summaryrefslogtreecommitdiff
path: root/test/racc/start.y
blob: 86296899b8444ae3eb6c08b61b7fbafa1a7a74b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class S

start st

rule

n: D { result = 'no' }
st : A B C n { result = 'ok' }

end

---- inner

  def parse
    do_parse
  end

---- footer

S.new.parse == 'ok' or raise 'start stmt not worked'
ba42a6ab02f1c43f2ac'>.document5
-rw-r--r--.gdbinit45
-rw-r--r--.git-blame-ignore-revs18
-rw-r--r--.gitattributes6
-rw-r--r--.github/actions/capiext/action.yml86
-rw-r--r--.github/actions/compilers/action.yml82
-rwxr-xr-x.github/actions/compilers/entrypoint.sh103
-rw-r--r--.github/actions/launchable/setup/action.yml284
-rw-r--r--.github/actions/make-snapshot/action.yml77
-rw-r--r--.github/actions/setup/baseruby/action.yml73
-rw-r--r--.github/actions/setup/directories/action.yml50
-rw-r--r--.github/actions/setup/macos/action.yml4
-rw-r--r--.github/actions/setup/ubuntu/action.yml35
-rw-r--r--.github/actions/slack/action.yml16
-rw-r--r--.github/auto_request_review.yml26
-rw-r--r--.github/codeql/codeql-config.yml22
-rw-r--r--.github/dependabot.yml31
-rw-r--r--.github/labeler.yml1
-rw-r--r--.github/workflows/annocheck.yml11
-rw-r--r--.github/workflows/auto_request_review.yml4
-rw-r--r--.github/workflows/auto_review_pr.yml41
-rw-r--r--.github/workflows/baseruby.yml11
-rw-r--r--.github/workflows/bundled_gems.yml106
-rw-r--r--.github/workflows/check_dependencies.yml16
-rw-r--r--.github/workflows/check_misc.yml94
-rw-r--r--.github/workflows/check_sast.yml133
-rw-r--r--.github/workflows/codeql-analysis.yml121
-rw-r--r--.github/workflows/compilers.yml268
-rw-r--r--.github/workflows/crosscompile.yml123
-rw-r--r--.github/workflows/cygwin.yml20
-rw-r--r--.github/workflows/default_gems.yml95
-rw-r--r--.github/workflows/default_gems_list.yml99
-rw-r--r--.github/workflows/dependabot_automerge.yml18
-rw-r--r--.github/workflows/labeler.yml5
-rw-r--r--.github/workflows/macos.yml70
-rw-r--r--.github/workflows/mingw.yml152
-rw-r--r--.github/workflows/modgc.yml42
-rw-r--r--.github/workflows/parse_y.yml101
-rw-r--r--.github/workflows/parsey.yml95
-rw-r--r--.github/workflows/post_push.yml97
-rw-r--r--.github/workflows/pr-playground.yml6
-rw-r--r--.github/workflows/publish.yml110
-rw-r--r--.github/workflows/release.yml106
-rw-r--r--.github/workflows/rust-warnings.yml62
-rw-r--r--.github/workflows/scorecards.yml46
-rw-r--r--.github/workflows/spec_guards.yml14
-rw-r--r--.github/workflows/sync_default_gems.yml80
-rw-r--r--.github/workflows/tarball-macos.yml101
-rw-r--r--.github/workflows/tarball-non-development.yml87
-rw-r--r--.github/workflows/tarball-test-schedule.yml26
-rw-r--r--.github/workflows/tarball-test.yml104
-rw-r--r--.github/workflows/tarball-ubuntu.yml151
-rw-r--r--.github/workflows/tarball-windows.yml163
-rw-r--r--.github/workflows/ubuntu.yml150
-rw-r--r--.github/workflows/wasm.yml76
-rw-r--r--.github/workflows/windows.yml153
-rw-r--r--.github/workflows/wsl.yml12
-rw-r--r--.github/workflows/yjit-macos.yml68
-rw-r--r--.github/workflows/yjit-ubuntu.yml77
-rw-r--r--.github/workflows/zjit-macos.yml239
-rw-r--r--.github/workflows/zjit-ubuntu.yml293
-rw-r--r--.github/zizmor.yml26
-rw-r--r--.gitignore18
-rw-r--r--.rdoc_options23
-rw-r--r--.travis.yml111
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--COPYING2
-rw-r--r--COPYING.ja2
-rw-r--r--Cargo.lock766
-rw-r--r--Cargo.toml64
-rw-r--r--LEGAL266
-rw-r--r--NEWS.md274
-rw-r--r--README.EXT1
-rw-r--r--README.EXT.ja1
-rw-r--r--README.ja.md2
-rw-r--r--README.md4
-rw-r--r--addr2line.c8
-rw-r--r--array.c400
-rw-r--r--array.rb55
-rw-r--r--ast.c58
-rwxr-xr-xautogen.sh21
-rw-r--r--benchmark/README.md2
-rw-r--r--benchmark/app_fib.rb2
-rw-r--r--benchmark/class_superclass.yml23
-rw-r--r--benchmark/dir_pwd.yml2
-rw-r--r--benchmark/file_basename.yml6
-rw-r--r--benchmark/file_dirname.yml6
-rw-r--r--benchmark/file_expand_path.yml4
-rw-r--r--benchmark/file_extname.yml6
-rw-r--r--benchmark/file_join.yml7
-rw-r--r--benchmark/float_predicate.yml12
-rw-r--r--benchmark/int_to_s.yml25
-rw-r--r--benchmark/integer_predicate.yml9
-rw-r--r--benchmark/io_close.yml13
-rw-r--r--benchmark/io_close_contended.yml21
-rw-r--r--benchmark/lib/benchmark_driver/runner/ractor.rb2
-rw-r--r--benchmark/module_eqq.yml7
-rw-r--r--benchmark/nilclass.yml6
-rw-r--r--benchmark/object_allocate.yml1
-rw-r--r--benchmark/object_class.yml40
-rw-r--r--benchmark/object_id.yml4
-rw-r--r--benchmark/pathname.yml15
-rw-r--r--benchmark/ractor_string_fstring.yml18
-rw-r--r--benchmark/set.yml261
-rw-r--r--benchmark/string_casecmp.yml2
-rw-r--r--benchmark/string_codepoints.yml9
-rw-r--r--benchmark/string_coderange_scan.yml10
-rw-r--r--benchmark/string_concat.yml4
-rw-r--r--benchmark/string_fstring.yml16
-rw-r--r--benchmark/string_gsub.yml11
-rw-r--r--benchmark/string_memsearch.yml75
-rw-r--r--benchmark/string_scrub.yml48
-rw-r--r--benchmark/struct_accessor.yml12
-rw-r--r--benchmark/time_now.yml1
-rw-r--r--benchmark/vm_ivar_get.yml67
-rw-r--r--benchmark/vm_ivar_set_on_instance.yml63
-rw-r--r--benchmark/vm_regexp.yml6
-rw-r--r--bignum.c247
-rwxr-xr-xbootstraptest/runner.rb45
-rw-r--r--bootstraptest/test_fiber.rb5
-rw-r--r--bootstraptest/test_flow.rb4
-rw-r--r--bootstraptest/test_insns.rb7
-rw-r--r--bootstraptest/test_io.rb2
-rw-r--r--bootstraptest/test_method.rb21
-rw-r--r--bootstraptest/test_ractor.rb1645
-rw-r--r--bootstraptest/test_syntax.rb8
-rw-r--r--bootstraptest/test_yjit.rb424
-rw-r--r--bootstraptest/test_yjit_rust_port.rb8
-rw-r--r--box.c1299
-rw-r--r--builtin.c85
-rw-r--r--builtin.h2
-rw-r--r--class.c1091
-rw-r--r--common.mk19394
-rw-r--r--compar.c60
-rw-r--r--compile.c941
-rw-r--r--complex.c328
-rw-r--r--concurrent_set.c518
-rw-r--r--configure.ac416
-rw-r--r--cont.c527
-rw-r--r--coroutine/ppc64le/Context.S7
-rw-r--r--cygwin/GNUmakefile.in11
-rw-r--r--darray.h23
-rw-r--r--debug.c33
-rw-r--r--debug_counter.h13
-rw-r--r--defs/gmake.mk152
-rw-r--r--defs/id.def5
-rw-r--r--defs/jit.mk107
-rw-r--r--defs/opt_insn_unif.def8
-rw-r--r--depend21719
-rw-r--r--dir.c278
-rw-r--r--dir.rb22
-rw-r--r--dln.c44
-rw-r--r--dln.h1
-rw-r--r--dmydln.c9
-rw-r--r--doc/.document16
-rw-r--r--doc/NEWS/NEWS-3.0.0.md4
-rw-r--r--doc/NEWS/NEWS-4.0.0.md802
-rw-r--r--doc/_regexp.rdoc99
-rw-r--r--doc/_timezones.rdoc2
-rw-r--r--doc/case_mapping.rdoc116
-rw-r--r--doc/character_selectors.rdoc97
-rw-r--r--doc/command_injection.rdoc37
-rw-r--r--doc/command_line/environment.md174
-rw-r--r--doc/contributing/bug_triaging.rdoc (renamed from doc/bug_triaging.rdoc)0
-rw-r--r--doc/contributing/building_ruby.md41
-rw-r--r--doc/contributing/concurrency_guide.md154
-rw-r--r--doc/contributing/documentation_guide.md149
-rw-r--r--doc/contributing/dtrace_probes.rdoc (renamed from doc/dtrace_probes.rdoc)0
-rw-r--r--doc/contributing/glossary.md15
-rw-r--r--doc/contributing/making_changes_to_stdlibs.md4
-rw-r--r--doc/contributing/memory_view.md (renamed from doc/memory_view.md)0
-rw-r--r--doc/contributing/vm_stack_and_frames.md163
-rw-r--r--doc/csv/arguments/io.rdoc5
-rw-r--r--doc/csv/options/common/col_sep.rdoc57
-rw-r--r--doc/csv/options/common/quote_char.rdoc42
-rw-r--r--doc/csv/options/common/row_sep.rdoc91
-rw-r--r--doc/csv/options/generating/force_quotes.rdoc17
-rw-r--r--doc/csv/options/generating/quote_empty.rdoc12
-rw-r--r--doc/csv/options/generating/write_converters.rdoc25
-rw-r--r--doc/csv/options/generating/write_empty_value.rdoc15
-rw-r--r--doc/csv/options/generating/write_headers.rdoc29
-rw-r--r--doc/csv/options/generating/write_nil_value.rdoc14
-rw-r--r--doc/csv/options/parsing/converters.rdoc46
-rw-r--r--doc/csv/options/parsing/empty_value.rdoc13
-rw-r--r--doc/csv/options/parsing/field_size_limit.rdoc39
-rw-r--r--doc/csv/options/parsing/header_converters.rdoc43
-rw-r--r--doc/csv/options/parsing/headers.rdoc63
-rw-r--r--doc/csv/options/parsing/liberal_parsing.rdoc38
-rw-r--r--doc/csv/options/parsing/nil_value.rdoc12
-rw-r--r--doc/csv/options/parsing/return_headers.rdoc22
-rw-r--r--doc/csv/options/parsing/skip_blanks.rdoc31
-rw-r--r--doc/csv/options/parsing/skip_lines.rdoc37
-rw-r--r--doc/csv/options/parsing/strip.rdoc15
-rw-r--r--doc/csv/options/parsing/unconverted_fields.rdoc27
-rw-r--r--doc/csv/recipes/filtering.rdoc158
-rw-r--r--doc/csv/recipes/generating.rdoc246
-rw-r--r--doc/csv/recipes/parsing.rdoc545
-rw-r--r--doc/csv/recipes/recipes.rdoc6
-rw-r--r--doc/date/calendars.rdoc62
-rw-r--r--doc/distribution.md48
-rw-r--r--doc/distribution/distribution.md48
-rw-r--r--doc/distribution/windows.md304
-rw-r--r--doc/encodings.rdoc482
-rw-r--r--doc/examples/files.rdoc8
-rw-r--r--doc/exceptions.md521
-rw-r--r--doc/extension.ja.rdoc6
-rw-r--r--doc/extension.rdoc135
-rw-r--r--doc/fiber.md232
-rw-r--r--doc/file/filename_globbing.md301
-rw-r--r--doc/file/filename_matching.md356
-rw-r--r--doc/file/timestamps.md83
-rw-r--r--doc/float.rb128
-rw-r--r--doc/format_specifications.rdoc350
-rw-r--r--doc/forwardable.rd.ja80
-rw-r--r--doc/globals.rdoc416
-rw-r--r--doc/jit/yjit.md547
-rw-r--r--doc/jit/zjit.md461
-rw-r--r--doc/language/box.md357
-rw-r--r--doc/language/bsearch.rdoc (renamed from doc/bsearch.rdoc)0
-rw-r--r--doc/language/calendars.rdoc62
-rw-r--r--doc/language/case_mapping.rdoc106
-rw-r--r--doc/language/character_selectors.rdoc100
-rw-r--r--doc/language/dig_methods.rdoc (renamed from doc/dig_methods.rdoc)0
-rw-r--r--doc/language/encodings.rdoc482
-rw-r--r--doc/language/exceptions.md521
-rw-r--r--doc/language/fiber.md290
-rw-r--r--doc/language/format_specifications.rdoc354
-rw-r--r--doc/language/globals.md611
-rw-r--r--doc/language/hash_inclusion.rdoc (renamed from doc/hash_inclusion.rdoc)0
-rw-r--r--doc/language/implicit_conversion.rdoc (renamed from doc/implicit_conversion.rdoc)0
-rw-r--r--doc/language/marshal.rdoc (renamed from doc/marshal.rdoc)0
-rw-r--r--doc/language/option_dump.md265
-rw-r--r--doc/language/options.md744
-rw-r--r--doc/language/packed_data.md886
-rw-r--r--doc/language/ractor.md797
-rw-r--r--doc/language/regexp/methods.rdoc (renamed from doc/regexp/methods.rdoc)0
-rw-r--r--doc/language/regexp/unicode_properties.rdoc718
-rw-r--r--doc/language/signals.rdoc106
-rw-r--r--doc/language/strftime_formatting.rdoc525
-rw-r--r--doc/maintainers.md217
-rw-r--r--doc/matchdata/begin.rdoc12
-rw-r--r--doc/matchdata/bytebegin.rdoc12
-rw-r--r--doc/matchdata/byteend.rdoc12
-rw-r--r--doc/matchdata/end.rdoc12
-rw-r--r--doc/matchdata/offset.rdoc12
-rw-r--r--doc/packed_data.rdoc706
-rw-r--r--doc/ractor.md951
-rw-r--r--doc/rdoc/markup_reference.rb1281
-rw-r--r--doc/regexp/unicode_properties.rdoc686
-rw-r--r--doc/reline/face.md111
-rw-r--r--doc/ruby/option_dump.md265
-rw-r--r--doc/ruby/options.md724
-rw-r--r--doc/security.rdoc139
-rw-r--r--doc/security/command_injection.rdoc15
-rw-r--r--doc/security/security.rdoc127
-rw-r--r--doc/signals.rdoc106
-rw-r--r--doc/standard_library.md38
-rw-r--r--doc/strftime_formatting.rdoc527
-rw-r--r--doc/string.rb421
-rw-r--r--doc/string/aref.rdoc96
-rw-r--r--doc/string/aset.rdoc179
-rw-r--r--doc/string/b.rdoc2
-rw-r--r--doc/string/bytes.rdoc5
-rw-r--r--doc/string/bytesize.rdoc17
-rw-r--r--doc/string/byteslice.rdoc54
-rw-r--r--doc/string/bytesplice.rdoc65
-rw-r--r--doc/string/capitalize.rdoc26
-rw-r--r--doc/string/center.rdoc21
-rw-r--r--doc/string/chars.rdoc4
-rw-r--r--doc/string/chomp.rdoc8
-rw-r--r--doc/string/chop.rdoc7
-rw-r--r--doc/string/chr.rdoc7
-rw-r--r--doc/string/codepoints.rdoc4
-rw-r--r--doc/string/concat.rdoc11
-rw-r--r--doc/string/count.rdoc74
-rw-r--r--doc/string/delete.rdoc75
-rw-r--r--doc/string/delete_prefix.rdoc11
-rw-r--r--doc/string/delete_suffix.rdoc10
-rw-r--r--doc/string/downcase.rdoc20
-rw-r--r--doc/string/dump.rdoc89
-rw-r--r--doc/string/each_byte.rdoc22
-rw-r--r--doc/string/each_char.rdoc26
-rw-r--r--doc/string/each_codepoint.rdoc28
-rw-r--r--doc/string/each_grapheme_cluster.rdoc19
-rw-r--r--doc/string/each_line.rdoc24
-rw-r--r--doc/string/encode.rdoc5
-rw-r--r--doc/string/end_with_p.rdoc16
-rw-r--r--doc/string/eql_p.rdoc18
-rw-r--r--doc/string/force_encoding.rdoc15
-rw-r--r--doc/string/getbyte.rdoc23
-rw-r--r--doc/string/grapheme_clusters.rdoc15
-rw-r--r--doc/string/hash.rdoc19
-rw-r--r--doc/string/index.rdoc30
-rw-r--r--doc/string/insert.rdoc15
-rw-r--r--doc/string/inspect.rdoc38
-rw-r--r--doc/string/intern.rdoc8
-rw-r--r--doc/string/length.rdoc7
-rw-r--r--doc/string/ljust.rdoc15
-rw-r--r--doc/string/new.rdoc48
-rw-r--r--doc/string/ord.rdoc3
-rw-r--r--doc/string/partition.rdoc51
-rw-r--r--doc/string/rindex.rdoc51
-rw-r--r--doc/string/rjust.rdoc9
-rw-r--r--doc/string/rpartition.rdoc55
-rw-r--r--doc/string/scan.rdoc35
-rw-r--r--doc/string/scrub.rdoc27
-rw-r--r--doc/string/split.rdoc129
-rw-r--r--doc/string/squeeze.rdoc33
-rw-r--r--doc/string/start_with_p.rdoc12
-rw-r--r--doc/string/sub.rdoc33
-rw-r--r--doc/string/succ.rdoc52
-rw-r--r--doc/string/sum.rdoc5
-rw-r--r--doc/string/swapcase.rdoc31
-rw-r--r--doc/string/unicode_normalize.rdoc28
-rw-r--r--doc/string/upcase.rdoc27
-rw-r--r--doc/string/upto.rdoc38
-rw-r--r--doc/string/valid_encoding_p.rdoc8
-rw-r--r--doc/stringio/each_byte.rdoc31
-rw-r--r--doc/stringio/each_char.rdoc31
-rw-r--r--doc/stringio/each_codepoint.rdoc33
-rw-r--r--doc/stringio/each_line.md189
-rw-r--r--doc/stringio/getbyte.rdoc24
-rw-r--r--doc/stringio/getc.rdoc30
-rw-r--r--doc/stringio/gets.rdoc99
-rw-r--r--doc/stringio/pread.rdoc65
-rw-r--r--doc/stringio/putc.rdoc82
-rw-r--r--doc/stringio/read.rdoc83
-rw-r--r--doc/stringio/size.rdoc4
-rw-r--r--doc/stringio/stringio.md702
-rw-r--r--doc/strscan/.document1
-rw-r--r--doc/strscan/link_refs.txt2
-rw-r--r--doc/strscan/methods/get_byte.md3
-rw-r--r--doc/strscan/methods/get_charpos.md3
-rw-r--r--doc/strscan/methods/get_pos.md3
-rw-r--r--doc/strscan/methods/getch.md3
-rw-r--r--doc/strscan/methods/scan.md3
-rw-r--r--doc/strscan/methods/scan_until.md3
-rw-r--r--doc/strscan/methods/set_pos.md4
-rw-r--r--doc/strscan/methods/skip.md3
-rw-r--r--doc/strscan/methods/skip_until.md9
-rw-r--r--doc/strscan/methods/terminate.md3
-rw-r--r--doc/strscan/strscan.md6
-rw-r--r--doc/syntax.rdoc3
-rw-r--r--doc/syntax/assignment.rdoc4
-rw-r--r--doc/syntax/calling_methods.rdoc7
-rw-r--r--doc/syntax/comments.rdoc2
-rw-r--r--doc/syntax/exceptions.rdoc2
-rw-r--r--doc/syntax/layout.rdoc118
-rw-r--r--doc/syntax/literals.rdoc11
-rw-r--r--doc/syntax/methods.rdoc1
-rw-r--r--doc/syntax/pattern_matching.rdoc2
-rw-r--r--doc/syntax/refinements.rdoc69
-rw-r--r--doc/windows.md254
-rw-r--r--doc/yarvarch.en7
-rw-r--r--doc/yarvarch.ja454
-rw-r--r--doc/yjit/yjit.md544
-rw-r--r--enc/Makefile.in5
-rw-r--r--enc/ascii.c4
-rw-r--r--enc/big5.c12
-rw-r--r--enc/cp949.c4
-rw-r--r--enc/depend73
-rw-r--r--enc/emacs_mule.c4
-rw-r--r--enc/euc_jp.c4
-rw-r--r--enc/euc_kr.c8
-rw-r--r--enc/euc_tw.c4
-rw-r--r--enc/gb18030.c4
-rw-r--r--enc/gbk.c4
-rw-r--r--enc/iso_8859_1.c6
-rw-r--r--enc/iso_8859_10.c6
-rw-r--r--enc/iso_8859_11.c4
-rw-r--r--enc/iso_8859_13.c6
-rw-r--r--enc/iso_8859_14.c6
-rw-r--r--enc/iso_8859_15.c6
-rw-r--r--enc/iso_8859_16.c6
-rw-r--r--enc/iso_8859_2.c6
-rw-r--r--enc/iso_8859_3.c6
-rw-r--r--enc/iso_8859_4.c6
-rw-r--r--enc/iso_8859_5.c6
-rw-r--r--enc/iso_8859_6.c4
-rw-r--r--enc/iso_8859_7.c6
-rw-r--r--enc/iso_8859_8.c4
-rw-r--r--enc/iso_8859_9.c6
-rw-r--r--enc/koi8_r.c4
-rw-r--r--enc/koi8_u.c4
-rwxr-xr-xenc/make_encmake.rb9
-rw-r--r--enc/shift_jis.c4
-rw-r--r--enc/trans/iso2022.trans3
-rw-r--r--enc/unicode.c12
-rw-r--r--enc/unicode/15.1.0/casefold.h7629
-rw-r--r--enc/unicode/15.1.0/name2ctype.h46714
-rw-r--r--enc/unicode/17.0.0/casefold.h8013
-rw-r--r--enc/unicode/17.0.0/name2ctype.h49725
-rw-r--r--enc/us_ascii.c4
-rw-r--r--enc/utf_16be.c4
-rw-r--r--enc/utf_16le.c4
-rw-r--r--enc/utf_32be.c4
-rw-r--r--enc/utf_32le.c4
-rw-r--r--enc/utf_8.c4
-rw-r--r--enc/windows_1250.c6
-rw-r--r--enc/windows_1251.c6
-rw-r--r--enc/windows_1252.c6
-rw-r--r--enc/windows_1253.c6
-rw-r--r--enc/windows_1254.c6
-rw-r--r--enc/windows_1257.c6
-rw-r--r--enc/windows_31j.c4
-rw-r--r--encoding.c380
-rw-r--r--enum.c148
-rw-r--r--enumerator.c695
-rw-r--r--error.c190
-rw-r--r--eval.c316
-rw-r--r--eval_intern.h42
-rw-r--r--eval_jump.c2
-rw-r--r--ext/-test-/RUBY_ALIGNOF/depend1
-rw-r--r--ext/-test-/abi/depend3
-rw-r--r--ext/-test-/arith_seq/beg_len_step/depend1
-rw-r--r--ext/-test-/arith_seq/extract/depend1
-rw-r--r--ext/-test-/array/concat/depend1
-rw-r--r--ext/-test-/array/resize/depend1
-rw-r--r--ext/-test-/asan/asan.c24
-rw-r--r--ext/-test-/asan/extconf.rb2
-rw-r--r--ext/-test-/bignum/depend19
-rw-r--r--ext/-test-/box/yay1/extconf.rb1
-rw-r--r--ext/-test-/box/yay1/yay1.c28
-rw-r--r--ext/-test-/box/yay1/yay1.def3
-rw-r--r--ext/-test-/box/yay1/yay1.h4
-rw-r--r--ext/-test-/box/yay2/extconf.rb1
-rw-r--r--ext/-test-/box/yay2/yay2.c28
-rw-r--r--ext/-test-/box/yay2/yay2.def3
-rw-r--r--ext/-test-/box/yay2/yay2.h4
-rw-r--r--ext/-test-/bug-14834/depend1
-rw-r--r--ext/-test-/bug-3571/depend1
-rw-r--r--ext/-test-/bug-5832/depend1
-rw-r--r--ext/-test-/bug_reporter/depend1
-rw-r--r--ext/-test-/class/depend2
-rw-r--r--ext/-test-/cxxanyargs/cxxanyargs.cpp26
-rw-r--r--ext/-test-/debug/depend3
-rw-r--r--ext/-test-/dln/empty/depend1
-rw-r--r--ext/-test-/econv/depend336
-rw-r--r--ext/-test-/ensure_and_callcc/depend163
-rw-r--r--ext/-test-/enumerator_kw/depend1
-rw-r--r--ext/-test-/eval/depend162
-rw-r--r--ext/-test-/exception/depend4
-rw-r--r--ext/-test-/fatal/depend3
-rw-r--r--ext/-test-/fatal/invalid.c6
-rw-r--r--ext/-test-/file/depend4
-rw-r--r--ext/-test-/float/depend2
-rw-r--r--ext/-test-/funcall/depend1
-rw-r--r--ext/-test-/gvl/call_without_gvl/depend1
-rw-r--r--ext/-test-/hash/depend2
-rw-r--r--ext/-test-/integer/depend6
-rw-r--r--ext/-test-/iseq_load/depend1
-rw-r--r--ext/-test-/iter/depend3
-rw-r--r--ext/-test-/load/dot.dot/depend1
-rw-r--r--ext/-test-/load/protect/depend1
-rw-r--r--ext/-test-/load/resolve_symbol_resolver/depend163
-rw-r--r--ext/-test-/load/resolve_symbol_target/depend164
-rw-r--r--ext/-test-/load/stringify_symbols/depend164
-rw-r--r--ext/-test-/load/stringify_target/depend164
-rw-r--r--ext/-test-/marshal/compat/depend1
-rw-r--r--ext/-test-/marshal/internal_ivar/depend1
-rw-r--r--ext/-test-/marshal/usr/depend1
-rw-r--r--ext/-test-/memory_view/depend1
-rw-r--r--ext/-test-/method/depend2
-rw-r--r--ext/-test-/notimplement/depend1
-rw-r--r--ext/-test-/num2int/depend1
-rw-r--r--ext/-test-/path_to_class/depend1
-rw-r--r--ext/-test-/popen_deadlock/depend1
-rw-r--r--ext/-test-/postponed_job/depend1
-rw-r--r--ext/-test-/postponed_job/postponed_job.c80
-rw-r--r--ext/-test-/printf/depend1
-rw-r--r--ext/-test-/proc/depend3
-rw-r--r--ext/-test-/random/depend3
-rw-r--r--ext/-test-/rational/depend4
-rw-r--r--ext/-test-/rb_call_super_kw/depend1
-rw-r--r--ext/-test-/recursion/depend1
-rw-r--r--ext/-test-/regexp/depend2
-rw-r--r--ext/-test-/sanitizers/depend162
-rw-r--r--ext/-test-/sanitizers/extconf.rb2
-rw-r--r--ext/-test-/sanitizers/sanitizers.c36
-rw-r--r--ext/-test-/scan_args/depend1
-rw-r--r--ext/-test-/scheduler/extconf.rb2
-rw-r--r--ext/-test-/scheduler/scheduler.c92
-rw-r--r--ext/-test-/st/foreach/depend1
-rw-r--r--ext/-test-/st/foreach/foreach.c12
-rw-r--r--ext/-test-/st/numhash/depend1
-rw-r--r--ext/-test-/st/update/depend1
-rw-r--r--ext/-test-/stack/depend179
-rw-r--r--ext/-test-/stack/extconf.rb3
-rw-r--r--ext/-test-/stack/stack.c35
-rw-r--r--ext/-test-/string/cstr.c3
-rw-r--r--ext/-test-/string/depend20
-rw-r--r--ext/-test-/string/fstring.c6
-rw-r--r--ext/-test-/struct/depend5
-rw-r--r--ext/-test-/symbol/depend2
-rw-r--r--ext/-test-/thread/id/depend163
-rw-r--r--ext/-test-/thread/instrumentation/depend1
-rw-r--r--ext/-test-/thread/instrumentation/instrumentation.c4
-rw-r--r--ext/-test-/thread/lock_native_thread/depend163
-rw-r--r--ext/-test-/thread_fd/depend161
-rw-r--r--ext/-test-/thread_fd/extconf.rb2
-rw-r--r--ext/-test-/thread_fd/thread_fd.c30
-rw-r--r--ext/-test-/time/depend3
-rw-r--r--ext/-test-/time/leap_second.c15
-rw-r--r--ext/-test-/tracepoint/depend2
-rw-r--r--ext/-test-/tracepoint/gc_hook.c26
-rw-r--r--ext/-test-/tracepoint/tracepoint.c10
-rw-r--r--ext/-test-/typeddata/depend1
-rw-r--r--ext/-test-/vm/depend1
-rw-r--r--ext/-test-/wait/depend1
-rw-r--r--ext/.document23
-rw-r--r--ext/Setup13
-rw-r--r--ext/Setup.atheos21
-rw-r--r--ext/Setup.nt22
-rw-r--r--ext/cgi/escape/depend1
-rw-r--r--ext/cgi/escape/escape.c30
-rw-r--r--ext/continuation/depend1
-rw-r--r--ext/coverage/coverage.c295
-rw-r--r--ext/coverage/depend3
-rw-r--r--ext/coverage/lib/coverage.rb5
-rw-r--r--ext/date/date_core.c444
-rw-r--r--ext/date/date_strptime.c6
-rw-r--r--ext/date/depend4
-rw-r--r--ext/date/lib/date.rb2
-rw-r--r--ext/digest/bubblebabble/depend1
-rw-r--r--ext/digest/defs.h22
-rw-r--r--ext/digest/depend1
-rw-r--r--ext/digest/digest.c2
-rw-r--r--ext/digest/digest_conf.rb18
-rw-r--r--ext/digest/lib/digest/version.rb3
-rw-r--r--ext/digest/md5/depend2
-rw-r--r--ext/digest/md5/md5cc.h8
-rw-r--r--ext/digest/md5/md5init.c1
-rw-r--r--ext/digest/rmd160/depend2
-rw-r--r--ext/digest/sha1/depend2
-rw-r--r--ext/digest/sha1/sha1.c14
-rw-r--r--ext/digest/sha2/depend2
-rw-r--r--ext/erb/escape/escape.c41
-rw-r--r--ext/erb/escape/extconf.rb1
-rw-r--r--ext/etc/depend1
-rw-r--r--ext/etc/etc.c10
-rw-r--r--ext/etc/etc.gemspec2
-rw-r--r--ext/etc/extconf.rb48
-rwxr-xr-xext/extmk.rb19
-rw-r--r--ext/fcntl/depend1
-rw-r--r--ext/fcntl/fcntl.c48
-rw-r--r--ext/io/console/console.c96
-rw-r--r--ext/io/console/depend1
-rw-r--r--ext/io/console/extconf.rb10
-rw-r--r--ext/io/nonblock/depend1
-rw-r--r--ext/io/nonblock/extconf.rb2
-rw-r--r--ext/io/nonblock/io-nonblock.gemspec4
-rw-r--r--ext/io/wait/depend2
-rw-r--r--ext/io/wait/extconf.rb23
-rw-r--r--ext/io/wait/io-wait.gemspec23
-rw-r--r--ext/io/wait/wait.c418
-rw-r--r--ext/json/fbuffer/fbuffer.h140
-rw-r--r--ext/json/generator/depend3
-rw-r--r--ext/json/generator/extconf.rb9
-rw-r--r--ext/json/generator/generator.c1377
-rw-r--r--ext/json/json.gemspec5
-rw-r--r--ext/json/json.h134
-rw-r--r--ext/json/lib/json.rb92
-rw-r--r--ext/json/lib/json/add/core.rb1
-rw-r--r--ext/json/lib/json/add/string.rb35
-rw-r--r--ext/json/lib/json/common.rb286
-rw-r--r--ext/json/lib/json/ext.rb4
-rw-r--r--ext/json/lib/json/ext/generator/state.rb25
-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/depend4
-rw-r--r--ext/json/parser/extconf.rb14
-rw-r--r--ext/json/parser/parser.c1528
-rw-r--r--ext/json/simd/conf.rb24
-rw-r--r--ext/json/simd/simd.h208
-rw-r--r--ext/json/vendor/fpconv.c39
-rw-r--r--ext/json/vendor/jeaiii-ltoa.h16
-rw-r--r--ext/json/vendor/ryu.h819
-rw-r--r--ext/monitor/depend161
-rw-r--r--ext/monitor/extconf.rb2
-rw-r--r--ext/monitor/lib/monitor.rb289
-rw-r--r--ext/monitor/monitor.c255
-rw-r--r--ext/objspace/depend13
-rw-r--r--ext/objspace/object_tracing.c11
-rw-r--r--ext/objspace/objspace.c292
-rw-r--r--ext/objspace/objspace_dump.c145
-rw-r--r--ext/openssl/History.md178
-rw-r--r--ext/openssl/depend33
-rw-r--r--ext/openssl/extconf.rb28
-rw-r--r--ext/openssl/lib/openssl.rb15
-rw-r--r--ext/openssl/lib/openssl/asn1.rb188
-rw-r--r--ext/openssl/lib/openssl/digest.rb26
-rw-r--r--ext/openssl/lib/openssl/pkey.rb84
-rw-r--r--ext/openssl/lib/openssl/ssl.rb49
-rw-r--r--ext/openssl/lib/openssl/version.rb3
-rw-r--r--ext/openssl/lib/openssl/x509.rb9
-rw-r--r--ext/openssl/openssl.gemspec5
-rw-r--r--ext/openssl/openssl_missing.h23
-rw-r--r--ext/openssl/ossl.c477
-rw-r--r--ext/openssl/ossl.h25
-rw-r--r--ext/openssl/ossl_asn1.c1055
-rw-r--r--ext/openssl/ossl_asn1.h16
-rw-r--r--ext/openssl/ossl_bio.c12
-rw-r--r--ext/openssl/ossl_bn.c576
-rw-r--r--ext/openssl/ossl_cipher.c473
-rw-r--r--ext/openssl/ossl_cipher.h11
-rw-r--r--ext/openssl/ossl_config.c7
-rw-r--r--ext/openssl/ossl_digest.c116
-rw-r--r--ext/openssl/ossl_digest.h10
-rw-r--r--ext/openssl/ossl_engine.c83
-rw-r--r--ext/openssl/ossl_hmac.c57
-rw-r--r--ext/openssl/ossl_kdf.c199
-rw-r--r--ext/openssl/ossl_ns_spki.c68
-rw-r--r--ext/openssl/ossl_ocsp.c451
-rw-r--r--ext/openssl/ossl_pkcs12.c50
-rw-r--r--ext/openssl/ossl_pkcs7.c277
-rw-r--r--ext/openssl/ossl_pkey.c280
-rw-r--r--ext/openssl/ossl_pkey.h199
-rw-r--r--ext/openssl/ossl_pkey_dh.c67
-rw-r--r--ext/openssl/ossl_pkey_dsa.c37
-rw-r--r--ext/openssl/ossl_pkey_ec.c336
-rw-r--r--ext/openssl/ossl_pkey_rsa.c120
-rw-r--r--ext/openssl/ossl_provider.c7
-rw-r--r--ext/openssl/ossl_rand.c19
-rw-r--r--ext/openssl/ossl_ssl.c710
-rw-r--r--ext/openssl/ossl_ssl.h16
-rw-r--r--ext/openssl/ossl_ssl_session.c189
-rw-r--r--ext/openssl/ossl_ts.c214
-rw-r--r--ext/openssl/ossl_x509.c7
-rw-r--r--ext/openssl/ossl_x509.h12
-rw-r--r--ext/openssl/ossl_x509attr.c104
-rw-r--r--ext/openssl/ossl_x509cert.c169
-rw-r--r--ext/openssl/ossl_x509crl.c144
-rw-r--r--ext/openssl/ossl_x509ext.c121
-rw-r--r--ext/openssl/ossl_x509name.c155
-rw-r--r--ext/openssl/ossl_x509req.c118
-rw-r--r--ext/openssl/ossl_x509revoked.c66
-rw-r--r--ext/openssl/ossl_x509store.c87
-rw-r--r--ext/pathname/depend174
-rw-r--r--ext/pathname/extconf.rb3
-rw-r--r--ext/pathname/lib/pathname.rb621
-rw-r--r--ext/pathname/pathname.c1668
-rw-r--r--ext/pathname/pathname.gemspec32
-rw-r--r--ext/psych/depend5
-rw-r--r--ext/psych/extconf.rb7
-rw-r--r--ext/psych/lib/psych.rb45
-rw-r--r--ext/psych/lib/psych/class_loader.rb1
-rw-r--r--ext/psych/lib/psych/core_ext.rb21
-rw-r--r--ext/psych/lib/psych/nodes/node.rb4
-rw-r--r--ext/psych/lib/psych/scalar_scanner.rb5
-rw-r--r--ext/psych/lib/psych/versions.rb4
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb54
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb40
-rw-r--r--ext/psych/psych_parser.c17
-rw-r--r--ext/psych/psych_to_ruby.c4
-rw-r--r--ext/pty/depend2
-rw-r--r--ext/pty/extconf.rb2
-rw-r--r--ext/pty/pty.c29
-rw-r--r--ext/rbconfig/sizeof/depend2
-rw-r--r--ext/ripper/depend13
-rw-r--r--ext/ripper/lib/ripper/lexer.rb2
-rw-r--r--ext/socket/depend75
-rw-r--r--ext/socket/extconf.rb1
-rw-r--r--ext/socket/getaddrinfo.c7
-rw-r--r--ext/socket/getnameinfo.c18
-rw-r--r--ext/socket/init.c8
-rw-r--r--ext/socket/ipsocket.c227
-rw-r--r--ext/socket/lib/socket.rb109
-rw-r--r--ext/socket/raddrinfo.c171
-rw-r--r--ext/socket/rubysocket.h14
-rw-r--r--ext/socket/socket.c8
-rw-r--r--ext/socket/sockssocket.c5
-rw-r--r--ext/socket/tcpserver.c2
-rw-r--r--ext/socket/tcpsocket.c26
-rw-r--r--ext/socket/udpsocket.c6
-rw-r--r--ext/socket/unixsocket.c3
-rw-r--r--ext/stringio/depend2
-rw-r--r--ext/stringio/extconf.rb2
-rw-r--r--ext/stringio/stringio.c416
-rw-r--r--ext/strscan/depend1
-rw-r--r--ext/strscan/extconf.rb8
-rw-r--r--ext/strscan/lib/strscan.rb20
-rw-r--r--ext/strscan/lib/strscan/strscan.rb44
-rw-r--r--ext/strscan/strscan.c372
-rw-r--r--ext/strscan/strscan.gemspec12
-rw-r--r--ext/win32/lib/win32/registry.rb925
-rw-r--r--ext/win32/lib/win32/resolv.rb135
-rw-r--r--ext/win32/resolv/extconf.rb3
-rw-r--r--ext/win32/resolv/resolv.c214
-rw-r--r--ext/win32/win32-registry.gemspec32
-rw-r--r--ext/zlib/depend1
-rw-r--r--ext/zlib/zlib.c51
-rw-r--r--file.c1527
-rw-r--r--gc.c2598
-rw-r--r--gc.rb698
-rw-r--r--gc/README.md9
-rw-r--r--gc/default/default.c1934
-rw-r--r--gc/gc.h151
-rw-r--r--gc/gc_impl.h18
-rw-r--r--gc/mmtk/Cargo.lock469
-rw-r--r--gc/mmtk/Cargo.toml9
-rw-r--r--gc/mmtk/cbindgen.toml5
-rw-r--r--gc/mmtk/extconf.rb4
-rw-r--r--gc/mmtk/mmtk.c696
-rw-r--r--gc/mmtk/mmtk.h41
-rw-r--r--gc/mmtk/src/abi.rs102
-rw-r--r--gc/mmtk/src/api.rs322
-rw-r--r--gc/mmtk/src/binding.rs10
-rw-r--r--gc/mmtk/src/collection.rs61
-rw-r--r--gc/mmtk/src/heap/cpu_heap_trigger.rs370
-rw-r--r--gc/mmtk/src/heap/mod.rs9
-rw-r--r--gc/mmtk/src/heap/ruby_heap_trigger.rs105
-rw-r--r--gc/mmtk/src/lib.rs36
-rw-r--r--gc/mmtk/src/object_model.rs53
-rw-r--r--gc/mmtk/src/pinning_registry.rs187
-rw-r--r--gc/mmtk/src/scanning.rs72
-rw-r--r--gc/mmtk/src/utils.rs60
-rw-r--r--gc/mmtk/src/weak_proc.rs257
-rw-r--r--gc/wbcheck/extconf.rb3
-rw-r--r--gc/wbcheck/wbcheck.c1936
-rw-r--r--gem_prelude.rb1
-rw-r--r--gems/bundled_gems58
-rw-r--r--hash.c694
-rw-r--r--hash.rb2
-rw-r--r--id_table.c208
-rw-r--r--id_table.h34
-rw-r--r--imemo.c547
-rw-r--r--include/ruby/atomic.h450
-rw-r--r--include/ruby/backward.h6
-rw-r--r--include/ruby/backward/2/rmodule.h2
-rw-r--r--include/ruby/backward/cxxanyargs.hpp29
-rw-r--r--include/ruby/debug.h55
-rw-r--r--include/ruby/fiber/scheduler.h87
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/internal/abi.h2
-rw-r--r--include/ruby/internal/anyargs.h22
-rw-r--r--include/ruby/internal/arithmetic/intptr_t.h12
-rw-r--r--include/ruby/internal/attr/deprecated.h9
-rw-r--r--include/ruby/internal/attr/forceinline.h2
-rw-r--r--include/ruby/internal/attr/format.h4
-rw-r--r--include/ruby/internal/attr/noexcept.h2
-rw-r--r--include/ruby/internal/attr/nonstring.h40
-rw-r--r--include/ruby/internal/attr/restrict.h2
-rw-r--r--include/ruby/internal/compiler_is/msvc.h13
-rw-r--r--include/ruby/internal/config.h2
-rw-r--r--include/ruby/internal/core/rarray.h2
-rw-r--r--include/ruby/internal/core/rbasic.h16
-rw-r--r--include/ruby/internal/core/rclass.h2
-rw-r--r--include/ruby/internal/core/rdata.h297
-rw-r--r--include/ruby/internal/core/rmatch.h55
-rw-r--r--include/ruby/internal/core/robject.h35
-rw-r--r--include/ruby/internal/core/rstring.h57
-rw-r--r--include/ruby/internal/core/rstruct.h12
-rw-r--r--include/ruby/internal/core/rtypeddata.h317
-rw-r--r--include/ruby/internal/ctype.h4
-rw-r--r--include/ruby/internal/encoding/string.h29
-rw-r--r--include/ruby/internal/error.h7
-rw-r--r--include/ruby/internal/eval.h15
-rw-r--r--include/ruby/internal/fl_type.h225
-rw-r--r--include/ruby/internal/gc.h161
-rw-r--r--include/ruby/internal/globals.h2
-rw-r--r--include/ruby/internal/intern/bignum.h45
-rw-r--r--include/ruby/internal/intern/complex.h4
-rw-r--r--include/ruby/internal/intern/cont.h11
-rw-r--r--include/ruby/internal/intern/enumerator.h12
-rw-r--r--include/ruby/internal/intern/file.h16
-rw-r--r--include/ruby/internal/intern/object.h3
-rw-r--r--include/ruby/internal/intern/proc.h12
-rw-r--r--include/ruby/internal/intern/select.h2
-rw-r--r--include/ruby/internal/intern/set.h111
-rw-r--r--include/ruby/internal/intern/string.h25
-rw-r--r--include/ruby/internal/intern/thread.h8
-rw-r--r--include/ruby/internal/intern/variable.h1
-rw-r--r--include/ruby/internal/intern/vm.h7
-rw-r--r--include/ruby/internal/iterator.h45
-rw-r--r--include/ruby/internal/memory.h76
-rw-r--r--include/ruby/internal/newobj.h38
-rw-r--r--include/ruby/internal/scan_args.h6
-rw-r--r--include/ruby/internal/static_assert.h2
-rw-r--r--include/ruby/internal/stdbool.h12
-rw-r--r--include/ruby/internal/symbol.h43
-rw-r--r--include/ruby/internal/value_type.h26
-rw-r--r--include/ruby/internal/warning_push.h2
-rw-r--r--include/ruby/internal/xmalloc.h151
-rw-r--r--include/ruby/io.h284
-rw-r--r--include/ruby/onigmo.h14
-rw-r--r--include/ruby/ractor.h16
-rw-r--r--include/ruby/random.h3
-rw-r--r--include/ruby/st.h5
-rw-r--r--include/ruby/thread.h7
-rw-r--r--include/ruby/version.h4
-rw-r--r--include/ruby/win32.h51
-rw-r--r--inits.c14
-rw-r--r--insns.def208
-rw-r--r--internal.h3
-rw-r--r--internal/array.h3
-rw-r--r--internal/basic_operators.h1
-rw-r--r--internal/bignum.h42
-rw-r--r--internal/bits.h31
-rw-r--r--internal/box.h96
-rw-r--r--internal/class.h687
-rw-r--r--internal/cmdlineopt.h3
-rw-r--r--internal/compar.h1
-rw-r--r--internal/concurrent_set.h21
-rw-r--r--internal/cont.h1
-rw-r--r--internal/encoding.h3
-rw-r--r--internal/error.h19
-rw-r--r--internal/eval.h10
-rw-r--r--internal/file.h2
-rw-r--r--internal/gc.h113
-rw-r--r--internal/hash.h19
-rw-r--r--internal/imemo.h185
-rw-r--r--internal/inits.h4
-rw-r--r--internal/io.h33
-rw-r--r--internal/load.h2
-rw-r--r--internal/numeric.h55
-rw-r--r--internal/object.h11
-rw-r--r--internal/range.h6
-rw-r--r--internal/rational.h23
-rw-r--r--internal/re.h53
-rw-r--r--internal/sanitizers.h16
-rw-r--r--internal/set_table.h74
-rw-r--r--internal/signal.h1
-rw-r--r--internal/st.h11
-rw-r--r--internal/string.h40
-rw-r--r--internal/struct.h75
-rw-r--r--internal/symbol.h9
-rw-r--r--internal/thread.h26
-rw-r--r--internal/time.h7
-rw-r--r--internal/variable.h26
-rw-r--r--internal/vm.h11
-rw-r--r--io.c685
-rw-r--r--io_buffer.c402
-rw-r--r--iseq.c657
-rw-r--r--iseq.h21
-rw-r--r--jit.c844
-rw-r--r--jit/Cargo.toml6
-rw-r--r--jit/src/lib.rs38
-rw-r--r--jit_hook.rb12
-rw-r--r--jit_undef.rb4
-rw-r--r--kernel.rb13
-rw-r--r--lib/English.gemspec11
-rw-r--r--lib/English.rb50
-rw-r--r--lib/bundled_gems.rb103
-rw-r--r--lib/bundler.rb71
-rw-r--r--lib/bundler/build_metadata.rb18
-rw-r--r--lib/bundler/bundler.gemspec10
-rw-r--r--lib/bundler/capistrano.rb20
-rw-r--r--lib/bundler/checksum.rb6
-rw-r--r--lib/bundler/cli.rb315
-rw-r--r--lib/bundler/cli/add.rb17
-rw-r--r--lib/bundler/cli/cache.rb13
-rw-r--r--lib/bundler/cli/common.rb31
-rw-r--r--lib/bundler/cli/config.rb14
-rw-r--r--lib/bundler/cli/console.rb5
-rw-r--r--lib/bundler/cli/doctor.rb182
-rw-r--r--lib/bundler/cli/doctor/diagnose.rb167
-rw-r--r--lib/bundler/cli/doctor/ssl.rb249
-rw-r--r--lib/bundler/cli/exec.rb33
-rw-r--r--lib/bundler/cli/gem.rb169
-rw-r--r--lib/bundler/cli/inject.rb60
-rw-r--r--lib/bundler/cli/install.rb108
-rw-r--r--lib/bundler/cli/issue.rb8
-rw-r--r--lib/bundler/cli/list.rb35
-rw-r--r--lib/bundler/cli/lock.rb10
-rw-r--r--lib/bundler/cli/outdated.rb46
-rw-r--r--lib/bundler/cli/plugin.rb6
-rw-r--r--lib/bundler/cli/pristine.rb6
-rw-r--r--lib/bundler/cli/show.rb10
-rw-r--r--lib/bundler/cli/update.rb12
-rw-r--r--lib/bundler/cli/viz.rb31
-rw-r--r--lib/bundler/compact_index_client.rb1
-rw-r--r--lib/bundler/compact_index_client/cache.rb2
-rw-r--r--lib/bundler/compact_index_client/gem_parser.rb32
-rw-r--r--lib/bundler/compact_index_client/parser.rb7
-rw-r--r--lib/bundler/current_ruby.rb20
-rw-r--r--lib/bundler/definition.rb513
-rw-r--r--lib/bundler/dependency.rb2
-rw-r--r--lib/bundler/deployment.rb65
-rw-r--r--lib/bundler/digest.rb2
-rw-r--r--lib/bundler/dsl.rb134
-rw-r--r--lib/bundler/endpoint_specification.rb12
-rw-r--r--lib/bundler/environment_preserver.rb1
-rw-r--r--lib/bundler/errors.rb45
-rw-r--r--lib/bundler/feature_flag.rb40
-rw-r--r--lib/bundler/fetcher.rb68
-rw-r--r--lib/bundler/fetcher/compact_index.rb2
-rw-r--r--lib/bundler/fetcher/dependency.rb11
-rw-r--r--lib/bundler/fetcher/downloader.rb41
-rw-r--r--lib/bundler/fetcher/gem_remote_fetcher.rb6
-rw-r--r--lib/bundler/friendly_errors.rb9
-rw-r--r--lib/bundler/gem_helpers.rb144
-rw-r--r--lib/bundler/graph.rb152
-rw-r--r--lib/bundler/index.rb16
-rw-r--r--lib/bundler/injector.rb9
-rw-r--r--lib/bundler/inline.rb58
-rw-r--r--lib/bundler/installer.rb28
-rw-r--r--lib/bundler/installer/gem_installer.rb25
-rw-r--r--lib/bundler/installer/parallel_installer.rb110
-rw-r--r--lib/bundler/lazy_specification.rb106
-rw-r--r--lib/bundler/lockfile_generator.rb19
-rw-r--r--lib/bundler/lockfile_parser.rb42
-rw-r--r--lib/bundler/man/bundle-add.114
-rw-r--r--lib/bundler/man/bundle-add.1.ronn14
-rw-r--r--lib/bundler/man/bundle-binstubs.19
-rw-r--r--lib/bundler/man/bundle-binstubs.1.ronn10
-rw-r--r--lib/bundler/man/bundle-cache.116
-rw-r--r--lib/bundler/man/bundle-cache.1.ronn15
-rw-r--r--lib/bundler/man/bundle-check.17
-rw-r--r--lib/bundler/man/bundle-check.1.ronn5
-rw-r--r--lib/bundler/man/bundle-clean.12
-rw-r--r--lib/bundler/man/bundle-config.1184
-rw-r--r--lib/bundler/man/bundle-config.1.ronn293
-rw-r--r--lib/bundler/man/bundle-console.12
-rw-r--r--lib/bundler/man/bundle-doctor.147
-rw-r--r--lib/bundler/man/bundle-doctor.1.ronn52
-rw-r--r--lib/bundler/man/bundle-env.12
-rw-r--r--lib/bundler/man/bundle-exec.17
-rw-r--r--lib/bundler/man/bundle-exec.1.ronn6
-rw-r--r--lib/bundler/man/bundle-fund.12
-rw-r--r--lib/bundler/man/bundle-gem.1108
-rw-r--r--lib/bundler/man/bundle-gem.1.ronn19
-rw-r--r--lib/bundler/man/bundle-help.12
-rw-r--r--lib/bundler/man/bundle-info.12
-rw-r--r--lib/bundler/man/bundle-init.12
-rw-r--r--lib/bundler/man/bundle-inject.131
-rw-r--r--lib/bundler/man/bundle-inject.1.ronn32
-rw-r--r--lib/bundler/man/bundle-install.176
-rw-r--r--lib/bundler/man/bundle-install.1.ronn141
-rw-r--r--lib/bundler/man/bundle-issue.12
-rw-r--r--lib/bundler/man/bundle-licenses.12
-rw-r--r--lib/bundler/man/bundle-list.17
-rw-r--r--lib/bundler/man/bundle-list.1.ronn5
-rw-r--r--lib/bundler/man/bundle-lock.12
-rw-r--r--lib/bundler/man/bundle-open.12
-rw-r--r--lib/bundler/man/bundle-outdated.131
-rw-r--r--lib/bundler/man/bundle-outdated.1.ronn31
-rw-r--r--lib/bundler/man/bundle-platform.12
-rw-r--r--lib/bundler/man/bundle-plugin.148
-rw-r--r--lib/bundler/man/bundle-plugin.1.ronn51
-rw-r--r--lib/bundler/man/bundle-pristine.12
-rw-r--r--lib/bundler/man/bundle-remove.110
-rw-r--r--lib/bundler/man/bundle-remove.1.ronn9
-rw-r--r--lib/bundler/man/bundle-show.17
-rw-r--r--lib/bundler/man/bundle-show.1.ronn4
-rw-r--r--lib/bundler/man/bundle-update.113
-rw-r--r--lib/bundler/man/bundle-update.1.ronn16
-rw-r--r--lib/bundler/man/bundle-version.12
-rw-r--r--lib/bundler/man/bundle-viz.130
-rw-r--r--lib/bundler/man/bundle-viz.1.ronn36
-rw-r--r--lib/bundler/man/bundle.111
-rw-r--r--lib/bundler/man/bundle.1.ronn9
-rw-r--r--lib/bundler/man/gemfile.577
-rw-r--r--lib/bundler/man/gemfile.5.ronn81
-rw-r--r--lib/bundler/man/index.txt2
-rw-r--r--lib/bundler/match_metadata.rb20
-rw-r--r--lib/bundler/match_platform.rb43
-rw-r--r--lib/bundler/match_remote_metadata.rb27
-rw-r--r--lib/bundler/materialization.rb6
-rw-r--r--lib/bundler/override.rb69
-rw-r--r--lib/bundler/plugin.rb11
-rw-r--r--lib/bundler/plugin/api/source.rb8
-rw-r--r--lib/bundler/plugin/events.rb68
-rw-r--r--lib/bundler/plugin/index.rb52
-rw-r--r--lib/bundler/plugin/installer.rb13
-rw-r--r--lib/bundler/plugin/source_list.rb2
-rw-r--r--lib/bundler/remote_specification.rb2
-rw-r--r--lib/bundler/resolver.rb129
-rw-r--r--lib/bundler/resolver/base.rb3
-rw-r--r--lib/bundler/resolver/package.rb3
-rw-r--r--lib/bundler/resolver/strategy.rb9
-rw-r--r--lib/bundler/retry.rb34
-rw-r--r--lib/bundler/ruby_dsl.rb29
-rw-r--r--lib/bundler/ruby_version.rb6
-rw-r--r--lib/bundler/rubygems_ext.rb271
-rw-r--r--lib/bundler/rubygems_gem_installer.rb38
-rw-r--r--lib/bundler/rubygems_integration.rb25
-rw-r--r--lib/bundler/runtime.rb17
-rw-r--r--lib/bundler/self_manager.rb77
-rw-r--r--lib/bundler/settings.rb54
-rw-r--r--lib/bundler/settings/validator.rb26
-rw-r--r--lib/bundler/shared_helpers.rb33
-rw-r--r--lib/bundler/similarity_detector.rb63
-rw-r--r--lib/bundler/source.rb4
-rw-r--r--lib/bundler/source/gemspec.rb4
-rw-r--r--lib/bundler/source/git.rb14
-rw-r--r--lib/bundler/source/git/git_proxy.rb91
-rw-r--r--lib/bundler/source/metadata.rb4
-rw-r--r--lib/bundler/source/path.rb24
-rw-r--r--lib/bundler/source/path/installer.rb2
-rw-r--r--lib/bundler/source/rubygems.rb170
-rw-r--r--lib/bundler/source/rubygems/remote.rb14
-rw-r--r--lib/bundler/source/rubygems_aggregate.rb5
-rw-r--r--lib/bundler/source_list.rb63
-rw-r--r--lib/bundler/source_map.rb15
-rw-r--r--lib/bundler/spec_set.rb87
-rw-r--r--lib/bundler/stub_specification.rb1
-rw-r--r--lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt136
-rw-r--r--lib/bundler/templates/newgem/Cargo.toml.tt6
-rw-r--r--lib/bundler/templates/newgem/Gemfile.tt8
-rw-r--r--lib/bundler/templates/newgem/Rakefile.tt5
-rw-r--r--lib/bundler/templates/newgem/circleci/config.yml.tt12
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt9
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/build.rs.tt5
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt11
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/go.mod.tt5
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt2
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/newgem.go.tt31
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt15
-rw-r--r--lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt69
-rw-r--r--lib/bundler/templates/newgem/github/workflows/main.yml.tt13
-rw-r--r--lib/bundler/templates/newgem/gitlab-ci.yml.tt9
-rw-r--r--lib/bundler/templates/newgem/lib/newgem.rb.tt2
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt32
-rw-r--r--lib/bundler/templates/newgem/spec/newgem_spec.rb.tt8
-rw-r--r--lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt6
-rw-r--r--lib/bundler/ui/shell.rb20
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool.rb59
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb65
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb2
-rw-r--r--lib/bundler/vendor/fileutils/lib/fileutils.rb109
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb126
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb3
-rw-r--r--lib/bundler/vendor/thor/lib/thor.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb48
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/options.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/runner.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/basic.rb10
-rw-r--r--lib/bundler/vendor/thor/lib/thor/version.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/common.rb72
-rw-r--r--lib/bundler/vendor/uri/lib/uri/file.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/generic.rb55
-rw-r--r--lib/bundler/vendor/uri/lib/uri/http.rb12
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb17
-rw-r--r--lib/bundler/vendor/uri/lib/uri/version.rb4
-rw-r--r--lib/bundler/version.rb12
-rw-r--r--lib/bundler/vlad.rb15
-rw-r--r--lib/bundler/worker.rb14
-rw-r--r--lib/cgi.rb300
-rw-r--r--lib/cgi/cgi.gemspec43
-rw-r--r--lib/cgi/cookie.rb210
-rw-r--r--lib/cgi/core.rb900
-rw-r--r--lib/cgi/escape.rb232
-rw-r--r--lib/cgi/html.rb1035
-rw-r--r--lib/cgi/session.rb562
-rw-r--r--lib/cgi/session/pstore.rb91
-rw-r--r--lib/cgi/util.rb261
-rw-r--r--lib/delegate.rb67
-rw-r--r--lib/did_you_mean.rb4
-rw-r--r--lib/erb.gemspec38
-rw-r--r--lib/erb.rb1274
-rw-r--r--lib/erb/compiler.rb13
-rw-r--r--lib/erb/def_method.rb2
-rw-r--r--lib/erb/erb.gemspec37
-rw-r--r--lib/erb/util.rb68
-rw-r--r--lib/erb/version.rb4
-rw-r--r--lib/error_highlight/base.rb198
-rw-r--r--lib/error_highlight/core_ext.rb35
-rw-r--r--lib/error_highlight/error_highlight.gemspec2
-rw-r--r--lib/error_highlight/formatter.rb4
-rw-r--r--lib/error_highlight/version.rb2
-rw-r--r--lib/fileutils.rb109
-rw-r--r--lib/find.rb83
-rw-r--r--lib/forwardable.rb51
-rw-r--r--lib/forwardable/forwardable.gemspec2
-rw-r--r--lib/forwardable/impl.rb17
-rw-r--r--lib/ipaddr.gemspec2
-rw-r--r--lib/ipaddr.rb56
-rw-r--r--lib/mkmf.rb51
-rw-r--r--lib/monitor.rb216
-rw-r--r--lib/net/http.rb100
-rw-r--r--lib/net/http/exceptions.rb3
-rw-r--r--lib/net/http/generic_request.rb45
-rw-r--r--lib/net/http/header.rb12
-rw-r--r--lib/net/http/net-http.gemspec9
-rw-r--r--lib/net/http/requests.rb64
-rw-r--r--lib/net/http/response.rb3
-rw-r--r--lib/net/http/responses.rb72
-rw-r--r--lib/net/net-protocol.gemspec5
-rw-r--r--lib/net/protocol.rb15
-rw-r--r--lib/open-uri.rb25
-rw-r--r--lib/open3/version.rb1
-rw-r--r--lib/optparse.rb109
-rw-r--r--lib/optparse/optparse.gemspec7
-rw-r--r--lib/pathname.rb151
-rw-r--r--lib/pp.rb76
-rw-r--r--lib/prettyprint.rb19
-rw-r--r--lib/prism.rb93
-rw-r--r--lib/prism/desugar_compiler.rb140
-rw-r--r--lib/prism/ffi.rb181
-rw-r--r--lib/prism/lex_compat.rb469
-rw-r--r--lib/prism/node_ext.rb348
-rw-r--r--lib/prism/node_find.rb185
-rw-r--r--lib/prism/pack.rb228
-rw-r--r--lib/prism/parse_result.rb515
-rw-r--r--lib/prism/parse_result/comments.rb44
-rw-r--r--lib/prism/parse_result/errors.rb9
-rw-r--r--lib/prism/parse_result/newlines.rb60
-rw-r--r--lib/prism/pattern.rb84
-rw-r--r--lib/prism/polyfill/scan_byte.rb14
-rw-r--r--lib/prism/polyfill/warn.rb38
-rw-r--r--lib/prism/prism.gemspec189
-rw-r--r--lib/prism/relocation.rb187
-rw-r--r--lib/prism/string_query.rb18
-rw-r--r--lib/prism/translation.rb11
-rw-r--r--lib/prism/translation/parser.rb18
-rw-r--r--lib/prism/translation/parser/builder.rb13
-rw-r--r--lib/prism/translation/parser/compiler.rb75
-rw-r--r--lib/prism/translation/parser/lexer.rb59
-rw-r--r--lib/prism/translation/parser33.rb12
-rw-r--r--lib/prism/translation/parser34.rb12
-rw-r--r--lib/prism/translation/parser35.rb12
-rw-r--r--lib/prism/translation/parser_current.rb10
-rw-r--r--lib/prism/translation/parser_versions.rb36
-rw-r--r--lib/prism/translation/ripper.rb1239
-rw-r--r--lib/prism/translation/ripper/filter.rb53
-rw-r--r--lib/prism/translation/ripper/lexer.rb133
-rw-r--r--lib/prism/translation/ripper/sexp.rb13
-rw-r--r--lib/prism/translation/ripper/shim.rb2
-rw-r--r--lib/prism/translation/ruby_parser.rb106
-rw-r--r--lib/resolv.gemspec5
-rw-r--r--lib/resolv.rb189
-rw-r--r--lib/rubygems.rb177
-rw-r--r--lib/rubygems/basic_specification.rb19
-rw-r--r--lib/rubygems/bundler_version_finder.rb80
-rw-r--r--lib/rubygems/command.rb2
-rw-r--r--lib/rubygems/command_manager.rb7
-rw-r--r--lib/rubygems/commands/build_command.rb7
-rw-r--r--lib/rubygems/commands/cert_command.rb2
-rw-r--r--lib/rubygems/commands/environment_command.rb1
-rw-r--r--lib/rubygems/commands/exec_command.rb3
-rw-r--r--lib/rubygems/commands/fetch_command.rb2
-rw-r--r--lib/rubygems/commands/help_command.rb4
-rw-r--r--lib/rubygems/commands/install_command.rb11
-rw-r--r--lib/rubygems/commands/owner_command.rb5
-rw-r--r--lib/rubygems/commands/pristine_command.rb30
-rw-r--r--lib/rubygems/commands/push_command.rb89
-rw-r--r--lib/rubygems/commands/query_command.rb43
-rw-r--r--lib/rubygems/commands/rebuild_command.rb1
-rw-r--r--lib/rubygems/commands/setup_command.rb14
-rw-r--r--lib/rubygems/commands/sources_command.rb167
-rw-r--r--lib/rubygems/commands/specification_command.rb8
-rw-r--r--lib/rubygems/commands/uninstall_command.rb2
-rw-r--r--lib/rubygems/compatibility.rb41
-rw-r--r--lib/rubygems/config_file.rb52
-rw-r--r--lib/rubygems/core_ext/kernel_require.rb7
-rw-r--r--lib/rubygems/defaults.rb11
-rw-r--r--lib/rubygems/dependency.rb2
-rw-r--r--lib/rubygems/dependency_installer.rb83
-rw-r--r--lib/rubygems/dependency_list.rb3
-rw-r--r--lib/rubygems/deprecate.rb146
-rw-r--r--lib/rubygems/doctor.rb2
-rw-r--r--lib/rubygems/errors.rb2
-rw-r--r--lib/rubygems/exceptions.rb74
-rw-r--r--lib/rubygems/ext/builder.rb54
-rw-r--r--lib/rubygems/ext/cargo_builder.rb21
-rw-r--r--lib/rubygems/ext/cmake_builder.rb105
-rw-r--r--lib/rubygems/ext/configure_builder.rb6
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb10
-rw-r--r--lib/rubygems/ext/rake_builder.rb8
-rw-r--r--lib/rubygems/gem_runner.rb1
-rw-r--r--lib/rubygems/gemcutter_utilities.rb14
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_listener.rb13
-rw-r--r--lib/rubygems/install_default_message.rb13
-rw-r--r--lib/rubygems/install_update_options.rb24
-rw-r--r--lib/rubygems/installer.rb219
-rw-r--r--lib/rubygems/name_tuple.rb8
-rw-r--r--lib/rubygems/package.rb93
-rw-r--r--lib/rubygems/package/tar_header.rb8
-rw-r--r--lib/rubygems/package/tar_reader.rb2
-rw-r--r--lib/rubygems/package/tar_writer.rb9
-rw-r--r--lib/rubygems/platform.rb223
-rw-r--r--lib/rubygems/psych_tree.rb2
-rw-r--r--lib/rubygems/remote_fetcher.rb35
-rw-r--r--lib/rubygems/request.rb1
-rw-r--r--lib/rubygems/request/connection_pools.rb7
-rw-r--r--lib/rubygems/request/http_pool.rb15
-rw-r--r--lib/rubygems/request_set.rb80
-rw-r--r--lib/rubygems/request_set/lockfile.rb4
-rw-r--r--lib/rubygems/request_set/lockfile/parser.rb344
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb122
-rw-r--r--lib/rubygems/resolver.rb528
-rw-r--r--lib/rubygems/resolver/api_set.rb10
-rw-r--r--lib/rubygems/resolver/api_set/gem_parser.rb9
-rw-r--r--lib/rubygems/resolver/api_specification.rb6
-rw-r--r--lib/rubygems/resolver/best_set.rb2
-rw-r--r--lib/rubygems/resolver/conflict.rb146
-rw-r--r--lib/rubygems/resolver/incompatibility.rb10
-rw-r--r--lib/rubygems/resolver/installer_set.rb2
-rw-r--r--lib/rubygems/resolver/source_set.rb2
-rw-r--r--lib/rubygems/resolver/stats.rb46
-rw-r--r--lib/rubygems/resolver/strategy.rb44
-rw-r--r--lib/rubygems/s3_uri_signer.rb69
-rw-r--r--lib/rubygems/safe_marshal.rb1
-rw-r--r--lib/rubygems/safe_yaml.rb16
-rw-r--r--lib/rubygems/security/policy.rb2
-rw-r--r--lib/rubygems/security/signer.rb2
-rw-r--r--lib/rubygems/shellwords.rb3
-rw-r--r--lib/rubygems/source.rb58
-rw-r--r--lib/rubygems/source/local.rb6
-rw-r--r--lib/rubygems/source_list.rb36
-rw-r--r--lib/rubygems/spec_fetcher.rb8
-rw-r--r--lib/rubygems/specification.rb182
-rw-r--r--lib/rubygems/specification_policy.rb83
-rw-r--r--lib/rubygems/specification_record.rb15
-rw-r--r--lib/rubygems/ssl_certs/rubygems.org/GlobalSign.pem (renamed from lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem)0
-rw-r--r--lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem21
-rw-r--r--lib/rubygems/stub_specification.rb1
-rw-r--r--lib/rubygems/text.rb2
-rw-r--r--lib/rubygems/uninstaller.rb23
-rw-r--r--lib/rubygems/uri_formatter.rb3
-rw-r--r--lib/rubygems/user_interaction.rb15
-rw-r--r--lib/rubygems/util.rb22
-rw-r--r--lib/rubygems/util/atomic_file_writer.rb76
-rw-r--r--lib/rubygems/util/licenses.rb54
-rw-r--r--lib/rubygems/util/list.rb40
-rw-r--r--lib/rubygems/validator.rb2
-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/lib/net/http.rb148
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb3
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb45
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/header.rb12
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/requests.rb16
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/response.rb3
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/responses.rb72
-rw-r--r--lib/rubygems/vendor/optparse/lib/optparse.rb123
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub.rb53
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb20
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb169
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb182
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb150
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb43
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb121
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb45
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb19
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb61
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb42
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb105
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb3
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb129
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb423
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb236
-rw-r--r--lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb178
-rw-r--r--lib/rubygems/vendor/resolv/lib/resolv.rb104
-rw-r--r--lib/rubygems/vendor/timeout/lib/timeout.rb5
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/common.rb72
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/file.rb2
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/generic.rb55
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/http.rb12
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb17
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/version.rb4
-rw-r--r--lib/rubygems/vendored_molinillo.rb3
-rw-r--r--lib/rubygems/vendored_pub_grub.rb3
-rw-r--r--lib/rubygems/version.rb355
-rw-r--r--lib/rubygems/win_platform.rb30
-rw-r--r--lib/rubygems/yaml_serializer.rb889
-rw-r--r--lib/set.rb855
-rw-r--r--lib/set/set.gemspec30
-rw-r--r--lib/set/sorted_set.rb6
-rw-r--r--lib/set/subclass_compatible.rb347
-rw-r--r--lib/shellwords.gemspec2
-rw-r--r--lib/singleton.rb11
-rw-r--r--lib/syntax_suggest/api.rb53
-rw-r--r--lib/syntax_suggest/clean_document.rb105
-rw-r--r--lib/syntax_suggest/code_line.rb134
-rw-r--r--lib/syntax_suggest/core_ext.rb127
-rw-r--r--lib/syntax_suggest/explain_syntax.rb18
-rw-r--r--lib/syntax_suggest/left_right_lex_count.rb168
-rw-r--r--lib/syntax_suggest/left_right_token_count.rb162
-rw-r--r--lib/syntax_suggest/lex_all.rb74
-rw-r--r--lib/syntax_suggest/lex_value.rb70
-rw-r--r--lib/syntax_suggest/ripper_errors.rb39
-rw-r--r--lib/syntax_suggest/syntax_suggest.gemspec2
-rw-r--r--lib/syntax_suggest/token.rb49
-rw-r--r--lib/syntax_suggest/version.rb2
-rw-r--r--lib/syntax_suggest/visitor.rb80
-rw-r--r--lib/tempfile.rb8
-rw-r--r--lib/time.gemspec1
-rw-r--r--lib/time.rb15
-rw-r--r--lib/timeout.rb264
-rw-r--r--lib/tsort.gemspec29
-rw-r--r--lib/tsort.rb455
-rw-r--r--lib/unicode_normalize/normalize.rb30
-rw-r--r--lib/unicode_normalize/tables.rb186
-rw-r--r--lib/uri/common.rb70
-rw-r--r--lib/uri/generic.rb55
-rw-r--r--lib/uri/http.rb12
-rw-r--r--lib/uri/rfc2396_parser.rb17
-rw-r--r--lib/uri/version.rb4
-rw-r--r--lib/weakref.rb3
-rw-r--r--lib/yaml.rb1
-rwxr-xr-xlibexec/erb50
-rw-r--r--load.c557
-rw-r--r--man/erb.14
-rw-r--r--man/goruby.14
-rw-r--r--man/ruby.123
-rw-r--r--marshal.c239
-rw-r--r--math.c74
-rw-r--r--memory_view.c29
-rw-r--r--method.h23
-rw-r--r--mini_builtin.c21
-rw-r--r--misc/.vscode/settings.json4
-rwxr-xr-xmisc/expand_tabs.rb34
-rwxr-xr-xmisc/jit_perf.py116
-rw-r--r--[-rwxr-xr-x]misc/lldb_cruby.py22
-rw-r--r--misc/lldb_rb/commands/heap_page_command.py5
-rw-r--r--misc/lldb_rb/commands/print_flags_command.py4
-rw-r--r--misc/lldb_rb/lldb_interface.py11
-rw-r--r--misc/lldb_rb/rb_heap_structs.py19
-rw-r--r--misc/lldb_rb/utils.py35
-rw-r--r--misc/tsan_suppressions.txt109
-rwxr-xr-xmisc/yjit_perf.py116
-rw-r--r--missing/dtoa.c298
-rw-r--r--nilclass.rb38
-rw-r--r--node_dump.c23
-rw-r--r--numeric.c751
-rw-r--r--numeric.rb19
-rw-r--r--object.c690
-rw-r--r--pack.c134
-rw-r--r--pack.rb24
-rw-r--r--parse.y1726
-rw-r--r--parser_bits.h133
-rw-r--r--parser_st.c6
-rw-r--r--parser_st.h5
-rw-r--r--pathname.c372
-rw-r--r--pathname_builtin.rb1895
-rw-r--r--prelude.rb17
-rw-r--r--prism/api_pack.c276
-rw-r--r--prism/arena.c117
-rw-r--r--prism/arena.h37
-rw-r--r--prism/buffer.c374
-rw-r--r--prism/buffer.h52
-rw-r--r--prism/char.c274
-rw-r--r--prism/comments.h43
-rw-r--r--prism/compiler/accel.h19
-rw-r--r--prism/compiler/align.h36
-rw-r--r--prism/compiler/exported.h24
-rw-r--r--prism/compiler/fallthrough.h22
-rw-r--r--prism/compiler/filesystem.h32
-rw-r--r--prism/compiler/flex_array.h19
-rw-r--r--prism/compiler/force_inline.h21
-rw-r--r--prism/compiler/format.h25
-rw-r--r--prism/compiler/inline.h17
-rw-r--r--prism/compiler/nodiscard.h22
-rw-r--r--prism/compiler/nonnull.h18
-rw-r--r--prism/compiler/unused.h18
-rw-r--r--prism/config.yml588
-rw-r--r--prism/constant_pool.c360
-rw-r--r--prism/constant_pool.h81
-rw-r--r--prism/defines.h260
-rw-r--r--prism/diagnostic.h93
-rw-r--r--prism/encoding.c248
-rw-r--r--prism/encoding.h283
-rw-r--r--prism/excludes.h29
-rw-r--r--prism/extension.c764
-rw-r--r--prism/extension.h4
-rw-r--r--prism/integer.c681
-rw-r--r--prism/integer.h41
-rw-r--r--prism/internal/allocator.h68
-rw-r--r--prism/internal/allocator_debug.h88
-rw-r--r--prism/internal/arena.h108
-rw-r--r--prism/internal/bit.h42
-rw-r--r--prism/internal/buffer.h91
-rw-r--r--prism/internal/char.h139
-rw-r--r--prism/internal/comments.h20
-rw-r--r--prism/internal/constant_pool.h117
-rw-r--r--prism/internal/encoding.h242
-rw-r--r--prism/internal/integer.h68
-rw-r--r--prism/internal/isinf.h16
-rw-r--r--prism/internal/line_offset_list.h34
-rw-r--r--prism/internal/list.h62
-rw-r--r--prism/internal/magic_comments.h23
-rw-r--r--prism/internal/memchr.h15
-rw-r--r--prism/internal/node.h32
-rw-r--r--prism/internal/options.h212
-rw-r--r--prism/internal/parser.h958
-rw-r--r--prism/internal/regexp.h41
-rw-r--r--prism/internal/serialize.h34
-rw-r--r--prism/internal/source.h72
-rw-r--r--prism/internal/static_literals.h98
-rw-r--r--prism/internal/stringy.h30
-rw-r--r--prism/internal/strncasecmp.h18
-rw-r--r--prism/internal/strpbrk.h33
-rw-r--r--prism/internal/tokens.h11
-rw-r--r--prism/json.h32
-rw-r--r--prism/line_offset_list.c100
-rw-r--r--prism/line_offset_list.h61
-rw-r--r--prism/list.c24
-rw-r--r--prism/magic_comments.h35
-rw-r--r--prism/memchr.c37
-rw-r--r--prism/node.h71
-rw-r--r--prism/options.c204
-rw-r--r--prism/options.h355
-rw-r--r--prism/pack.c509
-rw-r--r--prism/pack.h163
-rw-r--r--prism/parser.c302
-rw-r--r--prism/parser.h1155
-rw-r--r--prism/prettyprint.h15
-rw-r--r--prism/prism.c13032
-rw-r--r--prism/prism.h349
-rw-r--r--prism/regexp.c1015
-rw-r--r--prism/regexp.h43
-rw-r--r--prism/serialize.h96
-rw-r--r--prism/source.c491
-rw-r--r--prism/source.h148
-rw-r--r--prism/srcs.mk160
-rw-r--r--prism/srcs.mk.in52
-rw-r--r--prism/static_literals.c70
-rw-r--r--prism/static_literals.h121
-rw-r--r--prism/stream.h28
-rw-r--r--prism/string_query.c166
-rw-r--r--prism/string_query.h63
-rw-r--r--prism/stringy.c91
-rw-r--r--prism/stringy.h72
-rw-r--r--prism/strncasecmp.c37
-rw-r--r--prism/strpbrk.c439
-rw-r--r--prism/templates/ext/prism/api_node.c.erb92
-rw-r--r--prism/templates/include/prism/ast.h.erb118
-rw-r--r--prism/templates/include/prism/diagnostic.h.erb130
-rw-r--r--prism/templates/include/prism/internal/diagnostic.h.erb60
-rw-r--r--prism/templates/lib/prism/compiler.rb.erb23
-rw-r--r--prism/templates/lib/prism/dispatcher.rb.erb38
-rw-r--r--prism/templates/lib/prism/dot_visitor.rb.erb51
-rw-r--r--prism/templates/lib/prism/dsl.rb.erb47
-rw-r--r--prism/templates/lib/prism/inspect_visitor.rb.erb36
-rw-r--r--prism/templates/lib/prism/mutation_compiler.rb.erb7
-rw-r--r--prism/templates/lib/prism/node.rb.erb413
-rw-r--r--prism/templates/lib/prism/reflection.rb.erb13
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb298
-rw-r--r--prism/templates/lib/prism/visitor.rb.erb26
-rw-r--r--prism/templates/src/diagnostic.c.erb153
-rw-r--r--prism/templates/src/json.c.erb130
-rw-r--r--prism/templates/src/node.c.erb281
-rw-r--r--prism/templates/src/prettyprint.c.erb37
-rw-r--r--prism/templates/src/serialize.c.erb222
-rw-r--r--prism/templates/src/token_type.c.erb369
-rw-r--r--prism/templates/src/tokens.c.erb367
-rwxr-xr-xprism/templates/template.rb209
-rw-r--r--prism/util/pm_buffer.c357
-rw-r--r--prism/util/pm_buffer.h228
-rw-r--r--prism/util/pm_char.c318
-rw-r--r--prism/util/pm_char.h204
-rw-r--r--prism/util/pm_constant_pool.c342
-rw-r--r--prism/util/pm_constant_pool.h218
-rw-r--r--prism/util/pm_integer.c670
-rw-r--r--prism/util/pm_integer.h126
-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.c125
-rw-r--r--prism/util/pm_newline_list.h113
-rw-r--r--prism/util/pm_string.c383
-rw-r--r--prism/util/pm_string.h190
-rw-r--r--prism/util/pm_strncasecmp.c36
-rw-r--r--prism/util/pm_strncasecmp.h32
-rw-r--r--prism/util/pm_strpbrk.c206
-rw-r--r--prism/util/pm_strpbrk.h46
-rw-r--r--prism/version.h13
-rw-r--r--prism_compile.c1971
-rw-r--r--prism_compile.h115
-rw-r--r--prism_xallocator.h6
-rw-r--r--proc.c615
-rw-r--r--process.c50
-rw-r--r--ractor.c2576
-rw-r--r--ractor.rb929
-rw-r--r--ractor_core.h191
-rw-r--r--ractor_sync.c1489
-rw-r--r--random.c292
-rw-r--r--range.c61
-rw-r--r--rational.c254
-rw-r--r--re.c683
-rw-r--r--regcomp.c2425
-rw-r--r--regenc.c103
-rw-r--r--regenc.h17
-rw-r--r--regerror.c107
-rw-r--r--regexec.c3019
-rw-r--r--regint.h22
-rw-r--r--regparse.c2628
-rw-r--r--regparse.h6
-rw-r--r--ruby.c247
-rw-r--r--ruby.rs4
-rw-r--r--ruby_atomic.h90
-rw-r--r--ruby_parser.c2
-rw-r--r--rubyparser.h38
-rw-r--r--sample/drb/README.ja.rdoc59
-rw-r--r--sample/drb/README.rdoc56
-rw-r--r--sample/drb/acl.rb15
-rw-r--r--sample/drb/darray.rb12
-rw-r--r--sample/drb/darrayc.rb47
-rw-r--r--sample/drb/dbiff.rb51
-rw-r--r--sample/drb/dcdbiff.rb43
-rw-r--r--sample/drb/dchatc.rb41
-rw-r--r--sample/drb/dchats.rb69
-rw-r--r--sample/drb/dhasen.rb41
-rw-r--r--sample/drb/dhasenc.rb14
-rw-r--r--sample/drb/dlogc.rb16
-rw-r--r--sample/drb/dlogd.rb38
-rw-r--r--sample/drb/dqin.rb13
-rw-r--r--sample/drb/dqlib.rb14
-rw-r--r--sample/drb/dqout.rb14
-rw-r--r--sample/drb/dqueue.rb11
-rw-r--r--sample/drb/drbc.rb45
-rw-r--r--sample/drb/drbch.rb48
-rw-r--r--sample/drb/drbm.rb60
-rw-r--r--sample/drb/drbmc.rb22
-rw-r--r--sample/drb/drbs-acl.rb51
-rw-r--r--sample/drb/drbs.rb64
-rw-r--r--sample/drb/drbssl_c.rb19
-rw-r--r--sample/drb/drbssl_s.rb31
-rw-r--r--sample/drb/extserv_test.rb80
-rw-r--r--sample/drb/gw_ct.rb29
-rw-r--r--sample/drb/gw_cu.rb28
-rw-r--r--sample/drb/gw_s.rb10
-rw-r--r--sample/drb/holderc.rb22
-rw-r--r--sample/drb/holders.rb63
-rw-r--r--sample/drb/http0.rb77
-rw-r--r--sample/drb/http0serv.rb120
-rw-r--r--sample/drb/name.rb117
-rw-r--r--sample/drb/namec.rb36
-rw-r--r--sample/drb/old_tuplespace.rb212
-rw-r--r--sample/drb/rinda_ts.rb7
-rw-r--r--sample/drb/rindac.rb17
-rw-r--r--sample/drb/rindas.rb18
-rw-r--r--sample/drb/ring_echo.rb29
-rw-r--r--sample/drb/ring_inspect.rb30
-rw-r--r--sample/drb/ring_place.rb25
-rw-r--r--sample/drb/simpletuple.rb89
-rw-r--r--sample/drb/speedc.rb21
-rw-r--r--sample/drb/speeds.rb31
-rw-r--r--sample/openssl/c_rehash.rb2
-rw-r--r--sample/trick2025/01-omoikane/authors.markdown5
-rw-r--r--sample/trick2025/01-omoikane/bf.rb81
-rw-r--r--sample/trick2025/01-omoikane/entry.rb32
-rw-r--r--sample/trick2025/01-omoikane/remarks.markdown71
-rw-r--r--sample/trick2025/01-omoikane/sample_input.txt35
-rw-r--r--sample/trick2025/01-omoikane/spoiler_rot13.txt470
-rw-r--r--sample/trick2025/02-mame/authors.markdown3
-rw-r--r--sample/trick2025/02-mame/entry.rb34
-rw-r--r--sample/trick2025/02-mame/remarks.markdown141
-rw-r--r--sample/trick2025/02-mame/sample.orig.rb8
-rw-r--r--sample/trick2025/02-mame/test.patch16
-rw-r--r--sample/trick2025/03-tompng/authors.markdown3
-rw-r--r--sample/trick2025/03-tompng/entry.rb74
-rw-r--r--sample/trick2025/03-tompng/remarks.markdown146
-rw-r--r--sample/trick2025/04-tompng/authors.markdown3
-rw-r--r--sample/trick2025/04-tompng/entry.rb36
-rw-r--r--sample/trick2025/04-tompng/remarks.markdown43
-rw-r--r--sample/trick2025/05-tompng/authors.markdown3
-rw-r--r--sample/trick2025/05-tompng/entry.rb118
-rw-r--r--sample/trick2025/05-tompng/remarks.markdown106
-rw-r--r--sample/trick2025/README.md16
-rw-r--r--sample/uumerge.rb2
-rw-r--r--scheduler.c581
-rw-r--r--set.c2311
-rw-r--r--shape.c1458
-rw-r--r--shape.h673
-rw-r--r--signal.c128
-rw-r--r--siphash.c3
-rwxr-xr-xspec/bin/bundle6
-rwxr-xr-xspec/bin/parallel_rspec7
-rwxr-xr-xspec/bin/rspec7
-rw-r--r--spec/bundled_gems_spec.rb88
-rw-r--r--spec/bundler/bundler/build_metadata_spec.rb23
-rw-r--r--spec/bundler/bundler/bundler_spec.rb6
-rw-r--r--spec/bundler/bundler/cli_common_spec.rb22
-rw-r--r--spec/bundler/bundler/cli_spec.rb74
-rw-r--r--spec/bundler/bundler/compact_index_client/parser_spec.rb16
-rw-r--r--spec/bundler/bundler/current_ruby_spec.rb35
-rw-r--r--spec/bundler/bundler/definition_spec.rb81
-rw-r--r--spec/bundler/bundler/dsl_spec.rb213
-rw-r--r--spec/bundler/bundler/endpoint_specification_spec.rb40
-rw-r--r--spec/bundler/bundler/env_spec.rb5
-rw-r--r--spec/bundler/bundler/errors_spec.rb91
-rw-r--r--spec/bundler/bundler/fetcher/dependency_spec.rb14
-rw-r--r--spec/bundler/bundler/fetcher/downloader_spec.rb99
-rw-r--r--spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb60
-rw-r--r--spec/bundler/bundler/friendly_errors_spec.rb27
-rw-r--r--spec/bundler/bundler/gem_helper_spec.rb11
-rw-r--r--spec/bundler/bundler/installer/gem_installer_spec.rb8
-rw-r--r--spec/bundler/bundler/installer/parallel_installer_spec.rb79
-rw-r--r--spec/bundler/bundler/installer/spec_installation_spec.rb79
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb82
-rw-r--r--spec/bundler/bundler/override_spec.rb175
-rw-r--r--spec/bundler/bundler/plugin/events_spec.rb12
-rw-r--r--spec/bundler/bundler/plugin/index_spec.rb79
-rw-r--r--spec/bundler/bundler/plugin/installer_spec.rb7
-rw-r--r--spec/bundler/bundler/plugin_spec.rb24
-rw-r--r--spec/bundler/bundler/resolver/cooldown_spec.rb148
-rw-r--r--spec/bundler/bundler/retry_spec.rb111
-rw-r--r--spec/bundler/bundler/ruby_dsl_spec.rb37
-rw-r--r--spec/bundler/bundler/ruby_version_spec.rb22
-rw-r--r--spec/bundler/bundler/rubygems_ext_spec.rb39
-rw-r--r--spec/bundler/bundler/settings_spec.rb34
-rw-r--r--spec/bundler/bundler/shared_helpers_spec.rb34
-rw-r--r--spec/bundler/bundler/source/git/git_proxy_spec.rb139
-rw-r--r--spec/bundler/bundler/source/rubygems/remote_spec.rb35
-rw-r--r--spec/bundler/bundler/source/rubygems_spec.rb57
-rw-r--r--spec/bundler/bundler/source_list_spec.rb42
-rw-r--r--spec/bundler/bundler/spec_set_spec.rb89
-rw-r--r--spec/bundler/bundler/specifications/foo.gemspec2
-rw-r--r--spec/bundler/bundler/stub_specification_spec.rb8
-rw-r--r--spec/bundler/bundler/ui/shell_spec.rb28
-rw-r--r--spec/bundler/bundler/uri_normalizer_spec.rb25
-rw-r--r--spec/bundler/bundler/worker_spec.rb20
-rw-r--r--spec/bundler/cache/cache_path_spec.rb2
-rw-r--r--spec/bundler/cache/gems_spec.rb28
-rw-r--r--spec/bundler/cache/git_spec.rb73
-rw-r--r--spec/bundler/cache/path_spec.rb54
-rw-r--r--spec/bundler/commands/add_spec.rb143
-rw-r--r--spec/bundler/commands/binstubs_spec.rb34
-rw-r--r--spec/bundler/commands/cache_spec.rb195
-rw-r--r--spec/bundler/commands/check_spec.rb81
-rw-r--r--spec/bundler/commands/clean_spec.rb198
-rw-r--r--spec/bundler/commands/config_spec.rb62
-rw-r--r--spec/bundler/commands/console_spec.rb32
-rw-r--r--spec/bundler/commands/doctor_spec.rb29
-rw-r--r--spec/bundler/commands/exec_spec.rb176
-rw-r--r--spec/bundler/commands/fund_spec.rb2
-rw-r--r--spec/bundler/commands/info_spec.rb6
-rw-r--r--spec/bundler/commands/init_spec.rb2
-rw-r--r--spec/bundler/commands/inject_spec.rb117
-rw-r--r--spec/bundler/commands/install_spec.rb470
-rw-r--r--spec/bundler/commands/licenses_spec.rb2
-rw-r--r--spec/bundler/commands/list_spec.rb120
-rw-r--r--spec/bundler/commands/lock_spec.rb699
-rw-r--r--spec/bundler/commands/newgem_spec.rb1883
-rw-r--r--spec/bundler/commands/open_spec.rb8
-rw-r--r--spec/bundler/commands/outdated_spec.rb142
-rw-r--r--spec/bundler/commands/platform_spec.rb118
-rw-r--r--spec/bundler/commands/post_bundle_message_spec.rb214
-rw-r--r--spec/bundler/commands/pristine_spec.rb74
-rw-r--r--spec/bundler/commands/remove_spec.rb15
-rw-r--r--spec/bundler/commands/show_spec.rb55
-rw-r--r--spec/bundler/commands/ssl_spec.rb373
-rw-r--r--spec/bundler/commands/update_spec.rb268
-rw-r--r--spec/bundler/commands/version_spec.rb50
-rw-r--r--spec/bundler/commands/viz_spec.rb144
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb10
-rw-r--r--spec/bundler/install/binstubs_spec.rb2
-rw-r--r--spec/bundler/install/bundler_spec.rb10
-rw-r--r--spec/bundler/install/cooldown_spec.rb272
-rw-r--r--spec/bundler/install/deploy_spec.rb137
-rw-r--r--spec/bundler/install/failure_spec.rb34
-rw-r--r--spec/bundler/install/force_spec.rb71
-rw-r--r--spec/bundler/install/gemfile/eval_gemfile_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/force_ruby_platform_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb88
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb124
-rw-r--r--spec/bundler/install/gemfile/groups_spec.rb110
-rw-r--r--spec/bundler/install/gemfile/install_if_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/lockfile_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/override_spec.rb401
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb113
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb28
-rw-r--r--spec/bundler/install/gemfile/ruby_spec.rb4
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb1157
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb235
-rw-r--r--spec/bundler/install/gemfile_spec.rb31
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb152
-rw-r--r--spec/bundler/install/gems/dependency_api_fallback_spec.rb36
-rw-r--r--spec/bundler/install/gems/dependency_api_spec.rb144
-rw-r--r--spec/bundler/install/gems/flex_spec.rb10
-rw-r--r--spec/bundler/install/gems/fund_spec.rb2
-rw-r--r--spec/bundler/install/gems/gemfile_source_header_spec.rb24
-rw-r--r--spec/bundler/install/gems/mirror_probe_spec.rb68
-rw-r--r--spec/bundler/install/gems/mirror_spec.rb4
-rw-r--r--spec/bundler/install/gems/native_extensions_spec.rb18
-rw-r--r--spec/bundler/install/gems/no_build_extension_spec.rb54
-rw-r--r--spec/bundler/install/gems/no_install_plugin_spec.rb53
-rw-r--r--spec/bundler/install/gems/post_install_spec.rb4
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb38
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb145
-rw-r--r--spec/bundler/install/gemspecs_spec.rb6
-rw-r--r--spec/bundler/install/git_spec.rb90
-rw-r--r--spec/bundler/install/global_cache_spec.rb34
-rw-r--r--spec/bundler/install/path_spec.rb82
-rw-r--r--spec/bundler/install/process_lock_spec.rb56
-rw-r--r--spec/bundler/install/redownload_spec.rb91
-rw-r--r--spec/bundler/install/yanked_spec.rb8
-rw-r--r--spec/bundler/lock/git_spec.rb43
-rw-r--r--spec/bundler/lock/lockfile_spec.rb254
-rw-r--r--spec/bundler/other/cli_dispatch_spec.rb6
-rw-r--r--spec/bundler/other/cli_man_pages_spec.rb95
-rw-r--r--spec/bundler/other/ext_spec.rb45
-rw-r--r--spec/bundler/other/major_deprecation_spec.rb518
-rw-r--r--spec/bundler/plugins/command_spec.rb34
-rw-r--r--spec/bundler/plugins/hook_spec.rb123
-rw-r--r--spec/bundler/plugins/install_spec.rb48
-rw-r--r--spec/bundler/plugins/source/example_spec.rb16
-rw-r--r--spec/bundler/quality_es_spec.rb4
-rw-r--r--spec/bundler/quality_spec.rb20
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb137
-rw-r--r--spec/bundler/realworld/ffi_spec.rb4
-rw-r--r--spec/bundler/realworld/fixtures/tapioca/Gemfile.lock6
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile4
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile.lock31
-rw-r--r--spec/bundler/realworld/gemfile_source_header_spec.rb54
-rw-r--r--spec/bundler/realworld/mirror_probe_spec.rb132
-rw-r--r--spec/bundler/realworld/slow_perf_spec.rb111
-rw-r--r--spec/bundler/resolver/basic_spec.rb2
-rw-r--r--spec/bundler/resolver/platform_spec.rb44
-rw-r--r--spec/bundler/runtime/env_helpers_spec.rb103
-rw-r--r--spec/bundler/runtime/executable_spec.rb40
-rw-r--r--spec/bundler/runtime/gem_tasks_spec.rb15
-rw-r--r--spec/bundler/runtime/inline_spec.rb87
-rw-r--r--spec/bundler/runtime/load_spec.rb2
-rw-r--r--spec/bundler/runtime/platform_spec.rb28
-rw-r--r--spec/bundler/runtime/requiring_spec.rb8
-rw-r--r--spec/bundler/runtime/self_management_spec.rb110
-rw-r--r--spec/bundler/runtime/setup_spec.rb121
-rw-r--r--spec/bundler/spec_helper.rb88
-rw-r--r--spec/bundler/support/artifice/compact_index_cooldown.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_etag_match.rb2
-rw-r--r--spec/bundler/support/artifice/compact_index_mirror_down.rb21
-rw-r--r--spec/bundler/support/artifice/compact_index_no_checksums.rb16
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index.rb10
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index_cooldown.rb13
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint.rb2
-rw-r--r--spec/bundler/support/artifice/vcr.rb2
-rw-r--r--spec/bundler/support/build_metadata.rb12
-rw-r--r--spec/bundler/support/builders.rb175
-rwxr-xr-xspec/bundler/support/bundle6
-rw-r--r--spec/bundler/support/bundle.rb6
-rw-r--r--spec/bundler/support/checksums.rb21
-rw-r--r--spec/bundler/support/command_execution.rb5
-rw-r--r--spec/bundler/support/filters.rb20
-rw-r--r--spec/bundler/support/hax.rb20
-rw-r--r--spec/bundler/support/helpers.rb279
-rw-r--r--spec/bundler/support/indexes.rb2
-rw-r--r--spec/bundler/support/matchers.rb2
-rw-r--r--spec/bundler/support/path.rb133
-rw-r--r--spec/bundler/support/platforms.rb12
-rw-r--r--spec/bundler/support/rubygems_ext.rb154
-rw-r--r--spec/bundler/support/setup.rb9
-rw-r--r--spec/bundler/support/shards.rb200
-rw-r--r--spec/bundler/support/silent_logger.rb10
-rw-r--r--spec/bundler/support/subprocess.rb11
-rw-r--r--spec/bundler/support/switch_rubygems.rb1
-rw-r--r--spec/bundler/support/the_bundle.rb8
-rw-r--r--spec/bundler/update/force_spec.rb30
-rw-r--r--spec/bundler/update/gemfile_spec.rb2
-rw-r--r--spec/bundler/update/git_spec.rb4
-rw-r--r--spec/bundler/update/redownload_spec.rb44
-rw-r--r--spec/default.mspec33
-rw-r--r--spec/mspec/lib/mspec/commands/mspec-ci.rb1
-rw-r--r--spec/mspec/lib/mspec/commands/mspec-tag.rb1
-rw-r--r--spec/mspec/lib/mspec/matchers/base.rb16
-rw-r--r--spec/mspec/lib/mspec/matchers/raise_error.rb63
-rw-r--r--spec/mspec/lib/mspec/runner/formatters/base.rb2
-rw-r--r--spec/mspec/lib/mspec/runner/mspec.rb1
-rw-r--r--spec/mspec/lib/mspec/utils/name_map.rb13
-rw-r--r--spec/mspec/spec/commands/mspec_ci_spec.rb5
-rw-r--r--spec/mspec/spec/commands/mspec_run_spec.rb5
-rw-r--r--spec/mspec/spec/matchers/raise_error_spec.rb73
-rw-r--r--spec/mspec/spec/utils/fixtures/this_file_raises.rb1
-rw-r--r--spec/mspec/spec/utils/fixtures/this_file_raises2.rb1
-rw-r--r--spec/mspec/spec/utils/name_map_spec.rb12
-rwxr-xr-xspec/mspec/tool/remove_old_guards.rb9
-rw-r--r--spec/mspec/tool/sync/sync-rubyspec.rb30
-rwxr-xr-xspec/mspec/tool/tag_from_output.rb2
-rw-r--r--spec/ruby/.rubocop.yml7
-rw-r--r--spec/ruby/.rubocop_todo.yml35
-rw-r--r--spec/ruby/CONTRIBUTING.md51
-rw-r--r--spec/ruby/README.md8
-rwxr-xr-xspec/ruby/bin/rubocop2
-rwxr-xr-xspec/ruby/command_line/dash_0_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_r_spec.rb11
-rw-r--r--spec/ruby/command_line/dash_upper_i_spec.rb10
-rw-r--r--spec/ruby/command_line/dash_upper_s_spec.rb40
-rw-r--r--spec/ruby/command_line/dash_v_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_x_spec.rb2
-rw-r--r--spec/ruby/command_line/error_message_spec.rb5
-rw-r--r--spec/ruby/command_line/feature_spec.rb10
-rw-r--r--spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/fixtures/bin/embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/frozen_strings_spec.rb36
-rw-r--r--spec/ruby/command_line/rubylib_spec.rb16
-rw-r--r--spec/ruby/command_line/rubyopt_spec.rb4
-rw-r--r--spec/ruby/command_line/syntax_error_spec.rb10
-rw-r--r--spec/ruby/core/argf/argf_spec.rb4
-rw-r--r--spec/ruby/core/argf/argv_spec.rb2
-rw-r--r--spec/ruby/core/argf/binmode_spec.rb2
-rw-r--r--spec/ruby/core/argf/close_spec.rb8
-rw-r--r--spec/ruby/core/argf/closed_spec.rb2
-rw-r--r--spec/ruby/core/argf/each_byte_spec.rb58
-rw-r--r--spec/ruby/core/argf/each_char_spec.rb58
-rw-r--r--spec/ruby/core/argf/each_codepoint_spec.rb58
-rw-r--r--spec/ruby/core/argf/each_line_spec.rb62
-rw-r--r--spec/ruby/core/argf/each_spec.rb5
-rw-r--r--spec/ruby/core/argf/eof_spec.rb28
-rw-r--r--spec/ruby/core/argf/filename_spec.rb28
-rw-r--r--spec/ruby/core/argf/fileno_spec.rb24
-rw-r--r--spec/ruby/core/argf/inspect_spec.rb7
-rw-r--r--spec/ruby/core/argf/path_spec.rb5
-rw-r--r--spec/ruby/core/argf/pos_spec.rb31
-rw-r--r--spec/ruby/core/argf/read_nonblock_spec.rb2
-rw-r--r--spec/ruby/core/argf/readchar_spec.rb2
-rw-r--r--spec/ruby/core/argf/readline_spec.rb2
-rw-r--r--spec/ruby/core/argf/readlines_spec.rb22
-rw-r--r--spec/ruby/core/argf/readpartial_spec.rb6
-rw-r--r--spec/ruby/core/argf/rewind_spec.rb2
-rw-r--r--spec/ruby/core/argf/seek_spec.rb2
-rw-r--r--spec/ruby/core/argf/shared/each_byte.rb58
-rw-r--r--spec/ruby/core/argf/shared/each_char.rb58
-rw-r--r--spec/ruby/core/argf/shared/each_codepoint.rb58
-rw-r--r--spec/ruby/core/argf/shared/each_line.rb62
-rw-r--r--spec/ruby/core/argf/shared/eof.rb24
-rw-r--r--spec/ruby/core/argf/shared/filename.rb28
-rw-r--r--spec/ruby/core/argf/shared/fileno.rb24
-rw-r--r--spec/ruby/core/argf/shared/pos.rb31
-rw-r--r--spec/ruby/core/argf/shared/readlines.rb22
-rw-r--r--spec/ruby/core/argf/skip_spec.rb2
-rw-r--r--spec/ruby/core/argf/tell_spec.rb5
-rw-r--r--spec/ruby/core/argf/to_a_spec.rb5
-rw-r--r--spec/ruby/core/argf/to_i_spec.rb5
-rw-r--r--spec/ruby/core/argf/to_io_spec.rb2
-rw-r--r--spec/ruby/core/array/allocate_spec.rb4
-rw-r--r--spec/ruby/core/array/append_spec.rb11
-rw-r--r--spec/ruby/core/array/assoc_spec.rb30
-rw-r--r--spec/ruby/core/array/at_spec.rb4
-rw-r--r--spec/ruby/core/array/bsearch_index_spec.rb28
-rw-r--r--spec/ruby/core/array/bsearch_spec.rb26
-rw-r--r--spec/ruby/core/array/clear_spec.rb8
-rw-r--r--spec/ruby/core/array/clone_spec.rb8
-rw-r--r--spec/ruby/core/array/collect_spec.rb138
-rw-r--r--spec/ruby/core/array/combination_spec.rb6
-rw-r--r--spec/ruby/core/array/compact_spec.rb14
-rw-r--r--spec/ruby/core/array/comparison_spec.rb2
-rw-r--r--spec/ruby/core/array/concat_spec.rb10
-rw-r--r--spec/ruby/core/array/constructor_spec.rb4
-rw-r--r--spec/ruby/core/array/cycle_spec.rb20
-rw-r--r--spec/ruby/core/array/deconstruct_spec.rb2
-rw-r--r--spec/ruby/core/array/delete_at_spec.rb2
-rw-r--r--spec/ruby/core/array/delete_if_spec.rb16
-rw-r--r--spec/ruby/core/array/delete_spec.rb2
-rw-r--r--spec/ruby/core/array/difference_spec.rb4
-rw-r--r--spec/ruby/core/array/dig_spec.rb8
-rw-r--r--spec/ruby/core/array/drop_spec.rb8
-rw-r--r--spec/ruby/core/array/drop_while_spec.rb2
-rw-r--r--spec/ruby/core/array/dup_spec.rb12
-rw-r--r--spec/ruby/core/array/each_index_spec.rb2
-rw-r--r--spec/ruby/core/array/each_spec.rb2
-rw-r--r--spec/ruby/core/array/element_reference_spec.rb861
-rw-r--r--spec/ruby/core/array/element_set_spec.rb48
-rw-r--r--spec/ruby/core/array/eql_spec.rb4
-rw-r--r--spec/ruby/core/array/equal_value_spec.rb10
-rw-r--r--spec/ruby/core/array/fetch_spec.rb10
-rw-r--r--spec/ruby/core/array/fetch_values_spec.rb10
-rw-r--r--spec/ruby/core/array/fill_spec.rb50
-rw-r--r--spec/ruby/core/array/filter_spec.rb11
-rw-r--r--spec/ruby/core/array/find_index_spec.rb40
-rw-r--r--spec/ruby/core/array/first_spec.rb24
-rw-r--r--spec/ruby/core/array/flatten_spec.rb36
-rw-r--r--spec/ruby/core/array/hash_spec.rb8
-rw-r--r--spec/ruby/core/array/index_spec.rb5
-rw-r--r--spec/ruby/core/array/initialize_spec.rb32
-rw-r--r--spec/ruby/core/array/insert_spec.rb14
-rw-r--r--spec/ruby/core/array/inspect_spec.rb105
-rw-r--r--spec/ruby/core/array/join_spec.rb102
-rw-r--r--spec/ruby/core/array/keep_if_spec.rb2
-rw-r--r--spec/ruby/core/array/last_spec.rb22
-rw-r--r--spec/ruby/core/array/length_spec.rb11
-rw-r--r--spec/ruby/core/array/map_spec.rb10
-rw-r--r--spec/ruby/core/array/max_spec.rb8
-rw-r--r--spec/ruby/core/array/min_spec.rb10
-rw-r--r--spec/ruby/core/array/multiply_spec.rb22
-rw-r--r--spec/ruby/core/array/new_spec.rb28
-rw-r--r--spec/ruby/core/array/pack/a_spec.rb10
-rw-r--r--spec/ruby/core/array/pack/at_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/b_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/buffer_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb20
-rw-r--r--spec/ruby/core/array/pack/comment_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/h_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/m_spec.rb14
-rw-r--r--spec/ruby/core/array/pack/percent_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/r_spec.rb89
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb56
-rw-r--r--spec/ruby/core/array/pack/shared/encodings.rb4
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb90
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb116
-rw-r--r--spec/ruby/core/array/pack/shared/numeric_basic.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/string.rb8
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb26
-rw-r--r--spec/ruby/core/array/pack/u_spec.rb12
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb22
-rw-r--r--spec/ruby/core/array/pack/x_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/z_spec.rb6
-rw-r--r--spec/ruby/core/array/partition_spec.rb6
-rw-r--r--spec/ruby/core/array/permutation_spec.rb10
-rw-r--r--spec/ruby/core/array/plus_spec.rb12
-rw-r--r--spec/ruby/core/array/pop_spec.rb24
-rw-r--r--spec/ruby/core/array/prepend_spec.rb6
-rw-r--r--spec/ruby/core/array/product_spec.rb14
-rw-r--r--spec/ruby/core/array/push_spec.rb33
-rw-r--r--spec/ruby/core/array/rassoc_spec.rb22
-rw-r--r--spec/ruby/core/array/reject_spec.rb16
-rw-r--r--spec/ruby/core/array/repeated_combination_spec.rb8
-rw-r--r--spec/ruby/core/array/repeated_permutation_spec.rb4
-rw-r--r--spec/ruby/core/array/replace_spec.rb60
-rw-r--r--spec/ruby/core/array/reverse_each_spec.rb2
-rw-r--r--spec/ruby/core/array/reverse_spec.rb6
-rw-r--r--spec/ruby/core/array/rindex_spec.rb4
-rw-r--r--spec/ruby/core/array/rotate_spec.rb42
-rw-r--r--spec/ruby/core/array/sample_spec.rb32
-rw-r--r--spec/ruby/core/array/select_spec.rb35
-rw-r--r--spec/ruby/core/array/shared/clone.rb8
-rw-r--r--spec/ruby/core/array/shared/collect.rb141
-rw-r--r--spec/ruby/core/array/shared/difference.rb8
-rw-r--r--spec/ruby/core/array/shared/enumeratorize.rb2
-rw-r--r--spec/ruby/core/array/shared/eql.rb66
-rw-r--r--spec/ruby/core/array/shared/index.rb41
-rw-r--r--spec/ruby/core/array/shared/inspect.rb107
-rw-r--r--spec/ruby/core/array/shared/intersection.rb6
-rw-r--r--spec/ruby/core/array/shared/join.rb97
-rw-r--r--spec/ruby/core/array/shared/keep_if.rb16
-rw-r--r--spec/ruby/core/array/shared/length.rb11
-rw-r--r--spec/ruby/core/array/shared/push.rb33
-rw-r--r--spec/ruby/core/array/shared/replace.rb60
-rw-r--r--spec/ruby/core/array/shared/select.rb35
-rw-r--r--spec/ruby/core/array/shared/slice.rb859
-rw-r--r--spec/ruby/core/array/shared/union.rb6
-rw-r--r--spec/ruby/core/array/shared/unshift.rb64
-rw-r--r--spec/ruby/core/array/shift_spec.rb20
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb28
-rw-r--r--spec/ruby/core/array/size_spec.rb6
-rw-r--r--spec/ruby/core/array/slice_spec.rb23
-rw-r--r--spec/ruby/core/array/sort_by_spec.rb16
-rw-r--r--spec/ruby/core/array/sort_spec.rb40
-rw-r--r--spec/ruby/core/array/sum_spec.rb16
-rw-r--r--spec/ruby/core/array/take_spec.rb4
-rw-r--r--spec/ruby/core/array/take_while_spec.rb2
-rw-r--r--spec/ruby/core/array/to_a_spec.rb4
-rw-r--r--spec/ruby/core/array/to_ary_spec.rb4
-rw-r--r--spec/ruby/core/array/to_h_spec.rb16
-rw-r--r--spec/ruby/core/array/to_s_spec.rb7
-rw-r--r--spec/ruby/core/array/transpose_spec.rb10
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb16
-rw-r--r--spec/ruby/core/array/union_spec.rb2
-rw-r--r--spec/ruby/core/array/uniq_spec.rb12
-rw-r--r--spec/ruby/core/array/unshift_spec.rb64
-rw-r--r--spec/ruby/core/array/values_at_spec.rb2
-rw-r--r--spec/ruby/core/array/zip_spec.rb8
-rw-r--r--spec/ruby/core/basicobject/__send___spec.rb2
-rw-r--r--spec/ruby/core/basicobject/basicobject_spec.rb20
-rw-r--r--spec/ruby/core/basicobject/equal_spec.rb14
-rw-r--r--spec/ruby/core/basicobject/equal_value_spec.rb2
-rw-r--r--spec/ruby/core/basicobject/initialize_spec.rb4
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb60
-rw-r--r--spec/ruby/core/basicobject/instance_exec_spec.rb30
-rw-r--r--spec/ruby/core/basicobject/method_missing_spec.rb2
-rw-r--r--spec/ruby/core/basicobject/not_equal_spec.rb16
-rw-r--r--spec/ruby/core/basicobject/not_spec.rb4
-rw-r--r--spec/ruby/core/basicobject/singleton_method_added_spec.rb12
-rw-r--r--spec/ruby/core/basicobject/singleton_method_removed_spec.rb2
-rw-r--r--spec/ruby/core/basicobject/singleton_method_undefined_spec.rb2
-rw-r--r--spec/ruby/core/binding/dup_spec.rb2
-rw-r--r--spec/ruby/core/binding/eval_spec.rb16
-rw-r--r--spec/ruby/core/binding/local_variable_get_spec.rb10
-rw-r--r--spec/ruby/core/binding/local_variable_set_spec.rb8
-rw-r--r--spec/ruby/core/binding/local_variables_spec.rb2
-rw-r--r--spec/ruby/core/builtin_constants/builtin_constants_spec.rb88
-rw-r--r--spec/ruby/core/class/allocate_spec.rb6
-rw-r--r--spec/ruby/core/class/attached_object_spec.rb40
-rw-r--r--spec/ruby/core/class/dup_spec.rb4
-rw-r--r--spec/ruby/core/class/fixtures/callback_order.rb31
-rw-r--r--spec/ruby/core/class/inherited_spec.rb28
-rw-r--r--spec/ruby/core/class/initialize_spec.rb10
-rw-r--r--spec/ruby/core/class/new_spec.rb22
-rw-r--r--spec/ruby/core/class/subclasses_spec.rb4
-rw-r--r--spec/ruby/core/class/superclass_spec.rb2
-rw-r--r--spec/ruby/core/comparable/clamp_spec.rb179
-rw-r--r--spec/ruby/core/comparable/equal_value_spec.rb10
-rw-r--r--spec/ruby/core/comparable/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/comparable/gt_spec.rb2
-rw-r--r--spec/ruby/core/comparable/gte_spec.rb2
-rw-r--r--spec/ruby/core/comparable/lt_spec.rb6
-rw-r--r--spec/ruby/core/comparable/lte_spec.rb2
-rw-r--r--spec/ruby/core/complex/abs_spec.rb10
-rw-r--r--spec/ruby/core/complex/angle_spec.rb5
-rw-r--r--spec/ruby/core/complex/arg_spec.rb9
-rw-r--r--spec/ruby/core/complex/coerce_spec.rb32
-rw-r--r--spec/ruby/core/complex/comparison_spec.rb12
-rw-r--r--spec/ruby/core/complex/conj_spec.rb5
-rw-r--r--spec/ruby/core/complex/conjugate_spec.rb8
-rw-r--r--spec/ruby/core/complex/constants_spec.rb2
-rw-r--r--spec/ruby/core/complex/divide_spec.rb82
-rw-r--r--spec/ruby/core/complex/eql_spec.rb12
-rw-r--r--spec/ruby/core/complex/equal_value_spec.rb8
-rw-r--r--spec/ruby/core/complex/exponent_spec.rb4
-rw-r--r--spec/ruby/core/complex/fdiv_spec.rb42
-rw-r--r--spec/ruby/core/complex/imag_spec.rb5
-rw-r--r--spec/ruby/core/complex/imaginary_spec.rb8
-rw-r--r--spec/ruby/core/complex/integer_spec.rb4
-rw-r--r--spec/ruby/core/complex/magnitude_spec.rb5
-rw-r--r--spec/ruby/core/complex/marshal_dump_spec.rb2
-rw-r--r--spec/ruby/core/complex/negative_spec.rb4
-rw-r--r--spec/ruby/core/complex/phase_spec.rb5
-rw-r--r--spec/ruby/core/complex/polar_spec.rb28
-rw-r--r--spec/ruby/core/complex/positive_spec.rb4
-rw-r--r--spec/ruby/core/complex/quo_spec.rb5
-rw-r--r--spec/ruby/core/complex/rationalize_spec.rb8
-rw-r--r--spec/ruby/core/complex/real_spec.rb8
-rw-r--r--spec/ruby/core/complex/rect_spec.rb9
-rw-r--r--spec/ruby/core/complex/rectangular_spec.rb110
-rw-r--r--spec/ruby/core/complex/shared/abs.rb10
-rw-r--r--spec/ruby/core/complex/shared/arg.rb9
-rw-r--r--spec/ruby/core/complex/shared/conjugate.rb8
-rw-r--r--spec/ruby/core/complex/shared/divide.rb82
-rw-r--r--spec/ruby/core/complex/shared/image.rb8
-rw-r--r--spec/ruby/core/complex/shared/rect.rb94
-rw-r--r--spec/ruby/core/complex/to_c_spec.rb2
-rw-r--r--spec/ruby/core/complex/to_f_spec.rb4
-rw-r--r--spec/ruby/core/complex/to_i_spec.rb4
-rw-r--r--spec/ruby/core/complex/to_r_spec.rb4
-rw-r--r--spec/ruby/core/conditionvariable/broadcast_spec.rb2
-rw-r--r--spec/ruby/core/conditionvariable/marshal_dump_spec.rb2
-rw-r--r--spec/ruby/core/conditionvariable/signal_spec.rb2
-rw-r--r--spec/ruby/core/conditionvariable/wait_spec.rb2
-rw-r--r--spec/ruby/core/data/constants_spec.rb20
-rw-r--r--spec/ruby/core/data/deconstruct_keys_spec.rb135
-rw-r--r--spec/ruby/core/data/deconstruct_spec.rb8
-rw-r--r--spec/ruby/core/data/define_spec.rb48
-rw-r--r--spec/ruby/core/data/eql_spec.rb92
-rw-r--r--spec/ruby/core/data/equal_value_spec.rb92
-rw-r--r--spec/ruby/core/data/fixtures/classes.rb30
-rw-r--r--spec/ruby/core/data/hash_spec.rb36
-rw-r--r--spec/ruby/core/data/initialize_spec.rb215
-rw-r--r--spec/ruby/core/data/inspect_spec.rb63
-rw-r--r--spec/ruby/core/data/members_spec.rb26
-rw-r--r--spec/ruby/core/data/shared/inspect.rb54
-rw-r--r--spec/ruby/core/data/to_h_spec.rb94
-rw-r--r--spec/ruby/core/data/to_s_spec.rb9
-rw-r--r--spec/ruby/core/data/with_spec.rb66
-rw-r--r--spec/ruby/core/dir/chdir_spec.rb150
-rw-r--r--spec/ruby/core/dir/children_spec.rb18
-rw-r--r--spec/ruby/core/dir/chroot_spec.rb6
-rw-r--r--spec/ruby/core/dir/close_spec.rb16
-rw-r--r--spec/ruby/core/dir/each_child_spec.rb6
-rw-r--r--spec/ruby/core/dir/each_spec.rb4
-rw-r--r--spec/ruby/core/dir/empty_spec.rb8
-rw-r--r--spec/ruby/core/dir/entries_spec.rb10
-rw-r--r--spec/ruby/core/dir/exist_spec.rb65
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb108
-rw-r--r--spec/ruby/core/dir/fileno_spec.rb4
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb49
-rw-r--r--spec/ruby/core/dir/for_fd_spec.rb110
-rw-r--r--spec/ruby/core/dir/foreach_spec.rb6
-rw-r--r--spec/ruby/core/dir/getwd_spec.rb12
-rw-r--r--spec/ruby/core/dir/glob_spec.rb2
-rw-r--r--spec/ruby/core/dir/home_spec.rb48
-rw-r--r--spec/ruby/core/dir/inspect_spec.rb4
-rw-r--r--spec/ruby/core/dir/mkdir_spec.rb10
-rw-r--r--spec/ruby/core/dir/open_spec.rb73
-rw-r--r--spec/ruby/core/dir/path_spec.rb26
-rw-r--r--spec/ruby/core/dir/pos_spec.rb23
-rw-r--r--spec/ruby/core/dir/pwd_spec.rb45
-rw-r--r--spec/ruby/core/dir/read_spec.rb4
-rw-r--r--spec/ruby/core/dir/scan_spec.rb224
-rw-r--r--spec/ruby/core/dir/shared/chroot.rb4
-rw-r--r--spec/ruby/core/dir/shared/closed.rb2
-rw-r--r--spec/ruby/core/dir/shared/delete.rb24
-rw-r--r--spec/ruby/core/dir/shared/exist.rb57
-rw-r--r--spec/ruby/core/dir/shared/glob.rb12
-rw-r--r--spec/ruby/core/dir/shared/open.rb73
-rw-r--r--spec/ruby/core/dir/shared/path.rb30
-rw-r--r--spec/ruby/core/dir/shared/pos.rb27
-rw-r--r--spec/ruby/core/dir/shared/pwd.rb45
-rw-r--r--spec/ruby/core/dir/tell_spec.rb27
-rw-r--r--spec/ruby/core/dir/to_path_spec.rb12
-rw-r--r--spec/ruby/core/encoding/aliases_spec.rb10
-rw-r--r--spec/ruby/core/encoding/ascii_compatible_spec.rb15
-rw-r--r--spec/ruby/core/encoding/compatible_spec.rb54
-rw-r--r--spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb6
-rw-r--r--spec/ruby/core/encoding/converter/constants_spec.rb52
-rw-r--r--spec/ruby/core/encoding/converter/convert_spec.rb9
-rw-r--r--spec/ruby/core/encoding/converter/finish_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/last_error_spec.rb34
-rw-r--r--spec/ruby/core/encoding/converter/new_spec.rb12
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb28
-rw-r--r--spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb6
-rw-r--r--spec/ruby/core/encoding/converter/putback_spec.rb4
-rw-r--r--spec/ruby/core/encoding/converter/replacement_spec.rb8
-rw-r--r--spec/ruby/core/encoding/converter/search_convpath_spec.rb2
-rw-r--r--spec/ruby/core/encoding/default_external_spec.rb6
-rw-r--r--spec/ruby/core/encoding/default_internal_spec.rb12
-rw-r--r--spec/ruby/core/encoding/dummy_spec.rb21
-rw-r--r--spec/ruby/core/encoding/find_spec.rb8
-rw-r--r--spec/ruby/core/encoding/fixtures/classes.rb2
-rw-r--r--spec/ruby/core/encoding/inspect_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb6
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb8
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb6
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb4
-rw-r--r--spec/ruby/core/encoding/list_spec.rb10
-rw-r--r--spec/ruby/core/encoding/locale_charmap_spec.rb76
-rw-r--r--spec/ruby/core/encoding/name_list_spec.rb8
-rw-r--r--spec/ruby/core/encoding/name_spec.rb13
-rw-r--r--spec/ruby/core/encoding/names_spec.rb6
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb86
-rw-r--r--spec/ruby/core/encoding/shared/name.rb15
-rw-r--r--spec/ruby/core/encoding/to_s_spec.rb5
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb4
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/all_spec.rb20
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb20
-rw-r--r--spec/ruby/core/enumerable/chain_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/chunk_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/chunk_while_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/cycle_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/drop_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/drop_while_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/each_cons_spec.rb18
-rw-r--r--spec/ruby/core/enumerable/each_entry_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/each_slice_spec.rb20
-rw-r--r--spec/ruby/core/enumerable/each_with_index_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/each_with_object_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/filter_map_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/filter_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/find_index_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/first_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/fixtures/classes.rb7
-rw-r--r--spec/ruby/core/enumerable/grep_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/grep_v_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/group_by_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/lazy_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/max_by_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/max_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/min_by_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/min_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/minmax_by_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/none_spec.rb28
-rw-r--r--spec/ruby/core/enumerable/one_spec.rb32
-rw-r--r--spec/ruby/core/enumerable/partition_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/reject_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/reverse_each_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/shared/collect.rb4
-rw-r--r--spec/ruby/core/enumerable/shared/collect_concat.rb4
-rw-r--r--spec/ruby/core/enumerable/shared/find.rb2
-rw-r--r--spec/ruby/core/enumerable/shared/find_all.rb2
-rw-r--r--spec/ruby/core/enumerable/shared/include.rb2
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb18
-rw-r--r--spec/ruby/core/enumerable/shared/take.rb8
-rw-r--r--spec/ruby/core/enumerable/shared/value_packing.rb26
-rw-r--r--spec/ruby/core/enumerable/slice_after_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/slice_before_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/slice_when_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/sort_by_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/sort_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/take_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/take_while_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb12
-rw-r--r--spec/ruby/core/enumerable/to_h_spec.rb12
-rw-r--r--spec/ruby/core/enumerable/to_set_spec.rb35
-rw-r--r--spec/ruby/core/enumerable/zip_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/chain/initialize_spec.rb10
-rw-r--r--spec/ruby/core/enumerator/chain/rewind_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/each_spec.rb29
-rw-r--r--spec/ruby/core/enumerator/each_with_index_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/feed_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/generator/each_spec.rb40
-rw-r--r--spec/ruby/core/enumerator/generator/initialize_spec.rb26
-rw-r--r--spec/ruby/core/enumerator/initialize_spec.rb14
-rw-r--r--spec/ruby/core/enumerator/lazy/chunk_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/chunk_while_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/compact_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/drop_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/drop_while_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/grep_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/grep_v_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/initialize_spec.rb14
-rw-r--r--spec/ruby/core/enumerator/lazy/lazy_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/reject_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/collect.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/collect_concat.rb10
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/select.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/shared/to_enum.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/slice_after_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/slice_before_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/slice_when_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/take_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/lazy/take_while_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/uniq_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/with_index_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/lazy/zip_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/new_spec.rb61
-rw-r--r--spec/ruby/core/enumerator/next_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/next_values_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/peek_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/peek_values_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/plus_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/produce_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/product/each_spec.rb124
-rw-r--r--spec/ruby/core/enumerator/product/initialize_copy_spec.rb74
-rw-r--r--spec/ruby/core/enumerator/product/initialize_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/product/inspect_spec.rb28
-rw-r--r--spec/ruby/core/enumerator/product/rewind_spec.rb90
-rw-r--r--spec/ruby/core/enumerator/product/size_spec.rb88
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb138
-rw-r--r--spec/ruby/core/enumerator/shared/enum_for.rb6
-rw-r--r--spec/ruby/core/enumerator/shared/with_index.rb4
-rw-r--r--spec/ruby/core/enumerator/shared/with_object.rb14
-rw-r--r--spec/ruby/core/enumerator/size_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/with_index_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/yielder/append_spec.rb35
-rw-r--r--spec/ruby/core/enumerator/yielder/initialize_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/yielder/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/enumerator/yielder/yield_spec.rb33
-rw-r--r--spec/ruby/core/env/assoc_spec.rb2
-rw-r--r--spec/ruby/core/env/clear_spec.rb2
-rw-r--r--spec/ruby/core/env/clone_spec.rb14
-rw-r--r--spec/ruby/core/env/delete_if_spec.rb10
-rw-r--r--spec/ruby/core/env/delete_spec.rb2
-rw-r--r--spec/ruby/core/env/dup_spec.rb2
-rw-r--r--spec/ruby/core/env/each_key_spec.rb8
-rw-r--r--spec/ruby/core/env/each_value_spec.rb8
-rw-r--r--spec/ruby/core/env/element_reference_spec.rb6
-rw-r--r--spec/ruby/core/env/fetch_spec.rb4
-rw-r--r--spec/ruby/core/env/fetch_values_spec.rb51
-rw-r--r--spec/ruby/core/env/keep_if_spec.rb10
-rw-r--r--spec/ruby/core/env/key_spec.rb4
-rw-r--r--spec/ruby/core/env/rassoc_spec.rb2
-rw-r--r--spec/ruby/core/env/reject_spec.rb14
-rw-r--r--spec/ruby/core/env/replace_spec.rb16
-rw-r--r--spec/ruby/core/env/shared/each.rb12
-rw-r--r--spec/ruby/core/env/shared/include.rb2
-rw-r--r--spec/ruby/core/env/shared/select.rb4
-rw-r--r--spec/ruby/core/env/shared/store.rb14
-rw-r--r--spec/ruby/core/env/shared/to_hash.rb4
-rw-r--r--spec/ruby/core/env/shared/update.rb24
-rw-r--r--spec/ruby/core/env/shift_spec.rb8
-rw-r--r--spec/ruby/core/env/slice_spec.rb2
-rw-r--r--spec/ruby/core/env/to_h_spec.rb8
-rw-r--r--spec/ruby/core/env/values_at_spec.rb2
-rw-r--r--spec/ruby/core/exception/backtrace_locations_spec.rb6
-rw-r--r--spec/ruby/core/exception/backtrace_spec.rb10
-rw-r--r--spec/ruby/core/exception/cause_spec.rb54
-rw-r--r--spec/ruby/core/exception/detailed_message_spec.rb70
-rw-r--r--spec/ruby/core/exception/dup_spec.rb14
-rw-r--r--spec/ruby/core/exception/equal_value_spec.rb4
-rw-r--r--spec/ruby/core/exception/errno_spec.rb10
-rw-r--r--spec/ruby/core/exception/exception_spec.rb4
-rw-r--r--spec/ruby/core/exception/exit_value_spec.rb2
-rw-r--r--spec/ruby/core/exception/frozen_error_spec.rb24
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb96
-rw-r--r--spec/ruby/core/exception/io_error_spec.rb16
-rw-r--r--spec/ruby/core/exception/name_spec.rb12
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb269
-rw-r--r--spec/ruby/core/exception/reason_spec.rb2
-rw-r--r--spec/ruby/core/exception/receiver_spec.rb16
-rw-r--r--spec/ruby/core/exception/result_spec.rb4
-rw-r--r--spec/ruby/core/exception/set_backtrace_spec.rb71
-rw-r--r--spec/ruby/core/exception/shared/new.rb4
-rw-r--r--spec/ruby/core/exception/shared/set_backtrace.rb64
-rw-r--r--spec/ruby/core/exception/signal_exception_spec.rb10
-rw-r--r--spec/ruby/core/exception/signm_spec.rb2
-rw-r--r--spec/ruby/core/exception/signo_spec.rb2
-rw-r--r--spec/ruby/core/exception/standard_error_spec.rb2
-rw-r--r--spec/ruby/core/exception/status_spec.rb2
-rw-r--r--spec/ruby/core/exception/success_spec.rb4
-rw-r--r--spec/ruby/core/exception/syntax_error_spec.rb36
-rw-r--r--spec/ruby/core/exception/system_call_error_spec.rb30
-rw-r--r--spec/ruby/core/false/dup_spec.rb2
-rw-r--r--spec/ruby/core/false/falseclass_spec.rb4
-rw-r--r--spec/ruby/core/false/singleton_method_spec.rb16
-rw-r--r--spec/ruby/core/false/to_s_spec.rb2
-rw-r--r--spec/ruby/core/fiber/alive_spec.rb20
-rw-r--r--spec/ruby/core/fiber/blocking_spec.rb20
-rw-r--r--spec/ruby/core/fiber/current_spec.rb14
-rw-r--r--spec/ruby/core/fiber/fixtures/classes.rb16
-rw-r--r--spec/ruby/core/fiber/fixtures/scheduler.rb35
-rw-r--r--spec/ruby/core/fiber/kill_spec.rb120
-rw-r--r--spec/ruby/core/fiber/new_spec.rb8
-rw-r--r--spec/ruby/core/fiber/raise_spec.rb47
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb4
-rw-r--r--spec/ruby/core/fiber/scheduler_spec.rb8
-rw-r--r--spec/ruby/core/fiber/set_scheduler_spec.rb8
-rw-r--r--spec/ruby/core/fiber/shared/resume.rb14
-rw-r--r--spec/ruby/core/fiber/shared/scheduler.rb51
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb268
-rw-r--r--spec/ruby/core/fiber/transfer_spec.rb6
-rw-r--r--spec/ruby/core/fiber/yield_spec.rb4
-rw-r--r--spec/ruby/core/file/absolute_path_spec.rb24
-rw-r--r--spec/ruby/core/file/atime_spec.rb6
-rw-r--r--spec/ruby/core/file/basename_spec.rb36
-rw-r--r--spec/ruby/core/file/birthtime_spec.rb68
-rw-r--r--spec/ruby/core/file/chmod_spec.rb12
-rw-r--r--spec/ruby/core/file/chown_spec.rb2
-rw-r--r--spec/ruby/core/file/constants/constants_spec.rb6
-rw-r--r--spec/ruby/core/file/ctime_spec.rb6
-rw-r--r--spec/ruby/core/file/dirname_spec.rb45
-rw-r--r--spec/ruby/core/file/empty_spec.rb6
-rw-r--r--spec/ruby/core/file/exist_spec.rb8
-rw-r--r--spec/ruby/core/file/expand_path_spec.rb20
-rw-r--r--spec/ruby/core/file/extname_spec.rb12
-rw-r--r--spec/ruby/core/file/flock_spec.rb32
-rw-r--r--spec/ruby/core/file/ftype_spec.rb8
-rw-r--r--spec/ruby/core/file/inspect_spec.rb2
-rw-r--r--spec/ruby/core/file/join_spec.rb14
-rw-r--r--spec/ruby/core/file/lchmod_spec.rb2
-rw-r--r--spec/ruby/core/file/link_spec.rb12
-rw-r--r--spec/ruby/core/file/mkfifo_spec.rb4
-rw-r--r--spec/ruby/core/file/mtime_spec.rb6
-rw-r--r--spec/ruby/core/file/new_spec.rb54
-rw-r--r--spec/ruby/core/file/open_spec.rb128
-rw-r--r--spec/ruby/core/file/path_spec.rb41
-rw-r--r--spec/ruby/core/file/readlink_spec.rb6
-rw-r--r--spec/ruby/core/file/realdirpath_spec.rb6
-rw-r--r--spec/ruby/core/file/realpath_spec.rb6
-rw-r--r--spec/ruby/core/file/rename_spec.rb8
-rw-r--r--spec/ruby/core/file/setuid_spec.rb4
-rw-r--r--spec/ruby/core/file/shared/fnmatch.rb64
-rw-r--r--spec/ruby/core/file/shared/open.rb2
-rw-r--r--spec/ruby/core/file/shared/path.rb2
-rw-r--r--spec/ruby/core/file/shared/read.rb4
-rw-r--r--spec/ruby/core/file/shared/stat.rb6
-rw-r--r--spec/ruby/core/file/shared/unlink.rb4
-rw-r--r--spec/ruby/core/file/size_spec.rb6
-rw-r--r--spec/ruby/core/file/socket_spec.rb32
-rw-r--r--spec/ruby/core/file/split_spec.rb6
-rw-r--r--spec/ruby/core/file/stat/atime_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/birthtime_spec.rb36
-rw-r--r--spec/ruby/core/file/stat/blocks_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/ctime_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/dev_major_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/dev_minor_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/dev_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/ftype_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/ino_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/mtime_spec.rb2
-rw-r--r--spec/ruby/core/file/stat/new_spec.rb4
-rw-r--r--spec/ruby/core/file/stat/rdev_major_spec.rb17
-rw-r--r--spec/ruby/core/file/stat/rdev_minor_spec.rb17
-rw-r--r--spec/ruby/core/file/stat/rdev_spec.rb2
-rw-r--r--spec/ruby/core/file/stat_spec.rb12
-rw-r--r--spec/ruby/core/file/symlink_spec.rb12
-rw-r--r--spec/ruby/core/file/truncate_spec.rb24
-rw-r--r--spec/ruby/core/file/umask_spec.rb8
-rw-r--r--spec/ruby/core/file/world_readable_spec.rb2
-rw-r--r--spec/ruby/core/file/world_writable_spec.rb2
-rw-r--r--spec/ruby/core/file/zero_spec.rb6
-rw-r--r--spec/ruby/core/filetest/exist_spec.rb8
-rw-r--r--spec/ruby/core/filetest/grpowned_spec.rb2
-rw-r--r--spec/ruby/core/filetest/socket_spec.rb4
-rw-r--r--spec/ruby/core/filetest/zero_spec.rb6
-rw-r--r--spec/ruby/core/float/ceil_spec.rb28
-rw-r--r--spec/ruby/core/float/comparison_spec.rb10
-rw-r--r--spec/ruby/core/float/constants_spec.rb2
-rw-r--r--spec/ruby/core/float/denominator_spec.rb2
-rw-r--r--spec/ruby/core/float/divide_spec.rb20
-rw-r--r--spec/ruby/core/float/divmod_spec.rb22
-rw-r--r--spec/ruby/core/float/dup_spec.rb2
-rw-r--r--spec/ruby/core/float/eql_spec.rb8
-rw-r--r--spec/ruby/core/float/float_spec.rb4
-rw-r--r--spec/ruby/core/float/floor_spec.rb28
-rw-r--r--spec/ruby/core/float/gt_spec.rb4
-rw-r--r--spec/ruby/core/float/gte_spec.rb4
-rw-r--r--spec/ruby/core/float/lt_spec.rb4
-rw-r--r--spec/ruby/core/float/lte_spec.rb4
-rw-r--r--spec/ruby/core/float/multiply_spec.rb4
-rw-r--r--spec/ruby/core/float/negative_spec.rb10
-rw-r--r--spec/ruby/core/float/next_float_spec.rb2
-rw-r--r--spec/ruby/core/float/numerator_spec.rb4
-rw-r--r--spec/ruby/core/float/positive_spec.rb10
-rw-r--r--spec/ruby/core/float/prev_float_spec.rb2
-rw-r--r--spec/ruby/core/float/rationalize_spec.rb8
-rw-r--r--spec/ruby/core/float/round_spec.rb223
-rw-r--r--spec/ruby/core/float/shared/abs.rb2
-rw-r--r--spec/ruby/core/float/shared/arg.rb4
-rw-r--r--spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb2
-rw-r--r--spec/ruby/core/float/shared/comparison_exception_in_coerce.rb2
-rw-r--r--spec/ruby/core/float/shared/modulo.rb12
-rw-r--r--spec/ruby/core/float/shared/quo.rb8
-rw-r--r--spec/ruby/core/float/shared/to_i.rb14
-rw-r--r--spec/ruby/core/float/shared/to_s.rb4
-rw-r--r--spec/ruby/core/float/truncate_spec.rb10
-rw-r--r--spec/ruby/core/float/uplus_spec.rb2
-rw-r--r--spec/ruby/core/gc/config_spec.rb97
-rw-r--r--spec/ruby/core/gc/count_spec.rb2
-rw-r--r--spec/ruby/core/gc/profiler/enabled_spec.rb4
-rw-r--r--spec/ruby/core/gc/profiler/result_spec.rb2
-rw-r--r--spec/ruby/core/gc/profiler/total_time_spec.rb2
-rw-r--r--spec/ruby/core/gc/stat_spec.rb28
-rw-r--r--spec/ruby/core/gc/stress_spec.rb8
-rw-r--r--spec/ruby/core/gc/total_time_spec.rb2
-rw-r--r--spec/ruby/core/hash/allocate_spec.rb2
-rw-r--r--spec/ruby/core/hash/assoc_spec.rb8
-rw-r--r--spec/ruby/core/hash/clear_spec.rb6
-rw-r--r--spec/ruby/core/hash/clone_spec.rb2
-rw-r--r--spec/ruby/core/hash/compact_spec.rb46
-rw-r--r--spec/ruby/core/hash/compare_by_identity_spec.rb28
-rw-r--r--spec/ruby/core/hash/constructor_spec.rb57
-rw-r--r--spec/ruby/core/hash/deconstruct_keys_spec.rb4
-rw-r--r--spec/ruby/core/hash/default_proc_spec.rb20
-rw-r--r--spec/ruby/core/hash/default_spec.rb4
-rw-r--r--spec/ruby/core/hash/delete_if_spec.rb8
-rw-r--r--spec/ruby/core/hash/delete_spec.rb4
-rw-r--r--spec/ruby/core/hash/dig_spec.rb18
-rw-r--r--spec/ruby/core/hash/each_key_spec.rb2
-rw-r--r--spec/ruby/core/hash/each_pair_spec.rb106
-rw-r--r--spec/ruby/core/hash/each_spec.rb10
-rw-r--r--spec/ruby/core/hash/each_value_spec.rb2
-rw-r--r--spec/ruby/core/hash/element_reference_spec.rb2
-rw-r--r--spec/ruby/core/hash/element_set_spec.rb118
-rw-r--r--spec/ruby/core/hash/equal_value_spec.rb2
-rw-r--r--spec/ruby/core/hash/except_spec.rb30
-rw-r--r--spec/ruby/core/hash/fetch_spec.rb6
-rw-r--r--spec/ruby/core/hash/filter_spec.rb9
-rw-r--r--spec/ruby/core/hash/flatten_spec.rb4
-rw-r--r--spec/ruby/core/hash/gt_spec.rb2
-rw-r--r--spec/ruby/core/hash/gte_spec.rb2
-rw-r--r--spec/ruby/core/hash/has_key_spec.rb6
-rw-r--r--spec/ruby/core/hash/has_value_spec.rb15
-rw-r--r--spec/ruby/core/hash/include_spec.rb39
-rw-r--r--spec/ruby/core/hash/initialize_spec.rb12
-rw-r--r--spec/ruby/core/hash/inspect_spec.rb122
-rw-r--r--spec/ruby/core/hash/invert_spec.rb21
-rw-r--r--spec/ruby/core/hash/keep_if_spec.rb10
-rw-r--r--spec/ruby/core/hash/key_spec.rb30
-rw-r--r--spec/ruby/core/hash/keys_spec.rb4
-rw-r--r--spec/ruby/core/hash/length_spec.rb6
-rw-r--r--spec/ruby/core/hash/lt_spec.rb2
-rw-r--r--spec/ruby/core/hash/lte_spec.rb2
-rw-r--r--spec/ruby/core/hash/member_spec.rb6
-rw-r--r--spec/ruby/core/hash/merge_spec.rb39
-rw-r--r--spec/ruby/core/hash/new_spec.rb23
-rw-r--r--spec/ruby/core/hash/rassoc_spec.rb10
-rw-r--r--spec/ruby/core/hash/rehash_spec.rb6
-rw-r--r--spec/ruby/core/hash/reject_spec.rb31
-rw-r--r--spec/ruby/core/hash/replace_spec.rb59
-rw-r--r--spec/ruby/core/hash/ruby2_keywords_hash_spec.rb16
-rw-r--r--spec/ruby/core/hash/select_spec.rb108
-rw-r--r--spec/ruby/core/hash/shared/comparison.rb10
-rw-r--r--spec/ruby/core/hash/shared/each.rb105
-rw-r--r--spec/ruby/core/hash/shared/eql.rb88
-rw-r--r--spec/ruby/core/hash/shared/greater_than.rb6
-rw-r--r--spec/ruby/core/hash/shared/index.rb37
-rw-r--r--spec/ruby/core/hash/shared/iteration.rb6
-rw-r--r--spec/ruby/core/hash/shared/key.rb38
-rw-r--r--spec/ruby/core/hash/shared/length.rb12
-rw-r--r--spec/ruby/core/hash/shared/less_than.rb6
-rw-r--r--spec/ruby/core/hash/shared/select.rb91
-rw-r--r--spec/ruby/core/hash/shared/store.rb115
-rw-r--r--spec/ruby/core/hash/shared/to_s.rb87
-rw-r--r--spec/ruby/core/hash/shared/update.rb76
-rw-r--r--spec/ruby/core/hash/shared/value.rb14
-rw-r--r--spec/ruby/core/hash/shared/values_at.rb9
-rw-r--r--spec/ruby/core/hash/shift_spec.rb47
-rw-r--r--spec/ruby/core/hash/size_spec.rb13
-rw-r--r--spec/ruby/core/hash/slice_spec.rb25
-rw-r--r--spec/ruby/core/hash/store_spec.rb6
-rw-r--r--spec/ruby/core/hash/to_a_spec.rb4
-rw-r--r--spec/ruby/core/hash/to_h_spec.rb40
-rw-r--r--spec/ruby/core/hash/to_hash_spec.rb4
-rw-r--r--spec/ruby/core/hash/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/hash/to_s_spec.rb6
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb41
-rw-r--r--spec/ruby/core/hash/transform_values_spec.rb39
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb16
-rw-r--r--spec/ruby/core/hash/update_spec.rb76
-rw-r--r--spec/ruby/core/hash/value_spec.rb6
-rw-r--r--spec/ruby/core/hash/values_at_spec.rb10
-rw-r--r--spec/ruby/core/hash/values_spec.rb2
-rw-r--r--spec/ruby/core/integer/allbits_spec.rb6
-rw-r--r--spec/ruby/core/integer/anybits_spec.rb6
-rw-r--r--spec/ruby/core/integer/bit_and_spec.rb8
-rw-r--r--spec/ruby/core/integer/bit_or_spec.rb10
-rw-r--r--spec/ruby/core/integer/bit_xor_spec.rb10
-rw-r--r--spec/ruby/core/integer/ceil_spec.rb11
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb26
-rw-r--r--spec/ruby/core/integer/chr_spec.rb62
-rw-r--r--spec/ruby/core/integer/coerce_spec.rb28
-rw-r--r--spec/ruby/core/integer/comparison_spec.rb14
-rw-r--r--spec/ruby/core/integer/constants_spec.rb36
-rw-r--r--spec/ruby/core/integer/digits_spec.rb6
-rw-r--r--spec/ruby/core/integer/div_spec.rb40
-rw-r--r--spec/ruby/core/integer/divide_spec.rb33
-rw-r--r--spec/ruby/core/integer/divmod_spec.rb34
-rw-r--r--spec/ruby/core/integer/downto_spec.rb8
-rw-r--r--spec/ruby/core/integer/dup_spec.rb4
-rw-r--r--spec/ruby/core/integer/element_reference_spec.rb14
-rw-r--r--spec/ruby/core/integer/eql_spec.rb25
-rw-r--r--spec/ruby/core/integer/even_spec.rb26
-rw-r--r--spec/ruby/core/integer/fdiv_spec.rb8
-rw-r--r--spec/ruby/core/integer/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/integer/gcd_spec.rb16
-rw-r--r--spec/ruby/core/integer/gcdlcm_spec.rb16
-rw-r--r--spec/ruby/core/integer/gt_spec.rb13
-rw-r--r--spec/ruby/core/integer/gte_spec.rb13
-rw-r--r--spec/ruby/core/integer/integer_spec.rb4
-rw-r--r--spec/ruby/core/integer/lcm_spec.rb16
-rw-r--r--spec/ruby/core/integer/left_shift_spec.rb34
-rw-r--r--spec/ruby/core/integer/lt_spec.rb13
-rw-r--r--spec/ruby/core/integer/lte_spec.rb13
-rw-r--r--spec/ruby/core/integer/minus_spec.rb29
-rw-r--r--spec/ruby/core/integer/multiply_spec.rb12
-rw-r--r--spec/ruby/core/integer/nobits_spec.rb6
-rw-r--r--spec/ruby/core/integer/odd_spec.rb26
-rw-r--r--spec/ruby/core/integer/ord_spec.rb16
-rw-r--r--spec/ruby/core/integer/plus_spec.rb29
-rw-r--r--spec/ruby/core/integer/pow_spec.rb22
-rw-r--r--spec/ruby/core/integer/pred_spec.rb10
-rw-r--r--spec/ruby/core/integer/rationalize_spec.rb6
-rw-r--r--spec/ruby/core/integer/remainder_spec.rb14
-rw-r--r--spec/ruby/core/integer/right_shift_spec.rb34
-rw-r--r--spec/ruby/core/integer/round_spec.rb62
-rw-r--r--spec/ruby/core/integer/shared/arithmetic_coerce.rb2
-rw-r--r--spec/ruby/core/integer/shared/comparison_coerce.rb2
-rw-r--r--spec/ruby/core/integer/shared/equal.rb5
-rw-r--r--spec/ruby/core/integer/shared/exponent.rb100
-rw-r--r--spec/ruby/core/integer/shared/integer_ceil_precision.rb25
-rw-r--r--spec/ruby/core/integer/shared/integer_floor_precision.rb9
-rw-r--r--spec/ruby/core/integer/shared/integer_rounding.rb6
-rw-r--r--spec/ruby/core/integer/shared/modulo.rb78
-rw-r--r--spec/ruby/core/integer/shared/to_i.rb8
-rw-r--r--spec/ruby/core/integer/sqrt_spec.rb6
-rw-r--r--spec/ruby/core/integer/to_f_spec.rb6
-rw-r--r--spec/ruby/core/integer/to_r_spec.rb8
-rw-r--r--spec/ruby/core/integer/to_s_spec.rb24
-rw-r--r--spec/ruby/core/integer/truncate_spec.rb12
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb14
-rw-r--r--spec/ruby/core/integer/upto_spec.rb8
-rw-r--r--spec/ruby/core/io/advise_spec.rb28
-rw-r--r--spec/ruby/core/io/autoclose_spec.rb4
-rw-r--r--spec/ruby/core/io/binmode_spec.rb10
-rw-r--r--spec/ruby/core/io/binread_spec.rb6
-rw-r--r--spec/ruby/core/io/buffer/and_spec.rb62
-rw-r--r--spec/ruby/core/io/buffer/bit_count_spec.rb64
-rw-r--r--spec/ruby/core/io/buffer/empty_spec.rb27
-rw-r--r--spec/ruby/core/io/buffer/external_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/for_spec.rb95
-rw-r--r--spec/ruby/core/io/buffer/free_spec.rb102
-rw-r--r--spec/ruby/core/io/buffer/initialize_spec.rb119
-rw-r--r--spec/ruby/core/io/buffer/internal_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/locked_spec.rb75
-rw-r--r--spec/ruby/core/io/buffer/map_spec.rb343
-rw-r--r--spec/ruby/core/io/buffer/mapped_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/not_spec.rb37
-rw-r--r--spec/ruby/core/io/buffer/null_spec.rb27
-rw-r--r--spec/ruby/core/io/buffer/or_spec.rb62
-rw-r--r--spec/ruby/core/io/buffer/private_spec.rb23
-rw-r--r--spec/ruby/core/io/buffer/readonly_spec.rb28
-rw-r--r--spec/ruby/core/io/buffer/resize_spec.rb151
-rw-r--r--spec/ruby/core/io/buffer/shared/null_and_empty.rb57
-rw-r--r--spec/ruby/core/io/buffer/shared_spec.rb33
-rw-r--r--spec/ruby/core/io/buffer/string_spec.rb62
-rw-r--r--spec/ruby/core/io/buffer/transfer_spec.rb117
-rw-r--r--spec/ruby/core/io/buffer/valid_spec.rb99
-rw-r--r--spec/ruby/core/io/buffer/xor_spec.rb62
-rw-r--r--spec/ruby/core/io/close_on_exec_spec.rb4
-rw-r--r--spec/ruby/core/io/close_read_spec.rb10
-rw-r--r--spec/ruby/core/io/close_spec.rb12
-rw-r--r--spec/ruby/core/io/close_write_spec.rb10
-rw-r--r--spec/ruby/core/io/closed_spec.rb4
-rw-r--r--spec/ruby/core/io/copy_stream_spec.rb24
-rw-r--r--spec/ruby/core/io/dup_spec.rb6
-rw-r--r--spec/ruby/core/io/each_byte_spec.rb6
-rw-r--r--spec/ruby/core/io/each_codepoint_spec.rb4
-rw-r--r--spec/ruby/core/io/eof_spec.rb6
-rw-r--r--spec/ruby/core/io/external_encoding_spec.rb46
-rw-r--r--spec/ruby/core/io/fcntl_spec.rb2
-rw-r--r--spec/ruby/core/io/fileno_spec.rb2
-rw-r--r--spec/ruby/core/io/flush_spec.rb6
-rw-r--r--spec/ruby/core/io/foreach_spec.rb64
-rw-r--r--spec/ruby/core/io/fsync_spec.rb2
-rw-r--r--spec/ruby/core/io/getbyte_spec.rb4
-rw-r--r--spec/ruby/core/io/getc_spec.rb6
-rw-r--r--spec/ruby/core/io/gets_spec.rb38
-rw-r--r--spec/ruby/core/io/initialize_spec.rb12
-rw-r--r--spec/ruby/core/io/inspect_spec.rb4
-rw-r--r--spec/ruby/core/io/internal_encoding_spec.rb28
-rw-r--r--spec/ruby/core/io/ioctl_spec.rb6
-rw-r--r--spec/ruby/core/io/lineno_spec.rb18
-rw-r--r--spec/ruby/core/io/open_spec.rb8
-rw-r--r--spec/ruby/core/io/output_spec.rb2
-rw-r--r--spec/ruby/core/io/path_spec.rb14
-rw-r--r--spec/ruby/core/io/pid_spec.rb4
-rw-r--r--spec/ruby/core/io/pipe_spec.rb32
-rw-r--r--spec/ruby/core/io/popen_spec.rb34
-rw-r--r--spec/ruby/core/io/pread_spec.rb216
-rw-r--r--spec/ruby/core/io/print_spec.rb4
-rw-r--r--spec/ruby/core/io/printf_spec.rb2
-rw-r--r--spec/ruby/core/io/puts_spec.rb2
-rw-r--r--spec/ruby/core/io/pwrite_spec.rb104
-rw-r--r--spec/ruby/core/io/read_nonblock_spec.rb22
-rw-r--r--spec/ruby/core/io/read_spec.rb182
-rw-r--r--spec/ruby/core/io/readbyte_spec.rb2
-rw-r--r--spec/ruby/core/io/readchar_spec.rb10
-rw-r--r--spec/ruby/core/io/readline_spec.rb10
-rw-r--r--spec/ruby/core/io/readlines_spec.rb76
-rw-r--r--spec/ruby/core/io/readpartial_spec.rb21
-rw-r--r--spec/ruby/core/io/reopen_spec.rb26
-rw-r--r--spec/ruby/core/io/rewind_spec.rb2
-rw-r--r--spec/ruby/core/io/seek_spec.rb2
-rw-r--r--spec/ruby/core/io/select_spec.rb62
-rw-r--r--spec/ruby/core/io/set_encoding_by_bom_spec.rb10
-rw-r--r--spec/ruby/core/io/set_encoding_spec.rb42
-rw-r--r--spec/ruby/core/io/shared/binwrite.rb4
-rw-r--r--spec/ruby/core/io/shared/chars.rb10
-rw-r--r--spec/ruby/core/io/shared/codepoints.rb6
-rw-r--r--spec/ruby/core/io/shared/each.rb38
-rw-r--r--spec/ruby/core/io/shared/gets_ascii.rb2
-rw-r--r--spec/ruby/core/io/shared/new.rb79
-rw-r--r--spec/ruby/core/io/shared/pos.rb8
-rw-r--r--spec/ruby/core/io/shared/readlines.rb30
-rw-r--r--spec/ruby/core/io/shared/tty.rb2
-rw-r--r--spec/ruby/core/io/shared/write.rb8
-rw-r--r--spec/ruby/core/io/stat_spec.rb6
-rw-r--r--spec/ruby/core/io/sync_spec.rb4
-rw-r--r--spec/ruby/core/io/sysopen_spec.rb16
-rw-r--r--spec/ruby/core/io/sysread_spec.rb18
-rw-r--r--spec/ruby/core/io/sysseek_spec.rb4
-rw-r--r--spec/ruby/core/io/to_i_spec.rb2
-rw-r--r--spec/ruby/core/io/to_io_spec.rb4
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb12
-rw-r--r--spec/ruby/core/io/ungetbyte_spec.rb12
-rw-r--r--spec/ruby/core/io/ungetc_spec.rb14
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb8
-rw-r--r--spec/ruby/core/io/write_spec.rb21
-rw-r--r--spec/ruby/core/kernel/Array_spec.rb6
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb60
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb226
-rw-r--r--spec/ruby/core/kernel/Hash_spec.rb6
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb254
-rw-r--r--spec/ruby/core/kernel/Rational_spec.rb118
-rw-r--r--spec/ruby/core/kernel/String_spec.rb14
-rw-r--r--spec/ruby/core/kernel/abort_spec.rb2
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb4
-rw-r--r--spec/ruby/core/kernel/autoload_relative_spec.rb114
-rw-r--r--spec/ruby/core/kernel/autoload_spec.rb19
-rw-r--r--spec/ruby/core/kernel/backtick_spec.rb14
-rw-r--r--spec/ruby/core/kernel/binding_spec.rb4
-rw-r--r--spec/ruby/core/kernel/block_given_spec.rb2
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb19
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb41
-rw-r--r--spec/ruby/core/kernel/case_compare_spec.rb14
-rw-r--r--spec/ruby/core/kernel/catch_spec.rb10
-rw-r--r--spec/ruby/core/kernel/chomp_spec.rb2
-rw-r--r--spec/ruby/core/kernel/chop_spec.rb2
-rw-r--r--spec/ruby/core/kernel/class_spec.rb20
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb16
-rw-r--r--spec/ruby/core/kernel/comparison_spec.rb6
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb20
-rw-r--r--spec/ruby/core/kernel/dup_spec.rb8
-rw-r--r--spec/ruby/core/kernel/eql_spec.rb2
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb137
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb2
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb4
-rw-r--r--spec/ruby/core/kernel/extend_spec.rb8
-rw-r--r--spec/ruby/core/kernel/fail_spec.rb10
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_relative_b.rb7
-rw-r--r--spec/ruby/core/kernel/fixtures/autoload_relative_d.rb5
-rw-r--r--spec/ruby/core/kernel/fixtures/classes.rb19
-rw-r--r--spec/ruby/core/kernel/fork_spec.rb2
-rw-r--r--spec/ruby/core/kernel/format_spec.rb8
-rw-r--r--spec/ruby/core/kernel/freeze_spec.rb28
-rw-r--r--spec/ruby/core/kernel/frozen_spec.rb22
-rw-r--r--spec/ruby/core/kernel/gets_spec.rb2
-rw-r--r--spec/ruby/core/kernel/global_variables_spec.rb6
-rw-r--r--spec/ruby/core/kernel/gsub_spec.rb8
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb2
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb12
-rw-r--r--spec/ruby/core/kernel/initialize_dup_spec.rb2
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb76
-rw-r--r--spec/ruby/core/kernel/instance_of_spec.rb6
-rw-r--r--spec/ruby/core/kernel/instance_variable_defined_spec.rb12
-rw-r--r--spec/ruby/core/kernel/instance_variable_get_spec.rb28
-rw-r--r--spec/ruby/core/kernel/instance_variable_set_spec.rb28
-rw-r--r--spec/ruby/core/kernel/instance_variables_spec.rb2
-rw-r--r--spec/ruby/core/kernel/itself_spec.rb2
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb82
-rw-r--r--spec/ruby/core/kernel/load_spec.rb2
-rw-r--r--spec/ruby/core/kernel/local_variables_spec.rb11
-rw-r--r--spec/ruby/core/kernel/loop_spec.rb6
-rw-r--r--spec/ruby/core/kernel/match_spec.rb27
-rw-r--r--spec/ruby/core/kernel/method_spec.rb22
-rw-r--r--spec/ruby/core/kernel/methods_spec.rb34
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb14
-rw-r--r--spec/ruby/core/kernel/open_spec.rb100
-rw-r--r--spec/ruby/core/kernel/p_spec.rb2
-rw-r--r--spec/ruby/core/kernel/print_spec.rb2
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb2
-rw-r--r--spec/ruby/core/kernel/private_methods_spec.rb10
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb14
-rw-r--r--spec/ruby/core/kernel/protected_methods_spec.rb10
-rw-r--r--spec/ruby/core/kernel/public_method_spec.rb6
-rw-r--r--spec/ruby/core/kernel/public_methods_spec.rb19
-rw-r--r--spec/ruby/core/kernel/public_send_spec.rb16
-rw-r--r--spec/ruby/core/kernel/putc_spec.rb2
-rw-r--r--spec/ruby/core/kernel/puts_spec.rb2
-rw-r--r--spec/ruby/core/kernel/raise_spec.rb203
-rw-r--r--spec/ruby/core/kernel/rand_spec.rb94
-rw-r--r--spec/ruby/core/kernel/readline_spec.rb2
-rw-r--r--spec/ruby/core/kernel/readlines_spec.rb2
-rw-r--r--spec/ruby/core/kernel/remove_instance_variable_spec.rb20
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb132
-rw-r--r--spec/ruby/core/kernel/require_spec.rb36
-rw-r--r--spec/ruby/core/kernel/respond_to_missing_spec.rb20
-rw-r--r--spec/ruby/core/kernel/respond_to_spec.rb33
-rw-r--r--spec/ruby/core/kernel/select_spec.rb2
-rw-r--r--spec/ruby/core/kernel/set_trace_func_spec.rb2
-rw-r--r--spec/ruby/core/kernel/shared/dup_clone.rb8
-rw-r--r--spec/ruby/core/kernel/shared/kind_of.rb8
-rw-r--r--spec/ruby/core/kernel/shared/lambda.rb2
-rw-r--r--spec/ruby/core/kernel/shared/load.rb54
-rw-r--r--spec/ruby/core/kernel/shared/method.rb12
-rw-r--r--spec/ruby/core/kernel/shared/require.rb248
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb123
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb12
-rw-r--r--spec/ruby/core/kernel/shared/then.rb12
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb14
-rw-r--r--spec/ruby/core/kernel/singleton_method_spec.rb52
-rw-r--r--spec/ruby/core/kernel/singleton_methods_spec.rb65
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb65
-rw-r--r--spec/ruby/core/kernel/spawn_spec.rb2
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb36
-rw-r--r--spec/ruby/core/kernel/srand_spec.rb8
-rw-r--r--spec/ruby/core/kernel/sub_spec.rb4
-rw-r--r--spec/ruby/core/kernel/syscall_spec.rb2
-rw-r--r--spec/ruby/core/kernel/system_spec.rb18
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb23
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb25
-rw-r--r--spec/ruby/core/kernel/tap_spec.rb4
-rw-r--r--spec/ruby/core/kernel/test_spec.rb12
-rw-r--r--spec/ruby/core/kernel/throw_spec.rb14
-rw-r--r--spec/ruby/core/kernel/trace_var_spec.rb4
-rw-r--r--spec/ruby/core/kernel/trap_spec.rb2
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb24
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb24
-rw-r--r--spec/ruby/core/kernel/untrace_var_spec.rb2
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb23
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb24
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb24
-rw-r--r--spec/ruby/core/main/define_method_spec.rb6
-rw-r--r--spec/ruby/core/main/include_spec.rb4
-rw-r--r--spec/ruby/core/main/private_spec.rb14
-rw-r--r--spec/ruby/core/main/public_spec.rb14
-rw-r--r--spec/ruby/core/main/ruby2_keywords_spec.rb2
-rw-r--r--spec/ruby/core/main/using_spec.rb22
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb151
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb20
-rw-r--r--spec/ruby/core/marshal/float_spec.rb2
-rw-r--r--spec/ruby/core/marshal/shared/load.rb233
-rw-r--r--spec/ruby/core/matchdata/allocate_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/begin_spec.rb10
-rw-r--r--spec/ruby/core/matchdata/bytebegin_spec.rb132
-rw-r--r--spec/ruby/core/matchdata/byteend_spec.rb104
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb132
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb101
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb4
-rw-r--r--spec/ruby/core/matchdata/element_reference_spec.rb6
-rw-r--r--spec/ruby/core/matchdata/end_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/inspect_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/integer_at_spec.rb38
-rw-r--r--spec/ruby/core/matchdata/named_captures_spec.rb16
-rw-r--r--spec/ruby/core/matchdata/names_spec.rb4
-rw-r--r--spec/ruby/core/matchdata/offset_spec.rb106
-rw-r--r--spec/ruby/core/matchdata/post_match_spec.rb6
-rw-r--r--spec/ruby/core/matchdata/pre_match_spec.rb6
-rw-r--r--spec/ruby/core/matchdata/regexp_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/shared/captures.rb2
-rw-r--r--spec/ruby/core/matchdata/shared/eql.rb8
-rw-r--r--spec/ruby/core/matchdata/string_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/to_a_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/to_s_spec.rb2
-rw-r--r--spec/ruby/core/matchdata/values_at_spec.rb4
-rw-r--r--spec/ruby/core/math/acos_spec.rb14
-rw-r--r--spec/ruby/core/math/acosh_spec.rb14
-rw-r--r--spec/ruby/core/math/asin_spec.rb12
-rw-r--r--spec/ruby/core/math/asinh_spec.rb8
-rw-r--r--spec/ruby/core/math/atan2_spec.rb14
-rw-r--r--spec/ruby/core/math/atan_spec.rb8
-rw-r--r--spec/ruby/core/math/cbrt_spec.rb6
-rw-r--r--spec/ruby/core/math/cos_spec.rb12
-rw-r--r--spec/ruby/core/math/cosh_spec.rb8
-rw-r--r--spec/ruby/core/math/erf_spec.rb8
-rw-r--r--spec/ruby/core/math/erfc_spec.rb8
-rw-r--r--spec/ruby/core/math/exp_spec.rb8
-rw-r--r--spec/ruby/core/math/expm1_spec.rb37
-rw-r--r--spec/ruby/core/math/frexp_spec.rb6
-rw-r--r--spec/ruby/core/math/gamma_spec.rb6
-rw-r--r--spec/ruby/core/math/hypot_spec.rb12
-rw-r--r--spec/ruby/core/math/ldexp_spec.rb14
-rw-r--r--spec/ruby/core/math/lgamma_spec.rb13
-rw-r--r--spec/ruby/core/math/log10_spec.rb14
-rw-r--r--spec/ruby/core/math/log1p_spec.rb49
-rw-r--r--spec/ruby/core/math/log2_spec.rb10
-rw-r--r--spec/ruby/core/math/log_spec.rb16
-rw-r--r--spec/ruby/core/math/shared/atanh.rb12
-rw-r--r--spec/ruby/core/math/sin_spec.rb8
-rw-r--r--spec/ruby/core/math/sinh_spec.rb8
-rw-r--r--spec/ruby/core/math/sqrt_spec.rb10
-rw-r--r--spec/ruby/core/math/tan_spec.rb8
-rw-r--r--spec/ruby/core/math/tanh_spec.rb8
-rw-r--r--spec/ruby/core/method/curry_spec.rb18
-rw-r--r--spec/ruby/core/method/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/method/inspect_spec.rb2
-rw-r--r--spec/ruby/core/method/original_name_spec.rb37
-rw-r--r--spec/ruby/core/method/owner_spec.rb6
-rw-r--r--spec/ruby/core/method/parameters_spec.rb41
-rw-r--r--spec/ruby/core/method/private_spec.rb25
-rw-r--r--spec/ruby/core/method/protected_spec.rb25
-rw-r--r--spec/ruby/core/method/public_spec.rb25
-rw-r--r--spec/ruby/core/method/receiver_spec.rb8
-rw-r--r--spec/ruby/core/method/shared/aliased_inspect.rb31
-rw-r--r--spec/ruby/core/method/shared/call.rb4
-rw-r--r--spec/ruby/core/method/shared/dup.rb2
-rw-r--r--spec/ruby/core/method/shared/eql.rb32
-rw-r--r--spec/ruby/core/method/shared/to_s.rb4
-rw-r--r--spec/ruby/core/method/source_location_spec.rb28
-rw-r--r--spec/ruby/core/method/to_s_spec.rb2
-rw-r--r--spec/ruby/core/method/unbind_spec.rb14
-rw-r--r--spec/ruby/core/module/alias_method_spec.rb48
-rw-r--r--spec/ruby/core/module/ancestors_spec.rb29
-rw-r--r--spec/ruby/core/module/append_features_spec.rb14
-rw-r--r--spec/ruby/core/module/attr_accessor_spec.rb16
-rw-r--r--spec/ruby/core/module/attr_reader_spec.rb10
-rw-r--r--spec/ruby/core/module/attr_spec.rb14
-rw-r--r--spec/ruby/core/module/attr_writer_spec.rb12
-rw-r--r--spec/ruby/core/module/autoload_relative_spec.rb128
-rw-r--r--spec/ruby/core/module/autoload_spec.rb189
-rw-r--r--spec/ruby/core/module/class_variable_defined_spec.rb12
-rw-r--r--spec/ruby/core/module/class_variable_get_spec.rb16
-rw-r--r--spec/ruby/core/module/class_variable_set_spec.rb12
-rw-r--r--spec/ruby/core/module/class_variables_spec.rb8
-rw-r--r--spec/ruby/core/module/const_added_spec.rb293
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb62
-rw-r--r--spec/ruby/core/module/const_get_spec.rb46
-rw-r--r--spec/ruby/core/module/const_missing_spec.rb2
-rw-r--r--spec/ruby/core/module/const_set_spec.rb24
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb34
-rw-r--r--spec/ruby/core/module/constants_spec.rb7
-rw-r--r--spec/ruby/core/module/define_method_spec.rb114
-rw-r--r--spec/ruby/core/module/deprecate_constant_spec.rb8
-rw-r--r--spec/ruby/core/module/extend_object_spec.rb10
-rw-r--r--spec/ruby/core/module/extended_spec.rb2
-rw-r--r--spec/ruby/core/module/fixtures/autoload_relative_a.rb9
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb2
-rw-r--r--spec/ruby/core/module/gt_spec.rb10
-rw-r--r--spec/ruby/core/module/gte_spec.rb2
-rw-r--r--spec/ruby/core/module/include_spec.rb62
-rw-r--r--spec/ruby/core/module/included_modules_spec.rb8
-rw-r--r--spec/ruby/core/module/included_spec.rb2
-rw-r--r--spec/ruby/core/module/instance_method_spec.rb37
-rw-r--r--spec/ruby/core/module/instance_methods_spec.rb30
-rw-r--r--spec/ruby/core/module/lt_spec.rb10
-rw-r--r--spec/ruby/core/module/lte_spec.rb2
-rw-r--r--spec/ruby/core/module/method_added_spec.rb4
-rw-r--r--spec/ruby/core/module/method_defined_spec.rb6
-rw-r--r--spec/ruby/core/module/method_removed_spec.rb2
-rw-r--r--spec/ruby/core/module/method_undefined_spec.rb2
-rw-r--r--spec/ruby/core/module/module_function_spec.rb22
-rw-r--r--spec/ruby/core/module/name_spec.rb65
-rw-r--r--spec/ruby/core/module/new_spec.rb2
-rw-r--r--spec/ruby/core/module/prepend_features_spec.rb8
-rw-r--r--spec/ruby/core/module/prepend_spec.rb60
-rw-r--r--spec/ruby/core/module/prepended_spec.rb2
-rw-r--r--spec/ruby/core/module/private_class_method_spec.rb22
-rw-r--r--spec/ruby/core/module/private_constant_spec.rb8
-rw-r--r--spec/ruby/core/module/private_instance_methods_spec.rb18
-rw-r--r--spec/ruby/core/module/private_method_defined_spec.rb10
-rw-r--r--spec/ruby/core/module/private_spec.rb18
-rw-r--r--spec/ruby/core/module/protected_instance_methods_spec.rb12
-rw-r--r--spec/ruby/core/module/protected_method_defined_spec.rb10
-rw-r--r--spec/ruby/core/module/protected_spec.rb16
-rw-r--r--spec/ruby/core/module/public_class_method_spec.rb14
-rw-r--r--spec/ruby/core/module/public_constant_spec.rb2
-rw-r--r--spec/ruby/core/module/public_instance_method_spec.rb20
-rw-r--r--spec/ruby/core/module/public_instance_methods_spec.rb14
-rw-r--r--spec/ruby/core/module/public_method_defined_spec.rb10
-rw-r--r--spec/ruby/core/module/public_spec.rb14
-rw-r--r--spec/ruby/core/module/refine_spec.rb57
-rw-r--r--spec/ruby/core/module/refinements_spec.rb56
-rw-r--r--spec/ruby/core/module/remove_class_variable_spec.rb12
-rw-r--r--spec/ruby/core/module/remove_const_spec.rb30
-rw-r--r--spec/ruby/core/module/remove_method_spec.rb16
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb175
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb217
-rw-r--r--spec/ruby/core/module/shared/class_eval.rb22
-rw-r--r--spec/ruby/core/module/shared/class_exec.rb12
-rw-r--r--spec/ruby/core/module/shared/set_visibility.rb36
-rw-r--r--spec/ruby/core/module/undef_method_spec.rb32
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb33
-rw-r--r--spec/ruby/core/module/used_refinements_spec.rb110
-rw-r--r--spec/ruby/core/module/using_spec.rb12
-rw-r--r--spec/ruby/core/mutex/lock_spec.rb66
-rw-r--r--spec/ruby/core/mutex/locked_spec.rb8
-rw-r--r--spec/ruby/core/mutex/owned_spec.rb6
-rw-r--r--spec/ruby/core/mutex/sleep_spec.rb28
-rw-r--r--spec/ruby/core/mutex/synchronize_spec.rb8
-rw-r--r--spec/ruby/core/mutex/try_lock_spec.rb8
-rw-r--r--spec/ruby/core/mutex/unlock_spec.rb6
-rw-r--r--spec/ruby/core/nil/dup_spec.rb2
-rw-r--r--spec/ruby/core/nil/match_spec.rb14
-rw-r--r--spec/ruby/core/nil/nilclass_spec.rb4
-rw-r--r--spec/ruby/core/nil/rationalize_spec.rb4
-rw-r--r--spec/ruby/core/nil/singleton_method_spec.rb16
-rw-r--r--spec/ruby/core/nil/to_c_spec.rb2
-rw-r--r--spec/ruby/core/nil/to_s_spec.rb2
-rw-r--r--spec/ruby/core/numeric/abs2_spec.rb4
-rw-r--r--spec/ruby/core/numeric/clone_spec.rb10
-rw-r--r--spec/ruby/core/numeric/coerce_spec.rb12
-rw-r--r--spec/ruby/core/numeric/comparison_spec.rb8
-rw-r--r--spec/ruby/core/numeric/div_spec.rb6
-rw-r--r--spec/ruby/core/numeric/dup_spec.rb4
-rw-r--r--spec/ruby/core/numeric/eql_spec.rb12
-rw-r--r--spec/ruby/core/numeric/fdiv_spec.rb4
-rw-r--r--spec/ruby/core/numeric/finite_spec.rb2
-rw-r--r--spec/ruby/core/numeric/i_spec.rb2
-rw-r--r--spec/ruby/core/numeric/negative_spec.rb12
-rw-r--r--spec/ruby/core/numeric/polar_spec.rb6
-rw-r--r--spec/ruby/core/numeric/positive_spec.rb12
-rw-r--r--spec/ruby/core/numeric/quo_spec.rb24
-rw-r--r--spec/ruby/core/numeric/real_spec.rb4
-rw-r--r--spec/ruby/core/numeric/remainder_spec.rb10
-rw-r--r--spec/ruby/core/numeric/shared/conj.rb2
-rw-r--r--spec/ruby/core/numeric/shared/imag.rb2
-rw-r--r--spec/ruby/core/numeric/shared/rect.rb6
-rw-r--r--spec/ruby/core/numeric/shared/step.rb90
-rw-r--r--spec/ruby/core/numeric/singleton_method_added_spec.rb8
-rw-r--r--spec/ruby/core/numeric/step_spec.rb12
-rw-r--r--spec/ruby/core/numeric/to_c_spec.rb4
-rw-r--r--spec/ruby/core/objectspace/_id2ref_spec.rb87
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb22
-rw-r--r--spec/ruby/core/objectspace/each_object_spec.rb46
-rw-r--r--spec/ruby/core/objectspace/garbage_collect_spec.rb4
-rw-r--r--spec/ruby/core/objectspace/undefine_finalizer_spec.rb2
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/clear_spec.rb34
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/delete_spec.rb78
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb202
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb124
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb38
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb30
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/key_spec.rb68
-rw-r--r--spec/ruby/core/objectspace/weakmap/delete_spec.rb42
-rw-r--r--spec/ruby/core/objectspace/weakmap/shared/each.rb2
-rw-r--r--spec/ruby/core/proc/allocate_spec.rb2
-rw-r--r--spec/ruby/core/proc/binding_spec.rb2
-rw-r--r--spec/ruby/core/proc/block_pass_spec.rb4
-rw-r--r--spec/ruby/core/proc/clone_spec.rb20
-rw-r--r--spec/ruby/core/proc/curry_spec.rb62
-rw-r--r--spec/ruby/core/proc/dup_spec.rb18
-rw-r--r--spec/ruby/core/proc/element_reference_spec.rb10
-rw-r--r--spec/ruby/core/proc/hash_spec.rb6
-rw-r--r--spec/ruby/core/proc/lambda_spec.rb45
-rw-r--r--spec/ruby/core/proc/new_spec.rb28
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb82
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb16
-rw-r--r--spec/ruby/core/proc/shared/call.rb8
-rw-r--r--spec/ruby/core/proc/shared/compose.rb4
-rw-r--r--spec/ruby/core/proc/shared/dup.rb10
-rw-r--r--spec/ruby/core/proc/shared/equal.rb34
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb75
-rw-r--r--spec/ruby/core/proc/to_proc_spec.rb2
-rw-r--r--spec/ruby/core/process/_fork_spec.rb6
-rw-r--r--spec/ruby/core/process/argv0_spec.rb8
-rw-r--r--spec/ruby/core/process/clock_gettime_spec.rb62
-rw-r--r--spec/ruby/core/process/constants_spec.rb46
-rw-r--r--spec/ruby/core/process/daemon_spec.rb2
-rw-r--r--spec/ruby/core/process/detach_spec.rb14
-rw-r--r--spec/ruby/core/process/egid_spec.rb8
-rw-r--r--spec/ruby/core/process/euid_spec.rb8
-rw-r--r--spec/ruby/core/process/exec_spec.rb20
-rw-r--r--spec/ruby/core/process/fixtures/clocks.rb2
-rw-r--r--spec/ruby/core/process/getpriority_spec.rb8
-rw-r--r--spec/ruby/core/process/getrlimit_spec.rb14
-rw-r--r--spec/ruby/core/process/groups_spec.rb4
-rw-r--r--spec/ruby/core/process/initgroups_spec.rb2
-rw-r--r--spec/ruby/core/process/kill_spec.rb8
-rw-r--r--spec/ruby/core/process/last_status_spec.rb2
-rw-r--r--spec/ruby/core/process/maxgroups_spec.rb2
-rw-r--r--spec/ruby/core/process/pid_spec.rb2
-rw-r--r--spec/ruby/core/process/set_proctitle_spec.rb2
-rw-r--r--spec/ruby/core/process/setrlimit_spec.rb108
-rw-r--r--spec/ruby/core/process/spawn_spec.rb108
-rw-r--r--spec/ruby/core/process/status/bit_and_spec.rb6
-rw-r--r--spec/ruby/core/process/status/exited_spec.rb6
-rw-r--r--spec/ruby/core/process/status/right_shift_spec.rb6
-rw-r--r--spec/ruby/core/process/status/signaled_spec.rb6
-rw-r--r--spec/ruby/core/process/status/success_spec.rb8
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb4
-rw-r--r--spec/ruby/core/process/status/to_i_spec.rb4
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb18
-rw-r--r--spec/ruby/core/process/times_spec.rb2
-rw-r--r--spec/ruby/core/process/uid_spec.rb6
-rw-r--r--spec/ruby/core/process/wait2_spec.rb10
-rw-r--r--spec/ruby/core/process/wait_spec.rb16
-rw-r--r--spec/ruby/core/process/waitall_spec.rb10
-rw-r--r--spec/ruby/core/process/warmup_spec.rb10
-rw-r--r--spec/ruby/core/queue/deq_spec.rb4
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb10
-rw-r--r--spec/ruby/core/queue/pop_spec.rb4
-rw-r--r--spec/ruby/core/queue/shift_spec.rb4
-rw-r--r--spec/ruby/core/random/bytes_spec.rb2
-rw-r--r--spec/ruby/core/random/default_spec.rb32
-rw-r--r--spec/ruby/core/random/new_seed_spec.rb2
-rw-r--r--spec/ruby/core/random/new_spec.rb8
-rw-r--r--spec/ruby/core/random/rand_spec.rb34
-rw-r--r--spec/ruby/core/random/seed_spec.rb2
-rw-r--r--spec/ruby/core/random/shared/bytes.rb2
-rw-r--r--spec/ruby/core/random/shared/rand.rb4
-rw-r--r--spec/ruby/core/random/urandom_spec.rb4
-rw-r--r--spec/ruby/core/range/bsearch_spec.rb104
-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/each_spec.rb10
-rw-r--r--spec/ruby/core/range/eql_spec.rb2
-rw-r--r--spec/ruby/core/range/first_spec.rb10
-rw-r--r--spec/ruby/core/range/hash_spec.rb8
-rw-r--r--spec/ruby/core/range/include_spec.rb4
-rw-r--r--spec/ruby/core/range/initialize_spec.rb20
-rw-r--r--spec/ruby/core/range/last_spec.rb16
-rw-r--r--spec/ruby/core/range/max_spec.rb36
-rw-r--r--spec/ruby/core/range/member_spec.rb2
-rw-r--r--spec/ruby/core/range/min_spec.rb26
-rw-r--r--spec/ruby/core/range/minmax_spec.rb14
-rw-r--r--spec/ruby/core/range/new_spec.rb8
-rw-r--r--spec/ruby/core/range/overlap_spec.rb168
-rw-r--r--spec/ruby/core/range/reverse_each_spec.rb172
-rw-r--r--spec/ruby/core/range/shared/cover.rb144
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb32
-rw-r--r--spec/ruby/core/range/shared/include.rb34
-rw-r--r--spec/ruby/core/range/size_spec.rb45
-rw-r--r--spec/ruby/core/range/step_spec.rb190
-rw-r--r--spec/ruby/core/range/to_a_spec.rb6
-rw-r--r--spec/ruby/core/range/to_set_spec.rb54
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb49
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb44
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb4
-rw-r--r--spec/ruby/core/rational/div_spec.rb14
-rw-r--r--spec/ruby/core/rational/divide_spec.rb34
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb24
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb26
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb88
-rw-r--r--spec/ruby/core/rational/floor_spec.rb50
-rw-r--r--spec/ruby/core/rational/integer_spec.rb4
-rw-r--r--spec/ruby/core/rational/marshal_dump_spec.rb2
-rw-r--r--spec/ruby/core/rational/minus_spec.rb14
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb10
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb26
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb4
-rw-r--r--spec/ruby/core/rational/plus_spec.rb14
-rw-r--r--spec/ruby/core/rational/rational_spec.rb2
-rw-r--r--spec/ruby/core/rational/rationalize_spec.rb4
-rw-r--r--spec/ruby/core/rational/round_spec.rb24
-rw-r--r--spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb2
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb8
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb6
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb8
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb20
-rw-r--r--spec/ruby/core/rational/zero_spec.rb6
-rw-r--r--spec/ruby/core/refinement/append_features_spec.rb24
-rw-r--r--spec/ruby/core/refinement/extend_object_spec.rb28
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb36
-rw-r--r--spec/ruby/core/refinement/include_spec.rb26
-rw-r--r--spec/ruby/core/refinement/prepend_features_spec.rb24
-rw-r--r--spec/ruby/core/refinement/prepend_spec.rb26
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb6
-rw-r--r--spec/ruby/core/refinement/target_spec.rb4
-rw-r--r--spec/ruby/core/regexp/case_compare_spec.rb14
-rw-r--r--spec/ruby/core/regexp/compile_spec.rb2
-rw-r--r--spec/ruby/core/regexp/encoding_spec.rb2
-rw-r--r--spec/ruby/core/regexp/fixed_encoding_spec.rb16
-rw-r--r--spec/ruby/core/regexp/initialize_spec.rb22
-rw-r--r--spec/ruby/core/regexp/last_match_spec.rb6
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb83
-rw-r--r--spec/ruby/core/regexp/match_spec.rb38
-rw-r--r--spec/ruby/core/regexp/named_captures_spec.rb4
-rw-r--r--spec/ruby/core/regexp/names_spec.rb4
-rw-r--r--spec/ruby/core/regexp/new_spec.rb2
-rw-r--r--spec/ruby/core/regexp/options_spec.rb6
-rw-r--r--spec/ruby/core/regexp/shared/new.rb448
-rw-r--r--spec/ruby/core/regexp/shared/quote.rb6
-rw-r--r--spec/ruby/core/regexp/source_spec.rb4
-rw-r--r--spec/ruby/core/regexp/timeout_spec.rb48
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb4
-rw-r--r--spec/ruby/core/regexp/union_spec.rb28
-rw-r--r--spec/ruby/core/set/add_spec.rb34
-rw-r--r--spec/ruby/core/set/append_spec.rb6
-rw-r--r--spec/ruby/core/set/case_compare_spec.rb11
-rw-r--r--spec/ruby/core/set/case_equality_spec.rb6
-rw-r--r--spec/ruby/core/set/classify_spec.rb26
-rw-r--r--spec/ruby/core/set/clear_spec.rb16
-rw-r--r--spec/ruby/core/set/collect_spec.rb6
-rw-r--r--spec/ruby/core/set/compare_by_identity_spec.rb153
-rw-r--r--spec/ruby/core/set/comparison_spec.rb26
-rw-r--r--spec/ruby/core/set/constructor_spec.rb14
-rw-r--r--spec/ruby/core/set/delete_if_spec.rb37
-rw-r--r--spec/ruby/core/set/delete_spec.rb36
-rw-r--r--spec/ruby/core/set/difference_spec.rb6
-rw-r--r--spec/ruby/core/set/disjoint_spec.rb22
-rw-r--r--spec/ruby/core/set/divide_spec.rb68
-rw-r--r--spec/ruby/core/set/each_spec.rb26
-rw-r--r--spec/ruby/core/set/empty_spec.rb9
-rw-r--r--spec/ruby/core/set/enumerable/to_set_spec.rb12
-rw-r--r--spec/ruby/core/set/eql_spec.rb14
-rw-r--r--spec/ruby/core/set/equal_value_spec.rb34
-rw-r--r--spec/ruby/core/set/exclusion_spec.rb17
-rw-r--r--spec/ruby/core/set/filter_spec.rb (renamed from spec/ruby/library/set/filter_spec.rb)0
-rw-r--r--spec/ruby/core/set/fixtures/set_like.rb30
-rw-r--r--spec/ruby/core/set/flatten_merge_spec.rb24
-rw-r--r--spec/ruby/core/set/flatten_spec.rb49
-rw-r--r--spec/ruby/core/set/hash_spec.rb19
-rw-r--r--spec/ruby/core/set/include_spec.rb6
-rw-r--r--spec/ruby/core/set/initialize_clone_spec.rb15
-rw-r--r--spec/ruby/core/set/initialize_spec.rb88
-rw-r--r--spec/ruby/core/set/inspect_spec.rb6
-rw-r--r--spec/ruby/core/set/intersect_spec.rb22
-rw-r--r--spec/ruby/core/set/intersection_spec.rb10
-rw-r--r--spec/ruby/core/set/join_spec.rb30
-rw-r--r--spec/ruby/core/set/keep_if_spec.rb37
-rw-r--r--spec/ruby/core/set/length_spec.rb6
-rw-r--r--spec/ruby/core/set/map_spec.rb6
-rw-r--r--spec/ruby/core/set/member_spec.rb6
-rw-r--r--spec/ruby/core/set/merge_spec.rb29
-rw-r--r--spec/ruby/core/set/minus_spec.rb6
-rw-r--r--spec/ruby/core/set/plus_spec.rb6
-rw-r--r--spec/ruby/core/set/pretty_print_cycle_spec.rb14
-rw-r--r--spec/ruby/core/set/proper_subset_spec.rb35
-rw-r--r--spec/ruby/core/set/proper_superset_spec.rb42
-rw-r--r--spec/ruby/core/set/reject_spec.rb41
-rw-r--r--spec/ruby/core/set/replace_spec.rb24
-rw-r--r--spec/ruby/core/set/select_spec.rb (renamed from spec/ruby/library/set/select_spec.rb)0
-rw-r--r--spec/ruby/core/set/set_spec.rb10
-rw-r--r--spec/ruby/core/set/shared/add.rb14
-rw-r--r--spec/ruby/core/set/shared/collect.rb20
-rw-r--r--spec/ruby/core/set/shared/difference.rb15
-rw-r--r--spec/ruby/core/set/shared/include.rb29
-rw-r--r--spec/ruby/core/set/shared/inspect.rb45
-rw-r--r--spec/ruby/core/set/shared/intersection.rb15
-rw-r--r--spec/ruby/core/set/shared/length.rb (renamed from spec/ruby/library/set/shared/length.rb)0
-rw-r--r--spec/ruby/core/set/shared/select.rb41
-rw-r--r--spec/ruby/core/set/shared/union.rb15
-rw-r--r--spec/ruby/core/set/size_spec.rb6
-rw-r--r--spec/ruby/core/set/sortedset/sortedset_spec.rb13
-rw-r--r--spec/ruby/core/set/subset_spec.rb35
-rw-r--r--spec/ruby/core/set/subtract_spec.rb16
-rw-r--r--spec/ruby/core/set/superset_spec.rb42
-rw-r--r--spec/ruby/core/set/to_a_spec.rb7
-rw-r--r--spec/ruby/core/set/to_s_spec.rb11
-rw-r--r--spec/ruby/core/set/union_spec.rb10
-rw-r--r--spec/ruby/core/signal/signame_spec.rb4
-rw-r--r--spec/ruby/core/signal/trap_spec.rb40
-rw-r--r--spec/ruby/core/sizedqueue/append_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/deq_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/enq_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/pop_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/push_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/shift_spec.rb4
-rw-r--r--spec/ruby/core/string/allocate_spec.rb2
-rw-r--r--spec/ruby/core/string/append_as_bytes_spec.rb8
-rw-r--r--spec/ruby/core/string/append_spec.rb4
-rw-r--r--spec/ruby/core/string/ascii_only_spec.rb30
-rw-r--r--spec/ruby/core/string/b_spec.rb2
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb470
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb568
-rw-r--r--spec/ruby/core/string/bytes_spec.rb6
-rw-r--r--spec/ruby/core/string/byteslice_spec.rb2
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb566
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb28
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb10
-rw-r--r--spec/ruby/core/string/center_spec.rb34
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb12
-rw-r--r--spec/ruby/core/string/chomp_spec.rb40
-rw-r--r--spec/ruby/core/string/chop_spec.rb12
-rw-r--r--spec/ruby/core/string/chr_spec.rb4
-rw-r--r--spec/ruby/core/string/clear_spec.rb6
-rw-r--r--spec/ruby/core/string/clone_spec.rb4
-rw-r--r--spec/ruby/core/string/codepoints_spec.rb6
-rw-r--r--spec/ruby/core/string/comparison_spec.rb4
-rw-r--r--spec/ruby/core/string/concat_spec.rb2
-rw-r--r--spec/ruby/core/string/count_spec.rb14
-rw-r--r--spec/ruby/core/string/crypt_spec.rb30
-rw-r--r--spec/ruby/core/string/dedup_spec.rb4
-rw-r--r--spec/ruby/core/string/delete_prefix_spec.rb16
-rw-r--r--spec/ruby/core/string/delete_spec.rb22
-rw-r--r--spec/ruby/core/string/delete_suffix_spec.rb16
-rw-r--r--spec/ruby/core/string/downcase_spec.rb26
-rw-r--r--spec/ruby/core/string/dump_spec.rb2
-rw-r--r--spec/ruby/core/string/dup_spec.rb6
-rw-r--r--spec/ruby/core/string/each_byte_spec.rb4
-rw-r--r--spec/ruby/core/string/element_set_spec.rb86
-rw-r--r--spec/ruby/core/string/encode_spec.rb36
-rw-r--r--spec/ruby/core/string/encoding_spec.rb12
-rw-r--r--spec/ruby/core/string/eql_spec.rb8
-rw-r--r--spec/ruby/core/string/force_encoding_spec.rb10
-rw-r--r--spec/ruby/core/string/freeze_spec.rb4
-rw-r--r--spec/ruby/core/string/getbyte_spec.rb12
-rw-r--r--spec/ruby/core/string/gsub_spec.rb54
-rw-r--r--spec/ruby/core/string/include_spec.rb8
-rw-r--r--spec/ruby/core/string/index_spec.rb41
-rw-r--r--spec/ruby/core/string/initialize_spec.rb4
-rw-r--r--spec/ruby/core/string/insert_spec.rb16
-rw-r--r--spec/ruby/core/string/inspect_spec.rb2
-rw-r--r--spec/ruby/core/string/ljust_spec.rb32
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb16
-rw-r--r--spec/ruby/core/string/match_spec.rb34
-rw-r--r--spec/ruby/core/string/modulo_spec.rb156
-rw-r--r--spec/ruby/core/string/new_spec.rb10
-rw-r--r--spec/ruby/core/string/ord_spec.rb6
-rw-r--r--spec/ruby/core/string/partition_spec.rb4
-rw-r--r--spec/ruby/core/string/plus_spec.rb18
-rw-r--r--spec/ruby/core/string/prepend_spec.rb12
-rw-r--r--spec/ruby/core/string/reverse_spec.rb18
-rw-r--r--spec/ruby/core/string/rindex_spec.rb16
-rw-r--r--spec/ruby/core/string/rjust_spec.rb32
-rw-r--r--spec/ruby/core/string/rpartition_spec.rb4
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb36
-rw-r--r--spec/ruby/core/string/scan_spec.rb10
-rw-r--r--spec/ruby/core/string/scrub_spec.rb18
-rw-r--r--spec/ruby/core/string/setbyte_spec.rb16
-rw-r--r--spec/ruby/core/string/shared/byte_index_common.rb20
-rw-r--r--spec/ruby/core/string/shared/chars.rb26
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb21
-rw-r--r--spec/ruby/core/string/shared/concat.rb36
-rw-r--r--spec/ruby/core/string/shared/dedup.rb24
-rw-r--r--spec/ruby/core/string/shared/each_char_without_block.rb2
-rw-r--r--spec/ruby/core/string/shared/each_codepoint_without_block.rb10
-rw-r--r--spec/ruby/core/string/shared/each_line.rb58
-rw-r--r--spec/ruby/core/string/shared/each_line_without_block.rb2
-rw-r--r--spec/ruby/core/string/shared/encode.rb50
-rw-r--r--spec/ruby/core/string/shared/eql.rb18
-rw-r--r--spec/ruby/core/string/shared/equal_value.rb10
-rw-r--r--spec/ruby/core/string/shared/grapheme_clusters.rb11
-rw-r--r--spec/ruby/core/string/shared/partition.rb6
-rw-r--r--spec/ruby/core/string/shared/replace.rb14
-rw-r--r--spec/ruby/core/string/shared/slice.rb86
-rw-r--r--spec/ruby/core/string/shared/strip.rb6
-rw-r--r--spec/ruby/core/string/shared/succ.rb14
-rw-r--r--spec/ruby/core/string/shared/to_s.rb4
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb34
-rw-r--r--spec/ruby/core/string/slice_spec.rb60
-rw-r--r--spec/ruby/core/string/split_spec.rb56
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb24
-rw-r--r--spec/ruby/core/string/start_with_spec.rb15
-rw-r--r--spec/ruby/core/string/strip_spec.rb8
-rw-r--r--spec/ruby/core/string/sub_spec.rb42
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb28
-rw-r--r--spec/ruby/core/string/to_c_spec.rb22
-rw-r--r--spec/ruby/core/string/to_f_spec.rb20
-rw-r--r--spec/ruby/core/string/to_i_spec.rb18
-rw-r--r--spec/ruby/core/string/to_r_spec.rb2
-rw-r--r--spec/ruby/core/string/tr_s_spec.rb20
-rw-r--r--spec/ruby/core/string/tr_spec.rb24
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb16
-rw-r--r--spec/ruby/core/string/undump_spec.rb36
-rw-r--r--spec/ruby/core/string/unicode_normalize_spec.rb8
-rw-r--r--spec/ruby/core/string/unicode_normalized_spec.rb20
-rw-r--r--spec/ruby/core/string/unpack/a_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/at_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb38
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb20
-rw-r--r--spec/ruby/core/string/unpack/carret_spec.rb43
-rw-r--r--spec/ruby/core/string/unpack/comment_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb38
-rw-r--r--spec/ruby/core/string/unpack/m_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/p_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/percent_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/r_spec.rb85
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb19
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb84
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb112
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb18
-rw-r--r--spec/ruby/core/string/unpack/u_spec.rb6
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb20
-rw-r--r--spec/ruby/core/string/unpack/x_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/z_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb33
-rw-r--r--spec/ruby/core/string/unpack_spec.rb26
-rw-r--r--spec/ruby/core/string/upcase_spec.rb28
-rw-r--r--spec/ruby/core/string/uplus_spec.rb44
-rw-r--r--spec/ruby/core/string/upto_spec.rb10
-rw-r--r--spec/ruby/core/string/valid_encoding_spec.rb194
-rw-r--r--spec/ruby/core/struct/constants_spec.rb16
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb43
-rw-r--r--spec/ruby/core/struct/dig_spec.rb4
-rw-r--r--spec/ruby/core/struct/each_pair_spec.rb4
-rw-r--r--spec/ruby/core/struct/each_spec.rb2
-rw-r--r--spec/ruby/core/struct/element_reference_spec.rb14
-rw-r--r--spec/ruby/core/struct/element_set_spec.rb15
-rw-r--r--spec/ruby/core/struct/eql_spec.rb2
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/struct/hash_spec.rb4
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb39
-rw-r--r--spec/ruby/core/struct/instance_variable_get_spec.rb2
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb16
-rw-r--r--spec/ruby/core/struct/new_spec.rb131
-rw-r--r--spec/ruby/core/struct/shared/select.rb6
-rw-r--r--spec/ruby/core/struct/struct_spec.rb9
-rw-r--r--spec/ruby/core/struct/to_h_spec.rb8
-rw-r--r--spec/ruby/core/struct/values_at_spec.rb8
-rw-r--r--spec/ruby/core/symbol/all_symbols_spec.rb8
-rw-r--r--spec/ruby/core/symbol/capitalize_spec.rb2
-rw-r--r--spec/ruby/core/symbol/casecmp_spec.rb6
-rw-r--r--spec/ruby/core/symbol/comparison_spec.rb6
-rw-r--r--spec/ruby/core/symbol/downcase_spec.rb2
-rw-r--r--spec/ruby/core/symbol/dup_spec.rb2
-rw-r--r--spec/ruby/core/symbol/empty_spec.rb4
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb34
-rw-r--r--spec/ruby/core/symbol/intern_spec.rb2
-rw-r--r--spec/ruby/core/symbol/match_spec.rb18
-rw-r--r--spec/ruby/core/symbol/shared/id2name.rb14
-rw-r--r--spec/ruby/core/symbol/shared/slice.rb58
-rw-r--r--spec/ruby/core/symbol/swapcase_spec.rb2
-rw-r--r--spec/ruby/core/symbol/symbol_spec.rb4
-rw-r--r--spec/ruby/core/symbol/to_proc_spec.rb48
-rw-r--r--spec/ruby/core/symbol/upcase_spec.rb2
-rw-r--r--spec/ruby/core/thread/abort_on_exception_spec.rb8
-rw-r--r--spec/ruby/core/thread/allocate_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/fixtures/classes.rb104
-rw-r--r--spec/ruby/core/thread/backtrace/location/inspect_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/label_spec.rb194
-rw-r--r--spec/ruby/core/thread/backtrace/location/to_s_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace_locations_spec.rb12
-rw-r--r--spec/ruby/core/thread/backtrace_spec.rb4
-rw-r--r--spec/ruby/core/thread/current_spec.rb10
-rw-r--r--spec/ruby/core/thread/each_caller_location_spec.rb70
-rw-r--r--spec/ruby/core/thread/element_reference_spec.rb4
-rw-r--r--spec/ruby/core/thread/element_set_spec.rb8
-rw-r--r--spec/ruby/core/thread/exit_spec.rb2
-rw-r--r--spec/ruby/core/thread/fetch_spec.rb6
-rw-r--r--spec/ruby/core/thread/fixtures/classes.rb27
-rw-r--r--spec/ruby/core/thread/handle_interrupt_spec.rb6
-rw-r--r--spec/ruby/core/thread/initialize_spec.rb2
-rw-r--r--spec/ruby/core/thread/join_spec.rb20
-rw-r--r--spec/ruby/core/thread/key_spec.rb16
-rw-r--r--spec/ruby/core/thread/keys_spec.rb12
-rw-r--r--spec/ruby/core/thread/kill_spec.rb2
-rw-r--r--spec/ruby/core/thread/list_spec.rb12
-rw-r--r--spec/ruby/core/thread/name_spec.rb2
-rw-r--r--spec/ruby/core/thread/native_thread_id_spec.rb10
-rw-r--r--spec/ruby/core/thread/new_spec.rb4
-rw-r--r--spec/ruby/core/thread/pending_interrupt_spec.rb2
-rw-r--r--spec/ruby/core/thread/priority_spec.rb8
-rw-r--r--spec/ruby/core/thread/raise_spec.rb67
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb12
-rw-r--r--spec/ruby/core/thread/shared/exit.rb6
-rw-r--r--spec/ruby/core/thread/shared/start.rb8
-rw-r--r--spec/ruby/core/thread/shared/to_s.rb20
-rw-r--r--spec/ruby/core/thread/shared/wakeup.rb2
-rw-r--r--spec/ruby/core/thread/thread_variable_get_spec.rb12
-rw-r--r--spec/ruby/core/thread/thread_variable_set_spec.rb10
-rw-r--r--spec/ruby/core/thread/thread_variable_spec.rb22
-rw-r--r--spec/ruby/core/thread/thread_variables_spec.rb3
-rw-r--r--spec/ruby/core/thread/value_spec.rb2
-rw-r--r--spec/ruby/core/threadgroup/default_spec.rb2
-rw-r--r--spec/ruby/core/threadgroup/enclose_spec.rb2
-rw-r--r--spec/ruby/core/threadgroup/enclosed_spec.rb4
-rw-r--r--spec/ruby/core/threadgroup/list_spec.rb4
-rw-r--r--spec/ruby/core/time/_dump_spec.rb6
-rw-r--r--spec/ruby/core/time/_load_spec.rb4
-rw-r--r--spec/ruby/core/time/at_spec.rb54
-rw-r--r--spec/ruby/core/time/ceil_spec.rb4
-rw-r--r--spec/ruby/core/time/comparison_spec.rb2
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb80
-rw-r--r--spec/ruby/core/time/dup_spec.rb14
-rw-r--r--spec/ruby/core/time/eql_spec.rb16
-rw-r--r--spec/ruby/core/time/floor_spec.rb4
-rw-r--r--spec/ruby/core/time/getlocal_spec.rb54
-rw-r--r--spec/ruby/core/time/hash_spec.rb2
-rw-r--r--spec/ruby/core/time/localtime_spec.rb42
-rw-r--r--spec/ruby/core/time/minus_spec.rb16
-rw-r--r--spec/ruby/core/time/new_spec.rb474
-rw-r--r--spec/ruby/core/time/now_spec.rb172
-rw-r--r--spec/ruby/core/time/plus_spec.rb16
-rw-r--r--spec/ruby/core/time/round_spec.rb4
-rw-r--r--spec/ruby/core/time/shared/gmtime.rb6
-rw-r--r--spec/ruby/core/time/shared/inspect.rb2
-rw-r--r--spec/ruby/core/time/shared/now.rb4
-rw-r--r--spec/ruby/core/time/shared/time_params.rb36
-rw-r--r--spec/ruby/core/time/strftime_spec.rb2
-rw-r--r--spec/ruby/core/time/subsec_spec.rb12
-rw-r--r--spec/ruby/core/time/to_r_spec.rb4
-rw-r--r--spec/ruby/core/time/utc_spec.rb4
-rw-r--r--spec/ruby/core/time/zone_spec.rb4
-rw-r--r--spec/ruby/core/tracepoint/allow_reentry_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/binding_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/defined_class_spec.rb10
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb83
-rw-r--r--spec/ruby/core/tracepoint/event_spec.rb6
-rw-r--r--spec/ruby/core/tracepoint/lineno_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/method_id_spec.rb2
-rw-r--r--spec/ruby/core/tracepoint/new_spec.rb22
-rw-r--r--spec/ruby/core/tracepoint/path_spec.rb31
-rw-r--r--spec/ruby/core/tracepoint/raised_exception_spec.rb28
-rw-r--r--spec/ruby/core/tracepoint/self_spec.rb4
-rw-r--r--spec/ruby/core/true/dup_spec.rb2
-rw-r--r--spec/ruby/core/true/singleton_method_spec.rb16
-rw-r--r--spec/ruby/core/true/to_s_spec.rb2
-rw-r--r--spec/ruby/core/true/trueclass_spec.rb4
-rw-r--r--spec/ruby/core/unboundmethod/bind_call_spec.rb4
-rw-r--r--spec/ruby/core/unboundmethod/bind_spec.rb16
-rw-r--r--spec/ruby/core/unboundmethod/equal_value_spec.rb66
-rw-r--r--spec/ruby/core/unboundmethod/fixtures/classes.rb17
-rw-r--r--spec/ruby/core/unboundmethod/inspect_spec.rb2
-rw-r--r--spec/ruby/core/unboundmethod/original_name_spec.rb37
-rw-r--r--spec/ruby/core/unboundmethod/owner_spec.rb6
-rw-r--r--spec/ruby/core/unboundmethod/private_spec.rb25
-rw-r--r--spec/ruby/core/unboundmethod/protected_spec.rb25
-rw-r--r--spec/ruby/core/unboundmethod/public_spec.rb25
-rw-r--r--spec/ruby/core/unboundmethod/shared/dup.rb2
-rw-r--r--spec/ruby/core/unboundmethod/shared/to_s.rb19
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb22
-rw-r--r--spec/ruby/core/unboundmethod/to_s_spec.rb2
-rw-r--r--spec/ruby/core/warning/categories_spec.rb12
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb16
-rw-r--r--spec/ruby/core/warning/element_set_spec.rb24
-rw-r--r--spec/ruby/core/warning/warn_spec.rb30
-rw-r--r--spec/ruby/default.mspec5
-rw-r--r--spec/ruby/language/BEGIN_spec.rb2
-rw-r--r--spec/ruby/language/alias_spec.rb14
-rw-r--r--spec/ruby/language/and_spec.rb16
-rw-r--r--spec/ruby/language/array_spec.rb18
-rw-r--r--spec/ruby/language/assignments_spec.rb199
-rw-r--r--spec/ruby/language/block_spec.rb226
-rw-r--r--spec/ruby/language/break_spec.rb20
-rw-r--r--spec/ruby/language/case_spec.rb51
-rw-r--r--spec/ruby/language/class_spec.rb103
-rw-r--r--spec/ruby/language/class_variable_spec.rb22
-rw-r--r--spec/ruby/language/constants_spec.rb118
-rw-r--r--spec/ruby/language/def_spec.rb131
-rw-r--r--spec/ruby/language/defined_spec.rb226
-rw-r--r--spec/ruby/language/delegation_spec.rb90
-rw-r--r--spec/ruby/language/encoding_spec.rb4
-rw-r--r--spec/ruby/language/ensure_spec.rb32
-rw-r--r--spec/ruby/language/file_spec.rb14
-rw-r--r--spec/ruby/language/fixtures/class_with_class_variable.rb9
-rw-r--r--spec/ruby/language/fixtures/defined.rb27
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb4
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required.rb2
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb2
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb2
-rw-r--r--spec/ruby/language/fixtures/module.rb9
-rw-r--r--spec/ruby/language/fixtures/send.rb10
-rw-r--r--spec/ruby/language/fixtures/super.rb2
-rw-r--r--spec/ruby/language/for_spec.rb157
-rw-r--r--spec/ruby/language/hash_spec.rb69
-rw-r--r--spec/ruby/language/heredoc_spec.rb4
-rw-r--r--spec/ruby/language/if_spec.rb2
-rw-r--r--spec/ruby/language/it_parameter_spec.rb108
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb104
-rw-r--r--spec/ruby/language/lambda_spec.rb140
-rw-r--r--spec/ruby/language/line_spec.rb2
-rw-r--r--spec/ruby/language/loop_spec.rb2
-rw-r--r--spec/ruby/language/magic_comment_spec.rb3
-rw-r--r--spec/ruby/language/match_spec.rb8
-rw-r--r--spec/ruby/language/metaclass_spec.rb22
-rw-r--r--spec/ruby/language/method_spec.rb325
-rw-r--r--spec/ruby/language/module_spec.rb67
-rw-r--r--spec/ruby/language/next_spec.rb4
-rw-r--r--spec/ruby/language/not_spec.rb32
-rw-r--r--spec/ruby/language/numbered_parameters_spec.rb32
-rw-r--r--spec/ruby/language/numbers_spec.rb6
-rw-r--r--spec/ruby/language/optional_assignments_spec.rb10
-rw-r--r--spec/ruby/language/or_spec.rb32
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb30
-rw-r--r--spec/ruby/language/precedence_spec.rb16
-rw-r--r--spec/ruby/language/predefined_spec.rb345
-rw-r--r--spec/ruby/language/private_spec.rb20
-rw-r--r--spec/ruby/language/proc_spec.rb44
-rw-r--r--spec/ruby/language/redo_spec.rb2
-rw-r--r--spec/ruby/language/regexp/anchors_spec.rb58
-rw-r--r--spec/ruby/language/regexp/back-references_spec.rb54
-rw-r--r--spec/ruby/language/regexp/character_classes_spec.rb231
-rw-r--r--spec/ruby/language/regexp/encoding_spec.rb20
-rw-r--r--spec/ruby/language/regexp/escapes_spec.rb12
-rw-r--r--spec/ruby/language/regexp/grouping_spec.rb6
-rw-r--r--spec/ruby/language/regexp/interpolation_spec.rb6
-rw-r--r--spec/ruby/language/regexp/modifiers_spec.rb40
-rw-r--r--spec/ruby/language/regexp/repetition_spec.rb2
-rw-r--r--spec/ruby/language/regexp_spec.rb26
-rw-r--r--spec/ruby/language/rescue_spec.rb44
-rw-r--r--spec/ruby/language/reserved_keywords.rb149
-rw-r--r--spec/ruby/language/retry_spec.rb8
-rw-r--r--spec/ruby/language/return_spec.rb14
-rw-r--r--spec/ruby/language/safe_navigator_spec.rb8
-rw-r--r--spec/ruby/language/send_spec.rb69
-rw-r--r--spec/ruby/language/shared/__FILE__.rb4
-rw-r--r--spec/ruby/language/shared/__LINE__.rb2
-rw-r--r--spec/ruby/language/singleton_class_spec.rb86
-rw-r--r--spec/ruby/language/source_encoding_spec.rb4
-rw-r--r--spec/ruby/language/string_spec.rb24
-rw-r--r--spec/ruby/language/super_spec.rb22
-rw-r--r--spec/ruby/language/symbol_spec.rb22
-rw-r--r--spec/ruby/language/throw_spec.rb10
-rw-r--r--spec/ruby/language/undef_spec.rb14
-rw-r--r--spec/ruby/language/variables_spec.rb44
-rw-r--r--spec/ruby/language/while_spec.rb16
-rw-r--r--spec/ruby/language/yield_spec.rb32
-rw-r--r--spec/ruby/library/English/English_spec.rb64
-rw-r--r--spec/ruby/library/English/alias_spec.rb6
-rw-r--r--spec/ruby/library/base64/strict_decode64_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/BigDecimal_spec.rb76
-rw-r--r--spec/ruby/library/bigdecimal/add_spec.rb16
-rw-r--r--spec/ruby/library/bigdecimal/ceil_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/constants_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/core_spec.rb17
-rw-r--r--spec/ruby/library/bigdecimal/div_spec.rb28
-rw-r--r--spec/ruby/library/bigdecimal/divmod_spec.rb88
-rw-r--r--spec/ruby/library/bigdecimal/fix_spec.rb2
-rw-r--r--spec/ruby/library/bigdecimal/floor_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/gt_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/gte_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/lt_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/lte_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/mode_spec.rb10
-rw-r--r--spec/ruby/library/bigdecimal/mult_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/nonzero_spec.rb10
-rw-r--r--spec/ruby/library/bigdecimal/precs_spec.rb55
-rw-r--r--spec/ruby/library/bigdecimal/remainder_spec.rb29
-rw-r--r--spec/ruby/library/bigdecimal/round_spec.rb24
-rw-r--r--spec/ruby/library/bigdecimal/shared/clone.rb2
-rw-r--r--spec/ruby/library/bigdecimal/shared/modulo.rb22
-rw-r--r--spec/ruby/library/bigdecimal/shared/power.rb4
-rw-r--r--spec/ruby/library/bigdecimal/shared/quo.rb1
-rw-r--r--spec/ruby/library/bigdecimal/shared/to_int.rb4
-rw-r--r--spec/ruby/library/bigdecimal/sqrt_spec.rb18
-rw-r--r--spec/ruby/library/bigdecimal/sub_spec.rb8
-rw-r--r--spec/ruby/library/bigdecimal/to_f_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/to_r_spec.rb14
-rw-r--r--spec/ruby/library/bigdecimal/to_s_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/truncate_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/util_spec.rb2
-rw-r--r--spec/ruby/library/cgi/cookie/domain_spec.rb33
-rw-r--r--spec/ruby/library/cgi/cookie/expires_spec.rb33
-rw-r--r--spec/ruby/library/cgi/cookie/initialize_spec.rb235
-rw-r--r--spec/ruby/library/cgi/cookie/name_spec.rb33
-rw-r--r--spec/ruby/library/cgi/cookie/parse_spec.rb41
-rw-r--r--spec/ruby/library/cgi/cookie/path_spec.rb33
-rw-r--r--spec/ruby/library/cgi/cookie/secure_spec.rb99
-rw-r--r--spec/ruby/library/cgi/cookie/to_s_spec.rb51
-rw-r--r--spec/ruby/library/cgi/cookie/value_spec.rb121
-rw-r--r--spec/ruby/library/cgi/escapeElement_spec.rb8
-rw-r--r--spec/ruby/library/cgi/escapeHTML_spec.rb6
-rw-r--r--spec/ruby/library/cgi/escapeURIComponent_spec.rb105
-rw-r--r--spec/ruby/library/cgi/escape_spec.rb6
-rw-r--r--spec/ruby/library/cgi/htmlextension/a_spec.rb73
-rw-r--r--spec/ruby/library/cgi/htmlextension/base_spec.rb47
-rw-r--r--spec/ruby/library/cgi/htmlextension/blockquote_spec.rb47
-rw-r--r--spec/ruby/library/cgi/htmlextension/br_spec.rb31
-rw-r--r--spec/ruby/library/cgi/htmlextension/caption_spec.rb47
-rw-r--r--spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb121
-rw-r--r--spec/ruby/library/cgi/htmlextension/checkbox_spec.rb113
-rw-r--r--spec/ruby/library/cgi/htmlextension/doctype_spec.rb41
-rw-r--r--spec/ruby/library/cgi/htmlextension/file_field_spec.rb105
-rw-r--r--spec/ruby/library/cgi/htmlextension/form_spec.rb85
-rw-r--r--spec/ruby/library/cgi/htmlextension/frame_spec.rb21
-rw-r--r--spec/ruby/library/cgi/htmlextension/frameset_spec.rb21
-rw-r--r--spec/ruby/library/cgi/htmlextension/hidden_spec.rb87
-rw-r--r--spec/ruby/library/cgi/htmlextension/html_spec.rb99
-rw-r--r--spec/ruby/library/cgi/htmlextension/image_button_spec.rb101
-rw-r--r--spec/ruby/library/cgi/htmlextension/img_spec.rb123
-rw-r--r--spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb93
-rw-r--r--spec/ruby/library/cgi/htmlextension/password_field_spec.rb123
-rw-r--r--spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb13
-rw-r--r--spec/ruby/library/cgi/htmlextension/radio_button_spec.rb113
-rw-r--r--spec/ruby/library/cgi/htmlextension/radio_group_spec.rb123
-rw-r--r--spec/ruby/library/cgi/htmlextension/reset_spec.rb83
-rw-r--r--spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb13
-rw-r--r--spec/ruby/library/cgi/htmlextension/submit_spec.rb83
-rw-r--r--spec/ruby/library/cgi/htmlextension/text_field_spec.rb123
-rw-r--r--spec/ruby/library/cgi/htmlextension/textarea_spec.rb107
-rw-r--r--spec/ruby/library/cgi/http_header_spec.rb11
-rw-r--r--spec/ruby/library/cgi/initialize_spec.rb209
-rw-r--r--spec/ruby/library/cgi/out_spec.rb97
-rw-r--r--spec/ruby/library/cgi/parse_spec.rb37
-rw-r--r--spec/ruby/library/cgi/pretty_spec.rb19
-rw-r--r--spec/ruby/library/cgi/print_spec.rb39
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_charset_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_language_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/accept_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/auth_type_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/cache_control_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/content_length_spec.rb39
-rw-r--r--spec/ruby/library/cgi/queryextension/content_type_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/cookies_spec.rb15
-rw-r--r--spec/ruby/library/cgi/queryextension/element_reference_spec.rb41
-rw-r--r--spec/ruby/library/cgi/queryextension/from_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/has_key_spec.rb11
-rw-r--r--spec/ruby/library/cgi/queryextension/host_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/include_spec.rb11
-rw-r--r--spec/ruby/library/cgi/queryextension/key_spec.rb11
-rw-r--r--spec/ruby/library/cgi/queryextension/keys_spec.rb29
-rw-r--r--spec/ruby/library/cgi/queryextension/multipart_spec.rb47
-rw-r--r--spec/ruby/library/cgi/queryextension/negotiate_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/params_spec.rb55
-rw-r--r--spec/ruby/library/cgi/queryextension/path_info_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/path_translated_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/pragma_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/query_string_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/referer_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_addr_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_host_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_ident_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/remote_user_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/request_method_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/script_name_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/server_name_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/server_port_spec.rb39
-rw-r--r--spec/ruby/library/cgi/queryextension/server_protocol_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/server_software_spec.rb33
-rw-r--r--spec/ruby/library/cgi/queryextension/shared/has_key.rb6
-rw-r--r--spec/ruby/library/cgi/queryextension/user_agent_spec.rb33
-rw-r--r--spec/ruby/library/cgi/rfc1123_date_spec.rb15
-rw-r--r--spec/ruby/library/cgi/shared/http_header.rb10
-rw-r--r--spec/ruby/library/cgi/unescapeElement_spec.rb8
-rw-r--r--spec/ruby/library/cgi/unescapeHTML_spec.rb6
-rw-r--r--spec/ruby/library/cgi/unescapeURIComponent_spec.rb128
-rw-r--r--spec/ruby/library/cgi/unescape_spec.rb8
-rw-r--r--spec/ruby/library/coverage/result_spec.rb116
-rw-r--r--spec/ruby/library/coverage/start_spec.rb120
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb42
-rw-r--r--spec/ruby/library/csv/generate_spec.rb2
-rw-r--r--spec/ruby/library/csv/parse_spec.rb4
-rw-r--r--spec/ruby/library/csv/readlines_spec.rb2
-rw-r--r--spec/ruby/library/date/add_month_spec.rb8
-rw-r--r--spec/ruby/library/date/add_spec.rb8
-rw-r--r--spec/ruby/library/date/constants_spec.rb4
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb74
-rw-r--r--spec/ruby/library/date/eql_spec.rb4
-rw-r--r--spec/ruby/library/date/friday_spec.rb4
-rw-r--r--spec/ruby/library/date/gregorian_leap_spec.rb10
-rw-r--r--spec/ruby/library/date/gregorian_spec.rb6
-rw-r--r--spec/ruby/library/date/iso8601_spec.rb8
-rw-r--r--spec/ruby/library/date/julian_leap_spec.rb10
-rw-r--r--spec/ruby/library/date/julian_spec.rb4
-rw-r--r--spec/ruby/library/date/minus_month_spec.rb8
-rw-r--r--spec/ruby/library/date/minus_spec.rb6
-rw-r--r--spec/ruby/library/date/monday_spec.rb2
-rw-r--r--spec/ruby/library/date/parse_spec.rb6
-rw-r--r--spec/ruby/library/date/plus_spec.rb2
-rw-r--r--spec/ruby/library/date/saturday_spec.rb2
-rw-r--r--spec/ruby/library/date/shared/civil.rb16
-rw-r--r--spec/ruby/library/date/shared/commercial.rb18
-rw-r--r--spec/ruby/library/date/shared/valid_civil.rb16
-rw-r--r--spec/ruby/library/date/shared/valid_commercial.rb24
-rw-r--r--spec/ruby/library/date/shared/valid_jd.rb14
-rw-r--r--spec/ruby/library/date/sunday_spec.rb2
-rw-r--r--spec/ruby/library/date/thursday_spec.rb2
-rw-r--r--spec/ruby/library/date/today_spec.rb2
-rw-r--r--spec/ruby/library/date/tuesday_spec.rb2
-rw-r--r--spec/ruby/library/date/wednesday_spec.rb2
-rw-r--r--spec/ruby/library/datetime/deconstruct_keys_spec.rb78
-rw-r--r--spec/ruby/library/datetime/hour_spec.rb10
-rw-r--r--spec/ruby/library/datetime/new_spec.rb2
-rw-r--r--spec/ruby/library/datetime/now_spec.rb2
-rw-r--r--spec/ruby/library/datetime/parse_spec.rb12
-rw-r--r--spec/ruby/library/datetime/rfc2822_spec.rb2
-rw-r--r--spec/ruby/library/datetime/shared/min.rb10
-rw-r--r--spec/ruby/library/datetime/shared/sec.rb6
-rw-r--r--spec/ruby/library/datetime/time/to_datetime_spec.rb20
-rw-r--r--spec/ruby/library/datetime/to_date_spec.rb2
-rw-r--r--spec/ruby/library/datetime/to_s_spec.rb2
-rw-r--r--spec/ruby/library/datetime/to_time_spec.rb22
-rw-r--r--spec/ruby/library/delegate/delegate_class/instance_method_spec.rb14
-rw-r--r--spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb12
-rw-r--r--spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb12
-rw-r--r--spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb12
-rw-r--r--spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb10
-rw-r--r--spec/ruby/library/delegate/delegator/eql_spec.rb8
-rw-r--r--spec/ruby/library/delegate/delegator/equal_spec.rb6
-rw-r--r--spec/ruby/library/delegate/delegator/equal_value_spec.rb6
-rw-r--r--spec/ruby/library/delegate/delegator/frozen_spec.rb14
-rw-r--r--spec/ruby/library/delegate/delegator/marshal_spec.rb2
-rw-r--r--spec/ruby/library/delegate/delegator/method_spec.rb18
-rw-r--r--spec/ruby/library/delegate/delegator/methods_spec.rb14
-rw-r--r--spec/ruby/library/delegate/delegator/not_equal_spec.rb6
-rw-r--r--spec/ruby/library/delegate/delegator/private_methods_spec.rb8
-rw-r--r--spec/ruby/library/delegate/delegator/protected_methods_spec.rb4
-rw-r--r--spec/ruby/library/delegate/delegator/public_methods_spec.rb4
-rw-r--r--spec/ruby/library/delegate/delegator/send_spec.rb8
-rw-r--r--spec/ruby/library/delegate/delegator/tap_spec.rb2
-rw-r--r--spec/ruby/library/digest/bubblebabble_spec.rb6
-rw-r--r--spec/ruby/library/digest/hexencode_spec.rb4
-rw-r--r--spec/ruby/library/digest/instance/shared/update.rb2
-rw-r--r--spec/ruby/library/digest/md5/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/md5/shared/constants.rb2
-rw-r--r--spec/ruby/library/digest/sha1/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha1/shared/constants.rb2
-rw-r--r--spec/ruby/library/digest/sha256/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha256/shared/constants.rb2
-rw-r--r--spec/ruby/library/digest/sha384/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha384/shared/constants.rb2
-rw-r--r--spec/ruby/library/digest/sha512/file_spec.rb8
-rw-r--r--spec/ruby/library/digest/sha512/shared/constants.rb2
-rw-r--r--spec/ruby/library/erb/filename_spec.rb4
-rw-r--r--spec/ruby/library/erb/new_spec.rb28
-rw-r--r--spec/ruby/library/erb/result_spec.rb4
-rw-r--r--spec/ruby/library/erb/run_spec.rb4
-rw-r--r--spec/ruby/library/etc/confstr_spec.rb4
-rw-r--r--spec/ruby/library/etc/getgrgid_spec.rb8
-rw-r--r--spec/ruby/library/etc/getgrnam_spec.rb2
-rw-r--r--spec/ruby/library/etc/getlogin_spec.rb4
-rw-r--r--spec/ruby/library/etc/getpwnam_spec.rb2
-rw-r--r--spec/ruby/library/etc/getpwuid_spec.rb2
-rw-r--r--spec/ruby/library/etc/group_spec.rb4
-rw-r--r--spec/ruby/library/etc/nprocessors_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.rb2
-rw-r--r--spec/ruby/library/expect/expect_spec.rb4
-rw-r--r--spec/ruby/library/fiddle/handle/initialize_spec.rb2
-rw-r--r--spec/ruby/library/find/find_spec.rb2
-rw-r--r--spec/ruby/library/getoptlong/error_message_spec.rb2
-rw-r--r--spec/ruby/library/getoptlong/ordering_spec.rb4
-rw-r--r--spec/ruby/library/getoptlong/set_options_spec.rb14
-rw-r--r--spec/ruby/library/getoptlong/shared/get.rb2
-rw-r--r--spec/ruby/library/io-wait/wait_readable_spec.rb4
-rw-r--r--spec/ruby/library/io-wait/wait_spec.rb65
-rw-r--r--spec/ruby/library/io-wait/wait_writable_spec.rb4
-rw-r--r--spec/ruby/library/ipaddr/new_spec.rb8
-rw-r--r--spec/ruby/library/ipaddr/operator_spec.rb16
-rw-r--r--spec/ruby/library/ipaddr/reverse_spec.rb4
-rw-r--r--spec/ruby/library/logger/device/new_spec.rb8
-rw-r--r--spec/ruby/library/logger/logger/add_spec.rb6
-rw-r--r--spec/ruby/library/logger/logger/datetime_format_spec.rb2
-rw-r--r--spec/ruby/library/logger/logger/new_spec.rb10
-rw-r--r--spec/ruby/library/logger/logger/unknown_spec.rb2
-rw-r--r--spec/ruby/library/matrix/antisymmetric_spec.rb8
-rw-r--r--spec/ruby/library/matrix/build_spec.rb20
-rw-r--r--spec/ruby/library/matrix/clone_spec.rb8
-rw-r--r--spec/ruby/library/matrix/coerce_spec.rb2
-rw-r--r--spec/ruby/library/matrix/column_spec.rb6
-rw-r--r--spec/ruby/library/matrix/column_vector_spec.rb6
-rw-r--r--spec/ruby/library/matrix/column_vectors_spec.rb4
-rw-r--r--spec/ruby/library/matrix/columns_spec.rb4
-rw-r--r--spec/ruby/library/matrix/constructor_spec.rb20
-rw-r--r--spec/ruby/library/matrix/diagonal_spec.rb16
-rw-r--r--spec/ruby/library/matrix/divide_spec.rb16
-rw-r--r--spec/ruby/library/matrix/each_spec.rb10
-rw-r--r--spec/ruby/library/matrix/each_with_index_spec.rb10
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb6
-rw-r--r--spec/ruby/library/matrix/element_reference_spec.rb4
-rw-r--r--spec/ruby/library/matrix/empty_spec.rb22
-rw-r--r--spec/ruby/library/matrix/eql_spec.rb2
-rw-r--r--spec/ruby/library/matrix/exponent_spec.rb10
-rw-r--r--spec/ruby/library/matrix/find_index_spec.rb16
-rw-r--r--spec/ruby/library/matrix/hash_spec.rb2
-rw-r--r--spec/ruby/library/matrix/hermitian_spec.rb12
-rw-r--r--spec/ruby/library/matrix/lower_triangular_spec.rb22
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb2
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb4
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/l_spec.rb2
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/p_spec.rb2
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/solve_spec.rb6
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb4
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/u_spec.rb2
-rw-r--r--spec/ruby/library/matrix/minor_spec.rb2
-rw-r--r--spec/ruby/library/matrix/minus_spec.rb20
-rw-r--r--spec/ruby/library/matrix/multiply_spec.rb14
-rw-r--r--spec/ruby/library/matrix/new_spec.rb2
-rw-r--r--spec/ruby/library/matrix/normal_spec.rb2
-rw-r--r--spec/ruby/library/matrix/orthogonal_spec.rb2
-rw-r--r--spec/ruby/library/matrix/permutation_spec.rb14
-rw-r--r--spec/ruby/library/matrix/plus_spec.rb20
-rw-r--r--spec/ruby/library/matrix/real_spec.rb12
-rw-r--r--spec/ruby/library/matrix/regular_spec.rb12
-rw-r--r--spec/ruby/library/matrix/round_spec.rb2
-rw-r--r--spec/ruby/library/matrix/row_spec.rb6
-rw-r--r--spec/ruby/library/matrix/row_vector_spec.rb4
-rw-r--r--spec/ruby/library/matrix/row_vectors_spec.rb4
-rw-r--r--spec/ruby/library/matrix/rows_spec.rb8
-rw-r--r--spec/ruby/library/matrix/scalar_spec.rb4
-rw-r--r--spec/ruby/library/matrix/shared/collect.rb6
-rw-r--r--spec/ruby/library/matrix/shared/conjugate.rb2
-rw-r--r--spec/ruby/library/matrix/shared/determinant.rb4
-rw-r--r--spec/ruby/library/matrix/shared/equal_value.rb20
-rw-r--r--spec/ruby/library/matrix/shared/identity.rb4
-rw-r--r--spec/ruby/library/matrix/shared/imaginary.rb2
-rw-r--r--spec/ruby/library/matrix/shared/inverse.rb6
-rw-r--r--spec/ruby/library/matrix/shared/rectangular.rb2
-rw-r--r--spec/ruby/library/matrix/shared/trace.rb2
-rw-r--r--spec/ruby/library/matrix/shared/transpose.rb2
-rw-r--r--spec/ruby/library/matrix/singular_spec.rb12
-rw-r--r--spec/ruby/library/matrix/square_spec.rb16
-rw-r--r--spec/ruby/library/matrix/symmetric_spec.rb8
-rw-r--r--spec/ruby/library/matrix/unitary_spec.rb2
-rw-r--r--spec/ruby/library/matrix/upper_triangular_spec.rb22
-rw-r--r--spec/ruby/library/matrix/vector/cross_product_spec.rb2
-rw-r--r--spec/ruby/library/matrix/vector/each2_spec.rb12
-rw-r--r--spec/ruby/library/matrix/vector/eql_spec.rb4
-rw-r--r--spec/ruby/library/matrix/vector/inner_product_spec.rb2
-rw-r--r--spec/ruby/library/matrix/vector/normalize_spec.rb4
-rw-r--r--spec/ruby/library/matrix/zero_spec.rb4
-rw-r--r--spec/ruby/library/monitor/exit_spec.rb2
-rw-r--r--spec/ruby/library/monitor/mon_initialize_spec.rb2
-rw-r--r--spec/ruby/library/monitor/synchronize_spec.rb4
-rw-r--r--spec/ruby/library/net-ftp/FTPError_spec.rb11
-rw-r--r--spec/ruby/library/net-ftp/FTPPermError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/FTPProtoError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/FTPReplyError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/FTPTempError_spec.rb17
-rw-r--r--spec/ruby/library/net-ftp/abort_spec.rb97
-rw-r--r--spec/ruby/library/net-ftp/acct_spec.rb111
-rw-r--r--spec/ruby/library/net-ftp/binary_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/chdir_spec.rb145
-rw-r--r--spec/ruby/library/net-ftp/close_spec.rb47
-rw-r--r--spec/ruby/library/net-ftp/closed_spec.rb31
-rw-r--r--spec/ruby/library/net-ftp/connect_spec.rb81
-rw-r--r--spec/ruby/library/net-ftp/debug_mode_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/default_passive_spec.rb11
-rw-r--r--spec/ruby/library/net-ftp/delete_spec.rb113
-rw-r--r--spec/ruby/library/net-ftp/dir_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/fixtures/server.rb436
-rw-r--r--spec/ruby/library/net-ftp/get_spec.rb31
-rw-r--r--spec/ruby/library/net-ftp/getbinaryfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/getdir_spec.rb11
-rw-r--r--spec/ruby/library/net-ftp/gettextfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/help_spec.rb103
-rw-r--r--spec/ruby/library/net-ftp/initialize_spec.rb557
-rw-r--r--spec/ruby/library/net-ftp/last_response_code_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/last_response_spec.rb39
-rw-r--r--spec/ruby/library/net-ftp/lastresp_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/list_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/login_spec.rb379
-rw-r--r--spec/ruby/library/net-ftp/ls_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/mdtm_spec.rb59
-rw-r--r--spec/ruby/library/net-ftp/mkdir_spec.rb97
-rw-r--r--spec/ruby/library/net-ftp/mtime_spec.rb73
-rw-r--r--spec/ruby/library/net-ftp/nlst_spec.rb141
-rw-r--r--spec/ruby/library/net-ftp/noop_spec.rb59
-rw-r--r--spec/ruby/library/net-ftp/open_spec.rb73
-rw-r--r--spec/ruby/library/net-ftp/passive_spec.rb39
-rw-r--r--spec/ruby/library/net-ftp/put_spec.rb31
-rw-r--r--spec/ruby/library/net-ftp/putbinaryfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/puttextfile_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/pwd_spec.rb101
-rw-r--r--spec/ruby/library/net-ftp/quit_spec.rb51
-rw-r--r--spec/ruby/library/net-ftp/rename_spec.rb159
-rw-r--r--spec/ruby/library/net-ftp/resume_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/retrbinary_spec.rb47
-rw-r--r--spec/ruby/library/net-ftp/retrlines_spec.rb55
-rw-r--r--spec/ruby/library/net-ftp/return_code_spec.rb35
-rw-r--r--spec/ruby/library/net-ftp/rmdir_spec.rb111
-rw-r--r--spec/ruby/library/net-ftp/sendcmd_spec.rb103
-rw-r--r--spec/ruby/library/net-ftp/set_socket_spec.rb13
-rw-r--r--spec/ruby/library/net-ftp/shared/getbinaryfile.rb226
-rw-r--r--spec/ruby/library/net-ftp/shared/gettextfile.rb162
-rw-r--r--spec/ruby/library/net-ftp/shared/last_response_code.rb40
-rw-r--r--spec/ruby/library/net-ftp/shared/list.rb176
-rw-r--r--spec/ruby/library/net-ftp/shared/putbinaryfile.rb258
-rw-r--r--spec/ruby/library/net-ftp/shared/puttextfile.rb214
-rw-r--r--spec/ruby/library/net-ftp/shared/pwd.rb4
-rw-r--r--spec/ruby/library/net-ftp/site_spec.rb101
-rw-r--r--spec/ruby/library/net-ftp/size_spec.rb91
-rw-r--r--spec/ruby/library/net-ftp/spec_helper.rb8
-rw-r--r--spec/ruby/library/net-ftp/status_spec.rb105
-rw-r--r--spec/ruby/library/net-ftp/storbinary_spec.rb73
-rw-r--r--spec/ruby/library/net-ftp/storlines_spec.rb65
-rw-r--r--spec/ruby/library/net-ftp/system_spec.rb91
-rw-r--r--spec/ruby/library/net-ftp/voidcmd_spec.rb103
-rw-r--r--spec/ruby/library/net-ftp/welcome_spec.rb39
-rw-r--r--spec/ruby/library/net-http/HTTPServerException_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/Proxy_spec.rb6
-rw-r--r--spec/ruby/library/net-http/http/copy_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/default_port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/delete_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/finish_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/get_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/head_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/http_default_port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/https_default_port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/initialize_spec.rb10
-rw-r--r--spec/ruby/library/net-http/http/inspect_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/lock_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/mkcol_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/move_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/new_spec.rb40
-rw-r--r--spec/ruby/library/net-http/http/newobj_spec.rb12
-rw-r--r--spec/ruby/library/net-http/http/open_timeout_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/options_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/port_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/post_spec.rb14
-rw-r--r--spec/ruby/library/net-http/http/propfind_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/proppatch_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/proxy_address_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/proxy_class_spec.rb4
-rw-r--r--spec/ruby/library/net-http/http/proxy_pass_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/proxy_port_spec.rb12
-rw-r--r--spec/ruby/library/net-http/http/proxy_user_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/put_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/read_timeout_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_types_spec.rb56
-rw-r--r--spec/ruby/library/net-http/http/send_request_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/set_debug_output_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/shared/request_get.rb4
-rw-r--r--spec/ruby/library/net-http/http/shared/request_head.rb10
-rw-r--r--spec/ruby/library/net-http/http/shared/request_post.rb4
-rw-r--r--spec/ruby/library/net-http/http/shared/request_put.rb4
-rw-r--r--spec/ruby/library/net-http/http/shared/started.rb6
-rw-r--r--spec/ruby/library/net-http/http/shared/version_1_1.rb2
-rw-r--r--spec/ruby/library/net-http/http/shared/version_1_2.rb2
-rw-r--r--spec/ruby/library/net-http/http/start_spec.rb26
-rw-r--r--spec/ruby/library/net-http/http/trace_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/unlock_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/use_ssl_spec.rb2
-rw-r--r--spec/ruby/library/net-http/http/version_1_2_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb56
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpheader/chunked_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/content_length_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpheader/content_range_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/content_type_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/delete_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/each_value_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/element_reference_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpheader/element_set_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpheader/fetch_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/get_fields_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpheader/key_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/main_type_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/range_length_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpheader/range_spec.rb10
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_header.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_name.rb2
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_range.rb16
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/size.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/sub_type_spec.rb6
-rw-r--r--spec/ruby/library/net-http/httpheader/to_hash_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httprequest/initialize_spec.rb4
-rw-r--r--spec/ruby/library/net-http/httpresponse/error_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpresponse/header_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_body_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_header_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_new_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/reading_body_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpresponse/response_spec.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/shared/body.rb2
-rw-r--r--spec/ruby/library/net-http/httpresponse/value_spec.rb12
-rw-r--r--spec/ruby/library/objectspace/dump_all_spec.rb4
-rw-r--r--spec/ruby/library/objectspace/dump_spec.rb22
-rw-r--r--spec/ruby/library/objectspace/memsize_of_all_spec.rb4
-rw-r--r--spec/ruby/library/objectspace/memsize_of_spec.rb2
-rw-r--r--spec/ruby/library/objectspace/reachable_objects_from_spec.rb12
-rw-r--r--spec/ruby/library/objectspace/trace_object_allocations_spec.rb34
-rw-r--r--spec/ruby/library/observer/notify_observers_spec.rb2
-rw-r--r--spec/ruby/library/open3/popen3_spec.rb8
-rw-r--r--spec/ruby/library/openssl/cipher_spec.rb2
-rw-r--r--spec/ruby/library/openssl/digest/initialize_spec.rb16
-rw-r--r--spec/ruby/library/openssl/digest/shared/update.rb8
-rw-r--r--spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb12
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb42
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb45
-rw-r--r--spec/ruby/library/openssl/random/shared/random_bytes.rb4
-rw-r--r--spec/ruby/library/openssl/secure_compare_spec.rb12
-rw-r--r--spec/ruby/library/openssl/shared/constants.rb2
-rw-r--r--spec/ruby/library/openssl/x509/name/parse_spec.rb4
-rw-r--r--spec/ruby/library/openstruct/delete_field_spec.rb6
-rw-r--r--spec/ruby/library/openstruct/equal_value_spec.rb22
-rw-r--r--spec/ruby/library/openstruct/frozen_spec.rb12
-rw-r--r--spec/ruby/library/openstruct/initialize_spec.rb2
-rw-r--r--spec/ruby/library/openstruct/marshal_load_spec.rb2
-rw-r--r--spec/ruby/library/openstruct/method_missing_spec.rb6
-rw-r--r--spec/ruby/library/openstruct/new_spec.rb4
-rw-r--r--spec/ruby/library/openstruct/shared/inspect.rb2
-rw-r--r--spec/ruby/library/openstruct/to_h_spec.rb10
-rw-r--r--spec/ruby/library/pathname/birthtime_spec.rb4
-rw-r--r--spec/ruby/library/pathname/empty_spec.rb8
-rw-r--r--spec/ruby/library/pathname/glob_spec.rb4
-rw-r--r--spec/ruby/library/pathname/inspect_spec.rb2
-rw-r--r--spec/ruby/library/pathname/new_spec.rb12
-rw-r--r--spec/ruby/library/pathname/pathname_spec.rb4
-rw-r--r--spec/ruby/library/pathname/realdirpath_spec.rb2
-rw-r--r--spec/ruby/library/pathname/realpath_spec.rb2
-rw-r--r--spec/ruby/library/pathname/relative_path_from_spec.rb4
-rw-r--r--spec/ruby/library/prime/each_spec.rb22
-rw-r--r--spec/ruby/library/prime/instance_spec.rb8
-rw-r--r--spec/ruby/library/prime/integer/prime_division_spec.rb2
-rw-r--r--spec/ruby/library/prime/integer/prime_spec.rb14
-rw-r--r--spec/ruby/library/prime/prime_division_spec.rb4
-rw-r--r--spec/ruby/library/prime/prime_spec.rb14
-rw-r--r--spec/ruby/library/random/formatter/alphanumeric_spec.rb22
-rw-r--r--spec/ruby/library/rbconfig/rbconfig_spec.rb8
-rw-r--r--spec/ruby/library/rbconfig/sizeof/limits_spec.rb6
-rw-r--r--spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb6
-rw-r--r--spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb14
-rw-r--r--spec/ruby/library/rbconfig/unicode_version_spec.rb14
-rw-r--r--spec/ruby/library/readline/basic_quote_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/basic_word_break_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/completer_quote_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/completer_word_break_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/completion_append_character_spec.rb2
-rw-r--r--spec/ruby/library/readline/completion_case_fold_spec.rb2
-rw-r--r--spec/ruby/library/readline/completion_proc_spec.rb4
-rw-r--r--spec/ruby/library/readline/constants_spec.rb4
-rw-r--r--spec/ruby/library/readline/emacs_editing_mode_spec.rb2
-rw-r--r--spec/ruby/library/readline/filename_quote_characters_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/append_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/delete_at_spec.rb4
-rw-r--r--spec/ruby/library/readline/history/element_reference_spec.rb12
-rw-r--r--spec/ruby/library/readline/history/element_set_spec.rb4
-rw-r--r--spec/ruby/library/readline/history/empty_spec.rb6
-rw-r--r--spec/ruby/library/readline/history/history_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/pop_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/push_spec.rb2
-rw-r--r--spec/ruby/library/readline/history/shift_spec.rb2
-rw-r--r--spec/ruby/library/readline/vi_editing_mode_spec.rb2
-rw-r--r--spec/ruby/library/resolv/get_address_spec.rb2
-rw-r--r--spec/ruby/library/resolv/get_name_spec.rb2
-rw-r--r--spec/ruby/library/ripper/lex_spec.rb6
-rw-r--r--spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb2
-rw-r--r--spec/ruby/library/securerandom/base64_spec.rb10
-rw-r--r--spec/ruby/library/securerandom/hex_spec.rb14
-rw-r--r--spec/ruby/library/securerandom/random_bytes_spec.rb12
-rw-r--r--spec/ruby/library/securerandom/random_number_spec.rb20
-rw-r--r--spec/ruby/library/set/add_spec.rb27
-rw-r--r--spec/ruby/library/set/append_spec.rb7
-rw-r--r--spec/ruby/library/set/case_compare_spec.rb12
-rw-r--r--spec/ruby/library/set/case_equality_spec.rb7
-rw-r--r--spec/ruby/library/set/classify_spec.rb27
-rw-r--r--spec/ruby/library/set/clear_spec.rb17
-rw-r--r--spec/ruby/library/set/collect_spec.rb7
-rw-r--r--spec/ruby/library/set/compare_by_identity_spec.rb143
-rw-r--r--spec/ruby/library/set/comparison_spec.rb27
-rw-r--r--spec/ruby/library/set/constructor_spec.rb15
-rw-r--r--spec/ruby/library/set/delete_if_spec.rb38
-rw-r--r--spec/ruby/library/set/delete_spec.rb37
-rw-r--r--spec/ruby/library/set/difference_spec.rb7
-rw-r--r--spec/ruby/library/set/disjoint_spec.rb23
-rw-r--r--spec/ruby/library/set/divide_spec.rb59
-rw-r--r--spec/ruby/library/set/each_spec.rb27
-rw-r--r--spec/ruby/library/set/empty_spec.rb10
-rw-r--r--spec/ruby/library/set/enumerable/to_set_spec.rb13
-rw-r--r--spec/ruby/library/set/eql_spec.rb15
-rw-r--r--spec/ruby/library/set/equal_value_spec.rb33
-rw-r--r--spec/ruby/library/set/exclusion_spec.rb18
-rw-r--r--spec/ruby/library/set/fixtures/set_like.rb31
-rw-r--r--spec/ruby/library/set/flatten_merge_spec.rb23
-rw-r--r--spec/ruby/library/set/flatten_spec.rb56
-rw-r--r--spec/ruby/library/set/hash_spec.rb18
-rw-r--r--spec/ruby/library/set/include_spec.rb7
-rw-r--r--spec/ruby/library/set/initialize_clone_spec.rb16
-rw-r--r--spec/ruby/library/set/initialize_spec.rb73
-rw-r--r--spec/ruby/library/set/inspect_spec.rb7
-rw-r--r--spec/ruby/library/set/intersect_spec.rb23
-rw-r--r--spec/ruby/library/set/intersection_spec.rb11
-rw-r--r--spec/ruby/library/set/join_spec.rb29
-rw-r--r--spec/ruby/library/set/keep_if_spec.rb38
-rw-r--r--spec/ruby/library/set/length_spec.rb7
-rw-r--r--spec/ruby/library/set/map_spec.rb7
-rw-r--r--spec/ruby/library/set/member_spec.rb7
-rw-r--r--spec/ruby/library/set/merge_spec.rb31
-rw-r--r--spec/ruby/library/set/minus_spec.rb7
-rw-r--r--spec/ruby/library/set/plus_spec.rb7
-rw-r--r--spec/ruby/library/set/pretty_print_cycle_spec.rb10
-rw-r--r--spec/ruby/library/set/proper_subset_spec.rb44
-rw-r--r--spec/ruby/library/set/proper_superset_spec.rb41
-rw-r--r--spec/ruby/library/set/reject_spec.rb42
-rw-r--r--spec/ruby/library/set/replace_spec.rb17
-rw-r--r--spec/ruby/library/set/set_spec.rb12
-rw-r--r--spec/ruby/library/set/shared/add.rb14
-rw-r--r--spec/ruby/library/set/shared/collect.rb20
-rw-r--r--spec/ruby/library/set/shared/difference.rb15
-rw-r--r--spec/ruby/library/set/shared/include.rb29
-rw-r--r--spec/ruby/library/set/shared/inspect.rb25
-rw-r--r--spec/ruby/library/set/shared/intersection.rb15
-rw-r--r--spec/ruby/library/set/shared/select.rb42
-rw-r--r--spec/ruby/library/set/shared/union.rb15
-rw-r--r--spec/ruby/library/set/size_spec.rb7
-rw-r--r--spec/ruby/library/set/sortedset/sortedset_spec.rb12
-rw-r--r--spec/ruby/library/set/subset_spec.rb44
-rw-r--r--spec/ruby/library/set/subtract_spec.rb17
-rw-r--r--spec/ruby/library/set/superset_spec.rb41
-rw-r--r--spec/ruby/library/set/to_a_spec.rb8
-rw-r--r--spec/ruby/library/set/to_s_spec.rb12
-rw-r--r--spec/ruby/library/set/union_spec.rb11
-rw-r--r--spec/ruby/library/shellwords/shellwords_spec.rb4
-rw-r--r--spec/ruby/library/singleton/allocate_spec.rb2
-rw-r--r--spec/ruby/library/singleton/clone_spec.rb2
-rw-r--r--spec/ruby/library/singleton/dup_spec.rb2
-rw-r--r--spec/ruby/library/singleton/instance_spec.rb12
-rw-r--r--spec/ruby/library/singleton/load_spec.rb13
-rw-r--r--spec/ruby/library/singleton/new_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/afamily_spec.rb16
-rw-r--r--spec/ruby/library/socket/addrinfo/bind_spec.rb8
-rw-r--r--spec/ruby/library/socket/addrinfo/canonname_spec.rb4
-rw-r--r--spec/ruby/library/socket/addrinfo/connect_from_spec.rb12
-rw-r--r--spec/ruby/library/socket/addrinfo/connect_spec.rb6
-rw-r--r--spec/ruby/library/socket/addrinfo/connect_to_spec.rb12
-rw-r--r--spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb62
-rw-r--r--spec/ruby/library/socket/addrinfo/foreach_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb24
-rw-r--r--spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/initialize_spec.rb88
-rw-r--r--spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/inspect_spec.rb26
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_address_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_port_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv4_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb22
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_spec.rb18
-rw-r--r--spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/listen_spec.rb4
-rw-r--r--spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb58
-rw-r--r--spec/ruby/library/socket/addrinfo/marshal_load_spec.rb20
-rw-r--r--spec/ruby/library/socket/addrinfo/pfamily_spec.rb16
-rw-r--r--spec/ruby/library/socket/addrinfo/protocol_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb16
-rw-r--r--spec/ruby/library/socket/addrinfo/socktype_spec.rb14
-rw-r--r--spec/ruby/library/socket/addrinfo/tcp_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/udp_spec.rb8
-rw-r--r--spec/ruby/library/socket/addrinfo/unix_path_spec.rb46
-rw-r--r--spec/ruby/library/socket/addrinfo/unix_spec.rb52
-rw-r--r--spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb2
-rw-r--r--spec/ruby/library/socket/ancillarydata/initialize_spec.rb36
-rw-r--r--spec/ruby/library/socket/ancillarydata/int_spec.rb4
-rw-r--r--spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb16
-rw-r--r--spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb2
-rw-r--r--spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb10
-rw-r--r--spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb10
-rw-r--r--spec/ruby/library/socket/basicsocket/close_read_spec.rb12
-rw-r--r--spec/ruby/library/socket/basicsocket/close_write_spec.rb12
-rw-r--r--spec/ruby/library/socket/basicsocket/connect_address_spec.rb86
-rw-r--r--spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/for_fd_spec.rb6
-rw-r--r--spec/ruby/library/socket/basicsocket/getpeereid_spec.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/getpeername_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/getsockname_spec.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/getsockopt_spec.rb12
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb80
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_spec.rb85
-rw-r--r--spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb95
-rw-r--r--spec/ruby/library/socket/basicsocket/recvmsg_spec.rb64
-rw-r--r--spec/ruby/library/socket/basicsocket/send_spec.rb16
-rw-r--r--spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb6
-rw-r--r--spec/ruby/library/socket/basicsocket/sendmsg_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/setsockopt_spec.rb58
-rw-r--r--spec/ruby/library/socket/basicsocket/shutdown_spec.rb44
-rw-r--r--spec/ruby/library/socket/constants/constants_spec.rb28
-rw-r--r--spec/ruby/library/socket/ipsocket/addr_spec.rb8
-rw-r--r--spec/ruby/library/socket/ipsocket/getaddress_spec.rb2
-rw-r--r--spec/ruby/library/socket/ipsocket/inspect_spec.rb24
-rw-r--r--spec/ruby/library/socket/ipsocket/peeraddr_spec.rb4
-rw-r--r--spec/ruby/library/socket/ipsocket/recvfrom_spec.rb44
-rw-r--r--spec/ruby/library/socket/option/bool_spec.rb4
-rw-r--r--spec/ruby/library/socket/option/initialize_spec.rb18
-rw-r--r--spec/ruby/library/socket/option/int_spec.rb6
-rw-r--r--spec/ruby/library/socket/option/linger_spec.rb18
-rw-r--r--spec/ruby/library/socket/option/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/shared/address.rb92
-rw-r--r--spec/ruby/library/socket/shared/pack_sockaddr.rb69
-rw-r--r--spec/ruby/library/socket/shared/socketpair.rb38
-rw-r--r--spec/ruby/library/socket/socket/accept_loop_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/accept_nonblock_spec.rb24
-rw-r--r--spec/ruby/library/socket/socket/accept_spec.rb12
-rw-r--r--spec/ruby/library/socket/socket/bind_spec.rb28
-rw-r--r--spec/ruby/library/socket/socket/connect_nonblock_spec.rb68
-rw-r--r--spec/ruby/library/socket/socket/connect_spec.rb4
-rw-r--r--spec/ruby/library/socket/socket/getaddrinfo_spec.rb70
-rw-r--r--spec/ruby/library/socket/socket/gethostbyaddr_spec.rb37
-rw-r--r--spec/ruby/library/socket/socket/gethostbyname_spec.rb12
-rw-r--r--spec/ruby/library/socket/socket/getifaddrs_spec.rb42
-rw-r--r--spec/ruby/library/socket/socket/getnameinfo_spec.rb16
-rw-r--r--spec/ruby/library/socket/socket/getservbyname_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/getservbyport_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/initialize_spec.rb16
-rw-r--r--spec/ruby/library/socket/socket/ip_address_list_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/listen_spec.rb6
-rw-r--r--spec/ruby/library/socket/socket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb73
-rw-r--r--spec/ruby/library/socket/socket/recvfrom_spec.rb48
-rw-r--r--spec/ruby/library/socket/socket/remote_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/sysaccept_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/tcp_server_loop_spec.rb4
-rw-r--r--spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/tcp_spec.rb30
-rw-r--r--spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/udp_server_loop_spec.rb6
-rw-r--r--spec/ruby/library/socket/socket/udp_server_recv_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/udp_server_sockets_spec.rb8
-rw-r--r--spec/ruby/library/socket/socket/unix_server_loop_spec.rb76
-rw-r--r--spec/ruby/library/socket/socket/unix_server_socket_spec.rb56
-rw-r--r--spec/ruby/library/socket/socket/unix_spec.rb56
-rw-r--r--spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb16
-rw-r--r--spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb34
-rw-r--r--spec/ruby/library/socket/spec_helper.rb21
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb12
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_spec.rb8
-rw-r--r--spec/ruby/library/socket/tcpserver/gets_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/initialize_spec.rb12
-rw-r--r--spec/ruby/library/socket/tcpserver/listen_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/new_spec.rb28
-rw-r--r--spec/ruby/library/socket/tcpserver/sysaccept_spec.rb4
-rw-r--r--spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb18
-rw-r--r--spec/ruby/library/socket/tcpsocket/initialize_spec.rb10
-rw-r--r--spec/ruby/library/socket/tcpsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/remote_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/shared/new.rb74
-rw-r--r--spec/ruby/library/socket/udpsocket/bind_spec.rb4
-rw-r--r--spec/ruby/library/socket/udpsocket/initialize_spec.rb14
-rw-r--r--spec/ruby/library/socket/udpsocket/inspect_spec.rb17
-rw-r--r--spec/ruby/library/socket/udpsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/udpsocket/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/udpsocket/open_spec.rb2
-rw-r--r--spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb8
-rw-r--r--spec/ruby/library/socket/udpsocket/remote_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/udpsocket/send_spec.rb12
-rw-r--r--spec/ruby/library/socket/udpsocket/write_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb114
-rw-r--r--spec/ruby/library/socket/unixserver/accept_spec.rb166
-rw-r--r--spec/ruby/library/socket/unixserver/for_fd_spec.rb28
-rw-r--r--spec/ruby/library/socket/unixserver/initialize_spec.rb36
-rw-r--r--spec/ruby/library/socket/unixserver/listen_spec.rb24
-rw-r--r--spec/ruby/library/socket/unixserver/new_spec.rb14
-rw-r--r--spec/ruby/library/socket/unixserver/open_spec.rb30
-rw-r--r--spec/ruby/library/socket/unixserver/sysaccept_spec.rb64
-rw-r--r--spec/ruby/library/socket/unixsocket/addr_spec.rb48
-rw-r--r--spec/ruby/library/socket/unixsocket/initialize_spec.rb62
-rw-r--r--spec/ruby/library/socket/unixsocket/inspect_spec.rb20
-rw-r--r--spec/ruby/library/socket/unixsocket/local_address_spec.rb132
-rw-r--r--spec/ruby/library/socket/unixsocket/new_spec.rb14
-rw-r--r--spec/ruby/library/socket/unixsocket/open_spec.rb34
-rw-r--r--spec/ruby/library/socket/unixsocket/pair_spec.rb20
-rw-r--r--spec/ruby/library/socket/unixsocket/partially_closable_spec.rb30
-rw-r--r--spec/ruby/library/socket/unixsocket/path_spec.rb34
-rw-r--r--spec/ruby/library/socket/unixsocket/peeraddr_spec.rb38
-rw-r--r--spec/ruby/library/socket/unixsocket/recv_io_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/recvfrom_spec.rb152
-rw-r--r--spec/ruby/library/socket/unixsocket/remote_address_spec.rb60
-rw-r--r--spec/ruby/library/socket/unixsocket/send_io_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixsocket/shared/pair.rb42
-rw-r--r--spec/ruby/library/socket/unixsocket/socketpair_spec.rb20
-rw-r--r--spec/ruby/library/stringio/append_spec.rb10
-rw-r--r--spec/ruby/library/stringio/binmode_spec.rb2
-rw-r--r--spec/ruby/library/stringio/close_read_spec.rb6
-rw-r--r--spec/ruby/library/stringio/close_spec.rb8
-rw-r--r--spec/ruby/library/stringio/close_write_spec.rb6
-rw-r--r--spec/ruby/library/stringio/closed_read_spec.rb4
-rw-r--r--spec/ruby/library/stringio/closed_spec.rb6
-rw-r--r--spec/ruby/library/stringio/closed_write_spec.rb4
-rw-r--r--spec/ruby/library/stringio/each_line_spec.rb4
-rw-r--r--spec/ruby/library/stringio/each_spec.rb4
-rw-r--r--spec/ruby/library/stringio/fcntl_spec.rb2
-rw-r--r--spec/ruby/library/stringio/fileno_spec.rb5
-rw-r--r--spec/ruby/library/stringio/flush_spec.rb2
-rw-r--r--spec/ruby/library/stringio/fsync_spec.rb2
-rw-r--r--spec/ruby/library/stringio/gets_spec.rb263
-rw-r--r--spec/ruby/library/stringio/initialize_spec.rb140
-rw-r--r--spec/ruby/library/stringio/inspect_spec.rb2
-rw-r--r--spec/ruby/library/stringio/lineno_spec.rb8
-rw-r--r--spec/ruby/library/stringio/open_spec.rb120
-rw-r--r--spec/ruby/library/stringio/path_spec.rb2
-rw-r--r--spec/ruby/library/stringio/pid_spec.rb2
-rw-r--r--spec/ruby/library/stringio/pos_spec.rb2
-rw-r--r--spec/ruby/library/stringio/print_spec.rb14
-rw-r--r--spec/ruby/library/stringio/printf_spec.rb14
-rw-r--r--spec/ruby/library/stringio/putc_spec.rb8
-rw-r--r--spec/ruby/library/stringio/puts_spec.rb8
-rw-r--r--spec/ruby/library/stringio/read_nonblock_spec.rb2
-rw-r--r--spec/ruby/library/stringio/read_spec.rb4
-rw-r--r--spec/ruby/library/stringio/readline_spec.rb160
-rw-r--r--spec/ruby/library/stringio/readlines_spec.rb14
-rw-r--r--spec/ruby/library/stringio/readpartial_spec.rb44
-rw-r--r--spec/ruby/library/stringio/reopen_spec.rb74
-rw-r--r--spec/ruby/library/stringio/rewind_spec.rb2
-rw-r--r--spec/ruby/library/stringio/seek_spec.rb24
-rw-r--r--spec/ruby/library/stringio/set_encoding_by_bom_spec.rb6
-rw-r--r--spec/ruby/library/stringio/shared/codepoints.rb10
-rw-r--r--spec/ruby/library/stringio/shared/each.rb90
-rw-r--r--spec/ruby/library/stringio/shared/each_byte.rb10
-rw-r--r--spec/ruby/library/stringio/shared/each_char.rb8
-rw-r--r--spec/ruby/library/stringio/shared/eof.rb10
-rw-r--r--spec/ruby/library/stringio/shared/getc.rb20
-rw-r--r--spec/ruby/library/stringio/shared/gets.rb249
-rw-r--r--spec/ruby/library/stringio/shared/isatty.rb2
-rw-r--r--spec/ruby/library/stringio/shared/read.rb26
-rw-r--r--spec/ruby/library/stringio/shared/readchar.rb6
-rw-r--r--spec/ruby/library/stringio/shared/sysread.rb2
-rw-r--r--spec/ruby/library/stringio/shared/write.rb8
-rw-r--r--spec/ruby/library/stringio/string_spec.rb12
-rw-r--r--spec/ruby/library/stringio/stringio_spec.rb2
-rw-r--r--spec/ruby/library/stringio/sync_spec.rb4
-rw-r--r--spec/ruby/library/stringio/sysread_spec.rb2
-rw-r--r--spec/ruby/library/stringio/truncate_spec.rb16
-rw-r--r--spec/ruby/library/stringio/ungetc_spec.rb14
-rw-r--r--spec/ruby/library/stringscanner/check_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/check_until_spec.rb20
-rw-r--r--spec/ruby/library/stringscanner/clear_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/dup_spec.rb4
-rw-r--r--spec/ruby/library/stringscanner/element_reference_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/empty_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/eos_spec.rb17
-rw-r--r--spec/ruby/library/stringscanner/exist_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/get_byte_spec.rb81
-rw-r--r--spec/ruby/library/stringscanner/getbyte_spec.rb21
-rw-r--r--spec/ruby/library/stringscanner/getch_spec.rb21
-rw-r--r--spec/ruby/library/stringscanner/initialize_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/inspect_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/match_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/matched_spec.rb4
-rw-r--r--spec/ruby/library/stringscanner/named_captures_spec.rb42
-rw-r--r--spec/ruby/library/stringscanner/peek_spec.rb39
-rw-r--r--spec/ruby/library/stringscanner/peep_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/rest_size_spec.rb27
-rw-r--r--spec/ruby/library/stringscanner/rest_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/restsize_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/scan_byte_spec.rb10
-rw-r--r--spec/ruby/library/stringscanner/scan_full_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/scan_integer_spec.rb18
-rw-r--r--spec/ruby/library/stringscanner/scan_spec.rb22
-rw-r--r--spec/ruby/library/stringscanner/scan_until_spec.rb20
-rw-r--r--spec/ruby/library/stringscanner/search_full_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/shared/bol.rb16
-rw-r--r--spec/ruby/library/stringscanner/shared/concat.rb14
-rw-r--r--spec/ruby/library/stringscanner/shared/eos.rb17
-rw-r--r--spec/ruby/library/stringscanner/shared/extract_range.rb4
-rw-r--r--spec/ruby/library/stringscanner/shared/extract_range_matched.rb4
-rw-r--r--spec/ruby/library/stringscanner/shared/get_byte.rb87
-rw-r--r--spec/ruby/library/stringscanner/shared/peek.rb39
-rw-r--r--spec/ruby/library/stringscanner/shared/pos.rb11
-rw-r--r--spec/ruby/library/stringscanner/shared/rest_size.rb18
-rw-r--r--spec/ruby/library/stringscanner/shared/terminate.rb8
-rw-r--r--spec/ruby/library/stringscanner/skip_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/skip_until_spec.rb20
-rw-r--r--spec/ruby/library/stringscanner/string_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/terminate_spec.rb8
-rw-r--r--spec/ruby/library/stringscanner/unscan_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/values_at_spec.rb4
-rw-r--r--spec/ruby/library/syslog/close_spec.rb16
-rw-r--r--spec/ruby/library/syslog/constants_spec.rb4
-rw-r--r--spec/ruby/library/syslog/facility_spec.rb6
-rw-r--r--spec/ruby/library/syslog/ident_spec.rb4
-rw-r--r--spec/ruby/library/syslog/inspect_spec.rb4
-rw-r--r--spec/ruby/library/syslog/log_spec.rb10
-rw-r--r--spec/ruby/library/syslog/mask_spec.rb14
-rw-r--r--spec/ruby/library/syslog/open_spec.rb10
-rw-r--r--spec/ruby/library/syslog/opened_spec.rb16
-rw-r--r--spec/ruby/library/syslog/options_spec.rb6
-rw-r--r--spec/ruby/library/syslog/shared/log.rb6
-rw-r--r--spec/ruby/library/syslog/shared/reopen.rb14
-rw-r--r--spec/ruby/library/tempfile/_close_spec.rb4
-rw-r--r--spec/ruby/library/tempfile/callback_spec.rb6
-rw-r--r--spec/ruby/library/tempfile/close_spec.rb6
-rw-r--r--spec/ruby/library/tempfile/create_spec.rb176
-rw-r--r--spec/ruby/library/tempfile/initialize_spec.rb2
-rw-r--r--spec/ruby/library/tempfile/open_spec.rb18
-rw-r--r--spec/ruby/library/tempfile/path_spec.rb2
-rw-r--r--spec/ruby/library/tempfile/shared/length.rb6
-rw-r--r--spec/ruby/library/thread/queue_spec.rb4
-rw-r--r--spec/ruby/library/thread/sizedqueue_spec.rb4
-rw-r--r--spec/ruby/library/time/shared/rfc2822.rb2
-rw-r--r--spec/ruby/library/time/to_time_spec.rb4
-rw-r--r--spec/ruby/library/timeout/error_spec.rb2
-rw-r--r--spec/ruby/library/timeout/timeout_spec.rb16
-rw-r--r--spec/ruby/library/tmpdir/dir/mktmpdir_spec.rb18
-rw-r--r--spec/ruby/library/tmpdir/dir/tmpdir_spec.rb4
-rw-r--r--spec/ruby/library/uri/generic/host_spec.rb8
-rw-r--r--spec/ruby/library/uri/generic/to_s_spec.rb8
-rw-r--r--spec/ruby/library/uri/join_spec.rb2
-rw-r--r--spec/ruby/library/uri/mailto/build_spec.rb2
-rw-r--r--spec/ruby/library/uri/parse_spec.rb24
-rw-r--r--spec/ruby/library/uri/plus_spec.rb170
-rw-r--r--spec/ruby/library/uri/select_spec.rb6
-rw-r--r--spec/ruby/library/uri/set_component_spec.rb60
-rw-r--r--spec/ruby/library/uri/shared/eql.rb6
-rw-r--r--spec/ruby/library/uri/shared/join.rb2
-rw-r--r--spec/ruby/library/uri/shared/parse.rb32
-rw-r--r--spec/ruby/library/uri/uri_spec.rb4
-rw-r--r--spec/ruby/library/weakref/__getobj___spec.rb4
-rw-r--r--spec/ruby/library/weakref/allocate_spec.rb2
-rw-r--r--spec/ruby/library/weakref/send_spec.rb4
-rw-r--r--spec/ruby/library/weakref/weakref_alive_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/fixtures/classes.rb17
-rw-r--r--spec/ruby/library/win32ole/win32ole/_invoke_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/connect_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/const_load_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole/locale_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/new_spec.rb10
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole/shared/ole_method.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole/shared/setproperty.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/new_spec.rb14
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb12
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb14
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_spec.rb10
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb12
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/name_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/new_spec.rb22
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/params_spec.rb20
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb10
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/shared/name.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/visible_spec.rb10
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/default_spec.rb16
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/input_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/name_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/optional_spec.rb10
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/retval_spec.rb10
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/shared/name.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/guid_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/name_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/new_spec.rb34
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progid_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progids_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/shared/name.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb2
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb8
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/variables_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/visible_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb6
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/shared/name.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/value_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb4
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb4
-rw-r--r--spec/ruby/library/yaml/parse_file_spec.rb2
-rw-r--r--spec/ruby/library/yaml/parse_spec.rb2
-rw-r--r--spec/ruby/library/yaml/shared/load.rb6
-rw-r--r--spec/ruby/library/yaml/to_yaml_spec.rb18
-rw-r--r--spec/ruby/library/zlib/adler32_spec.rb2
-rw-r--r--spec/ruby/library/zlib/crc32_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipfile/close_spec.rb6
-rw-r--r--spec/ruby/library/zlib/gzipfile/comment_spec.rb3
-rw-r--r--spec/ruby/library/zlib/gzipfile/orig_name_spec.rb3
-rw-r--r--spec/ruby/library/zlib/gzipreader/eof_spec.rb22
-rw-r--r--spec/ruby/library/zlib/gzipreader/getc_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipreader/gets_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipreader/read_spec.rb6
-rw-r--r--spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb4
-rw-r--r--spec/ruby/library/zlib/gzipreader/ungetc_spec.rb12
-rw-r--r--spec/ruby/library/zlib/gzipwriter/append_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipwriter/mtime_spec.rb3
-rw-r--r--spec/ruby/library/zlib/inflate/append_spec.rb2
-rw-r--r--spec/ruby/library/zlib/inflate/finish_spec.rb2
-rw-r--r--spec/ruby/library/zlib/inflate/inflate_spec.rb4
-rw-r--r--spec/ruby/library/zlib/inflate/set_dictionary_spec.rb2
-rw-r--r--spec/ruby/library/zlib/zlib_version_spec.rb2
-rw-r--r--spec/ruby/optional/capi/array_spec.rb86
-rw-r--r--spec/ruby/optional/capi/bignum_spec.rb16
-rw-r--r--spec/ruby/optional/capi/binding_spec.rb18
-rw-r--r--spec/ruby/optional/capi/class_spec.rb129
-rw-r--r--spec/ruby/optional/capi/constants_spec.rb2
-rw-r--r--spec/ruby/optional/capi/data_spec.rb2
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb10
-rw-r--r--spec/ruby/optional/capi/digest_spec.rb103
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb141
-rw-r--r--spec/ruby/optional/capi/exception_spec.rb46
-rw-r--r--spec/ruby/optional/capi/ext/array_spec.c8
-rw-r--r--spec/ruby/optional/capi/ext/class_spec.c4
-rw-r--r--spec/ruby/optional/capi/ext/constants_spec.c6
-rw-r--r--spec/ruby/optional/capi/ext/digest_spec.c168
-rw-r--r--spec/ruby/optional/capi/ext/encoding_spec.c11
-rw-r--r--spec/ruby/optional/capi/ext/exception_spec.c8
-rw-r--r--spec/ruby/optional/capi/ext/fiber_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/gc_spec.c29
-rw-r--r--spec/ruby/optional/capi/ext/hash_spec.c4
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c56
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c19
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c49
-rw-r--r--spec/ruby/optional/capi/ext/range_spec.c48
-rw-r--r--spec/ruby/optional/capi/ext/rbasic_spec.c10
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h20
-rw-r--r--spec/ruby/optional/capi/ext/set_spec.c65
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c66
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c10
-rw-r--r--spec/ruby/optional/capi/ext/typed_data_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/util_spec.c4
-rw-r--r--spec/ruby/optional/capi/fiber_spec.rb12
-rw-r--r--spec/ruby/optional/capi/file_spec.rb8
-rw-r--r--spec/ruby/optional/capi/fixnum_spec.rb20
-rw-r--r--spec/ruby/optional/capi/fixtures/class.rb10
-rw-r--r--spec/ruby/optional/capi/float_spec.rb4
-rw-r--r--spec/ruby/optional/capi/gc_spec.rb40
-rw-r--r--spec/ruby/optional/capi/globals_spec.rb31
-rw-r--r--spec/ruby/optional/capi/hash_spec.rb58
-rw-r--r--spec/ruby/optional/capi/integer_spec.rb2
-rw-r--r--spec/ruby/optional/capi/io_spec.rb370
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb132
-rw-r--r--spec/ruby/optional/capi/module_spec.rb58
-rw-r--r--spec/ruby/optional/capi/mutex_spec.rb34
-rw-r--r--spec/ruby/optional/capi/numeric_spec.rb56
-rw-r--r--spec/ruby/optional/capi/object_spec.rb164
-rw-r--r--spec/ruby/optional/capi/proc_spec.rb24
-rw-r--r--spec/ruby/optional/capi/range_spec.rb158
-rw-r--r--spec/ruby/optional/capi/regexp_spec.rb4
-rw-r--r--spec/ruby/optional/capi/set_spec.rb96
-rw-r--r--spec/ruby/optional/capi/shared/rbasic.rb1
-rw-r--r--spec/ruby/optional/capi/spec_helper.rb49
-rw-r--r--spec/ruby/optional/capi/string_spec.rb338
-rw-r--r--spec/ruby/optional/capi/struct_spec.rb152
-rw-r--r--spec/ruby/optional/capi/thread_spec.rb28
-rw-r--r--spec/ruby/optional/capi/time_spec.rb108
-rw-r--r--spec/ruby/optional/capi/tracepoint_spec.rb2
-rw-r--r--spec/ruby/optional/capi/typed_data_spec.rb24
-rw-r--r--spec/ruby/optional/capi/util_spec.rb23
-rw-r--r--spec/ruby/optional/thread_safety/fixtures/classes.rb39
-rw-r--r--spec/ruby/optional/thread_safety/hash_spec.rb210
-rw-r--r--spec/ruby/security/cve_2010_1330_spec.rb2
-rw-r--r--spec/ruby/security/cve_2018_8778_spec.rb2
-rw-r--r--spec/ruby/security/cve_2018_8779_spec.rb4
-rw-r--r--spec/ruby/security/cve_2018_8780_spec.rb12
-rw-r--r--spec/ruby/security/cve_2019_8322_spec.rb33
-rw-r--r--spec/ruby/security/cve_2020_10663_spec.rb4
-rw-r--r--spec/ruby/security/cve_2024_49761_spec.rb8
-rw-r--r--spec/ruby/shared/basicobject/method_missing.rb18
-rw-r--r--spec/ruby/shared/basicobject/send.rb18
-rw-r--r--spec/ruby/shared/enumerable/minmax.rb6
-rw-r--r--spec/ruby/shared/file/directory.rb18
-rw-r--r--spec/ruby/shared/file/executable.rb8
-rw-r--r--spec/ruby/shared/file/executable_real.rb8
-rw-r--r--spec/ruby/shared/file/exist.rb6
-rw-r--r--spec/ruby/shared/file/file.rb8
-rw-r--r--spec/ruby/shared/file/grpowned.rb6
-rw-r--r--spec/ruby/shared/file/identical.rb18
-rw-r--r--spec/ruby/shared/file/size.rb2
-rw-r--r--spec/ruby/shared/file/socket.rb32
-rw-r--r--spec/ruby/shared/file/sticky.rb2
-rw-r--r--spec/ruby/shared/file/world_readable.rb10
-rw-r--r--spec/ruby/shared/file/world_writable.rb10
-rw-r--r--spec/ruby/shared/file/writable_real.rb8
-rw-r--r--spec/ruby/shared/file/zero.rb10
-rw-r--r--spec/ruby/shared/hash/key_error.rb8
-rw-r--r--spec/ruby/shared/io/putc.rb10
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb5
-rw-r--r--spec/ruby/shared/kernel/complex.rb2
-rw-r--r--spec/ruby/shared/kernel/equal.rb4
-rw-r--r--spec/ruby/shared/kernel/object_id.rb2
-rw-r--r--spec/ruby/shared/kernel/raise.rb362
-rw-r--r--spec/ruby/shared/process/abort.rb12
-rw-r--r--spec/ruby/shared/process/exit.rb22
-rw-r--r--spec/ruby/shared/process/fork.rb29
-rw-r--r--spec/ruby/shared/queue/clear.rb4
-rw-r--r--spec/ruby/shared/queue/close.rb4
-rw-r--r--spec/ruby/shared/queue/closed.rb4
-rw-r--r--spec/ruby/shared/queue/deque.rb128
-rw-r--r--spec/ruby/shared/queue/empty.rb4
-rw-r--r--spec/ruby/shared/queue/enque.rb2
-rw-r--r--spec/ruby/shared/queue/freeze.rb18
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb156
-rw-r--r--spec/ruby/shared/sizedqueue/max.rb10
-rw-r--r--spec/ruby/shared/sizedqueue/new.rb10
-rw-r--r--spec/ruby/shared/string/end_with.rb8
-rw-r--r--spec/ruby/shared/string/start_with.rb28
-rw-r--r--spec/ruby/shared/string/times.rb22
-rw-r--r--spec/ruby/shared/types/rb_num2dbl_fails.rb6
-rw-r--r--spec/syntax_suggest/integration/ruby_command_line_spec.rb4
-rw-r--r--spec/syntax_suggest/integration/syntax_suggest_spec.rb33
-rw-r--r--spec/syntax_suggest/spec_helper.rb10
-rw-r--r--spec/syntax_suggest/unit/api_spec.rb10
-rw-r--r--spec/syntax_suggest/unit/clean_document_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/code_block_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/code_line_spec.rb15
-rw-r--r--spec/syntax_suggest/unit/core_ext_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/explain_syntax_spec.rb32
-rw-r--r--spec/syntax_suggest/unit/lex_all_spec.rb26
-rw-r--r--spec/syntax_suggest/unit/visitor_spec.rb119
-rw-r--r--sprintf.c10
-rw-r--r--st.c1127
-rw-r--r--string.c2809
-rw-r--r--string.rb556
-rw-r--r--struct.c264
-rw-r--r--symbol.c1019
-rw-r--r--symbol.h11
-rw-r--r--template/GNUmakefile.in3
-rw-r--r--template/Makefile.in88
-rw-r--r--template/builtin_binary.inc.tmpl30
-rw-r--r--template/builtin_binary.rbbin.tmpl35
-rw-r--r--template/configure-ext.mk.tmpl41
-rw-r--r--template/fake.rb.in2
-rw-r--r--template/id.c.tmpl5
-rw-r--r--template/id.h.tmpl8
-rw-r--r--template/prelude.c.tmpl5
-rw-r--r--template/unicode_norm_gen.tmpl37
-rw-r--r--test/-ext-/box/test_load_ext.rb97
-rw-r--r--test/-ext-/bug_reporter/test_bug_reporter.rb8
-rw-r--r--test/-ext-/debug/test_debug.rb54
-rw-r--r--test/-ext-/gvl/test_last_thread.rb3
-rw-r--r--test/-ext-/postponed_job/test_postponed_job.rb35
-rw-r--r--test/-ext-/scheduler/test_interrupt_with_scheduler.rb54
-rw-r--r--test/-ext-/stack/test_stack_overflow.rb55
-rw-r--r--test/-ext-/string/test_capacity.rb13
-rw-r--r--test/-ext-/string/test_interned_str.rb5
-rw-r--r--test/-ext-/string/test_set_len.rb2
-rw-r--r--test/-ext-/symbol/test_type.rb16
-rw-r--r--test/-ext-/test_abi.rb12
-rw-r--r--test/-ext-/thread/test_instrumentation_api.rb4
-rw-r--r--test/-ext-/thread/test_lock_native_thread.rb4
-rw-r--r--test/-ext-/thread_fd/test_thread_fd_close.rb24
-rw-r--r--test/-ext-/tracepoint/test_tracepoint.rb2
-rw-r--r--test/.excludes-mmtk/TestEtc.rb1
-rw-r--r--test/.excludes-mmtk/TestGc.rb1
-rw-r--r--test/.excludes-mmtk/TestObjSpace.rb2
-rw-r--r--test/.excludes-mmtk/TestObjectSpace.rb1
-rw-r--r--test/.excludes-parsey/TestDefined.rb1
-rw-r--r--test/.excludes-zjit/TestResolvDNS.rb1
-rw-r--r--test/.excludes/JSONGenericObjectTest.rb4
-rw-r--r--test/.excludes/TestPatternMatching.rb1
-rw-r--r--test/.excludes/TestThread.rb2
-rw-r--r--test/.excludes/URI/TestMailTo.rb1
-rw-r--r--test/.excludes/_appveyor/TestArray.rb7
-rw-r--r--test/cgi/test_cgi_cookie.rb211
-rw-r--r--test/cgi/test_cgi_core.rb307
-rw-r--r--test/cgi/test_cgi_escape.rb325
-rw-r--r--test/cgi/test_cgi_header.rb192
-rw-r--r--test/cgi/test_cgi_modruby.rb149
-rw-r--r--test/cgi/test_cgi_multipart.rb385
-rw-r--r--test/cgi/test_cgi_session.rb169
-rw-r--r--test/cgi/test_cgi_tag_helper.rb355
-rw-r--r--test/cgi/test_cgi_util.rb330
-rw-r--r--test/cgi/testdata/file1.html10
-rw-r--r--test/cgi/testdata/large.pngbin156414 -> 0 bytes-rw-r--r--test/cgi/testdata/small.pngbin82 -> 0 bytes-rw-r--r--test/coverage/test_coverage.rb81
-rw-r--r--test/date/test_date.rb4
-rw-r--r--test/date/test_date_conv.rb20
-rw-r--r--test/date/test_date_parse.rb26
-rw-r--r--test/date/test_date_ractor.rb2
-rw-r--r--test/date/test_date_strptime.rb15
-rw-r--r--test/date/test_switch_hitter.rb5
-rw-r--r--test/did_you_mean/spell_checking/test_method_name_check.rb4
-rw-r--r--test/did_you_mean/test_ractor_compatibility.rb12
-rw-r--r--test/digest/test_ractor.rb6
-rw-r--r--test/dtrace/helper.rb6
-rw-r--r--test/erb/test_erb.rb111
-rw-r--r--test/error_highlight/test_error_highlight.rb309
-rw-r--r--test/etc/test_etc.rb22
-rw-r--r--test/fiber/scheduler.rb158
-rw-r--r--test/fiber/test_io.rb59
-rw-r--r--test/fiber/test_io_close.rb107
-rw-r--r--test/fiber/test_ractor.rb2
-rw-r--r--test/fiber/test_scheduler.rb160
-rw-r--r--test/fiber/test_sleep.rb4
-rw-r--r--test/fiber/test_thread.rb47
-rw-r--r--test/fileutils/test_fileutils.rb95
-rw-r--r--test/io/console/test_io_console.rb26
-rw-r--r--test/io/console/test_ractor.rb12
-rw-r--r--test/io/wait/test_io_wait.rb38
-rw-r--r--test/io/wait/test_io_wait_uncommon.rb15
-rw-r--r--test/io/wait/test_ractor.rb6
-rw-r--r--test/json/fixtures/fail15.json (renamed from test/json/fixtures/pass15.json)0
-rw-r--r--test/json/fixtures/fail16.json (renamed from test/json/fixtures/pass16.json)0
-rw-r--r--test/json/fixtures/fail17.json (renamed from test/json/fixtures/pass17.json)0
-rw-r--r--test/json/fixtures/fail26.json (renamed from test/json/fixtures/pass26.json)0
-rw-r--r--test/json/fixtures/pass1.json2
-rwxr-xr-xtest/json/json_coder_test.rb107
-rw-r--r--test/json/json_common_interface_test.rb126
-rw-r--r--test/json/json_encoding_test.rb188
-rw-r--r--test/json/json_ext_parser_test.rb31
-rw-r--r--test/json/json_fixtures_test.rb2
-rwxr-xr-xtest/json/json_generator_test.rb567
-rw-r--r--test/json/json_generic_object_test.rb24
-rw-r--r--test/json/json_parser_test.rb263
-rw-r--r--test/json/json_ryu_fallback_test.rb191
-rw-r--r--test/json/ractor_test.rb74
-rw-r--r--test/json/test_helper.rb25
-rw-r--r--test/lib/jit_support.rb12
-rw-r--r--test/mkmf/test_egrep_cpp.rb14
-rw-r--r--test/mkmf/test_pkg_config.rb17
-rw-r--r--test/monitor/test_monitor.rb2
-rw-r--r--test/net/http/test_http.rb47
-rw-r--r--test/net/http/test_http_request.rb34
-rw-r--r--test/net/http/test_https.rb84
-rw-r--r--test/net/http/test_https_proxy.rb16
-rw-r--r--test/net/http/utils.rb16
-rw-r--r--test/objspace/test_objspace.rb128
-rw-r--r--test/objspace/test_ractor.rb74
-rw-r--r--test/open-uri/test_open-uri.rb2
-rw-r--r--test/openssl/fixtures/pkey/dsa1024.pem12
-rw-r--r--test/openssl/fixtures/pkey/dsa256.pem8
-rw-r--r--test/openssl/fixtures/pkey/dsa512.pem8
-rw-r--r--test/openssl/fixtures/pkey/mldsa65-1.pem88
-rw-r--r--test/openssl/fixtures/pkey/mldsa65-2.pem88
-rw-r--r--test/openssl/fixtures/pkey/rsa1024.pem15
-rw-r--r--test/openssl/test_asn1.rb104
-rw-r--r--test/openssl/test_bn.rb48
-rw-r--r--test/openssl/test_cipher.rb103
-rw-r--r--test/openssl/test_digest.rb80
-rw-r--r--test/openssl/test_fips.rb2
-rw-r--r--test/openssl/test_hmac.rb34
-rw-r--r--test/openssl/test_kdf.rb135
-rw-r--r--test/openssl/test_ns_spki.rb4
-rw-r--r--test/openssl/test_ocsp.rb43
-rw-r--r--test/openssl/test_ossl.rb69
-rw-r--r--test/openssl/test_pkcs12.rb38
-rw-r--r--test/openssl/test_pkcs7.rb352
-rw-r--r--test/openssl/test_pkey.rb158
-rw-r--r--test/openssl/test_pkey_dh.rb85
-rw-r--r--test/openssl/test_pkey_dsa.rb122
-rw-r--r--test/openssl/test_pkey_ec.rb64
-rw-r--r--test/openssl/test_pkey_rsa.rb333
-rw-r--r--test/openssl/test_provider.rb1
-rw-r--r--test/openssl/test_ssl.rb390
-rw-r--r--test/openssl/test_ssl_session.rb2
-rw-r--r--test/openssl/test_ts.rb84
-rw-r--r--test/openssl/test_x509cert.rb176
-rw-r--r--test/openssl/test_x509crl.rb78
-rw-r--r--test/openssl/test_x509name.rb16
-rw-r--r--test/openssl/test_x509req.rb94
-rw-r--r--test/openssl/test_x509store.rb12
-rw-r--r--test/openssl/utils.rb37
-rw-r--r--test/optparse/test_load.rb61
-rw-r--r--test/optparse/test_optparse.rb12
-rw-r--r--test/optparse/test_switch.rb50
-rw-r--r--test/pathname/test_pathname.rb69
-rw-r--r--test/pathname/test_ractor.rb12
-rw-r--r--test/prism/api/freeze_test.rb5
-rw-r--r--test/prism/api/parse_stream_test.rb51
-rw-r--r--test/prism/api/parse_test.rb18
-rw-r--r--test/prism/bom_test.rb3
-rw-r--r--test/prism/encoding/encodings_test.rb18
-rw-r--r--test/prism/encoding/regular_expression_encoding_test.rb34
-rw-r--r--test/prism/errors/3.3-3.3/circular_parameters.txt12
-rw-r--r--test/prism/errors/3.3-3.4/leading_logical.txt34
-rw-r--r--test/prism/errors/3.3-3.4/private_endless_method.txt3
-rw-r--r--test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt (renamed from test/prism/errors/do_not_allow_trailing_commas_in_method_parameters.txt)0
-rw-r--r--test/prism/errors/3.3-4.0/noblock.txt6
-rw-r--r--test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt3
-rw-r--r--test/prism/errors/3.4-4.0/void_value.txt18
-rw-r--r--test/prism/errors/3.4/block_args_in_array_assignment.txt (renamed from test/prism/errors/block_args_in_array_assignment.txt)0
-rw-r--r--test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt (renamed from test/prism/errors/dont_allow_return_inside_sclass_body.txt)0
-rw-r--r--test/prism/errors/3.4/it_with_ordinary_parameter.txt (renamed from test/prism/errors/it_with_ordinary_parameter.txt)0
-rw-r--r--test/prism/errors/3.4/keyword_args_in_array_assignment.txt (renamed from test/prism/errors/keyword_args_in_array_assignment.txt)0
-rw-r--r--test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt6
-rw-r--r--test/prism/errors/4.1/end_block_exit.txt10
-rw-r--r--test/prism/errors/4.1/multiple_blocks.txt12
-rw-r--r--test/prism/errors/4.1/singleton_method_with_void_value.txt4
-rw-r--r--test/prism/errors/4.1/void_value.txt44
-rw-r--r--test/prism/errors/block_args_with_endless_def.txt5
-rw-r--r--test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt2
-rw-r--r--test/prism/errors/block_pass_return_value.txt33
-rw-r--r--test/prism/errors/command_call_in.txt1
-rw-r--r--test/prism/errors/command_call_in_2.txt4
-rw-r--r--test/prism/errors/command_call_in_3.txt4
-rw-r--r--test/prism/errors/command_call_in_4.txt4
-rw-r--r--test/prism/errors/command_call_in_5.txt4
-rw-r--r--test/prism/errors/command_call_in_6.txt4
-rw-r--r--test/prism/errors/command_call_in_7.txt4
-rw-r--r--test/prism/errors/command_call_value_and.txt3
-rw-r--r--test/prism/errors/command_call_value_or.txt3
-rw-r--r--test/prism/errors/command_calls.txt7
-rw-r--r--test/prism/errors/command_calls_2.txt2
-rw-r--r--test/prism/errors/command_calls_24.txt2
-rw-r--r--test/prism/errors/command_calls_25.txt2
-rw-r--r--test/prism/errors/command_calls_31.txt17
-rw-r--r--test/prism/errors/command_calls_32.txt19
-rw-r--r--test/prism/errors/command_calls_33.txt6
-rw-r--r--test/prism/errors/command_calls_34.txt31
-rw-r--r--test/prism/errors/command_calls_35.txt50
-rw-r--r--test/prism/errors/def_endless_do.txt6
-rw-r--r--test/prism/errors/def_with_optional_splat.txt6
-rw-r--r--test/prism/errors/destroy_call_operator_write_arguments.txt11
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt12
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt12
-rw-r--r--test/prism/errors/endless_method_command_call.txt3
-rw-r--r--test/prism/errors/endless_method_command_call_parameters.txt27
-rw-r--r--test/prism/errors/heredoc_percent_q_newline_delimiter.txt11
-rw-r--r--test/prism/errors/heredoc_unterminated.txt2
-rw-r--r--test/prism/errors/infix_after_label.txt2
-rw-r--r--test/prism/errors/interpolated_symbol_pattern_hash_key.txt3
-rw-r--r--test/prism/errors/label_in_interpolated_string.txt14
-rw-r--r--test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt1
-rw-r--r--test/prism/errors/match_predicate_after_rescue_with_opreator.txt1
-rw-r--r--test/prism/errors/match_required_after_rescue_with_dot_method_call.txt1
-rw-r--r--test/prism/errors/match_required_after_rescue_with_opreator.txt1
-rw-r--r--test/prism/errors/modifier_conditional_in_predicate.txt12
-rw-r--r--test/prism/errors/not_without_parens_assignment.txt4
-rw-r--r--test/prism/errors/not_without_parens_call.txt7
-rw-r--r--test/prism/errors/not_without_parens_command.txt4
-rw-r--r--test/prism/errors/not_without_parens_command_call.txt4
-rw-r--r--test/prism/errors/not_without_parens_return.txt4
-rw-r--r--test/prism/errors/pattern-capture-in-alt-array.txt4
-rw-r--r--test/prism/errors/pattern-capture-in-alt-hash.txt3
-rw-r--r--test/prism/errors/pattern-capture-in-alt-name.txt3
-rw-r--r--test/prism/errors/pattern-capture-in-alt-top.txt4
-rw-r--r--test/prism/errors/pattern_arithmetic_expressions.txt3
-rw-r--r--test/prism/errors/pattern_match_implicit_rest.txt3
-rw-r--r--test/prism/errors/pattern_string_key.txt8
-rw-r--r--test/prism/errors/rescue_pattern.txt4
-rw-r--r--test/prism/errors/shadow_args_in_lambda.txt2
-rw-r--r--test/prism/errors/singleton_method_for_literals.txt2
-rw-r--r--test/prism/errors/unterminated_begin.txt4
-rw-r--r--test/prism/errors/unterminated_begin_upcase.txt4
-rw-r--r--test/prism/errors/unterminated_block.txt2
-rw-r--r--test/prism/errors/unterminated_block_do_end.txt4
-rw-r--r--test/prism/errors/unterminated_class.txt4
-rw-r--r--test/prism/errors/unterminated_def.txt5
-rw-r--r--test/prism/errors/unterminated_end_upcase.txt4
-rw-r--r--test/prism/errors/unterminated_for.txt5
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr.txt11
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr_2.txt9
-rw-r--r--test/prism/errors/unterminated_if.txt5
-rw-r--r--test/prism/errors/unterminated_if_else.txt5
-rw-r--r--test/prism/errors/unterminated_lambda_brace.txt4
-rw-r--r--test/prism/errors/unterminated_module.txt4
-rw-r--r--test/prism/errors/unterminated_pattern_bracket.txt7
-rw-r--r--test/prism/errors/unterminated_pattern_paren.txt7
-rw-r--r--test/prism/errors/unterminated_until.txt5
-rw-r--r--test/prism/errors/void_value_expression_in_begin_statement.txt2
-rw-r--r--test/prism/errors/while_endless_method.txt2
-rw-r--r--test/prism/errors_test.rb110
-rw-r--r--test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/it.txt5
-rw-r--r--test/prism/fixtures/3.3-3.3/it_indirect_writes.txt (renamed from test/prism/fixtures/it_indirect_writes.txt)0
-rw-r--r--test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt1
-rw-r--r--test/prism/fixtures/3.3-3.3/return_in_sclass.txt1
-rw-r--r--test/prism/fixtures/3.3-4.0/end_block_exit.txt11
-rw-r--r--test/prism/fixtures/3.3-4.0/void_value.txt29
-rw-r--r--test/prism/fixtures/3.4/circular_parameters.txt4
-rw-r--r--test/prism/fixtures/3.4/it.txt5
-rw-r--r--test/prism/fixtures/3.4/it_indirect_writes.txt23
-rw-r--r--test/prism/fixtures/3.4/it_read_and_assignment.txt1
-rw-r--r--test/prism/fixtures/4.0/endless_methods_command_call.txt11
-rw-r--r--test/prism/fixtures/4.0/leading_logical.txt16
-rw-r--r--test/prism/fixtures/4.1/noblock.txt4
-rw-r--r--test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt15
-rw-r--r--test/prism/fixtures/4.1/void_value.txt7
-rw-r--r--test/prism/fixtures/__END__.txt3
-rw-r--r--test/prism/fixtures/and_or_with_suffix.txt17
-rw-r--r--test/prism/fixtures/blocks.txt8
-rw-r--r--test/prism/fixtures/bom_leading_space.txt1
-rw-r--r--test/prism/fixtures/bom_spaces.txt1
-rw-r--r--test/prism/fixtures/break.txt4
-rw-r--r--test/prism/fixtures/case_in_hash_key.txt6
-rw-r--r--test/prism/fixtures/case_in_in.txt4
-rw-r--r--test/prism/fixtures/character_literal.txt2
-rw-r--r--test/prism/fixtures/command_method_call_2.txt1
-rw-r--r--test/prism/fixtures/command_method_call_3.txt19
-rw-r--r--test/prism/fixtures/endless_method_as_default_arg.txt11
-rw-r--r--test/prism/fixtures/endless_methods.txt6
-rw-r--r--test/prism/fixtures/escaped_newline_with_trailing_content.txt2
-rw-r--r--test/prism/fixtures/heredoc_dedent_line_continuation.txt5
-rw-r--r--test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt22
-rw-r--r--test/prism/fixtures/it.txt3
-rw-r--r--test/prism/fixtures/it_assignment.txt1
-rw-r--r--test/prism/fixtures/next.txt4
-rw-r--r--test/prism/fixtures/non_void_value.txt31
-rw-r--r--test/prism/fixtures/patterns.txt4
-rw-r--r--test/prism/fixtures/rescue.txt4
-rw-r--r--test/prism/fixtures/return.txt3
-rw-r--r--test/prism/fixtures/string_concatination_frozen_false.txt5
-rw-r--r--test/prism/fixtures/string_concatination_frozen_true.txt5
-rw-r--r--test/prism/fixtures/strings.txt32
-rw-r--r--test/prism/fixtures/unary_method_calls.txt8
-rw-r--r--test/prism/fixtures/write_command_operator.txt3
-rw-r--r--test/prism/fixtures_test.rb10
-rw-r--r--test/prism/lex_test.rb117
-rw-r--r--test/prism/locals_test.rb20
-rw-r--r--test/prism/magic_comment_test.rb5
-rw-r--r--test/prism/newline_offsets_test.rb27
-rw-r--r--test/prism/newline_test.rb3
-rw-r--r--test/prism/ractor_test.rb6
-rw-r--r--test/prism/result/breadth_first_search_test.rb11
-rw-r--r--test/prism/result/continuable_test.rb124
-rw-r--r--test/prism/result/error_recovery_test.rb237
-rw-r--r--test/prism/result/numeric_value_test.rb11
-rw-r--r--test/prism/result/overlap_test.rb9
-rw-r--r--test/prism/result/source_location_test.rb16
-rw-r--r--test/prism/result/warnings_test.rb19
-rw-r--r--test/prism/ruby/find_fixtures.rb69
-rw-r--r--test/prism/ruby/find_test.rb242
-rw-r--r--test/prism/ruby/location_test.rb49
-rw-r--r--test/prism/ruby/parameters_signature_test.rb17
-rw-r--r--test/prism/ruby/parser_test.rb96
-rw-r--r--test/prism/ruby/ripper_test.rb277
-rw-r--r--test/prism/ruby/ruby_parser_test.rb45
-rw-r--r--test/prism/ruby/source_test.rb51
-rw-r--r--test/prism/snippets_test.rb12
-rw-r--r--test/prism/test_helper.rb58
-rw-r--r--test/psych/test_data.rb93
-rw-r--r--test/psych/test_exception.rb13
-rw-r--r--test/psych/test_object_references.rb5
-rw-r--r--test/psych/test_parser.rb42
-rw-r--r--test/psych/test_psych.rb11
-rw-r--r--test/psych/test_psych_set.rb57
-rw-r--r--test/psych/test_ractor.rb6
-rw-r--r--test/psych/test_safe_load.rb32
-rw-r--r--test/psych/test_scalar_scanner.rb5
-rw-r--r--test/psych/test_serialize_subclasses.rb18
-rw-r--r--test/psych/test_set.rb61
-rw-r--r--test/psych/test_stream.rb8
-rw-r--r--test/psych/test_stringio.rb14
-rw-r--r--test/psych/test_yaml.rb47
-rw-r--r--test/psych/test_yaml_special_cases.rb12
-rw-r--r--test/psych/visitors/test_to_ruby.rb6
-rw-r--r--test/psych/visitors/test_yaml_tree.rb21
-rw-r--r--test/resolv/test_dns.rb134
-rw-r--r--test/resolv/test_resource.rb74
-rw-r--r--test/resolv/test_win32_config.rb26
-rw-r--r--test/ripper/assert_parse_files.rb1
-rw-r--r--test/ripper/test_lexer.rb52
-rw-r--r--test/ripper/test_parser_events.rb7
-rw-r--r--test/ruby/box/a.1_1_0.rb17
-rw-r--r--test/ruby/box/a.1_2_0.rb17
-rw-r--r--test/ruby/box/a.rb15
-rw-r--r--test/ruby/box/autoloading.rb8
-rw-r--r--test/ruby/box/blank.rb2
-rw-r--r--test/ruby/box/blank1.rb2
-rw-r--r--test/ruby/box/blank2.rb2
-rw-r--r--test/ruby/box/box.rb10
-rw-r--r--test/ruby/box/call_proc.rb5
-rw-r--r--test/ruby/box/call_toplevel.rb8
-rw-r--r--test/ruby/box/consts.rb148
-rw-r--r--test/ruby/box/define_toplevel.rb5
-rw-r--r--test/ruby/box/global_vars.rb37
-rw-r--r--test/ruby/box/instance_variables.rb21
-rw-r--r--test/ruby/box/line_splitter.rb9
-rw-r--r--test/ruby/box/load_path.rb26
-rw-r--r--test/ruby/box/open_class_with_include.rb31
-rw-r--r--test/ruby/box/proc_callee.rb14
-rw-r--r--test/ruby/box/proc_caller.rb5
-rw-r--r--test/ruby/box/procs.rb64
-rw-r--r--test/ruby/box/raise.rb3
-rw-r--r--test/ruby/box/returns_proc.rb12
-rw-r--r--test/ruby/box/singleton_methods.rb65
-rw-r--r--test/ruby/box/string_ext.rb13
-rw-r--r--test/ruby/box/string_ext_caller.rb5
-rw-r--r--test/ruby/box/string_ext_calling.rb1
-rw-r--r--test/ruby/box/string_ext_eval_caller.rb12
-rw-r--r--test/ruby/box/top_level.rb33
-rw-r--r--test/ruby/enc/test_emoji_breaks.rb2
-rw-r--r--test/ruby/sentence.rb2
-rw-r--r--test/ruby/test_allocation.rb85
-rw-r--r--test/ruby/test_array.rb75
-rw-r--r--test/ruby/test_ast.rb154
-rw-r--r--test/ruby/test_autoload.rb119
-rw-r--r--test/ruby/test_backtrace.rb22
-rw-r--r--test/ruby/test_beginendblock.rb3
-rw-r--r--test/ruby/test_bignum.rb46
-rw-r--r--test/ruby/test_box.rb1219
-rw-r--r--test/ruby/test_call.rb97
-rw-r--r--test/ruby/test_class.rb164
-rw-r--r--test/ruby/test_compile_prism.rb74
-rw-r--r--test/ruby/test_data.rb35
-rw-r--r--test/ruby/test_defined.rb28
-rw-r--r--test/ruby/test_dir.rb2
-rw-r--r--test/ruby/test_encoding.rb44
-rw-r--r--test/ruby/test_enum.rb10
-rw-r--r--test/ruby/test_enumerator.rb28
-rw-r--r--test/ruby/test_env.rb532
-rw-r--r--test/ruby/test_exception.rb29
-rw-r--r--test/ruby/test_fiber.rb45
-rw-r--r--test/ruby/test_file.rb19
-rw-r--r--test/ruby/test_file_exhaustive.rb53
-rw-r--r--test/ruby/test_float.rb43
-rw-r--r--test/ruby/test_frozen.rb16
-rw-r--r--test/ruby/test_gc.rb183
-rw-r--r--test/ruby/test_gc_compact.rb58
-rw-r--r--test/ruby/test_hash.rb51
-rw-r--r--test/ruby/test_integer.rb10
-rw-r--r--test/ruby/test_io.rb124
-rw-r--r--test/ruby/test_io_buffer.rb410
-rw-r--r--test/ruby/test_io_m17n.rb41
-rw-r--r--test/ruby/test_iseq.rb185
-rw-r--r--test/ruby/test_keyword.rb34
-rw-r--r--test/ruby/test_lambda.rb14
-rw-r--r--test/ruby/test_lazy_enumerator.rb21
-rw-r--r--test/ruby/test_literal.rb5
-rw-r--r--test/ruby/test_m17n.rb118
-rw-r--r--test/ruby/test_marshal.rb100
-rw-r--r--test/ruby/test_math.rb32
-rw-r--r--test/ruby/test_memory_view.rb2
-rw-r--r--test/ruby/test_metaclass.rb2
-rw-r--r--test/ruby/test_method.rb49
-rw-r--r--test/ruby/test_module.rb107
-rw-r--r--test/ruby/test_nomethod_error.rb30
-rw-r--r--test/ruby/test_numeric.rb42
-rw-r--r--test/ruby/test_object.rb204
-rw-r--r--test/ruby/test_object_id.rb303
-rw-r--r--test/ruby/test_objectspace.rb54
-rw-r--r--test/ruby/test_optimization.rb72
-rw-r--r--test/ruby/test_pack.rb167
-rw-r--r--test/ruby/test_parse.rb19
-rw-r--r--test/ruby/test_pattern_matching.rb42
-rw-r--r--test/ruby/test_proc.rb229
-rw-r--r--test/ruby/test_process.rb53
-rw-r--r--test/ruby/test_ractor.rb340
-rw-r--r--test/ruby/test_range.rb7
-rw-r--r--test/ruby/test_rational.rb48
-rw-r--r--test/ruby/test_refinement.rb950
-rw-r--r--test/ruby/test_regexp.rb236
-rw-r--r--test/ruby/test_require.rb48
-rw-r--r--test/ruby/test_require_lib.rb2
-rw-r--r--test/ruby/test_rubyoptions.rb126
-rw-r--r--test/ruby/test_set.rb1072
-rw-r--r--test/ruby/test_settracefunc.rb230
-rw-r--r--test/ruby/test_shapes.rb418
-rw-r--r--test/ruby/test_signal.rb22
-rw-r--r--test/ruby/test_sleep.rb18
-rw-r--r--test/ruby/test_string.rb393
-rw-r--r--test/ruby/test_struct.rb20
-rw-r--r--test/ruby/test_super.rb29
-rw-r--r--test/ruby/test_symbol.rb5
-rw-r--r--test/ruby/test_syntax.rb287
-rw-r--r--test/ruby/test_thread.rb113
-rw-r--r--test/ruby/test_thread_cv.rb4
-rw-r--r--test/ruby/test_thread_queue.rb16
-rw-r--r--test/ruby/test_time.rb7
-rw-r--r--test/ruby/test_time_tz.rb1
-rw-r--r--test/ruby/test_transcode.rb87
-rw-r--r--test/ruby/test_variable.rb156
-rw-r--r--test/ruby/test_vm_dump.rb5
-rw-r--r--test/ruby/test_weakmap.rb34
-rw-r--r--test/ruby/test_yield.rb2
-rw-r--r--test/ruby/test_yjit.rb161
-rw-r--r--test/ruby/test_zjit.rb556
-rw-r--r--test/rubygems/coverage_setup.rb9
-rw-r--r--test/rubygems/helper.rb145
-rw-r--r--test/rubygems/installer_test_case.rb30
-rw-r--r--test/rubygems/mock_gem_ui.rb2
-rw-r--r--test/rubygems/package/tar_test_case.rb38
-rw-r--r--test/rubygems/test_bundled_ca.rb2
-rw-r--r--test/rubygems/test_config.rb7
-rw-r--r--test/rubygems/test_gem.rb102
-rw-r--r--test/rubygems/test_gem_bundler_version_finder.rb159
-rw-r--r--test/rubygems/test_gem_command_manager.rb45
-rw-r--r--test/rubygems/test_gem_commands_build_command.rb10
-rw-r--r--test/rubygems/test_gem_commands_cert_command.rb22
-rw-r--r--test/rubygems/test_gem_commands_environment_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_exec_command.rb29
-rw-r--r--test/rubygems/test_gem_commands_fetch_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_help_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_info_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_install_command.rb156
-rw-r--r--test/rubygems/test_gem_commands_open_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb30
-rw-r--r--test/rubygems/test_gem_commands_pristine_command.rb62
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb172
-rw-r--r--test/rubygems/test_gem_commands_query_command.rb830
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb31
-rw-r--r--test/rubygems/test_gem_commands_signin_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_sources_command.rb685
-rw-r--r--test/rubygems/test_gem_commands_uninstall_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_update_command.rb32
-rw-r--r--test/rubygems/test_gem_commands_which_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb15
-rw-r--r--test/rubygems/test_gem_config_file.rb56
-rw-r--r--test/rubygems/test_gem_dependency_installer.rb200
-rw-r--r--test/rubygems/test_gem_dependency_resolution_error.rb23
-rw-r--r--test/rubygems/test_gem_ext_builder.rb69
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder.rb52
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock51
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock51
-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_link_flag_converter.rb2
-rw-r--r--test/rubygems/test_gem_ext_cmake_builder.rb97
-rw-r--r--test/rubygems/test_gem_ext_ext_conf_builder.rb33
-rw-r--r--test/rubygems/test_gem_ext_rake_builder.rb2
-rw-r--r--test/rubygems/test_gem_gem_runner.rb11
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb16
-rw-r--r--test/rubygems/test_gem_impossible_dependencies_error.rb60
-rw-r--r--test/rubygems/test_gem_install_update_options.rb12
-rw-r--r--test/rubygems/test_gem_installer.rb398
-rw-r--r--test/rubygems/test_gem_name_tuple.rb37
-rw-r--r--test/rubygems/test_gem_package.rb187
-rw-r--r--test/rubygems/test_gem_package_old.rb2
-rw-r--r--test/rubygems/test_gem_package_tar_header_ractor.rb61
-rw-r--r--test/rubygems/test_gem_package_tar_writer.rb13
-rw-r--r--test/rubygems/test_gem_path_support.rb8
-rw-r--r--test/rubygems/test_gem_platform.rb305
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb239
-rw-r--r--test/rubygems/test_gem_remote_fetcher_s3.rb296
-rw-r--r--test/rubygems/test_gem_request.rb12
-rw-r--r--test/rubygems/test_gem_request_connection_pools.rb12
-rw-r--r--test/rubygems/test_gem_request_set.rb132
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_parser.rb544
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_tokenizer.rb307
-rw-r--r--test/rubygems/test_gem_requirement.rb22
-rw-r--r--test/rubygems/test_gem_resolver.rb496
-rw-r--r--test/rubygems/test_gem_resolver_best_set.rb14
-rw-r--r--test/rubygems/test_gem_resolver_conflict.rb80
-rw-r--r--test/rubygems/test_gem_resolver_git_specification.rb38
-rw-r--r--test/rubygems/test_gem_resolver_strategy.rb163
-rw-r--r--test/rubygems/test_gem_safe_marshal.rb4
-rw-r--r--test/rubygems/test_gem_safe_yaml.rb1302
-rw-r--r--test/rubygems/test_gem_security_trust_dir.rb6
-rw-r--r--test/rubygems/test_gem_source_git.rb2
-rw-r--r--test/rubygems/test_gem_source_list.rb127
-rw-r--r--test/rubygems/test_gem_source_local.rb24
-rw-r--r--test/rubygems/test_gem_specification.rb231
-rw-r--r--test/rubygems/test_gem_stub_specification.rb26
-rw-r--r--test/rubygems/test_gem_uri.rb2
-rw-r--r--test/rubygems/test_gem_util.rb11
-rw-r--r--test/rubygems/test_gem_util_atomic_file_writer.rb12
-rw-r--r--test/rubygems/test_gem_version.rb92
-rw-r--r--test/rubygems/test_project_sanity.rb3
-rw-r--r--test/rubygems/test_require.rb19
-rw-r--r--test/rubygems/test_rubygems.rb1
-rw-r--r--test/rubygems/test_webauthn_listener.rb2
-rw-r--r--test/set/fixtures/fake_sorted_set_gem/sorted_set.rb9
-rw-r--r--test/set/test_set.rb897
-rw-r--r--test/set/test_sorted_set.rb45
-rw-r--r--test/socket/test_addrinfo.rb6
-rw-r--r--test/socket/test_nonblock.rb4
-rw-r--r--test/socket/test_socket.rb123
-rw-r--r--test/socket/test_tcp.rb26
-rw-r--r--test/socket/test_unix.rb21
-rw-r--r--test/stringio/test_ractor.rb6
-rw-r--r--test/stringio/test_stringio.rb151
-rw-r--r--test/strscan/test_ractor.rb6
-rw-r--r--test/strscan/test_stringscanner.rb95
-rw-r--r--test/test_bundled_gems.rb38
-rw-r--r--test/test_delegate.rb57
-rw-r--r--test/test_extlibs.rb2
-rw-r--r--test/test_ipaddr.rb100
-rw-r--r--test/test_pp.rb58
-rw-r--r--test/test_prettyprint.rb71
-rw-r--r--test/test_rbconfig.rb2
-rw-r--r--test/test_time.rb2
-rw-r--r--test/test_timeout.rb264
-rw-r--r--test/test_tmpdir.rb33
-rw-r--r--test/test_tsort.rb115
-rw-r--r--test/test_unicode_normalize.rb28
-rw-r--r--test/uri/test_common.rb26
-rw-r--r--test/uri/test_ftp.rb10
-rw-r--r--test/uri/test_generic.rb74
-rw-r--r--test/uri/test_http.rb20
-rw-r--r--test/uri/test_mailto.rb72
-rw-r--r--test/uri/test_parser.rb26
-rw-r--r--test/uri/test_ws.rb16
-rw-r--r--test/uri/test_wss.rb16
-rw-r--r--test/win32/test_registry.rb256
-rw-r--r--test/zlib/test_zlib.rb85
-rw-r--r--thread.c760
-rw-r--r--thread_none.c19
-rw-r--r--thread_pthread.c567
-rw-r--r--thread_pthread.h25
-rw-r--r--thread_pthread_mn.c184
-rw-r--r--thread_sync.c1370
-rw-r--r--thread_sync.rb649
-rw-r--r--thread_win32.c57
-rw-r--r--time.c123
-rw-r--r--timev.rb18
-rwxr-xr-xtool/auto-style.rb284
-rwxr-xr-xtool/auto_review_pr.rb172
-rw-r--r--tool/bundler/dev_gems.rb5
-rw-r--r--tool/bundler/dev_gems.rb.lock127
-rw-r--r--tool/bundler/rubocop_gems.rb4
-rw-r--r--tool/bundler/rubocop_gems.rb.lock170
-rw-r--r--tool/bundler/standard_gems.rb4
-rw-r--r--tool/bundler/standard_gems.rb.lock190
-rw-r--r--tool/bundler/test_gems.rb12
-rw-r--r--tool/bundler/test_gems.rb.lock95
-rw-r--r--tool/bundler/vendor_gems.rb18
-rw-r--r--tool/bundler/vendor_gems.rb.lock58
-rwxr-xr-xtool/commit-email.rb372
-rw-r--r--tool/downloader.rb87
-rw-r--r--tool/dump_ast.c77
-rwxr-xr-xtool/dump_ast.mkmf.rb37
-rwxr-xr-xtool/enc-unicode.rb6
-rwxr-xr-xtool/fetch-bundled_gems.rb24
-rwxr-xr-xtool/format-release51
-rwxr-xr-xtool/ifchange4
-rwxr-xr-xtool/leaked-globals2
-rw-r--r--tool/lib/_tmpdir.rb121
-rw-r--r--tool/lib/bundle_env.rb4
-rw-r--r--tool/lib/bundled_gem.rb54
-rw-r--r--tool/lib/colorize.rb72
-rw-r--r--tool/lib/core_assertions.rb112
-rw-r--r--tool/lib/dump.gdb17
-rw-r--r--tool/lib/dump.lldb13
-rw-r--r--tool/lib/envutil.rb112
-rw-r--r--tool/lib/gem_env.rb3
-rw-r--r--tool/lib/leakchecker.rb36
-rw-r--r--tool/lib/memory_status.rb100
-rw-r--r--tool/lib/output.rb13
-rw-r--r--tool/lib/test/jobserver.rb47
-rw-r--r--tool/lib/test/unit.rb32
-rw-r--r--tool/lib/test/unit/assertions.rb10
-rw-r--r--tool/lib/vcs.rb357
-rw-r--r--tool/lrama/NEWS.md445
-rwxr-xr-xtool/lrama/exe/lrama2
-rw-r--r--tool/lrama/lib/lrama.rb10
-rw-r--r--tool/lrama/lib/lrama/bitmap.rb23
-rw-r--r--tool/lrama/lib/lrama/command.rb138
-rw-r--r--tool/lrama/lib/lrama/context.rb46
-rw-r--r--tool/lrama/lib/lrama/counterexamples.rb304
-rw-r--r--tool/lrama/lib/lrama/counterexamples/derivation.rb18
-rw-r--r--tool/lrama/lib/lrama/counterexamples/example.rb69
-rw-r--r--tool/lrama/lib/lrama/counterexamples/node.rb30
-rw-r--r--tool/lrama/lib/lrama/counterexamples/path.rb26
-rw-r--r--tool/lrama/lib/lrama/counterexamples/production_path.rb19
-rw-r--r--tool/lrama/lib/lrama/counterexamples/start_path.rb23
-rw-r--r--tool/lrama/lib/lrama/counterexamples/state_item.rb25
-rw-r--r--tool/lrama/lib/lrama/counterexamples/transition_path.rb19
-rw-r--r--tool/lrama/lib/lrama/counterexamples/triple.rb36
-rw-r--r--tool/lrama/lib/lrama/diagnostics.rb36
-rw-r--r--tool/lrama/lib/lrama/diagram.rb77
-rw-r--r--tool/lrama/lib/lrama/digraph.rb35
-rw-r--r--tool/lrama/lib/lrama/erb.rb29
-rw-r--r--tool/lrama/lib/lrama/grammar.rb266
-rw-r--r--tool/lrama/lib/lrama/grammar/auxiliary.rb7
-rw-r--r--tool/lrama/lib/lrama/grammar/binding.rb63
-rw-r--r--tool/lrama/lib/lrama/grammar/code.rb17
-rw-r--r--tool/lrama/lib/lrama/grammar/code/destructor_code.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/code/initial_action_code.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/code/no_reference_code.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/code/printer_code.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/code/rule_action.rb50
-rw-r--r--tool/lrama/lib/lrama/grammar/counter.rb10
-rw-r--r--tool/lrama/lib/lrama/grammar/destructor.rb15
-rw-r--r--tool/lrama/lib/lrama/grammar/error_token.rb15
-rw-r--r--tool/lrama/lib/lrama/grammar/inline.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/inline/resolver.rb80
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized.rb5
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized/resolver.rb73
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized/rhs.rb45
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterized/rule.rb36
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule.rb5
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb62
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb40
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb24
-rw-r--r--tool/lrama/lib/lrama/grammar/percent_code.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar/precedence.rb44
-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.rb66
-rw-r--r--tool/lrama/lib/lrama/grammar/rule_builder.rb153
-rw-r--r--tool/lrama/lib/lrama/grammar/stdlib.y116
-rw-r--r--tool/lrama/lib/lrama/grammar/symbol.rb82
-rw-r--r--tool/lrama/lib/lrama/grammar/symbols/resolver.rb67
-rw-r--r--tool/lrama/lib/lrama/grammar/type.rb14
-rw-r--r--tool/lrama/lib/lrama/grammar/union.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar_validator.rb37
-rw-r--r--tool/lrama/lib/lrama/lexer.rb74
-rw-r--r--tool/lrama/lib/lrama/lexer/location.rb33
-rw-r--r--tool/lrama/lib/lrama/lexer/token.rb62
-rw-r--r--tool/lrama/lib/lrama/lexer/token/base.rb73
-rw-r--r--tool/lrama/lib/lrama/lexer/token/char.rb17
-rw-r--r--tool/lrama/lib/lrama/lexer/token/empty.rb14
-rw-r--r--tool/lrama/lib/lrama/lexer/token/ident.rb4
-rw-r--r--tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb8
-rw-r--r--tool/lrama/lib/lrama/lexer/token/int.rb14
-rw-r--r--tool/lrama/lib/lrama/lexer/token/str.rb11
-rw-r--r--tool/lrama/lib/lrama/lexer/token/tag.rb4
-rw-r--r--tool/lrama/lib/lrama/lexer/token/token.rb11
-rw-r--r--tool/lrama/lib/lrama/lexer/token/user_code.rb100
-rw-r--r--tool/lrama/lib/lrama/logger.rb14
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb72
-rw-r--r--tool/lrama/lib/lrama/options.rb32
-rw-r--r--tool/lrama/lib/lrama/output.rb17
-rw-r--r--tool/lrama/lib/lrama/parser.rb1591
-rw-r--r--tool/lrama/lib/lrama/report.rb4
-rw-r--r--tool/lrama/lib/lrama/report/duration.rb27
-rw-r--r--tool/lrama/lib/lrama/report/profile.rb16
-rw-r--r--tool/lrama/lib/lrama/reporter.rb39
-rw-r--r--tool/lrama/lib/lrama/reporter/conflicts.rb44
-rw-r--r--tool/lrama/lib/lrama/reporter/grammar.rb39
-rw-r--r--tool/lrama/lib/lrama/reporter/precedences.rb54
-rw-r--r--tool/lrama/lib/lrama/reporter/profile.rb4
-rw-r--r--tool/lrama/lib/lrama/reporter/profile/call_stack.rb45
-rw-r--r--tool/lrama/lib/lrama/reporter/profile/memory.rb44
-rw-r--r--tool/lrama/lib/lrama/reporter/rules.rb43
-rw-r--r--tool/lrama/lib/lrama/reporter/states.rb387
-rw-r--r--tool/lrama/lib/lrama/reporter/terms.rb44
-rw-r--r--tool/lrama/lib/lrama/state.rb501
-rw-r--r--tool/lrama/lib/lrama/state/action.rb5
-rw-r--r--tool/lrama/lib/lrama/state/action/goto.rb33
-rw-r--r--tool/lrama/lib/lrama/state/action/reduce.rb71
-rw-r--r--tool/lrama/lib/lrama/state/action/shift.rb39
-rw-r--r--tool/lrama/lib/lrama/state/inadequacy_annotation.rb140
-rw-r--r--tool/lrama/lib/lrama/state/item.rb120
-rw-r--r--tool/lrama/lib/lrama/state/reduce.rb37
-rw-r--r--tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb15
-rw-r--r--tool/lrama/lib/lrama/state/resolved_conflict.rb42
-rw-r--r--tool/lrama/lib/lrama/state/shift.rb15
-rw-r--r--tool/lrama/lib/lrama/state/shift_reduce_conflict.rb15
-rw-r--r--tool/lrama/lib/lrama/states.rb622
-rw-r--r--tool/lrama/lib/lrama/states/item.rb91
-rw-r--r--tool/lrama/lib/lrama/states_reporter.rb362
-rw-r--r--tool/lrama/lib/lrama/trace_reporter.rb45
-rw-r--r--tool/lrama/lib/lrama/tracer.rb51
-rw-r--r--tool/lrama/lib/lrama/tracer/actions.rb22
-rw-r--r--tool/lrama/lib/lrama/tracer/closure.rb30
-rw-r--r--tool/lrama/lib/lrama/tracer/duration.rb38
-rw-r--r--tool/lrama/lib/lrama/tracer/only_explicit_rules.rb24
-rw-r--r--tool/lrama/lib/lrama/tracer/rules.rb23
-rw-r--r--tool/lrama/lib/lrama/tracer/state.rb33
-rw-r--r--tool/lrama/lib/lrama/version.rb3
-rw-r--r--tool/lrama/lib/lrama/warnings.rb33
-rw-r--r--tool/lrama/lib/lrama/warnings/conflicts.rb27
-rw-r--r--tool/lrama/lib/lrama/warnings/implicit_empty.rb29
-rw-r--r--tool/lrama/lib/lrama/warnings/name_conflicts.rb63
-rw-r--r--tool/lrama/lib/lrama/warnings/redefined_rules.rb23
-rw-r--r--tool/lrama/lib/lrama/warnings/required.rb23
-rw-r--r--tool/lrama/lib/lrama/warnings/useless_precedence.rb25
-rw-r--r--tool/lrama/template/bison/_yacc.h8
-rw-r--r--tool/lrama/template/diagram/diagram.html102
-rw-r--r--tool/m4/ruby_append_option.m42
-rw-r--r--tool/m4/ruby_defint.m43
-rwxr-xr-xtool/make-snapshot66
-rwxr-xr-xtool/merger.rb21
-rwxr-xr-xtool/missing-baseruby.bat11
-rw-r--r--tool/mk_builtin_loader.rb399
-rwxr-xr-xtool/mkconfig.rb1
-rw-r--r--tool/notes-github-pr.rb138
-rw-r--r--tool/notify-slack-commits.rb87
-rwxr-xr-xtool/outdate-bundled-gems.rb25
-rw-r--r--tool/prereq.status11
-rwxr-xr-xtool/rbinstall.rb158
-rw-r--r--tool/rbs_skip_tests34
-rw-r--r--tool/rbs_skip_tests_windows111
-rwxr-xr-xtool/rdoc-srcdir5
-rwxr-xr-xtool/redmine-backporter.rb2
-rwxr-xr-xtool/releng/gen-mail.rb2
-rwxr-xr-xtool/releng/update-www-meta.rb25
-rwxr-xr-xtool/ruby-version.rb52
-rw-r--r--tool/ruby_vm/models/bare_instruction.rb236
-rw-r--r--tool/ruby_vm/models/bare_instructions.rb239
-rw-r--r--tool/ruby_vm/models/instructions.rb18
-rw-r--r--tool/ruby_vm/models/instructions_unification.rb42
-rw-r--r--tool/ruby_vm/models/instructions_unifications.rb42
-rw-r--r--tool/ruby_vm/models/operands_unification.rb141
-rw-r--r--tool/ruby_vm/models/operands_unifications.rb141
-rw-r--r--tool/ruby_vm/models/trace_instruction.rb70
-rw-r--r--tool/ruby_vm/models/trace_instructions.rb70
-rw-r--r--tool/ruby_vm/models/zjit_instruction.rb56
-rw-r--r--tool/ruby_vm/views/_comptime_insn_stack_increase.erb25
-rw-r--r--tool/ruby_vm/views/_insn_leaf_info.erb18
-rw-r--r--tool/ruby_vm/views/_insn_len_info.erb12
-rw-r--r--tool/ruby_vm/views/_insn_name_info.erb33
-rw-r--r--tool/ruby_vm/views/_insn_operand_info.erb32
-rw-r--r--tool/ruby_vm/views/_leaf_helpers.erb6
-rw-r--r--tool/ruby_vm/views/_zjit_helpers.erb31
-rw-r--r--tool/ruby_vm/views/_zjit_instruction.erb12
-rw-r--r--tool/ruby_vm/views/insns.inc.erb17
-rw-r--r--tool/ruby_vm/views/insns_info.inc.erb5
-rw-r--r--tool/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb14
-rw-r--r--tool/ruby_vm/views/optinsn.inc.erb4
-rw-r--r--tool/ruby_vm/views/optunifs.inc.erb5
-rw-r--r--tool/ruby_vm/views/vm.inc.erb12
-rw-r--r--tool/ruby_vm/views/vmtc.inc.erb10
-rwxr-xr-xtool/sync_default_gems.rb1129
-rw-r--r--tool/test-bundled-gems.rb226
-rw-r--r--tool/test-coverage.rb4
-rw-r--r--tool/test/init.rb12
-rw-r--r--tool/test/test_commit_email.rb102
-rwxr-xr-xtool/test/test_sync_default_gems.rb110
-rw-r--r--tool/test/testunit/test_assertion.rb25
-rw-r--r--tool/test/testunit/test_minitest_unit.rb9
-rw-r--r--tool/test/testunit/test_parallel.rb32
-rw-r--r--tool/test/testunit/tests_for_parallel/ptest_forth.rb8
-rwxr-xr-xtool/update-NEWS-gemlist.rb28
-rwxr-xr-xtool/update-NEWS-github-release.rb395
-rwxr-xr-xtool/update-bundled_gems.rb55
-rwxr-xr-xtool/update-deps32
-rwxr-xr-xtool/zjit_bisect.rb165
-rwxr-xr-xtool/zjit_diff.rb272
-rw-r--r--tool/zjit_iongraph.html551
-rwxr-xr-xtool/zjit_iongraph.rb38
-rw-r--r--trace_point.rb8
-rw-r--r--transcode.c379
-rw-r--r--universal_parser.c3
-rw-r--r--util.c73
-rw-r--r--variable.c2286
-rw-r--r--variable.h28
-rw-r--r--vcpkg.json4
-rw-r--r--version.c45
-rw-r--r--vm.c856
-rw-r--r--vm_args.c115
-rw-r--r--vm_backtrace.c266
-rw-r--r--vm_callinfo.h200
-rw-r--r--vm_core.h432
-rw-r--r--vm_debug.h8
-rw-r--r--vm_dump.c356
-rw-r--r--vm_eval.c302
-rw-r--r--vm_exec.c6
-rw-r--r--vm_exec.h27
-rw-r--r--vm_insnhelper.c1234
-rw-r--r--vm_insnhelper.h15
-rw-r--r--vm_method.c963
-rw-r--r--vm_sync.c76
-rw-r--r--vm_sync.h25
-rw-r--r--vm_trace.c488
-rw-r--r--wasm/setjmp.h2
-rw-r--r--weakmap.c512
-rw-r--r--win32/Makefile.sub269
-rw-r--r--[-rwxr-xr-x]win32/configure.bat479
-rw-r--r--win32/enc-setup.mak4
-rw-r--r--win32/file.c4
-rwxr-xr-xwin32/ifchange.bat117
-rwxr-xr-xwin32/install-buildtools.cmd14
-rwxr-xr-xwin32/install-msys-packages.cmd29
-rwxr-xr-xwin32/lastrev.bat30
-rwxr-xr-xwin32/makedirs.bat2
-rwxr-xr-xwin32/mkexports.rb13
-rwxr-xr-xwin32/rm.bat70
-rwxr-xr-xwin32/rmdirs.bat8
-rwxr-xr-xwin32/rtname.cmd71
-rw-r--r--win32/setup.mak100
-rw-r--r--win32/shellsplit.cmd114
-rw-r--r--win32/test_shellsplit.cmd28
-rwxr-xr-xwin32/vssetup.cmd56
-rw-r--r--win32/win32.c354
-rw-r--r--yjit.c846
-rw-r--r--yjit.h11
-rw-r--r--yjit.rb39
-rw-r--r--yjit/Cargo.lock22
-rw-r--r--yjit/Cargo.toml35
-rw-r--r--yjit/bindgen/Cargo.lock2
-rw-r--r--yjit/bindgen/Cargo.toml2
-rw-r--r--yjit/bindgen/src/main.rs162
-rw-r--r--yjit/not_gmake.mk2
-rw-r--r--yjit/src/asm/mod.rs49
-rw-r--r--yjit/src/asm/x86_64/mod.rs10
-rw-r--r--yjit/src/asm/x86_64/tests.rs1
-rw-r--r--yjit/src/backend/arm64/mod.rs17
-rw-r--r--yjit/src/backend/ir.rs20
-rw-r--r--yjit/src/backend/tests.rs4
-rw-r--r--yjit/src/backend/x86_64/mod.rs30
-rw-r--r--yjit/src/codegen.rs715
-rw-r--r--yjit/src/core.rs219
-rw-r--r--yjit/src/cruby.rs56
-rw-r--r--yjit/src/cruby_bindings.inc.rs692
-rw-r--r--yjit/src/invariants.rs12
-rw-r--r--yjit/src/options.rs2
-rw-r--r--yjit/src/stats.rs73
-rw-r--r--yjit/src/utils.rs15
-rw-r--r--yjit/src/virtualmem.rs99
-rw-r--r--yjit/src/yjit.rs24
-rw-r--r--yjit/yjit.mk98
-rw-r--r--yjit_hook.rb9
-rw-r--r--zjit.c255
-rw-r--r--zjit.h119
-rw-r--r--zjit.rb284
-rw-r--r--zjit/.gitignore2
-rw-r--r--zjit/Cargo.lock594
-rw-r--r--zjit/Cargo.toml25
-rw-r--r--zjit/bindgen/Cargo.lock392
-rw-r--r--zjit/bindgen/Cargo.toml12
-rw-r--r--zjit/bindgen/src/main.rs470
-rw-r--r--zjit/build.rs29
-rw-r--r--zjit/src/asm/arm64/README.md16
-rw-r--r--zjit/src/asm/arm64/arg/bitmask_imm.rs255
-rw-r--r--zjit/src/asm/arm64/arg/condition.rs52
-rw-r--r--zjit/src/asm/arm64/arg/inst_offset.rs47
-rw-r--r--zjit/src/asm/arm64/arg/mod.rs18
-rw-r--r--zjit/src/asm/arm64/arg/sf.rs19
-rw-r--r--zjit/src/asm/arm64/arg/shifted_imm.rs80
-rw-r--r--zjit/src/asm/arm64/arg/sys_reg.rs6
-rw-r--r--zjit/src/asm/arm64/arg/truncate.rs66
-rw-r--r--zjit/src/asm/arm64/inst/atomic.rs86
-rw-r--r--zjit/src/asm/arm64/inst/branch.rs100
-rw-r--r--zjit/src/asm/arm64/inst/branch_cond.rs78
-rw-r--r--zjit/src/asm/arm64/inst/breakpoint.rs55
-rw-r--r--zjit/src/asm/arm64/inst/call.rs104
-rw-r--r--zjit/src/asm/arm64/inst/conditional.rs73
-rw-r--r--zjit/src/asm/arm64/inst/data_imm.rs143
-rw-r--r--zjit/src/asm/arm64/inst/data_reg.rs192
-rw-r--r--zjit/src/asm/arm64/inst/halfword_imm.rs179
-rw-r--r--zjit/src/asm/arm64/inst/load_literal.rs91
-rw-r--r--zjit/src/asm/arm64/inst/load_register.rs108
-rw-r--r--zjit/src/asm/arm64/inst/load_store.rs255
-rw-r--r--zjit/src/asm/arm64/inst/load_store_exclusive.rs109
-rw-r--r--zjit/src/asm/arm64/inst/logical_imm.rs154
-rw-r--r--zjit/src/asm/arm64/inst/logical_reg.rs207
-rw-r--r--zjit/src/asm/arm64/inst/madd.rs73
-rw-r--r--zjit/src/asm/arm64/inst/mod.rs56
-rw-r--r--zjit/src/asm/arm64/inst/mov.rs192
-rw-r--r--zjit/src/asm/arm64/inst/nop.rs44
-rw-r--r--zjit/src/asm/arm64/inst/pc_rel.rs107
-rw-r--r--zjit/src/asm/arm64/inst/reg_pair.rs212
-rw-r--r--zjit/src/asm/arm64/inst/sbfm.rs103
-rw-r--r--zjit/src/asm/arm64/inst/shift_imm.rs147
-rw-r--r--zjit/src/asm/arm64/inst/smulh.rs60
-rw-r--r--zjit/src/asm/arm64/inst/sys_reg.rs86
-rw-r--r--zjit/src/asm/arm64/inst/test_bit.rs133
-rw-r--r--zjit/src/asm/arm64/inst/udf.rs52
-rw-r--r--zjit/src/asm/arm64/mod.rs1987
-rw-r--r--zjit/src/asm/arm64/opnd.rs270
-rw-r--r--zjit/src/asm/mod.rs463
-rw-r--r--zjit/src/asm/x86_64/mod.rs1439
-rw-r--r--zjit/src/asm/x86_64/tests.rs966
-rw-r--r--zjit/src/backend/arm64/mod.rs2929
-rw-r--r--zjit/src/backend/lir.rs4471
-rw-r--r--zjit/src/backend/mod.rs19
-rw-r--r--zjit/src/backend/parcopy.rs368
-rw-r--r--zjit/src/backend/tests.rs261
-rw-r--r--zjit/src/backend/x86_64/mod.rs2461
-rw-r--r--zjit/src/bitset.rs225
-rw-r--r--zjit/src/cast.rs64
-rw-r--r--zjit/src/codegen.rs3638
-rw-r--r--zjit/src/codegen_tests.rs5768
-rw-r--r--zjit/src/cruby.rs1659
-rw-r--r--zjit/src/cruby_bindings.inc.rs2326
-rw-r--r--zjit/src/cruby_methods.rs1040
-rw-r--r--zjit/src/disasm.rs72
-rw-r--r--zjit/src/distribution.rs282
-rw-r--r--zjit/src/gc.rs244
-rw-r--r--zjit/src/hir.rs9491
-rw-r--r--zjit/src/hir/opt_tests.rs17281
-rw-r--r--zjit/src/hir/tests.rs6433
-rw-r--r--zjit/src/hir_effect/gen_hir_effect.rb126
-rw-r--r--zjit/src/hir_effect/hir_effect.inc.rs63
-rw-r--r--zjit/src/hir_effect/mod.rs420
-rw-r--r--zjit/src/hir_type/gen_hir_type.rb251
-rw-r--r--zjit/src/hir_type/hir_type.inc.rs300
-rw-r--r--zjit/src/hir_type/mod.rs1107
-rw-r--r--zjit/src/invariants.rs543
-rw-r--r--zjit/src/jit_frame.rs314
-rw-r--r--zjit/src/json.rs700
-rw-r--r--zjit/src/lib.rs46
-rw-r--r--zjit/src/options.rs631
-rw-r--r--zjit/src/payload.rs135
-rw-r--r--zjit/src/profile.rs582
-rw-r--r--zjit/src/state.rs541
-rw-r--r--zjit/src/stats.rs1280
-rw-r--r--zjit/src/ttycolors.rs31
-rw-r--r--zjit/src/virtualmem.rs504
-rw-r--r--zjit/zjit.mk141
5583 files changed, 371500 insertions, 216397 deletions
diff --git a/.document b/.document
index 7d4dc02d4a..753d6f9892 100644
--- a/.document
+++ b/.document
@@ -22,6 +22,7 @@ marshal.rb
numeric.rb
nilclass.rb
pack.rb
+pathname_builtin.rb
ractor.rb
string.rb
symbol.rb
@@ -30,6 +31,7 @@ thread_sync.rb
trace_point.rb
warning.rb
yjit.rb
+zjit.rb
# Errno::*
known_errors.inc
@@ -40,6 +42,9 @@ lib
# and some of the ext/ directory (which has its own .document file)
ext
+# For `prism`, ruby code is in lib and c in the prism folder
+prism
+
# rdoc files
NEWS.md
diff --git a/.gdbinit b/.gdbinit
index 4bf99377ac..4457f6f12b 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -51,7 +51,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) @ (RSHAPE_CAPACITY(rb_obj_shape_id($arg0)))
else
print (((struct RObject *)($arg0))->as.heap)
if (((struct RObject*)($arg0))->as.heap.numiv) > 0
@@ -185,12 +185,14 @@ define rp
print (struct RBasic *)($arg0)
else
if ($flags & RUBY_T_MASK) == RUBY_T_DATA
- if ((struct RTypedData *)($arg0))->typed_flag == 1
- printf "%sT_DATA%s(%s): ", $color_type, $color_end, ((struct RTypedData *)($arg0))->type->wrap_struct_name
- print (struct RTypedData *)($arg0)
+ set $data = (struct RTypedData *)($arg0)
+ set $type = (const rb_data_type_t *)($data->type & ~1)
+ printf "%sT_DATA%s(%s): ", $color_type, $color_end, $type->wrap_struct_name
+ print *$type
+ if ($data->type & 1)
+ print (void *)&$data->data
else
- printf "%sT_DATA%s: ", $color_type, $color_end
- print (struct RData *)($arg0)
+ print $data
end
else
if ($flags & RUBY_T_MASK) == RUBY_T_MATCH
@@ -523,14 +525,14 @@ document rp_bignum
end
define rp_class
+ set $class_and_classext = (struct RClass_and_rb_classext_t *)($arg0)
printf "(struct RClass *) %p", (void*)$arg0
- if RCLASS_ORIGIN((struct RClass *)($arg0)) != $arg0
- printf " -> %p", RCLASS_ORIGIN((struct RClass *)($arg0))
+ if $class_and_classext->classext->origin_ != (VALUE)$arg0
+ printf " -> %p", $class_and_classext->classext->origin_
end
printf "\n"
rb_classname $arg0
- print/x *(struct RClass *)($arg0)
- print *RCLASS_EXT((struct RClass *)($arg0))
+ print/x *$class_and_classext
end
document rp_class
Print the content of a Class/Module.
@@ -896,10 +898,10 @@ document rb_method_entry
end
define rb_classname
- # up to 128bit int
- set $rb_classname = rb_mod_name($arg0)
- if $rb_classname != RUBY_Qnil
- rp $rb_classname
+ set $rb_classname = ((struct RClass_and_rb_classext_t*)$arg0)->classext->classpath
+ if $rb_classname != RUBY_Qfalse
+ print_string $rb_classname
+ printf "\n"
else
echo anonymous class/module\n
end
@@ -972,7 +974,7 @@ end
define print_lineno
set $cfp = $arg0
- set $iseq = $cfp->iseq
+ set $iseq = rb_get_cfp_iseq($cfp)
set $pos = $cfp->pc - $iseq->body->iseq_encoded
if $pos != 0
set $pos = $pos - 1
@@ -1053,7 +1055,7 @@ define print_id
else
set $serial = (rb_id_serial_t)$id
end
- if $serial && $serial <= ruby_global_symbols.last_id
+ if $serial && $serial < ruby_global_symbols.next_id
set $idx = $serial / ID_ENTRY_UNIT
set $ids = (struct RArray *)ruby_global_symbols.ids
set $flags = $ids->basic.flags
@@ -1076,7 +1078,7 @@ define print_id
set $aryptr = $ary->as.heap.ptr
set $arylen = $ary->as.heap.len
end
- set $result = $aryptr[($serial % ID_ENTRY_UNIT) * ID_ENTRY_SIZE + $t]
+ set $result = $aryptr[($serial % ID_ENTRY_UNIT) + $t]
if $result != RUBY_Qnil
print_string $result
else
@@ -1110,16 +1112,17 @@ define rb_ps_thread
set $cfp = $ps_thread_th->ec->cfp
set $cfpend = (rb_control_frame_t *)($ps_thread_th->ec->vm_stack + $ps_thread_th->ec->vm_stack_size)-1
while $cfp < $cfpend
- if $cfp->iseq
- if !((VALUE)$cfp->iseq & RUBY_IMMEDIATE_MASK) && (((imemo_ifunc << RUBY_FL_USHIFT) | RUBY_T_IMEMO)==$cfp->iseq->flags & ((RUBY_IMEMO_MASK << RUBY_FL_USHIFT) | RUBY_T_MASK))
+ if $cfp->_iseq
+ set $iseq = rb_get_cfp_iseq($cfp)
+ if !((VALUE)$iseq & RUBY_IMMEDIATE_MASK) && (((imemo_ifunc << RUBY_FL_USHIFT) | RUBY_T_IMEMO)==$iseq->flags & ((RUBY_IMEMO_MASK << RUBY_FL_USHIFT) | RUBY_T_MASK))
printf "%d:ifunc ", $cfpend-$cfp
set print symbol-filename on
- output/a $cfp->iseq.body
+ output/a $iseq.body
set print symbol-filename off
printf "\n"
else
if $cfp->pc
- set $location = $cfp->iseq->body->location
+ set $location = $iseq->body->location
printf "%d:", $cfpend-$cfp
print_pathobj $location.pathobj
printf ":"
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index de62eb432a..d752612085 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -10,6 +10,11 @@ e63a2115f64433b21cb5dd67c5bf8b30f87ef293
712ac99e4d0384a941c80a9f48f62943ba7d97c0
d1474affa8e105bece209cc9d594bb0a989859e1
2da92388b948821269b18d6b178a680f17e41750
+5062c0c621d887367af8a054e5e5d83d7ec57dd3
+
+# Indentation
+0e4bad888e605d424b9222ae0ca43f85c1634e5e
+61aa46c41648c6d1e9b0daa1a292de551fde78df
# Enable Style/StringLiterals cop for RubyGems/Bundler
d7ffd3fea402239b16833cc434404a7af82d44f3
@@ -34,3 +39,16 @@ d2c5867357ed88eccc28c2b3bd4a46e206e7ff85
# Miss-and-revived commits
a0f7de814ae5c299d6ce99bed5fb308a05d50ba0
d4e24021d39e1f80f0055b55d91f8d5f22e15084
+7a56c316418980b8a41fcbdc94067b2bda2ad112
+e90282be7ba1bc8e3119f6e1a2c80356ceb3f80a
+26a9e0b4e31f7b5a9cbd755e0a15823a8fa51bae
+2f53985da9ee593fe524d408256835667938c7d7
+bf01f6ae89a95d8f5572e050facfe311c8c28aaf
+7480cd8d37fd71a41ce12b759090051c7e14fb5a
+
+# Win32: EOL code of batch files
+23f9a0d655c4d405bb2397a147a1523436205486
+b839989fd22fef85e2af19de1bc83aa72a5b22bd
+
+# ZJIT cargo-insta snapshot raw string literals
+b78e0a6ddf7df8a7568ea71284f593423c739551
diff --git a/.gitattributes b/.gitattributes
index d0c2d266b4..f98c091e3f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,8 +1,14 @@
*.gemspec diff=ruby
*.rb diff=ruby
+*.inc.rs linguist-generated=true
bin svn-properties=svn:ignore=ruby
bin/* diff=ruby
tool/update-deps diff=ruby
tool/make-snapshot diff=ruby
tool/format-release diff=ruby
tool/leaked-globals diff=ruby
+
+# To strip CR from the batch files, set the `diff.dos.textconv` filter
+# like as `git config diff.dos.textconv $'sed \'s/\r$//\''`.
+*.bat diff=dos
+*.cmd diff=dos
diff --git a/.github/actions/capiext/action.yml b/.github/actions/capiext/action.yml
new file mode 100644
index 0000000000..ed69c8ac5e
--- /dev/null
+++ b/.github/actions/capiext/action.yml
@@ -0,0 +1,86 @@
+name: rubyspec C-API extensions
+
+inputs:
+ builddir:
+ required: false
+ default: '.'
+ make:
+ required: false
+ default: 'make -s'
+
+outputs:
+ key:
+ value: >-
+ ${{
+ !steps.restore.outputs.cache-hit &&
+ github.ref == 'refs/heads/master' &&
+ steps.config.outputs.key
+ }}
+
+runs:
+ using: composite
+
+ steps:
+ - id: config
+ shell: bash
+ run: |
+ eval $(grep -e '^arch *=' -e '^ruby_version *=' -e '^DLEXT *=' Makefile |
+ sed 's/ *= */=/')
+ case "${ruby_version}" in
+ *+*) key=capiexts-${arch}-${ruby_version}-${{ hashFiles('src/spec/ruby/optional/capi/ext/*.[ch]') }};;
+ *) key=;;
+ esac
+ echo version=$ruby_version >> $GITHUB_OUTPUT
+ echo key="$key" >> $GITHUB_OUTPUT
+ echo DLEXT=$DLEXT >> $GITHUB_OUTPUT
+ working-directory: ${{ inputs.builddir }}
+
+ - name: Restore previous CAPI extensions
+ uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ id: cache
+ with:
+ path: ${{ inputs.builddir }}/spec/ruby/optional/capi/ext/
+ key: ${{ steps.config.outputs.key }}
+ if: ${{ steps.config.outputs.key }}
+
+ - name: Run test-spec with previous CAPI extension binaries
+ id: check
+ shell: bash
+ run: | # zizmor: ignore[template-injection]
+ touch spec/ruby/optional/capi/ext/*.$DLEXT
+ [ ! -f spec/ruby/optional/capi/ext/\*.$DLEXT ]
+ ${{ inputs.make }} SPECOPTS=optional/capi test-spec
+ env:
+ DLEXT: ${{ steps.config.outputs.DLEXT }}
+ working-directory: ${{ inputs.builddir }}
+ if: ${{ steps.cache.outputs.cache-hit }}
+
+ - name: Strip CAPI extensions
+ id: strip
+ shell: bash
+ run: |
+ rm -f spec/ruby/optional/capi/ext/*.c
+ [ "$DLEXT" = bundle ] || # separated to .dSYM directories
+ strip spec/ruby/optional/capi/ext/*.$DLEXT
+ env:
+ DLEXT: ${{ steps.config.outputs.DLEXT }}
+ working-directory: ${{ inputs.builddir }}
+ if: >-
+ ${{true
+ && ! steps.cache.outputs.cache-hit
+ && github.ref_name == 'master'
+ }}
+
+ - name: Save CAPI extensions
+ uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ with:
+ path: ${{ inputs.builddir }}/spec/ruby/optional/capi/ext/
+ key: ${{ steps.config.outputs.key }}
+ if: ${{ steps.strip.outcome == 'success' }}
+
+ - shell: bash
+ run: |
+ echo "::error::Change from ${prev} detected; bump up ABI version"
+ env:
+ prev: ${{ steps.config.outputs.version }}
+ if: ${{ always() && steps.check.outcome == 'failure' }}
diff --git a/.github/actions/compilers/action.yml b/.github/actions/compilers/action.yml
index 30ccd25a12..c700bbfe9e 100644
--- a/.github/actions/compilers/action.yml
+++ b/.github/actions/compilers/action.yml
@@ -5,7 +5,7 @@ description: >-
inputs:
tag:
required: false
- default: clang-18
+ default: clang-20
description: >-
container image tag to use in this run.
@@ -60,11 +60,17 @@ inputs:
description: >-
Whether to run `make check`
- mspecopt:
+ test_all:
required: false
default: ''
description: >-
- Additional options for mspec.
+ Whether to run `make test-all` with options for test-all.
+
+ test_spec:
+ required: false
+ default: ''
+ description: >-
+ Whether to run `make test-spec` with options for mspec.
static_exts:
required: false
@@ -75,7 +81,9 @@ runs:
using: composite
steps:
- shell: bash
- run: docker pull --quiet 'ghcr.io/ruby/ruby-ci-image:${{ inputs.tag }}'
+ run: docker pull --quiet "ghcr.io/ruby/ruby-ci-image:${INPUT_TAG}"
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
- name: Enable Launchable conditionally
id: enable-launchable
@@ -93,27 +101,28 @@ runs:
docker run
--rm
--user=root
- --volume '${{ github.workspace }}:/github/workspace:ro'
+ --volume "${GITHUB_WORKSPACE}:/github/workspace:ro"
--workdir=/github/workspace
--entrypoint=/github/workspace/.github/actions/compilers/entrypoint.sh
--env CI
--env GITHUB_ACTION
- --env INPUT_WITH_GCC='${{ inputs.with_gcc || inputs.tag }}'
- --env INPUT_CFLAGS='${{ inputs.CFLAGS }}'
- --env INPUT_CXXFLAGS='${{ inputs.CXXFLAGS }}'
- --env INPUT_OPTFLAGS='${{ inputs.OPTFLAGS }}'
- --env INPUT_CPPFLAGS='${{ inputs.cppflags }}'
- --env INPUT_APPEND_CONFIGURE='${{ inputs.append_configure }}'
- --env INPUT_CHECK='${{ inputs.check }}'
- --env INPUT_MSPECOPT='${{ inputs.mspecopt }}'
- --env INPUT_ENABLE_SHARED='${{ inputs.enable_shared }}'
- --env INPUT_STATIC_EXTS='${{ inputs.static_exts }}'
- --env LAUNCHABLE_ORGANIZATION='${{ github.repository_owner }}'
- --env LAUNCHABLE_WORKSPACE='${{ github.event.repository.name }}'
- --env LAUNCHABLE_ENABLED='${{ steps.enable-launchable.outputs.enable-launchable || false }}'
- --env GITHUB_PR_HEAD_SHA='${{ github.event.pull_request.head.sha || github.sha }}'
- --env GITHUB_PULL_REQUEST_URL='${{ github.event.pull_request.html_url }}'
- --env GITHUB_REF='${{ github.ref }}'
+ --env INPUT_WITH_GCC
+ --env INPUT_CFLAGS
+ --env INPUT_CXXFLAGS
+ --env INPUT_OPTFLAGS
+ --env INPUT_CPPFLAGS
+ --env INPUT_APPEND_CONFIGURE
+ --env INPUT_CHECK
+ --env INPUT_TEST_ALL
+ --env INPUT_TEST_SPEC
+ --env INPUT_ENABLE_SHARED
+ --env INPUT_STATIC_EXTS
+ --env LAUNCHABLE_ORGANIZATION
+ --env LAUNCHABLE_WORKSPACE
+ --env LAUNCHABLE_ENABLED
+ --env GITHUB_PR_HEAD_SHA
+ --env GITHUB_PULL_REQUEST_URL
+ --env GITHUB_REF
--env GITHUB_ACTIONS
--env GITHUB_RUN_ID
--env GITHUB_REPOSITORY
@@ -123,4 +132,33 @@ runs:
--env GITHUB_SHA
--env GITHUB_HEAD_REF
--env GITHUB_SERVER_URL
- 'ghcr.io/ruby/ruby-ci-image:${{ inputs.tag }}'
+ "ghcr.io/ruby/ruby-ci-image:${INPUT_TAG}"
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
+ INPUT_WITH_GCC: ${{ inputs.with_gcc || inputs.tag }}
+ INPUT_CFLAGS: ${{ inputs.CFLAGS }}
+ INPUT_CXXFLAGS: ${{ inputs.CXXFLAGS }}
+ INPUT_OPTFLAGS: ${{ inputs.OPTFLAGS }}
+ INPUT_CPPFLAGS: ${{ inputs.cppflags }}
+ INPUT_APPEND_CONFIGURE: ${{ inputs.append_configure }}
+ INPUT_CHECK: ${{ inputs.check }}
+ INPUT_TEST_ALL: ${{ inputs.test_all }}
+ INPUT_TEST_SPEC: ${{ inputs.test_spec }}
+ INPUT_ENABLE_SHARED: ${{ inputs.enable_shared }}
+ INPUT_STATIC_EXTS: ${{ inputs.static_exts }}
+ LAUNCHABLE_ORGANIZATION: ${{ github.repository_owner }}
+ LAUNCHABLE_WORKSPACE: ${{ github.event.repository.name }}
+ LAUNCHABLE_ENABLED: ${{ steps.enable-launchable.outputs.enable-launchable || false }}
+ GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
+ GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }}
+ GITHUB_REF: ${{ github.ref }}
+
+ # Clean up non-default docker images to save disk space.
+ # The default image (clang-20) is reused across multiple steps
+ # within the same job, so we keep it to avoid redundant pulls.
+ - name: clean up docker image
+ shell: bash
+ run: docker rmi "ghcr.io/ruby/ruby-ci-image:${INPUT_TAG}" || true
+ if: ${{ always() && inputs.tag != 'clang-20' }}
+ env:
+ INPUT_TAG: ${{ inputs.tag }}
diff --git a/.github/actions/compilers/entrypoint.sh b/.github/actions/compilers/entrypoint.sh
index be10ed9c61..b554151091 100755
--- a/.github/actions/compilers/entrypoint.sh
+++ b/.github/actions/compilers/entrypoint.sh
@@ -26,7 +26,7 @@ export CONFIGURE_TTY='never'
export RUBY_DEBUG='ci rgengc'
export RUBY_TESTOPTS='-q --color=always --tty=no'
export RUBY_DEBUG_COUNTER_DISABLE='1'
-export GNUMAKEFLAGS="-j$((1 + $(nproc --all)))"
+export GNUMAKEFLAGS="-j$((1 + $(nproc)))"
case "x${INPUT_ENABLE_SHARED}" in
x | xno | xfalse )
@@ -47,6 +47,7 @@ grouped ${srcdir}/configure \
--enable-debug-env \
--disable-install-doc \
--with-ext=-test-/cxxanyargs,+ \
+ --without-git \
${enable_shared} \
${INPUT_APPEND_CONFIGURE} \
CFLAGS="${INPUT_CFLAGS}" \
@@ -70,100 +71,20 @@ if [[ -n "${INPUT_STATIC_EXTS}" ]]; then
echo "::endgroup::"
fi
-btests=''
-tests=''
-spec_opts=''
-
-# Launchable
-setup_launchable() {
- pushd ${srcdir}
- # To prevent a slowdown in CI, disable request retries when the Launchable server is unstable.
- export LAUNCHABLE_SKIP_TIMEOUT_RETRY=1
- # Launchable creates .launchable file in the current directory, but cannot a file to ${srcdir} directory.
- # As a workaround, we set LAUNCHABLE_SESSION_DIR to ${builddir}.
- export LAUNCHABLE_SESSION_DIR=${builddir}
- local github_ref="${GITHUB_REF//\//_}"
- local build_name="${github_ref}"_"${GITHUB_PR_HEAD_SHA}"
- btest_report_path='launchable_bootstraptest.json'
- test_report_path='launchable_test_all.json'
- test_spec_report_path='launchable_test_spec_report'
- test_all_session_file='launchable_test_all_session.txt'
- btest_session_file='launchable_btest_session.txt'
- test_spec_session_file='launchable_test_spec_session.txt'
- btests+=--launchable-test-reports="${btest_report_path}"
- echo "::group::Setup Launchable"
- launchable record build --name "${build_name}" || true
- launchable record session \
- --build "${build_name}" \
- --flavor test_task=test \
- --flavor workflow=Compilations \
- --flavor with-gcc="${INPUT_WITH_GCC}" \
- --flavor CFLAGS="${INPUT_CFLAGS}" \
- --flavor CXXFLAGS="${INPUT_CXXFLAGS}" \
- --flavor optflags="${INPUT_OPTFLAGS}" \
- --flavor cppflags="${INPUT_CPPFLAGS}" \
- --test-suite btest \
- > "${builddir}"/${btest_session_file} \
- || true
- if [ "$INPUT_CHECK" = "true" ]; then
- tests+=--launchable-test-reports="${test_report_path}"
- launchable record session \
- --build "${build_name}" \
- --flavor test_task=test-all \
- --flavor workflow=Compilations \
- --flavor with-gcc="${INPUT_WITH_GCC}" \
- --flavor CFLAGS="${INPUT_CFLAGS}" \
- --flavor CXXFLAGS="${INPUT_CXXFLAGS}" \
- --flavor optflags="${INPUT_OPTFLAGS}" \
- --flavor cppflags="${INPUT_CPPFLAGS}" \
- --test-suite test-all \
- > "${builddir}"/${test_all_session_file} \
- || true
- mkdir "${builddir}"/"${test_spec_report_path}"
- spec_opts+=--launchable-test-reports="${test_spec_report_path}"
- launchable record session \
- --build "${build_name}" \
- --flavor test_task=test-spec \
- --flavor workflow=Compilations \
- --flavor with-gcc="${INPUT_WITH_GCC}" \
- --flavor CFLAGS="${INPUT_CFLAGS}" \
- --flavor CXXFLAGS="${INPUT_CXXFLAGS}" \
- --flavor optflags="${INPUT_OPTFLAGS}" \
- --flavor cppflags="${INPUT_CPPFLAGS}" \
- --test-suite test-spec \
- > "${builddir}"/${test_spec_session_file} \
- || true
- fi
- echo "::endgroup::"
- trap launchable_record_test EXIT
-}
-launchable_record_test() {
- pushd "${builddir}"
- grouped launchable record tests --session "$(cat "${btest_session_file}")" raw "${btest_report_path}" || true
- if [ "$INPUT_CHECK" = "true" ]; then
- grouped launchable record tests --session "$(cat "${test_all_session_file}")" raw "${test_report_path}" || true
- grouped launchable record tests --session "$(cat "${test_spec_session_file}")" raw "${test_spec_report_path}"/* || true
- fi
-}
-if [ "$LAUNCHABLE_ENABLED" = "true" ]; then
- setup_launchable
+if [ -n "$INPUT_TEST_ALL" ]; then
+ tests=" -- $INPUT_TEST_ALL"
+else
+ tests=" -- ruby -ext-"
fi
pushd ${builddir}
grouped make showflags
grouped make all
-grouped make test BTESTS="${btests}"
-
-[[ -z "${INPUT_CHECK}" ]] && exit 0
-
-if [ "$INPUT_CHECK" = "true" ]; then
- tests+=" -- ruby -ext-"
-else
- tests+=" -- $INPUT_CHECK"
-fi
-
# grouped make install
-grouped make test-tool
-grouped make test-all TESTS="$tests"
-grouped env CHECK_LEAKS=true make test-spec MSPECOPT="$INPUT_MSPECOPT" SPECOPTS="${spec_opts}"
+
+# Run only `make test` by default. Run other tests if specified.
+grouped make test
+if [[ -n "$INPUT_CHECK" ]]; then grouped make test-tool; fi
+if [[ -n "$INPUT_CHECK" || -n "$INPUT_TEST_ALL" ]]; then grouped make test-all TESTS="$tests"; fi
+if [[ -n "$INPUT_CHECK" || -n "$INPUT_TEST_SPEC" ]]; then grouped env CHECK_LEAKS=true make test-spec MSPECOPT="$INPUT_TEST_SPEC"; fi
diff --git a/.github/actions/launchable/setup/action.yml b/.github/actions/launchable/setup/action.yml
index 8ea8f61414..305878492c 100644
--- a/.github/actions/launchable/setup/action.yml
+++ b/.github/actions/launchable/setup/action.yml
@@ -55,6 +55,23 @@ inputs:
description: >-
Whether this workflow is executed on YJIT.
+ is-zjit:
+ required: false
+ default: 'false'
+ description: >-
+ Whether this workflow is executed on ZJIT.
+
+outputs:
+ stdout_report_path:
+ value: ${{ steps.global.outputs.stdout_report_path }}
+ description: >-
+ Report file path for standard output.
+
+ stderr_report_path:
+ value: ${{ steps.global.outputs.stderr_report_path }}
+ description: >-
+ Report file path for standard error.
+
runs:
using: composite
@@ -78,17 +95,41 @@ runs:
# Launchable CLI requires Python and Java.
# https://www.launchableinc.com/docs/resources/cli-reference/
- name: Set up Python
- uses: actions/setup-python@871daa956ca9ea99f3c3e30acb424b7960676734 # v5.0.0
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.x"
- if: steps.enable-launchable.outputs.enable-launchable
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && !endsWith(inputs.os, 'ppc64le') && !endsWith(inputs.os, 's390x') }}
- name: Set up Java
- uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0
+ uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
distribution: 'temurin'
java-version: '17'
- if: steps.enable-launchable.outputs.enable-launchable
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && !endsWith(inputs.os, 'ppc64le') && !endsWith(inputs.os, 's390x') }}
+
+ - name: Set up Java ppc64le
+ uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
+ with:
+ distribution: 'semeru'
+ architecture: 'ppc64le'
+ java-version: '17'
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && endsWith(inputs.os, 'ppc64le') }}
+
+ - name: Set up Java s390x
+ uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
+ with:
+ distribution: 'semeru'
+ architecture: 's390x'
+ java-version: '17'
+ if: >-
+ ${{ steps.enable-launchable.outputs.enable-launchable
+ && endsWith(inputs.os, 's390x') }}
- name: Set global vars
id: global
@@ -100,29 +141,35 @@ runs:
echo test_all_enabled="${test_all_enabled}" >> $GITHUB_OUTPUT
echo btest_enabled="${btest_enabled}" >> $GITHUB_OUTPUT
echo test_spec_enabled="${test_spec_enabled}" >> $GITHUB_OUTPUT
- echo test_all_session_file='launchable_test_all_session.txt' >> $GITHUB_OUTPUT
- echo btest_session_file='launchable_btest_session.txt' >> $GITHUB_OUTPUT
- echo test_spec_session_file='launchable_test_spec_session.txt' >> $GITHUB_OUTPUT
echo test_all_report_file='launchable_test_all_report.json' >> $GITHUB_OUTPUT
echo btest_report_file='launchable_btest_report.json' >> $GITHUB_OUTPUT
echo test_spec_report_dir='launchable_test_spec_report' >> $GITHUB_OUTPUT
+ echo stdout_report_path="launchable_stdout.log" >> $GITHUB_OUTPUT
+ echo stderr_report_path="launchable_stderr.log" >> $GITHUB_OUTPUT
if: steps.enable-launchable.outputs.enable-launchable
- name: Set environment variables for Launchable
shell: bash
- run: |
+ run: | # zizmor: ignore[github-env]
: # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App.
: # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42
- echo "GITHUB_PULL_REQUEST_URL=${{ github.event.pull_request.html_url }}" >> $GITHUB_ENV
+ echo "GITHUB_PULL_REQUEST_URL=${INPUT_PR_HTML_URL}" >> $GITHUB_ENV
: # The following envs are necessary in Launchable tokenless authentication.
: # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20
- echo "LAUNCHABLE_ORGANIZATION=${{ github.repository_owner }}" >> $GITHUB_ENV
- echo "LAUNCHABLE_WORKSPACE=${{ github.event.repository.name }}" >> $GITHUB_ENV
+ echo "LAUNCHABLE_ORGANIZATION=${INPUT_REPOSITORY_OWNER}" >> $GITHUB_ENV
+ echo "LAUNCHABLE_WORKSPACE=${INPUT_REPOSITORY_NAME}" >> $GITHUB_ENV
: # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71
- echo "GITHUB_PR_HEAD_SHA=${{ github.event.pull_request.head.sha || github.sha }}" >> $GITHUB_ENV
- echo "LAUNCHABLE_TOKEN=${{ inputs.launchable-token }}" >> $GITHUB_ENV
+ echo "GITHUB_PR_HEAD_SHA=${INPUT_PR_HEAD_SHA}" >> $GITHUB_ENV
+ echo "LAUNCHABLE_TOKEN=${INPUT_LAUNCHABLE_TOKEN}" >> $GITHUB_ENV
: # To prevent a slowdown in CI, disable request retries when the Launchable server is unstable.
echo "LAUNCHABLE_SKIP_TIMEOUT_RETRY=1" >> $GITHUB_ENV
+ echo "LAUNCHABLE_COMMIT_TIMEOUT=1" >> $GITHUB_ENV
+ env:
+ INPUT_PR_HTML_URL: ${{ github.event.pull_request.html_url }}
+ INPUT_REPOSITORY_OWNER: ${{ github.repository_owner }}
+ INPUT_REPOSITORY_NAME: ${{ github.event.repository.name }}
+ INPUT_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
+ INPUT_LAUNCHABLE_TOKEN: ${{ inputs.launchable-token }}
if: steps.enable-launchable.outputs.enable-launchable
- name: Set up path
@@ -130,194 +177,161 @@ runs:
working-directory: ${{ inputs.srcdir }}
# Since updated PATH variable will be available in only subsequent actions, we need to add the path beforehand.
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path
- run: echo "$(python -msite --user-base)/bin" >> $GITHUB_PATH
- if: steps.enable-launchable.outputs.enable-launchable && startsWith(inputs.os, 'macos')
+ run: echo "$(python -msite --user-base)/bin" >> $GITHUB_PATH # zizmor: ignore[github-env]
+ if: >-
+ ${{
+ steps.enable-launchable.outputs.enable-launchable
+ && (startsWith(inputs.os, 'macos')
+ || endsWith(inputs.os, 'ppc64le')
+ || endsWith(inputs.os, 's390x'))
+ }}
- name: Set up Launchable
+ id: setup-launchable
shell: bash
working-directory: ${{ inputs.srcdir }}
- run: |
+ run: | # zizmor: ignore[github-env]
set -x
pip install --user launchable
: # The build name cannot include a slash, so we replace the string here.
- github_ref="${{ github.ref }}"
+ github_ref="${INPUT_GITHUB_REF}"
github_ref="${github_ref//\//_}"
: # With the --name option, we need to configure a unique identifier for this build.
: # To avoid setting the same build name as the CI which runs on other branches, we use the branch name here.
build_name="${github_ref}_${GITHUB_PR_HEAD_SHA}"
- test_opts="${{ inputs.test-opts }}"
+ test_opts="${INPUT_TEST_OPTS}"
test_opts="${test_opts// /}"
test_opts="${test_opts//=/:}"
test_all_test_suite='test-all'
btest_test_suite='btest'
test_spec_test_suite='test-spec'
- if [ "${{ inputs.is-yjit }}" = "true" ]; then
+ if [ "${INPUT_IS_YJIT}" = "true" ]; then
test_all_test_suite="yjit-${test_all_test_suite}"
btest_test_suite="yjit-${btest_test_suite}"
test_spec_test_suite="yjit-${test_spec_test_suite}"
fi
- launchable record build --name "${build_name}"
- if [ "${test_all_enabled}" = "true" ]; then
- launchable record session \
- --build "${build_name}" \
- --observation \
- --flavor os="${{ inputs.os }}" \
- --flavor test_task="${{ inputs.test-task }}" \
- --flavor test_opts="${test_opts}" \
- --flavor workflow="${{ github.workflow }}" \
- --test-suite ${test_all_test_suite} \
- > "${test_all_session_file}"
- launchable subset \
- --get-tests-from-previous-sessions \
- --non-blocking \
- --target 90% \
- --session "$(cat "${test_all_session_file}")" \
- raw > /dev/null
- echo "TESTS=${TESTS} --launchable-test-reports=${test_all_report_file}" >> $GITHUB_ENV
+ if [ "${INPUT_IS_ZJIT}" = "true" ]; then
+ test_all_test_suite="zjit-${test_all_test_suite}"
+ btest_test_suite="zjit-${btest_test_suite}"
+ test_spec_test_suite="zjit-${test_spec_test_suite}"
fi
- if [ "${btest_enabled}" = "true" ]; then
- launchable record session \
+ # launchable_setup target var -- refers ${target} prefixed variables
+ launchable_setup() {
+ local target=$1 session
+ eval [ "\${${target}_enabled}" = "true" ] || return
+ eval local suite=\${${target}_test_suite}
+ session=$(launchable record session \
--build "${build_name}" \
--observation \
- --flavor os="${{ inputs.os }}" \
- --flavor test_task="${{ inputs.test-task }}" \
+ --flavor os="${INPUT_OS}" \
+ --flavor test_task="${INPUT_TEST_TASK}" \
--flavor test_opts="${test_opts}" \
- --flavor workflow="${{ github.workflow }}" \
- --test-suite ${btest_test_suite} \
- > "${btest_session_file}"
- launchable subset \
- --get-tests-from-previous-sessions \
- --non-blocking \
- --target 90% \
- --session "$(cat "${btest_session_file}")" \
- raw > /dev/null
- echo "BTESTS=${BTESTS} --launchable-test-reports=${btest_report_file}" >> $GITHUB_ENV
+ --flavor workflow="${INPUT_WORKFLOW}" \
+ --test-suite ${suite} \
+ )
+ echo "${target}_session=${session}" >> $GITHUB_OUTPUT
+ }
+
+ launchable record build --name "${build_name}"
+ if launchable_setup test_all; then
+ echo "TESTS=${TESTS:+$TESTS }--launchable-test-reports=${test_all_report_file}" >> $GITHUB_ENV
fi
- if [ "${test_spec_enabled}" = "true" ]; then
- launchable record session \
- --build "${build_name}" \
- --observation \
- --flavor os="${{ inputs.os }}" \
- --flavor test_task="${{ inputs.test-task }}" \
- --flavor test_opts="${test_opts}" \
- --flavor workflow="${{ github.workflow }}" \
- --test-suite ${test_spec_test_suite} \
- > "${test_spec_session_file}"
- launchable subset \
- --get-tests-from-previous-sessions \
- --non-blocking \
- --target 90% \
- --session "$(cat "${test_spec_session_file}")" \
- raw > /dev/null
- echo "SPECOPTS=${SPECOPTS} --launchable-test-reports=${test_spec_report_dir}" >> $GITHUB_ENV
+ if launchable_setup btest; then
+ echo "BTESTS=${BTESTS:+$BTESTS }--launchable-test-reports=${btest_report_file}" >> $GITHUB_ENV
fi
+ if launchable_setup test_spec; then
+ echo "SPECOPTS=${SPECOPTS:$SPECOPTS }--launchable-test-reports=${test_spec_report_dir}" >> $GITHUB_ENV
+ echo test_spec_enabled=true >> $GITHUB_OUTPUT
+ fi
+
+ echo launchable_setup_dir=$(pwd) >> $GITHUB_OUTPUT
if: steps.enable-launchable.outputs.enable-launchable
env:
+ INPUT_GITHUB_REF: ${{ github.ref }}
+ INPUT_TEST_OPTS: ${{ inputs.test-opts }}
+ INPUT_IS_YJIT: ${{ inputs.is-yjit }}
+ INPUT_IS_ZJIT: ${{ inputs.is-zjit }}
+ INPUT_OS: ${{ inputs.os }}
+ INPUT_TEST_TASK: ${{ inputs.test-task }}
+ INPUT_WORKFLOW: ${{ github.workflow }}
test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
btest_enabled: ${{ steps.global.outputs.btest_enabled }}
test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
- test_all_session_file: ${{ steps.global.outputs.test_all_session_file }}
- btest_session_file: ${{ steps.global.outputs.btest_session_file }}
- test_spec_session_file: ${{ steps.global.outputs.test_spec_session_file }}
test_all_report_file: ${{ steps.global.outputs.test_all_report_file }}
btest_report_file: ${{ steps.global.outputs.btest_report_file }}
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
- - name: Variables to report Launchable
- id: variables
+ - name: make test-spec report directory in build directory
shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: |
- set -x
- : # report-path from srcdir
- if [ "${srcdir}" = "${{ github.workspace }}" ]; then
- dir=
- else
- # srcdir must be equal to or under workspace
- dir=$(echo ${srcdir:+${srcdir}/} | sed 's:[^/][^/]*/:../:g')
- fi
- if [ "${test_all_enabled}" = "true" ]; then
- test_report_path="${dir}${builddir:+${builddir}/}${test_all_report_file}"
- echo test_report_path="${test_report_path}" >> $GITHUB_OUTPUT
- fi
- if [ "${btest_enabled}" = "true" ]; then
- btest_report_path="${dir}${builddir:+${builddir}/}${btest_report_file}"
- echo btest_report_path="${btest_report_path}" >> $GITHUB_OUTPUT
- fi
- if [ "${test_spec_enabled}" = "true" ]; then
- test_spec_report_path="${dir}${builddir:+${builddir}/}${test_spec_report_dir}"
- mkdir "${test_spec_report_path}"
- echo test_spec_report_path="${test_spec_report_path}" >> $GITHUB_OUTPUT
- fi
- stdout_report_path="${dir}${builddir:+${builddir}/}launchable_stdout.log"
- stderr_report_path="${dir}${builddir:+${builddir}/}launchable_stderr.log"
- echo stdout_report_path="${stdout_report_path}" >> $GITHUB_OUTPUT
- echo stderr_report_path="${stderr_report_path}" >> $GITHUB_OUTPUT
- if: steps.enable-launchable.outputs.enable-launchable
+ working-directory: ${{ inputs.builddir }}
+ run: mkdir "${test_spec_report_dir}"
+ if: ${{ steps.setup-launchable.outputs.test_spec_enabled == 'true' }}
+ env:
+ test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
+
+ - name: Clean up test results in Launchable
+ uses: gacts/run-and-post-run@81b6ce503cde93862cec047c54652e45c5dca991 # v1.4.3
+ with:
+ shell: bash
+ working-directory: ${{ inputs.builddir }}
+ post: |
+ rm -f "${test_all_report_file}"
+ rm -f "${btest_report_file}"
+ rm -fr "${test_spec_report_dir}"
+ rm -f launchable_stdout.log
+ rm -f launchable_stderr.log
+ if: always() && steps.setup-launchable.outcome == 'success'
env:
- srcdir: ${{ inputs.srcdir }}
- builddir: ${{ inputs.builddir }}
- test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
- btest_enabled: ${{ steps.global.outputs.btest_enabled }}
- test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
test_all_report_file: ${{ steps.global.outputs.test_all_report_file }}
btest_report_file: ${{ steps.global.outputs.btest_report_file }}
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
- name: Record test results in Launchable
- uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0
+ uses: gacts/run-and-post-run@81b6ce503cde93862cec047c54652e45c5dca991 # v1.4.3
with:
shell: bash
- working-directory: ${{ inputs.srcdir }}
+ working-directory: ${{ inputs.builddir }}
post: |
if [[ "${test_all_enabled}" = "true" ]]; then \
launchable record attachment \
- --session "$(cat "${test_all_session_file}")" \
+ --session "${test_all_session}" \
"${stdout_report_path}" \
"${stderr_report_path}"; \
launchable record tests \
- --session "$(cat "${test_all_session_file}")" \
- raw "${test_report_path}" || true; \
+ --session "${test_all_session}" \
+ raw "${test_all_report_file}" || true; \
fi
if [[ "${btest_enabled}" = "true" ]]; then \
launchable record attachment \
- --session "$(cat "${btest_session_file}")" \
+ --session "${btest_session}" \
"${stdout_report_path}" \
"${stderr_report_path}"; \
launchable record tests \
- --session "$(cat "${btest_session_file}")" \
- raw "${btest_report_path}" || true; \
+ --session "${btest_session}" \
+ raw "${btest_report_file}" || true; \
fi
if [[ "${test_spec_enabled}" = "true" ]]; then \
launchable record attachment \
- --session "$(cat "${test_spec_session_file}")" \
+ --session "${test_spec_session}" \
"${stdout_report_path}" \
"${stderr_report_path}"; \
launchable record tests \
- --session "$(cat "${test_spec_session_file}")" \
- raw ${test_spec_report_path}/* || true; \
+ --session "${test_spec_session}" \
+ raw ${test_spec_report_dir}/* || true; \
fi
-
- rm -f "${test_all_session_file}"
- rm -f "${btest_session_file}"
- rm -f "${test_spec_session_file}"
- rm -f "${test_report_path}"
- rm -f "${btest_report_path}"
- rm -fr "${test_spec_report_path}"
- rm -f "${stdout_report_path}"
- rm -f "${stderr_report_path}"
- if: ${{ always() && steps.enable-launchable.outputs.enable-launchable }}
+ if: ${{ always() && steps.setup-launchable.outcome == 'success' }}
env:
- test_report_path: ${{ steps.variables.outputs.test_report_path }}
- btest_report_path: ${{ steps.variables.outputs.btest_report_path }}
- test_spec_report_path: ${{ steps.variables.outputs.test_spec_report_path }}
+ test_all_report_file: ${{ steps.global.outputs.test_all_report_file }}
+ btest_report_file: ${{ steps.global.outputs.btest_report_file }}
+ test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
btest_enabled: ${{ steps.global.outputs.btest_enabled }}
test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
- test_all_session_file: ${{ steps.global.outputs.test_all_session_file }}
- btest_session_file: ${{ steps.global.outputs.btest_session_file }}
- test_spec_session_file: ${{ steps.global.outputs.test_spec_session_file }}
- stdout_report_path: ${{ steps.variables.outputs.stdout_report_path }}
- stderr_report_path: ${{ steps.variables.outputs.stderr_report_path }}
+ test_all_session: ${{ steps.setup-launchable.outputs.test_all_session }}
+ btest_session: ${{ steps.setup-launchable.outputs.btest_session }}
+ test_spec_session: ${{ steps.setup-launchable.outputs.test_spec_session }}
+ stdout_report_path: ${{ steps.global.outputs.stdout_report_path }}
+ stderr_report_path: ${{ steps.global.outputs.stderr_report_path }}
+ LAUNCHABLE_SETUP_DIR: ${{ steps.setup-launchable.outputs.launchable_setup_dir }}
diff --git a/.github/actions/make-snapshot/action.yml b/.github/actions/make-snapshot/action.yml
new file mode 100644
index 0000000000..4552f0e067
--- /dev/null
+++ b/.github/actions/make-snapshot/action.yml
@@ -0,0 +1,77 @@
+name: 'make-snapshot'
+description: 'Make snapshot tarballs'
+inputs:
+ archname:
+ description: 'archname passed to tool/make-snapshot (e.g. snapshot-master)'
+ required: true
+ version:
+ description: 'Target Version'
+ required: false
+ shallow-since:
+ description: 'git fetch --shallow-since'
+ required: true
+ default: '2018-12-25 00:00:00'
+ fetch-branch:
+ description: 'fetch branch'
+ required: false
+ srcdir:
+ description: 'srcdir for tool/make-snapshot. Empty = clone ruby/ruby into ./ruby.'
+ required: false
+ default: ''
+ upload-artifact:
+ description: 'Upload Packages and Info as workflow artifacts. Pass "false" when callers run in a matrix that would collide on artifact names.'
+ required: false
+ default: 'true'
+
+runs:
+ using: "composite"
+ steps:
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential git bison autoconf ruby p7zip-full curl
+ shell: bash
+ - name: Checkout ruby/ruby for tool/make-snapshot
+ if: inputs.srcdir == ''
+ run: git clone --single-branch --depth=1 https://github.com/ruby/ruby ruby
+ shell: bash
+ - name: Fetch branches and notes (clone mode)
+ if: inputs.srcdir == ''
+ env:
+ SHALLOW_SINCE: ${{ inputs.shallow-since }}
+ FETCH_BRANCH: ${{ inputs.fetch-branch }}
+ run: |
+ set -x
+ cd ruby
+ git fetch --shallow-since="$SHALLOW_SINCE"
+ [ -n "$FETCH_BRANCH" ] && git fetch origin "+$FETCH_BRANCH:$FETCH_BRANCH"
+ git fetch origin '+refs/notes/commits:refs/notes/commits'
+ git fetch origin '+refs/notes/log-fix:refs/notes/log-fix'
+ shell: bash
+ - name: Fetch notes (local srcdir mode)
+ if: inputs.srcdir != ''
+ working-directory: ${{ inputs.srcdir }}
+ run: |
+ git fetch origin '+refs/notes/commits:refs/notes/commits' || :
+ git fetch origin '+refs/notes/log-fix:refs/notes/log-fix' || :
+ shell: bash
+ - name: Make snapshot
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ SRCDIR: ${{ inputs.srcdir }}
+ VERSION: ${{ inputs.version }}
+ run: |
+ [ -z "$SRCDIR" ] && SRCDIR=ruby
+ ruby "$SRCDIR/tool/make-snapshot" "-archname=$ARCHNAME" -srcdir="$SRCDIR" -packages=gzip,xz,zip pkg $VERSION
+ shell: bash
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: Packages
+ path: pkg
+ if: ${{ inputs.upload-artifact == 'true' }}
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: Info
+ path: pkg/info
+ if: ${{ inputs.upload-artifact == 'true' }}
diff --git a/.github/actions/setup/baseruby/action.yml b/.github/actions/setup/baseruby/action.yml
new file mode 100644
index 0000000000..76fe068897
--- /dev/null
+++ b/.github/actions/setup/baseruby/action.yml
@@ -0,0 +1,73 @@
+name: Setup directories etc.
+description: >-
+ Build baseruby for cross-compiling
+
+inputs:
+ srcdir:
+ required: true
+ default: ${{ github.workspace }}
+ description: >-
+ Directory of source codes.
+
+ builddir:
+ required: false
+ default: ${{ github.workspace }}/baseruby
+ description: >-
+ Where baseruby will be built.
+
+ installdir:
+ required: false
+ default: install
+ description: >-
+ The path where the baseruby will be installed to.
+ This is relative from the workspace.
+
+outputs:
+ ruby:
+ value: ${{ steps.build.outputs.installdir }}/bin/ruby
+ description: >-
+ The path of the executable baseruby.
+ dump_ast:
+ value: ${{ steps.build.outputs.installdir }}/bin/dump_ast
+ description: >-
+ The path of the executable dump_ast.
+
+runs:
+ using: composite
+
+ steps:
+ - name: Build baseruby
+ shell: bash
+ id: build
+ run: |
+ case "$installdir" in /*) ;; *) installdir="$PWD/$installdir";; esac
+ mkdir "$builddir"
+ ln -sr "$srcdir" "$builddir/.src"
+ pushd "$builddir"
+ .src/configure "--prefix=${installdir}" --disable-install-doc
+ CONFIGURE_ARGS=--with-out-ext=-test- make install
+ install dump_ast "${installdir}/bin"
+ {
+ echo "${installdir}/bin/dump_ast"
+ echo "${installdir}/.installed.list"
+ echo "${installdir}/"
+ } >> .installed.list
+ cp .installed.list "${installdir}/"
+ make distclean
+ rm .src
+ popd
+ rmdir "$builddir"
+ {
+ echo "installdir=${installdir}"
+ } | tee -a "$GITHUB_OUTPUT"
+ env:
+ srcdir: ${{ inputs.srcdir }}
+ builddir: ${{ inputs.builddir }}
+ installdir: ${{ inputs.installdir }}
+
+ - name: clean
+ uses: gacts/run-and-post-run@598d7a875d5620e0457490555b5e18e46082aa47 # v1.4.4
+ with:
+ working-directory: ${{ inputs.srcdir }}
+ post: |
+ ruby tool/rbuninstall.rb "${{ steps.build.outputs.installdir }}/.installed.list" > /dev/null
diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml
index 48e2c64a96..589049a4b8 100644
--- a/.github/actions/setup/directories/action.yml
+++ b/.github/actions/setup/directories/action.yml
@@ -19,6 +19,13 @@ inputs:
Where binaries and other generated contents go. This will be
created if absent.
+ make-command:
+ required: false
+ type: string
+ default: 'make'
+ description: >-
+ The command of `make`.
+
makeup:
required: false
type: boolean
@@ -67,8 +74,11 @@ runs:
# their bash manually installed.
- shell: bash
run: |
- mkdir -p ${{ inputs.srcdir }}
- mkdir -p ${{ inputs.builddir }}
+ mkdir -p "${INPUT_SRCDIR}"
+ mkdir -p "${INPUT_BUILDDIR}"
+ env:
+ INPUT_SRCDIR: ${{ inputs.srcdir }}
+ INPUT_BUILDDIR: ${{ inputs.builddir }}
# Did you know that actions/checkout works without git(1)? We are
# checking that here.
@@ -76,7 +86,7 @@ runs:
shell: bash
run: |
echo "git=`command -v git`" >> "$GITHUB_OUTPUT"
- echo "sudo=`command -v sudo`" >> "$GITHUB_OUTPUT"
+ echo "sudo=`sudo true && command -v sudo`" >> "$GITHUB_OUTPUT"
echo "autoreconf=`command -v autoreconf`" >> "$GITHUB_OUTPUT"
- if: steps.which.outputs.git
@@ -88,15 +98,16 @@ runs:
git config --global init.defaultBranch garbage
- if: inputs.checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: ${{ inputs.srcdir }}
fetch-depth: ${{ inputs.fetch-depth }}
+ persist-credentials: false
- - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ inputs.srcdir }}/.downloaded-cache
- key: downloaded-cache
+ key: ${{ runner.os }}-${{ runner.arch }}-downloaded-cache
- if: steps.which.outputs.autoreconf
shell: bash
@@ -106,16 +117,16 @@ runs:
# This is for MinGW.
- if: runner.os == 'Windows'
shell: bash
- run: echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
+ run: echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV # zizmor: ignore[github-env]
- if: runner.os == 'Linux'
shell: bash
- run: echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> "$GITHUB_ENV"
+ run: echo "GNUMAKEFLAGS=-sj$((1 + $(nproc)))" >> "$GITHUB_ENV" # zizmor: ignore[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"
+ run: echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> "$GITHUB_ENV" # zizmor: ignore[github-env]
- if: inputs.makeup
shell: bash
@@ -134,6 +145,7 @@ runs:
run: |
rm -f config.status .rbconfig.time \
Makefile GNUmakefile uncommon.mk enc.mk noarch-fake.rb
+ rm -f prism/.time prism/util/.time
- if: steps.which.outputs.sudo
shell: bash
@@ -163,19 +175,25 @@ runs:
done
# drop {a..z}.rb if case-insensitive filesystem
grep -F A.rb a.rb > /dev/null && set "${@:27}"
- echo clean="cd ${{ inputs.builddir }} && rm $*" >> $GITHUB_OUTPUT
+ echo clean="cd ${INPUT_BUILDDIR} && rm $*" >> $GITHUB_OUTPUT
+ env:
+ INPUT_BUILDDIR: ${{ inputs.builddir }}
- if: inputs.clean == 'true'
shell: bash
id: clean
run: |
- echo distclean='make -C ${{ inputs.builddir }} distclean' >> $GITHUB_OUTPUT
- echo remained-files='find ${{ inputs.builddir }} -ls' >> $GITHUB_OUTPUT
- [ "${{ inputs.builddir }}" = "${{ inputs.srcdir }}" ] ||
- echo final='rmdir ${{ inputs.builddir }}' >> $GITHUB_OUTPUT
+ echo distclean="cd ${INPUT_BUILDDIR} && ${INPUT_MAKE_COMMAND} distclean" >> $GITHUB_OUTPUT
+ echo remained-files="find ${INPUT_BUILDDIR} -ls" >> $GITHUB_OUTPUT
+ [ "${INPUT_BUILDDIR}" = "${INPUT_SRCDIR}" ] ||
+ echo final="rmdir ${INPUT_BUILDDIR}" >> $GITHUB_OUTPUT
+ env:
+ INPUT_BUILDDIR: ${{ inputs.builddir }}
+ INPUT_SRCDIR: ${{ inputs.srcdir }}
+ INPUT_MAKE_COMMAND: ${{ inputs.make-command }}
- name: clean
- uses: gacts/run-and-post-run@d803f6920adc9a47eeac4cb6c93dbc2e2890c684 # v1.4.2
+ uses: gacts/run-and-post-run@598d7a875d5620e0457490555b5e18e46082aa47 # v1.4.4
with:
working-directory:
post: |
@@ -183,3 +201,5 @@ runs:
${{ steps.clean.outputs.distclean }}
${{ steps.clean.outputs.remained-files }}
${{ steps.clean.outputs.final }}
+ # rmdir randomly fails due to launchable files
+ continue-on-error: true
diff --git a/.github/actions/setup/macos/action.yml b/.github/actions/setup/macos/action.yml
index 5da7c6d44c..9cd37a9b12 100644
--- a/.github/actions/setup/macos/action.yml
+++ b/.github/actions/setup/macos/action.yml
@@ -17,11 +17,11 @@ runs:
- name: Set ENV
shell: bash
- run: |
+ run: | # zizmor: ignore[github-env]
dir_config() {
local args=() lib var="$1"; shift
for lib in "$@"; do
- args+="--with-${lib%@*}-dir=$(brew --prefix $lib)"
+ args+=("--with-${lib%@*}-dir=$(brew --prefix $lib)")
done
echo "$var=${args[*]}" >> $GITHUB_ENV
}
diff --git a/.github/actions/setup/ubuntu/action.yml b/.github/actions/setup/ubuntu/action.yml
index a9e5b41951..5209ccc03f 100644
--- a/.github/actions/setup/ubuntu/action.yml
+++ b/.github/actions/setup/ubuntu/action.yml
@@ -24,18 +24,38 @@ runs:
using: composite
steps:
+ - id: uname
+ name: uname
+ shell: bash
+ env:
+ arch: ${{ inputs.arch }}
+ run: |
+ setarch="${arch:+setarch $arch --}"
+ # normalize `uname`
+ if uname=$(${setarch} uname -m 2> /dev/null); then
+ # `setarch` works, `$arch` is a valid architecture name.
+ echo "setarch=${setarch}" >> "$GITHUB_OUTPUT"
+ else
+ # if `setarch` failed, take the given `arch` as-is.
+ uname="${arch}"
+ setarch=""
+ fi
+ echo "uname=$uname" >> "$GITHUB_OUTPUT"
+ echo "dpkg=${uname/686/386}" >> "$GITHUB_OUTPUT"
+
- name: set SETARCH
shell: bash
- run: echo "SETARCH=${setarch}" >> "$GITHUB_ENV"
+ run: echo "SETARCH=${setarch}" >> "$GITHUB_ENV" # zizmor: ignore[github-env]
env:
- setarch: ${{ inputs.arch && format('setarch {0} --', inputs.arch) }}
+ setarch: ${{ steps.uname.outputs.setarch }} # validated
- - id: uname
- name: uname
+ - name: dpkg setup
shell: bash
- run: |
- echo uname=`${SETARCH} uname -m` >> "$GITHUB_OUTPUT"
- echo dpkg=`${SETARCH} uname -m | sed s/686/386/` >> "$GITHUB_OUTPUT"
+ run: sudo dpkg --add-architecture "${dpkg}"
+ # `dpkg` is valid, also `uname`.
+ if: ${{ inputs.arch }}
+ env:
+ dpkg: ${{ steps.uname.outputs.dpkg }}
- name: apt-get
shell: bash
@@ -43,7 +63,6 @@ runs:
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/:/-} \
diff --git a/.github/actions/slack/action.yml b/.github/actions/slack/action.yml
index 98171efc5e..6f89bef11a 100644
--- a/.github/actions/slack/action.yml
+++ b/.github/actions/slack/action.yml
@@ -18,13 +18,24 @@ inputs:
Human-readable description of the run, something like "DEBUG=1".
This need not be unique among runs.
+ event_name:
+ required: false
+ default: 'push'
+ description: >-
+ Target event to trigger notification. Notify only push by default.
+
+ extra_channel_id:
+ required: false
+ description: >-
+ Slack channel ID to notify besides #alerts and #alerts-emoji.
+
outputs: {} # Nothing?
runs:
using: composite
steps:
- - uses: ruby/action-slack@54175162371f1f7c8eb94d7c8644ee2479fcd375 # v3.2.2
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
with:
payload: |
{
@@ -33,7 +44,8 @@ runs:
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"commit": "${{ github.sha }}",
"branch": "${{ github.ref_name }}"
+ ${{ inputs.extra_channel_id && format(', "extra_channel_id": "{0}"', inputs.extra_channel_id) }}
}
env:
SLACK_WEBHOOK_URL: ${{ inputs.SLACK_WEBHOOK_URL }}
- if: ${{github.event_name == 'push' && startsWith(github.repository, 'ruby/')}}
+ if: ${{ github.event_name == inputs.event_name && startsWith(github.repository, 'ruby/') }}
diff --git a/.github/auto_request_review.yml b/.github/auto_request_review.yml
index 8726df577d..9e20cb7459 100644
--- a/.github/auto_request_review.yml
+++ b/.github/auto_request_review.yml
@@ -1,13 +1,21 @@
files:
- 'yjit*': [team:yjit]
- 'yjit/**/*': [team:yjit]
+ 'yjit*': [team:jit]
+ 'yjit/**/*': [team:jit]
'yjit/src/cruby_bindings.inc.rs': []
- 'doc/yjit/*': [team:yjit]
- 'bootstraptest/test_yjit*': [team:yjit]
- 'test/ruby/test_yjit*': [team:yjit]
+ 'bootstraptest/test_yjit*': [team:jit]
+ 'test/ruby/test_yjit*': [team:jit]
+ 'zjit*': [team:jit]
+ 'zjit/**/*': [team:jit]
+ 'zjit/src/cruby_bindings.inc.rs': []
+ 'test/ruby/test_zjit*': [team:jit]
+ 'defs/jit.mk': [team:jit]
+ 'tool/zjit_bisect.rb': [team:jit]
+ 'doc/jit/*': [team:jit]
+ # Skip files updated by dependabot. It's noisy in notifications, and they're auto-merged anyway.
+ 'yjit/Cargo.lock': []
+ 'zjit/Cargo.lock': []
+ '.github/workflows/yjit-*.yml': []
+ '.github/workflows/zjit-*.yml': []
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
+ 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..f5d33545c1
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,22 @@
+paths-ignore:
+ - benchmark
+ - sample
+ - spec/ruby/command_line/fixtures
+ - spec/ruby/core/enumerable/shared/inject.rb
+ - spec/ruby/core/exception/fixtures
+ - spec/ruby/core/proc/parameters_spec.rb
+ - spec/ruby/core/proc/ruby2_keywords_spec.rb
+ - spec/ruby/core/range/reverse_each_spec.rb
+ - spec/ruby/language/fixtures
+ - spec/ruby/language/lambda_spec.rb
+ - spec/ruby/language/method_spec.rb
+ - spec/ruby/language/string_spec.rb
+ - test/error_highlight/test_error_highlight.rb
+ - test/prism/result/named_capture_test.rb
+ - test/ruby/test_call.rb
+ - test/ruby/test_signal.rb
+ - test/ruby/test_super.rb
+ - test/ruby/test_syntax.rb
+ - test/ruby/test_unicode_escape.rb
+ - test/rubygems/specifications/foo-0.0.1-x86-mswin32.gemspec
+ - trace_point.rb
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 426893be2a..57da742e5c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,18 +1,29 @@
version: 2
updates:
- package-ecosystem: 'github-actions'
- directory: '/'
- schedule:
- interval: 'daily'
- - package-ecosystem: 'github-actions'
- directory: '/.github/actions/slack'
- schedule:
- interval: 'daily'
- - package-ecosystem: 'github-actions'
- directory: '/.github/actions/setup/directories'
+ directories:
+ - '/'
+ - '/.github/actions/slack'
+ - '/.github/actions/setup/directories'
schedule:
interval: 'daily'
+ groups:
+ github-actions:
+ patterns:
+ - "*"
- package-ecosystem: 'cargo'
- directory: '/yjit'
+ directories:
+ - '/yjit'
+ - '/zjit'
+ exclude-paths:
+ - 'gc/mmtk/**'
+ schedule:
+ interval: 'monthly'
+ groups:
+ jit:
+ patterns:
+ - "*"
+ - package-ecosystem: 'vcpkg'
+ directory: '/'
schedule:
interval: 'daily'
diff --git a/.github/labeler.yml b/.github/labeler.yml
index e81aed8e98..f39fcec386 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -4,3 +4,4 @@ Documentation:
Backport:
- base-branch: 'ruby_3_\d'
+- base-branch: 'ruby_4_\d'
diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml
index 8cc482c428..1d23c38fcd 100644
--- a/.github/workflows/annocheck.yml
+++ b/.github/workflows/annocheck.yml
@@ -39,11 +39,9 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
env:
@@ -63,10 +61,11 @@ jobs:
- run: id
working-directory:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/directories
with:
@@ -74,9 +73,9 @@ jobs:
builddir: build
makeup: true
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- ruby-version: '3.0'
+ ruby-version: '3.1'
bundler: none
# Minimal flags to pass the check.
diff --git a/.github/workflows/auto_request_review.yml b/.github/workflows/auto_request_review.yml
index a6c81c78cd..1be2b11b86 100644
--- a/.github/workflows/auto_request_review.yml
+++ b/.github/workflows/auto_request_review.yml
@@ -14,7 +14,7 @@ jobs:
if: ${{ github.repository == 'ruby/ruby' && github.base_ref == 'master' }}
steps:
- name: Request review based on files changes and/or groups the author belongs to
- uses: necojackarc/auto-request-review@e89da1a8cd7c8c16d9de9c6e763290b6b0e3d424 # v0.13.0
+ uses: necojackarc/auto-request-review@5d3060495e58e9cb41f51de50e808d3135d5374e # master
with:
# scope: public_repo
- token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
+ token: ${{ secrets.MATZBOT_AUTO_REQUEST_REVIEW_TOKEN }}
diff --git a/.github/workflows/auto_review_pr.yml b/.github/workflows/auto_review_pr.yml
new file mode 100644
index 0000000000..24859ad0b0
--- /dev/null
+++ b/.github/workflows/auto_review_pr.yml
@@ -0,0 +1,41 @@
+name: Auto Review PR
+on:
+ pull_request_target:
+ types: [opened, ready_for_review, reopened]
+ branches: [master]
+ workflow_dispatch:
+ inputs:
+ pr_number:
+ description: 'PR number to review'
+ required: true
+ type: number
+
+permissions:
+ contents: read
+
+jobs:
+ auto-review-pr:
+ name: Auto Review PR
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'ruby/ruby' && (github.base_ref == 'master' || github.event_name == 'workflow_dispatch') }}
+
+ permissions:
+ pull-requests: write
+ contents: read
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.4'
+ bundler: none
+
+ - name: Auto Review PR
+ run: ruby tool/auto_review_pr.rb "$GITHUB_PR_NUMBER"
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index 94560551a0..1acfbe19ac 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -35,28 +35,27 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
strategy:
matrix:
ruby:
- - ruby-3.0
- ruby-3.1
- ruby-3.2
- ruby-3.3
steps:
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml
index da2c7028c2..d890ed2495 100644
--- a/.github/workflows/bundled_gems.yml
+++ b/.github/workflows/bundled_gems.yml
@@ -1,5 +1,8 @@
name: bundled_gems
+env:
+ UPDATE_ENABLED: true
+
on:
push:
branches: ['master']
@@ -31,13 +34,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # zizmor: ignore[artipacked]
+ with:
+ token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ ruby-version: 4.0
- uses: ./.github/actions/setup/directories
with:
- # Skip overwriting MATZBOT_GITHUB_TOKEN
+ # Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
- name: Set ENV
@@ -49,24 +56,20 @@ jobs:
mkdir -p .downloaded-cache
for data in bundled_gems.json default_gems.json; do
ln -s .downloaded-cache/$data .
- curl -O -R -z ./$data https://stdgems.org/$data
+ curl --retry 5 --retry-connrefused --retry-delay 2 --retry-max-time 60 -O -R -z ./$data https://stdgems.org/$data
done
- name: Update bundled gems list
id: bundled_gems
run: |
ruby -i~ tool/update-bundled_gems.rb gems/bundled_gems >> $GITHUB_OUTPUT
-
- - name: Update spec/bundler/support/builders.rb
- run: |
- #!ruby
- rake_version = File.read("gems/bundled_gems")[/^rake\s+(\S+)/, 1]
- print ARGF.read.sub(/^ *def rake_version\s*\K".*?"/) {rake_version.dump}
- shell: ruby -i~ {0} spec/bundler/support/builders.rb
+ if: ${{ env.UPDATE_ENABLED == 'true' }}
- name: Maintain updated gems list in NEWS
run: |
ruby tool/update-NEWS-gemlist.rb bundled
+ ruby tool/update-NEWS-github-release.rb --update
+ if: ${{ env.UPDATE_ENABLED == 'true' }}
- name: Check diffs
id: diff
@@ -77,11 +80,71 @@ jobs:
git diff --color --no-ext-diff --ignore-submodules --exit-code -- gems/bundled_gems ||
gems=true
git add -- NEWS.md gems/bundled_gems
- git add -- spec/bundler/support/builders.rb
echo news=$news >> $GITHUB_OUTPUT
echo gems=$gems >> $GITHUB_OUTPUT
echo update=${news:-$gems} >> $GITHUB_OUTPUT
+ - name: Commit
+ id: commit
+ run: |
+ git pull --ff-only origin ${GITHUB_REF#refs/heads/}
+ message="Update bundled gems list"
+ if [ -z "${gems}" ]; then
+ git commit --message="[DOC] ${message} at ${GITHUB_SHA:0:30}"
+ else
+ git commit --message="${message} as of ${TODAY}"
+ fi
+ 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: ${{ steps.diff.outputs.update }}
+
+ - name: Development revision of bundled gems
+ run: |
+ #!ruby
+ file = "gems/bundled_gems"
+
+ SECONDS_IN_DAY = 86400
+ today = Time.new("#{ENV['TODAY']}Z")
+ if !(december = today.month == 12)
+ days = 30
+ elsif (days = 26 - today.day).positive?
+ days += 4
+ else
+ puts "::info:: just after released"
+ exit
+ end
+
+ since = "#{today.year-1}-12-26"
+ ref = ENV['GITHUB_REF']
+ puts "::group::\e[94mfetching \e[1m#{file}\e[22m since \e[1m#{since}\e[22m from \e[1m#{ref}\e[m"
+ system(*%W[git fetch --shallow-since=#{since} --no-tags origin #{ref}], exception: true)
+ puts "::endgroup::"
+
+ puts "\e[94mchecking development version bundled gems older than \e[1m#{days}\e[22m days\e[m"
+ limit = today.to_i - days * SECONDS_IN_DAY
+ old = 0
+ IO.popen(%W"git blame --line-porcelain -- #{file}") do |blame|
+ while head = blame.gets("\n\t") and s = blame.gets
+ next unless (gem = s.split(/\s+|#.*/)).size > 3
+ time = head[/^committer-time \K\d+/].to_i
+ next if (d = limit - time) <= 0
+ d /= SECONDS_IN_DAY
+ line = head[/\A\h+ \d+ \K\d+/].to_i
+ level = if d < days; 'warning'; else old += 1; 'error'; end
+ d += days
+ puts "::#{level} file=#{file},line=#{line},title=Older than #{d} days::#{gem[0]} #{gem[3]}"
+ end
+ end
+ abort "::error title=Too long-standing gems::The release comes soon." if december and old.nonzero?
+ shell: ruby {0}
+ env:
+ file: ${{ steps.logs.outputs.file }}
+ days: ${{ steps.logs.outputs.days }}
+
- name: Install libraries
uses: ./.github/actions/setup/ubuntu
if: ${{ steps.diff.outputs.gems }}
@@ -104,30 +167,17 @@ jobs:
timeout-minutes: 30
env:
RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
if: ${{ steps.diff.outputs.gems }}
- - name: Commit
+ - name: Push
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]"
- else
- git commit --message="${message} as of ${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
+ steps.commit.outcome == 'success'
}}
- uses: ./.github/actions/slack
diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml
index d871ef02c0..ad399b264f 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -30,7 +30,9 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
if: ${{ contains(matrix.os, 'ubuntu') }}
@@ -40,21 +42,17 @@ jobs:
- uses: ./.github/actions/setup/directories
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- ruby-version: '3.0'
+ ruby-version: '3.1'
bundler: none
- 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: ./goruby -veh
-
- - run: ruby tool/update-deps --fix
+ - run: make fix-depends
- - run: git diff --no-ext-diff --ignore-submodules --exit-code
+ - run: git diff --color --no-ext-diff --ignore-submodules --exit-code
- uses: ./.github/actions/slack
with:
diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml
index 42ad551430..f194d00779 100644
--- a/.github/workflows/check_misc.yml
+++ b/.github/workflows/check_misc.yml
@@ -18,24 +18,49 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: head
- uses: ./.github/actions/setup/directories
with:
makeup: true
- # Skip overwriting MATZBOT_GITHUB_TOKEN
+ # Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
- - name: Check if C-sources are US-ASCII
+ - name: Re-generate Makefiles
+ run: |
+ # config.status needs to run as a shell script
+ { echo ':&&exit'; cat tool/prereq.status; } > config.status
+ : # same as actions/setup/directories/action.yml
+ for mk in Makefile GNUmakefile; do
+ sed -f tool/prereq.status template/$mk.in > $mk
+ done
+
+ - name: Check for code styles
run: |
- grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || :
+ set -x
+ ruby tool/auto-style.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA"
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.pull_request.base.sha }}
+ GITHUB_NEW_SHA: ${{ github.event.pull_request.merge_commit_sha }}
+ # Skip 'push' events because post_push.yml fixes them on push
+ if: ${{ github.repository == 'ruby/ruby' && startsWith(github.event_name, 'pull') }}
- - name: Check for trailing spaces
+ - name: Check if date in man pages is up-to-date
run: |
- git grep -I -n $'[\t ]$' -- '*.rb' '*.[chy]' '*.rs' '*.yml' && exit 1 || :
- git grep -n $'^[\t ][\t ]*$' -- '*.md' && exit 1 || :
+ git fetch origin --depth=1 "${GITHUB_OLD_SHA}"
+ git diff --exit-code --name-only "${GITHUB_OLD_SHA}" HEAD -- man ||
+ make V=1 GIT=git BASERUBY=ruby update-man-date
+ git diff --color --no-ext-diff --ignore-submodules --exit-code -- man
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.pull_request.base.sha }}
+ if: ${{ startsWith(github.event_name, 'pull') }}
- name: Check for bash specific substitution in configure.ac
run: |
@@ -52,24 +77,69 @@ jobs:
exit $fail
working-directory: include
+ - id: now
+ run: |
+ date +"mon=%-m"%n"day=%-d" >> $GITHUB_OUTPUT
+ env:
+ TZ: Asia/Tokyo
+
+ - id: deprecation
+ run: |
+ eval $(sed -n 's/^#define RUBY_API_VERSION_\(MAJOR\|MINOR\) /\1=/p' include/ruby/version.h)
+ if git --no-pager grep --color -o 'rb_warn_deprecated_to_remove_at('$MAJOR'\.'$MINOR',.*' -- '*.c' >&2; then
+ false
+ else
+ true
+ fi
+ continue-on-error: ${{ steps.now.outputs.mon < 12 }}
+
+ - name: Check if to generate documents
+ id: rdoc
+ run: |
+ set -- $(sed 's/#.*//;/^rdoc /!d' gems/bundled_gems)
+ { echo version=$2; echo ref=$4; } >> $GITHUB_OUTPUT
+
+ - name: Checkout rdoc
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ repository: ruby/rdoc
+ ref: ${{ steps.rdoc.outputs.ref }}
+ path: .bundle/gems/rdoc-${{ steps.rdoc.outputs.version }}
+ persist-credentials: false
+ if: ${{ steps.rdoc.outputs.ref != '' }}
+
+ - name: Generate rdoc scripts
+ run: |
+ set -x
+ gempath=$(ruby -e 'print Gem.user_dir, "/bin"')
+ PATH=$gempath:$PATH
+ gem install --user bundler
+ bundle config --local path vendor/bundle
+ bundle install --jobs 4
+ bundle exec rake generate
+ working-directory: .bundle/gems/rdoc-${{ steps.rdoc.outputs.version }}
+ if: ${{ steps.rdoc.outputs.ref != '' }}
+
+ - name: Core docs coverage
+ run: |
+ make XRUBY=ruby RDOC_DEPENDS= RBCONFIG=update-rbconfig rdoc-coverage
+
- name: Generate docs
id: docs
run: |
- ruby -W0 --disable-gems -I./lib tool/rdoc-srcdir -q --op html .
+ make XRUBY=ruby RDOC_DEPENDS= RBCONFIG=update-rbconfig HTMLOUT=html html
echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT
# Generate only when document commit/PR
if: >-
${{false
|| contains(github.event.head_commit.message, '[ruby/rdoc]')
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
}}
- name: Upload docs
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
path: html
name: ${{ steps.docs.outputs.htmlout }}
diff --git a/.github/workflows/check_sast.yml b/.github/workflows/check_sast.yml
new file mode 100644
index 0000000000..6fd1be6542
--- /dev/null
+++ b/.github/workflows/check_sast.yml
@@ -0,0 +1,133 @@
+name: 'Check SAST tool'
+
+on:
+ push:
+ branches: ['master']
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ schedule:
+ - cron: '0 12 * * *'
+ workflow_dispatch:
+
+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
+ contents: read
+
+jobs:
+ zizmor:
+ name: zizmor
+
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ security-events: write
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - name: Run zizmor
+ uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
+ continue-on-error: true
+
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-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/upload-sarif to send a status report
+ # 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.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - language: cpp
+ - language: ruby
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: none
+ config-file: .github/codeql/codeql-config.yml
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
+ with:
+ category: '/language:${{ matrix.language }}'
+ upload: False
+ output: sarif-results
+
+ - name: filter-sarif
+ uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1
+ 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
+ -spec/ruby/core/regexp/timeout_spec.rb:rb/redos
+ -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: filter-sarif
+ uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1
+ with:
+ patterns: |
+ +**/*.c
+ +**/*.h
+ input: sarif-results/${{ matrix.language }}.sarif
+ output: sarif-results/${{ matrix.language }}.sarif
+ if: ${{ matrix.language == 'cpp' }}
+ continue-on-error: true
+
+ - name: Upload SARIF
+ uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
+ with:
+ sarif_file: sarif-results/${{ matrix.language }}.sarif
+ continue-on-error: true
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 5310d0875f..0000000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-name: 'CodeQL'
-
-on:
- push:
- branches: ['master']
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- schedule:
- - cron: '0 12 * * *'
- workflow_dispatch:
-
-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
- contents: read
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-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
- # 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.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- env:
- enable_install_doc: no
-
- strategy:
- fail-fast: false
- matrix:
- include:
- - language: cpp
- - language: ruby
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
- - name: Install libraries
- if: ${{ contains(matrix.os, 'macos') }}
- uses: ./.github/actions/setup/macos
-
- - name: Install libraries
- if : ${{ matrix.os == 'ubuntu-latest' }}
- uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
-
- - name: Remove an obsolete rubygems vendored file
- if: ${{ matrix.os == 'ubuntu-latest' }}
- run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
-
- - name: Initialize CodeQL
- uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
- with:
- languages: ${{ matrix.language }}
-
- - name: Autobuild
- uses: github/codeql-action/autobuild@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
- with:
- category: '/language:${{ matrix.language }}'
- upload: False
- output: sarif-results
-
- - name: filter-sarif
- uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # v1.0.1
- 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: Upload SARIF
- uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
- with:
- sarif_file: sarif-results/${{ matrix.language }}.sarif
- continue-on-error: true
diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml
index 33e321b470..147470f38a 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -35,11 +35,9 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- run: true
@@ -51,20 +49,21 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
# Set fetch-depth: 10 so that Launchable can receive commits information.
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - name: 'clang 18 LTO'
+ - name: 'clang 22 LTO'
uses: './.github/actions/compilers'
with:
- tag: clang-18
- with_gcc: 'clang-18 -flto=auto'
+ tag: clang-22
+ with_gcc: 'clang-22 -flto=auto'
optflags: '-O2'
enable_shared: false
- - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' } }
+ timeout-minutes: 30
+ - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 5 }
# - { uses: './.github/actions/compilers', name: '-O3', with: { optflags: '-O3 -march=x86-64 -mtune=generic', check: true } }
compile2:
@@ -73,27 +72,27 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - name: 'GCC 13 LTO'
+ - name: 'GCC 15 LTO'
uses: './.github/actions/compilers'
with:
- tag: gcc-13
- with_gcc: 'gcc-13 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
+ tag: gcc-15
+ with_gcc: 'gcc-15 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
optflags: '-O2'
enable_shared: false
- - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' } }
- - { uses: './.github/actions/compilers', name: 'GCC 14', with: { tag: 'gcc-14' } }
- - { uses: './.github/actions/compilers', name: 'GCC 13', with: { tag: 'gcc-13' } }
- - { uses: './.github/actions/compilers', name: 'GCC 12', with: { tag: 'gcc-12' } }
- - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' } }
- - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' } }
- - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' } }
- - { uses: './.github/actions/compilers', name: 'GCC 8', with: { tag: 'gcc-8' } }
- - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' } }
+ timeout-minutes: 10
+ - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 15', with: { tag: 'gcc-15' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 14', with: { tag: 'gcc-14' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 13', with: { tag: 'gcc-13' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 12', with: { tag: 'gcc-12' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' }, timeout-minutes: 5 }
compile3:
name: 'omnibus compilations, #3'
@@ -101,19 +100,18 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' } }
- - { uses: './.github/actions/compilers', name: 'clang 20', with: { tag: 'clang-20' } }
- - { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' } }
- - { uses: './.github/actions/compilers', name: 'clang 18', with: { tag: 'clang-18' } }
- - { uses: './.github/actions/compilers', name: 'clang 17', with: { tag: 'clang-17' } }
- - { uses: './.github/actions/compilers', name: 'clang 16', with: { tag: 'clang-16' } }
- - { uses: './.github/actions/compilers', name: 'clang 15', with: { tag: 'clang-15' } }
- - { uses: './.github/actions/compilers', name: 'clang 14', with: { tag: 'clang-14' } }
+ - { uses: './.github/actions/compilers', name: 'clang 20', with: { tag: 'clang-20' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 18', with: { tag: 'clang-18' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 17', with: { tag: 'clang-17' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 16', with: { tag: 'clang-16' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 15', with: { tag: 'clang-15' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 14', with: { tag: 'clang-14' }, timeout-minutes: 5 }
compile4:
name: 'omnibus compilations, #4'
@@ -121,20 +119,20 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'clang 13', with: { tag: 'clang-13' } }
- - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' } }
- - { uses: './.github/actions/compilers', name: 'clang 11', with: { tag: 'clang-11' } }
- - { uses: './.github/actions/compilers', name: 'clang 10', with: { tag: 'clang-10' } }
- # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o.
- - { uses: './.github/actions/compilers', name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit' } }
+ - { uses: './.github/actions/compilers', name: 'clang 13', with: { tag: 'clang-13' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 11', with: { tag: 'clang-11' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 10', with: { tag: 'clang-10' }, timeout-minutes: 5 }
+ # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o and fail `make test-leaked-globals`.
+ - { uses: './.github/actions/compilers', name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
compile5:
name: 'omnibus compilations, #5'
@@ -142,10 +140,10 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
# -Wno-strict-prototypes is necessary with current clang-15 since
# older autoconf generate functions without prototype and -pedantic
@@ -153,14 +151,14 @@ 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
- - { uses: './.github/actions/compilers', name: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C17', with: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C23', with: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+ - { uses: './.github/actions/compilers', name: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C17', with: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C23', with: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
compile6:
name: 'omnibus compilations, #6'
@@ -168,19 +166,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'gmp', with: { append_configure: '--with-gmp', check: 'ruby/test_bignum.rb', mspecopt: "/github/workspace/src/spec/ruby/core/integer" } }
- - { uses: './.github/actions/compilers', name: 'jemalloc', with: { append_configure: '--with-jemalloc' } }
- - { uses: './.github/actions/compilers', name: 'valgrind', with: { append_configure: '--with-valgrind' } }
- - { uses: './.github/actions/compilers', name: 'coroutine=ucontext', with: { append_configure: '--with-coroutine=ucontext' } }
- - { uses: './.github/actions/compilers', name: 'coroutine=pthread', with: { append_configure: '--with-coroutine=pthread' } }
+ - { uses: './.github/actions/compilers', name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'gmp', with: { append_configure: '--with-gmp', test_all: 'ruby/test_bignum.rb', test_spec: "/github/workspace/src/spec/ruby/core/integer" }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'jemalloc', with: { append_configure: '--with-jemalloc' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'valgrind', with: { append_configure: '--with-valgrind' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'coroutine=ucontext', with: { append_configure: '--with-coroutine=ucontext' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'coroutine=pthread', with: { append_configure: '--with-coroutine=pthread' }, timeout-minutes: 5 }
compile7:
name: 'omnibus compilations, #7'
@@ -188,19 +186,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' } }
- - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' } }
- - { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' } }
- - { uses: './.github/actions/compilers', name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' } }
- - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' } }
- - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' } }
- - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' } }
+ - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' }, timeout-minutes: 5 }
compile8:
name: 'omnibus compilations, #8'
@@ -208,19 +206,18 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'NDEBUG', with: { cppflags: '-DNDEBUG' } }
- - { uses: './.github/actions/compilers', name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'BIGNUM_DEBUG', with: { cppflags: '-DBIGNUM_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' } }
- - { uses: './.github/actions/compilers', name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' } }
+ - { uses: './.github/actions/compilers', name: 'NDEBUG', with: { cppflags: '-DNDEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 5 }
compile9:
name: 'omnibus compilations, #9'
@@ -228,19 +225,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' } }
- - { uses: './.github/actions/compilers', name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' } }
- - { uses: './.github/actions/compilers', name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' } }
- - { uses: './.github/actions/compilers', name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' } }
- - { uses: './.github/actions/compilers', name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit' } }
+ - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 5 }
compileX:
name: 'omnibus compilations, #10'
@@ -248,19 +245,20 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' } }
- - { uses: './.github/actions/compilers', name: 'USE_SYMBOL_GC=0', with: { cppflags: '-DUSE_SYMBOL_GC=0' } }
- - { uses: './.github/actions/compilers', name: 'USE_THREAD_CACHE=0', with: { cppflags: '-DUSE_THREAD_CACHE=0' } }
- - { uses: './.github/actions/compilers', name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } }
- - { uses: './.github/actions/compilers', name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' } }
- - { uses: './.github/actions/compilers', name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' } }
- - { uses: './.github/actions/compilers', name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' } }
- - { uses: './.github/actions/compilers', name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' } }
+ - { uses: './.github/actions/compilers', name: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' }, timeout-minutes: 5 }
compileB:
name: 'omnibus compilations, #11'
@@ -268,19 +266,18 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' } }
- - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' } }
- - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' } }
- - { uses: './.github/actions/compilers', name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' } }
- - { uses: './.github/actions/compilers', name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_OBJ_INFO', with: { cppflags: '-DRGENGC_OBJ_INFO' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' } }
+ - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 5 }
compileC:
name: 'omnibus compilations, #12'
@@ -288,16 +285,19 @@ jobs:
needs: compile-if
if: ${{ needs.compile-if.result == 'success' }}
timeout-minutes: 60
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
+
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' } }
- - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' } }
- - { uses: './.github/actions/compilers', name: 'enable-yjit', with: { append_configure: '--enable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' } }
- - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' } }
+ - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 23', with: { tag: 'clang-23' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 8', with: { tag: 'gcc-8' }, timeout-minutes: 5 }
+ - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' }, timeout-minutes: 5 }
compilemax:
name: 'omnibus compilations, result'
@@ -317,6 +317,8 @@ jobs:
- 'compileB'
- 'compileC'
steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- uses: ./.github/actions/slack
with:
label: 'omnibus'
diff --git a/.github/workflows/crosscompile.yml b/.github/workflows/crosscompile.yml
new file mode 100644
index 0000000000..4c28516e25
--- /dev/null
+++ b/.github/workflows/crosscompile.yml
@@ -0,0 +1,123 @@
+name: Cross compile
+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
+ 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:
+ make:
+ name: make (${{ matrix.host }} host on ${{ matrix.build }})
+ strategy:
+ matrix:
+ include:
+ - host: aarch64-linux-gnu
+ arch: arm64
+ build: x86_64-linux-gnu
+ runs-on: ubuntu-24.04
+ file_arch: ARM aarch64
+ - host: x86_64-linux-gnu
+ arch: amd64
+ build: aarch64-linux-gnu
+ runs-on: ubuntu-24.04-arm
+ file_arch: x86-64
+ fail-fast: false
+
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+
+ runs-on: ${{ matrix.runs-on }}
+
+ 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.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout-cone-mode: false
+ sparse-checkout: /.github
+ persist-credentials: false
+
+ - uses: ./.github/actions/setup/directories
+ with:
+ srcdir: src
+ builddir: build
+ makeup: true
+
+ - name: Setup cross-compilation toolchain sources
+ run: |
+ native_arch=$(dpkg --print-architecture)
+ # Restrict existing sources to native arch
+ sudo sed -i '/^Architectures:/d' /etc/apt/sources.list.d/ubuntu.sources
+ sudo sed -i "/^Types:/a Architectures: ${native_arch}" /etc/apt/sources.list.d/ubuntu.sources
+ # Add cross-arch sources
+ if [ "${{ matrix.arch }}" = "arm64" ]; then
+ cross_uri="http://ports.ubuntu.com/"
+ else
+ cross_uri="http://archive.ubuntu.com/ubuntu/"
+ fi
+ printf '%s\n' \
+ "Types: deb" \
+ "URIs: ${cross_uri}" \
+ "Suites: noble noble-updates noble-security" \
+ "Components: main universe" \
+ "Architectures: ${{ matrix.arch }}" \
+ | sudo tee /etc/apt/sources.list.d/cross-${{ matrix.arch }}.sources
+
+ - uses: ./.github/actions/setup/ubuntu
+ with:
+ arch: ${{ matrix.arch }}
+
+ - uses: ./.github/actions/setup/baseruby
+ id: baseruby
+ with:
+ srcdir: src
+
+ - name: Run configure
+ run: >-
+ ../src/configure -C --disable-install-doc
+ --prefix=/usr
+ --build=${{ matrix.build }}
+ --host=${{ matrix.host }}
+ --with-baseruby="$baseruby"
+ env:
+ baseruby: ${{ steps.baseruby.outputs.ruby }}
+
+ - run: make
+
+ - run: make install DESTDIR=$PWD/install
+
+ - name: Verify cross-compiled binary
+ run: |
+ file install/usr/bin/ruby
+ file install/usr/bin/ruby | grep -q '${{ matrix.file_arch }}'
+
+ - uses: ./.github/actions/slack
+ with:
+ label: cross ${{ matrix.host }}
+ 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/cygwin.yml b/.github/workflows/cygwin.yml
index 5b111bd389..5ab86c7b19 100644
--- a/.github/workflows/cygwin.yml
+++ b/.github/workflows/cygwin.yml
@@ -32,22 +32,24 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- run: git config --global core.autocrlf input
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- name: Setup Cygwin
- uses: cygwin/cygwin-install-action@master
+ uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6.1
with:
- packages: ruby gcc-core make autoconf libtool libssl-devel libyaml-devel libffi-devel zlib-devel
+ packages: ruby gcc-core make autoconf libtool libssl-devel libyaml-devel libffi-devel zlib-devel rubygems
+ site: |
+ https://cygwin.osuosl.org/
- name: configure
run: |
@@ -65,3 +67,9 @@ jobs:
timeout-minutes: 30
run: make -j4 V=1
shell: C:\cygwin\bin\bash.EXE --noprofile --norc -e -o igncr -o pipefail {0}
+
+ - uses: ./.github/actions/slack
+ with:
+ label: Cygwin
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
diff --git a/.github/workflows/default_gems.yml b/.github/workflows/default_gems.yml
deleted file mode 100644
index ea2e287066..0000000000
--- a/.github/workflows/default_gems.yml
+++ /dev/null
@@ -1,95 +0,0 @@
-name: Update default gems list
-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:
- update_default_gems:
- name: Update default gems list
-
- permissions:
- contents: write # for Git to git push
-
- runs-on: ubuntu-latest
-
- if: ${{ github.repository == 'ruby/ruby' }}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- 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)
-
- - 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/default_gems_list.yml b/.github/workflows/default_gems_list.yml
new file mode 100644
index 0000000000..f52b83103c
--- /dev/null
+++ b/.github/workflows/default_gems_list.yml
@@ -0,0 +1,99 @@
+name: Update default gems list
+on: [push, pull_request, merge_group]
+
+env:
+ UPDATE_NEWS_ENABLED: true
+
+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:
+ update_default_gems_list:
+ name: Update default gems list
+
+ permissions:
+ contents: write # for Git to git push
+
+ runs-on: ubuntu-latest
+
+ if: ${{ github.repository == 'ruby/ruby' }}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # zizmor: ignore[artipacked]
+ with:
+ token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+
+ - id: gems
+ run: true
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - uses: ./.github/actions/setup/directories
+ with:
+ makeup: true
+ # Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
+ checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
+ if: ${{ steps.gems.outcome == 'success' }}
+
+ - name: Download previous gems list
+ run: |
+ data=default_gems.json
+ mkdir -p .downloaded-cache
+ ln -s .downloaded-cache/$data .
+ curl --retry 5 --retry-connrefused --retry-delay 2 --retry-max-time 60 -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' && env.UPDATE_NEWS_ENABLED == 'true' }}
+
+ - 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/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml
index 69ab5d9131..2e4dc8d7a2 100644
--- a/.github/workflows/dependabot_automerge.yml
+++ b/.github/workflows/dependabot_automerge.yml
@@ -1,23 +1,25 @@
# from https://github.com/gofiber/swagger/blob/main/.github/workflows/dependabot_automerge.yml
name: Dependabot auto-merge
on:
- pull_request_target:
+ pull_request:
+
+permissions:
+ contents: write
+ pull-requests: write
jobs:
automerge:
runs-on: ubuntu-latest
-
- if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
-
+ if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'ruby/ruby'
steps:
- name: Dependabot metadata
- uses: dependabot/fetch-metadata@dbb049abf0d677abbd7f7eee0375145b417fdd34 # v2.2.0
+ uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
id: metadata
- name: Wait for status checks
- uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4
+ uses: lewagon/wait-on-check-action@9312864dfbc9fd208e9c0417843430751c042800 # v1.7.0
with:
- repo-token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
check-regexp: 'make \(check, .*\)'
wait-interval: 30
@@ -27,4 +29,4 @@ jobs:
run: gh pr merge --auto --rebase "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
- GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.MATZBOT_DEPENDABOT_MERGE_TOKEN }}
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index e57cd86e2b..d0a8024b05 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -2,6 +2,9 @@ name: "Pull Request Labeler"
on:
- pull_request_target
+permissions:
+ contents: read
+
jobs:
labeler:
permissions:
@@ -9,4 +12,4 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- - uses: actions/labeler@v5
+ - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 77fe2d21fc..501d35698b 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -26,27 +26,29 @@ jobs:
matrix:
include:
- test_task: check
- os: macos-14
+ os: macos-26
- test_task: check
- os: macos-14
+ os: macos-15
configure_args: '--with-gcc=gcc-14'
- test_task: check
- os: macos-14
+ os: macos-26
configure_args: '--with-jemalloc --with-opt-dir=$(brew --prefix jemalloc)'
- test_task: check
- os: macos-14
+ os: macos-26
configure_args: '--with-gmp'
- test_task: test-all
test_opts: --repeat-count=2
- os: macos-14
+ os: macos-26
- test_task: test-bundler-parallel
- os: macos-14
+ os: macos-26
- test_task: test-bundled-gems
- os: macos-14
+ os: macos-26
- test_task: check
os: macos-15
- test_task: check
- os: macos-13
+ os: macos-15-intel
+ - test_task: check
+ os: macos-14
fail-fast: false
env:
@@ -57,18 +59,17 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries
uses: ./.github/actions/setup/macos
@@ -107,6 +108,10 @@ jobs:
- run: make hello
+ - name: runirb
+ run: |
+ echo IRB::VERSION | make runirb RUNOPT="-- -f"
+
- name: Set test options for skipped tests
run: |
set -x
@@ -115,6 +120,7 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
- name: Set up Launchable
+ id: launchable
uses: ./.github/actions/launchable/setup
with:
os: ${{ matrix.os }}
@@ -123,6 +129,7 @@ jobs:
builddir: build
srcdir: src
continue-on-error: true
+ timeout-minutes: 3
- name: Set extra test options
run: |
@@ -132,19 +139,18 @@ jobs:
- name: make ${{ matrix.test_task }}
run: |
- if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
- exec \
- > >(tee launchable_stdout.log) \
- 2> >(tee launchable_stderr.log)
- fi
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
ulimit -c unlimited
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- timeout-minutes: 60
+ timeout-minutes: 90
env:
RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
PRECHECK_BUNDLED_GEMS: 'no'
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
- name: make skipped tests
run: |
@@ -156,32 +162,24 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
+ - name: CAPI extensions
+ uses: ./.github/actions/capiext
+ with:
+ builddir: build
+ env:
+ RUBY_TESTOPTS: '-v --tty=no'
+ if: ${{ contains(matrix.extra_checks, 'capi') }}
+
- uses: ./.github/actions/slack
with:
label: ${{ matrix.os }} / ${{ matrix.test_task }}
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
if: ${{ failure() }}
- - name: Resolve job ID
- id: job_id
- uses: actions/github-script@main
- env:
- matrix: ${{ toJson(matrix) }}
- with:
- script: |
- const { data: workflow_run } = await github.rest.actions.listJobsForWorkflowRun({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: context.runId
- });
- const matrix = JSON.parse(process.env.matrix);
- const job_name = `${context.job}${matrix ? ` (${Object.values(matrix).join(", ")})` : ""}`;
- return workflow_run.jobs.find((job) => job.name === job_name).id;
-
result:
if: ${{ always() }}
name: ${{ github.workflow }} result
- runs-on: macos-latest
+ runs-on: ubuntu-latest
needs: [make]
steps:
- run: exit 1
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index 01de0917c9..1efae8be59 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -30,16 +30,32 @@ permissions:
#
jobs:
make:
- runs-on: windows-2022
+ runs-on: windows-${{ matrix.os }}
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'
+ MSYS2_ARCH: >-
+ ${{ case(
+ contains(matrix.msystem, 'arm64'), 'aarch64',
+ contains(matrix.msystem, '64'), 'x86_64',
+ 'i686'
+ ) }}
+ MINGW_PACKAGE_PREFIX: >-
+ mingw-w${{
+ case(endsWith(matrix.msystem, '64'), '64', '32')
+ }}-${{ case(
+ startsWith(matrix.msystem, 'clang'), 'clang',
+ startsWith(matrix.msystem, 'ucrt'), 'ucrt',
+ 'mingw'
+ ) }}-${{ case(
+ contains(matrix.msystem, 'arm64'), 'aarch64',
+ endsWith(matrix.msystem, '64'), 'x86_64',
+ 'i686'
+ ) }}
+ CFLAGS: '-mtune=generic -O3 -pipe'
+ CXXFLAGS: '-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 }}
@@ -50,54 +66,113 @@ jobs:
# To mitigate flakiness of MinGW CI, we test only one runtime that newer MSYS2 uses.
# Ruby 3.2 is the first Windows Ruby to use OpenSSL 3.x
- msystem: 'UCRT64'
- baseruby: '3.2'
+ os: 2022
test_task: 'check'
test-all-opts: '--name=!/TestObjSpace#test_reachable_objects_during_iteration/'
+ - msystem: 'CLANGARM64'
+ os: 11-arm
+ test_task: 'check'
fail-fast: false
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/vcpkg'))
)}}
steps:
- - name: Set up Ruby & MSYS2
- uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1
+ id: msys2
with:
- ruby-version: ${{ matrix.baseruby }}
+ msystem: ${{ matrix.msystem }}
+ update: true
+ install: >-
+ git
+ make
+ ruby
+ autoconf
+ ${{ env.MINGW_PACKAGE_PREFIX }}-gcc
+ ${{ env.MINGW_PACKAGE_PREFIX }}-ragel
+ ${{ env.MINGW_PACKAGE_PREFIX }}-openssl
+ ${{ env.MINGW_PACKAGE_PREFIX }}-libyaml
+ ${{ env.MINGW_PACKAGE_PREFIX }}-libffi
+
+ - name: Set up env
+ id: setup-env
+ working-directory:
+ run: |
+ $msys2 = ${env:MSYS2_LOCATION}
+ $msystem = ${env:MSYSTEM}.ToLower()
+ echo $msys2\usr\bin $msys2\$msystem\bin |
+ Tee-Object ${env:GITHUB_PATH} -Append -Encoding utf-8
+
+ # Use the fast device for the temporary directory.
+ # %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
+ # https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
+ $tmp = ${env:RUNNER_TEMP}
+ echo HOME=$home TMP=$tmp TEMP=$tmp TMPDIR=$tmp |
+ Tee-Object ${env:GITHUB_ENV} -Append -Encoding utf-8
+ shell: pwsh # cmd.exe does not strip spaces before `|`.
+ env:
+ MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
+ MSYSTEM: ${{ matrix.msystem }}
+
+ - name: Remove Strawberry Perl pkg-config
+ working-directory:
+ # `pkg-config.bat` included in Strawberry Perl is written in
+ # Perl and doesn't work when another msys2 `perl` precede its
+ # own `perl`.
+ #
+ # ```
+ # Can't find C:\Strawberry\perl\bin\pkg-config.bat on PATH, '.' not in PATH.
+ # ```
+ run: |
+ Get-Command pkg-config.bat | % { ren $_.path ($_.path + "~") }
+ shell: pwsh
- name: Misc system & package info
working-directory:
run: |
- # show where
- result=true
- for e in gcc.exe ragel.exe make.exe libcrypto-3-x64.dll libssl-3-x64.dll; do
- echo ::group::$'\033[93m'$e$'\033[m'
- where $e || result=false
- echo ::endgroup::
- done
- # show version
- for e in gcc ragel make "openssl version"; do
- case "$e" in *" "*) ;; *) e="$e --version";; esac
- echo ::group::$'\033[93m'$e$'\033[m'
- $e || result=false
- echo ::endgroup::
- done
- # show packages
- echo ::group::$'\033[93m'Packages$'\033[m'
- pacman -Qs mingw-w64-ucrt-x86_64-* | sed -n "s,local/mingw-w64-ucrt-x86_64-,,p"
- echo ::endgroup::
- $result
-
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ group() { echo ::group::$'\e[94;1m'"$*"$'\e[m'; }
+ endgroup() { echo ::endgroup::; }
+
+ group Path
+ cygpath -wa / . $(type -p cygpath bash sh)
+ endgroup
+
+ I() {
+ group $1
+ run Where type -pa $1 && { [ $# -eq 1 ] || run Version "$@"; } ||
+ failed+=($1)
+ endgroup
+ }
+ run() { local w m=$1; shift; w="$("$@")" && show "$m" && indent "$w"; }
+ indent() { [ -z "$1" ] || echo "$1" | /bin/sed '/^$/!s/^/ /'; }
+ show() { echo $'\e[96m'"$*"$'\e[m'; }
+
+ failed=()
+
+ I gcc.exe --version
+ I ragel.exe --version
+ I make.exe --version
+ I openssl.exe version
+ I libcrypto-3-x64.dll
+ I libssl-3-x64.dll
+
+ group Packages
+ pacman -Qs $MINGW_PACKAGE_PREFIX-* | /bin/sed -n "s,local/$MINGW_PACKAGE_PREFIX-,,p"
+ endgroup
+
+ [ ${#failed[@]} -eq 0 ]
+ shell: sh
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/directories
with:
@@ -111,6 +186,9 @@ jobs:
run: >
../src/configure --disable-install-doc --prefix=/.
--build=$CHOST --host=$CHOST --target=$CHOST
+ shell: sh
+ env:
+ CHOST: ${{ env.MSYS2_ARCH }}-w64-mingw32
- name: make all
timeout-minutes: 30
@@ -128,11 +206,11 @@ jobs:
srcdir: src
test-tasks: '["test", "test-all", "test-spec"]'
continue-on-error: true
+ timeout-minutes: 3
- name: test
timeout-minutes: 30
- run: make test
- shell: cmd
+ run: make test test-tool
env:
GNUMAKEFLAGS: ''
RUBY_TESTOPTS: '-v --tty=no'
@@ -140,7 +218,6 @@ jobs:
- name: test-all
timeout-minutes: 45
- shell: cmd
run: |
make ${{ StartsWith(matrix.test_task, 'test/') && matrix.test_task || 'test-all' }}
env:
@@ -155,7 +232,6 @@ jobs:
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/') }}
- uses: ./src/.github/actions/slack
@@ -167,4 +243,4 @@ jobs:
defaults:
run:
working-directory: build
- shell: sh
+ shell: cmd
diff --git a/.github/workflows/modgc.yml b/.github/workflows/modgc.yml
index 9162c17924..bd3c6ab575 100644
--- a/.github/workflows/modgc.yml
+++ b/.github/workflows/modgc.yml
@@ -28,7 +28,7 @@ jobs:
- name: default
- name: mmtk
mmtk_build: release
- os: [macos-latest, ubuntu-latest]
+ os: [macos-26, ubuntu-latest]
include:
- test_task: check
fail-fast: false
@@ -42,18 +42,17 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries (macOS)
uses: ./.github/actions/setup/macos
@@ -63,9 +62,9 @@ jobs:
uses: ./.github/actions/setup/ubuntu
if: ${{ contains(matrix.os, 'ubuntu') }}
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- ruby-version: '3.0'
+ ruby-version: '3.1'
bundler: none
if: ${{ contains(matrix.os, 'ubuntu') }}
@@ -102,18 +101,20 @@ jobs:
- name: Run configure
env:
arch: ${{ matrix.arch }}
- run: >-
- $SETARCH ../src/configure -C --disable-install-doc --with-modular-gc=${{ env.MODULAR_GC_DIR }}
+ run: |
+ ${SETARCH} ../src/configure -C --disable-install-doc --with-modular-gc="${MODULAR_GC_DIR}" \
${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
- - uses: actions-rust-lang/setup-rust-toolchain@v1
+ - uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1.16.1
+ with:
+ cache-bin: false
- name: Set MMTk environment variables
run: |
echo 'EXCLUDES=../src/test/.excludes-mmtk' >> $GITHUB_ENV
echo 'MSPECOPT=-B../src/spec/mmtk.mspec' >> $GITHUB_ENV
if: ${{ matrix.gc.name == 'mmtk' }}
- - run: $SETARCH make
+ - run: ${SETARCH} make
- name: Build Modular GC
run: |
@@ -121,7 +122,7 @@ jobs:
make install-modular-gc MODULAR_GC=${{ matrix.gc.name }} MMTK_BUILD=${{ matrix.gc.mmtk_build }}
make distclean-modular-gc MODULAR_GC=${{ matrix.gc.name }}
- - run: $SETARCH make hello
+ - run: ${SETARCH} make hello
- name: Set test options for skipped tests
run: |
@@ -131,6 +132,7 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
- name: Set up Launchable
+ id: launchable
uses: ./.github/actions/launchable/setup
with:
os: ${{ matrix.os || 'ubuntu-22.04' }}
@@ -139,27 +141,27 @@ jobs:
builddir: build
srcdir: src
continue-on-error: true
+ timeout-minutes: 3
- name: make ${{ matrix.test_task }}
run: |
- if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
- exec \
- > >(tee launchable_stdout.log) \
- 2> >(tee launchable_stderr.log)
- fi
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
- $SETARCH make -s ${{ matrix.test_task }} \
+ ${SETARCH} make -s ${{ matrix.test_task }} \
${TESTS:+TESTS="$TESTS"} \
${{ !contains(matrix.test_task, 'bundle') && 'RUBYOPT=-w' || '' }}
timeout-minutes: ${{ matrix.gc.timeout || 40 }}
env:
RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
PRECHECK_BUNDLED_GEMS: 'no'
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
- name: make skipped tests
run: |
- $SETARCH make -s test-all TESTS="${TESTS//-n!\//-n/}"
+ ${SETARCH} make -s test-all TESTS="${TESTS//-n!\//-n/}"
env:
GNUMAKEFLAGS: ''
RUBY_TESTOPTS: '-v --tty=no'
diff --git a/.github/workflows/parse_y.yml b/.github/workflows/parse_y.yml
new file mode 100644
index 0000000000..a0082f71de
--- /dev/null
+++ b/.github/workflows/parse_y.yml
@@ -0,0 +1,101 @@
+name: parse.y
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ 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:
+ make:
+ strategy:
+ matrix:
+ include:
+ - test_task: check
+ - test_task: test-bundler-parallel
+ - test_task: test-bundled-gems
+ 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.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout-cone-mode: false
+ sparse-checkout: /.github
+ persist-credentials: false
+
+ - uses: ./.github/actions/setup/ubuntu
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.1'
+ bundler: none
+
+ - uses: ./.github/actions/setup/directories
+ with:
+ srcdir: src
+ builddir: build
+ makeup: true
+ clean: true
+ dummy-files: ${{ matrix.test_task == 'check' }}
+
+ - name: Run configure
+ run: ../src/configure -C --disable-install-doc cppflags=-DRUBY_DEBUG --with-parser=parse.y
+
+ - run: make
+
+ - run: make TESTRUN_SCRIPT='-renvutil -v -e "exit EnvUtil.current_parser == %[parse.y]"' run
+ env:
+ RUNOPT0: -I$(tooldir)/lib
+
+ - name: make ${{ matrix.test_task }}
+ run: make -s ${{ matrix.test_task }} RUN_OPTS="$RUN_OPTS" SPECOPTS="$SPECOPTS"
+ env:
+ RUBY_TESTOPTS: ${{ matrix.testopts }}
+ EXCLUDES: '../src/test/.excludes-parsey'
+ RUN_OPTS: ${{ matrix.run_opts || '--parser=parse.y' }}
+ SPECOPTS: ${{ matrix.specopts || '-T --parser=parse.y' }}
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
+
+ - 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/parsey.yml b/.github/workflows/parsey.yml
deleted file mode 100644
index 3d5e314eaf..0000000000
--- a/.github/workflows/parsey.yml
+++ /dev/null
@@ -1,95 +0,0 @@
-name: parse.y
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- 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:
- make:
- strategy:
- matrix:
- include:
- - test_task: check
- - test_task: test-bundler-parallel
- - test_task: test-bundled-gems
- 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.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- 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
- clean: true
- dummy-files: ${{ matrix.test_task == 'check' }}
-
- - name: Run configure
- run: ../src/configure -C --disable-install-doc cppflags=-DRUBY_DEBUG --with-parser=parse.y
-
- - run: make
-
- - run: make TESTRUN_SCRIPT='-e "exit !RUBY_DESCRIPTION.include?(%[+PRISM])"' run
-
- - name: make ${{ matrix.test_task }}
- run: make -s ${{ matrix.test_task }} RUN_OPTS="$RUN_OPTS" SPECOPTS="$SPECOPTS"
- env:
- RUBY_TESTOPTS: ${{ matrix.testopts }}
- EXCLUDES: '../src/test/.excludes-parsey'
- RUN_OPTS: ${{ matrix.run_opts || '--parser=parse.y' }}
- SPECOPTS: ${{ matrix.specopts || '-T --parser=parse.y' }}
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
-
- - 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/post_push.yml b/.github/workflows/post_push.yml
new file mode 100644
index 0000000000..237679ebb1
--- /dev/null
+++ b/.github/workflows/post_push.yml
@@ -0,0 +1,97 @@
+name: Post-push
+on:
+ push:
+ branches:
+ - master
+ - 'ruby_*_*'
+
+permissions:
+ contents: read
+
+jobs:
+ hooks:
+ name: Post-push hooks
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'ruby/ruby' }}
+ steps:
+ - name: Sync git.ruby-lang.org
+ id: sync-git
+ continue-on-error: true
+ run: |
+ mkdir -p ~/.ssh
+ (umask 066; printenv RUBY_GIT_SYNC_PRIVATE_KEY > ~/.ssh/id_ed25519)
+ ssh-keyscan -t ed25519 git.ruby-lang.org >> ~/.ssh/known_hosts
+ ssh -i ~/.ssh/id_ed25519 git-sync@git.ruby-lang.org "sudo -u git /home/git/git.ruby-lang.org/bin/update-ruby.sh $GITHUB_REF"
+ env:
+ GITHUB_REF: ${{ github.ref }}
+ RUBY_GIT_SYNC_PRIVATE_KEY: ${{ secrets.RUBY_GIT_SYNC_PRIVATE_KEY }}
+ if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/ruby_') }}
+
+ - name: Fetch changesets on bugs.ruby-lang.org
+ run: |
+ curl "https://bugs.ruby-lang.org/sys/fetch_changesets?key=${REDMINE_SYS_API_KEY}" -s --fail-with-body -w '* status: %{http_code}\n'
+ env:
+ REDMINE_SYS_API_KEY: ${{ secrets.REDMINE_SYS_API_KEY }}
+ if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/ruby_') }}
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # zizmor: ignore[artipacked]
+ with:
+ fetch-depth: 500 # for notify-slack-commits
+ token: ${{ secrets.MATZBOT_AUTO_UPDATE_TOKEN }}
+
+ - name: Notify commit to Slack
+ run: ruby tool/notify-slack-commits.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" refs/heads/master
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ SLACK_WEBHOOK_URL_ALERTS: ${{ secrets.SLACK_WEBHOOK_URL_ALERTS }}
+ SLACK_WEBHOOK_URL_COMMITS: ${{ secrets.SLACK_WEBHOOK_URL_COMMITS }}
+ SLACK_WEBHOOK_URL_RUBY_JP: ${{ secrets.SLACK_WEBHOOK_URL_RUBY_JP }}
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - name: Notify commit to ruby-cvs
+ run: |
+ SENDMAIL="ssh -i ${HOME}/.ssh/id_ed25519 git-sync@git.ruby-lang.org /usr/sbin/sendmail" \
+ ruby tool/commit-email.rb . ruby-cvs@g.ruby-lang.org \
+ "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" "$GITHUB_REF" \
+ --viewer-uri "https://github.com/ruby/ruby/commit/" \
+ --error-to cvs-admin@ruby-lang.org
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ GITHUB_REF: ${{ github.ref }}
+ if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/ruby_') }}
+
+ - name: Auto-correct code styles
+ run: |
+ set -x
+ ruby tool/auto-style.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" refs/heads/master
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+ EMAIL: svn-admin@ruby-lang.org
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - name: Push PR notes to GitHub
+ id: pr-notes
+ continue-on-error: true
+ run: ruby tool/notes-github-pr.rb "$(pwd)/.git" "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" refs/heads/master
+ env:
+ GITHUB_OLD_SHA: ${{ github.event.before }}
+ GITHUB_NEW_SHA: ${{ github.event.after }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+ EMAIL: svn-admin@ruby-lang.org
+ if: ${{ github.ref == 'refs/heads/master' }}
+
+ - name: Check for failures
+ run: exit 1
+ if: ${{ steps.sync-git.outcome == 'failure' || steps.pr-notes.outcome == 'failure' }}
+
+ - 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/pr-playground.yml b/.github/workflows/pr-playground.yml
index cc06006142..dc4f075a38 100644
--- a/.github/workflows/pr-playground.yml
+++ b/.github/workflows/pr-playground.yml
@@ -6,6 +6,10 @@ on:
workflows: ["WebAssembly"]
types: [completed]
+permissions:
+ contents: read
+ actions: read
+
jobs:
post-summary:
name: Post Playground link
@@ -25,7 +29,7 @@ jobs:
&& github.event.workflow_run.event == 'pull_request')
}}
steps:
- - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
+ - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 5d4474d978..5d16915e10 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,18 +1,114 @@
-name: Start release workflow
+name: Publish Ruby packages
+
on:
- push:
- tags:
- - '*'
+ repository_dispatch:
+ types:
+ - release
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version of the Ruby package to release'
+ required: true
+ default: '4.0.0'
+
+permissions:
+ contents: read
jobs:
- notify:
+ release:
runs-on: ubuntu-latest
steps:
- - name: Build release package
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: 3.3.4
+
+ - name: Store Ruby version
+ env:
+ RUBY_VERSION: ${{ github.event.client_payload.version || github.event.inputs.version }}
+ run: |
+ echo "RUBY_VERSION=${RUBY_VERSION}" >> $GITHUB_ENV
+
+ - name: Store ABI version
+ run: echo "ABI_VERSION=$(echo ${RUBY_VERSION} | cut -d '.' -f 1-2)" >> $GITHUB_ENV
+
+ - name: Copy draft package `/tmp` to `/pub` directory
+ run: tool/release.sh ${RUBY_VERSION}
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.FTP_R_L_O_AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.FTP_R_L_O_AWS_SECRET_ACCESS_KEY }}
+ AWS_DEFAULT_REGION: us-west-2
+
+ - name: Purge URLs of release package
+ run: |
+ curl -X POST \
+ -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
+ https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${ABI_VERSION}/ruby-${RUBY_VERSION}.tar.gz
+ curl -X POST \
+ -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
+ https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${ABI_VERSION}/ruby-${RUBY_VERSION}.tar.xz
+ curl -X POST \
+ -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
+ https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${ABI_VERSION}/ruby-${RUBY_VERSION}.zip
+
+ - name: Create a release on GitHub
+ run: |
+ RELEASE_TAG=$(ruby tool/ruby-version.rb tag "${RUBY_VERSION}")
+ echo $RELEASE_TAG
+ PREVIOUS_RELEASE_TAG=$(ruby tool/ruby-version.rb previous-tag "${RUBY_VERSION}")
+ echo $PREVIOUS_RELEASE_TAG
+ tool/gen-github-release.rb $PREVIOUS_RELEASE_TAG $RELEASE_TAG --no-dry-run
+ env:
+ GITHUB_TOKEN: ${{ secrets.MATZBOT_AUTO_UPDATE_TOKEN }}
+
+ - name: Update versions index
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 }}"}'
+ -d '{"event_type": "update_index"}'
+
+ - name: Build and push Docker images
+ 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/docker-images/dispatches \
+ -d "{\"event_type\": \"build\", \"client_payload\": {\"ruby_version\": \"${RUBY_VERSION}\"}}"
+
+ - name: Build snapcraft packages
+ 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/snap.ruby/dispatches \
+ -d "{\"event_type\": \"build\", \"client_payload\": {\"ruby_version\": \"${RUBY_VERSION}\"}}"
+
+ - name: Store the latest LTS version of OpenSSL
+ run: |
+ echo "OPENSSL_VERSION=`curl -s https://api.github.com/repos/openssl/openssl/releases | jq -r '.[].tag_name | select(startswith("openssl-3.0"))' | sort -Vr | head -n1 | cut -d'-' -f2`" >> $GITHUB_ENV
+
+ - name: Update ruby-build definition
+ run: |
+ curl -L -X POST \
+ -H "Authorization: Bearer ${{ secrets.RUBY_BUILD_WORKFLOW_TOKEN }}" \
+ -H "Accept: application/vnd.github+json" \
+ -H "X-GitHub-Api-Version: 2022-11-28" \
+ https://api.github.com/repos/rbenv/ruby-build/dispatches \
+ -d "{\"event_type\": \"update-ruby\", \"client_payload\": {\"ruby_version\": \"${RUBY_VERSION}\", \"openssl_version\": \"${OPENSSL_VERSION}\"}}"
+
+ - name: Update all-ruby definition
+ 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/all-ruby/dispatches \
+ -d '{"event_type": "update"}'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 25916066d6..a35bcff99a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,107 +1,21 @@
-name: Publish Ruby packages
-
+name: Start release workflow
on:
- repository_dispatch:
- types:
- - release
- workflow_dispatch:
- inputs:
- version:
- description: 'Version of the Ruby package to release'
- required: true
- default: '3.3.4'
+ push:
+ tags:
+ - '*'
+
+permissions:
+ contents: read
jobs:
- release:
+ notify:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
-
- - uses: ruby/setup-ruby@v1
- with:
- ruby-version: 3.3.4
-
- - name: Store Ruby version
- run: |
- echo "RUBY_VERSION=${{ github.event.client_payload.version || github.event.inputs.version }}" >> $GITHUB_ENV
-
- - name: Store ABI version
- run: echo "ABI_VERSION=$(echo ${{ env.RUBY_VERSION }} | cut -d '.' -f 1-2)" >> $GITHUB_ENV
-
- - name: Copy draft package `/tmp` to `/pub` directory
- run: tool/release.sh ${{ env.RUBY_VERSION }}
- env:
- AWS_ACCESS_KEY_ID: ${{ secrets.FTP_R_L_O_AWS_ACCESS_KEY_ID }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.FTP_R_L_O_AWS_SECRET_ACCESS_KEY }}
- AWS_DEFAULT_REGION: us-west-2
-
- - name: Purge URLs of release package
- run: |
- curl -X POST \
- -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
- https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${{ env.ABI_VERSION }}/ruby-${{ env.RUBY_VERSION }}.tar.gz
- curl -X POST \
- -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
- https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${{ env.ABI_VERSION }}/ruby-${{ env.RUBY_VERSION }}.tar.xz
- curl -X POST \
- -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
- https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${{ env.ABI_VERSION }}/ruby-${{ env.RUBY_VERSION }}.zip
-
- - name: Create a release on GitHub
- run: |
- RELEASE_TAG=$(echo v${{ env.RUBY_VERSION }} | sed 's/\./_/g')
- echo $RELEASE_TAG
- PREVIOUS_RELEASE_TAG=$(echo $RELEASE_TAG | awk 'BEGIN {FS="_"; OFS="_"}{ $NF=$NF-1; print }')
- echo $PREVIOUS_RELEASE_TAG
- tool/gen-github-release.rb $PREVIOUS_RELEASE_TAG $RELEASE_TAG --no-dry-run
- env:
- GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}
-
- - name: Update versions index
+ - 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": "update_index"}'
-
- - name: Build and push Docker images
- 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/docker-images/dispatches \
- -d '{"event_type": "build", "client_payload": {"ruby_version": "${{ env.RUBY_VERSION }}"}}'
-
- - name: Build snapcraft packages
- 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/snap.ruby/dispatches \
- -d '{"event_type": "build", "client_payload": {"ruby_version": "${{ env.RUBY_VERSION }}"}}'
-
- - name: Store the latest LTS version of OpenSSL
- run: |
- echo "OPENSSL_VERSION=`curl -s https://api.github.com/repos/openssl/openssl/releases | jq -r '.[].tag_name | select(startswith("openssl-3.0"))' | sort -Vr | head -n1 | cut -d'-' -f2`" >> $GITHUB_ENV
-
- - name: Update ruby-build definition
- run: |
- curl -L -X POST \
- -H "Authorization: Bearer ${{ secrets.RUBY_BUILD_WORKFLOW_TOKEN }}" \
- -H "Accept: application/vnd.github+json" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/rbenv/ruby-build/dispatches \
- -d '{"event_type": "update-ruby", "client_payload": {"ruby_version": "${{ env.RUBY_VERSION }}", "openssl_version": "${{ env.OPENSSL_VERSION }}"}}'
-
- - name: Update all-ruby definition
- 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/all-ruby/dispatches \
- -d '{"event_type": "update"}'
+ -d "{\"event_type\": \"$GITHUB_REF\"}"
diff --git a/.github/workflows/rust-warnings.yml b/.github/workflows/rust-warnings.yml
new file mode 100644
index 0000000000..23ed164405
--- /dev/null
+++ b/.github/workflows/rust-warnings.yml
@@ -0,0 +1,62 @@
+# Surface Rust warnings on PRs that touch any Rust code.
+# Not a required check so we never block people over new warnings
+# that might come from a new Rust version being released.
+name: Rust warnings
+on:
+ pull_request:
+ types:
+ - opened
+ - synchronize
+ - reopened
+ paths:
+ - '**.rs'
+ - '!**.inc.rs'
+ 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:
+ rust-warnings:
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+
+ runs-on: ubuntu-24.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.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - name: Install Rust
+ run: rustup default beta
+
+ - name: Rust warnings
+ shell: bash
+ run: |
+ set -eu
+ cargo check --quiet --all-features --message-format=json \
+ | jq -r 'select(.message.level | IN("warning", "error")) | .message.rendered' \
+ | tee messages.txt
+ (exit "${PIPESTATUS[0]}") && ! grep --quiet '[^[:space:]]' messages.txt
+
+ - name: "📜 `rustdoc` warnings"
+ shell: bash
+ run: |
+ set -eu
+ cargo doc --document-private-items --all --no-deps --message-format=json \
+ | jq -r 'select(.message.level | IN("warning", "error")) | .message.rendered' \
+ | tee messages.txt
+ (exit "${PIPESTATUS[0]}") && ! grep --quiet '[^[:space:]]' messages.txt
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index afc41298ba..74c13f98fa 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -2,7 +2,7 @@
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
-name: Scorecards supply-chain security
+name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
@@ -10,7 +10,7 @@ on:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- - cron: '22 4 * * 2'
+ - cron: '39 3 * * 5'
# push:
# branches: [ "master" ]
@@ -19,8 +19,10 @@ permissions: read-all
jobs:
analysis:
- name: Scorecards analysis
+ name: Scorecard analysis
runs-on: ubuntu-latest
+ # `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
+ if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
@@ -31,21 +33,21 @@ jobs:
# actions: read
steps:
- - name: 'Checkout code'
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - name: "Checkout code"
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- - name: 'Run analysis'
- uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
- # (Optional) Read-only PAT token. Uncomment the `repo_token` line below if:
+ # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
- # - you are installing Scorecards on a *private* repository
- # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
- repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
+ # - you are installing Scorecard on a *private* repository
+ # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
+ # repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
@@ -56,17 +58,21 @@ jobs:
# of the value entered here.
publish_results: true
+ # (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
+ # file_mode: git
+
# 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.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@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
+ # Upload the results to GitHub's code scanning dashboard (optional).
+ # Commenting out will disable upload of results to your repo's Code Scanning dashboard
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
with:
sarif_file: results.sarif
diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index 37d58cea24..856b6e434e 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -29,11 +29,9 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
strategy:
@@ -41,15 +39,17 @@ jobs:
# Specs from ruby/spec should still run on all supported Ruby versions.
# This also ensures the needed ruby_version_is guards are there, see spec/README.md.
ruby:
- - ruby-3.1
- - ruby-3.2
- ruby-3.3
- ruby-3.4
+ - ruby-4.0
+ fail-fast: false
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- - uses: ruby/setup-ruby@4a9ddd6f338a97768b8006bf671dfbad383215f4 # v1.207.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
diff --git a/.github/workflows/sync_default_gems.yml b/.github/workflows/sync_default_gems.yml
new file mode 100644
index 0000000000..9fd1945449
--- /dev/null
+++ b/.github/workflows/sync_default_gems.yml
@@ -0,0 +1,80 @@
+name: Sync default gems
+
+env:
+ DEFAULT_GEM_SYNC_ENABLED: true
+
+on:
+ workflow_dispatch:
+ inputs:
+ gem:
+ required: true
+ description: 'Name of the gem to be synchronized'
+ type: string
+ before:
+ required: true
+ description: 'Gem commit SHA before sync'
+ type: string
+ after:
+ required: true
+ description: 'Gem commit SHA after sync'
+ type: string
+
+permissions:
+ contents: read
+
+jobs:
+ sync_default_gems:
+ name: Sync default gem ${{ github.event.inputs.gem }}
+
+ permissions:
+ contents: write # for Git to git push
+
+ runs-on: ubuntu-latest
+
+ if: ${{ github.repository == 'ruby/ruby' }}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # zizmor: ignore[artipacked]
+ name: Check out ruby/ruby
+ with:
+ token: ${{ github.repository == 'ruby/ruby' && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.4'
+ bundler: none
+
+ - name: Run tool/sync_default_gems.rb
+ id: sync
+ run: |
+ ruby_before=$(git rev-parse HEAD)
+ set -x
+ ruby tool/sync_default_gems.rb "${gem_name}" "${gem_before}..${gem_after}"
+ if [[ "$(git rev-parse HEAD)" != "$ruby_before" ]]; then
+ echo update=true >> $GITHUB_OUTPUT
+ fi
+ env:
+ gem_name: ${{ github.event.inputs.gem }}
+ gem_before: ${{ github.event.inputs.before }}
+ gem_after: ${{ github.event.inputs.after }}
+ EMAIL: svn-admin@ruby-lang.org
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+
+ - name: Push
+ run: |
+ git pull --rebase origin ${GITHUB_REF#refs/heads/}
+ git push origin ${GITHUB_REF#refs/heads/}
+ if: ${{ steps.sync.outputs.update && env.DEFAULT_GEM_SYNC_ENABLED == 'true' }}
+ env:
+ EMAIL: svn-admin@ruby-lang.org
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+
+ - uses: ./.github/actions/slack
+ with:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ label: "${{ github.event.inputs.gem }} (<https://github.com/${{ github.event.inputs.gem == 'rubygems' && 'rubygems' || 'ruby' }}/${{ github.event.inputs.gem }}/compare/${{ github.event.inputs.before }}...${{ github.event.inputs.after }}|diff>)"
+ event_name: workflow_dispatch
+ extra_channel_id: C05FPKAU743 # alerts-sync
+ if: ${{ failure() }}
diff --git a/.github/workflows/tarball-macos.yml b/.github/workflows/tarball-macos.yml
new file mode 100644
index 0000000000..9bec94d528
--- /dev/null
+++ b/.github/workflows/tarball-macos.yml
@@ -0,0 +1,101 @@
+name: tarball-macos (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ archname:
+ description: 'archname (e.g. snapshot-master, snapshot-ruby_3_3)'
+ required: true
+ type: string
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (schedule/release builds).'
+ required: false
+ type: boolean
+ default: false
+ secrets:
+ SIMPLER_ALERTS_URL:
+ required: false
+ SNAPSHOT_SLACK_WEBHOOK_URL:
+ required: false
+
+permissions:
+ contents: read
+
+jobs:
+ macos:
+ strategy:
+ matrix:
+ test_task: [check, test-bundled-gems, test-bundler-parallel]
+ os: [macos-26, macos-15, macos-14]
+ include:
+ - os: macos-15-intel
+ test_task: check
+ fail-fast: false
+ runs-on: ${{ matrix.os }}
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ steps:
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: tar xf pkg/*.tar.xz
+ - name: Install libraries
+ run: |
+ with_retry () {
+ "$@" || { sleep 5 && "$@"; } || { sleep 60 && "$@"; }
+ }
+ set -x
+ with_retry brew install gmp libffi openssl zlib autoconf automake libtool libyaml
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(sysctl -n hw.activecpu)))" >> $GITHUB_ENV
+ - name: configure
+ run: cd "$ARCHNAME/" && ./configure --with-openssl-dir=$(brew --prefix openssl) --with-libyaml-dir=$(brew --prefix libyaml)
+ - name: make
+ run: cd "$ARCHNAME/" && make $JOBS
+ - name: Tests
+ run: cd "$ARCHNAME/" && make $JOBS -s ${{ matrix.test_task }}
+ env:
+ RUBY_TESTOPTS: "-q --tty=no"
+ RUBY_DEBUG_TEST_NO_REMOTE: "1"
+ # leaked-globals since 2.7
+ - name: Leaked Globals
+ run: cd "$ARCHNAME/" && make -s leaked-globals
+ if: matrix.test_task == 'check'
+ - name: make install without root privilege
+ run: cd "$ARCHNAME/" && make $JOBS install DESTDIR="/tmp/destdir"
+ if: matrix.test_task == 'check'
+ - name: make install
+ run: cd "$ARCHNAME/" && sudo make $JOBS install
+ if: matrix.test_task == 'check'
+ - name: Verify installed binaries
+ run: |
+ /usr/local/bin/ruby -v
+ /usr/local/bin/gem -v
+ /usr/local/bin/bundle -v
+ if: matrix.test_task == 'check'
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout: .github/actions/slack
+ sparse-checkout-cone-mode: false
+ persist-credentials: false
+ if: ${{ failure() }}
+ - uses: ./.github/actions/slack
+ with:
+ label: "${{ matrix.os }} / ${{ matrix.test_task }}"
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
+ with:
+ payload: |
+ {
+ "attachments": [{
+ "text": "${{ job.status }}: ${{ matrix.os }} / ${{ matrix.test_task }} <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ inputs.archname }}>",
+ "color": "danger"
+ }]
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+ if: failure() && inputs.notify-release-channel
diff --git a/.github/workflows/tarball-non-development.yml b/.github/workflows/tarball-non-development.yml
new file mode 100644
index 0000000000..db6230b301
--- /dev/null
+++ b/.github/workflows/tarball-non-development.yml
@@ -0,0 +1,87 @@
+name: tarball-non-development (reusable)
+
+on:
+ workflow_call: {}
+
+permissions:
+ contents: read
+
+jobs:
+ non_development:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - { variant: default, remove_ruby: false, configure_extra: '' }
+ - { variant: no-ruby, remove_ruby: true, configure_extra: '' }
+ - { variant: baseruby-no, remove_ruby: false, configure_extra: '--with-baseruby=no' }
+ runs-on: ubuntu-24.04
+ env:
+ ruby_prefix: /tmp/ruby-snapshot
+ steps:
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: tar xf pkg/*.tar.xz
+ - name: Substitute patchlevel
+ run: |
+ set -x
+ cd snapshot-*/
+ sed -i.orig 's/^\( *# *define *RUBY_PATCHLEVEL\) *-.*/\1 0/' version.h
+ diff -u version.h.orig version.h || :
+ rm -f version.h.orig
+ - 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 zlib1g-dev libffi-dev libgmp-dev bison- autoconf-
+ - name: Remove host ruby
+ if: matrix.remove_ruby
+ run: |
+ set -x
+ sudo apt-get purge -y -q 'ruby*' || :
+ sudo rm -rf /opt/hostedtoolcache/Ruby
+ ! command -v ruby
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: configure
+ run: cd snapshot-*/ && ./configure --prefix="${ruby_prefix}" ${{ matrix.configure_extra }}
+ - name: make
+ run: cd snapshot-*/ && make $JOBS
+ - name: Leaked Globals
+ run: cd snapshot-*/ && make -s leaked-globals
+ - name: make install
+ run: cd snapshot-*/ && make $JOBS install
+ - name: Set PATH
+ run: echo "PATH=${ruby_prefix}/bin:$PATH" >> $GITHUB_ENV
+ - name: Check patchlevel
+ id: check-patchlevel
+ run: |
+ exec "${ruby_prefix}/bin/ruby" -vx "$0"
+ #!ruby
+ puts "RUBY_PATCHLEVEL=#{RUBY_PATCHLEVEL.inspect}"
+ abort unless RUBY_PATCHLEVEL >= 0
+ working-directory: ${{ env.ruby_prefix }}
+ continue-on-error: true
+ - name: Check LOADPATH
+ id: check-loadpath
+ run: |
+ exec ${ruby_prefix}/bin/ruby -vx "$0"
+ #!ruby
+ paths = $:.grep(/\+/)
+ pp paths
+ abort unless paths.empty?
+ working-directory: ${{ env.ruby_prefix }}
+ continue-on-error: true
+ - name: Check pathnames
+ id: check-pathnames
+ run: |
+ ! find -name '*+*' | grep +
+ working-directory: ${{ env.ruby_prefix }}
+ continue-on-error: true
+ - name: result
+ run: false
+ if: ${{ contains(steps.*.outcome, 'failure') }}
diff --git a/.github/workflows/tarball-test-schedule.yml b/.github/workflows/tarball-test-schedule.yml
new file mode 100644
index 0000000000..6684b09edb
--- /dev/null
+++ b/.github/workflows/tarball-test-schedule.yml
@@ -0,0 +1,26 @@
+name: tarball-test-schedule
+on:
+ schedule:
+ - cron: '30 18 * * *' # Daily at 18:30 UTC
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ dispatch:
+ if: ${{ github.event_name != 'schedule' || github.repository == 'ruby/ruby' }}
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ branch:
+ - master
+ - ruby_4_0
+ - ruby_3_4
+ - ruby_3_3
+ steps:
+ - name: Trigger tarball-test on ${{ matrix.branch }}
+ run: gh workflow run tarball-test.yml --ref "$BRANCH" --repo "$GITHUB_REPOSITORY" -f notify-release-channel=true
+ env:
+ BRANCH: ${{ matrix.branch }}
+ GH_TOKEN: ${{ secrets.MATZBOT_GITHUB_ACTION_TOKEN }}
diff --git a/.github/workflows/tarball-test.yml b/.github/workflows/tarball-test.yml
new file mode 100644
index 0000000000..c862ab76cc
--- /dev/null
+++ b/.github/workflows/tarball-test.yml
@@ -0,0 +1,104 @@
+name: tarball-test
+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:
+ workflow_dispatch:
+ inputs:
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (set by tarball-test-schedule).'
+ type: boolean
+ default: false
+
+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:
+ tarball:
+ runs-on: ubuntu-latest
+ # Cherry-pick to maintenance branches by changing only env.BRANCH below;
+ # archname / branch-label / Materialize all derive from it.
+ env:
+ BRANCH: master
+ outputs:
+ branch: ${{ env.BRANCH }}
+ skip: ${{ steps.skipping.outputs.skip }}
+ steps:
+ - id: skipping
+ run: echo 'skip=true' >> $GITHUB_OUTPUT
+ 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.pull_request.user.login == 'dependabot[bot]')
+ )}}
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ fetch-depth: 1 # actions/checkout fetches all heads/tags unless > 0
+ persist-credentials: false
+ # tool/make-snapshot derives the branch name from HEAD and looks up
+ # the upstream during ChangeLog generation. Detached checkouts
+ # (pull_request, merge_group) lack a local branch with tracking, so
+ # pin one to HEAD and connect it to the matching origin ref.
+ - name: Materialize local branch
+ run: |
+ git fetch --no-tags --depth=1 origin "+refs/heads/$BASE:refs/remotes/origin/$BASE"
+ git checkout -B "$BRANCH" HEAD
+ git branch --set-upstream-to="origin/$BASE" "$BRANCH"
+ env:
+ BASE: ${{ github.base_ref || env.BRANCH }}
+ - uses: ./.github/actions/make-snapshot
+ with:
+ archname: snapshot-${{ env.BRANCH }}
+ srcdir: '.'
+
+ ubuntu:
+ needs: tarball
+ if: ${{ ! needs.tarball.outputs.skip }}
+ uses: ./.github/workflows/tarball-ubuntu.yml
+ with:
+ archname: snapshot-${{ needs.tarball.outputs.branch }}
+ notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }}
+ secrets:
+ SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }}
+ SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+
+ macos:
+ needs: tarball
+ if: ${{ ! needs.tarball.outputs.skip }}
+ uses: ./.github/workflows/tarball-macos.yml
+ with:
+ archname: snapshot-${{ needs.tarball.outputs.branch }}
+ notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }}
+ secrets:
+ SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }}
+ SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+
+ windows:
+ needs: tarball
+ if: ${{ ! needs.tarball.outputs.skip }}
+ uses: ./.github/workflows/tarball-windows.yml
+ with:
+ archname: snapshot-${{ needs.tarball.outputs.branch }}
+ notify-release-channel: ${{ github.event_name == 'workflow_dispatch' && inputs.notify-release-channel || false }}
+ secrets:
+ SIMPLER_ALERTS_URL: ${{ secrets.SIMPLER_ALERTS_URL }}
+ SNAPSHOT_SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+
+ non_development:
+ needs: tarball
+ uses: ./.github/workflows/tarball-non-development.yml
diff --git a/.github/workflows/tarball-ubuntu.yml b/.github/workflows/tarball-ubuntu.yml
new file mode 100644
index 0000000000..e227dc29aa
--- /dev/null
+++ b/.github/workflows/tarball-ubuntu.yml
@@ -0,0 +1,151 @@
+name: tarball-ubuntu (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ archname:
+ description: 'archname (e.g. snapshot-master, snapshot-ruby_3_3)'
+ required: true
+ type: string
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (schedule/release builds).'
+ required: false
+ type: boolean
+ default: false
+ secrets:
+ SIMPLER_ALERTS_URL:
+ required: false
+ SNAPSHOT_SLACK_WEBHOOK_URL:
+ required: false
+
+permissions:
+ contents: read
+
+jobs:
+ ubuntu:
+ strategy:
+ matrix:
+ test_task: [check, test-bundler-parallel, test-bundled-gems]
+ os: [ubuntu-24.04, ubuntu-22.04]
+ fail-fast: false
+ runs-on: ${{ matrix.os }}
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ steps:
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: tar xf pkg/*.tar.xz
+ - 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 zlib1g-dev libffi-dev libgmp-dev bison- autoconf-
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.2'
+ # test-bundled-gems requires executable host ruby
+ if: matrix.test_task == 'test-bundled-gems'
+ - name: Fixed world writable dirs
+ run: |
+ mkdir -p $HOME/.local/share
+ mkdir -p $HOME/.cache/gem/specs
+ mkdir -p $HOME/.bundle/cache
+ mkdir -p $HOME/.ssh
+ chmod a-w $HOME/.bundle
+ # chmod a-w $HOME
+ # allow to write $HOME and check stats of HOME around tests (see below)
+ chmod -v a-w $HOME/.config
+ sudo chmod -R a-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v a-w $d; done' || :
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: configure
+ run: cd "$ARCHNAME/" && ./configure
+ - name: make
+ run: cd "$ARCHNAME/" && make $JOBS
+ - name: Save stats of HOME
+ run: |
+ set -euxo pipefail
+ cat >"$ARCHNAME/save-stats.rb" <<'EOF'
+ require 'pathname'
+ require 'digest'
+ out = []
+ [
+ Dir.home,
+ ].each do |dir|
+ Dir.each_child(dir) do |name|
+ pn = File.join(dir, name)
+ st = File.stat(pn)
+ if st.file?
+ content = Digest::SHA1.file(pn).hexdigest
+ elsif st.directory? && st.nlink <= 10
+ content = Dir.children(pn).sort
+ end
+ out << [pn, "%o"%st.mode, st.nlink, st.uid, st.gid, st.size, content].to_s
+ rescue
+ out << [pn, $!.inspect].to_s
+ end
+ end
+ File.open(ARGV.shift, "w") do |io|
+ io.puts out.sort
+ end
+ EOF
+ make -C "$ARCHNAME" TESTRUN_SCRIPT=save-stats.rb RUNOPT=/tmp/stat-before-tests.txt runruby
+ - name: Tests
+ run: cd "$ARCHNAME/" && make $JOBS -s ${{ matrix.test_task }}
+ env:
+ RUBY_TESTOPTS: "-q --tty=no"
+ # test_sync_default_gems triggers gpg, whose agent processes leave
+ # $HOME/.gnupg around even when GNUPGHOME points elsewhere.
+ - name: Forcibly remove ~/.gnupg
+ run: rm -rf $HOME/.gnupg
+ - name: Diff stats of HOME
+ run: |
+ make -C "$ARCHNAME" TESTRUN_SCRIPT=save-stats.rb RUNOPT=/tmp/stat-after-tests.txt runruby
+ rm -f "$ARCHNAME/save-stats.rb"
+ diff -u /tmp/stat-before-tests.txt /tmp/stat-after-tests.txt
+ # leaked-globals since 2.7
+ - name: Leaked Globals
+ run: cd "$ARCHNAME/" && make -s leaked-globals
+ if: matrix.test_task == 'check'
+ - name: make install without root privilege
+ run: cd "$ARCHNAME/" && make $JOBS install DESTDIR="/tmp/destdir"
+ if: matrix.test_task == 'check'
+ - name: make install
+ run: cd "$ARCHNAME/" && sudo make $JOBS install
+ if: matrix.test_task == 'check'
+ - name: Verify installed binaries
+ run: |
+ /usr/local/bin/ruby -v
+ /usr/local/bin/gem -v
+ /usr/local/bin/bundle -v
+ if: matrix.test_task == 'check'
+ - name: Show .local
+ run: find $HOME/.local -ls
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout: .github/actions/slack
+ sparse-checkout-cone-mode: false
+ persist-credentials: false
+ if: ${{ failure() }}
+ - uses: ./.github/actions/slack
+ with:
+ label: "${{ matrix.os }} / ${{ matrix.test_task }}"
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
+ with:
+ payload: |
+ {
+ "attachments": [{
+ "text": "${{ job.status }}: ${{ matrix.os }} / ${{ matrix.test_task }} <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ inputs.archname }}>",
+ "color": "danger"
+ }]
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+ if: failure() && inputs.notify-release-channel
diff --git a/.github/workflows/tarball-windows.yml b/.github/workflows/tarball-windows.yml
new file mode 100644
index 0000000000..1ce95de6fc
--- /dev/null
+++ b/.github/workflows/tarball-windows.yml
@@ -0,0 +1,163 @@
+name: tarball-windows (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ archname:
+ description: 'archname (e.g. snapshot-master)'
+ required: true
+ type: string
+ notify-release-channel:
+ description: 'Also send failure notifications to SNAPSHOT_SLACK_WEBHOOK_URL (schedule/release builds).'
+ required: false
+ type: boolean
+ default: false
+ secrets:
+ SIMPLER_ALERTS_URL:
+ required: false
+ SNAPSHOT_SLACK_WEBHOOK_URL:
+ required: false
+
+permissions:
+ contents: read
+
+jobs:
+ windows:
+ strategy:
+ matrix:
+ include:
+ - os: '2022'
+ test_task: check
+ - os: '2025-vs2026'
+ test_task: check
+ fail-fast: false
+ runs-on: windows-${{ matrix.os }}
+ defaults:
+ run:
+ shell: cmd
+ working-directory: build
+ name: Windows ${{ matrix.os }} (${{ matrix.test_task }})
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ PATCH: C:\msys64\usr\bin\patch.exe
+ OS_VER: windows-${{ matrix.os }}
+ # see https://github.com/ruby/ruby/commit/9ff4399decef0036897d3cfb9ac2c710dea913ca
+ OPENSSL_MODULES: C:\vcpkg\installed\x64-windows\bin
+ steps:
+ - run: md build
+ working-directory:
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.2'
+ bundler: none
+ windows-toolchain: none
+
+ - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1
+ id: setup-msys2
+ with:
+ update: true
+ install: >-
+ patch
+ - name: patch path
+ shell: msys2 {0}
+ run: echo PATCH=$(cygpath -wa $(command -v patch)) >> $GITHUB_ENV
+ if: ${{ steps.setup-msys2.outcome == 'success' }}
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
+ with:
+ path: C:\vcpkg\installed
+ key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-
+ ${{ runner.os }}-vcpkg-installed-
+ - name: Install libraries with vcpkg
+ run: |
+ vcpkg --triplet x64-windows install gmp libffi libyaml openssl zlib
+
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: Packages
+ path: pkg
+ - name: Extract
+ run: 7z x pkg/*.zip
+ working-directory:
+
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
+ with:
+ path: snapshot-*/.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
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ run: |
+ set > old.env
+ call ..\%ARCHNAME%\win32\vssetup.cmd
+ set TMP=%USERPROFILE%\AppData\Local\Temp
+ set TEMP=%USERPROFILE%\AppData\Local\Temp
+ set /a TEST_JOBS=(15 * %NUMBER_OF_PROCESSORS% / 10) > nul
+ set > new.env
+
+ - name: update env
+ shell: pwsh
+ run: |
+ $old = (Get-Content old.env); $new = (Get-Content new.env)
+ del *.env
+ Compare-Object $old $new |
+ Where-Object { $_.SideIndicator -eq '=>' } |
+ Select-Object -ExpandProperty InputObject |
+ Add-Content -Path $env:GITHUB_ENV
+ - name: link libraries
+ run: |
+ for %%I in (C:\vcpkg\installed\x64-windows\bin\*.dll) do (
+ mklink %%~nxI %%I
+ )
+ - name: Configure
+ env:
+ ARCHNAME: ${{ inputs.archname }}
+ run: >-
+ ../%ARCHNAME%/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
+
+ - name: ruby -v
+ run: .\ruby -v
+
+ - run: nmake test
+ timeout-minutes: 5
+
+ - run: nmake ${{ matrix.test_task }}
+ env:
+ RUBY_TESTOPTS: -j${{env.TEST_JOBS}}
+ timeout-minutes: 70
+ continue-on-error: ${{ matrix.continue-on-error || false }}
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout: .github/actions/slack
+ sparse-checkout-cone-mode: false
+ persist-credentials: false
+ if: ${{ failure() }}
+ - uses: ./.github/actions/slack
+ with:
+ label: "${{ env.OS_VER }} / ${{ matrix.test_task }}"
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+ - uses: ruby/action-slack@d260b61aa817726d5bedd22dd6cc305787fa4cdd # v4.0.0
+ with:
+ payload: |
+ {
+ "attachments": [{
+ "text": "${{ job.status }}: ${{ env.OS_VER }} / ${{ matrix.test_task }} <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ inputs.archname }}>",
+ "color": "danger"
+ }]
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SNAPSHOT_SLACK_WEBHOOK_URL }}
+ if: failure() && inputs.notify-release-channel
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index f14e68f0e8..09e96f764c 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -24,6 +24,7 @@ jobs:
make:
strategy:
matrix:
+ # We enumerate every job in matrix.include to save build time
include:
- test_task: check
configure: 'cppflags=-DVM_CHECK_MODE'
@@ -38,11 +39,13 @@ jobs:
- test_task: test-bundled-gems
- test_task: check
os: ubuntu-24.04
- - test_task: check
- os: ubuntu-24.04-arm
+ extra_checks: [capi]
+ # ubuntu-24.04-arm jobs don't start on ruby/ruby as of 2025-10-29
+ #- test_task: check
+ # os: ubuntu-24.04-arm
fail-fast: false
- env:
+ env: &make-env
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
RUBY_DEBUG: ci
@@ -51,28 +54,29 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ steps: &make-steps
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
with:
arch: ${{ matrix.arch }}
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- ruby-version: '3.0'
+ ruby-version: '3.1'
bundler: none
- if: ${{ !endsWith(matrix.os, 'arm') }}
+ if: >-
+ ${{ !endsWith(matrix.os, 'arm')
+ && !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }}
- uses: ./.github/actions/setup/directories
with:
@@ -89,7 +93,7 @@ jobs:
arch: ${{ matrix.arch }}
configure: ${{ matrix.configure }}
run: >-
- $SETARCH ../src/configure -C --disable-install-doc ${configure:-cppflags=-DRUBY_DEBUG}
+ $SETARCH ../src/configure -C --disable-install-doc ${configure:- --enable-debug-env cppflags=-DRUBY_DEBUG}
${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
- run: $SETARCH make prepare-gems
@@ -99,6 +103,10 @@ jobs:
- run: $SETARCH make hello
+ - name: runirb
+ run: |
+ echo IRB::VERSION | $SETARCH make runirb RUNOPT="-- -f"
+
- name: Set test options for skipped tests
run: |
set -x
@@ -107,6 +115,7 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
- name: Set up Launchable
+ id: launchable
uses: ./.github/actions/launchable/setup
with:
os: ${{ matrix.os || 'ubuntu-22.04' }}
@@ -115,14 +124,19 @@ jobs:
builddir: build
srcdir: src
continue-on-error: true
+ timeout-minutes: 3
+
+ # Avoid possible test failures with the zlib applying the following patch
+ # on s390x CPU architecture.
+ # https://github.com/madler/zlib/pull/410
+ - name: Disable DFLTCC
+ run: echo "DFLTCC=0" >> $GITHUB_ENV
+ if: ${{ endsWith(matrix.os, 's390x') }}
- name: make ${{ matrix.test_task }}
run: |
- if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
- exec \
- > >(tee launchable_stdout.log) \
- 2> >(tee launchable_stderr.log)
- fi
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
$SETARCH make -s ${{ matrix.test_task }} \
${TESTS:+TESTS="$TESTS"} \
@@ -130,8 +144,10 @@ jobs:
timeout-minutes: ${{ matrix.timeout || 40 }}
env:
RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
PRECHECK_BUNDLED_GEMS: 'no'
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
- name: make skipped tests
run: |
@@ -142,9 +158,105 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
+ - name: test-pc
+ run: |
+ DESTDIR=${RUNNER_TEMP-${TMPDIR-/tmp}}/installed
+ $SETARCH make test-pc "DESTDIR=$DESTDIR"
+
+ - name: CAPI extensions
+ uses: ./.github/actions/capiext
+ with:
+ builddir: build
+ make: '$SETARCH make'
+ env:
+ RUBY_TESTOPTS: '-v --tty=no'
+ if: ${{ contains(matrix.extra_checks, 'capi') }}
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}${{ matrix.os }}
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() }}
+
+ make-ibm:
+ strategy:
+ matrix:
+ include:
+ - test_task: check
+ os: ubuntu-24.04-ppc64le
+ - test_task: check
+ os: ubuntu-24.04-s390x
+ fail-fast: false
+
+ env: *make-env
+
+ runs-on: ${{ matrix.os }}
+
+ 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.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps: *make-steps
+
+ # Separated from `make` job to avoid making it a required status check
+ ruby-bench:
+ strategy:
+ matrix:
+ include:
+ # Using the same setup as ZJIT jobs
+ - bench_opts: '--warmup=1 --bench=1 --excludes=shipit'
+
+ runs-on: ubuntu-24.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.pull_request.user.login == 'dependabot[bot]')
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - 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"
+
+ - run: make install
+
+ - name: Checkout ruby-bench
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ repository: ruby/ruby-bench
+ persist-credentials: false
+ path: ruby-bench
+
+ # If you want to skip failing benchmark, consider using `--excludes`.
+ # e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
+ - name: Run ruby-bench
+ run: ruby run_benchmarks.rb -e "ruby::../build/install/bin/ruby" ${{ matrix.bench_opts }}
+ working-directory: ruby-bench
+ env:
+ BUNDLER_VERSION: 0
+
- uses: ./.github/actions/slack
with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}
+ label: ruby-bench ${{ matrix.bench_opts }} ${{ matrix.ruby_opts }}
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
if: ${{ failure() }}
diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml
index f5c8ca62d1..edb2c76c48 100644
--- a/.github/workflows/wasm.yml
+++ b/.github/workflows/wasm.yml
@@ -53,18 +53,22 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.1'
+ bundler: none
- uses: ./.github/actions/setup/directories
with:
@@ -100,19 +104,10 @@ jobs:
run: |
echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ./.github/actions/setup/baseruby
+ id: baseruby
with:
- ruby-version: '3.0'
- bundler: none
-
- - name: Build baseruby
- run: |
- set -ex
- mkdir ../baseruby
- pushd ../baseruby
- ../src/configure --prefix=$PWD/install
- make
- make install
+ srcdir: src
- name: Download config.guess with wasi version
run: |
@@ -121,19 +116,38 @@ jobs:
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=cgi/escape,continuation,coverage,date,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,json,json/generator,json/parser,objspace,pathname,rbconfig/sizeof,ripper,stringio,strscan,monitor \
- LDFLAGS=" \
- -Xlinker --stack-first \
- -Xlinker -z -Xlinker stack-size=16777216 \
- " \
- optflags="${{ matrix.entry.optflags }}" \
- debugflags="${{ matrix.entry.debugflags }}" \
- wasmoptflags="${{ matrix.entry.wasmoptflags }} ${{ matrix.entry.debugflags }}"
+ run: >-
+ ../src/configure
+ --host wasm32-unknown-wasi
+ --with-baseruby="${{ steps.baseruby.outputs.ruby }}"
+ --with-dump-ast="${{ steps.baseruby.outputs.dump_ast }}"
+ --with-static-linked-ext
+ --with-ext=${EXTS// /,}
+ LDFLAGS="
+ -Xlinker --stack-first
+ -Xlinker -z -Xlinker stack-size=16777216
+ "
+ optflags="${{ matrix.entry.optflags }}"
+ debugflags="${{ matrix.entry.debugflags }}"
+ wasmoptflags="${{ matrix.entry.wasmoptflags }} ${{ matrix.entry.debugflags }}"
+ env:
+ EXTS:
+ cgi/escape
+ continuation
+ coverage
+ date
+ digest
+ digest/*
+ erb/escape
+ etc
+ fcntl
+ json
+ json/*
+ objspace
+ rbconfig/sizeof
+ ripper
+ stringio
+ strscan
# miniruby may not be built when cross-compling
- run: make mini ruby
@@ -142,7 +156,7 @@ jobs:
- run: tar cfz ../install.tar.gz -C ../install .
- name: Upload artifacts
- uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ruby-wasm-install
path: ${{ github.workspace }}/install.tar.gz
@@ -170,7 +184,7 @@ jobs:
- name: Save Pull Request number
if: ${{ github.event_name == 'pull_request' }}
run: echo "${{ github.event.pull_request.number }}" >> ${{ github.workspace }}/github-pr-info.txt
- - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ github.event_name == 'pull_request' }}
with:
name: github-pr-info
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index d13d20df9b..13551427bb 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -25,120 +25,114 @@ jobs:
strategy:
matrix:
include:
- - vc: 2015
- vs: 2019
- vcvars: '10.0.14393.0 -vcvars_ver=14.0' # The oldest Windows 10 SDK w/ VC++ 2015 toolset (v140)
+ - os: 2022
test_task: check
- - vs: 2019
+ - os: 2022
+ test_task: test-bundled-gems
+ - os: 2025-vs2026
test_task: check
- - vs: 2019
+ - os: 2025-vs2026
test_task: test-bundled-gems
- # - vs: 2022
- # test_task: check
+ - os: 11-arm
+ test_task: 'btest test-basic test-tool' # check and test-spec are broken yet.
+ target: arm64
fail-fast: false
- runs-on: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
+ runs-on: windows-${{ matrix.os }}
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/vcpkg'))
)}}
- name: VisualStudio ${{ matrix.vc || matrix.vs }} (${{ matrix.test_task }})
+ name: Windows ${{ matrix.os }} (${{ matrix.test_task }})
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- OS_VER: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
VCPKG_DEFAULT_TRIPLET: ${{ matrix.target || 'x64' }}-windows
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
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- update: true
- install: >-
- ${{ steps.find-tools.outputs.needs }}
- if: ${{ steps.find-tools.outputs.needs != '' }}
-
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
- with:
- ruby-version: '3.0'
+ # windows-11-arm has only 3.4.1, 3.4.2, 3.4.3, head
+ ruby-version: ${{ !endsWith(matrix.os, 'arm') && '3.1' || '3.4' }}
bundler: none
windows-toolchain: none
- - name: Export GitHub Actions cache environment variables
- uses: actions/github-script@v7
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ sparse-checkout-cone-mode: false
+ sparse-checkout: /.github
+
+ - uses: ./.github/actions/setup/directories
with:
- script: |
- core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
- core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
+ srcdir: src
+ builddir: build
+ make-command: nmake
+ clean: true
- - name: Install libraries with scoop
+ - name: Install tools with scoop
run: |
- iex "& {$(irm get.scoop.sh)} -RunAsAdmin"
+ if ((vcpkg.exe help install) -match "manifest") { exit }
+ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+ iwr -useb get.scoop.sh | iex
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
scoop install vcpkg
shell: pwsh
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - name: Restore vcpkg artifact
+ id: restore-vcpkg
+ uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
+ path: src\vcpkg_installed
+ key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
- - uses: ./.github/actions/setup/directories
+ - name: Install libraries with vcpkg
+ run: |
+ vcpkg install
+ working-directory: src
+ if: ${{ ! steps.restore-vcpkg.outputs.cache-hit }}
+
+ - name: Save vcpkg artifact
+ uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
- srcdir: src
- builddir: build
+ path: src\vcpkg_installed
+ key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
+ if: ${{ ! steps.restore-vcpkg.outputs.cache-hit && (github.ref_name == 'master' || startsWith(github.ref_name, 'ruby_')) }}
- name: setup env
# Available Ruby versions: https://github.com/actions/runner-images/blob/main/images/windows/Windows2019-Readme.md#ruby
# %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
# https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
run: |
- ::- Set up VC ${{ matrix.vc || matrix.vs }}
- set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
- for /f "delims=;" %%I in ('%vswhere% -latest -property installationPath') do (
- set VCVARS="%%I\VC\Auxiliary\Build\vcvars64.bat"
- )
- set VCVARS
- set | C:\msys64\usr\bin\sort > old.env
- call %VCVARS% ${{ matrix.vcvars || '' }}
+ set > old.env
+ call ..\src\win32\vssetup.cmd ^
+ -arch=${{ matrix.target || 'amd64' }} ^
+ ${{ matrix.vcvars && '-vcvars_ver=' || '' }}${{ matrix.vcvars }}
nmake -f nul
- set TMP=%USERPROFILE%\AppData\Local\Temp
- set TEMP=%USERPROFILE%\AppData\Local\Temp
+ set TMP=%RUNNER_TEMP%
+ set TEMP=%RUNNER_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%
+ set RUBY_OPT_DIR=%GITHUB_WORKSPACE:\=/%/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET%
+ set > new.env
+
+ - name: update env
+ shell: pwsh
+ run: |
+ $old = (Get-Content old.env); $new = (Get-Content new.env)
del *.env
+ Compare-Object $old $new |
+ Where-Object { $_.SideIndicator -eq '=>' } |
+ Select-Object -ExpandProperty InputObject |
+ Add-Content -Path $env:GITHUB_ENV
- name: baseruby version
run: ruby -v
@@ -150,18 +144,11 @@ jobs:
run: Get-Volume
shell: pwsh
- - name: Install libraries with vcpkg
- run: |
- vcpkg install
- working-directory: src
- env:
- VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
-
# TODO: We should use `../src` instead of `D:/a/ruby/ruby/src`
- name: Configure
run: >-
../src/win32/configure.bat --disable-install-doc
- --with-opt-dir=D:/a/ruby/ruby/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET%
+ --with-opt-dir=%RUBY_OPT_DIR%
--with-gmp
- run: nmake prepare-vcpkg
@@ -174,18 +161,26 @@ jobs:
# But not for this Visual Studio workflow. So here we extract gems before building.
- run: nmake extract-gems
+ # windows-11-arm runner cannot run `ruby tool/file2lastrev.rb --revision.h --output=revision.h`
+ - name: make revision.h
+ run: |
+ win32\lastrev.bat | win32\ifchange.bat --timestamp=.revision.time revision.h -
+ type revision.h
+ working-directory: src
+
- run: nmake
- name: Set up Launchable
uses: ./.github/actions/launchable/setup
with:
- os: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
+ os: windows-${{ matrix.os }}
launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
builddir: build
srcdir: src
test-task: ${{ matrix.test_task || 'check' }}
continue-on-error: true
if: ${{ matrix.test_task != 'test-bundled-gems' }}
+ timeout-minutes: 3
- run: nmake ${{ matrix.test_task || 'check' }}
env:
@@ -194,14 +189,14 @@ jobs:
- uses: ./.github/actions/slack
with:
- label: VS${{ matrix.vc || matrix.vs }} / ${{ matrix.test_task || 'check' }}
+ label: Windows ${{ matrix.os }} / ${{ matrix.test_task || 'check' }}
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
+ runs-on: windows-2025-vs2026
needs: [make]
steps:
- run: exit 1
diff --git a/.github/workflows/wsl.yml b/.github/workflows/wsl.yml
index e6b4133b76..470b68fe66 100644
--- a/.github/workflows/wsl.yml
+++ b/.github/workflows/wsl.yml
@@ -14,24 +14,22 @@ on:
# 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:
+permissions:
+ contents: read
+
jobs:
wsl:
- runs-on: windows-latest
+ runs-on: windows-2025-vs2026
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- - name: Install winget
- uses: Cyberboss/install-winget@v1
-
- name: Install or update WSL
uses: Ubuntu/WSL/.github/actions/wsl-install@main
with:
diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml
index 930b1b3b31..b52c6355ad 100644
--- a/.github/workflows/yjit-macos.yml
+++ b/.github/workflows/yjit-macos.yml
@@ -1,6 +1,8 @@
-name: YJIT macOS Arm64
+name: YJIT macOS
on:
push:
+ branches:
+ - master
paths-ignore:
- 'doc/**'
- '**/man/*'
@@ -9,6 +11,10 @@ on:
- '**/.document'
- '.*.yml'
pull_request:
+ types:
+ - opened
+ - synchronize
+ - reopened
# 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:
@@ -24,20 +30,20 @@ jobs:
cargo:
name: cargo test
- runs-on: macos-14
+ runs-on: macos-26
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
- run: RUST_BACKTRACE=1 cargo test
working-directory: yjit
@@ -68,23 +74,22 @@ jobs:
RUN_OPTS: ${{ matrix.yjit_opts }}
SPECOPTS: ${{ matrix.specopts }}
- runs-on: macos-14
+ runs-on: macos-26
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- name: Install libraries
uses: ./.github/actions/setup/macos
@@ -106,8 +111,17 @@ jobs:
- run: make
- - name: Enable YJIT through ENV
- run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ - name: Verify that --yjit-dump-disasm works
+ run: |
+ ./miniruby --yjit-call-threshold=1 --yjit-dump-disasm -e0 | \
+ wc -l | \
+ ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
+ if: ${{ contains(matrix.configure, 'jit=dev') }}
+
+ - name: Set ENV for YJIT
+ run: |
+ echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
- name: Set test options for skipped tests
run: |
@@ -117,33 +131,35 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
- name: Set up Launchable
+ id: launchable
uses: ./.github/actions/launchable/setup
with:
- os: macos-14
+ os: macos-26
test-opts: ${{ matrix.configure }}
launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
builddir: build
srcdir: src
is-yjit: true
continue-on-error: true
+ timeout-minutes: 3
- name: make ${{ matrix.test_task }}
run: |
- if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
- exec \
- > >(tee launchable_stdout.log) \
- 2> >(tee launchable_stderr.log)
- fi
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+ set -x
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
RUN_OPTS="$RUN_OPTS" \
SPECOPTS="$SPECOPTS"
timeout-minutes: 60
env:
RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
SYNTAX_SUGGEST_TIMEOUT: '5'
PRECHECK_BUNDLED_GEMS: 'no'
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
continue-on-error: ${{ matrix.continue-on-test_task || false }}
- name: make skipped tests
@@ -156,6 +172,13 @@ jobs:
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
+
- uses: ./.github/actions/slack
with:
label: ${{ matrix.test_task }} ${{ matrix.configure }} ${{ matrix.yjit_opts }}
@@ -165,10 +188,11 @@ jobs:
result:
if: ${{ always() }}
name: ${{ github.workflow }} result
- runs-on: macos-14
+ runs-on: ubuntu-latest
needs: [make]
steps:
- - run: exit 1
+ - name: ${{ github.workflow }} jobs have failed
+ run: exit 1
working-directory:
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml
index 9ad5cdac8a..934c3f56d4 100644
--- a/.github/workflows/yjit-ubuntu.yml
+++ b/.github/workflows/yjit-ubuntu.yml
@@ -32,11 +32,13 @@ jobs:
|| 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.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
# For now we can't run cargo test --offline because it complains about the
# capstone dependency, even though the dependency is optional
@@ -64,11 +66,13 @@ jobs:
|| 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.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
# Check that we don't have linting errors in release mode, too
- run: cargo clippy --all-targets --all-features
@@ -81,7 +85,8 @@ jobs:
include:
- test_task: 'yjit-bindgen'
hint: 'To fix: use patch in logs'
- configure: '--with-gcc=clang-14 --enable-yjit=dev'
+ # Build with YJIT+ZJIT for output that works in the most number of configurations
+ configure: '--with-gcc=clang-14 --enable-yjit=dev --enable-zjit'
libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1'
- test_task: 'check'
@@ -101,18 +106,12 @@ jobs:
- test_task: 'test-bundled-gems'
configure: '--enable-yjit=dev'
- - test_task: 'yjit-bench'
- configure: '--enable-yjit=dev'
- yjit_bench_opts: '--yjit-stats'
- continue-on-test_task: true
-
env:
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
RUN_OPTS: ${{ matrix.yjit_opts }}
YJIT_BENCH_OPTS: ${{ matrix.yjit_bench_opts }}
SPECOPTS: ${{ matrix.specopts }}
RUBY_DEBUG: ci
- BUNDLE_JOBS: 8 # for yjit-bench
RUST_BACKTRACE: 1
runs-on: ubuntu-22.04
@@ -120,24 +119,23 @@ jobs:
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
)}}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github
+ persist-credentials: false
- uses: ./.github/actions/setup/ubuntu
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
- ruby-version: '3.0'
+ ruby-version: '3.1'
bundler: none
- uses: ./.github/actions/setup/directories
@@ -153,6 +151,12 @@ jobs:
if: ${{ matrix.rust_version }}
run: rustup install ${{ matrix.rust_version }} --profile minimal
+ - name: Remove cargo
+ # Since this tests a `rustc` build for release, remove `cargo` to ensure
+ # that only `rustc` is used.
+ if: ${{ contains(matrix.configure, 'rustc') }}
+ run: sudo rm $(which -a cargo | uniq)
+
- name: Run configure
run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install ${{ matrix.configure }}
@@ -163,14 +167,24 @@ jobs:
- run: make
- - name: Enable YJIT through ENV
- run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ - name: Verify that --yjit-dump-disasm works
+ run: |
+ ./miniruby --yjit-call-threshold=1 --yjit-dump-disasm -e0 | \
+ wc -l | \
+ ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
+ if: ${{ contains(matrix.configure, 'jit=dev') }}
+
+ - name: Set ENV for YJIT
+ run: |
+ echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
# Check that the binary was built with YJIT
- name: Check YJIT enabled
run: ./miniruby --yjit -v | grep "+YJIT"
- name: Set up Launchable
+ id: launchable
uses: ./.github/actions/launchable/setup
with:
os: ubuntu-22.04
@@ -180,34 +194,35 @@ jobs:
srcdir: src
is-yjit: true
continue-on-error: true
+ timeout-minutes: 3
- name: make ${{ matrix.test_task }}
run: |
- if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
- exec \
- > >(tee launchable_stdout.log) \
- 2> >(tee launchable_stderr.log)
- fi
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+ set -x
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" \
YJIT_BENCH_OPTS="$YJIT_BENCH_OPTS" YJIT_BINDGEN_DIFF_OPTS="$YJIT_BINDGEN_DIFF_OPTS"
timeout-minutes: 90
env:
RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
PRECHECK_BUNDLED_GEMS: 'no'
SYNTAX_SUGGEST_TIMEOUT: '5'
YJIT_BINDGEN_DIFF_OPTS: '--exit-code'
LIBCLANG_PATH: ${{ matrix.libclang_path }}
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
continue-on-error: ${{ matrix.continue-on-test_task || false }}
- - 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') }}
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
- uses: ./.github/actions/slack
with:
diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml
new file mode 100644
index 0000000000..e68bd897fd
--- /dev/null
+++ b/.github/workflows/zjit-macos.yml
@@ -0,0 +1,239 @@
+name: ZJIT macOS
+on:
+ push:
+ branches:
+ - master
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ pull_request:
+ types:
+ - opened
+ - synchronize
+ - reopened
+ # 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:
+
+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:
+ fail-fast: false
+ matrix:
+ include:
+ - test_task: 'check'
+ run_opts: '--zjit-call-threshold=1'
+ specopts: '-T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'check'
+ run_opts: '--zjit-disable-hir-opt --zjit-call-threshold=1'
+ specopts: '-T --zjit-disable-hir-opt -T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
+ configure: '--enable-yjit=dev --enable-zjit'
+ rust_version: "1.85.0"
+
+ - test_task: 'ruby'
+ hint: 'combo build test'
+ configure: '--enable-yjit --enable-zjit'
+
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ RUN_OPTS: ${{ matrix.run_opts }}
+ SPECOPTS: ${{ matrix.specopts }}
+ TESTOPTS: ${{ matrix.testopts }}
+ RUST_BACKTRACE: 1
+ ZJIT_RB_BUG: 1
+
+ runs-on: macos-26
+
+ 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.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout-cone-mode: false
+ sparse-checkout: /.github
+ persist-credentials: false
+
+ - 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' }}
+ # Set fetch-depth: 10 so that Launchable can receive commits information.
+ fetch-depth: 10
+
+ - name: Install Rust
+ if: ${{ matrix.rust_version }}
+ run: |
+ rustup install ${{ matrix.rust_version }} --profile minimal
+ rustup default ${{ matrix.rust_version }}
+
+ - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1
+ with:
+ tool: nextest@0.9
+ if: ${{ matrix.test_task == 'zjit-check' }}
+
+ - name: Run configure
+ run: ../src/configure -C --disable-install-doc ${{ matrix.configure }}
+
+ - run: make
+
+ - name: Verify that --zjit-dump-disasm works
+ run: |
+ ./miniruby --zjit-call-threshold=1 --zjit-dump-disasm -e0 | \
+ wc -l | \
+ ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
+ if: ${{ contains(matrix.configure, 'jit=dev') }}
+
+ - name: Set ENV for ZJIT
+ run: |
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
+
+ - name: Set up Launchable
+ id: launchable
+ uses: ./.github/actions/launchable/setup
+ with:
+ os: macos-26
+ test-opts: ${{ matrix.configure }}
+ launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
+ builddir: build
+ srcdir: src
+ is-zjit: true
+ continue-on-error: true
+ timeout-minutes: 3
+
+ - name: make ${{ matrix.test_task }}
+ run: |
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+
+ set -x
+ make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
+ RUN_OPTS="$RUN_OPTS" \
+ SPECOPTS="$SPECOPTS" \
+ TESTOPTS="$TESTOPTS"
+ timeout-minutes: 60
+ env:
+ RUBY_TESTOPTS: '-q --tty=no'
+ EXCLUDES: '../src/test/.excludes-zjit'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
+ SYNTAX_SUGGEST_TIMEOUT: '30'
+ PRECHECK_BUNDLED_GEMS: 'no'
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
+ continue-on-error: ${{ matrix.continue-on-test_task || false }}
+
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ${{ matrix.test_task }} ${{ matrix.configure }}
+ 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
+ working-directory:
+ if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+
+ # Separated from `make` job to avoid making it a required status check for now
+ ruby-bench:
+ strategy:
+ matrix:
+ include:
+ # Test --call-threshold=2 with 2 iterations in total
+ - ruby_opts: '--zjit-call-threshold=2'
+ bench_opts: '--warmup=1 --bench=1 --excludes=shipit'
+ configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow
+
+ runs-on: macos-26
+
+ 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.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - uses: ./.github/actions/setup/macos
+
+ - 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" ${{ matrix.configure }}
+
+ - run: make install
+
+ # setup/directories set MAKEFLAGS=-j4 for macOS, which randomly fails sqlite3.gem builds
+ - name: Unset MAKEFLAGS
+ run: echo "MAKEFLAGS=" >> "$GITHUB_ENV"
+
+ - name: Checkout ruby-bench
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ repository: ruby/ruby-bench
+ path: ruby-bench
+
+ # If you want to skip failing benchmark, consider using `--excludes`.
+ # e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
+ - name: Run ruby-bench
+ run: ruby run_benchmarks.rb -e "zjit::../build/install/bin/ruby ${{ matrix.ruby_opts }}" ${{ matrix.bench_opts }}
+ working-directory: ruby-bench
+ env:
+ BUNDLER_VERSION: 0
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ruby-bench ${{ matrix.bench_opts }} ${{ matrix.ruby_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/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml
new file mode 100644
index 0000000000..8d146b7bdc
--- /dev/null
+++ b/.github/workflows/zjit-ubuntu.yml
@@ -0,0 +1,293 @@
+name: ZJIT Ubuntu
+on:
+ push:
+ branches:
+ - master
+ paths-ignore:
+ - 'doc/**'
+ - '**/man/*'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '.*.yml'
+ pull_request:
+ types:
+ - opened
+ - synchronize
+ - reopened
+ # 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:
+
+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:
+ lint:
+ name: cargo clippy
+
+ 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.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - run: cargo clippy --all-targets --all-features
+ working-directory: zjit
+
+ make:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - test_task: 'check'
+ run_opts: '--zjit-call-threshold=1'
+ specopts: '-T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'check'
+ run_opts: '--zjit-disable-hir-opt --zjit-call-threshold=1'
+ specopts: '-T --zjit-disable-hir-opt -T --zjit-call-threshold=1'
+ configure: '--enable-zjit=dev'
+
+ # The optimizer benefits from at least 1 iteration of profiling. Also, many
+ # regression tests in bootstraptest/test_yjit.rb assume call-threshold=2.
+ - test_task: 'btest'
+ run_opts: '--zjit-call-threshold=2'
+ configure: '--enable-zjit=dev'
+
+ - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
+ configure: '--enable-yjit --enable-zjit=dev'
+ rust_version: '1.85.0'
+
+ - test_task: 'zjit-bindgen'
+ hint: 'To fix: use patch in logs'
+ # Build with YJIT+ZJIT for output that works in the most number of configurations
+ configure: '--enable-zjit=dev --enable-yjit --with-gcc=clang-16'
+ clang_path: '/usr/bin/clang-16'
+ runs-on: 'ubuntu-24.04' # for clang-16
+
+ - test_task: 'test-bundled-gems'
+ configure: '--enable-zjit=dev'
+ run_opts: '--zjit-call-threshold=1'
+
+ env:
+ GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ RUN_OPTS: ${{ matrix.run_opts }}
+ YJIT_BENCH_OPTS: ${{ matrix.yjit_bench_opts }}
+ SPECOPTS: ${{ matrix.specopts }}
+ TESTOPTS: ${{ matrix.testopts }}
+ RUBY_DEBUG: ci
+ BUNDLE_JOBS: 8 # for yjit-bench
+ RUST_BACKTRACE: 1
+ ZJIT_RB_BUG: 1
+
+ runs-on: ${{ matrix.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.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ sparse-checkout-cone-mode: false
+ sparse-checkout: /.github
+ persist-credentials: false
+
+ - uses: ./.github/actions/setup/ubuntu
+
+ - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
+ with:
+ ruby-version: '3.1'
+ bundler: none
+
+ - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1
+ with:
+ tool: nextest@0.9
+ if: ${{ matrix.test_task == 'zjit-check' }}
+
+ - uses: ./.github/actions/setup/directories
+ with:
+ srcdir: src
+ builddir: build
+ makeup: true
+ dummy-files: ${{ matrix.test_task == 'check' }}
+ # Set fetch-depth: 10 so that Launchable can receive commits information.
+ fetch-depth: 10
+
+ - name: Install Rust
+ if: ${{ matrix.rust_version }}
+ run: |
+ rustup install ${{ matrix.rust_version }} --profile minimal
+ rustup default ${{ matrix.rust_version }}
+
+ - name: Install rustfmt
+ if: ${{ matrix.test_task == 'zjit-bindgen' }}
+ run: rustup component add rustfmt
+
+ - 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
+
+ - name: Verify that --zjit-dump-disasm works
+ run: |
+ ./miniruby --zjit-call-threshold=1 --zjit-dump-disasm -e0 | \
+ wc -l | \
+ ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
+ if: ${{ contains(matrix.configure, 'jit=dev') }}
+
+ # Check that the binary was built with ZJIT
+ - name: Check ZJIT enabled
+ run: ./miniruby --zjit -v | grep "+ZJIT"
+ if: ${{ matrix.configure != '--disable-zjit' }}
+
+ - name: Set ENV for ZJIT
+ run: |
+ echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV
+
+ - name: Set up Launchable
+ id: launchable
+ uses: ./.github/actions/launchable/setup
+ with:
+ os: ${{ matrix.runs-on || 'ubuntu-22.04' }}
+ test-opts: ${{ matrix.configure }}
+ launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
+ builddir: build
+ srcdir: src
+ is-zjit: true
+ continue-on-error: true
+ timeout-minutes: 3
+
+ - name: make ${{ matrix.test_task }}
+ run: |
+ test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
+ test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
+
+ set -x
+ make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
+ RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" \
+ TESTOPTS="$TESTOPTS" \
+ ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS"
+ timeout-minutes: 90
+ env:
+ RUBY_TESTOPTS: '-q --tty=no'
+ EXCLUDES: '../src/test/.excludes-zjit'
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
+ PRECHECK_BUNDLED_GEMS: 'no'
+ SYNTAX_SUGGEST_TIMEOUT: '30'
+ ZJIT_BINDGEN_DIFF_OPTS: '--exit-code'
+ CLANG_PATH: ${{ matrix.clang_path }}
+ LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
+ LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
+ continue-on-error: ${{ matrix.continue-on-test_task || false }}
+
+ - name: Dump crash logs
+ if: ${{ failure() }}
+ continue-on-error: true
+ run: |
+ tail --verbose --lines=+1 rb_crash_*.txt
+ exit 1
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ${{ matrix.test_task }} ${{ matrix.configure }}
+ 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-22.04
+ needs: [make]
+ steps:
+ - name: ${{ github.workflow }} jobs have failed
+ run: exit 1
+ working-directory:
+ if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+
+ # Separated from `make` job to avoid making it a required status check for now
+ ruby-bench:
+ strategy:
+ matrix:
+ include:
+ # Test --call-threshold=2 with 2 iterations in total
+ - ruby_opts: '--zjit-call-threshold=2'
+ bench_opts: '--warmup=1 --bench=1 --excludes=shipit'
+ configure: '--enable-zjit=dev_nodebug' # --enable-zjit=dev is too slow
+
+ runs-on: ubuntu-24.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.pull_request.user.login == 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/cargo'))
+ )}}
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - 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" ${{ matrix.configure }}
+
+ - run: make install
+
+ - name: Checkout ruby-bench
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ repository: ruby/ruby-bench
+ persist-credentials: false
+ path: ruby-bench
+
+ # If you want to skip failing benchmark, consider using `--excludes`.
+ # e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
+ - name: Run ruby-bench
+ run: ruby run_benchmarks.rb -e "zjit::../build/install/bin/ruby ${{ matrix.ruby_opts }}" ${{ matrix.bench_opts }}
+ working-directory: ruby-bench
+ env:
+ BUNDLER_VERSION: 0
+
+ - uses: ./.github/actions/slack
+ with:
+ label: ruby-bench ${{ matrix.bench_opts }} ${{ matrix.ruby_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/zizmor.yml b/.github/zizmor.yml
new file mode 100644
index 0000000000..65b67fb6c8
--- /dev/null
+++ b/.github/zizmor.yml
@@ -0,0 +1,26 @@
+# Ignore existing findings (baseline)
+# Composite action findings are suppressed inline with # zizmor: ignore
+rules:
+ dangerous-triggers:
+ ignore:
+ - auto_request_review.yml
+ - auto_review_pr.yml
+ - labeler.yml
+ - pr-playground.yml
+ dependabot-cooldown:
+ ignore:
+ - dependabot.yml
+ misfeature:
+ ignore:
+ - mingw.yml
+ - tarball-windows.yml
+ - windows.yml
+ unpinned-images:
+ ignore:
+ - compilers.yml
+ secrets-outside-env:
+ # All committers with write access are trusted; no need for environment-scoped secrets.
+ disable: true
+ unpinned-uses:
+ ignore:
+ - wsl.yml
diff --git a/.gitignore b/.gitignore
index 0f3574115b..7ead3a81f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
*.pch
*.pdb
*.rbinc
+*.rbbin
*.rej
*.s
*.sav
@@ -96,6 +97,7 @@ lcov*.info
/enc.mk
/encdb.h
/exts.mk
+/gc/*/exts.mk
/goruby
/id.[ch]
/largefile.h
@@ -246,6 +248,9 @@ lcov*.info
/yjit-bench
/yjit_exit_locations.dump
+# Rust
+/target
+
# /wasm/
/wasm/tests/*.wasm
@@ -260,16 +265,27 @@ lcov*.info
/lib/prism/reflection.rb
/lib/prism/serialize.rb
/lib/prism/visitor.rb
+/prism/internal/diagnostic.h
/prism/api_node.c
/prism/ast.h
/prism/diagnostic.c
-/prism/diagnostic.h
+/prism/json.c
/prism/node.c
/prism/prettyprint.c
/prism/serialize.c
+/prism/tokens.c
+/prism/srcs.mk
+/dump_ast
+
+# prism (old file)
/prism/token_type.c
# tool/update-NEWS-gemlist.rb
/bundled_gems.json
/default_gems.json
/gems/default_gems
+
+# AI agents
+/.claude
+/AGENTS.md
+/CLAUDE.md
diff --git a/.rdoc_options b/.rdoc_options
index 7325a10edf..5172911e16 100644
--- a/.rdoc_options
+++ b/.rdoc_options
@@ -1,7 +1,5 @@
---
page_dir: doc
-charset: UTF-8
-encoding: UTF-8
main_page: index.md
title: Documentation for Ruby development version
visibility: :private
@@ -9,10 +7,11 @@ rdoc_include:
- doc
exclude:
-- \Alib/irb
-- .gemspec\z
+- \.gemspec\z
+- lib/set/subclass_compatible.rb
autolink_excluded_words:
+- Box
- Class
- Method
- Module
@@ -20,3 +19,19 @@ autolink_excluded_words:
- RDoc
- Ruby
- Set
+- ZJIT
+- YJIT
+
+canonical_root: https://docs.ruby-lang.org/en/master
+
+footer_content:
+ Ruby:
+ Documentation: index.html
+ Official Website: https://www.ruby-lang.org/
+ Playground: https://ruby.github.io/play-ruby/
+ Resources:
+ GitHub: https://github.com/ruby/ruby
+ Issue Tracker: https://bugs.ruby-lang.org/projects/ruby-master/issues
+ RubyGems: https://rubygems.org/
+ Community:
+ X: https://x.com/rubylangorg
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index ca68ed20ab..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,111 +0,0 @@
-# -*- YAML -*-
-# Copyright (C) 2011 Urabe, Shyouhei. All rights reserved.
-#
-# This file is a part of the programming language Ruby. Permission is hereby
-# granted, to either redistribute or modify this file, provided that the
-# conditions mentioned in the file COPYING are met. Consult the file for
-# details.
-
-# When you see Travis CI issues, or you are interested in understanding how to
-# manage, please check the link below.
-# https://github.com/ruby/ruby/wiki/CI-Servers#travis-ci
-
-# We enable Travis on the specific branches or forked repositories here.
-# https://docs.travis-ci.com/user/conditions-v1
-if: >-
- (fork OR branch = master OR branch =~ /^ruby_\d_\d$/)
- AND (commit_message !~ /(\[DOC\]|Document)/)
- AND NOT (type = 'push' AND sender =~ /\[bot\]/)
-
-language: c
-
-os: linux
-
-dist: jammy
-
-git:
- quiet: true
-
-env:
- global:
- - NPROC="$(nproc)"
- - JOBS="-j${NPROC}"
- # https://github.com/travis-ci/travis-build/blob/e411371dda21430a60f61b8f3f57943d2fe4d344/lib/travis/build/bash/travis_apt_get_options.bash#L7
- - travis_apt_get_options='--allow-downgrades --allow-remove-essential --allow-change-held-packages'
- - travis_apt_get_options="-yq --no-install-suggests --no-install-recommends $travis_apt_get_options"
- # -g0 disables backtraces when SEGV. Do not set that.
- - debugflags=-ggdb3
- - RUBY_TESTOPTS="$JOBS -q --tty=no"
-
-.org.ruby-lang.ci.matrix-definitions:
- - &gcc-11
- compiler: gcc-11
- before_install:
- - tool/travis_retry.sh sudo bash -c "rm -rf '${TRAVIS_ROOT}/var/lib/apt/lists/'* && exec apt-get update -yq"
- - >-
- tool/travis_retry.sh sudo -E apt-get $travis_apt_get_options install
- gcc-11
- g++-11
- libffi-dev
- libncurses-dev
- libncursesw5-dev
- libreadline-dev
- libssl-dev
- libyaml-dev
- openssl
- zlib1g-dev
- - gcc-11 --version
- - &ppc64le-linux
- name: ppc64le-linux
- arch: ppc64le
- <<: *gcc-11
- - &s390x-linux
- name: s390x-linux
- arch: s390x
- <<: *gcc-11
- env:
- # Avoid possible test failures with the zlib applying the following patch
- # on s390x CPU architecture.
- # https://github.com/madler/zlib/pull/410
- - DFLTCC=0
-
-matrix:
- include:
- - <<: *ppc64le-linux
- - <<: *s390x-linux
- allow_failures:
- - name: ppc64le-linux
- - name: s390x-linux
- fast_finish: true
-
-before_script:
- - lscpu
- - ./autogen.sh
- - mkdir build
- - cd build
- - ../configure -C --disable-install-doc --prefix=$(pwd)/install
- - make -s $JOBS
- - make -s $JOBS install
- # Useful info to report issues to the Ruby.
- - $(pwd)/install/bin/ruby -v
- # Useful info To report issues to the RubyGems.
- - $(pwd)/install/bin/gem env
-
-script:
- - make -s test
- - ../tool/travis_wait.sh make -s test-all RUBYOPT="-w"
- - ../tool/travis_wait.sh make -s test-spec
-
-# We want to be notified when something happens.
-notifications:
- webhooks:
- urls:
- # ruby-lang slack: ruby/simpler-alerts-bot (travis)
- - secure: mRsoS/UbqDkKkW5p3AEqM27d4SZnV6Gsylo3bm8T/deltQzTsGzZwrm7OIBXZv0UFZdE68XmPlyHfZFLSP2V9QZ7apXMf9/vw0GtcSe1gchtnjpAPF6lYBn7nMCbVPPx9cS0dwL927fjdRM1vj7IKZ2bk4F0lAJ25R25S6teqdk=
- on_success: never
- on_failure: always
- email:
- recipients:
- - jun.aruga@gmail.com
- on_success: never
- on_failure: always
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 13df6087ca..35e79dd3b9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1 +1 @@
-See ["Contributing to Ruby"](https://docs.ruby-lang.org/en/master/contributing_md.html), which includes setup and build instructions.
+See ["Contributing to Ruby"](https://docs.ruby-lang.org/en/master/contributing/contributing_md.html), which includes setup and build instructions.
diff --git a/COPYING b/COPYING
index 48e5a96de7..428ce03ed7 100644
--- a/COPYING
+++ b/COPYING
@@ -1,3 +1,5 @@
+{日本語}[rdoc-ref:COPYING.ja]
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
You can redistribute it and/or modify it under either the terms of the
2-clause BSDL (see the file BSDL), or the conditions below:
diff --git a/COPYING.ja b/COPYING.ja
index 230376bc60..5de2dbcc8f 100644
--- a/COPYING.ja
+++ b/COPYING.ja
@@ -1,3 +1,5 @@
+{English}[rdoc-ref:COPYING]
+
本プログラムはフリーソフトウェアです.2-clause BSDL
または以下に示す条件で本プログラムを再配布できます
2-clause BSDLについてはBSDLファイルを参照して下さい.
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000000..2108276e72
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,766 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
+name = "capstone"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4"
+dependencies = [
+ "capstone-sys",
+ "static_assertions",
+]
+
+[[package]]
+name = "capstone-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chacha20"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "rand_core",
+]
+
+[[package]]
+name = "console"
+version = "0.16.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "foldhash"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
+
+[[package]]
+name = "getrandom"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "rand_core",
+ "wasip2",
+ "wasip3",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "foldhash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "id-arena"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.16.1",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "insta"
+version = "1.47.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e"
+dependencies = [
+ "console",
+ "once_cell",
+ "similar",
+ "tempfile",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "jit"
+version = "0.1.0"
+
+[[package]]
+name = "leb128fmt"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+
+[[package]]
+name = "libc"
+version = "0.2.163"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fdaeca4cf44ed4ac623e86ef41f056e848dbeab7ec043ecb7326ba300b36fd0"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "log"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+
+[[package]]
+name = "memchr"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76fc44e2588d5b436dbc3c6cf62aef290f90dab6235744a93dfe1cc18f451e2c"
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+dependencies = [
+ "chacha20",
+ "getrandom",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "ruby"
+version = "0.0.0"
+dependencies = [
+ "yjit",
+ "zjit",
+]
+
+[[package]]
+name = "rustix"
+version = "0.37.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6"
+dependencies = [
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "semver"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.143"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "similar"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "fastrand",
+ "redox_syscall",
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "wasip2"
+version = "1.0.1+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+dependencies = [
+ "wit-bindgen 0.46.0",
+]
+
+[[package]]
+name = "wasip3"
+version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
+dependencies = [
+ "wit-bindgen 0.51.0",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
+dependencies = [
+ "leb128fmt",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "wasm-encoder",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
+dependencies = [
+ "bitflags 2.11.0",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+dependencies = [
+ "wit-bindgen-rust-macro",
+]
+
+[[package]]
+name = "wit-bindgen-core"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
+dependencies = [
+ "anyhow",
+ "heck",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-bindgen-rust"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
+dependencies = [
+ "anyhow",
+ "heck",
+ "indexmap",
+ "prettyplease",
+ "syn",
+ "wasm-metadata",
+ "wit-bindgen-core",
+ "wit-component",
+]
+
+[[package]]
+name = "wit-bindgen-rust-macro"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
+dependencies = [
+ "anyhow",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wit-bindgen-core",
+ "wit-bindgen-rust",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.11.0",
+ "indexmap",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder",
+ "wasm-metadata",
+ "wasmparser",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser",
+]
+
+[[package]]
+name = "yjit"
+version = "0.1.0"
+dependencies = [
+ "capstone",
+ "jit",
+]
+
+[[package]]
+name = "zjit"
+version = "0.0.1"
+dependencies = [
+ "capstone",
+ "insta",
+ "jit",
+ "rand",
+ "yjit",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000..33010e65fb
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,64 @@
+# This is the root Cargo [workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html)
+# and the root package for all the rust code that are statically linked into ruby. Rust tooling
+# limitations means all Rust code need to share a single archive library (staticlib) at the
+# integration point with non-rust code. (See rustlang/rust#44322 and #104707 for a taste of
+# the linking challenges.)
+#
+# Do not add required dependencies. This is a policy that helps downstream consumers and give
+# us tight control over what we ship. All of the optional dependencies are used exclusively
+# during development.
+#
+# Release builds avoid Cargo entirely because offline builds can fail even when none of the
+# optional dependencies are built (rust-lang/cargo#10352).
+
+[workspace]
+members = ["zjit", "yjit", "jit"]
+
+[package]
+name = "ruby"
+version = "0.0.0"
+edition = "2024"
+rust-version = "1.85.0"
+publish = false # Don't publish to crates.io
+
+[dependencies]
+yjit = { path = "yjit", optional = true }
+zjit = { path = "zjit", optional = true }
+
+[lib]
+crate-type = ["staticlib"]
+path = "ruby.rs"
+
+[features]
+disasm = ["yjit?/disasm", "zjit?/disasm"]
+runtime_checks = ["yjit?/runtime_checks", "zjit?/runtime_checks"]
+yjit = [ "dep:yjit" ]
+zjit = [ "dep:zjit" ]
+
+[profile.dev]
+opt-level = 1 # On 0, functions use so much stack space that we get stray `SystemStackError`s
+debug = true
+debug-assertions = true
+overflow-checks = true
+
+[profile.test]
+inherits = "dev"
+opt-level = 0
+
+[profile.dev_nodebug]
+inherits = "dev"
+
+[profile.stats]
+inherits = "release"
+
+[profile.release]
+# NOTE: --enable-yjit and zjit builds use `rustc` without going through Cargo. You
+# might want to update the `rustc` invocation if you change this profile.
+opt-level = 3
+# The extra robustness that comes from checking for arithmetic overflow is
+# worth the performance cost for the compiler.
+overflow-checks = true
+# Generate debug info
+debug = true
+# Use ThinLTO. Much smaller output for a small amount of build time increase.
+lto = "thin"
diff --git a/LEGAL b/LEGAL
index a05cd6eaa3..2777aa2c14 100644
--- a/LEGAL
+++ b/LEGAL
@@ -704,32 +704,7 @@ mentioned below.
[ext/json/vendor/fpconv.c]
- This file is under the Boost Software License.
-
- >>>
- Boost Software License - Version 1.0 - August 17th, 2003
-
- Permission is hereby granted, free of charge, to any person or organization
- obtaining a copy of the software and accompanying documentation covered by
- this license (the "Software") to use, reproduce, display, distribute,
- execute, and transmit the Software, and to prepare derivative works of the
- Software, and to permit third-parties to whom the Software is furnished to
- do so, all subject to the following:
-
- The copyright notices in the Software and this entire statement, including
- the above license grant, this restriction and the following disclaimer,
- must be included in all copies of the Software, in whole or in part, and
- all derivative works of the Software, unless such copies or derivative
- works are solely in the form of machine-executable object code generated by
- a source language processor.
-
- 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
- SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
- FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
+ This file is under the {Boost Software License}[rdoc-ref:@Boost+Software+License+1.0].
[ext/json/vendor/jeaiii-ltoa.h]
@@ -738,7 +713,11 @@ mentioned below.
Copyright (c) 2022 James Edward Anhalt III - https://github.com/jeaiii/itoa
{MIT License}[rdoc-ref:@MIT+License]
-
+
+[ext/json/vendor/ryu.h]
+ This file is adapted from the Ryu algorithm by Ulf Adams https://github.com/ulfjack/ryu.
+ It is dual-licensed under {Apache License 2.0}[rdoc-ref:@Apache+License+2.0] OR
+ {Boost Software License 1.0}[rdoc-ref:@Boost+Software+License+1.0].
[ext/psych]
[test/psych]
@@ -1086,3 +1065,236 @@ mentioned below.
From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
paragraph 3 above is now null and void.
+
+== Boost Software License 1.0
+
+>>>
+ Boost Software License - Version 1.0 - August 17th, 2003
+
+ Permission is hereby granted, free of charge, to any person or organization
+ obtaining a copy of the software and accompanying documentation covered by
+ this license (the "Software") to use, reproduce, display, distribute,
+ execute, and transmit the Software, and to prepare derivative works of the
+ Software, and to permit third-parties to whom the Software is furnished to
+ do so, all subject to the following:
+
+ The copyright notices in the Software and this entire statement, including
+ the above license grant, this restriction and the following disclaimer,
+ must be included in all copies of the Software, in whole or in part, and
+ all derivative works of the Software, unless such copies or derivative
+ works are solely in the form of machine-executable object code generated by
+ a source language processor.
+
+ 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+== Apache License 2.0
+
+>>>
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ a. You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ b. You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ c. You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ d. If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ >>>
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/NEWS.md b/NEWS.md
index 3d884ac1d9..501b894c67 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,79 +1,138 @@
-# NEWS for Ruby 3.5.0
+# NEWS for Ruby 4.1.0
This document is a list of user-visible feature changes
-since the **3.4.0** release, except for bug fixes.
+since the **4.0.0** release, except for bug fixes.
Note that each entry is kept to a minimum, see links for details.
## Language changes
-* `*nil` no longer calls `nil.to_a`, similar to how `**nil` does
- not call `nil.to_hash`. [[Feature #21047]]
+* `Module#clone` and `Module#dup` no longer rewrite the lexical scope of
+ copied methods. Constants and class variables resolve through the
+ original class, consistent with inheritance and mixins.
+ [[Feature #21981]]
## Core classes updates
Note: We're only listing outstanding class updates.
-* Binding
+* Array
- * `Binding#local_variables` does no longer include numbered parameters.
- Also, `Binding#local_variable_get` and `Binding#local_variable_set` reject to handle numbered parameters.
- [[Bug #21049]]
+ * `Array#pack` accepts a new format `R` and `r` for unpacking unsigned
+ and signed LEB128 encoded integers. [[Feature #21785]]
+ * `Array#pack` accepts a new format `^` that returns the current offset.
+ Useful when combined with variable width formats like LEB128. [[Feature #21796]]
-* String
+* ENV
- * Update Unicode to Version 15.1.0 and Emoji Version 15.1. [[Feature #19908]]
- (also applies to Regexp)
+ * `ENV.fetch_values` is added. It returns an array of values for the
+ given names, raising `KeyError` for missing names unless a block is
+ given. [[Feature #21781]]
+
+* Kernel
+
+ * `Kernel#autoload_relative` and `Module#autoload_relative` are added.
+ These methods work like `autoload`, but resolve the file path relative
+ to the file where the method is called, similar to `require_relative`.
+ This makes it easier to autoload constants from files in the same
+ directory without hardcoding absolute paths or manipulating `$LOAD_PATH`.
+ [[Feature #15330]]
+
+* MatchData
+
+ * `MatchData#integer_at` is added. It converts the matched substring to
+ integer and return the result. [[Feature #21932]]
+
+* Regexp
+
+ * All instances of `Regexp` are now frozen, not just literals.
+ Subclasses of `Regexp` are not frozen for compatibility.
+ [[Feature #8948]]
+
+* Set
+
+ * A deprecated behavior, `Set#to_set`, `Range#to_set`, and
+ `Enumerable#to_set` accepting arguments, was removed. [[Feature #21390]]
## Stdlib updates
-The following bundled gems are promoted from default gems.
+### The following bundled gems are added.
-* ostruct 0.6.1
-* pstore 0.2.0
-* benchmark 0.4.0
-* logger 1.7.0
-* rdoc 6.13.1
-* win32ole 1.9.1
-* irb 1.15.1
-* reline 0.6.0
-* readline 0.0.4
-* fiddle 1.1.6
We only list stdlib changes that are notable feature changes.
-Other changes are listed in the following sections. we also listed release history from the previous bundled version that is Ruby 3.3.0 if it has GitHub releases.
+Other changes are listed in the following sections. We also listed release
+history from the previous bundled version that is Ruby 3.4.0 if it has GitHub
+releases.
-The following default gem is added.
+### The following bundled gems are promoted from default gems.
-* win32-registry 0.1.0
+* tsort 0.2.0
+* win32-registry 0.1.2
-The following default gems are updated.
+### The following default gem is added.
-* RubyGems 3.7.0.dev
-* bundler 2.7.0.dev
-* cgi 0.4.2
-* json 2.10.2
-* optparse 0.7.0.dev.2
-* prism 1.4.0
-* psych 5.2.3
-* stringio 3.1.6
-* uri 1.0.3
+### The following default gems are updated.
-The following bundled gems are added.
+* RubyGems 4.1.0.dev
+ * 4.0.3 to [v4.0.4][RubyGems-v4.0.4], [v4.0.5][RubyGems-v4.0.5], [v4.0.6][RubyGems-v4.0.6], [v4.0.7][RubyGems-v4.0.7], [v4.0.8][RubyGems-v4.0.8], [v4.0.9][RubyGems-v4.0.9], [v4.0.10][RubyGems-v4.0.10], [v4.0.11][RubyGems-v4.0.11], [v4.0.12][RubyGems-v4.0.12], [v4.0.13][RubyGems-v4.0.13]
+* bundler 4.1.0.dev
+ * 4.0.3 to [v4.0.4][bundler-v4.0.4], [v4.0.5][bundler-v4.0.5], [v4.0.6][bundler-v4.0.6], [v4.0.7][bundler-v4.0.7], [v4.0.8][bundler-v4.0.8], [v4.0.9][bundler-v4.0.9], [v4.0.10][bundler-v4.0.10], [v4.0.11][bundler-v4.0.11], [v4.0.12][bundler-v4.0.12], [v4.0.13][bundler-v4.0.13]
+* erb 6.0.4
+ * 6.0.1 to [v6.0.1.1][erb-v6.0.1.1], [v6.0.2][erb-v6.0.2], [v6.0.3][erb-v6.0.3], [v6.0.4][erb-v6.0.4]
+* ipaddr 1.2.9
+ * 1.2.8 to [v1.2.9][ipaddr-v1.2.9]
+* json 2.19.8
+ * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3], [v2.19.4][json-v2.19.4], [v2.19.5][json-v2.19.5], [v2.19.6][json-v2.19.6], [v2.19.7][json-v2.19.7]
+* openssl 4.0.2
+ * 4.0.0 to [v4.0.1][openssl-v4.0.1], [v4.0.2][openssl-v4.0.2]
+* prism 1.9.0
+ * 1.7.0 to [v1.8.0][prism-v1.8.0], [v1.8.1][prism-v1.8.1], [v1.9.0][prism-v1.9.0]
+* psych 5.4.0
+* resolv 0.7.1
+ * 0.7.0 to [v0.7.1][resolv-v0.7.1]
+* stringio 3.2.1.dev
+* strscan 3.1.9.dev
+ * 3.1.6 to [v3.1.7][strscan-v3.1.7], [v3.1.8][strscan-v3.1.8]
+* syntax_suggest 3.0.0
+* timeout 0.6.1
+ * 0.6.0 to [v0.6.1][timeout-v0.6.1]
+* zlib 3.2.3
+ * 3.2.2 to [v3.2.3][zlib-v3.2.3]
+### The following bundled gems are updated.
-The following bundled gems are updated.
+* minitest 6.0.6
+* rake 13.4.2
+ * 13.3.1 to [v13.4.0][rake-v13.4.0], [v13.4.1][rake-v13.4.1], [v13.4.2][rake-v13.4.2]
+* test-unit 3.7.7
+ * 3.7.5 to [3.7.6][test-unit-3.7.6], [3.7.7][test-unit-3.7.7]
+* net-imap 0.6.4
+ * 0.6.2 to [v0.6.3][net-imap-v0.6.3], [v0.6.4][net-imap-v0.6.4]
+* rbs 4.0.2
+ * 3.10.0 to [v3.10.1][rbs-v3.10.1], [v3.10.2][rbs-v3.10.2], [v3.10.3][rbs-v3.10.3], [v3.10.4][rbs-v3.10.4], [v4.0.0.dev.5][rbs-v4.0.0.dev.5], [v4.0.0][rbs-v4.0.0], [v4.0.2][rbs-v4.0.2]
+* typeprof 0.32.0
+* mutex_m 0.3.0
+* bigdecimal 4.1.2
+ * 4.0.1 to [v4.1.0][bigdecimal-v4.1.0], [v4.1.1][bigdecimal-v4.1.1], [v4.1.2][bigdecimal-v4.1.2]
+* resolv-replace 0.2.0
+ * 0.1.1 to [v0.2.0][resolv-replace-v0.2.0]
+* syslog 0.4.0
+ * 0.3.0 to [v0.4.0][syslog-v0.4.0]
+* repl_type_completor 0.1.15
+ * 0.1.12 to [v0.1.13][repl_type_completor-v0.1.13], [v0.1.14][repl_type_completor-v0.1.14], [v0.1.15][repl_type_completor-v0.1.15]
+* pstore 0.2.1
+ * 0.2.0 to [v0.2.1][pstore-v0.2.1]
+* rdoc 7.2.0
+ * 7.0.3 to [v7.0.4][rdoc-v7.0.4], [v7.1.0][rdoc-v7.1.0], [v7.2.0][rdoc-v7.2.0]
+* win32ole 1.9.3
+ * 1.9.2 to [v1.9.3][win32ole-v1.9.3]
+* irb 1.18.0
+ * 1.16.0 to [v1.17.0][irb-v1.17.0], [v1.18.0][irb-v1.18.0]
-* minitest 5.25.5
-* rexml 3.4.1
-* net-imap 0.5.6
-* net-smtp 0.5.1
-* rbs 3.9.2
-* bigdecimal 3.1.9
-* syslog 0.3.0
-* csv 3.3.3
-* repl_type_completor 0.1.10
+### RubyGems and Bundler
+
+Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for details.
## Supported platforms
@@ -83,10 +142,127 @@ The following bundled gems are updated.
## C API updates
+### Embedded TypedData
+
+* The `RUBY_TYPED_EMBEDDABLE` flag is now public and documented and can be used by C extensions.
+ It allows allocating C structs directly into Ruby object slots, which reduces pointer chasing,
+ and in some case memory usage.
+ See the C extension documentation for details. [[Feature #21853]]
+
+* Added new C23 inspired allocator functions, that takes the previous memory size.
+ This allow the Ruby GC to better keep track of memory usage, improving its heuristics.
+ It also improves the performance of system allocators that support C23 `free_sized`.
+
+ However, it is important to note that passing an incorrect size to these function is undefined
+ behavior and may result in crashes or memory leaks.
+
+ - `ruby_xfree_sized(void *ptr, size_t size)`
+ - `ruby_xrealloc_sized(void *ptr, size_t newsiz, size_t oldsiz)`
+ - `ruby_xrealloc2_sized(void *ptr, size_t newelems, size_t newsiz, size_t oldelems)`
+
+ [[Feature #21861]]
+
+### Removed APIs
+
+The following APIs, which have been deprecated for many years, are removed.
+[[Feature #21768]]
+
+* old postponed job functions,
+* untyped data object type/functions,
+* old APIs to allocate a data object,
+* taintedness/trustedness enums/macros,
+* `rb_gc_force_recycle` function,
+* `rb_iterate` function,
+* and some functions and constants for internal use.
+
## Implementation improvements
+### Ractor
+
+A lot of work has gone into making Ractors more stable, performant, and usable. These improvements bring Ractor implementation closer to leaving experimental status.
+
## JIT
-[Feature #19908]: https://bugs.ruby-lang.org/issues/19908
-[Feature #21047]: https://bugs.ruby-lang.org/issues/21047
-[Bug #21049]: https://bugs.ruby-lang.org/issues/21049
+[Feature #8948]: https://bugs.ruby-lang.org/issues/8948
+[Feature #15330]: https://bugs.ruby-lang.org/issues/15330
+[Feature #21390]: https://bugs.ruby-lang.org/issues/21390
+[Feature #21768]: https://bugs.ruby-lang.org/issues/21768
+[Feature #21785]: https://bugs.ruby-lang.org/issues/21785
+[Feature #21796]: https://bugs.ruby-lang.org/issues/21796
+[Feature #21853]: https://bugs.ruby-lang.org/issues/21853
+[Feature #21861]: https://bugs.ruby-lang.org/issues/21861
+[Feature #21932]: https://bugs.ruby-lang.org/issues/21932
+[Feature #21981]: https://bugs.ruby-lang.org/issues/21981
+[RubyGems-v4.0.4]: https://github.com/rubygems/rubygems/releases/tag/v4.0.4
+[RubyGems-v4.0.5]: https://github.com/rubygems/rubygems/releases/tag/v4.0.5
+[RubyGems-v4.0.6]: https://github.com/rubygems/rubygems/releases/tag/v4.0.6
+[RubyGems-v4.0.7]: https://github.com/rubygems/rubygems/releases/tag/v4.0.7
+[RubyGems-v4.0.8]: https://github.com/rubygems/rubygems/releases/tag/v4.0.8
+[RubyGems-v4.0.9]: https://github.com/rubygems/rubygems/releases/tag/v4.0.9
+[RubyGems-v4.0.10]: https://github.com/rubygems/rubygems/releases/tag/v4.0.10
+[RubyGems-v4.0.11]: https://github.com/rubygems/rubygems/releases/tag/v4.0.11
+[RubyGems-v4.0.12]: https://github.com/rubygems/rubygems/releases/tag/v4.0.12
+[RubyGems-v4.0.13]: https://github.com/rubygems/rubygems/releases/tag/v4.0.13
+[bundler-v4.0.4]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.4
+[bundler-v4.0.5]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.5
+[bundler-v4.0.6]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.6
+[bundler-v4.0.7]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.7
+[bundler-v4.0.8]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.8
+[bundler-v4.0.9]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.9
+[bundler-v4.0.10]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.10
+[bundler-v4.0.11]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.11
+[bundler-v4.0.12]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.12
+[bundler-v4.0.13]: https://github.com/rubygems/rubygems/releases/tag/bundler-v4.0.13
+[erb-v6.0.1.1]: https://github.com/ruby/erb/releases/tag/v6.0.1.1
+[erb-v6.0.2]: https://github.com/ruby/erb/releases/tag/v6.0.2
+[erb-v6.0.3]: https://github.com/ruby/erb/releases/tag/v6.0.3
+[erb-v6.0.4]: https://github.com/ruby/erb/releases/tag/v6.0.4
+[ipaddr-v1.2.9]: https://github.com/ruby/ipaddr/releases/tag/v1.2.9
+[json-v2.18.1]: https://github.com/ruby/json/releases/tag/v2.18.1
+[json-v2.19.0]: https://github.com/ruby/json/releases/tag/v2.19.0
+[json-v2.19.1]: https://github.com/ruby/json/releases/tag/v2.19.1
+[json-v2.19.2]: https://github.com/ruby/json/releases/tag/v2.19.2
+[json-v2.19.3]: https://github.com/ruby/json/releases/tag/v2.19.3
+[json-v2.19.4]: https://github.com/ruby/json/releases/tag/v2.19.4
+[json-v2.19.5]: https://github.com/ruby/json/releases/tag/v2.19.5
+[json-v2.19.6]: https://github.com/ruby/json/releases/tag/v2.19.6
+[json-v2.19.7]: https://github.com/ruby/json/releases/tag/v2.19.7
+[openssl-v4.0.1]: https://github.com/ruby/openssl/releases/tag/v4.0.1
+[openssl-v4.0.2]: https://github.com/ruby/openssl/releases/tag/v4.0.2
+[prism-v1.8.0]: https://github.com/ruby/prism/releases/tag/v1.8.0
+[prism-v1.8.1]: https://github.com/ruby/prism/releases/tag/v1.8.1
+[prism-v1.9.0]: https://github.com/ruby/prism/releases/tag/v1.9.0
+[resolv-v0.7.1]: https://github.com/ruby/resolv/releases/tag/v0.7.1
+[strscan-v3.1.7]: https://github.com/ruby/strscan/releases/tag/v3.1.7
+[strscan-v3.1.8]: https://github.com/ruby/strscan/releases/tag/v3.1.8
+[timeout-v0.6.1]: https://github.com/ruby/timeout/releases/tag/v0.6.1
+[zlib-v3.2.3]: https://github.com/ruby/zlib/releases/tag/v3.2.3
+[rake-v13.4.0]: https://github.com/ruby/rake/releases/tag/v13.4.0
+[rake-v13.4.1]: https://github.com/ruby/rake/releases/tag/v13.4.1
+[rake-v13.4.2]: https://github.com/ruby/rake/releases/tag/v13.4.2
+[test-unit-3.7.6]: https://github.com/test-unit/test-unit/releases/tag/3.7.6
+[test-unit-3.7.7]: https://github.com/test-unit/test-unit/releases/tag/3.7.7
+[net-imap-v0.6.3]: https://github.com/ruby/net-imap/releases/tag/v0.6.3
+[net-imap-v0.6.4]: https://github.com/ruby/net-imap/releases/tag/v0.6.4
+[rbs-v3.10.1]: https://github.com/ruby/rbs/releases/tag/v3.10.1
+[rbs-v3.10.2]: https://github.com/ruby/rbs/releases/tag/v3.10.2
+[rbs-v3.10.3]: https://github.com/ruby/rbs/releases/tag/v3.10.3
+[rbs-v3.10.4]: https://github.com/ruby/rbs/releases/tag/v3.10.4
+[rbs-v4.0.0.dev.5]: https://github.com/ruby/rbs/releases/tag/v4.0.0.dev.5
+[rbs-v4.0.0]: https://github.com/ruby/rbs/releases/tag/v4.0.0
+[rbs-v4.0.2]: https://github.com/ruby/rbs/releases/tag/v4.0.2
+[bigdecimal-v4.1.0]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.0
+[bigdecimal-v4.1.1]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.1
+[bigdecimal-v4.1.2]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.2
+[resolv-replace-v0.2.0]: https://github.com/ruby/resolv-replace/releases/tag/v0.2.0
+[syslog-v0.4.0]: https://github.com/ruby/syslog/releases/tag/v0.4.0
+[repl_type_completor-v0.1.13]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.13
+[repl_type_completor-v0.1.14]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.14
+[repl_type_completor-v0.1.15]: https://github.com/ruby/repl_type_completor/releases/tag/v0.1.15
+[pstore-v0.2.1]: https://github.com/ruby/pstore/releases/tag/v0.2.1
+[rdoc-v7.0.4]: https://github.com/ruby/rdoc/releases/tag/v7.0.4
+[rdoc-v7.1.0]: https://github.com/ruby/rdoc/releases/tag/v7.1.0
+[rdoc-v7.2.0]: https://github.com/ruby/rdoc/releases/tag/v7.2.0
+[win32ole-v1.9.3]: https://github.com/ruby/win32ole/releases/tag/v1.9.3
+[irb-v1.17.0]: https://github.com/ruby/irb/releases/tag/v1.17.0
+[irb-v1.18.0]: https://github.com/ruby/irb/releases/tag/v1.18.0
diff --git a/README.EXT b/README.EXT
deleted file mode 100644
index 48b8d964c4..0000000000
--- a/README.EXT
+++ /dev/null
@@ -1 +0,0 @@
-Moved to doc/extension.rdoc
diff --git a/README.EXT.ja b/README.EXT.ja
deleted file mode 100644
index f884ecbb0e..0000000000
--- a/README.EXT.ja
+++ /dev/null
@@ -1 +0,0 @@
-doc/extension.ja.rdocに移動しました
diff --git a/README.ja.md b/README.ja.md
index 278285dc83..9bbc3a83a5 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -4,6 +4,8 @@
[![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)
+[English](rdoc-ref:README.md)
+
# Rubyとは
Rubyはシンプルかつ強力なオブジェクト指向スクリプト言語です. Rubyは純粋なオブジェクト指向言語として設計されているので,
diff --git a/README.md b/README.md
index 6297ef1324..02435b419e 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby)
+[日本語](rdoc-ref:README.ja.md)
+
# What is Ruby?
Ruby is an interpreted object-oriented programming language often
@@ -85,7 +87,7 @@ Bugs should be reported at https://bugs.ruby-lang.org. Read ["Reporting Issues"]
## Contributing
-See ["Contributing to Ruby"](https://docs.ruby-lang.org/en/master/contributing_md.html), which includes setup and build instructions.
+See ["Contributing to Ruby"](https://docs.ruby-lang.org/en/master/contributing/contributing_md.html), which includes setup and build instructions.
## The Author
diff --git a/addr2line.c b/addr2line.c
index dc0892e308..19a6a425c1 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -637,12 +637,13 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr
obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
{
static const char global_debug_dir[] = "/usr/lib/debug/.build-id/";
+ static const char debug_suffix[] = ".debug";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
char *p;
obj_info_t *o1 = *objp, *o2;
size_t i;
- if (PATH_MAX < global_debug_dir_len + 1 + build_id_size * 2 + 6) return;
+ if (PATH_MAX < global_debug_dir_len + build_id_size * 2 + sizeof(debug_suffix)) return;
memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
p = binary_filename + global_debug_dir_len;
@@ -653,7 +654,7 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr
*p++ = tbl[n % 16];
if (i == 0) *p++ = '/';
}
- strcpy(p, ".debug");
+ memcpy(p, debug_suffix, sizeof(debug_suffix));
append_obj(objp);
o2 = *objp;
@@ -2175,9 +2176,8 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
}
}
- if (offset == -1) {
+ if (offset == 0) {
/* main executable */
- offset = 0;
if (dynsym_shdr && dynstr_shdr) {
char *strtab = file + dynstr_shdr->sh_offset;
ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
diff --git a/array.c b/array.c
index 7f1db81040..db4c2c4802 100644
--- a/array.c
+++ b/array.c
@@ -27,7 +27,10 @@
#include "probes.h"
#include "ruby/encoding.h"
#include "ruby/st.h"
+#include "ruby/thread.h"
#include "ruby/util.h"
+#include "ruby/ractor.h"
+#include "shape.h"
#include "vm_core.h"
#include "builtin.h"
@@ -106,10 +109,12 @@ should_be_T_ARRAY(VALUE ary)
} while (0)
#define FL_UNSET_SHARED(ary) FL_UNSET((ary), RARRAY_SHARED_FLAG)
+#define ARY_SET_PTR_FORCE(ary, p) \
+ (RARRAY(ary)->as.heap.ptr = (p))
#define ARY_SET_PTR(ary, p) do { \
RUBY_ASSERT(!ARY_EMBED_P(ary)); \
RUBY_ASSERT(!OBJ_FROZEN(ary)); \
- RARRAY(ary)->as.heap.ptr = (p); \
+ ARY_SET_PTR_FORCE(ary, p); \
} while (0)
#define ARY_SET_EMBED_LEN(ary, n) do { \
long tmp_n = (n); \
@@ -147,11 +152,13 @@ should_be_T_ARRAY(VALUE ary)
#define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? ary_embed_capa(ary) : \
ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary))
+#define ARY_SET_CAPA_FORCE(ary, n) \
+ RARRAY(ary)->as.heap.aux.capa = (n);
#define ARY_SET_CAPA(ary, n) do { \
RUBY_ASSERT(!ARY_EMBED_P(ary)); \
RUBY_ASSERT(!ARY_SHARED_P(ary)); \
RUBY_ASSERT(!OBJ_FROZEN(ary)); \
- RARRAY(ary)->as.heap.aux.capa = (n); \
+ ARY_SET_CAPA_FORCE(ary, n); \
} while (0)
#define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1)
@@ -188,7 +195,9 @@ ary_embed_capa(VALUE ary)
static size_t
ary_embed_size(long capa)
{
- return offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa);
+ size_t size = offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa);
+ if (size < sizeof(struct RArray)) size = sizeof(struct RArray);
+ return size;
}
static bool
@@ -353,7 +362,7 @@ ary_heap_alloc_buffer(size_t capa)
static void
ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
{
- ruby_sized_xfree((void *)ptr, size);
+ ruby_xfree_sized((void *)ptr, size);
}
static void
@@ -379,13 +388,14 @@ rb_ary_make_embedded(VALUE ary)
if (!ARY_EMBED_P(ary)) {
const VALUE *buf = ARY_HEAP_PTR(ary);
long len = ARY_HEAP_LEN(ary);
+ long capa = ARY_HEAP_CAPA(ary);
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));
+ ary_heap_free_ptr(ary, buf, capa * sizeof(VALUE));
}
}
@@ -420,7 +430,7 @@ ary_resize_capa(VALUE ary, long capacity)
if (len > capacity) len = capacity;
MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len);
- ary_heap_free_ptr(ary, ptr, old_capa);
+ ary_heap_free_ptr(ary, ptr, old_capa * sizeof(VALUE));
FL_SET_EMBED(ary);
ARY_SET_LEN(ary, len);
@@ -521,6 +531,8 @@ rb_ary_set_shared(VALUE ary, VALUE shared_root)
static inline void
rb_ary_modify_check(VALUE ary)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
rb_check_frozen(ary);
ary_verify(ary);
}
@@ -557,8 +569,8 @@ rb_ary_cancel_sharing(VALUE ary)
VALUE *ptr = ary_heap_alloc_buffer(len);
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
rb_ary_unshare(ary);
- ARY_SET_CAPA(ary, len);
- ARY_SET_PTR(ary, ptr);
+ ARY_SET_CAPA_FORCE(ary, len);
+ ARY_SET_PTR_FORCE(ary, ptr);
}
rb_gc_writebarrier_remember(ary);
@@ -676,22 +688,22 @@ ary_alloc_embed(VALUE klass, long capa)
{
size_t size = ary_embed_size(capa);
RUBY_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, 0);
- /* Created array is:
- * FL_SET_EMBED((VALUE)ary);
- * ARY_SET_EMBED_LEN((VALUE)ary, 0);
- */
- return (VALUE)ary;
+ /* Created array is:
+ * FL_SET_EMBED((VALUE)ary);
+ * ARY_SET_EMBED_LEN((VALUE)ary, 0);
+ */
+ return rb_newobj_of(klass, T_ARRAY | RARRAY_EMBED_FLAG, size);
}
static VALUE
ary_alloc_heap(VALUE klass)
{
- NEWOBJ_OF(ary, struct RArray, klass,
- T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- sizeof(struct RArray), 0);
+ NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY, sizeof(struct RArray));
+
+ ary->as.heap.len = 0;
+ ary->as.heap.aux.capa = 0;
+ ary->as.heap.ptr = NULL;
+
return (VALUE)ary;
}
@@ -705,6 +717,8 @@ empty_ary_alloc(VALUE klass)
static VALUE
ary_new(VALUE klass, long capa)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
VALUE ary;
if (capa < 0) {
@@ -787,23 +801,21 @@ ec_ary_alloc_embed(rb_execution_context_t *ec, VALUE klass, long capa)
{
size_t size = ary_embed_size(capa);
RUBY_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);
- /* Created array is:
- * FL_SET_EMBED((VALUE)ary);
- * ARY_SET_EMBED_LEN((VALUE)ary, 0);
- */
- return (VALUE)ary;
+ /* Created array is:
+ * FL_SET_EMBED((VALUE)ary);
+ * ARY_SET_EMBED_LEN((VALUE)ary, 0);
+ */
+ return rb_ec_newobj_of(ec, klass, T_ARRAY | RARRAY_EMBED_FLAG, size);
}
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);
- return (VALUE)ary;
+ VALUE ary = rb_ec_newobj_of(ec, klass, T_ARRAY, sizeof(struct RArray));
+ RARRAY(ary)->as.heap.len = 0;
+ RARRAY(ary)->as.heap.aux.capa = 0;
+ RARRAY(ary)->as.heap.ptr = NULL;
+ return ary;
}
static VALUE
@@ -898,6 +910,7 @@ init_fake_ary_flags(void)
struct RArray fake_ary = {0};
fake_ary.basic.flags = T_ARRAY;
VALUE ary = (VALUE)&fake_ary;
+ RBASIC_SET_SHAPE_ID(ary, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
rb_ary_freeze(ary);
return fake_ary.basic.flags;
}
@@ -1434,10 +1447,12 @@ rb_ary_pop(VALUE ary)
{
ary_resize_capa(ary, n * 2);
}
- --n;
- ARY_SET_LEN(ary, n);
+
+ VALUE obj = RARRAY_AREF(ary, n - 1);
+
+ ARY_SET_LEN(ary, n - 1);
ary_verify(ary);
- return RARRAY_AREF(ary, n);
+ return obj;
}
/*
@@ -1765,14 +1780,10 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
/*
* call-seq:
- * self[index] -> object or nil
- * self[start, length] -> object or nil
+ * self[offset] -> object or nil
+ * self[offset, size] -> object or nil
* self[range] -> object or nil
* self[aseq] -> object or nil
- * slice(index) -> object or nil
- * slice(start, length) -> object or nil
- * slice(range) -> object or nil
- * slice(aseq) -> object or nil
*
* Returns elements from +self+; does not modify +self+.
*
@@ -1780,27 +1791,27 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
*
* a = [:foo, 'bar', 2]
*
- * # Single argument index: returns one element.
+ * # Single argument offset: returns one element.
* a[0] # => :foo # Zero-based index.
* a[-1] # => 2 # Negative index counts backwards from end.
*
- * # Arguments start and length: returns an array.
+ * # Arguments offset and size: returns an array.
* a[1, 2] # => ["bar", 2]
- * a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end.
+ * a[-2, 2] # => ["bar", 2] # Negative offset counts backwards from end.
*
* # Single argument range: returns an array.
* a[0..1] # => [:foo, "bar"]
* a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end.
* a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
*
- * When a single integer argument +index+ is given, returns the element at offset +index+:
+ * When a single integer argument +offset+ is given, returns the element at offset +offset+:
*
* a = [:foo, 'bar', 2]
* a[0] # => :foo
* a[2] # => 2
* a # => [:foo, "bar", 2]
*
- * If +index+ is negative, counts backwards from the end of +self+:
+ * If +offset+ is negative, counts backwards from the end of +self+:
*
* a = [:foo, 'bar', 2]
* a[-1] # => 2
@@ -1808,29 +1819,29 @@ 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,
- * returns a new array of size +length+ containing successive elements beginning at offset +start+:
+ * When two Integer arguments +offset+ and +size+ are given,
+ * returns a new array of size +size+ containing successive elements beginning at offset +offset+:
*
* a = [:foo, 'bar', 2]
* a[0, 2] # => [:foo, "bar"]
* a[1, 2] # => ["bar", 2]
*
- * If <tt>start + length</tt> is greater than <tt>self.length</tt>,
- * returns all elements from offset +start+ to the end:
+ * If <tt>offset + size</tt> is greater than <tt>self.size</tt>,
+ * returns all elements from offset +offset+ to the end:
*
* a = [:foo, 'bar', 2]
* a[0, 4] # => [:foo, "bar", 2]
* a[1, 3] # => ["bar", 2]
* a[2, 2] # => [2]
*
- * If <tt>start == self.size</tt> and <tt>length >= 0</tt>,
+ * If <tt>offset == self.size</tt> and <tt>size >= 0</tt>,
* returns a new empty array.
*
- * If +length+ is negative, returns +nil+.
+ * If +size+ is negative, returns +nil+.
*
* When a single Range argument +range+ is given,
- * treats <tt>range.min</tt> as +start+ above
- * and <tt>range.size</tt> as +length+ above:
+ * treats <tt>range.min</tt> as +offset+ above
+ * and <tt>range.size</tt> as +size+ above:
*
* a = [:foo, 'bar', 2]
* a[0..1] # => [:foo, "bar"]
@@ -2065,6 +2076,95 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
}
/*
+ * call-seq:
+ * find(if_none_proc = nil) {|element| ... } -> object or nil
+ * find(if_none_proc = nil) -> enumerator
+ *
+ * Returns the first element for which the block returns a truthy value.
+ *
+ * With a block given, calls the block with successive elements of the array;
+ * returns the first element for which the block returns a truthy value:
+ *
+ * [1, 3, 5].find {|element| element > 2} # => 3
+ *
+ * If no such element is found, calls +if_none_proc+ and returns its return value.
+ *
+ * [1, 3, 5].find(proc {-1}) {|element| element > 12} # => -1
+ *
+ * With no block given, returns an Enumerator.
+ *
+ */
+
+static VALUE
+rb_ary_find(int argc, VALUE *argv, VALUE ary)
+{
+ VALUE if_none;
+ long idx;
+
+ RETURN_ENUMERATOR(ary, argc, argv);
+ if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
+
+ for (idx = 0; idx < RARRAY_LEN(ary); idx++) {
+ VALUE elem = RARRAY_AREF(ary, idx);
+ if (RTEST(rb_yield(elem))) {
+ return elem;
+ }
+ }
+
+ if (!NIL_P(if_none)) {
+ return rb_funcallv(if_none, idCall, 0, 0);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * rfind(if_none_proc = nil) {|element| ... } -> object or nil
+ * rfind(if_none_proc = nil) -> enumerator
+ *
+ * Returns the last element for which the block returns a truthy value.
+ *
+ * With a block given, calls the block with successive elements of the array in
+ * reverse order; returns the first element for which the block returns a truthy
+ * value:
+ *
+ * [1, 2, 3, 4, 5, 6].rfind {|element| element < 5} # => 4
+ *
+ * If no such element is found, calls +if_none_proc+ and returns its return value.
+ *
+ * [1, 2, 3, 4].rfind(proc {0}) {|element| element < -2} # => 0
+ *
+ * With no block given, returns an Enumerator.
+ *
+ */
+
+static VALUE
+rb_ary_rfind(int argc, VALUE *argv, VALUE ary)
+{
+ VALUE if_none;
+ long len, idx;
+
+ RETURN_ENUMERATOR(ary, argc, argv);
+ if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
+
+ idx = RARRAY_LEN(ary);
+ while (idx--) {
+ VALUE elem = RARRAY_AREF(ary, idx);
+ if (RTEST(rb_yield(elem))) {
+ return elem;
+ }
+
+ len = RARRAY_LEN(ary);
+ idx = (idx >= len) ? len : idx;
+ }
+
+ if (!NIL_P(if_none)) {
+ return rb_funcallv(if_none, idCall, 0, 0);
+ }
+ return Qnil;
+}
+
+/*
* call-seq:
* find_index(object) -> integer or nil
* find_index {|element| ... } -> integer or nil
@@ -2317,7 +2417,7 @@ rb_ary_resize(VALUE ary, long len)
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); /* WB: no new reference */
ARY_SET_EMBED_LEN(ary, len);
- if (is_malloc_ptr) ruby_sized_xfree((void *)ptr, ptr_capa);
+ if (is_malloc_ptr) ruby_xfree_sized((void *)ptr, ptr_capa);
}
else {
if (olen > len + ARY_DEFAULT_SIZE) {
@@ -2584,18 +2684,39 @@ ary_enum_length(VALUE ary, VALUE args, VALUE eobj)
return rb_ary_length(ary);
}
-// Primitive to avoid a race condition in Array#each.
-// Return `true` and write `value` and `index` if the element exists.
-static VALUE
-ary_fetch_next(VALUE self, VALUE *index, VALUE *value)
+// These array primitives enable tight compatibility with the C implementation
+// in terms of what method calls happen. They can use unchecked utilities such as
+// FIX2LONG since unlike userland Ruby code, these methods cannot be traced with
+// TracePoint (or ruby/debug.h APIs) and have their local variables changed from
+// underneath them.
+
+// Return true if the index is at or past the end of the array.
+VALUE
+rb_jit_ary_at_end(rb_execution_context_t *ec, VALUE self, VALUE index)
{
- long i = NUM2LONG(*index);
- if (i >= RARRAY_LEN(self)) {
- return Qfalse;
- }
- *value = RARRAY_AREF(self, i);
- *index = LONG2NUM(i + 1);
- return Qtrue;
+ return FIX2LONG(index) >= RARRAY_LEN(self) ? Qtrue : Qfalse;
+}
+
+// Return the element at the given fixnum index.
+VALUE
+rb_jit_ary_at(rb_execution_context_t *ec, VALUE self, VALUE index)
+{
+ return RARRAY_AREF(self, FIX2LONG(index));
+}
+
+// Increment a fixnum by 1.
+VALUE
+rb_jit_fixnum_inc(rb_execution_context_t *ec, VALUE self, VALUE num)
+{
+ return LONG2FIX(FIX2LONG(num) + 1);
+}
+
+// Push a value onto an array and return the value.
+VALUE
+rb_jit_ary_push(rb_execution_context_t *ec, VALUE self, VALUE ary, VALUE val)
+{
+ rb_ary_push(ary, val);
+ return val;
}
/*
@@ -2893,23 +3014,28 @@ rb_ary_join(VALUE ary, VALUE sep)
StringValue(sep);
len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
}
- for (i=0; i<RARRAY_LEN(ary); i++) {
+ long len_memo = RARRAY_LEN(ary);
+ for (i=0; i < len_memo; i++) {
val = RARRAY_AREF(ary, i);
- tmp = rb_check_string_type(val);
-
- if (NIL_P(tmp) || tmp != val) {
- int first;
- long n = RARRAY_LEN(ary);
- if (i > n) i = n;
- result = rb_str_buf_new(len + (n-i)*10);
- rb_enc_associate(result, rb_usascii_encoding());
- i = ary_join_0(ary, sep, i, result);
- first = i == 0;
- ary_join_1(ary, ary, sep, i, result, &first);
- return result;
+ if (RB_UNLIKELY(!RB_TYPE_P(val, T_STRING))) {
+ tmp = rb_check_string_type(val);
+ if (NIL_P(tmp) || tmp != val) {
+ int first;
+ long n = RARRAY_LEN(ary);
+ if (i > n) i = n;
+ result = rb_str_buf_new(len + (n-i)*10);
+ rb_enc_associate(result, rb_usascii_encoding());
+ i = ary_join_0(ary, sep, i, result);
+ first = i == 0;
+ ary_join_1(ary, ary, sep, i, result, &first);
+ return result;
+ }
+ len += RSTRING_LEN(tmp);
+ len_memo = RARRAY_LEN(ary);
+ }
+ else {
+ len += RSTRING_LEN(val);
}
-
- len += RSTRING_LEN(tmp);
}
result = rb_str_new(0, len);
@@ -3048,7 +3174,7 @@ rb_ary_to_a(VALUE ary)
* forms each sub-array into a key-value pair in the new hash:
*
* a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
- * a.to_h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
+ * a.to_h # => {"foo" => "zero", "bar" => "one", "baz" => "two"}
* [].to_h # => {}
*
* With a block given, the block must return a 2-element array;
@@ -3057,7 +3183,7 @@ rb_ary_to_a(VALUE ary)
*
* a = ['foo', :bar, 1, [2, 3], {baz: 4}]
* a.to_h {|element| [element, element.class] }
- * # => {"foo"=>String, :bar=>Symbol, 1=>Integer, [2, 3]=>Array, {:baz=>4}=>Hash}
+ * # => {"foo" => String, bar: Symbol, 1 => Integer, [2, 3] => Array, {baz: 4} => Hash}
*
* Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
*/
@@ -3434,10 +3560,9 @@ rb_ary_sort_bang(VALUE ary)
ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp));
}
/* tmp was lost ownership for the ptr */
- FL_UNSET(tmp, FL_FREEZE);
FL_SET_EMBED(tmp);
ARY_SET_EMBED_LEN(tmp, 0);
- FL_SET(tmp, FL_FREEZE);
+ OBJ_FREEZE(tmp);
}
/* tmp will be GC'ed. */
RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
@@ -3498,7 +3623,7 @@ static VALUE rb_ary_bsearch_index(VALUE ary);
* Returns the element from +self+ found by a binary search,
* or +nil+ if the search found no suitable element.
*
- * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
* Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
@@ -3522,7 +3647,7 @@ rb_ary_bsearch(VALUE ary)
* Returns the integer index of the element from +self+ found by a binary search,
* or +nil+ if the search found no suitable element.
*
- * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
* Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
@@ -3655,9 +3780,9 @@ rb_ary_collect(VALUE ary)
/*
* call-seq:
- * collect! {|element| ... } -> new_array
+ * collect! {|element| ... } -> self
* collect! -> new_enumerator
- * map! {|element| ... } -> new_array
+ * map! {|element| ... } -> self
* map! -> new_enumerator
*
* With a block given, calls the block with each element of +self+
@@ -4553,7 +4678,7 @@ take_items(VALUE obj, long n)
* [:c3, :b3, :a3]]
*
* For an *object* in *other_arrays* that is not actually an array,
- * forms the the "other array" as <tt>object.to_ary</tt>, if defined,
+ * forms the "other array" as <tt>object.to_ary</tt>, if defined,
* or as <tt>object.each.to_a</tt> otherwise.
*
* Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
@@ -4713,6 +4838,8 @@ rb_ary_replace(VALUE copy, VALUE orig)
ARY_SET_PTR(copy, ARY_HEAP_PTR(orig));
ARY_SET_LEN(copy, ARY_HEAP_LEN(orig));
rb_ary_set_shared(copy, shared_root);
+
+ RUBY_ASSERT(RB_OBJ_SHAREABLE_P(copy) ? RB_OBJ_SHAREABLE_P(shared_root) : 1);
}
ary_verify(copy);
return copy;
@@ -4751,10 +4878,10 @@ rb_ary_clear(VALUE ary)
/*
* call-seq:
- * fill(object, start = nil, count = nil) -> new_array
- * fill(object, range) -> new_array
- * fill(start = nil, count = nil) {|element| ... } -> new_array
- * fill(range) {|element| ... } -> new_array
+ * fill(object, start = nil, count = nil) -> self
+ * fill(object, range) -> self
+ * fill(start = nil, count = nil) {|element| ... } -> self
+ * fill(range) {|element| ... } -> self
*
* Replaces selected elements in +self+;
* may add elements to +self+;
@@ -5316,8 +5443,8 @@ rb_ary_eql(VALUE ary1, VALUE ary2)
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
}
-VALUE
-rb_ary_hash_values(long len, const VALUE *elements)
+static VALUE
+ary_hash_values(long len, const VALUE *elements, const VALUE ary)
{
long i;
st_index_t h;
@@ -5328,11 +5455,21 @@ rb_ary_hash_values(long len, const VALUE *elements)
for (i=0; i<len; i++) {
n = rb_hash(elements[i]);
h = rb_hash_uint(h, NUM2LONG(n));
+ if (ary) {
+ len = RARRAY_LEN(ary);
+ elements = RARRAY_CONST_PTR(ary);
+ }
}
h = rb_hash_end(h);
return ST2FIX(h);
}
+VALUE
+rb_ary_hash_values(long len, const VALUE *elements)
+{
+ return ary_hash_values(len, elements, 0);
+}
+
/*
* call-seq:
* hash -> integer
@@ -5351,7 +5488,8 @@ 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));
+ RBIMPL_ASSERT_OR_ASSUME(ary);
+ return ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), ary);
}
/*
@@ -5608,7 +5746,7 @@ rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
VALUE elt = rb_ary_elt(ary, i);
for (j = 0; j < argc; j++) {
if (is_hash[j]) {
- if (rb_hash_stlike_lookup(argv[j], RARRAY_AREF(ary, i), NULL))
+ if (rb_hash_stlike_lookup(argv[j], elt, NULL))
break;
}
else {
@@ -5753,7 +5891,7 @@ rb_ary_union_hash(VALUE hash, VALUE ary2)
*
* Returns the union of +self+ and +other_array+;
* duplicates are removed; order is preserved;
- * items are compared using <tt>eql?</tt>:
+ * items are compared using <tt>eql?</tt> and <tt>hash</tt>:
*
* [0, 1] | [2, 3] # => [0, 1, 2, 3]
* [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3]
@@ -5787,7 +5925,7 @@ rb_ary_or(VALUE ary1, VALUE ary2)
*
* Returns a new array that is the union of the elements of +self+
* and all given arrays +other_arrays+;
- * items are compared using <tt>eql?</tt>:
+ * items are compared using <tt>eql?</tt> and <tt>hash</tt>:
*
* [0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7]
*
@@ -6287,7 +6425,7 @@ push_value(st_data_t key, st_data_t val, st_data_t ary)
* returns +self+ if any elements removed, +nil+ otherwise.
*
* With no block given, identifies and removes elements using method <tt>eql?</tt>
- * to compare elements:
+ * and <tt>hash</tt> to compare elements:
*
* a = [0, 0, 1, 1, 2, 2]
* a.uniq! # => [0, 1, 2]
@@ -6295,7 +6433,7 @@ push_value(st_data_t key, st_data_t val, st_data_t ary)
*
* With a block given, calls the block for each element;
* identifies and omits "duplicate" elements using method <tt>eql?</tt>
- * to compare <i>block return values</i>;
+ * and <tt>hash</tt> to compare <i>block return values</i>;
* that is, an element is a duplicate if its block return value
* is the same as that of a previous element:
*
@@ -6344,14 +6482,14 @@ rb_ary_uniq_bang(VALUE ary)
* the first occurrence always being retained.
*
* With no block given, identifies and omits duplicate elements using method <tt>eql?</tt>
- * to compare elements:
+ * and <tt>hash</tt> to compare elements:
*
* a = [0, 0, 1, 1, 2, 2]
* a.uniq # => [0, 1, 2]
*
* With a block given, calls the block for each element;
* identifies and omits "duplicate" elements using method <tt>eql?</tt>
- * to compare <i>block return values</i>;
+ * and <tt>hash</tt> to compare <i>block return values</i>;
* that is, an element is a duplicate if its block return value
* is the same as that of a previous element:
*
@@ -6398,7 +6536,7 @@ rb_ary_uniq(VALUE ary)
* see also {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
*/
-static VALUE
+VALUE
rb_ary_compact_bang(VALUE ary)
{
VALUE *p, *t, *end;
@@ -6605,16 +6743,16 @@ flatten(VALUE ary, int level)
* With non-negative integer argument +depth+, flattens recursively through +depth+ levels:
*
* a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ]
- * a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
+ * a # => [0, [1, [2, 3], 4], 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.dup.flatten!(1) # => [0, 1, [2, 3], 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.dup.flatten!(1.1) # => [0, 1, [2, 3], 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.dup.flatten!(2) # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.dup.flatten!(3) # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
*
* With +nil+ or negative argument +depth+, flattens all levels:
*
- * a.dup.flatten! # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
+ * a.dup.flatten! # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.dup.flatten!(-1) # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
*
* Related: Array#flatten;
* see also {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
@@ -6661,17 +6799,17 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
* With non-negative integer argument +depth+, flattens recursively through +depth+ levels:
*
* a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ]
- * a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(0) # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(1 ) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
+ * a # => [0, [1, [2, 3], 4], 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.flatten(0) # => [0, [1, [2, 3], 4], 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.flatten(1 ) # => [0, 1, [2, 3], 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.flatten(1.1) # => [0, 1, [2, 3], 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.flatten(2) # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.flatten(3) # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
*
* With +nil+ or negative +depth+, flattens all levels.
*
- * a.flatten # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
+ * a.flatten # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
+ * a.flatten(-1) # => [0, 1, 2, 3, 4, 5, {foo: 0}, #<Set: {6, 7}>]
*
* Related: Array#flatten!;
* see also {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
@@ -8117,7 +8255,11 @@ 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)) {
+ bool init_is_float = RB_FLOAT_TYPE_P(v);
+ if (init_is_float) {
+ v = LONG2FIX(0);
+ }
+ else if (!RB_INTEGER_TYPE_P(v) && !RB_TYPE_P(v, T_RATIONAL)) {
i = 0;
goto init_is_a_value;
}
@@ -8145,12 +8287,13 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
goto not_exact;
}
v = finish_exact_sum(n, r, v, argc!=0);
+ if (init_is_float) v = rb_float_plus(argv[0], v);
return v;
not_exact:
v = finish_exact_sum(n, r, v, i!=0);
- if (RB_FLOAT_TYPE_P(e)) {
+ if (init_is_float ? (--i, e = argv[0], true) : RB_FLOAT_TYPE_P(e)) {
/*
* Kahan-Babuska balancing compensated summation algorithm
* See https://link.springer.com/article/10.1007/s00607-005-0139-x
@@ -8297,12 +8440,12 @@ rb_ary_deconstruct(VALUE ary)
*
* [1, 'one', :one, [2, 'two', :two]]
*
- * - A {%w or %W string-array Literal}[rdoc-ref:syntax/literals.rdoc@25w+and+-25W-3A+String-Array+Literals]:
+ * - A {%w or %W string-array Literal}[rdoc-ref:syntax/literals.rdoc@w-and-w-String-Array-Literals]:
*
* %w[foo bar baz] # => ["foo", "bar", "baz"]
* %w[1 % *] # => ["1", "%", "*"]
*
- * - A {%i or %I symbol-array Literal}[rdoc-ref:syntax/literals.rdoc@25i+and+-25I-3A+Symbol-Array+Literals]:
+ * - A {%i or %I symbol-array Literal}[rdoc-ref:syntax/literals.rdoc@i+and-I-Symbol-Array+Literals]:
*
* %i[foo bar baz] # => [:foo, :bar, :baz]
* %i[1 % *] # => [:"1", :%, :*]
@@ -8564,8 +8707,8 @@ rb_ary_deconstruct(VALUE ary)
*
* First, what's elsewhere. Class \Array:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats-Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats-Here],
* which provides dozens of additional methods.
*
* Here, class \Array provides methods that are useful for:
@@ -8707,7 +8850,7 @@ rb_ary_deconstruct(VALUE ary)
* - #collect! (aliased as #map!): Replaces each element with a block return-value.
* - #flatten: Returns an array that is a recursive flattening of +self+.
* - #inspect (aliased as #to_s): Returns a new String containing the elements.
- * - #join: Returns a newsString containing the elements joined by the field separator.
+ * - #join: Returns a new String containing the elements joined by the field separator.
* - #to_a: Returns +self+ or a new array containing all elements.
* - #to_ary: Returns +self+.
* - #to_h: Returns a new hash formed from the elements.
@@ -8775,6 +8918,9 @@ Init_Array(void)
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
rb_define_method(rb_cArray, "size", rb_ary_length, 0);
rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
+ rb_define_method(rb_cArray, "find", rb_ary_find, -1);
+ rb_define_method(rb_cArray, "detect", rb_ary_find, -1);
+ rb_define_method(rb_cArray, "rfind", rb_ary_rfind, -1);
rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
rb_define_method(rb_cArray, "index", rb_ary_index, -1);
rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
@@ -8856,7 +9002,7 @@ Init_Array(void)
rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0);
- rb_cArray_empty_frozen = rb_ary_freeze(rb_ary_new());
+ rb_cArray_empty_frozen = RB_OBJ_SET_SHAREABLE(rb_ary_freeze(rb_ary_new()));
rb_vm_register_global_object(rb_cArray_empty_frozen);
}
diff --git a/array.rb b/array.rb
index 5f31693cab..7ee4e09a4c 100644
--- a/array.rb
+++ b/array.rb
@@ -212,20 +212,20 @@ class Array
indexes
end
- with_yjit do
+ with_jit do
if Primitive.rb_builtin_basic_definition_p(:each)
undef :each
def each # :nodoc:
- Primitive.attr! :inline_block, :c_trace
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
unless defined?(yield)
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
end
- _i = 0
- value = nil
- while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
- yield value
+ i = 0
+ until Primitive.rb_jit_ary_at_end(i)
+ yield Primitive.rb_jit_ary_at(i)
+ i = Primitive.rb_jit_fixnum_inc(i)
end
self
end
@@ -235,17 +235,18 @@ class Array
undef :map
def map # :nodoc:
- Primitive.attr! :inline_block, :c_trace
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
unless defined?(yield)
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
end
- _i = 0
- value = nil
+ i = 0
result = Primitive.ary_sized_alloc
- while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
- result << yield(value)
+ until Primitive.rb_jit_ary_at_end(i)
+ value = yield(Primitive.rb_jit_ary_at(i))
+ Primitive.rb_jit_ary_push(result, value)
+ i = Primitive.rb_jit_fixnum_inc(i)
end
result
end
@@ -260,17 +261,20 @@ class Array
undef :select
def select # :nodoc:
- Primitive.attr! :inline_block, :c_trace
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
unless defined?(yield)
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
end
- _i = 0
- value = nil
+ i = 0
result = Primitive.ary_sized_alloc
- while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
- result << value if yield value
+ until Primitive.rb_jit_ary_at_end(i)
+ value = Primitive.rb_jit_ary_at(i)
+ if yield value
+ Primitive.rb_jit_ary_push(result, value)
+ end
+ i = Primitive.rb_jit_fixnum_inc(i)
end
result
end
@@ -280,5 +284,24 @@ class Array
alias filter select
end
end
+
+ if Primitive.rb_builtin_basic_definition_p(:find)
+ undef :find
+
+ def find(if_none_proc = nil) # :nodoc:
+ Primitive.attr! :inline_block, :c_trace, :without_interrupts
+
+ unless defined?(yield)
+ return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
+ end
+ i = 0
+ until Primitive.rb_jit_ary_at_end(i)
+ value = Primitive.rb_jit_ary_at(i)
+ return value if yield(value)
+ i = Primitive.rb_jit_fixnum_inc(i)
+ end
+ if_none_proc&.call
+ end
+ end
end
end
diff --git a/ast.c b/ast.c
index b98fba6fab..1ddc2b5791 100644
--- a/ast.c
+++ b/ast.c
@@ -32,9 +32,13 @@ static size_t
node_memsize(const void *ptr)
{
struct ASTNodeData *data = (struct ASTNodeData *)ptr;
- rb_ast_t *ast = rb_ruby_ast_data_get(data->ast_value);
+ size_t size = sizeof(struct ASTNodeData);
+ if (data->ast_value) {
+ rb_ast_t *ast = rb_ruby_ast_data_get(data->ast_value);
+ size += rb_ast_memsize(ast);
+ }
- return sizeof(struct ASTNodeData) + rb_ast_memsize(ast);
+ return size;
}
static const rb_data_type_t rb_node_type = {
@@ -400,6 +404,19 @@ rest_arg(VALUE ast_value, const NODE *rest_arg)
return NODE_NAMED_REST_P(rest_arg) ? NEW_CHILD(ast_value, rest_arg) : no_name_rest();
}
+static ID
+node_colon_name(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 VALUE
node_children(VALUE ast_value, const NODE *node)
{
@@ -493,7 +510,7 @@ node_children(VALUE ast_value, const NODE *node)
if (RNODE_CDECL(node)->nd_vid) {
return rb_ary_new_from_args(2, ID2SYM(RNODE_CDECL(node)->nd_vid), NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_value));
}
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_else), ID2SYM(RNODE_COLON2(RNODE_CDECL(node)->nd_else)->nd_mid), NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_else), ID2SYM(node_colon_name(RNODE_CDECL(node)->nd_else)), NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_value));
case NODE_OP_ASGN1:
return rb_ary_new_from_args(4, NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_recv),
ID2SYM(RNODE_OP_ASGN1(node)->nd_mid),
@@ -681,7 +698,7 @@ node_children(VALUE ast_value, const NODE *node)
: var_name(ainfo->rest_arg)),
(ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast_value, (NODE *)ainfo->kw_args)),
(ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast_value, ainfo->kw_rest_arg)),
- var_name(ainfo->block_arg));
+ (ainfo->no_blockarg ? Qfalse : var_name(ainfo->block_arg)));
}
case NODE_SCOPE:
{
@@ -812,6 +829,20 @@ node_locations(VALUE ast_value, const NODE *node)
location_new(&RNODE_CLASS(node)->class_keyword_loc),
location_new(&RNODE_CLASS(node)->inheritance_operator_loc),
location_new(&RNODE_CLASS(node)->end_keyword_loc));
+ case NODE_COLON2:
+ return rb_ary_new_from_args(3,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_COLON2(node)->delimiter_loc),
+ location_new(&RNODE_COLON2(node)->name_loc));
+ case NODE_COLON3:
+ return rb_ary_new_from_args(3,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_COLON3(node)->delimiter_loc),
+ location_new(&RNODE_COLON3(node)->name_loc));
+ case NODE_DEFINED:
+ return rb_ary_new_from_args(2,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_DEFINED(node)->keyword_loc));
case NODE_DOT2:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
@@ -852,6 +883,17 @@ node_locations(VALUE ast_value, const NODE *node)
location_new(&RNODE_IF(node)->if_keyword_loc),
location_new(&RNODE_IF(node)->then_keyword_loc),
location_new(&RNODE_IF(node)->end_keyword_loc));
+ case NODE_IN:
+ return rb_ary_new_from_args(4,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_IN(node)->in_keyword_loc),
+ location_new(&RNODE_IN(node)->then_keyword_loc),
+ location_new(&RNODE_IN(node)->operator_loc));
+ case NODE_MODULE:
+ return rb_ary_new_from_args(3,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_MODULE(node)->module_keyword_loc),
+ location_new(&RNODE_MODULE(node)->end_keyword_loc));
case NODE_NEXT:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
@@ -893,6 +935,14 @@ node_locations(VALUE ast_value, const NODE *node)
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
location_new(&RNODE_RETURN(node)->keyword_loc));
+
+ case NODE_SCLASS:
+ return rb_ary_new_from_args(4,
+ location_new(nd_code_loc(node)),
+ location_new(&RNODE_SCLASS(node)->class_keyword_loc),
+ location_new(&RNODE_SCLASS(node)->operator_loc),
+ location_new(&RNODE_SCLASS(node)->end_keyword_loc));
+
case NODE_SPLAT:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
diff --git a/autogen.sh b/autogen.sh
index f8cdf3c0c1..6cbc5dddab 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,17 +1,22 @@
#!/bin/sh
+# Clear PWD to force commands to recompute working directory
PWD=
+
+# Figure out the source directory for this script
+# configure.ac should be in the same place
case "$0" in
-*/*) srcdir=`dirname $0`;;
-*) srcdir="";;
+ */* ) srcdir=`dirname "$0"` ;; # Called with path
+ * ) srcdir="";; # Otherwise
esac
-symlink='--install --symlink'
+# If install-only is explicitly requested, disable symlink flags
case " $* " in
- *" -i "*|*" --install "*)
- # reset to copy missing standard auxiliary files, instead of symlinks
- symlink=
- ;;
+ *" -i "* | *" --install"* ) symlink_flags="" ;;
+ * ) symlink_flags="--install --symlink" ;;
esac
-exec ${AUTORECONF:-autoreconf} ${symlink} "$@" ${srcdir:+"$srcdir"}
+exec ${AUTORECONF:-autoreconf} \
+ $symlink_flags \
+ "$@" \
+ $srcdir
diff --git a/benchmark/README.md b/benchmark/README.md
index c5c29d0daf..9f9192685e 100644
--- a/benchmark/README.md
+++ b/benchmark/README.md
@@ -40,7 +40,7 @@ Usage: benchmark-driver [options] RUBY|YAML...
--filter REGEXP Filter out benchmarks with given regexp
--run-duration SECONDS Warmup estimates loop_count to run for this duration (default: 3)
--timeout SECONDS Timeout ruby command execution with timeout(1)
- -v, --verbose Verbose mode. Multiple -v options increase visilibity (max: 2)
+ -v, --verbose Verbose mode. Multiple -v options increase visibility (max: 2)
```
## make benchmark
diff --git a/benchmark/app_fib.rb b/benchmark/app_fib.rb
index 34a7b2e725..e61bc8aa32 100644
--- a/benchmark/app_fib.rb
+++ b/benchmark/app_fib.rb
@@ -1,4 +1,4 @@
-def fib n
+def fib(n)
if n < 3
1
else
diff --git a/benchmark/class_superclass.yml b/benchmark/class_superclass.yml
new file mode 100644
index 0000000000..847ff811f1
--- /dev/null
+++ b/benchmark/class_superclass.yml
@@ -0,0 +1,23 @@
+prelude: |
+ class SimpleClass; end
+ class OneModuleClass
+ 1.times { include Module.new }
+ end
+ class MediumClass
+ 10.times { include Module.new }
+ end
+ class LargeClass
+ 100.times { include Module.new }
+ end
+benchmark:
+ object_class_superclass: |
+ Object.superclass
+ simple_class_superclass: |
+ SimpleClass.superclass
+ one_module_class: |
+ OneModuleClass.superclass
+ medium_class_superclass: |
+ MediumClass.superclass
+ large_class_superclass: |
+ LargeClass.superclass
+loop_count: 20000000
diff --git a/benchmark/dir_pwd.yml b/benchmark/dir_pwd.yml
new file mode 100644
index 0000000000..c435d3ac5e
--- /dev/null
+++ b/benchmark/dir_pwd.yml
@@ -0,0 +1,2 @@
+benchmark:
+ pwd: Dir.pwd
diff --git a/benchmark/file_basename.yml b/benchmark/file_basename.yml
new file mode 100644
index 0000000000..fbd78785aa
--- /dev/null
+++ b/benchmark/file_basename.yml
@@ -0,0 +1,6 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ long: File.basename("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml")
+ long_name: File.basename("Users_george_src_github.com_ruby_ruby_benchmark_file_dirname.yml")
+ withext: File.basename("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml", ".yml")
diff --git a/benchmark/file_dirname.yml b/benchmark/file_dirname.yml
new file mode 100644
index 0000000000..43a81c9371
--- /dev/null
+++ b/benchmark/file_dirname.yml
@@ -0,0 +1,6 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ long: File.dirname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml")
+ short: File.dirname("foo/bar")
+ n_4: File.dirname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml", 4)
diff --git a/benchmark/file_expand_path.yml b/benchmark/file_expand_path.yml
new file mode 100644
index 0000000000..9e503ab003
--- /dev/null
+++ b/benchmark/file_expand_path.yml
@@ -0,0 +1,4 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ expand_path: File.expand_path("../../foo.txt", __FILE__)
diff --git a/benchmark/file_extname.yml b/benchmark/file_extname.yml
new file mode 100644
index 0000000000..fb16e55840
--- /dev/null
+++ b/benchmark/file_extname.yml
@@ -0,0 +1,6 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ long: File.extname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml")
+ long_name: File.extname("Users_george_src_github.com_ruby_ruby_benchmark_file_dirname.yml")
+ short: File.extname("foo/bar")
diff --git a/benchmark/file_join.yml b/benchmark/file_join.yml
new file mode 100644
index 0000000000..845257cf1e
--- /dev/null
+++ b/benchmark/file_join.yml
@@ -0,0 +1,7 @@
+prelude: |
+ # frozen_string_literal: true
+benchmark:
+ two_strings: File.join(__FILE__, "path")
+ many_strings: File.join(__FILE__, "path", "a", "b", "c", "d")
+ array: File.join([__FILE__, "path", "a", "b", "c", "d"])
+ mixed: File.join(__FILE__, "path", "a", "b", ["c", "d"])
diff --git a/benchmark/float_predicate.yml b/benchmark/float_predicate.yml
new file mode 100644
index 0000000000..b946937666
--- /dev/null
+++ b/benchmark/float_predicate.yml
@@ -0,0 +1,12 @@
+prelude: |
+ floats = [1.0, -1.0, 0.0, Float::NAN, Float::INFINITY, -Float::INFINITY]
+
+benchmark:
+ float_nan?: floats.each { |f| f.nan? }
+ float_finite?: floats.each { |f| f.finite? }
+ float_infinite?: floats.each { |f| f.infinite? }
+ float_zero?: floats.each { |f| f.zero? }
+ float_positive?: floats.each { |f| f.positive? }
+ float_negative?: floats.each { |f| f.negative? }
+
+loop_count: 1000000
diff --git a/benchmark/int_to_s.yml b/benchmark/int_to_s.yml
new file mode 100644
index 0000000000..000dae9612
--- /dev/null
+++ b/benchmark/int_to_s.yml
@@ -0,0 +1,25 @@
+prelude: |
+ # frozen_string_literal: true
+ N1 = 5
+ N2 = 42
+ N3 = 400
+ N5 = 12345
+ N10 = 1_234_567_890
+ N19 = 4_611_686_018_427_387_903
+ NEG = -1_234_567_890
+ BIG20 = 10 ** 19 + 12_345_678_901_234_567
+ BIG40 = 10 ** 39 + 123_456_789_012_345
+ BIG100 = 10 ** 99 + 42
+benchmark:
+ fix_1digit: "N1.to_s"
+ fix_2digit: "N2.to_s"
+ fix_3digit: "N3.to_s"
+ fix_5digit: "N5.to_s"
+ fix_10digit: "N10.to_s"
+ fix_19digit: "N19.to_s"
+ fix_negative: "NEG.to_s"
+ big_20digit: "BIG20.to_s"
+ big_40digit: "BIG40.to_s"
+ big_100digit: "BIG100.to_s"
+ interp_id: '"id=#{N10}"'
+ interp_mixed: '"a=#{N2},b=#{N5},c=#{N10}"'
diff --git a/benchmark/integer_predicate.yml b/benchmark/integer_predicate.yml
new file mode 100644
index 0000000000..7c05ff2587
--- /dev/null
+++ b/benchmark/integer_predicate.yml
@@ -0,0 +1,9 @@
+prelude: |
+ nums = (0..9).to_a
+
+benchmark:
+ integer_zero?: nums.each { |n| n.zero? }
+ integer_even?: nums.each { |n| n.even? }
+ integer_odd?: nums.each { |n| n.odd? }
+
+loop_count: 1000000
diff --git a/benchmark/io_close.yml b/benchmark/io_close.yml
new file mode 100644
index 0000000000..a552872884
--- /dev/null
+++ b/benchmark/io_close.yml
@@ -0,0 +1,13 @@
+prelude: |
+ ios = 1000.times.map do
+ 100.times.map{IO.pipe}
+ end
+benchmark:
+ # Close IO
+ io_close: |
+ # Process each batch of ios per iteration of the benchmark.
+ ios.pop.each do |r, w|
+ r.close
+ w.close
+ end
+loop_count: 100
diff --git a/benchmark/io_close_contended.yml b/benchmark/io_close_contended.yml
new file mode 100644
index 0000000000..1d9e4e0d0f
--- /dev/null
+++ b/benchmark/io_close_contended.yml
@@ -0,0 +1,21 @@
+prelude: |
+ ios = 100.times.map do
+ 10.times.map do
+ pipe = IO.pipe.tap do |r, w|
+ Thread.new do
+ r.read
+ rescue IOError
+ # Ignore
+ end
+ end
+ end
+ end
+benchmark:
+ # Close IO
+ io_close_contended: |
+ # Process each batch of ios per iteration of the benchmark.
+ ios.pop.each do |r, w|
+ r.close
+ w.close
+ end
+loop_count: 10
diff --git a/benchmark/lib/benchmark_driver/runner/ractor.rb b/benchmark/lib/benchmark_driver/runner/ractor.rb
index c730b8e4a5..fd9c2dd4db 100644
--- a/benchmark/lib/benchmark_driver/runner/ractor.rb
+++ b/benchmark/lib/benchmark_driver/runner/ractor.rb
@@ -87,7 +87,7 @@ __bmdv_ractors << Ractor.new(__bmdv_loop_after - __bmdv_loop_before) { |__bmdv_l
<% end %>
# Wait for all Ractors before executing code to write results
-__bmdv_ractors.map!(&:take)
+__bmdv_ractors.map!(&:value)
<% results.each do |result| %>
File.write(<%= result.dump %>, __bmdv_ractors.shift)
diff --git a/benchmark/module_eqq.yml b/benchmark/module_eqq.yml
index a561fb86dc..2f9c490d92 100644
--- a/benchmark/module_eqq.yml
+++ b/benchmark/module_eqq.yml
@@ -1,4 +1,5 @@
prelude: |
+ module SomeModule; end
class SimpleClass; end
class MediumClass
10.times { include Module.new }
@@ -24,4 +25,8 @@ benchmark:
SimpleClass === LargeObj
simple_class_eqq_huge_obj: |
SimpleClass === HugeObj
-loop_count: 20000000
+ simple_class_eqq_module: |
+ SimpleClass === HugeObj
+ module_eqq_module: |
+ SomeModule === HugeObj
+loop_count: 10000000
diff --git a/benchmark/nilclass.yml b/benchmark/nilclass.yml
index da66e71068..66234c4cdf 100644
--- a/benchmark/nilclass.yml
+++ b/benchmark/nilclass.yml
@@ -1,10 +1,16 @@
prelude: |
def a = nil
benchmark:
+ rationalize:
+ nil.rationalize
+ to_c: |
+ nil.to_c
to_i: |
nil.to_i
to_f: |
nil.to_f
+ to_r: |
+ nil.to_r
splat: |
a(*nil)
loop_count: 100000
diff --git a/benchmark/object_allocate.yml b/benchmark/object_allocate.yml
index bdbd4536db..c6269923f0 100644
--- a/benchmark/object_allocate.yml
+++ b/benchmark/object_allocate.yml
@@ -45,4 +45,5 @@ benchmark:
allocate_kwarg_params: "KWArg.new(a: 1, b: 2, c: 3, d: 4)"
allocate_mixed_params: "Mixed.new(1, 2, c: 3, d: 4)"
allocate_no_params: "Object.new"
+ allocate_allocate: "Object.allocate"
loop_count: 100000
diff --git a/benchmark/object_class.yml b/benchmark/object_class.yml
new file mode 100644
index 0000000000..1e5409d1e2
--- /dev/null
+++ b/benchmark/object_class.yml
@@ -0,0 +1,40 @@
+prelude: |
+ def get_class(obj)
+ i = 10_000
+ while i > 0
+ i -= 1
+ # 100 times per loop
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
+ end
+ end
+
+ class Obj
+ end
+ obj = Obj.new
+
+ singleton = Obj.new
+ def singleton.bar
+ end
+
+ extended = Obj.new
+ 2.times do
+ extended.extend Module.new
+ end
+
+ immediate = 1.4
+benchmark:
+ obj: get_class(obj)
+ extended: get_class(extended)
+ singleton: get_class(singleton)
+ immediate: get_class(immediate)
+loop_count: 1000
diff --git a/benchmark/object_id.yml b/benchmark/object_id.yml
new file mode 100644
index 0000000000..2bd52b923f
--- /dev/null
+++ b/benchmark/object_id.yml
@@ -0,0 +1,4 @@
+benchmark:
+ baseline: "Object.new"
+ object_id: "Object.new.object_id"
+# loop_count: 100000
diff --git a/benchmark/pathname.yml b/benchmark/pathname.yml
new file mode 100644
index 0000000000..bcf3011eab
--- /dev/null
+++ b/benchmark/pathname.yml
@@ -0,0 +1,15 @@
+prelude: |
+ abs = Pathname("/a")
+ rel = Pathname("a")
+ p1 = Pathname.new('foo/././././bar')
+ p2 = Pathname.new('foo/bar/./../..')
+ p3 = Pathname.new('foo/bar/zot')
+benchmark:
+ p1+p2: p1+p2
+ abs.root?: abs.root?
+ rel.root?: rel.root?
+ abs.absolute?: abs.absolute?
+ rel.absolute?: rel.absolute?
+ p1.cleanpath: p1.cleanpath
+ p2.cleanpath: p2.cleanpath
+ relative_path_from: p3.relative_path_from('foo/bar/qux/quax')
diff --git a/benchmark/ractor_string_fstring.yml b/benchmark/ractor_string_fstring.yml
new file mode 100644
index 0000000000..14b92d8fd8
--- /dev/null
+++ b/benchmark/ractor_string_fstring.yml
@@ -0,0 +1,18 @@
+type: lib/benchmark_driver/runner/ractor
+benchmark:
+ ractor_fstring_random: |
+ i = 0
+ str = "same".dup
+ while i < 2000000
+ -(i.to_s.freeze)
+ i += 1
+ end
+ ractor_fstring_same: |
+ i = 0
+ str = "same".dup
+ while i < 2000000
+ -str
+ i += 1
+ end
+loop_count: 1
+ractor: 4
diff --git a/benchmark/set.yml b/benchmark/set.yml
new file mode 100644
index 0000000000..061509cb1f
--- /dev/null
+++ b/benchmark/set.yml
@@ -0,0 +1,261 @@
+prelude: |
+ # First 1000 digits of pi
+ pi = <<~END.gsub(/\D/, '')
+ 31415926535897932384626433832795028841971693993751058209749445923078164062862089
+ 98628034825342117067982148086513282306647093844609550582231725359408128481117450
+ 28410270193852110555964462294895493038196442881097566593344612847564823378678316
+ 52712019091456485669234603486104543266482133936072602491412737245870066063155881
+ 74881520920962829254091715364367892590360011330530548820466521384146951941511609
+ 43305727036575959195309218611738193261179310511854807446237996274956735188575272
+ 48912279381830119491298336733624406566430860213949463952247371907021798609437027
+ 70539217176293176752384674818467669405132000568127145263560827785771342757789609
+ 17363717872146844090122495343014654958537105079227968925892354201995611212902196
+ 08640344181598136297747713099605187072113499999983729780499510597317328160963185
+ 95024459455346908302642522308253344685035261931188171010003137838752886587533208
+ 38142061717766914730359825349042875546873115956286388235378759375195778185778053
+ 21712268066130019278766111959092164201989380952572010654505906988788448549
+ END
+ array1 = 10.times.flat_map do |i|
+ pi[i...].chars.each_slice(10).map(&:join)
+ end
+ array2 = array1.map(&:reverse)
+ array1.map!(&:to_i)
+ array2.map!(&:to_i)
+ a1 = array1[...10]
+ a2 = array1[...100]
+ a3 = array1
+ oa1 = array2[...10]
+ oa2 = array2[...100]
+ oa3 = array2
+ s0 = Set.new
+ s0 = Set.new
+ s1 = Set.new(a1)
+ s2 = Set.new(a2)
+ s3 = Set.new(a3)
+ o0 = Set.new
+ o1 = Set.new(array2[...10])
+ o2 = Set.new(array2[...100])
+ o3 = Set.new(array2)
+ d0 = s0.dup
+ d1 = s1.dup
+ d2 = s2.dup
+ d3 = s3.dup
+ ss1 = s1 - a1[-1..-1]
+ ss2 = s2 - a2[-1..-1]
+ ss3 = s3 - a3[-1..-1]
+ os1 = o1 - oa1[-1..-1]
+ os2 = o2 - oa2[-1..-1]
+ os3 = o3 - oa3[-1..-1]
+ member = a1.first
+ cbi = s0.dup.compare_by_identity
+ ns = Set[s3, o3, d3]
+ set_subclass = Class.new(Set)
+
+benchmark:
+ new_0: Set.new
+ new_10: Set.new(a1)
+ new_100: Set.new(a2)
+ new_1000: Set.new(a3)
+ aref_0: Set[]
+ aref_10: Set[*a1]
+ aref_100: Set[*a2]
+ aref_1000: Set[*a3]
+ amp_0: s0 & o0
+ amp_10: s1 & o1
+ amp_100: s2 & o2
+ amp_1000: s3 & o3
+ amp_same_0: s0 & d0
+ amp_same_10: s1 & d1
+ amp_same_100: s2 & d2
+ amp_same_1000: s3 & d3
+ minus_0: s0 - o0
+ minus_10: s1 - o1
+ minus_100: s2 - o2
+ minus_1000: s3 - o3
+ minus_same_0: s0 - d0
+ minus_same_10: s1 - d1
+ minus_same_100: s2 - d2
+ minus_same_1000: s3 - d3
+ spaceship_0: s0 <=> o0
+ spaceship_diff_10: s1 <=> o1
+ spaceship_diff_100: s2 <=> o2
+ spaceship_diff_1000: s2 <=> o3
+ spaceship_sub_10: s1 <=> ss1
+ spaceship_sub_100: s2 <=> ss2
+ spaceship_sub_1000: s2 <=> ss3
+ spaceship_sup_10: ss1 <=> s1
+ spaceship_sup_100: ss2 <=> s2
+ spaceship_sup_1000: ss2 <=> s3
+ eq_0: s0 == o0
+ eq_10: s1 == o1
+ eq_100: s2 == o2
+ eq_1000: s3 == o3
+ eq_same_0: s0 == d0
+ eq_same_10: s1 == d1
+ eq_same_100: s2 == d2
+ eq_same_1000: s3 == d3
+ xor_0: s0 ^ o0
+ xor_10: s1 ^ o1
+ xor_100: s2 ^ o2
+ xor_1000: s3 ^ o3
+ xor_same_0: s0 ^ d0
+ xor_same_10: s1 ^ d1
+ xor_same_100: s2 ^ d2
+ xor_same_1000: s3 ^ d3
+ pipe_0: s0 | o0
+ pipe_10: s1 | o1
+ pipe_100: s2 | o2
+ pipe_1000: s3 | o3
+ pipe_same_0: s0 | d0
+ pipe_same_10: s1 | d1
+ pipe_same_100: s2 | d2
+ pipe_same_1000: s3 | d3
+ add: a3.each { s0.add(it) }
+ add_exist: a3.each { s3.add(it) }
+ addq: a3.each { s0.add?(it) }
+ addq_exist: a3.each { s3.add?(it) }
+ classify_0: s0.classify { it }
+ classify_10: s1.classify { it & 2 }
+ classify_100: s2.classify { it & 8 }
+ classify_1000: s3.classify { it & 32 }
+ clear: s0.clear
+ collect_0: s0.collect! { it }
+ collect_10: s1.collect! { it }
+ collect_100: s2.collect! { it }
+ collect_1000: s3.collect! { it }
+ compare_by_identity_0: s0.dup.compare_by_identity
+ compare_by_identity_10: s1.dup.compare_by_identity
+ compare_by_identity_100: s2.dup.compare_by_identity
+ compare_by_identity_1000: s3.dup.compare_by_identity
+ compare_by_identityq_false: s0.compare_by_identity?
+ compare_by_identityq_true: cbi.compare_by_identity?
+ clone_0: s0.clone
+ clone_10: s1.clone
+ clone_100: s2.clone
+ clone_1000: s3.clone
+ delete: a3.each { s3.delete(it) }
+ delete_not_exist: a3.each { o3.delete(it) }
+ deleteq: a3.each { s3.delete?(it) }
+ deleteq_not_exist: a3.each { o3.delete?(it) }
+ delete_if_0: s0.delete_if { it }
+ delete_if_10: s1.delete_if { it & 2 == 0 }
+ delete_if_100: s2.delete_if { it & 2 == 0 }
+ delete_if_1000: s3.delete_if { it & 2 == 0 }
+ disjoint_0: s0.disjoint? o0
+ disjoint_10: s1.disjoint? o1
+ disjoint_100: s2.disjoint? o2
+ disjoint_1000: s3.disjoint? o3
+ disjoint_same_0: s0.disjoint? d0
+ disjoint_same_10: s1.disjoint? d1
+ disjoint_same_100: s2.disjoint? d2
+ disjoint_same_1000: s3.disjoint? d3
+ divide_1arity_0: s0.divide { true }
+ divide_1arity_10: s1.divide { it & 2 }
+ divide_1arity_100: s2.divide { it & 8 }
+ divide_1arity_1000: s3.divide { it & 32 }
+ divide_2arity_0: s0.divide { true }
+ divide_2arity_10: s1.divide { (_1 & 2) == (_2 & 2) }
+ divide_2arity_100: s2.divide { (_1 & 8) == (_2 & 8) }
+ divide_2arity_1000: s3.divide { (_1 & 32) == (_2 & 32) }
+ dup_0: s0.dup
+ dup_10: s1.dup
+ dup_100: s2.dup
+ dup_1000: s3.dup
+ each_0: s0.each { it }
+ each_10: s1.each { it }
+ each_100: s2.each { it }
+ each_1000: s3.each { it }
+ empty_true: s0.empty?
+ empty_false: s3.empty?
+ flatten: ns.flatten
+ flattenb: ns.flatten!
+ include_true_0: s0.include? member
+ include_true_10: s1.include? member
+ include_true_100: s2.include? member
+ include_true_1000: s3.include? member
+ include_false_0: s0.include?(-1)
+ include_false_10: s1.include?(-1)
+ include_false_100: s2.include?(-1)
+ include_false_1000: s3.include?(-1)
+ intersect_0: s0.intersect? o0
+ intersect_10: s1.intersect? o1
+ intersect_100: s2.intersect? o2
+ intersect_1000: s3.intersect? o3
+ intersect_same_0: s0.intersect? d0
+ intersect_same_10: s1.intersect? d1
+ intersect_same_100: s2.intersect? d2
+ intersect_same_1000: s3.intersect? d3
+ join_0: s0.join
+ join_10: s1.join
+ join_100: s2.join
+ join_1000: s3.join
+ join_arg_0: s0.join ""
+ join_arg_10: s1.join ""
+ join_arg_100: s2.join ""
+ join_arg_1000: s3.join ""
+ keep_if_0: s0.keep_if { it }
+ keep_if_10: s1.keep_if { it & 2 == 0 }
+ keep_if_100: s2.keep_if { it & 2 == 0 }
+ keep_if_1000: s3.keep_if { it & 2 == 0 }
+ merge_set: s0.dup.merge(s3, o3)
+ merge_enum: s0.dup.merge(array1, array2)
+ proper_subset_0: s0.proper_subset? s0
+ proper_subset_10: s1.proper_subset? ss1
+ proper_subset_100: s2.proper_subset? ss2
+ proper_subset_1000: s3.proper_subset? ss3
+ proper_subset_false_10: s1.proper_subset? os1
+ proper_subset_false_100: s2.proper_subset? os2
+ proper_subset_false_1000: s3.proper_subset? os3
+ proper_superset_0: s0.proper_superset? s0
+ proper_superset_10: ss1.proper_superset? s1
+ proper_superset_100: ss2.proper_superset? s2
+ proper_superset_1000: ss3.proper_superset? s3
+ proper_superset_false_10: os1.proper_superset? s1
+ proper_superset_false_100: os2.proper_superset? s2
+ proper_superset_false_1000: os3.proper_superset? s3
+ reject_0: s0.reject! { it }
+ reject_10: s1.reject! { it & 2 == 0 }
+ reject_100: s2.reject! { it & 2 == 0 }
+ reject_1000: s3.reject! { it & 2 == 0 }
+ replace_0: s = Set.new; array1.each { s.replace(s0) }
+ replace_10: s = Set.new; array1.each { s.replace(s1) }
+ replace_100: s = Set.new; array1.each { s.replace(s2) }
+ replace_1000: s = Set.new; array1.each { s.replace(s3) }
+ reset_0: s0.reset
+ reset_10: s1.reset
+ reset_100: s2.reset
+ reset_1000: s3.reset
+ select_0: s0.select! { it }
+ select_10: s1.select! { it & 2 == 0 }
+ select_100: s2.select! { it & 2 == 0 }
+ select_1000: s3.select! { it & 2 == 0 }
+ size_0: s0.size
+ size_10: s1.size
+ size_100: s2.size
+ size_1000: s3.size
+ subtract_set: s3.dup.subtract(os3)
+ subtract_enum: s3.dup.subtract(oa3)
+ subtract_same_set: s3.dup.subtract(s3)
+ subtract_same_enum: s3.dup.subtract(a3)
+ subset_0: s0.subset? s0
+ subset_10: s1.subset? ss1
+ subset_100: s2.subset? ss2
+ subset_1000: s3.subset? ss3
+ subset_false_10: s1.subset? os1
+ subset_false_100: s2.subset? os2
+ subset_false_1000: s3.subset? os3
+ superset_0: s0.superset? s0
+ superset_10: ss1.superset? s1
+ superset_100: ss2.superset? s2
+ superset_1000: ss3.superset? s3
+ superset_false_10: os1.superset? s1
+ superset_false_100: os2.superset? s2
+ superset_false_1000: os3.superset? s3
+ to_a_0: s0.to_a
+ to_a_10: s1.to_a
+ to_a_100: s2.to_a
+ to_a_1000: s3.to_a
+ to_set_0: s0.to_set
+ to_set_10: s1.to_set
+ to_set_100: s2.to_set
+ to_set_1000: s3.to_set
diff --git a/benchmark/string_casecmp.yml b/benchmark/string_casecmp.yml
index 2354040a04..88a3555c8a 100644
--- a/benchmark/string_casecmp.yml
+++ b/benchmark/string_casecmp.yml
@@ -20,7 +20,9 @@ benchmark:
casecmp-10: lstr10.casecmp(ustr10)
casecmp-100: lstr100.casecmp(ustr100)
casecmp-1000: lstr1000.casecmp(ustr1000)
+ casecmp-1000vs10: lstr1000.casecmp(ustr10)
casecmp-nonascii1: lnonascii1.casecmp(unonascii1)
casecmp-nonascii10: lnonascii10.casecmp(unonascii10)
casecmp-nonascii100: lnonascii100.casecmp(unonascii100)
casecmp-nonascii1000: lnonascii1000.casecmp(unonascii1000)
+ casecmp-nonascii1000vs10: lnonascii1000.casecmp(unonascii10)
diff --git a/benchmark/string_codepoints.yml b/benchmark/string_codepoints.yml
new file mode 100644
index 0000000000..6a07db7ce1
--- /dev/null
+++ b/benchmark/string_codepoints.yml
@@ -0,0 +1,9 @@
+prelude: |
+ mixed_ascii64 = ("a" * 63 + "\u{100}") * 2048
+ mixed_ascii256 = ("a" * 255 + "\u{100}") * 512
+ utf8_2byte = "\u{100}" * 65536
+
+benchmark:
+ codepoints_mixed_ascii64: mixed_ascii64.codepoints
+ codepoints_mixed_ascii256: mixed_ascii256.codepoints
+ codepoints_utf8_2byte: utf8_2byte.codepoints
diff --git a/benchmark/string_coderange_scan.yml b/benchmark/string_coderange_scan.yml
new file mode 100644
index 0000000000..d47bbd2b30
--- /dev/null
+++ b/benchmark/string_coderange_scan.yml
@@ -0,0 +1,10 @@
+prelude: |
+ def unknown(s) = s.b.force_encoding("UTF-8")
+ multibyte = unknown("\u{00e9}" * 16384) # best case: every byte non-ASCII
+ alternating = unknown("\u{00e9}a" * 10922) # worst case: non-ASCII then ASCII
+ ascii = unknown("a" * 32768) # baseline
+
+benchmark:
+ coderange_multibyte: multibyte.dup.valid_encoding?
+ coderange_alternating: alternating.dup.valid_encoding?
+ coderange_ascii: ascii.dup.valid_encoding?
diff --git a/benchmark/string_concat.yml b/benchmark/string_concat.yml
index f11f95ee9a..c07fd21013 100644
--- a/benchmark/string_concat.yml
+++ b/benchmark/string_concat.yml
@@ -1,8 +1,8 @@
prelude: |
CHUNK = "a" * 64
UCHUNK = "é" * 32
- SHORT = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] / 2)
- LONG = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 2)
+ SHORT = "a" * (GC.stat_heap(0, :slot_size) / 2)
+ LONG = "a" * (GC.stat_heap(0, :slot_size) * 2)
GC.disable # GC causes a lot of variance
benchmark:
binary_concat_7bit: |
diff --git a/benchmark/string_fstring.yml b/benchmark/string_fstring.yml
new file mode 100644
index 0000000000..cafef1f3fe
--- /dev/null
+++ b/benchmark/string_fstring.yml
@@ -0,0 +1,16 @@
+benchmark:
+ fstring_random: |
+ i = 0
+ str = "same".dup
+ while i < 5_000_000
+ -(i.to_s.freeze)
+ i += 1
+ end
+ fstring_same: |
+ i = 0
+ str = "same".dup
+ while i < 10_000_000
+ -str
+ i += 1
+ end
+loop_count: 1
diff --git a/benchmark/string_gsub.yml b/benchmark/string_gsub.yml
index 0f964337dd..c26e1a6498 100644
--- a/benchmark/string_gsub.yml
+++ b/benchmark/string_gsub.yml
@@ -20,8 +20,19 @@ prelude: |
}
ESCAPE_PATTERN = Regexp.union(ESCAPED_CHARS.keys)
+ NO_MATCH_SHARED_STRING = ("a" * 100_000).freeze
benchmark:
+ gsub_no_match_shared: |
+ str = NO_MATCH_SHARED_STRING.dup
+ str.gsub!("z", "x")
+ str
+
+ sub_no_match_shared: |
+ str = NO_MATCH_SHARED_STRING.dup
+ str.sub!("z", "x")
+ str
+
escape: |
str = STR.dup
str.gsub!(ESCAPE_PATTERN, ESCAPED_CHARS)
diff --git a/benchmark/string_memsearch.yml b/benchmark/string_memsearch.yml
new file mode 100644
index 0000000000..cde363289a
--- /dev/null
+++ b/benchmark/string_memsearch.yml
@@ -0,0 +1,75 @@
+prelude: |
+ # Haystacks of various sizes
+ small_hay = "a" * 256
+ medium_hay = "a" * 4096
+ large_hay = "a" * 65536
+
+ # Short needles (2-8 bytes) that exercise rb_memsearch_ss
+ needle_2 = "xy"
+ needle_4 = "xyzw"
+ needle_8 = "xyzwabcd"
+
+ # Needle whose first byte is absent from the haystack (memchr fast-path)
+ # vs needle whose first byte is common (rolling hash comparison)
+ first_byte_absent = "x" + "a" * 3
+ first_byte_common = "a" + "x" * 3
+
+ # Haystack with match at the end
+ hay_match_end = "a" * 4095 + "xy"
+
+ # Haystack with match at the start
+ hay_match_start = "xy" + "a" * 4094
+
+ # Mixed content haystack (more realistic)
+ mixed_hay = (("abcdefghij" * 100) + "z") * 10
+
+benchmark:
+ # === First byte absent from haystack (biggest win for rolling hash) ===
+ index_first_byte_absent_small: |
+ small_hay.index(first_byte_absent)
+ index_first_byte_absent_medium: |
+ medium_hay.index(first_byte_absent)
+ index_first_byte_absent_large: |
+ large_hay.index(first_byte_absent)
+
+ # === First byte common in haystack (stresses comparison loop) ===
+ index_first_byte_common_small: |
+ small_hay.index(first_byte_common)
+ index_first_byte_common_medium: |
+ medium_hay.index(first_byte_common)
+ index_first_byte_common_large: |
+ large_hay.index(first_byte_common)
+
+ # === Needle length variations (all absent) ===
+ index_needle_2_absent: |
+ medium_hay.index(needle_2)
+ index_needle_4_absent: |
+ medium_hay.index(needle_4)
+ index_needle_8_absent: |
+ medium_hay.index(needle_8)
+
+ # === Match at end of haystack ===
+ index_match_at_end: |
+ hay_match_end.index(needle_2)
+
+ # === Match at start of haystack ===
+ index_match_at_start: |
+ hay_match_start.index(needle_2)
+
+ # === include? (same code path) ===
+ include_first_byte_absent: |
+ medium_hay.include?(first_byte_absent)
+ include_first_byte_common: |
+ medium_hay.include?(first_byte_common)
+
+ # === byteindex ===
+ byteindex_first_byte_absent: |
+ medium_hay.byteindex(first_byte_absent)
+ byteindex_first_byte_common: |
+ medium_hay.byteindex(first_byte_common)
+
+ # === Mixed/realistic haystack ===
+ index_mixed_absent: |
+ mixed_hay.index(needle_4)
+ index_mixed_present: |
+ mixed_hay.index("ijab")
diff --git a/benchmark/string_scrub.yml b/benchmark/string_scrub.yml
new file mode 100644
index 0000000000..4b5faaad8e
--- /dev/null
+++ b/benchmark/string_scrub.yml
@@ -0,0 +1,48 @@
+prelude: |
+
+ STRING_SIZE = 1024
+ def duplicate_to_length(str, target_length)
+ return "" if target_length <= 0
+ return str[0, target_length] if str.length >= target_length
+
+ (str * ((target_length / str.length) + 1))[0, target_length]
+ end
+ base = "Hello \u{1f600} world! \u{00e9}\u{00f1}"
+ padding = duplicate_to_length(base, STRING_SIZE)
+
+ valid_utf8 = (padding.b + "OK".b).force_encoding("UTF-8")
+ valid_utf8.valid_encoding?
+ unknown_but_valid_utf8 = valid_utf8.dup.b.force_encoding("UTF-8")
+ invalid_utf8 = (padding.b + "\x80\xFF".b).force_encoding("UTF-8")
+ invalid_utf8.valid_encoding?
+ unknown_but_invalid_utf8 = (padding.b + "\x80\xFF".b).force_encoding("UTF-8")
+
+ worst_case_utf8 = duplicate_to_length("\u{1f600}\u{00e9}\u{00f1}", STRING_SIZE).b.force_encoding("UTF-8")
+
+ unknown_but_valid_utf8_worst_case = worst_case_utf8.dup.b.force_encoding("UTF-8")
+ unknown_but_invalid_utf8_worst_case = (worst_case_utf8.b + "\x80\xFF".b).force_encoding("UTF-8")
+
+benchmark:
+ scrub_known_valid: |
+ string = valid_utf8.dup
+ string.scrub!
+
+ scrub_known_invalid: |
+ string = invalid_utf8.dup
+ string.scrub!
+
+ scrub_unknown_but_valid_coderange: |
+ string = unknown_but_valid_utf8.dup
+ string.scrub!
+
+ scrub_unknown_and_invalid_coderange: |
+ string = unknown_but_invalid_utf8.dup
+ string.scrub!
+
+ scrub_unknown_but_valid_coderange_worst_case: |
+ string = unknown_but_valid_utf8_worst_case.dup
+ string.scrub!
+
+ scrub_unknown_and_invalid_coderange_worst_case: |
+ string = unknown_but_invalid_utf8_worst_case.dup
+ string.scrub! \ No newline at end of file
diff --git a/benchmark/struct_accessor.yml b/benchmark/struct_accessor.yml
index 61176cfdd4..d95240e2dd 100644
--- a/benchmark/struct_accessor.yml
+++ b/benchmark/struct_accessor.yml
@@ -1,5 +1,12 @@
prelude: |
C = Struct.new(:x) do
+ def initialize(...)
+ super
+ @ivar = 42
+ end
+
+ attr_accessor :ivar
+
class_eval <<-END
def r
#{'x;'*256}
@@ -15,11 +22,16 @@ prelude: |
m = method(:x=)
#{'m.call(nil);'*256}
end
+ def r_ivar
+ #{'ivar;'*256}
+ end
END
end
+ C.new(nil) # ensure common shape is known
obj = C.new(nil)
benchmark:
member_reader: "obj.r"
member_writer: "obj.w"
member_reader_method: "obj.rm"
member_writer_method: "obj.wm"
+ ivar_reader: "obj.r_ivar"
diff --git a/benchmark/time_now.yml b/benchmark/time_now.yml
index f6d6a31489..9336877cd4 100644
--- a/benchmark/time_now.yml
+++ b/benchmark/time_now.yml
@@ -1,3 +1,4 @@
benchmark:
- 'Time.now'
- 'Time.now(in: "+09:00")'
+ - 'Time.now.year'
diff --git a/benchmark/vm_ivar_get.yml b/benchmark/vm_ivar_get.yml
index 9174af6965..1e0dad665f 100644
--- a/benchmark/vm_ivar_get.yml
+++ b/benchmark/vm_ivar_get.yml
@@ -1,17 +1,75 @@
prelude: |
class Example
def initialize
+ @levar = 1
@v0 = 1
@v1 = 2
@v3 = 3
+ end
+
+ def get_value_loop
+ sum = 0
+
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ i += 1
+ end
+
+ return sum
+ end
+
+ @levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
+
+ def self.get_value_loop
+ sum = 0
+
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ sum += @levar
+ i += 1
+ end
+
+ return sum
+ end
+ end
+
+ class GenExample < Time
+ def initialize
@levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
end
def get_value_loop
sum = 0
i = 0
- while i < 1000000
+ while i < 100_000
# 10 times to de-emphasize loop overhead
sum += @levar
sum += @levar
@@ -31,7 +89,12 @@ prelude: |
end
obj = Example.new
+ gen = GenExample.new
benchmark:
- vm_ivar_get: |
+ vm_ivar_get_on_obj: |
obj.get_value_loop
+ vm_ivar_get_on_class: |
+ Example.get_value_loop
+ vm_ivar_get_on_generic: |
+ gen.get_value_loop
loop_count: 100
diff --git a/benchmark/vm_ivar_set_on_instance.yml b/benchmark/vm_ivar_set_on_instance.yml
index 91857b7742..6ce53a86ec 100644
--- a/benchmark/vm_ivar_set_on_instance.yml
+++ b/benchmark/vm_ivar_set_on_instance.yml
@@ -1,16 +1,44 @@
prelude: |
class TheClass
def initialize
+ @levar = 1
@v0 = 1
@v1 = 2
@v3 = 3
+ end
+
+ def set_value_loop
+ # 100k
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ i += 1
+ end
+ end
+ end
+
+ class Generic < Time
+ def initialize
@levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
end
def set_value_loop
- # 1M
+ # 100k
i = 0
- while i < 1000000
+ while i < 100_000
# 10 times to de-emphasize loop overhead
@levar = i
@levar = i
@@ -28,8 +56,39 @@ prelude: |
end
obj = TheClass.new
+ gen_obj = Generic.new
+
+ class SomeClass
+ @levar = 1
+ @v0 = 1
+ @v1 = 2
+ @v3 = 3
+
+ def self.set_value_loop
+ # 100k
+ i = 0
+ while i < 100_000
+ # 10 times to de-emphasize loop overhead
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ @levar = i
+ i += 1
+ end
+ end
+ end
benchmark:
vm_ivar_set_on_instance: |
obj.set_value_loop
+ vm_ivar_set_on_generic: |
+ gen_obj.set_value_loop
+ vm_ivar_set_on_class: |
+ SomeClass.set_value_loop
loop_count: 100
diff --git a/benchmark/vm_regexp.yml b/benchmark/vm_regexp.yml
index 2aa3d94dbd..80541332b1 100644
--- a/benchmark/vm_regexp.yml
+++ b/benchmark/vm_regexp.yml
@@ -3,6 +3,12 @@ prelude: |
benchmark:
vm_regexp: |
/hoge/ =~ str
+ vm_regexp_alternating: |
+ /hoge/ =~ str
+ /huge/ =~ str
vm_regexp_invert: |
str =~ /hoge/
+ vm_regexp_invert_alternating: |
+ str =~ /hoge/
+ str =~ /huge/
loop_count: 6000000
diff --git a/bignum.c b/bignum.c
index fb4714307e..28924b4eb9 100644
--- a/bignum.c
+++ b/bignum.c
@@ -64,6 +64,21 @@ static const bool debug_integer_pack = (
const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+/* Two-digit decimal lookup table. Offset 2*n holds the ASCII pair for
+ * n in the range 0..99. Used by both rb_fix2str in numeric.c and
+ * big2str_2bdigits below to emit two base-10 digits per iteration. */
+const char ruby_decimal_digit_pairs[201] =
+ "00010203040506070809"
+ "10111213141516171819"
+ "20212223242526272829"
+ "30313233343536373839"
+ "40414243444546474849"
+ "50515253545556575859"
+ "60616263646566676869"
+ "70717273747576777879"
+ "80818283848586878889"
+ "90919293949596979899";
+
#ifndef SIZEOF_BDIGIT_DBL
# if SIZEOF_INT*2 <= SIZEOF_LONG_LONG
# define SIZEOF_BDIGIT_DBL SIZEOF_LONG_LONG
@@ -79,7 +94,6 @@ STATIC_ASSERT(sizeof_bdigit_and_dbl, SIZEOF_BDIGIT*2 <= SIZEOF_BDIGIT_DBL);
STATIC_ASSERT(bdigit_signedness, 0 < (BDIGIT)-1);
STATIC_ASSERT(bdigit_dbl_signedness, 0 < (BDIGIT_DBL)-1);
STATIC_ASSERT(bdigit_dbl_signed_signedness, 0 > (BDIGIT_DBL_SIGNED)-1);
-STATIC_ASSERT(rbignum_embed_len_max, BIGNUM_EMBED_LEN_MAX <= (BIGNUM_EMBED_LEN_MASK >> BIGNUM_EMBED_LEN_SHIFT));
#if SIZEOF_BDIGIT < SIZEOF_LONG
STATIC_ASSERT(sizeof_long_and_sizeof_bdigit, SIZEOF_LONG % SIZEOF_BDIGIT == 0);
@@ -2944,11 +2958,6 @@ bary_divmod(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT *xds, s
}
}
-
-#ifndef BIGNUM_DEBUG
-# define BIGNUM_DEBUG (0+RUBY_DEBUG)
-#endif
-
static int
bigzero_p(VALUE x)
{
@@ -2965,7 +2974,7 @@ int
rb_cmpint(VALUE val, VALUE a, VALUE b)
{
if (NIL_P(val)) {
- rb_cmperr(a, b);
+ rb_cmperr_reason(a, b, "comparator returned nil");
}
if (FIXNUM_P(val)) {
long l = FIX2LONG(val);
@@ -2990,36 +2999,68 @@ rb_cmpint(VALUE val, VALUE a, VALUE b)
((l) << BIGNUM_EMBED_LEN_SHIFT)) : \
(void)(RBIGNUM(b)->as.heap.len = (l)))
+static size_t
+big_embed_capa(VALUE big)
+{
+ size_t size = rb_gc_obj_slot_size(big) - offsetof(struct RBignum, as.ary);
+ RUBY_ASSERT(size % sizeof(BDIGIT) == 0);
+ size_t capa = size / sizeof(BDIGIT);
+ RUBY_ASSERT(capa <= BIGNUM_EMBED_LEN_MAX);
+ return capa;
+}
+
+static size_t
+big_embed_size(size_t capa)
+{
+ size_t size = offsetof(struct RBignum, as.ary) + (sizeof(BDIGIT) * capa);
+ if (size < sizeof(struct RBignum)) {
+ size = sizeof(struct RBignum);
+ }
+ return size;
+}
+
+static bool
+big_embeddable_p(size_t capa)
+{
+ if (capa > BIGNUM_EMBED_LEN_MAX) {
+ return false;
+ }
+ return rb_gc_size_allocatable_p(big_embed_size(capa));
+}
+
static void
rb_big_realloc(VALUE big, size_t len)
{
BDIGIT *ds;
+ size_t embed_capa = big_embed_capa(big);
+
if (BIGNUM_EMBED_P(big)) {
- if (BIGNUM_EMBED_LEN_MAX < len) {
+ if (embed_capa < len) {
ds = ALLOC_N(BDIGIT, len);
- MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, BIGNUM_EMBED_LEN_MAX);
+ MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, embed_capa);
RBIGNUM(big)->as.heap.len = BIGNUM_LEN(big);
RBIGNUM(big)->as.heap.digits = ds;
FL_UNSET_RAW(big, BIGNUM_EMBED_FLAG);
}
}
else {
- if (len <= BIGNUM_EMBED_LEN_MAX) {
+ if (len <= embed_capa) {
ds = RBIGNUM(big)->as.heap.digits;
+ size_t old_len = RBIGNUM(big)->as.heap.len;
FL_SET_RAW(big, BIGNUM_EMBED_FLAG);
BIGNUM_SET_LEN(big, len);
- (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)RBIGNUM(big)->as.ary, sizeof(RBIGNUM(big)->as.ary));
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)RBIGNUM(big)->as.ary, embed_capa * sizeof(BDIGIT));
if (ds) {
MEMCPY(RBIGNUM(big)->as.ary, ds, BDIGIT, len);
- xfree(ds);
+ SIZED_FREE_N(ds, old_len);
}
}
else {
if (BIGNUM_LEN(big) == 0) {
RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
}
- else {
- REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len);
+ else if (BIGNUM_LEN(big) != len) {
+ SIZED_REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len, BIGNUM_LEN(big));
}
}
}
@@ -3035,16 +3076,21 @@ 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);
- VALUE bigv = (VALUE)big;
- BIGNUM_SET_SIGN(bigv, sign);
- if (len <= BIGNUM_EMBED_LEN_MAX) {
- FL_SET_RAW(bigv, BIGNUM_EMBED_FLAG);
+ VALUE bigv;
+
+ if (big_embeddable_p(len)) {
+ size_t size = big_embed_size(len);
+ RUBY_ASSERT(rb_gc_size_allocatable_p(size));
+ NEWOBJ_OF(big, struct RBignum, klass, T_BIGNUM | BIGNUM_EMBED_FLAG, size);
+ bigv = (VALUE)big;
+ BIGNUM_SET_SIGN(bigv, sign);
BIGNUM_SET_LEN(bigv, len);
- (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)big->as.ary, sizeof(big->as.ary));
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)big->as.ary, len * sizeof(BDIGIT));
}
else {
+ NEWOBJ_OF(big, struct RBignum, klass, T_BIGNUM, sizeof(struct RBignum));
+ bigv = (VALUE)big;
+ BIGNUM_SET_SIGN(bigv, sign);
big->as.heap.digits = ALLOC_N(BDIGIT, len);
big->as.heap.len = len;
}
@@ -3055,7 +3101,9 @@ bignew_1(VALUE klass, size_t len, int sign)
VALUE
rb_big_new(size_t len, int sign)
{
- return bignew(len, sign != 0);
+ VALUE obj = bignew(len, sign != 0);
+ memset(BIGNUM_DIGITS(obj), 0, len * sizeof(BDIGIT));
+ return obj;
}
VALUE
@@ -4475,7 +4523,7 @@ rb_str2big_gmp(VALUE arg, int base, int badcheck)
#if HAVE_LONG_LONG
-static VALUE
+VALUE
rb_ull2big(unsigned LONG_LONG n)
{
long i;
@@ -4497,7 +4545,7 @@ rb_ull2big(unsigned LONG_LONG n)
return big;
}
-static VALUE
+VALUE
rb_ll2big(LONG_LONG n)
{
long neg = 0;
@@ -4535,7 +4583,7 @@ rb_ll2inum(LONG_LONG n)
#endif /* HAVE_LONG_LONG */
#ifdef HAVE_INT128_T
-static VALUE
+VALUE
rb_uint128t2big(uint128_t n)
{
long i;
@@ -4778,11 +4826,34 @@ big2str_2bdigits(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t tail
return;
p = buf;
j = sizeof(buf);
- do {
- BDIGIT_DBL idx = num % b2s->base;
- num /= b2s->base;
- p[--j] = ruby_digitmap[idx];
- } while (num);
+ if (b2s->base == 10) {
+ /* Emit two decimal digits per iteration from ruby_decimal_digit_pairs.
+ * See the comment on the table in bignum.c near ruby_digitmap. */
+ while (num >= 100) {
+ BDIGIT_DBL idx = (num % 100) * 2;
+ num /= 100;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ if (num >= 10) {
+ BDIGIT_DBL idx = num * 2;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ else {
+ /* num is 1..9 here (0 was handled above) */
+ p[--j] = (char)('0' + num);
+ }
+ }
+ else {
+ do {
+ BDIGIT_DBL idx = num % b2s->base;
+ num /= b2s->base;
+ p[--j] = ruby_digitmap[idx];
+ } while (num);
+ }
len = sizeof(buf) - j;
big2str_alloc(b2s, len + taillen);
MEMCPY(b2s->ptr, buf + j, char, len);
@@ -4790,11 +4861,39 @@ big2str_2bdigits(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t tail
else {
p = b2s->ptr;
j = b2s->hbase2_numdigits;
- do {
- BDIGIT_DBL idx = num % b2s->base;
- num /= b2s->base;
- p[--j] = ruby_digitmap[idx];
- } while (j);
+ if (b2s->base == 10) {
+ /* Non-beginning chunks must emit EXACTLY hbase2_numdigits,
+ * zero-padded on the left. Consume num in 2-digit groups,
+ * handle the odd trailing digit, then memset remaining
+ * positions with '0'. */
+ while (num >= 100) {
+ BDIGIT_DBL idx = (num % 100) * 2;
+ num /= 100;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ if (num >= 10) {
+ BDIGIT_DBL idx = num * 2;
+ j -= 2;
+ p[j] = ruby_decimal_digit_pairs[idx];
+ p[j + 1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ else if (num > 0) {
+ p[--j] = (char)('0' + num);
+ }
+ if (j > 0) {
+ memset(p, '0', j);
+ j = 0;
+ }
+ }
+ else {
+ do {
+ BDIGIT_DBL idx = num % b2s->base;
+ num /= b2s->base;
+ p[--j] = ruby_digitmap[idx];
+ } while (j);
+ }
len = b2s->hbase2_numdigits;
}
b2s->ptr += len;
@@ -6346,7 +6445,7 @@ bigand_int(VALUE x, long xn, BDIGIT hibitsx, long y)
BDIGIT hibitsy;
if (y == 0) return INT2FIX(0);
- if (xn == 0) return hibitsx ? LONG2NUM(y) : 0;
+ if (xn == 0) return hibitsx ? LONG2NUM(y) : INT2FIX(0);
hibitsy = 0 <= y ? 0 : BDIGMAX;
xds = BDIGITS(x);
#if SIZEOF_BDIGIT >= SIZEOF_LONG
@@ -6758,6 +6857,73 @@ rb_big_aref(VALUE x, VALUE y)
}
VALUE
+rb_big_aref2(VALUE x, VALUE beg, VALUE len)
+{
+ BDIGIT *xds, *vds;
+ VALUE v;
+ size_t copy_begin, xn, shift;
+ ssize_t begin, length, end;
+ bool negative_add_one;
+
+ beg = rb_to_int(beg);
+ len = rb_to_int(len);
+ length = NUM2SSIZET(len);
+ begin = NUM2SSIZET(beg);
+ end = NUM2SSIZET(rb_int_plus(beg, len));
+ shift = begin < 0 ? -begin : 0;
+ xn = BIGNUM_LEN(x);
+ xds = BDIGITS(x);
+
+ if (length < 0) return rb_big_rshift(x, beg);
+ if (length == 0 || end <= 0) return INT2FIX(0);
+ if (begin < 0) begin = 0;
+
+ if ((size_t)(end - 1) / BITSPERDIG >= xn) {
+ /* end > xn * BITSPERDIG */
+ end = xn * BITSPERDIG;
+ }
+
+ if ((size_t)begin / BITSPERDIG < xn) {
+ /* begin < xn * BITSPERDIG */
+ size_t shift_bits, copy_end;
+ copy_begin = begin / BITSPERDIG;
+ shift_bits = begin % BITSPERDIG;
+ copy_end = (end - 1) / BITSPERDIG + 1;
+ v = bignew(copy_end - copy_begin, 1);
+ vds = BDIGITS(v);
+ MEMCPY(vds, xds + copy_begin, BDIGIT, copy_end - copy_begin);
+ negative_add_one = (vds[0] & ((1 << shift_bits) - 1)) == 0;
+ v = bignorm(v);
+ if (shift_bits) v = rb_int_rshift(v, SIZET2NUM(shift_bits));
+ }
+ else {
+ /* Out of range */
+ v = INT2FIX(0);
+ negative_add_one = false;
+ copy_begin = begin = end = 0;
+ }
+
+ if (BIGNUM_NEGATIVE_P(x)) {
+ size_t mask_size = length - shift;
+ VALUE mask = rb_int_minus(rb_int_lshift(INT2FIX(1), SIZET2NUM(mask_size)), INT2FIX(1));
+ v = rb_int_xor(v, mask);
+ for (size_t i = 0; negative_add_one && i < copy_begin; i++) {
+ if (xds[i]) negative_add_one = false;
+ }
+ if (negative_add_one) v = rb_int_plus(v, INT2FIX(1));
+ v = rb_int_and(v, mask);
+ }
+ else {
+ size_t mask_size = (size_t)end - begin;
+ VALUE mask = rb_int_minus(rb_int_lshift(INT2FIX(1), SIZET2NUM(mask_size)), INT2FIX(1));
+ v = rb_int_and(v, mask);
+ }
+ RB_GC_GUARD(x);
+ if (shift) v = rb_int_lshift(v, SSIZET2NUM(shift));
+ return v;
+}
+
+VALUE
rb_big_hash(VALUE x)
{
st_index_t hash;
@@ -6963,7 +7129,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
zn = mn;
z = bignew(zn, 1);
bary_powm_gmp(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn, BDIGITS(m), mn);
- if (nega_flg & BIGNUM_POSITIVE_P(z)) {
+ if (nega_flg && BIGNUM_POSITIVE_P(z) && !BIGZEROP(z)) {
z = rb_big_minus(z, m);
}
RB_GC_GUARD(x);
@@ -6991,7 +7157,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
x = rb_int_modulo(x, m);
}
- if (nega_flg && rb_int_positive_p(tmp)) {
+ if (nega_flg && rb_int_positive_p(tmp) && !rb_int_zero_p(tmp)) {
tmp = rb_int_minus(tmp, m);
}
return tmp;
@@ -7103,6 +7269,11 @@ rb_int_powm(int const argc, VALUE * const argv, VALUE const num)
rb_raise(rb_eTypeError, "Integer#pow() 2nd argument not allowed unless all arguments are integers");
}
+ if (rb_int_zero_p(a) && !rb_int_zero_p(b)) {
+ /* shortcut; 0**x => 0 except for x == 0 */
+ return INT2FIX(0);
+ }
+
if (rb_int_negative_p(m)) {
m = rb_int_uminus(m);
nega_flg = 1;
diff --git a/bootstraptest/runner.rb b/bootstraptest/runner.rb
index 16bfdd9ea2..04de0c93b9 100755
--- a/bootstraptest/runner.rb
+++ b/bootstraptest/runner.rb
@@ -16,6 +16,7 @@ rescue LoadError
$:.unshift File.join(File.dirname(__FILE__), '../lib')
retry
end
+require_relative '../tool/lib/test/jobserver'
if !Dir.respond_to?(:mktmpdir)
# copied from lib/tmpdir.rb
@@ -110,35 +111,7 @@ BT = Class.new(bt) do
def wn=(wn)
unless wn == 1
- if /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ ENV.delete("MAKEFLAGS")
- begin
- if fifo = $3
- fifo.gsub!(/\\(?=.)/, '')
- r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY)
- w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY)
- else
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- end
- rescue
- r.close if r
- else
- r.close_on_exec = true
- w.close_on_exec = true
- tokens = r.read_nonblock(wn > 0 ? wn : 1024, exception: false)
- r.close
- if String === tokens
- tokens.freeze
- auth = w
- w = nil
- at_exit {auth << tokens; auth.close}
- wn = tokens.size + 1
- else
- w.close
- wn = 1
- end
- end
- end
+ wn = Test::JobServer.max_jobs(wn > 0 ? wn : 1024, ENV.delete("MAKEFLAGS")) || wn
if wn <= 0
require 'etc'
wn = [Etc.nprocessors / 2, 1].max
@@ -298,7 +271,7 @@ End
if defined?(RUBY_DESCRIPTION)
puts "Driver is #{RUBY_DESCRIPTION}"
elsif defined?(RUBY_PATCHLEVEL)
- puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{RUBY_PLATFORM}) [#{RUBY_PLATFORM}]"
+ puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]"
else
puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
end
@@ -625,6 +598,8 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
end
end
+ class Timeout < StandardError; end
+
def get_result_string(opt = '', timeout: BT.timeout, **argh)
if BT.ruby
timeout = BT.apply_timeout_scale(timeout)
@@ -634,7 +609,11 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
out = IO.popen("#{BT.ruby} -W0 #{opt} #{filename}", **kw)
pid = out.pid
th = Thread.new {out.read.tap {Process.waitpid(pid); out.close}}
- th.value if th.join(timeout)
+ if th.join(timeout)
+ th.value
+ else
+ Timeout.new("timed out after #{timeout} seconds")
+ end
ensure
raise Interrupt if $? and $?.signaled? && $?.termsig == Signal.list["INT"]
@@ -891,4 +870,8 @@ def yjit_enabled?
ENV.key?('RUBY_YJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('yjit') || BT.ruby.include?('yjit')
end
+def zjit_enabled?
+ ENV.key?('RUBY_ZJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('zjit') || BT.ruby.include?('zjit')
+end
+
exit main
diff --git a/bootstraptest/test_fiber.rb b/bootstraptest/test_fiber.rb
index 2614dd13bf..ae809a5936 100644
--- a/bootstraptest/test_fiber.rb
+++ b/bootstraptest/test_fiber.rb
@@ -37,3 +37,8 @@ assert_normal_exit %q{
assert_normal_exit %q{
Fiber.new(&Object.method(:class_eval)).resume("foo")
}, '[ruby-dev:34128]'
+
+# [Bug #21400]
+assert_normal_exit %q{
+ Thread.new { Fiber.current.kill }.join
+}
diff --git a/bootstraptest/test_flow.rb b/bootstraptest/test_flow.rb
index 15528a4213..7a95def1e6 100644
--- a/bootstraptest/test_flow.rb
+++ b/bootstraptest/test_flow.rb
@@ -376,7 +376,7 @@ assert_equal %q{[1, 4, 7, 5, 8, 9]}, %q{$a = []; begin; ; $a << 1
; $a << 3
end; $a << 4
def m2; $a << 5
- m1(:a, :b, (return 1; :c)); $a << 6
+ m1(:a, :b, (return 1 if true; :c)); $a << 6
end; $a << 7
m2; $a << 8
; $a << 9
@@ -399,7 +399,7 @@ assert_equal %q{[1, 3, 11, 4, 5, 6, 7, 12, 13]}, %q{$a = []; begin; ; $a << 1
m2(begin; $a << 5
2; $a << 6
ensure; $a << 7
- return 3; $a << 8
+ return 3 if true; $a << 8
end); $a << 9
4; $a << 10
end; $a << 11
diff --git a/bootstraptest/test_insns.rb b/bootstraptest/test_insns.rb
index 8a6efae089..1f70c8075c 100644
--- a/bootstraptest/test_insns.rb
+++ b/bootstraptest/test_insns.rb
@@ -86,7 +86,7 @@ tests = [
[ 'putobject', %q{ /(?<x>x)/ =~ "x"; x == "x" }, ],
[ 'putspecialobject', %q{ {//=>true}[//] }, ],
- [ 'putstring', %q{ "true" }, ],
+ [ 'dupstring', %q{ "true" }, ],
[ 'tostring / concatstrings', %q{ "#{true}" }, ],
[ 'toregexp', %q{ /#{true}/ =~ "true" && $~ }, ],
[ 'intern', %q{ :"#{true}" }, ],
@@ -426,11 +426,6 @@ tests = [
x&.x[true] ||= true # here
},
- [ 'opt_aref_with', %q{ { 'true' => true }['true'] }, ],
- [ 'opt_aref_with', %q{ Struct.new(:nil).new['nil'].nil? }, ],
- [ 'opt_aset_with', %q{ {}['true'] = true }, ],
- [ 'opt_aset_with', %q{ Struct.new(:true).new['true'] = true }, ],
-
[ 'opt_length', %q{ 'true' .length == 4 }, ],
[ 'opt_length', %q{ :true .length == 4 }, ],
[ 'opt_length', %q{ [ 'true' ] .length == 1 }, ],
diff --git a/bootstraptest/test_io.rb b/bootstraptest/test_io.rb
index 4e5d6d59c9..4081769a8c 100644
--- a/bootstraptest/test_io.rb
+++ b/bootstraptest/test_io.rb
@@ -85,7 +85,7 @@ assert_normal_exit %q{
ARGF.set_encoding "foo"
}
-/freebsd/ =~ RUBY_PLATFORM or
+/(freebsd|mswin)/ =~ RUBY_PLATFORM or
10.times do
assert_normal_exit %q{
at_exit { p :foo }
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index 41823b5007..e894f6f601 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -1419,3 +1419,24 @@ assert_equal 'ok', %q{
"ok"
end
}
+
+assert_equal 'ok', <<~RUBY
+ def test(*, kw: false)
+ "ok"
+ end
+
+ test
+RUBY
+
+assert_equal '[1, 2, 3]', %q{
+ def target(*args) = args
+ def x = [1]
+ def forwarder(...) = target(*x, 2, ...)
+ forwarder(3).inspect
+}, '[Bug #21832] post-splat args before forwarding'
+
+assert_equal '[nil, nil]', %q{
+ def self_reading(a = a, kw:) = a
+ def through_binding(a = binding.local_variable_get(:a), kw:) = a
+ [self_reading(kw: 1), through_binding(kw: 1)]
+}, 'nil initialization of optional parameters'
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 7cc3092c49..4fe90703fc 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -67,7 +67,7 @@ assert_equal "#<Ractor:#1 running>", %q{
# Return id, loc, and status for no-name ractor
assert_match /^#<Ractor:#([^ ]*?) .+:[0-9]+ terminated>$/, %q{
r = Ractor.new { '' }
- r.take
+ r.join
sleep 0.1 until r.inspect =~ /terminated/
r.inspect
}
@@ -75,7 +75,7 @@ assert_match /^#<Ractor:#([^ ]*?) .+:[0-9]+ terminated>$/, %q{
# Return id, name, loc, and status for named ractor
assert_match /^#<Ractor:#([^ ]*?) Test Ractor .+:[0-9]+ terminated>$/, %q{
r = Ractor.new(name: 'Test Ractor') { '' }
- r.take
+ r.join
sleep 0.1 until r.inspect =~ /terminated/
r.inspect
}
@@ -86,7 +86,7 @@ assert_equal 'ok', %q{
r = Ractor.new do
'ok'
end
- r.take
+ r.value
}
# Passed arguments to Ractor.new will be a block parameter
@@ -96,7 +96,7 @@ assert_equal 'ok', %q{
r = Ractor.new 'ok' do |msg|
msg
end
- r.take
+ r.value
}
# Pass multiple arguments to Ractor.new
@@ -105,7 +105,7 @@ assert_equal 'ok', %q{
r = Ractor.new 'ping', 'pong' do |msg, msg2|
[msg, msg2]
end
- 'ok' if r.take == ['ping', 'pong']
+ 'ok' if r.value == ['ping', 'pong']
}
# Ractor#send passes an object with copy to a Ractor
@@ -115,100 +115,137 @@ assert_equal 'ok', %q{
msg = Ractor.receive
end
r.send 'ok'
- r.take
+ r.value
}
# Ractor#receive_if can filter the message
-assert_equal '[2, 3, 1]', %q{
- r = Ractor.new Ractor.current do |main|
- main << 1
- main << 2
- main << 3
+assert_equal '[1, 2, 3]', %q{
+ ports = 3.times.map{Ractor::Port.new}
+
+ r = Ractor.new ports do |ports|
+ ports[0] << 3
+ ports[1] << 1
+ ports[2] << 2
end
a = []
- a << Ractor.receive_if{|msg| msg == 2}
- a << Ractor.receive_if{|msg| msg == 3}
- a << Ractor.receive
+ a << ports[1].receive # 1
+ a << ports[2].receive # 2
+ a << ports[0].receive # 3
+ a
+}
+
+# dtoa race condition
+assert_equal '[:ok, :ok, :ok]', %q{
+ n = 3
+ n.times.map{
+ Ractor.new{
+ 10_000.times{ rand.to_s }
+ :ok
+ }
+ }.map(&:value)
}
-# Ractor#receive_if with break
-assert_equal '[2, [1, :break], 3]', %q{
- r = Ractor.new Ractor.current do |main|
- main << 1
- main << 2
- main << 3
+assert_equal "42", %q{
+ a = 42
+ Ractor.shareable_lambda{ a }.call
+}
+
+# Ractor.shareable_proc issue for locals in proc [Bug #18023]
+assert_equal '[:a, :b, :c, :d, :e]', %q{
+ v1, v2, v3, v4, v5 = :a, :b, :c, :d, :e
+ closure = Proc.new { [v1, v2, v3, v4, v5] }
+ Ractor.shareable_proc(&closure).call
+}
+
+# Ractor.shareable_proc makes a copy of given Proc
+assert_equal '[true, true]', %q{
+ pr1 = Proc.new do
+ self
end
+ pr2 = Ractor.shareable_proc(&pr1)
- a = []
- a << Ractor.receive_if{|msg| msg == 2}
- a << Ractor.receive_if{|msg| break [msg, :break]}
- a << Ractor.receive
+ [pr1.call == self, pr2.call == nil]
}
-# Ractor#receive_if can't be called recursively
-assert_equal '[[:e1, 1], [:e2, 2]]', %q{
- r = Ractor.new Ractor.current do |main|
- main << 1
- main << 2
- main << 3
+# Ractor.shareable_proc keeps the original Proc intact
+assert_equal '[SyntaxError, [Object, 43, 43], Binding]', %q{
+ a = 42
+ pr1 = Proc.new do
+ [self.class, eval("a"), binding.local_variable_get(:a)]
end
+ a += 1
+ pr2 = Ractor.shareable_proc(&pr1)
- a = []
+ r = []
+ begin
+ pr2.call
+ rescue SyntaxError
+ r << SyntaxError
+ end
- Ractor.receive_if do |msg|
- begin
- Ractor.receive
- rescue Ractor::Error
- a << [:e1, msg]
+ r << pr1.call << pr1.binding.class
+}
+
+# Ractor.make_shareable mutates the original Proc
+# This is the current behavior, it's currently considered safe enough
+# because in most cases it would raise anyway due to not-shared self or not-shared captured variable value
+assert_equal '[[42, 42], Binding, true, SyntaxError, "Can\'t create Binding from isolated Proc"]', %q{
+ a = 42
+ pr1 = nil.instance_exec do
+ Proc.new do
+ [eval("a"), binding.local_variable_get(:a)]
end
- true # delete 1 from queue
end
- Ractor.receive_if do |msg|
- begin
- Ractor.receive_if{}
- rescue Ractor::Error
- a << [:e2, msg]
- end
- true # delete 2 from queue
+ r = [pr1.call, pr1.binding.class]
+
+ pr2 = Ractor.make_shareable(pr1)
+ r << pr1.equal?(pr2)
+
+ begin
+ pr1.call
+ rescue SyntaxError
+ r << SyntaxError
end
- a #
-}
+ begin
+ r << pr1.binding
+ rescue ArgumentError
+ r << $!.message
+ end
-# dtoa race condition
-assert_equal '[:ok, :ok, :ok]', %q{
- n = 3
- n.times.map{
- Ractor.new{
- 10_000.times{ rand.to_s }
- :ok
- }
- }.map(&:take)
+ r
}
-# Ractor.make_shareable issue for locals in proc [Bug #18023]
-assert_equal '[:a, :b, :c, :d, :e]', %q{
- v1, v2, v3, v4, v5 = :a, :b, :c, :d, :e
- closure = Ractor.current.instance_eval{ Proc.new { [v1, v2, v3, v4, v5] } }
+# Ractor::IsolationError cases
+assert_equal '3', %q{
+ ok = 0
- Ractor.make_shareable(closure).call
-}
+ begin
+ a = 1
+ Ractor.shareable_proc{a}
+ a = 2
+ rescue Ractor::IsolationError => e
+ ok += 1
+ end
-# Ractor.make_shareable issue for locals in proc [Bug #18023]
-assert_equal '[:a, :b, :c, :d, :e, :f, :g]', %q{
- a = :a
- closure = Ractor.current.instance_eval do
- -> {
- b, c, d = :b, :c, :d
- -> {
- e, f, g = :e, :f, :g
- -> { [a, b, c, d, e, f, g] }
- }.call
- }.call
+ begin
+ cond = false
+ b = 1
+ b = 2 if cond
+ Ractor.shareable_proc{b}
+ rescue Ractor::IsolationError => e
+ ok += 1
end
- Ractor.make_shareable(closure).call
+ begin
+ 1.times{|i|
+ i = 2
+ Ractor.shareable_proc{i}
+ }
+ rescue Ractor::IsolationError => e
+ ok += 1
+ end
}
###
@@ -218,27 +255,32 @@ if ENV['GITHUB_WORKFLOW'] == 'Compilations'
# ignore the follow
else
-# Ractor.select(*ractors) receives a values from a ractors.
-# It is similar to select(2) and Go's select syntax.
-# The return value is [ch, received_value]
+# Ractor.select with a Ractor argument
assert_equal 'ok', %q{
# select 1
r1 = Ractor.new{'r1'}
- r, obj = Ractor.select(r1)
- 'ok' if r == r1 and obj == 'r1'
+ port, obj = Ractor.select(r1)
+ if port == r1 and obj == 'r1'
+ 'ok'
+ else
+ # failed
+ [port, obj].inspect
+ end
}
# Ractor.select from two ractors.
assert_equal '["r1", "r2"]', %q{
# select 2
- r1 = Ractor.new{'r1'}
- r2 = Ractor.new{'r2'}
- rs = [r1, r2]
+ p1 = Ractor::Port.new
+ p2 = Ractor::Port.new
+ r1 = Ractor.new(p1){|p1| p1 << 'r1'}
+ r2 = Ractor.new(p2){|p2| p2 << 'r2'}
+ ps = [p1, p2]
as = []
- r, obj = Ractor.select(*rs)
- rs.delete(r)
+ port, obj = Ractor.select(*ps)
+ ps.delete(port)
as << obj
- r, obj = Ractor.select(*rs)
+ port, obj = Ractor.select(*ps)
as << obj
as.sort #=> ["r1", "r2"]
}
@@ -274,7 +316,7 @@ assert_equal 30.times.map { 'ok' }.to_s, %q{
} unless (ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'arm64') # https://bugs.ruby-lang.org/issues/17878
# Exception for empty select
-assert_match /specify at least one ractor/, %q{
+assert_match /specify at least one Ractor::Port or Ractor/, %q{
begin
Ractor.select
rescue ArgumentError => e
@@ -282,30 +324,12 @@ assert_match /specify at least one ractor/, %q{
end
}
-# Outgoing port of a ractor will be closed when the Ractor is terminated.
-assert_equal 'ok', %q{
- r = Ractor.new do
- 'finish'
- end
-
- r.take
- sleep 0.1 until r.inspect =~ /terminated/
-
- begin
- o = r.take
- rescue Ractor::ClosedError
- 'ok'
- else
- "ng: #{o}"
- end
-}
-
# Raise Ractor::ClosedError when try to send into a terminated ractor
assert_equal 'ok', %q{
r = Ractor.new do
end
- r.take # closed
+ r.join # closed
sleep 0.1 until r.inspect =~ /terminated/
begin
@@ -317,47 +341,16 @@ assert_equal 'ok', %q{
end
}
-# Raise Ractor::ClosedError when try to send into a closed actor
-assert_equal 'ok', %q{
- r = Ractor.new { Ractor.receive }
- r.close_incoming
-
- begin
- r.send(1)
- rescue Ractor::ClosedError
- 'ok'
- else
- 'ng'
- end
-}
-
-# Raise Ractor::ClosedError when try to take from closed actor
-assert_equal 'ok', %q{
- r = Ractor.new do
- Ractor.yield 1
- Ractor.receive
- end
-
- r.close_outgoing
- begin
- r.take
- rescue Ractor::ClosedError
- 'ok'
- else
- 'ng'
- end
-}
-
-# Can mix with Thread#interrupt and Ractor#take [Bug #17366]
+# Can mix with Thread#interrupt and Ractor#join [Bug #17366]
assert_equal 'err', %q{
- Ractor.new{
+ Ractor.new do
t = Thread.current
begin
Thread.new{ t.raise "err" }.join
rescue => e
e.message
end
- }.take
+ end.value
}
# Killed Ractor's thread yields nil
@@ -365,34 +358,18 @@ assert_equal 'nil', %q{
Ractor.new{
t = Thread.current
Thread.new{ t.kill }.join
- }.take.inspect #=> nil
+ }.value.inspect #=> nil
}
-# Ractor.yield raises Ractor::ClosedError when outgoing port is closed.
+# Raise Ractor::ClosedError when try to send into a ractor with closed default port
assert_equal 'ok', %q{
- r = Ractor.new Ractor.current do |main|
+ r = Ractor.new {
+ Ractor.current.close
+ Ractor.main << :ok
Ractor.receive
- main << true
- Ractor.yield 1
- end
-
- r.close_outgoing
- r << true
- Ractor.receive
-
- begin
- r.take
- rescue Ractor::ClosedError
- 'ok'
- else
- 'ng'
- end
-}
+ }
-# Raise Ractor::ClosedError when try to send into a ractor with closed incoming port
-assert_equal 'ok', %q{
- r = Ractor.new { Ractor.receive }
- r.close_incoming
+ Ractor.receive # wait for ok
begin
r.send(1)
@@ -403,154 +380,82 @@ assert_equal 'ok', %q{
end
}
-# A ractor with closed incoming port still can send messages out
-assert_equal '[1, 2]', %q{
- r = Ractor.new do
- Ractor.yield 1
- 2
- end
- r.close_incoming
-
- [r.take, r.take]
-}
-
-# Raise Ractor::ClosedError when try to take from a ractor with closed outgoing port
-assert_equal 'ok', %q{
- r = Ractor.new do
- Ractor.yield 1
- Ractor.receive
- end
-
- sleep 0.01 # wait for Ractor.yield in r
- r.close_outgoing
- begin
- r.take
- rescue Ractor::ClosedError
- 'ok'
- else
- 'ng'
- end
-}
-
-# A ractor with closed outgoing port still can receive messages from incoming port
-assert_equal 'ok', %q{
- r = Ractor.new do
- Ractor.receive
- end
-
- r.close_outgoing
- begin
- r.send(1)
- rescue Ractor::ClosedError
- 'ng'
- else
- 'ok'
- end
-}
-
# Ractor.main returns main ractor
assert_equal 'true', %q{
Ractor.new{
Ractor.main
- }.take == Ractor.current
+ }.value == Ractor.current
}
# a ractor with closed outgoing port should terminate
assert_equal 'ok', %q{
Ractor.new do
- close_outgoing
+ Ractor.current.close
end
true until Ractor.count == 1
:ok
}
-# multiple Ractors can receive (wait) from one Ractor
-assert_equal '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]', %q{
- pipe = Ractor.new do
- loop do
- Ractor.yield Ractor.receive
- end
+# an exception in a Ractor main thread will be re-raised at Ractor#receive
+assert_equal '[RuntimeError, "ok", true]', %q{
+ r = Ractor.new do
+ raise 'ok' # exception will be transferred receiver
end
-
- RN = 10
- rs = RN.times.map{|i|
- Ractor.new pipe, i do |pipe, i|
- msg = pipe.take
- msg # ping-pong
- end
- }
- RN.times{|i|
- pipe << i
- }
- RN.times.map{
- r, n = Ractor.select(*rs)
- rs.delete r
- n
- }.sort
-} unless /mswin/ =~ RUBY_PLATFORM # randomly hangs on mswin https://github.com/ruby/ruby/actions/runs/3753871445/jobs/6377551069#step:20:131
-
-# Ractor.select also support multiple take, receive and yield
-assert_equal '[true, true, true]', %q{
- RN = 10
- CR = Ractor.current
-
- rs = (1..RN).map{
- Ractor.new do
- CR.send 'send' + CR.take #=> 'sendyield'
- 'take'
- end
- }
- received = []
- taken = []
- yielded = []
- until received.size == RN && taken.size == RN && yielded.size == RN
- r, v = Ractor.select(CR, *rs, yield_value: 'yield')
- case r
- when :receive
- received << v
- when :yield
- yielded << v
- else
- taken << v
- rs.delete r
- end
+ begin
+ r.join
+ rescue Ractor::RemoteError => e
+ [e.cause.class, #=> RuntimeError
+ e.cause.message, #=> 'ok'
+ e.ractor == r] #=> true
end
- r = [received == ['sendyield'] * RN,
- yielded == [nil] * RN,
- taken == ['take'] * RN,
- ]
-
- STDERR.puts [received, yielded, taken].inspect
- r
}
-# multiple Ractors can send to one Ractor
-assert_equal '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]', %q{
- pipe = Ractor.new do
- loop do
- Ractor.yield Ractor.receive
- end
+# an exception in a Ractor will be re-raised at Ractor#value
+assert_equal '[RuntimeError, "ok", true]', %q{
+ r = Ractor.new do
+ raise 'ok' # exception will be transferred receiver
end
+ begin
+ r.value
+ rescue Ractor::RemoteError => e
+ [e.cause.class, #=> RuntimeError
+ e.cause.message, #=> 'ok'
+ e.ractor == r] #=> true
+ end
+}
- RN = 10
- RN.times.map{|i|
- Ractor.new pipe, i do |pipe, i|
- pipe << i
+# an exception in a Ractor non-main thread will not be re-raised at Ractor#receive
+assert_equal 'ok', %q{
+ r = Ractor.new do
+ Thread.new do
+ raise 'ng'
end
- }
- RN.times.map{
- pipe.take
- }.sort
+ sleep 0.1
+ 'ok'
+ end
+ r.value
}
-# an exception in a Ractor will be re-raised at Ractor#receive
-assert_equal '[RuntimeError, "ok", true]', %q{
- r = Ractor.new do
- raise 'ok' # exception will be transferred receiver
+# SystemExit from a Ractor is re-raised
+# [Bug #21505]
+assert_equal '[SystemExit, "exit", true]', %q{
+ r = Ractor.new { exit }
+ begin
+ r.value
+ rescue Ractor::RemoteError => e
+ [e.cause.class, #=> RuntimeError
+ e.cause.message, #=> 'ok'
+ e.ractor == r] #=> true
end
+}
+
+# SystemExit from a Thread inside a Ractor is re-raised
+# [Bug #21505]
+assert_equal '[SystemExit, "exit", true]', %q{
+ r = Ractor.new { Thread.new { exit }.join }
begin
- r.take
+ r.value
rescue Ractor::RemoteError => e
[e.cause.class, #=> RuntimeError
e.cause.message, #=> 'ok'
@@ -589,7 +494,7 @@ assert_equal '{ok: 3}', %q{
end
3.times.map{Ractor.receive}.tally
-} unless yjit_enabled? # `[BUG] Bus Error at 0x000000010b7002d0` in jit_exec()
+} unless yjit_enabled? # YJIT: `[BUG] Bus Error at 0x000000010b7002d0` in jit_exec()
# unshareable object are copied
assert_equal 'false', %q{
@@ -598,18 +503,18 @@ assert_equal 'false', %q{
msg.object_id
end
- obj.object_id == r.take
+ obj.object_id == r.value
}
# To copy the object, now Marshal#dump is used
-assert_equal "allocator undefined for Thread", %q{
+assert_match /can't clone unshareable instance of Thread/, %q{
obj = Thread.new{}
begin
r = Ractor.new obj do |msg|
msg
end
- rescue TypeError => e
- e.message #=> no _dump_data is defined for class Thread
+ rescue Ractor::Error => e
+ e.message
else
'ng'
end
@@ -617,10 +522,11 @@ assert_equal "allocator undefined for Thread", %q{
# send shareable and unshareable objects
assert_equal "ok", <<~'RUBY', frozen_string_literal: false
- echo_ractor = Ractor.new do
+ port = Ractor::Port.new
+ echo_ractor = Ractor.new port do |port|
loop do
v = Ractor.receive
- Ractor.yield v
+ port << v
end
end
@@ -668,13 +574,13 @@ assert_equal "ok", <<~'RUBY', frozen_string_literal: false
shareable_objects.map{|o|
echo_ractor << o
- o2 = echo_ractor.take
+ o2 = port.receive
results << "#{o} is copied" unless o.object_id == o2.object_id
}
unshareable_objects.map{|o|
echo_ractor << o
- o2 = echo_ractor.take
+ o2 = port.receive
results << "#{o.inspect} is not copied" if o.object_id == o2.object_id
}
@@ -700,7 +606,7 @@ assert_equal [false, true, false].inspect, <<~'RUBY', frozen_string_literal: fal
def check obj1
obj2 = Ractor.new obj1 do |obj|
obj
- end.take
+ end.value
obj1.object_id == obj2.object_id
end
@@ -722,7 +628,7 @@ assert_equal 'hello world', <<~'RUBY', frozen_string_literal: false
str = 'hello'
r.send str, move: true
- modified = r.take
+ modified = r.value
begin
str << ' exception' # raise Ractor::MovedError
@@ -742,7 +648,7 @@ assert_equal '[0, 1]', %q{
a1 = [0]
r.send a1, move: true
- a2 = r.take
+ a2 = r.value
begin
a1 << 2 # raise Ractor::MovedError
rescue Ractor::MovedError
@@ -752,79 +658,37 @@ assert_equal '[0, 1]', %q{
# unshareable frozen objects should still be frozen in new ractor after move
assert_equal 'true', %q{
-r = Ractor.new do
- obj = receive
- { frozen: obj.frozen? }
-end
-obj = [Object.new].freeze
-r.send(obj, move: true)
-r.take[:frozen]
-}
-
-# move with yield
-assert_equal 'hello', %q{
- r = Ractor.new do
- Thread.current.report_on_exception = false
- obj = 'hello'
- Ractor.yield obj, move: true
- obj << 'world'
- end
-
- str = r.take
- begin
- r.take
- rescue Ractor::RemoteError
- str #=> "hello"
- end
-}
-
-# yield/move should not make moved object when the yield is not succeeded
-assert_equal '"str"', %q{
- R = Ractor.new{}
- M = Ractor.current
- r = Ractor.new do
- s = 'str'
- selected_r, v = Ractor.select R, yield_value: s, move: true
- raise if selected_r != R # taken from R
- M.send s.inspect # s should not be a moved object
- end
-
- Ractor.receive
-}
-
-# yield/move can fail
-assert_equal "allocator undefined for Thread", %q{
r = Ractor.new do
- obj = Thread.new{}
- Ractor.yield obj
- rescue => e
- e.message
+ obj = receive
+ { frozen: obj.frozen? }
end
- r.take
+ obj = [Object.new].freeze
+ r.send(obj, move: true)
+ r.value[:frozen]
}
-# Access to global-variables are prohibited
-assert_equal 'can not access global variables $gv from non-main Ractors', %q{
+# Access to global-variables are prohibited (read)
+assert_equal 'can not access global variable $gv from non-main Ractor', %q{
$gv = 1
r = Ractor.new do
$gv
end
begin
- r.take
+ r.join
rescue Ractor::RemoteError => e
e.cause.message
end
}
-# Access to global-variables are prohibited
-assert_equal 'can not access global variables $gv from non-main Ractors', %q{
+# Access to global-variables are prohibited (write)
+assert_equal 'can not access global variable $gv from non-main Ractor', %q{
r = Ractor.new do
$gv = 1
end
begin
- r.take
+ r.join
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -838,7 +702,7 @@ assert_equal 'ok', %q{
}
end
- [$stdin, $stdout, $stderr].zip(r.take){|io, (oid, fno)|
+ [$stdin, $stdout, $stderr].zip(r.value){|io, (oid, fno)|
raise "should not be different object" if io.object_id == oid
raise "fd should be same" unless io.fileno == fno
}
@@ -854,7 +718,7 @@ assert_equal 'ok', %q{
'ok'
end
- r.take
+ r.value
}
# $DEBUG, $VERBOSE are Ractor local
@@ -912,7 +776,7 @@ assert_equal 'true', %q{
h = Ractor.new do
ractor_local_globals
- end.take
+ end.value
ractor_local_globals == h #=> true
}
@@ -921,7 +785,8 @@ assert_equal 'false', %q{
r = Ractor.new do
self.object_id
end
- r.take == self.object_id #=> false
+ ret = r.value
+ ret == self.object_id
}
# self is a Ractor instance
@@ -929,11 +794,16 @@ assert_equal 'true', %q{
r = Ractor.new do
self.object_id
end
- r.object_id == r.take #=> true
+ ret = r.value
+ if r.object_id == ret #=> true
+ true
+ else
+ raise [ret, r.object_id].inspect
+ end
}
# given block Proc will be isolated, so can not access outer variables.
-assert_equal 'ArgumentError', %q{
+assert_equal 'Ractor::IsolationError', %q{
begin
a = true
r = Ractor.new do
@@ -944,8 +814,39 @@ assert_equal 'ArgumentError', %q{
end
}
+# eval with outer locals in a Ractor raises SyntaxError
+# [Bug #21522]
+assert_equal 'SyntaxError', %q{
+ outer = 42
+ r = Ractor.new do
+ eval("outer")
+ end
+ begin
+ r.value
+ rescue Ractor::RemoteError => e
+ e.cause.class
+ end
+}
+
+# eval of an undefined name in a Ractor raises NameError
+assert_equal 'NameError', %q{
+ r = Ractor.new do
+ eval("totally_undefined_name")
+ end
+ begin
+ r.value
+ rescue Ractor::RemoteError => e
+ e.cause.class
+ end
+}
+
+# eval of a local defined inside the Ractor works
+assert_equal '99', %q{
+ Ractor.new { inner = 99; eval("inner").to_s }.value
+}
+
# ivar in shareable-objects are not allowed to access from non-main Ractor
-assert_equal "can not get unshareable values from instance variables of classes/modules from non-main Ractors", <<~'RUBY', frozen_string_literal: false
+assert_equal "can not get unshareable values from instance variables of classes/modules from non-main Ractors (@iv from C)", <<~'RUBY', frozen_string_literal: false
class C
@iv = 'str'
end
@@ -957,7 +858,7 @@ assert_equal "can not get unshareable values from instance variables of classes/
end
begin
- r.take
+ r.value
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -973,7 +874,7 @@ assert_equal 'can not access instance variables of shareable objects from non-ma
end
begin
- r.take
+ r.value
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -999,7 +900,7 @@ assert_equal 'can not access instance variables of shareable objects from non-ma
end
begin
- r.take
+ r.value
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -1020,7 +921,7 @@ assert_equal 'can not access instance variables of shareable objects from non-ma
end
begin
- r.take
+ r.value
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -1034,7 +935,7 @@ assert_equal '11', %q{
Ractor.new obj do |obj|
obj.instance_variable_get('@a')
- end.take.to_s
+ end.value.to_s
}.join
}
@@ -1060,25 +961,25 @@ assert_equal '333', %q{
def self.fstr = @fstr
end
- a = Ractor.new{ C.int }.take
+ a = Ractor.new{ C.int }.value
b = Ractor.new do
C.str.to_i
rescue Ractor::IsolationError
10
- end.take
+ end.value
c = Ractor.new do
C.fstr.to_i
- end.take
+ end.value
- d = Ractor.new{ M.int }.take
+ d = Ractor.new{ M.int }.value
e = Ractor.new do
M.str.to_i
rescue Ractor::IsolationError
20
- end.take
+ end.value
f = Ractor.new do
M.fstr.to_i
- end.take
+ end.value
# 1 + 10 + 100 + 2 + 20 + 200
@@ -1096,32 +997,32 @@ assert_equal '["instance-variable", "instance-variable", nil]', %q{
Ractor.new{
[C.iv1, C.iv2, C.iv3]
- }.take
+ }.value
}
# moved objects have their shape properly set to original object's shape
assert_equal '1234', %q{
-class Obj
- attr_accessor :a, :b, :c, :d
- def initialize
- @a = 1
- @b = 2
- @c = 3
+ class Obj
+ attr_accessor :a, :b, :c, :d
+ def initialize
+ @a = 1
+ @b = 2
+ @c = 3
+ end
end
-end
-r = Ractor.new do
- obj = receive
- obj.d = 4
- [obj.a, obj.b, obj.c, obj.d]
-end
-obj = Obj.new
-r.send(obj, move: true)
-values = r.take
-values.join
+ r = Ractor.new do
+ obj = receive
+ obj.d = 4
+ [obj.a, obj.b, obj.c, obj.d]
+ end
+ obj = Obj.new
+ r.send(obj, move: true)
+ values = r.value
+ values.join
}
-# cvar in shareable-objects are not allowed to access from non-main Ractor
-assert_equal 'can not access class variables from non-main Ractors', %q{
+# Reading non-shareable cvar from non-main Ractor is not allowed
+assert_equal 'can not read non-shareable class variable @@cv from non-main Ractors (C)', %q{
class C
@@cv = 'str'
end
@@ -1133,14 +1034,14 @@ assert_equal 'can not access class variables from non-main Ractors', %q{
end
begin
- r.take
+ r.join
rescue Ractor::RemoteError => e
e.cause.message
end
}
-# also cached cvar in shareable-objects are not allowed to access from non-main Ractor
-assert_equal 'can not access class variables from non-main Ractors', %q{
+# also cached non-shareable cvar read from non-main Ractor is not allowed
+assert_equal 'can not read non-shareable class variable @@cv from non-main Ractors (C)', %q{
class C
@@cv = 'str'
def self.cv
@@ -1155,12 +1056,101 @@ assert_equal 'can not access class variables from non-main Ractors', %q{
end
begin
- r.take
+ r.join
+ rescue Ractor::RemoteError => e
+ e.cause.message
+ end
+}
+
+# Reading shareable cvar from non-main Ractor is allowed
+assert_equal 'shareable', %q{
+ class C
+ @@cv = 'shareable'.freeze
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value
+}
+
+# Reading shareable cvar (integer) from non-main Ractor is allowed
+assert_equal '42', %q{
+ class C
+ @@cv = 42
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value.to_s
+}
+
+# Reading shareable cvar via module include from non-main Ractor is allowed
+assert_equal 'hello', %q{
+ module M
+ @@cv = 'hello'.freeze
+ def self.cv
+ @@cv
+ end
+ end
+
+ class C
+ include M
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value
+}
+
+# Writing cvar from non-main Ractor is not allowed
+assert_equal 'can not set class variables from non-main Ractors (@@cv from C)', %q{
+ class C
+ @@cv = 'str'
+ def self.cv=(v)
+ @@cv = v
+ end
+ end
+
+ r = Ractor.new do
+ C.cv = 'new'
+ end
+
+ begin
+ r.join
rescue Ractor::RemoteError => e
e.cause.message
end
}
+# Reading cvar that was made shareable after initial assignment
+assert_equal 'made shareable', %q{
+ class C
+ @@cv = +'made shareable'
+ Ractor.make_shareable(@@cv)
+ def self.cv
+ @@cv
+ end
+ end
+
+ Ractor.new { C.cv }.value
+}
+
+# cvar_defined? works from non-main Ractor
+assert_equal 'true', %q{
+ class C
+ @@cv = 42
+ def self.cv?
+ defined?(@@cv)
+ end
+ end
+
+ r = Ractor.new { C.cv? ? 'true' : 'false' }
+ r.value
+}
+
# Getting non-shareable objects via constants by other Ractors is not allowed
assert_equal 'can not access non-shareable objects in constant C::CONST by non-main Ractor.', <<~'RUBY', frozen_string_literal: false
class C
@@ -1170,19 +1160,33 @@ assert_equal 'can not access non-shareable objects in constant C::CONST by non-m
C::CONST
end
begin
- r.take
+ r.join
rescue Ractor::RemoteError => e
e.cause.message
end
RUBY
-# Constant cache should care about non-sharable constants
+# Constant cache should care about non-shareable constants
assert_equal "can not access non-shareable objects in constant Object::STR by non-main Ractor.", <<~'RUBY', frozen_string_literal: false
STR = "hello"
def str; STR; end
s = str() # fill const cache
begin
- Ractor.new{ str() }.take
+ Ractor.new{ str() }.join
+ rescue Ractor::RemoteError => e
+ e.cause.message
+ end
+RUBY
+
+# The correct constant path shall be reported
+assert_equal "can not access non-shareable objects in constant Object::STR by non-main Ractor.", <<~'RUBY', frozen_string_literal: false
+ STR = "hello"
+ module M
+ def self.str; STR; end
+ end
+
+ begin
+ Ractor.new{ M.str }.join
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -1196,7 +1200,7 @@ assert_equal 'can not set constants with non-shareable objects by non-main Racto
C::CONST = 'str'
end
begin
- r.take
+ r.join
rescue Ractor::RemoteError => e
e.cause.message
end
@@ -1207,7 +1211,7 @@ assert_equal "defined with an un-shareable Proc in a different Ractor", %q{
str = "foo"
define_method(:buggy){|i| str << "#{i}"}
begin
- Ractor.new{buggy(10)}.take
+ Ractor.new{buggy(10)}.join
rescue => e
e.cause.message
end
@@ -1218,7 +1222,7 @@ assert_equal '[1000, 3]', %q{
A = Array.new(1000).freeze # [nil, ...]
H = {a: 1, b: 2, c: 3}.freeze
- Ractor.new{ [A.size, H.size] }.take
+ Ractor.new{ [A.size, H.size] }.value
}
# Ractor.count
@@ -1228,15 +1232,15 @@ assert_equal '[1, 4, 3, 2, 1]', %q{
ractors = (1..3).map { Ractor.new { Ractor.receive } }
counts << Ractor.count
- ractors[0].send('End 0').take
+ ractors[0].send('End 0').join
sleep 0.1 until ractors[0].inspect =~ /terminated/
counts << Ractor.count
- ractors[1].send('End 1').take
+ ractors[1].send('End 1').join
sleep 0.1 until ractors[1].inspect =~ /terminated/
counts << Ractor.count
- ractors[2].send('End 2').take
+ ractors[2].send('End 2').join
sleep 0.1 until ractors[2].inspect =~ /terminated/
counts << Ractor.count
@@ -1249,7 +1253,7 @@ assert_equal '0', %q{
n = 0
ObjectSpace.each_object{|o| n += 1 unless Ractor.shareable?(o)}
n
- }.take
+ }.value
}
# ObjectSpace._id2ref can not handle unshareable objects with Ractors
@@ -1262,7 +1266,25 @@ assert_equal 'ok', <<~'RUBY', frozen_string_literal: false
rescue => e
:ok
end
- end.take
+ end.value
+RUBY
+
+# Inserting into the id2ref table should be Ractor-safe
+assert_equal 'ok', <<~'RUBY'
+ # Force all calls to Kernel#object_id to insert into the id2ref table
+ obj = Object.new
+ ObjectSpace._id2ref(obj.object_id) rescue nil
+
+ 10.times.map do
+ Ractor.new do
+ 10_000.times do
+ a = Object.new
+ a.object_id
+ end
+ end
+ end.map(&:value)
+
+ :ok
RUBY
# Ractor.make_shareable(obj)
@@ -1346,41 +1368,42 @@ assert_equal 'true', %q{
[a.frozen?, a[0].frozen?] == [true, false]
}
-# Ractor.make_shareable(a_proc) makes a proc shareable.
-assert_equal 'true', %q{
- a = [1, [2, 3], {a: "4"}]
+# Ractor.make_shareable(a_proc) requires a shareable receiver
+assert_equal '[:ok, "Proc\'s self is not shareable:"]', %q{
+ pr1 = nil.instance_exec { Proc.new{} }
+ pr2 = Proc.new{}
- pr = Ractor.current.instance_eval do
- Proc.new do
- a
+ [pr1, pr2].map do |pr|
+ begin
+ Ractor.make_shareable(pr)
+ rescue Ractor::Error => e
+ e.message[/^.+?:/]
+ else
+ :ok
end
end
-
- Ractor.make_shareable(a) # referred value should be shareable
- Ractor.make_shareable(pr)
- Ractor.shareable?(pr)
}
-# Ractor.make_shareable(a_proc) makes inner structure shareable and freezes it
-assert_equal 'true,true,true,true', %q{
- class Proc
- attr_reader :obj
- def initialize
- @obj = Object.new
- end
+# Ractor.make_shareable(Method/UnboundMethod)
+assert_equal 'true', %q{
+ # raise because receiver is unshareable
+ begin
+ _m0 = Ractor.make_shareable(self.method(:__id__))
+ rescue => e
+ raise e unless e.message =~ /can not make shareable object/
+ else
+ raise "no error"
end
- pr = Ractor.current.instance_eval do
- Proc.new {}
- end
+ # Method with shareable receiver
+ M1 = Ractor.make_shareable(Object.method(:__id__))
- results = []
- Ractor.make_shareable(pr)
- results << Ractor.shareable?(pr)
- results << pr.frozen?
- results << Ractor.shareable?(pr.obj)
- results << pr.obj.frozen?
- results.map(&:to_s).join(',')
+ # UnboundMethod
+ M2 = Ractor.make_shareable(Object.instance_method(:__id__))
+
+ Ractor.new do
+ Object.__id__ == M1.call && M1.call == M2.bind_call(Object)
+ end.value
}
# Ractor.shareable?(recursive_objects)
@@ -1411,48 +1434,14 @@ assert_equal '[C, M]', %q{
Ractor.make_shareable(ary = [C, M])
}
-# Ractor.make_shareable with curried proc checks isolation of original proc
-assert_equal 'isolation error', %q{
- a = Object.new
- orig = proc { a }
- curried = orig.curry
-
- begin
- Ractor.make_shareable(curried)
- rescue Ractor::IsolationError
- 'isolation error'
- else
- 'no error'
- end
-}
-
# define_method() can invoke different Ractor's proc if the proc is shareable.
assert_equal '1', %q{
class C
a = 1
- define_method "foo", Ractor.make_shareable(Proc.new{ a })
- a = 2
- end
-
- Ractor.new{ C.new.foo }.take
-}
-
-# Ractor.make_shareable(a_proc) makes a proc shareable.
-assert_equal 'can not make a Proc shareable because it accesses outer variables (a).', %q{
- a = b = nil
- pr = Ractor.current.instance_eval do
- Proc.new do
- c = b # assign to a is okay because c is block local variable
- # reading b is okay
- a = b # assign to a is not allowed #=> Ractor::Error
- end
+ define_method "foo", Ractor.shareable_proc{ a }
end
- begin
- Ractor.make_shareable(pr)
- rescue => e
- e.message
- end
+ Ractor.new{ C.new.foo }.value
}
# Ractor.make_shareable(obj, copy: true) makes copied shareable object.
@@ -1477,7 +1466,7 @@ assert_equal '[6, 10]', %q{
Ractor.new{ # line 5
a = 1
b = 2
- }.take
+ }.value
c = 3 # line 9
end
rs
@@ -1487,7 +1476,7 @@ assert_equal '[6, 10]', %q{
assert_equal '[true, false]', %q{
Ractor.new([[]].freeze) { |ary|
[ary.frozen?, ary.first.frozen? ]
- }.take
+ }.value
}
# Ractor deep copies frozen objects (str)
@@ -1495,7 +1484,7 @@ assert_equal '[true, false]', %q{
s = String.new.instance_eval { @x = []; freeze}
Ractor.new(s) { |s|
[s.frozen?, s.instance_variable_get(:@x).frozen?]
- }.take
+ }.value
}
# Can not trap with not isolated Proc on non-main ractor
@@ -1503,15 +1492,15 @@ assert_equal '[:ok, :ok]', %q{
a = []
Ractor.new{
trap(:INT){p :ok}
- }.take
+ }.join
a << :ok
begin
Ractor.new{
s = 'str'
trap(:INT){p s}
- }.take
- rescue => Ractor::RemoteError
+ }.join
+ rescue Ractor::RemoteError
a << :ok
end
}
@@ -1540,12 +1529,12 @@ assert_equal '[nil, "b", "a"]', %q{
ans = []
Ractor.current[:key] = 'a'
r = Ractor.new{
- Ractor.yield self[:key]
+ Ractor.main << self[:key]
self[:key] = 'b'
self[:key]
}
- ans << r.take
- ans << r.take
+ ans << Ractor.receive
+ ans << r.value
ans << Ractor.current[:key]
}
@@ -1561,7 +1550,25 @@ assert_equal '1', %q{
}
}.each(&:join)
a.uniq.size
- }.take
+ }.value
+}
+
+# Ractor-local storage
+assert_equal '2', %q{
+ Ractor.new {
+ fails = 0
+ begin
+ Ractor.main[:key] # cannot get ractor local storage from non-main ractor
+ rescue => e
+ fails += 1 if e.message =~ /Cannot get ractor local/
+ end
+ begin
+ Ractor.main[:key] = 'val'
+ rescue => e
+ fails += 1 if e.message =~ /Cannot set ractor local/
+ end
+ fails
+ }.value
}
###
@@ -1577,10 +1584,28 @@ assert_equal "#{N}#{N}", %Q{
Ractor.new{
N.times{|i| -(i.to_s)}
}
- }.map{|r| r.take}.join
+ }.map{|r| r.value}.join
+}
+
+assert_equal "ok", %Q{
+ N = #{N}
+ a, b = 2.times.map{
+ Ractor.new{
+ N.times.map{|i| -(i.to_s)}
+ }
+ }.map{|r| r.value}
+ N.times do |i|
+ unless a[i].equal?(b[i])
+ raise [a[i], b[i]].inspect
+ end
+ unless a[i] == i.to_s
+ raise [i, a[i], b[i]].inspect
+ end
+ end
+ :ok
}
-# Generic ivtbl
+# Generic fields_tbl
n = N/2
assert_equal "#{n}#{n}", %Q{
2.times.map{
@@ -1593,21 +1618,20 @@ assert_equal "#{n}#{n}", %Q{
obj.instance_variable_defined?("@a")
end
end
- }.map{|r| r.take}.join
+ }.map{|r| r.value}.join
}
-# NameError
-assert_equal "ok", %q{
+# Now NoMethodError is copyable
+assert_equal "NoMethodError", %q{
obj = "".freeze # NameError refers the receiver indirectly
begin
obj.bar
rescue => err
end
- begin
- Ractor.new{} << err
- rescue TypeError
- 'ok'
- end
+
+ r = Ractor.new{ Ractor.receive }
+ r << err
+ r.value.class
}
assert_equal "ok", %q{
@@ -1625,54 +1649,27 @@ assert_equal "ok", %q{
# Can yield back values while GC is sweeping [Bug #18117]
assert_equal "ok", %q{
+ port = Ractor::Port.new
workers = (0...8).map do
- Ractor.new do
+ Ractor.new port do |port|
loop do
10_000.times.map { Object.new }
- Ractor.yield Time.now
+ port << Time.now
+ Ractor.receive
end
end
end
- 1_000.times { idle_worker, tmp_reporter = Ractor.select(*workers) }
+ 100.times {
+ workers.each do
+ port.receive
+ end
+ workers.each do |w|
+ w.send(nil)
+ end
+ }
"ok"
-} if !yjit_enabled? || ENV['GITHUB_WORKFLOW'] == 'ModGC' # flaky
-
-assert_equal "ok", %q{
- def foo(*); ->{ super }; end
- begin
- Ractor.make_shareable(foo)
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
-assert_equal "ok", %q{
- def foo(**); ->{ super }; end
- begin
- Ractor.make_shareable(foo)
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
-assert_equal "ok", %q{
- def foo(...); ->{ super }; end
- begin
- Ractor.make_shareable(foo)
- rescue Ractor::IsolationError
- "ok"
- end
-}
-
-assert_equal "ok", %q{
- def foo((x), (y)); ->{ super }; end
- begin
- Ractor.make_shareable(foo([], []))
- rescue Ractor::IsolationError
- "ok"
- end
-}
+} if !yjit_enabled? && ENV['GITHUB_WORKFLOW'] != 'ModGC' # flaky
# check method cache invalidation
assert_equal "ok", %q{
@@ -1737,14 +1734,41 @@ assert_equal 'true', %q{
}
n = CS.inject(1){|r, c| r * c.foo} * LN
- rs.map{|r| r.take} == Array.new(RN){n}
+ rs.map{|r| r.value} == Array.new(RN){n}
+}
+
+# check method cache invalidation
+assert_equal 'true', %q{
+ class Foo
+ def hello = nil
+ end
+
+ r1 = Ractor.new do
+ 1000.times do
+ class Foo
+ def hello = nil
+ end
+ end
+ end
+
+ r2 = Ractor.new do
+ 1000.times do
+ o = Foo.new
+ o.hello
+ end
+ end
+
+ r1.value
+ r2.value
+
+ true
}
# check experimental warning
-assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{
+assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor API is experimental/, %q{
Warning[:experimental] = $VERBOSE = true
STDERR.reopen(STDOUT)
- eval("Ractor.new{}.take", nil, "test_ractor.rb", 1)
+ eval("Ractor.new{}.value", nil, "test_ractor.rb", 1)
}, frozen_string_literal: false
# check moved object
@@ -1762,7 +1786,7 @@ assert_equal 'ok', %q{
end
r.send obj, move: true
- r.take
+ r.value
}
## Ractor::Selector
@@ -1838,10 +1862,11 @@ assert_equal '600', %q{
RN = 100
s = Ractor::Selector.new
+ port = Ractor::Port.new
rs = RN.times.map{
Ractor.new{
- Ractor.main << Ractor.new{ Ractor.yield :v3; :v4 }
- Ractor.main << Ractor.new{ Ractor.yield :v5; :v6 }
+ Ractor.main << Ractor.new(port){|port| port << :v3; :v4 }
+ Ractor.main << Ractor.new(port){|port| port << :v5; :v6 }
Ractor.yield :v1
:v2
}
@@ -1907,7 +1932,7 @@ assert_equal 'true', %q{
# prism parser with -O0 build consumes a lot of machine stack
Data.define(:fileno).new(1)
end
- }.take.fileno > 0
+ }.value.fileno > 0
}
# require_relative in Ractor
@@ -1925,7 +1950,7 @@ assert_equal 'true', %q{
begin
Ractor.new dummyfile do |f|
require_relative File.basename(f)
- end.take
+ end.value
ensure
File.unlink dummyfile
end
@@ -1942,7 +1967,7 @@ assert_equal 'LoadError', %q{
rescue LoadError => e
e.class
end
- end.take
+ end.value
}
# autolaod in Ractor
@@ -1957,7 +1982,7 @@ assert_equal 'true', %q{
Data.define(:fileno).new(1)
end
end
- r.take.fileno > 0
+ r.value.fileno > 0
}
# failed in autolaod in Ractor
@@ -1972,7 +1997,7 @@ assert_equal 'LoadError', %q{
e.class
end
end
- r.take
+ r.value
}
# bind_call in Ractor [Bug #20934]
@@ -1983,7 +2008,7 @@ assert_equal 'ok', %q{
Object.instance_method(:itself).bind_call(self)
end
end
- end.each(&:take)
+ end.each(&:join)
GC.start
:ok.itself
}
@@ -1993,7 +2018,7 @@ assert_equal 'ok', %q{
ractor = Ractor.new { Ractor.receive }
obj = "foobarbazfoobarbazfoobarbazfoobarbaz"
ractor.send(obj.dup, move: true)
- roundtripped_obj = ractor.take
+ roundtripped_obj = ractor.value
roundtripped_obj == obj ? :ok : roundtripped_obj
}
@@ -2002,7 +2027,7 @@ assert_equal 'ok', %q{
ractor = Ractor.new { Ractor.receive }
obj = Array.new(10, 42)
ractor.send(obj.dup, move: true)
- roundtripped_obj = ractor.take
+ roundtripped_obj = ractor.value
roundtripped_obj == obj ? :ok : roundtripped_obj
}
@@ -2011,7 +2036,7 @@ assert_equal 'ok', %q{
ractor = Ractor.new { Ractor.receive }
obj = { foo: 1, bar: 2 }
ractor.send(obj.dup, move: true)
- roundtripped_obj = ractor.take
+ roundtripped_obj = ractor.value
roundtripped_obj == obj ? :ok : roundtripped_obj
}
@@ -2020,7 +2045,7 @@ assert_equal 'ok', %q{
ractor = Ractor.new { Ractor.receive }
obj = "foo".match(/o/)
ractor.send(obj.dup, move: true)
- roundtripped_obj = ractor.take
+ roundtripped_obj = ractor.value
roundtripped_obj == obj ? :ok : roundtripped_obj
}
@@ -2029,7 +2054,7 @@ assert_equal 'ok', %q{
ractor = Ractor.new { Ractor.receive }
obj = Struct.new(:a, :b, :c, :d, :e, :f).new(1, 2, 3, 4, 5, 6)
ractor.send(obj.dup, move: true)
- roundtripped_obj = ractor.take
+ roundtripped_obj = ractor.value
roundtripped_obj == obj ? :ok : roundtripped_obj
}
@@ -2056,7 +2081,7 @@ assert_equal 'ok', %q{
obj = SomeObject.new
ractor.send(obj.dup, move: true)
- roundtripped_obj = ractor.take
+ roundtripped_obj = ractor.value
roundtripped_obj == obj ? :ok : roundtripped_obj
}
@@ -2101,3 +2126,541 @@ assert_equal 'ok', %q{
:fail
end
}
+
+# move objects inside frozen containers
+assert_equal 'ok', %q{
+ ractor = Ractor.new { Ractor.receive }
+ obj = Array.new(10, 42)
+ original = obj.dup
+ ractor.send([obj].freeze, move: true)
+ roundtripped_obj = ractor.value[0]
+ roundtripped_obj == original ? :ok : roundtripped_obj
+}
+
+# move object with generic ivar
+assert_equal 'ok', %q{
+ ractor = Ractor.new { Ractor.receive }
+ obj = Array.new(10, 42)
+ obj.instance_variable_set(:@array, [1])
+
+ ractor.send(obj, move: true)
+ roundtripped_obj = ractor.value
+ roundtripped_obj.instance_variable_get(:@array) == [1] ? :ok : roundtripped_obj
+}
+
+# move object with many generic ivars
+assert_equal 'ok', %q{
+ ractor = Ractor.new { Ractor.receive }
+ obj = Array.new(10, 42)
+ 0.upto(300) do |i|
+ obj.instance_variable_set(:"@array#{i}", [i])
+ end
+
+ ractor.send(obj, move: true)
+ roundtripped_obj = ractor.value
+ roundtripped_obj.instance_variable_get(:@array1) == [1] ? :ok : roundtripped_obj
+}
+
+# move object with complex generic ivars
+assert_equal 'ok', %q{
+ # Make Array complex
+ 30.times { |i| [].instance_variable_set(:"@complex#{i}", 1) }
+
+ ractor = Ractor.new { Ractor.receive }
+ obj = Array.new(10, 42)
+ obj.instance_variable_set(:@array1, [1])
+
+ ractor.send(obj, move: true)
+ roundtripped_obj = ractor.value
+ roundtripped_obj.instance_variable_get(:@array1) == [1] ? :ok : roundtripped_obj
+}
+
+# move object with generic ivars and existing id2ref table
+# [Bug #21664]
+assert_equal 'ok', %q{
+ obj = [1]
+ obj.instance_variable_set("@field", :ok)
+ ObjectSpace._id2ref(obj.object_id) # build id2ref table
+
+ ractor = Ractor.new { Ractor.receive }
+ ractor.send(obj, move: true)
+ obj = ractor.value
+ obj.instance_variable_get("@field")
+}
+
+# copy object with complex generic ivars
+assert_equal 'ok', %q{
+ # Make Array complex
+ 30.times { |i| [].instance_variable_set(:"@complex#{i}", 1) }
+
+ ractor = Ractor.new { Ractor.receive }
+ obj = Array.new(10, 42)
+ obj.instance_variable_set(:@array1, [1])
+
+ ractor.send(obj)
+ roundtripped_obj = ractor.value
+ roundtripped_obj.instance_variable_get(:@array1) == [1] ? :ok : roundtripped_obj
+}
+
+# copy object with many generic ivars
+assert_equal 'ok', %q{
+ ractor = Ractor.new { Ractor.receive }
+ obj = Array.new(10, 42)
+ 0.upto(300) do |i|
+ obj.instance_variable_set(:"@array#{i}", [i])
+ end
+
+ ractor.send(obj)
+ roundtripped_obj = ractor.value
+ roundtripped_obj.instance_variable_get(:@array1) == [1] ? :ok : roundtripped_obj
+}
+
+# moved composite types move their non-shareable parts properly
+assert_equal 'ok', %q{
+ k, v = String.new("key"), String.new("value")
+ h = { k => v }
+ h.instance_variable_set("@b", String.new("b"))
+ a = [k,v]
+ o_singleton = Object.new
+ def o_singleton.a
+ @a
+ end
+ o_singleton.instance_variable_set("@a", String.new("a"))
+ class MyObject
+ attr_reader :a
+ def initialize(a)
+ @a = a
+ end
+ end
+ struct_class = Struct.new(:a)
+ struct = struct_class.new(String.new('a'))
+ o = MyObject.new(String.new('a'))
+ port = Ractor::Port.new
+
+ r = Ractor.new port do |port|
+ loop do
+ obj = Ractor.receive
+ val = case obj
+ when Hash
+ obj['key'] == 'value' && obj.instance_variable_get("@b") == 'b'
+ when Array
+ obj[0] == 'key'
+ when Struct
+ obj.a == 'a'
+ when Object
+ obj.a == 'a'
+ end
+ port << val
+ end
+ end
+
+ objs = [h, a, o_singleton, o, struct]
+ objs.each_with_index do |obj, i|
+ klass = obj.class
+ parts_moved = {}
+ case obj
+ when Hash
+ parts_moved[klass] = [obj['key'], obj.instance_variable_get("@b")]
+ when Array
+ parts_moved[klass] = obj.dup # the contents
+ when Struct, Object
+ parts_moved[klass] = [obj.a]
+ end
+ r.send(obj, move: true)
+ val = port.receive
+ if val != true
+ raise "bad val in ractor for obj at i:#{i}"
+ end
+ begin
+ p obj
+ rescue
+ else
+ raise "should be moved"
+ end
+ parts_moved.each do |klass, parts|
+ parts.each_with_index do |part, j|
+ case part
+ when Ractor::MovedObject
+ else
+ raise "part for class #{klass} at i:#{j} should be moved"
+ end
+ end
+ end
+ end
+ 'ok'
+}
+
+# fork after creating Ractor
+assert_equal 'ok', %q{
+begin
+ Ractor.new { Ractor.receive }
+ _, status = Process.waitpid2 fork { }
+ status.success? ? "ok" : status
+rescue NotImplementedError
+ :ok
+end
+}
+
+# Ractors should be terminated after fork
+assert_equal 'ok', %q{
+begin
+ r = Ractor.new { Ractor.receive }
+ _, status = Process.waitpid2 fork {
+ begin
+ raise if r.value != nil
+ end
+ }
+ r.send(123)
+ raise unless r.value == 123
+ status.success? ? "ok" : status
+rescue NotImplementedError
+ :ok
+end
+}
+
+# Ractors should be terminated after fork
+assert_equal 'ok', %q{
+begin
+ r = Ractor.new { Ractor.receive }
+ _, status = Process.waitpid2 fork {
+ begin
+ r.send(123)
+ rescue Ractor::ClosedError
+ end
+ }
+ r.send(123)
+ raise unless r.value == 123
+ status.success? ? "ok" : status
+rescue NotImplementedError
+ :ok
+end
+}
+
+# Creating classes inside of Ractors
+# [Bug #18119]
+assert_equal 'ok', %q{
+ port = Ractor::Port.new
+ workers = (0...8).map do
+ Ractor.new port do |port|
+ loop do
+ 100.times.map { Class.new }
+ port << nil
+ end
+ end
+ end
+
+ 100.times { port.receive }
+
+ 'ok'
+}
+
+# Using Symbol#to_proc inside ractors
+# [Bug #21354]
+assert_equal 'ok', %q{
+ :inspect.to_proc
+ Ractor.new do
+ # It should not use this cached proc, it should create a new one. If it used
+ # the cached proc, we would get a ractor_confirm_belonging error here.
+ :inspect.to_proc
+ end.join
+ 'ok'
+}
+
+# take vm lock when deleting generic ivars from the global table
+assert_equal 'ok', %q{
+ Ractor.new do
+ a = [1, 2, 3]
+ a.object_id
+ a.dup # this deletes generic ivar on dupped object
+ 'ok'
+ end.value
+}
+
+## Ractor#monitor
+
+# monitor port returns `:exited` when the monitering Ractor terminated.
+assert_equal 'true', %q{
+ r = Ractor.new do
+ Ractor.main << :ok1
+ :ok2
+ end
+
+ r.monitor port = Ractor::Port.new
+ Ractor.receive # :ok1
+ port.receive == :exited
+}
+
+# monitor port returns `:exited` even if the monitoring Ractor was terminated.
+assert_equal 'true', %q{
+ r = Ractor.new do
+ :ok
+ end
+
+ r.join # wait for r's terminateion
+
+ r.monitor port = Ractor::Port.new
+ port.receive == :exited
+}
+
+# monitor returns false if the monitoring Ractor was terminated.
+assert_equal 'false', %q{
+ r = Ractor.new do
+ :ok
+ end
+
+ r.join # wait for r's terminateion
+
+ r.monitor Ractor::Port.new
+}
+
+# monitor port returns `:aborted` when the monitering Ractor is aborted.
+assert_equal 'true', %q{
+ r = Ractor.new do
+ Ractor.main << :ok1
+ raise 'ok'
+ end
+
+ r.monitor port = Ractor::Port.new
+ Ractor.receive # :ok1
+ port.receive == :aborted
+}
+
+# monitor port returns `:aborted` even if the monitoring Ractor was aborted.
+assert_equal 'true', %q{
+ r = Ractor.new do
+ raise 'ok'
+ end
+
+ begin
+ r.join # wait for r's terminateion
+ rescue Ractor::RemoteError
+ # ignore
+ end
+
+ r.monitor port = Ractor::Port.new
+ port.receive == :aborted
+}
+
+## Ractor#join
+
+# Ractor#join returns self when the Ractor is terminated.
+assert_equal 'true', %q{
+ r = Ractor.new do
+ Ractor.receive
+ end
+
+ r << :ok
+ r.join
+ r.inspect in /terminated/
+} if false # TODO
+
+# Ractor#join raises RemoteError when the remote Ractor aborted with an exception
+assert_equal 'err', %q{
+ r = Ractor.new do
+ raise 'err'
+ end
+
+ begin
+ r.join
+ rescue Ractor::RemoteError => e
+ e.cause.message
+ end
+}
+
+## Ractor#value
+
+# Ractor#value returns the last expression even if it is unshareable
+assert_equal 'true', %q{
+ r = Ractor.new do
+ obj = [1, 2]
+ obj << obj.object_id
+ end
+
+ ret = r.value
+ ret == [1, 2, ret.object_id]
+}
+
+# Only one Ractor can call Ractor#value
+assert_equal '[["Only the successor ractor can take a value", 9], ["ok", 2]]', %q{
+ r = Ractor.new do
+ 'ok'
+ end
+
+ RN = 10
+
+ rs = RN.times.map do
+ Ractor.new r do |r|
+ begin
+ Ractor.main << r.value
+ Ractor.main << r.value # this ractor can get same result
+ rescue Ractor::Error => e
+ Ractor.main << e.message
+ end
+ end
+ end
+
+ (RN+1).times.map{
+ Ractor.receive
+ }.tally.sort
+}
+
+# Cause lots of inline CC misses.
+assert_equal 'ok', <<~'RUBY'
+ class A; def test; 1 + 1; end; end
+ class B; def test; 1 + 1; end; end
+ class C; def test; 1 + 1; end; end
+ class D; def test; 1 + 1; end; end
+ class E; def test; 1 + 1; end; end
+ class F; def test; 1 + 1; end; end
+ class G; def test; 1 + 1; end; end
+
+ objs = [A.new, B.new, C.new, D.new, E.new, F.new, G.new].freeze
+
+ def call_test(obj)
+ obj.test
+ end
+
+ ractors = 7.times.map do
+ Ractor.new(objs) do |objs|
+ objs = objs.shuffle
+ 100_000.times do
+ objs.each do |o|
+ call_test(o)
+ end
+ end
+ end
+ end
+ ractors.each(&:join)
+ :ok
+RUBY
+
+# This test checks that we do not trigger a GC when we have malloc with Ractor
+# locks. We cannot trigger a GC with Ractor locks because GC requires VM lock
+# and Ractor barrier. If another Ractor is waiting on this Ractor lock, then it
+# will deadlock because the other Ractor will never join the barrier.
+#
+# Creating Ractor::Port requires locking the Ractor and inserting into an
+# st_table, which can call malloc.
+assert_equal 'ok', <<~'RUBY'
+ r = Ractor.new do
+ loop do
+ Ractor::Port.new
+ end
+ end
+
+ 10.times do
+ 10_000.times do
+ r.send(nil)
+ end
+ sleep(0.01)
+ end
+ :ok
+RUBY
+
+assert_equal 'ok', <<~'RUBY'
+ begin
+ 100.times do |i|
+ Ractor.new(i) do |j|
+ 1000.times do |i|
+ "#{j}-#{i}"
+ end
+ Ractor.receive
+ end
+ pid = fork { }
+ _, status = Process.waitpid2 pid
+ raise unless status.success?
+ end
+
+ :ok
+ rescue NotImplementedError
+ :ok
+ end
+RUBY
+
+assert_equal 'ok', <<~'RUBY'
+ begin
+ 100.times do |i|
+ Ractor.new(i) do |j|
+ 1000.times do |i|
+ "#{j}-#{i}"
+ end
+ end
+ pid = fork do
+ GC.verify_internal_consistency
+ end
+ _, status = Process.waitpid2 pid
+ raise unless status.success?
+ end
+
+ :ok
+ rescue NotImplementedError
+ :ok
+ end
+RUBY
+
+# When creating bmethods in Ractors, they should only be usable from their
+# defining ractor, even if it is GC'd
+assert_equal 'ok', <<~'RUBY'
+
+begin
+ CLASSES = 1000.times.map { Class.new }.freeze
+
+ # This would be better to run in parallel, but there's a bug with lambda
+ # creation and YJIT causing crashes in dev mode
+ ractors = CLASSES.map do |klass|
+ Ractor.new(klass) do |klass|
+ Ractor.receive
+ klass.define_method(:foo) {}
+ end
+ end
+
+ ractors.each do |ractor|
+ ractor << nil
+ ractor.join
+ end
+
+ ractors.clear
+ GC.start
+
+ any = 1000.times.map do
+ Ractor.new do
+ CLASSES.any? do |klass|
+ begin
+ klass.new.foo
+ true
+ rescue RuntimeError
+ false
+ end
+ end
+ end
+ end.map(&:value).none? && :ok
+rescue ThreadError => e
+ # ignore limited memory machine
+ if /can\'t create Thread/ =~ e.message
+ :ok
+ else
+ raise
+ end
+end
+RUBY
+
+# Concurrent super calls with keyword arguments must not race on the
+# callinfo kwarg reference count. [Bug #22075]
+assert_equal 'ok', %q{
+ class Base
+ def foo(a:, b:, c:) = a
+ end
+
+ class Sub < Base
+ def foo(a:, b:, c:) = super(a: a, b: b, c: c)
+ end
+
+ 4.times.map do
+ Ractor.new do
+ obj = Sub.new
+ 100_000.times { obj.foo(a: 1, b: 2, c: 3) }
+ end
+ end.each(&:join)
+
+ :ok
+}
diff --git a/bootstraptest/test_syntax.rb b/bootstraptest/test_syntax.rb
index fbc9c6f62e..29bf93cb8f 100644
--- a/bootstraptest/test_syntax.rb
+++ b/bootstraptest/test_syntax.rb
@@ -571,7 +571,7 @@ assert_equal 'ok', %q{
assert_equal 'ok', %q{
1.times{
- p(1, (next; 2))
+ p(1, (next if true; 2))
}; :ok
}
assert_equal '3', %q{
@@ -585,7 +585,7 @@ assert_equal '3', %q{
i = 0
1 + (while true
break 2 if (i+=1) > 1
- p(1, (next; 2))
+ p(1, (next if true; 2))
end)
}
# redo
@@ -594,7 +594,7 @@ assert_equal 'ok', %q{
1.times{
break if i>1
i+=1
- p(1, (redo; 2))
+ p(1, (redo if true; 2))
}; :ok
}
assert_equal '3', %q{
@@ -608,7 +608,7 @@ assert_equal '3', %q{
i = 0
1 + (while true
break 2 if (i+=1) > 1
- p(1, (redo; 2))
+ p(1, (redo if true; 2))
end)
}
assert_equal '1', %q{
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 5a5e08f095..e9ce905e2c 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -220,7 +220,7 @@ assert_equal 'Sub', %q{
call(Sub.new('o')).class
}
-# String#dup with FL_EXIVAR
+# String#dup with generic ivars
assert_equal '["str", "ivar"]', %q{
def str_dup(str) = str.dup
str = "str"
@@ -468,91 +468,6 @@ assert_normal_exit %q{
end
}
-assert_equal '0', %q{
- # This is a regression test for incomplete invalidation from
- # opt_setinlinecache. This test might be brittle, so
- # feel free to remove it in the future if it's too annoying.
- # This test assumes --yjit-call-threshold=2.
- module M
- Foo = 1
- def foo
- Foo
- end
-
- def pin_self_type_then_foo
- _ = @foo
- foo
- end
-
- def only_ints
- 1 + self
- foo
- end
- end
-
- class Integer
- include M
- end
-
- class Sub
- include M
- end
-
- foo_method = M.instance_method(:foo)
-
- dbg = ->(message) do
- return # comment this out to get printouts
-
- $stderr.puts RubyVM::YJIT.disasm(foo_method)
- $stderr.puts message
- end
-
- 2.times { 42.only_ints }
-
- dbg["There should be two versions of getinlineache"]
-
- module M
- remove_const(:Foo)
- end
-
- dbg["There should be no getinlinecaches"]
-
- 2.times do
- 42.only_ints
- rescue NameError => err
- _ = "caught name error #{err}"
- end
-
- dbg["There should be one version of getinlineache"]
-
- 2.times do
- Sub.new.pin_self_type_then_foo
- rescue NameError
- _ = 'second specialization'
- end
-
- dbg["There should be two versions of getinlineache"]
-
- module M
- Foo = 1
- end
-
- dbg["There should still be two versions of getinlineache"]
-
- 42.only_ints
-
- dbg["There should be no getinlinecaches"]
-
- # Find name of the first VM instruction in M#foo.
- insns = RubyVM::InstructionSequence.of(foo_method).to_a
- if defined?(RubyVM::YJIT.blocks_for) && (insns.last.find { Array === _1 }&.first == :opt_getinlinecache)
- RubyVM::YJIT.blocks_for(RubyVM::InstructionSequence.of(foo_method))
- .filter { _1.iseq_start_index == 0 }.count
- else
- 0 # skip the test
- end
-}
-
# Check that frozen objects are respected
assert_equal 'great', %q{
class Foo
@@ -1415,7 +1330,7 @@ assert_equal '[42, :default]', %q{
]
}
-# Test default value block for Hash with opt_aref_with
+# Test default value block for Hash
assert_equal "false", <<~RUBY, frozen_string_literal: false
def index_with_string(h)
h["foo"]
@@ -2568,6 +2483,32 @@ assert_equal '[0, 2]', %q{
B.new.foo
}
+# invokesuper in a weird block
+assert_equal '["block->A#itself", "block->singleton#itself"]', %q{
+ # This test runs the same block as first as a block and then as a method,
+ # testing the routine that finds the currently running method, which is
+ # relevant for `super`.
+ class BlockIseqDuality
+ prepend(Module.new do
+ def itself
+ nested = -> { "block->" + super() }
+ @singleton_itself.define_singleton_method(:itself, &nested)
+ nested
+ end
+ end)
+
+ attr_reader :singleton_itself
+ def initialize = (@singleton_itself = "singleton#itself")
+
+ def itself = "A#itself"
+ end
+
+ tester = BlockIseqDuality.new
+ super_lambda = tester.itself
+ super_lambda.call # warmup
+ [super_lambda.call, tester.singleton_itself.itself]
+}
+
# invokesuper zsuper in a bmethod
assert_equal 'ok', %q{
class Foo
@@ -2765,6 +2706,22 @@ assert_equal '[1, 2]', %q{
expandarray_redefined_nilclass
}
+assert_equal 'not_array', %q{
+ def expandarray_not_array(obj)
+ a, = obj
+ a
+ end
+
+ obj = Object.new
+ def obj.method_missing(m, *args, &block)
+ return [:not_array] if m == :to_ary
+ super
+ end
+
+ expandarray_not_array(obj)
+ expandarray_not_array(obj)
+}
+
assert_equal '[1, 2, nil]', %q{
def expandarray_rhs_too_small
a, b, c = [1, 2]
@@ -3018,15 +2975,16 @@ assert_equal '[:itself]', %q{
itself
end
- tracing_ractor = Ractor.new do
+ port = Ractor::Port.new
+ tracing_ractor = Ractor.new port do |port|
# 1: start tracing
events = []
tp = TracePoint.new(:c_call) { events << _1.method_id }
tp.enable
- Ractor.yield(nil)
+ port << nil
# 3: run compiled method on tracing ractor
- Ractor.yield(nil)
+ port << nil
traced_method
events
@@ -3034,13 +2992,13 @@ assert_equal '[:itself]', %q{
tp&.disable
end
- tracing_ractor.take
+ port.receive
# 2: compile on non tracing ractor
traced_method
- tracing_ractor.take
- tracing_ractor.take
+ port.receive
+ tracing_ractor.value
}
# Try to hit a lazy branch stub while another ractor enables tracing
@@ -3054,17 +3012,18 @@ assert_equal '42', %q{
end
end
- ractor = Ractor.new do
+ port = Ractor::Port.new
+ ractor = Ractor.new port do |port|
compiled(false)
- Ractor.yield(nil)
+ port << nil
compiled(41)
end
tp = TracePoint.new(:line) { itself }
- ractor.take
+ port.receive
tp.enable
- ractor.take
+ ractor.value
}
# Test equality with changing types
@@ -3140,7 +3099,7 @@ assert_equal '42', %q{
A.foo
A.foo
- Ractor.new { A.foo }.take
+ Ractor.new { A.foo }.value
}
assert_equal '["plain", "special", "sub", "plain"]', %q{
@@ -3667,6 +3626,74 @@ assert_equal 'new', %q{
test
}
+# Bug #21257 (infinite jmp)
+assert_equal 'ok', %q{
+ Good = :ok
+
+ def first
+ second
+ end
+
+ def second
+ ::Good
+ end
+
+ # Make `second` side exit on its first instruction
+ trace = TracePoint.new(:line) { }
+ trace.enable(target: method(:second))
+
+ first
+ # Recompile now that the constant cache is populated, so we get a fallthrough from `first` to `second`
+ # (this is need to reproduce with --yjit-call-threshold=1)
+ RubyVM::YJIT.code_gc if defined?(RubyVM::YJIT)
+ first
+
+ # Trigger a constant cache miss in rb_vm_opt_getconstant_path (in `second`) next time it's called
+ module InvalidateConstantCache
+ Good = nil
+ end
+
+ RubyVM::YJIT.simulate_oom! if defined?(RubyVM::YJIT)
+
+ first
+ first
+}
+
+assert_equal 'ok', %q{
+ # Multiple incoming branches into second
+ Good = :ok
+
+ def incoming_one
+ second
+ end
+
+ def incoming_two
+ second
+ end
+
+ def second
+ ::Good
+ end
+
+ # Make `second` side exit on its first instruction
+ trace = TracePoint.new(:line) { }
+ trace.enable(target: method(:second))
+
+ incoming_one
+ # Recompile now that the constant cache is populated, so we get a fallthrough from `incoming_one` to `second`
+ # (this is need to reproduce with --yjit-call-threshold=1)
+ RubyVM::YJIT.code_gc if defined?(RubyVM::YJIT)
+ incoming_one
+ incoming_two
+
+ # Trigger a constant cache miss in rb_vm_opt_getconstant_path (in `second`) next time it's called
+ module InvalidateConstantCache
+ Good = nil
+ end
+
+ incoming_one
+}
+
assert_equal 'ok', %q{
# Try to compile new method while OOM
def foo
@@ -3791,36 +3818,6 @@ assert_equal '3,12', %q{
pt_inspect(p)
}
-# Regression test for deadlock between branch_stub_hit and ractor_receive_if
-assert_equal '10', %q{
- r = Ractor.new Ractor.current do |main|
- main << 1
- main << 2
- main << 3
- main << 4
- main << 5
- main << 6
- main << 7
- main << 8
- main << 9
- main << 10
- end
-
- a = []
- a << Ractor.receive_if{|msg| msg == 10}
- a << Ractor.receive_if{|msg| msg == 9}
- a << Ractor.receive_if{|msg| msg == 8}
- a << Ractor.receive_if{|msg| msg == 7}
- a << Ractor.receive_if{|msg| msg == 6}
- a << Ractor.receive_if{|msg| msg == 5}
- a << Ractor.receive_if{|msg| msg == 4}
- a << Ractor.receive_if{|msg| msg == 3}
- a << Ractor.receive_if{|msg| msg == 2}
- a << Ractor.receive_if{|msg| msg == 1}
-
- a.length
-}
-
# checktype
assert_equal 'false', %q{
def function()
@@ -4126,6 +4123,26 @@ assert_equal '1', %q{
bar { }
}
+# unshareable bmethod call through Method#to_proc#call
+assert_equal '1000', %q{
+ define_method(:bmethod) do
+ self
+ end
+
+ Ractor.new do
+ errors = 0
+ 1000.times do
+ p = method(:bmethod).to_proc
+ begin
+ p.call
+ rescue RuntimeError
+ errors += 1
+ end
+ end
+ errors
+ end.value
+}
+
# test for return stub lifetime issue
assert_equal '1', %q{
def foo(n)
@@ -4898,6 +4915,16 @@ assert_equal '[:ok, :ok, :ok, :ok, :ok]', %q{
tests
}
+# regression test for splat with &proc{} when the target has rest (Bug #21266)
+assert_equal '[]', %q{
+ def foo(args) = bar(*args, &proc { _1 })
+ def bar(_, _, _, _, *rest) = yield rest
+
+ GC.stress = true
+ foo([1,2,3,4])
+ foo([1,2,3,4])
+}
+
# regression test for invalidating an empty block
assert_equal '0', %q{
def foo = (* = 1).pred
@@ -5387,3 +5414,144 @@ assert_equal 'nil', %{
test_local_fill_in_forwardable.inspect
}
+
+# Test defined?(yield) and block_given? in non-method context.
+# It's good that the body of this runs at true top level and isn't wrapped in a block.
+assert_equal 'false', %{
+ RESULT = []
+ RESULT << defined?(yield)
+ RESULT << block_given?
+
+ 1.times do
+ RESULT << defined?(yield)
+ RESULT << block_given?
+ end
+
+ module ModuleContext
+ 1.times do
+ RESULT << defined?(yield)
+ RESULT << block_given?
+ end
+ end
+
+ class << self
+ RESULT << defined?(yield)
+ RESULT << block_given?
+ end
+
+ RESULT.any?
+}
+
+# throw and String#dup with GC stress
+assert_equal 'foo', %{
+ GC.stress = true
+
+ def foo
+ 1.times { return "foo".dup }
+ end
+
+ 10.times.map { foo.dup }.last
+}
+
+# regression test for [Bug #21772]
+# local variable type tracking desync
+assert_normal_exit %q{
+ def some_method = 0
+
+ def test_body(key)
+ some_method
+ key = key.to_s # setting of local relevant
+
+ key == "symbol"
+ end
+
+ def jit_caller = test_body("session_id")
+
+ jit_caller # first iteration, non-escaped environment
+ alias some_method binding # induce environment escape
+ test_body(:symbol)
+}
+
+# regression test for missing check in identity method inlining
+assert_normal_exit %q{
+ # Use dead code (if false) to create a local
+ # without initialization instructions.
+ def foo(a)
+ if false
+ x = nil
+ end
+ x
+ end
+ def test = foo(1)
+ test
+ test
+}
+
+# regression test for tracing invalidation with on-stack compiled methods
+# Exercises the on_stack_iseqs path in rb_yjit_tracing_invalidate_all
+# where delayed deallocation must not create aliasing &mut references
+# to IseqPayload (use-after-free of version_map backing storage).
+assert_normal_exit %q{
+ def deep = 42
+ def mid = deep
+ def outer = mid
+
+ # Compile all three methods with YJIT
+ 10.times { outer }
+
+ # Enable tracing from within a call chain so that outer/mid/deep
+ # are on the stack when rb_yjit_tracing_invalidate_all runs.
+ # This triggers the on_stack_iseqs (delayed deallocation) path.
+ def deep
+ TracePoint.new(:line) {}.enable
+ 42
+ end
+
+ outer
+
+ # After invalidation, verify YJIT can recompile and run correctly
+ def deep = 42
+ 10.times { outer }
+}
+
+# regression test for tracing invalidation with on-stack fibers
+# Suspended fibers have iseqs on their stack that must survive invalidation.
+assert_equal '42', %q{
+ def compiled_method
+ Fiber.yield
+ 42
+ end
+
+ # Compile the method
+ 10.times { compiled_method rescue nil }
+
+ fiber = Fiber.new { compiled_method }
+ fiber.resume # suspends inside compiled_method — it's now on the fiber's stack
+
+ # Enable tracing while compiled_method is on the fiber's stack.
+ # This triggers rb_yjit_tracing_invalidate_all with on-stack iseqs.
+ TracePoint.new(:call) {}.enable
+
+ # Resume the fiber — compiled_method's iseq must still be valid
+ fiber.resume.to_s
+}
+
+# regression test for register mapping of methods with over 256 locals
+# [Bug #22074]
+assert_equal "ok", %q{
+ source = +"def many_locals\n"
+ source << " total = 0\n"
+
+ 128.times do |i|
+ source << " y#{i} = 1\n"
+ source << " x#{i} = Object.new\n"
+ end
+
+ source << " total += 1\n"
+ source << " raise total.inspect unless total == 1\n"
+ source << "end\n"
+
+ eval(source)
+ many_locals
+ "ok"
+}
diff --git a/bootstraptest/test_yjit_rust_port.rb b/bootstraptest/test_yjit_rust_port.rb
index e399e0e49e..2dbcebc03a 100644
--- a/bootstraptest/test_yjit_rust_port.rb
+++ b/bootstraptest/test_yjit_rust_port.rb
@@ -374,7 +374,7 @@ assert_equal 'ok', %q{
r = Ractor.new do
'ok'
end
- r.take
+ r.value
}
# Passed arguments to Ractor.new will be a block parameter
@@ -384,7 +384,7 @@ assert_equal 'ok', %q{
r = Ractor.new 'ok' do |msg|
msg
end
- r.take
+ r.value
}
# Pass multiple arguments to Ractor.new
@@ -393,7 +393,7 @@ assert_equal 'ok', %q{
r = Ractor.new 'ping', 'pong' do |msg, msg2|
[msg, msg2]
end
- 'ok' if r.take == ['ping', 'pong']
+ 'ok' if r.value == ['ping', 'pong']
}
# Ractor#send passes an object with copy to a Ractor
@@ -403,7 +403,7 @@ assert_equal 'ok', %q{
msg = Ractor.receive
end
r.send 'ok'
- r.take
+ r.value
}
assert_equal '[1, 2, 3]', %q{
diff --git a/box.c b/box.c
new file mode 100644
index 0000000000..0ca7838be9
--- /dev/null
+++ b/box.c
@@ -0,0 +1,1299 @@
+/* indent-tabs-mode: nil */
+
+#include "eval_intern.h"
+#include "internal.h"
+#include "internal/box.h"
+#include "internal/class.h"
+#include "internal/eval.h"
+#include "internal/error.h"
+#include "internal/file.h"
+#include "internal/gc.h"
+#include "internal/hash.h"
+#include "internal/io.h"
+#include "internal/load.h"
+#include "internal/st.h"
+#include "internal/variable.h"
+#include "iseq.h"
+#include "ruby/internal/globals.h"
+#include "ruby/util.h"
+#include "vm_core.h"
+#include "darray.h"
+#include "zjit.h"
+
+#include "builtin.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_SENDFILE_H
+# include <sys/sendfile.h>
+#endif
+#ifdef HAVE_COPYFILE_H
+#include <copyfile.h>
+#endif
+
+VALUE rb_cBox = 0;
+VALUE rb_cBoxEntry = 0;
+VALUE rb_mBoxLoader = 0;
+
+static rb_box_t master_box[1]; /* Initialize in initialize_master_box() */
+static rb_box_t *root_box;
+static rb_box_t *main_box;
+
+static rb_box_gem_flags_t box_gem_flags[1];
+
+static char *tmp_dir;
+static bool tmp_dir_has_dirsep;
+
+#define BOX_TMP_PREFIX "_ruby_box_"
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+#if defined(_WIN32)
+# define DIRSEP "\\"
+#else
+# define DIRSEP "/"
+#endif
+
+bool ruby_box_enabled = false; // extern
+bool ruby_box_init_done = false; // extern
+bool ruby_box_crashed = false; // extern, changed only in vm.c
+
+VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
+static VALUE rb_box_inspect(VALUE obj);
+static void cleanup_all_local_extensions(VALUE libmap);
+
+void
+rb_box_set_gem_flags(rb_box_gem_flags_t *flags)
+{
+
+ box_gem_flags->gem = flags->gem;
+ box_gem_flags->error_highlight = flags->error_highlight;
+ box_gem_flags->did_you_mean = flags->did_you_mean;
+ box_gem_flags->syntax_suggest = flags->syntax_suggest;
+}
+
+void
+rb_box_init_done(void)
+{
+ ruby_box_init_done = true;
+}
+
+const rb_box_t *
+rb_master_box(void)
+{
+ return master_box;
+}
+
+const rb_box_t *
+rb_root_box(void)
+{
+ if (!root_box) // The root box isn't initialized yet - The Ruby runtime is in setup.
+ return master_box;
+ return root_box;
+}
+
+const rb_box_t *
+rb_main_box(void)
+{
+ return main_box;
+}
+
+const rb_box_t *
+rb_current_box(void)
+{
+ /*
+ * If RUBY_BOX is not set, the master box is the only available one.
+ *
+ * While the root/main boxes are not initialized, the master box is
+ * the only valid box.
+ * This early return is to avoid accessing EC before its setup.
+ */
+ if (!root_box)
+ return master_box;
+ if (!main_box)
+ return root_box;
+
+ return rb_vm_current_box(GET_EC());
+}
+
+const rb_box_t *
+rb_loading_box(void)
+{
+ if (!root_box)
+ return master_box;
+ if (!main_box)
+ return root_box;
+
+ return rb_vm_loading_box(GET_EC());
+}
+
+const rb_box_t *
+rb_current_box_in_crash_report(void)
+{
+ if (ruby_box_crashed)
+ return NULL;
+ return rb_current_box();
+}
+
+static long box_id_counter = 0;
+
+static long
+box_generate_id(void)
+{
+ long id;
+ RB_VM_LOCKING() {
+ id = ++box_id_counter;
+ }
+ return id;
+}
+
+static VALUE
+box_main_to_s(VALUE obj)
+{
+ return rb_str_new2("main");
+}
+
+static void
+box_entry_initialize(rb_box_t *box)
+{
+ const rb_box_t *master = rb_master_box();
+
+ // These will be updated immediately
+ box->box_object = 0;
+ box->box_id = 0;
+
+ box->top_self = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(box->top_self, "to_s", box_main_to_s, 0);
+ rb_define_alias(rb_singleton_class(box->top_self), "inspect", "to_s");
+ box->load_path = rb_ary_dup(master->load_path);
+ box->expanded_load_path = rb_ary_dup(master->expanded_load_path);
+ box->load_path_snapshot = rb_ary_new();
+ box->load_path_check_cache = 0;
+ box->loaded_features = rb_ary_dup(master->loaded_features);
+ box->loaded_features_snapshot = rb_ary_new();
+ box->loaded_features_index = st_init_numtable();
+ box->loaded_features_realpaths = rb_hash_dup(master->loaded_features_realpaths);
+ box->loaded_features_realpath_map = rb_hash_dup(master->loaded_features_realpath_map);
+ box->loading_table = st_init_strtable();
+ box->ruby_dln_libmap = rb_hash_new_with_size(0);
+ box->gvar_tbl = rb_hash_new_with_size(0);
+ box->classext_cow_classes = st_init_numtable();
+
+ box->is_user = true;
+ box->is_optional = true;
+}
+
+void
+rb_box_gc_update_references(void *ptr)
+{
+ rb_box_t *box = (rb_box_t *)ptr;
+ if (!box) return;
+
+ if (box->box_object)
+ box->box_object = rb_gc_location(box->box_object);
+ if (box->top_self)
+ box->top_self = rb_gc_location(box->top_self);
+ box->load_path = rb_gc_location(box->load_path);
+ box->expanded_load_path = rb_gc_location(box->expanded_load_path);
+ box->load_path_snapshot = rb_gc_location(box->load_path_snapshot);
+ if (box->load_path_check_cache) {
+ box->load_path_check_cache = rb_gc_location(box->load_path_check_cache);
+ }
+ box->loaded_features = rb_gc_location(box->loaded_features);
+ box->loaded_features_snapshot = rb_gc_location(box->loaded_features_snapshot);
+ box->loaded_features_realpaths = rb_gc_location(box->loaded_features_realpaths);
+ box->loaded_features_realpath_map = rb_gc_location(box->loaded_features_realpath_map);
+ box->ruby_dln_libmap = rb_gc_location(box->ruby_dln_libmap);
+ box->gvar_tbl = rb_gc_location(box->gvar_tbl);
+}
+
+void
+rb_box_entry_mark(void *ptr)
+{
+ const rb_box_t *box = (rb_box_t *)ptr;
+ if (!box) return;
+
+ rb_gc_mark(box->box_object);
+ rb_gc_mark(box->top_self);
+ rb_gc_mark(box->load_path);
+ rb_gc_mark(box->expanded_load_path);
+ rb_gc_mark(box->load_path_snapshot);
+ rb_gc_mark(box->load_path_check_cache);
+ rb_gc_mark(box->loaded_features);
+ rb_gc_mark(box->loaded_features_snapshot);
+ rb_gc_mark(box->loaded_features_realpaths);
+ rb_gc_mark(box->loaded_features_realpath_map);
+ if (box->loading_table) {
+ rb_mark_tbl(box->loading_table);
+ }
+ rb_gc_mark(box->ruby_dln_libmap);
+ rb_gc_mark(box->gvar_tbl);
+ if (box->classext_cow_classes) {
+ rb_mark_set(box->classext_cow_classes);
+ }
+}
+
+static int
+free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
+{
+ xfree((char *)key);
+ return ST_DELETE;
+}
+
+static int
+free_loaded_feature_index_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ if (!FIXNUM_P(value)) {
+ rb_darray_free_sized((void *)value, long);
+ }
+ return ST_CONTINUE;
+}
+
+static void
+free_box_st_tables(void *ptr)
+{
+ rb_box_t *box = (rb_box_t *)ptr;
+ if (box->loading_table) {
+ st_foreach(box->loading_table, free_loading_table_entry, 0);
+ st_free_table(box->loading_table);
+ box->loading_table = 0;
+ }
+
+ if (box->loaded_features_index) {
+ st_foreach(box->loaded_features_index, free_loaded_feature_index_i, 0);
+ st_free_table(box->loaded_features_index);
+ }
+}
+
+static int
+free_classext_for_box(st_data_t key, st_data_t _value, st_data_t box_arg)
+{
+ rb_classext_t *ext;
+ VALUE obj = (VALUE)key;
+ const rb_box_t *box = (const rb_box_t *)box_arg;
+
+ if (RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE)) {
+ ext = rb_class_unlink_classext(obj, box);
+ rb_class_classext_free(obj, ext, false);
+ }
+ else if (RB_TYPE_P(obj, T_ICLASS)) {
+ ext = rb_class_unlink_classext(obj, box);
+ rb_iclass_classext_free(obj, ext, false);
+ }
+ else {
+ rb_bug("Invalid type of object in classext_cow_classes: %s", rb_type_str(BUILTIN_TYPE(obj)));
+ }
+ return ST_CONTINUE;
+}
+
+static void
+box_entry_free(void *ptr)
+{
+ const rb_box_t *box = (const rb_box_t *)ptr;
+
+ if (box->classext_cow_classes) {
+ st_foreach(box->classext_cow_classes, free_classext_for_box, (st_data_t)box);
+ }
+
+ cleanup_all_local_extensions(box->ruby_dln_libmap);
+
+ free_box_st_tables(ptr);
+ SIZED_FREE(box);
+}
+
+static size_t
+box_entry_memsize(const void *ptr)
+{
+ size_t size = sizeof(rb_box_t);
+ const rb_box_t *box = (const rb_box_t *)ptr;
+ if (box->loaded_features_index) {
+ size += rb_st_memsize(box->loaded_features_index);
+ }
+ if (box->loading_table) {
+ size += rb_st_memsize(box->loading_table);
+ }
+ return size;
+}
+
+static const rb_data_type_t rb_box_data_type = {
+ "Ruby::Box::Entry",
+ {
+ rb_box_entry_mark,
+ box_entry_free,
+ box_entry_memsize,
+ rb_box_gc_update_references,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
+};
+
+static const rb_data_type_t rb_master_box_data_type = {
+ "Ruby::Box::Master",
+ {
+ rb_box_entry_mark,
+ free_box_st_tables,
+ box_entry_memsize,
+ rb_box_gc_update_references,
+ },
+ &rb_box_data_type, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
+};
+
+VALUE
+rb_box_entry_alloc(VALUE klass)
+{
+ rb_box_t *entry;
+ VALUE obj = TypedData_Make_Struct(klass, rb_box_t, &rb_box_data_type, entry);
+ box_entry_initialize(entry);
+ return obj;
+}
+
+static rb_box_t *
+get_box_struct_internal(VALUE entry)
+{
+ rb_box_t *sval;
+ TypedData_Get_Struct(entry, rb_box_t, &rb_box_data_type, sval);
+ return sval;
+}
+
+rb_box_t *
+rb_get_box_t(VALUE box)
+{
+ VALUE entry;
+ ID id_box_entry;
+
+ VM_ASSERT(box);
+
+ if (NIL_P(box))
+ return (rb_box_t *)rb_root_box();
+
+ VM_ASSERT(BOX_OBJ_P(box));
+
+ CONST_ID(id_box_entry, "__box_entry__");
+ entry = rb_attr_get(box, id_box_entry);
+ return get_box_struct_internal(entry);
+}
+
+VALUE
+rb_get_box_object(rb_box_t *box)
+{
+ VM_ASSERT(box && box->box_object);
+ return box->box_object;
+}
+
+/*
+ * call-seq:
+ * Ruby::Box.new -> new_box
+ *
+ * Returns a new Ruby::Box object.
+ */
+static VALUE
+box_initialize(VALUE box_value)
+{
+ rb_box_t *box;
+ rb_classext_t *object_classext;
+ VALUE entry;
+ ID id_box_entry;
+ CONST_ID(id_box_entry, "__box_entry__");
+
+ if (!rb_box_available()) {
+ rb_raise(rb_eRuntimeError, "Ruby Box is disabled. Set RUBY_BOX=1 environment variable to use Ruby::Box.");
+ }
+
+ entry = rb_class_new_instance_pass_kw(0, NULL, rb_cBoxEntry);
+ box = get_box_struct_internal(entry);
+
+ box->box_object = box_value;
+ box->box_id = box_generate_id();
+ rb_define_singleton_method(box->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
+
+ // Set the Ruby::Box object unique/consistent from any boxes to have just single
+ // constant table from any view of every (including main) box.
+ // If a code in the box adds a constant, the constant will be visible even from root/main.
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE(box_value, true);
+
+ // Get a clean constant table of Object even by writable one
+ // because ns was just created, so it has not touched any constants yet.
+ object_classext = RCLASS_EXT_WRITABLE_IN_BOX(rb_cObject, box);
+ RCLASS_SET_CONST_TBL(box_value, RCLASSEXT_CONST_TBL(object_classext), true);
+
+ rb_ivar_set(box_value, id_box_entry, entry);
+
+ if (ruby_box_init_done) {
+ if (box_gem_flags->gem) {
+ rb_vm_call_cfunc_in_box(Qnil, rb_define_gem_modules, (VALUE)box_gem_flags, Qnil,
+ rb_str_new_cstr("before_prelude.user.dummy"), (const rb_box_t *)box);
+ rb_load_gem_prelude((VALUE)box);
+ }
+ }
+
+ // Invalidate ZJIT code that assumes only the root box is active
+ rb_zjit_invalidate_root_box();
+
+ return box_value;
+}
+
+/*
+ * call-seq:
+ * Ruby::Box.enabled? -> true or false
+ *
+ * Returns +true+ if Ruby::Box is enabled.
+ */
+static VALUE
+rb_box_s_getenabled(VALUE recv)
+{
+ return RBOOL(rb_box_available());
+}
+
+/*
+ * call-seq:
+ * Ruby::Box.current -> box, nil or false
+ *
+ * Returns the current box.
+ * Returns +nil+ if Ruby Box is not enabled.
+ */
+static VALUE
+rb_box_s_current(VALUE recv)
+{
+ const rb_box_t *box;
+
+ if (!rb_box_available())
+ return Qnil;
+
+ box = rb_vm_current_box(GET_EC());
+ VM_ASSERT(box && box->box_object);
+ return box->box_object;
+}
+
+/*
+ * call-seq:
+ * load_path -> array
+ *
+ * Returns box local load path.
+ */
+static VALUE
+rb_box_load_path(VALUE box)
+{
+ VM_ASSERT(BOX_OBJ_P(box));
+ return rb_get_box_t(box)->load_path;
+}
+
+#ifdef _WIN32
+UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
+#endif
+
+/* Copied from mjit.c Ruby 3.0.3 */
+static char *
+system_default_tmpdir(void)
+{
+ // c.f. ext/etc/etc.c:etc_systmpdir()
+#ifdef _WIN32
+ WCHAR tmppath[_MAX_PATH];
+ UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
+ if (len) {
+ int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
+ char *tmpdir = xmalloc(blen + 1);
+ WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
+ tmpdir[blen] = '\0';
+ return tmpdir;
+ }
+#elif 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 _WIN32
+# 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;
+#endif
+ 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
+}
+
+/* end of copy */
+
+static int
+sprint_ext_filename(char *str, size_t size, long box_id, const char *prefix, const char *basename)
+{
+ if (tmp_dir_has_dirsep) {
+ return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), box_id, basename);
+ }
+ return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), box_id, basename);
+}
+
+enum copy_error_type {
+ COPY_ERROR_NONE,
+ COPY_ERROR_SRC_OPEN,
+ COPY_ERROR_DST_OPEN,
+ COPY_ERROR_SRC_READ,
+ COPY_ERROR_DST_WRITE,
+ COPY_ERROR_SRC_STAT,
+ COPY_ERROR_DST_CHMOD,
+ COPY_ERROR_SYSERR
+};
+
+static const char *
+copy_ext_file_error(char *message, size_t size, int copy_retvalue)
+{
+#ifdef _WIN32
+ int error = GetLastError();
+ char *p = message;
+ size_t len = snprintf(message, size, "%d: ", error);
+
+#define format_message(sublang) FormatMessage(\
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
+ NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
+ message + len, size - len, NULL)
+ if (format_message(SUBLANG_ENGLISH_US) == 0)
+ format_message(SUBLANG_DEFAULT);
+ for (p = message + len; *p; p++) {
+ if (*p == '\n' || *p == '\r')
+ *p = ' ';
+ }
+#else
+ switch (copy_retvalue) {
+ case COPY_ERROR_SRC_OPEN:
+ strlcpy(message, "can't open the extension path", size);
+ break;
+ case COPY_ERROR_DST_OPEN:
+ strlcpy(message, "can't open the file to write", size);
+ break;
+ case COPY_ERROR_SRC_READ:
+ strlcpy(message, "failed to read the extension path", size);
+ break;
+ case COPY_ERROR_DST_WRITE:
+ strlcpy(message, "failed to write the extension path", size);
+ break;
+ case COPY_ERROR_SRC_STAT:
+ strlcpy(message, "failed to stat the extension path to copy permissions", size);
+ break;
+ case COPY_ERROR_DST_CHMOD:
+ strlcpy(message, "failed to set permissions to the copied extension path", size);
+ break;
+ case COPY_ERROR_SYSERR:
+ strlcpy(message, strerror(errno), size);
+ break;
+ case COPY_ERROR_NONE: /* shouldn't be called */
+ default:
+ rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
+ }
+#endif
+ return message;
+}
+
+#ifndef _WIN32
+static enum copy_error_type
+copy_stream(int src_fd, int dst_fd)
+{
+ char buffer[1024];
+ ssize_t rsize;
+
+ while ((rsize = read(src_fd, buffer, sizeof(buffer))) != 0) {
+ if (rsize < 0) return COPY_ERROR_SRC_READ;
+ for (size_t written = 0; written < (size_t)rsize;) {
+ ssize_t wsize = write(dst_fd, buffer+written, rsize-written);
+ if (wsize < 0) return COPY_ERROR_DST_WRITE;
+ written += (size_t)wsize;
+ }
+ }
+ return COPY_ERROR_NONE;
+}
+#endif
+
+static enum copy_error_type
+copy_ext_file(const char *src_path, const char *dst_path)
+{
+#if defined(_WIN32)
+ WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
+ WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
+ if (!w_src || !w_dst) {
+ free(w_src);
+ free(w_dst);
+ rb_memerror();
+ }
+
+ enum copy_error_type rvalue = CopyFileW(w_src, w_dst, TRUE) ?
+ COPY_ERROR_NONE : COPY_ERROR_SYSERR;
+ free(w_src);
+ free(w_dst);
+ return rvalue;
+#else
+# ifdef O_BINARY
+ const int bin = O_BINARY;
+# else
+ const int bin = 0;
+# endif
+# ifdef O_CLOEXEC
+ const int cloexec = O_CLOEXEC;
+# else
+ const int cloexec = 0;
+# endif
+ const int src_fd = open(src_path, O_RDONLY|cloexec|bin);
+ if (src_fd < 0) return COPY_ERROR_SRC_OPEN;
+ if (!cloexec) rb_maygvl_fd_fix_cloexec(src_fd);
+
+ struct stat src_st;
+ if (fstat(src_fd, &src_st)) {
+ close(src_fd);
+ return COPY_ERROR_SRC_STAT;
+ }
+
+ const int dst_fd = open(dst_path, O_WRONLY|O_CREAT|O_EXCL|cloexec|bin, S_IRWXU);
+ if (dst_fd < 0) {
+ close(src_fd);
+ return COPY_ERROR_DST_OPEN;
+ }
+ if (!cloexec) rb_maygvl_fd_fix_cloexec(dst_fd);
+
+ enum copy_error_type ret = COPY_ERROR_NONE;
+
+ if (fchmod(dst_fd, src_st.st_mode & 0777)) {
+ ret = COPY_ERROR_DST_CHMOD;
+ goto done;
+ }
+
+ const size_t count_max = (SIZE_MAX >> 1) + 1;
+ (void)count_max;
+
+# ifdef HAVE_COPY_FILE_RANGE
+ for (;;) {
+ ssize_t written = copy_file_range(src_fd, NULL, dst_fd, NULL, count_max, 0);
+ if (written == 0) goto done;
+ if (written < 0) break;
+ }
+# endif
+# ifdef HAVE_FCOPYFILE
+ if (fcopyfile(src_fd, dst_fd, NULL, COPYFILE_DATA) == 0) {
+ goto done;
+ }
+# endif
+# ifdef USE_SENDFILE
+ for (;;) {
+ ssize_t written = sendfile(src_fd, dst_fd, NULL count_max);
+ if (written == 0) goto done;
+ if (written < 0) break;
+ }
+# endif
+ ret = copy_stream(src_fd, dst_fd);
+
+ done:
+ close(src_fd);
+ if (dst_fd >= 0) close(dst_fd);
+ if (ret != COPY_ERROR_NONE) unlink(dst_path);
+ return ret;
+#endif
+}
+
+#if defined __CYGWIN__ || defined DOSISH
+#define isdirsep(x) ((x) == '/' || (x) == '\\')
+#else
+#define isdirsep(x) ((x) == '/')
+#endif
+
+#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
+#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
+
+static void
+fname_without_suffix(const char *fname, char *rvalue, size_t rsize)
+{
+ size_t len = strlen(fname);
+ const char *pos;
+ for (pos = fname + len; pos > fname; pos--) {
+ if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
+ len = pos - fname;
+ break;
+ }
+ if (fname + len - pos > DLEXT_MAXLEN) break;
+ }
+ if (len > rsize - 1) len = rsize - 1;
+ memcpy(rvalue, fname, len);
+ rvalue[len] = '\0';
+}
+
+static void
+escaped_basename(const char *path, const char *fname, char *rvalue, size_t rsize)
+{
+ char *pos;
+ const char *leaf = path, *found;
+ // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
+ while ((found = strstr(leaf + 1, fname)) != NULL) {
+ leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
+ }
+ strlcpy(rvalue, leaf, rsize);
+ for (pos = rvalue; *pos; pos++) {
+ if (isdirsep(*pos)) {
+ *pos = '+';
+ }
+ }
+}
+
+static void
+box_ext_cleanup_mark(void *p)
+{
+ rb_gc_mark((VALUE)p);
+}
+
+static void
+box_ext_cleanup_free(void *p)
+{
+ VALUE path = (VALUE)p;
+ unlink(RSTRING_PTR(path));
+}
+
+static const rb_data_type_t box_ext_cleanup_type = {
+ "box_ext_cleanup",
+ {box_ext_cleanup_mark, box_ext_cleanup_free},
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+void
+rb_box_cleanup_local_extension(VALUE cleanup)
+{
+ void *p = DATA_PTR(cleanup);
+ DATA_PTR(cleanup) = NULL;
+#ifndef _WIN32
+ if (p) box_ext_cleanup_free(p);
+#endif
+ (void)p;
+}
+
+static int
+cleanup_local_extension_i(VALUE key, VALUE value, VALUE arg)
+{
+#if defined(_WIN32)
+ HMODULE h = (HMODULE)NUM2PTR(value);
+ WCHAR module_path[MAXPATHLEN];
+ DWORD len = GetModuleFileNameW(h, module_path, numberof(module_path));
+
+ FreeLibrary(h);
+ if (len > 0 && len < numberof(module_path)) DeleteFileW(module_path);
+#endif
+ return ST_DELETE;
+}
+
+static void
+cleanup_all_local_extensions(VALUE libmap)
+{
+ rb_hash_foreach(libmap, cleanup_local_extension_i, 0);
+}
+
+VALUE
+rb_box_local_extension(VALUE box_value, VALUE fname, VALUE path, VALUE *cleanup)
+{
+ char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
+ int wrote;
+ const char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
+ rb_box_t *box = rb_get_box_t(box_value);
+
+ fname_without_suffix(fname_ptr, fname2, sizeof(fname2));
+ escaped_basename(src_path, fname2, basename, sizeof(basename));
+
+ wrote = sprint_ext_filename(ext_path, sizeof(ext_path), box->box_id, BOX_TMP_PREFIX, basename);
+ if (wrote >= (int)sizeof(ext_path)) {
+ rb_bug("Extension file path in the box was too long");
+ }
+ VALUE new_path = rb_str_new_cstr(ext_path);
+ *cleanup = TypedData_Wrap_Struct(0, &box_ext_cleanup_type, NULL);
+ enum copy_error_type copy_error = copy_ext_file(src_path, ext_path);
+ if (copy_error) {
+ char message[1024];
+ copy_ext_file_error(message, sizeof(message), copy_error);
+ rb_raise(rb_eLoadError, "can't prepare the extension file for Ruby Box (%s from %"PRIsVALUE"): %s", ext_path, path, message);
+ }
+ DATA_PTR(*cleanup) = (void *)new_path;
+ return new_path;
+}
+
+static VALUE
+rb_box_load(int argc, VALUE *argv, VALUE box)
+{
+ VALUE fname, wrap;
+ rb_scan_args(argc, argv, "11", &fname, &wrap);
+
+ rb_vm_frame_flag_set_box_require(GET_EC());
+
+ return rb_load_entrypoint(fname, wrap);
+}
+
+static VALUE
+rb_box_require(VALUE box, VALUE fname)
+{
+ rb_vm_frame_flag_set_box_require(GET_EC());
+
+ return rb_require_string(fname);
+}
+
+static VALUE
+rb_box_require_relative(VALUE box, VALUE fname)
+{
+ rb_vm_frame_flag_set_box_require(GET_EC());
+
+ return rb_require_relative_entrypoint(fname);
+}
+
+static void
+initialize_master_box(void)
+{
+ rb_vm_t *vm = GET_VM();
+ rb_box_t *master = (rb_box_t *)rb_master_box();
+
+ master->load_path = rb_ary_new();
+ master->expanded_load_path = rb_ary_hidden_new(0);
+ master->load_path_snapshot = rb_ary_hidden_new(0);
+ master->load_path_check_cache = 0;
+ rb_define_singleton_method(master->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
+
+ master->loaded_features = rb_ary_new();
+ master->loaded_features_snapshot = rb_ary_hidden_new(0);
+ master->loaded_features_index = st_init_numtable();
+ master->loaded_features_realpaths = rb_hash_new();
+ rb_obj_hide(master->loaded_features_realpaths);
+ master->loaded_features_realpath_map = rb_hash_new();
+ rb_obj_hide(master->loaded_features_realpath_map);
+
+ master->ruby_dln_libmap = rb_hash_new_with_size(0);
+ master->gvar_tbl = rb_hash_new_with_size(0);
+ master->classext_cow_classes = NULL; // classext CoW never happen on the master box
+
+ vm->master_box = master;
+
+ if (rb_box_available()) {
+ VALUE master_box, entry;
+ ID id_box_entry;
+ CONST_ID(id_box_entry, "__box_entry__");
+
+ master_box = rb_obj_alloc(rb_cBox);
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE(master_box, true);
+ RCLASS_SET_CONST_TBL(master_box, RCLASSEXT_CONST_TBL(RCLASS_EXT_PRIME(rb_cObject)), true);
+
+ master->box_id = box_generate_id();
+ master->box_object = master_box;
+
+ entry = TypedData_Wrap_Struct(rb_cBoxEntry, &rb_master_box_data_type, master);
+ rb_ivar_set(master_box, id_box_entry, entry);
+
+ rb_gc_register_mark_object(master_box);
+ rb_gc_register_mark_object(entry);
+ }
+ else {
+ master->box_id = 1;
+ master->box_object = Qnil;
+ }
+}
+
+static VALUE
+rb_box_eval(VALUE box_value, VALUE str)
+{
+ const rb_iseq_t *iseq;
+ const rb_box_t *box;
+
+ StringValue(str);
+
+ iseq = rb_iseq_compile_iseq(str, rb_str_new_cstr("eval"));
+ VM_ASSERT(iseq);
+
+ box = (const rb_box_t *)rb_get_box_t(box_value);
+
+ return rb_iseq_eval(iseq, box);
+}
+
+static int box_experimental_warned = 0;
+
+RUBY_EXTERN const char ruby_api_version_name[];
+
+static VALUE
+box_value_initialize(bool root, bool user, bool optional)
+{
+ rb_box_t *box;
+ VALUE box_value = rb_class_new_instance(0, NULL, rb_cBox);
+
+ VM_ASSERT(BOX_OBJ_P(box_value));
+
+ box = rb_get_box_t(box_value);
+ box->box_object = box_value;
+ box->is_root = root;
+ box->is_user = user;
+ box->is_optional = optional;
+ return box_value;
+}
+
+void
+rb_initialize_mandatory_boxes(void)
+{
+ VALUE root_box_value, main_box_value;
+ rb_vm_t *vm = GET_VM();
+
+ VM_ASSERT(rb_box_available());
+
+ if (!box_experimental_warned) {
+ rb_category_warn(RB_WARN_CATEGORY_EXPERIMENTAL,
+ "Ruby::Box is experimental, and the behavior may change in the future!\n"
+ "See https://docs.ruby-lang.org/en/%s/Ruby/Box.html for known issues, etc.",
+ ruby_api_version_name);
+ box_experimental_warned = 1;
+ }
+
+ root_box_value = box_value_initialize(true, false, false);
+ main_box_value = box_value_initialize(false, true, false);
+
+ rb_const_set(rb_cBox, rb_intern("ROOT"), root_box_value);
+ rb_const_set(rb_cBox, rb_intern("MAIN"), main_box_value);
+
+ vm->root_box = root_box = rb_get_box_t(root_box_value);
+ vm->main_box = main_box = rb_get_box_t(main_box_value);
+
+ // create the writable classext of ::Object explicitly to finalize the set of visible top-level constants
+ RCLASS_EXT_WRITABLE_IN_BOX(rb_cObject, root_box);
+ RCLASS_EXT_WRITABLE_IN_BOX(rb_cObject, main_box);
+}
+
+static VALUE
+rb_box_inspect(VALUE obj)
+{
+ rb_box_t *box;
+ VALUE r;
+ if (obj == Qfalse) {
+ r = rb_str_new_cstr("#<Ruby::Box:master>");
+ return r;
+ }
+ box = rb_get_box_t(obj);
+ r = rb_str_new_cstr("#<Ruby::Box:");
+ rb_str_concat(r, rb_funcall(LONG2NUM(box->box_id), rb_intern("to_s"), 0));
+ if (BOX_MASTER_P(box)) {
+ rb_str_cat_cstr(r, ",master");
+ }
+ if (BOX_ROOT_P(box)) {
+ rb_str_cat_cstr(r, ",root");
+ }
+ if (BOX_USER_P(box)) {
+ rb_str_cat_cstr(r, ",user");
+ }
+ if (BOX_MAIN_P(box)) {
+ rb_str_cat_cstr(r, ",main");
+ }
+ else if (BOX_OPTIONAL_P(box)) {
+ rb_str_cat_cstr(r, ",optional");
+ }
+ rb_str_cat_cstr(r, ">");
+ return r;
+}
+
+static VALUE
+rb_box_loading_func(int argc, VALUE *argv, VALUE _self)
+{
+ rb_vm_frame_flag_set_box_require(GET_EC());
+ return rb_call_super(argc, argv);
+}
+
+static void
+box_define_loader_method(const char *name)
+{
+ rb_define_private_method(rb_mBoxLoader, name, rb_box_loading_func, -1);
+ rb_define_singleton_method(rb_mBoxLoader, name, rb_box_loading_func, -1);
+}
+
+void
+Init_master_box(void)
+{
+ master_box->loading_table = st_init_strtable();
+}
+
+void
+Init_enable_box(void)
+{
+ const char *env = getenv("RUBY_BOX");
+ if (env && strlen(env) == 1 && env[0] == '1') {
+ ruby_box_enabled = true;
+ }
+ else {
+ ruby_box_init_done = true;
+ }
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_s_master(VALUE recv)
+{
+ return master_box->box_object;
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_s_root(VALUE recv)
+{
+ return root_box->box_object;
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_s_main(VALUE recv)
+{
+ return main_box->box_object;
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_master_p(VALUE box_value)
+{
+ const rb_box_t *box = (const rb_box_t *)rb_get_box_t(box_value);
+ return RBOOL(BOX_MASTER_P(box));
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_root_p(VALUE box_value)
+{
+ const rb_box_t *box = (const rb_box_t *)rb_get_box_t(box_value);
+ return RBOOL(BOX_ROOT_P(box));
+}
+
+/* :nodoc: */
+static VALUE
+rb_box_main_p(VALUE box_value)
+{
+ const rb_box_t *box = (const rb_box_t *)rb_get_box_t(box_value);
+ return RBOOL(BOX_MAIN_P(box));
+}
+
+#if RUBY_DEBUG
+
+static const char *
+classname(VALUE klass)
+{
+ VALUE p;
+ if (!klass) {
+ return "Qfalse";
+ }
+ p = RCLASSEXT_CLASSPATH(RCLASS_EXT_PRIME(klass));
+ if (RTEST(p))
+ return RSTRING_PTR(p);
+ if (RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS))
+ return "AnyClassValue";
+ return "NonClassValue";
+}
+
+static enum rb_id_table_iterator_result
+dump_classext_methods_i(ID mid, VALUE _val, void *data)
+{
+ VALUE ary = (VALUE)data;
+ rb_ary_push(ary, rb_id2str(mid));
+ return ID_TABLE_CONTINUE;
+}
+
+static enum rb_id_table_iterator_result
+dump_classext_constants_i(ID mid, VALUE _val, void *data)
+{
+ VALUE ary = (VALUE)data;
+ rb_ary_push(ary, rb_id2str(mid));
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+dump_classext_i(rb_classext_t *ext, bool is_prime, VALUE _recv, void *data)
+{
+ char buf[4096];
+ struct rb_id_table *tbl;
+ VALUE ary, res = (VALUE)data;
+
+ snprintf(buf, 4096, "Ruby::Box %ld:%s classext %p\n",
+ RCLASSEXT_BOX(ext)->box_id, is_prime ? " prime" : "", (void *)ext);
+ rb_str_cat_cstr(res, buf);
+
+ snprintf(buf, 2048, " Super: %s\n", classname(RCLASSEXT_SUPER(ext)));
+ rb_str_cat_cstr(res, buf);
+
+ tbl = RCLASSEXT_M_TBL(ext);
+ if (tbl) {
+ ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
+ rb_id_table_foreach(RCLASSEXT_M_TBL(ext), dump_classext_methods_i, (void *)ary);
+ rb_ary_sort_bang(ary);
+ snprintf(buf, 4096, " Methods(%ld): ", RARRAY_LEN(ary));
+ rb_str_cat_cstr(res, buf);
+ rb_str_concat(res, rb_ary_join(ary, rb_str_new_cstr(",")));
+ rb_str_cat_cstr(res, "\n");
+ }
+ else {
+ rb_str_cat_cstr(res, " Methods(0): .\n");
+ }
+
+ tbl = RCLASSEXT_CONST_TBL(ext);
+ if (tbl) {
+ ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
+ rb_id_table_foreach(tbl, dump_classext_constants_i, (void *)ary);
+ rb_ary_sort_bang(ary);
+ snprintf(buf, 4096, " Constants(%ld): ", RARRAY_LEN(ary));
+ rb_str_cat_cstr(res, buf);
+ rb_str_concat(res, rb_ary_join(ary, rb_str_new_cstr(",")));
+ rb_str_cat_cstr(res, "\n");
+ }
+ else {
+ rb_str_cat_cstr(res, " Constants(0): .\n");
+ }
+}
+
+/* :nodoc: */
+static VALUE
+rb_f_dump_classext(VALUE recv, VALUE klass)
+{
+ /*
+ * The desired output String value is:
+ * Class: 0x88800932 (String) [singleton]
+ * Prime classext box(2,main), readable(t), writable(f)
+ * Non-prime classexts: 3
+ * Box 2: prime classext 0x88800933
+ * Super: Object
+ * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
+ * Constants(12): FOO, Bar, ...
+ * Box 5: classext 0x88800934
+ * Super: Object
+ * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
+ * Constants(12): FOO, Bar, ...
+ */
+ char buf[2048];
+ VALUE res;
+ const rb_classext_t *ext;
+ const rb_box_t *box;
+ st_table *classext_tbl;
+
+ if (!(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE))) {
+ snprintf(buf, 2048, "Non-class/module value: %p (%s)\n", (void *)klass, rb_type_str(BUILTIN_TYPE(klass)));
+ return rb_str_new_cstr(buf);
+ }
+
+ if (RB_TYPE_P(klass, T_CLASS)) {
+ snprintf(buf, 2048, "Class: %p (%s)%s\n",
+ (void *)klass, classname(klass), RCLASS_SINGLETON_P(klass) ? " [singleton]" : "");
+ }
+ else {
+ snprintf(buf, 2048, "Module: %p (%s)\n", (void *)klass, classname(klass));
+ }
+ res = rb_str_new_cstr(buf);
+
+ ext = RCLASS_EXT_PRIME(klass);
+ box = RCLASSEXT_BOX(ext);
+ snprintf(buf, 2048, "Prime classext box(%ld,%s), readable(%s), writable(%s)\n",
+ box->box_id,
+ BOX_MASTER_P(box) ? "master" : (BOX_ROOT_P(box) ? "root" : (BOX_MAIN_P(box) ? "main" : "optional")),
+ RCLASS_PRIME_CLASSEXT_READABLE_P(klass) ? "t" : "f",
+ RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass) ? "t" : "f");
+ rb_str_cat_cstr(res, buf);
+
+ classext_tbl = RCLASS_CLASSEXT_TBL(klass);
+ if (!classext_tbl) {
+ rb_str_cat_cstr(res, "Non-prime classexts: 0\n");
+ }
+ else {
+ snprintf(buf, 2048, "Non-prime classexts: %zu\n", st_table_size(classext_tbl));
+ rb_str_cat_cstr(res, buf);
+ }
+
+ rb_class_classext_foreach(klass, dump_classext_i, (void *)res);
+
+ return res;
+}
+
+#endif /* RUBY_DEBUG */
+
+/*
+ * Document-class: Ruby::Box
+ *
+ * :markup: markdown
+ * :include: doc/language/box.md
+ */
+void
+Init_Box(void)
+{
+ tmp_dir = system_tmpdir();
+ tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
+
+ VALUE mRuby = rb_define_module("Ruby");
+
+ rb_cBox = rb_define_class_under(mRuby, "Box", rb_cModule);
+ rb_define_method(rb_cBox, "initialize", box_initialize, 0);
+
+ /* :nodoc: */
+ rb_cBoxEntry = rb_define_class_under(rb_cBox, "Entry", rb_cObject);
+ rb_define_alloc_func(rb_cBoxEntry, rb_box_entry_alloc);
+
+ initialize_master_box();
+
+ /* :nodoc: */
+ rb_mBoxLoader = rb_define_module_under(rb_cBox, "Loader");
+ box_define_loader_method("require");
+ box_define_loader_method("require_relative");
+ box_define_loader_method("load");
+
+ if (rb_box_available()) {
+ rb_include_module(rb_cObject, rb_mBoxLoader);
+
+ rb_define_singleton_method(rb_cBox, "master", rb_box_s_master, 0);
+ rb_define_singleton_method(rb_cBox, "root", rb_box_s_root, 0);
+ rb_define_singleton_method(rb_cBox, "main", rb_box_s_main, 0);
+ rb_define_method(rb_cBox, "master?", rb_box_master_p, 0);
+ rb_define_method(rb_cBox, "root?", rb_box_root_p, 0);
+ rb_define_method(rb_cBox, "main?", rb_box_main_p, 0);
+
+#if RUBY_DEBUG
+ rb_define_global_function("dump_classext", rb_f_dump_classext, 1);
+#endif
+ }
+
+ rb_define_singleton_method(rb_cBox, "enabled?", rb_box_s_getenabled, 0);
+ rb_define_singleton_method(rb_cBox, "current", rb_box_s_current, 0);
+
+ rb_define_method(rb_cBox, "load_path", rb_box_load_path, 0);
+ rb_define_method(rb_cBox, "load", rb_box_load, -1);
+ rb_define_method(rb_cBox, "require", rb_box_require, 1);
+ rb_define_method(rb_cBox, "require_relative", rb_box_require_relative, 1);
+ rb_define_method(rb_cBox, "eval", rb_box_eval, 1);
+
+ rb_define_method(rb_cBox, "inspect", rb_box_inspect, 0);
+}
diff --git a/builtin.c b/builtin.c
index 3bde2408f8..03c9d03bc3 100644
--- a/builtin.c
+++ b/builtin.c
@@ -1,9 +1,10 @@
#include "internal.h"
+#include "internal/box.h"
#include "vm_core.h"
#include "iseq.h"
#include "builtin.h"
-#include "builtin_binary.inc"
+#include "builtin_binary.rbbin"
#ifndef BUILTIN_BINARY_SIZE
@@ -22,18 +23,41 @@ bin4feature(const struct builtin_binary *bb, const char *feature, size_t *psize)
static const unsigned char*
builtin_lookup(const char *feature, size_t *psize)
{
- static int index = 0;
- const unsigned char *bin = bin4feature(&builtin_binary[index++], feature, psize);
+ static size_t index = 0;
+ const unsigned char *bin = NULL;
- // usually, `builtin_binary` order is loading order at miniruby.
- for (const struct builtin_binary *bb = &builtin_binary[0]; bb->feature &&! bin; bb++) {
- bin = bin4feature(bb++, feature, psize);
+ /*
+ * Fast path:
+ * builtin_binary is usually arranged in the same order
+ * as features are looked up in miniruby, so try the next entry first.
+ */
+ if (builtin_binary[index].feature) {
+ bin = bin4feature(&builtin_binary[index], feature, psize);
+ index++;
}
+ if (bin) {
+ return bin;
+ }
+
+ /*
+ * Fallback:
+ * In case the lookup order does not match the array order,
+ * scan the entire table to find the feature.
+ */
+ for (const struct builtin_binary *bb = &builtin_binary[0];
+ bb->feature;
+ bb++) {
+ bin = bin4feature(bb, feature, psize);
+ if (bin) {
+ break;
+ }
+ }
+
return bin;
}
-void
-rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+static void
+load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table, const rb_box_t *target_box)
{
// search binary
size_t size;
@@ -51,7 +75,40 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
vm->builtin_function_table = NULL;
// exec
- rb_iseq_eval(rb_iseq_check(iseq));
+ rb_iseq_eval(rb_iseq_check(iseq), target_box);
+}
+
+void
+rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
+{
+ load_with_builtin_functions(feature_name, table, rb_root_box());
+}
+
+VALUE
+rb_define_gem_modules(VALUE flags_value, VALUE _)
+{
+ rb_box_gem_flags_t *flags = (rb_box_gem_flags_t *)flags_value;
+
+ if (flags->gem) {
+ rb_define_module("Gem");
+ if (flags->error_highlight) {
+ rb_define_module("ErrorHighlight");
+ }
+ if (flags->did_you_mean) {
+ rb_define_module("DidYouMean");
+ }
+ if (flags->syntax_suggest) {
+ rb_define_module("SyntaxSuggest");
+ }
+ }
+
+ return Qnil;
+}
+
+void
+rb_load_gem_prelude(VALUE box)
+{
+ load_with_builtin_functions("gem_prelude", NULL, (const rb_box_t *)box);
}
#endif
@@ -71,5 +128,13 @@ Init_builtin(void)
void
Init_builtin_features(void)
{
- rb_load_with_builtin_functions("gem_prelude", NULL);
+
+#ifdef BUILTIN_BINARY_SIZE
+
+ rb_load_gem_prelude((VALUE)rb_root_box());
+
+ rb_load_gem_prelude((VALUE)rb_main_box());
+
+#endif
+
}
diff --git a/builtin.h b/builtin.h
index fd1c4c307f..ffd2aad88e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -21,6 +21,8 @@ struct rb_builtin_function {
}
void rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table);
+VALUE rb_define_gem_modules(VALUE, VALUE);
+void rb_load_gem_prelude(VALUE box);
#ifndef rb_execution_context_t
typedef struct rb_execution_context_struct rb_execution_context_t;
diff --git a/class.c b/class.c
index 9716aab78c..02078cc9bc 100644
--- a/class.c
+++ b/class.c
@@ -21,6 +21,7 @@
#include "debug_counter.h"
#include "id_table.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/class.h"
#include "internal/eval.h"
#include "internal/hash.h"
@@ -29,7 +30,9 @@
#include "internal/variable.h"
#include "ruby/st.h"
#include "vm_core.h"
+#include "ruby/ractor.h"
#include "yjit.h"
+#include "zjit.h"
/* Flags of T_CLASS
*
@@ -38,24 +41,22 @@
* This is done for classes defined from C to allow storing them in global variables.
* 1: RUBY_FL_SINGLETON
* This class is a singleton 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
+ * 2: RCLASS_PRIME_CLASSEXT_WRITABLE
+ * This class's prime classext is the only classext and writable from any boxes.
+ * If unset, the prime classext is writable only from the root box.
+ * 3: RCLASS_IS_INITIALIZED
+ * Class has been initialized.
+ * 4: RCLASS_BOXABLE
+ * Is a builtin class that may be boxed. It larger than a normal class.
*/
/* 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
+ * 2: RCLASS_PRIME_CLASSEXT_WRITABLE
+ * This module's prime classext is the only classext and writable from any boxes.
+ * If unset, the prime classext is writable only from the root box.
+ * 4: RCLASS_BOXABLE
+ * Is a builtin class that may be boxed. It larger than a normal class.
*/
/* Flags of T_MODULE
@@ -63,209 +64,634 @@
* 0: RCLASS_IS_ROOT
* The class has been added to the VM roots. Will always be marked and pinned.
* This is done for classes defined from C to allow storing them in global variables.
- * 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
+ * 1: <reserved>
+ * Ensures that RUBY_FL_SINGLETON is never set on a T_MODULE. See `rb_class_real`.
+ * 2: RCLASS_PRIME_CLASSEXT_WRITABLE
+ * This module's prime classext is the only classext and writable from any boxes.
+ * If unset, the prime classext is writable only from the root box.
+ * 3: RCLASS_IS_INITIALIZED
+ * Module has been initialized.
+ * 4: RCLASS_BOXABLE
+ * Is a builtin class that may be boxed. It larger than a normal class.
+ * 5: 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 METACLASS_OF(k) RBASIC(k)->klass
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
-RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
+rb_classext_t *
+rb_class_unlink_classext(VALUE klass, const rb_box_t *box)
+{
+ st_data_t ext;
+ st_data_t key = (st_data_t)box->box_object;
+ st_delete(box->classext_cow_classes, &klass, 0);
+ st_delete(RCLASS_CLASSEXT_TBL(klass), &key, &ext);
+ return (rb_classext_t *)ext;
+}
-static rb_subclass_entry_t *
-push_subclass_entry_to_list(VALUE super, VALUE klass)
+void
+rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime)
{
- rb_subclass_entry_t *entry, *head;
+ struct rb_id_table *tbl;
- entry = ZALLOC(rb_subclass_entry_t);
- entry->klass = klass;
+ rb_id_table_free(RCLASSEXT_M_TBL(ext));
- head = RCLASS_SUBCLASSES(super);
- if (!head) {
- head = ZALLOC(rb_subclass_entry_t);
- RCLASS_SUBCLASSES(super) = head;
+ if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
+ rb_free_const_table(tbl);
}
- entry->next = head->next;
- entry->prev = head;
- if (head->next) {
- head->next->prev = entry;
+ if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
+ RUBY_ASSERT(is_prime); // superclasses should only be used on prime
+ size_t depth = RCLASSEXT_SUPERCLASS_DEPTH(ext);
+ if (depth != RCLASS_MAX_SUPERCLASS_DEPTH) {
+ depth++;
+ }
+ SIZED_FREE_N(RCLASSEXT_SUPERCLASSES(ext), depth);
}
- head->next = entry;
- return entry;
+ if (!is_prime) { // the prime classext will be freed with RClass
+ SIZED_FREE(ext);
+ }
}
void
-rb_class_subclass_add(VALUE super, VALUE klass)
+rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime)
{
- if (super && !UNDEF_P(super)) {
- rb_subclass_entry_t *entry = push_subclass_entry_to_list(super, klass);
- RCLASS_SUBCLASS_ENTRY(klass) = entry;
+ if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
+ /* Method table is not shared for origin iclasses of classes */
+ rb_id_table_free(RCLASSEXT_M_TBL(ext));
+ }
+
+ if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
+ rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
+ }
+
+ if (!is_prime) { // the prime classext will be freed with RClass
+ SIZED_FREE(ext);
}
}
static void
-rb_module_add_to_subclasses_list(VALUE module, VALUE iclass)
+iclass_free_orphan_classext(VALUE klass, rb_classext_t *ext)
{
- rb_subclass_entry_t *entry = push_subclass_entry_to_list(module, iclass);
- RCLASS_MODULE_SUBCLASS_ENTRY(iclass) = entry;
+ if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
+ /* Method table is not shared for origin iclasses of classes */
+ rb_id_table_free(RCLASSEXT_M_TBL(ext));
+ }
+
+ if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
+ rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
+ }
+
+ SIZED_FREE(ext);
}
-void
-rb_class_remove_subclass_head(VALUE klass)
+struct rb_class_set_box_classext_args {
+ VALUE obj;
+ rb_classext_t *ext;
+};
+
+static int
+set_box_classext_update(st_data_t *key_ptr, st_data_t *val_ptr, st_data_t a, int existing)
{
- rb_subclass_entry_t *head = RCLASS_SUBCLASSES(klass);
+ struct rb_class_set_box_classext_args *args = (struct rb_class_set_box_classext_args *)a;
- if (head) {
- if (head->next) {
- head->next->prev = NULL;
+ if (existing) {
+ if (LIKELY(BUILTIN_TYPE(args->obj) == T_ICLASS)) {
+ iclass_free_orphan_classext(args->obj, (rb_classext_t *)*val_ptr);
+ }
+ else {
+ rb_bug("Updating existing classext for non-iclass never happen");
}
- RCLASS_SUBCLASSES(klass) = NULL;
- xfree(head);
}
+
+ *val_ptr = (st_data_t)args->ext;
+
+ return ST_CONTINUE;
}
void
-rb_class_remove_from_super_subclasses(VALUE klass)
+rb_class_set_box_classext(VALUE obj, const rb_box_t *box, rb_classext_t *ext)
{
- rb_subclass_entry_t *entry = RCLASS_SUBCLASS_ENTRY(klass);
+ struct rb_class_set_box_classext_args args = {
+ .obj = obj,
+ .ext = ext,
+ };
- if (entry) {
- rb_subclass_entry_t *prev = entry->prev, *next = entry->next;
+ VM_ASSERT(BOX_MUTABLE_P(box));
- if (prev) {
- prev->next = next;
- }
- if (next) {
- next->prev = prev;
- }
+ st_update(RCLASS_CLASSEXT_TBL(obj), (st_data_t)box->box_object, set_box_classext_update, (st_data_t)&args);
- xfree(entry);
+ // The classext references are now visible via the classext table,
+ // so we must issue the write barrier before any further allocations
+ // (e.g. st_insert below) that could trigger GC.
+ rb_gc_writebarrier_remember(obj);
+
+ st_insert(box->classext_cow_classes, (st_data_t)obj, 0);
+}
+
+RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
+
+struct duplicate_id_tbl_data {
+ struct rb_id_table *tbl;
+ VALUE klass;
+};
+
+static enum rb_id_table_iterator_result
+duplicate_classext_m_tbl_i(ID key, VALUE value, void *data)
+{
+ struct duplicate_id_tbl_data *arg = (struct duplicate_id_tbl_data *)data;
+ rb_method_entry_t *me = (rb_method_entry_t *)value;
+ rb_method_table_insert0(arg->klass, arg->tbl, key, me, false);
+ return ID_TABLE_CONTINUE;
+}
+
+static struct rb_id_table *
+duplicate_classext_m_tbl(struct rb_id_table *orig, VALUE klass, bool init_missing)
+{
+ struct rb_id_table *tbl;
+ if (!orig) {
+ if (init_missing)
+ return rb_id_table_create(0);
+ else
+ return NULL;
}
+ tbl = rb_id_table_create(rb_id_table_size(orig));
+ struct duplicate_id_tbl_data data = {
+ .tbl = tbl,
+ .klass = klass,
+ };
+ rb_id_table_foreach(orig, duplicate_classext_m_tbl_i, &data);
+ return tbl;
+}
+
+static rb_const_entry_t *
+duplicate_classext_const_entry(rb_const_entry_t *src, VALUE klass)
+{
+ // See also: setup_const_entry (variable.c)
+ rb_const_entry_t *dst = ZALLOC(rb_const_entry_t);
+
+ dst->flag = src->flag;
+ dst->line = src->line;
+ RB_OBJ_WRITE(klass, &dst->value, src->value);
+ RB_OBJ_WRITE(klass, &dst->file, src->file);
- RCLASS_SUBCLASS_ENTRY(klass) = NULL;
+ return dst;
}
-void
-rb_class_remove_from_module_subclasses(VALUE klass)
+static enum rb_id_table_iterator_result
+duplicate_classext_const_tbl_i(ID key, VALUE value, void *data)
{
- rb_subclass_entry_t *entry = RCLASS_MODULE_SUBCLASS_ENTRY(klass);
+ struct duplicate_id_tbl_data *arg = (struct duplicate_id_tbl_data *)data;
+ rb_const_entry_t *entry = duplicate_classext_const_entry((rb_const_entry_t *)value, arg->klass);
- if (entry) {
- rb_subclass_entry_t *prev = entry->prev, *next = entry->next;
+ rb_id_table_insert(arg->tbl, key, (VALUE)entry);
- if (prev) {
- prev->next = next;
- }
- if (next) {
- next->prev = prev;
- }
+ return ID_TABLE_CONTINUE;
+}
+
+static struct rb_id_table *
+duplicate_classext_const_tbl(struct rb_id_table *src, VALUE klass)
+{
+ struct rb_id_table *dst;
+
+ if (!src)
+ return NULL;
+
+ dst = rb_id_table_create(rb_id_table_size(src));
+
+ struct duplicate_id_tbl_data data = {
+ .tbl = dst,
+ .klass = klass,
+ };
+ rb_id_table_foreach(src, duplicate_classext_const_tbl_i, (void *)&data);
+
+ return dst;
+}
+
+static void
+class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_box_t *box)
+{
+ RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
- xfree(entry);
+ rb_classext_t *src = RCLASS_EXT_PRIME(iclass);
+ rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(iclass, box);
+ int first_set = 0;
+
+ if (ext) {
+ // iclass classext for the ns is only for cc/callable_m_tbl if it's created earlier than module's one
+ rb_invalidate_method_caches(RCLASSEXT_CALLABLE_M_TBL(ext), RCLASSEXT_CC_TBL(ext));
}
- RCLASS_MODULE_SUBCLASS_ENTRY(klass) = NULL;
+ ext = ZALLOC(rb_classext_t);
+
+ RCLASSEXT_BOX(ext) = box;
+
+ RCLASSEXT_SUPER(ext) = RCLASSEXT_SUPER(src);
+
+ // See also: rb_include_class_new()
+ if (RCLASSEXT_ICLASS_IS_ORIGIN(src) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(src)) {
+ RCLASSEXT_M_TBL(ext) = duplicate_classext_m_tbl(RCLASSEXT_M_TBL(src), iclass, true);
+ }
+ else {
+ RCLASSEXT_M_TBL(ext) = RCLASSEXT_M_TBL(mod_ext);
+ }
+
+ RCLASSEXT_CONST_TBL(ext) = RCLASSEXT_CONST_TBL(mod_ext);
+ RCLASSEXT_CVC_TBL(ext) = RCLASSEXT_CVC_TBL(mod_ext);
+
+ // Those are cache and should be recreated when methods are called
+ // RCLASSEXT_CALLABLE_M_TBL(ext) = NULL;
+ // RCLASSEXT_CC_TBL(ext) = NULL;
+
+ // Subclasses/back-pointers are only in the prime classext.
+
+ RCLASSEXT_SET_ORIGIN(ext, iclass, RCLASSEXT_ORIGIN(src));
+ RCLASSEXT_ICLASS_IS_ORIGIN(ext) = RCLASSEXT_ICLASS_IS_ORIGIN(src);
+ RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) = RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(src);
+
+ RCLASSEXT_SET_INCLUDER(ext, iclass, RCLASSEXT_INCLUDER(src));
+
+ VM_ASSERT(FL_TEST_RAW(iclass, RCLASS_BOXABLE));
+
+ first_set = RCLASS_SET_BOX_CLASSEXT(iclass, box, ext);
+ if (first_set) {
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE(iclass, false);
+ }
}
-void
-rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE arg)
+rb_classext_t *
+rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_box_t *box)
{
- // RCLASS_SUBCLASSES should always point to our head element which has NULL klass
- rb_subclass_entry_t *cur = RCLASS_SUBCLASSES(klass);
- // if we have a subclasses list, then the head is a placeholder with no valid
- // class. So ignore it and use the next element in the list (if one exists)
- if (cur) {
- RUBY_ASSERT(!cur->klass);
- cur = cur->next;
+ VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+
+ rb_classext_t *ext = ZALLOC(rb_classext_t);
+ bool dup_iclass = RB_TYPE_P(klass, T_MODULE) ? true : false;
+
+ RCLASSEXT_BOX(ext) = box;
+
+ RCLASSEXT_SUPER(ext) = RCLASSEXT_SUPER(orig);
+
+ RCLASSEXT_M_TBL(ext) = duplicate_classext_m_tbl(RCLASSEXT_M_TBL(orig), klass, dup_iclass);
+ RCLASSEXT_ICLASS_IS_ORIGIN(ext) = true;
+ RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) = false;
+
+ if (orig->fields_obj) {
+ RB_OBJ_WRITE(klass, &ext->fields_obj, rb_imemo_fields_clone(orig->fields_obj));
+ }
+
+ if (RCLASSEXT_SHARED_CONST_TBL(orig)) {
+ RCLASSEXT_CONST_TBL(ext) = RCLASSEXT_CONST_TBL(orig);
+ RCLASSEXT_SHARED_CONST_TBL(ext) = true;
+ }
+ else {
+ RCLASSEXT_CONST_TBL(ext) = duplicate_classext_const_tbl(RCLASSEXT_CONST_TBL(orig), klass);
+ RCLASSEXT_SHARED_CONST_TBL(ext) = false;
+ }
+ /*
+ * callable_m_tbl is for `super` chain, and entries will be created when the super chain is called.
+ * so initially, it can be NULL and let it be created lazily.
+ * RCLASSEXT_CALLABLE_M_TBL(ext) = NULL;
+ *
+ * cc_tbl is for method inline cache, and method calls from different boxes never occur on
+ * the same code, so the copied classext should have a different cc_tbl from the prime one.
+ * RCLASSEXT_CC_TBL(copy) = NULL
+ */
+
+ VALUE cvc_table = RCLASSEXT_CVC_TBL(orig);
+ if (cvc_table) {
+ cvc_table = rb_marked_id_table_dup(cvc_table);
+ }
+ else if (dup_iclass) {
+ cvc_table = rb_marked_id_table_new(2);
+ }
+ RB_OBJ_WRITE(klass, &RCLASSEXT_CVC_TBL(ext), cvc_table);
+
+ // Subclasses/back-pointers are only in the prime classext.
+
+ RCLASSEXT_SET_ORIGIN(ext, klass, RCLASSEXT_ORIGIN(orig));
+ /*
+ * Members not copied to box's classext values
+ * * refined_class
+ * * as.class.allocator / as.singleton_class.attached_object
+ * * includer
+ * * max IV count
+ * * variation count
+ */
+ RCLASSEXT_PERMANENT_CLASSPATH(ext) = RCLASSEXT_PERMANENT_CLASSPATH(orig);
+ RCLASSEXT_CLASSPATH(ext) = RCLASSEXT_CLASSPATH(orig);
+
+ /* For the usual T_CLASS/T_MODULE, iclass flags are always false */
+
+ if (dup_iclass) {
+ /*
+ * ICLASS has the same m_tbl/const_tbl/cvc_tbl with the included module.
+ * So the module's classext is copied, its tables should be also referred
+ * by the ICLASS's classext for the box.
+ *
+ * Subclasses are only in the prime classext, so read from orig.
+ */
+ VALUE subs_v = RCLASSEXT_SUBCLASSES(orig);
+ if (subs_v) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ VALUE iclass = entries[i];
+ if (!iclass) continue;
+
+ /* every node in the subclass list should be an ICLASS built from this module */
+ VM_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
+ VM_ASSERT(RBASIC_CLASS(iclass) == klass);
+
+ if (FL_TEST_RAW(iclass, RCLASS_BOXABLE)) {
+ // Non-boxable ICLASSes (included by classes in main/user boxes) can't
+ // hold per-box classexts, and their includer classes also can't, so
+ // method lookup through them always uses the prime classext.
+ class_duplicate_iclass_classext(iclass, ext, box);
+ }
+ }
+ }
}
- /* do not be tempted to simplify this loop into a for loop, the order of
- operations is important here if `f` modifies the linked list */
- while (cur) {
- VALUE curklass = cur->klass;
- cur = cur->next;
- // do not trigger GC during f, otherwise the cur will become
- // a dangling pointer if the subclass is collected
- f(curklass, arg);
+ return ext;
+}
+
+void
+rb_class_ensure_writable(VALUE klass)
+{
+ VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+ RCLASS_EXT_WRITABLE(klass);
+}
+
+struct class_classext_foreach_arg {
+ rb_class_classext_foreach_callback_func *func;
+ void * callback_arg;
+};
+
+static int
+class_classext_foreach_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct class_classext_foreach_arg *foreach_arg = (struct class_classext_foreach_arg *)arg;
+ rb_class_classext_foreach_callback_func *func = foreach_arg->func;
+ func((rb_classext_t *)value, false, (VALUE)key, foreach_arg->callback_arg);
+ return ST_CONTINUE;
+}
+
+void
+rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg)
+{
+ st_table *tbl = RCLASS_CLASSEXT_TBL(klass);
+ struct class_classext_foreach_arg foreach_arg;
+ if (tbl) {
+ foreach_arg.func = func;
+ foreach_arg.callback_arg = arg;
+ rb_st_foreach(tbl, class_classext_foreach_i, (st_data_t)&foreach_arg);
}
+ func(RCLASS_EXT_PRIME(klass), true, (VALUE)NULL, arg);
+}
+
+VALUE
+rb_class_super_of(VALUE klass)
+{
+ return RCLASS_SUPER(klass);
+}
+
+VALUE
+rb_class_singleton_p(VALUE klass)
+{
+ return RCLASS_SINGLETON_P(klass);
+}
+
+unsigned char
+rb_class_variation_count(VALUE klass)
+{
+ return RCLASS_VARIATION_COUNT(klass);
}
static void
-class_detach_subclasses(VALUE klass, VALUE arg)
+push_subclass_entry_to_list(VALUE super, VALUE klass)
{
- rb_class_remove_from_super_subclasses(klass);
+ RUBY_ASSERT(
+ (RB_TYPE_P(super, T_MODULE) && RB_TYPE_P(klass, T_ICLASS)) ||
+ (RB_TYPE_P(super, T_CLASS) && RB_TYPE_P(klass, T_CLASS)) ||
+ (RB_TYPE_P(klass, T_ICLASS) && !NIL_P(RCLASS_REFINED_CLASS(klass)))
+ );
+
+ RB_VM_LOCKING() {
+ VALUE subs_v = RCLASS_SUBCLASSES(super);
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+
+ if (!subs || subs->count == subs->capacity) {
+ VALUE *old_entries = subs ? rb_imemo_subclasses_entries(subs_v) : NULL;
+ uint32_t live = 0;
+ for (uint32_t i = 0; subs && i < subs->count; i++) {
+ if (old_entries[i]) live++;
+ }
+
+ uint32_t cap = subs ? subs->capacity : 2;
+ if (live * 2 >= cap) cap *= 2;
+
+ VALUE new_v = rb_imemo_subclasses_new(cap);
+ struct rb_subclasses *new_subs = (struct rb_subclasses *)new_v;
+ VALUE *new_entries = rb_imemo_subclasses_entries(new_v);
+ for (uint32_t i = 0; subs && i < subs->count; i++) {
+ VALUE entry = old_entries[i];
+ if (entry) {
+ new_entries[new_subs->count++] = entry;
+ RB_OBJ_WRITTEN(new_v, Qundef, entry);
+ }
+ }
+ RCLASS_SET_SUBCLASSES(super, new_v);
+ subs_v = new_v;
+ subs = new_subs;
+ }
+
+ rb_imemo_subclasses_entries(subs_v)[subs->count++] = klass;
+ RB_OBJ_WRITTEN(subs_v, Qundef, klass);
+ }
}
void
-rb_class_detach_subclasses(VALUE klass)
+rb_class_subclass_add(VALUE super, VALUE klass)
{
- rb_class_foreach_subclass(klass, class_detach_subclasses, Qnil);
+ if (super && !UNDEF_P(super)) {
+ RUBY_ASSERT(RB_TYPE_P(super, T_CLASS) || RB_TYPE_P(super, T_MODULE));
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
+ push_subclass_entry_to_list(super, klass);
+ }
}
static void
-class_detach_module_subclasses(VALUE klass, VALUE arg)
+rb_module_add_to_subclasses_list(VALUE module, VALUE iclass)
{
- rb_class_remove_from_module_subclasses(klass);
+ if (module && !UNDEF_P(module)) {
+ RUBY_ASSERT(RB_TYPE_P(module, T_MODULE));
+ RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
+ push_subclass_entry_to_list(module, iclass);
+ }
}
void
-rb_class_detach_module_subclasses(VALUE klass)
+rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE arg)
+{
+ VALUE subs_v = RCLASS_SUBCLASSES(klass);
+ if (!subs_v) return;
+
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ VALUE curklass = entries[i];
+ if (curklass) {
+ f(curklass, arg);
+ }
+ }
+}
+
+static void
+class_switch_superclass(VALUE super, VALUE klass)
{
- rb_class_foreach_subclass(klass, class_detach_module_subclasses, Qnil);
+ // No need to remove from old super's subclasses list — the GC
+ // will nullify the weak reference when appropriate.
+ rb_class_subclass_add(super, klass);
}
/**
- * Allocates a struct RClass for a new class.
+ * Allocates a struct RClass for a new class, iclass, or module.
*
- * @param flags initial value for basic.flags of the returned class.
- * @param klass the class of the returned class.
- * @return an uninitialized Class object.
- * @pre `klass` must refer `Class` class or an ancestor of Class.
- * @pre `(flags | T_CLASS) != 0`
- * @post the returned class can safely be `#initialize` 'd.
+ * @param type The type of the RClass (T_CLASS, T_ICLASS, or T_MODULE)
+ * @param klass value for basic.klass of the returned object.
+ * @return an uninitialized Class/IClass/Module object.
+ * @pre `klass` must refer to a class or module
*
* @note this function is not Class#allocate.
*/
static VALUE
-class_alloc(VALUE flags, VALUE klass)
+class_alloc0(enum ruby_value_type type, VALUE klass, bool boxable)
{
- size_t alloc_size = sizeof(struct RClass) + sizeof(rb_classext_t);
+ const rb_box_t *box = rb_current_box();
- flags &= T_MASK;
- if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED;
- NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size, 0);
+ if (!ruby_box_init_done) {
+ boxable = true;
+ }
+
+ size_t alloc_size = sizeof(struct RClass_and_rb_classext_t);
+ if (boxable) {
+ alloc_size = sizeof(struct RClass_boxable);
+ }
+
+ RUBY_ASSERT(type == T_CLASS || type == T_ICLASS || type == T_MODULE);
+
+ VALUE flags = type | FL_SHAREABLE;
+ if (boxable) flags |= RCLASS_BOXABLE;
+
+ shape_id_t shape_id = ROOT_SHAPE_ID;
+ if (boxable) {
+ shape_id |= SHAPE_ID_LAYOUT_OTHER;
+ }
+ else {
+ shape_id |= SHAPE_ID_LAYOUT_RCLASS;
+ }
- memset(RCLASS_EXT(obj), 0, sizeof(rb_classext_t));
+ struct RClass *obj = (struct RClass *)rb_newobj(GET_EC(), klass, flags, shape_id, true, alloc_size);
+
+ obj->object_id = 0;
+
+ memset(RCLASS_EXT_PRIME(obj), 0, sizeof(rb_classext_t));
/* ZALLOC
RCLASS_CONST_TBL(obj) = 0;
RCLASS_M_TBL(obj) = 0;
- RCLASS_IV_INDEX_TBL(obj) = 0;
+ RCLASS_FIELDS(obj) = 0;
RCLASS_SET_SUPER((VALUE)obj, 0);
- RCLASS_SUBCLASSES(obj) = NULL;
- RCLASS_PARENT_SUBCLASSES(obj) = NULL;
- RCLASS_MODULE_SUBCLASSES(obj) = NULL;
*/
+
+ if (boxable) {
+ ((struct RClass_boxable *)obj)->box_classext_tbl = NULL;
+ }
+
+ RCLASS_PRIME_BOX((VALUE)obj) = box;
+ // Classes/Modules defined in user boxes are
+ // writable directly because it exists only in a box.
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE((VALUE)obj, !boxable || BOX_USER_P(box));
+
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
- RB_OBJ_WRITE(obj, &RCLASS_REFINED_CLASS(obj), Qnil);
- RCLASS_SET_ALLOCATOR((VALUE)obj, 0);
+ RCLASS_SET_REFINED_CLASS((VALUE)obj, Qnil);
return (VALUE)obj;
}
+static VALUE
+class_alloc(enum ruby_value_type type, VALUE klass)
+{
+ bool boxable = rb_box_available() && BOX_MASTER_P(rb_current_box());
+ return class_alloc0(type, klass, boxable);
+}
+
+static VALUE
+class_associate_super(VALUE klass, VALUE super, bool init)
+{
+ if (super && !UNDEF_P(super)) {
+ // Only maintain subclass lists for T_CLASS→T_CLASS relationships.
+ // Include/prepend inserts ICLASSes into the super chain, but T_CLASS
+ // subclass lists should track only the immutable T_CLASS→T_CLASS link.
+ if (RB_TYPE_P(klass, T_CLASS) && RB_TYPE_P(super, T_CLASS)) {
+ if (RCLASS_SINGLETON_P(klass)) {
+ // Instead of adding singleton classes to the subclass list,
+ // just set a flag so that method cache invalidation takes the
+ // tree path.
+ FL_SET_RAW(super, RCLASS_HAS_SUBCLASSES);
+ }
+ else {
+ class_switch_superclass(super, klass);
+ }
+ }
+ }
+ if (init) {
+ RCLASS_SET_SUPER(klass, super);
+ }
+ else {
+ RCLASS_WRITE_SUPER(klass, super);
+ }
+ rb_class_update_superclasses(klass);
+ return super;
+}
+
+VALUE
+rb_class_set_super(VALUE klass, VALUE super)
+{
+ return class_associate_super(klass, super, false);
+}
+
+static void
+class_initialize_method_table(VALUE c)
+{
+ // initialize the prime classext m_tbl
+ RCLASS_SET_M_TBL(c, rb_id_table_create(0));
+}
+
static void
-RCLASS_M_TBL_INIT(VALUE c)
+class_clear_method_table(VALUE c)
+{
+ RCLASS_WRITE_M_TBL(c, rb_id_table_create(0));
+}
+
+static VALUE
+class_boot_boxable(VALUE super, bool boxable)
{
- RCLASS_M_TBL(c) = rb_id_table_create(0);
+ VALUE klass = class_alloc0(T_CLASS, rb_cClass, boxable);
+
+ // initialize method table prior to class_associate_super()
+ // because class_associate_super() may cause GC and promote klass
+ class_initialize_method_table(klass);
+
+ class_associate_super(klass, super, true);
+ if (super && !UNDEF_P(super)) {
+ RCLASS_SET_ALLOCATOR(klass, RCLASS_ALLOCATOR(super));
+ rb_class_set_initialized(klass);
+ }
+
+ return (VALUE)klass;
}
/**
@@ -280,18 +706,13 @@ RCLASS_M_TBL_INIT(VALUE c)
VALUE
rb_class_boot(VALUE super)
{
- VALUE klass = class_alloc(T_CLASS, rb_cClass);
-
- RCLASS_SET_SUPER(klass, super);
- RCLASS_M_TBL_INIT(klass);
-
- return (VALUE)klass;
+ return class_boot_boxable(super, false);
}
static VALUE *
class_superclasses_including_self(VALUE klass)
{
- if (FL_TEST_RAW(klass, RCLASS_SUPERCLASSES_INCLUDE_SELF))
+ if (RCLASS_SUPERCLASSES_WITH_SELF_P(klass))
return RCLASS_SUPERCLASSES(klass);
size_t depth = RCLASS_SUPERCLASS_DEPTH(klass);
@@ -300,14 +721,14 @@ class_superclasses_including_self(VALUE klass)
memcpy(superclasses, RCLASS_SUPERCLASSES(klass), sizeof(VALUE) * depth);
superclasses[depth] = klass;
- RCLASS_SUPERCLASSES(klass) = superclasses;
- FL_SET_RAW(klass, RCLASS_SUPERCLASSES_INCLUDE_SELF);
return superclasses;
}
void
rb_class_update_superclasses(VALUE klass)
{
+ VALUE *superclasses;
+ size_t super_depth;
VALUE super = RCLASS_SUPER(klass);
if (!RB_TYPE_P(klass, T_CLASS)) return;
@@ -336,8 +757,17 @@ rb_class_update_superclasses(VALUE klass)
return;
}
- RCLASS_SUPERCLASSES(klass) = class_superclasses_including_self(super);
- RCLASS_SUPERCLASS_DEPTH(klass) = RCLASS_SUPERCLASS_DEPTH(super) + 1;
+ super_depth = RCLASS_SUPERCLASS_DEPTH(super);
+ if (RCLASS_SUPERCLASSES_WITH_SELF_P(super)) {
+ superclasses = RCLASS_SUPERCLASSES(super);
+ }
+ else {
+ superclasses = class_superclasses_including_self(super);
+ RCLASS_WRITE_SUPERCLASSES(super, super_depth, superclasses, true);
+ }
+
+ size_t depth = super_depth == RCLASS_MAX_SUPERCLASS_DEPTH ? super_depth : super_depth + 1;
+ RCLASS_WRITE_SUPERCLASSES(klass, depth, superclasses, false);
}
void
@@ -362,9 +792,8 @@ rb_class_new(VALUE super)
rb_check_inheritable(super);
VALUE klass = rb_class_boot(super);
- if (super != rb_cObject && super != rb_cBasicObject) {
- RCLASS_EXT(klass)->max_iv_count = RCLASS_EXT(super)->max_iv_count;
- }
+ RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super));
+ RUBY_ASSERT(getenv("RUBY_BOX") || RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass));
return klass;
}
@@ -376,28 +805,20 @@ rb_class_s_alloc(VALUE klass)
}
static void
-clone_method(VALUE old_klass, VALUE new_klass, ID mid, const rb_method_entry_t *me)
+clone_method(VALUE new_klass, ID mid, const rb_method_entry_t *me)
{
- if (me->def->type == VM_METHOD_TYPE_ISEQ) {
- rb_cref_t *new_cref;
- rb_vm_rewrite_cref(me->def->body.iseq.cref, old_klass, new_klass, &new_cref);
- rb_add_method_iseq(new_klass, mid, me->def->body.iseq.iseqptr, new_cref, METHOD_ENTRY_VISI(me));
- }
- else {
- rb_method_entry_set(new_klass, mid, me, METHOD_ENTRY_VISI(me));
- }
+ rb_method_entry_set(new_klass, mid, me, METHOD_ENTRY_VISI(me));
}
struct clone_method_arg {
VALUE new_klass;
- VALUE old_klass;
};
static enum rb_id_table_iterator_result
clone_method_i(ID key, VALUE value, void *data)
{
const struct clone_method_arg *arg = (struct clone_method_arg *)data;
- clone_method(arg->old_klass, arg->new_klass, key, (const rb_method_entry_t *)value);
+ clone_method(arg->new_klass, key, (const rb_method_entry_t *)value);
return ID_TABLE_CONTINUE;
}
@@ -430,7 +851,7 @@ class_init_copy_check(VALUE clone, VALUE orig)
if (orig == rb_cBasicObject) {
rb_raise(rb_eTypeError, "can't copy the root class");
}
- if (RCLASS_SUPER(clone) != 0 || clone == rb_cBasicObject) {
+ if (RCLASS_INITIALIZED_P(clone)) {
rb_raise(rb_eTypeError, "already initialized class");
}
if (RCLASS_SINGLETON_P(orig)) {
@@ -440,9 +861,15 @@ class_init_copy_check(VALUE clone, VALUE orig)
struct cvc_table_copy_ctx {
VALUE clone;
- struct rb_id_table * new_table;
+ VALUE new_table;
};
+static struct rb_cvar_class_tbl_entry *
+cvc_table_entry_alloc(void)
+{
+ return (struct rb_cvar_class_tbl_entry *)SHAREABLE_IMEMO_NEW(struct rb_cvar_class_tbl_entry, imemo_cvar_entry, 0);
+}
+
static enum rb_id_table_iterator_result
cvc_table_copy(ID id, VALUE val, void *data)
{
@@ -452,13 +879,11 @@ cvc_table_copy(ID id, VALUE val, void *data)
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 = cvc_table_entry_alloc();
+ RB_OBJ_WRITE((VALUE)ent, &ent->class_value, ctx->clone);
+ RB_OBJ_WRITE(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);
+ rb_marked_id_table_insert(ctx->new_table, id, (VALUE)ent);
return ID_TABLE_CONTINUE;
}
@@ -468,62 +893,49 @@ copy_tables(VALUE clone, VALUE orig)
{
if (RCLASS_CONST_TBL(clone)) {
rb_free_const_table(RCLASS_CONST_TBL(clone));
- RCLASS_CONST_TBL(clone) = 0;
+ RCLASS_WRITE_CONST_TBL(clone, 0, false);
}
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));
+ VALUE rb_cvc_tbl = RCLASS_CVC_TBL(orig);
+ VALUE rb_cvc_tbl_dup = rb_marked_id_table_new(rb_marked_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_marked_id_table_foreach(rb_cvc_tbl, cvc_table_copy, &ctx);
+ RCLASS_WRITE_CVC_TBL(clone, rb_cvc_tbl_dup);
}
rb_id_table_free(RCLASS_M_TBL(clone));
- RCLASS_M_TBL(clone) = 0;
+ RCLASS_WRITE_M_TBL(clone, 0);
if (!RB_TYPE_P(clone, T_ICLASS)) {
- st_data_t id;
-
- rb_iv_tbl_copy(clone, orig);
- CONST_ID(id, "__tmp_classpath__");
- rb_attr_delete(clone, id);
- CONST_ID(id, "__classpath__");
- rb_attr_delete(clone, id);
+ rb_fields_tbl_copy(clone, orig);
}
if (RCLASS_CONST_TBL(orig)) {
struct clone_const_arg arg;
-
- arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
+ struct rb_id_table *const_tbl;
+ struct rb_id_table *orig_tbl = RCLASS_CONST_TBL(orig);
+ arg.tbl = const_tbl = rb_id_table_create(rb_id_table_size(orig_tbl));
arg.klass = clone;
- rb_id_table_foreach(RCLASS_CONST_TBL(orig), clone_const_i, &arg);
+ rb_id_table_foreach(orig_tbl, clone_const_i, &arg);
+ RCLASS_WRITE_CONST_TBL(clone, const_tbl, false);
+ rb_gc_writebarrier_remember(clone);
}
}
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};
-
-static inline bool
-RMODULE_UNINITIALIZED(VALUE module)
-{
- return FL_TEST_RAW(module, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
-}
-
void
-rb_module_set_initialized(VALUE mod)
+rb_class_set_initialized(VALUE klass)
{
- FL_UNSET_RAW(mod, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE));
+ FL_SET_RAW(klass, RCLASS_IS_INITIALIZED);
/* no more re-initialization */
}
void
rb_module_check_initializable(VALUE mod)
{
- if (!RMODULE_UNINITIALIZED(mod)) {
+ if (RCLASS_INITIALIZED_P(mod)) {
rb_raise(rb_eTypeError, "already initialized module");
}
}
@@ -532,9 +944,11 @@ rb_module_check_initializable(VALUE mod)
VALUE
rb_mod_init_copy(VALUE clone, VALUE orig)
{
+ /* Only class or module is valid here, but other classes may enter here and
+ * only hit an exception on the OBJ_INIT_COPY checks
+ */
switch (BUILTIN_TYPE(clone)) {
case T_CLASS:
- case T_ICLASS:
class_init_copy_check(clone, orig);
break;
case T_MODULE:
@@ -545,28 +959,28 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
}
if (!OBJ_INIT_COPY(clone, orig)) return clone;
- /* 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;
+ RUBY_ASSERT(RB_TYPE_P(orig, T_CLASS) || RB_TYPE_P(orig, T_MODULE));
+ RUBY_ASSERT(BUILTIN_TYPE(clone) == BUILTIN_TYPE(orig));
+
+ rb_class_set_initialized(clone);
if (!RCLASS_SINGLETON_P(CLASS_OF(clone))) {
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));
+ if (BUILTIN_TYPE(clone) == T_CLASS) {
+ RCLASS_SET_ALLOCATOR(clone, RCLASS_ALLOCATOR(orig));
+ }
copy_tables(clone, orig);
if (RCLASS_M_TBL(orig)) {
struct clone_method_arg arg;
- arg.old_klass = orig;
arg.new_klass = clone;
- RCLASS_M_TBL_INIT(clone);
+ class_initialize_method_table(clone);
rb_id_table_foreach(RCLASS_M_TBL(orig), clone_method_i, &arg);
}
if (RCLASS_ORIGIN(orig) == orig) {
- RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig));
+ rb_class_set_super(clone, RCLASS_SUPER(orig));
}
else {
VALUE p = RCLASS_SUPER(orig);
@@ -586,15 +1000,11 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
if (BUILTIN_TYPE(p) != T_ICLASS) {
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. */
+ clone_p = class_alloc(T_ICLASS, METACLASS_OF(p));
RCLASS_SET_M_TBL(clone_p, RCLASS_M_TBL(p));
- RCLASS_SET_SUPER(prev_clone_p, clone_p);
+ rb_class_set_super(prev_clone_p, clone_p);
prev_clone_p = clone_p;
- RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
- RCLASS_SET_ALLOCATOR(clone_p, RCLASS_ALLOCATOR(p));
+ RCLASS_SET_CONST_TBL(clone_p, RCLASS_CONST_TBL(p), false);
if (RB_TYPE_P(clone, T_CLASS)) {
RCLASS_SET_INCLUDER(clone_p, clone);
}
@@ -606,8 +1016,8 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
}
else if ((origin_len = RARRAY_LEN(origin_stack)) > 1 &&
RARRAY_AREF(origin_stack, origin_len - 1) == p) {
- RCLASS_SET_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), clone_p);
- RICLASS_SET_ORIGIN_SHARED_MTBL(clone_p);
+ RCLASS_WRITE_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), clone_p);
+ RICLASS_WRITE_ORIGIN_SHARED_MTBL(clone_p);
rb_ary_resize(origin_stack, origin_len);
add_subclass = FALSE;
}
@@ -619,15 +1029,14 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
if (p == orig_origin) {
if (clone_p) {
- RCLASS_SET_SUPER(clone_p, clone_origin);
- RCLASS_SET_SUPER(clone_origin, RCLASS_SUPER(orig_origin));
+ rb_class_set_super(clone_p, clone_origin);
+ rb_class_set_super(clone_origin, RCLASS_SUPER(orig_origin));
}
copy_tables(clone_origin, orig_origin);
if (RCLASS_M_TBL(orig_origin)) {
struct clone_method_arg arg;
- arg.old_klass = orig;
arg.new_klass = clone;
- RCLASS_M_TBL_INIT(clone_origin);
+ class_initialize_method_table(clone_origin);
rb_id_table_foreach(RCLASS_M_TBL(orig_origin), clone_method_i, &arg);
}
}
@@ -664,7 +1073,8 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
else {
/* copy singleton(unnamed) class */
bool klass_of_clone_is_new;
- VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
+ VALUE clone = class_alloc(T_CLASS, 0);
if (BUILTIN_TYPE(obj) == T_CLASS) {
klass_of_clone_is_new = true;
@@ -678,21 +1088,24 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
RBASIC_SET_CLASS(clone, klass_metaclass_clone);
}
- RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
- rb_iv_tbl_copy(clone, klass);
+ // initialize method table before any GC chance
+ class_initialize_method_table(clone);
+
+ rb_class_set_super(clone, RCLASS_SUPER(klass));
+ rb_fields_tbl_copy(clone, klass);
if (RCLASS_CONST_TBL(klass)) {
struct clone_const_arg arg;
- arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
+ struct rb_id_table *table;
+ arg.tbl = table = rb_id_table_create(rb_id_table_size(RCLASS_CONST_TBL(klass)));
arg.klass = clone;
rb_id_table_foreach(RCLASS_CONST_TBL(klass), clone_const_i, &arg);
+ RCLASS_SET_CONST_TBL(clone, table, false);
}
if (!UNDEF_P(attach)) {
rb_singleton_class_attached(clone, attach);
}
- RCLASS_M_TBL_INIT(clone);
{
struct clone_method_arg arg;
- arg.old_klass = klass;
arg.new_klass = clone;
rb_id_table_foreach(RCLASS_M_TBL(klass), clone_method_i, &arg);
}
@@ -766,7 +1179,7 @@ static inline VALUE
make_metaclass(VALUE klass)
{
VALUE super;
- VALUE metaclass = rb_class_boot(Qundef);
+ VALUE metaclass = class_boot_boxable(Qundef, FL_TEST_RAW(klass, RCLASS_BOXABLE));
FL_SET(metaclass, FL_SINGLETON);
rb_singleton_class_attached(metaclass, klass);
@@ -783,7 +1196,8 @@ make_metaclass(VALUE klass)
super = RCLASS_SUPER(klass);
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
- RCLASS_SET_SUPER(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass);
+ class_associate_super(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass, true);
+ rb_class_set_initialized(klass);
// Full class ancestry may not have been filled until we reach here.
rb_class_update_superclasses(METACLASS_OF(metaclass));
@@ -801,12 +1215,18 @@ static inline VALUE
make_singleton_class(VALUE obj)
{
VALUE orig_class = METACLASS_OF(obj);
- VALUE klass = rb_class_boot(orig_class);
-
+ VALUE klass = class_alloc0(T_CLASS, rb_cClass, FL_TEST_RAW(orig_class, RCLASS_BOXABLE));
FL_SET(klass, FL_SINGLETON);
+ class_initialize_method_table(klass);
+ class_associate_super(klass, orig_class, true);
+ if (orig_class && !UNDEF_P(orig_class)) {
+ rb_class_set_initialized(klass);
+ }
+
RBASIC_SET_CLASS(obj, klass);
rb_singleton_class_attached(klass, obj);
rb_yjit_invalidate_no_singleton_class(orig_class);
+ rb_zjit_invalidate_no_singleton_class(orig_class);
SET_METACLASS_OF(klass, METACLASS_OF(rb_class_real(orig_class)));
return klass;
@@ -901,8 +1321,12 @@ void
Init_class_hierarchy(void)
{
rb_cBasicObject = boot_defclass("BasicObject", 0);
+ RCLASS_SET_ALLOCATOR(rb_cBasicObject, rb_class_allocate_instance);
+ FL_SET_RAW(rb_cBasicObject, RCLASS_ALLOCATOR_DEFINED);
+ RCLASS_SET_EXPECT_NO_IVAR(rb_cBasicObject);
+
rb_cObject = boot_defclass("Object", rb_cBasicObject);
- rb_vm_register_global_object(rb_cObject);
+ RCLASS_SET_EXPECT_NO_IVAR(rb_cObject);
/* resolve class name ASAP for order-independence */
rb_set_class_path_string(rb_cObject, rb_cObject, rb_fstring_lit("Object"));
@@ -982,9 +1406,8 @@ VALUE
rb_define_class(const char *name, VALUE super)
{
VALUE klass;
- ID id;
+ ID id = rb_intern(name);
- id = rb_intern(name);
if (rb_const_defined(rb_cObject, id)) {
klass = rb_const_get(rb_cObject, id);
if (!RB_TYPE_P(klass, T_CLASS)) {
@@ -1004,9 +1427,8 @@ rb_define_class(const char *name, VALUE super)
}
klass = rb_define_class_id(id, super);
rb_vm_register_global_object(klass);
- rb_const_set_raw(rb_cObject, id, klass);
+ rb_const_set(rb_cObject, id, klass);
rb_class_inherited(super, klass);
- rb_const_added(klass, id);
return klass;
}
@@ -1044,10 +1466,8 @@ rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super)
}
klass = rb_define_class_id(id, super);
rb_set_class_path_string(klass, outer, rb_id2str(id));
-
- rb_const_set_raw(outer, id, klass);
+ rb_const_set(outer, id, klass);
rb_class_inherited(super, klass);
- rb_const_added(outer, id);
return klass;
}
@@ -1064,8 +1484,7 @@ VALUE
rb_module_s_alloc(VALUE klass)
{
VALUE mod = class_alloc(T_MODULE, klass);
- RCLASS_M_TBL_INIT(mod);
- FL_SET(mod, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
+ class_initialize_method_table(mod);
return mod;
}
@@ -1073,7 +1492,7 @@ static inline VALUE
module_new(VALUE klass)
{
VALUE mdl = class_alloc(T_MODULE, klass);
- RCLASS_M_TBL_INIT(mdl);
+ class_initialize_method_table(mdl);
return (VALUE)mdl;
}
@@ -1100,9 +1519,8 @@ VALUE
rb_define_module(const char *name)
{
VALUE module;
- ID id;
+ ID id = rb_intern(name);
- id = rb_intern(name);
if (rb_const_defined(rb_cObject, id)) {
module = rb_const_get(rb_cObject, id);
if (!RB_TYPE_P(module, T_MODULE)) {
@@ -1155,21 +1573,24 @@ 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_SET_M_TBL(klass, RCLASS_WRITABLE_M_TBL(module));
RCLASS_SET_ORIGIN(klass, klass);
if (BUILTIN_TYPE(module) == T_ICLASS) {
module = METACLASS_OF(module);
}
RUBY_ASSERT(!RB_TYPE_P(module, T_ICLASS));
- if (!RCLASS_CONST_TBL(module)) {
- RCLASS_CONST_TBL(module) = rb_id_table_create(0);
+ if (RCLASS_WRITABLE_CONST_TBL(module)) {
+ RCLASS_SET_CONST_TBL(klass, RCLASS_WRITABLE_CONST_TBL(module), true);
+ }
+ else {
+ RCLASS_WRITE_CONST_TBL(module, rb_id_table_create(0), false);
+ RCLASS_SET_CONST_TBL(klass, RCLASS_WRITABLE_CONST_TBL(module), true);
}
- RCLASS_CVC_TBL(klass) = RCLASS_CVC_TBL(module);
- RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
+ RCLASS_SET_CVC_TBL(klass, RCLASS_WRITABLE_CVC_TBL(module));
- RCLASS_SET_SUPER(klass, super);
+ class_associate_super(klass, super, true);
RBASIC_SET_CLASS(klass, module);
return (VALUE)klass;
@@ -1182,7 +1603,7 @@ ensure_includable(VALUE klass, VALUE module)
{
rb_class_modify_check(klass);
Check_Type(module, T_MODULE);
- rb_module_set_initialized(module);
+ rb_class_set_initialized(module);
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
rb_raise(rb_eArgError, "refinement module is not allowed");
}
@@ -1200,35 +1621,34 @@ rb_include_module(VALUE klass, VALUE module)
rb_raise(rb_eArgError, "cyclic include detected");
if (RB_TYPE_P(klass, T_MODULE)) {
- rb_subclass_entry_t *iclass = RCLASS_SUBCLASSES(klass);
- // skip the placeholder subclass entry at the head of the list
- if (iclass) {
- RUBY_ASSERT(!iclass->klass);
- iclass = iclass->next;
- }
-
- 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. */
- if (!rb_objspace_garbage_object_p(check_class)) {
- while (check_class) {
- RUBY_ASSERT(!rb_objspace_garbage_object_p(check_class));
-
- if (RB_TYPE_P(check_class, T_ICLASS) &&
- (METACLASS_OF(check_class) == module)) {
- do_include = 0;
+ VALUE subs_v = RCLASS_SUBCLASSES(klass);
+ if (subs_v) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ VALUE check_class = entries[i];
+ if (!check_class) continue;
+
+ int do_include = 1;
+ /* During lazy sweeping, the entry could be a dead object that
+ * has not yet been swept. */
+ if (!rb_objspace_garbage_object_p(check_class)) {
+ VALUE walk = check_class;
+ while (walk) {
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(walk));
+
+ if (RB_TYPE_P(walk, T_ICLASS) &&
+ (METACLASS_OF(walk) == module)) {
+ do_include = 0;
+ }
+ walk = RCLASS_SUPER(walk);
}
- check_class = RCLASS_SUPER(check_class);
- }
- if (do_include) {
- include_modules_at(iclass->klass, RCLASS_ORIGIN(iclass->klass), module, TRUE);
+ if (do_include) {
+ include_modules_at(check_class, RCLASS_ORIGIN(check_class), module, TRUE);
+ }
}
}
-
- iclass = iclass->next;
}
}
}
@@ -1337,7 +1757,7 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super
// setup T_ICLASS for the include/prepend module
iclass = rb_include_class_new(module, super_class);
- c = RCLASS_SET_SUPER(c, iclass);
+ c = rb_class_set_super(c, iclass);
RCLASS_SET_INCLUDER(iclass, klass);
if (module != RCLASS_ORIGIN(module)) {
if (!origin_stack) origin_stack = rb_ary_hidden_new(2);
@@ -1346,8 +1766,8 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super
}
else if (origin_stack && (origin_len = RARRAY_LEN(origin_stack)) > 1 &&
RARRAY_AREF(origin_stack, origin_len - 1) == module) {
- RCLASS_SET_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), iclass);
- RICLASS_SET_ORIGIN_SHARED_MTBL(iclass);
+ RCLASS_WRITE_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), iclass);
+ RICLASS_WRITE_ORIGIN_SHARED_MTBL(iclass);
rb_ary_resize(origin_stack, origin_len);
}
@@ -1386,7 +1806,7 @@ move_refined_method(ID key, VALUE value, void *data)
if (me->def->type == VM_METHOD_TYPE_REFINED) {
VALUE klass = (VALUE)data;
- struct rb_id_table *tbl = RCLASS_M_TBL(klass);
+ struct rb_id_table *tbl = RCLASS_WRITABLE_M_TBL(klass);
if (me->def->body.refined.orig_me) {
const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me;
@@ -1428,10 +1848,15 @@ ensure_origin(VALUE 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_INIT(klass);
+ rb_class_set_super(origin, RCLASS_SUPER(klass));
+ rb_class_set_super(klass, origin); // writes origin into RCLASS_SUPER(klass)
+ RCLASS_WRITE_ORIGIN(klass, origin);
+
+ // RCLASS_WRITE_ORIGIN marks origin as an origin, so this is the first
+ // point that it sees M_TBL and may mark it
+ rb_gc_writebarrier_remember(origin);
+
+ class_clear_method_table(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);
return true;
@@ -1456,35 +1881,32 @@ rb_prepend_module(VALUE klass, VALUE module)
rb_vm_check_redefinition_by_prepend(klass);
}
if (RB_TYPE_P(klass, T_MODULE)) {
- rb_subclass_entry_t *iclass = RCLASS_SUBCLASSES(klass);
- // skip the placeholder subclass entry at the head of the list if it exists
- if (iclass) {
- RUBY_ASSERT(!iclass->klass);
- iclass = iclass->next;
- }
-
+ VALUE subs_v = RCLASS_SUBCLASSES(klass);
VALUE klass_origin = RCLASS_ORIGIN(klass);
struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass);
struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin);
- while (iclass) {
- /* During lazy sweeping, iclass->klass could be a dead object that
- * has not yet been swept. */
- if (!rb_objspace_garbage_object_p(iclass->klass)) {
- const VALUE subclass = iclass->klass;
- if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) {
- // backfill an origin iclass to handle refinements and future prepends
- rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass);
- RCLASS_M_TBL(subclass) = klass_m_tbl;
- VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(subclass));
- RCLASS_SET_SUPER(subclass, origin);
- RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(subclass));
- RCLASS_SET_ORIGIN(subclass, origin);
- RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
+ if (subs_v) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)subs_v;
+ VALUE *entries = rb_imemo_subclasses_entries(subs_v);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ const VALUE subclass = entries[i];
+ if (!subclass) continue;
+ /* During lazy sweeping, the entry could be a dead object that
+ * has not yet been swept. */
+ if (!rb_objspace_garbage_object_p(subclass)) {
+ if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) {
+ // backfill an origin iclass to handle refinements and future prepends
+ rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass);
+ RCLASS_WRITE_M_TBL(subclass, klass_m_tbl);
+ VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(subclass));
+ rb_class_set_super(subclass, origin);
+ RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(subclass));
+ RCLASS_WRITE_ORIGIN(subclass, origin);
+ RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
+ }
+ include_modules_at(subclass, subclass, module, FALSE);
}
- include_modules_at(subclass, subclass, module, FALSE);
}
-
- iclass = iclass->next;
}
}
}
@@ -1554,7 +1976,7 @@ rb_mod_include_p(VALUE mod, VALUE mod2)
Check_Type(mod2, T_MODULE);
for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
- if (BUILTIN_TYPE(p) == T_ICLASS && !FL_TEST(p, RICLASS_IS_ORIGIN)) {
+ if (BUILTIN_TYPE(p) == T_ICLASS && !RICLASS_IS_ORIGIN_P(p)) {
if (METACLASS_OF(p) == mod2) return Qtrue;
}
}
@@ -1614,19 +2036,17 @@ class_descendants_recursive(VALUE klass, VALUE v)
{
struct subclass_traverse_data *data = (struct subclass_traverse_data *) v;
- if (BUILTIN_TYPE(klass) == T_CLASS && !RCLASS_SINGLETON_P(klass)) {
+ if (RB_TYPE_P(klass, T_ICLASS)) return; // skip refinement ICLASSes
+
+ if (!RCLASS_SINGLETON_P(klass)) {
if (data->buffer && data->count < data->maxcount && !rb_objspace_garbage_object_p(klass)) {
// assumes that this does not cause GC as long as the length does not exceed the capacity
rb_ary_push(data->buffer, klass);
}
data->count++;
- if (!data->immediate_only) {
- rb_class_foreach_subclass(klass, class_descendants_recursive, v);
- }
- }
- else {
- rb_class_foreach_subclass(klass, class_descendants_recursive, v);
+ if (data->immediate_only) return;
}
+ rb_class_foreach_subclass(klass, class_descendants_recursive, v);
}
static VALUE
@@ -2099,7 +2519,7 @@ rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
int recur = TRUE;
if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
- if (RCLASS_SINGLETON_P(obj)) {
+ if (RB_TYPE_P(obj, T_CLASS) && RCLASS_SINGLETON_P(obj)) {
rb_singleton_class(obj);
}
klass = CLASS_OF(obj);
@@ -2225,7 +2645,7 @@ rb_special_singleton_class(VALUE obj)
* consistency of the metaclass hierarchy.
*/
static VALUE
-singleton_class_of(VALUE obj)
+singleton_class_of(VALUE obj, bool ensure_eigenclass)
{
VALUE klass;
@@ -2253,27 +2673,43 @@ singleton_class_of(VALUE obj)
}
}
- klass = METACLASS_OF(obj);
- if (!(RCLASS_SINGLETON_P(klass) &&
- RCLASS_ATTACHED_OBJECT(klass) == obj)) {
- klass = rb_make_metaclass(obj, klass);
+ bool needs_lock = rb_multi_ractor_p() && rb_ractor_shareable_p(obj);
+ unsigned int lev;
+ if (needs_lock) {
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ }
+ {
+ klass = METACLASS_OF(obj);
+ if (!(RCLASS_SINGLETON_P(klass) &&
+ RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ klass = rb_make_metaclass(obj, klass);
+ }
+ RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
+ if (ensure_eigenclass && RB_TYPE_P(obj, T_CLASS)) {
+ /* ensures an exposed class belongs to its own eigenclass */
+ (void)ENSURE_EIGENCLASS(klass);
+ }
+ }
+ if (needs_lock) {
+ RB_VM_LOCK_LEAVE_LEV(&lev);
}
-
- RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
return klass;
}
void
-rb_freeze_singleton_class(VALUE x)
-{
- /* should not propagate to meta-meta-class, and so on */
- if (!RCLASS_SINGLETON_P(x)) {
- VALUE klass = RBASIC_CLASS(x);
- if (klass && // no class when hidden from ObjectSpace
- FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) {
- OBJ_FREEZE(klass);
- }
+rb_freeze_singleton_class(VALUE attached_object)
+{
+ VALUE klass;
+
+ /* Freeze singleton classes of singleton class, as singleton class is frozen, and so on */
+ /* In each iteration, check the current object's class pointer is the singleton class of the object. */
+ while ((klass = RBASIC_CLASS(attached_object)) &&
+ FL_TEST_RAW(klass, FL_SINGLETON) &&
+ !OBJ_FROZEN_RAW(klass) &&
+ (RCLASS_ATTACHED_OBJECT(klass) == attached_object)) {
+ attached_object = klass;
+ OBJ_FREEZE(attached_object);
}
}
@@ -2301,12 +2737,7 @@ rb_singleton_class_get(VALUE obj)
VALUE
rb_singleton_class(VALUE obj)
{
- VALUE klass = singleton_class_of(obj);
-
- /* ensures an exposed class belongs to its own eigenclass */
- if (RB_TYPE_P(obj, T_CLASS)) (void)ENSURE_EIGENCLASS(klass);
-
- return klass;
+ return singleton_class_of(obj, true);
}
/*!
@@ -2324,7 +2755,7 @@ rb_singleton_class(VALUE obj)
void
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
{
- rb_define_method(singleton_class_of(obj), name, func, argc);
+ rb_define_method(singleton_class_of(obj, false), name, func, argc);
}
#ifdef rb_define_module_function
diff --git a/common.mk b/common.mk
index a781b21c4a..916484a6fe 100644
--- a/common.mk
+++ b/common.mk
@@ -18,9 +18,10 @@ ECHO = @$(ECHO0)
mflags = $(MFLAGS)
gnumake_recursive =
+sequential = $(gnumake:yes=-sequential)
enable_shared = $(ENABLE_SHARED:no=)
-UNICODE_VERSION = 15.1.0
+UNICODE_VERSION = 17.0.0
UNICODE_EMOJI_VERSION_0 = $(UNICODE_VERSION)///
UNICODE_EMOJI_VERSION_1 = $(UNICODE_EMOJI_VERSION_0:.0///=)
UNICODE_EMOJI_VERSION = $(UNICODE_EMOJI_VERSION_1:///=)
@@ -43,10 +44,14 @@ RUBYLIB = $(PATH_SEPARATOR)
RUBYOPT = -
RUN_OPTS = --disable-gems
+GIT_IN_SRC = $(GIT) -C $(srcdir)
+GIT_LOG = $(GIT_IN_SRC) log --no-show-signature
+GIT_LOG_FORMAT = $(GIT_LOG) "--pretty=format:"
+
# 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$(ext_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(PRISM_SRCDIR) -I$(UNICODE_HDR_DIR) $(incflags)
GEM_HOME =
GEM_PATH =
@@ -64,13 +69,18 @@ LIBRUBY_EXTS = ./.libruby-with-ext.time
REVISION_H = ./.revision.time
PLATFORM_D = $(TIMESTAMPDIR)/.$(PLATFORM_DIR).time
ENC_TRANS_D = $(TIMESTAMPDIR)/.enc-trans.time
-RDOC = $(XRUBY) "$(tooldir)/rdoc-srcdir"
+yes_cross_compiling = $(CROSS_COMPILING:no=)
+X_$(CROSS_COMPILING:yes=)BASERUBY = $(BASERUBY)
+X_$(CROSS_COMPILING:no=)BASERUBY = $(XRUBY)
+RDOC = $(X_BASERUBY) --enable-gems "$(tooldir)/rdoc-srcdir"
RDOCOUT = $(EXTOUT)/rdoc
HTMLOUT = $(EXTOUT)/html
CAPIOUT = doc/capi
INSTALL_DOC_OPTS = --rdoc-output="$(RDOCOUT)" --html-output="$(HTMLOUT)"
RDOC_GEN_OPTS = --no-force-update \
+ --exclude '^lib/rubygems/core_ext/kernel_require\.rb$$' \
$(empty)
+RDOC_SERVER_PORT = 4000
INITOBJS = dmyext.$(OBJEXT) dmyenc.$(OBJEXT)
NORMALMAINOBJ = main.$(OBJEXT)
@@ -84,39 +94,54 @@ MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \
PRISM_BUILD_DIR = prism
-PRISM_FILES = prism/api_node.$(OBJEXT) \
- prism/api_pack.$(OBJEXT) \
+LIBPRISM_OBJS = \
+ prism/arena.$(OBJEXT) \
+ prism/buffer.$(OBJEXT) \
+ prism/char.$(OBJEXT) \
+ prism/constant_pool.$(OBJEXT) \
prism/diagnostic.$(OBJEXT) \
prism/encoding.$(OBJEXT) \
- prism/extension.$(OBJEXT) \
+ prism/integer.$(OBJEXT) \
+ prism/json.$(OBJEXT) \
+ prism/line_offset_list.$(OBJEXT) \
+ prism/list.$(OBJEXT) \
+ prism/memchr.$(OBJEXT) \
prism/node.$(OBJEXT) \
prism/options.$(OBJEXT) \
- prism/pack.$(OBJEXT) \
+ prism/parser.$(OBJEXT) \
prism/prettyprint.$(OBJEXT) \
+ prism/prism.$(OBJEXT) \
prism/regexp.$(OBJEXT) \
prism/serialize.$(OBJEXT) \
+ prism/source.$(OBJEXT) \
prism/static_literals.$(OBJEXT) \
- prism/token_type.$(OBJEXT) \
- prism/util/pm_buffer.$(OBJEXT) \
- prism/util/pm_char.$(OBJEXT) \
- prism/util/pm_constant_pool.$(OBJEXT) \
- prism/util/pm_integer.$(OBJEXT) \
- prism/util/pm_list.$(OBJEXT) \
- prism/util/pm_memchr.$(OBJEXT) \
- prism/util/pm_newline_list.$(OBJEXT) \
- prism/util/pm_string.$(OBJEXT) \
- prism/util/pm_strncasecmp.$(OBJEXT) \
- prism/util/pm_strpbrk.$(OBJEXT) \
- prism/prism.$(OBJEXT) \
+ prism/string_query.$(OBJEXT) \
+ prism/stringy.$(OBJEXT) \
+ prism/strncasecmp.$(OBJEXT) \
+ prism/strpbrk.$(OBJEXT) \
+ prism/tokens.$(OBJEXT)
+
+EXTPRISM_OBJS = prism/api_node.$(OBJEXT) \
+ prism/extension.$(OBJEXT) \
prism_init.$(OBJEXT)
-COMMONOBJS = array.$(OBJEXT) \
+PRISM_OBJS = $(LIBPRISM_OBJS) $(EXTPRISM_OBJS)
+
+# Prism objects depend on generated headers that are created from templates.
+# This must be declared here to ensure parallel builds don't compile prism
+# sources before the generated headers exist.
+$(LIBPRISM_OBJS): $(srcdir)/prism/ast.h $(srcdir)/prism/internal/diagnostic.h
+
+COMMONOBJS = \
+ array.$(OBJEXT) \
ast.$(OBJEXT) \
bignum.$(OBJEXT) \
+ box.$(OBJEXT) \
class.$(OBJEXT) \
compar.$(OBJEXT) \
compile.$(OBJEXT) \
complex.$(OBJEXT) \
+ concurrent_set.$(OBJEXT) \
cont.$(OBJEXT) \
debug.$(OBJEXT) \
debug_counter.$(OBJEXT) \
@@ -130,8 +155,8 @@ COMMONOBJS = array.$(OBJEXT) \
file.$(OBJEXT) \
gc.$(OBJEXT) \
hash.$(OBJEXT) \
- inits.$(OBJEXT) \
imemo.$(OBJEXT) \
+ inits.$(OBJEXT) \
io.$(OBJEXT) \
io_buffer.$(OBJEXT) \
iseq.$(OBJEXT) \
@@ -144,6 +169,7 @@ COMMONOBJS = array.$(OBJEXT) \
numeric.$(OBJEXT) \
object.$(OBJEXT) \
pack.$(OBJEXT) \
+ pathname.$(OBJEXT) \
parse.$(OBJEXT) \
parser_st.$(OBJEXT) \
proc.$(OBJEXT) \
@@ -162,6 +188,7 @@ COMMONOBJS = array.$(OBJEXT) \
ruby.$(OBJEXT) \
ruby_parser.$(OBJEXT) \
scheduler.$(OBJEXT) \
+ set.$(OBJEXT) \
shape.$(OBJEXT) \
signal.$(OBJEXT) \
sprintf.$(OBJEXT) \
@@ -182,98 +209,23 @@ COMMONOBJS = array.$(OBJEXT) \
vm_sync.$(OBJEXT) \
vm_trace.$(OBJEXT) \
weakmap.$(OBJEXT) \
- $(PRISM_FILES) \
+ $(PRISM_OBJS) \
$(YJIT_OBJ) \
- $(YJIT_LIBOBJ) \
+ $(ZJIT_OBJ) \
+ $(JIT_OBJ) \
+ $(RUST_LIBOBJ) \
$(COROUTINE_OBJ) \
$(DTRACE_OBJ) \
$(BUILTIN_ENCOBJS) \
$(BUILTIN_TRANSOBJS) \
$(MISSING)
-$(PRISM_FILES): $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time
+$(PRISM_OBJS): $(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/inspect_visitor.rb
-srcs: $(srcdir)/lib/prism/inspect_visitor.rb
-$(srcdir)/lib/prism/inspect_visitor.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/inspect_visitor.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/inspect_visitor.rb $(srcdir)/lib/prism/inspect_visitor.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/reflection.rb
-srcs: $(srcdir)/lib/prism/reflection.rb
-$(srcdir)/lib/prism/reflection.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/reflection.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/reflection.rb $(srcdir)/lib/prism/reflection.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/diagnostic.c
-prism/diagnostic.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/diagnostic.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/diagnostic.c $@
-
-srcs: prism/diagnostic.h
-prism/diagnostic.h: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/include/prism/diagnostic.h.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb include/prism/diagnostic.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) \
@@ -333,14 +285,18 @@ MAKE_LINK = $(MINIRUBY) -rfileutils -e "include FileUtils::Verbose" \
# For release builds
YJIT_RUSTC_ARGS = --crate-name=yjit \
- --crate-type=staticlib \
+ $(JIT_RUST_FLAGS) \
+ $(RUSTC_FLAGS) \
--edition=2021 \
- -g \
- -C lto=thin \
- -C opt-level=3 \
- -C overflow-checks=on \
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
- $(top_srcdir)/yjit/src/lib.rs
+ '$(top_srcdir)/yjit/src/lib.rs'
+
+ZJIT_RUSTC_ARGS = --crate-name=zjit \
+ $(JIT_RUST_FLAGS) \
+ $(RUSTC_FLAGS) \
+ --edition=2024 \
+ '--out-dir=$(CARGO_TARGET_DIR)/release/' \
+ '$(top_srcdir)/zjit/src/lib.rs'
all: $(SHOWFLAGS) main
@@ -366,6 +322,7 @@ showflags:
" MFLAGS = $(MFLAGS)" \
" RUSTC = $(RUSTC)" \
" YJIT_RUSTC_ARGS = $(YJIT_RUSTC_ARGS)" \
+ " ZJIT_RUSTC_ARGS = $(ZJIT_RUSTC_ARGS)" \
$(MESSAGE_END)
-@$(CC_VERSION)
@@ -390,12 +347,14 @@ $(EXTS_MK): ext/configure-ext.mk $(srcdir)/template/exts.mk.tmpl \
$(srcdir)/template/exts.mk.tmpl --gnumake=$(gnumake) --configure-exts=ext/configure-ext.mk
ext/configure-ext.mk: $(PREP) all-incs $(MKFILES) $(RBCONFIG) $(LIBRUBY) \
- $(srcdir)/template/configure-ext.mk.tmpl
+ $(srcdir)/template/configure-ext.mk.tmpl update-default-gemspecs \
+ $(HAVE_BASERUBY:yes=extract-gems)
$(ECHO) generating makefiles $@
$(Q)$(MAKEDIRS) $(@D)
$(Q)$(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ -c \
$(srcdir)/template/$(@F).tmpl --srcdir="$(srcdir)" \
- --miniruby="$(MINIRUBY)" --script-args='$(SCRIPT_ARGS)'
+ --miniruby="$(MINIRUBY)" --script-args='$(SCRIPT_ARGS)' \
+ $(yes_cross_compiling:yes=--without-ext=-test-)
configure-ext: $(EXTS_MK)
@@ -474,17 +433,19 @@ docs: srcs-doc $(DOCTARGETS)
pkgconfig-data: $(ruby_pc)
$(ruby_pc): $(srcdir)/template/ruby.pc.in config.status
+INSTALL_ALL = all
+
install-all: pre-install-all do-install-all post-install-all
pre-install-all:: all pre-install-local pre-install-ext pre-install-gem pre-install-doc
do-install-all: pre-install-all $(DOT_WAIT) docs
- $(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=all $(INSTALL_DOC_OPTS)
+ $(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=$(INSTALL_ALL) $(INSTALL_DOC_OPTS)
post-install-all:: post-install-local post-install-ext post-install-gem post-install-doc
@$(NULLCMD)
install-nodoc: pre-install-nodoc do-install-nodoc post-install-nodoc
pre-install-nodoc:: pre-install-local pre-install-ext pre-install-gem
do-install-nodoc: main pre-install-nodoc
- $(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=all --exclude=doc
+ $(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=$(INSTALL_ALL) --exclude=doc
post-install-nodoc:: post-install-local post-install-ext post-install-gem
install-local: pre-install-local do-install-local post-install-local
@@ -559,7 +520,7 @@ what-where-all: no-install-all
no-install-all: pre-no-install-all dont-install-all post-no-install-all
pre-no-install-all:: pre-no-install-local pre-no-install-ext pre-no-install-doc
dont-install-all: $(PROGRAM)
- $(INSTRUBY) -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=all $(INSTALL_DOC_OPTS)
+ $(INSTRUBY) -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=$(INSTALL_ALL) $(INSTALL_DOC_OPTS)
post-no-install-all:: post-no-install-local post-no-install-ext post-no-install-doc
@$(NULLCMD)
@@ -666,23 +627,33 @@ post-install-dbg::
srcs-doc: prepare-gems
-rdoc: PHONY main srcs-doc
+RDOC_DEPENDS = main srcs-doc
+rdoc: PHONY $(RDOC_DEPENDS) $(RBCONFIG) update-default-gemspecs
@echo Generating RDoc documentation
$(Q) $(RDOC) --ri --op "$(RDOCOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
-html: PHONY main srcs-doc
+html: PHONY $(RDOC_DEPENDS) $(RBCONFIG) update-default-gemspecs
@echo Generating RDoc HTML files
$(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
-rdoc-coverage: PHONY main srcs-doc
+html-server: PHONY $(RDOC_DEPENDS) $(RBCONFIG)
+ @echo Starting RDoc server with live reload
+ $(Q) $(RDOC) --server=$(RDOC_SERVER_PORT) $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
+
+RDOC_COVERAGE_EXCLUDES = -x ^ext/json -x ^ext/openssl -x ^ext/psych \
+ -x ^lib/bundler -x ^lib/rubygems \
+ -x ^lib/did_you_mean -x ^lib/error_highlight -x ^lib/syntax_suggest
+
+rdoc-coverage: PHONY $(RDOC_DEPENDS) $(RBCONFIG)
@echo Generating RDoc coverage report
- $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) "$(srcdir)"
+ $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) .
-undocumented: PHONY main srcs-doc
- $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) "$(srcdir)" | \
+undocumented: PHONY $(RDOC_DEPENDS) $(RBCONFIG)
+ $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) . | \
sed -n \
-e '/^ *# in file /{' -e 's///;N;s/\n/: /p' -e '}' \
- -e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p' | sort
+ -e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p' | \
+ sort -t: -k1,1 -k2n,2
RDOCBENCHOUT=/tmp/rdocbench
@@ -711,16 +682,20 @@ install-prereq: $(CLEAR_INSTALLED_LIST) yes-fake sudo-precheck PHONY
clear-installed-list: PHONY
@> $(INSTALLED_LIST) set MAKE="$(MAKE)"
+noarch_config_h = tmp/include/noarch/ruby/config.h
+
clean: clean-ext clean-enc clean-golf clean-docs clean-extout clean-modular-gc clean-local clean-platform clean-spec
clean-local:: clean-runnable
$(Q)$(RM) $(ALLOBJS) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
$(Q)$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) dmyenc.$(OBJEXT) $(ARCHFILE) .*.time
$(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) GNUmakefile.old Makefile.old $(arch)-fake.rb bisect.sh $(ENC_TRANS_D) builtin_binary.rbbin
$(Q)$(RM) $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/*/.time yjit_exit_locations.dump
- -$(Q)$(RMALL) yjit/target
- -$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit \
+ $(Q)$(RM) $(noarch_config_h)
+ -$(Q)$(RMALL) dump_ast$(BUILD_EXEEXT)*
+ -$(Q)$(RMALL) target
+ -$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine target \
$(PRISM_BUILD_DIR)/*/ $(PRISM_BUILD_DIR) tmp \
2> $(NULL) || $(NULLCMD)
@@ -751,7 +726,8 @@ distclean-local:: clean-local
$(Q)$(RM) config.cache config.status config.status.lineno
$(Q)$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP)
-$(Q)$(RMALL) $(srcdir)/autom4te.cache
-distclean-ext:: PHONY
+distclean-local:: distclean-srcs-local
+distclean-ext:: distclean-srcs-ext
distclean-golf: clean-golf
distclean-rdoc: clean-rdoc
distclean-html: clean-html
@@ -766,6 +742,7 @@ realclean:: realclean-ext realclean-local realclean-enc realclean-golf realclean
realclean-local:: distclean-local realclean-srcs-local
clean-srcs:: clean-srcs-local clean-srcs-ext
+distclean-srcs:: distclean-srcs-local distclean-srcs-ext
realclean-srcs:: realclean-srcs-local realclean-srcs-ext
clean-srcs-local::
@@ -773,14 +750,18 @@ clean-srcs-local::
$(Q)$(RM) id.c id.h probes.dmyh probes.h
$(Q)$(RM) encdb.h transdb.h verconf.h ruby-runner.h
-realclean-srcs-local:: clean-srcs-local
+distclean-srcs-local:: clean-srcs-local
+
+realclean-srcs-local:: distclean-srcs-local
$(Q)$(CHDIR) $(srcdir) && $(RM) \
parse.c parse.h lex.c enc/trans/newline.c $(PRELUDES) revision.h \
- id.c id.h probes.dmyh configure aclocal.m4 tool/config.guess tool/config.sub gems/*.gem \
+ id.c id.h probes.dmyh configure aclocal.m4 tool/config.guess tool/config.sub \
+ $(PRISM_SRCDIR)/srcs.mk gems/*.gem \
|| $(NULLCMD)
clean-srcs-ext::
-realclean-srcs-ext:: clean-srcs-ext
+distclean-srcs-ext:: clean-srcs-ext
+realclean-srcs-ext:: distclean-srcs-ext
realclean-ext:: PHONY
realclean-golf: distclean-golf
@@ -808,7 +789,7 @@ timestamp/distclean:: ext/distclean .bundle/distclean
timestamp/realclean:: ext/realclean .bundle/realclean
timestamp/clean timestamp/distclean timestamp/realclean::
- $(Q)$(RM) $(TIMESTAMPDIR)/.*.time $(TIMESTAMPDIR)/$(arch)/.time
+ $(Q)$(RM) $(TIMESTAMPDIR)/*.time $(TIMESTAMPDIR)/.*.time $(TIMESTAMPDIR)/$(arch)/.time
$(Q)$(RMDIRS) $(TIMESTAMPDIR)/$(arch) $(TIMESTAMPDIR) 2> $(NULL) || $(NULLCMD)
clean-ext::
@@ -840,9 +821,19 @@ clean-capi distclean-capi realclean-capi:
clean-platform distclean-platform realclean-platform:
$(Q) $(RM) $(PLATFORM_D)
- -$(Q) $(RMDIR) $(PLATFORM_DIR) 2> $(NULL) || $(NULLCMD)
+ -$(Q) $(RMDIR) $(PLATFORM_DIR) $(TIMESTAMPDIR) 2> $(NULL) || $(NULLCMD)
RUBYSPEC_CAPIEXT = spec/ruby/optional/capi/ext
+RUBYSPEC_CAPIEXT_SRCDIR = $(srcdir)/$(RUBYSPEC_CAPIEXT)
+RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) {$(VPATH)}internal/abi.h $(LIBRUBY)
+RUBYSPEC_CAPIEXT_BUILD = $(enable_shared:yes=rubyspec-capiext)
+
+yes-rubyspec-capiext: build-ext
+ $(ACTIONS_GROUP)
+rubyspec-capiext: build-ext $(DOT_WAIT) yes-rubyspec-capiext $(DOT_WAIT)
+ $(ACTIONS_ENDGROUP)
+# make-dependent rules should be included after this and built after build-ext.
+
clean-spec: PHONY
-$(Q) $(RM) $(RUBYSPEC_CAPIEXT)/*.$(OBJEXT) $(RUBYSPEC_CAPIEXT)/*.$(DLEXT)
-$(Q) $(RMDIRS) $(RUBYSPEC_CAPIEXT) 2> $(NULL) || $(NULLCMD)
@@ -875,6 +866,12 @@ $(arch:noarch=ignore)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_
i=- srcdir="$(srcdir)" BASERUBY="$(BASERUBY)" \
LIBPATHENV="$(LIBPATHENV)" PRELOADENV="$(PRELOADENV)" LIBRUBY_SO="$(LIBRUBY_SO)"
+# dummy file for generating sources; $(arch_hdrdir)/ruby/config.h with prereq.status.
+$(noarch_config_h):
+ $(ECHO) generating dummy config.h
+ $(Q) $(MAKEDIRS) $(@D)
+ $(Q) $(TOUCH) $@
+
noarch-fake.rb: # prerequisite of yes-fake
$(Q) exit > $@
@@ -930,7 +927,7 @@ no-test-testframework: PHONY
test-tool: $(TEST_RUNNABLE)-test-tool
yes-test-tool: prog PHONY
$(ACTIONS_GROUP)
- $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS)
+ $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS) $(TESTS)
$(ACTIONS_ENDGROUP)
no-test-tool: PHONY
@@ -941,7 +938,7 @@ test: test-short
# Separate to skip updating encs and exts by `make -o test-precheck`
# for GNU make.
test-precheck: $(ENCSTATIC:static=lib)encs exts PHONY $(DOT_WAIT)
-yes-test-all-precheck: programs $(DOT_WAIT) test-precheck
+yes-test-all-precheck: programs $(DOT_WAIT) test-precheck yes-fake
PRECHECK_TEST_ALL = yes-test-all-precheck
@@ -978,24 +975,20 @@ rbconfig.rb: $(RBCONFIG)
$(HAVE_BASERUBY:no=)$(RBCONFIG)$(HAVE_BASERUBY:no=): $(PREP)
$(RBCONFIG): $(tooldir)/mkconfig.rb config.status $(srcdir)/version.h $(srcdir)/common.mk
- $(Q)$(BOOTSTRAPRUBY) -n \
- -e 'BEGIN{version=ARGV.shift;mis=ARGV.dup}' \
- -e 'END{abort "UNICODE version mismatch: #{mis}" unless mis.empty?}' \
- -e '(mis.delete(ARGF.path); ARGF.close) if /ONIG_UNICODE_VERSION_STRING +"#{Regexp.quote(version)}"/o' \
- $(UNICODE_VERSION) $(UNICODE_DATA_HEADERS)
+
+$(RBCONFIG):
$(Q)$(BOOTSTRAPRUBY) $(tooldir)/mkconfig.rb \
-arch=$(arch) -version=$(RUBY_PROGRAM_VERSION) \
-install_name=$(RUBY_INSTALL_NAME) \
-so_name=$(RUBY_SO_NAME) \
-unicode_version=$(UNICODE_VERSION) \
-unicode_emoji_version=$(UNICODE_EMOJI_VERSION) \
- > rbconfig.tmp
- $(IFCHANGE) "--timestamp=$@" rbconfig.rb rbconfig.tmp
+ | $(IFCHANGE) "--timestamp=$@" rbconfig.rb -
test-rubyspec: test-spec
yes-test-rubyspec: yes-test-spec
-yes-test-spec-precheck: yes-test-all-precheck yes-fake
+yes-test-spec-precheck: yes-test-all-precheck $(RUBYSPEC_CAPIEXT_BUILD)
test-spec: $(TEST_RUNNABLE)-test-spec
yes-test-spec: yes-test-spec-precheck
@@ -1045,8 +1038,11 @@ $(ENC_MK): $(srcdir)/enc/make_encmake.rb $(srcdir)/enc/Makefile.in $(srcdir)/enc
.PHONY: test install install-nodoc install-doc dist
.PHONY: loadpath golf capi rdoc install-prereq clear-installed-list
.PHONY: clean clean-ext clean-local clean-enc clean-golf clean-rdoc clean-html clean-extout
+.PHONY: clean-srcs clean-srcs-local clean-srcs-ext
.PHONY: distclean distclean-ext distclean-local distclean-enc distclean-golf distclean-extout
+.PHONY: distclean-srcs distclean-srcs-local distclean-srcs-ext
.PHONY: realclean realclean-ext realclean-local realclean-enc realclean-golf realclean-extout
+.PHONY: realclean-srcs realclean-srcs-local realclean-srcs-ext
.PHONY: exam check test test-short test-all btest btest-ruby test-basic test-knownbug
.PHONY: run runruby parse benchmark gdb gdb-ruby
.PHONY: update-mspec update-rubyspec test-rubyspec test-spec
@@ -1162,7 +1158,7 @@ $(NEWLINE_C): $(srcdir)/enc/trans/newline.trans $(tooldir)/transcode-tblgen.rb
$(Q) $(BASERUBY) "$(tooldir)/transcode-tblgen.rb" -vo $@ $(srcdir)/enc/trans/newline.trans
enc/trans/newline.$(OBJEXT): $(NEWLINE_C)
-verconf.h: $(srcdir)/template/verconf.h.tmpl $(tooldir)/generic_erb.rb $(RBCONFIG)
+verconf.h: $(srcdir)/template/verconf.h.tmpl $(tooldir)/generic_erb.rb rbconfig.rb
$(ECHO) creating $@
$(Q) $(BOOTSTRAPRUBY) "$(tooldir)/generic_erb.rb" -o $@ $(srcdir)/template/verconf.h.tmpl
@@ -1181,10 +1177,12 @@ $(srcs_vpath)insns.inc: $(tooldir)/ruby_vm/views/insns.inc.erb $(inc_common_head
$(srcs_vpath)insns_info.inc: $(tooldir)/ruby_vm/views/insns_info.inc.erb $(inc_common_headers) \
$(tooldir)/ruby_vm/views/_insn_type_chars.erb $(tooldir)/ruby_vm/views/_insn_name_info.erb \
$(tooldir)/ruby_vm/views/_insn_len_info.erb $(tooldir)/ruby_vm/views/_insn_operand_info.erb \
- $(tooldir)/ruby_vm/views/_attributes.erb $(tooldir)/ruby_vm/views/_comptime_insn_stack_increase.erb
+ $(tooldir)/ruby_vm/views/_attributes.erb $(tooldir)/ruby_vm/views/_comptime_insn_stack_increase.erb \
+ $(tooldir)/ruby_vm/views/_zjit_helpers.erb $(tooldir)/ruby_vm/views/_insn_leaf_info.erb
$(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
+ $(tooldir)/ruby_vm/views/_insn_entry.erb $(tooldir)/ruby_vm/views/_trace_instruction.erb \
+ $(tooldir)/ruby_vm/views/_zjit_instruction.erb
BUILTIN_RB_SRCS = \
$(srcdir)/ast.rb \
@@ -1199,6 +1197,7 @@ BUILTIN_RB_SRCS = \
$(srcdir)/array.rb \
$(srcdir)/hash.rb \
$(srcdir)/kernel.rb \
+ $(srcdir)/pathname_builtin.rb \
$(srcdir)/ractor.rb \
$(srcdir)/symbol.rb \
$(srcdir)/timev.rb \
@@ -1206,8 +1205,10 @@ BUILTIN_RB_SRCS = \
$(srcdir)/nilclass.rb \
$(srcdir)/prelude.rb \
$(srcdir)/gem_prelude.rb \
+ $(srcdir)/jit_hook.rb \
+ $(srcdir)/jit_undef.rb \
$(srcdir)/yjit.rb \
- $(srcdir)/yjit_hook.rb \
+ $(srcdir)/zjit.rb \
$(empty)
BUILTIN_RB_INCS = $(BUILTIN_RB_SRCS:.rb=.rbinc)
@@ -1258,7 +1259,6 @@ incs: $(INSNS) {$(VPATH)}node_name.inc {$(VPATH)}known_errors.inc \
{$(VPATH)}vm_call_iseq_optimized.inc $(srcdir)/revision.h \
$(REVISION_H) \
$(UNICODE_DATA_HEADERS) $(ENC_HEADERS) \
- $(srcs_vpath)prism/ast.h $(srcs_vpath)prism/diagnostic.h \
{$(VPATH)}id.h {$(VPATH)}probes.dmyh
insns: $(INSNS)
@@ -1321,21 +1321,36 @@ preludes: {$(VPATH)}miniprelude.c
{$(srcdir)}.rb.rbbin:
$(ECHO) making $@
- $(Q) $(MINIRUBY) $(tooldir)/mk_rbbin.rb $< > $@
+ $(Q) $(MINIRUBY) $(tooldir)/mk_rbbin.rb $(SRC_FILE) > $(OS_DEST_FILE)
-{$(srcdir)}.rb.rbinc:
+{$(srcdir)}.rb.$(HAVE_BASERUBY:yes=)rbinc:
$(ECHO) making $@
- $(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $<
+ $(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $(DUMP_AST) $(SRC_FILE)
-$(BUILTIN_BINARY:yes=built)in_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.inc.tmpl
+$(BUILTIN_BINARY:yes=built)in_binary.rbbin: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.rbbin.tmpl
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ \
- $(srcdir)/template/builtin_binary.inc.tmpl
+ $(srcdir)/template/builtin_binary.rbbin.tmpl
-$(Q) sha256sum $@ 2> $(NULL) || $(NULLCMD)
-$(BUILTIN_BINARY:no=builtin)_binary.inc:
+$(BUILTIN_BINARY:no=builtin)_binary.rbbin:
$(Q) echo> $@ // empty $(@F)
-$(BUILTIN_RB_INCS): $(top_srcdir)/tool/mk_builtin_loader.rb
+$(BUILTIN_RB_INCS): $(tooldir)/mk_builtin_loader.rb $(DUMP_AST_TARGET)
+
+dump_ast$(BUILD_EXEEXT): $(tooldir)/dump_ast.c $(LIBPRISM_OBJS)
+ $(ECHO) compiling $@
+ $(Q) $(CC) $(CFLAGS) $(OUTFLAG)$@ $(INCFLAGS) $(tooldir)/dump_ast.c $(LIBPRISM_OBJS)
+
+build-tool/Makefile: $(tooldir)/dump_ast.mkmf.rb prism-srcs prism-incs
+ +$(BASERUBY) -s $(tooldir)/dump_ast.mkmf.rb "-INCFLAGS=$(INCFLAGS)" "-make=$(MAKE)" build-tool $(tooldir)/dump_ast.c dump_ast.$(OBJEXT) $(LIBPRISM_OBJS)
+
+build-tool/dump_ast$(BUILD_EXEEXT): build-tool/Makefile
+ cd build-tool && MAKEFLAGS= MFLAGS= && unset MAKEFLAGS MFLAGS && $(MAKE)
+
+clean-local:: clean-build-tool
+clean-build-tool:
+ - cd build-tool && $(MAKE) clean 2> $(NULL) || $(NULLCMD)
+ - $(RMDIR) build-tool
$(srcdir)/revision.h$(no_baseruby:no=~disabled~): $(REVISION_H)
@@ -1347,9 +1362,15 @@ $(REVISION_H)$(yes_baseruby:yes=~disabled~):
# uncommon.mk: $(REVISION_H)
# $(MKFILES): $(REVISION_H)
+# $(common_mk_includes) is set by config.status or GNUmakefile
+common_mk__$(gnumake:yes=artifact)_ = uncommon.mk
+common_mk_$(gnumake)_artifact_ = $(MKFILES)
+$(common_mk__artifact_): $(srcdir)/common.mk $(common_mk_includes)
+
ripper_srcs: $(RIPPER_SRCS)
$(RIPPER_SRCS): $(srcdir)/parse.y $(srcdir)/defs/id.def
+$(RIPPER_SRCS): $(srcdir)/ext/ripper/depend $(srcdir)/ext/ripper/extconf.rb
$(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
$(ECHO) generating $@
@@ -1400,8 +1421,8 @@ run: yes-fake miniruby$(EXEEXT) PHONY
runruby: $(PROGRAM) PHONY
RUBY_ON_BUG='gdb -x $(srcdir)/.gdbinit -p' $(RUNRUBY) $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
-runirb: $(PROGRAM) PHONY
- RUBY_ON_BUG='gdb -x $(srcdir)/.gdbinit -p' $(RUNRUBY) $(RUNOPT0) -r irb -e 'IRB.start("make runirb")' $(RUNOPT)
+runirb: $(PROGRAM) update-default-gemspecs
+ RUBY_ON_BUG='gdb -x $(srcdir)/.gdbinit -p' $(RUNRUBY) $(RUNOPT0) -rrubygems -r irb -e 'IRB.start("make runirb")' $(RUNOPT)
parse: yes-fake miniruby$(EXEEXT) PHONY
$(BTESTRUBY) --dump=parsetree_with_comment,insns $(TESTRUN_SCRIPT)
@@ -1469,7 +1490,7 @@ dist:
up:: update-remote
up$(DOT_WAIT)::
- -$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= after-update
+ -$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= MINIRUBY=$(BASERUBY) after-update
yes::
no::
@@ -1478,6 +1499,7 @@ after-update:: common-srcs
after-update:: $(REVISION_H)
after-update:: extract-extlibs
after-update:: extract-gems
+after-update:: update-default-gemspecs
update-src::
$(Q) $(RM) $(REVISION_H) revision.h "$(srcdir)/$(REVISION_H)" "$(srcdir)/revision.h"
@@ -1500,15 +1522,21 @@ update-coverage: main PHONY
--install-dir .bundle --conservative "simplecov"
refresh-gems: update-bundled_gems prepare-gems
+# can't recall exactly, but `make` somewhere (not GNU or nmake)
+# couldn't handle spaces in replacement strings; i.e.,
+# `$(HAVE_BASERUBY:yes=word word ...)` didn't work.
prepare-gems: $(HAVE_BASERUBY:yes=update-gems) $(HAVE_BASERUBY:yes=extract-gems)
-extract-gems: $(HAVE_BASERUBY:yes=update-gems)
+extract-gems: $(HAVE_BASERUBY:yes=update-gems) $(HAVE_BASERUBY:yes=outdate-bundled-gems)
+update-gems: $(HAVE_BASERUBY:yes=outdate-bundled-gems)
-update-gems$(gnumake:yes=-sequential): PHONY
+split_option = -F"\s+|$(HASH_SIGN).*"
+
+update-gems$(sequential): PHONY
$(ECHO) Downloading bundled gem files...
$(Q) $(BASERUBY) -C "$(srcdir)" \
- -I./tool -rdownloader -answ \
+ -I./tool -rdownloader $(split_option) -answ \
-e 'gem, ver = *$$F' \
- -e 'next if !ver or /^#/=~gem' \
+ -e 'next if !ver' \
-e 'old = Dir.glob("gems/#{gem}-*.gem")' \
-e 'gem = "#{gem}-#{ver}.gem"' \
-e 'Downloader::RubyGems.download(gem, "gems", nil) and' \
@@ -1517,13 +1545,13 @@ update-gems$(gnumake:yes=-sequential): PHONY
-e 'FileUtils.rm_rf(old.map{'"|n|"'n.chomp(".gem")})' \
gems/bundled_gems
-extract-gems$(gnumake:yes=-sequential): PHONY
+extract-gems$(sequential): PHONY
$(ECHO) Extracting bundled gem files...
$(Q) $(BASERUBY) -C "$(srcdir)" \
- -Itool/lib -rfileutils -rbundled_gem -answ \
+ -Itool/lib -rfileutils -rbundled_gem $(split_option) -answ \
-e 'BEGIN {d = ".bundle/gems"}' \
-e 'gem, ver, _, rev = *$$F' \
- -e 'next if !ver or /^#/=~gem' \
+ -e 'next if !ver' \
-e 'g = "#{gem}-#{ver}"' \
-e 'unless File.directory?("#{d}/#{g}")' \
-e 'if rev and File.exist?(gs = "gems/src/#{gem}/#{gem}.gemspec")' \
@@ -1533,20 +1561,9 @@ extract-gems$(gnumake:yes=-sequential): PHONY
-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
+extract-gems$(sequential): $(HAVE_GIT:yes=clone-bundled-gems-src)
+flush-gems: outdate-bundled-gems
outdate-bundled-gems: PHONY
$(Q) $(BASERUBY) $(tooldir)/$@.rb --make="$(MAKE)" --mflags="$(MFLAGS)" \
--ruby-platform=$(arch) --ruby-version=$(ruby_version) \
@@ -1557,35 +1574,21 @@ update-bundled_gems: PHONY
$(tooldir)/update-bundled_gems.rb \
"$(srcdir)/gems/bundled_gems" | \
$(IFCHANGE) "$(srcdir)/gems/bundled_gems" -
- $(GIT) -C "$(srcdir)" diff --no-ext-diff --ignore-submodules --exit-code || \
- $(GIT) -C "$(srcdir)" commit -m "Update bundled_gems" gems/bundled_gems
+ $(GIT_IN_SRC) diff --no-ext-diff --ignore-submodules --exit-code || \
+ $(GIT_IN_SRC) commit -m "Update bundled_gems" gems/bundled_gems
PRECHECK_BUNDLED_GEMS = yes
test-bundled-gems-precheck: $(TEST_RUNNABLE)-test-bundled-gems-precheck
yes-test-bundled-gems-precheck: $(PRECHECK_BUNDLED_GEMS:yes=main)
no-test-bundled-gems-precheck:
-update-default-gemspecs: $(TEST_RUNNABLE)-update-default-gemspecs
-no-update-default-gemspecs:
-yes-update-default-gemspecs: $(PRECHECK_BUNDLED_GEMS:yes=main)
+yes-update-default-gemspecs no-update-default-gemspecs: update-default-gemspecs
+update-default-gemspecs: $(PREP) $(RBCONFIG)
@$(MAKEDIRS) $(srcdir)/.bundle/specifications
- @$(XRUBY) -W0 -C "$(srcdir)" -rrubygems \
- -e "destdir = ARGV.shift" \
- -e "ARGV.each do |basedir|" \
- -e "Dir.glob(basedir+'/**/*.gemspec') do |g|" \
- -e "dir, base = File.split(g)" \
- -e "spec = Dir.chdir(dir) {Gem::Specification.load(base)} ||" \
- -e "Gem::Specification.load(g)" \
- -e "unless spec" \
- -e "puts %[Ignoring #{g}]" \
- -e "next" \
- -e "end" \
- -e "spec.files.clear" \
- -e "spec.extensions.clear" \
- -e "File.binwrite(File.join(destdir, spec.full_name+'.gemspec'), spec.to_ruby)" \
- -e "end" \
- -e "end" \
- -- .bundle/specifications lib ext
+ $(Q)$(MINIRUBY) -W0 -C "$(srcdir)" -I tool/lib -roptparse -routput -rbundled_gem \
+ -e "(out = Output.new).def_options(ARGV.options)" \
+ -e "BundledGem.update_default_gemspecs(ARGV.parse!, out, quiet: $(V).zero?)" \
+ -- -c -o .bundle/specifications lib ext
install-for-test-bundled-gems: $(TEST_RUNNABLE)-install-for-test-bundled-gems
no-install-for-test-bundled-gems: no-update-default-gemspecs
@@ -1593,11 +1596,15 @@ yes-install-for-test-bundled-gems: yes-update-default-gemspecs
$(XRUBY) -C "$(srcdir)" -r./tool/lib/gem_env.rb bin/gem \
install --no-document --conservative \
"hoe" "json-schema:5.1.0" "test-unit-rr" "simplecov" "simplecov-html" "simplecov-json" "rspec" "zeitwerk" \
- "sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer"
+ "sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer" "minitest-mock"
test-bundled-gems-fetch: yes-test-bundled-gems-fetch
-yes-test-bundled-gems-fetch:
- $(Q) $(BASERUBY) -C $(srcdir)/gems ../tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" src bundled_gems
+yes-test-bundled-gems-fetch: clone-bundled-gems-src
+clone-bundled-gems-src: PHONY $(TIMESTAMPDIR)/bundled-gems-src.time
+$(TIMESTAMPDIR)/bundled-gems-src.time: $(srcdir)/gems/bundled_gems
+ $(Q) $(MAKEDIRS) $(@D)
+ $(Q) $(BASERUBY) -C $(srcdir) tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" gems/src gems/bundled_gems
+ $(Q) $(TOUCH) $@
no-test-bundled-gems-fetch:
test-bundled-gems-prepare: $(TEST_RUNNABLE)-test-bundled-gems-prepare
@@ -1631,7 +1638,7 @@ yes-test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS)
no-test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS)
test-bundled-gems-spec: $(TEST_RUNNABLE)-test-bundled-gems-spec
-yes-test-bundled-gems-spec: yes-test-spec-precheck $(PREPARE_BUNDLED_GEMS)
+yes-test-bundled-gems-spec: yes-test-all-precheck $(PREPARE_BUNDLED_GEMS)
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
$(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
@@ -1645,6 +1652,11 @@ test-syntax-suggest:
check: $(DOT_WAIT) $(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
+RAKER = $(XRUBY) -I$(srcdir)/gems/lib$(PATH_SEPARATOR)$(srcdir)/.bundle/lib \
+ -rrubygems $(srcdir)/.bundle/bin/rake
+rake:
+ $(RAKER) $(RAKE_OPTS) $(RAKE)
+
test-bundler-precheck: $(TEST_RUNNABLE)-test-bundler-precheck
no-test-bundler-precheck:
yes-test-bundler-precheck: main $(arch)-fake.rb
@@ -1654,12 +1666,8 @@ 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)
- $(XRUBY) -C $(srcdir) -Ilib \
- -e 'ENV["GEM_HOME"] = File.expand_path(".bundle")' \
- -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
+ $(XRUBY) -C $(srcdir) -Ilib -r./tool/lib/bundle_env.rb \
+ spec/bin/bundle install --quiet --gemfile=tool/bundler/dev_gems.rb
$(ACTIONS_ENDGROUP)
RSPECOPTS = -r formatter_overrides
@@ -1667,10 +1675,12 @@ BUNDLER_SPECS =
PREPARE_BUNDLER = $(TEST_RUNNABLE)-test-bundler-prepare
test-bundler: $(TEST_RUNNABLE)-test-bundler
yes-test-bundler: $(PREPARE_BUNDLER)
- $(gnumake_recursive)$(XRUBY) \
+ $(gnumake_recursive)$(XRUBY) --enable-gems \
-r./$(arch)-fake \
- -e "exec(*ARGV)" -- \
- $(XRUBY) -C $(srcdir) -Ispec/bundler -Ispec/lib .bundle/bin/rspec \
+ -r$(tooldir)/lib/_tmpdir \
+ -I$(srcdir)/spec/bundler -I$(srcdir)/spec/lib \
+ -e "Dir.chdir(ARGV.shift); load('spec/bin/rspec')" \
+ -s -- -no-report-tmpdir -- "$(srcdir)" \
-r spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
no-test-bundler:
@@ -1679,11 +1689,13 @@ test-bundler-parallel: $(TEST_RUNNABLE)-test-bundler-parallel
yes-test-bundler-parallel: $(PREPARE_BUNDLER)
$(gnumake_recursive)$(XRUBY) \
-r./$(arch)-fake \
+ -r$(tooldir)/lib/_tmpdir \
-I$(srcdir)/spec/bundler \
-e "ruby = ENV['RUBY']" \
-e "ARGV[-1] = File.expand_path(ARGV[-1])" \
-e "ENV['RSPEC_EXECUTABLE'] = ruby + ARGV.shift" \
-e "load ARGV.shift" \
+ -s -- -no-report-tmpdir -- \
" -C $(srcdir) -Ispec/bundler -Ispec/lib .bundle/bin/rspec -r spec_helper" \
$(srcdir)/spec/bin/parallel_rspec $(RSPECOPTS) \
$(PARALLELRSPECOPTS) $(srcdir)/spec/bundler/$(BUNDLER_SPECS)
@@ -1706,7 +1718,7 @@ UNICODE_FILES = $(UNICODE_SRC_DATA_DIR)/UnicodeData.txt \
$(UNICODE_SRC_DATA_DIR)/SpecialCasing.txt \
$(empty)
-UNICODE_PROPERTY_FILES = \
+UNICODE_PROPERTY_FILES = \
$(UNICODE_SRC_DATA_DIR)/Blocks.txt \
$(UNICODE_SRC_DATA_DIR)/DerivedAge.txt \
$(UNICODE_SRC_DATA_DIR)/DerivedCoreProperties.txt \
@@ -1716,7 +1728,7 @@ UNICODE_PROPERTY_FILES = \
$(UNICODE_SRC_DATA_DIR)/Scripts.txt \
$(empty)
-UNICODE_AUXILIARY_FILES = \
+UNICODE_AUXILIARY_FILES = \
$(UNICODE_SRC_DATA_DIR)/auxiliary/GraphemeBreakProperty.txt \
$(UNICODE_SRC_DATA_DIR)/auxiliary/GraphemeBreakTest.txt \
$(empty)
@@ -1757,34 +1769,50 @@ UNICODE_UCD_EMOJI_DOWNLOAD = \
UNICODE_EMOJI_DOWNLOAD = \
$(UNICODE_DOWNLOADER) \
-d $(UNICODE_SRC_EMOJI_DATA_DIR) \
- -p emoji/$(UNICODE_EMOJI_VERSION)
+ -p $(UNICODE_VERSION)/emoji
-update-unicode-files: $(UNICODE_FILES) $(UNICODE_PROPERTY_FILES)
-$(UNICODE_FILES) $(UNICODE_PROPERTY_FILES):
+update-unicode-files:
$(ECHO) Downloading Unicode $(UNICODE_VERSION) data and property files...
$(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)"
$(Q) $(UNICODE_DOWNLOAD) $(UNICODE_FILES) $(UNICODE_PROPERTY_FILES)
-update-unicode-auxiliary-files: $(UNICODE_AUXILIARY_FILES)
-$(UNICODE_AUXILIARY_FILES):
+update-unicode-auxiliary-files:
$(ECHO) Downloading Unicode $(UNICODE_VERSION) auxiliary files...
$(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)/auxiliary"
$(Q) $(UNICODE_AUXILIARY_DOWNLOAD) $(UNICODE_AUXILIARY_FILES)
-update-unicode-ucd-emoji-files: $(UNICODE_UCD_EMOJI_FILES)
-$(UNICODE_UCD_EMOJI_FILES):
+update-unicode-ucd-emoji-files:
$(ECHO) Downloading Unicode UCD emoji $(UNICODE_EMOJI_VERSION) files...
$(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)/emoji"
$(Q) $(UNICODE_UCD_EMOJI_DOWNLOAD) $(UNICODE_UCD_EMOJI_FILES)
-update-unicode-emoji-files: $(UNICODE_EMOJI_FILES)
-$(UNICODE_EMOJI_FILES):
+update-unicode-emoji-files:
$(ECHO) Downloading Unicode emoji $(UNICODE_EMOJI_VERSION) files...
$(Q) $(MAKEDIRS) "$(UNICODE_SRC_EMOJI_DATA_DIR)"
$(Q) $(UNICODE_EMOJI_DOWNLOAD) $(UNICODE_EMOJI_FILES)
-$(srcdir)/lib/unicode_normalize/tables.rb: \
- $(UNICODE_SRC_DATA_DIR)/$(HAVE_BASERUBY:yes=.unicode-tables.time)
+$(UNICODE_FILES) $(UNICODE_PROPERTY_FILES):
+ $(ECHO) Downloading Unicode $(UNICODE_VERSION) data and property files...
+ $(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)"
+ $(Q) $(UNICODE_DOWNLOAD) $@
+
+$(UNICODE_AUXILIARY_FILES):
+ $(ECHO) Downloading Unicode $(UNICODE_VERSION) auxiliary files...
+ $(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)/auxiliary"
+ $(Q) $(UNICODE_AUXILIARY_DOWNLOAD) $@
+
+$(UNICODE_UCD_EMOJI_FILES):
+ $(ECHO) Downloading Unicode UCD emoji $(UNICODE_EMOJI_VERSION) files...
+ $(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)/emoji"
+ $(Q) $(UNICODE_UCD_EMOJI_DOWNLOAD) $@
+
+$(UNICODE_EMOJI_FILES):
+ $(ECHO) Downloading Unicode emoji $(UNICODE_EMOJI_VERSION) files...
+ $(Q) $(MAKEDIRS) "$(UNICODE_SRC_EMOJI_DATA_DIR)"
+ $(Q) $(UNICODE_EMOJI_DOWNLOAD) $@
+
+$(srcdir)/lib/unicode_normalize/$(HAVE_BASERUBY:yes=tables.rb): \
+ $(UNICODE_SRC_DATA_DIR)/.unicode-tables.time
$(UNICODE_SRC_DATA_DIR)/$(ALWAYS_UPDATE_UNICODE:yes=.unicode-tables.time): \
$(UNICODE_FILES) $(UNICODE_PROPERTY_FILES) \
@@ -1835,11 +1863,11 @@ $(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): \
+srcs-doc: $(srcdir)/doc/language/regexp/unicode_properties.rdoc
+$(srcdir)/doc/language/regexp/$(ALWAYS_UPDATE_UNICODE:yes=unicode_properties.rdoc): \
$(UNICODE_HDR_DIR)/name2ctype.h $(UNICODE_PROPERTY_FILES)
-$(srcdir)/doc/regexp/unicode_properties.rdoc:
+$(srcdir)/doc/language/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 || \
@@ -1876,6 +1904,9 @@ clean-gems:
CLEAN_CACHE = clean-extlibs
+prepare-package: prereq after-update
+clean-cache: $(CLEAN_CACHE)
+
info: info-program info-libruby_a info-libruby_so info-arch
info-program: PHONY
@echo PROGRAM=$(PROGRAM)
@@ -1902,9 +1933,9 @@ sudo-precheck: PHONY
@$(SUDO) echo > $(NULL)
update-man-date: PHONY
- -$(Q) $(BASERUBY) -I"$(tooldir)/lib" -rvcs -i -p \
+ $(Q) $(BASERUBY) -I"$(tooldir)/lib" -rvcs -i -p \
-e 'BEGIN{@vcs=VCS.detect(ARGV.shift)}' \
- -e '$$_.sub!(/^(\.Dd ).*/){$$1+@vcs.modified(ARGF.path).strftime("%B %d, %Y")}' \
+ -e '$$_.sub!(/^(\.Dd ).*/){$$1+@vcs.author_date(@vcs.relative_to(ARGF.path)).strftime("%B %d, %Y")}' \
"$(srcdir)" "$(srcdir)"/man/*.1
.PHONY: ChangeLog
@@ -1927,8 +1958,8 @@ nightly: yesterday $(DOT_WAIT) install
yesterday: rewindable
rewindable:
- $(GIT) -C $(srcdir) status --porcelain
- $(GIT) -C $(srcdir) diff --quiet
+ $(GIT_IN_SRC) status --porcelain
+ $(GIT_IN_SRC) diff --quiet
HELP_EXTRA_TASKS = ""
@@ -2008,18908 +2039,5 @@ help: PHONY
$(CROSS_COMPILING:yes=)builtin.$(OBJEXT): {$(VPATH)}mini_builtin.c
$(CROSS_COMPILING:yes=)builtin.$(OBJEXT): {$(VPATH)}miniprelude.c
-# AUTOGENERATED DEPENDENCIES START
-addr2line.$(OBJEXT): {$(VPATH)}addr2line.c
-addr2line.$(OBJEXT): {$(VPATH)}addr2line.h
-addr2line.$(OBJEXT): {$(VPATH)}assert.h
-addr2line.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-addr2line.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-addr2line.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-addr2line.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-addr2line.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-addr2line.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-addr2line.$(OBJEXT): {$(VPATH)}config.h
-addr2line.$(OBJEXT): {$(VPATH)}defines.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/assume.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/cast.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/config.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/dosish.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-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
-array.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-array.$(OBJEXT): $(top_srcdir)/internal/bits.h
-array.$(OBJEXT): $(top_srcdir)/internal/class.h
-array.$(OBJEXT): $(top_srcdir)/internal/compar.h
-array.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-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
-array.$(OBJEXT): $(top_srcdir)/internal/rational.h
-array.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-array.$(OBJEXT): $(top_srcdir)/internal/serial.h
-array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-array.$(OBJEXT): $(top_srcdir)/internal/variable.h
-array.$(OBJEXT): $(top_srcdir)/internal/vm.h
-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
-array.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-array.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-array.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-array.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-array.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-array.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-array.$(OBJEXT): {$(VPATH)}builtin.h
-array.$(OBJEXT): {$(VPATH)}config.h
-array.$(OBJEXT): {$(VPATH)}constant.h
-array.$(OBJEXT): {$(VPATH)}debug_counter.h
-array.$(OBJEXT): {$(VPATH)}defines.h
-array.$(OBJEXT): {$(VPATH)}encoding.h
-array.$(OBJEXT): {$(VPATH)}id.h
-array.$(OBJEXT): {$(VPATH)}id_table.h
-array.$(OBJEXT): {$(VPATH)}intern.h
-array.$(OBJEXT): {$(VPATH)}internal.h
-array.$(OBJEXT): {$(VPATH)}internal/abi.h
-array.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-array.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-array.$(OBJEXT): {$(VPATH)}internal/assume.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-array.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-array.$(OBJEXT): {$(VPATH)}internal/cast.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-array.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-array.$(OBJEXT): {$(VPATH)}internal/config.h
-array.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-array.$(OBJEXT): {$(VPATH)}internal/core.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-array.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-array.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-array.$(OBJEXT): {$(VPATH)}internal/ctype.h
-array.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-array.$(OBJEXT): {$(VPATH)}internal/dosish.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-array.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-array.$(OBJEXT): {$(VPATH)}internal/error.h
-array.$(OBJEXT): {$(VPATH)}internal/eval.h
-array.$(OBJEXT): {$(VPATH)}internal/event.h
-array.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-array.$(OBJEXT): {$(VPATH)}internal/gc.h
-array.$(OBJEXT): {$(VPATH)}internal/glob.h
-array.$(OBJEXT): {$(VPATH)}internal/globals.h
-array.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-array.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-array.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-array.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-array.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-array.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-array.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-array.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-array.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-array.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-array.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-array.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-array.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-array.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-array.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-array.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-array.$(OBJEXT): {$(VPATH)}internal/symbol.h
-array.$(OBJEXT): {$(VPATH)}internal/value.h
-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)}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
-ast.$(OBJEXT): $(CCAN_DIR)/str/str.h
-ast.$(OBJEXT): $(hdrdir)/ruby.h
-ast.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-ast.$(OBJEXT): $(top_srcdir)/internal/array.h
-ast.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-ast.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-ast.$(OBJEXT): $(top_srcdir)/internal/bits.h
-ast.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ast.$(OBJEXT): $(top_srcdir)/internal/complex.h
-ast.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-ast.$(OBJEXT): $(top_srcdir)/internal/gc.h
-ast.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ast.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-ast.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ast.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ast.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-ast.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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/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/static_literals.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_integer.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_string.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
-ast.$(OBJEXT): {$(VPATH)}atomic.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-ast.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-ast.$(OBJEXT): {$(VPATH)}builtin.h
-ast.$(OBJEXT): {$(VPATH)}config.h
-ast.$(OBJEXT): {$(VPATH)}constant.h
-ast.$(OBJEXT): {$(VPATH)}defines.h
-ast.$(OBJEXT): {$(VPATH)}encoding.h
-ast.$(OBJEXT): {$(VPATH)}id.h
-ast.$(OBJEXT): {$(VPATH)}id_table.h
-ast.$(OBJEXT): {$(VPATH)}intern.h
-ast.$(OBJEXT): {$(VPATH)}internal.h
-ast.$(OBJEXT): {$(VPATH)}internal/abi.h
-ast.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-ast.$(OBJEXT): {$(VPATH)}internal/assume.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-ast.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-ast.$(OBJEXT): {$(VPATH)}internal/cast.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-ast.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-ast.$(OBJEXT): {$(VPATH)}internal/config.h
-ast.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-ast.$(OBJEXT): {$(VPATH)}internal/core.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-ast.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-ast.$(OBJEXT): {$(VPATH)}internal/ctype.h
-ast.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-ast.$(OBJEXT): {$(VPATH)}internal/dosish.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-ast.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-ast.$(OBJEXT): {$(VPATH)}internal/error.h
-ast.$(OBJEXT): {$(VPATH)}internal/eval.h
-ast.$(OBJEXT): {$(VPATH)}internal/event.h
-ast.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-ast.$(OBJEXT): {$(VPATH)}internal/gc.h
-ast.$(OBJEXT): {$(VPATH)}internal/glob.h
-ast.$(OBJEXT): {$(VPATH)}internal/globals.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-ast.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-ast.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-ast.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-ast.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-ast.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-ast.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-ast.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-ast.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ast.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-ast.$(OBJEXT): {$(VPATH)}internal/symbol.h
-ast.$(OBJEXT): {$(VPATH)}internal/value.h
-ast.$(OBJEXT): {$(VPATH)}internal/value_type.h
-ast.$(OBJEXT): {$(VPATH)}internal/variable.h
-ast.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-ast.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-ast.$(OBJEXT): {$(VPATH)}iseq.h
-ast.$(OBJEXT): {$(VPATH)}method.h
-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/diagnostic.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
-ast.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-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
-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
-bignum.$(OBJEXT): $(top_srcdir)/internal/serial.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-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
-bignum.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-bignum.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-bignum.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-bignum.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-bignum.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-bignum.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-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
-bignum.$(OBJEXT): {$(VPATH)}internal.h
-bignum.$(OBJEXT): {$(VPATH)}internal/abi.h
-bignum.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-bignum.$(OBJEXT): {$(VPATH)}internal/assume.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-bignum.$(OBJEXT): {$(VPATH)}internal/cast.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-bignum.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-bignum.$(OBJEXT): {$(VPATH)}internal/config.h
-bignum.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-bignum.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-bignum.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-bignum.$(OBJEXT): {$(VPATH)}internal/gc.h
-bignum.$(OBJEXT): {$(VPATH)}internal/glob.h
-bignum.$(OBJEXT): {$(VPATH)}internal/globals.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-bignum.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-bignum.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-bignum.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-bignum.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-bignum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-bignum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-bignum.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-bignum.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-bignum.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-bignum.$(OBJEXT): {$(VPATH)}internal/symbol.h
-bignum.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-builtin.$(OBJEXT): $(CCAN_DIR)/str/str.h
-builtin.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/array.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h
-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/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/static_literals.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_integer.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_string.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
-builtin.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-builtin.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-builtin.$(OBJEXT): {$(VPATH)}builtin.c
-builtin.$(OBJEXT): {$(VPATH)}builtin.h
-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
-builtin.$(OBJEXT): {$(VPATH)}internal.h
-builtin.$(OBJEXT): {$(VPATH)}internal/abi.h
-builtin.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-builtin.$(OBJEXT): {$(VPATH)}internal/assume.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-builtin.$(OBJEXT): {$(VPATH)}internal/cast.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-builtin.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-builtin.$(OBJEXT): {$(VPATH)}internal/config.h
-builtin.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-builtin.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-builtin.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-builtin.$(OBJEXT): {$(VPATH)}internal/gc.h
-builtin.$(OBJEXT): {$(VPATH)}internal/glob.h
-builtin.$(OBJEXT): {$(VPATH)}internal/globals.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-builtin.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-builtin.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-builtin.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-builtin.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-builtin.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-builtin.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-builtin.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-builtin.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-builtin.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-builtin.$(OBJEXT): {$(VPATH)}internal/symbol.h
-builtin.$(OBJEXT): {$(VPATH)}internal/value.h
-builtin.$(OBJEXT): {$(VPATH)}internal/value_type.h
-builtin.$(OBJEXT): {$(VPATH)}internal/variable.h
-builtin.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-builtin.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-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/diagnostic.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
-builtin.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-builtin.$(OBJEXT): {$(VPATH)}thread_native.h
-builtin.$(OBJEXT): {$(VPATH)}vm_core.h
-builtin.$(OBJEXT): {$(VPATH)}vm_opts.h
-class.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-class.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-class.$(OBJEXT): $(CCAN_DIR)/list/list.h
-class.$(OBJEXT): $(CCAN_DIR)/str/str.h
-class.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-class.$(OBJEXT): $(top_srcdir)/internal/array.h
-class.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-class.$(OBJEXT): $(top_srcdir)/internal/class.h
-class.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-class.$(OBJEXT): $(top_srcdir)/internal/eval.h
-class.$(OBJEXT): $(top_srcdir)/internal/gc.h
-class.$(OBJEXT): $(top_srcdir)/internal/hash.h
-class.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-class.$(OBJEXT): $(top_srcdir)/internal/object.h
-class.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-class.$(OBJEXT): $(top_srcdir)/internal/serial.h
-class.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-class.$(OBJEXT): $(top_srcdir)/internal/string.h
-class.$(OBJEXT): $(top_srcdir)/internal/variable.h
-class.$(OBJEXT): $(top_srcdir)/internal/vm.h
-class.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-class.$(OBJEXT): {$(VPATH)}assert.h
-class.$(OBJEXT): {$(VPATH)}atomic.h
-class.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-class.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-class.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-class.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-class.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-class.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-class.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-class.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-class.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-class.$(OBJEXT): {$(VPATH)}class.c
-class.$(OBJEXT): {$(VPATH)}config.h
-class.$(OBJEXT): {$(VPATH)}constant.h
-class.$(OBJEXT): {$(VPATH)}debug_counter.h
-class.$(OBJEXT): {$(VPATH)}defines.h
-class.$(OBJEXT): {$(VPATH)}encoding.h
-class.$(OBJEXT): {$(VPATH)}id.h
-class.$(OBJEXT): {$(VPATH)}id_table.h
-class.$(OBJEXT): {$(VPATH)}intern.h
-class.$(OBJEXT): {$(VPATH)}internal.h
-class.$(OBJEXT): {$(VPATH)}internal/abi.h
-class.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-class.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-class.$(OBJEXT): {$(VPATH)}internal/assume.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-class.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-class.$(OBJEXT): {$(VPATH)}internal/cast.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-class.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-class.$(OBJEXT): {$(VPATH)}internal/config.h
-class.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-class.$(OBJEXT): {$(VPATH)}internal/core.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-class.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-class.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-class.$(OBJEXT): {$(VPATH)}internal/ctype.h
-class.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-class.$(OBJEXT): {$(VPATH)}internal/dosish.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-class.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-class.$(OBJEXT): {$(VPATH)}internal/error.h
-class.$(OBJEXT): {$(VPATH)}internal/eval.h
-class.$(OBJEXT): {$(VPATH)}internal/event.h
-class.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-class.$(OBJEXT): {$(VPATH)}internal/gc.h
-class.$(OBJEXT): {$(VPATH)}internal/glob.h
-class.$(OBJEXT): {$(VPATH)}internal/globals.h
-class.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-class.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-class.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-class.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-class.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-class.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-class.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-class.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-class.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-class.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-class.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-class.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-class.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-class.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-class.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-class.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-class.$(OBJEXT): {$(VPATH)}internal/symbol.h
-class.$(OBJEXT): {$(VPATH)}internal/value.h
-class.$(OBJEXT): {$(VPATH)}internal/value_type.h
-class.$(OBJEXT): {$(VPATH)}internal/variable.h
-class.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-class.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-class.$(OBJEXT): {$(VPATH)}method.h
-class.$(OBJEXT): {$(VPATH)}missing.h
-class.$(OBJEXT): {$(VPATH)}node.h
-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
-class.$(OBJEXT): {$(VPATH)}yjit.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
-compar.$(OBJEXT): $(top_srcdir)/internal/error.h
-compar.$(OBJEXT): $(top_srcdir)/internal/serial.h
-compar.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-compar.$(OBJEXT): $(top_srcdir)/internal/string.h
-compar.$(OBJEXT): $(top_srcdir)/internal/vm.h
-compar.$(OBJEXT): {$(VPATH)}assert.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-compar.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-compar.$(OBJEXT): {$(VPATH)}compar.c
-compar.$(OBJEXT): {$(VPATH)}config.h
-compar.$(OBJEXT): {$(VPATH)}defines.h
-compar.$(OBJEXT): {$(VPATH)}encoding.h
-compar.$(OBJEXT): {$(VPATH)}id.h
-compar.$(OBJEXT): {$(VPATH)}intern.h
-compar.$(OBJEXT): {$(VPATH)}internal.h
-compar.$(OBJEXT): {$(VPATH)}internal/abi.h
-compar.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-compar.$(OBJEXT): {$(VPATH)}internal/assume.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-compar.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-compar.$(OBJEXT): {$(VPATH)}internal/cast.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-compar.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-compar.$(OBJEXT): {$(VPATH)}internal/config.h
-compar.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-compar.$(OBJEXT): {$(VPATH)}internal/core.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-compar.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-compar.$(OBJEXT): {$(VPATH)}internal/ctype.h
-compar.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-compar.$(OBJEXT): {$(VPATH)}internal/dosish.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-compar.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-compar.$(OBJEXT): {$(VPATH)}internal/error.h
-compar.$(OBJEXT): {$(VPATH)}internal/eval.h
-compar.$(OBJEXT): {$(VPATH)}internal/event.h
-compar.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-compar.$(OBJEXT): {$(VPATH)}internal/gc.h
-compar.$(OBJEXT): {$(VPATH)}internal/glob.h
-compar.$(OBJEXT): {$(VPATH)}internal/globals.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-compar.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-compar.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-compar.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-compar.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-compar.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-compar.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-compar.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-compar.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-compar.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-compar.$(OBJEXT): {$(VPATH)}internal/symbol.h
-compar.$(OBJEXT): {$(VPATH)}internal/value.h
-compar.$(OBJEXT): {$(VPATH)}internal/value_type.h
-compar.$(OBJEXT): {$(VPATH)}internal/variable.h
-compar.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-compar.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-compar.$(OBJEXT): {$(VPATH)}missing.h
-compar.$(OBJEXT): {$(VPATH)}onigmo.h
-compar.$(OBJEXT): {$(VPATH)}oniguruma.h
-compar.$(OBJEXT): {$(VPATH)}st.h
-compar.$(OBJEXT): {$(VPATH)}subst.h
-compile.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-compile.$(OBJEXT): $(top_srcdir)/internal/bits.h
-compile.$(OBJEXT): $(top_srcdir)/internal/class.h
-compile.$(OBJEXT): $(top_srcdir)/internal/compile.h
-compile.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-compile.$(OBJEXT): $(top_srcdir)/internal/complex.h
-compile.$(OBJEXT): $(top_srcdir)/internal/encoding.h
-compile.$(OBJEXT): $(top_srcdir)/internal/error.h
-compile.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-compile.$(OBJEXT): $(top_srcdir)/internal/gc.h
-compile.$(OBJEXT): $(top_srcdir)/internal/hash.h
-compile.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-compile.$(OBJEXT): $(top_srcdir)/internal/io.h
-compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-compile.$(OBJEXT): $(top_srcdir)/internal/object.h
-compile.$(OBJEXT): $(top_srcdir)/internal/parse.h
-compile.$(OBJEXT): $(top_srcdir)/internal/rational.h
-compile.$(OBJEXT): $(top_srcdir)/internal/re.h
-compile.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-compile.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-compile.$(OBJEXT): $(top_srcdir)/internal/serial.h
-compile.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-compile.$(OBJEXT): $(top_srcdir)/internal/string.h
-compile.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-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/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/static_literals.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_integer.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_string.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
-compile.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-compile.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-compile.$(OBJEXT): {$(VPATH)}builtin.h
-compile.$(OBJEXT): {$(VPATH)}compile.c
-compile.$(OBJEXT): {$(VPATH)}config.h
-compile.$(OBJEXT): {$(VPATH)}constant.h
-compile.$(OBJEXT): {$(VPATH)}debug_counter.h
-compile.$(OBJEXT): {$(VPATH)}defines.h
-compile.$(OBJEXT): {$(VPATH)}encindex.h
-compile.$(OBJEXT): {$(VPATH)}encoding.h
-compile.$(OBJEXT): {$(VPATH)}id.h
-compile.$(OBJEXT): {$(VPATH)}id_table.h
-compile.$(OBJEXT): {$(VPATH)}insns.def
-compile.$(OBJEXT): {$(VPATH)}insns.inc
-compile.$(OBJEXT): {$(VPATH)}insns_info.inc
-compile.$(OBJEXT): {$(VPATH)}intern.h
-compile.$(OBJEXT): {$(VPATH)}internal.h
-compile.$(OBJEXT): {$(VPATH)}internal/abi.h
-compile.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-compile.$(OBJEXT): {$(VPATH)}internal/assume.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-compile.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-compile.$(OBJEXT): {$(VPATH)}internal/cast.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-compile.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-compile.$(OBJEXT): {$(VPATH)}internal/config.h
-compile.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-compile.$(OBJEXT): {$(VPATH)}internal/core.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-compile.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-compile.$(OBJEXT): {$(VPATH)}internal/ctype.h
-compile.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-compile.$(OBJEXT): {$(VPATH)}internal/dosish.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-compile.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-compile.$(OBJEXT): {$(VPATH)}internal/error.h
-compile.$(OBJEXT): {$(VPATH)}internal/eval.h
-compile.$(OBJEXT): {$(VPATH)}internal/event.h
-compile.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-compile.$(OBJEXT): {$(VPATH)}internal/gc.h
-compile.$(OBJEXT): {$(VPATH)}internal/glob.h
-compile.$(OBJEXT): {$(VPATH)}internal/globals.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-compile.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-compile.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-compile.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-compile.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-compile.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-compile.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-compile.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-compile.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-compile.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-compile.$(OBJEXT): {$(VPATH)}internal/symbol.h
-compile.$(OBJEXT): {$(VPATH)}internal/value.h
-compile.$(OBJEXT): {$(VPATH)}internal/value_type.h
-compile.$(OBJEXT): {$(VPATH)}internal/variable.h
-compile.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-compile.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-compile.$(OBJEXT): {$(VPATH)}io.h
-compile.$(OBJEXT): {$(VPATH)}iseq.h
-compile.$(OBJEXT): {$(VPATH)}method.h
-compile.$(OBJEXT): {$(VPATH)}missing.h
-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/diagnostic.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)}ractor.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
-compile.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-compile.$(OBJEXT): {$(VPATH)}thread_native.h
-compile.$(OBJEXT): {$(VPATH)}util.h
-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
-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/sanitizers.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
-complex.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-complex.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-complex.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-complex.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-complex.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-complex.$(OBJEXT): {$(VPATH)}internal.h
-complex.$(OBJEXT): {$(VPATH)}internal/abi.h
-complex.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-complex.$(OBJEXT): {$(VPATH)}internal/assume.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-complex.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-complex.$(OBJEXT): {$(VPATH)}internal/cast.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-complex.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-complex.$(OBJEXT): {$(VPATH)}internal/config.h
-complex.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-complex.$(OBJEXT): {$(VPATH)}internal/core.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-complex.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-complex.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-complex.$(OBJEXT): {$(VPATH)}internal/gc.h
-complex.$(OBJEXT): {$(VPATH)}internal/glob.h
-complex.$(OBJEXT): {$(VPATH)}internal/globals.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-complex.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-complex.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-complex.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-complex.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-complex.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-complex.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-complex.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-complex.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-complex.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-complex.$(OBJEXT): {$(VPATH)}internal/symbol.h
-complex.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-cont.$(OBJEXT): $(top_srcdir)/internal/cont.h
-cont.$(OBJEXT): $(top_srcdir)/internal/error.h
-cont.$(OBJEXT): $(top_srcdir)/internal/gc.h
-cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-cont.$(OBJEXT): $(top_srcdir)/internal/proc.h
-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/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/static_literals.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_integer.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_string.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
-cont.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-cont.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-cont.$(OBJEXT): {$(VPATH)}config.h
-cont.$(OBJEXT): {$(VPATH)}constant.h
-cont.$(OBJEXT): {$(VPATH)}cont.c
-cont.$(OBJEXT): {$(VPATH)}debug_counter.h
-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)}id.h
-cont.$(OBJEXT): {$(VPATH)}id_table.h
-cont.$(OBJEXT): {$(VPATH)}intern.h
-cont.$(OBJEXT): {$(VPATH)}internal.h
-cont.$(OBJEXT): {$(VPATH)}internal/abi.h
-cont.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-cont.$(OBJEXT): {$(VPATH)}internal/assume.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-cont.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-cont.$(OBJEXT): {$(VPATH)}internal/cast.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-cont.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-cont.$(OBJEXT): {$(VPATH)}internal/config.h
-cont.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-cont.$(OBJEXT): {$(VPATH)}internal/core.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-cont.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-cont.$(OBJEXT): {$(VPATH)}internal/ctype.h
-cont.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-cont.$(OBJEXT): {$(VPATH)}internal/dosish.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-cont.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-cont.$(OBJEXT): {$(VPATH)}internal/error.h
-cont.$(OBJEXT): {$(VPATH)}internal/eval.h
-cont.$(OBJEXT): {$(VPATH)}internal/event.h
-cont.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-cont.$(OBJEXT): {$(VPATH)}internal/gc.h
-cont.$(OBJEXT): {$(VPATH)}internal/glob.h
-cont.$(OBJEXT): {$(VPATH)}internal/globals.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-cont.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-cont.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-cont.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-cont.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-cont.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-cont.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-cont.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-cont.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-cont.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-cont.$(OBJEXT): {$(VPATH)}internal/symbol.h
-cont.$(OBJEXT): {$(VPATH)}internal/value.h
-cont.$(OBJEXT): {$(VPATH)}internal/value_type.h
-cont.$(OBJEXT): {$(VPATH)}internal/variable.h
-cont.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-cont.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-cont.$(OBJEXT): {$(VPATH)}iseq.h
-cont.$(OBJEXT): {$(VPATH)}method.h
-cont.$(OBJEXT): {$(VPATH)}missing.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/diagnostic.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)}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
-cont.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-cont.$(OBJEXT): {$(VPATH)}thread_native.h
-cont.$(OBJEXT): {$(VPATH)}vm_core.h
-cont.$(OBJEXT): {$(VPATH)}vm_debug.h
-cont.$(OBJEXT): {$(VPATH)}vm_opts.h
-cont.$(OBJEXT): {$(VPATH)}vm_sync.h
-cont.$(OBJEXT): {$(VPATH)}yjit.h
-debug.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-debug.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-debug.$(OBJEXT): $(CCAN_DIR)/list/list.h
-debug.$(OBJEXT): $(CCAN_DIR)/str/str.h
-debug.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-debug.$(OBJEXT): $(top_srcdir)/internal/array.h
-debug.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-debug.$(OBJEXT): $(top_srcdir)/internal/class.h
-debug.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-debug.$(OBJEXT): $(top_srcdir)/internal/gc.h
-debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-debug.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-debug.$(OBJEXT): $(top_srcdir)/internal/serial.h
-debug.$(OBJEXT): $(top_srcdir)/internal/signal.h
-debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-debug.$(OBJEXT): $(top_srcdir)/internal/variable.h
-debug.$(OBJEXT): $(top_srcdir)/internal/vm.h
-debug.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-debug.$(OBJEXT): {$(VPATH)}assert.h
-debug.$(OBJEXT): {$(VPATH)}atomic.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-debug.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-debug.$(OBJEXT): {$(VPATH)}config.h
-debug.$(OBJEXT): {$(VPATH)}constant.h
-debug.$(OBJEXT): {$(VPATH)}debug.c
-debug.$(OBJEXT): {$(VPATH)}debug_counter.h
-debug.$(OBJEXT): {$(VPATH)}defines.h
-debug.$(OBJEXT): {$(VPATH)}encindex.h
-debug.$(OBJEXT): {$(VPATH)}encoding.h
-debug.$(OBJEXT): {$(VPATH)}eval_intern.h
-debug.$(OBJEXT): {$(VPATH)}id.h
-debug.$(OBJEXT): {$(VPATH)}id_table.h
-debug.$(OBJEXT): {$(VPATH)}intern.h
-debug.$(OBJEXT): {$(VPATH)}internal.h
-debug.$(OBJEXT): {$(VPATH)}internal/abi.h
-debug.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-debug.$(OBJEXT): {$(VPATH)}internal/assume.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-debug.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-debug.$(OBJEXT): {$(VPATH)}internal/cast.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-debug.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-debug.$(OBJEXT): {$(VPATH)}internal/config.h
-debug.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-debug.$(OBJEXT): {$(VPATH)}internal/core.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-debug.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-debug.$(OBJEXT): {$(VPATH)}internal/ctype.h
-debug.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-debug.$(OBJEXT): {$(VPATH)}internal/dosish.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-debug.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-debug.$(OBJEXT): {$(VPATH)}internal/error.h
-debug.$(OBJEXT): {$(VPATH)}internal/eval.h
-debug.$(OBJEXT): {$(VPATH)}internal/event.h
-debug.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-debug.$(OBJEXT): {$(VPATH)}internal/gc.h
-debug.$(OBJEXT): {$(VPATH)}internal/glob.h
-debug.$(OBJEXT): {$(VPATH)}internal/globals.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-debug.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-debug.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-debug.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-debug.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-debug.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-debug.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-debug.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-debug.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-debug.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-debug.$(OBJEXT): {$(VPATH)}internal/symbol.h
-debug.$(OBJEXT): {$(VPATH)}internal/value.h
-debug.$(OBJEXT): {$(VPATH)}internal/value_type.h
-debug.$(OBJEXT): {$(VPATH)}internal/variable.h
-debug.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-debug.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-debug.$(OBJEXT): {$(VPATH)}io.h
-debug.$(OBJEXT): {$(VPATH)}method.h
-debug.$(OBJEXT): {$(VPATH)}missing.h
-debug.$(OBJEXT): {$(VPATH)}node.h
-debug.$(OBJEXT): {$(VPATH)}onigmo.h
-debug.$(OBJEXT): {$(VPATH)}oniguruma.h
-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
-debug.$(OBJEXT): {$(VPATH)}symbol.h
-debug.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-debug.$(OBJEXT): {$(VPATH)}thread_native.h
-debug.$(OBJEXT): {$(VPATH)}util.h
-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
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-debug_counter.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-debug_counter.$(OBJEXT): {$(VPATH)}config.h
-debug_counter.$(OBJEXT): {$(VPATH)}debug_counter.c
-debug_counter.$(OBJEXT): {$(VPATH)}debug_counter.h
-debug_counter.$(OBJEXT): {$(VPATH)}defines.h
-debug_counter.$(OBJEXT): {$(VPATH)}intern.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/abi.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/assume.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/cast.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/config.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/ctype.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/dosish.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/error.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/eval.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/event.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/gc.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/glob.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/globals.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/symbol.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/value.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/value_type.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/variable.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-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
-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/sanitizers.h
-dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
-dir.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-dir.$(OBJEXT): $(top_srcdir)/internal/string.h
-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
-dir.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-dir.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-dir.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-dir.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-dir.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-dir.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-dir.$(OBJEXT): {$(VPATH)}builtin.h
-dir.$(OBJEXT): {$(VPATH)}config.h
-dir.$(OBJEXT): {$(VPATH)}constant.h
-dir.$(OBJEXT): {$(VPATH)}defines.h
-dir.$(OBJEXT): {$(VPATH)}dir.c
-dir.$(OBJEXT): {$(VPATH)}dir.rbinc
-dir.$(OBJEXT): {$(VPATH)}encindex.h
-dir.$(OBJEXT): {$(VPATH)}encoding.h
-dir.$(OBJEXT): {$(VPATH)}id.h
-dir.$(OBJEXT): {$(VPATH)}id_table.h
-dir.$(OBJEXT): {$(VPATH)}intern.h
-dir.$(OBJEXT): {$(VPATH)}internal.h
-dir.$(OBJEXT): {$(VPATH)}internal/abi.h
-dir.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-dir.$(OBJEXT): {$(VPATH)}internal/assume.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-dir.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-dir.$(OBJEXT): {$(VPATH)}internal/cast.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-dir.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-dir.$(OBJEXT): {$(VPATH)}internal/config.h
-dir.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-dir.$(OBJEXT): {$(VPATH)}internal/core.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-dir.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-dir.$(OBJEXT): {$(VPATH)}internal/ctype.h
-dir.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-dir.$(OBJEXT): {$(VPATH)}internal/dosish.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-dir.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-dir.$(OBJEXT): {$(VPATH)}internal/error.h
-dir.$(OBJEXT): {$(VPATH)}internal/eval.h
-dir.$(OBJEXT): {$(VPATH)}internal/event.h
-dir.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-dir.$(OBJEXT): {$(VPATH)}internal/gc.h
-dir.$(OBJEXT): {$(VPATH)}internal/glob.h
-dir.$(OBJEXT): {$(VPATH)}internal/globals.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-dir.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-dir.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-dir.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-dir.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-dir.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-dir.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-dir.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-dir.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dir.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-dir.$(OBJEXT): {$(VPATH)}internal/symbol.h
-dir.$(OBJEXT): {$(VPATH)}internal/value.h
-dir.$(OBJEXT): {$(VPATH)}internal/value_type.h
-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
-dln.$(OBJEXT): {$(VPATH)}assert.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-dln.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-dln.$(OBJEXT): {$(VPATH)}config.h
-dln.$(OBJEXT): {$(VPATH)}defines.h
-dln.$(OBJEXT): {$(VPATH)}dln.c
-dln.$(OBJEXT): {$(VPATH)}dln.h
-dln.$(OBJEXT): {$(VPATH)}intern.h
-dln.$(OBJEXT): {$(VPATH)}internal.h
-dln.$(OBJEXT): {$(VPATH)}internal/abi.h
-dln.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-dln.$(OBJEXT): {$(VPATH)}internal/assume.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-dln.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-dln.$(OBJEXT): {$(VPATH)}internal/cast.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-dln.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-dln.$(OBJEXT): {$(VPATH)}internal/config.h
-dln.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-dln.$(OBJEXT): {$(VPATH)}internal/core.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-dln.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-dln.$(OBJEXT): {$(VPATH)}internal/ctype.h
-dln.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-dln.$(OBJEXT): {$(VPATH)}internal/dosish.h
-dln.$(OBJEXT): {$(VPATH)}internal/error.h
-dln.$(OBJEXT): {$(VPATH)}internal/eval.h
-dln.$(OBJEXT): {$(VPATH)}internal/event.h
-dln.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-dln.$(OBJEXT): {$(VPATH)}internal/gc.h
-dln.$(OBJEXT): {$(VPATH)}internal/glob.h
-dln.$(OBJEXT): {$(VPATH)}internal/globals.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-dln.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-dln.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-dln.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-dln.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-dln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-dln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-dln.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-dln.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dln.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-dln.$(OBJEXT): {$(VPATH)}internal/symbol.h
-dln.$(OBJEXT): {$(VPATH)}internal/value.h
-dln.$(OBJEXT): {$(VPATH)}internal/value_type.h
-dln.$(OBJEXT): {$(VPATH)}internal/variable.h
-dln.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-dln.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-dln.$(OBJEXT): {$(VPATH)}missing.h
-dln.$(OBJEXT): {$(VPATH)}st.h
-dln.$(OBJEXT): {$(VPATH)}subst.h
-dln_find.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-dln_find.$(OBJEXT): {$(VPATH)}assert.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-dln_find.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-dln_find.$(OBJEXT): {$(VPATH)}config.h
-dln_find.$(OBJEXT): {$(VPATH)}defines.h
-dln_find.$(OBJEXT): {$(VPATH)}dln.h
-dln_find.$(OBJEXT): {$(VPATH)}dln_find.c
-dln_find.$(OBJEXT): {$(VPATH)}intern.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/abi.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/assume.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/cast.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/config.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/ctype.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/dosish.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/error.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/eval.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/event.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/gc.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/glob.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/globals.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/symbol.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/value.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/value_type.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/variable.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-dln_find.$(OBJEXT): {$(VPATH)}missing.h
-dln_find.$(OBJEXT): {$(VPATH)}st.h
-dln_find.$(OBJEXT): {$(VPATH)}subst.h
-dmydln.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-dmydln.$(OBJEXT): {$(VPATH)}assert.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-dmydln.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-dmydln.$(OBJEXT): {$(VPATH)}config.h
-dmydln.$(OBJEXT): {$(VPATH)}defines.h
-dmydln.$(OBJEXT): {$(VPATH)}dmydln.c
-dmydln.$(OBJEXT): {$(VPATH)}intern.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/abi.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/assume.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/cast.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/config.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/ctype.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/dosish.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/error.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/eval.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/event.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/gc.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/glob.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/globals.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/symbol.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/value.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/value_type.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/variable.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-dmydln.$(OBJEXT): {$(VPATH)}missing.h
-dmydln.$(OBJEXT): {$(VPATH)}st.h
-dmydln.$(OBJEXT): {$(VPATH)}subst.h
-dmyenc.$(OBJEXT): {$(VPATH)}dmyenc.c
-dmyext.$(OBJEXT): {$(VPATH)}dmyext.c
-enc/ascii.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enc/ascii.$(OBJEXT): {$(VPATH)}assert.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-enc/ascii.$(OBJEXT): {$(VPATH)}config.h
-enc/ascii.$(OBJEXT): {$(VPATH)}defines.h
-enc/ascii.$(OBJEXT): {$(VPATH)}enc/ascii.c
-enc/ascii.$(OBJEXT): {$(VPATH)}encindex.h
-enc/ascii.$(OBJEXT): {$(VPATH)}encoding.h
-enc/ascii.$(OBJEXT): {$(VPATH)}intern.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/assume.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/cast.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/config.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/error.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/eval.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/event.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/gc.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/glob.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/globals.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/value.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/value_type.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/variable.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-enc/ascii.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enc/ascii.$(OBJEXT): {$(VPATH)}missing.h
-enc/ascii.$(OBJEXT): {$(VPATH)}onigmo.h
-enc/ascii.$(OBJEXT): {$(VPATH)}oniguruma.h
-enc/ascii.$(OBJEXT): {$(VPATH)}regenc.h
-enc/ascii.$(OBJEXT): {$(VPATH)}st.h
-enc/ascii.$(OBJEXT): {$(VPATH)}subst.h
-enc/trans/newline.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}assert.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}config.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}defines.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}enc/trans/newline.c
-enc/trans/newline.$(OBJEXT): {$(VPATH)}intern.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/assume.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/cast.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/config.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/error.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/eval.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/event.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/gc.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/glob.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/globals.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/value.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/value_type.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/variable.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}missing.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}st.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}subst.h
-enc/trans/newline.$(OBJEXT): {$(VPATH)}transcode_data.h
-enc/unicode.$(OBJEXT): $(UNICODE_HDR_DIR)/casefold.h
-enc/unicode.$(OBJEXT): $(UNICODE_HDR_DIR)/name2ctype.h
-enc/unicode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enc/unicode.$(OBJEXT): {$(VPATH)}assert.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-enc/unicode.$(OBJEXT): {$(VPATH)}config.h
-enc/unicode.$(OBJEXT): {$(VPATH)}defines.h
-enc/unicode.$(OBJEXT): {$(VPATH)}enc/unicode.c
-enc/unicode.$(OBJEXT): {$(VPATH)}intern.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/assume.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/cast.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/config.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/error.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/eval.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/event.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/gc.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/glob.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/globals.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/value.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/value_type.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/variable.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-enc/unicode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enc/unicode.$(OBJEXT): {$(VPATH)}missing.h
-enc/unicode.$(OBJEXT): {$(VPATH)}onigmo.h
-enc/unicode.$(OBJEXT): {$(VPATH)}regenc.h
-enc/unicode.$(OBJEXT): {$(VPATH)}regint.h
-enc/unicode.$(OBJEXT): {$(VPATH)}st.h
-enc/unicode.$(OBJEXT): {$(VPATH)}subst.h
-enc/us_ascii.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}assert.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}config.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}defines.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}enc/us_ascii.c
-enc/us_ascii.$(OBJEXT): {$(VPATH)}encindex.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}encoding.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}intern.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/assume.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/cast.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/config.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/error.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/eval.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/event.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/gc.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/glob.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/globals.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/value.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/value_type.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/variable.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}missing.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}onigmo.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}oniguruma.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}regenc.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}st.h
-enc/us_ascii.$(OBJEXT): {$(VPATH)}subst.h
-enc/utf_8.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}assert.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}config.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}defines.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}enc/utf_8.c
-enc/utf_8.$(OBJEXT): {$(VPATH)}encindex.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}encoding.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}intern.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/assume.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/cast.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/config.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/error.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/eval.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/event.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/gc.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/glob.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/globals.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/value.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/value_type.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/variable.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}missing.h
-enc/utf_8.$(OBJEXT): {$(VPATH)}onigmo.h
-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
-encoding.$(OBJEXT): $(top_srcdir)/internal/serial.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/string.h
-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
-encoding.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-encoding.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-encoding.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-encoding.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-encoding.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-encoding.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-encoding.$(OBJEXT): {$(VPATH)}config.h
-encoding.$(OBJEXT): {$(VPATH)}constant.h
-encoding.$(OBJEXT): {$(VPATH)}debug_counter.h
-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
-encoding.$(OBJEXT): {$(VPATH)}internal/abi.h
-encoding.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-encoding.$(OBJEXT): {$(VPATH)}internal/assume.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-encoding.$(OBJEXT): {$(VPATH)}internal/cast.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-encoding.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-encoding.$(OBJEXT): {$(VPATH)}internal/config.h
-encoding.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-encoding.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-encoding.$(OBJEXT): {$(VPATH)}internal/ctype.h
-encoding.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-encoding.$(OBJEXT): {$(VPATH)}internal/dosish.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-encoding.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-encoding.$(OBJEXT): {$(VPATH)}internal/error.h
-encoding.$(OBJEXT): {$(VPATH)}internal/eval.h
-encoding.$(OBJEXT): {$(VPATH)}internal/event.h
-encoding.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-encoding.$(OBJEXT): {$(VPATH)}internal/gc.h
-encoding.$(OBJEXT): {$(VPATH)}internal/glob.h
-encoding.$(OBJEXT): {$(VPATH)}internal/globals.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-encoding.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-encoding.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-encoding.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-encoding.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-encoding.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-encoding.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-encoding.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-encoding.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-encoding.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-encoding.$(OBJEXT): {$(VPATH)}internal/symbol.h
-encoding.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-enum.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-enum.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-enum.$(OBJEXT): $(top_srcdir)/internal/bits.h
-enum.$(OBJEXT): $(top_srcdir)/internal/class.h
-enum.$(OBJEXT): $(top_srcdir)/internal/compar.h
-enum.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-enum.$(OBJEXT): $(top_srcdir)/internal/enum.h
-enum.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-enum.$(OBJEXT): $(top_srcdir)/internal/gc.h
-enum.$(OBJEXT): $(top_srcdir)/internal/hash.h
-enum.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-enum.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-enum.$(OBJEXT): $(top_srcdir)/internal/object.h
-enum.$(OBJEXT): $(top_srcdir)/internal/proc.h
-enum.$(OBJEXT): $(top_srcdir)/internal/rational.h
-enum.$(OBJEXT): $(top_srcdir)/internal/re.h
-enum.$(OBJEXT): $(top_srcdir)/internal/serial.h
-enum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-enum.$(OBJEXT): $(top_srcdir)/internal/variable.h
-enum.$(OBJEXT): $(top_srcdir)/internal/vm.h
-enum.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-enum.$(OBJEXT): {$(VPATH)}assert.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-enum.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-enum.$(OBJEXT): {$(VPATH)}config.h
-enum.$(OBJEXT): {$(VPATH)}constant.h
-enum.$(OBJEXT): {$(VPATH)}defines.h
-enum.$(OBJEXT): {$(VPATH)}encoding.h
-enum.$(OBJEXT): {$(VPATH)}enum.c
-enum.$(OBJEXT): {$(VPATH)}id.h
-enum.$(OBJEXT): {$(VPATH)}id_table.h
-enum.$(OBJEXT): {$(VPATH)}intern.h
-enum.$(OBJEXT): {$(VPATH)}internal.h
-enum.$(OBJEXT): {$(VPATH)}internal/abi.h
-enum.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enum.$(OBJEXT): {$(VPATH)}internal/assume.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-enum.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enum.$(OBJEXT): {$(VPATH)}internal/cast.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enum.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enum.$(OBJEXT): {$(VPATH)}internal/config.h
-enum.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enum.$(OBJEXT): {$(VPATH)}internal/core.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enum.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enum.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enum.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enum.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-enum.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-enum.$(OBJEXT): {$(VPATH)}internal/error.h
-enum.$(OBJEXT): {$(VPATH)}internal/eval.h
-enum.$(OBJEXT): {$(VPATH)}internal/event.h
-enum.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enum.$(OBJEXT): {$(VPATH)}internal/gc.h
-enum.$(OBJEXT): {$(VPATH)}internal/glob.h
-enum.$(OBJEXT): {$(VPATH)}internal/globals.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enum.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enum.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enum.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enum.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enum.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enum.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enum.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-enum.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enum.$(OBJEXT): {$(VPATH)}internal/value.h
-enum.$(OBJEXT): {$(VPATH)}internal/value_type.h
-enum.$(OBJEXT): {$(VPATH)}internal/variable.h
-enum.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-enum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enum.$(OBJEXT): {$(VPATH)}missing.h
-enum.$(OBJEXT): {$(VPATH)}onigmo.h
-enum.$(OBJEXT): {$(VPATH)}oniguruma.h
-enum.$(OBJEXT): {$(VPATH)}ruby_assert.h
-enum.$(OBJEXT): {$(VPATH)}shape.h
-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
-enumerator.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/error.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/gc.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/hash.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/range.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/rational.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-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
-enumerator.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-enumerator.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-enumerator.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-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
-enumerator.$(OBJEXT): {$(VPATH)}id.h
-enumerator.$(OBJEXT): {$(VPATH)}id_table.h
-enumerator.$(OBJEXT): {$(VPATH)}intern.h
-enumerator.$(OBJEXT): {$(VPATH)}internal.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/abi.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/assume.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/cast.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/config.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/ctype.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/dosish.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/error.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/eval.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/event.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/gc.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/glob.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/globals.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/symbol.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-error.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-error.$(OBJEXT): $(top_srcdir)/internal/error.h
-error.$(OBJEXT): $(top_srcdir)/internal/eval.h
-error.$(OBJEXT): $(top_srcdir)/internal/gc.h
-error.$(OBJEXT): $(top_srcdir)/internal/hash.h
-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/sanitizers.h
-error.$(OBJEXT): $(top_srcdir)/internal/serial.h
-error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-error.$(OBJEXT): $(top_srcdir)/internal/string.h
-error.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-error.$(OBJEXT): $(top_srcdir)/internal/thread.h
-error.$(OBJEXT): $(top_srcdir)/internal/variable.h
-error.$(OBJEXT): $(top_srcdir)/internal/vm.h
-error.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-error.$(OBJEXT): {$(VPATH)}assert.h
-error.$(OBJEXT): {$(VPATH)}atomic.h
-error.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-error.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-error.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-error.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-error.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-error.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-error.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-error.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-error.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-error.$(OBJEXT): {$(VPATH)}builtin.h
-error.$(OBJEXT): {$(VPATH)}config.h
-error.$(OBJEXT): {$(VPATH)}constant.h
-error.$(OBJEXT): {$(VPATH)}debug_counter.h
-error.$(OBJEXT): {$(VPATH)}defines.h
-error.$(OBJEXT): {$(VPATH)}encoding.h
-error.$(OBJEXT): {$(VPATH)}error.c
-error.$(OBJEXT): {$(VPATH)}id.h
-error.$(OBJEXT): {$(VPATH)}id_table.h
-error.$(OBJEXT): {$(VPATH)}intern.h
-error.$(OBJEXT): {$(VPATH)}internal.h
-error.$(OBJEXT): {$(VPATH)}internal/abi.h
-error.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-error.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-error.$(OBJEXT): {$(VPATH)}internal/assume.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-error.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-error.$(OBJEXT): {$(VPATH)}internal/cast.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-error.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-error.$(OBJEXT): {$(VPATH)}internal/config.h
-error.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-error.$(OBJEXT): {$(VPATH)}internal/core.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-error.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-error.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-error.$(OBJEXT): {$(VPATH)}internal/ctype.h
-error.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-error.$(OBJEXT): {$(VPATH)}internal/dosish.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-error.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-error.$(OBJEXT): {$(VPATH)}internal/error.h
-error.$(OBJEXT): {$(VPATH)}internal/eval.h
-error.$(OBJEXT): {$(VPATH)}internal/event.h
-error.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-error.$(OBJEXT): {$(VPATH)}internal/gc.h
-error.$(OBJEXT): {$(VPATH)}internal/glob.h
-error.$(OBJEXT): {$(VPATH)}internal/globals.h
-error.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-error.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-error.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-error.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-error.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-error.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-error.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-error.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-error.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-error.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-error.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-error.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-error.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-error.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-error.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-error.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-error.$(OBJEXT): {$(VPATH)}internal/symbol.h
-error.$(OBJEXT): {$(VPATH)}internal/value.h
-error.$(OBJEXT): {$(VPATH)}internal/value_type.h
-error.$(OBJEXT): {$(VPATH)}internal/variable.h
-error.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-error.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-error.$(OBJEXT): {$(VPATH)}io.h
-error.$(OBJEXT): {$(VPATH)}known_errors.inc
-error.$(OBJEXT): {$(VPATH)}method.h
-error.$(OBJEXT): {$(VPATH)}missing.h
-error.$(OBJEXT): {$(VPATH)}node.h
-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_debug.h
-error.$(OBJEXT): {$(VPATH)}vm_opts.h
-error.$(OBJEXT): {$(VPATH)}vm_sync.h
-error.$(OBJEXT): {$(VPATH)}warning.rbinc
-error.$(OBJEXT): {$(VPATH)}yjit.h
-eval.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-eval.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-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
-eval.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-eval.$(OBJEXT): $(top_srcdir)/internal/cont.h
-eval.$(OBJEXT): $(top_srcdir)/internal/error.h
-eval.$(OBJEXT): $(top_srcdir)/internal/eval.h
-eval.$(OBJEXT): $(top_srcdir)/internal/gc.h
-eval.$(OBJEXT): $(top_srcdir)/internal/hash.h
-eval.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-eval.$(OBJEXT): $(top_srcdir)/internal/inits.h
-eval.$(OBJEXT): $(top_srcdir)/internal/io.h
-eval.$(OBJEXT): $(top_srcdir)/internal/object.h
-eval.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-eval.$(OBJEXT): $(top_srcdir)/internal/serial.h
-eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-eval.$(OBJEXT): $(top_srcdir)/internal/string.h
-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/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/static_literals.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_integer.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_string.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
-eval.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-eval.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-eval.$(OBJEXT): {$(VPATH)}config.h
-eval.$(OBJEXT): {$(VPATH)}constant.h
-eval.$(OBJEXT): {$(VPATH)}debug_counter.h
-eval.$(OBJEXT): {$(VPATH)}defines.h
-eval.$(OBJEXT): {$(VPATH)}encoding.h
-eval.$(OBJEXT): {$(VPATH)}eval.c
-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)}id.h
-eval.$(OBJEXT): {$(VPATH)}id_table.h
-eval.$(OBJEXT): {$(VPATH)}intern.h
-eval.$(OBJEXT): {$(VPATH)}internal.h
-eval.$(OBJEXT): {$(VPATH)}internal/abi.h
-eval.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-eval.$(OBJEXT): {$(VPATH)}internal/assume.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-eval.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-eval.$(OBJEXT): {$(VPATH)}internal/cast.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-eval.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-eval.$(OBJEXT): {$(VPATH)}internal/config.h
-eval.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-eval.$(OBJEXT): {$(VPATH)}internal/core.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-eval.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-eval.$(OBJEXT): {$(VPATH)}internal/ctype.h
-eval.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-eval.$(OBJEXT): {$(VPATH)}internal/dosish.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-eval.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-eval.$(OBJEXT): {$(VPATH)}internal/error.h
-eval.$(OBJEXT): {$(VPATH)}internal/eval.h
-eval.$(OBJEXT): {$(VPATH)}internal/event.h
-eval.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-eval.$(OBJEXT): {$(VPATH)}internal/gc.h
-eval.$(OBJEXT): {$(VPATH)}internal/glob.h
-eval.$(OBJEXT): {$(VPATH)}internal/globals.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-eval.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-eval.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-eval.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-eval.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-eval.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-eval.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-eval.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-eval.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-eval.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-eval.$(OBJEXT): {$(VPATH)}internal/symbol.h
-eval.$(OBJEXT): {$(VPATH)}internal/value.h
-eval.$(OBJEXT): {$(VPATH)}internal/value_type.h
-eval.$(OBJEXT): {$(VPATH)}internal/variable.h
-eval.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-eval.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-eval.$(OBJEXT): {$(VPATH)}io.h
-eval.$(OBJEXT): {$(VPATH)}iseq.h
-eval.$(OBJEXT): {$(VPATH)}method.h
-eval.$(OBJEXT): {$(VPATH)}missing.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/diagnostic.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)}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
-eval.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-eval.$(OBJEXT): {$(VPATH)}thread_native.h
-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
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-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
-file.$(OBJEXT): $(top_srcdir)/internal/dir.h
-file.$(OBJEXT): $(top_srcdir)/internal/error.h
-file.$(OBJEXT): $(top_srcdir)/internal/file.h
-file.$(OBJEXT): $(top_srcdir)/internal/gc.h
-file.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-file.$(OBJEXT): $(top_srcdir)/internal/io.h
-file.$(OBJEXT): $(top_srcdir)/internal/load.h
-file.$(OBJEXT): $(top_srcdir)/internal/object.h
-file.$(OBJEXT): $(top_srcdir)/internal/process.h
-file.$(OBJEXT): $(top_srcdir)/internal/serial.h
-file.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-file.$(OBJEXT): $(top_srcdir)/internal/string.h
-file.$(OBJEXT): $(top_srcdir)/internal/thread.h
-file.$(OBJEXT): $(top_srcdir)/internal/variable.h
-file.$(OBJEXT): $(top_srcdir)/internal/vm.h
-file.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-file.$(OBJEXT): {$(VPATH)}assert.h
-file.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-file.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-file.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-file.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-file.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-file.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-file.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-file.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-file.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-file.$(OBJEXT): {$(VPATH)}config.h
-file.$(OBJEXT): {$(VPATH)}constant.h
-file.$(OBJEXT): {$(VPATH)}defines.h
-file.$(OBJEXT): {$(VPATH)}dln.h
-file.$(OBJEXT): {$(VPATH)}encindex.h
-file.$(OBJEXT): {$(VPATH)}encoding.h
-file.$(OBJEXT): {$(VPATH)}file.c
-file.$(OBJEXT): {$(VPATH)}id.h
-file.$(OBJEXT): {$(VPATH)}id_table.h
-file.$(OBJEXT): {$(VPATH)}intern.h
-file.$(OBJEXT): {$(VPATH)}internal.h
-file.$(OBJEXT): {$(VPATH)}internal/abi.h
-file.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-file.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-file.$(OBJEXT): {$(VPATH)}internal/assume.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-file.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-file.$(OBJEXT): {$(VPATH)}internal/cast.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-file.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-file.$(OBJEXT): {$(VPATH)}internal/config.h
-file.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-file.$(OBJEXT): {$(VPATH)}internal/core.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-file.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-file.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-file.$(OBJEXT): {$(VPATH)}internal/ctype.h
-file.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-file.$(OBJEXT): {$(VPATH)}internal/dosish.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-file.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-file.$(OBJEXT): {$(VPATH)}internal/error.h
-file.$(OBJEXT): {$(VPATH)}internal/eval.h
-file.$(OBJEXT): {$(VPATH)}internal/event.h
-file.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-file.$(OBJEXT): {$(VPATH)}internal/gc.h
-file.$(OBJEXT): {$(VPATH)}internal/glob.h
-file.$(OBJEXT): {$(VPATH)}internal/globals.h
-file.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-file.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-file.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-file.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-file.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-file.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-file.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-file.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-file.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-file.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-file.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-file.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-file.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-file.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-file.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-file.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-file.$(OBJEXT): {$(VPATH)}internal/symbol.h
-file.$(OBJEXT): {$(VPATH)}internal/value.h
-file.$(OBJEXT): {$(VPATH)}internal/value_type.h
-file.$(OBJEXT): {$(VPATH)}internal/variable.h
-file.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-file.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-file.$(OBJEXT): {$(VPATH)}io.h
-file.$(OBJEXT): {$(VPATH)}missing.h
-file.$(OBJEXT): {$(VPATH)}onigmo.h
-file.$(OBJEXT): {$(VPATH)}oniguruma.h
-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
-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)/gc/default/default.c
-gc.$(OBJEXT): $(top_srcdir)/gc/gc.h
-gc.$(OBJEXT): $(top_srcdir)/gc/gc_impl.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
-gc.$(OBJEXT): $(top_srcdir)/internal/error.h
-gc.$(OBJEXT): $(top_srcdir)/internal/eval.h
-gc.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-gc.$(OBJEXT): $(top_srcdir)/internal/gc.h
-gc.$(OBJEXT): $(top_srcdir)/internal/hash.h
-gc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-gc.$(OBJEXT): $(top_srcdir)/internal/io.h
-gc.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-gc.$(OBJEXT): $(top_srcdir)/internal/object.h
-gc.$(OBJEXT): $(top_srcdir)/internal/proc.h
-gc.$(OBJEXT): $(top_srcdir)/internal/rational.h
-gc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-gc.$(OBJEXT): $(top_srcdir)/internal/serial.h
-gc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-gc.$(OBJEXT): $(top_srcdir)/internal/string.h
-gc.$(OBJEXT): $(top_srcdir)/internal/struct.h
-gc.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-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/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/static_literals.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_integer.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_string.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
-gc.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-gc.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-gc.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-gc.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-gc.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-gc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-gc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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.rbinc
-gc.$(OBJEXT): {$(VPATH)}id.h
-gc.$(OBJEXT): {$(VPATH)}id_table.h
-gc.$(OBJEXT): {$(VPATH)}intern.h
-gc.$(OBJEXT): {$(VPATH)}internal.h
-gc.$(OBJEXT): {$(VPATH)}internal/abi.h
-gc.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-gc.$(OBJEXT): {$(VPATH)}internal/assume.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-gc.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-gc.$(OBJEXT): {$(VPATH)}internal/cast.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-gc.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-gc.$(OBJEXT): {$(VPATH)}internal/config.h
-gc.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-gc.$(OBJEXT): {$(VPATH)}internal/core.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-gc.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-gc.$(OBJEXT): {$(VPATH)}internal/ctype.h
-gc.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-gc.$(OBJEXT): {$(VPATH)}internal/dosish.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-gc.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-gc.$(OBJEXT): {$(VPATH)}internal/error.h
-gc.$(OBJEXT): {$(VPATH)}internal/eval.h
-gc.$(OBJEXT): {$(VPATH)}internal/event.h
-gc.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-gc.$(OBJEXT): {$(VPATH)}internal/gc.h
-gc.$(OBJEXT): {$(VPATH)}internal/glob.h
-gc.$(OBJEXT): {$(VPATH)}internal/globals.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-gc.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-gc.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-gc.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-gc.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-gc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-gc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-gc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-gc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-gc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-gc.$(OBJEXT): {$(VPATH)}internal/symbol.h
-gc.$(OBJEXT): {$(VPATH)}internal/value.h
-gc.$(OBJEXT): {$(VPATH)}internal/value_type.h
-gc.$(OBJEXT): {$(VPATH)}internal/variable.h
-gc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-gc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-gc.$(OBJEXT): {$(VPATH)}io.h
-gc.$(OBJEXT): {$(VPATH)}iseq.h
-gc.$(OBJEXT): {$(VPATH)}method.h
-gc.$(OBJEXT): {$(VPATH)}missing.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/diagnostic.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
-gc.$(OBJEXT): {$(VPATH)}ractor_core.h
-gc.$(OBJEXT): {$(VPATH)}re.h
-gc.$(OBJEXT): {$(VPATH)}regenc.h
-gc.$(OBJEXT): {$(VPATH)}regex.h
-gc.$(OBJEXT): {$(VPATH)}regint.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
-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)}util.h
-gc.$(OBJEXT): {$(VPATH)}variable.h
-gc.$(OBJEXT): {$(VPATH)}vm.h
-gc.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-gc.$(OBJEXT): {$(VPATH)}vm_core.h
-gc.$(OBJEXT): {$(VPATH)}vm_debug.h
-gc.$(OBJEXT): {$(VPATH)}vm_opts.h
-gc.$(OBJEXT): {$(VPATH)}vm_sync.h
-gc.$(OBJEXT): {$(VPATH)}yjit.h
-goruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-goruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-goruby.$(OBJEXT): $(CCAN_DIR)/list/list.h
-goruby.$(OBJEXT): $(CCAN_DIR)/str/str.h
-goruby.$(OBJEXT): $(hdrdir)/ruby.h
-goruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/array.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/bits.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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/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/static_literals.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_integer.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_string.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
-goruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-goruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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.rbbin
-goruby.$(OBJEXT): {$(VPATH)}goruby.c
-goruby.$(OBJEXT): {$(VPATH)}id.h
-goruby.$(OBJEXT): {$(VPATH)}id_table.h
-goruby.$(OBJEXT): {$(VPATH)}intern.h
-goruby.$(OBJEXT): {$(VPATH)}internal.h
-goruby.$(OBJEXT): {$(VPATH)}internal/abi.h
-goruby.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-goruby.$(OBJEXT): {$(VPATH)}internal/assume.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/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
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-goruby.$(OBJEXT): {$(VPATH)}internal/cast.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-goruby.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-goruby.$(OBJEXT): {$(VPATH)}internal/config.h
-goruby.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-goruby.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-goruby.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-goruby.$(OBJEXT): {$(VPATH)}internal/gc.h
-goruby.$(OBJEXT): {$(VPATH)}internal/glob.h
-goruby.$(OBJEXT): {$(VPATH)}internal/globals.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-goruby.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-goruby.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-goruby.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-goruby.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-goruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-goruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-goruby.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-goruby.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-goruby.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-goruby.$(OBJEXT): {$(VPATH)}internal/symbol.h
-goruby.$(OBJEXT): {$(VPATH)}internal/value.h
-goruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
-goruby.$(OBJEXT): {$(VPATH)}internal/variable.h
-goruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-goruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-goruby.$(OBJEXT): {$(VPATH)}iseq.h
-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/diagnostic.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
-goruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-goruby.$(OBJEXT): {$(VPATH)}thread_native.h
-goruby.$(OBJEXT): {$(VPATH)}vm_core.h
-goruby.$(OBJEXT): {$(VPATH)}vm_debug.h
-goruby.$(OBJEXT): {$(VPATH)}vm_opts.h
-hash.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-hash.$(OBJEXT): $(top_srcdir)/internal/bits.h
-hash.$(OBJEXT): $(top_srcdir)/internal/class.h
-hash.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-hash.$(OBJEXT): $(top_srcdir)/internal/cont.h
-hash.$(OBJEXT): $(top_srcdir)/internal/error.h
-hash.$(OBJEXT): $(top_srcdir)/internal/gc.h
-hash.$(OBJEXT): $(top_srcdir)/internal/hash.h
-hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-hash.$(OBJEXT): $(top_srcdir)/internal/object.h
-hash.$(OBJEXT): $(top_srcdir)/internal/proc.h
-hash.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-hash.$(OBJEXT): $(top_srcdir)/internal/serial.h
-hash.$(OBJEXT): $(top_srcdir)/internal/st.h
-hash.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-hash.$(OBJEXT): $(top_srcdir)/internal/string.h
-hash.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-hash.$(OBJEXT): $(top_srcdir)/internal/thread.h
-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/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/static_literals.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_integer.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_string.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
-hash.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-hash.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-hash.$(OBJEXT): {$(VPATH)}builtin.h
-hash.$(OBJEXT): {$(VPATH)}config.h
-hash.$(OBJEXT): {$(VPATH)}constant.h
-hash.$(OBJEXT): {$(VPATH)}debug_counter.h
-hash.$(OBJEXT): {$(VPATH)}defines.h
-hash.$(OBJEXT): {$(VPATH)}encoding.h
-hash.$(OBJEXT): {$(VPATH)}hash.c
-hash.$(OBJEXT): {$(VPATH)}hash.rbinc
-hash.$(OBJEXT): {$(VPATH)}id.h
-hash.$(OBJEXT): {$(VPATH)}id_table.h
-hash.$(OBJEXT): {$(VPATH)}intern.h
-hash.$(OBJEXT): {$(VPATH)}internal.h
-hash.$(OBJEXT): {$(VPATH)}internal/abi.h
-hash.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-hash.$(OBJEXT): {$(VPATH)}internal/assume.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-hash.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-hash.$(OBJEXT): {$(VPATH)}internal/cast.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-hash.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-hash.$(OBJEXT): {$(VPATH)}internal/config.h
-hash.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-hash.$(OBJEXT): {$(VPATH)}internal/core.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-hash.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-hash.$(OBJEXT): {$(VPATH)}internal/ctype.h
-hash.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-hash.$(OBJEXT): {$(VPATH)}internal/dosish.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-hash.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-hash.$(OBJEXT): {$(VPATH)}internal/error.h
-hash.$(OBJEXT): {$(VPATH)}internal/eval.h
-hash.$(OBJEXT): {$(VPATH)}internal/event.h
-hash.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-hash.$(OBJEXT): {$(VPATH)}internal/gc.h
-hash.$(OBJEXT): {$(VPATH)}internal/glob.h
-hash.$(OBJEXT): {$(VPATH)}internal/globals.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-hash.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-hash.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-hash.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-hash.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-hash.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-hash.$(OBJEXT): {$(VPATH)}internal/st.h
-hash.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-hash.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-hash.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-hash.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-hash.$(OBJEXT): {$(VPATH)}internal/symbol.h
-hash.$(OBJEXT): {$(VPATH)}internal/value.h
-hash.$(OBJEXT): {$(VPATH)}internal/value_type.h
-hash.$(OBJEXT): {$(VPATH)}internal/variable.h
-hash.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-hash.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-hash.$(OBJEXT): {$(VPATH)}iseq.h
-hash.$(OBJEXT): {$(VPATH)}method.h
-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/diagnostic.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)}util.h
-hash.$(OBJEXT): {$(VPATH)}vm_core.h
-hash.$(OBJEXT): {$(VPATH)}vm_debug.h
-hash.$(OBJEXT): {$(VPATH)}vm_opts.h
-hash.$(OBJEXT): {$(VPATH)}vm_sync.h
-imemo.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-imemo.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-imemo.$(OBJEXT): $(CCAN_DIR)/list/list.h
-imemo.$(OBJEXT): $(CCAN_DIR)/str/str.h
-imemo.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/array.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/class.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/gc.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/serial.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/variable.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/vm.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-imemo.$(OBJEXT): {$(VPATH)}assert.h
-imemo.$(OBJEXT): {$(VPATH)}atomic.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-imemo.$(OBJEXT): {$(VPATH)}config.h
-imemo.$(OBJEXT): {$(VPATH)}constant.h
-imemo.$(OBJEXT): {$(VPATH)}debug_counter.h
-imemo.$(OBJEXT): {$(VPATH)}defines.h
-imemo.$(OBJEXT): {$(VPATH)}encoding.h
-imemo.$(OBJEXT): {$(VPATH)}id.h
-imemo.$(OBJEXT): {$(VPATH)}id_table.h
-imemo.$(OBJEXT): {$(VPATH)}imemo.c
-imemo.$(OBJEXT): {$(VPATH)}intern.h
-imemo.$(OBJEXT): {$(VPATH)}internal.h
-imemo.$(OBJEXT): {$(VPATH)}internal/abi.h
-imemo.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/assume.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-imemo.$(OBJEXT): {$(VPATH)}internal/cast.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-imemo.$(OBJEXT): {$(VPATH)}internal/config.h
-imemo.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-imemo.$(OBJEXT): {$(VPATH)}internal/ctype.h
-imemo.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-imemo.$(OBJEXT): {$(VPATH)}internal/dosish.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-imemo.$(OBJEXT): {$(VPATH)}internal/error.h
-imemo.$(OBJEXT): {$(VPATH)}internal/eval.h
-imemo.$(OBJEXT): {$(VPATH)}internal/event.h
-imemo.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-imemo.$(OBJEXT): {$(VPATH)}internal/gc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/glob.h
-imemo.$(OBJEXT): {$(VPATH)}internal/globals.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-imemo.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-imemo.$(OBJEXT): {$(VPATH)}internal/iterator.h
-imemo.$(OBJEXT): {$(VPATH)}internal/memory.h
-imemo.$(OBJEXT): {$(VPATH)}internal/method.h
-imemo.$(OBJEXT): {$(VPATH)}internal/module.h
-imemo.$(OBJEXT): {$(VPATH)}internal/newobj.h
-imemo.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-imemo.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-imemo.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-imemo.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-imemo.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-imemo.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-imemo.$(OBJEXT): {$(VPATH)}internal/symbol.h
-imemo.$(OBJEXT): {$(VPATH)}internal/value.h
-imemo.$(OBJEXT): {$(VPATH)}internal/value_type.h
-imemo.$(OBJEXT): {$(VPATH)}internal/variable.h
-imemo.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-imemo.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-imemo.$(OBJEXT): {$(VPATH)}method.h
-imemo.$(OBJEXT): {$(VPATH)}missing.h
-imemo.$(OBJEXT): {$(VPATH)}node.h
-imemo.$(OBJEXT): {$(VPATH)}onigmo.h
-imemo.$(OBJEXT): {$(VPATH)}oniguruma.h
-imemo.$(OBJEXT): {$(VPATH)}ruby_assert.h
-imemo.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-imemo.$(OBJEXT): {$(VPATH)}rubyparser.h
-imemo.$(OBJEXT): {$(VPATH)}shape.h
-imemo.$(OBJEXT): {$(VPATH)}st.h
-imemo.$(OBJEXT): {$(VPATH)}subst.h
-imemo.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-imemo.$(OBJEXT): {$(VPATH)}thread_native.h
-imemo.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-imemo.$(OBJEXT): {$(VPATH)}vm_core.h
-imemo.$(OBJEXT): {$(VPATH)}vm_debug.h
-imemo.$(OBJEXT): {$(VPATH)}vm_opts.h
-imemo.$(OBJEXT): {$(VPATH)}vm_sync.h
-inits.$(OBJEXT): $(hdrdir)/ruby.h
-inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-inits.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-inits.$(OBJEXT): $(top_srcdir)/internal/inits.h
-inits.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-inits.$(OBJEXT): {$(VPATH)}assert.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-inits.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-inits.$(OBJEXT): {$(VPATH)}builtin.h
-inits.$(OBJEXT): {$(VPATH)}config.h
-inits.$(OBJEXT): {$(VPATH)}defines.h
-inits.$(OBJEXT): {$(VPATH)}inits.c
-inits.$(OBJEXT): {$(VPATH)}intern.h
-inits.$(OBJEXT): {$(VPATH)}internal/abi.h
-inits.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-inits.$(OBJEXT): {$(VPATH)}internal/assume.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-inits.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-inits.$(OBJEXT): {$(VPATH)}internal/cast.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-inits.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-inits.$(OBJEXT): {$(VPATH)}internal/config.h
-inits.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-inits.$(OBJEXT): {$(VPATH)}internal/core.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-inits.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-inits.$(OBJEXT): {$(VPATH)}internal/ctype.h
-inits.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-inits.$(OBJEXT): {$(VPATH)}internal/dosish.h
-inits.$(OBJEXT): {$(VPATH)}internal/error.h
-inits.$(OBJEXT): {$(VPATH)}internal/eval.h
-inits.$(OBJEXT): {$(VPATH)}internal/event.h
-inits.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-inits.$(OBJEXT): {$(VPATH)}internal/gc.h
-inits.$(OBJEXT): {$(VPATH)}internal/glob.h
-inits.$(OBJEXT): {$(VPATH)}internal/globals.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-inits.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-inits.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-inits.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-inits.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-inits.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-inits.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-inits.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-inits.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-inits.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-inits.$(OBJEXT): {$(VPATH)}internal/symbol.h
-inits.$(OBJEXT): {$(VPATH)}internal/value.h
-inits.$(OBJEXT): {$(VPATH)}internal/value_type.h
-inits.$(OBJEXT): {$(VPATH)}internal/variable.h
-inits.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-inits.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-inits.$(OBJEXT): {$(VPATH)}missing.h
-inits.$(OBJEXT): {$(VPATH)}prelude.rbinc
-inits.$(OBJEXT): {$(VPATH)}st.h
-inits.$(OBJEXT): {$(VPATH)}subst.h
-io.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-io.$(OBJEXT): $(top_srcdir)/internal/bits.h
-io.$(OBJEXT): $(top_srcdir)/internal/class.h
-io.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-io.$(OBJEXT): $(top_srcdir)/internal/encoding.h
-io.$(OBJEXT): $(top_srcdir)/internal/error.h
-io.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-io.$(OBJEXT): $(top_srcdir)/internal/gc.h
-io.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-io.$(OBJEXT): $(top_srcdir)/internal/inits.h
-io.$(OBJEXT): $(top_srcdir)/internal/io.h
-io.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-io.$(OBJEXT): $(top_srcdir)/internal/object.h
-io.$(OBJEXT): $(top_srcdir)/internal/process.h
-io.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-io.$(OBJEXT): $(top_srcdir)/internal/serial.h
-io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-io.$(OBJEXT): $(top_srcdir)/internal/string.h
-io.$(OBJEXT): $(top_srcdir)/internal/thread.h
-io.$(OBJEXT): $(top_srcdir)/internal/transcode.h
-io.$(OBJEXT): $(top_srcdir)/internal/variable.h
-io.$(OBJEXT): $(top_srcdir)/internal/vm.h
-io.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-io.$(OBJEXT): {$(VPATH)}assert.h
-io.$(OBJEXT): {$(VPATH)}atomic.h
-io.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-io.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-io.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-io.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-io.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-io.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-io.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-io.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-io.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-io.$(OBJEXT): {$(VPATH)}builtin.h
-io.$(OBJEXT): {$(VPATH)}config.h
-io.$(OBJEXT): {$(VPATH)}constant.h
-io.$(OBJEXT): {$(VPATH)}debug_counter.h
-io.$(OBJEXT): {$(VPATH)}defines.h
-io.$(OBJEXT): {$(VPATH)}dln.h
-io.$(OBJEXT): {$(VPATH)}encindex.h
-io.$(OBJEXT): {$(VPATH)}encoding.h
-io.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
-io.$(OBJEXT): {$(VPATH)}id.h
-io.$(OBJEXT): {$(VPATH)}id_table.h
-io.$(OBJEXT): {$(VPATH)}intern.h
-io.$(OBJEXT): {$(VPATH)}internal.h
-io.$(OBJEXT): {$(VPATH)}internal/abi.h
-io.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-io.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-io.$(OBJEXT): {$(VPATH)}internal/assume.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-io.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-io.$(OBJEXT): {$(VPATH)}internal/cast.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-io.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-io.$(OBJEXT): {$(VPATH)}internal/config.h
-io.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-io.$(OBJEXT): {$(VPATH)}internal/core.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-io.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-io.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-io.$(OBJEXT): {$(VPATH)}internal/ctype.h
-io.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-io.$(OBJEXT): {$(VPATH)}internal/dosish.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-io.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-io.$(OBJEXT): {$(VPATH)}internal/error.h
-io.$(OBJEXT): {$(VPATH)}internal/eval.h
-io.$(OBJEXT): {$(VPATH)}internal/event.h
-io.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-io.$(OBJEXT): {$(VPATH)}internal/gc.h
-io.$(OBJEXT): {$(VPATH)}internal/glob.h
-io.$(OBJEXT): {$(VPATH)}internal/globals.h
-io.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-io.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-io.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-io.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-io.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-io.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-io.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-io.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-io.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-io.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-io.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-io.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-io.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-io.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-io.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-io.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-io.$(OBJEXT): {$(VPATH)}internal/symbol.h
-io.$(OBJEXT): {$(VPATH)}internal/value.h
-io.$(OBJEXT): {$(VPATH)}internal/value_type.h
-io.$(OBJEXT): {$(VPATH)}internal/variable.h
-io.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-io.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-io.$(OBJEXT): {$(VPATH)}io.c
-io.$(OBJEXT): {$(VPATH)}io.h
-io.$(OBJEXT): {$(VPATH)}io.rbinc
-io.$(OBJEXT): {$(VPATH)}io/buffer.h
-io.$(OBJEXT): {$(VPATH)}method.h
-io.$(OBJEXT): {$(VPATH)}missing.h
-io.$(OBJEXT): {$(VPATH)}node.h
-io.$(OBJEXT): {$(VPATH)}onigmo.h
-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
-io.$(OBJEXT): {$(VPATH)}thread.h
-io.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-io.$(OBJEXT): {$(VPATH)}thread_native.h
-io.$(OBJEXT): {$(VPATH)}util.h
-io.$(OBJEXT): {$(VPATH)}vm_core.h
-io.$(OBJEXT): {$(VPATH)}vm_debug.h
-io.$(OBJEXT): {$(VPATH)}vm_opts.h
-io.$(OBJEXT): {$(VPATH)}vm_sync.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/basic_operators.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/error.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/gc.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/io.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/serial.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/string.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/thread.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/vm.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-io_buffer.$(OBJEXT): {$(VPATH)}assert.h
-io_buffer.$(OBJEXT): {$(VPATH)}atomic.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-io_buffer.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-io_buffer.$(OBJEXT): {$(VPATH)}config.h
-io_buffer.$(OBJEXT): {$(VPATH)}defines.h
-io_buffer.$(OBJEXT): {$(VPATH)}encoding.h
-io_buffer.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
-io_buffer.$(OBJEXT): {$(VPATH)}id.h
-io_buffer.$(OBJEXT): {$(VPATH)}intern.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/abi.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/assume.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/cast.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/config.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/ctype.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/dosish.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/error.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/eval.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/event.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/gc.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/glob.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/globals.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/symbol.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/value.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/value_type.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/variable.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-io_buffer.$(OBJEXT): {$(VPATH)}io.h
-io_buffer.$(OBJEXT): {$(VPATH)}io/buffer.h
-io_buffer.$(OBJEXT): {$(VPATH)}io_buffer.c
-io_buffer.$(OBJEXT): {$(VPATH)}method.h
-io_buffer.$(OBJEXT): {$(VPATH)}missing.h
-io_buffer.$(OBJEXT): {$(VPATH)}node.h
-io_buffer.$(OBJEXT): {$(VPATH)}onigmo.h
-io_buffer.$(OBJEXT): {$(VPATH)}oniguruma.h
-io_buffer.$(OBJEXT): {$(VPATH)}ruby_assert.h
-io_buffer.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-io_buffer.$(OBJEXT): {$(VPATH)}rubyparser.h
-io_buffer.$(OBJEXT): {$(VPATH)}st.h
-io_buffer.$(OBJEXT): {$(VPATH)}subst.h
-io_buffer.$(OBJEXT): {$(VPATH)}thread.h
-io_buffer.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-io_buffer.$(OBJEXT): {$(VPATH)}thread_native.h
-io_buffer.$(OBJEXT): {$(VPATH)}vm_core.h
-io_buffer.$(OBJEXT): {$(VPATH)}vm_opts.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/bignum.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/bits.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/class.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/compile.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/complex.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/error.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/file.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-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/io.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/rational.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
-iseq.$(OBJEXT): $(top_srcdir)/internal/string.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-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/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/static_literals.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_integer.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_string.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
-iseq.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-iseq.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-iseq.$(OBJEXT): {$(VPATH)}builtin.h
-iseq.$(OBJEXT): {$(VPATH)}config.h
-iseq.$(OBJEXT): {$(VPATH)}constant.h
-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)}id.h
-iseq.$(OBJEXT): {$(VPATH)}id_table.h
-iseq.$(OBJEXT): {$(VPATH)}insns.def
-iseq.$(OBJEXT): {$(VPATH)}insns.inc
-iseq.$(OBJEXT): {$(VPATH)}insns_info.inc
-iseq.$(OBJEXT): {$(VPATH)}intern.h
-iseq.$(OBJEXT): {$(VPATH)}internal.h
-iseq.$(OBJEXT): {$(VPATH)}internal/abi.h
-iseq.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-iseq.$(OBJEXT): {$(VPATH)}internal/assume.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-iseq.$(OBJEXT): {$(VPATH)}internal/cast.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-iseq.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-iseq.$(OBJEXT): {$(VPATH)}internal/config.h
-iseq.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-iseq.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-iseq.$(OBJEXT): {$(VPATH)}internal/ctype.h
-iseq.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-iseq.$(OBJEXT): {$(VPATH)}internal/dosish.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-iseq.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-iseq.$(OBJEXT): {$(VPATH)}internal/error.h
-iseq.$(OBJEXT): {$(VPATH)}internal/eval.h
-iseq.$(OBJEXT): {$(VPATH)}internal/event.h
-iseq.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-iseq.$(OBJEXT): {$(VPATH)}internal/gc.h
-iseq.$(OBJEXT): {$(VPATH)}internal/glob.h
-iseq.$(OBJEXT): {$(VPATH)}internal/globals.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-iseq.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-iseq.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-iseq.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-iseq.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-iseq.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-iseq.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-iseq.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-iseq.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-iseq.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-iseq.$(OBJEXT): {$(VPATH)}internal/symbol.h
-iseq.$(OBJEXT): {$(VPATH)}internal/value.h
-iseq.$(OBJEXT): {$(VPATH)}internal/value_type.h
-iseq.$(OBJEXT): {$(VPATH)}internal/variable.h
-iseq.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-iseq.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-iseq.$(OBJEXT): {$(VPATH)}io.h
-iseq.$(OBJEXT): {$(VPATH)}iseq.c
-iseq.$(OBJEXT): {$(VPATH)}iseq.h
-iseq.$(OBJEXT): {$(VPATH)}method.h
-iseq.$(OBJEXT): {$(VPATH)}missing.h
-iseq.$(OBJEXT): {$(VPATH)}node.h
-iseq.$(OBJEXT): {$(VPATH)}onigmo.h
-iseq.$(OBJEXT): {$(VPATH)}oniguruma.h
-iseq.$(OBJEXT): {$(VPATH)}prism/ast.h
-iseq.$(OBJEXT): {$(VPATH)}prism/diagnostic.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)}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
-iseq.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-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/bignum.h
-load.$(OBJEXT): $(top_srcdir)/internal/bits.h
-load.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-load.$(OBJEXT): $(top_srcdir)/internal/complex.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/fixnum.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/numeric.h
-load.$(OBJEXT): $(top_srcdir)/internal/parse.h
-load.$(OBJEXT): $(top_srcdir)/internal/rational.h
-load.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-load.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-load.$(OBJEXT): $(top_srcdir)/internal/serial.h
-load.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-load.$(OBJEXT): $(top_srcdir)/internal/string.h
-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/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/static_literals.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_integer.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_string.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
-load.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-load.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-load.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-load.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-load.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-load.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-load.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-load.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-load.$(OBJEXT): {$(VPATH)}config.h
-load.$(OBJEXT): {$(VPATH)}constant.h
-load.$(OBJEXT): {$(VPATH)}darray.h
-load.$(OBJEXT): {$(VPATH)}defines.h
-load.$(OBJEXT): {$(VPATH)}dln.h
-load.$(OBJEXT): {$(VPATH)}encoding.h
-load.$(OBJEXT): {$(VPATH)}eval_intern.h
-load.$(OBJEXT): {$(VPATH)}id.h
-load.$(OBJEXT): {$(VPATH)}id_table.h
-load.$(OBJEXT): {$(VPATH)}intern.h
-load.$(OBJEXT): {$(VPATH)}internal.h
-load.$(OBJEXT): {$(VPATH)}internal/abi.h
-load.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-load.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-load.$(OBJEXT): {$(VPATH)}internal/assume.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-load.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-load.$(OBJEXT): {$(VPATH)}internal/cast.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-load.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-load.$(OBJEXT): {$(VPATH)}internal/config.h
-load.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-load.$(OBJEXT): {$(VPATH)}internal/core.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-load.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-load.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-load.$(OBJEXT): {$(VPATH)}internal/ctype.h
-load.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-load.$(OBJEXT): {$(VPATH)}internal/dosish.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-load.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-load.$(OBJEXT): {$(VPATH)}internal/error.h
-load.$(OBJEXT): {$(VPATH)}internal/eval.h
-load.$(OBJEXT): {$(VPATH)}internal/event.h
-load.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-load.$(OBJEXT): {$(VPATH)}internal/gc.h
-load.$(OBJEXT): {$(VPATH)}internal/glob.h
-load.$(OBJEXT): {$(VPATH)}internal/globals.h
-load.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-load.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-load.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-load.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-load.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-load.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-load.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-load.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-load.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-load.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-load.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-load.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-load.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-load.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-load.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-load.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-load.$(OBJEXT): {$(VPATH)}internal/symbol.h
-load.$(OBJEXT): {$(VPATH)}internal/value.h
-load.$(OBJEXT): {$(VPATH)}internal/value_type.h
-load.$(OBJEXT): {$(VPATH)}internal/variable.h
-load.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-load.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-load.$(OBJEXT): {$(VPATH)}iseq.h
-load.$(OBJEXT): {$(VPATH)}load.c
-load.$(OBJEXT): {$(VPATH)}method.h
-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/diagnostic.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)}ractor.h
-load.$(OBJEXT): {$(VPATH)}ractor_core.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
-load.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-load.$(OBJEXT): {$(VPATH)}thread_native.h
-load.$(OBJEXT): {$(VPATH)}util.h
-load.$(OBJEXT): {$(VPATH)}vm_core.h
-load.$(OBJEXT): {$(VPATH)}vm_debug.h
-load.$(OBJEXT): {$(VPATH)}vm_opts.h
-loadpath.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-loadpath.$(OBJEXT): $(hdrdir)/ruby/version.h
-loadpath.$(OBJEXT): $(top_srcdir)/version.h
-loadpath.$(OBJEXT): {$(VPATH)}assert.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-loadpath.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-loadpath.$(OBJEXT): {$(VPATH)}config.h
-loadpath.$(OBJEXT): {$(VPATH)}defines.h
-loadpath.$(OBJEXT): {$(VPATH)}intern.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/abi.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/assume.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/cast.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/config.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/ctype.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/dosish.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/error.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/eval.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/event.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/gc.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/glob.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/globals.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/symbol.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/value.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/value_type.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/variable.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-loadpath.$(OBJEXT): {$(VPATH)}loadpath.c
-loadpath.$(OBJEXT): {$(VPATH)}missing.h
-loadpath.$(OBJEXT): {$(VPATH)}st.h
-loadpath.$(OBJEXT): {$(VPATH)}subst.h
-loadpath.$(OBJEXT): {$(VPATH)}verconf.h
-localeinit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-localeinit.$(OBJEXT): {$(VPATH)}assert.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-localeinit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-localeinit.$(OBJEXT): {$(VPATH)}config.h
-localeinit.$(OBJEXT): {$(VPATH)}defines.h
-localeinit.$(OBJEXT): {$(VPATH)}encindex.h
-localeinit.$(OBJEXT): {$(VPATH)}encoding.h
-localeinit.$(OBJEXT): {$(VPATH)}intern.h
-localeinit.$(OBJEXT): {$(VPATH)}internal.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/abi.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/assume.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/cast.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/config.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/ctype.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/dosish.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/error.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/eval.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/event.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/gc.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/glob.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/globals.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/symbol.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/value.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/value_type.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/variable.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-localeinit.$(OBJEXT): {$(VPATH)}localeinit.c
-localeinit.$(OBJEXT): {$(VPATH)}missing.h
-localeinit.$(OBJEXT): {$(VPATH)}onigmo.h
-localeinit.$(OBJEXT): {$(VPATH)}oniguruma.h
-localeinit.$(OBJEXT): {$(VPATH)}st.h
-localeinit.$(OBJEXT): {$(VPATH)}subst.h
-main.$(OBJEXT): $(hdrdir)/ruby.h
-main.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-main.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-main.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-main.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-main.$(OBJEXT): {$(VPATH)}assert.h
-main.$(OBJEXT): {$(VPATH)}backward.h
-main.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-main.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-main.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-main.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-main.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-main.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-main.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-main.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-main.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-main.$(OBJEXT): {$(VPATH)}config.h
-main.$(OBJEXT): {$(VPATH)}defines.h
-main.$(OBJEXT): {$(VPATH)}intern.h
-main.$(OBJEXT): {$(VPATH)}internal/abi.h
-main.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-main.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-main.$(OBJEXT): {$(VPATH)}internal/assume.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-main.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-main.$(OBJEXT): {$(VPATH)}internal/cast.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-main.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-main.$(OBJEXT): {$(VPATH)}internal/config.h
-main.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-main.$(OBJEXT): {$(VPATH)}internal/core.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-main.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-main.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-main.$(OBJEXT): {$(VPATH)}internal/ctype.h
-main.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-main.$(OBJEXT): {$(VPATH)}internal/dosish.h
-main.$(OBJEXT): {$(VPATH)}internal/error.h
-main.$(OBJEXT): {$(VPATH)}internal/eval.h
-main.$(OBJEXT): {$(VPATH)}internal/event.h
-main.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-main.$(OBJEXT): {$(VPATH)}internal/gc.h
-main.$(OBJEXT): {$(VPATH)}internal/glob.h
-main.$(OBJEXT): {$(VPATH)}internal/globals.h
-main.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-main.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-main.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-main.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-main.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-main.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-main.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-main.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-main.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-main.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-main.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-main.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-main.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-main.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-main.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-main.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-main.$(OBJEXT): {$(VPATH)}internal/symbol.h
-main.$(OBJEXT): {$(VPATH)}internal/value.h
-main.$(OBJEXT): {$(VPATH)}internal/value_type.h
-main.$(OBJEXT): {$(VPATH)}internal/variable.h
-main.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-main.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-main.$(OBJEXT): {$(VPATH)}main.c
-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
-marshal.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/encoding.h
-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/sanitizers.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/string.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/struct.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/util.h
-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
-marshal.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-marshal.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-marshal.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-marshal.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-marshal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-marshal.$(OBJEXT): {$(VPATH)}internal/abi.h
-marshal.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-marshal.$(OBJEXT): {$(VPATH)}internal/assume.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/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
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-marshal.$(OBJEXT): {$(VPATH)}internal/cast.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-marshal.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-marshal.$(OBJEXT): {$(VPATH)}internal/config.h
-marshal.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-marshal.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-marshal.$(OBJEXT): {$(VPATH)}internal/ctype.h
-marshal.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-marshal.$(OBJEXT): {$(VPATH)}internal/dosish.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-marshal.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-marshal.$(OBJEXT): {$(VPATH)}internal/error.h
-marshal.$(OBJEXT): {$(VPATH)}internal/eval.h
-marshal.$(OBJEXT): {$(VPATH)}internal/event.h
-marshal.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-marshal.$(OBJEXT): {$(VPATH)}internal/gc.h
-marshal.$(OBJEXT): {$(VPATH)}internal/glob.h
-marshal.$(OBJEXT): {$(VPATH)}internal/globals.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-marshal.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-marshal.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-marshal.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-marshal.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-marshal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-marshal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-marshal.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-marshal.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-marshal.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-marshal.$(OBJEXT): {$(VPATH)}internal/symbol.h
-marshal.$(OBJEXT): {$(VPATH)}internal/value.h
-marshal.$(OBJEXT): {$(VPATH)}internal/value_type.h
-marshal.$(OBJEXT): {$(VPATH)}internal/variable.h
-marshal.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-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
-math.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-math.$(OBJEXT): $(top_srcdir)/internal/complex.h
-math.$(OBJEXT): $(top_srcdir)/internal/gc.h
-math.$(OBJEXT): $(top_srcdir)/internal/math.h
-math.$(OBJEXT): $(top_srcdir)/internal/object.h
-math.$(OBJEXT): $(top_srcdir)/internal/serial.h
-math.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-math.$(OBJEXT): $(top_srcdir)/internal/variable.h
-math.$(OBJEXT): $(top_srcdir)/internal/vm.h
-math.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-math.$(OBJEXT): {$(VPATH)}assert.h
-math.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-math.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-math.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-math.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-math.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-math.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-math.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-math.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-math.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-math.$(OBJEXT): {$(VPATH)}config.h
-math.$(OBJEXT): {$(VPATH)}constant.h
-math.$(OBJEXT): {$(VPATH)}defines.h
-math.$(OBJEXT): {$(VPATH)}id_table.h
-math.$(OBJEXT): {$(VPATH)}intern.h
-math.$(OBJEXT): {$(VPATH)}internal.h
-math.$(OBJEXT): {$(VPATH)}internal/abi.h
-math.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-math.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-math.$(OBJEXT): {$(VPATH)}internal/assume.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-math.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-math.$(OBJEXT): {$(VPATH)}internal/cast.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-math.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-math.$(OBJEXT): {$(VPATH)}internal/config.h
-math.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-math.$(OBJEXT): {$(VPATH)}internal/core.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-math.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-math.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-math.$(OBJEXT): {$(VPATH)}internal/ctype.h
-math.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-math.$(OBJEXT): {$(VPATH)}internal/dosish.h
-math.$(OBJEXT): {$(VPATH)}internal/error.h
-math.$(OBJEXT): {$(VPATH)}internal/eval.h
-math.$(OBJEXT): {$(VPATH)}internal/event.h
-math.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-math.$(OBJEXT): {$(VPATH)}internal/gc.h
-math.$(OBJEXT): {$(VPATH)}internal/glob.h
-math.$(OBJEXT): {$(VPATH)}internal/globals.h
-math.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-math.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-math.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-math.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-math.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-math.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-math.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-math.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-math.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-math.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-math.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-math.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-math.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-math.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-math.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-math.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-math.$(OBJEXT): {$(VPATH)}internal/symbol.h
-math.$(OBJEXT): {$(VPATH)}internal/value.h
-math.$(OBJEXT): {$(VPATH)}internal/value_type.h
-math.$(OBJEXT): {$(VPATH)}internal/variable.h
-math.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-math.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-math.$(OBJEXT): {$(VPATH)}math.c
-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/sanitizers.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
-memory_view.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-memory_view.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-memory_view.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-memory_view.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-memory_view.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-memory_view.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-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
-memory_view.$(OBJEXT): {$(VPATH)}internal/abi.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/assume.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/cast.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/config.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-memory_view.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/gc.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/glob.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/globals.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/symbol.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/value.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/value_type.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/variable.h
-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): $(top_srcdir)/internal/array.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/bits.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/complex.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/parse.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/rational.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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/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/static_literals.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_integer.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_string.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
-miniinit.$(OBJEXT): {$(VPATH)}atomic.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-miniinit.$(OBJEXT): {$(VPATH)}builtin.h
-miniinit.$(OBJEXT): {$(VPATH)}config.h
-miniinit.$(OBJEXT): {$(VPATH)}constant.h
-miniinit.$(OBJEXT): {$(VPATH)}defines.h
-miniinit.$(OBJEXT): {$(VPATH)}dir.rb
-miniinit.$(OBJEXT): {$(VPATH)}encoding.h
-miniinit.$(OBJEXT): {$(VPATH)}gc.rb
-miniinit.$(OBJEXT): {$(VPATH)}gem_prelude.rb
-miniinit.$(OBJEXT): {$(VPATH)}id.h
-miniinit.$(OBJEXT): {$(VPATH)}id_table.h
-miniinit.$(OBJEXT): {$(VPATH)}intern.h
-miniinit.$(OBJEXT): {$(VPATH)}internal.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/abi.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/assume.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/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
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/cast.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/config.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/ctype.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/dosish.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/error.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/eval.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/event.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/gc.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/glob.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/globals.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/symbol.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/value.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/value_type.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/variable.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-miniinit.$(OBJEXT): {$(VPATH)}io.rb
-miniinit.$(OBJEXT): {$(VPATH)}iseq.h
-miniinit.$(OBJEXT): {$(VPATH)}kernel.rb
-miniinit.$(OBJEXT): {$(VPATH)}marshal.rb
-miniinit.$(OBJEXT): {$(VPATH)}method.h
-miniinit.$(OBJEXT): {$(VPATH)}mini_builtin.c
-miniinit.$(OBJEXT): {$(VPATH)}miniinit.c
-miniinit.$(OBJEXT): {$(VPATH)}miniprelude.c
-miniinit.$(OBJEXT): {$(VPATH)}missing.h
-miniinit.$(OBJEXT): {$(VPATH)}nilclass.rb
-miniinit.$(OBJEXT): {$(VPATH)}node.h
-miniinit.$(OBJEXT): {$(VPATH)}numeric.rb
-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/diagnostic.h
-miniinit.$(OBJEXT): {$(VPATH)}prism/version.h
-miniinit.$(OBJEXT): {$(VPATH)}prism_compile.h
-miniinit.$(OBJEXT): {$(VPATH)}ractor.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
-miniinit.$(OBJEXT): {$(VPATH)}symbol.rb
-miniinit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-miniinit.$(OBJEXT): {$(VPATH)}thread_native.h
-miniinit.$(OBJEXT): {$(VPATH)}thread_sync.rb
-miniinit.$(OBJEXT): {$(VPATH)}timev.rb
-miniinit.$(OBJEXT): {$(VPATH)}trace_point.rb
-miniinit.$(OBJEXT): {$(VPATH)}vm_core.h
-miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
-miniinit.$(OBJEXT): {$(VPATH)}warning.rb
-miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
-miniinit.$(OBJEXT): {$(VPATH)}yjit_hook.rb
-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
-node.$(OBJEXT): $(CCAN_DIR)/str/str.h
-node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-node.$(OBJEXT): $(top_srcdir)/internal/array.h
-node.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-node.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-node.$(OBJEXT): $(top_srcdir)/internal/gc.h
-node.$(OBJEXT): $(top_srcdir)/internal/hash.h
-node.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-node.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-node.$(OBJEXT): $(top_srcdir)/internal/serial.h
-node.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-node.$(OBJEXT): $(top_srcdir)/internal/variable.h
-node.$(OBJEXT): $(top_srcdir)/internal/vm.h
-node.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-node.$(OBJEXT): {$(VPATH)}assert.h
-node.$(OBJEXT): {$(VPATH)}atomic.h
-node.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-node.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-node.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-node.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-node.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-node.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-node.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-node.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-node.$(OBJEXT): {$(VPATH)}internal.h
-node.$(OBJEXT): {$(VPATH)}internal/abi.h
-node.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-node.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-node.$(OBJEXT): {$(VPATH)}internal/assume.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-node.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-node.$(OBJEXT): {$(VPATH)}internal/cast.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-node.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-node.$(OBJEXT): {$(VPATH)}internal/config.h
-node.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-node.$(OBJEXT): {$(VPATH)}internal/core.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-node.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-node.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-node.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-node.$(OBJEXT): {$(VPATH)}internal/gc.h
-node.$(OBJEXT): {$(VPATH)}internal/glob.h
-node.$(OBJEXT): {$(VPATH)}internal/globals.h
-node.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-node.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-node.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-node.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-node.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-node.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-node.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-node.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-node.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-node.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-node.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-node.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-node.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-node.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-node.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-node.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-node.$(OBJEXT): {$(VPATH)}internal/symbol.h
-node.$(OBJEXT): {$(VPATH)}internal/value.h
-node.$(OBJEXT): {$(VPATH)}internal/value_type.h
-node.$(OBJEXT): {$(VPATH)}internal/variable.h
-node.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-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
-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/bignum.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/bits.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/class.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/complex.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/fixnum.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/numeric.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/parse.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/rational.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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)}debug_counter.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/stdckdint.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_debug.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_sync.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
-numeric.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/complex.h
-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
-numeric.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/serial.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/string.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/util.h
-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
-numeric.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-numeric.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-numeric.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-numeric.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-numeric.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-numeric.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-numeric.$(OBJEXT): {$(VPATH)}builtin.h
-numeric.$(OBJEXT): {$(VPATH)}config.h
-numeric.$(OBJEXT): {$(VPATH)}constant.h
-numeric.$(OBJEXT): {$(VPATH)}defines.h
-numeric.$(OBJEXT): {$(VPATH)}encoding.h
-numeric.$(OBJEXT): {$(VPATH)}id.h
-numeric.$(OBJEXT): {$(VPATH)}id_table.h
-numeric.$(OBJEXT): {$(VPATH)}intern.h
-numeric.$(OBJEXT): {$(VPATH)}internal.h
-numeric.$(OBJEXT): {$(VPATH)}internal/abi.h
-numeric.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-numeric.$(OBJEXT): {$(VPATH)}internal/assume.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-numeric.$(OBJEXT): {$(VPATH)}internal/cast.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-numeric.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-numeric.$(OBJEXT): {$(VPATH)}internal/config.h
-numeric.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-numeric.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-numeric.$(OBJEXT): {$(VPATH)}internal/ctype.h
-numeric.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-numeric.$(OBJEXT): {$(VPATH)}internal/dosish.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-numeric.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-numeric.$(OBJEXT): {$(VPATH)}internal/error.h
-numeric.$(OBJEXT): {$(VPATH)}internal/eval.h
-numeric.$(OBJEXT): {$(VPATH)}internal/event.h
-numeric.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-numeric.$(OBJEXT): {$(VPATH)}internal/gc.h
-numeric.$(OBJEXT): {$(VPATH)}internal/glob.h
-numeric.$(OBJEXT): {$(VPATH)}internal/globals.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-numeric.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-numeric.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-numeric.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-numeric.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-numeric.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-numeric.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-numeric.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-numeric.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-numeric.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-numeric.$(OBJEXT): {$(VPATH)}internal/symbol.h
-numeric.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-object.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-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
-object.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-object.$(OBJEXT): $(top_srcdir)/internal/serial.h
-object.$(OBJEXT): $(top_srcdir)/internal/st.h
-object.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-object.$(OBJEXT): $(top_srcdir)/internal/string.h
-object.$(OBJEXT): $(top_srcdir)/internal/struct.h
-object.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-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
-object.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-object.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-object.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-object.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-object.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-object.$(OBJEXT): {$(VPATH)}id_table.h
-object.$(OBJEXT): {$(VPATH)}intern.h
-object.$(OBJEXT): {$(VPATH)}internal.h
-object.$(OBJEXT): {$(VPATH)}internal/abi.h
-object.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-object.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-object.$(OBJEXT): {$(VPATH)}internal/assume.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-object.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-object.$(OBJEXT): {$(VPATH)}internal/cast.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-object.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-object.$(OBJEXT): {$(VPATH)}internal/config.h
-object.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-object.$(OBJEXT): {$(VPATH)}internal/core.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-object.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-object.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-object.$(OBJEXT): {$(VPATH)}internal/ctype.h
-object.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-object.$(OBJEXT): {$(VPATH)}internal/dosish.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-object.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-object.$(OBJEXT): {$(VPATH)}internal/error.h
-object.$(OBJEXT): {$(VPATH)}internal/eval.h
-object.$(OBJEXT): {$(VPATH)}internal/event.h
-object.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-object.$(OBJEXT): {$(VPATH)}internal/gc.h
-object.$(OBJEXT): {$(VPATH)}internal/glob.h
-object.$(OBJEXT): {$(VPATH)}internal/globals.h
-object.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-object.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-object.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-object.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-object.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-object.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-object.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-object.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-object.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-object.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-object.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-object.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-object.$(OBJEXT): {$(VPATH)}internal/st.h
-object.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-object.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-object.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-object.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-object.$(OBJEXT): {$(VPATH)}internal/symbol.h
-object.$(OBJEXT): {$(VPATH)}internal/value.h
-object.$(OBJEXT): {$(VPATH)}internal/value_type.h
-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
-object.$(OBJEXT): {$(VPATH)}yjit.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/sanitizers.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
-pack.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-pack.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-pack.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-pack.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-pack.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-pack.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-pack.$(OBJEXT): {$(VPATH)}builtin.h
-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
-pack.$(OBJEXT): {$(VPATH)}internal/abi.h
-pack.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-pack.$(OBJEXT): {$(VPATH)}internal/assume.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-pack.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-pack.$(OBJEXT): {$(VPATH)}internal/cast.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-pack.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-pack.$(OBJEXT): {$(VPATH)}internal/config.h
-pack.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-pack.$(OBJEXT): {$(VPATH)}internal/core.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-pack.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-pack.$(OBJEXT): {$(VPATH)}internal/ctype.h
-pack.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-pack.$(OBJEXT): {$(VPATH)}internal/dosish.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-pack.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-pack.$(OBJEXT): {$(VPATH)}internal/error.h
-pack.$(OBJEXT): {$(VPATH)}internal/eval.h
-pack.$(OBJEXT): {$(VPATH)}internal/event.h
-pack.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-pack.$(OBJEXT): {$(VPATH)}internal/gc.h
-pack.$(OBJEXT): {$(VPATH)}internal/glob.h
-pack.$(OBJEXT): {$(VPATH)}internal/globals.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-pack.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-pack.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-pack.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-pack.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-pack.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-pack.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-pack.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-pack.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-pack.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-pack.$(OBJEXT): {$(VPATH)}internal/symbol.h
-pack.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-parse.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-parse.$(OBJEXT): $(top_srcdir)/internal/complex.h
-parse.$(OBJEXT): $(top_srcdir)/internal/encoding.h
-parse.$(OBJEXT): $(top_srcdir)/internal/error.h
-parse.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-parse.$(OBJEXT): $(top_srcdir)/internal/gc.h
-parse.$(OBJEXT): $(top_srcdir)/internal/hash.h
-parse.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-parse.$(OBJEXT): $(top_srcdir)/internal/io.h
-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/sanitizers.h
-parse.$(OBJEXT): $(top_srcdir)/internal/serial.h
-parse.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-parse.$(OBJEXT): $(top_srcdir)/internal/string.h
-parse.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-parse.$(OBJEXT): $(top_srcdir)/internal/thread.h
-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
-parse.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-parse.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-parse.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-parse.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-parse.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-parse.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-parse.$(OBJEXT): {$(VPATH)}config.h
-parse.$(OBJEXT): {$(VPATH)}constant.h
-parse.$(OBJEXT): {$(VPATH)}defines.h
-parse.$(OBJEXT): {$(VPATH)}defs/keywords
-parse.$(OBJEXT): {$(VPATH)}encoding.h
-parse.$(OBJEXT): {$(VPATH)}id.h
-parse.$(OBJEXT): {$(VPATH)}id_table.h
-parse.$(OBJEXT): {$(VPATH)}intern.h
-parse.$(OBJEXT): {$(VPATH)}internal.h
-parse.$(OBJEXT): {$(VPATH)}internal/abi.h
-parse.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-parse.$(OBJEXT): {$(VPATH)}internal/assume.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-parse.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-parse.$(OBJEXT): {$(VPATH)}internal/cast.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-parse.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-parse.$(OBJEXT): {$(VPATH)}internal/config.h
-parse.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-parse.$(OBJEXT): {$(VPATH)}internal/core.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-parse.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-parse.$(OBJEXT): {$(VPATH)}internal/ctype.h
-parse.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-parse.$(OBJEXT): {$(VPATH)}internal/dosish.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-parse.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-parse.$(OBJEXT): {$(VPATH)}internal/error.h
-parse.$(OBJEXT): {$(VPATH)}internal/eval.h
-parse.$(OBJEXT): {$(VPATH)}internal/event.h
-parse.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-parse.$(OBJEXT): {$(VPATH)}internal/gc.h
-parse.$(OBJEXT): {$(VPATH)}internal/glob.h
-parse.$(OBJEXT): {$(VPATH)}internal/globals.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-parse.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-parse.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-parse.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-parse.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-parse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-parse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-parse.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-parse.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-parse.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-parse.$(OBJEXT): {$(VPATH)}internal/symbol.h
-parse.$(OBJEXT): {$(VPATH)}internal/value.h
-parse.$(OBJEXT): {$(VPATH)}internal/value_type.h
-parse.$(OBJEXT): {$(VPATH)}internal/variable.h
-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
-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/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/static_literals.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_integer.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_string.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/stdckdint.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/diagnostic.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/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/static_literals.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_integer.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_string.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/stdckdint.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/diagnostic.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/util/pm_buffer.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/diagnostic.c
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/diagnostic.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/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/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/static_literals.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_integer.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_string.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/stdckdint.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/diagnostic.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/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/static_literals.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_integer.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_string.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)}prism/ast.h
-prism/node.$(OBJEXT): {$(VPATH)}prism/diagnostic.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_char.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.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/prettyprint.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.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_string.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.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/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/static_literals.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_integer.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_string.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)}prism/ast.h
-prism/prism.$(OBJEXT): {$(VPATH)}prism/diagnostic.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/options.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/static_literals.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.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_string.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/regexp.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/defines.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/static_literals.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_integer.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_string.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)}prism/ast.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/serialize.c
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.c
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/static_literals.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.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): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.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_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_integer.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.c
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.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_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_string.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.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_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_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/options.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.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_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)}prism/ast.h
-prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism/diagnostic.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/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/static_literals.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_integer.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_string.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/stdckdint.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/diagnostic.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
-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
-proc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-proc.$(OBJEXT): $(top_srcdir)/internal/serial.h
-proc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-proc.$(OBJEXT): $(top_srcdir)/internal/string.h
-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/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/static_literals.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_integer.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_string.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
-proc.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-proc.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-proc.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-proc.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-proc.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-proc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-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)}id.h
-proc.$(OBJEXT): {$(VPATH)}id_table.h
-proc.$(OBJEXT): {$(VPATH)}intern.h
-proc.$(OBJEXT): {$(VPATH)}internal.h
-proc.$(OBJEXT): {$(VPATH)}internal/abi.h
-proc.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-proc.$(OBJEXT): {$(VPATH)}internal/assume.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-proc.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-proc.$(OBJEXT): {$(VPATH)}internal/cast.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-proc.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-proc.$(OBJEXT): {$(VPATH)}internal/config.h
-proc.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-proc.$(OBJEXT): {$(VPATH)}internal/core.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-proc.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-proc.$(OBJEXT): {$(VPATH)}internal/ctype.h
-proc.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-proc.$(OBJEXT): {$(VPATH)}internal/dosish.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-proc.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-proc.$(OBJEXT): {$(VPATH)}internal/error.h
-proc.$(OBJEXT): {$(VPATH)}internal/eval.h
-proc.$(OBJEXT): {$(VPATH)}internal/event.h
-proc.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-proc.$(OBJEXT): {$(VPATH)}internal/gc.h
-proc.$(OBJEXT): {$(VPATH)}internal/glob.h
-proc.$(OBJEXT): {$(VPATH)}internal/globals.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-proc.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-proc.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-proc.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-proc.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-proc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-proc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-proc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-proc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-proc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-proc.$(OBJEXT): {$(VPATH)}internal/symbol.h
-proc.$(OBJEXT): {$(VPATH)}internal/value.h
-proc.$(OBJEXT): {$(VPATH)}internal/value_type.h
-proc.$(OBJEXT): {$(VPATH)}internal/variable.h
-proc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-proc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-proc.$(OBJEXT): {$(VPATH)}iseq.h
-proc.$(OBJEXT): {$(VPATH)}method.h
-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/diagnostic.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
-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
-process.$(OBJEXT): $(top_srcdir)/internal/bits.h
-process.$(OBJEXT): $(top_srcdir)/internal/class.h
-process.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-process.$(OBJEXT): $(top_srcdir)/internal/dir.h
-process.$(OBJEXT): $(top_srcdir)/internal/error.h
-process.$(OBJEXT): $(top_srcdir)/internal/eval.h
-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
-process.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-process.$(OBJEXT): $(top_srcdir)/internal/serial.h
-process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-process.$(OBJEXT): $(top_srcdir)/internal/string.h
-process.$(OBJEXT): $(top_srcdir)/internal/thread.h
-process.$(OBJEXT): $(top_srcdir)/internal/time.h
-process.$(OBJEXT): $(top_srcdir)/internal/variable.h
-process.$(OBJEXT): $(top_srcdir)/internal/vm.h
-process.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-process.$(OBJEXT): {$(VPATH)}assert.h
-process.$(OBJEXT): {$(VPATH)}atomic.h
-process.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-process.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-process.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-process.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-process.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-process.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-process.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-process.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-process.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-process.$(OBJEXT): {$(VPATH)}config.h
-process.$(OBJEXT): {$(VPATH)}constant.h
-process.$(OBJEXT): {$(VPATH)}debug_counter.h
-process.$(OBJEXT): {$(VPATH)}defines.h
-process.$(OBJEXT): {$(VPATH)}dln.h
-process.$(OBJEXT): {$(VPATH)}encoding.h
-process.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
-process.$(OBJEXT): {$(VPATH)}hrtime.h
-process.$(OBJEXT): {$(VPATH)}id.h
-process.$(OBJEXT): {$(VPATH)}id_table.h
-process.$(OBJEXT): {$(VPATH)}intern.h
-process.$(OBJEXT): {$(VPATH)}internal.h
-process.$(OBJEXT): {$(VPATH)}internal/abi.h
-process.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-process.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-process.$(OBJEXT): {$(VPATH)}internal/assume.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-process.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-process.$(OBJEXT): {$(VPATH)}internal/cast.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-process.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-process.$(OBJEXT): {$(VPATH)}internal/config.h
-process.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-process.$(OBJEXT): {$(VPATH)}internal/core.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-process.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-process.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-process.$(OBJEXT): {$(VPATH)}internal/ctype.h
-process.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-process.$(OBJEXT): {$(VPATH)}internal/dosish.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-process.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-process.$(OBJEXT): {$(VPATH)}internal/error.h
-process.$(OBJEXT): {$(VPATH)}internal/eval.h
-process.$(OBJEXT): {$(VPATH)}internal/event.h
-process.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-process.$(OBJEXT): {$(VPATH)}internal/gc.h
-process.$(OBJEXT): {$(VPATH)}internal/glob.h
-process.$(OBJEXT): {$(VPATH)}internal/globals.h
-process.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-process.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-process.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-process.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-process.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-process.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-process.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-process.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-process.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-process.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-process.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-process.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-process.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-process.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-process.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-process.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-process.$(OBJEXT): {$(VPATH)}internal/symbol.h
-process.$(OBJEXT): {$(VPATH)}internal/value.h
-process.$(OBJEXT): {$(VPATH)}internal/value_type.h
-process.$(OBJEXT): {$(VPATH)}internal/variable.h
-process.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-process.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-process.$(OBJEXT): {$(VPATH)}io.h
-process.$(OBJEXT): {$(VPATH)}method.h
-process.$(OBJEXT): {$(VPATH)}missing.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)}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
-process.$(OBJEXT): {$(VPATH)}thread.h
-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
-ractor.$(OBJEXT): $(top_srcdir)/internal/bits.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/complex.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/error.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/gc.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/object.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/ractor.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/serial.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/string.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/struct.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/thread.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/variable.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/vm.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-ractor.$(OBJEXT): {$(VPATH)}assert.h
-ractor.$(OBJEXT): {$(VPATH)}atomic.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-ractor.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-ractor.$(OBJEXT): {$(VPATH)}builtin.h
-ractor.$(OBJEXT): {$(VPATH)}config.h
-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)}id.h
-ractor.$(OBJEXT): {$(VPATH)}id_table.h
-ractor.$(OBJEXT): {$(VPATH)}intern.h
-ractor.$(OBJEXT): {$(VPATH)}internal.h
-ractor.$(OBJEXT): {$(VPATH)}internal/abi.h
-ractor.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-ractor.$(OBJEXT): {$(VPATH)}internal/assume.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-ractor.$(OBJEXT): {$(VPATH)}internal/cast.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-ractor.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-ractor.$(OBJEXT): {$(VPATH)}internal/config.h
-ractor.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-ractor.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-ractor.$(OBJEXT): {$(VPATH)}internal/ctype.h
-ractor.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-ractor.$(OBJEXT): {$(VPATH)}internal/dosish.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-ractor.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-ractor.$(OBJEXT): {$(VPATH)}internal/error.h
-ractor.$(OBJEXT): {$(VPATH)}internal/eval.h
-ractor.$(OBJEXT): {$(VPATH)}internal/event.h
-ractor.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-ractor.$(OBJEXT): {$(VPATH)}internal/gc.h
-ractor.$(OBJEXT): {$(VPATH)}internal/glob.h
-ractor.$(OBJEXT): {$(VPATH)}internal/globals.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-ractor.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-ractor.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-ractor.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-ractor.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-ractor.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-ractor.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-ractor.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-ractor.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ractor.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-ractor.$(OBJEXT): {$(VPATH)}internal/symbol.h
-ractor.$(OBJEXT): {$(VPATH)}internal/value.h
-ractor.$(OBJEXT): {$(VPATH)}internal/value_type.h
-ractor.$(OBJEXT): {$(VPATH)}internal/variable.h
-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)}node.h
-ractor.$(OBJEXT): {$(VPATH)}onigmo.h
-ractor.$(OBJEXT): {$(VPATH)}oniguruma.h
-ractor.$(OBJEXT): {$(VPATH)}ractor.c
-ractor.$(OBJEXT): {$(VPATH)}ractor.h
-ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc
-ractor.$(OBJEXT): {$(VPATH)}ractor_core.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)}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
-random.$(OBJEXT): $(top_srcdir)/internal/serial.h
-random.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-random.$(OBJEXT): $(top_srcdir)/internal/variable.h
-random.$(OBJEXT): $(top_srcdir)/internal/vm.h
-random.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-random.$(OBJEXT): {$(VPATH)}assert.h
-random.$(OBJEXT): {$(VPATH)}atomic.h
-random.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-random.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-random.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-random.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-random.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-random.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-random.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-random.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-random.$(OBJEXT): {$(VPATH)}internal/abi.h
-random.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-random.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-random.$(OBJEXT): {$(VPATH)}internal/assume.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-random.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-random.$(OBJEXT): {$(VPATH)}internal/cast.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-random.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-random.$(OBJEXT): {$(VPATH)}internal/config.h
-random.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-random.$(OBJEXT): {$(VPATH)}internal/core.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-random.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-random.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-random.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-random.$(OBJEXT): {$(VPATH)}internal/gc.h
-random.$(OBJEXT): {$(VPATH)}internal/glob.h
-random.$(OBJEXT): {$(VPATH)}internal/globals.h
-random.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-random.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-random.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-random.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-random.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-random.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-random.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-random.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-random.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-random.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-random.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-random.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-random.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-random.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-random.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-random.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-random.$(OBJEXT): {$(VPATH)}internal/symbol.h
-random.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-range.$(OBJEXT): $(top_srcdir)/internal/bits.h
-range.$(OBJEXT): $(top_srcdir)/internal/compar.h
-range.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-range.$(OBJEXT): $(top_srcdir)/internal/enum.h
-range.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
-range.$(OBJEXT): $(top_srcdir)/internal/error.h
-range.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-range.$(OBJEXT): $(top_srcdir)/internal/gc.h
-range.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-range.$(OBJEXT): $(top_srcdir)/internal/range.h
-range.$(OBJEXT): $(top_srcdir)/internal/serial.h
-range.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-range.$(OBJEXT): $(top_srcdir)/internal/string.h
-range.$(OBJEXT): $(top_srcdir)/internal/struct.h
-range.$(OBJEXT): $(top_srcdir)/internal/vm.h
-range.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-range.$(OBJEXT): {$(VPATH)}assert.h
-range.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-range.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-range.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-range.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-range.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-range.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-range.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-range.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-range.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-range.$(OBJEXT): {$(VPATH)}config.h
-range.$(OBJEXT): {$(VPATH)}defines.h
-range.$(OBJEXT): {$(VPATH)}encoding.h
-range.$(OBJEXT): {$(VPATH)}id.h
-range.$(OBJEXT): {$(VPATH)}intern.h
-range.$(OBJEXT): {$(VPATH)}internal.h
-range.$(OBJEXT): {$(VPATH)}internal/abi.h
-range.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-range.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-range.$(OBJEXT): {$(VPATH)}internal/assume.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-range.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-range.$(OBJEXT): {$(VPATH)}internal/cast.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-range.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-range.$(OBJEXT): {$(VPATH)}internal/config.h
-range.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-range.$(OBJEXT): {$(VPATH)}internal/core.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-range.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-range.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-range.$(OBJEXT): {$(VPATH)}internal/ctype.h
-range.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-range.$(OBJEXT): {$(VPATH)}internal/dosish.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-range.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-range.$(OBJEXT): {$(VPATH)}internal/error.h
-range.$(OBJEXT): {$(VPATH)}internal/eval.h
-range.$(OBJEXT): {$(VPATH)}internal/event.h
-range.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-range.$(OBJEXT): {$(VPATH)}internal/gc.h
-range.$(OBJEXT): {$(VPATH)}internal/glob.h
-range.$(OBJEXT): {$(VPATH)}internal/globals.h
-range.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-range.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-range.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-range.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-range.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-range.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-range.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-range.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-range.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-range.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-range.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-range.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-range.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-range.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-range.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-range.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-range.$(OBJEXT): {$(VPATH)}internal/symbol.h
-range.$(OBJEXT): {$(VPATH)}internal/value.h
-range.$(OBJEXT): {$(VPATH)}internal/value_type.h
-range.$(OBJEXT): {$(VPATH)}internal/variable.h
-range.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-range.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-range.$(OBJEXT): {$(VPATH)}missing.h
-range.$(OBJEXT): {$(VPATH)}onigmo.h
-range.$(OBJEXT): {$(VPATH)}oniguruma.h
-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
-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
-rational.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-rational.$(OBJEXT): $(top_srcdir)/internal/serial.h
-rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-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
-rational.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-rational.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-rational.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-rational.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-rational.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-rational.$(OBJEXT): {$(VPATH)}internal.h
-rational.$(OBJEXT): {$(VPATH)}internal/abi.h
-rational.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-rational.$(OBJEXT): {$(VPATH)}internal/assume.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-rational.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-rational.$(OBJEXT): {$(VPATH)}internal/cast.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-rational.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-rational.$(OBJEXT): {$(VPATH)}internal/config.h
-rational.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-rational.$(OBJEXT): {$(VPATH)}internal/core.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-rational.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-rational.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-rational.$(OBJEXT): {$(VPATH)}internal/gc.h
-rational.$(OBJEXT): {$(VPATH)}internal/glob.h
-rational.$(OBJEXT): {$(VPATH)}internal/globals.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-rational.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-rational.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-rational.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-rational.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-rational.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-rational.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-rational.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-rational.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-rational.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-rational.$(OBJEXT): {$(VPATH)}internal/symbol.h
-rational.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-re.$(OBJEXT): $(top_srcdir)/internal/encoding.h
-re.$(OBJEXT): $(top_srcdir)/internal/gc.h
-re.$(OBJEXT): $(top_srcdir)/internal/hash.h
-re.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-re.$(OBJEXT): $(top_srcdir)/internal/object.h
-re.$(OBJEXT): $(top_srcdir)/internal/ractor.h
-re.$(OBJEXT): $(top_srcdir)/internal/re.h
-re.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-re.$(OBJEXT): $(top_srcdir)/internal/serial.h
-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
-re.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-re.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-re.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-re.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-re.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-re.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-re.$(OBJEXT): {$(VPATH)}config.h
-re.$(OBJEXT): {$(VPATH)}constant.h
-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
-re.$(OBJEXT): {$(VPATH)}internal/abi.h
-re.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-re.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-re.$(OBJEXT): {$(VPATH)}internal/assume.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-re.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-re.$(OBJEXT): {$(VPATH)}internal/cast.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-re.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-re.$(OBJEXT): {$(VPATH)}internal/config.h
-re.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-re.$(OBJEXT): {$(VPATH)}internal/core.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
-re.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-re.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-re.$(OBJEXT): {$(VPATH)}internal/ctype.h
-re.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-re.$(OBJEXT): {$(VPATH)}internal/dosish.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-re.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-re.$(OBJEXT): {$(VPATH)}internal/error.h
-re.$(OBJEXT): {$(VPATH)}internal/eval.h
-re.$(OBJEXT): {$(VPATH)}internal/event.h
-re.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-re.$(OBJEXT): {$(VPATH)}internal/gc.h
-re.$(OBJEXT): {$(VPATH)}internal/glob.h
-re.$(OBJEXT): {$(VPATH)}internal/globals.h
-re.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-re.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-re.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-re.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-re.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-re.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-re.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-re.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-re.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-re.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-re.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-re.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-re.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-re.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-re.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-re.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-re.$(OBJEXT): {$(VPATH)}internal/symbol.h
-re.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-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
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-regcomp.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-regcomp.$(OBJEXT): {$(VPATH)}config.h
-regcomp.$(OBJEXT): {$(VPATH)}defines.h
-regcomp.$(OBJEXT): {$(VPATH)}intern.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/abi.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/assume.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/cast.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/config.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/ctype.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/dosish.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/error.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/eval.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/event.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/gc.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/glob.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/globals.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/symbol.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/value.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/value_type.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/variable.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-regcomp.$(OBJEXT): {$(VPATH)}missing.h
-regcomp.$(OBJEXT): {$(VPATH)}onigmo.h
-regcomp.$(OBJEXT): {$(VPATH)}regcomp.c
-regcomp.$(OBJEXT): {$(VPATH)}regenc.h
-regcomp.$(OBJEXT): {$(VPATH)}regint.h
-regcomp.$(OBJEXT): {$(VPATH)}regparse.h
-regcomp.$(OBJEXT): {$(VPATH)}st.h
-regcomp.$(OBJEXT): {$(VPATH)}subst.h
-regenc.$(OBJEXT): $(hdrdir)/ruby.h
-regenc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-regenc.$(OBJEXT): {$(VPATH)}assert.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-regenc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-regenc.$(OBJEXT): {$(VPATH)}config.h
-regenc.$(OBJEXT): {$(VPATH)}defines.h
-regenc.$(OBJEXT): {$(VPATH)}intern.h
-regenc.$(OBJEXT): {$(VPATH)}internal/abi.h
-regenc.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-regenc.$(OBJEXT): {$(VPATH)}internal/assume.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-regenc.$(OBJEXT): {$(VPATH)}internal/cast.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-regenc.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-regenc.$(OBJEXT): {$(VPATH)}internal/config.h
-regenc.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-regenc.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-regenc.$(OBJEXT): {$(VPATH)}internal/ctype.h
-regenc.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-regenc.$(OBJEXT): {$(VPATH)}internal/dosish.h
-regenc.$(OBJEXT): {$(VPATH)}internal/error.h
-regenc.$(OBJEXT): {$(VPATH)}internal/eval.h
-regenc.$(OBJEXT): {$(VPATH)}internal/event.h
-regenc.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-regenc.$(OBJEXT): {$(VPATH)}internal/gc.h
-regenc.$(OBJEXT): {$(VPATH)}internal/glob.h
-regenc.$(OBJEXT): {$(VPATH)}internal/globals.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-regenc.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-regenc.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-regenc.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-regenc.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-regenc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-regenc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-regenc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-regenc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regenc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-regenc.$(OBJEXT): {$(VPATH)}internal/symbol.h
-regenc.$(OBJEXT): {$(VPATH)}internal/value.h
-regenc.$(OBJEXT): {$(VPATH)}internal/value_type.h
-regenc.$(OBJEXT): {$(VPATH)}internal/variable.h
-regenc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-regenc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-regenc.$(OBJEXT): {$(VPATH)}missing.h
-regenc.$(OBJEXT): {$(VPATH)}onigmo.h
-regenc.$(OBJEXT): {$(VPATH)}regenc.c
-regenc.$(OBJEXT): {$(VPATH)}regenc.h
-regenc.$(OBJEXT): {$(VPATH)}regint.h
-regenc.$(OBJEXT): {$(VPATH)}st.h
-regenc.$(OBJEXT): {$(VPATH)}subst.h
-regerror.$(OBJEXT): $(hdrdir)/ruby.h
-regerror.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-regerror.$(OBJEXT): {$(VPATH)}assert.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-regerror.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-regerror.$(OBJEXT): {$(VPATH)}config.h
-regerror.$(OBJEXT): {$(VPATH)}defines.h
-regerror.$(OBJEXT): {$(VPATH)}intern.h
-regerror.$(OBJEXT): {$(VPATH)}internal/abi.h
-regerror.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-regerror.$(OBJEXT): {$(VPATH)}internal/assume.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-regerror.$(OBJEXT): {$(VPATH)}internal/cast.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-regerror.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-regerror.$(OBJEXT): {$(VPATH)}internal/config.h
-regerror.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-regerror.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-regerror.$(OBJEXT): {$(VPATH)}internal/ctype.h
-regerror.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-regerror.$(OBJEXT): {$(VPATH)}internal/dosish.h
-regerror.$(OBJEXT): {$(VPATH)}internal/error.h
-regerror.$(OBJEXT): {$(VPATH)}internal/eval.h
-regerror.$(OBJEXT): {$(VPATH)}internal/event.h
-regerror.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-regerror.$(OBJEXT): {$(VPATH)}internal/gc.h
-regerror.$(OBJEXT): {$(VPATH)}internal/glob.h
-regerror.$(OBJEXT): {$(VPATH)}internal/globals.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-regerror.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-regerror.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-regerror.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-regerror.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-regerror.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-regerror.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-regerror.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-regerror.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regerror.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-regerror.$(OBJEXT): {$(VPATH)}internal/symbol.h
-regerror.$(OBJEXT): {$(VPATH)}internal/value.h
-regerror.$(OBJEXT): {$(VPATH)}internal/value_type.h
-regerror.$(OBJEXT): {$(VPATH)}internal/variable.h
-regerror.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-regerror.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-regerror.$(OBJEXT): {$(VPATH)}missing.h
-regerror.$(OBJEXT): {$(VPATH)}onigmo.h
-regerror.$(OBJEXT): {$(VPATH)}regenc.h
-regerror.$(OBJEXT): {$(VPATH)}regerror.c
-regerror.$(OBJEXT): {$(VPATH)}regint.h
-regerror.$(OBJEXT): {$(VPATH)}st.h
-regerror.$(OBJEXT): {$(VPATH)}subst.h
-regexec.$(OBJEXT): $(hdrdir)/ruby.h
-regexec.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-regexec.$(OBJEXT): {$(VPATH)}assert.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-regexec.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-regexec.$(OBJEXT): {$(VPATH)}config.h
-regexec.$(OBJEXT): {$(VPATH)}defines.h
-regexec.$(OBJEXT): {$(VPATH)}intern.h
-regexec.$(OBJEXT): {$(VPATH)}internal/abi.h
-regexec.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-regexec.$(OBJEXT): {$(VPATH)}internal/assume.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-regexec.$(OBJEXT): {$(VPATH)}internal/cast.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-regexec.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-regexec.$(OBJEXT): {$(VPATH)}internal/config.h
-regexec.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-regexec.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-regexec.$(OBJEXT): {$(VPATH)}internal/ctype.h
-regexec.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-regexec.$(OBJEXT): {$(VPATH)}internal/dosish.h
-regexec.$(OBJEXT): {$(VPATH)}internal/error.h
-regexec.$(OBJEXT): {$(VPATH)}internal/eval.h
-regexec.$(OBJEXT): {$(VPATH)}internal/event.h
-regexec.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-regexec.$(OBJEXT): {$(VPATH)}internal/gc.h
-regexec.$(OBJEXT): {$(VPATH)}internal/glob.h
-regexec.$(OBJEXT): {$(VPATH)}internal/globals.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-regexec.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-regexec.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-regexec.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-regexec.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-regexec.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-regexec.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-regexec.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-regexec.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regexec.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-regexec.$(OBJEXT): {$(VPATH)}internal/symbol.h
-regexec.$(OBJEXT): {$(VPATH)}internal/value.h
-regexec.$(OBJEXT): {$(VPATH)}internal/value_type.h
-regexec.$(OBJEXT): {$(VPATH)}internal/variable.h
-regexec.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-regexec.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-regexec.$(OBJEXT): {$(VPATH)}missing.h
-regexec.$(OBJEXT): {$(VPATH)}onigmo.h
-regexec.$(OBJEXT): {$(VPATH)}regenc.h
-regexec.$(OBJEXT): {$(VPATH)}regexec.c
-regexec.$(OBJEXT): {$(VPATH)}regint.h
-regexec.$(OBJEXT): {$(VPATH)}st.h
-regexec.$(OBJEXT): {$(VPATH)}subst.h
-regparse.$(OBJEXT): $(hdrdir)/ruby.h
-regparse.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-regparse.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-regparse.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-regparse.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-regparse.$(OBJEXT): {$(VPATH)}assert.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-regparse.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-regparse.$(OBJEXT): {$(VPATH)}config.h
-regparse.$(OBJEXT): {$(VPATH)}defines.h
-regparse.$(OBJEXT): {$(VPATH)}intern.h
-regparse.$(OBJEXT): {$(VPATH)}internal/abi.h
-regparse.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-regparse.$(OBJEXT): {$(VPATH)}internal/assume.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-regparse.$(OBJEXT): {$(VPATH)}internal/cast.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-regparse.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-regparse.$(OBJEXT): {$(VPATH)}internal/config.h
-regparse.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-regparse.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-regparse.$(OBJEXT): {$(VPATH)}internal/ctype.h
-regparse.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-regparse.$(OBJEXT): {$(VPATH)}internal/dosish.h
-regparse.$(OBJEXT): {$(VPATH)}internal/error.h
-regparse.$(OBJEXT): {$(VPATH)}internal/eval.h
-regparse.$(OBJEXT): {$(VPATH)}internal/event.h
-regparse.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-regparse.$(OBJEXT): {$(VPATH)}internal/gc.h
-regparse.$(OBJEXT): {$(VPATH)}internal/glob.h
-regparse.$(OBJEXT): {$(VPATH)}internal/globals.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-regparse.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-regparse.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-regparse.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-regparse.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-regparse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-regparse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-regparse.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-regparse.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regparse.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-regparse.$(OBJEXT): {$(VPATH)}internal/symbol.h
-regparse.$(OBJEXT): {$(VPATH)}internal/value.h
-regparse.$(OBJEXT): {$(VPATH)}internal/value_type.h
-regparse.$(OBJEXT): {$(VPATH)}internal/variable.h
-regparse.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-regparse.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-regparse.$(OBJEXT): {$(VPATH)}missing.h
-regparse.$(OBJEXT): {$(VPATH)}onigmo.h
-regparse.$(OBJEXT): {$(VPATH)}regenc.h
-regparse.$(OBJEXT): {$(VPATH)}regint.h
-regparse.$(OBJEXT): {$(VPATH)}regparse.c
-regparse.$(OBJEXT): {$(VPATH)}regparse.h
-regparse.$(OBJEXT): {$(VPATH)}st.h
-regparse.$(OBJEXT): {$(VPATH)}subst.h
-regsyntax.$(OBJEXT): $(hdrdir)/ruby.h
-regsyntax.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-regsyntax.$(OBJEXT): {$(VPATH)}assert.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-regsyntax.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-regsyntax.$(OBJEXT): {$(VPATH)}config.h
-regsyntax.$(OBJEXT): {$(VPATH)}defines.h
-regsyntax.$(OBJEXT): {$(VPATH)}intern.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/abi.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/assume.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/cast.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/config.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/ctype.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/dosish.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/error.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/eval.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/event.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/gc.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/glob.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/globals.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/symbol.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/value.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/value_type.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/variable.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-regsyntax.$(OBJEXT): {$(VPATH)}missing.h
-regsyntax.$(OBJEXT): {$(VPATH)}onigmo.h
-regsyntax.$(OBJEXT): {$(VPATH)}regenc.h
-regsyntax.$(OBJEXT): {$(VPATH)}regint.h
-regsyntax.$(OBJEXT): {$(VPATH)}regsyntax.c
-regsyntax.$(OBJEXT): {$(VPATH)}st.h
-regsyntax.$(OBJEXT): {$(VPATH)}subst.h
-ruby-runner.$(OBJEXT): {$(VPATH)}config.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-ruby-runner.$(OBJEXT): {$(VPATH)}internal/config.h
-ruby-runner.$(OBJEXT): {$(VPATH)}ruby-runner.c
-ruby-runner.$(OBJEXT): {$(VPATH)}ruby-runner.h
-ruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-ruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-ruby.$(OBJEXT): $(CCAN_DIR)/list/list.h
-ruby.$(OBJEXT): $(CCAN_DIR)/str/str.h
-ruby.$(OBJEXT): $(hdrdir)/ruby.h
-ruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-ruby.$(OBJEXT): $(hdrdir)/ruby/version.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/array.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/bits.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/class.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/cont.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/error.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/file.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/inits.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/io.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/load.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/loadpath.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/missing.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/object.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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/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/static_literals.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_integer.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_string.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
-ruby.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-ruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-ruby.$(OBJEXT): {$(VPATH)}config.h
-ruby.$(OBJEXT): {$(VPATH)}constant.h
-ruby.$(OBJEXT): {$(VPATH)}debug_counter.h
-ruby.$(OBJEXT): {$(VPATH)}defines.h
-ruby.$(OBJEXT): {$(VPATH)}dln.h
-ruby.$(OBJEXT): {$(VPATH)}encoding.h
-ruby.$(OBJEXT): {$(VPATH)}eval_intern.h
-ruby.$(OBJEXT): {$(VPATH)}id.h
-ruby.$(OBJEXT): {$(VPATH)}id_table.h
-ruby.$(OBJEXT): {$(VPATH)}intern.h
-ruby.$(OBJEXT): {$(VPATH)}internal.h
-ruby.$(OBJEXT): {$(VPATH)}internal/abi.h
-ruby.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-ruby.$(OBJEXT): {$(VPATH)}internal/assume.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-ruby.$(OBJEXT): {$(VPATH)}internal/cast.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-ruby.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-ruby.$(OBJEXT): {$(VPATH)}internal/config.h
-ruby.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-ruby.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-ruby.$(OBJEXT): {$(VPATH)}internal/ctype.h
-ruby.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-ruby.$(OBJEXT): {$(VPATH)}internal/dosish.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-ruby.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-ruby.$(OBJEXT): {$(VPATH)}internal/error.h
-ruby.$(OBJEXT): {$(VPATH)}internal/eval.h
-ruby.$(OBJEXT): {$(VPATH)}internal/event.h
-ruby.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-ruby.$(OBJEXT): {$(VPATH)}internal/gc.h
-ruby.$(OBJEXT): {$(VPATH)}internal/glob.h
-ruby.$(OBJEXT): {$(VPATH)}internal/globals.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-ruby.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-ruby.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-ruby.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-ruby.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-ruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-ruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-ruby.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-ruby.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ruby.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-ruby.$(OBJEXT): {$(VPATH)}internal/symbol.h
-ruby.$(OBJEXT): {$(VPATH)}internal/value.h
-ruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
-ruby.$(OBJEXT): {$(VPATH)}internal/variable.h
-ruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-ruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-ruby.$(OBJEXT): {$(VPATH)}io.h
-ruby.$(OBJEXT): {$(VPATH)}iseq.h
-ruby.$(OBJEXT): {$(VPATH)}method.h
-ruby.$(OBJEXT): {$(VPATH)}missing.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/diagnostic.h
-ruby.$(OBJEXT): {$(VPATH)}prism/version.h
-ruby.$(OBJEXT): {$(VPATH)}prism_compile.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
-ruby.$(OBJEXT): {$(VPATH)}thread.h
-ruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-ruby.$(OBJEXT): {$(VPATH)}thread_native.h
-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): $(hdrdir)/ruby/ruby.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/array.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bits.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/complex.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/error.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/re.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/serial.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/string.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/vm.h
-ruby_parser.$(OBJEXT): {$(VPATH)}assert.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-ruby_parser.$(OBJEXT): {$(VPATH)}config.h
-ruby_parser.$(OBJEXT): {$(VPATH)}defines.h
-ruby_parser.$(OBJEXT): {$(VPATH)}encoding.h
-ruby_parser.$(OBJEXT): {$(VPATH)}intern.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/abi.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/assume.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/cast.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/config.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/ctype.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/dosish.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/error.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/eval.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/event.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/gc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/glob.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/globals.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/iterator.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/memory.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/method.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/module.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/newobj.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/symbol.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/value.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/value_type.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/variable.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}missing.h
-ruby_parser.$(OBJEXT): {$(VPATH)}node.h
-ruby_parser.$(OBJEXT): {$(VPATH)}onigmo.h
-ruby_parser.$(OBJEXT): {$(VPATH)}oniguruma.h
-ruby_parser.$(OBJEXT): {$(VPATH)}ruby_assert.h
-ruby_parser.$(OBJEXT): {$(VPATH)}ruby_parser.c
-ruby_parser.$(OBJEXT): {$(VPATH)}rubyparser.h
-ruby_parser.$(OBJEXT): {$(VPATH)}st.h
-ruby_parser.$(OBJEXT): {$(VPATH)}subst.h
-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
-scheduler.$(OBJEXT): $(CCAN_DIR)/str/str.h
-scheduler.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/array.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/thread.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/variable.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-scheduler.$(OBJEXT): {$(VPATH)}assert.h
-scheduler.$(OBJEXT): {$(VPATH)}atomic.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-scheduler.$(OBJEXT): {$(VPATH)}config.h
-scheduler.$(OBJEXT): {$(VPATH)}constant.h
-scheduler.$(OBJEXT): {$(VPATH)}defines.h
-scheduler.$(OBJEXT): {$(VPATH)}encoding.h
-scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
-scheduler.$(OBJEXT): {$(VPATH)}id.h
-scheduler.$(OBJEXT): {$(VPATH)}id_table.h
-scheduler.$(OBJEXT): {$(VPATH)}intern.h
-scheduler.$(OBJEXT): {$(VPATH)}internal.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/abi.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/assume.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/cast.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/config.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/ctype.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/dosish.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/error.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/eval.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/event.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/gc.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/glob.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/globals.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/symbol.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/value.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/value_type.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/variable.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-scheduler.$(OBJEXT): {$(VPATH)}io.h
-scheduler.$(OBJEXT): {$(VPATH)}io/buffer.h
-scheduler.$(OBJEXT): {$(VPATH)}method.h
-scheduler.$(OBJEXT): {$(VPATH)}missing.h
-scheduler.$(OBJEXT): {$(VPATH)}node.h
-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
-scheduler.$(OBJEXT): {$(VPATH)}subst.h
-scheduler.$(OBJEXT): {$(VPATH)}thread.h
-scheduler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-scheduler.$(OBJEXT): {$(VPATH)}thread_native.h
-scheduler.$(OBJEXT): {$(VPATH)}vm_core.h
-scheduler.$(OBJEXT): {$(VPATH)}vm_opts.h
-setproctitle.$(OBJEXT): $(hdrdir)/ruby.h
-setproctitle.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-setproctitle.$(OBJEXT): {$(VPATH)}assert.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-setproctitle.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-setproctitle.$(OBJEXT): {$(VPATH)}config.h
-setproctitle.$(OBJEXT): {$(VPATH)}defines.h
-setproctitle.$(OBJEXT): {$(VPATH)}intern.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/abi.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/assume.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/cast.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/config.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/ctype.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/dosish.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/error.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/eval.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/event.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/gc.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/glob.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/globals.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/symbol.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/value.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/value_type.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/variable.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-setproctitle.$(OBJEXT): {$(VPATH)}missing.h
-setproctitle.$(OBJEXT): {$(VPATH)}setproctitle.c
-setproctitle.$(OBJEXT): {$(VPATH)}st.h
-setproctitle.$(OBJEXT): {$(VPATH)}subst.h
-setproctitle.$(OBJEXT): {$(VPATH)}util.h
-shape.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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/sanitizers.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
-shape.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-shape.$(OBJEXT): {$(VPATH)}assert.h
-shape.$(OBJEXT): {$(VPATH)}atomic.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-shape.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-shape.$(OBJEXT): {$(VPATH)}config.h
-shape.$(OBJEXT): {$(VPATH)}constant.h
-shape.$(OBJEXT): {$(VPATH)}debug_counter.h
-shape.$(OBJEXT): {$(VPATH)}defines.h
-shape.$(OBJEXT): {$(VPATH)}encoding.h
-shape.$(OBJEXT): {$(VPATH)}id.h
-shape.$(OBJEXT): {$(VPATH)}id_table.h
-shape.$(OBJEXT): {$(VPATH)}intern.h
-shape.$(OBJEXT): {$(VPATH)}internal.h
-shape.$(OBJEXT): {$(VPATH)}internal/abi.h
-shape.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-shape.$(OBJEXT): {$(VPATH)}internal/assume.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-shape.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-shape.$(OBJEXT): {$(VPATH)}internal/cast.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-shape.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-shape.$(OBJEXT): {$(VPATH)}internal/config.h
-shape.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-shape.$(OBJEXT): {$(VPATH)}internal/core.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-shape.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-shape.$(OBJEXT): {$(VPATH)}internal/ctype.h
-shape.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-shape.$(OBJEXT): {$(VPATH)}internal/dosish.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-shape.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-shape.$(OBJEXT): {$(VPATH)}internal/error.h
-shape.$(OBJEXT): {$(VPATH)}internal/eval.h
-shape.$(OBJEXT): {$(VPATH)}internal/event.h
-shape.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-shape.$(OBJEXT): {$(VPATH)}internal/gc.h
-shape.$(OBJEXT): {$(VPATH)}internal/glob.h
-shape.$(OBJEXT): {$(VPATH)}internal/globals.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-shape.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-shape.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-shape.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-shape.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-shape.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-shape.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-shape.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-shape.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-shape.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-shape.$(OBJEXT): {$(VPATH)}internal/symbol.h
-shape.$(OBJEXT): {$(VPATH)}internal/value.h
-shape.$(OBJEXT): {$(VPATH)}internal/value_type.h
-shape.$(OBJEXT): {$(VPATH)}internal/variable.h
-shape.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-shape.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-shape.$(OBJEXT): {$(VPATH)}method.h
-shape.$(OBJEXT): {$(VPATH)}missing.h
-shape.$(OBJEXT): {$(VPATH)}node.h
-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
-shape.$(OBJEXT): {$(VPATH)}subst.h
-shape.$(OBJEXT): {$(VPATH)}symbol.h
-shape.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-shape.$(OBJEXT): {$(VPATH)}thread_native.h
-shape.$(OBJEXT): {$(VPATH)}variable.h
-shape.$(OBJEXT): {$(VPATH)}vm_core.h
-shape.$(OBJEXT): {$(VPATH)}vm_debug.h
-shape.$(OBJEXT): {$(VPATH)}vm_opts.h
-shape.$(OBJEXT): {$(VPATH)}vm_sync.h
-signal.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-signal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-signal.$(OBJEXT): $(top_srcdir)/internal/serial.h
-signal.$(OBJEXT): $(top_srcdir)/internal/signal.h
-signal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-signal.$(OBJEXT): $(top_srcdir)/internal/string.h
-signal.$(OBJEXT): $(top_srcdir)/internal/thread.h
-signal.$(OBJEXT): $(top_srcdir)/internal/variable.h
-signal.$(OBJEXT): $(top_srcdir)/internal/vm.h
-signal.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-signal.$(OBJEXT): {$(VPATH)}assert.h
-signal.$(OBJEXT): {$(VPATH)}atomic.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-signal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-signal.$(OBJEXT): {$(VPATH)}config.h
-signal.$(OBJEXT): {$(VPATH)}constant.h
-signal.$(OBJEXT): {$(VPATH)}debug_counter.h
-signal.$(OBJEXT): {$(VPATH)}defines.h
-signal.$(OBJEXT): {$(VPATH)}encoding.h
-signal.$(OBJEXT): {$(VPATH)}eval_intern.h
-signal.$(OBJEXT): {$(VPATH)}id.h
-signal.$(OBJEXT): {$(VPATH)}id_table.h
-signal.$(OBJEXT): {$(VPATH)}intern.h
-signal.$(OBJEXT): {$(VPATH)}internal.h
-signal.$(OBJEXT): {$(VPATH)}internal/abi.h
-signal.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-signal.$(OBJEXT): {$(VPATH)}internal/assume.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/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
-signal.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-signal.$(OBJEXT): {$(VPATH)}internal/cast.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-signal.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-signal.$(OBJEXT): {$(VPATH)}internal/config.h
-signal.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-signal.$(OBJEXT): {$(VPATH)}internal/core.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-signal.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-signal.$(OBJEXT): {$(VPATH)}internal/ctype.h
-signal.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-signal.$(OBJEXT): {$(VPATH)}internal/dosish.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-signal.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-signal.$(OBJEXT): {$(VPATH)}internal/error.h
-signal.$(OBJEXT): {$(VPATH)}internal/eval.h
-signal.$(OBJEXT): {$(VPATH)}internal/event.h
-signal.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-signal.$(OBJEXT): {$(VPATH)}internal/gc.h
-signal.$(OBJEXT): {$(VPATH)}internal/glob.h
-signal.$(OBJEXT): {$(VPATH)}internal/globals.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-signal.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-signal.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-signal.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-signal.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-signal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-signal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-signal.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-signal.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-signal.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-signal.$(OBJEXT): {$(VPATH)}internal/symbol.h
-signal.$(OBJEXT): {$(VPATH)}internal/value.h
-signal.$(OBJEXT): {$(VPATH)}internal/value_type.h
-signal.$(OBJEXT): {$(VPATH)}internal/variable.h
-signal.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-signal.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-signal.$(OBJEXT): {$(VPATH)}method.h
-signal.$(OBJEXT): {$(VPATH)}missing.h
-signal.$(OBJEXT): {$(VPATH)}node.h
-signal.$(OBJEXT): {$(VPATH)}onigmo.h
-signal.$(OBJEXT): {$(VPATH)}oniguruma.h
-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
-signal.$(OBJEXT): {$(VPATH)}subst.h
-signal.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-signal.$(OBJEXT): {$(VPATH)}thread_native.h
-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
-sprintf.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/error.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/gc.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/hash.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/object.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/serial.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/string.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/variable.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/vm.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-sprintf.$(OBJEXT): {$(VPATH)}assert.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-sprintf.$(OBJEXT): {$(VPATH)}config.h
-sprintf.$(OBJEXT): {$(VPATH)}constant.h
-sprintf.$(OBJEXT): {$(VPATH)}defines.h
-sprintf.$(OBJEXT): {$(VPATH)}encoding.h
-sprintf.$(OBJEXT): {$(VPATH)}id.h
-sprintf.$(OBJEXT): {$(VPATH)}id_table.h
-sprintf.$(OBJEXT): {$(VPATH)}intern.h
-sprintf.$(OBJEXT): {$(VPATH)}internal.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/abi.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/assume.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/cast.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/config.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/ctype.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/dosish.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/error.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/eval.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/event.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/gc.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/glob.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/globals.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/symbol.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/value.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/value_type.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/variable.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-sprintf.$(OBJEXT): {$(VPATH)}missing.h
-sprintf.$(OBJEXT): {$(VPATH)}onigmo.h
-sprintf.$(OBJEXT): {$(VPATH)}oniguruma.h
-sprintf.$(OBJEXT): {$(VPATH)}re.h
-sprintf.$(OBJEXT): {$(VPATH)}regex.h
-sprintf.$(OBJEXT): {$(VPATH)}shape.h
-sprintf.$(OBJEXT): {$(VPATH)}sprintf.c
-sprintf.$(OBJEXT): {$(VPATH)}st.h
-sprintf.$(OBJEXT): {$(VPATH)}subst.h
-sprintf.$(OBJEXT): {$(VPATH)}util.h
-sprintf.$(OBJEXT): {$(VPATH)}vsnprintf.c
-st.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-st.$(OBJEXT): $(top_srcdir)/internal/bits.h
-st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-st.$(OBJEXT): $(top_srcdir)/internal/hash.h
-st.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-st.$(OBJEXT): $(top_srcdir)/internal/st.h
-st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-st.$(OBJEXT): {$(VPATH)}assert.h
-st.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-st.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-st.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-st.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-st.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-st.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-st.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-st.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-st.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-st.$(OBJEXT): {$(VPATH)}config.h
-st.$(OBJEXT): {$(VPATH)}defines.h
-st.$(OBJEXT): {$(VPATH)}intern.h
-st.$(OBJEXT): {$(VPATH)}internal.h
-st.$(OBJEXT): {$(VPATH)}internal/abi.h
-st.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-st.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-st.$(OBJEXT): {$(VPATH)}internal/assume.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-st.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-st.$(OBJEXT): {$(VPATH)}internal/cast.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-st.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-st.$(OBJEXT): {$(VPATH)}internal/config.h
-st.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-st.$(OBJEXT): {$(VPATH)}internal/core.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-st.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-st.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-st.$(OBJEXT): {$(VPATH)}internal/ctype.h
-st.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-st.$(OBJEXT): {$(VPATH)}internal/dosish.h
-st.$(OBJEXT): {$(VPATH)}internal/error.h
-st.$(OBJEXT): {$(VPATH)}internal/eval.h
-st.$(OBJEXT): {$(VPATH)}internal/event.h
-st.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-st.$(OBJEXT): {$(VPATH)}internal/gc.h
-st.$(OBJEXT): {$(VPATH)}internal/glob.h
-st.$(OBJEXT): {$(VPATH)}internal/globals.h
-st.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-st.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-st.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-st.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-st.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-st.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-st.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-st.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-st.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-st.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-st.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-st.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-st.$(OBJEXT): {$(VPATH)}internal/st.h
-st.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-st.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-st.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-st.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-st.$(OBJEXT): {$(VPATH)}internal/symbol.h
-st.$(OBJEXT): {$(VPATH)}internal/value.h
-st.$(OBJEXT): {$(VPATH)}internal/value_type.h
-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
-strftime.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/encoding.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/serial.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/string.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/vm.h
-strftime.$(OBJEXT): {$(VPATH)}assert.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-strftime.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-strftime.$(OBJEXT): {$(VPATH)}config.h
-strftime.$(OBJEXT): {$(VPATH)}defines.h
-strftime.$(OBJEXT): {$(VPATH)}encoding.h
-strftime.$(OBJEXT): {$(VPATH)}intern.h
-strftime.$(OBJEXT): {$(VPATH)}internal.h
-strftime.$(OBJEXT): {$(VPATH)}internal/abi.h
-strftime.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-strftime.$(OBJEXT): {$(VPATH)}internal/assume.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-strftime.$(OBJEXT): {$(VPATH)}internal/cast.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-strftime.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-strftime.$(OBJEXT): {$(VPATH)}internal/config.h
-strftime.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-strftime.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-strftime.$(OBJEXT): {$(VPATH)}internal/ctype.h
-strftime.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-strftime.$(OBJEXT): {$(VPATH)}internal/dosish.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-strftime.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-strftime.$(OBJEXT): {$(VPATH)}internal/error.h
-strftime.$(OBJEXT): {$(VPATH)}internal/eval.h
-strftime.$(OBJEXT): {$(VPATH)}internal/event.h
-strftime.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-strftime.$(OBJEXT): {$(VPATH)}internal/gc.h
-strftime.$(OBJEXT): {$(VPATH)}internal/glob.h
-strftime.$(OBJEXT): {$(VPATH)}internal/globals.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-strftime.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-strftime.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-strftime.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-strftime.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-strftime.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-strftime.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-strftime.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-strftime.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-strftime.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-strftime.$(OBJEXT): {$(VPATH)}internal/symbol.h
-strftime.$(OBJEXT): {$(VPATH)}internal/value.h
-strftime.$(OBJEXT): {$(VPATH)}internal/value_type.h
-strftime.$(OBJEXT): {$(VPATH)}internal/variable.h
-strftime.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-strftime.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-strftime.$(OBJEXT): {$(VPATH)}missing.h
-strftime.$(OBJEXT): {$(VPATH)}onigmo.h
-strftime.$(OBJEXT): {$(VPATH)}oniguruma.h
-strftime.$(OBJEXT): {$(VPATH)}st.h
-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
-string.$(OBJEXT): $(top_srcdir)/internal/bits.h
-string.$(OBJEXT): $(top_srcdir)/internal/class.h
-string.$(OBJEXT): $(top_srcdir)/internal/compar.h
-string.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-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/hash.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
-string.$(OBJEXT): $(top_srcdir)/internal/re.h
-string.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-string.$(OBJEXT): $(top_srcdir)/internal/serial.h
-string.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-string.$(OBJEXT): $(top_srcdir)/internal/string.h
-string.$(OBJEXT): $(top_srcdir)/internal/transcode.h
-string.$(OBJEXT): $(top_srcdir)/internal/variable.h
-string.$(OBJEXT): $(top_srcdir)/internal/vm.h
-string.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-string.$(OBJEXT): {$(VPATH)}assert.h
-string.$(OBJEXT): {$(VPATH)}atomic.h
-string.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-string.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-string.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-string.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-string.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-string.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-string.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-string.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-string.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-string.$(OBJEXT): {$(VPATH)}config.h
-string.$(OBJEXT): {$(VPATH)}constant.h
-string.$(OBJEXT): {$(VPATH)}debug_counter.h
-string.$(OBJEXT): {$(VPATH)}defines.h
-string.$(OBJEXT): {$(VPATH)}encindex.h
-string.$(OBJEXT): {$(VPATH)}encoding.h
-string.$(OBJEXT): {$(VPATH)}id.h
-string.$(OBJEXT): {$(VPATH)}id_table.h
-string.$(OBJEXT): {$(VPATH)}intern.h
-string.$(OBJEXT): {$(VPATH)}internal.h
-string.$(OBJEXT): {$(VPATH)}internal/abi.h
-string.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-string.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-string.$(OBJEXT): {$(VPATH)}internal/assume.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/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
-string.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-string.$(OBJEXT): {$(VPATH)}internal/cast.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-string.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-string.$(OBJEXT): {$(VPATH)}internal/config.h
-string.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-string.$(OBJEXT): {$(VPATH)}internal/core.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
-string.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-string.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-string.$(OBJEXT): {$(VPATH)}internal/ctype.h
-string.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-string.$(OBJEXT): {$(VPATH)}internal/dosish.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-string.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-string.$(OBJEXT): {$(VPATH)}internal/error.h
-string.$(OBJEXT): {$(VPATH)}internal/eval.h
-string.$(OBJEXT): {$(VPATH)}internal/event.h
-string.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-string.$(OBJEXT): {$(VPATH)}internal/gc.h
-string.$(OBJEXT): {$(VPATH)}internal/glob.h
-string.$(OBJEXT): {$(VPATH)}internal/globals.h
-string.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-string.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-string.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-string.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-string.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-string.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-string.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-string.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-string.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-string.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-string.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-string.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-string.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-string.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-string.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-string.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-string.$(OBJEXT): {$(VPATH)}internal/symbol.h
-string.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-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
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/config.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-strlcat.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-strlcat.$(OBJEXT): {$(VPATH)}missing.h
-strlcat.$(OBJEXT): {$(VPATH)}strlcat.c
-strlcpy.$(OBJEXT): {$(VPATH)}config.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/config.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-strlcpy.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-strlcpy.$(OBJEXT): {$(VPATH)}missing.h
-strlcpy.$(OBJEXT): {$(VPATH)}strlcpy.c
-struct.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-struct.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-struct.$(OBJEXT): $(top_srcdir)/internal/error.h
-struct.$(OBJEXT): $(top_srcdir)/internal/gc.h
-struct.$(OBJEXT): $(top_srcdir)/internal/hash.h
-struct.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-struct.$(OBJEXT): $(top_srcdir)/internal/object.h
-struct.$(OBJEXT): $(top_srcdir)/internal/proc.h
-struct.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-struct.$(OBJEXT): $(top_srcdir)/internal/serial.h
-struct.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-struct.$(OBJEXT): $(top_srcdir)/internal/string.h
-struct.$(OBJEXT): $(top_srcdir)/internal/struct.h
-struct.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-struct.$(OBJEXT): $(top_srcdir)/internal/variable.h
-struct.$(OBJEXT): $(top_srcdir)/internal/vm.h
-struct.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-struct.$(OBJEXT): {$(VPATH)}assert.h
-struct.$(OBJEXT): {$(VPATH)}atomic.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-struct.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-struct.$(OBJEXT): {$(VPATH)}id_table.h
-struct.$(OBJEXT): {$(VPATH)}intern.h
-struct.$(OBJEXT): {$(VPATH)}internal.h
-struct.$(OBJEXT): {$(VPATH)}internal/abi.h
-struct.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-struct.$(OBJEXT): {$(VPATH)}internal/assume.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-struct.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-struct.$(OBJEXT): {$(VPATH)}internal/cast.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-struct.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-struct.$(OBJEXT): {$(VPATH)}internal/config.h
-struct.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-struct.$(OBJEXT): {$(VPATH)}internal/core.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-struct.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-struct.$(OBJEXT): {$(VPATH)}internal/ctype.h
-struct.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-struct.$(OBJEXT): {$(VPATH)}internal/dosish.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-struct.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-struct.$(OBJEXT): {$(VPATH)}internal/error.h
-struct.$(OBJEXT): {$(VPATH)}internal/eval.h
-struct.$(OBJEXT): {$(VPATH)}internal/event.h
-struct.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-struct.$(OBJEXT): {$(VPATH)}internal/gc.h
-struct.$(OBJEXT): {$(VPATH)}internal/glob.h
-struct.$(OBJEXT): {$(VPATH)}internal/globals.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-struct.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-struct.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-struct.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-struct.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-struct.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-struct.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-struct.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-struct.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-struct.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-struct.$(OBJEXT): {$(VPATH)}internal/symbol.h
-struct.$(OBJEXT): {$(VPATH)}internal/value.h
-struct.$(OBJEXT): {$(VPATH)}internal/value_type.h
-struct.$(OBJEXT): {$(VPATH)}internal/variable.h
-struct.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-struct.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-struct.$(OBJEXT): {$(VPATH)}method.h
-struct.$(OBJEXT): {$(VPATH)}missing.h
-struct.$(OBJEXT): {$(VPATH)}node.h
-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)}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/sanitizers.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/string.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-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
-symbol.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-symbol.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-symbol.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-symbol.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-symbol.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-symbol.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-symbol.$(OBJEXT): {$(VPATH)}builtin.h
-symbol.$(OBJEXT): {$(VPATH)}config.h
-symbol.$(OBJEXT): {$(VPATH)}constant.h
-symbol.$(OBJEXT): {$(VPATH)}debug_counter.h
-symbol.$(OBJEXT): {$(VPATH)}defines.h
-symbol.$(OBJEXT): {$(VPATH)}encoding.h
-symbol.$(OBJEXT): {$(VPATH)}id.c
-symbol.$(OBJEXT): {$(VPATH)}id.h
-symbol.$(OBJEXT): {$(VPATH)}id_table.c
-symbol.$(OBJEXT): {$(VPATH)}id_table.h
-symbol.$(OBJEXT): {$(VPATH)}intern.h
-symbol.$(OBJEXT): {$(VPATH)}internal.h
-symbol.$(OBJEXT): {$(VPATH)}internal/abi.h
-symbol.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-symbol.$(OBJEXT): {$(VPATH)}internal/assume.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/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
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-symbol.$(OBJEXT): {$(VPATH)}internal/cast.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-symbol.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-symbol.$(OBJEXT): {$(VPATH)}internal/config.h
-symbol.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-symbol.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-symbol.$(OBJEXT): {$(VPATH)}internal/ctype.h
-symbol.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-symbol.$(OBJEXT): {$(VPATH)}internal/dosish.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-symbol.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-symbol.$(OBJEXT): {$(VPATH)}internal/error.h
-symbol.$(OBJEXT): {$(VPATH)}internal/eval.h
-symbol.$(OBJEXT): {$(VPATH)}internal/event.h
-symbol.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-symbol.$(OBJEXT): {$(VPATH)}internal/gc.h
-symbol.$(OBJEXT): {$(VPATH)}internal/glob.h
-symbol.$(OBJEXT): {$(VPATH)}internal/globals.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-symbol.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-symbol.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-symbol.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-symbol.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-symbol.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-symbol.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-symbol.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-symbol.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-symbol.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-symbol.$(OBJEXT): {$(VPATH)}internal/symbol.h
-symbol.$(OBJEXT): {$(VPATH)}internal/value.h
-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
-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
-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
-thread.$(OBJEXT): $(top_srcdir)/internal/class.h
-thread.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-thread.$(OBJEXT): $(top_srcdir)/internal/cont.h
-thread.$(OBJEXT): $(top_srcdir)/internal/error.h
-thread.$(OBJEXT): $(top_srcdir)/internal/gc.h
-thread.$(OBJEXT): $(top_srcdir)/internal/hash.h
-thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-thread.$(OBJEXT): $(top_srcdir)/internal/io.h
-thread.$(OBJEXT): $(top_srcdir)/internal/object.h
-thread.$(OBJEXT): $(top_srcdir)/internal/proc.h
-thread.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-thread.$(OBJEXT): $(top_srcdir)/internal/serial.h
-thread.$(OBJEXT): $(top_srcdir)/internal/signal.h
-thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-thread.$(OBJEXT): $(top_srcdir)/internal/string.h
-thread.$(OBJEXT): $(top_srcdir)/internal/thread.h
-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/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/static_literals.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_integer.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_string.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
-thread.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-thread.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-thread.$(OBJEXT): {$(VPATH)}builtin.h
-thread.$(OBJEXT): {$(VPATH)}config.h
-thread.$(OBJEXT): {$(VPATH)}constant.h
-thread.$(OBJEXT): {$(VPATH)}debug.h
-thread.$(OBJEXT): {$(VPATH)}debug_counter.h
-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)}hrtime.h
-thread.$(OBJEXT): {$(VPATH)}id.h
-thread.$(OBJEXT): {$(VPATH)}id_table.h
-thread.$(OBJEXT): {$(VPATH)}intern.h
-thread.$(OBJEXT): {$(VPATH)}internal.h
-thread.$(OBJEXT): {$(VPATH)}internal/abi.h
-thread.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-thread.$(OBJEXT): {$(VPATH)}internal/assume.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-thread.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-thread.$(OBJEXT): {$(VPATH)}internal/cast.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-thread.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-thread.$(OBJEXT): {$(VPATH)}internal/config.h
-thread.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-thread.$(OBJEXT): {$(VPATH)}internal/core.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-thread.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-thread.$(OBJEXT): {$(VPATH)}internal/ctype.h
-thread.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-thread.$(OBJEXT): {$(VPATH)}internal/dosish.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-thread.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-thread.$(OBJEXT): {$(VPATH)}internal/error.h
-thread.$(OBJEXT): {$(VPATH)}internal/eval.h
-thread.$(OBJEXT): {$(VPATH)}internal/event.h
-thread.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-thread.$(OBJEXT): {$(VPATH)}internal/gc.h
-thread.$(OBJEXT): {$(VPATH)}internal/glob.h
-thread.$(OBJEXT): {$(VPATH)}internal/globals.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-thread.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-thread.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-thread.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-thread.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-thread.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-thread.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-thread.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-thread.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-thread.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-thread.$(OBJEXT): {$(VPATH)}internal/symbol.h
-thread.$(OBJEXT): {$(VPATH)}internal/value.h
-thread.$(OBJEXT): {$(VPATH)}internal/value_type.h
-thread.$(OBJEXT): {$(VPATH)}internal/variable.h
-thread.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-thread.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-thread.$(OBJEXT): {$(VPATH)}io.h
-thread.$(OBJEXT): {$(VPATH)}iseq.h
-thread.$(OBJEXT): {$(VPATH)}method.h
-thread.$(OBJEXT): {$(VPATH)}missing.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/diagnostic.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)}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
-thread.$(OBJEXT): {$(VPATH)}thread.c
-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
-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
-time.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-time.$(OBJEXT): $(top_srcdir)/internal/bits.h
-time.$(OBJEXT): $(top_srcdir)/internal/compar.h
-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/sanitizers.h
-time.$(OBJEXT): $(top_srcdir)/internal/serial.h
-time.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-time.$(OBJEXT): $(top_srcdir)/internal/string.h
-time.$(OBJEXT): $(top_srcdir)/internal/time.h
-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
-time.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-time.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-time.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-time.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-time.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-time.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-time.$(OBJEXT): {$(VPATH)}builtin.h
-time.$(OBJEXT): {$(VPATH)}config.h
-time.$(OBJEXT): {$(VPATH)}constant.h
-time.$(OBJEXT): {$(VPATH)}defines.h
-time.$(OBJEXT): {$(VPATH)}encoding.h
-time.$(OBJEXT): {$(VPATH)}id.h
-time.$(OBJEXT): {$(VPATH)}id_table.h
-time.$(OBJEXT): {$(VPATH)}intern.h
-time.$(OBJEXT): {$(VPATH)}internal.h
-time.$(OBJEXT): {$(VPATH)}internal/abi.h
-time.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-time.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-time.$(OBJEXT): {$(VPATH)}internal/assume.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-time.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-time.$(OBJEXT): {$(VPATH)}internal/cast.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-time.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-time.$(OBJEXT): {$(VPATH)}internal/config.h
-time.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-time.$(OBJEXT): {$(VPATH)}internal/core.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-time.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-time.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-time.$(OBJEXT): {$(VPATH)}internal/ctype.h
-time.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-time.$(OBJEXT): {$(VPATH)}internal/dosish.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-time.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-time.$(OBJEXT): {$(VPATH)}internal/error.h
-time.$(OBJEXT): {$(VPATH)}internal/eval.h
-time.$(OBJEXT): {$(VPATH)}internal/event.h
-time.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-time.$(OBJEXT): {$(VPATH)}internal/gc.h
-time.$(OBJEXT): {$(VPATH)}internal/glob.h
-time.$(OBJEXT): {$(VPATH)}internal/globals.h
-time.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-time.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-time.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-time.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-time.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-time.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-time.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-time.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-time.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-time.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-time.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-time.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-time.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-time.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-time.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-time.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-time.$(OBJEXT): {$(VPATH)}internal/symbol.h
-time.$(OBJEXT): {$(VPATH)}internal/value.h
-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)}util.h
-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
-transcode.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/gc.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/inits.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/object.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/serial.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/string.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/transcode.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/variable.h
-transcode.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-transcode.$(OBJEXT): {$(VPATH)}assert.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-transcode.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-transcode.$(OBJEXT): {$(VPATH)}config.h
-transcode.$(OBJEXT): {$(VPATH)}constant.h
-transcode.$(OBJEXT): {$(VPATH)}defines.h
-transcode.$(OBJEXT): {$(VPATH)}encoding.h
-transcode.$(OBJEXT): {$(VPATH)}id.h
-transcode.$(OBJEXT): {$(VPATH)}id_table.h
-transcode.$(OBJEXT): {$(VPATH)}intern.h
-transcode.$(OBJEXT): {$(VPATH)}internal.h
-transcode.$(OBJEXT): {$(VPATH)}internal/abi.h
-transcode.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-transcode.$(OBJEXT): {$(VPATH)}internal/assume.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-transcode.$(OBJEXT): {$(VPATH)}internal/cast.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-transcode.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-transcode.$(OBJEXT): {$(VPATH)}internal/config.h
-transcode.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-transcode.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-transcode.$(OBJEXT): {$(VPATH)}internal/ctype.h
-transcode.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-transcode.$(OBJEXT): {$(VPATH)}internal/dosish.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-transcode.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-transcode.$(OBJEXT): {$(VPATH)}internal/error.h
-transcode.$(OBJEXT): {$(VPATH)}internal/eval.h
-transcode.$(OBJEXT): {$(VPATH)}internal/event.h
-transcode.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-transcode.$(OBJEXT): {$(VPATH)}internal/gc.h
-transcode.$(OBJEXT): {$(VPATH)}internal/glob.h
-transcode.$(OBJEXT): {$(VPATH)}internal/globals.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-transcode.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-transcode.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-transcode.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-transcode.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-transcode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-transcode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-transcode.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-transcode.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-transcode.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-transcode.$(OBJEXT): {$(VPATH)}internal/symbol.h
-transcode.$(OBJEXT): {$(VPATH)}internal/value.h
-transcode.$(OBJEXT): {$(VPATH)}internal/value_type.h
-transcode.$(OBJEXT): {$(VPATH)}internal/variable.h
-transcode.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-transcode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-transcode.$(OBJEXT): {$(VPATH)}missing.h
-transcode.$(OBJEXT): {$(VPATH)}onigmo.h
-transcode.$(OBJEXT): {$(VPATH)}oniguruma.h
-transcode.$(OBJEXT): {$(VPATH)}shape.h
-transcode.$(OBJEXT): {$(VPATH)}st.h
-transcode.$(OBJEXT): {$(VPATH)}subst.h
-transcode.$(OBJEXT): {$(VPATH)}transcode.c
-transcode.$(OBJEXT): {$(VPATH)}transcode_data.h
-util.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-util.$(OBJEXT): $(top_srcdir)/internal/array.h
-util.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-util.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-util.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-util.$(OBJEXT): $(top_srcdir)/internal/util.h
-util.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-util.$(OBJEXT): {$(VPATH)}assert.h
-util.$(OBJEXT): {$(VPATH)}atomic.h
-util.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-util.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-util.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-util.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-util.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-util.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-util.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-util.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-util.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-util.$(OBJEXT): {$(VPATH)}config.h
-util.$(OBJEXT): {$(VPATH)}defines.h
-util.$(OBJEXT): {$(VPATH)}dtoa.c
-util.$(OBJEXT): {$(VPATH)}intern.h
-util.$(OBJEXT): {$(VPATH)}internal.h
-util.$(OBJEXT): {$(VPATH)}internal/abi.h
-util.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-util.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-util.$(OBJEXT): {$(VPATH)}internal/assume.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-util.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-util.$(OBJEXT): {$(VPATH)}internal/cast.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-util.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-util.$(OBJEXT): {$(VPATH)}internal/config.h
-util.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-util.$(OBJEXT): {$(VPATH)}internal/core.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-util.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-util.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-util.$(OBJEXT): {$(VPATH)}internal/ctype.h
-util.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-util.$(OBJEXT): {$(VPATH)}internal/dosish.h
-util.$(OBJEXT): {$(VPATH)}internal/error.h
-util.$(OBJEXT): {$(VPATH)}internal/eval.h
-util.$(OBJEXT): {$(VPATH)}internal/event.h
-util.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-util.$(OBJEXT): {$(VPATH)}internal/gc.h
-util.$(OBJEXT): {$(VPATH)}internal/glob.h
-util.$(OBJEXT): {$(VPATH)}internal/globals.h
-util.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-util.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-util.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-util.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-util.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-util.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-util.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-util.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-util.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-util.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-util.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-util.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-util.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-util.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-util.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-util.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-util.$(OBJEXT): {$(VPATH)}internal/symbol.h
-util.$(OBJEXT): {$(VPATH)}internal/value.h
-util.$(OBJEXT): {$(VPATH)}internal/value_type.h
-util.$(OBJEXT): {$(VPATH)}internal/variable.h
-util.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-util.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-util.$(OBJEXT): {$(VPATH)}missing.h
-util.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-util.$(OBJEXT): {$(VPATH)}st.h
-util.$(OBJEXT): {$(VPATH)}subst.h
-util.$(OBJEXT): {$(VPATH)}util.c
-util.$(OBJEXT): {$(VPATH)}util.h
-variable.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-variable.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-variable.$(OBJEXT): $(top_srcdir)/internal/error.h
-variable.$(OBJEXT): $(top_srcdir)/internal/eval.h
-variable.$(OBJEXT): $(top_srcdir)/internal/gc.h
-variable.$(OBJEXT): $(top_srcdir)/internal/hash.h
-variable.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-variable.$(OBJEXT): $(top_srcdir)/internal/object.h
-variable.$(OBJEXT): $(top_srcdir)/internal/re.h
-variable.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-variable.$(OBJEXT): $(top_srcdir)/internal/serial.h
-variable.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-variable.$(OBJEXT): $(top_srcdir)/internal/string.h
-variable.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-variable.$(OBJEXT): $(top_srcdir)/internal/thread.h
-variable.$(OBJEXT): $(top_srcdir)/internal/variable.h
-variable.$(OBJEXT): $(top_srcdir)/internal/vm.h
-variable.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-variable.$(OBJEXT): {$(VPATH)}assert.h
-variable.$(OBJEXT): {$(VPATH)}atomic.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-variable.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-variable.$(OBJEXT): {$(VPATH)}config.h
-variable.$(OBJEXT): {$(VPATH)}constant.h
-variable.$(OBJEXT): {$(VPATH)}debug_counter.h
-variable.$(OBJEXT): {$(VPATH)}defines.h
-variable.$(OBJEXT): {$(VPATH)}encoding.h
-variable.$(OBJEXT): {$(VPATH)}id.h
-variable.$(OBJEXT): {$(VPATH)}id_table.h
-variable.$(OBJEXT): {$(VPATH)}intern.h
-variable.$(OBJEXT): {$(VPATH)}internal.h
-variable.$(OBJEXT): {$(VPATH)}internal/abi.h
-variable.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-variable.$(OBJEXT): {$(VPATH)}internal/assume.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-variable.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-variable.$(OBJEXT): {$(VPATH)}internal/cast.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-variable.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-variable.$(OBJEXT): {$(VPATH)}internal/config.h
-variable.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-variable.$(OBJEXT): {$(VPATH)}internal/core.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-variable.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-variable.$(OBJEXT): {$(VPATH)}internal/ctype.h
-variable.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-variable.$(OBJEXT): {$(VPATH)}internal/dosish.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-variable.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-variable.$(OBJEXT): {$(VPATH)}internal/error.h
-variable.$(OBJEXT): {$(VPATH)}internal/eval.h
-variable.$(OBJEXT): {$(VPATH)}internal/event.h
-variable.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-variable.$(OBJEXT): {$(VPATH)}internal/gc.h
-variable.$(OBJEXT): {$(VPATH)}internal/glob.h
-variable.$(OBJEXT): {$(VPATH)}internal/globals.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-variable.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-variable.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-variable.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-variable.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-variable.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-variable.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-variable.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-variable.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-variable.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-variable.$(OBJEXT): {$(VPATH)}internal/symbol.h
-variable.$(OBJEXT): {$(VPATH)}internal/value.h
-variable.$(OBJEXT): {$(VPATH)}internal/value_type.h
-variable.$(OBJEXT): {$(VPATH)}internal/variable.h
-variable.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-variable.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-variable.$(OBJEXT): {$(VPATH)}method.h
-variable.$(OBJEXT): {$(VPATH)}missing.h
-variable.$(OBJEXT): {$(VPATH)}node.h
-variable.$(OBJEXT): {$(VPATH)}onigmo.h
-variable.$(OBJEXT): {$(VPATH)}oniguruma.h
-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)}util.h
-variable.$(OBJEXT): {$(VPATH)}variable.c
-variable.$(OBJEXT): {$(VPATH)}variable.h
-variable.$(OBJEXT): {$(VPATH)}vm_core.h
-variable.$(OBJEXT): {$(VPATH)}vm_debug.h
-variable.$(OBJEXT): {$(VPATH)}vm_opts.h
-variable.$(OBJEXT): {$(VPATH)}vm_sync.h
-version.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-version.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-version.$(OBJEXT): $(CCAN_DIR)/list/list.h
-version.$(OBJEXT): $(CCAN_DIR)/str/str.h
-version.$(OBJEXT): $(hdrdir)/ruby.h
-version.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-version.$(OBJEXT): $(hdrdir)/ruby/version.h
-version.$(OBJEXT): $(top_srcdir)/internal/array.h
-version.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-version.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
-version.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-version.$(OBJEXT): $(top_srcdir)/internal/gc.h
-version.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-version.$(OBJEXT): $(top_srcdir)/internal/parse.h
-version.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-version.$(OBJEXT): $(top_srcdir)/internal/serial.h
-version.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-version.$(OBJEXT): $(top_srcdir)/internal/variable.h
-version.$(OBJEXT): $(top_srcdir)/internal/vm.h
-version.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-version.$(OBJEXT): $(top_srcdir)/version.h
-version.$(OBJEXT): {$(VPATH)}assert.h
-version.$(OBJEXT): {$(VPATH)}atomic.h
-version.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-version.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-version.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-version.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-version.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-version.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-version.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-version.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-version.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-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
-version.$(OBJEXT): {$(VPATH)}internal.h
-version.$(OBJEXT): {$(VPATH)}internal/abi.h
-version.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-version.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-version.$(OBJEXT): {$(VPATH)}internal/assume.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-version.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-version.$(OBJEXT): {$(VPATH)}internal/cast.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-version.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-version.$(OBJEXT): {$(VPATH)}internal/config.h
-version.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-version.$(OBJEXT): {$(VPATH)}internal/core.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-version.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-version.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-version.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-version.$(OBJEXT): {$(VPATH)}internal/gc.h
-version.$(OBJEXT): {$(VPATH)}internal/glob.h
-version.$(OBJEXT): {$(VPATH)}internal/globals.h
-version.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-version.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-version.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-version.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-version.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-version.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-version.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-version.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-version.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-version.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-version.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-version.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-version.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-version.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-version.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-version.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-version.$(OBJEXT): {$(VPATH)}internal/symbol.h
-version.$(OBJEXT): {$(VPATH)}internal/value.h
-version.$(OBJEXT): {$(VPATH)}internal/value_type.h
-version.$(OBJEXT): {$(VPATH)}internal/variable.h
-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)}node.h
-version.$(OBJEXT): {$(VPATH)}onigmo.h
-version.$(OBJEXT): {$(VPATH)}oniguruma.h
-version.$(OBJEXT): {$(VPATH)}revision.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
-version.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-version.$(OBJEXT): {$(VPATH)}thread_native.h
-version.$(OBJEXT): {$(VPATH)}version.c
-version.$(OBJEXT): {$(VPATH)}vm_core.h
-version.$(OBJEXT): {$(VPATH)}vm_opts.h
-version.$(OBJEXT): {$(VPATH)}yjit.h
-vm.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-vm.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-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
-vm.$(OBJEXT): $(top_srcdir)/internal/bits.h
-vm.$(OBJEXT): $(top_srcdir)/internal/class.h
-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/complex.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
-vm.$(OBJEXT): $(top_srcdir)/internal/gc.h
-vm.$(OBJEXT): $(top_srcdir)/internal/hash.h
-vm.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm.$(OBJEXT): $(top_srcdir)/internal/inits.h
-vm.$(OBJEXT): $(top_srcdir)/internal/missing.h
-vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-vm.$(OBJEXT): $(top_srcdir)/internal/object.h
-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/rational.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
-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/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/static_literals.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_integer.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_string.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
-vm.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-vm.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-vm.$(OBJEXT): {$(VPATH)}builtin.h
-vm.$(OBJEXT): {$(VPATH)}config.h
-vm.$(OBJEXT): {$(VPATH)}constant.h
-vm.$(OBJEXT): {$(VPATH)}debug_counter.h
-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)}id.h
-vm.$(OBJEXT): {$(VPATH)}id_table.h
-vm.$(OBJEXT): {$(VPATH)}insns.def
-vm.$(OBJEXT): {$(VPATH)}insns.inc
-vm.$(OBJEXT): {$(VPATH)}insns_info.inc
-vm.$(OBJEXT): {$(VPATH)}intern.h
-vm.$(OBJEXT): {$(VPATH)}internal.h
-vm.$(OBJEXT): {$(VPATH)}internal/abi.h
-vm.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-vm.$(OBJEXT): {$(VPATH)}internal/assume.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-vm.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-vm.$(OBJEXT): {$(VPATH)}internal/cast.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-vm.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-vm.$(OBJEXT): {$(VPATH)}internal/config.h
-vm.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-vm.$(OBJEXT): {$(VPATH)}internal/core.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-vm.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-vm.$(OBJEXT): {$(VPATH)}internal/ctype.h
-vm.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-vm.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-vm.$(OBJEXT): {$(VPATH)}internal/error.h
-vm.$(OBJEXT): {$(VPATH)}internal/eval.h
-vm.$(OBJEXT): {$(VPATH)}internal/event.h
-vm.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-vm.$(OBJEXT): {$(VPATH)}internal/gc.h
-vm.$(OBJEXT): {$(VPATH)}internal/glob.h
-vm.$(OBJEXT): {$(VPATH)}internal/globals.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-vm.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-vm.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-vm.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-vm.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-vm.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-vm.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-vm.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-vm.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-vm.$(OBJEXT): {$(VPATH)}internal/symbol.h
-vm.$(OBJEXT): {$(VPATH)}internal/value.h
-vm.$(OBJEXT): {$(VPATH)}internal/value_type.h
-vm.$(OBJEXT): {$(VPATH)}internal/variable.h
-vm.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-vm.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-vm.$(OBJEXT): {$(VPATH)}iseq.h
-vm.$(OBJEXT): {$(VPATH)}method.h
-vm.$(OBJEXT): {$(VPATH)}missing.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/diagnostic.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)}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
-vm.$(OBJEXT): {$(VPATH)}symbol.h
-vm.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-vm.$(OBJEXT): {$(VPATH)}thread_native.h
-vm.$(OBJEXT): {$(VPATH)}variable.h
-vm.$(OBJEXT): {$(VPATH)}vm.c
-vm.$(OBJEXT): {$(VPATH)}vm.h
-vm.$(OBJEXT): {$(VPATH)}vm.inc
-vm.$(OBJEXT): {$(VPATH)}vm_args.c
-vm.$(OBJEXT): {$(VPATH)}vm_call_iseq_optimized.inc
-vm.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-vm.$(OBJEXT): {$(VPATH)}vm_core.h
-vm.$(OBJEXT): {$(VPATH)}vm_debug.h
-vm.$(OBJEXT): {$(VPATH)}vm_eval.c
-vm.$(OBJEXT): {$(VPATH)}vm_exec.c
-vm.$(OBJEXT): {$(VPATH)}vm_exec.h
-vm.$(OBJEXT): {$(VPATH)}vm_insnhelper.c
-vm.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
-vm.$(OBJEXT): {$(VPATH)}vm_method.c
-vm.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm.$(OBJEXT): {$(VPATH)}vm_sync.h
-vm.$(OBJEXT): {$(VPATH)}vmtc.inc
-vm.$(OBJEXT): {$(VPATH)}yjit.h
-vm.$(OBJEXT): {$(VPATH)}yjit_hook.rbinc
-vm_backtrace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-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
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-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/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/static_literals.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_integer.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_string.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
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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
-vm_backtrace.$(OBJEXT): {$(VPATH)}id.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}id_table.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}intern.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/abi.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/assume.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/cast.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/config.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/ctype.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/error.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/eval.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/event.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/gc.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/glob.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/globals.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/symbol.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/value.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/value_type.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/variable.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}iseq.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}method.h
-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/diagnostic.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
-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
-vm_dump.$(OBJEXT): $(CCAN_DIR)/str/str.h
-vm_dump.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/array.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
-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/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/static_literals.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_integer.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_string.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
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-vm_dump.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-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)}fiber/scheduler.h
-vm_dump.$(OBJEXT): {$(VPATH)}id.h
-vm_dump.$(OBJEXT): {$(VPATH)}id_table.h
-vm_dump.$(OBJEXT): {$(VPATH)}intern.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/abi.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/assume.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/cast.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/config.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-vm_dump.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/gc.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/glob.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/globals.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/symbol.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/value.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/value_type.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/variable.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-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/diagnostic.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
-vm_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-vm_dump.$(OBJEXT): {$(VPATH)}thread_native.h
-vm_dump.$(OBJEXT): {$(VPATH)}vm_core.h
-vm_dump.$(OBJEXT): {$(VPATH)}vm_debug.h
-vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c
-vm_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm_sync.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-vm_sync.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-vm_sync.$(OBJEXT): $(CCAN_DIR)/list/list.h
-vm_sync.$(OBJEXT): $(CCAN_DIR)/str/str.h
-vm_sync.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/array.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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
-vm_sync.$(OBJEXT): {$(VPATH)}assert.h
-vm_sync.$(OBJEXT): {$(VPATH)}atomic.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-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)}id.h
-vm_sync.$(OBJEXT): {$(VPATH)}id_table.h
-vm_sync.$(OBJEXT): {$(VPATH)}intern.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/abi.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/assume.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/cast.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/config.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-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
-vm_sync.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/gc.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/glob.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/globals.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/symbol.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/value.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/value_type.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/variable.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-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
-vm_sync.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-vm_sync.$(OBJEXT): {$(VPATH)}thread_native.h
-vm_sync.$(OBJEXT): {$(VPATH)}vm_core.h
-vm_sync.$(OBJEXT): {$(VPATH)}vm_debug.h
-vm_sync.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm_sync.$(OBJEXT): {$(VPATH)}vm_sync.c
-vm_sync.$(OBJEXT): {$(VPATH)}vm_sync.h
-vm_trace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-vm_trace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-vm_trace.$(OBJEXT): $(CCAN_DIR)/list/list.h
-vm_trace.$(OBJEXT): $(CCAN_DIR)/str/str.h
-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
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.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/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/static_literals.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_integer.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_string.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
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-vm_trace.$(OBJEXT): {$(VPATH)}builtin.h
-vm_trace.$(OBJEXT): {$(VPATH)}config.h
-vm_trace.$(OBJEXT): {$(VPATH)}constant.h
-vm_trace.$(OBJEXT): {$(VPATH)}debug.h
-vm_trace.$(OBJEXT): {$(VPATH)}debug_counter.h
-vm_trace.$(OBJEXT): {$(VPATH)}defines.h
-vm_trace.$(OBJEXT): {$(VPATH)}encoding.h
-vm_trace.$(OBJEXT): {$(VPATH)}eval_intern.h
-vm_trace.$(OBJEXT): {$(VPATH)}id.h
-vm_trace.$(OBJEXT): {$(VPATH)}id_table.h
-vm_trace.$(OBJEXT): {$(VPATH)}intern.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/abi.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/assume.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/cast.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/config.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/ctype.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/error.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/eval.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/event.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/gc.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/glob.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/globals.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/symbol.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/value.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/value_type.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/variable.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-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)}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/diagnostic.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)}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
-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/stdckdint.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
-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
-yjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
-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
-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/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/static_literals.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_integer.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_string.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
-yjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-yjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-yjit.$(OBJEXT): {$(VPATH)}builtin.h
-yjit.$(OBJEXT): {$(VPATH)}config.h
-yjit.$(OBJEXT): {$(VPATH)}constant.h
-yjit.$(OBJEXT): {$(VPATH)}debug.h
-yjit.$(OBJEXT): {$(VPATH)}debug_counter.h
-yjit.$(OBJEXT): {$(VPATH)}defines.h
-yjit.$(OBJEXT): {$(VPATH)}encoding.h
-yjit.$(OBJEXT): {$(VPATH)}id.h
-yjit.$(OBJEXT): {$(VPATH)}id_table.h
-yjit.$(OBJEXT): {$(VPATH)}insns.def
-yjit.$(OBJEXT): {$(VPATH)}insns.inc
-yjit.$(OBJEXT): {$(VPATH)}insns_info.inc
-yjit.$(OBJEXT): {$(VPATH)}intern.h
-yjit.$(OBJEXT): {$(VPATH)}internal.h
-yjit.$(OBJEXT): {$(VPATH)}internal/abi.h
-yjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-yjit.$(OBJEXT): {$(VPATH)}internal/assume.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-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
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-yjit.$(OBJEXT): {$(VPATH)}internal/cast.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-yjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-yjit.$(OBJEXT): {$(VPATH)}internal/config.h
-yjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-yjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-yjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
-yjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-yjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-yjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-yjit.$(OBJEXT): {$(VPATH)}internal/error.h
-yjit.$(OBJEXT): {$(VPATH)}internal/eval.h
-yjit.$(OBJEXT): {$(VPATH)}internal/event.h
-yjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-yjit.$(OBJEXT): {$(VPATH)}internal/gc.h
-yjit.$(OBJEXT): {$(VPATH)}internal/glob.h
-yjit.$(OBJEXT): {$(VPATH)}internal/globals.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-yjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-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/hash.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-yjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-yjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-yjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
-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/scan_args.h
-yjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-yjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-yjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-yjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-yjit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-yjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
-yjit.$(OBJEXT): {$(VPATH)}internal/value.h
-yjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
-yjit.$(OBJEXT): {$(VPATH)}internal/variable.h
-yjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-yjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-yjit.$(OBJEXT): {$(VPATH)}iseq.h
-yjit.$(OBJEXT): {$(VPATH)}method.h
-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/diagnostic.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
-yjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-yjit.$(OBJEXT): {$(VPATH)}thread_native.h
-yjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-yjit.$(OBJEXT): {$(VPATH)}vm_core.h
-yjit.$(OBJEXT): {$(VPATH)}vm_debug.h
-yjit.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
-yjit.$(OBJEXT): {$(VPATH)}vm_opts.h
-yjit.$(OBJEXT): {$(VPATH)}vm_sync.h
-yjit.$(OBJEXT): {$(VPATH)}yjit.c
-yjit.$(OBJEXT): {$(VPATH)}yjit.h
-yjit.$(OBJEXT): {$(VPATH)}yjit.rbinc
-# AUTOGENERATED DEPENDENCIES END
+!include $(srcdir)/prism/srcs.mk
+!include $(srcdir)/depend
diff --git a/compar.c b/compar.c
index f5da6178cf..1ab2520f1e 100644
--- a/compar.c
+++ b/compar.c
@@ -24,8 +24,8 @@ rb_cmp(VALUE x, VALUE y)
return rb_funcallv(x, idCmp, 1, &y);
}
-void
-rb_cmperr(VALUE x, VALUE y)
+static VALUE
+cmperr_subject(VALUE y)
{
VALUE classname;
@@ -35,10 +35,25 @@ rb_cmperr(VALUE x, VALUE y)
else {
classname = rb_obj_class(y);
}
+ return classname;
+}
+
+void
+rb_cmperr(VALUE x, VALUE y)
+{
+ VALUE classname = cmperr_subject(y);
rb_raise(rb_eArgError, "comparison of %"PRIsVALUE" with %"PRIsVALUE" failed",
rb_obj_class(x), classname);
}
+void
+rb_cmperr_reason(VALUE x, VALUE y, const char *reason)
+{
+ VALUE classname = cmperr_subject(y);
+ rb_raise(rb_eArgError, "comparison of %"PRIsVALUE" with %"PRIsVALUE" failed: %s",
+ rb_obj_class(x), classname, reason);
+}
+
static VALUE
invcmp_recursive(VALUE x, VALUE y, int recursive)
{
@@ -95,10 +110,13 @@ cmpint(VALUE x, VALUE y)
/*
* call-seq:
- * obj > other -> true or false
+ * self > other -> true or false
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value greater than 0.
+ * Returns whether +self+ is "greater than" +other+;
+ * equivalent to <tt>(self <=> other) > 0</tt>:
+ *
+ * 'foo' > 'foo' # => false
+ * 'food' > 'foo' # => true
*/
static VALUE
@@ -109,10 +127,15 @@ cmp_gt(VALUE x, VALUE y)
/*
* call-seq:
- * obj >= other -> true or false
+ * self >= other -> true or false
+ *
+ * Returns whether +self+ is "greater than or equal to" +other+;
+ * equivalent to <tt>(self <=> other) >= 0</tt>:
+ *
+ * 'food' >= 'foo' # => true
+ * 'foo' >= 'foo' # => true
+ * 'foo' >= 'food' # => false
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value greater than or equal to 0.
*/
static VALUE
@@ -123,10 +146,14 @@ cmp_ge(VALUE x, VALUE y)
/*
* call-seq:
- * obj < other -> true or false
+ * self < other -> true or false
+ *
+ * Returns whether +self+ is "less than" +other+;
+ * equivalent to <tt>(self <=> other) < 0</tt>:
+ *
+ * 'foo' < 'foo' # => false
+ * 'foo' < 'food' # => true
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value less than 0.
*/
static VALUE
@@ -137,10 +164,15 @@ cmp_lt(VALUE x, VALUE y)
/*
* call-seq:
- * obj <= other -> true or false
+ * self <= other -> true or false
+ *
+ * Returns whether +self+ is "less than or equal to" +other+;
+ * equivalent to <tt>(self <=> other) <= 0</tt>:
+ *
+ * 'foo' <= 'foo' # => true
+ * 'foo' <= 'food' # => true
+ * 'food' <= 'foo' # => false
*
- * Compares two objects based on the receiver's <code><=></code>
- * method, returning true if it returns a value less than or equal to 0.
*/
static VALUE
diff --git a/compile.c b/compile.c
index cd7e92298c..65ced44f9c 100644
--- a/compile.c
+++ b/compile.c
@@ -494,6 +494,7 @@ static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const
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);
+static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
@@ -609,8 +610,6 @@ branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
return 1;
}
-#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
-
static VALUE
setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
{
@@ -837,9 +836,9 @@ get_string_value(const NODE *node)
{
switch (nd_type(node)) {
case NODE_STR:
- return rb_node_str_string_val(node);
+ return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
case NODE_FILE:
- return rb_node_file_path_val(node);
+ return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
default:
rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
}
@@ -876,6 +875,7 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
/* iseq type of top, method, class, block */
iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
+ iseq_set_parameters_lvar_state(iseq);
switch (ISEQ_BODY(iseq)->type) {
case ISEQ_TYPE_BLOCK:
@@ -1029,75 +1029,44 @@ rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
/* definition of data structure for compiler */
/*********************************************/
-/*
- * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
- * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
- * generate SPARCV8PLUS code with unaligned memory access instructions.
- * That is why the STRICT_ALIGNMENT is defined only with GCC.
- */
-#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
- #define STRICT_ALIGNMENT
+#if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
+# define ALIGNMENT_SIZE SIZEOF_LONG_LONG
+#else
+# define ALIGNMENT_SIZE SIZEOF_VALUE
#endif
+#define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
-/*
- * Some OpenBSD platforms (including sparc64) require strict alignment.
- */
-#if defined(__OpenBSD__)
- #include <sys/endian.h>
- #ifdef __STRICT_ALIGNMENT
- #define STRICT_ALIGNMENT
- #endif
-#endif
+#define ALIGNMENT_SIZE_OF(type) alignment_size_assert(RUBY_ALIGNOF(type), #type)
-#ifdef STRICT_ALIGNMENT
- #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
- #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
- #else
- #define ALIGNMENT_SIZE SIZEOF_VALUE
- #endif
- #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
- #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
- /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
-#else
- #define PADDING_SIZE_MAX 0
-#endif /* STRICT_ALIGNMENT */
+static inline size_t
+alignment_size_assert(size_t align, const char *type)
+{
+ RUBY_ASSERT((align & (align - 1)) == 0,
+ "ALIGNMENT_SIZE_OF(%s):%zd == (2 ** N) is expected", type, align);
+ return align;
+}
-#ifdef STRICT_ALIGNMENT
/* calculate padding size for aligned memory access */
-static size_t
-calc_padding(void *ptr, size_t size)
+static inline size_t
+calc_padding(void *ptr, size_t align)
{
size_t mis;
size_t padding = 0;
- mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
+ mis = (size_t)ptr & (align - 1);
if (mis > 0) {
- padding = ALIGNMENT_SIZE - mis;
+ padding = align - mis;
}
-/*
- * On 32-bit sparc or equivalents, when a single VALUE is requested
- * and padding == sizeof(VALUE), it is clear that no padding is needed.
- */
-#if ALIGNMENT_SIZE > SIZEOF_VALUE
- if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
- padding = 0;
- }
-#endif
return padding;
}
-#endif /* STRICT_ALIGNMENT */
static void *
-compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
+compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size, size_t align)
{
void *ptr = 0;
struct iseq_compile_data_storage *storage = *arena;
-#ifdef STRICT_ALIGNMENT
- size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
-#else
- const size_t padding = 0; /* expected to be optimized by compiler */
-#endif /* STRICT_ALIGNMENT */
+ size_t padding = calc_padding((void *)&storage->buff[storage->pos], align);
if (size >= INT_MAX - padding) rb_memerror();
if (storage->pos + size + padding > storage->size) {
@@ -1113,14 +1082,10 @@ compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t s
storage->next = 0;
storage->pos = 0;
storage->size = alloc_size;
-#ifdef STRICT_ALIGNMENT
- padding = calc_padding((void *)&storage->buff[storage->pos], size);
-#endif /* STRICT_ALIGNMENT */
+ padding = calc_padding((void *)&storage->buff[storage->pos], align);
}
-#ifdef STRICT_ALIGNMENT
storage->pos += (int)padding;
-#endif /* STRICT_ALIGNMENT */
ptr = (void *)&storage->buff[storage->pos];
storage->pos += (int)size;
@@ -1128,51 +1093,60 @@ compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t s
}
static void *
-compile_data_alloc(rb_iseq_t *iseq, size_t size)
+compile_data_alloc(rb_iseq_t *iseq, size_t size, size_t align)
{
struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
- return compile_data_alloc_with_arena(arena, size);
+ return compile_data_alloc_with_arena(arena, size, align);
}
+#define compile_data_alloc_type(iseq, type) \
+ (type *)compile_data_alloc(iseq, sizeof(type), ALIGNMENT_SIZE_OF(type))
+
static inline void *
-compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
+compile_data_alloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
{
- size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
- return compile_data_alloc(iseq, size);
+ size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
+ return compile_data_alloc(iseq, size, align);
}
+#define compile_data_alloc2_type(iseq, type, num) \
+ (type *)compile_data_alloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
+
static inline void *
-compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
+compile_data_calloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
{
- size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
- void *p = compile_data_alloc(iseq, size);
+ size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
+ void *p = compile_data_alloc(iseq, size, align);
memset(p, 0, size);
return p;
}
+#define compile_data_calloc2_type(iseq, type, num) \
+ (type *)compile_data_calloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
+
static INSN *
compile_data_alloc_insn(rb_iseq_t *iseq)
{
struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
- return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
+ return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN), ALIGNMENT_SIZE_OF(INSN));
}
static LABEL *
compile_data_alloc_label(rb_iseq_t *iseq)
{
- return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
+ return compile_data_alloc_type(iseq, LABEL);
}
static ADJUST *
compile_data_alloc_adjust(rb_iseq_t *iseq)
{
- return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
+ return compile_data_alloc_type(iseq, ADJUST);
}
static TRACE *
compile_data_alloc_trace(rb_iseq_t *iseq)
{
- return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
+ return compile_data_alloc_type(iseq, TRACE);
}
/*
@@ -1398,6 +1372,9 @@ static void
iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
{
RB_OBJ_WRITTEN(iseq, Qundef, *obj);
+ RUBY_ASSERT(SPECIAL_CONST_P(*obj) ||
+ RBASIC_CLASS(*obj) == 0 || // hidden
+ RB_OBJ_SHAREABLE_P(*obj));
}
static INSN *
@@ -1430,7 +1407,7 @@ new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type i
if (argc > 0) {
int i;
va_start(argv, argc);
- operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
+ operands = compile_data_alloc2_type(iseq, VALUE, argc);
for (i = 0; i < argc; i++) {
VALUE v = va_arg(argv, VALUE);
operands[i] = v;
@@ -1440,6 +1417,30 @@ new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type i
return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
}
+static INSN *
+insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
+{
+ VALUE *operands = 0;
+ va_list argv;
+ if (argc > 0) {
+ int i;
+ va_start(argv, argc);
+ operands = compile_data_alloc2_type(iseq, VALUE, argc);
+ for (i = 0; i < argc; i++) {
+ VALUE v = va_arg(argv, VALUE);
+ operands[i] = v;
+ }
+ va_end(argv);
+ }
+
+ iobj->insn_id = insn_id;
+ iobj->operand_size = argc;
+ iobj->operands = operands;
+ iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
+
+ return iobj;
+}
+
static const struct rb_callinfo *
new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
{
@@ -1464,7 +1465,7 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_cal
static INSN *
new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
{
- VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
+ VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
operands[0] = ci;
operands[1] = (VALUE)blockiseq;
@@ -1665,7 +1666,7 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
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) {
- xfree(ISEQ_BODY(iseq)->catch_table);
+ ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
ISEQ_BODY(iseq)->catch_table = NULL;
}
@@ -1691,6 +1692,7 @@ iseq_set_exception_local_table(rb_iseq_t *iseq)
{
ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
+ ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
return COMPILE_OK;
}
@@ -1838,6 +1840,46 @@ iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
}
static void
+update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
+{
+ for (int i=0; i<level; i++) {
+ iseq = ISEQ_BODY(iseq)->parent_iseq;
+ }
+
+ enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
+ int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
+ switch (states[table_idx]) {
+ case lvar_uninitialized:
+ states[table_idx] = lvar_initialized;
+ break;
+ case lvar_initialized:
+ states[table_idx] = lvar_reassigned;
+ break;
+ case lvar_reassigned:
+ /* nothing */
+ break;
+ default:
+ rb_bug("unreachable");
+ }
+}
+
+static int
+iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
+{
+ for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
+ ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
+ }
+
+ int lead_num = ISEQ_BODY(iseq)->param.lead_num;
+ int opt_num = ISEQ_BODY(iseq)->param.opt_num;
+ for (int i=0; i<opt_num; i++) {
+ ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
+ }
+
+ return COMPILE_OK;
+}
+
+static void
iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
{
if (iseq_local_block_param_p(iseq, idx, level)) {
@@ -1858,6 +1900,7 @@ iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const lin
else {
ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
+ update_lvar_state(iseq, level, idx);
if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
}
@@ -1995,6 +2038,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
for (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_ractor_make_shareable(dv);
RB_OBJ_WRITE(iseq, &dvs[i], dv);
}
@@ -2014,7 +2058,7 @@ iseq_set_use_block(rb_iseq_t *iseq)
if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
- st_insert(vm->unused_block_warning_table, key, 1);
+ set_insert(&vm->unused_block_warning_table, key);
}
}
}
@@ -2026,7 +2070,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;
+ const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
ID rest_id = 0;
int last_comma = 0;
ID block_id = 0;
@@ -2034,7 +2078,6 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
- body->param.flags.ruby2_keywords = args->ruby2_keywords;
body->param.lead_num = arg_size = (int)args->pre_args_num;
if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
debugs(" - argc: %d\n", body->param.lead_num);
@@ -2124,7 +2167,10 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
body->param.flags.accepts_no_kwarg = TRUE;
}
- if (block_id) {
+ if (args->no_blockarg) {
+ body->param.flags.accepts_no_block = TRUE;
+ }
+ else if (block_id) {
body->param.block_start = arg_size++;
body->param.flags.has_block = TRUE;
iseq_set_use_block(iseq);
@@ -2178,15 +2224,24 @@ iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *
// then its local table should only be `...`
// FIXME: I think this should be fixed in the AST rather than special case here.
if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
+ CHECK(size >= 3);
size -= 3;
offset += 3;
}
}
if (size > 0) {
- ID *ids = (ID *)ALLOC_N(ID, size);
+ ID *ids = ALLOC_N(ID, size);
MEMCPY(ids, tbl->ids + offset, ID, size);
ISEQ_BODY(iseq)->local_table = ids;
+
+ enum lvar_state *states = ALLOC_N(enum lvar_state, size);
+ // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
+ for (unsigned int i=0; i<size; i++) {
+ states[i] = lvar_uninitialized;
+ // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
+ }
+ ISEQ_BODY(iseq)->lvar_states = states;
}
ISEQ_BODY(iseq)->local_table_size = size;
@@ -2275,6 +2330,33 @@ static const struct st_hash_type cdhash_type = {
rb_iseq_cdhash_hash,
};
+static VALUE
+cdhash_new(size_t size)
+{
+ VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
+ RB_OBJ_SET_SHAREABLE(cdhash);
+ return cdhash;
+}
+
+static void
+cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
+{
+ st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
+ st_insert(tbl, key, val);
+ RB_OBJ_WRITTEN(cdhash, Qundef, key);
+}
+
+static void
+cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
+{
+ st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
+ VALUE dontcare;
+ if (!st_lookup(tbl, key, &dontcare)) {
+ st_insert(tbl, key, val);
+ RB_OBJ_WRITTEN(cdhash, Qundef, key);
+ }
+}
+
struct cdhash_set_label_struct {
VALUE hash;
int pos;
@@ -2282,15 +2364,20 @@ struct cdhash_set_label_struct {
};
static int
-cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
+cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
+{
+ return ST_REPLACE;
+}
+
+static int
+cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
{
struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
- LABEL *lobj = (LABEL *)(val & ~1);
- rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
+ LABEL *lobj = (LABEL *)(*value & ~1);
+ *value = lobj->position - (data->pos+data->len);
return ST_CONTINUE;
}
-
static inline VALUE
get_ivar_ic_value(rb_iseq_t *iseq,ID id)
{
@@ -2320,8 +2407,8 @@ get_cvar_ic_value(rb_iseq_t *iseq,ID id)
dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
#define BADINSN_ERROR \
- (xfree(generated_iseq), \
- xfree(insns_info), \
+ (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
+ SIZED_FREE_N(insns_info, insns_info_size), \
BADINSN_DUMP(anchor, list, NULL), \
COMPILE_ERROR)
@@ -2481,7 +2568,7 @@ array_to_idlist(VALUE arr)
RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
long size = RARRAY_LEN(arr);
ID *ids = (ID *)ALLOC_N(ID, size + 1);
- for (int i = 0; i < size; i++) {
+ for (long i = 0; i < size; i++) {
VALUE sym = RARRAY_AREF(arr, i);
ids[i] = SYM2ID(sym);
}
@@ -2587,8 +2674,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
}
/* make instruction sequence */
+ const int generated_iseq_size = code_index;
generated_iseq = ALLOC_N(VALUE, code_index);
+
+ const int insns_info_size = insn_num;
insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
+
+ const int positions_size = 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));
@@ -2596,7 +2688,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
else {
body->is_entries = NULL;
}
- body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
+
+ if (body->ci_size) {
+ body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
+ }
+ else {
+ body->call_data = NULL;
+ }
ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
// Calculate the bitmask buffer size.
@@ -2609,12 +2707,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
bool needs_bitmap = false;
- if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
+ const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
+ if (mark_offset_bits_size == 1) {
mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
}
else {
- mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
+ mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
}
@@ -2662,10 +2761,8 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
data.hash = map;
data.pos = code_index;
data.len = len;
- rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
+ st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
- rb_hash_rehash(map);
- freeze_hide_obj(map);
generated_iseq[code_index + 1 + j] = map;
ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
RB_OBJ_WRITTEN(iseq, Qundef, map);
@@ -2714,12 +2811,12 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
if (insn == BIN(setinstancevariable)) {
cache->iv_set_name = SYM2ID(operands[j - 1]);
+ cache->value = IVAR_CACHE_INIT;
}
else {
cache->iv_set_name = 0;
+ cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
}
-
- vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
}
case TS_ISE: /* inline storage entry: `once` insn */
case TS_ICVARC: /* inline cvar cache */
@@ -2806,11 +2903,11 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
}
else if (diff < 0) {
int label_no = adjust->label ? adjust->label->label_no : -1;
- xfree(generated_iseq);
- xfree(insns_info);
- xfree(positions);
+ SIZED_FREE_N(generated_iseq, generated_iseq_size);
+ SIZED_FREE_N(insns_info, insns_info_size);
+ SIZED_FREE_N(positions, positions_size);
if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
- xfree(mark_offset_bits);
+ SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
}
debug_list(anchor, list);
COMPILE_ERROR(iseq, adjust->line_no,
@@ -2842,7 +2939,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
else {
body->mark_bits.list = NULL;
ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
- ruby_xfree(mark_offset_bits);
+ SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
}
}
@@ -2850,9 +2947,9 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
body->insns_info.body = insns_info;
body->insns_info.positions = positions;
- REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
+ SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
body->insns_info.body = insns_info;
- REALLOC_N(positions, unsigned int, insns_info_index);
+ SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
body->insns_info.positions = positions;
body->insns_info.size = insns_info_index;
@@ -3128,7 +3225,7 @@ iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
static int
is_frozen_putstring(INSN *insn, VALUE *op)
{
- if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
+ if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
*op = OPERAND_AT(insn, 0);
return 1;
}
@@ -3140,6 +3237,25 @@ is_frozen_putstring(INSN *insn, VALUE *op)
}
static int
+insn_has_label_before(LINK_ELEMENT *elem)
+{
+ LINK_ELEMENT *prev = elem->prev;
+ while (prev) {
+ if (prev->type == ISEQ_ELEMENT_LABEL) {
+ LABEL *label = (LABEL *)prev;
+ if (label->refcnt > 0) {
+ return 1;
+ }
+ }
+ else if (prev->type == ISEQ_ELEMENT_INSN) {
+ break;
+ }
+ prev = prev->prev;
+ }
+ return 0;
+}
+
+static int
optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
{
/*
@@ -3169,8 +3285,8 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
VALUE type;
switch (INSN_OF(iobj)) {
- case BIN(putstring):
- case BIN(putchilledstring):
+ case BIN(dupstring):
+ case BIN(dupchilledstring):
type = INT2FIX(T_STRING);
break;
case BIN(putnil):
@@ -3368,8 +3484,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
/*
- * putstring "beg"
- * putstring "end"
+ * dupstring "beg"
+ * dupstring "end"
* newrange excl
*
* ==>
@@ -3384,9 +3500,10 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if ((end = (INSN *)get_prev_insn(range)) != 0 &&
is_frozen_putstring(end, &str_end) &&
(beg = (INSN *)get_prev_insn(end)) != 0 &&
- is_frozen_putstring(beg, &str_beg)) {
+ is_frozen_putstring(beg, &str_beg) &&
+ !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
int excl = FIX2INT(OPERAND_AT(range, 0));
- VALUE lit_range = rb_range_new(str_beg, str_end, excl);
+ VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
ELEM_REMOVE(&beg->link);
ELEM_REMOVE(&end->link);
@@ -3432,11 +3549,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
VALUE ary = iobj->operands[0];
rb_obj_reveal(ary, rb_cArray);
- iobj->insn_id = BIN(opt_ary_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = ary;
- iobj->operands[1] = (VALUE)ci;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
ELEM_REMOVE(next);
}
}
@@ -3457,12 +3570,9 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
VALUE hash = iobj->operands[0];
rb_obj_reveal(hash, rb_cHash);
+ RB_OBJ_SET_SHAREABLE(hash);
- iobj->insn_id = BIN(opt_hash_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = hash;
- iobj->operands[1] = (VALUE)ci;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
ELEM_REMOVE(next);
}
}
@@ -3481,11 +3591,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
- iobj->insn_id = BIN(opt_ary_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = rb_cArray_empty_frozen;
- iobj->operands[1] = (VALUE)ci;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
ELEM_REMOVE(next);
}
}
@@ -3504,11 +3610,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
- iobj->insn_id = BIN(opt_hash_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = rb_cHash_empty_frozen;
- iobj->operands[1] = (VALUE)ci;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
ELEM_REMOVE(next);
}
}
@@ -3598,16 +3700,16 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* =>
* jump L1
*
- * putstring ".."
+ * dupstring ".."
* if L1
* =>
* jump L1
*
- * putstring ".."
+ * dupstring ".."
* dup
* if L1
* =>
- * putstring ".."
+ * dupstring ".."
* jump L1
*
*/
@@ -3622,7 +3724,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
OPERAND_AT(pobj, 0) == Qfalse :
FALSE);
}
- else if (IS_INSN_ID(pobj, putstring) ||
+ else if (IS_INSN_ID(pobj, dupstring) ||
IS_INSN_ID(pobj, duparray) ||
IS_INSN_ID(pobj, newarray)) {
cond = IS_INSN_ID(iobj, branchif);
@@ -3660,7 +3762,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN_ID(iobj, pop)) {
/*
- * putself / putnil / putobject obj / putstring "..."
+ * putself / putnil / putobject obj / dupstring "..."
* pop
* =>
* # do nothing
@@ -3669,8 +3771,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN(prev)) {
enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
if (previ == BIN(putobject) || previ == BIN(putnil) ||
- previ == BIN(putself) || previ == BIN(putstring) ||
- previ == BIN(putchilledstring) ||
+ previ == BIN(putself) || previ == BIN(dupstring) ||
+ previ == BIN(dupchilledstring) ||
previ == BIN(dup) ||
previ == BIN(getlocal) ||
previ == BIN(getblockparam) ||
@@ -3812,10 +3914,10 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
- if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
+ if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
(IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
/*
- * putstring ""
+ * dupstring ""
* concatstrings N
* =>
* concatstrings N-1
@@ -3842,6 +3944,9 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
rb_set_errinfo(errinfo);
COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
}
+ else {
+ RB_OBJ_SET_SHAREABLE(re);
+ }
RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
ELEM_REMOVE(iobj->link.next);
}
@@ -3883,8 +3988,6 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (do_tailcallopt &&
(IS_INSN_ID(iobj, send) ||
- IS_INSN_ID(iobj, opt_aref_with) ||
- IS_INSN_ID(iobj, opt_aset_with) ||
IS_INSN_ID(iobj, invokesuper))) {
/*
* send ...
@@ -4085,7 +4188,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
unsigned int flags = vm_ci_flag(ci);
if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
((INSN*)niobj)->insn_id = BIN(putobject);
- OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
+ RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
@@ -4102,17 +4205,16 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
static int
insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
{
- iobj->insn_id = insn_id;
- iobj->operand_size = insn_len(insn_id) - 1;
- iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
-
if (insn_id == BIN(opt_neq)) {
VALUE original_ci = iobj->operands[0];
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
- iobj->operands[1] = original_ci;
+ VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
+ insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
}
+ else {
+ iobj->insn_id = insn_id;
+ iobj->operand_size = insn_len(insn_id) - 1;
+ }
+ iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
return COMPILE_OK;
}
@@ -4144,38 +4246,28 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
if (method != INT2FIX(0)) {
VALUE num = iobj->operands[0];
- int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
- iobj->operands[0] = num;
- iobj->operands[1] = method;
- iobj->operand_size = operand_len;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
ELEM_REMOVE(&niobj->link);
return COMPILE_OK;
}
}
}
- else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
+ else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
(IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
IS_NEXT_INSN_ID(&niobj->link, send)) {
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
VALUE num = iobj->operands[0];
- int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
- iobj->operands[0] = FIXNUM_INC(num, 1);
- iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
- iobj->operand_size = operand_len;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
ELEM_REMOVE(&iobj->link);
ELEM_REMOVE(niobj->link.next);
ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
return COMPILE_OK;
}
}
- // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
- // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
- else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
+ // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
+ // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
+ else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
(IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
(niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
@@ -4184,12 +4276,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
(kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
VALUE num = iobj->operands[0];
- int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
- iobj->operands[0] = FIXNUM_INC(num, 2);
- iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
- iobj->operand_size = operand_len;
+ insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
// Remove the "send" insn.
ELEM_REMOVE((niobj->link.next)->next);
// Remove the modified insn from its original "newarray" position...
@@ -4203,7 +4290,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
// Break the "else if" chain since some prior checks abort after sub-ifs.
// We already found "newarray". To match `[...].include?(arg)` we look for
// the instruction(s) representing the argument followed by a "send".
- if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
+ if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
IS_INSN_ID(niobj, putobject) ||
IS_INSN_ID(niobj, putself) ||
IS_INSN_ID(niobj, getlocal) ||
@@ -4223,11 +4310,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
VALUE num = iobj->operands[0];
INSN *sendins = (INSN *)sendobj;
- sendins->insn_id = BIN(opt_newarray_send);
- sendins->operand_size = insn_len(sendins->insn_id) - 1;
- sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
- sendins->operands[0] = FIXNUM_INC(num, 1);
- sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
+ insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
// Remove the original "newarray" insn.
ELEM_REMOVE(&iobj->link);
return COMPILE_OK;
@@ -4265,12 +4348,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
rb_obj_reveal(ary, rb_cArray);
INSN *sendins = (INSN *)sendobj;
- sendins->insn_id = BIN(opt_duparray_send);
- sendins->operand_size = insn_len(sendins->insn_id) - 1;;
- sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
- sendins->operands[0] = ary;
- sendins->operands[1] = rb_id2sym(idIncludeP);
- sendins->operands[2] = INT2FIX(1);
+ insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
// Remove the duparray insn.
ELEM_REMOVE(&iobj->link);
@@ -4361,6 +4439,7 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
+ const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
int rescue_level = 0;
int tailcallopt = do_tailcallopt;
@@ -4393,6 +4472,22 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
insn_operands_unification((INSN *)list);
}
+ if (do_without_ints) {
+ INSN *item = (INSN *)list;
+ if (IS_INSN_ID(item, jump)) {
+ item->insn_id = BIN(jump_without_ints);
+ }
+ else if (IS_INSN_ID(item, branchif)) {
+ item->insn_id = BIN(branchif_without_ints);
+ }
+ else if (IS_INSN_ID(item, branchunless)) {
+ item->insn_id = BIN(branchunless_without_ints);
+ }
+ else if (IS_INSN_ID(item, branchnil)) {
+ item->insn_id = BIN(branchnil_without_ints);
+ }
+ }
+
if (do_block_optimization) {
INSN * item = (INSN *)list;
// Give up if there is a throw
@@ -4460,7 +4555,7 @@ new_unified_insn(rb_iseq_t *iseq,
}
if (argc > 0) {
- ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
+ ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
}
/* copy operands */
@@ -4664,7 +4759,8 @@ 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_node_dstr_string_val(node);
- ADD_INSN1(ret, node, putstring, lit);
+ ADD_INSN1(ret, node, dupstring, lit);
+ RB_OBJ_SET_SHAREABLE(lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
else {
@@ -4684,6 +4780,7 @@ compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
if (!popped) {
VALUE src = rb_node_dregx_string_val(node);
VALUE match = rb_reg_compile(src, cflag, NULL, 0);
+ RB_OBJ_SET_SHAREABLE(match);
ADD_INSN1(ret, node, putobject, match);
RB_OBJ_WRITTEN(iseq, Qundef, match);
}
@@ -4776,6 +4873,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
cond = RNODE_AND(cond)->nd_2nd;
if (ok == COMPILE_SINGLE) {
+ ADD_INSNL(ret, cond, jump, else_label);
INIT_ANCHOR(ignore);
ret = ignore;
then_label = NEW_LABEL(nd_line(cond));
@@ -4785,6 +4883,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
cond = RNODE_OR(cond)->nd_2nd;
if (ok == COMPILE_SINGLE) {
+ ADD_INSNL(ret, cond, jump, then_label);
INIT_ANCHOR(ignore);
ret = ignore;
else_label = NEW_LABEL(nd_line(cond));
@@ -5028,13 +5127,21 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
{
switch (nd_type(node)) {
case NODE_INTEGER:
- return rb_node_integer_literal_val(node);
+ {
+ VALUE lit = rb_node_integer_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
+ return lit;
+ }
case NODE_FLOAT:
- return rb_node_float_literal_val(node);
+ {
+ VALUE lit = rb_node_float_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
+ return lit;
+ }
case NODE_RATIONAL:
- return rb_node_rational_literal_val(node);
+ return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
case NODE_IMAGINARY:
- return rb_node_imaginary_literal_val(node);
+ return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
case NODE_NIL:
return Qnil;
case NODE_TRUE:
@@ -5044,7 +5151,7 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
case NODE_SYM:
return rb_node_sym_string_val(node);
case NODE_REGX:
- return rb_node_regx_string_val(node);
+ return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
case NODE_LINE:
return rb_node_line_lineno_val(node);
case NODE_ENCODING:
@@ -5053,7 +5160,9 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
case NODE_STR:
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE lit = get_string_value(node);
- return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
+ VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
+ RB_OBJ_SET_SHAREABLE(str);
+ return str;
}
else {
return get_string_value(node);
@@ -5151,7 +5260,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
/* 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));
- OBJ_FREEZE(ary);
+ RB_OBJ_SET_FROZEN_SHAREABLE(ary);
/* Emit optimized code */
FLUSH_CHUNK;
@@ -5163,6 +5272,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
ADD_INSN1(ret, line_node, putobject, ary);
ADD_INSN(ret, line_node, concattoarray);
}
+ RB_OBJ_SET_SHAREABLE(ary);
RB_OBJ_WRITTEN(iseq, Qundef, ary);
}
}
@@ -5289,13 +5399,15 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
VALUE elem[2];
elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
+ if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
+ if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
rb_ary_cat(ary, elem, 2);
}
- VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
+ VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
- hash = rb_obj_hide(hash);
- OBJ_FREEZE(hash);
+ RB_GC_GUARD(ary);
+ hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
/* Emit optimized code */
FLUSH_CHUNK();
@@ -5444,8 +5556,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
if (UNDEF_P(lit)) {
only_special_literals = 0;
}
- else if (NIL_P(rb_hash_lookup(literals, lit))) {
- rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
+ else {
+ cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
}
if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
@@ -5962,10 +6074,12 @@ collect_const_segments(rb_iseq_t *iseq, const NODE *node)
switch (nd_type(node)) {
case NODE_CONST:
rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
+ RB_OBJ_SET_SHAREABLE(arr);
return arr;
case NODE_COLON3:
rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
rb_ary_unshift(arr, ID2SYM(idNULL));
+ RB_OBJ_SET_SHAREABLE(arr);
return arr;
case NODE_COLON2:
rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
@@ -6008,6 +6122,23 @@ compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
}
static int
+cpath_const_p(const NODE *node)
+{
+ switch (nd_type(node)) {
+ case NODE_CONST:
+ case NODE_COLON3:
+ return TRUE;
+ case NODE_COLON2:
+ if (RNODE_COLON2(node)->nd_head) {
+ return cpath_const_p(RNODE_COLON2(node)->nd_head);
+ }
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static int
compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
{
if (nd_type_p(cpath, NODE_COLON3)) {
@@ -6016,9 +6147,13 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
return VM_DEFINECLASS_FLAG_SCOPED;
}
else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
- /* Bar::Foo */
+ /* Bar::Foo or expr::Foo */
NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
- return VM_DEFINECLASS_FLAG_SCOPED;
+ int flags = VM_DEFINECLASS_FLAG_SCOPED;
+ if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
+ flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+ return flags;
}
else {
/* class at cbase Foo */
@@ -6375,7 +6510,7 @@ add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
LABEL *lstart, LABEL *lend)
{
struct ensure_range *ne =
- compile_data_alloc(iseq, sizeof(struct ensure_range));
+ compile_data_alloc_type(iseq, struct ensure_range);
while (erange->next != 0) {
erange = erange->next;
@@ -6634,6 +6769,14 @@ setup_args_dup_rest_p(const NODE *argn)
return false;
case NODE_COLON2:
return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
+ case NODE_LIST:
+ while (argn) {
+ if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
+ return true;
+ }
+ argn = RNODE_LIST(argn)->nd_next;
+ }
+ return false;
default:
return true;
}
@@ -6956,7 +7099,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
DECL_ANCHOR(body_seq);
DECL_ANCHOR(cond_seq);
int only_special_literals = 1;
- VALUE literals = rb_hash_new();
+ VALUE literals = cdhash_new(0);
int line;
enum node_type type;
const NODE *line_node;
@@ -6967,8 +7110,6 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);
- RHASH_TBL_RAW(literals)->type = &cdhash_type;
-
CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
@@ -7589,6 +7730,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, putnil);
}
else {
+ RB_OBJ_SET_FROZEN_SHAREABLE(keys);
ADD_INSN1(ret, line_node, duparray, keys);
RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
}
@@ -7626,7 +7768,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_INSNL(ret, line_node, branchif, match_succeeded);
- ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
+ VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
+ ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
@@ -8967,25 +9110,6 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
}
return TRUE;
}
- /* 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) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
- ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !frozen_string_literal_p(iseq) &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
- CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
- ADD_INSN2(ret, line_node, opt_aref_with, str,
- new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
- RB_OBJ_WRITTEN(iseq, Qundef, str);
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
- return TRUE;
- }
return FALSE;
}
@@ -9143,6 +9267,9 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
+ else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
+ ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
+ }
else {
goto unknown_arg;
}
@@ -9244,16 +9371,18 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
rb_node_init(RNODE(&scope_node), NODE_SCOPE);
scope_node.nd_tbl = tbl;
scope_node.nd_body = mandatory_node(iseq, node);
+ scope_node.nd_parent = NULL;
scope_node.nd_args = &args_node;
VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
- ISEQ_BODY(iseq)->mandatory_only_iseq =
+ const rb_iseq_t *mandatory_only_iseq =
rb_iseq_new_with_opt(ast_value, 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,
ISEQ_BODY(iseq)->variable.script_lines);
+ RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
ALLOCV_END(idtmp);
return COMPILE_OK;
@@ -9374,6 +9503,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
+
#if OPT_SUPPORT_JOKE
if (nd_type_p(node, NODE_VCALL)) {
ID id_bitblt;
@@ -9469,6 +9599,17 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
}
ADD_SEQ(ret, recv);
+
+ bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
+ mid == rb_intern("new") &&
+ parent_block == NULL &&
+ !(flag & VM_CALL_ARGS_BLOCKARG);
+
+ if (inline_new) {
+ ADD_INSN(ret, node, putnil);
+ ADD_INSN(ret, node, swap);
+ }
+
ADD_SEQ(ret, args);
debugp_param("call args argc", argc);
@@ -9485,7 +9626,37 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
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);
+
+ LABEL *not_basic_new = NEW_LABEL(nd_line(node));
+ LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
+
+ if (inline_new) {
+ // Jump unless the receiver uses the "basic" implementation of "new"
+ VALUE ci;
+ if (flag & VM_CALL_FORWARDING) {
+ ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
+ }
+ else {
+ ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
+ }
+ ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
+ LABEL_REF(not_basic_new);
+
+ // optimized path
+ ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
+ ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
+
+ ADD_LABEL(ret, not_basic_new);
+ // Fall back to normal send
+ ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
+ ADD_INSN(ret, line_node, swap);
+
+ ADD_LABEL(ret, not_basic_new_finish);
+ ADD_INSN(ret, line_node, pop);
+ }
+ else {
+ ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
+ }
qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
if (popped) {
@@ -10070,9 +10241,13 @@ 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, rb_node_regx_string_val(node));
- ADD_INSN2(val, node, getspecial, INT2FIX(0),
- INT2FIX(0));
+ {
+ VALUE re = rb_node_regx_string_val(node);
+ RB_OBJ_SET_FROZEN_SHAREABLE(re);
+ ADD_INSN1(recv, node, putobject, re);
+ ADD_INSN2(val, node, getspecial, INT2FIX(0),
+ INT2FIX(0));
+ }
break;
case NODE_MATCH2:
CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
@@ -10149,6 +10324,7 @@ compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
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));
+ RB_OBJ_SET_FROZEN_SHAREABLE(segments);
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
@@ -10176,6 +10352,7 @@ compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
VALUE bv = optimized_range_item(b);
VALUE ev = optimized_range_item(e);
VALUE val = rb_range_new(bv, ev, excl);
+ rb_ractor_make_shareable(rb_obj_freeze(val));
ADD_INSN1(ret, node, putobject, val);
RB_OBJ_WRITTEN(iseq, Qundef, val);
}
@@ -10270,31 +10447,6 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
LABEL *else_label = NULL;
VALUE branches = Qfalse;
- /* 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) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
- ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !frozen_string_literal_p(iseq) &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
- {
- VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
- 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));
- if (!popped) {
- ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, topn, INT2FIX(1));
- }
- ADD_INSN2(ret, node, opt_aset_with, str,
- new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
- RB_OBJ_WRITTEN(iseq, Qundef, str);
- ADD_INSN(ret, node, pop);
- return COMPILE_OK;
- }
-
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
@@ -10637,8 +10789,10 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa
ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
}
else if (nd_type(node) == NODE_HASH) {
- int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
- ADD_INSN1(anchor, node, newhash, INT2FIX(len));
+ long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
+ RBIMPL_ASSERT_OR_ASSUME(len >= 0);
+ RBIMPL_ASSERT_OR_ASSUME(RB_POSFIXABLE(len));
+ ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
}
*value_p = Qundef;
*shareable_literal_p = 0;
@@ -10652,8 +10806,10 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa
ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
}
else if (nd_type(node) == NODE_HASH) {
- int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
- ADD_INSN1(anchor, node, newhash, INT2FIX(len));
+ long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
+ RBIMPL_ASSERT_OR_ASSUME(len >= 0);
+ RBIMPL_ASSERT_OR_ASSUME(RB_POSFIXABLE(len));
+ ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
}
CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
*value_p = Qundef;
@@ -10740,7 +10896,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
if (nd_fl_newline(node)) {
int event = RUBY_EVENT_LINE;
ISEQ_COMPILE_DATA(iseq)->last_line = line;
- if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
+ if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
event |= RUBY_EVENT_COVERAGE_LINE;
}
ADD_TRACE(ret, event);
@@ -10827,10 +10983,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
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;
}
@@ -11012,6 +11165,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
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));
+ RB_OBJ_SET_FROZEN_SHAREABLE(segments);
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
@@ -11077,6 +11231,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_INTEGER:{
VALUE lit = rb_node_integer_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
debugp_param("integer", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11086,6 +11241,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_FLOAT:{
VALUE lit = rb_node_float_literal_val(node);
+ if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
debugp_param("float", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11095,6 +11251,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_RATIONAL:{
VALUE lit = rb_node_rational_literal_val(node);
+ rb_ractor_make_shareable(lit);
debugp_param("rational", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11104,6 +11261,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_IMAGINARY:{
VALUE lit = rb_node_imaginary_literal_val(node);
+ rb_ractor_make_shareable(lit);
debugp_param("imaginary", lit);
if (!popped) {
ADD_INSN1(ret, node, putobject, lit);
@@ -11120,13 +11278,14 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
+ RB_OBJ_SET_SHAREABLE(lit);
}
switch (option->frozen_string_literal) {
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
- ADD_INSN1(ret, node, putchilledstring, lit);
+ ADD_INSN1(ret, node, dupchilledstring, lit);
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
- ADD_INSN1(ret, node, putstring, lit);
+ ADD_INSN1(ret, node, dupstring, lit);
break;
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
ADD_INSN1(ret, node, putobject, lit);
@@ -11174,6 +11333,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_REGX:{
if (!popped) {
VALUE lit = rb_node_regx_string_val(node);
+ RB_OBJ_SET_SHAREABLE(lit);
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -11366,9 +11526,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
ADD_INSN (ret, node, putnil);
CONST_ID(singletonclass, "singletonclass");
+
+ /* `class << self` in a class body and `class << Foo` (constant
+ receiver) are stable. All other forms are potentially dynamic. */
+ int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
+ const NODE *recv = RNODE_SCLASS(node)->nd_recv;
+ if (!(nd_type_p(recv, NODE_SELF) &&
+ ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
+ !cpath_const_p(recv)) {
+ sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+
ADD_INSN3(ret, node, defineclass,
ID2SYM(singletonclass), singleton_class,
- INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
+ INT2FIX(sclass_flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
if (popped) {
@@ -11591,7 +11762,7 @@ insn_data_to_s_detail(INSN *iobj)
{
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
rb_str_cat2(str, "<calldata:");
- if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
+ if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
rb_str_catf(str, ", %d>", vm_ci_argc(ci));
break;
}
@@ -11945,7 +12116,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
}
if (argc > 0) {
- argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
+ argv = compile_data_calloc2_type(iseq, VALUE, argc);
// add element before operand setup to make GC root
ADD_ELEM(anchor,
@@ -12025,18 +12196,18 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
case TS_CDHASH:
{
int i;
- VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
+ VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
- RHASH_TBL_RAW(map)->type = &cdhash_type;
op = rb_to_array_type(op);
for (i=0; i<RARRAY_LEN(op); i+=2) {
VALUE key = RARRAY_AREF(op, i);
VALUE sym = RARRAY_AREF(op, i+1);
LABEL *label =
register_label(iseq, labels_table, sym);
- rb_hash_aset(map, key, (VALUE)label | 1);
+ cdhash_aset(map, key, (VALUE)label);
}
RB_GC_GUARD(op);
+ RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
argv[j] = map;
RB_OBJ_WRITTEN(iseq, Qundef, map);
}
@@ -12171,23 +12342,18 @@ rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
{
INSN *iobj = 0;
size_t size = sizeof(INSN);
+ size_t align = ALIGNMENT_SIZE_OF(INSN);
unsigned int pos = 0;
while (storage) {
-#ifdef STRICT_ALIGNMENT
- size_t padding = calc_padding((void *)&storage->buff[pos], size);
-#else
- const size_t padding = 0; /* expected to be optimized by compiler */
-#endif /* STRICT_ALIGNMENT */
+ size_t padding = calc_padding((void *)&storage->buff[pos], align);
size_t offset = pos + size + padding;
if (offset > storage->size || offset > storage->pos) {
pos = 0;
storage = storage->next;
}
else {
-#ifdef STRICT_ALIGNMENT
pos += (int)padding;
-#endif /* STRICT_ALIGNMENT */
iobj = (INSN *)&storage->buff[pos];
@@ -12383,7 +12549,7 @@ typedef uint32_t ibf_offset_t;
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
#ifdef RUBY_DEVEL
-#define IBF_DEVEL_VERSION 4
+#define IBF_DEVEL_VERSION 5
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
#else
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
@@ -12542,8 +12708,13 @@ static ibf_offset_t
ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
{
ibf_offset_t pos = ibf_dump_pos(dump);
+#if SIZEOF_LONG > SIZEOF_INT
+ /* ensure the resulting dump does not exceed UINT_MAX */
+ if (size >= UINT_MAX || pos + size >= UINT_MAX) {
+ rb_raise(rb_eRuntimeError, "dump size exceeds");
+ }
+#endif
rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
- /* TODO: overflow check */
return pos;
}
@@ -12781,7 +12952,8 @@ ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
if (strncmp(table[i].name, name, len) != 0) {
- rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
+ rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
+ i, len, name, table[i].name);
}
// fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
@@ -12867,21 +13039,23 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
VALUE iseqv = (VALUE)iseq;
unsigned int code_index;
ibf_offset_t reading_pos = bytecode_offset;
- VALUE *code = ALLOC_N(VALUE, iseq_size);
+ VALUE *code = ZALLOC_N(VALUE, iseq_size);
struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
struct rb_call_data *cd_entries = load_body->call_data;
int ic_index = 0;
- iseq_bits_t * mark_offset_bits;
-
- iseq_bits_t tmp[1] = {0};
+ load_body->iseq_encoded = code;
+ load_body->iseq_size = iseq_size;
+ iseq_bits_t * mark_offset_bits;
if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
- mark_offset_bits = tmp;
+ load_body->mark_bits.single = 0;
+ mark_offset_bits = &load_body->mark_bits.single;
}
else {
- mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
+ load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
+ mark_offset_bits = load_body->mark_bits.list;
}
bool needs_bitmap = false;
@@ -12913,10 +13087,6 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
{
VALUE op = ibf_load_small_value(load, &reading_pos);
VALUE v = ibf_load_object(load, op);
- v = rb_hash_dup(v); // hash dumped as frozen
- RHASH_TBL_RAW(v)->type = &cdhash_type;
- rb_hash_rehash(v); // hash function changed
- freeze_hide_obj(v);
// Overwrite the existing hash in the object list. This
// is to keep the object alive during load time.
@@ -12967,12 +13137,12 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
if (insn == BIN(setinstancevariable)) {
ID iv_name = (ID)code[code_index - 1];
cache->iv_set_name = iv_name;
+ cache->value = IVAR_CACHE_INIT;
}
else {
cache->iv_set_name = 0;
+ cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
}
-
- vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
}
}
@@ -13004,20 +13174,9 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
}
}
- load_body->iseq_encoded = code;
- load_body->iseq_size = code_index;
-
- if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
- load_body->mark_bits.single = mark_offset_bits[0];
- }
- else {
- if (needs_bitmap) {
- load_body->mark_bits.list = mark_offset_bits;
- }
- else {
- load_body->mark_bits.list = 0;
- ruby_xfree(mark_offset_bits);
- }
+ if (!needs_bitmap) {
+ SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
+ load_body->mark_bits.list = NULL;
}
RUBY_ASSERT(code_index == iseq_size);
@@ -13189,7 +13348,7 @@ ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
return ibf_dump_write(dump, table, sizeof(ID) * size);
}
-static ID *
+static const ID *
ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
{
if (size > 0) {
@@ -13199,7 +13358,14 @@ ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offse
for (i=0; i<size; i++) {
table[i] = ibf_load_id(load, table[i]);
}
- return table;
+
+ if (size == 1 && table[0] == idERROR_INFO) {
+ ruby_xfree_sized(table, sizeof(ID) * size);
+ return rb_iseq_shared_exc_local_tbl;
+ }
+ else {
+ return table;
+ }
}
else {
return NULL;
@@ -13207,6 +13373,28 @@ ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offse
}
static ibf_offset_t
+ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
+{
+ const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+ const int size = body->local_table_size;
+ IBF_W_ALIGN(enum lvar_state);
+ return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
+}
+
+static enum lvar_state *
+ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
+{
+ if (local_table == rb_iseq_shared_exc_local_tbl ||
+ size <= 0) {
+ return NULL;
+ }
+ else {
+ enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
+ return states;
+ }
+}
+
+static ibf_offset_t
ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
{
const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
@@ -13236,12 +13424,13 @@ ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
}
}
-static struct iseq_catch_table *
-ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
+static void
+ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
{
if (size) {
- struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
+ struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
table->size = size;
+ ISEQ_BODY(parent_iseq)->catch_table = table;
ibf_offset_t reading_pos = catch_table_offset;
@@ -13254,12 +13443,12 @@ ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offse
table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
- table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
+ rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
+ RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
}
- return table;
}
else {
- return NULL;
+ ISEQ_BODY(parent_iseq)->catch_table = NULL;
}
}
@@ -13330,6 +13519,14 @@ 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;
+
+ if (!ap->name) {
+ return -1;
+ }
+ else if (!bp->name) {
+ return 1;
+ }
+
return rb_str_cmp(ap->name, bp->name);
}
@@ -13370,6 +13567,11 @@ ibf_load_ci_entries(const struct ibf_load *load,
unsigned int ci_size,
struct rb_call_data **cd_ptr)
{
+ if (!ci_size) {
+ *cd_ptr = NULL;
+ return;
+ }
+
ibf_offset_t reading_pos = ci_entries_offset;
unsigned int i;
@@ -13462,9 +13664,10 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
- ruby_xfree(positions);
+ SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
+ const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
@@ -13497,7 +13700,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
(body->param.flags.anon_rest << 10) |
(body->param.flags.anon_kwrest << 11) |
(body->param.flags.use_block << 12) |
- (body->param.flags.forwardable << 13) ;
+ (body->param.flags.forwardable << 13) |
+ (body->param.flags.accepts_no_block << 14);
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
# define IBF_BODY_OFFSET(x) (x)
@@ -13532,6 +13736,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
ibf_dump_write_small_value(dump, body->insns_info.size);
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
+ ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
ibf_dump_write_small_value(dump, catch_table_size);
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
ibf_dump_write_small_value(dump, parent_iseq_index);
@@ -13643,6 +13848,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
+ const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
@@ -13715,6 +13921,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
load_body->param.flags.use_block = (param_flags >> 12) & 1;
load_body->param.flags.forwardable = (param_flags >> 13) & 1;
+ load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
load_body->param.size = param_size;
load_body->param.lead_num = param_lead_num;
load_body->param.opt_num = param_opt_num;
@@ -13759,10 +13966,16 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
- load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
- load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
- load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
- load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
+ load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
+ ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
+
+ const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
+ const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
+ const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
+
+ RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
+ RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
+ RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
// This must be done after the local table is loaded.
if (load_body->param.keyword != NULL) {
@@ -13836,8 +14049,6 @@ ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
header->iseq_list_size = (unsigned int)size;
}
-#define IBF_OBJECT_INTERNAL FL_PROMOTED0
-
/*
* Binary format
* - ibf_object_header
@@ -13897,7 +14108,11 @@ struct ibf_object_symbol {
#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
((((offset) - 1) / (align) + 1) * (align))
-#define IBF_OBJBODY(type, offset) (const type *)\
+/* No cast, since it's UB to create an unaligned pointer.
+ * Leave as void* for use with memcpy in those cases.
+ * We align the offset, but the buffer pointer is only VALUE aligned,
+ * so the returned pointer may be unaligned for `type` .*/
+#define IBF_OBJBODY(type, offset) \
ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
static const void *
@@ -13992,8 +14207,12 @@ ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
static VALUE
ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
{
- const double *dblp = IBF_OBJBODY(double, offset);
- return DBL2NUM(*dblp);
+ double d;
+ /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
+ memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
+ VALUE f = DBL2NUM(d);
+ if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
+ return f;
}
static void
@@ -14064,7 +14283,7 @@ ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_head
VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
if (header->internal) rb_obj_hide(reg);
- if (header->frozen) rb_obj_freeze(reg);
+ if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
return reg;
}
@@ -14095,7 +14314,10 @@ ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_heade
rb_ary_push(ary, ibf_load_object(load, index));
}
- if (header->frozen) rb_ary_freeze(ary);
+ if (header->frozen) {
+ rb_ary_freeze(ary);
+ rb_ractor_make_shareable(ary); // TODO: check elements
+ }
return ary;
}
@@ -14126,7 +14348,7 @@ static VALUE
ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
{
long len = (long)ibf_load_small_value(load, &offset);
- VALUE obj = rb_hash_new_with_size(len);
+ VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_with_size(len);
int i;
for (i = 0; i < len; i++) {
@@ -14137,10 +14359,59 @@ ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header
VALUE val = ibf_load_object(load, val_index);
rb_hash_aset(obj, key, val);
}
- rb_hash_rehash(obj);
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) {
+ RB_OBJ_SET_FROZEN_SHAREABLE(obj);
+ }
+
+ return obj;
+}
+
+static int
+ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
+{
+ struct ibf_dump *dump = (struct ibf_dump *)ptr;
+
+ VALUE key_index = ibf_dump_object(dump, (VALUE)key);
+
+ ibf_dump_write_small_value(dump, key_index);
+ ibf_dump_write_small_value(dump, val);
+ return ST_CONTINUE;
+}
+
+static void
+ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
+{
+ switch (imemo_type(obj)) {
+ case imemo_cdhash: {
+ st_table *tbl = rb_imemo_cdhash_tbl(obj);
+
+ long len = tbl->num_entries;
+ ibf_dump_write_small_value(dump, (VALUE)len);
+ if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
+ break;
+ }
+ default:
+ ibf_dump_object_unsupported(dump, obj);
+ break;
+ }
+}
+
+static VALUE
+ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
+{
+ long len = (long)ibf_load_small_value(load, &offset);
+ VALUE obj = cdhash_new(len);
+
+ int i;
+ for (i = 0; i < len; i++) {
+ VALUE key_index = ibf_load_small_value(load, &offset);
+ VALUE val = ibf_load_small_value(load, &offset);
+
+ VALUE key = ibf_load_object(load, key_index);
+ cdhash_aset(obj, key, val);
+ }
return obj;
}
@@ -14176,7 +14447,7 @@ ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_head
VALUE end = ibf_load_object(load, range->end);
VALUE obj = rb_range_new(beg, end, range->excl);
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
return obj;
}
@@ -14204,7 +14475,7 @@ ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_head
big_unpack_flags |
(sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
return obj;
}
@@ -14265,7 +14536,7 @@ ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_o
rb_complex_new(a, b) : rb_rational_new(a, b);
if (header->internal) rb_obj_hide(obj);
- if (header->frozen) rb_obj_freeze(obj);
+ if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
return obj;
}
@@ -14321,7 +14592,7 @@ static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
ibf_dump_object_unsupported, /* 0x17 */
ibf_dump_object_unsupported, /* 0x18 */
ibf_dump_object_unsupported, /* 0x19 */
- ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
+ ibf_dump_object_imemo, /* T_IMEMO 0x1a */
ibf_dump_object_unsupported, /* T_NODE 0x1b */
ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
@@ -14378,7 +14649,7 @@ ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
else {
obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
obj_header.special_const = FALSE;
- obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
+ obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
ibf_dump_object_object_header(dump, obj_header);
(*dump_object_functions[obj_header.type])(dump, obj);
}
@@ -14414,7 +14685,7 @@ static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
ibf_load_object_unsupported, /* 0x17 */
ibf_load_object_unsupported, /* 0x18 */
ibf_load_object_unsupported, /* 0x19 */
- ibf_load_object_unsupported, /* T_IMEMO 0x1a */
+ ibf_load_object_imemo, /* T_IMEMO 0x1a */
ibf_load_object_unsupported, /* T_NODE 0x1b */
ibf_load_object_unsupported, /* T_ICLASS 0x1c */
ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
@@ -14770,7 +15041,7 @@ static void
ibf_loader_free(void *ptr)
{
struct ibf_load *load = (struct ibf_load *)ptr;
- ruby_xfree(load);
+ SIZED_FREE(load);
}
static size_t
diff --git a/complex.c b/complex.c
index 6e4ec3b6c2..8c661f2019 100644
--- a/complex.c
+++ b/complex.c
@@ -20,6 +20,7 @@
#include "internal/array.h"
#include "internal/class.h"
#include "internal/complex.h"
+#include "internal/error.h"
#include "internal/math.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -51,20 +52,6 @@ static ID id_abs, id_arg,
#define id_quo idQuo
#define id_fdiv idFdiv
-#define fun1(n) \
-inline static VALUE \
-f_##n(VALUE x)\
-{\
- return rb_funcall(x, id_##n, 0);\
-}
-
-#define fun2(n) \
-inline static VALUE \
-f_##n(VALUE x, VALUE y)\
-{\
- return rb_funcall(x, id_##n, 1, y);\
-}
-
#define PRESERVE_SIGNEDZERO
inline static VALUE
@@ -275,8 +262,6 @@ f_to_f(VALUE x)
return rb_funcall(x, id_to_f, 0);
}
-fun1(to_r)
-
inline static int
f_eqeq_p(VALUE x, VALUE y)
{
@@ -287,8 +272,18 @@ f_eqeq_p(VALUE x, VALUE y)
return (int)rb_equal(x, y);
}
-fun2(expt)
-fun2(fdiv)
+static VALUE
+f_fdiv(VALUE x, VALUE y)
+{
+ if (RB_INTEGER_TYPE_P(x))
+ return rb_int_fdiv(x, y);
+ if (RB_FLOAT_TYPE_P(x))
+ return rb_float_div(x, y);
+ if (RB_TYPE_P(x, T_RATIONAL))
+ return rb_rational_fdiv(x, y);
+
+ return rb_funcallv(x, id_fdiv, 1, &y);
+}
static VALUE
f_quo(VALUE x, VALUE y)
@@ -317,24 +312,6 @@ f_negative_p(VALUE x)
#define f_positive_p(x) (!f_negative_p(x))
-inline static bool
-f_zero_p(VALUE x)
-{
- if (RB_FLOAT_TYPE_P(x)) {
- return FLOAT_ZERO_P(x);
- }
- else if (RB_INTEGER_TYPE_P(x)) {
- return FIXNUM_ZERO_P(x);
- }
- else if (RB_TYPE_P(x, T_RATIONAL)) {
- const VALUE num = RRATIONAL(x)->num;
- return FIXNUM_ZERO_P(num);
- }
- return rb_equal(x, ZERO) != 0;
-}
-
-#define f_nonzero_p(x) (!f_zero_p(x))
-
static inline bool
always_finite_type_p(VALUE x)
{
@@ -392,8 +369,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, sizeof(struct RComplex));
RCOMPLEX_SET_REAL(obj, real);
RCOMPLEX_SET_IMAG(obj, imag);
@@ -799,9 +775,9 @@ rb_complex_imag(VALUE self)
/*
* call-seq:
- * -complex -> new_complex
+ * -self -> complex
*
- * Returns the negation of +self+, which is the negation of each of its parts:
+ * Returns +self+, negated, which is the negation of each of its parts:
*
* -Complex.rect(1, 2) # => (-1-2i)
* -Complex.rect(-1, -2) # => (1+2i)
@@ -816,17 +792,26 @@ rb_complex_uminus(VALUE self)
}
/*
- * call-seq:
- * complex + numeric -> new_complex
+ * call-seq:
+ * self + other -> numeric
+ *
+ * Returns the sum of +self+ and +other+:
*
- * Returns the sum of +self+ and +numeric+:
+ * Complex(1, 2) + 0 # => (1+2i)
+ * Complex(1, 2) + 1 # => (2+2i)
+ * Complex(1, 2) + -1 # => (0+2i)
*
- * Complex.rect(2, 3) + Complex.rect(2, 3) # => (4+6i)
- * Complex.rect(900) + Complex.rect(1) # => (901+0i)
- * Complex.rect(-2, 9) + Complex.rect(-9, 2) # => (-11+11i)
- * Complex.rect(9, 8) + 4 # => (13+8i)
- * Complex.rect(20, 9) + 9.8 # => (29.8+9i)
+ * Complex(1, 2) + 1.0 # => (2.0+2i)
*
+ * Complex(1, 2) + Complex(2, 1) # => (3+3i)
+ * Complex(1, 2) + Complex(2.0, 1.0) # => (3.0+3.0i)
+ *
+ * Complex(1, 2) + Rational(1, 1) # => ((2/1)+2i)
+ * Complex(1, 2) + Rational(1, 2) # => ((3/2)+2i)
+ *
+ * For a computation involving Floats, the result may be inexact (see Float#+):
+ *
+ * Complex(1, 2) + 3.14 # => (4.140000000000001+2i)
*/
VALUE
rb_complex_plus(VALUE self, VALUE other)
@@ -852,9 +837,9 @@ rb_complex_plus(VALUE self, VALUE other)
/*
* call-seq:
- * complex - numeric -> new_complex
+ * self - other -> complex
*
- * Returns the difference of +self+ and +numeric+:
+ * Returns the difference of +self+ and +other+:
*
* Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i)
* Complex.rect(900) - Complex.rect(1) # => (899+0i)
@@ -913,15 +898,16 @@ comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE
/*
* call-seq:
- * complex * numeric -> new_complex
+ * self * other -> numeric
*
- * Returns the product of +self+ and +numeric+:
+ * Returns the numeric product of +self+ and +other+:
*
+ * Complex.rect(9, 8) * 4 # => (36+32i)
+ * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i)
* Complex.rect(2, 3) * Complex.rect(2, 3) # => (-5+12i)
* Complex.rect(900) * Complex.rect(1) # => (900+0i)
* Complex.rect(-2, 9) * Complex.rect(-9, 2) # => (0-85i)
- * Complex.rect(9, 8) * 4 # => (36+32i)
- * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i)
+ * Complex.rect(9, 8) * Rational(2, 3) # => ((6/1)+(16/3)*i)
*
*/
VALUE
@@ -989,9 +975,9 @@ f_divide(VALUE self, VALUE other,
/*
* call-seq:
- * complex / numeric -> new_complex
+ * self / other -> complex
*
- * Returns the quotient of +self+ and +numeric+:
+ * Returns the quotient of +self+ and +other+:
*
* Complex.rect(2, 3) / Complex.rect(2, 3) # => (1+0i)
* Complex.rect(900) / Complex.rect(1) # => (900+0i)
@@ -1065,7 +1051,8 @@ complex_pow_for_special_angle(VALUE self, VALUE other)
else if (f_eqeq_p(dat->real, f_negate(dat->imag))) {
x = dat->imag;
dir = 3;
- } else {
+ }
+ else {
dir = 0;
}
@@ -1111,9 +1098,9 @@ complex_pow_for_special_angle(VALUE self, VALUE other)
/*
* call-seq:
- * complex ** numeric -> new_complex
+ * self ** exponent -> complex
*
- * Returns +self+ raised to power +numeric+:
+ * Returns +self+ raised to the power +exponent+:
*
* Complex.rect(0, 1) ** 2 # => (-1+0i)
* Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i)
@@ -1204,21 +1191,20 @@ rb_complex_pow(VALUE self, VALUE other)
if (RB_BIGNUM_TYPE_P(other))
rb_warn("in a**b, b may be too big");
- r = f_abs(self);
- theta = f_arg(self);
+ r = rb_num_pow(f_abs(self), other);
+ theta = f_mul(f_arg(self), other);
- return f_complex_polar(CLASS_OF(self), f_expt(r, other),
- f_mul(theta, other));
+ return f_complex_polar(CLASS_OF(self), r, theta);
}
return rb_num_coerce_bin(self, other, id_expt);
}
/*
* call-seq:
- * complex == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if <tt>self.real == object.real</tt>
- * and <tt>self.imag == object.imag</tt>:
+ * Returns whether both <tt>self.real == other.real</tt>
+ * and <tt>self.imag == other.imag</tt>:
*
* Complex.rect(2, 3) == Complex.rect(2.0, 3.0) # => true
*
@@ -1249,14 +1235,16 @@ nucomp_real_p(VALUE self)
/*
* call-seq:
- * complex <=> object -> -1, 0, 1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
*
* Returns:
*
- * - <tt>self.real <=> object.real</tt> if both of the following are true:
+ * - <tt>self.real <=> other.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.
+ * - <tt>other.imag == 0</tt> (always true if +other+ is numeric but not complex).
*
* - +nil+ otherwise.
*
@@ -1269,6 +1257,8 @@ nucomp_real_p(VALUE self)
* Complex.rect(1) <=> Complex.rect(1, 1) # => nil # object.imag not zero.
* Complex.rect(1) <=> 'Foo' # => nil # object.imag not defined.
*
+ * \Class \Complex includes module Comparable,
+ * each of whose methods uses Complex#<=> for comparison.
*/
static VALUE
nucomp_cmp(VALUE self, VALUE other)
@@ -1764,12 +1754,6 @@ rb_complex_new_polar(VALUE x, VALUE y)
}
VALUE
-rb_complex_polar(VALUE x, VALUE y)
-{
- return rb_complex_new_polar(x, y);
-}
-
-VALUE
rb_Complex(VALUE x, VALUE y)
{
VALUE a[2];
@@ -1794,7 +1778,7 @@ rb_dbl_complex_new(double real, double imag)
* Complex.rect(1, Rational(0, 1)).to_i # => 1
*
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>).
*/
static VALUE
nucomp_to_i(VALUE self)
@@ -1818,7 +1802,7 @@ nucomp_to_i(VALUE self)
* Complex.rect(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>).
+ * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>).
*/
static VALUE
nucomp_to_f(VALUE self)
@@ -1843,7 +1827,7 @@ nucomp_to_f(VALUE self)
* Complex.rect(1, 0.0).to_r # => (1/1)
*
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>)
+ * (either <tt>Integer(0)</tt> or <tt>Rational(0, n)</tt>)
* and <tt>self.imag.to_r</tt> is not exactly zero.
*
* Related: Complex#rationalize.
@@ -1863,7 +1847,7 @@ nucomp_to_r(VALUE self)
self);
}
}
- return f_to_r(dat->real);
+ return rb_funcallv(dat->real, id_to_r, 0, 0);
}
/*
@@ -1926,21 +1910,6 @@ nucomp_to_c(VALUE self)
/*
* call-seq:
- * to_c -> (0+0i)
- *
- * Returns zero as a Complex:
- *
- * nil.to_c # => (0+0i)
- *
- */
-static VALUE
-nilclass_to_c(VALUE self)
-{
- return rb_complex_new1(INT2FIX(0));
-}
-
-/*
- * call-seq:
* to_c -> complex
*
* Returns +self+ as a Complex object.
@@ -2243,28 +2212,156 @@ 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)
+ * Returns a Complex object:
+ * parses the leading substring of +self+
+ * to extract two numeric values that become the coordinates of the complex object.
+ *
+ * The substring is interpreted as containing
+ * either rectangular coordinates (real and imaginary parts)
+ * or polar coordinates (magnitude and angle parts),
+ * depending on an included or implied "separator" character:
+ *
+ * - <tt>'+'</tt>, <tt>'-'</tt>, or no separator: rectangular coordinates.
+ * - <tt>'@'</tt>: polar coordinates.
+ *
+ * <b>In Brief</b>
+ *
+ * In these examples, we use method Complex#rect to display rectangular coordinates,
+ * and method Complex#polar to display polar coordinates.
+ *
+ * # Rectangular coordinates.
+ *
+ * # Real-only: no separator; imaginary part is zero.
+ * '9'.to_c.rect # => [9, 0] # Integer.
+ * '-9'.to_c.rect # => [-9, 0] # Integer (negative).
+ * '2.5'.to_c.rect # => [2.5, 0] # Float.
+ * '1.23e-14'.to_c.rect # => [1.23e-14, 0] # Float with exponent.
+ * '2.5/1'.to_c.rect # => [(5/2), 0] # Rational.
+ *
+ * # Some things are ignored.
+ * 'foo1'.to_c.rect # => [0, 0] # Unparsed entire substring.
+ * '1foo'.to_c.rect # => [1, 0] # Unparsed trailing substring.
+ * ' 1 '.to_c.rect # => [1, 0] # Leading and trailing whitespace.
+ * *
+ * # Imaginary only: trailing 'i' required; real part is zero.
+ * '9i'.to_c.rect # => [0, 9]
+ * '-9i'.to_c.rect # => [0, -9]
+ * '2.5i'.to_c.rect # => [0, 2.5]
+ * '1.23e-14i'.to_c.rect # => [0, 1.23e-14]
+ * '2.5/1i'.to_c.rect # => [0, (5/2)]
+ *
+ * # Real and imaginary; '+' or '-' separator; trailing 'i' required.
+ * '2+3i'.to_c.rect # => [2, 3]
+ * '-2-3i'.to_c.rect # => [-2, -3]
+ * '2.5+3i'.to_c.rect # => [2.5, 3]
+ * '2.5+3/2i'.to_c.rect # => [2.5, (3/2)]
+ *
+ * # Polar coordinates; '@' separator; magnitude required.
+ * '1.0@0'.to_c.polar # => [1.0, 0.0]
+ * '1.0@'.to_c.polar # => [1.0, 0.0]
+ * "1.0@#{Math::PI}".to_c.polar # => [1.0, 3.141592653589793]
+ * "1.0@#{Math::PI/2}".to_c.polar # => [1.0, 1.5707963267948966]
+ *
+ * <b>Parsed Values</b>
+ *
+ * The parsing may be thought of as searching for numeric literals
+ * embedded in the substring.
+ *
+ * This section shows how the method parses numeric values from leading substrings.
+ * The examples show real-only or imaginary-only parsing;
+ * the parsing is the same for each part.
+ *
+ * '1foo'.to_c # => (1+0i) # Ignores trailing unparsed characters.
+ * ' 1 '.to_c # => (1+0i) # Ignores leading and trailing whitespace.
+ * 'x1'.to_c # => (0+0i) # Finds no leading numeric.
+ *
+ * # Integer literal embedded in the substring.
+ * '1'.to_c # => (1+0i)
+ * '-1'.to_c # => (-1+0i)
+ * '1i'.to_c # => (0+1i)
+ *
+ * # Integer literals that don't work.
+ * '0b100'.to_c # => (0+0i) # Not parsed as binary.
+ * '0o100'.to_c # => (0+0i) # Not parsed as octal.
+ * '0d100'.to_c # => (0+0i) # Not parsed as decimal.
+ * '0x100'.to_c # => (0+0i) # Not parsed as hexadecimal.
+ * '010'.to_c # => (10+0i) # Not parsed as octal.
+ *
+ * # Float literals:
+ * '3.14'.to_c # => (3.14+0i)
+ * '3.14i'.to_c # => (0+3.14i)
+ * '1.23e4'.to_c # => (12300.0+0i)
+ * '1.23e+4'.to_c # => (12300.0+0i)
+ * '1.23e-4'.to_c # => (0.000123+0i)
+ *
+ * # Rational literals:
+ * '1/2'.to_c # => ((1/2)+0i)
+ * '-1/2'.to_c # => ((-1/2)+0i)
+ * '1/2r'.to_c # => ((1/2)+0i)
+ * '-1/2r'.to_c # => ((-1/2)+0i)
+ *
+ * <b>Rectangular Coordinates</b>
+ *
+ * With separator <tt>'+'</tt> or <tt>'-'</tt>,
+ * or with no separator,
+ * interprets the values as rectangular coordinates: real and imaginary.
+ *
+ * With no separator, assigns a single value to either the real or the imaginary part:
+ *
+ * ''.to_c # => (0+0i) # Defaults to zero.
+ * '1'.to_c # => (1+0i) # Real (no trailing 'i').
+ * '1i'.to_c # => (0+1i) # Imaginary (trailing 'i').
+ * 'i'.to_c # => (0+1i) # Special case (imaginary 1).
+ *
+ * With separator <tt>'+'</tt>, both parts positive (or zero):
+ *
+ * # Without trailing 'i'.
+ * '+'.to_c # => (0+0i) # No values: defaults to zero.
+ * '+1'.to_c # => (1+0i) # Value after '+': real only.
+ * '1+'.to_c # => (1+0i) # Value before '+': real only.
+ * '2+1'.to_c # => (2+0i) # Values before and after '+': real and imaginary.
+ * # With trailing 'i'.
+ * '+1i'.to_c # => (0+1i) # Value after '+': imaginary only.
+ * '2+i'.to_c # => (2+1i) # Value before '+': real and imaginary 1.
+ * '2+1i'.to_c # => (2+1i) # Values before and after '+': real and imaginary.
+ *
+ * With separator <tt>'-'</tt>, negative imaginary part:
+ *
+ * # Without trailing 'i'.
+ * '-'.to_c # => (0+0i) # No values: defaults to zero.
+ * '-1'.to_c # => (-1+0i) # Value after '-': negative real, zero imaginary.
+ * '1-'.to_c # => (1+0i) # Value before '-': positive real, zero imaginary.
+ * '2-1'.to_c # => (2+0i) # Values before and after '-': positive real, zero imaginary.
+ * # With trailing 'i'.
+ * '-1i'.to_c # => (0-1i) # Value after '-': negative real, zero imaginary.
+ * '2-i'.to_c # => (2-1i) # Value before '-': positive real, negative imaginary.
+ * '2-1i'.to_c # => (2-1i) # Values before and after '-': positive real, negative imaginary.
+ *
+ * Note that the suffixed character <tt>'i'</tt>
+ * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, or <tt>'J'</tt>,
+ * with the same effect.
+ *
+ * <b>Polar Coordinates</b>
+ *
+ * With separator <tt>'@'</tt>)
+ * interprets the values as polar coordinates: magnitude and angle.
+ *
+ * '2@'.to_c.polar # => [2, 0.0] # Value before '@': magnitude only.
+ * # Values before and after '@': magnitude and angle.
+ * '2@1'.to_c.polar # => [2.0, 1.0]
* "1.0@#{Math::PI/2}".to_c # => (0.0+1i)
* "1.0@#{Math::PI}".to_c # => (-1+0.0i)
+ * # Magnitude not given: defaults to zero.
+ * '@'.to_c.polar # => [0, 0.0]
+ * '@1'.to_c.polar # => [0, 0.0]
*
- * Returns \Complex zero if the string cannot be converted:
+ * '1.0@0'.to_c # => (1+0.0i)
*
- * 'ruby'.to_c # => (0+0i)
+ * Note that in all cases, the suffixed character <tt>'i'</tt>
+ * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, <tt>'J'</tt>,
+ * with the same effect.
*
- * See Kernel#Complex.
+ * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
*/
static VALUE
string_to_c(VALUE self)
@@ -2289,7 +2386,7 @@ nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
{
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Complex");
+ rb_cant_convert(Qnil, "Complex");
}
if (RB_TYPE_P(a1, T_STRING)) {
@@ -2523,9 +2620,9 @@ float_arg(VALUE self)
* First, what's elsewhere:
*
* - Class \Complex inherits (directly or indirectly)
- * from classes {Numeric}[rdoc-ref:Numeric@What-27s+Here]
- * and {Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * from classes {Numeric}[rdoc-ref:Numeric@Whats-Here]
+ * and {Object}[rdoc-ref:Object@Whats-Here].
+ * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@Whats-Here].
*
* Here, class \Complex has methods for:
*
@@ -2692,7 +2789,6 @@ Init_Complex(void)
rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
- rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
rb_define_method(rb_cString, "to_c", string_to_c, 0);
diff --git a/concurrent_set.c b/concurrent_set.c
new file mode 100644
index 0000000000..42a5bfe8da
--- /dev/null
+++ b/concurrent_set.c
@@ -0,0 +1,518 @@
+#include "internal.h"
+#include "internal/gc.h"
+#include "internal/concurrent_set.h"
+#include "ruby/atomic.h"
+#include "vm_sync.h"
+
+#define CONCURRENT_SET_CONTINUATION_BIT ((VALUE)1 << (sizeof(VALUE) * CHAR_BIT - 1))
+#define CONCURRENT_SET_HASH_MASK (~CONCURRENT_SET_CONTINUATION_BIT)
+
+enum concurrent_set_special_values {
+ CONCURRENT_SET_EMPTY,
+ CONCURRENT_SET_DELETED,
+ CONCURRENT_SET_MOVED,
+ CONCURRENT_SET_SPECIAL_VALUE_COUNT
+};
+
+struct concurrent_set_entry {
+ VALUE hash;
+ VALUE key;
+};
+
+struct concurrent_set {
+ rb_atomic_t size;
+ unsigned int capacity;
+ unsigned int deleted_entries;
+ const struct rb_concurrent_set_funcs *funcs;
+ struct concurrent_set_entry *entries;
+};
+
+static void
+concurrent_set_mark_continuation(struct concurrent_set_entry *entry, VALUE curr_hash_and_flags)
+{
+ if (curr_hash_and_flags & CONCURRENT_SET_CONTINUATION_BIT) return;
+
+ RUBY_ASSERT((curr_hash_and_flags & CONCURRENT_SET_HASH_MASK) != 0);
+
+ VALUE new_hash = curr_hash_and_flags | CONCURRENT_SET_CONTINUATION_BIT;
+ VALUE prev_hash = rbimpl_atomic_value_cas(&entry->hash, curr_hash_and_flags, new_hash, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+
+ // At the moment we only expect to be racing concurrently against another
+ // thread also setting the continuation bit.
+ // In the future if deletion is concurrent this will need adjusting
+ RUBY_ASSERT(prev_hash == curr_hash_and_flags || prev_hash == new_hash);
+ (void)prev_hash;
+}
+
+static VALUE
+concurrent_set_hash(const struct concurrent_set *set, VALUE key)
+{
+ VALUE hash = set->funcs->hash(key);
+ hash &= CONCURRENT_SET_HASH_MASK;
+ if (hash == 0) {
+ hash ^= CONCURRENT_SET_HASH_MASK;
+ }
+ RUBY_ASSERT(hash != 0);
+ RUBY_ASSERT(!(hash & CONCURRENT_SET_CONTINUATION_BIT));
+ return hash;
+}
+
+static void
+concurrent_set_free(void *ptr)
+{
+ struct concurrent_set *set = ptr;
+ SIZED_FREE_N(set->entries, set->capacity);
+}
+
+static size_t
+concurrent_set_size(const void *ptr)
+{
+ const struct concurrent_set *set = ptr;
+ return sizeof(struct concurrent_set) +
+ (set->capacity * sizeof(struct concurrent_set_entry));
+}
+
+/* Hack: Though it would be trivial, we're intentionally avoiding WB-protecting
+ * this object. This prevents the object from aging and ensures it can always be
+ * collected in a minor GC.
+ * Longer term this deserves a better way to reclaim memory promptly.
+ */
+static void
+concurrent_set_mark(void *ptr)
+{
+ (void)ptr;
+}
+
+static const rb_data_type_t concurrent_set_type = {
+ .wrap_struct_name = "VM/concurrent_set",
+ .function = {
+ .dmark = concurrent_set_mark,
+ .dfree = concurrent_set_free,
+ .dsize = concurrent_set_size,
+ },
+ /* Hack: NOT WB_PROTECTED on purpose (see above) */
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+};
+
+VALUE
+rb_concurrent_set_new(const struct rb_concurrent_set_funcs *funcs, int capacity)
+{
+ struct concurrent_set *set;
+ VALUE obj = TypedData_Make_Struct(0, struct concurrent_set, &concurrent_set_type, set);
+ set->funcs = funcs;
+ set->entries = ZALLOC_N(struct concurrent_set_entry, capacity);
+ set->capacity = capacity;
+ return obj;
+}
+
+rb_atomic_t
+rb_concurrent_set_size(VALUE set_obj)
+{
+ struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
+
+ return RUBY_ATOMIC_LOAD(set->size);
+}
+
+struct concurrent_set_probe {
+ int idx;
+ int d;
+ int mask;
+};
+
+static int
+concurrent_set_probe_start(struct concurrent_set_probe *probe, struct concurrent_set *set, VALUE hash)
+{
+ RUBY_ASSERT((set->capacity & (set->capacity - 1)) == 0);
+ probe->d = 0;
+ probe->mask = set->capacity - 1;
+ probe->idx = hash & probe->mask;
+ return probe->idx;
+}
+
+static int
+concurrent_set_probe_next(struct concurrent_set_probe *probe)
+{
+ probe->d++;
+ probe->idx = (probe->idx + probe->d) & probe->mask;
+ return probe->idx;
+}
+
+static void
+concurrent_set_try_resize_without_locking(VALUE old_set_obj, VALUE *set_obj_ptr)
+{
+ // Check if another thread has already resized.
+ if (rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE) != old_set_obj) {
+ return;
+ }
+
+ struct concurrent_set *old_set = RTYPEDDATA_GET_DATA(old_set_obj);
+
+ // This may overcount by up to the number of threads concurrently attempting to insert
+ // GC may also happen between now and the set being rebuilt
+ int expected_size = rbimpl_atomic_load(&old_set->size, RBIMPL_ATOMIC_RELAXED) - old_set->deleted_entries;
+
+ // NOTE: new capacity must make sense with load factor, don't change one without checking the other.
+ struct concurrent_set_entry *old_entries = old_set->entries;
+ int old_capacity = old_set->capacity;
+ int new_capacity = old_capacity * 2;
+ if (new_capacity > expected_size * 8) {
+ new_capacity = old_capacity / 2;
+ }
+ else if (new_capacity > expected_size * 4) {
+ new_capacity = old_capacity;
+ }
+
+ // May cause GC and therefore deletes, so must happen first.
+ VALUE new_set_obj = rb_concurrent_set_new(old_set->funcs, new_capacity);
+ struct concurrent_set *new_set = RTYPEDDATA_GET_DATA(new_set_obj);
+
+ for (int i = 0; i < old_capacity; i++) {
+ struct concurrent_set_entry *old_entry = &old_entries[i];
+ VALUE key = rbimpl_atomic_value_exchange(&old_entry->key, CONCURRENT_SET_MOVED, RBIMPL_ATOMIC_ACQUIRE);
+ RUBY_ASSERT(key != CONCURRENT_SET_MOVED);
+
+ if (key < CONCURRENT_SET_SPECIAL_VALUE_COUNT) continue;
+ if (!RB_SPECIAL_CONST_P(key) && rb_objspace_garbage_object_p(key)) continue;
+
+ VALUE hash = rbimpl_atomic_value_load(&old_entry->hash, RBIMPL_ATOMIC_RELAXED) & CONCURRENT_SET_HASH_MASK;
+ RUBY_ASSERT(hash != 0);
+ RUBY_ASSERT(hash == concurrent_set_hash(old_set, key));
+
+ // Insert key into new_set.
+ struct concurrent_set_probe probe;
+ int idx = concurrent_set_probe_start(&probe, new_set, hash);
+
+ while (true) {
+ struct concurrent_set_entry *entry = &new_set->entries[idx];
+
+ if (entry->hash == CONCURRENT_SET_EMPTY) {
+ RUBY_ASSERT(entry->key == CONCURRENT_SET_EMPTY);
+
+ new_set->size++;
+ RUBY_ASSERT(new_set->size <= new_set->capacity / 2);
+
+ entry->key = key;
+ entry->hash = hash;
+ break;
+ }
+
+ RUBY_ASSERT(entry->key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
+ entry->hash |= CONCURRENT_SET_CONTINUATION_BIT;
+ idx = concurrent_set_probe_next(&probe);
+ }
+ }
+
+ rbimpl_atomic_value_store(set_obj_ptr, new_set_obj, RBIMPL_ATOMIC_RELEASE);
+
+ RB_GC_GUARD(old_set_obj);
+}
+
+static void
+concurrent_set_try_resize(VALUE old_set_obj, VALUE *set_obj_ptr)
+{
+ RB_VM_LOCKING() {
+ concurrent_set_try_resize_without_locking(old_set_obj, set_obj_ptr);
+ }
+}
+
+VALUE
+rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
+{
+ RUBY_ASSERT(key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
+
+ VALUE set_obj;
+ VALUE hash = 0;
+ struct concurrent_set *set;
+ struct concurrent_set_probe probe;
+ int idx;
+
+ retry:
+ set_obj = rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE);
+ RUBY_ASSERT(set_obj);
+ set = RTYPEDDATA_GET_DATA(set_obj);
+
+ if (hash == 0) {
+ // We don't need to recompute the hash on every retry because it should
+ // never change.
+ hash = concurrent_set_hash(set, key);
+ }
+ RUBY_ASSERT(hash == concurrent_set_hash(set, key));
+
+ idx = concurrent_set_probe_start(&probe, set, hash);
+
+ while (true) {
+ struct concurrent_set_entry *entry = &set->entries[idx];
+ VALUE curr_hash_and_flags = rbimpl_atomic_value_load(&entry->hash, RBIMPL_ATOMIC_ACQUIRE);
+ VALUE curr_hash = curr_hash_and_flags & CONCURRENT_SET_HASH_MASK;
+ bool continuation = curr_hash_and_flags & CONCURRENT_SET_CONTINUATION_BIT;
+
+ if (curr_hash_and_flags == CONCURRENT_SET_EMPTY) {
+ return 0;
+ }
+
+ if (curr_hash != hash) {
+ if (!continuation) {
+ return 0;
+ }
+ idx = concurrent_set_probe_next(&probe);
+ continue;
+ }
+
+ VALUE curr_key = rbimpl_atomic_value_load(&entry->key, RBIMPL_ATOMIC_ACQUIRE);
+
+ switch (curr_key) {
+ case CONCURRENT_SET_EMPTY:
+ // In-progress insert: hash written but key not yet
+ break;
+ case CONCURRENT_SET_DELETED:
+ break;
+ case CONCURRENT_SET_MOVED:
+ // Wait
+ RB_VM_LOCKING();
+
+ goto retry;
+ default: {
+ if (UNLIKELY(!RB_SPECIAL_CONST_P(curr_key) && rb_objspace_garbage_object_p(curr_key))) {
+ // This is a weakref set, so after marking but before sweeping is complete we may find a matching garbage object.
+ // Skip it and let the GC pass clean it up
+ break;
+ }
+
+ if (set->funcs->cmp(key, curr_key)) {
+ // We've found a match.
+ RB_GC_GUARD(set_obj);
+ return curr_key;
+ }
+
+ if (!continuation) {
+ return 0;
+ }
+
+ break;
+ }
+ }
+
+ idx = concurrent_set_probe_next(&probe);
+ }
+}
+
+VALUE
+rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
+{
+ RUBY_ASSERT(key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
+
+ // First attempt to find
+ {
+ VALUE result = rb_concurrent_set_find(set_obj_ptr, key);
+ if (result) return result;
+ }
+
+ // First time we need to call create, and store the hash
+ VALUE set_obj = rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE);
+ RUBY_ASSERT(set_obj);
+
+ struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
+ key = set->funcs->create(key, data);
+ VALUE hash = concurrent_set_hash(set, key);
+
+ struct concurrent_set_probe probe;
+ int idx;
+
+ goto start_search;
+
+retry:
+ // On retries we only need to load the hash object
+ set_obj = rbimpl_atomic_value_load(set_obj_ptr, RBIMPL_ATOMIC_ACQUIRE);
+ RUBY_ASSERT(set_obj);
+ set = RTYPEDDATA_GET_DATA(set_obj);
+
+ RUBY_ASSERT(hash == concurrent_set_hash(set, key));
+
+start_search:
+ idx = concurrent_set_probe_start(&probe, set, hash);
+
+ while (true) {
+ struct concurrent_set_entry *entry = &set->entries[idx];
+ VALUE curr_hash_and_flags = rbimpl_atomic_value_load(&entry->hash, RBIMPL_ATOMIC_ACQUIRE);
+ VALUE curr_hash = curr_hash_and_flags & CONCURRENT_SET_HASH_MASK;
+ bool continuation = curr_hash_and_flags & CONCURRENT_SET_CONTINUATION_BIT;
+
+ if (curr_hash_and_flags == CONCURRENT_SET_EMPTY) {
+ // Reserve this slot for our hash value
+ curr_hash_and_flags = rbimpl_atomic_value_cas(&entry->hash, CONCURRENT_SET_EMPTY, hash, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+ if (curr_hash_and_flags != CONCURRENT_SET_EMPTY) {
+ // Lost race, retry same slot to check winner's hash
+ continue;
+ }
+
+ // CAS succeeded, so these are the values stored
+ curr_hash_and_flags = hash;
+ curr_hash = hash;
+
+ // Fall through to try to claim key
+ }
+
+ if (curr_hash != hash) {
+ goto probe_next;
+ }
+
+ VALUE curr_key = rbimpl_atomic_value_load(&entry->key, RBIMPL_ATOMIC_ACQUIRE);
+
+ switch (curr_key) {
+ case CONCURRENT_SET_EMPTY: {
+ rb_atomic_t prev_size = rbimpl_atomic_fetch_add(&set->size, 1, RBIMPL_ATOMIC_RELAXED);
+
+ // Load_factor reached at 75% full. ex: prev_size: 32, capacity: 64, load_factor: 50%.
+ bool load_factor_reached = (uint64_t)(prev_size * 4) >= (uint64_t)(set->capacity * 3);
+
+ if (UNLIKELY(load_factor_reached)) {
+ concurrent_set_try_resize(set_obj, set_obj_ptr);
+ goto retry;
+ }
+
+ VALUE prev_key = rbimpl_atomic_value_cas(&entry->key, CONCURRENT_SET_EMPTY, key, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+ if (prev_key == CONCURRENT_SET_EMPTY) {
+ RUBY_ASSERT(rb_concurrent_set_find(set_obj_ptr, key) == key);
+ RB_GC_GUARD(set_obj);
+ return key;
+ }
+ else {
+ // Entry was not inserted.
+ rbimpl_atomic_sub(&set->size, 1, RBIMPL_ATOMIC_RELAXED);
+
+ // Another thread won the race, try again at the same location.
+ continue;
+ }
+ }
+ case CONCURRENT_SET_DELETED:
+ break;
+ case CONCURRENT_SET_MOVED:
+ // Wait
+ RB_VM_LOCKING();
+ goto retry;
+ default:
+ // We're never GC during our search
+ // If the continuation bit wasn't set at the start of our search,
+ // any concurrent find with the same hash value would also look at
+ // this location and try to swap curr_key
+ if (UNLIKELY(!RB_SPECIAL_CONST_P(curr_key) && rb_objspace_garbage_object_p(curr_key))) {
+ if (continuation) {
+ goto probe_next;
+ }
+ {
+ VALUE prev = rbimpl_atomic_value_cas(&entry->key, curr_key, CONCURRENT_SET_EMPTY, RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_RELAXED);
+ if (prev == curr_key) {
+ rbimpl_atomic_sub(&set->size, 1, RBIMPL_ATOMIC_RELAXED);
+ }
+ }
+ continue;
+ }
+
+ if (set->funcs->cmp(key, curr_key)) {
+ // We've found a live match.
+ RB_GC_GUARD(set_obj);
+
+ // We created key using set->funcs->create, but we didn't end
+ // up inserting it into the set. Free it here to prevent memory
+ // leaks.
+ if (set->funcs->free) set->funcs->free(key);
+
+ return curr_key;
+ }
+ break;
+ }
+
+ probe_next:
+ RUBY_ASSERT(curr_hash_and_flags != CONCURRENT_SET_EMPTY);
+ concurrent_set_mark_continuation(entry, curr_hash_and_flags);
+ idx = concurrent_set_probe_next(&probe);
+ }
+}
+
+static void
+concurrent_set_delete_entry_locked(struct concurrent_set *set, struct concurrent_set_entry *entry)
+{
+ ASSERT_vm_locking_with_barrier();
+
+ if (entry->hash & CONCURRENT_SET_CONTINUATION_BIT) {
+ entry->hash = CONCURRENT_SET_CONTINUATION_BIT;
+ entry->key = CONCURRENT_SET_DELETED;
+ set->deleted_entries++;
+ }
+ else {
+ entry->hash = CONCURRENT_SET_EMPTY;
+ entry->key = CONCURRENT_SET_EMPTY;
+ set->size--;
+ }
+}
+
+VALUE
+rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key)
+{
+ ASSERT_vm_locking_with_barrier();
+
+ struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
+
+ VALUE hash = concurrent_set_hash(set, key);
+
+ struct concurrent_set_probe probe;
+ int idx = concurrent_set_probe_start(&probe, set, hash);
+
+ while (true) {
+ struct concurrent_set_entry *entry = &set->entries[idx];
+ VALUE curr_key = entry->key;
+
+ switch (curr_key) {
+ case CONCURRENT_SET_EMPTY:
+ // We didn't find our entry to delete.
+ return 0;
+ case CONCURRENT_SET_DELETED:
+ break;
+ case CONCURRENT_SET_MOVED:
+ rb_bug("rb_concurrent_set_delete_by_identity: moved entry");
+ break;
+ default:
+ if (key == curr_key) {
+ RUBY_ASSERT((entry->hash & CONCURRENT_SET_HASH_MASK) == hash);
+ concurrent_set_delete_entry_locked(set, entry);
+ return curr_key;
+ }
+ break;
+ }
+
+ idx = concurrent_set_probe_next(&probe);
+ }
+}
+
+void
+rb_concurrent_set_foreach_with_replace(VALUE set_obj, int (*callback)(VALUE *key, void *data), void *data)
+{
+ ASSERT_vm_locking_with_barrier();
+
+ struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
+
+ for (unsigned int i = 0; i < set->capacity; i++) {
+ struct concurrent_set_entry *entry = &set->entries[i];
+ VALUE key = entry->key;
+
+ switch (key) {
+ case CONCURRENT_SET_EMPTY:
+ case CONCURRENT_SET_DELETED:
+ continue;
+ case CONCURRENT_SET_MOVED:
+ rb_bug("rb_concurrent_set_foreach_with_replace: moved entry");
+ break;
+ default: {
+ int ret = callback(&entry->key, data);
+ switch (ret) {
+ case ST_STOP:
+ return;
+ case ST_DELETE:
+ concurrent_set_delete_entry_locked(set, entry);
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/configure.ac b/configure.ac
index 88b7d2ae85..2de91209d6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,6 +69,7 @@ dnl 93(bright yellow) is copied from .github/workflows/mingw.yml
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
+AC_ARG_VAR([rustc_flags], [additional RUSTC_FLAGS])dnl
[begin]_group "environment section" && {
HAVE_BASERUBY=yes
@@ -82,9 +83,17 @@ AC_ARG_WITH(baseruby,
],
[
AC_PATH_PROG([BASERUBY], [ruby], [false])
+ HAVE_BASERUBY=
])
-AS_IF([test "$HAVE_BASERUBY" != no], [
- RUBYOPT=- $BASERUBY --disable=gems -rerb -rfileutils -rtempfile "${tooldir}/missing-baseruby.bat" || HAVE_BASERUBY=no
+AS_IF([test "$HAVE_BASERUBY" = no], [
+ # --without-baseruby
+], [error=`RUBYOPT=- $BASERUBY --disable=gems "${tooldir}/missing-baseruby.bat" --verbose 2>&1`], [
+ HAVE_BASERUBY=yes
+], [test "$HAVE_BASERUBY" = ""], [ # no --with-baseruby option
+ AC_MSG_WARN($error) # just warn and continue
+ HAVE_BASERUBY=no
+], [ # the ruby given by --with-baseruby is too old
+ AC_MSG_ERROR($error) # bail out
])
AS_IF([test "${HAVE_BASERUBY:=no}" != no], [
AS_CASE(["$build_os"], [mingw*], [
@@ -101,16 +110,44 @@ AS_IF([test "$HAVE_BASERUBY" = no], [
])
AC_SUBST(BASERUBY)
AC_SUBST(HAVE_BASERUBY)
+AS_IF([test "$cross_compiling" = yes],
+ [X_BUILD_EXEEXT=`$BASERUBY -rrbconfig -e ['puts RbConfig::CONFIG["EXEEXT"]']`],
+ [X_BUILD_EXEEXT='$(EXEEXT)']
+)
+AC_SUBST(X_BUILD_EXEEXT)
+
+AC_ARG_WITH(dump-ast,
+ AS_HELP_STRING([--with-dump-ast=DUMP_AST], [use DUMP_AST as dump_ast; for cross-compiling with a host-built dump_ast]),
+ [DUMP_AST=$withval DUMP_AST_TARGET='$(empty)'],
+ [AS_IF([test "$cross_compiling" = yes], [
+ DUMP_AST='build-tool/dump_ast$(BUILD_EXEEXT)'
+ ], [
+ DUMP_AST='./dump_ast$(BUILD_EXEEXT)'
+ ])
+ DUMP_AST_TARGET='$(DUMP_AST)'])
+dnl Without baseruby, .rbinc files cannot be regenerated, so clear the
+dnl dependency on dump_ast to avoid rebuilding pre-generated .rbinc files.
+AS_IF([test "$HAVE_BASERUBY" = no], [DUMP_AST_TARGET='$(empty)'])
+AC_SUBST(X_DUMP_AST, "${DUMP_AST}")
+AC_SUBST(X_DUMP_AST_TARGET, "${DUMP_AST_TARGET}")
: ${GIT=git}
HAVE_GIT=yes
AC_ARG_WITH(git,
AS_HELP_STRING([--without-git], [never use git]),
[AS_CASE([$withval],
- [no], [GIT=never-use HAVE_GIT=no],
+ [no], [HAVE_GIT=no],
[yes], [],
[GIT=$withval])])
-AS_IF([test x"$HAVE_GIT" = xyes], [command -v "$GIT" > /dev/null || HAVE_GIT=no])
+{
+ test x"$HAVE_GIT" = xyes &&
+ command -v "$GIT" > /dev/null &&
+ # `git -C`: 1.8.5
+ # `git log --no-show-signature`: 2.10.0
+ AS_CASE([`$GIT -C . --version 2> /dev/null | sed 's/.* //'`],
+ [0.*|1.*|2.@<:@0-9@:>@.*], [false],
+ [true])
+} || HAVE_GIT=no GIT=never-use
AC_SUBST(GIT)
AC_SUBST(HAVE_GIT)
@@ -251,6 +288,11 @@ AS_CASE(["/${rb_CC} "],
RUBY_CHECK_PROG_FOR_CC([OBJDUMP], [clang], [${llvm_prefix}objdump])
RUBY_CHECK_PROG_FOR_CC([RANLIB], [clang], [${llvm_prefix}ranlib])
RUBY_CHECK_PROG_FOR_CC([STRIP], [clang], [${llvm_prefix}strip])
+
+ # These -Wno-* flags silence clang-specific diagnostics that don't exist
+ # in GCC. GCC silently accepts unknown -Wno-* flags but later emits noisy
+ # "unrecognized command-line option" notes whenever another warning fires.
+ clang_warnflags="-Wno-constant-logical-operand -Wno-parentheses-equality -Wno-self-assign"
])
AS_UNSET(rb_CC)
AS_UNSET(rb_dummy)
@@ -264,6 +306,8 @@ AS_CASE(["${build_os}"],
])
AS_CASE(["${target_os}"],
[cygwin*|msys*|mingw*|darwin*], [
+ ac_ct_OBJCOPY=":"
+ ac_cv_prog_OBJCOPY=":"
ac_cv_prog_ac_ct_OBJCOPY=":"
])
@@ -286,6 +330,8 @@ AC_CHECK_TOOLS([OBJCOPY], [gobjcopy objcopy], [:])
AC_CHECK_TOOLS([OBJDUMP], [gobjdump objdump])
AC_CHECK_TOOLS([STRIP], [gstrip strip], [:])
+FIRSTMAKEFILE=""
+
# 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 2>&1 | grep -q 'llvm-bc'], [NM="$NM --no-llvm-bc"])
@@ -460,6 +506,8 @@ AS_CASE(["$target_os"],
# so wrap clang to insert our fake wasm-opt, which does nothing, in PATH.
CC_WRAPPER=`cd -P "${tooldir}" && pwd`/wasm-clangw
CC="$CC_WRAPPER $CC"
+
+ FIRSTMAKEFILE=GNUmakefile:wasm/GNUmakefile.in
])
cc_version=
@@ -501,6 +549,8 @@ AS_CASE(["$target_os"],
target_cpu=`echo $target_cpu | sed s/i.86/i386/`
AS_CASE(["$target"], [-*], [ target="$target_cpu${target}"])
AS_CASE(["$target_alias"], [-*], [ target_alias="$target_cpu${target_alias}"])
+ # cygwin/GNUmakefile.in is not exclusively for cygwin.
+ FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in
AS_CASE(["$target_os"],
[mingw*], [
test "$rb_cv_msvcrt" = "" && unset rb_cv_msvcrt
@@ -521,7 +571,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>
@@ -603,6 +652,22 @@ AS_IF([test -f conf$$.dir/src/cdcmd], [
rm -fr conf$$.dir
AC_MSG_RESULT([$CHDIR])
AC_SUBST(CHDIR)
+
+AS_CASE(["$FIRSTMAKEFILE"], [*GNUmakefile:*], [gnumake=yes], [
+ AC_MSG_CHECKING([if ${MAKE-make} is GNU make])
+ mkdir conftest.dir
+ echo "all:; @echo yes" > conftest.dir/GNUmakefile
+ echo "all:; @echo no" > conftest.dir/Makefile
+ gnumake=`(cd conftest.dir; ${MAKE-make})`
+ rm -fr conftest.dir
+ AS_CASE(["$gnumake"],
+ [*yes*], [
+ FIRSTMAKEFILE=GNUmakefile:template/GNUmakefile.in
+ gnumake=yes],
+ [
+ gnumake=no])
+ AC_MSG_RESULT($gnumake)
+])
}
[begin]_group "compiler section" && {
@@ -675,7 +740,7 @@ AS_IF([test "$fdeclspec" = yes], [
RUBY_APPEND_OPTIONS(cflags, -fdeclspec)
RUBY_APPEND_OPTIONS(orig_cflags, -fdeclspec)
])
-RUBY_TRY_CXXFLAGS(-fdeclspec, [fdeclspec=yes], [fdeclspec=no])
+RUBY_TRY_CXXFLAGS(-fdeclspec, [fdeclspec=yes], [fdeclspec=no], [@%:@include <cstdio>])
AS_IF([test "$fdeclspec" = yes], [
RUBY_APPEND_OPTIONS(CXXFLAGS, -fdeclspec)
])
@@ -703,6 +768,12 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
AS_CASE([ $CFLAGS ], [*" -save-temps="*|*" -save-temps "*], [], [
extra_warnflags="$extra_warnflags -Werror=misleading-indentation"
])
+ AS_CASE([$target_os], [mingw*], [
+ # 64bit Windows is IL32P64; shorten-64-to-32 causes tons of warnigs
+ extra_warnflags="$extra_warnflags -Wno-shorten-64-to-32"
+ ], [
+ extra_warnflags="$extra_warnflags -Werror=shorten-64-to-32"
+ ])
# ICC doesn't support -Werror=
AS_IF([test $icc_version -gt 0], [
@@ -716,19 +787,15 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
-Werror=implicit-function-declaration \
-Werror=implicit-int \
-Werror=pointer-arith \
- -Werror=shorten-64-to-32 \
-Werror=write-strings \
-Werror=old-style-definition \
-Wimplicit-fallthrough=0 \
-Wmissing-noreturn \
-Wno-cast-function-type \
- -Wno-constant-logical-operand \
-Wno-long-long \
-Wno-missing-field-initializers \
-Wno-overlength-strings \
-Wno-packed-bitfield-compat \
- -Wno-parentheses-equality \
- -Wno-self-assign \
-Wno-tautological-compare \
-Wno-unused-parameter \
-Wno-unused-value \
@@ -736,6 +803,7 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
-Wsuggest-attribute=noreturn \
-Wunused-variable \
-diag-disable=175,188,1684,2259,2312 \
+ $clang_warnflags \
$extra_warnflags \
; do
AS_IF([test "$particular_werror_flags" != yes], [
@@ -1006,7 +1074,7 @@ AS_IF([test "x$OPT_DIR" != x], [
save_IFS="$IFS" IFS="$PATH_SEPARATOR" val= PWD=
for dir in $OPT_DIR; do
test -z "$dir" && continue
- dir=`eval $CHDIR '"$dir"' && pwd` || continue
+ dir=`eval $CHDIR '"$dir"' 2>/dev/null && pwd` || continue
val="${val:+$val$PATH_SEPARATOR}$dir"
done
IFS="$save_IFS" OPT_DIR="$val"
@@ -1228,6 +1296,11 @@ main()
ac_cv_header_sys_time_h=no
ac_cv_header_sys_times_h=no
ac_cv_header_sys_socket_h=no
+ ac_cv_func_chown=yes
+ ac_cv_func_getegid=yes
+ ac_cv_func_geteuid=yes
+ ac_cv_func_getgid=yes
+ ac_cv_func_getuid=yes
ac_cv_func_execv=yes
ac_cv_func_lstat=yes
ac_cv_func_times=yes
@@ -1240,6 +1313,8 @@ main()
ac_cv_func_readlink=yes
ac_cv_func_shutdown=yes
ac_cv_func_symlink=yes
+ ac_cv_func_clock_getres=yes
+ ac_cv_func_clock_gettime=yes
ac_cv_lib_crypt_crypt=no
ac_cv_func_getpgrp_void=no
ac_cv_func_memcmp_working=yes
@@ -1250,16 +1325,14 @@ main()
ac_cv_func_gmtime_r=yes
rb_cv_large_fd_select=yes
ac_cv_type_struct_timeval=yes
- ac_cv_func_clock_gettime=yes
- ac_cv_func_clock_getres=yes
ac_cv_func_malloc_usable_size=no
ac_cv_type_off_t=yes
ac_cv_sizeof_off_t=8
AS_IF([test "$target_cpu" = x64], [
ac_cv_func___builtin_setjmp=yes
ac_cv_func_round=no
+ ac_cv_func_tgamma=no
])
- ac_cv_func_tgamma=no
AC_CHECK_TYPE([NET_LUID], [], [],
[@%:@include <winsock2.h>
@%:@include <windows.h>
@@ -1374,6 +1447,7 @@ AC_CHECK_HEADERS(process.h)
AC_CHECK_HEADERS(pwd.h)
AC_CHECK_HEADERS(sanitizer/asan_interface.h)
AC_CHECK_HEADERS(sanitizer/msan_interface.h)
+AC_CHECK_HEADERS(sanitizer/tsan_interface.h)
AC_CHECK_HEADERS(setjmpex.h)
AC_CHECK_HEADERS(stdalign.h)
AC_CHECK_HEADERS(stdio.h)
@@ -1681,21 +1755,6 @@ AS_IF([test "$rb_cv_func_weak" != x], [
AC_DEFINE(HAVE_FUNC_WEAK)
])
-AC_CACHE_CHECK([for __attribute__((__deprecated__(msg))) in C++],
- rb_cv_CentOS6_CXX_workaround,
- RUBY_WERROR_FLAG([
- AC_LANG_PUSH([C++])
- AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM(
- [],
- [__attribute__((__deprecated__("message"))) int conftest(...);])],
- [rb_cv_CentOS6_CXX_workaround=yes],
- [rb_cv_CentOS6_CXX_workaround=no])
- AC_LANG_POP()]))
-AS_IF([test "$rb_cv_CentOS6_CXX_workaround" != no],[
- AC_DEFINE([RUBY_CXX_DEPRECATED(msg)],
- [__attribute__((__deprecated__(msg)))])])
-
AC_CACHE_CHECK([for std::nullptr_t], rb_cv_CXX_nullptr, [
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE(
@@ -1745,6 +1804,26 @@ AS_IF([test "$GCC" = yes], [
[rb_cv_gcc_atomic_builtins=no])])
AS_IF([test "$rb_cv_gcc_atomic_builtins" = yes], [
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS)
+ for lib in "" atomic; do
+ AS_IF([test "$lib" != ""], [
+ AC_CHECK_LIB([atomic], [__atomic_fetch_add_8])
+ unset rb_cv_gcc_atomic_builtins_64
+ ])
+ AC_CACHE_CHECK([for 64bit __atomic builtins${lib:+ with -l$lib}],
+ [rb_cv_gcc_atomic_builtins_64], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdint.h>
+ uint64_t atomic_var;]],
+ [[
+ __atomic_load_n(&atomic_var, __ATOMIC_RELAXED);
+ __atomic_store_n(&atomic_var, 0, __ATOMIC_RELAXED);
+ ]])],
+ [rb_cv_gcc_atomic_builtins_64=yes],
+ [rb_cv_gcc_atomic_builtins_64=no])])
+ AS_IF([test "$rb_cv_gcc_atomic_builtins_64" = yes], [
+ AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS_64)
+ break
+ ])
+ done
])
AC_CACHE_CHECK([for __sync builtins], [rb_cv_gcc_sync_builtins], [
@@ -1808,10 +1887,6 @@ RUBY_DECL_ATTRIBUTE([__nonnull__(n)], [RUBY_FUNC_NONNULL(n,x)], [rb_cv_func_nonn
RUBY_APPEND_OPTION(XCFLAGS, -DRUBY_EXPORT)
-AC_ARG_ENABLE(mathn,
- AS_HELP_STRING([--enable-mathn], [enable canonicalization for mathn]),
- [AC_MSG_ERROR([mathn support has been dropped])])
-
AC_CACHE_CHECK(for function name string predefined identifier,
rb_cv_function_name_string,
[AS_CASE(["$target_os"],[openbsd*],[
@@ -2439,9 +2514,7 @@ AC_CACHE_CHECK(for negative time_t for gmtime(3), rb_cv_negative_time_t,
#include <time.h>
void
-check(tm, y, m, d, h, s)
- struct tm *tm;
- int y, m, d, h, s;
+check(struct tm *tm, int y, int m, int d, int h, int s)
{
if (!tm ||
tm->tm_year != y ||
@@ -2525,8 +2598,7 @@ AS_IF([test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = ye
#include <signal.h>
void
-sig_handler(dummy)
- int dummy;
+sig_handler(int dummy)
{
}
@@ -3469,7 +3541,7 @@ AS_IF([test x"$cross_compiling" = xyes], [
# darwin target requires miniruby for linking ext bundles
PREP="$PREP"' miniruby$(EXEEXT)'
])
- RUNRUBY_COMMAND='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
+ RUNRUBY_COMMAND='$(MINIRUBY) -I`$(CHDIR) $(srcdir)/lib; pwd`'
RUNRUBY='$(RUNRUBY_COMMAND)'
XRUBY='$(MINIRUBY)'
TEST_RUNNABLE=no
@@ -3495,7 +3567,6 @@ AC_SUBST(RUNRUBY)
AC_SUBST(XRUBY)
AC_SUBST(EXTOUT, [${EXTOUT=.ext}])
-FIRSTMAKEFILE=""
LIBRUBY_A='lib$(RUBY_SO_NAME)-static.a'
LIBRUBY='$(LIBRUBY_A)'
LIBRUBYARG_STATIC='-l$(RUBY_SO_NAME)-static'
@@ -3512,7 +3583,8 @@ AS_CASE(["$target_os"],
AC_ARG_ENABLE(multiarch,
AS_HELP_STRING([--enable-multiarch], [enable multiarch compatible directories]),
- [multiarch=], [unset multiarch])
+ [AS_CASE([$enableval], [no], [unset multiarch], [multiarch=])],
+ [unset multiarch])
AS_IF([test ${multiarch+set}], [
AC_DEFINE(ENABLE_MULTIARCH)
])
@@ -3662,6 +3734,7 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-current_version $(RUBY_PROGRAM_VERSION)'
AS_IF([test "$visibility_option" = ld], [
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,_Init_*'
+ LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,_InitVM_*'
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,_ruby_static_id_*'
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "'-Wl,-unexported_symbol,*_threadptr_*'
])
@@ -3860,39 +3933,39 @@ AC_SUBST(INSTALL_STATIC_LIBRARY)
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)
-YJIT_RUSTC_OK=no
+JIT_RUSTC_OK=no
+JIT_TARGET_ARCH=
AS_IF([test "$RUSTC" != "no"],
AC_MSG_CHECKING([whether ${RUSTC} works for YJIT])
- YJIT_TARGET_ARCH=
AS_CASE(["$target_cpu"],
- [arm64|aarch64], [YJIT_TARGET_ARCH=aarch64],
- [x86_64], [YJIT_TARGET_ARCH=x86_64],
+ [arm64|aarch64], [JIT_TARGET_ARCH=aarch64],
+ [x86_64], [JIT_TARGET_ARCH=x86_64],
)
dnl Fails in case rustc target doesn't match ruby target.
dnl Can happen on Rosetta, for example.
- AS_IF([echo "#[cfg(target_arch = \"$YJIT_TARGET_ARCH\")] fn main() { let x = 1; format!(\"{x}\"); }" |
+ AS_IF([echo "#[cfg(target_arch = \"$JIT_TARGET_ARCH\")] fn main() { let x = 1; format!(\"{x}\"); }" |
$RUSTC - --emit asm=/dev/null 2>/dev/null],
- [YJIT_RUSTC_OK=yes]
+ [JIT_RUSTC_OK=yes]
)
- AC_MSG_RESULT($YJIT_RUSTC_OK)
+ AC_MSG_RESULT($JIT_RUSTC_OK)
)
-dnl check if we can build YJIT on this target platform
+dnl check if we can build YJIT/ZJIT on this target platform
dnl we can't easily cross-compile with rustc so we don't support that
-YJIT_TARGET_OK=no
+JIT_TARGET_OK=no
AS_IF([test "$cross_compiling" = no],
AS_CASE(["$target_cpu-$target_os"],
[*android*], [
- YJIT_TARGET_OK=no
+ JIT_TARGET_OK=no
],
[arm64-darwin*|aarch64-darwin*|x86_64-darwin*], [
- YJIT_TARGET_OK=yes
+ JIT_TARGET_OK=yes
],
[arm64-*linux*|aarch64-*linux*|x86_64-*linux*], [
- YJIT_TARGET_OK=yes
+ JIT_TARGET_OK=yes
],
[arm64-*bsd*|aarch64-*bsd*|x86_64-*bsd*], [
- YJIT_TARGET_OK=yes
+ JIT_TARGET_OK=yes
]
)
)
@@ -3902,7 +3975,7 @@ 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"],
+ [AS_CASE(["$JIT_TARGET_OK:$JIT_RUSTC_OK"],
[yes:yes], [
YJIT_SUPPORT=yes
],
@@ -3910,9 +3983,33 @@ AC_ARG_ENABLE(yjit,
)]
)
-CARGO=
+dnl build ZJIT in release mode if rustc >= 1.85.0 is present and we are on a supported platform
+ZJIT_SUPPORT=no
+AC_ARG_ENABLE(zjit,
+ AS_HELP_STRING([--enable-zjit],
+ [enable experimental JIT compiler that requires Rust build tools. enabled by default on supported platforms if rustc 1.85.0+ is available]),
+ [ZJIT_SUPPORT=$enableval],
+ [AS_CASE(["$JIT_TARGET_OK"],
+ [yes], [
+ rb_zjit_build_possible=no
+ AC_MSG_CHECKING([prerequisites for ZJIT])dnl only checked when --enable-zjit is not specified
+ # Fails in case rustc target doesn't match ruby target. Can happen on Rosetta, for example.
+ # 1.85.0 is the first stable version that supports the 2024 edition.
+ AS_IF([test "$RUSTC" != "no" && echo "#[cfg(target_arch = \"$JIT_TARGET_ARCH\")] fn main() {}" |
+ $RUSTC - --edition=2024 --emit asm=/dev/null 2>/dev/null],
+ AS_IF([test "$gnumake" = "yes"], [
+ rb_zjit_build_possible=yes
+ ])
+ )
+ AC_MSG_RESULT($rb_zjit_build_possible)
+ ZJIT_SUPPORT=$rb_zjit_build_possible
+ ]
+ )]
+)
+
CARGO_BUILD_ARGS=
YJIT_LIBS=
+JIT_CARGO_SUPPORT=no
AS_CASE(["${YJIT_SUPPORT}"],
[yes|dev|stats|dev_nodebug], [
AS_IF([test x"$RUSTC" = "xno"],
@@ -3921,36 +4018,26 @@ AS_CASE(["${YJIT_SUPPORT}"],
AS_CASE(["${YJIT_SUPPORT}"],
[yes], [
- rb_rust_target_subdir=release
],
[dev], [
- rb_rust_target_subdir=debug
- CARGO_BUILD_ARGS='--features disasm,runtime_checks'
+ rb_cargo_features='disasm,runtime_checks'
+ JIT_CARGO_SUPPORT=dev
AC_DEFINE(RUBY_DEBUG, 1)
],
[dev_nodebug], [
- rb_rust_target_subdir=dev_nodebug
- CARGO_BUILD_ARGS='--profile dev_nodebug --features disasm'
+ rb_cargo_features='disasm'
+ JIT_CARGO_SUPPORT=dev_nodebug
AC_DEFINE(YJIT_STATS, 1)
],
[stats], [
- rb_rust_target_subdir=stats
- CARGO_BUILD_ARGS='--profile stats'
+ JIT_CARGO_SUPPORT=stats
AC_DEFINE(YJIT_STATS, 1)
])
- AS_IF([test -n "${CARGO_BUILD_ARGS}"], [
- AC_CHECK_TOOL(CARGO, [cargo], [no])
- AS_IF([test x"$CARGO" = "xno"],
- AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
- ]))
-
- YJIT_LIBS="yjit/target/${rb_rust_target_subdir}/libyjit.a"
- AS_CASE(["$target_os"],[openbsd*],[
- # Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
- LDFLAGS="$LDFLAGS -lpthread -lc++abi"
- ])
+ YJIT_LIBS="target/release/libyjit.a"
+ RUST_LIB='$(YJIT_LIBS)'
YJIT_OBJ='yjit.$(OBJEXT)'
+ JIT_OBJ='jit.$(OBJEXT)'
AS_IF([test x"$YJIT_SUPPORT" != "xyes" ], [
AC_DEFINE_UNQUOTED(YJIT_SUPPORT, [$YJIT_SUPPORT])
])
@@ -3959,13 +4046,118 @@ AS_CASE(["${YJIT_SUPPORT}"],
AC_DEFINE(USE_YJIT, 0)
])
+ZJIT_LIBS=
+AS_CASE(["${ZJIT_SUPPORT}"],
+[yes|dev|dev_nodebug|stats], [
+ AS_IF([test x"$RUSTC" = "xno"],
+ AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
+ )
+
+ AS_CASE(["${ZJIT_SUPPORT}"],
+ [yes], [
+ ],
+ [dev], [
+ rb_cargo_features="$rb_cargo_features,disasm,runtime_checks"
+ JIT_CARGO_SUPPORT=dev
+ AC_DEFINE(RUBY_DEBUG, 1)
+ ],
+ [dev_nodebug], [
+ rb_cargo_features="$rb_cargo_features,disasm"
+ JIT_CARGO_SUPPORT=dev_nodebug
+ AC_DEFINE(ZJIT_STATS, 1)
+ ],
+ [stats], [
+ JIT_CARGO_SUPPORT=stats
+ AC_DEFINE(ZJIT_STATS, 1)
+ ])
+
+ ZJIT_LIBS="target/release/libzjit.a"
+ RUST_LIB='$(ZJIT_LIBS)'
+ ZJIT_OBJ='zjit.$(OBJEXT)'
+ JIT_OBJ='jit.$(OBJEXT)'
+ AS_IF([test x"$ZJIT_SUPPORT" != "xyes" ], [
+ AC_DEFINE_UNQUOTED(ZJIT_SUPPORT, [$ZJIT_SUPPORT])
+ ])
+ AC_DEFINE(USE_ZJIT, 1)
+], [
+ AC_DEFINE(USE_ZJIT, 0)
+])
+
+RUSTC_FLAGS='-g -C lto=thin -C opt-level=3 -C overflow-checks=on'
+AS_IF([test -n "${rustc_flags}"], [
+ RUSTC_FLAGS="${RUSTC_FLAGS} ${rustc_flags}"
+])
+
+JIT_RUST_FLAGS='--crate-type=staticlib --cfg feature=\"stats_allocator\"'
+RLIB_DIR=
+AS_CASE(["$JIT_CARGO_SUPPORT:$YJIT_SUPPORT:$ZJIT_SUPPORT"],
+[no:yes:yes], [ # release build of YJIT+ZJIT
+ YJIT_LIBS=
+ ZJIT_LIBS=
+ JIT_RUST_FLAGS="--crate-type=rlib"
+ RLIB_DIR="target/release"
+ RUST_LIB="target/release/libruby.a"
+],
+[no:*], [],
+[ # JIT_CARGO_SUPPORT not "no" -- cargo required.
+ AC_CHECK_TOOL(CARGO, [cargo], [no])
+ AS_IF([test x"$CARGO" = "xno"],
+ AC_MSG_ERROR([this build configuration requires cargo. Installation instructions available at https://www.rust-lang.org/tools/install]))
+
+ YJIT_LIBS=
+ ZJIT_LIBS=
+
+ # There's more processing below to get the feature set for the
+ # top-level crate, so capture at this point for feature set of
+ # just the zjit crate.
+ ZJIT_TEST_FEATURES="${rb_cargo_features}"
+
+ AS_IF([test x"${YJIT_SUPPORT}" != x"no"], [
+ rb_cargo_features="$rb_cargo_features,yjit"
+ ])
+ AS_IF([test x"${ZJIT_SUPPORT}" != x"no"], [
+ AC_SUBST(ZJIT_TEST_FEATURES)
+ rb_cargo_features="$rb_cargo_features,zjit"
+ ])
+ # if YJIT and ZJIT release mode
+ AS_IF([test "${YJIT_SUPPORT}:${ZJIT_SUPPORT}" = "yes:yes"], [
+ JIT_CARGO_SUPPORT=release
+ ])
+ CARGO_BUILD_ARGS="--profile ${JIT_CARGO_SUPPORT} --features ${rb_cargo_features}"
+ AS_IF([test "${JIT_CARGO_SUPPORT}" = "dev"], [
+ RUST_LIB="target/debug/libruby.a"
+ ], [
+ RUST_LIB="target/${JIT_CARGO_SUPPORT}/libruby.a"
+ ])
+])
+
+# In case either we're linking rust code
+AS_IF([test -n "$RUST_LIB"], [
+ AS_CASE(["$target_os"],[openbsd*],[
+ # Link libc++abi (which requires libpthread) for _Unwind_* functions needed by rust stdlib
+ LDFLAGS="$LDFLAGS -lpthread -lc++abi"
+ ])
+
+ # absolute path to stop the "target" dir in src dir from interfering through VPATH
+ RUST_LIB="$(pwd)/${RUST_LIB}"
+])
+
dnl These variables end up in ::RbConfig::CONFIG
-AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
AC_SUBST(RUSTC)dnl Rust compiler command
+AC_SUBST(JIT_RUST_FLAGS)dnl the common rustc flags for JIT crates such as zjit
+AC_SUBST(RUSTC_FLAGS)dnl user-configurable rustc compiler flags
AC_SUBST(CARGO)dnl Cargo command for Rust builds
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_SUPPORT)dnl what flavor of YJIT the Ruby build includes
+AC_SUBST(YJIT_LIBS)dnl the .a library of YJIT
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
+AC_SUBST(ZJIT_SUPPORT)dnl what flavor of ZJIT the Ruby build includes
+AC_SUBST(ZJIT_LIBS)dnl path to the .a library of ZJIT
+AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of ZJIT
+AC_SUBST(JIT_OBJ)dnl for optionally building C glue code for Rust FFI
+AC_SUBST(RUST_LIB)dnl path to the rust .a library that contains either or both JITs
+AC_SUBST(RLIB_DIR)dnl subpath of build directory for .rlib files
+AC_SUBST(JIT_CARGO_SUPPORT)dnl "no" or the cargo profile of the rust code
}
[begin]_group "build section" && {
@@ -4079,7 +4271,6 @@ enum {
PLATFORM_DIR=win32
])
LIBRUBY_ALIASES=''
- FIRSTMAKEFILE=GNUmakefile:cygwin/GNUmakefile.in
AS_IF([test x"$enable_shared" = xyes], [
LIBRUBY='lib$(RUBY_SO_NAME).dll.a'
], [
@@ -4089,7 +4280,6 @@ enum {
])
],
[wasi*], [
- FIRSTMAKEFILE=GNUmakefile:wasm/GNUmakefile.in
AC_LIBOBJ([wasm/missing])
AC_LIBOBJ([wasm/runtime])
AC_LIBOBJ([wasm/fiber])
@@ -4106,21 +4296,6 @@ AC_ARG_ENABLE(debug-env,
AS_HELP_STRING([--enable-debug-env], [enable RUBY_DEBUG environment variable]),
[AC_SUBST(ENABLE_DEBUG_ENV, yes)])
-AS_CASE(["$FIRSTMAKEFILE"], [*GNUmakefile:*], [gnumake=yes], [
- AC_MSG_CHECKING([if ${MAKE-make} is GNU make])
- mkdir conftest.dir
- echo "all:; @echo yes" > conftest.dir/GNUmakefile
- echo "all:; @echo no" > conftest.dir/Makefile
- gnumake=`(cd conftest.dir; ${MAKE-make})`
- rm -fr conftest.dir
- AS_CASE(["$gnumake"],
- [*yes*], [
- FIRSTMAKEFILE=GNUmakefile:template/GNUmakefile.in
- gnumake=yes],
- [
- gnumake=no])
- AC_MSG_RESULT($gnumake)
-])
AS_IF([test "$gnumake" = yes], [ NULLCMD=: ], [
AC_MSG_CHECKING([for safe null command for ${MAKE-make}])
mkdir conftest.dir
@@ -4188,8 +4363,7 @@ AS_IF([test -n "${LIBS}"], [
MAINFLAGS=`echo " $MAINLIBS " | sed "s|$libspat"'||;s/^ *//;s/ *$//'`
])
LIBRUBYARG_STATIC="${LIBRUBYARG_STATIC} \$(MAINLIBS)"
-CPPFLAGS="$CPPFLAGS "'$(DEFS)'
-test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}'
+CPPFLAGS="$CPPFLAGS "'$(DEFS) ${cppflags}'
AS_IF([test -n "${cflags+set}"], [
cflagspat=`eval echo '"'"${cflags}"'"' | sed 's/[[][|.*]]/\\&/g;s/^ */ /;s/^ *$/ /'`
CFLAGS=`echo " $CFLAGS " | sed "s|$cflagspat"'|${cflags}|;s/^ *//;s/ *$//'`
@@ -4204,6 +4378,24 @@ AS_IF([test "${ARCH_FLAG}"], [
CXXFLAGS=`echo "$CXXFLAGS" | sed "s| *$archflagpat"'||'`
LDFLAGS=`echo "$LDFLAGS" | sed "s| *$archflagpat"'||'`
])
+AS_CASE([" $rb_cv_warnflags "], [*" -Wshorten-64-to-32 "*|*" -Werror=shorten-64-to-32 "*], [
+ voidp_ll=
+ AS_CASE([$ac_cv_sizeof_voidp],
+ [SIZEOF_LONG_LONG], [voidp_ll=true],
+ [@<:@0-9@:>@*], [
+ AS_IF([test $ac_cv_sizeof_voidp -gt $ac_cv_sizeof_long], [voidp_ll=true])
+ ])
+ AS_IF([test "$voidp_ll"], [
+ # Disable the shorten-64-to-32 warning for now, because it currently
+ # generates a lot of warnings on platforms where `sizeof(void*)` is
+ # larger than `sizeof(long)`.
+ #
+ # TODO: Replace `long` with `ptrdiff_t` or something in the all sources.
+ rb_cv_warnflags=`echo "$rb_cv_warnflags" |
+ sed -e 's/ -W\(shorten-64-to-32 \)/ -Wno-\1/' \
+ -e 's/ -Werror=\(shorten-64-to-32 \)/ -Wno-\1/'`
+ ])
+])
rb_cv_warnflags=`echo "$rb_cv_warnflags" | sed 's/^ *//;s/ *$//'`
warnflags="$rb_cv_warnflags"
AC_SUBST(cppflags)dnl
@@ -4246,7 +4438,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/.*://'`
@@ -4510,6 +4701,9 @@ m4_foreach(parser, [available_parsers],
[AC_MSG_ERROR([Unknown parser: $with_parser])]
)
+# Use the ruby allocator for prism. See prism/defines.h
+RUBY_APPEND_OPTIONS(XCFLAGS, -DPRISM_XALLOCATOR)
+
arch_hdrdir="${EXTOUT}/include/${arch}/ruby"
AS_MKDIR_P("${arch_hdrdir}")
config_h="${arch_hdrdir}/config.h"
@@ -4596,8 +4790,12 @@ AC_CONFIG_FILES(Makefile:template/Makefile.in, [
sed '/^MISSING/s/\$U\././g;/^VCS *=/s#@VCS@#'"$VCS"'#;/^VCSUP *=/s#@VCSUP@#'"$VCSUP"'#' Makefile
echo; test x"$EXEEXT" = x || echo 'miniruby: miniruby$(EXEEXT)'
AS_IF([test "$gnumake" != yes], [
- echo ['$(MKFILES): $(srcdir)/common.mk']
- sed ['s/{\$([^(){}]*)[^{}]*}//g'] ${srcdir}/common.mk
+ # extract NMake-style include list
+ set = `sed -n 's/^!include *//p' ${srcdir}/common.mk`
+ echo common_mk_includes "@S|@*" # generate the macro assignment
+ shift
+ common_mk_includes="`echo \"@S|@*\" | sed 's|\$(srcdir)|.|g'`"
+ (PWD= cd ${srcdir} && sed -f tool/prereq.status common.mk ${common_mk_includes})
AS_IF([test "$YJIT_SUPPORT" = yes], [
cat ${srcdir}/yjit/not_gmake.mk
echo ['$(MKFILES): ${srcdir}/yjit/not_gmake.mk']
@@ -4608,20 +4806,7 @@ AC_CONFIG_FILES(Makefile:template/Makefile.in, [
echo; echo '$(srcdir)/$(CONFIGURE):RUBY_M4_INCLUDED \
$(empty)'
- } > $tmpmk && AS_IF([! grep '^ruby:' $tmpmk > /dev/null], [
- AS_IF([test "${gnumake}" = yes], [
- tmpgmk=confgmk$$.tmp
- {
- echo "include $tmpmk"
- echo "-include uncommon.mk"
- } > $tmpgmk
- ], [
- tmpgmk=$tmpmk
- ]) &&
- test -z "`${MAKE-make} -f $tmpgmk info-program | grep '^PROGRAM=ruby$'`" &&
- echo 'ruby: $(PROGRAM);' >> $tmpmk
- test "$tmpmk" = "$tmpgmk" || rm -f "$tmpgmk"
- ]) && mv -f $tmpmk Makefile],
+ } > $tmpmk && mv -f $tmpmk Makefile],
[EXEEXT='$EXEEXT' MAKE='${MAKE-make}' gnumake='$gnumake' GIT='$GIT' YJIT_SUPPORT='$YJIT_SUPPORT'])
AC_ARG_WITH([ruby-pc],
@@ -4636,6 +4821,11 @@ AC_ARG_WITH(destdir,
[DESTDIR="$withval"])
AC_SUBST(DESTDIR)
+AS_IF([test "x$load_relative:$DESTDIR" = xyes:], [
+ AS_IF([test "x$prefix" = xNONE], [DESTDIR="$ac_default_prefix"], [DESTDIR="$prefix"])
+ prefix=/.
+])
+
AC_OUTPUT
}
@@ -4688,6 +4878,8 @@ config_summary "hardenflags" "$hardenflags"
config_summary "strip command" "$STRIP"
config_summary "install doc" "$DOCTARGETS"
config_summary "YJIT support" "$YJIT_SUPPORT"
+config_summary "ZJIT support" "$ZJIT_SUPPORT"
+config_summary "RUSTC_FLAGS" "$RUSTC_FLAGS"
config_summary "man page type" "$MANTYPE"
config_summary "search path" "$search_path"
config_summary "static-linked-ext" ${EXTSTATIC:+"yes"}
diff --git a/cont.c b/cont.c
index 072ae4562f..6bb61e5ee8 100644
--- a/cont.c
+++ b/cont.c
@@ -30,6 +30,7 @@ extern int madvise(caddr_t, size_t, int);
#include "internal/cont.h"
#include "internal/thread.h"
#include "internal/error.h"
+#include "internal/eval.h"
#include "internal/gc.h"
#include "internal/proc.h"
#include "internal/sanitizers.h"
@@ -40,14 +41,20 @@ extern int madvise(caddr_t, size_t, int);
#include "vm_sync.h"
#include "id_table.h"
#include "ractor_core.h"
+#include "zjit.h"
-static const int DEBUG = 0;
+enum {
+ DEBUG = 0,
+ DEBUG_EXPAND = 0,
+ DEBUG_ACQUIRE = 0,
+};
#define RB_PAGE_SIZE (pagesize)
#define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
static long pagesize;
-static const rb_data_type_t cont_data_type, fiber_data_type;
+static const rb_data_type_t rb_cont_data_type;
+static const rb_data_type_t rb_fiber_data_type;
static VALUE rb_cContinuation;
static VALUE rb_cFiber;
static VALUE rb_eFiberError;
@@ -60,11 +67,11 @@ static VALUE rb_cFiberPool;
// Defined in `coroutine/$arch/Context.h`:
#ifdef COROUTINE_LIMITED_ADDRESS_SPACE
#define FIBER_POOL_ALLOCATION_FREE
-#define FIBER_POOL_INITIAL_SIZE 8
-#define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE 32
+#define FIBER_POOL_MINIMUM_COUNT 8
+#define FIBER_POOL_MAXIMUM_ALLOCATIONS 32
#else
-#define FIBER_POOL_INITIAL_SIZE 32
-#define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE 1024
+#define FIBER_POOL_MINIMUM_COUNT 32
+#define FIBER_POOL_MAXIMUM_ALLOCATIONS 1024
#endif
#ifdef RB_EXPERIMENTAL_FIBER_POOL
#define FIBER_POOL_ALLOCATION_FREE
@@ -77,6 +84,7 @@ enum context_type {
struct cont_saved_vm_stack {
VALUE *ptr;
+ size_t size;
#ifdef CAPTURE_JUST_VALID_VM_STACK
size_t slen; /* length of stack (head of ec->vm_stack) */
size_t clen; /* length of control frames (tail of ec->vm_stack) */
@@ -186,7 +194,11 @@ struct fiber_pool {
size_t count;
// The initial number of stacks to allocate.
- size_t initial_count;
+ size_t minimum_count;
+
+ // If positive, total stacks in this pool cannot exceed this (shared pool only:
+ // set via RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT). Expansion fails with errno EAGAIN.
+ size_t maximum_count;
// Whether to madvise(free) the stack or not.
// If this value is set to 1, the stack will be madvise(free)ed
@@ -279,7 +291,7 @@ rb_free_shared_fiber_pool(void)
struct fiber_pool_allocation *allocations = shared_fiber_pool.allocations;
while (allocations) {
struct fiber_pool_allocation *next = allocations->next;
- xfree(allocations);
+ SIZED_FREE(allocations);
allocations = next;
}
}
@@ -467,11 +479,12 @@ fiber_pool_allocate_memory(size_t * count, size_t stride)
// the system would allow (e.g. overcommit * physical memory + swap), we
// divide count by two and try again. This condition should only be
// encountered in edge cases, but we handle it here gracefully.
- while (*count > 1) {
+ while (*count) {
#if defined(_WIN32)
void * base = VirtualAlloc(0, (*count)*stride, MEM_COMMIT, PAGE_READWRITE);
if (!base) {
+ errno = rb_w32_map_errno(GetLastError());
*count = (*count) >> 1;
}
else {
@@ -503,26 +516,53 @@ fiber_pool_allocate_memory(size_t * count, size_t stride)
}
// Given an existing fiber pool, expand it by the specified number of stacks.
+//
// @param count the maximum number of stacks to allocate.
-// @return the allocated fiber pool.
+// @return the new allocation on success, or NULL on failure with errno set.
+// @raise NoMemoryError if the struct or memory allocation fails.
+//
+// Call from fiber_pool_stack_acquire_expand with VM lock held, or from
+// fiber_pool_initialize before the pool is shared across threads.
// @sa fiber_pool_allocation_free
static struct fiber_pool_allocation *
fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
{
+ if (count == 0) {
+ errno = EAGAIN;
+ return NULL;
+ }
+
STACK_GROW_DIR_DETECTION;
size_t size = fiber_pool->size;
size_t stride = size + RB_PAGE_SIZE;
+ // If the maximum number of stacks is set, and we have reached it, return NULL.
+ if (fiber_pool->maximum_count > 0) {
+ if (fiber_pool->count >= fiber_pool->maximum_count) {
+ errno = EAGAIN;
+ return NULL;
+ }
+ size_t remaining = fiber_pool->maximum_count - fiber_pool->count;
+ if (count > remaining) {
+ count = remaining;
+ }
+ }
+
+ // Allocate metadata before mmap: ruby_xmalloc (RB_ALLOC) raises on failure and
+ // must not run after base is mapped, or the region would leak.
+ struct fiber_pool_allocation * allocation = RB_ALLOC(struct fiber_pool_allocation);
+
// Allocate the memory required for the stacks:
void * base = fiber_pool_allocate_memory(&count, stride);
if (base == NULL) {
- rb_raise(rb_eFiberError, "can't alloc machine stack to fiber (%"PRIuSIZE" x %"PRIuSIZE" bytes): %s", count, size, ERRNOMSG);
+ if (!errno) errno = ENOMEM;
+ ruby_xfree(allocation);
+ return NULL;
}
struct fiber_pool_vacancy * vacancies = fiber_pool->vacancies;
- struct fiber_pool_allocation * allocation = RB_ALLOC(struct fiber_pool_allocation);
// Initialize fiber pool allocation:
allocation->base = base;
@@ -534,7 +574,7 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
#endif
allocation->pool = fiber_pool;
- if (DEBUG) {
+ if (DEBUG_EXPAND) {
fprintf(stderr, "fiber_pool_expand(%"PRIuSIZE"): %p, %"PRIuSIZE"/%"PRIuSIZE" x [%"PRIuSIZE":%"PRIuSIZE"]\n",
count, (void*)fiber_pool, fiber_pool->used, fiber_pool->count, size, fiber_pool->vm_stack_size);
}
@@ -543,21 +583,27 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
for (size_t i = 0; i < count; i += 1) {
void * base = (char*)allocation->base + (stride * i);
void * page = (char*)base + STACK_DIR_UPPER(size, 0);
-
#if defined(_WIN32)
DWORD old_protect;
if (!VirtualProtect(page, RB_PAGE_SIZE, PAGE_READWRITE | PAGE_GUARD, &old_protect)) {
+ int error = rb_w32_map_errno(GetLastError());
VirtualFree(allocation->base, 0, MEM_RELEASE);
- rb_raise(rb_eFiberError, "can't set a guard page: %s", ERRNOMSG);
+ ruby_xfree(allocation);
+ errno = error;
+ return NULL;
}
#elif defined(__wasi__)
// wasi-libc's mprotect emulation doesn't support PROT_NONE.
(void)page;
#else
if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
+ int error = errno;
+ if (!error) error = ENOMEM;
munmap(allocation->base, count*stride);
- rb_raise(rb_eFiberError, "can't set a guard page: %s", ERRNOMSG);
+ ruby_xfree(allocation);
+ errno = error;
+ return NULL;
}
#endif
@@ -593,7 +639,7 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
// Initialize the specified fiber pool with the given number of stacks.
// @param vm_stack_size The size of the vm stack to allocate.
static void
-fiber_pool_initialize(struct fiber_pool * fiber_pool, size_t size, size_t count, size_t vm_stack_size)
+fiber_pool_initialize(struct fiber_pool * fiber_pool, size_t size, size_t minimum_count, size_t maximum_count, size_t vm_stack_size)
{
VM_ASSERT(vm_stack_size < size);
@@ -601,13 +647,17 @@ fiber_pool_initialize(struct fiber_pool * fiber_pool, size_t size, size_t count,
fiber_pool->vacancies = NULL;
fiber_pool->size = ((size / RB_PAGE_SIZE) + 1) * RB_PAGE_SIZE;
fiber_pool->count = 0;
- fiber_pool->initial_count = count;
+ fiber_pool->minimum_count = minimum_count;
+ fiber_pool->maximum_count = maximum_count;
fiber_pool->free_stacks = 1;
fiber_pool->used = 0;
-
fiber_pool->vm_stack_size = vm_stack_size;
- fiber_pool_expand(fiber_pool, count);
+ if (fiber_pool->minimum_count > 0) {
+ if (RB_UNLIKELY(!fiber_pool_expand(fiber_pool, fiber_pool->minimum_count))) {
+ rb_raise(rb_eFiberError, "can't allocate initial fiber stacks (%"PRIuSIZE" x %"PRIuSIZE" bytes): %s", fiber_pool->minimum_count, fiber_pool->size, strerror(errno));
+ }
+ }
}
#ifdef FIBER_POOL_ALLOCATION_FREE
@@ -651,49 +701,120 @@ fiber_pool_allocation_free(struct fiber_pool_allocation * allocation)
allocation->pool->count -= allocation->count;
- ruby_xfree(allocation);
+ SIZED_FREE(allocation);
}
#endif
-// Acquire a stack from the given fiber pool. If none are available, allocate more.
-static struct fiber_pool_stack
-fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
+// Number of stacks to request when expanding the pool (clamped to min/max).
+static size_t
+fiber_pool_stack_expand_count(const struct fiber_pool *pool)
{
- struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pop(fiber_pool);
+ const size_t maximum_allocations = FIBER_POOL_MAXIMUM_ALLOCATIONS;
+ const size_t minimum_count = FIBER_POOL_MINIMUM_COUNT;
- if (DEBUG) fprintf(stderr, "fiber_pool_stack_acquire: %p used=%"PRIuSIZE"\n", (void*)fiber_pool->vacancies, fiber_pool->used);
+ // We are going try and double the number of stacks in the pool:
+ size_t count = pool->count;
+ if (count > maximum_allocations) count = maximum_allocations;
+ if (count < minimum_count) count = minimum_count;
- if (!vacancy) {
- const size_t maximum = FIBER_POOL_ALLOCATION_MAXIMUM_SIZE;
- const size_t minimum = fiber_pool->initial_count;
+ // If we have a maximum count, we need to clamp the number of stacks to the maximum:
+ if (pool->maximum_count > 0) {
+ if (pool->count >= pool->maximum_count) {
+ // No expansion is possible:
+ return 0;
+ }
+
+ // Otherwise, compute the number of stacks we can allocate to bring us to the maximum:
+ size_t remaining = pool->maximum_count - pool->count;
+ if (count > remaining) {
+ count = remaining;
+ }
+ }
- size_t count = fiber_pool->count;
- if (count > maximum) count = maximum;
- if (count < minimum) count = minimum;
+ return count;
+}
- fiber_pool_expand(fiber_pool, count);
+// When the vacancy list is empty, grow the pool (and run GC only if mmap fails). Caller holds the VM lock.
+// Returns NULL if expansion failed after GC + retry; errno is set. Otherwise returns a vacancy.
+static struct fiber_pool_vacancy *
+fiber_pool_stack_acquire_expand(struct fiber_pool *fiber_pool)
+{
+ size_t count = fiber_pool_stack_expand_count(fiber_pool);
+
+ if (DEBUG_ACQUIRE) fprintf(stderr, "fiber_pool_stack_acquire: expanding fiber pool by %"PRIuSIZE" stacks\n", count);
+
+ struct fiber_pool_vacancy *vacancy = NULL;
+
+ if (RB_LIKELY(fiber_pool_expand(fiber_pool, count))) {
+ return fiber_pool_vacancy_pop(fiber_pool);
+ }
+ else {
+ if (DEBUG_ACQUIRE) fprintf(stderr, "fiber_pool_stack_acquire: expand failed (%s), collecting garbage\n", strerror(errno));
- // The free list should now contain some stacks:
- VM_ASSERT(fiber_pool->vacancies);
+ rb_gc();
+ // After running GC, the vacancy list may have some stacks:
vacancy = fiber_pool_vacancy_pop(fiber_pool);
+ if (RB_LIKELY(vacancy)) {
+ return vacancy;
+ }
+
+ // Recompute count as gc may have freed up some allocations:
+ count = fiber_pool_stack_expand_count(fiber_pool);
+
+ // Try to expand the fiber pool again:
+ if (RB_LIKELY(fiber_pool_expand(fiber_pool, count))) {
+ return fiber_pool_vacancy_pop(fiber_pool);
+ }
+ else {
+ // Okay, we really failed to acquire a stack. Give up and return NULL with errno set:
+ return NULL;
+ }
}
+}
+
+// Acquire a stack from the given fiber pool. If none are available, allocate more.
+static struct fiber_pool_stack
+fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
+{
+ struct fiber_pool_vacancy * vacancy;
+
+ unsigned int lev;
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ {
+ // Fast path: try to acquire a stack from the vacancy list:
+ vacancy = fiber_pool_vacancy_pop(fiber_pool);
+
+ if (DEBUG) fprintf(stderr, "fiber_pool_stack_acquire: %p used=%"PRIuSIZE"\n", (void*)fiber_pool->vacancies, fiber_pool->used);
- VM_ASSERT(vacancy);
- VM_ASSERT(vacancy->stack.base);
+ // Slow path: If the pool has no vacancies, expand first. Only run GC when expansion fails (e.g. mmap), so we can reclaim stacks from dead fibers before retrying:
+ if (RB_UNLIKELY(!vacancy)) {
+ vacancy = fiber_pool_stack_acquire_expand(fiber_pool);
+
+ // If expansion failed, raise an error:
+ if (RB_UNLIKELY(!vacancy)) {
+ RB_VM_LOCK_LEAVE_LEV(&lev);
+ rb_raise(rb_eFiberError, "can't allocate fiber stack: %s", strerror(errno));
+ }
+ }
+
+ VM_ASSERT(vacancy);
+ VM_ASSERT(vacancy->stack.base);
#if defined(COROUTINE_SANITIZE_ADDRESS)
- __asan_unpoison_memory_region(fiber_pool_stack_poison_base(&vacancy->stack), fiber_pool_stack_poison_size(&vacancy->stack));
+ __asan_unpoison_memory_region(fiber_pool_stack_poison_base(&vacancy->stack), fiber_pool_stack_poison_size(&vacancy->stack));
#endif
- // Take the top item from the free list:
- fiber_pool->used += 1;
+ // Take the top item from the free list:
+ fiber_pool->used += 1;
#ifdef FIBER_POOL_ALLOCATION_FREE
- vacancy->stack.allocation->used += 1;
+ vacancy->stack.allocation->used += 1;
#endif
- fiber_pool_stack_reset(&vacancy->stack);
+ fiber_pool_stack_reset(&vacancy->stack);
+ }
+ RB_VM_LOCK_LEAVE_LEV(&lev);
return vacancy->stack;
}
@@ -910,6 +1031,17 @@ fiber_stack_release(rb_fiber_t * fiber)
rb_ec_clear_vm_stack(ec);
}
+static void
+fiber_stack_release_locked(rb_fiber_t *fiber)
+{
+ if (!ruby_vm_during_cleanup) {
+ // We can't try to acquire the VM lock here because MMTK calls free in its own native thread which has no ec.
+ // This assertion will fail on MMTK but we currently don't have CI for debug releases of MMTK, so we can assert for now.
+ ASSERT_vm_locking_with_barrier();
+ }
+ fiber_stack_release(fiber);
+}
+
static const char *
fiber_status_name(enum fiber_status s)
{
@@ -931,7 +1063,9 @@ fiber_verify(const rb_fiber_t *fiber)
switch (fiber->status) {
case FIBER_RESUMED:
- VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
+ if (fiber->cont.saved_ec.thread_ptr->self == 0) {
+ VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
+ }
break;
case FIBER_SUSPENDED:
VM_ASSERT(fiber->cont.saved_ec.vm_stack != NULL);
@@ -961,7 +1095,7 @@ cont_ptr(VALUE obj)
{
rb_context_t *cont;
- TypedData_Get_Struct(obj, rb_context_t, &cont_data_type, cont);
+ TypedData_Get_Struct(obj, rb_context_t, &rb_cont_data_type, cont);
return cont;
}
@@ -971,7 +1105,7 @@ fiber_ptr(VALUE obj)
{
rb_fiber_t *fiber;
- TypedData_Get_Struct(obj, rb_fiber_t, &fiber_data_type, fiber);
+ TypedData_Get_Struct(obj, rb_fiber_t, &rb_fiber_data_type, fiber);
if (!fiber) rb_raise(rb_eFiberError, "uninitialized fiber");
return fiber;
@@ -1064,21 +1198,26 @@ cont_free(void *ptr)
RUBY_FREE_ENTER("cont");
if (cont->type == CONTINUATION_CONTEXT) {
- ruby_xfree(cont->saved_ec.vm_stack);
- RUBY_FREE_UNLESS_NULL(cont->machine.stack);
+ SIZED_FREE_N(cont->saved_ec.vm_stack, cont->saved_ec.vm_stack_size);
+ SIZED_FREE_N(cont->machine.stack, cont->machine.stack_size);
}
else {
rb_fiber_t *fiber = (rb_fiber_t*)cont;
coroutine_destroy(&fiber->context);
- fiber_stack_release(fiber);
+ fiber_stack_release_locked(fiber);
}
- RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
+ SIZED_FREE_N(cont->saved_vm_stack.ptr, cont->saved_vm_stack.size);
VM_ASSERT(cont->jit_cont != NULL);
jit_cont_free(cont->jit_cont);
/* free rb_cont_t or rb_fiber_t */
- ruby_xfree(ptr);
+ if (cont->type == CONTINUATION_CONTEXT) {
+ SIZED_FREE(cont);
+ }
+ else {
+ SIZED_FREE((rb_fiber_t *)cont);
+ }
RUBY_FREE_LEAVE("cont");
}
@@ -1119,12 +1258,7 @@ rb_fiber_update_self(rb_fiber_t *fiber)
void
rb_fiber_mark_self(const rb_fiber_t *fiber)
{
- if (fiber->cont.self) {
- rb_gc_mark_movable(fiber->cont.self);
- }
- else {
- rb_execution_context_mark(&fiber->cont.saved_ec);
- }
+ rb_gc_mark_movable(fiber->cont.self);
}
static void
@@ -1190,12 +1324,13 @@ fiber_memsize(const void *ptr)
VALUE
rb_obj_is_fiber(VALUE obj)
{
- return RBOOL(rb_typeddata_is_kind_of(obj, &fiber_data_type));
+ return RBOOL(rb_typeddata_is_kind_of(obj, &rb_fiber_data_type));
}
static void
cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
{
+ const size_t old_stack_size = cont->machine.stack_size;
size_t size;
SET_MACHINE_STACK_END(&th->ec->machine.stack_end);
@@ -1210,10 +1345,10 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
}
if (cont->machine.stack) {
- REALLOC_N(cont->machine.stack, VALUE, size);
+ SIZED_REALLOC_N(cont->machine.stack, VALUE, cont->machine.stack_size, old_stack_size);
}
else {
- cont->machine.stack = ALLOC_N(VALUE, size);
+ cont->machine.stack = ALLOC_N(VALUE, cont->machine.stack_size);
}
FLUSH_REGISTER_WINDOWS;
@@ -1221,9 +1356,23 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size);
}
-static const rb_data_type_t cont_data_type = {
+static void
+cont_handle_weak_references(void *ptr)
+{
+ rb_context_t *cont = ptr;
+
+ if (!cont) return;
+
+ if (!rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.obj) ||
+ !rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.fields_obj)) {
+ cont->saved_ec.gen_fields_cache.obj = Qundef;
+ cont->saved_ec.gen_fields_cache.fields_obj = Qundef;
+ }
+}
+
+static const rb_data_type_t rb_cont_data_type = {
"continuation",
- {cont_mark, cont_free, cont_memsize, cont_compact},
+ {cont_mark, cont_free, cont_memsize, cont_compact, cont_handle_weak_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
@@ -1254,7 +1403,7 @@ jit_cont_new(rb_execution_context_t *ec)
// We need to use calloc instead of something like ZALLOC to avoid triggering GC here.
// When this function is called from rb_thread_alloc through rb_threadptr_root_fiber_setup,
// the thread is still being prepared and marking it causes SEGV.
- cont = calloc(1, sizeof(struct rb_jit_cont));
+ cont = ruby_mimcalloc(1, sizeof(struct rb_jit_cont));
if (cont == NULL)
rb_memerror();
cont->ec = ec;
@@ -1293,7 +1442,7 @@ jit_cont_free(struct rb_jit_cont *cont)
}
rb_native_mutex_unlock(&jit_cont_lock);
- free(cont);
+ ruby_mimfree(cont);
}
// Call a given callback against all on-stack ISEQs.
@@ -1307,8 +1456,11 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
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);
+ if (CFP_PC(cfp) && CFP_ISEQ(cfp)) {
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
+ if (iseq && imemo_type((VALUE)iseq) == imemo_iseq) {
+ callback(iseq, data);
+ }
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
}
@@ -1344,7 +1496,7 @@ rb_jit_cont_finish(void)
struct rb_jit_cont *cont, *next;
for (cont = first_jit_cont; cont != NULL; cont = next) {
next = cont->next;
- free(cont); // Don't use xfree because it's allocated by calloc.
+ ruby_mimfree(cont); // Don't use xfree because it's allocated by mimcalloc.
}
rb_native_mutex_destroy(&jit_cont_lock);
}
@@ -1383,7 +1535,8 @@ cont_new(VALUE klass)
rb_thread_t *th = GET_THREAD();
THREAD_MUST_BE_RUNNING(th);
- contval = TypedData_Make_Struct(klass, rb_context_t, &cont_data_type, cont);
+ contval = TypedData_Make_Struct(klass, rb_context_t, &rb_cont_data_type, cont);
+ rb_gc_declare_weak_references(contval);
cont->self = contval;
cont_init(cont, th);
return cont;
@@ -1427,8 +1580,8 @@ show_vm_pcs(const rb_control_frame_t *cfp,
int i=0;
while (cfp != end_of_cfp) {
int pc = 0;
- if (cfp->iseq) {
- pc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded;
+ if (CFP_ISEQ(cfp)) {
+ pc = cfp->pc - ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
}
fprintf(stderr, "%2d pc: %d\n", i++, pc);
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
@@ -1452,6 +1605,7 @@ cont_capture(volatile int *volatile stat)
#ifdef CAPTURE_JUST_VALID_VM_STACK
cont->saved_vm_stack.slen = ec->cfp->sp - ec->vm_stack;
cont->saved_vm_stack.clen = ec->vm_stack + ec->vm_stack_size - (VALUE*)ec->cfp;
+ cont->saved_vm_stack.size = cont->saved_vm_stack.slen + cont->saved_vm_stack.clen;
cont->saved_vm_stack.ptr = ALLOC_N(VALUE, cont->saved_vm_stack.slen + cont->saved_vm_stack.clen);
MEMCPY(cont->saved_vm_stack.ptr,
ec->vm_stack,
@@ -1461,6 +1615,7 @@ cont_capture(volatile int *volatile stat)
VALUE,
cont->saved_vm_stack.clen);
#else
+ cont->saved_vm_stack.size = ec->vm_stack_size;
cont->saved_vm_stack.ptr = ALLOC_N(VALUE, ec->vm_stack_size);
MEMCPY(cont->saved_vm_stack.ptr, ec->vm_stack, VALUE, ec->vm_stack_size);
#endif
@@ -1511,6 +1666,51 @@ cont_restore_thread(rb_context_t *cont)
rb_raise(rb_eRuntimeError, "can't call across trace_func");
}
+#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
+ if (th->ec->tag != sec->tag) {
+ /* find the lowest common ancestor tag of the current EC and the saved EC */
+
+ struct rb_vm_tag *lowest_common_ancestor = NULL;
+ size_t num_tags = 0;
+ size_t num_saved_tags = 0;
+ for (struct rb_vm_tag *tag = th->ec->tag; tag != NULL; tag = tag->prev) {
+ ++num_tags;
+ }
+ for (struct rb_vm_tag *tag = sec->tag; tag != NULL; tag = tag->prev) {
+ ++num_saved_tags;
+ }
+
+ size_t min_tags = num_tags <= num_saved_tags ? num_tags : num_saved_tags;
+
+ struct rb_vm_tag *tag = th->ec->tag;
+ while (num_tags > min_tags) {
+ tag = tag->prev;
+ --num_tags;
+ }
+
+ struct rb_vm_tag *saved_tag = sec->tag;
+ while (num_saved_tags > min_tags) {
+ saved_tag = saved_tag->prev;
+ --num_saved_tags;
+ }
+
+ while (min_tags > 0) {
+ if (tag == saved_tag) {
+ lowest_common_ancestor = tag;
+ break;
+ }
+ tag = tag->prev;
+ saved_tag = saved_tag->prev;
+ --min_tags;
+ }
+
+ /* free all the jump buffers between the current EC's tag and the lowest common ancestor tag */
+ for (struct rb_vm_tag *tag = th->ec->tag; tag != lowest_common_ancestor; tag = tag->prev) {
+ rb_vm_tag_jmpbuf_deinit(&tag->buf);
+ }
+ }
+#endif
+
/* copy vm stack */
#ifdef CAPTURE_JUST_VALID_VM_STACK
MEMCPY(th->ec->vm_stack,
@@ -1917,16 +2117,38 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
*
*/
-static const rb_data_type_t fiber_data_type = {
+static void
+fiber_handle_weak_references(void *ptr)
+{
+ rb_fiber_t *fiber = ptr;
+
+ if (!fiber) return;
+
+ if (!rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.obj) ||
+ !rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.fields_obj)) {
+ fiber->cont.saved_ec.gen_fields_cache.obj = Qundef;
+ fiber->cont.saved_ec.gen_fields_cache.fields_obj = Qundef;
+ }
+}
+
+static const rb_data_type_t rb_fiber_data_type = {
"fiber",
- {fiber_mark, fiber_free, fiber_memsize, fiber_compact,},
+ {fiber_mark, fiber_free, fiber_memsize, fiber_compact, fiber_handle_weak_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
fiber_alloc(VALUE klass)
{
- return TypedData_Wrap_Struct(klass, &fiber_data_type, 0);
+ VALUE obj = TypedData_Wrap_Struct(klass, &rb_fiber_data_type, 0);
+ rb_gc_declare_weak_references(obj);
+ return obj;
+}
+
+static rb_serial_t
+next_ec_serial(rb_ractor_t *cr)
+{
+ return cr->next_ec_serial++;
}
static rb_fiber_t*
@@ -1948,6 +2170,7 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
cont_init(&fiber->cont, th);
fiber->cont.saved_ec.fiber_ptr = fiber;
+ fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
rb_ec_clear_vm_stack(&fiber->cont.saved_ec);
fiber->prev = NULL;
@@ -1961,32 +2184,10 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
return fiber;
}
-static rb_fiber_t *
-root_fiber_alloc(rb_thread_t *th)
-{
- VALUE fiber_value = fiber_alloc(rb_cFiber);
- rb_fiber_t *fiber = th->ec->fiber_ptr;
-
- VM_ASSERT(DATA_PTR(fiber_value) == NULL);
- VM_ASSERT(fiber->cont.type == FIBER_CONTEXT);
- VM_ASSERT(FIBER_RESUMED_P(fiber));
-
- th->root_fiber = fiber;
- DATA_PTR(fiber_value) = fiber;
- fiber->cont.self = fiber_value;
-
- coroutine_initialize_main(&fiber->context);
-
- return fiber;
-}
-
static inline rb_fiber_t*
fiber_current(void)
{
rb_execution_context_t *ec = GET_EC();
- if (ec->fiber_ptr->cont.self == 0) {
- root_fiber_alloc(rb_ec_thread_ptr(ec));
- }
return ec->fiber_ptr;
}
@@ -2119,7 +2320,7 @@ rb_fiber_storage_set(VALUE self, VALUE value)
* Returns the value of the fiber storage variable identified by +key+.
*
* The +key+ must be a symbol, and the value is set by Fiber#[]= or
- * Fiber#store.
+ * Fiber#storage.
*
* See also Fiber::[]=.
*/
@@ -2488,21 +2689,36 @@ rb_fiber_start(rb_fiber_t *fiber)
void
rb_threadptr_root_fiber_setup(rb_thread_t *th)
{
- rb_fiber_t *fiber = ruby_mimcalloc(1, sizeof(rb_fiber_t));
+ rb_fiber_t *fiber = ZALLOC(rb_fiber_t);
if (!fiber) {
rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */
}
+
fiber->cont.type = FIBER_CONTEXT;
fiber->cont.saved_ec.fiber_ptr = fiber;
+ fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
fiber->cont.saved_ec.thread_ptr = th;
fiber->blocking = 1;
fiber->killed = 0;
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
+
+ coroutine_initialize_main(&fiber->context);
+
th->ec = &fiber->cont.saved_ec;
+
cont_init_jit_cont(&fiber->cont);
}
void
+rb_root_fiber_obj_setup(rb_thread_t *th)
+{
+ rb_fiber_t *fiber = th->ec->fiber_ptr;
+ VALUE fiber_value = fiber_alloc(rb_cFiber);
+ DATA_PTR(fiber_value) = fiber;
+ fiber->cont.self = fiber_value;
+}
+
+void
rb_threadptr_root_fiber_release(rb_thread_t *th)
{
if (th->root_fiber) {
@@ -2572,15 +2788,7 @@ rb_fiber_current(void)
static inline void
fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
{
- rb_fiber_t *fiber;
-
- if (th->ec->fiber_ptr != NULL) {
- fiber = th->ec->fiber_ptr;
- }
- else {
- /* create root fiber */
- fiber = root_fiber_alloc(th);
- }
+ rb_fiber_t *fiber = th->ec->fiber_ptr;
if (FIBER_CREATED_P(next_fiber)) {
fiber_prepare_stack(next_fiber);
@@ -2616,7 +2824,9 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
rb_thread_t *th = GET_THREAD();
/* make sure the root_fiber object is available */
- if (th->root_fiber == NULL) root_fiber_alloc(th);
+ if (th->root_fiber == NULL) {
+ th->root_fiber = th->ec->fiber_ptr;
+ }
if (th->ec->fiber_ptr == fiber) {
/* ignore fiber context switch
@@ -2681,8 +2891,10 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
// We cannot free the stack until the pthread is joined:
#ifndef COROUTINE_PTHREAD_CONTEXT
- if (resuming_fiber && FIBER_TERMINATED_P(fiber)) {
- fiber_stack_release(fiber);
+ if (FIBER_TERMINATED_P(fiber)) {
+ RB_VM_LOCKING() {
+ fiber_stack_release(fiber);
+ }
}
#endif
@@ -2822,6 +3034,7 @@ void
rb_fiber_close(rb_fiber_t *fiber)
{
fiber_status_set(fiber, FIBER_TERMINATED);
+ rb_ec_close(&fiber->cont.saved_ec);
}
static void
@@ -3160,37 +3373,46 @@ fiber_raise(rb_fiber_t *fiber, VALUE exception)
}
VALUE
-rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv)
+rb_fiber_raise(VALUE fiber, int argc, VALUE *argv)
{
- VALUE exception = rb_make_exception(argc, argv);
+ VALUE exception = rb_exception_setup(argc, argv);
return fiber_raise(fiber_ptr(fiber), exception);
}
/*
* call-seq:
- * fiber.raise -> obj
- * fiber.raise(string) -> obj
- * fiber.raise(exception [, string [, array]]) -> obj
+ * raise(exception, message = exception.to_s, backtrace = nil, cause: $!)
+ * raise(message = nil, cause: $!)
*
* Raises an exception in the fiber at the point at which the last
- * +Fiber.yield+ was called. If the fiber has not been started or has
+ * +Fiber.yield+ was called.
+ *
+ * f = Fiber.new {
+ * puts "Before the yield"
+ * Fiber.yield 1 # -- exception will be raised here
+ * puts "After the yield"
+ * }
+ *
+ * p f.resume
+ * f.raise "Gotcha"
+ *
+ * Output
+ *
+ * Before the first yield
+ * 1
+ * t.rb:8:in 'Fiber.yield': Gotcha (RuntimeError)
+ * from t.rb:8:in 'block in <main>'
+ *
+ * If the fiber has not been started or has
* already run to completion, raises +FiberError+. If the fiber is
* yielding, it is resumed. If it is transferring, it is transferred into.
* But if it is resuming, raises +FiberError+.
*
- * With no arguments, raises a +RuntimeError+. With a single +String+
- * argument, raises a +RuntimeError+ with the string as a message. Otherwise,
- * the first parameter should be the name of an +Exception+ class (or an
- * object that returns an +Exception+ object when sent an +exception+
- * message). The optional second parameter sets the message associated with
- * 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+.
*
- * See Kernel#raise for more information.
+ * See Kernel#raise for more information on arguments.
+ *
*/
static VALUE
rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
@@ -3285,6 +3507,8 @@ rb_fiber_atfork(rb_thread_t *th)
th->root_fiber = th->ec->fiber_ptr;
}
th->root_fiber->prev = 0;
+ th->root_fiber->blocking = 1;
+ th->blocking = 1;
}
}
#endif
@@ -3297,7 +3521,7 @@ fiber_pool_free(void *ptr)
RUBY_FREE_ENTER("fiber_pool");
fiber_pool_allocation_free(fiber_pool->allocations);
- ruby_xfree(fiber_pool);
+ SIZED_FREE(fiber_pool);
RUBY_FREE_LEAVE("fiber_pool");
}
@@ -3351,7 +3575,7 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self)
TypedData_Get_Struct(self, struct fiber_pool, &FiberPoolDataType, fiber_pool);
- fiber_pool_initialize(fiber_pool, NUM2SIZET(size), NUM2SIZET(count), NUM2SIZET(vm_stack_size));
+ fiber_pool_initialize(fiber_pool, NUM2SIZET(size), NUM2SIZET(count), 0, NUM2SIZET(vm_stack_size));
return self;
}
@@ -3370,6 +3594,46 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self)
* fiber.resume #=> FiberError: dead fiber called
*/
+static size_t
+shared_fiber_pool_minimum_count(void)
+{
+ size_t minimum_count = FIBER_POOL_MINIMUM_COUNT;
+
+ const char *minimum_count_env = getenv("RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT");
+ if (minimum_count_env && minimum_count_env[0]) {
+ char *end;
+ unsigned long value = strtoul(minimum_count_env, &end, 10);
+ if (end != minimum_count_env && *end == '\0') {
+ minimum_count = (size_t)value;
+ }
+ else {
+ rb_warn("invalid RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT=%s (expected a non-negative integer)", minimum_count_env);
+ }
+ }
+
+ return minimum_count;
+}
+
+static size_t
+shared_fiber_pool_maximum_count(void)
+{
+ size_t maximum_count = 0;
+
+ const char *maximum_count_env = getenv("RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT");
+ if (maximum_count_env && maximum_count_env[0]) {
+ char *end;
+ unsigned long value = strtoul(maximum_count_env, &end, 10);
+ if (end != maximum_count_env && *end == '\0') {
+ maximum_count = (size_t)value;
+ }
+ else {
+ rb_warn("invalid RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT=%s (expected a non-negative integer)", maximum_count_env);
+ }
+ }
+
+ return maximum_count;
+}
+
void
Init_Cont(void)
{
@@ -3387,7 +3651,11 @@ Init_Cont(void)
#endif
SET_MACHINE_STACK_END(&th->ec->machine.stack_end);
- fiber_pool_initialize(&shared_fiber_pool, stack_size, FIBER_POOL_INITIAL_SIZE, vm_stack_size);
+ rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
+
+ size_t minimum_count = shared_fiber_pool_minimum_count();
+ size_t maximum_count = shared_fiber_pool_maximum_count();
+ fiber_pool_initialize(&shared_fiber_pool, stack_size, minimum_count, maximum_count, vm_stack_size);
fiber_initialize_keywords[0] = rb_intern_const("blocking");
fiber_initialize_keywords[1] = rb_intern_const("pool");
@@ -3409,7 +3677,6 @@ Init_Cont(void)
rb_cFiber = rb_define_class("Fiber", rb_cObject);
rb_define_alloc_func(rb_cFiber, fiber_alloc);
- rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
rb_define_singleton_method(rb_cFiber, "blocking", rb_fiber_blocking, 0);
@@ -3437,6 +3704,10 @@ Init_Cont(void)
rb_define_singleton_method(rb_cFiber, "schedule", rb_fiber_s_schedule, -1);
+ rb_thread_t *current_thread = rb_current_thread();
+ RUBY_ASSERT(CLASS_OF(current_thread->ec->fiber_ptr->cont.self) == 0);
+ *(VALUE *)&((struct RBasic *)current_thread->ec->fiber_ptr->cont.self)->klass = rb_cFiber;
+
#ifdef RB_EXPERIMENTAL_FIBER_POOL
/*
* Document-class: Fiber::Pool
diff --git a/coroutine/ppc64le/Context.S b/coroutine/ppc64le/Context.S
index f7bcae2c3a..819264c245 100644
--- a/coroutine/ppc64le/Context.S
+++ b/coroutine/ppc64le/Context.S
@@ -1,11 +1,18 @@
#define TOKEN_PASTE(x,y) x##y
+.abiversion 2
.text
.align 2
.globl PREFIXED_SYMBOL(coroutine_transfer)
.type PREFIXED_SYMBOL(coroutine_transfer), @function
PREFIXED_SYMBOL(coroutine_transfer):
+ # Global entry: set up TOC pointer (r2) from r12.
+ # Required by ELFv2 ABI when this function is reached via the PLT.
+ addis 2, 12, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@ha
+ addi 2, 2, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@l
+ .localentry PREFIXED_SYMBOL(coroutine_transfer), .-PREFIXED_SYMBOL(coroutine_transfer)
+
# Make space on the stack for caller registers
addi 1,1,-160
diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in
index 8e83d73040..109baa747d 100644
--- a/cygwin/GNUmakefile.in
+++ b/cygwin/GNUmakefile.in
@@ -6,14 +6,9 @@ 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@
diff --git a/darray.h b/darray.h
index c9035b74b6..d6521be19f 100644
--- a/darray.h
+++ b/darray.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
+#include "ruby/ruby.h"
// Type for a dynamic array. Use to declare a dynamic array.
// It is a pointer so it fits in st_table nicely. Designed
@@ -133,6 +134,9 @@ rb_darray_size(const void *ary)
return meta ? meta->size : 0;
}
+/* Estimate of the amount of memory used by this darray.
+ * Useful for TypedData objects. */
+#define rb_darray_memsize(ary) (sizeof(*(ary)) + (rb_darray_size(ary) * sizeof((ary)->data[0])))
static inline void
rb_darray_pop(void *ary, size_t count)
@@ -158,6 +162,16 @@ rb_darray_free(void *ary)
}
static inline void
+rb_darray_free_sized0(void *ary, size_t element_size)
+{
+ const rb_darray_meta_t *meta = ary;
+ if (meta) {
+ ruby_xfree_sized(ary, sizeof(*meta) + (element_size * meta->capa));
+ }
+}
+#define rb_darray_free_sized(ary, T) rb_darray_free_sized0((ary), sizeof(T))
+
+static inline void
rb_darray_free_without_gc(void *ary)
{
free(ary);
@@ -187,13 +201,16 @@ rb_darray_calloc_mul_add_without_gc(size_t x, size_t y, size_t z)
return ptr;
}
+void *ruby_xrealloc_sized(void *ptr, size_t new_size, size_t old_size);
+
/* Internal function. Like rb_xrealloc_mul_add. */
static inline void *
-rb_darray_realloc_mul_add(void *orig_ptr, size_t x, size_t y, size_t z)
+rb_darray_realloc_mul_add(void *orig_ptr, size_t capa, size_t element_size, size_t header_size)
{
- size_t size = rbimpl_size_add_or_raise(rbimpl_size_mul_or_raise(x, y), z);
+ size_t size = rbimpl_size_add_or_raise(rbimpl_size_mul_or_raise(capa, element_size), header_size);
+ size_t old_size = (rb_darray_capa(orig_ptr) * element_size) + header_size; // We know it won't overflow
- void *ptr = xrealloc(orig_ptr, size);
+ void *ptr = ruby_xrealloc_sized(orig_ptr, size, old_size);
RUBY_ASSERT(ptr != NULL);
return ptr;
diff --git a/debug.c b/debug.c
index 4717a0bc9c..730f860e7a 100644
--- a/debug.c
+++ b/debug.c
@@ -57,6 +57,7 @@ const union {
enum ruby_rstring_flags rstring_flags;
enum ruby_rarray_flags rarray_flags;
enum ruby_rarray_consts rarray_consts;
+ enum rbimpl_typeddata_flags rtypeddata_consts;
enum {
RUBY_FMODE_READABLE = FMODE_READABLE,
RUBY_FMODE_WRITABLE = FMODE_WRITABLE,
@@ -168,9 +169,7 @@ ruby_debug_breakpoint(void)
}
#if defined _WIN32
-# if RUBY_MSVCRT_VERSION >= 80
extern int ruby_w32_rtc_error;
-# endif
#endif
#if defined _WIN32 || defined __CYGWIN__
#include <windows.h>
@@ -233,9 +232,7 @@ ruby_env_debug_option(const char *str, int len, void *arg)
SET_WHEN("ci", ruby_on_ci, 1);
SET_WHEN_UINT("rgengc", &ruby_rgengc_debug, 1, ruby_rgengc_debug = 1);
#if defined _WIN32
-# if RUBY_MSVCRT_VERSION >= 80
SET_WHEN("rtc_error", ruby_w32_rtc_error, 1);
-# endif
#endif
#if defined _WIN32 || defined __CYGWIN__
SET_WHEN_UINT("codepage", ruby_w32_codepage, numberof(ruby_w32_codepage),
@@ -371,7 +368,7 @@ setup_debug_log_filter(void)
if (len >= MAX_DEBUG_LOG_FILTER_LEN) {
fprintf(stderr, "too long: %s (max:%d)\n", str, MAX_DEBUG_LOG_FILTER_LEN - 1);
- exit(1);
+ exit(EXIT_FAILURE);
}
// body
@@ -399,7 +396,7 @@ setup_debug_log(void)
debug_log.mem = (char *)malloc(MAX_DEBUG_LOG * MAX_DEBUG_LOG_MESSAGE_LEN);
if (debug_log.mem == NULL) {
fprintf(stderr, "setup_debug_log failed (can't allocate memory)\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
ruby_debug_log_mode |= ruby_debug_log_memory;
}
@@ -427,7 +424,7 @@ setup_debug_log(void)
break;
default:
fprintf(stderr, "can not parse RUBY_DEBUG_LOG filename: %s\n", log_config);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
else {
@@ -436,13 +433,13 @@ setup_debug_log(void)
if (j >= DEBUG_LOG_MAX_PATH) {
fprintf(stderr, "RUBY_DEBUG_LOG=%s is too long\n", log_config);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if ((debug_log.output = fopen(debug_log.output_file, "w")) == NULL) {
fprintf(stderr, "can not open %s for RUBY_DEBUG_LOG\n", log_config);
- exit(1);
+ exit(EXIT_FAILURE);
}
setvbuf(debug_log.output, NULL, _IONBF, 0);
}
@@ -712,4 +709,22 @@ ruby_debug_log_dump(const char *fname, unsigned int n)
fclose(fp);
}
}
+
+#else
+
+#undef ruby_debug_log
+void
+ruby_debug_log(const char *file, int line, const char *func_name, const char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "[%s:%d] %s: ", file, line, func_name);
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ fprintf(stderr, "\n");
+}
+
#endif // #if USE_RUBY_DEBUG_LOG
diff --git a/debug_counter.h b/debug_counter.h
index 481a0727e6..721ff9d1b8 100644
--- a/debug_counter.h
+++ b/debug_counter.h
@@ -49,7 +49,7 @@ RB_DEBUG_COUNTER(cc_temp) // dummy CC (stack-allocated)
RB_DEBUG_COUNTER(cc_found_in_ccs) // count for CC lookup success in CCS
RB_DEBUG_COUNTER(cc_not_found_in_ccs) // count for CC lookup success in CCS
-RB_DEBUG_COUNTER(cc_ent_invalidate) // count for invalidating cc (cc->klass = 0)
+RB_DEBUG_COUNTER(cc_ent_invalidate) // count for invalidating cc (cc->klass = Qundef)
RB_DEBUG_COUNTER(cc_cme_invalidate) // count for invalidating CME
RB_DEBUG_COUNTER(cc_invalidate_leaf) // count for invalidating klass if klass has no-subclasses
@@ -240,7 +240,7 @@ RB_DEBUG_COUNTER(obj_wb_unprotect)
RB_DEBUG_COUNTER(obj_obj_embed)
RB_DEBUG_COUNTER(obj_obj_ptr)
-RB_DEBUG_COUNTER(obj_obj_too_complex)
+RB_DEBUG_COUNTER(obj_obj_complex)
RB_DEBUG_COUNTER(obj_str_ptr)
RB_DEBUG_COUNTER(obj_str_embed)
@@ -305,16 +305,21 @@ RB_DEBUG_COUNTER(obj_imemo_ment)
RB_DEBUG_COUNTER(obj_imemo_iseq)
RB_DEBUG_COUNTER(obj_imemo_env)
RB_DEBUG_COUNTER(obj_imemo_tmpbuf)
-RB_DEBUG_COUNTER(obj_imemo_ast)
+RB_DEBUG_COUNTER(obj_imemo_cvar_entry)
RB_DEBUG_COUNTER(obj_imemo_cref)
RB_DEBUG_COUNTER(obj_imemo_svar)
RB_DEBUG_COUNTER(obj_imemo_throw_data)
RB_DEBUG_COUNTER(obj_imemo_ifunc)
RB_DEBUG_COUNTER(obj_imemo_memo)
-RB_DEBUG_COUNTER(obj_imemo_parser_strterm)
RB_DEBUG_COUNTER(obj_imemo_callinfo)
RB_DEBUG_COUNTER(obj_imemo_callcache)
RB_DEBUG_COUNTER(obj_imemo_constcache)
+RB_DEBUG_COUNTER(obj_imemo_fields)
+RB_DEBUG_COUNTER(obj_imemo_subclasses)
+RB_DEBUG_COUNTER(obj_imemo_cdhash)
+
+RB_DEBUG_COUNTER(opt_new_hit)
+RB_DEBUG_COUNTER(opt_new_miss)
/* ar_table */
RB_DEBUG_COUNTER(artable_hint_hit)
diff --git a/defs/gmake.mk b/defs/gmake.mk
index b34e8420ba..0320f9b7d5 100644
--- a/defs/gmake.mk
+++ b/defs/gmake.mk
@@ -2,6 +2,7 @@
reconfig config.status: export MAKE:=$(MAKE)
export BASERUBY:=$(BASERUBY)
+export GIT
override gnumake_recursive := $(if $(findstring n,$(firstword $(MFLAGS))),,+)
override mflags := $(filter-out -j%,$(MFLAGS))
MSPECOPT += $(if $(filter -j%,$(MFLAGS)),-j)
@@ -161,6 +162,10 @@ endif
config.status: $(wildcard config.cache)
+ifneq (ruby,$(PROGRAM))
+ruby: $(PROGRAM);
+endif
+
STUBPROGRAM = rubystub$(EXEEXT)
IGNOREDPATTERNS = %~ .% %.orig %.rej \#%\#
SCRIPTBINDIR := $(if $(EXEEXT),,exec/)
@@ -204,7 +209,7 @@ post-commit: $(if $(DOT_WAIT),,do-commit)
+$(Q) \
{ \
$(in-srcdir) \
- exec sed -f tool/prereq.status defs/gmake.mk template/Makefile.in common.mk; \
+ exec sed -f tool/prereq.status defs/gmake.mk template/Makefile.in common.mk depend; \
} | \
$(MAKE) $(mflags) Q=$(Q) ECHO=$(ECHO) \
top_srcdir="$(top_srcdir)" srcdir="$(srcdir)" srcs_vpath="" CHDIR="$(CHDIR)" \
@@ -216,8 +221,8 @@ post-commit: $(if $(DOT_WAIT),,do-commit)
GITHUB_RUBY_URL = https://github.com/ruby/ruby
PR =
-COMMIT_GPG_SIGN = $(shell $(GIT) -C "$(srcdir)" config commit.gpgsign)
-REMOTE_GITHUB_URL = $(shell $(GIT) -C "$(srcdir)" config remote.github.url)
+COMMIT_GPG_SIGN = $(shell $(GIT_IN_SRC) config commit.gpgsign)
+REMOTE_GITHUB_URL = $(shell $(GIT_IN_SRC) config remote.github.url)
COMMITS_NOTES = commits
.PHONY: fetch-github
@@ -232,19 +237,19 @@ define fetch-github
$(eval REMOTE_GITHUB_URL := $(REMOTE_GITHUB_URL))
$(if $(REMOTE_GITHUB_URL),,
echo adding $(GITHUB_RUBY_URL) as remote github
- $(GIT) -C "$(srcdir)" remote add github $(GITHUB_RUBY_URL)
- $(GIT) -C "$(srcdir)" config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES)
+ $(GIT_IN_SRC) remote add github $(GITHUB_RUBY_URL)
+ $(GIT_IN_SRC) config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES)
$(eval REMOTE_GITHUB_URL := $(GITHUB_RUBY_URL))
)
- $(if $(shell $(GIT) -C "$(srcdir)" rev-parse "github/pull/$(1)/head" -- 2> /dev/null),
- $(GIT) -C "$(srcdir)" branch -f "gh-$(1)" "github/pull/$(1)/head",
- $(GIT) -C "$(srcdir)" fetch -f github "pull/$(1)/head:gh-$(1)"
+ $(if $(shell $(GIT_IN_SRC) rev-parse "github/pull/$(1)/head" -- 2> /dev/null),
+ $(GIT_IN_SRC) branch -f "gh-$(1)" "github/pull/$(1)/head",
+ $(GIT_IN_SRC) fetch -f github "pull/$(1)/head:gh-$(1)"
)
endef
.PHONY: checkout-github
checkout-github: fetch-github
- $(GIT) -C "$(srcdir)" checkout "gh-$(PR)"
+ $(GIT_IN_SRC) checkout "gh-$(PR)"
.PHONY: update-github
update-github: fetch-github
@@ -257,25 +262,25 @@ update-github: fetch-github
$(eval PR_BRANCH := $(word 2,$(PULL_REQUEST_FORK_BRANCH)))
$(eval GITHUB_UPDATE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(PR)-XXXXXX"))
- $(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)"
+ $(GIT_IN_SRC) worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)"
$(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" merge master --no-edit
@$(BASERUBY) -e 'print "Are you sure to push this to PR=$(PR)? [Y/n]: "; exit(gets.chomp != "n")'
- $(GIT) -C "$(srcdir)" remote add fork-$(PR) git@github.com:$(FORK_REPO).git
+ $(GIT_IN_SRC) remote add fork-$(PR) git@github.com:$(FORK_REPO).git
$(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" push fork-$(PR) gh-$(PR):$(PR_BRANCH)
- $(GIT) -C "$(srcdir)" remote rm fork-$(PR)
- $(GIT) -C "$(srcdir)" worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE))
- $(GIT) -C "$(srcdir)" branch -D gh-$(PR)
+ $(GIT_IN_SRC) remote rm fork-$(PR)
+ $(GIT_IN_SRC) worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE))
+ $(GIT_IN_SRC) branch -D gh-$(PR)
.PHONY: pull-github
pull-github: fetch-github
$(call pull-github,$(PR))
define pull-github
- $(eval GITHUB_MERGE_BASE := $(shell $(GIT) -C "$(srcdir)" log -1 --format=format:%H))
- $(eval GITHUB_MERGE_BRANCH := $(shell $(GIT) -C "$(srcdir)" symbolic-ref --short HEAD))
+ $(eval GITHUB_MERGE_BASE := $(shell $(GIT_IN_SRC) rev-parse HEAD)
+ $(eval GITHUB_MERGE_BRANCH := $(shell $(GIT_IN_SRC) symbolic-ref --short HEAD))
$(eval GITHUB_MERGE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(1)-XXXXXX"))
- $(GIT) -C "$(srcdir)" worktree prune
- $(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)"
+ $(GIT_IN_SRC) worktree prune
+ $(GIT_IN_SRC) worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)"
$(GIT) -C "$(GITHUB_MERGE_WORKTREE)" rebase $(GITHUB_MERGE_BRANCH)
$(eval COMMIT_GPG_SIGN := $(COMMIT_GPG_SIGN))
$(if $(filter true,$(COMMIT_GPG_SIGN)), \
@@ -290,7 +295,7 @@ fetch-github-%:
.PHONY: checkout-github-%
checkout-github-%: fetch-github-%
- $(GIT) -C "$(srcdir)" checkout "gh-$*"
+ $(GIT_IN_SRC) checkout "gh-$*"
.PHONY: pr-% pull-github-%
pr-% pull-github-%: fetch-github-%
@@ -309,7 +314,7 @@ HELP_EXTRA_TASKS = \
# 4. "gem x.y.z URL" -> "gem-x.y.z"
bundled-gems := $(shell sed \
-e 's/[ ][ ]*/ /g' \
- -e 's/^ //;/\#/d;s/ *$$//;/^$$/d' \
+ -e 's/^ //;s/\#.*//;s/ *$$//;/^$$/d' \
$(if $(filter yes,$(HAVE_GIT)), \
-e 's/^\(.*\) \(.*\) \(.*\) \(.*\)/\1|\2|\4|\3/' \
) \
@@ -365,7 +370,7 @@ $(srcdir)/.bundle/.timestamp:
define build-gem
$(srcdir)/gems/src/$(1)/.git: | $(srcdir)/gems/src
$(ECHO) Cloning $(4)
- $(Q) $(GIT) clone $(4) $$(@D)
+ $(Q) $(GIT) clone --depth=1 --no-tags $(4) $$(@D)
$(bundled-gem-revision): \
$(if $(if $(wildcard $$(@)),$(filter $(3),$(shell cat $$(@)))),,PHONY) \
@@ -406,6 +411,7 @@ $(srcdir)/.bundle/gems:
ifneq ($(DOT_WAIT),)
up:: $(DOT_WAIT) after-update
+after-update:: MINIRUBY = $(BASERUBY)
endif
ifneq ($(filter update-bundled_gems refresh-gems,$(MAKECMDGOALS)),)
@@ -429,7 +435,7 @@ ifneq ($(DOT_WAIT),)
endif
ifeq ($(HAVE_GIT),yes)
-REVISION_LATEST := $(shell $(CHDIR) $(srcdir) && $(GIT) log -1 --format=%H 2>/dev/null)
+REVISION_LATEST := $(shell $(GIT_IN_SRC) rev-parse HEAD 2>/dev/null)
else
REVISION_LATEST := update
endif
@@ -442,12 +448,16 @@ $(REVISION_H): PHONY
endif
include $(top_srcdir)/yjit/yjit.mk
+include $(top_srcdir)/zjit/zjit.mk
+include $(top_srcdir)/defs/jit.mk
# Query on the generated rdoc
#
# $ make rdoc:Integer#+
-rdoc\:%: PHONY
- $(Q)$(RUNRUBY) $(srcdir)/libexec/ri --no-standard-docs --doc-dir=$(RDOCOUT) $(patsubst rdoc:%,%,$@)
+rdoc\:%: PHONY programs $(RDOCOUT) update-default-gemspecs
+ $(Q)$(RUNRUBY) $(RUNOPT0) -I$(tooldir)/lib -rbundled_gem \
+ -e "load BundledGem.command('rdoc', 'ri')" -- \
+ --no-standard-docs --doc-dir=$(RDOCOUT) $(patsubst rdoc:%,%,$@)
test_%.rb test/%: programs PHONY
$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TEST_EXCLUDES) $(TESTOPTS) -- $(patsubst test/%,%,$@)
@@ -489,7 +499,7 @@ endif
update-deps:
$(eval update_deps := $(shell date +update-deps-%Y%m%d))
$(eval deps_dir := $(shell mktemp -d)/$(update_deps))
- $(eval GIT_DIR := $(shell $(GIT) -C $(srcdir) rev-parse --absolute-git-dir))
+ $(eval GIT_DIR := $(shell $(GIT_IN_SRC) rev-parse --absolute-git-dir))
$(GIT) --git-dir=$(GIT_DIR) worktree add $(deps_dir)
cp $(tooldir)/config.guess $(tooldir)/config.sub $(deps_dir)/tool
[ -f config.status ] && cp config.status $(deps_dir)
@@ -503,10 +513,14 @@ update-deps:
$(GIT) --git-dir=$(GIT_DIR) merge --no-edit --ff-only $(update_deps)
$(GIT) --git-dir=$(GIT_DIR) branch --delete $(update_deps)
+fix-depends check-depends: all hello
+ $(BASERUBY) -C $(srcdir) tool/update-deps $(if $(filter fix-%,$@),--fix)
+
# order-only-prerequisites doesn't work for $(RUBYSPEC_CAPIEXT)
# because the same named directory exists in the source tree.
-$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(srcdir)/$(RUBYSPEC_CAPIEXT)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY)
- $(ECHO) building $@
+$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(RUBYSPEC_CAPIEXT_DEPS) \
+ | build-ext yes-rubyspec-capiext
+ $(no_silence:no=$(ECHO) building $@)
$(Q) $(MAKEDIRS) $(@D)
$(Q) $(DLDSHARED) -L. $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG)
ifneq ($(POSTLINK),)
@@ -514,44 +528,86 @@ ifneq ($(POSTLINK),)
endif
$(Q) $(RMALL) $@.*
-RUBYSPEC_CAPIEXT_SO := $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
-rubyspec-capiext: $(RUBYSPEC_CAPIEXT_SO)
- @ $(NULLCMD)
-
-ifeq ($(ENABLE_SHARED),yes)
-ruby: $(if $(LIBRUBY_SO_UPDATE),$(RUBYSPEC_CAPIEXT_SO))
-exts: rubyspec-capiext
-endif
+RUBYSPEC_CAPIEXT_EXTS := $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
+rubyspec-capiext: $(RUBYSPEC_CAPIEXT_EXTS)
-spec/%/ spec/%_spec.rb: programs exts PHONY
+spec/%/ spec/%_spec.rb: programs exts $(RUBYSPEC_CAPIEXT_BUILD) 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))
+# `make matz`: bump up the MINOR;
+# Copying NEWS.md to doc/NEWS/, and empty the details in NEWS.md.
+#
+# `make matz NEW=x.y`: bump up to x.y.0;
+# Just update the version in the title of NEWS.md.
+
matz: up
- $(eval OLD := $(MAJOR).$(MINOR).0)
- $(eval MINOR := $(shell expr $(MINOR) + 1))
- $(eval NEW := $(MAJOR).$(MINOR).0)
- $(eval message := Development of $(NEW) started.)
- $(eval files := include/ruby/version.h include/ruby/internal/abi.h)
- $(GIT) -C $(srcdir) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md
- $(GIT) -C $(srcdir) commit -m "[DOC] Flush NEWS.md"
+matz-commit: OLD := $(MAJOR).$(MINOR).0
+ifdef NEW
+matz-commit: MAJOR := $(word 1,$(subst ., ,$(NEW)))
+matz-commit: MINOR := $(word 2,$(subst ., ,$(NEW)))
+matz-commit: $(DOT_WAIT) bump_news
+bump_news$(DOT_WAIT): up
+bump_headers$(DOT_WAIT): bump_news
+else
+matz-commit: MINOR := $(shell expr $(MINOR) + 1)
+matz-commit: $(DOT_WAIT) reset_news
+flush_news$(DOT_WAIT): up
+bump_headers$(DOT_WAIT): reset_news
+endif
+
+matz: $(DOT_WAIT) matz-commit
+matz-commit: bump_headers
+matz-commit: override NEW := $(MAJOR).$(MINOR).0
+matz-commit: files := include/ruby/version.h include/ruby/internal/abi.h
+matz-commit: message := Development of $(NEW) started.
+
+flush_news:
+ $(GIT_IN_SRC) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md
+ $(GIT_IN_SRC) commit -m "[DOC] Flush NEWS.md"
+
+.PHONY: flush_news reset_news bump_news bump_headers
+
+bump_headers:
sed -i~ \
+ -e "s/^\(#define RUBY_API_VERSION_MAJOR\) .*/\1 $(MAJOR)/" \
-e "s/^\(#define RUBY_API_VERSION_MINOR\) .*/\1 $(MINOR)/" \
-e "s/^\(#define RUBY_ABI_VERSION\) .*/\1 0/" \
$(files:%=$(srcdir)/%)
- $(GIT) -C $(srcdir) add $(files)
+
+reset_news: flush_news
$(BASERUBY) -C $(srcdir) -p -00 \
- -e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen("NEWS.md")}' \
+ -e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen(ARGV.shift)}' \
-e 'case $$.' \
-e 'when 1; $$_.sub!(/Ruby \K[0-9.]+/, new)' \
-e 'when 2; $$_.sub!(/\*\*\K[0-9.]+(?=\*\*)/, old)' \
-e 'end' \
-e 'next if /^[\[ *]/ =~ $$_' \
-e '$$_.sub!(/\n{2,}\z/, "\n\n")' \
- $(OLD) $(NEW) doc/NEWS/NEWS-$(OLD).md
- $(GIT) -C $(srcdir) add NEWS.md
- $(GIT) -C $(srcdir) commit -m "$(message)"
+ $(OLD) $(NEW) NEWS.md doc/NEWS/NEWS-$(OLD).md
+
+bump_news:
+ $(BASERUBY) -C $(srcdir) -p -i \
+ -e 'BEGIN {new = ARGV.shift; print gets("").sub(/Ruby \K[0-9.]+/, new)}' \
+ $(NEW) NEWS.md
+
+matz: matz-commit matz-push
+
+matz-commit:
+ $(GIT_IN_SRC) add NEWS.md $(files)
+ $(GIT_IN_SRC) commit -m "$(message)"
+
+GIT_REMOTE_ORIGIN = origin
+
+matz-push: matz-commit
+ $(eval origin_url := $(shell $(GIT_IN_SRC) remote get-url $(GIT_REMOTE_ORIGIN)))
+ $(if $(origin_url),,@false)
+ $(eval last_commit := $(shell $(GIT_IN_SRC) log -n1 --format=%H --author=matz HEAD~..HEAD))
+ $(if $(last_commit),,$(ECHO) No matz commits 1>&2; false)
+ $(if $(filter 12-25 12-26,$(shell date +%m-%d)),,$(ECHO) Not the release date 1>&2; false)
+ $(ECHO) $$'\e[31m'Pushing to $$'\e[7m'$(GIT_REMOTE_ORIGIN)$$'\e[27m'" ($(origin_url))"$$'\e[m'
+ $(GIT_IN_SRC) push $(GIT_REMOTE_ORIGIN)
tags:
$(MAKE) GIT="$(GIT)" -C "$(srcdir)" -f defs/tags.mk
diff --git a/defs/id.def b/defs/id.def
index 5e2da592ef..344b072e76 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -28,6 +28,7 @@ firstline, predefined = __LINE__+1, %[\
send
__send__
__recursive_key__
+ clone
initialize
initialize_copy
initialize_clone
@@ -63,6 +64,8 @@ firstline, predefined = __LINE__+1, %[\
pack
buffer
include?
+ aborted
+ exited
_ UScore
@@ -76,6 +79,8 @@ firstline, predefined = __LINE__+1, %[\
_7 NUMPARAM_7
_8 NUMPARAM_8
_9 NUMPARAM_9
+ <it> ItImplicit
+ it It
"/*NULL*/" NULL
empty?
diff --git a/defs/jit.mk b/defs/jit.mk
new file mode 100644
index 0000000000..2c1e819684
--- /dev/null
+++ b/defs/jit.mk
@@ -0,0 +1,107 @@
+# Make recipes that deal with the rust code of YJIT and ZJIT.
+#
+# $(gnumake_recursive) adds the '+' prefix to pass down GNU make's
+# jobserver resources to cargo/rustc as rust-lang.org recommends.
+# Without it, certain make version trigger a warning. It does not
+# add the prefix when `make --dry-run` so dry runs are indeed dry.
+
+ifneq ($(JIT_CARGO_SUPPORT),no)
+
+# Show Cargo progress when doing `make V=1`
+CARGO_VERBOSE_0 = -q
+CARGO_VERBOSE_1 =
+CARGO_VERBOSE = $(CARGO_VERBOSE_$(V))
+
+# Because of Cargo cache, if the actual binary is not changed from the
+# previous build, the mtime is preserved as the cached file.
+# This means the target is not updated actually, and it will need to
+# rebuild at the next build.
+RUST_LIB_TOUCH = touch $@
+
+# NOTE: MACOSX_DEPLOYMENT_TARGET to match `rustc --print deployment-target` to avoid the warning below.
+# ld: warning: object file (target/debug/libjit.a(<libcapstone object>)) was built for
+# newer macOS version (15.2) than being linked (15.0)
+# This limits us to an older set of macOS API in the rust code, but we don't use any.
+$(RUST_LIB): $(srcdir)/ruby.rs target/.rustc-version
+ $(Q)if [ '$(ZJIT_SUPPORT)' != no -a '$(YJIT_SUPPORT)' != no ]; then \
+ echo 'building YJIT and ZJIT ($(JIT_CARGO_SUPPORT:yes=release) mode)'; \
+ elif [ '$(ZJIT_SUPPORT)' != no ]; then \
+ echo 'building ZJIT ($(JIT_CARGO_SUPPORT) mode)'; \
+ elif [ '$(YJIT_SUPPORT)' != no ]; then \
+ echo 'building YJIT ($(JIT_CARGO_SUPPORT) mode)'; \
+ fi
+ $(gnumake_recursive)$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
+ CARGO_TERM_PROGRESS_WHEN='never' \
+ MACOSX_DEPLOYMENT_TARGET=11.0 \
+ $(CARGO) $(CARGO_VERBOSE) build --manifest-path '$(top_srcdir)/Cargo.toml' $(CARGO_BUILD_ARGS)
+ $(RUST_LIB_TOUCH)
+else ifneq ($(strip $(RLIB_DIR)),) # combo build
+
+$(RUST_LIB): $(srcdir)/ruby.rs target/.rustc-version
+ $(ECHO) 'building $(@F)'
+ $(gnumake_recursive)$(Q) $(RUSTC) --edition=2024 \
+ $(RUSTC_FLAGS) \
+ '-L$(@D)' \
+ --extern=yjit \
+ --extern=zjit \
+ --crate-type=staticlib \
+ --cfg 'feature="yjit"' \
+ --cfg 'feature="zjit"' \
+ '--out-dir=$(@D)' \
+ '$(top_srcdir)/ruby.rs'
+
+# Absolute path to avoid VPATH ambiguity
+JIT_RLIB = $(TOP_BUILD_DIR)/$(RLIB_DIR)/libjit.rlib
+$(YJIT_RLIB): $(JIT_RLIB)
+$(ZJIT_RLIB): $(JIT_RLIB)
+$(JIT_RLIB): target/.rustc-version
+ $(ECHO) 'building $(@F)'
+ $(gnumake_recursive)$(Q) $(RUSTC) --crate-name=jit \
+ --edition=2024 \
+ $(JIT_RUST_FLAGS) \
+ $(RUSTC_FLAGS) \
+ '--out-dir=$(@D)' \
+ '$(top_srcdir)/jit/src/lib.rs'
+endif # ifneq ($(JIT_CARGO_SUPPORT),no)
+
+RUST_LIB_SYMBOLS = $(RUST_LIB:.a=).symbols
+$(RUST_LIBOBJ): $(RUST_LIB)
+ $(ECHO) 'partial linking $(RUST_LIB) into $@'
+ifneq ($(findstring darwin,$(target_os)),)
+ $(Q) $(CC) -nodefaultlibs -r -o $@ -exported_symbols_list $(RUST_LIB_SYMBOLS) $(RUST_LIB)
+else
+ $(Q) $(LD) -r -o $@ --whole-archive $(RUST_LIB)
+ -$(Q) $(OBJCOPY) --wildcard --keep-global-symbol='$(SYMBOL_PREFIX)rb_*' $(@)
+endif
+
+rust-libobj: $(RUST_LIBOBJ)
+rust-lib: $(RUST_LIB)
+
+rustc-version-check: target/.rustc-version
+
+target/.rustc-version: PHONY
+ $(eval prev_version := $(if $(wildcard $@),$(shell cat $@)))
+ $(eval curr_version := $(shell $(RUSTC) -V | cut -d' ' -f2))
+ $(eval clean := $(filter-out $(prev_version),$(curr_version)))
+ $(if $(clean),$(ECHO) Cleaning $(@D) for rustc $(curr_version))
+ $(if $(clean),$(Q)$(RMALL) $(@D))
+ $(if $(clean),$(Q)$(MAKEDIRS) $(@D))
+ $(if $(clean),$(Q)echo $(curr_version) > $@)
+
+# For Darwin only: a list of symbols that we want the glommed Rust static lib to export.
+# Unfortunately, using wildcard like '_rb_*' with -exported-symbol does not work, at least
+# not on version 820.1. Assume llvm-nm, so XCode 8.0 (from 2016) or newer.
+#
+# The -exported_symbols_list pulls out the right archive members. Symbols not listed
+# in the list are made private extern, which are in turn made local as we're using `ld -r`.
+# Note, section about -keep_private_externs in ld's man page hints at this behavior on which
+# we rely.
+ifneq ($(findstring darwin,$(target_os)),)
+$(RUST_LIB_SYMBOLS): $(RUST_LIB)
+ $(Q) $(tooldir)/darwin-ar $(NM) --defined-only --extern-only $(RUST_LIB) | \
+ sed -n -e 's/.* //' -e '/^$(SYMBOL_PREFIX)rb_/p' \
+ -e '/^$(SYMBOL_PREFIX)rust_eh_personality/p' \
+ > $@
+
+$(RUST_LIBOBJ): $(RUST_LIB_SYMBOLS)
+endif
diff --git a/defs/opt_insn_unif.def b/defs/opt_insn_unif.def
index 31ae2eb6a1..5ce67538f1 100644
--- a/defs/opt_insn_unif.def
+++ b/defs/opt_insn_unif.def
@@ -6,12 +6,12 @@
__END__
putobject putobject
-putobject putstring
+putobject dupstring
putobject setlocal
-putstring putstring
-putstring putobject
-putstring setlocal
+dupstring dupstring
+dupstring putobject
+dupstring setlocal
# putnil end
diff --git a/depend b/depend
new file mode 100644
index 0000000000..a2e8312298
--- /dev/null
+++ b/depend
@@ -0,0 +1,21719 @@
+# AUTOGENERATED DEPENDENCIES START
+addr2line.$(OBJEXT): {$(VPATH)}addr2line.c
+addr2line.$(OBJEXT): {$(VPATH)}addr2line.h
+addr2line.$(OBJEXT): {$(VPATH)}assert.h
+addr2line.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+addr2line.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+addr2line.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+addr2line.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+addr2line.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+addr2line.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+addr2line.$(OBJEXT): {$(VPATH)}config.h
+addr2line.$(OBJEXT): {$(VPATH)}defines.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/assume.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+addr2line.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/cast.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/config.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/dosish.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+addr2line.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+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
+array.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+array.$(OBJEXT): $(top_srcdir)/internal/bits.h
+array.$(OBJEXT): $(top_srcdir)/internal/box.h
+array.$(OBJEXT): $(top_srcdir)/internal/class.h
+array.$(OBJEXT): $(top_srcdir)/internal/compar.h
+array.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+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
+array.$(OBJEXT): $(top_srcdir)/internal/rational.h
+array.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+array.$(OBJEXT): $(top_srcdir)/internal/serial.h
+array.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+array.$(OBJEXT): $(top_srcdir)/internal/struct.h
+array.$(OBJEXT): $(top_srcdir)/internal/variable.h
+array.$(OBJEXT): $(top_srcdir)/internal/vm.h
+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
+array.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+array.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+array.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+array.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+array.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+array.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+array.$(OBJEXT): {$(VPATH)}builtin.h
+array.$(OBJEXT): {$(VPATH)}config.h
+array.$(OBJEXT): {$(VPATH)}constant.h
+array.$(OBJEXT): {$(VPATH)}debug_counter.h
+array.$(OBJEXT): {$(VPATH)}defines.h
+array.$(OBJEXT): {$(VPATH)}encoding.h
+array.$(OBJEXT): {$(VPATH)}id.h
+array.$(OBJEXT): {$(VPATH)}id_table.h
+array.$(OBJEXT): {$(VPATH)}intern.h
+array.$(OBJEXT): {$(VPATH)}internal.h
+array.$(OBJEXT): {$(VPATH)}internal/abi.h
+array.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+array.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+array.$(OBJEXT): {$(VPATH)}internal/assume.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+array.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+array.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+array.$(OBJEXT): {$(VPATH)}internal/cast.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+array.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+array.$(OBJEXT): {$(VPATH)}internal/config.h
+array.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+array.$(OBJEXT): {$(VPATH)}internal/core.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+array.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+array.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+array.$(OBJEXT): {$(VPATH)}internal/ctype.h
+array.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+array.$(OBJEXT): {$(VPATH)}internal/dosish.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+array.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+array.$(OBJEXT): {$(VPATH)}internal/error.h
+array.$(OBJEXT): {$(VPATH)}internal/eval.h
+array.$(OBJEXT): {$(VPATH)}internal/event.h
+array.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+array.$(OBJEXT): {$(VPATH)}internal/gc.h
+array.$(OBJEXT): {$(VPATH)}internal/glob.h
+array.$(OBJEXT): {$(VPATH)}internal/globals.h
+array.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+array.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+array.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+array.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+array.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+array.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+array.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+array.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+array.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+array.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+array.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+array.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+array.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+array.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+array.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+array.$(OBJEXT): {$(VPATH)}internal/symbol.h
+array.$(OBJEXT): {$(VPATH)}internal/value.h
+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)}ractor.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.h
+array.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+array.$(OBJEXT): {$(VPATH)}thread_native.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
+ast.$(OBJEXT): $(CCAN_DIR)/str/str.h
+ast.$(OBJEXT): $(hdrdir)/ruby.h
+ast.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+ast.$(OBJEXT): $(top_srcdir)/internal/array.h
+ast.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+ast.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+ast.$(OBJEXT): $(top_srcdir)/internal/bits.h
+ast.$(OBJEXT): $(top_srcdir)/internal/box.h
+ast.$(OBJEXT): $(top_srcdir)/internal/compar.h
+ast.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+ast.$(OBJEXT): $(top_srcdir)/internal/complex.h
+ast.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+ast.$(OBJEXT): $(top_srcdir)/internal/gc.h
+ast.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+ast.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+ast.$(OBJEXT): $(top_srcdir)/internal/parse.h
+ast.$(OBJEXT): $(top_srcdir)/internal/rational.h
+ast.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+ast.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+ast.$(OBJEXT): $(top_srcdir)/internal/serial.h
+ast.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+ast.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+ast.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+ast.$(OBJEXT): $(top_srcdir)/prism/ast.h
+ast.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+ast.$(OBJEXT): $(top_srcdir)/prism/comments.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+ast.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+ast.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+ast.$(OBJEXT): $(top_srcdir)/prism/integer.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+ast.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+ast.$(OBJEXT): $(top_srcdir)/prism/json.h
+ast.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+ast.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+ast.$(OBJEXT): $(top_srcdir)/prism/node.h
+ast.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+ast.$(OBJEXT): $(top_srcdir)/prism/source.h
+ast.$(OBJEXT): $(top_srcdir)/prism/stream.h
+ast.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+ast.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+ast.$(OBJEXT): $(top_srcdir)/prism/version.h
+ast.$(OBJEXT): {$(VPATH)}assert.h
+ast.$(OBJEXT): {$(VPATH)}ast.c
+ast.$(OBJEXT): {$(VPATH)}ast.rbinc
+ast.$(OBJEXT): {$(VPATH)}atomic.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+ast.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+ast.$(OBJEXT): {$(VPATH)}builtin.h
+ast.$(OBJEXT): {$(VPATH)}config.h
+ast.$(OBJEXT): {$(VPATH)}constant.h
+ast.$(OBJEXT): {$(VPATH)}defines.h
+ast.$(OBJEXT): {$(VPATH)}encoding.h
+ast.$(OBJEXT): {$(VPATH)}id.h
+ast.$(OBJEXT): {$(VPATH)}id_table.h
+ast.$(OBJEXT): {$(VPATH)}intern.h
+ast.$(OBJEXT): {$(VPATH)}internal.h
+ast.$(OBJEXT): {$(VPATH)}internal/abi.h
+ast.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+ast.$(OBJEXT): {$(VPATH)}internal/assume.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+ast.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+ast.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+ast.$(OBJEXT): {$(VPATH)}internal/cast.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+ast.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+ast.$(OBJEXT): {$(VPATH)}internal/config.h
+ast.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+ast.$(OBJEXT): {$(VPATH)}internal/core.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+ast.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+ast.$(OBJEXT): {$(VPATH)}internal/ctype.h
+ast.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+ast.$(OBJEXT): {$(VPATH)}internal/dosish.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+ast.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+ast.$(OBJEXT): {$(VPATH)}internal/error.h
+ast.$(OBJEXT): {$(VPATH)}internal/eval.h
+ast.$(OBJEXT): {$(VPATH)}internal/event.h
+ast.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+ast.$(OBJEXT): {$(VPATH)}internal/gc.h
+ast.$(OBJEXT): {$(VPATH)}internal/glob.h
+ast.$(OBJEXT): {$(VPATH)}internal/globals.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+ast.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+ast.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+ast.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+ast.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+ast.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+ast.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+ast.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+ast.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+ast.$(OBJEXT): {$(VPATH)}internal/symbol.h
+ast.$(OBJEXT): {$(VPATH)}internal/value.h
+ast.$(OBJEXT): {$(VPATH)}internal/value_type.h
+ast.$(OBJEXT): {$(VPATH)}internal/variable.h
+ast.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+ast.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+ast.$(OBJEXT): {$(VPATH)}iseq.h
+ast.$(OBJEXT): {$(VPATH)}method.h
+ast.$(OBJEXT): {$(VPATH)}missing.h
+ast.$(OBJEXT): {$(VPATH)}node.h
+ast.$(OBJEXT): {$(VPATH)}onigmo.h
+ast.$(OBJEXT): {$(VPATH)}oniguruma.h
+ast.$(OBJEXT): {$(VPATH)}prism_compile.h
+ast.$(OBJEXT): {$(VPATH)}prism_xallocator.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
+ast.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+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/box.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/class.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/compar.h
+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
+bignum.$(OBJEXT): $(top_srcdir)/internal/serial.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+bignum.$(OBJEXT): $(top_srcdir)/internal/struct.h
+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
+bignum.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+bignum.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+bignum.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+bignum.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+bignum.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+bignum.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+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
+bignum.$(OBJEXT): {$(VPATH)}internal.h
+bignum.$(OBJEXT): {$(VPATH)}internal/abi.h
+bignum.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+bignum.$(OBJEXT): {$(VPATH)}internal/assume.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+bignum.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+bignum.$(OBJEXT): {$(VPATH)}internal/cast.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+bignum.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+bignum.$(OBJEXT): {$(VPATH)}internal/config.h
+bignum.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+bignum.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+bignum.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+bignum.$(OBJEXT): {$(VPATH)}internal/gc.h
+bignum.$(OBJEXT): {$(VPATH)}internal/glob.h
+bignum.$(OBJEXT): {$(VPATH)}internal/globals.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+bignum.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+bignum.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+bignum.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+bignum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+bignum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+bignum.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+bignum.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+bignum.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+bignum.$(OBJEXT): {$(VPATH)}internal/symbol.h
+bignum.$(OBJEXT): {$(VPATH)}internal/value.h
+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
+box.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+box.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+box.$(OBJEXT): $(CCAN_DIR)/list/list.h
+box.$(OBJEXT): $(CCAN_DIR)/str/str.h
+box.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+box.$(OBJEXT): $(top_srcdir)/internal/array.h
+box.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+box.$(OBJEXT): $(top_srcdir)/internal/box.h
+box.$(OBJEXT): $(top_srcdir)/internal/class.h
+box.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+box.$(OBJEXT): $(top_srcdir)/internal/error.h
+box.$(OBJEXT): $(top_srcdir)/internal/eval.h
+box.$(OBJEXT): $(top_srcdir)/internal/file.h
+box.$(OBJEXT): $(top_srcdir)/internal/gc.h
+box.$(OBJEXT): $(top_srcdir)/internal/hash.h
+box.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+box.$(OBJEXT): $(top_srcdir)/internal/io.h
+box.$(OBJEXT): $(top_srcdir)/internal/load.h
+box.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+box.$(OBJEXT): $(top_srcdir)/internal/serial.h
+box.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+box.$(OBJEXT): $(top_srcdir)/internal/st.h
+box.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+box.$(OBJEXT): $(top_srcdir)/internal/string.h
+box.$(OBJEXT): $(top_srcdir)/internal/struct.h
+box.$(OBJEXT): $(top_srcdir)/internal/variable.h
+box.$(OBJEXT): $(top_srcdir)/internal/vm.h
+box.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+box.$(OBJEXT): $(top_srcdir)/prism/arena.h
+box.$(OBJEXT): $(top_srcdir)/prism/ast.h
+box.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+box.$(OBJEXT): $(top_srcdir)/prism/comments.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+box.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+box.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+box.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+box.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+box.$(OBJEXT): $(top_srcdir)/prism/integer.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+box.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+box.$(OBJEXT): $(top_srcdir)/prism/json.h
+box.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+box.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+box.$(OBJEXT): $(top_srcdir)/prism/node.h
+box.$(OBJEXT): $(top_srcdir)/prism/options.h
+box.$(OBJEXT): $(top_srcdir)/prism/parser.h
+box.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+box.$(OBJEXT): $(top_srcdir)/prism/prism.h
+box.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+box.$(OBJEXT): $(top_srcdir)/prism/source.h
+box.$(OBJEXT): $(top_srcdir)/prism/stream.h
+box.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+box.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+box.$(OBJEXT): $(top_srcdir)/prism/version.h
+box.$(OBJEXT): {$(VPATH)}assert.h
+box.$(OBJEXT): {$(VPATH)}atomic.h
+box.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+box.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+box.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+box.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+box.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+box.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+box.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+box.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+box.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+box.$(OBJEXT): {$(VPATH)}box.c
+box.$(OBJEXT): {$(VPATH)}builtin.h
+box.$(OBJEXT): {$(VPATH)}config.h
+box.$(OBJEXT): {$(VPATH)}constant.h
+box.$(OBJEXT): {$(VPATH)}darray.h
+box.$(OBJEXT): {$(VPATH)}debug_counter.h
+box.$(OBJEXT): {$(VPATH)}defines.h
+box.$(OBJEXT): {$(VPATH)}encindex.h
+box.$(OBJEXT): {$(VPATH)}encoding.h
+box.$(OBJEXT): {$(VPATH)}eval_intern.h
+box.$(OBJEXT): {$(VPATH)}id.h
+box.$(OBJEXT): {$(VPATH)}id_table.h
+box.$(OBJEXT): {$(VPATH)}intern.h
+box.$(OBJEXT): {$(VPATH)}internal.h
+box.$(OBJEXT): {$(VPATH)}internal/abi.h
+box.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+box.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+box.$(OBJEXT): {$(VPATH)}internal/assume.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+box.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+box.$(OBJEXT): {$(VPATH)}internal/cast.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+box.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+box.$(OBJEXT): {$(VPATH)}internal/config.h
+box.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+box.$(OBJEXT): {$(VPATH)}internal/core.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+box.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+box.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+box.$(OBJEXT): {$(VPATH)}internal/ctype.h
+box.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+box.$(OBJEXT): {$(VPATH)}internal/dosish.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+box.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+box.$(OBJEXT): {$(VPATH)}internal/error.h
+box.$(OBJEXT): {$(VPATH)}internal/eval.h
+box.$(OBJEXT): {$(VPATH)}internal/event.h
+box.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+box.$(OBJEXT): {$(VPATH)}internal/gc.h
+box.$(OBJEXT): {$(VPATH)}internal/glob.h
+box.$(OBJEXT): {$(VPATH)}internal/globals.h
+box.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+box.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+box.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+box.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+box.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+box.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+box.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+box.$(OBJEXT): {$(VPATH)}internal/iterator.h
+box.$(OBJEXT): {$(VPATH)}internal/memory.h
+box.$(OBJEXT): {$(VPATH)}internal/method.h
+box.$(OBJEXT): {$(VPATH)}internal/module.h
+box.$(OBJEXT): {$(VPATH)}internal/newobj.h
+box.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+box.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+box.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+box.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+box.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+box.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+box.$(OBJEXT): {$(VPATH)}internal/symbol.h
+box.$(OBJEXT): {$(VPATH)}internal/value.h
+box.$(OBJEXT): {$(VPATH)}internal/value_type.h
+box.$(OBJEXT): {$(VPATH)}internal/variable.h
+box.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+box.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+box.$(OBJEXT): {$(VPATH)}io.h
+box.$(OBJEXT): {$(VPATH)}iseq.h
+box.$(OBJEXT): {$(VPATH)}method.h
+box.$(OBJEXT): {$(VPATH)}missing.h
+box.$(OBJEXT): {$(VPATH)}node.h
+box.$(OBJEXT): {$(VPATH)}onigmo.h
+box.$(OBJEXT): {$(VPATH)}oniguruma.h
+box.$(OBJEXT): {$(VPATH)}prism/ast.h
+box.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
+box.$(OBJEXT): {$(VPATH)}prism/version.h
+box.$(OBJEXT): {$(VPATH)}prism_compile.h
+box.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+box.$(OBJEXT): {$(VPATH)}ruby_assert.h
+box.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+box.$(OBJEXT): {$(VPATH)}rubyparser.h
+box.$(OBJEXT): {$(VPATH)}shape.h
+box.$(OBJEXT): {$(VPATH)}st.h
+box.$(OBJEXT): {$(VPATH)}subst.h
+box.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+box.$(OBJEXT): {$(VPATH)}thread_native.h
+box.$(OBJEXT): {$(VPATH)}util.h
+box.$(OBJEXT): {$(VPATH)}vm_core.h
+box.$(OBJEXT): {$(VPATH)}vm_debug.h
+box.$(OBJEXT): {$(VPATH)}vm_opts.h
+box.$(OBJEXT): {$(VPATH)}vm_sync.h
+box.$(OBJEXT): {$(VPATH)}zjit.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
+builtin.$(OBJEXT): $(CCAN_DIR)/str/str.h
+builtin.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/array.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/box.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+builtin.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/ast.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/comments.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/integer.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/json.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/node.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/source.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/stream.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+builtin.$(OBJEXT): $(top_srcdir)/prism/version.h
+builtin.$(OBJEXT): {$(VPATH)}assert.h
+builtin.$(OBJEXT): {$(VPATH)}atomic.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+builtin.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+builtin.$(OBJEXT): {$(VPATH)}builtin.c
+builtin.$(OBJEXT): {$(VPATH)}builtin.h
+builtin.$(OBJEXT): {$(VPATH)}builtin_binary.rbbin
+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
+builtin.$(OBJEXT): {$(VPATH)}internal.h
+builtin.$(OBJEXT): {$(VPATH)}internal/abi.h
+builtin.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+builtin.$(OBJEXT): {$(VPATH)}internal/assume.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+builtin.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+builtin.$(OBJEXT): {$(VPATH)}internal/cast.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+builtin.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+builtin.$(OBJEXT): {$(VPATH)}internal/config.h
+builtin.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+builtin.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+builtin.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+builtin.$(OBJEXT): {$(VPATH)}internal/gc.h
+builtin.$(OBJEXT): {$(VPATH)}internal/glob.h
+builtin.$(OBJEXT): {$(VPATH)}internal/globals.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+builtin.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+builtin.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+builtin.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+builtin.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+builtin.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+builtin.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+builtin.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+builtin.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+builtin.$(OBJEXT): {$(VPATH)}internal/symbol.h
+builtin.$(OBJEXT): {$(VPATH)}internal/value.h
+builtin.$(OBJEXT): {$(VPATH)}internal/value_type.h
+builtin.$(OBJEXT): {$(VPATH)}internal/variable.h
+builtin.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+builtin.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+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_compile.h
+builtin.$(OBJEXT): {$(VPATH)}prism_xallocator.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
+builtin.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+builtin.$(OBJEXT): {$(VPATH)}thread_native.h
+builtin.$(OBJEXT): {$(VPATH)}vm_core.h
+builtin.$(OBJEXT): {$(VPATH)}vm_opts.h
+class.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+class.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+class.$(OBJEXT): $(CCAN_DIR)/list/list.h
+class.$(OBJEXT): $(CCAN_DIR)/str/str.h
+class.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+class.$(OBJEXT): $(top_srcdir)/internal/array.h
+class.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+class.$(OBJEXT): $(top_srcdir)/internal/box.h
+class.$(OBJEXT): $(top_srcdir)/internal/class.h
+class.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+class.$(OBJEXT): $(top_srcdir)/internal/eval.h
+class.$(OBJEXT): $(top_srcdir)/internal/gc.h
+class.$(OBJEXT): $(top_srcdir)/internal/hash.h
+class.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+class.$(OBJEXT): $(top_srcdir)/internal/object.h
+class.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+class.$(OBJEXT): $(top_srcdir)/internal/serial.h
+class.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+class.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+class.$(OBJEXT): $(top_srcdir)/internal/string.h
+class.$(OBJEXT): $(top_srcdir)/internal/struct.h
+class.$(OBJEXT): $(top_srcdir)/internal/variable.h
+class.$(OBJEXT): $(top_srcdir)/internal/vm.h
+class.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+class.$(OBJEXT): {$(VPATH)}assert.h
+class.$(OBJEXT): {$(VPATH)}atomic.h
+class.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+class.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+class.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+class.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+class.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+class.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+class.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+class.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+class.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+class.$(OBJEXT): {$(VPATH)}class.c
+class.$(OBJEXT): {$(VPATH)}config.h
+class.$(OBJEXT): {$(VPATH)}constant.h
+class.$(OBJEXT): {$(VPATH)}debug_counter.h
+class.$(OBJEXT): {$(VPATH)}defines.h
+class.$(OBJEXT): {$(VPATH)}encindex.h
+class.$(OBJEXT): {$(VPATH)}encoding.h
+class.$(OBJEXT): {$(VPATH)}id.h
+class.$(OBJEXT): {$(VPATH)}id_table.h
+class.$(OBJEXT): {$(VPATH)}intern.h
+class.$(OBJEXT): {$(VPATH)}internal.h
+class.$(OBJEXT): {$(VPATH)}internal/abi.h
+class.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+class.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+class.$(OBJEXT): {$(VPATH)}internal/assume.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+class.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+class.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+class.$(OBJEXT): {$(VPATH)}internal/cast.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+class.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+class.$(OBJEXT): {$(VPATH)}internal/config.h
+class.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+class.$(OBJEXT): {$(VPATH)}internal/core.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+class.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+class.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+class.$(OBJEXT): {$(VPATH)}internal/ctype.h
+class.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+class.$(OBJEXT): {$(VPATH)}internal/dosish.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+class.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+class.$(OBJEXT): {$(VPATH)}internal/error.h
+class.$(OBJEXT): {$(VPATH)}internal/eval.h
+class.$(OBJEXT): {$(VPATH)}internal/event.h
+class.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+class.$(OBJEXT): {$(VPATH)}internal/gc.h
+class.$(OBJEXT): {$(VPATH)}internal/glob.h
+class.$(OBJEXT): {$(VPATH)}internal/globals.h
+class.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+class.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+class.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+class.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+class.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+class.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+class.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+class.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+class.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+class.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+class.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+class.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+class.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+class.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+class.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+class.$(OBJEXT): {$(VPATH)}internal/symbol.h
+class.$(OBJEXT): {$(VPATH)}internal/value.h
+class.$(OBJEXT): {$(VPATH)}internal/value_type.h
+class.$(OBJEXT): {$(VPATH)}internal/variable.h
+class.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+class.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+class.$(OBJEXT): {$(VPATH)}method.h
+class.$(OBJEXT): {$(VPATH)}missing.h
+class.$(OBJEXT): {$(VPATH)}node.h
+class.$(OBJEXT): {$(VPATH)}onigmo.h
+class.$(OBJEXT): {$(VPATH)}oniguruma.h
+class.$(OBJEXT): {$(VPATH)}ractor.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
+class.$(OBJEXT): {$(VPATH)}yjit.h
+class.$(OBJEXT): {$(VPATH)}zjit.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
+compar.$(OBJEXT): $(top_srcdir)/internal/error.h
+compar.$(OBJEXT): $(top_srcdir)/internal/serial.h
+compar.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+compar.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+compar.$(OBJEXT): $(top_srcdir)/internal/string.h
+compar.$(OBJEXT): $(top_srcdir)/internal/vm.h
+compar.$(OBJEXT): {$(VPATH)}assert.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+compar.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+compar.$(OBJEXT): {$(VPATH)}compar.c
+compar.$(OBJEXT): {$(VPATH)}config.h
+compar.$(OBJEXT): {$(VPATH)}defines.h
+compar.$(OBJEXT): {$(VPATH)}encindex.h
+compar.$(OBJEXT): {$(VPATH)}encoding.h
+compar.$(OBJEXT): {$(VPATH)}id.h
+compar.$(OBJEXT): {$(VPATH)}intern.h
+compar.$(OBJEXT): {$(VPATH)}internal.h
+compar.$(OBJEXT): {$(VPATH)}internal/abi.h
+compar.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+compar.$(OBJEXT): {$(VPATH)}internal/assume.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+compar.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+compar.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+compar.$(OBJEXT): {$(VPATH)}internal/cast.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+compar.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+compar.$(OBJEXT): {$(VPATH)}internal/config.h
+compar.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+compar.$(OBJEXT): {$(VPATH)}internal/core.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+compar.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+compar.$(OBJEXT): {$(VPATH)}internal/ctype.h
+compar.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+compar.$(OBJEXT): {$(VPATH)}internal/dosish.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+compar.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+compar.$(OBJEXT): {$(VPATH)}internal/error.h
+compar.$(OBJEXT): {$(VPATH)}internal/eval.h
+compar.$(OBJEXT): {$(VPATH)}internal/event.h
+compar.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+compar.$(OBJEXT): {$(VPATH)}internal/gc.h
+compar.$(OBJEXT): {$(VPATH)}internal/glob.h
+compar.$(OBJEXT): {$(VPATH)}internal/globals.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+compar.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+compar.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+compar.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+compar.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+compar.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+compar.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+compar.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+compar.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+compar.$(OBJEXT): {$(VPATH)}internal/symbol.h
+compar.$(OBJEXT): {$(VPATH)}internal/value.h
+compar.$(OBJEXT): {$(VPATH)}internal/value_type.h
+compar.$(OBJEXT): {$(VPATH)}internal/variable.h
+compar.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+compar.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+compar.$(OBJEXT): {$(VPATH)}missing.h
+compar.$(OBJEXT): {$(VPATH)}onigmo.h
+compar.$(OBJEXT): {$(VPATH)}oniguruma.h
+compar.$(OBJEXT): {$(VPATH)}st.h
+compar.$(OBJEXT): {$(VPATH)}subst.h
+compile.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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
+compile.$(OBJEXT): $(top_srcdir)/internal/bits.h
+compile.$(OBJEXT): $(top_srcdir)/internal/box.h
+compile.$(OBJEXT): $(top_srcdir)/internal/class.h
+compile.$(OBJEXT): $(top_srcdir)/internal/compar.h
+compile.$(OBJEXT): $(top_srcdir)/internal/compile.h
+compile.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+compile.$(OBJEXT): $(top_srcdir)/internal/complex.h
+compile.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+compile.$(OBJEXT): $(top_srcdir)/internal/error.h
+compile.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+compile.$(OBJEXT): $(top_srcdir)/internal/gc.h
+compile.$(OBJEXT): $(top_srcdir)/internal/hash.h
+compile.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+compile.$(OBJEXT): $(top_srcdir)/internal/io.h
+compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+compile.$(OBJEXT): $(top_srcdir)/internal/object.h
+compile.$(OBJEXT): $(top_srcdir)/internal/parse.h
+compile.$(OBJEXT): $(top_srcdir)/internal/rational.h
+compile.$(OBJEXT): $(top_srcdir)/internal/re.h
+compile.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+compile.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+compile.$(OBJEXT): $(top_srcdir)/internal/serial.h
+compile.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+compile.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+compile.$(OBJEXT): $(top_srcdir)/internal/string.h
+compile.$(OBJEXT): $(top_srcdir)/internal/struct.h
+compile.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+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/arena.h
+compile.$(OBJEXT): $(top_srcdir)/prism/ast.h
+compile.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+compile.$(OBJEXT): $(top_srcdir)/prism/comments.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+compile.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+compile.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+compile.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+compile.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+compile.$(OBJEXT): $(top_srcdir)/prism/integer.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+compile.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+compile.$(OBJEXT): $(top_srcdir)/prism/json.h
+compile.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+compile.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+compile.$(OBJEXT): $(top_srcdir)/prism/node.h
+compile.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+compile.$(OBJEXT): $(top_srcdir)/prism/source.h
+compile.$(OBJEXT): $(top_srcdir)/prism/stream.h
+compile.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+compile.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+compile.$(OBJEXT): $(top_srcdir)/prism/version.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
+compile.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+compile.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+compile.$(OBJEXT): {$(VPATH)}builtin.h
+compile.$(OBJEXT): {$(VPATH)}compile.c
+compile.$(OBJEXT): {$(VPATH)}config.h
+compile.$(OBJEXT): {$(VPATH)}constant.h
+compile.$(OBJEXT): {$(VPATH)}debug_counter.h
+compile.$(OBJEXT): {$(VPATH)}defines.h
+compile.$(OBJEXT): {$(VPATH)}encindex.h
+compile.$(OBJEXT): {$(VPATH)}encoding.h
+compile.$(OBJEXT): {$(VPATH)}id.h
+compile.$(OBJEXT): {$(VPATH)}id_table.h
+compile.$(OBJEXT): {$(VPATH)}insns.def
+compile.$(OBJEXT): {$(VPATH)}insns.inc
+compile.$(OBJEXT): {$(VPATH)}insns_info.inc
+compile.$(OBJEXT): {$(VPATH)}intern.h
+compile.$(OBJEXT): {$(VPATH)}internal.h
+compile.$(OBJEXT): {$(VPATH)}internal/abi.h
+compile.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+compile.$(OBJEXT): {$(VPATH)}internal/assume.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+compile.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+compile.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+compile.$(OBJEXT): {$(VPATH)}internal/cast.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+compile.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+compile.$(OBJEXT): {$(VPATH)}internal/config.h
+compile.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+compile.$(OBJEXT): {$(VPATH)}internal/core.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+compile.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+compile.$(OBJEXT): {$(VPATH)}internal/ctype.h
+compile.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+compile.$(OBJEXT): {$(VPATH)}internal/dosish.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+compile.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+compile.$(OBJEXT): {$(VPATH)}internal/error.h
+compile.$(OBJEXT): {$(VPATH)}internal/eval.h
+compile.$(OBJEXT): {$(VPATH)}internal/event.h
+compile.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+compile.$(OBJEXT): {$(VPATH)}internal/gc.h
+compile.$(OBJEXT): {$(VPATH)}internal/glob.h
+compile.$(OBJEXT): {$(VPATH)}internal/globals.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+compile.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+compile.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+compile.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+compile.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+compile.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+compile.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+compile.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+compile.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+compile.$(OBJEXT): {$(VPATH)}internal/symbol.h
+compile.$(OBJEXT): {$(VPATH)}internal/value.h
+compile.$(OBJEXT): {$(VPATH)}internal/value_type.h
+compile.$(OBJEXT): {$(VPATH)}internal/variable.h
+compile.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+compile.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+compile.$(OBJEXT): {$(VPATH)}io.h
+compile.$(OBJEXT): {$(VPATH)}iseq.h
+compile.$(OBJEXT): {$(VPATH)}method.h
+compile.$(OBJEXT): {$(VPATH)}missing.h
+compile.$(OBJEXT): {$(VPATH)}node.h
+compile.$(OBJEXT): {$(VPATH)}onigmo.h
+compile.$(OBJEXT): {$(VPATH)}oniguruma.h
+compile.$(OBJEXT): {$(VPATH)}optinsn.inc
+compile.$(OBJEXT): {$(VPATH)}prism_compile.c
+compile.$(OBJEXT): {$(VPATH)}prism_compile.h
+compile.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+compile.$(OBJEXT): {$(VPATH)}ractor.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
+compile.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+compile.$(OBJEXT): {$(VPATH)}thread_native.h
+compile.$(OBJEXT): {$(VPATH)}util.h
+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/box.h
+complex.$(OBJEXT): $(top_srcdir)/internal/class.h
+complex.$(OBJEXT): $(top_srcdir)/internal/compar.h
+complex.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+complex.$(OBJEXT): $(top_srcdir)/internal/complex.h
+complex.$(OBJEXT): $(top_srcdir)/internal/error.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/sanitizers.h
+complex.$(OBJEXT): $(top_srcdir)/internal/serial.h
+complex.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+complex.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+complex.$(OBJEXT): $(top_srcdir)/internal/string.h
+complex.$(OBJEXT): $(top_srcdir)/internal/struct.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
+complex.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+complex.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+complex.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+complex.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+complex.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}encindex.h
+complex.$(OBJEXT): {$(VPATH)}encoding.h
+complex.$(OBJEXT): {$(VPATH)}id.h
+complex.$(OBJEXT): {$(VPATH)}id_table.h
+complex.$(OBJEXT): {$(VPATH)}intern.h
+complex.$(OBJEXT): {$(VPATH)}internal.h
+complex.$(OBJEXT): {$(VPATH)}internal/abi.h
+complex.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+complex.$(OBJEXT): {$(VPATH)}internal/assume.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+complex.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+complex.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+complex.$(OBJEXT): {$(VPATH)}internal/cast.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+complex.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+complex.$(OBJEXT): {$(VPATH)}internal/config.h
+complex.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+complex.$(OBJEXT): {$(VPATH)}internal/core.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+complex.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+complex.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+complex.$(OBJEXT): {$(VPATH)}internal/gc.h
+complex.$(OBJEXT): {$(VPATH)}internal/glob.h
+complex.$(OBJEXT): {$(VPATH)}internal/globals.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+complex.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+complex.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+complex.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+complex.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+complex.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+complex.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+complex.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+complex.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+complex.$(OBJEXT): {$(VPATH)}internal/symbol.h
+complex.$(OBJEXT): {$(VPATH)}internal/value.h
+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
+concurrent_set.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+concurrent_set.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+concurrent_set.$(OBJEXT): $(CCAN_DIR)/list/list.h
+concurrent_set.$(OBJEXT): $(CCAN_DIR)/str/str.h
+concurrent_set.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/array.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/box.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/concurrent_set.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/gc.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/serial.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/vm.h
+concurrent_set.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+concurrent_set.$(OBJEXT): {$(VPATH)}assert.h
+concurrent_set.$(OBJEXT): {$(VPATH)}atomic.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+concurrent_set.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+concurrent_set.$(OBJEXT): {$(VPATH)}concurrent_set.c
+concurrent_set.$(OBJEXT): {$(VPATH)}config.h
+concurrent_set.$(OBJEXT): {$(VPATH)}debug_counter.h
+concurrent_set.$(OBJEXT): {$(VPATH)}defines.h
+concurrent_set.$(OBJEXT): {$(VPATH)}encindex.h
+concurrent_set.$(OBJEXT): {$(VPATH)}encoding.h
+concurrent_set.$(OBJEXT): {$(VPATH)}id.h
+concurrent_set.$(OBJEXT): {$(VPATH)}id_table.h
+concurrent_set.$(OBJEXT): {$(VPATH)}intern.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/abi.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/assume.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/cast.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/config.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/ctype.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/dosish.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/error.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/eval.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/event.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/gc.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/glob.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/globals.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/iterator.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/memory.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/method.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/module.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/newobj.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/symbol.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/value.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/value_type.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/variable.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+concurrent_set.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+concurrent_set.$(OBJEXT): {$(VPATH)}method.h
+concurrent_set.$(OBJEXT): {$(VPATH)}missing.h
+concurrent_set.$(OBJEXT): {$(VPATH)}node.h
+concurrent_set.$(OBJEXT): {$(VPATH)}onigmo.h
+concurrent_set.$(OBJEXT): {$(VPATH)}oniguruma.h
+concurrent_set.$(OBJEXT): {$(VPATH)}ruby_assert.h
+concurrent_set.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+concurrent_set.$(OBJEXT): {$(VPATH)}rubyparser.h
+concurrent_set.$(OBJEXT): {$(VPATH)}st.h
+concurrent_set.$(OBJEXT): {$(VPATH)}subst.h
+concurrent_set.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+concurrent_set.$(OBJEXT): {$(VPATH)}thread_native.h
+concurrent_set.$(OBJEXT): {$(VPATH)}vm_core.h
+concurrent_set.$(OBJEXT): {$(VPATH)}vm_debug.h
+concurrent_set.$(OBJEXT): {$(VPATH)}vm_opts.h
+concurrent_set.$(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/box.h
+cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+cont.$(OBJEXT): $(top_srcdir)/internal/cont.h
+cont.$(OBJEXT): $(top_srcdir)/internal/error.h
+cont.$(OBJEXT): $(top_srcdir)/internal/eval.h
+cont.$(OBJEXT): $(top_srcdir)/internal/gc.h
+cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+cont.$(OBJEXT): $(top_srcdir)/internal/proc.h
+cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+cont.$(OBJEXT): $(top_srcdir)/internal/serial.h
+cont.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+cont.$(OBJEXT): $(top_srcdir)/internal/string.h
+cont.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+cont.$(OBJEXT): $(top_srcdir)/prism/ast.h
+cont.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+cont.$(OBJEXT): $(top_srcdir)/prism/comments.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+cont.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+cont.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+cont.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+cont.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+cont.$(OBJEXT): $(top_srcdir)/prism/integer.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+cont.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+cont.$(OBJEXT): $(top_srcdir)/prism/json.h
+cont.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+cont.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+cont.$(OBJEXT): $(top_srcdir)/prism/node.h
+cont.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+cont.$(OBJEXT): $(top_srcdir)/prism/source.h
+cont.$(OBJEXT): $(top_srcdir)/prism/stream.h
+cont.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+cont.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+cont.$(OBJEXT): $(top_srcdir)/prism/version.h
+cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
+cont.$(OBJEXT): {$(VPATH)}assert.h
+cont.$(OBJEXT): {$(VPATH)}atomic.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+cont.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+cont.$(OBJEXT): {$(VPATH)}config.h
+cont.$(OBJEXT): {$(VPATH)}constant.h
+cont.$(OBJEXT): {$(VPATH)}cont.c
+cont.$(OBJEXT): {$(VPATH)}debug_counter.h
+cont.$(OBJEXT): {$(VPATH)}defines.h
+cont.$(OBJEXT): {$(VPATH)}encindex.h
+cont.$(OBJEXT): {$(VPATH)}encoding.h
+cont.$(OBJEXT): {$(VPATH)}eval_intern.h
+cont.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+cont.$(OBJEXT): {$(VPATH)}id.h
+cont.$(OBJEXT): {$(VPATH)}id_table.h
+cont.$(OBJEXT): {$(VPATH)}intern.h
+cont.$(OBJEXT): {$(VPATH)}internal.h
+cont.$(OBJEXT): {$(VPATH)}internal/abi.h
+cont.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+cont.$(OBJEXT): {$(VPATH)}internal/assume.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+cont.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+cont.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+cont.$(OBJEXT): {$(VPATH)}internal/cast.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+cont.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+cont.$(OBJEXT): {$(VPATH)}internal/config.h
+cont.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+cont.$(OBJEXT): {$(VPATH)}internal/core.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+cont.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+cont.$(OBJEXT): {$(VPATH)}internal/ctype.h
+cont.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+cont.$(OBJEXT): {$(VPATH)}internal/dosish.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+cont.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+cont.$(OBJEXT): {$(VPATH)}internal/error.h
+cont.$(OBJEXT): {$(VPATH)}internal/eval.h
+cont.$(OBJEXT): {$(VPATH)}internal/event.h
+cont.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+cont.$(OBJEXT): {$(VPATH)}internal/gc.h
+cont.$(OBJEXT): {$(VPATH)}internal/glob.h
+cont.$(OBJEXT): {$(VPATH)}internal/globals.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+cont.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+cont.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+cont.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+cont.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+cont.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+cont.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+cont.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+cont.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+cont.$(OBJEXT): {$(VPATH)}internal/symbol.h
+cont.$(OBJEXT): {$(VPATH)}internal/value.h
+cont.$(OBJEXT): {$(VPATH)}internal/value_type.h
+cont.$(OBJEXT): {$(VPATH)}internal/variable.h
+cont.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+cont.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+cont.$(OBJEXT): {$(VPATH)}iseq.h
+cont.$(OBJEXT): {$(VPATH)}method.h
+cont.$(OBJEXT): {$(VPATH)}missing.h
+cont.$(OBJEXT): {$(VPATH)}node.h
+cont.$(OBJEXT): {$(VPATH)}onigmo.h
+cont.$(OBJEXT): {$(VPATH)}oniguruma.h
+cont.$(OBJEXT): {$(VPATH)}prism_compile.h
+cont.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+cont.$(OBJEXT): {$(VPATH)}ractor.h
+cont.$(OBJEXT): {$(VPATH)}ractor_core.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
+cont.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+cont.$(OBJEXT): {$(VPATH)}thread_native.h
+cont.$(OBJEXT): {$(VPATH)}vm_core.h
+cont.$(OBJEXT): {$(VPATH)}vm_debug.h
+cont.$(OBJEXT): {$(VPATH)}vm_opts.h
+cont.$(OBJEXT): {$(VPATH)}vm_sync.h
+cont.$(OBJEXT): {$(VPATH)}yjit.h
+cont.$(OBJEXT): {$(VPATH)}zjit.h
+debug.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+debug.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+debug.$(OBJEXT): $(CCAN_DIR)/list/list.h
+debug.$(OBJEXT): $(CCAN_DIR)/str/str.h
+debug.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+debug.$(OBJEXT): $(top_srcdir)/internal/array.h
+debug.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+debug.$(OBJEXT): $(top_srcdir)/internal/box.h
+debug.$(OBJEXT): $(top_srcdir)/internal/class.h
+debug.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+debug.$(OBJEXT): $(top_srcdir)/internal/gc.h
+debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+debug.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+debug.$(OBJEXT): $(top_srcdir)/internal/serial.h
+debug.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+debug.$(OBJEXT): $(top_srcdir)/internal/signal.h
+debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+debug.$(OBJEXT): $(top_srcdir)/internal/struct.h
+debug.$(OBJEXT): $(top_srcdir)/internal/variable.h
+debug.$(OBJEXT): $(top_srcdir)/internal/vm.h
+debug.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+debug.$(OBJEXT): {$(VPATH)}assert.h
+debug.$(OBJEXT): {$(VPATH)}atomic.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+debug.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+debug.$(OBJEXT): {$(VPATH)}config.h
+debug.$(OBJEXT): {$(VPATH)}constant.h
+debug.$(OBJEXT): {$(VPATH)}debug.c
+debug.$(OBJEXT): {$(VPATH)}debug_counter.h
+debug.$(OBJEXT): {$(VPATH)}defines.h
+debug.$(OBJEXT): {$(VPATH)}encindex.h
+debug.$(OBJEXT): {$(VPATH)}encoding.h
+debug.$(OBJEXT): {$(VPATH)}eval_intern.h
+debug.$(OBJEXT): {$(VPATH)}id.h
+debug.$(OBJEXT): {$(VPATH)}id_table.h
+debug.$(OBJEXT): {$(VPATH)}intern.h
+debug.$(OBJEXT): {$(VPATH)}internal.h
+debug.$(OBJEXT): {$(VPATH)}internal/abi.h
+debug.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+debug.$(OBJEXT): {$(VPATH)}internal/assume.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+debug.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+debug.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+debug.$(OBJEXT): {$(VPATH)}internal/cast.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+debug.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+debug.$(OBJEXT): {$(VPATH)}internal/config.h
+debug.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+debug.$(OBJEXT): {$(VPATH)}internal/core.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+debug.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+debug.$(OBJEXT): {$(VPATH)}internal/ctype.h
+debug.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+debug.$(OBJEXT): {$(VPATH)}internal/dosish.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+debug.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+debug.$(OBJEXT): {$(VPATH)}internal/error.h
+debug.$(OBJEXT): {$(VPATH)}internal/eval.h
+debug.$(OBJEXT): {$(VPATH)}internal/event.h
+debug.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+debug.$(OBJEXT): {$(VPATH)}internal/gc.h
+debug.$(OBJEXT): {$(VPATH)}internal/glob.h
+debug.$(OBJEXT): {$(VPATH)}internal/globals.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+debug.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+debug.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+debug.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+debug.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+debug.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+debug.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+debug.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+debug.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+debug.$(OBJEXT): {$(VPATH)}internal/symbol.h
+debug.$(OBJEXT): {$(VPATH)}internal/value.h
+debug.$(OBJEXT): {$(VPATH)}internal/value_type.h
+debug.$(OBJEXT): {$(VPATH)}internal/variable.h
+debug.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+debug.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+debug.$(OBJEXT): {$(VPATH)}io.h
+debug.$(OBJEXT): {$(VPATH)}method.h
+debug.$(OBJEXT): {$(VPATH)}missing.h
+debug.$(OBJEXT): {$(VPATH)}node.h
+debug.$(OBJEXT): {$(VPATH)}onigmo.h
+debug.$(OBJEXT): {$(VPATH)}oniguruma.h
+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
+debug.$(OBJEXT): {$(VPATH)}symbol.h
+debug.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+debug.$(OBJEXT): {$(VPATH)}thread_native.h
+debug.$(OBJEXT): {$(VPATH)}util.h
+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.$(OBJEXT): {$(VPATH)}zjit.h
+debug_counter.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+debug_counter.$(OBJEXT): {$(VPATH)}assert.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+debug_counter.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+debug_counter.$(OBJEXT): {$(VPATH)}config.h
+debug_counter.$(OBJEXT): {$(VPATH)}debug_counter.c
+debug_counter.$(OBJEXT): {$(VPATH)}debug_counter.h
+debug_counter.$(OBJEXT): {$(VPATH)}defines.h
+debug_counter.$(OBJEXT): {$(VPATH)}intern.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/abi.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/assume.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/cast.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/config.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/ctype.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/dosish.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/error.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/eval.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/event.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/gc.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/glob.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/globals.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/symbol.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/value.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/value_type.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/variable.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+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/box.h
+dir.$(OBJEXT): $(top_srcdir)/internal/class.h
+dir.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+dir.$(OBJEXT): $(top_srcdir)/internal/dir.h
+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/sanitizers.h
+dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
+dir.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+dir.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+dir.$(OBJEXT): $(top_srcdir)/internal/string.h
+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
+dir.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+dir.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+dir.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+dir.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+dir.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+dir.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+dir.$(OBJEXT): {$(VPATH)}builtin.h
+dir.$(OBJEXT): {$(VPATH)}config.h
+dir.$(OBJEXT): {$(VPATH)}constant.h
+dir.$(OBJEXT): {$(VPATH)}defines.h
+dir.$(OBJEXT): {$(VPATH)}dir.c
+dir.$(OBJEXT): {$(VPATH)}dir.rbinc
+dir.$(OBJEXT): {$(VPATH)}encindex.h
+dir.$(OBJEXT): {$(VPATH)}encoding.h
+dir.$(OBJEXT): {$(VPATH)}id.h
+dir.$(OBJEXT): {$(VPATH)}id_table.h
+dir.$(OBJEXT): {$(VPATH)}intern.h
+dir.$(OBJEXT): {$(VPATH)}internal.h
+dir.$(OBJEXT): {$(VPATH)}internal/abi.h
+dir.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+dir.$(OBJEXT): {$(VPATH)}internal/assume.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+dir.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+dir.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+dir.$(OBJEXT): {$(VPATH)}internal/cast.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+dir.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+dir.$(OBJEXT): {$(VPATH)}internal/config.h
+dir.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+dir.$(OBJEXT): {$(VPATH)}internal/core.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+dir.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+dir.$(OBJEXT): {$(VPATH)}internal/ctype.h
+dir.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+dir.$(OBJEXT): {$(VPATH)}internal/dosish.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+dir.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+dir.$(OBJEXT): {$(VPATH)}internal/error.h
+dir.$(OBJEXT): {$(VPATH)}internal/eval.h
+dir.$(OBJEXT): {$(VPATH)}internal/event.h
+dir.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+dir.$(OBJEXT): {$(VPATH)}internal/gc.h
+dir.$(OBJEXT): {$(VPATH)}internal/glob.h
+dir.$(OBJEXT): {$(VPATH)}internal/globals.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+dir.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+dir.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+dir.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+dir.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+dir.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+dir.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+dir.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+dir.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+dir.$(OBJEXT): {$(VPATH)}internal/symbol.h
+dir.$(OBJEXT): {$(VPATH)}internal/value.h
+dir.$(OBJEXT): {$(VPATH)}internal/value_type.h
+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/box.h
+dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+dln.$(OBJEXT): {$(VPATH)}assert.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+dln.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+dln.$(OBJEXT): {$(VPATH)}config.h
+dln.$(OBJEXT): {$(VPATH)}defines.h
+dln.$(OBJEXT): {$(VPATH)}dln.c
+dln.$(OBJEXT): {$(VPATH)}dln.h
+dln.$(OBJEXT): {$(VPATH)}intern.h
+dln.$(OBJEXT): {$(VPATH)}internal.h
+dln.$(OBJEXT): {$(VPATH)}internal/abi.h
+dln.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+dln.$(OBJEXT): {$(VPATH)}internal/assume.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+dln.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+dln.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+dln.$(OBJEXT): {$(VPATH)}internal/cast.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+dln.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+dln.$(OBJEXT): {$(VPATH)}internal/config.h
+dln.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+dln.$(OBJEXT): {$(VPATH)}internal/core.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+dln.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+dln.$(OBJEXT): {$(VPATH)}internal/ctype.h
+dln.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+dln.$(OBJEXT): {$(VPATH)}internal/dosish.h
+dln.$(OBJEXT): {$(VPATH)}internal/error.h
+dln.$(OBJEXT): {$(VPATH)}internal/eval.h
+dln.$(OBJEXT): {$(VPATH)}internal/event.h
+dln.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+dln.$(OBJEXT): {$(VPATH)}internal/gc.h
+dln.$(OBJEXT): {$(VPATH)}internal/glob.h
+dln.$(OBJEXT): {$(VPATH)}internal/globals.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+dln.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+dln.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+dln.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+dln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+dln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+dln.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+dln.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+dln.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+dln.$(OBJEXT): {$(VPATH)}internal/symbol.h
+dln.$(OBJEXT): {$(VPATH)}internal/value.h
+dln.$(OBJEXT): {$(VPATH)}internal/value_type.h
+dln.$(OBJEXT): {$(VPATH)}internal/variable.h
+dln.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+dln.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+dln.$(OBJEXT): {$(VPATH)}missing.h
+dln.$(OBJEXT): {$(VPATH)}st.h
+dln.$(OBJEXT): {$(VPATH)}subst.h
+dln_find.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+dln_find.$(OBJEXT): {$(VPATH)}assert.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+dln_find.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+dln_find.$(OBJEXT): {$(VPATH)}config.h
+dln_find.$(OBJEXT): {$(VPATH)}defines.h
+dln_find.$(OBJEXT): {$(VPATH)}dln.h
+dln_find.$(OBJEXT): {$(VPATH)}dln_find.c
+dln_find.$(OBJEXT): {$(VPATH)}intern.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/abi.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/assume.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/cast.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/config.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/ctype.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/dosish.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/error.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/eval.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/event.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/gc.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/glob.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/globals.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/symbol.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/value.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/value_type.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/variable.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+dln_find.$(OBJEXT): {$(VPATH)}missing.h
+dln_find.$(OBJEXT): {$(VPATH)}st.h
+dln_find.$(OBJEXT): {$(VPATH)}subst.h
+dmydln.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+dmydln.$(OBJEXT): {$(VPATH)}assert.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+dmydln.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+dmydln.$(OBJEXT): {$(VPATH)}config.h
+dmydln.$(OBJEXT): {$(VPATH)}defines.h
+dmydln.$(OBJEXT): {$(VPATH)}dmydln.c
+dmydln.$(OBJEXT): {$(VPATH)}intern.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/abi.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/assume.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/cast.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/config.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/ctype.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/dosish.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/error.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/eval.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/event.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/gc.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/glob.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/globals.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/symbol.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/value.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/value_type.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/variable.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+dmydln.$(OBJEXT): {$(VPATH)}missing.h
+dmydln.$(OBJEXT): {$(VPATH)}st.h
+dmydln.$(OBJEXT): {$(VPATH)}subst.h
+dmyenc.$(OBJEXT): {$(VPATH)}dmyenc.c
+dmyext.$(OBJEXT): {$(VPATH)}dmyext.c
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/arena.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/ast.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/comments.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/integer.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/json.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/node.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/options.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/parser.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/prism.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/source.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/stream.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/prism/version.h
+dump_ast-dump_ast.$(OBJEXT): $(top_srcdir)/tool/dump_ast.c
+enc/ascii.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+enc/ascii.$(OBJEXT): {$(VPATH)}assert.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+enc/ascii.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+enc/ascii.$(OBJEXT): {$(VPATH)}config.h
+enc/ascii.$(OBJEXT): {$(VPATH)}defines.h
+enc/ascii.$(OBJEXT): {$(VPATH)}enc/ascii.c
+enc/ascii.$(OBJEXT): {$(VPATH)}encindex.h
+enc/ascii.$(OBJEXT): {$(VPATH)}encoding.h
+enc/ascii.$(OBJEXT): {$(VPATH)}intern.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/assume.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/cast.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/config.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/error.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/eval.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/event.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/gc.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/glob.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/globals.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/value.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/value_type.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/variable.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+enc/ascii.$(OBJEXT): {$(VPATH)}missing.h
+enc/ascii.$(OBJEXT): {$(VPATH)}onigmo.h
+enc/ascii.$(OBJEXT): {$(VPATH)}oniguruma.h
+enc/ascii.$(OBJEXT): {$(VPATH)}regenc.h
+enc/ascii.$(OBJEXT): {$(VPATH)}st.h
+enc/ascii.$(OBJEXT): {$(VPATH)}subst.h
+enc/trans/newline.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}assert.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}config.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}defines.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}enc/trans/newline.c
+enc/trans/newline.$(OBJEXT): {$(VPATH)}intern.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/assume.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/cast.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/config.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/error.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/eval.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/event.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/gc.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/glob.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/globals.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/value.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/value_type.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/variable.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}missing.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}st.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}subst.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}transcode_data.h
+enc/unicode.$(OBJEXT): $(UNICODE_HDR_DIR)/casefold.h
+enc/unicode.$(OBJEXT): $(UNICODE_HDR_DIR)/name2ctype.h
+enc/unicode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+enc/unicode.$(OBJEXT): {$(VPATH)}assert.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+enc/unicode.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+enc/unicode.$(OBJEXT): {$(VPATH)}config.h
+enc/unicode.$(OBJEXT): {$(VPATH)}defines.h
+enc/unicode.$(OBJEXT): {$(VPATH)}enc/unicode.c
+enc/unicode.$(OBJEXT): {$(VPATH)}intern.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/assume.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/cast.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/config.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/error.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/eval.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/event.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/gc.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/glob.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/globals.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/value.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/value_type.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/variable.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+enc/unicode.$(OBJEXT): {$(VPATH)}missing.h
+enc/unicode.$(OBJEXT): {$(VPATH)}onigmo.h
+enc/unicode.$(OBJEXT): {$(VPATH)}regenc.h
+enc/unicode.$(OBJEXT): {$(VPATH)}regint.h
+enc/unicode.$(OBJEXT): {$(VPATH)}st.h
+enc/unicode.$(OBJEXT): {$(VPATH)}subst.h
+enc/us_ascii.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}assert.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}config.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}defines.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}enc/us_ascii.c
+enc/us_ascii.$(OBJEXT): {$(VPATH)}encindex.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}encoding.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}intern.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/assume.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/cast.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/config.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/error.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/eval.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/event.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/gc.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/glob.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/globals.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/value.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/value_type.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/variable.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}missing.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}onigmo.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}oniguruma.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}regenc.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}st.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}subst.h
+enc/utf_8.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}assert.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}config.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}defines.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}enc/utf_8.c
+enc/utf_8.$(OBJEXT): {$(VPATH)}encindex.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}encoding.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}intern.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/assume.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/cast.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/config.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/error.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/eval.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/event.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/gc.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/glob.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/globals.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/value.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/value_type.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/variable.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}missing.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}onigmo.h
+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
+encoding.$(OBJEXT): $(top_srcdir)/internal/serial.h
+encoding.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+encoding.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+encoding.$(OBJEXT): $(top_srcdir)/internal/string.h
+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
+encoding.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+encoding.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+encoding.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+encoding.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+encoding.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+encoding.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+encoding.$(OBJEXT): {$(VPATH)}config.h
+encoding.$(OBJEXT): {$(VPATH)}constant.h
+encoding.$(OBJEXT): {$(VPATH)}debug_counter.h
+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
+encoding.$(OBJEXT): {$(VPATH)}internal/abi.h
+encoding.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+encoding.$(OBJEXT): {$(VPATH)}internal/assume.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+encoding.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+encoding.$(OBJEXT): {$(VPATH)}internal/cast.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+encoding.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+encoding.$(OBJEXT): {$(VPATH)}internal/config.h
+encoding.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+encoding.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+encoding.$(OBJEXT): {$(VPATH)}internal/ctype.h
+encoding.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+encoding.$(OBJEXT): {$(VPATH)}internal/dosish.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+encoding.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+encoding.$(OBJEXT): {$(VPATH)}internal/error.h
+encoding.$(OBJEXT): {$(VPATH)}internal/eval.h
+encoding.$(OBJEXT): {$(VPATH)}internal/event.h
+encoding.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+encoding.$(OBJEXT): {$(VPATH)}internal/gc.h
+encoding.$(OBJEXT): {$(VPATH)}internal/glob.h
+encoding.$(OBJEXT): {$(VPATH)}internal/globals.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+encoding.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+encoding.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+encoding.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+encoding.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+encoding.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+encoding.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+encoding.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+encoding.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+encoding.$(OBJEXT): {$(VPATH)}internal/symbol.h
+encoding.$(OBJEXT): {$(VPATH)}internal/value.h
+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)}ractor.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
+enum.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+enum.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+enum.$(OBJEXT): $(top_srcdir)/internal/bits.h
+enum.$(OBJEXT): $(top_srcdir)/internal/class.h
+enum.$(OBJEXT): $(top_srcdir)/internal/compar.h
+enum.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+enum.$(OBJEXT): $(top_srcdir)/internal/enum.h
+enum.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+enum.$(OBJEXT): $(top_srcdir)/internal/gc.h
+enum.$(OBJEXT): $(top_srcdir)/internal/hash.h
+enum.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+enum.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+enum.$(OBJEXT): $(top_srcdir)/internal/object.h
+enum.$(OBJEXT): $(top_srcdir)/internal/proc.h
+enum.$(OBJEXT): $(top_srcdir)/internal/rational.h
+enum.$(OBJEXT): $(top_srcdir)/internal/re.h
+enum.$(OBJEXT): $(top_srcdir)/internal/serial.h
+enum.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+enum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+enum.$(OBJEXT): $(top_srcdir)/internal/variable.h
+enum.$(OBJEXT): $(top_srcdir)/internal/vm.h
+enum.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+enum.$(OBJEXT): {$(VPATH)}assert.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+enum.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+enum.$(OBJEXT): {$(VPATH)}config.h
+enum.$(OBJEXT): {$(VPATH)}constant.h
+enum.$(OBJEXT): {$(VPATH)}defines.h
+enum.$(OBJEXT): {$(VPATH)}encoding.h
+enum.$(OBJEXT): {$(VPATH)}enum.c
+enum.$(OBJEXT): {$(VPATH)}id.h
+enum.$(OBJEXT): {$(VPATH)}id_table.h
+enum.$(OBJEXT): {$(VPATH)}intern.h
+enum.$(OBJEXT): {$(VPATH)}internal.h
+enum.$(OBJEXT): {$(VPATH)}internal/abi.h
+enum.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enum.$(OBJEXT): {$(VPATH)}internal/assume.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+enum.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enum.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enum.$(OBJEXT): {$(VPATH)}internal/cast.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enum.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enum.$(OBJEXT): {$(VPATH)}internal/config.h
+enum.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enum.$(OBJEXT): {$(VPATH)}internal/core.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enum.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enum.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enum.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enum.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+enum.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+enum.$(OBJEXT): {$(VPATH)}internal/error.h
+enum.$(OBJEXT): {$(VPATH)}internal/eval.h
+enum.$(OBJEXT): {$(VPATH)}internal/event.h
+enum.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enum.$(OBJEXT): {$(VPATH)}internal/gc.h
+enum.$(OBJEXT): {$(VPATH)}internal/glob.h
+enum.$(OBJEXT): {$(VPATH)}internal/globals.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enum.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enum.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enum.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enum.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enum.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enum.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+enum.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enum.$(OBJEXT): {$(VPATH)}internal/value.h
+enum.$(OBJEXT): {$(VPATH)}internal/value_type.h
+enum.$(OBJEXT): {$(VPATH)}internal/variable.h
+enum.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+enum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+enum.$(OBJEXT): {$(VPATH)}missing.h
+enum.$(OBJEXT): {$(VPATH)}onigmo.h
+enum.$(OBJEXT): {$(VPATH)}oniguruma.h
+enum.$(OBJEXT): {$(VPATH)}re.h
+enum.$(OBJEXT): {$(VPATH)}regex.h
+enum.$(OBJEXT): {$(VPATH)}ruby_assert.h
+enum.$(OBJEXT): {$(VPATH)}shape.h
+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/box.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/class.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/compar.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/error.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/gc.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/hash.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/range.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/rational.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/serial.h
+enumerator.$(OBJEXT): $(top_srcdir)/internal/set_table.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
+enumerator.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+enumerator.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+enumerator.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+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)}encindex.h
+enumerator.$(OBJEXT): {$(VPATH)}encoding.h
+enumerator.$(OBJEXT): {$(VPATH)}enumerator.c
+enumerator.$(OBJEXT): {$(VPATH)}id.h
+enumerator.$(OBJEXT): {$(VPATH)}id_table.h
+enumerator.$(OBJEXT): {$(VPATH)}intern.h
+enumerator.$(OBJEXT): {$(VPATH)}internal.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/abi.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/assume.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/cast.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/config.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/ctype.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/dosish.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/error.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/eval.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/event.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/gc.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/glob.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/globals.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/symbol.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/value.h
+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/box.h
+error.$(OBJEXT): $(top_srcdir)/internal/class.h
+error.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+error.$(OBJEXT): $(top_srcdir)/internal/error.h
+error.$(OBJEXT): $(top_srcdir)/internal/eval.h
+error.$(OBJEXT): $(top_srcdir)/internal/gc.h
+error.$(OBJEXT): $(top_srcdir)/internal/hash.h
+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/sanitizers.h
+error.$(OBJEXT): $(top_srcdir)/internal/serial.h
+error.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+error.$(OBJEXT): $(top_srcdir)/internal/string.h
+error.$(OBJEXT): $(top_srcdir)/internal/struct.h
+error.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+error.$(OBJEXT): $(top_srcdir)/internal/thread.h
+error.$(OBJEXT): $(top_srcdir)/internal/variable.h
+error.$(OBJEXT): $(top_srcdir)/internal/vm.h
+error.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+error.$(OBJEXT): {$(VPATH)}assert.h
+error.$(OBJEXT): {$(VPATH)}atomic.h
+error.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+error.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+error.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+error.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+error.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+error.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+error.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+error.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+error.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+error.$(OBJEXT): {$(VPATH)}builtin.h
+error.$(OBJEXT): {$(VPATH)}config.h
+error.$(OBJEXT): {$(VPATH)}constant.h
+error.$(OBJEXT): {$(VPATH)}debug_counter.h
+error.$(OBJEXT): {$(VPATH)}defines.h
+error.$(OBJEXT): {$(VPATH)}encindex.h
+error.$(OBJEXT): {$(VPATH)}encoding.h
+error.$(OBJEXT): {$(VPATH)}error.c
+error.$(OBJEXT): {$(VPATH)}id.h
+error.$(OBJEXT): {$(VPATH)}id_table.h
+error.$(OBJEXT): {$(VPATH)}intern.h
+error.$(OBJEXT): {$(VPATH)}internal.h
+error.$(OBJEXT): {$(VPATH)}internal/abi.h
+error.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+error.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+error.$(OBJEXT): {$(VPATH)}internal/assume.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+error.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+error.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+error.$(OBJEXT): {$(VPATH)}internal/cast.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+error.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+error.$(OBJEXT): {$(VPATH)}internal/config.h
+error.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+error.$(OBJEXT): {$(VPATH)}internal/core.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+error.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+error.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+error.$(OBJEXT): {$(VPATH)}internal/ctype.h
+error.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+error.$(OBJEXT): {$(VPATH)}internal/dosish.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+error.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+error.$(OBJEXT): {$(VPATH)}internal/error.h
+error.$(OBJEXT): {$(VPATH)}internal/eval.h
+error.$(OBJEXT): {$(VPATH)}internal/event.h
+error.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+error.$(OBJEXT): {$(VPATH)}internal/gc.h
+error.$(OBJEXT): {$(VPATH)}internal/glob.h
+error.$(OBJEXT): {$(VPATH)}internal/globals.h
+error.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+error.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+error.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+error.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+error.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+error.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+error.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+error.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+error.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+error.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+error.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+error.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+error.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+error.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+error.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+error.$(OBJEXT): {$(VPATH)}internal/symbol.h
+error.$(OBJEXT): {$(VPATH)}internal/value.h
+error.$(OBJEXT): {$(VPATH)}internal/value_type.h
+error.$(OBJEXT): {$(VPATH)}internal/variable.h
+error.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+error.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+error.$(OBJEXT): {$(VPATH)}io.h
+error.$(OBJEXT): {$(VPATH)}known_errors.inc
+error.$(OBJEXT): {$(VPATH)}method.h
+error.$(OBJEXT): {$(VPATH)}missing.h
+error.$(OBJEXT): {$(VPATH)}node.h
+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_debug.h
+error.$(OBJEXT): {$(VPATH)}vm_opts.h
+error.$(OBJEXT): {$(VPATH)}vm_sync.h
+error.$(OBJEXT): {$(VPATH)}warning.rbinc
+error.$(OBJEXT): {$(VPATH)}yjit.h
+error.$(OBJEXT): {$(VPATH)}zjit.h
+eval.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+eval.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+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/box.h
+eval.$(OBJEXT): $(top_srcdir)/internal/class.h
+eval.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+eval.$(OBJEXT): $(top_srcdir)/internal/cont.h
+eval.$(OBJEXT): $(top_srcdir)/internal/error.h
+eval.$(OBJEXT): $(top_srcdir)/internal/eval.h
+eval.$(OBJEXT): $(top_srcdir)/internal/gc.h
+eval.$(OBJEXT): $(top_srcdir)/internal/hash.h
+eval.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+eval.$(OBJEXT): $(top_srcdir)/internal/inits.h
+eval.$(OBJEXT): $(top_srcdir)/internal/io.h
+eval.$(OBJEXT): $(top_srcdir)/internal/object.h
+eval.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+eval.$(OBJEXT): $(top_srcdir)/internal/serial.h
+eval.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+eval.$(OBJEXT): $(top_srcdir)/internal/string.h
+eval.$(OBJEXT): $(top_srcdir)/internal/struct.h
+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/arena.h
+eval.$(OBJEXT): $(top_srcdir)/prism/ast.h
+eval.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+eval.$(OBJEXT): $(top_srcdir)/prism/comments.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+eval.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+eval.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+eval.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+eval.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+eval.$(OBJEXT): $(top_srcdir)/prism/integer.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+eval.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+eval.$(OBJEXT): $(top_srcdir)/prism/json.h
+eval.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+eval.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+eval.$(OBJEXT): $(top_srcdir)/prism/node.h
+eval.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+eval.$(OBJEXT): $(top_srcdir)/prism/source.h
+eval.$(OBJEXT): $(top_srcdir)/prism/stream.h
+eval.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+eval.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+eval.$(OBJEXT): $(top_srcdir)/prism/version.h
+eval.$(OBJEXT): {$(VPATH)}assert.h
+eval.$(OBJEXT): {$(VPATH)}atomic.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+eval.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+eval.$(OBJEXT): {$(VPATH)}config.h
+eval.$(OBJEXT): {$(VPATH)}constant.h
+eval.$(OBJEXT): {$(VPATH)}debug_counter.h
+eval.$(OBJEXT): {$(VPATH)}defines.h
+eval.$(OBJEXT): {$(VPATH)}encindex.h
+eval.$(OBJEXT): {$(VPATH)}encoding.h
+eval.$(OBJEXT): {$(VPATH)}eval.c
+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)}id.h
+eval.$(OBJEXT): {$(VPATH)}id_table.h
+eval.$(OBJEXT): {$(VPATH)}intern.h
+eval.$(OBJEXT): {$(VPATH)}internal.h
+eval.$(OBJEXT): {$(VPATH)}internal/abi.h
+eval.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+eval.$(OBJEXT): {$(VPATH)}internal/assume.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+eval.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+eval.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+eval.$(OBJEXT): {$(VPATH)}internal/cast.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+eval.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+eval.$(OBJEXT): {$(VPATH)}internal/config.h
+eval.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+eval.$(OBJEXT): {$(VPATH)}internal/core.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+eval.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+eval.$(OBJEXT): {$(VPATH)}internal/ctype.h
+eval.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+eval.$(OBJEXT): {$(VPATH)}internal/dosish.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+eval.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+eval.$(OBJEXT): {$(VPATH)}internal/error.h
+eval.$(OBJEXT): {$(VPATH)}internal/eval.h
+eval.$(OBJEXT): {$(VPATH)}internal/event.h
+eval.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+eval.$(OBJEXT): {$(VPATH)}internal/gc.h
+eval.$(OBJEXT): {$(VPATH)}internal/glob.h
+eval.$(OBJEXT): {$(VPATH)}internal/globals.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+eval.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+eval.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+eval.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+eval.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+eval.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+eval.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+eval.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+eval.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+eval.$(OBJEXT): {$(VPATH)}internal/symbol.h
+eval.$(OBJEXT): {$(VPATH)}internal/value.h
+eval.$(OBJEXT): {$(VPATH)}internal/value_type.h
+eval.$(OBJEXT): {$(VPATH)}internal/variable.h
+eval.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+eval.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+eval.$(OBJEXT): {$(VPATH)}io.h
+eval.$(OBJEXT): {$(VPATH)}iseq.h
+eval.$(OBJEXT): {$(VPATH)}method.h
+eval.$(OBJEXT): {$(VPATH)}missing.h
+eval.$(OBJEXT): {$(VPATH)}node.h
+eval.$(OBJEXT): {$(VPATH)}onigmo.h
+eval.$(OBJEXT): {$(VPATH)}oniguruma.h
+eval.$(OBJEXT): {$(VPATH)}prism_compile.h
+eval.$(OBJEXT): {$(VPATH)}prism_xallocator.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)}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
+eval.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+eval.$(OBJEXT): {$(VPATH)}thread_native.h
+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
+eval.$(OBJEXT): {$(VPATH)}zjit.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}config.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}explicit_bzero.c
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+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
+file.$(OBJEXT): $(top_srcdir)/internal/dir.h
+file.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+file.$(OBJEXT): $(top_srcdir)/internal/error.h
+file.$(OBJEXT): $(top_srcdir)/internal/file.h
+file.$(OBJEXT): $(top_srcdir)/internal/gc.h
+file.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+file.$(OBJEXT): $(top_srcdir)/internal/io.h
+file.$(OBJEXT): $(top_srcdir)/internal/load.h
+file.$(OBJEXT): $(top_srcdir)/internal/object.h
+file.$(OBJEXT): $(top_srcdir)/internal/process.h
+file.$(OBJEXT): $(top_srcdir)/internal/serial.h
+file.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+file.$(OBJEXT): $(top_srcdir)/internal/string.h
+file.$(OBJEXT): $(top_srcdir)/internal/thread.h
+file.$(OBJEXT): $(top_srcdir)/internal/variable.h
+file.$(OBJEXT): $(top_srcdir)/internal/vm.h
+file.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+file.$(OBJEXT): {$(VPATH)}assert.h
+file.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+file.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+file.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+file.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+file.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+file.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+file.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+file.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+file.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+file.$(OBJEXT): {$(VPATH)}config.h
+file.$(OBJEXT): {$(VPATH)}constant.h
+file.$(OBJEXT): {$(VPATH)}defines.h
+file.$(OBJEXT): {$(VPATH)}dln.h
+file.$(OBJEXT): {$(VPATH)}encindex.h
+file.$(OBJEXT): {$(VPATH)}encoding.h
+file.$(OBJEXT): {$(VPATH)}file.c
+file.$(OBJEXT): {$(VPATH)}id.h
+file.$(OBJEXT): {$(VPATH)}id_table.h
+file.$(OBJEXT): {$(VPATH)}intern.h
+file.$(OBJEXT): {$(VPATH)}internal.h
+file.$(OBJEXT): {$(VPATH)}internal/abi.h
+file.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+file.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+file.$(OBJEXT): {$(VPATH)}internal/assume.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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/nonstring.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
+file.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+file.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+file.$(OBJEXT): {$(VPATH)}internal/cast.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+file.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+file.$(OBJEXT): {$(VPATH)}internal/config.h
+file.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+file.$(OBJEXT): {$(VPATH)}internal/core.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+file.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+file.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+file.$(OBJEXT): {$(VPATH)}internal/ctype.h
+file.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+file.$(OBJEXT): {$(VPATH)}internal/dosish.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+file.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+file.$(OBJEXT): {$(VPATH)}internal/error.h
+file.$(OBJEXT): {$(VPATH)}internal/eval.h
+file.$(OBJEXT): {$(VPATH)}internal/event.h
+file.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+file.$(OBJEXT): {$(VPATH)}internal/gc.h
+file.$(OBJEXT): {$(VPATH)}internal/glob.h
+file.$(OBJEXT): {$(VPATH)}internal/globals.h
+file.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+file.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+file.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+file.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+file.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+file.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+file.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+file.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+file.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+file.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+file.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+file.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+file.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+file.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+file.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+file.$(OBJEXT): {$(VPATH)}internal/symbol.h
+file.$(OBJEXT): {$(VPATH)}internal/value.h
+file.$(OBJEXT): {$(VPATH)}internal/value_type.h
+file.$(OBJEXT): {$(VPATH)}internal/variable.h
+file.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+file.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+file.$(OBJEXT): {$(VPATH)}io.h
+file.$(OBJEXT): {$(VPATH)}missing.h
+file.$(OBJEXT): {$(VPATH)}onigmo.h
+file.$(OBJEXT): {$(VPATH)}oniguruma.h
+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
+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)/gc/default/default.c
+gc.$(OBJEXT): $(top_srcdir)/gc/gc.h
+gc.$(OBJEXT): $(top_srcdir)/gc/gc_impl.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/box.h
+gc.$(OBJEXT): $(top_srcdir)/internal/class.h
+gc.$(OBJEXT): $(top_srcdir)/internal/compar.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/concurrent_set.h
+gc.$(OBJEXT): $(top_srcdir)/internal/cont.h
+gc.$(OBJEXT): $(top_srcdir)/internal/error.h
+gc.$(OBJEXT): $(top_srcdir)/internal/eval.h
+gc.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+gc.$(OBJEXT): $(top_srcdir)/internal/gc.h
+gc.$(OBJEXT): $(top_srcdir)/internal/hash.h
+gc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+gc.$(OBJEXT): $(top_srcdir)/internal/io.h
+gc.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+gc.$(OBJEXT): $(top_srcdir)/internal/object.h
+gc.$(OBJEXT): $(top_srcdir)/internal/proc.h
+gc.$(OBJEXT): $(top_srcdir)/internal/rational.h
+gc.$(OBJEXT): $(top_srcdir)/internal/re.h
+gc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+gc.$(OBJEXT): $(top_srcdir)/internal/serial.h
+gc.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+gc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+gc.$(OBJEXT): $(top_srcdir)/internal/string.h
+gc.$(OBJEXT): $(top_srcdir)/internal/struct.h
+gc.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+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/arena.h
+gc.$(OBJEXT): $(top_srcdir)/prism/ast.h
+gc.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+gc.$(OBJEXT): $(top_srcdir)/prism/comments.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+gc.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+gc.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+gc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+gc.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+gc.$(OBJEXT): $(top_srcdir)/prism/integer.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+gc.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+gc.$(OBJEXT): $(top_srcdir)/prism/json.h
+gc.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+gc.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+gc.$(OBJEXT): $(top_srcdir)/prism/node.h
+gc.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+gc.$(OBJEXT): $(top_srcdir)/prism/source.h
+gc.$(OBJEXT): $(top_srcdir)/prism/stream.h
+gc.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+gc.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+gc.$(OBJEXT): $(top_srcdir)/prism/version.h
+gc.$(OBJEXT): {$(VPATH)}assert.h
+gc.$(OBJEXT): {$(VPATH)}atomic.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+gc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}encindex.h
+gc.$(OBJEXT): {$(VPATH)}encoding.h
+gc.$(OBJEXT): {$(VPATH)}eval_intern.h
+gc.$(OBJEXT): {$(VPATH)}gc.c
+gc.$(OBJEXT): {$(VPATH)}gc.rbinc
+gc.$(OBJEXT): {$(VPATH)}id.h
+gc.$(OBJEXT): {$(VPATH)}id_table.h
+gc.$(OBJEXT): {$(VPATH)}intern.h
+gc.$(OBJEXT): {$(VPATH)}internal.h
+gc.$(OBJEXT): {$(VPATH)}internal/abi.h
+gc.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+gc.$(OBJEXT): {$(VPATH)}internal/assume.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+gc.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+gc.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+gc.$(OBJEXT): {$(VPATH)}internal/cast.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+gc.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+gc.$(OBJEXT): {$(VPATH)}internal/config.h
+gc.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+gc.$(OBJEXT): {$(VPATH)}internal/core.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+gc.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+gc.$(OBJEXT): {$(VPATH)}internal/ctype.h
+gc.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+gc.$(OBJEXT): {$(VPATH)}internal/dosish.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+gc.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+gc.$(OBJEXT): {$(VPATH)}internal/error.h
+gc.$(OBJEXT): {$(VPATH)}internal/eval.h
+gc.$(OBJEXT): {$(VPATH)}internal/event.h
+gc.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+gc.$(OBJEXT): {$(VPATH)}internal/gc.h
+gc.$(OBJEXT): {$(VPATH)}internal/glob.h
+gc.$(OBJEXT): {$(VPATH)}internal/globals.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+gc.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+gc.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+gc.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+gc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+gc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+gc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+gc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+gc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+gc.$(OBJEXT): {$(VPATH)}internal/symbol.h
+gc.$(OBJEXT): {$(VPATH)}internal/value.h
+gc.$(OBJEXT): {$(VPATH)}internal/value_type.h
+gc.$(OBJEXT): {$(VPATH)}internal/variable.h
+gc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+gc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+gc.$(OBJEXT): {$(VPATH)}io.h
+gc.$(OBJEXT): {$(VPATH)}iseq.h
+gc.$(OBJEXT): {$(VPATH)}method.h
+gc.$(OBJEXT): {$(VPATH)}missing.h
+gc.$(OBJEXT): {$(VPATH)}node.h
+gc.$(OBJEXT): {$(VPATH)}onigmo.h
+gc.$(OBJEXT): {$(VPATH)}oniguruma.h
+gc.$(OBJEXT): {$(VPATH)}prism_compile.h
+gc.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+gc.$(OBJEXT): {$(VPATH)}probes.dmyh
+gc.$(OBJEXT): {$(VPATH)}probes.h
+gc.$(OBJEXT): {$(VPATH)}ractor.h
+gc.$(OBJEXT): {$(VPATH)}ractor_core.h
+gc.$(OBJEXT): {$(VPATH)}re.h
+gc.$(OBJEXT): {$(VPATH)}regenc.h
+gc.$(OBJEXT): {$(VPATH)}regex.h
+gc.$(OBJEXT): {$(VPATH)}regint.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
+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)}util.h
+gc.$(OBJEXT): {$(VPATH)}variable.h
+gc.$(OBJEXT): {$(VPATH)}vm.h
+gc.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+gc.$(OBJEXT): {$(VPATH)}vm_core.h
+gc.$(OBJEXT): {$(VPATH)}vm_debug.h
+gc.$(OBJEXT): {$(VPATH)}vm_opts.h
+gc.$(OBJEXT): {$(VPATH)}vm_sync.h
+gc.$(OBJEXT): {$(VPATH)}yjit.h
+gc.$(OBJEXT): {$(VPATH)}zjit.h
+goruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+goruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+goruby.$(OBJEXT): $(CCAN_DIR)/list/list.h
+goruby.$(OBJEXT): $(CCAN_DIR)/str/str.h
+goruby.$(OBJEXT): $(hdrdir)/ruby.h
+goruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/array.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/bits.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/box.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/set_table.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/arena.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/ast.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/integer.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/node.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/options.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/stringy.h
+goruby.$(OBJEXT): $(top_srcdir)/prism/version.h
+goruby.$(OBJEXT): {$(VPATH)}assert.h
+goruby.$(OBJEXT): {$(VPATH)}atomic.h
+goruby.$(OBJEXT): {$(VPATH)}backward.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+goruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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.rbbin
+goruby.$(OBJEXT): {$(VPATH)}goruby.c
+goruby.$(OBJEXT): {$(VPATH)}id.h
+goruby.$(OBJEXT): {$(VPATH)}id_table.h
+goruby.$(OBJEXT): {$(VPATH)}intern.h
+goruby.$(OBJEXT): {$(VPATH)}internal.h
+goruby.$(OBJEXT): {$(VPATH)}internal/abi.h
+goruby.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+goruby.$(OBJEXT): {$(VPATH)}internal/assume.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/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
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+goruby.$(OBJEXT): {$(VPATH)}internal/cast.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+goruby.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+goruby.$(OBJEXT): {$(VPATH)}internal/config.h
+goruby.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+goruby.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+goruby.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+goruby.$(OBJEXT): {$(VPATH)}internal/gc.h
+goruby.$(OBJEXT): {$(VPATH)}internal/glob.h
+goruby.$(OBJEXT): {$(VPATH)}internal/globals.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+goruby.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+goruby.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+goruby.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+goruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+goruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+goruby.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+goruby.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+goruby.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+goruby.$(OBJEXT): {$(VPATH)}internal/symbol.h
+goruby.$(OBJEXT): {$(VPATH)}internal/value.h
+goruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
+goruby.$(OBJEXT): {$(VPATH)}internal/variable.h
+goruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+goruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+goruby.$(OBJEXT): {$(VPATH)}iseq.h
+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_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
+goruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+goruby.$(OBJEXT): {$(VPATH)}thread_native.h
+goruby.$(OBJEXT): {$(VPATH)}vm_core.h
+goruby.$(OBJEXT): {$(VPATH)}vm_debug.h
+goruby.$(OBJEXT): {$(VPATH)}vm_opts.h
+hash.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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
+hash.$(OBJEXT): $(top_srcdir)/internal/bits.h
+hash.$(OBJEXT): $(top_srcdir)/internal/box.h
+hash.$(OBJEXT): $(top_srcdir)/internal/class.h
+hash.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+hash.$(OBJEXT): $(top_srcdir)/internal/cont.h
+hash.$(OBJEXT): $(top_srcdir)/internal/error.h
+hash.$(OBJEXT): $(top_srcdir)/internal/gc.h
+hash.$(OBJEXT): $(top_srcdir)/internal/hash.h
+hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+hash.$(OBJEXT): $(top_srcdir)/internal/object.h
+hash.$(OBJEXT): $(top_srcdir)/internal/proc.h
+hash.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+hash.$(OBJEXT): $(top_srcdir)/internal/serial.h
+hash.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+hash.$(OBJEXT): $(top_srcdir)/internal/st.h
+hash.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+hash.$(OBJEXT): $(top_srcdir)/internal/string.h
+hash.$(OBJEXT): $(top_srcdir)/internal/struct.h
+hash.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+hash.$(OBJEXT): $(top_srcdir)/internal/thread.h
+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/arena.h
+hash.$(OBJEXT): $(top_srcdir)/prism/ast.h
+hash.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+hash.$(OBJEXT): $(top_srcdir)/prism/comments.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+hash.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+hash.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+hash.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+hash.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+hash.$(OBJEXT): $(top_srcdir)/prism/integer.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+hash.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+hash.$(OBJEXT): $(top_srcdir)/prism/json.h
+hash.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+hash.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+hash.$(OBJEXT): $(top_srcdir)/prism/node.h
+hash.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+hash.$(OBJEXT): $(top_srcdir)/prism/source.h
+hash.$(OBJEXT): $(top_srcdir)/prism/stream.h
+hash.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+hash.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+hash.$(OBJEXT): $(top_srcdir)/prism/version.h
+hash.$(OBJEXT): {$(VPATH)}assert.h
+hash.$(OBJEXT): {$(VPATH)}atomic.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+hash.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+hash.$(OBJEXT): {$(VPATH)}builtin.h
+hash.$(OBJEXT): {$(VPATH)}config.h
+hash.$(OBJEXT): {$(VPATH)}constant.h
+hash.$(OBJEXT): {$(VPATH)}debug_counter.h
+hash.$(OBJEXT): {$(VPATH)}defines.h
+hash.$(OBJEXT): {$(VPATH)}encindex.h
+hash.$(OBJEXT): {$(VPATH)}encoding.h
+hash.$(OBJEXT): {$(VPATH)}hash.c
+hash.$(OBJEXT): {$(VPATH)}hash.rbinc
+hash.$(OBJEXT): {$(VPATH)}id.h
+hash.$(OBJEXT): {$(VPATH)}id_table.h
+hash.$(OBJEXT): {$(VPATH)}intern.h
+hash.$(OBJEXT): {$(VPATH)}internal.h
+hash.$(OBJEXT): {$(VPATH)}internal/abi.h
+hash.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+hash.$(OBJEXT): {$(VPATH)}internal/assume.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+hash.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+hash.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+hash.$(OBJEXT): {$(VPATH)}internal/cast.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+hash.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+hash.$(OBJEXT): {$(VPATH)}internal/config.h
+hash.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+hash.$(OBJEXT): {$(VPATH)}internal/core.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+hash.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+hash.$(OBJEXT): {$(VPATH)}internal/ctype.h
+hash.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+hash.$(OBJEXT): {$(VPATH)}internal/dosish.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+hash.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+hash.$(OBJEXT): {$(VPATH)}internal/error.h
+hash.$(OBJEXT): {$(VPATH)}internal/eval.h
+hash.$(OBJEXT): {$(VPATH)}internal/event.h
+hash.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+hash.$(OBJEXT): {$(VPATH)}internal/gc.h
+hash.$(OBJEXT): {$(VPATH)}internal/glob.h
+hash.$(OBJEXT): {$(VPATH)}internal/globals.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+hash.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+hash.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+hash.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+hash.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+hash.$(OBJEXT): {$(VPATH)}internal/st.h
+hash.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+hash.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+hash.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+hash.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+hash.$(OBJEXT): {$(VPATH)}internal/symbol.h
+hash.$(OBJEXT): {$(VPATH)}internal/value.h
+hash.$(OBJEXT): {$(VPATH)}internal/value_type.h
+hash.$(OBJEXT): {$(VPATH)}internal/variable.h
+hash.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+hash.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+hash.$(OBJEXT): {$(VPATH)}iseq.h
+hash.$(OBJEXT): {$(VPATH)}method.h
+hash.$(OBJEXT): {$(VPATH)}missing.h
+hash.$(OBJEXT): {$(VPATH)}node.h
+hash.$(OBJEXT): {$(VPATH)}onigmo.h
+hash.$(OBJEXT): {$(VPATH)}oniguruma.h
+hash.$(OBJEXT): {$(VPATH)}prism_compile.h
+hash.$(OBJEXT): {$(VPATH)}prism_xallocator.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)}util.h
+hash.$(OBJEXT): {$(VPATH)}variable.h
+hash.$(OBJEXT): {$(VPATH)}vm_core.h
+hash.$(OBJEXT): {$(VPATH)}vm_debug.h
+hash.$(OBJEXT): {$(VPATH)}vm_opts.h
+hash.$(OBJEXT): {$(VPATH)}vm_sync.h
+imemo.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+imemo.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+imemo.$(OBJEXT): $(CCAN_DIR)/list/list.h
+imemo.$(OBJEXT): $(CCAN_DIR)/str/str.h
+imemo.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/array.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/box.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/class.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/gc.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/object.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/serial.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/st.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/struct.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/variable.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/vm.h
+imemo.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+imemo.$(OBJEXT): {$(VPATH)}assert.h
+imemo.$(OBJEXT): {$(VPATH)}atomic.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+imemo.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+imemo.$(OBJEXT): {$(VPATH)}config.h
+imemo.$(OBJEXT): {$(VPATH)}constant.h
+imemo.$(OBJEXT): {$(VPATH)}debug_counter.h
+imemo.$(OBJEXT): {$(VPATH)}defines.h
+imemo.$(OBJEXT): {$(VPATH)}encoding.h
+imemo.$(OBJEXT): {$(VPATH)}id.h
+imemo.$(OBJEXT): {$(VPATH)}id_table.h
+imemo.$(OBJEXT): {$(VPATH)}imemo.c
+imemo.$(OBJEXT): {$(VPATH)}intern.h
+imemo.$(OBJEXT): {$(VPATH)}internal.h
+imemo.$(OBJEXT): {$(VPATH)}internal/abi.h
+imemo.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+imemo.$(OBJEXT): {$(VPATH)}internal/assume.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+imemo.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+imemo.$(OBJEXT): {$(VPATH)}internal/cast.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+imemo.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+imemo.$(OBJEXT): {$(VPATH)}internal/config.h
+imemo.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+imemo.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+imemo.$(OBJEXT): {$(VPATH)}internal/ctype.h
+imemo.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+imemo.$(OBJEXT): {$(VPATH)}internal/dosish.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+imemo.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+imemo.$(OBJEXT): {$(VPATH)}internal/error.h
+imemo.$(OBJEXT): {$(VPATH)}internal/eval.h
+imemo.$(OBJEXT): {$(VPATH)}internal/event.h
+imemo.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+imemo.$(OBJEXT): {$(VPATH)}internal/gc.h
+imemo.$(OBJEXT): {$(VPATH)}internal/glob.h
+imemo.$(OBJEXT): {$(VPATH)}internal/globals.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+imemo.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+imemo.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+imemo.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+imemo.$(OBJEXT): {$(VPATH)}internal/iterator.h
+imemo.$(OBJEXT): {$(VPATH)}internal/memory.h
+imemo.$(OBJEXT): {$(VPATH)}internal/method.h
+imemo.$(OBJEXT): {$(VPATH)}internal/module.h
+imemo.$(OBJEXT): {$(VPATH)}internal/newobj.h
+imemo.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+imemo.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+imemo.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+imemo.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+imemo.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+imemo.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+imemo.$(OBJEXT): {$(VPATH)}internal/symbol.h
+imemo.$(OBJEXT): {$(VPATH)}internal/value.h
+imemo.$(OBJEXT): {$(VPATH)}internal/value_type.h
+imemo.$(OBJEXT): {$(VPATH)}internal/variable.h
+imemo.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+imemo.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+imemo.$(OBJEXT): {$(VPATH)}method.h
+imemo.$(OBJEXT): {$(VPATH)}missing.h
+imemo.$(OBJEXT): {$(VPATH)}node.h
+imemo.$(OBJEXT): {$(VPATH)}onigmo.h
+imemo.$(OBJEXT): {$(VPATH)}oniguruma.h
+imemo.$(OBJEXT): {$(VPATH)}ruby_assert.h
+imemo.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+imemo.$(OBJEXT): {$(VPATH)}rubyparser.h
+imemo.$(OBJEXT): {$(VPATH)}shape.h
+imemo.$(OBJEXT): {$(VPATH)}st.h
+imemo.$(OBJEXT): {$(VPATH)}subst.h
+imemo.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+imemo.$(OBJEXT): {$(VPATH)}thread_native.h
+imemo.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+imemo.$(OBJEXT): {$(VPATH)}vm_core.h
+imemo.$(OBJEXT): {$(VPATH)}vm_debug.h
+imemo.$(OBJEXT): {$(VPATH)}vm_opts.h
+imemo.$(OBJEXT): {$(VPATH)}vm_sync.h
+inits.$(OBJEXT): $(hdrdir)/ruby.h
+inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+inits.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+inits.$(OBJEXT): $(top_srcdir)/internal/inits.h
+inits.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+inits.$(OBJEXT): {$(VPATH)}assert.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+inits.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+inits.$(OBJEXT): {$(VPATH)}builtin.h
+inits.$(OBJEXT): {$(VPATH)}config.h
+inits.$(OBJEXT): {$(VPATH)}defines.h
+inits.$(OBJEXT): {$(VPATH)}inits.c
+inits.$(OBJEXT): {$(VPATH)}intern.h
+inits.$(OBJEXT): {$(VPATH)}internal/abi.h
+inits.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+inits.$(OBJEXT): {$(VPATH)}internal/assume.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+inits.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+inits.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+inits.$(OBJEXT): {$(VPATH)}internal/cast.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+inits.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+inits.$(OBJEXT): {$(VPATH)}internal/config.h
+inits.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+inits.$(OBJEXT): {$(VPATH)}internal/core.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+inits.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+inits.$(OBJEXT): {$(VPATH)}internal/ctype.h
+inits.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+inits.$(OBJEXT): {$(VPATH)}internal/dosish.h
+inits.$(OBJEXT): {$(VPATH)}internal/error.h
+inits.$(OBJEXT): {$(VPATH)}internal/eval.h
+inits.$(OBJEXT): {$(VPATH)}internal/event.h
+inits.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+inits.$(OBJEXT): {$(VPATH)}internal/gc.h
+inits.$(OBJEXT): {$(VPATH)}internal/glob.h
+inits.$(OBJEXT): {$(VPATH)}internal/globals.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+inits.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+inits.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+inits.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+inits.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+inits.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+inits.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+inits.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+inits.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+inits.$(OBJEXT): {$(VPATH)}internal/symbol.h
+inits.$(OBJEXT): {$(VPATH)}internal/value.h
+inits.$(OBJEXT): {$(VPATH)}internal/value_type.h
+inits.$(OBJEXT): {$(VPATH)}internal/variable.h
+inits.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+inits.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+inits.$(OBJEXT): {$(VPATH)}missing.h
+inits.$(OBJEXT): {$(VPATH)}prelude.rbinc
+inits.$(OBJEXT): {$(VPATH)}st.h
+inits.$(OBJEXT): {$(VPATH)}subst.h
+io.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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
+io.$(OBJEXT): $(top_srcdir)/internal/bits.h
+io.$(OBJEXT): $(top_srcdir)/internal/box.h
+io.$(OBJEXT): $(top_srcdir)/internal/class.h
+io.$(OBJEXT): $(top_srcdir)/internal/compar.h
+io.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+io.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+io.$(OBJEXT): $(top_srcdir)/internal/error.h
+io.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+io.$(OBJEXT): $(top_srcdir)/internal/gc.h
+io.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+io.$(OBJEXT): $(top_srcdir)/internal/inits.h
+io.$(OBJEXT): $(top_srcdir)/internal/io.h
+io.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+io.$(OBJEXT): $(top_srcdir)/internal/object.h
+io.$(OBJEXT): $(top_srcdir)/internal/process.h
+io.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+io.$(OBJEXT): $(top_srcdir)/internal/serial.h
+io.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+io.$(OBJEXT): $(top_srcdir)/internal/string.h
+io.$(OBJEXT): $(top_srcdir)/internal/struct.h
+io.$(OBJEXT): $(top_srcdir)/internal/thread.h
+io.$(OBJEXT): $(top_srcdir)/internal/transcode.h
+io.$(OBJEXT): $(top_srcdir)/internal/variable.h
+io.$(OBJEXT): $(top_srcdir)/internal/vm.h
+io.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+io.$(OBJEXT): {$(VPATH)}assert.h
+io.$(OBJEXT): {$(VPATH)}atomic.h
+io.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+io.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+io.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+io.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+io.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+io.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+io.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+io.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+io.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+io.$(OBJEXT): {$(VPATH)}builtin.h
+io.$(OBJEXT): {$(VPATH)}config.h
+io.$(OBJEXT): {$(VPATH)}constant.h
+io.$(OBJEXT): {$(VPATH)}debug_counter.h
+io.$(OBJEXT): {$(VPATH)}defines.h
+io.$(OBJEXT): {$(VPATH)}dln.h
+io.$(OBJEXT): {$(VPATH)}encindex.h
+io.$(OBJEXT): {$(VPATH)}encoding.h
+io.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+io.$(OBJEXT): {$(VPATH)}id.h
+io.$(OBJEXT): {$(VPATH)}id_table.h
+io.$(OBJEXT): {$(VPATH)}intern.h
+io.$(OBJEXT): {$(VPATH)}internal.h
+io.$(OBJEXT): {$(VPATH)}internal/abi.h
+io.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+io.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+io.$(OBJEXT): {$(VPATH)}internal/assume.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+io.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+io.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+io.$(OBJEXT): {$(VPATH)}internal/cast.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+io.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+io.$(OBJEXT): {$(VPATH)}internal/config.h
+io.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+io.$(OBJEXT): {$(VPATH)}internal/core.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+io.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+io.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+io.$(OBJEXT): {$(VPATH)}internal/ctype.h
+io.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+io.$(OBJEXT): {$(VPATH)}internal/dosish.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+io.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+io.$(OBJEXT): {$(VPATH)}internal/error.h
+io.$(OBJEXT): {$(VPATH)}internal/eval.h
+io.$(OBJEXT): {$(VPATH)}internal/event.h
+io.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+io.$(OBJEXT): {$(VPATH)}internal/gc.h
+io.$(OBJEXT): {$(VPATH)}internal/glob.h
+io.$(OBJEXT): {$(VPATH)}internal/globals.h
+io.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+io.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+io.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+io.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+io.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+io.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+io.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+io.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+io.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+io.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+io.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+io.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+io.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+io.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+io.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+io.$(OBJEXT): {$(VPATH)}internal/symbol.h
+io.$(OBJEXT): {$(VPATH)}internal/value.h
+io.$(OBJEXT): {$(VPATH)}internal/value_type.h
+io.$(OBJEXT): {$(VPATH)}internal/variable.h
+io.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+io.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+io.$(OBJEXT): {$(VPATH)}io.c
+io.$(OBJEXT): {$(VPATH)}io.h
+io.$(OBJEXT): {$(VPATH)}io.rbinc
+io.$(OBJEXT): {$(VPATH)}io/buffer.h
+io.$(OBJEXT): {$(VPATH)}method.h
+io.$(OBJEXT): {$(VPATH)}missing.h
+io.$(OBJEXT): {$(VPATH)}node.h
+io.$(OBJEXT): {$(VPATH)}onigmo.h
+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
+io.$(OBJEXT): {$(VPATH)}thread.h
+io.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+io.$(OBJEXT): {$(VPATH)}thread_native.h
+io.$(OBJEXT): {$(VPATH)}util.h
+io.$(OBJEXT): {$(VPATH)}vm_core.h
+io.$(OBJEXT): {$(VPATH)}vm_debug.h
+io.$(OBJEXT): {$(VPATH)}vm_opts.h
+io.$(OBJEXT): {$(VPATH)}vm_sync.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/basic_operators.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/box.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/compar.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/error.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/gc.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/io.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/serial.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/string.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/thread.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/vm.h
+io_buffer.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+io_buffer.$(OBJEXT): {$(VPATH)}assert.h
+io_buffer.$(OBJEXT): {$(VPATH)}atomic.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+io_buffer.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+io_buffer.$(OBJEXT): {$(VPATH)}config.h
+io_buffer.$(OBJEXT): {$(VPATH)}defines.h
+io_buffer.$(OBJEXT): {$(VPATH)}encindex.h
+io_buffer.$(OBJEXT): {$(VPATH)}encoding.h
+io_buffer.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+io_buffer.$(OBJEXT): {$(VPATH)}id.h
+io_buffer.$(OBJEXT): {$(VPATH)}id_table.h
+io_buffer.$(OBJEXT): {$(VPATH)}intern.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/abi.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/assume.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/cast.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/config.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/ctype.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/dosish.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/error.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/eval.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/event.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/gc.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/glob.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/globals.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/symbol.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/value.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/value_type.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/variable.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+io_buffer.$(OBJEXT): {$(VPATH)}io.h
+io_buffer.$(OBJEXT): {$(VPATH)}io/buffer.h
+io_buffer.$(OBJEXT): {$(VPATH)}io_buffer.c
+io_buffer.$(OBJEXT): {$(VPATH)}method.h
+io_buffer.$(OBJEXT): {$(VPATH)}missing.h
+io_buffer.$(OBJEXT): {$(VPATH)}node.h
+io_buffer.$(OBJEXT): {$(VPATH)}onigmo.h
+io_buffer.$(OBJEXT): {$(VPATH)}oniguruma.h
+io_buffer.$(OBJEXT): {$(VPATH)}ruby_assert.h
+io_buffer.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+io_buffer.$(OBJEXT): {$(VPATH)}rubyparser.h
+io_buffer.$(OBJEXT): {$(VPATH)}st.h
+io_buffer.$(OBJEXT): {$(VPATH)}subst.h
+io_buffer.$(OBJEXT): {$(VPATH)}thread.h
+io_buffer.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+io_buffer.$(OBJEXT): {$(VPATH)}thread_native.h
+io_buffer.$(OBJEXT): {$(VPATH)}vm_core.h
+io_buffer.$(OBJEXT): {$(VPATH)}vm_opts.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/bignum.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/bits.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/box.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/class.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/compar.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/compile.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/complex.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/error.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/file.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+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/io.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/rational.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/set_table.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/string.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/struct.h
+iseq.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+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/arena.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/ast.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/comments.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/integer.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/json.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/node.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/source.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/stream.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+iseq.$(OBJEXT): $(top_srcdir)/prism/version.h
+iseq.$(OBJEXT): {$(VPATH)}assert.h
+iseq.$(OBJEXT): {$(VPATH)}atomic.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+iseq.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+iseq.$(OBJEXT): {$(VPATH)}builtin.h
+iseq.$(OBJEXT): {$(VPATH)}config.h
+iseq.$(OBJEXT): {$(VPATH)}constant.h
+iseq.$(OBJEXT): {$(VPATH)}debug_counter.h
+iseq.$(OBJEXT): {$(VPATH)}defines.h
+iseq.$(OBJEXT): {$(VPATH)}encindex.h
+iseq.$(OBJEXT): {$(VPATH)}encoding.h
+iseq.$(OBJEXT): {$(VPATH)}eval_intern.h
+iseq.$(OBJEXT): {$(VPATH)}id.h
+iseq.$(OBJEXT): {$(VPATH)}id_table.h
+iseq.$(OBJEXT): {$(VPATH)}insns.def
+iseq.$(OBJEXT): {$(VPATH)}insns.inc
+iseq.$(OBJEXT): {$(VPATH)}insns_info.inc
+iseq.$(OBJEXT): {$(VPATH)}intern.h
+iseq.$(OBJEXT): {$(VPATH)}internal.h
+iseq.$(OBJEXT): {$(VPATH)}internal/abi.h
+iseq.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+iseq.$(OBJEXT): {$(VPATH)}internal/assume.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+iseq.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+iseq.$(OBJEXT): {$(VPATH)}internal/cast.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+iseq.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+iseq.$(OBJEXT): {$(VPATH)}internal/config.h
+iseq.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+iseq.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+iseq.$(OBJEXT): {$(VPATH)}internal/ctype.h
+iseq.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+iseq.$(OBJEXT): {$(VPATH)}internal/dosish.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+iseq.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+iseq.$(OBJEXT): {$(VPATH)}internal/error.h
+iseq.$(OBJEXT): {$(VPATH)}internal/eval.h
+iseq.$(OBJEXT): {$(VPATH)}internal/event.h
+iseq.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+iseq.$(OBJEXT): {$(VPATH)}internal/gc.h
+iseq.$(OBJEXT): {$(VPATH)}internal/glob.h
+iseq.$(OBJEXT): {$(VPATH)}internal/globals.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+iseq.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+iseq.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+iseq.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+iseq.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+iseq.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+iseq.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+iseq.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+iseq.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+iseq.$(OBJEXT): {$(VPATH)}internal/symbol.h
+iseq.$(OBJEXT): {$(VPATH)}internal/value.h
+iseq.$(OBJEXT): {$(VPATH)}internal/value_type.h
+iseq.$(OBJEXT): {$(VPATH)}internal/variable.h
+iseq.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+iseq.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+iseq.$(OBJEXT): {$(VPATH)}io.h
+iseq.$(OBJEXT): {$(VPATH)}iseq.c
+iseq.$(OBJEXT): {$(VPATH)}iseq.h
+iseq.$(OBJEXT): {$(VPATH)}method.h
+iseq.$(OBJEXT): {$(VPATH)}missing.h
+iseq.$(OBJEXT): {$(VPATH)}node.h
+iseq.$(OBJEXT): {$(VPATH)}onigmo.h
+iseq.$(OBJEXT): {$(VPATH)}oniguruma.h
+iseq.$(OBJEXT): {$(VPATH)}prism_compile.h
+iseq.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+iseq.$(OBJEXT): {$(VPATH)}ractor.h
+iseq.$(OBJEXT): {$(VPATH)}ractor_core.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
+iseq.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+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
+iseq.$(OBJEXT): {$(VPATH)}zjit.h
+jit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+jit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+jit.$(OBJEXT): $(CCAN_DIR)/list/list.h
+jit.$(OBJEXT): $(CCAN_DIR)/str/str.h
+jit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+jit.$(OBJEXT): $(top_srcdir)/internal/array.h
+jit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+jit.$(OBJEXT): $(top_srcdir)/internal/bits.h
+jit.$(OBJEXT): $(top_srcdir)/internal/box.h
+jit.$(OBJEXT): $(top_srcdir)/internal/class.h
+jit.$(OBJEXT): $(top_srcdir)/internal/compile.h
+jit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+jit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+jit.$(OBJEXT): $(top_srcdir)/internal/gc.h
+jit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+jit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+jit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+jit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+jit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+jit.$(OBJEXT): $(top_srcdir)/internal/string.h
+jit.$(OBJEXT): $(top_srcdir)/internal/struct.h
+jit.$(OBJEXT): $(top_srcdir)/internal/variable.h
+jit.$(OBJEXT): $(top_srcdir)/internal/vm.h
+jit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+jit.$(OBJEXT): $(top_srcdir)/prism/arena.h
+jit.$(OBJEXT): $(top_srcdir)/prism/ast.h
+jit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+jit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+jit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+jit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+jit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+jit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+jit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+jit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+jit.$(OBJEXT): $(top_srcdir)/prism/json.h
+jit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+jit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+jit.$(OBJEXT): $(top_srcdir)/prism/node.h
+jit.$(OBJEXT): $(top_srcdir)/prism/options.h
+jit.$(OBJEXT): $(top_srcdir)/prism/parser.h
+jit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+jit.$(OBJEXT): $(top_srcdir)/prism/prism.h
+jit.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+jit.$(OBJEXT): $(top_srcdir)/prism/source.h
+jit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+jit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+jit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+jit.$(OBJEXT): $(top_srcdir)/prism/version.h
+jit.$(OBJEXT): {$(VPATH)}assert.h
+jit.$(OBJEXT): {$(VPATH)}atomic.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+jit.$(OBJEXT): {$(VPATH)}builtin.h
+jit.$(OBJEXT): {$(VPATH)}config.h
+jit.$(OBJEXT): {$(VPATH)}constant.h
+jit.$(OBJEXT): {$(VPATH)}debug_counter.h
+jit.$(OBJEXT): {$(VPATH)}defines.h
+jit.$(OBJEXT): {$(VPATH)}encindex.h
+jit.$(OBJEXT): {$(VPATH)}encoding.h
+jit.$(OBJEXT): {$(VPATH)}id.h
+jit.$(OBJEXT): {$(VPATH)}id_table.h
+jit.$(OBJEXT): {$(VPATH)}insns.def
+jit.$(OBJEXT): {$(VPATH)}insns.inc
+jit.$(OBJEXT): {$(VPATH)}insns_info.inc
+jit.$(OBJEXT): {$(VPATH)}intern.h
+jit.$(OBJEXT): {$(VPATH)}internal.h
+jit.$(OBJEXT): {$(VPATH)}internal/abi.h
+jit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/assume.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+jit.$(OBJEXT): {$(VPATH)}internal/cast.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+jit.$(OBJEXT): {$(VPATH)}internal/config.h
+jit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+jit.$(OBJEXT): {$(VPATH)}internal/core.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+jit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+jit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+jit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+jit.$(OBJEXT): {$(VPATH)}internal/error.h
+jit.$(OBJEXT): {$(VPATH)}internal/eval.h
+jit.$(OBJEXT): {$(VPATH)}internal/event.h
+jit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+jit.$(OBJEXT): {$(VPATH)}internal/gc.h
+jit.$(OBJEXT): {$(VPATH)}internal/glob.h
+jit.$(OBJEXT): {$(VPATH)}internal/globals.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+jit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+jit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+jit.$(OBJEXT): {$(VPATH)}internal/memory.h
+jit.$(OBJEXT): {$(VPATH)}internal/method.h
+jit.$(OBJEXT): {$(VPATH)}internal/module.h
+jit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+jit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+jit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+jit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+jit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+jit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+jit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+jit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+jit.$(OBJEXT): {$(VPATH)}internal/value.h
+jit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+jit.$(OBJEXT): {$(VPATH)}internal/variable.h
+jit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+jit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+jit.$(OBJEXT): {$(VPATH)}iseq.h
+jit.$(OBJEXT): {$(VPATH)}jit.c
+jit.$(OBJEXT): {$(VPATH)}method.h
+jit.$(OBJEXT): {$(VPATH)}missing.h
+jit.$(OBJEXT): {$(VPATH)}node.h
+jit.$(OBJEXT): {$(VPATH)}onigmo.h
+jit.$(OBJEXT): {$(VPATH)}oniguruma.h
+jit.$(OBJEXT): {$(VPATH)}prism_compile.h
+jit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+jit.$(OBJEXT): {$(VPATH)}ruby_assert.h
+jit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+jit.$(OBJEXT): {$(VPATH)}rubyparser.h
+jit.$(OBJEXT): {$(VPATH)}shape.h
+jit.$(OBJEXT): {$(VPATH)}st.h
+jit.$(OBJEXT): {$(VPATH)}subst.h
+jit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+jit.$(OBJEXT): {$(VPATH)}thread_native.h
+jit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+jit.$(OBJEXT): {$(VPATH)}vm_core.h
+jit.$(OBJEXT): {$(VPATH)}vm_debug.h
+jit.$(OBJEXT): {$(VPATH)}vm_opts.h
+jit.$(OBJEXT): {$(VPATH)}vm_sync.h
+jit.$(OBJEXT): {$(VPATH)}zjit.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/bignum.h
+load.$(OBJEXT): $(top_srcdir)/internal/bits.h
+load.$(OBJEXT): $(top_srcdir)/internal/box.h
+load.$(OBJEXT): $(top_srcdir)/internal/compar.h
+load.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+load.$(OBJEXT): $(top_srcdir)/internal/complex.h
+load.$(OBJEXT): $(top_srcdir)/internal/dir.h
+load.$(OBJEXT): $(top_srcdir)/internal/error.h
+load.$(OBJEXT): $(top_srcdir)/internal/eval.h
+load.$(OBJEXT): $(top_srcdir)/internal/file.h
+load.$(OBJEXT): $(top_srcdir)/internal/fixnum.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/numeric.h
+load.$(OBJEXT): $(top_srcdir)/internal/parse.h
+load.$(OBJEXT): $(top_srcdir)/internal/rational.h
+load.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+load.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+load.$(OBJEXT): $(top_srcdir)/internal/serial.h
+load.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+load.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+load.$(OBJEXT): $(top_srcdir)/internal/string.h
+load.$(OBJEXT): $(top_srcdir)/internal/struct.h
+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/arena.h
+load.$(OBJEXT): $(top_srcdir)/prism/ast.h
+load.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+load.$(OBJEXT): $(top_srcdir)/prism/comments.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+load.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+load.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+load.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+load.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+load.$(OBJEXT): $(top_srcdir)/prism/integer.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+load.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+load.$(OBJEXT): $(top_srcdir)/prism/json.h
+load.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+load.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+load.$(OBJEXT): $(top_srcdir)/prism/node.h
+load.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+load.$(OBJEXT): $(top_srcdir)/prism/source.h
+load.$(OBJEXT): $(top_srcdir)/prism/stream.h
+load.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+load.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+load.$(OBJEXT): $(top_srcdir)/prism/version.h
+load.$(OBJEXT): {$(VPATH)}assert.h
+load.$(OBJEXT): {$(VPATH)}atomic.h
+load.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+load.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+load.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+load.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+load.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+load.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+load.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+load.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+load.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+load.$(OBJEXT): {$(VPATH)}config.h
+load.$(OBJEXT): {$(VPATH)}constant.h
+load.$(OBJEXT): {$(VPATH)}darray.h
+load.$(OBJEXT): {$(VPATH)}defines.h
+load.$(OBJEXT): {$(VPATH)}dln.h
+load.$(OBJEXT): {$(VPATH)}encindex.h
+load.$(OBJEXT): {$(VPATH)}encoding.h
+load.$(OBJEXT): {$(VPATH)}eval_intern.h
+load.$(OBJEXT): {$(VPATH)}id.h
+load.$(OBJEXT): {$(VPATH)}id_table.h
+load.$(OBJEXT): {$(VPATH)}intern.h
+load.$(OBJEXT): {$(VPATH)}internal.h
+load.$(OBJEXT): {$(VPATH)}internal/abi.h
+load.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+load.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+load.$(OBJEXT): {$(VPATH)}internal/assume.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+load.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+load.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+load.$(OBJEXT): {$(VPATH)}internal/cast.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+load.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+load.$(OBJEXT): {$(VPATH)}internal/config.h
+load.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+load.$(OBJEXT): {$(VPATH)}internal/core.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+load.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+load.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+load.$(OBJEXT): {$(VPATH)}internal/ctype.h
+load.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+load.$(OBJEXT): {$(VPATH)}internal/dosish.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+load.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+load.$(OBJEXT): {$(VPATH)}internal/error.h
+load.$(OBJEXT): {$(VPATH)}internal/eval.h
+load.$(OBJEXT): {$(VPATH)}internal/event.h
+load.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+load.$(OBJEXT): {$(VPATH)}internal/gc.h
+load.$(OBJEXT): {$(VPATH)}internal/glob.h
+load.$(OBJEXT): {$(VPATH)}internal/globals.h
+load.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+load.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+load.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+load.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+load.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+load.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+load.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+load.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+load.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+load.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+load.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+load.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+load.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+load.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+load.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+load.$(OBJEXT): {$(VPATH)}internal/symbol.h
+load.$(OBJEXT): {$(VPATH)}internal/value.h
+load.$(OBJEXT): {$(VPATH)}internal/value_type.h
+load.$(OBJEXT): {$(VPATH)}internal/variable.h
+load.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+load.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+load.$(OBJEXT): {$(VPATH)}iseq.h
+load.$(OBJEXT): {$(VPATH)}load.c
+load.$(OBJEXT): {$(VPATH)}method.h
+load.$(OBJEXT): {$(VPATH)}missing.h
+load.$(OBJEXT): {$(VPATH)}node.h
+load.$(OBJEXT): {$(VPATH)}onigmo.h
+load.$(OBJEXT): {$(VPATH)}oniguruma.h
+load.$(OBJEXT): {$(VPATH)}prism_compile.h
+load.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+load.$(OBJEXT): {$(VPATH)}probes.dmyh
+load.$(OBJEXT): {$(VPATH)}probes.h
+load.$(OBJEXT): {$(VPATH)}ractor.h
+load.$(OBJEXT): {$(VPATH)}ractor_core.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
+load.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+load.$(OBJEXT): {$(VPATH)}thread_native.h
+load.$(OBJEXT): {$(VPATH)}util.h
+load.$(OBJEXT): {$(VPATH)}vm_core.h
+load.$(OBJEXT): {$(VPATH)}vm_debug.h
+load.$(OBJEXT): {$(VPATH)}vm_opts.h
+load.$(OBJEXT): {$(VPATH)}zjit.h
+loadpath.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+loadpath.$(OBJEXT): $(hdrdir)/ruby/version.h
+loadpath.$(OBJEXT): $(top_srcdir)/version.h
+loadpath.$(OBJEXT): {$(VPATH)}assert.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+loadpath.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+loadpath.$(OBJEXT): {$(VPATH)}config.h
+loadpath.$(OBJEXT): {$(VPATH)}defines.h
+loadpath.$(OBJEXT): {$(VPATH)}intern.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/abi.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/assume.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/cast.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/config.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/ctype.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/dosish.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/error.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/eval.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/event.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/gc.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/glob.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/globals.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/symbol.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/value.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/value_type.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/variable.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+loadpath.$(OBJEXT): {$(VPATH)}loadpath.c
+loadpath.$(OBJEXT): {$(VPATH)}missing.h
+loadpath.$(OBJEXT): {$(VPATH)}st.h
+loadpath.$(OBJEXT): {$(VPATH)}subst.h
+loadpath.$(OBJEXT): {$(VPATH)}verconf.h
+localeinit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+localeinit.$(OBJEXT): {$(VPATH)}assert.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+localeinit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+localeinit.$(OBJEXT): {$(VPATH)}config.h
+localeinit.$(OBJEXT): {$(VPATH)}defines.h
+localeinit.$(OBJEXT): {$(VPATH)}encindex.h
+localeinit.$(OBJEXT): {$(VPATH)}encoding.h
+localeinit.$(OBJEXT): {$(VPATH)}intern.h
+localeinit.$(OBJEXT): {$(VPATH)}internal.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/abi.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/assume.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/cast.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/config.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/error.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/eval.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/event.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/gc.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/glob.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/globals.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/value.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/variable.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+localeinit.$(OBJEXT): {$(VPATH)}localeinit.c
+localeinit.$(OBJEXT): {$(VPATH)}missing.h
+localeinit.$(OBJEXT): {$(VPATH)}onigmo.h
+localeinit.$(OBJEXT): {$(VPATH)}oniguruma.h
+localeinit.$(OBJEXT): {$(VPATH)}st.h
+localeinit.$(OBJEXT): {$(VPATH)}subst.h
+main.$(OBJEXT): $(hdrdir)/ruby.h
+main.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+main.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+main.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+main.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+main.$(OBJEXT): {$(VPATH)}assert.h
+main.$(OBJEXT): {$(VPATH)}backward.h
+main.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+main.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+main.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+main.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+main.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+main.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+main.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+main.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+main.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+main.$(OBJEXT): {$(VPATH)}config.h
+main.$(OBJEXT): {$(VPATH)}defines.h
+main.$(OBJEXT): {$(VPATH)}intern.h
+main.$(OBJEXT): {$(VPATH)}internal/abi.h
+main.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+main.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+main.$(OBJEXT): {$(VPATH)}internal/assume.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+main.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+main.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+main.$(OBJEXT): {$(VPATH)}internal/cast.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+main.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+main.$(OBJEXT): {$(VPATH)}internal/config.h
+main.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+main.$(OBJEXT): {$(VPATH)}internal/core.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+main.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+main.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+main.$(OBJEXT): {$(VPATH)}internal/ctype.h
+main.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+main.$(OBJEXT): {$(VPATH)}internal/dosish.h
+main.$(OBJEXT): {$(VPATH)}internal/error.h
+main.$(OBJEXT): {$(VPATH)}internal/eval.h
+main.$(OBJEXT): {$(VPATH)}internal/event.h
+main.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+main.$(OBJEXT): {$(VPATH)}internal/gc.h
+main.$(OBJEXT): {$(VPATH)}internal/glob.h
+main.$(OBJEXT): {$(VPATH)}internal/globals.h
+main.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+main.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+main.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+main.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+main.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+main.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+main.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+main.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+main.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+main.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+main.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+main.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+main.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+main.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+main.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+main.$(OBJEXT): {$(VPATH)}internal/symbol.h
+main.$(OBJEXT): {$(VPATH)}internal/value.h
+main.$(OBJEXT): {$(VPATH)}internal/value_type.h
+main.$(OBJEXT): {$(VPATH)}internal/variable.h
+main.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+main.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+main.$(OBJEXT): {$(VPATH)}main.c
+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/box.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/class.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/compar.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+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/re.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/string.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/struct.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/util.h
+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
+marshal.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+marshal.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+marshal.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+marshal.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+marshal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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
+marshal.$(OBJEXT): {$(VPATH)}internal/abi.h
+marshal.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+marshal.$(OBJEXT): {$(VPATH)}internal/assume.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+marshal.$(OBJEXT): {$(VPATH)}internal/cast.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+marshal.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+marshal.$(OBJEXT): {$(VPATH)}internal/config.h
+marshal.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+marshal.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+marshal.$(OBJEXT): {$(VPATH)}internal/ctype.h
+marshal.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+marshal.$(OBJEXT): {$(VPATH)}internal/dosish.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+marshal.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+marshal.$(OBJEXT): {$(VPATH)}internal/error.h
+marshal.$(OBJEXT): {$(VPATH)}internal/eval.h
+marshal.$(OBJEXT): {$(VPATH)}internal/event.h
+marshal.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+marshal.$(OBJEXT): {$(VPATH)}internal/gc.h
+marshal.$(OBJEXT): {$(VPATH)}internal/glob.h
+marshal.$(OBJEXT): {$(VPATH)}internal/globals.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+marshal.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+marshal.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+marshal.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+marshal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+marshal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+marshal.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+marshal.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+marshal.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+marshal.$(OBJEXT): {$(VPATH)}internal/symbol.h
+marshal.$(OBJEXT): {$(VPATH)}internal/value.h
+marshal.$(OBJEXT): {$(VPATH)}internal/value_type.h
+marshal.$(OBJEXT): {$(VPATH)}internal/variable.h
+marshal.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+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)}re.h
+marshal.$(OBJEXT): {$(VPATH)}regex.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
+math.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+math.$(OBJEXT): $(top_srcdir)/internal/complex.h
+math.$(OBJEXT): $(top_srcdir)/internal/gc.h
+math.$(OBJEXT): $(top_srcdir)/internal/math.h
+math.$(OBJEXT): $(top_srcdir)/internal/object.h
+math.$(OBJEXT): $(top_srcdir)/internal/serial.h
+math.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+math.$(OBJEXT): $(top_srcdir)/internal/variable.h
+math.$(OBJEXT): $(top_srcdir)/internal/vm.h
+math.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+math.$(OBJEXT): {$(VPATH)}assert.h
+math.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+math.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+math.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+math.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+math.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+math.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+math.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+math.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+math.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+math.$(OBJEXT): {$(VPATH)}config.h
+math.$(OBJEXT): {$(VPATH)}constant.h
+math.$(OBJEXT): {$(VPATH)}defines.h
+math.$(OBJEXT): {$(VPATH)}id_table.h
+math.$(OBJEXT): {$(VPATH)}intern.h
+math.$(OBJEXT): {$(VPATH)}internal.h
+math.$(OBJEXT): {$(VPATH)}internal/abi.h
+math.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+math.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+math.$(OBJEXT): {$(VPATH)}internal/assume.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+math.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+math.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+math.$(OBJEXT): {$(VPATH)}internal/cast.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+math.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+math.$(OBJEXT): {$(VPATH)}internal/config.h
+math.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+math.$(OBJEXT): {$(VPATH)}internal/core.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+math.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+math.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+math.$(OBJEXT): {$(VPATH)}internal/ctype.h
+math.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+math.$(OBJEXT): {$(VPATH)}internal/dosish.h
+math.$(OBJEXT): {$(VPATH)}internal/error.h
+math.$(OBJEXT): {$(VPATH)}internal/eval.h
+math.$(OBJEXT): {$(VPATH)}internal/event.h
+math.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+math.$(OBJEXT): {$(VPATH)}internal/gc.h
+math.$(OBJEXT): {$(VPATH)}internal/glob.h
+math.$(OBJEXT): {$(VPATH)}internal/globals.h
+math.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+math.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+math.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+math.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+math.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+math.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+math.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+math.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+math.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+math.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+math.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+math.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+math.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+math.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+math.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+math.$(OBJEXT): {$(VPATH)}internal/symbol.h
+math.$(OBJEXT): {$(VPATH)}internal/value.h
+math.$(OBJEXT): {$(VPATH)}internal/value_type.h
+math.$(OBJEXT): {$(VPATH)}internal/variable.h
+math.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+math.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+math.$(OBJEXT): {$(VPATH)}math.c
+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/box.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/sanitizers.h
+memory_view.$(OBJEXT): $(top_srcdir)/internal/serial.h
+memory_view.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+memory_view.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+memory_view.$(OBJEXT): $(top_srcdir)/internal/struct.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
+memory_view.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+memory_view.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+memory_view.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+memory_view.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+memory_view.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+memory_view.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+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
+memory_view.$(OBJEXT): {$(VPATH)}internal/abi.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/assume.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/cast.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/config.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+memory_view.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/gc.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/glob.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/globals.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/symbol.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/value.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/value_type.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/variable.h
+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): $(top_srcdir)/internal/array.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/bits.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/box.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/compar.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/complex.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/eval.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/parse.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/rational.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+miniinit.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/ast.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/json.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/node.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/source.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+miniinit.$(OBJEXT): $(top_srcdir)/prism/version.h
+miniinit.$(OBJEXT): {$(VPATH)}array.rb
+miniinit.$(OBJEXT): {$(VPATH)}assert.h
+miniinit.$(OBJEXT): {$(VPATH)}ast.rb
+miniinit.$(OBJEXT): {$(VPATH)}atomic.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+miniinit.$(OBJEXT): {$(VPATH)}builtin.h
+miniinit.$(OBJEXT): {$(VPATH)}config.h
+miniinit.$(OBJEXT): {$(VPATH)}constant.h
+miniinit.$(OBJEXT): {$(VPATH)}defines.h
+miniinit.$(OBJEXT): {$(VPATH)}dir.rb
+miniinit.$(OBJEXT): {$(VPATH)}encoding.h
+miniinit.$(OBJEXT): {$(VPATH)}gc.rb
+miniinit.$(OBJEXT): {$(VPATH)}gem_prelude.rb
+miniinit.$(OBJEXT): {$(VPATH)}id.h
+miniinit.$(OBJEXT): {$(VPATH)}id_table.h
+miniinit.$(OBJEXT): {$(VPATH)}intern.h
+miniinit.$(OBJEXT): {$(VPATH)}internal.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/abi.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/assume.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/cast.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/config.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/error.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/eval.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/event.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/gc.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/glob.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/globals.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/value.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/variable.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+miniinit.$(OBJEXT): {$(VPATH)}io.rb
+miniinit.$(OBJEXT): {$(VPATH)}iseq.h
+miniinit.$(OBJEXT): {$(VPATH)}jit_hook.rb
+miniinit.$(OBJEXT): {$(VPATH)}jit_undef.rb
+miniinit.$(OBJEXT): {$(VPATH)}kernel.rb
+miniinit.$(OBJEXT): {$(VPATH)}marshal.rb
+miniinit.$(OBJEXT): {$(VPATH)}method.h
+miniinit.$(OBJEXT): {$(VPATH)}mini_builtin.c
+miniinit.$(OBJEXT): {$(VPATH)}miniinit.c
+miniinit.$(OBJEXT): {$(VPATH)}miniprelude.c
+miniinit.$(OBJEXT): {$(VPATH)}missing.h
+miniinit.$(OBJEXT): {$(VPATH)}nilclass.rb
+miniinit.$(OBJEXT): {$(VPATH)}node.h
+miniinit.$(OBJEXT): {$(VPATH)}numeric.rb
+miniinit.$(OBJEXT): {$(VPATH)}onigmo.h
+miniinit.$(OBJEXT): {$(VPATH)}oniguruma.h
+miniinit.$(OBJEXT): {$(VPATH)}pack.rb
+miniinit.$(OBJEXT): {$(VPATH)}pathname_builtin.rb
+miniinit.$(OBJEXT): {$(VPATH)}prelude.rb
+miniinit.$(OBJEXT): {$(VPATH)}prism_compile.h
+miniinit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+miniinit.$(OBJEXT): {$(VPATH)}ractor.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
+miniinit.$(OBJEXT): {$(VPATH)}symbol.rb
+miniinit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+miniinit.$(OBJEXT): {$(VPATH)}thread_native.h
+miniinit.$(OBJEXT): {$(VPATH)}thread_sync.rb
+miniinit.$(OBJEXT): {$(VPATH)}timev.rb
+miniinit.$(OBJEXT): {$(VPATH)}trace_point.rb
+miniinit.$(OBJEXT): {$(VPATH)}vm_core.h
+miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
+miniinit.$(OBJEXT): {$(VPATH)}warning.rb
+miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
+miniinit.$(OBJEXT): {$(VPATH)}zjit.rb
+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
+node.$(OBJEXT): $(CCAN_DIR)/str/str.h
+node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+node.$(OBJEXT): $(top_srcdir)/internal/array.h
+node.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+node.$(OBJEXT): $(top_srcdir)/internal/box.h
+node.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+node.$(OBJEXT): $(top_srcdir)/internal/gc.h
+node.$(OBJEXT): $(top_srcdir)/internal/hash.h
+node.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+node.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+node.$(OBJEXT): $(top_srcdir)/internal/serial.h
+node.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+node.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+node.$(OBJEXT): $(top_srcdir)/internal/struct.h
+node.$(OBJEXT): $(top_srcdir)/internal/variable.h
+node.$(OBJEXT): $(top_srcdir)/internal/vm.h
+node.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+node.$(OBJEXT): {$(VPATH)}assert.h
+node.$(OBJEXT): {$(VPATH)}atomic.h
+node.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+node.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+node.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+node.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+node.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+node.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+node.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+node.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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
+node.$(OBJEXT): {$(VPATH)}internal.h
+node.$(OBJEXT): {$(VPATH)}internal/abi.h
+node.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+node.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+node.$(OBJEXT): {$(VPATH)}internal/assume.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+node.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+node.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+node.$(OBJEXT): {$(VPATH)}internal/cast.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+node.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+node.$(OBJEXT): {$(VPATH)}internal/config.h
+node.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+node.$(OBJEXT): {$(VPATH)}internal/core.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+node.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+node.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+node.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+node.$(OBJEXT): {$(VPATH)}internal/gc.h
+node.$(OBJEXT): {$(VPATH)}internal/glob.h
+node.$(OBJEXT): {$(VPATH)}internal/globals.h
+node.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+node.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+node.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+node.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+node.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+node.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+node.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+node.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+node.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+node.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+node.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+node.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+node.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+node.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+node.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+node.$(OBJEXT): {$(VPATH)}internal/symbol.h
+node.$(OBJEXT): {$(VPATH)}internal/value.h
+node.$(OBJEXT): {$(VPATH)}internal/value_type.h
+node.$(OBJEXT): {$(VPATH)}internal/variable.h
+node.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+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
+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/bignum.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/bits.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/box.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/class.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/compar.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/complex.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/fixnum.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/numeric.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/parse.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/rational.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+node_dump.$(OBJEXT): $(top_srcdir)/internal/struct.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)}debug_counter.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/set.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/stdckdint.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_debug.h
+node_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
+node_dump.$(OBJEXT): {$(VPATH)}vm_sync.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/box.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/class.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/compar.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/complex.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/error.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
+numeric.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/serial.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/string.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/struct.h
+numeric.$(OBJEXT): $(top_srcdir)/internal/util.h
+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
+numeric.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+numeric.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+numeric.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+numeric.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+numeric.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+numeric.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+numeric.$(OBJEXT): {$(VPATH)}builtin.h
+numeric.$(OBJEXT): {$(VPATH)}config.h
+numeric.$(OBJEXT): {$(VPATH)}constant.h
+numeric.$(OBJEXT): {$(VPATH)}defines.h
+numeric.$(OBJEXT): {$(VPATH)}encindex.h
+numeric.$(OBJEXT): {$(VPATH)}encoding.h
+numeric.$(OBJEXT): {$(VPATH)}id.h
+numeric.$(OBJEXT): {$(VPATH)}id_table.h
+numeric.$(OBJEXT): {$(VPATH)}intern.h
+numeric.$(OBJEXT): {$(VPATH)}internal.h
+numeric.$(OBJEXT): {$(VPATH)}internal/abi.h
+numeric.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+numeric.$(OBJEXT): {$(VPATH)}internal/assume.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+numeric.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+numeric.$(OBJEXT): {$(VPATH)}internal/cast.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+numeric.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+numeric.$(OBJEXT): {$(VPATH)}internal/config.h
+numeric.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+numeric.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+numeric.$(OBJEXT): {$(VPATH)}internal/ctype.h
+numeric.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+numeric.$(OBJEXT): {$(VPATH)}internal/dosish.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+numeric.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+numeric.$(OBJEXT): {$(VPATH)}internal/error.h
+numeric.$(OBJEXT): {$(VPATH)}internal/eval.h
+numeric.$(OBJEXT): {$(VPATH)}internal/event.h
+numeric.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+numeric.$(OBJEXT): {$(VPATH)}internal/gc.h
+numeric.$(OBJEXT): {$(VPATH)}internal/glob.h
+numeric.$(OBJEXT): {$(VPATH)}internal/globals.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+numeric.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+numeric.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+numeric.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+numeric.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+numeric.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+numeric.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+numeric.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+numeric.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+numeric.$(OBJEXT): {$(VPATH)}internal/symbol.h
+numeric.$(OBJEXT): {$(VPATH)}internal/value.h
+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/box.h
+object.$(OBJEXT): $(top_srcdir)/internal/class.h
+object.$(OBJEXT): $(top_srcdir)/internal/compar.h
+object.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+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
+object.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+object.$(OBJEXT): $(top_srcdir)/internal/serial.h
+object.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+object.$(OBJEXT): $(top_srcdir)/internal/st.h
+object.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+object.$(OBJEXT): $(top_srcdir)/internal/string.h
+object.$(OBJEXT): $(top_srcdir)/internal/struct.h
+object.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+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
+object.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+object.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+object.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+object.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+object.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}encindex.h
+object.$(OBJEXT): {$(VPATH)}encoding.h
+object.$(OBJEXT): {$(VPATH)}id.h
+object.$(OBJEXT): {$(VPATH)}id_table.h
+object.$(OBJEXT): {$(VPATH)}intern.h
+object.$(OBJEXT): {$(VPATH)}internal.h
+object.$(OBJEXT): {$(VPATH)}internal/abi.h
+object.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+object.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+object.$(OBJEXT): {$(VPATH)}internal/assume.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+object.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+object.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+object.$(OBJEXT): {$(VPATH)}internal/cast.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+object.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+object.$(OBJEXT): {$(VPATH)}internal/config.h
+object.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+object.$(OBJEXT): {$(VPATH)}internal/core.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+object.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+object.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+object.$(OBJEXT): {$(VPATH)}internal/ctype.h
+object.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+object.$(OBJEXT): {$(VPATH)}internal/dosish.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+object.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+object.$(OBJEXT): {$(VPATH)}internal/error.h
+object.$(OBJEXT): {$(VPATH)}internal/eval.h
+object.$(OBJEXT): {$(VPATH)}internal/event.h
+object.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+object.$(OBJEXT): {$(VPATH)}internal/gc.h
+object.$(OBJEXT): {$(VPATH)}internal/glob.h
+object.$(OBJEXT): {$(VPATH)}internal/globals.h
+object.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+object.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+object.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+object.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+object.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+object.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+object.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+object.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+object.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+object.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+object.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+object.$(OBJEXT): {$(VPATH)}internal/st.h
+object.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+object.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+object.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+object.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+object.$(OBJEXT): {$(VPATH)}internal/symbol.h
+object.$(OBJEXT): {$(VPATH)}internal/value.h
+object.$(OBJEXT): {$(VPATH)}internal/value_type.h
+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
+object.$(OBJEXT): {$(VPATH)}yjit.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/bignum.h
+pack.$(OBJEXT): $(top_srcdir)/internal/bits.h
+pack.$(OBJEXT): $(top_srcdir)/internal/box.h
+pack.$(OBJEXT): $(top_srcdir)/internal/compar.h
+pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+pack.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+pack.$(OBJEXT): $(top_srcdir)/internal/gc.h
+pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+pack.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+pack.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+pack.$(OBJEXT): $(top_srcdir)/internal/serial.h
+pack.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+pack.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+pack.$(OBJEXT): $(top_srcdir)/internal/string.h
+pack.$(OBJEXT): $(top_srcdir)/internal/struct.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
+pack.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+pack.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+pack.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+pack.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+pack.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+pack.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+pack.$(OBJEXT): {$(VPATH)}builtin.h
+pack.$(OBJEXT): {$(VPATH)}config.h
+pack.$(OBJEXT): {$(VPATH)}constant.h
+pack.$(OBJEXT): {$(VPATH)}defines.h
+pack.$(OBJEXT): {$(VPATH)}encindex.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
+pack.$(OBJEXT): {$(VPATH)}internal/abi.h
+pack.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+pack.$(OBJEXT): {$(VPATH)}internal/assume.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+pack.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+pack.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+pack.$(OBJEXT): {$(VPATH)}internal/cast.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+pack.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+pack.$(OBJEXT): {$(VPATH)}internal/config.h
+pack.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+pack.$(OBJEXT): {$(VPATH)}internal/core.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+pack.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+pack.$(OBJEXT): {$(VPATH)}internal/ctype.h
+pack.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+pack.$(OBJEXT): {$(VPATH)}internal/dosish.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+pack.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+pack.$(OBJEXT): {$(VPATH)}internal/error.h
+pack.$(OBJEXT): {$(VPATH)}internal/eval.h
+pack.$(OBJEXT): {$(VPATH)}internal/event.h
+pack.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+pack.$(OBJEXT): {$(VPATH)}internal/gc.h
+pack.$(OBJEXT): {$(VPATH)}internal/glob.h
+pack.$(OBJEXT): {$(VPATH)}internal/globals.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+pack.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+pack.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+pack.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+pack.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+pack.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+pack.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+pack.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+pack.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+pack.$(OBJEXT): {$(VPATH)}internal/symbol.h
+pack.$(OBJEXT): {$(VPATH)}internal/value.h
+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/box.h
+parse.$(OBJEXT): $(top_srcdir)/internal/compar.h
+parse.$(OBJEXT): $(top_srcdir)/internal/compile.h
+parse.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+parse.$(OBJEXT): $(top_srcdir)/internal/complex.h
+parse.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+parse.$(OBJEXT): $(top_srcdir)/internal/error.h
+parse.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+parse.$(OBJEXT): $(top_srcdir)/internal/gc.h
+parse.$(OBJEXT): $(top_srcdir)/internal/hash.h
+parse.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+parse.$(OBJEXT): $(top_srcdir)/internal/io.h
+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/sanitizers.h
+parse.$(OBJEXT): $(top_srcdir)/internal/serial.h
+parse.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+parse.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+parse.$(OBJEXT): $(top_srcdir)/internal/string.h
+parse.$(OBJEXT): $(top_srcdir)/internal/struct.h
+parse.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+parse.$(OBJEXT): $(top_srcdir)/internal/thread.h
+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
+parse.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+parse.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+parse.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+parse.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+parse.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+parse.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+parse.$(OBJEXT): {$(VPATH)}config.h
+parse.$(OBJEXT): {$(VPATH)}constant.h
+parse.$(OBJEXT): {$(VPATH)}defines.h
+parse.$(OBJEXT): {$(VPATH)}defs/keywords
+parse.$(OBJEXT): {$(VPATH)}encindex.h
+parse.$(OBJEXT): {$(VPATH)}encoding.h
+parse.$(OBJEXT): {$(VPATH)}id.h
+parse.$(OBJEXT): {$(VPATH)}id_table.h
+parse.$(OBJEXT): {$(VPATH)}intern.h
+parse.$(OBJEXT): {$(VPATH)}internal.h
+parse.$(OBJEXT): {$(VPATH)}internal/abi.h
+parse.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+parse.$(OBJEXT): {$(VPATH)}internal/assume.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+parse.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+parse.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+parse.$(OBJEXT): {$(VPATH)}internal/cast.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+parse.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+parse.$(OBJEXT): {$(VPATH)}internal/config.h
+parse.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+parse.$(OBJEXT): {$(VPATH)}internal/core.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+parse.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+parse.$(OBJEXT): {$(VPATH)}internal/ctype.h
+parse.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+parse.$(OBJEXT): {$(VPATH)}internal/dosish.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+parse.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+parse.$(OBJEXT): {$(VPATH)}internal/error.h
+parse.$(OBJEXT): {$(VPATH)}internal/eval.h
+parse.$(OBJEXT): {$(VPATH)}internal/event.h
+parse.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+parse.$(OBJEXT): {$(VPATH)}internal/gc.h
+parse.$(OBJEXT): {$(VPATH)}internal/glob.h
+parse.$(OBJEXT): {$(VPATH)}internal/globals.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+parse.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+parse.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+parse.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+parse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+parse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+parse.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+parse.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+parse.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+parse.$(OBJEXT): {$(VPATH)}internal/symbol.h
+parse.$(OBJEXT): {$(VPATH)}internal/value.h
+parse.$(OBJEXT): {$(VPATH)}internal/value_type.h
+parse.$(OBJEXT): {$(VPATH)}internal/variable.h
+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
+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)}re.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
+pathname.$(OBJEXT): $(hdrdir)/ruby.h
+pathname.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/file.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/serial.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/string.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/vm.h
+pathname.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+pathname.$(OBJEXT): {$(VPATH)}assert.h
+pathname.$(OBJEXT): {$(VPATH)}backward.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+pathname.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+pathname.$(OBJEXT): {$(VPATH)}builtin.h
+pathname.$(OBJEXT): {$(VPATH)}config.h
+pathname.$(OBJEXT): {$(VPATH)}defines.h
+pathname.$(OBJEXT): {$(VPATH)}encindex.h
+pathname.$(OBJEXT): {$(VPATH)}encoding.h
+pathname.$(OBJEXT): {$(VPATH)}intern.h
+pathname.$(OBJEXT): {$(VPATH)}internal.h
+pathname.$(OBJEXT): {$(VPATH)}internal/abi.h
+pathname.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+pathname.$(OBJEXT): {$(VPATH)}internal/assume.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+pathname.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+pathname.$(OBJEXT): {$(VPATH)}internal/cast.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+pathname.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+pathname.$(OBJEXT): {$(VPATH)}internal/config.h
+pathname.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+pathname.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+pathname.$(OBJEXT): {$(VPATH)}internal/ctype.h
+pathname.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+pathname.$(OBJEXT): {$(VPATH)}internal/dosish.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+pathname.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+pathname.$(OBJEXT): {$(VPATH)}internal/error.h
+pathname.$(OBJEXT): {$(VPATH)}internal/eval.h
+pathname.$(OBJEXT): {$(VPATH)}internal/event.h
+pathname.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+pathname.$(OBJEXT): {$(VPATH)}internal/gc.h
+pathname.$(OBJEXT): {$(VPATH)}internal/glob.h
+pathname.$(OBJEXT): {$(VPATH)}internal/globals.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+pathname.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+pathname.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+pathname.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+pathname.$(OBJEXT): {$(VPATH)}internal/iterator.h
+pathname.$(OBJEXT): {$(VPATH)}internal/memory.h
+pathname.$(OBJEXT): {$(VPATH)}internal/method.h
+pathname.$(OBJEXT): {$(VPATH)}internal/module.h
+pathname.$(OBJEXT): {$(VPATH)}internal/newobj.h
+pathname.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+pathname.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+pathname.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+pathname.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+pathname.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+pathname.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+pathname.$(OBJEXT): {$(VPATH)}internal/symbol.h
+pathname.$(OBJEXT): {$(VPATH)}internal/value.h
+pathname.$(OBJEXT): {$(VPATH)}internal/value_type.h
+pathname.$(OBJEXT): {$(VPATH)}internal/variable.h
+pathname.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+pathname.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+pathname.$(OBJEXT): {$(VPATH)}missing.h
+pathname.$(OBJEXT): {$(VPATH)}onigmo.h
+pathname.$(OBJEXT): {$(VPATH)}oniguruma.h
+pathname.$(OBJEXT): {$(VPATH)}pathname.c
+pathname.$(OBJEXT): {$(VPATH)}pathname_builtin.rbinc
+pathname.$(OBJEXT): {$(VPATH)}ruby.h
+pathname.$(OBJEXT): {$(VPATH)}st.h
+pathname.$(OBJEXT): {$(VPATH)}subst.h
+prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h
+prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+prism/api_node.$(OBJEXT): $(hdrdir)/ruby/version.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/api_node.c
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/extension.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/magic_comments.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/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/serialize.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/api_node.$(OBJEXT): $(top_srcdir)/prism/version.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/set.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/stdckdint.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_xallocator.h
+prism/api_node.$(OBJEXT): {$(VPATH)}st.h
+prism/api_node.$(OBJEXT): {$(VPATH)}subst.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/arena.c
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/arena.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/arena.$(OBJEXT): {$(VPATH)}config.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/arena.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/arena.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/buffer.c
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/buffer.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/buffer.$(OBJEXT): {$(VPATH)}config.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/buffer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/buffer.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/char.c
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h
+prism/char.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/char.$(OBJEXT): {$(VPATH)}config.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/char.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/char.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/constant_pool.c
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/constant_pool.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}config.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/constant_pool.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.c
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}config.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/diagnostic.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/encoding.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.c
+prism/encoding.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/encoding.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/encoding.$(OBJEXT): {$(VPATH)}config.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/encoding.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/encoding.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/extension.$(OBJEXT): $(hdrdir)/ruby.h
+prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+prism/extension.$(OBJEXT): $(hdrdir)/ruby/version.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.c
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/node.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/extension.$(OBJEXT): $(top_srcdir)/prism/version.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/set.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/stdckdint.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_xallocator.h
+prism/extension.$(OBJEXT): {$(VPATH)}st.h
+prism/extension.$(OBJEXT): {$(VPATH)}subst.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/integer.c
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/integer.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/integer.$(OBJEXT): {$(VPATH)}config.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/integer.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/integer.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/json.c
+prism/json.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/json.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.c
+prism/line_offset_list.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}config.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/line_offset_list.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/list.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/list.$(OBJEXT): $(top_srcdir)/prism/list.c
+prism/list.$(OBJEXT): {$(VPATH)}config.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/list.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/list.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/memchr.c
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/memchr.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/memchr.$(OBJEXT): {$(VPATH)}config.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/memchr.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/memchr.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/node.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/node.c
+prism/node.$(OBJEXT): $(top_srcdir)/prism/node.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/prism.h
+prism/node.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/node.$(OBJEXT): {$(VPATH)}config.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/node.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/options.c
+prism/options.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/options.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/options.$(OBJEXT): {$(VPATH)}config.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/options.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/options.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/parser.c
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/parser.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/parser.$(OBJEXT): {$(VPATH)}config.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/parser.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/parser.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.c
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}config.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/prettyprint.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/fallthrough.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/bit.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/isinf.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/line_offset_list.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/node.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/serialize.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/source.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/internal/tokens.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/node.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h
+prism/prism.$(OBJEXT): {$(VPATH)}config.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/prism.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/prism.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/fallthrough.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.c
+prism/regexp.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/regexp.$(OBJEXT): {$(VPATH)}config.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/regexp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/regexp.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/magic_comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/node.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.c
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/serialize.$(OBJEXT): $(top_srcdir)/prism/version.h
+prism/serialize.$(OBJEXT): {$(VPATH)}config.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/serialize.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/serialize.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/internal/source.h
+prism/source.$(OBJEXT): $(top_srcdir)/prism/source.c
+prism/source.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism/source.$(OBJEXT): {$(VPATH)}config.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/source.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/source.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/format.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/buffer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/integer.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/isinf.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/node.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.c
+prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}config.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/static_literals.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/string_query.c
+prism/string_query.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/internal/allocator.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/internal/stringy.h
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/stringy.c
+prism/stringy.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/stringy.$(OBJEXT): {$(VPATH)}config.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/stringy.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/stringy.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/strncasecmp.$(OBJEXT): $(top_srcdir)/prism/strncasecmp.c
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}config.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/strncasecmp.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/accel.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/flex_array.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/force_inline.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/inline.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/compiler/unused.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/arena.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/bit.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/constant_pool.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/diagnostic.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/options.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/parser.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/options.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/strpbrk.$(OBJEXT): $(top_srcdir)/prism/strpbrk.c
+prism/strpbrk.$(OBJEXT): {$(VPATH)}config.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/strpbrk.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism/tokens.$(OBJEXT): $(top_srcdir)/prism/tokens.c
+prism/tokens.$(OBJEXT): {$(VPATH)}config.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/config.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+prism/tokens.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+prism/tokens.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+prism_init.$(OBJEXT): $(hdrdir)/ruby.h
+prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+prism_init.$(OBJEXT): $(hdrdir)/ruby/version.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/arena.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/ast.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/comments.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/extension.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/integer.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/json.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/node.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/source.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/stream.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+prism_init.$(OBJEXT): $(top_srcdir)/prism/version.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/set.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/stdckdint.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_init.c
+prism_init.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+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/box.h
+proc.$(OBJEXT): $(top_srcdir)/internal/class.h
+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
+proc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+proc.$(OBJEXT): $(top_srcdir)/internal/serial.h
+proc.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+proc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+proc.$(OBJEXT): $(top_srcdir)/internal/string.h
+proc.$(OBJEXT): $(top_srcdir)/internal/struct.h
+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/arena.h
+proc.$(OBJEXT): $(top_srcdir)/prism/ast.h
+proc.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+proc.$(OBJEXT): $(top_srcdir)/prism/comments.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+proc.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+proc.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+proc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+proc.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+proc.$(OBJEXT): $(top_srcdir)/prism/integer.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+proc.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+proc.$(OBJEXT): $(top_srcdir)/prism/json.h
+proc.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+proc.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+proc.$(OBJEXT): $(top_srcdir)/prism/node.h
+proc.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+proc.$(OBJEXT): $(top_srcdir)/prism/source.h
+proc.$(OBJEXT): $(top_srcdir)/prism/stream.h
+proc.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+proc.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+proc.$(OBJEXT): $(top_srcdir)/prism/version.h
+proc.$(OBJEXT): {$(VPATH)}assert.h
+proc.$(OBJEXT): {$(VPATH)}atomic.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+proc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+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)}encindex.h
+proc.$(OBJEXT): {$(VPATH)}encoding.h
+proc.$(OBJEXT): {$(VPATH)}eval_intern.h
+proc.$(OBJEXT): {$(VPATH)}id.h
+proc.$(OBJEXT): {$(VPATH)}id_table.h
+proc.$(OBJEXT): {$(VPATH)}intern.h
+proc.$(OBJEXT): {$(VPATH)}internal.h
+proc.$(OBJEXT): {$(VPATH)}internal/abi.h
+proc.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+proc.$(OBJEXT): {$(VPATH)}internal/assume.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+proc.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+proc.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+proc.$(OBJEXT): {$(VPATH)}internal/cast.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+proc.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+proc.$(OBJEXT): {$(VPATH)}internal/config.h
+proc.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+proc.$(OBJEXT): {$(VPATH)}internal/core.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+proc.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+proc.$(OBJEXT): {$(VPATH)}internal/ctype.h
+proc.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+proc.$(OBJEXT): {$(VPATH)}internal/dosish.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+proc.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+proc.$(OBJEXT): {$(VPATH)}internal/error.h
+proc.$(OBJEXT): {$(VPATH)}internal/eval.h
+proc.$(OBJEXT): {$(VPATH)}internal/event.h
+proc.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+proc.$(OBJEXT): {$(VPATH)}internal/gc.h
+proc.$(OBJEXT): {$(VPATH)}internal/glob.h
+proc.$(OBJEXT): {$(VPATH)}internal/globals.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+proc.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+proc.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+proc.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+proc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+proc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+proc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+proc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+proc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+proc.$(OBJEXT): {$(VPATH)}internal/symbol.h
+proc.$(OBJEXT): {$(VPATH)}internal/value.h
+proc.$(OBJEXT): {$(VPATH)}internal/value_type.h
+proc.$(OBJEXT): {$(VPATH)}internal/variable.h
+proc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+proc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+proc.$(OBJEXT): {$(VPATH)}iseq.h
+proc.$(OBJEXT): {$(VPATH)}method.h
+proc.$(OBJEXT): {$(VPATH)}missing.h
+proc.$(OBJEXT): {$(VPATH)}node.h
+proc.$(OBJEXT): {$(VPATH)}onigmo.h
+proc.$(OBJEXT): {$(VPATH)}oniguruma.h
+proc.$(OBJEXT): {$(VPATH)}prism_compile.h
+proc.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+proc.$(OBJEXT): {$(VPATH)}proc.c
+proc.$(OBJEXT): {$(VPATH)}ractor.h
+proc.$(OBJEXT): {$(VPATH)}ractor_core.h
+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
+proc.$(OBJEXT): {$(VPATH)}zjit.h
+process.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+process.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+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
+process.$(OBJEXT): $(top_srcdir)/internal/bits.h
+process.$(OBJEXT): $(top_srcdir)/internal/box.h
+process.$(OBJEXT): $(top_srcdir)/internal/class.h
+process.$(OBJEXT): $(top_srcdir)/internal/compar.h
+process.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+process.$(OBJEXT): $(top_srcdir)/internal/dir.h
+process.$(OBJEXT): $(top_srcdir)/internal/error.h
+process.$(OBJEXT): $(top_srcdir)/internal/eval.h
+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
+process.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+process.$(OBJEXT): $(top_srcdir)/internal/serial.h
+process.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+process.$(OBJEXT): $(top_srcdir)/internal/string.h
+process.$(OBJEXT): $(top_srcdir)/internal/struct.h
+process.$(OBJEXT): $(top_srcdir)/internal/thread.h
+process.$(OBJEXT): $(top_srcdir)/internal/time.h
+process.$(OBJEXT): $(top_srcdir)/internal/variable.h
+process.$(OBJEXT): $(top_srcdir)/internal/vm.h
+process.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+process.$(OBJEXT): {$(VPATH)}assert.h
+process.$(OBJEXT): {$(VPATH)}atomic.h
+process.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+process.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+process.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+process.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+process.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+process.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+process.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+process.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+process.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+process.$(OBJEXT): {$(VPATH)}config.h
+process.$(OBJEXT): {$(VPATH)}constant.h
+process.$(OBJEXT): {$(VPATH)}debug_counter.h
+process.$(OBJEXT): {$(VPATH)}defines.h
+process.$(OBJEXT): {$(VPATH)}dln.h
+process.$(OBJEXT): {$(VPATH)}encindex.h
+process.$(OBJEXT): {$(VPATH)}encoding.h
+process.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+process.$(OBJEXT): {$(VPATH)}hrtime.h
+process.$(OBJEXT): {$(VPATH)}id.h
+process.$(OBJEXT): {$(VPATH)}id_table.h
+process.$(OBJEXT): {$(VPATH)}intern.h
+process.$(OBJEXT): {$(VPATH)}internal.h
+process.$(OBJEXT): {$(VPATH)}internal/abi.h
+process.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+process.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+process.$(OBJEXT): {$(VPATH)}internal/assume.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+process.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+process.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+process.$(OBJEXT): {$(VPATH)}internal/cast.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+process.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+process.$(OBJEXT): {$(VPATH)}internal/config.h
+process.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+process.$(OBJEXT): {$(VPATH)}internal/core.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+process.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+process.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+process.$(OBJEXT): {$(VPATH)}internal/ctype.h
+process.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+process.$(OBJEXT): {$(VPATH)}internal/dosish.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+process.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+process.$(OBJEXT): {$(VPATH)}internal/error.h
+process.$(OBJEXT): {$(VPATH)}internal/eval.h
+process.$(OBJEXT): {$(VPATH)}internal/event.h
+process.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+process.$(OBJEXT): {$(VPATH)}internal/gc.h
+process.$(OBJEXT): {$(VPATH)}internal/glob.h
+process.$(OBJEXT): {$(VPATH)}internal/globals.h
+process.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+process.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+process.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+process.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+process.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+process.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+process.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+process.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+process.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+process.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+process.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+process.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+process.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+process.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+process.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+process.$(OBJEXT): {$(VPATH)}internal/symbol.h
+process.$(OBJEXT): {$(VPATH)}internal/value.h
+process.$(OBJEXT): {$(VPATH)}internal/value_type.h
+process.$(OBJEXT): {$(VPATH)}internal/variable.h
+process.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+process.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+process.$(OBJEXT): {$(VPATH)}io.h
+process.$(OBJEXT): {$(VPATH)}method.h
+process.$(OBJEXT): {$(VPATH)}missing.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)}ractor_core.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
+process.$(OBJEXT): {$(VPATH)}thread.h
+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
+ractor.$(OBJEXT): $(top_srcdir)/internal/bits.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/box.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/compar.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/complex.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/error.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/gc.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/object.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/ractor.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/rational.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/serial.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/st.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/string.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/struct.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/thread.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/variable.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/vm.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+ractor.$(OBJEXT): {$(VPATH)}assert.h
+ractor.$(OBJEXT): {$(VPATH)}atomic.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+ractor.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+ractor.$(OBJEXT): {$(VPATH)}builtin.h
+ractor.$(OBJEXT): {$(VPATH)}config.h
+ractor.$(OBJEXT): {$(VPATH)}constant.h
+ractor.$(OBJEXT): {$(VPATH)}debug_counter.h
+ractor.$(OBJEXT): {$(VPATH)}defines.h
+ractor.$(OBJEXT): {$(VPATH)}encindex.h
+ractor.$(OBJEXT): {$(VPATH)}encoding.h
+ractor.$(OBJEXT): {$(VPATH)}eval_intern.h
+ractor.$(OBJEXT): {$(VPATH)}id.h
+ractor.$(OBJEXT): {$(VPATH)}id_table.h
+ractor.$(OBJEXT): {$(VPATH)}intern.h
+ractor.$(OBJEXT): {$(VPATH)}internal.h
+ractor.$(OBJEXT): {$(VPATH)}internal/abi.h
+ractor.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+ractor.$(OBJEXT): {$(VPATH)}internal/assume.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+ractor.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+ractor.$(OBJEXT): {$(VPATH)}internal/cast.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+ractor.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+ractor.$(OBJEXT): {$(VPATH)}internal/config.h
+ractor.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+ractor.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+ractor.$(OBJEXT): {$(VPATH)}internal/ctype.h
+ractor.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+ractor.$(OBJEXT): {$(VPATH)}internal/dosish.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+ractor.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+ractor.$(OBJEXT): {$(VPATH)}internal/error.h
+ractor.$(OBJEXT): {$(VPATH)}internal/eval.h
+ractor.$(OBJEXT): {$(VPATH)}internal/event.h
+ractor.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+ractor.$(OBJEXT): {$(VPATH)}internal/gc.h
+ractor.$(OBJEXT): {$(VPATH)}internal/glob.h
+ractor.$(OBJEXT): {$(VPATH)}internal/globals.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+ractor.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+ractor.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+ractor.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+ractor.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+ractor.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+ractor.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+ractor.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+ractor.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+ractor.$(OBJEXT): {$(VPATH)}internal/symbol.h
+ractor.$(OBJEXT): {$(VPATH)}internal/value.h
+ractor.$(OBJEXT): {$(VPATH)}internal/value_type.h
+ractor.$(OBJEXT): {$(VPATH)}internal/variable.h
+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)}node.h
+ractor.$(OBJEXT): {$(VPATH)}onigmo.h
+ractor.$(OBJEXT): {$(VPATH)}oniguruma.h
+ractor.$(OBJEXT): {$(VPATH)}ractor.c
+ractor.$(OBJEXT): {$(VPATH)}ractor.h
+ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc
+ractor.$(OBJEXT): {$(VPATH)}ractor_core.h
+ractor.$(OBJEXT): {$(VPATH)}ractor_sync.c
+ractor.$(OBJEXT): {$(VPATH)}re.h
+ractor.$(OBJEXT): {$(VPATH)}regex.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)}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
+ractor.$(OBJEXT): {$(VPATH)}zjit.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/box.h
+random.$(OBJEXT): $(top_srcdir)/internal/compar.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
+random.$(OBJEXT): $(top_srcdir)/internal/serial.h
+random.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+random.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+random.$(OBJEXT): $(top_srcdir)/internal/struct.h
+random.$(OBJEXT): $(top_srcdir)/internal/variable.h
+random.$(OBJEXT): $(top_srcdir)/internal/vm.h
+random.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+random.$(OBJEXT): {$(VPATH)}assert.h
+random.$(OBJEXT): {$(VPATH)}atomic.h
+random.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+random.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+random.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+random.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+random.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+random.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+random.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+random.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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
+random.$(OBJEXT): {$(VPATH)}internal/abi.h
+random.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+random.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+random.$(OBJEXT): {$(VPATH)}internal/assume.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+random.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+random.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+random.$(OBJEXT): {$(VPATH)}internal/cast.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+random.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+random.$(OBJEXT): {$(VPATH)}internal/config.h
+random.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+random.$(OBJEXT): {$(VPATH)}internal/core.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+random.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+random.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+random.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+random.$(OBJEXT): {$(VPATH)}internal/gc.h
+random.$(OBJEXT): {$(VPATH)}internal/glob.h
+random.$(OBJEXT): {$(VPATH)}internal/globals.h
+random.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+random.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+random.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+random.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+random.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+random.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+random.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+random.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+random.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+random.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+random.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+random.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+random.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+random.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+random.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+random.$(OBJEXT): {$(VPATH)}internal/symbol.h
+random.$(OBJEXT): {$(VPATH)}internal/value.h
+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
+range.$(OBJEXT): $(top_srcdir)/internal/bits.h
+range.$(OBJEXT): $(top_srcdir)/internal/compar.h
+range.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+range.$(OBJEXT): $(top_srcdir)/internal/enum.h
+range.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
+range.$(OBJEXT): $(top_srcdir)/internal/error.h
+range.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+range.$(OBJEXT): $(top_srcdir)/internal/gc.h
+range.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+range.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+range.$(OBJEXT): $(top_srcdir)/internal/range.h
+range.$(OBJEXT): $(top_srcdir)/internal/serial.h
+range.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+range.$(OBJEXT): $(top_srcdir)/internal/string.h
+range.$(OBJEXT): $(top_srcdir)/internal/struct.h
+range.$(OBJEXT): $(top_srcdir)/internal/vm.h
+range.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+range.$(OBJEXT): {$(VPATH)}assert.h
+range.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+range.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+range.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+range.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+range.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+range.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+range.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+range.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+range.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+range.$(OBJEXT): {$(VPATH)}config.h
+range.$(OBJEXT): {$(VPATH)}defines.h
+range.$(OBJEXT): {$(VPATH)}encindex.h
+range.$(OBJEXT): {$(VPATH)}encoding.h
+range.$(OBJEXT): {$(VPATH)}id.h
+range.$(OBJEXT): {$(VPATH)}id_table.h
+range.$(OBJEXT): {$(VPATH)}intern.h
+range.$(OBJEXT): {$(VPATH)}internal.h
+range.$(OBJEXT): {$(VPATH)}internal/abi.h
+range.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+range.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+range.$(OBJEXT): {$(VPATH)}internal/assume.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+range.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+range.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+range.$(OBJEXT): {$(VPATH)}internal/cast.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+range.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+range.$(OBJEXT): {$(VPATH)}internal/config.h
+range.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+range.$(OBJEXT): {$(VPATH)}internal/core.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+range.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+range.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+range.$(OBJEXT): {$(VPATH)}internal/ctype.h
+range.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+range.$(OBJEXT): {$(VPATH)}internal/dosish.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+range.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+range.$(OBJEXT): {$(VPATH)}internal/error.h
+range.$(OBJEXT): {$(VPATH)}internal/eval.h
+range.$(OBJEXT): {$(VPATH)}internal/event.h
+range.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+range.$(OBJEXT): {$(VPATH)}internal/gc.h
+range.$(OBJEXT): {$(VPATH)}internal/glob.h
+range.$(OBJEXT): {$(VPATH)}internal/globals.h
+range.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+range.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+range.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+range.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+range.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+range.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+range.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+range.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+range.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+range.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+range.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+range.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+range.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+range.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+range.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+range.$(OBJEXT): {$(VPATH)}internal/symbol.h
+range.$(OBJEXT): {$(VPATH)}internal/value.h
+range.$(OBJEXT): {$(VPATH)}internal/value_type.h
+range.$(OBJEXT): {$(VPATH)}internal/variable.h
+range.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+range.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+range.$(OBJEXT): {$(VPATH)}missing.h
+range.$(OBJEXT): {$(VPATH)}onigmo.h
+range.$(OBJEXT): {$(VPATH)}oniguruma.h
+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/box.h
+rational.$(OBJEXT): $(top_srcdir)/internal/class.h
+rational.$(OBJEXT): $(top_srcdir)/internal/compar.h
+rational.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+rational.$(OBJEXT): $(top_srcdir)/internal/complex.h
+rational.$(OBJEXT): $(top_srcdir)/internal/error.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
+rational.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+rational.$(OBJEXT): $(top_srcdir)/internal/serial.h
+rational.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+rational.$(OBJEXT): $(top_srcdir)/internal/string.h
+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
+rational.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+rational.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+rational.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+rational.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+rational.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}encindex.h
+rational.$(OBJEXT): {$(VPATH)}encoding.h
+rational.$(OBJEXT): {$(VPATH)}id.h
+rational.$(OBJEXT): {$(VPATH)}id_table.h
+rational.$(OBJEXT): {$(VPATH)}intern.h
+rational.$(OBJEXT): {$(VPATH)}internal.h
+rational.$(OBJEXT): {$(VPATH)}internal/abi.h
+rational.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+rational.$(OBJEXT): {$(VPATH)}internal/assume.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+rational.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+rational.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+rational.$(OBJEXT): {$(VPATH)}internal/cast.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+rational.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+rational.$(OBJEXT): {$(VPATH)}internal/config.h
+rational.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+rational.$(OBJEXT): {$(VPATH)}internal/core.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+rational.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+rational.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+rational.$(OBJEXT): {$(VPATH)}internal/gc.h
+rational.$(OBJEXT): {$(VPATH)}internal/glob.h
+rational.$(OBJEXT): {$(VPATH)}internal/globals.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+rational.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+rational.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+rational.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+rational.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+rational.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+rational.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+rational.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+rational.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+rational.$(OBJEXT): {$(VPATH)}internal/symbol.h
+rational.$(OBJEXT): {$(VPATH)}internal/value.h
+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/bignum.h
+re.$(OBJEXT): $(top_srcdir)/internal/bits.h
+re.$(OBJEXT): $(top_srcdir)/internal/box.h
+re.$(OBJEXT): $(top_srcdir)/internal/class.h
+re.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+re.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+re.$(OBJEXT): $(top_srcdir)/internal/error.h
+re.$(OBJEXT): $(top_srcdir)/internal/gc.h
+re.$(OBJEXT): $(top_srcdir)/internal/hash.h
+re.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+re.$(OBJEXT): $(top_srcdir)/internal/object.h
+re.$(OBJEXT): $(top_srcdir)/internal/ractor.h
+re.$(OBJEXT): $(top_srcdir)/internal/re.h
+re.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+re.$(OBJEXT): $(top_srcdir)/internal/serial.h
+re.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+re.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+re.$(OBJEXT): $(top_srcdir)/internal/string.h
+re.$(OBJEXT): $(top_srcdir)/internal/struct.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
+re.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+re.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+re.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+re.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+re.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+re.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+re.$(OBJEXT): {$(VPATH)}config.h
+re.$(OBJEXT): {$(VPATH)}constant.h
+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
+re.$(OBJEXT): {$(VPATH)}internal/abi.h
+re.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+re.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+re.$(OBJEXT): {$(VPATH)}internal/assume.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+re.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+re.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+re.$(OBJEXT): {$(VPATH)}internal/cast.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+re.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+re.$(OBJEXT): {$(VPATH)}internal/config.h
+re.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+re.$(OBJEXT): {$(VPATH)}internal/core.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+re.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+re.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+re.$(OBJEXT): {$(VPATH)}internal/ctype.h
+re.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+re.$(OBJEXT): {$(VPATH)}internal/dosish.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+re.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+re.$(OBJEXT): {$(VPATH)}internal/error.h
+re.$(OBJEXT): {$(VPATH)}internal/eval.h
+re.$(OBJEXT): {$(VPATH)}internal/event.h
+re.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+re.$(OBJEXT): {$(VPATH)}internal/gc.h
+re.$(OBJEXT): {$(VPATH)}internal/glob.h
+re.$(OBJEXT): {$(VPATH)}internal/globals.h
+re.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+re.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+re.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+re.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+re.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+re.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+re.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+re.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+re.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+re.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+re.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+re.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+re.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+re.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+re.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+re.$(OBJEXT): {$(VPATH)}internal/symbol.h
+re.$(OBJEXT): {$(VPATH)}internal/value.h
+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)}ractor.h
+re.$(OBJEXT): {$(VPATH)}ractor_core.h
+re.$(OBJEXT): {$(VPATH)}re.c
+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_debug.h
+re.$(OBJEXT): {$(VPATH)}vm_opts.h
+regcomp.$(OBJEXT): $(hdrdir)/ruby.h
+regcomp.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+regcomp.$(OBJEXT): {$(VPATH)}assert.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+regcomp.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+regcomp.$(OBJEXT): {$(VPATH)}config.h
+regcomp.$(OBJEXT): {$(VPATH)}defines.h
+regcomp.$(OBJEXT): {$(VPATH)}intern.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/abi.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/assume.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/cast.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/config.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/ctype.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/dosish.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/error.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/eval.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/event.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/gc.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/glob.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/globals.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/symbol.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/value.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/value_type.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/variable.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+regcomp.$(OBJEXT): {$(VPATH)}missing.h
+regcomp.$(OBJEXT): {$(VPATH)}onigmo.h
+regcomp.$(OBJEXT): {$(VPATH)}regcomp.c
+regcomp.$(OBJEXT): {$(VPATH)}regenc.h
+regcomp.$(OBJEXT): {$(VPATH)}regint.h
+regcomp.$(OBJEXT): {$(VPATH)}regparse.h
+regcomp.$(OBJEXT): {$(VPATH)}st.h
+regcomp.$(OBJEXT): {$(VPATH)}subst.h
+regenc.$(OBJEXT): $(hdrdir)/ruby.h
+regenc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+regenc.$(OBJEXT): {$(VPATH)}assert.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+regenc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+regenc.$(OBJEXT): {$(VPATH)}config.h
+regenc.$(OBJEXT): {$(VPATH)}defines.h
+regenc.$(OBJEXT): {$(VPATH)}intern.h
+regenc.$(OBJEXT): {$(VPATH)}internal/abi.h
+regenc.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+regenc.$(OBJEXT): {$(VPATH)}internal/assume.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+regenc.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+regenc.$(OBJEXT): {$(VPATH)}internal/cast.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+regenc.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+regenc.$(OBJEXT): {$(VPATH)}internal/config.h
+regenc.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+regenc.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+regenc.$(OBJEXT): {$(VPATH)}internal/ctype.h
+regenc.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+regenc.$(OBJEXT): {$(VPATH)}internal/dosish.h
+regenc.$(OBJEXT): {$(VPATH)}internal/error.h
+regenc.$(OBJEXT): {$(VPATH)}internal/eval.h
+regenc.$(OBJEXT): {$(VPATH)}internal/event.h
+regenc.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+regenc.$(OBJEXT): {$(VPATH)}internal/gc.h
+regenc.$(OBJEXT): {$(VPATH)}internal/glob.h
+regenc.$(OBJEXT): {$(VPATH)}internal/globals.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+regenc.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+regenc.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+regenc.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+regenc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+regenc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+regenc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+regenc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+regenc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+regenc.$(OBJEXT): {$(VPATH)}internal/symbol.h
+regenc.$(OBJEXT): {$(VPATH)}internal/value.h
+regenc.$(OBJEXT): {$(VPATH)}internal/value_type.h
+regenc.$(OBJEXT): {$(VPATH)}internal/variable.h
+regenc.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+regenc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+regenc.$(OBJEXT): {$(VPATH)}missing.h
+regenc.$(OBJEXT): {$(VPATH)}onigmo.h
+regenc.$(OBJEXT): {$(VPATH)}regenc.c
+regenc.$(OBJEXT): {$(VPATH)}regenc.h
+regenc.$(OBJEXT): {$(VPATH)}regint.h
+regenc.$(OBJEXT): {$(VPATH)}st.h
+regenc.$(OBJEXT): {$(VPATH)}subst.h
+regerror.$(OBJEXT): $(hdrdir)/ruby.h
+regerror.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+regerror.$(OBJEXT): {$(VPATH)}assert.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+regerror.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+regerror.$(OBJEXT): {$(VPATH)}config.h
+regerror.$(OBJEXT): {$(VPATH)}defines.h
+regerror.$(OBJEXT): {$(VPATH)}intern.h
+regerror.$(OBJEXT): {$(VPATH)}internal/abi.h
+regerror.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+regerror.$(OBJEXT): {$(VPATH)}internal/assume.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+regerror.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+regerror.$(OBJEXT): {$(VPATH)}internal/cast.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+regerror.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+regerror.$(OBJEXT): {$(VPATH)}internal/config.h
+regerror.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+regerror.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+regerror.$(OBJEXT): {$(VPATH)}internal/ctype.h
+regerror.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+regerror.$(OBJEXT): {$(VPATH)}internal/dosish.h
+regerror.$(OBJEXT): {$(VPATH)}internal/error.h
+regerror.$(OBJEXT): {$(VPATH)}internal/eval.h
+regerror.$(OBJEXT): {$(VPATH)}internal/event.h
+regerror.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+regerror.$(OBJEXT): {$(VPATH)}internal/gc.h
+regerror.$(OBJEXT): {$(VPATH)}internal/glob.h
+regerror.$(OBJEXT): {$(VPATH)}internal/globals.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+regerror.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+regerror.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+regerror.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+regerror.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+regerror.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+regerror.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+regerror.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+regerror.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+regerror.$(OBJEXT): {$(VPATH)}internal/symbol.h
+regerror.$(OBJEXT): {$(VPATH)}internal/value.h
+regerror.$(OBJEXT): {$(VPATH)}internal/value_type.h
+regerror.$(OBJEXT): {$(VPATH)}internal/variable.h
+regerror.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+regerror.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+regerror.$(OBJEXT): {$(VPATH)}missing.h
+regerror.$(OBJEXT): {$(VPATH)}onigmo.h
+regerror.$(OBJEXT): {$(VPATH)}regenc.h
+regerror.$(OBJEXT): {$(VPATH)}regerror.c
+regerror.$(OBJEXT): {$(VPATH)}regint.h
+regerror.$(OBJEXT): {$(VPATH)}st.h
+regerror.$(OBJEXT): {$(VPATH)}subst.h
+regexec.$(OBJEXT): $(hdrdir)/ruby.h
+regexec.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+regexec.$(OBJEXT): {$(VPATH)}assert.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+regexec.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+regexec.$(OBJEXT): {$(VPATH)}config.h
+regexec.$(OBJEXT): {$(VPATH)}defines.h
+regexec.$(OBJEXT): {$(VPATH)}intern.h
+regexec.$(OBJEXT): {$(VPATH)}internal/abi.h
+regexec.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+regexec.$(OBJEXT): {$(VPATH)}internal/assume.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+regexec.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+regexec.$(OBJEXT): {$(VPATH)}internal/cast.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+regexec.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+regexec.$(OBJEXT): {$(VPATH)}internal/config.h
+regexec.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+regexec.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+regexec.$(OBJEXT): {$(VPATH)}internal/ctype.h
+regexec.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+regexec.$(OBJEXT): {$(VPATH)}internal/dosish.h
+regexec.$(OBJEXT): {$(VPATH)}internal/error.h
+regexec.$(OBJEXT): {$(VPATH)}internal/eval.h
+regexec.$(OBJEXT): {$(VPATH)}internal/event.h
+regexec.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+regexec.$(OBJEXT): {$(VPATH)}internal/gc.h
+regexec.$(OBJEXT): {$(VPATH)}internal/glob.h
+regexec.$(OBJEXT): {$(VPATH)}internal/globals.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+regexec.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+regexec.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+regexec.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+regexec.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+regexec.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+regexec.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+regexec.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+regexec.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+regexec.$(OBJEXT): {$(VPATH)}internal/symbol.h
+regexec.$(OBJEXT): {$(VPATH)}internal/value.h
+regexec.$(OBJEXT): {$(VPATH)}internal/value_type.h
+regexec.$(OBJEXT): {$(VPATH)}internal/variable.h
+regexec.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+regexec.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+regexec.$(OBJEXT): {$(VPATH)}missing.h
+regexec.$(OBJEXT): {$(VPATH)}onigmo.h
+regexec.$(OBJEXT): {$(VPATH)}regenc.h
+regexec.$(OBJEXT): {$(VPATH)}regexec.c
+regexec.$(OBJEXT): {$(VPATH)}regint.h
+regexec.$(OBJEXT): {$(VPATH)}st.h
+regexec.$(OBJEXT): {$(VPATH)}subst.h
+regparse.$(OBJEXT): $(hdrdir)/ruby.h
+regparse.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+regparse.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+regparse.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+regparse.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+regparse.$(OBJEXT): {$(VPATH)}assert.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+regparse.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+regparse.$(OBJEXT): {$(VPATH)}config.h
+regparse.$(OBJEXT): {$(VPATH)}defines.h
+regparse.$(OBJEXT): {$(VPATH)}intern.h
+regparse.$(OBJEXT): {$(VPATH)}internal/abi.h
+regparse.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+regparse.$(OBJEXT): {$(VPATH)}internal/assume.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+regparse.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+regparse.$(OBJEXT): {$(VPATH)}internal/cast.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+regparse.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+regparse.$(OBJEXT): {$(VPATH)}internal/config.h
+regparse.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+regparse.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+regparse.$(OBJEXT): {$(VPATH)}internal/ctype.h
+regparse.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+regparse.$(OBJEXT): {$(VPATH)}internal/dosish.h
+regparse.$(OBJEXT): {$(VPATH)}internal/error.h
+regparse.$(OBJEXT): {$(VPATH)}internal/eval.h
+regparse.$(OBJEXT): {$(VPATH)}internal/event.h
+regparse.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+regparse.$(OBJEXT): {$(VPATH)}internal/gc.h
+regparse.$(OBJEXT): {$(VPATH)}internal/glob.h
+regparse.$(OBJEXT): {$(VPATH)}internal/globals.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+regparse.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+regparse.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+regparse.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+regparse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+regparse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+regparse.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+regparse.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+regparse.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+regparse.$(OBJEXT): {$(VPATH)}internal/symbol.h
+regparse.$(OBJEXT): {$(VPATH)}internal/value.h
+regparse.$(OBJEXT): {$(VPATH)}internal/value_type.h
+regparse.$(OBJEXT): {$(VPATH)}internal/variable.h
+regparse.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+regparse.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+regparse.$(OBJEXT): {$(VPATH)}missing.h
+regparse.$(OBJEXT): {$(VPATH)}onigmo.h
+regparse.$(OBJEXT): {$(VPATH)}regenc.h
+regparse.$(OBJEXT): {$(VPATH)}regint.h
+regparse.$(OBJEXT): {$(VPATH)}regparse.c
+regparse.$(OBJEXT): {$(VPATH)}regparse.h
+regparse.$(OBJEXT): {$(VPATH)}st.h
+regparse.$(OBJEXT): {$(VPATH)}subst.h
+regsyntax.$(OBJEXT): $(hdrdir)/ruby.h
+regsyntax.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+regsyntax.$(OBJEXT): {$(VPATH)}assert.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+regsyntax.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+regsyntax.$(OBJEXT): {$(VPATH)}config.h
+regsyntax.$(OBJEXT): {$(VPATH)}defines.h
+regsyntax.$(OBJEXT): {$(VPATH)}intern.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/abi.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/assume.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/cast.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/config.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/ctype.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/dosish.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/error.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/eval.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/event.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/gc.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/glob.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/globals.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/symbol.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/value.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/value_type.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/variable.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+regsyntax.$(OBJEXT): {$(VPATH)}missing.h
+regsyntax.$(OBJEXT): {$(VPATH)}onigmo.h
+regsyntax.$(OBJEXT): {$(VPATH)}regenc.h
+regsyntax.$(OBJEXT): {$(VPATH)}regint.h
+regsyntax.$(OBJEXT): {$(VPATH)}regsyntax.c
+regsyntax.$(OBJEXT): {$(VPATH)}st.h
+regsyntax.$(OBJEXT): {$(VPATH)}subst.h
+ruby-runner.$(OBJEXT): {$(VPATH)}config.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+ruby-runner.$(OBJEXT): {$(VPATH)}internal/config.h
+ruby-runner.$(OBJEXT): {$(VPATH)}ruby-runner.c
+ruby-runner.$(OBJEXT): {$(VPATH)}ruby-runner.h
+ruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+ruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+ruby.$(OBJEXT): $(CCAN_DIR)/list/list.h
+ruby.$(OBJEXT): $(CCAN_DIR)/str/str.h
+ruby.$(OBJEXT): $(hdrdir)/ruby.h
+ruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+ruby.$(OBJEXT): $(hdrdir)/ruby/version.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/array.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/bits.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/box.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/class.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/compar.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/cont.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/error.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/file.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/inits.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/io.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/load.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/loadpath.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/missing.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/object.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/string.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/ast.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/comments.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/integer.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/json.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/node.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/source.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/stream.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+ruby.$(OBJEXT): $(top_srcdir)/prism/version.h
+ruby.$(OBJEXT): {$(VPATH)}assert.h
+ruby.$(OBJEXT): {$(VPATH)}atomic.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+ruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+ruby.$(OBJEXT): {$(VPATH)}config.h
+ruby.$(OBJEXT): {$(VPATH)}constant.h
+ruby.$(OBJEXT): {$(VPATH)}debug_counter.h
+ruby.$(OBJEXT): {$(VPATH)}defines.h
+ruby.$(OBJEXT): {$(VPATH)}dln.h
+ruby.$(OBJEXT): {$(VPATH)}encindex.h
+ruby.$(OBJEXT): {$(VPATH)}encoding.h
+ruby.$(OBJEXT): {$(VPATH)}eval_intern.h
+ruby.$(OBJEXT): {$(VPATH)}id.h
+ruby.$(OBJEXT): {$(VPATH)}id_table.h
+ruby.$(OBJEXT): {$(VPATH)}intern.h
+ruby.$(OBJEXT): {$(VPATH)}internal.h
+ruby.$(OBJEXT): {$(VPATH)}internal/abi.h
+ruby.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+ruby.$(OBJEXT): {$(VPATH)}internal/assume.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+ruby.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+ruby.$(OBJEXT): {$(VPATH)}internal/cast.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+ruby.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+ruby.$(OBJEXT): {$(VPATH)}internal/config.h
+ruby.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+ruby.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+ruby.$(OBJEXT): {$(VPATH)}internal/ctype.h
+ruby.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+ruby.$(OBJEXT): {$(VPATH)}internal/dosish.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+ruby.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+ruby.$(OBJEXT): {$(VPATH)}internal/error.h
+ruby.$(OBJEXT): {$(VPATH)}internal/eval.h
+ruby.$(OBJEXT): {$(VPATH)}internal/event.h
+ruby.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+ruby.$(OBJEXT): {$(VPATH)}internal/gc.h
+ruby.$(OBJEXT): {$(VPATH)}internal/glob.h
+ruby.$(OBJEXT): {$(VPATH)}internal/globals.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+ruby.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+ruby.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+ruby.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+ruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+ruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+ruby.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+ruby.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+ruby.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+ruby.$(OBJEXT): {$(VPATH)}internal/symbol.h
+ruby.$(OBJEXT): {$(VPATH)}internal/value.h
+ruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
+ruby.$(OBJEXT): {$(VPATH)}internal/variable.h
+ruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+ruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+ruby.$(OBJEXT): {$(VPATH)}io.h
+ruby.$(OBJEXT): {$(VPATH)}iseq.h
+ruby.$(OBJEXT): {$(VPATH)}method.h
+ruby.$(OBJEXT): {$(VPATH)}missing.h
+ruby.$(OBJEXT): {$(VPATH)}node.h
+ruby.$(OBJEXT): {$(VPATH)}onigmo.h
+ruby.$(OBJEXT): {$(VPATH)}oniguruma.h
+ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
+ruby.$(OBJEXT): {$(VPATH)}prism_xallocator.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
+ruby.$(OBJEXT): {$(VPATH)}thread.h
+ruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+ruby.$(OBJEXT): {$(VPATH)}thread_native.h
+ruby.$(OBJEXT): {$(VPATH)}util.h
+ruby.$(OBJEXT): {$(VPATH)}vm_core.h
+ruby.$(OBJEXT): {$(VPATH)}vm_opts.h
+ruby.$(OBJEXT): {$(VPATH)}yjit.h
+ruby.$(OBJEXT): {$(VPATH)}zjit.h
+ruby_parser.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/array.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bits.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/compar.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/complex.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/error.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/parse.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/rational.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/re.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/serial.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/string.h
+ruby_parser.$(OBJEXT): $(top_srcdir)/internal/vm.h
+ruby_parser.$(OBJEXT): {$(VPATH)}assert.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+ruby_parser.$(OBJEXT): {$(VPATH)}config.h
+ruby_parser.$(OBJEXT): {$(VPATH)}defines.h
+ruby_parser.$(OBJEXT): {$(VPATH)}encindex.h
+ruby_parser.$(OBJEXT): {$(VPATH)}encoding.h
+ruby_parser.$(OBJEXT): {$(VPATH)}intern.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/abi.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/assume.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/cast.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/config.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/ctype.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/dosish.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/error.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/eval.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/event.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/gc.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/glob.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/globals.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/iterator.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/memory.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/method.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/module.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/symbol.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/value.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/value_type.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/variable.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+ruby_parser.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+ruby_parser.$(OBJEXT): {$(VPATH)}missing.h
+ruby_parser.$(OBJEXT): {$(VPATH)}node.h
+ruby_parser.$(OBJEXT): {$(VPATH)}onigmo.h
+ruby_parser.$(OBJEXT): {$(VPATH)}oniguruma.h
+ruby_parser.$(OBJEXT): {$(VPATH)}re.h
+ruby_parser.$(OBJEXT): {$(VPATH)}regex.h
+ruby_parser.$(OBJEXT): {$(VPATH)}ruby_assert.h
+ruby_parser.$(OBJEXT): {$(VPATH)}ruby_parser.c
+ruby_parser.$(OBJEXT): {$(VPATH)}rubyparser.h
+ruby_parser.$(OBJEXT): {$(VPATH)}st.h
+ruby_parser.$(OBJEXT): {$(VPATH)}subst.h
+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
+scheduler.$(OBJEXT): $(CCAN_DIR)/str/str.h
+scheduler.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/array.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/box.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/thread.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/variable.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.h
+scheduler.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+scheduler.$(OBJEXT): {$(VPATH)}assert.h
+scheduler.$(OBJEXT): {$(VPATH)}atomic.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+scheduler.$(OBJEXT): {$(VPATH)}config.h
+scheduler.$(OBJEXT): {$(VPATH)}constant.h
+scheduler.$(OBJEXT): {$(VPATH)}defines.h
+scheduler.$(OBJEXT): {$(VPATH)}encoding.h
+scheduler.$(OBJEXT): {$(VPATH)}eval_intern.h
+scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+scheduler.$(OBJEXT): {$(VPATH)}id.h
+scheduler.$(OBJEXT): {$(VPATH)}id_table.h
+scheduler.$(OBJEXT): {$(VPATH)}intern.h
+scheduler.$(OBJEXT): {$(VPATH)}internal.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/abi.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/assume.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/cast.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/config.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/ctype.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/dosish.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/error.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/eval.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/event.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/gc.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/glob.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/globals.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/symbol.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/value.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/value_type.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/variable.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+scheduler.$(OBJEXT): {$(VPATH)}io.h
+scheduler.$(OBJEXT): {$(VPATH)}io/buffer.h
+scheduler.$(OBJEXT): {$(VPATH)}method.h
+scheduler.$(OBJEXT): {$(VPATH)}missing.h
+scheduler.$(OBJEXT): {$(VPATH)}node.h
+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
+scheduler.$(OBJEXT): {$(VPATH)}subst.h
+scheduler.$(OBJEXT): {$(VPATH)}thread.h
+scheduler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+scheduler.$(OBJEXT): {$(VPATH)}thread_native.h
+scheduler.$(OBJEXT): {$(VPATH)}vm_core.h
+scheduler.$(OBJEXT): {$(VPATH)}vm_opts.h
+scheduler.$(OBJEXT): {$(VPATH)}zjit.h
+set.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+set.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+set.$(OBJEXT): $(CCAN_DIR)/list/list.h
+set.$(OBJEXT): $(CCAN_DIR)/str/str.h
+set.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+set.$(OBJEXT): $(top_srcdir)/internal/array.h
+set.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+set.$(OBJEXT): $(top_srcdir)/internal/bits.h
+set.$(OBJEXT): $(top_srcdir)/internal/box.h
+set.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+set.$(OBJEXT): $(top_srcdir)/internal/error.h
+set.$(OBJEXT): $(top_srcdir)/internal/gc.h
+set.$(OBJEXT): $(top_srcdir)/internal/hash.h
+set.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+set.$(OBJEXT): $(top_srcdir)/internal/proc.h
+set.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+set.$(OBJEXT): $(top_srcdir)/internal/serial.h
+set.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+set.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+set.$(OBJEXT): $(top_srcdir)/internal/string.h
+set.$(OBJEXT): $(top_srcdir)/internal/struct.h
+set.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+set.$(OBJEXT): $(top_srcdir)/internal/variable.h
+set.$(OBJEXT): $(top_srcdir)/internal/vm.h
+set.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+set.$(OBJEXT): {$(VPATH)}assert.h
+set.$(OBJEXT): {$(VPATH)}atomic.h
+set.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+set.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+set.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+set.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+set.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+set.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+set.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+set.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+set.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+set.$(OBJEXT): {$(VPATH)}config.h
+set.$(OBJEXT): {$(VPATH)}constant.h
+set.$(OBJEXT): {$(VPATH)}defines.h
+set.$(OBJEXT): {$(VPATH)}encindex.h
+set.$(OBJEXT): {$(VPATH)}encoding.h
+set.$(OBJEXT): {$(VPATH)}id.h
+set.$(OBJEXT): {$(VPATH)}id_table.h
+set.$(OBJEXT): {$(VPATH)}intern.h
+set.$(OBJEXT): {$(VPATH)}internal.h
+set.$(OBJEXT): {$(VPATH)}internal/abi.h
+set.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+set.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+set.$(OBJEXT): {$(VPATH)}internal/assume.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+set.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+set.$(OBJEXT): {$(VPATH)}internal/cast.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+set.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+set.$(OBJEXT): {$(VPATH)}internal/config.h
+set.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+set.$(OBJEXT): {$(VPATH)}internal/core.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+set.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+set.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+set.$(OBJEXT): {$(VPATH)}internal/ctype.h
+set.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+set.$(OBJEXT): {$(VPATH)}internal/dosish.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+set.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+set.$(OBJEXT): {$(VPATH)}internal/error.h
+set.$(OBJEXT): {$(VPATH)}internal/eval.h
+set.$(OBJEXT): {$(VPATH)}internal/event.h
+set.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+set.$(OBJEXT): {$(VPATH)}internal/gc.h
+set.$(OBJEXT): {$(VPATH)}internal/glob.h
+set.$(OBJEXT): {$(VPATH)}internal/globals.h
+set.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+set.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+set.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+set.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+set.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+set.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+set.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+set.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+set.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+set.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+set.$(OBJEXT): {$(VPATH)}internal/iterator.h
+set.$(OBJEXT): {$(VPATH)}internal/memory.h
+set.$(OBJEXT): {$(VPATH)}internal/method.h
+set.$(OBJEXT): {$(VPATH)}internal/module.h
+set.$(OBJEXT): {$(VPATH)}internal/newobj.h
+set.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+set.$(OBJEXT): {$(VPATH)}internal/set_table.h
+set.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+set.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+set.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+set.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+set.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+set.$(OBJEXT): {$(VPATH)}internal/symbol.h
+set.$(OBJEXT): {$(VPATH)}internal/value.h
+set.$(OBJEXT): {$(VPATH)}internal/value_type.h
+set.$(OBJEXT): {$(VPATH)}internal/variable.h
+set.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+set.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+set.$(OBJEXT): {$(VPATH)}method.h
+set.$(OBJEXT): {$(VPATH)}missing.h
+set.$(OBJEXT): {$(VPATH)}node.h
+set.$(OBJEXT): {$(VPATH)}onigmo.h
+set.$(OBJEXT): {$(VPATH)}oniguruma.h
+set.$(OBJEXT): {$(VPATH)}ruby_assert.h
+set.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+set.$(OBJEXT): {$(VPATH)}rubyparser.h
+set.$(OBJEXT): {$(VPATH)}set.c
+set.$(OBJEXT): {$(VPATH)}shape.h
+set.$(OBJEXT): {$(VPATH)}st.h
+set.$(OBJEXT): {$(VPATH)}subst.h
+set.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+set.$(OBJEXT): {$(VPATH)}thread_native.h
+set.$(OBJEXT): {$(VPATH)}vm_core.h
+set.$(OBJEXT): {$(VPATH)}vm_opts.h
+setproctitle.$(OBJEXT): $(hdrdir)/ruby.h
+setproctitle.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+setproctitle.$(OBJEXT): {$(VPATH)}assert.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+setproctitle.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+setproctitle.$(OBJEXT): {$(VPATH)}config.h
+setproctitle.$(OBJEXT): {$(VPATH)}defines.h
+setproctitle.$(OBJEXT): {$(VPATH)}intern.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/abi.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/assume.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/cast.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/config.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/ctype.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/dosish.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/error.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/eval.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/event.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/gc.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/glob.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/globals.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/symbol.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/value.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/value_type.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/variable.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+setproctitle.$(OBJEXT): {$(VPATH)}missing.h
+setproctitle.$(OBJEXT): {$(VPATH)}setproctitle.c
+setproctitle.$(OBJEXT): {$(VPATH)}st.h
+setproctitle.$(OBJEXT): {$(VPATH)}subst.h
+setproctitle.$(OBJEXT): {$(VPATH)}util.h
+shape.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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/box.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/sanitizers.h
+shape.$(OBJEXT): $(top_srcdir)/internal/serial.h
+shape.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+shape.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+shape.$(OBJEXT): $(top_srcdir)/internal/string.h
+shape.$(OBJEXT): $(top_srcdir)/internal/struct.h
+shape.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+shape.$(OBJEXT): $(top_srcdir)/internal/variable.h
+shape.$(OBJEXT): $(top_srcdir)/internal/vm.h
+shape.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+shape.$(OBJEXT): {$(VPATH)}assert.h
+shape.$(OBJEXT): {$(VPATH)}atomic.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+shape.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+shape.$(OBJEXT): {$(VPATH)}config.h
+shape.$(OBJEXT): {$(VPATH)}constant.h
+shape.$(OBJEXT): {$(VPATH)}debug_counter.h
+shape.$(OBJEXT): {$(VPATH)}defines.h
+shape.$(OBJEXT): {$(VPATH)}encindex.h
+shape.$(OBJEXT): {$(VPATH)}encoding.h
+shape.$(OBJEXT): {$(VPATH)}id.h
+shape.$(OBJEXT): {$(VPATH)}id_table.h
+shape.$(OBJEXT): {$(VPATH)}intern.h
+shape.$(OBJEXT): {$(VPATH)}internal.h
+shape.$(OBJEXT): {$(VPATH)}internal/abi.h
+shape.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+shape.$(OBJEXT): {$(VPATH)}internal/assume.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+shape.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+shape.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+shape.$(OBJEXT): {$(VPATH)}internal/cast.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+shape.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+shape.$(OBJEXT): {$(VPATH)}internal/config.h
+shape.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+shape.$(OBJEXT): {$(VPATH)}internal/core.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+shape.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+shape.$(OBJEXT): {$(VPATH)}internal/ctype.h
+shape.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+shape.$(OBJEXT): {$(VPATH)}internal/dosish.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+shape.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+shape.$(OBJEXT): {$(VPATH)}internal/error.h
+shape.$(OBJEXT): {$(VPATH)}internal/eval.h
+shape.$(OBJEXT): {$(VPATH)}internal/event.h
+shape.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+shape.$(OBJEXT): {$(VPATH)}internal/gc.h
+shape.$(OBJEXT): {$(VPATH)}internal/glob.h
+shape.$(OBJEXT): {$(VPATH)}internal/globals.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+shape.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+shape.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+shape.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+shape.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+shape.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+shape.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+shape.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+shape.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+shape.$(OBJEXT): {$(VPATH)}internal/symbol.h
+shape.$(OBJEXT): {$(VPATH)}internal/value.h
+shape.$(OBJEXT): {$(VPATH)}internal/value_type.h
+shape.$(OBJEXT): {$(VPATH)}internal/variable.h
+shape.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+shape.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+shape.$(OBJEXT): {$(VPATH)}method.h
+shape.$(OBJEXT): {$(VPATH)}missing.h
+shape.$(OBJEXT): {$(VPATH)}node.h
+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
+shape.$(OBJEXT): {$(VPATH)}subst.h
+shape.$(OBJEXT): {$(VPATH)}symbol.h
+shape.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+shape.$(OBJEXT): {$(VPATH)}thread_native.h
+shape.$(OBJEXT): {$(VPATH)}variable.h
+shape.$(OBJEXT): {$(VPATH)}vm_core.h
+shape.$(OBJEXT): {$(VPATH)}vm_debug.h
+shape.$(OBJEXT): {$(VPATH)}vm_opts.h
+shape.$(OBJEXT): {$(VPATH)}vm_sync.h
+signal.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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/box.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
+signal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+signal.$(OBJEXT): $(top_srcdir)/internal/serial.h
+signal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+signal.$(OBJEXT): $(top_srcdir)/internal/signal.h
+signal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+signal.$(OBJEXT): $(top_srcdir)/internal/string.h
+signal.$(OBJEXT): $(top_srcdir)/internal/thread.h
+signal.$(OBJEXT): $(top_srcdir)/internal/variable.h
+signal.$(OBJEXT): $(top_srcdir)/internal/vm.h
+signal.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+signal.$(OBJEXT): {$(VPATH)}assert.h
+signal.$(OBJEXT): {$(VPATH)}atomic.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+signal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+signal.$(OBJEXT): {$(VPATH)}config.h
+signal.$(OBJEXT): {$(VPATH)}constant.h
+signal.$(OBJEXT): {$(VPATH)}debug_counter.h
+signal.$(OBJEXT): {$(VPATH)}defines.h
+signal.$(OBJEXT): {$(VPATH)}encindex.h
+signal.$(OBJEXT): {$(VPATH)}encoding.h
+signal.$(OBJEXT): {$(VPATH)}eval_intern.h
+signal.$(OBJEXT): {$(VPATH)}id.h
+signal.$(OBJEXT): {$(VPATH)}id_table.h
+signal.$(OBJEXT): {$(VPATH)}intern.h
+signal.$(OBJEXT): {$(VPATH)}internal.h
+signal.$(OBJEXT): {$(VPATH)}internal/abi.h
+signal.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+signal.$(OBJEXT): {$(VPATH)}internal/assume.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+signal.$(OBJEXT): {$(VPATH)}internal/cast.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+signal.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+signal.$(OBJEXT): {$(VPATH)}internal/config.h
+signal.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+signal.$(OBJEXT): {$(VPATH)}internal/core.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+signal.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+signal.$(OBJEXT): {$(VPATH)}internal/ctype.h
+signal.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+signal.$(OBJEXT): {$(VPATH)}internal/dosish.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+signal.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+signal.$(OBJEXT): {$(VPATH)}internal/error.h
+signal.$(OBJEXT): {$(VPATH)}internal/eval.h
+signal.$(OBJEXT): {$(VPATH)}internal/event.h
+signal.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+signal.$(OBJEXT): {$(VPATH)}internal/gc.h
+signal.$(OBJEXT): {$(VPATH)}internal/glob.h
+signal.$(OBJEXT): {$(VPATH)}internal/globals.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+signal.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+signal.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+signal.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+signal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+signal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+signal.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+signal.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+signal.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+signal.$(OBJEXT): {$(VPATH)}internal/symbol.h
+signal.$(OBJEXT): {$(VPATH)}internal/value.h
+signal.$(OBJEXT): {$(VPATH)}internal/value_type.h
+signal.$(OBJEXT): {$(VPATH)}internal/variable.h
+signal.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+signal.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+signal.$(OBJEXT): {$(VPATH)}method.h
+signal.$(OBJEXT): {$(VPATH)}missing.h
+signal.$(OBJEXT): {$(VPATH)}node.h
+signal.$(OBJEXT): {$(VPATH)}onigmo.h
+signal.$(OBJEXT): {$(VPATH)}oniguruma.h
+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
+signal.$(OBJEXT): {$(VPATH)}subst.h
+signal.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+signal.$(OBJEXT): {$(VPATH)}thread_native.h
+signal.$(OBJEXT): {$(VPATH)}vm_core.h
+signal.$(OBJEXT): {$(VPATH)}vm_debug.h
+signal.$(OBJEXT): {$(VPATH)}vm_opts.h
+signal.$(OBJEXT): {$(VPATH)}zjit.h
+sprintf.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+sprintf.$(OBJEXT): $(hdrdir)/ruby/version.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/bits.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/class.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/compar.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/error.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/gc.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/hash.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/object.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/serial.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/string.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/variable.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/vm.h
+sprintf.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+sprintf.$(OBJEXT): {$(VPATH)}assert.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+sprintf.$(OBJEXT): {$(VPATH)}config.h
+sprintf.$(OBJEXT): {$(VPATH)}constant.h
+sprintf.$(OBJEXT): {$(VPATH)}defines.h
+sprintf.$(OBJEXT): {$(VPATH)}encindex.h
+sprintf.$(OBJEXT): {$(VPATH)}encoding.h
+sprintf.$(OBJEXT): {$(VPATH)}id.h
+sprintf.$(OBJEXT): {$(VPATH)}id_table.h
+sprintf.$(OBJEXT): {$(VPATH)}intern.h
+sprintf.$(OBJEXT): {$(VPATH)}internal.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/abi.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/assume.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/cast.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/config.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/ctype.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/dosish.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/error.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/eval.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/event.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/gc.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/glob.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/globals.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/symbol.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/value.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/value_type.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/variable.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+sprintf.$(OBJEXT): {$(VPATH)}missing.h
+sprintf.$(OBJEXT): {$(VPATH)}onigmo.h
+sprintf.$(OBJEXT): {$(VPATH)}oniguruma.h
+sprintf.$(OBJEXT): {$(VPATH)}re.h
+sprintf.$(OBJEXT): {$(VPATH)}regex.h
+sprintf.$(OBJEXT): {$(VPATH)}shape.h
+sprintf.$(OBJEXT): {$(VPATH)}sprintf.c
+sprintf.$(OBJEXT): {$(VPATH)}st.h
+sprintf.$(OBJEXT): {$(VPATH)}subst.h
+sprintf.$(OBJEXT): {$(VPATH)}util.h
+sprintf.$(OBJEXT): {$(VPATH)}vsnprintf.c
+st.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+st.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+st.$(OBJEXT): $(CCAN_DIR)/list/list.h
+st.$(OBJEXT): $(CCAN_DIR)/str/str.h
+st.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+st.$(OBJEXT): $(top_srcdir)/internal/array.h
+st.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+st.$(OBJEXT): $(top_srcdir)/internal/bits.h
+st.$(OBJEXT): $(top_srcdir)/internal/box.h
+st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+st.$(OBJEXT): $(top_srcdir)/internal/gc.h
+st.$(OBJEXT): $(top_srcdir)/internal/hash.h
+st.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+st.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+st.$(OBJEXT): $(top_srcdir)/internal/serial.h
+st.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+st.$(OBJEXT): $(top_srcdir)/internal/st.h
+st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+st.$(OBJEXT): $(top_srcdir)/internal/vm.h
+st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+st.$(OBJEXT): {$(VPATH)}assert.h
+st.$(OBJEXT): {$(VPATH)}atomic.h
+st.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+st.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+st.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+st.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+st.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+st.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+st.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+st.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+st.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+st.$(OBJEXT): {$(VPATH)}config.h
+st.$(OBJEXT): {$(VPATH)}defines.h
+st.$(OBJEXT): {$(VPATH)}encoding.h
+st.$(OBJEXT): {$(VPATH)}id.h
+st.$(OBJEXT): {$(VPATH)}id_table.h
+st.$(OBJEXT): {$(VPATH)}intern.h
+st.$(OBJEXT): {$(VPATH)}internal.h
+st.$(OBJEXT): {$(VPATH)}internal/abi.h
+st.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+st.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+st.$(OBJEXT): {$(VPATH)}internal/assume.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+st.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+st.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+st.$(OBJEXT): {$(VPATH)}internal/cast.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+st.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+st.$(OBJEXT): {$(VPATH)}internal/config.h
+st.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+st.$(OBJEXT): {$(VPATH)}internal/core.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+st.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+st.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+st.$(OBJEXT): {$(VPATH)}internal/ctype.h
+st.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+st.$(OBJEXT): {$(VPATH)}internal/dosish.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+st.$(OBJEXT): {$(VPATH)}internal/error.h
+st.$(OBJEXT): {$(VPATH)}internal/eval.h
+st.$(OBJEXT): {$(VPATH)}internal/event.h
+st.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+st.$(OBJEXT): {$(VPATH)}internal/gc.h
+st.$(OBJEXT): {$(VPATH)}internal/glob.h
+st.$(OBJEXT): {$(VPATH)}internal/globals.h
+st.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+st.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+st.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+st.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+st.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+st.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+st.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+st.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+st.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+st.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+st.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+st.$(OBJEXT): {$(VPATH)}internal/st.h
+st.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+st.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+st.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+st.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+st.$(OBJEXT): {$(VPATH)}internal/symbol.h
+st.$(OBJEXT): {$(VPATH)}internal/value.h
+st.$(OBJEXT): {$(VPATH)}internal/value_type.h
+st.$(OBJEXT): {$(VPATH)}internal/variable.h
+st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+st.$(OBJEXT): {$(VPATH)}method.h
+st.$(OBJEXT): {$(VPATH)}missing.h
+st.$(OBJEXT): {$(VPATH)}node.h
+st.$(OBJEXT): {$(VPATH)}onigmo.h
+st.$(OBJEXT): {$(VPATH)}oniguruma.h
+st.$(OBJEXT): {$(VPATH)}ruby_assert.h
+st.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+st.$(OBJEXT): {$(VPATH)}rubyparser.h
+st.$(OBJEXT): {$(VPATH)}st.c
+st.$(OBJEXT): {$(VPATH)}st.h
+st.$(OBJEXT): {$(VPATH)}subst.h
+st.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+st.$(OBJEXT): {$(VPATH)}thread_native.h
+st.$(OBJEXT): {$(VPATH)}vm_core.h
+st.$(OBJEXT): {$(VPATH)}vm_opts.h
+strftime.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+strftime.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+strftime.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+strftime.$(OBJEXT): $(top_srcdir)/internal/serial.h
+strftime.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+strftime.$(OBJEXT): $(top_srcdir)/internal/string.h
+strftime.$(OBJEXT): $(top_srcdir)/internal/vm.h
+strftime.$(OBJEXT): {$(VPATH)}assert.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+strftime.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+strftime.$(OBJEXT): {$(VPATH)}config.h
+strftime.$(OBJEXT): {$(VPATH)}defines.h
+strftime.$(OBJEXT): {$(VPATH)}encindex.h
+strftime.$(OBJEXT): {$(VPATH)}encoding.h
+strftime.$(OBJEXT): {$(VPATH)}intern.h
+strftime.$(OBJEXT): {$(VPATH)}internal.h
+strftime.$(OBJEXT): {$(VPATH)}internal/abi.h
+strftime.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+strftime.$(OBJEXT): {$(VPATH)}internal/assume.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+strftime.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+strftime.$(OBJEXT): {$(VPATH)}internal/cast.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+strftime.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+strftime.$(OBJEXT): {$(VPATH)}internal/config.h
+strftime.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+strftime.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+strftime.$(OBJEXT): {$(VPATH)}internal/ctype.h
+strftime.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+strftime.$(OBJEXT): {$(VPATH)}internal/dosish.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+strftime.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+strftime.$(OBJEXT): {$(VPATH)}internal/error.h
+strftime.$(OBJEXT): {$(VPATH)}internal/eval.h
+strftime.$(OBJEXT): {$(VPATH)}internal/event.h
+strftime.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+strftime.$(OBJEXT): {$(VPATH)}internal/gc.h
+strftime.$(OBJEXT): {$(VPATH)}internal/glob.h
+strftime.$(OBJEXT): {$(VPATH)}internal/globals.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+strftime.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+strftime.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+strftime.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+strftime.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+strftime.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+strftime.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+strftime.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+strftime.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+strftime.$(OBJEXT): {$(VPATH)}internal/symbol.h
+strftime.$(OBJEXT): {$(VPATH)}internal/value.h
+strftime.$(OBJEXT): {$(VPATH)}internal/value_type.h
+strftime.$(OBJEXT): {$(VPATH)}internal/variable.h
+strftime.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+strftime.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+strftime.$(OBJEXT): {$(VPATH)}missing.h
+strftime.$(OBJEXT): {$(VPATH)}onigmo.h
+strftime.$(OBJEXT): {$(VPATH)}oniguruma.h
+strftime.$(OBJEXT): {$(VPATH)}st.h
+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
+string.$(OBJEXT): $(top_srcdir)/internal/bits.h
+string.$(OBJEXT): $(top_srcdir)/internal/box.h
+string.$(OBJEXT): $(top_srcdir)/internal/class.h
+string.$(OBJEXT): $(top_srcdir)/internal/compar.h
+string.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+string.$(OBJEXT): $(top_srcdir)/internal/concurrent_set.h
+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/hash.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
+string.$(OBJEXT): $(top_srcdir)/internal/re.h
+string.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+string.$(OBJEXT): $(top_srcdir)/internal/serial.h
+string.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+string.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+string.$(OBJEXT): $(top_srcdir)/internal/string.h
+string.$(OBJEXT): $(top_srcdir)/internal/struct.h
+string.$(OBJEXT): $(top_srcdir)/internal/transcode.h
+string.$(OBJEXT): $(top_srcdir)/internal/variable.h
+string.$(OBJEXT): $(top_srcdir)/internal/vm.h
+string.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+string.$(OBJEXT): {$(VPATH)}assert.h
+string.$(OBJEXT): {$(VPATH)}atomic.h
+string.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+string.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+string.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+string.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+string.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+string.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+string.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+string.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+string.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+string.$(OBJEXT): {$(VPATH)}config.h
+string.$(OBJEXT): {$(VPATH)}constant.h
+string.$(OBJEXT): {$(VPATH)}debug_counter.h
+string.$(OBJEXT): {$(VPATH)}defines.h
+string.$(OBJEXT): {$(VPATH)}encindex.h
+string.$(OBJEXT): {$(VPATH)}encoding.h
+string.$(OBJEXT): {$(VPATH)}id.h
+string.$(OBJEXT): {$(VPATH)}id_table.h
+string.$(OBJEXT): {$(VPATH)}intern.h
+string.$(OBJEXT): {$(VPATH)}internal.h
+string.$(OBJEXT): {$(VPATH)}internal/abi.h
+string.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+string.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+string.$(OBJEXT): {$(VPATH)}internal/assume.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+string.$(OBJEXT): {$(VPATH)}internal/cast.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+string.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+string.$(OBJEXT): {$(VPATH)}internal/config.h
+string.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+string.$(OBJEXT): {$(VPATH)}internal/core.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+string.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+string.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+string.$(OBJEXT): {$(VPATH)}internal/ctype.h
+string.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+string.$(OBJEXT): {$(VPATH)}internal/dosish.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+string.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+string.$(OBJEXT): {$(VPATH)}internal/error.h
+string.$(OBJEXT): {$(VPATH)}internal/eval.h
+string.$(OBJEXT): {$(VPATH)}internal/event.h
+string.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+string.$(OBJEXT): {$(VPATH)}internal/gc.h
+string.$(OBJEXT): {$(VPATH)}internal/glob.h
+string.$(OBJEXT): {$(VPATH)}internal/globals.h
+string.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+string.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+string.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+string.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+string.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+string.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+string.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+string.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+string.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+string.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+string.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+string.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+string.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+string.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+string.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+string.$(OBJEXT): {$(VPATH)}internal/symbol.h
+string.$(OBJEXT): {$(VPATH)}internal/value.h
+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
+string.$(OBJEXT): {$(VPATH)}probes.h
+string.$(OBJEXT): {$(VPATH)}ractor.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.h
+string.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+string.$(OBJEXT): {$(VPATH)}thread_native.h
+string.$(OBJEXT): {$(VPATH)}util.h
+string.$(OBJEXT): {$(VPATH)}variable.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
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/config.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+strlcat.$(OBJEXT): {$(VPATH)}missing.h
+strlcat.$(OBJEXT): {$(VPATH)}strlcat.c
+strlcpy.$(OBJEXT): {$(VPATH)}config.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/config.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+strlcpy.$(OBJEXT): {$(VPATH)}missing.h
+strlcpy.$(OBJEXT): {$(VPATH)}strlcpy.c
+struct.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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/box.h
+struct.$(OBJEXT): $(top_srcdir)/internal/class.h
+struct.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+struct.$(OBJEXT): $(top_srcdir)/internal/error.h
+struct.$(OBJEXT): $(top_srcdir)/internal/gc.h
+struct.$(OBJEXT): $(top_srcdir)/internal/hash.h
+struct.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+struct.$(OBJEXT): $(top_srcdir)/internal/object.h
+struct.$(OBJEXT): $(top_srcdir)/internal/proc.h
+struct.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+struct.$(OBJEXT): $(top_srcdir)/internal/serial.h
+struct.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+struct.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+struct.$(OBJEXT): $(top_srcdir)/internal/string.h
+struct.$(OBJEXT): $(top_srcdir)/internal/struct.h
+struct.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+struct.$(OBJEXT): $(top_srcdir)/internal/variable.h
+struct.$(OBJEXT): $(top_srcdir)/internal/vm.h
+struct.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+struct.$(OBJEXT): {$(VPATH)}assert.h
+struct.$(OBJEXT): {$(VPATH)}atomic.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+struct.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}encindex.h
+struct.$(OBJEXT): {$(VPATH)}encoding.h
+struct.$(OBJEXT): {$(VPATH)}id.h
+struct.$(OBJEXT): {$(VPATH)}id_table.h
+struct.$(OBJEXT): {$(VPATH)}intern.h
+struct.$(OBJEXT): {$(VPATH)}internal.h
+struct.$(OBJEXT): {$(VPATH)}internal/abi.h
+struct.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+struct.$(OBJEXT): {$(VPATH)}internal/assume.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+struct.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+struct.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+struct.$(OBJEXT): {$(VPATH)}internal/cast.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+struct.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+struct.$(OBJEXT): {$(VPATH)}internal/config.h
+struct.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+struct.$(OBJEXT): {$(VPATH)}internal/core.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+struct.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+struct.$(OBJEXT): {$(VPATH)}internal/ctype.h
+struct.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+struct.$(OBJEXT): {$(VPATH)}internal/dosish.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+struct.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+struct.$(OBJEXT): {$(VPATH)}internal/error.h
+struct.$(OBJEXT): {$(VPATH)}internal/eval.h
+struct.$(OBJEXT): {$(VPATH)}internal/event.h
+struct.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+struct.$(OBJEXT): {$(VPATH)}internal/gc.h
+struct.$(OBJEXT): {$(VPATH)}internal/glob.h
+struct.$(OBJEXT): {$(VPATH)}internal/globals.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+struct.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+struct.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+struct.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+struct.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+struct.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+struct.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+struct.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+struct.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+struct.$(OBJEXT): {$(VPATH)}internal/symbol.h
+struct.$(OBJEXT): {$(VPATH)}internal/value.h
+struct.$(OBJEXT): {$(VPATH)}internal/value_type.h
+struct.$(OBJEXT): {$(VPATH)}internal/variable.h
+struct.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+struct.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+struct.$(OBJEXT): {$(VPATH)}method.h
+struct.$(OBJEXT): {$(VPATH)}missing.h
+struct.$(OBJEXT): {$(VPATH)}node.h
+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)}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/box.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/class.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/concurrent_set.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/sanitizers.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/string.h
+symbol.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+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
+symbol.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+symbol.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+symbol.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+symbol.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+symbol.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+symbol.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+symbol.$(OBJEXT): {$(VPATH)}builtin.h
+symbol.$(OBJEXT): {$(VPATH)}config.h
+symbol.$(OBJEXT): {$(VPATH)}constant.h
+symbol.$(OBJEXT): {$(VPATH)}darray.h
+symbol.$(OBJEXT): {$(VPATH)}debug_counter.h
+symbol.$(OBJEXT): {$(VPATH)}defines.h
+symbol.$(OBJEXT): {$(VPATH)}encindex.h
+symbol.$(OBJEXT): {$(VPATH)}encoding.h
+symbol.$(OBJEXT): {$(VPATH)}id.c
+symbol.$(OBJEXT): {$(VPATH)}id.h
+symbol.$(OBJEXT): {$(VPATH)}id_table.c
+symbol.$(OBJEXT): {$(VPATH)}id_table.h
+symbol.$(OBJEXT): {$(VPATH)}intern.h
+symbol.$(OBJEXT): {$(VPATH)}internal.h
+symbol.$(OBJEXT): {$(VPATH)}internal/abi.h
+symbol.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+symbol.$(OBJEXT): {$(VPATH)}internal/assume.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+symbol.$(OBJEXT): {$(VPATH)}internal/cast.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+symbol.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+symbol.$(OBJEXT): {$(VPATH)}internal/config.h
+symbol.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+symbol.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+symbol.$(OBJEXT): {$(VPATH)}internal/ctype.h
+symbol.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+symbol.$(OBJEXT): {$(VPATH)}internal/dosish.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+symbol.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+symbol.$(OBJEXT): {$(VPATH)}internal/error.h
+symbol.$(OBJEXT): {$(VPATH)}internal/eval.h
+symbol.$(OBJEXT): {$(VPATH)}internal/event.h
+symbol.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+symbol.$(OBJEXT): {$(VPATH)}internal/gc.h
+symbol.$(OBJEXT): {$(VPATH)}internal/glob.h
+symbol.$(OBJEXT): {$(VPATH)}internal/globals.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+symbol.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+symbol.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+symbol.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+symbol.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+symbol.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+symbol.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+symbol.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+symbol.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+symbol.$(OBJEXT): {$(VPATH)}internal/symbol.h
+symbol.$(OBJEXT): {$(VPATH)}internal/value.h
+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)}ractor.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
+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
+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
+thread.$(OBJEXT): $(top_srcdir)/internal/box.h
+thread.$(OBJEXT): $(top_srcdir)/internal/class.h
+thread.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+thread.$(OBJEXT): $(top_srcdir)/internal/cont.h
+thread.$(OBJEXT): $(top_srcdir)/internal/error.h
+thread.$(OBJEXT): $(top_srcdir)/internal/eval.h
+thread.$(OBJEXT): $(top_srcdir)/internal/gc.h
+thread.$(OBJEXT): $(top_srcdir)/internal/hash.h
+thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+thread.$(OBJEXT): $(top_srcdir)/internal/io.h
+thread.$(OBJEXT): $(top_srcdir)/internal/object.h
+thread.$(OBJEXT): $(top_srcdir)/internal/proc.h
+thread.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+thread.$(OBJEXT): $(top_srcdir)/internal/serial.h
+thread.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+thread.$(OBJEXT): $(top_srcdir)/internal/signal.h
+thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+thread.$(OBJEXT): $(top_srcdir)/internal/string.h
+thread.$(OBJEXT): $(top_srcdir)/internal/struct.h
+thread.$(OBJEXT): $(top_srcdir)/internal/thread.h
+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/arena.h
+thread.$(OBJEXT): $(top_srcdir)/prism/ast.h
+thread.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+thread.$(OBJEXT): $(top_srcdir)/prism/comments.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+thread.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+thread.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+thread.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+thread.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+thread.$(OBJEXT): $(top_srcdir)/prism/integer.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+thread.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+thread.$(OBJEXT): $(top_srcdir)/prism/json.h
+thread.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+thread.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+thread.$(OBJEXT): $(top_srcdir)/prism/node.h
+thread.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+thread.$(OBJEXT): $(top_srcdir)/prism/source.h
+thread.$(OBJEXT): $(top_srcdir)/prism/stream.h
+thread.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+thread.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+thread.$(OBJEXT): $(top_srcdir)/prism/version.h
+thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
+thread.$(OBJEXT): {$(VPATH)}assert.h
+thread.$(OBJEXT): {$(VPATH)}atomic.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+thread.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+thread.$(OBJEXT): {$(VPATH)}builtin.h
+thread.$(OBJEXT): {$(VPATH)}config.h
+thread.$(OBJEXT): {$(VPATH)}constant.h
+thread.$(OBJEXT): {$(VPATH)}debug.h
+thread.$(OBJEXT): {$(VPATH)}debug_counter.h
+thread.$(OBJEXT): {$(VPATH)}defines.h
+thread.$(OBJEXT): {$(VPATH)}encindex.h
+thread.$(OBJEXT): {$(VPATH)}encoding.h
+thread.$(OBJEXT): {$(VPATH)}eval_intern.h
+thread.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+thread.$(OBJEXT): {$(VPATH)}hrtime.h
+thread.$(OBJEXT): {$(VPATH)}id.h
+thread.$(OBJEXT): {$(VPATH)}id_table.h
+thread.$(OBJEXT): {$(VPATH)}intern.h
+thread.$(OBJEXT): {$(VPATH)}internal.h
+thread.$(OBJEXT): {$(VPATH)}internal/abi.h
+thread.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+thread.$(OBJEXT): {$(VPATH)}internal/assume.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+thread.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+thread.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+thread.$(OBJEXT): {$(VPATH)}internal/cast.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+thread.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+thread.$(OBJEXT): {$(VPATH)}internal/config.h
+thread.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+thread.$(OBJEXT): {$(VPATH)}internal/core.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+thread.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+thread.$(OBJEXT): {$(VPATH)}internal/ctype.h
+thread.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+thread.$(OBJEXT): {$(VPATH)}internal/dosish.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+thread.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+thread.$(OBJEXT): {$(VPATH)}internal/error.h
+thread.$(OBJEXT): {$(VPATH)}internal/eval.h
+thread.$(OBJEXT): {$(VPATH)}internal/event.h
+thread.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+thread.$(OBJEXT): {$(VPATH)}internal/gc.h
+thread.$(OBJEXT): {$(VPATH)}internal/glob.h
+thread.$(OBJEXT): {$(VPATH)}internal/globals.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+thread.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+thread.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+thread.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+thread.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+thread.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+thread.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+thread.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+thread.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+thread.$(OBJEXT): {$(VPATH)}internal/symbol.h
+thread.$(OBJEXT): {$(VPATH)}internal/value.h
+thread.$(OBJEXT): {$(VPATH)}internal/value_type.h
+thread.$(OBJEXT): {$(VPATH)}internal/variable.h
+thread.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+thread.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+thread.$(OBJEXT): {$(VPATH)}io.h
+thread.$(OBJEXT): {$(VPATH)}iseq.h
+thread.$(OBJEXT): {$(VPATH)}method.h
+thread.$(OBJEXT): {$(VPATH)}missing.h
+thread.$(OBJEXT): {$(VPATH)}node.h
+thread.$(OBJEXT): {$(VPATH)}onigmo.h
+thread.$(OBJEXT): {$(VPATH)}oniguruma.h
+thread.$(OBJEXT): {$(VPATH)}prism_compile.h
+thread.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+thread.$(OBJEXT): {$(VPATH)}ractor.h
+thread.$(OBJEXT): {$(VPATH)}ractor_core.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
+thread.$(OBJEXT): {$(VPATH)}thread.c
+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
+thread.$(OBJEXT): {$(VPATH)}vm_core.h
+thread.$(OBJEXT): {$(VPATH)}vm_debug.h
+thread.$(OBJEXT): {$(VPATH)}vm_opts.h
+thread.$(OBJEXT): {$(VPATH)}vm_sync.h
+thread.$(OBJEXT): {$(VPATH)}zjit.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
+time.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+time.$(OBJEXT): $(top_srcdir)/internal/bits.h
+time.$(OBJEXT): $(top_srcdir)/internal/box.h
+time.$(OBJEXT): $(top_srcdir)/internal/compar.h
+time.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+time.$(OBJEXT): $(top_srcdir)/internal/error.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/sanitizers.h
+time.$(OBJEXT): $(top_srcdir)/internal/serial.h
+time.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+time.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+time.$(OBJEXT): $(top_srcdir)/internal/string.h
+time.$(OBJEXT): $(top_srcdir)/internal/struct.h
+time.$(OBJEXT): $(top_srcdir)/internal/time.h
+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
+time.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+time.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+time.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+time.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+time.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+time.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+time.$(OBJEXT): {$(VPATH)}builtin.h
+time.$(OBJEXT): {$(VPATH)}config.h
+time.$(OBJEXT): {$(VPATH)}constant.h
+time.$(OBJEXT): {$(VPATH)}defines.h
+time.$(OBJEXT): {$(VPATH)}encindex.h
+time.$(OBJEXT): {$(VPATH)}encoding.h
+time.$(OBJEXT): {$(VPATH)}id.h
+time.$(OBJEXT): {$(VPATH)}id_table.h
+time.$(OBJEXT): {$(VPATH)}intern.h
+time.$(OBJEXT): {$(VPATH)}internal.h
+time.$(OBJEXT): {$(VPATH)}internal/abi.h
+time.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+time.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+time.$(OBJEXT): {$(VPATH)}internal/assume.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+time.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+time.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+time.$(OBJEXT): {$(VPATH)}internal/cast.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+time.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+time.$(OBJEXT): {$(VPATH)}internal/config.h
+time.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+time.$(OBJEXT): {$(VPATH)}internal/core.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+time.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+time.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+time.$(OBJEXT): {$(VPATH)}internal/ctype.h
+time.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+time.$(OBJEXT): {$(VPATH)}internal/dosish.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+time.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+time.$(OBJEXT): {$(VPATH)}internal/error.h
+time.$(OBJEXT): {$(VPATH)}internal/eval.h
+time.$(OBJEXT): {$(VPATH)}internal/event.h
+time.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+time.$(OBJEXT): {$(VPATH)}internal/gc.h
+time.$(OBJEXT): {$(VPATH)}internal/glob.h
+time.$(OBJEXT): {$(VPATH)}internal/globals.h
+time.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+time.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+time.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+time.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+time.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+time.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+time.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+time.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+time.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+time.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+time.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+time.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+time.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+time.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+time.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+time.$(OBJEXT): {$(VPATH)}internal/symbol.h
+time.$(OBJEXT): {$(VPATH)}internal/value.h
+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)}util.h
+time.$(OBJEXT): {$(VPATH)}vm_core.h
+time.$(OBJEXT): {$(VPATH)}vm_opts.h
+transcode.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+transcode.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+transcode.$(OBJEXT): $(CCAN_DIR)/list/list.h
+transcode.$(OBJEXT): $(CCAN_DIR)/str/str.h
+transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/array.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/box.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/class.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/encoding.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/gc.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/inits.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/object.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/serial.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/string.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/transcode.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/variable.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/vm.h
+transcode.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+transcode.$(OBJEXT): {$(VPATH)}assert.h
+transcode.$(OBJEXT): {$(VPATH)}atomic.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+transcode.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+transcode.$(OBJEXT): {$(VPATH)}config.h
+transcode.$(OBJEXT): {$(VPATH)}constant.h
+transcode.$(OBJEXT): {$(VPATH)}debug_counter.h
+transcode.$(OBJEXT): {$(VPATH)}defines.h
+transcode.$(OBJEXT): {$(VPATH)}encindex.h
+transcode.$(OBJEXT): {$(VPATH)}encoding.h
+transcode.$(OBJEXT): {$(VPATH)}id.h
+transcode.$(OBJEXT): {$(VPATH)}id_table.h
+transcode.$(OBJEXT): {$(VPATH)}intern.h
+transcode.$(OBJEXT): {$(VPATH)}internal.h
+transcode.$(OBJEXT): {$(VPATH)}internal/abi.h
+transcode.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+transcode.$(OBJEXT): {$(VPATH)}internal/assume.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+transcode.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+transcode.$(OBJEXT): {$(VPATH)}internal/cast.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+transcode.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+transcode.$(OBJEXT): {$(VPATH)}internal/config.h
+transcode.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+transcode.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+transcode.$(OBJEXT): {$(VPATH)}internal/ctype.h
+transcode.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+transcode.$(OBJEXT): {$(VPATH)}internal/dosish.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+transcode.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+transcode.$(OBJEXT): {$(VPATH)}internal/error.h
+transcode.$(OBJEXT): {$(VPATH)}internal/eval.h
+transcode.$(OBJEXT): {$(VPATH)}internal/event.h
+transcode.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+transcode.$(OBJEXT): {$(VPATH)}internal/gc.h
+transcode.$(OBJEXT): {$(VPATH)}internal/glob.h
+transcode.$(OBJEXT): {$(VPATH)}internal/globals.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+transcode.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+transcode.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+transcode.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+transcode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+transcode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+transcode.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+transcode.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+transcode.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+transcode.$(OBJEXT): {$(VPATH)}internal/symbol.h
+transcode.$(OBJEXT): {$(VPATH)}internal/value.h
+transcode.$(OBJEXT): {$(VPATH)}internal/value_type.h
+transcode.$(OBJEXT): {$(VPATH)}internal/variable.h
+transcode.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+transcode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+transcode.$(OBJEXT): {$(VPATH)}method.h
+transcode.$(OBJEXT): {$(VPATH)}missing.h
+transcode.$(OBJEXT): {$(VPATH)}node.h
+transcode.$(OBJEXT): {$(VPATH)}onigmo.h
+transcode.$(OBJEXT): {$(VPATH)}oniguruma.h
+transcode.$(OBJEXT): {$(VPATH)}ruby_assert.h
+transcode.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+transcode.$(OBJEXT): {$(VPATH)}rubyparser.h
+transcode.$(OBJEXT): {$(VPATH)}shape.h
+transcode.$(OBJEXT): {$(VPATH)}st.h
+transcode.$(OBJEXT): {$(VPATH)}subst.h
+transcode.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+transcode.$(OBJEXT): {$(VPATH)}thread_native.h
+transcode.$(OBJEXT): {$(VPATH)}transcode.c
+transcode.$(OBJEXT): {$(VPATH)}transcode_data.h
+transcode.$(OBJEXT): {$(VPATH)}vm_core.h
+transcode.$(OBJEXT): {$(VPATH)}vm_debug.h
+transcode.$(OBJEXT): {$(VPATH)}vm_opts.h
+transcode.$(OBJEXT): {$(VPATH)}vm_sync.h
+util.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+util.$(OBJEXT): $(top_srcdir)/internal/array.h
+util.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+util.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+util.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+util.$(OBJEXT): $(top_srcdir)/internal/util.h
+util.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+util.$(OBJEXT): {$(VPATH)}assert.h
+util.$(OBJEXT): {$(VPATH)}atomic.h
+util.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+util.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+util.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+util.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+util.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+util.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+util.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+util.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+util.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+util.$(OBJEXT): {$(VPATH)}config.h
+util.$(OBJEXT): {$(VPATH)}defines.h
+util.$(OBJEXT): {$(VPATH)}dtoa.c
+util.$(OBJEXT): {$(VPATH)}id_table.h
+util.$(OBJEXT): {$(VPATH)}intern.h
+util.$(OBJEXT): {$(VPATH)}internal.h
+util.$(OBJEXT): {$(VPATH)}internal/abi.h
+util.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+util.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+util.$(OBJEXT): {$(VPATH)}internal/assume.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+util.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+util.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+util.$(OBJEXT): {$(VPATH)}internal/cast.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+util.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+util.$(OBJEXT): {$(VPATH)}internal/config.h
+util.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+util.$(OBJEXT): {$(VPATH)}internal/core.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+util.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+util.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+util.$(OBJEXT): {$(VPATH)}internal/ctype.h
+util.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+util.$(OBJEXT): {$(VPATH)}internal/dosish.h
+util.$(OBJEXT): {$(VPATH)}internal/error.h
+util.$(OBJEXT): {$(VPATH)}internal/eval.h
+util.$(OBJEXT): {$(VPATH)}internal/event.h
+util.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+util.$(OBJEXT): {$(VPATH)}internal/gc.h
+util.$(OBJEXT): {$(VPATH)}internal/glob.h
+util.$(OBJEXT): {$(VPATH)}internal/globals.h
+util.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+util.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+util.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+util.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+util.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+util.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+util.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+util.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+util.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+util.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+util.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+util.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+util.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+util.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+util.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+util.$(OBJEXT): {$(VPATH)}internal/symbol.h
+util.$(OBJEXT): {$(VPATH)}internal/value.h
+util.$(OBJEXT): {$(VPATH)}internal/value_type.h
+util.$(OBJEXT): {$(VPATH)}internal/variable.h
+util.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+util.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+util.$(OBJEXT): {$(VPATH)}missing.h
+util.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+util.$(OBJEXT): {$(VPATH)}st.h
+util.$(OBJEXT): {$(VPATH)}subst.h
+util.$(OBJEXT): {$(VPATH)}util.c
+util.$(OBJEXT): {$(VPATH)}util.h
+variable.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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/box.h
+variable.$(OBJEXT): $(top_srcdir)/internal/class.h
+variable.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+variable.$(OBJEXT): $(top_srcdir)/internal/error.h
+variable.$(OBJEXT): $(top_srcdir)/internal/eval.h
+variable.$(OBJEXT): $(top_srcdir)/internal/gc.h
+variable.$(OBJEXT): $(top_srcdir)/internal/hash.h
+variable.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+variable.$(OBJEXT): $(top_srcdir)/internal/object.h
+variable.$(OBJEXT): $(top_srcdir)/internal/re.h
+variable.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+variable.$(OBJEXT): $(top_srcdir)/internal/serial.h
+variable.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+variable.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+variable.$(OBJEXT): $(top_srcdir)/internal/string.h
+variable.$(OBJEXT): $(top_srcdir)/internal/struct.h
+variable.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+variable.$(OBJEXT): $(top_srcdir)/internal/thread.h
+variable.$(OBJEXT): $(top_srcdir)/internal/variable.h
+variable.$(OBJEXT): $(top_srcdir)/internal/vm.h
+variable.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+variable.$(OBJEXT): {$(VPATH)}assert.h
+variable.$(OBJEXT): {$(VPATH)}atomic.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+variable.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+variable.$(OBJEXT): {$(VPATH)}config.h
+variable.$(OBJEXT): {$(VPATH)}constant.h
+variable.$(OBJEXT): {$(VPATH)}debug_counter.h
+variable.$(OBJEXT): {$(VPATH)}defines.h
+variable.$(OBJEXT): {$(VPATH)}encindex.h
+variable.$(OBJEXT): {$(VPATH)}encoding.h
+variable.$(OBJEXT): {$(VPATH)}id.h
+variable.$(OBJEXT): {$(VPATH)}id_table.h
+variable.$(OBJEXT): {$(VPATH)}intern.h
+variable.$(OBJEXT): {$(VPATH)}internal.h
+variable.$(OBJEXT): {$(VPATH)}internal/abi.h
+variable.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+variable.$(OBJEXT): {$(VPATH)}internal/assume.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+variable.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+variable.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+variable.$(OBJEXT): {$(VPATH)}internal/cast.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+variable.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+variable.$(OBJEXT): {$(VPATH)}internal/config.h
+variable.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+variable.$(OBJEXT): {$(VPATH)}internal/core.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+variable.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+variable.$(OBJEXT): {$(VPATH)}internal/ctype.h
+variable.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+variable.$(OBJEXT): {$(VPATH)}internal/dosish.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+variable.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+variable.$(OBJEXT): {$(VPATH)}internal/error.h
+variable.$(OBJEXT): {$(VPATH)}internal/eval.h
+variable.$(OBJEXT): {$(VPATH)}internal/event.h
+variable.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+variable.$(OBJEXT): {$(VPATH)}internal/gc.h
+variable.$(OBJEXT): {$(VPATH)}internal/glob.h
+variable.$(OBJEXT): {$(VPATH)}internal/globals.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+variable.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+variable.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+variable.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+variable.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+variable.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+variable.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+variable.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+variable.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+variable.$(OBJEXT): {$(VPATH)}internal/symbol.h
+variable.$(OBJEXT): {$(VPATH)}internal/value.h
+variable.$(OBJEXT): {$(VPATH)}internal/value_type.h
+variable.$(OBJEXT): {$(VPATH)}internal/variable.h
+variable.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+variable.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+variable.$(OBJEXT): {$(VPATH)}method.h
+variable.$(OBJEXT): {$(VPATH)}missing.h
+variable.$(OBJEXT): {$(VPATH)}node.h
+variable.$(OBJEXT): {$(VPATH)}onigmo.h
+variable.$(OBJEXT): {$(VPATH)}oniguruma.h
+variable.$(OBJEXT): {$(VPATH)}ractor.h
+variable.$(OBJEXT): {$(VPATH)}ractor_core.h
+variable.$(OBJEXT): {$(VPATH)}re.h
+variable.$(OBJEXT): {$(VPATH)}regex.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)}util.h
+variable.$(OBJEXT): {$(VPATH)}variable.c
+variable.$(OBJEXT): {$(VPATH)}variable.h
+variable.$(OBJEXT): {$(VPATH)}vm_core.h
+variable.$(OBJEXT): {$(VPATH)}vm_debug.h
+variable.$(OBJEXT): {$(VPATH)}vm_opts.h
+variable.$(OBJEXT): {$(VPATH)}vm_sync.h
+version.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+version.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+version.$(OBJEXT): $(CCAN_DIR)/list/list.h
+version.$(OBJEXT): $(CCAN_DIR)/str/str.h
+version.$(OBJEXT): $(hdrdir)/ruby.h
+version.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+version.$(OBJEXT): $(hdrdir)/ruby/version.h
+version.$(OBJEXT): $(top_srcdir)/internal/array.h
+version.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+version.$(OBJEXT): $(top_srcdir)/internal/box.h
+version.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
+version.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+version.$(OBJEXT): $(top_srcdir)/internal/gc.h
+version.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+version.$(OBJEXT): $(top_srcdir)/internal/parse.h
+version.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+version.$(OBJEXT): $(top_srcdir)/internal/serial.h
+version.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+version.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+version.$(OBJEXT): $(top_srcdir)/internal/variable.h
+version.$(OBJEXT): $(top_srcdir)/internal/vm.h
+version.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+version.$(OBJEXT): $(top_srcdir)/version.h
+version.$(OBJEXT): {$(VPATH)}assert.h
+version.$(OBJEXT): {$(VPATH)}atomic.h
+version.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+version.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+version.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+version.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+version.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+version.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+version.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+version.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+version.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+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
+version.$(OBJEXT): {$(VPATH)}internal.h
+version.$(OBJEXT): {$(VPATH)}internal/abi.h
+version.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+version.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+version.$(OBJEXT): {$(VPATH)}internal/assume.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+version.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+version.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+version.$(OBJEXT): {$(VPATH)}internal/cast.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+version.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+version.$(OBJEXT): {$(VPATH)}internal/config.h
+version.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+version.$(OBJEXT): {$(VPATH)}internal/core.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+version.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+version.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+version.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+version.$(OBJEXT): {$(VPATH)}internal/gc.h
+version.$(OBJEXT): {$(VPATH)}internal/glob.h
+version.$(OBJEXT): {$(VPATH)}internal/globals.h
+version.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+version.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+version.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+version.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+version.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+version.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+version.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+version.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+version.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+version.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+version.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+version.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+version.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+version.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+version.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+version.$(OBJEXT): {$(VPATH)}internal/symbol.h
+version.$(OBJEXT): {$(VPATH)}internal/value.h
+version.$(OBJEXT): {$(VPATH)}internal/value_type.h
+version.$(OBJEXT): {$(VPATH)}internal/variable.h
+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)}node.h
+version.$(OBJEXT): {$(VPATH)}onigmo.h
+version.$(OBJEXT): {$(VPATH)}oniguruma.h
+version.$(OBJEXT): {$(VPATH)}revision.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
+version.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+version.$(OBJEXT): {$(VPATH)}thread_native.h
+version.$(OBJEXT): {$(VPATH)}version.c
+version.$(OBJEXT): {$(VPATH)}vm_core.h
+version.$(OBJEXT): {$(VPATH)}vm_opts.h
+version.$(OBJEXT): {$(VPATH)}yjit.h
+vm.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+vm.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+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
+vm.$(OBJEXT): $(top_srcdir)/internal/bits.h
+vm.$(OBJEXT): $(top_srcdir)/internal/box.h
+vm.$(OBJEXT): $(top_srcdir)/internal/class.h
+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/complex.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
+vm.$(OBJEXT): $(top_srcdir)/internal/gc.h
+vm.$(OBJEXT): $(top_srcdir)/internal/hash.h
+vm.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+vm.$(OBJEXT): $(top_srcdir)/internal/inits.h
+vm.$(OBJEXT): $(top_srcdir)/internal/missing.h
+vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+vm.$(OBJEXT): $(top_srcdir)/internal/object.h
+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/rational.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/set_table.h
+vm.$(OBJEXT): $(top_srcdir)/internal/st.h
+vm.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+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/arena.h
+vm.$(OBJEXT): $(top_srcdir)/prism/ast.h
+vm.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+vm.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+vm.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+vm.$(OBJEXT): $(top_srcdir)/prism/node.h
+vm.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+vm.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+vm.$(OBJEXT): $(top_srcdir)/prism/version.h
+vm.$(OBJEXT): {$(VPATH)}assert.h
+vm.$(OBJEXT): {$(VPATH)}atomic.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+vm.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+vm.$(OBJEXT): {$(VPATH)}builtin.h
+vm.$(OBJEXT): {$(VPATH)}config.h
+vm.$(OBJEXT): {$(VPATH)}constant.h
+vm.$(OBJEXT): {$(VPATH)}debug_counter.h
+vm.$(OBJEXT): {$(VPATH)}defines.h
+vm.$(OBJEXT): {$(VPATH)}defs/opt_operand.def
+vm.$(OBJEXT): {$(VPATH)}encindex.h
+vm.$(OBJEXT): {$(VPATH)}encoding.h
+vm.$(OBJEXT): {$(VPATH)}eval_intern.h
+vm.$(OBJEXT): {$(VPATH)}id.h
+vm.$(OBJEXT): {$(VPATH)}id_table.h
+vm.$(OBJEXT): {$(VPATH)}insns.def
+vm.$(OBJEXT): {$(VPATH)}insns.inc
+vm.$(OBJEXT): {$(VPATH)}insns_info.inc
+vm.$(OBJEXT): {$(VPATH)}intern.h
+vm.$(OBJEXT): {$(VPATH)}internal.h
+vm.$(OBJEXT): {$(VPATH)}internal/abi.h
+vm.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+vm.$(OBJEXT): {$(VPATH)}internal/assume.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+vm.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+vm.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+vm.$(OBJEXT): {$(VPATH)}internal/cast.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+vm.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+vm.$(OBJEXT): {$(VPATH)}internal/config.h
+vm.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+vm.$(OBJEXT): {$(VPATH)}internal/core.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rmatch.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+vm.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+vm.$(OBJEXT): {$(VPATH)}internal/ctype.h
+vm.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+vm.$(OBJEXT): {$(VPATH)}internal/dosish.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+vm.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+vm.$(OBJEXT): {$(VPATH)}internal/error.h
+vm.$(OBJEXT): {$(VPATH)}internal/eval.h
+vm.$(OBJEXT): {$(VPATH)}internal/event.h
+vm.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+vm.$(OBJEXT): {$(VPATH)}internal/gc.h
+vm.$(OBJEXT): {$(VPATH)}internal/glob.h
+vm.$(OBJEXT): {$(VPATH)}internal/globals.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+vm.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+vm.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+vm.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+vm.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+vm.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+vm.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+vm.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+vm.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+vm.$(OBJEXT): {$(VPATH)}internal/symbol.h
+vm.$(OBJEXT): {$(VPATH)}internal/value.h
+vm.$(OBJEXT): {$(VPATH)}internal/value_type.h
+vm.$(OBJEXT): {$(VPATH)}internal/variable.h
+vm.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+vm.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+vm.$(OBJEXT): {$(VPATH)}iseq.h
+vm.$(OBJEXT): {$(VPATH)}jit_hook.rbinc
+vm.$(OBJEXT): {$(VPATH)}jit_undef.rbinc
+vm.$(OBJEXT): {$(VPATH)}method.h
+vm.$(OBJEXT): {$(VPATH)}missing.h
+vm.$(OBJEXT): {$(VPATH)}node.h
+vm.$(OBJEXT): {$(VPATH)}onigmo.h
+vm.$(OBJEXT): {$(VPATH)}oniguruma.h
+vm.$(OBJEXT): {$(VPATH)}prism_compile.h
+vm.$(OBJEXT): {$(VPATH)}prism_xallocator.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)}re.h
+vm.$(OBJEXT): {$(VPATH)}regex.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
+vm.$(OBJEXT): {$(VPATH)}symbol.h
+vm.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+vm.$(OBJEXT): {$(VPATH)}thread_native.h
+vm.$(OBJEXT): {$(VPATH)}variable.h
+vm.$(OBJEXT): {$(VPATH)}vm.c
+vm.$(OBJEXT): {$(VPATH)}vm.h
+vm.$(OBJEXT): {$(VPATH)}vm.inc
+vm.$(OBJEXT): {$(VPATH)}vm_args.c
+vm.$(OBJEXT): {$(VPATH)}vm_call_iseq_optimized.inc
+vm.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+vm.$(OBJEXT): {$(VPATH)}vm_core.h
+vm.$(OBJEXT): {$(VPATH)}vm_debug.h
+vm.$(OBJEXT): {$(VPATH)}vm_eval.c
+vm.$(OBJEXT): {$(VPATH)}vm_exec.c
+vm.$(OBJEXT): {$(VPATH)}vm_exec.h
+vm.$(OBJEXT): {$(VPATH)}vm_insnhelper.c
+vm.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
+vm.$(OBJEXT): {$(VPATH)}vm_method.c
+vm.$(OBJEXT): {$(VPATH)}vm_opts.h
+vm.$(OBJEXT): {$(VPATH)}vm_sync.h
+vm.$(OBJEXT): {$(VPATH)}vmtc.inc
+vm.$(OBJEXT): {$(VPATH)}yjit.h
+vm.$(OBJEXT): {$(VPATH)}zjit.h
+vm_backtrace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+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/box.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
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/object.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/string.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/ast.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/node.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/version.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}atomic.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}encindex.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}encoding.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}eval_intern.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}id.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}id_table.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}intern.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/abi.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/assume.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/cast.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/config.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/ctype.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/dosish.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/error.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/eval.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/event.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/gc.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/glob.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/globals.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/symbol.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/value.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/value_type.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/variable.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}iseq.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}method.h
+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_compile.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}prism_xallocator.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
+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_backtrace.$(OBJEXT): {$(VPATH)}zjit.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
+vm_dump.$(OBJEXT): $(CCAN_DIR)/str/str.h
+vm_dump.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/array.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/box.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+vm_dump.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/ast.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/node.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+vm_dump.$(OBJEXT): $(top_srcdir)/prism/version.h
+vm_dump.$(OBJEXT): {$(VPATH)}addr2line.h
+vm_dump.$(OBJEXT): {$(VPATH)}assert.h
+vm_dump.$(OBJEXT): {$(VPATH)}atomic.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+vm_dump.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+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)}fiber/scheduler.h
+vm_dump.$(OBJEXT): {$(VPATH)}id.h
+vm_dump.$(OBJEXT): {$(VPATH)}id_table.h
+vm_dump.$(OBJEXT): {$(VPATH)}intern.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/abi.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/assume.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/cast.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/config.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+vm_dump.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/gc.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/glob.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/globals.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/symbol.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/value.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/value_type.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/variable.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+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_compile.h
+vm_dump.$(OBJEXT): {$(VPATH)}prism_xallocator.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
+vm_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+vm_dump.$(OBJEXT): {$(VPATH)}thread_native.h
+vm_dump.$(OBJEXT): {$(VPATH)}vm_core.h
+vm_dump.$(OBJEXT): {$(VPATH)}vm_debug.h
+vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c
+vm_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
+vm_dump.$(OBJEXT): {$(VPATH)}zjit.h
+vm_sync.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+vm_sync.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+vm_sync.$(OBJEXT): $(CCAN_DIR)/list/list.h
+vm_sync.$(OBJEXT): $(CCAN_DIR)/str/str.h
+vm_sync.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/array.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/box.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h
+vm_sync.$(OBJEXT): $(top_srcdir)/internal/set_table.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
+vm_sync.$(OBJEXT): {$(VPATH)}assert.h
+vm_sync.$(OBJEXT): {$(VPATH)}atomic.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+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)}id.h
+vm_sync.$(OBJEXT): {$(VPATH)}id_table.h
+vm_sync.$(OBJEXT): {$(VPATH)}intern.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/abi.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/assume.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/cast.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/config.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+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
+vm_sync.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/gc.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/glob.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/globals.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/symbol.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/value.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/value_type.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/variable.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+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
+vm_sync.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+vm_sync.$(OBJEXT): {$(VPATH)}thread_native.h
+vm_sync.$(OBJEXT): {$(VPATH)}vm_core.h
+vm_sync.$(OBJEXT): {$(VPATH)}vm_debug.h
+vm_sync.$(OBJEXT): {$(VPATH)}vm_opts.h
+vm_sync.$(OBJEXT): {$(VPATH)}vm_sync.c
+vm_sync.$(OBJEXT): {$(VPATH)}vm_sync.h
+vm_trace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+vm_trace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+vm_trace.$(OBJEXT): $(CCAN_DIR)/list/list.h
+vm_trace.$(OBJEXT): $(CCAN_DIR)/str/str.h
+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/box.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
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+vm_trace.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/ast.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/comments.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/integer.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/json.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/node.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/source.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/stream.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+vm_trace.$(OBJEXT): $(top_srcdir)/prism/version.h
+vm_trace.$(OBJEXT): {$(VPATH)}assert.h
+vm_trace.$(OBJEXT): {$(VPATH)}atomic.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+vm_trace.$(OBJEXT): {$(VPATH)}builtin.h
+vm_trace.$(OBJEXT): {$(VPATH)}config.h
+vm_trace.$(OBJEXT): {$(VPATH)}constant.h
+vm_trace.$(OBJEXT): {$(VPATH)}debug.h
+vm_trace.$(OBJEXT): {$(VPATH)}debug_counter.h
+vm_trace.$(OBJEXT): {$(VPATH)}defines.h
+vm_trace.$(OBJEXT): {$(VPATH)}encoding.h
+vm_trace.$(OBJEXT): {$(VPATH)}eval_intern.h
+vm_trace.$(OBJEXT): {$(VPATH)}id.h
+vm_trace.$(OBJEXT): {$(VPATH)}id_table.h
+vm_trace.$(OBJEXT): {$(VPATH)}intern.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/abi.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/assume.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/cast.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/config.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/ctype.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/dosish.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/error.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/eval.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/event.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/gc.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/glob.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/globals.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/symbol.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/value.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/value_type.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/variable.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+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)}node.h
+vm_trace.$(OBJEXT): {$(VPATH)}onigmo.h
+vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h
+vm_trace.$(OBJEXT): {$(VPATH)}prism_compile.h
+vm_trace.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+vm_trace.$(OBJEXT): {$(VPATH)}ractor.h
+vm_trace.$(OBJEXT): {$(VPATH)}ractor_core.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
+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
+vm_trace.$(OBJEXT): {$(VPATH)}zjit.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/box.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/set_table.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)}id_table.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/set.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/stdckdint.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
+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/box.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/class.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/compar.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
+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/set_table.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/string.h
+yjit.$(OBJEXT): $(top_srcdir)/internal/struct.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/arena.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/ast.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/json.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/node.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/options.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/serialize.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/source.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+yjit.$(OBJEXT): $(top_srcdir)/prism/version.h
+yjit.$(OBJEXT): {$(VPATH)}assert.h
+yjit.$(OBJEXT): {$(VPATH)}atomic.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+yjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+yjit.$(OBJEXT): {$(VPATH)}builtin.h
+yjit.$(OBJEXT): {$(VPATH)}config.h
+yjit.$(OBJEXT): {$(VPATH)}constant.h
+yjit.$(OBJEXT): {$(VPATH)}debug.h
+yjit.$(OBJEXT): {$(VPATH)}debug_counter.h
+yjit.$(OBJEXT): {$(VPATH)}defines.h
+yjit.$(OBJEXT): {$(VPATH)}encindex.h
+yjit.$(OBJEXT): {$(VPATH)}encoding.h
+yjit.$(OBJEXT): {$(VPATH)}id.h
+yjit.$(OBJEXT): {$(VPATH)}id_table.h
+yjit.$(OBJEXT): {$(VPATH)}insns.def
+yjit.$(OBJEXT): {$(VPATH)}insns.inc
+yjit.$(OBJEXT): {$(VPATH)}insns_info.inc
+yjit.$(OBJEXT): {$(VPATH)}intern.h
+yjit.$(OBJEXT): {$(VPATH)}internal.h
+yjit.$(OBJEXT): {$(VPATH)}internal/abi.h
+yjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+yjit.$(OBJEXT): {$(VPATH)}internal/assume.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+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
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+yjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+yjit.$(OBJEXT): {$(VPATH)}internal/cast.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+yjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+yjit.$(OBJEXT): {$(VPATH)}internal/config.h
+yjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+yjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+yjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+yjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+yjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+yjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+yjit.$(OBJEXT): {$(VPATH)}internal/error.h
+yjit.$(OBJEXT): {$(VPATH)}internal/eval.h
+yjit.$(OBJEXT): {$(VPATH)}internal/event.h
+yjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+yjit.$(OBJEXT): {$(VPATH)}internal/gc.h
+yjit.$(OBJEXT): {$(VPATH)}internal/glob.h
+yjit.$(OBJEXT): {$(VPATH)}internal/globals.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+yjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+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/hash.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+yjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+yjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+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/scan_args.h
+yjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+yjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+yjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+yjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+yjit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+yjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+yjit.$(OBJEXT): {$(VPATH)}internal/value.h
+yjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+yjit.$(OBJEXT): {$(VPATH)}internal/variable.h
+yjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+yjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+yjit.$(OBJEXT): {$(VPATH)}iseq.h
+yjit.$(OBJEXT): {$(VPATH)}method.h
+yjit.$(OBJEXT): {$(VPATH)}missing.h
+yjit.$(OBJEXT): {$(VPATH)}node.h
+yjit.$(OBJEXT): {$(VPATH)}onigmo.h
+yjit.$(OBJEXT): {$(VPATH)}oniguruma.h
+yjit.$(OBJEXT): {$(VPATH)}prism_compile.h
+yjit.$(OBJEXT): {$(VPATH)}prism_xallocator.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
+yjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+yjit.$(OBJEXT): {$(VPATH)}thread_native.h
+yjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+yjit.$(OBJEXT): {$(VPATH)}vm_core.h
+yjit.$(OBJEXT): {$(VPATH)}vm_debug.h
+yjit.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
+yjit.$(OBJEXT): {$(VPATH)}vm_opts.h
+yjit.$(OBJEXT): {$(VPATH)}vm_sync.h
+yjit.$(OBJEXT): {$(VPATH)}yjit.c
+yjit.$(OBJEXT): {$(VPATH)}yjit.h
+yjit.$(OBJEXT): {$(VPATH)}yjit.rbinc
+yjit.$(OBJEXT): {$(VPATH)}zjit.h
+zjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+zjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+zjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
+zjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
+zjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/array.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/bits.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/box.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/class.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/compar.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/string.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/struct.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
+zjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/arena.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/ast.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/buffer.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/comments.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/align.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/exported.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/filesystem.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nodiscard.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/compiler/nonnull.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/constant_pool.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/excludes.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/integer.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/char.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/encoding.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/list.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/memchr.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/regexp.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/static_literals.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/strncasecmp.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/internal/strpbrk.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/json.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/line_offset_list.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/magic_comments.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/node.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/options.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/parser.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/prism.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/serialize.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/source.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/stream.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/string_query.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/stringy.h
+zjit.$(OBJEXT): $(top_srcdir)/prism/version.h
+zjit.$(OBJEXT): {$(VPATH)}assert.h
+zjit.$(OBJEXT): {$(VPATH)}atomic.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+zjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+zjit.$(OBJEXT): {$(VPATH)}builtin.h
+zjit.$(OBJEXT): {$(VPATH)}config.h
+zjit.$(OBJEXT): {$(VPATH)}constant.h
+zjit.$(OBJEXT): {$(VPATH)}debug.h
+zjit.$(OBJEXT): {$(VPATH)}debug_counter.h
+zjit.$(OBJEXT): {$(VPATH)}defines.h
+zjit.$(OBJEXT): {$(VPATH)}encindex.h
+zjit.$(OBJEXT): {$(VPATH)}encoding.h
+zjit.$(OBJEXT): {$(VPATH)}id.h
+zjit.$(OBJEXT): {$(VPATH)}id_table.h
+zjit.$(OBJEXT): {$(VPATH)}insns.def
+zjit.$(OBJEXT): {$(VPATH)}insns.inc
+zjit.$(OBJEXT): {$(VPATH)}insns_info.inc
+zjit.$(OBJEXT): {$(VPATH)}intern.h
+zjit.$(OBJEXT): {$(VPATH)}internal.h
+zjit.$(OBJEXT): {$(VPATH)}internal/abi.h
+zjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+zjit.$(OBJEXT): {$(VPATH)}internal/assume.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+zjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+zjit.$(OBJEXT): {$(VPATH)}internal/cast.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+zjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+zjit.$(OBJEXT): {$(VPATH)}internal/config.h
+zjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+zjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+zjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+zjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+zjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+zjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+zjit.$(OBJEXT): {$(VPATH)}internal/error.h
+zjit.$(OBJEXT): {$(VPATH)}internal/eval.h
+zjit.$(OBJEXT): {$(VPATH)}internal/event.h
+zjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+zjit.$(OBJEXT): {$(VPATH)}internal/gc.h
+zjit.$(OBJEXT): {$(VPATH)}internal/glob.h
+zjit.$(OBJEXT): {$(VPATH)}internal/globals.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+zjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/set.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+zjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+zjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+zjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+zjit.$(OBJEXT): {$(VPATH)}internal/memory.h
+zjit.$(OBJEXT): {$(VPATH)}internal/method.h
+zjit.$(OBJEXT): {$(VPATH)}internal/module.h
+zjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+zjit.$(OBJEXT): {$(VPATH)}internal/numeric.h
+zjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+zjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+zjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+zjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+zjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+zjit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+zjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+zjit.$(OBJEXT): {$(VPATH)}internal/value.h
+zjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+zjit.$(OBJEXT): {$(VPATH)}internal/variable.h
+zjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+zjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+zjit.$(OBJEXT): {$(VPATH)}iseq.h
+zjit.$(OBJEXT): {$(VPATH)}method.h
+zjit.$(OBJEXT): {$(VPATH)}missing.h
+zjit.$(OBJEXT): {$(VPATH)}node.h
+zjit.$(OBJEXT): {$(VPATH)}onigmo.h
+zjit.$(OBJEXT): {$(VPATH)}oniguruma.h
+zjit.$(OBJEXT): {$(VPATH)}prism_compile.h
+zjit.$(OBJEXT): {$(VPATH)}prism_xallocator.h
+zjit.$(OBJEXT): {$(VPATH)}probes.dmyh
+zjit.$(OBJEXT): {$(VPATH)}probes.h
+zjit.$(OBJEXT): {$(VPATH)}probes_helper.h
+zjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
+zjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+zjit.$(OBJEXT): {$(VPATH)}rubyparser.h
+zjit.$(OBJEXT): {$(VPATH)}shape.h
+zjit.$(OBJEXT): {$(VPATH)}st.h
+zjit.$(OBJEXT): {$(VPATH)}subst.h
+zjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+zjit.$(OBJEXT): {$(VPATH)}thread_native.h
+zjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+zjit.$(OBJEXT): {$(VPATH)}vm_core.h
+zjit.$(OBJEXT): {$(VPATH)}vm_debug.h
+zjit.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
+zjit.$(OBJEXT): {$(VPATH)}vm_opts.h
+zjit.$(OBJEXT): {$(VPATH)}vm_sync.h
+zjit.$(OBJEXT): {$(VPATH)}yjit.h
+zjit.$(OBJEXT): {$(VPATH)}zjit.c
+zjit.$(OBJEXT): {$(VPATH)}zjit.h
+zjit.$(OBJEXT): {$(VPATH)}zjit.rbinc
+# AUTOGENERATED DEPENDENCIES END
diff --git a/dir.c b/dir.c
index b934f2795c..9f2d36b633 100644
--- a/dir.c
+++ b/dir.c
@@ -504,6 +504,20 @@ fnmatch(
}
VALUE rb_cDir;
+static VALUE sym_directory, sym_link, sym_file, sym_unknown;
+
+#if defined(DT_BLK) || defined(S_IFBLK)
+static VALUE sym_block_device;
+#endif
+#if defined(DT_CHR) || defined(S_IFCHR)
+static VALUE sym_character_device;
+#endif
+#if defined(DT_FIFO) || defined(S_IFIFO)
+static VALUE sym_fifo;
+#endif
+#if defined(DT_SOCK) || defined(S_IFSOCK)
+static VALUE sym_socket;
+#endif
struct dir_data {
DIR *dir;
@@ -905,14 +919,109 @@ dir_read(VALUE dir)
}
}
-static VALUE dir_each_entry(VALUE, VALUE (*)(VALUE, VALUE), VALUE, int);
+struct dir_entry_args {
+ struct dir_data *dirp;
+ struct dirent *dp;
+};
+
+static VALUE dir_each_entry(VALUE, VALUE (*)(VALUE, VALUE, struct dir_entry_args *), VALUE, int);
static VALUE
-dir_yield(VALUE arg, VALUE path)
+dir_yield(VALUE arg, VALUE path, struct dir_entry_args *_unused)
{
return rb_yield(path);
}
+static int do_lstat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc);
+
+static VALUE
+dir_yield_with_type(VALUE arg, VALUE path, struct dir_entry_args *dir_entry)
+{
+ VALUE type;
+ switch (dir_entry->dp->d_type) {
+#ifdef DT_BLK
+ case DT_BLK:
+ type = sym_block_device;
+ break;
+#endif
+#ifdef DT_CHR
+ case DT_CHR:
+ type = sym_character_device;
+ break;
+#endif
+ case DT_DIR:
+ type = sym_directory;
+ break;
+#ifdef DT_FIFO
+ case DT_FIFO:
+ type = sym_fifo;
+ break;
+#endif
+ case DT_LNK:
+ type = sym_link;
+ break;
+ case DT_REG:
+ type = sym_file;
+ break;
+#ifdef DT_SOCK
+ case DT_SOCK:
+ type = sym_socket;
+ break;
+#endif
+ default:
+ type = sym_unknown;
+ break;
+ }
+
+#ifdef HAVE_DIRFD
+ if (RUBY_DEBUG || RB_UNLIKELY(type == sym_unknown)) {
+ struct stat st;
+ if (do_lstat(dirfd(dir_entry->dirp->dir), dir_entry->dp->d_name, &st, 0, rb_filesystem_encoding()) == 0) {
+ switch (st.st_mode & S_IFMT) {
+ case S_IFDIR:
+ type = sym_directory;
+ break;
+ case S_IFLNK:
+ type = sym_link;
+ break;
+ case S_IFREG:
+ type = sym_file;
+ break;
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ type = sym_socket;
+ break;
+#endif
+#ifdef S_IFIFO
+ case S_IFIFO:
+ type = sym_fifo;
+ break;
+#endif
+#ifdef S_IFBLK
+ case S_IFBLK:
+ type = sym_block_device;
+ break;
+#endif
+#ifdef S_IFCHR
+ case S_IFCHR:
+ type = sym_character_device;
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ }
+#endif // HAVE_DIRFD
+
+ if (NIL_P(arg)) {
+ return rb_yield_values(2, path, type);
+ }
+ else {
+ return rb_ary_push(arg, rb_assoc_new(path, type));
+ }
+}
+
/*
* call-seq:
* each {|entry_name| ... } -> self
@@ -940,7 +1049,7 @@ dir_each(VALUE dir)
}
static VALUE
-dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_only)
+dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE, struct dir_entry_args *), VALUE arg, int children_only)
{
struct dir_data *dirp;
struct dirent *dp;
@@ -966,7 +1075,11 @@ dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_o
else
#endif
path = rb_external_str_new_with_enc(name, namlen, dirp->enc);
- (*each)(arg, path);
+ struct dir_entry_args each_args = {
+ .dirp = dirp,
+ .dp = dp,
+ };
+ (*each)(arg, path, &each_args);
}
return dir;
}
@@ -1472,24 +1585,55 @@ dir_chdir(VALUE dir)
#endif
}
+static VALUE last_cwd;
+
#ifndef _WIN32
+static VALUE
+getcwd_to_str(VALUE arg)
+{
+ const char *path = (const char *)arg;
+#ifdef __APPLE__
+ return rb_str_normalize_ospath(path, strlen(path));
+#else
+ return rb_str_new2(path);
+#endif
+}
+
+static VALUE
+getcwd_xfree(VALUE arg)
+{
+ xfree((void *)arg);
+ return Qnil;
+}
+
+static VALUE
+rb_dir_getwd_ospath_slowpath(void)
+{
+ char *path = ruby_getcwd();
+ return rb_ensure(getcwd_to_str, (VALUE)path, getcwd_xfree, (VALUE)path);
+}
+
VALUE
rb_dir_getwd_ospath(void)
{
- char *path;
- VALUE cwd;
- VALUE path_guard;
+ char buf[PATH_MAX];
+ char *path = getcwd(buf, PATH_MAX);
+ if (!path) {
+ return rb_dir_getwd_ospath_slowpath();
+ }
+
+ VALUE cached_cwd = RUBY_ATOMIC_VALUE_LOAD(last_cwd);
- path_guard = rb_imemo_tmpbuf_auto_free_pointer();
- path = ruby_getcwd();
- rb_imemo_tmpbuf_set_ptr(path_guard, path);
+ if (!cached_cwd || strcmp(RSTRING_PTR(cached_cwd), path) != 0) {
#ifdef __APPLE__
- cwd = rb_str_normalize_ospath(path, strlen(path));
+ cached_cwd = rb_str_normalize_ospath(path, strlen(path));
#else
- cwd = rb_str_new2(path);
+ cached_cwd = rb_str_new2(path);
#endif
- rb_free_tmp_buffer(&path_guard);
- return cwd;
+ rb_str_freeze(cached_cwd);
+ RUBY_ATOMIC_VALUE_SET(last_cwd, cached_cwd);
+ }
+ return cached_cwd;
}
#endif
@@ -1498,7 +1642,7 @@ rb_dir_getwd(void)
{
rb_encoding *fs = rb_filesystem_encoding();
int fsenc = rb_enc_to_index(fs);
- VALUE cwd = rb_dir_getwd_ospath();
+ VALUE cwd = rb_str_new_shared(rb_dir_getwd_ospath());
switch (fsenc) {
case ENCINDEX_US_ASCII:
@@ -1804,7 +1948,7 @@ nogvl_stat(void *args)
/* System call with warning */
static int
-do_stat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
+do_stat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc)
{
#if USE_OPENDIR_AT
struct fstatat_args args;
@@ -1836,7 +1980,7 @@ nogvl_lstat(void *args)
#endif
static int
-do_lstat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
+do_lstat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc)
{
#if USE_OPENDIR_AT
struct fstatat_args args;
@@ -2659,8 +2803,10 @@ glob_opendir(ruby_glob_entries_t *ent, DIR *dirp, int flags, rb_encoding *enc)
}
if (count >= capacity) {
capacity += 256;
- if (!(newp = GLOB_REALLOC_N(ent->sort.entries, capacity)))
+ if (!(newp = GLOB_REALLOC_N(ent->sort.entries, capacity))) {
+ GLOB_FREE(rdp);
goto nomem;
+ }
ent->sort.entries = newp;
}
ent->sort.entries[count++] = rdp;
@@ -2779,7 +2925,7 @@ glob_helper(
if (*path) {
if (match_all && pathtype == path_unknown) {
- if (do_lstat(fd, baselen, path, &st, flags, enc) == 0) {
+ if (do_lstat(fd, path, &st, flags, enc) == 0) {
pathtype = IFTODT(st.st_mode);
}
else {
@@ -2787,7 +2933,7 @@ glob_helper(
}
}
if (match_dir && (pathtype == path_unknown || pathtype == path_symlink)) {
- if (do_stat(fd, baselen, path, &st, flags, enc) == 0) {
+ if (do_stat(fd, path, &st, flags, enc) == 0) {
pathtype = IFTODT(st.st_mode);
}
else {
@@ -2915,7 +3061,7 @@ glob_helper(
if (recursive && dotfile < ((flags & FNM_DOTMATCH) ? 2 : 1) &&
new_pathtype == path_unknown) {
/* RECURSIVE never match dot files unless FNM_DOTMATCH is set */
- if (do_lstat(fd, baselen, buf, &st, flags, enc) == 0)
+ if (do_lstat(fd, buf, &st, flags, enc) == 0)
new_pathtype = IFTODT(st.st_mode);
else
new_pathtype = path_noent;
@@ -3471,10 +3617,16 @@ dir_foreach(int argc, VALUE *argv, VALUE io)
}
static VALUE
+dir_entry_ary_push(VALUE ary, VALUE entry, struct dir_entry_args *_unused)
+{
+ return rb_ary_push(ary, entry);
+}
+
+static VALUE
dir_collect(VALUE dir)
{
VALUE ary = rb_ary_new();
- dir_each_entry(dir, rb_ary_push, ary, FALSE);
+ dir_each_entry(dir, dir_entry_ary_push, ary, FALSE);
return ary;
}
@@ -3569,12 +3721,37 @@ static VALUE
dir_collect_children(VALUE dir)
{
VALUE ary = rb_ary_new();
- dir_each_entry(dir, rb_ary_push, ary, TRUE);
+ dir_each_entry(dir, dir_entry_ary_push, ary, TRUE);
return ary;
}
/*
* call-seq:
+ * children -> array
+ *
+ * Returns an array of the entry names in +self+ along with their type
+ * except for <tt>'.'</tt> and <tt>'..'</tt>:
+ *
+ * dir = Dir.new('/example')
+ * dir.scan # => [["config.h", :file], ["lib", :directory], ["main.rb", :file]]
+ *
+ */
+static VALUE
+dir_scan_children(VALUE dir)
+{
+ if (rb_block_given_p()) {
+ dir_each_entry(dir, dir_yield_with_type, Qnil, TRUE);
+ return Qnil;
+ }
+ else {
+ VALUE ary = rb_ary_new();
+ dir_each_entry(dir, dir_yield_with_type, ary, TRUE);
+ return ary;
+ }
+}
+
+/*
+ * call-seq:
* Dir.children(dirpath) -> array
* Dir.children(dirpath, encoding: 'UTF-8') -> array
*
@@ -3601,6 +3778,40 @@ dir_s_children(int argc, VALUE *argv, VALUE io)
return rb_ensure(dir_collect_children, dir, dir_close, dir);
}
+/*
+ * call-seq:
+ * Dir.scan(dirpath) {|entry_name, entry_type| ... } -> nil
+ * Dir.scan(dirpath, encoding: 'UTF-8') {|entry_name, entry_type| ... } -> nil
+ * Dir.scan(dirpath) -> [[entry_name, entry_type], ...]
+ * Dir.scan(dirpath, encoding: 'UTF-8') -> [[entry_name, entry_type], ...]
+ *
+ * Yields or returns an array of the entry names in the directory at +dirpath+
+ * associated with their type, except for <tt>'.'</tt> and <tt>'..'</tt>;
+ * sets the given encoding onto each returned entry name.
+ *
+ * The type symbol is one of:
+ * ``<code>:file</code>'', ``<code>:directory</code>'',
+ * ``<code>:characterSpecial</code>'', ``<code>:blockSpecial</code>'',
+ * ``<code>:fifo</code>'', ``<code>:link</code>'',
+ * or ``<code>:socket</code>'':
+ *
+ * Dir.children('/example') # => [["config.h", :file], ["lib", :directory], ["main.rb", :file]]
+ * Dir.children('/example').first.first.encoding
+ * # => #<Encoding:UTF-8>
+ * Dir.children('/example', encoding: 'US-ASCII').first.encoding
+ * # => #<Encoding:US-ASCII>
+ *
+ * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
+ *
+ * Raises an exception if the directory does not exist.
+ */
+static VALUE
+dir_s_scan(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE dir = dir_open_dir(argc, argv);
+ return rb_ensure(dir_scan_children, dir, dir_close, dir);
+}
+
static int
fnmatch_brace(const char *pattern, VALUE val, void *enc)
{
@@ -3804,8 +4015,27 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
void
Init_Dir(void)
{
+ sym_directory = ID2SYM(rb_intern("directory"));
+ sym_link = ID2SYM(rb_intern("link"));
+ sym_file = ID2SYM(rb_intern("file"));
+ sym_unknown = ID2SYM(rb_intern("unknown"));
+
+#if defined(DT_BLK) || defined(S_IFBLK)
+ sym_block_device = ID2SYM(rb_intern("blockSpecial"));
+#endif
+#if defined(DT_CHR) || defined(S_IFCHR)
+ sym_character_device = ID2SYM(rb_intern("characterSpecial"));
+#endif
+#if defined(DT_FIFO) || defined(S_IFIFO)
+ sym_fifo = ID2SYM(rb_intern("fifo"));
+#endif
+#if defined(DT_SOCK) || defined(S_IFSOCK)
+ sym_socket = ID2SYM(rb_intern("socket"));
+#endif
+
rb_gc_register_address(&chdir_lock.path);
rb_gc_register_address(&chdir_lock.thread);
+ rb_gc_register_address(&last_cwd);
rb_cDir = rb_define_class("Dir", rb_cObject);
@@ -3817,6 +4047,7 @@ Init_Dir(void)
rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
rb_define_singleton_method(rb_cDir, "each_child", dir_s_each_child, -1);
rb_define_singleton_method(rb_cDir, "children", dir_s_children, -1);
+ rb_define_singleton_method(rb_cDir, "scan", dir_s_scan, -1);
rb_define_method(rb_cDir,"fileno", dir_fileno, 0);
rb_define_method(rb_cDir,"path", dir_path, 0);
@@ -3826,6 +4057,7 @@ Init_Dir(void)
rb_define_method(rb_cDir,"each", dir_each, 0);
rb_define_method(rb_cDir,"each_child", dir_each_child_m, 0);
rb_define_method(rb_cDir,"children", dir_collect_children, 0);
+ rb_define_method(rb_cDir,"scan", dir_scan_children, 0);
rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
rb_define_method(rb_cDir,"tell", dir_tell, 0);
rb_define_method(rb_cDir,"seek", dir_seek, 1);
diff --git a/dir.rb b/dir.rb
index 6cbfe1fb14..9b83f68822 100644
--- a/dir.rb
+++ b/dir.rb
@@ -31,7 +31,7 @@
# 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].
+# - It includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here].
#
# == \Dir As Stream-Like
#
@@ -85,8 +85,8 @@
#
# First, what's elsewhere. Class \Dir:
#
-# - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
-# - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+# - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+# - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
# which provides dozens of additional methods.
#
# Here, class \Dir provides methods that are useful for:
@@ -178,7 +178,7 @@ class Dir
# 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('.', encoding: Encoding::US_ASCII).read.encoding # => #<Encoding:US-ASCII>
#
def self.open(name, encoding: nil, &block)
dir = Primitive.dir_s_open(name, encoding)
@@ -206,7 +206,7 @@ class Dir
# 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>
+ # Dir.new('.', encoding: Encoding::US_ASCI).read.encoding # => #<Encoding:US-ASCII>
#
def initialize(name, encoding: nil)
Primitive.dir_initialize(name, encoding)
@@ -224,8 +224,8 @@ class Dir
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
+ # 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.
#
@@ -319,14 +319,14 @@ class Dir
#
# Dir.glob('io.?') # => ["io.c"]
#
- # - <tt>'[_set_]'</tt>: Matches any one character in the string _set_;
+ # - <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>:
+ # - <tt>'{abc,xyz}'</tt>:
# Matches either string _abc_ or string _xyz_;
# behaves like {Regexp alternation}[rdoc-ref:Regexp@Alternation]:
#
@@ -388,10 +388,10 @@ class Dir
#
# - File::FNM_EXTGLOB:
# enables the pattern extension
- # <tt>'{_a_,_b_}'</tt>, which matches pattern _a_ and pattern _b_;
+ # <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>):
+ # (e.g., <tt>'(?:a|b)'</tt>):
#
# pattern = '{LEGAL,BSDL}'
# Dir.glob(pattern) # => ["LEGAL", "BSDL"]
diff --git a/dln.c b/dln.c
index cd9792c432..d3b03e3e87 100644
--- a/dln.c
+++ b/dln.c
@@ -25,6 +25,7 @@ static void dln_loaderror(const char *format, ...);
#endif
#include "dln.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/compilers.h"
#ifdef HAVE_STDLIB_H
@@ -76,6 +77,10 @@ void *xrealloc();
# include <unistd.h>
#endif
+#ifndef UNREACHABLE_RETURN
+# define UNREACHABLE_RETURN(x) return (x)
+#endif
+
#ifndef dln_loaderror
static void
dln_loaderror(const char *format, ...)
@@ -347,6 +352,7 @@ dln_open(const char *file)
void *handle;
#if defined(_WIN32)
+# define DLN_DEFINED
char message[1024];
/* Convert the file path to wide char */
@@ -373,6 +379,7 @@ dln_open(const char *file)
# endif
#elif defined(USE_DLN_DLOPEN)
+# define DLN_DEFINED
# ifndef RTLD_LAZY
# define RTLD_LAZY 1
@@ -383,9 +390,13 @@ dln_open(const char *file)
# ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0
# endif
+# ifndef RTLD_LOCAL
+# define RTLD_LOCAL 0 /* TODO: 0??? some systems (including libc) use 0x00100 for RTLD_GLOBAL, 0x00000 for RTLD_LOCAL */
+# endif
/* Load file */
- handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL);
+ int mode = rb_box_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL;
+ handle = dlopen(file, mode);
if (handle == NULL) {
error = dln_strerror();
goto failed;
@@ -497,10 +508,10 @@ abi_check_enabled_p(void)
}
#endif
-void *
-dln_load(const char *file)
+static void *
+dln_load_and_init(const char *file, const char *init_fct_name)
{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
+#if defined(DLN_DEFINED)
void *handle = dln_open(file);
#ifdef RUBY_DLN_CHECK_ABI
@@ -512,18 +523,17 @@ dln_load(const char *file)
}
#endif
- char *init_fct_name;
- init_funcname(&init_fct_name, file);
-
/* Call the init code */
dln_sym_callable(void, (void), handle, init_fct_name)();
return handle;
#elif defined(_AIX)
+# define DLN_DEFINED
{
void (*init_fct)(void);
+ /* TODO: check - AIX's load system call will return the first/last symbol/function? */
init_fct = (void(*)(void))load((char*)file, 1, 0);
if (init_fct == NULL) {
aix_loaderror(file);
@@ -536,7 +546,25 @@ dln_load(const char *file)
}
#else
dln_notimplement();
+ UNREACHABLE_RETURN(0);
#endif
+}
- return 0; /* dummy return */
+void *
+dln_load(const char *file)
+{
+ return dln_load_feature(file, file);
+}
+
+void *
+dln_load_feature(const char *file, const char *fname)
+{
+#if defined(DLN_DEFINED)
+ char *init_fct_name;
+ init_funcname(&init_fct_name, fname);
+ return dln_load_and_init(file, init_fct_name);
+#else
+ dln_notimplement();
+ UNREACHABLE_RETURN(0);
+#endif
}
diff --git a/dln.h b/dln.h
index d624bb6611..711abf592c 100644
--- a/dln.h
+++ b/dln.h
@@ -25,6 +25,7 @@ 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_load_feature(const char*, const char*);
void *dln_symbol(void*,const char*);
RUBY_SYMBOL_EXPORT_END
diff --git a/dmydln.c b/dmydln.c
index 35824ebec8..62a89e2da5 100644
--- a/dmydln.c
+++ b/dmydln.c
@@ -12,6 +12,15 @@ dln_load(const char *file)
UNREACHABLE_RETURN(NULL);
}
+NORETURN(void *dln_load_feature(const char*,const char*));
+void*
+dln_load_feature(const char *file, const char *fname)
+{
+ rb_loaderror("this executable file can't load extension libraries");
+
+ UNREACHABLE_RETURN(NULL);
+}
+
NORETURN(void *dln_symbol(void*,const char*));
void*
dln_symbol(void *handle, const char *symbol)
diff --git a/doc/.document b/doc/.document
index 6e6caa8333..337289a662 100644
--- a/doc/.document
+++ b/doc/.document
@@ -1,12 +1,14 @@
-*.md
-*.rb
+[^_]*.md
+[^_]*.rb
[^_]*.rdoc
contributing
+distribution
NEWS
syntax
optparse
-date
-rdoc
-regexp
-yjit
-ruby
+jit
+security
+language
+strscan
+file
+
diff --git a/doc/NEWS/NEWS-3.0.0.md b/doc/NEWS/NEWS-3.0.0.md
index 004fa4bf67..9fbaf504b4 100644
--- a/doc/NEWS/NEWS-3.0.0.md
+++ b/doc/NEWS/NEWS-3.0.0.md
@@ -367,11 +367,11 @@ Outstanding ones only.
* Fiber.blocking? tells whether the current execution context is
blocking. [[Feature #16786]]
+* Thread
+
* Thread#join invokes the scheduler hooks `block`/`unblock` in a
non-blocking execution context. [[Feature #16786]]
-* Thread
-
* Thread.ignore_deadlock accessor has been added for disabling the
default deadlock detection, allowing the use of signal handlers to
break deadlock. [[Bug #13768]]
diff --git a/doc/NEWS/NEWS-4.0.0.md b/doc/NEWS/NEWS-4.0.0.md
new file mode 100644
index 0000000000..5d932fbf5d
--- /dev/null
+++ b/doc/NEWS/NEWS-4.0.0.md
@@ -0,0 +1,802 @@
+# NEWS for Ruby 4.0.0
+
+This document is a list of user-visible feature changes
+since the **3.4.0** release, except for bug fixes.
+
+Note that each entry is kept to a minimum, see links for details.
+
+## Language changes
+
+* `*nil` no longer calls `nil.to_a`, similar to how `**nil` does
+ not call `nil.to_hash`. [[Feature #21047]]
+
+* Logical binary operators (`||`, `&&`, `and` and `or`) at the
+ beginning of a line continue the previous line, like fluent dot.
+ The following code examples are equal:
+
+ ```ruby
+ if condition1
+ && condition2
+ ...
+ end
+ ```
+
+ Previously:
+
+ ```ruby
+ if condition1 && condition2
+ ...
+ end
+ ```
+
+ ```ruby
+ if condition1 &&
+ condition2
+ ...
+ end
+ ```
+
+ [[Feature #20925]]
+
+## Core classes updates
+
+Note: We're only listing outstanding class updates.
+
+* Array
+
+ * `Array#rfind` has been added as a more efficient alternative to `array.reverse_each.find` [[Feature #21678]]
+ * `Array#find` has been added as a more efficient override of `Enumerable#find` [[Feature #21678]]
+* Binding
+
+ * `Binding#local_variables` does no longer include numbered parameters.
+ Also, `Binding#local_variable_get`, `Binding#local_variable_set`, and
+ `Binding#local_variable_defined?` reject to handle numbered parameters.
+ [[Bug #21049]]
+
+ * `Binding#implicit_parameters`, `Binding#implicit_parameter_get`, and
+ `Binding#implicit_parameter_defined?` have been added to access
+ numbered parameters and "it" parameter. [[Bug #21049]]
+
+* Enumerator
+
+ * `Enumerator.produce` now accepts an optional `size` keyword argument
+ to specify the size of the enumerator. It can be an integer,
+ `Float::INFINITY`, a callable object (such as a lambda), or `nil` to
+ indicate unknown size. When not specified, the size defaults to
+ `Float::INFINITY`.
+
+ ```ruby
+ # Infinite enumerator
+ enum = Enumerator.produce(1, size: Float::INFINITY, &:succ)
+ enum.size # => Float::INFINITY
+
+ # Finite enumerator with known/computable size
+ abs_dir = File.expand_path("./baz") # => "/foo/bar/baz"
+ traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) {
+ raise StopIteration if it == "/"
+ File.dirname(it)
+ }
+ traverser.size # => 4
+ ```
+
+ [[Feature #21701]]
+
+* ErrorHighlight
+
+ * When an ArgumentError is raised, it now displays code snippets for
+ both the method call (caller) and the method definition (callee).
+ [[Feature #21543]]
+
+ ```
+ test.rb:1:in 'Object#add': wrong number of arguments (given 1, expected 2) (ArgumentError)
+
+ caller: test.rb:3
+ | add(1)
+ ^^^
+ callee: test.rb:1
+ | def add(x, y) = x + y
+ ^^^
+ from test.rb:3:in '<main>'
+ ```
+
+* Fiber
+
+ * Introduce support for `Fiber#raise(cause:)` argument similar to
+ `Kernel#raise`. [[Feature #21360]]
+
+* Fiber::Scheduler
+
+ * Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a
+ given exception. The initial use case is to interrupt a fiber that is
+ waiting on a blocking IO operation when the IO operation is closed.
+ [[Feature #21166]]
+
+ * Introduce `Fiber::Scheduler#yield` to allow the fiber scheduler to
+ continue processing when signal exceptions are disabled.
+ [[Bug #21633]]
+
+ * Reintroduce the `Fiber::Scheduler#io_close` hook for asynchronous `IO#close`.
+
+ * Invoke `Fiber::Scheduler#io_write` when flushing the IO write buffer.
+ [[Bug #21789]]
+
+* File
+
+ * `File::Stat#birthtime` is now available on Linux via the statx
+ system call when supported by the kernel and filesystem.
+ [[Feature #21205]]
+
+* IO
+
+ * `IO.select` accepts `Float::INFINITY` as a timeout argument.
+ [[Feature #20610]]
+
+ * A deprecated behavior, process creation by `IO` class methods
+ with a leading `|`, was removed. [[Feature #19630]]
+
+* Kernel
+
+ * `Kernel#inspect` now checks for the existence of a `#instance_variables_to_inspect` method,
+ allowing control over which instance variables are displayed in the `#inspect` string:
+
+ ```ruby
+ class DatabaseConfig
+ def initialize(host, user, password)
+ @host = host
+ @user = user
+ @password = password
+ end
+
+ private def instance_variables_to_inspect = [:@host, :@user]
+ end
+
+ conf = DatabaseConfig.new("localhost", "root", "hunter2")
+ conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
+ ```
+
+ [[Feature #21219]]
+
+ * A deprecated behavior, process creation by `Kernel#open` with a
+ leading `|`, was removed. [[Feature #19630]]
+
+* Math
+
+ * `Math.log1p` and `Math.expm1` are added. [[Feature #21527]]
+
+* Pathname
+
+ * Pathname has been promoted from a default gem to a core class of Ruby.
+ [[Feature #17473]]
+
+* Proc
+
+ * `Proc#parameters` now shows anonymous optional parameters as `[:opt]`
+ instead of `[:opt, nil]`, making the output consistent with when the
+ anonymous parameter is required. [[Bug #20974]]
+
+* Ractor
+
+ * `Ractor::Port` class was added for a new synchronization mechanism
+ to communicate between Ractors. [[Feature #21262]]
+
+ ```ruby
+ port1 = Ractor::Port.new
+ port2 = Ractor::Port.new
+ Ractor.new port1, port2 do |port1, port2|
+ port1 << 1
+ port2 << 11
+ port1 << 2
+ port2 << 12
+ end
+ 2.times{ p port1.receive } #=> 1, 2
+ 2.times{ p port2.receive } #=> 11, 12
+ ```
+
+ `Ractor::Port` provides the following methods:
+
+ * `Ractor::Port#receive`
+ * `Ractor::Port#send` (or `Ractor::Port#<<`)
+ * `Ractor::Port#close`
+ * `Ractor::Port#closed?`
+
+ As a result, `Ractor.yield` and `Ractor#take` were removed.
+
+ * `Ractor#join` and `Ractor#value` were added to wait for the
+ termination of a Ractor. These are similar to `Thread#join`
+ and `Thread#value`.
+
+ * `Ractor#monitor` and `Ractor#unmonitor` were added as low-level
+ interfaces used internally to implement `Ractor#join`.
+
+ * `Ractor.select` now only accepts Ractors and Ports. If Ractors are given,
+ it returns when a Ractor terminates.
+
+ * `Ractor#default_port` was added. Each `Ractor` has a default port,
+ which is used by `Ractor.send`, `Ractor.receive`.
+
+ * `Ractor#close_incoming` and `Ractor#close_outgoing` were removed.
+
+ * `Ractor.shareable_proc` and `Ractor.shareable_lambda` are introduced
+ to make shareable Proc or lambda.
+ [[Feature #21550]], [[Feature #21557]]
+
+* Range
+
+ * `Range#to_set` now performs size checks to prevent issues with
+ endless ranges. [[Bug #21654]]
+
+ * `Range#overlap?` now correctly handles infinite (unbounded) ranges.
+ [[Bug #21185]]
+
+ * `Range#max` behavior on beginless integer ranges has been fixed.
+ [[Bug #21174]] [[Bug #21175]]
+
+* Ruby
+
+ * A new toplevel module `Ruby` has been defined, which contains
+ Ruby-related constants. This module was reserved in Ruby 3.4
+ and is now officially defined. [[Feature #20884]]
+
+* Ruby::Box
+
+ * A new (experimental) feature to provide separation about definitions.
+ For the detail of "Ruby Box", see [doc/language/box.md](doc/language/box.md).
+ [[Feature #21311]] [[Misc #21385]]
+
+* Set
+
+ * `Set` is now a core class, instead of an autoloaded stdlib class.
+ [[Feature #21216]]
+
+ * `Set#inspect` now uses a simpler display, similar to literal arrays.
+ (e.g., `Set[1, 2, 3]` instead of `#<Set: {1, 2, 3}>`). [[Feature #21389]]
+
+ * Passing arguments to `Set#to_set` and `Enumerable#to_set` is now deprecated.
+ [[Feature #21390]]
+
+* Socket
+
+ * `Socket.tcp` & `TCPSocket.new` accepts an `open_timeout` keyword argument to specify
+ the timeout for the initial connection. [[Feature #21347]]
+ * When a user-specified timeout occurred in `TCPSocket.new`, either `Errno::ETIMEDOUT`
+ or `IO::TimeoutError` could previously be raised depending on the situation.
+ This behavior has been unified so that `IO::TimeoutError` is now consistently raised.
+ (Please note that, in `Socket.tcp`, there are still cases where `Errno::ETIMEDOUT`
+ may be raised in similar situations, and that in both cases `Errno::ETIMEDOUT` may be
+ raised when the timeout occurs at the OS level.)
+
+* String
+
+ * Update Unicode to Version 17.0.0 and Emoji Version 17.0.
+ [[Feature #19908]][[Feature #20724]][[Feature #21275]] (also applies to Regexp)
+
+ * `String#strip`, `strip!`, `lstrip`, `lstrip!`, `rstrip`, and `rstrip!`
+ are extended to accept `*selectors` arguments. [[Feature #21552]]
+
+* Thread
+
+ * Introduce support for `Thread#raise(cause:)` argument similar to
+ `Kernel#raise`. [[Feature #21360]]
+
+## Stdlib updates
+
+We only list stdlib changes that are notable feature changes.
+
+Other changes are listed in the following sections. We also listed release
+history from the previous bundled version that is Ruby 3.4.0 if it has GitHub
+releases.
+
+The following bundled gems are promoted from default gems.
+
+* ostruct 0.6.3
+ * 0.6.1 to [v0.6.2][ostruct-v0.6.2], [v0.6.3][ostruct-v0.6.3]
+* pstore 0.2.0
+ * 0.1.4 to [v0.2.0][pstore-v0.2.0]
+* benchmark 0.5.0
+ * 0.4.0 to [v0.4.1][benchmark-v0.4.1], [v0.5.0][benchmark-v0.5.0]
+* logger 1.7.0
+ * 1.6.4 to [v1.6.5][logger-v1.6.5], [v1.6.6][logger-v1.6.6], [v1.7.0][logger-v1.7.0]
+* rdoc 7.0.3
+ * 6.14.0 to [v6.14.1][rdoc-v6.14.1], [v6.14.2][rdoc-v6.14.2], [v6.15.0][rdoc-v6.15.0], [v6.15.1][rdoc-v6.15.1], [v6.16.0][rdoc-v6.16.0], [v6.16.1][rdoc-v6.16.1], [v6.17.0][rdoc-v6.17.0], [v7.0.0][rdoc-v7.0.0], [v7.0.1][rdoc-v7.0.1], [v7.0.2][rdoc-v7.0.2], [v7.0.3][rdoc-v7.0.3]
+* win32ole 1.9.2
+ * 1.9.1 to [v1.9.2][win32ole-v1.9.2]
+* irb 1.16.0
+ * 1.14.3 to [v1.15.0][irb-v1.15.0], [v1.15.1][irb-v1.15.1], [v1.15.2][irb-v1.15.2], [v1.15.3][irb-v1.15.3], [v1.16.0][irb-v1.16.0]
+* reline 0.6.3
+ * 0.6.0 to [v0.6.1][reline-v0.6.1], [v0.6.2][reline-v0.6.2], [v0.6.3][reline-v0.6.3]
+* readline 0.0.4
+* fiddle 1.1.8
+ * 1.1.6 to [v1.1.7][fiddle-v1.1.7], [v1.1.8][fiddle-v1.1.8]
+
+The following default gem is added.
+
+* win32-registry 0.1.2
+
+The following default gems are updated.
+
+* RubyGems 4.0.3
+* bundler 4.0.3
+* date 3.5.1
+ * 3.4.1 to [v3.5.0][date-v3.5.0], [v3.5.1][date-v3.5.1]
+* delegate 0.6.1
+ * 0.4.0 to [v0.5.0][delegate-v0.5.0], [v0.6.0][delegate-v0.6.0], [v0.6.1][delegate-v0.6.1]
+* digest 3.2.1
+ * 3.2.0 to [v3.2.1][digest-v3.2.1]
+* english 0.8.1
+ * 0.8.0 to [v0.8.1][english-v0.8.1]
+* erb 6.0.1
+ * 4.0.4 to [v5.1.2][erb-v5.1.2], [v5.1.3][erb-v5.1.3], [v6.0.0][erb-v6.0.0], [v6.0.1][erb-v6.0.1]
+* error_highlight 0.7.1
+* etc 1.4.6
+* fcntl 1.3.0
+ * 1.2.0 to [v1.3.0][fcntl-v1.3.0]
+* fileutils 1.8.0
+ * 1.7.3 to [v1.8.0][fileutils-v1.8.0]
+* forwardable 1.4.0
+ * 1.3.3 to [v1.4.0][forwardable-v1.4.0]
+* io-console 0.8.2
+ * 0.8.1 to [v0.8.2][io-console-v0.8.2]
+* io-nonblock 0.3.2
+* io-wait 0.4.0
+ * 0.3.2 to [v0.3.3][io-wait-v0.3.3], [v0.3.5.test1][io-wait-v0.3.5.test1], [v0.3.5][io-wait-v0.3.5], [v0.3.6][io-wait-v0.3.6], [v0.4.0][io-wait-v0.4.0]
+* ipaddr 1.2.8
+* json 2.18.0
+ * 2.9.1 to [v2.10.0][json-v2.10.0], [v2.10.1][json-v2.10.1], [v2.10.2][json-v2.10.2], [v2.11.0][json-v2.11.0], [v2.11.1][json-v2.11.1], [v2.11.2][json-v2.11.2], [v2.11.3][json-v2.11.3], [v2.12.0][json-v2.12.0], [v2.12.1][json-v2.12.1], [v2.12.2][json-v2.12.2], [v2.13.0][json-v2.13.0], [v2.13.1][json-v2.13.1], [v2.13.2][json-v2.13.2], [v2.14.0][json-v2.14.0], [v2.14.1][json-v2.14.1], [v2.15.0][json-v2.15.0], [v2.15.1][json-v2.15.1], [v2.15.2][json-v2.15.2], [v2.16.0][json-v2.16.0], [v2.17.0][json-v2.17.0], [v2.17.1][json-v2.17.1], [v2.18.0][json-v2.18.0]
+* net-http 0.9.1
+ * 0.6.0 to [v0.7.0][net-http-v0.7.0], [v0.8.0][net-http-v0.8.0], [v0.9.0][net-http-v0.9.0], [v0.9.1][net-http-v0.9.1]
+* openssl 4.0.0
+ * 3.3.1 to [v3.3.2][openssl-v3.3.2], [v4.0.0][openssl-v4.0.0]
+* optparse 0.8.1
+ * 0.6.0 to [v0.7.0][optparse-v0.7.0], [v0.8.0][optparse-v0.8.0], [v0.8.1][optparse-v0.8.1]
+* pp 0.6.3
+ * 0.6.2 to [v0.6.3][pp-v0.6.3]
+* prism 1.7.0
+ * 1.5.2 to [v1.6.0][prism-v1.6.0], [v1.7.0][prism-v1.7.0]
+* psych 5.3.1
+ * 5.2.2 to [v5.2.3][psych-v5.2.3], [v5.2.4][psych-v5.2.4], [v5.2.5][psych-v5.2.5], [v5.2.6][psych-v5.2.6], [v5.3.0][psych-v5.3.0], [v5.3.1][psych-v5.3.1]
+* resolv 0.7.0
+ * 0.6.2 to [v0.6.3][resolv-v0.6.3], [v0.7.0][resolv-v0.7.0]
+* stringio 3.2.0
+ * 3.1.2 to [v3.1.3][stringio-v3.1.3], [v3.1.4][stringio-v3.1.4], [v3.1.5][stringio-v3.1.5], [v3.1.6][stringio-v3.1.6], [v3.1.7][stringio-v3.1.7], [v3.1.8][stringio-v3.1.8], [v3.1.9][stringio-v3.1.9], [v3.2.0][stringio-v3.2.0]
+* strscan 3.1.6
+ * 3.1.2 to [v3.1.3][strscan-v3.1.3], [v3.1.4][strscan-v3.1.4], [v3.1.5][strscan-v3.1.5], [v3.1.6][strscan-v3.1.6]
+* time 0.4.2
+ * 0.4.1 to [v0.4.2][time-v0.4.2]
+* timeout 0.6.0
+ * 0.4.3 to [v0.4.4][timeout-v0.4.4], [v0.5.0][timeout-v0.5.0], [v0.6.0][timeout-v0.6.0]
+* uri 1.1.1
+ * 1.0.4 to [v1.1.0][uri-v1.1.0], [v1.1.1][uri-v1.1.1]
+* weakref 0.1.4
+ * 0.1.3 to [v0.1.4][weakref-v0.1.4]
+* zlib 3.2.2
+ * 3.2.1 to [v3.2.2][zlib-v3.2.2]
+
+The following bundled gems are updated.
+
+* minitest 6.0.0
+* power_assert 3.0.1
+ * 2.0.5 to [v3.0.0][power_assert-v3.0.0], [v3.0.1][power_assert-v3.0.1]
+* rake 13.3.1
+ * 13.2.1 to [v13.3.0][rake-v13.3.0], [v13.3.1][rake-v13.3.1]
+* test-unit 3.7.5
+ * 3.6.7 to [3.6.8][test-unit-3.6.8], [3.6.9][test-unit-3.6.9], [3.7.0][test-unit-3.7.0], [3.7.1][test-unit-3.7.1], [3.7.2][test-unit-3.7.2], [3.7.3][test-unit-3.7.3], [3.7.4][test-unit-3.7.4], [3.7.5][test-unit-3.7.5]
+* rexml 3.4.4
+* rss 0.3.2
+ * 0.3.1 to [0.3.2][rss-0.3.2]
+* net-ftp 0.3.9
+ * 0.3.8 to [v0.3.9][net-ftp-v0.3.9]
+* net-imap 0.6.2
+ * 0.5.8 to [v0.5.9][net-imap-v0.5.9], [v0.5.10][net-imap-v0.5.10], [v0.5.11][net-imap-v0.5.11], [v0.5.12][net-imap-v0.5.12], [v0.5.13][net-imap-v0.5.13], [v0.6.0][net-imap-v0.6.0], [v0.6.1][net-imap-v0.6.1], [v0.6.2][net-imap-v0.6.2]
+* net-smtp 0.5.1
+ * 0.5.0 to [v0.5.1][net-smtp-v0.5.1]
+* matrix 0.4.3
+ * 0.4.2 to [v0.4.3][matrix-v0.4.3]
+* prime 0.1.4
+ * 0.1.3 to [v0.1.4][prime-v0.1.4]
+* rbs 3.10.0
+ * 3.8.0 to [v3.8.1][rbs-v3.8.1], [v3.9.0.dev.1][rbs-v3.9.0.dev.1], [v3.9.0.pre.1][rbs-v3.9.0.pre.1], [v3.9.0.pre.2][rbs-v3.9.0.pre.2], [v3.9.0][rbs-v3.9.0], [v3.9.1][rbs-v3.9.1], [v3.9.2][rbs-v3.9.2], [v3.9.3][rbs-v3.9.3], [v3.9.4][rbs-v3.9.4], [v3.9.5][rbs-v3.9.5], [v3.10.0.pre.1][rbs-v3.10.0.pre.1], [v3.10.0.pre.2][rbs-v3.10.0.pre.2], [v3.10.0][rbs-v3.10.0]
+* typeprof 0.31.1
+* debug 1.11.1
+ * 1.11.0 to [v1.11.1][debug-v1.11.1]
+* base64 0.3.0
+ * 0.2.0 to [v0.3.0][base64-v0.3.0]
+* bigdecimal 4.0.1
+ * 3.1.8 to [v3.2.0][bigdecimal-v3.2.0], [v3.2.1][bigdecimal-v3.2.1], [v3.2.2][bigdecimal-v3.2.2], [v3.2.3][bigdecimal-v3.2.3], [v3.3.0][bigdecimal-v3.3.0], [v3.3.1][bigdecimal-v3.3.1], [v4.0.0][bigdecimal-v4.0.0], [v4.0.1][bigdecimal-v4.0.1]
+* drb 2.2.3
+ * 2.2.1 to [v2.2.3][drb-v2.2.3]
+* syslog 0.3.0
+ * 0.2.0 to [v0.3.0][syslog-v0.3.0]
+* csv 3.3.5
+ * 3.3.2 to [v3.3.3][csv-v3.3.3], [v3.3.4][csv-v3.3.4], [v3.3.5][csv-v3.3.5]
+* repl_type_completor 0.1.12
+
+### RubyGems and Bundler
+
+Ruby 4.0 bundled RubyGems and Bundler version 4. see the following links for details.
+
+* [Upgrading to RubyGems/Bundler 4 - RubyGems Blog](https://blog.rubygems.org/2025/12/03/upgrade-to-rubygems-bundler-4.html)
+* [4.0.0 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/03/4.0.0-released.html)
+* [4.0.1 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/09/4.0.1-released.html)
+* [4.0.2 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/17/4.0.2-released.html)
+* [4.0.3 Released - RubyGems Blog](https://blog.rubygems.org/2025/12/23/4.0.3-released.html)
+
+## Supported platforms
+
+* Windows
+
+ * Dropped support for MSVC versions older than 14.0 (_MSC_VER 1900).
+ This means Visual Studio 2015 or later is now required.
+
+## Compatibility issues
+
+* The following methods were removed from Ractor due to the addition of `Ractor::Port`:
+
+ * `Ractor.yield`
+ * `Ractor#take`
+ * `Ractor#close_incoming`
+ * `Ractor#close_outgoing`
+
+ [[Feature #21262]]
+
+* `ObjectSpace._id2ref` is deprecated. [[Feature #15408]]
+
+* `Process::Status#&` and `Process::Status#>>` have been removed.
+ They were deprecated in Ruby 3.3. [[Bug #19868]]
+
+* `rb_path_check` has been removed. This function was used for
+ `$SAFE` path checking which was removed in Ruby 2.7,
+ and was already deprecated.
+ [[Feature #20971]]
+
+* A backtrace for `ArgumentError` of "wrong number of arguments" now
+ include the receiver's class or module name (e.g., in `Foo#bar`
+ instead of in `bar`). [[Bug #21698]]
+
+* Backtraces no longer display `internal` frames.
+ These methods now appear as if it is in the Ruby source file,
+ consistent with other C-implemented methods. [[Bug #20968]]
+
+ Before:
+ ```
+ ruby -e '[1].fetch_values(42)'
+ <internal:array>:211:in 'Array#fetch': index 42 outside of array bounds: -1...1 (IndexError)
+ from <internal:array>:211:in 'block in Array#fetch_values'
+ from <internal:array>:211:in 'Array#map!'
+ from <internal:array>:211:in 'Array#fetch_values'
+ from -e:1:in '<main>'
+ ```
+
+ After:
+ ```
+ $ ruby -e '[1].fetch_values(42)'
+ -e:1:in 'Array#fetch_values': index 42 outside of array bounds: -1...1 (IndexError)
+ from -e:1:in '<main>'
+ ```
+
+## Stdlib compatibility issues
+
+* CGI library is removed from the default gems. Now we only provide `cgi/escape` for
+ the following methods:
+
+ * `CGI.escape` and `CGI.unescape`
+ * `CGI.escapeHTML` and `CGI.unescapeHTML`
+ * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent`
+ * `CGI.escapeElement` and `CGI.unescapeElement`
+
+ [[Feature #21258]]
+
+* With the move of `Set` from stdlib to core class, `set/sorted_set.rb` has
+ been removed, and `SortedSet` is no longer an autoloaded constant. Please
+ install the `sorted_set` gem and `require 'sorted_set'` to use `SortedSet`.
+ [[Feature #21287]]
+
+* Net::HTTP
+
+ * The default behavior of automatically setting the `Content-Type` header
+ to `application/x-www-form-urlencoded` for requests with a body
+ (e.g., `POST`, `PUT`) when the header was not explicitly set has been
+ removed. If your application relied on this automatic default, your
+ requests will now be sent without a Content-Type header, potentially
+ breaking compatibility with certain servers.
+ [[GH-net-http #205]]
+
+## C API updates
+
+* IO
+
+ * `rb_thread_fd_close` is deprecated and now a no-op. If you need to expose
+ file descriptors from C extensions to Ruby code, create an `IO` instance
+ using `RUBY_IO_MODE_EXTERNAL` and use `rb_io_close(io)` to close it (this
+ also interrupts and waits for all pending operations on the `IO`
+ instance). Directly closing file descriptors does not interrupt pending
+ operations, and may lead to undefined behaviour. In other words, if two
+ `IO` objects share the same file descriptor, closing one does not affect
+ the other. [[Feature #18455]]
+
+* GVL
+
+ * `rb_thread_call_with_gvl` now works with or without the GVL.
+ This allows gems to avoid checking `ruby_thread_has_gvl_p`.
+ Please still be diligent about the GVL. [[Feature #20750]]
+
+* Set
+
+ * A C API for `Set` has been added. The following methods are supported:
+ [[Feature #21459]]
+
+ * `rb_set_foreach`
+ * `rb_set_new`
+ * `rb_set_new_capa`
+ * `rb_set_lookup`
+ * `rb_set_add`
+ * `rb_set_clear`
+ * `rb_set_delete`
+ * `rb_set_size`
+
+## Implementation improvements
+
+* `Class#new` (ex. `Object.new`) is faster in all cases, but especially when passing keyword arguments. This has also been integrated into YJIT and ZJIT. [[Feature #21254]]
+* GC heaps of different size pools now grow independently, reducing memory usage when only some pools contain long-lived objects
+* GC sweeping is faster on pages of large objects
+* "Generic ivar" objects (String, Array, `TypedData`, etc.) now use a new internal "fields" object for faster instance variable access
+* The GC avoids maintaining an internal `id2ref` table until it is first used, making `object_id` allocation and GC sweeping faster
+* `object_id` and `hash` are faster on Class and Module objects
+* Larger bignum Integers can remain embedded using variable width allocation
+* `Random`, `Enumerator::Product`, `Enumerator::Chain`, `Addrinfo`,
+ `StringScanner`, and some internal objects are now write-barrier protected,
+ which reduces GC overhead.
+
+### Ractor
+
+A lot of work has gone into making Ractors more stable, performant, and usable. These improvements bring Ractor implementation closer to leaving experimental status.
+
+* Performance improvements
+ * Frozen strings and the symbol table internally use a lock-free hash set [[Feature #21268]]
+ * Method cache lookups avoid locking in most cases
+ * Class (and generic ivar) instance variable access is faster and avoids locking
+ * CPU cache contention is avoided in object allocation by using a per-ractor counter
+ * CPU cache contention is avoided in xmalloc/xfree by using a thread-local counter
+ * `object_id` avoids locking in most cases
+* Bug fixes and stability
+ * Fixed possible deadlocks when combining Ractors and Threads
+ * Fixed issues with require and autoload in a Ractor
+ * Fixed encoding/transcoding issues across Ractors
+ * Fixed race conditions in GC operations and method invalidation
+ * Fixed issues with processes forking after starting a Ractor
+ * GC allocation counts are now accurate under Ractors
+ * Fixed TracePoints not working after GC [[Bug #19112]]
+
+## JIT
+
+* ZJIT
+ * Introduce an [experimental method-based JIT compiler](https://docs.ruby-lang.org/en/master/jit/zjit_md.html).
+ Where available, ZJIT can be enabled at runtime with the `--zjit` option or by calling `RubyVM::ZJIT.enable`.
+ When building Ruby, Rust 1.85.0 or later is required to include ZJIT support.
+ * As of Ruby 4.0.0, ZJIT is faster than the interpreter, but not yet as fast as YJIT.
+ We encourage experimentation with ZJIT, but advise against deploying it in production for now.
+ * Our goal is to make ZJIT faster than YJIT and production-ready in Ruby 4.1.
+* YJIT
+ * `RubyVM::YJIT.runtime_stats`
+ * `ratio_in_yjit` no longer works in the default build.
+ Use `--enable-yjit=stats` on `configure` to enable it on `--yjit-stats`.
+ * Add `invalidate_everything` to default stats, which is
+ incremented when every code is invalidated by TracePoint.
+ * Add `mem_size:` and `call_threshold:` options to `RubyVM::YJIT.enable`.
+* RJIT
+ * `--rjit` is removed. We will move the implementation of the third-party JIT API
+ to the [ruby/rjit](https://github.com/ruby/rjit) repository.
+
+[Feature #15408]: https://bugs.ruby-lang.org/issues/15408
+[Feature #17473]: https://bugs.ruby-lang.org/issues/17473
+[Feature #18455]: https://bugs.ruby-lang.org/issues/18455
+[Bug #19112]: https://bugs.ruby-lang.org/issues/19112
+[Feature #19630]: https://bugs.ruby-lang.org/issues/19630
+[Bug #19868]: https://bugs.ruby-lang.org/issues/19868
+[Feature #19908]: https://bugs.ruby-lang.org/issues/19908
+[Feature #20610]: https://bugs.ruby-lang.org/issues/20610
+[Feature #20724]: https://bugs.ruby-lang.org/issues/20724
+[Feature #20750]: https://bugs.ruby-lang.org/issues/20750
+[Feature #20884]: https://bugs.ruby-lang.org/issues/20884
+[Feature #20925]: https://bugs.ruby-lang.org/issues/20925
+[Bug #20968]: https://bugs.ruby-lang.org/issues/20968
+[Feature #20971]: https://bugs.ruby-lang.org/issues/20971
+[Bug #20974]: https://bugs.ruby-lang.org/issues/20974
+[Feature #21047]: https://bugs.ruby-lang.org/issues/21047
+[Bug #21049]: https://bugs.ruby-lang.org/issues/21049
+[Feature #21166]: https://bugs.ruby-lang.org/issues/21166
+[Bug #21174]: https://bugs.ruby-lang.org/issues/21174
+[Bug #21175]: https://bugs.ruby-lang.org/issues/21175
+[Bug #21185]: https://bugs.ruby-lang.org/issues/21185
+[Feature #21205]: https://bugs.ruby-lang.org/issues/21205
+[Feature #21216]: https://bugs.ruby-lang.org/issues/21216
+[Feature #21219]: https://bugs.ruby-lang.org/issues/21219
+[Feature #21254]: https://bugs.ruby-lang.org/issues/21254
+[Feature #21258]: https://bugs.ruby-lang.org/issues/21258
+[Feature #21268]: https://bugs.ruby-lang.org/issues/21268
+[Feature #21262]: https://bugs.ruby-lang.org/issues/21262
+[Feature #21275]: https://bugs.ruby-lang.org/issues/21275
+[Feature #21287]: https://bugs.ruby-lang.org/issues/21287
+[Feature #21311]: https://bugs.ruby-lang.org/issues/21311
+[Feature #21347]: https://bugs.ruby-lang.org/issues/21347
+[Feature #21360]: https://bugs.ruby-lang.org/issues/21360
+[Misc #21385]: https://bugs.ruby-lang.org/issues/21385
+[Feature #21389]: https://bugs.ruby-lang.org/issues/21389
+[Feature #21390]: https://bugs.ruby-lang.org/issues/21390
+[Feature #21459]: https://bugs.ruby-lang.org/issues/21459
+[Feature #21527]: https://bugs.ruby-lang.org/issues/21527
+[Feature #21543]: https://bugs.ruby-lang.org/issues/21543
+[Feature #21550]: https://bugs.ruby-lang.org/issues/21550
+[Feature #21552]: https://bugs.ruby-lang.org/issues/21552
+[Feature #21557]: https://bugs.ruby-lang.org/issues/21557
+[Bug #21633]: https://bugs.ruby-lang.org/issues/21633
+[Bug #21654]: https://bugs.ruby-lang.org/issues/21654
+[Feature #21678]: https://bugs.ruby-lang.org/issues/21678
+[Bug #21698]: https://bugs.ruby-lang.org/issues/21698
+[Feature #21701]: https://bugs.ruby-lang.org/issues/21701
+[Bug #21789]: https://bugs.ruby-lang.org/issues/21789
+[GH-net-http #205]: https://github.com/ruby/net-http/issues/205
+[ostruct-v0.6.2]: https://github.com/ruby/ostruct/releases/tag/v0.6.2
+[ostruct-v0.6.3]: https://github.com/ruby/ostruct/releases/tag/v0.6.3
+[pstore-v0.2.0]: https://github.com/ruby/pstore/releases/tag/v0.2.0
+[benchmark-v0.4.1]: https://github.com/ruby/benchmark/releases/tag/v0.4.1
+[benchmark-v0.5.0]: https://github.com/ruby/benchmark/releases/tag/v0.5.0
+[logger-v1.6.5]: https://github.com/ruby/logger/releases/tag/v1.6.5
+[logger-v1.6.6]: https://github.com/ruby/logger/releases/tag/v1.6.6
+[logger-v1.7.0]: https://github.com/ruby/logger/releases/tag/v1.7.0
+[rdoc-v6.14.1]: https://github.com/ruby/rdoc/releases/tag/v6.14.1
+[rdoc-v6.14.2]: https://github.com/ruby/rdoc/releases/tag/v6.14.2
+[rdoc-v6.15.0]: https://github.com/ruby/rdoc/releases/tag/v6.15.0
+[rdoc-v6.15.1]: https://github.com/ruby/rdoc/releases/tag/v6.15.1
+[rdoc-v6.16.0]: https://github.com/ruby/rdoc/releases/tag/v6.16.0
+[rdoc-v6.16.1]: https://github.com/ruby/rdoc/releases/tag/v6.16.1
+[rdoc-v6.17.0]: https://github.com/ruby/rdoc/releases/tag/v6.17.0
+[rdoc-v7.0.0]: https://github.com/ruby/rdoc/releases/tag/v7.0.0
+[rdoc-v7.0.1]: https://github.com/ruby/rdoc/releases/tag/v7.0.1
+[rdoc-v7.0.2]: https://github.com/ruby/rdoc/releases/tag/v7.0.2
+[rdoc-v7.0.3]: https://github.com/ruby/rdoc/releases/tag/v7.0.3
+[win32ole-v1.9.2]: https://github.com/ruby/win32ole/releases/tag/v1.9.2
+[irb-v1.15.0]: https://github.com/ruby/irb/releases/tag/v1.15.0
+[irb-v1.15.1]: https://github.com/ruby/irb/releases/tag/v1.15.1
+[irb-v1.15.2]: https://github.com/ruby/irb/releases/tag/v1.15.2
+[irb-v1.15.3]: https://github.com/ruby/irb/releases/tag/v1.15.3
+[irb-v1.16.0]: https://github.com/ruby/irb/releases/tag/v1.16.0
+[reline-v0.6.1]: https://github.com/ruby/reline/releases/tag/v0.6.1
+[reline-v0.6.2]: https://github.com/ruby/reline/releases/tag/v0.6.2
+[reline-v0.6.3]: https://github.com/ruby/reline/releases/tag/v0.6.3
+[fiddle-v1.1.7]: https://github.com/ruby/fiddle/releases/tag/v1.1.7
+[fiddle-v1.1.8]: https://github.com/ruby/fiddle/releases/tag/v1.1.8
+[date-v3.5.0]: https://github.com/ruby/date/releases/tag/v3.5.0
+[date-v3.5.1]: https://github.com/ruby/date/releases/tag/v3.5.1
+[delegate-v0.5.0]: https://github.com/ruby/delegate/releases/tag/v0.5.0
+[delegate-v0.6.0]: https://github.com/ruby/delegate/releases/tag/v0.6.0
+[delegate-v0.6.1]: https://github.com/ruby/delegate/releases/tag/v0.6.1
+[digest-v3.2.1]: https://github.com/ruby/digest/releases/tag/v3.2.1
+[english-v0.8.1]: https://github.com/ruby/english/releases/tag/v0.8.1
+[erb-v5.1.2]: https://github.com/ruby/erb/releases/tag/v5.1.2
+[erb-v5.1.3]: https://github.com/ruby/erb/releases/tag/v5.1.3
+[erb-v6.0.0]: https://github.com/ruby/erb/releases/tag/v6.0.0
+[erb-v6.0.1]: https://github.com/ruby/erb/releases/tag/v6.0.1
+[fcntl-v1.3.0]: https://github.com/ruby/fcntl/releases/tag/v1.3.0
+[fileutils-v1.8.0]: https://github.com/ruby/fileutils/releases/tag/v1.8.0
+[forwardable-v1.4.0]: https://github.com/ruby/forwardable/releases/tag/v1.4.0
+[io-console-v0.8.2]: https://github.com/ruby/io-console/releases/tag/v0.8.2
+[io-wait-v0.3.3]: https://github.com/ruby/io-wait/releases/tag/v0.3.3
+[io-wait-v0.3.5.test1]: https://github.com/ruby/io-wait/releases/tag/v0.3.5.test1
+[io-wait-v0.3.5]: https://github.com/ruby/io-wait/releases/tag/v0.3.5
+[io-wait-v0.3.6]: https://github.com/ruby/io-wait/releases/tag/v0.3.6
+[io-wait-v0.4.0]: https://github.com/ruby/io-wait/releases/tag/v0.4.0
+[json-v2.10.0]: https://github.com/ruby/json/releases/tag/v2.10.0
+[json-v2.10.1]: https://github.com/ruby/json/releases/tag/v2.10.1
+[json-v2.10.2]: https://github.com/ruby/json/releases/tag/v2.10.2
+[json-v2.11.0]: https://github.com/ruby/json/releases/tag/v2.11.0
+[json-v2.11.1]: https://github.com/ruby/json/releases/tag/v2.11.1
+[json-v2.11.2]: https://github.com/ruby/json/releases/tag/v2.11.2
+[json-v2.11.3]: https://github.com/ruby/json/releases/tag/v2.11.3
+[json-v2.12.0]: https://github.com/ruby/json/releases/tag/v2.12.0
+[json-v2.12.1]: https://github.com/ruby/json/releases/tag/v2.12.1
+[json-v2.12.2]: https://github.com/ruby/json/releases/tag/v2.12.2
+[json-v2.13.0]: https://github.com/ruby/json/releases/tag/v2.13.0
+[json-v2.13.1]: https://github.com/ruby/json/releases/tag/v2.13.1
+[json-v2.13.2]: https://github.com/ruby/json/releases/tag/v2.13.2
+[json-v2.14.0]: https://github.com/ruby/json/releases/tag/v2.14.0
+[json-v2.14.1]: https://github.com/ruby/json/releases/tag/v2.14.1
+[json-v2.15.0]: https://github.com/ruby/json/releases/tag/v2.15.0
+[json-v2.15.1]: https://github.com/ruby/json/releases/tag/v2.15.1
+[json-v2.15.2]: https://github.com/ruby/json/releases/tag/v2.15.2
+[json-v2.16.0]: https://github.com/ruby/json/releases/tag/v2.16.0
+[json-v2.17.0]: https://github.com/ruby/json/releases/tag/v2.17.0
+[json-v2.17.1]: https://github.com/ruby/json/releases/tag/v2.17.1
+[json-v2.18.0]: https://github.com/ruby/json/releases/tag/v2.18.0
+[net-http-v0.7.0]: https://github.com/ruby/net-http/releases/tag/v0.7.0
+[net-http-v0.8.0]: https://github.com/ruby/net-http/releases/tag/v0.8.0
+[net-http-v0.9.0]: https://github.com/ruby/net-http/releases/tag/v0.9.0
+[net-http-v0.9.1]: https://github.com/ruby/net-http/releases/tag/v0.9.1
+[openssl-v3.3.2]: https://github.com/ruby/openssl/releases/tag/v3.3.2
+[openssl-v4.0.0]: https://github.com/ruby/openssl/releases/tag/v4.0.0
+[optparse-v0.7.0]: https://github.com/ruby/optparse/releases/tag/v0.7.0
+[optparse-v0.8.0]: https://github.com/ruby/optparse/releases/tag/v0.8.0
+[optparse-v0.8.1]: https://github.com/ruby/optparse/releases/tag/v0.8.1
+[pp-v0.6.3]: https://github.com/ruby/pp/releases/tag/v0.6.3
+[prism-v1.6.0]: https://github.com/ruby/prism/releases/tag/v1.6.0
+[prism-v1.7.0]: https://github.com/ruby/prism/releases/tag/v1.7.0
+[psych-v5.2.3]: https://github.com/ruby/psych/releases/tag/v5.2.3
+[psych-v5.2.4]: https://github.com/ruby/psych/releases/tag/v5.2.4
+[psych-v5.2.5]: https://github.com/ruby/psych/releases/tag/v5.2.5
+[psych-v5.2.6]: https://github.com/ruby/psych/releases/tag/v5.2.6
+[psych-v5.3.0]: https://github.com/ruby/psych/releases/tag/v5.3.0
+[psych-v5.3.1]: https://github.com/ruby/psych/releases/tag/v5.3.1
+[resolv-v0.6.3]: https://github.com/ruby/resolv/releases/tag/v0.6.3
+[resolv-v0.7.0]: https://github.com/ruby/resolv/releases/tag/v0.7.0
+[stringio-v3.1.3]: https://github.com/ruby/stringio/releases/tag/v3.1.3
+[stringio-v3.1.4]: https://github.com/ruby/stringio/releases/tag/v3.1.4
+[stringio-v3.1.5]: https://github.com/ruby/stringio/releases/tag/v3.1.5
+[stringio-v3.1.6]: https://github.com/ruby/stringio/releases/tag/v3.1.6
+[stringio-v3.1.7]: https://github.com/ruby/stringio/releases/tag/v3.1.7
+[stringio-v3.1.8]: https://github.com/ruby/stringio/releases/tag/v3.1.8
+[stringio-v3.1.9]: https://github.com/ruby/stringio/releases/tag/v3.1.9
+[stringio-v3.2.0]: https://github.com/ruby/stringio/releases/tag/v3.2.0
+[strscan-v3.1.3]: https://github.com/ruby/strscan/releases/tag/v3.1.3
+[strscan-v3.1.4]: https://github.com/ruby/strscan/releases/tag/v3.1.4
+[strscan-v3.1.5]: https://github.com/ruby/strscan/releases/tag/v3.1.5
+[strscan-v3.1.6]: https://github.com/ruby/strscan/releases/tag/v3.1.6
+[time-v0.4.2]: https://github.com/ruby/time/releases/tag/v0.4.2
+[timeout-v0.4.4]: https://github.com/ruby/timeout/releases/tag/v0.4.4
+[timeout-v0.5.0]: https://github.com/ruby/timeout/releases/tag/v0.5.0
+[timeout-v0.6.0]: https://github.com/ruby/timeout/releases/tag/v0.6.0
+[uri-v1.1.0]: https://github.com/ruby/uri/releases/tag/v1.1.0
+[uri-v1.1.1]: https://github.com/ruby/uri/releases/tag/v1.1.1
+[weakref-v0.1.4]: https://github.com/ruby/weakref/releases/tag/v0.1.4
+[zlib-v3.2.2]: https://github.com/ruby/zlib/releases/tag/v3.2.2
+[power_assert-v3.0.0]: https://github.com/ruby/power_assert/releases/tag/v3.0.0
+[power_assert-v3.0.1]: https://github.com/ruby/power_assert/releases/tag/v3.0.1
+[rake-v13.3.0]: https://github.com/ruby/rake/releases/tag/v13.3.0
+[rake-v13.3.1]: https://github.com/ruby/rake/releases/tag/v13.3.1
+[test-unit-3.6.8]: https://github.com/test-unit/test-unit/releases/tag/3.6.8
+[test-unit-3.6.9]: https://github.com/test-unit/test-unit/releases/tag/3.6.9
+[test-unit-3.7.0]: https://github.com/test-unit/test-unit/releases/tag/3.7.0
+[test-unit-3.7.1]: https://github.com/test-unit/test-unit/releases/tag/3.7.1
+[test-unit-3.7.2]: https://github.com/test-unit/test-unit/releases/tag/3.7.2
+[test-unit-3.7.3]: https://github.com/test-unit/test-unit/releases/tag/3.7.3
+[test-unit-3.7.4]: https://github.com/test-unit/test-unit/releases/tag/3.7.4
+[test-unit-3.7.5]: https://github.com/test-unit/test-unit/releases/tag/3.7.5
+[rss-0.3.2]: https://github.com/ruby/rss/releases/tag/0.3.2
+[net-ftp-v0.3.9]: https://github.com/ruby/net-ftp/releases/tag/v0.3.9
+[net-imap-v0.5.9]: https://github.com/ruby/net-imap/releases/tag/v0.5.9
+[net-imap-v0.5.10]: https://github.com/ruby/net-imap/releases/tag/v0.5.10
+[net-imap-v0.5.11]: https://github.com/ruby/net-imap/releases/tag/v0.5.11
+[net-imap-v0.5.12]: https://github.com/ruby/net-imap/releases/tag/v0.5.12
+[net-imap-v0.5.13]: https://github.com/ruby/net-imap/releases/tag/v0.5.13
+[net-imap-v0.6.0]: https://github.com/ruby/net-imap/releases/tag/v0.6.0
+[net-imap-v0.6.1]: https://github.com/ruby/net-imap/releases/tag/v0.6.1
+[net-imap-v0.6.2]: https://github.com/ruby/net-imap/releases/tag/v0.6.2
+[net-smtp-v0.5.1]: https://github.com/ruby/net-smtp/releases/tag/v0.5.1
+[matrix-v0.4.3]: https://github.com/ruby/matrix/releases/tag/v0.4.3
+[prime-v0.1.4]: https://github.com/ruby/prime/releases/tag/v0.1.4
+[rbs-v3.8.1]: https://github.com/ruby/rbs/releases/tag/v3.8.1
+[rbs-v3.9.0.dev.1]: https://github.com/ruby/rbs/releases/tag/v3.9.0.dev.1
+[rbs-v3.9.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.9.0.pre.1
+[rbs-v3.9.0.pre.2]: https://github.com/ruby/rbs/releases/tag/v3.9.0.pre.2
+[rbs-v3.9.0]: https://github.com/ruby/rbs/releases/tag/v3.9.0
+[rbs-v3.9.1]: https://github.com/ruby/rbs/releases/tag/v3.9.1
+[rbs-v3.9.2]: https://github.com/ruby/rbs/releases/tag/v3.9.2
+[rbs-v3.9.3]: https://github.com/ruby/rbs/releases/tag/v3.9.3
+[rbs-v3.9.4]: https://github.com/ruby/rbs/releases/tag/v3.9.4
+[rbs-v3.9.5]: https://github.com/ruby/rbs/releases/tag/v3.9.5
+[rbs-v3.10.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.10.0.pre.1
+[rbs-v3.10.0.pre.2]: https://github.com/ruby/rbs/releases/tag/v3.10.0.pre.2
+[rbs-v3.10.0]: https://github.com/ruby/rbs/releases/tag/v3.10.0
+[debug-v1.11.1]: https://github.com/ruby/debug/releases/tag/v1.11.1
+[base64-v0.3.0]: https://github.com/ruby/base64/releases/tag/v0.3.0
+[bigdecimal-v3.2.0]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.0
+[bigdecimal-v3.2.1]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.1
+[bigdecimal-v3.2.2]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.2
+[bigdecimal-v3.2.3]: https://github.com/ruby/bigdecimal/releases/tag/v3.2.3
+[bigdecimal-v3.3.0]: https://github.com/ruby/bigdecimal/releases/tag/v3.3.0
+[bigdecimal-v3.3.1]: https://github.com/ruby/bigdecimal/releases/tag/v3.3.1
+[bigdecimal-v4.0.0]: https://github.com/ruby/bigdecimal/releases/tag/v4.0.0
+[bigdecimal-v4.0.1]: https://github.com/ruby/bigdecimal/releases/tag/v4.0.1
+[drb-v2.2.3]: https://github.com/ruby/drb/releases/tag/v2.2.3
+[syslog-v0.3.0]: https://github.com/ruby/syslog/releases/tag/v0.3.0
+[csv-v3.3.3]: https://github.com/ruby/csv/releases/tag/v3.3.3
+[csv-v3.3.4]: https://github.com/ruby/csv/releases/tag/v3.3.4
+[csv-v3.3.5]: https://github.com/ruby/csv/releases/tag/v3.3.5
diff --git a/doc/_regexp.rdoc b/doc/_regexp.rdoc
index 468827da15..4ad6118ddd 100644
--- a/doc/_regexp.rdoc
+++ b/doc/_regexp.rdoc
@@ -26,20 +26,20 @@ A regexp may be used:
re.match('good') # => nil
See sections {Method match}[rdoc-ref:Regexp@Method+match]
- and {Operator =~}[rdoc-ref:Regexp@Operator+-3D~].
+ and {Operator =~}[rdoc-ref:Regexp@Operator-].
- 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].
+ See section {Method match?}[rdoc-ref:Regexp@Method+match].
- 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].
+ See {Regexp Methods}[rdoc-ref:language/regexp/methods.rdoc].
== \Regexp Objects
@@ -64,7 +64,7 @@ A regular expression may be created with:
/foo/ # => /foo/
- A <tt>%r</tt> regexp literal
- (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@25r-3A+Regexp+Literals]):
+ (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@r-regexp+literals]):
# Same delimiter character at beginning and end;
# useful for avoiding escaping characters
@@ -113,7 +113,7 @@ none sets {global variables}[rdoc-ref:Regexp@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~].
+- <tt>#=~</tt>: see {Operator =~}[rdoc-ref:Regexp@Operator-].
The affected global variables are:
@@ -414,21 +414,21 @@ Each of these anchors matches a boundary:
Lookahead anchors:
-- <tt>(?=_pat_)</tt>: Positive lookahead assertion:
+- <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:
+- <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:
+- <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:
+- <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.
@@ -439,6 +439,10 @@ without including the tags in the match:
/(?<=<b>)\w+(?=<\/b>)/.match("Fortune favors the <b>bold</b>.")
# => #<MatchData "bold">
+The pattern in lookbehind must be fixed-width.
+But top-level alternatives can be of various lengths.
+ex. (?<=a|bc) is OK. (?<=aaa(?:b|cd)) is not allowed.
+
==== Match-Reset Anchor
- <tt>\K</tt>: Match reset:
@@ -498,7 +502,7 @@ An added _quantifier_ specifies how many matches are required or allowed:
/\w*/.match('x')
# => #<MatchData "x">
/\w*/.match('xyz')
- # => #<MatchData "yz">
+ # => #<MatchData "xyz">
- <tt>+</tt> - Matches one or more times:
@@ -557,9 +561,9 @@ Quantifier matching may be greedy, lazy, or possessive:
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].
+ {Choosing Minimal or Maximal Repetition}[https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch02s13.html].
- 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].
+ {Eliminate Needless Backtracking}[https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch02s14.html].
=== Groups and Captures
@@ -570,7 +574,7 @@ A simple regexp has (at most) one match:
re.match('1943-02-04').size # => 1
re.match('foo') # => nil
-Adding one or more pairs of parentheses, <tt>(_subexpression_)</tt>,
+Adding one or more pairs of parentheses, <tt>(subexpression)</tt>,
defines _groups_, which may result in multiple matched substrings,
called _captures_:
@@ -643,8 +647,8 @@ 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_.
+ - 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,
@@ -657,7 +661,7 @@ A regexp may contain any number of groups:
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>,
+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")
@@ -672,7 +676,7 @@ 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>:
+A named group may be backreferenced as <tt>\k<name></tt>:
/(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
# => #<MatchData "ototo" vowel:"o">
@@ -709,7 +713,7 @@ 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>
+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;
@@ -728,10 +732,10 @@ 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>)
+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>):
+via the number n (<tt>\\gn</tt>) or name (<tt>\g<name></tt>):
/\A(?<paren>\(\g<paren>*\))*\z/.match('(())')
# ^1
@@ -760,16 +764,16 @@ The pattern:
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].
+See {Subexpression calls}[https://learnbyexample.github.io/Ruby_Regexp/groupings-and-backreferences.html#subexpression-calls].
==== Conditionals
-The conditional construct takes the form <tt>(?(_cond_)_yes_|_no_)</tt>, where:
+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.
+- If not needed, <tt>|no</tt> may be omitted.
Examples:
@@ -798,7 +802,7 @@ The absence operator is a special group that matches anything which does _not_ m
==== Unicode Properties
-The <tt>/\p{_property_name_}/</tt> construct (with lowercase +p+)
+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:
@@ -817,7 +821,7 @@ 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]
+See {Unicode Properties}[rdoc-ref:language/regexp/unicode_properties.rdoc]
for regexps based on the numerous properties.
Some commonly-used properties correspond to POSIX bracket expressions:
@@ -926,7 +930,7 @@ Punctuation:
- +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].
+- {Cn, Unassigned}[http://zuga.net/articles/unicode/category/unassigned/].
- {Co, Private_Use}[https://www.compart.com/en/unicode/category/Co].
- {Cs, Surrogate}[https://www.compart.com/en/unicode/category/Cs].
@@ -1029,23 +1033,23 @@ See also {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
Each of these modifiers sets a mode for the regexp:
-- +i+: <tt>/_pattern_/i</tt> sets
+- +i+: <tt>/pattern/i</tt> sets
{Case-Insensitive Mode}[rdoc-ref:Regexp@Case-Insensitive+Mode].
-- +m+: <tt>/_pattern_/m</tt> sets
+- +m+: <tt>/pattern/m</tt> sets
{Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode].
-- +x+: <tt>/_pattern_/x</tt> sets
+- +x+: <tt>/pattern/x</tt> sets
{Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
-- +o+: <tt>/_pattern_/o</tt> sets
+- +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
+- <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:
@@ -1124,6 +1128,13 @@ Regexp in extended mode:
re = /#{pattern}/x
re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
+Comments in regexp literals cannot include unescaped terminator
+characters:
+
+ /
+ foo # the following slash \/ must be escaped
+ /x
+
=== Interpolation Mode
Modifier +o+ means that the first time a literal regexp with interpolations
@@ -1162,22 +1173,22 @@ 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,
+- <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
+- <tt>/pat/u</tt>: UTF-8
/foo/u.encoding # => #<Encoding:UTF-8>
-- <tt>/_pat_/e</tt>: EUC-JP
+- <tt>/pat/e</tt>: EUC-JP
/foo/e.encoding # => #<Encoding:EUC-JP>
-- <tt>/_pat_/s</tt>: Windows-31J
+- <tt>/pat/s</tt>: Windows-31J
/foo/s.encoding # => #<Encoding:Windows-31J>
@@ -1247,7 +1258,7 @@ the potential vulnerability arising from this is the {regular expression denial-
\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.
+in relation to the input size, and a ReDoS attack is not possible.
This optimization is applied if the pattern meets these criteria:
@@ -1268,13 +1279,13 @@ because the optimization uses memoization (which may invoke large memory consump
== References
-Read (online PDF books):
+Read:
-- {Mastering Regular Expressions}[https://ia902508.us.archive.org/10/items/allitebooks-02/Mastering%20Regular%20Expressions%2C%203rd%20Edition.pdf]
+- <i>Mastering Regular Expressions</i>
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]
+- <i>Regular Expressions Cookbook</i>
by Jan Goyvaerts & Steven Levithan.
-Explore, test (interactive online editor):
+Explore, test:
-- {Rubular}[https://rubular.com/].
+- {Rubular}[https://rubular.com/]: interactive online editor.
diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc
index a2ac46584f..945654c163 100644
--- a/doc/_timezones.rdoc
+++ b/doc/_timezones.rdoc
@@ -11,7 +11,7 @@ Certain +Time+ methods accept arguments that specify timezones:
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].
+- {Hours/minutes offset}[rdoc-ref:Time@HoursMinutes+Offsets].
- {Single-letter offset}[rdoc-ref:Time@Single-Letter+Offsets].
- {Integer offset}[rdoc-ref:Time@Integer+Offsets].
- {Timezone object}[rdoc-ref:Time@Timezone+Objects].
diff --git a/doc/case_mapping.rdoc b/doc/case_mapping.rdoc
deleted file mode 100644
index 57c037b9d8..0000000000
--- a/doc/case_mapping.rdoc
+++ /dev/null
@@ -1,116 +0,0 @@
-= Case Mapping
-
-Some string-oriented methods use case mapping.
-
-In String:
-
-- String#capitalize
-- String#capitalize!
-- String#casecmp
-- String#casecmp?
-- String#downcase
-- String#downcase!
-- String#swapcase
-- String#swapcase!
-- String#upcase
-- String#upcase!
-
-In Symbol:
-
-- Symbol#capitalize
-- Symbol#casecmp
-- Symbol#casecmp?
-- Symbol#downcase
-- Symbol#swapcase
-- Symbol#upcase
-
-== Default Case Mapping
-
-By default, all of these methods use full Unicode case mapping,
-which is suitable for most languages.
-See {Section 3.13 (Default Case Algorithms) of the Unicode standard}[https://www.unicode.org/versions/latest/ch03.pdf].
-
-Non-ASCII case mapping and folding are supported for UTF-8,
-UTF-16BE/LE, UTF-32BE/LE, and ISO-8859-1~16 Strings/Symbols.
-
-Context-dependent case mapping as described in
-{Table 3-17 (Context Specification for Casing) of the Unicode standard}[https://www.unicode.org/versions/latest/ch03.pdf]
-is currently not supported.
-
-In most cases, case conversions of a string have the same number of characters.
-There are exceptions (see also +:fold+ below):
-
- s = "\u00DF" # => "ß"
- s.upcase # => "SS"
- s = "\u0149" # => "ʼn"
- s.upcase # => "ʼN"
-
-Case mapping may also depend on locale (see also +:turkic+ below):
-
- s = "\u0049" # => "I"
- s.downcase # => "i" # Dot above.
- s.downcase(:turkic) # => "ı" # No dot above.
-
-Case changes may not be reversible:
-
- s = 'Hello World!' # => "Hello World!"
- s.downcase # => "hello world!"
- s.downcase.upcase # => "HELLO WORLD!" # Different from original s.
-
-Case changing methods may not maintain Unicode normalization.
-See String#unicode_normalize).
-
-== Options for Case Mapping
-
-Except for +casecmp+ and +casecmp?+,
-each of the case-mapping methods listed above
-accepts optional arguments, <tt>*options</tt>.
-
-The arguments may be:
-
-- +:ascii+ only.
-- +:fold+ only.
-- +:turkic+ or +:lithuanian+ or both.
-
-The options:
-
-- +:ascii+:
- ASCII-only mapping:
- uppercase letters ('A'..'Z') are mapped to lowercase letters ('a'..'z);
- other characters are not changed
-
- s = "Foo \u00D8 \u00F8 Bar" # => "Foo Ø ø Bar"
- s.upcase # => "FOO Ø Ø BAR"
- s.downcase # => "foo ø ø bar"
- s.upcase(:ascii) # => "FOO Ø ø BAR"
- s.downcase(:ascii) # => "foo Ø ø bar"
-
-- +:turkic+:
- Full Unicode case mapping, adapted for the Turkic languages
- that distinguish dotted and dotless I, for example Turkish and Azeri.
-
- s = 'Türkiye' # => "Türkiye"
- s.upcase # => "TÜRKIYE"
- s.upcase(:turkic) # => "TÜRKİYE" # Dot above.
-
- s = 'TÜRKIYE' # => "TÜRKIYE"
- s.downcase # => "türkiye"
- s.downcase(:turkic) # => "türkıye" # No dot above.
-
-- +:lithuanian+:
- Not yet implemented.
-
-- +:fold+ (available only for String#downcase, String#downcase!,
- and Symbol#downcase):
- Unicode case folding,
- which is more far-reaching than Unicode case mapping.
-
- s = "\u00DF" # => "ß"
- s.downcase # => "ß"
- s.downcase(:fold) # => "ss"
- s.upcase # => "SS"
-
- s = "\uFB04" # => "ffl"
- s.downcase # => "ffl"
- s.upcase # => "FFL"
- s.downcase(:fold) # => "ffl"
diff --git a/doc/character_selectors.rdoc b/doc/character_selectors.rdoc
deleted file mode 100644
index 47cf242be7..0000000000
--- a/doc/character_selectors.rdoc
+++ /dev/null
@@ -1,97 +0,0 @@
-= Character Selectors
-
-== 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:
-
-- String#tr(selector, replacements): returns a new string.
-- String#tr!(selector, replacements): returns +self+ or +nil+.
-- String#tr_s(selector, replacements): returns a new string.
-- String#tr_s!(selector, replacements): returns +self+ or +nil+.
-- String#count(*selectors): returns the count of the specified characters.
-- String#delete(*selectors): returns a new string.
-- String#delete!(*selectors): returns +self+ or +nil+.
-- String#squeeze(*selectors): returns a new string.
-- String#squeeze!(*selectors): returns +self+ or +nil+.
-
-A character selector identifies zero or more characters in +self+
-that are to be operands for the method.
-
-In this section, we illustrate using method String#delete(selector),
-which deletes the selected characters.
-
-In the simplest case, the characters selected are exactly those
-contained in the selector itself:
-
- 'abracadabra'.delete('a') # => "brcdbr"
- 'abracadabra'.delete('ab') # => "rcdr"
- 'abracadabra'.delete('abc') # => "rdr"
- '0123456789'.delete('258') # => "0134679"
- '!@#$%&*()_+'.delete('+&#') # => "!@$%*()_"
- 'тест'.delete('т') # => "ес"
- 'こんにちは'.delete('に') # => "こんちは"
-
-Note that order and repetitions do not matter:
-
- 'abracadabra'.delete('dcab') # => "rr"
- 'abracadabra'.delete('aaaa') # => "brcdbr"
-
-In a character selector, these three characters get special treatment:
-
-- A leading caret (<tt>'^'</tt>) functions as a "not" operator
- for the characters to its right:
-
- 'abracadabra'.delete('^bc') # => "bcb"
- '0123456789'.delete('^852') # => "258"
-
-- A hyphen (<tt>'-'</tt>) between two other characters
- defines a range of characters instead of a plain string of characters:
-
- 'abracadabra'.delete('a-d') # => "rr"
- '0123456789'.delete('4-7') # => "012389"
- '!@#$%&*()_+'.delete(' -/') # => "@^_"
-
- # May contain more than one range.
- 'abracadabra'.delete('a-cq-t') # => "d"
-
- # Ranges may be mixed with plain characters.
- '0123456789'.delete('67-950-23') # => "4"
-
- # Ranges may be mixed with negations.
- 'abracadabra'.delete('^a-c') # => "abacaaba"
-
-- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
- or another backslash:
-
- 'abracadabra^'.delete('\^bc') # => "araadara"
- 'abracadabra-'.delete('a\-d') # => "brcbr"
- "hello\r\nworld".delete("\r") # => "hello\nworld"
- "hello\r\nworld".delete("\\r") # => "hello\r\nwold"
- "hello\r\nworld".delete("\\\r") # => "hello\nworld"
-
-== Multiple Character Selectors
-
-These instance methods accept multiple character selectors:
-
-- String#count(*selectors): returns the count of the specified characters.
-- String#delete(*selectors): returns a new string.
-- String#delete!(*selectors): returns +self+ or +nil+.
-- String#squeeze(*selectors): returns a new string.
-- String#squeeze!(*selectors): returns +self+ or +nil+.
-
-In effect, the given selectors are formed into a single selector
-consisting of only those characters common to _all_ of the given selectors.
-
-All forms of selectors may be used, including negations, ranges, and escapes.
-
-Each of these pairs of method calls is equivalent:
-
- s.delete('abcde', 'dcbfg')
- s.delete('bcd')
-
- s.delete('^abc', '^def')
- s.delete('^abcdef')
-
- s.delete('a-e', 'c-g')
- s.delete('cde')
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc
deleted file mode 100644
index ee33d4a04e..0000000000
--- a/doc/command_injection.rdoc
+++ /dev/null
@@ -1,37 +0,0 @@
-= Command Injection
-
-Some Ruby core methods accept string data
-that includes text to be executed as a system command.
-
-They should not be called with unknown or unsanitized commands.
-
-These methods include:
-
-- Kernel.exec
-- Kernel.spawn
-- Kernel.system
-- {\`command` (backtick method)}[rdoc-ref:Kernel#`]
- (also called by the expression <tt>%x[command]</tt>).
-- IO.popen (when called with other than <tt>"-"</tt>).
-
-Some methods execute a system command only if the given path name starts
-with a <tt>|</tt>:
-
-- Kernel.open(command).
-- IO.read(command).
-- IO.write(command).
-- IO.binread(command).
-- 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+:
-
-- File.read(path).
-- File.write(path).
-- File.binread(path).
-- File.binwrite(path).
-- File.readlines(path).
-- File.foreach(path).
diff --git a/doc/command_line/environment.md b/doc/command_line/environment.md
deleted file mode 100644
index 8f6d595f6c..0000000000
--- a/doc/command_line/environment.md
+++ /dev/null
@@ -1,174 +0,0 @@
-## Environment
-
-Certain command-line options affect the execution environment
-of the invoked Ruby program.
-
-### About the Examples
-
-The examples here use command-line option `-e`,
-which passes the Ruby code to be executed on the command line itself:
-
-```console
-$ ruby -e 'puts "Hello, World."'
-```
-
-### Option `-C`
-
-The argument to option `-C` specifies a working directory
-for the invoked Ruby program;
-does not change the working directory for the current process:
-
-```console
-$ basename `pwd`
-ruby
-$ ruby -C lib -e 'puts File.basename(Dir.pwd)'
-lib
-$ basename `pwd`
-ruby
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### Option `-I`
-
-The argument to option `-I` specifies a directory
-to be added to the array in global variable `$LOAD_PATH`;
-the option may be given more than once:
-
-```console
-$ pushd /tmp
-$ ruby -e 'p $LOAD_PATH.size'
-8
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.size'
-10
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.take(2)'
-["/tmp/my_lib", "/tmp/some_lib"]
-$ popd
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### Option `-r`
-
-The argument to option `-r` specifies a library to be required
-before executing the Ruby program;
-the option may be given more than once:
-
-```console
-$ ruby -e 'p defined?(JSON); p defined?(CSV)'
-nil
-nil
-$ ruby -r CSV -r JSON -e 'p defined?(JSON); p defined?(CSV)'
-"constant"
-"constant"
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### Option `-0`
-
-Option `-0` defines the input record separator `$/`
-for the invoked Ruby program.
-
-The optional argument to the option must be octal digits,
-each in the range `0..7`;
-these digits are prefixed with digit `0` to form an octal value:
-
-- If no argument is given, the input record separator is `0x00`.
-- If the argument is `0`, the input record separator is `''`;
- see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values].
-- If the argument is in range `(1..0377)`,
- it becomes the character value of the input record separator `$/`.
-- Otherwise, the input record separator is `nil`.
-
-Examples:
-
-```console
-$ ruby -0 -e 'p $/'
-"\x00"
-$ ruby -00 -e 'p $/'
-""
-$ ruby -012 -e 'p $/'
-"\n"
-$ ruby -015 -e 'p $/'
-"\r"
-$ ruby -0377 -e 'p $/'
-"\xFF"
-$ ruby -0400 -e 'p $/'
-nil
-```
-
-The option may not be separated from its argument by whitespace.
-
-### Option `-d`
-
-Some code in (or called by) the Ruby program may include statements or blocks
-conditioned by the global variable `$DEBUG` (e.g., `if $DEBUG`);
-these commonly write to `$stdout` or `$stderr`.
-
-The default value for `$DEBUG` is `false`;
-option `-d` (or `--debug`) sets it to `true`:
-
-```console
-$ ruby -e 'p $DEBUG'
-false
-$ ruby -d -e 'p $DEBUG'
-true
-```
-
-### Option '-w'
-
-Option `-w` (lowercase letter) is equivalent to option `-W1` (uppercase letter).
-
-### Option `-W`
-
-Any Ruby code can create a <i>warning message</i> by calling method Kernel#warn;
-methods in the Ruby core and standard libraries can also create warning messages.
-Such a message may be printed on `$stderr`
-(or not, depending on certain settings).
-
-Option `-W` helps determine whether a particular warning message
-will be written,
-by setting the initial value of global variable `$-W`:
-
-- `-W0`: Sets `$-W` to `0` (silent; no warnings).
-- `-W1`: Sets `$-W` to `1` (moderate verbosity).
-- `-W2`: Sets `$-W` to `2` (high verbosity).
-- `-W`: Same as `-W2` (high verbosity).
-- Option not given: Same as `-W1` (moderate verbosity).
-
-The value of `$-W`, in turn, determines which warning messages (if any)
-are to be printed to `$stdout` (see Kernel#warn):
-
-```console
-$ ruby -W1 -e 'p $foo'
-nil
-$ ruby -W2 -e 'p $foo'
--e:1: warning: global variable '$foo' not initialized
-nil
-```
-
-Ruby code may also define warnings for certain categories;
-these are the default settings for the defined categories:
-
-```ruby
-Warning[:experimental] # => true
-Warning[:deprecated] # => false
-Warning[:performance] # => false
-```
-
-They may also be set:
-
-```ruby
-Warning[:experimental] = false
-Warning[:deprecated] = true
-Warning[:performance] = true
-```
-
-You can suppress a category by prefixing `no-` to the category name:
-
-```console
-$ ruby -W:no-experimental -e 'p IO::Buffer.new'
-#<IO::Buffer>
-```
-
diff --git a/doc/bug_triaging.rdoc b/doc/contributing/bug_triaging.rdoc
index 83fe88cabe..83fe88cabe 100644
--- a/doc/bug_triaging.rdoc
+++ b/doc/contributing/bug_triaging.rdoc
diff --git a/doc/contributing/building_ruby.md b/doc/contributing/building_ruby.md
index 5037c8a78e..a283a2f3db 100644
--- a/doc/contributing/building_ruby.md
+++ b/doc/contributing/building_ruby.md
@@ -17,11 +17,11 @@
* [autoconf] - 2.67 or later
* [gperf] - 3.1 or later
* Usually unneeded; only if you edit some source files using gperf
- * ruby - 3.0 or later
+ * ruby - 3.1 or later
* We can upgrade this version to system ruby version of the latest
Ubuntu LTS.
* git - 2.32 or later
- * Anterior versions may work; 2.32 or later will prevent build
+ * Earlier versions may work; 2.32 or later will prevent build
errors in case your system `.gitconfig` uses `$HOME` paths.
2. Install optional, recommended dependencies:
@@ -151,7 +151,7 @@ ruby
├── build # Created in step 2 and populated in step 4
│ ├── GNUmakefile # Generated by `../configure`
│ ├── Makefile # Generated by `../configure`
-│ ├── object.o # Compiled object file, built my `make`
+│ ├── object.o # Compiled object file, built by `make`
│ └── ... other compiled `.o` object files
│ # Other interesting files:
@@ -184,7 +184,7 @@ cause build failures.
## Building on Windows
The documentation for building on Windows can be found in [the separated
-file](../windows.md).
+file](../distribution/windows.md).
## More details
@@ -248,13 +248,37 @@ following make targets:
* `make lldb-ruby`: Runs `test.rb` using Ruby in lldb
* `make gdb-ruby`: Runs `test.rb` using Ruby in gdb
+For VS Code users, you can set up editor-based debugging experience by running:
+
+```shell
+cp -r misc/.vscode .vscode
+```
+
+This will add launch configurations for debugging Ruby itself by running `test.rb` with `lldb`.
+
+**Note**: if you build Ruby under the `./build` folder, you'll need to update `.vscode/launch.json`'s program entry accordingly to: `"${workspaceFolder}/build/ruby"`
+
### Compiling for Debugging
-You should configure Ruby without optimization and other flags that may
-interfere with debugging:
+You can compile Ruby with the `RUBY_DEBUG` macro to enable debugging on some
+features. One example is debugging object shapes in Ruby with
+`RubyVM::Shape.of(object)`.
+
+Additionally Ruby can be compiled to support the `RUBY_DEBUG` environment
+variable to enable debugging on some features. An example is using
+`RUBY_DEBUG=gc_stress` to debug GC-related issues.
+
+There is also support for the `RUBY_DEBUG_LOG` environment variable to log a
+lot of information about what the VM is doing, via the `USE_RUBY_DEBUG_LOG`
+macro.
+
+You should also configure Ruby without optimization and other flags that may
+interfere with debugging by changing the optimization flags.
+
+Bringing it all together:
```sh
-./configure --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
+./configure cppflags="-DRUBY_DEBUG=1 -DUSE_RUBY_DEBUG_LOG=1" --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
```
### Building with Address Sanitizer
@@ -283,9 +307,6 @@ RUBY_TEST_TIMEOUT_SCALE=5 SYNTAX_SUGGEST_TIMEOUT=600 make check
Please note, however, the following caveats!
-* ASAN will not work properly on any currently released version of Ruby; the
- necessary support is currently only present on Ruby's master branch (and the
- whole test suite passes only as of commit [Revision 9d0a5148]).
* Due to [Bug #20243], Clang generates code for threadlocal variables which
doesn't work with M:N threading. Thus, it's necessary to disable M:N
threading support at build time for now (with the `-DUSE_MN_THREADS=0`
diff --git a/doc/contributing/concurrency_guide.md b/doc/contributing/concurrency_guide.md
new file mode 100644
index 0000000000..1fb58f7203
--- /dev/null
+++ b/doc/contributing/concurrency_guide.md
@@ -0,0 +1,154 @@
+# Concurrency Guide
+
+This is a guide to thinking about concurrency in the cruby source code, whether that's contributing to Ruby
+by writing C or by contributing to one of the JITs. This does not touch on native extensions, only the core
+language. It will go over:
+
+* What needs synchronizing?
+* How to use the VM lock, and what you can and can't do when you've acquired this lock.
+* What you can and can't do when you've acquired other native locks.
+* The difference between the VM lock and the GVL.
+* What a VM barrier is and when to use it.
+* The lock ordering of some important locks.
+* How ruby interrupt handling works.
+* The timer thread and what it's responsible for.
+
+## What needs synchronizing?
+
+Before ractors, only one ruby thread could run at once. That didn't mean you could forget about concurrency issues, though. The timer thread
+is a native thread that interacts with other ruby threads and changes some VM internals, so if these changes can be done in parallel by both the timer
+thread and a ruby thread, they need to be synchronized.
+
+When you add ractors to the mix, it gets more complicated. However, ractors allow you to forget about synchronization for non-shareable objects because
+they aren't used across ractors. Only one ruby thread can touch the object at once. For shareable objects, they are deeply frozen so there isn't any
+mutation on the objects themselves. However, something like reading/writing constants across ractors does need to be synchronized. In this case, ruby threads need to
+see a consistent view of the VM. If publishing the update takes 2 steps or even two separate instructions, like in this case, synchronization is required.
+
+Most synchronization is to protect VM internals. These internals include structures for the thread scheduler on each ractor, the global ractor scheduler, the
+coordination between ruby threads and ractors, global tables (for `fstrings`, encodings, symbols and global vars), etc. Anything that can be mutated by a ractor
+that can also be read or mutated by another ractor at the same time requires proper synchronization.
+
+## The VM Lock
+
+There's only one VM lock and it is for critical sections that can only be entered by one ractor at a time.
+Without ractors, the VM lock is useless. It does not stop all ractors from running, as ractors can run
+without trying to acquire this lock. If you're updating global (shared) data between ractors and aren't using
+atomics, you need to use a lock and this is a convenient one to use. Unlike other locks, you can allocate ruby-managed
+memory with it held. When you take the VM lock, there are things you can and can't do during your critical section:
+
+You can (as long as no other locks are also held before the VM lock):
+
+* Create ruby objects, call `ruby_xmalloc`, etc.
+
+You can't:
+
+* Context switch to another ruby thread or ractor. This is important, as many things can cause ruby-level context switches including:
+
+ * Calling any ruby method through, for example, `rb_funcall`. If you execute ruby code, a context switch could happen.
+ This also applies to ruby methods defined in C, as they can be redefined in Ruby. Things that call ruby methods such as
+ `rb_obj_respond_to` are also disallowed.
+
+ * Calling `rb_raise`. This will call `initialize` on the new exception object. With the VM lock
+ held, nothing you call should be able to raise an exception. `NoMemoryError` is allowed, however.
+
+ * Calling `rb_nogvl` or a ruby-level mechanism that can context switch like `rb_mutex_lock`.
+
+ * Enter any blocking operation managed by ruby. This will context switch to another ruby thread using `rb_nogvl` or
+ something equivalent. A blocking operation is one that blocks the thread's progress, such as `sleep` or `IO#read`.
+
+Internally, the VM lock is the `vm->ractor.sync.lock`.
+
+You need to be on a ruby thread to take the VM lock. You also can't take it inside any functions that could be called during sweeping, as MMTK sweeps
+on another thread and you need a valid `ec` to grab the lock. For this same reason (among others), you can't take it from the timer thread either.
+
+## Other Locks
+
+All native locks that aren't the VM lock share a more strict set of rules for what's allowed during the critical section. By native locks, we mean
+anything that uses `rb_native_mutex_lock`. Some important locks include the `interrupt_lock`, the ractor scheduling lock (protects global scheduling data structures),
+the thread scheduling lock (local to each ractor, protects per-ractor scheduling data structures) and the ractor lock (local to each ractor, protects ractor data structures).
+
+When you acquire one of these locks,
+
+You can:
+
+* Allocate memory though non-ruby allocation such as raw `malloc` or the standard library. But be careful, some functions like `strdup` use
+ruby allocation through the use of macros!
+
+* Use `ccan` lists, as they don't allocate.
+
+* Do the usual things like set variables or struct fields, manipulate linked lists, signal condition variables etc.
+
+You can't:
+
+* Allocate ruby-managed memory. This includes creating ruby objects or using `ruby_xmalloc` or `st_insert`. The reason this
+is disallowed is if that allocation causes a GC, then all other ruby threads must join a VM barrier as soon as possible
+(when they next check interrupts or acquire the VM lock). This is so that no other ractors are running during GC. If a ruby thread
+is waiting (blocked) on this same native lock, it can't join the barrier and a deadlock occurs because the barrier will never finish.
+
+* Raise exceptions. You also can't use `EC_JUMP_TAG` if it jumps out of the critical section.
+
+* Context switch. See the `VM Lock` section for more info.
+
+## Difference Between VM Lock and GVL
+
+The VM Lock is a particular lock in the source code. There is only one VM Lock. The GVL, on the other hand, is more of a combination of locks.
+It is "acquired" when a ruby thread is about to run or is running. Since many ruby threads can run at the same time if they're in different ractors,
+there are many GVLs (1 per `SNT` + 1 for the main ractor). It can no longer be thought of as a "Global VM Lock" like it once was before ractors.
+
+## VM Barriers
+
+Sometimes, taking the VM Lock isn't enough and you need a guarantee that all ractors have stopped. This happens when running `GC`, for instance.
+To get a barrier, you take the VM Lock and call `rb_vm_barrier()`. For the duration that the VM lock is held, no other ractors will be running. It's not used
+often as taking a barrier slows ractor performance down considerably, but it's useful to know about and is sometimes the only solution.
+
+## Lock Orderings
+
+It's a good idea to not hold more than 2 locks at once on the same thread. Locking multiple locks can introduce deadlocks, so do it with care. When locking
+multiple locks at once, follow an ordering that is consistent across the program, otherwise you can introduce deadlocks. Here are the orderings of some important locks:
+
+* VM lock before ractor_sched_lock
+* thread_sched_lock before ractor_sched_lock
+* interrupt_lock before timer_th.waiting_lock
+* timer_th.waiting_lock before ractor_sched_lock
+
+These orderings are subject to change, so check the source if you're not sure. On top of this:
+
+* During each `ubf` (unblock) function, the VM lock can be taken around it in some circumstances. This happens during VM shutdown, for example.
+See the "Interrupt Handling" section for more details.
+
+## Ruby Interrupt Handling
+
+When the VM runs ruby code, ruby's threads intermittently check ruby-level interrupts. These software interrupts
+are for various things in ruby and they can be set by other ruby threads or the timer thread.
+
+* Ruby threads check when they should give up their timeslice. The native thread switches to another ruby thread when their time is up.
+* The timer thread sends a "trap" interrupt to the main thread if any ruby-level signal handlers are pending.
+* Ruby threads can have other ruby threads run tasks for them by sending them an interrupt. For instance, ractors send
+the main thread an interrupt when they need to `require` a file so that it's done on the main thread. They wait for the
+main thread's result.
+* During VM shutdown, a "terminate" interrupt is sent to all ractor main threads top stop them asap.
+* When calling `Thread#raise`, the caller sends an interrupt to that thread telling it which exception to raise.
+* Unlocking a mutex sends the next waiter (if any) an interrupt telling it to grab the lock.
+* Signalling or broadcasting on a condition variable tells the waiter(s) to wake up.
+
+This isn't a complete list.
+
+When sending an interrupt to a ruby thread, the ruby thread can be blocked. For example, it could be in the middle of a `TCPSocket#read` call. If so,
+the receiving thread's `ubf` (unblock function) gets called from the thread (ruby thread or timer thread) that sent the interrupt.
+Each ruby thread has a `ubf` that is set when it enters a blocking operation and is unset after returning from it. By default, this `ubf` function sends a
+`SIGVTALRM` to the receiving thread to try to unblock it from the kernel so it can check its interrupts. There are other `ubfs` that
+aren't associated with a syscall, such as when calling `Ractor#join` or `sleep`. All `ubfs` are called with the `interrupt_lock` held,
+so take that into account when using locks inside `ubfs`.
+
+Remember, `ubfs` can be called from the timer thread so you cannot assume an `ec` inside them. The `ec` (execution context) is only set on ruby threads.
+
+## The Timer Thread
+
+The timer thread has a few functions. They are:
+
+* Send interrupts to ruby threads that have run for their whole timeslice.
+* Wake up M:N ruby threads (threads in non-main ractors) blocked on IO or after a specified timeout. This
+uses `kqueue` or `epoll`, depending on the OS, to receive IO events on behalf of the threads.
+* Continue calling the `SIGVTARLM` signal if a thread is still blocked on a syscall after the first `ubf` call.
+* Signal native threads (`SNT`) waiting on a ractor if there are ractors waiting in the global run queue.
+* Create more `SNT`s if some are blocked, like on IO or on `Ractor#join`.
diff --git a/doc/contributing/documentation_guide.md b/doc/contributing/documentation_guide.md
index deb17a793a..7c73ad1c50 100644
--- a/doc/contributing/documentation_guide.md
+++ b/doc/contributing/documentation_guide.md
@@ -6,8 +6,8 @@ in the Ruby core and in the Ruby standard library.
## Generating documentation
-Most Ruby documentation lives in the source files and is written in
-[RDoc format](rdoc-ref:RDoc::MarkupReference).
+Most Ruby documentation lives in the source files, and is written in RDoc format
+(described in the [RDoc Markup Reference]).
Some pages live under the `doc` folder and can be written in either
`.rdoc` or `.md` format, determined by the file extension.
@@ -20,12 +20,19 @@ build directory:
make html
```
+Or, to start a live-reloading server that automatically refreshes
+the browser when you edit source files:
+
+```sh
+make html-server
+```
+
+Then visit http://localhost:4000 in your browser.
+To use a different port: `make html-server RDOC_SERVER_PORT=8080`.
+
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
@@ -43,15 +50,12 @@ 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).
-- Refer to authoritative and relevant sources using
- [links](rdoc-ref:RDoc::MarkupReference@Links).
+- Organize material with [headings].
+- Refer to authoritative and relevant sources using [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).
+ - Excessive comma-separated phrases; consider a [list][lists].
- Idioms and culture-specific references.
- Overuse of headings.
- Using US-ASCII-incompatible characters in C source files;
@@ -62,7 +66,7 @@ Use your judgment about what the user needs to know.
Use only US-ASCII-compatible characters in a C source file.
(If you use other characters, the Ruby CI will gently let you know.)
-If want to put ASCII-incompatible characters into the documentation
+If you want to put ASCII-incompatible characters into the documentation
for a C-coded class, module, or method, there are workarounds
involving new files `doc/*.rdoc`:
@@ -75,7 +79,7 @@ involving new files `doc/*.rdoc`:
class Foo; end
```
-- Similarly, for module `Bar` (defined in file `bar.c`,
+- Similarly, for module `Bar` (defined in file `bar.c`),
create file `doc/bar.rdoc`, declare `module Bar; end`,
and place the module documentation above that declaration:
@@ -106,16 +110,16 @@ involving new files `doc/*.rdoc`:
*/
```
-### \RDoc
+### RDoc
Ruby is documented using RDoc.
-For information on \RDoc syntax and features, see the
-[RDoc Markup Reference](rdoc-ref:RDoc::MarkupReference).
+For information on RDoc syntax and features,
+see the [RDoc Markup Reference].
### Output from `irb`
For code examples, consider using interactive Ruby,
-[irb](https://ruby-doc.org/stdlib/libdoc/irb/rdoc/IRB.html).
+[irb].
For a code example that includes `irb` output,
consider aligning `# => ...` in successive lines.
@@ -129,22 +133,20 @@ a #=> [2, 3, 1]
### Headings
-Organize a long discussion for a class or module with [headings](rdoc-ref:RDoc::MarkupReference@Headings).
+Organize a long discussion for a class or module with [headings].
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.
+within the documentation for a method or constant,
+use [bold text] as pseudo-headings.
### 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)
-should be preceded by and followed by a blank line.
+A [code block][code blocks]
+or [list][lists] should be preceded by and followed by a blank line.
This is unnecessary for the HTML output, but helps in the `ri` output.
### \Method Names
@@ -164,7 +166,7 @@ For a method name in text:
Code or commands embedded in running text (i.e., not in a code block)
should marked up as
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
+[monofont].
Code that is a simple string should include the quote marks.
@@ -187,7 +189,7 @@ renders as:
> - File.new
> - File#read.
-In general, \RDoc's auto-linking should not be suppressed.
+In general, RDoc's auto-linking should not be suppressed.
For example, we should write just plain _Float_ (which is auto-linked):
```rdoc
@@ -214,7 +216,7 @@ refers to the current document
(e.g., _Float_ in the documentation for class Float).
In this case you may consider forcing the name to
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont),
+[monofont],
which suppresses auto-linking, and also emphasizes that the word is a class name:
```rdoc
@@ -267,16 +269,16 @@ and _never_ when referring to the class itself.
When writing an explicit link, follow these guidelines.
-#### +rdoc-ref+ Scheme
+#### `rdoc-ref` Scheme
-Use the +rdoc-ref+ scheme for:
+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].
+See section "`rdoc-ref` Scheme" in [links].
#### URL-Based Link
@@ -286,20 +288,44 @@ Use a full URL-based link for:
- 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
+Doing so ensures that the link will be 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.
+#### Fragments
+
+In general, a link that includes a [fragment][fragment]
+must cite the exact identifier on the target page;
+otherwise, the browser finds no suitable identifier,
+and does not scroll to the desired part of the page.
+
+However, certain pages on `github.com` and `github.io`
+support "fuzzy" identifier matching, so that URL
+https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#-why-are-rubys-floats-imprecise,
+(whose fragment is `-why-are-rubys-floats-imprecise`)
+scrolls to heading "Why are ruby’s floats imprecise?"
+even though the identifier there actually is the longer
+`#user-content--why-are-rubys-floats-imprecise`.
+
+Ruby documentation should avoid using these shortened fragments, for two reasons:
+
+- The GitHub pages that do this implement it using Javascript;
+ if the user's browser has Javascript disabled
+ (which some employers actually require),
+ the shortened fragment is ineffective and the desired scrolling does not occur.
+- A program that checks links in Ruby documentation will find no suitable identifier,
+ and therefore will report the fragment as not found.
+
### Variable Names
The name of a variable (as specified in its call-seq) should be marked up as
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
+[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+).
+(i.e., one defined and used only in the discussion, such as `n`).
### HTML Tags
@@ -314,13 +340,12 @@ In particular, avoid building tables with HTML tags
Alternatives:
-- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
+- A [verbatim text block][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:
+ note that [text markup][text markup] will not be honored:
- Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596].
- - Corresponding {output}[rdoc-ref:File@Read-2FWrite+Mode].
+ - Corresponding {output}[rdoc-ref:File@ReadWrite+Mode].
- (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-],
using special formatting for the text:
@@ -328,6 +353,16 @@ Alternatives:
- 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].
+### Languages in Examples
+
+For symbols and strings in documentation examples:
+
+- Prefer \English in \English documentation: <tt>'Hello'</tt>.
+- Prefer Japanese in Japanese documentation: <tt>'こんにちは'</tt>.
+- If a second language is needed (as, for example, characters with different byte-sizes),
+ prefer Japanese in \English documentation and \English in Japanese documentation.
+- Use other languages examples only as necessary: see String#capitalize.
+
## Documenting Classes and Modules
The general structure of the class or module documentation should be:
@@ -356,8 +391,7 @@ Guidelines:
- The section title is `What's Here`.
- Consider listing the parent class and any included modules; consider
- [links](rdoc-ref:RDoc::MarkupReference@Links)
- to their "What's Here" sections if those exist.
+ [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.
@@ -367,9 +401,9 @@ Guidelines:
and a short description.
- If the method has aliases, mention them in parentheses before the colon
(and do not list the aliases separately).
- - Check the rendered documentation to determine whether \RDoc has recognized
+ - 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][links].
- If there are numerous entries, consider grouping them into subsections with headings.
- If there are more than a few such subsections,
@@ -391,11 +425,11 @@ The general structure of the method documentation should be:
### Calling Sequence (for methods written in C)
-For methods written in Ruby, \RDoc documents the calling sequence automatically.
+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).
+For methods written in C, RDoc cannot determine what arguments
+the method accepts, so those need to be documented using RDoc directive
+[`call-seq:`][call-seq]
For a singleton method, use the form:
@@ -484,10 +518,10 @@ Return types:
- If the method can return multiple different types,
separate the types with "or" and, if necessary, commas.
-- If the method can return multiple types, use +object+.
-- If the method returns the receiver, use +self+.
+- If the method can return multiple types, use `object`.
+- If the method returns the receiver, use `self`.
- If the method returns an object of the same class,
- prefix `new_` if an only if the object is not +self+;
+ prefix `new_` if and only if the object is not `self`;
example: `new_array`.
Aliases:
@@ -570,7 +604,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][lists].
### Corner Cases and Exceptions
@@ -591,7 +625,7 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
`Hash#merge!` as a related method.
- Consider which methods may be related
- to the current method, and if you think the reader would benefit it,
+ to the current method, and if you think the reader would benefit from it,
at the end of the method documentation, add a line starting with
"Related: " (e.g. "Related: #fetch.").
- Don't list more than three related methods.
@@ -600,7 +634,7 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
- Consider adding:
- A phrase suggesting how the related method is similar to,
- or different from,the current method.
+ or different from, the current method.
See an example at Time#getutc.
- Example code that illustrates the similarities and differences.
See examples at Time#ctime, Time#inspect, Time#to_s.
@@ -610,3 +644,16 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
For methods that accept multiple argument types, in some cases it can
be useful to document the different argument types separately. It's
best to use a separate paragraph for each case you are discussing.
+
+[bold text]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#bold
+[call-seq]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#directive-for-specifying-rdoc-source-format
+[code blocks]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#code-blocks
+[fragment]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Fragment
+[headings]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#headings
+[irb]: https://ruby.github.io/irb/index.html
+[links]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#links
+[lists]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#lists
+[monofont]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#monofont
+[RDoc Markup Reference]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html
+[text markup]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#text-markup
+[verbatim text blocks]: https://ruby.github.io/rdoc/doc/markup_reference/rdoc_rdoc.html#verbatim-text-blocks
diff --git a/doc/dtrace_probes.rdoc b/doc/contributing/dtrace_probes.rdoc
index 1b20597ab4..1b20597ab4 100644
--- a/doc/dtrace_probes.rdoc
+++ b/doc/contributing/dtrace_probes.rdoc
diff --git a/doc/contributing/glossary.md b/doc/contributing/glossary.md
index 86c6671fbd..3ec9796147 100644
--- a/doc/contributing/glossary.md
+++ b/doc/contributing/glossary.md
@@ -4,14 +4,17 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
| Term | Definition |
| --- | -----------|
+| `bmethod` | Method defined by `define_method() {}` (a Block that runs as a Method). |
| `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 |
+| CFG | Control Flow Graph. Representation of the program where all control-flow and data dependencies have been made explicit by unrolling the stack and local variables. |
| `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`. |
+| `ci` | Call Information. Refers to an `rb_callinfo` struct. Contains call information about the call site, including number of parameters to be passed, whether they are keyword arguments or not, etc. Used in conjunction with the `cc` and `cd`. |
+| `cme` | Callable Method Entry. Refers to the `rb_callable_method_entry_t` struct, the internal representation of a Ruby method that has `defined_class` and `owner` set and is ready for dispatch. |
| `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 |
+| CRuby | Reference 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` |
@@ -25,16 +28,20 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
| `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. |
+| `IVC` | Instance Variable Cache. Cache specifically for instance variable access |
| 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.
+| `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 |
+| `snt` | Shared Native Thread. OS thread on which many ruby threads can run. Ruby threads from different ractors can even run on the same SNT. Ruby threads can switch SNTs when they context switch. SNTs are used in the M:N threading model. By default, non-main ractors use this model.
+| `dnt` | Dedicated Native Thread. OS thread on which only one ruby thread can run. The ruby thread always runs on that same OS thread. DNTs are used in the 1:1 threading model. By default, the main ractor uses this model.
| `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|
+| ST table | ST table is the main C implementation of a hash (smaller Ruby hashes may be backed by AR tables). |
| `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)
+| 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 |
diff --git a/doc/contributing/making_changes_to_stdlibs.md b/doc/contributing/making_changes_to_stdlibs.md
index 721ba84289..2ceb2e6075 100644
--- a/doc/contributing/making_changes_to_stdlibs.md
+++ b/doc/contributing/making_changes_to_stdlibs.md
@@ -4,7 +4,7 @@ Everything in the [lib](https://github.com/ruby/ruby/tree/master/lib) directory
If you'd like to make contributions to standard libraries, do so in the standalone repositories, and the
changes will be automatically mirrored into the Ruby repository.
-For example, CSV lives in [a separate repository](https://github.com/ruby/csv) and is mirrored into [Ruby](https://github.com/ruby/ruby/tree/master/lib/csv).
+For example, ERB lives in [a separate repository](https://github.com/ruby/erb) and is mirrored into [Ruby](https://github.com/ruby/ruby/tree/master/lib/erb).
## Maintainers
@@ -45,5 +45,5 @@ bundle exec rake test TEST="test/test_foo.rb"
To run a single test case:
```shell
-bundle exec rake test TEST="test/test_foo.rb" TESTOPS="--name=/test_mytest/"
+bundle exec rake test TEST="test/test_foo.rb" TESTOPTS="--name=/test_mytest/"
```
diff --git a/doc/memory_view.md b/doc/contributing/memory_view.md
index 0b1369163d..0b1369163d 100644
--- a/doc/memory_view.md
+++ b/doc/contributing/memory_view.md
diff --git a/doc/contributing/vm_stack_and_frames.md b/doc/contributing/vm_stack_and_frames.md
new file mode 100644
index 0000000000..c7dc59db16
--- /dev/null
+++ b/doc/contributing/vm_stack_and_frames.md
@@ -0,0 +1,163 @@
+# Ruby VM Stack and Frame Layout
+
+This document explains the Ruby VM stack architecture, including how the value
+stack (SP) and control frames (CFP) share a single contiguous memory region,
+and how individual frames are structured.
+
+## VM Stack Architecture
+
+The Ruby VM uses a single contiguous stack (`ec->vm_stack`) with two different
+regions growing toward each other. Understanding this requires distinguishing
+the overall architecture (how CFPs and values share one stack) from individual
+frame internals (how values are organized for one single frame).
+
+```text
+High addresses (ec->vm_stack + ec->vm_stack_size)
+ ↓
+ [CFP region starts here] ← RUBY_VM_END_CONTROL_FRAME(ec)
+ [CFP - 1] New frame pushed here (grows downward)
+ [CFP - 2] Another frame
+ ...
+
+ (Unused space - stack overflow when they meet)
+
+ ... Value stack grows UP toward higher addresses
+ [SP + n] Values pushed here
+ [ec->cfp->sp] Current executing frame's stack pointer
+ ↑
+Low addresses (ec->vm_stack)
+```
+
+The "unused space" represents free space available for new frames and values. When this gap closes (CFP meets SP), stack overflow occurs.
+
+### Stack Growth Directions
+
+**Control Frames (CFP):**
+
+- Start at `ec->vm_stack + ec->vm_stack_size` (high addresses)
+- Grow **downward** toward lower addresses as frames are pushed
+- Each new frame is allocated at `cfp - 1` (lower address)
+- The `rb_control_frame_t` structure itself moves downward
+
+**Value Stack (SP):**
+
+- Starts at `ec->vm_stack` (low addresses)
+- Grows **upward** toward higher addresses as values are pushed
+- Each frame's `cfp->sp` points to the top of its value stack
+
+### Stack Overflow
+
+When recursive calls push too many frames, CFP grows downward until it collides
+with SP growing upward. The VM detects this with `CHECK_VM_STACK_OVERFLOW0`,
+which computes `const rb_control_frame_struct *bound = (void *)&sp[margin];`
+and raises if `cfp <= &bound[1]`.
+
+## Understanding Individual Frame Value Stacks
+
+Each frame has its own portion of the overall VM stack, called its "VM value stack"
+or simply "value stack". This space is pre-allocated when the frame is created,
+with size determined by:
+
+- `local_size` - space for local variables
+- `stack_max` - maximum depth for temporary values during execution
+
+The frame's value stack grows upward from its base (where self/arguments/locals
+live) toward `cfp->sp` (the current top of temporary values).
+
+## Visualizing How Frames Fit in the VM Stack
+
+The left side shows the overall VM stack with CFP metadata separated from frame
+values. The right side zooms into one frame's value region, revealing its internal
+structure.
+
+```text
+Overall VM Stack (ec->vm_stack): Zooming into Frame 2's value stack:
+
+High addr (vm_stack + vm_stack_size) High addr (cfp->sp)
+ ↓ ┌
+ [CFP 1 metadata] │ [Temporaries]
+ [CFP 2 metadata] ─────────┐ │ [Env: Flags/Block/CME] ← cfp->ep
+ [CFP 3 metadata] │ │ [Locals]
+ ──────────────── │ ┌─┤ [Arguments]
+ (unused space) │ │ │ [self]
+ ──────────────── │ │ └
+ [Frame 3 values] │ │ Low addr (frame base)
+ [Frame 2 values] <────────┴───────┘
+ [Frame 1 values]
+ ↑
+Low addr (vm_stack)
+```
+
+## Examining a Single Frame's Value Stack
+
+Now let's walk through a concrete Ruby program to see how a single frame's
+value stack is structured internally:
+
+```ruby
+def foo(x, y)
+ z = x.casecmp(y)
+end
+
+foo(:one, :two)
+```
+
+First, after arguments are evaluated and right before the `send` to `foo`:
+
+```text
+ ┌────────────┐
+ putself │ :two │
+ putobject :one 0x2 ├────────────┤
+ putobject :two │ :one │
+► send <:foo, argc:2> 0x1 ├────────────┤
+ leave │ self │
+ 0x0 └────────────┘
+```
+
+The `put*` instructions have pushed 3 items onto the stack. It's now time to
+add a new control frame for `foo`. The following is the shape of the stack
+after one instruction in `foo`:
+
+```text
+ cfp->sp=0x8 at this point.
+ 0x8 ┌────────────┐◄──Stack space for temporaries
+ │ :one │ live above the environment.
+ 0x7 ├────────────┤
+ getlocal x@0 │ < flags > │ foo's rb_control_frame_t
+► getlocal y@1 0x6 ├────────────┤◄──has cfp->ep=0x6
+ send <:casecmp, argc:1> │ <no block> │
+ dup 0x5 ├────────────┤ The flags, block, and CME triple
+ setlocal z@2 │ <CME: foo> │ (VM_ENV_DATA_SIZE) form an
+ leave 0x4 ├────────────┤ environment. They can be used to
+ │ z (nil) │ figure out what local variables
+ 0x3 ├────────────┤ are below them.
+ │ :two │
+ 0x2 ├────────────┤ Notice how the arguments, now
+ │ :one │ locals, never moved. This layout
+ 0x1 ├────────────┤ allows for argument transfer
+ │ self │ without copying.
+ 0x0 └────────────┘
+```
+
+Given that locals have lower address than `cfp->ep`, it makes sense then that
+`getlocal` in `insns.def` has `val = *(vm_get_ep(GET_EP(), level) - idx);`.
+When accessing variables in the immediate scope, where `level=0`, it's
+essentially `val = cfp->ep[-idx];`.
+
+Note that this EP-relative index has a different basis than the index that comes
+after "@" in disassembly listings. The "@" index is relative to the 0th local
+(`x` in this case).
+
+### Q&A
+
+Q: It seems that the receiver is always at an offset relative to EP,
+ like locals. Couldn't we use EP to access it instead of using `cfp->self`?
+
+A: Not all calls put the `self` in the callee on the stack. Two
+ examples are `Proc#call`, where the receiver is the Proc object, but `self`
+ inside the callee is `Proc#receiver`, and `yield`, where the receiver isn't
+ pushed onto the stack before the arguments.
+
+Q: Why have `cfp->ep` when it seems that everything is below `cfp->sp`?
+
+A: In the example, `cfp->ep` points to the stack, but it can also point to the
+ GC heap. Blocks can capture and evacuate their environment to the heap.
diff --git a/doc/csv/arguments/io.rdoc b/doc/csv/arguments/io.rdoc
deleted file mode 100644
index f5fe1d1975..0000000000
--- a/doc/csv/arguments/io.rdoc
+++ /dev/null
@@ -1,5 +0,0 @@
-* Argument +io+ should be an IO object that is:
- * Open for reading; on return, the IO object will be closed.
- * Positioned at the beginning.
- To position at the end, for appending, use method CSV.generate.
- For any other positioning, pass a preset \StringIO object instead.
diff --git a/doc/csv/options/common/col_sep.rdoc b/doc/csv/options/common/col_sep.rdoc
deleted file mode 100644
index 3f23c6d2d3..0000000000
--- a/doc/csv/options/common/col_sep.rdoc
+++ /dev/null
@@ -1,57 +0,0 @@
-====== Option +col_sep+
-
-Specifies the \String field separator to be used
-for both parsing and generating.
-The \String will be transcoded into the data's \Encoding before use.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
-
-Using the default (comma):
- str = CSV.generate do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using +:+ (colon):
- col_sep = ':'
- str = CSV.generate(col_sep: col_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo:0\nbar:1\nbaz:2\n"
- ary = CSV.parse(str, col_sep: col_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using +::+ (two colons):
- col_sep = '::'
- str = CSV.generate(col_sep: col_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo::0\nbar::1\nbaz::2\n"
- ary = CSV.parse(str, col_sep: col_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>''</tt> (empty string):
- col_sep = ''
- str = CSV.generate(col_sep: col_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo0\nbar1\nbaz2\n"
-
----
-
-Raises an exception if parsing with the empty \String:
- col_sep = ''
- # Raises ArgumentError (:col_sep must be 1 or more characters: "")
- CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
-
diff --git a/doc/csv/options/common/quote_char.rdoc b/doc/csv/options/common/quote_char.rdoc
deleted file mode 100644
index 67fd3af68b..0000000000
--- a/doc/csv/options/common/quote_char.rdoc
+++ /dev/null
@@ -1,42 +0,0 @@
-====== Option +quote_char+
-
-Specifies the character (\String of length 1) used used to quote fields
-in both parsing and generating.
-This String will be transcoded into the data's \Encoding before use.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
-
-This is useful for an application that incorrectly uses <tt>'</tt> (single-quote)
-to quote fields, instead of the correct <tt>"</tt> (double-quote).
-
-Using the default (double quote):
- str = CSV.generate do |csv|
- csv << ['foo', 0]
- csv << ["'bar'", 1]
- csv << ['"baz"', 2]
- end
- str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
-
-Using <tt>'</tt> (single-quote):
- quote_char = "'"
- str = CSV.generate(quote_char: quote_char) do |csv|
- csv << ['foo', 0]
- csv << ["'bar'", 1]
- csv << ['"baz"', 2]
- end
- str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
- ary = CSV.parse(str, quote_char: quote_char)
- ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
-
----
-
-Raises an exception if the \String length is greater than 1:
- # Raises ArgumentError (:quote_char has to be nil or a single character String)
- CSV.new('', quote_char: 'xx')
-
-Raises an exception if the value is not a \String:
- # Raises ArgumentError (:quote_char has to be nil or a single character String)
- CSV.new('', quote_char: :foo)
diff --git a/doc/csv/options/common/row_sep.rdoc b/doc/csv/options/common/row_sep.rdoc
deleted file mode 100644
index eae15b4a84..0000000000
--- a/doc/csv/options/common/row_sep.rdoc
+++ /dev/null
@@ -1,91 +0,0 @@
-====== Option +row_sep+
-
-Specifies the row separator, a \String or the \Symbol <tt>:auto</tt> (see below),
-to be used for both parsing and generating.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
-
----
-
-When +row_sep+ is a \String, that \String becomes the row separator.
-The String will be transcoded into the data's Encoding before use.
-
-Using <tt>"\n"</tt>:
- row_sep = "\n"
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>|</tt> (pipe):
- row_sep = '|'
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0|bar,1|baz,2|"
- ary = CSV.parse(str, row_sep: row_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>--</tt> (two hyphens):
- row_sep = '--'
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0--bar,1--baz,2--"
- ary = CSV.parse(str, row_sep: row_sep)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using <tt>''</tt> (empty string):
- row_sep = ''
- str = CSV.generate(row_sep: row_sep) do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0bar,1baz,2"
- ary = CSV.parse(str, row_sep: row_sep)
- ary # => [["foo", "0bar", "1baz", "2"]]
-
----
-
-When +row_sep+ is the \Symbol +:auto+ (the default),
-generating uses <tt>"\n"</tt> as the row separator:
- str = CSV.generate do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
-
-Parsing, on the other hand, invokes auto-discovery of the row separator.
-
-Auto-discovery reads ahead in the data looking for the next <tt>\r\n</tt>, +\n+, or +\r+ sequence.
-The sequence will be selected even if it occurs in a quoted field,
-assuming that you would have the same line endings there.
-
-Example:
- str = CSV.generate do |csv|
- csv << [:foo, 0]
- csv << [:bar, 1]
- csv << [:baz, 2]
- end
- str # => "foo,0\nbar,1\nbaz,2\n"
- ary = CSV.parse(str)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-The default <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) is used
-if any of the following is true:
-* None of those sequences is found.
-* Data is +ARGF+, +STDIN+, +STDOUT+, or +STDERR+.
-* 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.
diff --git a/doc/csv/options/generating/force_quotes.rdoc b/doc/csv/options/generating/force_quotes.rdoc
deleted file mode 100644
index 11afd1a16c..0000000000
--- a/doc/csv/options/generating/force_quotes.rdoc
+++ /dev/null
@@ -1,17 +0,0 @@
-====== Option +force_quotes+
-
-Specifies the boolean that determines whether each output field is to be double-quoted.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false
-
-For examples in this section:
- ary = ['foo', 0, nil]
-
-Using the default, +false+:
- str = CSV.generate_line(ary)
- str # => "foo,0,\n"
-
-Using +true+:
- str = CSV.generate_line(ary, force_quotes: true)
- str # => "\"foo\",\"0\",\"\"\n"
diff --git a/doc/csv/options/generating/quote_empty.rdoc b/doc/csv/options/generating/quote_empty.rdoc
deleted file mode 100644
index 4c5645c662..0000000000
--- a/doc/csv/options/generating/quote_empty.rdoc
+++ /dev/null
@@ -1,12 +0,0 @@
-====== Option +quote_empty+
-
-Specifies the boolean that determines whether an empty value is to be double-quoted.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true
-
-With the default +true+:
- CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"
-
-With +false+:
- CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
diff --git a/doc/csv/options/generating/write_converters.rdoc b/doc/csv/options/generating/write_converters.rdoc
deleted file mode 100644
index d1a9cc748f..0000000000
--- a/doc/csv/options/generating/write_converters.rdoc
+++ /dev/null
@@ -1,25 +0,0 @@
-====== Option +write_converters+
-
-Specifies converters to be used in generating fields.
-See {Write Converters}[#class-CSV-label-Write+Converters]
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
-
-With no write converter:
- str = CSV.generate_line(["\na\n", "\tb\t", " c "])
- str # => "\"\na\n\",\tb\t, c \n"
-
-With a write converter:
- strip_converter = proc {|field| field.strip }
- str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
- str # => "a,b,c\n"
-
-With two write converters (called in order):
- upcase_converter = proc {|field| field.upcase }
- downcase_converter = proc {|field| field.downcase }
- write_converters = [upcase_converter, downcase_converter]
- str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
- str # => "a,b,c\n"
-
-See also {Write Converters}[#class-CSV-label-Write+Converters]
diff --git a/doc/csv/options/generating/write_empty_value.rdoc b/doc/csv/options/generating/write_empty_value.rdoc
deleted file mode 100644
index 67be5662cb..0000000000
--- a/doc/csv/options/generating/write_empty_value.rdoc
+++ /dev/null
@@ -1,15 +0,0 @@
-====== Option +write_empty_value+
-
-Specifies the object that is to be substituted for each field
-that has an empty \String.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""
-
-Without the option:
- str = CSV.generate_line(['a', '', 'c', ''])
- str # => "a,\"\",c,\"\"\n"
-
-With the option:
- str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x")
- str # => "a,x,c,x\n"
diff --git a/doc/csv/options/generating/write_headers.rdoc b/doc/csv/options/generating/write_headers.rdoc
deleted file mode 100644
index c56aa48adb..0000000000
--- a/doc/csv/options/generating/write_headers.rdoc
+++ /dev/null
@@ -1,29 +0,0 @@
-====== Option +write_headers+
-
-Specifies the boolean that determines whether a header row is included in the output;
-ignored if there are no headers.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
-
-Without +write_headers+:
- file_path = 't.csv'
- CSV.open(file_path,'w',
- :headers => ['Name','Value']
- ) do |csv|
- csv << ['foo', '0']
- end
- CSV.open(file_path) do |csv|
- csv.shift
- end # => ["foo", "0"]
-
-With +write_headers+":
- CSV.open(file_path,'w',
- :write_headers => true,
- :headers => ['Name','Value']
- ) do |csv|
- csv << ['foo', '0']
- end
- CSV.open(file_path) do |csv|
- csv.shift
- end # => ["Name", "Value"]
diff --git a/doc/csv/options/generating/write_nil_value.rdoc b/doc/csv/options/generating/write_nil_value.rdoc
deleted file mode 100644
index 65d33ff54e..0000000000
--- a/doc/csv/options/generating/write_nil_value.rdoc
+++ /dev/null
@@ -1,14 +0,0 @@
-====== Option +write_nil_value+
-
-Specifies the object that is to be substituted for each +nil+-valued field.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
-
-Without the option:
- str = CSV.generate_line(['a', nil, 'c', nil])
- str # => "a,,c,\n"
-
-With the option:
- str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
- str # => "a,x,c,x\n"
diff --git a/doc/csv/options/parsing/converters.rdoc b/doc/csv/options/parsing/converters.rdoc
deleted file mode 100644
index 211fa48de6..0000000000
--- a/doc/csv/options/parsing/converters.rdoc
+++ /dev/null
@@ -1,46 +0,0 @@
-====== Option +converters+
-
-Specifies converters to be used in parsing fields.
-See {Field Converters}[#class-CSV-label-Field+Converters]
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
-
-The value may be a field converter name
-(see {Stored Converters}[#class-CSV-label-Stored+Converters]):
- str = '1,2,3'
- # Without a converter
- array = CSV.parse_line(str)
- array # => ["1", "2", "3"]
- # With built-in converter :integer
- array = CSV.parse_line(str, converters: :integer)
- array # => [1, 2, 3]
-
-The value may be a converter list
-(see {Converter Lists}[#class-CSV-label-Converter+Lists]):
- str = '1,3.14159'
- # Without converters
- array = CSV.parse_line(str)
- array # => ["1", "3.14159"]
- # With built-in converters
- array = CSV.parse_line(str, converters: [:integer, :float])
- array # => [1, 3.14159]
-
-The value may be a \Proc custom converter:
-(see {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]):
- str = ' foo , bar , baz '
- # Without a converter
- array = CSV.parse_line(str)
- array # => [" foo ", " bar ", " baz "]
- # With a custom converter
- array = CSV.parse_line(str, converters: proc {|field| field.strip })
- array # => ["foo", "bar", "baz"]
-
-See also {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]
-
----
-
-Raises an exception if the converter is not a converter name or a \Proc:
- str = 'foo,0'
- # Raises NoMethodError (undefined method `arity' for nil:NilClass)
- CSV.parse(str, converters: :foo)
diff --git a/doc/csv/options/parsing/empty_value.rdoc b/doc/csv/options/parsing/empty_value.rdoc
deleted file mode 100644
index 7d3bcc078c..0000000000
--- a/doc/csv/options/parsing/empty_value.rdoc
+++ /dev/null
@@ -1,13 +0,0 @@
-====== Option +empty_value+
-
-Specifies the object that is to be substituted
-for each field that has an empty \String.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
-
-With the default, <tt>""</tt>:
- CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
-
-With a different object:
- CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
diff --git a/doc/csv/options/parsing/field_size_limit.rdoc b/doc/csv/options/parsing/field_size_limit.rdoc
deleted file mode 100644
index 797c5776fc..0000000000
--- a/doc/csv/options/parsing/field_size_limit.rdoc
+++ /dev/null
@@ -1,39 +0,0 @@
-====== Option +field_size_limit+
-
-Specifies the \Integer field size limit.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil
-
-This is a maximum size CSV will read ahead looking for the closing quote for a field.
-(In truth, it reads to the first line ending beyond this size.)
-If a quote cannot be found within the limit CSV will raise a MalformedCSVError,
-assuming the data is faulty.
-You can use this limit to prevent what are effectively DoS attacks on the parser.
-However, this limit can cause a legitimate parse to fail;
-therefore the default value is +nil+ (no limit).
-
-For the examples in this section:
- str = <<~EOT
- "a","b"
- "
- 2345
- ",""
- EOT
- str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"
-
-Using the default +nil+:
- ary = CSV.parse(str)
- ary # => [["a", "b"], ["\n2345\n", ""]]
-
-Using <tt>50</tt>:
- field_size_limit = 50
- ary = CSV.parse(str, field_size_limit: field_size_limit)
- ary # => [["a", "b"], ["\n2345\n", ""]]
-
----
-
-Raises an exception if a field is too long:
- big_str = "123456789\n" * 1024
- # Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
- CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
diff --git a/doc/csv/options/parsing/header_converters.rdoc b/doc/csv/options/parsing/header_converters.rdoc
deleted file mode 100644
index 309180805f..0000000000
--- a/doc/csv/options/parsing/header_converters.rdoc
+++ /dev/null
@@ -1,43 +0,0 @@
-====== Option +header_converters+
-
-Specifies converters to be used in parsing headers.
-See {Header Converters}[#class-CSV-label-Header+Converters]
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
-
-Identical in functionality to option {converters}[#class-CSV-label-Option+converters]
-except that:
-- The converters apply only to the header row.
-- The built-in header converters are +:downcase+ and +:symbol+.
-
-This section assumes prior execution of:
- str = <<-EOT
- Name,Value
- foo,0
- bar,1
- baz,2
- EOT
- # With no header converter
- table = CSV.parse(str, headers: true)
- table.headers # => ["Name", "Value"]
-
-The value may be a header converter name
-(see {Stored Converters}[#class-CSV-label-Stored+Converters]):
- table = CSV.parse(str, headers: true, header_converters: :downcase)
- table.headers # => ["name", "value"]
-
-The value may be a converter list
-(see {Converter Lists}[#class-CSV-label-Converter+Lists]):
- header_converters = [:downcase, :symbol]
- table = CSV.parse(str, headers: true, header_converters: header_converters)
- table.headers # => [:name, :value]
-
-The value may be a \Proc custom converter
-(see {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]):
- upcase_converter = proc {|field| field.upcase }
- table = CSV.parse(str, headers: true, header_converters: upcase_converter)
- table.headers # => ["NAME", "VALUE"]
-
-See also {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]
-
diff --git a/doc/csv/options/parsing/headers.rdoc b/doc/csv/options/parsing/headers.rdoc
deleted file mode 100644
index 0ea151f24b..0000000000
--- a/doc/csv/options/parsing/headers.rdoc
+++ /dev/null
@@ -1,63 +0,0 @@
-====== Option +headers+
-
-Specifies a boolean, \Symbol, \Array, or \String to be used
-to define column headers.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:headers) # => false
-
----
-
-Without +headers+:
- str = <<-EOT
- Name,Count
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str)
- csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
- csv.headers # => nil
- csv.shift # => ["Name", "Count"]
-
----
-
-If set to +true+ or the \Symbol +:first_row+,
-the first row of the data is treated as a row of headers:
- str = <<-EOT
- Name,Count
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str, headers: true)
- csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]>
- csv.headers # => ["Name", "Count"]
- csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
-
----
-
-If set to an \Array, the \Array elements are treated as headers:
- str = <<-EOT
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str, headers: ['Name', 'Count'])
- csv
- csv.headers # => ["Name", "Count"]
- csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
-
----
-
-If set to a \String +str+, method <tt>CSV::parse_line(str, options)</tt> is called
-with the current +options+, and the returned \Array is treated as headers:
- str = <<-EOT
- foo,0
- bar,1
- bax,2
- EOT
- csv = CSV.new(str, headers: 'Name,Count')
- csv
- csv.headers # => ["Name", "Count"]
- csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
diff --git a/doc/csv/options/parsing/liberal_parsing.rdoc b/doc/csv/options/parsing/liberal_parsing.rdoc
deleted file mode 100644
index 603de28613..0000000000
--- a/doc/csv/options/parsing/liberal_parsing.rdoc
+++ /dev/null
@@ -1,38 +0,0 @@
-====== Option +liberal_parsing+
-
-Specifies the boolean or hash 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:
- str = 'is,this "three, or four",fields'
-
-Without +liberal_parsing+:
- # Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
- CSV.parse_line(str)
-
-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/options/parsing/nil_value.rdoc b/doc/csv/options/parsing/nil_value.rdoc
deleted file mode 100644
index 412e8795e8..0000000000
--- a/doc/csv/options/parsing/nil_value.rdoc
+++ /dev/null
@@ -1,12 +0,0 @@
-====== Option +nil_value+
-
-Specifies the object that is to be substituted for each null (no-text) field.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
-
-With the default, +nil+:
- CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
-
-With a different object:
- CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
diff --git a/doc/csv/options/parsing/return_headers.rdoc b/doc/csv/options/parsing/return_headers.rdoc
deleted file mode 100644
index 45d2e3f3de..0000000000
--- a/doc/csv/options/parsing/return_headers.rdoc
+++ /dev/null
@@ -1,22 +0,0 @@
-====== Option +return_headers+
-
-Specifies the boolean that determines whether method #shift
-returns or ignores the header row.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false
-
-Examples:
- str = <<-EOT
- Name,Count
- foo,0
- bar,1
- bax,2
- EOT
- # Without return_headers first row is str.
- csv = CSV.new(str, headers: true)
- csv.shift # => #<CSV::Row "Name":"foo" "Count":"0">
- # With return_headers first row is headers.
- csv = CSV.new(str, headers: true, return_headers: true)
- csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
-
diff --git a/doc/csv/options/parsing/skip_blanks.rdoc b/doc/csv/options/parsing/skip_blanks.rdoc
deleted file mode 100644
index 2c8f7b7bb8..0000000000
--- a/doc/csv/options/parsing/skip_blanks.rdoc
+++ /dev/null
@@ -1,31 +0,0 @@
-====== Option +skip_blanks+
-
-Specifies a boolean that determines whether blank lines in the input will be ignored;
-a line that contains a column separator is not considered to be blank.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
-
-See also option {skiplines}[#class-CSV-label-Option+skip_lines].
-
-For examples in this section:
- str = <<-EOT
- foo,0
-
- bar,1
- baz,2
-
- ,
- EOT
-
-Using the default, +false+:
- ary = CSV.parse(str)
- ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
-
-Using +true+:
- ary = CSV.parse(str, skip_blanks: true)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
-
-Using a truthy value:
- ary = CSV.parse(str, skip_blanks: :foo)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
diff --git a/doc/csv/options/parsing/skip_lines.rdoc b/doc/csv/options/parsing/skip_lines.rdoc
deleted file mode 100644
index 1481c40a5f..0000000000
--- a/doc/csv/options/parsing/skip_lines.rdoc
+++ /dev/null
@@ -1,37 +0,0 @@
-====== Option +skip_lines+
-
-Specifies an object to use in identifying comment lines in the input that are to be ignored:
-* If a \Regexp, ignores lines that match it.
-* If a \String, converts it to a \Regexp, ignores lines that match it.
-* If +nil+, no lines are considered to be comments.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
-
-For examples in this section:
- str = <<-EOT
- # Comment
- foo,0
- bar,1
- baz,2
- # Another comment
- EOT
- str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
-
-Using the default, +nil+:
- ary = CSV.parse(str)
- ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
-
-Using a \Regexp:
- ary = CSV.parse(str, skip_lines: /^#/)
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Using a \String:
- ary = CSV.parse(str, skip_lines: '#')
- ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
----
-
-Raises an exception if given an object that is not a \Regexp, a \String, or +nil+:
- # Raises ArgumentError (:skip_lines has to respond to #match: 0)
- CSV.parse(str, skip_lines: 0)
diff --git a/doc/csv/options/parsing/strip.rdoc b/doc/csv/options/parsing/strip.rdoc
deleted file mode 100644
index 56ae4310c3..0000000000
--- a/doc/csv/options/parsing/strip.rdoc
+++ /dev/null
@@ -1,15 +0,0 @@
-====== Option +strip+
-
-Specifies the boolean value that determines whether
-whitespace is stripped from each input field.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
-
-With default value +false+:
- ary = CSV.parse_line(' a , b ')
- ary # => [" a ", " b "]
-
-With value +true+:
- ary = CSV.parse_line(' a , b ', strip: true)
- ary # => ["a", "b"]
diff --git a/doc/csv/options/parsing/unconverted_fields.rdoc b/doc/csv/options/parsing/unconverted_fields.rdoc
deleted file mode 100644
index 3e7f839d49..0000000000
--- a/doc/csv/options/parsing/unconverted_fields.rdoc
+++ /dev/null
@@ -1,27 +0,0 @@
-====== Option +unconverted_fields+
-
-Specifies the boolean that determines whether unconverted field values are to be available.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil
-
-The unconverted field values are those found in the source data,
-prior to any conversions performed via option +converters+.
-
-When option +unconverted_fields+ is +true+,
-each returned row (\Array or \CSV::Row) has an added method,
-+unconverted_fields+, that returns the unconverted field values:
- str = <<-EOT
- foo,0
- bar,1
- baz,2
- EOT
- # Without unconverted_fields
- csv = CSV.parse(str, converters: :integer)
- csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
- csv.first.respond_to?(:unconverted_fields) # => false
- # With unconverted_fields
- csv = CSV.parse(str, converters: :integer, unconverted_fields: true)
- csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
- csv.first.respond_to?(:unconverted_fields) # => true
- csv.first.unconverted_fields # => ["foo", "0"]
diff --git a/doc/csv/recipes/filtering.rdoc b/doc/csv/recipes/filtering.rdoc
deleted file mode 100644
index 1552bf0fb8..0000000000
--- a/doc/csv/recipes/filtering.rdoc
+++ /dev/null
@@ -1,158 +0,0 @@
-== 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:
- require 'csv'
-
-=== Contents
-
-- {Source and Output Formats}[#label-Source+and+Output+Formats]
- - {Filtering String to String}[#label-Filtering+String+to+String]
- - {Recipe: Filter String to String with Headers}[#label-Recipe-3A+Filter+String+to+String+with+Headers]
- - {Recipe: Filter String to String Without Headers}[#label-Recipe-3A+Filter+String+to+String+Without+Headers]
- - {Filtering String to IO Stream}[#label-Filtering+String+to+IO+Stream]
- - {Recipe: Filter String to IO Stream with Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+with+Headers]
- - {Recipe: Filter String to IO Stream Without Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+Without+Headers]
- - {Filtering IO Stream to String}[#label-Filtering+IO+Stream+to+String]
- - {Recipe: Filter IO Stream to String with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+with+Headers]
- - {Recipe: Filter IO Stream to String Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+Without+Headers]
- - {Filtering IO Stream to IO Stream}[#label-Filtering+IO+Stream+to+IO+Stream]
- - {Recipe: Filter IO Stream to IO Stream with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+with+Headers]
- - {Recipe: Filter IO Stream to IO Stream Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+Without+Headers]
-
-=== Source and Output Formats
-
-You can use a Unix-style "filter" for \CSV data.
-The filter reads source \CSV data and writes output \CSV data as modified by the filter.
-The input and output \CSV data may be any mixture of \Strings and \IO streams.
-
-==== Filtering \String to \String
-
-You can filter one \String to another, with or without headers.
-
-===== Recipe: Filter \String to \String with Headers
-
-Use class method CSV.filter with option +headers+ to filter a \String to another \String:
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- out_string = ''
- CSV.filter(in_string, out_string, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \String to \String Without Headers
-
-Use class method CSV.filter without option +headers+ to filter a \String to another \String:
- in_string = "foo,0\nbar,1\nbaz,2\n"
- out_string = ''
- CSV.filter(in_string, out_string) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
-
-==== Filtering \String to \IO Stream
-
-You can filter a \String to an \IO stream, with or without headers.
-
-===== Recipe: Filter \String to \IO Stream with Headers
-
-Use class method CSV.filter with option +headers+ to filter a \String to an \IO stream:
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.open(path, 'w') do |out_io|
- CSV.filter(in_string, out_io, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- p File.read(path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \String to \IO Stream Without Headers
-
-Use class method CSV.filter without option +headers+ to filter a \String to an \IO stream:
- in_string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.open(path, 'w') do |out_io|
- CSV.filter(in_string, out_io) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- p File.read(path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
-
-==== Filtering \IO Stream to \String
-
-You can filter an \IO stream to a \String, with or without headers.
-
-===== Recipe: Filter \IO Stream to \String with Headers
-
-Use class method CSV.filter with option +headers+ to filter an \IO stream to a \String:
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, in_string)
- out_string = ''
- File.open(path, headers: true) do |in_io|
- CSV.filter(in_io, out_string, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \IO Stream to \String Without Headers
-
-Use class method CSV.filter without option +headers+ to filter an \IO stream to a \String:
- in_string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, in_string)
- out_string = ''
- File.open(path) do |in_io|
- CSV.filter(in_io, out_string) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
-
-==== Filtering \IO Stream to \IO Stream
-
-You can filter an \IO stream to another \IO stream, with or without headers.
-
-===== Recipe: Filter \IO Stream to \IO Stream with Headers
-
-Use class method CSV.filter with option +headers+ to filter an \IO stream to another \IO stream:
- in_path = 't.csv'
- in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- File.write(in_path, in_string)
- out_path = 'u.csv'
- File.open(in_path) do |in_io|
- File.open(out_path, 'w') do |out_io|
- CSV.filter(in_io, out_io, headers: true) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- end
- p File.read(out_path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
-
-===== Recipe: Filter \IO Stream to \IO Stream Without Headers
-
-Use class method CSV.filter without option +headers+ to filter an \IO stream to another \IO stream:
- in_path = 't.csv'
- in_string = "foo,0\nbar,1\nbaz,2\n"
- File.write(in_path, in_string)
- out_path = 'u.csv'
- File.open(in_path) do |in_io|
- File.open(out_path, 'w') do |out_io|
- CSV.filter(in_io, out_io) do |row|
- row[0] = row[0].upcase
- row[1] *= 4
- end
- end
- end
- p File.read(out_path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
diff --git a/doc/csv/recipes/generating.rdoc b/doc/csv/recipes/generating.rdoc
deleted file mode 100644
index e61838d31a..0000000000
--- a/doc/csv/recipes/generating.rdoc
+++ /dev/null
@@ -1,246 +0,0 @@
-== 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:
- require 'csv'
-
-=== Contents
-
-- {Output Formats}[#label-Output+Formats]
- - {Generating to a String}[#label-Generating+to+a+String]
- - {Recipe: Generate to String with Headers}[#label-Recipe-3A+Generate+to+String+with+Headers]
- - {Recipe: Generate to String Without Headers}[#label-Recipe-3A+Generate+to+String+Without+Headers]
- - {Generating to a File}[#label-Generating+to+a+File]
- - {Recipe: Generate to File with Headers}[#label-Recipe-3A+Generate+to+File+with+Headers]
- - {Recipe: Generate to File Without Headers}[#label-Recipe-3A+Generate+to+File+Without+Headers]
- - {Generating to IO an Stream}[#label-Generating+to+an+IO+Stream]
- - {Recipe: Generate to IO Stream with Headers}[#label-Recipe-3A+Generate+to+IO+Stream+with+Headers]
- - {Recipe: Generate to IO Stream Without Headers}[#label-Recipe-3A+Generate+to+IO+Stream+Without+Headers]
-- {Converting Fields}[#label-Converting+Fields]
- - {Recipe: Filter Generated Field Strings}[#label-Recipe-3A+Filter+Generated+Field+Strings]
- - {Recipe: Specify Multiple Write Converters}[#label-Recipe-3A+Specify+Multiple+Write+Converters]
-- {RFC 4180 Compliance}[#label-RFC+4180+Compliance]
- - {Row Separator}[#label-Row+Separator]
- - {Recipe: Generate Compliant Row Separator}[#label-Recipe-3A+Generate+Compliant+Row+Separator]
- - {Recipe: Generate Non-Compliant Row Separator}[#label-Recipe-3A+Generate+Non-Compliant+Row+Separator]
- - {Column Separator}[#label-Column+Separator]
- - {Recipe: Generate Compliant Column Separator}[#label-Recipe-3A+Generate+Compliant+Column+Separator]
- - {Recipe: Generate Non-Compliant Column Separator}[#label-Recipe-3A+Generate+Non-Compliant+Column+Separator]
- - {Quote Character}[#label-Quote+Character]
- - {Recipe: Generate Compliant Quote Character}[#label-Recipe-3A+Generate+Compliant+Quote+Character]
- - {Recipe: Generate Non-Compliant Quote Character}[#label-Recipe-3A+Generate+Non-Compliant+Quote+Character]
-
-=== Output Formats
-
-You can generate \CSV output to a \String, to a \File (via its path), or to an \IO stream.
-
-==== Generating to a \String
-
-You can generate \CSV output to a \String, with or without headers.
-
-===== Recipe: Generate to \String with Headers
-
-Use class method CSV.generate with option +headers+ to generate to a \String.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- output_string = CSV.generate('', headers: ['Name', 'Value'], write_headers: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate to \String Without Headers
-
-Use class method CSV.generate without option +headers+ to generate to a \String.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- output_string = CSV.generate do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo,0\nBar,1\nBaz,2\n"
-
-==== Generating to a \File
-
-You can generate /CSV data to a \File, with or without headers.
-
-===== Recipe: Generate to \File with Headers
-
-Use class method CSV.open with option +headers+ generate to a \File.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- path = 't.csv'
- CSV.open(path, 'w', headers: ['Name', 'Value'], write_headers: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate to \File Without Headers
-
-Use class method CSV.open without option +headers+ to generate to a \File.
-
-This example uses method CSV#<< to append the rows
-that are to be generated:
- path = 't.csv'
- CSV.open(path, 'w') do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"
-
-==== Generating to an \IO Stream
-
-You can generate \CSV data to an \IO stream, with or without headers.
-
-==== Recipe: Generate to \IO Stream with Headers
-
-Use class method CSV.new with option +headers+ to generate \CSV data to an \IO stream:
- path = 't.csv'
- File.open(path, 'w') do |file|
- csv = CSV.new(file, headers: ['Name', 'Value'], write_headers: true)
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate to \IO Stream Without Headers
-
-Use class method CSV.new without option +headers+ to generate \CSV data to an \IO stream:
- path = 't.csv'
- File.open(path, 'w') do |file|
- csv = CSV.new(file)
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"
-
-=== Converting Fields
-
-You can use _write_ _converters_ to convert fields when generating \CSV.
-
-==== Recipe: Filter Generated Field Strings
-
-Use option <tt>:write_converters</tt> and a custom converter to convert field values when generating \CSV.
-
-This example defines and uses a custom write converter to strip whitespace from generated fields:
- strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
- output_string = CSV.generate(write_converters: strip_converter) do |csv|
- csv << [' foo ', 0]
- csv << [' bar ', 1]
- csv << [' baz ', 2]
- end
- output_string # => "foo,0\nbar,1\nbaz,2\n"
-
-==== Recipe: Specify Multiple Write Converters
-
-Use option <tt>:write_converters</tt> and multiple custom converters
-to convert field values when generating \CSV.
-
-This example defines and uses two custom write converters to strip and upcase generated fields:
- strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
- upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
- converters = [strip_converter, upcase_converter]
- output_string = CSV.generate(write_converters: converters) do |csv|
- csv << [' foo ', 0]
- csv << [' bar ', 1]
- csv << [' baz ', 2]
- end
- output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
-
-=== RFC 4180 Compliance
-
-By default, \CSV generates data that is compliant with
-{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
-with respect to:
-- Column separator.
-- Quote character.
-
-==== Row Separator
-
-RFC 4180 specifies the row separator CRLF (Ruby <tt>"\r\n"</tt>).
-
-===== Recipe: Generate Compliant Row Separator
-
-For strict compliance, use option +:row_sep+ to specify row separator <tt>"\r\n"</tt>:
- output_string = CSV.generate('', row_sep: "\r\n") do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo,0\r\nBar,1\r\nBaz,2\r\n"
-
-===== Recipe: Generate Non-Compliant Row Separator
-
-For data with non-compliant row separators, use option +:row_sep+ with a different value:
-This example source uses semicolon (<tt>";'</tt>) as its row separator:
- output_string = CSV.generate('', row_sep: ";") do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo,0;Bar,1;Baz,2;"
-
-==== Column Separator
-
-RFC 4180 specifies column separator COMMA (Ruby <tt>","</tt>).
-
-===== Recipe: Generate Compliant Column Separator
-
-Because the \CSV default comma separator is <tt>","</tt>,
-you need not specify option +:col_sep+ for compliant data:
- output_string = CSV.generate('') do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo,0\nBar,1\nBaz,2\n"
-
-===== Recipe: Generate Non-Compliant Column Separator
-
-For data with non-compliant column separators, use option +:col_sep+.
-This example source uses TAB (<tt>"\t"</tt>) as its column separator:
- output_string = CSV.generate('', col_sep: "\t") do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "Foo\t0\nBar\t1\nBaz\t2\n"
-
-==== Quote Character
-
-RFC 4180 specifies quote character DQUOTE (Ruby <tt>"\""</tt>).
-
-===== Recipe: Generate Compliant Quote Character
-
-Because the \CSV default quote character is <tt>"\""</tt>,
-you need not specify option +:quote_char+ for compliant data:
- output_string = CSV.generate('', force_quotes: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n"
-
-===== Recipe: Generate Non-Compliant Quote Character
-
-For data with non-compliant quote characters, use option +:quote_char+.
-This example source uses SQUOTE (<tt>"'"</tt>) as its quote character:
- output_string = CSV.generate('', quote_char: "'", force_quotes: true) do |csv|
- csv << ['Foo', 0]
- csv << ['Bar', 1]
- csv << ['Baz', 2]
- end
- output_string # => "'Foo','0'\n'Bar','1'\n'Baz','2'\n"
diff --git a/doc/csv/recipes/parsing.rdoc b/doc/csv/recipes/parsing.rdoc
deleted file mode 100644
index 1b7071e33f..0000000000
--- a/doc/csv/recipes/parsing.rdoc
+++ /dev/null
@@ -1,545 +0,0 @@
-== 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:
- require 'csv'
-
-=== Contents
-
-- {Source Formats}[#label-Source+Formats]
- - {Parsing from a String}[#label-Parsing+from+a+String]
- - {Recipe: Parse from String with Headers}[#label-Recipe-3A+Parse+from+String+with+Headers]
- - {Recipe: Parse from String Without Headers}[#label-Recipe-3A+Parse+from+String+Without+Headers]
- - {Parsing from a File}[#label-Parsing+from+a+File]
- - {Recipe: Parse from File with Headers}[#label-Recipe-3A+Parse+from+File+with+Headers]
- - {Recipe: Parse from File Without Headers}[#label-Recipe-3A+Parse+from+File+Without+Headers]
- - {Parsing from an IO Stream}[#label-Parsing+from+an+IO+Stream]
- - {Recipe: Parse from IO Stream with Headers}[#label-Recipe-3A+Parse+from+IO+Stream+with+Headers]
- - {Recipe: Parse from IO Stream Without Headers}[#label-Recipe-3A+Parse+from+IO+Stream+Without+Headers]
-- {RFC 4180 Compliance}[#label-RFC+4180+Compliance]
- - {Row Separator}[#label-Row+Separator]
- - {Recipe: Handle Compliant Row Separator}[#label-Recipe-3A+Handle+Compliant+Row+Separator]
- - {Recipe: Handle Non-Compliant Row Separator}[#label-Recipe-3A+Handle+Non-Compliant+Row+Separator]
- - {Column Separator}[#label-Column+Separator]
- - {Recipe: Handle Compliant Column Separator}[#label-Recipe-3A+Handle+Compliant+Column+Separator]
- - {Recipe: Handle Non-Compliant Column Separator}[#label-Recipe-3A+Handle+Non-Compliant+Column+Separator]
- - {Quote Character}[#label-Quote+Character]
- - {Recipe: Handle Compliant Quote Character}[#label-Recipe-3A+Handle+Compliant+Quote+Character]
- - {Recipe: Handle Non-Compliant Quote Character}[#label-Recipe-3A+Handle+Non-Compliant+Quote+Character]
- - {Recipe: Allow Liberal Parsing}[#label-Recipe-3A+Allow+Liberal+Parsing]
-- {Special Handling}[#label-Special+Handling]
- - {Special Line Handling}[#label-Special+Line+Handling]
- - {Recipe: Ignore Blank Lines}[#label-Recipe-3A+Ignore+Blank+Lines]
- - {Recipe: Ignore Selected Lines}[#label-Recipe-3A+Ignore+Selected+Lines]
- - {Special Field Handling}[#label-Special+Field+Handling]
- - {Recipe: Strip Fields}[#label-Recipe-3A+Strip+Fields]
- - {Recipe: Handle Null Fields}[#label-Recipe-3A+Handle+Null+Fields]
- - {Recipe: Handle Empty Fields}[#label-Recipe-3A+Handle+Empty+Fields]
-- {Converting Fields}[#label-Converting+Fields]
- - {Converting Fields to Objects}[#label-Converting+Fields+to+Objects]
- - {Recipe: Convert Fields to Integers}[#label-Recipe-3A+Convert+Fields+to+Integers]
- - {Recipe: Convert Fields to Floats}[#label-Recipe-3A+Convert+Fields+to+Floats]
- - {Recipe: Convert Fields to Numerics}[#label-Recipe-3A+Convert+Fields+to+Numerics]
- - {Recipe: Convert Fields to Dates}[#label-Recipe-3A+Convert+Fields+to+Dates]
- - {Recipe: Convert Fields to DateTimes}[#label-Recipe-3A+Convert+Fields+to+DateTimes]
- - {Recipe: Convert Assorted Fields to Objects}[#label-Recipe-3A+Convert+Assorted+Fields+to+Objects]
- - {Recipe: Convert Fields to Other Objects}[#label-Recipe-3A+Convert+Fields+to+Other+Objects]
- - {Recipe: Filter Field Strings}[#label-Recipe-3A+Filter+Field+Strings]
- - {Recipe: Register Field Converters}[#label-Recipe-3A+Register+Field+Converters]
- - {Using Multiple Field Converters}[#label-Using+Multiple+Field+Converters]
- - {Recipe: Specify Multiple Field Converters in Option :converters}[#label-Recipe-3A+Specify+Multiple+Field+Converters+in+Option+-3Aconverters]
- - {Recipe: Specify Multiple Field Converters in a Custom Converter List}[#label-Recipe-3A+Specify+Multiple+Field+Converters+in+a+Custom+Converter+List]
-- {Converting Headers}[#label-Converting+Headers]
- - {Recipe: Convert Headers to Lowercase}[#label-Recipe-3A+Convert+Headers+to+Lowercase]
- - {Recipe: Convert Headers to Symbols}[#label-Recipe-3A+Convert+Headers+to+Symbols]
- - {Recipe: Filter Header Strings}[#label-Recipe-3A+Filter+Header+Strings]
- - {Recipe: Register Header Converters}[#label-Recipe-3A+Register+Header+Converters]
- - {Using Multiple Header Converters}[#label-Using+Multiple+Header+Converters]
- - {Recipe: Specify Multiple Header Converters in Option :header_converters}[#label-Recipe-3A+Specify+Multiple+Header+Converters+in+Option+-3Aheader_converters]
- - {Recipe: Specify Multiple Header Converters in a Custom Header Converter List}[#label-Recipe-3A+Specify+Multiple+Header+Converters+in+a+Custom+Header+Converter+List]
-- {Diagnostics}[#label-Diagnostics]
- - {Recipe: Capture Unconverted Fields}[#label-Recipe-3A+Capture+Unconverted+Fields]
- - {Recipe: Capture Field Info}[#label-Recipe-3A+Capture+Field+Info]
-
-=== Source Formats
-
-You can parse \CSV data from a \String, from a \File (via its path), or from an \IO stream.
-
-==== Parsing from a \String
-
-You can parse \CSV data from a \String, with or without headers.
-
-===== Recipe: Parse from \String with Headers
-
-Use class method CSV.parse with option +headers+ to read a source \String all at once
-(may have memory resource implications):
- string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- CSV.parse(string, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
-
-Use instance method CSV#each with option +headers+ to read a source \String one row at a time:
- CSV.new(string, headers: true).each do |row|
- p row
- end
-Output:
- #<CSV::Row "Name":"foo" "Value":"0">
- #<CSV::Row "Name":"bar" "Value":"1">
- #<CSV::Row "Name":"baz" "Value":"2">
-
-===== Recipe: Parse from \String Without Headers
-
-Use class method CSV.parse without option +headers+ to read a source \String all at once
-(may have memory resource implications):
- string = "foo,0\nbar,1\nbaz,2\n"
- CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Use instance method CSV#each without option +headers+ to read a source \String one row at a time:
- CSV.new(string).each do |row|
- p row
- end
-Output:
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-==== Parsing from a \File
-
-You can parse \CSV data from a \File, with or without headers.
-
-===== Recipe: Parse from \File with Headers
-
-Use instance method CSV#read with option +headers+ to read a file all at once:
- string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
-
-Use class method CSV.foreach with option +headers+ to read one row at a time:
- CSV.foreach(path, headers: true) do |row|
- p row
- end
-Output:
- #<CSV::Row "Name":"foo" "Value":"0">
- #<CSV::Row "Name":"bar" "Value":"1">
- #<CSV::Row "Name":"baz" "Value":"2">
-
-===== Recipe: Parse from \File Without Headers
-
-Use class method CSV.read without option +headers+ to read a file all at once:
- string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Use class method CSV.foreach without option +headers+ to read one row at a time:
- CSV.foreach(path) do |row|
- p row
- end
-Output:
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-==== Parsing from an \IO Stream
-
-You can parse \CSV data from an \IO stream, with or without headers.
-
-===== Recipe: Parse from \IO Stream with Headers
-
-Use class method CSV.parse with option +headers+ to read an \IO stream all at once:
- string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- File.open(path) do |file|
- CSV.parse(file, headers: true)
- end # => #<CSV::Table mode:col_or_row row_count:4>
-
-Use class method CSV.foreach with option +headers+ to read one row at a time:
- File.open(path) do |file|
- CSV.foreach(file, headers: true) do |row|
- p row
- end
- end
-Output:
- #<CSV::Row "Name":"foo" "Value":"0">
- #<CSV::Row "Name":"bar" "Value":"1">
- #<CSV::Row "Name":"baz" "Value":"2">
-
-===== Recipe: Parse from \IO Stream Without Headers
-
-Use class method CSV.parse without option +headers+ to read an \IO stream all at once:
- string = "foo,0\nbar,1\nbaz,2\n"
- path = 't.csv'
- File.write(path, string)
- File.open(path) do |file|
- CSV.parse(file)
- end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-Use class method CSV.foreach without option +headers+ to read one row at a time:
- File.open(path) do |file|
- CSV.foreach(file) do |row|
- p row
- end
- end
-Output:
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-=== RFC 4180 Compliance
-
-By default, \CSV parses data that is compliant with
-{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
-with respect to:
-- Row separator.
-- Column separator.
-- Quote character.
-
-==== Row Separator
-
-RFC 4180 specifies the row separator CRLF (Ruby <tt>"\r\n"</tt>).
-
-Although the \CSV default row separator is <tt>"\n"</tt>,
-the parser also by default handles row separator <tt>"\r"</tt> and the RFC-compliant <tt>"\r\n"</tt>.
-
-===== Recipe: Handle Compliant Row Separator
-
-For strict compliance, use option +:row_sep+ to specify row separator <tt>"\r\n"</tt>,
-which allows the compliant row separator:
- source = "foo,1\r\nbar,1\r\nbaz,2\r\n"
- CSV.parse(source, row_sep: "\r\n") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-But rejects other row separators:
- source = "foo,1\nbar,1\nbaz,2\n"
- CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError
- source = "foo,1\rbar,1\rbaz,2\r"
- CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError
- source = "foo,1\n\rbar,1\n\rbaz,2\n\r"
- CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError
-
-===== Recipe: Handle Non-Compliant Row Separator
-
-For data with non-compliant row separators, use option +:row_sep+.
-This example source uses semicolon (<tt>";"</tt>) as its row separator:
- source = "foo,1;bar,1;baz,2;"
- CSV.parse(source, row_sep: ';') # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-==== Column Separator
-
-RFC 4180 specifies column separator COMMA (Ruby <tt>","</tt>).
-
-===== Recipe: Handle Compliant Column Separator
-
-Because the \CSV default comma separator is ',',
-you need not specify option +:col_sep+ for compliant data:
- source = "foo,1\nbar,1\nbaz,2\n"
- CSV.parse(source) # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-===== Recipe: Handle Non-Compliant Column Separator
-
-For data with non-compliant column separators, use option +:col_sep+.
-This example source uses TAB (<tt>"\t"</tt>) as its column separator:
- source = "foo,1\tbar,1\tbaz,2"
- CSV.parse(source, col_sep: "\t") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-==== Quote Character
-
-RFC 4180 specifies quote character DQUOTE (Ruby <tt>"\""</tt>).
-
-===== Recipe: Handle Compliant Quote Character
-
-Because the \CSV default quote character is <tt>"\""</tt>,
-you need not specify option +:quote_char+ for compliant data:
- source = "\"foo\",\"1\"\n\"bar\",\"1\"\n\"baz\",\"2\"\n"
- CSV.parse(source) # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-===== Recipe: Handle Non-Compliant Quote Character
-
-For data with non-compliant quote characters, use option +:quote_char+.
-This example source uses SQUOTE (<tt>"'"</tt>) as its quote character:
- source = "'foo','1'\n'bar','1'\n'baz','2'\n"
- CSV.parse(source, quote_char: "'") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]]
-
-==== Recipe: Allow Liberal Parsing
-
-Use option +:liberal_parsing+ to specify that \CSV should
-attempt to parse input not conformant with RFC 4180, such as double quotes in unquoted fields:
- source = 'is,this "three, or four",fields'
- CSV.parse(source) # Raises MalformedCSVError
- CSV.parse(source, liberal_parsing: true) # => [["is", "this \"three", " or four\"", "fields"]]
-
-=== Special Handling
-
-You can use parsing options to specify special handling for certain lines and fields.
-
-==== Special Line Handling
-
-Use parsing options to specify special handling for blank lines, or for other selected lines.
-
-===== Recipe: Ignore Blank Lines
-
-Use option +:skip_blanks+ to ignore blank lines:
- source = <<-EOT
- foo,0
-
- bar,1
- baz,2
-
- ,
- EOT
- parsed = CSV.parse(source, skip_blanks: true)
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
-
-===== Recipe: Ignore Selected Lines
-
-Use option +:skip_lines+ to ignore selected lines.
- source = <<-EOT
- # Comment
- foo,0
- bar,1
- baz,2
- # Another comment
- EOT
- parsed = CSV.parse(source, skip_lines: /^#/)
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-
-==== Special Field Handling
-
-Use parsing options to specify special handling for certain field values.
-
-===== Recipe: Strip Fields
-
-Use option +:strip+ to strip parsed field values:
- CSV.parse_line(' a , b ', strip: true) # => ["a", "b"]
-
-===== Recipe: Handle Null Fields
-
-Use option +:nil_value+ to specify a value that will replace each field
-that is null (no text):
- CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
-
-===== Recipe: Handle Empty Fields
-
-Use option +:empty_value+ to specify a value that will replace each field
-that is empty (\String of length 0);
- CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
-
-=== Converting Fields
-
-You can use field converters to change parsed \String fields into other objects,
-or to otherwise modify the \String fields.
-
-==== Converting Fields to Objects
-
-Use field converters to change parsed \String objects into other, more specific, objects.
-
-There are built-in field converters for converting to objects of certain classes:
-- \Float
-- \Integer
-- \Date
-- \DateTime
-
-Other built-in field converters include:
-- +:numeric+: converts to \Integer and \Float.
-- +:all+: converts to \DateTime, \Integer, \Float.
-
-You can also define field converters to convert to objects of other classes.
-
-===== Recipe: Convert Fields to Integers
-
-Convert fields to \Integer objects using built-in converter +:integer+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: :integer)
- parsed.map {|row| row['Value'].class} # => [Integer, Integer, Integer]
-
-===== Recipe: Convert Fields to Floats
-
-Convert fields to \Float objects using built-in converter +:float+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: :float)
- parsed.map {|row| row['Value'].class} # => [Float, Float, Float]
-
-===== Recipe: Convert Fields to Numerics
-
-Convert fields to \Integer and \Float objects using built-in converter +:numeric+:
- source = "Name,Value\nfoo,0\nbar,1.1\nbaz,2.2\n"
- parsed = CSV.parse(source, headers: true, converters: :numeric)
- parsed.map {|row| row['Value'].class} # => [Integer, Float, Float]
-
-===== Recipe: Convert Fields to Dates
-
-Convert fields to \Date objects using built-in converter +:date+:
- source = "Name,Date\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2001-02-03\n"
- parsed = CSV.parse(source, headers: true, converters: :date)
- parsed.map {|row| row['Date'].class} # => [Date, Date, Date]
-
-===== Recipe: Convert Fields to DateTimes
-
-Convert fields to \DateTime objects using built-in converter +:date_time+:
- source = "Name,DateTime\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2020-05-07T14:59:00-05:00\n"
- parsed = CSV.parse(source, headers: true, converters: :date_time)
- parsed.map {|row| row['DateTime'].class} # => [DateTime, DateTime, DateTime]
-
-===== Recipe: Convert Assorted Fields to Objects
-
-Convert assorted fields to objects using built-in converter +:all+:
- source = "Type,Value\nInteger,0\nFloat,1.0\nDateTime,2001-02-04\n"
- parsed = CSV.parse(source, headers: true, converters: :all)
- parsed.map {|row| row['Value'].class} # => [Integer, Float, DateTime]
-
-===== Recipe: Convert Fields to Other Objects
-
-Define a custom field converter to convert \String fields into other objects.
-This example defines and uses a custom field converter
-that converts each column-1 value to a \Rational object:
- rational_converter = proc do |field, field_context|
- field_context.index == 1 ? field.to_r : field
- end
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: rational_converter)
- parsed.map {|row| row['Value'].class} # => [Rational, Rational, Rational]
-
-==== Recipe: Filter Field Strings
-
-Define a custom field converter to modify \String fields.
-This example defines and uses a custom field converter
-that strips whitespace from each field value:
- strip_converter = proc {|field| field.strip }
- source = "Name,Value\n foo , 0 \n bar , 1 \n baz , 2 \n"
- parsed = CSV.parse(source, headers: true, converters: strip_converter)
- parsed['Name'] # => ["foo", "bar", "baz"]
- parsed['Value'] # => ["0", "1", "2"]
-
-==== Recipe: Register Field Converters
-
-Register a custom field converter, assigning it a name;
-then refer to the converter by its name:
- rational_converter = proc do |field, field_context|
- field_context.index == 1 ? field.to_r : field
- end
- CSV::Converters[:rational] = rational_converter
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, converters: :rational)
- parsed['Value'] # => [(0/1), (1/1), (2/1)]
-
-==== Using Multiple Field Converters
-
-You can use multiple field converters in either of these ways:
-- Specify converters in option +:converters+.
-- Specify converters in a custom converter list.
-
-===== Recipe: Specify Multiple Field Converters in Option +:converters+
-
-Apply multiple field converters by specifying them in option +:converters+:
- source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
- parsed = CSV.parse(source, headers: true, converters: [:integer, :float])
- parsed['Value'] # => [0, 1.0, 2.0]
-
-===== Recipe: Specify Multiple Field Converters in a Custom Converter List
-
-Apply multiple field converters by defining and registering a custom converter list:
- strip_converter = proc {|field| field.strip }
- CSV::Converters[:strip] = strip_converter
- CSV::Converters[:my_converters] = [:integer, :float, :strip]
- source = "Name,Value\n foo , 0 \n bar , 1.0 \n baz , 2.0 \n"
- parsed = CSV.parse(source, headers: true, converters: :my_converters)
- parsed['Name'] # => ["foo", "bar", "baz"]
- parsed['Value'] # => [0, 1.0, 2.0]
-
-=== Converting Headers
-
-You can use header converters to modify parsed \String headers.
-
-Built-in header converters include:
-- +:symbol+: converts \String header to \Symbol.
-- +:downcase+: converts \String header to lowercase.
-
-You can also define header converters to otherwise modify header \Strings.
-
-==== Recipe: Convert Headers to Lowercase
-
-Convert headers to lowercase using built-in converter +:downcase+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: :downcase)
- parsed.headers # => ["name", "value"]
-
-==== Recipe: Convert Headers to Symbols
-
-Convert headers to downcased Symbols using built-in converter +:symbol+:
- source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: :symbol)
- parsed.headers # => [:name, :value]
- parsed.headers.map {|header| header.class} # => [Symbol, Symbol]
-
-==== Recipe: Filter Header Strings
-
-Define a custom header converter to modify \String fields.
-This example defines and uses a custom header converter
-that capitalizes each header \String:
- capitalize_converter = proc {|header| header.capitalize }
- source = "NAME,VALUE\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: capitalize_converter)
- parsed.headers # => ["Name", "Value"]
-
-==== Recipe: Register Header Converters
-
-Register a custom header converter, assigning it a name;
-then refer to the converter by its name:
- capitalize_converter = proc {|header| header.capitalize }
- CSV::HeaderConverters[:capitalize] = capitalize_converter
- source = "NAME,VALUE\nfoo,0\nbar,1\nbaz,2\n"
- parsed = CSV.parse(source, headers: true, header_converters: :capitalize)
- parsed.headers # => ["Name", "Value"]
-
-==== Using Multiple Header Converters
-
-You can use multiple header converters in either of these ways:
-- Specify header converters in option +:header_converters+.
-- Specify header converters in a custom header converter list.
-
-===== Recipe: Specify Multiple Header Converters in Option :header_converters
-
-Apply multiple header converters by specifying them in option +:header_converters+:
- source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
- parsed = CSV.parse(source, headers: true, header_converters: [:downcase, :symbol])
- parsed.headers # => [:name, :value]
-
-===== Recipe: Specify Multiple Header Converters in a Custom Header Converter List
-
-Apply multiple header converters by defining and registering a custom header converter list:
- CSV::HeaderConverters[:my_header_converters] = [:symbol, :downcase]
- source = "NAME,VALUE\nfoo,0\nbar,1.0\nbaz,2.0\n"
- parsed = CSV.parse(source, headers: true, header_converters: :my_header_converters)
- parsed.headers # => [:name, :value]
-
-=== Diagnostics
-
-==== Recipe: Capture Unconverted Fields
-
-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.each {|row| p row.unconverted_fields }
-Output:
- ["Name", "Value"]
- ["foo", "0"]
- ["bar", "1"]
- ["baz", "2"]
-
-==== Recipe: Capture Field Info
-
-To capture field info in a custom converter, accept two block arguments.
-The first is the field value; the second is a +CSV::FieldInfo+ object:
- strip_converter = proc {|field, field_info| p field_info; field.strip }
- source = " foo , 0 \n bar , 1 \n baz , 2 \n"
- parsed = CSV.parse(source, converters: strip_converter)
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
-Output:
- #<struct CSV::FieldInfo index=0, line=1, header=nil>
- #<struct CSV::FieldInfo index=1, line=1, header=nil>
- #<struct CSV::FieldInfo index=0, line=2, header=nil>
- #<struct CSV::FieldInfo index=1, line=2, header=nil>
- #<struct CSV::FieldInfo index=0, line=3, header=nil>
- #<struct CSV::FieldInfo index=1, line=3, header=nil>
diff --git a/doc/csv/recipes/recipes.rdoc b/doc/csv/recipes/recipes.rdoc
deleted file mode 100644
index 9bf7885b1e..0000000000
--- a/doc/csv/recipes/recipes.rdoc
+++ /dev/null
@@ -1,6 +0,0 @@
-== Recipes for \CSV
-
-The recipes are specific code examples for specific tasks. 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/date/calendars.rdoc b/doc/date/calendars.rdoc
deleted file mode 100644
index 4e6fd8334b..0000000000
--- a/doc/date/calendars.rdoc
+++ /dev/null
@@ -1,62 +0,0 @@
-== Julian and Gregorian Calendars
-
-The difference between the
-{Julian calendar}[https://en.wikipedia.org/wiki/Julian_calendar]
-and the
-{Gregorian calendar}[https://en.wikipedia.org/wiki/Gregorian_calendar]
-may matter to your program if it uses dates before the switchovers.
-
-- October 15, 1582.
-- September 14, 1752.
-
-A date will be different in the two calendars, in general.
-
-=== Different switchover dates
-
-The reasons for the difference are religious/political histories.
-
-- On October 15, 1582, several countries changed
- from the Julian calendar to the Gregorian calendar;
- these included Italy, Poland, Portugal, and Spain.
- Other countries in the Western world retained the Julian calendar.
-- On September 14, 1752, most of the British empire
- changed from the Julian calendar to the Gregorian calendar.
-
-When your code uses a date before these switchover dates,
-it will matter whether it considers the switchover date
-to be the earlier date or the later date (or neither).
-
-See also {a concrete example here}[rdoc-ref:DateTime@When+should+you+use+DateTime+and+when+should+you+use+Time-3F].
-
-=== Argument +start+
-
-Certain methods in class \Date handle differences in the
-{Julian and Gregorian calendars}[rdoc-ref:date/calendars.rdoc@Julian+and+Gregorian+Calendars]
-by accepting an optional argument +start+, whose value may be:
-
-- Date::ITALY (the default): the created date is Julian
- if before October 15, 1582, Gregorian otherwise:
-
- d = Date.new(1582, 10, 15)
- d.prev_day.julian? # => true
- d.julian? # => false
- d.gregorian? # => true
-
-- Date::ENGLAND: the created date is Julian if before September 14, 1752,
- Gregorian otherwise:
-
- d = Date.new(1752, 9, 14, Date::ENGLAND)
- d.prev_day.julian? # => true
- d.julian? # => false
- d.gregorian? # => true
-
-- Date::JULIAN: the created date is Julian regardless of its value:
-
- d = Date.new(1582, 10, 15, Date::JULIAN)
- d.julian? # => true
-
-- Date::GREGORIAN: the created date is Gregorian regardless of its value:
-
- d = Date.new(1752, 9, 14, Date::GREGORIAN)
- d.prev_day.gregorian? # => true
-
diff --git a/doc/distribution.md b/doc/distribution.md
deleted file mode 100644
index 5a4d51da6f..0000000000
--- a/doc/distribution.md
+++ /dev/null
@@ -1,48 +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:
-
-```console
-$ ./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/distribution/distribution.md b/doc/distribution/distribution.md
new file mode 100644
index 0000000000..e0e4ad354b
--- /dev/null
+++ b/doc/distribution/distribution.md
@@ -0,0 +1,48 @@
+# 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 cryptographically 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:
+
+```console
+$ ./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/distribution/windows.md b/doc/distribution/windows.md
new file mode 100644
index 0000000000..26a727d7ad
--- /dev/null
+++ b/doc/distribution/windows.md
@@ -0,0 +1,304 @@
+# 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:
+
+```batch
+ridk install
+ridk enable ucrt64
+
+pacman -S --needed %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-libffi
+
+mkdir c:\work\ruby
+cd /d c:\work\ruby
+
+git clone https://github.com/ruby/ruby src
+
+sh ./src/autogen.sh
+
+mkdir build
+cd build
+sh ../src/configure -C --disable-install-doc
+make
+```
+
+or in MSYS2 `bash` like:
+
+```bash
+ridk install
+ridk enable ucrt64
+bash
+
+pacman -S --needed $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-libffi
+
+mkdir /c/work/ruby
+cd /c/work/ruby
+
+git clone https://github.com/ruby/ruby src
+
+./src/autogen.sh
+cd build
+../src/configure -C --disable-install-doc
+make
+```
+
+If you have other MSYS2 environment via other package manager like `scoop`, you need to specify `$MINGW_PACKAGE_PREFIX` is `mingw-w64-ucrt-x86_64`.
+And you need to add `--with-opt-dir` option to `configure` command like:
+
+```batch
+sh ../../ruby/configure -C --disable-install-doc --with-opt-dir=C:\Users\username\scoop\apps\msys2\current\ucrt64
+```
+
+[RubyInstaller-Devkit]: https://rubyinstaller.org/
+[git-for-windows]: https://gitforwindows.org/
+[VSCode]: https://code.visualstudio.com/
+
+## Building Ruby using Visual C++
+
+### Requirement
+
+1. Windows 10/Windows Server 2016 or later.
+
+2. Visual C++ 14.0 (2015) or later.
+
+ **Note** if you want to build x64 version, use native compiler for
+ x64.
+
+ The minimum requirement is here:
+ * VC++/MSVC on VS 2017/2019/2022 version build tools.
+ * Windows 10/11 SDK
+
+ You can install Visual Studio Build Tools with `winget`.
+ `win32\install-buildtools.cmd` is a batch file to install the
+ minimum requirements excluding the IDE etc.
+
+3. Please set environment variable `INCLUDE`, `LIB`, `PATH` to run
+ required commands properly from the command line. These are set
+ properly by `vsdevcmd.bat` or `vcvarall*.bat` usually. You can run
+ the following command to set them in your command line.
+
+ To native build:
+
+ ```
+ cmd /k win32\vssetup.cmd
+ ```
+
+ To cross build arm64 binary:
+
+ ```
+ cmd /k win32\vssetup.cmd -arch=arm64
+ ```
+
+ To cross build x64 binary:
+
+ ```
+ cmd /k win32\vssetup.cmd -arch=x64
+ ```
+
+ This batch file is a wrapper of `vsdevcmd.bat` and options are
+ passed to it as-is. `win32\vssetup.cmd -help` for other command
+ line options.
+
+ **Note** building ruby requires following commands.
+
+ * `nmake`
+ * `cl`
+ * `ml`
+ * `lib`
+ * `dumpbin`
+
+4. If you want to build from GIT source, following commands are required.
+ * `git`
+ * `ruby` 3.1 or later
+
+ You can use [scoop](https://scoop.sh/) to install them like:
+
+ ```batch
+ scoop install git ruby
+ ```
+
+ The windows version of `git` configured with `autocrlf` is `true`. The Ruby
+ test suite may fail with `autocrlf` set to `true`. You can set it to `false`
+ like:
+
+ ```batch
+ git config --global core.autocrlf false
+ ```
+
+5. You need to install required libraries using [vcpkg](https://vcpkg.io/) on
+ directory of ruby repository like:
+
+ ```batch
+ vcpkg --triplet x64-windows install
+ ```
+
+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` .
+
+2. If you want to append to the executable and DLL file names,
+ specify `--program-prefix` and `--program-suffix`, like
+ `win32\configure.bat --program-suffix=-$(MAJOR)$(MINOR)`.
+
+ Also, the `--install-name` and `--so-name` options specify the
+ exact base names of the executable and DLL files, respectively,
+ like `win32\configure.bat --install-name=$(RUBY_BASE_NAME)-$(MAJOR)$(MINOR)`.
+
+ By default, the name for the executable without a console window
+ is generated from the _RUBY_INSTALL_NAME_ specified as above by
+ replacing `ruby` with `rubyw`. If you want to make it different
+ more, modify _RUBYW_INSTALL_NAME_ directly in the Makefile.
+
+3. You need specify vcpkg directory to use `--with-opt-dir`
+ option like `win32\configure.bat --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 prepare-vcpkg` with administrator privilege if you need to
+ copy vcpkg installed libraries like `libssl-3-x64.dll` to the build directory.
+
+7. Run `nmake check`
+
+8. 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
+ ```
+
+ ```batch
+ 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
+ ```
+
+ ```batch
+ 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
+ ```
+
+ ```batch
+ 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
+ ```
+
+ ```batch
+ 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`.
+
+### Dependency management
+
+Ruby uses [vcpkg](https://vcpkg.io/) to manage dependencies on mswin platform.
+
+You can update and install it under the build directory like:
+
+```batch
+nmake update-vcpkg # Update baseline version of vcpkg
+nmake install-vcpkg # Install vcpkg from build directory
+```
+
+
+## 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/encodings.rdoc b/doc/encodings.rdoc
deleted file mode 100644
index eaee2efd62..0000000000
--- a/doc/encodings.rdoc
+++ /dev/null
@@ -1,482 +0,0 @@
-= Encodings
-
-== The Basics
-
-A {character encoding}[https://en.wikipedia.org/wiki/Character_encoding],
-often shortened to _encoding_, is a mapping between:
-
-- A sequence of 8-bit bytes (each byte in the range <tt>0..255</tt>).
-- Characters in a specific character set.
-
-Some character sets contain only 1-byte characters;
-{US-ASCII}[https://en.wikipedia.org/wiki/ASCII], for example, has 256 1-byte characters.
-This string, encoded in US-ASCII, has six characters that are stored as six bytes:
-
- s = 'Hello!'.encode(Encoding::US_ASCII) # => "Hello!"
- s.encoding # => #<Encoding:US-ASCII>
- s.bytes # => [72, 101, 108, 108, 111, 33]
-
-Other encodings may involve multi-byte characters.
-{UTF-8}[https://en.wikipedia.org/wiki/UTF-8], for example,
-encodes more than one million characters, encoding each in one to four bytes.
-The lowest-valued of these characters correspond to ASCII characters,
-and so are 1-byte characters:
-
- s = 'Hello!' # => "Hello!"
- s.bytes # => [72, 101, 108, 108, 111, 33]
-
-Other characters, such as the Euro symbol, are multi-byte:
-
- s = "\u20ac" # => "€"
- s.bytes # => [226, 130, 172]
-
-== The \Encoding Class
-
-=== \Encoding Objects
-
-Ruby encodings are defined by constants in class \Encoding.
-There can be only one instance of \Encoding for each of these constants.
-Method Encoding.list returns an array of \Encoding objects (one for each constant):
-
- Encoding.list.size # => 103
- Encoding.list.first.class # => Encoding
- Encoding.list.take(3)
- # => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]
-
-=== Names and Aliases
-
-Method Encoding#name returns the name of an \Encoding:
-
- Encoding::ASCII_8BIT.name # => "ASCII-8BIT"
- Encoding::WINDOWS_31J.name # => "Windows-31J"
-
-An \Encoding object has zero or more aliases;
-method Encoding#names returns an array containing the name and all aliases:
-
- Encoding::ASCII_8BIT.names
- # => ["ASCII-8BIT", "BINARY"]
- Encoding::WINDOWS_31J.names
- #=> ["Windows-31J", "CP932", "csWindows31J", "SJIS", "PCK"]
-
-Method Encoding.aliases returns a hash of all alias/name pairs:
-
- Encoding.aliases.size # => 71
- Encoding.aliases.take(3)
- # => [["BINARY", "ASCII-8BIT"], ["CP437", "IBM437"], ["CP720", "IBM720"]]
-
-Method Encoding.name_list returns an array of all the encoding names and aliases:
-
- Encoding.name_list.size # => 175
- Encoding.name_list.take(3)
- # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
-
-Method +name_list+ returns more entries than method +list+
-because it includes both the names and their aliases.
-
-Method Encoding.find returns the \Encoding for a given name or alias, if it exists:
-
- Encoding.find("US-ASCII") # => #<Encoding:US-ASCII>
- Encoding.find("US-ASCII").class # => Encoding
-
-=== Default Encodings
-
-Method Encoding.find, above, also returns a default \Encoding
-for each of these special names:
-
-- +external+: the default external \Encoding:
-
- Encoding.find("external") # => #<Encoding:UTF-8>
-
-- +internal+: the default internal \Encoding (may be +nil+):
-
- Encoding.find("internal") # => nil
-
-- +locale+: the default \Encoding for a string from the environment:
-
- Encoding.find("locale") # => #<Encoding:UTF-8> # Linux
- Encoding.find("locale") # => #<Encoding:IBM437> # Windows
-
-- +filesystem+: the default \Encoding for a string from the filesystem:
-
- Encoding.find("filesystem") # => #<Encoding:UTF-8>
-
-Method Encoding.default_external returns the default external \Encoding:
-
- Encoding.default_external # => #<Encoding:UTF-8>
-
-Method Encoding.default_external= sets that value:
-
- Encoding.default_external = Encoding::US_ASCII # => #<Encoding:US-ASCII>
- Encoding.default_external # => #<Encoding:US-ASCII>
-
-Method Encoding.default_internal returns the default internal \Encoding:
-
- Encoding.default_internal # => nil
-
-Method Encoding.default_internal= sets the default internal \Encoding:
-
- Encoding.default_internal = Encoding::US_ASCII # => #<Encoding:US-ASCII>
- Encoding.default_internal # => #<Encoding:US-ASCII>
-
-=== Compatible Encodings
-
-Method Encoding.compatible? returns whether two given objects are encoding-compatible
-(that is, whether they can be concatenated);
-returns the \Encoding of the concatenated string, or +nil+ if incompatible:
-
- rus = "\u{442 435 441 442}"
- eng = 'text'
- Encoding.compatible?(rus, eng) # => #<Encoding:UTF-8>
-
- s0 = "\xa1\xa1".force_encoding(Encoding::ISO_8859_1) # => "\xA1\xA1"
- s1 = "\xa1\xa1".force_encoding(Encoding::EUCJP) # => "\x{A1A1}"
- Encoding.compatible?(s0, s1) # => nil
-
-== \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].
-
- 's'.encoding # => #<Encoding:UTF-8>
-
-The default encoding for a string created with method String.new is:
-
-- For no argument, ASCII-8BIT.
-- 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].
-
-In either case, any encoding may be specified:
-
- s = String.new(encoding: Encoding::UTF_8) # => ""
- s.encoding # => #<Encoding:UTF-8>
- s = String.new('foo', encoding: Encoding::BINARY) # => "foo"
- s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
-
-The encoding for a string may be changed:
-
- s = "R\xC3\xA9sum\xC3\xA9" # => "Résumé"
- s.encoding # => #<Encoding:UTF-8>
- s.force_encoding(Encoding::ISO_8859_1) # => "R\xC3\xA9sum\xC3\xA9"
- s.encoding # => #<Encoding:ISO-8859-1>
-
-Changing the assigned encoding does not alter the content of the string;
-it changes only the way the content is to be interpreted:
-
- s # => "R\xC3\xA9sum\xC3\xA9"
- s.force_encoding(Encoding::UTF_8) # => "Résumé"
-
-The actual content of a string may also be altered;
-see {Transcoding a String}[#label-Transcoding+a+String].
-
-Here are a couple of useful query methods:
-
- s = "abc".force_encoding(Encoding::UTF_8) # => "abc"
- s.ascii_only? # => true
- s = "abc\u{6666}".force_encoding(Encoding::UTF_8) # => "abc晦"
- s.ascii_only? # => false
-
- s = "\xc2\xa1".force_encoding(Encoding::UTF_8) # => "¡"
- s.valid_encoding? # => true
- s = "\xc2".force_encoding(Encoding::UTF_8) # => "\xC2"
- s.valid_encoding? # => false
-
-== \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.
-
-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].
-
-== Filesystem \Encoding
-
-The filesystem encoding is the default \Encoding for a string from the filesystem:
-
- Encoding.find("filesystem") # => #<Encoding:UTF-8>
-
-== 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
-
-Certain stream objects can have two encodings; these objects include instances of:
-
-- IO.
-- File.
-- ARGF.
-- StringIO.
-
-The two encodings are:
-
-- An _external_ _encoding_, which identifies the encoding of the stream.
-- An _internal_ _encoding_, which (if not +nil+) specifies the encoding
- to be used for the string constructed from the stream.
-
-=== External \Encoding
-
-The external encoding, which is an \Encoding object, specifies how bytes read
-from the stream are to be interpreted as characters.
-
-The default external encoding is:
-
-- UTF-8 for a text stream.
-- ASCII-8BIT for a binary stream.
-
-The default external encoding is returned by method Encoding.default_external,
-and may be set by:
-
-- Ruby command-line options <tt>--external_encoding</tt> or <tt>-E</tt>.
-
-You can also set the default external encoding using method Encoding.default_external=,
-but doing so may cause problems; strings created before and after the change
-may have a different encodings.
-
-For an \IO or \File object, the external encoding may be set by:
-
-- Open options +external_encoding+ or +encoding+, when the object is created;
- see {Open Options}[rdoc-ref:IO@Open+Options].
-
-For an \IO, \File, \ARGF, or \StringIO object, the external encoding may be set by:
-
-- Methods +set_encoding+ or (except for \ARGF) +set_encoding_by_bom+.
-
-=== Internal \Encoding
-
-The internal encoding, which is an \Encoding object or +nil+,
-specifies how characters read from the stream
-are to be converted to characters in the internal encoding;
-those characters become a string whose encoding is set to the internal encoding.
-
-The default internal encoding is +nil+ (no conversion).
-It is returned by method Encoding.default_internal,
-and may be set by:
-
-- Ruby command-line options <tt>--internal_encoding</tt> or <tt>-E</tt>.
-
-You can also set the default internal encoding using method Encoding.default_internal=,
-but doing so may cause problems; strings created before and after the change
-may have a different encodings.
-
-For an \IO or \File object, the internal encoding may be set by:
-
-- Open options +internal_encoding+ or +encoding+, when the object is created;
- see {Open Options}[rdoc-ref:IO@Open+Options].
-
-For an \IO, \File, \ARGF, or \StringIO object, the internal encoding may be set by:
-
-- Method +set_encoding+.
-
-== Script \Encoding
-
-A Ruby script has a script encoding, which may be retrieved by:
-
- __ENCODING__ # => #<Encoding:UTF-8>
-
-The default script encoding is UTF-8;
-a Ruby source file may set its script encoding with a magic comment
-on the first line of the file (or second line, if there is a shebang on the first).
-The comment must contain the word +coding+ or +encoding+,
-followed by a colon, space and the Encoding name or alias:
-
- # encoding: ISO-8859-1
- __ENCODING__ #=> #<Encoding:ISO-8859-1>
-
-== Transcoding
-
-_Transcoding_ is the process of changing a sequence of characters
-from one encoding to another.
-
-As far as possible, the characters remain the same,
-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
-
-Each of these methods transcodes a string:
-
-- String#encode: Transcodes +self+ into a new string
- according to given encodings and options.
-- String#encode!: Like String#encode, but transcodes +self+ in place.
-- String#scrub: Transcodes +self+ into a new string
- by replacing invalid byte sequences with a given or default replacement string.
-- String#scrub!: Like String#scrub, but transcodes +self+ in place.
-- String#unicode_normalize: Transcodes +self+ into a new string
- according to Unicode normalization.
-- String#unicode_normalize!: Like String#unicode_normalize,
- but transcodes +self+ in place.
-
-== Transcoding a Stream
-
-Each of these methods may transcode a stream;
-whether it does so depends on the external and internal encodings:
-
-- IO.foreach: Yields each line of given stream to the block.
-- IO.new: Creates and returns a new \IO object for the given integer file descriptor.
-- IO.open: Creates a new \IO object.
-- IO.pipe: Creates a connected pair of reader and writer \IO objects.
-- IO.popen: Creates an \IO object to interact with a subprocess.
-- IO.read: Returns a string with all or a subset of bytes from the given stream.
-- IO.readlines: Returns an array of strings, which are the lines from the given stream.
-- IO.write: Writes a given string to the given stream.
-
-This example writes a string to a file, encoding it as ISO-8859-1,
-then reads the file into a new string, encoding it as UTF-8:
-
- s = "R\u00E9sum\u00E9"
- path = 't.tmp'
- ext_enc = Encoding::ISO_8859_1
- int_enc = Encoding::UTF_8
-
- File.write(path, s, external_encoding: ext_enc)
- raw_text = File.binread(path)
-
- transcoded_text = File.read(path, external_encoding: ext_enc, internal_encoding: int_enc)
-
- p raw_text
- p transcoded_text
-
-Output:
-
- "R\xE9sum\xE9"
- "Résumé"
-
-== \Encoding Options
-
-A number of methods in the Ruby core accept keyword arguments as encoding options.
-
-Some of the options specify or utilize a _replacement_ _string_, to be used
-in certain transcoding operations.
-A replacement string may be in any encoding that can be converted
-to the encoding of the destination string.
-
-These keyword-value pairs specify encoding options:
-
-- For an invalid byte sequence:
-
- - <tt>:invalid: nil</tt> (default): Raise exception.
- - <tt>:invalid: :replace</tt>: Replace each invalid byte sequence
- with the replacement string.
-
- Examples:
-
- s = "\x80foo\x80"
- s.encode(Encoding::ISO_8859_3) # Raises Encoding::InvalidByteSequenceError.
- s.encode(Encoding::ISO_8859_3, invalid: :replace) # => "?foo?"
-
-- For an undefined character:
-
- - <tt>:undef: nil</tt> (default): Raise exception.
- - <tt>:undef: :replace</tt>: Replace each undefined character
- with the replacement string.
-
- Examples:
-
- s = "\x80foo\x80"
- "\x80".encode(Encoding::UTF_8, Encoding::BINARY) # Raises Encoding::UndefinedConversionError.
- s.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace) # => "�foo�"
-
-
-- Replacement string:
-
- - <tt>:replace: nil</tt> (default): Set replacement string to default value:
- <tt>"\uFFFD"</tt> ("�") for a Unicode encoding, <tt>'?'</tt> otherwise.
- - <tt>:replace: _some_string_</tt>: Set replacement string to the given +some_string+;
- overrides +:fallback+.
-
- Examples:
-
- s = "\xA5foo\xA5"
- options = {:undef => :replace, :replace => 'xyzzy'}
- s.encode(Encoding::UTF_8, Encoding::ISO_8859_3, **options) # => "xyzzyfooxyzzy"
-
-- Replacement fallback:
-
- One of these may be specified:
-
- - <tt>:fallback: nil</tt> (default): No replacement fallback.
- - <tt>:fallback: _hash_like_object_</tt>: Set replacement fallback to the given
- +hash_like_object+; the replacement string is <tt>_hash_like_object_[X]</tt>.
- - <tt>:fallback: _method_</tt>: Set replacement fallback to the given
- +method+; the replacement string is <tt>_method_(X)</tt>.
- - <tt>:fallback: _proc_</tt>: Set replacement fallback to the given
- +proc+; the replacement string is <tt>_proc_[X]</tt>.
-
- Examples:
-
- s = "\u3042foo\u3043"
-
- hash = {"\u3042" => 'xyzzy'}
- hash.default = 'XYZZY'
- s.encode(Encoding::US_ASCII, fallback: hash) # => "xyzzyfooXYZZY"
-
- def (fallback = "U+%.4X").escape(x)
- self % x.unpack("U")
- end
- "\u{3042}".encode(Encoding::US_ASCII, fallback: fallback.method(:escape)) # => "U+3042"
-
- proc = Proc.new {|x| x == "\u3042" ? 'xyzzy' : 'XYZZY' }
- s.encode('ASCII', fallback: proc) # => "XYZZYfooXYZZY"
-
-- XML entities:
-
- One of these may be specified:
-
- - <tt>:xml: nil</tt> (default): No handling for XML entities.
- - <tt>:xml: :text</tt>: Treat source text as XML;
- replace each undefined character
- with its upper-case hexdecimal numeric character reference,
- except that:
-
- - <tt>&</tt> is replaced with <tt>&amp;</tt>.
- - <tt><</tt> is replaced with <tt>&lt;</tt>.
- - <tt>></tt> is replaced with <tt>&gt;</tt>.
-
- - <tt>:xml: :attr</tt>: Treat source text as XML attribute value;
- replace each undefined character
- with its upper-case hexdecimal numeric character reference,
- except that:
-
- - The replacement string <tt>r</tt> is double-quoted (<tt>"r"</tt>).
- - Each embedded double-quote is replaced with <tt>&quot;</tt>.
- - <tt>&</tt> is replaced with <tt>&amp;</tt>.
- - <tt><</tt> is replaced with <tt>&lt;</tt>.
- - <tt>></tt> is replaced with <tt>&gt;</tt>.
-
- Examples:
-
- s = 'foo"<&>"bar' + "\u3042"
- s.encode(Encoding::US_ASCII, xml: :text) # => "foo\"&lt;&amp;&gt;\"bar&#x3042;"
- s.encode(Encoding::US_ASCII, xml: :attr) # => "\"foo&quot;&lt;&amp;&gt;&quot;bar&#x3042;\""
-
-
-- Newlines:
-
- One of these may be specified:
-
- - <tt>:cr_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
- with a carriage-return character (<tt>"\r"</tt>).
- - <tt>:crlf_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
- with a carriage-return/line-feed string (<tt>"\r\n"</tt>).
- - <tt>:universal_newline: true</tt>: Replace each carriage-return
- character (<tt>"\r"</tt>) and each carriage-return/line-feed string
- (<tt>"\r\n"</tt>) with a line-feed character (<tt>"\n"</tt>).
-
- Examples:
-
- s = "\n \r \r\n" # => "\n \r \r\n"
- s.encode(Encoding::US_ASCII, cr_newline: true) # => "\r \r \r\r"
- s.encode(Encoding::US_ASCII, crlf_newline: true) # => "\r\n \r \r\r\n"
- s.encode(Encoding::US_ASCII, universal_newline: true) # => "\n \n \n"
diff --git a/doc/examples/files.rdoc b/doc/examples/files.rdoc
index f736132770..cb400c81be 100644
--- a/doc/examples/files.rdoc
+++ b/doc/examples/files.rdoc
@@ -7,8 +7,8 @@ text = <<~EOT
Fifth line
EOT
-# Russian text.
-russian = "\u{442 435 441 442}" # => "тест"
+# Japanese text.
+japanese = 'こんにちは'
# Binary data.
data = "\u9990\u9991\u9992\u9993\u9994"
@@ -16,8 +16,8 @@ data = "\u9990\u9991\u9992\u9993\u9994"
# Text file.
File.write('t.txt', text)
-# File with Russian text.
-File.write('t.rus', russian)
+# File with Japanese text.
+File.write('t.ja', japanese)
# File with binary data.
f = File.new('t.dat', 'wb:UTF-16')
diff --git a/doc/exceptions.md b/doc/exceptions.md
deleted file mode 100644
index ffa4669a3b..0000000000
--- a/doc/exceptions.md
+++ /dev/null
@@ -1,521 +0,0 @@
-# Exceptions
-
-Ruby code can raise exceptions.
-
-Most often, a raised exception is meant to alert the running program
-that an unusual (i.e., _exceptional_) situation has arisen,
-and may need to be handled.
-
-Code throughout the Ruby core, Ruby standard library, and Ruby gems generates exceptions
-in certain circumstances:
-
-```rb
-File.open('nope.txt') # Raises Errno::ENOENT: "No such file or directory"
-```
-
-## Raised Exceptions
-
-A raised exception transfers program execution, one way or another.
-
-### Unrescued Exceptions
-
-If an exception not _rescued_
-(see [Rescued Exceptions](#label-Rescued+Exceptions) below),
-execution transfers to code in the Ruby interpreter
-that prints a message and exits the program (or thread):
-
-```console
-$ ruby -e "raise"
--e:1:in '<main>': unhandled exception
-```
-
-### Rescued Exceptions
-
-An <i>exception handler</i> may determine what is to happen
-when an exception is raised;
-the handler may _rescue_ an exception,
-and may prevent the program from exiting.
-
-A simple example:
-
-```rb
-begin
- raise 'Boom!' # Raises an exception, transfers control.
- puts 'Will not get here.'
-rescue
- puts 'Rescued an exception.' # Control transferred to here; program does not exit.
-end
-puts 'Got here.'
-```
-
-Output:
-
-```
-Rescued an exception.
-Got here.
-```
-
-An exception handler has several elements:
-
-| Element | Use |
-|-----------------------------|------------------------------------------------------------------------------------------|
-| Begin clause. | Begins the handler and contains the code whose raised exception, if any, may be rescued. |
-| One or more rescue clauses. | Each contains "rescuing" code, which is to be executed for certain exceptions. |
-| Else clause (optional). | Contains code to be executed if no exception is raised. |
-| Ensure clause (optional). | Contains code to be executed whether or not an exception is raised, or is rescued. |
-| <tt>end</tt> statement. | Ends the handler. ` |
-
-#### Begin Clause
-
-The begin clause begins the exception handler:
-
-- May start with a `begin` statement;
- see also [Begin-Less Exception Handlers](#label-Begin-Less+Exception+Handlers).
-- Contains code whose raised exception (if any) is covered
- by the handler.
-- Ends with the first following `rescue` statement.
-
-#### Rescue Clauses
-
-A rescue clause:
-
-- Starts with a `rescue` statement.
-- Contains code that is to be executed for certain raised exceptions.
-- Ends with the first following `rescue`,
- `else`, `ensure`, or `end` statement.
-
-##### Rescued Exceptions
-
-A `rescue` statement may include one or more classes
-that are to be rescued;
-if none is given, StandardError is assumed.
-
-The rescue clause rescues both the specified class
-(or StandardError if none given) or any of its subclasses;
-see [Built-In Exception Class Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
-
-```rb
-begin
- 1 / 0 # Raises ZeroDivisionError, a subclass of StandardError.
-rescue
- puts "Rescued #{$!.class}"
-end
-```
-
-Output:
-
-```
-Rescued ZeroDivisionError
-```
-
-If the `rescue` statement specifies an exception class,
-only that class (or one of its subclasses) is rescued;
-this example exits with a ZeroDivisionError,
-which was not rescued because it is not ArgumentError or one of its subclasses:
-
-```rb
-begin
- 1 / 0
-rescue ArgumentError
- puts "Rescued #{$!.class}"
-end
-```
-
-A `rescue` statement may specify multiple classes,
-which means that its code rescues an exception
-of any of the given classes (or their subclasses):
-
-```rb
-begin
- 1 / 0
-rescue FloatDomainError, ZeroDivisionError
- puts "Rescued #{$!.class}"
-end
-```
-
-##### Multiple Rescue Clauses
-
-An exception handler may contain multiple rescue clauses;
-in that case, the first clause that rescues the exception does so,
-and those before and after are ignored:
-
-```rb
-begin
- Dir.open('nosuch')
-rescue Errno::ENOTDIR
- puts "Rescued #{$!.class}"
-rescue Errno::ENOENT
- puts "Rescued #{$!.class}"
-end
-```
-
-Output:
-
-```
-Rescued Errno::ENOENT
-```
-
-##### Capturing the Rescued \Exception
-
-A `rescue` statement may specify a variable
-whose value becomes the rescued exception
-(an instance of Exception or one of its subclasses:
-
-```rb
-begin
- 1 / 0
-rescue => x
- puts x.class
- puts x.message
-end
-```
-
-Output:
-
-```
-ZeroDivisionError
-divided by 0
-```
-
-##### Global Variables
-
-Two read-only global variables always have `nil` value
-except in a rescue clause;
-there:
-
-- `$!`: contains the rescued exception.
-- `$@`: contains its backtrace.
-
-Example:
-
-```rb
-begin
- 1 / 0
-rescue
- p $!
- p $@
-end
-```
-
-Output:
-
-```
-#<ZeroDivisionError: divided by 0>
-["t.rb:2:in 'Integer#/'", "t.rb:2:in '<main>'"]
-```
-
-##### Cause
-
-In a rescue clause, the method Exception#cause returns the previous value of `$!`,
-which may be `nil`;
-elsewhere, the method returns `nil`.
-
-Example:
-
-```rb
-begin
- raise('Boom 0')
-rescue => x0
- puts "Exception: #{x0.inspect}; $!: #{$!.inspect}; cause: #{x0.cause.inspect}."
- begin
- raise('Boom 1')
- rescue => x1
- puts "Exception: #{x1.inspect}; $!: #{$!.inspect}; cause: #{x1.cause.inspect}."
- begin
- raise('Boom 2')
- rescue => x2
- puts "Exception: #{x2.inspect}; $!: #{$!.inspect}; cause: #{x2.cause.inspect}."
- end
- end
-end
-```
-
-Output:
-
-```
-Exception: #<RuntimeError: Boom 0>; $!: #<RuntimeError: Boom 0>; cause: nil.
-Exception: #<RuntimeError: Boom 1>; $!: #<RuntimeError: Boom 1>; cause: #<RuntimeError: Boom 0>.
-Exception: #<RuntimeError: Boom 2>; $!: #<RuntimeError: Boom 2>; cause: #<RuntimeError: Boom 1>.
-```
-
-#### Else Clause
-
-The `else` clause:
-
-- Starts with an `else` statement.
-- Contains code that is to be executed if no exception is raised in the begin clause.
-- Ends with the first following `ensure` or `end` statement.
-
-```rb
-begin
- puts 'Begin.'
-rescue
- puts 'Rescued an exception!'
-else
- puts 'No exception raised.'
-end
-```
-
-Output:
-
-```
-Begin.
-No exception raised.
-```
-
-#### Ensure Clause
-
-The ensure clause:
-
-- Starts with an `ensure` statement.
-- Contains code that is to be executed
- regardless of whether an exception is raised,
- and regardless of whether a raised exception is handled.
-- Ends with the first following `end` statement.
-
-```rb
-def foo(boom: false)
- puts 'Begin.'
- raise 'Boom!' if boom
-rescue
- puts 'Rescued an exception!'
-else
- puts 'No exception raised.'
-ensure
- puts 'Always do this.'
-end
-
-foo(boom: true)
-foo(boom: false)
-```
-
-Output:
-
-```
-Begin.
-Rescued an exception!
-Always do this.
-Begin.
-No exception raised.
-Always do this.
-```
-
-#### End Statement
-
-The `end` statement ends the handler.
-
-Code following it is reached only if any raised exception is rescued.
-
-#### Begin-Less \Exception Handlers
-
-As seen above, an exception handler may be implemented with `begin` and `end`.
-
-An exception handler may also be implemented as:
-
-- A method body:
-
- ```rb
- def foo(boom: false) # Serves as beginning of exception handler.
- puts 'Begin.'
- raise 'Boom!' if boom
- rescue
- puts 'Rescued an exception!'
- else
- puts 'No exception raised.'
- end # Serves as end of exception handler.
- ```
-
-- A block:
-
- ```rb
- Dir.chdir('.') do |dir| # Serves as beginning of exception handler.
- raise 'Boom!'
- rescue
- puts 'Rescued an exception!'
- end # Serves as end of exception handler.
- ```
-
-#### Re-Raising an \Exception
-
-It can be useful to rescue an exception, but allow its eventual effect;
-for example, a program can rescue an exception, log data about it,
-and then "reinstate" the exception.
-
-This may be done via the `raise` method, but in a special way;
-a rescuing clause:
-
- - Captures an exception.
- - Does whatever is needed concerning the exception (such as logging it).
- - Calls method `raise` with no argument,
- which raises the rescued exception:
-
-```rb
-begin
- 1 / 0
-rescue ZeroDivisionError
- # Do needful things (like logging).
- raise # Raised exception will be ZeroDivisionError, not RuntimeError.
-end
-```
-
-Output:
-
-```
-ruby t.rb
-t.rb:2:in 'Integer#/': divided by 0 (ZeroDivisionError)
- from t.rb:2:in '<main>'
-```
-
-#### Retrying
-
-It can be useful to retry a begin clause;
-for example, if it must access a possibly-volatile resource
-(such as a web page),
-it can be useful to try the access more than once
-(in the hope that it may become available):
-
-```rb
-retries = 0
-begin
- puts "Try ##{retries}."
- raise 'Boom'
-rescue
- puts "Rescued retry ##{retries}."
- if (retries += 1) < 3
- puts 'Retrying'
- retry
- else
- puts 'Giving up.'
- raise
- end
-end
-```
-
-```
-Try #0.
-Rescued retry #0.
-Retrying
-Try #1.
-Rescued retry #1.
-Retrying
-Try #2.
-Rescued retry #2.
-Giving up.
-# RuntimeError ('Boom') raised.
-```
-
-Note that the retry re-executes the entire begin clause,
-not just the part after the point of failure.
-
-## Raising an \Exception
-
-Method Kernel#raise raises an exception.
-
-## Custom Exceptions
-
-To provide additional or alternate information,
-you may create custom exception classes.
-Each should be a subclass of one of the built-in exception classes
-(commonly StandardError or RuntimeError);
-see [Built-In Exception Class Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
-
-```rb
-class MyException < StandardError; end
-```
-
-## Messages
-
-Every `Exception` object has a message,
-which is a string that is set at the time the object is created;
-see Exception.new.
-
-The message cannot be changed, but you can create a similar object with a different message;
-see Exception#exception.
-
-This method returns the message as defined:
-
-- Exception#message.
-
-Two other methods return enhanced versions of the message:
-
-- Exception#detailed_message: adds exception class name, with optional highlighting.
-- Exception#full_message: adds exception class name and backtrace, with optional highlighting.
-
-Each of the two methods above accepts keyword argument `highlight`;
-if the value of keyword `highlight` is `true`,
-the returned string includes bolding and underlining ANSI codes (see below)
-to enhance the appearance of the message.
-
-Any exception class (Ruby or custom) may choose to override either of these methods,
-and may choose to interpret keyword argument <tt>highlight: true</tt>
-to mean that the returned message should contain
-[ANSI codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
-that specify color, bolding, and underlining.
-
-Because the enhanced message may be written to a non-terminal device
-(e.g., into an HTML page),
-it is best to limit the ANSI codes to these widely-supported codes:
-
-- Begin font color:
-
- | Color | ANSI Code |
- |---------|------------------|
- | Red | <tt>\\e[31m</tt> |
- | Green | <tt>\\e[32m</tt> |
- | Yellow | <tt>\\e[33m</tt> |
- | Blue | <tt>\\e[34m</tt> |
- | Magenta | <tt>\\e[35m</tt> |
- | Cyan | <tt>\\e[36m</tt> |
-
-<br>
-
-- Begin font attribute:
-
- | Attribute | ANSI Code |
- |-----------|-----------------|
- | Bold | <tt>\\e[1m</tt> |
- | Underline | <tt>\\e[4m</tt> |
-
-<br>
-
-- End all of the above:
-
- | Color | ANSI Code |
- |-------|-----------------|
- | Reset | <tt>\\e[0m</tt> |
-
-It's also best to craft a message that is conveniently human-readable,
-even if the ANSI codes are included "as-is"
-(rather than interpreted as font directives).
-
-## Backtraces
-
-A _backtrace_ is a record of the methods currently
-in the [call stack](https://en.wikipedia.org/wiki/Call_stack);
-each such method has been called, but has not yet returned.
-
-These methods return backtrace information:
-
-- Exception#backtrace: returns the backtrace as an array of strings or `nil`.
-- Exception#backtrace_locations: returns the backtrace as an array
- of Thread::Backtrace::Location objects or `nil`.
- Each Thread::Backtrace::Location object gives detailed information about a called method.
-
-By default, Ruby sets the backtrace of the exception to the location where it
-was raised.
-
-The developer might adjust this by either providing +backtrace+ argument
-to Kernel#raise, or using Exception#set_backtrace.
-
-Note that:
-
-- by default, both +backtrace+ and +backtrace_locations+ represent the same backtrace;
-- if the developer sets the backtrace by one of the above methods to an array of
- Thread::Backtrace::Location, they still represent the same backtrace;
-- if the developer sets the backtrace to a string or an array of strings:
- - by Kernel#raise: +backtrace_locations+ become +nil+;
- - by Exception#set_backtrace: +backtrace_locations+ preserve the original
- value;
-- if the developer sets the backtrace to +nil+ by Exception#set_backtrace,
- +backtrace_locations+ preserve the original value; but if the exception is then
- reraised, both +backtrace+ and +backtrace_locations+ become the location of reraise.
diff --git a/doc/extension.ja.rdoc b/doc/extension.ja.rdoc
index 2f7856f3d4..a943f7a109 100644
--- a/doc/extension.ja.rdoc
+++ b/doc/extension.ja.rdoc
@@ -1,5 +1,7 @@
# extension.ja.rdoc - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995
+{English}[rdoc-ref:extension.rdoc]
+
= Rubyの拡張ライブラリの作り方
Rubyの拡張ライブラリの作り方を説明します.
@@ -335,11 +337,11 @@ rb_ary_aref(int argc, const VALUE *argv, VALUE ary) ::
rb_ary_entry(VALUE ary, long offset) ::
- \ary[offset]
+ ary\[offset]
rb_ary_store(VALUE ary, long offset, VALUE obj) ::
- \ary[offset] = obj
+ ary\[offset] = obj
rb_ary_subseq(VALUE ary, long beg, long len) ::
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index ba59d107ab..9fc507706e 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -1,5 +1,7 @@
# extension.rdoc - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995
+{日本語}[rdoc-ref:extension.ja.rdoc]
+
= Creating extension libraries for Ruby
This document explains how to make extension libraries for Ruby.
@@ -315,11 +317,11 @@ rb_ary_aref(int argc, const VALUE *argv, VALUE ary) ::
rb_ary_entry(VALUE ary, long offset) ::
- \ary[offset]
+ ary\[offset]
rb_ary_store(VALUE ary, long offset, VALUE obj) ::
- \ary[offset] = obj
+ ary\[offset] = obj
rb_ary_subseq(VALUE ary, long beg, long len) ::
@@ -759,6 +761,50 @@ RUBY_TYPED_FROZEN_SHAREABLE ::
If this flag is not set, the object can not become a shareable
object by Ractor.make_shareable() method.
+RUBY_TYPED_EMBEDDABLE ::
+
+ This flag indicates that Ruby may store the C struct inside the object
+ slot, rather than allocate it separately with +malloc+.
+ However, it is not a guarantee. Ruby may decide not to embed the object.
+ For instance if it's too large to fit into one of the available slot sizes.
+
+ Embedding the C struct inside the object slot reduces pointer chasing,
+ malloc overhead, and improves sweep performance.
+ In some cases, it can also reduce the memory footprint of the object.
+
+ To be embeddable, types must abide by some restrictions:
+
+ * Pointers to the C struct, or into the C struct, MUST NOT be stored,
+ as they become invalid when GC compaction occurs.
+ It is however valid to pass and use such pointers for as long as the Ruby
+ object remains on the stack.
+
+ In a sense, this is similar to the restrictions of a stack allocated struct.
+
+ The +RB_GC_GUARD+ macro must be used to ensure the object is not moved by
+ compaction and not freed, unless the object is passed directly as an
+ argument from Ruby to C, i.e. as a parameter of a function used with
+ +rb_define_method+ and similar.
+
+ * The +DATA_PTR+ and +RTYPEDDATA_DATA+ macro can't be used.
+ Only +RTYPEDDATA_GET_DATA+` or +TypedData_Get_Struct+ macros can be used
+ with embeddable objects.
+ Accessing `RDATA(obj)->data` or `RTYPEDDATA(obj)->data` is invalid too.
+
+ * The +dfree+ function MUST NOT free the C struct itself.
+ Setting +dfree+ to +RUBY_DEFAULT_FREE+ is fine.
+ To support older Ruby versions without this feature, you can
+ conditionally free the C struct if +RUBY_TYPED_EMBEDDABLE+ isn't defined.
+
+ * The type must have the +RUBY_TYPED_FREE_IMMEDIATELY+ flag set.
+
+ If the embedded C struct is of variable size, +rb_data_typed_object_zalloc+
+ can be used instead of +TypedData_Make_Struct+.
+
+ See {Embedded TypedData}[rdoc-ref:@Appendix+G.+Embedded+TypedData] for a
+ commented example of how to use +RUBY_TYPED_EMBEDDABLE+.
+
+
Note that this macro can raise an exception. If sval to be wrapped
holds a resource needs to be released (e.g., allocated memory, handle
from an external library, and etc), you will have to use rb_protect.
@@ -2047,7 +2093,7 @@ the <code>*_kw</code> functions introduced in Ruby 2.7.
#define rb_proc_call_with_block_kw(p, c, v, b, kw) rb_proc_call_with_block(p, c, v, b)
#define rb_method_call_kw(c, v, m, kw) rb_method_call(c, v, m)
#define rb_method_call_with_block_kw(c, v, m, b, kw) rb_method_call_with_block(c, v, m, b)
- #define rb_eval_cmd_kwd(c, a, kw) rb_eval_cmd(c, a, 0)
+ #define rb_eval_cmd_kw(c, a, kw) rb_eval_cmd(c, a, 0)
#endif
== Appendix C. Functions available for use in extconf.rb
@@ -2283,6 +2329,89 @@ To make a "Ractor-safe" C extension, we need to check the following points:
making of a Ractor-safe extension. This document will be extended as they are
discovered.
+== Appendix G. Embedded TypedData
+
+Here is an example of how to use +RUBY_TYPED_EMBEDDABLE+::
+
+ struct my_data {
+ struct timespec created_at;
+ size_t buffer_capa;
+ char *buffer;
+ };
+
+ static void
+ my_data_free(void *ptr)
+ {
+ struct my_data *data = (struct my_data *)ptr;
+
+ // Deliberately don't free `ptr` if it is embeddable.
+ // Only auxiliary memory need to be freed.
+ ruby_xfree(data->buffer);
+ }
+
+ static size_t
+ my_data_size(const void *ptr)
+ {
+ const struct my_data *data = (const struct my_data *)ptr;
+ // We don't need to account for `sizeof(struct my_struct)` because it is embedded inside the Ruby object.
+ // Only auxiliary memory need to be reported.
+ return data->buffer_capa;
+ }
+
+ static const rb_data_type_t my_type = {
+ .wrap_struct_name = "my_type",
+ .function = {
+ .dfree = my_data_free,
+ .dsize = my_data_size,
+ }
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
+ };
+
+ static VALUE
+ my_data_alloc(VALUE klass)
+ {
+ struct my_data *data;
+ VALUE obj = TypedData_Make_Struct(klass, struct my_data, &my_type, data);
+
+ // Is it fine to pass pointers into the embedded struct, for as long as
+ // the called function won't use it after the Ruby object have left the stack.
+ clock_gettime(CLOCK_REALTIME, &data->created_at);
+ data->buffer_capa = 1024;
+ data->buffer = ZALLOC_N(char, data->buffer_capa);
+
+ return obj
+ }
+
+ static VALUE
+ my_data_m_parse(VALUE klass)
+ {
+ struct my_data *data;
+ VALUE my_data_obj = my_data_alloc(klass);
+ TypedData_Get_Struct(obj, struct my_data, &my_type, data);
+
+ // `my_data_obj` was allocated from C, `RB_GC_GUARD` must be used to
+ // ensure the compiler will keep its reference on the stack.
+ RB_GC_GUARD(my_data_obj)
+ }
+
+ static VALUE
+ my_data_read(VALUE self)
+ {
+ struct my_data *data;
+ TypedData_Get_Struct(obj, struct my_data, &my_type, data);
+
+ // `self` is received from `rb_define_method` so `RB_GC_GUARD` isn't necessary.
+ return rb_str_new(data->buffer, data->buffer_capa)
+ }
+
+ void
+ Init_my_data(void)
+ {
+ VALUE cMyData = rb_define_class("MyData");
+ rb_define_method(cMyData, "read", my_data_read, 0);
+ rb_define_singleton_method(cMyData, "parse", my_data_m_parse, 0);
+ }
+
--
Local variables:
fill-column: 70
diff --git a/doc/fiber.md b/doc/fiber.md
deleted file mode 100644
index 2bc1ff96b2..0000000000
--- a/doc/fiber.md
+++ /dev/null
@@ -1,232 +0,0 @@
-# Fiber
-
-Fibers provide a mechanism for cooperative concurrency.
-
-## Context Switching
-
-Fibers execute a user-provided block. During the execution, the block may call `Fiber.yield` or `Fiber.transfer` to switch to another fiber. `Fiber#resume` is used to continue execution from the point where `Fiber.yield` was called.
-
-```rb
-#!/usr/bin/env ruby
-
-puts "1: Start program."
-
-f = Fiber.new do
- puts "3: Entered fiber."
- Fiber.yield
- puts "5: Resumed fiber."
-end
-
-puts "2: Resume fiber first time."
-f.resume
-
-puts "4: Resume fiber second time."
-f.resume
-
-puts "6: Finished."
-```
-
-This program demonstrates the flow control of fibers.
-
-## Scheduler
-
-The scheduler interface is used to intercept blocking operations. A typical
-implementation would be a wrapper for a gem like `EventMachine` or `Async`. This
-design provides separation of concerns between the event loop implementation
-and application code. It also allows for layered schedulers which can perform
-instrumentation.
-
-To set the scheduler for the current thread:
-
-```rb
-Fiber.set_scheduler(MyScheduler.new)
-```
-
-When the thread exits, there is an implicit call to `set_scheduler`:
-
-```rb
-Fiber.set_scheduler(nil)
-```
-
-### Design
-
-The scheduler interface is designed to be a un-opinionated light-weight layer
-between user code and blocking operations. The scheduler hooks should avoid
-translating or converting arguments or return values. Ideally, the exact same
-arguments from the user code are provided directly to the scheduler hook with
-no changes.
-
-### Interface
-
-This is the interface you need to implement.
-
-```rb
-class Scheduler
- # Wait for the specified process ID to exit.
- # This hook is optional.
- # @parameter pid [Integer] The process ID to wait for.
- # @parameter flags [Integer] A bit-mask of flags suitable for `Process::Status.wait`.
- # @returns [Process::Status] A process status instance.
- def process_wait(pid, flags)
- Thread.new do
- Process::Status.wait(pid, flags)
- end.value
- end
-
- # Wait for the given io readiness to match the specified events within
- # the specified timeout.
- # @parameter event [Integer] A bit mask of `IO::READABLE`,
- # `IO::WRITABLE` and `IO::PRIORITY`.
- # @parameter timeout [Numeric] The amount of time to wait for the event in seconds.
- # @returns [Integer] The subset of events that are ready.
- def io_wait(io, events, timeout)
- end
-
- # Read from the given io into the specified buffer.
- # WARNING: Experimental hook! Do not use in production code!
- # @parameter io [IO] The io to read from.
- # @parameter buffer [IO::Buffer] The buffer to read into.
- # @parameter length [Integer] The minimum amount to read.
- def io_read(io, buffer, length)
- end
-
- # Write from the given buffer into the specified IO.
- # WARNING: Experimental hook! Do not use in production code!
- # @parameter io [IO] The io to write to.
- # @parameter buffer [IO::Buffer] The buffer to write from.
- # @parameter length [Integer] The minimum amount to write.
- def io_write(io, buffer, length)
- end
-
- # Sleep the current task for the specified duration, or forever if not
- # specified.
- # @parameter duration [Numeric] The amount of time to sleep in seconds.
- def kernel_sleep(duration = nil)
- end
-
- # Execute the given block. If the block execution exceeds the given timeout,
- # the specified exception `klass` will be raised. Typically, only non-blocking
- # methods which enter the scheduler will raise such exceptions.
- # @parameter duration [Integer] The amount of time to wait, after which an exception will be raised.
- # @parameter klass [Class] The exception class to raise.
- # @parameter *arguments [Array] The arguments to send to the constructor of the exception.
- # @yields {...} The user code to execute.
- def timeout_after(duration, klass, *arguments, &block)
- end
-
- # Resolve hostname to an array of IP addresses.
- # This hook is optional.
- # @parameter hostname [String] Example: "www.ruby-lang.org".
- # @returns [Array] An array of IPv4 and/or IPv6 address strings that the hostname resolves to.
- def address_resolve(hostname)
- end
-
- # Block the calling fiber.
- # @parameter blocker [Object] What we are waiting on, informational only.
- # @parameter timeout [Numeric | Nil] The amount of time to wait for in seconds.
- # @returns [Boolean] Whether the blocking operation was successful or not.
- def block(blocker, timeout = nil)
- end
-
- # Unblock the specified fiber.
- # @parameter blocker [Object] What we are waiting on, informational only.
- # @parameter fiber [Fiber] The fiber to unblock.
- # @reentrant Thread safe.
- def unblock(blocker, fiber)
- end
-
- # Intercept the creation of a non-blocking fiber.
- # @returns [Fiber]
- def fiber(&block)
- Fiber.new(blocking: false, &block)
- end
-
- # Invoked when the thread exits.
- def close
- self.run
- end
-
- def run
- # Implement event loop here.
- end
-end
-```
-
-Additional hooks may be introduced in the future, we will use feature detection
-in order to enable these hooks.
-
-### Non-blocking Execution
-
-The scheduler hooks will only be used in special non-blocking execution
-contexts. Non-blocking execution contexts introduce non-determinism because the
-execution of scheduler hooks may introduce context switching points into your
-program.
-
-#### Fibers
-
-Fibers can be used to create non-blocking execution contexts.
-
-```rb
-Fiber.new do
- puts Fiber.current.blocking? # false
-
- # May invoke `Fiber.scheduler&.io_wait`.
- io.read(...)
-
- # May invoke `Fiber.scheduler&.io_wait`.
- io.write(...)
-
- # Will invoke `Fiber.scheduler&.kernel_sleep`.
- sleep(n)
-end.resume
-```
-
-We also introduce a new method which simplifies the creation of these
-non-blocking fibers:
-
-```rb
-Fiber.schedule do
- puts Fiber.current.blocking? # false
-end
-```
-
-The purpose of this method is to allow the scheduler to internally decide the
-policy for when to start the fiber, and whether to use symmetric or asymmetric
-fibers.
-
-You can also create blocking execution contexts:
-
-```rb
-Fiber.new(blocking: true) do
- # Won't use the scheduler:
- sleep(n)
-end
-```
-
-However you should generally avoid this unless you are implementing a scheduler.
-
-#### IO
-
-By default, I/O is non-blocking. Not all operating systems support non-blocking
-I/O. Windows is a notable example where socket I/O can be non-blocking but pipe
-I/O is blocking. Provided that there *is* a scheduler and the current thread *is
-non-blocking*, the operation will invoke the scheduler.
-
-#### Mutex
-
-The `Mutex` class can be used in a non-blocking context and is fiber specific.
-
-#### ConditionVariable
-
-The `ConditionVariable` class can be used in a non-blocking context and is
-fiber-specific.
-
-#### Queue / SizedQueue
-
-The `Queue` and `SizedQueue` classes can be used in a non-blocking context and
-are fiber-specific.
-
-#### Thread
-
-The `Thread#join` operation can be used in a non-blocking context and is
-fiber-specific.
diff --git a/doc/file/filename_globbing.md b/doc/file/filename_globbing.md
new file mode 100644
index 0000000000..7981964c5c
--- /dev/null
+++ b/doc/file/filename_globbing.md
@@ -0,0 +1,301 @@
+# Filename Globbing
+
+Filename globbing is a pattern-matching feature implemented in certain Ruby methods.
+
+Filename-globbing methods find filesystem entries (files and directories)
+that match certain patterns;
+these methods are:
+
+- Dir.glob.
+- [`Dir[]`](https://docs.ruby-lang.org/en/master/Dir.html#method-c-5B-5D).
+- Pathname.glob.
+- Pathname#glob.
+
+These methods are quite different from filename-matching methods (not discussed here),
+which match patterns against string paths, and do not access the filesystem;
+those methods are:
+
+- File.fnmatch.
+- Pathname#fnmatch.
+
+These are the basic elements of filename-globbing patterns;
+see the sections below for details:
+
+| Pattern | Meaning | Examples |
+|:------------------------:|------------------------------------------|------------------------------|
+| Simple string. | Matches itself. | `'LEGAL'` |
+| `'*'` | Matches any sequence of characters. | `'*.txt'` |
+| `'?'` | Matches any single character. | `'?.txt'` |
+| `'[abc]'`,<br>`'[^abc]'` | Matches a single character from a set. | `'x[abc]y'`,<br>`'x[^abc]y'` |
+| `'[a-z]`',<br>`'[^a-z]'` | Matches a single character from a range. | `'x[0-9]y'`,<br>`'x[^0-9]y'` |
+| `'{ , }'` | Matches alternatives. | `'{abc,def}'` |
+| `'**'` | Matches directories recursively. | `'**/test.rb'` |
+| `'\'` | Escapes the next character. | `'\\*'`, `'\?'` |
+
+## Patterns
+
+### Simple \String
+
+A "simple string" is one that does not contain special filename-globbing patterns;
+see the table above.
+
+A simple string matches itself:
+
+```ruby
+Dir.glob('LEGAL') # => ["LEGAL"]
+Dir.glob('LEGA') # => [] # Must be exact.
+Dir.glob('legal') # => [] # Case-sensitive.
+```
+
+Note that case-sensitivity may _not_ be modified by flags.
+
+By default, the Windows short name pattern is disabled:
+
+```ruby
+Dir.glob('PROGRAM~1') # => []
+```
+
+It may be enabled by flag [`File::FNM_SHORTNAME`](#constant-filefnmshortname).
+
+
+### Any Sequence of Characters (`'*'`)
+
+The asterisk pattern (`'*'`) matches any sequence of characters:
+
+```ruby
+Dir.glob('*').take(3) # => ["BSDL", "CONTRIBUTING.md", "COPYING"]
+Dir.glob('\*') # => [] # Escaped.
+```
+
+By default, the asterisk pattern does not match a leading period (as in a dot-file):
+
+```ruby
+Dir.glob('*').select {|entry| entry.start_with?('.') } # => []
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+The asterisk pattern does not match across file separators:
+
+```ruby
+Dir.glob('*.rb').select {|entry| entry.include?('/') } # => []
+```
+
+Therefore flag File::FNM_PATHNAME does not affect the pattern.
+
+### Single Character (`'?'`)
+
+The question-mark pattern (`'?'`) matches any single character:
+
+```ruby
+Dir.glob('???') # => ["GPL", "bin", "doc", "enc", "ext", "jit", "lib", "man"]
+Dir.glob('??') # => ["gc"] # Only one entry with a 2-character name.
+Dir.glob('?') # => [] # No entries with a 1-character name.
+Dir.glob('\?') # => [] # No entries containing character '?'.
+```
+
+By default, the question-mark pattern does not match a leading period (as in a dot-file):
+
+```ruby
+Dir.glob(".???") # => [".git"]
+Dir.glob("????").select {|entry| entry.start_with?('.') } # => []
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+### Single Character from a Set (`'[abc]'`, `'[^abc]'`)
+
+Characters enclosed in square brackets define a set of characters,
+any of which matches a single character:
+
+```ruby
+Dir.glob('[efgh][abcd]') # => ["gc"]
+Dir.glob('\[efgh][abcd]') # => [] # Escaped.
+```
+
+The character set may be negated:
+
+```ruby
+Dir.glob('[^abcd][^efgh]') # => ["gc"]
+```
+
+### Single Character from a \Range (`'[a-c]'`, `'[^a-c]'`)
+
+A range of characters enclosed in square brackets defines a set of characters,
+any of which matches a single character:
+
+```ruby
+Dir.glob('[k-m][h-j][a-c]') # => ["lib"]
+Dir.glob('\[k-m][h-j][a-c]') # => [] # Escaped.
+```
+
+The range may be negated:
+
+```ruby
+Dir.glob('[^k-m][h-j][a-c]') # => []
+Dir.glob('[^a-c][^k-m][^h-j]') # => ["GPL", "doc", "enc", "ext", "jit", "lib", "man"]
+```
+
+### Alternatives (`'{ , }'`)
+
+The alternatives pattern consists of comma-separated strings
+enclosed in curly braces:
+
+```ruby
+Dir.glob('{k,L,R}*') # => ["kernel.rb", "LEGAL", "README.ja.md", "README.md"]
+Dir.glob('{R,L,k}*') # => ["README.ja.md", "README.md", "LEGAL", "kernel.rb"]
+# Whitespace matters:
+Dir.glob('{k ,L,R}*') # => ["LEGAL", "README.ja.md", "README.md"]
+```
+
+### Recursive Directory Matching (`'**'`)
+
+The double-asterisk pattern (`'**'`) matches directories recursively:
+
+```ruby
+# Find all entries everywhere ending with '.ja'.
+Dir.glob('**/*.ja')
+# => ["COPYING.ja", "doc/pty/README.expect.ja", "doc/pty/README.ja"]
+
+# Find all entries everywhere ending with '.rb'.
+Dir.glob('**/*.rb').size # => 7574
+Dir.glob('**/*.rb').take(3)
+# => ["KNOWNBUGS.rb", "array.rb", "ast.rb"]
+
+# Find all entries in directory 'lib' ending with `.rb'.
+Dir.glob('lib/**/*.rb').size # => 626
+Dir.glob('lib/**/*.rb').take(3)
+# # =>
+# ["lib/English.rb",
+# "lib/bundled_gems.rb",
+# "lib/bundler/build_metadata.rb"]
+
+# Find all entries in directory 'test/ruby' ending with '.rb'.
+Dir.glob('test/ruby/**/*.rb').size # => 200
+Dir.glob('test/ruby/**/*.rb').take(3)
+# # =>
+# ["test/ruby/allpairs.rb",
+# "test/ruby/beginmainend.rb",
+# "test/ruby/box/a.1_1_0.rb"]
+
+# Escaped.
+Dir.glob('\**/*.rb') # => []
+```
+
+
+### Escape (`'\'`)
+
+The backslash character (`'\'`) may be used to escape any of the characters
+that filename globbing treats as special:
+
+```ruby
+Dir.glob('\*') # => []
+Dir.glob('\?') # => []
+Dir.glob('\[efgh][abcd]') # => []
+Dir.glob('\[k-m][h-j][a-c]') # => []
+Dir.glob('\**/*.rb') # => []
+```
+
+## Keyword Arguments
+
+| Keyword | Value | Default | Meaning |
+|-------------------|--------------------------|:-------:|-----------------------------------------|
+| [`base`](#base) | \String path. | `'.'` | Root for searching. |
+| [`flags`](#flags) | Logical OR of constants. | `0` | Modify globbing behavior. |
+| [`sort`](#sort) | `true` or `false` | `true` | Whether returned array is to be sorted. |
+
+### `base`
+
+Optional keyword argument `base` (defaults to `'.'`)
+specifies where in the filesystem the searching is to begin:
+
+```ruby
+Dir.glob('*').size # => 241
+Dir.glob('*').take(3)
+# => ["BSDL", "CONTRIBUTING.md", "COPYING"]
+
+Dir.glob('*', base: 'lib').size # => 72
+Dir.glob('*', base: 'lib').take(3)
+# => ["English.gemspec", "English.rb", "bundled_gems.rb"]
+
+Dir.glob('*', base: 'lib/net').size # => 5
+Dir.glob('*', base: 'lib/net').take(3)
+# => ["http", "http.rb", "https.rb"]
+```
+
+### `flags`
+
+Optional keyword argument `flags` (defaults to `0`) may be the bitwise OR
+of the constants `File::FNM*`:
+
+```ruby
+Dir.glob('*', flags: File::FNM_DOTMATCH | File::FNM_NOESCAPE)
+```
+
+These are the constants for filename-globbing patterns;
+see the sections below for details:
+
+
+| Constant | Meaning |
+|-----------------------------------------------------|--------------------------------------------|
+| [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch) | Make pattern `'*'` match a leading period. |
+| [`File::FNM_NOESCAPE`](#constant-filefnmnoescape) | Disable escaping. |
+| [`File::FNM_SHORTNAME`](#constant-filefnmshortname) | Enable short-name matching (Windows only). |
+
+These constants do not affect filename globbing:
+
+- File::FNM_CASEFOLD.
+- File::FNM_EXTGLOB.
+- File::FNM_PATHNAME.
+- File::FNM_SYSCASE.
+
+#### Constant File::FNM_DOTMATCH
+
+By default, filename globbing does not allow patterns `'*'` and `'?'` to match a dotfile name
+(i.e, an entry name beginning with a dot);
+use constant [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch)
+to enable the match:
+
+```ruby
+Dir.glob('*').size # => 241
+Dir.glob('*', flags: File::FNM_DOTMATCH).size # => 256
+Dir.glob('*', flags: File::FNM_DOTMATCH).take(3) # => [".", ".dir-locals.el", ".document"]
+```
+
+#### Constant File::FNM_NOESCAPE
+
+By default filename globbing has escaping enabled;
+use constant [`File::FNM_NOESCAPE`](#constant-filefnmnoescape)
+to disable it:
+
+```ruby
+Dir.glob('*').size # => 241
+Dir.glob('\*').size # => 0
+```
+
+#### Constant File::FNM_SHORTNAME
+
+By default, Windows shortname matching is disabled;
+use constant [`File::FNM_SHORTNAME`](#constant-filefnmshortname)
+to enable it (on Windows only).
+
+Using that constant allows patterns to match short names
+in filename globbing on Windows,
+which can be useful for compatibility with legacy applications
+that rely on these short names;
+see [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename).
+This feature helps ensure that file operations work correctly
+even when dealing with files that have long names.
+
+### `sort`
+
+Optional keyword argument `sort` (defaults to `'true'`)
+specifies whether the returned array is to be sorted:
+
+```ruby
+Dir.glob('*').take(3)
+# => ["BSDL", "CONTRIBUTING.md", "COPYING"]
+Dir.glob('*', sort: false).take(3)
+# => ["gc.rb", "yjit.rb", "iseq.h"]
+```
+
diff --git a/doc/file/filename_matching.md b/doc/file/filename_matching.md
new file mode 100644
index 0000000000..9f13da9012
--- /dev/null
+++ b/doc/file/filename_matching.md
@@ -0,0 +1,356 @@
+## Filename Matching
+
+Filename matching is a pattern-matching feature implemented in certain Ruby methods:
+
+- File.fnmatch.
+- Pathname#fnmatch.
+
+Each `fnmatch` method matches a pattern against a string _path_;
+these methods operate only on strings, and do not access the file system.
+
+These are quite different from filename globbing methods (not discussed here),
+which match patterns against string paths found in the actual file system:
+
+- Dir.glob.
+- Pathname.glob.
+- Pathname#glob.
+
+### Patterns
+
+These are the basic elements of filename matching patterns;
+see the sections below for details:
+
+| Pattern | Meaning | Examples |
+|:------------------------:|--------------------------------------------|------------------------------|
+| Simple string. | Matches itself. | `'Rakefile'`, `'LEGAL'` |
+| `'*'` | Matches any sequence of characters. | `'*.txt'` |
+| `'?'` | Matches any single character. | `'?.txt'` |
+| `'[abc]'`,<br>`'[^abc]'` | Matches a single character from a set. | `'x[abc]y'`,<br>`'x[^abc]y'` |
+| `'[a-z]`',<br>`'[^a-z]'` | Matches a single character from a range. | `'x[0-9]y'`,<br>`'x[^0-9]y'` |
+| `'\'` | Escapes the next character. | `'\\*'`, `'\?'` |
+
+There are two other patterns that are disabled by default:
+
+- Directory-like substring (`'**'`);
+ see [`File::FNM_PATHNAME`](#constant-filefnmpathname) below.
+- Alternatives (`'{ , }'`);
+ see [`File::FNM_EXTGLOB`](#constant-filefnmextglob) below.
+
+#### Simple \String
+
+A "simple string" is one that does not contain special filename-matching patterns;
+see the table above.
+
+A simple string matches itself:
+
+```ruby
+File.fnmatch('xyzzy', 'xyzzy') # => true
+File.fnmatch('one_two_three', 'one_two_three') # => true
+File.fnmatch('123', '123') # => true
+File.fnmatch('Form 27B/6', 'Form 27B/6') # => true
+File.fnmatch('bcd', 'abcde') # => false # Must be exact.
+```
+
+By default, the matching is case-sensitive:
+
+```ruby
+File.fnmatch('abc', 'ABC') # => false
+```
+
+Case-sensitivity may be modified by flags:
+
+- [`File::FNM_CASEFOLD`](#constant-filefnmcasefold).
+- [`File::FNM_SYSCASE`](#constant-filefnmsyscase).
+
+By default, the alternatives pattern is disabled:
+
+```rutby
+File.fnmatch('R{ub,foo}y', 'Ruby') # => false
+```
+
+It may be enabled by flag [`File::FNM_EXTGLOB`](#constant-filefnmextglob).
+
+By default, the Windows short name pattern is disabled:
+
+```ruby
+File.fnmatch('PROGRAM~1', 'Program Files') # => false
+```
+
+It may be enabled by flag [`File::FNM_SHORTNAME`](#constant-filefnmshortname).
+
+#### Any Sequence of Characters (`'*'`)
+
+The asterisk pattern (`'*'`) matches any sequence of characters:
+
+```ruby
+File.fnmatch('*', 'foo') # => true
+File.fnmatch('*', '') # => true
+File.fnmatch('*', '*') # => true
+File.fnmatch('\*', 'foo') # => false # Escaped.
+```
+
+By default, the asterisk pattern does not match a leading period (as in a dot-file):
+
+```ruby
+File.fnmatch('*', '.document') # => false
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+By default, the asterisk pattern matches across file separators:
+
+```ruby
+File.fnmatch('*.rb', 'lib/test.rb') # => true
+```
+
+That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname).
+
+#### Single Character (`'?'`)
+
+The question-mark pattern (`'?'`) matches any single character:
+
+```ruby
+File.fnmatch('?', 'f') # => true
+File.fnmatch("foo-?.txt", "foo-1.txt") # => true
+File.fnmatch('?', 'foo') # => false
+File.fnmatch('?', '') # => false
+File.fnmatch('\?', 'f') # => false # Escaped.
+```
+
+By default, pattern `'?'` matches the file separator:
+
+```ruby
+File.fnmatch('foo?boo', 'foo/boo') # => true
+```
+
+That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname).
+
+#### Single Character from a Set (`'[abc]'`, `'[^abc]'`)
+
+Characters enclosed in square brackets define a set of characters,
+any of which matches a single character:
+
+```ruby
+File.fnmatch('[ruby]', 'r') # => true
+File.fnmatch('[ruby]', 'u') # => true
+File.fnmatch('[ruby]', 'y') # => true
+File.fnmatch('[ruby]', 'ruby') # => false
+File.fnmatch('\[ruby]', 'r') # => false # Escaped.
+```
+
+The character set may be negated:
+
+```ruby
+File.fnmatch('[^ruby]', 'r') # => false
+File.fnmatch('[^ruby]', 'u') # => false
+```
+
+#### Single Character from a \Range (`'[a-c]'`, `'[^a-c]'`)
+
+A range of characters enclosed in square brackets defines a set of characters,
+any of which matches a single character:
+
+```ruby
+File.fnmatch('[a-c]', 'b') # => true
+File.fnmatch('[a-c]', 'd') # => false
+File.fnmatch('[a-c]', 'abc') # => false
+File.fnmatch('R[t-v][a-c]y', 'Ruby') # => true # Multiple ranges allowed.
+File.fnmatch('\[a-c]', 'b') # => false # Escaped.
+```
+
+The range may be negated:
+
+```ruby
+File.fnmatch('[^a-c]', 'b') # => false
+File.fnmatch('[^a-c]', 'd') # => true
+```
+
+#### Escape (`'\'`)
+
+The backslash character (`'\'`) may be used to escape any of the characters
+that filename matching treats as special:
+
+```ruby
+File.fnmatch('[a-c]', 'b') # => true
+File.fnmatch('\[a-c]', 'b') # => false
+File.fnmatch('[a-c\]', 'b') # => false
+File.fnmatch('[a\-c]', 'b') # => false
+
+File.fnmatch('{a,b}', 'b', File::FNM_EXTGLOB) # => true
+File.fnmatch('\{a,b}', 'b', File::FNM_EXTGLOB) # => false
+File.fnmatch('{a\,b}', 'b', File::FNM_EXTGLOB) # => false
+File.fnmatch('{a,b\}', 'b', File::FNM_EXTGLOB) # => false
+```
+
+Use a double-backslash to represent an ordinary backslash:
+
+```ruby
+File.fnmatch('\\\\', '\\') # => true
+```
+
+By default escape pattern `'\'` is enabled;
+it may be disabled by flag [`File::FNM_NOESCAPE`](#constant-filefnmnoescape).
+
+### Flags
+
+Optional argument `flags` (defaults to `0`) may be the bitwise OR
+of the constants `File::FNM*`.
+
+These are the constants for filename-matching patterns;
+see the sections below for details:
+
+| Constant | Meaning |
+|-----------------------------------------------------|-------------------------------------------------------------|
+| [`File::FNM_CASEFOLD`](#constant-filefnmcasefold) | Make the pattern case-insensitive. |
+| [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch) | Make pattern `*` match a leading period.. |
+| [`File::FNM_EXTGLOB`](#constant-filefnmextglob) | Enable alternatives in pattern. |
+| [`File::FNM_NOESCAPE`](#constant-filefnmnoescape) | Disable escaping. |
+| [`File::FNM_PATHNAME`](#constant-filefnmpathname) | Make patterns `'*'` and `'?'` not match the file separator. |
+| [`File::FNM_SHORTNAME`](#constant-filefnmshortname) | Enable short-name matching (Windows only). |
+| [`File::FNM_SYSCASE`](#constant-filefnmsyscase) | Make the pattern use OS's case sensitivity. |
+
+
+#### Constant File::FNM_CASEFOLD
+
+By default, filename matching is case-sensitive;
+use constant [`File::FNM_CASEFOLD`](#constant-filefnmcasefold)
+to make the matching case-insensitive:
+
+```ruby
+File.fnmatch('abc', 'ABC') # => false
+File.fnmatch('abc', 'ABC', File::FNM_CASEFOLD) # => true
+```
+
+#### Constant File::FNM_DOTMATCH
+
+By default, filename matching does not allow pattern `'*'` to match a dotfile name
+(i.e, a filename beginning with a dot);
+use constant [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch)
+to enable the match:
+
+```ruby
+File.fnmatch('*', '.document') # => false
+File.fnmatch('*', '.document', File::FNM_DOTMATCH) # => true
+```
+#### Constant File::FNM_EXTGLOB
+
+By default, filename matching has the alternative notation disabled;
+use constant [`File::FNM_EXTGLOB`](#constant-filefnmextglob)
+to enable it:
+
+```ruby
+File.fnmatch('R{ub,foo}y', 'Ruby') # => false
+File.fnmatch('R{ub,foo}y', 'Ruby', File::FNM_EXTGLOB) # => true
+```
+
+The alternatives pattern consists of zero or more unquoted strings,
+separated by commas, and enclosed in curly braces:
+
+```ruby
+File.fnmatch('R{ub,foo,bar}y', 'Ruby') # => false # Not enabled.
+File.fnmatch('R{ub,foo,bar}y', 'Ruby', File::FNM_EXTGLOB) # => true
+# Whitespace matters.
+File.fnmatch('R{ub ,foo,bar}y', 'Ruby', File::FNM_EXTGLOB) # => false
+File.fnmatch('R{ ub,foo,bar}y', 'Ruby', File::FNM_EXTGLOB) # => false
+# Special characters remain in force:
+File.fnmatch('{*,?}', 'hello', File::FNM_EXTGLOB) # => true
+File.fnmatch('{*ello,?}', 'hello', File::FNM_EXTGLOB) # => true
+File.fnmatch('{*ELLO,?}', 'hello', File::FNM_EXTGLOB) # => false
+File.fnmatch('{*ELLO,?????}', 'hello', File::FNM_EXTGLOB) # => true
+# With the flag not given.
+File.fnmatch('R{ub,foo,bar}y', 'Ruby') # => false
+```
+
+#### Constant File::FNM_NOESCAPE
+
+By default filename matching has escaping enabled;
+use constant [`File::FNM_NOESCAPE`](#constant-filefnmnoescape)
+to disable it:
+
+```ruby
+File.fnmatch('\*\?\*\*', '*?**') # => true
+File.fnmatch('\*\?\*\*', '*?**', File::FNM_NOESCAPE) # => false
+```
+
+#### Constant File::FNM_PATHNAME
+
+Flag [`File::FNM_PATHNAME`](#constant-filefnmpathname) affects
+patterns `'**'`, `'*'`, and `'?'`.
+
+By default, the double-asterisk pattern (`'**'`) is equivalent to pattern `'*'`,
+and matches any sequence of directory-like substrings:
+
+```ruby
+File.fnmatch('**', 'a/b/c') # => true
+File.fnmatch('*', 'a/b/c') # => true
+```
+
+When flag [`File::FNM_PATHNAME`](#constant-filefnmpathname) is given,
+the pattern matches only one component of a file path:
+
+```ruby
+File.fnmatch('**', 'a/b/c') # => true # Matches 'a/b/c'.
+File.fnmatch('**', 'a/b/c', File::FNM_PATHNAME) # => false # Matches only 'a'.
+File.fnmatch('**', 'a/b/c', File::FNM_PATHNAME) # => false # Matches only 'a/b'.
+File.fnmatch('**/*', 'a/b/c', File::FNM_PATHNAME) # => true # Matches 'a/b', then 'c'.
+```
+
+By default, filename matching enables pattern `'*'` to match
+at or across the file separator (`File::SEPARATOR`);
+use constant [`File::FNM_PATHNAME`](#constant-filefnmpathname)
+to disable such matching:
+
+```ruby
+File::SEPARATOR # => "/"
+File.fnmatch('*.rb', 'lib/test.rb') # => true
+File.fnmatch('*.rb', 'lib/test.rb', File::FNM_PATHNAME) # => false
+```
+
+By default, filename matching enables pattern `'?'` to match
+at or across the file separator (`File::SEPARATOR`);
+use constant [`File::FNM_PATHNAME`](#constant-filefnmpathname)
+to disable such matching:
+
+```ruby
+File.fnmatch('foo?boo', 'foo/boo') # => true
+File.fnmatch('foo?boo', 'foo/boo', File::FNM_PATHNAME) # => false
+```
+
+#### Constant File::FNM_SHORTNAME
+
+By default, Windows shortname matching is disabled;
+use constant [`File::FNM_SHORTNAME`](#constant-filefnmshortname)
+to enable it (on Windows only).
+
+Using that constant allows patterns to match short names
+in filename matching on Windows,
+which can be useful for compatibility with legacy applications
+that rely on these short names;
+see [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename).
+This feature helps ensure that file operations work correctly
+even when dealing with files that have long names.
+
+```ruby
+File::FNM_SHORTNAME.zero? # => false # On Windows, not zero; may be enabled.
+File::FNM_SHORTNAME.zero? # => true # Elsewhere, always zero; may not be enabled.
+
+File.fnmatch('PROGRAM~1', 'Program Files') # => false
+# This will be true if and only if on Windows and short name 'PROGRAM~1' exists.
+File.fnmatch('PROGRAM~1', 'Program Files', File::FNM_SHORTNAME) # => true
+```
+
+#### Constant File::FNM_SYSCASE
+
+By default, filename matching uses Ruby's own case-sensitivity rules;
+use constant [`File::FNM_SYSCASE`](#constant-filefnmsyscase)
+to use the case-sensitivity rules of the underlying file system:
+
+```ruby
+File::FNM_SYSCASE.zero? # => false # On Windows, not zero; may be enabled.
+File::FNM_SYSCASE.zero? # => true # Elsewhere, always zero; may not be enabled.
+
+File.fnmatch('abc', 'ABC') # => false # Ruby; case-sensitive.
+File.fnmatch('abc', 'ABC', File::FNM_SYSCASE) # => true # Windows; case-insensitive.
+File.fnmatch('abc', 'ABC', File::FNM_SYSCASE) # => false # Linus; case-sensitive.
+```
+
diff --git a/doc/file/timestamps.md b/doc/file/timestamps.md
new file mode 100644
index 0000000000..c8ad616567
--- /dev/null
+++ b/doc/file/timestamps.md
@@ -0,0 +1,83 @@
+# \File System Timestamps
+
+A file system entry (the name of a file or directory)
+has several times (called timestamps) associated with it.
+
+The Ruby methods that return these timestamps (each as a Time object)
+are actually returning "whatever the OS says,"
+and so their behaviors may vary among OS platforms.
+If a platform does not support a particular timestamp,
+the corresponding Ruby methods raise NotImplementedError.
+
+These timestamps are:
+
+| Name | Meaning | Changes |
+|:--------------------------------:|----------------------------------------|-----------------------|
+| [`birthtime`](#birth-time) | Create time. | Never. |
+| [`mtime`](#modification-time) | Modification time. | When written. |
+| [`atime`](#access-time) | Access time. | When read or written. |
+| [`ctime`](#metadata-change-time) | Metadata-change time (or create time). | See below. |
+
+## Birth \Time
+
+The birth time for an entry is the time the entry was created.
+The birth time does not change, although if the entry is deleted and re-created,
+the birth time will be different.
+
+Each of these methods returns the birth time for an entry as a Time object:
+
+- File::birthtime.
+- File#birthtime.
+- File::Stat#birthtime.
+- Pathname#birthtime.
+
+On Windows, each of these methods also returns the birth time:
+
+- File::ctime.
+- File#ctime.
+- File::Stat#ctime.
+- Pathname#ctime.
+
+## Modification \Time
+
+The modification time for an entry is the time the entry was last modified.
+The modification time is updated when the entry is written,
+though some file systems may delay the update.
+
+Each of these methods returns the modification time for an entry as a Time object:
+
+- File::mtime.
+- File#mtime.
+- File::Stat#mtime.
+- Pathname#mtime.
+
+## Access \Time
+
+The access time for an entry is the time the entry last read.
+The access time is updated when the entry is read,
+though some file systems may delay the update.
+
+Each of these methods returns the access time for an entry as a Time object:
+
+- File::atime.
+- File#atime.
+- File::Stat#atime.
+- Pathname#atime.
+
+## Metadata-Change \Time
+
+The metadata-change time for an entry is the time the entry last read.
+The metadata-change time is updated when the entry's metadata is changed;
+changing access mode or permissions may update the metadata-change time,
+though some file systems may delay the update.
+
+On non-Windows systems,
+each of these methods returns the metadata-change time for an entry:
+
+- File::ctime.
+- File#ctime.
+- File::Stat#ctime.
+- Pathname#ctime.
+
+On Windows, each `ctime` method returns the birth time,
+not the metadata-change time.
diff --git a/doc/float.rb b/doc/float.rb
new file mode 100644
index 0000000000..93b57ebc4c
--- /dev/null
+++ b/doc/float.rb
@@ -0,0 +1,128 @@
+# A \Float object stores a real number
+# using the native architecture's double-precision floating-point representation.
+#
+# == \Float Imprecisions
+#
+# Some real numbers can be represented precisely as \Float objects:
+#
+# 37.5 # => 37.5
+# 98.75 # => 98.75
+# 12.3125 # => 12.3125
+#
+# Others cannot; among these are the transcendental numbers, including:
+#
+# - Pi, <i>π</i>: in mathematics, a number of infinite precision:
+# 3.1415926535897932384626433... (to 25 places);
+# in Ruby, it is of limited precision (in this case, to 16 decimal places):
+#
+# Math::PI # => 3.141592653589793
+#
+# - Euler's number, <i>e</i>: in mathematics, a number of infinite precision:
+# 2.7182818284590452353602874... (to 25 places);
+# in Ruby, it is of limited precision (in this case, to 15 decimal places):
+#
+# Math::E # => 2.718281828459045
+#
+# Some floating-point computations in Ruby give precise results:
+#
+# 1.0/2 # => 0.5
+# 100.0/8 # => 12.5
+#
+# Others do not:
+#
+# - In mathematics, 2/3 as a decimal number is an infinitely-repeating decimal:
+# 0.666... (forever);
+# in Ruby, +2.0/3+ is of limited precision (in this case, to 16 decimal places):
+#
+# 2.0/3 # => 0.6666666666666666
+#
+# - In mathematics, the square root of 2 is an irrational number of infinite precision:
+# 1.4142135623730950488016887... (to 25 decimal places);
+# in Ruby, it is of limited precision (in this case, to 16 decimal places):
+#
+# Math.sqrt(2.0) # => 1.4142135623730951
+#
+# - Even a simple computation can introduce imprecision:
+#
+# x = 0.1 + 0.2 # => 0.30000000000000004
+# y = 0.3 # => 0.3
+# x == y # => false
+#
+# See:
+#
+# - https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
+# - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#user-content--why-are-rubys-floats-imprecise
+# - https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
+#
+# Note that precise storage and computation of rational numbers
+# is possible using Rational objects.
+#
+# == Creating a \Float
+#
+# You can create a \Float object explicitly with:
+#
+# - A {floating-point literal}[rdoc-ref:syntax/literals.rdoc@Float+Literals].
+#
+# You can convert certain objects to Floats with:
+#
+# - Method #Float.
+#
+# == What's Here
+#
+# First, what's elsewhere. Class \Float:
+#
+# - Inherits from
+# {class Numeric}[rdoc-ref:Numeric@Whats+Here]
+# and {class Object}[rdoc-ref:Object@Whats+Here].
+# - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
+#
+# Here, class \Float provides methods for:
+#
+# - {Querying}[rdoc-ref:Float@Querying]
+# - {Comparing}[rdoc-ref:Float@Comparing]
+# - {Converting}[rdoc-ref:Float@Converting]
+#
+# === Querying
+#
+# - #finite?: Returns whether +self+ is finite.
+# - #hash: Returns the integer hash code for +self+.
+# - #infinite?: Returns whether +self+ is infinite.
+# - #nan?: Returns whether +self+ is a NaN (not-a-number).
+#
+# === Comparing
+#
+# - #<: Returns whether +self+ is less than the given value.
+# - #<=: Returns whether +self+ is less than or equal to the given value.
+# - #<=>: Returns a number indicating whether +self+ is less than, equal
+# to, or greater than the given value.
+# - #== (aliased as #=== and #eql?): Returns whether +self+ is equal to
+# the given value.
+# - #>: Returns whether +self+ is greater than the given value.
+# - #>=: Returns whether +self+ is greater than or equal to the given value.
+#
+# === Converting
+#
+# - #% (aliased as #modulo): Returns +self+ modulo the given value.
+# - #*: Returns the product of +self+ and the given value.
+# - #**: Returns the value of +self+ raised to the power of the given value.
+# - #+: Returns the sum of +self+ and the given value.
+# - #-: Returns the difference of +self+ and the given value.
+# - #/: 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+
+# - #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.
+# - #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.
+# - #quo: Returns the quotient from dividing +self+ by the given value.
+# - #round: Returns +self+ rounded to the nearest value, to a given precision.
+# - #to_i (aliased as #to_int): Returns +self+ truncated to an Integer.
+# - #to_s (aliased as #inspect): Returns a string containing the place-value
+# representation of +self+ in the given radix.
+# - #truncate: Returns +self+ truncated to a given precision.
+#
+
+ class Float; end
diff --git a/doc/format_specifications.rdoc b/doc/format_specifications.rdoc
deleted file mode 100644
index bdfdc24953..0000000000
--- a/doc/format_specifications.rdoc
+++ /dev/null
@@ -1,350 +0,0 @@
-= Format Specifications
-
-Several Ruby core classes have instance method +printf+ or +sprintf+:
-
-- ARGF#printf
-- IO#printf
-- Kernel#printf
-- Kernel#sprintf
-
-Each of these methods takes:
-
-- Argument +format_string+, which has zero or more
- embedded _format_ _specifications_ (see below).
-- Arguments <tt>*arguments</tt>, which are zero or more objects to be formatted.
-
-Each of these methods prints or returns the string
-resulting from replacing each
-format specification embedded in +format_string+ with a string form
-of the corresponding argument among +arguments+.
-
-A simple example:
-
- sprintf('Name: %s; value: %d', 'Foo', 0) # => "Name: Foo; value: 0"
-
-A format specification has the form:
-
- %[flags][width][.precision]type
-
-It consists of:
-
-- A leading percent character.
-- Zero or more _flags_ (each is a character).
-- An optional _width_ _specifier_ (an integer).
-- An optional _precision_ _specifier_ (a period followed by a non-negative integer).
-- A _type_ _specifier_ (a character).
-
-Except for the leading percent character,
-the only required part is the type specifier, so we begin with that.
-
-== Type Specifiers
-
-This section provides a brief explanation of each type specifier.
-The links lead to the details and examples.
-
-=== \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].
-- +d+, +i+, or +u+ (all are identical):
- Format +argument+ as a decimal integer.
- See {Specifier d}[rdoc-ref:format_specifications.rdoc@Specifier+d].
-- +o+: Format +argument+ as an octal integer.
- See {Specifier o}[rdoc-ref:format_specifications.rdoc@Specifier+o].
-- +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
-
-- +a+ or +A+: Format +argument+ as hexadecimal floating-point number.
- See {Specifiers a and A}[rdoc-ref:format_specifications.rdoc@Specifiers+a+and+A].
-- +e+ or +E+: Format +argument+ in scientific notation.
- See {Specifiers e and E}[rdoc-ref:format_specifications.rdoc@Specifiers+e+and+E].
-- +f+: Format +argument+ as a decimal floating-point number.
- See {Specifier f}[rdoc-ref:format_specifications.rdoc@Specifier+f].
-- +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
-
-- +c+: Format +argument+ as a character.
- See {Specifier c}[rdoc-ref:format_specifications.rdoc@Specifier+c].
-- +p+: Format +argument+ as a string via <tt>argument.inspect</tt>.
- See {Specifier p}[rdoc-ref:format_specifications.rdoc@Specifier+p].
-- +s+: Format +argument+ as a string via <tt>argument.to_s</tt>.
- See {Specifier s}[rdoc-ref:format_specifications.rdoc@Specifier+s].
-- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character.
- See {Specifier %}[rdoc-ref:format_specifications.rdoc@Specifier+-25].
-
-== Flags
-
-The effect of a flag may vary greatly among type specifiers.
-These remarks are general in nature.
-See {type-specific details}[rdoc-ref:format_specifications.rdoc@Type+Specifier+Details+and+Examples].
-
-Multiple flags may be given with single type specifier;
-order does not matter.
-
-=== <tt>' '</tt> Flag
-
-Insert a space before a non-negative number:
-
- sprintf('%d', 10) # => "10"
- sprintf('% d', 10) # => " 10"
-
-Insert a minus sign for negative value:
-
- sprintf('%d', -10) # => "-10"
- sprintf('% d', -10) # => "-10"
-
-=== <tt>'#'</tt> Flag
-
-Use an alternate format; varies among types:
-
- sprintf('%x', 100) # => "64"
- sprintf('%#x', 100) # => "0x64"
-
-=== <tt>'+'</tt> Flag
-
-Add a leading plus sign for a non-negative number:
-
- sprintf('%x', 100) # => "64"
- sprintf('%+x', 100) # => "+64"
-
-=== <tt>'-'</tt> Flag
-
-Left justify the value in its field:
-
- sprintf('%6d', 100) # => " 100"
- sprintf('%-6d', 100) # => "100 "
-
-=== <tt>'0'</tt> Flag
-
-Left-pad with zeros instead of spaces:
-
- sprintf('%6d', 100) # => " 100"
- sprintf('%06d', 100) # => "000100"
-
-=== <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
-
-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
-
-In general, a width specifier determines the minimum width (in characters)
-of the formatted field:
-
- sprintf('%10d', 100) # => " 100"
-
- # Left-justify if negative.
- sprintf('%-10d', 100) # => "100 "
-
- # Ignore if too small.
- sprintf('%1d', 100) # => "100"
-
-== Precision Specifier
-
-A precision specifier is a decimal point followed by zero or more
-decimal digits.
-
-For integer type specifiers, the precision specifies the minimum number of
-digits to be written. If the precision is shorter than the integer, the result is
-padded with leading zeros. There is no modification or truncation of the result
-if the integer is longer than the precision:
-
- sprintf('%.3d', 1) # => "001"
- sprintf('%.3d', 1000) # => "1000"
-
- # If the precision is 0 and the value is 0, nothing is written
- sprintf('%.d', 0) # => ""
- sprintf('%.0d', 0) # => ""
-
-For the +a+/+A+, +e+/+E+, +f+/+F+ specifiers, the precision specifies
-the number of digits after the decimal point to be written:
-
- sprintf('%.2f', 3.14159) # => "3.14"
- sprintf('%.10f', 3.14159) # => "3.1415900000"
-
- # With no precision specifier, defaults to 6-digit precision.
- sprintf('%f', 3.14159) # => "3.141590"
-
-For the +g+/+G+ specifiers, the precision specifies
-the number of significant digits to be written:
-
- sprintf('%.2g', 123.45) # => "1.2e+02"
- sprintf('%.3g', 123.45) # => "123"
- sprintf('%.10g', 123.45) # => "123.45"
-
- # With no precision specifier, defaults to 6 significant digits.
- sprintf('%g', 123.456789) # => "123.457"
-
-For the +s+, +p+ specifiers, the precision specifies
-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
-
-=== Specifiers +a+ and +A+
-
-Format +argument+ as hexadecimal floating-point number:
-
- sprintf('%a', 3.14159) # => "0x1.921f9f01b866ep+1"
- sprintf('%a', -3.14159) # => "-0x1.921f9f01b866ep+1"
- sprintf('%a', 4096) # => "0x1p+12"
- sprintf('%a', -4096) # => "-0x1p+12"
-
- # Capital 'A' means that alphabetical characters are printed in upper case.
- sprintf('%A', 4096) # => "0X1P+12"
- sprintf('%A', -4096) # => "-0X1P+12"
-
-=== Specifiers +b+ and +B+
-
-The two specifiers +b+ and +B+ behave identically
-except when flag <tt>'#'</tt>+ is used.
-
-Format +argument+ as a binary integer:
-
- sprintf('%b', 1) # => "1"
- sprintf('%b', 4) # => "100"
-
- # Prefix '..' for negative value.
- sprintf('%b', -4) # => "..100"
-
- # Alternate format.
- sprintf('%#b', 4) # => "0b100"
- sprintf('%#B', 4) # => "0B100"
-
-=== Specifier +c+
-
-Format +argument+ as a single character:
-
- sprintf('%c', 'A') # => "A"
- sprintf('%c', 65) # => "A"
-
-This behaves like String#<<, except for raising ArgumentError instead of RangeError.
-
-=== Specifier +d+
-
-Format +argument+ as a decimal integer:
-
- sprintf('%d', 100) # => "100"
- sprintf('%d', -100) # => "-100"
-
-Flag <tt>'#'</tt> does not apply.
-
-=== Specifiers +e+ and +E+
-
-Format +argument+ in
-{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]:
-
- sprintf('%e', 3.14159) # => "3.141590e+00"
- sprintf('%E', -3.14159) # => "-3.141590E+00"
-
-=== Specifier +f+
-
-Format +argument+ as a floating-point number:
-
- sprintf('%f', 3.14159) # => "3.141590"
- sprintf('%f', -3.14159) # => "-3.141590"
-
-Flag <tt>'#'</tt> does not apply.
-
-=== 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.
-Otherwise format +argument+ using floating-point form (+f+ specifier):
-
- sprintf('%g', 100) # => "100"
- sprintf('%g', 100.0) # => "100"
- sprintf('%g', 3.14159) # => "3.14159"
- sprintf('%g', 100000000000) # => "1e+11"
- sprintf('%g', 0.000000000001) # => "1e-12"
-
- # Capital 'G' means use capital 'E'.
- sprintf('%G', 100000000000) # => "1E+11"
- sprintf('%G', 0.000000000001) # => "1E-12"
-
- # Alternate format.
- sprintf('%#g', 100000000000) # => "1.00000e+11"
- sprintf('%#g', 0.000000000001) # => "1.00000e-12"
- sprintf('%#G', 100000000000) # => "1.00000E+11"
- sprintf('%#G', 0.000000000001) # => "1.00000E-12"
-
-=== Specifier +o+
-
-Format +argument+ as an octal integer.
-If +argument+ is negative, it will be formatted as a two's complement
-prefixed with +..7+:
-
- sprintf('%o', 16) # => "20"
-
- # Prefix '..7' for negative value.
- sprintf('%o', -16) # => "..760"
-
- # Prefix zero for alternate format if positive.
- sprintf('%#o', 16) # => "020"
- sprintf('%#o', -16) # => "..760"
-
-=== 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+
-
-Format +argument+ as a string via <tt>argument.to_s</tt>:
-
- t = Time.now
- sprintf('%s', t) # => "2022-05-01 13:42:07 -0500"
-
-Flag <tt>'#'</tt> does not apply.
-
-=== Specifiers +x+ and +X+
-
-Format +argument+ as a hexadecimal integer.
-If +argument+ is negative, it will be formatted as a two's complement
-prefixed with +..f+:
-
- sprintf('%x', 100) # => "64"
-
- # Prefix '..f' for negative value.
- sprintf('%x', -100) # => "..f9c"
-
- # Use alternate format.
- sprintf('%#x', 100) # => "0x64"
-
- # Alternate format for negative value.
- sprintf('%#x', -100) # => "0x..f9c"
-
-=== Specifier <tt>%</tt>
-
-Format +argument+ (<tt>'%'</tt>) as a single percent character:
-
- sprintf('%d %%', 100) # => "100 %"
-
-Flags do not apply.
-
-== Reference by Name
-
-For more complex formatting, Ruby supports a reference by name.
-%<name>s style uses format style, but %{name} style doesn't.
-
-Examples:
-
- sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
- sprintf("%{foo}f", { :foo => 1 }) # => "1f"
diff --git a/doc/forwardable.rd.ja b/doc/forwardable.rd.ja
deleted file mode 100644
index 53e8202513..0000000000
--- a/doc/forwardable.rd.ja
+++ /dev/null
@@ -1,80 +0,0 @@
- -- forwardable.rb
- $Release Version: 1.1 $
- $Revision$
-
-=begin
-= Forwardable
-
-クラスに対しメソッドの委譲機能を定義します.
-
-== 使い方
-
-クラスに対してextendして使います.
-
- class Foo
- extend Forwardable
-
- def_delegators("@out", "printf", "print")
- def_delegators(:@in, :gets)
- def_delegator(:@contents, :[], "content_at")
- end
- f = Foo.new
- f.printf ...
- f.gets
- f.content_at(1)
-
-== メソッド
-
---- Forwardable#def_instance_delegators(accessor, *methods)
-
- ((|methods|))で渡されたメソッドのリストを((|accessorに|))委譲する
- ようにします.
-
---- Forwardable#def_instance_delegator(accessor, method, ali = method)
-
- ((||method|))で渡されたメソッドを((|accessor|))に委譲するようにし
- ます. ((|ali|))が引数として渡されたときは, メソッド((|ali|))が呼ば
- れたときには, ((|accessor|))に対し((|method|))を呼び出します.
-
---- Forwardable#def_delegators(accessor, *methods)
-
- ((|Forwardable#def_instance_delegators|))の別名です.
-
---- Forwardable#def_delegator(accessor, method, ali = method)
-
- ((|Forwardable#def_instance_delegator|))の別名です.
-
-= SingleForwardable
-
-オブジェクトに対し, メソッドの委譲機能を定義します.
-
-== 使い方
-
-オブジェクトに対して((|extend|))して使います.
-
- g = Goo.new
- g.extend SingleForwardable
- g.def_delegator("@out", :puts)
- g.puts ...
-
-== メソッド
-
---- SingleForwardable#def_singleton_delegators(accessor, *methods)
-
- ((|methods|))で渡されたメソッドのリストを((|accessor|))に委譲する
- ようにします.
-
---- SingleForwardable#def_singleton_delegator(accessor, method, ali = method)
-
- ((|method|))で渡されたメソッドを((|accessor|))に委譲するようにしま
- す. ((|ali|))が引数として渡されたときは, メソッド((|ali|))が呼ばれ
- たときには, ((|accessor|))に対し((|method|))を呼び出します.
-
---- SingleForwardable#def_delegators(accessor, *methods)
-
- ((|SingleForwardable#def_singleton_delegators|))の別名です.
-
---- SingleForwardable#def_delegator(accessor, method, ali = method)
-
- ((|SingleForwardable#def_singleton_delegator|))の別名です.
-=end
diff --git a/doc/globals.rdoc b/doc/globals.rdoc
deleted file mode 100644
index 9d9fc57e6e..0000000000
--- a/doc/globals.rdoc
+++ /dev/null
@@ -1,416 +0,0 @@
-= Pre-Defined Global Variables
-
-Some of the pre-defined global variables have synonyms
-that are available via module English.
-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> (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>
-
-=== <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"
diff --git a/doc/jit/yjit.md b/doc/jit/yjit.md
new file mode 100644
index 0000000000..d91877c30e
--- /dev/null
+++ b/doc/jit/yjit.md
@@ -0,0 +1,547 @@
+<p align="center">
+ <a href="https://yjit.org/" target="_blank" rel="noopener noreferrer">
+ <img src="https://user-images.githubusercontent.com/224488/131155756-aa8fb528-a813-4dfd-99ac-8785c3d5eed7.png" width="400">
+ </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.
+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:ruby@shopify.com">share your success stories with us!</a>
+</b></p>
+
+If you wish to learn more about the approach taken, here are some conference talks and publications:
+
+- MPLR 2023 talk: [Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach](https://www.youtube.com/watch?v=pVRmPZcNUhc)
+- 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)
+- ECOOP 2016 paper: [Interprocedural Type Specialization of JavaScript Programs Without Type Analysis](https://drops.dagstuhl.de/opus/volltexte/2016/6101/pdf/LIPIcs-ECOOP-2016-7.pdf)
+- 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:
+
+```BibTeX
+@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},
+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}
+}
+```
+
+## 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).
+
+## Installation
+
+### Requirements
+
+You will need to install:
+
+ - All the usual build tools for Ruby. See [Building Ruby](../contributing/building_ruby.md)
+ - The Rust compiler `rustc`
+ - The Rust version must be [>= 1.58.0](../../yjit/Cargo.toml).
+ - Optionally, only if you wish to build in dev/debug mode, Rust's `cargo`
+
+If you don't intend on making code changes to YJIT itself, we recommend
+obtaining `rustc` through your OS's package manager since that
+likely reuses the same vendor which provides the C toolchain.
+
+If you will be changing YJIT's Rust code, we suggest using the
+[first-party installation method][rust-install] for Rust. Rust also provides
+first class [support][editor-tools] for many source code editors.
+
+[rust-install]: https://www.rust-lang.org/tools/install
+[editor-tools]: https://www.rust-lang.org/tools
+
+### Building YJIT
+
+Start by cloning the `ruby/ruby` repository:
+
+```sh
+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.
+See [Building Ruby](rdoc-ref:contributing/building_ruby.md@building-ruby).
+
+```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
+```
+
+or
+
+```sh
+# Configure in lower-performance 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
+```
+
+On macOS, you may need to specify where to find some libraries:
+
+```sh
+# Install dependencies
+brew install openssl 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
+```
+
+Typically configure will choose the default C compiler. To specify the C compiler, use
+
+```sh
+# Choosing a specific c compiler
+export CC=/path/to/my/chosen/c/compiler
+```
+
+before running `./configure`.
+
+You can test that YJIT works correctly by running:
+
+```sh
+# Quick tests found in /bootstraptest
+make btest
+
+# Complete set of tests
+make -j test-all
+```
+
+## Usage
+
+### Examples
+
+Once YJIT is built, you can either use `./miniruby` from within your build directory, or switch to the YJIT version of `ruby`
+by using the `chruby` tool:
+
+```sh
+chruby ruby-yjit
+ruby myscript.rb
+```
+
+You can dump statistics about compilation and execution by running YJIT with the `--yjit-stats` command-line option:
+
+```sh
+./miniruby --yjit-stats myscript.rb
+```
+
+You can see what YJIT has compiled by running YJIT with the `--yjit-log` command-line option:
+
+```sh
+./miniruby --yjit-log myscript.rb
+```
+
+The machine code generated for a given method can be printed by adding `puts RubyVM::YJIT.disasm(method(:method_name))` to a Ruby script. Note that no code will be generated if the method is not compiled.
+
+<h3 id="command-line-options">Command-Line Options</h3>
+
+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-mem-size=N`: soft limit on YJIT memory usage in MiB (default: 128). Tries to limit `code_region_size + yjit_alloc_size`
+- `--yjit-exec-mem-size=N`: hard limit on executable memory block in MiB. Limits `code_region_size`
+- `--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-log[=file|dir]`: log all compilation events to the specified file or directory. If no name is supplied, the last 1024 log entries will be printed to stderr when the application exits.
+- `--yjit-log=quiet`: gather a circular buffer of recent YJIT compilations. The compilation log entries are accessible through `RubyVM::YJIT.log` and old entries will be discarded if the buffer is not drained quickly. (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 all exits. Automatically enables `--yjit-stats`
+- `--yjit-trace-exits=COUNTER`: produce a Marshal dump of backtraces from a counted exit or a fallback. Automatically enables `--yjit-stats`
+- `--yjit-trace-exits-sample-rate=N`: trace exit locations only every Nth occurrence. Automatically enables `--yjit-trace-exits`
+
+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-mem-size
+
+The `--yjit-mem-size` value can be used to set the maximum amount of memory that YJIT
+is allowed to use. This corresponds to the total of `RubyVM::YJIT.runtime_stats[:code_region_size]`
+and `RubyVM::YJIT.runtime_stats[:yjit_alloc_size]`
+Increasing the `--yjit-mem-size` value 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 percentage of total YARV instructions
+executed by YJIT as opposed to the CRuby interpreter.
+Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-mem-size` often
+helps improving `ratio_in_yjit`.
+
+### Running workers as long as possible
+
+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.
+
+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.
+
+## 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-mem-size
+
+YJIT uses memory for compiled code and metadata. You can change the maximum amount of memory
+that YJIT can use by specifying a different `--yjit-mem-size` command-line option. The default value
+is currently `128`.
+When changing this value, 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`
+- 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
+- Minimize layers of indirection
+ - Avoid writing wrapper classes if you can (e.g. a class that only wraps a Ruby hash)
+ - Avoid methods that just call another method
+- Ruby method calls are costly. Avoid things such as methods that only return a value from a hash
+- Try to write code so that the same variables and method arguments always have the same type
+- Avoid using `TracePoint` as it can cause YJIT to deoptimize code
+- Avoid using `binding` as it can cause YJIT to deoptimize code
+
+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`.
+
+```rb
+$ RUBYOPT="--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,
+ :send_callsite_not_simple=>7267,
+ :send_kw_splat=>7,
+ :send_ivar_set_method=>72,
+...
+```
+
+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 main-line machine code
+* `:outlined_code_size` - size in bytes of relatively uncommonly executed machine 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.)
+
+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.
+
+The printed text after a `--yjit-stats` run includes other information that may be named differently than the information in `RubyVM::YJIT.runtime_stats`.
+
+## Contributing
+
+We welcome open source contributions. 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
+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.
+
+### Source Code Organization
+
+The YJIT source code is divided between:
+
+- `yjit.c`: code YJIT uses to interface with the rest of CRuby
+- `yjit.h`: C definitions YJIT exposes to the rest of the CRuby
+- `yjit.rb`: `YJIT` Ruby module that is exposed to Ruby
+- `yjit/src/asm/*`: in-memory assembler we use to generate machine code
+- `yjit/src/codegen.rs`: logic for translating Ruby bytecode to machine code
+- `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
+
+The core of CRuby's interpreter logic is found in:
+
+- `insns.def`: defines Ruby's bytecode instructions (gets compiled into `vm.inc`)
+- `vm_insnshelper.c`: logic used by Ruby's bytecode instructions
+- `vm_exec.c`: Ruby interpreter loop
+
+### Generating C bindings with bindgen
+
+In order to expose C functions to the Rust codebase, you will need to generate C bindings:
+
+```sh
+CC=clang ./configure --enable-yjit=dev
+make -j yjit-bindgen
+```
+
+This uses the bindgen tools to generate/update `yjit/src/cruby_bindings.inc.rs` based on the
+bindings listed in `yjit/bindgen/src/main.rs`. Avoid manually editing this file
+as it could be automatically regenerated at a later time. If you need to manually add C bindings,
+add them to `yjit/cruby.rs` instead.
+
+### Coding & Debugging Protips
+
+There are multiple test suites:
+
+- `make btest` (see `/bootstraptest`)
+- `make test-all`
+- `make test-spec`
+- `make check` runs all of the above
+- `make yjit-check` runs quick checks to see that YJIT is working correctly
+
+The tests can be run in parallel like this:
+
+```sh
+make -j test-all RUN_OPTS="--yjit-call-threshold=1"
+```
+
+Or single-threaded like this, to more easily identify which specific test is failing:
+
+```sh
+make test-all TESTOPTS=--verbose RUN_OPTS="--yjit-call-threshold=1"
+```
+
+To run a single test file with `test-all`:
+
+```sh
+make test-all TESTS='test/-ext-/marshal/test_usrmarshal.rb' RUNRUBYOPT=--debugger=lldb RUN_OPTS="--yjit-call-threshold=1"
+```
+
+It's also possible to filter tests by name to run a single test:
+
+```sh
+make test-all TESTS='-n /test_float_plus/' RUN_OPTS="--yjit-call-threshold=1"
+```
+
+You can also run one specific test in `btest`:
+
+```sh
+make btest BTESTS=bootstraptest/test_ractor.rb RUN_OPTS="--yjit-call-threshold=1"
+```
+
+There are shortcuts to run/debug your own test/repro in `test.rb`:
+
+```sh
+make run # runs ./miniruby test.rb
+make lldb # launches ./miniruby test.rb in lldb
+```
+
+You can use the Intel syntax for disassembly in LLDB, keeping it consistent with YJIT's disassembly:
+
+```sh
+echo "settings set target.x86-disassembly-flavor intel" >> ~/.lldbinit
+```
+
+## Running x86 YJIT on Apple's Rosetta
+
+For development purposes, it is possible to run x86 YJIT on an Apple M1 via Rosetta. You can find basic
+instructions below, but there are a few caveats listed further down.
+
+First, install Rosetta:
+
+```console
+$ softwareupdate --install-rosetta
+```
+
+Now any command can be run with Rosetta via the `arch` command line tool.
+
+Then you can start your shell in an x86 environment:
+
+```console
+$ arch -x86_64 zsh
+```
+
+You can double check your current architecture via the `arch` command:
+
+```console
+$ arch -x86_64 zsh
+$ arch
+i386
+```
+
+You may need to set the default target for `rustc` to x86-64, e.g.
+
+```console
+$ rustup default stable-x86_64-apple-darwin
+```
+
+While in your i386 shell, install Cargo and Homebrew, then hack away!
+
+### Rosetta Caveats
+
+1. You must install a version of Homebrew for each architecture
+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.
+
+### Call graph
+
+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
+```
+
+### YJIT codegen
+
+You can also profile the number of cycles consumed by code generated by each YJIT function.
+
+```bash
+# Install perf
+apt-get install linux-tools-common linux-tools-generic linux-tools-`uname -r`
+
+# [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=codegen
+cd ../yjit-bench
+PERF=record ruby --yjit-perf=codegen -Iharness-perf benchmarks/lobsters/benchmark.rb
+
+# Aggregate results
+perf script > /tmp/perf.txt
+../ruby/misc/jit_perf.py /tmp/perf.txt
+```
+
+#### Building perf with Python support
+
+The above instructions work fine for most people, but you could also use
+a handy `perf script -s` interface if you build perf from source.
+
+```bash
+# Build perf from source for Python support
+sudo apt-get install libpython3-dev python3-pip flex libtraceevent-dev \
+ libelf-dev libunwind-dev libaudit-dev libslang2-dev libdw-dev
+git clone --depth=1 https://github.com/torvalds/linux
+cd linux/tools/perf
+make
+make install
+
+# Aggregate results
+perf script -s ../ruby/misc/jit_perf.py
+```
diff --git a/doc/jit/zjit.md b/doc/jit/zjit.md
new file mode 100644
index 0000000000..ebe5cc4f9b
--- /dev/null
+++ b/doc/jit/zjit.md
@@ -0,0 +1,461 @@
+<p align="center">
+ <img src="https://github.com/user-attachments/assets/27abfe03-3e96-4220-b6f1-278bb0c87684" width="400">
+</p>
+
+# ZJIT: ADVANCED RUBY JIT PROTOTYPE
+
+ZJIT is a method-based just-in-time (JIT) compiler for Ruby. It uses profile
+information from the interpreter to guide optimization in the compiler.
+
+ZJIT is currently supported for macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs.
+This project is open source and falls under the same license as CRuby.
+
+## Current Limitations
+
+ZJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. ZJIT 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 [ZJIT's command-line options](rdoc-ref:@Command-Line+Options).
+
+## Contributing
+
+We welcome open source contributions. Feel free to open new issues to report
+bugs or just to ask questions. Suggestions on how to make this document more
+helpful for new contributors are most welcome.
+
+Bug fixes and bug reports are very valuable to us. If you find a bug in ZJIT,
+it's very possible that nobody has reported it before, or that we don't have
+a good reproduction for it, so please open a ticket on [the official Ruby bug
+tracker][rubybugs] (or, if you don't want to make an account, [on
+Shopify/ruby][shopifyruby]) 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 ZJIT 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.
+
+[rubybugs]: https://bugs.ruby-lang.org/projects/ruby-master
+[shopifyruby]: https://github.com/Shopify/ruby/issues
+
+If you would like to contribute a large patch to ZJIT, we suggest [chatting on
+Zulip][zulip] for a casual chat and then opening an issue on the [Shopify/ruby
+repository][shopifyruby] so that we can have a technical 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
+ZJIT.
+
+[zulip]: https://zjit.zulipchat.com/
+
+## Build Instructions
+
+Refer to [Building Ruby](rdoc-ref:contributing/building_ruby.md) for general build prerequisites.
+Additionally, ZJIT requires Rust 1.85.0 or later. Release builds need only `rustc`. Development
+builds require `cargo` and may download dependencies. GNU Make is required.
+
+### For normal use
+
+To build ZJIT on macOS:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc \
+ --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
+
+make -j miniruby
+```
+
+To build ZJIT on Linux:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc
+
+make -j miniruby
+```
+
+### For development
+
+To build ZJIT on macOS:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit=dev \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc \
+ --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
+
+make -j miniruby
+```
+
+To build ZJIT on Linux:
+
+```bash
+./autogen.sh
+
+./configure \
+ --enable-zjit=dev \
+ --prefix="$HOME"/.rubies/ruby-zjit \
+ --disable-install-doc
+
+make -j miniruby
+```
+
+Note that `--enable-zjit=dev` does a lot of IR validation, which will help to catch errors early but mean compilation and warmup are significantly slower.
+
+The valid values for `--enable-zjit` are, from fastest to slowest:
+* `--enable-zjit`: enable ZJIT in release mode for maximum performance
+* `--enable-zjit=stats`: enable ZJIT in extended-stats mode
+* `--enable-zjit=dev_nodebug`: enable ZJIT in development mode but without slow runtime checks
+* `--enable-zjit=dev`: enable ZJIT in debug mode for development, also enables `RUBY_DEBUG`
+
+### Regenerate bindings
+
+When modifying `zjit/bindgen/src/main.rs` you need to regenerate bindings in `zjit/src/cruby_bindings.inc.rs` with:
+
+```bash
+make zjit-bindgen
+```
+
+## Documentation
+
+### Command-Line Options
+
+See `ruby --help` for ZJIT-specific command-line options:
+
+```
+$ ruby --help
+...
+ZJIT options:
+ --zjit-mem-size=num
+ Max amount of memory that ZJIT can use in MiB (default: 128).
+ --zjit-call-threshold=num
+ Number of calls to trigger JIT (default: 30).
+ --zjit-num-profiles=num
+ Number of profiled calls before JIT (default: 5).
+ --zjit-stats[=quiet]
+ Enable collecting ZJIT statistics (=quiet to suppress output).
+ --zjit-disable Disable ZJIT for lazily enabling it with RubyVM::ZJIT.enable.
+ --zjit-perf Dump ISEQ symbols into /tmp/perf-{}.map for Linux perf.
+ --zjit-log-compiled-iseqs=path
+ Log compiled ISEQs to the file. The file will be truncated.
+ --zjit-trace-exits[=counter]
+ Record source on side-exit. `Counter` picks specific counter.
+ --zjit-trace-exits-sample-rate=num
+ Frequency at which to record side exits. Must be `usize`.
+$
+```
+
+### Source level documentation
+
+You can generate and open the source level documentation in your browser using:
+
+```bash
+cargo doc --document-private-items -p zjit --open
+```
+
+### Graph of the Type System
+
+You can generate a graph of the ZJIT type hierarchy using:
+
+```bash
+ruby zjit/src/hir_type/gen_hir_type.rb > zjit/src/hir_type/hir_type.inc.rs
+dot -O -Tpdf zjit_types.dot
+open zjit_types.dot.pdf
+```
+
+## Testing
+
+Note that tests link against CRuby, so directly calling `cargo test`, or `cargo nextest` should not build. All tests are instead accessed through `make`.
+
+### Setup
+
+First, ensure you have `cargo` installed. If you do not already have it, you can use [rustup.rs](https://rustup.rs/).
+
+Also install cargo-binstall with:
+
+```bash
+cargo install cargo-binstall
+```
+
+Make sure to add `--enable-zjit=dev` when you run `configure`, then install the following tools:
+
+```bash
+cargo binstall --secure cargo-nextest
+cargo binstall --secure cargo-insta
+```
+
+`cargo-insta` is used for updating snapshots. `cargo-nextest` runs each test in its own process, which is valuable since CRuby only supports booting once per process, and most APIs are not thread safe.
+
+### Running unit tests
+
+For testing functionality within ZJIT, use:
+
+```bash
+make zjit-test
+```
+
+You can also run a single test case by specifying the function name:
+
+```bash
+make zjit-test ZJIT_TESTS=test_putobject
+```
+
+#### Snapshot Testing
+
+ZJIT uses [insta](https://insta.rs/) for snapshot testing within unit tests. When tests fail due to snapshot mismatches, pending snapshots are created. The test command will notify you if there are pending snapshots:
+
+```
+Pending snapshots found. Accept with: make zjit-test-update
+```
+
+To update/accept all the snapshot changes:
+
+```bash
+make zjit-test-update
+```
+
+You can also review snapshot changes interactively one by one:
+
+```bash
+cd zjit && cargo insta review
+```
+
+Test changes will be reviewed alongside code changes.
+
+### Running integration tests
+
+This command runs Ruby execution tests.
+
+```bash
+make test-all TESTS="test/ruby/test_zjit.rb"
+```
+
+You can also run a single test case by matching the method name:
+
+```bash
+make test-all TESTS="test/ruby/test_zjit.rb -n TestZJIT#test_putobject"
+```
+
+### Running all tests
+
+Runs both `make zjit-test` and `test/ruby/test_zjit.rb`:
+
+```bash
+make zjit-check
+```
+
+## Statistics Collection
+
+ZJIT provides detailed statistics about JIT compilation and execution behavior.
+
+### Basic Stats
+
+Run with basic statistics printed on exit:
+
+```bash
+./miniruby --zjit-stats script.rb
+```
+
+Collect stats without printing (access via `RubyVM::ZJIT.stats` in Ruby):
+
+```bash
+./miniruby --zjit-stats=quiet script.rb
+```
+
+### Accessing Stats in Ruby
+
+```ruby
+# Check if stats are enabled
+if RubyVM::ZJIT.stats_enabled?
+ stats = RubyVM::ZJIT.stats
+ puts "Compiled ISEQs: #{stats[:compiled_iseq_count]}"
+ puts "Failed ISEQs: #{stats[:failed_iseq_count]}"
+
+ # You can also reset stats during execution
+ RubyVM::ZJIT.reset_stats!
+end
+```
+
+### Performance Ratio
+
+The `ratio_in_zjit` stat shows the percentage of Ruby instructions executed in JIT code vs interpreter.
+This metric only appears when ZJIT is built with `--enable-zjit=stats` [or more](#build-instructions) (which enables `rb_vm_insn_count` tracking) and represents a key performance indicator for ZJIT effectiveness.
+
+### Tracing side exits
+
+`--zjit-trace-exits` records a backtrace every time compiled code takes a
+side exit. The output is a [Fuchsia Trace Format](https://fuchsia.dev/fuchsia-src/reference/tracing/trace-format)
+(`.fxt`) file written to `/tmp/perfetto-{pid}.fxt`, which can be opened
+directly in [Perfetto UI](https://ui.perfetto.dev/) or queried with the
+[Perfetto trace processor](https://perfetto.dev/docs/quickstart/trace-analysis).
+
+```bash
+$ ./miniruby --zjit-trace-exits -e '
+def poly(x)
+ x.to_s
+end
+
+30.times { poly(1) }
+30.times { poly("hello") }
+30.times { poly(:sym) }
+'
+ZJIT: writing trace exits to /tmp/perfetto-123456.fxt
+```
+
+To find the hottest side-exit locations, open the `.fxt` file in
+[Perfetto UI](https://ui.perfetto.dev/) and run an SQL query via the
+"Query (SQL)" tab in the bottom panel. Alternatively, download
+`trace_processor_shell` to query from the command line:
+
+```bash
+curl -Lo /tmp/trace_processor_shell https://get.perfetto.dev/trace_processor
+chmod +x /tmp/trace_processor_shell
+
+/tmp/trace_processor_shell /tmp/perfetto-123456.fxt -Q "
+SELECT reason, backtrace, count(*) AS exits FROM (
+ SELECT
+ s.id,
+ s.name AS reason,
+ group_concat(a.display_value, ' <- ') AS backtrace
+ FROM slice s
+ JOIN args a USING(arg_set_id)
+ WHERE s.category = 'side_exit'
+ GROUP BY s.id
+)
+GROUP BY reason, backtrace
+ORDER BY exits DESC
+LIMIT 30
+"
+```
+
+Example output:
+
+```
+"reason","backtrace","exits"
+"GuardType(Fixnum)","Object#poly (-e) <- block in <main> (-e) <- Integer#times (<internal:numeric>) <- <main> (-e)",60
+```
+
+You can also trace a specific counter with `--zjit-trace-exits=<counter_name>`
+(e.g. `--zjit-trace-exits=exit_compile_error`), or downsample with
+`--zjit-trace-exits-sample-rate=N` to record every N-th exit.
+Enabling `--zjit-trace-exits-sample-rate=N` will automatically enable
+`--zjit-trace-exits`.
+
+### Viewing HIR as text
+
+The compiled ZJIT HIR can be viewed as text using the `--zjit-dump-hir` option. However, HIR will only be generated if the call threshold is reached (default 30). By setting the threshold to 1 you can easily view the HIR for code snippets such as `1 + 1`:
+
+```bash
+./miniruby --zjit --zjit-dump-hir --zjit-call-threshold=1 -e "1 + 1"
+```
+
+Note that this disables profiling. To inject interpreter profiles into ZJIT, consider running your sample code 30 times:
+
+```bash
+./miniruby --zjit --zjit-dump-hir -e "30.times { 1 + 1 }"
+```
+
+### Viewing HIR in Iongraph
+
+Using `--zjit-dump-hir-iongraph` will dump all compiled functions into a directory named `/tmp/zjit-iongraph-{PROCESS_PID}`. Each file will be named `func_{ZJIT_FUNC_NAME}.json`. In order to use them in the Iongraph viewer, you'll need to use `jq` to collate them to a single file. An example invocation of `jq` is shown below for reference.
+
+`jq --slurp --null-input '.functions=inputs | .version=1' /tmp/zjit-iongraph-{PROCESS_PID}/func*.json > ~/Downloads/ion.json`
+
+From there, you can use https://mozilla-spidermonkey.github.io/iongraph/ to view your trace.
+
+### Printing ZJIT Errors
+
+`--zjit-debug` prints ZJIT compilation errors and other diagnostics:
+
+```bash
+./miniruby --zjit-debug script.rb
+```
+
+As you might guess from the name, this option is intended mostly for ZJIT developers.
+
+## Useful dev commands
+
+To view YARV output for code snippets:
+
+```bash
+./miniruby --dump=insns -e0
+```
+
+To run code snippets with ZJIT:
+
+```bash
+./miniruby --zjit -e0
+```
+
+You can also try https://www.rubyexplorer.xyz/ to view Ruby YARV disasm output with syntax highlighting
+in a way that can be easily shared with other team members.
+
+## Understanding Ruby Stacks
+
+Ruby execution involves three distinct stacks and understanding them will help you understand ZJIT's implementation:
+
+### 1. Native Stack
+
+- **Purpose**: Return addresses and saved registers. ZJIT also uses it for some C functions' argument arrays
+- **Management**: OS-managed, one per native thread
+- **Growth**: Downward from high addresses
+- **Constants**: `NATIVE_STACK_PTR`, `NATIVE_BASE_PTR`
+
+### 2. Ruby VM Stack
+
+The Ruby VM uses a single contiguous memory region (`ec->vm_stack`) containing two sub-stacks that grow toward each other. When they meet, stack overflow occurs.
+
+See [doc/contributing/vm_stack_and_frames.md](rdoc-ref:contributing/vm_stack_and_frames.md) for detailed architecture and frame layout.
+
+**Control Frame Stack:**
+
+- **Stores**: Frame metadata (`rb_control_frame_t` structures)
+- **Growth**: Downward from `vm_stack + size` (high addresses)
+- **Constants**: `CFP`
+
+**Value Stack:**
+
+- **Stores**: YARV bytecode operands (self, arguments, locals, temporaries)
+- **Growth**: Upward from `vm_stack` (low addresses)
+- **Constants**: `SP`
+
+## ZJIT Glossary
+
+This glossary contains terms that are helpful for understanding ZJIT.
+
+Please note that some terms may appear in CRuby internals too but with different meanings.
+
+| Term | Definition |
+| ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| HIR | High-level Intermediate Representation. High-level (Ruby semantics) graph representation in static single-assignment (SSA) form |
+| LIR | Low-level Intermediate Representation. Low-level IR used in the backend for assembly generation |
+| SSA | Static Single Assignment. A form where each variable is assigned exactly once |
+| `opnd` | Operand. An operand to an IR instruction (can be register, memory, immediate, etc.) |
+| `dst` | Destination. The output operand of an instruction where the result is stored |
+| VReg | Virtual Register. A virtual register that gets lowered to physical register or memory |
+| `insn_id` | Instruction ID. An index of an instruction in a function |
+| `block_id` | The index of a basic block, which effectively acts like a pointer |
+| `branch` | Control flow edge between basic blocks in the compiled code |
+| `cb` | Code Block. Memory region for generated machine code |
+| `entry` | The starting address of compiled code for an ISEQ |
+| Patch Point | Location in generated code that can be modified later in case assumptions get invalidated |
+| Frame State | Captured state of the Ruby stack frame at a specific point for deoptimization |
+| Guard | A run-time check that ensures assumptions are still valid |
+| `invariant` | An assumption that JIT code relies on, requiring invalidation if broken |
+| Deopt | Deoptimization. Process of falling back from JIT code to interpreter |
+| Side Exit | Exit from JIT code back to interpreter |
+| Type Lattice | Hierarchy of types used for type inference and optimization |
+| Constant Folding | Optimization that evaluates constant expressions at compile time |
+| RSP | x86-64 stack pointer register used for native stack operations |
+| Register Spilling | Process of moving register values to memory when running out of physical registers |
diff --git a/doc/language/box.md b/doc/language/box.md
new file mode 100644
index 0000000000..92514b3ec9
--- /dev/null
+++ b/doc/language/box.md
@@ -0,0 +1,357 @@
+# Ruby Box - Ruby's in-process separation of Classes and Modules
+
+Ruby Box is designed to provide separated spaces in a Ruby process, to isolate application code, libraries and monkey patches.
+
+## Known issues
+
+* Experimental warning is shown when ruby starts with `RUBY_BOX=1` (specify `-W:no-experimental` option to hide it)
+* Installing native extensions may fail under `RUBY_BOX=1` because of stack level too deep in extconf.rb
+* `require 'active_support/core_ext'` may fail under `RUBY_BOX=1`
+* Defined methods in a box may not be referred by built-in methods written in Ruby
+
+## TODOs
+
+* Add the loaded box on iseq to check if another box tries running the iseq (add a field only when VM_CHECK_MODE?)
+* Assign its own TOPLEVEL_BINDING in boxes
+* Fix calling `warn` in boxes to refer `$VERBOSE` and `Warning.warn` in the box
+* Make an internal data container class `Ruby::Box::Entry` invisible
+* More test cases about `$LOAD_PATH` and `$LOADED_FEATURES`
+
+## How to use
+
+### Enabling Ruby Box
+
+First, an environment variable should be set at the ruby process bootup: `RUBY_BOX=1`.
+The only valid value is `1` to enable Ruby Box. Other values (or unset `RUBY_BOX`) means disabling Ruby Box. And setting the value after Ruby program starts doesn't work.
+
+### Using Ruby Box
+
+`Ruby::Box` class is the entrypoint of Ruby Box.
+
+```ruby
+box = Ruby::Box.new
+box.require('something') # or require_relative, load
+```
+
+The required file (either .rb or .so/.dll/.bundle) is loaded in the box (`box` here). The required/loaded files from `something` will be loaded in the box recursively.
+
+```ruby
+# something.rb
+
+X = 1
+
+class Something
+ def self.x = X
+ def x = ::X
+end
+```
+
+Classes/modules, those methods and constants defined in the box can be accessed via `box` object.
+
+```ruby
+X = 2
+p X # 2
+p ::X # 2
+p box::Something.x # 1
+p box::X # 1
+```
+
+Instance methods defined in the box also run with definitions in the box.
+
+```ruby
+s = box::Something.new
+
+p s.x # 1
+```
+
+## Specifications
+
+### Ruby Box types
+
+There are three box types:
+
+* Master box
+* Root box
+* User boxes
+
+Ruby bootstrap runs in the root box, and a
+
+There is the root box, just a single box in a Ruby process. All builtin classes/modules are defined and run in the root box. (See "Builtin classes and modules".)
+
+User boxes are to run user-written programs and libraries loaded from user programs. The user's main program (specified by the `ruby` command line argument) is executed in the "main" box, which is a user box automatically created at the end of Ruby's bootstrap. The files specified with `-r` command line option will be required in the main box.
+
+Calling `Ruby::Box.new` creates an "optional" box (a user, non-main box), technically equal to the main box.
+
+Ruby also has the master box. The master box is the "master copy" of all boxes. Boxes will be created as a copy of the master box. The master box is only for the source of box copies, and no code runs in the master box.
+
+
+```
+[master]
+ |
+ |----[root]
+ |
+ |----[main]
+ |
+ |----[user box 1]
+ |
+ |----[user box 2]
+ ...
+```
+
+### Ruby Box class and instances
+
+`Ruby::Box` is a class, as a subclass of `Module`. `Ruby::Box` instances are a kind of `Module`.
+
+### Classes and modules defined in boxes
+
+The classes and modules, newly defined in a box `box`, are accessible via `box`. For example, if a class `A` is defined in `box`, it is accessible as `box::A` from outside of the box.
+
+In the box `box`, `A` can be referred to as `A` (and `::A`).
+
+### Built-in classes and modules reopened in boxes
+
+In boxes, builtin classes/modules are visible and can be reopened. Those classes/modules can be reopened using `class` or `module` clauses, and class/module definitions can be changed.
+
+The changed definitions are visible only in the box. In other boxes, builtin classes/modules and those instances work without changed definitions.
+
+```ruby
+# in foo.rb
+class String
+ BLANK_PATTERN = /\A\s*\z/
+ def blank?
+ self.match?(BLANK_PATTERN)
+ end
+end
+
+module Foo
+ def self.foo = "foo"
+
+ def self.foo_is_blank?
+ foo.blank?
+ end
+end
+
+Foo.foo.blank? #=> false
+"foo".blank? #=> false
+
+# in main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::Foo.foo_is_blank? #=> false (#blank? called in box)
+
+"foo".blank? # NoMethodError
+String::BLANK_PATTERN # NameError
+```
+
+The main box and `box` above are different boxes, so monkey patches in main are also invisible in `box`.
+
+### Builtin classes and modules
+
+In the box context, "builtin" classes and modules are classes and modules:
+
+* Accessible without any `require` calls in user scripts
+* Defined before any user program start running
+
+Hereafter, "builtin classes and modules" will be referred to as just "builtin classes".
+
+Builtin classes and modules are loaded in all boxes, and run in the root box.
+
+### Exceptional non-built-in classes/modules
+
+There are some exceptional classes/modules that are enabled in default, but aren't built-in classes. Those classes/modules are:
+
+* `RubyGems`
+* `ErrorHighlight`
+* `DidYouMean`
+* `SyntaxSuggest`
+
+Those classes/modules (part of default gems) are loaded in each boxes independently. If a user box's code calls RubyGems, it calls the RubyGems inside the box itself, instead of the root box's one.
+
+### Builtin classes referred via box objects
+
+Builtin classes in a box `box` can be referred from other boxes. For example, `box::String` is a valid reference, and `String` and `box::String` are identical (`String == box::String`, `String.object_id == box::String.object_id`).
+
+`box::String`-like reference returns just a `String` in the current box, so its definition is `String` in the box, not in `box`.
+
+```ruby
+# foo.rb
+class String
+ def self.foo = "foo"
+end
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::String.foo # NoMethodError
+```
+
+### Class instance variables, class variables, constants
+
+Builtin classes can have different sets of class instance variables, class variables and constants between boxes.
+
+```ruby
+# foo.rb
+class Array
+ @v = "foo"
+ @@v = "_foo_"
+ V = "FOO"
+end
+
+Array.instance_variable_get(:@v) #=> "foo"
+Array.class_variable_get(:@@v) #=> "_foo_"
+Array.const_get(:V) #=> "FOO"
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+Array.instance_variable_get(:@v) #=> nil
+Array.class_variable_get(:@@v) # NameError
+Array.const_get(:V) # NameError
+```
+
+### Global variables
+
+In boxes, changes on global variables are also isolated in the boxes. Changes on global variables in a box are visible/applied only in the box.
+
+```ruby
+# foo.rb
+$foo = "foo"
+$VERBOSE = nil
+
+puts "This appears: '#{$foo}'"
+
+# main.rb
+p $foo #=> nil
+p $VERBOSE #=> false
+
+box = Ruby::Box.new
+box.require_relative('foo') # "This appears: 'foo'"
+
+p $foo #=> nil
+p $VERBOSE #=> false
+```
+
+### Top level constants
+
+Usually, top level constants are defined as constants of `Object`. In boxes, top level constants are constants of `Object` in the box. And the box object `box`'s constants are strictly equal to constants of `Object`.
+
+```ruby
+# foo.rb
+FOO = 100
+
+FOO #=> 100
+Object::FOO #=> 100
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::FOO #=> 100
+
+FOO # NameError
+Object::FOO # NameError
+```
+
+### Top level methods
+
+Top level methods are private instance methods of `Object`, in each box.
+
+```ruby
+# foo.rb
+def yay = "foo"
+
+class Foo
+ def self.say = yay
+end
+
+Foo.say #=> "foo"
+yay #=> "foo"
+
+# main.rb
+box = Ruby::Box.new
+box.require_relative('foo')
+
+box::Foo.say #=> "foo"
+
+yay # NoMethodError
+```
+
+There is no way to expose top level methods in boxes to others.
+(See "Expose top level methods as a method of the box object" in "Discussions" section below)
+
+### Ruby Box scopes
+
+Ruby Box works in file scope. One `.rb` file runs in a single box.
+
+Once a file is loaded in a box `box`, all methods/procs defined/created in the file run in `box`.
+
+### Utility methods
+
+Several methods are available for trying/testing Ruby Box.
+
+* `Ruby::Box.current` returns the current box
+* `Ruby::Box.enabled?` returns true/false to represent `RUBY_BOX=1` is specified or not
+* `Ruby::Box.root` returns the root box
+* `Ruby::Box.main` returns the main box
+* `Ruby::Box#eval` evaluates a Ruby code (String) in the receiver box, just like calling `#load` with a file
+
+## Implementation details
+
+#### ISeq inline method/constant cache
+
+As described above in "Ruby Box scopes", an ".rb" file runs in a box. So method/constant resolution will be done in a box consistently.
+
+That means ISeq inline caches work well even with boxes. Otherwise, it's a bug.
+
+#### Method call global cache (gccct)
+
+`rb_funcall()` C function refers to the global cc cache table (gccct), and the cache key is calculated with the current box.
+
+So, `rb_funcall()` calls have a performance penalty when Ruby Box is enabled.
+
+#### Current box and loading box
+
+The current box is the box that the executing code is in. `Ruby::Box.current` returns the current box object.
+
+The loading box is an internally managed box to determine the box to load newly required/loaded files. For example, `box` is the loading box when `box.require("foo")` is called.
+
+## Discussions
+
+#### More builtin methods written in Ruby
+
+If Ruby Box is enabled by default, builtin methods can be written in Ruby because it can't be overridden by users' monkey patches. Builtin Ruby methods can be JIT-ed, and it could bring performance reward.
+
+#### Monkey patching methods called by builtin methods
+
+Builtin methods sometimes call other builtin methods. For example, `Hash#map` calls `Hash#each` to retrieve entries to be mapped. Without Ruby Box, Ruby users can overwrite `Hash#each` and expect the behavior change of `Hash#map` as a result.
+
+But with boxes, `Hash#map` runs in the root box. Ruby users can define `Hash#each` only in user boxes, so users cannot change `Hash#map`'s behavior in this case. To achieve it, users should override both`Hash#map` and `Hash#each` (or only `Hash#map`).
+
+It is a breaking change.
+
+Users can define methods using `Ruby::Box.root.eval(...)`, but it's clearly not ideal API.
+
+#### Assigning values to global variables used by builtin methods
+
+Similar to monkey patching methods, global variables assigned in a box is separated from the root box. Methods defined in the root box referring a global variable can't find the re-assigned one.
+
+#### Context of `$LOAD_PATH` and `$LOADED_FEATURES`
+
+Global variables `$LOAD_PATH` and `$LOADED_FEATURES` control `require` method behaviors. So those variables are determined by the loading box instead of the current box.
+
+This could potentially conflict with the user's expectations. We should find the solution.
+
+#### Expose top level methods as a method of the box object
+
+Currently, top level methods in boxes are not accessible from outside of the box. But there might be a use case to call other box's top level methods.
+
+#### Separate `cc_tbl` and `callable_m_tbl`, `cvc_tbl` for less classext CoW
+
+The fields of `rb_classext_t` contains several cache(-like) data, `cc_tbl`(callcache table), `callable_m_tbl`(table of resolved complemented methods) and `cvc_tbl`(class variable cache table).
+
+The classext CoW is triggered when the contents of `rb_classext_t` are changed, including `cc_tbl`, `callable_m_tbl`, and `cvc_tbl`. But those three tables are changed by just calling methods or referring class variables. So, currently, classext CoW is triggered much more times than the original expectation.
+
+If we can move those three tables outside of `rb_classext_t`, the number of copied `rb_classext_t` will be much less than the current implementation.
diff --git a/doc/bsearch.rdoc b/doc/language/bsearch.rdoc
index 90705853d7..90705853d7 100644
--- a/doc/bsearch.rdoc
+++ b/doc/language/bsearch.rdoc
diff --git a/doc/language/calendars.rdoc b/doc/language/calendars.rdoc
new file mode 100644
index 0000000000..a2540f1c43
--- /dev/null
+++ b/doc/language/calendars.rdoc
@@ -0,0 +1,62 @@
+== Julian and Gregorian Calendars
+
+The difference between the
+{Julian calendar}[https://en.wikipedia.org/wiki/Julian_calendar]
+and the
+{Gregorian calendar}[https://en.wikipedia.org/wiki/Gregorian_calendar]
+may matter to your program if it uses dates before the switchovers.
+
+- October 15, 1582.
+- September 14, 1752.
+
+A date will be different in the two calendars, in general.
+
+=== Different switchover dates
+
+The reasons for the difference are religious/political histories.
+
+- On October 15, 1582, several countries changed
+ from the Julian calendar to the Gregorian calendar;
+ these included Italy, Poland, Portugal, and Spain.
+ Other countries in the Western world retained the Julian calendar.
+- On September 14, 1752, most of the British empire
+ changed from the Julian calendar to the Gregorian calendar.
+
+When your code uses a date before these switchover dates,
+it will matter whether it considers the switchover date
+to be the earlier date or the later date (or neither).
+
+See also {a concrete example here}[rdoc-ref:DateTime@When+should+you+use+DateTime+and+when+should+you+use+Time-3F].
+
+=== Argument +start+
+
+Certain methods in class \Date handle differences in the
+{Julian and Gregorian calendars}[rdoc-ref:@Julian+and+Gregorian+Calendars]
+by accepting an optional argument +start+, whose value may be:
+
+- Date::ITALY (the default): the created date is Julian
+ if before October 15, 1582, Gregorian otherwise:
+
+ d = Date.new(1582, 10, 15)
+ d.prev_day.julian? # => true
+ d.julian? # => false
+ d.gregorian? # => true
+
+- Date::ENGLAND: the created date is Julian if before September 14, 1752,
+ Gregorian otherwise:
+
+ d = Date.new(1752, 9, 14, Date::ENGLAND)
+ d.prev_day.julian? # => true
+ d.julian? # => false
+ d.gregorian? # => true
+
+- Date::JULIAN: the created date is Julian regardless of its value:
+
+ d = Date.new(1582, 10, 15, Date::JULIAN)
+ d.julian? # => true
+
+- Date::GREGORIAN: the created date is Gregorian regardless of its value:
+
+ d = Date.new(1752, 9, 14, Date::GREGORIAN)
+ d.prev_day.gregorian? # => true
+
diff --git a/doc/language/case_mapping.rdoc b/doc/language/case_mapping.rdoc
new file mode 100644
index 0000000000..d40155db03
--- /dev/null
+++ b/doc/language/case_mapping.rdoc
@@ -0,0 +1,106 @@
+= Case Mapping
+
+Some string-oriented methods use case mapping.
+
+In String:
+
+- String#capitalize
+- String#capitalize!
+- String#casecmp
+- String#casecmp?
+- String#downcase
+- String#downcase!
+- String#swapcase
+- String#swapcase!
+- String#upcase
+- String#upcase!
+
+In Symbol:
+
+- Symbol#capitalize
+- Symbol#casecmp
+- Symbol#casecmp?
+- Symbol#downcase
+- Symbol#swapcase
+- Symbol#upcase
+
+== Default Case Mapping
+
+By default, all of these methods use full Unicode case mapping,
+which is suitable for most languages.
+See {Section 3.13 (Default Case Algorithms) of the Unicode standard}[https://www.unicode.org/versions/latest/ch03.pdf].
+
+Non-ASCII case mapping and folding are supported for UTF-8,
+UTF-16BE/LE, UTF-32BE/LE, and ISO-8859-1~16 Strings/Symbols.
+
+Context-dependent case mapping as described in
+{Table 3-17 (Context Specification for Casing) of the Unicode standard}[https://www.unicode.org/versions/latest/ch03.pdf]
+is currently not supported.
+
+In most cases, the case conversion of a string has the same number of characters as before.
+There are exceptions (see also +:fold+ below):
+
+ s = "\u00DF" # => "ß"
+ s.upcase # => "SS"
+ s = "\u0149" # => "ʼn"
+ s.upcase # => "ʼN"
+
+Case mapping may also depend on locale (see also +:turkic+ below):
+
+ s = "\u0049" # => "I"
+ s.downcase # => "i" # Dot above.
+ s.downcase(:turkic) # => "ı" # No dot above.
+
+Case changes may not be reversible:
+
+ s = 'Hello World!' # => "Hello World!"
+ s.downcase # => "hello world!"
+ s.downcase.upcase # => "HELLO WORLD!" # Different from original s.
+
+Case changing methods may not maintain Unicode normalization.
+See String#unicode_normalize.
+
+== Case Mappings
+
+Except for +casecmp+ and +casecmp?+,
+each of the case-mapping methods listed above
+accepts an optional argument, <tt>mapping</tt>.
+
+The argument is one of:
+
+- +:ascii+: ASCII-only mapping.
+ Uppercase letters ('A'..'Z') are mapped to lowercase letters ('a'..'z);
+ other characters are not changed
+
+ s = "Foo \u00D8 \u00F8 Bar" # => "Foo Ø ø Bar"
+ s.upcase # => "FOO Ø Ø BAR"
+ s.downcase # => "foo ø ø bar"
+ s.upcase(:ascii) # => "FOO Ø ø BAR"
+ s.downcase(:ascii) # => "foo Ø ø bar"
+
+- +:turkic+: Full Unicode case mapping.
+ For the Turkic languages
+ that distinguish dotted and dotless I, for example Turkish and Azeri.
+
+ s = 'Türkiye' # => "Türkiye"
+ s.upcase # => "TÜRKIYE"
+ s.upcase(:turkic) # => "TÜRKİYE" # Dot above.
+
+ s = 'TÜRKIYE' # => "TÜRKIYE"
+ s.downcase # => "türkiye"
+ s.downcase(:turkic) # => "türkıye" # No dot above.
+
+- +:fold+ (available only for String#downcase, String#downcase!,
+ and Symbol#downcase).
+ Unicode case folding,
+ which is more far-reaching than Unicode case mapping.
+
+ s = "\u00DF" # => "ß"
+ s.downcase # => "ß"
+ s.downcase(:fold) # => "ss"
+ s.upcase # => "SS"
+
+ s = "\uFB04" # => "ffl"
+ s.downcase # => "ffl"
+ s.upcase # => "FFL"
+ s.downcase(:fold) # => "ffl"
diff --git a/doc/language/character_selectors.rdoc b/doc/language/character_selectors.rdoc
new file mode 100644
index 0000000000..8bfc9b719b
--- /dev/null
+++ b/doc/language/character_selectors.rdoc
@@ -0,0 +1,100 @@
+= Character Selectors
+
+== 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:
+
+- String#tr(selector, replacements): returns a new string.
+- String#tr!(selector, replacements): returns +self+ or +nil+.
+- String#tr_s(selector, replacements): returns a new string.
+- String#tr_s!(selector, replacements): returns +self+ or +nil+.
+- String#count(*selectors): returns the count of the specified characters.
+- String#delete(*selectors): returns a new string.
+- String#delete!(*selectors): returns +self+ or +nil+.
+- String#squeeze(*selectors): returns a new string.
+- String#squeeze!(*selectors): returns +self+ or +nil+.
+- String#strip(*selectors): returns a new string.
+- String#strip!(*selectors): returns +self+ or +nil+.
+
+A character selector identifies zero or more characters in +self+
+that are to be operands for the method.
+
+In this section, we illustrate using method String#delete(selector),
+which deletes the selected characters.
+
+In the simplest case, the characters selected are exactly those
+contained in the selector itself:
+
+ 'abracadabra'.delete('a') # => "brcdbr"
+ 'abracadabra'.delete('ab') # => "rcdr"
+ 'abracadabra'.delete('abc') # => "rdr"
+ '0123456789'.delete('258') # => "0134679"
+ '!@#$%&*()_+'.delete('+&#') # => "!@$%*()_"
+ 'こんにちは'.delete('に') # => "こんちは"
+
+Note that order and repetitions do not matter:
+
+ 'abracadabra'.delete('dcab') # => "rr"
+ 'abracadabra'.delete('aaaa') # => "brcdbr"
+
+In a character selector, these three characters get special treatment:
+
+- A leading caret (<tt>'^'</tt>) functions as a "not" operator
+ for the characters to its right:
+
+ 'abracadabra'.delete('^bc') # => "bcb"
+ '0123456789'.delete('^852') # => "258"
+
+- A hyphen (<tt>'-'</tt>) between two other characters
+ defines a range of characters instead of a plain string of characters:
+
+ 'abracadabra'.delete('a-d') # => "rr"
+ '0123456789'.delete('4-7') # => "012389"
+ '!@#$%&*()_+'.delete(' -/') # => "@^_"
+
+ # May contain more than one range.
+ 'abracadabra'.delete('a-cq-t') # => "d"
+
+ # Ranges may be mixed with plain characters.
+ '0123456789'.delete('67-950-23') # => "4"
+
+ # Ranges may be mixed with negations.
+ 'abracadabra'.delete('^a-c') # => "abacaaba"
+
+- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
+ or another backslash:
+
+ 'abracadabra^'.delete('\^bc') # => "araadara"
+ 'abracadabra-'.delete('a\-d') # => "brcbr"
+ "hello\r\nworld".delete("\r") # => "hello\nworld"
+ "hello\r\nworld".delete("\\r") # => "hello\r\nwold"
+ "hello\r\nworld".delete("\\\r") # => "hello\nworld"
+
+== Multiple Character Selectors
+
+These instance methods accept multiple character selectors:
+
+- String#count(*selectors): returns the count of the specified characters.
+- String#delete(*selectors): returns a new string.
+- String#delete!(*selectors): returns +self+ or +nil+.
+- String#squeeze(*selectors): returns a new string.
+- String#squeeze!(*selectors): returns +self+ or +nil+.
+- String#strip(*selectors): returns a new string.
+- String#strip!(*selectors): returns +self+ or +nil+.
+
+In effect, the given selectors are formed into a single selector
+consisting of only those characters common to _all_ of the given selectors.
+
+All forms of selectors may be used, including negations, ranges, and escapes.
+
+Each of these pairs of method calls is equivalent:
+
+ s.delete('abcde', 'dcbfg')
+ s.delete('bcd')
+
+ s.delete('^abc', '^def')
+ s.delete('^abcdef')
+
+ s.delete('a-e', 'c-g')
+ s.delete('cde')
diff --git a/doc/dig_methods.rdoc b/doc/language/dig_methods.rdoc
index 366275d451..366275d451 100644
--- a/doc/dig_methods.rdoc
+++ b/doc/language/dig_methods.rdoc
diff --git a/doc/language/encodings.rdoc b/doc/language/encodings.rdoc
new file mode 100644
index 0000000000..683842d3fb
--- /dev/null
+++ b/doc/language/encodings.rdoc
@@ -0,0 +1,482 @@
+= Encodings
+
+== The Basics
+
+A {character encoding}[https://en.wikipedia.org/wiki/Character_encoding],
+often shortened to _encoding_, is a mapping between:
+
+- A sequence of 8-bit bytes (each byte in the range <tt>0..255</tt>).
+- Characters in a specific character set.
+
+Some character sets contain only 1-byte characters;
+{US-ASCII}[https://en.wikipedia.org/wiki/ASCII], for example, has 256 1-byte characters.
+This string, encoded in US-ASCII, has six characters that are stored as six bytes:
+
+ s = 'Hello!'.encode(Encoding::US_ASCII) # => "Hello!"
+ s.encoding # => #<Encoding:US-ASCII>
+ s.bytes # => [72, 101, 108, 108, 111, 33]
+
+Other encodings may involve multi-byte characters.
+{UTF-8}[https://en.wikipedia.org/wiki/UTF-8], for example,
+encodes more than one million characters, encoding each in one to four bytes.
+The lowest-valued of these characters correspond to ASCII characters,
+and so are 1-byte characters:
+
+ s = 'Hello!' # => "Hello!"
+ s.bytes # => [72, 101, 108, 108, 111, 33]
+
+Other characters, such as the Euro symbol, are multi-byte:
+
+ s = "\u20ac" # => "€"
+ s.bytes # => [226, 130, 172]
+
+== The \Encoding Class
+
+=== \Encoding Objects
+
+Ruby encodings are defined by constants in class \Encoding.
+There can be only one instance of \Encoding for each of these constants.
+Method Encoding.list returns an array of \Encoding objects (one for each constant):
+
+ Encoding.list.size # => 103
+ Encoding.list.first.class # => Encoding
+ Encoding.list.take(3)
+ # => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]
+
+=== Names and Aliases
+
+Method Encoding#name returns the name of an \Encoding:
+
+ Encoding::ASCII_8BIT.name # => "ASCII-8BIT"
+ Encoding::WINDOWS_31J.name # => "Windows-31J"
+
+An \Encoding object has zero or more aliases;
+method Encoding#names returns an array containing the name and all aliases:
+
+ Encoding::ASCII_8BIT.names
+ # => ["ASCII-8BIT", "BINARY"]
+ Encoding::WINDOWS_31J.names
+ #=> ["Windows-31J", "CP932", "csWindows31J", "SJIS", "PCK"]
+
+Method Encoding.aliases returns a hash of all alias/name pairs:
+
+ Encoding.aliases.size # => 71
+ Encoding.aliases.take(3)
+ # => [["BINARY", "ASCII-8BIT"], ["CP437", "IBM437"], ["CP720", "IBM720"]]
+
+Method Encoding.name_list returns an array of all the encoding names and aliases:
+
+ Encoding.name_list.size # => 175
+ Encoding.name_list.take(3)
+ # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
+
+Method +name_list+ returns more entries than method +list+
+because it includes both the names and their aliases.
+
+Method Encoding.find returns the \Encoding for a given name or alias, if it exists:
+
+ Encoding.find("US-ASCII") # => #<Encoding:US-ASCII>
+ Encoding.find("US-ASCII").class # => Encoding
+
+=== Default Encodings
+
+Method Encoding.find, above, also returns a default \Encoding
+for each of these special names:
+
+- +external+: the default external \Encoding:
+
+ Encoding.find("external") # => #<Encoding:UTF-8>
+
+- +internal+: the default internal \Encoding (may be +nil+):
+
+ Encoding.find("internal") # => nil
+
+- +locale+: the default \Encoding for a string from the environment:
+
+ Encoding.find("locale") # => #<Encoding:UTF-8> # Linux
+ Encoding.find("locale") # => #<Encoding:IBM437> # Windows
+
+- +filesystem+: the default \Encoding for a string from the filesystem:
+
+ Encoding.find("filesystem") # => #<Encoding:UTF-8>
+
+Method Encoding.default_external returns the default external \Encoding:
+
+ Encoding.default_external # => #<Encoding:UTF-8>
+
+Method Encoding.default_external= sets that value:
+
+ Encoding.default_external = Encoding::US_ASCII # => #<Encoding:US-ASCII>
+ Encoding.default_external # => #<Encoding:US-ASCII>
+
+Method Encoding.default_internal returns the default internal \Encoding:
+
+ Encoding.default_internal # => nil
+
+Method Encoding.default_internal= sets the default internal \Encoding:
+
+ Encoding.default_internal = Encoding::US_ASCII # => #<Encoding:US-ASCII>
+ Encoding.default_internal # => #<Encoding:US-ASCII>
+
+=== Compatible Encodings
+
+Method Encoding.compatible? returns whether two given objects are encoding-compatible
+(that is, whether they can be concatenated);
+returns the \Encoding of the concatenated string, or +nil+ if incompatible:
+
+ rus = "\u{442 435 441 442}"
+ eng = 'text'
+ Encoding.compatible?(rus, eng) # => #<Encoding:UTF-8>
+
+ s0 = "\xa1\xa1".force_encoding(Encoding::ISO_8859_1) # => "\xA1\xA1"
+ s1 = "\xa1\xa1".force_encoding(Encoding::EUCJP) # => "\x{A1A1}"
+ Encoding.compatible?(s0, s1) # => nil
+
+== \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:@Script+Encoding].
+
+ 's'.encoding # => #<Encoding:UTF-8>
+
+The default encoding for a string created with method String.new is:
+
+- For no argument, ASCII-8BIT.
+- For a \String object argument, the encoding of that string.
+- For a string literal, the script encoding;
+ see {Script Encoding}[rdoc-ref:@Script+Encoding].
+
+In either case, any encoding may be specified:
+
+ s = String.new(encoding: Encoding::UTF_8) # => ""
+ s.encoding # => #<Encoding:UTF-8>
+ s = String.new('foo', encoding: Encoding::BINARY) # => "foo"
+ s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+
+The encoding for a string may be changed:
+
+ s = "R\xC3\xA9sum\xC3\xA9" # => "Résumé"
+ s.encoding # => #<Encoding:UTF-8>
+ s.force_encoding(Encoding::ISO_8859_1) # => "R\xC3\xA9sum\xC3\xA9"
+ s.encoding # => #<Encoding:ISO-8859-1>
+
+Changing the assigned encoding does not alter the content of the string;
+it changes only the way the content is to be interpreted:
+
+ s # => "R\xC3\xA9sum\xC3\xA9"
+ s.force_encoding(Encoding::UTF_8) # => "Résumé"
+
+The actual content of a string may also be altered;
+see {Transcoding a String}[#label-Transcoding+a+String].
+
+Here are a couple of useful query methods:
+
+ s = "abc".force_encoding(Encoding::UTF_8) # => "abc"
+ s.ascii_only? # => true
+ s = "abc\u{6666}".force_encoding(Encoding::UTF_8) # => "abc晦"
+ s.ascii_only? # => false
+
+ s = "\xc2\xa1".force_encoding(Encoding::UTF_8) # => "¡"
+ s.valid_encoding? # => true
+ s = "\xc2".force_encoding(Encoding::UTF_8) # => "\xC2"
+ s.valid_encoding? # => false
+
+== \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.
+
+The default encoding for these, however, is:
+
+- US-ASCII, if all characters are US-ASCII.
+- The script encoding, otherwise;
+ see (Script Encoding)[rdoc-ref:@Script+Encoding].
+
+== Filesystem \Encoding
+
+The filesystem encoding is the default \Encoding for a string from the filesystem:
+
+ Encoding.find("filesystem") # => #<Encoding:UTF-8>
+
+== 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
+
+Certain stream objects can have two encodings; these objects include instances of:
+
+- IO.
+- File.
+- ARGF.
+- StringIO.
+
+The two encodings are:
+
+- An _external_ _encoding_, which identifies the encoding of the stream.
+- An _internal_ _encoding_, which (if not +nil+) specifies the encoding
+ to be used for the string constructed from the stream.
+
+=== External \Encoding
+
+The external encoding, which is an \Encoding object, specifies how bytes read
+from the stream are to be interpreted as characters.
+
+The default external encoding is:
+
+- UTF-8 for a text stream.
+- ASCII-8BIT for a binary stream.
+
+The default external encoding is returned by method Encoding.default_external,
+and may be set by:
+
+- Ruby command-line options <tt>--external_encoding</tt> or <tt>-E</tt>.
+
+You can also set the default external encoding using method Encoding.default_external=,
+but doing so may cause problems; strings created before and after the change
+may have a different encodings.
+
+For an \IO or \File object, the external encoding may be set by:
+
+- Open options +external_encoding+ or +encoding+, when the object is created;
+ see {Open Options}[rdoc-ref:IO@Open+Options].
+
+For an \IO, \File, \ARGF, or \StringIO object, the external encoding may be set by:
+
+- Methods +set_encoding+ or (except for \ARGF) +set_encoding_by_bom+.
+
+=== Internal \Encoding
+
+The internal encoding, which is an \Encoding object or +nil+,
+specifies how characters read from the stream
+are to be converted to characters in the internal encoding;
+those characters become a string whose encoding is set to the internal encoding.
+
+The default internal encoding is +nil+ (no conversion).
+It is returned by method Encoding.default_internal,
+and may be set by:
+
+- Ruby command-line options <tt>--internal_encoding</tt> or <tt>-E</tt>.
+
+You can also set the default internal encoding using method Encoding.default_internal=,
+but doing so may cause problems; strings created before and after the change
+may have a different encodings.
+
+For an \IO or \File object, the internal encoding may be set by:
+
+- Open options +internal_encoding+ or +encoding+, when the object is created;
+ see {Open Options}[rdoc-ref:IO@Open+Options].
+
+For an \IO, \File, \ARGF, or \StringIO object, the internal encoding may be set by:
+
+- Method +set_encoding+.
+
+== Script \Encoding
+
+A Ruby script has a script encoding, which may be retrieved by:
+
+ __ENCODING__ # => #<Encoding:UTF-8>
+
+The default script encoding is UTF-8;
+a Ruby source file may set its script encoding with a magic comment
+on the first line of the file (or second line, if there is a shebang on the first).
+The comment must contain the word +coding+ or +encoding+,
+followed by a colon, space and the Encoding name or alias:
+
+ # encoding: ISO-8859-1
+ __ENCODING__ #=> #<Encoding:ISO-8859-1>
+
+== Transcoding
+
+_Transcoding_ is the process of changing a sequence of characters
+from one encoding to another.
+
+As far as possible, the characters remain the same,
+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
+
+Each of these methods transcodes a string:
+
+- String#encode: Transcodes +self+ into a new string
+ according to given encodings and options.
+- String#encode!: Like String#encode, but transcodes +self+ in place.
+- String#scrub: Transcodes +self+ into a new string
+ by replacing invalid byte sequences with a given or default replacement string.
+- String#scrub!: Like String#scrub, but transcodes +self+ in place.
+- String#unicode_normalize: Transcodes +self+ into a new string
+ according to Unicode normalization.
+- String#unicode_normalize!: Like String#unicode_normalize,
+ but transcodes +self+ in place.
+
+== Transcoding a Stream
+
+Each of these methods may transcode a stream;
+whether it does so depends on the external and internal encodings:
+
+- IO.foreach: Yields each line of given stream to the block.
+- IO.new: Creates and returns a new \IO object for the given integer file descriptor.
+- IO.open: Creates a new \IO object.
+- IO.pipe: Creates a connected pair of reader and writer \IO objects.
+- IO.popen: Creates an \IO object to interact with a subprocess.
+- IO.read: Returns a string with all or a subset of bytes from the given stream.
+- IO.readlines: Returns an array of strings, which are the lines from the given stream.
+- IO.write: Writes a given string to the given stream.
+
+This example writes a string to a file, encoding it as ISO-8859-1,
+then reads the file into a new string, encoding it as UTF-8:
+
+ s = "R\u00E9sum\u00E9"
+ path = 't.tmp'
+ ext_enc = Encoding::ISO_8859_1
+ int_enc = Encoding::UTF_8
+
+ File.write(path, s, external_encoding: ext_enc)
+ raw_text = File.binread(path)
+
+ transcoded_text = File.read(path, external_encoding: ext_enc, internal_encoding: int_enc)
+
+ p raw_text
+ p transcoded_text
+
+Output:
+
+ "R\xE9sum\xE9"
+ "Résumé"
+
+== \Encoding Options
+
+A number of methods in the Ruby core accept keyword arguments as encoding options.
+
+Some of the options specify or utilize a _replacement_ _string_, to be used
+in certain transcoding operations.
+A replacement string may be in any encoding that can be converted
+to the encoding of the destination string.
+
+These keyword-value pairs specify encoding options:
+
+- For an invalid byte sequence:
+
+ - <tt>:invalid: nil</tt> (default): Raise exception.
+ - <tt>:invalid: :replace</tt>: Replace each invalid byte sequence
+ with the replacement string.
+
+ Examples:
+
+ s = "\x80foo\x80"
+ s.encode(Encoding::ISO_8859_3) # Raises Encoding::InvalidByteSequenceError.
+ s.encode(Encoding::ISO_8859_3, invalid: :replace) # => "?foo?"
+
+- For an undefined character:
+
+ - <tt>:undef: nil</tt> (default): Raise exception.
+ - <tt>:undef: :replace</tt>: Replace each undefined character
+ with the replacement string.
+
+ Examples:
+
+ s = "\x80foo\x80"
+ "\x80".encode(Encoding::UTF_8, Encoding::BINARY) # Raises Encoding::UndefinedConversionError.
+ s.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace) # => "�foo�"
+
+
+- Replacement string:
+
+ - <tt>:replace: nil</tt> (default): Set replacement string to default value:
+ <tt>"\uFFFD"</tt> ("�") for a Unicode encoding, <tt>'?'</tt> otherwise.
+ - <tt>:replace: some_string</tt>: Set replacement string to the given +some_string+;
+ overrides +:fallback+.
+
+ Examples:
+
+ s = "\xA5foo\xA5"
+ options = {:undef => :replace, :replace => 'xyzzy'}
+ s.encode(Encoding::UTF_8, Encoding::ISO_8859_3, **options) # => "xyzzyfooxyzzy"
+
+- Replacement fallback:
+
+ One of these may be specified:
+
+ - <tt>:fallback: nil</tt> (default): No replacement fallback.
+ - <tt>:fallback: hash_like_object</tt>: Set replacement fallback to the given
+ +hash_like_object+; the replacement string is <tt>hash_like_object[X]</tt>.
+ - <tt>:fallback: method</tt>: Set replacement fallback to the given
+ +method+; the replacement string is <tt>method(X)</tt>.
+ - <tt>:fallback: proc</tt>: Set replacement fallback to the given
+ +proc+; the replacement string is <tt>proc[X]</tt>.
+
+ Examples:
+
+ s = "\u3042foo\u3043"
+
+ hash = {"\u3042" => 'xyzzy'}
+ hash.default = 'XYZZY'
+ s.encode(Encoding::US_ASCII, fallback: hash) # => "xyzzyfooXYZZY"
+
+ def (fallback = "U+%.4X").escape(x)
+ self % x.unpack("U")
+ end
+ "\u{3042}".encode(Encoding::US_ASCII, fallback: fallback.method(:escape)) # => "U+3042"
+
+ proc = Proc.new {|x| x == "\u3042" ? 'xyzzy' : 'XYZZY' }
+ s.encode('ASCII', fallback: proc) # => "XYZZYfooXYZZY"
+
+- XML entities:
+
+ One of these may be specified:
+
+ - <tt>:xml: nil</tt> (default): No handling for XML entities.
+ - <tt>:xml: :text</tt>: Treat source text as XML;
+ replace each undefined character
+ with its upper-case hexadecimal numeric character reference,
+ except that:
+
+ - <tt>&</tt> is replaced with <tt>&amp;</tt>.
+ - <tt><</tt> is replaced with <tt>&lt;</tt>.
+ - <tt>></tt> is replaced with <tt>&gt;</tt>.
+
+ - <tt>:xml: :attr</tt>: Treat source text as XML attribute value;
+ replace each undefined character
+ with its upper-case hexadecimal numeric character reference,
+ except that:
+
+ - The replacement string <tt>r</tt> is double-quoted (<tt>"r"</tt>).
+ - Each embedded double-quote is replaced with <tt>&quot;</tt>.
+ - <tt>&</tt> is replaced with <tt>&amp;</tt>.
+ - <tt><</tt> is replaced with <tt>&lt;</tt>.
+ - <tt>></tt> is replaced with <tt>&gt;</tt>.
+
+ Examples:
+
+ s = 'foo"<&>"bar' + "\u3042"
+ s.encode(Encoding::US_ASCII, xml: :text) # => "foo\"&lt;&amp;&gt;\"bar&#x3042;"
+ s.encode(Encoding::US_ASCII, xml: :attr) # => "\"foo&quot;&lt;&amp;&gt;&quot;bar&#x3042;\""
+
+
+- Newlines:
+
+ One of these may be specified:
+
+ - <tt>:cr_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
+ with a carriage-return character (<tt>"\r"</tt>).
+ - <tt>:crlf_newline: true</tt>: Replace each line-feed character (<tt>"\n"</tt>)
+ with a carriage-return/line-feed string (<tt>"\r\n"</tt>).
+ - <tt>:universal_newline: true</tt>: Replace each carriage-return
+ character (<tt>"\r"</tt>) and each carriage-return/line-feed string
+ (<tt>"\r\n"</tt>) with a line-feed character (<tt>"\n"</tt>).
+
+ Examples:
+
+ s = "\n \r \r\n" # => "\n \r \r\n"
+ s.encode(Encoding::US_ASCII, cr_newline: true) # => "\r \r \r\r"
+ s.encode(Encoding::US_ASCII, crlf_newline: true) # => "\r\n \r \r\r\n"
+ s.encode(Encoding::US_ASCII, universal_newline: true) # => "\n \n \n"
diff --git a/doc/language/exceptions.md b/doc/language/exceptions.md
new file mode 100644
index 0000000000..5f8f0ece69
--- /dev/null
+++ b/doc/language/exceptions.md
@@ -0,0 +1,521 @@
+# Exceptions
+
+Ruby code can raise exceptions.
+
+Most often, a raised exception is meant to alert the running program
+that an unusual (i.e., _exceptional_) situation has arisen,
+and may need to be handled.
+
+Code throughout the Ruby core, Ruby standard library, and Ruby gems generates exceptions
+in certain circumstances:
+
+```rb
+File.open('nope.txt') # Raises Errno::ENOENT: "No such file or directory"
+```
+
+## Raised Exceptions
+
+A raised exception transfers program execution, one way or another.
+
+### Unrescued Exceptions
+
+If an exception not _rescued_
+(see [Rescued Exceptions](#label-Rescued+Exceptions) below),
+execution transfers to code in the Ruby interpreter
+that prints a message and exits the program (or thread):
+
+```console
+$ ruby -e "raise"
+-e:1:in '<main>': unhandled exception
+```
+
+### Rescued Exceptions
+
+An <i>exception handler</i> may determine what is to happen
+when an exception is raised;
+the handler may _rescue_ an exception,
+and may prevent the program from exiting.
+
+A simple example:
+
+```rb
+begin
+ raise 'Boom!' # Raises an exception, transfers control.
+ puts 'Will not get here.'
+rescue
+ puts 'Rescued an exception.' # Control transferred to here; program does not exit.
+end
+puts 'Got here.'
+```
+
+Output:
+
+```
+Rescued an exception.
+Got here.
+```
+
+An exception handler has several elements:
+
+| Element | Use |
+|-----------------------------|------------------------------------------------------------------------------------------|
+| Begin clause. | Begins the handler and contains the code whose raised exception, if any, may be rescued. |
+| One or more rescue clauses. | Each contains "rescuing" code, which is to be executed for certain exceptions. |
+| Else clause (optional). | Contains code to be executed if no exception is raised. |
+| Ensure clause (optional). | Contains code to be executed whether or not an exception is raised, or is rescued. |
+| <tt>end</tt> statement. | Ends the handler. ` |
+
+#### Begin Clause
+
+The begin clause begins the exception handler:
+
+- May start with a `begin` statement;
+ see also [Begin-Less Exception Handlers](#label-Begin-Less+Exception+Handlers).
+- Contains code whose raised exception (if any) is covered
+ by the handler.
+- Ends with the first following `rescue` statement.
+
+#### Rescue Clauses
+
+A rescue clause:
+
+- Starts with a `rescue` statement.
+- Contains code that is to be executed for certain raised exceptions.
+- Ends with the first following `rescue`,
+ `else`, `ensure`, or `end` statement.
+
+##### Rescued Exceptions
+
+A `rescue` statement may include one or more classes
+that are to be rescued;
+if none is given, StandardError is assumed.
+
+The rescue clause rescues both the specified class
+(or StandardError if none given) or any of its subclasses;
+see [Built-In Exception Class Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
+
+```rb
+begin
+ 1 / 0 # Raises ZeroDivisionError, a subclass of StandardError.
+rescue
+ puts "Rescued #{$!.class}"
+end
+```
+
+Output:
+
+```
+Rescued ZeroDivisionError
+```
+
+If the `rescue` statement specifies an exception class,
+only that class (or one of its subclasses) is rescued;
+this example exits with a ZeroDivisionError,
+which was not rescued because it is not ArgumentError or one of its subclasses:
+
+```rb
+begin
+ 1 / 0
+rescue ArgumentError
+ puts "Rescued #{$!.class}"
+end
+```
+
+A `rescue` statement may specify multiple classes,
+which means that its code rescues an exception
+of any of the given classes (or their subclasses):
+
+```rb
+begin
+ 1 / 0
+rescue FloatDomainError, ZeroDivisionError
+ puts "Rescued #{$!.class}"
+end
+```
+
+##### Multiple Rescue Clauses
+
+An exception handler may contain multiple rescue clauses;
+in that case, the first clause that rescues the exception does so,
+and those before and after are ignored:
+
+```rb
+begin
+ Dir.open('nosuch')
+rescue Errno::ENOTDIR
+ puts "Rescued #{$!.class}"
+rescue Errno::ENOENT
+ puts "Rescued #{$!.class}"
+end
+```
+
+Output:
+
+```
+Rescued Errno::ENOENT
+```
+
+##### Capturing the Rescued \Exception
+
+A `rescue` statement may specify a variable
+whose value becomes the rescued exception
+(an instance of Exception or one of its subclasses:
+
+```rb
+begin
+ 1 / 0
+rescue => x
+ puts x.class
+ puts x.message
+end
+```
+
+Output:
+
+```
+ZeroDivisionError
+divided by 0
+```
+
+##### Global Variables
+
+Two read-only global variables always have `nil` value
+except in a rescue clause;
+they're:
+
+- `$!`: contains the rescued exception.
+- `$@`: contains its backtrace.
+
+Example:
+
+```rb
+begin
+ 1 / 0
+rescue
+ p $!
+ p $@
+end
+```
+
+Output:
+
+```
+#<ZeroDivisionError: divided by 0>
+["t.rb:2:in 'Integer#/'", "t.rb:2:in '<main>'"]
+```
+
+##### Cause
+
+In a rescue clause, the method Exception#cause returns the previous value of `$!`,
+which may be `nil`;
+elsewhere, the method returns `nil`.
+
+Example:
+
+```rb
+begin
+ raise('Boom 0')
+rescue => x0
+ puts "Exception: #{x0.inspect}; $!: #{$!.inspect}; cause: #{x0.cause.inspect}."
+ begin
+ raise('Boom 1')
+ rescue => x1
+ puts "Exception: #{x1.inspect}; $!: #{$!.inspect}; cause: #{x1.cause.inspect}."
+ begin
+ raise('Boom 2')
+ rescue => x2
+ puts "Exception: #{x2.inspect}; $!: #{$!.inspect}; cause: #{x2.cause.inspect}."
+ end
+ end
+end
+```
+
+Output:
+
+```
+Exception: #<RuntimeError: Boom 0>; $!: #<RuntimeError: Boom 0>; cause: nil.
+Exception: #<RuntimeError: Boom 1>; $!: #<RuntimeError: Boom 1>; cause: #<RuntimeError: Boom 0>.
+Exception: #<RuntimeError: Boom 2>; $!: #<RuntimeError: Boom 2>; cause: #<RuntimeError: Boom 1>.
+```
+
+#### Else Clause
+
+The `else` clause:
+
+- Starts with an `else` statement.
+- Contains code that is to be executed if no exception is raised in the begin clause.
+- Ends with the first following `ensure` or `end` statement.
+
+```rb
+begin
+ puts 'Begin.'
+rescue
+ puts 'Rescued an exception!'
+else
+ puts 'No exception raised.'
+end
+```
+
+Output:
+
+```
+Begin.
+No exception raised.
+```
+
+#### Ensure Clause
+
+The ensure clause:
+
+- Starts with an `ensure` statement.
+- Contains code that is to be executed
+ regardless of whether an exception is raised,
+ and regardless of whether a raised exception is handled.
+- Ends with the first following `end` statement.
+
+```rb
+def foo(boom: false)
+ puts 'Begin.'
+ raise 'Boom!' if boom
+rescue
+ puts 'Rescued an exception!'
+else
+ puts 'No exception raised.'
+ensure
+ puts 'Always do this.'
+end
+
+foo(boom: true)
+foo(boom: false)
+```
+
+Output:
+
+```
+Begin.
+Rescued an exception!
+Always do this.
+Begin.
+No exception raised.
+Always do this.
+```
+
+#### End Statement
+
+The `end` statement ends the handler.
+
+Code following it is reached only if any raised exception is rescued.
+
+#### Begin-Less \Exception Handlers
+
+As seen above, an exception handler may be implemented with `begin` and `end`.
+
+An exception handler may also be implemented as:
+
+- A method body:
+
+ ```rb
+ def foo(boom: false) # Serves as beginning of exception handler.
+ puts 'Begin.'
+ raise 'Boom!' if boom
+ rescue
+ puts 'Rescued an exception!'
+ else
+ puts 'No exception raised.'
+ end # Serves as end of exception handler.
+ ```
+
+- A block:
+
+ ```rb
+ Dir.chdir('.') do |dir| # Serves as beginning of exception handler.
+ raise 'Boom!'
+ rescue
+ puts 'Rescued an exception!'
+ end # Serves as end of exception handler.
+ ```
+
+#### Re-Raising an \Exception
+
+It can be useful to rescue an exception, but allow its eventual effect;
+for example, a program can rescue an exception, log data about it,
+and then "reinstate" the exception.
+
+This may be done via the `raise` method, but in a special way;
+a rescuing clause:
+
+ - Captures an exception.
+ - Does whatever is needed concerning the exception (such as logging it).
+ - Calls method `raise` with no argument,
+ which raises the rescued exception:
+
+```rb
+begin
+ 1 / 0
+rescue ZeroDivisionError
+ # Do needful things (like logging).
+ raise # Raised exception will be ZeroDivisionError, not RuntimeError.
+end
+```
+
+Output:
+
+```
+ruby t.rb
+t.rb:2:in 'Integer#/': divided by 0 (ZeroDivisionError)
+ from t.rb:2:in '<main>'
+```
+
+#### Retrying
+
+It can be useful to retry a begin clause;
+for example, if it must access a possibly-volatile resource
+(such as a web page),
+it can be useful to try the access more than once
+(in the hope that it may become available):
+
+```rb
+retries = 0
+begin
+ puts "Try ##{retries}."
+ raise 'Boom'
+rescue
+ puts "Rescued retry ##{retries}."
+ if (retries += 1) < 3
+ puts 'Retrying'
+ retry
+ else
+ puts 'Giving up.'
+ raise
+ end
+end
+```
+
+```
+Try #0.
+Rescued retry #0.
+Retrying
+Try #1.
+Rescued retry #1.
+Retrying
+Try #2.
+Rescued retry #2.
+Giving up.
+# RuntimeError ('Boom') raised.
+```
+
+Note that the retry re-executes the entire begin clause,
+not just the part after the point of failure.
+
+## Raising an \Exception
+
+Method Kernel#raise raises an exception.
+
+## Custom Exceptions
+
+To provide additional or alternate information,
+you may create custom exception classes.
+Each should be a subclass of one of the built-in exception classes
+(commonly StandardError or RuntimeError);
+see [Built-In Exception Class Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
+
+```rb
+class MyException < StandardError; end
+```
+
+## Messages
+
+Every `Exception` object has a message,
+which is a string that is set at the time the object is created;
+see Exception.new.
+
+The message cannot be changed, but you can create a similar object with a different message;
+see Exception#exception.
+
+This method returns the message as defined:
+
+- Exception#message.
+
+Two other methods return enhanced versions of the message:
+
+- Exception#detailed_message: adds exception class name, with optional highlighting.
+- Exception#full_message: adds exception class name and backtrace, with optional highlighting.
+
+Each of the two methods above accepts keyword argument `highlight`;
+if the value of keyword `highlight` is `true`,
+the returned string includes bolding and underlining ANSI codes (see below)
+to enhance the appearance of the message.
+
+Any exception class (Ruby or custom) may choose to override either of these methods,
+and may choose to interpret keyword argument <tt>highlight: true</tt>
+to mean that the returned message should contain
+[ANSI codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
+that specify color, bolding, and underlining.
+
+Because the enhanced message may be written to a non-terminal device
+(e.g., into an HTML page),
+it is best to limit the ANSI codes to these widely-supported codes:
+
+- Begin font color:
+
+ | Color | ANSI Code |
+ |---------|------------------|
+ | Red | <tt>\\e[31m</tt> |
+ | Green | <tt>\\e[32m</tt> |
+ | Yellow | <tt>\\e[33m</tt> |
+ | Blue | <tt>\\e[34m</tt> |
+ | Magenta | <tt>\\e[35m</tt> |
+ | Cyan | <tt>\\e[36m</tt> |
+
+<br>
+
+- Begin font attribute:
+
+ | Attribute | ANSI Code |
+ |-----------|-----------------|
+ | Bold | <tt>\\e[1m</tt> |
+ | Underline | <tt>\\e[4m</tt> |
+
+<br>
+
+- End all of the above:
+
+ | Color | ANSI Code |
+ |-------|-----------------|
+ | Reset | <tt>\\e[0m</tt> |
+
+It's also best to craft a message that is conveniently human-readable,
+even if the ANSI codes are included "as-is"
+(rather than interpreted as font directives).
+
+## Backtraces
+
+A _backtrace_ is a record of the methods currently
+in the [call stack](https://en.wikipedia.org/wiki/Call_stack);
+each such method has been called, but has not yet returned.
+
+These methods return backtrace information:
+
+- Exception#backtrace: returns the backtrace as an array of strings or `nil`.
+- Exception#backtrace_locations: returns the backtrace as an array
+ of Thread::Backtrace::Location objects or `nil`.
+ Each Thread::Backtrace::Location object gives detailed information about a called method.
+
+By default, Ruby sets the backtrace of the exception to the location where it
+was raised.
+
+The developer might adjust this by either providing `backtrace` argument
+to Kernel#raise, or using Exception#set_backtrace.
+
+Note that:
+
+- by default, both `backtrace` and `backtrace_locations` represent the same backtrace;
+- if the developer sets the backtrace by one of the above methods to an array of
+ Thread::Backtrace::Location, they still represent the same backtrace;
+- if the developer sets the backtrace to a string or an array of strings:
+ - by Kernel#raise: `backtrace_locations` become `nil`;
+ - by Exception#set_backtrace: `backtrace_locations` preserve the original
+ value;
+- if the developer sets the backtrace to `nil` by Exception#set_backtrace,
+ `backtrace_locations` preserve the original value; but if the exception is then
+ reraised, both `backtrace` and `backtrace_locations` become the location of reraise.
diff --git a/doc/language/fiber.md b/doc/language/fiber.md
new file mode 100644
index 0000000000..d9011cce2f
--- /dev/null
+++ b/doc/language/fiber.md
@@ -0,0 +1,290 @@
+# Fiber
+
+Fibers provide a mechanism for cooperative concurrency.
+
+## Context Switching
+
+Fibers execute a user-provided block. During the execution, the block may call `Fiber.yield` or `Fiber.transfer` to switch to another fiber. `Fiber#resume` is used to continue execution from the point where `Fiber.yield` was called.
+
+```rb
+#!/usr/bin/env ruby
+
+puts "1: Start program."
+
+f = Fiber.new do
+ puts "3: Entered fiber."
+ Fiber.yield
+ puts "5: Resumed fiber."
+end
+
+puts "2: Resume fiber first time."
+f.resume
+
+puts "4: Resume fiber second time."
+f.resume
+
+puts "6: Finished."
+```
+
+This program demonstrates the flow control of fibers.
+
+## Scheduler
+
+The scheduler interface is used to intercept blocking operations. A typical
+implementation would be a wrapper for a gem like `EventMachine` or `Async`. This
+design provides separation of concerns between the event loop implementation
+and application code. It also allows for layered schedulers which can perform
+instrumentation.
+
+To set the scheduler for the current thread:
+
+```rb
+Fiber.set_scheduler(MyScheduler.new)
+```
+
+When the thread exits, there is an implicit call to `set_scheduler`:
+
+```rb
+Fiber.set_scheduler(nil)
+```
+
+### Design
+
+The scheduler interface is designed to be a un-opinionated light-weight layer
+between user code and blocking operations. The scheduler hooks should avoid
+translating or converting arguments or return values. Ideally, the exact same
+arguments from the user code are provided directly to the scheduler hook with
+no changes.
+
+### Interface
+
+This is the interface you need to implement.
+
+```rb
+class Scheduler
+ # Wait for the specified process ID to exit.
+ # This hook is optional.
+ # @parameter pid [Integer] The process ID to wait for.
+ # @parameter flags [Integer] A bit-mask of flags suitable for `Process::Status.wait`.
+ # @returns [Process::Status] A process status instance.
+ def process_wait(pid, flags)
+ Thread.new do
+ Process::Status.wait(pid, flags)
+ end.value
+ end
+
+ # Wait for the given io readiness to match the specified events within
+ # the specified timeout.
+ # @parameter event [Integer] A bit mask of `IO::READABLE`,
+ # `IO::WRITABLE` and `IO::PRIORITY`.
+ # @parameter timeout [Numeric] The amount of time to wait for the event in seconds.
+ # @returns [Integer] The subset of events that are ready.
+ def io_wait(io, events, timeout)
+ end
+
+ # Read from the given io into the specified buffer.
+ # WARNING: Experimental hook! Do not use in production code!
+ # @parameter io [IO] The io to read from.
+ # @parameter buffer [IO::Buffer] The buffer to read into.
+ # @parameter length [Integer] The minimum amount to read.
+ def io_read(io, buffer, length)
+ end
+
+ # Write from the given buffer into the specified IO.
+ # WARNING: Experimental hook! Do not use in production code!
+ # @parameter io [IO] The io to write to.
+ # @parameter buffer [IO::Buffer] The buffer to write from.
+ # @parameter length [Integer] The minimum amount to write.
+ def io_write(io, buffer, length)
+ end
+
+ # Sleep the current task for the specified duration, or forever if not
+ # specified.
+ # @parameter duration [Numeric] The amount of time to sleep in seconds.
+ def kernel_sleep(duration = nil)
+ end
+
+ # Execute the given block. If the block execution exceeds the given timeout,
+ # the specified exception `klass` will be raised. Typically, only non-blocking
+ # methods which enter the scheduler will raise such exceptions.
+ # @parameter duration [Integer] The amount of time to wait, after which an exception will be raised.
+ # @parameter klass [Class] The exception class to raise.
+ # @parameter *arguments [Array] The arguments to send to the constructor of the exception.
+ # @yields {...} The user code to execute.
+ def timeout_after(duration, klass, *arguments, &block)
+ end
+
+ # Resolve hostname to an array of IP addresses.
+ # This hook is optional.
+ # @parameter hostname [String] Example: "www.ruby-lang.org".
+ # @returns [Array] An array of IPv4 and/or IPv6 address strings that the hostname resolves to.
+ def address_resolve(hostname)
+ end
+
+ # Block the calling fiber.
+ # @parameter blocker [Object] What we are waiting on, informational only.
+ # @parameter timeout [Numeric | Nil] The amount of time to wait for in seconds.
+ # @returns [Boolean] Whether the blocking operation was successful or not.
+ def block(blocker, timeout = nil)
+ end
+
+ # Unblock the specified fiber.
+ # @parameter blocker [Object] What we are waiting on, informational only.
+ # @parameter fiber [Fiber] The fiber to unblock.
+ # @reentrant Thread safe.
+ def unblock(blocker, fiber)
+ end
+
+ # Intercept the creation of a non-blocking fiber.
+ # @returns [Fiber]
+ def fiber(&block)
+ Fiber.new(blocking: false, &block)
+ end
+
+ # Invoked when the thread exits.
+ def close
+ self.run
+ end
+
+ def run
+ # Implement event loop here.
+ end
+end
+```
+
+Additional hooks may be introduced in the future, we will use feature detection
+in order to enable these hooks.
+
+### Non-blocking Execution
+
+The scheduler hooks will only be used in special non-blocking execution
+contexts. Non-blocking execution contexts introduce non-determinism because the
+execution of scheduler hooks may introduce context switching points into your
+program.
+
+#### Fibers
+
+Fibers can be used to create non-blocking execution contexts.
+
+```rb
+Fiber.new do
+ puts Fiber.current.blocking? # false
+
+ # May invoke `Fiber.scheduler&.io_wait`.
+ io.read(...)
+
+ # May invoke `Fiber.scheduler&.io_wait`.
+ io.write(...)
+
+ # Will invoke `Fiber.scheduler&.kernel_sleep`.
+ sleep(n)
+end.resume
+```
+
+We also introduce a new method which simplifies the creation of these
+non-blocking fibers:
+
+```rb
+Fiber.schedule do
+ puts Fiber.current.blocking? # false
+end
+```
+
+The purpose of this method is to allow the scheduler to internally decide the
+policy for when to start the fiber, and whether to use symmetric or asymmetric
+fibers.
+
+You can also create blocking execution contexts:
+
+```rb
+Fiber.new(blocking: true) do
+ # Won't use the scheduler:
+ sleep(n)
+end
+```
+
+However you should generally avoid this unless you are implementing a scheduler.
+
+#### IO
+
+By default, I/O is non-blocking. Not all operating systems support non-blocking
+I/O. Windows is a notable example where socket I/O can be non-blocking but pipe
+I/O is blocking. Provided that there *is* a scheduler and the current thread *is
+non-blocking*, the operation will invoke the scheduler.
+
+##### `IO#close`
+
+Closing an IO interrupts all blocking operations on that IO. When a thread calls `IO#close`, it first attempts to interrupt any threads or fibers that are blocked on that IO. The closing thread waits until all blocked threads and fibers have been properly interrupted and removed from the IO's blocking list. Each interrupted thread or fiber receives an `IOError` and is cleanly removed from the blocking operation. Only after all blocking operations have been interrupted and cleaned up will the actual file descriptor be closed, ensuring proper resource cleanup and preventing potential race conditions.
+
+For fibers managed by a scheduler, the interruption process involves calling `rb_fiber_scheduler_fiber_interrupt` on the scheduler. This allows the scheduler to handle the interruption in a way that's appropriate for its event loop implementation. The scheduler can then notify the fiber, which will receive an `IOError` and be removed from the blocking operation. This mechanism ensures that fiber-based concurrency works correctly with IO operations, even when those operations are interrupted by `IO#close`.
+
+```mermaid
+sequenceDiagram
+ participant ThreadB
+ participant ThreadA
+ participant Scheduler
+ participant IO
+ participant Fiber1
+ participant Fiber2
+
+ Note over ThreadA: Thread A has a fiber scheduler
+ activate Scheduler
+ ThreadA->>Fiber1: Schedule Fiber 1
+ activate Fiber1
+ Fiber1->>IO: IO.read
+ IO->>Scheduler: rb_thread_io_blocking_region
+ deactivate Fiber1
+
+ ThreadA->>Fiber2: Schedule Fiber 2
+ activate Fiber2
+ Fiber2->>IO: IO.read
+ IO->>Scheduler: rb_thread_io_blocking_region
+ deactivate Fiber2
+
+ Note over Fiber1,Fiber2: Both fibers blocked on same IO
+
+ Note over ThreadB: IO.close
+ activate ThreadB
+ ThreadB->>IO: thread_io_close_notify_all
+ Note over ThreadB: rb_mutex_sleep
+
+ IO->>Scheduler: rb_fiber_scheduler_fiber_interrupt(Fiber1)
+ Scheduler->>Fiber1: fiber_interrupt with IOError
+ activate Fiber1
+ Note over IO: fiber_interrupt causes removal from blocking list
+ Fiber1->>IO: rb_io_blocking_operation_exit()
+ IO-->>ThreadB: Wakeup thread
+ deactivate Fiber1
+
+ IO->>Scheduler: rb_fiber_scheduler_fiber_interrupt(Fiber2)
+ Scheduler->>Fiber2: fiber_interrupt with IOError
+ activate Fiber2
+ Note over IO: fiber_interrupt causes removal from blocking list
+ Fiber2->>IO: rb_io_blocking_operation_exit()
+ IO-->>ThreadB: Wakeup thread
+ deactivate Fiber2
+ deactivate Scheduler
+
+ Note over ThreadB: Blocking operations list empty
+ ThreadB->>IO: close(fd)
+ deactivate ThreadB
+```
+
+#### Mutex
+
+The `Mutex` class can be used in a non-blocking context and is fiber specific.
+
+#### ConditionVariable
+
+The `ConditionVariable` class can be used in a non-blocking context and is
+fiber-specific.
+
+#### Queue / SizedQueue
+
+The `Queue` and `SizedQueue` classes can be used in a non-blocking context and
+are fiber-specific.
+
+#### Thread
+
+The `Thread#join` operation can be used in a non-blocking context and is
+fiber-specific.
diff --git a/doc/language/format_specifications.rdoc b/doc/language/format_specifications.rdoc
new file mode 100644
index 0000000000..763470aa02
--- /dev/null
+++ b/doc/language/format_specifications.rdoc
@@ -0,0 +1,354 @@
+= Format Specifications
+
+Several Ruby core classes have instance method +printf+ or +sprintf+:
+
+- ARGF#printf
+- IO#printf
+- Kernel#printf
+- Kernel#sprintf
+
+Each of these methods takes:
+
+- Argument +format_string+, which has zero or more
+ embedded _format_ _specifications_ (see below).
+- Arguments <tt>*arguments</tt>, which are zero or more objects to be formatted.
+
+Each of these methods prints or returns the string
+resulting from replacing each
+format specification embedded in +format_string+ with a string form
+of the corresponding argument among +arguments+.
+
+A simple example:
+
+ sprintf('Name: %s; value: %d', 'Foo', 0) # => "Name: Foo; value: 0"
+
+A format specification has the form:
+
+ %[flags][width][.precision]type
+
+It consists of:
+
+- A leading percent character.
+- Zero or more _flags_ (each is a character).
+- An optional _width_ _specifier_ (an integer, or <tt>*</tt>).
+- An optional _precision_ _specifier_ (a period followed by a non-negative
+ integer, or <tt>*</tt>).
+- A _type_ _specifier_ (a character).
+
+Except for the leading percent character,
+the only required part is the type specifier, so we begin with that.
+
+== Type Specifiers
+
+This section provides a brief explanation of each type specifier.
+The links lead to the details and examples.
+
+=== \Integer Type Specifiers
+
+- +b+ or +B+: Format +argument+ as a binary integer.
+ See {Specifiers b and B}[rdoc-ref:@Specifiers+b+and+B].
+- +d+, +i+, or +u+ (all are identical):
+ Format +argument+ as a decimal integer.
+ See {Specifier d}[rdoc-ref:@Specifier+d].
+- +o+: Format +argument+ as an octal integer.
+ See {Specifier o}[rdoc-ref:@Specifier+o].
+- +x+ or +X+: Format +argument+ as a hexadecimal integer.
+ See {Specifiers x and X}[rdoc-ref:@Specifiers+x+and+X].
+
+=== Floating-Point Type Specifiers
+
+- +a+ or +A+: Format +argument+ as hexadecimal floating-point number.
+ See {Specifiers a and A}[rdoc-ref:@Specifiers+a+and+A].
+- +e+ or +E+: Format +argument+ in scientific notation.
+ See {Specifiers e and E}[rdoc-ref:@Specifiers+e+and+E].
+- +f+: Format +argument+ as a decimal floating-point number.
+ See {Specifier f}[rdoc-ref:@Specifier+f].
+- +g+ or +G+: Format +argument+ in a "general" format.
+ See {Specifiers g and G}[rdoc-ref:@Specifiers+g+and+G].
+
+=== Other Type Specifiers
+
+- +c+: Format +argument+ as a character.
+ See {Specifier c}[rdoc-ref:@Specifier+c].
+- +p+: Format +argument+ as a string via <tt>argument.inspect</tt>.
+ See {Specifier p}[rdoc-ref:@Specifier+p].
+- +s+: Format +argument+ as a string via <tt>argument.to_s</tt>.
+ See {Specifier s}[rdoc-ref:@Specifier+s].
+- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character.
+ See {Specifier %}[rdoc-ref:@Specifier+-25].
+
+== Flags
+
+The effect of a flag may vary greatly among type specifiers.
+These remarks are general in nature.
+See {type-specific details}[rdoc-ref:@Type+Specifier+Details+and+Examples].
+
+Multiple flags may be given with single type specifier;
+order does not matter.
+
+=== <tt>' '</tt> Flag
+
+Insert a space before a non-negative number:
+
+ sprintf('%d', 10) # => "10"
+ sprintf('% d', 10) # => " 10"
+
+Insert a minus sign for negative value:
+
+ sprintf('%d', -10) # => "-10"
+ sprintf('% d', -10) # => "-10"
+
+=== <tt>'#'</tt> Flag
+
+Use an alternate format; varies among types:
+
+ sprintf('%x', 100) # => "64"
+ sprintf('%#x', 100) # => "0x64"
+
+=== <tt>'+'</tt> Flag
+
+Add a leading plus sign for a non-negative number:
+
+ sprintf('%x', 100) # => "64"
+ sprintf('%+x', 100) # => "+64"
+
+=== <tt>'-'</tt> Flag
+
+Left justify the value in its field:
+
+ sprintf('%6d', 100) # => " 100"
+ sprintf('%-6d', 100) # => "100 "
+
+=== <tt>'0'</tt> Flag
+
+Left-pad with zeros instead of spaces:
+
+ sprintf('%6d', 100) # => " 100"
+ sprintf('%06d', 100) # => "000100"
+
+=== <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
+
+In general, a width specifier determines the minimum width (in characters)
+of the formatted field:
+
+ sprintf('%10d', 100) # => " 100"
+
+ # Left-justify if negative.
+ sprintf('%-10d', 100) # => "100 "
+
+ # Ignore if too small.
+ sprintf('%1d', 100) # => "100"
+
+If the width specifier is <tt>'*'</tt> instead of an integer, the actual minimum
+width is taken from the argument list:
+
+ sprintf('%*d', 20, 14) # => " 14"
+
+== Precision Specifier
+
+A precision specifier is a decimal point followed by zero or more
+decimal digits.
+
+For integer type specifiers, the precision specifies the minimum number of
+digits to be written. If the precision is shorter than the integer, the result is
+padded with leading zeros. There is no modification or truncation of the result
+if the integer is longer than the precision:
+
+ sprintf('%.3d', 1) # => "001"
+ sprintf('%.3d', 1000) # => "1000"
+
+ # If the precision is 0 and the value is 0, nothing is written
+ sprintf('%.d', 0) # => ""
+ sprintf('%.0d', 0) # => ""
+
+For the +a+/+A+, +e+/+E+, +f+ specifiers, the precision specifies
+the number of digits after the decimal point to be written:
+
+ sprintf('%.2f', 3.14159) # => "3.14"
+ sprintf('%.10f', 3.14159) # => "3.1415900000"
+
+ # With no precision specifier, defaults to 6-digit precision.
+ sprintf('%f', 3.14159) # => "3.141590"
+
+For the +g+/+G+ specifiers, the precision specifies
+the number of significant digits to be written:
+
+ sprintf('%.2g', 123.45) # => "1.2e+02"
+ sprintf('%.3g', 123.45) # => "123"
+ sprintf('%.10g', 123.45) # => "123.45"
+
+ # With no precision specifier, defaults to 6 significant digits.
+ sprintf('%g', 123.456789) # => "123.457"
+
+For the +s+, +p+ specifiers, the precision specifies
+the number of characters to write:
+
+ sprintf('%s', Time.now) # => "2022-05-04 11:59:16 -0400"
+ sprintf('%.10s', Time.now) # => "2022-05-04"
+
+If the precision specifier is <tt>'*'</tt> instead of a non-negative integer,
+the actual precision is taken from the argument list:
+
+ sprintf('%.*d', 20, 1) # => "00000000000000000001"
+
+== Type Specifier Details and Examples
+
+=== Specifiers +a+ and +A+
+
+Format +argument+ as hexadecimal floating-point number:
+
+ sprintf('%a', 3.14159) # => "0x1.921f9f01b866ep+1"
+ sprintf('%a', -3.14159) # => "-0x1.921f9f01b866ep+1"
+ sprintf('%a', 4096) # => "0x1p+12"
+ sprintf('%a', -4096) # => "-0x1p+12"
+
+ # Capital 'A' means that alphabetical characters are printed in upper case.
+ sprintf('%A', 4096) # => "0X1P+12"
+ sprintf('%A', -4096) # => "-0X1P+12"
+
+=== Specifiers +b+ and +B+
+
+The two specifiers +b+ and +B+ behave identically
+except when flag <tt>'#'</tt>+ is used.
+
+Format +argument+ as a binary integer:
+
+ sprintf('%b', 1) # => "1"
+ sprintf('%b', 4) # => "100"
+
+ # Prefix '..' for negative value.
+ sprintf('%b', -4) # => "..100"
+
+ # Alternate format.
+ sprintf('%#b', 4) # => "0b100"
+ sprintf('%#B', 4) # => "0B100"
+
+=== Specifier +c+
+
+Format +argument+ as a single character:
+
+ sprintf('%c', 'A') # => "A"
+ sprintf('%c', 65) # => "A"
+
+This behaves like String#<<, except for raising ArgumentError instead of RangeError.
+
+=== Specifier +d+
+
+Format +argument+ as a decimal integer:
+
+ sprintf('%d', 100) # => "100"
+ sprintf('%d', -100) # => "-100"
+
+Flag <tt>'#'</tt> does not apply.
+
+=== Specifiers +e+ and +E+
+
+Format +argument+ in
+{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]:
+
+ sprintf('%e', 3.14159) # => "3.141590e+00"
+ sprintf('%E', -3.14159) # => "-3.141590E+00"
+
+=== Specifier +f+
+
+Format +argument+ as a floating-point number:
+
+ sprintf('%f', 3.14159) # => "3.141590"
+ sprintf('%f', -3.14159) # => "-3.141590"
+
+Flag <tt>'#'</tt> does not apply.
+
+=== 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.
+Otherwise format +argument+ using floating-point form (+f+ specifier):
+
+ sprintf('%g', 100) # => "100"
+ sprintf('%g', 100.0) # => "100"
+ sprintf('%g', 3.14159) # => "3.14159"
+ sprintf('%g', 100000000000) # => "1e+11"
+ sprintf('%g', 0.000000000001) # => "1e-12"
+
+ # Capital 'G' means use capital 'E'.
+ sprintf('%G', 100000000000) # => "1E+11"
+ sprintf('%G', 0.000000000001) # => "1E-12"
+
+ # Alternate format.
+ sprintf('%#g', 100000000000) # => "1.00000e+11"
+ sprintf('%#g', 0.000000000001) # => "1.00000e-12"
+ sprintf('%#G', 100000000000) # => "1.00000E+11"
+ sprintf('%#G', 0.000000000001) # => "1.00000E-12"
+
+=== Specifier +o+
+
+Format +argument+ as an octal integer.
+If +argument+ is negative, it will be formatted as a two's complement
+prefixed with +..7+:
+
+ sprintf('%o', 16) # => "20"
+
+ # Prefix '..7' for negative value.
+ sprintf('%o', -16) # => "..760"
+
+ # Prefix zero for alternate format if positive.
+ sprintf('%#o', 16) # => "020"
+ sprintf('%#o', -16) # => "..760"
+
+=== 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+
+
+Format +argument+ as a string via <tt>argument.to_s</tt>:
+
+ t = Time.now
+ sprintf('%s', t) # => "2022-05-01 13:42:07 -0500"
+
+Flag <tt>'#'</tt> does not apply.
+
+=== Specifiers +x+ and +X+
+
+Format +argument+ as a hexadecimal integer.
+If +argument+ is negative, it will be formatted as a two's complement
+prefixed with +..f+:
+
+ sprintf('%x', 100) # => "64"
+
+ # Prefix '..f' for negative value.
+ sprintf('%x', -100) # => "..f9c"
+
+ # Use alternate format.
+ sprintf('%#x', 100) # => "0x64"
+
+ # Alternate format for negative value.
+ sprintf('%#x', -100) # => "0x..f9c"
+
+=== Specifier <tt>%</tt>
+
+Format +argument+ (<tt>'%'</tt>) as a single percent character:
+
+ sprintf('%d %%', 100) # => "100 %"
+
+Flags do not apply.
+
+== Reference by Name
+
+For more complex formatting, Ruby supports a reference by name.
+%<name>s style uses format style, but %{name} style doesn't.
+
+Examples:
+
+ sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
+ sprintf("%{foo}f", { :foo => 1 }) # => "1f"
diff --git a/doc/language/globals.md b/doc/language/globals.md
new file mode 100644
index 0000000000..0f6b632a08
--- /dev/null
+++ b/doc/language/globals.md
@@ -0,0 +1,611 @@
+# Pre-Defined Global Variables
+
+Some of the pre-defined global variables have synonyms
+that are available via module English.
+For each of those, the \English synonym is given.
+
+To use the module:
+
+```ruby
+require 'English'
+```
+
+## In Brief
+
+### Exceptions
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:--------:|:-----------------:|----------------------------------------|:---------:|:---------:|--------------|
+| `$!` | `$ERROR_INFO` | \Exception object or `nil` | `nil` | Yes | Kernel#raise |
+| `$@` | `$ERROR_POSITION` | \Array of backtrace positions or `nil` | `nil` | Yes | Kernel#raise |
+
+### Matched \Data
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:---------:|:-------------------:|-----------------------------------|:---------:|:---------:|-----------------|
+| `$~` | `$LAST_MATCH_INFO` | \MatchData object or `nil` | `nil` | No | Matcher methods |
+| `$&` | `$MATCH` | Matched substring or `nil` | `nil` | No | Matcher methods |
+| `` $` `` | `$PRE_MATCH` | Substring left of match or `nil` | `nil` | No | Matcher methods |
+| `$'` | `$POST_MATCH` | Substring right of match or `nil` | `nil` | No | Matcher methods |
+| `$+` | `$LAST_PAREN_MATCH` | Last group matched or `nil` | `nil` | No | Matcher methods |
+| `$1` | | First group matched or `nil` | `nil` | Yes | Matcher methods |
+| `$2` | | Second group matched or `nil` | `nil` | Yes | Matcher methods |
+| `$n` | | <i>n</i>th group matched or `nil` | `nil` | Yes | Matcher methods |
+
+### Separators
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-----------:|:---------------------------:|-------------------------|:---------:|:---------:|----------|
+| `$/`, `$-0` | `$INPUT_RECORD_SEPARATOR` | Input record separator | Newline | No | |
+| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator | `nil` | No | |
+
+### Streams
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:---------:|:----------------------------:|---------------------------------------------|:---------:|:---------:|----------------------|
+| `$stdin` | | Standard input stream | `STDIN` | No | |
+| `$stdout` | | Standard output stream | `STDOUT` | No | |
+| `$stderr` | | Standard error stream | `STDERR` | No | |
+| `$<` | `$DEFAULT_INPUT` | Default standard input | `ARGF` | Yes | |
+| `$>` | `$DEFAULT_OUTPUT` | Default standard output | `STDOUT` | No | |
+| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream | 0 | No | Certain read methods |
+| `$_` | `$LAST_READ_LINE` | String from most recently read stream | `nil` | No | Certain read methods |
+
+### Processes
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-------------------------:|:----------------------:|---------------------------------|:-------------:|:---------:|----------|
+| `$0`, `$PROGRAM_NAME` | | Program name | Program name | No | |
+| `$*` | `$ARGV` | \ARGV array | `ARGV` | Yes | |
+| `$$` | `$PROCESS_ID`, `$PID` | Process id | Process PID | Yes | |
+| `$?` | `$CHILD_STATUS` | Status of recently exited child | `nil` | Yes | |
+| `$LOAD_PATH`, `$:`, `$-I` | | \Array of search paths | Ruby defaults | Yes | |
+| `$LOADED_FEATURES`, `$"` | | \Array of load paths | Ruby defaults | Yes | |
+
+### Debugging
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-----------:|:--------:|--------------------------------------------|:----------------------------:|:---------:|----------|
+| `$FILENAME` | | Value returned by method `ARGF.filename` | Command-line argument or '-' | Yes | |
+| `$DEBUG` | | Whether option `-d` or `--debug` was given | Command-line option | No | |
+| `$VERBOSE` | | Whether option `-V` or `-W` was given | Command-line option | No | |
+
+### Other Variables
+
+| Variable | \English | Contains | Initially | Read-Only | Reset By |
+|:-----------:|:--------:|-----------------------------------------------|:---------:|:---------:|----------|
+| `$-F`, `$;` | | Separator given with command-line option `-F` | | | |
+| `$-a` | | Whether option `-a` was given | | Yes | |
+| `$-i` | | Extension given with command-line option `-i` | | No | |
+| `$-l` | | Whether option `-l` was given | | Yes | |
+| `$-p` | | Whether option `-p` was given | | Yes | |
+| `$F` | | \Array of `$_` split by `$-F` | | | |
+
+## Exceptions
+
+### `$!` (\Exception)
+
+Contains the Exception object set by Kernel#raise:
+
+```ruby
+begin
+ raise RuntimeError.new('Boo!')
+rescue RuntimeError
+ p $!
+end
+```
+
+Output:
+
+```
+#<RuntimeError: Boo!>
+```
+
+English - `$ERROR_INFO`
+
+### `$@` (Backtrace)
+
+Same as `$!.backtrace`;
+returns an array of backtrace positions:
+
+```ruby
+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 - `$ERROR_POSITION`.
+
+## Matched \Data
+
+These global variables store information about the most recent
+successful match in the current scope.
+
+For details and examples,
+see [Regexp Global Variables].
+
+### `$~` (\MatchData)
+
+MatchData object created from the match;
+thread-local and frame-local.
+
+English - `$LAST_MATCH_INFO`.
+
+### `$&` (Matched Substring)
+
+The matched string.
+
+English - `$MATCH`.
+
+### `` $` `` (Pre-Match Substring)
+The string to the left of the match.
+
+English - `$PREMATCH`.
+
+### `$'` (Post-Match Substring)
+
+The string to the right of the match.
+
+English - `$POSTMATCH`.
+
+### `$+` (Last Matched Group)
+
+The last group matched.
+
+English - `$LAST_PAREN_MATCH`.
+
+### `$1`, `$2`, \Etc. (Matched Group)
+
+For <tt>$n</tt> the <i>n</i>th group of the match.
+
+No \English.
+
+## Separators
+
+### `$/` (Input Record Separator)
+
+An input record separator, initially newline.
+Set by the [command-line option `-0`].
+
+Setting to non-nil value by other than the command-line option is
+deprecated.
+
+English - `$INPUT_RECORD_SEPARATOR`, `$RS`.
+
+Aliased as `$-0`.
+
+### `$\` (Output Record Separator)
+
+An output record separator, initially `nil`.
+
+Copied from `$/` when the [command-line option `-l`] is
+given.
+
+Setting to non-nil value by other than the command-line option is
+deprecated.
+
+English - `$OUTPUT_RECORD_SEPARATOR`, `$ORS`.
+
+## Streams
+
+### `$stdin` (Standard Input)
+
+The current standard input stream; initially:
+
+```ruby
+$stdin # => #<IO:<STDIN>>
+```
+
+### `$stdout` (Standard Output)
+
+The current standard output stream; initially:
+
+```ruby
+$stdout # => #<IO:<STDOUT>>
+```
+
+### `$stderr` (Standard Error)
+
+The current standard error stream; initially:
+
+```ruby
+$stderr # => #<IO:<STDERR>>
+```
+
+### `$<` (\ARGF or $stdin)
+
+Points to stream ARGF if not empty, else to stream $stdin; read-only.
+
+English - `$DEFAULT_INPUT`.
+
+### `$>` (Default Standard Output)
+
+An output stream, initially `$stdout`.
+
+English - `$DEFAULT_OUTPUT`
+
+### `$.` (Input Position)
+
+The input position (line number) in the most recently read stream.
+
+English - `$INPUT_LINE_NUMBER`, `$NR`
+
+### `$_` (Last Read Line)
+
+The line (string) from the most recently read stream.
+
+English - `$LAST_READ_LINE`.
+
+## Processes
+
+### `$0`
+
+Initially, contains the name of the script being executed;
+may be reassigned.
+
+### `$*` (\ARGV)
+
+Points to ARGV.
+
+English - `$ARGV`.
+
+### `$$` (Process ID)
+
+The process ID of the current process. Same as Process.pid.
+
+English - `$PROCESS_ID`, `$PID`.
+
+### `$?` (Child Status)
+
+Initially `nil`, otherwise the Process::Status object
+created for the most-recently exited child process;
+thread-local.
+
+English - `$CHILD_STATUS`.
+
+### `$LOAD_PATH` (Load Path)
+
+Contains the array of paths to be searched
+by Kernel#load and Kernel#require.
+
+Singleton method `$LOAD_PATH.resolve_feature_path(feature)`
+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:
+
+```ruby
+$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 `$:` and `$-I`.
+
+### `$LOADED_FEATURES`
+
+Contains an array of the paths to the loaded files:
+
+```ruby
+$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 `$"`.
+
+## Debugging
+
+### `$FILENAME`
+
+The value returned by method ARGF.filename.
+
+### `$DEBUG`
+
+Initially `true` if [command-line option `-d`] or
+[`--debug`][command-line option `-d`] is given, otherwise initially `false`;
+may be set to either value in the running program.
+
+When `true`, prints each raised exception to `$stderr`.
+
+Aliased as `$-d`.
+
+### `$VERBOSE`
+
+Initially `true` if [command-line option `-v`] or
+[command-line option `-w`] 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 `$-v` and `$-w`.
+
+## Other Variables
+
+### `$-F`
+
+The default field separator in String#split; must be a String or a
+Regexp, and can be set with [command-line option `-F`].
+
+Setting to non-nil value by other than the command-line option is
+deprecated.
+
+Aliased as `$;`.
+
+### `$-a`
+
+Whether [command-line option `-a`] was given; read-only.
+
+### `$-i`
+
+Contains the extension given with [command-line option `-i`],
+or `nil` if none.
+
+An alias of ARGF.inplace_mode.
+
+### `$-l`
+
+Whether [command-line option `-l`] was set; read-only.
+
+### `$-p`
+
+Whether [command-line option `-p`] was given; read-only.
+
+### `$F`
+
+If the [command-line option `-a`] is given, the array
+obtained by splitting `$_` by `$-F` is assigned at the start of each
+`-l`/`-p` loop.
+
+## Deprecated
+
+### `$=`
+
+### `$,`
+
+# Pre-Defined Global Constants
+
+## Summary
+
+### Streams
+
+| Constant | Contains |
+|:--------:|-------------------------|
+| `STDIN` | Standard input stream. |
+| `STDOUT` | Standard output stream. |
+| `STDERR` | Standard error stream. |
+
+### Environment
+
+| Constant | Contains |
+|-----------------------|-------------------------------------------------------------------------------|
+| `ENV` | Hash of current environment variable names and values. |
+| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. |
+| `ARGV` | Array of the given command-line arguments. |
+| `TOPLEVEL_BINDING` | Binding of the top level scope. |
+| `RUBY_VERSION` | String Ruby version. |
+| `RUBY_RELEASE_DATE` | String Ruby release date. |
+| `RUBY_PLATFORM` | String Ruby platform. |
+| `RUBY_PATCH_LEVEL` | String Ruby patch level. |
+| `RUBY_REVISION` | String Ruby revision. |
+| `RUBY_COPYRIGHT` | String Ruby copyright. |
+| `RUBY_ENGINE` | String Ruby engine. |
+| `RUBY_ENGINE_VERSION` | String Ruby engine version. |
+| `RUBY_DESCRIPTION` | String Ruby description. |
+
+### Embedded \Data
+
+| Constant | Contains |
+|:---------------------:|-------------------------------------------------------------------------------|
+| `DATA` | File containing embedded data (lines following `__END__`, if any). |
+
+## Streams
+
+### `STDIN`
+
+The standard input stream (the default value for `$stdin`):
+
+```ruby
+STDIN # => #<IO:<STDIN>>
+```
+
+### `STDOUT`
+
+The standard output stream (the default value for `$stdout`):
+
+```ruby
+STDOUT # => #<IO:<STDOUT>>
+```
+
+### `STDERR`
+
+The standard error stream (the default value for `$stderr`):
+
+```ruby
+STDERR # => #<IO:<STDERR>>
+```
+
+## Environment
+
+### `ENV`
+
+A hash of the contains current environment variables names and values:
+
+```ruby
+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
+`$stdin` if no files were given, `"-"` is given, or after
+all files have been read.
+
+### `ARGV`
+
+An array of the given command-line arguments.
+
+### `TOPLEVEL_BINDING`
+
+The Binding of the top level scope:
+
+```ruby
+TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
+```
+
+### `RUBY_VERSION`
+
+The Ruby version:
+
+```ruby
+RUBY_VERSION # => "3.2.2"
+```
+
+### `RUBY_RELEASE_DATE`
+
+The release date string:
+
+```ruby
+RUBY_RELEASE_DATE # => "2023-03-30"
+```
+
+### `RUBY_PLATFORM`
+
+The platform identifier:
+
+```ruby
+RUBY_PLATFORM # => "x86_64-linux"
+```
+
+### `RUBY_PATCHLEVEL`
+
+The integer patch level for this Ruby:
+
+```ruby
+RUBY_PATCHLEVEL # => 53
+```
+
+For a development build the patch level will be -1.
+
+### `RUBY_REVISION`
+
+The git commit hash for this Ruby:
+
+```ruby
+RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
+```
+
+### `RUBY_COPYRIGHT`
+
+The copyright string:
+
+```ruby
+RUBY_COPYRIGHT
+# => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
+```
+
+### `RUBY_ENGINE`
+
+The name of the Ruby implementation:
+
+```ruby
+RUBY_ENGINE # => "ruby"
+```
+
+### `RUBY_ENGINE_VERSION`
+
+The version of the Ruby implementation:
+
+```ruby
+RUBY_ENGINE_VERSION # => "3.2.2"
+```
+
+### `RUBY_DESCRIPTION`
+
+The description of the Ruby implementation:
+
+```ruby
+RUBY_DESCRIPTION
+# => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
+```
+
+## Embedded \Data
+
+### `DATA`
+
+Defined if and only if the program has this line:
+
+```ruby
+__END__
+```
+
+When defined, `DATA` is a File object
+containing the lines following the `__END__`,
+positioned at the first of those lines:
+
+```ruby
+p DATA
+DATA.each_line { |line| p line }
+__END__
+Foo
+Bar
+Baz
+```
+
+Output:
+
+```
+#<File:t.rb>
+"Foo\n"
+"Bar\n"
+"Baz\n"
+```
+
+[command-line option `-0`]: rdoc-ref:language/options.md@-0-set--input-record-separator
+[command-line option `-F`]: rdoc-ref:language/options.md@-f-set-input-field-separator
+[command-line option `-a`]: rdoc-ref:language/options.md@-a-split-input-lines-into-fields
+[command-line option `-d`]: rdoc-ref:language/options.md@-d-set-debug-to-true
+[command-line option `-i`]: rdoc-ref:language/options.md@-i-set-argf-in-place-mode
+[command-line option `-l`]: rdoc-ref:language/options.md@-l-set-output-record-separator-chop-lines
+[command-line option `-p`]: rdoc-ref:language/options.md@-p--n-with-printing
+[command-line option `-v`]: rdoc-ref:language/options.md@-v-print-version-set-verbose
+[command-line option `-w`]: rdoc-ref:language/options.md@-w-synonym-for--w1
+
+[Regexp Global Variables]: rdoc-ref:Regexp@Global+Variables
+
diff --git a/doc/hash_inclusion.rdoc b/doc/language/hash_inclusion.rdoc
index 05c2b0932a..05c2b0932a 100644
--- a/doc/hash_inclusion.rdoc
+++ b/doc/language/hash_inclusion.rdoc
diff --git a/doc/implicit_conversion.rdoc b/doc/language/implicit_conversion.rdoc
index e244096125..e244096125 100644
--- a/doc/implicit_conversion.rdoc
+++ b/doc/language/implicit_conversion.rdoc
diff --git a/doc/marshal.rdoc b/doc/language/marshal.rdoc
index 740064ade6..740064ade6 100644
--- a/doc/marshal.rdoc
+++ b/doc/language/marshal.rdoc
diff --git a/doc/language/option_dump.md b/doc/language/option_dump.md
new file mode 100644
index 0000000000..328c6b52af
--- /dev/null
+++ b/doc/language/option_dump.md
@@ -0,0 +1,265 @@
+# Option `--dump`
+
+For other argument values,
+see {Option `--dump`}[rdoc-ref:options.md@--dump+Dump+Items].
+
+For the examples here, we use this program:
+
+```console
+$ cat t.rb
+puts 'Foo'
+```
+
+The supported dump items:
+
+- `insns`: Instruction sequences:
+
+ ```sh
+ $ ruby --dump=insns t.rb
+ == disasm: #<ISeq:<main>@t.rb:1 (1,0)-(1,10)> (catch: FALSE)
+ 0000 putself ( 1)[Li]
+ 0001 dupstring "Foo"
+ 0003 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
+ 0005 leave
+ ```
+
+- `parsetree`: {Abstract syntax tree}[https://en.wikipedia.org/wiki/Abstract_syntax_tree]
+ (AST):
+
+ ```console
+ $ ruby --dump=parsetree t.rb
+ ###########################################################
+ ## Do NOT use this node dump for any purpose other than ##
+ ## debug and research. Compatibility is not guaranteed. ##
+ ###########################################################
+
+ # @ NODE_SCOPE (line: 1, location: (1,0)-(1,10))
+ # +- nd_tbl: (empty)
+ # +- nd_args:
+ # | (null node)
+ # +- nd_body:
+ # @ NODE_FCALL (line: 1, location: (1,0)-(1,10))*
+ # +- nd_mid: :puts
+ # +- nd_args:
+ # @ NODE_LIST (line: 1, location: (1,5)-(1,10))
+ # +- nd_alen: 1
+ # +- nd_head:
+ # | @ NODE_STR (line: 1, location: (1,5)-(1,10))
+ # | +- nd_lit: "Foo"
+ # +- nd_next:
+ # (null node)
+ ```
+
+- `yydebug`: Debugging information from yacc parser generator:
+
+ ```
+ $ ruby --dump=yydebug t.rb
+ Starting parse
+ Entering state 0
+ Reducing stack by rule 1 (line 1295):
+ lex_state: NONE -> BEG at line 1296
+ vtable_alloc:12392: 0x0000558453df1a00
+ vtable_alloc:12393: 0x0000558453df1a60
+ cmdarg_stack(push): 0 at line 12406
+ cond_stack(push): 0 at line 12407
+ -> $$ = nterm $@1 (1.0-1.0: )
+ Stack now 0
+ Entering state 2
+ Reading a token:
+ lex_state: BEG -> CMDARG at line 9049
+ Next token is token "local variable or method" (1.0-1.4: puts)
+ Shifting token "local variable or method" (1.0-1.4: puts)
+ Entering state 35
+ Reading a token: Next token is token "string literal" (1.5-1.6: )
+ Reducing stack by rule 742 (line 5567):
+ $1 = token "local variable or method" (1.0-1.4: puts)
+ -> $$ = nterm operation (1.0-1.4: )
+ Stack now 0 2
+ Entering state 126
+ Reducing stack by rule 78 (line 1794):
+ $1 = nterm operation (1.0-1.4: )
+ -> $$ = nterm fcall (1.0-1.4: )
+ Stack now 0 2
+ Entering state 80
+ Next token is token "string literal" (1.5-1.6: )
+ Reducing stack by rule 292 (line 2723):
+ cmdarg_stack(push): 1 at line 2737
+ -> $$ = nterm $@16 (1.4-1.4: )
+ Stack now 0 2 80
+ Entering state 235
+ Next token is token "string literal" (1.5-1.6: )
+ Shifting token "string literal" (1.5-1.6: )
+ Entering state 216
+ Reducing stack by rule 607 (line 4706):
+ -> $$ = nterm string_contents (1.6-1.6: )
+ Stack now 0 2 80 235 216
+ Entering state 437
+ Reading a token: Next token is token "literal content" (1.6-1.9: "Foo")
+ Shifting token "literal content" (1.6-1.9: "Foo")
+ Entering state 503
+ Reducing stack by rule 613 (line 4802):
+ $1 = token "literal content" (1.6-1.9: "Foo")
+ -> $$ = nterm string_content (1.6-1.9: )
+ Stack now 0 2 80 235 216 437
+ Entering state 507
+ Reducing stack by rule 608 (line 4716):
+ $1 = nterm string_contents (1.6-1.6: )
+ $2 = nterm string_content (1.6-1.9: )
+ -> $$ = nterm string_contents (1.6-1.9: )
+ Stack now 0 2 80 235 216
+ Entering state 437
+ Reading a token:
+ lex_state: CMDARG -> END at line 7276
+ Next token is token "terminator" (1.9-1.10: )
+ Shifting token "terminator" (1.9-1.10: )
+ Entering state 508
+ Reducing stack by rule 590 (line 4569):
+ $1 = token "string literal" (1.5-1.6: )
+ $2 = nterm string_contents (1.6-1.9: )
+ $3 = token "terminator" (1.9-1.10: )
+ -> $$ = nterm string1 (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 109
+ Reducing stack by rule 588 (line 4559):
+ $1 = nterm string1 (1.5-1.10: )
+ -> $$ = nterm string (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 108
+ Reading a token:
+ lex_state: END -> BEG at line 9200
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 586 (line 4541):
+ $1 = nterm string (1.5-1.10: )
+ -> $$ = nterm strings (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 107
+ Reducing stack by rule 307 (line 2837):
+ $1 = nterm strings (1.5-1.10: )
+ -> $$ = nterm primary (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 90
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 261 (line 2553):
+ $1 = nterm primary (1.5-1.10: )
+ -> $$ = nterm arg (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 220
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 270 (line 2586):
+ $1 = nterm arg (1.5-1.10: )
+ -> $$ = nterm arg_value (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 221
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 297 (line 2779):
+ $1 = nterm arg_value (1.5-1.10: )
+ -> $$ = nterm args (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 224
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 772 (line 5626):
+ -> $$ = nterm none (1.10-1.10: )
+ Stack now 0 2 80 235 224
+ Entering state 442
+ Reducing stack by rule 296 (line 2773):
+ $1 = nterm none (1.10-1.10: )
+
+ -> $$ = nterm opt_block_arg (1.10-1.10: )
+ Stack now 0 2 80 235 224
+ Entering state 441
+ Reducing stack by rule 288 (line 2696):
+ $1 = nterm args (1.5-1.10: )
+ $2 = nterm opt_block_arg (1.10-1.10: )
+ -> $$ = nterm call_args (1.5-1.10: )
+ Stack now 0 2 80 235
+ Entering state 453
+ Reducing stack by rule 293 (line 2723):
+ $1 = nterm $@16 (1.4-1.4: )
+ $2 = nterm call_args (1.5-1.10: )
+ cmdarg_stack(pop): 0 at line 2754
+ -> $$ = nterm command_args (1.4-1.10: )
+ Stack now 0 2 80
+ Entering state 333
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 79 (line 1804):
+ $1 = nterm fcall (1.0-1.4: )
+ $2 = nterm command_args (1.4-1.10: )
+ -> $$ = nterm command (1.0-1.10: )
+ Stack now 0 2
+ Entering state 81
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 73 (line 1770):
+ $1 = nterm command (1.0-1.10: )
+ -> $$ = nterm command_call (1.0-1.10: )
+ Stack now 0 2
+ Entering state 78
+ Reducing stack by rule 51 (line 1659):
+ $1 = nterm command_call (1.0-1.10: )
+ -> $$ = nterm expr (1.0-1.10: )
+ Stack now 0 2
+ Entering state 75
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 39 (line 1578):
+ $1 = nterm expr (1.0-1.10: )
+ -> $$ = nterm stmt (1.0-1.10: )
+ Stack now 0 2
+ Entering state 73
+ Next token is token '\n' (1.10-1.10: )
+ Reducing stack by rule 8 (line 1354):
+ $1 = nterm stmt (1.0-1.10: )
+ -> $$ = nterm top_stmt (1.0-1.10: )
+ Stack now 0 2
+ Entering state 72
+ Reducing stack by rule 5 (line 1334):
+ $1 = nterm top_stmt (1.0-1.10: )
+ -> $$ = nterm top_stmts (1.0-1.10: )
+ Stack now 0 2
+ Entering state 71
+ Next token is token '\n' (1.10-1.10: )
+ Shifting token '\n' (1.10-1.10: )
+ Entering state 311
+ Reducing stack by rule 769 (line 5618):
+ $1 = token '\n' (1.10-1.10: )
+ -> $$ = nterm term (1.10-1.10: )
+ Stack now 0 2 71
+ Entering state 313
+ Reducing stack by rule 770 (line 5621):
+ $1 = nterm term (1.10-1.10: )
+ -> $$ = nterm terms (1.10-1.10: )
+ Stack now 0 2 71
+ Entering state 314
+ Reading a token: Now at end of input.
+ Reducing stack by rule 759 (line 5596):
+ $1 = nterm terms (1.10-1.10: )
+ -> $$ = nterm opt_terms (1.10-1.10: )
+ Stack now 0 2 71
+ Entering state 312
+ Reducing stack by rule 3 (line 1321):
+ $1 = nterm top_stmts (1.0-1.10: )
+ $2 = nterm opt_terms (1.10-1.10: )
+ -> $$ = nterm top_compstmt (1.0-1.10: )
+ Stack now 0 2
+ Entering state 70
+ Reducing stack by rule 2 (line 1295):
+ $1 = nterm $@1 (1.0-1.0: )
+ $2 = nterm top_compstmt (1.0-1.10: )
+ vtable_free:12426: p->lvtbl->args(0x0000558453df1a00)
+ vtable_free:12427: p->lvtbl->vars(0x0000558453df1a60)
+ cmdarg_stack(pop): 0 at line 12428
+ cond_stack(pop): 0 at line 12429
+ -> $$ = nterm program (1.0-1.10: )
+ Stack now 0
+ Entering state 1
+ Now at end of input.
+ Shifting token "end-of-input" (1.10-1.10: )
+ Entering state 3
+ Stack now 0 1 3
+ Cleanup: popping token "end-of-input" (1.10-1.10: )
+ Cleanup: popping nterm program (1.0-1.10: )
+ ```
+
+Additional flags can follow dump items.
+
+- `+comment`: Add comments to AST.
+- `+error-tolerant`: Parse in error-tolerant mode.
+- `-optimize`: Disable optimizations for instruction sequences.
diff --git a/doc/language/options.md b/doc/language/options.md
new file mode 100644
index 0000000000..1329b7ca63
--- /dev/null
+++ b/doc/language/options.md
@@ -0,0 +1,744 @@
+# Ruby Command-Line Options
+
+## About the Examples
+
+Some examples here use command-line option `-e`,
+which passes the Ruby code to be executed on the command line itself:
+
+```console
+$ ruby -e 'puts "Hello, World."'
+```
+
+Some examples here assume that file `desiderata.txt` exists:
+
+```console
+$ cat desiderata.txt
+Go placidly amid the noise and the haste,
+and remember what peace there may be in silence.
+As far as possible, without surrender,
+be on good terms with all persons.
+```
+
+## Options
+
+### `-0`: Set `$/` (Input Record Separator)
+
+Option `-0` defines the input record separator `$/`
+for the invoked Ruby program.
+
+The optional argument to the option must be octal digits,
+each in the range `0..7`;
+these digits are prefixed with digit `0` to form an octal value.
+
+If no argument is given, the input record separator is `0x00`.
+
+If an argument is given, it must immediately follow the option
+(no intervening whitespace or equal-sign character `'='`);
+argument values:
+
+- `0`: the input record separator is `''`;
+ see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values].
+- In range `(1..0377)`:
+ the input record separator `$/` is set to the character value of the argument.
+- Any other octal value: the input record separator is `nil`.
+
+Examples:
+
+```console
+$ ruby -0 -e 'p $/'
+"\x00"
+ruby -00 -e 'p $/'
+""
+$ ruby -012 -e 'p $/'
+"\n"
+$ ruby -015 -e 'p $/'
+"\r"
+$ ruby -0377 -e 'p $/'
+"\xFF"
+$ ruby -0400 -e 'p $/'
+nil
+```
+
+See also:
+
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-a`: Split Input Lines into Fields
+
+Option `-a`, when given with either of options `-n` or `-p`,
+splits the string at `$_` into an array of strings at `$F`:
+
+```console
+$ ruby -an -e 'p $F' desiderata.txt
+["Go", "placidly", "amid", "the", "noise", "and", "the", "haste,"]
+["and", "remember", "what", "peace", "there", "may", "be", "in", "silence."]
+["As", "far", "as", "possible,", "without", "surrender,"]
+["be", "on", "good", "terms", "with", "all", "persons."]
+```
+
+For the splitting,
+the default record separator is `$/`,
+and the default field separator is `$;`.
+
+See also:
+
+- [Option `-0`][-0]:
+ Set `$/` (input record separator).
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-c`: Check Syntax
+
+Option `-c` specifies that the specified Ruby program
+should be checked for syntax, but not actually executed:
+
+```console
+$ ruby -e 'puts "Foo"'
+Foo
+$ ruby -c -e 'puts "Foo"'
+Syntax OK
+```
+
+### `-C`: Set Working Directory
+
+The argument to option `-C` specifies a working directory
+for the invoked Ruby program;
+does not change the working directory for the current process:
+
+```console
+$ basename `pwd`
+ruby
+$ ruby -C lib -e 'puts File.basename(Dir.pwd)'
+lib
+$ basename `pwd`
+ruby
+```
+
+This option is accumulative; relative paths are solved from the
+previous working directory.
+
+```console
+$ ruby -C / -C usr -e 'puts Dir.pwd'
+/usr
+```
+
+If the argument is not an existing directory, a fatal error will
+occur:
+
+```console
+$ ruby -C /nonexistent
+ruby: Can't chdir to /nonexistent (fatal)
+$ ruby -C /dev/null
+ruby: Can't chdir to /dev/null (fatal)
+```
+
+Whitespace between the option and its argument may be omitted.
+
+### `-d`: Set `$DEBUG` to `true`
+
+Some code in (or called by) the Ruby program may include statements or blocks
+conditioned by the global variable `$DEBUG` (e.g., `if $DEBUG`);
+these commonly write to `$stdout` or `$stderr`.
+
+The default value for `$DEBUG` is `false`;
+option `-d` sets it to `true`:
+
+```console
+$ ruby -e 'p $DEBUG'
+false
+$ ruby -d -e 'p $DEBUG'
+true
+```
+
+[Option `--debug`][--debug] is an alias for option `-d`.
+
+### `-e`: Execute Given Ruby Code
+
+Option `-e` requires an argument, which is Ruby code to be executed;
+the option may be given more than once:
+
+```console
+$ ruby -e 'puts "Foo"' -e 'puts "Bar"'
+Foo
+Bar
+```
+
+Whitespace between the option and its argument may be omitted.
+
+The command may include other options,
+but should not include arguments (which, if given, are ignored).
+
+### `-E`: Set Default Encodings
+
+Option `-E` requires an argument, which specifies either the default external encoding,
+or both the default external and internal encodings for the invoked Ruby program:
+
+```console
+# No option -E.
+$ ruby -e 'p [Encoding::default_external, Encoding::default_internal]'
+[#<Encoding:UTF-8>, nil]
+# Option -E with default external encoding.
+$ ruby -E cesu-8 -e 'p [Encoding::default_external, Encoding::default_internal]'
+[#<Encoding:CESU-8>, nil]
+# Option -E with default external and internal encodings.
+$ ruby -E utf-8:cesu-8 -e 'p [Encoding::default_external, Encoding::default_internal]'
+[#<Encoding:UTF-8>, #<Encoding:CESU-8>]
+```
+
+Whitespace between the option and its argument may be omitted.
+
+See also:
+
+- [Option `--external-encoding`][--external-encoding]:
+ Set default external encoding.
+- [Option `--internal-encoding`][--internal-encoding]:
+ Set default internal encoding.
+
+Option `--encoding` is an alias for option `-E`.
+
+### `-F`: Set Input Field Separator
+
+Option `-F`, when given with option `-a`,
+specifies that its argument is to be the input field separator to be used for splitting:
+
+```console
+$ ruby -an -Fs -e 'p $F' desiderata.txt
+["Go placidly amid the noi", "e and the ha", "te,\n"]
+["and remember what peace there may be in ", "ilence.\n"]
+["A", " far a", " po", "", "ible, without ", "urrender,\n"]
+["be on good term", " with all per", "on", ".\n"]
+```
+
+The argument may be a regular expression:
+
+```console
+$ ruby -an -F'[.,]\s*' -e 'p $F' desiderata.txt
+["Go placidly amid the noise and the haste"]
+["and remember what peace there may be in silence"]
+["As far as possible", "without surrender"]
+["be on good terms with all persons"]
+```
+
+The argument must immediately follow the option
+(no intervening whitespace or equal-sign character `'='`).
+
+See also:
+
+- [Option `-0`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-h`: Print Short Help Message
+
+Option `-h` prints a short help message
+that includes single-hyphen options (e.g. `-I`),
+and largely omits double-hyphen options (e.g., `--version`).
+
+Arguments and additional options are ignored.
+
+For a longer help message, use option `--help`.
+
+### `-i`: Set \ARGF In-Place Mode
+
+Option `-i` sets the \ARGF in-place mode for the invoked Ruby program;
+see ARGF#inplace_mode=:
+
+```console
+$ ruby -e 'p ARGF.inplace_mode'
+nil
+$ ruby -i -e 'p ARGF.inplace_mode'
+""
+$ ruby -i.bak -e 'p ARGF.inplace_mode'
+".bak"
+```
+
+### `-I`: Add to `$LOAD_PATH`
+
+The argument to option `-I` specifies a directory
+to be added to the array in global variable `$LOAD_PATH`;
+the option may be given more than once:
+
+```console
+$ pushd /tmp
+$ ruby -e 'p $LOAD_PATH.size'
+8
+$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.size'
+10
+$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.take(2)'
+["/tmp/my_lib", "/tmp/some_lib"]
+$ popd
+```
+
+This option and [option `-C`][-C] will
+be applied in the order in the command line; expansion of `-I` options
+are affected by preceeding `-C` options.
+
+```console
+$ ruby -C / -Ilib -C usr -Ilib -e 'puts $:[0, 2]'
+/lib
+/usr/lib
+```
+
+Whitespace between the option and its argument may be omitted.
+
+### `-l`: Set Output Record Separator; Chop Lines
+
+Option `-l`, when given with option `-n` or `-p`,
+modifies line-ending processing by:
+
+- Setting global variable output record separator `$\`
+ to the current value of input record separator `$/`;
+ this affects line-oriented output (such a the output from Kernel#puts).
+- Calling String#chop! on each line read.
+
+Without option `-l` (unchopped):
+
+```console
+$ ruby -n -e 'p $_' desiderata.txt
+"Go placidly amid the noise and the haste,\n"
+"and remember what peace there may be in silence.\n"
+"As far as possible, without surrender,\n"
+"be on good terms with all persons.\n"
+```
+
+With option `-l` (chopped):
+
+```console
+$ ruby -ln -e 'p $_' desiderata.txt
+"Go placidly amid the noise and the haste,"
+"and remember what peace there may be in silence."
+"As far as possible, without surrender,"
+"be on good terms with all persons."
+```
+
+See also:
+
+- [Option `-0`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-n`: Run Program in `gets` Loop
+
+Option `-n` runs your program in a `Kernel#gets` loop:
+
+```ruby
+while gets
+ # Your Ruby code.
+end
+```
+
+Note that `gets` reads the next line and sets global variable `$_`
+to the last read line:
+
+```console
+$ ruby -n -e 'puts $_' desiderata.txt
+Go placidly amid the noise and the haste,
+and remember what peace there may be in silence.
+As far as possible, without surrender,
+be on good terms with all persons.
+```
+
+See also:
+
+- [Option `-0`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-p`][-p]:
+ `-n`, with printing.
+
+### `-p`: `-n`, with Printing
+
+Option `-p` is like option `-n`, but also prints each line:
+
+```console
+$ ruby -p -e 'puts $_.size' desiderata.txt
+42
+Go placidly amid the noise and the haste,
+49
+and remember what peace there may be in silence.
+39
+As far as possible, without surrender,
+35
+be on good terms with all persons.
+```
+
+See also:
+
+- [Option `-0`][-0]:
+ Set `$/` (input record separator).
+- [Option `-a`][-a]:
+ Split input lines into fields.
+- [Option `-F`][-F]:
+ Set input field separator.
+- [Option `-l`][-l]:
+ Set output record separator; chop lines.
+- [Option `-n`][-n]:
+ Run program in `gets` loop.
+
+### `-r`: Require Library
+
+The argument to option `-r` specifies a library to be required
+before executing the Ruby program;
+the option may be given more than once:
+
+```console
+$ ruby -e 'p defined?(JSON); p defined?(CSV)'
+nil
+nil
+$ ruby -r csv -r json -e 'p defined?(JSON); p defined?(CSV)'
+"constant"
+"constant"
+```
+
+The library is loaded with the `Kernel#require` method, after the
+other options such as [`-C`][-C], [`-I`][-I], and "custom options" by
+[`-s`][-s], are applied:
+
+Whitespace between the option and its argument may be omitted.
+
+### `-s`: Define Global Variable
+
+Option `-s` specifies that a "custom option" is to define a global variable
+in the invoked Ruby program:
+
+- The custom option must appear _after_ the program name.
+- If there is no script name in the command line (using {option
+ -e}[rdoc-ref:@-e+Execute+Given+Ruby+Code] or implicit reading from
+ `$stdin`), the custom options must be separated from the other
+ interpreter options with a `--`.
+- The custom option must begin with single hyphen (e.g., `-foo`),
+ not two hyphens (e.g., `--foo`).
+- The name of the global variable is based on the option name:
+ global variable `$foo` for custom option`-foo`.
+- The value of the global variable is the string option argument if given,
+ `true` otherwise.
+
+More than one custom option may be given:
+
+```console
+$ cat t.rb
+p [$foo, $bar]
+$ ruby t.rb
+[nil, nil]
+$ ruby -s t.rb -foo=baz
+["baz", nil]
+$ ruby -s t.rb -foo
+[true, nil]
+$ ruby -s t.rb -foo=baz -bar=bat
+["baz", "bat"]
+```
+
+### `-S`: Search Directories in `ENV['PATH']`
+
+Option `-S` specifies that the Ruby interpreter
+is to search (if necessary) the directories whose paths are in the program's
+`PATH` environment variable;
+the program is executed in the shell's current working directory
+(not necessarily in the directory where the program is found).
+
+This example uses adds path `'tmp/'` to the `PATH` environment variable:
+
+```console
+$ export PATH=/tmp:$PATH
+$ echo "puts File.basename(Dir.pwd)" > /tmp/t.rb
+$ ruby -S t.rb
+ruby
+```
+
+### `-v`: Print Version; Set `$VERBOSE`
+
+Options `-v` prints the Ruby version and sets global variable `$VERBOSE`:
+
+```console
+$ ruby -e 'p $VERBOSE'
+false
+$ ruby -v -e 'p $VERBOSE'
+ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x64-mingw-ucrt]
+true
+```
+
+### `-w`: Synonym for `-W1`
+
+Option `-w` (lowercase letter) is equivalent to option `-W1` (uppercase letter).
+
+### `-W`: Set \Warning Policy
+
+Any Ruby code can create a <i>warning message</i> by calling method Kernel#warn;
+methods in the Ruby core and standard libraries can also create warning messages.
+Such a message may be printed on `$stderr`
+(or not, depending on certain settings).
+
+Option `-W` helps determine whether a particular warning message
+will be written,
+by setting the initial value of global variable `$-W`:
+
+- `-W0`: Sets `$-W` to `0` (silent; no warnings).
+- `-W1`: Sets `$-W` to `1` (moderate verbosity).
+- `-W2`: Sets `$-W` to `2` (high verbosity).
+- `-W`: Same as `-W2` (high verbosity).
+- Option not given: Same as `-W1` (moderate verbosity).
+
+The value of `$-W`, in turn, determines which warning messages (if any)
+are to be printed to `$stdout` (see Kernel#warn):
+
+```console
+$ ruby -W1 -e 'p $foo'
+nil
+$ ruby -W2 -e 'p $foo'
+-e:1: warning: global variable '$foo' not initialized
+nil
+```
+
+Ruby code may also define warnings for certain categories;
+these are the default settings for the defined categories:
+
+```rb
+Warning[:experimental] # => true
+Warning[:deprecated] # => false
+Warning[:performance] # => false
+```
+
+They may also be set:
+
+```rb
+Warning[:experimental] = false
+Warning[:deprecated] = true
+Warning[:performance] = true
+```
+
+You can suppress a category by prefixing `no-` to the category name:
+
+```console
+$ ruby -W:no-experimental -e 'p IO::Buffer.new'
+#<IO::Buffer>
+```
+
+### `-x`: Execute Ruby Code Found in Text
+
+Option `-x` executes a Ruby program whose code is embedded
+in other, non-code, text:
+
+The ruby code:
+
+- Begins after the first line beginning with `'#!` and containing string `'ruby'`.
+- Ends before any one of:
+
+ - End-of-file.
+ - A line consisting of `'__END__'`,
+ - Character `Ctrl-D` or `Ctrl-Z`.
+
+Example:
+
+```console
+$ cat t.txt
+Leading garbage.
+#!ruby
+puts File.basename(Dir.pwd)
+__END__
+Trailing garbage.
+
+$ ruby -x t.txt
+ruby
+```
+
+The optional argument specifies the directory where the text file
+is to be found;
+the Ruby code is executed in that directory:
+
+```console
+$ cp t.txt /tmp/
+$ ruby -x/tmp t.txt
+tmp
+$
+
+```
+
+If an argument is given, it must immediately follow the option
+(no intervening whitespace or equal-sign character `'='`).
+
+### `--backtrace-limit`: Set Backtrace Limit
+
+Option `--backtrace-limit` sets a limit on the number of entries
+to be displayed in a backtrace.
+
+See Thread::Backtrace.limit.
+
+### `--copyright`: Print Ruby Copyright
+
+Option `--copyright` prints a copyright message:
+
+```console
+$ ruby --copyright
+ruby - Copyright (C) 1993-2024 Yukihiro Matsumoto
+```
+
+### `--debug`: Alias for `-d`
+
+Option `--debug` is an alias for
+[option `-d`][-d].
+
+### `--disable`: Disable Features
+
+Option `--disable` specifies features to be disabled;
+the argument is a comma-separated list of the features to be disabled:
+
+```sh
+ruby --disable=gems,rubyopt t.rb
+```
+
+The supported features:
+
+- `gems`: Rubygems (default: enabled).
+- `did_you_mean`: [`did_you_mean`](https://github.com/ruby/did_you_mean) (default: enabled).
+- `rubyopt`: `RUBYOPT` environment variable (default: enabled).
+- `frozen-string-literal`: Freeze all string literals (default: disabled).
+- `jit`: JIT compiler (default: disabled).
+
+See also [option `--enable`][--enable].
+
+### `--dump`: Dump Items
+
+Option `--dump` specifies items to be dumped;
+the argument is a comma-separated list of the items.
+
+Some of the argument values cause the command to behave as if a different
+option was given:
+
+- `--dump=copyright`:
+ Same as [option `--copyright`][--copyright].
+- `--dump=help`:
+ Same as [option `--help`][--help].
+- `--dump=syntax`:
+ Same as [option `-c`][-c].
+- `--dump=usage`:
+ Same as [option `-h`][-h].
+- `--dump=version`:
+ Same as [option `--version`][--version].
+
+For other argument values and examples,
+see {Option `--dump`}[rdoc-ref:option_dump.md].
+
+### `--enable`: Enable Features
+
+Option `--enable` specifies features to be enabled;
+the argument is a comma-separated list of the features to be enabled.
+
+```sh
+ruby --enable=gems,rubyopt t.rb
+```
+
+For the features,
+see [option `--disable`][--disable].
+
+### `--encoding`: Alias for `-E`.
+
+Option `--encoding` is an alias for
+[option `-E`][-E].
+
+### `--external-encoding`: Set Default External \Encoding
+
+Option `--external-encoding`
+sets the default external encoding for the invoked Ruby program;
+for values of `encoding`,
+see [Encoding: Names and Aliases].
+
+```console
+$ ruby -e 'puts Encoding::default_external'
+UTF-8
+$ ruby --external-encoding=cesu-8 -e 'puts Encoding::default_external'
+CESU-8
+```
+
+### `--help`: Print Help Message
+
+Option `--help` prints a long help message.
+
+Arguments and additional options are ignored.
+
+For a shorter help message, use option `-h`.
+
+### `--internal-encoding`: Set Default Internal \Encoding
+
+Option `--internal-encoding`
+sets the default internal encoding for the invoked Ruby program;
+for values of `encoding`,
+see [Encoding: Names and Aliases].
+
+```console
+$ ruby -e 'puts Encoding::default_internal.nil?'
+true
+$ ruby --internal-encoding=cesu-8 -e 'puts Encoding::default_internal'
+CESU-8
+```
+
+### `--jit`
+
+Option `--jit` is an alias for option `--yjit`, which enables YJIT;
+see additional YJIT options in the [YJIT documentation](rdoc-ref:jit/yjit.md).
+
+### `--verbose`: Set `$VERBOSE`
+
+Option `--verbose` sets global variable `$VERBOSE` to `true`
+and disables input from `$stdin`.
+
+### `--version`: Print Ruby Version
+
+Option `--version` prints the version of the Ruby interpreter, then exits.
+
+[-0]: rdoc-ref:@-0+Set++Input+Record+Separator
+[-C]: rdoc-ref:@-C+Set+Working+Directory
+[-E]: rdoc-ref:@-E+Set+Default+Encodings
+[-F]: rdoc-ref:@-F+Set+Input+Field+Separator
+[-I]: rdoc-ref:@-I+Add+to+LOADPATH
+[-a]: rdoc-ref:@-a+Split+Input+Lines+into+Fields
+[-c]: rdoc-ref:@-c+Check+Syntax
+[-d]: rdoc-ref:@-d+Set+DEBUG+to+true
+[-e]: rdoc-ref:@-e+Execute+Given+Ruby+Code
+[-h]: rdoc-ref:@-h+Print+Short+Help+Message
+[-l]: rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines
+[-n]: rdoc-ref:@-n+Run+Program+in+gets+Loop
+[-p]: rdoc-ref:@-p+-n+with+Printing
+[-s]: rdoc-ref:@-s+Define+Global+Variable
+[--copyright]: rdoc-ref:@--copyright+Print+Ruby+Copyright
+[--debug]: rdoc-ref:@--debug+Alias+for+-d
+[--disable]: rdoc-ref:@--disable+Disable+Features
+[--enable]: rdoc-ref:@--enable+Enable+Features
+[--external-encoding]: rdoc-ref:@--external+encoding+Set+Default+External+Encoding
+[--internal-encoding]: rdoc-ref:@--internal+encoding+Set+Default+Internal+Encoding
+[--help]: rdoc-ref:@--help+Print+Help+Message
+[--version]: rdoc-ref:@--version+Print+Ruby+Version
+[Encoding: Names and Aliases]: rdoc-ref:encodings.rdoc@Names+and+Aliases
diff --git a/doc/language/packed_data.md b/doc/language/packed_data.md
new file mode 100644
index 0000000000..1b133367d6
--- /dev/null
+++ b/doc/language/packed_data.md
@@ -0,0 +1,886 @@
+# Packed \Data
+
+## Quick Reference
+
+These tables summarize the directives for packing and unpacking.
+
+### For Integers
+
+| Directive | Meaning |
+|-----------------------|-----------------------------------------------------------------------------------------------------|
+| `C` | 8-bit unsigned (`unsigned char`) |
+| `S` | 16-bit unsigned, native endian (`uint16_t`) |
+| `L` | 32-bit unsigned, native endian (`uint32_t`) |
+| `Q` | 64-bit unsigned, native endian (`uint64_t`) |
+| `J` | pointer width unsigned, native endian (`uintptr_t`) |
+| | |
+| `c` | 8-bit signed (`signed char`) |
+| `s` | 16-bit signed, native endian (`int16_t`) |
+| `l` | 32-bit signed, native endian (`int32_t`) |
+| `q` | 64-bit signed, native endian (`int64_t`) |
+| `j` | pointer width signed, native endian (`intptr_t`) |
+| | |
+| `S_` `S!` | `unsigned short`, native endian |
+| `I` `I_` `I!` | `unsigned int`, native endian |
+| `L_` `L!` | `unsigned long`, native endian |
+| `Q_` `Q!` | `unsigned long long`, native endian; (raises ArgumentError if the platform has no `long long` type) |
+| `J!` | `uintptr_t`, native endian (same with `J`) |
+| | |
+| `s_` `s!` | `signed short`, native endian |
+| `i` `i_` `i!` | `signed int`, native endian |
+| `l_` `l!` | `signed long`, native endian |
+| `q_` `q!` | `signed long long`, native endian; (raises ArgumentError if the platform has no `long long` type) |
+| `j!` | `intptr_t`, native endian (same with `j`) |
+| | |
+| `S>` `s>` `S!>` `s!>` | each the same as the directive without `>`, but big endian; `S>` is the same as `n` |
+| `L>` `l>` `L!>` `l!>` | `L>` is the same as `N` |
+| `I!>` `i!>` | |
+| `Q>` `q>` `Q!>` `q!>` | |
+| `J>` `j>` `J!>` `j!>` | |
+| | |
+| `S<` `s<` `S!<` `s!<` | each the same as the directive without `<`, but little endian; `S<` is the same as `v` |
+| `L<` `l<` `L!<` `l!<` | `L<` is the same as `V` |
+| `I!<` `i!<` | |
+| `Q<` `q<` `Q!<` `q!<` | |
+| `J<` `j<` `J!<` `j!<` | |
+| | |
+| `n` | 16-bit unsigned, network (big-endian) byte order |
+| `N` | 32-bit unsigned, network (big-endian) byte order |
+| `v` | 16-bit unsigned, VAX (little-endian) byte order |
+| `V` | 32-bit unsigned, VAX (little-endian) byte order |
+| | |
+| `U` | UTF-8 character |
+| `w` | BER-compressed integer |
+| `R` | LEB128 encoded unsigned integer |
+| `r` | LEB128 encoded signed integer |
+
+### For Floats
+
+| Directive | Meaning |
+|-----------|---------------------------------------------------|
+| `D` `d` | double-precision, native format |
+| `F` `f` | single-precision, native format |
+| `E` | double-precision, little-endian byte order |
+| `e` | single-precision, little-endian byte order |
+| `G` | double-precision, network (big-endian) byte order |
+| `g` | single-precision, network (big-endian) byte order |
+
+### For Strings
+
+| Directive | Meaning |
+|-----------|------------------------------------------------------------------------------------------------|
+| `A` | arbitrary binary string (remove trailing nulls and ASCII spaces) |
+| `a` | arbitrary binary string |
+| `Z` | null-terminated string |
+| `B` | bit string (MSB first) |
+| `b` | bit string (LSB first) |
+| `H` | hex string (high nibble first) |
+| `h` | hex string (low nibble first) |
+| `u` | UU-encoded string |
+| `M` | quoted-printable, MIME encoding (see RFC2045) |
+| `m` | base64 encoded string (RFC 2045) (default) (base64 encoded string (RFC 4648) if followed by 0) |
+| `P` | pointer to a structure (fixed-length string) |
+| `p` | pointer to a null-terminated string |
+
+### Additional Directives for Packing
+
+| Directive | Meaning |
+|-----------|----------------------------|
+| `@` | moves to absolute position |
+| `X` | back up a byte |
+| `x` | null byte |
+
+### Additional Directives for Unpacking
+
+| Directive | Meaning |
+|-----------|-------------------------------------------------|
+| `@` | skip to the offset given by the length argument |
+| `X` | skip backward one byte |
+| `x` | skip forward one byte |
+| `^` | return the current offset |
+
+## Packing and Unpacking
+
+Certain Ruby core methods deal with packing and unpacking data:
+
+- Method Array#pack:
+ Formats each element in array `self` into a binary string;
+ returns that string.
+- Method String#unpack:
+ Extracts data from string `self`,
+ forming objects that become the elements of a new array;
+ returns that array.
+- Method String#unpack1:
+ Does the same, but unpacks and returns only the first extracted object.
+
+Each of these methods accepts a string `template`,
+consisting of zero or more _directive_ characters,
+each followed by zero or more _modifier_ characters.
+
+Examples (directive `'C'` specifies '`unsigned character`'):
+
+```ruby
+[65].pack('C') # => "A" # One element, one directive.
+[65, 66].pack('CC') # => "AB" # Two elements, two directives.
+[65, 66].pack('C') # => "A" # Extra element is ignored.
+[65].pack('') # => "" # No directives.
+[65].pack('CC') # Extra directive raises ArgumentError.
+```
+
+```ruby
+'A'.unpack('C') # => [65] # One character, one directive.
+'AB'.unpack('CC') # => [65, 66] # Two characters, two directives.
+'AB'.unpack('C') # => [65] # Extra character is ignored.
+'A'.unpack('CC') # => [65, nil] # Extra directive generates nil.
+'AB'.unpack('') # => [] # No directives.
+```
+
+The string `template` may contain any mixture of valid directives
+(directive `'c'` specifies 'signed character'):
+
+```ruby
+[65, -1].pack('cC') # => "A\xFF"
+"A\xFF".unpack('cC') # => [65, 255]
+```
+
+The string `template` may contain whitespace (which is ignored)
+and comments, each of which begins with character `'#'`
+and continues up to and including the next following newline:
+
+```ruby
+[0,1].pack(" C #foo \n C ") # => "\x00\x01"
+"\0\1".unpack(" C #foo \n C ") # => [0, 1]
+```
+
+Any directive may be followed by either of these modifiers:
+
+- `'*'` - The directive is to be applied as many times as needed:
+
+ ```ruby
+ [65, 66].pack('C*') # => "AB"
+ 'AB'.unpack('C*') # => [65, 66]
+ ```
+
+- \Integer `count` - The directive is to be applied `count` times:
+
+ ```ruby
+ [65, 66].pack('C2') # => "AB"
+ [65, 66].pack('C3') # Raises ArgumentError.
+ 'AB'.unpack('C2') # => [65, 66]
+ 'AB'.unpack('C3') # => [65, 66, nil]
+ ```
+
+ Note: Directives in `%w[A a Z m]` use `count` differently;
+ see [\String Directives][rdoc-ref:@String+Directives].
+
+If elements don't fit the provided directive, only least significant bits are encoded:
+
+```ruby
+[257].pack("C").unpack("C") # => [1]
+```
+
+## Packing Method
+
+Method Array#pack accepts optional keyword argument
+`buffer` that specifies the target string (instead of a new string):
+
+```ruby
+[65, 66].pack('C*', buffer: 'foo') # => "fooAB"
+```
+
+The method can accept a block:
+
+```ruby
+# Packed string is passed to the block.
+[65, 66].pack('C*') {|s| p s } # => "AB"
+```
+
+## Unpacking Methods
+
+Methods String#unpack and String#unpack1 each accept
+an optional keyword argument `offset` that specifies an offset
+into the string:
+
+```ruby
+'ABC'.unpack('C*', offset: 1) # => [66, 67]
+'ABC'.unpack1('C*', offset: 1) # => 66
+```
+
+Both methods can accept a block:
+
+```ruby
+# Each unpacked object is passed to the block.
+ret = []
+"ABCD".unpack("C*") {|c| ret << c }
+ret # => [65, 66, 67, 68]
+```
+
+```ruby
+# The single unpacked object is passed to the block.
+'AB'.unpack1('C*') {|ele| p ele } # => 65
+```
+
+## \Integer Directives
+
+Each integer directive specifies the packing or unpacking
+for one element in the input or output array.
+
+### 8-Bit \Integer Directives
+
+- `'c'` - 8-bit signed integer
+ (like C `signed char`):
+
+ ```ruby
+ [0, 1, 255].pack('c*') # => "\x00\x01\xFF"
+ s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
+ s.unpack('c*') # => [0, 1, -1]
+ ```
+
+- `'C'` - 8-bit unsigned integer
+ (like C `unsigned char`):
+
+ ```ruby
+ [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
+
+- `'s'` - 16-bit signed integer, native-endian
+ (like C `int16_t`):
+
+ ```ruby
+ [513, -514].pack('s*') # => "\x01\x02\xFE\xFD"
+ s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD"
+ s.unpack('s*') # => [513, -514]
+ ```
+
+- `'S'` - 16-bit unsigned integer, native-endian
+ (like C `uint16_t`):
+
+ ```ruby
+ [513, -514].pack('S*') # => "\x01\x02\xFE\xFD"
+ s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD"
+ s.unpack('S*') # => [513, 65022]
+ ```
+
+- `'n'` - 16-bit network integer, big-endian:
+
+ ```ruby
+ s = [0, 1, -1, 32767, -32768, 65535].pack('n*')
+ # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF"
+ s.unpack('n*')
+ # => [0, 1, 65535, 32767, 32768, 65535]
+ ```
+
+- `'v'` - 16-bit VAX integer, little-endian:
+
+ ```ruby
+ s = [0, 1, -1, 32767, -32768, 65535].pack('v*')
+ # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF"
+ s.unpack('v*')
+ # => [0, 1, 65535, 32767, 32768, 65535]
+ ```
+
+### 32-Bit \Integer Directives
+
+- `'l'` - 32-bit signed integer, native-endian
+ (like C `int32_t`):
+
+ ```ruby
+ s = [67305985, -50462977].pack('l*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('l*')
+ # => [67305985, -50462977]
+ ```
+
+- `'L'` - 32-bit unsigned integer, native-endian
+ (like C `uint32_t`):
+
+ ```ruby
+ s = [67305985, 4244504319].pack('L*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('L*')
+ # => [67305985, 4244504319]
+ ```
+
+- `'N'` - 32-bit network integer, big-endian:
+
+ ```ruby
+ s = [0,1,-1].pack('N*')
+ # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF"
+ s.unpack('N*')
+ # => [0, 1, 4294967295]
+ ```
+
+- `'V'` - 32-bit VAX integer, little-endian:
+
+ ```ruby
+ s = [0,1,-1].pack('V*')
+ # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
+ s.unpack('v*')
+ # => [0, 0, 1, 0, 65535, 65535]
+ ```
+
+### 64-Bit \Integer Directives
+
+- `'q'` - 64-bit signed integer, native-endian
+ (like C `int64_t`):
+
+ ```ruby
+ s = [578437695752307201, -506097522914230529].pack('q*')
+ # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
+ s.unpack('q*')
+ # => [578437695752307201, -506097522914230529]
+ ```
+
+- `'Q'` - 64-bit unsigned integer, native-endian
+ (like C `uint64_t`):
+
+ ```ruby
+ s = [578437695752307201, 17940646550795321087].pack('Q*')
+ # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
+ s.unpack('Q*')
+ # => [578437695752307201, 17940646550795321087]
+ ```
+
+### Platform-Dependent \Integer Directives
+
+- `'i'` - Platform-dependent width signed integer,
+ native-endian (like C `int`):
+
+ ```ruby
+ s = [67305985, -50462977].pack('i*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('i*')
+ # => [67305985, -50462977]
+ ```
+
+- `'I'` - Platform-dependent width unsigned integer,
+ native-endian (like C `unsigned int`):
+
+ ```ruby
+ s = [67305985, -50462977].pack('I*')
+ # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
+ s.unpack('I*')
+ # => [67305985, 4244504319]
+ ```
+
+- `'j'` - Pointer-width signed integer, native-endian
+ (like C `intptr_t`):
+
+ ```ruby
+ 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]
+ ```
+
+- `'J'` - Pointer-width unsigned integer, native-endian
+ (like C `uintptr_t`):
+
+ ```ruby
+ 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
+
+- `'U'` - UTF-8 character:
+
+ ```ruby
+ s = [4194304].pack('U*')
+ # => "\xF8\x90\x80\x80\x80"
+ s.unpack('U*')
+ # => [4194304]
+ ```
+
+- `'r'` - Signed LEB128-encoded integer
+ (see [Signed LEB128](https://en.wikipedia.org/wiki/LEB128#Signed_LEB128))
+
+ ```ruby
+ s = [1, 127, -128, 16383, -16384].pack("r*")
+ # => "\x01\xFF\x00\x80\x7F\xFF\xFF\x00\x80\x80\x7F"
+ s.unpack('r*')
+ # => [1, 127, -128, 16383, -16384]
+ ```
+
+- `'R'` - Unsigned LEB128-encoded integer
+ (see [Unsigned LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128))
+
+ ```ruby
+ s = [1, 127, 128, 16383, 16384].pack("R*")
+ # => "\x01\x7F\x80\x01\xFF\x7F\x80\x80\x01"
+ s.unpack('R*')
+ # => [1, 127, 128, 16383, 16384]
+ ```
+
+- `'w'` - BER-encoded integer
+ (see [BER encoding](https://en.wikipedia.org/wiki/X.690#BER_encoding)):
+
+ ```ruby
+ s = [1073741823].pack('w*')
+ # => "\x83\xFF\xFF\xFF\x7F"
+ s.unpack('w*')
+ # => [1073741823]
+ ```
+
+### Modifiers for \Integer Directives
+
+For the following directives, `'!'` or `'_'` modifiers may be
+suffixed as underlying platform’s native size.
+
+- `'i'`, `'I'` - C `int`, always native size.
+- `'s'`, `'S'` - C `short`.
+- `'l'`, `'L'` - C `long`.
+- `'q'`, `'Q'` - C `long long`, if available.
+- `'j'`, `'J'` - C `intptr_t`, 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:
+
+- `'>'` - Big-endian.
+- `'<'` - Little-endian.
+
+## \Float Directives
+
+Each float directive specifies the packing or unpacking
+for one element in the input or output array.
+
+### Single-Precision \Float Directives
+
+- `'F'` or `'f'` - Native format:
+
+ ```ruby
+ s = [3.0].pack('F') # => "\x00\x00@@"
+ s.unpack('F') # => [3.0]
+ ```
+
+- `'e'` - Little-endian:
+
+ ```ruby
+ s = [3.0].pack('e') # => "\x00\x00@@"
+ s.unpack('e') # => [3.0]
+ ```
+
+- `'g'` - Big-endian:
+
+ ```ruby
+ s = [3.0].pack('g') # => "@@\x00\x00"
+ s.unpack('g') # => [3.0]
+ ```
+
+### Double-Precision \Float Directives
+
+- `'D'` or `'d'` - Native format:
+
+ ```ruby
+ s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@"
+ s.unpack('D') # => [3.0]
+ ```
+
+- `'E'` - Little-endian:
+
+ ```ruby
+ s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@"
+ s.unpack('E') # => [3.0]
+ ```
+
+- `'G'` - Big-endian:
+
+ ```ruby
+ s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00"
+ s.unpack('G') # => [3.0]
+ ```
+
+A float directive may be infinity or not-a-number:
+
+```ruby
+inf = 1.0/0.0 # => Infinity
+[inf].pack('f') # => "\x00\x00\x80\x7F"
+"\x00\x00\x80\x7F".unpack('f') # => [Infinity]
+
+nan = inf/inf # => NaN
+[nan].pack('f') # => "\x00\x00\xC0\x7F"
+"\x00\x00\xC0\x7F".unpack('f') # => [NaN]
+```
+
+## \String Directives
+
+Each string directive specifies the packing or unpacking
+for one byte in the input or output string.
+
+### Binary \String Directives
+
+- `'A'` - Arbitrary binary string (space padded; count is width);
+ `nil` is treated as the empty string:
+
+ ```ruby
+ ['foo'].pack('A') # => "f"
+ ['foo'].pack('A*') # => "foo"
+ ['foo'].pack('A2') # => "fo"
+ ['foo'].pack('A4') # => "foo "
+ [nil].pack('A') # => " "
+ [nil].pack('A*') # => ""
+ [nil].pack('A2') # => " "
+ [nil].pack('A4') # => " "
+ ```
+
+ ```ruby
+ "foo\0".unpack('A') # => ["f"]
+ "foo\0".unpack('A4') # => ["foo"]
+ "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0".
+ "foo ".unpack('A') # => ["f"]
+ "foo ".unpack('A4') # => ["foo"]
+ "foo".unpack('A4') # => ["foo"]
+ ```
+
+ ```ruby
+ japanese = 'こんにちは'
+ japanese.size # => 5
+ japanese.bytesize # => 15
+ [japanese].pack('A') # => "\xE3"
+ [japanese].pack('A*') # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ japanese.unpack('A') # => ["\xE3"]
+ japanese.unpack('A2') # => ["\xE3\x81"]
+ japanese.unpack('A4') # => ["\xE3\x81\x93\xE3"]
+ japanese.unpack('A*') # => ["\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"]
+ ```
+
+- `'a'` - Arbitrary binary string (null padded; count is width):
+
+ ```ruby
+ ["foo"].pack('a') # => "f"
+ ["foo"].pack('a*') # => "foo"
+ ["foo"].pack('a2') # => "fo"
+ ["foo\0"].pack('a4') # => "foo\x00"
+ [nil].pack('a') # => "\x00"
+ [nil].pack('a*') # => ""
+ [nil].pack('a2') # => "\x00\x00"
+ [nil].pack('a4') # => "\x00\x00\x00\x00"
+ ```
+
+ ```ruby
+ "foo\0".unpack('a') # => ["f"]
+ "foo\0".unpack('a4') # => ["foo\x00"]
+ "foo ".unpack('a4') # => ["foo "]
+ "foo".unpack('a4') # => ["foo"]
+ "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0".
+ ```
+
+- `'Z'` - Same as `'a'`,
+ except that null is added or ignored with `'*'`:
+
+ ```ruby
+ ["foo"].pack('Z*') # => "foo\x00"
+ [nil].pack('Z*') # => "\x00"
+ ```
+
+ ```ruby
+ "foo\0".unpack('Z*') # => ["foo"]
+ "foo".unpack('Z*') # => ["foo"]
+ "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
+ ```
+
+### Bit \String Directives
+
+- `'B'` - Bit string (high byte first):
+
+ ```ruby
+ ['11111111' + '00000000'].pack('B*') # => "\xFF\x00"
+ ['10000000' + '01000000'].pack('B*') # => "\x80@"
+ ```
+
+ ```ruby
+ ['1'].pack('B0') # => ""
+ ['1'].pack('B1') # => "\x80"
+ ['1'].pack('B2') # => "\x80\x00"
+ ['1'].pack('B3') # => "\x80\x00"
+ ['1'].pack('B4') # => "\x80\x00\x00"
+ ['1'].pack('B5') # => "\x80\x00\x00"
+ ['1'].pack('B6') # => "\x80\x00\x00\x00"
+ ```
+
+ ```ruby
+ "\xff\x00".unpack("B*") # => ["1111111100000000"]
+ "\x01\x02".unpack("B*") # => ["0000000100000010"]
+ ```
+
+ ```ruby
+ "".unpack("B0") # => [""]
+ "\x80".unpack("B1") # => ["1"]
+ "\x80".unpack("B2") # => ["10"]
+ "\x80".unpack("B3") # => ["100"]
+ ```
+
+- `'b'` - Bit string (low byte first):
+
+ ```ruby
+ ['11111111' + '00000000'].pack('b*') # => "\xFF\x00"
+ ['10000000' + '01000000'].pack('b*') # => "\x01\x02"
+ ```
+
+ ```ruby
+ ['1'].pack('b0') # => ""
+ ['1'].pack('b1') # => "\x01"
+ ['1'].pack('b2') # => "\x01\x00"
+ ['1'].pack('b3') # => "\x01\x00"
+ ['1'].pack('b4') # => "\x01\x00\x00"
+ ['1'].pack('b5') # => "\x01\x00\x00"
+ ['1'].pack('b6') # => "\x01\x00\x00\x00"
+ ```
+
+ ```ruby
+ "\xff\x00".unpack("b*") # => ["1111111100000000"]
+ "\x01\x02".unpack("b*") # => ["1000000001000000"]
+ ```
+
+ ```ruby
+ "".unpack("b0") # => [""]
+ "\x01".unpack("b1") # => ["1"]
+ "\x01".unpack("b2") # => ["10"]
+ "\x01".unpack("b3") # => ["100"]
+ ```
+
+### Hex \String Directives
+
+- `'H'` - Hex string (high nibble first):
+
+ ```ruby
+ ['10ef'].pack('H*') # => "\x10\xEF"
+ ['10ef'].pack('H0') # => ""
+ ['10ef'].pack('H3') # => "\x10\xE0"
+ ['10ef'].pack('H5') # => "\x10\xEF\x00"
+ ```
+
+ ```ruby
+ ['fff'].pack('H3') # => "\xFF\xF0"
+ ['fff'].pack('H4') # => "\xFF\xF0"
+ ['fff'].pack('H5') # => "\xFF\xF0\x00"
+ ['fff'].pack('H6') # => "\xFF\xF0\x00"
+ ['fff'].pack('H7') # => "\xFF\xF0\x00\x00"
+ ['fff'].pack('H8') # => "\xFF\xF0\x00\x00"
+ ```
+
+ ```ruby
+ "\x10\xef".unpack('H*') # => ["10ef"]
+ "\x10\xef".unpack('H0') # => [""]
+ "\x10\xef".unpack('H1') # => ["1"]
+ "\x10\xef".unpack('H2') # => ["10"]
+ "\x10\xef".unpack('H3') # => ["10e"]
+ "\x10\xef".unpack('H4') # => ["10ef"]
+ "\x10\xef".unpack('H5') # => ["10ef"]
+ ```
+
+- `'h'` - Hex string (low nibble first):
+
+ ```ruby
+ ['10ef'].pack('h*') # => "\x01\xFE"
+ ['10ef'].pack('h0') # => ""
+ ['10ef'].pack('h3') # => "\x01\x0E"
+ ['10ef'].pack('h5') # => "\x01\xFE\x00"
+ ```
+
+ ```ruby
+ ['fff'].pack('h3') # => "\xFF\x0F"
+ ['fff'].pack('h4') # => "\xFF\x0F"
+ ['fff'].pack('h5') # => "\xFF\x0F\x00"
+ ['fff'].pack('h6') # => "\xFF\x0F\x00"
+ ['fff'].pack('h7') # => "\xFF\x0F\x00\x00"
+ ['fff'].pack('h8') # => "\xFF\x0F\x00\x00"
+ ```
+
+ ```ruby
+ "\x01\xfe".unpack('h*') # => ["10ef"]
+ "\x01\xfe".unpack('h0') # => [""]
+ "\x01\xfe".unpack('h1') # => ["1"]
+ "\x01\xfe".unpack('h2') # => ["10"]
+ "\x01\xfe".unpack('h3') # => ["10e"]
+ "\x01\xfe".unpack('h4') # => ["10ef"]
+ "\x01\xfe".unpack('h5') # => ["10ef"]
+ ```
+
+### Pointer \String Directives
+
+- `'P'` - Pointer to a structure (fixed-length string):
+
+ ```ruby
+ s = ['abc'].pack('P') # => "\xE0O\x7F\xE5\xA1\x01\x00\x00"
+ s.unpack('P*') # => ["abc"]
+ ".".unpack("P") # => []
+ ("\0" * 8).unpack("P") # => [nil]
+ [nil].pack("P") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
+ ```
+
+- `'p'` - Pointer to a null-terminated string:
+
+ ```ruby
+ s = ['abc'].pack('p') # => "(\xE4u\xE5\xA1\x01\x00\x00"
+ s.unpack('p*') # => ["abc"]
+ ".".unpack("p") # => []
+ ("\0" * 8).unpack("p") # => [nil]
+ [nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
+ ```
+
+### Other \String Directives
+
+- `'M'` - Quoted printable, MIME encoding;
+ text mode, but input must use LF and output LF;
+ (see [RFC 2045](https://www.ietf.org/rfc/rfc2045.txt)):
+
+ ```ruby
+ ["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n"
+ ["\0"].pack('M') # => "=00=\n"
+ ```
+
+ ```ruby
+ ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n" # => true
+ ("a"*73+"=\na=\n").unpack('M') == ["a"*74] # => true
+ (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true
+ ```
+
+ ```ruby
+ "a b c\td =\n\ne=\n".unpack('M') # => ["a b c\td \ne"]
+ "=00=\n".unpack('M') # => ["\x00"]
+ ```
+
+ ```ruby
+ "pre=31=32=33after".unpack('M') # => ["pre123after"]
+ "pre=\nafter".unpack('M') # => ["preafter"]
+ "pre=\r\nafter".unpack('M') # => ["preafter"]
+ "pre=".unpack('M') # => ["pre="]
+ "pre=\r".unpack('M') # => ["pre=\r"]
+ "pre=hoge".unpack('M') # => ["pre=hoge"]
+ "pre==31after".unpack('M') # => ["pre==31after"]
+ "pre===31after".unpack('M') # => ["pre===31after"]
+ ```
+
+- `'m'` - Base64 encoded string;
+ count specifies input bytes between each newline,
+ rounded down to nearest multiple of 3;
+ if count is zero, no newlines are added;
+ (see [RFC 4648](https://www.ietf.org/rfc/rfc4648.txt)):
+
+ ```ruby
+ [""].pack('m') # => ""
+ ["\0"].pack('m') # => "AA==\n"
+ ["\0\0"].pack('m') # => "AAA=\n"
+ ["\0\0\0"].pack('m') # => "AAAA\n"
+ ["\377"].pack('m') # => "/w==\n"
+ ["\377\377"].pack('m') # => "//8=\n"
+ ["\377\377\377"].pack('m') # => "////\n"
+ ```
+
+ ```ruby
+ "".unpack('m') # => [""]
+ "AA==\n".unpack('m') # => ["\x00"]
+ "AAA=\n".unpack('m') # => ["\x00\x00"]
+ "AAAA\n".unpack('m') # => ["\x00\x00\x00"]
+ "/w==\n".unpack('m') # => ["\xFF"]
+ "//8=\n".unpack('m') # => ["\xFF\xFF"]
+ "////\n".unpack('m') # => ["\xFF\xFF\xFF"]
+ "A\n".unpack('m') # => [""]
+ "AA\n".unpack('m') # => ["\x00"]
+ "AA=\n".unpack('m') # => ["\x00"]
+ "AAA\n".unpack('m') # => ["\x00\x00"]
+ ```
+
+ ```ruby
+ [""].pack('m0') # => ""
+ ["\0"].pack('m0') # => "AA=="
+ ["\0\0"].pack('m0') # => "AAA="
+ ["\0\0\0"].pack('m0') # => "AAAA"
+ ["\377"].pack('m0') # => "/w=="
+ ["\377\377"].pack('m0') # => "//8="
+ ["\377\377\377"].pack('m0') # => "////"
+ ```
+
+ ```ruby
+ "".unpack('m0') # => [""]
+ "AA==".unpack('m0') # => ["\x00"]
+ "AAA=".unpack('m0') # => ["\x00\x00"]
+ "AAAA".unpack('m0') # => ["\x00\x00\x00"]
+ "/w==".unpack('m0') # => ["\xFF"]
+ "//8=".unpack('m0') # => ["\xFF\xFF"]
+ "////".unpack('m0') # => ["\xFF\xFF\xFF"]
+ ```
+
+- `'u'` - UU-encoded string:
+
+ ```ruby
+ [""].pack("u") # => ""
+ ["a"].pack("u") # => "!80``\n"
+ ["aaa"].pack("u") # => "#86%A\n"
+ ```
+
+ ```ruby
+ "".unpack("u") # => [""]
+ "#86)C\n".unpack("u") # => ["abc"]
+ ```
+
+## Offset Directives
+
+- `'@'` - Begin packing at the given byte offset;
+ for packing, null fill or shrink if necessary:
+
+ ```ruby
+ [1, 2].pack("C@0C") # => "\x02"
+ [1, 2].pack("C@1C") # => "\x01\x02"
+ [1, 2].pack("C@5C") # => "\x01\x00\x00\x00\x00\x02"
+ [*1..5].pack("CCCC@2C") # => "\x01\x02\x05"
+ ```
+
+ For unpacking, cannot to move to outside the string:
+
+ ```ruby
+ "\x01\x00\x00\x02".unpack("C@3C") # => [1, 2]
+ "\x00".unpack("@1C") # => [nil]
+ "\x00".unpack("@2C") # Raises ArgumentError.
+ ```
+
+- `'X'` - For packing, shrink for the given byte offset:
+
+ ```ruby
+ [0, 1, 2].pack("CCXC") # => "\x00\x02"
+ [0, 1, 2].pack("CCX2C") # => "\x02"
+ ```
+
+ For unpacking; rewind unpacking position for the given byte offset:
+
+ ```ruby
+ "\x00\x02".unpack("CCXC") # => [0, 2, 2]
+ ```
+
+ Cannot to move to outside the string:
+
+ ```ruby
+ [0, 1, 2].pack("CCX3C") # Raises ArgumentError.
+ "\x00\x02".unpack("CX3C") # Raises ArgumentError.
+ ```
+
+- `'x'` - Begin packing at after the given byte offset;
+ for packing, null fill if necessary:
+
+ ```ruby
+ [].pack("x0") # => ""
+ [].pack("x") # => "\x00"
+ [].pack("x8") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
+ ```
+
+ For unpacking, cannot to move to outside the string:
+
+ ```ruby
+ "\x00\x00\x02".unpack("CxC") # => [0, 2]
+ "\x00\x00\x02".unpack("x3C") # => [nil]
+ "\x00\x00\x02".unpack("x4C") # Raises ArgumentError
+ ```
+
+- `'^'` - Only for unpacking; the current position:
+
+ ```ruby
+ "foo\0\0\0".unpack("Z*^") # => ["foo", 4]
+ ```
diff --git a/doc/language/ractor.md b/doc/language/ractor.md
new file mode 100644
index 0000000000..1592656217
--- /dev/null
+++ b/doc/language/ractor.md
@@ -0,0 +1,797 @@
+# Ractor - Ruby's Actor-like concurrency abstraction
+
+Ractors are designed to provide parallel execution of Ruby code without thread-safety concerns.
+
+## Summary
+
+### Multiple Ractors in a ruby process
+
+You can create multiple Ractors which can run ruby code in parallel with each other.
+
+* `Ractor.new{ expr }` creates a new Ractor and `expr` can run in parallel with other ractors on a multi-core computer.
+* Ruby processes start with one ractor (called the *main ractor*).
+* If the main ractor terminates, all other ractors receive termination requests, similar to how threads behave.
+* Each Ractor contains one or more `Thread`s.
+ * Threads within the same ractor share a ractor-wide global lock (GVL in MRI terminology), so they can't run in parallel with each other (without releasing the GVL explicitly in C extensions). Threads in different ractors can run in parallel.
+ * The overhead of creating a ractor is slightly above the overhead of creating a thread.
+
+### Limited sharing between Ractors
+
+Ractors don't share all objects, unlike threads which can access any object other than objects stored in another thread's thread-locals.
+
+* Most objects are *unshareable objects*. Unshareable objects can only be used by the ractor that instantiated them, so you don't need to worry about thread-safety issues resulting from using the object concurrently across ractors.
+* Some objects are *shareable objects*. Here is an incomplete list to give you an idea:
+ * `i = 123`: All `Integer`s are shareable.
+ * `s = "str".freeze`: Frozen strings are shareable if they have no instance variables that refer to unshareable objects.
+ * `a = [1, [2], 3].freeze`: `a` is not a shareable object because `a` refers to the unshareable object `[2]` (this Array is not frozen).
+ * `h = {c: Object}.freeze`: `h` is shareable because `Symbol`s and `Class`es are shareable, and the Hash is frozen.
+ * Class/Module objects are always shareable, even if they refer to unshareable objects.
+ * Special shareable objects
+ * Ractor objects themselves are shareable.
+ * And more...
+
+### Communication between Ractors with `Ractor::Port`
+
+Ractors communicate with each other and synchronize their execution by exchanging messages. The `Ractor::Port` class provides this communication mechanism.
+
+```ruby
+port = Ractor::Port.new
+
+Ractor.new port do |port|
+ # Other ractors can send to the port
+ port << 42
+end
+
+port.receive # get a message from the port. Only the ractor that created the Port can receive from it.
+#=> 42
+```
+
+All Ractors have a default port, which `Ractor#send`, `Ractor.receive` (etc) will use.
+
+### Copy & Move semantics when sending objects
+
+To send unshareable objects to another ractor, objects are either copied or moved.
+
+* Copy: deep-copies the object to the other ractor. All unshareable objects will be `Kernel#clone`ed.
+* Move: moves membership to another ractor.
+ * The sending ractor can not access the moved object after it moves.
+ * There is a guarantee that only one ractor can access an unshareable object at once.
+
+### Thread-safety
+
+Ractors help to write thread-safe, concurrent programs. They allow sharing of data only through explicit message passing for
+unshareable objects. Shareable objects are guaranteed to work correctly across ractors, even if the ractors are running in parallel.
+This guarantee, however, only applies across ractors. You still need to use `Mutex`es and other thread-safety tools within a ractor if
+you're using multiple ruby `Thread`s.
+
+ * Most objects are unshareable. You can't create data-races across ractors due to the inability to use these objects across ractors.
+ * Shareable objects are protected by locks (or otherwise don't need to be) so they can be used by more than one ractor at once.
+
+## Creation and termination
+
+### `Ractor.new`
+
+* `Ractor.new { expr }` creates a Ractor.
+
+```ruby
+# Ractor.new with a block creates a new Ractor
+r = Ractor.new do
+ # This block can run in parallel with other ractors
+end
+
+# You can name a Ractor with a `name:` argument.
+r = Ractor.new name: 'my-first-ractor' do
+end
+
+r.name #=> 'my-first-ractor'
+```
+
+### Block isolation
+
+The Ractor executes `expr` in the given block.
+The given block will be isolated from its outer scope. To prevent sharing objects between ractors, outer variables, `self` and other information is isolated from the block.
+
+This isolation occurs at Ractor creation time (when `Ractor.new` is called). If the given block is not able to be isolated because of outer variables or `self`, an error will be raised.
+
+```ruby
+begin
+ a = true
+ r = Ractor.new do
+ a #=> Ractor::IsolationError because this block accesses outer variable `a`.
+ end
+ r.join # wait for ractor to finish
+rescue Ractor::IsolationError
+end
+```
+
+* The `self` of the given block is the `Ractor` object itself.
+
+```ruby
+r = Ractor.new do
+ p self.class #=> Ractor
+ self.object_id
+end
+r.value == self.object_id #=> false
+```
+
+Arguments passed to `Ractor.new()` become block parameters for the given block. However, Ruby does not pass the objects themselves, but sends them as messages (see below for details).
+
+```ruby
+r = Ractor.new 'ok' do |msg|
+ msg #=> 'ok'
+end
+r.value #=> 'ok'
+```
+
+```ruby
+# similar to the last example
+r = Ractor.new do
+ msg = Ractor.receive
+ msg
+end
+r.send 'ok'
+r.value #=> 'ok'
+```
+
+### The execution result of the given block
+
+The return value of the given block becomes an outgoing message (see below for details).
+
+```ruby
+r = Ractor.new do
+ 'ok'
+end
+r.value #=> `ok`
+```
+
+An error in the given block will be propagated to the consumer of the outgoing message.
+
+```ruby
+r = Ractor.new do
+ raise 'ok' # exception will be transferred to the consumer
+end
+
+begin
+ r.value
+rescue Ractor::RemoteError => e
+ e.cause.class #=> RuntimeError
+ e.cause.message #=> 'ok'
+ e.ractor #=> r
+end
+```
+
+## Communication between Ractors
+
+Communication between ractors is achieved by sending and receiving messages. There are two ways to communicate:
+
+* (1) Sending and receiving messages via `Ractor::Port`
+* (2) Using shareable container objects. For example, the Ractor::TVar gem ([ko1/ractor-tvar](https://github.com/ko1/ractor-tvar))
+
+Users can control program execution timing with (1), but should not control with (2) (only perform critical sections).
+
+For sending and receiving messages, these are the fundamental APIs:
+
+* send/receive via `Ractor::Port`.
+ * `Ractor::Port#send(obj)` (`Ractor::Port#<<(obj)` is an alias) sends a message to the port. Ports are connected to an infinite size incoming queue so sending will never block the caller.
+ * `Ractor::Port#receive` dequeues a message from its own incoming queue. If the incoming queue is empty, `Ractor::Port#receive` will block the execution of the current Thread until a message is sent.
+ * `Ractor#send` and `Ractor.receive` use ports (their default port) internally, so are conceptually similar to the above.
+* You can close a `Ractor::Port` by `Ractor::Port#close`. A port can only be closed by the ractor that created it.
+ * If a port is closed, you can't `send` to it. Doing so raises an exception.
+ * When a ractor is terminated, the ractor's ports are automatically closed.
+* You can wait for a ractor's termination and receive its return value with `Ractor#value`. This is similar to `Thread#value`.
+
+There are 3 ways to send an object as a message:
+
+1) Send a reference: sending a shareable object sends only a reference to the object (fast).
+
+2) Copy an object: sending an unshareable object through copying it deeply (can be slow). Note that you can not send an object this way which does not support deep copy. Some `T_DATA` objects (objects whose class is defined in a C extension, such as `StringIO`) are not supported.
+
+3) Move an object: sending an unshareable object across ractors with a membership change. The sending Ractor can not access the moved object after moving it, otherwise an exception will be raised. Implementation note: `T_DATA` objects are not supported.
+
+You can choose between "Copy" and "Move" by the `move:` keyword, `Ractor#send(obj, move: true/false)`. The default is `false` ("Copy"). However, if the object is shareable it will automatically use `move`.
+
+### Wait for multiple Ractors with `Ractor.select`
+
+You can wait for messages on multiple ports at once.
+The return value of `Ractor.select()` is `[port, msg]` where `port` is a ready port and `msg` is the received message.
+
+To make it convenient, `Ractor.select` can also accept ractors. In this case, it waits for their termination.
+The return value of `Ractor.select()` is `[r, msg]` where `r` is a terminated Ractor and `msg` is the value of the ractor's block.
+
+Wait for a single ractor (same as `Ractor#value`):
+
+```ruby
+r1 = Ractor.new{'r1'}
+
+r, obj = Ractor.select(r1)
+r == r1 and obj == 'r1' #=> true
+```
+
+Wait for two ractors:
+
+```ruby
+r1 = Ractor.new{'r1'}
+r2 = Ractor.new{'r2'}
+rs = [r1, r2]
+values = []
+
+while rs.any?
+ r, obj = Ractor.select(*rs)
+ rs.delete(r)
+ values << obj
+end
+
+values.sort == ['r1', 'r2'] #=> true
+```
+
+NOTE: Using `Ractor.select()` on a very large number of ractors has the same issue as `select(2)` currently.
+
+### Closing ports
+
+* `Ractor::Port#close` closes the port (similar to `Queue#close`).
+ * `port.send(obj)` will raise an exception when the port is closed.
+ * When the queue connected to the port is empty and port is closed, `Ractor::Port#receive` raises an exception. If the queue is not empty, it dequeues an object without exceptions.
+* When a Ractor terminates, the ports are closed automatically.
+
+Example (try to get a result from closed ractor):
+
+```ruby
+r = Ractor.new do
+ 'finish'
+end
+r.join # success (wait for the termination)
+r.value # success (will return 'finish')
+
+# The ractor's termination value has already been given to another ractor
+Ractor.new r do |r|
+ r.value #=> Ractor::Error
+end.join
+```
+
+Example (try to send to closed port):
+
+```ruby
+r = Ractor.new do
+end
+
+r.join # wait for termination, closes default port
+
+begin
+ r.send(1)
+rescue Ractor::ClosedError
+ 'ok'
+end
+```
+
+### Send a message by copying
+
+`Ractor::Port#send(obj)` copies `obj` deeply if `obj` is an unshareable object.
+
+```ruby
+obj = 'str'.dup
+r = Ractor.new obj do |msg|
+ # return received msg's object_id
+ msg.object_id
+end
+
+obj.object_id == r.value #=> false
+```
+
+Some objects do not support copying, and raise an exception.
+
+```ruby
+obj = Thread.new{}
+begin
+ Ractor.new obj do |msg|
+ msg
+ end
+rescue TypeError => e
+ e.message #=> #<TypeError: allocator undefined for Thread>
+end
+```
+
+### Send a message by moving
+
+`Ractor::Port#send(obj, move: true)` moves `obj` to the destination Ractor.
+If the source ractor uses the moved object (for example, calls a method like `obj.foo()`), it will raise an error.
+
+```ruby
+r = Ractor.new do
+ obj = Ractor.receive
+ obj << ' world'
+end
+
+str = 'hello'.dup
+r.send str, move: true
+# str is now moved, and accessing str from this ractor is prohibited
+modified = r.value #=> 'hello world'
+
+
+begin
+ # Error because it uses moved str.
+ str << ' exception' # raise Ractor::MovedError
+rescue Ractor::MovedError
+ modified #=> 'hello world'
+end
+```
+
+Some objects do not support moving, and an exception will be raised.
+
+```ruby
+r = Ractor.new do
+ Ractor.receive
+end
+
+r.send(Thread.new{}, move: true) #=> allocator undefined for Thread (TypeError)
+```
+
+Once an object has been moved, the source object's class is changed to `Ractor::MovedObject`.
+
+### Shareable objects
+
+The following is an inexhaustive list of shareable objects:
+
+* `Integer`, `Float`, `Complex`, `Rational`
+* `Symbol`, frozen `String` objects that don't refer to unshareables, `true`, `false`, `nil`
+* `Regexp` objects, if they have no instance variables or their instance variables refer only to shareables
+* `Class` and `Module` objects
+* `Ractor` and other special objects which deal with synchronization
+
+To make objects shareable, `Ractor.make_shareable(obj)` is provided. It tries to make the object shareable by freezing `obj` and recursively traversing its references to freeze them all. This method accepts the `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. `Ractor.make_shareable(copy: false)` has no effect on an already shareable object. If the object cannot be made shareable, a `Ractor::Error` exception will be raised.
+
+## Language changes to limit sharing between Ractors
+
+To isolate unshareable objects across ractors, we introduced additional language semantics for multi-ractor Ruby programs.
+
+Note that when not using ractors, these additional semantics are not needed (100% compatible with Ruby 2).
+
+### Global variables
+
+Only the main Ractor can access global variables.
+
+```ruby
+$gv = 1
+r = Ractor.new do
+ $gv
+end
+
+begin
+ r.join
+rescue Ractor::RemoteError => e
+ e.cause.message #=> 'can not access global variables from non-main Ractors'
+end
+```
+
+Note that some special global variables, such as `$stdin`, `$stdout` and `$stderr` are local to each ractor. See [[Bug #17268]](https://bugs.ruby-lang.org/issues/17268) for more details.
+
+### Instance variables of shareable objects
+
+Instance variables of classes/modules can be accessed from non-main ractors only if their values are shareable objects.
+
+```ruby
+class C
+ @iv = 1
+end
+
+p Ractor.new do
+ class C
+ @iv
+ end
+end.value #=> 1
+```
+
+Otherwise, only the main Ractor can access instance variables of shareable objects.
+
+```ruby
+class C
+ @iv = [] # unshareable object
+end
+
+Ractor.new do
+ class C
+ begin
+ p @iv
+ rescue Ractor::IsolationError
+ p $!.message
+ #=> "can not get unshareable values from instance variables of classes/modules from non-main Ractors"
+ end
+
+ begin
+ @iv = 42
+ rescue Ractor::IsolationError
+ p $!.message
+ #=> "can not set instance variables of classes/modules by non-main Ractors"
+ end
+ end
+end.join
+```
+
+```ruby
+shared = Ractor.new{}
+shared.instance_variable_set(:@iv, 'str')
+
+r = Ractor.new shared do |shared|
+ p shared.instance_variable_get(:@iv)
+end
+
+begin
+ r.join
+rescue Ractor::RemoteError => e
+ e.cause.message #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError)
+end
+```
+
+### Class variables
+
+Only the main Ractor can access class variables.
+
+```ruby
+class C
+ @@cv = 'str'
+end
+
+r = Ractor.new do
+ class C
+ p @@cv
+ end
+end
+
+
+begin
+ r.join
+rescue => e
+ e.class #=> Ractor::IsolationError
+end
+```
+
+### Constants
+
+Only the main Ractor can read constants which refer to an unshareable object.
+
+```ruby
+class C
+ CONST = 'str'.dup
+end
+r = Ractor.new do
+ C::CONST
+end
+begin
+ r.join
+rescue => e
+ e.class #=> Ractor::IsolationError
+end
+```
+
+Only the main Ractor can define constants which refer to an unshareable object.
+
+```ruby
+class C
+end
+r = Ractor.new do
+ C::CONST = 'str'.dup
+end
+begin
+ r.join
+rescue => e
+ e.class #=> Ractor::IsolationError
+end
+```
+
+When creating/updating a library to support ractors, constants should only refer to shareable objects if they are to be used by non-main ractors.
+
+```ruby
+TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
+```
+
+In this case, `TABLE` refers to an unshareable Hash object. In order for other ractors to use `TABLE`, we need to make it shareable. We can use `Ractor.make_shareable()` like so:
+
+```ruby
+TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
+```
+
+To make it easy, Ruby 3.0 introduced a new `shareable_constant_value` file directive.
+
+```ruby
+# shareable_constant_value: literal
+
+TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
+#=> Same as: TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
+```
+
+The `shareable_constant_value` directive accepts the following modes (descriptions use the example: `CONST = expr`):
+
+* 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)}`.
+* experimental_everything: replaced to `CONST = Ractor.make_shareable(expr)`.
+* experimental_copy: replaced to `CONST = Ractor.make_shareable(expr, copy: true)`.
+
+Except for the `none` mode (default), it is guaranteed that these constants refer only to shareable objects.
+
+See [syntax/comments.rdoc](../syntax/comments.rdoc) for more details.
+
+### Shareable procs
+
+Procs and lambdas are unshareable objects, even when they are frozen. To create an unshareable Proc, you must use `Ractor.shareable_proc { expr }`. Much like during Ractor creation, the proc's block is isolated from its outer environment, so it cannot access variables from the outside scope. `self` is also changed within the Proc to be `nil` by default, although a `self:` keyword can be provided if you want to customize the value to a different shareable object.
+
+```ruby
+p = Ractor.shareable_proc { p self }
+p.call #=> nil
+```
+
+```ruby
+begin
+ a = 1
+ pr = Ractor.shareable_proc { p a }
+ pr.call # never gets here
+rescue Ractor::IsolationError
+end
+```
+
+In order to dynamically define a method with `Module#define_method` that can be used from different ractors, you must define it with a shareable proc. Alternatively, you can use `Module#class_eval` or `Module#module_eval` with a String. Even though the shareable proc's `self` is initially bound to `nil`, `define_method` will bind `self` to the correct value in the method.
+
+```ruby
+class A
+ define_method :testing, &Ractor.shareable_proc do
+ p self
+ end
+end
+Ractor.new do
+ a = A.new
+ a.testing #=> #<A:0x0000000101acfe10>
+end.join
+```
+
+This isolation must be done to prevent the method from accessing and assigning captured outer variables across ractors.
+
+### Ractor-local storage
+
+You can store any object (even unshareables) in ractor-local storage.
+
+```ruby
+r = Ractor.new do
+ values = []
+ Ractor[:threads] = []
+ 3.times do |i|
+ Ractor[:threads] << Thread.new do
+ values << [Ractor.receive, i+1] # Ractor.receive blocks the current thread in the current ractor until it receives a message
+ end
+ end
+ Ractor[:threads].each(&:join)
+ values
+end
+
+r << 1
+r << 2
+r << 3
+r.value #=> [[1,1],[2,2],[3,3]] (the order can change with each run)
+```
+
+## Examples
+
+### Traditional Ring example in Actor-model
+
+```ruby
+RN = 1_000
+CR = Ractor.current
+
+r = Ractor.new do
+ p Ractor.receive
+ CR << :fin
+end
+
+RN.times{
+ r = Ractor.new r do |next_r|
+ next_r << Ractor.receive
+ end
+}
+
+p :setup_ok
+r << 1
+p Ractor.receive
+```
+
+### Fork-join
+
+```ruby
+def fib n
+ if n < 2
+ 1
+ else
+ fib(n-2) + fib(n-1)
+ end
+end
+
+RN = 10
+rs = (1..RN).map do |i|
+ Ractor.new i do |i|
+ [i, fib(i)]
+ end
+end
+
+until rs.empty?
+ r, v = Ractor.select(*rs)
+ rs.delete r
+ p answer: v
+end
+```
+
+### Worker pool
+
+(1) One ractor has a pool
+
+```ruby
+require 'prime'
+
+N = 1000
+RN = 10
+
+# make RN workers
+workers = (1..RN).map do
+ Ractor.new do |; result_port|
+ loop do
+ n, result_port = Ractor.receive
+ result_port << [n, n.prime?, Ractor.current]
+ end
+ end
+end
+
+result_port = Ractor::Port.new
+results = []
+
+(1..N).each do |i|
+ if workers.empty?
+ # receive a result
+ n, result, w = result_port.receive
+ results << [n, result]
+ else
+ w = workers.pop
+ end
+
+ # send a task to the idle worker ractor
+ w << [i, result_port]
+end
+
+# receive a result
+while results.size != N
+ n, result, _w = result_port.receive
+ results << [n, result]
+end
+
+pp results.sort_by{|n, result| n}
+```
+
+### Pipeline
+
+```ruby
+# pipeline with send/receive
+
+r3 = Ractor.new Ractor.current do |cr|
+ cr.send Ractor.receive + 'r3'
+end
+
+r2 = Ractor.new r3 do |r3|
+ r3.send Ractor.receive + 'r2'
+end
+
+r1 = Ractor.new r2 do |r2|
+ r2.send Ractor.receive + 'r1'
+end
+
+r1 << 'r0'
+p Ractor.receive #=> "r0r1r2r3"
+```
+
+### Supervise
+
+```ruby
+# ring example again
+
+r = Ractor.current
+(1..10).map{|i|
+ r = Ractor.new r, i do |r, i|
+ r.send Ractor.receive + "r#{i}"
+ end
+}
+
+r.send "r0"
+p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
+```
+
+```ruby
+# ring example with an error
+
+r = Ractor.current
+rs = (1..10).map{|i|
+ r = Ractor.new r, i do |r, i|
+ loop do
+ msg = Ractor.receive
+ raise if /e/ =~ msg
+ r.send msg + "r#{i}"
+ end
+ end
+}
+
+r.send "r0"
+p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
+r.send "r0"
+p Ractor.select(*rs, Ractor.current) #=> [:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
+r.send "e0"
+p Ractor.select(*rs, Ractor.current)
+#=>
+# <Thread:0x000056262de28bd8 run> terminated with exception (report_on_exception is true):
+# Traceback (most recent call last):
+# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
+# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
+# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
+# Traceback (most recent call last):
+# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
+# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
+# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
+# 1: from /home/ko1/src/ruby/trunk/test.rb:21:in `<main>'
+# <internal:ractor>:69:in `select': thrown by remote Ractor. (Ractor::RemoteError)
+```
+
+```ruby
+# resend non-error message
+
+r = Ractor.current
+rs = (1..10).map{|i|
+ r = Ractor.new r, i do |r, i|
+ loop do
+ msg = Ractor.receive
+ raise if /e/ =~ msg
+ r.send msg + "r#{i}"
+ end
+ end
+}
+
+r.send "r0"
+p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
+r.send "r0"
+p Ractor.select(*rs, Ractor.current)
+[:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
+msg = 'e0'
+begin
+ r.send msg
+ p Ractor.select(*rs, Ractor.current)
+rescue Ractor::RemoteError
+ msg = 'r0'
+ retry
+end
+
+#=> <internal:ractor>:100:in `send': The incoming-port is already closed (Ractor::ClosedError)
+# because r == r[-1] is terminated.
+```
+
+```ruby
+# ring example with supervisor and re-start
+
+def make_ractor r, i
+ Ractor.new r, i do |r, i|
+ loop do
+ msg = Ractor.receive
+ raise if /e/ =~ msg
+ r.send msg + "r#{i}"
+ end
+ end
+end
+
+r = Ractor.current
+rs = (1..10).map{|i|
+ r = make_ractor(r, i)
+}
+
+msg = 'e0' # error causing message
+begin
+ r.send msg
+ p Ractor.select(*rs, Ractor.current)
+rescue Ractor::RemoteError
+ r = rs[-1] = make_ractor(rs[-2], rs.size-1)
+ msg = 'x0'
+ retry
+end
+
+#=> [:receive, "x0r9r9r8r7r6r5r4r3r2r1"]
+```
diff --git a/doc/regexp/methods.rdoc b/doc/language/regexp/methods.rdoc
index 356156ac9a..356156ac9a 100644
--- a/doc/regexp/methods.rdoc
+++ b/doc/language/regexp/methods.rdoc
diff --git a/doc/language/regexp/unicode_properties.rdoc b/doc/language/regexp/unicode_properties.rdoc
new file mode 100644
index 0000000000..94080f7199
--- /dev/null
+++ b/doc/language/regexp/unicode_properties.rdoc
@@ -0,0 +1,718 @@
+== \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{IDS_Unary_Operator}</tt>, <tt>\p{IDSU}</tt>
+- <tt>\p{ID_Compat_Math_Continue}</tt>
+- <tt>\p{ID_Compat_Math_Start}</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{Modifier_Combining_Mark}</tt>, <tt>\p{MCM}</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{InCB_Consonant}</tt>
+- <tt>\p{InCB_Extend}</tt>
+- <tt>\p{InCB_Linker}</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{Beria_Erfe}</tt>, <tt>\p{Berf}</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{Garay}</tt>, <tt>\p{Gara}</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{Gurung_Khema}</tt>, <tt>\p{Gukh}</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{Kirat_Rai}</tt>, <tt>\p{Krai}</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{Ol_Onal}</tt>, <tt>\p{Onao}</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{Sidetic}</tt>, <tt>\p{Sidt}</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{Sunuwar}</tt>, <tt>\p{Sunu}</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{Tai_Yo}</tt>, <tt>\p{Tayo}</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{Todhri}</tt>, <tt>\p{Todr}</tt>
+- <tt>\p{Tolong_Siki}</tt>, <tt>\p{Tols}</tt>
+- <tt>\p{Toto}</tt>
+- <tt>\p{Tulu_Tigalari}</tt>, <tt>\p{Tutg}</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_Beria_Erfe}</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_CJK_Unified_Ideographs_Extension_I}</tt>
+- <tt>\p{In_CJK_Unified_Ideographs_Extension_J}</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_Egyptian_Hieroglyphs_Extended_A}</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_Garay}</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_Gurung_Khema}</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_Kirat_Rai}</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_Supplement}</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_Myanmar_Extended_C}</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_Ol_Onal}</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_Sharada_Supplement}</tt>
+- <tt>\p{In_Shavian}</tt>
+- <tt>\p{In_Shorthand_Format_Controls}</tt>
+- <tt>\p{In_Siddham}</tt>
+- <tt>\p{In_Sidetic}</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_Sunuwar}</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_Symbols_for_Legacy_Computing_Supplement}</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_Tai_Yo}</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_Components_Supplement}</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_Todhri}</tt>
+- <tt>\p{In_Tolong_Siki}</tt>
+- <tt>\p{In_Toto}</tt>
+- <tt>\p{In_Transport_and_Map_Symbols}</tt>
+- <tt>\p{In_Tulu_Tigalari}</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_15_1}</tt>
+- <tt>\p{Age_16_0}</tt>
+- <tt>\p{Age_17_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/language/signals.rdoc b/doc/language/signals.rdoc
new file mode 100644
index 0000000000..a82dab81c6
--- /dev/null
+++ b/doc/language/signals.rdoc
@@ -0,0 +1,106 @@
+= Caveats for implementing Signal.trap callbacks
+
+As with implementing signal handlers in C or most other languages,
+all code passed to Signal.trap must be reentrant. If you are not
+familiar with reentrancy, you need to read up on it at
+{Wikipedia}[https://en.wikipedia.org/wiki/Reentrancy_(computing)] or
+elsewhere before reading the rest of this document.
+
+Most importantly, "thread-safety" does not guarantee reentrancy;
+and methods such as Mutex#lock and Mutex#synchronize which are
+commonly used for thread-safety even prevent reentrancy.
+
+== An implementation detail of the Ruby VM
+
+The Ruby VM defers Signal.trap callbacks from running until it is safe
+for its internal data structures, but it does not know when it is safe
+for data structures in YOUR code. Ruby implements deferred signal
+handling by registering short C functions with only
+{async-signal-safe functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html] as
+signal handlers. These short C functions only do enough to tell the VM to
+run callbacks registered via Signal.trap later in the main Ruby Thread.
+
+== Unsafe methods to call in Signal.trap blocks
+
+When in doubt, consider anything not listed as safe below as being
+unsafe.
+
+* Mutex#lock, Mutex#synchronize and any code using them are explicitly
+ unsafe. This includes Monitor in the standard library which uses
+ Mutex to provide reentrancy.
+
+* Dir.chdir with block
+
+* any IO write operations when IO#sync is false;
+ including IO#write, IO#write_nonblock, IO#puts.
+ Pipes and sockets default to `IO#sync = true', so it is safe to
+ write to them unless IO#sync was disabled.
+
+* File#flock, as the underlying flock(2) call is not specified by POSIX
+
+== Commonly safe operations inside Signal.trap blocks
+
+* Assignment and retrieval of local, instance, and class variables
+
+* Most object allocations and initializations of common types
+ including Array, Hash, String, Struct, Time.
+
+* Common Array, Hash, String, Struct operations which do not execute a block
+ are generally safe; but beware if iteration is occurring elsewhere.
+
+* Hash#[], Hash#[]= (unless Hash.new was given an unsafe block)
+
+* Thread::Queue#push and Thread::SizedQueue#push (since Ruby 2.1)
+
+* Creating a new Thread via Thread.new/Thread.start can used to get
+ around the unusability of Mutexes inside a signal handler
+
+* Signal.trap is safe to use inside blocks passed to Signal.trap
+
+* arithmetic on Integer and Float (`+', `-', '%', '*', '/')
+
+ Additionally, signal handlers do not run between two successive
+ local variable accesses, so shortcuts such as `+=' and `-=' will
+ not trigger a data race when used on Integer and Float classes in
+ signal handlers.
+
+== System call wrapper methods which are safe inside Signal.trap
+
+Since Ruby has wrappers around many
+{async-signal-safe C functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html]
+the corresponding wrappers for many IO, File, Dir, and Socket methods
+are safe.
+
+(Incomplete list)
+
+* Dir.chdir (without block arg)
+* Dir.mkdir
+* Dir.open
+* File#truncate
+* File.link
+* File.open
+* File.readlink
+* File.rename
+* File.stat
+* File.symlink
+* File.truncate
+* File.unlink
+* File.utime
+* IO#close
+* IO#dup
+* IO#fsync
+* IO#read
+* IO#read_nonblock
+* IO#stat
+* IO#sysread
+* IO#syswrite
+* IO.select
+* IO.pipe
+* Process.clock_gettime
+* Process.exit!
+* Process.fork
+* Process.kill
+* Process.pid
+* Process.ppid
+* Process.waitpid
+...
diff --git a/doc/language/strftime_formatting.rdoc b/doc/language/strftime_formatting.rdoc
new file mode 100644
index 0000000000..2bfa6b975e
--- /dev/null
+++ b/doc/language/strftime_formatting.rdoc
@@ -0,0 +1,525 @@
+= 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:
+
+- Date#strftime.
+- DateTime#strftime.
+- Time#strftime.
+
+Each of these methods takes optional argument +format+,
+which has zero or more embedded _format_ _specifications_ (see below).
+
+Each of these methods returns the string resulting from replacing each
+format specification embedded in +format+ with a string form
+of one or more parts of the date or time.
+
+A simple example:
+
+ Time.now.strftime('%H:%M:%S') # => "14:02:07"
+
+A format specification has the form:
+
+ %[flags][width]conversion
+
+It consists of:
+
+- A leading percent character.
+- Zero or more _flags_ (each is a character).
+- An optional _width_ _specifier_ (an integer).
+- A _conversion_ _specifier_ (a character).
+
+Except for the leading percent character,
+the only required part is the conversion specifier, so we begin with that.
+
+== Conversion Specifiers
+
+=== \Date (Year, Month, Day)
+
+- <tt>%Y</tt> - Year including century, zero-padded:
+
+ Time.now.strftime('%Y') # => "2022"
+ Time.new(-1000).strftime('%Y') # => "-1000" # Before common era.
+ Time.new(10000).strftime('%Y') # => "10000" # Far future.
+ Time.new(10).strftime('%Y') # => "0010" # Zero-padded by default.
+
+- <tt>%y</tt> - Year without century, in range (0.99), zero-padded:
+
+ Time.now.strftime('%y') # => "22"
+ Time.new(1).strftime('%y') # => "01" # Zero-padded by default.
+
+- <tt>%C</tt> - Century, zero-padded:
+
+ Time.now.strftime('%C') # => "20"
+ Time.new(-1000).strftime('%C') # => "-10" # Before common era.
+ Time.new(10000).strftime('%C') # => "100" # Far future.
+ Time.new(100).strftime('%C') # => "01" # Zero-padded by default.
+
+- <tt>%m</tt> - Month of the year, in range (1..12), zero-padded:
+
+ Time.new(2022, 1).strftime('%m') # => "01" # Zero-padded by default.
+ Time.new(2022, 12).strftime('%m') # => "12"
+
+- <tt>%B</tt> - Full month name, capitalized:
+
+ Time.new(2022, 1).strftime('%B') # => "January"
+ Time.new(2022, 12).strftime('%B') # => "December"
+
+- <tt>%b</tt> - Abbreviated month name, capitalized:
+
+ Time.new(2022, 1).strftime('%b') # => "Jan"
+ Time.new(2022, 12).strftime('%h') # => "Dec"
+
+- <tt>%h</tt> - Same as <tt>%b</tt>.
+
+- <tt>%d</tt> - Day of the month, in range (1..31), zero-padded:
+
+ Time.new(2002, 1, 1).strftime('%d') # => "01"
+ Time.new(2002, 1, 31).strftime('%d') # => "31"
+
+- <tt>%e</tt> - Day of the month, in range (1..31), blank-padded:
+
+ Time.new(2002, 1, 1).strftime('%e') # => " 1"
+ Time.new(2002, 1, 31).strftime('%e') # => "31"
+
+- <tt>%j</tt> - Day of the year, in range (1..366), zero-padded:
+
+ Time.new(2002, 1, 1).strftime('%j') # => "001"
+ Time.new(2002, 12, 31).strftime('%j') # => "365"
+
+=== \Time (Hour, Minute, Second, Subsecond)
+
+- <tt>%H</tt> - Hour of the day, in range (0..23), zero-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%H') # => "01"
+ Time.new(2022, 1, 1, 13).strftime('%H') # => "13"
+
+- <tt>%k</tt> - Hour of the day, in range (0..23), blank-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%k') # => " 1"
+ Time.new(2022, 1, 1, 13).strftime('%k') # => "13"
+
+- <tt>%I</tt> - Hour of the day, in range (1..12), zero-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%I') # => "01"
+ Time.new(2022, 1, 1, 13).strftime('%I') # => "01"
+
+- <tt>%l</tt> - Hour of the day, in range (1..12), blank-padded:
+
+ Time.new(2022, 1, 1, 1).strftime('%l') # => " 1"
+ Time.new(2022, 1, 1, 13).strftime('%l') # => " 1"
+
+- <tt>%P</tt> - Meridian indicator, lowercase:
+
+ Time.new(2022, 1, 1, 1).strftime('%P') # => "am"
+ Time.new(2022, 1, 1, 13).strftime('%P') # => "pm"
+
+- <tt>%p</tt> - Meridian indicator, uppercase:
+
+ Time.new(2022, 1, 1, 1).strftime('%p') # => "AM"
+ Time.new(2022, 1, 1, 13).strftime('%p') # => "PM"
+
+- <tt>%M</tt> - Minute of the hour, in range (0..59), zero-padded:
+
+ Time.new(2022, 1, 1, 1, 0, 0).strftime('%M') # => "00"
+
+- <tt>%S</tt> - Second of the minute in range (0..59), zero-padded:
+
+ Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%S') # => "00"
+
+- <tt>%L</tt> - Millisecond of the second, in range (0..999), zero-padded:
+
+ Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%L') # => "000"
+
+- <tt>%N</tt> - Fractional seconds, default width is 9 digits (nanoseconds):
+
+ t = Time.now # => 2022-06-29 07:10:20.3230914 -0500
+ t.strftime('%N') # => "323091400" # Default.
+
+ Use {width specifiers}[rdoc-ref:@Width+Specifiers]
+ to adjust units:
+
+ t.strftime('%3N') # => "323" # Milliseconds.
+ t.strftime('%6N') # => "323091" # Microseconds.
+ t.strftime('%9N') # => "323091400" # Nanoseconds.
+ t.strftime('%12N') # => "323091400000" # Picoseconds.
+ t.strftime('%15N') # => "323091400000000" # Femptoseconds.
+ t.strftime('%18N') # => "323091400000000000" # Attoseconds.
+ t.strftime('%21N') # => "323091400000000000000" # Zeptoseconds.
+ t.strftime('%24N') # => "323091400000000000000000" # Yoctoseconds.
+
+- <tt>%s</tt> - Number of seconds since the epoch:
+
+ Time.now.strftime('%s') # => "1656505136"
+
+=== Timezone
+
+- <tt>%z</tt> - Timezone as hour and minute offset from UTC:
+
+ Time.now.strftime('%z') # => "-0500"
+
+- <tt>%Z</tt> - Timezone name (platform-dependent):
+
+ Time.now.strftime('%Z') # => "Central Daylight Time"
+
+=== Weekday
+
+- <tt>%A</tt> - Full weekday name:
+
+ Time.now.strftime('%A') # => "Wednesday"
+
+- <tt>%a</tt> - Abbreviated weekday name:
+
+ Time.now.strftime('%a') # => "Wed"
+
+- <tt>%u</tt> - Day of the week, in range (1..7), Monday is 1:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%u') # => "7"
+
+- <tt>%w</tt> - Day of the week, in range (0..6), Sunday is 0:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%w') # => "0"
+
+=== Week Number
+
+- <tt>%U</tt> - Week number of the year, in range (0..53), zero-padded,
+ where each week begins on a Sunday:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%U') # => "26"
+
+- <tt>%W</tt> - Week number of the year, in range (0..53), zero-padded,
+ where each week begins on a Monday:
+
+ t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
+ t.strftime('%a') # => "Sun"
+ t.strftime('%W') # => "25"
+
+=== Week Dates
+
+See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
+
+ t0 = Time.new(2023, 1, 1) # => 2023-01-01 00:00:00 -0600
+ t1 = Time.new(2024, 1, 1) # => 2024-01-01 00:00:00 -0600
+
+- <tt>%G</tt> - Week-based year:
+
+ t0.strftime('%G') # => "2022"
+ t1.strftime('%G') # => "2024"
+
+- <tt>%g</tt> - Week-based year without century, in range (0..99), zero-padded:
+
+ t0.strftime('%g') # => "22"
+ t1.strftime('%g') # => "24"
+
+- <tt>%V</tt> - Week number of the week-based year, in range (1..53),
+ zero-padded:
+
+ t0.strftime('%V') # => "52"
+ t1.strftime('%V') # => "01"
+
+=== Literals
+
+- <tt>%n</tt> - Newline character "\n":
+
+ Time.now.strftime('%n') # => "\n"
+
+- <tt>%t</tt> - Tab character "\t":
+
+ Time.now.strftime('%t') # => "\t"
+
+- <tt>%%</tt> - Percent character '%':
+
+ Time.now.strftime('%%') # => "%"
+
+=== Shorthand Conversion Specifiers
+
+Each shorthand specifier here is shown with its corresponding
+longhand specifier.
+
+- <tt>%c</tt> - \Date and time:
+
+ Time.now.strftime('%c') # => "Wed Jun 29 08:01:41 2022"
+ Time.now.strftime('%a %b %e %T %Y') # => "Wed Jun 29 08:02:07 2022"
+
+- <tt>%D</tt> - \Date:
+
+ Time.now.strftime('%D') # => "06/29/22"
+ Time.now.strftime('%m/%d/%y') # => "06/29/22"
+
+- <tt>%F</tt> - ISO 8601 date:
+
+ Time.now.strftime('%F') # => "2022-06-29"
+ Time.now.strftime('%Y-%m-%d') # => "2022-06-29"
+
+- <tt>%v</tt> - VMS date:
+
+ Time.now.strftime('%v') # => "29-JUN-2022"
+ Time.now.strftime('%e-%^b-%4Y') # => "29-JUN-2022"
+
+- <tt>%x</tt> - Same as <tt>%D</tt>.
+
+- <tt>%X</tt> - Same as <tt>%T</tt>.
+
+- <tt>%r</tt> - 12-hour time:
+
+ Time.new(2022, 1, 1, 1).strftime('%r') # => "01:00:00 AM"
+ Time.new(2022, 1, 1, 1).strftime('%I:%M:%S %p') # => "01:00:00 AM"
+ Time.new(2022, 1, 1, 13).strftime('%r') # => "01:00:00 PM"
+ Time.new(2022, 1, 1, 13).strftime('%I:%M:%S %p') # => "01:00:00 PM"
+
+- <tt>%R</tt> - 24-hour time:
+
+ Time.new(2022, 1, 1, 1).strftime('%R') # => "01:00"
+ Time.new(2022, 1, 1, 1).strftime('%H:%M') # => "01:00"
+ Time.new(2022, 1, 1, 13).strftime('%R') # => "13:00"
+ Time.new(2022, 1, 1, 13).strftime('%H:%M') # => "13:00"
+
+- <tt>%T</tt> - 24-hour time:
+
+ Time.new(2022, 1, 1, 1).strftime('%T') # => "01:00:00"
+ Time.new(2022, 1, 1, 1).strftime('%H:%M:%S') # => "01:00:00"
+ Time.new(2022, 1, 1, 13).strftime('%T') # => "13:00:00"
+ Time.new(2022, 1, 1, 13).strftime('%H:%M:%S') # => "13:00:00"
+
+- <tt>%+</tt> (not supported in Time#strftime) - \Date and time:
+
+ DateTime.now.strftime('%+')
+ # => "Wed Jun 29 08:31:53 -05:00 2022"
+ DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y')
+ # => "Wed Jun 29 08:32:18 -05:00 2022"
+
+== Flags
+
+Flags may affect certain formatting specifications.
+
+Multiple flags may be given with a single conversion specified;
+order does not matter.
+
+=== Padding Flags
+
+- <tt>0</tt> - Pad with zeroes:
+
+ Time.new(10).strftime('%0Y') # => "0010"
+
+- <tt>_</tt> - Pad with blanks:
+
+ Time.new(10).strftime('%_Y') # => " 10"
+
+- <tt>-</tt> - Don't pad:
+
+ Time.new(10).strftime('%-Y') # => "10"
+
+=== Casing Flags
+
+- <tt>^</tt> - Upcase result:
+
+ Time.new(2022, 1).strftime('%B') # => "January" # No casing flag.
+ Time.new(2022, 1).strftime('%^B') # => "JANUARY"
+
+- <tt>#</tt> - Swapcase result:
+
+ Time.now.strftime('%p') # => "AM"
+ Time.now.strftime('%^p') # => "AM"
+ Time.now.strftime('%#p') # => "am"
+
+=== Timezone Flags
+
+- <tt>:</tt> - Put timezone as colon-separated hours and minutes:
+
+ Time.now.strftime('%:z') # => "-05:00"
+
+- <tt>::</tt> - Put timezone as colon-separated hours, minutes, and seconds:
+
+ Time.now.strftime('%::z') # => "-05:00:00"
+
+== Width Specifiers
+
+The integer width specifier gives a minimum width for the returned string:
+
+ Time.new(2002).strftime('%Y') # => "2002" # No width specifier.
+ Time.new(2002).strftime('%10Y') # => "0000002002"
+ Time.new(2002, 12).strftime('%B') # => "December" # No width specifier.
+ Time.new(2002, 12).strftime('%10B') # => " December"
+ Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
+
+= Specialized Format Strings
+
+Here are a few specialized format strings,
+each based on an external standard.
+
+== HTTP Format
+
+The HTTP date format is based on
+{RFC 2616}[https://www.rfc-editor.org/rfc/rfc2616],
+and treats dates in the format <tt>'%a, %d %b %Y %T GMT'</tt>:
+
+ d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
+ # Return HTTP-formatted string.
+ httpdate = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
+ # Return new date parsed from HTTP-formatted string.
+ Date.httpdate(httpdate) # => #<Date: 2001-02-03>
+ # Return hash parsed from HTTP-formatted string.
+ Date._httpdate(httpdate)
+ # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
+
+== RFC 3339 Format
+
+The RFC 3339 date format is based on
+{RFC 3339}[https://www.rfc-editor.org/rfc/rfc3339]:
+
+ d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
+ # Return 3339-formatted string.
+ rfc3339 = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
+ # Return new date parsed from 3339-formatted string.
+ Date.rfc3339(rfc3339) # => #<Date: 2001-02-03>
+ # Return hash parsed from 3339-formatted string.
+ Date._rfc3339(rfc3339)
+ # => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
+
+== RFC 2822 Format
+
+The RFC 2822 date format is based on
+{RFC 2822}[https://www.rfc-editor.org/rfc/rfc2822],
+and treats dates in the format <tt>'%a, %-d %b %Y %T %z'</tt>]:
+
+ d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
+ # Return 2822-formatted string.
+ rfc2822 = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
+ # Return new date parsed from 2822-formatted string.
+ Date.rfc2822(rfc2822) # => #<Date: 2001-02-03>
+ # Return hash parsed from 2822-formatted string.
+ 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
+
+The JIS X 0301 format includes the
+{Japanese era name}[https://en.wikipedia.org/wiki/Japanese_era_name],
+and treats dates in the format <tt>'%Y-%m-%d'</tt>
+with the first letter of the romanized era name prefixed:
+
+ d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
+ # Return 0301-formatted string.
+ jisx0301 = d.jisx0301 # => "H13.02.03"
+ # Return new date parsed from 0301-formatted string.
+ Date.jisx0301(jisx0301) # => #<Date: 2001-02-03>
+ # Return hash parsed from 0301-formatted string.
+ Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
+
+== ISO 8601 Format Specifications
+
+This section shows format specifications that are compatible with
+{ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601].
+Details for various formats may be seen at the links.
+
+Examples in this section assume:
+
+ t = Time.now # => 2022-06-29 16:49:25.465246 -0500
+
+=== Dates
+
+See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
+
+- {Years}[https://en.wikipedia.org/wiki/ISO_8601#Years]:
+
+ - Basic year (+YYYY+):
+
+ t.strftime('%Y') # => "2022"
+
+ - Expanded year (<tt>±YYYYY</tt>):
+
+ t.strftime('+%5Y') # => "+02022"
+ t.strftime('-%5Y') # => "-02022"
+
+- {Calendar dates}[https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates]:
+
+ - Basic date (+YYYYMMDD+):
+
+ t.strftime('%Y%m%d') # => "20220629"
+
+ - Extended date (<tt>YYYY-MM-DD</tt>):
+
+ t.strftime('%Y-%m-%d') # => "2022-06-29"
+
+ - Reduced extended date (<tt>YYYY-MM</tt>):
+
+ t.strftime('%Y-%m') # => "2022-06"
+
+- {Week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates]:
+
+ - Basic date (+YYYYWww+ or +YYYYWwwD+):
+
+ t.strftime('%Y%Ww') # => "202226w"
+ t.strftime('%Y%Ww%u') # => "202226w3"
+
+ - Extended date (<tt>YYYY-Www</tt> or <tt>YYYY-Www-D<tt>):
+
+ t.strftime('%Y-%Ww') # => "2022-26w"
+ t.strftime('%Y-%Ww-%u') # => "2022-26w-3"
+
+- {Ordinal dates}[https://en.wikipedia.org/wiki/ISO_8601#Ordinal_dates]:
+
+ - Basic date (+YYYYDDD+):
+
+ t.strftime('%Y%j') # => "2022180"
+
+ - Extended date (<tt>YYYY-DDD</tt>):
+
+ t.strftime('%Y-%j') # => "2022-180"
+
+=== Times
+
+See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
+
+- Times:
+
+ - Basic time (+Thhmmss.sss+, +Thhmmss+, +Thhmm+, or +Thh+):
+
+ t.strftime('T%H%M%S.%L') # => "T164925.465"
+ t.strftime('T%H%M%S') # => "T164925"
+ t.strftime('T%H%M') # => "T1649"
+ t.strftime('T%H') # => "T16"
+
+ - Extended time (+Thh:mm:ss.sss+, +Thh:mm:ss+, or +Thh:mm+):
+
+ t.strftime('T%H:%M:%S.%L') # => "T16:49:25.465"
+ t.strftime('T%H:%M:%S') # => "T16:49:25"
+ t.strftime('T%H:%M') # => "T16:49"
+
+- {Time zone designators}[https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators]:
+
+ - Timezone (+time+ represents a valid time,
+ +hh+ represents a valid 2-digit hour,
+ and +mm+ represents a valid 2-digit minute):
+
+ - Basic timezone (<tt>time±hhmm</tt>, <tt>time±hh</tt>, or +timeZ+):
+
+ t.strftime('T%H%M%S%z') # => "T164925-0500"
+ t.strftime('T%H%M%S%z').slice(0..-3) # => "T164925-05"
+ t.strftime('T%H%M%SZ') # => "T164925Z"
+
+ - Extended timezone (<tt>time±hh:mm</tt>):
+
+ t.strftime('T%H:%M:%S%z') # => "T16:49:25-0500"
+
+ - See also:
+
+ - {Local time (unqualified)}[https://en.wikipedia.org/wiki/ISO_8601#Local_time_(unqualified)].
+ - {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
+
+See {ISO 8601 Combined date and time representations}[https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations].
+
+An ISO 8601 combined date and time representation may be any
+ISO 8601 date and any ISO 8601 time,
+separated by the letter +T+.
+
+For the relevant +strftime+ formats, see {Dates}[rdoc-ref:@Dates] and {Times}[rdoc-ref:@Times] above.
diff --git a/doc/maintainers.md b/doc/maintainers.md
index a216e564a5..e87ccaca05 100644
--- a/doc/maintainers.md
+++ b/doc/maintainers.md
@@ -28,6 +28,10 @@ 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.
+No maintainer means that there is no specific maintainer for the part now.
+The member of ruby core team can fix issues at anytime. But major changes need
+consensus on ruby-core/ruby-dev.
+
### Language core features including security
* Yukihiro Matsumoto ([matz])
@@ -40,25 +44,30 @@ have commit right, others don't.
* Yukihiro Matsumoto ([matz])
-## Standard Library Maintainers
-
-### Libraries
+### Standard Library Maintainers
#### lib/mkmf.rb
-* *unmaintained*
+* *No maintainer*
+
+#### pathname_builtin.rb, lib/pathname.rb
+
+* Tanaka Akira ([akr])
#### lib/rubygems.rb, lib/rubygems/*
-* Eric Hodel ([drbrain])
* Hiroshi SHIBATA ([hsbt])
-* https://github.com/rubygems/rubygems
+* https://github.com/ruby/rubygems
#### lib/unicode_normalize.rb, lib/unicode_normalize/*
* Martin J. Dürst ([duerst])
-### Extensions
+### Standard Library(Extensions) Maintainers
+
+#### set.c
+
+* Akinori MUSHA ([knu])
#### ext/continuation
@@ -78,15 +87,19 @@ have commit right, others don't.
#### ext/objspace
-* *unmaintained*
+* *No maintainer*
+
+#### ext/pathname
+
+* Tanaka Akira ([akr])
#### ext/pty
-* *unmaintained*
+* *No maintainer*
#### ext/ripper
-* *unmaintained*
+* *No maintainer*
#### ext/socket
@@ -97,31 +110,27 @@ have commit right, others don't.
* NAKAMURA Usaku ([unak])
-## Default gems Maintainers
-
-### Libraries
+### Default gems(Libraries) Maintainers
#### lib/bundler.rb, lib/bundler/*
* Hiroshi SHIBATA ([hsbt])
-* https://github.com/rubygems/rubygems
+* https://github.com/ruby/rubygems
* https://rubygems.org/gems/bundler
-#### lib/cgi.rb, lib/cgi/*
+#### lib/cgi/escape.rb
-* *unmaintained*
-* https://github.com/ruby/cgi
-* https://rubygems.org/gems/cgi
+* *No maintainer*
#### lib/English.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/English
* https://rubygems.org/gems/English
#### lib/delegate.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/delegate
* https://rubygems.org/gems/delegate
@@ -152,7 +161,7 @@ have commit right, others don't.
#### lib/fileutils.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/fileutils
* https://rubygems.org/gems/fileutils
@@ -178,6 +187,7 @@ have commit right, others don't.
* Nobuyuki Nakada ([nobu])
* https://github.com/ruby/optparse
+* https://rubygems.org/gems/optparse
#### lib/net/http.rb, lib/net/https.rb
@@ -187,13 +197,13 @@ have commit right, others don't.
#### lib/net/protocol.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/net-protocol
* https://rubygems.org/gems/net-protocol
#### lib/open3.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/open3
* https://rubygems.org/gems/open3
@@ -201,6 +211,7 @@ have commit right, others don't.
* Tanaka Akira ([akr])
* https://github.com/ruby/open-uri
+* https://rubygems.org/gems/open-uri
#### lib/pp.rb
@@ -219,6 +230,7 @@ have commit right, others don't.
* Kevin Newton ([kddnewton])
* Eileen Uchitelle ([eileencodes])
* Aaron Patterson ([tenderlove])
+* Earlopain ([earlopain])
* https://github.com/ruby/prism
* https://rubygems.org/gems/prism
@@ -234,12 +246,6 @@ have commit right, others don't.
* 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])
@@ -254,7 +260,7 @@ have commit right, others don't.
#### lib/tempfile.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/tempfile
* https://rubygems.org/gems/tempfile
@@ -270,24 +276,12 @@ have commit right, others don't.
* 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*
+* *No maintainer*
* 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])
@@ -309,33 +303,31 @@ have commit right, others don't.
#### lib/weakref.rb
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/weakref
* https://rubygems.org/gems/weakref
-### Extensions
+### Default gems(Extensions) Maintainers
#### ext/cgi
* Nobuyoshi Nakada ([nobu])
-* https://github.com/ruby/cgi
-* https://rubygems.org/gems/cgi
#### ext/date
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/date
* https://rubygems.org/gems/date
#### ext/etc
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/etc
* https://rubygems.org/gems/etc
#### ext/fcntl
-* *unmaintained*
+* *No maintainer*
* https://github.com/ruby/fcntl
* https://rubygems.org/gems/fcntl
@@ -371,12 +363,6 @@ have commit right, others don't.
* 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])
@@ -402,159 +388,248 @@ have commit right, others don't.
* https://github.com/ruby/zlib
* https://rubygems.org/gems/zlib
-## Bundled gems upstream repositories
+## Bundled gems upstream repositories and maintainers
+
+The maintanance policy of bundled gems is different from Module Maintainers above.
+Please check the policies for each repository.
+
+The ruby core team tries to maintain the repositories with no maintainers.
+It may needs to make consensus on ruby-core/ruby-dev before making major changes.
### minitest
+* Ryan Davis ([zenspider])
* https://github.com/minitest/minitest
+* https://rubygems.org/gems/minitest
### power_assert
+* Tsujimoto Kenta ([k-tsj])
* https://github.com/ruby/power_assert
+* https://rubygems.org/gems/power_assert
### rake
+* Hiroshi SHIBATA ([hsbt])
* https://github.com/ruby/rake
+* https://rubygems.org/gems/rake
### test-unit
+* Kouhei Sutou ([kou])
* https://github.com/test-unit/test-unit
+* https://rubygems.org/gems/test-unit
### rexml
+* Kouhei Sutou ([kou])
* https://github.com/ruby/rexml
+* https://rubygems.org/gems/rexml
### rss
+* Kouhei Sutou ([kou])
* https://github.com/ruby/rss
-
-### net-ftp
-
-* https://github.com/ruby/net-ftp
+* https://rubygems.org/gems/rss
### net-imap
+* Nicholas A. Evans ([nevans])
* https://github.com/ruby/net-imap
-
-### net-pop
-
-* https://github.com/ruby/net-pop
+* https://rubygems.org/gems/net-imap
### net-smtp
+* TOMITA Masahiro ([tmtm])
* https://github.com/ruby/net-smtp
+* https://rubygems.org/gems/net-smtp
### matrix
+* Marc-André Lafortune ([marcandre])
* https://github.com/ruby/matrix
+* https://rubygems.org/gems/matrix
### prime
* https://github.com/ruby/prime
+* https://rubygems.org/gems/prime
### rbs
+* Soutaro Matsumoto ([soutaro])
* https://github.com/ruby/rbs
+* https://rubygems.org/gems/rbs
### typeprof
+* Yusuke Endoh ([mame])
* https://github.com/ruby/typeprof
+* https://rubygems.org/gems/typeprof
### debug
+* Koichi Sasada ([ko1])
* https://github.com/ruby/debug
+* https://rubygems.org/gems/debug
### racc
+* Yuichi Kaneko ([yui-knk])
* https://github.com/ruby/racc
+* https://rubygems.org/gems/racc
#### mutex_m
* https://github.com/ruby/mutex_m
+* https://rubygems.org/gems/mutex_m
#### getoptlong
* https://github.com/ruby/getoptlong
+* https://rubygems.org/gems/getoptlong
#### base64
+* Yusuke Endoh ([mame])
* https://github.com/ruby/base64
+* https://rubygems.org/gems/base64
#### bigdecimal
+* Kenta Murata ([mrkn])
* https://github.com/ruby/bigdecimal
+* https://rubygems.org/gems/bigdecimal
#### observer
* https://github.com/ruby/observer
+* https://rubygems.org/gems/observer
#### abbrev
+* Akinori MUSHA ([knu])
* https://github.com/ruby/abbrev
+* https://rubygems.org/gems/abbrev
#### resolv-replace
+* Akira TANAKA ([akr])
* https://github.com/ruby/resolv-replace
+* https://rubygems.org/gems/resolv-replace
#### rinda
+* Masatoshi SEKI ([seki])
* https://github.com/ruby/rinda
+* https://rubygems.org/gems/rinda
#### drb
+* Masatoshi SEKI ([seki])
* https://github.com/ruby/drb
+* https://rubygems.org/gems/drb
#### nkf
+* Naruse Yusuke ([nurse])
* https://github.com/ruby/nkf
+* https://rubygems.org/gems/nkf
#### syslog
+* Akinori Musha ([knu])
* https://github.com/ruby/syslog
+* https://rubygems.org/gems/syslog
#### csv
+* Kouhei Sutou ([kou])
* https://github.com/ruby/csv
+* https://rubygems.org/gems/csv
#### ostruct
+* Marc-André Lafortune ([marcandre])
* https://github.com/ruby/ostruct
+* https://rubygems.org/gems/ostruct
#### pstore
* https://github.com/ruby/pstore
+* https://rubygems.org/gems/pstore
#### benchmark
+* Benoit Daloze ([eregon])
* https://github.com/ruby/benchmark
+* https://rubygems.org/gems/benchmark
#### logger
+* Naotoshi Seo ([sonots])
* https://github.com/ruby/logger
+* https://rubygems.org/gems/logger
#### rdoc
+* Stan Lo ([st0012])
+* Nobuyoshi Nakada ([nobu])
* https://github.com/ruby/rdoc
+* https://rubygems.org/gems/rdoc
#### win32ole
+* Masaki Suketa ([suketa])
* https://github.com/ruby/win32ole
+* https://rubygems.org/gems/win32ole
#### irb
+* Tomoya Ishida ([tompng])
+* Stan Lo ([st0012])
+* Mari Imaizumi ([ima1zumi])
+* HASUMI Hitoshi ([hasumikin])
* https://github.com/ruby/irb
+* https://rubygems.org/gems/irb
#### reline
+* Tomoya Ishida ([tompng])
+* Stan Lo ([st0012])
+* Mari Imaizumi ([ima1zumi])
+* HASUMI Hitoshi ([hasumikin])
* https://github.com/ruby/reline
+* https://rubygems.org/gems/reline
#### readline
* https://github.com/ruby/readline
+* https://rubygems.org/gems/readline
#### fiddle
+* Kouhei Sutou ([kou])
* https://github.com/ruby/fiddle
+* https://rubygems.org/gems/fiddle
+
+#### repl_type_completor
+
+* Tomoya Ishida ([tompng])
+* https://github.com/ruby/repl_type_completor
+* https://rubygems.org/gems/repl_type_completor
+
+#### tsort
+
+* Tanaka Akira ([akr])
+* https://github.com/ruby/tsort
+* https://rubygems.org/gems/tsort
+
+#### win32-registry
+
+* Nakamura Usaku ([unak])
+* https://github.com/ruby/win32-registry
+* https://rubygems.org/gems/win32-registry
## Platform Maintainers
@@ -592,7 +667,7 @@ have commit right, others don't.
### cygwin, ...
-* none. (Maintainer WANTED)
+* **No maintainer**
### WebAssembly/WASI
@@ -603,8 +678,10 @@ have commit right, others don't.
[colby-swandale]: https://github.com/colby-swandale
[drbrain]: https://github.com/drbrain
[duerst]: https://github.com/duerst
+[earlopain]: https://github.com/earlopain
[eban]: https://github.com/eban
[eileencodes]: https://github.com/eileencodes
+[eregon]: https://github.com/eregon
[hasumikin]: https://github.com/hasumikin
[hsbt]: https://github.com/hsbt
[ima1zumi]: https://github.com/ima1zumi
@@ -635,3 +712,11 @@ have commit right, others don't.
[tompng]: https://github.com/tompng
[unak]: https://github.com/unak
[yuki24]: https://github.com/yuki24
+[zenspider]: https://github.com/zenspider
+[k-tsj]: https://github.com/k-tsj
+[nevans]: https://github.com/nevans
+[tmtm]: https://github.com/tmtm
+[soutaro]: https://github.com/soutaro
+[yui-knk]: https://github.com/yui-knk
+[hasumikin]: https://github.com/hasumikin
+[suketa]: https://github.com/suketa
diff --git a/doc/matchdata/begin.rdoc b/doc/matchdata/begin.rdoc
index 8046dd9d55..6100617e19 100644
--- a/doc/matchdata/begin.rdoc
+++ b/doc/matchdata/begin.rdoc
@@ -10,12 +10,12 @@ returns the offset of the beginning of the <tt>n</tt>th match:
m[3] # => "113"
m.begin(3) # => 3
- m = /(т)(е)(с)/.match('тест')
- # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
- m[0] # => "тес"
- m.begin(0) # => 0
- m[3] # => "с"
- m.begin(3) # => 2
+ m = /(ん)(に)(ち)/.match('こんにちは')
+ # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
+ m[0] # => "んにち"
+ m.begin(0) # => 1
+ m[3] # => "ち"
+ m.begin(3) # => 3
When string or symbol argument +name+ is given,
returns the offset of the beginning for the named match:
diff --git a/doc/matchdata/bytebegin.rdoc b/doc/matchdata/bytebegin.rdoc
index 5b40a7ef73..54e417a7fc 100644
--- a/doc/matchdata/bytebegin.rdoc
+++ b/doc/matchdata/bytebegin.rdoc
@@ -10,12 +10,12 @@ returns the offset of the beginning of the <tt>n</tt>th match:
m[3] # => "113"
m.bytebegin(3) # => 3
- m = /(т)(е)(с)/.match('тест')
- # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
- m[0] # => "тес"
- m.bytebegin(0) # => 0
- m[3] # => "с"
- m.bytebegin(3) # => 4
+ m = /(ん)(に)(ち)/.match('こんにちは')
+ # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
+ m[0] # => "んにち"
+ m.bytebegin(0) # => 3
+ m[3] # => "ち"
+ m.bytebegin(3) # => 9
When string or symbol argument +name+ is given,
returns the offset of the beginning for the named match:
diff --git a/doc/matchdata/byteend.rdoc b/doc/matchdata/byteend.rdoc
index eb57664022..0a03f76208 100644
--- a/doc/matchdata/byteend.rdoc
+++ b/doc/matchdata/byteend.rdoc
@@ -10,12 +10,12 @@ returns the offset of the end of the <tt>n</tt>th match:
m[3] # => "113"
m.byteend(3) # => 6
- m = /(т)(е)(с)/.match('тест')
- # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
- m[0] # => "тес"
- m.byteend(0) # => 6
- m[3] # => "с"
- m.byteend(3) # => 6
+ m = /(ん)(に)(ち)/.match('こんにちは')
+ # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
+ m[0] # => "んにち"
+ m.byteend(0) # => 12
+ m[3] # => "ち"
+ m.byteend(3) # => 12
When string or symbol argument +name+ is given,
returns the offset of the end for the named match:
diff --git a/doc/matchdata/end.rdoc b/doc/matchdata/end.rdoc
index 0209b2d2fc..c43a5428f3 100644
--- a/doc/matchdata/end.rdoc
+++ b/doc/matchdata/end.rdoc
@@ -10,12 +10,12 @@ returns the offset of the end of the <tt>n</tt>th match:
m[3] # => "113"
m.end(3) # => 6
- m = /(т)(е)(с)/.match('тест')
- # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
- m[0] # => "тес"
- m.end(0) # => 3
- m[3] # => "с"
- m.end(3) # => 3
+ m = /(ん)(に)(ち)/.match('こんにちは')
+ # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
+ m[0] # => "んにち"
+ m.end(0) # => 4
+ m[3] # => "ち"
+ m.end(3) # => 4
When string or symbol argument +name+ is given,
returns the offset of the end for the named match:
diff --git a/doc/matchdata/offset.rdoc b/doc/matchdata/offset.rdoc
index 0985316d76..4194ef7ef9 100644
--- a/doc/matchdata/offset.rdoc
+++ b/doc/matchdata/offset.rdoc
@@ -11,12 +11,12 @@ returns the starting and ending offsets of the <tt>n</tt>th match:
m[3] # => "113"
m.offset(3) # => [3, 6]
- m = /(т)(е)(с)/.match('тест')
- # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
- m[0] # => "тес"
- m.offset(0) # => [0, 3]
- m[3] # => "с"
- m.offset(3) # => [2, 3]
+ m = /(ん)(に)(ち)/.match('こんにちは')
+ # => #<MatchData "んにち" 1:"ん" 2:"に" 3:"ち">
+ m[0] # => "んにち"
+ m.offset(0) # => [1, 4]
+ m[3] # => "ち"
+ m.offset(3) # => [3, 4]
When string or symbol argument +name+ is given,
returns the starting and ending offsets for the named match:
diff --git a/doc/packed_data.rdoc b/doc/packed_data.rdoc
deleted file mode 100644
index b33eed58e7..0000000000
--- a/doc/packed_data.rdoc
+++ /dev/null
@@ -1,706 +0,0 @@
-= Packed \Data
-
-== Quick Reference
-
-These tables summarize the directives for packing and unpacking.
-
-=== For Integers
-
- Directive | Meaning
- --------------|---------------------------------------------------------------
- C | 8-bit unsigned (unsigned char)
- S | 16-bit unsigned, native endian (uint16_t)
- L | 32-bit unsigned, native endian (uint32_t)
- Q | 64-bit unsigned, native endian (uint64_t)
- J | pointer width unsigned, native endian (uintptr_t)
-
- c | 8-bit signed (signed char)
- s | 16-bit signed, native endian (int16_t)
- l | 32-bit signed, native endian (int32_t)
- q | 64-bit signed, native endian (int64_t)
- j | pointer width signed, native endian (intptr_t)
-
- S_ S! | unsigned short, native endian
- I I_ I! | unsigned int, native endian
- L_ L! | unsigned long, native endian
- Q_ Q! | unsigned long long, native endian
- | (raises ArgumentError if the platform has no long long type)
- J! | uintptr_t, native endian (same with J)
-
- s_ s! | signed short, native endian
- i i_ i! | signed int, native endian
- l_ l! | signed long, native endian
- q_ q! | signed long long, native endian
- | (raises ArgumentError if the platform has no long long type)
- j! | intptr_t, native endian (same with j)
-
- S> s> S!> s!> | each the same as the directive without >, but big endian
- L> l> L!> l!> | S> is the same as n
- I!> i!> | L> is the same as N
- Q> q> Q!> q!> |
- J> j> J!> j!> |
-
- S< s< S!< s!< | each the same as the directive without <, but little endian
- L< l< L!< l!< | S< is the same as v
- I!< i!< | L< is the same as V
- Q< q< Q!< q!< |
- J< j< J!< j!< |
-
- n | 16-bit unsigned, network (big-endian) byte order
- N | 32-bit unsigned, network (big-endian) byte order
- v | 16-bit unsigned, VAX (little-endian) byte order
- V | 32-bit unsigned, VAX (little-endian) byte order
-
- U | UTF-8 character
- w | BER-compressed integer
-
-=== For Floats
-
- Directive | Meaning
- ----------|--------------------------------------------------
- D d | double-precision, native format
- F f | single-precision, native format
- E | double-precision, little-endian byte order
- e | single-precision, little-endian byte order
- G | double-precision, network (big-endian) byte order
- g | single-precision, network (big-endian) byte order
-
-=== For Strings
-
- Directive | Meaning
- ----------|-----------------------------------------------------------------
- A | arbitrary binary string (remove trailing nulls and ASCII spaces)
- a | arbitrary binary string
- Z | null-terminated string
- B | bit string (MSB first)
- b | bit string (LSB first)
- H | hex string (high nibble first)
- h | hex string (low nibble first)
- u | UU-encoded string
- M | quoted-printable, MIME encoding (see RFC2045)
- m | base64 encoded string (RFC 2045) (default)
- | (base64 encoded string (RFC 4648) if followed by 0)
- P | pointer to a structure (fixed-length string)
- p | pointer to a null-terminated string
-
-=== Additional Directives for Packing
-
- Directive | Meaning
- ----------|----------------------------------------------------------------
- @ | moves to absolute position
- X | back up a byte
- x | null byte
-
-=== Additional Directives for Unpacking
-
- Directive | Meaning
- ----------|----------------------------------------------------------------
- @ | skip to the offset given by the length argument
- X | skip backward one byte
- x | skip forward one byte
-
-== Packing and Unpacking
-
-Certain Ruby core methods deal with packing and unpacking data:
-
-- Method Array#pack:
- Formats each element in array +self+ into a binary string;
- returns that string.
-- Method String#unpack:
- Extracts data from string +self+,
- forming objects that become the elements of a new array;
- returns that array.
-- Method String#unpack1:
- Does the same, but unpacks and returns only the first extracted object.
-
-Each of these methods accepts a string +template+,
-consisting of zero or more _directive_ characters,
-each followed by zero or more _modifier_ characters.
-
-Examples (directive <tt>'C'</tt> specifies 'unsigned character'):
-
- [65].pack('C') # => "A" # One element, one directive.
- [65, 66].pack('CC') # => "AB" # Two elements, two directives.
- [65, 66].pack('C') # => "A" # Extra element is ignored.
- [65].pack('') # => "" # No directives.
- [65].pack('CC') # Extra directive raises ArgumentError.
-
- 'A'.unpack('C') # => [65] # One character, one directive.
- 'AB'.unpack('CC') # => [65, 66] # Two characters, two directives.
- 'AB'.unpack('C') # => [65] # Extra character is ignored.
- 'A'.unpack('CC') # => [65, nil] # Extra directive generates nil.
- 'AB'.unpack('') # => [] # No directives.
-
-The string +template+ may contain any mixture of valid directives
-(directive <tt>'c'</tt> specifies 'signed character'):
-
- [65, -1].pack('cC') # => "A\xFF"
- "A\xFF".unpack('cC') # => [65, 255]
-
-The string +template+ may contain whitespace (which is ignored)
-and comments, each of which begins with character <tt>'#'</tt>
-and continues up to and including the next following newline:
-
- [0,1].pack(" C #foo \n C ") # => "\x00\x01"
- "\0\1".unpack(" C #foo \n C ") # => [0, 1]
-
-Any directive may be followed by either of these modifiers:
-
-- <tt>'*'</tt> - The directive is to be applied as many times as needed:
-
- [65, 66].pack('C*') # => "AB"
- 'AB'.unpack('C*') # => [65, 66]
-
-- Integer +count+ - The directive is to be applied +count+ times:
-
- [65, 66].pack('C2') # => "AB"
- [65, 66].pack('C3') # Raises ArgumentError.
- 'AB'.unpack('C2') # => [65, 66]
- 'AB'.unpack('C3') # => [65, 66, nil]
-
- Note: Directives in <tt>%w[A a Z m]</tt> use +count+ differently;
- see {String Directives}[rdoc-ref:packed_data.rdoc@String+Directives].
-
-If elements don't fit the provided directive, only least significant bits are encoded:
-
- [257].pack("C").unpack("C") # => [1]
-
-== Packing Method
-
-Method Array#pack accepts optional keyword argument
-+buffer+ that specifies the target string (instead of a new string):
-
- [65, 66].pack('C*', buffer: 'foo') # => "fooAB"
-
-The method can accept a block:
-
- # Packed string is passed to the block.
- [65, 66].pack('C*') {|s| p s } # => "AB"
-
-== Unpacking Methods
-
-Methods String#unpack and String#unpack1 each accept
-an optional keyword argument +offset+ that specifies an offset
-into the string:
-
- 'ABC'.unpack('C*', offset: 1) # => [66, 67]
- 'ABC'.unpack1('C*', offset: 1) # => 66
-
-Both methods can accept a block:
-
- # Each unpacked object is passed to the block.
- ret = []
- "ABCD".unpack("C*") {|c| ret << c }
- ret # => [65, 66, 67, 68]
-
- # The single unpacked object is passed to the block.
- 'AB'.unpack1('C*') {|ele| p ele } # => 65
-
-== \Integer Directives
-
-Each integer directive specifies the packing or unpacking
-for one element in the input or output array.
-
-=== 8-Bit \Integer Directives
-
-- <tt>'c'</tt> - 8-bit signed integer
- (like C <tt>signed char</tt>):
-
- [0, 1, 255].pack('c*') # => "\x00\x01\xFF"
- s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
- s.unpack('c*') # => [0, 1, -1]
-
-- <tt>'C'</tt> - 8-bit unsigned 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
-
-- <tt>'s'</tt> - 16-bit signed integer, native-endian
- (like C <tt>int16_t</tt>):
-
- [513, -514].pack('s*') # => "\x01\x02\xFE\xFD"
- s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD"
- s.unpack('s*') # => [513, -514]
-
-- <tt>'S'</tt> - 16-bit unsigned integer, native-endian
- (like C <tt>uint16_t</tt>):
-
- [513, -514].pack('S*') # => "\x01\x02\xFE\xFD"
- s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD"
- s.unpack('S*') # => [513, 65022]
-
-- <tt>'n'</tt> - 16-bit network integer, big-endian:
-
- s = [0, 1, -1, 32767, -32768, 65535].pack('n*')
- # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF"
- s.unpack('n*')
- # => [0, 1, 65535, 32767, 32768, 65535]
-
-- <tt>'v'</tt> - 16-bit VAX integer, little-endian:
-
- s = [0, 1, -1, 32767, -32768, 65535].pack('v*')
- # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF"
- s.unpack('v*')
- # => [0, 1, 65535, 32767, 32768, 65535]
-
-=== 32-Bit \Integer Directives
-
-- <tt>'l'</tt> - 32-bit signed integer, native-endian
- (like C <tt>int32_t</tt>):
-
- s = [67305985, -50462977].pack('l*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('l*')
- # => [67305985, -50462977]
-
-- <tt>'L'</tt> - 32-bit unsigned integer, native-endian
- (like C <tt>uint32_t</tt>):
-
- s = [67305985, 4244504319].pack('L*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('L*')
- # => [67305985, 4244504319]
-
-- <tt>'N'</tt> - 32-bit network integer, big-endian:
-
- s = [0,1,-1].pack('N*')
- # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF"
- s.unpack('N*')
- # => [0, 1, 4294967295]
-
-- <tt>'V'</tt> - 32-bit VAX integer, little-endian:
-
- s = [0,1,-1].pack('V*')
- # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
- s.unpack('v*')
- # => [0, 0, 1, 0, 65535, 65535]
-
-=== 64-Bit \Integer Directives
-
-- <tt>'q'</tt> - 64-bit signed integer, native-endian
- (like C <tt>int64_t</tt>):
-
- s = [578437695752307201, -506097522914230529].pack('q*')
- # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
- s.unpack('q*')
- # => [578437695752307201, -506097522914230529]
-
-- <tt>'Q'</tt> - 64-bit unsigned integer, native-endian
- (like C <tt>uint64_t</tt>):
-
- s = [578437695752307201, 17940646550795321087].pack('Q*')
- # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
- s.unpack('Q*')
- # => [578437695752307201, 17940646550795321087]
-
-=== Platform-Dependent \Integer Directives
-
-- <tt>'i'</tt> - Platform-dependent width signed integer,
- native-endian (like C <tt>int</tt>):
-
- s = [67305985, -50462977].pack('i*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('i*')
- # => [67305985, -50462977]
-
-- <tt>'I'</tt> - Platform-dependent width unsigned integer,
- native-endian (like C <tt>unsigned int</tt>):
-
- s = [67305985, -50462977].pack('I*')
- # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
- s.unpack('I*')
- # => [67305985, 4244504319]
-
-- <tt>'j'</tt> - 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>):
-
- 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
-
-- <tt>'U'</tt> - UTF-8 character:
-
- s = [4194304].pack('U*')
- # => "\xF8\x90\x80\x80\x80"
- s.unpack('U*')
- # => [4194304]
-
-- <tt>'w'</tt> - BER-encoded integer
- (see {BER encoding}[https://en.wikipedia.org/wiki/X.690#BER_encoding]):
-
- s = [1073741823].pack('w*')
- # => "\x83\xFF\xFF\xFF\x7F"
- 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:
-
-- <tt>'>'</tt> - Big-endian.
-- <tt>'<'</tt> - Little-endian.
-
-== \Float Directives
-
-Each float directive specifies the packing or unpacking
-for one element in the input or output array.
-
-=== Single-Precision \Float Directives
-
-- <tt>'F'</tt> or <tt>'f'</tt> - Native format:
-
- s = [3.0].pack('F') # => "\x00\x00@@"
- s.unpack('F') # => [3.0]
-
-- <tt>'e'</tt> - Little-endian:
-
- s = [3.0].pack('e') # => "\x00\x00@@"
- s.unpack('e') # => [3.0]
-
-- <tt>'g'</tt> - Big-endian:
-
- s = [3.0].pack('g') # => "@@\x00\x00"
- s.unpack('g') # => [3.0]
-
-=== Double-Precision \Float Directives
-
-- <tt>'D'</tt> or <tt>'d'</tt> - Native format:
-
- s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@"
- s.unpack('D') # => [3.0]
-
-- <tt>'E'</tt> - Little-endian:
-
- s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@"
- s.unpack('E') # => [3.0]
-
-- <tt>'G'</tt> - Big-endian:
-
- s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00"
- s.unpack('G') # => [3.0]
-
-A float directive may be infinity or not-a-number:
-
- inf = 1.0/0.0 # => Infinity
- [inf].pack('f') # => "\x00\x00\x80\x7F"
- "\x00\x00\x80\x7F".unpack('f') # => [Infinity]
-
- nan = inf/inf # => NaN
- [nan].pack('f') # => "\x00\x00\xC0\x7F"
- "\x00\x00\xC0\x7F".unpack('f') # => [NaN]
-
-== \String Directives
-
-Each string directive specifies the packing or unpacking
-for one byte in the input or output string.
-
-=== Binary \String Directives
-
-- <tt>'A'</tt> - Arbitrary binary string (space padded; count is width);
- +nil+ is treated as the empty string:
-
- ['foo'].pack('A') # => "f"
- ['foo'].pack('A*') # => "foo"
- ['foo'].pack('A2') # => "fo"
- ['foo'].pack('A4') # => "foo "
- [nil].pack('A') # => " "
- [nil].pack('A*') # => ""
- [nil].pack('A2') # => " "
- [nil].pack('A4') # => " "
-
- "foo\0".unpack('A') # => ["f"]
- "foo\0".unpack('A4') # => ["foo"]
- "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0".
- "foo ".unpack('A') # => ["f"]
- "foo ".unpack('A4') # => ["foo"]
- "foo".unpack('A4') # => ["foo"]
-
- russian = "\u{442 435 441 442}" # => "тест"
- russian.size # => 4
- russian.bytesize # => 8
- [russian].pack('A') # => "\xD1"
- [russian].pack('A*') # => "\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"
- russian.unpack('A') # => ["\xD1"]
- russian.unpack('A2') # => ["\xD1\x82"]
- russian.unpack('A4') # => ["\xD1\x82\xD0\xB5"]
- russian.unpack('A*') # => ["\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"]
-
-- <tt>'a'</tt> - Arbitrary binary string (null padded; count is width):
-
- ["foo"].pack('a') # => "f"
- ["foo"].pack('a*') # => "foo"
- ["foo"].pack('a2') # => "fo"
- ["foo\0"].pack('a4') # => "foo\x00"
- [nil].pack('a') # => "\x00"
- [nil].pack('a*') # => ""
- [nil].pack('a2') # => "\x00\x00"
- [nil].pack('a4') # => "\x00\x00\x00\x00"
-
- "foo\0".unpack('a') # => ["f"]
- "foo\0".unpack('a4') # => ["foo\x00"]
- "foo ".unpack('a4') # => ["foo "]
- "foo".unpack('a4') # => ["foo"]
- "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0".
-
-- <tt>'Z'</tt> - Same as <tt>'a'</tt>,
- except that null is added or ignored with <tt>'*'</tt>:
-
- ["foo"].pack('Z*') # => "foo\x00"
- [nil].pack('Z*') # => "\x00"
-
- "foo\0".unpack('Z*') # => ["foo"]
- "foo".unpack('Z*') # => ["foo"]
- "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
-
-=== Bit \String Directives
-
-- <tt>'B'</tt> - Bit string (high byte first):
-
- ['11111111' + '00000000'].pack('B*') # => "\xFF\x00"
- ['10000000' + '01000000'].pack('B*') # => "\x80@"
-
- ['1'].pack('B0') # => ""
- ['1'].pack('B1') # => "\x80"
- ['1'].pack('B2') # => "\x80\x00"
- ['1'].pack('B3') # => "\x80\x00"
- ['1'].pack('B4') # => "\x80\x00\x00"
- ['1'].pack('B5') # => "\x80\x00\x00"
- ['1'].pack('B6') # => "\x80\x00\x00\x00"
-
- "\xff\x00".unpack("B*") # => ["1111111100000000"]
- "\x01\x02".unpack("B*") # => ["0000000100000010"]
-
- "".unpack("B0") # => [""]
- "\x80".unpack("B1") # => ["1"]
- "\x80".unpack("B2") # => ["10"]
- "\x80".unpack("B3") # => ["100"]
-
-- <tt>'b'</tt> - Bit string (low byte first):
-
- ['11111111' + '00000000'].pack('b*') # => "\xFF\x00"
- ['10000000' + '01000000'].pack('b*') # => "\x01\x02"
-
- ['1'].pack('b0') # => ""
- ['1'].pack('b1') # => "\x01"
- ['1'].pack('b2') # => "\x01\x00"
- ['1'].pack('b3') # => "\x01\x00"
- ['1'].pack('b4') # => "\x01\x00\x00"
- ['1'].pack('b5') # => "\x01\x00\x00"
- ['1'].pack('b6') # => "\x01\x00\x00\x00"
-
- "\xff\x00".unpack("b*") # => ["1111111100000000"]
- "\x01\x02".unpack("b*") # => ["1000000001000000"]
-
- "".unpack("b0") # => [""]
- "\x01".unpack("b1") # => ["1"]
- "\x01".unpack("b2") # => ["10"]
- "\x01".unpack("b3") # => ["100"]
-
-=== Hex \String Directives
-
-- <tt>'H'</tt> - Hex string (high nibble first):
-
- ['10ef'].pack('H*') # => "\x10\xEF"
- ['10ef'].pack('H0') # => ""
- ['10ef'].pack('H3') # => "\x10\xE0"
- ['10ef'].pack('H5') # => "\x10\xEF\x00"
-
- ['fff'].pack('H3') # => "\xFF\xF0"
- ['fff'].pack('H4') # => "\xFF\xF0"
- ['fff'].pack('H5') # => "\xFF\xF0\x00"
- ['fff'].pack('H6') # => "\xFF\xF0\x00"
- ['fff'].pack('H7') # => "\xFF\xF0\x00\x00"
- ['fff'].pack('H8') # => "\xFF\xF0\x00\x00"
-
- "\x10\xef".unpack('H*') # => ["10ef"]
- "\x10\xef".unpack('H0') # => [""]
- "\x10\xef".unpack('H1') # => ["1"]
- "\x10\xef".unpack('H2') # => ["10"]
- "\x10\xef".unpack('H3') # => ["10e"]
- "\x10\xef".unpack('H4') # => ["10ef"]
- "\x10\xef".unpack('H5') # => ["10ef"]
-
-- <tt>'h'</tt> - Hex string (low nibble first):
-
- ['10ef'].pack('h*') # => "\x01\xFE"
- ['10ef'].pack('h0') # => ""
- ['10ef'].pack('h3') # => "\x01\x0E"
- ['10ef'].pack('h5') # => "\x01\xFE\x00"
-
- ['fff'].pack('h3') # => "\xFF\x0F"
- ['fff'].pack('h4') # => "\xFF\x0F"
- ['fff'].pack('h5') # => "\xFF\x0F\x00"
- ['fff'].pack('h6') # => "\xFF\x0F\x00"
- ['fff'].pack('h7') # => "\xFF\x0F\x00\x00"
- ['fff'].pack('h8') # => "\xFF\x0F\x00\x00"
-
- "\x01\xfe".unpack('h*') # => ["10ef"]
- "\x01\xfe".unpack('h0') # => [""]
- "\x01\xfe".unpack('h1') # => ["1"]
- "\x01\xfe".unpack('h2') # => ["10"]
- "\x01\xfe".unpack('h3') # => ["10e"]
- "\x01\xfe".unpack('h4') # => ["10ef"]
- "\x01\xfe".unpack('h5') # => ["10ef"]
-
-=== Pointer \String Directives
-
-- <tt>'P'</tt> - Pointer to a structure (fixed-length string):
-
- s = ['abc'].pack('P') # => "\xE0O\x7F\xE5\xA1\x01\x00\x00"
- s.unpack('P*') # => ["abc"]
- ".".unpack("P") # => []
- ("\0" * 8).unpack("P") # => [nil]
- [nil].pack("P") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
-- <tt>'p'</tt> - Pointer to a null-terminated string:
-
- s = ['abc'].pack('p') # => "(\xE4u\xE5\xA1\x01\x00\x00"
- s.unpack('p*') # => ["abc"]
- ".".unpack("p") # => []
- ("\0" * 8).unpack("p") # => [nil]
- [nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
-=== Other \String Directives
-
-- <tt>'M'</tt> - Quoted printable, MIME encoding;
- text mode, but input must use LF and output LF;
- (see {RFC 2045}[https://www.ietf.org/rfc/rfc2045.txt]):
-
- ["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n"
- ["\0"].pack('M') # => "=00=\n"
-
- ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n" # => true
- ("a"*73+"=\na=\n").unpack('M') == ["a"*74] # => true
- (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true
-
- "a b c\td =\n\ne=\n".unpack('M') # => ["a b c\td \ne"]
- "=00=\n".unpack('M') # => ["\x00"]
-
- "pre=31=32=33after".unpack('M') # => ["pre123after"]
- "pre=\nafter".unpack('M') # => ["preafter"]
- "pre=\r\nafter".unpack('M') # => ["preafter"]
- "pre=".unpack('M') # => ["pre="]
- "pre=\r".unpack('M') # => ["pre=\r"]
- "pre=hoge".unpack('M') # => ["pre=hoge"]
- "pre==31after".unpack('M') # => ["pre==31after"]
- "pre===31after".unpack('M') # => ["pre===31after"]
-
-- <tt>'m'</tt> - Base64 encoded string;
- count specifies input bytes between each newline,
- rounded down to nearest multiple of 3;
- if count is zero, no newlines are added;
- (see {RFC 4648}[https://www.ietf.org/rfc/rfc4648.txt]):
-
- [""].pack('m') # => ""
- ["\0"].pack('m') # => "AA==\n"
- ["\0\0"].pack('m') # => "AAA=\n"
- ["\0\0\0"].pack('m') # => "AAAA\n"
- ["\377"].pack('m') # => "/w==\n"
- ["\377\377"].pack('m') # => "//8=\n"
- ["\377\377\377"].pack('m') # => "////\n"
-
- "".unpack('m') # => [""]
- "AA==\n".unpack('m') # => ["\x00"]
- "AAA=\n".unpack('m') # => ["\x00\x00"]
- "AAAA\n".unpack('m') # => ["\x00\x00\x00"]
- "/w==\n".unpack('m') # => ["\xFF"]
- "//8=\n".unpack('m') # => ["\xFF\xFF"]
- "////\n".unpack('m') # => ["\xFF\xFF\xFF"]
- "A\n".unpack('m') # => [""]
- "AA\n".unpack('m') # => ["\x00"]
- "AA=\n".unpack('m') # => ["\x00"]
- "AAA\n".unpack('m') # => ["\x00\x00"]
-
- [""].pack('m0') # => ""
- ["\0"].pack('m0') # => "AA=="
- ["\0\0"].pack('m0') # => "AAA="
- ["\0\0\0"].pack('m0') # => "AAAA"
- ["\377"].pack('m0') # => "/w=="
- ["\377\377"].pack('m0') # => "//8="
- ["\377\377\377"].pack('m0') # => "////"
-
- "".unpack('m0') # => [""]
- "AA==".unpack('m0') # => ["\x00"]
- "AAA=".unpack('m0') # => ["\x00\x00"]
- "AAAA".unpack('m0') # => ["\x00\x00\x00"]
- "/w==".unpack('m0') # => ["\xFF"]
- "//8=".unpack('m0') # => ["\xFF\xFF"]
- "////".unpack('m0') # => ["\xFF\xFF\xFF"]
-
-- <tt>'u'</tt> - UU-encoded string:
-
- [""].pack("u") # => ""
- ["a"].pack("u") # => "!80``\n"
- ["aaa"].pack("u") # => "#86%A\n"
-
- "".unpack("u") # => [""]
- "#86)C\n".unpack("u") # => ["abc"]
-
-== Offset Directives
-
-- <tt>'@'</tt> - Begin packing at the given byte offset;
- for packing, null fill or shrink if necessary:
-
- [1, 2].pack("C@0C") # => "\x02"
- [1, 2].pack("C@1C") # => "\x01\x02"
- [1, 2].pack("C@5C") # => "\x01\x00\x00\x00\x00\x02"
- [*1..5].pack("CCCC@2C") # => "\x01\x02\x05"
-
- For unpacking, cannot to move to outside the string:
-
- "\x01\x00\x00\x02".unpack("C@3C") # => [1, 2]
- "\x00".unpack("@1C") # => [nil]
- "\x00".unpack("@2C") # Raises ArgumentError.
-
-- <tt>'X'</tt> - For packing, shrink for the given byte offset:
-
- [0, 1, 2].pack("CCXC") # => "\x00\x02"
- [0, 1, 2].pack("CCX2C") # => "\x02"
-
- For unpacking; rewind unpacking position for the given byte offset:
-
- "\x00\x02".unpack("CCXC") # => [0, 2, 2]
-
- Cannot to move to outside the string:
-
- [0, 1, 2].pack("CCX3C") # Raises ArgumentError.
- "\x00\x02".unpack("CX3C") # Raises ArgumentError.
-
-- <tt>'x'</tt> - Begin packing at after the given byte offset;
- for packing, null fill if necessary:
-
- [].pack("x0") # => ""
- [].pack("x") # => "\x00"
- [].pack("x8") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
- For unpacking, cannot to move to outside the string:
-
- "\x00\x00\x02".unpack("CxC") # => [0, 2]
- "\x00\x00\x02".unpack("x3C") # => [nil]
- "\x00\x00\x02".unpack("x4C") # Raises ArgumentError
diff --git a/doc/ractor.md b/doc/ractor.md
deleted file mode 100644
index 6a1cff4e7b..0000000000
--- a/doc/ractor.md
+++ /dev/null
@@ -1,951 +0,0 @@
-# Ractor - Ruby's Actor-like concurrent abstraction
-
-Ractor is designed to provide a parallel execution feature of Ruby without thread-safety concerns.
-
-## Summary
-
-### Multiple Ractors in an interpreter process
-
-You can make multiple Ractors and they run in parallel.
-
-* `Ractor.new{ expr }` creates a new Ractor and `expr` is run in parallel on a parallel computer.
-* Interpreter invokes with the first Ractor (called *main Ractor*).
-* If main Ractor terminated, all Ractors receive terminate request like Threads (if main thread (first invoked Thread), Ruby interpreter sends all running threads to terminate execution).
-* Each Ractor has 1 or more Threads.
- * Threads in a Ractor shares a Ractor-wide global lock like GIL (GVL in MRI terminology), so they can't run in parallel (without releasing GVL explicitly in C-level). Threads in different ractors run in parallel.
- * The overhead of creating a Ractor is similar to overhead of one Thread creation.
-
-### Limited sharing between multiple ractors
-
-Ractors don't share everything, unlike threads.
-
-* Most objects are *Unshareable objects*, so you don't need to care about thread-safety problems which are caused by sharing.
-* Some objects are *Shareable objects*.
- * Immutable objects: frozen objects which don't refer to unshareable-objects.
- * `i = 123`: `i` is an immutable object.
- * `s = "str".freeze`: `s` is an immutable object.
- * `a = [1, [2], 3].freeze`: `a` is not an immutable object because `a` refers unshareable-object `[2]` (which is not frozen).
- * `h = {c: Object}.freeze`: `h` is an immutable object because `h` refers Symbol `:c` and shareable `Object` class object which is not frozen.
- * Class/Module objects
- * Special shareable objects
- * Ractor object itself.
- * And more...
-
-### Two-types communication between Ractors
-
-Ractors communicate with each other and synchronize the execution by message exchanging between Ractors. There are two message exchange protocols: push type (message passing) and pull type.
-
-* Push type message passing: `Ractor#send(obj)` and `Ractor.receive()` pair.
- * Sender ractor passes the `obj` to the ractor `r` by `r.send(obj)` and receiver ractor receives the message with `Ractor.receive`.
- * Sender knows the destination Ractor `r` and the receiver does not know the sender (accept all messages from any ractors).
- * Receiver has infinite queue and sender enqueues the message. Sender doesn't block to put message into this queue.
- * This type of message exchanging is employed by many other Actor-based languages.
- * `Ractor.receive_if{ filter_expr }` is a variant of `Ractor.receive` to select a message.
-* Pull type communication: `Ractor.yield(obj)` and `Ractor#take()` pair.
- * Sender ractor declare to yield the `obj` by `Ractor.yield(obj)` and receiver Ractor take it with `r.take`.
- * Sender doesn't know a destination Ractor and receiver knows the sender Ractor `r`.
- * Sender or receiver will block if there is no other side.
-
-### Copy & Move semantics to send messages
-
-To send unshareable objects as messages, objects are copied or moved.
-
-* Copy: use deep-copy.
-* Move: move membership.
- * Sender can not access the moved object after moving the object.
- * Guarantee that at least only 1 Ractor can access the object.
-
-### Thread-safety
-
-Ractor helps to write a thread-safe concurrent program, but we can make thread-unsafe programs with Ractors.
-
-* GOOD: Sharing limitation
- * Most objects are unshareable, so we can't make data-racy and race-conditional programs.
- * Shareable objects are protected by an interpreter or locking mechanism.
-* BAD: Class/Module can violate this assumption
- * To make it compatible with old behavior, classes and modules can introduce data-race and so on.
- * Ruby programmers should take care if they modify class/module objects on multi Ractor programs.
-* BAD: Ractor can't solve all thread-safety problems
- * There are several blocking operations (waiting send, waiting yield and waiting take) so you can make a program which has dead-lock and live-lock issues.
- * Some kind of shareable objects can introduce transactions (STM, for example). However, misusing transactions will generate inconsistent state.
-
-Without Ractor, we need to trace all state-mutations to debug thread-safety issues.
-With Ractor, you can concentrate on suspicious code which are shared with Ractors.
-
-## Creation and termination
-
-### `Ractor.new`
-
-* `Ractor.new{ expr }` generates another Ractor.
-
-```ruby
-# Ractor.new with a block creates new Ractor
-r = Ractor.new do
- # This block will be run in parallel with other ractors
-end
-
-# You can name a Ractor with `name:` argument.
-r = Ractor.new name: 'test-name' do
-end
-
-# and Ractor#name returns its name.
-r.name #=> 'test-name'
-```
-
-### Given block isolation
-
-The Ractor executes given `expr` in a given block.
-Given block will be isolated from outer scope by the `Proc#isolate` method (not exposed yet for Ruby users). To prevent sharing unshareable objects between ractors, block outer-variables, `self` and other information are isolated.
-
-`Proc#isolate` is called at Ractor creation time (when `Ractor.new` is called). If given Proc object is not able to isolate because of outer variables and so on, an error will be raised.
-
-```ruby
-begin
- a = true
- r = Ractor.new do
- a #=> ArgumentError because this block accesses `a`.
- end
- r.take # see later
-rescue ArgumentError
-end
-```
-
-* The `self` of the given block is the `Ractor` object itself.
-
-```ruby
-r = Ractor.new do
- p self.class #=> Ractor
- self.object_id
-end
-r.take == self.object_id #=> false
-```
-
-Passed arguments to `Ractor.new()` becomes block parameters for the given block. However, an interpreter does not pass the parameter object references, but send them as messages (see below for details).
-
-```ruby
-r = Ractor.new 'ok' do |msg|
- msg #=> 'ok'
-end
-r.take #=> 'ok'
-```
-
-```ruby
-# almost similar to the last example
-r = Ractor.new do
- msg = Ractor.receive
- msg
-end
-r.send 'ok'
-r.take #=> 'ok'
-```
-
-### An execution result of given block
-
-Return value of the given block becomes an outgoing message (see below for details).
-
-```ruby
-r = Ractor.new do
- 'ok'
-end
-r.take #=> `ok`
-```
-
-```ruby
-# almost similar to the last example
-r = Ractor.new do
- Ractor.yield 'ok'
-end
-r.take #=> 'ok'
-```
-
-Error in the given block will be propagated to the receiver of an outgoing message.
-
-```ruby
-r = Ractor.new do
- raise 'ok' # exception will be transferred to the receiver
-end
-
-begin
- r.take
-rescue Ractor::RemoteError => e
- e.cause.class #=> RuntimeError
- e.cause.message #=> 'ok'
- e.ractor #=> r
-end
-```
-
-## Communication between Ractors
-
-Communication between Ractors is achieved by sending and receiving messages. There are two ways to communicate with each other.
-
-* (1) Message sending/receiving
- * (1-1) push type send/receive (sender knows receiver). Similar to the Actor model.
- * (1-2) pull type yield/take (receiver knows sender).
-* (2) Using shareable container objects
- * Ractor::TVar gem ([ko1/ractor-tvar](https://github.com/ko1/ractor-tvar))
- * more?
-
-Users can control program execution timing with (1), but should not control with (2) (only manage as critical section).
-
-For message sending and receiving, there are two types of APIs: push type and pull type.
-
-* (1-1) send/receive (push type)
- * `Ractor#send(obj)` (`Ractor#<<(obj)` is an alias) send a message to the Ractor's incoming port. Incoming port is connected to the infinite size incoming queue so `Ractor#send` will never block.
- * `Ractor.receive` dequeue a message from its own incoming queue. If the incoming queue is empty, `Ractor.receive` calling will block.
- * `Ractor.receive_if{|msg| filter_expr }` is variant of `Ractor.receive`. `receive_if` only receives a message which `filter_expr` is true (So `Ractor.receive` is the same as `Ractor.receive_if{ true }`.
-* (1-2) yield/take (pull type)
- * `Ractor.yield(obj)` send an message to a Ractor which are calling `Ractor#take` via outgoing port . If no Ractors are waiting for it, the `Ractor.yield(obj)` will block. If multiple Ractors are waiting for `Ractor.yield(obj)`, only one Ractor can receive the message.
- * `Ractor#take` receives a message which is waiting by `Ractor.yield(obj)` method from the specified Ractor. If the Ractor does not call `Ractor.yield` yet, the `Ractor#take` call will block.
-* `Ractor.select()` can wait for the success of `take`, `yield` and `receive`.
-* You can close the incoming port or outgoing port.
- * You can close then with `Ractor#close_incoming` and `Ractor#close_outgoing`.
- * If the incoming port is closed for a Ractor, you can't `send` to the Ractor. If `Ractor.receive` is blocked for the closed incoming port, then it will raise an exception.
- * If the outgoing port is closed for a Ractor, you can't call `Ractor#take` and `Ractor.yield` on the Ractor. If ractors are blocking by `Ractor#take` or `Ractor.yield`, closing outgoing port will raise an exception on these blocking ractors.
- * When a Ractor is terminated, the Ractor's ports are closed.
-* There are 3 ways to send an object as a message
- * (1) Send a reference: Sending a shareable object, send only a reference to the object (fast)
- * (2) Copy an object: Sending an unshareable object by copying an object deeply (slow). Note that you can not send an object which does not support deep copy. Some `T_DATA` objects (objects whose class is defined in a C extension, such as `StringIO`) are not supported.
- * (3) Move an object: Sending an unshareable object reference with a membership. Sender Ractor can not access moved objects anymore (raise an exception) after moving it. Current implementation makes new object as a moved object for receiver Ractor and copies references of sending object to moved object. `T_DATA` objects are not supported.
- * You can choose "Copy" and "Move" by the `move:` keyword, `Ractor#send(obj, move: true/false)` and `Ractor.yield(obj, move: true/false)` (default is `false` (COPY)).
-
-### Sending/Receiving ports
-
-Each Ractor has _incoming-port_ and _outgoing-port_. Incoming-port is connected to the infinite sized incoming queue.
-
-```
- Ractor r
- +-------------------------------------------+
- | incoming outgoing |
- | port port |
- r.send(obj) ->*->[incoming queue] Ractor.yield(obj) ->*-> r.take
- | | |
- | v |
- | Ractor.receive |
- +-------------------------------------------+
-
-
-Connection example: r2.send obj on r1、Ractor.receive on r2
- +----+ +----+
- * r1 |---->* r2 *
- +----+ +----+
-
-
-Connection example: Ractor.yield(obj) on r1, r1.take on r2
- +----+ +----+
- * r1 *---->- r2 *
- +----+ +----+
-
-Connection example: Ractor.yield(obj) on r1 and r2,
- and waiting for both simultaneously by Ractor.select(r1, r2)
-
- +----+
- * r1 *------+
- +----+ |
- +----> Ractor.select(r1, r2)
- +----+ |
- * r2 *------|
- +----+
-```
-
-```ruby
-r = Ractor.new do
- msg = Ractor.receive # Receive from r's incoming queue
- msg # send back msg as block return value
-end
-r.send 'ok' # Send 'ok' to r's incoming port -> incoming queue
-r.take # Receive from r's outgoing port
-```
-
-The last example shows the following ractor network.
-
-```
- +------+ +---+
- * main |------> * r *---+
- +------+ +---+ |
- ^ |
- +-------------------+
-```
-
-And this code can be simplified by using an argument for `Ractor.new`.
-
-```ruby
-# Actual argument 'ok' for `Ractor.new()` will be sent to created Ractor.
-r = Ractor.new 'ok' do |msg|
- # Values for formal parameters will be received from incoming queue.
- # Similar to: msg = Ractor.receive
-
- msg # Return value of the given block will be sent via outgoing port
-end
-
-# receive from the r's outgoing port.
-r.take #=> `ok`
-```
-
-### Return value of a block for `Ractor.new`
-
-As already explained, the return value of `Ractor.new` (an evaluated value of `expr` in `Ractor.new{ expr }`) can be taken by `Ractor#take`.
-
-```ruby
-Ractor.new{ 42 }.take #=> 42
-```
-
-When the block return value is available, the Ractor is dead so that no ractors except taken Ractor can touch the return value, so any values can be sent with this communication path without any modification.
-
-```ruby
-r = Ractor.new do
- a = "hello"
- binding
-end
-
-r.take.eval("p a") #=> "hello" (other communication path can not send a Binding object directly)
-```
-
-### Wait for multiple Ractors with `Ractor.select`
-
-You can wait multiple Ractor's `yield` with `Ractor.select(*ractors)`.
-The return value of `Ractor.select()` is `[r, msg]` where `r` is yielding Ractor and `msg` is yielded message.
-
-Wait for a single ractor (same as `Ractor.take`):
-
-```ruby
-r1 = Ractor.new{'r1'}
-
-r, obj = Ractor.select(r1)
-r == r1 and obj == 'r1' #=> true
-```
-
-Wait for two ractors:
-
-```ruby
-r1 = Ractor.new{'r1'}
-r2 = Ractor.new{'r2'}
-rs = [r1, r2]
-as = []
-
-# Wait for r1 or r2's Ractor.yield
-r, obj = Ractor.select(*rs)
-rs.delete(r)
-as << obj
-
-# Second try (rs only contain not-closed ractors)
-r, obj = Ractor.select(*rs)
-rs.delete(r)
-as << obj
-as.sort == ['r1', 'r2'] #=> true
-```
-
-\Complex example:
-
-```ruby
-pipe = Ractor.new do
- loop do
- Ractor.yield Ractor.receive
- end
-end
-
-RN = 10
-rs = RN.times.map{|i|
- Ractor.new pipe, i do |pipe, i|
- msg = pipe.take
- msg # ping-pong
- end
-}
-RN.times{|i|
- pipe << i
-}
-RN.times.map{
- r, n = Ractor.select(*rs)
- rs.delete r
- n
-}.sort #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-```
-
-Multiple Ractors can send to one Ractor.
-
-```ruby
-# Create 10 ractors and they send objects to pipe ractor.
-# pipe ractor yield received objects
-
-pipe = Ractor.new do
- loop do
- Ractor.yield Ractor.receive
- end
-end
-
-RN = 10
-rs = RN.times.map{|i|
- Ractor.new pipe, i do |pipe, i|
- pipe << i
- end
-}
-
-RN.times.map{
- pipe.take
-}.sort #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-```
-
-TODO: Current `Ractor.select()` has the same issue of `select(2)`, so this interface should be refined.
-
-TODO: `select` syntax of go-language uses round-robin technique to make fair scheduling. Now `Ractor.select()` doesn't use it.
-
-### Closing Ractor's ports
-
-* `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.
- * 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.
- * `Ractor#take` for a Ractor which closed the outgoing port, it will raise an exception. If `Ractor#take` is blocking, it will raise an exception.
-* When a Ractor terminates, the ports are closed automatically.
- * Return value of the Ractor's block will be yielded as `Ractor.yield(ret_val)`, even if the implementation terminates the based native thread.
-
-Example (try to take from closed Ractor):
-
-```ruby
-r = Ractor.new do
- 'finish'
-end
-r.take # success (will return 'finish')
-begin
- o = r.take # try to take from closed Ractor
-rescue Ractor::ClosedError
- 'ok'
-else
- "ng: #{o}"
-end
-```
-
-Example (try to send to closed (terminated) Ractor):
-
-```ruby
-r = Ractor.new do
-end
-
-r.take # wait terminate
-
-begin
- r.send(1)
-rescue Ractor::ClosedError
- 'ok'
-else
- 'ng'
-end
-```
-
-When multiple Ractors are waiting for `Ractor.yield()`, `Ractor#close_outgoing` will cancel all blocking by raising an exception (`ClosedError`).
-
-### Send a message by copying
-
-`Ractor#send(obj)` or `Ractor.yield(obj)` copy `obj` deeply if `obj` is an unshareable object.
-
-```ruby
-obj = 'str'.dup
-r = Ractor.new obj do |msg|
- # return received msg's object_id
- msg.object_id
-end
-
-obj.object_id == r.take #=> false
-```
-
-Some objects are not supported to copy the value, and raise an exception.
-
-```ruby
-obj = Thread.new{}
-begin
- Ractor.new obj do |msg|
- msg
- end
-rescue TypeError => e
- e.message #=> #<TypeError: allocator undefined for Thread>
-else
- 'ng' # unreachable here
-end
-```
-
-### Send a message by moving
-
-`Ractor#send(obj, move: true)` or `Ractor.yield(obj, move: true)` move `obj` to the destination Ractor.
-If the source Ractor touches the moved object (for example, call the method like `obj.foo()`), it will be an error.
-
-```ruby
-# move with Ractor#send
-r = Ractor.new do
- obj = Ractor.receive
- obj << ' world'
-end
-
-str = 'hello'
-r.send str, move: true
-modified = r.take #=> 'hello world'
-
-# str is moved, and accessing str from this Ractor is prohibited
-
-begin
- # Error because it touches moved str.
- str << ' exception' # raise Ractor::MovedError
-rescue Ractor::MovedError
- modified #=> 'hello world'
-else
- raise 'unreachable'
-end
-```
-
-```ruby
-# move with Ractor.yield
-r = Ractor.new do
- obj = 'hello'
- Ractor.yield obj, move: true
- obj << 'world' # raise Ractor::MovedError
-end
-
-str = r.take
-begin
- r.take
-rescue Ractor::RemoteError
- p str #=> "hello"
-end
-```
-
-Some objects are not supported to move, and an exception will be raised.
-
-```ruby
-r = Ractor.new do
- Ractor.receive
-end
-
-r.send(Thread.new{}, move: true) #=> allocator undefined for Thread (TypeError)
-```
-
-To achieve the access prohibition for moved objects, _class replacement_ technique is used to implement it.
-
-### Shareable objects
-
-The following objects are shareable.
-
-* Immutable objects
- * Small integers, some symbols, `true`, `false`, `nil` (a.k.a. `SPECIAL_CONST_P()` objects in internal)
- * Frozen native objects
- * Numeric objects: `Float`, `Complex`, `Rational`, big integers (`T_BIGNUM` in internal)
- * All Symbols.
- * Frozen `String` and `Regexp` objects (their instance variables should refer only shareable objects)
-* Class, Module objects (`T_CLASS`, `T_MODULE` and `T_ICLASS` in internal)
-* `Ractor` and other special objects which care about synchronization.
-
-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.
-
-## Language changes to isolate unshareable objects between Ractors
-
-To isolate unshareable objects between Ractors, we introduced additional language semantics on multi-Ractor Ruby programs.
-
-Note that without using Ractors, these additional semantics is not needed (100% compatible with Ruby 2).
-
-### Global variables
-
-Only the main Ractor (a Ractor created at starting of interpreter) can access global variables.
-
-```ruby
-$gv = 1
-r = Ractor.new do
- $gv
-end
-
-begin
- r.take
-rescue Ractor::RemoteError => e
- e.cause.message #=> 'can not access global variables from non-main Ractors'
-end
-```
-
-Note that some special global variables are ractor-local, like `$stdin`, `$stdout`, `$stderr`. See [[Bug #17268]](https://bugs.ruby-lang.org/issues/17268) for more details.
-
-### Instance variables of shareable objects
-
-Instance variables of classes/modules can be get from non-main Ractors if the referring values are shareable objects.
-
-```ruby
-class C
- @iv = 1
-end
-
-p Ractor.new do
- class C
- @iv
- end
-end.take #=> 1
-```
-
-Otherwise, only the main Ractor can access instance variables of shareable objects.
-
-```ruby
-class C
- @iv = [] # unshareable object
-end
-
-Ractor.new do
- class C
- begin
- p @iv
- rescue Ractor::IsolationError
- p $!.message
- #=> "can not get unshareable values from instance variables of classes/modules from non-main Ractors"
- end
-
- begin
- @iv = 42
- rescue Ractor::IsolationError
- p $!.message
- #=> "can not set instance variables of classes/modules by non-main Ractors"
- end
- end
-end.take
-```
-
-
-
-```ruby
-shared = Ractor.new{}
-shared.instance_variable_set(:@iv, 'str')
-
-r = Ractor.new shared do |shared|
- p shared.instance_variable_get(:@iv)
-end
-
-begin
- r.take
-rescue Ractor::RemoteError => e
- e.cause.message #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError)
-end
-```
-
-Note that instance variables for class/module objects are also prohibited on Ractors.
-
-### Class variables
-
-Only the main Ractor can access class variables.
-
-```ruby
-class C
- @@cv = 'str'
-end
-
-r = Ractor.new do
- class C
- p @@cv
- end
-end
-
-
-begin
- r.take
-rescue => e
- e.class #=> Ractor::IsolationError
-end
-```
-
-### Constants
-
-Only the main Ractor can read constants which refer to the unshareable object.
-
-```ruby
-class C
- CONST = 'str'
-end
-r = Ractor.new do
- C::CONST
-end
-begin
- r.take
-rescue => e
- e.class #=> Ractor::IsolationError
-end
-```
-
-Only the main Ractor can define constants which refer to the unshareable object.
-
-```ruby
-class C
-end
-r = Ractor.new do
- C::CONST = 'str'
-end
-begin
- r.take
-rescue => e
- e.class #=> Ractor::IsolationError
-end
-```
-
-To make multi-ractor supported library, the constants should only refer shareable objects.
-
-```ruby
-TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
-```
-
-In this case, `TABLE` references an unshareable Hash object. So that other ractors can not refer `TABLE` constant. To make it shareable, we can use `Ractor.make_shareable()` like that.
-
-```ruby
-TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
-```
-
-To make it easy, Ruby 3.0 introduced new `shareable_constant_value` Directive.
-
-```ruby
-# shareable_constant_value: literal
-
-TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
-#=> Same as: TABLE = Ractor.make_shareable( {a: 'ko1', b: 'ko2', c: 'ko3'} )
-```
-
-`shareable_constant_value` directive accepts the following modes (descriptions use the example: `CONST = expr`):
-
-* 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)}`.
-* experimental_everything: replaced to `CONST = Ractor.make_shareable(expr)`.
-* experimental_copy: replaced to `CONST = Ractor.make_shareable(expr, copy: true)`.
-
-Except the `none` mode (default), it is guaranteed that the assigned constants refer to only shareable objects.
-
-See [doc/syntax/comments.rdoc](syntax/comments.rdoc) for more details.
-
-## Implementation note
-
-* Each Ractor has its own thread, it means each Ractor has at least 1 native thread.
-* Each Ractor has its own ID (`rb_ractor_t::pub::id`).
- * On debug mode, all unshareable objects are labeled with current Ractor's id, and it is checked to detect unshareable object leak (access an object from different Ractor) in VM.
-
-## Examples
-
-### Traditional Ring example in Actor-model
-
-```ruby
-RN = 1_000
-CR = Ractor.current
-
-r = Ractor.new do
- p Ractor.receive
- CR << :fin
-end
-
-RN.times{
- r = Ractor.new r do |next_r|
- next_r << Ractor.receive
- end
-}
-
-p :setup_ok
-r << 1
-p Ractor.receive
-```
-
-### Fork-join
-
-```ruby
-def fib n
- if n < 2
- 1
- else
- fib(n-2) + fib(n-1)
- end
-end
-
-RN = 10
-rs = (1..RN).map do |i|
- Ractor.new i do |i|
- [i, fib(i)]
- end
-end
-
-until rs.empty?
- r, v = Ractor.select(*rs)
- rs.delete r
- p answer: v
-end
-```
-
-### Worker pool
-
-```ruby
-require 'prime'
-
-pipe = Ractor.new do
- loop do
- Ractor.yield Ractor.receive
- end
-end
-
-N = 1000
-RN = 10
-workers = (1..RN).map do
- Ractor.new pipe do |pipe|
- while n = pipe.take
- Ractor.yield [n, n.prime?]
- end
- end
-end
-
-(1..N).each{|i|
- pipe << i
-}
-
-pp (1..N).map{
- _r, (n, b) = Ractor.select(*workers)
- [n, b]
-}.sort_by{|(n, b)| n}
-```
-
-### Pipeline
-
-```ruby
-# pipeline with yield/take
-r1 = Ractor.new do
- 'r1'
-end
-
-r2 = Ractor.new r1 do |r1|
- r1.take + 'r2'
-end
-
-r3 = Ractor.new r2 do |r2|
- r2.take + 'r3'
-end
-
-p r3.take #=> 'r1r2r3'
-```
-
-```ruby
-# pipeline with send/receive
-
-r3 = Ractor.new Ractor.current do |cr|
- cr.send Ractor.receive + 'r3'
-end
-
-r2 = Ractor.new r3 do |r3|
- r3.send Ractor.receive + 'r2'
-end
-
-r1 = Ractor.new r2 do |r2|
- r2.send Ractor.receive + 'r1'
-end
-
-r1 << 'r0'
-p Ractor.receive #=> "r0r1r2r3"
-```
-
-### Supervise
-
-```ruby
-# ring example again
-
-r = Ractor.current
-(1..10).map{|i|
- r = Ractor.new r, i do |r, i|
- r.send Ractor.receive + "r#{i}"
- end
-}
-
-r.send "r0"
-p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
-```
-
-```ruby
-# ring example with an error
-
-r = Ractor.current
-rs = (1..10).map{|i|
- r = Ractor.new r, i do |r, i|
- loop do
- msg = Ractor.receive
- raise if /e/ =~ msg
- r.send msg + "r#{i}"
- end
- end
-}
-
-r.send "r0"
-p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
-r.send "r0"
-p Ractor.select(*rs, Ractor.current) #=> [:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
-r.send "e0"
-p Ractor.select(*rs, Ractor.current)
-#=>
-# <Thread:0x000056262de28bd8 run> terminated with exception (report_on_exception is true):
-# Traceback (most recent call last):
-# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
-# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
-# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
-# Traceback (most recent call last):
-# 2: from /home/ko1/src/ruby/trunk/test.rb:7:in `block (2 levels) in <main>'
-# 1: from /home/ko1/src/ruby/trunk/test.rb:7:in `loop'
-# /home/ko1/src/ruby/trunk/test.rb:9:in `block (3 levels) in <main>': unhandled exception
-# 1: from /home/ko1/src/ruby/trunk/test.rb:21:in `<main>'
-# <internal:ractor>:69:in `select': thrown by remote Ractor. (Ractor::RemoteError)
-```
-
-```ruby
-# resend non-error message
-
-r = Ractor.current
-rs = (1..10).map{|i|
- r = Ractor.new r, i do |r, i|
- loop do
- msg = Ractor.receive
- raise if /e/ =~ msg
- r.send msg + "r#{i}"
- end
- end
-}
-
-r.send "r0"
-p Ractor.receive #=> "r0r10r9r8r7r6r5r4r3r2r1"
-r.send "r0"
-p Ractor.select(*rs, Ractor.current)
-[:receive, "r0r10r9r8r7r6r5r4r3r2r1"]
-msg = 'e0'
-begin
- r.send msg
- p Ractor.select(*rs, Ractor.current)
-rescue Ractor::RemoteError
- msg = 'r0'
- retry
-end
-
-#=> <internal:ractor>:100:in `send': The incoming-port is already closed (Ractor::ClosedError)
-# because r == r[-1] is terminated.
-```
-
-```ruby
-# ring example with supervisor and re-start
-
-def make_ractor r, i
- Ractor.new r, i do |r, i|
- loop do
- msg = Ractor.receive
- raise if /e/ =~ msg
- r.send msg + "r#{i}"
- end
- end
-end
-
-r = Ractor.current
-rs = (1..10).map{|i|
- r = make_ractor(r, i)
-}
-
-msg = 'e0' # error causing message
-begin
- r.send msg
- p Ractor.select(*rs, Ractor.current)
-rescue Ractor::RemoteError
- r = rs[-1] = make_ractor(rs[-2], rs.size-1)
- msg = 'x0'
- retry
-end
-
-#=> [:receive, "x0r9r9r8r7r6r5r4r3r2r1"]
-```
diff --git a/doc/rdoc/markup_reference.rb b/doc/rdoc/markup_reference.rb
deleted file mode 100644
index ee585b2497..0000000000
--- a/doc/rdoc/markup_reference.rb
+++ /dev/null
@@ -1,1281 +0,0 @@
-require 'rdoc'
-
-# \Class \RDoc::MarkupReference exists only to provide a suitable home
-# for a reference document for \RDoc markup.
-#
-# All objects defined in this class -- classes, modules, methods, aliases,
-# attributes, and constants -- are solely for illustrating \RDoc markup,
-# and have no other legitimate use.
-#
-# == About the Examples
-#
-# - Examples in this reference are Ruby code and comments;
-# certain differences from other sources
-# (such as C code and comments) are noted.
-# - Almost all examples on this page are all RDoc-like;
-# that is, they have no explicit comment markers like Ruby <tt>#</tt>
-# or C <tt>/* ... */</tt>.
-# - An example that shows rendered HTML output
-# displays that output in a blockquote:
-#
-# >>>
-# Some stuff
-#
-# == \RDoc Sources
-#
-# The sources of \RDoc documentation vary according to the type of file:
-#
-# - <tt>.rb</tt> (Ruby code file):
-#
-# - Markup may be found in Ruby comments:
-# A comment that immediately precedes the definition
-# of a Ruby class, module, method, alias, constant, or attribute
-# becomes the documentation for that defined object.
-# - An \RDoc directive may be found in:
-#
-# - A trailing comment (on the same line as code);
-# see <tt>:nodoc:</tt>, <tt>:doc:</tt>, and <tt>:notnew:</tt>.
-# - A single-line comment;
-# see other {Directives}[rdoc-ref:RDoc::MarkupReference@Directives].
-#
-# - Documentation may be derived from the Ruby code itself;
-# see {Documentation Derived from Ruby Code}[rdoc-ref:RDoc::MarkupReference@Documentation+Derived+from+Ruby+Code].
-#
-# - <tt>.c</tt> (C code file): markup is parsed from C comments.
-# A comment that immediately precedes
-# a function that implements a Ruby method,
-# or otherwise immediately precedes the definition of a Ruby object,
-# becomes the documentation for that object.
-# - <tt>.rdoc</tt> (\RDoc markup text file) or <tt>.md</tt> (\RDoc markdown text file):
-# markup is parsed from the entire file.
-# The text is not associated with any code object,
-# but may (depending on how the documentation is built)
-# become a separate page.
-#
-# An <i>RDoc document</i>:
-#
-# - A (possibly multi-line) comment in a Ruby or C file
-# that generates \RDoc documentation (as above).
-# - The entire markup (<tt>.rdoc</tt>) file or markdown (<tt>.md</tt>) file
-# (which is usually multi-line).
-#
-# === Blocks
-#
-# It's convenient to think of an \RDoc document as a sequence of _blocks_
-# of various types (details at the links):
-#
-# - {Paragraph}[rdoc-ref:RDoc::MarkupReference@Paragraphs]:
-# an ordinary paragraph.
-# - {Verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks]:
-# a block of text to be rendered literally.
-# - {Code block}[rdoc-ref:RDoc::MarkupReference@Code+Blocks]:
-# a verbatim text block containing Ruby code,
-# to be rendered with code highlighting.
-# - {Block quote}[rdoc-ref:RDoc::MarkupReference@Block+Quotes]:
-# a longish quoted passage, to be rendered with indentation
-# instead of quote marks.
-# - {List}[rdoc-ref:RDoc::MarkupReference@Lists]: items for
-# a bullet list, numbered list, lettered list, or labeled list.
-# - {Heading}[rdoc-ref:RDoc::MarkupReference@Headings]:
-# a heading.
-# - {Horizontal rule}[rdoc-ref:RDoc::MarkupReference@Horizontal+Rules]:
-# a line across the rendered page.
-# - {Directive}[rdoc-ref:RDoc::MarkupReference@Directives]:
-# various special directions for the rendering.
-# - {Text Markup}[rdoc-ref:RDoc:MarkupReference@Text+Markup]:
-# text to be rendered in a special way.
-#
-# About the blocks:
-#
-# - Except for a paragraph, a block is distinguished by its indentation,
-# or by unusual initial or embedded characters.
-# - Any block may appear independently
-# (that is, not nested in another block);
-# some blocks may be nested, as detailed below.
-# - In a multi-line block,
-# \RDoc looks for the block's natural left margin,
-# which becomes the <em>base margin</em> for the block
-# and is the initial <em>current margin</em> for the block.
-#
-# ==== Paragraphs
-#
-# A paragraph consists of one or more non-empty lines of ordinary text,
-# each beginning at the current margin.
-#
-# Note: Here, <em>ordinary text</em> means text that is <em>not identified</em>
-# by indentation, or by unusual initial or embedded characters.
-# See below.
-#
-# Paragraphs are separated by one or more empty lines.
-#
-# Example input:
-#
-# \RDoc produces HTML and command-line documentation for Ruby projects.
-# \RDoc includes the rdoc and ri tools for generating and displaying
-# documentation from the command-line.
-#
-# You'll love it.
-#
-# Rendered HTML:
-# >>>
-# \RDoc produces HTML and command-line documentation for Ruby projects.
-# \RDoc includes the rdoc and ri tools for generating and displaying
-# documentation from the command-line.
-#
-# You'll love it.
-#
-# A paragraph may contain nested blocks, including:
-#
-# - {Verbatim text blocks}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks].
-# - {Code blocks}[rdoc-ref:RDoc::MarkupReference@Code+Blocks].
-# - {Block quotes}[rdoc-ref:RDoc::MarkupReference@Block+Quotes].
-# - {Lists}[rdoc-ref:RDoc::MarkupReference@Lists].
-# - {Headings}[rdoc-ref:RDoc::MarkupReference@Headings].
-# - {Horizontal rules}[rdoc-ref:RDoc::MarkupReference@Horizontal+Rules].
-# - {Text Markup}[rdoc-ref:RDoc:MarkupReference@Text+Markup].
-#
-# ==== Verbatim Text Blocks
-#
-# Text indented farther than the current margin becomes a <em>verbatim text block</em>
-# (or a code block, described next).
-# In the rendered HTML, such text:
-#
-# - Is indented.
-# - Has a contrasting background color.
-#
-# The verbatim text block ends at the first line beginning at the current margin.
-#
-# Example input:
-#
-# This is not verbatim text.
-#
-# This is verbatim text.
-# Whitespace is honored. # See?
-# Whitespace is honored. # See?
-#
-# This is still the same verbatim text block.
-#
-# This is not verbatim text.
-#
-# Rendered HTML:
-# >>>
-# This is not verbatim text.
-#
-# This is verbatim text.
-# Whitespace is honored. # See?
-# Whitespace is honored. # See?
-#
-# This is still the same verbatim text block.
-#
-# This is not verbatim text.
-#
-# A verbatim text block may not contain nested blocks of any kind
-# -- it's verbatim.
-#
-# ==== Code Blocks
-#
-# A special case of verbatim text is the <em>code block</em>,
-# which is merely verbatim text that \RDoc recognizes as Ruby code:
-#
-# In the rendered HTML, the code block:
-#
-# - Is indented.
-# - Has a contrasting background color.
-# - Has syntax highlighting.
-#
-# Example input:
-#
-# Consider this method:
-#
-# def foo(name = '', value = 0)
-# @name = name # Whitespace is still honored.
-# @value = value
-# end
-#
-#
-# Rendered HTML:
-# >>>
-# Consider this method:
-#
-# def foo(name = '', value = 0)
-# @name = name # Whitespace is still honored.
-# @value = value
-# end
-#
-# Pro tip: If your indented Ruby code does not get highlighted,
-# it may contain a syntax error.
-#
-# A code block may not contain nested blocks of any kind
-# -- it's verbatim.
-#
-# ==== Block Quotes
-#
-# You can use the characters <tt>>>></tt> (unindented),
-# followed by indented text, to treat the text
-# as a {block quote}[https://en.wikipedia.org/wiki/Block_quotation]:
-#
-# Example input:
-#
-# Here's a block quote:
-# >>>
-# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
-# commodo quam iaculis massa posuere, dictum fringilla justo pulvinar.
-# Quisque turpis erat, pharetra eu dui at, sollicitudin accumsan nulla.
-#
-# Aenean congue ligula eu ligula molestie, eu pellentesque purus
-# faucibus. In id leo non ligula condimentum lobortis. Duis vestibulum,
-# diam in pellentesque aliquet, mi tellus placerat sapien, id euismod
-# purus magna ut tortor.
-#
-# Rendered HTML:
-#
-# >>>
-# Here's a block quote:
-# >>>
-# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
-# commodo quam iaculis massa posuere, dictum fringilla justo pulvinar.
-# Quisque turpis erat, pharetra eu dui at, sollicitudin accumsan nulla.
-#
-# Aenean congue ligula eu ligula molestie, eu pellentesque purus
-# faucibus. In id leo non ligula condimentum lobortis. Duis vestibulum,
-# diam in pellentesque aliquet, mi tellus placerat sapien, id euismod
-# purus magna ut tortor.
-#
-# Note that, unlike verbatim text, single newlines are not honored,
-# but that a double newline begins a new paragraph in the block quote.
-#
-# A block quote may contain nested blocks, including:
-#
-# - Other block quotes.
-# - {Paragraphs}[rdoc-ref:RDoc::MarkupReference@Paragraphs].
-# - {Verbatim text blocks}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks].
-# - {Code blocks}[rdoc-ref:RDoc::MarkupReference@Code+Blocks].
-# - {Lists}[rdoc-ref:RDoc::MarkupReference@Lists].
-# - {Headings}[rdoc-ref:RDoc::MarkupReference@Headings].
-# - {Horizontal rules}[rdoc-ref:RDoc::MarkupReference@Horizontal+Rules].
-# - {Text Markup}[rdoc-ref:RDoc:MarkupReference@Text+Markup].
-#
-# ==== Lists
-#
-# Each type of list item is marked by a special beginning:
-#
-# - Bullet list item: Begins with a hyphen or asterisk.
-# - Numbered list item: Begins with digits and a period.
-# - Lettered list item: Begins with an alphabetic character and a period.
-# - Labeled list item: Begins with one of:
-# - Square-bracketed text.
-# - A word followed by two colons.
-#
-# A list begins with a list item and continues, even across blank lines,
-# as long as list items of the same type are found at the same indentation level.
-#
-# A new list resets the current margin inward.
-# Additional lines of text aligned at that margin
-# are part of the continuing list item.
-#
-# A list item may be continued on additional lines that are aligned
-# with the first line. See examples below.
-#
-# A list item may contain nested blocks, including:
-#
-# - Other lists of any type.
-# - {Paragraphs}[rdoc-ref:RDoc::MarkupReference@Paragraphs].
-# - {Verbatim text blocks}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks].
-# - {Code blocks}[rdoc-ref:RDoc::MarkupReference@Code+Blocks].
-# - {Block quotes}[rdoc-ref:RDoc::MarkupReference@Block+Quotes].
-# - {Headings}[rdoc-ref:RDoc::MarkupReference@Headings].
-# - {Horizontal rules}[rdoc-ref:RDoc::MarkupReference@Horizontal+Rules].
-# - {Text Markup}[rdoc-ref:RDoc:MarkupReference@Text+Markup].
-#
-# ===== Bullet Lists
-#
-# A bullet list item begins with a hyphen or asterisk.
-#
-# Example input:
-#
-# - An item.
-# - Another.
-# - An item spanning
-# multiple lines.
-#
-# * Yet another.
-# - Last one.
-#
-# Rendered HTML:
-# >>>
-# - An item.
-# - Another.
-# - An item spanning
-# multiple lines.
-#
-# * Yet another.
-# - Last one.
-#
-# ===== Numbered Lists
-#
-# A numbered list item begins with digits and a period.
-#
-# The items are automatically re-numbered.
-#
-# Example input:
-#
-# 100. An item.
-# 10. Another.
-# 1. An item spanning
-# multiple lines.
-#
-# 1. Yet another.
-# 1000. Last one.
-#
-# Rendered HTML:
-# >>>
-# 100. An item.
-# 10. Another.
-# 1. An item spanning
-# multiple lines.
-#
-# 1. Yet another.
-# 1000. Last one.
-#
-# ===== Lettered Lists
-#
-# A lettered list item begins with letters and a period.
-#
-# The items are automatically "re-lettered."
-#
-# Example input:
-#
-# z. An item.
-# y. Another.
-# x. An item spanning
-# multiple lines.
-#
-# x. Yet another.
-# a. Last one.
-#
-# Rendered HTML:
-# >>>
-# z. An item.
-# y. Another.
-#
-# x. Yet another.
-# a. Last one.
-#
-# ===== Labeled Lists
-#
-# A labeled list item begins with one of:
-#
-# - Square-bracketed text: the label and text are on two lines.
-# - A word followed by two colons: the label and text are on the same line.
-#
-# Example input:
-#
-# [foo] An item.
-# bat:: Another.
-# [bag] An item spanning
-# multiple lines.
-#
-# [bar baz] Yet another.
-# bam:: Last one.
-#
-# Rendered HTML:
-# >>>
-# [foo] An item.
-# bat:: Another.
-# [bag] An item spanning
-# multiple lines.
-#
-# [bar baz] Yet another.
-# bam:: Last one.
-#
-# ==== Headings
-#
-# A heading begins with up to six equal-signs, followed by heading text.
-# Whitespace between those and the heading text is optional.
-#
-# Examples:
-#
-# = Section 1
-# == Section 1.1
-# === Section 1.1.1
-# === Section 1.1.2
-# == Section 1.2
-# = Section 2
-# = Foo
-# == Bar
-# === Baz
-# ==== Bam
-# ===== Bat
-# ====== Bad
-# ============Still a Heading (Level 6)
-# \== Not a Heading
-#
-# A heading may contain only one type of nested block:
-#
-# - {Text Markup}[rdoc-ref:RDoc:MarkupReference@Text+Markup].
-#
-# ==== Horizontal Rules
-#
-# A horizontal rule consists of a line with three or more hyphens
-# and nothing more.
-#
-# Example input:
-#
-# ---
-# --- Not a horizontal rule.
-#
-# -- Also not a horizontal rule.
-# ---
-#
-# Rendered HTML:
-# >>>
-# ---
-# --- Not a horizontal rule.
-#
-# -- Also not a horizontal rule.
-# ---
-#
-# ==== Directives
-#
-# ===== Directives for Allowing or Suppressing Documentation
-#
-# - <tt># :stopdoc:</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies that \RDoc should ignore markup
-# until next <tt>:startdoc:</tt> directive or end-of-file.
-#
-# - <tt># :startdoc:</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies that \RDoc should resume parsing markup.
-#
-# - <tt># :enddoc:</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies that \RDoc should ignore markup to end-of-file
-# regardless of other directives.
-#
-# - <tt># :nodoc:</tt>:
-#
-# - 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 a method definition in C code, it the directive must be in the comment line
-# immediately preceding the definition:
-#
-# /* :nodoc: */
-# static VALUE
-# some_method(VALUE self)
-# {
-# return self;
-# }
-#
-# Note that this directive has <em>no effect at all</em>
-# when placed at the method declaration:
-#
-# /* :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 a constant definition in C code, this directive <em>can not work</em>
-# because there is no "implementation" place for a constant.
-#
-# - <tt># :nodoc: all</tt>:
-#
-# - Appended to a line of code
-# that defines a class or module.
-# - Specifies that the class or module should not be documented.
-# By default, however, a nested class or module _will_ be documented.
-#
-# - <tt># :doc:</tt>:
-#
-# - Appended to a line of code
-# that defines a class, module, method, alias, constant, or attribute.
-# - Specifies the defined object should be documented, even if it otherwise
-# would not be documented.
-#
-# - <tt># :notnew:</tt> (aliased as <tt>:not_new:</tt> and <tt>:not-new:</tt>):
-#
-# - Appended to a line of code
-# that defines instance method +initialize+.
-# - Specifies that singleton method +new+ should not be documented.
-# By default, Ruby fakes a corresponding singleton method +new+,
-# which \RDoc includes in the documentation.
-# Note that instance method +initialize+ is private, and so by default
-# is not documented.
-#
-# For Ruby code, but not for other \RDoc sources,
-# there is a shorthand for <tt>:stopdoc:</tt> and <tt>:startdoc:</tt>:
-#
-# # Documented.
-# #--
-# # Not documented.
-# #++
-# # Documented.
-#
-# For C code, any of directives <tt>:startdoc:</tt>, <tt>:stopdoc:</tt>,
-# and <tt>:enddoc:</tt> may appear in a stand-alone comment:
-#
-# /* :startdoc: */
-# /* :stopdoc: */
-# /* :enddoc: */
-#
-# ===== Directive for Specifying \RDoc Source Format
-#
-# - <tt># :markup: _type_</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies the format for the \RDoc input;
-# parameter +type+ is one of: +rdoc+ (the default), +markdown+, +rd+, +tomdoc+.
-# See {Markup Formats}[rdoc-ref:RDoc::Markup@Markup+Formats].
-#
-# ===== Directives for Method Documentation
-#
-# - <tt># :call-seq:</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies the calling sequence to be reported in the HTML,
-# overriding the actual calling sequence in the code.
-# See method #call_seq_directive.
-#
-# Note that \RDoc can build the calling sequence for a Ruby-coded method,
-# but not for other languages.
-# You may want to override that by explicitly giving a <tt>:call-seq:</tt>
-# directive if you want to include:
-#
-# - A return type, which is not automatically inferred.
-# - Multiple calling sequences.
-#
-# For C code, the directive may appear in a stand-alone comment.
-#
-# - <tt># :args: _arg_names_</tt> (aliased as <tt>:arg:</tt>):
-#
-# - Appears on a line by itself.
-# - Specifies the arguments to be reported in the HTML,
-# overriding the actual arguments in the code.
-# See method #args_directive.
-#
-# - <tt># :yields: _arg_names_</tt> (aliased as <tt>:yield:</tt>):
-#
-# - Appears on a line by itself.
-# - Specifies the yield arguments to be reported in the HTML,
-# overriding the actual yield in the code.
-# See method #yields_directive.
-#
-# ===== Directives for Organizing Documentation
-#
-# By default, \RDoc groups:
-#
-# - Singleton methods together in alphabetical order.
-# - Instance methods and their aliases together in alphabetical order.
-# - Attributes and their aliases together in alphabetical order.
-#
-# You can use directives to modify those behaviors.
-#
-# - <tt># :section: _section_title_</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies that following methods are to be grouped into the section
-# with the given <em>section_title</em>,
-# or into the default section if no title is given.
-# The directive remains in effect until another such directive is given,
-# but may be temporarily overridden by directive <tt>:category:</tt>.
-# See below.
-#
-# The comment block containing this directive:
-#
-# - Must be separated by a blank line from the documentation for the next item.
-# - May have one or more lines preceding the directive.
-# These will be removed, along with any trailing lines that match them.
-# Such lines may be visually helpful.
-# - Lines of text that are not so removed become the descriptive text
-# for the section.
-#
-# Example:
-#
-# # ----------------------------------------
-# # :section: My Section
-# # This is the section that I wrote.
-# # See it glisten in the noon-day sun.
-# # ----------------------------------------
-#
-# ##
-# # Comment for some_method
-# def some_method
-# # ...
-# end
-#
-# You can use directive <tt>:category:</tt> to temporarily
-# override the current section.
-#
-# - <tt># :category: _section_title_</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies that just one following method is to be included
-# in the given section, or in the default section if no title is given.
-# Subsequent methods are to be grouped into the current section.
-#
-# ===== Directive for Including a File
-#
-# - <tt># :include: _filepath_</tt>:
-#
-# - Appears on a line by itself.
-# - Specifies that the contents of the given file
-# are to be included at this point.
-# The file content is shifted to have the same indentation as the colon
-# at the start of the directive.
-#
-# The file is searched for in the directory containing the current file,
-# and then in each of the directories given with the <tt>--include</tt>
-# command-line option.
-#
-# For C code, the directive may appear in a stand-alone comment
-#
-# ==== Text Markup
-#
-# Text markup is metatext that affects HTML rendering:
-#
-# - Typeface: italic, bold, monofont.
-# - Character conversions: copyright, trademark, certain punctuation.
-# - Links.
-# - Escapes: marking text as "not markup."
-#
-# ===== Typeface Markup
-#
-# Typeface markup can specify that text is to be rendered
-# as italic, bold, or monofont.
-#
-# Typeface markup may contain only one type of nested block:
-#
-# - More typeface markup:
-# italic, bold, monofont.
-#
-# ====== Italic
-#
-# Text may be marked as italic via HTML tag <tt><i></tt> or <tt><em></tt>.
-#
-# Example input:
-#
-# <i>Italicized words</i> in a paragraph.
-#
-# >>>
-# <i>Italicized words in a block quote</i>.
-#
-# - <i>Italicized words</i> in a list item.
-#
-# ====== <i>Italicized words</i> in a Heading
-#
-# <i>Italicized passage containing *bold* and +monofont+.</i>
-#
-# Rendered HTML:
-# >>>
-# <i>Italicized words</i> in a paragraph.
-#
-# >>>
-# <i>Italicized words in a block quote</i>.
-#
-# - <i>Italicized words</i> in a list item.
-#
-# ====== <i>Italicized words</i> in a Heading
-#
-# <i>Italicized passage containing *bold* and +monofont+.</i>
-#
-# A single word may be italicized via a shorthand:
-# prefixed and suffixed underscores.
-#
-# Example input:
-#
-# _Italic_ in a paragraph.
-#
-# >>>
-# _Italic_ in a block quote.
-#
-# - _Italic_ in a list item.
-#
-# ====== _Italic_ in a Heading
-#
-# Rendered HTML:
-# >>>
-# _Italic_ in a paragraph.
-#
-# >>>
-# _Italic_ in a block quote.
-#
-# - _Italic_ in a list item.
-#
-# ====== _Italic_ in a Heading
-#
-# ====== Bold
-#
-# Text may be marked as bold via HTML tag <tt><b></tt>.
-#
-# Example input:
-#
-# <b>Bold words</b> in a paragraph.
-#
-# >>>
-# <b>Bold words</b> in a block quote.
-#
-# - <b>Bold words</b> in a list item.
-#
-# ====== <b>Bold words</b> in a Heading
-#
-# <b>Bold passage containing _italics_ and +monofont+.</b>
-#
-# Rendered HTML:
-#
-# >>>
-# <b>Bold words</b> in a paragraph.
-#
-# >>>
-# <b>Bold words</b> in a block quote.
-#
-# - <b>Bold words</b> in a list item.
-#
-# ====== <b>Bold words</b> in a Heading
-#
-# <b>Bold passage containing _italics_ and +monofont+.</b>
-#
-# A single word may be made bold via a shorthand:
-# prefixed and suffixed asterisks.
-#
-# Example input:
-#
-# *Bold* in a paragraph.
-#
-# >>>
-# *Bold* in a block quote.
-#
-# - *Bold* in a list item.
-#
-# ===== *Bold* in a Heading
-#
-# Rendered HTML:
-#
-# >>>
-# *Bold* in a paragraph.
-#
-# >>>
-# *Bold* in a block quote.
-#
-# - *Bold* in a list item.
-#
-# ===== *Bold* in a Heading
-#
-# ====== Monofont
-#
-# Text may be marked as monofont
-# -- sometimes called 'typewriter font' --
-# via HTML tag <tt><tt></tt> or <tt><code></tt>.
-#
-# Example input:
-#
-# <tt>Monofont words</tt> in a paragraph.
-#
-# >>>
-# <tt>Monofont words</tt> in a block quote.
-#
-# - <tt>Monofont words</tt> in a list item.
-#
-# ====== <tt>Monofont words</tt> in heading
-#
-# <tt>Monofont passage containing _italics_ and *bold*.</tt>
-#
-# Rendered HTML:
-#
-# >>>
-# <tt>Monofont words</tt> in a paragraph.
-#
-# >>>
-# <tt>Monofont words</tt> in a block quote.
-#
-# - <tt>Monofont words</tt> in a list item.
-#
-# ====== <tt>Monofont words</tt> in heading
-#
-# <tt>Monofont passage containing _italics_ and *bold*.</tt>
-#
-# A single word may be made monofont by a shorthand:
-# prefixed and suffixed plus-signs.
-#
-# Example input:
-#
-# +Monofont+ in a paragraph.
-#
-# >>>
-# +Monofont+ in a block quote.
-#
-# - +Monofont+ in a list item.
-#
-# ====== +Monofont+ in a Heading
-#
-# Rendered HTML:
-#
-# >>>
-# +Monofont+ in a paragraph.
-#
-# >>>
-# +Monofont+ in a block quote.
-#
-# - +Monofont+ in a list item.
-#
-# ====== +Monofont+ in a Heading
-#
-# ==== Character Conversions
-#
-# Certain combinations of characters may be converted to special characters;
-# whether the conversion occurs depends on whether the special character
-# is available in the current encoding.
-#
-# - <tt>(c)</tt> converts to (c) (copyright character); must be lowercase.
-#
-# - <tt>(r)</tt> converts to (r) (registered trademark character); must be lowercase.
-#
-# - <tt>'foo'</tt> converts to 'foo' (smart single-quotes).
-#
-# - <tt>"foo"</tt> converts to "foo" (smart double-quotes).
-#
-# - <tt>foo ... bar</tt> converts to foo ... bar (1-character ellipsis).
-#
-# - <tt>foo -- bar</tt> converts to foo -- bar (1-character en-dash).
-#
-# - <tt>foo --- bar</tt> converts to foo --- bar (1-character em-dash).
-#
-# ==== Links
-#
-# Certain strings in \RDoc text are converted to links.
-# Any such link may be suppressed by prefixing a backslash.
-# This section shows how to link to various
-# targets.
-#
-# [Class]
-#
-# - On-page: <tt>DummyClass</tt> links to DummyClass.
-# - Off-page: <tt>RDoc::Alias</tt> links to RDoc::Alias.
-#
-# Note: For poeple want to mark up code (such as class, module,
-# constant, and method) as "<tt>+code+</tt>" (for interoperability
-# with other MarkDown parsers mainly), such word that refers a known
-# code object and is marked up entirely and separately as "monofont"
-# is also converted to a link.
-#
-# - <tt>+DummyClass+</tt> links to DummyClass
-# - <tt>+DummyClass-object+</tt> is not a link.
-#
-# [Module]
-#
-# - On-page: <tt>DummyModule</tt> links to DummyModule.
-# - Off-page: <tt>RDoc</tt> links to RDoc.
-#
-# [Constant]
-#
-# - On-page: <tt>DUMMY_CONSTANT</tt> links to DUMMY_CONSTANT.
-# - Off-page: <tt>RDoc::Text::MARKUP_FORMAT</tt> links to RDoc::Text::MARKUP_FORMAT.
-#
-# [Singleton Method]
-#
-# - On-page: <tt>::dummy_singleton_method</tt> links to ::dummy_singleton_method.
-# - Off-page<tt>RDoc::TokenStream::to_html</tt> links to RDoc::TokenStream::to_html.
-#
-# Note: Occasionally \RDoc is not linked to a method whose name
-# has only special characters. Check whether the links you were expecting
-# are actually there. If not, you'll need to put in an explicit link;
-# see below.
-#
-# Pro tip: The link to any method is available in the alphabetical table of contents
-# at the top left of the page for the class or module.
-#
-# [Instance Method]
-#
-# - On-page: <tt>#dummy_instance_method</tt> links to #dummy_instance_method.
-# - Off-page: <tt>RDoc::Alias#html_name</tt> links to RDoc::Alias#html_name.
-#
-# See the Note and Pro Tip immediately above.
-#
-# [Attribute]
-#
-# - On-page: <tt>#dummy_attribute</tt> links to #dummy_attribute.
-# - Off-page: <tt>RDoc::Alias#name</tt> links to RDoc::Alias#name.
-#
-# [Alias]
-#
-# - On-page: <tt>#dummy_instance_alias</tt> links to #dummy_instance_alias.
-# - Off-page: <tt>RDoc::Alias#new_name</tt> links to RDoc::Alias#new_name.
-#
-# [Protocol +http+]
-#
-# - Linked: <tt>http://yahoo.com</tt> links to http://yahoo.com.
-#
-# [Protocol +https+]
-#
-# - Linked: <tt>https://github.com</tt> links to https://github.com.
-#
-# [Protocol +ftp+]
-#
-# - Linked: <tt>ftp://nosuch.site</tt> links to ftp://nosuch.site.
-#
-# [Protocol +mailto+]
-#
-# - Linked: <tt>mailto:/foo@bar.com</tt> links to mailto://foo@bar.com.
-#
-# [Protocol +irc+]
-#
-# - link: <tt>irc://irc.freenode.net/ruby</tt> links to irc://irc.freenode.net/ruby.
-#
-# [Image Filename Extensions]
-#
-# - Link: <tt>https://www.ruby-lang.org/images/header-ruby-logo@2x.png</tt> is
-# converted to an in-line HTML +img+ tag, which displays the image in the HTML:
-#
-# https://www.ruby-lang.org/images/header-ruby-logo@2x.png
-#
-# Also works for +bmp+, +gif+, +jpeg+, and +jpg+ files.
-#
-# Note: Works only for a fully qualified URL.
-#
-# [Heading]
-#
-# - Link: <tt>RDoc::RD@LICENSE</tt> links to RDoc::RDoc::RD@LICENSE.
-#
-# Note that spaces in the actual heading are represented by <tt>+</tt> characters
-# in the linkable text.
-#
-# - Link: <tt>RDoc::Options@Saved+Options</tt>
-# links to RDoc::Options@Saved+Options.
-#
-# Punctuation and other special characters must be escaped like CGI.escape.
-#
-# Pro tip: The link to any heading is available in the alphabetical table of contents
-# at the top left of the page for the class or module.
-#
-# [Section]
-#
-# See {Directives for Organizing Documentation}[#class-RDoc::MarkupReference-label-Directives+for+Organizing+Documentation].
-#
-# - Link: <tt>RDoc::Markup::ToHtml@Visitor</tt> links to RDoc::Markup::ToHtml@Visitor.
-#
-# If a section and a heading share the same name, the link target is the section.
-#
-# [Single-Word Text Link]
-#
-# Use square brackets to create single-word text link:
-#
-# - <tt>GitHub[https://github.com]</tt> links to GitHub[https://github.com].
-#
-# [Multi-Word Text Link]
-#
-# Use square brackets and curly braces to create a multi-word text link.
-#
-# - <tt>{GitHub home page}[https://github.com]</tt> links to
-# {GitHub home page}[https://github.com].
-#
-# [<tt>rdoc-ref</tt> Scheme]
-#
-# A link with the <tt>rdoc-ref:</tt> scheme links to the referenced item,
-# if that item exists.
-# The referenced item may be a class, module, method, file, etc.
-#
-# - Class: <tt>Alias[rdoc-ref:RDoc::Alias]</tt> generates Alias[rdoc-ref:RDoc::Alias].
-# - Module: <tt>RDoc[rdoc-ref:RDoc]</tt> generates RDoc[rdoc-ref:RDoc].
-# - Method: <tt>foo[rdoc-ref:RDoc::MarkupReference#dummy_instance_method]</tt>
-# generates foo[rdoc-ref:RDoc::MarkupReference#dummy_instance_method].
-# - Constant: <tt>bar[rdoc-ref:RDoc::MarkupReference::DUMMY_CONSTANT]</tt>
-# generates bar[rdoc-ref:RDoc::MarkupReference::DUMMY_CONSTANT].
-# - Attribute: <tt>baz[rdoc-ref:RDoc::MarkupReference#dummy_attribute]</tt>
-# generates baz[rdoc-ref:RDoc::MarkupReference#dummy_attribute].
-# - Alias: <tt>bad[rdoc-ref:RDoc::MarkupReference#dummy_instance_alias]</tt>
-# generates bad[rdoc-ref:RDoc::MarkupReference#dummy_instance_alias].
-#
-# If the referenced item does not exist, no link is generated
-# and entire <tt>rdoc-ref:</tt> square-bracketed clause is removed
-# from the resulting text.
-#
-# - <tt>Nosuch[rdoc-ref:RDoc::Nosuch]</tt> generates Nosuch.
-#
-#
-# [<tt>rdoc-label</tt> Scheme]
-#
-# [Simple]
-#
-# You can specify a link target using this form,
-# where the second part cites the id of an HTML element.
-#
-# This link refers to the constant +DUMMY_CONSTANT+ on this page:
-#
-# - <tt>{DUMMY_CONSTANT}[rdoc-label:DUMMY_CONSTANT]</tt>
-#
-# Thus:
-#
-# {DUMMY_CONSTANT}[rdoc-label:DUMMY_CONSTANT]
-#
-# [With Return]
-#
-# You can specify both a link target and a local label
-# that can be used as the target for a return link.
-# These two links refer to each other:
-#
-# - <tt>{go to addressee}[rdoc-label:addressee:sender]</tt>
-# - <tt>{return to sender}[rdoc-label:sender:addressee]</tt>
-#
-# Thus:
-#
-# {go to addressee}[rdoc-label:addressee:sender]
-#
-# Some text.
-#
-# {return to sender}[rdoc-label:sender:addressee]
-#
-# [<tt>link:</tt> Scheme]
-#
-# - <tt>link:README_rdoc.html</tt> links to link:README_rdoc.html.
-#
-# [<tt>rdoc-image</tt> Scheme]
-#
-# Use the <tt>rdoc-image</tt> scheme to display an image that is also a link:
-#
-# # {rdoc-image:path/to/image}[link_target]
-#
-# - Link: <tt>{rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[https://www.ruby-lang.org]</tt>
-# displays image <tt>https://www.ruby-lang.org/images/header-ruby-logo@2x.png</tt>
-# as a link to <tt>https://www.ruby-lang.org</tt>.
-#
-# {rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[https://www.ruby-lang.org]
-#
-# A relative path as the target also works:
-#
-# - Link: <tt>{rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[./Alias.html]</tt> links to <tt>./Alias.html</tt>
-#
-# {rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[./Alias.html]
-#
-# === Escaping Text
-#
-# Text that would otherwise be interpreted as markup
-# can be "escaped," so that it is not interpreted as markup;
-# the escape character is the backslash (<tt>'\\'</tt>).
-#
-# In a verbatim text block or a code block,
-# the escape character is always preserved:
-#
-# Example input:
-#
-# This is not verbatim text.
-#
-# This is verbatim text, with an escape character \.
-#
-# This is not a code block.
-#
-# def foo
-# 'String with an escape character.'
-# end
-#
-# Rendered HTML:
-#
-# >>>
-# This is not verbatim text.
-#
-# This is verbatim text, with an escape character \.
-#
-# This is not a code block.
-#
-# def foo
-# 'This is a code block with an escape character \.'
-# end
-#
-# In typeface markup (italic, bold, or monofont),
-# an escape character is preserved unless it is immediately
-# followed by nested typeface markup.
-#
-# Example input:
-#
-# This list is about escapes; it contains:
-#
-# - <tt>Monofont text with unescaped nested _italic_</tt>.
-# - <tt>Monofont text with escaped nested \_italic_</tt>.
-# - <tt>Monofont text with an escape character \</tt>.
-#
-# Rendered HTML:
-#
-# >>>
-# This list is about escapes; it contains:
-#
-# - <tt>Monofont text with unescaped nested _italic_</tt>.
-# - <tt>Monofont text with escaped nested \_italic_</tt>.
-# - <tt>Monofont text with an escape character \ </tt>.
-#
-# In other text-bearing blocks
-# (paragraphs, block quotes, list items, headings):
-#
-# - A single escape character immediately followed by markup
-# escapes the markup.
-# - A single escape character followed by whitespace is preserved.
-# - A single escape character anywhere else is ignored.
-# - A double escape character is rendered as a single backslash.
-#
-# Example input:
-#
-# This list is about escapes; it contains:
-#
-# - An unescaped class name, RDoc, that will become a link.
-# - An escaped class name, \RDoc, that will not become a link.
-# - An escape character followed by whitespace \ .
-# - An escape character \that is ignored.
-# - A double escape character \\ that is rendered
-# as a single backslash.
-#
-# Rendered HTML:
-#
-# >>>
-# This list is about escapes; it contains:
-#
-# - An unescaped class name, RDoc, that will become a link.
-# - An escaped class name, \RDoc, that will not become a link.
-# - An escape character followed by whitespace \ .
-# - An escape character \that is ignored.
-# - A double escape character \\ that is rendered
-# as a single backslash.
-#
-# == Documentation Derived from Ruby Code
-#
-# [Class]
-#
-# By default, \RDoc documents:
-#
-# - \Class name.
-# - Parent class.
-# - Singleton methods.
-# - Instance methods.
-# - Aliases.
-# - Constants.
-# - Attributes.
-#
-# [Module]
-#
-# By default, \RDoc documents:
-#
-# - \Module name.
-# - \Singleton methods.
-# - Instance methods.
-# - Aliases.
-# - Constants.
-# - Attributes.
-#
-# [Method]
-#
-# By default, \RDoc documents:
-#
-# - \Method name.
-# - Arguments.
-# - Yielded values.
-#
-# See #method.
-#
-# [Alias]
-#
-# By default, \RDoc documents:
-#
-# - Alias name.
-# - Aliased name.
-#
-# See #dummy_instance_alias and #dummy_instance_method.
-#
-# [Constant]
-#
-# By default, \RDoc documents:
-#
-# - \Constant name.
-#
-# See DUMMY_CONSTANT.
-#
-# [Attribute]
-#
-# By default, \RDoc documents:
-#
-# - Attribute name.
-# - Attribute type (<tt>[R]</tt>, <tt>[W]</tt>, or <tt>[RW]</tt>)
-#
-# See #dummy_attribute.
-#
-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:
- # call_seq_directive(foo, bar)
- # Can be anything -> bar
- # Also anything more -> baz or bat
- #
- # The <tt>:call-seq:</tt> directive overrides the actual calling sequence
- # found in the Ruby code.
- #
- # - It can specify anything at all.
- # - It can have multiple calling sequences.
- #
- # This one includes <tt>Can be anything -> foo</tt>, which is nonsense.
- #
- # Note that the "arrow" is two characters, hyphen and right angle-bracket,
- # which is made into a single character in the HTML.
- #
- # Click on the calling sequence to see the code.
- #
- # Here is the <tt>:call-seq:</tt> directive given for the method:
- #
- # :call-seq:
- # call_seq_directive(foo, bar)
- # Can be anything -> bar
- # Also anything more -> baz or bat
- #
- def call_seq_directive
- nil
- end
-
- # The <tt>:args:</tt> directive overrides the actual arguments found in the Ruby code.
- #
- # Click on the calling sequence to see the code.
- #
- def args_directive(foo, bar) # :args: baz
- nil
- end
-
- # The <tt>:yields:</tt> directive overrides the actual yield found in the Ruby code.
- #
- # Click on the calling sequence to see the code.
- #
- def yields_directive(foo, bar) # :yields: 'bat'
- yield 'baz'
- end
-
- # This method is documented only by \RDoc, except for these comments.
- #
- # Click on the calling sequence to see the code.
- #
- def method(foo, bar)
- yield 'baz'
- end
-
-end
diff --git a/doc/regexp/unicode_properties.rdoc b/doc/regexp/unicode_properties.rdoc
deleted file mode 100644
index 9720e02c18..0000000000
--- a/doc/regexp/unicode_properties.rdoc
+++ /dev/null
@@ -1,686 +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{IDS_Unary_Operator}</tt>, <tt>\p{IDSU}</tt>
-- <tt>\p{ID_Compat_Math_Continue}</tt>
-- <tt>\p{ID_Compat_Math_Start}</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{InCB_Consonant}</tt>
-- <tt>\p{InCB_Extend}</tt>
-- <tt>\p{InCB_Linker}</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_CJK_Unified_Ideographs_Extension_I}</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_15_1}</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/ruby/option_dump.md b/doc/ruby/option_dump.md
deleted file mode 100644
index a156484bf6..0000000000
--- a/doc/ruby/option_dump.md
+++ /dev/null
@@ -1,265 +0,0 @@
-# Option `--dump`
-
-For other argument values,
-see {Option --dump}[options_md.html#label--dump-3A+Dump+Items].
-
-For the examples here, we use this program:
-
-```console
-$ cat t.rb
-puts 'Foo'
-```
-
-The supported dump items:
-
-- `insns`: Instruction sequences:
-
- ```sh
- $ ruby --dump=insns t.rb
- == disasm: #<ISeq:<main>@t.rb:1 (1,0)-(1,10)> (catch: FALSE)
- 0000 putself ( 1)[Li]
- 0001 putstring "Foo"
- 0003 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
- 0005 leave
- ```
-
-- `parsetree`: {Abstract syntax tree}[https://en.wikipedia.org/wiki/Abstract_syntax_tree]
- (AST):
-
- ```console
- $ ruby --dump=parsetree t.rb
- ###########################################################
- ## Do NOT use this node dump for any purpose other than ##
- ## debug and research. Compatibility is not guaranteed. ##
- ###########################################################
-
- # @ NODE_SCOPE (line: 1, location: (1,0)-(1,10))
- # +- nd_tbl: (empty)
- # +- nd_args:
- # | (null node)
- # +- nd_body:
- # @ NODE_FCALL (line: 1, location: (1,0)-(1,10))*
- # +- nd_mid: :puts
- # +- nd_args:
- # @ NODE_LIST (line: 1, location: (1,5)-(1,10))
- # +- nd_alen: 1
- # +- nd_head:
- # | @ NODE_STR (line: 1, location: (1,5)-(1,10))
- # | +- nd_lit: "Foo"
- # +- nd_next:
- # (null node)
- ```
-
-- `yydebug`: Debugging information from yacc parser generator:
-
- ```
- $ ruby --dump=yydebug t.rb
- Starting parse
- Entering state 0
- Reducing stack by rule 1 (line 1295):
- lex_state: NONE -> BEG at line 1296
- vtable_alloc:12392: 0x0000558453df1a00
- vtable_alloc:12393: 0x0000558453df1a60
- cmdarg_stack(push): 0 at line 12406
- cond_stack(push): 0 at line 12407
- -> $$ = nterm $@1 (1.0-1.0: )
- Stack now 0
- Entering state 2
- Reading a token:
- lex_state: BEG -> CMDARG at line 9049
- Next token is token "local variable or method" (1.0-1.4: puts)
- Shifting token "local variable or method" (1.0-1.4: puts)
- Entering state 35
- Reading a token: Next token is token "string literal" (1.5-1.6: )
- Reducing stack by rule 742 (line 5567):
- $1 = token "local variable or method" (1.0-1.4: puts)
- -> $$ = nterm operation (1.0-1.4: )
- Stack now 0 2
- Entering state 126
- Reducing stack by rule 78 (line 1794):
- $1 = nterm operation (1.0-1.4: )
- -> $$ = nterm fcall (1.0-1.4: )
- Stack now 0 2
- Entering state 80
- Next token is token "string literal" (1.5-1.6: )
- Reducing stack by rule 292 (line 2723):
- cmdarg_stack(push): 1 at line 2737
- -> $$ = nterm $@16 (1.4-1.4: )
- Stack now 0 2 80
- Entering state 235
- Next token is token "string literal" (1.5-1.6: )
- Shifting token "string literal" (1.5-1.6: )
- Entering state 216
- Reducing stack by rule 607 (line 4706):
- -> $$ = nterm string_contents (1.6-1.6: )
- Stack now 0 2 80 235 216
- Entering state 437
- Reading a token: Next token is token "literal content" (1.6-1.9: "Foo")
- Shifting token "literal content" (1.6-1.9: "Foo")
- Entering state 503
- Reducing stack by rule 613 (line 4802):
- $1 = token "literal content" (1.6-1.9: "Foo")
- -> $$ = nterm string_content (1.6-1.9: )
- Stack now 0 2 80 235 216 437
- Entering state 507
- Reducing stack by rule 608 (line 4716):
- $1 = nterm string_contents (1.6-1.6: )
- $2 = nterm string_content (1.6-1.9: )
- -> $$ = nterm string_contents (1.6-1.9: )
- Stack now 0 2 80 235 216
- Entering state 437
- Reading a token:
- lex_state: CMDARG -> END at line 7276
- Next token is token "terminator" (1.9-1.10: )
- Shifting token "terminator" (1.9-1.10: )
- Entering state 508
- Reducing stack by rule 590 (line 4569):
- $1 = token "string literal" (1.5-1.6: )
- $2 = nterm string_contents (1.6-1.9: )
- $3 = token "terminator" (1.9-1.10: )
- -> $$ = nterm string1 (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 109
- Reducing stack by rule 588 (line 4559):
- $1 = nterm string1 (1.5-1.10: )
- -> $$ = nterm string (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 108
- Reading a token:
- lex_state: END -> BEG at line 9200
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 586 (line 4541):
- $1 = nterm string (1.5-1.10: )
- -> $$ = nterm strings (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 107
- Reducing stack by rule 307 (line 2837):
- $1 = nterm strings (1.5-1.10: )
- -> $$ = nterm primary (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 90
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 261 (line 2553):
- $1 = nterm primary (1.5-1.10: )
- -> $$ = nterm arg (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 220
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 270 (line 2586):
- $1 = nterm arg (1.5-1.10: )
- -> $$ = nterm arg_value (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 221
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 297 (line 2779):
- $1 = nterm arg_value (1.5-1.10: )
- -> $$ = nterm args (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 224
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 772 (line 5626):
- -> $$ = nterm none (1.10-1.10: )
- Stack now 0 2 80 235 224
- Entering state 442
- Reducing stack by rule 296 (line 2773):
- $1 = nterm none (1.10-1.10: )
-
- -> $$ = nterm opt_block_arg (1.10-1.10: )
- Stack now 0 2 80 235 224
- Entering state 441
- Reducing stack by rule 288 (line 2696):
- $1 = nterm args (1.5-1.10: )
- $2 = nterm opt_block_arg (1.10-1.10: )
- -> $$ = nterm call_args (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 453
- Reducing stack by rule 293 (line 2723):
- $1 = nterm $@16 (1.4-1.4: )
- $2 = nterm call_args (1.5-1.10: )
- cmdarg_stack(pop): 0 at line 2754
- -> $$ = nterm command_args (1.4-1.10: )
- Stack now 0 2 80
- Entering state 333
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 79 (line 1804):
- $1 = nterm fcall (1.0-1.4: )
- $2 = nterm command_args (1.4-1.10: )
- -> $$ = nterm command (1.0-1.10: )
- Stack now 0 2
- Entering state 81
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 73 (line 1770):
- $1 = nterm command (1.0-1.10: )
- -> $$ = nterm command_call (1.0-1.10: )
- Stack now 0 2
- Entering state 78
- Reducing stack by rule 51 (line 1659):
- $1 = nterm command_call (1.0-1.10: )
- -> $$ = nterm expr (1.0-1.10: )
- Stack now 0 2
- Entering state 75
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 39 (line 1578):
- $1 = nterm expr (1.0-1.10: )
- -> $$ = nterm stmt (1.0-1.10: )
- Stack now 0 2
- Entering state 73
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 8 (line 1354):
- $1 = nterm stmt (1.0-1.10: )
- -> $$ = nterm top_stmt (1.0-1.10: )
- Stack now 0 2
- Entering state 72
- Reducing stack by rule 5 (line 1334):
- $1 = nterm top_stmt (1.0-1.10: )
- -> $$ = nterm top_stmts (1.0-1.10: )
- Stack now 0 2
- Entering state 71
- Next token is token '\n' (1.10-1.10: )
- Shifting token '\n' (1.10-1.10: )
- Entering state 311
- Reducing stack by rule 769 (line 5618):
- $1 = token '\n' (1.10-1.10: )
- -> $$ = nterm term (1.10-1.10: )
- Stack now 0 2 71
- Entering state 313
- Reducing stack by rule 770 (line 5621):
- $1 = nterm term (1.10-1.10: )
- -> $$ = nterm terms (1.10-1.10: )
- Stack now 0 2 71
- Entering state 314
- Reading a token: Now at end of input.
- Reducing stack by rule 759 (line 5596):
- $1 = nterm terms (1.10-1.10: )
- -> $$ = nterm opt_terms (1.10-1.10: )
- Stack now 0 2 71
- Entering state 312
- Reducing stack by rule 3 (line 1321):
- $1 = nterm top_stmts (1.0-1.10: )
- $2 = nterm opt_terms (1.10-1.10: )
- -> $$ = nterm top_compstmt (1.0-1.10: )
- Stack now 0 2
- Entering state 70
- Reducing stack by rule 2 (line 1295):
- $1 = nterm $@1 (1.0-1.0: )
- $2 = nterm top_compstmt (1.0-1.10: )
- vtable_free:12426: p->lvtbl->args(0x0000558453df1a00)
- vtable_free:12427: p->lvtbl->vars(0x0000558453df1a60)
- cmdarg_stack(pop): 0 at line 12428
- cond_stack(pop): 0 at line 12429
- -> $$ = nterm program (1.0-1.10: )
- Stack now 0
- Entering state 1
- Now at end of input.
- Shifting token "end-of-input" (1.10-1.10: )
- Entering state 3
- Stack now 0 1 3
- Cleanup: popping token "end-of-input" (1.10-1.10: )
- Cleanup: popping nterm program (1.0-1.10: )
- ```
-
-Additional flags can follow dump items.
-
-- `+comment`: Add comments to AST.
-- `+error-tolerant`: Parse in error-tolerant mode.
-- `-optimize`: Disable optimizations for instruction sequences.
diff --git a/doc/ruby/options.md b/doc/ruby/options.md
deleted file mode 100644
index bfbd2530de..0000000000
--- a/doc/ruby/options.md
+++ /dev/null
@@ -1,724 +0,0 @@
-# Ruby Command-Line Options
-
-## About the Examples
-
-Some examples here use command-line option `-e`,
-which passes the Ruby code to be executed on the command line itself:
-
-```console
-$ ruby -e 'puts "Hello, World."'
-```
-
-Some examples here assume that file `desiderata.txt` exists:
-
-```console
-$ cat desiderata.txt
-Go placidly amid the noise and the haste,
-and remember what peace there may be in silence.
-As far as possible, without surrender,
-be on good terms with all persons.
-```
-
-## Options
-
-### `-0`: Set `$/` (Input Record Separator)
-
-Option `-0` defines the input record separator `$/`
-for the invoked Ruby program.
-
-The optional argument to the option must be octal digits,
-each in the range `0..7`;
-these digits are prefixed with digit `0` to form an octal value.
-
-If no argument is given, the input record separator is `0x00`.
-
-If an argument is given, it must immediately follow the option
-(no intervening whitespace or equal-sign character `'='`);
-argument values:
-
-- `0`: the input record separator is `''`;
- see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values].
-- In range `(1..0377)`:
- the input record separator `$/` is set to the character value of the argument.
-- Any other octal value: the input record separator is `nil`.
-
-Examples:
-
-```console
-$ ruby -0 -e 'p $/'
-"\x00"
-ruby -00 -e 'p $/'
-""
-$ ruby -012 -e 'p $/'
-"\n"
-$ ruby -015 -e 'p $/'
-"\r"
-$ ruby -0377 -e 'p $/'
-"\xFF"
-$ ruby -0400 -e 'p $/'
-nil
-```
-
-See also:
-
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-a`: Split Input Lines into Fields
-
-Option `-a`, when given with either of options `-n` or `-p`,
-splits the string at `$_` into an array of strings at `$F`:
-
-```console
-$ ruby -an -e 'p $F' desiderata.txt
-["Go", "placidly", "amid", "the", "noise", "and", "the", "haste,"]
-["and", "remember", "what", "peace", "there", "may", "be", "in", "silence."]
-["As", "far", "as", "possible,", "without", "surrender,"]
-["be", "on", "good", "terms", "with", "all", "persons."]
-```
-
-For the splitting,
-the default record separator is `$/`,
-and the default field separator is `$;`.
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- Set `$/` (input record separator).
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-c`: Check Syntax
-
-Option `-c` specifies that the specified Ruby program
-should be checked for syntax, but not actually executed:
-
-```console
-$ ruby -e 'puts "Foo"'
-Foo
-$ ruby -c -e 'puts "Foo"'
-Syntax OK
-```
-
-### `-C`: Set Working Directory
-
-The argument to option `-C` specifies a working directory
-for the invoked Ruby program;
-does not change the working directory for the current process:
-
-```console
-$ basename `pwd`
-ruby
-$ ruby -C lib -e 'puts File.basename(Dir.pwd)'
-lib
-$ basename `pwd`
-ruby
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### `-d`: Set `$DEBUG` to `true`
-
-Some code in (or called by) the Ruby program may include statements or blocks
-conditioned by the global variable `$DEBUG` (e.g., `if $DEBUG`);
-these commonly write to `$stdout` or `$stderr`.
-
-The default value for `$DEBUG` is `false`;
-option `-d` sets it to `true`:
-
-```console
-$ ruby -e 'p $DEBUG'
-false
-$ ruby -d -e 'p $DEBUG'
-true
-```
-
-Option `--debug` is an alias for option `-d`.
-
-### `-e`: Execute Given Ruby Code
-
-Option `-e` requires an argument, which is Ruby code to be executed;
-the option may be given more than once:
-
-```console
-$ ruby -e 'puts "Foo"' -e 'puts "Bar"'
-Foo
-Bar
-```
-
-Whitespace between the option and its argument may be omitted.
-
-The command may include other options,
-but should not include arguments (which, if given, are ignored).
-
-### `-E`: Set Default Encodings
-
-Option `-E` requires an argument, which specifies either the default external encoding,
-or both the default external and internal encodings for the invoked Ruby program:
-
-```console
-# No option -E.
-$ ruby -e 'p [Encoding::default_external, Encoding::default_internal]'
-[#<Encoding:UTF-8>, nil]
-# Option -E with default external encoding.
-$ ruby -E cesu-8 -e 'p [Encoding::default_external, Encoding::default_internal]'
-[#<Encoding:CESU-8>, nil]
-# Option -E with default external and internal encodings.
-$ ruby -E utf-8:cesu-8 -e 'p [Encoding::default_external, Encoding::default_internal]'
-[#<Encoding:UTF-8>, #<Encoding:CESU-8>]
-```
-
-Whitespace between the option and its argument may be omitted.
-
-See also:
-
-- {Option --external-encoding}[options_md.html#label--external-encoding-3A+Set+Default+External+Encoding]:
- Set default external encoding.
-- {Option --internal-encoding}[options_md.html#label--internal-encoding-3A+Set+Default+Internal+Encoding]:
- Set default internal encoding.
-
-Option `--encoding` is an alias for option `-E`.
-
-### `-F`: Set Input Field Separator
-
-Option `-F`, when given with option `-a`,
-specifies that its argument is to be the input field separator to be used for splitting:
-
-```console
-$ ruby -an -Fs -e 'p $F' desiderata.txt
-["Go placidly amid the noi", "e and the ha", "te,\n"]
-["and remember what peace there may be in ", "ilence.\n"]
-["A", " far a", " po", "", "ible, without ", "urrender,\n"]
-["be on good term", " with all per", "on", ".\n"]
-```
-
-The argument may be a regular expression:
-
-```console
-$ ruby -an -F'[.,]\s*' -e 'p $F' desiderata.txt
-["Go placidly amid the noise and the haste"]
-["and remember what peace there may be in silence"]
-["As far as possible", "without surrender"]
-["be on good terms with all persons"]
-```
-
-The argument must immediately follow the option
-(no intervening whitespace or equal-sign character `'='`).
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-h`: Print Short Help Message
-
-Option `-h` prints a short help message
-that includes single-hyphen options (e.g. `-I`),
-and largely omits double-hyphen options (e.g., `--version`).
-
-Arguments and additional options are ignored.
-
-For a longer help message, use option `--help`.
-
-### `-i`: Set \ARGF In-Place Mode
-
-Option `-i` sets the \ARGF in-place mode for the invoked Ruby program;
-see ARGF#inplace_mode=:
-
-```console
-$ ruby -e 'p ARGF.inplace_mode'
-nil
-$ ruby -i -e 'p ARGF.inplace_mode'
-""
-$ ruby -i.bak -e 'p ARGF.inplace_mode'
-".bak"
-```
-
-### `-I`: Add to `$LOAD_PATH`
-
-The argument to option `-I` specifies a directory
-to be added to the array in global variable `$LOAD_PATH`;
-the option may be given more than once:
-
-```console
-$ pushd /tmp
-$ ruby -e 'p $LOAD_PATH.size'
-8
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.size'
-10
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.take(2)'
-["/tmp/my_lib", "/tmp/some_lib"]
-$ popd
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### `-l`: Set Output Record Separator; Chop Lines
-
-Option `-l`, when given with option `-n` or `-p`,
-modifies line-ending processing by:
-
-- Setting global variable output record separator `$\`
- to the current value of input record separator `$/`;
- this affects line-oriented output (such a the output from Kernel#puts).
-- Calling String#chop! on each line read.
-
-Without option `-l` (unchopped):
-
-```console
-$ ruby -n -e 'p $_' desiderata.txt
-"Go placidly amid the noise and the haste,\n"
-"and remember what peace there may be in silence.\n"
-"As far as possible, without surrender,\n"
-"be on good terms with all persons.\n"
-```
-
-With option `-l' (chopped):
-
-```console
-$ ruby -ln -e 'p $_' desiderata.txt
-"Go placidly amid the noise and the haste,"
-"and remember what peace there may be in silence."
-"As far as possible, without surrender,"
-"be on good terms with all persons."
-```
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- Set input field separator.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-n`: Run Program in `gets` Loop
-
-Option `-n` runs your program in a `Kernel#gets` loop:
-
-```ruby
-while gets
- # Your Ruby code.
-end
-```
-
-Note that `gets` reads the next line and sets global variable `$_`
-to the last read line:
-
-```console
-$ ruby -n -e 'puts $_' desiderata.txt
-Go placidly amid the noise and the haste,
-and remember what peace there may be in silence.
-As far as possible, without surrender,
-be on good terms with all persons.
-```
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- Set output record separator; chop lines.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-p`: `-n`, with Printing
-
-Option `-p` is like option `-n`, but also prints each line:
-
-```console
-$ ruby -p -e 'puts $_.size' desiderata.txt
-42
-Go placidly amid the noise and the haste,
-49
-and remember what peace there may be in silence.
-39
-As far as possible, without surrender,
-35
-be on good terms with all persons.
-```
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-
-### `-r`: Require Library
-
-The argument to option `-r` specifies a library to be required
-before executing the Ruby program;
-the option may be given more than once:
-
-```console
-$ ruby -e 'p defined?(JSON); p defined?(CSV)'
-nil
-nil
-$ ruby -r CSV -r JSON -e 'p defined?(JSON); p defined?(CSV)'
-"constant"
-"constant"
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### `-s`: Define Global Variable
-
-Option `-s` specifies that a "custom option" is to define a global variable
-in the invoked Ruby program:
-
-- The custom option must appear _after_ the program name.
-- The custom option must begin with single hyphen (e.g., `-foo`),
- not two hyphens (e.g., `--foo`).
-- The name of the global variable is based on the option name:
- global variable `$foo` for custom option`-foo`.
-- The value of the global variable is the string option argument if given,
- `true` otherwise.
-
-More than one custom option may be given:
-
-```console
-$ cat t.rb
-p [$foo, $bar]
-$ ruby t.rb
-[nil, nil]
-$ ruby -s t.rb -foo=baz
-["baz", nil]
-$ ruby -s t.rb -foo
-[true, nil]
-$ ruby -s t.rb -foo=baz -bar=bat
-["baz", "bat"]
-```
-
-The option may not be used with
-{option -e}[rdoc-ref:ruby/options.md@e-3A+Execute+Given+Ruby+Code]
-
-### `-S`: Search Directories in `ENV['PATH']`
-
-Option `-S` specifies that the Ruby interpreter
-is to search (if necessary) the directories whose paths are in the program's
-`PATH` environment variable;
-the program is executed in the shell's current working directory
-(not necessarily in the directory where the program is found).
-
-This example uses adds path `'tmp/'` to the `PATH` environment variable:
-
-```console
-$ export PATH=/tmp:$PATH
-$ echo "puts File.basename(Dir.pwd)" > /tmp/t.rb
-$ ruby -S t.rb
-ruby
-```
-
-### `-v`: Print Version; Set `$VERBOSE`
-
-Options `-v` prints the Ruby version and sets global variable `$VERBOSE`:
-
-```console
-$ ruby -e 'p $VERBOSE'
-false
-$ ruby -v -e 'p $VERBOSE'
-ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x64-mingw-ucrt]
-true
-```
-
-### `-w`: Synonym for `-W1`
-
-Option `-w` (lowercase letter) is equivalent to option `-W1` (uppercase letter).
-
-### `-W`: Set \Warning Policy
-
-Any Ruby code can create a <i>warning message</i> by calling method Kernel#warn;
-methods in the Ruby core and standard libraries can also create warning messages.
-Such a message may be printed on `$stderr`
-(or not, depending on certain settings).
-
-Option `-W` helps determine whether a particular warning message
-will be written,
-by setting the initial value of global variable `$-W`:
-
-- `-W0`: Sets `$-W` to `0` (silent; no warnings).
-- `-W1`: Sets `$-W` to `1` (moderate verbosity).
-- `-W2`: Sets `$-W` to `2` (high verbosity).
-- `-W`: Same as `-W2` (high verbosity).
-- Option not given: Same as `-W1` (moderate verbosity).
-
-The value of `$-W`, in turn, determines which warning messages (if any)
-are to be printed to `$stdout` (see Kernel#warn):
-
-```console
-$ ruby -W1 -e 'p $foo'
-nil
-$ ruby -W2 -e 'p $foo'
--e:1: warning: global variable '$foo' not initialized
-nil
-```
-
-Ruby code may also define warnings for certain categories;
-these are the default settings for the defined categories:
-
-```rb
-Warning[:experimental] # => true
-Warning[:deprecated] # => false
-Warning[:performance] # => false
-```
-
-They may also be set:
-
-```rb
-Warning[:experimental] = false
-Warning[:deprecated] = true
-Warning[:performance] = true
-```
-
-You can suppress a category by prefixing `no-` to the category name:
-
-```console
-$ ruby -W:no-experimental -e 'p IO::Buffer.new'
-#<IO::Buffer>
-```
-
-### `-x`: Execute Ruby Code Found in Text
-
-Option `-x` executes a Ruby program whose code is embedded
-in other, non-code, text:
-
-The ruby code:
-
-- Begins after the first line beginning with `'#!` and containing string `'ruby'`.
-- Ends before any one of:
-
- - End-of-file.
- - A line consisting of `'__END__'`,
- - Character `Ctrl-D` or `Ctrl-Z`.
-
-Example:
-
-```console
-$ cat t.txt
-Leading garbage.
-#!ruby
-puts File.basename(Dir.pwd)
-__END__
-Trailing garbage.
-
-$ ruby -x t.txt
-ruby
-```
-
-The optional argument specifies the directory where the text file
-is to be found;
-the Ruby code is executed in that directory:
-
-```console
-$ cp t.txt /tmp/
-$ ruby -x/tmp t.txt
-tmp
-$
-
-```
-
-If an argument is given, it must immediately follow the option
-(no intervening whitespace or equal-sign character `'='`).
-
-### `--backtrace-limit`: Set Backtrace Limit
-
-Option `--backtrace-limit` sets a limit on the number of entries
-to be displayed in a backtrace.
-
-See Thread::Backtrace.limit.
-
-### `--copyright`: Print Ruby Copyright
-
-Option `--copyright` prints a copyright message:
-
-```console
-$ ruby --copyright
-ruby - Copyright (C) 1993-2024 Yukihiro Matsumoto
-```
-
-### `--debug`: Alias for `-d`
-
-Option `--debug` is an alias for
-{option -d}[rdoc-ref:ruby/options.md@d-3A+Set+-24DEBUG+to+true].
-
-### `--disable`: Disable Features
-
-Option `--disable` specifies features to be disabled;
-the argument is a comma-separated list of the features to be disabled:
-
-```sh
-ruby --disable=gems,rubyopt t.rb
-```
-
-The supported features:
-
-- `gems`: Rubygems (default: enabled).
-- `did_you_mean`: [`did_you_mean`](https://github.com/ruby/did_you_mean) (default: enabled).
-- `rubyopt`: `RUBYOPT` environment variable (default: enabled).
-- `frozen-string-literal`: Freeze all string literals (default: disabled).
-- `jit`: JIT compiler (default: disabled).
-
-See also {option --enable}[options_md.html#label--enable-3A+Enable+Features].
-
-### `--dump`: Dump Items
-
-Option `--dump` specifies items to be dumped;
-the argument is a comma-separated list of the items.
-
-Some of the argument values cause the command to behave as if a different
-option was given:
-
-- `--dump=copyright`:
- Same as {option \-\-copyright}[options_md.html#label--copyright-3A+Print+Ruby+Copyright].
-- `--dump=help`:
- Same as {option \-\-help}[options_md.html#label--help-3A+Print+Help+Message].
-- `--dump=syntax`:
- Same as {option -c}[rdoc-ref:ruby/options.md@c-3A+Check+Syntax].
-- `--dump=usage`:
- Same as {option -h}[rdoc-ref:ruby/options.md@h-3A+Print+Short+Help+Message].
-- `--dump=version`:
- Same as {option \-\-version}[options_md.html#label--version-3A+Print+Ruby+Version].
-
-For other argument values and examples,
-see {Option --dump}[option_dump_md.html].
-
-### `--enable`: Enable Features
-
-Option `--enable` specifies features to be enabled;
-the argument is a comma-separated list of the features to be enabled.
-
-```sh
-ruby --enable=gems,rubyopt t.rb
-```
-
-For the features,
-see {option --disable}[options_md.html#label--disable-3A+Disable+Features].
-
-### `--encoding`: Alias for `-E`.
-
-Option `--encoding` is an alias for
-{option -E}[rdoc-ref:ruby/options.md@E-3A+Set+Default+Encodings].
-
-### `--external-encoding`: Set Default External \Encoding
-
-Option `--external-encoding`
-sets the default external encoding for the invoked Ruby program;
-for values of +encoding+,
-see {Encoding: Names and Aliases}[rdoc-ref:encodings.rdoc@Names+and+Aliases].
-
-```console
-$ ruby -e 'puts Encoding::default_external'
-UTF-8
-$ ruby --external-encoding=cesu-8 -e 'puts Encoding::default_external'
-CESU-8
-```
-
-### `--help`: Print Help Message
-
-Option `--help` prints a long help message.
-
-Arguments and additional options are ignored.
-
-For a shorter help message, use option `-h`.
-
-### `--internal-encoding`: Set Default Internal \Encoding
-
-Option `--internal-encoding`
-sets the default internal encoding for the invoked Ruby program;
-for values of +encoding+,
-see {Encoding: Names and Aliases}[rdoc-ref:encodings.rdoc@Names+and+Aliases].
-
-```console
-$ ruby -e 'puts Encoding::default_internal.nil?'
-true
-$ ruby --internal-encoding=cesu-8 -e 'puts Encoding::default_internal'
-CESU-8
-```
-
-### `--verbose`: Set `$VERBOSE`
-
-Option `--verbose` sets global variable `$VERBOSE` to `true`
-and disables input from `$stdin`.
-
-### `--version`: Print Ruby Version
-
-Option `--version` prints the version of the Ruby interpreter, then exits.
-
-## Experimental Options
-
-These options are experimental in the current Ruby release,
-and may be modified or withdrawn in later releases.
-
-### `--jit`
-
-Option `-jit` enables JIT compilation with the default option.
-
-#### `--jit-debug`
-
-Option `--jit-debug` enables JIT debugging (very slow);
-adds compiler flags if given.
-
-#### `--jit-max-cache=num`
-
-Option `--jit-max-cache=num` sets the maximum number of methods
-to be JIT-ed in a cache; default: 100).
-
-#### `--jit-min-calls=num`
-
-Option `jit-min-calls=num` sets the minimum number of calls to trigger JIT
-(for testing); default: 10000).
-
-#### `--jit-save-temps`
-
-Option `--jit-save-temps` saves JIT temporary files in $TMP or /tmp (for testing).
-
-#### `--jit-verbose`
-
-Option `--jit-verbose` prints JIT logs of level `num` or less
-to `$stderr`; default: 0.
-
-#### `--jit-wait`
-
-Option `--jit-wait` waits until JIT compilation finishes every time (for testing).
-
-#### `--jit-warnings`
-
-Option `--jit-warnings` enables printing of JIT warnings.
-
diff --git a/doc/security.rdoc b/doc/security.rdoc
deleted file mode 100644
index e428036cf5..0000000000
--- a/doc/security.rdoc
+++ /dev/null
@@ -1,139 +0,0 @@
-= Ruby Security
-
-The Ruby programming language is large and complex and there are many security
-pitfalls often encountered by newcomers and experienced Rubyists alike.
-
-This document aims to discuss many of these pitfalls and provide more secure
-alternatives where applicable.
-
-Please check the full list of publicly known CVEs and how to correctly report a
-security vulnerability, at: https://www.ruby-lang.org/en/security/
-Japanese version is here: https://www.ruby-lang.org/ja/security/
-
-Security vulnerabilities should be reported via an email to
-mailto:security@ruby-lang.org ({the PGP public
-key}[https://www.ruby-lang.org/security.asc]), which is a private mailing list.
-Reported problems will be published after fixes.
-
-== +Marshal.load+
-
-Ruby's +Marshal+ module provides methods for serializing and deserializing Ruby
-object trees to and from a binary data format.
-
-Never use +Marshal.load+ to deserialize untrusted or user supplied data.
-Because +Marshal+ can deserialize to almost any Ruby object and has full
-control over instance variables, it is possible to craft a malicious payload
-that executes code shortly after deserialization.
-
-If you need to deserialize untrusted data, you should use JSON as it is only
-capable of returning 'primitive' types such as strings, arrays, hashes, numbers
-and nil. If you need to deserialize other classes, you should handle this
-manually. Never deserialize to a user specified class.
-
-== YAML
-
-YAML is a popular human readable data serialization format used by many Ruby
-programs for configuration and database persistence of Ruby object trees.
-
-Similar to +Marshal+, it is able to deserialize into arbitrary Ruby classes.
-For example, the following YAML data will create an +ERB+ object when
-deserialized, using the `unsafe_load` method:
-
- !ruby/object:ERB
- src: puts `uname`
-
-Because of this, many of the security considerations applying to Marshal are
-also applicable to YAML. Do not use YAML to deserialize untrusted data.
-
-== Symbols
-
-Symbols are often seen as syntax sugar for simple strings, but they play a much
-more crucial role. The MRI Ruby implementation uses Symbols internally for
-method, variable and constant names. The reason for this is that symbols are
-simply integers with names attached to them, so they are faster to look up in
-hashtables.
-
-Starting in version 2.2, most symbols can be garbage collected; these are
-called <i>mortal</i> symbols. Most symbols you create (e.g. by calling
-+to_sym+) are mortal.
-
-<i>Immortal</i> symbols on the other hand will never be garbage collected.
-They are created when modifying code:
-* defining a method (e.g. with +define_method+),
-* setting an instance variable (e.g. with +instance_variable_set+),
-* creating a variable or constant (e.g. with +const_set+)
-C extensions that have not been updated and are still calling `SYM2ID`
-will create immortal symbols.
-Bugs in 2.2.0: +send+ and +__send__+ also created immortal symbols,
-and calling methods with keyword arguments could also create some.
-
-Don't create immortal symbols from user inputs. Otherwise, this would
-allow a user to mount a denial of service attack against your application by
-flooding it with unique strings, which will cause memory to grow indefinitely
-until the Ruby process is killed or causes the system to slow to a halt.
-
-While it might not be a good idea to call these with user inputs, methods that
-used to be vulnerable such as +to_sym+, +respond_to?+,
-+method+, +instance_variable_get+, +const_get+, etc. are no longer a threat.
-
-== Regular expressions
-
-Ruby's regular expression syntax has some minor differences when compared to
-other languages. In Ruby, the <code>^</code> and <code>$</code> anchors do not
-refer to the beginning and end of the string, rather the beginning and end of a
-*line*.
-
-This means that if you're using a regular expression like
-<code>/^[a-z]+$/</code> to restrict a string to only letters, an attacker can
-bypass this check by passing a string containing a letter, then a newline, then
-any string of their choosing.
-
-If you want to match the beginning and end of the entire string in Ruby, use
-the anchors +\A+ and +\z+.
-
-== +eval+
-
-Never pass untrusted or user controlled input to +eval+.
-
-Unless you are implementing a REPL like +irb+ or +pry+, +eval+ is almost
-certainly not what you want. Do not attempt to filter user input before passing
-it to +eval+ - this approach is fraught with danger and will most likely open
-your application up to a serious remote code execution vulnerability.
-
-== +send+
-
-'Global functions' in Ruby (+puts+, +exit+, etc.) are actually private instance
-methods on +Object+. This means it is possible to invoke these methods with
-+send+, even if the call to +send+ has an explicit receiver.
-
-For example, the following code snippet writes "Hello world" to the terminal:
-
- 1.send(:puts, "Hello world")
-
-You should never call +send+ with user supplied input as the first parameter.
-Doing so can introduce a denial of service vulnerability:
-
- foo.send(params[:bar]) # params[:bar] is "exit!"
-
-If an attacker can control the first two arguments to +send+, remote code
-execution is possible:
-
- # params is { :a => "eval", :b => "...ruby code to be executed..." }
- foo.send(params[:a], params[:b])
-
-When dispatching a method call based on user input, carefully verify that the
-method name. If possible, check it against a whitelist of safe method names.
-
-Note that the use of +public_send+ is also dangerous, as +send+ itself is
-public:
-
- 1.public_send("send", "eval", "...ruby code to be executed...")
-
-== DRb
-
-As DRb allows remote clients to invoke arbitrary methods, it is not suitable to
-expose to untrusted clients.
-
-When using DRb, try to avoid exposing it over the network if possible. If this
-isn't possible and you need to expose DRb to the world, you *must* configure an
-appropriate security policy with <code>DRb::ACL</code>.
diff --git a/doc/security/command_injection.rdoc b/doc/security/command_injection.rdoc
new file mode 100644
index 0000000000..d46e42f7be
--- /dev/null
+++ b/doc/security/command_injection.rdoc
@@ -0,0 +1,15 @@
+= Command Injection
+
+Some Ruby core methods accept string data
+that includes text to be executed as a system command.
+
+They should not be called with unknown or unsanitized commands.
+
+These methods include:
+
+- Kernel.exec
+- Kernel.spawn
+- Kernel.system
+- {\`command` (backtick method)}[rdoc-ref:Kernel#`]
+ (also called by the expression <tt>%x[command]</tt>).
+- IO.popen (when called with other than <tt>"-"</tt>).
diff --git a/doc/security/security.rdoc b/doc/security/security.rdoc
new file mode 100644
index 0000000000..af9970d336
--- /dev/null
+++ b/doc/security/security.rdoc
@@ -0,0 +1,127 @@
+= Ruby Security
+
+The Ruby programming language is large and complex and there are many security
+pitfalls often encountered by newcomers and experienced Rubyists alike.
+
+This document aims to discuss many of these pitfalls and provide more secure
+alternatives where applicable.
+
+Please check the full list of publicly known CVEs and how to correctly report a
+security vulnerability, at: https://www.ruby-lang.org/en/security/
+Japanese version is here: https://www.ruby-lang.org/ja/security/
+
+Security vulnerabilities should be reported via an email to
+mailto:security@ruby-lang.org ({the PGP public
+key}[https://www.ruby-lang.org/security.asc]), which is a private mailing list.
+Reported problems will be published after fixes.
+
+== +Marshal.load+
+
+Ruby's +Marshal+ module provides methods for serializing and deserializing Ruby
+object trees to and from a binary data format.
+
+Never use +Marshal.load+ to deserialize untrusted or user supplied data.
+Because +Marshal+ can deserialize to almost any Ruby object and has full
+control over instance variables, it is possible to craft a malicious payload
+that executes code shortly after deserialization.
+
+If you need to deserialize untrusted data, you should use JSON as it is only
+capable of returning 'primitive' types such as strings, arrays, hashes, numbers
+and nil. If you need to deserialize other classes, you should handle this
+manually. Never deserialize to a user specified class.
+
+== YAML
+
+YAML is a popular human readable data serialization format used by many Ruby
+programs for configuration and database persistence of Ruby object trees.
+
+Similar to +Marshal+, it is able to deserialize into arbitrary Ruby classes.
+For example, the following YAML data will create an +ERB+ object when
+deserialized, using the +unsafe_load+ method:
+
+ !ruby/object:ERB
+ src: puts `uname`
+
+Because of this, many of the security considerations applying to Marshal are
+also applicable to YAML. Do not use YAML to deserialize untrusted data.
+
+== Symbols
+
+Symbols are often seen as syntax sugar for simple strings, but they play a much
+more crucial role. The MRI Ruby implementation uses Symbols internally for
+method, variable and constant names. The reason for this is that symbols are
+simply integers with names attached to them, so they are faster to look up in
+hashtables.
+
+Most symbols can be garbage collected; these are called _mortal_
+symbols. Most symbols you create (e.g. by calling +to_sym+) are mortal.
+
+_Immortal_ symbols on the other hand will never be garbage collected.
+They are created when modifying code:
+* defining a method (e.g. with +define_method+),
+* setting an instance variable (e.g. with +instance_variable_set+),
+* creating a variable or constant (e.g. with +const_set+)
+C extensions that have not been updated and are still calling +SYM2ID+
+will create immortal symbols.
+
+Don't create immortal symbols from user inputs. Otherwise, this would
+allow a user to mount a denial of service attack against your application by
+flooding it with unique strings, which will cause memory to grow indefinitely
+until the Ruby process is killed or causes the system to slow to a halt.
+
+While it might not be a good idea to call these with user inputs, methods that
+used to be vulnerable such as +to_sym+, +respond_to?+,
++method+, +instance_variable_get+, +const_get+, etc. are no longer a threat.
+
+== Regular expressions
+
+Ruby's regular expression syntax has some minor differences when compared to
+other languages. In Ruby, the <code>^</code> and <code>$</code> anchors do not
+refer to the beginning and end of the string, rather the beginning and end of a
+*line*.
+
+This means that if you're using a regular expression like
+<code>/^[a-z]+$/</code> to restrict a string to only letters, an attacker can
+bypass this check by passing a string containing a letter, then a newline, then
+any string of their choosing.
+
+If you want to match the beginning and end of the entire string in Ruby, use
+the anchors +\A+ and +\z+.
+
+== +eval+
+
+Never pass untrusted or user controlled input to +eval+.
+
+Unless you are implementing a REPL like +irb+ or +pry+, +eval+ is almost
+certainly not what you want. Do not attempt to filter user input before passing
+it to +eval+ - this approach is fraught with danger and will most likely open
+your application up to a serious remote code execution vulnerability.
+
+== +send+
+
+'Global functions' in Ruby (+puts+, +exit+, etc.) are actually private instance
+methods on +Object+. This means it is possible to invoke these methods with
++send+, even if the call to +send+ has an explicit receiver.
+
+For example, the following code snippet writes "Hello world" to the terminal:
+
+ 1.send(:puts, "Hello world")
+
+You should never call +send+ with user supplied input as the first parameter.
+Doing so can introduce a denial of service vulnerability:
+
+ foo.send(params[:bar]) # params[:bar] is "exit!"
+
+If an attacker can control the first two arguments to +send+, remote code
+execution is possible:
+
+ # params is { :a => "eval", :b => "...ruby code to be executed..." }
+ foo.send(params[:a], params[:b])
+
+When dispatching a method call based on user input, carefully verify that the
+method name. If possible, check it against a whitelist of safe method names.
+
+Note that the use of +public_send+ is also dangerous, as +send+ itself is
+public:
+
+ 1.public_send("send", "eval", "...ruby code to be executed...")
diff --git a/doc/signals.rdoc b/doc/signals.rdoc
deleted file mode 100644
index 403eb66549..0000000000
--- a/doc/signals.rdoc
+++ /dev/null
@@ -1,106 +0,0 @@
-= Caveats for implementing Signal.trap callbacks
-
-As with implementing signal handlers in C or most other languages,
-all code passed to Signal.trap must be reentrant. If you are not
-familiar with reentrancy, you need to read up on it at
-{Wikipedia}[https://en.wikipedia.org/wiki/Reentrancy_(computing)] or
-elsewhere before reading the rest of this document.
-
-Most importantly, "thread-safety" does not guarantee reentrancy;
-and methods such as Mutex#lock and Mutex#synchronize which are
-commonly used for thread-safety even prevent reentrancy.
-
-== An implementation detail of the Ruby VM
-
-The Ruby VM defers Signal.trap callbacks from running until it is safe
-for its internal data structures, but it does not know when it is safe
-for data structures in YOUR code. Ruby implements deferred signal
-handling by registering short C functions with only
-{async-signal-safe functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html] as
-signal handlers. These short C functions only do enough tell the VM to
-run callbacks registered via Signal.trap later in the main Ruby Thread.
-
-== Unsafe methods to call in Signal.trap blocks
-
-When in doubt, consider anything not listed as safe below as being
-unsafe.
-
-* Mutex#lock, Mutex#synchronize and any code using them are explicitly
- unsafe. This includes Monitor in the standard library which uses
- Mutex to provide reentrancy.
-
-* Dir.chdir with block
-
-* any IO write operations when IO#sync is false;
- including IO#write, IO#write_nonblock, IO#puts.
- Pipes and sockets default to `IO#sync = true', so it is safe to
- write to them unless IO#sync was disabled.
-
-* File#flock, as the underlying flock(2) call is not specified by POSIX
-
-== Commonly safe operations inside Signal.trap blocks
-
-* Assignment and retrieval of local, instance, and class variables
-
-* Most object allocations and initializations of common types
- including Array, Hash, String, Struct, Time.
-
-* Common Array, Hash, String, Struct operations which do not execute a block
- are generally safe; but beware if iteration is occurring elsewhere.
-
-* Hash#[], Hash#[]= (unless Hash.new was given an unsafe block)
-
-* Thread::Queue#push and Thread::SizedQueue#push (since Ruby 2.1)
-
-* Creating a new Thread via Thread.new/Thread.start can used to get
- around the unusability of Mutexes inside a signal handler
-
-* Signal.trap is safe to use inside blocks passed to Signal.trap
-
-* arithmetic on Integer and Float (`+', `-', '%', '*', '/')
-
- Additionally, signal handlers do not run between two successive
- local variable accesses, so shortcuts such as `+=' and `-=' will
- not trigger a data race when used on Integer and Float classes in
- signal handlers.
-
-== System call wrapper methods which are safe inside Signal.trap
-
-Since Ruby has wrappers around many
-{async-signal-safe C functions}[http://man7.org/linux/man-pages/man7/signal-safety.7.html]
-the corresponding wrappers for many IO, File, Dir, and Socket methods
-are safe.
-
-(Incomplete list)
-
-* Dir.chdir (without block arg)
-* Dir.mkdir
-* Dir.open
-* File#truncate
-* File.link
-* File.open
-* File.readlink
-* File.rename
-* File.stat
-* File.symlink
-* File.truncate
-* File.unlink
-* File.utime
-* IO#close
-* IO#dup
-* IO#fsync
-* IO#read
-* IO#read_nonblock
-* IO#stat
-* IO#sysread
-* IO#syswrite
-* IO.select
-* IO.pipe
-* Process.clock_gettime
-* Process.exit!
-* Process.fork
-* Process.kill
-* Process.pid
-* Process.ppid
-* Process.waitpid
-...
diff --git a/doc/standard_library.md b/doc/standard_library.md
index a6702bb80f..782db10c37 100644
--- a/doc/standard_library.md
+++ b/doc/standard_library.md
@@ -11,6 +11,7 @@ of each.
- `MakeMakefile`: A module used to generate a Makefile for C extensions
- `RbConfig`: Information about your Ruby configuration and build
- `Gem`: A package management framework for Ruby
+- `Pathname`: Representation of the name of a file or directory on the filesystem. Pathname is a core class, but only methods that depend on other libraries are provided as a library.
## Extensions
@@ -34,7 +35,6 @@ of each.
## Libraries
- Bundler ([GitHub][bundler]): Manage your Ruby application's gem dependencies
-- CGI ([GitHub][cgi]): Support for the Common Gateway Interface protocol
- Delegator ([GitHub][delegate]): Provides three abilities to delegate method calls to an object
- DidYouMean ([GitHub][did_you_mean]): "Did you mean?" experience in Ruby
- English ([GitHub][English]): Provides references to special global variables with less cryptic names
@@ -53,13 +53,12 @@ of each.
- Prism ([GitHub][prism]): A portable, error-tolerant Ruby parser
- Resolv ([GitHub][resolv]): Thread-aware DNS resolver library in Ruby
- SecureRandom ([GitHub][securerandom]): Interface for a secure random number generator
-- [Set](rdoc-ref:Set) ([GitHub][set]): Provides a class to deal with collections of unordered, unique values
- Shellwords ([GitHub][shellwords]): Manipulates strings with the word parsing rules of the UNIX Bourne shell
- Singleton ([GitHub][singleton]): Implementation of the Singleton pattern for Ruby
- Tempfile ([GitHub][tempfile]): A utility class for managing temporary files
- Time ([GitHub][time]): Extends the Time class with methods for parsing and conversion
- Timeout ([GitHub][timeout]): Auto-terminate potentially long-running operations in Ruby
-- TSort ([GitHub][tsort]): Topological sorting using Tarjan's algorithm
+- TmpDir ([GitHub][tmpdir]): Extends the Dir class to manage the OS temporary file path
- UN ([GitHub][un]): Utilities to replace common UNIX commands
- URI ([GitHub][uri]): A Ruby module providing support for Uniform Resource Identifiers
- YAML ([GitHub][yaml]): The Ruby client library for the Psych YAML implementation
@@ -72,13 +71,13 @@ of each.
- Etc ([GitHub][etc]): Provides access to information typically stored in the UNIX /etc directory
- Fcntl ([GitHub][fcntl]): Loads constants defined in the OS fcntl.h C header file
- IO.console ([GitHub][io-console]): Extensions for the IO class, including `IO.console`, `IO.winsize`, etc.
+- IO#nonblock ([GitHub][io-nonblock]): Enable non-blocking mode with IO class.
+- IO#wait ([GitHub][io-wait]): Provides the feature for waiting until IO is readable or writable without blocking.
- JSON ([GitHub][json]): Implements JavaScript Object Notation for Ruby
- OpenSSL ([GitHub][openssl]): Provides SSL, TLS, and general-purpose cryptography for Ruby
-- Pathname ([GitHub][pathname]): Representation of the name of a file or directory on the filesystem
- Psych ([GitHub][psych]): A YAML parser and emitter for Ruby
- StringIO ([GitHub][stringio]): Pseudo-I/O on String objects
- StringScanner ([GitHub][strscan]): Provides lexical scanning operations on a String
-- TmpDir ([GitHub][tmpdir]): Extends the Dir class to manage the OS temporary file path
- Zlib ([GitHub][zlib]): Ruby interface for the zlib compression/decompression library
# Bundled gems
@@ -92,20 +91,18 @@ of each.
- [minitest]: A test library supporting TDD, BDD, mocking, and benchmarking
- [power_assert]: Power Assert for Ruby
-- [rake]: Ruby build program with capabilities similar to make
+- [rake][rake-doc] ([GitHub][rake]): Ruby build program with capabilities similar to make
- [test-unit]: A compatibility layer for MiniTest
-- [rexml]: An XML toolkit for Ruby
+- [rexml][rexml-doc] ([GitHub][rexml]): An XML toolkit for Ruby
- [rss]: A family of libraries supporting various XML-based "feeds"
-- [net-ftp]: Support for the File Transfer Protocol
- [net-imap]: Ruby client API for the Internet Message Access Protocol
-- [net-pop]: Ruby client library for POP3
- [net-smtp]: Simple Mail Transfer Protocol client library for Ruby
- [matrix]: Represents a mathematical matrix
- [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
- [debug]: Debugging functionality for Ruby
-- [racc]: A LALR(1) parser generator written in Ruby
+- [racc][racc-doc] ([GitHub][racc]): A LALR(1) parser generator written in Ruby
- [mutex_m]: Mixin to extend objects to be handled like a Mutex
- [getoptlong]: Parse command line options similar to the GNU C getopt_long()
- [base64]: Support for encoding and decoding binary data using a Base64 representation
@@ -117,15 +114,17 @@ of each.
- [drb]: Distributed object system for Ruby
- [nkf]: Ruby extension for the Network Kanji Filter
- [syslog]: Ruby interface for the POSIX system logging facility
-- [csv]: Provides an interface to read and write CSV files and data
+- [csv][csv-doc] ([GitHub][csv]): Provides an interface to read and write CSV files and data
- [ostruct]: A class to build custom data structures, similar to a Hash
- [benchmark]: Provides methods to measure and report the time used to execute code
-- [logger]: Provides a simple logging utility for outputting messages
+- [logger][logger-doc] ([GitHub][logger]): Provides a simple logging utility for outputting messages
- [pstore]: Implements a file-based persistence mechanism based on a Hash
- [win32ole]: Provides an interface for OLE Automation in Ruby
-- [reline]: GNU Readline and Editline in a pure Ruby implementation
+- [reline][reline-doc] ([GitHub][reline]): GNU Readline and Editline in a pure Ruby implementation
- [readline]: Wrapper for the Readline extension and Reline
- [fiddle]: A libffi wrapper for Ruby
+- [tsort]: Topological sorting using Tarjan's algorithm
+- [win32-registry]: Registry accessor library for the Windows platform.
## Tools
@@ -137,7 +136,6 @@ of each.
[benchmark]: https://github.com/ruby/benchmark
[bigdecimal]: https://github.com/ruby/bigdecimal
[bundler]: https://github.com/rubygems/rubygems
-[cgi]: https://github.com/ruby/cgi
[csv]: https://github.com/ruby/csv
[date]: https://github.com/ruby/date
[debug]: https://github.com/ruby/debug
@@ -156,6 +154,8 @@ of each.
[forwardable]: https://github.com/ruby/forwardable
[getoptlong]: https://github.com/ruby/getoptlong
[io-console]: https://github.com/ruby/io-console
+[io-nonblock]: https://github.com/ruby/io-nonblock
+[io-wait]: https://github.com/ruby/io-wait
[ipaddr]: https://github.com/ruby/ipaddr
[irb]: https://github.com/ruby/irb
[json]: https://github.com/ruby/json
@@ -163,10 +163,8 @@ of each.
[matrix]: https://github.com/ruby/matrix
[minitest]: https://github.com/seattlerb/minitest
[mutex_m]: https://github.com/ruby/mutex_m
-[net-ftp]: https://github.com/ruby/net-ftp
[net-http]: https://github.com/ruby/net-http
[net-imap]: https://github.com/ruby/net-imap
-[net-pop]: https://github.com/ruby/net-pop
[net-smtp]: https://github.com/ruby/net-smtp
[nkf]: https://github.com/ruby/nkf
[observer]: https://github.com/ruby/observer
@@ -195,7 +193,6 @@ of each.
[rinda]: https://github.com/ruby/rinda
[rss]: https://github.com/ruby/rss
[securerandom]: https://github.com/ruby/securerandom
-[set]: https://github.com/ruby/set
[shellwords]: https://github.com/ruby/shellwords
[singleton]: https://github.com/ruby/singleton
[stringio]: https://github.com/ruby/stringio
@@ -212,8 +209,15 @@ of each.
[uri]: https://github.com/ruby/uri
[weakref]: https://github.com/ruby/weakref
[win32ole]: https://github.com/ruby/win32ole
+[win32-registry]: https://github.com/ruby/win32-registry
[yaml]: https://github.com/ruby/yaml
[zlib]: https://github.com/ruby/zlib
+[reline-doc]: https://ruby.github.io/reline/
+[rake-doc]: https://ruby.github.io/rake/
[irb-doc]: https://ruby.github.io/irb/
[rdoc-doc]: https://ruby.github.io/rdoc/
+[logger-doc]: https://ruby.github.io/logger/
+[racc-doc]: https://ruby.github.io/racc/
+[csv-doc]: https://ruby.github.io/csv/
+[rexml-doc]: https://ruby.github.io/rexml/
diff --git a/doc/strftime_formatting.rdoc b/doc/strftime_formatting.rdoc
deleted file mode 100644
index 5c7b33155d..0000000000
--- a/doc/strftime_formatting.rdoc
+++ /dev/null
@@ -1,527 +0,0 @@
-= 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:
-
-- Date#strftime.
-- DateTime#strftime.
-- Time#strftime.
-
-Each of these methods takes optional argument +format+,
-which has zero or more embedded _format_ _specifications_ (see below).
-
-Each of these methods returns the string resulting from replacing each
-format specification embedded in +format+ with a string form
-of one or more parts of the date or time.
-
-A simple example:
-
- Time.now.strftime('%H:%M:%S') # => "14:02:07"
-
-A format specification has the form:
-
- %[flags][width]conversion
-
-It consists of:
-
-- A leading percent character.
-- Zero or more _flags_ (each is a character).
-- An optional _width_ _specifier_ (an integer).
-- A _conversion_ _specifier_ (a character).
-
-Except for the leading percent character,
-the only required part is the conversion specifier, so we begin with that.
-
-== Conversion Specifiers
-
-=== \Date (Year, Month, Day)
-
-- <tt>%Y</tt> - Year including century, zero-padded:
-
- Time.now.strftime('%Y') # => "2022"
- Time.new(-1000).strftime('%Y') # => "-1000" # Before common era.
- Time.new(10000).strftime('%Y') # => "10000" # Far future.
- Time.new(10).strftime('%Y') # => "0010" # Zero-padded by default.
-
-- <tt>%y</tt> - Year without century, in range (0.99), zero-padded:
-
- Time.now.strftime('%y') # => "22"
- Time.new(1).strftime('%y') # => "01" # Zero-padded by default.
-
-- <tt>%C</tt> - Century, zero-padded:
-
- Time.now.strftime('%C') # => "20"
- Time.new(-1000).strftime('%C') # => "-10" # Before common era.
- Time.new(10000).strftime('%C') # => "100" # Far future.
- Time.new(100).strftime('%C') # => "01" # Zero-padded by default.
-
-- <tt>%m</tt> - Month of the year, in range (1..12), zero-padded:
-
- Time.new(2022, 1).strftime('%m') # => "01" # Zero-padded by default.
- Time.new(2022, 12).strftime('%m') # => "12"
-
-- <tt>%B</tt> - Full month name, capitalized:
-
- Time.new(2022, 1).strftime('%B') # => "January"
- Time.new(2022, 12).strftime('%B') # => "December"
-
-- <tt>%b</tt> - Abbreviated month name, capitalized:
-
- Time.new(2022, 1).strftime('%b') # => "Jan"
- Time.new(2022, 12).strftime('%h') # => "Dec"
-
-- <tt>%h</tt> - Same as <tt>%b</tt>.
-
-- <tt>%d</tt> - Day of the month, in range (1..31), zero-padded:
-
- Time.new(2002, 1, 1).strftime('%d') # => "01"
- Time.new(2002, 1, 31).strftime('%d') # => "31"
-
-- <tt>%e</tt> - Day of the month, in range (1..31), blank-padded:
-
- Time.new(2002, 1, 1).strftime('%e') # => " 1"
- Time.new(2002, 1, 31).strftime('%e') # => "31"
-
-- <tt>%j</tt> - Day of the year, in range (1..366), zero-padded:
-
- Time.new(2002, 1, 1).strftime('%j') # => "001"
- Time.new(2002, 12, 31).strftime('%j') # => "365"
-
-=== \Time (Hour, Minute, Second, Subsecond)
-
-- <tt>%H</tt> - Hour of the day, in range (0..23), zero-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%H') # => "01"
- Time.new(2022, 1, 1, 13).strftime('%H') # => "13"
-
-- <tt>%k</tt> - Hour of the day, in range (0..23), blank-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%k') # => " 1"
- Time.new(2022, 1, 1, 13).strftime('%k') # => "13"
-
-- <tt>%I</tt> - Hour of the day, in range (1..12), zero-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%I') # => "01"
- Time.new(2022, 1, 1, 13).strftime('%I') # => "01"
-
-- <tt>%l</tt> - Hour of the day, in range (1..12), blank-padded:
-
- Time.new(2022, 1, 1, 1).strftime('%l') # => " 1"
- Time.new(2022, 1, 1, 13).strftime('%l') # => " 1"
-
-- <tt>%P</tt> - Meridian indicator, lowercase:
-
- Time.new(2022, 1, 1, 1).strftime('%P') # => "am"
- Time.new(2022, 1, 1, 13).strftime('%P') # => "pm"
-
-- <tt>%p</tt> - Meridian indicator, uppercase:
-
- Time.new(2022, 1, 1, 1).strftime('%p') # => "AM"
- Time.new(2022, 1, 1, 13).strftime('%p') # => "PM"
-
-- <tt>%M</tt> - Minute of the hour, in range (0..59), zero-padded:
-
- Time.new(2022, 1, 1, 1, 0, 0).strftime('%M') # => "00"
-
-- <tt>%S</tt> - Second of the minute in range (0..59), zero-padded:
-
- Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%S') # => "00"
-
-- <tt>%L</tt> - Millisecond of the second, in range (0..999), zero-padded:
-
- Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%L') # => "000"
-
-- <tt>%N</tt> - Fractional seconds, default width is 9 digits (nanoseconds):
-
- t = Time.now # => 2022-06-29 07:10:20.3230914 -0500
- t.strftime('%N') # => "323091400" # Default.
-
- Use {width specifiers}[rdoc-ref:strftime_formatting.rdoc@Width+Specifiers]
- to adjust units:
-
- t.strftime('%3N') # => "323" # Milliseconds.
- t.strftime('%6N') # => "323091" # Microseconds.
- t.strftime('%9N') # => "323091400" # Nanoseconds.
- t.strftime('%12N') # => "323091400000" # Picoseconds.
- t.strftime('%15N') # => "323091400000000" # Femptoseconds.
- t.strftime('%18N') # => "323091400000000000" # Attoseconds.
- t.strftime('%21N') # => "323091400000000000000" # Zeptoseconds.
- t.strftime('%24N') # => "323091400000000000000000" # Yoctoseconds.
-
-- <tt>%s</tt> - Number of seconds since the epoch:
-
- Time.now.strftime('%s') # => "1656505136"
-
-=== Timezone
-
-- <tt>%z</tt> - Timezone as hour and minute offset from UTC:
-
- Time.now.strftime('%z') # => "-0500"
-
-- <tt>%Z</tt> - Timezone name (platform-dependent):
-
- Time.now.strftime('%Z') # => "Central Daylight Time"
-
-=== Weekday
-
-- <tt>%A</tt> - Full weekday name:
-
- Time.now.strftime('%A') # => "Wednesday"
-
-- <tt>%a</tt> - Abbreviated weekday name:
-
- Time.now.strftime('%a') # => "Wed"
-
-- <tt>%u</tt> - Day of the week, in range (1..7), Monday is 1:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%u') # => "7"
-
-- <tt>%w</tt> - Day of the week, in range (0..6), Sunday is 0:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%w') # => "0"
-
-=== Week Number
-
-- <tt>%U</tt> - Week number of the year, in range (0..53), zero-padded,
- where each week begins on a Sunday:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%U') # => "26"
-
-- <tt>%W</tt> - Week number of the year, in range (0..53), zero-padded,
- where each week begins on a Monday:
-
- t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500
- t.strftime('%a') # => "Sun"
- t.strftime('%W') # => "25"
-
-=== Week Dates
-
-See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
-
- t0 = Time.new(2023, 1, 1) # => 2023-01-01 00:00:00 -0600
- t1 = Time.new(2024, 1, 1) # => 2024-01-01 00:00:00 -0600
-
-- <tt>%G</tt> - Week-based year:
-
- t0.strftime('%G') # => "2022"
- t1.strftime('%G') # => "2024"
-
-- <tt>%g</tt> - Week-based year without century, in range (0..99), zero-padded:
-
- t0.strftime('%g') # => "22"
- t1.strftime('%g') # => "24"
-
-- <tt>%V</tt> - Week number of the week-based year, in range (1..53),
- zero-padded:
-
- t0.strftime('%V') # => "52"
- t1.strftime('%V') # => "01"
-
-=== Literals
-
-- <tt>%n</tt> - Newline character "\n":
-
- Time.now.strftime('%n') # => "\n"
-
-- <tt>%t</tt> - Tab character "\t":
-
- Time.now.strftime('%t') # => "\t"
-
-- <tt>%%</tt> - Percent character '%':
-
- Time.now.strftime('%%') # => "%"
-
-=== Shorthand Conversion Specifiers
-
-Each shorthand specifier here is shown with its corresponding
-longhand specifier.
-
-- <tt>%c</tt> - \Date and time:
-
- Time.now.strftime('%c') # => "Wed Jun 29 08:01:41 2022"
- Time.now.strftime('%a %b %e %T %Y') # => "Wed Jun 29 08:02:07 2022"
-
-- <tt>%D</tt> - \Date:
-
- Time.now.strftime('%D') # => "06/29/22"
- Time.now.strftime('%m/%d/%y') # => "06/29/22"
-
-- <tt>%F</tt> - ISO 8601 date:
-
- Time.now.strftime('%F') # => "2022-06-29"
- Time.now.strftime('%Y-%m-%d') # => "2022-06-29"
-
-- <tt>%v</tt> - VMS date:
-
- Time.now.strftime('%v') # => "29-JUN-2022"
- Time.now.strftime('%e-%^b-%4Y') # => "29-JUN-2022"
-
-- <tt>%x</tt> - Same as <tt>%D</tt>.
-
-- <tt>%X</tt> - Same as <tt>%T</tt>.
-
-- <tt>%r</tt> - 12-hour time:
-
- Time.new(2022, 1, 1, 1).strftime('%r') # => "01:00:00 AM"
- Time.new(2022, 1, 1, 1).strftime('%I:%M:%S %p') # => "01:00:00 AM"
- Time.new(2022, 1, 1, 13).strftime('%r') # => "01:00:00 PM"
- Time.new(2022, 1, 1, 13).strftime('%I:%M:%S %p') # => "01:00:00 PM"
-
-- <tt>%R</tt> - 24-hour time:
-
- Time.new(2022, 1, 1, 1).strftime('%R') # => "01:00"
- Time.new(2022, 1, 1, 1).strftime('%H:%M') # => "01:00"
- Time.new(2022, 1, 1, 13).strftime('%R') # => "13:00"
- Time.new(2022, 1, 1, 13).strftime('%H:%M') # => "13:00"
-
-- <tt>%T</tt> - 24-hour time:
-
- Time.new(2022, 1, 1, 1).strftime('%T') # => "01:00:00"
- Time.new(2022, 1, 1, 1).strftime('%H:%M:%S') # => "01:00:00"
- Time.new(2022, 1, 1, 13).strftime('%T') # => "13:00:00"
- Time.new(2022, 1, 1, 13).strftime('%H:%M:%S') # => "13:00:00"
-
-- <tt>%+</tt> (not supported in Time#strftime) - \Date and time:
-
- DateTime.now.strftime('%+')
- # => "Wed Jun 29 08:31:53 -05:00 2022"
- DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y')
- # => "Wed Jun 29 08:32:18 -05:00 2022"
-
-== Flags
-
-Flags may affect certain formatting specifications.
-
-Multiple flags may be given with a single conversion specified;
-order does not matter.
-
-=== Padding Flags
-
-- <tt>0</tt> - Pad with zeroes:
-
- Time.new(10).strftime('%0Y') # => "0010"
-
-- <tt>_</tt> - Pad with blanks:
-
- Time.new(10).strftime('%_Y') # => " 10"
-
-- <tt>-</tt> - Don't pad:
-
- Time.new(10).strftime('%-Y') # => "10"
-
-=== Casing Flags
-
-- <tt>^</tt> - Upcase result:
-
- Time.new(2022, 1).strftime('%B') # => "January" # No casing flag.
- Time.new(2022, 1).strftime('%^B') # => "JANUARY"
-
-- <tt>#</tt> - Swapcase result:
-
- Time.now.strftime('%p') # => "AM"
- Time.now.strftime('%^p') # => "AM"
- Time.now.strftime('%#p') # => "am"
-
-=== Timezone Flags
-
-- <tt>:</tt> - Put timezone as colon-separated hours and minutes:
-
- Time.now.strftime('%:z') # => "-05:00"
-
-- <tt>::</tt> - Put timezone as colon-separated hours, minutes, and seconds:
-
- Time.now.strftime('%::z') # => "-05:00:00"
-
-== Width Specifiers
-
-The integer width specifier gives a minimum width for the returned string:
-
- Time.new(2002).strftime('%Y') # => "2002" # No width specifier.
- Time.new(2002).strftime('%10Y') # => "0000002002"
- Time.new(2002, 12).strftime('%B') # => "December" # No width specifier.
- Time.new(2002, 12).strftime('%10B') # => " December"
- Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
-
-= Specialized Format Strings
-
-Here are a few specialized format strings,
-each based on an external standard.
-
-== HTTP Format
-
-The HTTP date format is based on
-{RFC 2616}[https://www.rfc-editor.org/rfc/rfc2616],
-and treats dates in the format <tt>'%a, %d %b %Y %T GMT'</tt>:
-
- d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
- # Return HTTP-formatted string.
- httpdate = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
- # Return new date parsed from HTTP-formatted string.
- Date.httpdate(httpdate) # => #<Date: 2001-02-03>
- # Return hash parsed from HTTP-formatted string.
- Date._httpdate(httpdate)
- # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
-
-== RFC 3339 Format
-
-The RFC 3339 date format is based on
-{RFC 3339}[https://www.rfc-editor.org/rfc/rfc3339]:
-
- d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
- # Return 3339-formatted string.
- rfc3339 = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
- # Return new date parsed from 3339-formatted string.
- Date.rfc3339(rfc3339) # => #<Date: 2001-02-03>
- # Return hash parsed from 3339-formatted string.
- Date._rfc3339(rfc3339)
- # => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
-
-== RFC 2822 Format
-
-The RFC 2822 date format is based on
-{RFC 2822}[https://www.rfc-editor.org/rfc/rfc2822],
-and treats dates in the format <tt>'%a, %-d %b %Y %T %z'</tt>]:
-
- d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
- # Return 2822-formatted string.
- rfc2822 = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
- # Return new date parsed from 2822-formatted string.
- Date.rfc2822(rfc2822) # => #<Date: 2001-02-03>
- # Return hash parsed from 2822-formatted string.
- 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
-
-The JIS X 0301 format includes the
-{Japanese era name}[https://en.wikipedia.org/wiki/Japanese_era_name],
-and treats dates in the format <tt>'%Y-%m-%d'</tt>
-with the first letter of the romanized era name prefixed:
-
- d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
- # Return 0301-formatted string.
- jisx0301 = d.jisx0301 # => "H13.02.03"
- # Return new date parsed from 0301-formatted string.
- Date.jisx0301(jisx0301) # => #<Date: 2001-02-03>
- # Return hash parsed from 0301-formatted string.
- Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
-
-== ISO 8601 Format Specifications
-
-This section shows format specifications that are compatible with
-{ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601].
-Details for various formats may be seen at the links.
-
-Examples in this section assume:
-
- t = Time.now # => 2022-06-29 16:49:25.465246 -0500
-
-=== Dates
-
-See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
-
-- {Years}[https://en.wikipedia.org/wiki/ISO_8601#Years]:
-
- - Basic year (+YYYY+):
-
- t.strftime('%Y') # => "2022"
-
- - Expanded year (<tt>±YYYYY</tt>):
-
- t.strftime('+%5Y') # => "+02022"
- t.strftime('-%5Y') # => "-02022"
-
-- {Calendar dates}[https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates]:
-
- - Basic date (+YYYYMMDD+):
-
- t.strftime('%Y%m%d') # => "20220629"
-
- - Extended date (<tt>YYYY-MM-DD</tt>):
-
- t.strftime('%Y-%m-%d') # => "2022-06-29"
-
- - Reduced extended date (<tt>YYYY-MM</tt>):
-
- t.strftime('%Y-%m') # => "2022-06"
-
-- {Week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates]:
-
- - Basic date (+YYYYWww+ or +YYYYWwwD+):
-
- t.strftime('%Y%Ww') # => "202226w"
- t.strftime('%Y%Ww%u') # => "202226w3"
-
- - Extended date (<tt>YYYY-Www</tt> or <tt>YYYY-Www-D<tt>):
-
- t.strftime('%Y-%Ww') # => "2022-26w"
- t.strftime('%Y-%Ww-%u') # => "2022-26w-3"
-
-- {Ordinal dates}[https://en.wikipedia.org/wiki/ISO_8601#Ordinal_dates]:
-
- - Basic date (+YYYYDDD+):
-
- t.strftime('%Y%j') # => "2022180"
-
- - Extended date (<tt>YYYY-DDD</tt>):
-
- t.strftime('%Y-%j') # => "2022-180"
-
-=== Times
-
-See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
-
-- Times:
-
- - Basic time (+Thhmmss.sss+, +Thhmmss+, +Thhmm+, or +Thh+):
-
- t.strftime('T%H%M%S.%L') # => "T164925.465"
- t.strftime('T%H%M%S') # => "T164925"
- t.strftime('T%H%M') # => "T1649"
- t.strftime('T%H') # => "T16"
-
- - Extended time (+Thh:mm:ss.sss+, +Thh:mm:ss+, or +Thh:mm+):
-
- t.strftime('T%H:%M:%S.%L') # => "T16:49:25.465"
- t.strftime('T%H:%M:%S') # => "T16:49:25"
- t.strftime('T%H:%M') # => "T16:49"
-
-- {Time zone designators}[https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators]:
-
- - Timezone (+time+ represents a valid time,
- +hh+ represents a valid 2-digit hour,
- and +mm+ represents a valid 2-digit minute):
-
- - Basic timezone (<tt>time±hhmm</tt>, <tt>time±hh</tt>, or +timeZ+):
-
- t.strftime('T%H%M%S%z') # => "T164925-0500"
- t.strftime('T%H%M%S%z').slice(0..-3) # => "T164925-05"
- t.strftime('T%H%M%SZ') # => "T164925Z"
-
- - Extended timezone (<tt>time±hh:mm</tt>):
-
- t.strftime('T%H:%M:%S%z') # => "T16:49:25-0500"
-
- - See also:
-
- - {Local time (unqualified)}[https://en.wikipedia.org/wiki/ISO_8601#Local_time_(unqualified)].
- - {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
-
-See {ISO 8601 Combined date and time representations}[https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations].
-
-An ISO 8601 combined date and time representation may be any
-ISO 8601 date and any ISO 8601 time,
-separated by the letter +T+.
-
-For the relevant +strftime+ formats, see
-{Dates}[rdoc-ref:strftime_formatting.rdoc@Dates]
-and {Times}[rdoc-ref:strftime_formatting.rdoc@Times] above.
diff --git a/doc/string.rb b/doc/string.rb
new file mode 100644
index 0000000000..4dac94e93a
--- /dev/null
+++ b/doc/string.rb
@@ -0,0 +1,421 @@
+# A +String+ object has an arbitrary sequence of bytes,
+# typically representing text or binary data.
+# A +String+ object may be created using String::new or as literals.
+#
+# String objects differ from Symbol objects in that Symbol objects are
+# designed to be used as identifiers, instead of text or data.
+#
+# You can create a +String+ object explicitly with:
+#
+# - A {string literal}[rdoc-ref:syntax/literals.rdoc@String+Literals].
+# - A {heredoc literal}[rdoc-ref:syntax/literals.rdoc@Here+Document+Literals].
+#
+# You can convert certain objects to Strings with:
+#
+# - Method #String.
+#
+# Some +String+ methods modify +self+.
+# Typically, a method whose name ends with <tt>!</tt> modifies +self+
+# and returns +self+;
+# often, a similarly named method (without the <tt>!</tt>)
+# returns a new string.
+#
+# In general, if both bang and non-bang versions of a method exist,
+# the bang method mutates and the non-bang method does not.
+# However, a method without a bang can also mutate, such as String#replace.
+#
+# == Substitution Methods
+#
+# These methods perform substitutions:
+#
+# - String#sub: One substitution (or none); returns a new string.
+# - String#sub!: One substitution (or none); returns +self+ if any changes,
+# +nil+ otherwise.
+# - String#gsub: Zero or more substitutions; returns a new string.
+# - String#gsub!: Zero or more substitutions; returns +self+ if any changes,
+# +nil+ otherwise.
+#
+# Each of these methods takes:
+#
+# - A first argument, +pattern+ (String or Regexp),
+# that specifies the substring(s) to be replaced.
+#
+# - Either of the following:
+#
+# - A second argument, +replacement+ (String or Hash),
+# that determines the replacing string.
+# - A block that will determine the replacing string.
+#
+# The examples in this section mostly use the String#sub and String#gsub methods;
+# the principles illustrated apply to all four substitution methods.
+#
+# <b>Argument +pattern+</b>
+#
+# Argument +pattern+ is commonly a regular expression:
+#
+# s = 'hello'
+# s.sub(/[aeiou]/, '*') # => "h*llo"
+# s.gsub(/[aeiou]/, '*') # => "h*ll*"
+# s.gsub(/[aeiou]/, '') # => "hll"
+# s.sub(/ell/, 'al') # => "halo"
+# s.gsub(/xyzzy/, '*') # => "hello"
+# 'THX1138'.gsub(/\d+/, '00') # => "THX00"
+#
+# When +pattern+ is a string, all its characters are treated
+# as ordinary characters (not as Regexp special characters):
+#
+# 'THX1138'.gsub('\d+', '00') # => "THX1138"
+#
+# <b>+String+ +replacement+</b>
+#
+# If +replacement+ is a string, that string determines
+# the replacing string that is substituted for the matched text.
+#
+# Each of the examples above uses a simple string as the replacing string.
+#
+# +String+ +replacement+ may contain back-references to the pattern's captures:
+#
+# - <tt>\n</tt> (_n_ is a non-negative integer) refers to <tt>$n</tt>.
+# - <tt>\k<name></tt> refers to the named capture +name+.
+#
+# See Regexp for details.
+#
+# Note that within the string +replacement+, a character combination
+# such as <tt>$&</tt> is treated as ordinary text, not as
+# a special match variable.
+# However, you may refer to some special match variables using these
+# combinations:
+#
+# - <tt>\&</tt> and <tt>\0</tt> correspond to <tt>$&</tt>,
+# which contains the complete matched text.
+# - <tt>\'</tt> corresponds to <tt>$'</tt>,
+# which contains the string after the match.
+# - <tt>\`</tt> corresponds to <tt>$`</tt>,
+# which contains the string before the match.
+# - <tt>\\+</tt> corresponds to <tt>$+</tt>,
+# which contains the last capture group.
+#
+# See Regexp for details.
+#
+# Note that <tt>\\\\</tt> is interpreted as an escape, i.e., a single backslash.
+#
+# Note also that a string literal consumes backslashes.
+# See {String Literals}[rdoc-ref:syntax/literals.rdoc@String+Literals] for details about string literals.
+#
+# A back-reference is typically preceded by an additional backslash.
+# For example, if you want to write a back-reference <tt>\&</tt> in
+# +replacement+ with a double-quoted string literal, you need to write
+# <tt>"..\\\\&.."</tt>.
+#
+# If you want to write a non-back-reference string <tt>\&</tt> in
+# +replacement+, you need to first escape the backslash to prevent
+# this method from interpreting it as a back-reference, and then you
+# need to escape the backslashes again to prevent a string literal from
+# consuming them: <tt>"..\\\\\\\\&.."</tt>.
+#
+# You may want to use the block form to avoid excessive backslashes.
+#
+# <b>\Hash +replacement+</b>
+#
+# If the argument +replacement+ is a hash, and +pattern+ matches one of its keys,
+# the replacing string is the value for that key:
+#
+# h = {'foo' => 'bar', 'baz' => 'bat'}
+# 'food'.sub('foo', h) # => "bard"
+#
+# Note that a symbol key does not match:
+#
+# h = {foo: 'bar', baz: 'bat'}
+# 'food'.sub('foo', h) # => "d"
+#
+# <b>Block</b>
+#
+# In the block form, the current match string is passed to the block;
+# the block's return value becomes the replacing string:
+#
+# s = '@'
+# '1234'.gsub(/\d/) { |match| s.succ! } # => "ABCD"
+#
+# Special match variables such as <tt>$1</tt>, <tt>$2</tt>, <tt>$`</tt>,
+# <tt>$&</tt>, and <tt>$'</tt> are set appropriately.
+#
+# == Whitespace in Strings
+#
+# In the class +String+, _whitespace_ is defined as a contiguous sequence of characters
+# consisting of any mixture of the following:
+#
+# - NL (null): <tt>"\x00"</tt>, <tt>"\u0000"</tt>.
+# - HT (horizontal tab): <tt>"\x09"</tt>, <tt>"\t"</tt>.
+# - LF (line feed): <tt>"\x0a"</tt>, <tt>"\n"</tt>.
+# - VT (vertical tab): <tt>"\x0b"</tt>, <tt>"\v"</tt>.
+# - FF (form feed): <tt>"\x0c"</tt>, <tt>"\f"</tt>.
+# - CR (carriage return): <tt>"\x0d"</tt>, <tt>"\r"</tt>.
+# - SP (space): <tt>"\x20"</tt>, <tt>" "</tt>.
+#
+#
+# Whitespace is relevant for the following methods:
+#
+# - #lstrip, #lstrip!: Strip leading whitespace.
+# - #rstrip, #rstrip!: Strip trailing whitespace.
+# - #strip, #strip!: Strip leading and trailing whitespace.
+#
+# == What's Here
+#
+# First, what's elsewhere. Class +String+:
+#
+# - Inherits from the {Object class}[rdoc-ref:Object@Whats+Here].
+# - Includes the {Comparable module}[rdoc-ref:Comparable@Whats+Here].
+#
+# Here, class +String+ provides methods that are useful for:
+#
+# - {Creating a \String}[rdoc-ref:String@Creating+a+String].
+# - {Freezing/Unfreezing a \String}[rdoc-ref:String@FreezingUnfreezing].
+# - {Querying a \String}[rdoc-ref:String@Querying].
+# - {Comparing Strings}[rdoc-ref:String@Comparing].
+# - {Modifying a \String}[rdoc-ref:String@Modifying].
+# - {Converting to a new \String}[rdoc-ref:String@Converting+to+New+String].
+# - {Converting to a non-\String}[rdoc-ref:String@Converting+to+Non--5CString].
+# - {Iterating over a \String}[rdoc-ref:String@Iterating].
+#
+# === Creating a \String
+#
+# - ::new: Returns a new string.
+# - ::try_convert: Returns a new string created from a given object.
+#
+# === Freezing/Unfreezing
+#
+# - #+@: Returns a string that is not frozen: +self+ if not frozen;
+# +self.dup+ otherwise.
+# - #-@ (aliased as #dedup): Returns a string that is frozen: +self+ if already frozen;
+# +self.freeze+ otherwise.
+# - #freeze: Freezes +self+ if not already frozen; returns +self+.
+#
+# === Querying
+#
+# _Counts_
+#
+# - #bytesize: Returns the count of bytes.
+# - #count: Returns the count of substrings matching given strings.
+# - #empty?: Returns whether the length of +self+ is zero.
+# - #length (aliased as #size): Returns the count of characters (not bytes).
+#
+# _Substrings_
+#
+# - #=~: Returns the index of the first substring that matches a given
+# Regexp or other object; returns +nil+ if no match is found.
+# - #byteindex: Returns the byte index of the first occurrence of a given substring.
+# - #byterindex: Returns the byte index of the last occurrence of a given substring.
+# - #index: Returns the index of the _first_ occurrence of a given substring;
+# returns +nil+ if none found.
+# - #rindex: Returns the index of the _last_ occurrence of a given substring;
+# returns +nil+ if none found.
+# - #include?: Returns +true+ if the string contains a given substring; +false+ otherwise.
+# - #match: Returns a MatchData object if the string matches a given Regexp; +nil+ otherwise.
+# - #match?: Returns +true+ if the string matches a given Regexp; +false+ otherwise.
+# - #start_with?: Returns +true+ if the string begins with any of the given substrings.
+# - #end_with?: Returns +true+ if the string ends with any of the given substrings.
+#
+# _Encodings_
+#
+# - #encoding\: Returns the Encoding object that represents the encoding of the string.
+# - #unicode_normalized?: Returns +true+ if the string is in Unicode normalized form; +false+ otherwise.
+# - #valid_encoding?: Returns +true+ if the string contains only characters that are valid
+# for its encoding.
+# - #ascii_only?: Returns +true+ if the string has only ASCII characters; +false+ otherwise.
+#
+# _Other_
+#
+# - #sum: Returns a basic checksum for the string: the sum of each byte.
+# - #hash: Returns the integer hash code.
+#
+# === Comparing
+#
+# - #== (aliased as #===): Returns +true+ if a given other string has the same content as +self+.
+# - #eql?: Returns +true+ if the content is the same as the given other string.
+# - #<=>: Returns -1, 0, or 1 as a given other string is smaller than,
+# equal to, or larger than +self+.
+# - #casecmp: Ignoring case, returns -1, 0, or 1 as
+# +self+ is smaller than, equal to, or larger than a given other string.
+# - #casecmp?: Ignoring case, returns whether a given other string is equal to +self+.
+#
+# === Modifying
+#
+# Each of these methods modifies +self+.
+#
+# _Insertion_
+#
+# - #insert: Returns +self+ with a given string inserted at a specified offset.
+# - #<<: Returns +self+ concatenated with a given string or integer.
+# - #append_as_bytes: Returns +self+ concatenated with strings without performing any
+# encoding validation or conversion.
+# - #prepend: Prefixes to +self+ the concatenation of given other strings.
+#
+# _Substitution_
+#
+# - #bytesplice: Replaces bytes of +self+ with bytes from a given string; returns +self+.
+# - #sub!: Replaces the first substring that matches a given pattern with a given replacement string;
+# returns +self+ if any changes, +nil+ otherwise.
+# - #gsub!: Replaces each substring that matches a given pattern with a given replacement string;
+# returns +self+ if any changes, +nil+ otherwise.
+# - #succ! (aliased as #next!): Returns +self+ modified to become its own successor.
+# - #replace: Returns +self+ with its entire content replaced by a given string.
+# - #reverse!: Returns +self+ with its characters in reverse order.
+# - #setbyte: Sets the byte at a given integer offset to a given value; returns the argument.
+# - #tr!: Replaces specified characters in +self+ with specified replacement characters;
+# returns +self+ if any changes, +nil+ otherwise.
+# - #tr_s!: Replaces specified characters in +self+ with specified replacement characters,
+# removing duplicates from the substrings that were modified;
+# returns +self+ if any changes, +nil+ otherwise.
+#
+# _Casing_
+#
+# - #capitalize!: Upcases the initial character and downcases all others;
+# returns +self+ if any changes, +nil+ otherwise.
+# - #downcase!: Downcases all characters; returns +self+ if any changes, +nil+ otherwise.
+# - #upcase!: Upcases all characters; returns +self+ if any changes, +nil+ otherwise.
+# - #swapcase!: Upcases each downcase character and downcases each upcase character;
+# returns +self+ if any changes, +nil+ otherwise.
+#
+# _Encoding_
+#
+# - #encode!: Returns +self+ with all characters transcoded from one encoding to another.
+# - #unicode_normalize!: Unicode-normalizes +self+; returns +self+.
+# - #scrub!: Replaces each invalid byte with a given character; returns +self+.
+# - #force_encoding: Changes the encoding to a given encoding; returns +self+.
+#
+# _Deletion_
+#
+# - #clear: Removes all content, so that +self+ is empty; returns +self+.
+# - #slice!, #[]=: Removes a substring determined by a given index, start/length, range, regexp, or substring.
+# - #squeeze!: Removes contiguous duplicate characters; returns +self+.
+# - #delete!: Removes characters as determined by the intersection of substring arguments.
+# - #delete_prefix!: Removes leading prefix; returns +self+ if any changes, +nil+ otherwise.
+# - #delete_suffix!: Removes trailing suffix; returns +self+ if any changes, +nil+ otherwise.
+# - #lstrip!: Removes leading whitespace; returns +self+ if any changes, +nil+ otherwise.
+# - #rstrip!: Removes trailing whitespace; returns +self+ if any changes, +nil+ otherwise.
+# - #strip!: Removes leading and trailing whitespace; returns +self+ if any changes, +nil+ otherwise.
+# - #chomp!: Removes the trailing record separator, if found; returns +self+ if any changes, +nil+ otherwise.
+# - #chop!: Removes trailing newline characters if found; otherwise removes the last character;
+# returns +self+ if any changes, +nil+ otherwise.
+#
+# === Converting to New \String
+#
+# Each of these methods returns a new +String+ based on +self+,
+# often just a modified copy of +self+.
+#
+# _Extension_
+#
+# - #*: Returns the concatenation of multiple copies of +self+.
+# - #+: Returns the concatenation of +self+ and a given other string.
+# - #center: Returns a copy of +self+, centered by specified padding.
+# - #concat: Returns the concatenation of +self+ with given other strings.
+# - #ljust: Returns a copy of +self+ of a given length, right-padded with a given other string.
+# - #rjust: Returns a copy of +self+ of a given length, left-padded with a given other string.
+#
+# _Encoding_
+#
+# - #b: Returns a copy of +self+ with ASCII-8BIT encoding.
+# - #scrub: Returns a copy of +self+ with each invalid byte replaced with a given character.
+# - #unicode_normalize: Returns a copy of +self+ with each character Unicode-normalized.
+# - #encode: Returns a copy of +self+ with all characters transcoded from one encoding to another.
+#
+# _Substitution_
+#
+# - #dump: Returns a printable version of +self+, enclosed in double-quotes.
+# - #undump: Inverse of #dump; returns a copy of +self+ with changes of the kinds made by #dump "undone."
+# - #sub: Returns a copy of +self+ with the first substring matching a given pattern
+# replaced with a given replacement string.
+# - #gsub: Returns a copy of +self+ with each substring that matches a given pattern
+# replaced with a given replacement string.
+# - #succ (aliased as #next): Returns the string that is the successor to +self+.
+# - #reverse: Returns a copy of +self+ with its characters in reverse order.
+# - #tr: Returns a copy of +self+ with specified characters replaced with specified replacement characters.
+# - #tr_s: Returns a copy of +self+ with specified characters replaced with
+# specified replacement characters,
+# removing duplicates from the substrings that were modified.
+# - #%: Returns the string resulting from formatting a given object into +self+.
+#
+# _Casing_
+#
+# - #capitalize: Returns a copy of +self+ with the first character upcased
+# and all other characters downcased.
+# - #downcase: Returns a copy of +self+ with all characters downcased.
+# - #upcase: Returns a copy of +self+ with all characters upcased.
+# - #swapcase: Returns a copy of +self+ with all upcase characters downcased
+# and all downcase characters upcased.
+#
+# _Deletion_
+#
+# - #delete: Returns a copy of +self+ with characters removed.
+# - #delete_prefix: Returns a copy of +self+ with a given prefix removed.
+# - #delete_suffix: Returns a copy of +self+ with a given suffix removed.
+# - #lstrip: Returns a copy of +self+ with leading whitespace removed.
+# - #rstrip: Returns a copy of +self+ with trailing whitespace removed.
+# - #strip: Returns a copy of +self+ with leading and trailing whitespace removed.
+# - #chomp: Returns a copy of +self+ with a trailing record separator removed, if found.
+# - #chop: Returns a copy of +self+ with trailing newline characters or the last character removed.
+# - #squeeze: Returns a copy of +self+ with contiguous duplicate characters removed.
+# - #[] (aliased as #slice): Returns a substring determined by a given index, start/length, range, regexp, or string.
+# - #byteslice: Returns a substring determined by a given index, start/length, or range.
+# - #chr: Returns the first character.
+#
+# _Duplication_
+#
+# - #to_s (aliased as #to_str): If +self+ is a subclass of +String+, returns +self+ copied into a +String+;
+# otherwise, returns +self+.
+#
+# === Converting to Non-\String
+#
+# Each of these methods converts the contents of +self+ to a non-+String+.
+#
+# <em>Characters, Bytes, and Clusters</em>
+#
+# - #bytes: Returns an array of the bytes in +self+.
+# - #chars: Returns an array of the characters in +self+.
+# - #codepoints: Returns an array of the integer ordinals in +self+.
+# - #getbyte: Returns the integer byte at the given index in +self+.
+# - #grapheme_clusters: Returns an array of the grapheme clusters in +self+.
+#
+# _Splitting_
+#
+# - #lines: Returns an array of the lines in +self+, as determined by a given record separator.
+# - #partition: Returns a 3-element array determined by the first substring that matches
+# a given substring or regexp.
+# - #rpartition: Returns a 3-element array determined by the last substring that matches
+# a given substring or regexp.
+# - #split: Returns an array of substrings determined by a given delimiter -- regexp or string --
+# or, if a block is given, passes those substrings to the block.
+#
+# _Matching_
+#
+# - #scan: Returns an array of substrings matching a given regexp or string, or,
+# if a block is given, passes each matching substring to the block.
+# - #unpack: Returns an array of substrings extracted from +self+ according to a given format.
+# - #unpack1: Returns the first substring extracted from +self+ according to a given format.
+#
+# _Numerics_
+#
+# - #hex: Returns the integer value of the leading characters, interpreted as hexadecimal digits.
+# - #oct: Returns the integer value of the leading characters, interpreted as octal digits.
+# - #ord: Returns the integer ordinal of the first character in +self+.
+# - #to_c: Returns the complex value of leading characters, interpreted as a complex number.
+# - #to_i: Returns the integer value of leading characters, interpreted as an integer.
+# - #to_f: Returns the floating-point value of leading characters, interpreted as a floating-point number.
+# - #to_r: Returns the rational value of leading characters, interpreted as a rational.
+#
+# <em>Strings and Symbols</em>
+#
+# - #inspect: Returns a copy of +self+, enclosed in double quotes, with special characters escaped.
+# - #intern (aliased as #to_sym): Returns the symbol corresponding to +self+.
+#
+# === Iterating
+#
+# - #each_byte: Calls the given block with each successive byte in +self+.
+# - #each_char: Calls the given block with each successive character in +self+.
+# - #each_codepoint: Calls the given block with each successive integer codepoint in +self+.
+# - #each_grapheme_cluster: Calls the given block with each successive grapheme cluster in +self+.
+# - #each_line: Calls the given block with each successive line in +self+,
+# as determined by a given record separator.
+# - #upto: Calls the given block with each string value returned by successive calls to #succ.
+
+class String; end
diff --git a/doc/string/aref.rdoc b/doc/string/aref.rdoc
new file mode 100644
index 0000000000..a9ab8857bc
--- /dev/null
+++ b/doc/string/aref.rdoc
@@ -0,0 +1,96 @@
+Returns the substring of +self+ specified by the arguments.
+
+<b>Form <tt>self[offset]</tt></b>
+
+With non-negative integer argument +offset+ given,
+returns the 1-character substring found in self at character offset +offset+:
+
+ 'hello'[0] # => "h"
+ 'hello'[4] # => "o"
+ 'hello'[5] # => nil
+ 'こんにちは'[4] # => "は"
+
+With negative integer argument +offset+ given,
+counts backward from the end of +self+:
+
+ 'hello'[-1] # => "o"
+ 'hello'[-5] # => "h"
+ 'hello'[-6] # => nil
+
+<b>Form <tt>self[offset, size]</tt></b>
+
+With integer arguments +offset+ and +size+ given,
+returns a substring of size +size+ characters (as available)
+beginning at character offset specified by +offset+.
+
+If argument +offset+ is non-negative,
+the offset is +offset+:
+
+ 'hello'[0, 1] # => "h"
+ 'hello'[0, 5] # => "hello"
+ 'hello'[0, 6] # => "hello"
+ 'hello'[2, 3] # => "llo"
+ 'hello'[2, 0] # => ""
+ 'hello'[2, -1] # => nil
+
+If argument +offset+ is negative,
+counts backward from the end of +self+:
+
+ 'hello'[-1, 1] # => "o"
+ 'hello'[-5, 5] # => "hello"
+ 'hello'[-1, 0] # => ""
+ 'hello'[-6, 5] # => nil
+
+Special case: if +offset+ equals the size of +self+,
+returns a new empty string:
+
+ 'hello'[5, 3] # => ""
+
+<b>Form <tt>self[range]</tt></b>
+
+With Range argument +range+ given,
+forms substring <tt>self[range.start, range.size]</tt>:
+
+ 'hello'[0..2] # => "hel"
+ 'hello'[0, 3] # => "hel"
+
+ 'hello'[0...2] # => "he"
+ 'hello'[0, 2] # => "he"
+
+ 'hello'[0, 0] # => ""
+ 'hello'[0...0] # => ""
+
+<b>Form <tt>self[regexp, capture = 0]</tt></b>
+
+With Regexp argument +regexp+ given and +capture+ as zero,
+searches for a matching substring in +self+;
+updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ 'hello'[/ell/] # => "ell"
+ 'hello'[/l+/] # => "ll"
+ 'hello'[//] # => ""
+ 'hello'[/nosuch/] # => nil
+
+With +capture+ as a positive integer +n+,
+returns the +n+th matched group:
+
+ 'hello'[/(h)(e)(l+)(o)/] # => "hello"
+ 'hello'[/(h)(e)(l+)(o)/, 1] # => "h"
+ $1 # => "h"
+ 'hello'[/(h)(e)(l+)(o)/, 2] # => "e"
+ $2 # => "e"
+ 'hello'[/(h)(e)(l+)(o)/, 3] # => "ll"
+ 'hello'[/(h)(e)(l+)(o)/, 4] # => "o"
+ 'hello'[/(h)(e)(l+)(o)/, 5] # => nil
+
+<b>Form <tt>self[substring]</tt></b>
+
+With string argument +substring+ given,
+returns the matching substring of +self+, if found:
+
+ 'hello'['ell'] # => "ell"
+ 'hello'[''] # => ""
+ 'hello'['nosuch'] # => nil
+ 'こんにちは'['んにち'] # => "んにち"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/aset.rdoc b/doc/string/aset.rdoc
new file mode 100644
index 0000000000..98c58b59cc
--- /dev/null
+++ b/doc/string/aset.rdoc
@@ -0,0 +1,179 @@
+Returns +self+ with all, a substring, or none of its contents replaced;
+returns the argument +other_string+.
+
+<b>Form <tt>self[index] = other_string</tt></b>
+
+With non-negative integer argument +index+ given,
+searches for the 1-character substring found in self at character offset index:
+
+ s = 'hello'
+ s[0] = 'foo' # => "foo"
+ s # => "fooello"
+
+ s = 'hello'
+ s[4] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[5] = 'foo' # => "foo"
+ s # => "hellofoo"
+
+ s = 'hello'
+ s[6] = 'foo' # Raises IndexError: index 6 out of string.
+
+With negative integer argument +index+ given,
+counts backward from the end of +self+:
+
+ s = 'hello'
+ s[-1] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[-5] = 'foo' # => "foo"
+ s # => "fooello"
+
+ s = 'hello'
+ s[-6] = 'foo' # Raises IndexError: index -6 out of string.
+
+<b>Form <tt>self[start, length] = other_string</tt></b>
+
+With integer arguments +start+ and +length+ given,
+searches for a substring of size +length+ characters (as available)
+beginning at character offset specified by +start+.
+
+If argument +start+ is non-negative,
+the offset is +start+:
+
+ s = 'hello'
+ s[0, 1] = 'foo' # => "foo"
+ s # => "fooello"
+
+ s = 'hello'
+ s[0, 5] = 'foo' # => "foo"
+ s # => "foo"
+
+ s = 'hello'
+ s[0, 9] = 'foo' # => "foo"
+ s # => "foo"
+
+ s = 'hello'
+ s[2, 0] = 'foo' # => "foo"
+ s # => "hefoollo"
+
+ s = 'hello'
+ s[2, -1] = 'foo' # Raises IndexError: negative length -1.
+
+If argument +start+ is negative,
+counts backward from the end of +self+:
+
+ s = 'hello'
+ s[-1, 1] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[-1, 9] = 'foo' # => "foo"
+ s # => "hellfoo"
+
+ s = 'hello'
+ s[-5, 2] = 'foo' # => "foo"
+ s # => "foollo"
+
+ s = 'hello'
+ s[-3, 0] = 'foo' # => "foo"
+ s # => "hefoollo"
+
+ s = 'hello'
+ s[-6, 2] = 'foo' # Raises IndexError: index -6 out of string.
+
+Special case: if +start+ equals the length of +self+,
+the argument is appended to +self+:
+
+ s = 'hello'
+ s[5, 3] = 'foo' # => "foo"
+ s # => "hellofoo"
+
+<b>Form <tt>self[range] = other_string</tt></b>
+
+With Range argument +range+ given,
+equivalent to <tt>self[range.start, range.size] = other_string</tt>:
+
+ s0 = 'hello'
+ s1 = 'hello'
+ s0[0..2] = 'foo' # => "foo"
+ s1[0, 3] = 'foo' # => "foo"
+ s0 # => "foolo"
+ s1 # => "foolo"
+
+ s = 'hello'
+ s[0...2] = 'foo' # => "foo"
+ s # => "foollo"
+
+ s = 'hello'
+ s[0...0] = 'foo' # => "foo"
+ s # => "foohello"
+
+ s = 'hello'
+ s[9..10] = 'foo' # Raises RangeError: 9..10 out of range
+
+<b>Form <tt>self[regexp, capture = 0] = other_string</tt></b>
+
+With Regexp argument +regexp+ given and +capture+ as zero,
+searches for a matching substring in +self+;
+updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ s = 'hello'
+ s[/l/] = 'L' # => "L"
+ [$`, $&, $'] # => ["he", "l", "lo"]
+ s[/eLlo/] = 'owdy' # => "owdy"
+ [$`, $&, $'] # => ["h", "eLlo", ""]
+ s[/eLlo/] = 'owdy' # Raises IndexError: regexp not matched.
+ [$`, $&, $'] # => [nil, nil, nil]
+
+With +capture+ as a positive integer +n+,
+searches for the +n+th matched group:
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/] = 'foo' # => "foo"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/, 1] = 'foo' # => "foo"
+ s # => "fooello"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/, 2] = 'foo' # => "foo"
+ s # => "hfoollo"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ s[/(h)(e)(l+)(o)/, 4] = 'foo' # => "foo"
+ s # => "hellfoo"
+ [$`, $&, $'] # => ["", "hello", ""]
+
+ s = 'hello'
+ # => "hello"
+ s[/(h)(e)(l+)(o)/, 5] = 'foo # Raises IndexError: index 5 out of regexp.
+
+ s = 'hello'
+ s[/nosuch/] = 'foo' # Raises IndexError: regexp not matched.
+
+<b>Form <tt>self[substring] = other_string</tt></b>
+
+With string argument +substring+ given:
+
+ s = 'hello'
+ s['l'] = 'foo' # => "foo"
+ s # => "hefoolo"
+
+ s = 'hello'
+ s['ll'] = 'foo' # => "foo"
+ s # => "hefooo"
+
+ s = 'こんにちは'
+ s['んにち'] = 'foo' # => "foo"
+ s # => "こfooは"
+
+ s['nosuch'] = 'foo' # Raises IndexError: string not matched.
+
+Related: see {Modifying}[rdoc-ref:String@Modifying].
diff --git a/doc/string/b.rdoc b/doc/string/b.rdoc
index f8ad2910b4..8abd6d9532 100644
--- a/doc/string/b.rdoc
+++ b/doc/string/b.rdoc
@@ -12,3 +12,5 @@ the underlying bytes are not modified:
t = s.b # => "\xE4\x82\x95"
t.encoding # => #<Encoding:ASCII-8BIT>
t.bytes # => [228, 130, 149]
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/bytes.rdoc b/doc/string/bytes.rdoc
index a9e89f1cd1..16fa8e0bb0 100644
--- a/doc/string/bytes.rdoc
+++ b/doc/string/bytes.rdoc
@@ -1,6 +1,7 @@
Returns an array of the bytes in +self+:
- 'hello'.bytes # => [104, 101, 108, 108, 111]
- 'тест'.bytes # => [209, 130, 208, 181, 209, 129, 209, 130]
+ 'hello'.bytes # => [104, 101, 108, 108, 111]
'こんにちは'.bytes
# => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/bytesize.rdoc b/doc/string/bytesize.rdoc
index b0567ff67b..8d12a0d454 100644
--- a/doc/string/bytesize.rdoc
+++ b/doc/string/bytesize.rdoc
@@ -1,11 +1,12 @@
-Returns the count of bytes (not characters) in +self+:
+Returns the count of bytes in +self+.
- 'foo'.bytesize # => 3
- 'тест'.bytesize # => 8
- 'こんにちは'.bytesize # => 15
+Note that the byte count may be different from the character count (returned by #size):
-Contrast with String#length:
+ s = 'foo'
+ s.bytesize # => 3
+ s.size # => 3
+ s = 'こんにちは'
+ s.bytesize # => 15
+ s.size # => 5
- 'foo'.length # => 3
- 'тест'.length # => 4
- 'こんにちは'.length # => 5
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/byteslice.rdoc b/doc/string/byteslice.rdoc
new file mode 100644
index 0000000000..d70441fb2b
--- /dev/null
+++ b/doc/string/byteslice.rdoc
@@ -0,0 +1,54 @@
+Returns a substring of +self+, or +nil+ if the substring cannot be constructed.
+
+With integer arguments +offset+ and +length+ given,
+returns the substring beginning at the given +offset+
+and of the given +length+ (as available):
+
+ s = '0123456789' # => "0123456789"
+ s.byteslice(2) # => "2"
+ s.byteslice(200) # => nil
+ s.byteslice(4, 3) # => "456"
+ s.byteslice(4, 30) # => "456789"
+
+Returns +nil+ if +length+ is negative or +offset+ falls outside of +self+:
+
+ s.byteslice(4, -1) # => nil
+ s.byteslice(40, 2) # => nil
+
+Counts backwards from the end of +self+
+if +offset+ is negative:
+
+ s = '0123456789' # => "0123456789"
+ s.byteslice(-4) # => "6"
+ s.byteslice(-4, 3) # => "678"
+
+With Range argument +range+ given, returns
+<tt>byteslice(range.begin, range.size)</tt>:
+
+ s = '0123456789' # => "0123456789"
+ s.byteslice(4..6) # => "456"
+ s.byteslice(-6..-4) # => "456"
+ s.byteslice(5..2) # => "" # range.size is zero.
+ s.byteslice(40..42) # => nil
+
+The starting and ending offsets need not be on character boundaries:
+
+ s = 'こんにちは'
+ s.byteslice(0, 3) # => "こ"
+ s.byteslice(1, 3) # => "\x81\x93\xE3"
+
+The encodings of +self+ and the returned substring
+are always the same:
+
+ s.encoding # => #<Encoding:UTF-8>
+ s.byteslice(0, 3).encoding # => #<Encoding:UTF-8>
+ s.byteslice(1, 3).encoding # => #<Encoding:UTF-8>
+
+But, depending on the character boundaries,
+the encoding of the returned substring may not be valid:
+
+ s.valid_encoding? # => true
+ s.byteslice(0, 3).valid_encoding? # => true
+ s.byteslice(1, 3).valid_encoding? # => false
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/bytesplice.rdoc b/doc/string/bytesplice.rdoc
new file mode 100644
index 0000000000..790f9eb9a0
--- /dev/null
+++ b/doc/string/bytesplice.rdoc
@@ -0,0 +1,65 @@
+Replaces <i>target bytes</i> in +self+ with <i>source bytes</i> from the given string +str+;
+returns +self+.
+
+In the first form, arguments +offset+ and +length+ determine the target bytes,
+and the source bytes are all of the given +str+:
+
+ '0123456789'.bytesplice(0, 3, 'abc') # => "abc3456789"
+ '0123456789'.bytesplice(3, 3, 'abc') # => "012abc6789"
+ '0123456789'.bytesplice(0, 50, 'abc') # => "abc"
+ '0123456789'.bytesplice(50, 3, 'abc') # Raises IndexError.
+
+The counts of the target bytes and source source bytes may be different:
+
+ '0123456789'.bytesplice(0, 6, 'abc') # => "abc6789" # Shorter source.
+ '0123456789'.bytesplice(0, 1, 'abc') # => "abc123456789" # Shorter target.
+
+And either count may be zero (i.e., specifying an empty string):
+
+ '0123456789'.bytesplice(0, 3, '') # => "3456789" # Empty source.
+ '0123456789'.bytesplice(0, 0, 'abc') # => "abc0123456789" # Empty target.
+
+In the second form, just as in the first,
+arguments +offset+ and +length+ determine the target bytes;
+argument +str+ _contains_ the source bytes,
+and the additional arguments +str_offset+ and +str_length+
+determine the actual source bytes:
+
+ '0123456789'.bytesplice(0, 3, 'abc', 0, 3) # => "abc3456789"
+ '0123456789'.bytesplice(0, 3, 'abc', 1, 1) # => "b3456789" # Shorter source.
+ '0123456789'.bytesplice(0, 1, 'abc', 0, 3) # => "abc123456789" # Shorter target.
+ '0123456789'.bytesplice(0, 3, 'abc', 1, 0) # => "3456789" # Empty source.
+ '0123456789'.bytesplice(0, 0, 'abc', 0, 3) # => "abc0123456789" # Empty target.
+
+In the third form, argument +range+ determines the target bytes
+and the source bytes are all of the given +str+:
+
+ '0123456789'.bytesplice(0..2, 'abc') # => "abc3456789"
+ '0123456789'.bytesplice(3..5, 'abc') # => "012abc6789"
+ '0123456789'.bytesplice(0..5, 'abc') # => "abc6789" # Shorter source.
+ '0123456789'.bytesplice(0..0, 'abc') # => "abc123456789" # Shorter target.
+ '0123456789'.bytesplice(0..2, '') # => "3456789" # Empty source.
+ '0123456789'.bytesplice(0...0, 'abc') # => "abc0123456789" # Empty target.
+
+In the fourth form, just as in the third,
+argument +range+ determines the target bytes;
+argument +str+ _contains_ the source bytes,
+and the additional argument +str_range+
+determines the actual source bytes:
+
+ '0123456789'.bytesplice(0..2, 'abc', 0..2) # => "abc3456789"
+ '0123456789'.bytesplice(3..5, 'abc', 0..2) # => "012abc6789"
+ '0123456789'.bytesplice(0..2, 'abc', 0..1) # => "ab3456789" # Shorter source.
+ '0123456789'.bytesplice(0..1, 'abc', 0..2) # => "abc23456789" # Shorter target.
+ '0123456789'.bytesplice(0..2, 'abc', 0...0) # => "3456789" # Empty source.
+ '0123456789'.bytesplice(0...0, 'abc', 0..2) # => "abc0123456789" # Empty target.
+
+In any of the forms, the beginnings and endings of both source and target
+must be on character boundaries.
+
+In these examples, +self+ has five 3-byte characters,
+and so has character boundaries at offsets 0, 3, 6, 9, 12, and 15.
+
+ 'こんにちは'.bytesplice(0, 3, 'abc') # => "abcんにちは"
+ 'こんにちは'.bytesplice(1, 3, 'abc') # Raises IndexError.
+ 'こんにちは'.bytesplice(0, 2, 'abc') # Raises IndexError.
diff --git a/doc/string/capitalize.rdoc b/doc/string/capitalize.rdoc
new file mode 100644
index 0000000000..3a1a2dcb8b
--- /dev/null
+++ b/doc/string/capitalize.rdoc
@@ -0,0 +1,26 @@
+Returns a string containing the characters in +self+,
+each with possibly changed case:
+
+- The first character made uppercase.
+- All other characters are made lowercase.
+
+Examples:
+
+ 'hello'.capitalize # => "Hello"
+ 'HELLO'.capitalize # => "Hello"
+ 'straße'.capitalize # => "Straße" # Lowercase 'ß' not changed.
+ 'STRAẞE'.capitalize # => "Straße" # Uppercase 'ẞ' downcased to 'ß'.
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.capitalize == s # => true
+ s = 'こんにちは'
+ s.capitalize == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/center.rdoc b/doc/string/center.rdoc
index d53d921ad5..b86c8b5916 100644
--- a/doc/string/center.rdoc
+++ b/doc/string/center.rdoc
@@ -2,15 +2,18 @@ Returns a centered copy of +self+.
If integer argument +size+ is greater than the size (in characters) of +self+,
returns a new string of length +size+ that is a copy of +self+,
-centered and padded on both ends with +pad_string+:
+centered and padded on one or both ends with +pad_string+:
- 'hello'.center(10) # => " hello "
- ' hello'.center(10) # => " hello "
- 'hello'.center(10, 'ab') # => "abhelloaba"
- 'тест'.center(10) # => " тест "
- 'こんにちは'.center(10) # => " こんにちは "
+ 'hello'.center(6) # => "hello " # Padded on one end.
+ 'hello'.center(10) # => " hello " # Padded on both ends.
+ 'hello'.center(20, '-|') # => "-|-|-|-hello-|-|-|-|" # Some padding repeated.
+ 'hello'.center(10, 'abcdefg') # => "abhelloabc" # Some padding not used.
+ ' hello '.center(13) # => " hello "
+ 'こんにちは'.center(10) # => " こんにちは " # Multi-byte characters.
-If +size+ is not greater than the size of +self+, returns a copy of +self+:
+If +size+ is less than or equal to the size of +self+, returns an unpadded copy of +self+:
- 'hello'.center(5) # => "hello"
- 'hello'.center(1) # => "hello"
+ 'hello'.center(5) # => "hello"
+ 'hello'.center(-10) # => "hello"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/chars.rdoc b/doc/string/chars.rdoc
index d24a1cc3a9..47fb01b43a 100644
--- a/doc/string/chars.rdoc
+++ b/doc/string/chars.rdoc
@@ -1,5 +1,7 @@
Returns an array of the characters in +self+:
'hello'.chars # => ["h", "e", "l", "l", "o"]
- 'тест'.chars # => ["т", "е", "с", "т"]
'こんにちは'.chars # => ["こ", "ん", "に", "ち", "は"]
+ ''.chars # => []
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/chomp.rdoc b/doc/string/chomp.rdoc
index b6fb9ff38c..4efff5c291 100644
--- a/doc/string/chomp.rdoc
+++ b/doc/string/chomp.rdoc
@@ -9,7 +9,6 @@ if they are <tt>"\r"</tt>, <tt>"\n"</tt>, or <tt>"\r\n"</tt>
"abc\n".chomp # => "abc"
"abc\r\n".chomp # => "abc"
"abc\n\r".chomp # => "abc\n"
- "тест\r\n".chomp # => "тест"
"こんにちは\r\n".chomp # => "こんにちは"
When +line_sep+ is <tt>''</tt> (an empty string),
@@ -25,5 +24,8 @@ removes multiple trailing occurrences of <tt>"\n"</tt> or <tt>"\r\n"</tt>
When +line_sep+ is neither <tt>"\n"</tt> nor <tt>''</tt>,
removes a single trailing line separator if there is one:
- 'abcd'.chomp('d') # => "abc"
- 'abcdd'.chomp('d') # => "abcd"
+ 'abcd'.chomp('cd') # => "ab"
+ 'abcdcd'.chomp('cd') # => "abcd"
+ 'abcd'.chomp('xx') # => "abcd"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/chop.rdoc b/doc/string/chop.rdoc
index 8ef82f8a49..d818ba467a 100644
--- a/doc/string/chop.rdoc
+++ b/doc/string/chop.rdoc
@@ -3,14 +3,15 @@ Returns a new string copied from +self+, with trailing characters possibly remov
Removes <tt>"\r\n"</tt> if those are the last two characters.
"abc\r\n".chop # => "abc"
- "тест\r\n".chop # => "тест"
"こんにちは\r\n".chop # => "こんにちは"
Otherwise removes the last character if it exists.
'abcd'.chop # => "abc"
- 'тест'.chop # => "тес"
'こんにちは'.chop # => "こんにち"
''.chop # => ""
-If you only need to remove the newline separator at the end of the string, String#chomp is a better alternative.
+If you only need to remove the newline separator at the end of the string,
+String#chomp is a better alternative.
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/chr.rdoc b/doc/string/chr.rdoc
new file mode 100644
index 0000000000..153d5d71c3
--- /dev/null
+++ b/doc/string/chr.rdoc
@@ -0,0 +1,7 @@
+Returns a string containing the first character of +self+:
+
+ 'hello'.chr # => "h"
+ 'こんにちは'.chr # => "こ"
+ ''.chr # => ""
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/codepoints.rdoc b/doc/string/codepoints.rdoc
index 0c55d3f4b9..0ad866389e 100644
--- a/doc/string/codepoints.rdoc
+++ b/doc/string/codepoints.rdoc
@@ -2,5 +2,7 @@ Returns an array of the codepoints in +self+;
each codepoint is the integer value for a character:
'hello'.codepoints # => [104, 101, 108, 108, 111]
- 'тест'.codepoints # => [1090, 1077, 1089, 1090]
'こんにちは'.codepoints # => [12371, 12435, 12395, 12385, 12399]
+ ''.codepoints # => []
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/concat.rdoc b/doc/string/concat.rdoc
new file mode 100644
index 0000000000..92ba664b8c
--- /dev/null
+++ b/doc/string/concat.rdoc
@@ -0,0 +1,11 @@
+Concatenates each object in +objects+ to +self+; returns +self+:
+
+ 'foo'.concat('bar', 'baz') # => "foobarbaz"
+
+For each given object +object+ that is an integer,
+the value is considered a codepoint and converted to a character before concatenation:
+
+ 'foo'.concat(32, 'bar', 32, 'baz') # => "foo bar baz" # Embeds spaces.
+ 'こん'.concat(12395, 12385, 12399) # => "こんにちは"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/count.rdoc b/doc/string/count.rdoc
new file mode 100644
index 0000000000..7a3b9f1e21
--- /dev/null
+++ b/doc/string/count.rdoc
@@ -0,0 +1,74 @@
+Returns the total number of characters in +self+ that are specified by the given selectors.
+
+For one 1-character selector,
+returns the count of instances of that character:
+
+ s = 'abracadabra'
+ s.count('a') # => 5
+ s.count('b') # => 2
+ s.count('x') # => 0
+ s.count('') # => 0
+
+ s = 'よろしくお願いします'
+ s.count('よ') # => 1
+ s.count('し') # => 2
+
+For one multi-character selector,
+returns the count of instances for all specified characters:
+
+ s = 'abracadabra'
+ s.count('ab') # => 7
+ s.count('abc') # => 8
+ s.count('abcd') # => 9
+ s.count('abcdr') # => 11
+ s.count('abcdrx') # => 11
+
+Order and repetition do not matter:
+
+ s.count('ba') == s.count('ab') # => true
+ s.count('baab') == s.count('ab') # => true
+
+For multiple selectors,
+forms a single selector that is the intersection of characters in all selectors
+and returns the count of instances for that selector:
+
+ s = 'abcdefg'
+ s.count('abcde', 'dcbfg') == s.count('bcd') # => true
+ s.count('abc', 'def') == s.count('') # => true
+
+In a character selector, three characters get special treatment:
+
+- A caret (<tt>'^'</tt>) functions as a _negation_ operator
+ for the immediately following characters:
+
+ s = 'abracadabra'
+ s.count('^bc') # => 8 # Count of all except 'b' and 'c'.
+
+- A hyphen (<tt>'-'</tt>) between two other characters defines a _range_ of characters:
+
+ s = 'abracadabra'
+ s.count('a-c') # => 8 # Count of all 'a', 'b', and 'c'.
+
+- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
+ or another backslash:
+
+ s = 'abracadabra'
+ s.count('\^bc') # => 3 # Count of '^', 'b', and 'c'.
+ s.count('a\-c') # => 6 # Count of 'a', '-', and 'c'.
+ 'foo\bar\baz'.count('\\') # => 2 # Count of '\'.
+
+These usages may be mixed:
+
+ s = 'abracadabra'
+ s.count('a-cq-t') # => 10 # Multiple ranges.
+ s.count('ac-d') # => 7 # Range mixed with plain characters.
+ s.count('^a-c') # => 3 # Range mixed with negation.
+
+For multiple selectors, all forms may be used, including negations, ranges, and escapes.
+
+ s = 'abracadabra'
+ s.count('^abc', '^def') == s.count('^abcdef') # => true
+ s.count('a-e', 'c-g') == s.count('cde') # => true
+ s.count('^abc', 'c-g') == s.count('defg') # => true
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/delete.rdoc b/doc/string/delete.rdoc
new file mode 100644
index 0000000000..1827f177e6
--- /dev/null
+++ b/doc/string/delete.rdoc
@@ -0,0 +1,75 @@
+Returns a new string that is a copy of +self+ with certain characters removed;
+the removed characters are all instances of those specified by the given string +selectors+.
+
+For one 1-character selector,
+removes all instances of that character:
+
+ s = 'abracadabra'
+ s.delete('a') # => "brcdbr"
+ s.delete('b') # => "aracadara"
+ s.delete('x') # => "abracadabra"
+ s.delete('') # => "abracadabra"
+
+ s = 'よろしくお願いします'
+ s.delete('よ') # => "ろしくお願いします"
+ s.delete('し') # => "よろくお願います"
+
+For one multi-character selector,
+removes all instances of the specified characters:
+
+ s = 'abracadabra'
+ s.delete('ab') # => "rcdr"
+ s.delete('abc') # => "rdr"
+ s.delete('abcd') # => "rr"
+ s.delete('abcdr') # => ""
+ s.delete('abcdrx') # => ""
+
+Order and repetition do not matter:
+
+ s.delete('ba') == s.delete('ab') # => true
+ s.delete('baab') == s.delete('ab') # => true
+
+For multiple selectors,
+forms a single selector that is the intersection of characters in all selectors
+and removes all instances of characters specified by that selector:
+
+ s = 'abcdefg'
+ s.delete('abcde', 'dcbfg') == s.delete('bcd') # => true
+ s.delete('abc', 'def') == s.delete('') # => true
+
+In a character selector, three characters get special treatment:
+
+- A caret (<tt>'^'</tt>) functions as a _negation_ operator
+ for the immediately following characters:
+
+ s = 'abracadabra'
+ s.delete('^bc') # => "bcb" # Deletes all except 'b' and 'c'.
+
+- A hyphen (<tt>'-'</tt>) between two other characters defines a _range_ of characters:
+
+ s = 'abracadabra'
+ s.delete('a-c') # => "rdr" # Deletes all 'a', 'b', and 'c'.
+
+- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
+ or another backslash:
+
+ s = 'abracadabra'
+ s.delete('\^bc') # => "araadara" # Deletes all '^', 'b', and 'c'.
+ s.delete('a\-c') # => "brdbr" # Deletes all 'a', '-', and 'c'.
+ 'foo\bar\baz'.delete('\\') # => "foobarbaz" # Deletes all '\'.
+
+These usages may be mixed:
+
+ s = 'abracadabra'
+ s.delete('a-cq-t') # => "d" # Multiple ranges.
+ s.delete('ac-d') # => "brbr" # Range mixed with plain characters.
+ s.delete('^a-c') # => "abacaaba" # Range mixed with negation.
+
+For multiple selectors, all forms may be used, including negations, ranges, and escapes.
+
+ s = 'abracadabra'
+ s.delete('^abc', '^def') == s.delete('^abcdef') # => true
+ s.delete('a-e', 'c-g') == s.delete('cde') # => true
+ s.delete('^abc', 'c-g') == s.delete('defg') # => true
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/delete_prefix.rdoc b/doc/string/delete_prefix.rdoc
index fa9d8abd38..6255e300e3 100644
--- a/doc/string/delete_prefix.rdoc
+++ b/doc/string/delete_prefix.rdoc
@@ -1,8 +1,9 @@
-Returns a copy of +self+ with leading substring <tt>prefix</tt> removed:
+Returns a copy of +self+ with leading substring +prefix+ removed:
- 'hello'.delete_prefix('hel') # => "lo"
- 'hello'.delete_prefix('llo') # => "hello"
- 'тест'.delete_prefix('те') # => "ст"
+ 'oof'.delete_prefix('o') # => "of"
+ 'oof'.delete_prefix('oo') # => "f"
+ 'oof'.delete_prefix('oof') # => ""
+ 'oof'.delete_prefix('x') # => "oof"
'こんにちは'.delete_prefix('こん') # => "にちは"
-Related: String#delete_prefix!, String#delete_suffix.
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/delete_suffix.rdoc b/doc/string/delete_suffix.rdoc
index 4862b725cf..a4d9a80f85 100644
--- a/doc/string/delete_suffix.rdoc
+++ b/doc/string/delete_suffix.rdoc
@@ -1,8 +1,10 @@
Returns a copy of +self+ with trailing substring <tt>suffix</tt> removed:
- 'hello'.delete_suffix('llo') # => "he"
- 'hello'.delete_suffix('hel') # => "hello"
- 'тест'.delete_suffix('ст') # => "те"
+ 'foo'.delete_suffix('o') # => "fo"
+ 'foo'.delete_suffix('oo') # => "f"
+ 'foo'.delete_suffix('foo') # => ""
+ 'foo'.delete_suffix('f') # => "foo"
+ 'foo'.delete_suffix('x') # => "foo"
'こんにちは'.delete_suffix('ちは') # => "こんに"
-Related: String#delete_suffix!, String#delete_prefix.
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/downcase.rdoc b/doc/string/downcase.rdoc
new file mode 100644
index 0000000000..d5fffa037b
--- /dev/null
+++ b/doc/string/downcase.rdoc
@@ -0,0 +1,20 @@
+Returns a new string containing the downcased characters in +self+:
+
+ 'HELLO'.downcase # => "hello"
+ 'STRAẞE'.downcase # => "straße"
+ 'ПРИВЕТ'.downcase # => "привет"
+ 'RubyGems.org'.downcase # => "rubygems.org"
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.downcase == s # => true
+ s = 'こんにちは'
+ s.downcase == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/dump.rdoc b/doc/string/dump.rdoc
new file mode 100644
index 0000000000..7b688c28a6
--- /dev/null
+++ b/doc/string/dump.rdoc
@@ -0,0 +1,89 @@
+For an ordinary string, this method, +String#dump+,
+returns a printable ASCII-only version of +self+, enclosed in double-quotes.
+
+For a dumped string, method String#undump is the inverse of +String#dump+;
+it returns a "restored" version of +self+,
+where all the dumping changes have been undone.
+
+In the simplest case, the dumped string contains the original string,
+enclosed in double-quotes;
+this example is done in +irb+ (interactive Ruby), which uses method `inspect` to render the results:
+
+ s = 'hello' # => "hello"
+ s.dump # => "\"hello\""
+ s.dump.undump # => "hello"
+
+Keep in mind that in the second line above:
+
+- The outer double-quotes are put on by +inspect+,
+ and _are_ _not_ part of the output of #dump.
+- The inner double-quotes _are_ part of the output of +dump+,
+ and are escaped by +inspect+ because they are within the outer double-quotes.
+
+To avoid confusion, we'll use this helper method to omit the outer double-quotes:
+
+ def dump(s)
+ print "String: ", s, "\n"
+ print "Dumped: ", s.dump, "\n"
+ print "Undumped: ", s.dump.undump, "\n"
+ end
+
+So that for string <tt>'hello'</tt>, we'll see:
+
+ String: hello
+ Dumped: "hello"
+ Undumped: hello
+
+In a dump, certain special characters are escaped:
+
+ String: "
+ Dumped: "\""
+ Undumped: "
+
+ String: \
+ Dumped: "\\"
+ Undumped: \
+
+In a dump, unprintable characters are replaced by printable ones;
+the unprintable characters are the whitespace characters (other than space itself);
+here we see the ordinals for those characters, together with explanatory text:
+
+ h = {
+ 7 => 'Alert (BEL)',
+ 8 => 'Backspace (BS)',
+ 9 => 'Horizontal tab (HT)',
+ 10 => 'Linefeed (LF)',
+ 11 => 'Vertical tab (VT)',
+ 12 => 'Formfeed (FF)',
+ 13 => 'Carriage return (CR)'
+ }
+
+In this example, the dumped output is printed by method #inspect,
+and so contains both outer double-quotes and escaped inner double-quotes:
+
+ s = ''
+ h.keys.each {|i| s << i } # => [7, 8, 9, 10, 11, 12, 13]
+ s # => "\a\b\t\n\v\f\r"
+ s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\""
+
+If +self+ is encoded in UTF-8 and contains Unicode characters,
+each Unicode character is dumped as a Unicode escape sequence:
+
+ String: こんにちは
+ Dumped: "\u3053\u3093\u306B\u3061\u306F"
+ Undumped: こんにちは
+
+If the encoding of +self+ is not ASCII-compatible
+(i.e., if <tt>self.encoding.ascii_compatible?</tt> returns +false+),
+each ASCII-compatible byte is dumped as an ASCII character,
+and all other bytes are dumped as hexadecimal;
+also appends <tt>.dup.force_encoding(\"encoding\")</tt>,
+where <tt><encoding></tt> is <tt>self.encoding.name</tt>:
+
+ String: hello
+ Dumped: "\xFE\xFF\x00h\x00e\x00l\x00l\x00o".dup.force_encoding("UTF-16")
+ Undumped: hello
+
+ String: こんにちは
+ Dumped: "\xFE\xFF0S0\x930k0a0o".dup.force_encoding("UTF-16")
+ Undumped: こんにちは
diff --git a/doc/string/each_byte.rdoc b/doc/string/each_byte.rdoc
index 643118fea3..642d71e84b 100644
--- a/doc/string/each_byte.rdoc
+++ b/doc/string/each_byte.rdoc
@@ -1,17 +1,15 @@
-Calls the given block with each successive byte from +self+;
+With a block given, calls the block with each successive byte from +self+;
returns +self+:
- 'hello'.each_byte {|byte| print byte, ' ' }
- print "\n"
- 'тест'.each_byte {|byte| print byte, ' ' }
- print "\n"
- 'こんにちは'.each_byte {|byte| print byte, ' ' }
- print "\n"
+ a = []
+ 'hello'.each_byte {|byte| a.push(byte) } # Five 1-byte characters.
+ a # => [104, 101, 108, 108, 111]
+ a = []
+ 'こんにちは'.each_byte {|byte| a.push(byte) } # Five 3-byte characters.
+ a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
-Output:
+With no block given, returns an enumerator.
+
+Related: see {Iterating}[rdoc-ref:String@Iterating].
- 104 101 108 108 111
- 209 130 208 181 209 129 209 130
- 227 129 147 227 130 147 227 129 171 227 129 161 227 129 175
-Returns an enumerator if no block is given.
diff --git a/doc/string/each_char.rdoc b/doc/string/each_char.rdoc
index e5ae5a1812..2dd56711d3 100644
--- a/doc/string/each_char.rdoc
+++ b/doc/string/each_char.rdoc
@@ -1,17 +1,17 @@
-Calls the given block with each successive character from +self+;
+With a block given, calls the block with each successive character from +self+;
returns +self+:
- 'hello'.each_char {|char| print char, ' ' }
- print "\n"
- 'тест'.each_char {|char| print char, ' ' }
- print "\n"
- 'こんにちは'.each_char {|char| print char, ' ' }
- print "\n"
+ a = []
+ 'hello'.each_char do |char|
+ a.push(char)
+ end
+ a # => ["h", "e", "l", "l", "o"]
+ a = []
+ 'こんにちは'.each_char do |char|
+ a.push(char)
+ end
+ a # => ["こ", "ん", "に", "ち", "は"]
-Output:
+With no block given, returns an enumerator.
- h e l l o
- т е с т
- こ ん に ち は
-
-Returns an enumerator if no block is given.
+Related: see {Iterating}[rdoc-ref:String@Iterating].
diff --git a/doc/string/each_codepoint.rdoc b/doc/string/each_codepoint.rdoc
index 88bfcbd1c0..8e4e7545e6 100644
--- a/doc/string/each_codepoint.rdoc
+++ b/doc/string/each_codepoint.rdoc
@@ -1,18 +1,18 @@
-Calls the given block with each successive codepoint from +self+;
-each codepoint is the integer value for a character;
+With a block given, calls the block with each successive codepoint from +self+;
+each {codepoint}[https://en.wikipedia.org/wiki/Code_point] is the integer value for a character;
returns +self+:
- 'hello'.each_codepoint {|codepoint| print codepoint, ' ' }
- print "\n"
- 'тест'.each_codepoint {|codepoint| print codepoint, ' ' }
- print "\n"
- 'こんにちは'.each_codepoint {|codepoint| print codepoint, ' ' }
- print "\n"
+ a = []
+ 'hello'.each_codepoint do |codepoint|
+ a.push(codepoint)
+ end
+ a # => [104, 101, 108, 108, 111]
+ a = []
+ 'こんにちは'.each_codepoint do |codepoint|
+ a.push(codepoint)
+ end
+ a # => [12371, 12435, 12395, 12385, 12399]
-Output:
+With no block given, returns an enumerator.
- 104 101 108 108 111
- 1090 1077 1089 1090
- 12371 12435 12395 12385 12399
-
-Returns an enumerator if no block is given.
+Related: see {Iterating}[rdoc-ref:String@Iterating].
diff --git a/doc/string/each_grapheme_cluster.rdoc b/doc/string/each_grapheme_cluster.rdoc
index 40be95fcac..384cd6967d 100644
--- a/doc/string/each_grapheme_cluster.rdoc
+++ b/doc/string/each_grapheme_cluster.rdoc
@@ -1,12 +1,19 @@
-Calls the given block with each successive grapheme cluster from +self+
+With a block given, calls the given block with each successive grapheme cluster from +self+
(see {Unicode Grapheme Cluster Boundaries}[https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries]);
returns +self+:
- s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈"
- s.each_grapheme_cluster {|gc| print gc, ' ' }
+ a = []
+ 'hello'.each_grapheme_cluster do |grapheme_cluster|
+ a.push(grapheme_cluster)
+ end
+ a # => ["h", "e", "l", "l", "o"]
-Output:
+ a = []
+ 'こんにちは'.each_grapheme_cluster do |grapheme_cluster|
+ a.push(grapheme_cluster)
+ end
+ a # => ["こ", "ん", "に", "ち", "は"]
- ä - p q r - b̈ - x y z - c̈
+With no block given, returns an enumerator.
-Returns an enumerator if no block is given.
+Related: see {Iterating}[rdoc-ref:String@Iterating].
diff --git a/doc/string/each_line.rdoc b/doc/string/each_line.rdoc
index e254c22d40..217c188e35 100644
--- a/doc/string/each_line.rdoc
+++ b/doc/string/each_line.rdoc
@@ -1,9 +1,12 @@
-With a block given, forms the substrings ("lines")
+With a block given, forms the substrings (lines)
that are the result of splitting +self+
-at each occurrence of the given line separator +line_sep+;
+at each occurrence of the given +record_separator+;
passes each line to the block;
-returns +self+:
+returns +self+.
+With the default +record_separator+:
+
+ $/ # => "\n"
s = <<~EOT
This is the first line.
This is line two.
@@ -11,7 +14,6 @@ returns +self+:
This is line four.
This is line five.
EOT
-
s.each_line {|line| p line }
Output:
@@ -22,9 +24,10 @@ Output:
"This is line four.\n"
"This is line five.\n"
-With a different +line_sep+:
+With a different +record_separator+:
- s.each_line(' is ') {|line| p line }
+ record_separator = ' is '
+ s.each_line(record_separator) {|line| p line }
Output:
@@ -34,7 +37,7 @@ Output:
"line four.\nThis is "
"line five.\n"
-With +chomp+ as +true+, removes the trailing +line_sep+ from each line:
+With +chomp+ as +true+, removes the trailing +record_separator+ from each line:
s.each_line(chomp: true) {|line| p line }
@@ -46,11 +49,12 @@ Output:
"This is line four."
"This is line five."
-With an empty string as +line_sep+,
+With an empty string as +record_separator+,
forms and passes "paragraphs" by splitting at each occurrence
of two or more newlines:
- s.each_line('') {|line| p line }
+ record_separator = ''
+ s.each_line(record_separator) {|line| p line }
Output:
@@ -58,3 +62,5 @@ Output:
"This is line four.\nThis is line five.\n"
With no block given, returns an enumerator.
+
+Related: see {Iterating}[rdoc-ref:String@Iterating].
diff --git a/doc/string/encode.rdoc b/doc/string/encode.rdoc
index 65872fdfd4..14b959ffff 100644
--- a/doc/string/encode.rdoc
+++ b/doc/string/encode.rdoc
@@ -1,4 +1,6 @@
-Returns a copy of +self+ transcoded as determined by +dst_encoding+.
+Returns a copy of +self+ transcoded as determined by +dst_encoding+;
+see {Encodings}[rdoc-ref:encodings.rdoc].
+
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.
@@ -45,3 +47,4 @@ given, conversion from an encoding +enc+ to the same encoding +enc+
no-op, i.e. the string is simply copied without any changes, and no
exceptions are raised, even if there are invalid bytes.
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/end_with_p.rdoc b/doc/string/end_with_p.rdoc
index f959cf7aaa..9a95d74fde 100644
--- a/doc/string/end_with_p.rdoc
+++ b/doc/string/end_with_p.rdoc
@@ -1,11 +1,9 @@
-Returns whether +self+ ends with any of the given +strings+.
+Returns whether +self+ ends with any of the given +strings+:
-Returns +true+ if any given string matches the end, +false+ otherwise:
+ 'foo'.end_with?('oo') # => true
+ 'foo'.end_with?('bar', 'oo') # => true
+ 'foo'.end_with?('bar', 'baz') # => false
+ 'foo'.end_with?('') # => true
+ 'こんにちは'.end_with?('は') # => true
- 'hello'.end_with?('ello') #=> true
- 'hello'.end_with?('heaven', 'ello') #=> true
- 'hello'.end_with?('heaven', 'paradise') #=> false
- 'тест'.end_with?('т') # => true
- 'こんにちは'.end_with?('は') # => true
-
-Related: String#start_with?.
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/eql_p.rdoc b/doc/string/eql_p.rdoc
new file mode 100644
index 0000000000..85409c5ed6
--- /dev/null
+++ b/doc/string/eql_p.rdoc
@@ -0,0 +1,18 @@
+Returns whether +self+ and +object+ have the same length and content:
+
+ s = 'foo'
+ s.eql?('foo') # => true
+ s.eql?('food') # => false
+ s.eql?('FOO') # => false
+
+Returns +false+ if the two strings' encodings are not compatible:
+
+ s0 = "äöü" # => "äöü"
+ s1 = s0.encode(Encoding::ISO_8859_1) # => "\xE4\xF6\xFC"
+ s0.encoding # => #<Encoding:UTF-8>
+ s1.encoding # => #<Encoding:ISO-8859-1>
+ s0.eql?(s1) # => false
+
+See {Encodings}[rdoc-ref:encodings.rdoc].
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/force_encoding.rdoc b/doc/string/force_encoding.rdoc
index fd9615caaa..a509e67f80 100644
--- a/doc/string/force_encoding.rdoc
+++ b/doc/string/force_encoding.rdoc
@@ -1,5 +1,6 @@
-Changes the encoding of +self+ to +encoding+,
+Changes the encoding of +self+ to the given +encoding+,
which may be a string encoding name or an Encoding object;
+does not change the underlying bytes;
returns self:
s = 'łał'
@@ -7,14 +8,14 @@ returns self:
s.encoding # => #<Encoding:UTF-8>
s.force_encoding('ascii') # => "\xC5\x82a\xC5\x82"
s.encoding # => #<Encoding:US-ASCII>
-
-Does not change the underlying bytes:
-
+ s.valid_encoding? # => true
s.bytes # => [197, 130, 97, 197, 130]
Makes the change even if the given +encoding+ is invalid
for +self+ (as is the change above):
- s.valid_encoding? # => false
- s.force_encoding(Encoding::UTF_8) # => "łał"
- s.valid_encoding? # => true
+ s.valid_encoding? # => false
+
+See {Encodings}[rdoc-ref:encodings.rdoc].
+
+Related: see {Modifying}[rdoc-ref:String@Modifying].
diff --git a/doc/string/getbyte.rdoc b/doc/string/getbyte.rdoc
new file mode 100644
index 0000000000..974e21c473
--- /dev/null
+++ b/doc/string/getbyte.rdoc
@@ -0,0 +1,23 @@
+Returns the byte at zero-based +index+ as an integer:
+
+ s = 'foo'
+ s.getbyte(0) # => 102
+ s.getbyte(1) # => 111
+ s.getbyte(2) # => 111
+
+Counts backward from the end if +index+ is negative:
+
+ s.getbyte(-3) # => 102
+
+Returns +nil+ if +index+ is out of range:
+
+ s.getbyte(3) # => nil
+ s.getbyte(-4) # => nil
+
+More examples:
+
+ s = 'こんにちは'
+ s.bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+ s.getbyte(2) # => 147
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/grapheme_clusters.rdoc b/doc/string/grapheme_clusters.rdoc
index 8c7f5a7259..ee8b45700e 100644
--- a/doc/string/grapheme_clusters.rdoc
+++ b/doc/string/grapheme_clusters.rdoc
@@ -1,6 +1,19 @@
Returns an array of the grapheme clusters in +self+
(see {Unicode Grapheme Cluster Boundaries}[https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries]):
- s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈"
+ s = "ä-pqr-b̈-xyz-c̈"
+ s.size # => 16
+ s.bytesize # => 19
+ s.grapheme_clusters.size # => 13
s.grapheme_clusters
# => ["ä", "-", "p", "q", "r", "-", "b̈", "-", "x", "y", "z", "-", "c̈"]
+
+Details:
+
+ s = "ä"
+ s.grapheme_clusters # => ["ä"] # One grapheme cluster.
+ s.bytes # => [97, 204, 136] # Three bytes.
+ s.chars # => ["a", "̈"] # Two characters.
+ s.chars.map {|char| char.ord } # => [97, 776] # Their values.
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/hash.rdoc b/doc/string/hash.rdoc
new file mode 100644
index 0000000000..fe94770ed9
--- /dev/null
+++ b/doc/string/hash.rdoc
@@ -0,0 +1,19 @@
+Returns the integer hash value for +self+.
+
+Two \String objects that have identical content and compatible encodings
+also have the same hash value;
+see Object#hash and {Encodings}[rdoc-ref:encodings.rdoc]:
+
+ s = 'foo'
+ h = s.hash # => -569050784
+ h == 'foo'.hash # => true
+ h == 'food'.hash # => false
+ h == 'FOO'.hash # => false
+
+ s0 = "äöü"
+ s1 = s0.encode(Encoding::ISO_8859_1)
+ s0.encoding # => #<Encoding:UTF-8>
+ s1.encoding # => #<Encoding:ISO-8859-1>
+ s0.hash == s1.hash # => false
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/index.rdoc b/doc/string/index.rdoc
index ce09a37bdf..c3cff24dac 100644
--- a/doc/string/index.rdoc
+++ b/doc/string/index.rdoc
@@ -1,31 +1,31 @@
-Returns the integer index of the first match for the given argument,
-or +nil+ if none found;
-the search of +self+ is forward, and begins at position +offset+ (in characters).
+Returns the integer position of the first substring that matches the given argument +pattern+,
+or +nil+ if none found.
-With string argument +substring+,
+When +pattern+ is a string,
returns the index of the first matching substring in +self+:
'foo'.index('f') # => 0
'foo'.index('o') # => 1
'foo'.index('oo') # => 1
'foo'.index('ooo') # => nil
- 'тест'.index('с') # => 2
- 'こんにちは'.index('ち') # => 3
+ 'こんにちは'.index('ち') # => 3
-With Regexp argument +regexp+, returns the index of the first match in +self+:
+When +pattern+ is a Regexp, returns the index of the first match in +self+:
'foo'.index(/o./) # => 1
'foo'.index(/.o/) # => 0
-With positive integer +offset+, begins the search at position +offset+:
+When +offset+ is non-negative, begins the search at position +offset+;
+the returned index is relative to the beginning of +self+:
- 'foo'.index('o', 1) # => 1
- 'foo'.index('o', 2) # => 2
- 'foo'.index('o', 3) # => nil
- 'тест'.index('с', 1) # => 2
- 'こんにちは'.index('ち', 2) # => 3
+ 'bar'.index('r', 0) # => 2
+ 'bar'.index('r', 1) # => 2
+ 'bar'.index('r', 2) # => 2
+ 'bar'.index('r', 3) # => nil
+ 'bar'.index(/[r-z]/, 0) # => 2
+ 'こんにちは'.index('ち', 2) # => 3
-With negative integer +offset+, selects the search position by counting backward
+With negative integer argument +offset+, selects the search position by counting backward
from the end of +self+:
'foo'.index('o', -1) # => 2
@@ -35,4 +35,4 @@ from the end of +self+:
'foo'.index(/o./, -2) # => 1
'foo'.index(/.o/, -2) # => 1
-Related: String#rindex.
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/insert.rdoc b/doc/string/insert.rdoc
new file mode 100644
index 0000000000..73205f2069
--- /dev/null
+++ b/doc/string/insert.rdoc
@@ -0,0 +1,15 @@
+Inserts the given +other_string+ into +self+; returns +self+.
+
+If the given +index+ is non-negative, inserts +other_string+ at offset +index+:
+
+ 'foo'.insert(0, 'bar') # => "barfoo"
+ 'foo'.insert(1, 'bar') # => "fbaroo"
+ 'foo'.insert(3, 'bar') # => "foobar"
+ 'こんにちは'.insert(2, 'bar') # => "こんbarにちは"
+
+If the +index+ is negative, counts backward from the end of +self+
+and inserts +other_string+ _after_ the offset:
+
+ 'foo'.insert(-2, 'bar') # => "fobaro"
+
+Related: see {Modifying}[rdoc-ref:String@Modifying].
diff --git a/doc/string/inspect.rdoc b/doc/string/inspect.rdoc
new file mode 100644
index 0000000000..398a5a74c5
--- /dev/null
+++ b/doc/string/inspect.rdoc
@@ -0,0 +1,38 @@
+Returns a printable version of +self+, enclosed in double-quotes.
+
+Most printable characters are rendered simply as themselves:
+
+ 'abc'.inspect # => "\"abc\""
+ '012'.inspect # => "\"012\""
+ ''.inspect # => "\"\""
+ "\u000012".inspect # => "\"\\u000012\""
+ 'こんにちは'.inspect # => "\"こんにちは\""
+
+But printable characters double-quote (<tt>'"'</tt>) and backslash and (<tt>'\\'</tt>) are escaped:
+
+ '"'.inspect # => "\"\\\"\""
+ '\\'.inspect # => "\"\\\\\""
+
+Unprintable characters are the {ASCII characters}[https://en.wikipedia.org/wiki/ASCII]
+whose values are in range <tt>0..31</tt>,
+along with the character whose value is +127+.
+
+Most of these characters are rendered thus:
+
+ 0.chr.inspect # => "\"\\x00\""
+ 1.chr.inspect # => "\"\\x01\""
+ 2.chr.inspect # => "\"\\x02\""
+ # ...
+
+A few, however, have special renderings:
+
+ 7.chr.inspect # => "\"\\a\"" # BEL
+ 8.chr.inspect # => "\"\\b\"" # BS
+ 9.chr.inspect # => "\"\\t\"" # TAB
+ 10.chr.inspect # => "\"\\n\"" # LF
+ 11.chr.inspect # => "\"\\v\"" # VT
+ 12.chr.inspect # => "\"\\f\"" # FF
+ 13.chr.inspect # => "\"\\r\"" # CR
+ 27.chr.inspect # => "\"\\e\"" # ESC
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/intern.rdoc b/doc/string/intern.rdoc
new file mode 100644
index 0000000000..c82302b906
--- /dev/null
+++ b/doc/string/intern.rdoc
@@ -0,0 +1,8 @@
+Returns the Symbol object derived from +self+,
+creating it if it did not already exist:
+
+ 'foo'.intern # => :foo
+ 'こんにちは'.intern # => :こんにちは
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
+
diff --git a/doc/string/length.rdoc b/doc/string/length.rdoc
index 544bca269f..eb68edb10c 100644
--- a/doc/string/length.rdoc
+++ b/doc/string/length.rdoc
@@ -1,12 +1,11 @@
Returns the count of characters (not bytes) in +self+:
'foo'.length # => 3
- 'тест'.length # => 4
- 'こんにちは'.length # => 5
+ 'こんにちは'.length # => 5
Contrast with String#bytesize:
'foo'.bytesize # => 3
- 'тест'.bytesize # => 8
- 'こんにちは'.bytesize # => 15
+ 'こんにちは'.bytesize # => 15
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/ljust.rdoc b/doc/string/ljust.rdoc
index 8e23c1fc8f..a8ca62ee76 100644
--- a/doc/string/ljust.rdoc
+++ b/doc/string/ljust.rdoc
@@ -1,16 +1,13 @@
-Returns a left-justified copy of +self+.
-
-If integer argument +size+ is greater than the size (in characters) of +self+,
-returns a new string of length +size+ that is a copy of +self+,
-left justified and padded on the right with +pad_string+:
+Returns a copy of +self+, left-justified and, if necessary, right-padded with the +pad_string+:
'hello'.ljust(10) # => "hello "
' hello'.ljust(10) # => " hello "
'hello'.ljust(10, 'ab') # => "helloababa"
- 'тест'.ljust(10) # => "тест "
- 'こんにちは'.ljust(10) # => "こんにちは "
+ 'こんにちは'.ljust(10) # => "こんにちは "
-If +size+ is not greater than the size of +self+, returns a copy of +self+:
+If <tt>width <= self.length</tt>, returns a copy of +self+:
'hello'.ljust(5) # => "hello"
- 'hello'.ljust(1) # => "hello"
+ 'hello'.ljust(1) # => "hello" # Does not truncate to width.
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/new.rdoc b/doc/string/new.rdoc
index 1d44291f76..e2752d6e1f 100644
--- a/doc/string/new.rdoc
+++ b/doc/string/new.rdoc
@@ -1,34 +1,38 @@
-Returns a new \String that is a copy of +string+.
+Returns a new \String object containing the given +string+.
-With no arguments, returns the empty string with the Encoding <tt>ASCII-8BIT</tt>:
+The +options+ are optional keyword options (see below).
- s = String.new
- s # => ""
- s.encoding # => #<Encoding:ASCII-8BIT>
+With no argument given and keyword +encoding+ also not given,
+returns an empty string with the Encoding <tt>ASCII-8BIT</tt>:
-With optional argument +string+ and no keyword arguments,
-returns a copy of +string+ with the same encoding:
+ s = String.new # => ""
+ s.encoding # => #<Encoding:ASCII-8BIT>
- String.new('foo') # => "foo"
- String.new('тест') # => "тест"
- String.new('こんにちは') # => "こんにちは"
+With argument +string+ given and keyword option +encoding+ not given,
+returns a new string with the same encoding as +string+:
+
+ s0 = 'foo'.encode(Encoding::UTF_16)
+ s1 = String.new(s0)
+ s1.encoding # => #<Encoding:UTF-16 (dummy)>
(Unlike \String.new,
a {string literal}[rdoc-ref:syntax/literals.rdoc@String+Literals] like <tt>''</tt> or a
{here document literal}[rdoc-ref:syntax/literals.rdoc@Here+Document+Literals]
always has {script encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].)
-With optional keyword argument +encoding+, returns a copy of +string+
-with the specified encoding;
+With keyword option +encoding+ given,
+returns a string with the specified encoding;
the +encoding+ may be an Encoding object, an encoding name,
or an encoding name alias:
+ String.new(encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
+ String.new('', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'US-ASCII').encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'ASCII').encoding # => #<Encoding:US-ASCII>
The given encoding need not be valid for the string's content,
-and that validity is not checked:
+and its validity is not checked:
s = String.new('こんにちは', encoding: 'ascii')
s.valid_encoding? # => false
@@ -37,19 +41,11 @@ But the given +encoding+ itself is checked:
String.new('foo', encoding: 'bar') # Raises ArgumentError.
-With optional keyword argument +capacity+, returns a copy of +string+
-(or an empty string, if +string+ is not given);
-the given +capacity+ is advisory only,
+With keyword option +capacity+ given,
+the given value is advisory only,
and may or may not set the size of the internal buffer,
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)
+ String.new('foo', capacity: 1) # Buffer size is at least 4 (includes terminal null byte).
+ String.new('foo', capacity: 4096) # Buffer size is at least 4;
+ # may be equal to, greater than, or less than 4096.
diff --git a/doc/string/ord.rdoc b/doc/string/ord.rdoc
index d586363d44..8c460d3ba4 100644
--- a/doc/string/ord.rdoc
+++ b/doc/string/ord.rdoc
@@ -2,5 +2,6 @@ Returns the integer ordinal of the first character of +self+:
'h'.ord # => 104
'hello'.ord # => 104
- 'тест'.ord # => 1090
'こんにちは'.ord # => 12371
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/partition.rdoc b/doc/string/partition.rdoc
index ebe575e8eb..b2e620a9fc 100644
--- a/doc/string/partition.rdoc
+++ b/doc/string/partition.rdoc
@@ -1,24 +1,43 @@
Returns a 3-element array of substrings of +self+.
-Matches a pattern against +self+, scanning from the beginning.
-The pattern is:
+If +pattern+ is matched, returns the array:
-- +string_or_regexp+ itself, if it is a Regexp.
-- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
+ [pre_match, first_match, post_match]
-If the pattern is matched, returns pre-match, first-match, post-match:
+where:
- 'hello'.partition('l') # => ["he", "l", "lo"]
- 'hello'.partition('ll') # => ["he", "ll", "o"]
- 'hello'.partition('h') # => ["", "h", "ello"]
- 'hello'.partition('o') # => ["hell", "o", ""]
- 'hello'.partition(/l+/) #=> ["he", "ll", "o"]
- 'hello'.partition('') # => ["", "", "hello"]
- 'тест'.partition('т') # => ["", "т", "ест"]
- 'こんにちは'.partition('に') # => ["こん", "に", "ちは"]
+- +first_match+ is the first-found matching substring.
+- +pre_match+ and +post_match+ are the preceding and following substrings.
-If the pattern is not matched, returns a copy of +self+ and two empty strings:
+If +pattern+ is not matched, returns the array:
- 'hello'.partition('x') # => ["hello", "", ""]
+ [self.dup, "", ""]
-Related: String#rpartition, String#split.
+Note that in the examples below, a returned string <tt>'hello'</tt>
+is a copy of +self+, not +self+.
+
+If +pattern+ is a Regexp, performs the equivalent of <tt>self.match(pattern)</tt>
+(also setting {matched-data variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.partition(/h/) # => ["", "h", "ello"]
+ 'hello'.partition(/l/) # => ["he", "l", "lo"]
+ 'hello'.partition(/l+/) # => ["he", "ll", "o"]
+ 'hello'.partition(/o/) # => ["hell", "o", ""]
+ 'hello'.partition(/^/) # => ["", "", "hello"]
+ 'hello'.partition(//) # => ["", "", "hello"]
+ 'hello'.partition(/$/) # => ["hello", "", ""]
+ 'hello'.partition(/x/) # => ["hello", "", ""]
+
+If +pattern+ is not a Regexp, converts it to a string (if it is not already one),
+then performs the equivalent of <tt>self.index(pattern)</tt>
+(and does _not_ set {matched-data global variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.partition('h') # => ["", "h", "ello"]
+ 'hello'.partition('l') # => ["he", "l", "lo"]
+ 'hello'.partition('ll') # => ["he", "ll", "o"]
+ 'hello'.partition('o') # => ["hell", "o", ""]
+ 'hello'.partition('') # => ["", "", "hello"]
+ 'hello'.partition('x') # => ["hello", "", ""]
+ 'こんにちは'.partition('に') # => ["こん", "に", "ちは"]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/rindex.rdoc b/doc/string/rindex.rdoc
new file mode 100644
index 0000000000..2b81c3716d
--- /dev/null
+++ b/doc/string/rindex.rdoc
@@ -0,0 +1,51 @@
+Returns the integer position of the _last_ substring that matches the given argument +pattern+,
+or +nil+ if none found.
+
+When +pattern+ is a string, returns the index of the last matching substring in self:
+
+ 'foo'.rindex('f') # => 0
+ 'foo'.rindex('o') # => 2
+ 'foo'.rindex('oo' # => 1
+ 'foo'.rindex('ooo') # => nil
+ 'こんにちは'.rindex('ち') # => 3
+
+When +pattern+ is a Regexp, returns the index of the last match in self:
+
+ 'foo'.rindex(/f/) # => 0
+ 'foo'.rindex(/o/) # => 2
+ 'foo'.rindex(/oo/) # => 1
+ 'foo'.rindex(/ooo/) # => nil
+
+When +offset+ is non-negative, it specifies the maximum starting position in the
+string to end the search:
+
+ 'foo'.rindex('o', 0) # => nil
+ 'foo'.rindex('o', 1) # => 1
+ 'foo'.rindex('o', 2) # => 2
+ 'foo'.rindex('o', 3) # => 2
+
+With negative integer argument +offset+,
+selects the search position by counting backward from the end of +self+:
+
+ 'foo'.rindex('o', -1) # => 2
+ 'foo'.rindex('o', -2) # => 1
+ 'foo'.rindex('o', -3) # => nil
+ 'foo'.rindex('o', -4) # => nil
+
+The last match means starting at the possible last position, not
+the last of longest matches:
+
+ 'foo'.rindex(/o+/) # => 2
+ $~ # => #<MatchData "o">
+
+To get the last longest match, combine with negative lookbehind:
+
+ 'foo'.rindex(/(?<!o)o+/) # => 1
+ $~ # => #<MatchData "oo">
+
+Or String#index with negative lookforward.
+
+ 'foo'.index(/o+(?!.*o)/) # => 1
+ $~ # => #<MatchData "oo">
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/rjust.rdoc b/doc/string/rjust.rdoc
index 24e7bf3159..acd3f198d4 100644
--- a/doc/string/rjust.rdoc
+++ b/doc/string/rjust.rdoc
@@ -1,16 +1,17 @@
Returns a right-justified copy of +self+.
-If integer argument +size+ is greater than the size (in characters) of +self+,
-returns a new string of length +size+ that is a copy of +self+,
+If integer argument +width+ is greater than the size (in characters) of +self+,
+returns a new string of length +width+ that is a copy of +self+,
right justified and padded on the left with +pad_string+:
'hello'.rjust(10) # => " hello"
'hello '.rjust(10) # => " hello "
'hello'.rjust(10, 'ab') # => "ababahello"
- 'тест'.rjust(10) # => " тест"
'こんにちは'.rjust(10) # => " こんにちは"
-If +size+ is not greater than the size of +self+, returns a copy of +self+:
+If <tt>width <= self.size</tt>, returns a copy of +self+:
'hello'.rjust(5, 'ab') # => "hello"
'hello'.rjust(1, 'ab') # => "hello"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/rpartition.rdoc b/doc/string/rpartition.rdoc
index d24106fb9f..add95b1f40 100644
--- a/doc/string/rpartition.rdoc
+++ b/doc/string/rpartition.rdoc
@@ -1,24 +1,47 @@
Returns a 3-element array of substrings of +self+.
-Matches a pattern against +self+, scanning backwards from the end.
-The pattern is:
+Searches +self+ for a match of +pattern+, seeking the _last_ match.
-- +string_or_regexp+ itself, if it is a Regexp.
-- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
+If +pattern+ is not matched, returns the array:
-If the pattern is matched, returns pre-match, last-match, post-match:
+ ["", "", self.dup]
- 'hello'.rpartition('l') # => ["hel", "l", "o"]
- 'hello'.rpartition('ll') # => ["he", "ll", "o"]
- 'hello'.rpartition('h') # => ["", "h", "ello"]
- 'hello'.rpartition('o') # => ["hell", "o", ""]
- 'hello'.rpartition(/l+/) # => ["hel", "l", "o"]
- 'hello'.rpartition('') # => ["hello", "", ""]
- 'тест'.rpartition('т') # => ["тес", "т", ""]
- 'こんにちは'.rpartition('に') # => ["こん", "に", "ちは"]
+If +pattern+ is matched, returns the array:
-If the pattern is not matched, returns two empty strings and a copy of +self+:
+ [pre_match, last_match, post_match]
- 'hello'.rpartition('x') # => ["", "", "hello"]
+where:
-Related: String#partition, String#split.
+- +last_match+ is the last-found matching substring.
+- +pre_match+ and +post_match+ are the preceding and following substrings.
+
+The pattern used is:
+
+- +pattern+ itself, if it is a Regexp.
+- <tt>Regexp.quote(pattern)</tt>, if +pattern+ is a string.
+
+Note that in the examples below, a returned string <tt>'hello'</tt> is a copy of +self+, not +self+.
+
+If +pattern+ is a Regexp, searches for the last matching substring
+(also setting {matched-data global variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.rpartition(/l/) # => ["hel", "l", "o"]
+ 'hello'.rpartition(/ll/) # => ["he", "ll", "o"]
+ 'hello'.rpartition(/h/) # => ["", "h", "ello"]
+ 'hello'.rpartition(/o/) # => ["hell", "o", ""]
+ 'hello'.rpartition(//) # => ["hello", "", ""]
+ 'hello'.rpartition(/x/) # => ["", "", "hello"]
+ 'こんにちは'.rpartition(/に/) # => ["こん", "に", "ちは"]
+
+If +pattern+ is not a Regexp, converts it to a string (if it is not already one),
+then searches for the last matching substring
+(and does _not_ set {matched-data global variables}[rdoc-ref:language/globals.md@Matched+Data]):
+
+ 'hello'.rpartition('l') # => ["hel", "l", "o"]
+ 'hello'.rpartition('ll') # => ["he", "ll", "o"]
+ 'hello'.rpartition('h') # => ["", "h", "ello"]
+ 'hello'.rpartition('o') # => ["hell", "o", ""]
+ 'hello'.rpartition('') # => ["hello", "", ""]
+ 'こんにちは'.rpartition('に') # => ["こん", "に", "ちは"]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/scan.rdoc b/doc/string/scan.rdoc
new file mode 100644
index 0000000000..d39b5b6dfa
--- /dev/null
+++ b/doc/string/scan.rdoc
@@ -0,0 +1,35 @@
+Matches a pattern against +self+:
+
+- If +pattern+ is a Regexp, the pattern used is +pattern+ itself.
+- If +pattern+ is a string, the pattern used is <tt>Regexp.quote(pattern)</tt>.
+
+Generates a collection of matching results
+and updates {regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+- If the pattern contains no groups, each result is a matched substring.
+- If the pattern contains groups, each result is an array
+ containing a matched substring for each group.
+
+With no block given, returns an array of the results:
+
+ 'cruel world'.scan(/\w+/) # => ["cruel", "world"]
+ 'cruel world'.scan(/.../) # => ["cru", "el ", "wor"]
+ 'cruel world'.scan(/(...)/) # => [["cru"], ["el "], ["wor"]]
+ 'cruel world'.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]]
+ 'こんにちは'.scan(/../) # => ["こん", "にち"]
+ 'abracadabra'.scan('ab') # => ["ab", "ab"]
+ 'abracadabra'.scan('nosuch') # => []
+
+With a block given, calls the block with each result; returns +self+:
+
+ 'cruel world'.scan(/\w+/) {|w| p w }
+ # => "cruel"
+ # => "world"
+ 'cruel world'.scan(/(.)(.)/) {|x, y| p [x, y] }
+ # => ["c", "r"]
+ # => ["u", "e"]
+ # => ["l", " "]
+ # => ["w", "o"]
+ # => ["r", "l"]
+
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/scrub.rdoc b/doc/string/scrub.rdoc
index 1a5b1c79d0..314b28c465 100644
--- a/doc/string/scrub.rdoc
+++ b/doc/string/scrub.rdoc
@@ -1,25 +1,22 @@
Returns a copy of +self+ with each invalid byte sequence replaced
by the given +replacement_string+.
-With no block given and no argument, replaces each invalid sequence
-with the default replacement string
-(<tt>"�"</tt> for a Unicode encoding, <tt>'?'</tt> otherwise):
+With no block given, replaces each invalid sequence
+with the given +default_replacement_string+
+(by default, <tt>"�"</tt> for a Unicode encoding, <tt>'?'</tt> otherwise):
- s = "foo\x81\x81bar"
- s.scrub # => "foo��bar"
+ "foo\x81\x81bar".scrub # => "foo��bar"
+ "foo\x81\x81bar".force_encoding('US-ASCII').scrub # => "foo??bar"
+ "foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"
-With no block given and argument +replacement_string+ given,
-replaces each invalid sequence with that string:
+With a block given, calls the block with each invalid sequence,
+and replaces that sequence with the return value of the block:
- "foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"
+ "foo\x81\x81bar".scrub {|sequence| p sequence; 'XYZZY' } # => "fooXYZZYXYZZYbar"
-With a block given, replaces each invalid sequence with the value
-of the block:
-
- "foo\x81\x81bar".scrub {|bytes| p bytes; 'XYZZY' }
- # => "fooXYZZYXYZZYbar"
-
-Output:
+Output :
"\x81"
"\x81"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/split.rdoc b/doc/string/split.rdoc
index 95dda3c654..8679149003 100644
--- a/doc/string/split.rdoc
+++ b/doc/string/split.rdoc
@@ -1,84 +1,101 @@
-Returns an array of substrings of +self+
-that are the result of splitting +self+
+Creates an array of substrings by splitting +self+
at each occurrence of the given field separator +field_sep+.
-When +field_sep+ is <tt>$;</tt>:
+With no arguments given,
+splits using the field separator <tt>$;</tt>,
+whose default value is +nil+.
-- If <tt>$;</tt> is +nil+ (its default value),
- the split occurs just as if +field_sep+ were given as a space character
- (see below).
+With no block given, returns the array of substrings:
-- If <tt>$;</tt> is a string,
- the split occurs just as if +field_sep+ were given as that string
- (see below).
+ 'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
-When +field_sep+ is <tt>' '</tt> and +limit+ is +0+ (its default value),
-the split occurs at each sequence of whitespace:
+When +field_sep+ is +nil+ or <tt>' '</tt> (a single space),
+splits at each sequence of whitespace:
- 'abc def ghi'.split(' ') => ["abc", "def", "ghi"]
- "abc \n\tdef\t\n ghi".split(' ') # => ["abc", "def", "ghi"]
- 'abc def ghi'.split(' ') => ["abc", "def", "ghi"]
- ''.split(' ') => []
+ 'foo bar baz'.split(nil) # => ["foo", "bar", "baz"]
+ 'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
+ "foo \n\tbar\t\n baz".split(' ') # => ["foo", "bar", "baz"]
+ 'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
+ ''.split(' ') # => []
-When +field_sep+ is a string different from <tt>' '</tt>
-and +limit+ is +0+,
-the split occurs at each occurrence of +field_sep+;
-trailing empty substrings are not returned:
+When +field_sep+ is an empty string,
+splits at every character:
- 'abracadabra'.split('ab') => ["", "racad", "ra"]
- 'aaabcdaaa'.split('a') => ["", "", "", "bcd"]
- ''.split('a') => []
- '3.14159'.split('1') => ["3.", "4", "59"]
- '!@#$%^$&*($)_+'.split('$') # => ["!@#", "%^", "&*(", ")_+"]
- 'тест'.split('т') => ["", "ес"]
- 'こんにちは'.split('に') => ["こん", "ちは"]
+ 'abracadabra'.split('') # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
+ ''.split('') # => []
+ 'こんにちは'.split('') # => ["こ", "ん", "に", "ち", "は"]
-When +field_sep+ is a Regexp and +limit+ is +0+,
-the split occurs at each occurrence of a match;
-trailing empty substrings are not returned:
+When +field_sep+ is a non-empty string and different from <tt>' '</tt> (a single space),
+uses that string as the separator:
+
+ 'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
+ 'abracadabra'.split('ab') # => ["", "racad", "ra"]
+ ''.split('a') # => []
+ 'こんにちは'.split('に') # => ["こん", "ちは"]
+
+When +field_sep+ is a Regexp,
+splits at each occurrence of a matching substring:
'abracadabra'.split(/ab/) # => ["", "racad", "ra"]
- 'aaabcdaaa'.split(/a/) => ["", "", "", "bcd"]
- 'aaabcdaaa'.split(//) => ["a", "a", "a", "b", "c", "d", "a", "a", "a"]
'1 + 1 == 2'.split(/\W+/) # => ["1", "1", "2"]
+ 'abracadabra'.split(//) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
-If the \Regexp contains groups, their matches are also included
+If the \Regexp contains groups, their matches are included
in the returned array:
'1:2:3'.split(/(:)()()/, 2) # => ["1", ":", "", "", "2:3"]
-As seen above, if +limit+ is +0+,
-trailing empty substrings are not returned:
+Argument +limit+ sets a limit on the size of the returned array;
+it also determines whether trailing empty strings are included in the returned array.
+
+When +limit+ is zero,
+there is no limit on the size of the array,
+but trailing empty strings are omitted:
+
+ 'abracadabra'.split('', 0) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"]
+ 'abracadabra'.split('a', 0) # => ["", "br", "c", "d", "br"] # Empty string after last 'a' omitted.
+
+When +limit+ is a positive integer,
+there is a limit on the size of the array (no more than <tt>n - 1</tt> splits occur),
+and trailing empty strings are included:
+
+ 'abracadabra'.split('', 3) # => ["a", "b", "racadabra"]
+ 'abracadabra'.split('a', 3) # => ["", "br", "cadabra"]
+ 'abracadabra'.split('', 30) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""]
+ 'abracadabra'.split('a', 30) # => ["", "br", "c", "d", "br", ""]
+ 'abracadabra'.split('', 1) # => ["abracadabra"]
+ 'abracadabra'.split('a', 1) # => ["abracadabra"]
+
+When +limit+ is negative,
+there is no limit on the size of the array,
+and trailing empty strings are omitted:
+
+ 'abracadabra'.split('', -1) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""]
+ 'abracadabra'.split('a', -1) # => ["", "br", "c", "d", "br", ""]
- 'aaabcdaaa'.split('a') => ["", "", "", "bcd"]
+If a block is given, it is called with each substring and returns +self+:
-If +limit+ is positive integer +n+, no more than <tt>n - 1-</tt>
-splits occur, so that at most +n+ substrings are returned,
-and trailing empty substrings are included:
+ 'foo bar baz'.split(' ') {|substring| p substring }
- 'aaabcdaaa'.split('a', 1) # => ["aaabcdaaa"]
- 'aaabcdaaa'.split('a', 2) # => ["", "aabcdaaa"]
- 'aaabcdaaa'.split('a', 5) # => ["", "", "", "bcd", "aa"]
- 'aaabcdaaa'.split('a', 7) # => ["", "", "", "bcd", "", "", ""]
- 'aaabcdaaa'.split('a', 8) # => ["", "", "", "bcd", "", "", ""]
+Output :
-Note that if +field_sep+ is a \Regexp containing groups,
-their matches are in the returned array, but do not count toward the limit.
+ "foo"
+ "bar"
+ "baz"
-If +limit+ is negative, it behaves the same as if +limit+ was zero,
-meaning that there is no limit,
-and trailing empty substrings are included:
+Note that the above example is functionally equivalent to:
- 'aaabcdaaa'.split('a', -1) # => ["", "", "", "bcd", "", "", ""]
+ 'foo bar baz'.split(' ').each {|substring| p substring }
-If a block is given, it is called with each substring:
+Output :
- 'abc def ghi'.split(' ') {|substring| p substring }
+ "foo"
+ "bar"
+ "baz"
-Output:
+But the latter:
- "abc"
- "def"
- "ghi"
+- Has poorer performance because it creates an intermediate array.
+- Returns an array (instead of +self+).
-Related: String#partition, String#rpartition.
+Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
diff --git a/doc/string/squeeze.rdoc b/doc/string/squeeze.rdoc
new file mode 100644
index 0000000000..1a38c08b32
--- /dev/null
+++ b/doc/string/squeeze.rdoc
@@ -0,0 +1,33 @@
+Returns a copy of +self+ with each tuple (doubling, tripling, etc.) of specified characters
+"squeezed" down to a single character.
+
+The tuples to be squeezed are specified by arguments +selectors+,
+each of which is a string;
+see {Character Selectors}[rdoc-ref:character_selectors.rdoc@Character+Selectors].
+
+A single argument may be a single character:
+
+ 'Noooooo!'.squeeze('o') # => "No!"
+ 'foo bar baz'.squeeze(' ') # => "foo bar baz"
+ 'Mississippi'.squeeze('s') # => "Misisippi"
+ 'Mississippi'.squeeze('p') # => "Mississipi"
+ 'Mississippi'.squeeze('x') # => "Mississippi" # Unused selector character is ignored.
+ 'бессонница'.squeeze('с') # => "бесонница"
+ 'бессонница'.squeeze('н') # => "бессоница"
+
+A single argument may be a string of characters:
+
+ 'Mississippi'.squeeze('sp') # => "Misisipi"
+ 'Mississippi'.squeeze('ps') # => "Misisipi" # Order doesn't matter.
+ 'Mississippi'.squeeze('nonsense') # => "Misisippi" # Unused selector characters are ignored.
+
+A single argument may be a range of characters:
+
+ 'Mississippi'.squeeze('a-p') # => "Mississipi"
+ 'Mississippi'.squeeze('q-z') # => "Misisippi"
+ 'Mississippi'.squeeze('a-z') # => "Misisipi"
+
+Multiple arguments are allowed;
+see {Multiple Character Selectors}[rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/start_with_p.rdoc b/doc/string/start_with_p.rdoc
index 5d1f9f9543..f78edc7fa3 100644
--- a/doc/string/start_with_p.rdoc
+++ b/doc/string/start_with_p.rdoc
@@ -1,10 +1,9 @@
-Returns whether +self+ starts with any of the given +string_or_regexp+.
+Returns whether +self+ starts with any of the given +patterns+.
-Matches patterns against the beginning of +self+.
-For each given +string_or_regexp+, the pattern is:
+For each argument, the pattern used is:
-- +string_or_regexp+ itself, if it is a Regexp.
-- <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
+- The pattern itself, if it is a Regexp.
+- <tt>Regexp.quote(pattern)</tt>, if it is a string.
Returns +true+ if any pattern matches the beginning, +false+ otherwise:
@@ -12,7 +11,6 @@ Returns +true+ if any pattern matches the beginning, +false+ otherwise:
'hello'.start_with?(/H/i) # => true
'hello'.start_with?('heaven', 'hell') # => true
'hello'.start_with?('heaven', 'paradise') # => false
- 'тест'.start_with?('т') # => true
'こんにちは'.start_with?('こ') # => true
-Related: String#end_with?.
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/sub.rdoc b/doc/string/sub.rdoc
new file mode 100644
index 0000000000..ff051ea177
--- /dev/null
+++ b/doc/string/sub.rdoc
@@ -0,0 +1,33 @@
+Returns a copy of self, possibly with a substring replaced.
+
+Argument +pattern+ may be a string or a Regexp;
+argument +replacement+ may be a string or a Hash.
+
+Varying types for the argument values makes this method very versatile.
+
+Below are some simple examples; for many more examples,
+see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
+
+With arguments +pattern+ and string +replacement+ given,
+replaces the first matching substring with the given replacement string:
+
+ s = 'abracadabra' # => "abracadabra"
+ s.sub('bra', 'xyzzy') # => "axyzzycadabra"
+ s.sub(/bra/, 'xyzzy') # => "axyzzycadabra"
+ s.sub('nope', 'xyzzy') # => "abracadabra"
+
+With arguments +pattern+ and hash +replacement+ given,
+replaces the first matching substring with a value from the given replacement hash, or removes it:
+
+ h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
+ s.sub('b', h) # => "aBracadabra"
+ s.sub(/b/, h) # => "aBracadabra"
+ s.sub(/d/, h) # => "abracaabra" # 'd' removed.
+
+With argument +pattern+ and a block given,
+calls the block with each matching substring;
+replaces that substring with the block’s return value:
+
+ s.sub('b') {|match| match.upcase } # => "aBracadabra"
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/succ.rdoc b/doc/string/succ.rdoc
new file mode 100644
index 0000000000..1b4b936a8e
--- /dev/null
+++ b/doc/string/succ.rdoc
@@ -0,0 +1,52 @@
+Returns the successor to +self+. The successor is calculated by
+incrementing characters.
+
+The first character to be incremented is the rightmost alphanumeric:
+or, if no alphanumerics, the rightmost character:
+
+ 'THX1138'.succ # => "THX1139"
+ '<<koala>>'.succ # => "<<koalb>>"
+ '***'.succ # => '**+'
+ 'こんにちは'.succ # => "こんにちば"
+
+The successor to a digit is another digit, "carrying" to the next-left
+character for a "rollover" from 9 to 0, and prepending another digit
+if necessary:
+
+ '00'.succ # => "01"
+ '09'.succ # => "10"
+ '99'.succ # => "100"
+
+The successor to a letter is another letter of the same case,
+carrying to the next-left character for a rollover,
+and prepending another same-case letter if necessary:
+
+ 'aa'.succ # => "ab"
+ 'az'.succ # => "ba"
+ 'zz'.succ # => "aaa"
+ 'AA'.succ # => "AB"
+ 'AZ'.succ # => "BA"
+ 'ZZ'.succ # => "AAA"
+
+The successor to a non-alphanumeric character is the next character
+in the underlying character set's collating sequence,
+carrying to the next-left character for a rollover,
+and prepending another character if necessary:
+
+ s = 0.chr * 3 # => "\x00\x00\x00"
+ s.succ # => "\x00\x00\x01"
+ s = 255.chr * 3 # => "\xFF\xFF\xFF"
+ s.succ # => "\x01\x00\x00\x00"
+
+Carrying can occur between and among mixtures of alphanumeric characters:
+
+ s = 'zz99zz99' # => "zz99zz99"
+ s.succ # => "aaa00aa00"
+ s = '99zz99zz' # => "99zz99zz"
+ s.succ # => "100aa00aa"
+
+The successor to an empty +String+ is a new empty +String+:
+
+ ''.succ # => ""
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/sum.rdoc b/doc/string/sum.rdoc
index 5de24e6402..22045e5f4d 100644
--- a/doc/string/sum.rdoc
+++ b/doc/string/sum.rdoc
@@ -1,11 +1,12 @@
-Returns a basic +n+-bit checksum of the characters in +self+;
+Returns a basic +n+-bit {checksum}[https://en.wikipedia.org/wiki/Checksum] of the characters in +self+;
the checksum is the sum of the binary value of each byte in +self+,
modulo <tt>2**n - 1</tt>:
'hello'.sum # => 532
'hello'.sum(4) # => 4
'hello'.sum(64) # => 532
- 'тест'.sum # => 1405
'こんにちは'.sum # => 2582
This is not a particularly strong checksum.
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/string/swapcase.rdoc b/doc/string/swapcase.rdoc
new file mode 100644
index 0000000000..4353c8528a
--- /dev/null
+++ b/doc/string/swapcase.rdoc
@@ -0,0 +1,31 @@
+Returns a string containing the characters in +self+, with cases reversed:
+
+- Each uppercase character is downcased.
+- Each lowercase character is upcased.
+
+Examples:
+
+ 'Hello'.swapcase # => "hELLO"
+ 'Straße'.swapcase # => "sTRASSE"
+ 'RubyGems.org'.swapcase # => "rUBYgEMS.ORG"
+
+The sizes of +self+ and the upcased result may differ:
+
+ s = 'Straße'
+ s.size # => 6
+ s.swapcase # => "sTRASSE"
+ s.swapcase.size # => 7
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.swapcase == s # => true
+ s = 'こんにちは'
+ s.swapcase == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/unicode_normalize.rdoc b/doc/string/unicode_normalize.rdoc
new file mode 100644
index 0000000000..5f733c0fb8
--- /dev/null
+++ b/doc/string/unicode_normalize.rdoc
@@ -0,0 +1,28 @@
+Returns a copy of +self+ with
+{Unicode normalization}[https://unicode.org/reports/tr15] applied.
+
+Argument +form+ must be one of the following symbols
+(see {Unicode normalization forms}[https://unicode.org/reports/tr15/#Norm_Forms]):
+
+- +:nfc+: Canonical decomposition, followed by canonical composition.
+- +:nfd+: Canonical decomposition.
+- +:nfkc+: Compatibility decomposition, followed by canonical composition.
+- +:nfkd+: Compatibility decomposition.
+
+The encoding of +self+ must be one of:
+
+- <tt>Encoding::UTF_8</tt>.
+- <tt>Encoding::UTF_16BE</tt>.
+- <tt>Encoding::UTF_16LE</tt>.
+- <tt>Encoding::UTF_32BE</tt>.
+- <tt>Encoding::UTF_32LE</tt>.
+- <tt>Encoding::GB18030</tt>.
+- <tt>Encoding::UCS_2BE</tt>.
+- <tt>Encoding::UCS_4BE</tt>.
+
+Examples:
+
+ "a\u0300".unicode_normalize # => "à" # Lowercase 'a' with grave accens.
+ "a\u0300".unicode_normalize(:nfd) # => "à" # Same.
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/upcase.rdoc b/doc/string/upcase.rdoc
new file mode 100644
index 0000000000..ad859e8973
--- /dev/null
+++ b/doc/string/upcase.rdoc
@@ -0,0 +1,27 @@
+Returns a new string containing the upcased characters in +self+:
+
+ 'hello'.upcase # => "HELLO"
+ 'straße'.upcase # => "STRASSE"
+ 'привет'.upcase # => "ПРИВЕТ"
+ 'RubyGems.org'.upcase # => "RUBYGEMS.ORG"
+
+The sizes of +self+ and the upcased result may differ:
+
+ s = 'Straße'
+ s.size # => 6
+ s.upcase # => "STRASSE"
+ s.upcase.size # => 7
+
+Some characters (and some character sets) do not have upcase and downcase versions;
+see {Case Mapping}[rdoc-ref:case_mapping.rdoc]:
+
+ s = '1, 2, 3, ...'
+ s.upcase == s # => true
+ s = 'こんにちは'
+ s.upcase == s # => true
+
+The casing is affected by the given +mapping+,
+which may be +:ascii+, +:fold+, or +:turkic+;
+see {Case Mappings}[rdoc-ref:case_mapping.rdoc@Case+Mappings].
+
+Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
diff --git a/doc/string/upto.rdoc b/doc/string/upto.rdoc
new file mode 100644
index 0000000000..f860fe84fe
--- /dev/null
+++ b/doc/string/upto.rdoc
@@ -0,0 +1,38 @@
+With a block given, calls the block with each +String+ value
+returned by successive calls to String#succ;
+the first value is +self+, the next is <tt>self.succ</tt>, and so on;
+the sequence terminates when value +other_string+ is reached;
+returns +self+:
+
+ a = []
+ 'a'.upto('f') {|c| a.push(c) }
+ a # => ["a", "b", "c", "d", "e", "f"]
+
+ a = []
+ 'Ж'.upto('П') {|c| a.push(c) }
+ a # => ["Ж", "З", "И", "Й", "К", "Л", "М", "Н", "О", "П"]
+
+ a = []
+ 'よ'.upto('ろ') {|c| a.push(c) }
+ a # => ["よ", "ら", "り", "る", "れ", "ろ"]
+
+ a = []
+ 'a8'.upto('b6') {|c| a.push(c) }
+ a # => ["a8", "a9", "b0", "b1", "b2", "b3", "b4", "b5", "b6"]
+
+If argument +exclusive+ is given as a truthy object, the last value is omitted:
+
+ a = []
+ 'a'.upto('f', true) {|c| a.push(c) }
+ a # => ["a", "b", "c", "d", "e"]
+
+If +other_string+ would not be reached, does not call the block:
+
+ '25'.upto('5') {|s| fail s }
+ 'aa'.upto('a') {|s| fail s }
+
+With no block given, returns a new Enumerator:
+
+ 'a8'.upto('b6') # => #<Enumerator: "a8":upto("b6")>
+
+Related: see {Iterating}[rdoc-ref:String@Iterating].
diff --git a/doc/string/valid_encoding_p.rdoc b/doc/string/valid_encoding_p.rdoc
new file mode 100644
index 0000000000..e1db55174a
--- /dev/null
+++ b/doc/string/valid_encoding_p.rdoc
@@ -0,0 +1,8 @@
+Returns whether +self+ is encoded correctly:
+
+ s = 'Straße'
+ s.valid_encoding? # => true
+ s.encoding # => #<Encoding:UTF-8>
+ s.force_encoding(Encoding::ASCII).valid_encoding? # => false
+
+Related: see {Querying}[rdoc-ref:String@Querying].
diff --git a/doc/stringio/each_byte.rdoc b/doc/stringio/each_byte.rdoc
new file mode 100644
index 0000000000..708432b69e
--- /dev/null
+++ b/doc/stringio/each_byte.rdoc
@@ -0,0 +1,31 @@
+With a block given, calls the block with each remaining byte in the stream;
+positions the stream at end-of-file;
+returns +self+:
+
+ bytes = []
+ strio = StringIO.new('hello') # Five 1-byte characters.
+ strio.each_byte {|byte| bytes.push(byte) }
+ strio.eof? # => true
+ bytes # => [104, 101, 108, 108, 111]
+
+ bytes = []
+ strio = StringIO.new('こんにちは') # Five 3-byte characters.
+ strio.each_byte {|byte| bytes.push(byte) }
+ bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+
+The position in the stream matters:
+
+ bytes = []
+ strio = StringIO.new('こんにちは')
+ strio.getc # => "こ"
+ strio.pos # => 3 # 3-byte character was read.
+ strio.each_byte {|byte| bytes.push(byte) }
+ bytes # => [227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+
+If at end-of-file, does not call the block:
+
+ strio.eof? # => true
+ strio.each_byte {|byte| fail 'Boo!' }
+ strio.eof? # => true
+
+With no block given, returns a new {Enumerator}[rdoc-ref:Enumerator].
diff --git a/doc/stringio/each_char.rdoc b/doc/stringio/each_char.rdoc
new file mode 100644
index 0000000000..bec5ecac3f
--- /dev/null
+++ b/doc/stringio/each_char.rdoc
@@ -0,0 +1,31 @@
+With a block given, calls the block with each remaining character in the stream;
+positions the stream at end-of-file;
+returns +self+:
+
+ chars = []
+ strio = StringIO.new('hello')
+ strio.each_char {|char| chars.push(char) }
+ strio.eof? # => true
+ chars # => ["h", "e", "l", "l", "o"]
+
+ chars = []
+ strio = StringIO.new('こんにちは')
+ strio.each_char {|char| chars.push(char) }
+ chars # => ["こ", "ん", "に", "ち", "は"]
+
+Stream position matters:
+
+ chars = []
+ strio = StringIO.new('こんにちは')
+ strio.getc # => "こ"
+ strio.pos # => 3 # 3-byte character was read.
+ strio.each_char {|char| chars.push(char) }
+ chars # => ["ん", "に", "ち", "は"]
+
+When at end-of-stream does not call the block:
+
+ strio.eof? # => true
+ strio.each_char {|char| fail 'Boo!' }
+ strio.eof? # => true
+
+With no block given, returns a new {Enumerator}[rdoc-ref:Enumerator].
diff --git a/doc/stringio/each_codepoint.rdoc b/doc/stringio/each_codepoint.rdoc
new file mode 100644
index 0000000000..0d10831142
--- /dev/null
+++ b/doc/stringio/each_codepoint.rdoc
@@ -0,0 +1,33 @@
+With a block given, calls the block with each successive codepoint from self;
+sets the position to end-of-stream;
+returns +self+.
+
+Each codepoint is the integer value for a character; returns self:
+
+ codepoints = []
+ strio = StringIO.new('hello')
+ strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
+ strio.eof? # => true
+ codepoints # => [104, 101, 108, 108, 111]
+
+ codepoints = []
+ strio = StringIO.new('こんにちは')
+ strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
+ codepoints # => [12371, 12435, 12395, 12385, 12399]
+
+Position in the stream matters:
+
+ codepoints = []
+ strio = StringIO.new('こんにちは')
+ strio.getc # => "こ"
+ strio.pos # => 3
+ strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
+ codepoints # => [12435, 12395, 12385, 12399]
+
+When at end-of-stream, the block is not called:
+
+ strio.eof? # => true
+ strio.each_codepoint {|codepoint| fail 'Boo!' }
+ strio.eof? # => true
+
+With no block given, returns a new {Enumerator}[rdoc-ref:Enumerator].
diff --git a/doc/stringio/each_line.md b/doc/stringio/each_line.md
new file mode 100644
index 0000000000..e29640a12a
--- /dev/null
+++ b/doc/stringio/each_line.md
@@ -0,0 +1,189 @@
+With a block given calls the block with each remaining line (see "Position" below) in the stream;
+returns `self`.
+
+Leaves stream position at end-of-stream.
+
+**No Arguments**
+
+With no arguments given,
+reads lines using the default record separator
+(global variable `$/`, whose initial value is `"\n"`).
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line {|line| p line }
+strio.eof? # => true
+```
+
+Output:
+
+```
+"First line\n"
+"Second line\n"
+"\n"
+"Fourth line\n"
+"Fifth line\n"
+```
+
+**Argument `sep`**
+
+With only string argument `sep` given,
+reads lines using that string as the record separator:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(' ') {|line| p line }
+```
+
+Output:
+
+```
+"First "
+"line\nSecond "
+"line\n\nFourth "
+"line\nFifth "
+"line\n"
+```
+
+**Argument `limit`**
+
+With only integer argument `limit` given,
+reads lines using the default record separator;
+also limits the size (in characters) of each line to the given limit:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(10) {|line| p line }
+```
+
+Output:
+
+```
+"First line"
+"\n"
+"Second lin"
+"e\n"
+"\n"
+"Fourth lin"
+"e\n"
+"Fifth line"
+"\n"
+```
+
+**Arguments `sep` and `limit`**
+
+With arguments `sep` and `limit` both given,
+honors both:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(' ', 10) {|line| p line }
+```
+
+Output:
+
+```
+"First "
+"line\nSecon"
+"d "
+"line\n\nFour"
+"th "
+"line\nFifth"
+" "
+"line\n"
+```
+
+**Position**
+
+As stated above, method `each` _remaining_ line in the stream.
+
+In the examples above each `strio` object starts with its position at beginning-of-stream;
+but in other cases the position may be anywhere (see StringIO#pos):
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.pos = 30 # Set stream position to character 30.
+strio.each_line {|line| p line }
+```
+
+Output:
+
+```
+" line\n"
+"Fifth line\n"
+```
+
+In all the examples above, the stream position is at the beginning of a character;
+in other cases, that need not be so:
+
+```ruby
+s = 'こんにちは' # Five 3-byte characters.
+strio = StringIO.new(s)
+strio.pos = 3 # At beginning of second character.
+strio.each_line {|line| p line }
+strio.pos = 4 # At second byte of second character.
+strio.each_line {|line| p line }
+strio.pos = 5 # At third byte of second character.
+strio.each_line {|line| p line }
+```
+
+Output:
+
+```
+"んにちは"
+"\x82\x93にちは"
+"\x93にちは"
+```
+
+**Special Record Separators**
+
+Like some methods in class `IO`, StringIO.each honors two special record separators;
+see {Special Line Separators}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Special+Line+Separator+Values].
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line('') {|line| p line } # Read as paragraphs (separated by blank lines).
+```
+
+Output:
+
+```
+"First line\nSecond line\n\n"
+"Fourth line\nFifth line\n"
+```
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(nil) {|line| p line } # "Slurp"; read it all.
+```
+
+Output:
+
+```
+"First line\nSecond line\n\nFourth line\nFifth line\n"
+```
+
+**Keyword Argument `chomp`**
+
+With keyword argument `chomp` given as `true` (the default is `false`),
+removes trailing newline (if any) from each line:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.each_line(chomp: true) {|line| p line }
+```
+
+Output:
+
+```
+"First line"
+"Second line"
+""
+"Fourth line"
+"Fifth line"
+```
+
+With no block given, returns a new {Enumerator}[https://docs.ruby-lang.org/en/master/Enumerator.html].
+
+
+Related: StringIO.each_byte, StringIO.each_char, StringIO.each_codepoint.
diff --git a/doc/stringio/getbyte.rdoc b/doc/stringio/getbyte.rdoc
new file mode 100644
index 0000000000..148455abf4
--- /dev/null
+++ b/doc/stringio/getbyte.rdoc
@@ -0,0 +1,24 @@
+Reads and returns the next integer byte (not character) from the stream:
+
+ s = 'foo'
+ s.bytes # => [102, 111, 111]
+ strio = StringIO.new(s)
+ strio.getbyte # => 102
+ strio.getbyte # => 111
+ strio.getbyte # => 111
+
+Returns +nil+ if at end-of-stream:
+
+ strio.eof? # => true
+ strio.getbyte # => nil
+
+Returns a byte, not a character:
+
+ s = 'こんにちは'
+ s.bytes
+ # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
+ strio = StringIO.new(s)
+ strio.getbyte # => 227
+ strio.getbyte # => 129
+
+Related: #each_byte, #ungetbyte, #getc.
diff --git a/doc/stringio/getc.rdoc b/doc/stringio/getc.rdoc
new file mode 100644
index 0000000000..58ce47c337
--- /dev/null
+++ b/doc/stringio/getc.rdoc
@@ -0,0 +1,30 @@
+Reads and returns the next character (or byte; see below) from the stream:
+
+ strio = StringIO.new('foo')
+ strio.getc # => "f"
+ strio.getc # => "o"
+ strio.getc # => "o"
+
+Returns +nil+ if at end-of-stream:
+
+ strio.eof? # => true
+ strio.getc # => nil
+
+Returns characters, not bytes:
+
+ strio = StringIO.new('こんにちは')
+ strio.getc # => "こ"
+ strio.getc # => "ん"
+
+In each of the examples above, the stream is positioned at the beginning of a character;
+in other cases that need not be true:
+
+ strio = StringIO.new('こんにちは') # Five 3-byte characters.
+ strio.pos = 3 # => 3 # At beginning of second character; returns character.
+ strio.getc # => "ん"
+ strio.pos = 4 # => 4 # At second byte of second character; returns byte.
+ strio.getc # => "\x82"
+ strio.pos = 5 # => 5 # At third byte of second character; returns byte.
+ strio.getc # => "\x93"
+
+Related: #getbyte, #putc, #ungetc.
diff --git a/doc/stringio/gets.rdoc b/doc/stringio/gets.rdoc
new file mode 100644
index 0000000000..4152152a25
--- /dev/null
+++ b/doc/stringio/gets.rdoc
@@ -0,0 +1,99 @@
+Reads and returns a line from the stream;
+returns +nil+ if at end-of-stream.
+
+Side effects:
+
+- Increments stream position by the number of bytes read.
+- Assigns the return value to global variable <tt>$_</tt>.
+
+With no arguments given, reads a line using the default record separator
+(global variable <tt>$/</tt>,* whose initial value is <tt>"\n"</tt>):
+
+ strio = StringIO.new(TEXT)
+ strio.pos # => 0
+ strio.gets # => "First line\n"
+ strio.pos # => 11
+ $_ # => "First line\n"
+ strio.gets # => "Second line\n"
+ strio.read # => "\nFourth line\nFifth line\n"
+ strio.eof? # => true
+ strio.gets # => nil
+
+ strio = StringIO.new('こんにちは') # Five 3-byte characters.
+ strio.pos # => 0
+ strio.gets # => "こんにちは"
+ strio.pos # => 15
+
+<b>Argument +sep+</b>
+
+With only string argument +sep+ given, reads a line using that string as the record separator:
+
+ strio = StringIO.new(TEXT)
+ strio.gets(' ') # => "First "
+ strio.gets(' ') # => "line\nSecond "
+ strio.gets(' ') # => "line\n\nFourth "
+
+<b>Argument +limit+</b>
+
+With only integer argument +limit+ given,
+reads a line using the default record separator;
+limits the size (in characters) of each line to the given limit:
+
+ strio = StringIO.new(TEXT)
+ strio.gets(10) # => "First line"
+ strio.gets(10) # => "\n"
+ strio.gets(10) # => "Second lin"
+ strio.gets(10) # => "e\n"
+
+<b>Arguments +sep+ and +limit+</b>
+
+With arguments +sep+ and +limit+ both given, honors both:
+
+ strio = StringIO.new(TEXT)
+ strio.gets(' ', 10) # => "First "
+ strio.gets(' ', 10) # => "line\nSecon"
+ strio.gets(' ', 10) # => "d "
+
+<b>Position</b>
+
+As stated above, method +gets+ reads and returns the next line in the stream.
+
+In the examples above each +strio+ object starts with its position at beginning-of-stream;
+but in other cases the position may be anywhere:
+
+ strio = StringIO.new(TEXT)
+ strio.pos = 12
+ strio.gets # => "econd line\n"
+
+The position need not be at a character boundary:
+
+ strio = StringIO.new('こんにちは') # Five 3-byte characters.
+ strio.pos = 3 # At beginning of second character.
+ strio.gets # => "んにちは"
+ strio.pos = 4 # Within second character.
+ strio.gets # => "\x82\x93にちは"
+
+<b>Special Record Separators</b>
+
+Like some methods in class IO, method +gets+ honors two special record separators;
+see {Special Line Separators}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Special+Line+Separator+Values]:
+
+ strio = StringIO.new(TEXT)
+ strio.gets('') # Read "paragraph" (up to empty line).
+ # => "First line\nSecond line\n\n"
+
+ strio = StringIO.new(TEXT)
+ strio.gets(nil) # "Slurp": read all.
+ # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+
+<b>Keyword Argument +chomp+</b>
+
+With keyword argument +chomp+ given as +true+ (the default is +false+),
+removes the trailing newline (if any) from the returned line:
+
+ strio = StringIO.new(TEXT)
+ strio.gets # => "First line\n"
+ strio.gets(chomp: true) # => "Second line"
+
+Related: #each_line, #readlines,
+{Kernel#puts}[rdoc-ref:Kernel#puts].
diff --git a/doc/stringio/pread.rdoc b/doc/stringio/pread.rdoc
new file mode 100644
index 0000000000..2dcbc18ad8
--- /dev/null
+++ b/doc/stringio/pread.rdoc
@@ -0,0 +1,65 @@
+**Note**: \Method +pread+ is different from other reading methods
+in that it does not modify +self+ in any way;
+thus, multiple threads may read safely from the same stream.
+
+Reads up to +maxlen+ bytes from the stream,
+beginning at 0-based byte offset +offset+;
+returns a string containing the read bytes.
+
+The returned string:
+
+- Contains +maxlen+ bytes from the stream, if available;
+ otherwise contains all available bytes.
+- Has encoding +Encoding::ASCII_8BIT+.
+
+With only arguments +maxlen+ and +offset+ given,
+returns a new string:
+
+ english = 'Hello' # Five 1-byte characters.
+ strio = StringIO.new(english)
+ strio.pread(3, 0) # => "Hel"
+ strio.pread(3, 2) # => "llo"
+ strio.pread(0, 0) # => ""
+ strio.pread(50, 0) # => "Hello"
+ strio.pread(50, 2) # => "llo"
+ strio.pread(50, 4) # => "o"
+ strio.pread(0, 0).encoding
+ # => #<Encoding:BINARY (ASCII-8BIT)>
+
+ russian = 'Привет' # Six 2-byte characters.
+ strio = StringIO.new(russian)
+ strio.pread(50, 0) # All 12 bytes.
+ # => "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"
+ strio.pread(3, 0) # => "\xD0\x9F\xD1"
+ strio.pread(3, 3) # => "\x80\xD0\xB8"
+ strio.pread(0, 0).encoding
+ # => #<Encoding:BINARY (ASCII-8BIT)>
+
+ japanese = 'こんにちは' # Five 3-byte characters.
+ strio = StringIO.new(japanese)
+ strio.pread(50, 0) # All 15 bytes.
+ # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ strio.pread(6, 0) # => "\xE3\x81\x93\xE3\x82\x93"
+ strio.pread(1, 2) # => "\x93"
+ strio.pread(0, 0).encoding
+ # => #<Encoding:BINARY (ASCII-8BIT)>
+
+Raises an exception if +offset+ is out-of-range:
+
+ strio = StringIO.new(english)
+ strio.pread(5, 50) # Raises EOFError: end of file reached
+
+With string argument +out_string+ given:
+
+- Reads as above.
+- Overwrites the content of +out_string+ with the read bytes.
+
+Examples:
+
+ out_string = 'Will be overwritten'
+ out_string.encoding # => #<Encoding:UTF-8>
+ result = StringIO.new(english).pread(50, 0, out_string)
+ result.__id__ == out_string.__id__ # => true
+ out_string # => "Hello"
+ out_string.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+
diff --git a/doc/stringio/putc.rdoc b/doc/stringio/putc.rdoc
new file mode 100644
index 0000000000..4636ffa0db
--- /dev/null
+++ b/doc/stringio/putc.rdoc
@@ -0,0 +1,82 @@
+Replaces one or more bytes at position +pos+
+with bytes of the given argument;
+advances the position by the count of bytes written;
+returns the argument.
+
+\StringIO object for 1-byte characters.
+
+ strio = StringIO.new('foo')
+ strio.pos # => 0
+
+With 1-byte argument, replaces one byte:
+
+ strio.putc('b')
+ strio.string # => "boo"
+ strio.pos # => 1
+ strio.putc('a') # => "a"
+ strio.string # => "bao"
+ strio.pos # => 2
+ strio.putc('r') # => "r"
+ strio.string # => "bar"
+ strio.pos # => 3
+ strio.putc('n') # => "n"
+ strio.string # => "barn"
+ strio.pos # => 4
+
+Fills with null characters if necessary:
+
+ strio.pos = 6
+ strio.putc('x') # => "x"
+ strio.string # => "barn\u0000\u0000x"
+ strio.pos # => 7
+
+With integer argument, replaces one byte with the low-order byte of the integer:
+
+ strio = StringIO.new('foo')
+ strio.putc(70)
+ strio.string # => "Foo"
+ strio.putc(79)
+ strio.string # => "FOo"
+ strio.putc(79 + 1024)
+ strio.string # => "FOO"
+
+\StringIO object for Multi-byte characters:
+
+ greek = 'αβγδε' # Five 2-byte characters.
+ strio = StringIO.new(greek)
+ strio.string# => "αβγδε"
+ strio.string.b # => "\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => ["α", "β", "γ", "δ", "ε"]
+ strio.string.size # => 5
+
+With 1-byte argument, replaces one byte of the string:
+
+ strio.putc(' ') # 1-byte ascii space.
+ strio.pos # => 1
+ strio.string # => " \xB1βγδε"
+ strio.string.b # => " \xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => [" ", "\xB1", "β", "γ", "δ", "ε"]
+ strio.string.size # => 6
+
+ strio.putc(' ')
+ strio.pos # => 2
+ strio.string # => " βγδε"
+ strio.string.b # => " \xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => [" ", " ", "β", "γ", "δ", "ε"]
+ strio.string.size # => 6
+
+With 2-byte argument, replaces two bytes of the string:
+
+ strio.rewind
+ strio.putc('α')
+ strio.pos # => 2
+ strio.string # => "αβγδε"
+ strio.string.b # => "\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5"
+ strio.string.bytesize # => 10
+ strio.string.chars # => ["α", "β", "γ", "δ", "ε"]
+ strio.string.size # => 5
+
+Related: #getc, #ungetc.
diff --git a/doc/stringio/read.rdoc b/doc/stringio/read.rdoc
new file mode 100644
index 0000000000..46b9fa349f
--- /dev/null
+++ b/doc/stringio/read.rdoc
@@ -0,0 +1,83 @@
+Reads and returns a string containing bytes read from the stream,
+beginning at the current position;
+advances the position by the count of bytes read.
+
+With no arguments given,
+reads all remaining bytes in the stream;
+returns a new string containing bytes read:
+
+ strio = StringIO.new('Hello') # Five 1-byte characters.
+ strio.read # => "Hello"
+ strio.pos # => 5
+ strio.read # => ""
+ StringIO.new('').read # => ""
+
+With non-negative argument +maxlen+ given,
+reads +maxlen+ bytes as available;
+returns a new string containing the bytes read, or +nil+ if none:
+
+ strio.rewind
+ strio.read(3) # => "Hel"
+ strio.read(3) # => "lo"
+ strio.read(3) # => nil
+
+ russian = 'Привет' # Six 2-byte characters.
+ russian.b
+ # => "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"
+ strio = StringIO.new(russian)
+ strio.read(6) # => "\xD0\x9F\xD1\x80\xD0\xB8"
+ strio.read(6) # => "\xD0\xB2\xD0\xB5\xD1\x82"
+ strio.read(6) # => nil
+
+ japanese = 'こんにちは'
+ japanese.b
+ # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ strio = StringIO.new(japanese)
+ strio.read(9) # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB"
+ strio.read(9) # => "\xE3\x81\xA1\xE3\x81\xAF"
+ strio.read(9) # => nil
+
+With argument +max_len+ as +nil+ and string argument +out_string+ given,
+reads the remaining bytes in the stream;
+clears +out_string+ and writes the bytes into it;
+returns +out_string+:
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new('Hello')
+ strio.read(nil, out_string) # => "Hello"
+ strio.read(nil, out_string) # => ""
+
+With non-negative argument +maxlen+ and string argument +out_string+ given,
+reads the +maxlen bytes from the stream, as availble;
+clears +out_string+ and writes the bytes into it;
+returns +out_string+ if any bytes were read, or +nil+ if none:
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new('Hello')
+ strio.read(3, out_string) # => "Hel"
+ strio.read(3, out_string) # => "lo"
+ strio.read(3, out_string) # => nil
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new(russian)
+ strio.read(6, out_string) # => "При"
+ strio.read(6, out_string) # => "вет"
+ strio.read(6, out_string) # => nil
+ strio.rewind
+ russian.b
+ # => "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"
+ strio.read(3) # => "\xD0\x9F\xD1"
+ strio.read(3) # => "\x80\xD0\xB8"
+
+ out_string = 'Will be overwritten'
+ strio = StringIO.new(japanese)
+ strio.read(9, out_string) # => "こんに"
+ strio.read(9, out_string) # => "ちは"
+ strio.read(9, out_string) # => nil
+ strio.rewind
+ japanese.b
+ # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ strio.read(4) # => "\xE3\x81\x93\xE3"
+ strio.read(4) # => "\x82\x93\xE3\x81"
+
+Related: #gets, #readlines.
diff --git a/doc/stringio/size.rdoc b/doc/stringio/size.rdoc
new file mode 100644
index 0000000000..253c612c43
--- /dev/null
+++ b/doc/stringio/size.rdoc
@@ -0,0 +1,4 @@
+Returns the number of bytes in the string in +self+:
+
+ StringIO.new('hello').size # => 5 # Five 1-byte characters.
+ StringIO.new('こんにちは').size # => 15 # Five 3-byte characters.
diff --git a/doc/stringio/stringio.md b/doc/stringio/stringio.md
new file mode 100644
index 0000000000..f81f79cfea
--- /dev/null
+++ b/doc/stringio/stringio.md
@@ -0,0 +1,702 @@
+\Class \StringIO supports accessing a string as a stream,
+similar in some ways to [class IO][io class].
+
+You can create a \StringIO instance using:
+
+- StringIO.new: returns a new \StringIO object containing the given string.
+- StringIO.open: passes a new \StringIO object to the given block.
+
+Like an \IO stream, a \StringIO stream has certain properties:
+
+- **Read/write mode**: whether the stream may be read, written, appended to, etc.;
+ see [Read/Write Mode][read/write mode].
+- **Data mode**: text-only or binary;
+ see [Data Mode][data mode].
+- **Encodings**: internal and external encodings;
+ see [Encodings][encodings].
+- **Position**: where in the stream the next read or write is to occur;
+ see [Position][position].
+- **Line number**: a special, line-oriented, "position" (different from the position mentioned above);
+ see [Line Number][line number].
+- **Open/closed**: whether the stream is open or closed, for reading or writing.
+ see [Open/Closed Streams][open/closed streams].
+- **BOM**: byte mark order;
+ see [Byte Order Mark][bom (byte order mark)].
+
+## About the Examples
+
+Examples on this page assume that \StringIO has been required:
+
+```ruby
+require 'stringio'
+```
+
+And that this constant has been defined:
+
+```ruby
+TEXT = <<EOT
+First line
+Second line
+
+Fourth line
+Fifth line
+EOT
+```
+
+## Stream Properties
+
+### Read/Write Mode
+
+#### Summary
+
+| Mode | Initial Clear? | Read | Write |
+|:--------------------------:|:--------------:|:--------:|:--------:|
+| <tt>'r'</tt>: read-only | No | Anywhere | Error |
+| <tt>'w'</tt>: write-only | Yes | Error | Anywhere |
+| <tt>'a'</tt>: append-only | No | Error | End only |
+| <tt>'r+'</tt>: read/write | No | Anywhere | Anywhere |
+| <tt>'w+'</tt>: read-write | Yes | Anywhere | Anywhere |
+| <tt>'a+'</tt>: read/append | No | Anywhere | End only |
+
+Each section below describes a read/write mode.
+
+Any of the modes may be given as a string or as file constants;
+example:
+
+```ruby
+strio = StringIO.new('foo', 'a')
+strio = StringIO.new('foo', File::WRONLY | File::APPEND)
+```
+
+#### `'r'`: Read-Only
+
+Mode specified as one of:
+
+- String: `'r'`.
+- Constant: `File::RDONLY`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foobarbaz', 'r')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foobarbaz" # Not cleared.
+```
+
+May be read anywhere:
+
+```ruby
+strio.gets(3) # => "foo"
+strio.gets(3) # => "bar"
+strio.pos = 9
+strio.gets(3) # => nil
+```
+
+May not be written:
+
+```ruby
+strio.write('foo') # Raises IOError: not opened for writing
+```
+
+#### `'w'`: Write-Only
+
+Mode specified as one of:
+
+- String: `'w'`.
+- Constant: `File::WRONLY`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'w')
+strio.pos # => 0 # Beginning of stream.
+strio.string # => "" # Initially cleared.
+```
+
+May be written anywhere (even past end-of-stream):
+
+```ruby
+strio.write('foobar')
+strio.string # => "foobar"
+strio.rewind
+strio.write('FOO')
+strio.string # => "FOObar"
+strio.pos = 3
+strio.write('BAR')
+strio.string # => "FOOBAR"
+strio.pos = 9
+strio.write('baz')
+strio.string # => "FOOBAR\u0000\u0000\u0000baz" # Null-padded.
+```
+
+May not be read:
+
+```ruby
+strio.read # Raises IOError: not opened for reading
+```
+
+#### `'a'`: Append-Only
+
+Mode specified as one of:
+
+- String: `'a'`.
+- Constant: `File::WRONLY | File::APPEND`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'a')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foo" # Not cleared.
+```
+
+May be written only at the end; position does not affect writing:
+
+```ruby
+strio.write('bar')
+strio.string # => "foobar"
+strio.write('baz')
+strio.string # => "foobarbaz"
+strio.pos = 400
+strio.write('bat')
+strio.string # => "foobarbazbat"
+```
+
+May not be read:
+
+```ruby
+strio.gets # Raises IOError: not opened for reading
+```
+
+#### `'r+'`: Read/Write
+
+Mode specified as one of:
+
+- String: `'r+'`.
+- Constant: `File::RDRW`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foobar', 'r+')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foobar" # Not cleared.
+```
+
+May be written anywhere (even past end-of-stream):
+
+```ruby
+strio.write('FOO')
+strio.string # => "FOObar"
+strio.write('BAR')
+strio.string # => "FOOBAR"
+strio.write('BAZ')
+strio.string # => "FOOBARBAZ"
+strio.pos = 12
+strio.write('BAT')
+strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT" # Null padded.
+```
+
+May be read anywhere:
+
+```ruby
+strio.pos = 0
+strio.gets(3) # => "FOO"
+strio.pos = 6
+strio.gets(3) # => "BAZ"
+strio.pos = 400
+strio.gets(3) # => nil
+```
+
+#### `'w+'`: Read/Write (Initially Clear)
+
+Mode specified as one of:
+
+- String: `'w+'`.
+- Constant: `File::RDWR | File::TRUNC`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'w+')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "" # Truncated.
+```
+
+May be written anywhere (even past end-of-stream):
+
+```ruby
+strio.write('foobar')
+strio.string # => "foobar"
+strio.rewind
+strio.write('FOO')
+strio.string # => "FOObar"
+strio.write('BAR')
+strio.string # => "FOOBAR"
+strio.write('BAZ')
+strio.string # => "FOOBARBAZ"
+strio.pos = 12
+strio.write('BAT')
+strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT" # Null-padded.
+```
+
+May be read anywhere:
+
+```ruby
+strio.rewind
+strio.gets(3) # => "FOO"
+strio.gets(3) # => "BAR"
+strio.pos = 12
+strio.gets(3) # => "BAT"
+strio.pos = 400
+strio.gets(3) # => nil
+```
+
+#### `'a+'`: Read/Append
+
+Mode specified as one of:
+
+- String: `'a+'`.
+- Constant: `File::RDWR | File::APPEND`.
+
+Initial state:
+
+```ruby
+strio = StringIO.new('foo', 'a+')
+strio.pos # => 0 # Beginning-of-stream.
+strio.string # => "foo" # Not cleared.
+```
+
+May be written only at the end; #rewind; position does not affect writing:
+
+```ruby
+strio.write('bar')
+strio.string # => "foobar"
+strio.write('baz')
+strio.string # => "foobarbaz"
+strio.pos = 400
+strio.write('bat')
+strio.string # => "foobarbazbat"
+```
+
+May be read anywhere:
+
+```ruby
+strio.rewind
+strio.gets(3) # => "foo"
+strio.gets(3) # => "bar"
+strio.pos = 9
+strio.gets(3) # => "bat"
+strio.pos = 400
+strio.gets(3) # => nil
+```
+
+### Data Mode
+
+To specify whether the stream is to be treated as text or as binary data,
+either of the following may be suffixed to any of the string read/write modes above:
+
+- `'t'`: Text;
+ initializes the encoding as Encoding::UTF_8.
+- `'b'`: Binary;
+ initializes the encoding as Encoding::ASCII_8BIT.
+
+If neither is given, the stream defaults to text data.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo', 'rt')
+strio.external_encoding # => #<Encoding:UTF-8>
+data = "\u9990\u9991\u9992\u9993\u9994"
+strio = StringIO.new(data, 'rb')
+strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+```
+
+When the data mode is specified, the read/write mode may not be omitted:
+
+```ruby
+StringIO.new(data, 'b') # Raises ArgumentError: invalid access mode b
+```
+
+A text stream may be changed to binary by calling instance method #binmode;
+a binary stream may not be changed to text.
+
+### Encodings
+
+A stream has an encoding; see [Encodings][encodings document].
+
+The initial encoding for a new or re-opened stream depends on its [data mode][data mode]:
+
+- Text: `Encoding::UTF_8`.
+- Binary: `Encoding::ASCII_8BIT`.
+
+These instance methods are relevant:
+
+- #external_encoding: returns the current encoding of the stream as an `Encoding` object.
+- #internal_encoding: returns +nil+; a stream does not have an internal encoding.
+- #set_encoding: sets the encoding for the stream.
+- #set_encoding_by_bom: sets the encoding for the stream to the stream's BOM (byte order mark).
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo', 'rt') # Text mode.
+strio.external_encoding # => #<Encoding:UTF-8>
+data = "\u9990\u9991\u9992\u9993\u9994"
+strio = StringIO.new(data, 'rb') # Binary mode.
+strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+strio = StringIO.new('foo')
+strio.external_encoding # => #<Encoding:UTF-8>
+strio.set_encoding('US-ASCII')
+strio.external_encoding # => #<Encoding:US-ASCII>
+```
+
+### Position
+
+A stream has a _position_, and integer offset (in bytes) into the stream.
+The initial position of a stream is zero.
+
+#### Getting and Setting the Position
+
+Each of these methods initializes (to zero) the position of a new or re-opened stream:
+
+- ::new: returns a new stream.
+- ::open: passes a new stream to the block.
+- #reopen: re-initializes the stream.
+
+Each of these methods queries, gets, or sets the position, without otherwise changing the stream:
+
+- #eof?: returns whether the position is at end-of-stream.
+- #pos: returns the position.
+- #pos=: sets the position.
+- #rewind: sets the position to zero.
+- #seek: sets the position.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foobar')
+strio.pos # => 0
+strio.pos = 3
+strio.pos # => 3
+strio.eof? # => false
+strio.rewind
+strio.pos # => 0
+strio.seek(0, IO::SEEK_END)
+strio.pos # => 6
+strio.eof? # => true
+```
+
+#### Position Before and After Reading
+
+Except for #pread, a stream reading method (see [Basic Reading][basic reading])
+begins reading at the current position.
+
+Except for #pread, a read method advances the position past the read substring.
+
+Examples:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+strio.pos # => 0
+strio.getc # => "F"
+strio.pos # => 1
+strio.gets # => "irst line\n"
+strio.pos # => 11
+strio.pos = 24
+strio.gets # => "Fourth line\n"
+strio.pos # => 36
+
+strio = StringIO.new('こんにちは') # Five 3-byte characters.
+strio.pos = 0 # At first byte of first character.
+strio.read # => "こんにちは"
+strio.pos = 1 # At second byte of first character.
+strio.read # => "\x81\x93んにちは"
+strio.pos = 2 # At third byte of first character.
+strio.read # => "\x93んにちは"
+strio.pos = 3 # At first byte of second character.
+strio.read # => "んにちは"
+
+strio = StringIO.new(TEXT)
+strio.pos = 15
+a = []
+strio.each_line {|line| a.push(line) }
+a # => ["nd line\n", "\n", "Fourth line\n", "Fifth line\n"]
+strio.pos # => 47 ## End-of-stream.
+```
+
+#### Position Before and After Writing
+
+Each of these methods begins writing at the current position,
+and advances the position to the end of the written substring:
+
+- #putc: writes the given character.
+- #write: writes the given objects as strings.
+- [Kernel#puts][kernel#puts]: writes given objects as strings, each followed by newline.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo')
+strio.pos # => 0
+strio.putc('b')
+strio.string # => "boo"
+strio.pos # => 1
+strio.write('r')
+strio.string # => "bro"
+strio.pos # => 2
+strio.puts('ew')
+strio.string # => "brew\n"
+strio.pos # => 5
+strio.pos = 8
+strio.write('foo')
+strio.string # => "brew\n\u0000\u0000\u0000foo"
+strio.pos # => 11
+```
+
+Each of these methods writes _before_ the current position, and decrements the position
+so that the written data is next to be read:
+
+- #ungetbyte: unshifts the given byte.
+- #ungetc: unshifts the given character.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foo')
+strio.pos = 2
+strio.ungetc('x')
+strio.pos # => 1
+strio.string # => "fxo"
+strio.ungetc('x')
+strio.pos # => 0
+strio.string # => "xxo"
+```
+
+This method does not affect the position:
+
+- #truncate: truncates the stream's string to the given size.
+
+Examples:
+
+```ruby
+strio = StringIO.new('foobar')
+strio.pos # => 0
+strio.truncate(3)
+strio.string # => "foo"
+strio.pos # => 0
+strio.pos = 500
+strio.truncate(0)
+strio.string # => ""
+strio.pos # => 500
+```
+
+### Line Number
+
+A stream has a line number, which initially is zero:
+
+- Method #lineno returns the line number.
+- Method #lineno= sets the line number.
+
+The line number can be affected by reading (but never by writing);
+in general, the line number is incremented each time the record separator (default: `"\n"`) is read.
+
+Examples:
+
+```ruby
+strio = StringIO.new(TEXT)
+strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+strio.lineno # => 0
+strio.gets # => "First line\n"
+strio.lineno # => 1
+strio.getc # => "S"
+strio.lineno # => 1
+strio.gets # => "econd line\n"
+strio.lineno # => 2
+strio.gets # => "\n"
+strio.lineno # => 3
+strio.gets # => "Fourth line\n"
+strio.lineno # => 4
+```
+
+Setting the position does not affect the line number:
+
+```ruby
+strio.pos = 0
+strio.lineno # => 4
+strio.gets # => "First line\n"
+strio.pos # => 11
+strio.lineno # => 5
+```
+
+And setting the line number does not affect the position:
+
+```ruby
+strio.lineno = 10
+strio.pos # => 11
+strio.gets # => "Second line\n"
+strio.lineno # => 11
+strio.pos # => 23
+```
+
+### Open/Closed Streams
+
+A new stream is open for either reading or writing, and may be open for both;
+see [Read/Write Mode][read/write mode].
+
+Each of these methods initializes the read/write mode for a new or re-opened stream:
+
+- ::new: returns a new stream.
+- ::open: passes a new stream to the block.
+- #reopen: re-initializes the stream.
+
+Other relevant methods:
+
+- #close: closes the stream for both reading and writing.
+- #close_read: closes the stream for reading.
+- #close_write: closes the stream for writing.
+- #closed?: returns whether the stream is closed for both reading and writing.
+- #closed_read?: returns whether the stream is closed for reading.
+- #closed_write?: returns whether the stream is closed for writing.
+
+### BOM (Byte Order Mark)
+
+The string provided for ::new, ::open, or #reopen
+may contain an optional [BOM][bom] (byte order mark) at the beginning of the string;
+the BOM can affect the stream's encoding.
+
+The BOM (if provided):
+
+- Is stored as part of the stream's string.
+- Does _not_ immediately affect the encoding.
+- Is _initially_ considered part of the stream.
+
+```ruby
+utf8_bom = "\xEF\xBB\xBF"
+string = utf8_bom + 'foo'
+string.bytes # => [239, 187, 191, 102, 111, 111]
+strio.string.bytes.take(3) # => [239, 187, 191] # The BOM.
+strio = StringIO.new(string, 'rb')
+strio.string.bytes # => [239, 187, 191, 102, 111, 111] # BOM is part of the stored string.
+strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)> # Default for a binary stream.
+strio.gets # => "\xEF\xBB\xBFfoo" # BOM is part of the stream.
+```
+
+You can call instance method #set_encoding_by_bom to "activate" the stored BOM;
+after doing so the BOM:
+
+- Is _still_ stored as part of the stream's string.
+- _Determines_ (and may have changed) the stream's encoding.
+- Is _no longer_ considered part of the stream.
+
+```ruby
+strio.set_encoding_by_bom
+strio.string.bytes # => [239, 187, 191, 102, 111, 111] # BOM is still part of the stored string.
+strio.external_encoding # => #<Encoding:UTF-8> # The new encoding.
+strio.rewind # => 0
+strio.gets # => "foo" # BOM is not part of the stream.
+```
+
+## Basic Stream \IO
+
+### Basic Reading
+
+You can read from the stream using these instance methods:
+
+- #getbyte: reads and returns the next byte.
+- #getc: reads and returns the next character.
+- #gets: reads and returns all or part of the next line.
+- #read: reads and returns all or part of the remaining data in the stream.
+- #readlines: reads the remaining data the stream and returns an array of its lines.
+- [Kernel#readline][kernel#readline]: like #gets, but raises an exception if at end-of-stream.
+
+You can iterate over the stream using these instance methods:
+
+- #each_byte: reads each remaining byte, passing it to the block.
+- #each_char: reads each remaining character, passing it to the block.
+- #each_codepoint: reads each remaining codepoint, passing it to the block.
+- #each_line: reads all or part of each remaining line, passing the read string to the block
+
+This instance method is useful in a multi-threaded application:
+
+- #pread: reads and returns all or part of the stream.
+
+### Basic Writing
+
+You can write to the stream, advancing the position, using these instance methods:
+
+- #putc: writes a given character.
+- #write: writes the given objects as strings.
+- [Kernel#puts][kernel#puts] writes given objects as strings, each followed by newline.
+
+You can "unshift" to the stream using these instance methods;
+each writes _before_ the current position, and decrements the position
+so that the written data is next to be read.
+
+- #ungetbyte: unshifts the given byte.
+- #ungetc: unshifts the given character.
+
+One more writing method:
+
+- #truncate: truncates the stream's string to the given size.
+
+## Line \IO
+
+Reading:
+
+- #gets: reads and returns the next line.
+- [Kernel#readline][kernel#readline]: like #gets, but raises an exception if at end-of-stream.
+- #readlines: reads the remaining data the stream and returns an array of its lines.
+- #each_line: reads each remaining line, passing it to the block
+
+Writing:
+
+- [Kernel#puts][kernel#puts]: writes given objects, each followed by newline.
+
+## Character \IO
+
+Reading:
+
+- #each_char: reads each remaining character, passing it to the block.
+- #getc: reads and returns the next character.
+
+Writing:
+
+- #putc: writes the given character.
+- #ungetc.: unshifts the given character.
+
+## Byte \IO
+
+Reading:
+
+- #each_byte: reads each remaining byte, passing it to the block.
+- #getbyte: reads and returns the next byte.
+
+Writing:
+
+- #ungetbyte: unshifts the given byte.
+
+## Codepoint \IO
+
+Reading:
+
+- #each_codepoint: reads each remaining codepoint, passing it to the block.
+
+[bom]: https://en.wikipedia.org/wiki/Byte_order_mark
+[encodings document]: https://docs.ruby-lang.org/en/master/language/encodings_rdoc.html
+[io class]: https://docs.ruby-lang.org/en/master/IO.html
+[kernel#puts]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-puts
+[kernel#readline]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-readline
+
+[basic reading]: rdoc-ref:StringIO@Basic+Reading
+[basic writing]: rdoc-ref:StringIO@Basic+Writing
+[bom (byte order mark)]: rdoc-ref:StringIO@BOM+Byte+Order+Mark
+[data mode]: rdoc-ref:StringIO@Data+Mode
+[encodings]: rdoc-ref:StringIO@Encodings
+[end-of-stream]: rdoc-ref:StringIO@End-of-Stream
+[line number]: rdoc-ref:StringIO@Line+Number
+[open/closed streams]: rdoc-ref:StringIO@OpenClosed+Streams
+[position]: rdoc-ref:StringIO@Position
+[read/write mode]: rdoc-ref:StringIO@ReadWrite+Mode
diff --git a/doc/strscan/.document b/doc/strscan/.document
new file mode 100644
index 0000000000..b8085a8474
--- /dev/null
+++ b/doc/strscan/.document
@@ -0,0 +1 @@
+helper_methods.md
diff --git a/doc/strscan/link_refs.txt b/doc/strscan/link_refs.txt
index 19f6f7ce5c..04c4419982 100644
--- a/doc/strscan/link_refs.txt
+++ b/doc/strscan/link_refs.txt
@@ -1,5 +1,5 @@
[1]: rdoc-ref:StringScanner@Stored+String
-[2]: rdoc-ref:StringScanner@Byte+Position+-28Position-29
+[2]: rdoc-ref:StringScanner@Byte+Position+Position
[3]: rdoc-ref:StringScanner@Target+Substring
[4]: rdoc-ref:StringScanner@Setting+the+Target+Substring
[5]: rdoc-ref:StringScanner@Traversing+the+Target+Substring
diff --git a/doc/strscan/methods/get_byte.md b/doc/strscan/methods/get_byte.md
index 3208d77158..775226638e 100644
--- a/doc/strscan/methods/get_byte.md
+++ b/doc/strscan/methods/get_byte.md
@@ -1,6 +1,3 @@
-call-seq:
- get_byte -> byte_as_character or nil
-
Returns the next byte, if available:
- If the [position][2]
diff --git a/doc/strscan/methods/get_charpos.md b/doc/strscan/methods/get_charpos.md
index 954fcf5b44..4de07897dc 100644
--- a/doc/strscan/methods/get_charpos.md
+++ b/doc/strscan/methods/get_charpos.md
@@ -1,6 +1,3 @@
-call-seq:
- charpos -> character_position
-
Returns the [character position][7] (initially zero),
which may be different from the [byte position][2]
given by method #pos:
diff --git a/doc/strscan/methods/get_pos.md b/doc/strscan/methods/get_pos.md
index 81bbb2345e..56b1636812 100644
--- a/doc/strscan/methods/get_pos.md
+++ b/doc/strscan/methods/get_pos.md
@@ -1,6 +1,3 @@
-call-seq:
- pos -> byte_position
-
Returns the integer [byte position][2],
which may be different from the [character position][7]:
diff --git a/doc/strscan/methods/getch.md b/doc/strscan/methods/getch.md
index 3dd70e4c5b..ede1d2b071 100644
--- a/doc/strscan/methods/getch.md
+++ b/doc/strscan/methods/getch.md
@@ -1,6 +1,3 @@
-call-seq:
- getch -> character or nil
-
Returns the next (possibly multibyte) character,
if available:
diff --git a/doc/strscan/methods/scan.md b/doc/strscan/methods/scan.md
index 22ddd368b6..805c797913 100644
--- a/doc/strscan/methods/scan.md
+++ b/doc/strscan/methods/scan.md
@@ -1,6 +1,3 @@
-call-seq:
- scan(pattern) -> substring or nil
-
Attempts to [match][17] the given `pattern`
at the beginning of the [target substring][3].
diff --git a/doc/strscan/methods/scan_until.md b/doc/strscan/methods/scan_until.md
index 9a8c7c02f6..5fb2912a1b 100644
--- a/doc/strscan/methods/scan_until.md
+++ b/doc/strscan/methods/scan_until.md
@@ -1,6 +1,3 @@
-call-seq:
- scan_until(pattern) -> substring or nil
-
Attempts to [match][17] the given `pattern`
anywhere (at any [position][2]) in the [target substring][3].
diff --git a/doc/strscan/methods/set_pos.md b/doc/strscan/methods/set_pos.md
index 3b7abe65e3..6a43edeb41 100644
--- a/doc/strscan/methods/set_pos.md
+++ b/doc/strscan/methods/set_pos.md
@@ -1,7 +1,3 @@
-call-seq:
- pos = n -> n
- pointer = n -> n
-
Sets the [byte position][2] and the [character position][11];
returns `n`.
diff --git a/doc/strscan/methods/skip.md b/doc/strscan/methods/skip.md
index 10a329e0e4..7e924b624b 100644
--- a/doc/strscan/methods/skip.md
+++ b/doc/strscan/methods/skip.md
@@ -1,6 +1,3 @@
-call-seq:
- skip(pattern) match_size or nil
-
Attempts to [match][17] the given `pattern`
at the beginning of the [target substring][3];
diff --git a/doc/strscan/methods/skip_until.md b/doc/strscan/methods/skip_until.md
index b7dacf6da1..a0ffab0b84 100644
--- a/doc/strscan/methods/skip_until.md
+++ b/doc/strscan/methods/skip_until.md
@@ -1,13 +1,11 @@
-call-seq:
- skip_until(pattern) -> matched_substring_size or nil
-
Attempts to [match][17] the given `pattern`
-anywhere (at any [position][2]) in the [target substring][3];
-does not modify the positions.
+anywhere (at any [position][2]) in the [target substring][3].
If the match attempt succeeds:
- Sets [match values][9].
+- Sets the [byte position][2] to the end of the matched substring;
+ may adjust the [character position][7].
- Returns the size of the matched substring.
```rb
@@ -42,6 +40,7 @@ If the match attempt fails:
- Clears match values.
- Returns `nil`.
+- Does not update positions.
```rb
scanner.skip_until(/nope/) # => nil
diff --git a/doc/strscan/methods/terminate.md b/doc/strscan/methods/terminate.md
index b03b37d2a2..27f7d41cb1 100644
--- a/doc/strscan/methods/terminate.md
+++ b/doc/strscan/methods/terminate.md
@@ -1,6 +1,3 @@
-call-seq:
- terminate -> self
-
Sets the scanner to end-of-string;
returns +self+:
diff --git a/doc/strscan/strscan.md b/doc/strscan/strscan.md
index 1211a687c2..bbdeccd75e 100644
--- a/doc/strscan/strscan.md
+++ b/doc/strscan/strscan.md
@@ -37,7 +37,7 @@ Some examples here assume that certain helper methods are defined:
- `match_values_cleared?(scanner)`:
Returns whether the scanner's [match values][9] are cleared.
-See examples [here][ext/strscan/helper_methods_md.html].
+See examples at [helper methods](doc/strscan/helper_methods.md).
## The `StringScanner` \Object
@@ -204,7 +204,7 @@ put_situation(scanner)
## Target Substring
-The target substring is the the part of the [stored string][1]
+The target substring is the part of the [stored string][1]
that extends from the current [byte position][2] to the end of the stored string;
it is always either:
@@ -417,7 +417,7 @@ Each of these methods returns a captured match value:
| Method | Return After Match | Return After No Match |
|-----------------|-----------------------------------------|-----------------------|
| #size | Count of captured substrings. | +nil+. |
-| #[](n) | <tt>n</tt>th captured substring. | +nil+. |
+| #\[\](n) | <tt>n</tt>th captured substring. | +nil+. |
| #captures | Array of all captured substrings. | +nil+. |
| #values_at(*n) | Array of specified captured substrings. | +nil+. |
| #named_captures | Hash of named captures. | <tt>{}</tt>. |
diff --git a/doc/syntax.rdoc b/doc/syntax.rdoc
index cb427b6f0f..a48c83ff15 100644
--- a/doc/syntax.rdoc
+++ b/doc/syntax.rdoc
@@ -2,6 +2,9 @@
The Ruby syntax is large and is split up into the following sections:
+{Code Layout}[rdoc-ref:syntax/layout.rdoc] ::
+ Breaking code in lines
+
Literals[rdoc-ref:syntax/literals.rdoc] ::
Numbers, Strings, Arrays, Hashes, etc.
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc
index f45f5bc0ea..3988f82e5f 100644
--- a/doc/syntax/assignment.rdoc
+++ b/doc/syntax/assignment.rdoc
@@ -9,7 +9,7 @@ Assignment creates a local variable if the variable was not previously
referenced.
An assignment expression result is always the assigned value, including
-{assignment methods}[rdoc-ref:syntax/assignment.rdoc@Assignment+Methods].
+{assignment methods}[rdoc-ref:@Assignment+Methods].
== Local Variable Names
@@ -279,7 +279,7 @@ An uninitialized global variable has a value of +nil+.
Ruby has some special globals that behave differently depending on context
such as the regular expression match variables or that have a side-effect when
-assigned to. See the {global variables documentation}[rdoc-ref:globals.rdoc]
+assigned to. See the {global variables documentation}[rdoc-ref:language/globals.md]
for details.
== Assignment Methods
diff --git a/doc/syntax/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc
index bf5916e99a..a24c5fbf1f 100644
--- a/doc/syntax/calling_methods.rdoc
+++ b/doc/syntax/calling_methods.rdoc
@@ -355,9 +355,8 @@ as one argument:
# Prints the object itself:
# #<Name:0x00007f9d07bca650 @name="Jane Doe">
-This allows to handle one or many arguments polymorphically. Note also that +nil+
-has NilClass#to_a defined to return an empty array, so conditional unpacking is
-possible:
+This allows to handle one or many arguments polymorphically. Note also that <tt>*nil</tt>
+is unpacked to an empty list of arguments, so conditional unpacking is possible:
my_method(*(some_arguments if some_condition?))
@@ -426,7 +425,7 @@ as keyword arguments:
name = Name.new('Jane Doe')
p(**name)
- # Prints: {name: "Jane", last: "Doe"}
+ # Prints: {first: "Jane", last: "Doe"}
Unlike <code>*</code> operator, <code>**</code> raises an error when used on an
object that doesn't respond to <code>#to_hash</code>. The one exception is
diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc
index 00d19d588a..cb6829a984 100644
--- a/doc/syntax/comments.rdoc
+++ b/doc/syntax/comments.rdoc
@@ -170,7 +170,7 @@ In this mode, all values assigned to constants are made shareable.
# shareable_constant_value: experimental_everything
FOO = Set[1, 2, {foo: []}]
- # same as FOO = Ractor.make_sharable(...)
+ # same as FOO = Ractor.make_shareable(...)
# OR same as `FOO = Set[1, 2, {foo: [].freeze}.freeze].freeze`
var = [{foo: []}]
diff --git a/doc/syntax/exceptions.rdoc b/doc/syntax/exceptions.rdoc
index ac5ff78a95..cdf9d367a7 100644
--- a/doc/syntax/exceptions.rdoc
+++ b/doc/syntax/exceptions.rdoc
@@ -103,4 +103,4 @@ You may also run some code when an exception is not raised:
# It will not return implicitly.
end
-NB : Without explicit +return+ in the +ensure+ block, +begin+/+end+ block will return the last evaluated statement before entering in the `ensure` block.
+NB : Without explicit +return+ in the +ensure+ block, +begin+/+end+ block will return the last evaluated statement before entering in the +ensure+ block.
diff --git a/doc/syntax/layout.rdoc b/doc/syntax/layout.rdoc
new file mode 100644
index 0000000000..31e51d9ff1
--- /dev/null
+++ b/doc/syntax/layout.rdoc
@@ -0,0 +1,118 @@
+= Code Layout
+
+Expressions in Ruby are separated by line breaks:
+
+ x = 1
+ y = 2
+ z = x + y
+
+Line breaks are also used as logical separators of the headers of some control structures from their bodies:
+
+ if z > 3 # line break ends the condition and starts the body
+ puts "more"
+ end
+
+ while x < 3 # line break ends the condition and starts the body
+ x += 1
+ end
+
+<tt>;</tt> can be used as an expressions separator instead of a line break:
+
+ x = 1; y = 2; z = x + y
+ if z > 3; puts "more"; end
+
+Traditionally, expressions separated by <tt>;</tt> are used only in short scripts and experiments.
+
+In some control structures, there is an optional keyword that can be used instead of a line break to separate their elements:
+
+ # if, elsif, until and case ... when: 'then' is an optional separator:
+
+ if z > 3 then puts "more" end
+
+ case x
+ when Numeric then "number"
+ when String then "string"
+ else "object"
+ end
+
+ # while and until: 'do' is an optional separator
+ while x < 3 do x +=1 end
+
+Also, line breaks can be skipped in some places where it doesn't create any ambiguity. Note in the example above: no line break needed before +end+, just as no line break needed after +else+.
+
+== Breaking expressions in lines
+
+One expression might be split into several lines when each line can be unambiguously identified as "incomplete" without the next one.
+
+These works:
+
+ x = # incomplete without something after =
+ 1 + # incomplete without something after +
+ 2
+
+ File.read "test.txt", # incomplete without something after ,
+ enconding: "utf-8"
+
+These would not:
+
+ # unintended interpretation:
+ x = 1 # already complete expression
+ + 2 # interpreted as a separate +2
+
+ # syntax error:
+ File.read "test.txt" # already complete expression
+ , encoding: "utf-8" # attempt to parse as a new expression, SyntaxError
+
+The exceptions to the rule are lines starting with <tt>.</tt> ("leading dot" style of method calls) or logical operators <tt>&&</tt>/<tt>||</tt> and <tt>and</tt>/<tt>or</tt>:
+
+ # OK, interpreted as a chain of calls
+ File.read('test.txt')
+ .strip("\n")
+ .split("\t")
+ .sort
+
+ # OK, interpreted as a chain of logical operators:
+ File.empty?('test.txt')
+ || File.size('test.txt') < 10
+ || File.read('test.txt').strip.empty?
+
+If the expressions is broken into multiple lines in any of the ways described above, comments between separate lines are allowed:
+
+ sum = base_salary +
+ # see "yearly bonuses section"
+ yearly_bonus(year) +
+ # per-employee coefficient is described
+ # in another module
+ personal_coeff(employee)
+
+ # We want to short-circuit on empty files
+ File.empty?('test.txt')
+ # Or almost empty ones
+ || File.size('test.txt') < 10
+ # Otherwise we check if it is full of spaces
+ || File.read('test.txt').strip.empty?
+
+Finally, the code can explicitly tell Ruby that the expression is continued on the next line with <tt>\\</tt>:
+
+ # Unusual, but works
+ File.read "test.txt" \
+ , encoding: "utf-8"
+
+ # More regular usage (joins the strings on parsing instead
+ # of concatenating them in runtime, as + would do):
+ TEXT = "One pretty long line" \
+ "one more long line" \
+ "one other line of the text"
+
+The <tt>\\</tt> works as a parse time line break escape, so with it, comments can not be inserted between the lines:
+
+ TEXT = "line 1" \
+ # here would be line 2:
+ "line 2"
+
+ # This is interpreted as if there was no line break where \ is,
+ # i.e. the same as
+ TEXT = "line 1" # here would be line 2:
+ "line 2"
+
+ puts TEXT #=> "line 1"
diff --git a/doc/syntax/literals.rdoc b/doc/syntax/literals.rdoc
index 46bb7673f3..c876558d4e 100644
--- a/doc/syntax/literals.rdoc
+++ b/doc/syntax/literals.rdoc
@@ -3,7 +3,7 @@
Literals create objects you can use in your program. Literals include:
* {Boolean and Nil Literals}[#label-Boolean+and+Nil+Literals]
-* {Number Literals}[#label-Number+Literals]
+* {Numeric Literals}[#label-Numeric+Literals]
* {Integer Literals}[#label-Integer+Literals]
* {Float Literals}[#label-Float+Literals]
@@ -36,7 +36,7 @@ Literals create objects you can use in your program. Literals include:
+true+ is a true value. All objects except +nil+ and +false+ evaluate to a
true value in conditional expressions.
-== Number Literals
+== \Numeric Literals
=== \Integer Literals
@@ -547,6 +547,13 @@ with <tt>%w</tt> (non-interpolable) or <tt>%W</tt> (interpolable):
# (not nested array).
%w[foo[bar baz]qux] # => ["foo[bar", "baz]qux"]
+The interpolated string is treated as a single word even if it contains
+whitespace.
+
+ s = "bar baz"
+ %W[foo #{s} zot] #=> ["foo", "bar baz", "zot"]
+ %W[foo #{"bar baz zot"} qux] # => ["foo", "bar baz zot", "qux"]
+
The following characters are considered as white spaces to separate words:
* space, ASCII 20h (SPC)
diff --git a/doc/syntax/methods.rdoc b/doc/syntax/methods.rdoc
index 8dafa6bb0c..14810a188f 100644
--- a/doc/syntax/methods.rdoc
+++ b/doc/syntax/methods.rdoc
@@ -100,6 +100,7 @@ operators.
<code>/</code> :: divide
<code>%</code> :: modulus division, String#%
<code>&</code> :: AND
+<code>|</code> :: OR
<code>^</code> :: XOR (exclusive OR)
<code>>></code> :: right-shift
<code><<</code> :: left-shift, append
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index c43919ba14..06aae26d49 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -253,11 +253,11 @@ The "rest" part of a pattern also can be bound to a variable:
case {a: 1, b: 2}
in {a: } | Array
+ # ^ SyntaxError (variable capture in alternative pattern)
"matched: #{a}"
else
"not matched"
end
- # SyntaxError (illegal variable in alternative pattern (a))
Variables that start with <code>_</code> are the only exclusions from this rule:
diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc
index 17d5e67c21..80595eb445 100644
--- a/doc/syntax/refinements.rdoc
+++ b/doc/syntax/refinements.rdoc
@@ -210,43 +210,58 @@ all refinements from the same module are active when a refined method
== Method Lookup
-When looking up a method for an instance of class +C+ Ruby checks:
+Method lookup in Ruby is based on the ancestor chain. You can see the
+ancestor chain for any object in Ruby by doing:
-* If refinements are active for +C+, in the reverse order they were activated:
- * The prepended modules from the refinement for +C+
- * The refinement for +C+
- * The included modules from the refinement for +C+
-* The prepended modules of +C+
-* +C+
-* The included modules of +C+
+ object.singleton_class.ancestors
+ # or, if the object does not support a singleton class:
+ object.class.ancestors
-If no method was found at any point this repeats with the superclass of +C+.
+The ancestor chain is constructed as follows:
-Note that methods in a subclass have priority over refinements in a
-superclass. For example, if the method <code>/</code> is defined in a
-refinement for Numeric <code>1 / 2</code> invokes the original Integer#/
-because Integer is a subclass of Numeric and is searched before the refinements
-for the superclass Numeric. Since the method <code>/</code> is also present
-in child +Integer+, the method lookup does not move up to the superclass.
+* Subclasses are before superclasses in the ancestor chain
+* Prepended modules are before the class they prepend in the ancestor
+ chain, in reverse order in which they were prepended.
+* Included modules are after the class they are included in in the
+ ancestor chain, in reverse order in which they were included.
+
+When looking up a method for an object, Ruby goes through each ancestor:
+
+* If the class/module has been refined, Ruby will consider the refinements
+ activated at the point the method was called, in reverse order of
+ activation.
+* Otherwise, Ruby will check the methods of the class/module itself.
+
+If no method was found at either point this repeats with the next
+ancestor.
-However, if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code>
+Note that methods in a earlier ancestor have priority over refinements in a
+later ancestor. For example, if the method <code>/</code> is defined in a
+refinement for Numeric <code>1 / 2</code> invokes the original Integer#/
+because Integer is a comes before Numeric in the ancestor chain. However,
+if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code>
invokes that method since +foo+ does not exist on Integer.
== +super+
-When +super+ is invoked method lookup checks:
+When +super+ is invoked, method lookup starts:
+
+* If the method is in a refinement, at the refined class or module
+* Otherwise, at the next ancestor
+
+Method lookup then proceeds as described in the Method Lookup section
+above.
-* The included modules of the current class. Note that the current class may
- be a refinement.
-* If the current class is a refinement, the method lookup proceeds as in the
- Method Lookup section above.
-* If the current class has a direct superclass, the method proceeds as in the
- Method Lookup section above using the superclass.
+Refinements activated at the call site of a refinement method do not
+affect +super+ inside that method. Only refinements activated at the
+point +super+ was called affect method lookup for that +super+ call.
+You cannot use refinements to insert into the middle of a method
+lookup chain, only to insert at the start of a method lookup chain,
+unless you control the +super+ call sites.
-Note that +super+ in a method of a refinement invokes the method in the
-refined class even if there is another refinement which has been activated in
-the same context. This is only true for +super+ in a method of a refinement, it
-does not apply to +super+ in a method in a module that is included in a refinement.
+Note that if you refine a module, the refinement method can call +super+
+to call the method in the module, but the method in the module cannot
+call +super+ to continue the method lookup process to further ancestors.
== Methods Introspection
diff --git a/doc/windows.md b/doc/windows.md
deleted file mode 100644
index 7cf3a42ad6..0000000000
--- a/doc/windows.md
+++ /dev/null
@@ -1,254 +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:
-
-```batch
-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:
-
-```bash
-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 10/Windows Server 2016 or later.
-
-2. Visual C++ 14.0 (2015) 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.
- These are set properly by `vcvarall*.bat` usually.
-
- **Note** building ruby requires following commands.
-
- * `nmake`
- * `cl`
- * `ml`
- * `lib`
- * `dumpbin`
-
-4. If you want to build from GIT source, following commands are required.
- * `git`
- * `sed`
- * `ruby` 3.0 or later
-
- You can use [scoop](https://scoop.sh/) to install them like:
-
- ```batch
- scoop install git sed ruby
- ```
-
-5. You need to install required libraries using [vcpkg](https://vcpkg.io/) on
- directory of ruby repository like:
-
- ```batch
- vcpkg --triplet x64-windows install
- ```
-
-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` .
-
-2. If you want to append to the executable and DLL file names,
- specify `--program-prefix` and `--program-suffix`, like
- `win32\configure.bat --program-suffix=-$(MAJOR)$(MINOR)`.
-
- Also, the `--install-name` and `--so-name` options specify the
- exact base names of the executable and DLL files, respectively,
- like `win32\configure.bat --install-name=$(RUBY_BASE_NAME)-$(MAJOR)$(MINOR)`.
-
- By default, the name for the executable without a console window
- is generated from the _RUBY_INSTALL_NAME_ specified as above by
- replacing `ruby` with `rubyw`. If you want to make it different
- more, modify _RUBYW_INSTALL_NAME_ directly in the Makefile.
-
-3. You need specify vcpkg directory to use `--with-opt-dir`
- option like `win32\configure.bat --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 prepare-vcpkg` with administrator privilege if you need to
- copy vcpkg installed libraries like `libssl-3-x64.dll` to the build directory.
-
-7. Run `nmake check`
-
-8. 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
- ```
-
- ```batch
- 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
- ```
-
- ```batch
- 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
- ```
-
- ```batch
- 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
- ```
-
- ```batch
- 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`.
-
-### Dependency management
-
-Ruby uses [vcpkg](https://vcpkg.io/) to manage dependencies on mswin platform.
-
-You can update and install it under the build directory like:
-
-```batch
-nmake update-vcpkg # Update baseline version of vcpkg
-nmake install-vcpkg # Install vcpkg from build directory
-```
-
-
-## 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/yarvarch.en b/doc/yarvarch.en
deleted file mode 100644
index 7a76e25b7e..0000000000
--- a/doc/yarvarch.en
+++ /dev/null
@@ -1,7 +0,0 @@
-#title YARV: Yet another RubyVM - Software Architecture
-
-maybe writing.
-
-* YARV instruction set
-
-<%= d %>
diff --git a/doc/yarvarch.ja b/doc/yarvarch.ja
deleted file mode 100644
index 2739ec6b14..0000000000
--- a/doc/yarvarch.ja
+++ /dev/null
@@ -1,454 +0,0 @@
-#title YARVアーキテクチャ
-#set author 日本 Ruby の会 ささだこういち
-
-
-- 2005-03-03(Thu) 00:31:12 +0900 いろいろと書き直し
-
-----
-
-* これは?
-
-[[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] の 設計メモです。
-
-
-YARV は、Ruby プログラムのための次の機能を提供します。
-
-- Compiler
-- VM Generator
-- VM (Virtual Machine)
-- Assembler
-- Dis-Assembler
-- (experimental) JIT Compiler
-- (experimental) AOT Compiler
-
-
-現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ
-れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存
-の拡張ライブラリ)などがほぼそのまま利用できます。
-
-ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。
-
-今後は、Ruby 本体のインタプリタ部分(eval.c)を置き換えることを目指して
-開発を継続する予定です。
-
-
-* Compiler (compile.h, compile.c)
-
-コンパイラは、Ruby インタプリタのパーサによって生成された構文木(RNode
-データによる木)を YARV 命令列に変換します。YARV 命令については後述しま
-す。
-
-とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初
-期化などを行い、あとは構文木を辿り変換していきます。
-
-変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ
-ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ
-ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV
-の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽
-に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし
-てくれるため)。
-
-YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで
-表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で
-は VALUE のサイズ)で表現されます。そのため、YARV 命令はいわゆる「バイト
-コード」ではありません。そのため、YARV の説明などでは「命令列」という用
-語を使っています。
-
-1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な
-どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ
-ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で
-すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。
-
-
-* VM Generator (rb/insns2vm.rb, insns.def)
-
-rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、
-VM のために必要なファイルを生成します。具体的には、命令を実行する部分を
-生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ
-ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。
-
-
-** 命令記述
-
-insns.def には、各命令がどのような命令であるかを記述します。具体的には次
-の情報を記述します。
-
-- 命令の名前
-- その命令のカテゴリ、コメント(英語、日本語)
-- オペランドの名前
-- その命令実行前にスタックからポップする値
-- その命令実行後にスタックにプッシュする値
-- その命令のロジック(C 言語で記述)
-
-たとえば、スタックに self をおく putself という命令は次のように記述しま
-す。
-
-#code
-/**
- @c put
- @e put self.
- @j self を置く。
- */
-DEFINE_INSN
-putself
-()
-()
-(VALUE val)
-{
- val = GET_SELF();
-}
-#end
-
-この場合、オペランドと、スタックからポップする値は無いことになります。命
-令終了後、self をスタックトップに置きたいわけですが、それは val という、
-スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ
-れを変換するとスタックトップに置く C プログラムが生成されます。
-
-細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく
-ないと思います。
-
-insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ
-が定義されています。また、VM の内部構造に関する定義は vm.h というファイ
-ルにあります。
-
-
-* VM (Virtual Machine, vm.h, vm.c)
-
-VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ
-に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え
-たいと考えています。
-
-現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる
-ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。
-
-VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ
-クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域
-設定が可能です。
-
-
-** レジスタ
-
-VM は 5 つの仮想的なレジスタによって制御されます。
-
-- PC (Program Counter)
-- SP (Stack Pointer)
-- CFP (Control Frame Pointer)
-- LFP (Local Frame Pointer)
-- DFP (Dynamic Frame Pointer)
-
-PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し
-ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。
-
-
-** スタックフレーム
-
-obsolete (update soon)
-
-
-** フレームデザインについての補足
-
-Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ
-ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。
-あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外
-側に辿れば必ずたどり着くことができるからです(つまり、lfp は必要ない)。
-
-しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が
-あること、具体的にはブロックとself(callee からみると receiver)です。こ
-の情報をそれぞれのフレームにもたせるのは無駄です。
-
-また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル
-引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ
-ル変数へのアクセスが頻発することが予想されます。
-
-このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の
-リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと
-ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム
-が lfpレジスタによって容易にアクセスできるようにしました。
-
-
-** メソッド呼び出しについて
-
-メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ
-ソッドかによってディスパッチ手法が変わります。
-
-YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し
-ます。とくに VM の関数を再帰呼び出すすることは行ないません。
-
-C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、
-バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから
-行ないます)。
-
-このため、VM 用スタックを別途用意したものの、プログラムによってはマシン
-スタックを使い切ってしまう可能性があります(C -> Ruby -> C -> ... という
-呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。
-
-
-** 例外
-
-例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外
-が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発
-生したときの PC の値に合致するエントリがあった場合、そのエントリに従って
-動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた
-同様にそのスコープの例外テーブルを検査します。
-
-また、break、return(ブロック中)、retry なども同様の仕組みで実現します。
-
-*** 例外テーブル
-
-例外テーブルエントリは具体的には次の情報が格納されています。
-
-- 対象とする PC の範囲
-- 対象とする例外の種類
-- もし対象となったときにジャンプする先(種類による)
-- もし対象となったときに起動するブロックの iseq
-
-
-*** rescue
-
-rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま
-す。
-
-#code
-begin
-rescue A
-rescue B
-rescue C
-end
-#end
-
-は、次のような Ruby スクリプトに変換されます。
-
-#code
-{|err|
- case err
- when A === err
- when B === err
- when C === err
- else
- raise # yarv の命令では throw
- end
-}
-#end
-
-
-*** ensure
-
-正常系(例外が発生しなかった場合)と異常系(例外が発生したときなど)の2
-種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ
-ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず
-throw 命令で締めることになります。
-
-
-*** break, return(ブロック中)、retry
-
-break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル
-されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判
-断します。
-
-
-** 定数の検索
-
-定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い
-つまでも再定義可能になっています。
-
-定数アクセスのためのRuby記述は次のようになります。
-
-#code
-Ruby表現:
-expr::ID::...::ID
-#end
-
-これは、yarv命令セットでは次のようになります。
-
-#code
-(expr)
-getconstant ID
-...
-getconstant ID
-#end
-
-
-*** 定数検索パス
-
-もし expr が nil だった場合、定数検索パスに従って定数を検索します。この
-挙動は今後 Ruby 2.0 に向けて変更される場合があります。
-
-+ クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る
-+ 継承関係をルート(Object)まで辿る
-
-このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。
-このために、thread_object には klass_nest_stack というものを用意しました。
-これは、現在のネストの情報を保存します。
-
-メソッド定義時、その現在のネスト情報をメソッド定義時に(dupして)加える
-ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま
-す。
-
-トップレベルでは、その情報はないことになります。
-
-クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり
-ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします
-(すでにコピーされていれば、これを行いません)。
-
-これにより、動的なネスト情報を統一的に扱うことができます。
-
-
-** 最適化手法
-
-YARV では高速化を目的としているので、さまざまな最適化手法を利用していま
-す。詳細は割愛しますが、以下に述べる最適化などを行なっております。
-
-
-*** threaded code
-
-GCC の C 言語拡張である値としてのラベルを利用して direct threaded code
-を実現しています。
-
-
-*** Peephole optimization
-
-いくつかの簡単な最適化をしています。
-
-
-*** inline method cache
-
-命令列の中にメソッド検索結果を埋め込みます。
-
-
-*** inline constant cache
-
-命令列の中に定数検索結果を埋め込みます。
-
-
-*** ブロックと Proc オブジェクトの分離
-
-ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc
-オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの
-生成を抑えています。
-
-Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー
-プ上に確保された変数など)をヒープに保存します。
-
-
-*** 特化命令
-
-Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか
-るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命
-令を用意しました。
-
-
-*** 命令融合
-
-複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ
-り自動的に生成されます。
-
-
-*** オペランド融合
-
-複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の
-記述によって自動的に生成されます。
-
-
-*** stack caching
-
-スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ
-ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ
-シングする命令は自動的に生成されます。
-
-
-*** JIT Compile
-
-機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ
-とんどのプログラムは動きません。
-
-
-*** AOT Compile
-
-YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、
-それなりに動きます。rb/aotc.rb がコンパイラです。
-
-
-* Assembler (rb/yasm.rb)
-
-YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく
-ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり
-ません)。
-
-
-* Dis-Assembler (disasm.c)
-
-YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm
-メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。
-
-
-* YARV 命令セット
-
-<%= d %>
-
-* その他
-
-** テスト
-
-test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、
-このテストに記述されている例ではきちんと動作するということです。
-
-
-** ベンチマーク
-
-benchmark/bm_* にベンチマークプログラムがおいてあります。
-
-
-** 今後の予定
-
-まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって
-いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう
-か。
-
-
-*** Verifier
-
-YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま
-す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ
-アを用意しなければならないと考えています。
-
-
-*** Compiled File の構想
-
-Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに
-出力できるようにしたいと考えています。これを利用して一度コンパイルした命
-令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト
-を省くことができます。
-
-
-**** 全体構成
-
-次のようなファイル構成を考えていますが、まだ未定です。
-
-#code
-u4 : 4 byte unsigned storage
-u2 : 2 byte unsigned storage
-u1 : 1 byte unsigned storage
-
-every storages are little endian :-)
-
-CompiledFile{
- u4 magic;
-
- u2 major;
- u2 minor;
-
- u4 character_code;
-
- u4 constants_pool_count;
- ConstantEntry constants_pool[constants_pool_count];
-
- u4 block_count;
- blockEntry blocks[block_count];
-
- u4 method_count;
- MethodEntry methods[method_count];
-}
-#end
-
-Java classfile のパクリ。
-
diff --git a/doc/yjit/yjit.md b/doc/yjit/yjit.md
deleted file mode 100644
index 0024c780b9..0000000000
--- a/doc/yjit/yjit.md
+++ /dev/null
@@ -1,544 +0,0 @@
-<p align="center">
- <a href="https://yjit.org/" target="_blank" rel="noopener noreferrer">
- <img src="https://user-images.githubusercontent.com/224488/131155756-aa8fb528-a813-4dfd-99ac-8785c3d5eed7.png" width="400">
- </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.
-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>
-
-If you wish to learn more about the approach taken, here are some conference talks and publications:
-
-- MPLR 2023 talk: [Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach](https://www.youtube.com/watch?v=pVRmPZcNUhc)
-- 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)
-- ECOOP 2016 paper: [Interprocedural Type Specialization of JavaScript Programs Without Type Analysis](https://drops.dagstuhl.de/opus/volltexte/2016/6101/pdf/LIPIcs-ECOOP-2016-7.pdf)
-- 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:
-
-```BibTeX
-@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},
-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}
-}
-```
-
-## 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).
-
-## Installation
-
-### Requirements
-
-You will need to install:
-
- - All the usual build tools for Ruby. See [Building Ruby](../contributing/building_ruby.md)
- - The Rust compiler `rustc`
- - The Rust version must be [>= 1.58.0](../../yjit/Cargo.toml).
- - Optionally, only if you wish to build in dev/debug mode, Rust's `cargo`
-
-If you don't intend on making code changes to YJIT itself, we recommend
-obtaining `rustc` through your OS's package manager since that
-likely reuses the same vendor which provides the C toolchain.
-
-If you will be changing YJIT's Rust code, we suggest using the
-[first-party installation method][rust-install] for Rust. Rust also provides
-first class [support][editor-tools] for many source code editors.
-
-[rust-install]: https://www.rust-lang.org/tools/install
-[editor-tools]: https://www.rust-lang.org/tools
-
-### Building YJIT
-
-Start by cloning the `ruby/ruby` repository:
-
-```sh
-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).
-
-```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
-```
-
-or
-
-```sh
-# Configure in lower-performance 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
-```
-
-On macOS, you may need to specify where to find some libraries:
-
-```sh
-# Install dependencies
-brew install openssl 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
-```
-
-Typically configure will choose the default C compiler. To specify the C compiler, use
-
-```sh
-# Choosing a specific c compiler
-export CC=/path/to/my/chosen/c/compiler
-```
-
-before running `./configure`.
-
-You can test that YJIT works correctly by running:
-
-```sh
-# Quick tests found in /bootstraptest
-make btest
-
-# Complete set of tests
-make -j test-all
-```
-
-## Usage
-
-### Examples
-
-Once YJIT is built, you can either use `./miniruby` from within your build directory, or switch to the YJIT version of `ruby`
-by using the `chruby` tool:
-
-```sh
-chruby ruby-yjit
-ruby myscript.rb
-```
-
-You can dump statistics about compilation and execution by running YJIT with the `--yjit-stats` command-line option:
-
-```sh
-./miniruby --yjit-stats myscript.rb
-```
-
-You can see what YJIT has compiled by running YJIT with the `--yjit-log` command-line option:
-
-```sh
-./miniruby --yjit-log myscript.rb
-```
-
-The machine code generated for a given method can be printed by adding `puts RubyVM::YJIT.disasm(method(:method_name))` to a Ruby script. Note that no code will be generated if the method is not compiled.
-
-<h3 id="command-line-options">Command-Line Options</h3>
-
-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-mem-size=N`: soft limit on YJIT memory usage in MiB (default: 128). Tries to limit `code_region_size + yjit_alloc_size`
-- `--yjit-exec-mem-size=N`: hard limit on executable memory block in MiB. Limits `code_region_size`
-- `--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-log[=file|dir]`: log all compilation events to the specified file or directory. If no name is supplied, the last 1024 log entries will be printed to stderr when the application exits.
-- `--yjit-log=quiet`: gather a circular buffer of recent YJIT compilations. The compilation log entries are accessible through `RubyVM::YJIT.log` and old entries will be discarded if the buffer is not drained quickly. (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 all exits. Automatically enables `--yjit-stats`
-- `--yjit-trace-exits=COUNTER`: produce a Marshal dump of backtraces from a counted exit or a fallback. Automatically enables `--yjit-stats`
-- `--yjit-trace-exits-sample-rate=N`: trace exit locations only every Nth occurrence. Automatically enables `--yjit-trace-exits`
-
-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-mem-size
-
-The `--yjit-mem-size` value can be used to set the maximum amount of memory that YJIT
-is allowed to use. This corresponds to the total of `RubyVM::YJIT.runtime_stats[:code_region_size]`
-and `RubyVM::YJIT.runtime_stats[:yjit_alloc_size]`
-Increasing the `--yjit-mem-size` value 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 percentage of total YARV instructions
-executed by YJIT as opposed to the CRuby interpreter.
-Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-mem-size` often
-helps improving `ratio_in_yjit`.
-
-### Running workers as long as possible
-
-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.
-
-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.
-
-## 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-mem-size
-
-YJIT uses memory for compiled code and metadata. You can change the maximum amount of memory
-that YJIT can use by specifying a different `--yjit-mem-size` command-line option. The default value
-is currently `128`.
-When changing this value, 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`
-- 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
-- Minimize layers of indirection
- - Avoid writing wrapper classes if you can (e.g. a class that only wraps a Ruby hash)
- - Avoid methods that just call another method
-- Ruby method calls are costly. Avoid things such as methods that only return a value from a hash
-- Try to write code so that the same variables and method arguments always have the same type
-- Avoid using `TracePoint` as it can cause YJIT to deoptimize code
-- Avoid using `binding` as it can cause YJIT to deoptimize code
-
-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`.
-
-```rb
-$ RUBYOPT="--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,
- :send_callsite_not_simple=>7267,
- :send_kw_splat=>7,
- :send_ivar_set_method=>72,
-...
-```
-
-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.)
-
-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.
-
-The printed text after a `--yjit-stats` run includes other information that may be named differently than the information in `RubyVM::YJIT.runtime_stats`.
-
-## Contributing
-
-We welcome open source contributions. 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
-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.
-
-### Source Code Organization
-
-The YJIT source code is divided between:
-
-- `yjit.c`: code YJIT uses to interface with the rest of CRuby
-- `yjit.h`: C definitions YJIT exposes to the rest of the CRuby
-- `yjit.rb`: `YJIT` Ruby module that is exposed to Ruby
-- `yjit/src/asm/*`: in-memory assembler we use to generate machine code
-- `yjit/src/codegen.rs`: logic for translating Ruby bytecode to machine code
-- `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
-
-The core of CRuby's interpreter logic is found in:
-
-- `insns.def`: defines Ruby's bytecode instructions (gets compiled into `vm.inc`)
-- `vm_insnshelper.c`: logic used by Ruby's bytecode instructions
-- `vm_exec.c`: Ruby interpreter loop
-
-### Generating C bindings with bindgen
-
-In order to expose C functions to the Rust codebase, you will need to generate C bindings:
-
-```sh
-CC=clang ./configure --enable-yjit=dev
-make -j yjit-bindgen
-```
-
-This uses the bindgen tools to generate/update `yjit/src/cruby_bindings.inc.rs` based on the
-bindings listed in `yjit/bindgen/src/main.rs`. Avoid manually editing this file
-as it could be automatically regenerated at a later time. If you need to manually add C bindings,
-add them to `yjit/cruby.rs` instead.
-
-### Coding & Debugging Protips
-
-There are multiple 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:
-
-```sh
-make -j test-all RUN_OPTS="--yjit-call-threshold=1"
-```
-
-Or single-threaded like this, to more easily identify which specific test is failing:
-
-```sh
-make test-all TESTOPTS=--verbose RUN_OPTS="--yjit-call-threshold=1"
-```
-
-To run a single test file with `test-all`:
-
-```sh
-make test-all TESTS='test/-ext-/marshal/test_usrmarshal.rb' RUNRUBYOPT=--debugger=lldb RUN_OPTS="--yjit-call-threshold=1"
-```
-
-It's also possible to filter tests by name to run a single test:
-
-```sh
-make test-all TESTS='-n /test_float_plus/' RUN_OPTS="--yjit-call-threshold=1"
-```
-
-You can also run one specific test in `btest`:
-
-```sh
-make btest BTESTS=bootstraptest/test_ractor.rb RUN_OPTS="--yjit-call-threshold=1"
-```
-
-There are shortcuts to run/debug your own test/repro in `test.rb`:
-
-```sh
-make run # runs ./miniruby test.rb
-make lldb # launches ./miniruby test.rb in lldb
-```
-
-You can use the Intel syntax for disassembly in LLDB, keeping it consistent with YJIT's disassembly:
-
-```sh
-echo "settings set target.x86-disassembly-flavor intel" >> ~/.lldbinit
-```
-
-## Running x86 YJIT on Apple's Rosetta
-
-For development purposes, it is possible to run x86 YJIT on an Apple M1 via Rosetta. You can find basic
-instructions below, but there are a few caveats listed further down.
-
-First, install Rosetta:
-
-```console
-$ softwareupdate --install-rosetta
-```
-
-Now any command can be run with Rosetta via the `arch` command line tool.
-
-Then you can start your shell in an x86 environment:
-
-```console
-$ arch -x86_64 zsh
-```
-
-You can double check your current architecture via the `arch` command:
-
-```console
-$ arch -x86_64 zsh
-$ arch
-i386
-```
-
-You may need to set the default target for `rustc` to x86-64, e.g.
-
-```console
-$ rustup default stable-x86_64-apple-darwin
-```
-
-While in your i386 shell, install Cargo and Homebrew, then hack away!
-
-### Rosetta Caveats
-
-1. You must install a version of Homebrew for each architecture
-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.
-
-### Call graph
-
-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
-```
-
-### YJIT codegen
-
-You can also profile the number of cycles consumed by code generated by each YJIT function.
-
-```bash
-# Install perf
-apt-get install linux-tools-common linux-tools-generic linux-tools-`uname -r`
-
-# [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=codegen
-cd ../yjit-bench
-PERF=record ruby --yjit-perf=codegen -Iharness-perf benchmarks/lobsters/benchmark.rb
-
-# Aggregate results
-perf script > /tmp/perf.txt
-../ruby/misc/yjit_perf.py /tmp/perf.txt
-```
-
-#### Building perf with Python support
-
-The above instructions work fine for most people, but you could also use
-a handy `perf script -s` interface if you build perf from source.
-
-```bash
-# Build perf from source for Python support
-sudo apt-get install libpython3-dev python3-pip flex libtraceevent-dev \
- libelf-dev libunwind-dev libaudit-dev libslang2-dev libdw-dev
-git clone --depth=1 https://github.com/torvalds/linux
-cd linux/tools/perf
-make
-make install
-
-# Aggregate results
-perf script -s ../ruby/misc/yjit_perf.py
-```
diff --git a/enc/Makefile.in b/enc/Makefile.in
index ce93fdd22d..2a3c45169f 100644
--- a/enc/Makefile.in
+++ b/enc/Makefile.in
@@ -24,13 +24,14 @@ OBJEXT = @OBJEXT@
LIBEXT = @LIBEXT@
EXEEXT = @EXEEXT@
TIMESTAMPDIR = $(EXTOUT)/.timestamp
-ENC_TRANS_D = $(TIMESTAMPDIR)/.enc-trans.time
-ENC_TRANS_SO_D = $(TIMESTAMPDIR)/.enc-trans.so.time
+ENC_TRANS_D = $(TIMESTAMPDIR)/enc-trans.time
+ENC_TRANS_SO_D = $(TIMESTAMPDIR)/enc-trans-$(arch).time
BUILTIN_ENCS = enc/ascii.c enc/us_ascii.c\
enc/unicode.c enc/utf_8.c
BUILTIN_TRANSES = enc/trans/newline.trans
+BUILTIN_TRANS_CSRCS = $(BUILTIN_TRANSES:.trans=.c)
RUBY_SO_NAME = @RUBY_SO_NAME@
LIBRUBY = @LIBRUBY@
diff --git a/enc/ascii.c b/enc/ascii.c
index ae7db97f25..4ba93f4feb 100644
--- a/enc/ascii.c
+++ b/enc/ascii.c
@@ -54,7 +54,11 @@ OnigEncodingDefine(ascii, ASCII) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
ENCINDEX_ASCII_8BIT,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/big5.c b/enc/big5.c
index ab4fb69819..e141ebdbe3 100644
--- a/enc/big5.c
+++ b/enc/big5.c
@@ -300,7 +300,11 @@ OnigEncodingDefine(big5, BIG5) = {
onigenc_not_support_get_ctype_code_range,
big5_left_adjust_char_head,
big5_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
@@ -335,7 +339,11 @@ OnigEncodingDefine(big5_hkscs, BIG5_HKSCS) = {
onigenc_not_support_get_ctype_code_range,
big5_left_adjust_char_head,
big5_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
@@ -370,7 +378,11 @@ OnigEncodingDefine(big5_uao, BIG5_UAO) = {
onigenc_not_support_get_ctype_code_range,
big5_left_adjust_char_head,
big5_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/cp949.c b/enc/cp949.c
index 1600d0cd5b..77e961a7cd 100644
--- a/enc/cp949.c
+++ b/enc/cp949.c
@@ -211,7 +211,11 @@ OnigEncodingDefine(cp949, CP949) = {
onigenc_not_support_get_ctype_code_range,
cp949_left_adjust_char_head,
cp949_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/depend b/enc/depend
index 2918a90a05..4bf97dc880 100644
--- a/enc/depend
+++ b/enc/depend
@@ -157,15 +157,15 @@ clean:
% end
% unless inplace
$(Q)$(RM) enc/unicode/*/casefold.h enc/unicode/*/name2ctype.h
- $(Q)$(RM) enc/jis/props.h
- -$(Q)$(RMDIR) enc/unicode<%=ignore_error%>
+ $(Q)$(RM) enc/trans/newline.c enc/jis/props.h
+ -$(Q)$(RMDIR) enc/trnas enc/unicode<%=ignore_error%>
% end
% workdirs.reverse_each do|d|
-$(Q)$(RMDIR) <%=pathrep[d]%><%=ignore_error%>
% end
clean-srcs:
- $(Q)$(RM) <%=pathrep['$(TRANSCSRCS)']%>
+ $(Q)$(RM) <%=pathrep['$(TRANSCSRCS)']%> <%=pathrep['$(BUILTIN_TRANS_CSRCS)']%>
-$(Q)$(RMDIR) <%=pathrep['enc/trans']%><%=ignore_error%>
$(Q)$(RM) enc/unicode/*/casefold.h enc/unicode/*/name2ctype.h
$(Q)$(RM) enc/jis/props.h
@@ -317,6 +317,7 @@ enc/ascii.$(OBJEXT): internal/intern/re.h
enc/ascii.$(OBJEXT): internal/intern/ruby.h
enc/ascii.$(OBJEXT): internal/intern/select.h
enc/ascii.$(OBJEXT): internal/intern/select/largesize.h
+enc/ascii.$(OBJEXT): internal/intern/set.h
enc/ascii.$(OBJEXT): internal/intern/signal.h
enc/ascii.$(OBJEXT): internal/intern/sprintf.h
enc/ascii.$(OBJEXT): internal/intern/string.h
@@ -479,6 +480,7 @@ enc/big5.$(OBJEXT): internal/intern/re.h
enc/big5.$(OBJEXT): internal/intern/ruby.h
enc/big5.$(OBJEXT): internal/intern/select.h
enc/big5.$(OBJEXT): internal/intern/select/largesize.h
+enc/big5.$(OBJEXT): internal/intern/set.h
enc/big5.$(OBJEXT): internal/intern/signal.h
enc/big5.$(OBJEXT): internal/intern/sprintf.h
enc/big5.$(OBJEXT): internal/intern/string.h
@@ -651,6 +653,7 @@ enc/cesu_8.$(OBJEXT): internal/intern/re.h
enc/cesu_8.$(OBJEXT): internal/intern/ruby.h
enc/cesu_8.$(OBJEXT): internal/intern/select.h
enc/cesu_8.$(OBJEXT): internal/intern/select/largesize.h
+enc/cesu_8.$(OBJEXT): internal/intern/set.h
enc/cesu_8.$(OBJEXT): internal/intern/signal.h
enc/cesu_8.$(OBJEXT): internal/intern/sprintf.h
enc/cesu_8.$(OBJEXT): internal/intern/string.h
@@ -813,6 +816,7 @@ enc/cp949.$(OBJEXT): internal/intern/re.h
enc/cp949.$(OBJEXT): internal/intern/ruby.h
enc/cp949.$(OBJEXT): internal/intern/select.h
enc/cp949.$(OBJEXT): internal/intern/select/largesize.h
+enc/cp949.$(OBJEXT): internal/intern/set.h
enc/cp949.$(OBJEXT): internal/intern/signal.h
enc/cp949.$(OBJEXT): internal/intern/sprintf.h
enc/cp949.$(OBJEXT): internal/intern/string.h
@@ -974,6 +978,7 @@ enc/emacs_mule.$(OBJEXT): internal/intern/re.h
enc/emacs_mule.$(OBJEXT): internal/intern/ruby.h
enc/emacs_mule.$(OBJEXT): internal/intern/select.h
enc/emacs_mule.$(OBJEXT): internal/intern/select/largesize.h
+enc/emacs_mule.$(OBJEXT): internal/intern/set.h
enc/emacs_mule.$(OBJEXT): internal/intern/signal.h
enc/emacs_mule.$(OBJEXT): internal/intern/sprintf.h
enc/emacs_mule.$(OBJEXT): internal/intern/string.h
@@ -1145,6 +1150,7 @@ enc/encdb.$(OBJEXT): internal/intern/re.h
enc/encdb.$(OBJEXT): internal/intern/ruby.h
enc/encdb.$(OBJEXT): internal/intern/select.h
enc/encdb.$(OBJEXT): internal/intern/select/largesize.h
+enc/encdb.$(OBJEXT): internal/intern/set.h
enc/encdb.$(OBJEXT): internal/intern/signal.h
enc/encdb.$(OBJEXT): internal/intern/sprintf.h
enc/encdb.$(OBJEXT): internal/intern/string.h
@@ -1309,6 +1315,7 @@ enc/euc_jp.$(OBJEXT): internal/intern/re.h
enc/euc_jp.$(OBJEXT): internal/intern/ruby.h
enc/euc_jp.$(OBJEXT): internal/intern/select.h
enc/euc_jp.$(OBJEXT): internal/intern/select/largesize.h
+enc/euc_jp.$(OBJEXT): internal/intern/set.h
enc/euc_jp.$(OBJEXT): internal/intern/signal.h
enc/euc_jp.$(OBJEXT): internal/intern/sprintf.h
enc/euc_jp.$(OBJEXT): internal/intern/string.h
@@ -1470,6 +1477,7 @@ enc/euc_kr.$(OBJEXT): internal/intern/re.h
enc/euc_kr.$(OBJEXT): internal/intern/ruby.h
enc/euc_kr.$(OBJEXT): internal/intern/select.h
enc/euc_kr.$(OBJEXT): internal/intern/select/largesize.h
+enc/euc_kr.$(OBJEXT): internal/intern/set.h
enc/euc_kr.$(OBJEXT): internal/intern/signal.h
enc/euc_kr.$(OBJEXT): internal/intern/sprintf.h
enc/euc_kr.$(OBJEXT): internal/intern/string.h
@@ -1631,6 +1639,7 @@ enc/euc_tw.$(OBJEXT): internal/intern/re.h
enc/euc_tw.$(OBJEXT): internal/intern/ruby.h
enc/euc_tw.$(OBJEXT): internal/intern/select.h
enc/euc_tw.$(OBJEXT): internal/intern/select/largesize.h
+enc/euc_tw.$(OBJEXT): internal/intern/set.h
enc/euc_tw.$(OBJEXT): internal/intern/signal.h
enc/euc_tw.$(OBJEXT): internal/intern/sprintf.h
enc/euc_tw.$(OBJEXT): internal/intern/string.h
@@ -1792,6 +1801,7 @@ enc/gb18030.$(OBJEXT): internal/intern/re.h
enc/gb18030.$(OBJEXT): internal/intern/ruby.h
enc/gb18030.$(OBJEXT): internal/intern/select.h
enc/gb18030.$(OBJEXT): internal/intern/select/largesize.h
+enc/gb18030.$(OBJEXT): internal/intern/set.h
enc/gb18030.$(OBJEXT): internal/intern/signal.h
enc/gb18030.$(OBJEXT): internal/intern/sprintf.h
enc/gb18030.$(OBJEXT): internal/intern/string.h
@@ -1953,6 +1963,7 @@ enc/gb2312.$(OBJEXT): internal/intern/re.h
enc/gb2312.$(OBJEXT): internal/intern/ruby.h
enc/gb2312.$(OBJEXT): internal/intern/select.h
enc/gb2312.$(OBJEXT): internal/intern/select/largesize.h
+enc/gb2312.$(OBJEXT): internal/intern/set.h
enc/gb2312.$(OBJEXT): internal/intern/signal.h
enc/gb2312.$(OBJEXT): internal/intern/sprintf.h
enc/gb2312.$(OBJEXT): internal/intern/string.h
@@ -2114,6 +2125,7 @@ enc/gbk.$(OBJEXT): internal/intern/re.h
enc/gbk.$(OBJEXT): internal/intern/ruby.h
enc/gbk.$(OBJEXT): internal/intern/select.h
enc/gbk.$(OBJEXT): internal/intern/select/largesize.h
+enc/gbk.$(OBJEXT): internal/intern/set.h
enc/gbk.$(OBJEXT): internal/intern/signal.h
enc/gbk.$(OBJEXT): internal/intern/sprintf.h
enc/gbk.$(OBJEXT): internal/intern/string.h
@@ -2276,6 +2288,7 @@ enc/iso_8859_1.$(OBJEXT): internal/intern/re.h
enc/iso_8859_1.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_1.$(OBJEXT): internal/intern/select.h
enc/iso_8859_1.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_1.$(OBJEXT): internal/intern/set.h
enc/iso_8859_1.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_1.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_1.$(OBJEXT): internal/intern/string.h
@@ -2438,6 +2451,7 @@ enc/iso_8859_10.$(OBJEXT): internal/intern/re.h
enc/iso_8859_10.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_10.$(OBJEXT): internal/intern/select.h
enc/iso_8859_10.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_10.$(OBJEXT): internal/intern/set.h
enc/iso_8859_10.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_10.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_10.$(OBJEXT): internal/intern/string.h
@@ -2599,6 +2613,7 @@ enc/iso_8859_11.$(OBJEXT): internal/intern/re.h
enc/iso_8859_11.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_11.$(OBJEXT): internal/intern/select.h
enc/iso_8859_11.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_11.$(OBJEXT): internal/intern/set.h
enc/iso_8859_11.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_11.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_11.$(OBJEXT): internal/intern/string.h
@@ -2761,6 +2776,7 @@ enc/iso_8859_13.$(OBJEXT): internal/intern/re.h
enc/iso_8859_13.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_13.$(OBJEXT): internal/intern/select.h
enc/iso_8859_13.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_13.$(OBJEXT): internal/intern/set.h
enc/iso_8859_13.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_13.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_13.$(OBJEXT): internal/intern/string.h
@@ -2923,6 +2939,7 @@ enc/iso_8859_14.$(OBJEXT): internal/intern/re.h
enc/iso_8859_14.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_14.$(OBJEXT): internal/intern/select.h
enc/iso_8859_14.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_14.$(OBJEXT): internal/intern/set.h
enc/iso_8859_14.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_14.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_14.$(OBJEXT): internal/intern/string.h
@@ -3085,6 +3102,7 @@ enc/iso_8859_15.$(OBJEXT): internal/intern/re.h
enc/iso_8859_15.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_15.$(OBJEXT): internal/intern/select.h
enc/iso_8859_15.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_15.$(OBJEXT): internal/intern/set.h
enc/iso_8859_15.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_15.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_15.$(OBJEXT): internal/intern/string.h
@@ -3247,6 +3265,7 @@ enc/iso_8859_16.$(OBJEXT): internal/intern/re.h
enc/iso_8859_16.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_16.$(OBJEXT): internal/intern/select.h
enc/iso_8859_16.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_16.$(OBJEXT): internal/intern/set.h
enc/iso_8859_16.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_16.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_16.$(OBJEXT): internal/intern/string.h
@@ -3409,6 +3428,7 @@ enc/iso_8859_2.$(OBJEXT): internal/intern/re.h
enc/iso_8859_2.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_2.$(OBJEXT): internal/intern/select.h
enc/iso_8859_2.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_2.$(OBJEXT): internal/intern/set.h
enc/iso_8859_2.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_2.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_2.$(OBJEXT): internal/intern/string.h
@@ -3571,6 +3591,7 @@ enc/iso_8859_3.$(OBJEXT): internal/intern/re.h
enc/iso_8859_3.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_3.$(OBJEXT): internal/intern/select.h
enc/iso_8859_3.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_3.$(OBJEXT): internal/intern/set.h
enc/iso_8859_3.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_3.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_3.$(OBJEXT): internal/intern/string.h
@@ -3733,6 +3754,7 @@ enc/iso_8859_4.$(OBJEXT): internal/intern/re.h
enc/iso_8859_4.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_4.$(OBJEXT): internal/intern/select.h
enc/iso_8859_4.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_4.$(OBJEXT): internal/intern/set.h
enc/iso_8859_4.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_4.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_4.$(OBJEXT): internal/intern/string.h
@@ -3894,6 +3916,7 @@ enc/iso_8859_5.$(OBJEXT): internal/intern/re.h
enc/iso_8859_5.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_5.$(OBJEXT): internal/intern/select.h
enc/iso_8859_5.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_5.$(OBJEXT): internal/intern/set.h
enc/iso_8859_5.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_5.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_5.$(OBJEXT): internal/intern/string.h
@@ -4055,6 +4078,7 @@ enc/iso_8859_6.$(OBJEXT): internal/intern/re.h
enc/iso_8859_6.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_6.$(OBJEXT): internal/intern/select.h
enc/iso_8859_6.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_6.$(OBJEXT): internal/intern/set.h
enc/iso_8859_6.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_6.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_6.$(OBJEXT): internal/intern/string.h
@@ -4216,6 +4240,7 @@ enc/iso_8859_7.$(OBJEXT): internal/intern/re.h
enc/iso_8859_7.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_7.$(OBJEXT): internal/intern/select.h
enc/iso_8859_7.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_7.$(OBJEXT): internal/intern/set.h
enc/iso_8859_7.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_7.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_7.$(OBJEXT): internal/intern/string.h
@@ -4377,6 +4402,7 @@ enc/iso_8859_8.$(OBJEXT): internal/intern/re.h
enc/iso_8859_8.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_8.$(OBJEXT): internal/intern/select.h
enc/iso_8859_8.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_8.$(OBJEXT): internal/intern/set.h
enc/iso_8859_8.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_8.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_8.$(OBJEXT): internal/intern/string.h
@@ -4539,6 +4565,7 @@ enc/iso_8859_9.$(OBJEXT): internal/intern/re.h
enc/iso_8859_9.$(OBJEXT): internal/intern/ruby.h
enc/iso_8859_9.$(OBJEXT): internal/intern/select.h
enc/iso_8859_9.$(OBJEXT): internal/intern/select/largesize.h
+enc/iso_8859_9.$(OBJEXT): internal/intern/set.h
enc/iso_8859_9.$(OBJEXT): internal/intern/signal.h
enc/iso_8859_9.$(OBJEXT): internal/intern/sprintf.h
enc/iso_8859_9.$(OBJEXT): internal/intern/string.h
@@ -4700,6 +4727,7 @@ enc/koi8_r.$(OBJEXT): internal/intern/re.h
enc/koi8_r.$(OBJEXT): internal/intern/ruby.h
enc/koi8_r.$(OBJEXT): internal/intern/select.h
enc/koi8_r.$(OBJEXT): internal/intern/select/largesize.h
+enc/koi8_r.$(OBJEXT): internal/intern/set.h
enc/koi8_r.$(OBJEXT): internal/intern/signal.h
enc/koi8_r.$(OBJEXT): internal/intern/sprintf.h
enc/koi8_r.$(OBJEXT): internal/intern/string.h
@@ -4861,6 +4889,7 @@ enc/koi8_u.$(OBJEXT): internal/intern/re.h
enc/koi8_u.$(OBJEXT): internal/intern/ruby.h
enc/koi8_u.$(OBJEXT): internal/intern/select.h
enc/koi8_u.$(OBJEXT): internal/intern/select/largesize.h
+enc/koi8_u.$(OBJEXT): internal/intern/set.h
enc/koi8_u.$(OBJEXT): internal/intern/signal.h
enc/koi8_u.$(OBJEXT): internal/intern/sprintf.h
enc/koi8_u.$(OBJEXT): internal/intern/string.h
@@ -5025,6 +5054,7 @@ enc/shift_jis.$(OBJEXT): internal/intern/re.h
enc/shift_jis.$(OBJEXT): internal/intern/ruby.h
enc/shift_jis.$(OBJEXT): internal/intern/select.h
enc/shift_jis.$(OBJEXT): internal/intern/select/largesize.h
+enc/shift_jis.$(OBJEXT): internal/intern/set.h
enc/shift_jis.$(OBJEXT): internal/intern/signal.h
enc/shift_jis.$(OBJEXT): internal/intern/sprintf.h
enc/shift_jis.$(OBJEXT): internal/intern/string.h
@@ -5185,6 +5215,7 @@ enc/trans/big5.$(OBJEXT): internal/intern/re.h
enc/trans/big5.$(OBJEXT): internal/intern/ruby.h
enc/trans/big5.$(OBJEXT): internal/intern/select.h
enc/trans/big5.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/big5.$(OBJEXT): internal/intern/set.h
enc/trans/big5.$(OBJEXT): internal/intern/signal.h
enc/trans/big5.$(OBJEXT): internal/intern/sprintf.h
enc/trans/big5.$(OBJEXT): internal/intern/string.h
@@ -5344,6 +5375,7 @@ enc/trans/cesu_8.$(OBJEXT): internal/intern/re.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/ruby.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/select.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/cesu_8.$(OBJEXT): internal/intern/set.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/signal.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/sprintf.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/string.h
@@ -5503,6 +5535,7 @@ enc/trans/chinese.$(OBJEXT): internal/intern/re.h
enc/trans/chinese.$(OBJEXT): internal/intern/ruby.h
enc/trans/chinese.$(OBJEXT): internal/intern/select.h
enc/trans/chinese.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/chinese.$(OBJEXT): internal/intern/set.h
enc/trans/chinese.$(OBJEXT): internal/intern/signal.h
enc/trans/chinese.$(OBJEXT): internal/intern/sprintf.h
enc/trans/chinese.$(OBJEXT): internal/intern/string.h
@@ -5662,6 +5695,7 @@ enc/trans/ebcdic.$(OBJEXT): internal/intern/re.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/ruby.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/select.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/ebcdic.$(OBJEXT): internal/intern/set.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/signal.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/sprintf.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/string.h
@@ -5821,6 +5855,7 @@ enc/trans/emoji.$(OBJEXT): internal/intern/re.h
enc/trans/emoji.$(OBJEXT): internal/intern/ruby.h
enc/trans/emoji.$(OBJEXT): internal/intern/select.h
enc/trans/emoji.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/emoji.$(OBJEXT): internal/intern/set.h
enc/trans/emoji.$(OBJEXT): internal/intern/signal.h
enc/trans/emoji.$(OBJEXT): internal/intern/sprintf.h
enc/trans/emoji.$(OBJEXT): internal/intern/string.h
@@ -5980,6 +6015,7 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/re.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/ruby.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/select.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/set.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/signal.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/sprintf.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/string.h
@@ -6139,6 +6175,7 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/re.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/ruby.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/select.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/set.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/signal.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/sprintf.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/string.h
@@ -6298,6 +6335,7 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/re.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/ruby.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/select.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/set.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/signal.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/sprintf.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/string.h
@@ -6457,6 +6495,7 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/re.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/ruby.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/select.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/set.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/signal.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/sprintf.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/string.h
@@ -6616,6 +6655,7 @@ enc/trans/escape.$(OBJEXT): internal/intern/re.h
enc/trans/escape.$(OBJEXT): internal/intern/ruby.h
enc/trans/escape.$(OBJEXT): internal/intern/select.h
enc/trans/escape.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/escape.$(OBJEXT): internal/intern/set.h
enc/trans/escape.$(OBJEXT): internal/intern/signal.h
enc/trans/escape.$(OBJEXT): internal/intern/sprintf.h
enc/trans/escape.$(OBJEXT): internal/intern/string.h
@@ -6775,6 +6815,7 @@ enc/trans/gb18030.$(OBJEXT): internal/intern/re.h
enc/trans/gb18030.$(OBJEXT): internal/intern/ruby.h
enc/trans/gb18030.$(OBJEXT): internal/intern/select.h
enc/trans/gb18030.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/gb18030.$(OBJEXT): internal/intern/set.h
enc/trans/gb18030.$(OBJEXT): internal/intern/signal.h
enc/trans/gb18030.$(OBJEXT): internal/intern/sprintf.h
enc/trans/gb18030.$(OBJEXT): internal/intern/string.h
@@ -6934,6 +6975,7 @@ enc/trans/gbk.$(OBJEXT): internal/intern/re.h
enc/trans/gbk.$(OBJEXT): internal/intern/ruby.h
enc/trans/gbk.$(OBJEXT): internal/intern/select.h
enc/trans/gbk.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/gbk.$(OBJEXT): internal/intern/set.h
enc/trans/gbk.$(OBJEXT): internal/intern/signal.h
enc/trans/gbk.$(OBJEXT): internal/intern/sprintf.h
enc/trans/gbk.$(OBJEXT): internal/intern/string.h
@@ -7016,6 +7058,7 @@ enc/trans/iso2022.$(OBJEXT): internal/attr/nodiscard.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noexcept.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noinline.h
enc/trans/iso2022.$(OBJEXT): internal/attr/nonnull.h
+enc/trans/iso2022.$(OBJEXT): internal/attr/nonstring.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noreturn.h
enc/trans/iso2022.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/iso2022.$(OBJEXT): internal/attr/pure.h
@@ -7093,6 +7136,7 @@ enc/trans/iso2022.$(OBJEXT): internal/intern/re.h
enc/trans/iso2022.$(OBJEXT): internal/intern/ruby.h
enc/trans/iso2022.$(OBJEXT): internal/intern/select.h
enc/trans/iso2022.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/iso2022.$(OBJEXT): internal/intern/set.h
enc/trans/iso2022.$(OBJEXT): internal/intern/signal.h
enc/trans/iso2022.$(OBJEXT): internal/intern/sprintf.h
enc/trans/iso2022.$(OBJEXT): internal/intern/string.h
@@ -7252,6 +7296,7 @@ enc/trans/japanese.$(OBJEXT): internal/intern/re.h
enc/trans/japanese.$(OBJEXT): internal/intern/ruby.h
enc/trans/japanese.$(OBJEXT): internal/intern/select.h
enc/trans/japanese.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/japanese.$(OBJEXT): internal/intern/set.h
enc/trans/japanese.$(OBJEXT): internal/intern/signal.h
enc/trans/japanese.$(OBJEXT): internal/intern/sprintf.h
enc/trans/japanese.$(OBJEXT): internal/intern/string.h
@@ -7411,6 +7456,7 @@ enc/trans/japanese_euc.$(OBJEXT): internal/intern/re.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/ruby.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/select.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/japanese_euc.$(OBJEXT): internal/intern/set.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/signal.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/sprintf.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/string.h
@@ -7570,6 +7616,7 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/intern/re.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/ruby.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/select.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/japanese_sjis.$(OBJEXT): internal/intern/set.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/signal.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/sprintf.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/string.h
@@ -7729,6 +7776,7 @@ enc/trans/korean.$(OBJEXT): internal/intern/re.h
enc/trans/korean.$(OBJEXT): internal/intern/ruby.h
enc/trans/korean.$(OBJEXT): internal/intern/select.h
enc/trans/korean.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/korean.$(OBJEXT): internal/intern/set.h
enc/trans/korean.$(OBJEXT): internal/intern/signal.h
enc/trans/korean.$(OBJEXT): internal/intern/sprintf.h
enc/trans/korean.$(OBJEXT): internal/intern/string.h
@@ -7887,6 +7935,7 @@ enc/trans/newline.$(OBJEXT): internal/intern/re.h
enc/trans/newline.$(OBJEXT): internal/intern/ruby.h
enc/trans/newline.$(OBJEXT): internal/intern/select.h
enc/trans/newline.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/newline.$(OBJEXT): internal/intern/set.h
enc/trans/newline.$(OBJEXT): internal/intern/signal.h
enc/trans/newline.$(OBJEXT): internal/intern/sprintf.h
enc/trans/newline.$(OBJEXT): internal/intern/string.h
@@ -8046,6 +8095,7 @@ enc/trans/single_byte.$(OBJEXT): internal/intern/re.h
enc/trans/single_byte.$(OBJEXT): internal/intern/ruby.h
enc/trans/single_byte.$(OBJEXT): internal/intern/select.h
enc/trans/single_byte.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/single_byte.$(OBJEXT): internal/intern/set.h
enc/trans/single_byte.$(OBJEXT): internal/intern/signal.h
enc/trans/single_byte.$(OBJEXT): internal/intern/sprintf.h
enc/trans/single_byte.$(OBJEXT): internal/intern/string.h
@@ -8205,6 +8255,7 @@ enc/trans/transdb.$(OBJEXT): internal/intern/re.h
enc/trans/transdb.$(OBJEXT): internal/intern/ruby.h
enc/trans/transdb.$(OBJEXT): internal/intern/select.h
enc/trans/transdb.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/transdb.$(OBJEXT): internal/intern/set.h
enc/trans/transdb.$(OBJEXT): internal/intern/signal.h
enc/trans/transdb.$(OBJEXT): internal/intern/sprintf.h
enc/trans/transdb.$(OBJEXT): internal/intern/string.h
@@ -8365,6 +8416,7 @@ enc/trans/utf8_mac.$(OBJEXT): internal/intern/re.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/ruby.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/select.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/utf8_mac.$(OBJEXT): internal/intern/set.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/signal.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/sprintf.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/string.h
@@ -8524,6 +8576,7 @@ enc/trans/utf_16_32.$(OBJEXT): internal/intern/re.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/ruby.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/select.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/select/largesize.h
+enc/trans/utf_16_32.$(OBJEXT): internal/intern/set.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/signal.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/sprintf.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/string.h
@@ -8686,6 +8739,7 @@ enc/unicode.$(OBJEXT): internal/intern/re.h
enc/unicode.$(OBJEXT): internal/intern/ruby.h
enc/unicode.$(OBJEXT): internal/intern/select.h
enc/unicode.$(OBJEXT): internal/intern/select/largesize.h
+enc/unicode.$(OBJEXT): internal/intern/set.h
enc/unicode.$(OBJEXT): internal/intern/signal.h
enc/unicode.$(OBJEXT): internal/intern/sprintf.h
enc/unicode.$(OBJEXT): internal/intern/string.h
@@ -8857,6 +8911,7 @@ enc/us_ascii.$(OBJEXT): internal/intern/re.h
enc/us_ascii.$(OBJEXT): internal/intern/ruby.h
enc/us_ascii.$(OBJEXT): internal/intern/select.h
enc/us_ascii.$(OBJEXT): internal/intern/select/largesize.h
+enc/us_ascii.$(OBJEXT): internal/intern/set.h
enc/us_ascii.$(OBJEXT): internal/intern/signal.h
enc/us_ascii.$(OBJEXT): internal/intern/sprintf.h
enc/us_ascii.$(OBJEXT): internal/intern/string.h
@@ -9020,6 +9075,7 @@ enc/utf_16be.$(OBJEXT): internal/intern/re.h
enc/utf_16be.$(OBJEXT): internal/intern/ruby.h
enc/utf_16be.$(OBJEXT): internal/intern/select.h
enc/utf_16be.$(OBJEXT): internal/intern/select/largesize.h
+enc/utf_16be.$(OBJEXT): internal/intern/set.h
enc/utf_16be.$(OBJEXT): internal/intern/signal.h
enc/utf_16be.$(OBJEXT): internal/intern/sprintf.h
enc/utf_16be.$(OBJEXT): internal/intern/string.h
@@ -9182,6 +9238,7 @@ enc/utf_16le.$(OBJEXT): internal/intern/re.h
enc/utf_16le.$(OBJEXT): internal/intern/ruby.h
enc/utf_16le.$(OBJEXT): internal/intern/select.h
enc/utf_16le.$(OBJEXT): internal/intern/select/largesize.h
+enc/utf_16le.$(OBJEXT): internal/intern/set.h
enc/utf_16le.$(OBJEXT): internal/intern/signal.h
enc/utf_16le.$(OBJEXT): internal/intern/sprintf.h
enc/utf_16le.$(OBJEXT): internal/intern/string.h
@@ -9344,6 +9401,7 @@ enc/utf_32be.$(OBJEXT): internal/intern/re.h
enc/utf_32be.$(OBJEXT): internal/intern/ruby.h
enc/utf_32be.$(OBJEXT): internal/intern/select.h
enc/utf_32be.$(OBJEXT): internal/intern/select/largesize.h
+enc/utf_32be.$(OBJEXT): internal/intern/set.h
enc/utf_32be.$(OBJEXT): internal/intern/signal.h
enc/utf_32be.$(OBJEXT): internal/intern/sprintf.h
enc/utf_32be.$(OBJEXT): internal/intern/string.h
@@ -9506,6 +9564,7 @@ enc/utf_32le.$(OBJEXT): internal/intern/re.h
enc/utf_32le.$(OBJEXT): internal/intern/ruby.h
enc/utf_32le.$(OBJEXT): internal/intern/select.h
enc/utf_32le.$(OBJEXT): internal/intern/select/largesize.h
+enc/utf_32le.$(OBJEXT): internal/intern/set.h
enc/utf_32le.$(OBJEXT): internal/intern/signal.h
enc/utf_32le.$(OBJEXT): internal/intern/sprintf.h
enc/utf_32le.$(OBJEXT): internal/intern/string.h
@@ -9677,6 +9736,7 @@ enc/utf_8.$(OBJEXT): internal/intern/re.h
enc/utf_8.$(OBJEXT): internal/intern/ruby.h
enc/utf_8.$(OBJEXT): internal/intern/select.h
enc/utf_8.$(OBJEXT): internal/intern/select/largesize.h
+enc/utf_8.$(OBJEXT): internal/intern/set.h
enc/utf_8.$(OBJEXT): internal/intern/signal.h
enc/utf_8.$(OBJEXT): internal/intern/sprintf.h
enc/utf_8.$(OBJEXT): internal/intern/string.h
@@ -9840,6 +9900,7 @@ enc/windows_1250.$(OBJEXT): internal/intern/re.h
enc/windows_1250.$(OBJEXT): internal/intern/ruby.h
enc/windows_1250.$(OBJEXT): internal/intern/select.h
enc/windows_1250.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_1250.$(OBJEXT): internal/intern/set.h
enc/windows_1250.$(OBJEXT): internal/intern/signal.h
enc/windows_1250.$(OBJEXT): internal/intern/sprintf.h
enc/windows_1250.$(OBJEXT): internal/intern/string.h
@@ -10001,6 +10062,7 @@ enc/windows_1251.$(OBJEXT): internal/intern/re.h
enc/windows_1251.$(OBJEXT): internal/intern/ruby.h
enc/windows_1251.$(OBJEXT): internal/intern/select.h
enc/windows_1251.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_1251.$(OBJEXT): internal/intern/set.h
enc/windows_1251.$(OBJEXT): internal/intern/signal.h
enc/windows_1251.$(OBJEXT): internal/intern/sprintf.h
enc/windows_1251.$(OBJEXT): internal/intern/string.h
@@ -10163,6 +10225,7 @@ enc/windows_1252.$(OBJEXT): internal/intern/re.h
enc/windows_1252.$(OBJEXT): internal/intern/ruby.h
enc/windows_1252.$(OBJEXT): internal/intern/select.h
enc/windows_1252.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_1252.$(OBJEXT): internal/intern/set.h
enc/windows_1252.$(OBJEXT): internal/intern/signal.h
enc/windows_1252.$(OBJEXT): internal/intern/sprintf.h
enc/windows_1252.$(OBJEXT): internal/intern/string.h
@@ -10324,6 +10387,7 @@ enc/windows_1253.$(OBJEXT): internal/intern/re.h
enc/windows_1253.$(OBJEXT): internal/intern/ruby.h
enc/windows_1253.$(OBJEXT): internal/intern/select.h
enc/windows_1253.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_1253.$(OBJEXT): internal/intern/set.h
enc/windows_1253.$(OBJEXT): internal/intern/signal.h
enc/windows_1253.$(OBJEXT): internal/intern/sprintf.h
enc/windows_1253.$(OBJEXT): internal/intern/string.h
@@ -10486,6 +10550,7 @@ enc/windows_1254.$(OBJEXT): internal/intern/re.h
enc/windows_1254.$(OBJEXT): internal/intern/ruby.h
enc/windows_1254.$(OBJEXT): internal/intern/select.h
enc/windows_1254.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_1254.$(OBJEXT): internal/intern/set.h
enc/windows_1254.$(OBJEXT): internal/intern/signal.h
enc/windows_1254.$(OBJEXT): internal/intern/sprintf.h
enc/windows_1254.$(OBJEXT): internal/intern/string.h
@@ -10648,6 +10713,7 @@ enc/windows_1257.$(OBJEXT): internal/intern/re.h
enc/windows_1257.$(OBJEXT): internal/intern/ruby.h
enc/windows_1257.$(OBJEXT): internal/intern/select.h
enc/windows_1257.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_1257.$(OBJEXT): internal/intern/set.h
enc/windows_1257.$(OBJEXT): internal/intern/signal.h
enc/windows_1257.$(OBJEXT): internal/intern/sprintf.h
enc/windows_1257.$(OBJEXT): internal/intern/string.h
@@ -10812,6 +10878,7 @@ enc/windows_31j.$(OBJEXT): internal/intern/re.h
enc/windows_31j.$(OBJEXT): internal/intern/ruby.h
enc/windows_31j.$(OBJEXT): internal/intern/select.h
enc/windows_31j.$(OBJEXT): internal/intern/select/largesize.h
+enc/windows_31j.$(OBJEXT): internal/intern/set.h
enc/windows_31j.$(OBJEXT): internal/intern/signal.h
enc/windows_31j.$(OBJEXT): internal/intern/sprintf.h
enc/windows_31j.$(OBJEXT): internal/intern/string.h
diff --git a/enc/emacs_mule.c b/enc/emacs_mule.c
index f92eb183cf..abd986a187 100644
--- a/enc/emacs_mule.c
+++ b/enc/emacs_mule.c
@@ -334,7 +334,11 @@ OnigEncodingDefine(emacs_mule, Emacs_Mule) = {
onigenc_not_support_get_ctype_code_range,
left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/euc_jp.c b/enc/euc_jp.c
index d283bf4ebb..678d011668 100644
--- a/enc/euc_jp.c
+++ b/enc/euc_jp.c
@@ -576,7 +576,11 @@ OnigEncodingDefine(euc_jp, EUC_JP) = {
get_ctype_code_range,
left_adjust_char_head,
is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/euc_kr.c b/enc/euc_kr.c
index 21d6ab4e1c..4079a0ece0 100644
--- a/enc/euc_kr.c
+++ b/enc/euc_kr.c
@@ -188,7 +188,11 @@ OnigEncodingDefine(euc_kr, EUC_KR) = {
onigenc_not_support_get_ctype_code_range,
euckr_left_adjust_char_head,
euckr_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
@@ -213,7 +217,11 @@ OnigEncodingDefine(euc_cn, EUC_CN) = {
onigenc_not_support_get_ctype_code_range,
euckr_left_adjust_char_head,
euckr_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/euc_tw.c b/enc/euc_tw.c
index 1c5659cb1d..722e29a9da 100644
--- a/enc/euc_tw.c
+++ b/enc/euc_tw.c
@@ -221,7 +221,11 @@ OnigEncodingDefine(euc_tw, EUC_TW) = {
onigenc_not_support_get_ctype_code_range,
euctw_left_adjust_char_head,
euctw_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/gb18030.c b/enc/gb18030.c
index 63d2e633ec..316737db11 100644
--- a/enc/gb18030.c
+++ b/enc/gb18030.c
@@ -597,7 +597,11 @@ OnigEncodingDefine(gb18030, GB18030) = {
onigenc_not_support_get_ctype_code_range,
gb18030_left_adjust_char_head,
gb18030_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/gbk.c b/enc/gbk.c
index 31032553bf..3df4e4b6d6 100644
--- a/enc/gbk.c
+++ b/enc/gbk.c
@@ -211,7 +211,11 @@ OnigEncodingDefine(gbk, GBK) = {
onigenc_not_support_get_ctype_code_range,
gbk_left_adjust_char_head,
gbk_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_1.c b/enc/iso_8859_1.c
index 7af0888c3e..78ea1fba60 100644
--- a/enc/iso_8859_1.c
+++ b/enc/iso_8859_1.c
@@ -255,6 +255,7 @@ is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc ARG_UNUSE
return FALSE;
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -297,6 +298,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_1, ISO_8859_1) = {
onigenc_single_byte_mbc_enc_len,
@@ -315,7 +317,11 @@ OnigEncodingDefine(iso_8859_1, ISO_8859_1) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_10.c b/enc/iso_8859_10.c
index cae4be2db0..bf1c884cb2 100644
--- a/enc/iso_8859_10.c
+++ b/enc/iso_8859_10.c
@@ -224,6 +224,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -269,6 +270,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_10, ISO_8859_10) = {
onigenc_single_byte_mbc_enc_len,
@@ -287,7 +289,11 @@ OnigEncodingDefine(iso_8859_10, ISO_8859_10) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_11.c b/enc/iso_8859_11.c
index b9c6119fd9..403ae6499e 100644
--- a/enc/iso_8859_11.c
+++ b/enc/iso_8859_11.c
@@ -93,7 +93,11 @@ OnigEncodingDefine(iso_8859_11, ISO_8859_11) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_13.c b/enc/iso_8859_13.c
index fe1ddd7065..8c6e758b80 100644
--- a/enc/iso_8859_13.c
+++ b/enc/iso_8859_13.c
@@ -217,6 +217,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -264,6 +265,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_13, ISO_8859_13) = {
onigenc_single_byte_mbc_enc_len,
@@ -282,7 +284,11 @@ OnigEncodingDefine(iso_8859_13, ISO_8859_13) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_14.c b/enc/iso_8859_14.c
index 647514a016..21dffea76f 100644
--- a/enc/iso_8859_14.c
+++ b/enc/iso_8859_14.c
@@ -226,6 +226,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -280,6 +281,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_14, ISO_8859_14) = {
onigenc_single_byte_mbc_enc_len,
@@ -298,7 +300,11 @@ OnigEncodingDefine(iso_8859_14, ISO_8859_14) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_15.c b/enc/iso_8859_15.c
index 377a3afc7b..dd6c29a643 100644
--- a/enc/iso_8859_15.c
+++ b/enc/iso_8859_15.c
@@ -220,6 +220,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -271,6 +272,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_15, ISO_8859_15) = {
onigenc_single_byte_mbc_enc_len,
@@ -289,7 +291,11 @@ OnigEncodingDefine(iso_8859_15, ISO_8859_15) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_16.c b/enc/iso_8859_16.c
index 135630eb73..aa7ce99fba 100644
--- a/enc/iso_8859_16.c
+++ b/enc/iso_8859_16.c
@@ -222,6 +222,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -275,6 +276,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_16, ISO_8859_16) = {
onigenc_single_byte_mbc_enc_len,
@@ -293,7 +295,11 @@ OnigEncodingDefine(iso_8859_16, ISO_8859_16) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_2.c b/enc/iso_8859_2.c
index 3a05c6320d..859073fd14 100644
--- a/enc/iso_8859_2.c
+++ b/enc/iso_8859_2.c
@@ -220,6 +220,7 @@ is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc ARG_UNUSE
return FALSE;
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -266,6 +267,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_2, ISO_8859_2) = {
onigenc_single_byte_mbc_enc_len,
@@ -284,7 +286,11 @@ OnigEncodingDefine(iso_8859_2, ISO_8859_2) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_3.c b/enc/iso_8859_3.c
index 2a343eac63..d8199d5125 100644
--- a/enc/iso_8859_3.c
+++ b/enc/iso_8859_3.c
@@ -220,6 +220,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xB9)
#define I_WITH_DOT_ABOVE (0xA9)
static int
@@ -276,6 +277,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_3, ISO_8859_3) = {
onigenc_single_byte_mbc_enc_len,
@@ -294,7 +296,11 @@ OnigEncodingDefine(iso_8859_3, ISO_8859_3) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_4.c b/enc/iso_8859_4.c
index e2134e8c0b..5f01f01575 100644
--- a/enc/iso_8859_4.c
+++ b/enc/iso_8859_4.c
@@ -223,6 +223,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -272,6 +273,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_4, ISO_8859_4) = {
onigenc_single_byte_mbc_enc_len,
@@ -290,7 +292,11 @@ OnigEncodingDefine(iso_8859_4, ISO_8859_4) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_5.c b/enc/iso_8859_5.c
index 6fafc35823..8223fc0ec7 100644
--- a/enc/iso_8859_5.c
+++ b/enc/iso_8859_5.c
@@ -209,6 +209,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -240,6 +241,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_5, ISO_8859_5) = {
onigenc_single_byte_mbc_enc_len,
@@ -258,7 +260,11 @@ OnigEncodingDefine(iso_8859_5, ISO_8859_5) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_6.c b/enc/iso_8859_6.c
index cdb74054d1..78543ea307 100644
--- a/enc/iso_8859_6.c
+++ b/enc/iso_8859_6.c
@@ -93,7 +93,11 @@ OnigEncodingDefine(iso_8859_6, ISO_8859_6) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_7.c b/enc/iso_8859_7.c
index ac973f74ba..e84f5c3460 100644
--- a/enc/iso_8859_7.c
+++ b/enc/iso_8859_7.c
@@ -205,6 +205,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -259,6 +260,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_7, ISO_8859_7) = {
onigenc_single_byte_mbc_enc_len,
@@ -277,7 +279,11 @@ OnigEncodingDefine(iso_8859_7, ISO_8859_7) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_8.c b/enc/iso_8859_8.c
index e256855f21..b757a283de 100644
--- a/enc/iso_8859_8.c
+++ b/enc/iso_8859_8.c
@@ -93,7 +93,11 @@ OnigEncodingDefine(iso_8859_8, ISO_8859_8) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/iso_8859_9.c b/enc/iso_8859_9.c
index 004eec310f..f15953963b 100644
--- a/enc/iso_8859_9.c
+++ b/enc/iso_8859_9.c
@@ -213,6 +213,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xFD)
#define I_WITH_DOT_ABOVE (0xDD)
static int
@@ -265,6 +266,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(iso_8859_9, ISO_8859_9) = {
onigenc_single_byte_mbc_enc_len,
@@ -283,7 +285,11 @@ OnigEncodingDefine(iso_8859_9, ISO_8859_9) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/koi8_r.c b/enc/koi8_r.c
index a520975774..39f2482465 100644
--- a/enc/koi8_r.c
+++ b/enc/koi8_r.c
@@ -214,7 +214,11 @@ OnigEncodingDefine(koi8_r, KOI8_R) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/koi8_u.c b/enc/koi8_u.c
index 50bb78bd04..8cd890dd16 100644
--- a/enc/koi8_u.c
+++ b/enc/koi8_u.c
@@ -218,7 +218,11 @@ OnigEncodingDefine(koi8_u, KOI8_U) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/make_encmake.rb b/enc/make_encmake.rb
index 96d1944bcb..e5ed4eb4b5 100755
--- a/enc/make_encmake.rb
+++ b/enc/make_encmake.rb
@@ -1,8 +1,11 @@
#! ./miniruby
dir = File.expand_path("../..", __FILE__)
-$:.unshift(dir)
-$:.unshift(".")
+# The source lib directory provides the standard library for miniruby.
+# Don't add it when running with baseruby to avoid loading both
+# baseruby's cgi/escape.so and source cgi/escape.rb via erb.
+$:.unshift("#{dir}/lib") unless defined?(CROSS_COMPILING)
+$:.unshift(Dir.pwd, "#{dir}/tool/lib")
if $".grep(/mkmf/).empty?
$" << "mkmf.rb"
load File.expand_path("lib/mkmf.rb", dir)
@@ -147,6 +150,6 @@ if MODULE_TYPE == :static
Dir.mkdir 'enc'
rescue Errno::EEXIST
end
- require 'tool/lib/output'
+ require 'output'
Output.new(path: "enc/encinit.c", ifchange: true).write(tmp)
end
diff --git a/enc/shift_jis.c b/enc/shift_jis.c
index f1355d2d95..48f648868a 100644
--- a/enc/shift_jis.c
+++ b/enc/shift_jis.c
@@ -47,7 +47,11 @@ OnigEncodingDefine(shift_jis, Shift_JIS) = {
get_ctype_code_range,
left_adjust_char_head,
is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/trans/iso2022.trans b/enc/trans/iso2022.trans
index a25a4a12a1..bc42bbc19c 100644
--- a/enc/trans/iso2022.trans
+++ b/enc/trans/iso2022.trans
@@ -1,4 +1,5 @@
#include "transcode_data.h"
+#include "ruby/internal/attr/nonstring.h"
<%
map = {
@@ -436,7 +437,7 @@ rb_cp50221_encoder = {
/* JIS0201 to JIS0208 conversion table */
enum {tbl0208_num = 0xDF - 0xA1 + 1};
-static const char tbl0208[tbl0208_num][2] = {
+RBIMPL_ATTR_NONSTRING_ARRAY() static const char tbl0208[tbl0208_num][2] = {
"\x21\x23", "\x21\x56", "\x21\x57", "\x21\x22",
"\x21\x26", "\x25\x72", "\x25\x21", "\x25\x23",
"\x25\x25", "\x25\x27", "\x25\x29", "\x25\x63",
diff --git a/enc/unicode.c b/enc/unicode.c
index 18fba02476..5bc806863e 100644
--- a/enc/unicode.c
+++ b/enc/unicode.c
@@ -655,6 +655,7 @@ onigenc_unicode_get_case_fold_codes_by_str(OnigEncoding enc,
return n;
}
+#ifdef USE_CASE_MAP_API
/* length in bytes for three characters in UTF-32; e.g. needed for ffi (U+FB03) */
#define CASE_MAPPING_SLACK 12
#define MODIFIED (flags |= ONIGENC_CASE_MODIFIED)
@@ -682,15 +683,13 @@ onigenc_unicode_case_map(OnigCaseFoldType* flagP,
*pp += codepoint_length;
if (code <= 'z') { /* ASCII comes first */
- if (code >= 'a' && code <= 'z') {
+ if (code >= 'a' /*&& code <= 'z'*/) {
if (flags & ONIGENC_CASE_UPCASE) {
MODIFIED;
if (flags & ONIGENC_CASE_FOLD_TURKISH_AZERI && code == 'i')
code = I_WITH_DOT_ABOVE;
- else {
- code -= 'a';
- code += 'A';
- }
+ else
+ code -= 'a' - 'A';
}
}
else if (code >= 'A' && code <= 'Z') {
@@ -800,8 +799,8 @@ SpecialsCopy:
*flagP = flags;
return (int )(to - to_start);
}
+#endif
-#if 0
const char onigenc_unicode_version_string[] =
#ifdef ONIG_UNICODE_VERSION_STRING
ONIG_UNICODE_VERSION_STRING
@@ -817,4 +816,3 @@ const int onigenc_unicode_version_number[3] = {
0
#endif
};
-#endif
diff --git a/enc/unicode/15.1.0/casefold.h b/enc/unicode/15.1.0/casefold.h
deleted file mode 100644
index 03caace48c..0000000000
--- a/enc/unicode/15.1.0/casefold.h
+++ /dev/null
@@ -1,7629 +0,0 @@
-/* DO NOT EDIT THIS FILE. */
-/* Generated by enc-case-folding.rb */
-
-#if defined ONIG_UNICODE_VERSION_STRING && !( \
- ONIG_UNICODE_VERSION_MAJOR == 15 && \
- ONIG_UNICODE_VERSION_MINOR == 1 && \
- ONIG_UNICODE_VERSION_TEENY == 0 && \
- 1)
-# error ONIG_UNICODE_VERSION_STRING mismatch
-#endif
-#define ONIG_UNICODE_VERSION_STRING "15.1.0"
-#define ONIG_UNICODE_VERSION_MAJOR 15
-#define ONIG_UNICODE_VERSION_MINOR 1
-#define ONIG_UNICODE_VERSION_TEENY 0
-
-static const CaseFold_11_Type CaseFold_11_Table[] = {
-#define CaseFold (*(CaseFold_11_Type (*)[1528])(CaseFold_11_Table+0))
- {0x0041, {1|F|D, {0x0061}}},
- {0x0042, {1|F|D, {0x0062}}},
- {0x0043, {1|F|D, {0x0063}}},
- {0x0044, {1|F|D, {0x0064}}},
- {0x0045, {1|F|D, {0x0065}}},
- {0x0046, {1|F|D, {0x0066}}},
- {0x0047, {1|F|D, {0x0067}}},
- {0x0048, {1|F|D, {0x0068}}},
- {0x004a, {1|F|D, {0x006a}}},
- {0x004b, {1|F|D, {0x006b}}},
- {0x004c, {1|F|D, {0x006c}}},
- {0x004d, {1|F|D, {0x006d}}},
- {0x004e, {1|F|D, {0x006e}}},
- {0x004f, {1|F|D, {0x006f}}},
- {0x0050, {1|F|D, {0x0070}}},
- {0x0051, {1|F|D, {0x0071}}},
- {0x0052, {1|F|D, {0x0072}}},
- {0x0053, {1|F|D, {0x0073}}},
- {0x0054, {1|F|D, {0x0074}}},
- {0x0055, {1|F|D, {0x0075}}},
- {0x0056, {1|F|D, {0x0076}}},
- {0x0057, {1|F|D, {0x0077}}},
- {0x0058, {1|F|D, {0x0078}}},
- {0x0059, {1|F|D, {0x0079}}},
- {0x005a, {1|F|D, {0x007a}}},
- {0x00b5, {1|F|SU|I(0), {0x03bc}}},
- {0x00c0, {1|F|D, {0x00e0}}},
- {0x00c1, {1|F|D, {0x00e1}}},
- {0x00c2, {1|F|D, {0x00e2}}},
- {0x00c3, {1|F|D, {0x00e3}}},
- {0x00c4, {1|F|D, {0x00e4}}},
- {0x00c5, {1|F|D, {0x00e5}}},
- {0x00c6, {1|F|D, {0x00e6}}},
- {0x00c7, {1|F|D, {0x00e7}}},
- {0x00c8, {1|F|D, {0x00e8}}},
- {0x00c9, {1|F|D, {0x00e9}}},
- {0x00ca, {1|F|D, {0x00ea}}},
- {0x00cb, {1|F|D, {0x00eb}}},
- {0x00cc, {1|F|D, {0x00ec}}},
- {0x00cd, {1|F|D, {0x00ed}}},
- {0x00ce, {1|F|D, {0x00ee}}},
- {0x00cf, {1|F|D, {0x00ef}}},
- {0x00d0, {1|F|D, {0x00f0}}},
- {0x00d1, {1|F|D, {0x00f1}}},
- {0x00d2, {1|F|D, {0x00f2}}},
- {0x00d3, {1|F|D, {0x00f3}}},
- {0x00d4, {1|F|D, {0x00f4}}},
- {0x00d5, {1|F|D, {0x00f5}}},
- {0x00d6, {1|F|D, {0x00f6}}},
- {0x00d8, {1|F|D, {0x00f8}}},
- {0x00d9, {1|F|D, {0x00f9}}},
- {0x00da, {1|F|D, {0x00fa}}},
- {0x00db, {1|F|D, {0x00fb}}},
- {0x00dc, {1|F|D, {0x00fc}}},
- {0x00dd, {1|F|D, {0x00fd}}},
- {0x00de, {1|F|D, {0x00fe}}},
- {0x00df, {2|F|ST|SU|I(1), {0x0073, 0x0073}}},
- {0x0100, {1|F|D, {0x0101}}},
- {0x0102, {1|F|D, {0x0103}}},
- {0x0104, {1|F|D, {0x0105}}},
- {0x0106, {1|F|D, {0x0107}}},
- {0x0108, {1|F|D, {0x0109}}},
- {0x010a, {1|F|D, {0x010b}}},
- {0x010c, {1|F|D, {0x010d}}},
- {0x010e, {1|F|D, {0x010f}}},
- {0x0110, {1|F|D, {0x0111}}},
- {0x0112, {1|F|D, {0x0113}}},
- {0x0114, {1|F|D, {0x0115}}},
- {0x0116, {1|F|D, {0x0117}}},
- {0x0118, {1|F|D, {0x0119}}},
- {0x011a, {1|F|D, {0x011b}}},
- {0x011c, {1|F|D, {0x011d}}},
- {0x011e, {1|F|D, {0x011f}}},
- {0x0120, {1|F|D, {0x0121}}},
- {0x0122, {1|F|D, {0x0123}}},
- {0x0124, {1|F|D, {0x0125}}},
- {0x0126, {1|F|D, {0x0127}}},
- {0x0128, {1|F|D, {0x0129}}},
- {0x012a, {1|F|D, {0x012b}}},
- {0x012c, {1|F|D, {0x012d}}},
- {0x012e, {1|F|D, {0x012f}}},
- {0x0132, {1|F|D, {0x0133}}},
- {0x0134, {1|F|D, {0x0135}}},
- {0x0136, {1|F|D, {0x0137}}},
- {0x0139, {1|F|D, {0x013a}}},
- {0x013b, {1|F|D, {0x013c}}},
- {0x013d, {1|F|D, {0x013e}}},
- {0x013f, {1|F|D, {0x0140}}},
- {0x0141, {1|F|D, {0x0142}}},
- {0x0143, {1|F|D, {0x0144}}},
- {0x0145, {1|F|D, {0x0146}}},
- {0x0147, {1|F|D, {0x0148}}},
- {0x0149, {2|F|SU|I(5), {0x02bc, 0x006e}}},
- {0x014a, {1|F|D, {0x014b}}},
- {0x014c, {1|F|D, {0x014d}}},
- {0x014e, {1|F|D, {0x014f}}},
- {0x0150, {1|F|D, {0x0151}}},
- {0x0152, {1|F|D, {0x0153}}},
- {0x0154, {1|F|D, {0x0155}}},
- {0x0156, {1|F|D, {0x0157}}},
- {0x0158, {1|F|D, {0x0159}}},
- {0x015a, {1|F|D, {0x015b}}},
- {0x015c, {1|F|D, {0x015d}}},
- {0x015e, {1|F|D, {0x015f}}},
- {0x0160, {1|F|D, {0x0161}}},
- {0x0162, {1|F|D, {0x0163}}},
- {0x0164, {1|F|D, {0x0165}}},
- {0x0166, {1|F|D, {0x0167}}},
- {0x0168, {1|F|D, {0x0169}}},
- {0x016a, {1|F|D, {0x016b}}},
- {0x016c, {1|F|D, {0x016d}}},
- {0x016e, {1|F|D, {0x016f}}},
- {0x0170, {1|F|D, {0x0171}}},
- {0x0172, {1|F|D, {0x0173}}},
- {0x0174, {1|F|D, {0x0175}}},
- {0x0176, {1|F|D, {0x0177}}},
- {0x0178, {1|F|D, {0x00ff}}},
- {0x0179, {1|F|D, {0x017a}}},
- {0x017b, {1|F|D, {0x017c}}},
- {0x017d, {1|F|D, {0x017e}}},
- {0x017f, {1|F|SU|I(7), {0x0073}}},
- {0x0181, {1|F|D, {0x0253}}},
- {0x0182, {1|F|D, {0x0183}}},
- {0x0184, {1|F|D, {0x0185}}},
- {0x0186, {1|F|D, {0x0254}}},
- {0x0187, {1|F|D, {0x0188}}},
- {0x0189, {1|F|D, {0x0256}}},
- {0x018a, {1|F|D, {0x0257}}},
- {0x018b, {1|F|D, {0x018c}}},
- {0x018e, {1|F|D, {0x01dd}}},
- {0x018f, {1|F|D, {0x0259}}},
- {0x0190, {1|F|D, {0x025b}}},
- {0x0191, {1|F|D, {0x0192}}},
- {0x0193, {1|F|D, {0x0260}}},
- {0x0194, {1|F|D, {0x0263}}},
- {0x0196, {1|F|D, {0x0269}}},
- {0x0197, {1|F|D, {0x0268}}},
- {0x0198, {1|F|D, {0x0199}}},
- {0x019c, {1|F|D, {0x026f}}},
- {0x019d, {1|F|D, {0x0272}}},
- {0x019f, {1|F|D, {0x0275}}},
- {0x01a0, {1|F|D, {0x01a1}}},
- {0x01a2, {1|F|D, {0x01a3}}},
- {0x01a4, {1|F|D, {0x01a5}}},
- {0x01a6, {1|F|D, {0x0280}}},
- {0x01a7, {1|F|D, {0x01a8}}},
- {0x01a9, {1|F|D, {0x0283}}},
- {0x01ac, {1|F|D, {0x01ad}}},
- {0x01ae, {1|F|D, {0x0288}}},
- {0x01af, {1|F|D, {0x01b0}}},
- {0x01b1, {1|F|D, {0x028a}}},
- {0x01b2, {1|F|D, {0x028b}}},
- {0x01b3, {1|F|D, {0x01b4}}},
- {0x01b5, {1|F|D, {0x01b6}}},
- {0x01b7, {1|F|D, {0x0292}}},
- {0x01b8, {1|F|D, {0x01b9}}},
- {0x01bc, {1|F|D, {0x01bd}}},
- {0x01c4, {1|F|D|ST|I(8), {0x01c6}}},
- {0x01c5, {1|F|D|IT|SU|I(9), {0x01c6}}},
- {0x01c7, {1|F|D|ST|I(12), {0x01c9}}},
- {0x01c8, {1|F|D|IT|SU|I(13), {0x01c9}}},
- {0x01ca, {1|F|D|ST|I(16), {0x01cc}}},
- {0x01cb, {1|F|D|IT|SU|I(17), {0x01cc}}},
- {0x01cd, {1|F|D, {0x01ce}}},
- {0x01cf, {1|F|D, {0x01d0}}},
- {0x01d1, {1|F|D, {0x01d2}}},
- {0x01d3, {1|F|D, {0x01d4}}},
- {0x01d5, {1|F|D, {0x01d6}}},
- {0x01d7, {1|F|D, {0x01d8}}},
- {0x01d9, {1|F|D, {0x01da}}},
- {0x01db, {1|F|D, {0x01dc}}},
- {0x01de, {1|F|D, {0x01df}}},
- {0x01e0, {1|F|D, {0x01e1}}},
- {0x01e2, {1|F|D, {0x01e3}}},
- {0x01e4, {1|F|D, {0x01e5}}},
- {0x01e6, {1|F|D, {0x01e7}}},
- {0x01e8, {1|F|D, {0x01e9}}},
- {0x01ea, {1|F|D, {0x01eb}}},
- {0x01ec, {1|F|D, {0x01ed}}},
- {0x01ee, {1|F|D, {0x01ef}}},
- {0x01f0, {2|F|SU|I(20), {0x006a, 0x030c}}},
- {0x01f1, {1|F|D|ST|I(22), {0x01f3}}},
- {0x01f2, {1|F|D|IT|SU|I(23), {0x01f3}}},
- {0x01f4, {1|F|D, {0x01f5}}},
- {0x01f6, {1|F|D, {0x0195}}},
- {0x01f7, {1|F|D, {0x01bf}}},
- {0x01f8, {1|F|D, {0x01f9}}},
- {0x01fa, {1|F|D, {0x01fb}}},
- {0x01fc, {1|F|D, {0x01fd}}},
- {0x01fe, {1|F|D, {0x01ff}}},
- {0x0200, {1|F|D, {0x0201}}},
- {0x0202, {1|F|D, {0x0203}}},
- {0x0204, {1|F|D, {0x0205}}},
- {0x0206, {1|F|D, {0x0207}}},
- {0x0208, {1|F|D, {0x0209}}},
- {0x020a, {1|F|D, {0x020b}}},
- {0x020c, {1|F|D, {0x020d}}},
- {0x020e, {1|F|D, {0x020f}}},
- {0x0210, {1|F|D, {0x0211}}},
- {0x0212, {1|F|D, {0x0213}}},
- {0x0214, {1|F|D, {0x0215}}},
- {0x0216, {1|F|D, {0x0217}}},
- {0x0218, {1|F|D, {0x0219}}},
- {0x021a, {1|F|D, {0x021b}}},
- {0x021c, {1|F|D, {0x021d}}},
- {0x021e, {1|F|D, {0x021f}}},
- {0x0220, {1|F|D, {0x019e}}},
- {0x0222, {1|F|D, {0x0223}}},
- {0x0224, {1|F|D, {0x0225}}},
- {0x0226, {1|F|D, {0x0227}}},
- {0x0228, {1|F|D, {0x0229}}},
- {0x022a, {1|F|D, {0x022b}}},
- {0x022c, {1|F|D, {0x022d}}},
- {0x022e, {1|F|D, {0x022f}}},
- {0x0230, {1|F|D, {0x0231}}},
- {0x0232, {1|F|D, {0x0233}}},
- {0x023a, {1|F|D, {0x2c65}}},
- {0x023b, {1|F|D, {0x023c}}},
- {0x023d, {1|F|D, {0x019a}}},
- {0x023e, {1|F|D, {0x2c66}}},
- {0x0241, {1|F|D, {0x0242}}},
- {0x0243, {1|F|D, {0x0180}}},
- {0x0244, {1|F|D, {0x0289}}},
- {0x0245, {1|F|D, {0x028c}}},
- {0x0246, {1|F|D, {0x0247}}},
- {0x0248, {1|F|D, {0x0249}}},
- {0x024a, {1|F|D, {0x024b}}},
- {0x024c, {1|F|D, {0x024d}}},
- {0x024e, {1|F|D, {0x024f}}},
- {0x0345, {1|F|SU|I(26), {0x03b9}}},
- {0x0370, {1|F|D, {0x0371}}},
- {0x0372, {1|F|D, {0x0373}}},
- {0x0376, {1|F|D, {0x0377}}},
- {0x037f, {1|F|D, {0x03f3}}},
- {0x0386, {1|F|D, {0x03ac}}},
- {0x0388, {1|F|D, {0x03ad}}},
- {0x0389, {1|F|D, {0x03ae}}},
- {0x038a, {1|F|D, {0x03af}}},
- {0x038c, {1|F|D, {0x03cc}}},
- {0x038e, {1|F|D, {0x03cd}}},
- {0x038f, {1|F|D, {0x03ce}}},
- {0x0390, {3|F|SU|I(27), {0x03b9, 0x0308, 0x0301}}},
- {0x0391, {1|F|D, {0x03b1}}},
- {0x0392, {1|F|D, {0x03b2}}},
- {0x0393, {1|F|D, {0x03b3}}},
- {0x0394, {1|F|D, {0x03b4}}},
- {0x0395, {1|F|D, {0x03b5}}},
- {0x0396, {1|F|D, {0x03b6}}},
- {0x0397, {1|F|D, {0x03b7}}},
- {0x0398, {1|F|D, {0x03b8}}},
- {0x0399, {1|F|D, {0x03b9}}},
- {0x039a, {1|F|D, {0x03ba}}},
- {0x039b, {1|F|D, {0x03bb}}},
- {0x039c, {1|F|D, {0x03bc}}},
- {0x039d, {1|F|D, {0x03bd}}},
- {0x039e, {1|F|D, {0x03be}}},
- {0x039f, {1|F|D, {0x03bf}}},
- {0x03a0, {1|F|D, {0x03c0}}},
- {0x03a1, {1|F|D, {0x03c1}}},
- {0x03a3, {1|F|D, {0x03c3}}},
- {0x03a4, {1|F|D, {0x03c4}}},
- {0x03a5, {1|F|D, {0x03c5}}},
- {0x03a6, {1|F|D, {0x03c6}}},
- {0x03a7, {1|F|D, {0x03c7}}},
- {0x03a8, {1|F|D, {0x03c8}}},
- {0x03a9, {1|F|D, {0x03c9}}},
- {0x03aa, {1|F|D, {0x03ca}}},
- {0x03ab, {1|F|D, {0x03cb}}},
- {0x03b0, {3|F|SU|I(30), {0x03c5, 0x0308, 0x0301}}},
- {0x03c2, {1|F|SU|I(33), {0x03c3}}},
- {0x03cf, {1|F|D, {0x03d7}}},
- {0x03d0, {1|F|SU|I(34), {0x03b2}}},
- {0x03d1, {1|F|SU|I(35), {0x03b8}}},
- {0x03d5, {1|F|SU|I(36), {0x03c6}}},
- {0x03d6, {1|F|SU|I(37), {0x03c0}}},
- {0x03d8, {1|F|D, {0x03d9}}},
- {0x03da, {1|F|D, {0x03db}}},
- {0x03dc, {1|F|D, {0x03dd}}},
- {0x03de, {1|F|D, {0x03df}}},
- {0x03e0, {1|F|D, {0x03e1}}},
- {0x03e2, {1|F|D, {0x03e3}}},
- {0x03e4, {1|F|D, {0x03e5}}},
- {0x03e6, {1|F|D, {0x03e7}}},
- {0x03e8, {1|F|D, {0x03e9}}},
- {0x03ea, {1|F|D, {0x03eb}}},
- {0x03ec, {1|F|D, {0x03ed}}},
- {0x03ee, {1|F|D, {0x03ef}}},
- {0x03f0, {1|F|SU|I(38), {0x03ba}}},
- {0x03f1, {1|F|SU|I(39), {0x03c1}}},
- {0x03f4, {1|F|D, {0x03b8}}},
- {0x03f5, {1|F|SU|I(40), {0x03b5}}},
- {0x03f7, {1|F|D, {0x03f8}}},
- {0x03f9, {1|F|D, {0x03f2}}},
- {0x03fa, {1|F|D, {0x03fb}}},
- {0x03fd, {1|F|D, {0x037b}}},
- {0x03fe, {1|F|D, {0x037c}}},
- {0x03ff, {1|F|D, {0x037d}}},
- {0x0400, {1|F|D, {0x0450}}},
- {0x0401, {1|F|D, {0x0451}}},
- {0x0402, {1|F|D, {0x0452}}},
- {0x0403, {1|F|D, {0x0453}}},
- {0x0404, {1|F|D, {0x0454}}},
- {0x0405, {1|F|D, {0x0455}}},
- {0x0406, {1|F|D, {0x0456}}},
- {0x0407, {1|F|D, {0x0457}}},
- {0x0408, {1|F|D, {0x0458}}},
- {0x0409, {1|F|D, {0x0459}}},
- {0x040a, {1|F|D, {0x045a}}},
- {0x040b, {1|F|D, {0x045b}}},
- {0x040c, {1|F|D, {0x045c}}},
- {0x040d, {1|F|D, {0x045d}}},
- {0x040e, {1|F|D, {0x045e}}},
- {0x040f, {1|F|D, {0x045f}}},
- {0x0410, {1|F|D, {0x0430}}},
- {0x0411, {1|F|D, {0x0431}}},
- {0x0412, {1|F|D, {0x0432}}},
- {0x0413, {1|F|D, {0x0433}}},
- {0x0414, {1|F|D, {0x0434}}},
- {0x0415, {1|F|D, {0x0435}}},
- {0x0416, {1|F|D, {0x0436}}},
- {0x0417, {1|F|D, {0x0437}}},
- {0x0418, {1|F|D, {0x0438}}},
- {0x0419, {1|F|D, {0x0439}}},
- {0x041a, {1|F|D, {0x043a}}},
- {0x041b, {1|F|D, {0x043b}}},
- {0x041c, {1|F|D, {0x043c}}},
- {0x041d, {1|F|D, {0x043d}}},
- {0x041e, {1|F|D, {0x043e}}},
- {0x041f, {1|F|D, {0x043f}}},
- {0x0420, {1|F|D, {0x0440}}},
- {0x0421, {1|F|D, {0x0441}}},
- {0x0422, {1|F|D, {0x0442}}},
- {0x0423, {1|F|D, {0x0443}}},
- {0x0424, {1|F|D, {0x0444}}},
- {0x0425, {1|F|D, {0x0445}}},
- {0x0426, {1|F|D, {0x0446}}},
- {0x0427, {1|F|D, {0x0447}}},
- {0x0428, {1|F|D, {0x0448}}},
- {0x0429, {1|F|D, {0x0449}}},
- {0x042a, {1|F|D, {0x044a}}},
- {0x042b, {1|F|D, {0x044b}}},
- {0x042c, {1|F|D, {0x044c}}},
- {0x042d, {1|F|D, {0x044d}}},
- {0x042e, {1|F|D, {0x044e}}},
- {0x042f, {1|F|D, {0x044f}}},
- {0x0460, {1|F|D, {0x0461}}},
- {0x0462, {1|F|D, {0x0463}}},
- {0x0464, {1|F|D, {0x0465}}},
- {0x0466, {1|F|D, {0x0467}}},
- {0x0468, {1|F|D, {0x0469}}},
- {0x046a, {1|F|D, {0x046b}}},
- {0x046c, {1|F|D, {0x046d}}},
- {0x046e, {1|F|D, {0x046f}}},
- {0x0470, {1|F|D, {0x0471}}},
- {0x0472, {1|F|D, {0x0473}}},
- {0x0474, {1|F|D, {0x0475}}},
- {0x0476, {1|F|D, {0x0477}}},
- {0x0478, {1|F|D, {0x0479}}},
- {0x047a, {1|F|D, {0x047b}}},
- {0x047c, {1|F|D, {0x047d}}},
- {0x047e, {1|F|D, {0x047f}}},
- {0x0480, {1|F|D, {0x0481}}},
- {0x048a, {1|F|D, {0x048b}}},
- {0x048c, {1|F|D, {0x048d}}},
- {0x048e, {1|F|D, {0x048f}}},
- {0x0490, {1|F|D, {0x0491}}},
- {0x0492, {1|F|D, {0x0493}}},
- {0x0494, {1|F|D, {0x0495}}},
- {0x0496, {1|F|D, {0x0497}}},
- {0x0498, {1|F|D, {0x0499}}},
- {0x049a, {1|F|D, {0x049b}}},
- {0x049c, {1|F|D, {0x049d}}},
- {0x049e, {1|F|D, {0x049f}}},
- {0x04a0, {1|F|D, {0x04a1}}},
- {0x04a2, {1|F|D, {0x04a3}}},
- {0x04a4, {1|F|D, {0x04a5}}},
- {0x04a6, {1|F|D, {0x04a7}}},
- {0x04a8, {1|F|D, {0x04a9}}},
- {0x04aa, {1|F|D, {0x04ab}}},
- {0x04ac, {1|F|D, {0x04ad}}},
- {0x04ae, {1|F|D, {0x04af}}},
- {0x04b0, {1|F|D, {0x04b1}}},
- {0x04b2, {1|F|D, {0x04b3}}},
- {0x04b4, {1|F|D, {0x04b5}}},
- {0x04b6, {1|F|D, {0x04b7}}},
- {0x04b8, {1|F|D, {0x04b9}}},
- {0x04ba, {1|F|D, {0x04bb}}},
- {0x04bc, {1|F|D, {0x04bd}}},
- {0x04be, {1|F|D, {0x04bf}}},
- {0x04c0, {1|F|D, {0x04cf}}},
- {0x04c1, {1|F|D, {0x04c2}}},
- {0x04c3, {1|F|D, {0x04c4}}},
- {0x04c5, {1|F|D, {0x04c6}}},
- {0x04c7, {1|F|D, {0x04c8}}},
- {0x04c9, {1|F|D, {0x04ca}}},
- {0x04cb, {1|F|D, {0x04cc}}},
- {0x04cd, {1|F|D, {0x04ce}}},
- {0x04d0, {1|F|D, {0x04d1}}},
- {0x04d2, {1|F|D, {0x04d3}}},
- {0x04d4, {1|F|D, {0x04d5}}},
- {0x04d6, {1|F|D, {0x04d7}}},
- {0x04d8, {1|F|D, {0x04d9}}},
- {0x04da, {1|F|D, {0x04db}}},
- {0x04dc, {1|F|D, {0x04dd}}},
- {0x04de, {1|F|D, {0x04df}}},
- {0x04e0, {1|F|D, {0x04e1}}},
- {0x04e2, {1|F|D, {0x04e3}}},
- {0x04e4, {1|F|D, {0x04e5}}},
- {0x04e6, {1|F|D, {0x04e7}}},
- {0x04e8, {1|F|D, {0x04e9}}},
- {0x04ea, {1|F|D, {0x04eb}}},
- {0x04ec, {1|F|D, {0x04ed}}},
- {0x04ee, {1|F|D, {0x04ef}}},
- {0x04f0, {1|F|D, {0x04f1}}},
- {0x04f2, {1|F|D, {0x04f3}}},
- {0x04f4, {1|F|D, {0x04f5}}},
- {0x04f6, {1|F|D, {0x04f7}}},
- {0x04f8, {1|F|D, {0x04f9}}},
- {0x04fa, {1|F|D, {0x04fb}}},
- {0x04fc, {1|F|D, {0x04fd}}},
- {0x04fe, {1|F|D, {0x04ff}}},
- {0x0500, {1|F|D, {0x0501}}},
- {0x0502, {1|F|D, {0x0503}}},
- {0x0504, {1|F|D, {0x0505}}},
- {0x0506, {1|F|D, {0x0507}}},
- {0x0508, {1|F|D, {0x0509}}},
- {0x050a, {1|F|D, {0x050b}}},
- {0x050c, {1|F|D, {0x050d}}},
- {0x050e, {1|F|D, {0x050f}}},
- {0x0510, {1|F|D, {0x0511}}},
- {0x0512, {1|F|D, {0x0513}}},
- {0x0514, {1|F|D, {0x0515}}},
- {0x0516, {1|F|D, {0x0517}}},
- {0x0518, {1|F|D, {0x0519}}},
- {0x051a, {1|F|D, {0x051b}}},
- {0x051c, {1|F|D, {0x051d}}},
- {0x051e, {1|F|D, {0x051f}}},
- {0x0520, {1|F|D, {0x0521}}},
- {0x0522, {1|F|D, {0x0523}}},
- {0x0524, {1|F|D, {0x0525}}},
- {0x0526, {1|F|D, {0x0527}}},
- {0x0528, {1|F|D, {0x0529}}},
- {0x052a, {1|F|D, {0x052b}}},
- {0x052c, {1|F|D, {0x052d}}},
- {0x052e, {1|F|D, {0x052f}}},
- {0x0531, {1|F|D, {0x0561}}},
- {0x0532, {1|F|D, {0x0562}}},
- {0x0533, {1|F|D, {0x0563}}},
- {0x0534, {1|F|D, {0x0564}}},
- {0x0535, {1|F|D, {0x0565}}},
- {0x0536, {1|F|D, {0x0566}}},
- {0x0537, {1|F|D, {0x0567}}},
- {0x0538, {1|F|D, {0x0568}}},
- {0x0539, {1|F|D, {0x0569}}},
- {0x053a, {1|F|D, {0x056a}}},
- {0x053b, {1|F|D, {0x056b}}},
- {0x053c, {1|F|D, {0x056c}}},
- {0x053d, {1|F|D, {0x056d}}},
- {0x053e, {1|F|D, {0x056e}}},
- {0x053f, {1|F|D, {0x056f}}},
- {0x0540, {1|F|D, {0x0570}}},
- {0x0541, {1|F|D, {0x0571}}},
- {0x0542, {1|F|D, {0x0572}}},
- {0x0543, {1|F|D, {0x0573}}},
- {0x0544, {1|F|D, {0x0574}}},
- {0x0545, {1|F|D, {0x0575}}},
- {0x0546, {1|F|D, {0x0576}}},
- {0x0547, {1|F|D, {0x0577}}},
- {0x0548, {1|F|D, {0x0578}}},
- {0x0549, {1|F|D, {0x0579}}},
- {0x054a, {1|F|D, {0x057a}}},
- {0x054b, {1|F|D, {0x057b}}},
- {0x054c, {1|F|D, {0x057c}}},
- {0x054d, {1|F|D, {0x057d}}},
- {0x054e, {1|F|D, {0x057e}}},
- {0x054f, {1|F|D, {0x057f}}},
- {0x0550, {1|F|D, {0x0580}}},
- {0x0551, {1|F|D, {0x0581}}},
- {0x0552, {1|F|D, {0x0582}}},
- {0x0553, {1|F|D, {0x0583}}},
- {0x0554, {1|F|D, {0x0584}}},
- {0x0555, {1|F|D, {0x0585}}},
- {0x0556, {1|F|D, {0x0586}}},
- {0x0587, {2|F|ST|SU|I(41), {0x0565, 0x0582}}},
- {0x10a0, {1|F|D, {0x2d00}}},
- {0x10a1, {1|F|D, {0x2d01}}},
- {0x10a2, {1|F|D, {0x2d02}}},
- {0x10a3, {1|F|D, {0x2d03}}},
- {0x10a4, {1|F|D, {0x2d04}}},
- {0x10a5, {1|F|D, {0x2d05}}},
- {0x10a6, {1|F|D, {0x2d06}}},
- {0x10a7, {1|F|D, {0x2d07}}},
- {0x10a8, {1|F|D, {0x2d08}}},
- {0x10a9, {1|F|D, {0x2d09}}},
- {0x10aa, {1|F|D, {0x2d0a}}},
- {0x10ab, {1|F|D, {0x2d0b}}},
- {0x10ac, {1|F|D, {0x2d0c}}},
- {0x10ad, {1|F|D, {0x2d0d}}},
- {0x10ae, {1|F|D, {0x2d0e}}},
- {0x10af, {1|F|D, {0x2d0f}}},
- {0x10b0, {1|F|D, {0x2d10}}},
- {0x10b1, {1|F|D, {0x2d11}}},
- {0x10b2, {1|F|D, {0x2d12}}},
- {0x10b3, {1|F|D, {0x2d13}}},
- {0x10b4, {1|F|D, {0x2d14}}},
- {0x10b5, {1|F|D, {0x2d15}}},
- {0x10b6, {1|F|D, {0x2d16}}},
- {0x10b7, {1|F|D, {0x2d17}}},
- {0x10b8, {1|F|D, {0x2d18}}},
- {0x10b9, {1|F|D, {0x2d19}}},
- {0x10ba, {1|F|D, {0x2d1a}}},
- {0x10bb, {1|F|D, {0x2d1b}}},
- {0x10bc, {1|F|D, {0x2d1c}}},
- {0x10bd, {1|F|D, {0x2d1d}}},
- {0x10be, {1|F|D, {0x2d1e}}},
- {0x10bf, {1|F|D, {0x2d1f}}},
- {0x10c0, {1|F|D, {0x2d20}}},
- {0x10c1, {1|F|D, {0x2d21}}},
- {0x10c2, {1|F|D, {0x2d22}}},
- {0x10c3, {1|F|D, {0x2d23}}},
- {0x10c4, {1|F|D, {0x2d24}}},
- {0x10c5, {1|F|D, {0x2d25}}},
- {0x10c7, {1|F|D, {0x2d27}}},
- {0x10cd, {1|F|D, {0x2d2d}}},
- {0x13f8, {1|F|U, {0x13f0}}},
- {0x13f9, {1|F|U, {0x13f1}}},
- {0x13fa, {1|F|U, {0x13f2}}},
- {0x13fb, {1|F|U, {0x13f3}}},
- {0x13fc, {1|F|U, {0x13f4}}},
- {0x13fd, {1|F|U, {0x13f5}}},
- {0x1c80, {1|F|SU|I(45), {0x0432}}},
- {0x1c81, {1|F|SU|I(46), {0x0434}}},
- {0x1c82, {1|F|SU|I(47), {0x043e}}},
- {0x1c83, {1|F|SU|I(48), {0x0441}}},
- {0x1c84, {1|F|SU|I(49), {0x0442}}},
- {0x1c85, {1|F|SU|I(50), {0x0442}}},
- {0x1c86, {1|F|SU|I(51), {0x044a}}},
- {0x1c87, {1|F|SU|I(52), {0x0463}}},
- {0x1c88, {1|F|SU|I(53), {0xa64b}}},
- {0x1c90, {1|F|D, {0x10d0}}},
- {0x1c91, {1|F|D, {0x10d1}}},
- {0x1c92, {1|F|D, {0x10d2}}},
- {0x1c93, {1|F|D, {0x10d3}}},
- {0x1c94, {1|F|D, {0x10d4}}},
- {0x1c95, {1|F|D, {0x10d5}}},
- {0x1c96, {1|F|D, {0x10d6}}},
- {0x1c97, {1|F|D, {0x10d7}}},
- {0x1c98, {1|F|D, {0x10d8}}},
- {0x1c99, {1|F|D, {0x10d9}}},
- {0x1c9a, {1|F|D, {0x10da}}},
- {0x1c9b, {1|F|D, {0x10db}}},
- {0x1c9c, {1|F|D, {0x10dc}}},
- {0x1c9d, {1|F|D, {0x10dd}}},
- {0x1c9e, {1|F|D, {0x10de}}},
- {0x1c9f, {1|F|D, {0x10df}}},
- {0x1ca0, {1|F|D, {0x10e0}}},
- {0x1ca1, {1|F|D, {0x10e1}}},
- {0x1ca2, {1|F|D, {0x10e2}}},
- {0x1ca3, {1|F|D, {0x10e3}}},
- {0x1ca4, {1|F|D, {0x10e4}}},
- {0x1ca5, {1|F|D, {0x10e5}}},
- {0x1ca6, {1|F|D, {0x10e6}}},
- {0x1ca7, {1|F|D, {0x10e7}}},
- {0x1ca8, {1|F|D, {0x10e8}}},
- {0x1ca9, {1|F|D, {0x10e9}}},
- {0x1caa, {1|F|D, {0x10ea}}},
- {0x1cab, {1|F|D, {0x10eb}}},
- {0x1cac, {1|F|D, {0x10ec}}},
- {0x1cad, {1|F|D, {0x10ed}}},
- {0x1cae, {1|F|D, {0x10ee}}},
- {0x1caf, {1|F|D, {0x10ef}}},
- {0x1cb0, {1|F|D, {0x10f0}}},
- {0x1cb1, {1|F|D, {0x10f1}}},
- {0x1cb2, {1|F|D, {0x10f2}}},
- {0x1cb3, {1|F|D, {0x10f3}}},
- {0x1cb4, {1|F|D, {0x10f4}}},
- {0x1cb5, {1|F|D, {0x10f5}}},
- {0x1cb6, {1|F|D, {0x10f6}}},
- {0x1cb7, {1|F|D, {0x10f7}}},
- {0x1cb8, {1|F|D, {0x10f8}}},
- {0x1cb9, {1|F|D, {0x10f9}}},
- {0x1cba, {1|F|D, {0x10fa}}},
- {0x1cbd, {1|F|D, {0x10fd}}},
- {0x1cbe, {1|F|D, {0x10fe}}},
- {0x1cbf, {1|F|D, {0x10ff}}},
- {0x1e00, {1|F|D, {0x1e01}}},
- {0x1e02, {1|F|D, {0x1e03}}},
- {0x1e04, {1|F|D, {0x1e05}}},
- {0x1e06, {1|F|D, {0x1e07}}},
- {0x1e08, {1|F|D, {0x1e09}}},
- {0x1e0a, {1|F|D, {0x1e0b}}},
- {0x1e0c, {1|F|D, {0x1e0d}}},
- {0x1e0e, {1|F|D, {0x1e0f}}},
- {0x1e10, {1|F|D, {0x1e11}}},
- {0x1e12, {1|F|D, {0x1e13}}},
- {0x1e14, {1|F|D, {0x1e15}}},
- {0x1e16, {1|F|D, {0x1e17}}},
- {0x1e18, {1|F|D, {0x1e19}}},
- {0x1e1a, {1|F|D, {0x1e1b}}},
- {0x1e1c, {1|F|D, {0x1e1d}}},
- {0x1e1e, {1|F|D, {0x1e1f}}},
- {0x1e20, {1|F|D, {0x1e21}}},
- {0x1e22, {1|F|D, {0x1e23}}},
- {0x1e24, {1|F|D, {0x1e25}}},
- {0x1e26, {1|F|D, {0x1e27}}},
- {0x1e28, {1|F|D, {0x1e29}}},
- {0x1e2a, {1|F|D, {0x1e2b}}},
- {0x1e2c, {1|F|D, {0x1e2d}}},
- {0x1e2e, {1|F|D, {0x1e2f}}},
- {0x1e30, {1|F|D, {0x1e31}}},
- {0x1e32, {1|F|D, {0x1e33}}},
- {0x1e34, {1|F|D, {0x1e35}}},
- {0x1e36, {1|F|D, {0x1e37}}},
- {0x1e38, {1|F|D, {0x1e39}}},
- {0x1e3a, {1|F|D, {0x1e3b}}},
- {0x1e3c, {1|F|D, {0x1e3d}}},
- {0x1e3e, {1|F|D, {0x1e3f}}},
- {0x1e40, {1|F|D, {0x1e41}}},
- {0x1e42, {1|F|D, {0x1e43}}},
- {0x1e44, {1|F|D, {0x1e45}}},
- {0x1e46, {1|F|D, {0x1e47}}},
- {0x1e48, {1|F|D, {0x1e49}}},
- {0x1e4a, {1|F|D, {0x1e4b}}},
- {0x1e4c, {1|F|D, {0x1e4d}}},
- {0x1e4e, {1|F|D, {0x1e4f}}},
- {0x1e50, {1|F|D, {0x1e51}}},
- {0x1e52, {1|F|D, {0x1e53}}},
- {0x1e54, {1|F|D, {0x1e55}}},
- {0x1e56, {1|F|D, {0x1e57}}},
- {0x1e58, {1|F|D, {0x1e59}}},
- {0x1e5a, {1|F|D, {0x1e5b}}},
- {0x1e5c, {1|F|D, {0x1e5d}}},
- {0x1e5e, {1|F|D, {0x1e5f}}},
- {0x1e60, {1|F|D, {0x1e61}}},
- {0x1e62, {1|F|D, {0x1e63}}},
- {0x1e64, {1|F|D, {0x1e65}}},
- {0x1e66, {1|F|D, {0x1e67}}},
- {0x1e68, {1|F|D, {0x1e69}}},
- {0x1e6a, {1|F|D, {0x1e6b}}},
- {0x1e6c, {1|F|D, {0x1e6d}}},
- {0x1e6e, {1|F|D, {0x1e6f}}},
- {0x1e70, {1|F|D, {0x1e71}}},
- {0x1e72, {1|F|D, {0x1e73}}},
- {0x1e74, {1|F|D, {0x1e75}}},
- {0x1e76, {1|F|D, {0x1e77}}},
- {0x1e78, {1|F|D, {0x1e79}}},
- {0x1e7a, {1|F|D, {0x1e7b}}},
- {0x1e7c, {1|F|D, {0x1e7d}}},
- {0x1e7e, {1|F|D, {0x1e7f}}},
- {0x1e80, {1|F|D, {0x1e81}}},
- {0x1e82, {1|F|D, {0x1e83}}},
- {0x1e84, {1|F|D, {0x1e85}}},
- {0x1e86, {1|F|D, {0x1e87}}},
- {0x1e88, {1|F|D, {0x1e89}}},
- {0x1e8a, {1|F|D, {0x1e8b}}},
- {0x1e8c, {1|F|D, {0x1e8d}}},
- {0x1e8e, {1|F|D, {0x1e8f}}},
- {0x1e90, {1|F|D, {0x1e91}}},
- {0x1e92, {1|F|D, {0x1e93}}},
- {0x1e94, {1|F|D, {0x1e95}}},
- {0x1e96, {2|F|SU|I(54), {0x0068, 0x0331}}},
- {0x1e97, {2|F|SU|I(56), {0x0074, 0x0308}}},
- {0x1e98, {2|F|SU|I(58), {0x0077, 0x030a}}},
- {0x1e99, {2|F|SU|I(60), {0x0079, 0x030a}}},
- {0x1e9a, {2|F|SU|I(62), {0x0061, 0x02be}}},
- {0x1e9b, {1|F|SU|I(64), {0x1e61}}},
- {0x1e9e, {2|F|SL|I(65), {0x0073, 0x0073}}},
- {0x1ea0, {1|F|D, {0x1ea1}}},
- {0x1ea2, {1|F|D, {0x1ea3}}},
- {0x1ea4, {1|F|D, {0x1ea5}}},
- {0x1ea6, {1|F|D, {0x1ea7}}},
- {0x1ea8, {1|F|D, {0x1ea9}}},
- {0x1eaa, {1|F|D, {0x1eab}}},
- {0x1eac, {1|F|D, {0x1ead}}},
- {0x1eae, {1|F|D, {0x1eaf}}},
- {0x1eb0, {1|F|D, {0x1eb1}}},
- {0x1eb2, {1|F|D, {0x1eb3}}},
- {0x1eb4, {1|F|D, {0x1eb5}}},
- {0x1eb6, {1|F|D, {0x1eb7}}},
- {0x1eb8, {1|F|D, {0x1eb9}}},
- {0x1eba, {1|F|D, {0x1ebb}}},
- {0x1ebc, {1|F|D, {0x1ebd}}},
- {0x1ebe, {1|F|D, {0x1ebf}}},
- {0x1ec0, {1|F|D, {0x1ec1}}},
- {0x1ec2, {1|F|D, {0x1ec3}}},
- {0x1ec4, {1|F|D, {0x1ec5}}},
- {0x1ec6, {1|F|D, {0x1ec7}}},
- {0x1ec8, {1|F|D, {0x1ec9}}},
- {0x1eca, {1|F|D, {0x1ecb}}},
- {0x1ecc, {1|F|D, {0x1ecd}}},
- {0x1ece, {1|F|D, {0x1ecf}}},
- {0x1ed0, {1|F|D, {0x1ed1}}},
- {0x1ed2, {1|F|D, {0x1ed3}}},
- {0x1ed4, {1|F|D, {0x1ed5}}},
- {0x1ed6, {1|F|D, {0x1ed7}}},
- {0x1ed8, {1|F|D, {0x1ed9}}},
- {0x1eda, {1|F|D, {0x1edb}}},
- {0x1edc, {1|F|D, {0x1edd}}},
- {0x1ede, {1|F|D, {0x1edf}}},
- {0x1ee0, {1|F|D, {0x1ee1}}},
- {0x1ee2, {1|F|D, {0x1ee3}}},
- {0x1ee4, {1|F|D, {0x1ee5}}},
- {0x1ee6, {1|F|D, {0x1ee7}}},
- {0x1ee8, {1|F|D, {0x1ee9}}},
- {0x1eea, {1|F|D, {0x1eeb}}},
- {0x1eec, {1|F|D, {0x1eed}}},
- {0x1eee, {1|F|D, {0x1eef}}},
- {0x1ef0, {1|F|D, {0x1ef1}}},
- {0x1ef2, {1|F|D, {0x1ef3}}},
- {0x1ef4, {1|F|D, {0x1ef5}}},
- {0x1ef6, {1|F|D, {0x1ef7}}},
- {0x1ef8, {1|F|D, {0x1ef9}}},
- {0x1efa, {1|F|D, {0x1efb}}},
- {0x1efc, {1|F|D, {0x1efd}}},
- {0x1efe, {1|F|D, {0x1eff}}},
- {0x1f08, {1|F|D, {0x1f00}}},
- {0x1f09, {1|F|D, {0x1f01}}},
- {0x1f0a, {1|F|D, {0x1f02}}},
- {0x1f0b, {1|F|D, {0x1f03}}},
- {0x1f0c, {1|F|D, {0x1f04}}},
- {0x1f0d, {1|F|D, {0x1f05}}},
- {0x1f0e, {1|F|D, {0x1f06}}},
- {0x1f0f, {1|F|D, {0x1f07}}},
- {0x1f18, {1|F|D, {0x1f10}}},
- {0x1f19, {1|F|D, {0x1f11}}},
- {0x1f1a, {1|F|D, {0x1f12}}},
- {0x1f1b, {1|F|D, {0x1f13}}},
- {0x1f1c, {1|F|D, {0x1f14}}},
- {0x1f1d, {1|F|D, {0x1f15}}},
- {0x1f28, {1|F|D, {0x1f20}}},
- {0x1f29, {1|F|D, {0x1f21}}},
- {0x1f2a, {1|F|D, {0x1f22}}},
- {0x1f2b, {1|F|D, {0x1f23}}},
- {0x1f2c, {1|F|D, {0x1f24}}},
- {0x1f2d, {1|F|D, {0x1f25}}},
- {0x1f2e, {1|F|D, {0x1f26}}},
- {0x1f2f, {1|F|D, {0x1f27}}},
- {0x1f38, {1|F|D, {0x1f30}}},
- {0x1f39, {1|F|D, {0x1f31}}},
- {0x1f3a, {1|F|D, {0x1f32}}},
- {0x1f3b, {1|F|D, {0x1f33}}},
- {0x1f3c, {1|F|D, {0x1f34}}},
- {0x1f3d, {1|F|D, {0x1f35}}},
- {0x1f3e, {1|F|D, {0x1f36}}},
- {0x1f3f, {1|F|D, {0x1f37}}},
- {0x1f48, {1|F|D, {0x1f40}}},
- {0x1f49, {1|F|D, {0x1f41}}},
- {0x1f4a, {1|F|D, {0x1f42}}},
- {0x1f4b, {1|F|D, {0x1f43}}},
- {0x1f4c, {1|F|D, {0x1f44}}},
- {0x1f4d, {1|F|D, {0x1f45}}},
- {0x1f50, {2|F|SU|I(66), {0x03c5, 0x0313}}},
- {0x1f52, {3|F|SU|I(68), {0x03c5, 0x0313, 0x0300}}},
- {0x1f54, {3|F|SU|I(71), {0x03c5, 0x0313, 0x0301}}},
- {0x1f56, {3|F|SU|I(74), {0x03c5, 0x0313, 0x0342}}},
- {0x1f59, {1|F|D, {0x1f51}}},
- {0x1f5b, {1|F|D, {0x1f53}}},
- {0x1f5d, {1|F|D, {0x1f55}}},
- {0x1f5f, {1|F|D, {0x1f57}}},
- {0x1f68, {1|F|D, {0x1f60}}},
- {0x1f69, {1|F|D, {0x1f61}}},
- {0x1f6a, {1|F|D, {0x1f62}}},
- {0x1f6b, {1|F|D, {0x1f63}}},
- {0x1f6c, {1|F|D, {0x1f64}}},
- {0x1f6d, {1|F|D, {0x1f65}}},
- {0x1f6e, {1|F|D, {0x1f66}}},
- {0x1f6f, {1|F|D, {0x1f67}}},
- {0x1f80, {2|F|ST|SU|I(77), {0x1f00, 0x03b9}}},
- {0x1f81, {2|F|ST|SU|I(80), {0x1f01, 0x03b9}}},
- {0x1f82, {2|F|ST|SU|I(83), {0x1f02, 0x03b9}}},
- {0x1f83, {2|F|ST|SU|I(86), {0x1f03, 0x03b9}}},
- {0x1f84, {2|F|ST|SU|I(89), {0x1f04, 0x03b9}}},
- {0x1f85, {2|F|ST|SU|I(92), {0x1f05, 0x03b9}}},
- {0x1f86, {2|F|ST|SU|I(95), {0x1f06, 0x03b9}}},
- {0x1f87, {2|F|ST|SU|I(98), {0x1f07, 0x03b9}}},
- {0x1f88, {2|F|IT|SL|SU|I(101), {0x1f00, 0x03b9}}},
- {0x1f89, {2|F|IT|SL|SU|I(106), {0x1f01, 0x03b9}}},
- {0x1f8a, {2|F|IT|SL|SU|I(111), {0x1f02, 0x03b9}}},
- {0x1f8b, {2|F|IT|SL|SU|I(116), {0x1f03, 0x03b9}}},
- {0x1f8c, {2|F|IT|SL|SU|I(121), {0x1f04, 0x03b9}}},
- {0x1f8d, {2|F|IT|SL|SU|I(126), {0x1f05, 0x03b9}}},
- {0x1f8e, {2|F|IT|SL|SU|I(131), {0x1f06, 0x03b9}}},
- {0x1f8f, {2|F|IT|SL|SU|I(136), {0x1f07, 0x03b9}}},
- {0x1f90, {2|F|ST|SU|I(141), {0x1f20, 0x03b9}}},
- {0x1f91, {2|F|ST|SU|I(144), {0x1f21, 0x03b9}}},
- {0x1f92, {2|F|ST|SU|I(147), {0x1f22, 0x03b9}}},
- {0x1f93, {2|F|ST|SU|I(150), {0x1f23, 0x03b9}}},
- {0x1f94, {2|F|ST|SU|I(153), {0x1f24, 0x03b9}}},
- {0x1f95, {2|F|ST|SU|I(156), {0x1f25, 0x03b9}}},
- {0x1f96, {2|F|ST|SU|I(159), {0x1f26, 0x03b9}}},
- {0x1f97, {2|F|ST|SU|I(162), {0x1f27, 0x03b9}}},
- {0x1f98, {2|F|IT|SL|SU|I(165), {0x1f20, 0x03b9}}},
- {0x1f99, {2|F|IT|SL|SU|I(170), {0x1f21, 0x03b9}}},
- {0x1f9a, {2|F|IT|SL|SU|I(175), {0x1f22, 0x03b9}}},
- {0x1f9b, {2|F|IT|SL|SU|I(180), {0x1f23, 0x03b9}}},
- {0x1f9c, {2|F|IT|SL|SU|I(185), {0x1f24, 0x03b9}}},
- {0x1f9d, {2|F|IT|SL|SU|I(190), {0x1f25, 0x03b9}}},
- {0x1f9e, {2|F|IT|SL|SU|I(195), {0x1f26, 0x03b9}}},
- {0x1f9f, {2|F|IT|SL|SU|I(200), {0x1f27, 0x03b9}}},
- {0x1fa0, {2|F|ST|SU|I(205), {0x1f60, 0x03b9}}},
- {0x1fa1, {2|F|ST|SU|I(208), {0x1f61, 0x03b9}}},
- {0x1fa2, {2|F|ST|SU|I(211), {0x1f62, 0x03b9}}},
- {0x1fa3, {2|F|ST|SU|I(214), {0x1f63, 0x03b9}}},
- {0x1fa4, {2|F|ST|SU|I(217), {0x1f64, 0x03b9}}},
- {0x1fa5, {2|F|ST|SU|I(220), {0x1f65, 0x03b9}}},
- {0x1fa6, {2|F|ST|SU|I(223), {0x1f66, 0x03b9}}},
- {0x1fa7, {2|F|ST|SU|I(226), {0x1f67, 0x03b9}}},
- {0x1fa8, {2|F|IT|SL|SU|I(229), {0x1f60, 0x03b9}}},
- {0x1fa9, {2|F|IT|SL|SU|I(234), {0x1f61, 0x03b9}}},
- {0x1faa, {2|F|IT|SL|SU|I(239), {0x1f62, 0x03b9}}},
- {0x1fab, {2|F|IT|SL|SU|I(244), {0x1f63, 0x03b9}}},
- {0x1fac, {2|F|IT|SL|SU|I(249), {0x1f64, 0x03b9}}},
- {0x1fad, {2|F|IT|SL|SU|I(254), {0x1f65, 0x03b9}}},
- {0x1fae, {2|F|IT|SL|SU|I(259), {0x1f66, 0x03b9}}},
- {0x1faf, {2|F|IT|SL|SU|I(264), {0x1f67, 0x03b9}}},
- {0x1fb2, {2|F|ST|SU|I(269), {0x1f70, 0x03b9}}},
- {0x1fb3, {2|F|ST|SU|I(273), {0x03b1, 0x03b9}}},
- {0x1fb4, {2|F|ST|SU|I(276), {0x03ac, 0x03b9}}},
- {0x1fb6, {2|F|SU|I(280), {0x03b1, 0x0342}}},
- {0x1fb7, {3|F|ST|SU|I(282), {0x03b1, 0x0342, 0x03b9}}},
- {0x1fb8, {1|F|D, {0x1fb0}}},
- {0x1fb9, {1|F|D, {0x1fb1}}},
- {0x1fba, {1|F|D, {0x1f70}}},
- {0x1fbb, {1|F|D, {0x1f71}}},
- {0x1fbc, {2|F|IT|SL|SU|I(288), {0x03b1, 0x03b9}}},
- {0x1fbe, {1|F|SU|I(293), {0x03b9}}},
- {0x1fc2, {2|F|ST|SU|I(294), {0x1f74, 0x03b9}}},
- {0x1fc3, {2|F|ST|SU|I(298), {0x03b7, 0x03b9}}},
- {0x1fc4, {2|F|ST|SU|I(301), {0x03ae, 0x03b9}}},
- {0x1fc6, {2|F|SU|I(305), {0x03b7, 0x0342}}},
- {0x1fc7, {3|F|ST|SU|I(307), {0x03b7, 0x0342, 0x03b9}}},
- {0x1fc8, {1|F|D, {0x1f72}}},
- {0x1fc9, {1|F|D, {0x1f73}}},
- {0x1fca, {1|F|D, {0x1f74}}},
- {0x1fcb, {1|F|D, {0x1f75}}},
- {0x1fcc, {2|F|IT|SL|SU|I(313), {0x03b7, 0x03b9}}},
- {0x1fd2, {3|F|SU|I(318), {0x03b9, 0x0308, 0x0300}}},
- {0x1fd3, {3|F|SU|I(321), {0x03b9, 0x0308, 0x0301}}},
- {0x1fd6, {2|F|SU|I(324), {0x03b9, 0x0342}}},
- {0x1fd7, {3|F|SU|I(326), {0x03b9, 0x0308, 0x0342}}},
- {0x1fd8, {1|F|D, {0x1fd0}}},
- {0x1fd9, {1|F|D, {0x1fd1}}},
- {0x1fda, {1|F|D, {0x1f76}}},
- {0x1fdb, {1|F|D, {0x1f77}}},
- {0x1fe2, {3|F|SU|I(329), {0x03c5, 0x0308, 0x0300}}},
- {0x1fe3, {3|F|SU|I(332), {0x03c5, 0x0308, 0x0301}}},
- {0x1fe4, {2|F|SU|I(335), {0x03c1, 0x0313}}},
- {0x1fe6, {2|F|SU|I(337), {0x03c5, 0x0342}}},
- {0x1fe7, {3|F|SU|I(339), {0x03c5, 0x0308, 0x0342}}},
- {0x1fe8, {1|F|D, {0x1fe0}}},
- {0x1fe9, {1|F|D, {0x1fe1}}},
- {0x1fea, {1|F|D, {0x1f7a}}},
- {0x1feb, {1|F|D, {0x1f7b}}},
- {0x1fec, {1|F|D, {0x1fe5}}},
- {0x1ff2, {2|F|ST|SU|I(342), {0x1f7c, 0x03b9}}},
- {0x1ff3, {2|F|ST|SU|I(346), {0x03c9, 0x03b9}}},
- {0x1ff4, {2|F|ST|SU|I(349), {0x03ce, 0x03b9}}},
- {0x1ff6, {2|F|SU|I(353), {0x03c9, 0x0342}}},
- {0x1ff7, {3|F|ST|SU|I(355), {0x03c9, 0x0342, 0x03b9}}},
- {0x1ff8, {1|F|D, {0x1f78}}},
- {0x1ff9, {1|F|D, {0x1f79}}},
- {0x1ffa, {1|F|D, {0x1f7c}}},
- {0x1ffb, {1|F|D, {0x1f7d}}},
- {0x1ffc, {2|F|IT|SL|SU|I(361), {0x03c9, 0x03b9}}},
- {0x2126, {1|F|D, {0x03c9}}},
- {0x212a, {1|F|D, {0x006b}}},
- {0x212b, {1|F|D, {0x00e5}}},
- {0x2132, {1|F|D, {0x214e}}},
- {0x2160, {1|F|D, {0x2170}}},
- {0x2161, {1|F|D, {0x2171}}},
- {0x2162, {1|F|D, {0x2172}}},
- {0x2163, {1|F|D, {0x2173}}},
- {0x2164, {1|F|D, {0x2174}}},
- {0x2165, {1|F|D, {0x2175}}},
- {0x2166, {1|F|D, {0x2176}}},
- {0x2167, {1|F|D, {0x2177}}},
- {0x2168, {1|F|D, {0x2178}}},
- {0x2169, {1|F|D, {0x2179}}},
- {0x216a, {1|F|D, {0x217a}}},
- {0x216b, {1|F|D, {0x217b}}},
- {0x216c, {1|F|D, {0x217c}}},
- {0x216d, {1|F|D, {0x217d}}},
- {0x216e, {1|F|D, {0x217e}}},
- {0x216f, {1|F|D, {0x217f}}},
- {0x2183, {1|F|D, {0x2184}}},
- {0x24b6, {1|F|D, {0x24d0}}},
- {0x24b7, {1|F|D, {0x24d1}}},
- {0x24b8, {1|F|D, {0x24d2}}},
- {0x24b9, {1|F|D, {0x24d3}}},
- {0x24ba, {1|F|D, {0x24d4}}},
- {0x24bb, {1|F|D, {0x24d5}}},
- {0x24bc, {1|F|D, {0x24d6}}},
- {0x24bd, {1|F|D, {0x24d7}}},
- {0x24be, {1|F|D, {0x24d8}}},
- {0x24bf, {1|F|D, {0x24d9}}},
- {0x24c0, {1|F|D, {0x24da}}},
- {0x24c1, {1|F|D, {0x24db}}},
- {0x24c2, {1|F|D, {0x24dc}}},
- {0x24c3, {1|F|D, {0x24dd}}},
- {0x24c4, {1|F|D, {0x24de}}},
- {0x24c5, {1|F|D, {0x24df}}},
- {0x24c6, {1|F|D, {0x24e0}}},
- {0x24c7, {1|F|D, {0x24e1}}},
- {0x24c8, {1|F|D, {0x24e2}}},
- {0x24c9, {1|F|D, {0x24e3}}},
- {0x24ca, {1|F|D, {0x24e4}}},
- {0x24cb, {1|F|D, {0x24e5}}},
- {0x24cc, {1|F|D, {0x24e6}}},
- {0x24cd, {1|F|D, {0x24e7}}},
- {0x24ce, {1|F|D, {0x24e8}}},
- {0x24cf, {1|F|D, {0x24e9}}},
- {0x2c00, {1|F|D, {0x2c30}}},
- {0x2c01, {1|F|D, {0x2c31}}},
- {0x2c02, {1|F|D, {0x2c32}}},
- {0x2c03, {1|F|D, {0x2c33}}},
- {0x2c04, {1|F|D, {0x2c34}}},
- {0x2c05, {1|F|D, {0x2c35}}},
- {0x2c06, {1|F|D, {0x2c36}}},
- {0x2c07, {1|F|D, {0x2c37}}},
- {0x2c08, {1|F|D, {0x2c38}}},
- {0x2c09, {1|F|D, {0x2c39}}},
- {0x2c0a, {1|F|D, {0x2c3a}}},
- {0x2c0b, {1|F|D, {0x2c3b}}},
- {0x2c0c, {1|F|D, {0x2c3c}}},
- {0x2c0d, {1|F|D, {0x2c3d}}},
- {0x2c0e, {1|F|D, {0x2c3e}}},
- {0x2c0f, {1|F|D, {0x2c3f}}},
- {0x2c10, {1|F|D, {0x2c40}}},
- {0x2c11, {1|F|D, {0x2c41}}},
- {0x2c12, {1|F|D, {0x2c42}}},
- {0x2c13, {1|F|D, {0x2c43}}},
- {0x2c14, {1|F|D, {0x2c44}}},
- {0x2c15, {1|F|D, {0x2c45}}},
- {0x2c16, {1|F|D, {0x2c46}}},
- {0x2c17, {1|F|D, {0x2c47}}},
- {0x2c18, {1|F|D, {0x2c48}}},
- {0x2c19, {1|F|D, {0x2c49}}},
- {0x2c1a, {1|F|D, {0x2c4a}}},
- {0x2c1b, {1|F|D, {0x2c4b}}},
- {0x2c1c, {1|F|D, {0x2c4c}}},
- {0x2c1d, {1|F|D, {0x2c4d}}},
- {0x2c1e, {1|F|D, {0x2c4e}}},
- {0x2c1f, {1|F|D, {0x2c4f}}},
- {0x2c20, {1|F|D, {0x2c50}}},
- {0x2c21, {1|F|D, {0x2c51}}},
- {0x2c22, {1|F|D, {0x2c52}}},
- {0x2c23, {1|F|D, {0x2c53}}},
- {0x2c24, {1|F|D, {0x2c54}}},
- {0x2c25, {1|F|D, {0x2c55}}},
- {0x2c26, {1|F|D, {0x2c56}}},
- {0x2c27, {1|F|D, {0x2c57}}},
- {0x2c28, {1|F|D, {0x2c58}}},
- {0x2c29, {1|F|D, {0x2c59}}},
- {0x2c2a, {1|F|D, {0x2c5a}}},
- {0x2c2b, {1|F|D, {0x2c5b}}},
- {0x2c2c, {1|F|D, {0x2c5c}}},
- {0x2c2d, {1|F|D, {0x2c5d}}},
- {0x2c2e, {1|F|D, {0x2c5e}}},
- {0x2c2f, {1|F|D, {0x2c5f}}},
- {0x2c60, {1|F|D, {0x2c61}}},
- {0x2c62, {1|F|D, {0x026b}}},
- {0x2c63, {1|F|D, {0x1d7d}}},
- {0x2c64, {1|F|D, {0x027d}}},
- {0x2c67, {1|F|D, {0x2c68}}},
- {0x2c69, {1|F|D, {0x2c6a}}},
- {0x2c6b, {1|F|D, {0x2c6c}}},
- {0x2c6d, {1|F|D, {0x0251}}},
- {0x2c6e, {1|F|D, {0x0271}}},
- {0x2c6f, {1|F|D, {0x0250}}},
- {0x2c70, {1|F|D, {0x0252}}},
- {0x2c72, {1|F|D, {0x2c73}}},
- {0x2c75, {1|F|D, {0x2c76}}},
- {0x2c7e, {1|F|D, {0x023f}}},
- {0x2c7f, {1|F|D, {0x0240}}},
- {0x2c80, {1|F|D, {0x2c81}}},
- {0x2c82, {1|F|D, {0x2c83}}},
- {0x2c84, {1|F|D, {0x2c85}}},
- {0x2c86, {1|F|D, {0x2c87}}},
- {0x2c88, {1|F|D, {0x2c89}}},
- {0x2c8a, {1|F|D, {0x2c8b}}},
- {0x2c8c, {1|F|D, {0x2c8d}}},
- {0x2c8e, {1|F|D, {0x2c8f}}},
- {0x2c90, {1|F|D, {0x2c91}}},
- {0x2c92, {1|F|D, {0x2c93}}},
- {0x2c94, {1|F|D, {0x2c95}}},
- {0x2c96, {1|F|D, {0x2c97}}},
- {0x2c98, {1|F|D, {0x2c99}}},
- {0x2c9a, {1|F|D, {0x2c9b}}},
- {0x2c9c, {1|F|D, {0x2c9d}}},
- {0x2c9e, {1|F|D, {0x2c9f}}},
- {0x2ca0, {1|F|D, {0x2ca1}}},
- {0x2ca2, {1|F|D, {0x2ca3}}},
- {0x2ca4, {1|F|D, {0x2ca5}}},
- {0x2ca6, {1|F|D, {0x2ca7}}},
- {0x2ca8, {1|F|D, {0x2ca9}}},
- {0x2caa, {1|F|D, {0x2cab}}},
- {0x2cac, {1|F|D, {0x2cad}}},
- {0x2cae, {1|F|D, {0x2caf}}},
- {0x2cb0, {1|F|D, {0x2cb1}}},
- {0x2cb2, {1|F|D, {0x2cb3}}},
- {0x2cb4, {1|F|D, {0x2cb5}}},
- {0x2cb6, {1|F|D, {0x2cb7}}},
- {0x2cb8, {1|F|D, {0x2cb9}}},
- {0x2cba, {1|F|D, {0x2cbb}}},
- {0x2cbc, {1|F|D, {0x2cbd}}},
- {0x2cbe, {1|F|D, {0x2cbf}}},
- {0x2cc0, {1|F|D, {0x2cc1}}},
- {0x2cc2, {1|F|D, {0x2cc3}}},
- {0x2cc4, {1|F|D, {0x2cc5}}},
- {0x2cc6, {1|F|D, {0x2cc7}}},
- {0x2cc8, {1|F|D, {0x2cc9}}},
- {0x2cca, {1|F|D, {0x2ccb}}},
- {0x2ccc, {1|F|D, {0x2ccd}}},
- {0x2cce, {1|F|D, {0x2ccf}}},
- {0x2cd0, {1|F|D, {0x2cd1}}},
- {0x2cd2, {1|F|D, {0x2cd3}}},
- {0x2cd4, {1|F|D, {0x2cd5}}},
- {0x2cd6, {1|F|D, {0x2cd7}}},
- {0x2cd8, {1|F|D, {0x2cd9}}},
- {0x2cda, {1|F|D, {0x2cdb}}},
- {0x2cdc, {1|F|D, {0x2cdd}}},
- {0x2cde, {1|F|D, {0x2cdf}}},
- {0x2ce0, {1|F|D, {0x2ce1}}},
- {0x2ce2, {1|F|D, {0x2ce3}}},
- {0x2ceb, {1|F|D, {0x2cec}}},
- {0x2ced, {1|F|D, {0x2cee}}},
- {0x2cf2, {1|F|D, {0x2cf3}}},
- {0xa640, {1|F|D, {0xa641}}},
- {0xa642, {1|F|D, {0xa643}}},
- {0xa644, {1|F|D, {0xa645}}},
- {0xa646, {1|F|D, {0xa647}}},
- {0xa648, {1|F|D, {0xa649}}},
- {0xa64a, {1|F|D, {0xa64b}}},
- {0xa64c, {1|F|D, {0xa64d}}},
- {0xa64e, {1|F|D, {0xa64f}}},
- {0xa650, {1|F|D, {0xa651}}},
- {0xa652, {1|F|D, {0xa653}}},
- {0xa654, {1|F|D, {0xa655}}},
- {0xa656, {1|F|D, {0xa657}}},
- {0xa658, {1|F|D, {0xa659}}},
- {0xa65a, {1|F|D, {0xa65b}}},
- {0xa65c, {1|F|D, {0xa65d}}},
- {0xa65e, {1|F|D, {0xa65f}}},
- {0xa660, {1|F|D, {0xa661}}},
- {0xa662, {1|F|D, {0xa663}}},
- {0xa664, {1|F|D, {0xa665}}},
- {0xa666, {1|F|D, {0xa667}}},
- {0xa668, {1|F|D, {0xa669}}},
- {0xa66a, {1|F|D, {0xa66b}}},
- {0xa66c, {1|F|D, {0xa66d}}},
- {0xa680, {1|F|D, {0xa681}}},
- {0xa682, {1|F|D, {0xa683}}},
- {0xa684, {1|F|D, {0xa685}}},
- {0xa686, {1|F|D, {0xa687}}},
- {0xa688, {1|F|D, {0xa689}}},
- {0xa68a, {1|F|D, {0xa68b}}},
- {0xa68c, {1|F|D, {0xa68d}}},
- {0xa68e, {1|F|D, {0xa68f}}},
- {0xa690, {1|F|D, {0xa691}}},
- {0xa692, {1|F|D, {0xa693}}},
- {0xa694, {1|F|D, {0xa695}}},
- {0xa696, {1|F|D, {0xa697}}},
- {0xa698, {1|F|D, {0xa699}}},
- {0xa69a, {1|F|D, {0xa69b}}},
- {0xa722, {1|F|D, {0xa723}}},
- {0xa724, {1|F|D, {0xa725}}},
- {0xa726, {1|F|D, {0xa727}}},
- {0xa728, {1|F|D, {0xa729}}},
- {0xa72a, {1|F|D, {0xa72b}}},
- {0xa72c, {1|F|D, {0xa72d}}},
- {0xa72e, {1|F|D, {0xa72f}}},
- {0xa732, {1|F|D, {0xa733}}},
- {0xa734, {1|F|D, {0xa735}}},
- {0xa736, {1|F|D, {0xa737}}},
- {0xa738, {1|F|D, {0xa739}}},
- {0xa73a, {1|F|D, {0xa73b}}},
- {0xa73c, {1|F|D, {0xa73d}}},
- {0xa73e, {1|F|D, {0xa73f}}},
- {0xa740, {1|F|D, {0xa741}}},
- {0xa742, {1|F|D, {0xa743}}},
- {0xa744, {1|F|D, {0xa745}}},
- {0xa746, {1|F|D, {0xa747}}},
- {0xa748, {1|F|D, {0xa749}}},
- {0xa74a, {1|F|D, {0xa74b}}},
- {0xa74c, {1|F|D, {0xa74d}}},
- {0xa74e, {1|F|D, {0xa74f}}},
- {0xa750, {1|F|D, {0xa751}}},
- {0xa752, {1|F|D, {0xa753}}},
- {0xa754, {1|F|D, {0xa755}}},
- {0xa756, {1|F|D, {0xa757}}},
- {0xa758, {1|F|D, {0xa759}}},
- {0xa75a, {1|F|D, {0xa75b}}},
- {0xa75c, {1|F|D, {0xa75d}}},
- {0xa75e, {1|F|D, {0xa75f}}},
- {0xa760, {1|F|D, {0xa761}}},
- {0xa762, {1|F|D, {0xa763}}},
- {0xa764, {1|F|D, {0xa765}}},
- {0xa766, {1|F|D, {0xa767}}},
- {0xa768, {1|F|D, {0xa769}}},
- {0xa76a, {1|F|D, {0xa76b}}},
- {0xa76c, {1|F|D, {0xa76d}}},
- {0xa76e, {1|F|D, {0xa76f}}},
- {0xa779, {1|F|D, {0xa77a}}},
- {0xa77b, {1|F|D, {0xa77c}}},
- {0xa77d, {1|F|D, {0x1d79}}},
- {0xa77e, {1|F|D, {0xa77f}}},
- {0xa780, {1|F|D, {0xa781}}},
- {0xa782, {1|F|D, {0xa783}}},
- {0xa784, {1|F|D, {0xa785}}},
- {0xa786, {1|F|D, {0xa787}}},
- {0xa78b, {1|F|D, {0xa78c}}},
- {0xa78d, {1|F|D, {0x0265}}},
- {0xa790, {1|F|D, {0xa791}}},
- {0xa792, {1|F|D, {0xa793}}},
- {0xa796, {1|F|D, {0xa797}}},
- {0xa798, {1|F|D, {0xa799}}},
- {0xa79a, {1|F|D, {0xa79b}}},
- {0xa79c, {1|F|D, {0xa79d}}},
- {0xa79e, {1|F|D, {0xa79f}}},
- {0xa7a0, {1|F|D, {0xa7a1}}},
- {0xa7a2, {1|F|D, {0xa7a3}}},
- {0xa7a4, {1|F|D, {0xa7a5}}},
- {0xa7a6, {1|F|D, {0xa7a7}}},
- {0xa7a8, {1|F|D, {0xa7a9}}},
- {0xa7aa, {1|F|D, {0x0266}}},
- {0xa7ab, {1|F|D, {0x025c}}},
- {0xa7ac, {1|F|D, {0x0261}}},
- {0xa7ad, {1|F|D, {0x026c}}},
- {0xa7ae, {1|F|D, {0x026a}}},
- {0xa7b0, {1|F|D, {0x029e}}},
- {0xa7b1, {1|F|D, {0x0287}}},
- {0xa7b2, {1|F|D, {0x029d}}},
- {0xa7b3, {1|F|D, {0xab53}}},
- {0xa7b4, {1|F|D, {0xa7b5}}},
- {0xa7b6, {1|F|D, {0xa7b7}}},
- {0xa7b8, {1|F|D, {0xa7b9}}},
- {0xa7ba, {1|F|D, {0xa7bb}}},
- {0xa7bc, {1|F|D, {0xa7bd}}},
- {0xa7be, {1|F|D, {0xa7bf}}},
- {0xa7c0, {1|F|D, {0xa7c1}}},
- {0xa7c2, {1|F|D, {0xa7c3}}},
- {0xa7c4, {1|F|D, {0xa794}}},
- {0xa7c5, {1|F|D, {0x0282}}},
- {0xa7c6, {1|F|D, {0x1d8e}}},
- {0xa7c7, {1|F|D, {0xa7c8}}},
- {0xa7c9, {1|F|D, {0xa7ca}}},
- {0xa7d0, {1|F|D, {0xa7d1}}},
- {0xa7d6, {1|F|D, {0xa7d7}}},
- {0xa7d8, {1|F|D, {0xa7d9}}},
- {0xa7f5, {1|F|D, {0xa7f6}}},
- {0xab70, {1|F|U, {0x13a0}}},
- {0xab71, {1|F|U, {0x13a1}}},
- {0xab72, {1|F|U, {0x13a2}}},
- {0xab73, {1|F|U, {0x13a3}}},
- {0xab74, {1|F|U, {0x13a4}}},
- {0xab75, {1|F|U, {0x13a5}}},
- {0xab76, {1|F|U, {0x13a6}}},
- {0xab77, {1|F|U, {0x13a7}}},
- {0xab78, {1|F|U, {0x13a8}}},
- {0xab79, {1|F|U, {0x13a9}}},
- {0xab7a, {1|F|U, {0x13aa}}},
- {0xab7b, {1|F|U, {0x13ab}}},
- {0xab7c, {1|F|U, {0x13ac}}},
- {0xab7d, {1|F|U, {0x13ad}}},
- {0xab7e, {1|F|U, {0x13ae}}},
- {0xab7f, {1|F|U, {0x13af}}},
- {0xab80, {1|F|U, {0x13b0}}},
- {0xab81, {1|F|U, {0x13b1}}},
- {0xab82, {1|F|U, {0x13b2}}},
- {0xab83, {1|F|U, {0x13b3}}},
- {0xab84, {1|F|U, {0x13b4}}},
- {0xab85, {1|F|U, {0x13b5}}},
- {0xab86, {1|F|U, {0x13b6}}},
- {0xab87, {1|F|U, {0x13b7}}},
- {0xab88, {1|F|U, {0x13b8}}},
- {0xab89, {1|F|U, {0x13b9}}},
- {0xab8a, {1|F|U, {0x13ba}}},
- {0xab8b, {1|F|U, {0x13bb}}},
- {0xab8c, {1|F|U, {0x13bc}}},
- {0xab8d, {1|F|U, {0x13bd}}},
- {0xab8e, {1|F|U, {0x13be}}},
- {0xab8f, {1|F|U, {0x13bf}}},
- {0xab90, {1|F|U, {0x13c0}}},
- {0xab91, {1|F|U, {0x13c1}}},
- {0xab92, {1|F|U, {0x13c2}}},
- {0xab93, {1|F|U, {0x13c3}}},
- {0xab94, {1|F|U, {0x13c4}}},
- {0xab95, {1|F|U, {0x13c5}}},
- {0xab96, {1|F|U, {0x13c6}}},
- {0xab97, {1|F|U, {0x13c7}}},
- {0xab98, {1|F|U, {0x13c8}}},
- {0xab99, {1|F|U, {0x13c9}}},
- {0xab9a, {1|F|U, {0x13ca}}},
- {0xab9b, {1|F|U, {0x13cb}}},
- {0xab9c, {1|F|U, {0x13cc}}},
- {0xab9d, {1|F|U, {0x13cd}}},
- {0xab9e, {1|F|U, {0x13ce}}},
- {0xab9f, {1|F|U, {0x13cf}}},
- {0xaba0, {1|F|U, {0x13d0}}},
- {0xaba1, {1|F|U, {0x13d1}}},
- {0xaba2, {1|F|U, {0x13d2}}},
- {0xaba3, {1|F|U, {0x13d3}}},
- {0xaba4, {1|F|U, {0x13d4}}},
- {0xaba5, {1|F|U, {0x13d5}}},
- {0xaba6, {1|F|U, {0x13d6}}},
- {0xaba7, {1|F|U, {0x13d7}}},
- {0xaba8, {1|F|U, {0x13d8}}},
- {0xaba9, {1|F|U, {0x13d9}}},
- {0xabaa, {1|F|U, {0x13da}}},
- {0xabab, {1|F|U, {0x13db}}},
- {0xabac, {1|F|U, {0x13dc}}},
- {0xabad, {1|F|U, {0x13dd}}},
- {0xabae, {1|F|U, {0x13de}}},
- {0xabaf, {1|F|U, {0x13df}}},
- {0xabb0, {1|F|U, {0x13e0}}},
- {0xabb1, {1|F|U, {0x13e1}}},
- {0xabb2, {1|F|U, {0x13e2}}},
- {0xabb3, {1|F|U, {0x13e3}}},
- {0xabb4, {1|F|U, {0x13e4}}},
- {0xabb5, {1|F|U, {0x13e5}}},
- {0xabb6, {1|F|U, {0x13e6}}},
- {0xabb7, {1|F|U, {0x13e7}}},
- {0xabb8, {1|F|U, {0x13e8}}},
- {0xabb9, {1|F|U, {0x13e9}}},
- {0xabba, {1|F|U, {0x13ea}}},
- {0xabbb, {1|F|U, {0x13eb}}},
- {0xabbc, {1|F|U, {0x13ec}}},
- {0xabbd, {1|F|U, {0x13ed}}},
- {0xabbe, {1|F|U, {0x13ee}}},
- {0xabbf, {1|F|U, {0x13ef}}},
- {0xfb00, {2|F|ST|SU|I(366), {0x0066, 0x0066}}},
- {0xfb01, {2|F|ST|SU|I(370), {0x0066, 0x0069}}},
- {0xfb02, {2|F|ST|SU|I(374), {0x0066, 0x006c}}},
- {0xfb03, {3|F|ST|SU|I(378), {0x0066, 0x0066, 0x0069}}},
- {0xfb04, {3|F|ST|SU|I(384), {0x0066, 0x0066, 0x006c}}},
- {0xfb05, {2|F|ST|SU|I(390), {0x0073, 0x0074}}},
- {0xfb06, {2|F|ST|SU|I(394), {0x0073, 0x0074}}},
- {0xfb13, {2|F|ST|SU|I(398), {0x0574, 0x0576}}},
- {0xfb14, {2|F|ST|SU|I(402), {0x0574, 0x0565}}},
- {0xfb15, {2|F|ST|SU|I(406), {0x0574, 0x056b}}},
- {0xfb16, {2|F|ST|SU|I(410), {0x057e, 0x0576}}},
- {0xfb17, {2|F|ST|SU|I(414), {0x0574, 0x056d}}},
- {0xff21, {1|F|D, {0xff41}}},
- {0xff22, {1|F|D, {0xff42}}},
- {0xff23, {1|F|D, {0xff43}}},
- {0xff24, {1|F|D, {0xff44}}},
- {0xff25, {1|F|D, {0xff45}}},
- {0xff26, {1|F|D, {0xff46}}},
- {0xff27, {1|F|D, {0xff47}}},
- {0xff28, {1|F|D, {0xff48}}},
- {0xff29, {1|F|D, {0xff49}}},
- {0xff2a, {1|F|D, {0xff4a}}},
- {0xff2b, {1|F|D, {0xff4b}}},
- {0xff2c, {1|F|D, {0xff4c}}},
- {0xff2d, {1|F|D, {0xff4d}}},
- {0xff2e, {1|F|D, {0xff4e}}},
- {0xff2f, {1|F|D, {0xff4f}}},
- {0xff30, {1|F|D, {0xff50}}},
- {0xff31, {1|F|D, {0xff51}}},
- {0xff32, {1|F|D, {0xff52}}},
- {0xff33, {1|F|D, {0xff53}}},
- {0xff34, {1|F|D, {0xff54}}},
- {0xff35, {1|F|D, {0xff55}}},
- {0xff36, {1|F|D, {0xff56}}},
- {0xff37, {1|F|D, {0xff57}}},
- {0xff38, {1|F|D, {0xff58}}},
- {0xff39, {1|F|D, {0xff59}}},
- {0xff3a, {1|F|D, {0xff5a}}},
- {0x10400, {1|F|D, {0x10428}}},
- {0x10401, {1|F|D, {0x10429}}},
- {0x10402, {1|F|D, {0x1042a}}},
- {0x10403, {1|F|D, {0x1042b}}},
- {0x10404, {1|F|D, {0x1042c}}},
- {0x10405, {1|F|D, {0x1042d}}},
- {0x10406, {1|F|D, {0x1042e}}},
- {0x10407, {1|F|D, {0x1042f}}},
- {0x10408, {1|F|D, {0x10430}}},
- {0x10409, {1|F|D, {0x10431}}},
- {0x1040a, {1|F|D, {0x10432}}},
- {0x1040b, {1|F|D, {0x10433}}},
- {0x1040c, {1|F|D, {0x10434}}},
- {0x1040d, {1|F|D, {0x10435}}},
- {0x1040e, {1|F|D, {0x10436}}},
- {0x1040f, {1|F|D, {0x10437}}},
- {0x10410, {1|F|D, {0x10438}}},
- {0x10411, {1|F|D, {0x10439}}},
- {0x10412, {1|F|D, {0x1043a}}},
- {0x10413, {1|F|D, {0x1043b}}},
- {0x10414, {1|F|D, {0x1043c}}},
- {0x10415, {1|F|D, {0x1043d}}},
- {0x10416, {1|F|D, {0x1043e}}},
- {0x10417, {1|F|D, {0x1043f}}},
- {0x10418, {1|F|D, {0x10440}}},
- {0x10419, {1|F|D, {0x10441}}},
- {0x1041a, {1|F|D, {0x10442}}},
- {0x1041b, {1|F|D, {0x10443}}},
- {0x1041c, {1|F|D, {0x10444}}},
- {0x1041d, {1|F|D, {0x10445}}},
- {0x1041e, {1|F|D, {0x10446}}},
- {0x1041f, {1|F|D, {0x10447}}},
- {0x10420, {1|F|D, {0x10448}}},
- {0x10421, {1|F|D, {0x10449}}},
- {0x10422, {1|F|D, {0x1044a}}},
- {0x10423, {1|F|D, {0x1044b}}},
- {0x10424, {1|F|D, {0x1044c}}},
- {0x10425, {1|F|D, {0x1044d}}},
- {0x10426, {1|F|D, {0x1044e}}},
- {0x10427, {1|F|D, {0x1044f}}},
- {0x104b0, {1|F|D, {0x104d8}}},
- {0x104b1, {1|F|D, {0x104d9}}},
- {0x104b2, {1|F|D, {0x104da}}},
- {0x104b3, {1|F|D, {0x104db}}},
- {0x104b4, {1|F|D, {0x104dc}}},
- {0x104b5, {1|F|D, {0x104dd}}},
- {0x104b6, {1|F|D, {0x104de}}},
- {0x104b7, {1|F|D, {0x104df}}},
- {0x104b8, {1|F|D, {0x104e0}}},
- {0x104b9, {1|F|D, {0x104e1}}},
- {0x104ba, {1|F|D, {0x104e2}}},
- {0x104bb, {1|F|D, {0x104e3}}},
- {0x104bc, {1|F|D, {0x104e4}}},
- {0x104bd, {1|F|D, {0x104e5}}},
- {0x104be, {1|F|D, {0x104e6}}},
- {0x104bf, {1|F|D, {0x104e7}}},
- {0x104c0, {1|F|D, {0x104e8}}},
- {0x104c1, {1|F|D, {0x104e9}}},
- {0x104c2, {1|F|D, {0x104ea}}},
- {0x104c3, {1|F|D, {0x104eb}}},
- {0x104c4, {1|F|D, {0x104ec}}},
- {0x104c5, {1|F|D, {0x104ed}}},
- {0x104c6, {1|F|D, {0x104ee}}},
- {0x104c7, {1|F|D, {0x104ef}}},
- {0x104c8, {1|F|D, {0x104f0}}},
- {0x104c9, {1|F|D, {0x104f1}}},
- {0x104ca, {1|F|D, {0x104f2}}},
- {0x104cb, {1|F|D, {0x104f3}}},
- {0x104cc, {1|F|D, {0x104f4}}},
- {0x104cd, {1|F|D, {0x104f5}}},
- {0x104ce, {1|F|D, {0x104f6}}},
- {0x104cf, {1|F|D, {0x104f7}}},
- {0x104d0, {1|F|D, {0x104f8}}},
- {0x104d1, {1|F|D, {0x104f9}}},
- {0x104d2, {1|F|D, {0x104fa}}},
- {0x104d3, {1|F|D, {0x104fb}}},
- {0x10570, {1|F|D, {0x10597}}},
- {0x10571, {1|F|D, {0x10598}}},
- {0x10572, {1|F|D, {0x10599}}},
- {0x10573, {1|F|D, {0x1059a}}},
- {0x10574, {1|F|D, {0x1059b}}},
- {0x10575, {1|F|D, {0x1059c}}},
- {0x10576, {1|F|D, {0x1059d}}},
- {0x10577, {1|F|D, {0x1059e}}},
- {0x10578, {1|F|D, {0x1059f}}},
- {0x10579, {1|F|D, {0x105a0}}},
- {0x1057a, {1|F|D, {0x105a1}}},
- {0x1057c, {1|F|D, {0x105a3}}},
- {0x1057d, {1|F|D, {0x105a4}}},
- {0x1057e, {1|F|D, {0x105a5}}},
- {0x1057f, {1|F|D, {0x105a6}}},
- {0x10580, {1|F|D, {0x105a7}}},
- {0x10581, {1|F|D, {0x105a8}}},
- {0x10582, {1|F|D, {0x105a9}}},
- {0x10583, {1|F|D, {0x105aa}}},
- {0x10584, {1|F|D, {0x105ab}}},
- {0x10585, {1|F|D, {0x105ac}}},
- {0x10586, {1|F|D, {0x105ad}}},
- {0x10587, {1|F|D, {0x105ae}}},
- {0x10588, {1|F|D, {0x105af}}},
- {0x10589, {1|F|D, {0x105b0}}},
- {0x1058a, {1|F|D, {0x105b1}}},
- {0x1058c, {1|F|D, {0x105b3}}},
- {0x1058d, {1|F|D, {0x105b4}}},
- {0x1058e, {1|F|D, {0x105b5}}},
- {0x1058f, {1|F|D, {0x105b6}}},
- {0x10590, {1|F|D, {0x105b7}}},
- {0x10591, {1|F|D, {0x105b8}}},
- {0x10592, {1|F|D, {0x105b9}}},
- {0x10594, {1|F|D, {0x105bb}}},
- {0x10595, {1|F|D, {0x105bc}}},
- {0x10c80, {1|F|D, {0x10cc0}}},
- {0x10c81, {1|F|D, {0x10cc1}}},
- {0x10c82, {1|F|D, {0x10cc2}}},
- {0x10c83, {1|F|D, {0x10cc3}}},
- {0x10c84, {1|F|D, {0x10cc4}}},
- {0x10c85, {1|F|D, {0x10cc5}}},
- {0x10c86, {1|F|D, {0x10cc6}}},
- {0x10c87, {1|F|D, {0x10cc7}}},
- {0x10c88, {1|F|D, {0x10cc8}}},
- {0x10c89, {1|F|D, {0x10cc9}}},
- {0x10c8a, {1|F|D, {0x10cca}}},
- {0x10c8b, {1|F|D, {0x10ccb}}},
- {0x10c8c, {1|F|D, {0x10ccc}}},
- {0x10c8d, {1|F|D, {0x10ccd}}},
- {0x10c8e, {1|F|D, {0x10cce}}},
- {0x10c8f, {1|F|D, {0x10ccf}}},
- {0x10c90, {1|F|D, {0x10cd0}}},
- {0x10c91, {1|F|D, {0x10cd1}}},
- {0x10c92, {1|F|D, {0x10cd2}}},
- {0x10c93, {1|F|D, {0x10cd3}}},
- {0x10c94, {1|F|D, {0x10cd4}}},
- {0x10c95, {1|F|D, {0x10cd5}}},
- {0x10c96, {1|F|D, {0x10cd6}}},
- {0x10c97, {1|F|D, {0x10cd7}}},
- {0x10c98, {1|F|D, {0x10cd8}}},
- {0x10c99, {1|F|D, {0x10cd9}}},
- {0x10c9a, {1|F|D, {0x10cda}}},
- {0x10c9b, {1|F|D, {0x10cdb}}},
- {0x10c9c, {1|F|D, {0x10cdc}}},
- {0x10c9d, {1|F|D, {0x10cdd}}},
- {0x10c9e, {1|F|D, {0x10cde}}},
- {0x10c9f, {1|F|D, {0x10cdf}}},
- {0x10ca0, {1|F|D, {0x10ce0}}},
- {0x10ca1, {1|F|D, {0x10ce1}}},
- {0x10ca2, {1|F|D, {0x10ce2}}},
- {0x10ca3, {1|F|D, {0x10ce3}}},
- {0x10ca4, {1|F|D, {0x10ce4}}},
- {0x10ca5, {1|F|D, {0x10ce5}}},
- {0x10ca6, {1|F|D, {0x10ce6}}},
- {0x10ca7, {1|F|D, {0x10ce7}}},
- {0x10ca8, {1|F|D, {0x10ce8}}},
- {0x10ca9, {1|F|D, {0x10ce9}}},
- {0x10caa, {1|F|D, {0x10cea}}},
- {0x10cab, {1|F|D, {0x10ceb}}},
- {0x10cac, {1|F|D, {0x10cec}}},
- {0x10cad, {1|F|D, {0x10ced}}},
- {0x10cae, {1|F|D, {0x10cee}}},
- {0x10caf, {1|F|D, {0x10cef}}},
- {0x10cb0, {1|F|D, {0x10cf0}}},
- {0x10cb1, {1|F|D, {0x10cf1}}},
- {0x10cb2, {1|F|D, {0x10cf2}}},
- {0x118a0, {1|F|D, {0x118c0}}},
- {0x118a1, {1|F|D, {0x118c1}}},
- {0x118a2, {1|F|D, {0x118c2}}},
- {0x118a3, {1|F|D, {0x118c3}}},
- {0x118a4, {1|F|D, {0x118c4}}},
- {0x118a5, {1|F|D, {0x118c5}}},
- {0x118a6, {1|F|D, {0x118c6}}},
- {0x118a7, {1|F|D, {0x118c7}}},
- {0x118a8, {1|F|D, {0x118c8}}},
- {0x118a9, {1|F|D, {0x118c9}}},
- {0x118aa, {1|F|D, {0x118ca}}},
- {0x118ab, {1|F|D, {0x118cb}}},
- {0x118ac, {1|F|D, {0x118cc}}},
- {0x118ad, {1|F|D, {0x118cd}}},
- {0x118ae, {1|F|D, {0x118ce}}},
- {0x118af, {1|F|D, {0x118cf}}},
- {0x118b0, {1|F|D, {0x118d0}}},
- {0x118b1, {1|F|D, {0x118d1}}},
- {0x118b2, {1|F|D, {0x118d2}}},
- {0x118b3, {1|F|D, {0x118d3}}},
- {0x118b4, {1|F|D, {0x118d4}}},
- {0x118b5, {1|F|D, {0x118d5}}},
- {0x118b6, {1|F|D, {0x118d6}}},
- {0x118b7, {1|F|D, {0x118d7}}},
- {0x118b8, {1|F|D, {0x118d8}}},
- {0x118b9, {1|F|D, {0x118d9}}},
- {0x118ba, {1|F|D, {0x118da}}},
- {0x118bb, {1|F|D, {0x118db}}},
- {0x118bc, {1|F|D, {0x118dc}}},
- {0x118bd, {1|F|D, {0x118dd}}},
- {0x118be, {1|F|D, {0x118de}}},
- {0x118bf, {1|F|D, {0x118df}}},
- {0x16e40, {1|F|D, {0x16e60}}},
- {0x16e41, {1|F|D, {0x16e61}}},
- {0x16e42, {1|F|D, {0x16e62}}},
- {0x16e43, {1|F|D, {0x16e63}}},
- {0x16e44, {1|F|D, {0x16e64}}},
- {0x16e45, {1|F|D, {0x16e65}}},
- {0x16e46, {1|F|D, {0x16e66}}},
- {0x16e47, {1|F|D, {0x16e67}}},
- {0x16e48, {1|F|D, {0x16e68}}},
- {0x16e49, {1|F|D, {0x16e69}}},
- {0x16e4a, {1|F|D, {0x16e6a}}},
- {0x16e4b, {1|F|D, {0x16e6b}}},
- {0x16e4c, {1|F|D, {0x16e6c}}},
- {0x16e4d, {1|F|D, {0x16e6d}}},
- {0x16e4e, {1|F|D, {0x16e6e}}},
- {0x16e4f, {1|F|D, {0x16e6f}}},
- {0x16e50, {1|F|D, {0x16e70}}},
- {0x16e51, {1|F|D, {0x16e71}}},
- {0x16e52, {1|F|D, {0x16e72}}},
- {0x16e53, {1|F|D, {0x16e73}}},
- {0x16e54, {1|F|D, {0x16e74}}},
- {0x16e55, {1|F|D, {0x16e75}}},
- {0x16e56, {1|F|D, {0x16e76}}},
- {0x16e57, {1|F|D, {0x16e77}}},
- {0x16e58, {1|F|D, {0x16e78}}},
- {0x16e59, {1|F|D, {0x16e79}}},
- {0x16e5a, {1|F|D, {0x16e7a}}},
- {0x16e5b, {1|F|D, {0x16e7b}}},
- {0x16e5c, {1|F|D, {0x16e7c}}},
- {0x16e5d, {1|F|D, {0x16e7d}}},
- {0x16e5e, {1|F|D, {0x16e7e}}},
- {0x16e5f, {1|F|D, {0x16e7f}}},
- {0x1e900, {1|F|D, {0x1e922}}},
- {0x1e901, {1|F|D, {0x1e923}}},
- {0x1e902, {1|F|D, {0x1e924}}},
- {0x1e903, {1|F|D, {0x1e925}}},
- {0x1e904, {1|F|D, {0x1e926}}},
- {0x1e905, {1|F|D, {0x1e927}}},
- {0x1e906, {1|F|D, {0x1e928}}},
- {0x1e907, {1|F|D, {0x1e929}}},
- {0x1e908, {1|F|D, {0x1e92a}}},
- {0x1e909, {1|F|D, {0x1e92b}}},
- {0x1e90a, {1|F|D, {0x1e92c}}},
- {0x1e90b, {1|F|D, {0x1e92d}}},
- {0x1e90c, {1|F|D, {0x1e92e}}},
- {0x1e90d, {1|F|D, {0x1e92f}}},
- {0x1e90e, {1|F|D, {0x1e930}}},
- {0x1e90f, {1|F|D, {0x1e931}}},
- {0x1e910, {1|F|D, {0x1e932}}},
- {0x1e911, {1|F|D, {0x1e933}}},
- {0x1e912, {1|F|D, {0x1e934}}},
- {0x1e913, {1|F|D, {0x1e935}}},
- {0x1e914, {1|F|D, {0x1e936}}},
- {0x1e915, {1|F|D, {0x1e937}}},
- {0x1e916, {1|F|D, {0x1e938}}},
- {0x1e917, {1|F|D, {0x1e939}}},
- {0x1e918, {1|F|D, {0x1e93a}}},
- {0x1e919, {1|F|D, {0x1e93b}}},
- {0x1e91a, {1|F|D, {0x1e93c}}},
- {0x1e91b, {1|F|D, {0x1e93d}}},
- {0x1e91c, {1|F|D, {0x1e93e}}},
- {0x1e91d, {1|F|D, {0x1e93f}}},
- {0x1e91e, {1|F|D, {0x1e940}}},
- {0x1e91f, {1|F|D, {0x1e941}}},
- {0x1e920, {1|F|D, {0x1e942}}},
- {0x1e921, {1|F|D, {0x1e943}}},
-#define CaseFold_Locale (*(CaseFold_11_Type (*)[2])(CaseFold_11_Table+1528))
- {0x0049, {1|F|D, {0x0069}}},
- {0x0130, {2|F|D, {0x0069, 0x0307}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseFold_11_hash -N onigenc_unicode_CaseFold_11_lookup -n */
-
-/* maximum key range = 3080, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseFold_11_hash(const OnigCodePoint code)
-{
- static const unsigned short asso_values[] =
- {
- 1, 3085, 2, 20, 3, 307, 200, 8, 31, 159,
- 2, 253, 33, 967, 3085, 3085, 3085, 3085, 3085, 3085,
- 3085, 3085, 3085, 3085, 3085, 3085, 3085, 30, 3085, 3085,
- 3085, 3085, 3085, 3085, 3085, 352, 3085, 3085, 3085, 3085,
- 3085, 93, 3085, 3085, 3085, 3085, 3085, 3085, 3085, 3085,
- 3085, 407, 3085, 3085, 3085, 3085, 3085, 3085, 3085, 201,
- 3085, 3085, 14, 13, 373, 1, 3085, 3085, 503, 19,
- 3085, 3085, 3085, 3085, 3085, 325, 3085, 3085, 290, 1064,
- 484, 28, 1906, 447, 272, 414, 2002, 79, 905, 5,
- 11, 22, 2024, 623, 761, 617, 1893, 45, 1874, 113,
- 1856, 255, 1823, 96, 1463, 62, 1841, 130, 1798, 331,
- 1771, 238, 1977, 147, 1387, 464, 1691, 187, 1639, 181,
- 366, 580, 1331, 508, 1287, 547, 1583, 541, 400, 783,
- 1944, 657, 1850, 932, 1785, 858, 1645, 681, 1412, 722,
- 1622, 972, 1306, 807, 1942, 1282, 283, 1218, 1557, 1055,
- 1406, 1258, 1401, 1168, 1327, 864, 893, 1123, 1714, 1195,
- 1885, 1083, 2016, 1232, 823, 678, 1420, 1017, 155, 1261,
- 86, 1351, 794, 1929, 51, 1525, 50, 221, 4, 1383,
- 196, 325, 1, 1562, 102, 1441, 3, 1356, 226, 1304,
- 271, 1516, 68, 1752, 37, 1469, 51, 1920, 143, 2059,
- 198, 2095, 370, 2069, 137, 718, 407, 1926, 136
- };
- return asso_values[bits_of(code, 2)+81] + asso_values[bits_of(code, 1)+2] + asso_values[bits_of(code, 0)];
-}
-
-static const CodePointList3 *
-onigenc_unicode_CaseFold_11_lookup(const OnigCodePoint code)
-{
- enum
- {
- MIN_CODE_VALUE = 0x41,
- MAX_CODE_VALUE = 0x1e921,
- TOTAL_KEYWORDS = 1530,
- MIN_WORD_LENGTH = 3,
- MAX_WORD_LENGTH = 3,
- MIN_HASH_VALUE = 5,
- MAX_HASH_VALUE = 3084
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1, -1, -1,
- /*0x1fe9*/ 850,
- -1,
- /*0x1f88*/ 775,
- /*0x0408*/ 305,
- /*0x0108*/ 61,
- /*0x10408*/ 1276,
- -1,
- /*0xab88*/ 1174,
- /*0x1f89*/ 776,
- /*0x0409*/ 306,
- /*0x2c69*/ 964,
- /*0x10409*/ 1277,
- /*0x2c08*/ 919,
- /*0xab89*/ 1175,
- /*0x1e88*/ 653,
- /*0x1e08*/ 589,
- -1, -1,
- /*0x2c09*/ 920,
- /*0x1f8a*/ 777,
- /*0x040a*/ 307,
- /*0x010a*/ 62,
- /*0x1040a*/ 1278,
- /*0x2c88*/ 978,
- /*0xab8a*/ 1176,
- /*0x1f80*/ 767,
- /*0x0400*/ 297,
- /*0x0100*/ 57,
- /*0x10400*/ 1268,
- /*0x2c0a*/ 921,
- /*0xab80*/ 1166,
- /*0x1e8a*/ 654,
- /*0x1e0a*/ 590,
- /*0x10c88*/ 1387,
- /*0x0508*/ 425,
- /*0x2c00*/ 911,
- -1,
- /*0x1e80*/ 649,
- /*0x1e00*/ 585,
- /*0x10c89*/ 1388,
- /*0x2c8a*/ 979,
- -1,
- /*0x1f90*/ 783,
- /*0x0410*/ 313,
- /*0x0110*/ 65,
- /*0x10410*/ 1284,
- /*0x2c80*/ 974,
- /*0xab90*/ 1182,
- /*0x1ff3*/ 855,
- -1,
- /*0x10c8a*/ 1389,
- /*0x050a*/ 426,
- /*0x2c10*/ 927,
- /*0xa780*/ 1106,
- /*0x1e90*/ 657,
- /*0x1e10*/ 593,
- /*0x10c80*/ 1379,
- /*0x0500*/ 421,
- -1,
- /*0x1f98*/ 791,
- /*0x0418*/ 321,
- /*0x0118*/ 69,
- /*0x10418*/ 1292,
- /*0x2c90*/ 982,
- /*0xab98*/ 1190,
- -1,
- /*0x00df*/ 56,
- /*0x00dd*/ 54,
- /*0x10571*/ 1345,
- /*0x2c18*/ 935,
- /*0xa790*/ 1112,
- /*0x1e98*/ 662,
- /*0x1e18*/ 597,
- /*0x10c90*/ 1395,
- /*0x0510*/ 429,
- /*0x2c6f*/ 968,
- /*0x1f86*/ 773,
- /*0x0406*/ 303,
- /*0x0106*/ 60,
- /*0x10406*/ 1274,
- /*0x2c98*/ 986,
- /*0xab86*/ 1172,
- /*0x10573*/ 1347,
- /*0x1fd9*/ 841,
- /*0x0059*/ 23,
- -1,
- /*0x2c06*/ 917,
- /*0xa798*/ 1115,
- /*0x1e86*/ 652,
- /*0x1e06*/ 588,
- /*0x10c98*/ 1403,
- /*0x0518*/ 433,
- -1,
- /*0x1f96*/ 789,
- /*0x0416*/ 319,
- /*0x0116*/ 68,
- /*0x10416*/ 1290,
- /*0x2c86*/ 977,
- /*0xab96*/ 1188,
- /*0x1fe7*/ 848,
- -1, -1,
- /*0x00d9*/ 50,
- /*0x2c16*/ 933,
- /*0xa786*/ 1109,
- /*0x1e96*/ 660,
- /*0x1e16*/ 596,
- /*0x10c86*/ 1385,
- /*0x0506*/ 424,
- /*0x2c67*/ 963,
- /*0x1f92*/ 785,
- /*0x0412*/ 315,
- /*0x0112*/ 66,
- /*0x10412*/ 1286,
- /*0x2c96*/ 985,
- /*0xab92*/ 1184,
- -1, -1, -1, -1,
- /*0x2c12*/ 929,
- /*0xa796*/ 1114,
- /*0x1e92*/ 658,
- /*0x1e12*/ 594,
- /*0x10c96*/ 1401,
- /*0x0516*/ 432,
- -1,
- /*0x1f9a*/ 793,
- /*0x041a*/ 323,
- /*0x011a*/ 70,
- /*0x1041a*/ 1294,
- /*0x2c92*/ 983,
- /*0xab9a*/ 1192,
- -1,
- /*0x1ffb*/ 862,
- /*0x017f*/ 120,
- /*0x017b*/ 118,
- /*0x2c1a*/ 937,
- /*0xa792*/ 1113,
- /*0x1e9a*/ 664,
- /*0x1e1a*/ 598,
- /*0x10c92*/ 1397,
- /*0x0512*/ 430,
- /*0x2c7f*/ 973,
- /*0x1fa0*/ 799,
- /*0x0420*/ 329,
- /*0x0120*/ 73,
- /*0x10420*/ 1300,
- /*0x2c9a*/ 987,
- /*0xaba0*/ 1198,
- /*0x2c75*/ 971,
- -1,
- /*0x1fd7*/ 839,
- /*0x0057*/ 21,
- /*0x2c20*/ 943,
- /*0xa79a*/ 1116,
- /*0x1ea0*/ 667,
- /*0x1e20*/ 601,
- /*0x10c9a*/ 1405,
- /*0x051a*/ 434,
- /*0x0388*/ 235,
- -1, -1,
- /*0x037f*/ 233,
- -1,
- /*0x2ca0*/ 990,
- /*0x0389*/ 236,
- /*0x1057f*/ 1358,
- /*0xa7f5*/ 1149,
- -1, -1, -1,
- /*0xa7a0*/ 1119,
- -1,
- /*0x10575*/ 1349,
- /*0x10ca0*/ 1411,
- /*0x0520*/ 437,
- /*0x038a*/ 237,
- /*0x1fa6*/ 805,
- /*0x0426*/ 335,
- /*0x0126*/ 76,
- /*0x10426*/ 1306,
- -1,
- /*0xaba6*/ 1204,
- /*0x1fa4*/ 803,
- /*0x0424*/ 333,
- /*0x0124*/ 75,
- /*0x10424*/ 1304,
- /*0x2c26*/ 949,
- /*0xaba4*/ 1202,
- /*0x1ea6*/ 670,
- /*0x1e26*/ 604,
- /*0x03f1*/ 288,
- /*0x1fe3*/ 845,
- /*0x2c24*/ 947,
- /*0x1ff7*/ 858,
- /*0x1ea4*/ 669,
- /*0x1e24*/ 603,
- -1,
- /*0x2ca6*/ 993,
- /*0x0390*/ 241,
- /*0x0208*/ 194,
- /*0x1c88*/ 538,
- /*0x2c63*/ 961,
- -1,
- /*0x2ca4*/ 992,
- /*0xa7a6*/ 1122,
- -1, -1,
- /*0x10ca6*/ 1417,
- /*0x0526*/ 440,
- -1,
- /*0xa7a4*/ 1121,
- -1, -1,
- /*0x10ca4*/ 1415,
- /*0x0524*/ 439,
- /*0x0398*/ 249,
- /*0x020a*/ 195,
- /*0x0460*/ 345,
- /*0x0160*/ 104,
- -1, -1,
- /*0x1feb*/ 852,
- /*0x0200*/ 190,
- /*0x1c80*/ 530,
- /*0x13fb*/ 527,
- -1,
- /*0x2c60*/ 959,
- /*0x10577*/ 1351,
- /*0x1ee0*/ 699,
- /*0x1e60*/ 633,
- -1,
- /*0x2c6b*/ 965,
- /*0x0386*/ 234,
- /*0x1f9e*/ 797,
- /*0x041e*/ 327,
- /*0x011e*/ 72,
- /*0x1041e*/ 1298,
- /*0x2ce0*/ 1022,
- /*0xab9e*/ 1196,
- /*0x0210*/ 198,
- /*0x1c90*/ 539,
- -1,
- /*0x2ceb*/ 1024,
- /*0x2c1e*/ 941,
- -1,
- /*0x1e9e*/ 666,
- /*0x1e1e*/ 600,
- -1, -1,
- /*0x0396*/ 247,
- /*0x1f94*/ 787,
- /*0x0414*/ 317,
- /*0x0114*/ 67,
- /*0x10414*/ 1288,
- /*0x2c9e*/ 989,
- /*0xab94*/ 1186,
- /*0x0218*/ 202,
- /*0x1c98*/ 547,
- -1, -1,
- /*0x2c14*/ 931,
- /*0xa79e*/ 1118,
- /*0x1e94*/ 659,
- /*0x1e14*/ 595,
- /*0x10c9e*/ 1409,
- /*0x051e*/ 436,
- /*0x0392*/ 243,
- /*0x1f83*/ 770,
- /*0x0403*/ 300,
- /*0x048a*/ 362,
- /*0x10403*/ 1271,
- /*0x2c94*/ 984,
- /*0xab83*/ 1169,
- /*0x0206*/ 193,
- /*0x1c86*/ 536,
- /*0x0480*/ 361,
- /*0x2c6d*/ 966,
- /*0x2c03*/ 914,
- /*0x1e908*/ 1502,
- /*0x0041*/ 0,
- /*0x0141*/ 88,
- /*0x10c94*/ 1399,
- /*0x0514*/ 431,
- /*0x039a*/ 251,
- /*0x1e909*/ 1503,
- /*0x2183*/ 884,
- -1,
- /*0x2ced*/ 1025,
- -1,
- /*0x03ff*/ 296,
- /*0x0216*/ 201,
- /*0x1c96*/ 545,
- /*0x0490*/ 365,
- -1, -1,
- /*0x1e90a*/ 1504,
- /*0x03f5*/ 290,
- /*0x00c1*/ 27,
- /*0x10c83*/ 1382,
- -1,
- /*0x03a0*/ 257,
- /*0x1e900*/ 1494,
- -1, -1, -1, -1, -1,
- /*0x0212*/ 199,
- /*0x1c92*/ 541,
- /*0x0498*/ 369,
- /*0x0541*/ 461,
- -1,
- /*0x0189*/ 126,
- -1, -1, -1, -1, -1,
- /*0x1e910*/ 1510,
- -1,
- /*0x1fe4*/ 846,
- /*0x0464*/ 347,
- /*0x0164*/ 106,
- /*0x018a*/ 127,
- /*0x021a*/ 203,
- /*0x1c9a*/ 549,
- /*0x1f9c*/ 795,
- /*0x041c*/ 325,
- /*0x011c*/ 71,
- /*0x1041c*/ 1296,
- /*0x2c64*/ 962,
- /*0xab9c*/ 1194,
- /*0x1ee4*/ 701,
- /*0x1e64*/ 635,
- /*0x03a6*/ 262,
- /*0x1e918*/ 1518,
- /*0x2c1c*/ 939,
- -1,
- /*0x01f1*/ 181,
- /*0x1e1c*/ 599,
- /*0x03a4*/ 260,
- /*0x0220*/ 206,
- /*0x1ca0*/ 555,
- /*0x0496*/ 368,
- -1, -1,
- /*0x0190*/ 131,
- /*0x2c9c*/ 988,
- -1, -1, -1,
- /*0x03f7*/ 291,
- /*0x1e906*/ 1500,
- -1,
- /*0xa79c*/ 1117,
- -1, -1,
- /*0x10c9c*/ 1407,
- /*0x051c*/ 435,
- -1,
- /*0x0492*/ 366,
- /*0x1fa7*/ 806,
- /*0x0427*/ 336,
- /*0x0198*/ 137,
- /*0x10427*/ 1307,
- /*0x1ff9*/ 860,
- /*0xaba7*/ 1205,
- /*0x0179*/ 117,
- -1,
- /*0x1e916*/ 1516,
- /*0x1f69*/ 760,
- /*0x2c27*/ 950,
- /*0x1f08*/ 715,
- -1,
- /*0x03e0*/ 279,
- /*0x0226*/ 209,
- /*0x1ca6*/ 561,
- /*0x049a*/ 370,
- /*0x1f09*/ 716,
- -1,
- /*0x0186*/ 124,
- /*0x0224*/ 208,
- /*0x1ca4*/ 559,
- -1, -1, -1,
- /*0x1e912*/ 1512,
- /*0x01d9*/ 169,
- -1,
- /*0x1f0a*/ 717,
- -1,
- /*0x039e*/ 255,
- /*0x10ca7*/ 1418,
- -1,
- /*0x04a0*/ 373,
- /*0x1faf*/ 814,
- /*0x042f*/ 344,
- /*0x0196*/ 135,
- -1,
- /*0x10579*/ 1353,
- /*0xabaf*/ 1213,
- -1, -1,
- /*0x1e91a*/ 1520,
- /*0x017d*/ 119,
- /*0x2c2f*/ 958,
- -1,
- /*0xfb00*/ 1230,
- /*0x0394*/ 245,
- /*0x1f84*/ 771,
- /*0x0404*/ 301,
- /*0x0104*/ 59,
- /*0x10404*/ 1272,
- -1,
- /*0xab84*/ 1170,
- -1, -1,
- /*0x1f5f*/ 758,
- /*0x1f5d*/ 757,
- /*0x2c04*/ 915,
- /*0x1e920*/ 1526,
- /*0x1e84*/ 651,
- /*0x1e04*/ 587,
- -1, -1, -1,
- /*0x10caf*/ 1426,
- -1,
- /*0x04a6*/ 376,
- /*0x1f18*/ 723,
- /*0x2c84*/ 976,
- -1,
- /*0x021e*/ 205,
- /*0x1c9e*/ 553,
- /*0x04a4*/ 375,
- /*0x1f6f*/ 766,
- /*0x1057d*/ 1356,
- /*0xa784*/ 1108,
- -1, -1,
- /*0x10c84*/ 1383,
- /*0x0504*/ 423,
- /*0x1f82*/ 769,
- /*0x0402*/ 299,
- /*0x0102*/ 58,
- /*0x10402*/ 1270,
- -1,
- /*0xab82*/ 1168,
- /*0x01a0*/ 141,
- /*0x0214*/ 200,
- /*0x1c94*/ 543,
- -1,
- /*0x2c02*/ 913,
- /*0x1f59*/ 755,
- /*0x1e82*/ 650,
- /*0x1e02*/ 586,
- /*0x01d7*/ 168,
- /*0x13f9*/ 525,
- /*0xfb06*/ 1236,
- /*0x1fa2*/ 801,
- /*0x0422*/ 331,
- /*0x0122*/ 74,
- /*0x10422*/ 1302,
- /*0x2c82*/ 975,
- /*0xaba2*/ 1200,
- -1, -1,
- /*0x1c83*/ 533,
- /*0x04e0*/ 405,
- /*0x2c22*/ 945,
- /*0xa782*/ 1107,
- /*0x1ea2*/ 668,
- /*0x1e22*/ 602,
- /*0x10c82*/ 1381,
- /*0x0502*/ 422,
- /*0xfb16*/ 1240,
- -1,
- /*0x0241*/ 220,
- /*0x03e4*/ 281,
- -1,
- /*0x2ca2*/ 991,
- -1,
- /*0x01a6*/ 144,
- -1,
- /*0x039c*/ 253,
- /*0x049e*/ 372,
- -1,
- /*0xa7a2*/ 1120,
- /*0x01a4*/ 143,
- -1,
- /*0x10ca2*/ 1413,
- /*0x0522*/ 438,
- -1,
- /*0x10a0*/ 484,
- /*0x13fd*/ 529,
- -1, -1,
- /*0x1f1a*/ 725,
- /*0x2165*/ 873,
- /*0x01f7*/ 185,
- /*0x2169*/ 877,
- /*0x2161*/ 869,
- /*0x0494*/ 367,
- /*0x1faa*/ 809,
- /*0x042a*/ 339,
- /*0x012a*/ 78,
- /*0xa660*/ 1043,
- -1,
- /*0xabaa*/ 1208,
- -1, -1,
- /*0x1e91e*/ 1524,
- -1,
- /*0x2c2a*/ 953,
- -1,
- /*0x1eaa*/ 672,
- /*0x1e2a*/ 606,
- -1, -1,
- /*0x03a7*/ 263,
- -1, -1,
- /*0x01e0*/ 172,
- /*0x03f9*/ 292,
- /*0x2caa*/ 995,
- /*0x021c*/ 204,
- /*0x1c9c*/ 551,
- /*0x10a6*/ 490,
- /*0x1e914*/ 1514,
- -1,
- /*0x04c1*/ 390,
- /*0xa7aa*/ 1124,
- /*0x104c1*/ 1325,
- /*0x10a4*/ 488,
- /*0x10caa*/ 1421,
- /*0x052a*/ 442,
- /*0x1fae*/ 813,
- /*0x042e*/ 343,
- /*0x012e*/ 80,
- -1, -1,
- /*0xabae*/ 1212,
- /*0x1fac*/ 811,
- /*0x042c*/ 341,
- /*0x012c*/ 79,
- /*0x1e903*/ 1497,
- /*0x2c2e*/ 957,
- /*0xabac*/ 1210,
- /*0x1eae*/ 674,
- /*0x1e2e*/ 608,
- /*0x118a0*/ 1430,
- -1,
- /*0x2c2c*/ 955,
- -1,
- /*0x1eac*/ 673,
- /*0x1e2c*/ 607,
- /*0x0194*/ 134,
- /*0x2cae*/ 997,
- -1, -1,
- /*0x03fd*/ 294,
- /*0x1ca7*/ 562,
- -1,
- /*0x2cac*/ 996,
- /*0xa7ae*/ 1128,
- /*0x216f*/ 883,
- -1,
- /*0x10cae*/ 1425,
- /*0x052e*/ 444,
- -1,
- /*0xa7ac*/ 1126,
- -1,
- /*0x04e4*/ 407,
- /*0x10cac*/ 1423,
- /*0x052c*/ 443,
- /*0x1fa8*/ 807,
- /*0x0428*/ 337,
- /*0x0128*/ 77,
- /*0x049c*/ 371,
- -1,
- /*0xaba8*/ 1206,
- -1, -1, -1,
- /*0x118a6*/ 1436,
- /*0x2c28*/ 951,
- -1,
- /*0x1ea8*/ 671,
- /*0x1e28*/ 605,
- -1,
- /*0x118a4*/ 1434,
- -1, -1,
- /*0x1f6b*/ 762,
- /*0xff26*/ 1247,
- /*0x1caf*/ 570,
- /*0x2ca8*/ 994,
- -1, -1,
- /*0x2167*/ 875,
- /*0xff24*/ 1245,
- -1,
- /*0x24c1*/ 896,
- /*0xa7a8*/ 1123,
- /*0x1e91c*/ 1522,
- -1,
- /*0x10ca8*/ 1419,
- /*0x0528*/ 441,
- /*0x0204*/ 192,
- /*0x1c84*/ 534,
- /*0xa664*/ 1045,
- -1,
- /*0x1f8e*/ 781,
- /*0x040e*/ 311,
- /*0x010e*/ 64,
- /*0x1040e*/ 1282,
- /*0xa77b*/ 1103,
- /*0xab8e*/ 1180,
- /*0x1f8c*/ 779,
- /*0x040c*/ 309,
- /*0x010c*/ 63,
- /*0x1040c*/ 1280,
- /*0x2c0e*/ 925,
- /*0xab8c*/ 1178,
- /*0x1e8e*/ 656,
- /*0x1e0e*/ 592,
- /*0x01e4*/ 174,
- -1,
- /*0x2c0c*/ 923,
- /*0x10c1*/ 517,
- /*0x1e8c*/ 655,
- /*0x1e0c*/ 591,
- /*0x019c*/ 138,
- /*0x2c8e*/ 981,
- /*0xfb14*/ 1238,
- -1, -1, -1,
- /*0x1f6d*/ 764,
- /*0x2c8c*/ 980,
- -1,
- /*0x0202*/ 191,
- /*0x1c82*/ 532,
- /*0x10c8e*/ 1393,
- /*0x050e*/ 428,
- -1, -1, -1, -1,
- /*0x10c8c*/ 1391,
- /*0x050c*/ 427,
- /*0xfb03*/ 1233,
- /*0x1fb2*/ 815,
- -1,
- /*0x0132*/ 81,
- -1, -1,
- /*0xabb2*/ 1216,
- /*0x0222*/ 207,
- /*0x1ca2*/ 557,
- /*0xa726*/ 1066,
- /*0x03aa*/ 266,
- -1, -1,
- /*0x1eb2*/ 676,
- /*0x1e32*/ 610,
- /*0xa724*/ 1065,
- /*0x01a7*/ 145,
- -1, -1, -1, -1, -1,
- /*0x2cb2*/ 999,
- /*0x0054*/ 18,
- /*0x0154*/ 98,
- /*0x1fb8*/ 820,
- -1,
- /*0x2126*/ 864,
- -1,
- /*0xa7b2*/ 1131,
- /*0xabb8*/ 1222,
- -1,
- /*0x10cb2*/ 1429,
- /*0x0532*/ 446,
- /*0x1ed4*/ 693,
- /*0x1e54*/ 627,
- /*0x1e904*/ 1498,
- /*0x1eb8*/ 679,
- /*0x1e38*/ 613,
- -1, -1,
- /*0x00d4*/ 46,
- /*0x2163*/ 871,
- /*0x2cd4*/ 1016,
- -1, -1,
- /*0x2cb8*/ 1002,
- /*0x1f1c*/ 727,
- -1,
- /*0xa760*/ 1094,
- /*0x01af*/ 149,
- /*0x022a*/ 211,
- /*0x1caa*/ 565,
- /*0xa7b8*/ 1135,
- /*0x0554*/ 480,
- -1, -1,
- /*0x0538*/ 452,
- -1, -1,
- /*0x04a2*/ 374,
- /*0x10a7*/ 491,
- /*0x1ffc*/ 863,
- /*0x047c*/ 359,
- /*0x0184*/ 123,
- -1,
- /*0x1fba*/ 822,
- /*0x2160*/ 868,
- -1,
- /*0x1e902*/ 1496,
- -1,
- /*0xabba*/ 1224,
- /*0x216b*/ 879,
- -1,
- /*0x1efc*/ 713,
- /*0x1e7c*/ 647,
- -1, -1,
- /*0x1eba*/ 680,
- /*0x1e3a*/ 614,
- -1, -1,
- /*0x03a8*/ 264,
- -1,
- /*0x022e*/ 213,
- /*0x1cae*/ 569,
- -1,
- /*0x2cba*/ 1003,
- -1, -1,
- /*0x022c*/ 212,
- /*0x1cac*/ 567,
- -1, -1,
- /*0xa7ba*/ 1136,
- /*0x10af*/ 499,
- /*0x1057c*/ 1355,
- /*0x0182*/ 122,
- /*0x053a*/ 454,
- -1, -1, -1, -1, -1,
- /*0x04aa*/ 378,
- /*0x1f8d*/ 780,
- /*0x040d*/ 310,
- -1,
- /*0x1040d*/ 1281,
- -1,
- /*0xab8d*/ 1179,
- -1, -1, -1,
- /*0x01a2*/ 142,
- /*0x2c0d*/ 924,
- /*0x1f2f*/ 736,
- /*0x216d*/ 881,
- /*0x118a7*/ 1437,
- /*0x038e*/ 239,
- -1, -1, -1,
- /*0x0228*/ 210,
- /*0x1ca8*/ 563,
- /*0x038c*/ 238,
- -1, -1,
- /*0xff27*/ 1248,
- /*0x0130*/ 1529,
- -1, -1,
- /*0xabb0*/ 1214,
- /*0xa78d*/ 1111,
- -1, -1,
- /*0x10c8d*/ 1392,
- /*0x04ae*/ 380,
- /*0x1fdb*/ 843,
- /*0x1eb0*/ 675,
- /*0x1e30*/ 609,
- -1,
- /*0xfb04*/ 1234,
- /*0x04ac*/ 379,
- -1, -1, -1, -1,
- /*0x2cb0*/ 998,
- -1, -1,
- /*0x1fbe*/ 825,
- /*0x118af*/ 1445,
- /*0xa764*/ 1096,
- /*0x13fc*/ 528,
- /*0xa7b0*/ 1129,
- /*0xabbe*/ 1228,
- /*0x00db*/ 52,
- /*0x10cb0*/ 1427,
- /*0x10a2*/ 486,
- /*0x020e*/ 197,
- -1,
- /*0xff2f*/ 1256,
- /*0x1ebe*/ 682,
- /*0x1e3e*/ 616,
- -1,
- /*0x020c*/ 196,
- /*0x1fd3*/ 837,
- /*0x0053*/ 17,
- -1, -1,
- /*0x2164*/ 872,
- /*0x2cbe*/ 1005,
- -1, -1,
- /*0xfb02*/ 1232,
- /*0x04a8*/ 377,
- -1, -1,
- /*0xa7be*/ 1138,
- -1, -1, -1,
- /*0x053e*/ 458,
- -1, -1,
- /*0x00d3*/ 45,
- -1, -1, -1, -1,
- /*0x01ae*/ 148,
- -1, -1, -1, -1, -1,
- /*0x01ac*/ 147,
- /*0xa779*/ 1102,
- /*0x0553*/ 479,
- /*0x0232*/ 215,
- /*0x1cb2*/ 573,
- /*0x1fb6*/ 818,
- /*0x10aa*/ 494,
- /*0x0136*/ 83,
- -1, -1,
- /*0xabb6*/ 1220,
- /*0x1fca*/ 833,
- /*0x004a*/ 8,
- /*0x014a*/ 93,
- -1, -1,
- /*0x048e*/ 364,
- /*0x1eb6*/ 678,
- /*0x1e36*/ 612,
- /*0x118a2*/ 1432,
- -1, -1,
- /*0x048c*/ 363,
- /*0x1eca*/ 688,
- /*0x1e4a*/ 622,
- -1,
- /*0x2cb6*/ 1001,
- /*0x1f2a*/ 731,
- /*0x1cb8*/ 579,
- /*0xff22*/ 1243,
- /*0x00ca*/ 36,
- -1,
- /*0x2cca*/ 1011,
- /*0xa7b6*/ 1134,
- -1, -1, -1,
- /*0x0536*/ 450,
- /*0xa77d*/ 1104,
- /*0x10ae*/ 498,
- /*0x1fcb*/ 834,
- /*0x004b*/ 9,
- /*0x1e90e*/ 1508,
- /*0x054a*/ 470,
- -1,
- /*0x10ac*/ 496,
- -1, -1,
- /*0x1e90c*/ 1506,
- -1, -1, -1,
- /*0x1f87*/ 774,
- /*0x0407*/ 304,
- -1,
- /*0x10407*/ 1275,
- /*0x04b2*/ 382,
- /*0xab87*/ 1173,
- /*0x104b2*/ 1310,
- /*0x00cb*/ 37,
- /*0x1f2e*/ 735,
- -1,
- /*0x2c07*/ 918,
- /*0x118aa*/ 1440,
- -1, -1,
- /*0x1f2c*/ 733,
- -1,
- /*0x023a*/ 216,
- /*0x1cba*/ 581,
- /*0x018e*/ 129,
- -1,
- /*0x054b*/ 471,
- /*0xff2a*/ 1251,
- -1, -1, -1,
- /*0x04d4*/ 399,
- /*0x10a8*/ 492,
- /*0x1fb4*/ 817,
- /*0x04b8*/ 385,
- /*0x0134*/ 82,
- /*0x104b8*/ 1316,
- /*0x10c87*/ 1386,
- /*0xabb4*/ 1218,
- -1, -1, -1,
- /*0x03b0*/ 268,
- /*0xab71*/ 1151,
- -1,
- /*0x1eb4*/ 677,
- /*0x1e34*/ 611,
- -1, -1,
- /*0xa722*/ 1064,
- /*0x118ae*/ 1444,
- -1, -1,
- /*0x1f28*/ 729,
- /*0x2cb4*/ 1000,
- -1,
- /*0x118ac*/ 1442,
- /*0xab73*/ 1153,
- -1, -1,
- /*0xff2e*/ 1255,
- /*0xa7b4*/ 1133,
- -1, -1,
- /*0x01b2*/ 151,
- /*0x0534*/ 448,
- /*0xff2c*/ 1253,
- -1, -1,
- /*0xa654*/ 1037,
- -1,
- /*0x04fc*/ 419,
- -1,
- /*0x1fbc*/ 824,
- /*0x10588*/ 1367,
- /*0x04ba*/ 386,
- -1,
- /*0x104ba*/ 1318,
- /*0xabbc*/ 1226,
- -1,
- /*0x10589*/ 1368,
- -1, -1,
- /*0x0230*/ 214,
- /*0x1cb0*/ 571,
- /*0x1ebc*/ 681,
- /*0x1e3c*/ 615,
- -1,
- /*0x01b8*/ 155,
- /*0x118a8*/ 1438,
- /*0x1f0e*/ 721,
- /*0x1058a*/ 1369,
- -1,
- /*0xa72a*/ 1068,
- /*0x2cbc*/ 1004,
- -1,
- /*0x1f0c*/ 719,
- /*0x10580*/ 1359,
- -1,
- /*0xff28*/ 1249,
- -1,
- /*0xa7bc*/ 1137,
- -1, -1, -1,
- /*0x053c*/ 456,
- /*0x24b8*/ 887,
- /*0x023e*/ 219,
- /*0x1cbe*/ 583,
- /*0x10b2*/ 502,
- -1,
- /*0x212a*/ 865,
- -1, -1,
- /*0x10590*/ 1374,
- -1, -1, -1,
- /*0x1fd6*/ 838,
- /*0x0056*/ 20,
- /*0x0156*/ 99,
- -1, -1, -1, -1,
- /*0x01fc*/ 188,
- /*0xa72e*/ 1070,
- -1, -1, -1,
- /*0x1ed6*/ 694,
- /*0x1e56*/ 628,
- /*0xa72c*/ 1069,
- /*0x10b8*/ 508,
- -1, -1,
- /*0x04b0*/ 381,
- /*0x00d6*/ 48,
- /*0x104b0*/ 1308,
- /*0x2cd6*/ 1017,
- /*0x1e90d*/ 1507,
- -1,
- /*0xab7f*/ 1165,
- /*0xab7b*/ 1161,
- -1, -1,
- /*0xa7d6*/ 1147,
- /*0x24ba*/ 889,
- /*0x10586*/ 1365,
- /*0xab75*/ 1155,
- /*0x0556*/ 482,
- /*0x1f54*/ 753,
- -1, -1,
- /*0x1f38*/ 737,
- -1,
- /*0x1fc4*/ 828,
- /*0x0044*/ 3,
- -1,
- /*0x1cb6*/ 577,
- /*0x04be*/ 388,
- -1,
- /*0x104be*/ 1322,
- -1,
- /*0x024a*/ 226,
- /*0xa728*/ 1067,
- /*0x118b2*/ 1448,
- -1,
- /*0x1ec4*/ 685,
- /*0x1e44*/ 619,
- /*0xa688*/ 1054,
- -1, -1, -1,
- /*0x10ba*/ 510,
- /*0x00c4*/ 30,
- /*0xff32*/ 1259,
- /*0x2cc4*/ 1008,
- /*0x104d3*/ 1343,
- -1, -1, -1,
- /*0x10592*/ 1376,
- -1,
- /*0xa7c4*/ 1141,
- /*0x0050*/ 14,
- /*0x0150*/ 96,
- /*0xa68a*/ 1055,
- /*0x0544*/ 464,
- -1,
- /*0x118b8*/ 1454,
- -1, -1,
- /*0xa680*/ 1050,
- -1,
- /*0x1f3a*/ 739,
- /*0x1ed0*/ 691,
- /*0x1e50*/ 625,
- -1, -1,
- /*0xff38*/ 1265,
- /*0x01db*/ 170,
- -1,
- /*0x00d0*/ 42,
- /*0xab77*/ 1157,
- /*0x2cd0*/ 1014,
- /*0x1c87*/ 537,
- -1, -1, -1,
- /*0xa690*/ 1058,
- /*0x04b6*/ 384,
- /*0xa7d0*/ 1146,
- /*0x104b6*/ 1314,
- -1, -1,
- /*0x0550*/ 476,
- /*0x16e5f*/ 1493,
- /*0x16e5d*/ 1491,
- /*0x104ca*/ 1334,
- -1, -1, -1, -1,
- /*0x1fcc*/ 835,
- /*0x004c*/ 10,
- /*0x014c*/ 94,
- /*0xa698*/ 1062,
- -1, -1,
- /*0x01d3*/ 166,
- /*0x118ba*/ 1456,
- /*0x24be*/ 893,
- /*0x1cb4*/ 575,
- /*0x1f0d*/ 720,
- /*0x10b0*/ 500,
- /*0x1ecc*/ 689,
- /*0x1e4c*/ 623,
- -1, -1, -1,
- /*0xff3a*/ 1267,
- /*0xa732*/ 1071,
- /*0x00cc*/ 38,
- /*0xa686*/ 1053,
- /*0x2ccc*/ 1012,
- /*0x04cb*/ 395,
- -1,
- /*0x104cb*/ 1335,
- -1, -1, -1, -1,
- /*0x16e59*/ 1487,
- -1,
- /*0xa64a*/ 1032,
- /*0x054c*/ 472,
- -1, -1,
- /*0x10be*/ 514,
- /*0x2132*/ 867,
- /*0xa696*/ 1061,
- -1,
- /*0xa754*/ 1088,
- -1, -1,
- /*0xa738*/ 1074,
- /*0x1f5b*/ 756,
- -1,
- /*0x1fc8*/ 831,
- /*0x0048*/ 7,
- /*0x01ca*/ 161,
- -1, -1, -1, -1,
- /*0x03d6*/ 274,
- -1,
- /*0xa692*/ 1059,
- -1,
- /*0x1f3e*/ 743,
- /*0x1ec8*/ 687,
- /*0x1e48*/ 621,
- /*0x24b6*/ 885,
- /*0x1e907*/ 1501,
- /*0x04b4*/ 383,
- -1,
- /*0x104b4*/ 1312,
- /*0x00c8*/ 34,
- /*0x24ca*/ 905,
- /*0x2cc8*/ 1010,
- -1,
- /*0x118b0*/ 1446,
- -1, -1,
- /*0xa69a*/ 1063,
- -1,
- /*0x004e*/ 12,
- /*0x014e*/ 95,
- -1,
- /*0x01cb*/ 162,
- /*0x0548*/ 468,
- /*0xff30*/ 1257,
- -1, -1, -1, -1,
- /*0xa73a*/ 1075,
- /*0x1ece*/ 690,
- /*0x1e4e*/ 624,
- /*0x10b6*/ 506,
- -1,
- /*0x0187*/ 125,
- -1, -1,
- /*0x00ce*/ 40,
- /*0x118be*/ 1460,
- /*0x2cce*/ 1013,
- /*0x24cb*/ 906,
- /*0x1fc2*/ 826,
- /*0x0042*/ 1,
- -1,
- /*0x16e57*/ 1485,
- -1,
- /*0x10594*/ 1377,
- /*0x04bc*/ 387,
- -1,
- /*0x104bc*/ 1320,
- /*0x054e*/ 474,
- -1, -1,
- /*0x1ec2*/ 684,
- /*0x1e42*/ 618,
- /*0x1fd2*/ 836,
- /*0x0052*/ 16,
- /*0x0152*/ 97,
- -1,
- /*0x1f4a*/ 747,
- /*0x00c2*/ 28,
- -1,
- /*0x2cc2*/ 1007,
- /*0x10583*/ 1362,
- /*0x03d0*/ 271,
- -1, -1,
- /*0x1ed2*/ 692,
- /*0x1e52*/ 626,
- /*0xa7c2*/ 1140,
- -1, -1, -1,
- /*0x0542*/ 462,
- /*0x00d2*/ 44,
- -1,
- /*0x2cd2*/ 1015,
- /*0x0244*/ 222,
- -1, -1, -1,
- /*0x1fc6*/ 829,
- /*0x0046*/ 5,
- -1,
- /*0x1fd8*/ 840,
- /*0x0058*/ 22,
- /*0x0158*/ 100,
- /*0x0552*/ 478,
- /*0x1f4b*/ 748,
- /*0x118b6*/ 1452,
- -1, -1,
- /*0x04d6*/ 400,
- /*0x1ec6*/ 686,
- /*0x1e46*/ 620,
- -1,
- /*0x1ed8*/ 695,
- /*0x1e58*/ 629,
- /*0xab79*/ 1159,
- /*0xff36*/ 1263,
- /*0x00c6*/ 32,
- /*0x01bc*/ 156,
- /*0x2cc6*/ 1009,
- /*0x00d8*/ 49,
- -1,
- /*0x2cd8*/ 1018,
- /*0x10b4*/ 504,
- -1, -1,
- /*0xa7c6*/ 1143,
- /*0x1fab*/ 810,
- /*0x042b*/ 340,
- /*0xa7d8*/ 1148,
- /*0x0546*/ 466,
- /*0xa73e*/ 1077,
- /*0xabab*/ 1209,
- -1,
- /*0x1ec0*/ 683,
- /*0x1e40*/ 617,
- /*0x24bc*/ 891,
- /*0x2c2b*/ 954,
- -1, -1, -1,
- /*0x00c0*/ 26,
- -1,
- /*0x2cc0*/ 1006,
- /*0x1fec*/ 853,
- /*0x046c*/ 351,
- /*0x016c*/ 110,
- /*0xa656*/ 1038,
- /*0x013d*/ 86,
- /*0x104c4*/ 1328,
- /*0xa7c0*/ 1139,
- /*0xabbd*/ 1227,
- /*0xab7d*/ 1163,
- -1,
- /*0x0540*/ 460,
- /*0xa7ab*/ 1125,
- /*0x1eec*/ 705,
- /*0x1e6c*/ 639,
- /*0x10cab*/ 1422,
- /*0xa694*/ 1060,
- -1, -1,
- /*0x024c*/ 227,
- /*0x10bc*/ 512,
- -1, -1, -1,
- /*0x1fc9*/ 832,
- /*0x0049*/ 1528,
- /*0x0149*/ 92,
- -1,
- /*0x1fa9*/ 808,
- /*0x0429*/ 338,
- -1, -1,
- /*0x04d0*/ 397,
- /*0xaba9*/ 1207,
- /*0x104d0*/ 1340,
- /*0x053d*/ 457,
- -1,
- /*0x118b4*/ 1450,
- /*0x2c29*/ 952,
- /*0xa736*/ 1073,
- -1,
- /*0x1f3c*/ 741,
- /*0xa644*/ 1029,
- /*0x00c9*/ 35,
- -1,
- /*0xa74a*/ 1083,
- /*0x16e41*/ 1463,
- /*0xff34*/ 1261,
- /*0x1fda*/ 842,
- /*0x005a*/ 24,
- /*0x015a*/ 101,
- -1,
- /*0xa7c9*/ 1145,
- /*0x1fea*/ 851,
- /*0x046a*/ 350,
- /*0x016a*/ 109,
- /*0x0549*/ 469,
- -1,
- /*0x01c4*/ 157,
- /*0x10ca9*/ 1420,
- /*0x1eda*/ 696,
- /*0x1e5a*/ 630,
- -1, -1,
- /*0x0248*/ 225,
- /*0x1eea*/ 704,
- /*0x1e6a*/ 638,
- /*0x00da*/ 51,
- -1,
- /*0x2cda*/ 1019,
- /*0xa650*/ 1035,
- -1, -1,
- /*0x03c2*/ 269,
- /*0x104cc*/ 1336,
- -1,
- /*0x24c4*/ 899,
- /*0x118bc*/ 1458,
- -1,
- /*0x10584*/ 1363,
- /*0x1fe2*/ 844,
- /*0x0462*/ 346,
- /*0x0162*/ 105,
- -1,
- /*0x1fa1*/ 800,
- /*0x0421*/ 330,
- /*0x1f56*/ 754,
- /*0x10421*/ 1301,
- -1,
- /*0xaba1*/ 1199,
- /*0x2c62*/ 960,
- /*0x024e*/ 228,
- /*0x1ee2*/ 700,
- /*0x1e62*/ 634,
- /*0x2c21*/ 944,
- -1, -1, -1,
- /*0x1fc7*/ 830,
- /*0x0047*/ 6,
- /*0x0147*/ 91,
- /*0x2ce2*/ 1023,
- -1,
- /*0x10c4*/ 520,
- /*0x0045*/ 4,
- /*0x0145*/ 90,
- -1, -1, -1,
- /*0x1fb9*/ 821,
- /*0xa64c*/ 1033,
- /*0x0139*/ 84,
- /*0x10582*/ 1361,
- /*0xa734*/ 1072,
- /*0xabb9*/ 1223,
- /*0x10ca1*/ 1412,
- /*0x03d8*/ 275,
- /*0x00c7*/ 33,
- /*0x0055*/ 19,
- /*0x104c8*/ 1332,
- -1, -1,
- /*0x00c5*/ 31,
- -1, -1, -1,
- /*0xa7c7*/ 1144,
- -1, -1, -1,
- /*0x0547*/ 467,
- /*0xa7c5*/ 1142,
- -1,
- /*0x0345*/ 229,
- -1,
- /*0x0545*/ 465,
- /*0x00d5*/ 47,
- -1,
- /*0x1fe8*/ 849,
- /*0x0468*/ 349,
- /*0x0168*/ 108,
- /*0x0539*/ 453,
- /*0x03ab*/ 267,
- -1,
- /*0x24cc*/ 907,
- -1,
- /*0x104ce*/ 1338,
- -1, -1,
- /*0x0555*/ 481,
- /*0x1ee8*/ 703,
- /*0x1e68*/ 637,
- /*0x1f50*/ 751,
- /*0xa73c*/ 1076,
- /*0x0246*/ 224,
- /*0xa648*/ 1031,
- -1, -1, -1,
- /*0x03ec*/ 285,
- /*0x1f97*/ 790,
- /*0x0417*/ 320,
- -1,
- /*0x10417*/ 1291,
- -1,
- /*0xab97*/ 1189,
- /*0x1ff2*/ 854,
- /*0x0472*/ 354,
- /*0x0172*/ 113,
- /*0x104c2*/ 1326,
- /*0x2c17*/ 934,
- /*0x01c8*/ 160,
- /*0x1e97*/ 661,
- -1, -1,
- /*0xa684*/ 1052,
- /*0x2c72*/ 970,
- -1,
- /*0x1ef2*/ 708,
- /*0x1e72*/ 642,
- -1,
- /*0x04d2*/ 398,
- /*0xa64e*/ 1034,
- /*0x104d2*/ 1342,
- /*0x1cab*/ 566,
- -1,
- /*0x03a9*/ 265,
- /*0x2cf2*/ 1026,
- -1,
- /*0x24c8*/ 903,
- -1,
- /*0x10c97*/ 1402,
- /*0x1f4c*/ 749,
- -1, -1, -1,
- /*0x0372*/ 231,
- -1,
- /*0xa756*/ 1089,
- -1,
- /*0x10572*/ 1346,
- -1,
- /*0x023d*/ 218,
- /*0x1cbd*/ 582,
- -1,
- /*0xa642*/ 1028,
- /*0x03da*/ 276,
- -1,
- /*0xa682*/ 1051,
- /*0x104c6*/ 1330,
- /*0x04d8*/ 401,
- /*0x03ea*/ 284,
- -1, -1,
- /*0x046e*/ 352,
- /*0x016e*/ 111,
- /*0x24ce*/ 909,
- -1, -1,
- /*0xa652*/ 1036,
- -1, -1, -1,
- /*0x2c6e*/ 967,
- /*0x015e*/ 103,
- /*0x1eee*/ 706,
- /*0x1e6e*/ 640,
- -1,
- /*0x1ca9*/ 564,
- -1, -1,
- /*0x04c0*/ 389,
- -1,
- /*0x104c0*/ 1324,
- /*0x1ede*/ 698,
- /*0x1e5e*/ 632,
- /*0xa744*/ 1080,
- /*0x1f48*/ 745,
- /*0x03e2*/ 280,
- /*0x24c2*/ 897,
- -1,
- /*0x00de*/ 55,
- /*0x03a1*/ 258,
- /*0x2cde*/ 1021,
- -1,
- /*0xa646*/ 1030,
- -1, -1,
- /*0xa658*/ 1039,
- -1, -1, -1, -1,
- /*0x04ec*/ 411,
- /*0x1fc3*/ 827,
- /*0x0043*/ 2,
- /*0x0143*/ 89,
- /*0x104bd*/ 1321,
- -1,
- /*0x1fe6*/ 847,
- /*0x0466*/ 348,
- /*0x0166*/ 107,
- -1, -1,
- /*0xa750*/ 1086,
- -1,
- /*0x10c2*/ 518,
- -1, -1,
- /*0xa640*/ 1027,
- -1,
- /*0x1ee6*/ 702,
- /*0x1e66*/ 636,
- /*0x00c3*/ 29,
- -1,
- /*0x03d5*/ 273,
- /*0x04c9*/ 394,
- -1,
- /*0x104c9*/ 1333,
- /*0x24c6*/ 901,
- /*0x1fad*/ 812,
- /*0x042d*/ 342,
- /*0x1058e*/ 1372,
- -1,
- /*0x1ca1*/ 556,
- /*0xabad*/ 1211,
- /*0x0543*/ 463,
- -1,
- /*0x1058c*/ 1370,
- -1,
- /*0x2c2d*/ 956,
- /*0xa66c*/ 1049,
- -1, -1, -1, -1,
- /*0x03e8*/ 283,
- -1, -1, -1,
- /*0x04da*/ 402,
- /*0x1f52*/ 752,
- /*0x0245*/ 223,
- /*0x24c0*/ 895,
- /*0xa74c*/ 1084,
- /*0x04ea*/ 410,
- -1,
- /*0x01ec*/ 178,
- /*0xa7ad*/ 1127,
- /*0x1cb9*/ 580,
- -1,
- /*0x10cad*/ 1424,
- -1, -1, -1, -1, -1, -1,
- /*0x0397*/ 248,
- /*0x1fbb*/ 823,
- /*0xab7c*/ 1162,
- /*0x013b*/ 85,
- -1, -1,
- /*0xabbb*/ 1225,
- -1, -1,
- /*0x24bd*/ 892,
- -1, -1,
- /*0x10c0*/ 516,
- -1,
- /*0x04e2*/ 406,
- -1,
- /*0x01a9*/ 146,
- /*0x10ab*/ 495,
- /*0x1fa5*/ 804,
- /*0x0425*/ 334,
- /*0xa65a*/ 1040,
- /*0x10425*/ 1305,
- -1,
- /*0xaba5*/ 1203,
- /*0x1fb7*/ 819,
- /*0xa66a*/ 1048,
- -1, -1,
- /*0x2c25*/ 948,
- /*0xabb7*/ 1221,
- /*0x24c9*/ 904,
- /*0xa748*/ 1082,
- /*0x04c7*/ 393,
- /*0x053b*/ 455,
- /*0x104c7*/ 1331,
- -1,
- /*0x10bd*/ 513,
- /*0x04c5*/ 392,
- /*0x1f2b*/ 732,
- /*0x104c5*/ 1329,
- -1,
- /*0x01ea*/ 177,
- /*0x1c97*/ 546,
- -1,
- /*0x1e921*/ 1527,
- /*0x104b9*/ 1317,
- -1, -1, -1,
- /*0x10ca5*/ 1416,
- -1, -1,
- /*0xa662*/ 1044,
- /*0x03ee*/ 286,
- -1,
- /*0x1f6c*/ 763,
- /*0x0537*/ 451,
- /*0x1f3d*/ 742,
- /*0xa74e*/ 1085,
- -1,
- /*0xa68e*/ 1057,
- /*0x10a9*/ 493,
- /*0x03de*/ 278,
- -1, -1, -1,
- /*0xa68c*/ 1056,
- -1,
- /*0x01e2*/ 173,
- -1,
- /*0x1fa3*/ 802,
- /*0x0423*/ 332,
- /*0x04e8*/ 409,
- /*0x10423*/ 1303,
- /*0x118ab*/ 1441,
- /*0xaba3*/ 1201,
- -1, -1,
- /*0x1f49*/ 746,
- -1,
- /*0x2c23*/ 946,
- /*0xa742*/ 1079,
- /*0x1f29*/ 730,
- -1,
- /*0xff2b*/ 1252,
- -1,
- /*0x01c7*/ 159,
- -1, -1, -1, -1,
- /*0x01c5*/ 158,
- -1,
- /*0x118bd*/ 1459,
- /*0x004d*/ 11,
- /*0xa752*/ 1087,
- -1, -1, -1,
- /*0x03e6*/ 282,
- /*0x04f2*/ 414,
- /*0x10ca3*/ 1414,
- -1, -1,
- /*0x24c7*/ 902,
- /*0x01d5*/ 167,
- -1,
- /*0x1f6a*/ 761,
- /*0x1058d*/ 1371,
- /*0x24c5*/ 900,
- /*0xa668*/ 1047,
- -1,
- /*0x00cd*/ 39,
- -1, -1,
- /*0x24b9*/ 888,
- -1,
- /*0x10a1*/ 485,
- /*0x118a9*/ 1439,
- -1,
- /*0x1e917*/ 1517,
- /*0xa746*/ 1081,
- -1,
- /*0x16e54*/ 1482,
- /*0xa758*/ 1090,
- /*0x054d*/ 473,
- /*0x01e8*/ 176,
- -1,
- /*0xff29*/ 1250,
- -1, -1,
- /*0x10c7*/ 522,
- /*0x0470*/ 353,
- /*0x0170*/ 112,
- -1,
- /*0x0243*/ 221,
- /*0x10c5*/ 521,
- -1, -1, -1, -1,
- /*0x2c70*/ 969,
- /*0x10b9*/ 509,
- /*0x1ef0*/ 707,
- /*0x1e70*/ 641,
- /*0xa740*/ 1078,
- -1,
- /*0x04ee*/ 412,
- /*0x0197*/ 136,
- -1,
- /*0x1f9d*/ 796,
- /*0x041d*/ 326,
- -1,
- /*0x1041d*/ 1297,
- /*0x01f2*/ 182,
- /*0xab9d*/ 1195,
- /*0x04de*/ 404,
- -1, -1, -1,
- /*0x2c1d*/ 940,
- /*0x0370*/ 230,
- /*0x1cad*/ 568,
- /*0x1f39*/ 738,
- -1,
- /*0x10570*/ 1344,
- -1,
- /*0xa76c*/ 1100,
- /*0x212b*/ 866,
- /*0xabb5*/ 1219,
- -1, -1, -1, -1,
- /*0x118a1*/ 1431,
- -1,
- /*0x03a5*/ 261,
- /*0x1f9b*/ 794,
- /*0x041b*/ 324,
- -1,
- /*0x1041b*/ 1295,
- /*0x10c9d*/ 1408,
- /*0xab9b*/ 1193,
- /*0x00b5*/ 25,
- /*0xff21*/ 1242,
- /*0x216c*/ 880,
- -1,
- /*0x2c1b*/ 938,
- /*0x04c3*/ 391,
- /*0x1e9b*/ 665,
- /*0x104c3*/ 1327,
- -1,
- /*0x1f68*/ 759,
- /*0x04e6*/ 408,
- /*0xa65e*/ 1042,
- -1,
- /*0x0535*/ 449,
- -1, -1,
- /*0x118b9*/ 1455,
- /*0x023b*/ 217,
- /*0x01ee*/ 179,
- /*0x1f95*/ 788,
- /*0x0415*/ 318,
- -1,
- /*0x10415*/ 1289,
- -1,
- /*0xab95*/ 1187,
- /*0x10c9b*/ 1406,
- /*0xff39*/ 1266,
- /*0x01de*/ 171,
- -1,
- /*0x2c15*/ 932,
- -1,
- /*0xa75a*/ 1091,
- -1, -1, -1,
- /*0x1ca5*/ 560,
- /*0xa76a*/ 1099,
- /*0x1f99*/ 792,
- /*0x0419*/ 322,
- -1,
- /*0x10419*/ 1293,
- /*0x1cb7*/ 578,
- /*0xab99*/ 1191,
- /*0xfb17*/ 1241,
- -1,
- /*0x03a3*/ 259,
- /*0x1fb3*/ 816,
- /*0x2c19*/ 936,
- /*0xa666*/ 1046,
- /*0x1e99*/ 663,
- /*0x10c95*/ 1400,
- /*0xabb3*/ 1217,
- /*0x1f93*/ 786,
- /*0x0413*/ 316,
- /*0x216a*/ 878,
- /*0x10413*/ 1287,
- /*0x16e5b*/ 1489,
- /*0xab93*/ 1185,
- -1, -1, -1, -1,
- /*0x2c13*/ 930,
- /*0xa762*/ 1095,
- /*0x01e6*/ 175,
- -1, -1,
- /*0x0587*/ 483,
- /*0x10c99*/ 1404,
- /*0x10587*/ 1366,
- /*0x1f91*/ 784,
- /*0x0411*/ 314,
- /*0x104bb*/ 1319,
- /*0x10411*/ 1285,
- /*0xa7b3*/ 1132,
- /*0xab91*/ 1183,
- -1,
- /*0x24c3*/ 898,
- /*0x0533*/ 447,
- -1,
- /*0x2c11*/ 928,
- /*0x2162*/ 870,
- /*0x004f*/ 13,
- /*0x10c93*/ 1398,
- /*0x1f6e*/ 765,
- /*0x16e53*/ 1481,
- -1,
- /*0x1ca3*/ 558,
- -1,
- /*0x1f8f*/ 782,
- /*0x040f*/ 312,
- -1,
- /*0x1040f*/ 1283,
- -1,
- /*0xab8f*/ 1181,
- /*0x104b7*/ 1315,
- -1, -1, -1,
- /*0x2c0f*/ 926,
- /*0x00cf*/ 41,
- /*0x10c91*/ 1396,
- /*0x1f81*/ 768,
- /*0x0401*/ 298,
- /*0x10c3*/ 519,
- /*0x10401*/ 1269,
- /*0x03f0*/ 287,
- /*0xab81*/ 1167,
- -1, -1, -1, -1,
- /*0x2c01*/ 912,
- /*0x054f*/ 475,
- -1, -1,
- /*0x1ff4*/ 856,
- /*0x0474*/ 355,
- /*0x0174*/ 114,
- -1,
- /*0x10c8f*/ 1394,
- /*0xa768*/ 1098,
- -1,
- /*0x047e*/ 360,
- -1,
- /*0x039d*/ 254,
- /*0x16e4a*/ 1472,
- /*0x015c*/ 102,
- /*0x1ef4*/ 709,
- /*0x1e74*/ 643,
- /*0x10ad*/ 497,
- -1,
- /*0x2c7e*/ 972,
- /*0x10c81*/ 1380,
- /*0x1efe*/ 714,
- /*0x1e7e*/ 648,
- -1,
- /*0x1edc*/ 697,
- /*0x1e5c*/ 631,
- /*0x2168*/ 876,
- /*0x013f*/ 87,
- -1,
- /*0x24bb*/ 890,
- /*0xabbf*/ 1229,
- /*0x00dc*/ 53,
- /*0xabb1*/ 1215,
- /*0x2cdc*/ 1020,
- /*0x01b7*/ 154,
- -1, -1,
- /*0x10574*/ 1348,
- /*0x1f2d*/ 734,
- /*0x039b*/ 252,
- -1, -1,
- /*0x16e4b*/ 1473,
- /*0x1057e*/ 1357,
- -1, -1, -1, -1, -1,
- /*0x04cd*/ 396,
- -1,
- /*0x104cd*/ 1337,
- /*0x24b7*/ 886,
- -1,
- /*0x1c9d*/ 552,
- /*0xa7b1*/ 1130,
- /*0x10bb*/ 511,
- /*0x053f*/ 459,
- /*0x10cb1*/ 1428,
- /*0x0531*/ 445,
- /*0x1f9f*/ 798,
- /*0x041f*/ 328,
- -1,
- /*0x1041f*/ 1299,
- /*0x0395*/ 246,
- /*0xab9f*/ 1197,
- -1, -1,
- /*0x1cb5*/ 576,
- -1,
- /*0x2c1f*/ 942,
- -1, -1,
- /*0x10a5*/ 489,
- /*0x118ad*/ 1443,
- -1, -1,
- /*0x1f3b*/ 740,
- -1,
- /*0x10b7*/ 507,
- -1,
- /*0x1c9b*/ 550,
- /*0x0399*/ 250,
- /*0xa76e*/ 1101,
- /*0xff2d*/ 1254,
- /*0x1f85*/ 772,
- /*0x0405*/ 302,
- /*0x04f0*/ 413,
- /*0x10405*/ 1273,
- -1,
- /*0xab85*/ 1171,
- /*0x10c9f*/ 1410,
- /*0xa75e*/ 1093,
- -1, -1,
- /*0x2c05*/ 916,
- -1,
- /*0x0393*/ 244,
- -1, -1,
- /*0x0051*/ 15,
- /*0x216e*/ 882,
- -1,
- /*0x01cd*/ 163,
- -1, -1,
- /*0x1c95*/ 544,
- /*0x1f8b*/ 778,
- /*0x040b*/ 308,
- -1,
- /*0x1040b*/ 1279,
- -1,
- /*0xab8b*/ 1177,
- /*0x118bb*/ 1457,
- -1,
- /*0x0391*/ 242,
- /*0x10c85*/ 1384,
- /*0x2c0b*/ 922,
- /*0x00d1*/ 43,
- -1, -1,
- /*0x24cd*/ 908,
- /*0x104b5*/ 1313,
- -1,
- /*0x1c99*/ 548,
- /*0x10a3*/ 487,
- /*0x03cf*/ 270,
- -1, -1,
- /*0xa766*/ 1097,
- /*0x118a5*/ 1435,
- /*0x0551*/ 477,
- /*0x1e91d*/ 1523,
- /*0x1cb3*/ 574,
- /*0x038f*/ 240,
- /*0xa78b*/ 1110,
- /*0x118b7*/ 1453,
- -1,
- /*0x10c8b*/ 1390,
- /*0x1c93*/ 542,
- /*0xff25*/ 1246,
- /*0x01f0*/ 180,
- /*0x1ff6*/ 857,
- /*0x0476*/ 356,
- /*0x0176*/ 115,
- -1,
- /*0xff37*/ 1264,
- /*0x2166*/ 874,
- /*0x10cd*/ 523,
- -1, -1, -1,
- /*0x1ffa*/ 861,
- /*0x047a*/ 358,
- /*0x1ef6*/ 710,
- /*0x1e76*/ 644,
- -1,
- /*0x1c91*/ 540,
- -1,
- /*0x1e91b*/ 1521,
- /*0x019d*/ 139,
- /*0x03f4*/ 289,
- -1, -1,
- /*0x1efa*/ 712,
- /*0x1e7a*/ 646,
- /*0x16e56*/ 1484,
- /*0x03fe*/ 295,
- -1,
- /*0x1f4d*/ 750,
- /*0x03dc*/ 277,
- -1,
- /*0x0376*/ 232,
- -1,
- /*0x01b5*/ 153,
- -1,
- /*0x10576*/ 1350,
- -1,
- /*0x1ff8*/ 859,
- /*0x0478*/ 357,
- /*0x0178*/ 116,
- -1,
- /*0x118a3*/ 1433,
- -1,
- /*0x1e915*/ 1515,
- -1,
- /*0x1057a*/ 1354,
- /*0x104b3*/ 1311,
- -1,
- /*0x1c81*/ 531,
- /*0x1ef8*/ 711,
- /*0x1e78*/ 645,
- /*0xff23*/ 1244,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x1e919*/ 1519,
- -1,
- /*0x16e44*/ 1466,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x10578*/ 1352,
- -1, -1, -1, -1,
- /*0x1e913*/ 1513,
- /*0x039f*/ 256,
- /*0x10b5*/ 505,
- -1, -1,
- /*0x104cf*/ 1339,
- -1, -1,
- /*0x1cbf*/ 584,
- /*0x1f1d*/ 728,
- /*0x1cb1*/ 572,
- -1, -1, -1, -1,
- /*0x16e50*/ 1478,
- -1, -1,
- /*0x1e911*/ 1511,
- -1, -1, -1,
- /*0x01b3*/ 152,
- -1, -1, -1, -1,
- /*0x13fa*/ 526,
- /*0x0193*/ 133,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x1f1b*/ 726,
- /*0x1e90f*/ 1509,
- /*0x04f4*/ 415,
- -1,
- /*0x03d1*/ 272,
- -1, -1,
- /*0x1c9f*/ 554,
- /*0x04fe*/ 420,
- -1,
- /*0x0191*/ 132,
- /*0x04dc*/ 403,
- -1, -1,
- /*0x1e901*/ 1495,
- -1, -1,
- /*0x13f8*/ 524,
- -1,
- /*0x16e4c*/ 1474,
- -1,
- /*0x01cf*/ 164,
- -1,
- /*0x118b5*/ 1451,
- -1, -1,
- /*0x104bf*/ 1323,
- -1,
- /*0x104b1*/ 1309,
- /*0x018f*/ 130,
- -1,
- /*0x10b3*/ 503,
- /*0x1c85*/ 535,
- /*0xff35*/ 1262,
- -1, -1, -1,
- /*0xfb15*/ 1239,
- -1,
- /*0x24cf*/ 910,
- -1, -1,
- /*0x0181*/ 121,
- /*0x1f19*/ 724,
- -1, -1, -1, -1, -1,
- /*0xa65c*/ 1041,
- -1, -1, -1, -1, -1, -1,
- /*0x01f4*/ 183,
- /*0x03fa*/ 293,
- -1, -1, -1, -1,
- /*0x01fe*/ 189,
- -1,
- /*0x16e48*/ 1470,
- -1, -1, -1, -1, -1,
- /*0xfb13*/ 1237,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x01b1*/ 150,
- -1, -1, -1, -1,
- /*0x1e91f*/ 1525,
- -1, -1,
- /*0x118b3*/ 1449,
- -1, -1,
- /*0x16e4e*/ 1476,
- -1, -1, -1,
- /*0x1f0f*/ 722,
- /*0x24bf*/ 894,
- -1,
- /*0xff33*/ 1260,
- -1,
- /*0x104d1*/ 1341,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x1e905*/ 1499,
- -1, -1,
- /*0x019f*/ 140,
- /*0x16e42*/ 1464,
- -1, -1, -1, -1, -1,
- /*0xfb01*/ 1231,
- -1, -1,
- /*0x10bf*/ 515,
- -1,
- /*0x10b1*/ 501,
- -1, -1,
- /*0x16e52*/ 1480,
- -1, -1, -1,
- /*0x1e90b*/ 1505,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x04f6*/ 416,
- -1, -1,
- /*0x1f3f*/ 744,
- -1, -1, -1, -1, -1, -1,
- /*0x04fa*/ 418,
- /*0x01d1*/ 165,
- -1,
- /*0x16e46*/ 1468,
- -1, -1,
- /*0x16e58*/ 1486,
- -1, -1,
- /*0x018b*/ 128,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x04f8*/ 417,
- /*0x16e40*/ 1462,
- -1,
- /*0x118bf*/ 1461,
- -1,
- /*0x118b1*/ 1447,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xff31*/ 1258,
- -1, -1,
- /*0x01f6*/ 184,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xab72*/ 1152,
- /*0x01fa*/ 187,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0xfb05*/ 1235,
- -1, -1, -1, -1, -1, -1,
- /*0x16e49*/ 1471,
- -1, -1,
- /*0x1f0b*/ 718,
- -1, -1, -1, -1,
- /*0x01f8*/ 186,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xa77e*/ 1105,
- -1, -1,
- /*0xa75c*/ 1092,
- -1, -1, -1,
- /*0x16e5a*/ 1488,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x16e47*/ 1469,
- -1, -1, -1, -1,
- /*0x16e45*/ 1467,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x16e55*/ 1483,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e5e*/ 1492,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x16e43*/ 1465,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xab70*/ 1150,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e4d*/ 1475,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x10595*/ 1378,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xab74*/ 1154,
- -1, -1, -1, -1, -1,
- /*0xab7e*/ 1164,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x10591*/ 1375,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x1058f*/ 1373,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x10581*/ 1360,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x16e4f*/ 1477,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xab76*/ 1156,
- -1, -1, -1, -1, -1,
- /*0x10585*/ 1364,
- -1, -1, -1,
- /*0xab7a*/ 1160,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x16e5c*/ 1490,
- -1, -1, -1, -1,
- /*0xab78*/ 1158,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x16e51*/ 1479
- };
-
- if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseFold_11_hash(code);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code1_equal(code, CaseFold_11_Table[s].from))
- return &CaseFold_11_Table[s].to;
- }
- }
- return 0;
-}
-
-static const CaseUnfold_11_Type CaseUnfold_11_Table[] = {
-#define CaseUnfold_11 (*(CaseUnfold_11_Type (*)[1395])(CaseUnfold_11_Table+0))
- {0x0061, {1|U, {0x0041}}},
- {0x0062, {1|U, {0x0042}}},
- {0x0063, {1|U, {0x0043}}},
- {0x0064, {1|U, {0x0044}}},
- {0x0065, {1|U, {0x0045}}},
- {0x0066, {1|U, {0x0046}}},
- {0x0067, {1|U, {0x0047}}},
- {0x0068, {1|U, {0x0048}}},
- {0x006a, {1|U, {0x004a}}},
- {0x006b, {2|U, {0x004b, 0x212a}}},
- {0x006c, {1|U, {0x004c}}},
- {0x006d, {1|U, {0x004d}}},
- {0x006e, {1|U, {0x004e}}},
- {0x006f, {1|U, {0x004f}}},
- {0x0070, {1|U, {0x0050}}},
- {0x0071, {1|U, {0x0051}}},
- {0x0072, {1|U, {0x0052}}},
- {0x0073, {2|U, {0x0053, 0x017f}}},
- {0x0074, {1|U, {0x0054}}},
- {0x0075, {1|U, {0x0055}}},
- {0x0076, {1|U, {0x0056}}},
- {0x0077, {1|U, {0x0057}}},
- {0x0078, {1|U, {0x0058}}},
- {0x0079, {1|U, {0x0059}}},
- {0x007a, {1|U, {0x005a}}},
- {0x00e0, {1|U, {0x00c0}}},
- {0x00e1, {1|U, {0x00c1}}},
- {0x00e2, {1|U, {0x00c2}}},
- {0x00e3, {1|U, {0x00c3}}},
- {0x00e4, {1|U, {0x00c4}}},
- {0x00e5, {2|U, {0x00c5, 0x212b}}},
- {0x00e6, {1|U, {0x00c6}}},
- {0x00e7, {1|U, {0x00c7}}},
- {0x00e8, {1|U, {0x00c8}}},
- {0x00e9, {1|U, {0x00c9}}},
- {0x00ea, {1|U, {0x00ca}}},
- {0x00eb, {1|U, {0x00cb}}},
- {0x00ec, {1|U, {0x00cc}}},
- {0x00ed, {1|U, {0x00cd}}},
- {0x00ee, {1|U, {0x00ce}}},
- {0x00ef, {1|U, {0x00cf}}},
- {0x00f0, {1|U, {0x00d0}}},
- {0x00f1, {1|U, {0x00d1}}},
- {0x00f2, {1|U, {0x00d2}}},
- {0x00f3, {1|U, {0x00d3}}},
- {0x00f4, {1|U, {0x00d4}}},
- {0x00f5, {1|U, {0x00d5}}},
- {0x00f6, {1|U, {0x00d6}}},
- {0x00f8, {1|U, {0x00d8}}},
- {0x00f9, {1|U, {0x00d9}}},
- {0x00fa, {1|U, {0x00da}}},
- {0x00fb, {1|U, {0x00db}}},
- {0x00fc, {1|U, {0x00dc}}},
- {0x00fd, {1|U, {0x00dd}}},
- {0x00fe, {1|U, {0x00de}}},
- {0x00ff, {1|U, {0x0178}}},
- {0x0101, {1|U, {0x0100}}},
- {0x0103, {1|U, {0x0102}}},
- {0x0105, {1|U, {0x0104}}},
- {0x0107, {1|U, {0x0106}}},
- {0x0109, {1|U, {0x0108}}},
- {0x010b, {1|U, {0x010a}}},
- {0x010d, {1|U, {0x010c}}},
- {0x010f, {1|U, {0x010e}}},
- {0x0111, {1|U, {0x0110}}},
- {0x0113, {1|U, {0x0112}}},
- {0x0115, {1|U, {0x0114}}},
- {0x0117, {1|U, {0x0116}}},
- {0x0119, {1|U, {0x0118}}},
- {0x011b, {1|U, {0x011a}}},
- {0x011d, {1|U, {0x011c}}},
- {0x011f, {1|U, {0x011e}}},
- {0x0121, {1|U, {0x0120}}},
- {0x0123, {1|U, {0x0122}}},
- {0x0125, {1|U, {0x0124}}},
- {0x0127, {1|U, {0x0126}}},
- {0x0129, {1|U, {0x0128}}},
- {0x012b, {1|U, {0x012a}}},
- {0x012d, {1|U, {0x012c}}},
- {0x012f, {1|U, {0x012e}}},
- {0x0133, {1|U, {0x0132}}},
- {0x0135, {1|U, {0x0134}}},
- {0x0137, {1|U, {0x0136}}},
- {0x013a, {1|U, {0x0139}}},
- {0x013c, {1|U, {0x013b}}},
- {0x013e, {1|U, {0x013d}}},
- {0x0140, {1|U, {0x013f}}},
- {0x0142, {1|U, {0x0141}}},
- {0x0144, {1|U, {0x0143}}},
- {0x0146, {1|U, {0x0145}}},
- {0x0148, {1|U, {0x0147}}},
- {0x014b, {1|U, {0x014a}}},
- {0x014d, {1|U, {0x014c}}},
- {0x014f, {1|U, {0x014e}}},
- {0x0151, {1|U, {0x0150}}},
- {0x0153, {1|U, {0x0152}}},
- {0x0155, {1|U, {0x0154}}},
- {0x0157, {1|U, {0x0156}}},
- {0x0159, {1|U, {0x0158}}},
- {0x015b, {1|U, {0x015a}}},
- {0x015d, {1|U, {0x015c}}},
- {0x015f, {1|U, {0x015e}}},
- {0x0161, {1|U, {0x0160}}},
- {0x0163, {1|U, {0x0162}}},
- {0x0165, {1|U, {0x0164}}},
- {0x0167, {1|U, {0x0166}}},
- {0x0169, {1|U, {0x0168}}},
- {0x016b, {1|U, {0x016a}}},
- {0x016d, {1|U, {0x016c}}},
- {0x016f, {1|U, {0x016e}}},
- {0x0171, {1|U, {0x0170}}},
- {0x0173, {1|U, {0x0172}}},
- {0x0175, {1|U, {0x0174}}},
- {0x0177, {1|U, {0x0176}}},
- {0x017a, {1|U, {0x0179}}},
- {0x017c, {1|U, {0x017b}}},
- {0x017e, {1|U, {0x017d}}},
- {0x0180, {1|U, {0x0243}}},
- {0x0183, {1|U, {0x0182}}},
- {0x0185, {1|U, {0x0184}}},
- {0x0188, {1|U, {0x0187}}},
- {0x018c, {1|U, {0x018b}}},
- {0x0192, {1|U, {0x0191}}},
- {0x0195, {1|U, {0x01f6}}},
- {0x0199, {1|U, {0x0198}}},
- {0x019a, {1|U, {0x023d}}},
- {0x019e, {1|U, {0x0220}}},
- {0x01a1, {1|U, {0x01a0}}},
- {0x01a3, {1|U, {0x01a2}}},
- {0x01a5, {1|U, {0x01a4}}},
- {0x01a8, {1|U, {0x01a7}}},
- {0x01ad, {1|U, {0x01ac}}},
- {0x01b0, {1|U, {0x01af}}},
- {0x01b4, {1|U, {0x01b3}}},
- {0x01b6, {1|U, {0x01b5}}},
- {0x01b9, {1|U, {0x01b8}}},
- {0x01bd, {1|U, {0x01bc}}},
- {0x01bf, {1|U, {0x01f7}}},
- {0x01c6, {2|U|ST, {0x01c4, 0x01c5}}},
- {0x01c9, {2|U|ST, {0x01c7, 0x01c8}}},
- {0x01cc, {2|U|ST, {0x01ca, 0x01cb}}},
- {0x01ce, {1|U, {0x01cd}}},
- {0x01d0, {1|U, {0x01cf}}},
- {0x01d2, {1|U, {0x01d1}}},
- {0x01d4, {1|U, {0x01d3}}},
- {0x01d6, {1|U, {0x01d5}}},
- {0x01d8, {1|U, {0x01d7}}},
- {0x01da, {1|U, {0x01d9}}},
- {0x01dc, {1|U, {0x01db}}},
- {0x01dd, {1|U, {0x018e}}},
- {0x01df, {1|U, {0x01de}}},
- {0x01e1, {1|U, {0x01e0}}},
- {0x01e3, {1|U, {0x01e2}}},
- {0x01e5, {1|U, {0x01e4}}},
- {0x01e7, {1|U, {0x01e6}}},
- {0x01e9, {1|U, {0x01e8}}},
- {0x01eb, {1|U, {0x01ea}}},
- {0x01ed, {1|U, {0x01ec}}},
- {0x01ef, {1|U, {0x01ee}}},
- {0x01f3, {2|U|ST, {0x01f1, 0x01f2}}},
- {0x01f5, {1|U, {0x01f4}}},
- {0x01f9, {1|U, {0x01f8}}},
- {0x01fb, {1|U, {0x01fa}}},
- {0x01fd, {1|U, {0x01fc}}},
- {0x01ff, {1|U, {0x01fe}}},
- {0x0201, {1|U, {0x0200}}},
- {0x0203, {1|U, {0x0202}}},
- {0x0205, {1|U, {0x0204}}},
- {0x0207, {1|U, {0x0206}}},
- {0x0209, {1|U, {0x0208}}},
- {0x020b, {1|U, {0x020a}}},
- {0x020d, {1|U, {0x020c}}},
- {0x020f, {1|U, {0x020e}}},
- {0x0211, {1|U, {0x0210}}},
- {0x0213, {1|U, {0x0212}}},
- {0x0215, {1|U, {0x0214}}},
- {0x0217, {1|U, {0x0216}}},
- {0x0219, {1|U, {0x0218}}},
- {0x021b, {1|U, {0x021a}}},
- {0x021d, {1|U, {0x021c}}},
- {0x021f, {1|U, {0x021e}}},
- {0x0223, {1|U, {0x0222}}},
- {0x0225, {1|U, {0x0224}}},
- {0x0227, {1|U, {0x0226}}},
- {0x0229, {1|U, {0x0228}}},
- {0x022b, {1|U, {0x022a}}},
- {0x022d, {1|U, {0x022c}}},
- {0x022f, {1|U, {0x022e}}},
- {0x0231, {1|U, {0x0230}}},
- {0x0233, {1|U, {0x0232}}},
- {0x023c, {1|U, {0x023b}}},
- {0x023f, {1|U, {0x2c7e}}},
- {0x0240, {1|U, {0x2c7f}}},
- {0x0242, {1|U, {0x0241}}},
- {0x0247, {1|U, {0x0246}}},
- {0x0249, {1|U, {0x0248}}},
- {0x024b, {1|U, {0x024a}}},
- {0x024d, {1|U, {0x024c}}},
- {0x024f, {1|U, {0x024e}}},
- {0x0250, {1|U, {0x2c6f}}},
- {0x0251, {1|U, {0x2c6d}}},
- {0x0252, {1|U, {0x2c70}}},
- {0x0253, {1|U, {0x0181}}},
- {0x0254, {1|U, {0x0186}}},
- {0x0256, {1|U, {0x0189}}},
- {0x0257, {1|U, {0x018a}}},
- {0x0259, {1|U, {0x018f}}},
- {0x025b, {1|U, {0x0190}}},
- {0x025c, {1|U, {0xa7ab}}},
- {0x0260, {1|U, {0x0193}}},
- {0x0261, {1|U, {0xa7ac}}},
- {0x0263, {1|U, {0x0194}}},
- {0x0265, {1|U, {0xa78d}}},
- {0x0266, {1|U, {0xa7aa}}},
- {0x0268, {1|U, {0x0197}}},
- {0x0269, {1|U, {0x0196}}},
- {0x026a, {1|U, {0xa7ae}}},
- {0x026b, {1|U, {0x2c62}}},
- {0x026c, {1|U, {0xa7ad}}},
- {0x026f, {1|U, {0x019c}}},
- {0x0271, {1|U, {0x2c6e}}},
- {0x0272, {1|U, {0x019d}}},
- {0x0275, {1|U, {0x019f}}},
- {0x027d, {1|U, {0x2c64}}},
- {0x0280, {1|U, {0x01a6}}},
- {0x0282, {1|U, {0xa7c5}}},
- {0x0283, {1|U, {0x01a9}}},
- {0x0287, {1|U, {0xa7b1}}},
- {0x0288, {1|U, {0x01ae}}},
- {0x0289, {1|U, {0x0244}}},
- {0x028a, {1|U, {0x01b1}}},
- {0x028b, {1|U, {0x01b2}}},
- {0x028c, {1|U, {0x0245}}},
- {0x0292, {1|U, {0x01b7}}},
- {0x029d, {1|U, {0xa7b2}}},
- {0x029e, {1|U, {0xa7b0}}},
- {0x0371, {1|U, {0x0370}}},
- {0x0373, {1|U, {0x0372}}},
- {0x0377, {1|U, {0x0376}}},
- {0x037b, {1|U, {0x03fd}}},
- {0x037c, {1|U, {0x03fe}}},
- {0x037d, {1|U, {0x03ff}}},
- {0x03ac, {1|U, {0x0386}}},
- {0x03ad, {1|U, {0x0388}}},
- {0x03ae, {1|U, {0x0389}}},
- {0x03af, {1|U, {0x038a}}},
- {0x03b1, {1|U, {0x0391}}},
- {0x03b2, {2|U, {0x0392, 0x03d0}}},
- {0x03b3, {1|U, {0x0393}}},
- {0x03b4, {1|U, {0x0394}}},
- {0x03b5, {2|U, {0x0395, 0x03f5}}},
- {0x03b6, {1|U, {0x0396}}},
- {0x03b7, {1|U, {0x0397}}},
- {0x03b8, {3|U, {0x0398, 0x03d1, 0x03f4}}},
- {0x03b9, {3|U, {0x0399, 0x0345, 0x1fbe}}},
- {0x03ba, {2|U, {0x039a, 0x03f0}}},
- {0x03bb, {1|U, {0x039b}}},
- {0x03bc, {2|U, {0x039c, 0x00b5}}},
- {0x03bd, {1|U, {0x039d}}},
- {0x03be, {1|U, {0x039e}}},
- {0x03bf, {1|U, {0x039f}}},
- {0x03c0, {2|U, {0x03a0, 0x03d6}}},
- {0x03c1, {2|U, {0x03a1, 0x03f1}}},
- {0x03c3, {2|U, {0x03a3, 0x03c2}}},
- {0x03c4, {1|U, {0x03a4}}},
- {0x03c5, {1|U, {0x03a5}}},
- {0x03c6, {2|U, {0x03a6, 0x03d5}}},
- {0x03c7, {1|U, {0x03a7}}},
- {0x03c8, {1|U, {0x03a8}}},
- {0x03c9, {2|U, {0x03a9, 0x2126}}},
- {0x03ca, {1|U, {0x03aa}}},
- {0x03cb, {1|U, {0x03ab}}},
- {0x03cc, {1|U, {0x038c}}},
- {0x03cd, {1|U, {0x038e}}},
- {0x03ce, {1|U, {0x038f}}},
- {0x03d7, {1|U, {0x03cf}}},
- {0x03d9, {1|U, {0x03d8}}},
- {0x03db, {1|U, {0x03da}}},
- {0x03dd, {1|U, {0x03dc}}},
- {0x03df, {1|U, {0x03de}}},
- {0x03e1, {1|U, {0x03e0}}},
- {0x03e3, {1|U, {0x03e2}}},
- {0x03e5, {1|U, {0x03e4}}},
- {0x03e7, {1|U, {0x03e6}}},
- {0x03e9, {1|U, {0x03e8}}},
- {0x03eb, {1|U, {0x03ea}}},
- {0x03ed, {1|U, {0x03ec}}},
- {0x03ef, {1|U, {0x03ee}}},
- {0x03f2, {1|U, {0x03f9}}},
- {0x03f3, {1|U, {0x037f}}},
- {0x03f8, {1|U, {0x03f7}}},
- {0x03fb, {1|U, {0x03fa}}},
- {0x0430, {1|U, {0x0410}}},
- {0x0431, {1|U, {0x0411}}},
- {0x0432, {2|U, {0x0412, 0x1c80}}},
- {0x0433, {1|U, {0x0413}}},
- {0x0434, {2|U, {0x0414, 0x1c81}}},
- {0x0435, {1|U, {0x0415}}},
- {0x0436, {1|U, {0x0416}}},
- {0x0437, {1|U, {0x0417}}},
- {0x0438, {1|U, {0x0418}}},
- {0x0439, {1|U, {0x0419}}},
- {0x043a, {1|U, {0x041a}}},
- {0x043b, {1|U, {0x041b}}},
- {0x043c, {1|U, {0x041c}}},
- {0x043d, {1|U, {0x041d}}},
- {0x043e, {2|U, {0x041e, 0x1c82}}},
- {0x043f, {1|U, {0x041f}}},
- {0x0440, {1|U, {0x0420}}},
- {0x0441, {2|U, {0x0421, 0x1c83}}},
- {0x0442, {3|U, {0x0422, 0x1c84, 0x1c85}}},
- {0x0443, {1|U, {0x0423}}},
- {0x0444, {1|U, {0x0424}}},
- {0x0445, {1|U, {0x0425}}},
- {0x0446, {1|U, {0x0426}}},
- {0x0447, {1|U, {0x0427}}},
- {0x0448, {1|U, {0x0428}}},
- {0x0449, {1|U, {0x0429}}},
- {0x044a, {2|U, {0x042a, 0x1c86}}},
- {0x044b, {1|U, {0x042b}}},
- {0x044c, {1|U, {0x042c}}},
- {0x044d, {1|U, {0x042d}}},
- {0x044e, {1|U, {0x042e}}},
- {0x044f, {1|U, {0x042f}}},
- {0x0450, {1|U, {0x0400}}},
- {0x0451, {1|U, {0x0401}}},
- {0x0452, {1|U, {0x0402}}},
- {0x0453, {1|U, {0x0403}}},
- {0x0454, {1|U, {0x0404}}},
- {0x0455, {1|U, {0x0405}}},
- {0x0456, {1|U, {0x0406}}},
- {0x0457, {1|U, {0x0407}}},
- {0x0458, {1|U, {0x0408}}},
- {0x0459, {1|U, {0x0409}}},
- {0x045a, {1|U, {0x040a}}},
- {0x045b, {1|U, {0x040b}}},
- {0x045c, {1|U, {0x040c}}},
- {0x045d, {1|U, {0x040d}}},
- {0x045e, {1|U, {0x040e}}},
- {0x045f, {1|U, {0x040f}}},
- {0x0461, {1|U, {0x0460}}},
- {0x0463, {2|U, {0x0462, 0x1c87}}},
- {0x0465, {1|U, {0x0464}}},
- {0x0467, {1|U, {0x0466}}},
- {0x0469, {1|U, {0x0468}}},
- {0x046b, {1|U, {0x046a}}},
- {0x046d, {1|U, {0x046c}}},
- {0x046f, {1|U, {0x046e}}},
- {0x0471, {1|U, {0x0470}}},
- {0x0473, {1|U, {0x0472}}},
- {0x0475, {1|U, {0x0474}}},
- {0x0477, {1|U, {0x0476}}},
- {0x0479, {1|U, {0x0478}}},
- {0x047b, {1|U, {0x047a}}},
- {0x047d, {1|U, {0x047c}}},
- {0x047f, {1|U, {0x047e}}},
- {0x0481, {1|U, {0x0480}}},
- {0x048b, {1|U, {0x048a}}},
- {0x048d, {1|U, {0x048c}}},
- {0x048f, {1|U, {0x048e}}},
- {0x0491, {1|U, {0x0490}}},
- {0x0493, {1|U, {0x0492}}},
- {0x0495, {1|U, {0x0494}}},
- {0x0497, {1|U, {0x0496}}},
- {0x0499, {1|U, {0x0498}}},
- {0x049b, {1|U, {0x049a}}},
- {0x049d, {1|U, {0x049c}}},
- {0x049f, {1|U, {0x049e}}},
- {0x04a1, {1|U, {0x04a0}}},
- {0x04a3, {1|U, {0x04a2}}},
- {0x04a5, {1|U, {0x04a4}}},
- {0x04a7, {1|U, {0x04a6}}},
- {0x04a9, {1|U, {0x04a8}}},
- {0x04ab, {1|U, {0x04aa}}},
- {0x04ad, {1|U, {0x04ac}}},
- {0x04af, {1|U, {0x04ae}}},
- {0x04b1, {1|U, {0x04b0}}},
- {0x04b3, {1|U, {0x04b2}}},
- {0x04b5, {1|U, {0x04b4}}},
- {0x04b7, {1|U, {0x04b6}}},
- {0x04b9, {1|U, {0x04b8}}},
- {0x04bb, {1|U, {0x04ba}}},
- {0x04bd, {1|U, {0x04bc}}},
- {0x04bf, {1|U, {0x04be}}},
- {0x04c2, {1|U, {0x04c1}}},
- {0x04c4, {1|U, {0x04c3}}},
- {0x04c6, {1|U, {0x04c5}}},
- {0x04c8, {1|U, {0x04c7}}},
- {0x04ca, {1|U, {0x04c9}}},
- {0x04cc, {1|U, {0x04cb}}},
- {0x04ce, {1|U, {0x04cd}}},
- {0x04cf, {1|U, {0x04c0}}},
- {0x04d1, {1|U, {0x04d0}}},
- {0x04d3, {1|U, {0x04d2}}},
- {0x04d5, {1|U, {0x04d4}}},
- {0x04d7, {1|U, {0x04d6}}},
- {0x04d9, {1|U, {0x04d8}}},
- {0x04db, {1|U, {0x04da}}},
- {0x04dd, {1|U, {0x04dc}}},
- {0x04df, {1|U, {0x04de}}},
- {0x04e1, {1|U, {0x04e0}}},
- {0x04e3, {1|U, {0x04e2}}},
- {0x04e5, {1|U, {0x04e4}}},
- {0x04e7, {1|U, {0x04e6}}},
- {0x04e9, {1|U, {0x04e8}}},
- {0x04eb, {1|U, {0x04ea}}},
- {0x04ed, {1|U, {0x04ec}}},
- {0x04ef, {1|U, {0x04ee}}},
- {0x04f1, {1|U, {0x04f0}}},
- {0x04f3, {1|U, {0x04f2}}},
- {0x04f5, {1|U, {0x04f4}}},
- {0x04f7, {1|U, {0x04f6}}},
- {0x04f9, {1|U, {0x04f8}}},
- {0x04fb, {1|U, {0x04fa}}},
- {0x04fd, {1|U, {0x04fc}}},
- {0x04ff, {1|U, {0x04fe}}},
- {0x0501, {1|U, {0x0500}}},
- {0x0503, {1|U, {0x0502}}},
- {0x0505, {1|U, {0x0504}}},
- {0x0507, {1|U, {0x0506}}},
- {0x0509, {1|U, {0x0508}}},
- {0x050b, {1|U, {0x050a}}},
- {0x050d, {1|U, {0x050c}}},
- {0x050f, {1|U, {0x050e}}},
- {0x0511, {1|U, {0x0510}}},
- {0x0513, {1|U, {0x0512}}},
- {0x0515, {1|U, {0x0514}}},
- {0x0517, {1|U, {0x0516}}},
- {0x0519, {1|U, {0x0518}}},
- {0x051b, {1|U, {0x051a}}},
- {0x051d, {1|U, {0x051c}}},
- {0x051f, {1|U, {0x051e}}},
- {0x0521, {1|U, {0x0520}}},
- {0x0523, {1|U, {0x0522}}},
- {0x0525, {1|U, {0x0524}}},
- {0x0527, {1|U, {0x0526}}},
- {0x0529, {1|U, {0x0528}}},
- {0x052b, {1|U, {0x052a}}},
- {0x052d, {1|U, {0x052c}}},
- {0x052f, {1|U, {0x052e}}},
- {0x0561, {1|U, {0x0531}}},
- {0x0562, {1|U, {0x0532}}},
- {0x0563, {1|U, {0x0533}}},
- {0x0564, {1|U, {0x0534}}},
- {0x0565, {1|U, {0x0535}}},
- {0x0566, {1|U, {0x0536}}},
- {0x0567, {1|U, {0x0537}}},
- {0x0568, {1|U, {0x0538}}},
- {0x0569, {1|U, {0x0539}}},
- {0x056a, {1|U, {0x053a}}},
- {0x056b, {1|U, {0x053b}}},
- {0x056c, {1|U, {0x053c}}},
- {0x056d, {1|U, {0x053d}}},
- {0x056e, {1|U, {0x053e}}},
- {0x056f, {1|U, {0x053f}}},
- {0x0570, {1|U, {0x0540}}},
- {0x0571, {1|U, {0x0541}}},
- {0x0572, {1|U, {0x0542}}},
- {0x0573, {1|U, {0x0543}}},
- {0x0574, {1|U, {0x0544}}},
- {0x0575, {1|U, {0x0545}}},
- {0x0576, {1|U, {0x0546}}},
- {0x0577, {1|U, {0x0547}}},
- {0x0578, {1|U, {0x0548}}},
- {0x0579, {1|U, {0x0549}}},
- {0x057a, {1|U, {0x054a}}},
- {0x057b, {1|U, {0x054b}}},
- {0x057c, {1|U, {0x054c}}},
- {0x057d, {1|U, {0x054d}}},
- {0x057e, {1|U, {0x054e}}},
- {0x057f, {1|U, {0x054f}}},
- {0x0580, {1|U, {0x0550}}},
- {0x0581, {1|U, {0x0551}}},
- {0x0582, {1|U, {0x0552}}},
- {0x0583, {1|U, {0x0553}}},
- {0x0584, {1|U, {0x0554}}},
- {0x0585, {1|U, {0x0555}}},
- {0x0586, {1|U, {0x0556}}},
- {0x10d0, {1|U|IT, {0x1c90}}},
- {0x10d1, {1|U|IT, {0x1c91}}},
- {0x10d2, {1|U|IT, {0x1c92}}},
- {0x10d3, {1|U|IT, {0x1c93}}},
- {0x10d4, {1|U|IT, {0x1c94}}},
- {0x10d5, {1|U|IT, {0x1c95}}},
- {0x10d6, {1|U|IT, {0x1c96}}},
- {0x10d7, {1|U|IT, {0x1c97}}},
- {0x10d8, {1|U|IT, {0x1c98}}},
- {0x10d9, {1|U|IT, {0x1c99}}},
- {0x10da, {1|U|IT, {0x1c9a}}},
- {0x10db, {1|U|IT, {0x1c9b}}},
- {0x10dc, {1|U|IT, {0x1c9c}}},
- {0x10dd, {1|U|IT, {0x1c9d}}},
- {0x10de, {1|U|IT, {0x1c9e}}},
- {0x10df, {1|U|IT, {0x1c9f}}},
- {0x10e0, {1|U|IT, {0x1ca0}}},
- {0x10e1, {1|U|IT, {0x1ca1}}},
- {0x10e2, {1|U|IT, {0x1ca2}}},
- {0x10e3, {1|U|IT, {0x1ca3}}},
- {0x10e4, {1|U|IT, {0x1ca4}}},
- {0x10e5, {1|U|IT, {0x1ca5}}},
- {0x10e6, {1|U|IT, {0x1ca6}}},
- {0x10e7, {1|U|IT, {0x1ca7}}},
- {0x10e8, {1|U|IT, {0x1ca8}}},
- {0x10e9, {1|U|IT, {0x1ca9}}},
- {0x10ea, {1|U|IT, {0x1caa}}},
- {0x10eb, {1|U|IT, {0x1cab}}},
- {0x10ec, {1|U|IT, {0x1cac}}},
- {0x10ed, {1|U|IT, {0x1cad}}},
- {0x10ee, {1|U|IT, {0x1cae}}},
- {0x10ef, {1|U|IT, {0x1caf}}},
- {0x10f0, {1|U|IT, {0x1cb0}}},
- {0x10f1, {1|U|IT, {0x1cb1}}},
- {0x10f2, {1|U|IT, {0x1cb2}}},
- {0x10f3, {1|U|IT, {0x1cb3}}},
- {0x10f4, {1|U|IT, {0x1cb4}}},
- {0x10f5, {1|U|IT, {0x1cb5}}},
- {0x10f6, {1|U|IT, {0x1cb6}}},
- {0x10f7, {1|U|IT, {0x1cb7}}},
- {0x10f8, {1|U|IT, {0x1cb8}}},
- {0x10f9, {1|U|IT, {0x1cb9}}},
- {0x10fa, {1|U|IT, {0x1cba}}},
- {0x10fd, {1|U|IT, {0x1cbd}}},
- {0x10fe, {1|U|IT, {0x1cbe}}},
- {0x10ff, {1|U|IT, {0x1cbf}}},
- {0x13a0, {1|D, {0xab70}}},
- {0x13a1, {1|D, {0xab71}}},
- {0x13a2, {1|D, {0xab72}}},
- {0x13a3, {1|D, {0xab73}}},
- {0x13a4, {1|D, {0xab74}}},
- {0x13a5, {1|D, {0xab75}}},
- {0x13a6, {1|D, {0xab76}}},
- {0x13a7, {1|D, {0xab77}}},
- {0x13a8, {1|D, {0xab78}}},
- {0x13a9, {1|D, {0xab79}}},
- {0x13aa, {1|D, {0xab7a}}},
- {0x13ab, {1|D, {0xab7b}}},
- {0x13ac, {1|D, {0xab7c}}},
- {0x13ad, {1|D, {0xab7d}}},
- {0x13ae, {1|D, {0xab7e}}},
- {0x13af, {1|D, {0xab7f}}},
- {0x13b0, {1|D, {0xab80}}},
- {0x13b1, {1|D, {0xab81}}},
- {0x13b2, {1|D, {0xab82}}},
- {0x13b3, {1|D, {0xab83}}},
- {0x13b4, {1|D, {0xab84}}},
- {0x13b5, {1|D, {0xab85}}},
- {0x13b6, {1|D, {0xab86}}},
- {0x13b7, {1|D, {0xab87}}},
- {0x13b8, {1|D, {0xab88}}},
- {0x13b9, {1|D, {0xab89}}},
- {0x13ba, {1|D, {0xab8a}}},
- {0x13bb, {1|D, {0xab8b}}},
- {0x13bc, {1|D, {0xab8c}}},
- {0x13bd, {1|D, {0xab8d}}},
- {0x13be, {1|D, {0xab8e}}},
- {0x13bf, {1|D, {0xab8f}}},
- {0x13c0, {1|D, {0xab90}}},
- {0x13c1, {1|D, {0xab91}}},
- {0x13c2, {1|D, {0xab92}}},
- {0x13c3, {1|D, {0xab93}}},
- {0x13c4, {1|D, {0xab94}}},
- {0x13c5, {1|D, {0xab95}}},
- {0x13c6, {1|D, {0xab96}}},
- {0x13c7, {1|D, {0xab97}}},
- {0x13c8, {1|D, {0xab98}}},
- {0x13c9, {1|D, {0xab99}}},
- {0x13ca, {1|D, {0xab9a}}},
- {0x13cb, {1|D, {0xab9b}}},
- {0x13cc, {1|D, {0xab9c}}},
- {0x13cd, {1|D, {0xab9d}}},
- {0x13ce, {1|D, {0xab9e}}},
- {0x13cf, {1|D, {0xab9f}}},
- {0x13d0, {1|D, {0xaba0}}},
- {0x13d1, {1|D, {0xaba1}}},
- {0x13d2, {1|D, {0xaba2}}},
- {0x13d3, {1|D, {0xaba3}}},
- {0x13d4, {1|D, {0xaba4}}},
- {0x13d5, {1|D, {0xaba5}}},
- {0x13d6, {1|D, {0xaba6}}},
- {0x13d7, {1|D, {0xaba7}}},
- {0x13d8, {1|D, {0xaba8}}},
- {0x13d9, {1|D, {0xaba9}}},
- {0x13da, {1|D, {0xabaa}}},
- {0x13db, {1|D, {0xabab}}},
- {0x13dc, {1|D, {0xabac}}},
- {0x13dd, {1|D, {0xabad}}},
- {0x13de, {1|D, {0xabae}}},
- {0x13df, {1|D, {0xabaf}}},
- {0x13e0, {1|D, {0xabb0}}},
- {0x13e1, {1|D, {0xabb1}}},
- {0x13e2, {1|D, {0xabb2}}},
- {0x13e3, {1|D, {0xabb3}}},
- {0x13e4, {1|D, {0xabb4}}},
- {0x13e5, {1|D, {0xabb5}}},
- {0x13e6, {1|D, {0xabb6}}},
- {0x13e7, {1|D, {0xabb7}}},
- {0x13e8, {1|D, {0xabb8}}},
- {0x13e9, {1|D, {0xabb9}}},
- {0x13ea, {1|D, {0xabba}}},
- {0x13eb, {1|D, {0xabbb}}},
- {0x13ec, {1|D, {0xabbc}}},
- {0x13ed, {1|D, {0xabbd}}},
- {0x13ee, {1|D, {0xabbe}}},
- {0x13ef, {1|D, {0xabbf}}},
- {0x13f0, {1|D, {0x13f8}}},
- {0x13f1, {1|D, {0x13f9}}},
- {0x13f2, {1|D, {0x13fa}}},
- {0x13f3, {1|D, {0x13fb}}},
- {0x13f4, {1|D, {0x13fc}}},
- {0x13f5, {1|D, {0x13fd}}},
- {0x1d79, {1|U, {0xa77d}}},
- {0x1d7d, {1|U, {0x2c63}}},
- {0x1d8e, {1|U, {0xa7c6}}},
- {0x1e01, {1|U, {0x1e00}}},
- {0x1e03, {1|U, {0x1e02}}},
- {0x1e05, {1|U, {0x1e04}}},
- {0x1e07, {1|U, {0x1e06}}},
- {0x1e09, {1|U, {0x1e08}}},
- {0x1e0b, {1|U, {0x1e0a}}},
- {0x1e0d, {1|U, {0x1e0c}}},
- {0x1e0f, {1|U, {0x1e0e}}},
- {0x1e11, {1|U, {0x1e10}}},
- {0x1e13, {1|U, {0x1e12}}},
- {0x1e15, {1|U, {0x1e14}}},
- {0x1e17, {1|U, {0x1e16}}},
- {0x1e19, {1|U, {0x1e18}}},
- {0x1e1b, {1|U, {0x1e1a}}},
- {0x1e1d, {1|U, {0x1e1c}}},
- {0x1e1f, {1|U, {0x1e1e}}},
- {0x1e21, {1|U, {0x1e20}}},
- {0x1e23, {1|U, {0x1e22}}},
- {0x1e25, {1|U, {0x1e24}}},
- {0x1e27, {1|U, {0x1e26}}},
- {0x1e29, {1|U, {0x1e28}}},
- {0x1e2b, {1|U, {0x1e2a}}},
- {0x1e2d, {1|U, {0x1e2c}}},
- {0x1e2f, {1|U, {0x1e2e}}},
- {0x1e31, {1|U, {0x1e30}}},
- {0x1e33, {1|U, {0x1e32}}},
- {0x1e35, {1|U, {0x1e34}}},
- {0x1e37, {1|U, {0x1e36}}},
- {0x1e39, {1|U, {0x1e38}}},
- {0x1e3b, {1|U, {0x1e3a}}},
- {0x1e3d, {1|U, {0x1e3c}}},
- {0x1e3f, {1|U, {0x1e3e}}},
- {0x1e41, {1|U, {0x1e40}}},
- {0x1e43, {1|U, {0x1e42}}},
- {0x1e45, {1|U, {0x1e44}}},
- {0x1e47, {1|U, {0x1e46}}},
- {0x1e49, {1|U, {0x1e48}}},
- {0x1e4b, {1|U, {0x1e4a}}},
- {0x1e4d, {1|U, {0x1e4c}}},
- {0x1e4f, {1|U, {0x1e4e}}},
- {0x1e51, {1|U, {0x1e50}}},
- {0x1e53, {1|U, {0x1e52}}},
- {0x1e55, {1|U, {0x1e54}}},
- {0x1e57, {1|U, {0x1e56}}},
- {0x1e59, {1|U, {0x1e58}}},
- {0x1e5b, {1|U, {0x1e5a}}},
- {0x1e5d, {1|U, {0x1e5c}}},
- {0x1e5f, {1|U, {0x1e5e}}},
- {0x1e61, {2|U, {0x1e60, 0x1e9b}}},
- {0x1e63, {1|U, {0x1e62}}},
- {0x1e65, {1|U, {0x1e64}}},
- {0x1e67, {1|U, {0x1e66}}},
- {0x1e69, {1|U, {0x1e68}}},
- {0x1e6b, {1|U, {0x1e6a}}},
- {0x1e6d, {1|U, {0x1e6c}}},
- {0x1e6f, {1|U, {0x1e6e}}},
- {0x1e71, {1|U, {0x1e70}}},
- {0x1e73, {1|U, {0x1e72}}},
- {0x1e75, {1|U, {0x1e74}}},
- {0x1e77, {1|U, {0x1e76}}},
- {0x1e79, {1|U, {0x1e78}}},
- {0x1e7b, {1|U, {0x1e7a}}},
- {0x1e7d, {1|U, {0x1e7c}}},
- {0x1e7f, {1|U, {0x1e7e}}},
- {0x1e81, {1|U, {0x1e80}}},
- {0x1e83, {1|U, {0x1e82}}},
- {0x1e85, {1|U, {0x1e84}}},
- {0x1e87, {1|U, {0x1e86}}},
- {0x1e89, {1|U, {0x1e88}}},
- {0x1e8b, {1|U, {0x1e8a}}},
- {0x1e8d, {1|U, {0x1e8c}}},
- {0x1e8f, {1|U, {0x1e8e}}},
- {0x1e91, {1|U, {0x1e90}}},
- {0x1e93, {1|U, {0x1e92}}},
- {0x1e95, {1|U, {0x1e94}}},
- {0x1ea1, {1|U, {0x1ea0}}},
- {0x1ea3, {1|U, {0x1ea2}}},
- {0x1ea5, {1|U, {0x1ea4}}},
- {0x1ea7, {1|U, {0x1ea6}}},
- {0x1ea9, {1|U, {0x1ea8}}},
- {0x1eab, {1|U, {0x1eaa}}},
- {0x1ead, {1|U, {0x1eac}}},
- {0x1eaf, {1|U, {0x1eae}}},
- {0x1eb1, {1|U, {0x1eb0}}},
- {0x1eb3, {1|U, {0x1eb2}}},
- {0x1eb5, {1|U, {0x1eb4}}},
- {0x1eb7, {1|U, {0x1eb6}}},
- {0x1eb9, {1|U, {0x1eb8}}},
- {0x1ebb, {1|U, {0x1eba}}},
- {0x1ebd, {1|U, {0x1ebc}}},
- {0x1ebf, {1|U, {0x1ebe}}},
- {0x1ec1, {1|U, {0x1ec0}}},
- {0x1ec3, {1|U, {0x1ec2}}},
- {0x1ec5, {1|U, {0x1ec4}}},
- {0x1ec7, {1|U, {0x1ec6}}},
- {0x1ec9, {1|U, {0x1ec8}}},
- {0x1ecb, {1|U, {0x1eca}}},
- {0x1ecd, {1|U, {0x1ecc}}},
- {0x1ecf, {1|U, {0x1ece}}},
- {0x1ed1, {1|U, {0x1ed0}}},
- {0x1ed3, {1|U, {0x1ed2}}},
- {0x1ed5, {1|U, {0x1ed4}}},
- {0x1ed7, {1|U, {0x1ed6}}},
- {0x1ed9, {1|U, {0x1ed8}}},
- {0x1edb, {1|U, {0x1eda}}},
- {0x1edd, {1|U, {0x1edc}}},
- {0x1edf, {1|U, {0x1ede}}},
- {0x1ee1, {1|U, {0x1ee0}}},
- {0x1ee3, {1|U, {0x1ee2}}},
- {0x1ee5, {1|U, {0x1ee4}}},
- {0x1ee7, {1|U, {0x1ee6}}},
- {0x1ee9, {1|U, {0x1ee8}}},
- {0x1eeb, {1|U, {0x1eea}}},
- {0x1eed, {1|U, {0x1eec}}},
- {0x1eef, {1|U, {0x1eee}}},
- {0x1ef1, {1|U, {0x1ef0}}},
- {0x1ef3, {1|U, {0x1ef2}}},
- {0x1ef5, {1|U, {0x1ef4}}},
- {0x1ef7, {1|U, {0x1ef6}}},
- {0x1ef9, {1|U, {0x1ef8}}},
- {0x1efb, {1|U, {0x1efa}}},
- {0x1efd, {1|U, {0x1efc}}},
- {0x1eff, {1|U, {0x1efe}}},
- {0x1f00, {1|U, {0x1f08}}},
- {0x1f01, {1|U, {0x1f09}}},
- {0x1f02, {1|U, {0x1f0a}}},
- {0x1f03, {1|U, {0x1f0b}}},
- {0x1f04, {1|U, {0x1f0c}}},
- {0x1f05, {1|U, {0x1f0d}}},
- {0x1f06, {1|U, {0x1f0e}}},
- {0x1f07, {1|U, {0x1f0f}}},
- {0x1f10, {1|U, {0x1f18}}},
- {0x1f11, {1|U, {0x1f19}}},
- {0x1f12, {1|U, {0x1f1a}}},
- {0x1f13, {1|U, {0x1f1b}}},
- {0x1f14, {1|U, {0x1f1c}}},
- {0x1f15, {1|U, {0x1f1d}}},
- {0x1f20, {1|U, {0x1f28}}},
- {0x1f21, {1|U, {0x1f29}}},
- {0x1f22, {1|U, {0x1f2a}}},
- {0x1f23, {1|U, {0x1f2b}}},
- {0x1f24, {1|U, {0x1f2c}}},
- {0x1f25, {1|U, {0x1f2d}}},
- {0x1f26, {1|U, {0x1f2e}}},
- {0x1f27, {1|U, {0x1f2f}}},
- {0x1f30, {1|U, {0x1f38}}},
- {0x1f31, {1|U, {0x1f39}}},
- {0x1f32, {1|U, {0x1f3a}}},
- {0x1f33, {1|U, {0x1f3b}}},
- {0x1f34, {1|U, {0x1f3c}}},
- {0x1f35, {1|U, {0x1f3d}}},
- {0x1f36, {1|U, {0x1f3e}}},
- {0x1f37, {1|U, {0x1f3f}}},
- {0x1f40, {1|U, {0x1f48}}},
- {0x1f41, {1|U, {0x1f49}}},
- {0x1f42, {1|U, {0x1f4a}}},
- {0x1f43, {1|U, {0x1f4b}}},
- {0x1f44, {1|U, {0x1f4c}}},
- {0x1f45, {1|U, {0x1f4d}}},
- {0x1f51, {1|U, {0x1f59}}},
- {0x1f53, {1|U, {0x1f5b}}},
- {0x1f55, {1|U, {0x1f5d}}},
- {0x1f57, {1|U, {0x1f5f}}},
- {0x1f60, {1|U, {0x1f68}}},
- {0x1f61, {1|U, {0x1f69}}},
- {0x1f62, {1|U, {0x1f6a}}},
- {0x1f63, {1|U, {0x1f6b}}},
- {0x1f64, {1|U, {0x1f6c}}},
- {0x1f65, {1|U, {0x1f6d}}},
- {0x1f66, {1|U, {0x1f6e}}},
- {0x1f67, {1|U, {0x1f6f}}},
- {0x1f70, {1|U, {0x1fba}}},
- {0x1f71, {1|U, {0x1fbb}}},
- {0x1f72, {1|U, {0x1fc8}}},
- {0x1f73, {1|U, {0x1fc9}}},
- {0x1f74, {1|U, {0x1fca}}},
- {0x1f75, {1|U, {0x1fcb}}},
- {0x1f76, {1|U, {0x1fda}}},
- {0x1f77, {1|U, {0x1fdb}}},
- {0x1f78, {1|U, {0x1ff8}}},
- {0x1f79, {1|U, {0x1ff9}}},
- {0x1f7a, {1|U, {0x1fea}}},
- {0x1f7b, {1|U, {0x1feb}}},
- {0x1f7c, {1|U, {0x1ffa}}},
- {0x1f7d, {1|U, {0x1ffb}}},
- {0x1fb0, {1|U, {0x1fb8}}},
- {0x1fb1, {1|U, {0x1fb9}}},
- {0x1fd0, {1|U, {0x1fd8}}},
- {0x1fd1, {1|U, {0x1fd9}}},
- {0x1fe0, {1|U, {0x1fe8}}},
- {0x1fe1, {1|U, {0x1fe9}}},
- {0x1fe5, {1|U, {0x1fec}}},
- {0x214e, {1|U, {0x2132}}},
- {0x2170, {1|U, {0x2160}}},
- {0x2171, {1|U, {0x2161}}},
- {0x2172, {1|U, {0x2162}}},
- {0x2173, {1|U, {0x2163}}},
- {0x2174, {1|U, {0x2164}}},
- {0x2175, {1|U, {0x2165}}},
- {0x2176, {1|U, {0x2166}}},
- {0x2177, {1|U, {0x2167}}},
- {0x2178, {1|U, {0x2168}}},
- {0x2179, {1|U, {0x2169}}},
- {0x217a, {1|U, {0x216a}}},
- {0x217b, {1|U, {0x216b}}},
- {0x217c, {1|U, {0x216c}}},
- {0x217d, {1|U, {0x216d}}},
- {0x217e, {1|U, {0x216e}}},
- {0x217f, {1|U, {0x216f}}},
- {0x2184, {1|U, {0x2183}}},
- {0x24d0, {1|U, {0x24b6}}},
- {0x24d1, {1|U, {0x24b7}}},
- {0x24d2, {1|U, {0x24b8}}},
- {0x24d3, {1|U, {0x24b9}}},
- {0x24d4, {1|U, {0x24ba}}},
- {0x24d5, {1|U, {0x24bb}}},
- {0x24d6, {1|U, {0x24bc}}},
- {0x24d7, {1|U, {0x24bd}}},
- {0x24d8, {1|U, {0x24be}}},
- {0x24d9, {1|U, {0x24bf}}},
- {0x24da, {1|U, {0x24c0}}},
- {0x24db, {1|U, {0x24c1}}},
- {0x24dc, {1|U, {0x24c2}}},
- {0x24dd, {1|U, {0x24c3}}},
- {0x24de, {1|U, {0x24c4}}},
- {0x24df, {1|U, {0x24c5}}},
- {0x24e0, {1|U, {0x24c6}}},
- {0x24e1, {1|U, {0x24c7}}},
- {0x24e2, {1|U, {0x24c8}}},
- {0x24e3, {1|U, {0x24c9}}},
- {0x24e4, {1|U, {0x24ca}}},
- {0x24e5, {1|U, {0x24cb}}},
- {0x24e6, {1|U, {0x24cc}}},
- {0x24e7, {1|U, {0x24cd}}},
- {0x24e8, {1|U, {0x24ce}}},
- {0x24e9, {1|U, {0x24cf}}},
- {0x2c30, {1|U, {0x2c00}}},
- {0x2c31, {1|U, {0x2c01}}},
- {0x2c32, {1|U, {0x2c02}}},
- {0x2c33, {1|U, {0x2c03}}},
- {0x2c34, {1|U, {0x2c04}}},
- {0x2c35, {1|U, {0x2c05}}},
- {0x2c36, {1|U, {0x2c06}}},
- {0x2c37, {1|U, {0x2c07}}},
- {0x2c38, {1|U, {0x2c08}}},
- {0x2c39, {1|U, {0x2c09}}},
- {0x2c3a, {1|U, {0x2c0a}}},
- {0x2c3b, {1|U, {0x2c0b}}},
- {0x2c3c, {1|U, {0x2c0c}}},
- {0x2c3d, {1|U, {0x2c0d}}},
- {0x2c3e, {1|U, {0x2c0e}}},
- {0x2c3f, {1|U, {0x2c0f}}},
- {0x2c40, {1|U, {0x2c10}}},
- {0x2c41, {1|U, {0x2c11}}},
- {0x2c42, {1|U, {0x2c12}}},
- {0x2c43, {1|U, {0x2c13}}},
- {0x2c44, {1|U, {0x2c14}}},
- {0x2c45, {1|U, {0x2c15}}},
- {0x2c46, {1|U, {0x2c16}}},
- {0x2c47, {1|U, {0x2c17}}},
- {0x2c48, {1|U, {0x2c18}}},
- {0x2c49, {1|U, {0x2c19}}},
- {0x2c4a, {1|U, {0x2c1a}}},
- {0x2c4b, {1|U, {0x2c1b}}},
- {0x2c4c, {1|U, {0x2c1c}}},
- {0x2c4d, {1|U, {0x2c1d}}},
- {0x2c4e, {1|U, {0x2c1e}}},
- {0x2c4f, {1|U, {0x2c1f}}},
- {0x2c50, {1|U, {0x2c20}}},
- {0x2c51, {1|U, {0x2c21}}},
- {0x2c52, {1|U, {0x2c22}}},
- {0x2c53, {1|U, {0x2c23}}},
- {0x2c54, {1|U, {0x2c24}}},
- {0x2c55, {1|U, {0x2c25}}},
- {0x2c56, {1|U, {0x2c26}}},
- {0x2c57, {1|U, {0x2c27}}},
- {0x2c58, {1|U, {0x2c28}}},
- {0x2c59, {1|U, {0x2c29}}},
- {0x2c5a, {1|U, {0x2c2a}}},
- {0x2c5b, {1|U, {0x2c2b}}},
- {0x2c5c, {1|U, {0x2c2c}}},
- {0x2c5d, {1|U, {0x2c2d}}},
- {0x2c5e, {1|U, {0x2c2e}}},
- {0x2c5f, {1|U, {0x2c2f}}},
- {0x2c61, {1|U, {0x2c60}}},
- {0x2c65, {1|U, {0x023a}}},
- {0x2c66, {1|U, {0x023e}}},
- {0x2c68, {1|U, {0x2c67}}},
- {0x2c6a, {1|U, {0x2c69}}},
- {0x2c6c, {1|U, {0x2c6b}}},
- {0x2c73, {1|U, {0x2c72}}},
- {0x2c76, {1|U, {0x2c75}}},
- {0x2c81, {1|U, {0x2c80}}},
- {0x2c83, {1|U, {0x2c82}}},
- {0x2c85, {1|U, {0x2c84}}},
- {0x2c87, {1|U, {0x2c86}}},
- {0x2c89, {1|U, {0x2c88}}},
- {0x2c8b, {1|U, {0x2c8a}}},
- {0x2c8d, {1|U, {0x2c8c}}},
- {0x2c8f, {1|U, {0x2c8e}}},
- {0x2c91, {1|U, {0x2c90}}},
- {0x2c93, {1|U, {0x2c92}}},
- {0x2c95, {1|U, {0x2c94}}},
- {0x2c97, {1|U, {0x2c96}}},
- {0x2c99, {1|U, {0x2c98}}},
- {0x2c9b, {1|U, {0x2c9a}}},
- {0x2c9d, {1|U, {0x2c9c}}},
- {0x2c9f, {1|U, {0x2c9e}}},
- {0x2ca1, {1|U, {0x2ca0}}},
- {0x2ca3, {1|U, {0x2ca2}}},
- {0x2ca5, {1|U, {0x2ca4}}},
- {0x2ca7, {1|U, {0x2ca6}}},
- {0x2ca9, {1|U, {0x2ca8}}},
- {0x2cab, {1|U, {0x2caa}}},
- {0x2cad, {1|U, {0x2cac}}},
- {0x2caf, {1|U, {0x2cae}}},
- {0x2cb1, {1|U, {0x2cb0}}},
- {0x2cb3, {1|U, {0x2cb2}}},
- {0x2cb5, {1|U, {0x2cb4}}},
- {0x2cb7, {1|U, {0x2cb6}}},
- {0x2cb9, {1|U, {0x2cb8}}},
- {0x2cbb, {1|U, {0x2cba}}},
- {0x2cbd, {1|U, {0x2cbc}}},
- {0x2cbf, {1|U, {0x2cbe}}},
- {0x2cc1, {1|U, {0x2cc0}}},
- {0x2cc3, {1|U, {0x2cc2}}},
- {0x2cc5, {1|U, {0x2cc4}}},
- {0x2cc7, {1|U, {0x2cc6}}},
- {0x2cc9, {1|U, {0x2cc8}}},
- {0x2ccb, {1|U, {0x2cca}}},
- {0x2ccd, {1|U, {0x2ccc}}},
- {0x2ccf, {1|U, {0x2cce}}},
- {0x2cd1, {1|U, {0x2cd0}}},
- {0x2cd3, {1|U, {0x2cd2}}},
- {0x2cd5, {1|U, {0x2cd4}}},
- {0x2cd7, {1|U, {0x2cd6}}},
- {0x2cd9, {1|U, {0x2cd8}}},
- {0x2cdb, {1|U, {0x2cda}}},
- {0x2cdd, {1|U, {0x2cdc}}},
- {0x2cdf, {1|U, {0x2cde}}},
- {0x2ce1, {1|U, {0x2ce0}}},
- {0x2ce3, {1|U, {0x2ce2}}},
- {0x2cec, {1|U, {0x2ceb}}},
- {0x2cee, {1|U, {0x2ced}}},
- {0x2cf3, {1|U, {0x2cf2}}},
- {0x2d00, {1|U, {0x10a0}}},
- {0x2d01, {1|U, {0x10a1}}},
- {0x2d02, {1|U, {0x10a2}}},
- {0x2d03, {1|U, {0x10a3}}},
- {0x2d04, {1|U, {0x10a4}}},
- {0x2d05, {1|U, {0x10a5}}},
- {0x2d06, {1|U, {0x10a6}}},
- {0x2d07, {1|U, {0x10a7}}},
- {0x2d08, {1|U, {0x10a8}}},
- {0x2d09, {1|U, {0x10a9}}},
- {0x2d0a, {1|U, {0x10aa}}},
- {0x2d0b, {1|U, {0x10ab}}},
- {0x2d0c, {1|U, {0x10ac}}},
- {0x2d0d, {1|U, {0x10ad}}},
- {0x2d0e, {1|U, {0x10ae}}},
- {0x2d0f, {1|U, {0x10af}}},
- {0x2d10, {1|U, {0x10b0}}},
- {0x2d11, {1|U, {0x10b1}}},
- {0x2d12, {1|U, {0x10b2}}},
- {0x2d13, {1|U, {0x10b3}}},
- {0x2d14, {1|U, {0x10b4}}},
- {0x2d15, {1|U, {0x10b5}}},
- {0x2d16, {1|U, {0x10b6}}},
- {0x2d17, {1|U, {0x10b7}}},
- {0x2d18, {1|U, {0x10b8}}},
- {0x2d19, {1|U, {0x10b9}}},
- {0x2d1a, {1|U, {0x10ba}}},
- {0x2d1b, {1|U, {0x10bb}}},
- {0x2d1c, {1|U, {0x10bc}}},
- {0x2d1d, {1|U, {0x10bd}}},
- {0x2d1e, {1|U, {0x10be}}},
- {0x2d1f, {1|U, {0x10bf}}},
- {0x2d20, {1|U, {0x10c0}}},
- {0x2d21, {1|U, {0x10c1}}},
- {0x2d22, {1|U, {0x10c2}}},
- {0x2d23, {1|U, {0x10c3}}},
- {0x2d24, {1|U, {0x10c4}}},
- {0x2d25, {1|U, {0x10c5}}},
- {0x2d27, {1|U, {0x10c7}}},
- {0x2d2d, {1|U, {0x10cd}}},
- {0xa641, {1|U, {0xa640}}},
- {0xa643, {1|U, {0xa642}}},
- {0xa645, {1|U, {0xa644}}},
- {0xa647, {1|U, {0xa646}}},
- {0xa649, {1|U, {0xa648}}},
- {0xa64b, {2|U, {0xa64a, 0x1c88}}},
- {0xa64d, {1|U, {0xa64c}}},
- {0xa64f, {1|U, {0xa64e}}},
- {0xa651, {1|U, {0xa650}}},
- {0xa653, {1|U, {0xa652}}},
- {0xa655, {1|U, {0xa654}}},
- {0xa657, {1|U, {0xa656}}},
- {0xa659, {1|U, {0xa658}}},
- {0xa65b, {1|U, {0xa65a}}},
- {0xa65d, {1|U, {0xa65c}}},
- {0xa65f, {1|U, {0xa65e}}},
- {0xa661, {1|U, {0xa660}}},
- {0xa663, {1|U, {0xa662}}},
- {0xa665, {1|U, {0xa664}}},
- {0xa667, {1|U, {0xa666}}},
- {0xa669, {1|U, {0xa668}}},
- {0xa66b, {1|U, {0xa66a}}},
- {0xa66d, {1|U, {0xa66c}}},
- {0xa681, {1|U, {0xa680}}},
- {0xa683, {1|U, {0xa682}}},
- {0xa685, {1|U, {0xa684}}},
- {0xa687, {1|U, {0xa686}}},
- {0xa689, {1|U, {0xa688}}},
- {0xa68b, {1|U, {0xa68a}}},
- {0xa68d, {1|U, {0xa68c}}},
- {0xa68f, {1|U, {0xa68e}}},
- {0xa691, {1|U, {0xa690}}},
- {0xa693, {1|U, {0xa692}}},
- {0xa695, {1|U, {0xa694}}},
- {0xa697, {1|U, {0xa696}}},
- {0xa699, {1|U, {0xa698}}},
- {0xa69b, {1|U, {0xa69a}}},
- {0xa723, {1|U, {0xa722}}},
- {0xa725, {1|U, {0xa724}}},
- {0xa727, {1|U, {0xa726}}},
- {0xa729, {1|U, {0xa728}}},
- {0xa72b, {1|U, {0xa72a}}},
- {0xa72d, {1|U, {0xa72c}}},
- {0xa72f, {1|U, {0xa72e}}},
- {0xa733, {1|U, {0xa732}}},
- {0xa735, {1|U, {0xa734}}},
- {0xa737, {1|U, {0xa736}}},
- {0xa739, {1|U, {0xa738}}},
- {0xa73b, {1|U, {0xa73a}}},
- {0xa73d, {1|U, {0xa73c}}},
- {0xa73f, {1|U, {0xa73e}}},
- {0xa741, {1|U, {0xa740}}},
- {0xa743, {1|U, {0xa742}}},
- {0xa745, {1|U, {0xa744}}},
- {0xa747, {1|U, {0xa746}}},
- {0xa749, {1|U, {0xa748}}},
- {0xa74b, {1|U, {0xa74a}}},
- {0xa74d, {1|U, {0xa74c}}},
- {0xa74f, {1|U, {0xa74e}}},
- {0xa751, {1|U, {0xa750}}},
- {0xa753, {1|U, {0xa752}}},
- {0xa755, {1|U, {0xa754}}},
- {0xa757, {1|U, {0xa756}}},
- {0xa759, {1|U, {0xa758}}},
- {0xa75b, {1|U, {0xa75a}}},
- {0xa75d, {1|U, {0xa75c}}},
- {0xa75f, {1|U, {0xa75e}}},
- {0xa761, {1|U, {0xa760}}},
- {0xa763, {1|U, {0xa762}}},
- {0xa765, {1|U, {0xa764}}},
- {0xa767, {1|U, {0xa766}}},
- {0xa769, {1|U, {0xa768}}},
- {0xa76b, {1|U, {0xa76a}}},
- {0xa76d, {1|U, {0xa76c}}},
- {0xa76f, {1|U, {0xa76e}}},
- {0xa77a, {1|U, {0xa779}}},
- {0xa77c, {1|U, {0xa77b}}},
- {0xa77f, {1|U, {0xa77e}}},
- {0xa781, {1|U, {0xa780}}},
- {0xa783, {1|U, {0xa782}}},
- {0xa785, {1|U, {0xa784}}},
- {0xa787, {1|U, {0xa786}}},
- {0xa78c, {1|U, {0xa78b}}},
- {0xa791, {1|U, {0xa790}}},
- {0xa793, {1|U, {0xa792}}},
- {0xa794, {1|U, {0xa7c4}}},
- {0xa797, {1|U, {0xa796}}},
- {0xa799, {1|U, {0xa798}}},
- {0xa79b, {1|U, {0xa79a}}},
- {0xa79d, {1|U, {0xa79c}}},
- {0xa79f, {1|U, {0xa79e}}},
- {0xa7a1, {1|U, {0xa7a0}}},
- {0xa7a3, {1|U, {0xa7a2}}},
- {0xa7a5, {1|U, {0xa7a4}}},
- {0xa7a7, {1|U, {0xa7a6}}},
- {0xa7a9, {1|U, {0xa7a8}}},
- {0xa7b5, {1|U, {0xa7b4}}},
- {0xa7b7, {1|U, {0xa7b6}}},
- {0xa7b9, {1|U, {0xa7b8}}},
- {0xa7bb, {1|U, {0xa7ba}}},
- {0xa7bd, {1|U, {0xa7bc}}},
- {0xa7bf, {1|U, {0xa7be}}},
- {0xa7c1, {1|U, {0xa7c0}}},
- {0xa7c3, {1|U, {0xa7c2}}},
- {0xa7c8, {1|U, {0xa7c7}}},
- {0xa7ca, {1|U, {0xa7c9}}},
- {0xa7d1, {1|U, {0xa7d0}}},
- {0xa7d7, {1|U, {0xa7d6}}},
- {0xa7d9, {1|U, {0xa7d8}}},
- {0xa7f6, {1|U, {0xa7f5}}},
- {0xab53, {1|U, {0xa7b3}}},
- {0xff41, {1|U, {0xff21}}},
- {0xff42, {1|U, {0xff22}}},
- {0xff43, {1|U, {0xff23}}},
- {0xff44, {1|U, {0xff24}}},
- {0xff45, {1|U, {0xff25}}},
- {0xff46, {1|U, {0xff26}}},
- {0xff47, {1|U, {0xff27}}},
- {0xff48, {1|U, {0xff28}}},
- {0xff49, {1|U, {0xff29}}},
- {0xff4a, {1|U, {0xff2a}}},
- {0xff4b, {1|U, {0xff2b}}},
- {0xff4c, {1|U, {0xff2c}}},
- {0xff4d, {1|U, {0xff2d}}},
- {0xff4e, {1|U, {0xff2e}}},
- {0xff4f, {1|U, {0xff2f}}},
- {0xff50, {1|U, {0xff30}}},
- {0xff51, {1|U, {0xff31}}},
- {0xff52, {1|U, {0xff32}}},
- {0xff53, {1|U, {0xff33}}},
- {0xff54, {1|U, {0xff34}}},
- {0xff55, {1|U, {0xff35}}},
- {0xff56, {1|U, {0xff36}}},
- {0xff57, {1|U, {0xff37}}},
- {0xff58, {1|U, {0xff38}}},
- {0xff59, {1|U, {0xff39}}},
- {0xff5a, {1|U, {0xff3a}}},
- {0x10428, {1|U, {0x10400}}},
- {0x10429, {1|U, {0x10401}}},
- {0x1042a, {1|U, {0x10402}}},
- {0x1042b, {1|U, {0x10403}}},
- {0x1042c, {1|U, {0x10404}}},
- {0x1042d, {1|U, {0x10405}}},
- {0x1042e, {1|U, {0x10406}}},
- {0x1042f, {1|U, {0x10407}}},
- {0x10430, {1|U, {0x10408}}},
- {0x10431, {1|U, {0x10409}}},
- {0x10432, {1|U, {0x1040a}}},
- {0x10433, {1|U, {0x1040b}}},
- {0x10434, {1|U, {0x1040c}}},
- {0x10435, {1|U, {0x1040d}}},
- {0x10436, {1|U, {0x1040e}}},
- {0x10437, {1|U, {0x1040f}}},
- {0x10438, {1|U, {0x10410}}},
- {0x10439, {1|U, {0x10411}}},
- {0x1043a, {1|U, {0x10412}}},
- {0x1043b, {1|U, {0x10413}}},
- {0x1043c, {1|U, {0x10414}}},
- {0x1043d, {1|U, {0x10415}}},
- {0x1043e, {1|U, {0x10416}}},
- {0x1043f, {1|U, {0x10417}}},
- {0x10440, {1|U, {0x10418}}},
- {0x10441, {1|U, {0x10419}}},
- {0x10442, {1|U, {0x1041a}}},
- {0x10443, {1|U, {0x1041b}}},
- {0x10444, {1|U, {0x1041c}}},
- {0x10445, {1|U, {0x1041d}}},
- {0x10446, {1|U, {0x1041e}}},
- {0x10447, {1|U, {0x1041f}}},
- {0x10448, {1|U, {0x10420}}},
- {0x10449, {1|U, {0x10421}}},
- {0x1044a, {1|U, {0x10422}}},
- {0x1044b, {1|U, {0x10423}}},
- {0x1044c, {1|U, {0x10424}}},
- {0x1044d, {1|U, {0x10425}}},
- {0x1044e, {1|U, {0x10426}}},
- {0x1044f, {1|U, {0x10427}}},
- {0x104d8, {1|U, {0x104b0}}},
- {0x104d9, {1|U, {0x104b1}}},
- {0x104da, {1|U, {0x104b2}}},
- {0x104db, {1|U, {0x104b3}}},
- {0x104dc, {1|U, {0x104b4}}},
- {0x104dd, {1|U, {0x104b5}}},
- {0x104de, {1|U, {0x104b6}}},
- {0x104df, {1|U, {0x104b7}}},
- {0x104e0, {1|U, {0x104b8}}},
- {0x104e1, {1|U, {0x104b9}}},
- {0x104e2, {1|U, {0x104ba}}},
- {0x104e3, {1|U, {0x104bb}}},
- {0x104e4, {1|U, {0x104bc}}},
- {0x104e5, {1|U, {0x104bd}}},
- {0x104e6, {1|U, {0x104be}}},
- {0x104e7, {1|U, {0x104bf}}},
- {0x104e8, {1|U, {0x104c0}}},
- {0x104e9, {1|U, {0x104c1}}},
- {0x104ea, {1|U, {0x104c2}}},
- {0x104eb, {1|U, {0x104c3}}},
- {0x104ec, {1|U, {0x104c4}}},
- {0x104ed, {1|U, {0x104c5}}},
- {0x104ee, {1|U, {0x104c6}}},
- {0x104ef, {1|U, {0x104c7}}},
- {0x104f0, {1|U, {0x104c8}}},
- {0x104f1, {1|U, {0x104c9}}},
- {0x104f2, {1|U, {0x104ca}}},
- {0x104f3, {1|U, {0x104cb}}},
- {0x104f4, {1|U, {0x104cc}}},
- {0x104f5, {1|U, {0x104cd}}},
- {0x104f6, {1|U, {0x104ce}}},
- {0x104f7, {1|U, {0x104cf}}},
- {0x104f8, {1|U, {0x104d0}}},
- {0x104f9, {1|U, {0x104d1}}},
- {0x104fa, {1|U, {0x104d2}}},
- {0x104fb, {1|U, {0x104d3}}},
- {0x10597, {1|U, {0x10570}}},
- {0x10598, {1|U, {0x10571}}},
- {0x10599, {1|U, {0x10572}}},
- {0x1059a, {1|U, {0x10573}}},
- {0x1059b, {1|U, {0x10574}}},
- {0x1059c, {1|U, {0x10575}}},
- {0x1059d, {1|U, {0x10576}}},
- {0x1059e, {1|U, {0x10577}}},
- {0x1059f, {1|U, {0x10578}}},
- {0x105a0, {1|U, {0x10579}}},
- {0x105a1, {1|U, {0x1057a}}},
- {0x105a3, {1|U, {0x1057c}}},
- {0x105a4, {1|U, {0x1057d}}},
- {0x105a5, {1|U, {0x1057e}}},
- {0x105a6, {1|U, {0x1057f}}},
- {0x105a7, {1|U, {0x10580}}},
- {0x105a8, {1|U, {0x10581}}},
- {0x105a9, {1|U, {0x10582}}},
- {0x105aa, {1|U, {0x10583}}},
- {0x105ab, {1|U, {0x10584}}},
- {0x105ac, {1|U, {0x10585}}},
- {0x105ad, {1|U, {0x10586}}},
- {0x105ae, {1|U, {0x10587}}},
- {0x105af, {1|U, {0x10588}}},
- {0x105b0, {1|U, {0x10589}}},
- {0x105b1, {1|U, {0x1058a}}},
- {0x105b3, {1|U, {0x1058c}}},
- {0x105b4, {1|U, {0x1058d}}},
- {0x105b5, {1|U, {0x1058e}}},
- {0x105b6, {1|U, {0x1058f}}},
- {0x105b7, {1|U, {0x10590}}},
- {0x105b8, {1|U, {0x10591}}},
- {0x105b9, {1|U, {0x10592}}},
- {0x105bb, {1|U, {0x10594}}},
- {0x105bc, {1|U, {0x10595}}},
- {0x10cc0, {1|U, {0x10c80}}},
- {0x10cc1, {1|U, {0x10c81}}},
- {0x10cc2, {1|U, {0x10c82}}},
- {0x10cc3, {1|U, {0x10c83}}},
- {0x10cc4, {1|U, {0x10c84}}},
- {0x10cc5, {1|U, {0x10c85}}},
- {0x10cc6, {1|U, {0x10c86}}},
- {0x10cc7, {1|U, {0x10c87}}},
- {0x10cc8, {1|U, {0x10c88}}},
- {0x10cc9, {1|U, {0x10c89}}},
- {0x10cca, {1|U, {0x10c8a}}},
- {0x10ccb, {1|U, {0x10c8b}}},
- {0x10ccc, {1|U, {0x10c8c}}},
- {0x10ccd, {1|U, {0x10c8d}}},
- {0x10cce, {1|U, {0x10c8e}}},
- {0x10ccf, {1|U, {0x10c8f}}},
- {0x10cd0, {1|U, {0x10c90}}},
- {0x10cd1, {1|U, {0x10c91}}},
- {0x10cd2, {1|U, {0x10c92}}},
- {0x10cd3, {1|U, {0x10c93}}},
- {0x10cd4, {1|U, {0x10c94}}},
- {0x10cd5, {1|U, {0x10c95}}},
- {0x10cd6, {1|U, {0x10c96}}},
- {0x10cd7, {1|U, {0x10c97}}},
- {0x10cd8, {1|U, {0x10c98}}},
- {0x10cd9, {1|U, {0x10c99}}},
- {0x10cda, {1|U, {0x10c9a}}},
- {0x10cdb, {1|U, {0x10c9b}}},
- {0x10cdc, {1|U, {0x10c9c}}},
- {0x10cdd, {1|U, {0x10c9d}}},
- {0x10cde, {1|U, {0x10c9e}}},
- {0x10cdf, {1|U, {0x10c9f}}},
- {0x10ce0, {1|U, {0x10ca0}}},
- {0x10ce1, {1|U, {0x10ca1}}},
- {0x10ce2, {1|U, {0x10ca2}}},
- {0x10ce3, {1|U, {0x10ca3}}},
- {0x10ce4, {1|U, {0x10ca4}}},
- {0x10ce5, {1|U, {0x10ca5}}},
- {0x10ce6, {1|U, {0x10ca6}}},
- {0x10ce7, {1|U, {0x10ca7}}},
- {0x10ce8, {1|U, {0x10ca8}}},
- {0x10ce9, {1|U, {0x10ca9}}},
- {0x10cea, {1|U, {0x10caa}}},
- {0x10ceb, {1|U, {0x10cab}}},
- {0x10cec, {1|U, {0x10cac}}},
- {0x10ced, {1|U, {0x10cad}}},
- {0x10cee, {1|U, {0x10cae}}},
- {0x10cef, {1|U, {0x10caf}}},
- {0x10cf0, {1|U, {0x10cb0}}},
- {0x10cf1, {1|U, {0x10cb1}}},
- {0x10cf2, {1|U, {0x10cb2}}},
- {0x118c0, {1|U, {0x118a0}}},
- {0x118c1, {1|U, {0x118a1}}},
- {0x118c2, {1|U, {0x118a2}}},
- {0x118c3, {1|U, {0x118a3}}},
- {0x118c4, {1|U, {0x118a4}}},
- {0x118c5, {1|U, {0x118a5}}},
- {0x118c6, {1|U, {0x118a6}}},
- {0x118c7, {1|U, {0x118a7}}},
- {0x118c8, {1|U, {0x118a8}}},
- {0x118c9, {1|U, {0x118a9}}},
- {0x118ca, {1|U, {0x118aa}}},
- {0x118cb, {1|U, {0x118ab}}},
- {0x118cc, {1|U, {0x118ac}}},
- {0x118cd, {1|U, {0x118ad}}},
- {0x118ce, {1|U, {0x118ae}}},
- {0x118cf, {1|U, {0x118af}}},
- {0x118d0, {1|U, {0x118b0}}},
- {0x118d1, {1|U, {0x118b1}}},
- {0x118d2, {1|U, {0x118b2}}},
- {0x118d3, {1|U, {0x118b3}}},
- {0x118d4, {1|U, {0x118b4}}},
- {0x118d5, {1|U, {0x118b5}}},
- {0x118d6, {1|U, {0x118b6}}},
- {0x118d7, {1|U, {0x118b7}}},
- {0x118d8, {1|U, {0x118b8}}},
- {0x118d9, {1|U, {0x118b9}}},
- {0x118da, {1|U, {0x118ba}}},
- {0x118db, {1|U, {0x118bb}}},
- {0x118dc, {1|U, {0x118bc}}},
- {0x118dd, {1|U, {0x118bd}}},
- {0x118de, {1|U, {0x118be}}},
- {0x118df, {1|U, {0x118bf}}},
- {0x16e60, {1|U, {0x16e40}}},
- {0x16e61, {1|U, {0x16e41}}},
- {0x16e62, {1|U, {0x16e42}}},
- {0x16e63, {1|U, {0x16e43}}},
- {0x16e64, {1|U, {0x16e44}}},
- {0x16e65, {1|U, {0x16e45}}},
- {0x16e66, {1|U, {0x16e46}}},
- {0x16e67, {1|U, {0x16e47}}},
- {0x16e68, {1|U, {0x16e48}}},
- {0x16e69, {1|U, {0x16e49}}},
- {0x16e6a, {1|U, {0x16e4a}}},
- {0x16e6b, {1|U, {0x16e4b}}},
- {0x16e6c, {1|U, {0x16e4c}}},
- {0x16e6d, {1|U, {0x16e4d}}},
- {0x16e6e, {1|U, {0x16e4e}}},
- {0x16e6f, {1|U, {0x16e4f}}},
- {0x16e70, {1|U, {0x16e50}}},
- {0x16e71, {1|U, {0x16e51}}},
- {0x16e72, {1|U, {0x16e52}}},
- {0x16e73, {1|U, {0x16e53}}},
- {0x16e74, {1|U, {0x16e54}}},
- {0x16e75, {1|U, {0x16e55}}},
- {0x16e76, {1|U, {0x16e56}}},
- {0x16e77, {1|U, {0x16e57}}},
- {0x16e78, {1|U, {0x16e58}}},
- {0x16e79, {1|U, {0x16e59}}},
- {0x16e7a, {1|U, {0x16e5a}}},
- {0x16e7b, {1|U, {0x16e5b}}},
- {0x16e7c, {1|U, {0x16e5c}}},
- {0x16e7d, {1|U, {0x16e5d}}},
- {0x16e7e, {1|U, {0x16e5e}}},
- {0x16e7f, {1|U, {0x16e5f}}},
- {0x1e922, {1|U, {0x1e900}}},
- {0x1e923, {1|U, {0x1e901}}},
- {0x1e924, {1|U, {0x1e902}}},
- {0x1e925, {1|U, {0x1e903}}},
- {0x1e926, {1|U, {0x1e904}}},
- {0x1e927, {1|U, {0x1e905}}},
- {0x1e928, {1|U, {0x1e906}}},
- {0x1e929, {1|U, {0x1e907}}},
- {0x1e92a, {1|U, {0x1e908}}},
- {0x1e92b, {1|U, {0x1e909}}},
- {0x1e92c, {1|U, {0x1e90a}}},
- {0x1e92d, {1|U, {0x1e90b}}},
- {0x1e92e, {1|U, {0x1e90c}}},
- {0x1e92f, {1|U, {0x1e90d}}},
- {0x1e930, {1|U, {0x1e90e}}},
- {0x1e931, {1|U, {0x1e90f}}},
- {0x1e932, {1|U, {0x1e910}}},
- {0x1e933, {1|U, {0x1e911}}},
- {0x1e934, {1|U, {0x1e912}}},
- {0x1e935, {1|U, {0x1e913}}},
- {0x1e936, {1|U, {0x1e914}}},
- {0x1e937, {1|U, {0x1e915}}},
- {0x1e938, {1|U, {0x1e916}}},
- {0x1e939, {1|U, {0x1e917}}},
- {0x1e93a, {1|U, {0x1e918}}},
- {0x1e93b, {1|U, {0x1e919}}},
- {0x1e93c, {1|U, {0x1e91a}}},
- {0x1e93d, {1|U, {0x1e91b}}},
- {0x1e93e, {1|U, {0x1e91c}}},
- {0x1e93f, {1|U, {0x1e91d}}},
- {0x1e940, {1|U, {0x1e91e}}},
- {0x1e941, {1|U, {0x1e91f}}},
- {0x1e942, {1|U, {0x1e920}}},
- {0x1e943, {1|U, {0x1e921}}},
-#define CaseUnfold_11_Locale (*(CaseUnfold_11_Type (*)[1])(CaseUnfold_11_Table+1395))
- {0x0069, {1|U, {0x0049}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_11_hash -N onigenc_unicode_CaseUnfold_11_lookup -n */
-
-/* maximum key range = 2771, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseUnfold_11_hash(const OnigCodePoint code)
-{
- static const unsigned short asso_values[] =
- {
- 1, 2774, 2, 2, 4, 421, 9, 371, 231, 463,
- 37, 20, 2, 3, 419, 408, 2774, 2774, 2774, 2774,
- 2774, 2774, 2774, 2774, 2774, 2774, 2774, 2774, 2774, 112,
- 2774, 2774, 2774, 2774, 2774, 2774, 2774, 120, 2774, 2774,
- 2774, 2774, 2774, 1, 2774, 2774, 2774, 2774, 2774, 2774,
- 2774, 2774, 2774, 355, 2774, 2774, 2774, 2774, 2774, 2774,
- 2774, 2774, 10, 9, 7, 8, 244, 689, 226, 993,
- 561, 710, 104, 1429, 36, 1190, 28, 15, 114, 1768,
- 241, 1003, 87, 285, 26, 1399, 78, 1360, 7, 1455,
- 90, 1076, 113, 10, 724, 1460, 167, 1727, 155, 1040,
- 67, 754, 66, 705, 246, 886, 331, 1140, 430, 1251,
- 864, 768, 643, 1064, 1591, 865, 834, 720, 1700, 671,
- 1581, 657, 1794, 842, 1782, 1050, 1537, 1024, 1760, 814,
- 975, 440, 1187, 407, 1440, 951, 1384, 909, 1320, 555,
- 1567, 541, 1723, 525, 383, 501, 1179, 250, 1596, 342,
- 1575, 352, 1501, 194, 1559, 70, 1512, 85, 1509, 129,
- 467, 100, 1413, 1, 1485, 25, 1351, 35, 1088, 55,
- 1262, 45, 1277, 160, 1245, 317, 118, 220, 1300, 596,
- 1100, 373, 1632, 617, 1337, 1236, 1500, 1152, 148, 793,
- 1538, 979, 385, 1228
- };
- return asso_values[bits_of(code, 2)+66] + asso_values[bits_of(code, 1)+4] + asso_values[bits_of(code, 0)];
-}
-
-static const CodePointList3 *
-onigenc_unicode_CaseUnfold_11_lookup(const OnigCodePoint code)
-{
- enum
- {
- MIN_CODE_VALUE = 0x61,
- MAX_CODE_VALUE = 0x1e943,
- TOTAL_KEYWORDS = 1396,
- MIN_WORD_LENGTH = 3,
- MAX_WORD_LENGTH = 3,
- MIN_HASH_VALUE = 3,
- MAX_HASH_VALUE = 2773
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1,
- /*0x13e1*/ 589,
- /*0x0461*/ 340,
- /*0x04e1*/ 400,
- /*0x0061*/ 0,
- -1,
- /*0x104e1*/ 1184,
- /*0x1e61*/ 661,
- /*0x1ee1*/ 720,
- /*0x0161*/ 102,
- /*0x2ce1*/ 953,
- -1,
- /*0x049b*/ 365,
- -1, -1,
- /*0x24e1*/ 840,
- /*0x1e1b*/ 626,
- /*0x048b*/ 357,
- /*0x011b*/ 69,
- /*0x2c9b*/ 918,
- /*0x03e1*/ 280,
- /*0x1e0b*/ 618,
- /*0x1e8b*/ 682,
- /*0x010b*/ 61,
- /*0x2c8b*/ 910,
- /*0x13e3*/ 591,
- /*0x0463*/ 341,
- /*0x04e3*/ 401,
- /*0x0063*/ 2,
- -1,
- /*0x104e3*/ 1186,
- /*0x1e63*/ 662,
- /*0x1ee3*/ 721,
- /*0x0163*/ 103,
- /*0x2ce3*/ 954,
- /*0x13e5*/ 593,
- /*0x0465*/ 342,
- /*0x04e5*/ 402,
- /*0x0065*/ 4,
- /*0x24e3*/ 842,
- /*0x104e5*/ 1188,
- /*0x1e65*/ 663,
- /*0x1ee5*/ 722,
- /*0x0165*/ 104,
- /*0x03e3*/ 281,
- /*0x13e9*/ 597,
- /*0x0469*/ 344,
- /*0x04e9*/ 404,
- /*0x0069*/ 1395,
- /*0x24e5*/ 844,
- /*0x104e9*/ 1192,
- /*0x1e69*/ 665,
- /*0x1ee9*/ 724,
- /*0x0169*/ 106,
- /*0x03e5*/ 282,
- /*0x13e7*/ 595,
- /*0x0467*/ 343,
- /*0x04e7*/ 403,
- /*0x0067*/ 6,
- /*0x24e9*/ 848,
- /*0x104e7*/ 1190,
- /*0x1e67*/ 664,
- /*0x1ee7*/ 723,
- /*0x0167*/ 105,
- /*0x03e9*/ 284,
- -1,
- /*0x13a4*/ 528,
- /*0x13a2*/ 526,
- -1,
- /*0x24e7*/ 846,
- /*0x13d9*/ 581,
- /*0x0459*/ 333,
- /*0x04d9*/ 396,
- -1,
- /*0x03e7*/ 283,
- /*0x104d9*/ 1176,
- /*0x1e59*/ 657,
- /*0x1ed9*/ 716,
- /*0x0159*/ 98,
- /*0x2cd9*/ 949,
- -1, -1, -1, -1,
- /*0x24d9*/ 832,
- /*0x13db*/ 583,
- /*0x045b*/ 335,
- /*0x04db*/ 397,
- /*0xa761*/ 1065,
- /*0x03d9*/ 276,
- /*0x104db*/ 1178,
- /*0x1e5b*/ 658,
- /*0x1edb*/ 717,
- /*0x015b*/ 99,
- /*0x2cdb*/ 950,
- -1, -1, -1, -1,
- /*0x24db*/ 834,
- /*0x13df*/ 587,
- /*0x045f*/ 339,
- /*0x04df*/ 399,
- -1,
- /*0x03db*/ 277,
- /*0x104df*/ 1182,
- /*0x1e5f*/ 660,
- /*0x1edf*/ 719,
- /*0x015f*/ 101,
- /*0x2cdf*/ 952,
- -1, -1,
- /*0xa763*/ 1066,
- /*0x2c61*/ 897,
- /*0x24df*/ 838,
- /*0x10ce1*/ 1279,
- -1, -1,
- /*0x13ee*/ 602,
- /*0x03df*/ 279,
- /*0x10e1*/ 495,
- /*0x006e*/ 12,
- /*0xa765*/ 1067,
- /*0x104ee*/ 1197,
- -1, -1, -1,
- /*0x2cee*/ 956,
- -1,
- /*0x13dd*/ 585,
- /*0x045d*/ 337,
- /*0x04dd*/ 398,
- /*0xa769*/ 1069,
- -1,
- /*0x104dd*/ 1180,
- /*0x1e5d*/ 659,
- /*0x1edd*/ 718,
- /*0x015d*/ 100,
- /*0x2cdd*/ 951,
- /*0x10ce3*/ 1281,
- -1, -1,
- /*0xa767*/ 1068,
- /*0x24dd*/ 836,
- /*0x10e3*/ 497,
- -1, -1,
- /*0x2c65*/ 898,
- /*0x03dd*/ 278,
- /*0x10ce5*/ 1283,
- -1,
- /*0x007a*/ 24,
- -1,
- /*0x104fa*/ 1209,
- /*0x10e5*/ 499,
- /*0x13a0*/ 524,
- /*0x017a*/ 114,
- /*0xa759*/ 1061,
- -1,
- /*0x10ce9*/ 1287,
- /*0x13eb*/ 599,
- /*0x046b*/ 345,
- /*0x04eb*/ 405,
- /*0x006b*/ 9,
- /*0x10e9*/ 503,
- /*0x104eb*/ 1194,
- /*0x1e6b*/ 666,
- /*0x1eeb*/ 725,
- /*0x016b*/ 107,
- /*0x10ce7*/ 1285,
- -1, -1,
- /*0xa75b*/ 1062,
- -1,
- /*0x10e7*/ 501,
- -1, -1, -1, -1,
- /*0x03eb*/ 285,
- -1, -1,
- /*0x2c59*/ 890,
- -1,
- /*0x10cd9*/ 1271,
- -1, -1,
- /*0xa75f*/ 1064,
- -1,
- /*0x10d9*/ 487,
- -1, -1, -1, -1,
- /*0x13d7*/ 579,
- /*0x0457*/ 331,
- /*0x04d7*/ 395,
- /*0x2c5b*/ 892,
- -1,
- /*0x10cdb*/ 1273,
- /*0x1e57*/ 656,
- /*0x1ed7*/ 715,
- /*0x0157*/ 97,
- /*0x2cd7*/ 948,
- /*0x10db*/ 489,
- -1, -1, -1,
- /*0x24d7*/ 830,
- -1, -1, -1,
- /*0x2c5f*/ 896,
- /*0x03d7*/ 275,
- /*0x10cdf*/ 1277,
- -1,
- /*0xa75d*/ 1063,
- -1, -1,
- /*0x10df*/ 493,
- /*0x13ef*/ 603,
- /*0x046f*/ 347,
- /*0x04ef*/ 407,
- /*0x006f*/ 13,
- -1,
- /*0x104ef*/ 1198,
- /*0x1e6f*/ 668,
- /*0x1eef*/ 727,
- /*0x016f*/ 109,
- -1, -1,
- /*0x0261*/ 210,
- /*0x10cee*/ 1292,
- -1, -1,
- /*0xa77a*/ 1073,
- -1,
- /*0x10ee*/ 508,
- -1,
- /*0x03ef*/ 287,
- /*0x021b*/ 178,
- /*0x2c5d*/ 894,
- /*0xa661*/ 1014,
- /*0x10cdd*/ 1275,
- /*0x1f61*/ 777,
- /*0x020b*/ 170,
- /*0x13a6*/ 530,
- /*0xa76b*/ 1070,
- /*0x10dd*/ 491,
- /*0x1d8e*/ 612,
- /*0x13d1*/ 573,
- /*0x0451*/ 325,
- /*0x04d1*/ 392,
- -1, -1,
- /*0x0263*/ 211,
- /*0x1e51*/ 653,
- /*0x1ed1*/ 712,
- /*0x0151*/ 94,
- /*0x2cd1*/ 945,
- -1, -1, -1, -1,
- /*0x24d1*/ 824,
- /*0x0265*/ 212,
- /*0xa663*/ 1015,
- /*0x10fa*/ 520,
- /*0x1f63*/ 779,
- /*0x1f12*/ 746,
- -1, -1, -1, -1,
- /*0x10ceb*/ 1289,
- /*0x0269*/ 215,
- /*0xa665*/ 1016,
- -1,
- /*0x1f65*/ 781,
- /*0x10eb*/ 505,
- -1,
- /*0xa757*/ 1060,
- -1, -1, -1, -1,
- /*0xa669*/ 1018,
- /*0x0491*/ 360,
- -1, -1, -1,
- /*0x1e11*/ 621,
- /*0x1e91*/ 685,
- /*0x0111*/ 64,
- /*0x2c91*/ 913,
- /*0xa79b*/ 1086,
- /*0xa667*/ 1017,
- -1,
- /*0x1f67*/ 783,
- -1,
- /*0x0259*/ 206,
- -1, -1, -1, -1, -1,
- /*0x2c57*/ 888,
- /*0xa76f*/ 1072,
- /*0x10cd7*/ 1269,
- /*0x1f24*/ 754,
- /*0x1f22*/ 752,
- /*0xa659*/ 1010,
- -1,
- /*0x10d7*/ 485,
- -1,
- /*0x025b*/ 207,
- -1,
- /*0x13ed*/ 601,
- /*0x046d*/ 346,
- /*0x04ed*/ 406,
- /*0x006d*/ 11,
- /*0x1f14*/ 748,
- /*0x104ed*/ 1196,
- /*0x1e6d*/ 667,
- /*0x1eed*/ 726,
- /*0x016d*/ 108,
- /*0xa65b*/ 1011,
- -1, -1, -1,
- /*0x1f10*/ 744,
- /*0x13a8*/ 532,
- -1, -1,
- /*0x10cef*/ 1293,
- /*0x10428*/ 1135,
- /*0x03ed*/ 286,
- /*0xa751*/ 1057,
- -1,
- /*0x10ef*/ 509,
- -1,
- /*0xa65f*/ 1013,
- /*0x13d3*/ 575,
- /*0x0453*/ 327,
- /*0x04d3*/ 393,
- -1, -1,
- /*0x1f06*/ 742,
- /*0x1e53*/ 654,
- /*0x1ed3*/ 713,
- /*0x0153*/ 95,
- /*0x2cd3*/ 946,
- /*0x13d5*/ 577,
- /*0x0455*/ 329,
- /*0x04d5*/ 394,
- /*0xa7d9*/ 1106,
- /*0x24d3*/ 826,
- -1,
- /*0x1e55*/ 655,
- /*0x1ed5*/ 714,
- /*0x0155*/ 96,
- /*0x2cd5*/ 947,
- /*0x2c51*/ 882,
- /*0xa794*/ 1083,
- /*0x10cd1*/ 1263,
- -1,
- /*0x24d5*/ 828,
- -1, -1,
- /*0x10d1*/ 479,
- /*0xa65d*/ 1012,
- /*0x01e1*/ 151,
- -1,
- /*0x13f3*/ 607,
- /*0x0473*/ 349,
- /*0x04f3*/ 409,
- /*0x0073*/ 17,
- -1,
- /*0x104f3*/ 1202,
- /*0x1e73*/ 670,
- /*0x1ef3*/ 729,
- /*0x0173*/ 111,
- /*0x2cf3*/ 957,
- /*0x13ce*/ 570,
- /*0x044e*/ 322,
- /*0x04ce*/ 390,
- -1,
- /*0x1044e*/ 1173,
- -1, -1,
- /*0x026b*/ 217,
- /*0x1f7a*/ 794,
- /*0x03f3*/ 289,
- /*0x017e*/ 116,
- -1,
- /*0x01e3*/ 152,
- /*0x0192*/ 122,
- -1,
- /*0x1f20*/ 750,
- /*0xa78c*/ 1080,
- -1,
- /*0xa66b*/ 1019,
- /*0x03ce*/ 274,
- -1,
- /*0xa76d*/ 1071,
- /*0x01e5*/ 153,
- /*0x0188*/ 120,
- /*0x13c3*/ 559,
- /*0x0443*/ 311,
- /*0x0373*/ 237,
- -1,
- /*0x10443*/ 1162,
- -1,
- /*0x1e43*/ 646,
- /*0x1ec3*/ 705,
- /*0x01e9*/ 155,
- /*0x2cc3*/ 938,
- -1, -1,
- /*0x0561*/ 440,
- /*0x1059b*/ 1215,
- /*0x00e1*/ 26,
- -1, -1,
- /*0x0257*/ 205,
- /*0x01e7*/ 154,
- /*0x03c3*/ 263,
- /*0x118d9*/ 1322,
- /*0x051b*/ 429,
- /*0xa753*/ 1058,
- /*0x13aa*/ 534,
- /*0x10ced*/ 1291,
- /*0xab53*/ 1108,
- /*0x050b*/ 421,
- /*0x1042a*/ 1137,
- /*0xa657*/ 1009,
- /*0x10ed*/ 507,
- /*0x1f57*/ 775,
- -1,
- /*0xa755*/ 1059,
- /*0x13c1*/ 557,
- /*0x0441*/ 309,
- /*0x118db*/ 1324,
- /*0x0563*/ 442,
- /*0x10441*/ 1160,
- /*0x00e3*/ 28,
- /*0x1e41*/ 645,
- /*0x1ec1*/ 704,
- -1,
- /*0x2cc1*/ 937,
- /*0x026f*/ 219,
- -1, -1,
- /*0x0565*/ 444,
- /*0x2c53*/ 884,
- /*0x00e5*/ 30,
- /*0x10cd3*/ 1265,
- /*0x118df*/ 1328,
- -1,
- /*0x03c1*/ 262,
- -1,
- /*0x10d3*/ 481,
- -1,
- /*0x0569*/ 448,
- /*0x2c55*/ 886,
- /*0x00e9*/ 34,
- /*0x10cd5*/ 1267,
- /*0x13de*/ 586,
- /*0x045e*/ 338,
- /*0x1f02*/ 738,
- /*0x01df*/ 150,
- /*0x10d5*/ 483,
- /*0x104de*/ 1181,
- /*0x0567*/ 446,
- -1,
- /*0x00e7*/ 32,
- /*0x105a4*/ 1223,
- /*0x028b*/ 231,
- -1,
- /*0xa7d7*/ 1105,
- /*0x0251*/ 200,
- /*0x24de*/ 837,
- -1,
- /*0x019a*/ 125,
- /*0x018c*/ 121,
- /*0x2c73*/ 903,
- /*0x118dd*/ 1326,
- /*0x1f00*/ 736,
- /*0x0292*/ 233,
- /*0x1f26*/ 756,
- /*0x028a*/ 230,
- /*0xa651*/ 1006,
- /*0x10f3*/ 513,
- /*0x1f51*/ 772,
- /*0xa743*/ 1050,
- /*0x2c4e*/ 879,
- -1,
- /*0x10cce*/ 1260,
- /*0x0288*/ 228,
- /*0x01dd*/ 149,
- /*0x10598*/ 1212,
- /*0x13cf*/ 571,
- /*0x044f*/ 323,
- /*0x04cf*/ 391,
- /*0x10fe*/ 522,
- /*0x1044f*/ 1174,
- -1,
- /*0x1e4f*/ 652,
- /*0x1ecf*/ 711,
- /*0x014f*/ 93,
- /*0x2ccf*/ 944,
- /*0x0586*/ 477,
- -1,
- /*0x1e924*/ 1363,
- /*0x1e922*/ 1361,
- /*0x0211*/ 173,
- -1, -1, -1,
- /*0x2c43*/ 868,
- -1,
- /*0x10cc3*/ 1249,
- -1,
- /*0x1059a*/ 1214,
- -1,
- /*0x13cd*/ 569,
- /*0x044d*/ 321,
- /*0xa741*/ 1049,
- /*0x1f11*/ 745,
- /*0x1044d*/ 1172,
- /*0x01eb*/ 156,
- /*0x1e4d*/ 651,
- /*0x1ecd*/ 710,
- /*0x014d*/ 92,
- /*0x2ccd*/ 943,
- /*0xa7d1*/ 1104,
- /*0x056e*/ 453,
- /*0x019e*/ 126,
- /*0x00ee*/ 39,
- -1, -1,
- /*0x13cb*/ 567,
- /*0x044b*/ 319,
- -1,
- /*0x03cd*/ 273,
- /*0x1044b*/ 1170,
- -1,
- /*0x1e4b*/ 650,
- /*0x1ecb*/ 709,
- /*0x014b*/ 91,
- /*0x2ccb*/ 942,
- /*0x118d7*/ 1320,
- /*0x2c41*/ 866,
- -1,
- /*0x10cc1*/ 1247,
- /*0x13c9*/ 565,
- /*0x0449*/ 317,
- -1,
- /*0xa66d*/ 1020,
- /*0x10449*/ 1168,
- /*0x03cb*/ 271,
- /*0x1e49*/ 649,
- /*0x1ec9*/ 708,
- -1,
- /*0x2cc9*/ 941,
- /*0x105a0*/ 1220,
- /*0x057a*/ 465,
- -1,
- /*0x00fa*/ 50,
- -1,
- /*0xa791*/ 1081,
- -1,
- /*0x0253*/ 202,
- -1,
- /*0x03c9*/ 269,
- -1,
- /*0x028c*/ 232,
- /*0x1059e*/ 1218,
- /*0x056b*/ 450,
- /*0x2c5e*/ 895,
- /*0x00eb*/ 36,
- /*0x10cde*/ 1276,
- -1,
- /*0xa653*/ 1007,
- -1,
- /*0x1f53*/ 773,
- /*0x10de*/ 492,
- /*0x16e61*/ 1330,
- /*0xa74f*/ 1056,
- -1,
- /*0x01ef*/ 158,
- -1, -1,
- /*0xa655*/ 1008,
- -1,
- /*0x1f55*/ 774,
- /*0x13f1*/ 605,
- /*0x0471*/ 348,
- /*0x04f1*/ 408,
- /*0x0071*/ 15,
- -1,
- /*0x104f1*/ 1200,
- /*0x1e71*/ 669,
- /*0x1ef1*/ 728,
- /*0x0171*/ 110,
- -1, -1,
- /*0x118d1*/ 1314,
- -1, -1, -1,
- /*0x16e63*/ 1332,
- /*0xa74d*/ 1055,
- /*0x2c4f*/ 880,
- /*0x0180*/ 117,
- /*0x10ccf*/ 1261,
- /*0x1f73*/ 787,
- /*0x13f5*/ 609,
- /*0x0475*/ 350,
- /*0x04f5*/ 410,
- /*0x0075*/ 19,
- /*0x16e65*/ 1334,
- /*0x104f5*/ 1204,
- /*0x1e75*/ 671,
- /*0x1ef5*/ 730,
- /*0x0175*/ 112,
- -1, -1,
- /*0xa74b*/ 1054,
- /*0x029e*/ 235,
- -1,
- /*0x16e69*/ 1338,
- /*0x0371*/ 236,
- /*0x0582*/ 473,
- -1, -1, -1,
- /*0x2c4d*/ 878,
- /*0x056f*/ 454,
- /*0x10ccd*/ 1259,
- /*0x00ef*/ 40,
- /*0x16e67*/ 1336,
- /*0xa749*/ 1053,
- /*0x13ae*/ 538,
- -1, -1, -1,
- /*0x1042e*/ 1141,
- /*0xa643*/ 999,
- -1,
- /*0x1f43*/ 769,
- /*0x0580*/ 471,
- -1,
- /*0x2c4b*/ 876,
- -1,
- /*0x10ccb*/ 1257,
- /*0x105a6*/ 1225,
- /*0x13b7*/ 547,
- /*0x0437*/ 299,
- /*0x04b7*/ 379,
- -1,
- /*0x10437*/ 1150,
- /*0x03ae*/ 244,
- /*0x1e37*/ 640,
- /*0x1eb7*/ 699,
- /*0x0137*/ 82,
- /*0x2cb7*/ 932,
- /*0x2c49*/ 874,
- -1,
- /*0x10cc9*/ 1255,
- -1,
- /*0x13b5*/ 545,
- /*0x0435*/ 297,
- /*0x04b5*/ 378,
- -1,
- /*0x10435*/ 1148,
- /*0x03b7*/ 252,
- /*0x1e35*/ 639,
- /*0x1eb5*/ 698,
- /*0x0135*/ 81,
- /*0x2cb5*/ 931,
- /*0xa641*/ 998,
- -1,
- /*0x1f41*/ 767,
- -1, -1, -1,
- /*0x01ed*/ 157,
- /*0x0282*/ 225,
- /*0x1fe1*/ 803,
- /*0x03b5*/ 250,
- /*0x0481*/ 356,
- /*0xa7c3*/ 1101,
- /*0x1e926*/ 1365,
- -1,
- /*0x1e01*/ 613,
- /*0x1e81*/ 677,
- /*0x0101*/ 56,
- /*0x2c81*/ 905,
- /*0x118d3*/ 1316,
- -1,
- /*0x01a8*/ 130,
- -1,
- /*0x0511*/ 424,
- /*0x16e6e*/ 1343,
- /*0x13a5*/ 529,
- /*0x0280*/ 224,
- /*0x04a5*/ 370,
- /*0x217a*/ 816,
- /*0x118d5*/ 1318,
- /*0x10cf1*/ 1295,
- /*0x1e25*/ 631,
- /*0x1ea5*/ 690,
- /*0x0125*/ 74,
- /*0x2ca5*/ 923,
- /*0x10f1*/ 511,
- /*0x1e05*/ 615,
- /*0x1e85*/ 679,
- /*0x0105*/ 58,
- /*0x2c85*/ 907,
- /*0x13b3*/ 543,
- /*0x0433*/ 295,
- /*0x04b3*/ 377,
- /*0x1fe5*/ 804,
- /*0x10433*/ 1146,
- /*0xa7c1*/ 1100,
- /*0x1e33*/ 638,
- /*0x1eb3*/ 697,
- /*0x0133*/ 80,
- /*0x2cb3*/ 930,
- /*0x2d16*/ 980,
- /*0x024f*/ 198,
- -1,
- /*0x2d1b*/ 985,
- /*0x16e7a*/ 1355,
- /*0x056d*/ 452,
- /*0x10f5*/ 515,
- /*0x00ed*/ 38,
- /*0x2d0b*/ 969,
- /*0x03b3*/ 248,
- /*0x118ce*/ 1311,
- /*0x105a8*/ 1227,
- /*0xa64f*/ 1005,
- /*0x01f3*/ 159,
- /*0xa737*/ 1044,
- -1,
- /*0x16e6b*/ 1340,
- -1, -1,
- /*0x2d12*/ 976,
- -1,
- /*0x2d0a*/ 968,
- -1,
- /*0x01ce*/ 141,
- /*0x13a3*/ 527,
- /*0x024d*/ 197,
- /*0x04a3*/ 369,
- -1,
- /*0xa735*/ 1043,
- /*0x2d08*/ 966,
- /*0x1e23*/ 630,
- /*0x1ea3*/ 689,
- /*0x0123*/ 73,
- /*0x2ca3*/ 922,
- /*0x118c3*/ 1300,
- -1,
- /*0xa64d*/ 1004,
- -1,
- /*0x13ad*/ 537,
- /*0x2c37*/ 856,
- /*0x04ad*/ 374,
- /*0x024b*/ 196,
- /*0x1042d*/ 1140,
- -1,
- /*0x1e2d*/ 635,
- /*0x1ead*/ 694,
- /*0x012d*/ 78,
- /*0x2cad*/ 927,
- /*0x1e928*/ 1367,
- -1, -1, -1,
- /*0xa64b*/ 1003,
- /*0x2c35*/ 854,
- -1,
- /*0x0249*/ 195,
- -1,
- /*0x03ad*/ 243,
- -1,
- /*0x2d24*/ 994,
- /*0x2d22*/ 992,
- /*0x0573*/ 458,
- /*0xa725*/ 1036,
- /*0x00f3*/ 44,
- /*0x047b*/ 353,
- /*0x04fb*/ 413,
- /*0xa649*/ 1002,
- /*0x118c1*/ 1298,
- /*0x104fb*/ 1210,
- /*0x1e7b*/ 674,
- /*0x1efb*/ 733,
- /*0x2d14*/ 978,
- -1,
- /*0x057e*/ 469,
- /*0x1f04*/ 740,
- /*0x00fe*/ 54,
- /*0x16e6f*/ 1344,
- /*0xa733*/ 1042,
- -1, -1,
- /*0x2d10*/ 974,
- -1,
- /*0x03fb*/ 291,
- /*0x2d18*/ 982,
- /*0x13bf*/ 555,
- /*0x043f*/ 307,
- /*0x04bf*/ 383,
- -1,
- /*0x1043f*/ 1158,
- -1,
- /*0x1e3f*/ 644,
- /*0x1ebf*/ 703,
- -1,
- /*0x2cbf*/ 936,
- /*0x118de*/ 1327,
- -1,
- /*0x0271*/ 220,
- /*0x2d06*/ 964,
- -1,
- /*0x037b*/ 239,
- -1, -1,
- /*0x2c33*/ 852,
- /*0x03bf*/ 260,
- /*0x13b2*/ 542,
- /*0x0432*/ 294,
- /*0x2d1a*/ 984,
- /*0x2d0c*/ 970,
- /*0x10432*/ 1145,
- /*0x1f71*/ 785,
- /*0x105aa*/ 1229,
- /*0xa723*/ 1035,
- /*0x13b9*/ 549,
- /*0x0439*/ 301,
- /*0x04b9*/ 380,
- -1,
- /*0x10439*/ 1152,
- /*0x0275*/ 222,
- /*0x1e39*/ 641,
- /*0x1eb9*/ 700,
- -1,
- /*0x2cb9*/ 933,
- -1,
- /*0x03b2*/ 247,
- /*0x1e943*/ 1394,
- /*0xa72d*/ 1040,
- -1, -1,
- /*0x118cf*/ 1312,
- -1,
- /*0x1f75*/ 789,
- /*0x03b9*/ 254,
- -1, -1,
- /*0x13ac*/ 536,
- /*0x13b1*/ 541,
- /*0x0431*/ 293,
- /*0x04b1*/ 376,
- /*0x1042c*/ 1139,
- /*0x10431*/ 1144,
- -1,
- /*0x1e31*/ 637,
- /*0x1eb1*/ 696,
- -1,
- /*0x2cb1*/ 929,
- -1, -1,
- /*0x1e92a*/ 1369,
- /*0x2d20*/ 990,
- -1, -1, -1,
- /*0x118cd*/ 1310,
- /*0x03ac*/ 242,
- /*0x03b1*/ 246,
- -1,
- /*0x13a7*/ 531,
- /*0x1e941*/ 1392,
- /*0x04a7*/ 371,
- -1,
- /*0x2d1e*/ 988,
- -1,
- /*0x1e27*/ 632,
- /*0x1ea7*/ 691,
- /*0x0127*/ 75,
- /*0x2ca7*/ 924,
- -1, -1,
- /*0x118cb*/ 1308,
- -1,
- /*0x1f37*/ 765,
- /*0xa73f*/ 1048,
- -1,
- /*0x16e6d*/ 1342,
- -1, -1, -1, -1, -1,
- /*0x13c7*/ 563,
- /*0x0447*/ 315,
- -1,
- /*0x118c9*/ 1306,
- /*0x10447*/ 1166,
- /*0x1f35*/ 763,
- /*0x1e47*/ 648,
- /*0x1ec7*/ 707,
- -1,
- /*0x2cc7*/ 940,
- /*0x0201*/ 165,
- -1, -1, -1, -1, -1,
- /*0x01c9*/ 139,
- /*0x2c3f*/ 864,
- -1,
- /*0x03c7*/ 267,
- /*0xa739*/ 1045,
- -1, -1,
- /*0x1f01*/ 737,
- /*0x2173*/ 809,
- -1,
- /*0x0225*/ 182,
- -1, -1,
- /*0x1fd1*/ 801,
- -1,
- /*0x0205*/ 167,
- -1,
- /*0xa7b7*/ 1095,
- /*0x214e*/ 805,
- -1,
- /*0x217e*/ 820,
- /*0x2c32*/ 851,
- -1,
- /*0x1f25*/ 755,
- /*0x2d02*/ 960,
- /*0x0233*/ 189,
- /*0x13c5*/ 561,
- /*0x0445*/ 313,
- /*0x1f05*/ 741,
- /*0x2c39*/ 858,
- /*0x10445*/ 1164,
- /*0xa7b5*/ 1094,
- /*0x1e45*/ 647,
- /*0x1ec5*/ 706,
- /*0x16e73*/ 1348,
- /*0x2cc5*/ 939,
- -1, -1,
- /*0x1f33*/ 761,
- /*0x2d0e*/ 972,
- -1, -1,
- /*0x2d00*/ 958,
- /*0x0584*/ 475,
- -1,
- /*0x03c5*/ 265,
- /*0x16e7e*/ 1359,
- -1,
- /*0xa727*/ 1037,
- /*0xa781*/ 1076,
- /*0x13c0*/ 556,
- /*0x0440*/ 308,
- /*0x2c31*/ 850,
- -1,
- /*0x10440*/ 1159,
- /*0x047d*/ 354,
- /*0x04fd*/ 414,
- -1,
- /*0x0140*/ 86,
- /*0x0223*/ 181,
- /*0x1e7d*/ 675,
- /*0x1efd*/ 734,
- /*0x01f5*/ 160,
- /*0x1d7d*/ 611,
- -1,
- /*0xa7a5*/ 1091,
- -1, -1, -1,
- /*0x03c0*/ 261,
- /*0xa785*/ 1078,
- /*0xa747*/ 1052,
- /*0x1f23*/ 753,
- /*0x022d*/ 186,
- /*0x1e03*/ 614,
- /*0x1e83*/ 678,
- /*0x0103*/ 57,
- /*0x2c83*/ 906,
- -1, -1,
- /*0x048f*/ 359,
- -1, -1,
- /*0x2d11*/ 975,
- /*0x1e0f*/ 620,
- /*0x1e8f*/ 684,
- /*0x010f*/ 63,
- /*0x2c8f*/ 912,
- /*0xa69b*/ 1034,
- /*0x0571*/ 456,
- /*0x037d*/ 241,
- /*0x00f1*/ 42,
- -1,
- /*0xa68b*/ 1026,
- -1, -1,
- /*0x2c47*/ 872,
- -1,
- /*0x10cc7*/ 1253,
- /*0x13bd*/ 553,
- /*0x043d*/ 305,
- /*0x04bd*/ 382,
- -1,
- /*0x1043d*/ 1156,
- -1,
- /*0x1e3d*/ 643,
- /*0x1ebd*/ 702,
- -1,
- /*0x2cbd*/ 935,
- -1,
- /*0x0575*/ 460,
- /*0x1f7b*/ 795,
- /*0x00f5*/ 46,
- /*0xa745*/ 1051,
- /*0xa7a3*/ 1090,
- /*0x13a1*/ 525,
- -1,
- /*0x04a1*/ 368,
- /*0x03bd*/ 258,
- /*0x023f*/ 191,
- /*0xff59*/ 1133,
- /*0x1e21*/ 629,
- /*0x1ea1*/ 688,
- /*0x0121*/ 72,
- /*0x2ca1*/ 921,
- /*0x13bb*/ 551,
- /*0x043b*/ 303,
- /*0x04bb*/ 381,
- /*0x105ae*/ 1233,
- /*0x1043b*/ 1154,
- -1,
- /*0x1e3b*/ 642,
- /*0x1ebb*/ 701,
- -1,
- /*0x2cbb*/ 934,
- -1, -1, -1,
- /*0x2c45*/ 870,
- /*0x13af*/ 539,
- /*0x10cc5*/ 1251,
- /*0x04af*/ 375,
- /*0x105b7*/ 1241,
- /*0x1042f*/ 1142,
- /*0x03bb*/ 256,
- /*0x1e2f*/ 636,
- /*0x1eaf*/ 695,
- /*0x012f*/ 79,
- /*0x2caf*/ 928,
- -1,
- /*0x01a5*/ 129,
- -1,
- /*0x1f32*/ 760,
- /*0x0499*/ 364,
- -1,
- /*0x0185*/ 119,
- /*0x105b5*/ 1239,
- /*0x1e19*/ 625,
- /*0x03af*/ 245,
- /*0x0119*/ 68,
- /*0x2c99*/ 917,
- -1,
- /*0x2c40*/ 865,
- /*0x13e6*/ 594,
- /*0x10cc0*/ 1246,
- /*0x1e92e*/ 1373,
- /*0x0066*/ 5,
- -1,
- /*0x104e6*/ 1189,
- -1,
- /*0x0231*/ 188,
- /*0x0581*/ 472,
- -1,
- /*0x10fd*/ 521,
- /*0xa7bf*/ 1099,
- /*0x13f2*/ 606,
- -1,
- /*0x24e6*/ 845,
- /*0x0072*/ 16,
- /*0x1e937*/ 1382,
- /*0x104f2*/ 1201,
- -1,
- /*0x0501*/ 416,
- /*0x1f31*/ 759,
- -1, -1,
- /*0xa73d*/ 1047,
- -1, -1, -1,
- /*0x105a5*/ 1224,
- /*0x0227*/ 183,
- /*0x0585*/ 476,
- /*0x1e935*/ 1380,
- /*0x03f2*/ 288,
- -1, -1, -1,
- /*0x0525*/ 434,
- /*0x01a3*/ 128,
- -1, -1,
- /*0xa7b9*/ 1096,
- /*0x0505*/ 418,
- /*0x1f27*/ 757,
- /*0x105b3*/ 1237,
- -1, -1, -1,
- /*0x1059c*/ 1216,
- -1,
- /*0x2c3d*/ 862,
- /*0xa73b*/ 1046,
- /*0x01ad*/ 131,
- /*0x0247*/ 194,
- /*0x13a9*/ 533,
- -1,
- /*0x04a9*/ 372,
- -1,
- /*0x10429*/ 1136,
- -1,
- /*0x1e29*/ 633,
- /*0x1ea9*/ 692,
- /*0x0129*/ 76,
- /*0x2ca9*/ 925,
- /*0xa647*/ 1001,
- /*0xa72f*/ 1041,
- /*0x1e925*/ 1364,
- /*0x0479*/ 352,
- /*0x04f9*/ 412,
- /*0x0079*/ 23,
- /*0x2171*/ 807,
- /*0x104f9*/ 1208,
- /*0x1e79*/ 673,
- /*0x1ef9*/ 732,
- -1,
- /*0x1d79*/ 610,
- /*0x2c3b*/ 860,
- /*0x01fb*/ 162,
- /*0x105a3*/ 1222,
- -1, -1,
- /*0x1e933*/ 1378,
- -1,
- /*0xff57*/ 1131,
- -1,
- /*0xa7a7*/ 1092,
- /*0x0523*/ 433,
- -1, -1, -1, -1,
- /*0x2175*/ 811,
- /*0x105ad*/ 1232,
- /*0x13d0*/ 572,
- /*0x0450*/ 324,
- -1,
- /*0x16e71*/ 1346,
- -1,
- /*0x01bf*/ 137,
- -1,
- /*0x052d*/ 438,
- /*0x13c2*/ 558,
- /*0x0442*/ 310,
- /*0x04c2*/ 384,
- -1,
- /*0x10442*/ 1161,
- /*0xa645*/ 1000,
- /*0x24d0*/ 823,
- /*0x1f45*/ 771,
- /*0x0142*/ 87,
- /*0x1e09*/ 617,
- /*0x1e89*/ 681,
- /*0x0109*/ 60,
- /*0x2c89*/ 909,
- /*0x2c66*/ 899,
- /*0x1e923*/ 1362,
- /*0x10ce6*/ 1284,
- /*0x16e75*/ 1350,
- -1,
- /*0x0240*/ 192,
- -1,
- /*0x10e6*/ 500,
- -1,
- /*0x027d*/ 223,
- -1,
- /*0x057b*/ 466,
- /*0x01b9*/ 135,
- /*0x00fb*/ 51,
- /*0x10cf2*/ 1296,
- /*0x1e92d*/ 1372,
- -1, -1,
- /*0x1f40*/ 766,
- /*0x10f2*/ 512,
- -1, -1,
- /*0x1f7d*/ 797,
- /*0x0203*/ 166,
- -1,
- /*0xff51*/ 1125,
- -1,
- /*0xa729*/ 1038,
- -1,
- /*0x047f*/ 355,
- /*0x04ff*/ 415,
- -1, -1,
- /*0x020f*/ 172,
- /*0x1e7f*/ 676,
- /*0x1eff*/ 735,
- /*0x1f03*/ 739,
- /*0x0477*/ 351,
- /*0x04f7*/ 411,
- /*0x0077*/ 21,
- -1,
- /*0x104f7*/ 1206,
- /*0x1e77*/ 672,
- /*0x1ef7*/ 731,
- /*0x0177*/ 113,
- /*0x13ec*/ 600,
- -1, -1,
- /*0x006c*/ 10,
- -1,
- /*0x104ec*/ 1195,
- /*0x13ab*/ 535,
- /*0x105b9*/ 1243,
- /*0x04ab*/ 373,
- /*0x2cec*/ 955,
- /*0x1042b*/ 1138,
- -1,
- /*0x1e2b*/ 634,
- /*0x1eab*/ 693,
- /*0x012b*/ 77,
- /*0x2cab*/ 926,
- /*0x1e93f*/ 1390,
- /*0x13e8*/ 596,
- -1, -1,
- /*0x0068*/ 7,
- /*0x118c7*/ 1304,
- /*0x104e8*/ 1191,
- -1, -1,
- /*0x2184*/ 822,
- /*0x10f9*/ 519,
- /*0x0377*/ 238,
- -1,
- /*0x105ac*/ 1231,
- /*0x105b1*/ 1236,
- /*0x24e8*/ 847,
- /*0x13ea*/ 598,
- /*0xa783*/ 1077,
- -1,
- /*0x006a*/ 8,
- /*0x1e932*/ 1377,
- /*0x104ea*/ 1193,
- /*0x1f21*/ 751,
- /*0x2d04*/ 962,
- -1, -1, -1,
- /*0xa691*/ 1029,
- /*0x1e939*/ 1384,
- -1,
- /*0x2c50*/ 881,
- -1,
- /*0x10cd0*/ 1262,
- /*0x022f*/ 187,
- -1,
- /*0x105a7*/ 1226,
- -1,
- /*0x10d0*/ 478,
- /*0x2c42*/ 867,
- /*0x13f0*/ 604,
- /*0x10cc2*/ 1248,
- -1,
- /*0x0070*/ 14,
- /*0x0527*/ 435,
- /*0x104f0*/ 1199,
- /*0x0219*/ 177,
- -1,
- /*0x118c5*/ 1302,
- /*0xa7bd*/ 1098,
- -1,
- /*0x1e92c*/ 1371,
- /*0x1e931*/ 1376,
- -1, -1,
- /*0xa77f*/ 1075,
- -1,
- /*0xff53*/ 1127,
- /*0x0266*/ 213,
- -1,
- /*0x13c8*/ 564,
- /*0x0448*/ 316,
- /*0x04c8*/ 387,
- -1,
- /*0x10448*/ 1167,
- /*0xa7a1*/ 1089,
- -1,
- /*0xff55*/ 1129,
- /*0x0148*/ 90,
- -1,
- /*0x0272*/ 221,
- /*0x1f66*/ 782,
- /*0x118c0*/ 1297,
- /*0x1e927*/ 1366,
- -1,
- /*0xa7bb*/ 1097,
- -1, -1,
- /*0xa72b*/ 1039,
- /*0x03c8*/ 268,
- /*0x0076*/ 20,
- -1,
- /*0x104f6*/ 1205,
- /*0x1f72*/ 786,
- -1, -1, -1,
- /*0x10ff*/ 523,
- -1,
- /*0x01fd*/ 163,
- -1,
- /*0x13e4*/ 592,
- -1,
- /*0x217b*/ 817,
- /*0x0064*/ 3,
- /*0x10f7*/ 517,
- /*0x104e4*/ 1187,
- /*0x2c6c*/ 902,
- /*0xff4e*/ 1122,
- /*0x10cec*/ 1290,
- -1,
- /*0xa799*/ 1085,
- /*0x0495*/ 362,
- /*0x0183*/ 118,
- /*0x10ec*/ 506,
- /*0x24e4*/ 843,
- /*0x1e15*/ 623,
- /*0x1e95*/ 687,
- /*0x0115*/ 66,
- /*0x2c95*/ 915,
- /*0x0229*/ 184,
- -1, -1, -1,
- /*0x2c68*/ 900,
- -1,
- /*0x10ce8*/ 1286,
- -1, -1,
- /*0x16e7b*/ 1356,
- -1,
- /*0x10e8*/ 502,
- /*0xff43*/ 1111,
- -1,
- /*0x13c6*/ 562,
- /*0x0446*/ 314,
- /*0x04c6*/ 386,
- -1,
- /*0x10446*/ 1165,
- /*0x2c6a*/ 901,
- -1,
- /*0x10cea*/ 1288,
- /*0x0146*/ 89,
- -1,
- /*0x01bd*/ 136,
- /*0x1f79*/ 793,
- /*0x10ea*/ 504,
- /*0x057d*/ 468,
- -1,
- /*0x00fd*/ 53,
- /*0x0583*/ 474,
- /*0x0493*/ 361,
- -1,
- /*0x03c6*/ 266,
- -1,
- /*0x1e13*/ 622,
- /*0x1e93*/ 686,
- /*0x0113*/ 65,
- /*0x2c93*/ 914,
- /*0x0250*/ 199,
- /*0x01a1*/ 127,
- /*0x0503*/ 417,
- /*0x2d01*/ 959,
- /*0x13e0*/ 588,
- /*0x10cf0*/ 1294,
- /*0xff41*/ 1109,
- -1,
- /*0x0242*/ 193,
- /*0x104e0*/ 1183,
- /*0x10f0*/ 510,
- /*0x0209*/ 169,
- /*0x050f*/ 423,
- /*0x1e940*/ 1391,
- -1, -1,
- /*0xa7a9*/ 1093,
- -1,
- /*0x24e0*/ 839,
- /*0x2d25*/ 995,
- -1,
- /*0x1f42*/ 768,
- -1,
- /*0x2c48*/ 873,
- /*0x2d05*/ 963,
- /*0x10cc8*/ 1254,
- /*0x1e07*/ 616,
- /*0x1e87*/ 680,
- /*0x0107*/ 59,
- /*0x2c87*/ 908,
- -1,
- /*0x13c4*/ 560,
- /*0x0444*/ 312,
- /*0x04c4*/ 385,
- -1,
- /*0x10444*/ 1163,
- -1,
- /*0x0199*/ 124,
- /*0x2d1c*/ 986,
- /*0x0144*/ 88,
- /*0x2c76*/ 904,
- /*0x105a1*/ 1221,
- -1, -1, -1, -1,
- /*0x0283*/ 226,
- /*0x10f6*/ 516,
- /*0x0497*/ 363,
- /*0x0521*/ 432,
- /*0x03c4*/ 264,
- /*0x105bb*/ 1244,
- /*0x1e17*/ 624,
- /*0x049d*/ 366,
- /*0x0117*/ 67,
- /*0x2c97*/ 916,
- /*0x10ce4*/ 1282,
- /*0x1e1d*/ 627,
- -1,
- /*0x011d*/ 70,
- /*0x2c9d*/ 919,
- /*0x10e4*/ 498,
- /*0x1e93d*/ 1388,
- -1, -1,
- /*0x105af*/ 1234,
- /*0x026c*/ 218,
- /*0xff4f*/ 1123,
- /*0x2d23*/ 993,
- -1,
- /*0x1f77*/ 791,
- -1,
- /*0x022b*/ 185,
- /*0x052f*/ 439,
- -1, -1,
- /*0x13e2*/ 590,
- /*0x10599*/ 1213,
- -1,
- /*0x0062*/ 1,
- -1,
- /*0x104e2*/ 1185,
- /*0x2d2d*/ 997,
- /*0x0268*/ 214,
- -1,
- /*0x0519*/ 428,
- -1,
- /*0x2c46*/ 871,
- /*0x1e93b*/ 1386,
- /*0x10cc6*/ 1252,
- /*0x24e2*/ 841,
- /*0xff4d*/ 1121,
- /*0x13d6*/ 578,
- /*0x0456*/ 330,
- /*0x0078*/ 22,
- -1,
- /*0x104f8*/ 1207,
- /*0x0566*/ 445,
- /*0x026a*/ 216,
- /*0x00e6*/ 31,
- /*0x13dc*/ 584,
- /*0x045c*/ 336,
- /*0x1e92f*/ 1374,
- /*0x13da*/ 582,
- /*0x045a*/ 334,
- /*0x104dc*/ 1179,
- /*0x24d6*/ 829,
- /*0xff4b*/ 1119,
- /*0x104da*/ 1177,
- /*0x0572*/ 457,
- /*0x03f8*/ 290,
- /*0x00f2*/ 43,
- -1,
- /*0x01f9*/ 161,
- /*0x24dc*/ 835,
- -1, -1,
- /*0x24da*/ 833,
- /*0x10ce0*/ 1278,
- -1, -1,
- /*0xff49*/ 1117,
- -1,
- /*0x10e0*/ 494,
- -1, -1, -1,
- /*0x118d0*/ 1313,
- /*0x13bc*/ 552,
- /*0x043c*/ 304,
- /*0x217d*/ 819,
- -1,
- /*0x1043c*/ 1155,
- -1,
- /*0x1f70*/ 784,
- /*0x118c2*/ 1299,
- /*0x013c*/ 84,
- /*0x017c*/ 115,
- -1, -1,
- /*0x01d0*/ 142,
- /*0x105a9*/ 1228,
- -1,
- /*0x2c44*/ 869,
- /*0x1fb1*/ 799,
- /*0x10cc4*/ 1250,
- -1,
- /*0x03bc*/ 257,
- -1,
- /*0x0529*/ 436,
- /*0x13d8*/ 580,
- /*0x0458*/ 332,
- -1, -1, -1,
- /*0x104d8*/ 1175,
- /*0x16e7d*/ 1358,
- -1,
- /*0x13ca*/ 566,
- /*0x044a*/ 318,
- /*0x04ca*/ 388,
- /*0x0579*/ 464,
- /*0x1044a*/ 1169,
- /*0x00f9*/ 49,
- /*0x24d8*/ 831,
- /*0x037c*/ 240,
- /*0x13d4*/ 576,
- /*0x0454*/ 328,
- -1, -1, -1,
- /*0x1f76*/ 790,
- /*0x13b6*/ 546,
- /*0x0436*/ 298,
- -1, -1,
- /*0x10436*/ 1149,
- /*0x03ca*/ 270,
- /*0x1e929*/ 1368,
- -1,
- /*0x24d4*/ 827,
- /*0x0215*/ 175,
- /*0x13b0*/ 540,
- /*0x0430*/ 292,
- -1,
- /*0x1f64*/ 780,
- /*0x10430*/ 1143,
- /*0x13d2*/ 574,
- /*0x0452*/ 326,
- /*0x01ff*/ 164,
- /*0x10ce2*/ 1280,
- /*0x03b6*/ 251,
- -1, -1,
- /*0x1f15*/ 749,
- /*0x10e2*/ 496,
- /*0xa7c8*/ 1102,
- -1, -1,
- /*0x0509*/ 420,
- /*0x2d27*/ 996,
- /*0x24d2*/ 825,
- -1, -1,
- /*0x2c56*/ 887,
- -1,
- /*0x10cd6*/ 1268,
- -1, -1, -1,
- /*0x10f8*/ 518,
- /*0x10d6*/ 484,
- /*0x2c5c*/ 893,
- /*0xa7f6*/ 1107,
- /*0x10cdc*/ 1274,
- /*0x2c5a*/ 891,
- /*0xa77c*/ 1074,
- /*0x10cda*/ 1272,
- -1,
- /*0x10dc*/ 490,
- /*0x0213*/ 174,
- -1,
- /*0x10da*/ 488,
- /*0x13f4*/ 608,
- -1,
- /*0x1e942*/ 1393,
- /*0x0074*/ 18,
- -1,
- /*0x104f4*/ 1203,
- -1, -1, -1, -1,
- /*0x1f13*/ 747,
- /*0x0260*/ 209,
- -1, -1,
- /*0x057f*/ 470,
- -1,
- /*0x00ff*/ 55,
- /*0x2c3c*/ 861,
- -1, -1,
- /*0x0289*/ 229,
- -1,
- /*0x0577*/ 462,
- -1,
- /*0x1f60*/ 776,
- -1, -1,
- /*0x0207*/ 168,
- /*0x2172*/ 808,
- /*0x105ab*/ 1230,
- -1,
- /*0x056c*/ 451,
- -1,
- /*0x00ec*/ 37,
- -1, -1, -1,
- /*0x052b*/ 437,
- -1,
- /*0x2c58*/ 889,
- /*0x1f07*/ 743,
- /*0x10cd8*/ 1270,
- /*0x16e66*/ 1335,
- -1, -1,
- /*0x118c8*/ 1305,
- /*0x10d8*/ 486,
- /*0x2c4a*/ 875,
- /*0x0568*/ 447,
- /*0x10cca*/ 1256,
- /*0x00e8*/ 33,
- /*0x1f44*/ 770,
- /*0xa793*/ 1082,
- /*0x0217*/ 176,
- /*0x16e72*/ 1347,
- /*0x2c54*/ 885,
- -1,
- /*0x10cd4*/ 1266,
- /*0x021d*/ 179,
- -1,
- /*0xa681*/ 1021,
- /*0x2c36*/ 855,
- /*0x10d4*/ 482,
- /*0x056a*/ 449,
- -1,
- /*0x00ea*/ 35,
- /*0x1e92b*/ 1370,
- -1,
- /*0x13b4*/ 544,
- /*0x0434*/ 296,
- -1,
- /*0x2c30*/ 849,
- /*0x10434*/ 1147,
- -1, -1, -1,
- /*0x2c52*/ 883,
- -1,
- /*0x10cd2*/ 1264,
- -1,
- /*0x2179*/ 815,
- /*0xa685*/ 1023,
- /*0xa787*/ 1079,
- /*0x10d2*/ 480,
- /*0x2d03*/ 961,
- -1,
- /*0x0570*/ 455,
- /*0x03b4*/ 249,
- /*0x00f0*/ 41,
- -1, -1,
- /*0x13cc*/ 568,
- /*0x044c*/ 320,
- /*0x04cc*/ 389,
- /*0x2d0f*/ 973,
- /*0x1044c*/ 1171,
- /*0x1f62*/ 778,
- /*0x049f*/ 367,
- /*0x0195*/ 123,
- /*0x0256*/ 204,
- -1,
- /*0x1e1f*/ 628,
- -1,
- /*0x011f*/ 71,
- /*0x2c9f*/ 920,
- -1,
- /*0x16e79*/ 1354,
- /*0x025c*/ 208,
- /*0xa797*/ 1084,
- /*0x118c6*/ 1303,
- /*0x03cc*/ 272,
- /*0x1f78*/ 792,
- -1,
- /*0xa79d*/ 1087,
- -1, -1, -1, -1, -1,
- /*0x10f4*/ 514,
- -1, -1,
- /*0x01c6*/ 138,
- /*0x0576*/ 461,
- -1,
- /*0x00f6*/ 47,
- -1, -1,
- /*0x13be*/ 554,
- /*0x043e*/ 306,
- -1,
- /*0x2d21*/ 991,
- /*0x1043e*/ 1157,
- -1, -1,
- /*0x023c*/ 190,
- /*0x013e*/ 85,
- /*0x0564*/ 443,
- /*0x048d*/ 358,
- /*0x00e4*/ 29,
- -1, -1,
- /*0x1e0d*/ 619,
- /*0x1e8d*/ 683,
- /*0x010d*/ 62,
- /*0x2c8d*/ 911,
- /*0x0515*/ 426,
- /*0x03be*/ 259,
- -1,
- /*0x1f7c*/ 796,
- /*0x13ba*/ 550,
- /*0x043a*/ 302,
- -1, -1,
- /*0x1043a*/ 1153,
- -1,
- /*0x217f*/ 821,
- -1,
- /*0x013a*/ 83,
- -1, -1, -1,
- /*0x13b8*/ 548,
- /*0x0438*/ 300,
- /*0x2177*/ 813,
- /*0x118c4*/ 1301,
- /*0x10438*/ 1151,
- /*0x2d19*/ 983,
- -1,
- /*0x03ba*/ 255,
- -1, -1, -1,
- /*0x0254*/ 203,
- -1, -1, -1, -1, -1, -1,
- /*0x2c34*/ 853,
- /*0x03b8*/ 253,
- /*0x16e7f*/ 1360,
- -1, -1,
- /*0x0513*/ 425,
- -1, -1, -1, -1,
- /*0x16e77*/ 1352,
- -1,
- /*0x1f36*/ 764,
- -1,
- /*0x0252*/ 201,
- -1, -1, -1, -1,
- /*0x16e6c*/ 1341,
- -1,
- /*0x00e0*/ 25,
- /*0x1f30*/ 758,
- /*0x2c4c*/ 877,
- -1,
- /*0x10ccc*/ 1258,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x0507*/ 419,
- /*0x16e68*/ 1337,
- -1, -1, -1,
- /*0xa7ca*/ 1103,
- -1, -1, -1, -1, -1,
- /*0x118d6*/ 1319,
- -1,
- /*0x2170*/ 806,
- -1, -1,
- /*0x16e6a*/ 1339,
- -1,
- /*0x10597*/ 1211,
- /*0x118dc*/ 1325,
- /*0x1fd0*/ 800,
- -1,
- /*0x118da*/ 1323,
- /*0x1059d*/ 1217,
- /*0x01d6*/ 145,
- /*0x2c3e*/ 863,
- /*0x0517*/ 427,
- -1,
- /*0x1f74*/ 788,
- -1, -1,
- /*0x051d*/ 430,
- /*0x01dc*/ 148,
- -1, -1,
- /*0x01da*/ 147,
- -1,
- /*0xff47*/ 1115,
- -1,
- /*0x16e70*/ 1345,
- -1, -1, -1, -1,
- /*0x0287*/ 227,
- -1, -1,
- /*0x2c3a*/ 859,
- -1, -1,
- /*0x2176*/ 812,
- -1, -1, -1, -1, -1,
- /*0x0562*/ 441,
- -1,
- /*0x00e2*/ 27,
- /*0x2c38*/ 857,
- -1, -1, -1, -1, -1, -1,
- /*0x2d09*/ 967,
- -1, -1,
- /*0x118d8*/ 1321,
- -1,
- /*0x0578*/ 463,
- -1,
- /*0x00f8*/ 48,
- -1,
- /*0x029d*/ 234,
- /*0x16e76*/ 1351,
- /*0x118ca*/ 1307,
- -1,
- /*0xff45*/ 1113,
- -1, -1,
- /*0x01d8*/ 146,
- -1, -1,
- /*0x118d4*/ 1317,
- -1, -1, -1, -1,
- /*0x16e64*/ 1333,
- -1, -1, -1, -1, -1,
- /*0x1f34*/ 762,
- -1,
- /*0x01d4*/ 144,
- -1,
- /*0x105bc*/ 1245,
- -1, -1, -1,
- /*0x01b6*/ 134,
- -1,
- /*0x118d2*/ 1315,
- -1, -1,
- /*0x057c*/ 467,
- /*0x021f*/ 180,
- /*0x00fc*/ 52,
- -1, -1,
- /*0x01b0*/ 132,
- -1, -1, -1, -1,
- /*0x01d2*/ 143,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x1e93c*/ 1387,
- -1, -1, -1, -1, -1, -1,
- /*0x105b6*/ 1240,
- -1, -1, -1, -1,
- /*0xa683*/ 1022,
- -1,
- /*0x020d*/ 171,
- /*0x16e60*/ 1329,
- -1,
- /*0x105b0*/ 1235,
- -1, -1, -1, -1,
- /*0xa68f*/ 1028,
- -1, -1, -1, -1, -1,
- /*0xa79f*/ 1088,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x1e936*/ 1381,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x1e930*/ 1375,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x0574*/ 459,
- -1,
- /*0x00f4*/ 45,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x2178*/ 814,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x01b4*/ 133,
- /*0x16e62*/ 1331,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xa699*/ 1033,
- /*0x118cc*/ 1309,
- -1, -1,
- /*0x2d15*/ 979,
- -1, -1,
- /*0x16e78*/ 1353,
- -1, -1, -1, -1, -1, -1,
- /*0x01cc*/ 140,
- -1, -1, -1, -1,
- /*0x217c*/ 818,
- -1, -1,
- /*0x1fe0*/ 802,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0x105b4*/ 1238,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x2d13*/ 977,
- -1,
- /*0x16e7c*/ 1357,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x1059f*/ 1219,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x051f*/ 431,
- -1,
- /*0x1e934*/ 1379,
- -1, -1, -1, -1,
- /*0x2d07*/ 965,
- -1,
- /*0xff50*/ 1124,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xff42*/ 1110,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x2d17*/ 981,
- -1, -1, -1, -1,
- /*0x2d1d*/ 987,
- -1, -1,
- /*0x050d*/ 422,
- -1, -1, -1, -1, -1,
- /*0x2174*/ 810,
- /*0xa689*/ 1025,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x105b8*/ 1242,
- -1, -1,
- /*0x1e93e*/ 1389,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x16e74*/ 1349,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0x1e93a*/ 1385,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x1e938*/ 1383,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0x1fb0*/ 798,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xff48*/ 1116,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0xff46*/ 1114,
- -1, -1, -1,
- /*0xa695*/ 1031,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xa693*/ 1030,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xff44*/ 1112,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0xa687*/ 1024,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x2d1f*/ 989,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xa697*/ 1032,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0xff56*/ 1130,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1,
- /*0xff5a*/ 1134,
- -1, -1, -1,
- /*0x2d0d*/ 971,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xff58*/ 1132,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xff4a*/ 1118,
- -1, -1, -1, -1, -1, -1,
- -1,
- /*0xff54*/ 1128,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1,
- /*0xff52*/ 1126,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xff4c*/ 1120,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0xa68d*/ 1027
- };
-
- if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseUnfold_11_hash(code);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code1_equal(code, CaseUnfold_11_Table[s].from))
- return &CaseUnfold_11_Table[s].to;
- }
- }
- return 0;
-}
-
-static const CaseUnfold_12_Type CaseUnfold_12_Table[] = {
-#define CaseUnfold_12 (*(CaseUnfold_12_Type (*)[58])(CaseUnfold_12_Table+0))
- {{0x0061, 0x02be}, {1, {0x1e9a}}},
- {{0x0066, 0x0066}, {1, {0xfb00}}},
- {{0x0066, 0x0069}, {1, {0xfb01}}},
- {{0x0066, 0x006c}, {1, {0xfb02}}},
- {{0x0068, 0x0331}, {1, {0x1e96}}},
- {{0x006a, 0x030c}, {1, {0x01f0}}},
- {{0x0073, 0x0073}, {2, {0x00df, 0x1e9e}}},
- {{0x0073, 0x0074}, {2, {0xfb05, 0xfb06}}},
- {{0x0074, 0x0308}, {1, {0x1e97}}},
- {{0x0077, 0x030a}, {1, {0x1e98}}},
- {{0x0079, 0x030a}, {1, {0x1e99}}},
- {{0x02bc, 0x006e}, {1, {0x0149}}},
- {{0x03ac, 0x03b9}, {1, {0x1fb4}}},
- {{0x03ae, 0x03b9}, {1, {0x1fc4}}},
- {{0x03b1, 0x0342}, {1, {0x1fb6}}},
- {{0x03b1, 0x03b9}, {2, {0x1fb3, 0x1fbc}}},
- {{0x03b7, 0x0342}, {1, {0x1fc6}}},
- {{0x03b7, 0x03b9}, {2, {0x1fc3, 0x1fcc}}},
- {{0x03b9, 0x0342}, {1, {0x1fd6}}},
- {{0x03c1, 0x0313}, {1, {0x1fe4}}},
- {{0x03c5, 0x0313}, {1, {0x1f50}}},
- {{0x03c5, 0x0342}, {1, {0x1fe6}}},
- {{0x03c9, 0x0342}, {1, {0x1ff6}}},
- {{0x03c9, 0x03b9}, {2, {0x1ff3, 0x1ffc}}},
- {{0x03ce, 0x03b9}, {1, {0x1ff4}}},
- {{0x0565, 0x0582}, {1, {0x0587}}},
- {{0x0574, 0x0565}, {1, {0xfb14}}},
- {{0x0574, 0x056b}, {1, {0xfb15}}},
- {{0x0574, 0x056d}, {1, {0xfb17}}},
- {{0x0574, 0x0576}, {1, {0xfb13}}},
- {{0x057e, 0x0576}, {1, {0xfb16}}},
- {{0x1f00, 0x03b9}, {2, {0x1f80, 0x1f88}}},
- {{0x1f01, 0x03b9}, {2, {0x1f81, 0x1f89}}},
- {{0x1f02, 0x03b9}, {2, {0x1f82, 0x1f8a}}},
- {{0x1f03, 0x03b9}, {2, {0x1f83, 0x1f8b}}},
- {{0x1f04, 0x03b9}, {2, {0x1f84, 0x1f8c}}},
- {{0x1f05, 0x03b9}, {2, {0x1f85, 0x1f8d}}},
- {{0x1f06, 0x03b9}, {2, {0x1f86, 0x1f8e}}},
- {{0x1f07, 0x03b9}, {2, {0x1f87, 0x1f8f}}},
- {{0x1f20, 0x03b9}, {2, {0x1f90, 0x1f98}}},
- {{0x1f21, 0x03b9}, {2, {0x1f91, 0x1f99}}},
- {{0x1f22, 0x03b9}, {2, {0x1f92, 0x1f9a}}},
- {{0x1f23, 0x03b9}, {2, {0x1f93, 0x1f9b}}},
- {{0x1f24, 0x03b9}, {2, {0x1f94, 0x1f9c}}},
- {{0x1f25, 0x03b9}, {2, {0x1f95, 0x1f9d}}},
- {{0x1f26, 0x03b9}, {2, {0x1f96, 0x1f9e}}},
- {{0x1f27, 0x03b9}, {2, {0x1f97, 0x1f9f}}},
- {{0x1f60, 0x03b9}, {2, {0x1fa0, 0x1fa8}}},
- {{0x1f61, 0x03b9}, {2, {0x1fa1, 0x1fa9}}},
- {{0x1f62, 0x03b9}, {2, {0x1fa2, 0x1faa}}},
- {{0x1f63, 0x03b9}, {2, {0x1fa3, 0x1fab}}},
- {{0x1f64, 0x03b9}, {2, {0x1fa4, 0x1fac}}},
- {{0x1f65, 0x03b9}, {2, {0x1fa5, 0x1fad}}},
- {{0x1f66, 0x03b9}, {2, {0x1fa6, 0x1fae}}},
- {{0x1f67, 0x03b9}, {2, {0x1fa7, 0x1faf}}},
- {{0x1f70, 0x03b9}, {1, {0x1fb2}}},
- {{0x1f74, 0x03b9}, {1, {0x1fc2}}},
- {{0x1f7c, 0x03b9}, {1, {0x1ff2}}},
-#define CaseUnfold_12_Locale (*(CaseUnfold_12_Type (*)[1])(CaseUnfold_12_Table+58))
- {{0x0069, 0x0307}, {1, {0x0130}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3,4,5,6 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_12_hash -N onigenc_unicode_CaseUnfold_12_lookup -n */
-
-/* maximum key range = 71, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseUnfold_12_hash(const OnigCodePoint *codes)
-{
- static const unsigned char asso_values[] =
- {
- 3, 58, 54, 57, 56, 16, 8, 2, 43, 82,
- 3, 1, 23, 82, 82, 82, 82, 82, 82, 4,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 52, 51, 50, 49, 48, 47, 46, 45,
- 82, 82, 82, 82, 43, 82, 42, 82, 82, 13,
- 82, 82, 82, 82, 82, 11, 82, 1, 82, 82,
- 14, 82, 1, 82, 82, 31, 3, 82, 82, 30,
- 82, 82, 82, 10, 82, 82, 82, 82, 37, 82,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 82, 37, 15, 36, 35,
- 34, 17, 1, 33, 12, 4, 23, 23, 26, 21,
- 13, 82, 27, 82, 82, 2, 5, 82, 11, 16,
- 82, 15, 82, 82, 23, 82, 8, 82
- };
- return asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
-}
-
-static const CodePointList2 *
-onigenc_unicode_CaseUnfold_12_lookup(const OnigCodePoint *codes)
-{
- enum
- {
- MIN_CODE_VALUE = 0x61,
- MAX_CODE_VALUE = 0x1f7c,
- TOTAL_KEYWORDS = 59,
- MIN_WORD_LENGTH = 6,
- MAX_WORD_LENGTH = 6,
- MIN_HASH_VALUE = 11,
- MAX_HASH_VALUE = 81
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1,
- /*0x1f66,0x03b9*/ 53,
- /*0x1f07,0x03b9*/ 38,
- /*0x1f00,0x03b9*/ 31,
- /*0x0066,0x0066*/ 1,
- /*0x1f74,0x03b9*/ 56,
- /*0x0073,0x0073*/ 6,
- /*0x0066,0x0069*/ 2,
- /*0x1f06,0x03b9*/ 37,
- /*0x0073,0x0074*/ 7,
- /*0x03b9,0x0342*/ 18,
- /*0x03c9,0x03b9*/ 23,
- /*0x03b7,0x03b9*/ 17,
- /*0x0069,0x0307*/ 58,
- /*0x03b1,0x03b9*/ 15,
- /*0x1f61,0x03b9*/ 48,
- /*0x1f05,0x03b9*/ 36,
- /*0x1f65,0x03b9*/ 52,
- /*0x0574,0x0576*/ 29,
- /*0x03c9,0x0342*/ 22,
- /*0x03b7,0x0342*/ 16,
- /*0x057e,0x0576*/ 30,
- /*0x03b1,0x0342*/ 14,
- /*0x1f7c,0x03b9*/ 57,
- /*0x0574,0x0565*/ 26,
- /*0x0079,0x030a*/ 10,
- /*0x0077,0x030a*/ 9,
- /*0x1f70,0x03b9*/ 55,
- /*0x0574,0x056d*/ 28,
- /*0x0066,0x006c*/ 3,
- /*0x0574,0x056b*/ 27,
- /*0x0061,0x02be*/ 0,
- /*0x0068,0x0331*/ 4,
- /*0x1f67,0x03b9*/ 54,
- /*0x1f64,0x03b9*/ 51,
- /*0x1f63,0x03b9*/ 50,
- /*0x1f62,0x03b9*/ 49,
- /*0x1f60,0x03b9*/ 47,
- /*0x03ce,0x03b9*/ 24,
- /*0x03c5,0x0342*/ 21,
- /*0x03c5,0x0313*/ 20,
- /*0x03c1,0x0313*/ 19,
- /*0x02bc,0x006e*/ 11,
- /*0x03ae,0x03b9*/ 13,
- /*0x03ac,0x03b9*/ 12,
- /*0x1f27,0x03b9*/ 46,
- /*0x1f26,0x03b9*/ 45,
- /*0x1f25,0x03b9*/ 44,
- /*0x1f24,0x03b9*/ 43,
- /*0x1f23,0x03b9*/ 42,
- /*0x1f22,0x03b9*/ 41,
- /*0x1f21,0x03b9*/ 40,
- /*0x1f20,0x03b9*/ 39,
- /*0x006a,0x030c*/ 5,
- /*0x1f02,0x03b9*/ 33,
- /*0x0074,0x0308*/ 8,
- /*0x1f04,0x03b9*/ 35,
- /*0x1f03,0x03b9*/ 34,
- /*0x1f01,0x03b9*/ 32,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- /*0x0565,0x0582*/ 25
- };
-
- if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
- codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseUnfold_12_hash(codes);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code2_equal(codes, CaseUnfold_12_Table[s].from))
- return &CaseUnfold_12_Table[s].to;
- }
- }
- return 0;
-}
-
-static const CaseUnfold_13_Type CaseUnfold_13_Table[] = {
-#define CaseUnfold_13 (*(CaseUnfold_13_Type (*)[14])(CaseUnfold_13_Table+0))
- {{0x0066, 0x0066, 0x0069}, {1, {0xfb03}}},
- {{0x0066, 0x0066, 0x006c}, {1, {0xfb04}}},
- {{0x03b1, 0x0342, 0x03b9}, {1, {0x1fb7}}},
- {{0x03b7, 0x0342, 0x03b9}, {1, {0x1fc7}}},
- {{0x03b9, 0x0308, 0x0300}, {1, {0x1fd2}}},
- {{0x03b9, 0x0308, 0x0301}, {2, {0x0390, 0x1fd3}}},
- {{0x03b9, 0x0308, 0x0342}, {1, {0x1fd7}}},
- {{0x03c5, 0x0308, 0x0300}, {1, {0x1fe2}}},
- {{0x03c5, 0x0308, 0x0301}, {2, {0x03b0, 0x1fe3}}},
- {{0x03c5, 0x0308, 0x0342}, {1, {0x1fe7}}},
- {{0x03c5, 0x0313, 0x0300}, {1, {0x1f52}}},
- {{0x03c5, 0x0313, 0x0301}, {1, {0x1f54}}},
- {{0x03c5, 0x0313, 0x0342}, {1, {0x1f56}}},
- {{0x03c9, 0x0342, 0x03b9}, {1, {0x1ff7}}},
-};
-
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -k1,2,3,4,5,6,7,8,9 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_13_hash -N onigenc_unicode_CaseUnfold_13_lookup -n */
-
-/* maximum key range = 20, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-/*ARGSUSED*/
-static unsigned int
-onigenc_unicode_CaseUnfold_13_hash(const OnigCodePoint *codes)
-{
- static const unsigned char asso_values[] =
- {
- 7, 4, 47, 47, 47, 47, 1, 1, 2, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 1,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 11,
- 47, 47, 47, 47, 47, 10, 47, 2, 47, 47,
- 47, 47, 47, 47, 47, 47, 1, 47, 47, 1,
- 47, 47, 47, 9, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 1, 47, 47, 2, 47, 47, 1, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47
- };
- return asso_values[bits_at(codes, 8)] + asso_values[bits_at(codes, 7)] + asso_values[bits_at(codes, 6)] + asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
-}
-
-static const CodePointList2 *
-onigenc_unicode_CaseUnfold_13_lookup(const OnigCodePoint *codes)
-{
- enum
- {
- MIN_CODE_VALUE = 0x66,
- MAX_CODE_VALUE = 0x3c9,
- TOTAL_KEYWORDS = 14,
- MIN_WORD_LENGTH = 9,
- MAX_WORD_LENGTH = 9,
- MIN_HASH_VALUE = 27,
- MAX_HASH_VALUE = 46
- };
-
- static const short wordlist[] =
- {
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1,
- -1, -1, -1,
- /*0x03c5,0x0313,0x0342*/ 12,
- /*0x03c5,0x0308,0x0342*/ 9,
- /*0x03b9,0x0308,0x0342*/ 6,
- /*0x03c5,0x0313,0x0301*/ 11,
- /*0x03c5,0x0308,0x0301*/ 8,
- /*0x03b9,0x0308,0x0301*/ 5,
- /*0x03c5,0x0313,0x0300*/ 10,
- /*0x03c5,0x0308,0x0300*/ 7,
- /*0x03b9,0x0308,0x0300*/ 4,
- /*0x03c9,0x0342,0x03b9*/ 13,
- /*0x03b7,0x0342,0x03b9*/ 3,
- /*0x03b1,0x0342,0x03b9*/ 2,
- -1, -1, -1, -1, -1, -1,
- /*0x0066,0x0066,0x006c*/ 1,
- /*0x0066,0x0066,0x0069*/ 0
- };
-
- if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
- codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE &&
- codes[2] <= MAX_CODE_VALUE && codes[2] >= MIN_CODE_VALUE)
- {
- register unsigned int key = onigenc_unicode_CaseUnfold_13_hash(codes);
-
- if (key <= MAX_HASH_VALUE)
- {
- register short s = wordlist[key];
-
- if (s >= 0 && code3_equal(codes, CaseUnfold_13_Table[s].from))
- return &CaseUnfold_13_Table[s].to;
- }
- }
- return 0;
-}
-
-static const OnigCodePoint CaseMappingSpecials[] = {
- L(1)|0x039C,
- L(2)|0x0053, 0x0073, L(2)|0x0053, 0x0053,
- L(2)|0x02BC, 0x004E,
- L(1)|0x0053,
- L(1)|0x01C5,
- L(2)|0x0064, 0x017D, L(1)|0x01C4,
- L(1)|0x01C8,
- L(2)|0x006C, 0x004A, L(1)|0x01C7,
- L(1)|0x01CB,
- L(2)|0x006E, 0x004A, L(1)|0x01CA,
- L(2)|0x004A, 0x030C,
- L(1)|0x01F2,
- L(2)|0x0064, 0x005A, L(1)|0x01F1,
- L(1)|0x0399,
- L(3)|0x0399, 0x0308, 0x0301,
- L(3)|0x03A5, 0x0308, 0x0301,
- L(1)|0x03A3,
- L(1)|0x0392,
- L(1)|0x0398,
- L(1)|0x03A6,
- L(1)|0x03A0,
- L(1)|0x039A,
- L(1)|0x03A1,
- L(1)|0x0395,
- L(2)|0x0535, 0x0582, L(2)|0x0535, 0x0552,
- L(1)|0x0412,
- L(1)|0x0414,
- L(1)|0x041E,
- L(1)|0x0421,
- L(1)|0x0422,
- L(1)|0x0422,
- L(1)|0x042A,
- L(1)|0x0462,
- L(1)|0xA64A,
- L(2)|0x0048, 0x0331,
- L(2)|0x0054, 0x0308,
- L(2)|0x0057, 0x030A,
- L(2)|0x0059, 0x030A,
- L(2)|0x0041, 0x02BE,
- L(1)|0x1E60,
- L(1)|0x00DF,
- L(2)|0x03A5, 0x0313,
- L(3)|0x03A5, 0x0313, 0x0300,
- L(3)|0x03A5, 0x0313, 0x0301,
- L(3)|0x03A5, 0x0313, 0x0342,
- L(1)|0x1F88, L(2)|0x1F08, 0x0399,
- L(1)|0x1F89, L(2)|0x1F09, 0x0399,
- L(1)|0x1F8A, L(2)|0x1F0A, 0x0399,
- L(1)|0x1F8B, L(2)|0x1F0B, 0x0399,
- L(1)|0x1F8C, L(2)|0x1F0C, 0x0399,
- L(1)|0x1F8D, L(2)|0x1F0D, 0x0399,
- L(1)|0x1F8E, L(2)|0x1F0E, 0x0399,
- L(1)|0x1F8F, L(2)|0x1F0F, 0x0399,
- L(2)|0x1F00, 0x0399, L(1)|0x1F80, L(2)|0x1F08, 0x0399,
- L(2)|0x1F01, 0x0399, L(1)|0x1F81, L(2)|0x1F09, 0x0399,
- L(2)|0x1F02, 0x0399, L(1)|0x1F82, L(2)|0x1F0A, 0x0399,
- L(2)|0x1F03, 0x0399, L(1)|0x1F83, L(2)|0x1F0B, 0x0399,
- L(2)|0x1F04, 0x0399, L(1)|0x1F84, L(2)|0x1F0C, 0x0399,
- L(2)|0x1F05, 0x0399, L(1)|0x1F85, L(2)|0x1F0D, 0x0399,
- L(2)|0x1F06, 0x0399, L(1)|0x1F86, L(2)|0x1F0E, 0x0399,
- L(2)|0x1F07, 0x0399, L(1)|0x1F87, L(2)|0x1F0F, 0x0399,
- L(1)|0x1F98, L(2)|0x1F28, 0x0399,
- L(1)|0x1F99, L(2)|0x1F29, 0x0399,
- L(1)|0x1F9A, L(2)|0x1F2A, 0x0399,
- L(1)|0x1F9B, L(2)|0x1F2B, 0x0399,
- L(1)|0x1F9C, L(2)|0x1F2C, 0x0399,
- L(1)|0x1F9D, L(2)|0x1F2D, 0x0399,
- L(1)|0x1F9E, L(2)|0x1F2E, 0x0399,
- L(1)|0x1F9F, L(2)|0x1F2F, 0x0399,
- L(2)|0x1F20, 0x0399, L(1)|0x1F90, L(2)|0x1F28, 0x0399,
- L(2)|0x1F21, 0x0399, L(1)|0x1F91, L(2)|0x1F29, 0x0399,
- L(2)|0x1F22, 0x0399, L(1)|0x1F92, L(2)|0x1F2A, 0x0399,
- L(2)|0x1F23, 0x0399, L(1)|0x1F93, L(2)|0x1F2B, 0x0399,
- L(2)|0x1F24, 0x0399, L(1)|0x1F94, L(2)|0x1F2C, 0x0399,
- L(2)|0x1F25, 0x0399, L(1)|0x1F95, L(2)|0x1F2D, 0x0399,
- L(2)|0x1F26, 0x0399, L(1)|0x1F96, L(2)|0x1F2E, 0x0399,
- L(2)|0x1F27, 0x0399, L(1)|0x1F97, L(2)|0x1F2F, 0x0399,
- L(1)|0x1FA8, L(2)|0x1F68, 0x0399,
- L(1)|0x1FA9, L(2)|0x1F69, 0x0399,
- L(1)|0x1FAA, L(2)|0x1F6A, 0x0399,
- L(1)|0x1FAB, L(2)|0x1F6B, 0x0399,
- L(1)|0x1FAC, L(2)|0x1F6C, 0x0399,
- L(1)|0x1FAD, L(2)|0x1F6D, 0x0399,
- L(1)|0x1FAE, L(2)|0x1F6E, 0x0399,
- L(1)|0x1FAF, L(2)|0x1F6F, 0x0399,
- L(2)|0x1F60, 0x0399, L(1)|0x1FA0, L(2)|0x1F68, 0x0399,
- L(2)|0x1F61, 0x0399, L(1)|0x1FA1, L(2)|0x1F69, 0x0399,
- L(2)|0x1F62, 0x0399, L(1)|0x1FA2, L(2)|0x1F6A, 0x0399,
- L(2)|0x1F63, 0x0399, L(1)|0x1FA3, L(2)|0x1F6B, 0x0399,
- L(2)|0x1F64, 0x0399, L(1)|0x1FA4, L(2)|0x1F6C, 0x0399,
- L(2)|0x1F65, 0x0399, L(1)|0x1FA5, L(2)|0x1F6D, 0x0399,
- L(2)|0x1F66, 0x0399, L(1)|0x1FA6, L(2)|0x1F6E, 0x0399,
- L(2)|0x1F67, 0x0399, L(1)|0x1FA7, L(2)|0x1F6F, 0x0399,
- L(2)|0x1FBA, 0x0345, L(2)|0x1FBA, 0x0399,
- L(1)|0x1FBC, L(2)|0x0391, 0x0399,
- L(2)|0x0386, 0x0345, L(2)|0x0386, 0x0399,
- L(2)|0x0391, 0x0342,
- L(3)|0x0391, 0x0342, 0x0345, L(3)|0x0391, 0x0342, 0x0399,
- L(2)|0x03B1, 0x0399, L(1)|0x1FB3, L(2)|0x0391, 0x0399,
- L(1)|0x0399,
- L(2)|0x1FCA, 0x0345, L(2)|0x1FCA, 0x0399,
- L(1)|0x1FCC, L(2)|0x0397, 0x0399,
- L(2)|0x0389, 0x0345, L(2)|0x0389, 0x0399,
- L(2)|0x0397, 0x0342,
- L(3)|0x0397, 0x0342, 0x0345, L(3)|0x0397, 0x0342, 0x0399,
- L(2)|0x03B7, 0x0399, L(1)|0x1FC3, L(2)|0x0397, 0x0399,
- L(3)|0x0399, 0x0308, 0x0300,
- L(3)|0x0399, 0x0308, 0x0301,
- L(2)|0x0399, 0x0342,
- L(3)|0x0399, 0x0308, 0x0342,
- L(3)|0x03A5, 0x0308, 0x0300,
- L(3)|0x03A5, 0x0308, 0x0301,
- L(2)|0x03A1, 0x0313,
- L(2)|0x03A5, 0x0342,
- L(3)|0x03A5, 0x0308, 0x0342,
- L(2)|0x1FFA, 0x0345, L(2)|0x1FFA, 0x0399,
- L(1)|0x1FFC, L(2)|0x03A9, 0x0399,
- L(2)|0x038F, 0x0345, L(2)|0x038F, 0x0399,
- L(2)|0x03A9, 0x0342,
- L(3)|0x03A9, 0x0342, 0x0345, L(3)|0x03A9, 0x0342, 0x0399,
- L(2)|0x03C9, 0x0399, L(1)|0x1FF3, L(2)|0x03A9, 0x0399,
- L(2)|0x0046, 0x0066, L(2)|0x0046, 0x0046,
- L(2)|0x0046, 0x0069, L(2)|0x0046, 0x0049,
- L(2)|0x0046, 0x006C, L(2)|0x0046, 0x004C,
- L(3)|0x0046, 0x0066, 0x0069, L(3)|0x0046, 0x0046, 0x0049,
- L(3)|0x0046, 0x0066, 0x006C, L(3)|0x0046, 0x0046, 0x004C,
- L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
- L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
- L(2)|0x0544, 0x0576, L(2)|0x0544, 0x0546,
- L(2)|0x0544, 0x0565, L(2)|0x0544, 0x0535,
- L(2)|0x0544, 0x056B, L(2)|0x0544, 0x053B,
- L(2)|0x054E, 0x0576, L(2)|0x054E, 0x0546,
- L(2)|0x0544, 0x056D, L(2)|0x0544, 0x053D,
-};
diff --git a/enc/unicode/15.1.0/name2ctype.h b/enc/unicode/15.1.0/name2ctype.h
deleted file mode 100644
index b55a4f89b0..0000000000
--- a/enc/unicode/15.1.0/name2ctype.h
+++ /dev/null
@@ -1,46714 +0,0 @@
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -7 -c -j1 -i1 -t -C -P -T -H uniname2ctype_hash -Q uniname2ctype_pool -N uniname2ctype_p */
-#ifndef USE_UNICODE_PROPERTIES
-/* Computed positions: -k'1,3' */
-#else /* USE_UNICODE_PROPERTIES */
-/* Computed positions: -k'1-3,5-6,12,16,$' */
-#endif /* USE_UNICODE_PROPERTIES */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
- && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
- && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
- && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
- && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
- && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
- && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
- && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
- && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
- && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
- && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
- && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
- && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
- && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
- && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
- && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
- && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
- && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
- && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
- && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
- && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
- && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
- && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646. */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
-#endif
-
-
-
-/* 'NEWLINE': [[:NEWLINE:]] */
-static const OnigCodePoint CR_NEWLINE[] = {
- 1,
- 0x000a, 0x000a,
-}; /* CR_NEWLINE */
-
-/* 'Alpha': [[:Alpha:]] */
-static const OnigCodePoint CR_Alpha[] = {
- 733,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0345, 0x0345,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05b0, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0657,
- 0x0659, 0x065f,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06e1, 0x06e8,
- 0x06ed, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x073f,
- 0x074d, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0817,
- 0x081a, 0x082c,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x08d4, 0x08df,
- 0x08e3, 0x08e9,
- 0x08f0, 0x093b,
- 0x093d, 0x094c,
- 0x094e, 0x0950,
- 0x0955, 0x0963,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09ce, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4c,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a70, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0af9, 0x0afc,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccc,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e46,
- 0x0e4d, 0x0e4d,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ecd, 0x0ecd,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f83,
- 0x0f88, 0x0f97,
- 0x0f99, 0x0fbc,
- 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,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Alpha */
-
-/* 'Blank': [[:Blank:]] */
-static const OnigCodePoint CR_Blank[] = {
- 8,
- 0x0009, 0x0009,
- 0x0020, 0x0020,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Blank */
-
-/* 'Cntrl': [[:Cntrl:]] */
-static const OnigCodePoint CR_Cntrl[] = {
- 2,
- 0x0000, 0x001f,
- 0x007f, 0x009f,
-}; /* CR_Cntrl */
-
-/* 'Digit': [[:Digit:]] */
-static const OnigCodePoint CR_Digit[] = {
- 64,
- 0x0030, 0x0039,
- 0x0660, 0x0669,
- 0x06f0, 0x06f9,
- 0x07c0, 0x07c9,
- 0x0966, 0x096f,
- 0x09e6, 0x09ef,
- 0x0a66, 0x0a6f,
- 0x0ae6, 0x0aef,
- 0x0b66, 0x0b6f,
- 0x0be6, 0x0bef,
- 0x0c66, 0x0c6f,
- 0x0ce6, 0x0cef,
- 0x0d66, 0x0d6f,
- 0x0de6, 0x0def,
- 0x0e50, 0x0e59,
- 0x0ed0, 0x0ed9,
- 0x0f20, 0x0f29,
- 0x1040, 0x1049,
- 0x1090, 0x1099,
- 0x17e0, 0x17e9,
- 0x1810, 0x1819,
- 0x1946, 0x194f,
- 0x19d0, 0x19d9,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1b50, 0x1b59,
- 0x1bb0, 0x1bb9,
- 0x1c40, 0x1c49,
- 0x1c50, 0x1c59,
- 0xa620, 0xa629,
- 0xa8d0, 0xa8d9,
- 0xa900, 0xa909,
- 0xa9d0, 0xa9d9,
- 0xa9f0, 0xa9f9,
- 0xaa50, 0xaa59,
- 0xabf0, 0xabf9,
- 0xff10, 0xff19,
- 0x104a0, 0x104a9,
- 0x10d30, 0x10d39,
- 0x11066, 0x1106f,
- 0x110f0, 0x110f9,
- 0x11136, 0x1113f,
- 0x111d0, 0x111d9,
- 0x112f0, 0x112f9,
- 0x11450, 0x11459,
- 0x114d0, 0x114d9,
- 0x11650, 0x11659,
- 0x116c0, 0x116c9,
- 0x11730, 0x11739,
- 0x118e0, 0x118e9,
- 0x11950, 0x11959,
- 0x11c50, 0x11c59,
- 0x11d50, 0x11d59,
- 0x11da0, 0x11da9,
- 0x11f50, 0x11f59,
- 0x16a60, 0x16a69,
- 0x16ac0, 0x16ac9,
- 0x16b50, 0x16b59,
- 0x1d7ce, 0x1d7ff,
- 0x1e140, 0x1e149,
- 0x1e2f0, 0x1e2f9,
- 0x1e4f0, 0x1e4f9,
- 0x1e950, 0x1e959,
- 0x1fbf0, 0x1fbf9,
-}; /* CR_Digit */
-
-/* 'Graph': [[:Graph:]] */
-static const OnigCodePoint CR_Graph[] = {
- 713,
- 0x0021, 0x007e,
- 0x00a1, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x167f,
- 0x1681, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x200b, 0x2027,
- 0x202a, 0x202e,
- 0x2030, 0x205e,
- 0x2060, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2fff,
- 0x3001, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xe000, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Graph */
-
-/* 'Lower': [[:Lower:]] */
-static const OnigCodePoint CR_Lower[] = {
- 671,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0138,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018d,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019b,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01aa, 0x01ab,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01ba,
- 0x01bd, 0x01bf,
- 0x01c6, 0x01c6,
- 0x01c9, 0x01c9,
- 0x01cc, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f0,
- 0x01f3, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0221, 0x0221,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0239,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0293,
- 0x0295, 0x02b8,
- 0x02c0, 0x02c1,
- 0x02e0, 0x02e4,
- 0x0345, 0x0345,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037a, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fc,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0560, 0x0588,
- 0x10d0, 0x10fa,
- 0x10fc, 0x10ff,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1d00, 0x1dbf,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9d,
- 0x1e9f, 0x1e9f,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x210a, 0x210a,
- 0x210e, 0x210f,
- 0x2113, 0x2113,
- 0x212f, 0x212f,
- 0x2134, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213d,
- 0x2146, 0x2149,
- 0x214e, 0x214e,
- 0x2170, 0x217f,
- 0x2184, 0x2184,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c71, 0x2c71,
- 0x2c73, 0x2c74,
- 0x2c76, 0x2c7d,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce4,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69d,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa731,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa778,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa78e, 0xa78e,
- 0xa791, 0xa791,
- 0xa793, 0xa795,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7af, 0xa7af,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7d1, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d5,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7f2, 0xa7f4,
- 0xa7f6, 0xa7f6,
- 0xa7f8, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10780, 0x10780,
- 0x10783, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10cc0, 0x10cf2,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1d41a, 0x1d433,
- 0x1d44e, 0x1d454,
- 0x1d456, 0x1d467,
- 0x1d482, 0x1d49b,
- 0x1d4b6, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d4cf,
- 0x1d4ea, 0x1d503,
- 0x1d51e, 0x1d537,
- 0x1d552, 0x1d56b,
- 0x1d586, 0x1d59f,
- 0x1d5ba, 0x1d5d3,
- 0x1d5ee, 0x1d607,
- 0x1d622, 0x1d63b,
- 0x1d656, 0x1d66f,
- 0x1d68a, 0x1d6a5,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6e1,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d71b,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d755,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d78f,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7c9,
- 0x1d7cb, 0x1d7cb,
- 0x1df00, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e030, 0x1e06d,
- 0x1e922, 0x1e943,
-}; /* CR_Lower */
-
-/* 'Print': [[:Print:]] */
-static const OnigCodePoint CR_Print[] = {
- 709,
- 0x0020, 0x007e,
- 0x00a0, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2027,
- 0x202a, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xe000, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Print */
-
-/* 'XPosixPunct': [[:Punct:]] */
-static const OnigCodePoint CR_XPosixPunct[] = {
- 186,
- 0x0021, 0x002f,
- 0x003a, 0x0040,
- 0x005b, 0x0060,
- 0x007b, 0x007e,
- 0x00a1, 0x00a1,
- 0x00a7, 0x00a7,
- 0x00ab, 0x00ab,
- 0x00b6, 0x00b7,
- 0x00bb, 0x00bb,
- 0x00bf, 0x00bf,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x055a, 0x055f,
- 0x0589, 0x058a,
- 0x05be, 0x05be,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05f3, 0x05f4,
- 0x0609, 0x060a,
- 0x060c, 0x060d,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x066a, 0x066d,
- 0x06d4, 0x06d4,
- 0x0700, 0x070d,
- 0x07f7, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0970, 0x0970,
- 0x09fd, 0x09fd,
- 0x0a76, 0x0a76,
- 0x0af0, 0x0af0,
- 0x0c77, 0x0c77,
- 0x0c84, 0x0c84,
- 0x0df4, 0x0df4,
- 0x0e4f, 0x0e4f,
- 0x0e5a, 0x0e5b,
- 0x0f04, 0x0f12,
- 0x0f14, 0x0f14,
- 0x0f3a, 0x0f3d,
- 0x0f85, 0x0f85,
- 0x0fd0, 0x0fd4,
- 0x0fd9, 0x0fda,
- 0x104a, 0x104f,
- 0x10fb, 0x10fb,
- 0x1360, 0x1368,
- 0x1400, 0x1400,
- 0x166e, 0x166e,
- 0x169b, 0x169c,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17d8, 0x17da,
- 0x1800, 0x180a,
- 0x1944, 0x1945,
- 0x1a1e, 0x1a1f,
- 0x1aa0, 0x1aa6,
- 0x1aa8, 0x1aad,
- 0x1b5a, 0x1b60,
- 0x1b7d, 0x1b7e,
- 0x1bfc, 0x1bff,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x2010, 0x2027,
- 0x2030, 0x2043,
- 0x2045, 0x2051,
- 0x2053, 0x205e,
- 0x207d, 0x207e,
- 0x208d, 0x208e,
- 0x2308, 0x230b,
- 0x2329, 0x232a,
- 0x2768, 0x2775,
- 0x27c5, 0x27c6,
- 0x27e6, 0x27ef,
- 0x2983, 0x2998,
- 0x29d8, 0x29db,
- 0x29fc, 0x29fd,
- 0x2cf9, 0x2cfc,
- 0x2cfe, 0x2cff,
- 0x2d70, 0x2d70,
- 0x2e00, 0x2e2e,
- 0x2e30, 0x2e4f,
- 0x2e52, 0x2e5d,
- 0x3001, 0x3003,
- 0x3008, 0x3011,
- 0x3014, 0x301f,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x30a0, 0x30a0,
- 0x30fb, 0x30fb,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa673, 0xa673,
- 0xa67e, 0xa67e,
- 0xa6f2, 0xa6f7,
- 0xa874, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa8f8, 0xa8fa,
- 0xa8fc, 0xa8fc,
- 0xa92e, 0xa92f,
- 0xa95f, 0xa95f,
- 0xa9c1, 0xa9cd,
- 0xa9de, 0xa9df,
- 0xaa5c, 0xaa5f,
- 0xaade, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfd3e, 0xfd3f,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe61,
- 0xfe63, 0xfe63,
- 0xfe68, 0xfe68,
- 0xfe6a, 0xfe6b,
- 0xff01, 0xff03,
- 0xff05, 0xff0a,
- 0xff0c, 0xff0f,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff20,
- 0xff3b, 0xff3d,
- 0xff3f, 0xff3f,
- 0xff5b, 0xff5b,
- 0xff5d, 0xff5d,
- 0xff5f, 0xff65,
- 0x10100, 0x10102,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x1056f, 0x1056f,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x1093f, 0x1093f,
- 0x10a50, 0x10a58,
- 0x10a7f, 0x10a7f,
- 0x10af0, 0x10af6,
- 0x10b39, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10ead, 0x10ead,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x11140, 0x11143,
- 0x11174, 0x11175,
- 0x111c5, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111db, 0x111db,
- 0x111dd, 0x111df,
- 0x11238, 0x1123d,
- 0x112a9, 0x112a9,
- 0x1144b, 0x1144f,
- 0x1145a, 0x1145b,
- 0x1145d, 0x1145d,
- 0x114c6, 0x114c6,
- 0x115c1, 0x115d7,
- 0x11641, 0x11643,
- 0x11660, 0x1166c,
- 0x116b9, 0x116b9,
- 0x1173c, 0x1173e,
- 0x1183b, 0x1183b,
- 0x11944, 0x11946,
- 0x119e2, 0x119e2,
- 0x11a3f, 0x11a46,
- 0x11a9a, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11b00, 0x11b09,
- 0x11c41, 0x11c45,
- 0x11c70, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f4f,
- 0x11fff, 0x11fff,
- 0x12470, 0x12474,
- 0x12ff1, 0x12ff2,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b3b,
- 0x16b44, 0x16b44,
- 0x16e97, 0x16e9a,
- 0x16fe2, 0x16fe2,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8b,
- 0x1e95e, 0x1e95f,
-}; /* CR_XPosixPunct */
-
-/* 'Space': [[:Space:]] */
-static const OnigCodePoint CR_Space[] = {
- 10,
- 0x0009, 0x000d,
- 0x0020, 0x0020,
- 0x0085, 0x0085,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x2028, 0x2029,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Space */
-
-/* 'Upper': [[:Upper:]] */
-static const OnigCodePoint CR_Upper[] = {
- 651,
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x014a, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c4,
- 0x01c7, 0x01c7,
- 0x01ca, 0x01ca,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f1,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03cf, 0x03cf,
- 0x03d2, 0x03d4,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f4, 0x03f4,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 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,
-}; /* CR_Upper */
-
-/* 'XDigit': [[:XDigit:]] */
-static const OnigCodePoint CR_XDigit[] = {
- 3,
- 0x0030, 0x0039,
- 0x0041, 0x0046,
- 0x0061, 0x0066,
-}; /* CR_XDigit */
-
-/* 'Word': [[:Word:]] */
-static const OnigCodePoint CR_Word[] = {
- 771,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x005f, 0x005f,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0300, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x0483, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06df, 0x06e8,
- 0x06ea, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0800, 0x082d,
- 0x0840, 0x085b,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0898, 0x08e1,
- 0x08e3, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e4e,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f18, 0x0f19,
- 0x0f20, 0x0f29,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x1000, 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,
- 0x135d, 0x135f,
- 0x1380, 0x138f,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1734,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dd,
- 0x17e0, 0x17e9,
- 0x180b, 0x180d,
- 0x180f, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1946, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x1a00, 0x1a1b,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b59,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1bf3,
- 0x1c00, 0x1c37,
- 0x1c40, 0x1c49,
- 0x1c4d, 0x1c7d,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1cfa,
- 0x1d00, 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,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20f0,
- 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, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2dff,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3007,
- 0x3021, 0x302f,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x3099, 0x309a,
- 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, 0xa672,
- 0xa674, 0xa67d,
- 0xa67f, 0xa6f1,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa827,
- 0xa82c, 0xa82c,
- 0xa840, 0xa873,
- 0xa880, 0xa8c5,
- 0xa8d0, 0xa8d9,
- 0xa8e0, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa92d,
- 0xa930, 0xa953,
- 0xa960, 0xa97c,
- 0xa980, 0xa9c0,
- 0xa9cf, 0xa9d9,
- 0xa9e0, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaef,
- 0xaaf2, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabea,
- 0xabec, 0xabed,
- 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,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff10, 0xff19,
- 0xff21, 0xff3a,
- 0xff3f, 0xff3f,
- 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,
- 0x101fd, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102e0,
- 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,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae6,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f50,
- 0x10f70, 0x10f85,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11046,
- 0x11066, 0x11075,
- 0x1107f, 0x110ba,
- 0x110c2, 0x110c2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x1113f,
- 0x11144, 0x11147,
- 0x11150, 0x11173,
- 0x11176, 0x11176,
- 0x11180, 0x111c4,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x11237,
- 0x1123e, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1144a,
- 0x11450, 0x11459,
- 0x1145e, 0x11461,
- 0x11480, 0x114c5,
- 0x114c7, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115d8, 0x115dd,
- 0x11600, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x1183a,
- 0x118a0, 0x118e9,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11943,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e1,
- 0x119e3, 0x119e4,
- 0x11a00, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a50, 0x11a99,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c40,
- 0x11c50, 0x11c59,
- 0x11c72, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef6,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f50, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13440, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af4,
- 0x16b00, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 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,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 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,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8d0, 0x1e8d6,
- 0x1e900, 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,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0100, 0xe01ef,
-}; /* CR_Word */
-
-/* 'Alnum': [[:Alnum:]] */
-static const OnigCodePoint CR_Alnum[] = {
- 773,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0345, 0x0345,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05b0, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0657,
- 0x0659, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06e1, 0x06e8,
- 0x06ed, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x073f,
- 0x074d, 0x07b1,
- 0x07c0, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0817,
- 0x081a, 0x082c,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x08d4, 0x08df,
- 0x08e3, 0x08e9,
- 0x08f0, 0x093b,
- 0x093d, 0x094c,
- 0x094e, 0x0950,
- 0x0955, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09ce, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4c,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0afc,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccc,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e46,
- 0x0e4d, 0x0e4d,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ecd, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f20, 0x0f29,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f83,
- 0x0f88, 0x0f97,
- 0x0f99, 0x0fbc,
- 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,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Alnum */
-
-/* 'ASCII': [[:ASCII:]] */
-static const OnigCodePoint CR_ASCII[] = {
- 1,
- 0x0000, 0x007f,
-}; /* CR_ASCII */
-
-/* 'Punct': [[:Punct:]] */
-static const OnigCodePoint CR_Punct[] = {
- 191,
- 0x0021, 0x0023,
- 0x0025, 0x002a,
- 0x002c, 0x002f,
- 0x003a, 0x003b,
- 0x003f, 0x0040,
- 0x005b, 0x005d,
- 0x005f, 0x005f,
- 0x007b, 0x007b,
- 0x007d, 0x007d,
- 0x00a1, 0x00a1,
- 0x00a7, 0x00a7,
- 0x00ab, 0x00ab,
- 0x00b6, 0x00b7,
- 0x00bb, 0x00bb,
- 0x00bf, 0x00bf,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x055a, 0x055f,
- 0x0589, 0x058a,
- 0x05be, 0x05be,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05f3, 0x05f4,
- 0x0609, 0x060a,
- 0x060c, 0x060d,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x066a, 0x066d,
- 0x06d4, 0x06d4,
- 0x0700, 0x070d,
- 0x07f7, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0970, 0x0970,
- 0x09fd, 0x09fd,
- 0x0a76, 0x0a76,
- 0x0af0, 0x0af0,
- 0x0c77, 0x0c77,
- 0x0c84, 0x0c84,
- 0x0df4, 0x0df4,
- 0x0e4f, 0x0e4f,
- 0x0e5a, 0x0e5b,
- 0x0f04, 0x0f12,
- 0x0f14, 0x0f14,
- 0x0f3a, 0x0f3d,
- 0x0f85, 0x0f85,
- 0x0fd0, 0x0fd4,
- 0x0fd9, 0x0fda,
- 0x104a, 0x104f,
- 0x10fb, 0x10fb,
- 0x1360, 0x1368,
- 0x1400, 0x1400,
- 0x166e, 0x166e,
- 0x169b, 0x169c,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17d8, 0x17da,
- 0x1800, 0x180a,
- 0x1944, 0x1945,
- 0x1a1e, 0x1a1f,
- 0x1aa0, 0x1aa6,
- 0x1aa8, 0x1aad,
- 0x1b5a, 0x1b60,
- 0x1b7d, 0x1b7e,
- 0x1bfc, 0x1bff,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x2010, 0x2027,
- 0x2030, 0x2043,
- 0x2045, 0x2051,
- 0x2053, 0x205e,
- 0x207d, 0x207e,
- 0x208d, 0x208e,
- 0x2308, 0x230b,
- 0x2329, 0x232a,
- 0x2768, 0x2775,
- 0x27c5, 0x27c6,
- 0x27e6, 0x27ef,
- 0x2983, 0x2998,
- 0x29d8, 0x29db,
- 0x29fc, 0x29fd,
- 0x2cf9, 0x2cfc,
- 0x2cfe, 0x2cff,
- 0x2d70, 0x2d70,
- 0x2e00, 0x2e2e,
- 0x2e30, 0x2e4f,
- 0x2e52, 0x2e5d,
- 0x3001, 0x3003,
- 0x3008, 0x3011,
- 0x3014, 0x301f,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x30a0, 0x30a0,
- 0x30fb, 0x30fb,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa673, 0xa673,
- 0xa67e, 0xa67e,
- 0xa6f2, 0xa6f7,
- 0xa874, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa8f8, 0xa8fa,
- 0xa8fc, 0xa8fc,
- 0xa92e, 0xa92f,
- 0xa95f, 0xa95f,
- 0xa9c1, 0xa9cd,
- 0xa9de, 0xa9df,
- 0xaa5c, 0xaa5f,
- 0xaade, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfd3e, 0xfd3f,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe61,
- 0xfe63, 0xfe63,
- 0xfe68, 0xfe68,
- 0xfe6a, 0xfe6b,
- 0xff01, 0xff03,
- 0xff05, 0xff0a,
- 0xff0c, 0xff0f,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff20,
- 0xff3b, 0xff3d,
- 0xff3f, 0xff3f,
- 0xff5b, 0xff5b,
- 0xff5d, 0xff5d,
- 0xff5f, 0xff65,
- 0x10100, 0x10102,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x1056f, 0x1056f,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x1093f, 0x1093f,
- 0x10a50, 0x10a58,
- 0x10a7f, 0x10a7f,
- 0x10af0, 0x10af6,
- 0x10b39, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10ead, 0x10ead,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x11140, 0x11143,
- 0x11174, 0x11175,
- 0x111c5, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111db, 0x111db,
- 0x111dd, 0x111df,
- 0x11238, 0x1123d,
- 0x112a9, 0x112a9,
- 0x1144b, 0x1144f,
- 0x1145a, 0x1145b,
- 0x1145d, 0x1145d,
- 0x114c6, 0x114c6,
- 0x115c1, 0x115d7,
- 0x11641, 0x11643,
- 0x11660, 0x1166c,
- 0x116b9, 0x116b9,
- 0x1173c, 0x1173e,
- 0x1183b, 0x1183b,
- 0x11944, 0x11946,
- 0x119e2, 0x119e2,
- 0x11a3f, 0x11a46,
- 0x11a9a, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11b00, 0x11b09,
- 0x11c41, 0x11c45,
- 0x11c70, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f4f,
- 0x11fff, 0x11fff,
- 0x12470, 0x12474,
- 0x12ff1, 0x12ff2,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b3b,
- 0x16b44, 0x16b44,
- 0x16e97, 0x16e9a,
- 0x16fe2, 0x16fe2,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8b,
- 0x1e95e, 0x1e95f,
-}; /* CR_Punct */
-
-#ifdef USE_UNICODE_PROPERTIES
-/* 'Any': - */
-static const OnigCodePoint CR_Any[] = {
- 1,
- 0x0000, 0x10ffff,
-}; /* CR_Any */
-
-/* 'Assigned': - */
-static const OnigCodePoint CR_Assigned[] = {
- 707,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Assigned */
-
-/* 'C': Major Category */
-static const OnigCodePoint CR_C[] = {
- 712,
- 0x0000, 0x001f,
- 0x007f, 0x009f,
- 0x00ad, 0x00ad,
- 0x0378, 0x0379,
- 0x0380, 0x0383,
- 0x038b, 0x038b,
- 0x038d, 0x038d,
- 0x03a2, 0x03a2,
- 0x0530, 0x0530,
- 0x0557, 0x0558,
- 0x058b, 0x058c,
- 0x0590, 0x0590,
- 0x05c8, 0x05cf,
- 0x05eb, 0x05ee,
- 0x05f5, 0x0605,
- 0x061c, 0x061c,
- 0x06dd, 0x06dd,
- 0x070e, 0x070f,
- 0x074b, 0x074c,
- 0x07b2, 0x07bf,
- 0x07fb, 0x07fc,
- 0x082e, 0x082f,
- 0x083f, 0x083f,
- 0x085c, 0x085d,
- 0x085f, 0x085f,
- 0x086b, 0x086f,
- 0x088f, 0x0897,
- 0x08e2, 0x08e2,
- 0x0984, 0x0984,
- 0x098d, 0x098e,
- 0x0991, 0x0992,
- 0x09a9, 0x09a9,
- 0x09b1, 0x09b1,
- 0x09b3, 0x09b5,
- 0x09ba, 0x09bb,
- 0x09c5, 0x09c6,
- 0x09c9, 0x09ca,
- 0x09cf, 0x09d6,
- 0x09d8, 0x09db,
- 0x09de, 0x09de,
- 0x09e4, 0x09e5,
- 0x09ff, 0x0a00,
- 0x0a04, 0x0a04,
- 0x0a0b, 0x0a0e,
- 0x0a11, 0x0a12,
- 0x0a29, 0x0a29,
- 0x0a31, 0x0a31,
- 0x0a34, 0x0a34,
- 0x0a37, 0x0a37,
- 0x0a3a, 0x0a3b,
- 0x0a3d, 0x0a3d,
- 0x0a43, 0x0a46,
- 0x0a49, 0x0a4a,
- 0x0a4e, 0x0a50,
- 0x0a52, 0x0a58,
- 0x0a5d, 0x0a5d,
- 0x0a5f, 0x0a65,
- 0x0a77, 0x0a80,
- 0x0a84, 0x0a84,
- 0x0a8e, 0x0a8e,
- 0x0a92, 0x0a92,
- 0x0aa9, 0x0aa9,
- 0x0ab1, 0x0ab1,
- 0x0ab4, 0x0ab4,
- 0x0aba, 0x0abb,
- 0x0ac6, 0x0ac6,
- 0x0aca, 0x0aca,
- 0x0ace, 0x0acf,
- 0x0ad1, 0x0adf,
- 0x0ae4, 0x0ae5,
- 0x0af2, 0x0af8,
- 0x0b00, 0x0b00,
- 0x0b04, 0x0b04,
- 0x0b0d, 0x0b0e,
- 0x0b11, 0x0b12,
- 0x0b29, 0x0b29,
- 0x0b31, 0x0b31,
- 0x0b34, 0x0b34,
- 0x0b3a, 0x0b3b,
- 0x0b45, 0x0b46,
- 0x0b49, 0x0b4a,
- 0x0b4e, 0x0b54,
- 0x0b58, 0x0b5b,
- 0x0b5e, 0x0b5e,
- 0x0b64, 0x0b65,
- 0x0b78, 0x0b81,
- 0x0b84, 0x0b84,
- 0x0b8b, 0x0b8d,
- 0x0b91, 0x0b91,
- 0x0b96, 0x0b98,
- 0x0b9b, 0x0b9b,
- 0x0b9d, 0x0b9d,
- 0x0ba0, 0x0ba2,
- 0x0ba5, 0x0ba7,
- 0x0bab, 0x0bad,
- 0x0bba, 0x0bbd,
- 0x0bc3, 0x0bc5,
- 0x0bc9, 0x0bc9,
- 0x0bce, 0x0bcf,
- 0x0bd1, 0x0bd6,
- 0x0bd8, 0x0be5,
- 0x0bfb, 0x0bff,
- 0x0c0d, 0x0c0d,
- 0x0c11, 0x0c11,
- 0x0c29, 0x0c29,
- 0x0c3a, 0x0c3b,
- 0x0c45, 0x0c45,
- 0x0c49, 0x0c49,
- 0x0c4e, 0x0c54,
- 0x0c57, 0x0c57,
- 0x0c5b, 0x0c5c,
- 0x0c5e, 0x0c5f,
- 0x0c64, 0x0c65,
- 0x0c70, 0x0c76,
- 0x0c8d, 0x0c8d,
- 0x0c91, 0x0c91,
- 0x0ca9, 0x0ca9,
- 0x0cb4, 0x0cb4,
- 0x0cba, 0x0cbb,
- 0x0cc5, 0x0cc5,
- 0x0cc9, 0x0cc9,
- 0x0cce, 0x0cd4,
- 0x0cd7, 0x0cdc,
- 0x0cdf, 0x0cdf,
- 0x0ce4, 0x0ce5,
- 0x0cf0, 0x0cf0,
- 0x0cf4, 0x0cff,
- 0x0d0d, 0x0d0d,
- 0x0d11, 0x0d11,
- 0x0d45, 0x0d45,
- 0x0d49, 0x0d49,
- 0x0d50, 0x0d53,
- 0x0d64, 0x0d65,
- 0x0d80, 0x0d80,
- 0x0d84, 0x0d84,
- 0x0d97, 0x0d99,
- 0x0db2, 0x0db2,
- 0x0dbc, 0x0dbc,
- 0x0dbe, 0x0dbf,
- 0x0dc7, 0x0dc9,
- 0x0dcb, 0x0dce,
- 0x0dd5, 0x0dd5,
- 0x0dd7, 0x0dd7,
- 0x0de0, 0x0de5,
- 0x0df0, 0x0df1,
- 0x0df5, 0x0e00,
- 0x0e3b, 0x0e3e,
- 0x0e5c, 0x0e80,
- 0x0e83, 0x0e83,
- 0x0e85, 0x0e85,
- 0x0e8b, 0x0e8b,
- 0x0ea4, 0x0ea4,
- 0x0ea6, 0x0ea6,
- 0x0ebe, 0x0ebf,
- 0x0ec5, 0x0ec5,
- 0x0ec7, 0x0ec7,
- 0x0ecf, 0x0ecf,
- 0x0eda, 0x0edb,
- 0x0ee0, 0x0eff,
- 0x0f48, 0x0f48,
- 0x0f6d, 0x0f70,
- 0x0f98, 0x0f98,
- 0x0fbd, 0x0fbd,
- 0x0fcd, 0x0fcd,
- 0x0fdb, 0x0fff,
- 0x10c6, 0x10c6,
- 0x10c8, 0x10cc,
- 0x10ce, 0x10cf,
- 0x1249, 0x1249,
- 0x124e, 0x124f,
- 0x1257, 0x1257,
- 0x1259, 0x1259,
- 0x125e, 0x125f,
- 0x1289, 0x1289,
- 0x128e, 0x128f,
- 0x12b1, 0x12b1,
- 0x12b6, 0x12b7,
- 0x12bf, 0x12bf,
- 0x12c1, 0x12c1,
- 0x12c6, 0x12c7,
- 0x12d7, 0x12d7,
- 0x1311, 0x1311,
- 0x1316, 0x1317,
- 0x135b, 0x135c,
- 0x137d, 0x137f,
- 0x139a, 0x139f,
- 0x13f6, 0x13f7,
- 0x13fe, 0x13ff,
- 0x169d, 0x169f,
- 0x16f9, 0x16ff,
- 0x1716, 0x171e,
- 0x1737, 0x173f,
- 0x1754, 0x175f,
- 0x176d, 0x176d,
- 0x1771, 0x1771,
- 0x1774, 0x177f,
- 0x17de, 0x17df,
- 0x17ea, 0x17ef,
- 0x17fa, 0x17ff,
- 0x180e, 0x180e,
- 0x181a, 0x181f,
- 0x1879, 0x187f,
- 0x18ab, 0x18af,
- 0x18f6, 0x18ff,
- 0x191f, 0x191f,
- 0x192c, 0x192f,
- 0x193c, 0x193f,
- 0x1941, 0x1943,
- 0x196e, 0x196f,
- 0x1975, 0x197f,
- 0x19ac, 0x19af,
- 0x19ca, 0x19cf,
- 0x19db, 0x19dd,
- 0x1a1c, 0x1a1d,
- 0x1a5f, 0x1a5f,
- 0x1a7d, 0x1a7e,
- 0x1a8a, 0x1a8f,
- 0x1a9a, 0x1a9f,
- 0x1aae, 0x1aaf,
- 0x1acf, 0x1aff,
- 0x1b4d, 0x1b4f,
- 0x1b7f, 0x1b7f,
- 0x1bf4, 0x1bfb,
- 0x1c38, 0x1c3a,
- 0x1c4a, 0x1c4c,
- 0x1c89, 0x1c8f,
- 0x1cbb, 0x1cbc,
- 0x1cc8, 0x1ccf,
- 0x1cfb, 0x1cff,
- 0x1f16, 0x1f17,
- 0x1f1e, 0x1f1f,
- 0x1f46, 0x1f47,
- 0x1f4e, 0x1f4f,
- 0x1f58, 0x1f58,
- 0x1f5a, 0x1f5a,
- 0x1f5c, 0x1f5c,
- 0x1f5e, 0x1f5e,
- 0x1f7e, 0x1f7f,
- 0x1fb5, 0x1fb5,
- 0x1fc5, 0x1fc5,
- 0x1fd4, 0x1fd5,
- 0x1fdc, 0x1fdc,
- 0x1ff0, 0x1ff1,
- 0x1ff5, 0x1ff5,
- 0x1fff, 0x1fff,
- 0x200b, 0x200f,
- 0x202a, 0x202e,
- 0x2060, 0x206f,
- 0x2072, 0x2073,
- 0x208f, 0x208f,
- 0x209d, 0x209f,
- 0x20c1, 0x20cf,
- 0x20f1, 0x20ff,
- 0x218c, 0x218f,
- 0x2427, 0x243f,
- 0x244b, 0x245f,
- 0x2b74, 0x2b75,
- 0x2b96, 0x2b96,
- 0x2cf4, 0x2cf8,
- 0x2d26, 0x2d26,
- 0x2d28, 0x2d2c,
- 0x2d2e, 0x2d2f,
- 0x2d68, 0x2d6e,
- 0x2d71, 0x2d7e,
- 0x2d97, 0x2d9f,
- 0x2da7, 0x2da7,
- 0x2daf, 0x2daf,
- 0x2db7, 0x2db7,
- 0x2dbf, 0x2dbf,
- 0x2dc7, 0x2dc7,
- 0x2dcf, 0x2dcf,
- 0x2dd7, 0x2dd7,
- 0x2ddf, 0x2ddf,
- 0x2e5e, 0x2e7f,
- 0x2e9a, 0x2e9a,
- 0x2ef4, 0x2eff,
- 0x2fd6, 0x2fef,
- 0x3040, 0x3040,
- 0x3097, 0x3098,
- 0x3100, 0x3104,
- 0x3130, 0x3130,
- 0x318f, 0x318f,
- 0x31e4, 0x31ee,
- 0x321f, 0x321f,
- 0xa48d, 0xa48f,
- 0xa4c7, 0xa4cf,
- 0xa62c, 0xa63f,
- 0xa6f8, 0xa6ff,
- 0xa7cb, 0xa7cf,
- 0xa7d2, 0xa7d2,
- 0xa7d4, 0xa7d4,
- 0xa7da, 0xa7f1,
- 0xa82d, 0xa82f,
- 0xa83a, 0xa83f,
- 0xa878, 0xa87f,
- 0xa8c6, 0xa8cd,
- 0xa8da, 0xa8df,
- 0xa954, 0xa95e,
- 0xa97d, 0xa97f,
- 0xa9ce, 0xa9ce,
- 0xa9da, 0xa9dd,
- 0xa9ff, 0xa9ff,
- 0xaa37, 0xaa3f,
- 0xaa4e, 0xaa4f,
- 0xaa5a, 0xaa5b,
- 0xaac3, 0xaada,
- 0xaaf7, 0xab00,
- 0xab07, 0xab08,
- 0xab0f, 0xab10,
- 0xab17, 0xab1f,
- 0xab27, 0xab27,
- 0xab2f, 0xab2f,
- 0xab6c, 0xab6f,
- 0xabee, 0xabef,
- 0xabfa, 0xabff,
- 0xd7a4, 0xd7af,
- 0xd7c7, 0xd7ca,
- 0xd7fc, 0xf8ff,
- 0xfa6e, 0xfa6f,
- 0xfada, 0xfaff,
- 0xfb07, 0xfb12,
- 0xfb18, 0xfb1c,
- 0xfb37, 0xfb37,
- 0xfb3d, 0xfb3d,
- 0xfb3f, 0xfb3f,
- 0xfb42, 0xfb42,
- 0xfb45, 0xfb45,
- 0xfbc3, 0xfbd2,
- 0xfd90, 0xfd91,
- 0xfdc8, 0xfdce,
- 0xfdd0, 0xfdef,
- 0xfe1a, 0xfe1f,
- 0xfe53, 0xfe53,
- 0xfe67, 0xfe67,
- 0xfe6c, 0xfe6f,
- 0xfe75, 0xfe75,
- 0xfefd, 0xff00,
- 0xffbf, 0xffc1,
- 0xffc8, 0xffc9,
- 0xffd0, 0xffd1,
- 0xffd8, 0xffd9,
- 0xffdd, 0xffdf,
- 0xffe7, 0xffe7,
- 0xffef, 0xfffb,
- 0xfffe, 0xffff,
- 0x1000c, 0x1000c,
- 0x10027, 0x10027,
- 0x1003b, 0x1003b,
- 0x1003e, 0x1003e,
- 0x1004e, 0x1004f,
- 0x1005e, 0x1007f,
- 0x100fb, 0x100ff,
- 0x10103, 0x10106,
- 0x10134, 0x10136,
- 0x1018f, 0x1018f,
- 0x1019d, 0x1019f,
- 0x101a1, 0x101cf,
- 0x101fe, 0x1027f,
- 0x1029d, 0x1029f,
- 0x102d1, 0x102df,
- 0x102fc, 0x102ff,
- 0x10324, 0x1032c,
- 0x1034b, 0x1034f,
- 0x1037b, 0x1037f,
- 0x1039e, 0x1039e,
- 0x103c4, 0x103c7,
- 0x103d6, 0x103ff,
- 0x1049e, 0x1049f,
- 0x104aa, 0x104af,
- 0x104d4, 0x104d7,
- 0x104fc, 0x104ff,
- 0x10528, 0x1052f,
- 0x10564, 0x1056e,
- 0x1057b, 0x1057b,
- 0x1058b, 0x1058b,
- 0x10593, 0x10593,
- 0x10596, 0x10596,
- 0x105a2, 0x105a2,
- 0x105b2, 0x105b2,
- 0x105ba, 0x105ba,
- 0x105bd, 0x105ff,
- 0x10737, 0x1073f,
- 0x10756, 0x1075f,
- 0x10768, 0x1077f,
- 0x10786, 0x10786,
- 0x107b1, 0x107b1,
- 0x107bb, 0x107ff,
- 0x10806, 0x10807,
- 0x10809, 0x10809,
- 0x10836, 0x10836,
- 0x10839, 0x1083b,
- 0x1083d, 0x1083e,
- 0x10856, 0x10856,
- 0x1089f, 0x108a6,
- 0x108b0, 0x108df,
- 0x108f3, 0x108f3,
- 0x108f6, 0x108fa,
- 0x1091c, 0x1091e,
- 0x1093a, 0x1093e,
- 0x10940, 0x1097f,
- 0x109b8, 0x109bb,
- 0x109d0, 0x109d1,
- 0x10a04, 0x10a04,
- 0x10a07, 0x10a0b,
- 0x10a14, 0x10a14,
- 0x10a18, 0x10a18,
- 0x10a36, 0x10a37,
- 0x10a3b, 0x10a3e,
- 0x10a49, 0x10a4f,
- 0x10a59, 0x10a5f,
- 0x10aa0, 0x10abf,
- 0x10ae7, 0x10aea,
- 0x10af7, 0x10aff,
- 0x10b36, 0x10b38,
- 0x10b56, 0x10b57,
- 0x10b73, 0x10b77,
- 0x10b92, 0x10b98,
- 0x10b9d, 0x10ba8,
- 0x10bb0, 0x10bff,
- 0x10c49, 0x10c7f,
- 0x10cb3, 0x10cbf,
- 0x10cf3, 0x10cf9,
- 0x10d28, 0x10d2f,
- 0x10d3a, 0x10e5f,
- 0x10e7f, 0x10e7f,
- 0x10eaa, 0x10eaa,
- 0x10eae, 0x10eaf,
- 0x10eb2, 0x10efc,
- 0x10f28, 0x10f2f,
- 0x10f5a, 0x10f6f,
- 0x10f8a, 0x10faf,
- 0x10fcc, 0x10fdf,
- 0x10ff7, 0x10fff,
- 0x1104e, 0x11051,
- 0x11076, 0x1107e,
- 0x110bd, 0x110bd,
- 0x110c3, 0x110cf,
- 0x110e9, 0x110ef,
- 0x110fa, 0x110ff,
- 0x11135, 0x11135,
- 0x11148, 0x1114f,
- 0x11177, 0x1117f,
- 0x111e0, 0x111e0,
- 0x111f5, 0x111ff,
- 0x11212, 0x11212,
- 0x11242, 0x1127f,
- 0x11287, 0x11287,
- 0x11289, 0x11289,
- 0x1128e, 0x1128e,
- 0x1129e, 0x1129e,
- 0x112aa, 0x112af,
- 0x112eb, 0x112ef,
- 0x112fa, 0x112ff,
- 0x11304, 0x11304,
- 0x1130d, 0x1130e,
- 0x11311, 0x11312,
- 0x11329, 0x11329,
- 0x11331, 0x11331,
- 0x11334, 0x11334,
- 0x1133a, 0x1133a,
- 0x11345, 0x11346,
- 0x11349, 0x1134a,
- 0x1134e, 0x1134f,
- 0x11351, 0x11356,
- 0x11358, 0x1135c,
- 0x11364, 0x11365,
- 0x1136d, 0x1136f,
- 0x11375, 0x113ff,
- 0x1145c, 0x1145c,
- 0x11462, 0x1147f,
- 0x114c8, 0x114cf,
- 0x114da, 0x1157f,
- 0x115b6, 0x115b7,
- 0x115de, 0x115ff,
- 0x11645, 0x1164f,
- 0x1165a, 0x1165f,
- 0x1166d, 0x1167f,
- 0x116ba, 0x116bf,
- 0x116ca, 0x116ff,
- 0x1171b, 0x1171c,
- 0x1172c, 0x1172f,
- 0x11747, 0x117ff,
- 0x1183c, 0x1189f,
- 0x118f3, 0x118fe,
- 0x11907, 0x11908,
- 0x1190a, 0x1190b,
- 0x11914, 0x11914,
- 0x11917, 0x11917,
- 0x11936, 0x11936,
- 0x11939, 0x1193a,
- 0x11947, 0x1194f,
- 0x1195a, 0x1199f,
- 0x119a8, 0x119a9,
- 0x119d8, 0x119d9,
- 0x119e5, 0x119ff,
- 0x11a48, 0x11a4f,
- 0x11aa3, 0x11aaf,
- 0x11af9, 0x11aff,
- 0x11b0a, 0x11bff,
- 0x11c09, 0x11c09,
- 0x11c37, 0x11c37,
- 0x11c46, 0x11c4f,
- 0x11c6d, 0x11c6f,
- 0x11c90, 0x11c91,
- 0x11ca8, 0x11ca8,
- 0x11cb7, 0x11cff,
- 0x11d07, 0x11d07,
- 0x11d0a, 0x11d0a,
- 0x11d37, 0x11d39,
- 0x11d3b, 0x11d3b,
- 0x11d3e, 0x11d3e,
- 0x11d48, 0x11d4f,
- 0x11d5a, 0x11d5f,
- 0x11d66, 0x11d66,
- 0x11d69, 0x11d69,
- 0x11d8f, 0x11d8f,
- 0x11d92, 0x11d92,
- 0x11d99, 0x11d9f,
- 0x11daa, 0x11edf,
- 0x11ef9, 0x11eff,
- 0x11f11, 0x11f11,
- 0x11f3b, 0x11f3d,
- 0x11f5a, 0x11faf,
- 0x11fb1, 0x11fbf,
- 0x11ff2, 0x11ffe,
- 0x1239a, 0x123ff,
- 0x1246f, 0x1246f,
- 0x12475, 0x1247f,
- 0x12544, 0x12f8f,
- 0x12ff3, 0x12fff,
- 0x13430, 0x1343f,
- 0x13456, 0x143ff,
- 0x14647, 0x167ff,
- 0x16a39, 0x16a3f,
- 0x16a5f, 0x16a5f,
- 0x16a6a, 0x16a6d,
- 0x16abf, 0x16abf,
- 0x16aca, 0x16acf,
- 0x16aee, 0x16aef,
- 0x16af6, 0x16aff,
- 0x16b46, 0x16b4f,
- 0x16b5a, 0x16b5a,
- 0x16b62, 0x16b62,
- 0x16b78, 0x16b7c,
- 0x16b90, 0x16e3f,
- 0x16e9b, 0x16eff,
- 0x16f4b, 0x16f4e,
- 0x16f88, 0x16f8e,
- 0x16fa0, 0x16fdf,
- 0x16fe5, 0x16fef,
- 0x16ff2, 0x16fff,
- 0x187f8, 0x187ff,
- 0x18cd6, 0x18cff,
- 0x18d09, 0x1afef,
- 0x1aff4, 0x1aff4,
- 0x1affc, 0x1affc,
- 0x1afff, 0x1afff,
- 0x1b123, 0x1b131,
- 0x1b133, 0x1b14f,
- 0x1b153, 0x1b154,
- 0x1b156, 0x1b163,
- 0x1b168, 0x1b16f,
- 0x1b2fc, 0x1bbff,
- 0x1bc6b, 0x1bc6f,
- 0x1bc7d, 0x1bc7f,
- 0x1bc89, 0x1bc8f,
- 0x1bc9a, 0x1bc9b,
- 0x1bca0, 0x1ceff,
- 0x1cf2e, 0x1cf2f,
- 0x1cf47, 0x1cf4f,
- 0x1cfc4, 0x1cfff,
- 0x1d0f6, 0x1d0ff,
- 0x1d127, 0x1d128,
- 0x1d173, 0x1d17a,
- 0x1d1eb, 0x1d1ff,
- 0x1d246, 0x1d2bf,
- 0x1d2d4, 0x1d2df,
- 0x1d2f4, 0x1d2ff,
- 0x1d357, 0x1d35f,
- 0x1d379, 0x1d3ff,
- 0x1d455, 0x1d455,
- 0x1d49d, 0x1d49d,
- 0x1d4a0, 0x1d4a1,
- 0x1d4a3, 0x1d4a4,
- 0x1d4a7, 0x1d4a8,
- 0x1d4ad, 0x1d4ad,
- 0x1d4ba, 0x1d4ba,
- 0x1d4bc, 0x1d4bc,
- 0x1d4c4, 0x1d4c4,
- 0x1d506, 0x1d506,
- 0x1d50b, 0x1d50c,
- 0x1d515, 0x1d515,
- 0x1d51d, 0x1d51d,
- 0x1d53a, 0x1d53a,
- 0x1d53f, 0x1d53f,
- 0x1d545, 0x1d545,
- 0x1d547, 0x1d549,
- 0x1d551, 0x1d551,
- 0x1d6a6, 0x1d6a7,
- 0x1d7cc, 0x1d7cd,
- 0x1da8c, 0x1da9a,
- 0x1daa0, 0x1daa0,
- 0x1dab0, 0x1deff,
- 0x1df1f, 0x1df24,
- 0x1df2b, 0x1dfff,
- 0x1e007, 0x1e007,
- 0x1e019, 0x1e01a,
- 0x1e022, 0x1e022,
- 0x1e025, 0x1e025,
- 0x1e02b, 0x1e02f,
- 0x1e06e, 0x1e08e,
- 0x1e090, 0x1e0ff,
- 0x1e12d, 0x1e12f,
- 0x1e13e, 0x1e13f,
- 0x1e14a, 0x1e14d,
- 0x1e150, 0x1e28f,
- 0x1e2af, 0x1e2bf,
- 0x1e2fa, 0x1e2fe,
- 0x1e300, 0x1e4cf,
- 0x1e4fa, 0x1e7df,
- 0x1e7e7, 0x1e7e7,
- 0x1e7ec, 0x1e7ec,
- 0x1e7ef, 0x1e7ef,
- 0x1e7ff, 0x1e7ff,
- 0x1e8c5, 0x1e8c6,
- 0x1e8d7, 0x1e8ff,
- 0x1e94c, 0x1e94f,
- 0x1e95a, 0x1e95d,
- 0x1e960, 0x1ec70,
- 0x1ecb5, 0x1ed00,
- 0x1ed3e, 0x1edff,
- 0x1ee04, 0x1ee04,
- 0x1ee20, 0x1ee20,
- 0x1ee23, 0x1ee23,
- 0x1ee25, 0x1ee26,
- 0x1ee28, 0x1ee28,
- 0x1ee33, 0x1ee33,
- 0x1ee38, 0x1ee38,
- 0x1ee3a, 0x1ee3a,
- 0x1ee3c, 0x1ee41,
- 0x1ee43, 0x1ee46,
- 0x1ee48, 0x1ee48,
- 0x1ee4a, 0x1ee4a,
- 0x1ee4c, 0x1ee4c,
- 0x1ee50, 0x1ee50,
- 0x1ee53, 0x1ee53,
- 0x1ee55, 0x1ee56,
- 0x1ee58, 0x1ee58,
- 0x1ee5a, 0x1ee5a,
- 0x1ee5c, 0x1ee5c,
- 0x1ee5e, 0x1ee5e,
- 0x1ee60, 0x1ee60,
- 0x1ee63, 0x1ee63,
- 0x1ee65, 0x1ee66,
- 0x1ee6b, 0x1ee6b,
- 0x1ee73, 0x1ee73,
- 0x1ee78, 0x1ee78,
- 0x1ee7d, 0x1ee7d,
- 0x1ee7f, 0x1ee7f,
- 0x1ee8a, 0x1ee8a,
- 0x1ee9c, 0x1eea0,
- 0x1eea4, 0x1eea4,
- 0x1eeaa, 0x1eeaa,
- 0x1eebc, 0x1eeef,
- 0x1eef2, 0x1efff,
- 0x1f02c, 0x1f02f,
- 0x1f094, 0x1f09f,
- 0x1f0af, 0x1f0b0,
- 0x1f0c0, 0x1f0c0,
- 0x1f0d0, 0x1f0d0,
- 0x1f0f6, 0x1f0ff,
- 0x1f1ae, 0x1f1e5,
- 0x1f203, 0x1f20f,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f24f,
- 0x1f252, 0x1f25f,
- 0x1f266, 0x1f2ff,
- 0x1f6d8, 0x1f6db,
- 0x1f6ed, 0x1f6ef,
- 0x1f6fd, 0x1f6ff,
- 0x1f777, 0x1f77a,
- 0x1f7da, 0x1f7df,
- 0x1f7ec, 0x1f7ef,
- 0x1f7f1, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8af,
- 0x1f8b2, 0x1f8ff,
- 0x1fa54, 0x1fa5f,
- 0x1fa6e, 0x1fa6f,
- 0x1fa7d, 0x1fa7f,
- 0x1fa89, 0x1fa8f,
- 0x1fabe, 0x1fabe,
- 0x1fac6, 0x1facd,
- 0x1fadc, 0x1fadf,
- 0x1fae9, 0x1faef,
- 0x1faf9, 0x1faff,
- 0x1fb93, 0x1fb93,
- 0x1fbcb, 0x1fbef,
- 0x1fbfa, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2b73a, 0x2b73f,
- 0x2b81e, 0x2b81f,
- 0x2cea2, 0x2ceaf,
- 0x2ebe1, 0x2ebef,
- 0x2ee5e, 0x2f7ff,
- 0x2fa1e, 0x2ffff,
- 0x3134b, 0x3134f,
- 0x323b0, 0xe00ff,
- 0xe01f0, 0x10ffff,
-}; /* CR_C */
-
-/* 'Cc': General Category */
-#define CR_Cc CR_Cntrl
-
-/* 'Cf': General Category */
-static const OnigCodePoint CR_Cf[] = {
- 21,
- 0x00ad, 0x00ad,
- 0x0600, 0x0605,
- 0x061c, 0x061c,
- 0x06dd, 0x06dd,
- 0x070f, 0x070f,
- 0x0890, 0x0891,
- 0x08e2, 0x08e2,
- 0x180e, 0x180e,
- 0x200b, 0x200f,
- 0x202a, 0x202e,
- 0x2060, 0x2064,
- 0x2066, 0x206f,
- 0xfeff, 0xfeff,
- 0xfff9, 0xfffb,
- 0x110bd, 0x110bd,
- 0x110cd, 0x110cd,
- 0x13430, 0x1343f,
- 0x1bca0, 0x1bca3,
- 0x1d173, 0x1d17a,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
-}; /* CR_Cf */
-
-/* 'Cn': General Category */
-static const OnigCodePoint CR_Cn[] = {
- 707,
- 0x0378, 0x0379,
- 0x0380, 0x0383,
- 0x038b, 0x038b,
- 0x038d, 0x038d,
- 0x03a2, 0x03a2,
- 0x0530, 0x0530,
- 0x0557, 0x0558,
- 0x058b, 0x058c,
- 0x0590, 0x0590,
- 0x05c8, 0x05cf,
- 0x05eb, 0x05ee,
- 0x05f5, 0x05ff,
- 0x070e, 0x070e,
- 0x074b, 0x074c,
- 0x07b2, 0x07bf,
- 0x07fb, 0x07fc,
- 0x082e, 0x082f,
- 0x083f, 0x083f,
- 0x085c, 0x085d,
- 0x085f, 0x085f,
- 0x086b, 0x086f,
- 0x088f, 0x088f,
- 0x0892, 0x0897,
- 0x0984, 0x0984,
- 0x098d, 0x098e,
- 0x0991, 0x0992,
- 0x09a9, 0x09a9,
- 0x09b1, 0x09b1,
- 0x09b3, 0x09b5,
- 0x09ba, 0x09bb,
- 0x09c5, 0x09c6,
- 0x09c9, 0x09ca,
- 0x09cf, 0x09d6,
- 0x09d8, 0x09db,
- 0x09de, 0x09de,
- 0x09e4, 0x09e5,
- 0x09ff, 0x0a00,
- 0x0a04, 0x0a04,
- 0x0a0b, 0x0a0e,
- 0x0a11, 0x0a12,
- 0x0a29, 0x0a29,
- 0x0a31, 0x0a31,
- 0x0a34, 0x0a34,
- 0x0a37, 0x0a37,
- 0x0a3a, 0x0a3b,
- 0x0a3d, 0x0a3d,
- 0x0a43, 0x0a46,
- 0x0a49, 0x0a4a,
- 0x0a4e, 0x0a50,
- 0x0a52, 0x0a58,
- 0x0a5d, 0x0a5d,
- 0x0a5f, 0x0a65,
- 0x0a77, 0x0a80,
- 0x0a84, 0x0a84,
- 0x0a8e, 0x0a8e,
- 0x0a92, 0x0a92,
- 0x0aa9, 0x0aa9,
- 0x0ab1, 0x0ab1,
- 0x0ab4, 0x0ab4,
- 0x0aba, 0x0abb,
- 0x0ac6, 0x0ac6,
- 0x0aca, 0x0aca,
- 0x0ace, 0x0acf,
- 0x0ad1, 0x0adf,
- 0x0ae4, 0x0ae5,
- 0x0af2, 0x0af8,
- 0x0b00, 0x0b00,
- 0x0b04, 0x0b04,
- 0x0b0d, 0x0b0e,
- 0x0b11, 0x0b12,
- 0x0b29, 0x0b29,
- 0x0b31, 0x0b31,
- 0x0b34, 0x0b34,
- 0x0b3a, 0x0b3b,
- 0x0b45, 0x0b46,
- 0x0b49, 0x0b4a,
- 0x0b4e, 0x0b54,
- 0x0b58, 0x0b5b,
- 0x0b5e, 0x0b5e,
- 0x0b64, 0x0b65,
- 0x0b78, 0x0b81,
- 0x0b84, 0x0b84,
- 0x0b8b, 0x0b8d,
- 0x0b91, 0x0b91,
- 0x0b96, 0x0b98,
- 0x0b9b, 0x0b9b,
- 0x0b9d, 0x0b9d,
- 0x0ba0, 0x0ba2,
- 0x0ba5, 0x0ba7,
- 0x0bab, 0x0bad,
- 0x0bba, 0x0bbd,
- 0x0bc3, 0x0bc5,
- 0x0bc9, 0x0bc9,
- 0x0bce, 0x0bcf,
- 0x0bd1, 0x0bd6,
- 0x0bd8, 0x0be5,
- 0x0bfb, 0x0bff,
- 0x0c0d, 0x0c0d,
- 0x0c11, 0x0c11,
- 0x0c29, 0x0c29,
- 0x0c3a, 0x0c3b,
- 0x0c45, 0x0c45,
- 0x0c49, 0x0c49,
- 0x0c4e, 0x0c54,
- 0x0c57, 0x0c57,
- 0x0c5b, 0x0c5c,
- 0x0c5e, 0x0c5f,
- 0x0c64, 0x0c65,
- 0x0c70, 0x0c76,
- 0x0c8d, 0x0c8d,
- 0x0c91, 0x0c91,
- 0x0ca9, 0x0ca9,
- 0x0cb4, 0x0cb4,
- 0x0cba, 0x0cbb,
- 0x0cc5, 0x0cc5,
- 0x0cc9, 0x0cc9,
- 0x0cce, 0x0cd4,
- 0x0cd7, 0x0cdc,
- 0x0cdf, 0x0cdf,
- 0x0ce4, 0x0ce5,
- 0x0cf0, 0x0cf0,
- 0x0cf4, 0x0cff,
- 0x0d0d, 0x0d0d,
- 0x0d11, 0x0d11,
- 0x0d45, 0x0d45,
- 0x0d49, 0x0d49,
- 0x0d50, 0x0d53,
- 0x0d64, 0x0d65,
- 0x0d80, 0x0d80,
- 0x0d84, 0x0d84,
- 0x0d97, 0x0d99,
- 0x0db2, 0x0db2,
- 0x0dbc, 0x0dbc,
- 0x0dbe, 0x0dbf,
- 0x0dc7, 0x0dc9,
- 0x0dcb, 0x0dce,
- 0x0dd5, 0x0dd5,
- 0x0dd7, 0x0dd7,
- 0x0de0, 0x0de5,
- 0x0df0, 0x0df1,
- 0x0df5, 0x0e00,
- 0x0e3b, 0x0e3e,
- 0x0e5c, 0x0e80,
- 0x0e83, 0x0e83,
- 0x0e85, 0x0e85,
- 0x0e8b, 0x0e8b,
- 0x0ea4, 0x0ea4,
- 0x0ea6, 0x0ea6,
- 0x0ebe, 0x0ebf,
- 0x0ec5, 0x0ec5,
- 0x0ec7, 0x0ec7,
- 0x0ecf, 0x0ecf,
- 0x0eda, 0x0edb,
- 0x0ee0, 0x0eff,
- 0x0f48, 0x0f48,
- 0x0f6d, 0x0f70,
- 0x0f98, 0x0f98,
- 0x0fbd, 0x0fbd,
- 0x0fcd, 0x0fcd,
- 0x0fdb, 0x0fff,
- 0x10c6, 0x10c6,
- 0x10c8, 0x10cc,
- 0x10ce, 0x10cf,
- 0x1249, 0x1249,
- 0x124e, 0x124f,
- 0x1257, 0x1257,
- 0x1259, 0x1259,
- 0x125e, 0x125f,
- 0x1289, 0x1289,
- 0x128e, 0x128f,
- 0x12b1, 0x12b1,
- 0x12b6, 0x12b7,
- 0x12bf, 0x12bf,
- 0x12c1, 0x12c1,
- 0x12c6, 0x12c7,
- 0x12d7, 0x12d7,
- 0x1311, 0x1311,
- 0x1316, 0x1317,
- 0x135b, 0x135c,
- 0x137d, 0x137f,
- 0x139a, 0x139f,
- 0x13f6, 0x13f7,
- 0x13fe, 0x13ff,
- 0x169d, 0x169f,
- 0x16f9, 0x16ff,
- 0x1716, 0x171e,
- 0x1737, 0x173f,
- 0x1754, 0x175f,
- 0x176d, 0x176d,
- 0x1771, 0x1771,
- 0x1774, 0x177f,
- 0x17de, 0x17df,
- 0x17ea, 0x17ef,
- 0x17fa, 0x17ff,
- 0x181a, 0x181f,
- 0x1879, 0x187f,
- 0x18ab, 0x18af,
- 0x18f6, 0x18ff,
- 0x191f, 0x191f,
- 0x192c, 0x192f,
- 0x193c, 0x193f,
- 0x1941, 0x1943,
- 0x196e, 0x196f,
- 0x1975, 0x197f,
- 0x19ac, 0x19af,
- 0x19ca, 0x19cf,
- 0x19db, 0x19dd,
- 0x1a1c, 0x1a1d,
- 0x1a5f, 0x1a5f,
- 0x1a7d, 0x1a7e,
- 0x1a8a, 0x1a8f,
- 0x1a9a, 0x1a9f,
- 0x1aae, 0x1aaf,
- 0x1acf, 0x1aff,
- 0x1b4d, 0x1b4f,
- 0x1b7f, 0x1b7f,
- 0x1bf4, 0x1bfb,
- 0x1c38, 0x1c3a,
- 0x1c4a, 0x1c4c,
- 0x1c89, 0x1c8f,
- 0x1cbb, 0x1cbc,
- 0x1cc8, 0x1ccf,
- 0x1cfb, 0x1cff,
- 0x1f16, 0x1f17,
- 0x1f1e, 0x1f1f,
- 0x1f46, 0x1f47,
- 0x1f4e, 0x1f4f,
- 0x1f58, 0x1f58,
- 0x1f5a, 0x1f5a,
- 0x1f5c, 0x1f5c,
- 0x1f5e, 0x1f5e,
- 0x1f7e, 0x1f7f,
- 0x1fb5, 0x1fb5,
- 0x1fc5, 0x1fc5,
- 0x1fd4, 0x1fd5,
- 0x1fdc, 0x1fdc,
- 0x1ff0, 0x1ff1,
- 0x1ff5, 0x1ff5,
- 0x1fff, 0x1fff,
- 0x2065, 0x2065,
- 0x2072, 0x2073,
- 0x208f, 0x208f,
- 0x209d, 0x209f,
- 0x20c1, 0x20cf,
- 0x20f1, 0x20ff,
- 0x218c, 0x218f,
- 0x2427, 0x243f,
- 0x244b, 0x245f,
- 0x2b74, 0x2b75,
- 0x2b96, 0x2b96,
- 0x2cf4, 0x2cf8,
- 0x2d26, 0x2d26,
- 0x2d28, 0x2d2c,
- 0x2d2e, 0x2d2f,
- 0x2d68, 0x2d6e,
- 0x2d71, 0x2d7e,
- 0x2d97, 0x2d9f,
- 0x2da7, 0x2da7,
- 0x2daf, 0x2daf,
- 0x2db7, 0x2db7,
- 0x2dbf, 0x2dbf,
- 0x2dc7, 0x2dc7,
- 0x2dcf, 0x2dcf,
- 0x2dd7, 0x2dd7,
- 0x2ddf, 0x2ddf,
- 0x2e5e, 0x2e7f,
- 0x2e9a, 0x2e9a,
- 0x2ef4, 0x2eff,
- 0x2fd6, 0x2fef,
- 0x3040, 0x3040,
- 0x3097, 0x3098,
- 0x3100, 0x3104,
- 0x3130, 0x3130,
- 0x318f, 0x318f,
- 0x31e4, 0x31ee,
- 0x321f, 0x321f,
- 0xa48d, 0xa48f,
- 0xa4c7, 0xa4cf,
- 0xa62c, 0xa63f,
- 0xa6f8, 0xa6ff,
- 0xa7cb, 0xa7cf,
- 0xa7d2, 0xa7d2,
- 0xa7d4, 0xa7d4,
- 0xa7da, 0xa7f1,
- 0xa82d, 0xa82f,
- 0xa83a, 0xa83f,
- 0xa878, 0xa87f,
- 0xa8c6, 0xa8cd,
- 0xa8da, 0xa8df,
- 0xa954, 0xa95e,
- 0xa97d, 0xa97f,
- 0xa9ce, 0xa9ce,
- 0xa9da, 0xa9dd,
- 0xa9ff, 0xa9ff,
- 0xaa37, 0xaa3f,
- 0xaa4e, 0xaa4f,
- 0xaa5a, 0xaa5b,
- 0xaac3, 0xaada,
- 0xaaf7, 0xab00,
- 0xab07, 0xab08,
- 0xab0f, 0xab10,
- 0xab17, 0xab1f,
- 0xab27, 0xab27,
- 0xab2f, 0xab2f,
- 0xab6c, 0xab6f,
- 0xabee, 0xabef,
- 0xabfa, 0xabff,
- 0xd7a4, 0xd7af,
- 0xd7c7, 0xd7ca,
- 0xd7fc, 0xd7ff,
- 0xfa6e, 0xfa6f,
- 0xfada, 0xfaff,
- 0xfb07, 0xfb12,
- 0xfb18, 0xfb1c,
- 0xfb37, 0xfb37,
- 0xfb3d, 0xfb3d,
- 0xfb3f, 0xfb3f,
- 0xfb42, 0xfb42,
- 0xfb45, 0xfb45,
- 0xfbc3, 0xfbd2,
- 0xfd90, 0xfd91,
- 0xfdc8, 0xfdce,
- 0xfdd0, 0xfdef,
- 0xfe1a, 0xfe1f,
- 0xfe53, 0xfe53,
- 0xfe67, 0xfe67,
- 0xfe6c, 0xfe6f,
- 0xfe75, 0xfe75,
- 0xfefd, 0xfefe,
- 0xff00, 0xff00,
- 0xffbf, 0xffc1,
- 0xffc8, 0xffc9,
- 0xffd0, 0xffd1,
- 0xffd8, 0xffd9,
- 0xffdd, 0xffdf,
- 0xffe7, 0xffe7,
- 0xffef, 0xfff8,
- 0xfffe, 0xffff,
- 0x1000c, 0x1000c,
- 0x10027, 0x10027,
- 0x1003b, 0x1003b,
- 0x1003e, 0x1003e,
- 0x1004e, 0x1004f,
- 0x1005e, 0x1007f,
- 0x100fb, 0x100ff,
- 0x10103, 0x10106,
- 0x10134, 0x10136,
- 0x1018f, 0x1018f,
- 0x1019d, 0x1019f,
- 0x101a1, 0x101cf,
- 0x101fe, 0x1027f,
- 0x1029d, 0x1029f,
- 0x102d1, 0x102df,
- 0x102fc, 0x102ff,
- 0x10324, 0x1032c,
- 0x1034b, 0x1034f,
- 0x1037b, 0x1037f,
- 0x1039e, 0x1039e,
- 0x103c4, 0x103c7,
- 0x103d6, 0x103ff,
- 0x1049e, 0x1049f,
- 0x104aa, 0x104af,
- 0x104d4, 0x104d7,
- 0x104fc, 0x104ff,
- 0x10528, 0x1052f,
- 0x10564, 0x1056e,
- 0x1057b, 0x1057b,
- 0x1058b, 0x1058b,
- 0x10593, 0x10593,
- 0x10596, 0x10596,
- 0x105a2, 0x105a2,
- 0x105b2, 0x105b2,
- 0x105ba, 0x105ba,
- 0x105bd, 0x105ff,
- 0x10737, 0x1073f,
- 0x10756, 0x1075f,
- 0x10768, 0x1077f,
- 0x10786, 0x10786,
- 0x107b1, 0x107b1,
- 0x107bb, 0x107ff,
- 0x10806, 0x10807,
- 0x10809, 0x10809,
- 0x10836, 0x10836,
- 0x10839, 0x1083b,
- 0x1083d, 0x1083e,
- 0x10856, 0x10856,
- 0x1089f, 0x108a6,
- 0x108b0, 0x108df,
- 0x108f3, 0x108f3,
- 0x108f6, 0x108fa,
- 0x1091c, 0x1091e,
- 0x1093a, 0x1093e,
- 0x10940, 0x1097f,
- 0x109b8, 0x109bb,
- 0x109d0, 0x109d1,
- 0x10a04, 0x10a04,
- 0x10a07, 0x10a0b,
- 0x10a14, 0x10a14,
- 0x10a18, 0x10a18,
- 0x10a36, 0x10a37,
- 0x10a3b, 0x10a3e,
- 0x10a49, 0x10a4f,
- 0x10a59, 0x10a5f,
- 0x10aa0, 0x10abf,
- 0x10ae7, 0x10aea,
- 0x10af7, 0x10aff,
- 0x10b36, 0x10b38,
- 0x10b56, 0x10b57,
- 0x10b73, 0x10b77,
- 0x10b92, 0x10b98,
- 0x10b9d, 0x10ba8,
- 0x10bb0, 0x10bff,
- 0x10c49, 0x10c7f,
- 0x10cb3, 0x10cbf,
- 0x10cf3, 0x10cf9,
- 0x10d28, 0x10d2f,
- 0x10d3a, 0x10e5f,
- 0x10e7f, 0x10e7f,
- 0x10eaa, 0x10eaa,
- 0x10eae, 0x10eaf,
- 0x10eb2, 0x10efc,
- 0x10f28, 0x10f2f,
- 0x10f5a, 0x10f6f,
- 0x10f8a, 0x10faf,
- 0x10fcc, 0x10fdf,
- 0x10ff7, 0x10fff,
- 0x1104e, 0x11051,
- 0x11076, 0x1107e,
- 0x110c3, 0x110cc,
- 0x110ce, 0x110cf,
- 0x110e9, 0x110ef,
- 0x110fa, 0x110ff,
- 0x11135, 0x11135,
- 0x11148, 0x1114f,
- 0x11177, 0x1117f,
- 0x111e0, 0x111e0,
- 0x111f5, 0x111ff,
- 0x11212, 0x11212,
- 0x11242, 0x1127f,
- 0x11287, 0x11287,
- 0x11289, 0x11289,
- 0x1128e, 0x1128e,
- 0x1129e, 0x1129e,
- 0x112aa, 0x112af,
- 0x112eb, 0x112ef,
- 0x112fa, 0x112ff,
- 0x11304, 0x11304,
- 0x1130d, 0x1130e,
- 0x11311, 0x11312,
- 0x11329, 0x11329,
- 0x11331, 0x11331,
- 0x11334, 0x11334,
- 0x1133a, 0x1133a,
- 0x11345, 0x11346,
- 0x11349, 0x1134a,
- 0x1134e, 0x1134f,
- 0x11351, 0x11356,
- 0x11358, 0x1135c,
- 0x11364, 0x11365,
- 0x1136d, 0x1136f,
- 0x11375, 0x113ff,
- 0x1145c, 0x1145c,
- 0x11462, 0x1147f,
- 0x114c8, 0x114cf,
- 0x114da, 0x1157f,
- 0x115b6, 0x115b7,
- 0x115de, 0x115ff,
- 0x11645, 0x1164f,
- 0x1165a, 0x1165f,
- 0x1166d, 0x1167f,
- 0x116ba, 0x116bf,
- 0x116ca, 0x116ff,
- 0x1171b, 0x1171c,
- 0x1172c, 0x1172f,
- 0x11747, 0x117ff,
- 0x1183c, 0x1189f,
- 0x118f3, 0x118fe,
- 0x11907, 0x11908,
- 0x1190a, 0x1190b,
- 0x11914, 0x11914,
- 0x11917, 0x11917,
- 0x11936, 0x11936,
- 0x11939, 0x1193a,
- 0x11947, 0x1194f,
- 0x1195a, 0x1199f,
- 0x119a8, 0x119a9,
- 0x119d8, 0x119d9,
- 0x119e5, 0x119ff,
- 0x11a48, 0x11a4f,
- 0x11aa3, 0x11aaf,
- 0x11af9, 0x11aff,
- 0x11b0a, 0x11bff,
- 0x11c09, 0x11c09,
- 0x11c37, 0x11c37,
- 0x11c46, 0x11c4f,
- 0x11c6d, 0x11c6f,
- 0x11c90, 0x11c91,
- 0x11ca8, 0x11ca8,
- 0x11cb7, 0x11cff,
- 0x11d07, 0x11d07,
- 0x11d0a, 0x11d0a,
- 0x11d37, 0x11d39,
- 0x11d3b, 0x11d3b,
- 0x11d3e, 0x11d3e,
- 0x11d48, 0x11d4f,
- 0x11d5a, 0x11d5f,
- 0x11d66, 0x11d66,
- 0x11d69, 0x11d69,
- 0x11d8f, 0x11d8f,
- 0x11d92, 0x11d92,
- 0x11d99, 0x11d9f,
- 0x11daa, 0x11edf,
- 0x11ef9, 0x11eff,
- 0x11f11, 0x11f11,
- 0x11f3b, 0x11f3d,
- 0x11f5a, 0x11faf,
- 0x11fb1, 0x11fbf,
- 0x11ff2, 0x11ffe,
- 0x1239a, 0x123ff,
- 0x1246f, 0x1246f,
- 0x12475, 0x1247f,
- 0x12544, 0x12f8f,
- 0x12ff3, 0x12fff,
- 0x13456, 0x143ff,
- 0x14647, 0x167ff,
- 0x16a39, 0x16a3f,
- 0x16a5f, 0x16a5f,
- 0x16a6a, 0x16a6d,
- 0x16abf, 0x16abf,
- 0x16aca, 0x16acf,
- 0x16aee, 0x16aef,
- 0x16af6, 0x16aff,
- 0x16b46, 0x16b4f,
- 0x16b5a, 0x16b5a,
- 0x16b62, 0x16b62,
- 0x16b78, 0x16b7c,
- 0x16b90, 0x16e3f,
- 0x16e9b, 0x16eff,
- 0x16f4b, 0x16f4e,
- 0x16f88, 0x16f8e,
- 0x16fa0, 0x16fdf,
- 0x16fe5, 0x16fef,
- 0x16ff2, 0x16fff,
- 0x187f8, 0x187ff,
- 0x18cd6, 0x18cff,
- 0x18d09, 0x1afef,
- 0x1aff4, 0x1aff4,
- 0x1affc, 0x1affc,
- 0x1afff, 0x1afff,
- 0x1b123, 0x1b131,
- 0x1b133, 0x1b14f,
- 0x1b153, 0x1b154,
- 0x1b156, 0x1b163,
- 0x1b168, 0x1b16f,
- 0x1b2fc, 0x1bbff,
- 0x1bc6b, 0x1bc6f,
- 0x1bc7d, 0x1bc7f,
- 0x1bc89, 0x1bc8f,
- 0x1bc9a, 0x1bc9b,
- 0x1bca4, 0x1ceff,
- 0x1cf2e, 0x1cf2f,
- 0x1cf47, 0x1cf4f,
- 0x1cfc4, 0x1cfff,
- 0x1d0f6, 0x1d0ff,
- 0x1d127, 0x1d128,
- 0x1d1eb, 0x1d1ff,
- 0x1d246, 0x1d2bf,
- 0x1d2d4, 0x1d2df,
- 0x1d2f4, 0x1d2ff,
- 0x1d357, 0x1d35f,
- 0x1d379, 0x1d3ff,
- 0x1d455, 0x1d455,
- 0x1d49d, 0x1d49d,
- 0x1d4a0, 0x1d4a1,
- 0x1d4a3, 0x1d4a4,
- 0x1d4a7, 0x1d4a8,
- 0x1d4ad, 0x1d4ad,
- 0x1d4ba, 0x1d4ba,
- 0x1d4bc, 0x1d4bc,
- 0x1d4c4, 0x1d4c4,
- 0x1d506, 0x1d506,
- 0x1d50b, 0x1d50c,
- 0x1d515, 0x1d515,
- 0x1d51d, 0x1d51d,
- 0x1d53a, 0x1d53a,
- 0x1d53f, 0x1d53f,
- 0x1d545, 0x1d545,
- 0x1d547, 0x1d549,
- 0x1d551, 0x1d551,
- 0x1d6a6, 0x1d6a7,
- 0x1d7cc, 0x1d7cd,
- 0x1da8c, 0x1da9a,
- 0x1daa0, 0x1daa0,
- 0x1dab0, 0x1deff,
- 0x1df1f, 0x1df24,
- 0x1df2b, 0x1dfff,
- 0x1e007, 0x1e007,
- 0x1e019, 0x1e01a,
- 0x1e022, 0x1e022,
- 0x1e025, 0x1e025,
- 0x1e02b, 0x1e02f,
- 0x1e06e, 0x1e08e,
- 0x1e090, 0x1e0ff,
- 0x1e12d, 0x1e12f,
- 0x1e13e, 0x1e13f,
- 0x1e14a, 0x1e14d,
- 0x1e150, 0x1e28f,
- 0x1e2af, 0x1e2bf,
- 0x1e2fa, 0x1e2fe,
- 0x1e300, 0x1e4cf,
- 0x1e4fa, 0x1e7df,
- 0x1e7e7, 0x1e7e7,
- 0x1e7ec, 0x1e7ec,
- 0x1e7ef, 0x1e7ef,
- 0x1e7ff, 0x1e7ff,
- 0x1e8c5, 0x1e8c6,
- 0x1e8d7, 0x1e8ff,
- 0x1e94c, 0x1e94f,
- 0x1e95a, 0x1e95d,
- 0x1e960, 0x1ec70,
- 0x1ecb5, 0x1ed00,
- 0x1ed3e, 0x1edff,
- 0x1ee04, 0x1ee04,
- 0x1ee20, 0x1ee20,
- 0x1ee23, 0x1ee23,
- 0x1ee25, 0x1ee26,
- 0x1ee28, 0x1ee28,
- 0x1ee33, 0x1ee33,
- 0x1ee38, 0x1ee38,
- 0x1ee3a, 0x1ee3a,
- 0x1ee3c, 0x1ee41,
- 0x1ee43, 0x1ee46,
- 0x1ee48, 0x1ee48,
- 0x1ee4a, 0x1ee4a,
- 0x1ee4c, 0x1ee4c,
- 0x1ee50, 0x1ee50,
- 0x1ee53, 0x1ee53,
- 0x1ee55, 0x1ee56,
- 0x1ee58, 0x1ee58,
- 0x1ee5a, 0x1ee5a,
- 0x1ee5c, 0x1ee5c,
- 0x1ee5e, 0x1ee5e,
- 0x1ee60, 0x1ee60,
- 0x1ee63, 0x1ee63,
- 0x1ee65, 0x1ee66,
- 0x1ee6b, 0x1ee6b,
- 0x1ee73, 0x1ee73,
- 0x1ee78, 0x1ee78,
- 0x1ee7d, 0x1ee7d,
- 0x1ee7f, 0x1ee7f,
- 0x1ee8a, 0x1ee8a,
- 0x1ee9c, 0x1eea0,
- 0x1eea4, 0x1eea4,
- 0x1eeaa, 0x1eeaa,
- 0x1eebc, 0x1eeef,
- 0x1eef2, 0x1efff,
- 0x1f02c, 0x1f02f,
- 0x1f094, 0x1f09f,
- 0x1f0af, 0x1f0b0,
- 0x1f0c0, 0x1f0c0,
- 0x1f0d0, 0x1f0d0,
- 0x1f0f6, 0x1f0ff,
- 0x1f1ae, 0x1f1e5,
- 0x1f203, 0x1f20f,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f24f,
- 0x1f252, 0x1f25f,
- 0x1f266, 0x1f2ff,
- 0x1f6d8, 0x1f6db,
- 0x1f6ed, 0x1f6ef,
- 0x1f6fd, 0x1f6ff,
- 0x1f777, 0x1f77a,
- 0x1f7da, 0x1f7df,
- 0x1f7ec, 0x1f7ef,
- 0x1f7f1, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8af,
- 0x1f8b2, 0x1f8ff,
- 0x1fa54, 0x1fa5f,
- 0x1fa6e, 0x1fa6f,
- 0x1fa7d, 0x1fa7f,
- 0x1fa89, 0x1fa8f,
- 0x1fabe, 0x1fabe,
- 0x1fac6, 0x1facd,
- 0x1fadc, 0x1fadf,
- 0x1fae9, 0x1faef,
- 0x1faf9, 0x1faff,
- 0x1fb93, 0x1fb93,
- 0x1fbcb, 0x1fbef,
- 0x1fbfa, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2b73a, 0x2b73f,
- 0x2b81e, 0x2b81f,
- 0x2cea2, 0x2ceaf,
- 0x2ebe1, 0x2ebef,
- 0x2ee5e, 0x2f7ff,
- 0x2fa1e, 0x2ffff,
- 0x3134b, 0x3134f,
- 0x323b0, 0xe0000,
- 0xe0002, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xeffff,
- 0xffffe, 0xfffff,
- 0x10fffe, 0x10ffff,
-}; /* CR_Cn */
-
-/* 'Co': General Category */
-static const OnigCodePoint CR_Co[] = {
- 3,
- 0xe000, 0xf8ff,
- 0xf0000, 0xffffd,
- 0x100000, 0x10fffd,
-}; /* CR_Co */
-
-/* 'Cs': General Category */
-static const OnigCodePoint CR_Cs[] = {
- 1,
- 0xd800, 0xdfff,
-}; /* CR_Cs */
-
-/* 'L': Major Category */
-static const OnigCodePoint CR_L[] = {
- 660,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0971, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 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,
- 0x16f1, 0x16f8,
- 0x1700, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dc,
- 0x1820, 0x1878,
- 0x1880, 0x1884,
- 0x1887, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1aa7, 0x1aa7,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 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,
- 0x2183, 0x2184,
- 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,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3006,
- 0x3031, 0x3035,
- 0x303b, 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,
- 0xa67f, 0xa69d,
- 0xa6a0, 0xa6e5,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9cf, 0xa9cf,
- 0xa9e0, 0xa9e4,
- 0xa9e6, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf4,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 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,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031f,
- 0x1032d, 0x10340,
- 0x10342, 0x10349,
- 0x10350, 0x10375,
- 0x10380, 0x1039d,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103cf,
- 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, 0x10a00,
- 0x10a10, 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, 0x10d23,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118a0, 0x118df,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 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,
- 0x16f50, 0x16f50,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 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,
- 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,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4eb,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e900, 0x1e943,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_L */
-
-/* 'LC': General Category */
-static const OnigCodePoint CR_LC[] = {
- 143,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x01ba,
- 0x01bc, 0x01bf,
- 0x01c4, 0x0293,
- 0x0295, 0x02af,
- 0x0370, 0x0373,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0560, 0x0588,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1d00, 0x1d2b,
- 0x1d6b, 0x1d77,
- 0x1d79, 0x1d9a,
- 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,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x212d,
- 0x212f, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2183, 0x2184,
- 0x2c00, 0x2c7b,
- 0x2c7e, 0x2ce4,
- 0x2ceb, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa640, 0xa66d,
- 0xa680, 0xa69b,
- 0xa722, 0xa76f,
- 0xa771, 0xa787,
- 0xa78b, 0xa78e,
- 0xa790, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f5, 0xa7f6,
- 0xa7fa, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab60, 0xab68,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10400, 0x1044f,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x118a0, 0x118df,
- 0x16e40, 0x16e7f,
- 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, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e900, 0x1e943,
-}; /* CR_LC */
-
-/* 'Ll': General Category */
-static const OnigCodePoint CR_Ll[] = {
- 658,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0138,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018d,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019b,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01aa, 0x01ab,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01ba,
- 0x01bd, 0x01bf,
- 0x01c6, 0x01c6,
- 0x01c9, 0x01c9,
- 0x01cc, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f0,
- 0x01f3, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0221, 0x0221,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0239,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0293,
- 0x0295, 0x02af,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037b, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fc,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0560, 0x0588,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1d00, 0x1d2b,
- 0x1d6b, 0x1d77,
- 0x1d79, 0x1d9a,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9d,
- 0x1e9f, 0x1e9f,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x210a, 0x210a,
- 0x210e, 0x210f,
- 0x2113, 0x2113,
- 0x212f, 0x212f,
- 0x2134, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213d,
- 0x2146, 0x2149,
- 0x214e, 0x214e,
- 0x2184, 0x2184,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c71, 0x2c71,
- 0x2c73, 0x2c74,
- 0x2c76, 0x2c7b,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce4,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69b,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa731,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa76f,
- 0xa771, 0xa778,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa78e, 0xa78e,
- 0xa791, 0xa791,
- 0xa793, 0xa795,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7af, 0xa7af,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7d1, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d5,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7f6, 0xa7f6,
- 0xa7fa, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab60, 0xab68,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10cc0, 0x10cf2,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1d41a, 0x1d433,
- 0x1d44e, 0x1d454,
- 0x1d456, 0x1d467,
- 0x1d482, 0x1d49b,
- 0x1d4b6, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d4cf,
- 0x1d4ea, 0x1d503,
- 0x1d51e, 0x1d537,
- 0x1d552, 0x1d56b,
- 0x1d586, 0x1d59f,
- 0x1d5ba, 0x1d5d3,
- 0x1d5ee, 0x1d607,
- 0x1d622, 0x1d63b,
- 0x1d656, 0x1d66f,
- 0x1d68a, 0x1d6a5,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6e1,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d71b,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d755,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d78f,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7c9,
- 0x1d7cb, 0x1d7cb,
- 0x1df00, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e922, 0x1e943,
-}; /* CR_Ll */
-
-/* 'Lm': General Category */
-static const OnigCodePoint CR_Lm[] = {
- 71,
- 0x02b0, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0374, 0x0374,
- 0x037a, 0x037a,
- 0x0559, 0x0559,
- 0x0640, 0x0640,
- 0x06e5, 0x06e6,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x08c9, 0x08c9,
- 0x0971, 0x0971,
- 0x0e46, 0x0e46,
- 0x0ec6, 0x0ec6,
- 0x10fc, 0x10fc,
- 0x17d7, 0x17d7,
- 0x1843, 0x1843,
- 0x1aa7, 0x1aa7,
- 0x1c78, 0x1c7d,
- 0x1d2c, 0x1d6a,
- 0x1d78, 0x1d78,
- 0x1d9b, 0x1dbf,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x2c7c, 0x2c7d,
- 0x2d6f, 0x2d6f,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3005,
- 0x3031, 0x3035,
- 0x303b, 0x303b,
- 0x309d, 0x309e,
- 0x30fc, 0x30fe,
- 0xa015, 0xa015,
- 0xa4f8, 0xa4fd,
- 0xa60c, 0xa60c,
- 0xa67f, 0xa67f,
- 0xa69c, 0xa69d,
- 0xa717, 0xa71f,
- 0xa770, 0xa770,
- 0xa788, 0xa788,
- 0xa7f2, 0xa7f4,
- 0xa7f8, 0xa7f9,
- 0xa9cf, 0xa9cf,
- 0xa9e6, 0xa9e6,
- 0xaa70, 0xaa70,
- 0xaadd, 0xaadd,
- 0xaaf3, 0xaaf4,
- 0xab5c, 0xab5f,
- 0xab69, 0xab69,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x16b40, 0x16b43,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1e030, 0x1e06d,
- 0x1e137, 0x1e13d,
- 0x1e4eb, 0x1e4eb,
- 0x1e94b, 0x1e94b,
-}; /* CR_Lm */
-
-/* 'Lo': General Category */
-static const OnigCodePoint CR_Lo[] = {
- 511,
- 0x00aa, 0x00aa,
- 0x00ba, 0x00ba,
- 0x01bb, 0x01bb,
- 0x01c0, 0x01c3,
- 0x0294, 0x0294,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x063f,
- 0x0641, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x0800, 0x0815,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c8,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0972, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e45,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 0x1100, 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,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16f1, 0x16f8,
- 0x1700, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17dc, 0x17dc,
- 0x1820, 0x1842,
- 0x1844, 0x1878,
- 0x1880, 0x1884,
- 0x1887, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c77,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x2135, 0x2138,
- 0x2d30, 0x2d67,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x3006, 0x3006,
- 0x303c, 0x303c,
- 0x3041, 0x3096,
- 0x309f, 0x309f,
- 0x30a1, 0x30fa,
- 0x30ff, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x31a0, 0x31bf,
- 0x31f0, 0x31ff,
- 0x3400, 0x4dbf,
- 0x4e00, 0xa014,
- 0xa016, 0xa48c,
- 0xa4d0, 0xa4f7,
- 0xa500, 0xa60b,
- 0xa610, 0xa61f,
- 0xa62a, 0xa62b,
- 0xa66e, 0xa66e,
- 0xa6a0, 0xa6e5,
- 0xa78f, 0xa78f,
- 0xa7f7, 0xa7f7,
- 0xa7fb, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9e0, 0xa9e4,
- 0xa9e7, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa6f,
- 0xaa71, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadc,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf2,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 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,
- 0xff66, 0xff6f,
- 0xff71, 0xff9d,
- 0xffa0, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031f,
- 0x1032d, 0x10340,
- 0x10342, 0x10349,
- 0x10350, 0x10375,
- 0x10380, 0x1039d,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103cf,
- 0x10450, 0x1049d,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 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, 0x10a00,
- 0x10a10, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae4,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10d00, 0x10d23,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a70, 0x16abe,
- 0x16ad0, 0x16aed,
- 0x16b00, 0x16b2f,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f50,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18d00, 0x18d08,
- 0x1b000, 0x1b122,
- 0x1b132, 0x1b132,
- 0x1b150, 0x1b152,
- 0x1b155, 0x1b155,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1df0a, 0x1df0a,
- 0x1e100, 0x1e12c,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4ea,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Lo */
-
-/* 'Lt': General Category */
-static const OnigCodePoint CR_Lt[] = {
- 10,
- 0x01c5, 0x01c5,
- 0x01c8, 0x01c8,
- 0x01cb, 0x01cb,
- 0x01f2, 0x01f2,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fbc, 0x1fbc,
- 0x1fcc, 0x1fcc,
- 0x1ffc, 0x1ffc,
-}; /* CR_Lt */
-
-/* 'Lu': General Category */
-static const OnigCodePoint CR_Lu[] = {
- 646,
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x014a, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c4,
- 0x01c7, 0x01c7,
- 0x01ca, 0x01ca,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f1,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03cf, 0x03cf,
- 0x03d2, 0x03d4,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f4, 0x03f4,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 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,
- 0x2183, 0x2183,
- 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,
-}; /* CR_Lu */
-
-/* 'M': Major Category */
-static const OnigCodePoint CR_M[] = {
- 310,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0898, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0903,
- 0x093a, 0x093c,
- 0x093e, 0x094f,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0983,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0abc, 0x0abc,
- 0x0abe, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c83,
- 0x0cbc, 0x0cbc,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0cf3, 0x0cf3,
- 0x0d00, 0x0d03,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d83,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f3f,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102b, 0x103e,
- 0x1056, 0x1059,
- 0x105e, 0x1060,
- 0x1062, 0x1064,
- 0x1067, 0x106d,
- 0x1071, 0x1074,
- 0x1082, 0x108d,
- 0x108f, 0x108f,
- 0x109a, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1715,
- 0x1732, 0x1734,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1a17, 0x1a1b,
- 0x1a55, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b04,
- 0x1b34, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b82,
- 0x1ba1, 0x1bad,
- 0x1be6, 0x1bf3,
- 0x1c24, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf7, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa823, 0xa827,
- 0xa82c, 0xa82c,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa953,
- 0xa980, 0xa983,
- 0xa9b3, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4d,
- 0xaa7b, 0xaa7d,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaeb, 0xaaef,
- 0xaaf5, 0xaaf6,
- 0xabe3, 0xabea,
- 0xabec, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11000, 0x11002,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11082,
- 0x110b0, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x11134,
- 0x11145, 0x11146,
- 0x11173, 0x11173,
- 0x11180, 0x11182,
- 0x111b3, 0x111c0,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111cf,
- 0x1122c, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112ea,
- 0x11300, 0x11303,
- 0x1133b, 0x1133c,
- 0x1133e, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11357, 0x11357,
- 0x11362, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11435, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114c3,
- 0x115af, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11630, 0x11640,
- 0x116ab, 0x116b7,
- 0x1171d, 0x1172b,
- 0x1182c, 0x1183a,
- 0x11930, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x1193e,
- 0x11940, 0x11940,
- 0x11942, 0x11943,
- 0x119d1, 0x119d7,
- 0x119da, 0x119e0,
- 0x119e4, 0x119e4,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a39,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a5b,
- 0x11a8a, 0x11a99,
- 0x11c2f, 0x11c36,
- 0x11c38, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d8a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d97,
- 0x11ef3, 0x11ef6,
- 0x11f00, 0x11f01,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f51, 0x16f87,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0xe0100, 0xe01ef,
-}; /* CR_M */
-
-/* 'Mc': General Category */
-static const OnigCodePoint CR_Mc[] = {
- 182,
- 0x0903, 0x0903,
- 0x093b, 0x093b,
- 0x093e, 0x0940,
- 0x0949, 0x094c,
- 0x094e, 0x094f,
- 0x0982, 0x0983,
- 0x09be, 0x09c0,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09d7, 0x09d7,
- 0x0a03, 0x0a03,
- 0x0a3e, 0x0a40,
- 0x0a83, 0x0a83,
- 0x0abe, 0x0ac0,
- 0x0ac9, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0b02, 0x0b03,
- 0x0b3e, 0x0b3e,
- 0x0b40, 0x0b40,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b57, 0x0b57,
- 0x0bbe, 0x0bbf,
- 0x0bc1, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd7, 0x0bd7,
- 0x0c01, 0x0c03,
- 0x0c41, 0x0c44,
- 0x0c82, 0x0c83,
- 0x0cbe, 0x0cbe,
- 0x0cc0, 0x0cc4,
- 0x0cc7, 0x0cc8,
- 0x0cca, 0x0ccb,
- 0x0cd5, 0x0cd6,
- 0x0cf3, 0x0cf3,
- 0x0d02, 0x0d03,
- 0x0d3e, 0x0d40,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d57, 0x0d57,
- 0x0d82, 0x0d83,
- 0x0dcf, 0x0dd1,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0f3e, 0x0f3f,
- 0x0f7f, 0x0f7f,
- 0x102b, 0x102c,
- 0x1031, 0x1031,
- 0x1038, 0x1038,
- 0x103b, 0x103c,
- 0x1056, 0x1057,
- 0x1062, 0x1064,
- 0x1067, 0x106d,
- 0x1083, 0x1084,
- 0x1087, 0x108c,
- 0x108f, 0x108f,
- 0x109a, 0x109c,
- 0x1715, 0x1715,
- 0x1734, 0x1734,
- 0x17b6, 0x17b6,
- 0x17be, 0x17c5,
- 0x17c7, 0x17c8,
- 0x1923, 0x1926,
- 0x1929, 0x192b,
- 0x1930, 0x1931,
- 0x1933, 0x1938,
- 0x1a19, 0x1a1a,
- 0x1a55, 0x1a55,
- 0x1a57, 0x1a57,
- 0x1a61, 0x1a61,
- 0x1a63, 0x1a64,
- 0x1a6d, 0x1a72,
- 0x1b04, 0x1b04,
- 0x1b35, 0x1b35,
- 0x1b3b, 0x1b3b,
- 0x1b3d, 0x1b41,
- 0x1b43, 0x1b44,
- 0x1b82, 0x1b82,
- 0x1ba1, 0x1ba1,
- 0x1ba6, 0x1ba7,
- 0x1baa, 0x1baa,
- 0x1be7, 0x1be7,
- 0x1bea, 0x1bec,
- 0x1bee, 0x1bee,
- 0x1bf2, 0x1bf3,
- 0x1c24, 0x1c2b,
- 0x1c34, 0x1c35,
- 0x1ce1, 0x1ce1,
- 0x1cf7, 0x1cf7,
- 0x302e, 0x302f,
- 0xa823, 0xa824,
- 0xa827, 0xa827,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c3,
- 0xa952, 0xa953,
- 0xa983, 0xa983,
- 0xa9b4, 0xa9b5,
- 0xa9ba, 0xa9bb,
- 0xa9be, 0xa9c0,
- 0xaa2f, 0xaa30,
- 0xaa33, 0xaa34,
- 0xaa4d, 0xaa4d,
- 0xaa7b, 0xaa7b,
- 0xaa7d, 0xaa7d,
- 0xaaeb, 0xaaeb,
- 0xaaee, 0xaaef,
- 0xaaf5, 0xaaf5,
- 0xabe3, 0xabe4,
- 0xabe6, 0xabe7,
- 0xabe9, 0xabea,
- 0xabec, 0xabec,
- 0x11000, 0x11000,
- 0x11002, 0x11002,
- 0x11082, 0x11082,
- 0x110b0, 0x110b2,
- 0x110b7, 0x110b8,
- 0x1112c, 0x1112c,
- 0x11145, 0x11146,
- 0x11182, 0x11182,
- 0x111b3, 0x111b5,
- 0x111bf, 0x111c0,
- 0x111ce, 0x111ce,
- 0x1122c, 0x1122e,
- 0x11232, 0x11233,
- 0x11235, 0x11235,
- 0x112e0, 0x112e2,
- 0x11302, 0x11303,
- 0x1133e, 0x1133f,
- 0x11341, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11357, 0x11357,
- 0x11362, 0x11363,
- 0x11435, 0x11437,
- 0x11440, 0x11441,
- 0x11445, 0x11445,
- 0x114b0, 0x114b2,
- 0x114b9, 0x114b9,
- 0x114bb, 0x114be,
- 0x114c1, 0x114c1,
- 0x115af, 0x115b1,
- 0x115b8, 0x115bb,
- 0x115be, 0x115be,
- 0x11630, 0x11632,
- 0x1163b, 0x1163c,
- 0x1163e, 0x1163e,
- 0x116ac, 0x116ac,
- 0x116ae, 0x116af,
- 0x116b6, 0x116b6,
- 0x11720, 0x11721,
- 0x11726, 0x11726,
- 0x1182c, 0x1182e,
- 0x11838, 0x11838,
- 0x11930, 0x11935,
- 0x11937, 0x11938,
- 0x1193d, 0x1193d,
- 0x11940, 0x11940,
- 0x11942, 0x11942,
- 0x119d1, 0x119d3,
- 0x119dc, 0x119df,
- 0x119e4, 0x119e4,
- 0x11a39, 0x11a39,
- 0x11a57, 0x11a58,
- 0x11a97, 0x11a97,
- 0x11c2f, 0x11c2f,
- 0x11c3e, 0x11c3e,
- 0x11ca9, 0x11ca9,
- 0x11cb1, 0x11cb1,
- 0x11cb4, 0x11cb4,
- 0x11d8a, 0x11d8e,
- 0x11d93, 0x11d94,
- 0x11d96, 0x11d96,
- 0x11ef5, 0x11ef6,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f35,
- 0x11f3e, 0x11f3f,
- 0x11f41, 0x11f41,
- 0x16f51, 0x16f87,
- 0x16ff0, 0x16ff1,
- 0x1d165, 0x1d166,
- 0x1d16d, 0x1d172,
-}; /* CR_Mc */
-
-/* 'Me': General Category */
-static const OnigCodePoint CR_Me[] = {
- 5,
- 0x0488, 0x0489,
- 0x1abe, 0x1abe,
- 0x20dd, 0x20e0,
- 0x20e2, 0x20e4,
- 0xa670, 0xa672,
-}; /* CR_Me */
-
-/* 'Mn': General Category */
-static const OnigCodePoint CR_Mn[] = {
- 346,
- 0x0300, 0x036f,
- 0x0483, 0x0487,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0898, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3f, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b56,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cbf,
- 0x0cc6, 0x0cc6,
- 0x0ccc, 0x0ccd,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1714,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b34,
- 0x1b36, 0x1b3a,
- 0x1b3c, 0x1b3c,
- 0x1b42, 0x1b42,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1ba9,
- 0x1bab, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf1,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302d,
- 0x3099, 0x309a,
- 0xa66f, 0xa66f,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11234,
- 0x11236, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x11340, 0x11340,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b5,
- 0x116b7, 0x116b7,
- 0x1171d, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x1193b, 0x1193c,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f40,
- 0x11f42, 0x11f42,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0xe0100, 0xe01ef,
-}; /* CR_Mn */
-
-/* 'N': Major Category */
-static const OnigCodePoint CR_N[] = {
- 137,
- 0x0030, 0x0039,
- 0x00b2, 0x00b3,
- 0x00b9, 0x00b9,
- 0x00bc, 0x00be,
- 0x0660, 0x0669,
- 0x06f0, 0x06f9,
- 0x07c0, 0x07c9,
- 0x0966, 0x096f,
- 0x09e6, 0x09ef,
- 0x09f4, 0x09f9,
- 0x0a66, 0x0a6f,
- 0x0ae6, 0x0aef,
- 0x0b66, 0x0b6f,
- 0x0b72, 0x0b77,
- 0x0be6, 0x0bf2,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7e,
- 0x0ce6, 0x0cef,
- 0x0d58, 0x0d5e,
- 0x0d66, 0x0d78,
- 0x0de6, 0x0def,
- 0x0e50, 0x0e59,
- 0x0ed0, 0x0ed9,
- 0x0f20, 0x0f33,
- 0x1040, 0x1049,
- 0x1090, 0x1099,
- 0x1369, 0x137c,
- 0x16ee, 0x16f0,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1810, 0x1819,
- 0x1946, 0x194f,
- 0x19d0, 0x19da,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1b50, 0x1b59,
- 0x1bb0, 0x1bb9,
- 0x1c40, 0x1c49,
- 0x1c50, 0x1c59,
- 0x2070, 0x2070,
- 0x2074, 0x2079,
- 0x2080, 0x2089,
- 0x2150, 0x2182,
- 0x2185, 0x2189,
- 0x2460, 0x249b,
- 0x24ea, 0x24ff,
- 0x2776, 0x2793,
- 0x2cfd, 0x2cfd,
- 0x3007, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303a,
- 0x3192, 0x3195,
- 0x3220, 0x3229,
- 0x3248, 0x324f,
- 0x3251, 0x325f,
- 0x3280, 0x3289,
- 0x32b1, 0x32bf,
- 0xa620, 0xa629,
- 0xa6e6, 0xa6ef,
- 0xa830, 0xa835,
- 0xa8d0, 0xa8d9,
- 0xa900, 0xa909,
- 0xa9d0, 0xa9d9,
- 0xa9f0, 0xa9f9,
- 0xaa50, 0xaa59,
- 0xabf0, 0xabf9,
- 0xff10, 0xff19,
- 0x10107, 0x10133,
- 0x10140, 0x10178,
- 0x1018a, 0x1018b,
- 0x102e1, 0x102fb,
- 0x10320, 0x10323,
- 0x10341, 0x10341,
- 0x1034a, 0x1034a,
- 0x103d1, 0x103d5,
- 0x104a0, 0x104a9,
- 0x10858, 0x1085f,
- 0x10879, 0x1087f,
- 0x108a7, 0x108af,
- 0x108fb, 0x108ff,
- 0x10916, 0x1091b,
- 0x109bc, 0x109bd,
- 0x109c0, 0x109cf,
- 0x109d2, 0x109ff,
- 0x10a40, 0x10a48,
- 0x10a7d, 0x10a7e,
- 0x10a9d, 0x10a9f,
- 0x10aeb, 0x10aef,
- 0x10b58, 0x10b5f,
- 0x10b78, 0x10b7f,
- 0x10ba9, 0x10baf,
- 0x10cfa, 0x10cff,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f1d, 0x10f26,
- 0x10f51, 0x10f54,
- 0x10fc5, 0x10fcb,
- 0x11052, 0x1106f,
- 0x110f0, 0x110f9,
- 0x11136, 0x1113f,
- 0x111d0, 0x111d9,
- 0x111e1, 0x111f4,
- 0x112f0, 0x112f9,
- 0x11450, 0x11459,
- 0x114d0, 0x114d9,
- 0x11650, 0x11659,
- 0x116c0, 0x116c9,
- 0x11730, 0x1173b,
- 0x118e0, 0x118f2,
- 0x11950, 0x11959,
- 0x11c50, 0x11c6c,
- 0x11d50, 0x11d59,
- 0x11da0, 0x11da9,
- 0x11f50, 0x11f59,
- 0x11fc0, 0x11fd4,
- 0x12400, 0x1246e,
- 0x16a60, 0x16a69,
- 0x16ac0, 0x16ac9,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16e80, 0x16e96,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d360, 0x1d378,
- 0x1d7ce, 0x1d7ff,
- 0x1e140, 0x1e149,
- 0x1e2f0, 0x1e2f9,
- 0x1e4f0, 0x1e4f9,
- 0x1e8c7, 0x1e8cf,
- 0x1e950, 0x1e959,
- 0x1ec71, 0x1ecab,
- 0x1ecad, 0x1ecaf,
- 0x1ecb1, 0x1ecb4,
- 0x1ed01, 0x1ed2d,
- 0x1ed2f, 0x1ed3d,
- 0x1f100, 0x1f10c,
- 0x1fbf0, 0x1fbf9,
-}; /* CR_N */
-
-/* 'Nd': General Category */
-#define CR_Nd CR_Digit
-
-/* 'Nl': General Category */
-static const OnigCodePoint CR_Nl[] = {
- 12,
- 0x16ee, 0x16f0,
- 0x2160, 0x2182,
- 0x2185, 0x2188,
- 0x3007, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303a,
- 0xa6e6, 0xa6ef,
- 0x10140, 0x10174,
- 0x10341, 0x10341,
- 0x1034a, 0x1034a,
- 0x103d1, 0x103d5,
- 0x12400, 0x1246e,
-}; /* CR_Nl */
-
-/* 'No': General Category */
-static const OnigCodePoint CR_No[] = {
- 72,
- 0x00b2, 0x00b3,
- 0x00b9, 0x00b9,
- 0x00bc, 0x00be,
- 0x09f4, 0x09f9,
- 0x0b72, 0x0b77,
- 0x0bf0, 0x0bf2,
- 0x0c78, 0x0c7e,
- 0x0d58, 0x0d5e,
- 0x0d70, 0x0d78,
- 0x0f2a, 0x0f33,
- 0x1369, 0x137c,
- 0x17f0, 0x17f9,
- 0x19da, 0x19da,
- 0x2070, 0x2070,
- 0x2074, 0x2079,
- 0x2080, 0x2089,
- 0x2150, 0x215f,
- 0x2189, 0x2189,
- 0x2460, 0x249b,
- 0x24ea, 0x24ff,
- 0x2776, 0x2793,
- 0x2cfd, 0x2cfd,
- 0x3192, 0x3195,
- 0x3220, 0x3229,
- 0x3248, 0x324f,
- 0x3251, 0x325f,
- 0x3280, 0x3289,
- 0x32b1, 0x32bf,
- 0xa830, 0xa835,
- 0x10107, 0x10133,
- 0x10175, 0x10178,
- 0x1018a, 0x1018b,
- 0x102e1, 0x102fb,
- 0x10320, 0x10323,
- 0x10858, 0x1085f,
- 0x10879, 0x1087f,
- 0x108a7, 0x108af,
- 0x108fb, 0x108ff,
- 0x10916, 0x1091b,
- 0x109bc, 0x109bd,
- 0x109c0, 0x109cf,
- 0x109d2, 0x109ff,
- 0x10a40, 0x10a48,
- 0x10a7d, 0x10a7e,
- 0x10a9d, 0x10a9f,
- 0x10aeb, 0x10aef,
- 0x10b58, 0x10b5f,
- 0x10b78, 0x10b7f,
- 0x10ba9, 0x10baf,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x10f1d, 0x10f26,
- 0x10f51, 0x10f54,
- 0x10fc5, 0x10fcb,
- 0x11052, 0x11065,
- 0x111e1, 0x111f4,
- 0x1173a, 0x1173b,
- 0x118ea, 0x118f2,
- 0x11c5a, 0x11c6c,
- 0x11fc0, 0x11fd4,
- 0x16b5b, 0x16b61,
- 0x16e80, 0x16e96,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d360, 0x1d378,
- 0x1e8c7, 0x1e8cf,
- 0x1ec71, 0x1ecab,
- 0x1ecad, 0x1ecaf,
- 0x1ecb1, 0x1ecb4,
- 0x1ed01, 0x1ed2d,
- 0x1ed2f, 0x1ed3d,
- 0x1f100, 0x1f10c,
-}; /* CR_No */
-
-/* 'P': Major Category */
-#define CR_P CR_Punct
-
-/* 'Pc': General Category */
-static const OnigCodePoint CR_Pc[] = {
- 6,
- 0x005f, 0x005f,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xff3f, 0xff3f,
-}; /* CR_Pc */
-
-/* 'Pd': General Category */
-static const OnigCodePoint CR_Pd[] = {
- 19,
- 0x002d, 0x002d,
- 0x058a, 0x058a,
- 0x05be, 0x05be,
- 0x1400, 0x1400,
- 0x1806, 0x1806,
- 0x2010, 0x2015,
- 0x2e17, 0x2e17,
- 0x2e1a, 0x2e1a,
- 0x2e3a, 0x2e3b,
- 0x2e40, 0x2e40,
- 0x2e5d, 0x2e5d,
- 0x301c, 0x301c,
- 0x3030, 0x3030,
- 0x30a0, 0x30a0,
- 0xfe31, 0xfe32,
- 0xfe58, 0xfe58,
- 0xfe63, 0xfe63,
- 0xff0d, 0xff0d,
- 0x10ead, 0x10ead,
-}; /* CR_Pd */
-
-/* 'Pe': General Category */
-static const OnigCodePoint CR_Pe[] = {
- 76,
- 0x0029, 0x0029,
- 0x005d, 0x005d,
- 0x007d, 0x007d,
- 0x0f3b, 0x0f3b,
- 0x0f3d, 0x0f3d,
- 0x169c, 0x169c,
- 0x2046, 0x2046,
- 0x207e, 0x207e,
- 0x208e, 0x208e,
- 0x2309, 0x2309,
- 0x230b, 0x230b,
- 0x232a, 0x232a,
- 0x2769, 0x2769,
- 0x276b, 0x276b,
- 0x276d, 0x276d,
- 0x276f, 0x276f,
- 0x2771, 0x2771,
- 0x2773, 0x2773,
- 0x2775, 0x2775,
- 0x27c6, 0x27c6,
- 0x27e7, 0x27e7,
- 0x27e9, 0x27e9,
- 0x27eb, 0x27eb,
- 0x27ed, 0x27ed,
- 0x27ef, 0x27ef,
- 0x2984, 0x2984,
- 0x2986, 0x2986,
- 0x2988, 0x2988,
- 0x298a, 0x298a,
- 0x298c, 0x298c,
- 0x298e, 0x298e,
- 0x2990, 0x2990,
- 0x2992, 0x2992,
- 0x2994, 0x2994,
- 0x2996, 0x2996,
- 0x2998, 0x2998,
- 0x29d9, 0x29d9,
- 0x29db, 0x29db,
- 0x29fd, 0x29fd,
- 0x2e23, 0x2e23,
- 0x2e25, 0x2e25,
- 0x2e27, 0x2e27,
- 0x2e29, 0x2e29,
- 0x2e56, 0x2e56,
- 0x2e58, 0x2e58,
- 0x2e5a, 0x2e5a,
- 0x2e5c, 0x2e5c,
- 0x3009, 0x3009,
- 0x300b, 0x300b,
- 0x300d, 0x300d,
- 0x300f, 0x300f,
- 0x3011, 0x3011,
- 0x3015, 0x3015,
- 0x3017, 0x3017,
- 0x3019, 0x3019,
- 0x301b, 0x301b,
- 0x301e, 0x301f,
- 0xfd3e, 0xfd3e,
- 0xfe18, 0xfe18,
- 0xfe36, 0xfe36,
- 0xfe38, 0xfe38,
- 0xfe3a, 0xfe3a,
- 0xfe3c, 0xfe3c,
- 0xfe3e, 0xfe3e,
- 0xfe40, 0xfe40,
- 0xfe42, 0xfe42,
- 0xfe44, 0xfe44,
- 0xfe48, 0xfe48,
- 0xfe5a, 0xfe5a,
- 0xfe5c, 0xfe5c,
- 0xfe5e, 0xfe5e,
- 0xff09, 0xff09,
- 0xff3d, 0xff3d,
- 0xff5d, 0xff5d,
- 0xff60, 0xff60,
- 0xff63, 0xff63,
-}; /* CR_Pe */
-
-/* 'Pf': General Category */
-static const OnigCodePoint CR_Pf[] = {
- 10,
- 0x00bb, 0x00bb,
- 0x2019, 0x2019,
- 0x201d, 0x201d,
- 0x203a, 0x203a,
- 0x2e03, 0x2e03,
- 0x2e05, 0x2e05,
- 0x2e0a, 0x2e0a,
- 0x2e0d, 0x2e0d,
- 0x2e1d, 0x2e1d,
- 0x2e21, 0x2e21,
-}; /* CR_Pf */
-
-/* 'Pi': General Category */
-static const OnigCodePoint CR_Pi[] = {
- 11,
- 0x00ab, 0x00ab,
- 0x2018, 0x2018,
- 0x201b, 0x201c,
- 0x201f, 0x201f,
- 0x2039, 0x2039,
- 0x2e02, 0x2e02,
- 0x2e04, 0x2e04,
- 0x2e09, 0x2e09,
- 0x2e0c, 0x2e0c,
- 0x2e1c, 0x2e1c,
- 0x2e20, 0x2e20,
-}; /* CR_Pi */
-
-/* 'Po': General Category */
-static const OnigCodePoint CR_Po[] = {
- 187,
- 0x0021, 0x0023,
- 0x0025, 0x0027,
- 0x002a, 0x002a,
- 0x002c, 0x002c,
- 0x002e, 0x002f,
- 0x003a, 0x003b,
- 0x003f, 0x0040,
- 0x005c, 0x005c,
- 0x00a1, 0x00a1,
- 0x00a7, 0x00a7,
- 0x00b6, 0x00b7,
- 0x00bf, 0x00bf,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x055a, 0x055f,
- 0x0589, 0x0589,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05f3, 0x05f4,
- 0x0609, 0x060a,
- 0x060c, 0x060d,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x066a, 0x066d,
- 0x06d4, 0x06d4,
- 0x0700, 0x070d,
- 0x07f7, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0970, 0x0970,
- 0x09fd, 0x09fd,
- 0x0a76, 0x0a76,
- 0x0af0, 0x0af0,
- 0x0c77, 0x0c77,
- 0x0c84, 0x0c84,
- 0x0df4, 0x0df4,
- 0x0e4f, 0x0e4f,
- 0x0e5a, 0x0e5b,
- 0x0f04, 0x0f12,
- 0x0f14, 0x0f14,
- 0x0f85, 0x0f85,
- 0x0fd0, 0x0fd4,
- 0x0fd9, 0x0fda,
- 0x104a, 0x104f,
- 0x10fb, 0x10fb,
- 0x1360, 0x1368,
- 0x166e, 0x166e,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17d8, 0x17da,
- 0x1800, 0x1805,
- 0x1807, 0x180a,
- 0x1944, 0x1945,
- 0x1a1e, 0x1a1f,
- 0x1aa0, 0x1aa6,
- 0x1aa8, 0x1aad,
- 0x1b5a, 0x1b60,
- 0x1b7d, 0x1b7e,
- 0x1bfc, 0x1bff,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x2016, 0x2017,
- 0x2020, 0x2027,
- 0x2030, 0x2038,
- 0x203b, 0x203e,
- 0x2041, 0x2043,
- 0x2047, 0x2051,
- 0x2053, 0x2053,
- 0x2055, 0x205e,
- 0x2cf9, 0x2cfc,
- 0x2cfe, 0x2cff,
- 0x2d70, 0x2d70,
- 0x2e00, 0x2e01,
- 0x2e06, 0x2e08,
- 0x2e0b, 0x2e0b,
- 0x2e0e, 0x2e16,
- 0x2e18, 0x2e19,
- 0x2e1b, 0x2e1b,
- 0x2e1e, 0x2e1f,
- 0x2e2a, 0x2e2e,
- 0x2e30, 0x2e39,
- 0x2e3c, 0x2e3f,
- 0x2e41, 0x2e41,
- 0x2e43, 0x2e4f,
- 0x2e52, 0x2e54,
- 0x3001, 0x3003,
- 0x303d, 0x303d,
- 0x30fb, 0x30fb,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa673, 0xa673,
- 0xa67e, 0xa67e,
- 0xa6f2, 0xa6f7,
- 0xa874, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa8f8, 0xa8fa,
- 0xa8fc, 0xa8fc,
- 0xa92e, 0xa92f,
- 0xa95f, 0xa95f,
- 0xa9c1, 0xa9cd,
- 0xa9de, 0xa9df,
- 0xaa5c, 0xaa5f,
- 0xaade, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfe10, 0xfe16,
- 0xfe19, 0xfe19,
- 0xfe30, 0xfe30,
- 0xfe45, 0xfe46,
- 0xfe49, 0xfe4c,
- 0xfe50, 0xfe52,
- 0xfe54, 0xfe57,
- 0xfe5f, 0xfe61,
- 0xfe68, 0xfe68,
- 0xfe6a, 0xfe6b,
- 0xff01, 0xff03,
- 0xff05, 0xff07,
- 0xff0a, 0xff0a,
- 0xff0c, 0xff0c,
- 0xff0e, 0xff0f,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff20,
- 0xff3c, 0xff3c,
- 0xff61, 0xff61,
- 0xff64, 0xff65,
- 0x10100, 0x10102,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x1056f, 0x1056f,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x1093f, 0x1093f,
- 0x10a50, 0x10a58,
- 0x10a7f, 0x10a7f,
- 0x10af0, 0x10af6,
- 0x10b39, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x11140, 0x11143,
- 0x11174, 0x11175,
- 0x111c5, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111db, 0x111db,
- 0x111dd, 0x111df,
- 0x11238, 0x1123d,
- 0x112a9, 0x112a9,
- 0x1144b, 0x1144f,
- 0x1145a, 0x1145b,
- 0x1145d, 0x1145d,
- 0x114c6, 0x114c6,
- 0x115c1, 0x115d7,
- 0x11641, 0x11643,
- 0x11660, 0x1166c,
- 0x116b9, 0x116b9,
- 0x1173c, 0x1173e,
- 0x1183b, 0x1183b,
- 0x11944, 0x11946,
- 0x119e2, 0x119e2,
- 0x11a3f, 0x11a46,
- 0x11a9a, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11b00, 0x11b09,
- 0x11c41, 0x11c45,
- 0x11c70, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f4f,
- 0x11fff, 0x11fff,
- 0x12470, 0x12474,
- 0x12ff1, 0x12ff2,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b3b,
- 0x16b44, 0x16b44,
- 0x16e97, 0x16e9a,
- 0x16fe2, 0x16fe2,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8b,
- 0x1e95e, 0x1e95f,
-}; /* CR_Po */
-
-/* 'Ps': General Category */
-static const OnigCodePoint CR_Ps[] = {
- 79,
- 0x0028, 0x0028,
- 0x005b, 0x005b,
- 0x007b, 0x007b,
- 0x0f3a, 0x0f3a,
- 0x0f3c, 0x0f3c,
- 0x169b, 0x169b,
- 0x201a, 0x201a,
- 0x201e, 0x201e,
- 0x2045, 0x2045,
- 0x207d, 0x207d,
- 0x208d, 0x208d,
- 0x2308, 0x2308,
- 0x230a, 0x230a,
- 0x2329, 0x2329,
- 0x2768, 0x2768,
- 0x276a, 0x276a,
- 0x276c, 0x276c,
- 0x276e, 0x276e,
- 0x2770, 0x2770,
- 0x2772, 0x2772,
- 0x2774, 0x2774,
- 0x27c5, 0x27c5,
- 0x27e6, 0x27e6,
- 0x27e8, 0x27e8,
- 0x27ea, 0x27ea,
- 0x27ec, 0x27ec,
- 0x27ee, 0x27ee,
- 0x2983, 0x2983,
- 0x2985, 0x2985,
- 0x2987, 0x2987,
- 0x2989, 0x2989,
- 0x298b, 0x298b,
- 0x298d, 0x298d,
- 0x298f, 0x298f,
- 0x2991, 0x2991,
- 0x2993, 0x2993,
- 0x2995, 0x2995,
- 0x2997, 0x2997,
- 0x29d8, 0x29d8,
- 0x29da, 0x29da,
- 0x29fc, 0x29fc,
- 0x2e22, 0x2e22,
- 0x2e24, 0x2e24,
- 0x2e26, 0x2e26,
- 0x2e28, 0x2e28,
- 0x2e42, 0x2e42,
- 0x2e55, 0x2e55,
- 0x2e57, 0x2e57,
- 0x2e59, 0x2e59,
- 0x2e5b, 0x2e5b,
- 0x3008, 0x3008,
- 0x300a, 0x300a,
- 0x300c, 0x300c,
- 0x300e, 0x300e,
- 0x3010, 0x3010,
- 0x3014, 0x3014,
- 0x3016, 0x3016,
- 0x3018, 0x3018,
- 0x301a, 0x301a,
- 0x301d, 0x301d,
- 0xfd3f, 0xfd3f,
- 0xfe17, 0xfe17,
- 0xfe35, 0xfe35,
- 0xfe37, 0xfe37,
- 0xfe39, 0xfe39,
- 0xfe3b, 0xfe3b,
- 0xfe3d, 0xfe3d,
- 0xfe3f, 0xfe3f,
- 0xfe41, 0xfe41,
- 0xfe43, 0xfe43,
- 0xfe47, 0xfe47,
- 0xfe59, 0xfe59,
- 0xfe5b, 0xfe5b,
- 0xfe5d, 0xfe5d,
- 0xff08, 0xff08,
- 0xff3b, 0xff3b,
- 0xff5b, 0xff5b,
- 0xff5f, 0xff5f,
- 0xff62, 0xff62,
-}; /* CR_Ps */
-
-/* 'S': Major Category */
-static const OnigCodePoint CR_S[] = {
- 233,
- 0x0024, 0x0024,
- 0x002b, 0x002b,
- 0x003c, 0x003e,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x007c, 0x007c,
- 0x007e, 0x007e,
- 0x00a2, 0x00a6,
- 0x00a8, 0x00a9,
- 0x00ac, 0x00ac,
- 0x00ae, 0x00b1,
- 0x00b4, 0x00b4,
- 0x00b8, 0x00b8,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x02c2, 0x02c5,
- 0x02d2, 0x02df,
- 0x02e5, 0x02eb,
- 0x02ed, 0x02ed,
- 0x02ef, 0x02ff,
- 0x0375, 0x0375,
- 0x0384, 0x0385,
- 0x03f6, 0x03f6,
- 0x0482, 0x0482,
- 0x058d, 0x058f,
- 0x0606, 0x0608,
- 0x060b, 0x060b,
- 0x060e, 0x060f,
- 0x06de, 0x06de,
- 0x06e9, 0x06e9,
- 0x06fd, 0x06fe,
- 0x07f6, 0x07f6,
- 0x07fe, 0x07ff,
- 0x0888, 0x0888,
- 0x09f2, 0x09f3,
- 0x09fa, 0x09fb,
- 0x0af1, 0x0af1,
- 0x0b70, 0x0b70,
- 0x0bf3, 0x0bfa,
- 0x0c7f, 0x0c7f,
- 0x0d4f, 0x0d4f,
- 0x0d79, 0x0d79,
- 0x0e3f, 0x0e3f,
- 0x0f01, 0x0f03,
- 0x0f13, 0x0f13,
- 0x0f15, 0x0f17,
- 0x0f1a, 0x0f1f,
- 0x0f34, 0x0f34,
- 0x0f36, 0x0f36,
- 0x0f38, 0x0f38,
- 0x0fbe, 0x0fc5,
- 0x0fc7, 0x0fcc,
- 0x0fce, 0x0fcf,
- 0x0fd5, 0x0fd8,
- 0x109e, 0x109f,
- 0x1390, 0x1399,
- 0x166d, 0x166d,
- 0x17db, 0x17db,
- 0x1940, 0x1940,
- 0x19de, 0x19ff,
- 0x1b61, 0x1b6a,
- 0x1b74, 0x1b7c,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x2044, 0x2044,
- 0x2052, 0x2052,
- 0x207a, 0x207c,
- 0x208a, 0x208c,
- 0x20a0, 0x20c0,
- 0x2100, 0x2101,
- 0x2103, 0x2106,
- 0x2108, 0x2109,
- 0x2114, 0x2114,
- 0x2116, 0x2118,
- 0x211e, 0x2123,
- 0x2125, 0x2125,
- 0x2127, 0x2127,
- 0x2129, 0x2129,
- 0x212e, 0x212e,
- 0x213a, 0x213b,
- 0x2140, 0x2144,
- 0x214a, 0x214d,
- 0x214f, 0x214f,
- 0x218a, 0x218b,
- 0x2190, 0x2307,
- 0x230c, 0x2328,
- 0x232b, 0x2426,
- 0x2440, 0x244a,
- 0x249c, 0x24e9,
- 0x2500, 0x2767,
- 0x2794, 0x27c4,
- 0x27c7, 0x27e5,
- 0x27f0, 0x2982,
- 0x2999, 0x29d7,
- 0x29dc, 0x29fb,
- 0x29fe, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2bff,
- 0x2ce5, 0x2cea,
- 0x2e50, 0x2e51,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2fff,
- 0x3004, 0x3004,
- 0x3012, 0x3013,
- 0x3020, 0x3020,
- 0x3036, 0x3037,
- 0x303e, 0x303f,
- 0x309b, 0x309c,
- 0x3190, 0x3191,
- 0x3196, 0x319f,
- 0x31c0, 0x31e3,
- 0x31ef, 0x31ef,
- 0x3200, 0x321e,
- 0x322a, 0x3247,
- 0x3250, 0x3250,
- 0x3260, 0x327f,
- 0x328a, 0x32b0,
- 0x32c0, 0x33ff,
- 0x4dc0, 0x4dff,
- 0xa490, 0xa4c6,
- 0xa700, 0xa716,
- 0xa720, 0xa721,
- 0xa789, 0xa78a,
- 0xa828, 0xa82b,
- 0xa836, 0xa839,
- 0xaa77, 0xaa79,
- 0xab5b, 0xab5b,
- 0xab6a, 0xab6b,
- 0xfb29, 0xfb29,
- 0xfbb2, 0xfbc2,
- 0xfd40, 0xfd4f,
- 0xfdcf, 0xfdcf,
- 0xfdfc, 0xfdff,
- 0xfe62, 0xfe62,
- 0xfe64, 0xfe66,
- 0xfe69, 0xfe69,
- 0xff04, 0xff04,
- 0xff0b, 0xff0b,
- 0xff1c, 0xff1e,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xff5c, 0xff5c,
- 0xff5e, 0xff5e,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffc, 0xfffd,
- 0x10137, 0x1013f,
- 0x10179, 0x10189,
- 0x1018c, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fc,
- 0x10877, 0x10878,
- 0x10ac8, 0x10ac8,
- 0x1173f, 0x1173f,
- 0x11fd5, 0x11ff1,
- 0x16b3c, 0x16b3f,
- 0x16b45, 0x16b45,
- 0x1bc9c, 0x1bc9c,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d164,
- 0x1d16a, 0x1d16c,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d200, 0x1d241,
- 0x1d245, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
- 0x1d800, 0x1d9ff,
- 0x1da37, 0x1da3a,
- 0x1da6d, 0x1da74,
- 0x1da76, 0x1da83,
- 0x1da85, 0x1da86,
- 0x1e14f, 0x1e14f,
- 0x1e2ff, 0x1e2ff,
- 0x1ecac, 0x1ecac,
- 0x1ecb0, 0x1ecb0,
- 0x1ed2e, 0x1ed2e,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f10d, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
-}; /* CR_S */
-
-/* 'Sc': General Category */
-static const OnigCodePoint CR_Sc[] = {
- 21,
- 0x0024, 0x0024,
- 0x00a2, 0x00a5,
- 0x058f, 0x058f,
- 0x060b, 0x060b,
- 0x07fe, 0x07ff,
- 0x09f2, 0x09f3,
- 0x09fb, 0x09fb,
- 0x0af1, 0x0af1,
- 0x0bf9, 0x0bf9,
- 0x0e3f, 0x0e3f,
- 0x17db, 0x17db,
- 0x20a0, 0x20c0,
- 0xa838, 0xa838,
- 0xfdfc, 0xfdfc,
- 0xfe69, 0xfe69,
- 0xff04, 0xff04,
- 0xffe0, 0xffe1,
- 0xffe5, 0xffe6,
- 0x11fdd, 0x11fe0,
- 0x1e2ff, 0x1e2ff,
- 0x1ecb0, 0x1ecb0,
-}; /* CR_Sc */
-
-/* 'Sk': General Category */
-static const OnigCodePoint CR_Sk[] = {
- 31,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x00a8, 0x00a8,
- 0x00af, 0x00af,
- 0x00b4, 0x00b4,
- 0x00b8, 0x00b8,
- 0x02c2, 0x02c5,
- 0x02d2, 0x02df,
- 0x02e5, 0x02eb,
- 0x02ed, 0x02ed,
- 0x02ef, 0x02ff,
- 0x0375, 0x0375,
- 0x0384, 0x0385,
- 0x0888, 0x0888,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x309b, 0x309c,
- 0xa700, 0xa716,
- 0xa720, 0xa721,
- 0xa789, 0xa78a,
- 0xab5b, 0xab5b,
- 0xab6a, 0xab6b,
- 0xfbb2, 0xfbc2,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xffe3, 0xffe3,
- 0x1f3fb, 0x1f3ff,
-}; /* CR_Sk */
-
-/* 'Sm': General Category */
-static const OnigCodePoint CR_Sm[] = {
- 64,
- 0x002b, 0x002b,
- 0x003c, 0x003e,
- 0x007c, 0x007c,
- 0x007e, 0x007e,
- 0x00ac, 0x00ac,
- 0x00b1, 0x00b1,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x03f6, 0x03f6,
- 0x0606, 0x0608,
- 0x2044, 0x2044,
- 0x2052, 0x2052,
- 0x207a, 0x207c,
- 0x208a, 0x208c,
- 0x2118, 0x2118,
- 0x2140, 0x2144,
- 0x214b, 0x214b,
- 0x2190, 0x2194,
- 0x219a, 0x219b,
- 0x21a0, 0x21a0,
- 0x21a3, 0x21a3,
- 0x21a6, 0x21a6,
- 0x21ae, 0x21ae,
- 0x21ce, 0x21cf,
- 0x21d2, 0x21d2,
- 0x21d4, 0x21d4,
- 0x21f4, 0x22ff,
- 0x2320, 0x2321,
- 0x237c, 0x237c,
- 0x239b, 0x23b3,
- 0x23dc, 0x23e1,
- 0x25b7, 0x25b7,
- 0x25c1, 0x25c1,
- 0x25f8, 0x25ff,
- 0x266f, 0x266f,
- 0x27c0, 0x27c4,
- 0x27c7, 0x27e5,
- 0x27f0, 0x27ff,
- 0x2900, 0x2982,
- 0x2999, 0x29d7,
- 0x29dc, 0x29fb,
- 0x29fe, 0x2aff,
- 0x2b30, 0x2b44,
- 0x2b47, 0x2b4c,
- 0xfb29, 0xfb29,
- 0xfe62, 0xfe62,
- 0xfe64, 0xfe66,
- 0xff0b, 0xff0b,
- 0xff1c, 0xff1e,
- 0xff5c, 0xff5c,
- 0xff5e, 0xff5e,
- 0xffe2, 0xffe2,
- 0xffe9, 0xffec,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
- 0x1eef0, 0x1eef1,
-}; /* CR_Sm */
-
-/* 'So': General Category */
-static const OnigCodePoint CR_So[] = {
- 185,
- 0x00a6, 0x00a6,
- 0x00a9, 0x00a9,
- 0x00ae, 0x00ae,
- 0x00b0, 0x00b0,
- 0x0482, 0x0482,
- 0x058d, 0x058e,
- 0x060e, 0x060f,
- 0x06de, 0x06de,
- 0x06e9, 0x06e9,
- 0x06fd, 0x06fe,
- 0x07f6, 0x07f6,
- 0x09fa, 0x09fa,
- 0x0b70, 0x0b70,
- 0x0bf3, 0x0bf8,
- 0x0bfa, 0x0bfa,
- 0x0c7f, 0x0c7f,
- 0x0d4f, 0x0d4f,
- 0x0d79, 0x0d79,
- 0x0f01, 0x0f03,
- 0x0f13, 0x0f13,
- 0x0f15, 0x0f17,
- 0x0f1a, 0x0f1f,
- 0x0f34, 0x0f34,
- 0x0f36, 0x0f36,
- 0x0f38, 0x0f38,
- 0x0fbe, 0x0fc5,
- 0x0fc7, 0x0fcc,
- 0x0fce, 0x0fcf,
- 0x0fd5, 0x0fd8,
- 0x109e, 0x109f,
- 0x1390, 0x1399,
- 0x166d, 0x166d,
- 0x1940, 0x1940,
- 0x19de, 0x19ff,
- 0x1b61, 0x1b6a,
- 0x1b74, 0x1b7c,
- 0x2100, 0x2101,
- 0x2103, 0x2106,
- 0x2108, 0x2109,
- 0x2114, 0x2114,
- 0x2116, 0x2117,
- 0x211e, 0x2123,
- 0x2125, 0x2125,
- 0x2127, 0x2127,
- 0x2129, 0x2129,
- 0x212e, 0x212e,
- 0x213a, 0x213b,
- 0x214a, 0x214a,
- 0x214c, 0x214d,
- 0x214f, 0x214f,
- 0x218a, 0x218b,
- 0x2195, 0x2199,
- 0x219c, 0x219f,
- 0x21a1, 0x21a2,
- 0x21a4, 0x21a5,
- 0x21a7, 0x21ad,
- 0x21af, 0x21cd,
- 0x21d0, 0x21d1,
- 0x21d3, 0x21d3,
- 0x21d5, 0x21f3,
- 0x2300, 0x2307,
- 0x230c, 0x231f,
- 0x2322, 0x2328,
- 0x232b, 0x237b,
- 0x237d, 0x239a,
- 0x23b4, 0x23db,
- 0x23e2, 0x2426,
- 0x2440, 0x244a,
- 0x249c, 0x24e9,
- 0x2500, 0x25b6,
- 0x25b8, 0x25c0,
- 0x25c2, 0x25f7,
- 0x2600, 0x266e,
- 0x2670, 0x2767,
- 0x2794, 0x27bf,
- 0x2800, 0x28ff,
- 0x2b00, 0x2b2f,
- 0x2b45, 0x2b46,
- 0x2b4d, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2bff,
- 0x2ce5, 0x2cea,
- 0x2e50, 0x2e51,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2fff,
- 0x3004, 0x3004,
- 0x3012, 0x3013,
- 0x3020, 0x3020,
- 0x3036, 0x3037,
- 0x303e, 0x303f,
- 0x3190, 0x3191,
- 0x3196, 0x319f,
- 0x31c0, 0x31e3,
- 0x31ef, 0x31ef,
- 0x3200, 0x321e,
- 0x322a, 0x3247,
- 0x3250, 0x3250,
- 0x3260, 0x327f,
- 0x328a, 0x32b0,
- 0x32c0, 0x33ff,
- 0x4dc0, 0x4dff,
- 0xa490, 0xa4c6,
- 0xa828, 0xa82b,
- 0xa836, 0xa837,
- 0xa839, 0xa839,
- 0xaa77, 0xaa79,
- 0xfd40, 0xfd4f,
- 0xfdcf, 0xfdcf,
- 0xfdfd, 0xfdff,
- 0xffe4, 0xffe4,
- 0xffe8, 0xffe8,
- 0xffed, 0xffee,
- 0xfffc, 0xfffd,
- 0x10137, 0x1013f,
- 0x10179, 0x10189,
- 0x1018c, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fc,
- 0x10877, 0x10878,
- 0x10ac8, 0x10ac8,
- 0x1173f, 0x1173f,
- 0x11fd5, 0x11fdc,
- 0x11fe1, 0x11ff1,
- 0x16b3c, 0x16b3f,
- 0x16b45, 0x16b45,
- 0x1bc9c, 0x1bc9c,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d164,
- 0x1d16a, 0x1d16c,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d200, 0x1d241,
- 0x1d245, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d800, 0x1d9ff,
- 0x1da37, 0x1da3a,
- 0x1da6d, 0x1da74,
- 0x1da76, 0x1da83,
- 0x1da85, 0x1da86,
- 0x1e14f, 0x1e14f,
- 0x1ecac, 0x1ecac,
- 0x1ed2e, 0x1ed2e,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f10d, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f3fa,
- 0x1f400, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
-}; /* CR_So */
-
-/* 'Z': Major Category */
-static const OnigCodePoint CR_Z[] = {
- 8,
- 0x0020, 0x0020,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x2028, 0x2029,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Z */
-
-/* 'Zl': General Category */
-static const OnigCodePoint CR_Zl[] = {
- 1,
- 0x2028, 0x2028,
-}; /* CR_Zl */
-
-/* 'Zp': General Category */
-static const OnigCodePoint CR_Zp[] = {
- 1,
- 0x2029, 0x2029,
-}; /* CR_Zp */
-
-/* 'Zs': General Category */
-static const OnigCodePoint CR_Zs[] = {
- 7,
- 0x0020, 0x0020,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x2000, 0x200a,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
-}; /* CR_Zs */
-
-/* 'Math': Derived Property */
-static const OnigCodePoint CR_Math[] = {
- 138,
- 0x002b, 0x002b,
- 0x003c, 0x003e,
- 0x005e, 0x005e,
- 0x007c, 0x007c,
- 0x007e, 0x007e,
- 0x00ac, 0x00ac,
- 0x00b1, 0x00b1,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x03d0, 0x03d2,
- 0x03d5, 0x03d5,
- 0x03f0, 0x03f1,
- 0x03f4, 0x03f6,
- 0x0606, 0x0608,
- 0x2016, 0x2016,
- 0x2032, 0x2034,
- 0x2040, 0x2040,
- 0x2044, 0x2044,
- 0x2052, 0x2052,
- 0x2061, 0x2064,
- 0x207a, 0x207e,
- 0x208a, 0x208e,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20e6,
- 0x20eb, 0x20ef,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2128, 0x2129,
- 0x212c, 0x212d,
- 0x212f, 0x2131,
- 0x2133, 0x2138,
- 0x213c, 0x2149,
- 0x214b, 0x214b,
- 0x2190, 0x21a7,
- 0x21a9, 0x21ae,
- 0x21b0, 0x21b1,
- 0x21b6, 0x21b7,
- 0x21bc, 0x21db,
- 0x21dd, 0x21dd,
- 0x21e4, 0x21e5,
- 0x21f4, 0x22ff,
- 0x2308, 0x230b,
- 0x2320, 0x2321,
- 0x237c, 0x237c,
- 0x239b, 0x23b5,
- 0x23b7, 0x23b7,
- 0x23d0, 0x23d0,
- 0x23dc, 0x23e2,
- 0x25a0, 0x25a1,
- 0x25ae, 0x25b7,
- 0x25bc, 0x25c1,
- 0x25c6, 0x25c7,
- 0x25ca, 0x25cb,
- 0x25cf, 0x25d3,
- 0x25e2, 0x25e2,
- 0x25e4, 0x25e4,
- 0x25e7, 0x25ec,
- 0x25f8, 0x25ff,
- 0x2605, 0x2606,
- 0x2640, 0x2640,
- 0x2642, 0x2642,
- 0x2660, 0x2663,
- 0x266d, 0x266f,
- 0x27c0, 0x27ff,
- 0x2900, 0x2aff,
- 0x2b30, 0x2b44,
- 0x2b47, 0x2b4c,
- 0xfb29, 0xfb29,
- 0xfe61, 0xfe66,
- 0xfe68, 0xfe68,
- 0xff0b, 0xff0b,
- 0xff1c, 0xff1e,
- 0xff3c, 0xff3c,
- 0xff3e, 0xff3e,
- 0xff5c, 0xff5c,
- 0xff5e, 0xff5e,
- 0xffe2, 0xffe2,
- 0xffe9, 0xffec,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
-}; /* CR_Math */
-
-/* 'Alphabetic': Derived Property */
-#define CR_Alphabetic CR_Alpha
-
-/* 'Lowercase': Derived Property */
-#define CR_Lowercase CR_Lower
-
-/* 'Uppercase': Derived Property */
-#define CR_Uppercase CR_Upper
-
-/* 'Cased': Derived Property */
-static const OnigCodePoint CR_Cased[] = {
- 157,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x01ba,
- 0x01bc, 0x01bf,
- 0x01c4, 0x0293,
- 0x0295, 0x02b8,
- 0x02c0, 0x02c1,
- 0x02e0, 0x02e4,
- 0x0345, 0x0345,
- 0x0370, 0x0373,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0560, 0x0588,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fc, 0x10ff,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1d00, 0x1dbf,
- 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, 0x2134,
- 0x2139, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x217f,
- 0x2183, 0x2184,
- 0x24b6, 0x24e9,
- 0x2c00, 0x2ce4,
- 0x2ceb, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa640, 0xa66d,
- 0xa680, 0xa69d,
- 0xa722, 0xa787,
- 0xa78b, 0xa78e,
- 0xa790, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa7f6,
- 0xa7f8, 0xa7fa,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10400, 0x1044f,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10780, 0x10780,
- 0x10783, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x118a0, 0x118df,
- 0x16e40, 0x16e7f,
- 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, 0x1df09,
- 0x1df0b, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e030, 0x1e06d,
- 0x1e900, 0x1e943,
- 0x1f130, 0x1f149,
- 0x1f150, 0x1f169,
- 0x1f170, 0x1f189,
-}; /* CR_Cased */
-
-/* 'Case_Ignorable': Derived Property */
-static const OnigCodePoint CR_Case_Ignorable[] = {
- 437,
- 0x0027, 0x0027,
- 0x002e, 0x002e,
- 0x003a, 0x003a,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x00a8, 0x00a8,
- 0x00ad, 0x00ad,
- 0x00af, 0x00af,
- 0x00b4, 0x00b4,
- 0x00b7, 0x00b8,
- 0x02b0, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x0384, 0x0385,
- 0x0387, 0x0387,
- 0x0483, 0x0489,
- 0x0559, 0x0559,
- 0x055f, 0x055f,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05f4, 0x05f4,
- 0x0600, 0x0605,
- 0x0610, 0x061a,
- 0x061c, 0x061c,
- 0x0640, 0x0640,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dd,
- 0x06df, 0x06e8,
- 0x06ea, 0x06ed,
- 0x070f, 0x070f,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0816, 0x082d,
- 0x0859, 0x085b,
- 0x0888, 0x0888,
- 0x0890, 0x0891,
- 0x0898, 0x089f,
- 0x08c9, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0971, 0x0971,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3f, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b56,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cbf,
- 0x0cc6, 0x0cc6,
- 0x0ccc, 0x0ccd,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e46, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x10fc, 0x10fc,
- 0x135d, 0x135f,
- 0x1712, 0x1714,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dd, 0x17dd,
- 0x180b, 0x180f,
- 0x1843, 0x1843,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b34,
- 0x1b36, 0x1b3a,
- 0x1b3c, 0x1b3c,
- 0x1b42, 0x1b42,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1ba9,
- 0x1bab, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf1,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1c78, 0x1c7d,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1d2c, 0x1d6a,
- 0x1d78, 0x1d78,
- 0x1d9b, 0x1dff,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x200b, 0x200f,
- 0x2018, 0x2019,
- 0x2024, 0x2024,
- 0x2027, 0x2027,
- 0x202a, 0x202e,
- 0x2060, 0x2064,
- 0x2066, 0x206f,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20f0,
- 0x2c7c, 0x2c7d,
- 0x2cef, 0x2cf1,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x2e2f, 0x2e2f,
- 0x3005, 0x3005,
- 0x302a, 0x302d,
- 0x3031, 0x3035,
- 0x303b, 0x303b,
- 0x3099, 0x309e,
- 0x30fc, 0x30fe,
- 0xa015, 0xa015,
- 0xa4f8, 0xa4fd,
- 0xa60c, 0xa60c,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa67f, 0xa67f,
- 0xa69c, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa700, 0xa721,
- 0xa770, 0xa770,
- 0xa788, 0xa78a,
- 0xa7f2, 0xa7f4,
- 0xa7f8, 0xa7f9,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9cf, 0xa9cf,
- 0xa9e5, 0xa9e6,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa70, 0xaa70,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaadd, 0xaadd,
- 0xaaec, 0xaaed,
- 0xaaf3, 0xaaf4,
- 0xaaf6, 0xaaf6,
- 0xab5b, 0xab5f,
- 0xab69, 0xab6b,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfbb2, 0xfbc2,
- 0xfe00, 0xfe0f,
- 0xfe13, 0xfe13,
- 0xfe20, 0xfe2f,
- 0xfe52, 0xfe52,
- 0xfe55, 0xfe55,
- 0xfeff, 0xfeff,
- 0xff07, 0xff07,
- 0xff0e, 0xff0e,
- 0xff1a, 0xff1a,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0xffe3, 0xffe3,
- 0xfff9, 0xfffb,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110bd, 0x110bd,
- 0x110c2, 0x110c2,
- 0x110cd, 0x110cd,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11234,
- 0x11236, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x11340, 0x11340,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b5,
- 0x116b7, 0x116b7,
- 0x1171d, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x1193b, 0x1193c,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f40,
- 0x11f42, 0x11f42,
- 0x13430, 0x13440,
- 0x13447, 0x13455,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1bc9d, 0x1bc9e,
- 0x1bca0, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d173, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e13d,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4eb, 0x1e4ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94b,
- 0x1f3fb, 0x1f3ff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_Case_Ignorable */
-
-/* 'Changes_When_Lowercased': Derived Property */
-static const OnigCodePoint CR_Changes_When_Lowercased[] = {
- 609,
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x014a, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c5,
- 0x01c7, 0x01c8,
- 0x01ca, 0x01cb,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f2,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03cf, 0x03cf,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f4, 0x03f4,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 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,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fb8, 0x1fbc,
- 0x1fc8, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffc,
- 0x2126, 0x2126,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 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,
- 0x1e900, 0x1e921,
-}; /* CR_Changes_When_Lowercased */
-
-/* 'Changes_When_Uppercased': Derived Property */
-static const OnigCodePoint CR_Changes_When_Uppercased[] = {
- 627,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0137,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018c,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019a,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01b9,
- 0x01bd, 0x01bd,
- 0x01bf, 0x01bf,
- 0x01c5, 0x01c6,
- 0x01c8, 0x01c9,
- 0x01cb, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f0,
- 0x01f2, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0233,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0254,
- 0x0256, 0x0257,
- 0x0259, 0x0259,
- 0x025b, 0x025c,
- 0x0260, 0x0261,
- 0x0263, 0x0263,
- 0x0265, 0x0266,
- 0x0268, 0x026c,
- 0x026f, 0x026f,
- 0x0271, 0x0272,
- 0x0275, 0x0275,
- 0x027d, 0x027d,
- 0x0280, 0x0280,
- 0x0282, 0x0283,
- 0x0287, 0x028c,
- 0x0292, 0x0292,
- 0x029d, 0x029e,
- 0x0345, 0x0345,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037b, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fb,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0561, 0x0587,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1d79, 0x1d79,
- 0x1d7d, 0x1d7d,
- 0x1d8e, 0x1d8e,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9b,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbc, 0x1fbc,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fcc, 0x1fcc,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x1ffc, 0x1ffc,
- 0x214e, 0x214e,
- 0x2170, 0x217f,
- 0x2184, 0x2184,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c73, 0x2c73,
- 0x2c76, 0x2c76,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce3,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69b,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa72f,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa76f,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa791, 0xa791,
- 0xa793, 0xa794,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7d1, 0xa7d1,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7f6, 0xa7f6,
- 0xab53, 0xab53,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10cc0, 0x10cf2,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1e922, 0x1e943,
-}; /* CR_Changes_When_Uppercased */
-
-/* 'Changes_When_Titlecased': Derived Property */
-static const OnigCodePoint CR_Changes_When_Titlecased[] = {
- 626,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0101, 0x0101,
- 0x0103, 0x0103,
- 0x0105, 0x0105,
- 0x0107, 0x0107,
- 0x0109, 0x0109,
- 0x010b, 0x010b,
- 0x010d, 0x010d,
- 0x010f, 0x010f,
- 0x0111, 0x0111,
- 0x0113, 0x0113,
- 0x0115, 0x0115,
- 0x0117, 0x0117,
- 0x0119, 0x0119,
- 0x011b, 0x011b,
- 0x011d, 0x011d,
- 0x011f, 0x011f,
- 0x0121, 0x0121,
- 0x0123, 0x0123,
- 0x0125, 0x0125,
- 0x0127, 0x0127,
- 0x0129, 0x0129,
- 0x012b, 0x012b,
- 0x012d, 0x012d,
- 0x012f, 0x012f,
- 0x0131, 0x0131,
- 0x0133, 0x0133,
- 0x0135, 0x0135,
- 0x0137, 0x0137,
- 0x013a, 0x013a,
- 0x013c, 0x013c,
- 0x013e, 0x013e,
- 0x0140, 0x0140,
- 0x0142, 0x0142,
- 0x0144, 0x0144,
- 0x0146, 0x0146,
- 0x0148, 0x0149,
- 0x014b, 0x014b,
- 0x014d, 0x014d,
- 0x014f, 0x014f,
- 0x0151, 0x0151,
- 0x0153, 0x0153,
- 0x0155, 0x0155,
- 0x0157, 0x0157,
- 0x0159, 0x0159,
- 0x015b, 0x015b,
- 0x015d, 0x015d,
- 0x015f, 0x015f,
- 0x0161, 0x0161,
- 0x0163, 0x0163,
- 0x0165, 0x0165,
- 0x0167, 0x0167,
- 0x0169, 0x0169,
- 0x016b, 0x016b,
- 0x016d, 0x016d,
- 0x016f, 0x016f,
- 0x0171, 0x0171,
- 0x0173, 0x0173,
- 0x0175, 0x0175,
- 0x0177, 0x0177,
- 0x017a, 0x017a,
- 0x017c, 0x017c,
- 0x017e, 0x0180,
- 0x0183, 0x0183,
- 0x0185, 0x0185,
- 0x0188, 0x0188,
- 0x018c, 0x018c,
- 0x0192, 0x0192,
- 0x0195, 0x0195,
- 0x0199, 0x019a,
- 0x019e, 0x019e,
- 0x01a1, 0x01a1,
- 0x01a3, 0x01a3,
- 0x01a5, 0x01a5,
- 0x01a8, 0x01a8,
- 0x01ad, 0x01ad,
- 0x01b0, 0x01b0,
- 0x01b4, 0x01b4,
- 0x01b6, 0x01b6,
- 0x01b9, 0x01b9,
- 0x01bd, 0x01bd,
- 0x01bf, 0x01bf,
- 0x01c4, 0x01c4,
- 0x01c6, 0x01c7,
- 0x01c9, 0x01ca,
- 0x01cc, 0x01cc,
- 0x01ce, 0x01ce,
- 0x01d0, 0x01d0,
- 0x01d2, 0x01d2,
- 0x01d4, 0x01d4,
- 0x01d6, 0x01d6,
- 0x01d8, 0x01d8,
- 0x01da, 0x01da,
- 0x01dc, 0x01dd,
- 0x01df, 0x01df,
- 0x01e1, 0x01e1,
- 0x01e3, 0x01e3,
- 0x01e5, 0x01e5,
- 0x01e7, 0x01e7,
- 0x01e9, 0x01e9,
- 0x01eb, 0x01eb,
- 0x01ed, 0x01ed,
- 0x01ef, 0x01f1,
- 0x01f3, 0x01f3,
- 0x01f5, 0x01f5,
- 0x01f9, 0x01f9,
- 0x01fb, 0x01fb,
- 0x01fd, 0x01fd,
- 0x01ff, 0x01ff,
- 0x0201, 0x0201,
- 0x0203, 0x0203,
- 0x0205, 0x0205,
- 0x0207, 0x0207,
- 0x0209, 0x0209,
- 0x020b, 0x020b,
- 0x020d, 0x020d,
- 0x020f, 0x020f,
- 0x0211, 0x0211,
- 0x0213, 0x0213,
- 0x0215, 0x0215,
- 0x0217, 0x0217,
- 0x0219, 0x0219,
- 0x021b, 0x021b,
- 0x021d, 0x021d,
- 0x021f, 0x021f,
- 0x0223, 0x0223,
- 0x0225, 0x0225,
- 0x0227, 0x0227,
- 0x0229, 0x0229,
- 0x022b, 0x022b,
- 0x022d, 0x022d,
- 0x022f, 0x022f,
- 0x0231, 0x0231,
- 0x0233, 0x0233,
- 0x023c, 0x023c,
- 0x023f, 0x0240,
- 0x0242, 0x0242,
- 0x0247, 0x0247,
- 0x0249, 0x0249,
- 0x024b, 0x024b,
- 0x024d, 0x024d,
- 0x024f, 0x0254,
- 0x0256, 0x0257,
- 0x0259, 0x0259,
- 0x025b, 0x025c,
- 0x0260, 0x0261,
- 0x0263, 0x0263,
- 0x0265, 0x0266,
- 0x0268, 0x026c,
- 0x026f, 0x026f,
- 0x0271, 0x0272,
- 0x0275, 0x0275,
- 0x027d, 0x027d,
- 0x0280, 0x0280,
- 0x0282, 0x0283,
- 0x0287, 0x028c,
- 0x0292, 0x0292,
- 0x029d, 0x029e,
- 0x0345, 0x0345,
- 0x0371, 0x0371,
- 0x0373, 0x0373,
- 0x0377, 0x0377,
- 0x037b, 0x037d,
- 0x0390, 0x0390,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03d9, 0x03d9,
- 0x03db, 0x03db,
- 0x03dd, 0x03dd,
- 0x03df, 0x03df,
- 0x03e1, 0x03e1,
- 0x03e3, 0x03e3,
- 0x03e5, 0x03e5,
- 0x03e7, 0x03e7,
- 0x03e9, 0x03e9,
- 0x03eb, 0x03eb,
- 0x03ed, 0x03ed,
- 0x03ef, 0x03f3,
- 0x03f5, 0x03f5,
- 0x03f8, 0x03f8,
- 0x03fb, 0x03fb,
- 0x0430, 0x045f,
- 0x0461, 0x0461,
- 0x0463, 0x0463,
- 0x0465, 0x0465,
- 0x0467, 0x0467,
- 0x0469, 0x0469,
- 0x046b, 0x046b,
- 0x046d, 0x046d,
- 0x046f, 0x046f,
- 0x0471, 0x0471,
- 0x0473, 0x0473,
- 0x0475, 0x0475,
- 0x0477, 0x0477,
- 0x0479, 0x0479,
- 0x047b, 0x047b,
- 0x047d, 0x047d,
- 0x047f, 0x047f,
- 0x0481, 0x0481,
- 0x048b, 0x048b,
- 0x048d, 0x048d,
- 0x048f, 0x048f,
- 0x0491, 0x0491,
- 0x0493, 0x0493,
- 0x0495, 0x0495,
- 0x0497, 0x0497,
- 0x0499, 0x0499,
- 0x049b, 0x049b,
- 0x049d, 0x049d,
- 0x049f, 0x049f,
- 0x04a1, 0x04a1,
- 0x04a3, 0x04a3,
- 0x04a5, 0x04a5,
- 0x04a7, 0x04a7,
- 0x04a9, 0x04a9,
- 0x04ab, 0x04ab,
- 0x04ad, 0x04ad,
- 0x04af, 0x04af,
- 0x04b1, 0x04b1,
- 0x04b3, 0x04b3,
- 0x04b5, 0x04b5,
- 0x04b7, 0x04b7,
- 0x04b9, 0x04b9,
- 0x04bb, 0x04bb,
- 0x04bd, 0x04bd,
- 0x04bf, 0x04bf,
- 0x04c2, 0x04c2,
- 0x04c4, 0x04c4,
- 0x04c6, 0x04c6,
- 0x04c8, 0x04c8,
- 0x04ca, 0x04ca,
- 0x04cc, 0x04cc,
- 0x04ce, 0x04cf,
- 0x04d1, 0x04d1,
- 0x04d3, 0x04d3,
- 0x04d5, 0x04d5,
- 0x04d7, 0x04d7,
- 0x04d9, 0x04d9,
- 0x04db, 0x04db,
- 0x04dd, 0x04dd,
- 0x04df, 0x04df,
- 0x04e1, 0x04e1,
- 0x04e3, 0x04e3,
- 0x04e5, 0x04e5,
- 0x04e7, 0x04e7,
- 0x04e9, 0x04e9,
- 0x04eb, 0x04eb,
- 0x04ed, 0x04ed,
- 0x04ef, 0x04ef,
- 0x04f1, 0x04f1,
- 0x04f3, 0x04f3,
- 0x04f5, 0x04f5,
- 0x04f7, 0x04f7,
- 0x04f9, 0x04f9,
- 0x04fb, 0x04fb,
- 0x04fd, 0x04fd,
- 0x04ff, 0x04ff,
- 0x0501, 0x0501,
- 0x0503, 0x0503,
- 0x0505, 0x0505,
- 0x0507, 0x0507,
- 0x0509, 0x0509,
- 0x050b, 0x050b,
- 0x050d, 0x050d,
- 0x050f, 0x050f,
- 0x0511, 0x0511,
- 0x0513, 0x0513,
- 0x0515, 0x0515,
- 0x0517, 0x0517,
- 0x0519, 0x0519,
- 0x051b, 0x051b,
- 0x051d, 0x051d,
- 0x051f, 0x051f,
- 0x0521, 0x0521,
- 0x0523, 0x0523,
- 0x0525, 0x0525,
- 0x0527, 0x0527,
- 0x0529, 0x0529,
- 0x052b, 0x052b,
- 0x052d, 0x052d,
- 0x052f, 0x052f,
- 0x0561, 0x0587,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1d79, 0x1d79,
- 0x1d7d, 0x1d7d,
- 0x1d8e, 0x1d8e,
- 0x1e01, 0x1e01,
- 0x1e03, 0x1e03,
- 0x1e05, 0x1e05,
- 0x1e07, 0x1e07,
- 0x1e09, 0x1e09,
- 0x1e0b, 0x1e0b,
- 0x1e0d, 0x1e0d,
- 0x1e0f, 0x1e0f,
- 0x1e11, 0x1e11,
- 0x1e13, 0x1e13,
- 0x1e15, 0x1e15,
- 0x1e17, 0x1e17,
- 0x1e19, 0x1e19,
- 0x1e1b, 0x1e1b,
- 0x1e1d, 0x1e1d,
- 0x1e1f, 0x1e1f,
- 0x1e21, 0x1e21,
- 0x1e23, 0x1e23,
- 0x1e25, 0x1e25,
- 0x1e27, 0x1e27,
- 0x1e29, 0x1e29,
- 0x1e2b, 0x1e2b,
- 0x1e2d, 0x1e2d,
- 0x1e2f, 0x1e2f,
- 0x1e31, 0x1e31,
- 0x1e33, 0x1e33,
- 0x1e35, 0x1e35,
- 0x1e37, 0x1e37,
- 0x1e39, 0x1e39,
- 0x1e3b, 0x1e3b,
- 0x1e3d, 0x1e3d,
- 0x1e3f, 0x1e3f,
- 0x1e41, 0x1e41,
- 0x1e43, 0x1e43,
- 0x1e45, 0x1e45,
- 0x1e47, 0x1e47,
- 0x1e49, 0x1e49,
- 0x1e4b, 0x1e4b,
- 0x1e4d, 0x1e4d,
- 0x1e4f, 0x1e4f,
- 0x1e51, 0x1e51,
- 0x1e53, 0x1e53,
- 0x1e55, 0x1e55,
- 0x1e57, 0x1e57,
- 0x1e59, 0x1e59,
- 0x1e5b, 0x1e5b,
- 0x1e5d, 0x1e5d,
- 0x1e5f, 0x1e5f,
- 0x1e61, 0x1e61,
- 0x1e63, 0x1e63,
- 0x1e65, 0x1e65,
- 0x1e67, 0x1e67,
- 0x1e69, 0x1e69,
- 0x1e6b, 0x1e6b,
- 0x1e6d, 0x1e6d,
- 0x1e6f, 0x1e6f,
- 0x1e71, 0x1e71,
- 0x1e73, 0x1e73,
- 0x1e75, 0x1e75,
- 0x1e77, 0x1e77,
- 0x1e79, 0x1e79,
- 0x1e7b, 0x1e7b,
- 0x1e7d, 0x1e7d,
- 0x1e7f, 0x1e7f,
- 0x1e81, 0x1e81,
- 0x1e83, 0x1e83,
- 0x1e85, 0x1e85,
- 0x1e87, 0x1e87,
- 0x1e89, 0x1e89,
- 0x1e8b, 0x1e8b,
- 0x1e8d, 0x1e8d,
- 0x1e8f, 0x1e8f,
- 0x1e91, 0x1e91,
- 0x1e93, 0x1e93,
- 0x1e95, 0x1e9b,
- 0x1ea1, 0x1ea1,
- 0x1ea3, 0x1ea3,
- 0x1ea5, 0x1ea5,
- 0x1ea7, 0x1ea7,
- 0x1ea9, 0x1ea9,
- 0x1eab, 0x1eab,
- 0x1ead, 0x1ead,
- 0x1eaf, 0x1eaf,
- 0x1eb1, 0x1eb1,
- 0x1eb3, 0x1eb3,
- 0x1eb5, 0x1eb5,
- 0x1eb7, 0x1eb7,
- 0x1eb9, 0x1eb9,
- 0x1ebb, 0x1ebb,
- 0x1ebd, 0x1ebd,
- 0x1ebf, 0x1ebf,
- 0x1ec1, 0x1ec1,
- 0x1ec3, 0x1ec3,
- 0x1ec5, 0x1ec5,
- 0x1ec7, 0x1ec7,
- 0x1ec9, 0x1ec9,
- 0x1ecb, 0x1ecb,
- 0x1ecd, 0x1ecd,
- 0x1ecf, 0x1ecf,
- 0x1ed1, 0x1ed1,
- 0x1ed3, 0x1ed3,
- 0x1ed5, 0x1ed5,
- 0x1ed7, 0x1ed7,
- 0x1ed9, 0x1ed9,
- 0x1edb, 0x1edb,
- 0x1edd, 0x1edd,
- 0x1edf, 0x1edf,
- 0x1ee1, 0x1ee1,
- 0x1ee3, 0x1ee3,
- 0x1ee5, 0x1ee5,
- 0x1ee7, 0x1ee7,
- 0x1ee9, 0x1ee9,
- 0x1eeb, 0x1eeb,
- 0x1eed, 0x1eed,
- 0x1eef, 0x1eef,
- 0x1ef1, 0x1ef1,
- 0x1ef3, 0x1ef3,
- 0x1ef5, 0x1ef5,
- 0x1ef7, 0x1ef7,
- 0x1ef9, 0x1ef9,
- 0x1efb, 0x1efb,
- 0x1efd, 0x1efd,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fbe, 0x1fbe,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x214e, 0x214e,
- 0x2170, 0x217f,
- 0x2184, 0x2184,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5f,
- 0x2c61, 0x2c61,
- 0x2c65, 0x2c66,
- 0x2c68, 0x2c68,
- 0x2c6a, 0x2c6a,
- 0x2c6c, 0x2c6c,
- 0x2c73, 0x2c73,
- 0x2c76, 0x2c76,
- 0x2c81, 0x2c81,
- 0x2c83, 0x2c83,
- 0x2c85, 0x2c85,
- 0x2c87, 0x2c87,
- 0x2c89, 0x2c89,
- 0x2c8b, 0x2c8b,
- 0x2c8d, 0x2c8d,
- 0x2c8f, 0x2c8f,
- 0x2c91, 0x2c91,
- 0x2c93, 0x2c93,
- 0x2c95, 0x2c95,
- 0x2c97, 0x2c97,
- 0x2c99, 0x2c99,
- 0x2c9b, 0x2c9b,
- 0x2c9d, 0x2c9d,
- 0x2c9f, 0x2c9f,
- 0x2ca1, 0x2ca1,
- 0x2ca3, 0x2ca3,
- 0x2ca5, 0x2ca5,
- 0x2ca7, 0x2ca7,
- 0x2ca9, 0x2ca9,
- 0x2cab, 0x2cab,
- 0x2cad, 0x2cad,
- 0x2caf, 0x2caf,
- 0x2cb1, 0x2cb1,
- 0x2cb3, 0x2cb3,
- 0x2cb5, 0x2cb5,
- 0x2cb7, 0x2cb7,
- 0x2cb9, 0x2cb9,
- 0x2cbb, 0x2cbb,
- 0x2cbd, 0x2cbd,
- 0x2cbf, 0x2cbf,
- 0x2cc1, 0x2cc1,
- 0x2cc3, 0x2cc3,
- 0x2cc5, 0x2cc5,
- 0x2cc7, 0x2cc7,
- 0x2cc9, 0x2cc9,
- 0x2ccb, 0x2ccb,
- 0x2ccd, 0x2ccd,
- 0x2ccf, 0x2ccf,
- 0x2cd1, 0x2cd1,
- 0x2cd3, 0x2cd3,
- 0x2cd5, 0x2cd5,
- 0x2cd7, 0x2cd7,
- 0x2cd9, 0x2cd9,
- 0x2cdb, 0x2cdb,
- 0x2cdd, 0x2cdd,
- 0x2cdf, 0x2cdf,
- 0x2ce1, 0x2ce1,
- 0x2ce3, 0x2ce3,
- 0x2cec, 0x2cec,
- 0x2cee, 0x2cee,
- 0x2cf3, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa641, 0xa641,
- 0xa643, 0xa643,
- 0xa645, 0xa645,
- 0xa647, 0xa647,
- 0xa649, 0xa649,
- 0xa64b, 0xa64b,
- 0xa64d, 0xa64d,
- 0xa64f, 0xa64f,
- 0xa651, 0xa651,
- 0xa653, 0xa653,
- 0xa655, 0xa655,
- 0xa657, 0xa657,
- 0xa659, 0xa659,
- 0xa65b, 0xa65b,
- 0xa65d, 0xa65d,
- 0xa65f, 0xa65f,
- 0xa661, 0xa661,
- 0xa663, 0xa663,
- 0xa665, 0xa665,
- 0xa667, 0xa667,
- 0xa669, 0xa669,
- 0xa66b, 0xa66b,
- 0xa66d, 0xa66d,
- 0xa681, 0xa681,
- 0xa683, 0xa683,
- 0xa685, 0xa685,
- 0xa687, 0xa687,
- 0xa689, 0xa689,
- 0xa68b, 0xa68b,
- 0xa68d, 0xa68d,
- 0xa68f, 0xa68f,
- 0xa691, 0xa691,
- 0xa693, 0xa693,
- 0xa695, 0xa695,
- 0xa697, 0xa697,
- 0xa699, 0xa699,
- 0xa69b, 0xa69b,
- 0xa723, 0xa723,
- 0xa725, 0xa725,
- 0xa727, 0xa727,
- 0xa729, 0xa729,
- 0xa72b, 0xa72b,
- 0xa72d, 0xa72d,
- 0xa72f, 0xa72f,
- 0xa733, 0xa733,
- 0xa735, 0xa735,
- 0xa737, 0xa737,
- 0xa739, 0xa739,
- 0xa73b, 0xa73b,
- 0xa73d, 0xa73d,
- 0xa73f, 0xa73f,
- 0xa741, 0xa741,
- 0xa743, 0xa743,
- 0xa745, 0xa745,
- 0xa747, 0xa747,
- 0xa749, 0xa749,
- 0xa74b, 0xa74b,
- 0xa74d, 0xa74d,
- 0xa74f, 0xa74f,
- 0xa751, 0xa751,
- 0xa753, 0xa753,
- 0xa755, 0xa755,
- 0xa757, 0xa757,
- 0xa759, 0xa759,
- 0xa75b, 0xa75b,
- 0xa75d, 0xa75d,
- 0xa75f, 0xa75f,
- 0xa761, 0xa761,
- 0xa763, 0xa763,
- 0xa765, 0xa765,
- 0xa767, 0xa767,
- 0xa769, 0xa769,
- 0xa76b, 0xa76b,
- 0xa76d, 0xa76d,
- 0xa76f, 0xa76f,
- 0xa77a, 0xa77a,
- 0xa77c, 0xa77c,
- 0xa77f, 0xa77f,
- 0xa781, 0xa781,
- 0xa783, 0xa783,
- 0xa785, 0xa785,
- 0xa787, 0xa787,
- 0xa78c, 0xa78c,
- 0xa791, 0xa791,
- 0xa793, 0xa794,
- 0xa797, 0xa797,
- 0xa799, 0xa799,
- 0xa79b, 0xa79b,
- 0xa79d, 0xa79d,
- 0xa79f, 0xa79f,
- 0xa7a1, 0xa7a1,
- 0xa7a3, 0xa7a3,
- 0xa7a5, 0xa7a5,
- 0xa7a7, 0xa7a7,
- 0xa7a9, 0xa7a9,
- 0xa7b5, 0xa7b5,
- 0xa7b7, 0xa7b7,
- 0xa7b9, 0xa7b9,
- 0xa7bb, 0xa7bb,
- 0xa7bd, 0xa7bd,
- 0xa7bf, 0xa7bf,
- 0xa7c1, 0xa7c1,
- 0xa7c3, 0xa7c3,
- 0xa7c8, 0xa7c8,
- 0xa7ca, 0xa7ca,
- 0xa7d1, 0xa7d1,
- 0xa7d7, 0xa7d7,
- 0xa7d9, 0xa7d9,
- 0xa7f6, 0xa7f6,
- 0xab53, 0xab53,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x104d8, 0x104fb,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10cc0, 0x10cf2,
- 0x118c0, 0x118df,
- 0x16e60, 0x16e7f,
- 0x1e922, 0x1e943,
-}; /* CR_Changes_When_Titlecased */
-
-/* 'Changes_When_Casefolded': Derived Property */
-static const OnigCodePoint CR_Changes_When_Casefolded[] = {
- 622,
- 0x0041, 0x005a,
- 0x00b5, 0x00b5,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00df,
- 0x0100, 0x0100,
- 0x0102, 0x0102,
- 0x0104, 0x0104,
- 0x0106, 0x0106,
- 0x0108, 0x0108,
- 0x010a, 0x010a,
- 0x010c, 0x010c,
- 0x010e, 0x010e,
- 0x0110, 0x0110,
- 0x0112, 0x0112,
- 0x0114, 0x0114,
- 0x0116, 0x0116,
- 0x0118, 0x0118,
- 0x011a, 0x011a,
- 0x011c, 0x011c,
- 0x011e, 0x011e,
- 0x0120, 0x0120,
- 0x0122, 0x0122,
- 0x0124, 0x0124,
- 0x0126, 0x0126,
- 0x0128, 0x0128,
- 0x012a, 0x012a,
- 0x012c, 0x012c,
- 0x012e, 0x012e,
- 0x0130, 0x0130,
- 0x0132, 0x0132,
- 0x0134, 0x0134,
- 0x0136, 0x0136,
- 0x0139, 0x0139,
- 0x013b, 0x013b,
- 0x013d, 0x013d,
- 0x013f, 0x013f,
- 0x0141, 0x0141,
- 0x0143, 0x0143,
- 0x0145, 0x0145,
- 0x0147, 0x0147,
- 0x0149, 0x014a,
- 0x014c, 0x014c,
- 0x014e, 0x014e,
- 0x0150, 0x0150,
- 0x0152, 0x0152,
- 0x0154, 0x0154,
- 0x0156, 0x0156,
- 0x0158, 0x0158,
- 0x015a, 0x015a,
- 0x015c, 0x015c,
- 0x015e, 0x015e,
- 0x0160, 0x0160,
- 0x0162, 0x0162,
- 0x0164, 0x0164,
- 0x0166, 0x0166,
- 0x0168, 0x0168,
- 0x016a, 0x016a,
- 0x016c, 0x016c,
- 0x016e, 0x016e,
- 0x0170, 0x0170,
- 0x0172, 0x0172,
- 0x0174, 0x0174,
- 0x0176, 0x0176,
- 0x0178, 0x0179,
- 0x017b, 0x017b,
- 0x017d, 0x017d,
- 0x017f, 0x017f,
- 0x0181, 0x0182,
- 0x0184, 0x0184,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a2, 0x01a2,
- 0x01a4, 0x01a4,
- 0x01a6, 0x01a7,
- 0x01a9, 0x01a9,
- 0x01ac, 0x01ac,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b5, 0x01b5,
- 0x01b7, 0x01b8,
- 0x01bc, 0x01bc,
- 0x01c4, 0x01c5,
- 0x01c7, 0x01c8,
- 0x01ca, 0x01cb,
- 0x01cd, 0x01cd,
- 0x01cf, 0x01cf,
- 0x01d1, 0x01d1,
- 0x01d3, 0x01d3,
- 0x01d5, 0x01d5,
- 0x01d7, 0x01d7,
- 0x01d9, 0x01d9,
- 0x01db, 0x01db,
- 0x01de, 0x01de,
- 0x01e0, 0x01e0,
- 0x01e2, 0x01e2,
- 0x01e4, 0x01e4,
- 0x01e6, 0x01e6,
- 0x01e8, 0x01e8,
- 0x01ea, 0x01ea,
- 0x01ec, 0x01ec,
- 0x01ee, 0x01ee,
- 0x01f1, 0x01f2,
- 0x01f4, 0x01f4,
- 0x01f6, 0x01f8,
- 0x01fa, 0x01fa,
- 0x01fc, 0x01fc,
- 0x01fe, 0x01fe,
- 0x0200, 0x0200,
- 0x0202, 0x0202,
- 0x0204, 0x0204,
- 0x0206, 0x0206,
- 0x0208, 0x0208,
- 0x020a, 0x020a,
- 0x020c, 0x020c,
- 0x020e, 0x020e,
- 0x0210, 0x0210,
- 0x0212, 0x0212,
- 0x0214, 0x0214,
- 0x0216, 0x0216,
- 0x0218, 0x0218,
- 0x021a, 0x021a,
- 0x021c, 0x021c,
- 0x021e, 0x021e,
- 0x0220, 0x0220,
- 0x0222, 0x0222,
- 0x0224, 0x0224,
- 0x0226, 0x0226,
- 0x0228, 0x0228,
- 0x022a, 0x022a,
- 0x022c, 0x022c,
- 0x022e, 0x022e,
- 0x0230, 0x0230,
- 0x0232, 0x0232,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0241, 0x0241,
- 0x0243, 0x0246,
- 0x0248, 0x0248,
- 0x024a, 0x024a,
- 0x024c, 0x024c,
- 0x024e, 0x024e,
- 0x0345, 0x0345,
- 0x0370, 0x0370,
- 0x0372, 0x0372,
- 0x0376, 0x0376,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03c2, 0x03c2,
- 0x03cf, 0x03d1,
- 0x03d5, 0x03d6,
- 0x03d8, 0x03d8,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03e2,
- 0x03e4, 0x03e4,
- 0x03e6, 0x03e6,
- 0x03e8, 0x03e8,
- 0x03ea, 0x03ea,
- 0x03ec, 0x03ec,
- 0x03ee, 0x03ee,
- 0x03f0, 0x03f1,
- 0x03f4, 0x03f5,
- 0x03f7, 0x03f7,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x0460, 0x0460,
- 0x0462, 0x0462,
- 0x0464, 0x0464,
- 0x0466, 0x0466,
- 0x0468, 0x0468,
- 0x046a, 0x046a,
- 0x046c, 0x046c,
- 0x046e, 0x046e,
- 0x0470, 0x0470,
- 0x0472, 0x0472,
- 0x0474, 0x0474,
- 0x0476, 0x0476,
- 0x0478, 0x0478,
- 0x047a, 0x047a,
- 0x047c, 0x047c,
- 0x047e, 0x047e,
- 0x0480, 0x0480,
- 0x048a, 0x048a,
- 0x048c, 0x048c,
- 0x048e, 0x048e,
- 0x0490, 0x0490,
- 0x0492, 0x0492,
- 0x0494, 0x0494,
- 0x0496, 0x0496,
- 0x0498, 0x0498,
- 0x049a, 0x049a,
- 0x049c, 0x049c,
- 0x049e, 0x049e,
- 0x04a0, 0x04a0,
- 0x04a2, 0x04a2,
- 0x04a4, 0x04a4,
- 0x04a6, 0x04a6,
- 0x04a8, 0x04a8,
- 0x04aa, 0x04aa,
- 0x04ac, 0x04ac,
- 0x04ae, 0x04ae,
- 0x04b0, 0x04b0,
- 0x04b2, 0x04b2,
- 0x04b4, 0x04b4,
- 0x04b6, 0x04b6,
- 0x04b8, 0x04b8,
- 0x04ba, 0x04ba,
- 0x04bc, 0x04bc,
- 0x04be, 0x04be,
- 0x04c0, 0x04c1,
- 0x04c3, 0x04c3,
- 0x04c5, 0x04c5,
- 0x04c7, 0x04c7,
- 0x04c9, 0x04c9,
- 0x04cb, 0x04cb,
- 0x04cd, 0x04cd,
- 0x04d0, 0x04d0,
- 0x04d2, 0x04d2,
- 0x04d4, 0x04d4,
- 0x04d6, 0x04d6,
- 0x04d8, 0x04d8,
- 0x04da, 0x04da,
- 0x04dc, 0x04dc,
- 0x04de, 0x04de,
- 0x04e0, 0x04e0,
- 0x04e2, 0x04e2,
- 0x04e4, 0x04e4,
- 0x04e6, 0x04e6,
- 0x04e8, 0x04e8,
- 0x04ea, 0x04ea,
- 0x04ec, 0x04ec,
- 0x04ee, 0x04ee,
- 0x04f0, 0x04f0,
- 0x04f2, 0x04f2,
- 0x04f4, 0x04f4,
- 0x04f6, 0x04f6,
- 0x04f8, 0x04f8,
- 0x04fa, 0x04fa,
- 0x04fc, 0x04fc,
- 0x04fe, 0x04fe,
- 0x0500, 0x0500,
- 0x0502, 0x0502,
- 0x0504, 0x0504,
- 0x0506, 0x0506,
- 0x0508, 0x0508,
- 0x050a, 0x050a,
- 0x050c, 0x050c,
- 0x050e, 0x050e,
- 0x0510, 0x0510,
- 0x0512, 0x0512,
- 0x0514, 0x0514,
- 0x0516, 0x0516,
- 0x0518, 0x0518,
- 0x051a, 0x051a,
- 0x051c, 0x051c,
- 0x051e, 0x051e,
- 0x0520, 0x0520,
- 0x0522, 0x0522,
- 0x0524, 0x0524,
- 0x0526, 0x0526,
- 0x0528, 0x0528,
- 0x052a, 0x052a,
- 0x052c, 0x052c,
- 0x052e, 0x052e,
- 0x0531, 0x0556,
- 0x0587, 0x0587,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 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,
- 0x1e9a, 0x1e9b,
- 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,
- 0x1f80, 0x1faf,
- 0x1fb2, 0x1fb4,
- 0x1fb7, 0x1fbc,
- 0x1fc2, 0x1fc4,
- 0x1fc7, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff2, 0x1ff4,
- 0x1ff7, 0x1ffc,
- 0x2126, 0x2126,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 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,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x104b0, 0x104d3,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10c80, 0x10cb2,
- 0x118a0, 0x118bf,
- 0x16e40, 0x16e5f,
- 0x1e900, 0x1e921,
-}; /* CR_Changes_When_Casefolded */
-
-/* 'Changes_When_Casemapped': Derived Property */
-static const OnigCodePoint CR_Changes_When_Casemapped[] = {
- 131,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00b5, 0x00b5,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x0137,
- 0x0139, 0x018c,
- 0x018e, 0x019a,
- 0x019c, 0x01a9,
- 0x01ac, 0x01b9,
- 0x01bc, 0x01bd,
- 0x01bf, 0x01bf,
- 0x01c4, 0x0220,
- 0x0222, 0x0233,
- 0x023a, 0x0254,
- 0x0256, 0x0257,
- 0x0259, 0x0259,
- 0x025b, 0x025c,
- 0x0260, 0x0261,
- 0x0263, 0x0263,
- 0x0265, 0x0266,
- 0x0268, 0x026c,
- 0x026f, 0x026f,
- 0x0271, 0x0272,
- 0x0275, 0x0275,
- 0x027d, 0x027d,
- 0x0280, 0x0280,
- 0x0282, 0x0283,
- 0x0287, 0x028c,
- 0x0292, 0x0292,
- 0x029d, 0x029e,
- 0x0345, 0x0345,
- 0x0370, 0x0373,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03d1,
- 0x03d5, 0x03f5,
- 0x03f7, 0x03fb,
- 0x03fd, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0561, 0x0587,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fd, 0x10ff,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1d79, 0x1d79,
- 0x1d7d, 0x1d7d,
- 0x1d8e, 0x1d8e,
- 0x1e00, 0x1e9b,
- 0x1e9e, 0x1e9e,
- 0x1ea0, 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,
- 0x2126, 0x2126,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 0x214e, 0x214e,
- 0x2160, 0x217f,
- 0x2183, 0x2184,
- 0x24b6, 0x24e9,
- 0x2c00, 0x2c70,
- 0x2c72, 0x2c73,
- 0x2c75, 0x2c76,
- 0x2c7e, 0x2ce3,
- 0x2ceb, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0xa640, 0xa66d,
- 0xa680, 0xa69b,
- 0xa722, 0xa72f,
- 0xa732, 0xa76f,
- 0xa779, 0xa787,
- 0xa78b, 0xa78d,
- 0xa790, 0xa794,
- 0xa796, 0xa7ae,
- 0xa7b0, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d6, 0xa7d9,
- 0xa7f5, 0xa7f6,
- 0xab53, 0xab53,
- 0xab70, 0xabbf,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10400, 0x1044f,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x118a0, 0x118df,
- 0x16e40, 0x16e7f,
- 0x1e900, 0x1e943,
-}; /* CR_Changes_When_Casemapped */
-
-/* 'ID_Start': Derived Property */
-static const OnigCodePoint CR_ID_Start[] = {
- 660,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0971, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 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, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dc,
- 0x1820, 0x1878,
- 0x1880, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1aa7, 0x1aa7,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 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,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 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,
- 0x3005, 0x3007,
- 0x3021, 0x3029,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x309b, 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,
- 0xa67f, 0xa69d,
- 0xa6a0, 0xa6ef,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9cf, 0xa9cf,
- 0xa9e0, 0xa9e4,
- 0xa9e6, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf4,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 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, 0x10375,
- 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, 0x10a00,
- 0x10a10, 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, 0x10d23,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118a0, 0x118df,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 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,
- 0x16f50, 0x16f50,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 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,
- 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,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4eb,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e900, 0x1e943,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_ID_Start */
-
-/* 'ID_Continue': Derived Property */
-static const OnigCodePoint CR_ID_Continue[] = {
- 769,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x005f, 0x005f,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00b7, 0x00b7,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0300, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x0483, 0x0487,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06df, 0x06e8,
- 0x06ea, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0800, 0x082d,
- 0x0840, 0x085b,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0898, 0x08e1,
- 0x08e3, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e4e,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f18, 0x0f19,
- 0x0f20, 0x0f29,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x1000, 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,
- 0x135d, 0x135f,
- 0x1369, 0x1371,
- 0x1380, 0x138f,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1734,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dd,
- 0x17e0, 0x17e9,
- 0x180b, 0x180d,
- 0x180f, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1946, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x1a00, 0x1a1b,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b59,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1bf3,
- 0x1c00, 0x1c37,
- 0x1c40, 0x1c49,
- 0x1c4d, 0x1c7d,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1cfa,
- 0x1d00, 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,
- 0x200c, 0x200d,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 0x2c00, 0x2ce4,
- 0x2ceb, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2dff,
- 0x3005, 0x3007,
- 0x3021, 0x302f,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x3099, 0x309f,
- 0x30a1, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x31a0, 0x31bf,
- 0x31f0, 0x31ff,
- 0x3400, 0x4dbf,
- 0x4e00, 0xa48c,
- 0xa4d0, 0xa4fd,
- 0xa500, 0xa60c,
- 0xa610, 0xa62b,
- 0xa640, 0xa66f,
- 0xa674, 0xa67d,
- 0xa67f, 0xa6f1,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa827,
- 0xa82c, 0xa82c,
- 0xa840, 0xa873,
- 0xa880, 0xa8c5,
- 0xa8d0, 0xa8d9,
- 0xa8e0, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa92d,
- 0xa930, 0xa953,
- 0xa960, 0xa97c,
- 0xa980, 0xa9c0,
- 0xa9cf, 0xa9d9,
- 0xa9e0, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaef,
- 0xaaf2, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabea,
- 0xabec, 0xabed,
- 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,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff10, 0xff19,
- 0xff21, 0xff3a,
- 0xff3f, 0xff3f,
- 0xff41, 0xff5a,
- 0xff65, 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,
- 0x101fd, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102e0,
- 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,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae6,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f50,
- 0x10f70, 0x10f85,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11046,
- 0x11066, 0x11075,
- 0x1107f, 0x110ba,
- 0x110c2, 0x110c2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x1113f,
- 0x11144, 0x11147,
- 0x11150, 0x11173,
- 0x11176, 0x11176,
- 0x11180, 0x111c4,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x11237,
- 0x1123e, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1144a,
- 0x11450, 0x11459,
- 0x1145e, 0x11461,
- 0x11480, 0x114c5,
- 0x114c7, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115d8, 0x115dd,
- 0x11600, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x1183a,
- 0x118a0, 0x118e9,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11943,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e1,
- 0x119e3, 0x119e4,
- 0x11a00, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a50, 0x11a99,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c40,
- 0x11c50, 0x11c59,
- 0x11c72, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef6,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f50, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13440, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af4,
- 0x16b00, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 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,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 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,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8d0, 0x1e8d6,
- 0x1e900, 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,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0100, 0xe01ef,
-}; /* CR_ID_Continue */
-
-/* 'XID_Start': Derived Property */
-static const OnigCodePoint CR_XID_Start[] = {
- 667,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0620, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06d5, 0x06d5,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x07fa, 0x07fa,
- 0x0800, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0840, 0x0858,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x08a0, 0x08c9,
- 0x0904, 0x0939,
- 0x093d, 0x093d,
- 0x0950, 0x0950,
- 0x0958, 0x0961,
- 0x0971, 0x0980,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x09fc, 0x09fc,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0abd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0af9, 0x0af9,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b71, 0x0b71,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bd0, 0x0bd0,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c80, 0x0c80,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbd,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0cf1, 0x0cf2,
- 0x0d04, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d4e, 0x0d4e,
- 0x0d54, 0x0d56,
- 0x0d5f, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e32,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb2,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8c,
- 0x1000, 0x102a,
- 0x103f, 0x103f,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1061, 0x1061,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x108e, 0x108e,
- 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, 0x1711,
- 0x171f, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dc,
- 0x1820, 0x1878,
- 0x1880, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1aa7, 0x1aa7,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4c,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1bba, 0x1be5,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf6,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 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,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 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,
- 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,
- 0xa67f, 0xa69d,
- 0xa6a0, 0xa6ef,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa8fe,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xa9cf, 0xa9cf,
- 0xa9e0, 0xa9e4,
- 0xa9e6, 0xa9ef,
- 0xa9fa, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaa7a,
- 0xaa7e, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaea,
- 0xaaf2, 0xaaf4,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 0xfb28,
- 0xfb2a, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfc5d,
- 0xfc64, 0xfd3d,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdf9,
- 0xfe71, 0xfe71,
- 0xfe73, 0xfe73,
- 0xfe77, 0xfe77,
- 0xfe79, 0xfe79,
- 0xfe7b, 0xfe7b,
- 0xfe7d, 0xfe7d,
- 0xfe7f, 0xfefc,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0xff66, 0xff9d,
- 0xffa0, 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, 0x10375,
- 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, 0x10a00,
- 0x10a10, 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, 0x10d23,
- 0x10e80, 0x10ea9,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f70, 0x10f81,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11003, 0x11037,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11083, 0x110af,
- 0x110d0, 0x110e8,
- 0x11103, 0x11126,
- 0x11144, 0x11144,
- 0x11147, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11183, 0x111b2,
- 0x111c1, 0x111c4,
- 0x111da, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x1122b,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112de,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x11350, 0x11350,
- 0x1135d, 0x11361,
- 0x11400, 0x11434,
- 0x11447, 0x1144a,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114c4, 0x114c5,
- 0x114c7, 0x114c7,
- 0x11580, 0x115ae,
- 0x115d8, 0x115db,
- 0x11600, 0x1162f,
- 0x11644, 0x11644,
- 0x11680, 0x116aa,
- 0x116b8, 0x116b8,
- 0x11700, 0x1171a,
- 0x11740, 0x11746,
- 0x11800, 0x1182b,
- 0x118a0, 0x118df,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d0,
- 0x119e1, 0x119e1,
- 0x119e3, 0x119e3,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a3a, 0x11a3a,
- 0x11a50, 0x11a50,
- 0x11a5c, 0x11a89,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2e,
- 0x11c40, 0x11c40,
- 0x11c72, 0x11c8f,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d89,
- 0x11d98, 0x11d98,
- 0x11ee0, 0x11ef2,
- 0x11f02, 0x11f02,
- 0x11f04, 0x11f10,
- 0x11f12, 0x11f33,
- 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,
- 0x16f50, 0x16f50,
- 0x16f93, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 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,
- 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,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e4d0, 0x1e4eb,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e900, 0x1e943,
- 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,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_XID_Start */
-
-/* 'XID_Continue': Derived Property */
-static const OnigCodePoint CR_XID_Continue[] = {
- 776,
- 0x0030, 0x0039,
- 0x0041, 0x005a,
- 0x005f, 0x005f,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00b5, 0x00b5,
- 0x00b7, 0x00b7,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x02ec, 0x02ec,
- 0x02ee, 0x02ee,
- 0x0300, 0x0374,
- 0x0376, 0x0377,
- 0x037b, 0x037d,
- 0x037f, 0x037f,
- 0x0386, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x0483, 0x0487,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x0559,
- 0x0560, 0x0588,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f2,
- 0x0610, 0x061a,
- 0x0620, 0x0669,
- 0x066e, 0x06d3,
- 0x06d5, 0x06dc,
- 0x06df, 0x06e8,
- 0x06ea, 0x06fc,
- 0x06ff, 0x06ff,
- 0x0710, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07f5,
- 0x07fa, 0x07fa,
- 0x07fd, 0x07fd,
- 0x0800, 0x082d,
- 0x0840, 0x085b,
- 0x0860, 0x086a,
- 0x0870, 0x0887,
- 0x0889, 0x088e,
- 0x0898, 0x08e1,
- 0x08e3, 0x0963,
- 0x0966, 0x096f,
- 0x0971, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09f1,
- 0x09fc, 0x09fc,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b6f,
- 0x0b71, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bef,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c80, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d54, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d6f,
- 0x0d7a, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df3,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e4e,
- 0x0e50, 0x0e59,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f00,
- 0x0f18, 0x0f19,
- 0x0f20, 0x0f29,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f84,
- 0x0f86, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x1000, 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,
- 0x135d, 0x135f,
- 0x1369, 0x1371,
- 0x1380, 0x138f,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1734,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17d3,
- 0x17d7, 0x17d7,
- 0x17dc, 0x17dd,
- 0x17e0, 0x17e9,
- 0x180b, 0x180d,
- 0x180f, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1946, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x1a00, 0x1a1b,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa7, 0x1aa7,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b59,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1bf3,
- 0x1c00, 0x1c37,
- 0x1c40, 0x1c49,
- 0x1c4d, 0x1c7d,
- 0x1c80, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1cfa,
- 0x1d00, 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,
- 0x200c, 0x200d,
- 0x203f, 0x2040,
- 0x2054, 0x2054,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2118, 0x211d,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212a, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 0x2c00, 0x2ce4,
- 0x2ceb, 0x2cf3,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d6f,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2dff,
- 0x3005, 0x3007,
- 0x3021, 0x302f,
- 0x3031, 0x3035,
- 0x3038, 0x303c,
- 0x3041, 0x3096,
- 0x3099, 0x309a,
- 0x309d, 0x309f,
- 0x30a1, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x31a0, 0x31bf,
- 0x31f0, 0x31ff,
- 0x3400, 0x4dbf,
- 0x4e00, 0xa48c,
- 0xa4d0, 0xa4fd,
- 0xa500, 0xa60c,
- 0xa610, 0xa62b,
- 0xa640, 0xa66f,
- 0xa674, 0xa67d,
- 0xa67f, 0xa6f1,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa827,
- 0xa82c, 0xa82c,
- 0xa840, 0xa873,
- 0xa880, 0xa8c5,
- 0xa8d0, 0xa8d9,
- 0xa8e0, 0xa8f7,
- 0xa8fb, 0xa8fb,
- 0xa8fd, 0xa92d,
- 0xa930, 0xa953,
- 0xa960, 0xa97c,
- 0xa980, 0xa9c0,
- 0xa9cf, 0xa9d9,
- 0xa9e0, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa60, 0xaa76,
- 0xaa7a, 0xaac2,
- 0xaadb, 0xaadd,
- 0xaae0, 0xaaef,
- 0xaaf2, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5a,
- 0xab5c, 0xab69,
- 0xab70, 0xabea,
- 0xabec, 0xabed,
- 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, 0xfc5d,
- 0xfc64, 0xfd3d,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdf9,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xfe33, 0xfe34,
- 0xfe4d, 0xfe4f,
- 0xfe71, 0xfe71,
- 0xfe73, 0xfe73,
- 0xfe77, 0xfe77,
- 0xfe79, 0xfe79,
- 0xfe7b, 0xfe7b,
- 0xfe7d, 0xfe7d,
- 0xfe7f, 0xfefc,
- 0xff10, 0xff19,
- 0xff21, 0xff3a,
- 0xff3f, 0xff3f,
- 0xff41, 0xff5a,
- 0xff65, 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,
- 0x101fd, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102e0,
- 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,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10a60, 0x10a7c,
- 0x10a80, 0x10a9c,
- 0x10ac0, 0x10ac7,
- 0x10ac9, 0x10ae6,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10b80, 0x10b91,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10eac,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f1c,
- 0x10f27, 0x10f27,
- 0x10f30, 0x10f50,
- 0x10f70, 0x10f85,
- 0x10fb0, 0x10fc4,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11046,
- 0x11066, 0x11075,
- 0x1107f, 0x110ba,
- 0x110c2, 0x110c2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x1113f,
- 0x11144, 0x11147,
- 0x11150, 0x11173,
- 0x11176, 0x11176,
- 0x11180, 0x111c4,
- 0x111c9, 0x111cc,
- 0x111ce, 0x111da,
- 0x111dc, 0x111dc,
- 0x11200, 0x11211,
- 0x11213, 0x11237,
- 0x1123e, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a8,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1144a,
- 0x11450, 0x11459,
- 0x1145e, 0x11461,
- 0x11480, 0x114c5,
- 0x114c7, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c0,
- 0x115d8, 0x115dd,
- 0x11600, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x1183a,
- 0x118a0, 0x118e9,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11943,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e1,
- 0x119e3, 0x119e4,
- 0x11a00, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a50, 0x11a99,
- 0x11a9d, 0x11a9d,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c40,
- 0x11c50, 0x11c59,
- 0x11c72, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef6,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f42,
- 0x11f50, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff0,
- 0x13000, 0x1342f,
- 0x13440, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af4,
- 0x16b00, 0x16b36,
- 0x16b40, 0x16b43,
- 0x16b50, 0x16b59,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e7f,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe4,
- 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,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 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,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14e,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8d0, 0x1e8d6,
- 0x1e900, 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,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
- 0xe0100, 0xe01ef,
-}; /* CR_XID_Continue */
-
-/* 'Default_Ignorable_Code_Point': Derived Property */
-static const OnigCodePoint CR_Default_Ignorable_Code_Point[] = {
- 17,
- 0x00ad, 0x00ad,
- 0x034f, 0x034f,
- 0x061c, 0x061c,
- 0x115f, 0x1160,
- 0x17b4, 0x17b5,
- 0x180b, 0x180f,
- 0x200b, 0x200f,
- 0x202a, 0x202e,
- 0x2060, 0x206f,
- 0x3164, 0x3164,
- 0xfe00, 0xfe0f,
- 0xfeff, 0xfeff,
- 0xffa0, 0xffa0,
- 0xfff0, 0xfff8,
- 0x1bca0, 0x1bca3,
- 0x1d173, 0x1d17a,
- 0xe0000, 0xe0fff,
-}; /* CR_Default_Ignorable_Code_Point */
-
-/* 'Grapheme_Extend': Derived Property */
-static const OnigCodePoint CR_Grapheme_Extend[] = {
- 363,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0898, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09be, 0x09be,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bbe,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cbf,
- 0x0cc2, 0x0cc2,
- 0x0cc6, 0x0cc6,
- 0x0ccc, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d3e,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dcf,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0ddf, 0x0ddf,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1714,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b3a,
- 0x1b3c, 0x1b3c,
- 0x1b42, 0x1b42,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1ba9,
- 0x1bab, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf1,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200c, 0x200c,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xff9e, 0xff9f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11234,
- 0x11236, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x1133e, 0x1133e,
- 0x11340, 0x11340,
- 0x11357, 0x11357,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114b0,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bd, 0x114bd,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115af, 0x115af,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b5,
- 0x116b7, 0x116b7,
- 0x1171d, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x11930, 0x11930,
- 0x1193b, 0x1193c,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f40,
- 0x11f42, 0x11f42,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d165,
- 0x1d167, 0x1d169,
- 0x1d16e, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_Grapheme_Extend */
-
-/* 'Grapheme_Base': Derived Property */
-static const OnigCodePoint CR_Grapheme_Base[] = {
- 875,
- 0x0020, 0x007e,
- 0x00a0, 0x00ac,
- 0x00ae, 0x02ff,
- 0x0370, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0482,
- 0x048a, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x05be, 0x05be,
- 0x05c0, 0x05c0,
- 0x05c3, 0x05c3,
- 0x05c6, 0x05c6,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0606, 0x060f,
- 0x061b, 0x061b,
- 0x061d, 0x064a,
- 0x0660, 0x066f,
- 0x0671, 0x06d5,
- 0x06de, 0x06de,
- 0x06e5, 0x06e6,
- 0x06e9, 0x06e9,
- 0x06ee, 0x070d,
- 0x0710, 0x0710,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07b1, 0x07b1,
- 0x07c0, 0x07ea,
- 0x07f4, 0x07fa,
- 0x07fe, 0x0815,
- 0x081a, 0x081a,
- 0x0824, 0x0824,
- 0x0828, 0x0828,
- 0x0830, 0x083e,
- 0x0840, 0x0858,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x08a0, 0x08c9,
- 0x0903, 0x0939,
- 0x093b, 0x093b,
- 0x093d, 0x0940,
- 0x0949, 0x094c,
- 0x094e, 0x0950,
- 0x0958, 0x0961,
- 0x0964, 0x0980,
- 0x0982, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bd, 0x09bd,
- 0x09bf, 0x09c0,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09ce, 0x09ce,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09e6, 0x09fd,
- 0x0a03, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3e, 0x0a40,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a6f,
- 0x0a72, 0x0a74,
- 0x0a76, 0x0a76,
- 0x0a83, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abd, 0x0ac0,
- 0x0ac9, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae1,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0af9,
- 0x0b02, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3d, 0x0b3d,
- 0x0b40, 0x0b40,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b77,
- 0x0b83, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbf, 0x0bbf,
- 0x0bc1, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd0, 0x0bd0,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c3d,
- 0x0c41, 0x0c44,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c80,
- 0x0c82, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbd, 0x0cbe,
- 0x0cc0, 0x0cc1,
- 0x0cc3, 0x0cc4,
- 0x0cc7, 0x0cc8,
- 0x0cca, 0x0ccb,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d02, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d3d,
- 0x0d3f, 0x0d40,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d4e, 0x0d4f,
- 0x0d54, 0x0d56,
- 0x0d58, 0x0d61,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dd0, 0x0dd1,
- 0x0dd8, 0x0dde,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e3f, 0x0e46,
- 0x0e4f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ebd, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f17,
- 0x0f1a, 0x0f34,
- 0x0f36, 0x0f36,
- 0x0f38, 0x0f38,
- 0x0f3a, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f7f, 0x0f7f,
- 0x0f85, 0x0f85,
- 0x0f88, 0x0f8c,
- 0x0fbe, 0x0fc5,
- 0x0fc7, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x102c,
- 0x1031, 0x1031,
- 0x1038, 0x1038,
- 0x103b, 0x103c,
- 0x103f, 0x1057,
- 0x105a, 0x105d,
- 0x1061, 0x1070,
- 0x1075, 0x1081,
- 0x1083, 0x1084,
- 0x1087, 0x108c,
- 0x108e, 0x109c,
- 0x109e, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x1360, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1711,
- 0x1715, 0x1715,
- 0x171f, 0x1731,
- 0x1734, 0x1736,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x17b6, 0x17b6,
- 0x17be, 0x17c5,
- 0x17c7, 0x17c8,
- 0x17d4, 0x17dc,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180a,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x1884,
- 0x1887, 0x18a8,
- 0x18aa, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1923, 0x1926,
- 0x1929, 0x192b,
- 0x1930, 0x1931,
- 0x1933, 0x1938,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a16,
- 0x1a19, 0x1a1a,
- 0x1a1e, 0x1a55,
- 0x1a57, 0x1a57,
- 0x1a61, 0x1a61,
- 0x1a63, 0x1a64,
- 0x1a6d, 0x1a72,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b04, 0x1b33,
- 0x1b3b, 0x1b3b,
- 0x1b3d, 0x1b41,
- 0x1b43, 0x1b4c,
- 0x1b50, 0x1b6a,
- 0x1b74, 0x1b7e,
- 0x1b82, 0x1ba1,
- 0x1ba6, 0x1ba7,
- 0x1baa, 0x1baa,
- 0x1bae, 0x1be5,
- 0x1be7, 0x1be7,
- 0x1bea, 0x1bec,
- 0x1bee, 0x1bee,
- 0x1bf2, 0x1bf3,
- 0x1bfc, 0x1c2b,
- 0x1c34, 0x1c35,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd3, 0x1cd3,
- 0x1ce1, 0x1ce1,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf7,
- 0x1cfa, 0x1cfa,
- 0x1d00, 0x1dbf,
- 0x1e00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x200a,
- 0x2010, 0x2027,
- 0x202f, 0x205f,
- 0x2070, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cee,
- 0x2cf2, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2e00, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x3029,
- 0x3030, 0x303f,
- 0x3041, 0x3096,
- 0x309b, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa66e,
- 0xa673, 0xa673,
- 0xa67e, 0xa69d,
- 0xa6a0, 0xa6ef,
- 0xa6f2, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa824,
- 0xa827, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c3,
- 0xa8ce, 0xa8d9,
- 0xa8f2, 0xa8fe,
- 0xa900, 0xa925,
- 0xa92e, 0xa946,
- 0xa952, 0xa953,
- 0xa95f, 0xa97c,
- 0xa983, 0xa9b2,
- 0xa9b4, 0xa9b5,
- 0xa9ba, 0xa9bb,
- 0xa9be, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9e4,
- 0xa9e6, 0xa9fe,
- 0xaa00, 0xaa28,
- 0xaa2f, 0xaa30,
- 0xaa33, 0xaa34,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa4d, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa7d, 0xaaaf,
- 0xaab1, 0xaab1,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaac0, 0xaac0,
- 0xaac2, 0xaac2,
- 0xaadb, 0xaaeb,
- 0xaaee, 0xaaf5,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabe4,
- 0xabe6, 0xabe7,
- 0xabe9, 0xabec,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb1d,
- 0xfb1f, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfdff,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff01, 0xff9d,
- 0xffa0, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffc, 0xfffd,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fc,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e1, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x10375,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a00,
- 0x10a10, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a40, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae4,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d23,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10ead, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f45,
- 0x10f51, 0x10f59,
- 0x10f70, 0x10f81,
- 0x10f86, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x11000,
- 0x11002, 0x11037,
- 0x11047, 0x1104d,
- 0x11052, 0x1106f,
- 0x11071, 0x11072,
- 0x11075, 0x11075,
- 0x11082, 0x110b2,
- 0x110b7, 0x110b8,
- 0x110bb, 0x110bc,
- 0x110be, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11103, 0x11126,
- 0x1112c, 0x1112c,
- 0x11136, 0x11147,
- 0x11150, 0x11172,
- 0x11174, 0x11176,
- 0x11182, 0x111b5,
- 0x111bf, 0x111c8,
- 0x111cd, 0x111ce,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1122e,
- 0x11232, 0x11233,
- 0x11235, 0x11235,
- 0x11238, 0x1123d,
- 0x1123f, 0x11240,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112de,
- 0x112e0, 0x112e2,
- 0x112f0, 0x112f9,
- 0x11302, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133d, 0x1133d,
- 0x1133f, 0x1133f,
- 0x11341, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x1135d, 0x11363,
- 0x11400, 0x11437,
- 0x11440, 0x11441,
- 0x11445, 0x11445,
- 0x11447, 0x1145b,
- 0x1145d, 0x1145d,
- 0x1145f, 0x11461,
- 0x11480, 0x114af,
- 0x114b1, 0x114b2,
- 0x114b9, 0x114b9,
- 0x114bb, 0x114bc,
- 0x114be, 0x114be,
- 0x114c1, 0x114c1,
- 0x114c4, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115ae,
- 0x115b0, 0x115b1,
- 0x115b8, 0x115bb,
- 0x115be, 0x115be,
- 0x115c1, 0x115db,
- 0x11600, 0x11632,
- 0x1163b, 0x1163c,
- 0x1163e, 0x1163e,
- 0x11641, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116aa,
- 0x116ac, 0x116ac,
- 0x116ae, 0x116af,
- 0x116b6, 0x116b6,
- 0x116b8, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x11720, 0x11721,
- 0x11726, 0x11726,
- 0x11730, 0x11746,
- 0x11800, 0x1182e,
- 0x11838, 0x11838,
- 0x1183b, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x1192f,
- 0x11931, 0x11935,
- 0x11937, 0x11938,
- 0x1193d, 0x1193d,
- 0x1193f, 0x11942,
- 0x11944, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d3,
- 0x119dc, 0x119df,
- 0x119e1, 0x119e4,
- 0x11a00, 0x11a00,
- 0x11a0b, 0x11a32,
- 0x11a39, 0x11a3a,
- 0x11a3f, 0x11a46,
- 0x11a50, 0x11a50,
- 0x11a57, 0x11a58,
- 0x11a5c, 0x11a89,
- 0x11a97, 0x11a97,
- 0x11a9a, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c2f,
- 0x11c3e, 0x11c3e,
- 0x11c40, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11ca9, 0x11ca9,
- 0x11cb1, 0x11cb1,
- 0x11cb4, 0x11cb4,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d30,
- 0x11d46, 0x11d46,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d93, 0x11d94,
- 0x11d96, 0x11d96,
- 0x11d98, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef2,
- 0x11ef5, 0x11ef8,
- 0x11f02, 0x11f10,
- 0x11f12, 0x11f35,
- 0x11f3e, 0x11f3f,
- 0x11f41, 0x11f41,
- 0x11f43, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x1342f,
- 0x13441, 0x13446,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af5, 0x16af5,
- 0x16b00, 0x16b2f,
- 0x16b37, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f50, 0x16f87,
- 0x16f93, 0x16f9f,
- 0x16fe0, 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,
- 0x1bc9c, 0x1bc9c,
- 0x1bc9f, 0x1bc9f,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d164,
- 0x1d166, 0x1d166,
- 0x1d16a, 0x1d16d,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d200, 0x1d241,
- 0x1d245, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d9ff,
- 0x1da37, 0x1da3a,
- 0x1da6d, 0x1da74,
- 0x1da76, 0x1da83,
- 0x1da85, 0x1da8b,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e030, 0x1e06d,
- 0x1e100, 0x1e12c,
- 0x1e137, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ad,
- 0x1e2c0, 0x1e2eb,
- 0x1e2f0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4eb,
- 0x1e4f0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8cf,
- 0x1e900, 0x1e943,
- 0x1e94b, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Grapheme_Base */
-
-/* 'Grapheme_Link': Derived Property */
-static const OnigCodePoint CR_Grapheme_Link[] = {
- 56,
- 0x094d, 0x094d,
- 0x09cd, 0x09cd,
- 0x0a4d, 0x0a4d,
- 0x0acd, 0x0acd,
- 0x0b4d, 0x0b4d,
- 0x0bcd, 0x0bcd,
- 0x0c4d, 0x0c4d,
- 0x0ccd, 0x0ccd,
- 0x0d3b, 0x0d3c,
- 0x0d4d, 0x0d4d,
- 0x0dca, 0x0dca,
- 0x0e3a, 0x0e3a,
- 0x0eba, 0x0eba,
- 0x0f84, 0x0f84,
- 0x1039, 0x103a,
- 0x1714, 0x1715,
- 0x1734, 0x1734,
- 0x17d2, 0x17d2,
- 0x1a60, 0x1a60,
- 0x1b44, 0x1b44,
- 0x1baa, 0x1bab,
- 0x1bf2, 0x1bf3,
- 0x2d7f, 0x2d7f,
- 0xa806, 0xa806,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c4,
- 0xa953, 0xa953,
- 0xa9c0, 0xa9c0,
- 0xaaf6, 0xaaf6,
- 0xabed, 0xabed,
- 0x10a3f, 0x10a3f,
- 0x11046, 0x11046,
- 0x11070, 0x11070,
- 0x1107f, 0x1107f,
- 0x110b9, 0x110b9,
- 0x11133, 0x11134,
- 0x111c0, 0x111c0,
- 0x11235, 0x11235,
- 0x112ea, 0x112ea,
- 0x1134d, 0x1134d,
- 0x11442, 0x11442,
- 0x114c2, 0x114c2,
- 0x115bf, 0x115bf,
- 0x1163f, 0x1163f,
- 0x116b6, 0x116b6,
- 0x1172b, 0x1172b,
- 0x11839, 0x11839,
- 0x1193d, 0x1193e,
- 0x119e0, 0x119e0,
- 0x11a34, 0x11a34,
- 0x11a47, 0x11a47,
- 0x11a99, 0x11a99,
- 0x11c3f, 0x11c3f,
- 0x11d44, 0x11d45,
- 0x11d97, 0x11d97,
- 0x11f41, 0x11f42,
-}; /* CR_Grapheme_Link */
-
-/* 'InCB_Linker': Derived Property */
-static const OnigCodePoint CR_InCB_Linker[] = {
- 6,
- 0x094d, 0x094d,
- 0x09cd, 0x09cd,
- 0x0acd, 0x0acd,
- 0x0b4d, 0x0b4d,
- 0x0c4d, 0x0c4d,
- 0x0d4d, 0x0d4d,
-}; /* CR_InCB_Linker */
-
-/* 'InCB_Consonant': Derived Property */
-static const OnigCodePoint CR_InCB_Consonant[] = {
- 26,
- 0x0915, 0x0939,
- 0x0958, 0x095f,
- 0x0978, 0x097f,
- 0x0995, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09dc, 0x09dd,
- 0x09df, 0x09df,
- 0x09f0, 0x09f1,
- 0x0a95, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0af9, 0x0af9,
- 0x0b15, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b5f,
- 0x0b71, 0x0b71,
- 0x0c15, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c58, 0x0c5a,
- 0x0d15, 0x0d3a,
-}; /* CR_InCB_Consonant */
-
-/* 'InCB_Extend': Derived Property */
-static const OnigCodePoint CR_InCB_Extend[] = {
- 169,
- 0x0300, 0x034e,
- 0x0350, 0x036f,
- 0x0483, 0x0487,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0898, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x08ff,
- 0x093c, 0x093c,
- 0x0951, 0x0954,
- 0x09bc, 0x09bc,
- 0x09fe, 0x09fe,
- 0x0a3c, 0x0a3c,
- 0x0abc, 0x0abc,
- 0x0b3c, 0x0b3c,
- 0x0c3c, 0x0c3c,
- 0x0c55, 0x0c56,
- 0x0cbc, 0x0cbc,
- 0x0d3b, 0x0d3c,
- 0x0e38, 0x0e3a,
- 0x0e48, 0x0e4b,
- 0x0eb8, 0x0eba,
- 0x0ec8, 0x0ecb,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f72,
- 0x0f74, 0x0f74,
- 0x0f7a, 0x0f7d,
- 0x0f80, 0x0f80,
- 0x0f82, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0fc6, 0x0fc6,
- 0x1037, 0x1037,
- 0x1039, 0x103a,
- 0x108d, 0x108d,
- 0x135d, 0x135f,
- 0x1714, 0x1714,
- 0x17d2, 0x17d2,
- 0x17dd, 0x17dd,
- 0x18a9, 0x18a9,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a60, 0x1a60,
- 0x1a75, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1abd,
- 0x1abf, 0x1ace,
- 0x1b34, 0x1b34,
- 0x1b6b, 0x1b73,
- 0x1bab, 0x1bab,
- 0x1be6, 0x1be6,
- 0x1c37, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200d, 0x200d,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa66f,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa82c, 0xa82c,
- 0xa8e0, 0xa8f1,
- 0xa92b, 0xa92d,
- 0xa9b3, 0xa9b3,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaf6, 0xaaf6,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe20, 0xfe2f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a0d, 0x10a0d,
- 0x10a0f, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11070, 0x11070,
- 0x1107f, 0x1107f,
- 0x110ba, 0x110ba,
- 0x11100, 0x11102,
- 0x11133, 0x11134,
- 0x11173, 0x11173,
- 0x111ca, 0x111ca,
- 0x11236, 0x11236,
- 0x112e9, 0x112ea,
- 0x1133b, 0x1133c,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114c3, 0x114c3,
- 0x115c0, 0x115c0,
- 0x116b7, 0x116b7,
- 0x1172b, 0x1172b,
- 0x1183a, 0x1183a,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x11a34, 0x11a34,
- 0x11a47, 0x11a47,
- 0x11a99, 0x11a99,
- 0x11d42, 0x11d42,
- 0x11d44, 0x11d45,
- 0x11d97, 0x11d97,
- 0x11f42, 0x11f42,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x1bc9e, 0x1bc9e,
- 0x1d165, 0x1d165,
- 0x1d167, 0x1d169,
- 0x1d16e, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
-}; /* CR_InCB_Extend */
-
-/* 'Common': Script */
-static const OnigCodePoint CR_Common[] = {
- 173,
- 0x0000, 0x0040,
- 0x005b, 0x0060,
- 0x007b, 0x00a9,
- 0x00ab, 0x00b9,
- 0x00bb, 0x00bf,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x02b9, 0x02df,
- 0x02e5, 0x02e9,
- 0x02ec, 0x02ff,
- 0x0374, 0x0374,
- 0x037e, 0x037e,
- 0x0385, 0x0385,
- 0x0387, 0x0387,
- 0x0605, 0x0605,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0640, 0x0640,
- 0x06dd, 0x06dd,
- 0x08e2, 0x08e2,
- 0x0964, 0x0965,
- 0x0e3f, 0x0e3f,
- 0x0fd5, 0x0fd8,
- 0x10fb, 0x10fb,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x1802, 0x1803,
- 0x1805, 0x1805,
- 0x1cd3, 0x1cd3,
- 0x1ce1, 0x1ce1,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf3,
- 0x1cf5, 0x1cf7,
- 0x1cfa, 0x1cfa,
- 0x2000, 0x200b,
- 0x200e, 0x2064,
- 0x2066, 0x2070,
- 0x2074, 0x207e,
- 0x2080, 0x208e,
- 0x20a0, 0x20c0,
- 0x2100, 0x2125,
- 0x2127, 0x2129,
- 0x212c, 0x2131,
- 0x2133, 0x214d,
- 0x214f, 0x215f,
- 0x2189, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x27ff,
- 0x2900, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2bff,
- 0x2e00, 0x2e5d,
- 0x2ff0, 0x3004,
- 0x3006, 0x3006,
- 0x3008, 0x3020,
- 0x3030, 0x3037,
- 0x303c, 0x303f,
- 0x309b, 0x309c,
- 0x30a0, 0x30a0,
- 0x30fb, 0x30fc,
- 0x3190, 0x319f,
- 0x31c0, 0x31e3,
- 0x31ef, 0x31ef,
- 0x3220, 0x325f,
- 0x327f, 0x32cf,
- 0x32ff, 0x32ff,
- 0x3358, 0x33ff,
- 0x4dc0, 0x4dff,
- 0xa700, 0xa721,
- 0xa788, 0xa78a,
- 0xa830, 0xa839,
- 0xa92e, 0xa92e,
- 0xa9cf, 0xa9cf,
- 0xab5b, 0xab5b,
- 0xab6a, 0xab6b,
- 0xfd3e, 0xfd3f,
- 0xfe10, 0xfe19,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfeff, 0xfeff,
- 0xff01, 0xff20,
- 0xff3b, 0xff40,
- 0xff5b, 0xff65,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xfffd,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1013f,
- 0x10190, 0x1019c,
- 0x101d0, 0x101fc,
- 0x102e1, 0x102fb,
- 0x1bca0, 0x1bca3,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d166,
- 0x1d16a, 0x1d17a,
- 0x1d183, 0x1d184,
- 0x1d18c, 0x1d1a9,
- 0x1d1ae, 0x1d1ea,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f1ff,
- 0x1f201, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
-}; /* CR_Common */
-
-/* 'Latin': Script */
-static const OnigCodePoint CR_Latin[] = {
- 39,
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00aa, 0x00aa,
- 0x00ba, 0x00ba,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02b8,
- 0x02e0, 0x02e4,
- 0x1d00, 0x1d25,
- 0x1d2c, 0x1d5c,
- 0x1d62, 0x1d65,
- 0x1d6b, 0x1d77,
- 0x1d79, 0x1dbe,
- 0x1e00, 0x1eff,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x212a, 0x212b,
- 0x2132, 0x2132,
- 0x214e, 0x214e,
- 0x2160, 0x2188,
- 0x2c60, 0x2c7f,
- 0xa722, 0xa787,
- 0xa78b, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa7ff,
- 0xab30, 0xab5a,
- 0xab5c, 0xab64,
- 0xab66, 0xab69,
- 0xfb00, 0xfb06,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
-}; /* CR_Latin */
-
-/* 'Greek': Script */
-static const OnigCodePoint CR_Greek[] = {
- 36,
- 0x0370, 0x0373,
- 0x0375, 0x0377,
- 0x037a, 0x037d,
- 0x037f, 0x037f,
- 0x0384, 0x0384,
- 0x0386, 0x0386,
- 0x0388, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03e1,
- 0x03f0, 0x03ff,
- 0x1d26, 0x1d2a,
- 0x1d5d, 0x1d61,
- 0x1d66, 0x1d6a,
- 0x1dbf, 0x1dbf,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2126, 0x2126,
- 0xab65, 0xab65,
- 0x10140, 0x1018e,
- 0x101a0, 0x101a0,
- 0x1d200, 0x1d245,
-}; /* CR_Greek */
-
-/* 'Cyrillic': Script */
-static const OnigCodePoint CR_Cyrillic[] = {
- 10,
- 0x0400, 0x0484,
- 0x0487, 0x052f,
- 0x1c80, 0x1c88,
- 0x1d2b, 0x1d2b,
- 0x1d78, 0x1d78,
- 0x2de0, 0x2dff,
- 0xa640, 0xa69f,
- 0xfe2e, 0xfe2f,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
-}; /* CR_Cyrillic */
-
-/* 'Armenian': Script */
-static const OnigCodePoint CR_Armenian[] = {
- 4,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0xfb13, 0xfb17,
-}; /* CR_Armenian */
-
-/* 'Hebrew': Script */
-static const OnigCodePoint CR_Hebrew[] = {
- 9,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfb4f,
-}; /* CR_Hebrew */
-
-/* 'Arabic': Script */
-static const OnigCodePoint CR_Arabic[] = {
- 58,
- 0x0600, 0x0604,
- 0x0606, 0x060b,
- 0x060d, 0x061a,
- 0x061c, 0x061e,
- 0x0620, 0x063f,
- 0x0641, 0x064a,
- 0x0656, 0x066f,
- 0x0671, 0x06dc,
- 0x06de, 0x06ff,
- 0x0750, 0x077f,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x08e1,
- 0x08e3, 0x08ff,
- 0xfb50, 0xfbc2,
- 0xfbd3, 0xfd3d,
- 0xfd40, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfdcf,
- 0xfdf0, 0xfdff,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0x10e60, 0x10e7e,
- 0x10efd, 0x10eff,
- 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,
- 0x1eef0, 0x1eef1,
-}; /* CR_Arabic */
-
-/* 'Syriac': Script */
-static const OnigCodePoint CR_Syriac[] = {
- 4,
- 0x0700, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x074f,
- 0x0860, 0x086a,
-}; /* CR_Syriac */
-
-/* 'Thaana': Script */
-static const OnigCodePoint CR_Thaana[] = {
- 1,
- 0x0780, 0x07b1,
-}; /* CR_Thaana */
-
-/* 'Devanagari': Script */
-static const OnigCodePoint CR_Devanagari[] = {
- 5,
- 0x0900, 0x0950,
- 0x0955, 0x0963,
- 0x0966, 0x097f,
- 0xa8e0, 0xa8ff,
- 0x11b00, 0x11b09,
-}; /* CR_Devanagari */
-
-/* 'Bengali': Script */
-static const OnigCodePoint CR_Bengali[] = {
- 14,
- 0x0980, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
-}; /* CR_Bengali */
-
-/* 'Gurmukhi': Script */
-static const OnigCodePoint CR_Gurmukhi[] = {
- 16,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
-}; /* CR_Gurmukhi */
-
-/* 'Gujarati': Script */
-static const OnigCodePoint CR_Gujarati[] = {
- 14,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
-}; /* CR_Gujarati */
-
-/* 'Oriya': Script */
-static const OnigCodePoint CR_Oriya[] = {
- 14,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
-}; /* CR_Oriya */
-
-/* 'Tamil': Script */
-static const OnigCodePoint CR_Tamil[] = {
- 18,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x11fff,
-}; /* CR_Tamil */
-
-/* 'Telugu': Script */
-static const OnigCodePoint CR_Telugu[] = {
- 13,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c7f,
-}; /* CR_Telugu */
-
-/* 'Kannada': Script */
-static const OnigCodePoint CR_Kannada[] = {
- 13,
- 0x0c80, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
-}; /* CR_Kannada */
-
-/* 'Malayalam': Script */
-static const OnigCodePoint CR_Malayalam[] = {
- 7,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
-}; /* CR_Malayalam */
-
-/* 'Sinhala': Script */
-static const OnigCodePoint CR_Sinhala[] = {
- 13,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x111e1, 0x111f4,
-}; /* CR_Sinhala */
-
-/* 'Thai': Script */
-static const OnigCodePoint CR_Thai[] = {
- 2,
- 0x0e01, 0x0e3a,
- 0x0e40, 0x0e5b,
-}; /* CR_Thai */
-
-/* 'Lao': Script */
-static const OnigCodePoint CR_Lao[] = {
- 11,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
-}; /* CR_Lao */
-
-/* 'Tibetan': Script */
-static const OnigCodePoint CR_Tibetan[] = {
- 7,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fd4,
- 0x0fd9, 0x0fda,
-}; /* CR_Tibetan */
-
-/* 'Myanmar': Script */
-static const OnigCodePoint CR_Myanmar[] = {
- 3,
- 0x1000, 0x109f,
- 0xa9e0, 0xa9fe,
- 0xaa60, 0xaa7f,
-}; /* CR_Myanmar */
-
-/* 'Georgian': Script */
-static const OnigCodePoint CR_Georgian[] = {
- 10,
- 0x10a0, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 0x10fa,
- 0x10fc, 0x10ff,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cbf,
- 0x2d00, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
-}; /* CR_Georgian */
-
-/* 'Hangul': Script */
-static const OnigCodePoint CR_Hangul[] = {
- 14,
- 0x1100, 0x11ff,
- 0x302e, 0x302f,
- 0x3131, 0x318e,
- 0x3200, 0x321e,
- 0x3260, 0x327e,
- 0xa960, 0xa97c,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xffa0, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
-}; /* CR_Hangul */
-
-/* 'Ethiopic': Script */
-static const OnigCodePoint CR_Ethiopic[] = {
- 36,
- 0x1200, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
-}; /* CR_Ethiopic */
-
-/* 'Cherokee': Script */
-static const OnigCodePoint CR_Cherokee[] = {
- 3,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0xab70, 0xabbf,
-}; /* CR_Cherokee */
-
-/* 'Canadian_Aboriginal': Script */
-static const OnigCodePoint CR_Canadian_Aboriginal[] = {
- 3,
- 0x1400, 0x167f,
- 0x18b0, 0x18f5,
- 0x11ab0, 0x11abf,
-}; /* CR_Canadian_Aboriginal */
-
-/* 'Ogham': Script */
-static const OnigCodePoint CR_Ogham[] = {
- 1,
- 0x1680, 0x169c,
-}; /* CR_Ogham */
-
-/* 'Runic': Script */
-static const OnigCodePoint CR_Runic[] = {
- 2,
- 0x16a0, 0x16ea,
- 0x16ee, 0x16f8,
-}; /* CR_Runic */
-
-/* 'Khmer': Script */
-static const OnigCodePoint CR_Khmer[] = {
- 4,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x19e0, 0x19ff,
-}; /* CR_Khmer */
-
-/* 'Mongolian': Script */
-static const OnigCodePoint CR_Mongolian[] = {
- 6,
- 0x1800, 0x1801,
- 0x1804, 0x1804,
- 0x1806, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x11660, 0x1166c,
-}; /* CR_Mongolian */
-
-/* 'Hiragana': Script */
-static const OnigCodePoint CR_Hiragana[] = {
- 6,
- 0x3041, 0x3096,
- 0x309d, 0x309f,
- 0x1b001, 0x1b11f,
- 0x1b132, 0x1b132,
- 0x1b150, 0x1b152,
- 0x1f200, 0x1f200,
-}; /* CR_Hiragana */
-
-/* 'Katakana': Script */
-static const OnigCodePoint CR_Katakana[] = {
- 14,
- 0x30a1, 0x30fa,
- 0x30fd, 0x30ff,
- 0x31f0, 0x31ff,
- 0x32d0, 0x32fe,
- 0x3300, 0x3357,
- 0xff66, 0xff6f,
- 0xff71, 0xff9d,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1b000, 0x1b000,
- 0x1b120, 0x1b122,
- 0x1b155, 0x1b155,
- 0x1b164, 0x1b167,
-}; /* CR_Katakana */
-
-/* 'Bopomofo': Script */
-static const OnigCodePoint CR_Bopomofo[] = {
- 3,
- 0x02ea, 0x02eb,
- 0x3105, 0x312f,
- 0x31a0, 0x31bf,
-}; /* CR_Bopomofo */
-
-/* 'Han': Script */
-static const OnigCodePoint CR_Han[] = {
- 22,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x3005, 0x3005,
- 0x3007, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303b,
- 0x3400, 0x4dbf,
- 0x4e00, 0x9fff,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0x16fe2, 0x16fe3,
- 0x16ff0, 0x16ff1,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Han */
-
-/* 'Yi': Script */
-static const OnigCodePoint CR_Yi[] = {
- 2,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
-}; /* CR_Yi */
-
-/* 'Old_Italic': Script */
-static const OnigCodePoint CR_Old_Italic[] = {
- 2,
- 0x10300, 0x10323,
- 0x1032d, 0x1032f,
-}; /* CR_Old_Italic */
-
-/* 'Gothic': Script */
-static const OnigCodePoint CR_Gothic[] = {
- 1,
- 0x10330, 0x1034a,
-}; /* CR_Gothic */
-
-/* 'Deseret': Script */
-static const OnigCodePoint CR_Deseret[] = {
- 1,
- 0x10400, 0x1044f,
-}; /* CR_Deseret */
-
-/* 'Inherited': Script */
-static const OnigCodePoint CR_Inherited[] = {
- 29,
- 0x0300, 0x036f,
- 0x0485, 0x0486,
- 0x064b, 0x0655,
- 0x0670, 0x0670,
- 0x0951, 0x0954,
- 0x1ab0, 0x1ace,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200c, 0x200d,
- 0x20d0, 0x20f0,
- 0x302a, 0x302d,
- 0x3099, 0x309a,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2d,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x1133b, 0x1133b,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0xe0100, 0xe01ef,
-}; /* CR_Inherited */
-
-/* 'Tagalog': Script */
-static const OnigCodePoint CR_Tagalog[] = {
- 2,
- 0x1700, 0x1715,
- 0x171f, 0x171f,
-}; /* CR_Tagalog */
-
-/* 'Hanunoo': Script */
-static const OnigCodePoint CR_Hanunoo[] = {
- 1,
- 0x1720, 0x1734,
-}; /* CR_Hanunoo */
-
-/* 'Buhid': Script */
-static const OnigCodePoint CR_Buhid[] = {
- 1,
- 0x1740, 0x1753,
-}; /* CR_Buhid */
-
-/* 'Tagbanwa': Script */
-static const OnigCodePoint CR_Tagbanwa[] = {
- 3,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
-}; /* CR_Tagbanwa */
-
-/* 'Limbu': Script */
-static const OnigCodePoint CR_Limbu[] = {
- 5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x194f,
-}; /* CR_Limbu */
-
-/* 'Tai_Le': Script */
-static const OnigCodePoint CR_Tai_Le[] = {
- 2,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
-}; /* CR_Tai_Le */
-
-/* 'Linear_B': Script */
-static const OnigCodePoint CR_Linear_B[] = {
- 7,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
-}; /* CR_Linear_B */
-
-/* 'Ugaritic': Script */
-static const OnigCodePoint CR_Ugaritic[] = {
- 2,
- 0x10380, 0x1039d,
- 0x1039f, 0x1039f,
-}; /* CR_Ugaritic */
-
-/* 'Shavian': Script */
-static const OnigCodePoint CR_Shavian[] = {
- 1,
- 0x10450, 0x1047f,
-}; /* CR_Shavian */
-
-/* 'Osmanya': Script */
-static const OnigCodePoint CR_Osmanya[] = {
- 2,
- 0x10480, 0x1049d,
- 0x104a0, 0x104a9,
-}; /* CR_Osmanya */
-
-/* 'Cypriot': Script */
-static const OnigCodePoint CR_Cypriot[] = {
- 6,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
-}; /* CR_Cypriot */
-
-/* 'Braille': Script */
-static const OnigCodePoint CR_Braille[] = {
- 1,
- 0x2800, 0x28ff,
-}; /* CR_Braille */
-
-/* 'Buginese': Script */
-static const OnigCodePoint CR_Buginese[] = {
- 2,
- 0x1a00, 0x1a1b,
- 0x1a1e, 0x1a1f,
-}; /* CR_Buginese */
-
-/* 'Coptic': Script */
-static const OnigCodePoint CR_Coptic[] = {
- 3,
- 0x03e2, 0x03ef,
- 0x2c80, 0x2cf3,
- 0x2cf9, 0x2cff,
-}; /* CR_Coptic */
-
-/* 'New_Tai_Lue': Script */
-static const OnigCodePoint CR_New_Tai_Lue[] = {
- 4,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x19df,
-}; /* CR_New_Tai_Lue */
-
-/* 'Glagolitic': Script */
-static const OnigCodePoint CR_Glagolitic[] = {
- 6,
- 0x2c00, 0x2c5f,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
-}; /* CR_Glagolitic */
-
-/* 'Tifinagh': Script */
-static const OnigCodePoint CR_Tifinagh[] = {
- 3,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d7f,
-}; /* CR_Tifinagh */
-
-/* 'Syloti_Nagri': Script */
-static const OnigCodePoint CR_Syloti_Nagri[] = {
- 1,
- 0xa800, 0xa82c,
-}; /* CR_Syloti_Nagri */
-
-/* 'Old_Persian': Script */
-static const OnigCodePoint CR_Old_Persian[] = {
- 2,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103d5,
-}; /* CR_Old_Persian */
-
-/* 'Kharoshthi': Script */
-static const OnigCodePoint CR_Kharoshthi[] = {
- 8,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
-}; /* CR_Kharoshthi */
-
-/* 'Balinese': Script */
-static const OnigCodePoint CR_Balinese[] = {
- 2,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
-}; /* CR_Balinese */
-
-/* 'Cuneiform': Script */
-static const OnigCodePoint CR_Cuneiform[] = {
- 4,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
-}; /* CR_Cuneiform */
-
-/* 'Phoenician': Script */
-static const OnigCodePoint CR_Phoenician[] = {
- 2,
- 0x10900, 0x1091b,
- 0x1091f, 0x1091f,
-}; /* CR_Phoenician */
-
-/* 'Phags_Pa': Script */
-static const OnigCodePoint CR_Phags_Pa[] = {
- 1,
- 0xa840, 0xa877,
-}; /* CR_Phags_Pa */
-
-/* 'Nko': Script */
-static const OnigCodePoint CR_Nko[] = {
- 2,
- 0x07c0, 0x07fa,
- 0x07fd, 0x07ff,
-}; /* CR_Nko */
-
-/* 'Sundanese': Script */
-static const OnigCodePoint CR_Sundanese[] = {
- 2,
- 0x1b80, 0x1bbf,
- 0x1cc0, 0x1cc7,
-}; /* CR_Sundanese */
-
-/* 'Lepcha': Script */
-static const OnigCodePoint CR_Lepcha[] = {
- 3,
- 0x1c00, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c4f,
-}; /* CR_Lepcha */
-
-/* 'Ol_Chiki': Script */
-static const OnigCodePoint CR_Ol_Chiki[] = {
- 1,
- 0x1c50, 0x1c7f,
-}; /* CR_Ol_Chiki */
-
-/* 'Vai': Script */
-static const OnigCodePoint CR_Vai[] = {
- 1,
- 0xa500, 0xa62b,
-}; /* CR_Vai */
-
-/* 'Saurashtra': Script */
-static const OnigCodePoint CR_Saurashtra[] = {
- 2,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
-}; /* CR_Saurashtra */
-
-/* 'Kayah_Li': Script */
-static const OnigCodePoint CR_Kayah_Li[] = {
- 2,
- 0xa900, 0xa92d,
- 0xa92f, 0xa92f,
-}; /* CR_Kayah_Li */
-
-/* 'Rejang': Script */
-static const OnigCodePoint CR_Rejang[] = {
- 2,
- 0xa930, 0xa953,
- 0xa95f, 0xa95f,
-}; /* CR_Rejang */
-
-/* 'Lycian': Script */
-static const OnigCodePoint CR_Lycian[] = {
- 1,
- 0x10280, 0x1029c,
-}; /* CR_Lycian */
-
-/* 'Carian': Script */
-static const OnigCodePoint CR_Carian[] = {
- 1,
- 0x102a0, 0x102d0,
-}; /* CR_Carian */
-
-/* 'Lydian': Script */
-static const OnigCodePoint CR_Lydian[] = {
- 2,
- 0x10920, 0x10939,
- 0x1093f, 0x1093f,
-}; /* CR_Lydian */
-
-/* 'Cham': Script */
-static const OnigCodePoint CR_Cham[] = {
- 4,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa5f,
-}; /* CR_Cham */
-
-/* 'Tai_Tham': Script */
-static const OnigCodePoint CR_Tai_Tham[] = {
- 5,
- 0x1a20, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
-}; /* CR_Tai_Tham */
-
-/* 'Tai_Viet': Script */
-static const OnigCodePoint CR_Tai_Viet[] = {
- 2,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaadf,
-}; /* CR_Tai_Viet */
-
-/* 'Avestan': Script */
-static const OnigCodePoint CR_Avestan[] = {
- 2,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b3f,
-}; /* CR_Avestan */
-
-/* 'Egyptian_Hieroglyphs': Script */
-static const OnigCodePoint CR_Egyptian_Hieroglyphs[] = {
- 1,
- 0x13000, 0x13455,
-}; /* CR_Egyptian_Hieroglyphs */
-
-/* 'Samaritan': Script */
-static const OnigCodePoint CR_Samaritan[] = {
- 2,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
-}; /* CR_Samaritan */
-
-/* 'Lisu': Script */
-static const OnigCodePoint CR_Lisu[] = {
- 2,
- 0xa4d0, 0xa4ff,
- 0x11fb0, 0x11fb0,
-}; /* CR_Lisu */
-
-/* 'Bamum': Script */
-static const OnigCodePoint CR_Bamum[] = {
- 2,
- 0xa6a0, 0xa6f7,
- 0x16800, 0x16a38,
-}; /* CR_Bamum */
-
-/* 'Javanese': Script */
-static const OnigCodePoint CR_Javanese[] = {
- 3,
- 0xa980, 0xa9cd,
- 0xa9d0, 0xa9d9,
- 0xa9de, 0xa9df,
-}; /* CR_Javanese */
-
-/* 'Meetei_Mayek': Script */
-static const OnigCodePoint CR_Meetei_Mayek[] = {
- 3,
- 0xaae0, 0xaaf6,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
-}; /* CR_Meetei_Mayek */
-
-/* 'Imperial_Aramaic': Script */
-static const OnigCodePoint CR_Imperial_Aramaic[] = {
- 2,
- 0x10840, 0x10855,
- 0x10857, 0x1085f,
-}; /* CR_Imperial_Aramaic */
-
-/* 'Old_South_Arabian': Script */
-static const OnigCodePoint CR_Old_South_Arabian[] = {
- 1,
- 0x10a60, 0x10a7f,
-}; /* CR_Old_South_Arabian */
-
-/* 'Inscriptional_Parthian': Script */
-static const OnigCodePoint CR_Inscriptional_Parthian[] = {
- 2,
- 0x10b40, 0x10b55,
- 0x10b58, 0x10b5f,
-}; /* CR_Inscriptional_Parthian */
-
-/* 'Inscriptional_Pahlavi': Script */
-static const OnigCodePoint CR_Inscriptional_Pahlavi[] = {
- 2,
- 0x10b60, 0x10b72,
- 0x10b78, 0x10b7f,
-}; /* CR_Inscriptional_Pahlavi */
-
-/* 'Old_Turkic': Script */
-static const OnigCodePoint CR_Old_Turkic[] = {
- 1,
- 0x10c00, 0x10c48,
-}; /* CR_Old_Turkic */
-
-/* 'Kaithi': Script */
-static const OnigCodePoint CR_Kaithi[] = {
- 2,
- 0x11080, 0x110c2,
- 0x110cd, 0x110cd,
-}; /* CR_Kaithi */
-
-/* 'Batak': Script */
-static const OnigCodePoint CR_Batak[] = {
- 2,
- 0x1bc0, 0x1bf3,
- 0x1bfc, 0x1bff,
-}; /* CR_Batak */
-
-/* 'Brahmi': Script */
-static const OnigCodePoint CR_Brahmi[] = {
- 3,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x1107f,
-}; /* CR_Brahmi */
-
-/* 'Mandaic': Script */
-static const OnigCodePoint CR_Mandaic[] = {
- 2,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
-}; /* CR_Mandaic */
-
-/* 'Chakma': Script */
-static const OnigCodePoint CR_Chakma[] = {
- 2,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
-}; /* CR_Chakma */
-
-/* 'Meroitic_Cursive': Script */
-static const OnigCodePoint CR_Meroitic_Cursive[] = {
- 3,
- 0x109a0, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x109ff,
-}; /* CR_Meroitic_Cursive */
-
-/* 'Meroitic_Hieroglyphs': Script */
-static const OnigCodePoint CR_Meroitic_Hieroglyphs[] = {
- 1,
- 0x10980, 0x1099f,
-}; /* CR_Meroitic_Hieroglyphs */
-
-/* 'Miao': Script */
-static const OnigCodePoint CR_Miao[] = {
- 3,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
-}; /* CR_Miao */
-
-/* 'Sharada': Script */
-static const OnigCodePoint CR_Sharada[] = {
- 1,
- 0x11180, 0x111df,
-}; /* CR_Sharada */
-
-/* 'Sora_Sompeng': Script */
-static const OnigCodePoint CR_Sora_Sompeng[] = {
- 2,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
-}; /* CR_Sora_Sompeng */
-
-/* 'Takri': Script */
-static const OnigCodePoint CR_Takri[] = {
- 2,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
-}; /* CR_Takri */
-
-/* 'Caucasian_Albanian': Script */
-static const OnigCodePoint CR_Caucasian_Albanian[] = {
- 2,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
-}; /* CR_Caucasian_Albanian */
-
-/* 'Bassa_Vah': Script */
-static const OnigCodePoint CR_Bassa_Vah[] = {
- 2,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
-}; /* CR_Bassa_Vah */
-
-/* 'Duployan': Script */
-static const OnigCodePoint CR_Duployan[] = {
- 5,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bc9f,
-}; /* CR_Duployan */
-
-/* 'Elbasan': Script */
-static const OnigCodePoint CR_Elbasan[] = {
- 1,
- 0x10500, 0x10527,
-}; /* CR_Elbasan */
-
-/* 'Grantha': Script */
-static const OnigCodePoint CR_Grantha[] = {
- 15,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
-}; /* CR_Grantha */
-
-/* 'Pahawh_Hmong': Script */
-static const OnigCodePoint CR_Pahawh_Hmong[] = {
- 5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
-}; /* CR_Pahawh_Hmong */
-
-/* 'Khojki': Script */
-static const OnigCodePoint CR_Khojki[] = {
- 2,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
-}; /* CR_Khojki */
-
-/* 'Linear_A': Script */
-static const OnigCodePoint CR_Linear_A[] = {
- 3,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
-}; /* CR_Linear_A */
-
-/* 'Mahajani': Script */
-static const OnigCodePoint CR_Mahajani[] = {
- 1,
- 0x11150, 0x11176,
-}; /* CR_Mahajani */
-
-/* 'Manichaean': Script */
-static const OnigCodePoint CR_Manichaean[] = {
- 2,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
-}; /* CR_Manichaean */
-
-/* 'Mende_Kikakui': Script */
-static const OnigCodePoint CR_Mende_Kikakui[] = {
- 2,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
-}; /* CR_Mende_Kikakui */
-
-/* 'Modi': Script */
-static const OnigCodePoint CR_Modi[] = {
- 2,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
-}; /* CR_Modi */
-
-/* 'Mro': Script */
-static const OnigCodePoint CR_Mro[] = {
- 3,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
-}; /* CR_Mro */
-
-/* 'Old_North_Arabian': Script */
-static const OnigCodePoint CR_Old_North_Arabian[] = {
- 1,
- 0x10a80, 0x10a9f,
-}; /* CR_Old_North_Arabian */
-
-/* 'Nabataean': Script */
-static const OnigCodePoint CR_Nabataean[] = {
- 2,
- 0x10880, 0x1089e,
- 0x108a7, 0x108af,
-}; /* CR_Nabataean */
-
-/* 'Palmyrene': Script */
-static const OnigCodePoint CR_Palmyrene[] = {
- 1,
- 0x10860, 0x1087f,
-}; /* CR_Palmyrene */
-
-/* 'Pau_Cin_Hau': Script */
-static const OnigCodePoint CR_Pau_Cin_Hau[] = {
- 1,
- 0x11ac0, 0x11af8,
-}; /* CR_Pau_Cin_Hau */
-
-/* 'Old_Permic': Script */
-static const OnigCodePoint CR_Old_Permic[] = {
- 1,
- 0x10350, 0x1037a,
-}; /* CR_Old_Permic */
-
-/* 'Psalter_Pahlavi': Script */
-static const OnigCodePoint CR_Psalter_Pahlavi[] = {
- 3,
- 0x10b80, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
-}; /* CR_Psalter_Pahlavi */
-
-/* 'Siddham': Script */
-static const OnigCodePoint CR_Siddham[] = {
- 2,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
-}; /* CR_Siddham */
-
-/* 'Khudawadi': Script */
-static const OnigCodePoint CR_Khudawadi[] = {
- 2,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
-}; /* CR_Khudawadi */
-
-/* 'Tirhuta': Script */
-static const OnigCodePoint CR_Tirhuta[] = {
- 2,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
-}; /* CR_Tirhuta */
-
-/* 'Warang_Citi': Script */
-static const OnigCodePoint CR_Warang_Citi[] = {
- 2,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
-}; /* CR_Warang_Citi */
-
-/* 'Ahom': Script */
-static const OnigCodePoint CR_Ahom[] = {
- 3,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
-}; /* CR_Ahom */
-
-/* 'Anatolian_Hieroglyphs': Script */
-static const OnigCodePoint CR_Anatolian_Hieroglyphs[] = {
- 1,
- 0x14400, 0x14646,
-}; /* CR_Anatolian_Hieroglyphs */
-
-/* 'Hatran': Script */
-static const OnigCodePoint CR_Hatran[] = {
- 3,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x108ff,
-}; /* CR_Hatran */
-
-/* 'Multani': Script */
-static const OnigCodePoint CR_Multani[] = {
- 5,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
-}; /* CR_Multani */
-
-/* 'Old_Hungarian': Script */
-static const OnigCodePoint CR_Old_Hungarian[] = {
- 3,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
-}; /* CR_Old_Hungarian */
-
-/* 'SignWriting': Script */
-static const OnigCodePoint CR_SignWriting[] = {
- 3,
- 0x1d800, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
-}; /* CR_SignWriting */
-
-/* 'Adlam': Script */
-static const OnigCodePoint CR_Adlam[] = {
- 3,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
-}; /* CR_Adlam */
-
-/* 'Bhaiksuki': Script */
-static const OnigCodePoint CR_Bhaiksuki[] = {
- 4,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
-}; /* CR_Bhaiksuki */
-
-/* 'Marchen': Script */
-static const OnigCodePoint CR_Marchen[] = {
- 3,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
-}; /* CR_Marchen */
-
-/* 'Newa': Script */
-static const OnigCodePoint CR_Newa[] = {
- 2,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
-}; /* CR_Newa */
-
-/* 'Osage': Script */
-static const OnigCodePoint CR_Osage[] = {
- 2,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
-}; /* CR_Osage */
-
-/* 'Tangut': Script */
-static const OnigCodePoint CR_Tangut[] = {
- 4,
- 0x16fe0, 0x16fe0,
- 0x17000, 0x187f7,
- 0x18800, 0x18aff,
- 0x18d00, 0x18d08,
-}; /* CR_Tangut */
-
-/* 'Masaram_Gondi': Script */
-static const OnigCodePoint CR_Masaram_Gondi[] = {
- 7,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
-}; /* CR_Masaram_Gondi */
-
-/* 'Nushu': Script */
-static const OnigCodePoint CR_Nushu[] = {
- 2,
- 0x16fe1, 0x16fe1,
- 0x1b170, 0x1b2fb,
-}; /* CR_Nushu */
-
-/* 'Soyombo': Script */
-static const OnigCodePoint CR_Soyombo[] = {
- 1,
- 0x11a50, 0x11aa2,
-}; /* CR_Soyombo */
-
-/* 'Zanabazar_Square': Script */
-static const OnigCodePoint CR_Zanabazar_Square[] = {
- 1,
- 0x11a00, 0x11a47,
-}; /* CR_Zanabazar_Square */
-
-/* 'Dogra': Script */
-static const OnigCodePoint CR_Dogra[] = {
- 1,
- 0x11800, 0x1183b,
-}; /* CR_Dogra */
-
-/* 'Gunjala_Gondi': Script */
-static const OnigCodePoint CR_Gunjala_Gondi[] = {
- 6,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
-}; /* CR_Gunjala_Gondi */
-
-/* 'Makasar': Script */
-static const OnigCodePoint CR_Makasar[] = {
- 1,
- 0x11ee0, 0x11ef8,
-}; /* CR_Makasar */
-
-/* 'Medefaidrin': Script */
-static const OnigCodePoint CR_Medefaidrin[] = {
- 1,
- 0x16e40, 0x16e9a,
-}; /* CR_Medefaidrin */
-
-/* 'Hanifi_Rohingya': Script */
-static const OnigCodePoint CR_Hanifi_Rohingya[] = {
- 2,
- 0x10d00, 0x10d27,
- 0x10d30, 0x10d39,
-}; /* CR_Hanifi_Rohingya */
-
-/* 'Sogdian': Script */
-static const OnigCodePoint CR_Sogdian[] = {
- 1,
- 0x10f30, 0x10f59,
-}; /* CR_Sogdian */
-
-/* 'Old_Sogdian': Script */
-static const OnigCodePoint CR_Old_Sogdian[] = {
- 1,
- 0x10f00, 0x10f27,
-}; /* CR_Old_Sogdian */
-
-/* 'Elymaic': Script */
-static const OnigCodePoint CR_Elymaic[] = {
- 1,
- 0x10fe0, 0x10ff6,
-}; /* CR_Elymaic */
-
-/* 'Nandinagari': Script */
-static const OnigCodePoint CR_Nandinagari[] = {
- 3,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
-}; /* CR_Nandinagari */
-
-/* 'Nyiakeng_Puachue_Hmong': Script */
-static const OnigCodePoint CR_Nyiakeng_Puachue_Hmong[] = {
- 4,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
-}; /* CR_Nyiakeng_Puachue_Hmong */
-
-/* 'Wancho': Script */
-static const OnigCodePoint CR_Wancho[] = {
- 2,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
-}; /* CR_Wancho */
-
-/* 'Chorasmian': Script */
-static const OnigCodePoint CR_Chorasmian[] = {
- 1,
- 0x10fb0, 0x10fcb,
-}; /* CR_Chorasmian */
-
-/* 'Dives_Akuru': Script */
-static const OnigCodePoint CR_Dives_Akuru[] = {
- 8,
- 0x11900, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
-}; /* CR_Dives_Akuru */
-
-/* 'Khitan_Small_Script': Script */
-static const OnigCodePoint CR_Khitan_Small_Script[] = {
- 2,
- 0x16fe4, 0x16fe4,
- 0x18b00, 0x18cd5,
-}; /* CR_Khitan_Small_Script */
-
-/* 'Yezidi': Script */
-static const OnigCodePoint CR_Yezidi[] = {
- 3,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
-}; /* CR_Yezidi */
-
-/* 'Cypro_Minoan': Script */
-static const OnigCodePoint CR_Cypro_Minoan[] = {
- 1,
- 0x12f90, 0x12ff2,
-}; /* CR_Cypro_Minoan */
-
-/* 'Old_Uyghur': Script */
-static const OnigCodePoint CR_Old_Uyghur[] = {
- 1,
- 0x10f70, 0x10f89,
-}; /* CR_Old_Uyghur */
-
-/* 'Tangsa': Script */
-static const OnigCodePoint CR_Tangsa[] = {
- 2,
- 0x16a70, 0x16abe,
- 0x16ac0, 0x16ac9,
-}; /* CR_Tangsa */
-
-/* 'Toto': Script */
-static const OnigCodePoint CR_Toto[] = {
- 1,
- 0x1e290, 0x1e2ae,
-}; /* CR_Toto */
-
-/* 'Vithkuqi': Script */
-static const OnigCodePoint CR_Vithkuqi[] = {
- 8,
- 0x10570, 0x1057a,
- 0x1057c, 0x1058a,
- 0x1058c, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105a1,
- 0x105a3, 0x105b1,
- 0x105b3, 0x105b9,
- 0x105bb, 0x105bc,
-}; /* CR_Vithkuqi */
-
-/* 'Kawi': Script */
-static const OnigCodePoint CR_Kawi[] = {
- 3,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
-}; /* CR_Kawi */
-
-/* 'Nag_Mundari': Script */
-static const OnigCodePoint CR_Nag_Mundari[] = {
- 1,
- 0x1e4d0, 0x1e4f9,
-}; /* CR_Nag_Mundari */
-
-/* 'White_Space': Binary Property */
-#define CR_White_Space CR_Space
-
-/* 'Bidi_Control': Binary Property */
-static const OnigCodePoint CR_Bidi_Control[] = {
- 4,
- 0x061c, 0x061c,
- 0x200e, 0x200f,
- 0x202a, 0x202e,
- 0x2066, 0x2069,
-}; /* CR_Bidi_Control */
-
-/* 'Join_Control': Binary Property */
-static const OnigCodePoint CR_Join_Control[] = {
- 1,
- 0x200c, 0x200d,
-}; /* CR_Join_Control */
-
-/* 'Dash': Binary Property */
-static const OnigCodePoint CR_Dash[] = {
- 23,
- 0x002d, 0x002d,
- 0x058a, 0x058a,
- 0x05be, 0x05be,
- 0x1400, 0x1400,
- 0x1806, 0x1806,
- 0x2010, 0x2015,
- 0x2053, 0x2053,
- 0x207b, 0x207b,
- 0x208b, 0x208b,
- 0x2212, 0x2212,
- 0x2e17, 0x2e17,
- 0x2e1a, 0x2e1a,
- 0x2e3a, 0x2e3b,
- 0x2e40, 0x2e40,
- 0x2e5d, 0x2e5d,
- 0x301c, 0x301c,
- 0x3030, 0x3030,
- 0x30a0, 0x30a0,
- 0xfe31, 0xfe32,
- 0xfe58, 0xfe58,
- 0xfe63, 0xfe63,
- 0xff0d, 0xff0d,
- 0x10ead, 0x10ead,
-}; /* CR_Dash */
-
-/* 'Hyphen': Binary Property */
-static const OnigCodePoint CR_Hyphen[] = {
- 10,
- 0x002d, 0x002d,
- 0x00ad, 0x00ad,
- 0x058a, 0x058a,
- 0x1806, 0x1806,
- 0x2010, 0x2011,
- 0x2e17, 0x2e17,
- 0x30fb, 0x30fb,
- 0xfe63, 0xfe63,
- 0xff0d, 0xff0d,
- 0xff65, 0xff65,
-}; /* CR_Hyphen */
-
-/* 'Quotation_Mark': Binary Property */
-static const OnigCodePoint CR_Quotation_Mark[] = {
- 13,
- 0x0022, 0x0022,
- 0x0027, 0x0027,
- 0x00ab, 0x00ab,
- 0x00bb, 0x00bb,
- 0x2018, 0x201f,
- 0x2039, 0x203a,
- 0x2e42, 0x2e42,
- 0x300c, 0x300f,
- 0x301d, 0x301f,
- 0xfe41, 0xfe44,
- 0xff02, 0xff02,
- 0xff07, 0xff07,
- 0xff62, 0xff63,
-}; /* CR_Quotation_Mark */
-
-/* 'Terminal_Punctuation': Binary Property */
-static const OnigCodePoint CR_Terminal_Punctuation[] = {
- 108,
- 0x0021, 0x0021,
- 0x002c, 0x002c,
- 0x002e, 0x002e,
- 0x003a, 0x003b,
- 0x003f, 0x003f,
- 0x037e, 0x037e,
- 0x0387, 0x0387,
- 0x0589, 0x0589,
- 0x05c3, 0x05c3,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061d, 0x061f,
- 0x06d4, 0x06d4,
- 0x0700, 0x070a,
- 0x070c, 0x070c,
- 0x07f8, 0x07f9,
- 0x0830, 0x083e,
- 0x085e, 0x085e,
- 0x0964, 0x0965,
- 0x0e5a, 0x0e5b,
- 0x0f08, 0x0f08,
- 0x0f0d, 0x0f12,
- 0x104a, 0x104b,
- 0x1361, 0x1368,
- 0x166e, 0x166e,
- 0x16eb, 0x16ed,
- 0x1735, 0x1736,
- 0x17d4, 0x17d6,
- 0x17da, 0x17da,
- 0x1802, 0x1805,
- 0x1808, 0x1809,
- 0x1944, 0x1945,
- 0x1aa8, 0x1aab,
- 0x1b5a, 0x1b5b,
- 0x1b5d, 0x1b5f,
- 0x1b7d, 0x1b7e,
- 0x1c3b, 0x1c3f,
- 0x1c7e, 0x1c7f,
- 0x203c, 0x203d,
- 0x2047, 0x2049,
- 0x2e2e, 0x2e2e,
- 0x2e3c, 0x2e3c,
- 0x2e41, 0x2e41,
- 0x2e4c, 0x2e4c,
- 0x2e4e, 0x2e4f,
- 0x2e53, 0x2e54,
- 0x3001, 0x3002,
- 0xa4fe, 0xa4ff,
- 0xa60d, 0xa60f,
- 0xa6f3, 0xa6f7,
- 0xa876, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa92f, 0xa92f,
- 0xa9c7, 0xa9c9,
- 0xaa5d, 0xaa5f,
- 0xaadf, 0xaadf,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfe50, 0xfe52,
- 0xfe54, 0xfe57,
- 0xff01, 0xff01,
- 0xff0c, 0xff0c,
- 0xff0e, 0xff0e,
- 0xff1a, 0xff1b,
- 0xff1f, 0xff1f,
- 0xff61, 0xff61,
- 0xff64, 0xff64,
- 0x1039f, 0x1039f,
- 0x103d0, 0x103d0,
- 0x10857, 0x10857,
- 0x1091f, 0x1091f,
- 0x10a56, 0x10a57,
- 0x10af0, 0x10af5,
- 0x10b3a, 0x10b3f,
- 0x10b99, 0x10b9c,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x1104d,
- 0x110be, 0x110c1,
- 0x11141, 0x11143,
- 0x111c5, 0x111c6,
- 0x111cd, 0x111cd,
- 0x111de, 0x111df,
- 0x11238, 0x1123c,
- 0x112a9, 0x112a9,
- 0x1144b, 0x1144d,
- 0x1145a, 0x1145b,
- 0x115c2, 0x115c5,
- 0x115c9, 0x115d7,
- 0x11641, 0x11642,
- 0x1173c, 0x1173e,
- 0x11944, 0x11944,
- 0x11946, 0x11946,
- 0x11a42, 0x11a43,
- 0x11a9b, 0x11a9c,
- 0x11aa1, 0x11aa2,
- 0x11c41, 0x11c43,
- 0x11c71, 0x11c71,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f44,
- 0x12470, 0x12474,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b39,
- 0x16b44, 0x16b44,
- 0x16e97, 0x16e98,
- 0x1bc9f, 0x1bc9f,
- 0x1da87, 0x1da8a,
-}; /* CR_Terminal_Punctuation */
-
-/* 'Other_Math': Binary Property */
-static const OnigCodePoint CR_Other_Math[] = {
- 134,
- 0x005e, 0x005e,
- 0x03d0, 0x03d2,
- 0x03d5, 0x03d5,
- 0x03f0, 0x03f1,
- 0x03f4, 0x03f5,
- 0x2016, 0x2016,
- 0x2032, 0x2034,
- 0x2040, 0x2040,
- 0x2061, 0x2064,
- 0x207d, 0x207e,
- 0x208d, 0x208e,
- 0x20d0, 0x20dc,
- 0x20e1, 0x20e1,
- 0x20e5, 0x20e6,
- 0x20eb, 0x20ef,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210a, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211d,
- 0x2124, 0x2124,
- 0x2128, 0x2129,
- 0x212c, 0x212d,
- 0x212f, 0x2131,
- 0x2133, 0x2138,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x2195, 0x2199,
- 0x219c, 0x219f,
- 0x21a1, 0x21a2,
- 0x21a4, 0x21a5,
- 0x21a7, 0x21a7,
- 0x21a9, 0x21ad,
- 0x21b0, 0x21b1,
- 0x21b6, 0x21b7,
- 0x21bc, 0x21cd,
- 0x21d0, 0x21d1,
- 0x21d3, 0x21d3,
- 0x21d5, 0x21db,
- 0x21dd, 0x21dd,
- 0x21e4, 0x21e5,
- 0x2308, 0x230b,
- 0x23b4, 0x23b5,
- 0x23b7, 0x23b7,
- 0x23d0, 0x23d0,
- 0x23e2, 0x23e2,
- 0x25a0, 0x25a1,
- 0x25ae, 0x25b6,
- 0x25bc, 0x25c0,
- 0x25c6, 0x25c7,
- 0x25ca, 0x25cb,
- 0x25cf, 0x25d3,
- 0x25e2, 0x25e2,
- 0x25e4, 0x25e4,
- 0x25e7, 0x25ec,
- 0x2605, 0x2606,
- 0x2640, 0x2640,
- 0x2642, 0x2642,
- 0x2660, 0x2663,
- 0x266d, 0x266e,
- 0x27c5, 0x27c6,
- 0x27e6, 0x27ef,
- 0x2983, 0x2998,
- 0x29d8, 0x29db,
- 0x29fc, 0x29fd,
- 0xfe61, 0xfe61,
- 0xfe63, 0xfe63,
- 0xfe68, 0xfe68,
- 0xff3c, 0xff3c,
- 0xff3e, 0xff3e,
- 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,
- 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,
-}; /* CR_Other_Math */
-
-/* 'Hex_Digit': Binary Property */
-static const OnigCodePoint CR_Hex_Digit[] = {
- 6,
- 0x0030, 0x0039,
- 0x0041, 0x0046,
- 0x0061, 0x0066,
- 0xff10, 0xff19,
- 0xff21, 0xff26,
- 0xff41, 0xff46,
-}; /* CR_Hex_Digit */
-
-/* 'ASCII_Hex_Digit': Binary Property */
-#define CR_ASCII_Hex_Digit CR_XDigit
-
-/* 'Other_Alphabetic': Binary Property */
-static const OnigCodePoint CR_Other_Alphabetic[] = {
- 240,
- 0x0345, 0x0345,
- 0x05b0, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x0657,
- 0x0659, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06e1, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ed, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x073f,
- 0x07a6, 0x07b0,
- 0x0816, 0x0817,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082c,
- 0x08d4, 0x08df,
- 0x08e3, 0x08e9,
- 0x08f0, 0x0903,
- 0x093a, 0x093b,
- 0x093e, 0x094c,
- 0x094e, 0x094f,
- 0x0955, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0983,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x0a01, 0x0a03,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4c,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0abe, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0afc,
- 0x0b01, 0x0b03,
- 0x0b3e, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0b56, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c04,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4c,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c83,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccc,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0cf3, 0x0cf3,
- 0x0d00, 0x0d03,
- 0x0d3e, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d83,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df3,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e4d, 0x0e4d,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0eb9,
- 0x0ebb, 0x0ebc,
- 0x0ecd, 0x0ecd,
- 0x0f71, 0x0f83,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x102b, 0x1036,
- 0x1038, 0x1038,
- 0x103b, 0x103e,
- 0x1056, 0x1059,
- 0x105e, 0x1060,
- 0x1062, 0x1064,
- 0x1067, 0x106d,
- 0x1071, 0x1074,
- 0x1082, 0x108d,
- 0x108f, 0x108f,
- 0x109a, 0x109d,
- 0x1712, 0x1713,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b6, 0x17c8,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x192b,
- 0x1930, 0x1938,
- 0x1a17, 0x1a1b,
- 0x1a55, 0x1a5e,
- 0x1a61, 0x1a74,
- 0x1abf, 0x1ac0,
- 0x1acc, 0x1ace,
- 0x1b00, 0x1b04,
- 0x1b35, 0x1b43,
- 0x1b80, 0x1b82,
- 0x1ba1, 0x1ba9,
- 0x1bac, 0x1bad,
- 0x1be7, 0x1bf1,
- 0x1c24, 0x1c36,
- 0x1de7, 0x1df4,
- 0x24b6, 0x24e9,
- 0x2de0, 0x2dff,
- 0xa674, 0xa67b,
- 0xa69e, 0xa69f,
- 0xa802, 0xa802,
- 0xa80b, 0xa80b,
- 0xa823, 0xa827,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c3,
- 0xa8c5, 0xa8c5,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92a,
- 0xa947, 0xa952,
- 0xa980, 0xa983,
- 0xa9b4, 0xa9bf,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4d,
- 0xaa7b, 0xaa7d,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabe,
- 0xaaeb, 0xaaef,
- 0xaaf5, 0xaaf5,
- 0xabe3, 0xabea,
- 0xfb1e, 0xfb1e,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x11000, 0x11002,
- 0x11038, 0x11045,
- 0x11073, 0x11074,
- 0x11080, 0x11082,
- 0x110b0, 0x110b8,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x11132,
- 0x11145, 0x11146,
- 0x11180, 0x11182,
- 0x111b3, 0x111bf,
- 0x111ce, 0x111cf,
- 0x1122c, 0x11234,
- 0x11237, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112e8,
- 0x11300, 0x11303,
- 0x1133e, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134c,
- 0x11357, 0x11357,
- 0x11362, 0x11363,
- 0x11435, 0x11441,
- 0x11443, 0x11445,
- 0x114b0, 0x114c1,
- 0x115af, 0x115b5,
- 0x115b8, 0x115be,
- 0x115dc, 0x115dd,
- 0x11630, 0x1163e,
- 0x11640, 0x11640,
- 0x116ab, 0x116b5,
- 0x1171d, 0x1172a,
- 0x1182c, 0x11838,
- 0x11930, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x1193c,
- 0x11940, 0x11940,
- 0x11942, 0x11942,
- 0x119d1, 0x119d7,
- 0x119da, 0x119df,
- 0x119e4, 0x119e4,
- 0x11a01, 0x11a0a,
- 0x11a35, 0x11a39,
- 0x11a3b, 0x11a3e,
- 0x11a51, 0x11a5b,
- 0x11a8a, 0x11a97,
- 0x11c2f, 0x11c36,
- 0x11c38, 0x11c3e,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d41,
- 0x11d43, 0x11d43,
- 0x11d47, 0x11d47,
- 0x11d8a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d96,
- 0x11ef3, 0x11ef6,
- 0x11f00, 0x11f01,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f3a,
- 0x11f3e, 0x11f40,
- 0x16f4f, 0x16f4f,
- 0x16f51, 0x16f87,
- 0x16f8f, 0x16f92,
- 0x16ff0, 0x16ff1,
- 0x1bc9e, 0x1bc9e,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e947, 0x1e947,
- 0x1f130, 0x1f149,
- 0x1f150, 0x1f169,
- 0x1f170, 0x1f189,
-}; /* CR_Other_Alphabetic */
-
-/* 'Ideographic': Binary Property */
-static const OnigCodePoint CR_Ideographic[] = {
- 21,
- 0x3006, 0x3007,
- 0x3021, 0x3029,
- 0x3038, 0x303a,
- 0x3400, 0x4dbf,
- 0x4e00, 0x9fff,
- 0xf900, 0xfa6d,
- 0xfa70, 0xfad9,
- 0x16fe4, 0x16fe4,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18d00, 0x18d08,
- 0x1b170, 0x1b2fb,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Ideographic */
-
-/* 'Diacritic': Binary Property */
-static const OnigCodePoint CR_Diacritic[] = {
- 195,
- 0x005e, 0x005e,
- 0x0060, 0x0060,
- 0x00a8, 0x00a8,
- 0x00af, 0x00af,
- 0x00b4, 0x00b4,
- 0x00b7, 0x00b8,
- 0x02b0, 0x034e,
- 0x0350, 0x0357,
- 0x035d, 0x0362,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x0384, 0x0385,
- 0x0483, 0x0487,
- 0x0559, 0x0559,
- 0x0591, 0x05a1,
- 0x05a3, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c4,
- 0x064b, 0x0652,
- 0x0657, 0x0658,
- 0x06df, 0x06e0,
- 0x06e5, 0x06e6,
- 0x06ea, 0x06ec,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f5,
- 0x0818, 0x0819,
- 0x0898, 0x089f,
- 0x08c9, 0x08d2,
- 0x08e3, 0x08fe,
- 0x093c, 0x093c,
- 0x094d, 0x094d,
- 0x0951, 0x0954,
- 0x0971, 0x0971,
- 0x09bc, 0x09bc,
- 0x09cd, 0x09cd,
- 0x0a3c, 0x0a3c,
- 0x0a4d, 0x0a4d,
- 0x0abc, 0x0abc,
- 0x0acd, 0x0acd,
- 0x0afd, 0x0aff,
- 0x0b3c, 0x0b3c,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b55,
- 0x0bcd, 0x0bcd,
- 0x0c3c, 0x0c3c,
- 0x0c4d, 0x0c4d,
- 0x0cbc, 0x0cbc,
- 0x0ccd, 0x0ccd,
- 0x0d3b, 0x0d3c,
- 0x0d4d, 0x0d4d,
- 0x0dca, 0x0dca,
- 0x0e47, 0x0e4c,
- 0x0e4e, 0x0e4e,
- 0x0eba, 0x0eba,
- 0x0ec8, 0x0ecc,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f3e, 0x0f3f,
- 0x0f82, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0fc6, 0x0fc6,
- 0x1037, 0x1037,
- 0x1039, 0x103a,
- 0x1063, 0x1064,
- 0x1069, 0x106d,
- 0x1087, 0x108d,
- 0x108f, 0x108f,
- 0x109a, 0x109b,
- 0x135d, 0x135f,
- 0x1714, 0x1715,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x1939, 0x193b,
- 0x1a75, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1abe,
- 0x1ac1, 0x1acb,
- 0x1b34, 0x1b34,
- 0x1b44, 0x1b44,
- 0x1b6b, 0x1b73,
- 0x1baa, 0x1bab,
- 0x1c36, 0x1c37,
- 0x1c78, 0x1c7d,
- 0x1cd0, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf7, 0x1cf9,
- 0x1d2c, 0x1d6a,
- 0x1dc4, 0x1dcf,
- 0x1df5, 0x1dff,
- 0x1fbd, 0x1fbd,
- 0x1fbf, 0x1fc1,
- 0x1fcd, 0x1fcf,
- 0x1fdd, 0x1fdf,
- 0x1fed, 0x1fef,
- 0x1ffd, 0x1ffe,
- 0x2cef, 0x2cf1,
- 0x2e2f, 0x2e2f,
- 0x302a, 0x302f,
- 0x3099, 0x309c,
- 0x30fc, 0x30fc,
- 0xa66f, 0xa66f,
- 0xa67c, 0xa67d,
- 0xa67f, 0xa67f,
- 0xa69c, 0xa69d,
- 0xa6f0, 0xa6f1,
- 0xa700, 0xa721,
- 0xa788, 0xa78a,
- 0xa7f8, 0xa7f9,
- 0xa8c4, 0xa8c4,
- 0xa8e0, 0xa8f1,
- 0xa92b, 0xa92e,
- 0xa953, 0xa953,
- 0xa9b3, 0xa9b3,
- 0xa9c0, 0xa9c0,
- 0xa9e5, 0xa9e5,
- 0xaa7b, 0xaa7d,
- 0xaabf, 0xaac2,
- 0xaaf6, 0xaaf6,
- 0xab5b, 0xab5f,
- 0xab69, 0xab6b,
- 0xabec, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe20, 0xfe2f,
- 0xff3e, 0xff3e,
- 0xff40, 0xff40,
- 0xff70, 0xff70,
- 0xff9e, 0xff9f,
- 0xffe3, 0xffe3,
- 0x102e0, 0x102e0,
- 0x10780, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x10ae5, 0x10ae6,
- 0x10d22, 0x10d27,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11046, 0x11046,
- 0x11070, 0x11070,
- 0x110b9, 0x110ba,
- 0x11133, 0x11134,
- 0x11173, 0x11173,
- 0x111c0, 0x111c0,
- 0x111ca, 0x111cc,
- 0x11235, 0x11236,
- 0x112e9, 0x112ea,
- 0x1133c, 0x1133c,
- 0x1134d, 0x1134d,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11442, 0x11442,
- 0x11446, 0x11446,
- 0x114c2, 0x114c3,
- 0x115bf, 0x115c0,
- 0x1163f, 0x1163f,
- 0x116b6, 0x116b7,
- 0x1172b, 0x1172b,
- 0x11839, 0x1183a,
- 0x1193d, 0x1193e,
- 0x11943, 0x11943,
- 0x119e0, 0x119e0,
- 0x11a34, 0x11a34,
- 0x11a47, 0x11a47,
- 0x11a99, 0x11a99,
- 0x11c3f, 0x11c3f,
- 0x11d42, 0x11d42,
- 0x11d44, 0x11d45,
- 0x11d97, 0x11d97,
- 0x13447, 0x13455,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f8f, 0x16f9f,
- 0x16ff0, 0x16ff1,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d167, 0x1d169,
- 0x1d16d, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1e030, 0x1e06d,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e946,
- 0x1e948, 0x1e94a,
-}; /* CR_Diacritic */
-
-/* 'Extender': Binary Property */
-static const OnigCodePoint CR_Extender[] = {
- 33,
- 0x00b7, 0x00b7,
- 0x02d0, 0x02d1,
- 0x0640, 0x0640,
- 0x07fa, 0x07fa,
- 0x0b55, 0x0b55,
- 0x0e46, 0x0e46,
- 0x0ec6, 0x0ec6,
- 0x180a, 0x180a,
- 0x1843, 0x1843,
- 0x1aa7, 0x1aa7,
- 0x1c36, 0x1c36,
- 0x1c7b, 0x1c7b,
- 0x3005, 0x3005,
- 0x3031, 0x3035,
- 0x309d, 0x309e,
- 0x30fc, 0x30fe,
- 0xa015, 0xa015,
- 0xa60c, 0xa60c,
- 0xa9cf, 0xa9cf,
- 0xa9e6, 0xa9e6,
- 0xaa70, 0xaa70,
- 0xaadd, 0xaadd,
- 0xaaf3, 0xaaf4,
- 0xff70, 0xff70,
- 0x10781, 0x10782,
- 0x1135d, 0x1135d,
- 0x115c6, 0x115c8,
- 0x11a98, 0x11a98,
- 0x16b42, 0x16b43,
- 0x16fe0, 0x16fe1,
- 0x16fe3, 0x16fe3,
- 0x1e13c, 0x1e13d,
- 0x1e944, 0x1e946,
-}; /* CR_Extender */
-
-/* 'Other_Lowercase': Binary Property */
-static const OnigCodePoint CR_Other_Lowercase[] = {
- 28,
- 0x00aa, 0x00aa,
- 0x00ba, 0x00ba,
- 0x02b0, 0x02b8,
- 0x02c0, 0x02c1,
- 0x02e0, 0x02e4,
- 0x0345, 0x0345,
- 0x037a, 0x037a,
- 0x10fc, 0x10fc,
- 0x1d2c, 0x1d6a,
- 0x1d78, 0x1d78,
- 0x1d9b, 0x1dbf,
- 0x2071, 0x2071,
- 0x207f, 0x207f,
- 0x2090, 0x209c,
- 0x2170, 0x217f,
- 0x24d0, 0x24e9,
- 0x2c7c, 0x2c7d,
- 0xa69c, 0xa69d,
- 0xa770, 0xa770,
- 0xa7f2, 0xa7f4,
- 0xa7f8, 0xa7f9,
- 0xab5c, 0xab5f,
- 0xab69, 0xab69,
- 0x10780, 0x10780,
- 0x10783, 0x10785,
- 0x10787, 0x107b0,
- 0x107b2, 0x107ba,
- 0x1e030, 0x1e06d,
-}; /* CR_Other_Lowercase */
-
-/* 'Other_Uppercase': Binary Property */
-static const OnigCodePoint CR_Other_Uppercase[] = {
- 5,
- 0x2160, 0x216f,
- 0x24b6, 0x24cf,
- 0x1f130, 0x1f149,
- 0x1f150, 0x1f169,
- 0x1f170, 0x1f189,
-}; /* CR_Other_Uppercase */
-
-/* 'Noncharacter_Code_Point': Binary Property */
-static const OnigCodePoint CR_Noncharacter_Code_Point[] = {
- 18,
- 0xfdd0, 0xfdef,
- 0xfffe, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0xeffff,
- 0xffffe, 0xfffff,
- 0x10fffe, 0x10ffff,
-}; /* CR_Noncharacter_Code_Point */
-
-/* 'Other_Grapheme_Extend': Binary Property */
-static const OnigCodePoint CR_Other_Grapheme_Extend[] = {
- 25,
- 0x09be, 0x09be,
- 0x09d7, 0x09d7,
- 0x0b3e, 0x0b3e,
- 0x0b57, 0x0b57,
- 0x0bbe, 0x0bbe,
- 0x0bd7, 0x0bd7,
- 0x0cc2, 0x0cc2,
- 0x0cd5, 0x0cd6,
- 0x0d3e, 0x0d3e,
- 0x0d57, 0x0d57,
- 0x0dcf, 0x0dcf,
- 0x0ddf, 0x0ddf,
- 0x1b35, 0x1b35,
- 0x200c, 0x200c,
- 0x302e, 0x302f,
- 0xff9e, 0xff9f,
- 0x1133e, 0x1133e,
- 0x11357, 0x11357,
- 0x114b0, 0x114b0,
- 0x114bd, 0x114bd,
- 0x115af, 0x115af,
- 0x11930, 0x11930,
- 0x1d165, 0x1d165,
- 0x1d16e, 0x1d172,
- 0xe0020, 0xe007f,
-}; /* CR_Other_Grapheme_Extend */
-
-/* 'IDS_Binary_Operator': Binary Property */
-static const OnigCodePoint CR_IDS_Binary_Operator[] = {
- 3,
- 0x2ff0, 0x2ff1,
- 0x2ff4, 0x2ffd,
- 0x31ef, 0x31ef,
-}; /* CR_IDS_Binary_Operator */
-
-/* 'IDS_Trinary_Operator': Binary Property */
-static const OnigCodePoint CR_IDS_Trinary_Operator[] = {
- 1,
- 0x2ff2, 0x2ff3,
-}; /* CR_IDS_Trinary_Operator */
-
-/* 'IDS_Unary_Operator': Binary Property */
-static const OnigCodePoint CR_IDS_Unary_Operator[] = {
- 1,
- 0x2ffe, 0x2fff,
-}; /* CR_IDS_Unary_Operator */
-
-/* 'Radical': Binary Property */
-static const OnigCodePoint CR_Radical[] = {
- 3,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
-}; /* CR_Radical */
-
-/* 'Unified_Ideograph': Binary Property */
-static const OnigCodePoint CR_Unified_Ideograph[] = {
- 17,
- 0x3400, 0x4dbf,
- 0x4e00, 0x9fff,
- 0xfa0e, 0xfa0f,
- 0xfa11, 0xfa11,
- 0xfa13, 0xfa14,
- 0xfa1f, 0xfa1f,
- 0xfa21, 0xfa21,
- 0xfa23, 0xfa24,
- 0xfa27, 0xfa29,
- 0x20000, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x30000, 0x3134a,
- 0x31350, 0x323af,
-}; /* CR_Unified_Ideograph */
-
-/* 'Other_Default_Ignorable_Code_Point': Binary Property */
-static const OnigCodePoint CR_Other_Default_Ignorable_Code_Point[] = {
- 11,
- 0x034f, 0x034f,
- 0x115f, 0x1160,
- 0x17b4, 0x17b5,
- 0x2065, 0x2065,
- 0x3164, 0x3164,
- 0xffa0, 0xffa0,
- 0xfff0, 0xfff8,
- 0xe0000, 0xe0000,
- 0xe0002, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xe0fff,
-}; /* CR_Other_Default_Ignorable_Code_Point */
-
-/* 'Deprecated': Binary Property */
-static const OnigCodePoint CR_Deprecated[] = {
- 8,
- 0x0149, 0x0149,
- 0x0673, 0x0673,
- 0x0f77, 0x0f77,
- 0x0f79, 0x0f79,
- 0x17a3, 0x17a4,
- 0x206a, 0x206f,
- 0x2329, 0x232a,
- 0xe0001, 0xe0001,
-}; /* CR_Deprecated */
-
-/* 'Soft_Dotted': Binary Property */
-static const OnigCodePoint CR_Soft_Dotted[] = {
- 34,
- 0x0069, 0x006a,
- 0x012f, 0x012f,
- 0x0249, 0x0249,
- 0x0268, 0x0268,
- 0x029d, 0x029d,
- 0x02b2, 0x02b2,
- 0x03f3, 0x03f3,
- 0x0456, 0x0456,
- 0x0458, 0x0458,
- 0x1d62, 0x1d62,
- 0x1d96, 0x1d96,
- 0x1da4, 0x1da4,
- 0x1da8, 0x1da8,
- 0x1e2d, 0x1e2d,
- 0x1ecb, 0x1ecb,
- 0x2071, 0x2071,
- 0x2148, 0x2149,
- 0x2c7c, 0x2c7c,
- 0x1d422, 0x1d423,
- 0x1d456, 0x1d457,
- 0x1d48a, 0x1d48b,
- 0x1d4be, 0x1d4bf,
- 0x1d4f2, 0x1d4f3,
- 0x1d526, 0x1d527,
- 0x1d55a, 0x1d55b,
- 0x1d58e, 0x1d58f,
- 0x1d5c2, 0x1d5c3,
- 0x1d5f6, 0x1d5f7,
- 0x1d62a, 0x1d62b,
- 0x1d65e, 0x1d65f,
- 0x1d692, 0x1d693,
- 0x1df1a, 0x1df1a,
- 0x1e04c, 0x1e04d,
- 0x1e068, 0x1e068,
-}; /* CR_Soft_Dotted */
-
-/* 'Logical_Order_Exception': Binary Property */
-static const OnigCodePoint CR_Logical_Order_Exception[] = {
- 7,
- 0x0e40, 0x0e44,
- 0x0ec0, 0x0ec4,
- 0x19b5, 0x19b7,
- 0x19ba, 0x19ba,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaab9,
- 0xaabb, 0xaabc,
-}; /* CR_Logical_Order_Exception */
-
-/* 'Other_ID_Start': Binary Property */
-static const OnigCodePoint CR_Other_ID_Start[] = {
- 4,
- 0x1885, 0x1886,
- 0x2118, 0x2118,
- 0x212e, 0x212e,
- 0x309b, 0x309c,
-}; /* CR_Other_ID_Start */
-
-/* 'Other_ID_Continue': Binary Property */
-static const OnigCodePoint CR_Other_ID_Continue[] = {
- 7,
- 0x00b7, 0x00b7,
- 0x0387, 0x0387,
- 0x1369, 0x1371,
- 0x19da, 0x19da,
- 0x200c, 0x200d,
- 0x30fb, 0x30fb,
- 0xff65, 0xff65,
-}; /* CR_Other_ID_Continue */
-
-/* 'ID_Compat_Math_Continue': Binary Property */
-static const OnigCodePoint CR_ID_Compat_Math_Continue[] = {
- 18,
- 0x00b2, 0x00b3,
- 0x00b9, 0x00b9,
- 0x2070, 0x2070,
- 0x2074, 0x207e,
- 0x2080, 0x208e,
- 0x2202, 0x2202,
- 0x2207, 0x2207,
- 0x221e, 0x221e,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
-}; /* CR_ID_Compat_Math_Continue */
-
-/* 'ID_Compat_Math_Start': Binary Property */
-static const OnigCodePoint CR_ID_Compat_Math_Start[] = {
- 13,
- 0x2202, 0x2202,
- 0x2207, 0x2207,
- 0x221e, 0x221e,
- 0x1d6c1, 0x1d6c1,
- 0x1d6db, 0x1d6db,
- 0x1d6fb, 0x1d6fb,
- 0x1d715, 0x1d715,
- 0x1d735, 0x1d735,
- 0x1d74f, 0x1d74f,
- 0x1d76f, 0x1d76f,
- 0x1d789, 0x1d789,
- 0x1d7a9, 0x1d7a9,
- 0x1d7c3, 0x1d7c3,
-}; /* CR_ID_Compat_Math_Start */
-
-/* 'Sentence_Terminal': Binary Property */
-static const OnigCodePoint CR_Sentence_Terminal[] = {
- 81,
- 0x0021, 0x0021,
- 0x002e, 0x002e,
- 0x003f, 0x003f,
- 0x0589, 0x0589,
- 0x061d, 0x061f,
- 0x06d4, 0x06d4,
- 0x0700, 0x0702,
- 0x07f9, 0x07f9,
- 0x0837, 0x0837,
- 0x0839, 0x0839,
- 0x083d, 0x083e,
- 0x0964, 0x0965,
- 0x104a, 0x104b,
- 0x1362, 0x1362,
- 0x1367, 0x1368,
- 0x166e, 0x166e,
- 0x1735, 0x1736,
- 0x17d4, 0x17d5,
- 0x1803, 0x1803,
- 0x1809, 0x1809,
- 0x1944, 0x1945,
- 0x1aa8, 0x1aab,
- 0x1b5a, 0x1b5b,
- 0x1b5e, 0x1b5f,
- 0x1b7d, 0x1b7e,
- 0x1c3b, 0x1c3c,
- 0x1c7e, 0x1c7f,
- 0x203c, 0x203d,
- 0x2047, 0x2049,
- 0x2e2e, 0x2e2e,
- 0x2e3c, 0x2e3c,
- 0x2e53, 0x2e54,
- 0x3002, 0x3002,
- 0xa4ff, 0xa4ff,
- 0xa60e, 0xa60f,
- 0xa6f3, 0xa6f3,
- 0xa6f7, 0xa6f7,
- 0xa876, 0xa877,
- 0xa8ce, 0xa8cf,
- 0xa92f, 0xa92f,
- 0xa9c8, 0xa9c9,
- 0xaa5d, 0xaa5f,
- 0xaaf0, 0xaaf1,
- 0xabeb, 0xabeb,
- 0xfe52, 0xfe52,
- 0xfe56, 0xfe57,
- 0xff01, 0xff01,
- 0xff0e, 0xff0e,
- 0xff1f, 0xff1f,
- 0xff61, 0xff61,
- 0x10a56, 0x10a57,
- 0x10f55, 0x10f59,
- 0x10f86, 0x10f89,
- 0x11047, 0x11048,
- 0x110be, 0x110c1,
- 0x11141, 0x11143,
- 0x111c5, 0x111c6,
- 0x111cd, 0x111cd,
- 0x111de, 0x111df,
- 0x11238, 0x11239,
- 0x1123b, 0x1123c,
- 0x112a9, 0x112a9,
- 0x1144b, 0x1144c,
- 0x115c2, 0x115c3,
- 0x115c9, 0x115d7,
- 0x11641, 0x11642,
- 0x1173c, 0x1173e,
- 0x11944, 0x11944,
- 0x11946, 0x11946,
- 0x11a42, 0x11a43,
- 0x11a9b, 0x11a9c,
- 0x11c41, 0x11c42,
- 0x11ef7, 0x11ef8,
- 0x11f43, 0x11f44,
- 0x16a6e, 0x16a6f,
- 0x16af5, 0x16af5,
- 0x16b37, 0x16b38,
- 0x16b44, 0x16b44,
- 0x16e98, 0x16e98,
- 0x1bc9f, 0x1bc9f,
- 0x1da88, 0x1da88,
-}; /* CR_Sentence_Terminal */
-
-/* 'Variation_Selector': Binary Property */
-static const OnigCodePoint CR_Variation_Selector[] = {
- 4,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0xfe00, 0xfe0f,
- 0xe0100, 0xe01ef,
-}; /* CR_Variation_Selector */
-
-/* 'Pattern_White_Space': Binary Property */
-static const OnigCodePoint CR_Pattern_White_Space[] = {
- 5,
- 0x0009, 0x000d,
- 0x0020, 0x0020,
- 0x0085, 0x0085,
- 0x200e, 0x200f,
- 0x2028, 0x2029,
-}; /* CR_Pattern_White_Space */
-
-/* 'Pattern_Syntax': Binary Property */
-static const OnigCodePoint CR_Pattern_Syntax[] = {
- 28,
- 0x0021, 0x002f,
- 0x003a, 0x0040,
- 0x005b, 0x005e,
- 0x0060, 0x0060,
- 0x007b, 0x007e,
- 0x00a1, 0x00a7,
- 0x00a9, 0x00a9,
- 0x00ab, 0x00ac,
- 0x00ae, 0x00ae,
- 0x00b0, 0x00b1,
- 0x00b6, 0x00b6,
- 0x00bb, 0x00bb,
- 0x00bf, 0x00bf,
- 0x00d7, 0x00d7,
- 0x00f7, 0x00f7,
- 0x2010, 0x2027,
- 0x2030, 0x203e,
- 0x2041, 0x2053,
- 0x2055, 0x205e,
- 0x2190, 0x245f,
- 0x2500, 0x2775,
- 0x2794, 0x2bff,
- 0x2e00, 0x2e7f,
- 0x3001, 0x3003,
- 0x3008, 0x3020,
- 0x3030, 0x3030,
- 0xfd3e, 0xfd3f,
- 0xfe45, 0xfe46,
-}; /* CR_Pattern_Syntax */
-
-/* 'Prepended_Concatenation_Mark': Binary Property */
-static const OnigCodePoint CR_Prepended_Concatenation_Mark[] = {
- 7,
- 0x0600, 0x0605,
- 0x06dd, 0x06dd,
- 0x070f, 0x070f,
- 0x0890, 0x0891,
- 0x08e2, 0x08e2,
- 0x110bd, 0x110bd,
- 0x110cd, 0x110cd,
-}; /* CR_Prepended_Concatenation_Mark */
-
-/* 'Regional_Indicator': Binary Property */
-static const OnigCodePoint CR_Regional_Indicator[] = {
- 1,
- 0x1f1e6, 0x1f1ff,
-}; /* CR_Regional_Indicator */
-
-/* 'Emoji': Emoji */
-static const OnigCodePoint CR_Emoji[] = {
- 151,
- 0x0023, 0x0023,
- 0x002a, 0x002a,
- 0x0030, 0x0039,
- 0x00a9, 0x00a9,
- 0x00ae, 0x00ae,
- 0x203c, 0x203c,
- 0x2049, 0x2049,
- 0x2122, 0x2122,
- 0x2139, 0x2139,
- 0x2194, 0x2199,
- 0x21a9, 0x21aa,
- 0x231a, 0x231b,
- 0x2328, 0x2328,
- 0x23cf, 0x23cf,
- 0x23e9, 0x23f3,
- 0x23f8, 0x23fa,
- 0x24c2, 0x24c2,
- 0x25aa, 0x25ab,
- 0x25b6, 0x25b6,
- 0x25c0, 0x25c0,
- 0x25fb, 0x25fe,
- 0x2600, 0x2604,
- 0x260e, 0x260e,
- 0x2611, 0x2611,
- 0x2614, 0x2615,
- 0x2618, 0x2618,
- 0x261d, 0x261d,
- 0x2620, 0x2620,
- 0x2622, 0x2623,
- 0x2626, 0x2626,
- 0x262a, 0x262a,
- 0x262e, 0x262f,
- 0x2638, 0x263a,
- 0x2640, 0x2640,
- 0x2642, 0x2642,
- 0x2648, 0x2653,
- 0x265f, 0x2660,
- 0x2663, 0x2663,
- 0x2665, 0x2666,
- 0x2668, 0x2668,
- 0x267b, 0x267b,
- 0x267e, 0x267f,
- 0x2692, 0x2697,
- 0x2699, 0x2699,
- 0x269b, 0x269c,
- 0x26a0, 0x26a1,
- 0x26a7, 0x26a7,
- 0x26aa, 0x26ab,
- 0x26b0, 0x26b1,
- 0x26bd, 0x26be,
- 0x26c4, 0x26c5,
- 0x26c8, 0x26c8,
- 0x26ce, 0x26cf,
- 0x26d1, 0x26d1,
- 0x26d3, 0x26d4,
- 0x26e9, 0x26ea,
- 0x26f0, 0x26f5,
- 0x26f7, 0x26fa,
- 0x26fd, 0x26fd,
- 0x2702, 0x2702,
- 0x2705, 0x2705,
- 0x2708, 0x270d,
- 0x270f, 0x270f,
- 0x2712, 0x2712,
- 0x2714, 0x2714,
- 0x2716, 0x2716,
- 0x271d, 0x271d,
- 0x2721, 0x2721,
- 0x2728, 0x2728,
- 0x2733, 0x2734,
- 0x2744, 0x2744,
- 0x2747, 0x2747,
- 0x274c, 0x274c,
- 0x274e, 0x274e,
- 0x2753, 0x2755,
- 0x2757, 0x2757,
- 0x2763, 0x2764,
- 0x2795, 0x2797,
- 0x27a1, 0x27a1,
- 0x27b0, 0x27b0,
- 0x27bf, 0x27bf,
- 0x2934, 0x2935,
- 0x2b05, 0x2b07,
- 0x2b1b, 0x2b1c,
- 0x2b50, 0x2b50,
- 0x2b55, 0x2b55,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x3297, 0x3297,
- 0x3299, 0x3299,
- 0x1f004, 0x1f004,
- 0x1f0cf, 0x1f0cf,
- 0x1f170, 0x1f171,
- 0x1f17e, 0x1f17f,
- 0x1f18e, 0x1f18e,
- 0x1f191, 0x1f19a,
- 0x1f1e6, 0x1f1ff,
- 0x1f201, 0x1f202,
- 0x1f21a, 0x1f21a,
- 0x1f22f, 0x1f22f,
- 0x1f232, 0x1f23a,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f321,
- 0x1f324, 0x1f393,
- 0x1f396, 0x1f397,
- 0x1f399, 0x1f39b,
- 0x1f39e, 0x1f3f0,
- 0x1f3f3, 0x1f3f5,
- 0x1f3f7, 0x1f4fd,
- 0x1f4ff, 0x1f53d,
- 0x1f549, 0x1f54e,
- 0x1f550, 0x1f567,
- 0x1f56f, 0x1f570,
- 0x1f573, 0x1f57a,
- 0x1f587, 0x1f587,
- 0x1f58a, 0x1f58d,
- 0x1f590, 0x1f590,
- 0x1f595, 0x1f596,
- 0x1f5a4, 0x1f5a5,
- 0x1f5a8, 0x1f5a8,
- 0x1f5b1, 0x1f5b2,
- 0x1f5bc, 0x1f5bc,
- 0x1f5c2, 0x1f5c4,
- 0x1f5d1, 0x1f5d3,
- 0x1f5dc, 0x1f5de,
- 0x1f5e1, 0x1f5e1,
- 0x1f5e3, 0x1f5e3,
- 0x1f5e8, 0x1f5e8,
- 0x1f5ef, 0x1f5ef,
- 0x1f5f3, 0x1f5f3,
- 0x1f5fa, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f6cb, 0x1f6d2,
- 0x1f6d5, 0x1f6d7,
- 0x1f6dc, 0x1f6e5,
- 0x1f6e9, 0x1f6e9,
- 0x1f6eb, 0x1f6ec,
- 0x1f6f0, 0x1f6f0,
- 0x1f6f3, 0x1f6fc,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f90c, 0x1f93a,
- 0x1f93c, 0x1f945,
- 0x1f947, 0x1f9ff,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
-}; /* CR_Emoji */
-
-/* 'Emoji_Presentation': Emoji */
-static const OnigCodePoint CR_Emoji_Presentation[] = {
- 81,
- 0x231a, 0x231b,
- 0x23e9, 0x23ec,
- 0x23f0, 0x23f0,
- 0x23f3, 0x23f3,
- 0x25fd, 0x25fe,
- 0x2614, 0x2615,
- 0x2648, 0x2653,
- 0x267f, 0x267f,
- 0x2693, 0x2693,
- 0x26a1, 0x26a1,
- 0x26aa, 0x26ab,
- 0x26bd, 0x26be,
- 0x26c4, 0x26c5,
- 0x26ce, 0x26ce,
- 0x26d4, 0x26d4,
- 0x26ea, 0x26ea,
- 0x26f2, 0x26f3,
- 0x26f5, 0x26f5,
- 0x26fa, 0x26fa,
- 0x26fd, 0x26fd,
- 0x2705, 0x2705,
- 0x270a, 0x270b,
- 0x2728, 0x2728,
- 0x274c, 0x274c,
- 0x274e, 0x274e,
- 0x2753, 0x2755,
- 0x2757, 0x2757,
- 0x2795, 0x2797,
- 0x27b0, 0x27b0,
- 0x27bf, 0x27bf,
- 0x2b1b, 0x2b1c,
- 0x2b50, 0x2b50,
- 0x2b55, 0x2b55,
- 0x1f004, 0x1f004,
- 0x1f0cf, 0x1f0cf,
- 0x1f18e, 0x1f18e,
- 0x1f191, 0x1f19a,
- 0x1f1e6, 0x1f1ff,
- 0x1f201, 0x1f201,
- 0x1f21a, 0x1f21a,
- 0x1f22f, 0x1f22f,
- 0x1f232, 0x1f236,
- 0x1f238, 0x1f23a,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f32d, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f37e, 0x1f393,
- 0x1f3a0, 0x1f3ca,
- 0x1f3cf, 0x1f3d3,
- 0x1f3e0, 0x1f3f0,
- 0x1f3f4, 0x1f3f4,
- 0x1f3f8, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4fc,
- 0x1f4ff, 0x1f53d,
- 0x1f54b, 0x1f54e,
- 0x1f550, 0x1f567,
- 0x1f57a, 0x1f57a,
- 0x1f595, 0x1f596,
- 0x1f5a4, 0x1f5a4,
- 0x1f5fb, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f6cc, 0x1f6cc,
- 0x1f6d0, 0x1f6d2,
- 0x1f6d5, 0x1f6d7,
- 0x1f6dc, 0x1f6df,
- 0x1f6eb, 0x1f6ec,
- 0x1f6f4, 0x1f6fc,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f90c, 0x1f93a,
- 0x1f93c, 0x1f945,
- 0x1f947, 0x1f9ff,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
-}; /* CR_Emoji_Presentation */
-
-/* 'Emoji_Modifier': Emoji */
-static const OnigCodePoint CR_Emoji_Modifier[] = {
- 1,
- 0x1f3fb, 0x1f3ff,
-}; /* CR_Emoji_Modifier */
-
-/* 'Emoji_Modifier_Base': Emoji */
-static const OnigCodePoint CR_Emoji_Modifier_Base[] = {
- 40,
- 0x261d, 0x261d,
- 0x26f9, 0x26f9,
- 0x270a, 0x270d,
- 0x1f385, 0x1f385,
- 0x1f3c2, 0x1f3c4,
- 0x1f3c7, 0x1f3c7,
- 0x1f3ca, 0x1f3cc,
- 0x1f442, 0x1f443,
- 0x1f446, 0x1f450,
- 0x1f466, 0x1f478,
- 0x1f47c, 0x1f47c,
- 0x1f481, 0x1f483,
- 0x1f485, 0x1f487,
- 0x1f48f, 0x1f48f,
- 0x1f491, 0x1f491,
- 0x1f4aa, 0x1f4aa,
- 0x1f574, 0x1f575,
- 0x1f57a, 0x1f57a,
- 0x1f590, 0x1f590,
- 0x1f595, 0x1f596,
- 0x1f645, 0x1f647,
- 0x1f64b, 0x1f64f,
- 0x1f6a3, 0x1f6a3,
- 0x1f6b4, 0x1f6b6,
- 0x1f6c0, 0x1f6c0,
- 0x1f6cc, 0x1f6cc,
- 0x1f90c, 0x1f90c,
- 0x1f90f, 0x1f90f,
- 0x1f918, 0x1f91f,
- 0x1f926, 0x1f926,
- 0x1f930, 0x1f939,
- 0x1f93c, 0x1f93e,
- 0x1f977, 0x1f977,
- 0x1f9b5, 0x1f9b6,
- 0x1f9b8, 0x1f9b9,
- 0x1f9bb, 0x1f9bb,
- 0x1f9cd, 0x1f9cf,
- 0x1f9d1, 0x1f9dd,
- 0x1fac3, 0x1fac5,
- 0x1faf0, 0x1faf8,
-}; /* CR_Emoji_Modifier_Base */
-
-/* 'Emoji_Component': Emoji */
-static const OnigCodePoint CR_Emoji_Component[] = {
- 10,
- 0x0023, 0x0023,
- 0x002a, 0x002a,
- 0x0030, 0x0039,
- 0x200d, 0x200d,
- 0x20e3, 0x20e3,
- 0xfe0f, 0xfe0f,
- 0x1f1e6, 0x1f1ff,
- 0x1f3fb, 0x1f3ff,
- 0x1f9b0, 0x1f9b3,
- 0xe0020, 0xe007f,
-}; /* CR_Emoji_Component */
-
-/* 'Extended_Pictographic': Emoji */
-static const OnigCodePoint CR_Extended_Pictographic[] = {
- 78,
- 0x00a9, 0x00a9,
- 0x00ae, 0x00ae,
- 0x203c, 0x203c,
- 0x2049, 0x2049,
- 0x2122, 0x2122,
- 0x2139, 0x2139,
- 0x2194, 0x2199,
- 0x21a9, 0x21aa,
- 0x231a, 0x231b,
- 0x2328, 0x2328,
- 0x2388, 0x2388,
- 0x23cf, 0x23cf,
- 0x23e9, 0x23f3,
- 0x23f8, 0x23fa,
- 0x24c2, 0x24c2,
- 0x25aa, 0x25ab,
- 0x25b6, 0x25b6,
- 0x25c0, 0x25c0,
- 0x25fb, 0x25fe,
- 0x2600, 0x2605,
- 0x2607, 0x2612,
- 0x2614, 0x2685,
- 0x2690, 0x2705,
- 0x2708, 0x2712,
- 0x2714, 0x2714,
- 0x2716, 0x2716,
- 0x271d, 0x271d,
- 0x2721, 0x2721,
- 0x2728, 0x2728,
- 0x2733, 0x2734,
- 0x2744, 0x2744,
- 0x2747, 0x2747,
- 0x274c, 0x274c,
- 0x274e, 0x274e,
- 0x2753, 0x2755,
- 0x2757, 0x2757,
- 0x2763, 0x2767,
- 0x2795, 0x2797,
- 0x27a1, 0x27a1,
- 0x27b0, 0x27b0,
- 0x27bf, 0x27bf,
- 0x2934, 0x2935,
- 0x2b05, 0x2b07,
- 0x2b1b, 0x2b1c,
- 0x2b50, 0x2b50,
- 0x2b55, 0x2b55,
- 0x3030, 0x3030,
- 0x303d, 0x303d,
- 0x3297, 0x3297,
- 0x3299, 0x3299,
- 0x1f000, 0x1f0ff,
- 0x1f10d, 0x1f10f,
- 0x1f12f, 0x1f12f,
- 0x1f16c, 0x1f171,
- 0x1f17e, 0x1f17f,
- 0x1f18e, 0x1f18e,
- 0x1f191, 0x1f19a,
- 0x1f1ad, 0x1f1e5,
- 0x1f201, 0x1f20f,
- 0x1f21a, 0x1f21a,
- 0x1f22f, 0x1f22f,
- 0x1f232, 0x1f23a,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f3fa,
- 0x1f400, 0x1f53d,
- 0x1f546, 0x1f64f,
- 0x1f680, 0x1f6ff,
- 0x1f774, 0x1f77f,
- 0x1f7d5, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8ff,
- 0x1f90c, 0x1f93a,
- 0x1f93c, 0x1f945,
- 0x1f947, 0x1faff,
- 0x1fc00, 0x1fffd,
-}; /* CR_Extended_Pictographic */
-
-/* 'Unknown': Script */
-static const OnigCodePoint CR_Unknown[] = {
- 705,
- 0x0378, 0x0379,
- 0x0380, 0x0383,
- 0x038b, 0x038b,
- 0x038d, 0x038d,
- 0x03a2, 0x03a2,
- 0x0530, 0x0530,
- 0x0557, 0x0558,
- 0x058b, 0x058c,
- 0x0590, 0x0590,
- 0x05c8, 0x05cf,
- 0x05eb, 0x05ee,
- 0x05f5, 0x05ff,
- 0x070e, 0x070e,
- 0x074b, 0x074c,
- 0x07b2, 0x07bf,
- 0x07fb, 0x07fc,
- 0x082e, 0x082f,
- 0x083f, 0x083f,
- 0x085c, 0x085d,
- 0x085f, 0x085f,
- 0x086b, 0x086f,
- 0x088f, 0x088f,
- 0x0892, 0x0897,
- 0x0984, 0x0984,
- 0x098d, 0x098e,
- 0x0991, 0x0992,
- 0x09a9, 0x09a9,
- 0x09b1, 0x09b1,
- 0x09b3, 0x09b5,
- 0x09ba, 0x09bb,
- 0x09c5, 0x09c6,
- 0x09c9, 0x09ca,
- 0x09cf, 0x09d6,
- 0x09d8, 0x09db,
- 0x09de, 0x09de,
- 0x09e4, 0x09e5,
- 0x09ff, 0x0a00,
- 0x0a04, 0x0a04,
- 0x0a0b, 0x0a0e,
- 0x0a11, 0x0a12,
- 0x0a29, 0x0a29,
- 0x0a31, 0x0a31,
- 0x0a34, 0x0a34,
- 0x0a37, 0x0a37,
- 0x0a3a, 0x0a3b,
- 0x0a3d, 0x0a3d,
- 0x0a43, 0x0a46,
- 0x0a49, 0x0a4a,
- 0x0a4e, 0x0a50,
- 0x0a52, 0x0a58,
- 0x0a5d, 0x0a5d,
- 0x0a5f, 0x0a65,
- 0x0a77, 0x0a80,
- 0x0a84, 0x0a84,
- 0x0a8e, 0x0a8e,
- 0x0a92, 0x0a92,
- 0x0aa9, 0x0aa9,
- 0x0ab1, 0x0ab1,
- 0x0ab4, 0x0ab4,
- 0x0aba, 0x0abb,
- 0x0ac6, 0x0ac6,
- 0x0aca, 0x0aca,
- 0x0ace, 0x0acf,
- 0x0ad1, 0x0adf,
- 0x0ae4, 0x0ae5,
- 0x0af2, 0x0af8,
- 0x0b00, 0x0b00,
- 0x0b04, 0x0b04,
- 0x0b0d, 0x0b0e,
- 0x0b11, 0x0b12,
- 0x0b29, 0x0b29,
- 0x0b31, 0x0b31,
- 0x0b34, 0x0b34,
- 0x0b3a, 0x0b3b,
- 0x0b45, 0x0b46,
- 0x0b49, 0x0b4a,
- 0x0b4e, 0x0b54,
- 0x0b58, 0x0b5b,
- 0x0b5e, 0x0b5e,
- 0x0b64, 0x0b65,
- 0x0b78, 0x0b81,
- 0x0b84, 0x0b84,
- 0x0b8b, 0x0b8d,
- 0x0b91, 0x0b91,
- 0x0b96, 0x0b98,
- 0x0b9b, 0x0b9b,
- 0x0b9d, 0x0b9d,
- 0x0ba0, 0x0ba2,
- 0x0ba5, 0x0ba7,
- 0x0bab, 0x0bad,
- 0x0bba, 0x0bbd,
- 0x0bc3, 0x0bc5,
- 0x0bc9, 0x0bc9,
- 0x0bce, 0x0bcf,
- 0x0bd1, 0x0bd6,
- 0x0bd8, 0x0be5,
- 0x0bfb, 0x0bff,
- 0x0c0d, 0x0c0d,
- 0x0c11, 0x0c11,
- 0x0c29, 0x0c29,
- 0x0c3a, 0x0c3b,
- 0x0c45, 0x0c45,
- 0x0c49, 0x0c49,
- 0x0c4e, 0x0c54,
- 0x0c57, 0x0c57,
- 0x0c5b, 0x0c5c,
- 0x0c5e, 0x0c5f,
- 0x0c64, 0x0c65,
- 0x0c70, 0x0c76,
- 0x0c8d, 0x0c8d,
- 0x0c91, 0x0c91,
- 0x0ca9, 0x0ca9,
- 0x0cb4, 0x0cb4,
- 0x0cba, 0x0cbb,
- 0x0cc5, 0x0cc5,
- 0x0cc9, 0x0cc9,
- 0x0cce, 0x0cd4,
- 0x0cd7, 0x0cdc,
- 0x0cdf, 0x0cdf,
- 0x0ce4, 0x0ce5,
- 0x0cf0, 0x0cf0,
- 0x0cf4, 0x0cff,
- 0x0d0d, 0x0d0d,
- 0x0d11, 0x0d11,
- 0x0d45, 0x0d45,
- 0x0d49, 0x0d49,
- 0x0d50, 0x0d53,
- 0x0d64, 0x0d65,
- 0x0d80, 0x0d80,
- 0x0d84, 0x0d84,
- 0x0d97, 0x0d99,
- 0x0db2, 0x0db2,
- 0x0dbc, 0x0dbc,
- 0x0dbe, 0x0dbf,
- 0x0dc7, 0x0dc9,
- 0x0dcb, 0x0dce,
- 0x0dd5, 0x0dd5,
- 0x0dd7, 0x0dd7,
- 0x0de0, 0x0de5,
- 0x0df0, 0x0df1,
- 0x0df5, 0x0e00,
- 0x0e3b, 0x0e3e,
- 0x0e5c, 0x0e80,
- 0x0e83, 0x0e83,
- 0x0e85, 0x0e85,
- 0x0e8b, 0x0e8b,
- 0x0ea4, 0x0ea4,
- 0x0ea6, 0x0ea6,
- 0x0ebe, 0x0ebf,
- 0x0ec5, 0x0ec5,
- 0x0ec7, 0x0ec7,
- 0x0ecf, 0x0ecf,
- 0x0eda, 0x0edb,
- 0x0ee0, 0x0eff,
- 0x0f48, 0x0f48,
- 0x0f6d, 0x0f70,
- 0x0f98, 0x0f98,
- 0x0fbd, 0x0fbd,
- 0x0fcd, 0x0fcd,
- 0x0fdb, 0x0fff,
- 0x10c6, 0x10c6,
- 0x10c8, 0x10cc,
- 0x10ce, 0x10cf,
- 0x1249, 0x1249,
- 0x124e, 0x124f,
- 0x1257, 0x1257,
- 0x1259, 0x1259,
- 0x125e, 0x125f,
- 0x1289, 0x1289,
- 0x128e, 0x128f,
- 0x12b1, 0x12b1,
- 0x12b6, 0x12b7,
- 0x12bf, 0x12bf,
- 0x12c1, 0x12c1,
- 0x12c6, 0x12c7,
- 0x12d7, 0x12d7,
- 0x1311, 0x1311,
- 0x1316, 0x1317,
- 0x135b, 0x135c,
- 0x137d, 0x137f,
- 0x139a, 0x139f,
- 0x13f6, 0x13f7,
- 0x13fe, 0x13ff,
- 0x169d, 0x169f,
- 0x16f9, 0x16ff,
- 0x1716, 0x171e,
- 0x1737, 0x173f,
- 0x1754, 0x175f,
- 0x176d, 0x176d,
- 0x1771, 0x1771,
- 0x1774, 0x177f,
- 0x17de, 0x17df,
- 0x17ea, 0x17ef,
- 0x17fa, 0x17ff,
- 0x181a, 0x181f,
- 0x1879, 0x187f,
- 0x18ab, 0x18af,
- 0x18f6, 0x18ff,
- 0x191f, 0x191f,
- 0x192c, 0x192f,
- 0x193c, 0x193f,
- 0x1941, 0x1943,
- 0x196e, 0x196f,
- 0x1975, 0x197f,
- 0x19ac, 0x19af,
- 0x19ca, 0x19cf,
- 0x19db, 0x19dd,
- 0x1a1c, 0x1a1d,
- 0x1a5f, 0x1a5f,
- 0x1a7d, 0x1a7e,
- 0x1a8a, 0x1a8f,
- 0x1a9a, 0x1a9f,
- 0x1aae, 0x1aaf,
- 0x1acf, 0x1aff,
- 0x1b4d, 0x1b4f,
- 0x1b7f, 0x1b7f,
- 0x1bf4, 0x1bfb,
- 0x1c38, 0x1c3a,
- 0x1c4a, 0x1c4c,
- 0x1c89, 0x1c8f,
- 0x1cbb, 0x1cbc,
- 0x1cc8, 0x1ccf,
- 0x1cfb, 0x1cff,
- 0x1f16, 0x1f17,
- 0x1f1e, 0x1f1f,
- 0x1f46, 0x1f47,
- 0x1f4e, 0x1f4f,
- 0x1f58, 0x1f58,
- 0x1f5a, 0x1f5a,
- 0x1f5c, 0x1f5c,
- 0x1f5e, 0x1f5e,
- 0x1f7e, 0x1f7f,
- 0x1fb5, 0x1fb5,
- 0x1fc5, 0x1fc5,
- 0x1fd4, 0x1fd5,
- 0x1fdc, 0x1fdc,
- 0x1ff0, 0x1ff1,
- 0x1ff5, 0x1ff5,
- 0x1fff, 0x1fff,
- 0x2065, 0x2065,
- 0x2072, 0x2073,
- 0x208f, 0x208f,
- 0x209d, 0x209f,
- 0x20c1, 0x20cf,
- 0x20f1, 0x20ff,
- 0x218c, 0x218f,
- 0x2427, 0x243f,
- 0x244b, 0x245f,
- 0x2b74, 0x2b75,
- 0x2b96, 0x2b96,
- 0x2cf4, 0x2cf8,
- 0x2d26, 0x2d26,
- 0x2d28, 0x2d2c,
- 0x2d2e, 0x2d2f,
- 0x2d68, 0x2d6e,
- 0x2d71, 0x2d7e,
- 0x2d97, 0x2d9f,
- 0x2da7, 0x2da7,
- 0x2daf, 0x2daf,
- 0x2db7, 0x2db7,
- 0x2dbf, 0x2dbf,
- 0x2dc7, 0x2dc7,
- 0x2dcf, 0x2dcf,
- 0x2dd7, 0x2dd7,
- 0x2ddf, 0x2ddf,
- 0x2e5e, 0x2e7f,
- 0x2e9a, 0x2e9a,
- 0x2ef4, 0x2eff,
- 0x2fd6, 0x2fef,
- 0x3040, 0x3040,
- 0x3097, 0x3098,
- 0x3100, 0x3104,
- 0x3130, 0x3130,
- 0x318f, 0x318f,
- 0x31e4, 0x31ee,
- 0x321f, 0x321f,
- 0xa48d, 0xa48f,
- 0xa4c7, 0xa4cf,
- 0xa62c, 0xa63f,
- 0xa6f8, 0xa6ff,
- 0xa7cb, 0xa7cf,
- 0xa7d2, 0xa7d2,
- 0xa7d4, 0xa7d4,
- 0xa7da, 0xa7f1,
- 0xa82d, 0xa82f,
- 0xa83a, 0xa83f,
- 0xa878, 0xa87f,
- 0xa8c6, 0xa8cd,
- 0xa8da, 0xa8df,
- 0xa954, 0xa95e,
- 0xa97d, 0xa97f,
- 0xa9ce, 0xa9ce,
- 0xa9da, 0xa9dd,
- 0xa9ff, 0xa9ff,
- 0xaa37, 0xaa3f,
- 0xaa4e, 0xaa4f,
- 0xaa5a, 0xaa5b,
- 0xaac3, 0xaada,
- 0xaaf7, 0xab00,
- 0xab07, 0xab08,
- 0xab0f, 0xab10,
- 0xab17, 0xab1f,
- 0xab27, 0xab27,
- 0xab2f, 0xab2f,
- 0xab6c, 0xab6f,
- 0xabee, 0xabef,
- 0xabfa, 0xabff,
- 0xd7a4, 0xd7af,
- 0xd7c7, 0xd7ca,
- 0xd7fc, 0xf8ff,
- 0xfa6e, 0xfa6f,
- 0xfada, 0xfaff,
- 0xfb07, 0xfb12,
- 0xfb18, 0xfb1c,
- 0xfb37, 0xfb37,
- 0xfb3d, 0xfb3d,
- 0xfb3f, 0xfb3f,
- 0xfb42, 0xfb42,
- 0xfb45, 0xfb45,
- 0xfbc3, 0xfbd2,
- 0xfd90, 0xfd91,
- 0xfdc8, 0xfdce,
- 0xfdd0, 0xfdef,
- 0xfe1a, 0xfe1f,
- 0xfe53, 0xfe53,
- 0xfe67, 0xfe67,
- 0xfe6c, 0xfe6f,
- 0xfe75, 0xfe75,
- 0xfefd, 0xfefe,
- 0xff00, 0xff00,
- 0xffbf, 0xffc1,
- 0xffc8, 0xffc9,
- 0xffd0, 0xffd1,
- 0xffd8, 0xffd9,
- 0xffdd, 0xffdf,
- 0xffe7, 0xffe7,
- 0xffef, 0xfff8,
- 0xfffe, 0xffff,
- 0x1000c, 0x1000c,
- 0x10027, 0x10027,
- 0x1003b, 0x1003b,
- 0x1003e, 0x1003e,
- 0x1004e, 0x1004f,
- 0x1005e, 0x1007f,
- 0x100fb, 0x100ff,
- 0x10103, 0x10106,
- 0x10134, 0x10136,
- 0x1018f, 0x1018f,
- 0x1019d, 0x1019f,
- 0x101a1, 0x101cf,
- 0x101fe, 0x1027f,
- 0x1029d, 0x1029f,
- 0x102d1, 0x102df,
- 0x102fc, 0x102ff,
- 0x10324, 0x1032c,
- 0x1034b, 0x1034f,
- 0x1037b, 0x1037f,
- 0x1039e, 0x1039e,
- 0x103c4, 0x103c7,
- 0x103d6, 0x103ff,
- 0x1049e, 0x1049f,
- 0x104aa, 0x104af,
- 0x104d4, 0x104d7,
- 0x104fc, 0x104ff,
- 0x10528, 0x1052f,
- 0x10564, 0x1056e,
- 0x1057b, 0x1057b,
- 0x1058b, 0x1058b,
- 0x10593, 0x10593,
- 0x10596, 0x10596,
- 0x105a2, 0x105a2,
- 0x105b2, 0x105b2,
- 0x105ba, 0x105ba,
- 0x105bd, 0x105ff,
- 0x10737, 0x1073f,
- 0x10756, 0x1075f,
- 0x10768, 0x1077f,
- 0x10786, 0x10786,
- 0x107b1, 0x107b1,
- 0x107bb, 0x107ff,
- 0x10806, 0x10807,
- 0x10809, 0x10809,
- 0x10836, 0x10836,
- 0x10839, 0x1083b,
- 0x1083d, 0x1083e,
- 0x10856, 0x10856,
- 0x1089f, 0x108a6,
- 0x108b0, 0x108df,
- 0x108f3, 0x108f3,
- 0x108f6, 0x108fa,
- 0x1091c, 0x1091e,
- 0x1093a, 0x1093e,
- 0x10940, 0x1097f,
- 0x109b8, 0x109bb,
- 0x109d0, 0x109d1,
- 0x10a04, 0x10a04,
- 0x10a07, 0x10a0b,
- 0x10a14, 0x10a14,
- 0x10a18, 0x10a18,
- 0x10a36, 0x10a37,
- 0x10a3b, 0x10a3e,
- 0x10a49, 0x10a4f,
- 0x10a59, 0x10a5f,
- 0x10aa0, 0x10abf,
- 0x10ae7, 0x10aea,
- 0x10af7, 0x10aff,
- 0x10b36, 0x10b38,
- 0x10b56, 0x10b57,
- 0x10b73, 0x10b77,
- 0x10b92, 0x10b98,
- 0x10b9d, 0x10ba8,
- 0x10bb0, 0x10bff,
- 0x10c49, 0x10c7f,
- 0x10cb3, 0x10cbf,
- 0x10cf3, 0x10cf9,
- 0x10d28, 0x10d2f,
- 0x10d3a, 0x10e5f,
- 0x10e7f, 0x10e7f,
- 0x10eaa, 0x10eaa,
- 0x10eae, 0x10eaf,
- 0x10eb2, 0x10efc,
- 0x10f28, 0x10f2f,
- 0x10f5a, 0x10f6f,
- 0x10f8a, 0x10faf,
- 0x10fcc, 0x10fdf,
- 0x10ff7, 0x10fff,
- 0x1104e, 0x11051,
- 0x11076, 0x1107e,
- 0x110c3, 0x110cc,
- 0x110ce, 0x110cf,
- 0x110e9, 0x110ef,
- 0x110fa, 0x110ff,
- 0x11135, 0x11135,
- 0x11148, 0x1114f,
- 0x11177, 0x1117f,
- 0x111e0, 0x111e0,
- 0x111f5, 0x111ff,
- 0x11212, 0x11212,
- 0x11242, 0x1127f,
- 0x11287, 0x11287,
- 0x11289, 0x11289,
- 0x1128e, 0x1128e,
- 0x1129e, 0x1129e,
- 0x112aa, 0x112af,
- 0x112eb, 0x112ef,
- 0x112fa, 0x112ff,
- 0x11304, 0x11304,
- 0x1130d, 0x1130e,
- 0x11311, 0x11312,
- 0x11329, 0x11329,
- 0x11331, 0x11331,
- 0x11334, 0x11334,
- 0x1133a, 0x1133a,
- 0x11345, 0x11346,
- 0x11349, 0x1134a,
- 0x1134e, 0x1134f,
- 0x11351, 0x11356,
- 0x11358, 0x1135c,
- 0x11364, 0x11365,
- 0x1136d, 0x1136f,
- 0x11375, 0x113ff,
- 0x1145c, 0x1145c,
- 0x11462, 0x1147f,
- 0x114c8, 0x114cf,
- 0x114da, 0x1157f,
- 0x115b6, 0x115b7,
- 0x115de, 0x115ff,
- 0x11645, 0x1164f,
- 0x1165a, 0x1165f,
- 0x1166d, 0x1167f,
- 0x116ba, 0x116bf,
- 0x116ca, 0x116ff,
- 0x1171b, 0x1171c,
- 0x1172c, 0x1172f,
- 0x11747, 0x117ff,
- 0x1183c, 0x1189f,
- 0x118f3, 0x118fe,
- 0x11907, 0x11908,
- 0x1190a, 0x1190b,
- 0x11914, 0x11914,
- 0x11917, 0x11917,
- 0x11936, 0x11936,
- 0x11939, 0x1193a,
- 0x11947, 0x1194f,
- 0x1195a, 0x1199f,
- 0x119a8, 0x119a9,
- 0x119d8, 0x119d9,
- 0x119e5, 0x119ff,
- 0x11a48, 0x11a4f,
- 0x11aa3, 0x11aaf,
- 0x11af9, 0x11aff,
- 0x11b0a, 0x11bff,
- 0x11c09, 0x11c09,
- 0x11c37, 0x11c37,
- 0x11c46, 0x11c4f,
- 0x11c6d, 0x11c6f,
- 0x11c90, 0x11c91,
- 0x11ca8, 0x11ca8,
- 0x11cb7, 0x11cff,
- 0x11d07, 0x11d07,
- 0x11d0a, 0x11d0a,
- 0x11d37, 0x11d39,
- 0x11d3b, 0x11d3b,
- 0x11d3e, 0x11d3e,
- 0x11d48, 0x11d4f,
- 0x11d5a, 0x11d5f,
- 0x11d66, 0x11d66,
- 0x11d69, 0x11d69,
- 0x11d8f, 0x11d8f,
- 0x11d92, 0x11d92,
- 0x11d99, 0x11d9f,
- 0x11daa, 0x11edf,
- 0x11ef9, 0x11eff,
- 0x11f11, 0x11f11,
- 0x11f3b, 0x11f3d,
- 0x11f5a, 0x11faf,
- 0x11fb1, 0x11fbf,
- 0x11ff2, 0x11ffe,
- 0x1239a, 0x123ff,
- 0x1246f, 0x1246f,
- 0x12475, 0x1247f,
- 0x12544, 0x12f8f,
- 0x12ff3, 0x12fff,
- 0x13456, 0x143ff,
- 0x14647, 0x167ff,
- 0x16a39, 0x16a3f,
- 0x16a5f, 0x16a5f,
- 0x16a6a, 0x16a6d,
- 0x16abf, 0x16abf,
- 0x16aca, 0x16acf,
- 0x16aee, 0x16aef,
- 0x16af6, 0x16aff,
- 0x16b46, 0x16b4f,
- 0x16b5a, 0x16b5a,
- 0x16b62, 0x16b62,
- 0x16b78, 0x16b7c,
- 0x16b90, 0x16e3f,
- 0x16e9b, 0x16eff,
- 0x16f4b, 0x16f4e,
- 0x16f88, 0x16f8e,
- 0x16fa0, 0x16fdf,
- 0x16fe5, 0x16fef,
- 0x16ff2, 0x16fff,
- 0x187f8, 0x187ff,
- 0x18cd6, 0x18cff,
- 0x18d09, 0x1afef,
- 0x1aff4, 0x1aff4,
- 0x1affc, 0x1affc,
- 0x1afff, 0x1afff,
- 0x1b123, 0x1b131,
- 0x1b133, 0x1b14f,
- 0x1b153, 0x1b154,
- 0x1b156, 0x1b163,
- 0x1b168, 0x1b16f,
- 0x1b2fc, 0x1bbff,
- 0x1bc6b, 0x1bc6f,
- 0x1bc7d, 0x1bc7f,
- 0x1bc89, 0x1bc8f,
- 0x1bc9a, 0x1bc9b,
- 0x1bca4, 0x1ceff,
- 0x1cf2e, 0x1cf2f,
- 0x1cf47, 0x1cf4f,
- 0x1cfc4, 0x1cfff,
- 0x1d0f6, 0x1d0ff,
- 0x1d127, 0x1d128,
- 0x1d1eb, 0x1d1ff,
- 0x1d246, 0x1d2bf,
- 0x1d2d4, 0x1d2df,
- 0x1d2f4, 0x1d2ff,
- 0x1d357, 0x1d35f,
- 0x1d379, 0x1d3ff,
- 0x1d455, 0x1d455,
- 0x1d49d, 0x1d49d,
- 0x1d4a0, 0x1d4a1,
- 0x1d4a3, 0x1d4a4,
- 0x1d4a7, 0x1d4a8,
- 0x1d4ad, 0x1d4ad,
- 0x1d4ba, 0x1d4ba,
- 0x1d4bc, 0x1d4bc,
- 0x1d4c4, 0x1d4c4,
- 0x1d506, 0x1d506,
- 0x1d50b, 0x1d50c,
- 0x1d515, 0x1d515,
- 0x1d51d, 0x1d51d,
- 0x1d53a, 0x1d53a,
- 0x1d53f, 0x1d53f,
- 0x1d545, 0x1d545,
- 0x1d547, 0x1d549,
- 0x1d551, 0x1d551,
- 0x1d6a6, 0x1d6a7,
- 0x1d7cc, 0x1d7cd,
- 0x1da8c, 0x1da9a,
- 0x1daa0, 0x1daa0,
- 0x1dab0, 0x1deff,
- 0x1df1f, 0x1df24,
- 0x1df2b, 0x1dfff,
- 0x1e007, 0x1e007,
- 0x1e019, 0x1e01a,
- 0x1e022, 0x1e022,
- 0x1e025, 0x1e025,
- 0x1e02b, 0x1e02f,
- 0x1e06e, 0x1e08e,
- 0x1e090, 0x1e0ff,
- 0x1e12d, 0x1e12f,
- 0x1e13e, 0x1e13f,
- 0x1e14a, 0x1e14d,
- 0x1e150, 0x1e28f,
- 0x1e2af, 0x1e2bf,
- 0x1e2fa, 0x1e2fe,
- 0x1e300, 0x1e4cf,
- 0x1e4fa, 0x1e7df,
- 0x1e7e7, 0x1e7e7,
- 0x1e7ec, 0x1e7ec,
- 0x1e7ef, 0x1e7ef,
- 0x1e7ff, 0x1e7ff,
- 0x1e8c5, 0x1e8c6,
- 0x1e8d7, 0x1e8ff,
- 0x1e94c, 0x1e94f,
- 0x1e95a, 0x1e95d,
- 0x1e960, 0x1ec70,
- 0x1ecb5, 0x1ed00,
- 0x1ed3e, 0x1edff,
- 0x1ee04, 0x1ee04,
- 0x1ee20, 0x1ee20,
- 0x1ee23, 0x1ee23,
- 0x1ee25, 0x1ee26,
- 0x1ee28, 0x1ee28,
- 0x1ee33, 0x1ee33,
- 0x1ee38, 0x1ee38,
- 0x1ee3a, 0x1ee3a,
- 0x1ee3c, 0x1ee41,
- 0x1ee43, 0x1ee46,
- 0x1ee48, 0x1ee48,
- 0x1ee4a, 0x1ee4a,
- 0x1ee4c, 0x1ee4c,
- 0x1ee50, 0x1ee50,
- 0x1ee53, 0x1ee53,
- 0x1ee55, 0x1ee56,
- 0x1ee58, 0x1ee58,
- 0x1ee5a, 0x1ee5a,
- 0x1ee5c, 0x1ee5c,
- 0x1ee5e, 0x1ee5e,
- 0x1ee60, 0x1ee60,
- 0x1ee63, 0x1ee63,
- 0x1ee65, 0x1ee66,
- 0x1ee6b, 0x1ee6b,
- 0x1ee73, 0x1ee73,
- 0x1ee78, 0x1ee78,
- 0x1ee7d, 0x1ee7d,
- 0x1ee7f, 0x1ee7f,
- 0x1ee8a, 0x1ee8a,
- 0x1ee9c, 0x1eea0,
- 0x1eea4, 0x1eea4,
- 0x1eeaa, 0x1eeaa,
- 0x1eebc, 0x1eeef,
- 0x1eef2, 0x1efff,
- 0x1f02c, 0x1f02f,
- 0x1f094, 0x1f09f,
- 0x1f0af, 0x1f0b0,
- 0x1f0c0, 0x1f0c0,
- 0x1f0d0, 0x1f0d0,
- 0x1f0f6, 0x1f0ff,
- 0x1f1ae, 0x1f1e5,
- 0x1f203, 0x1f20f,
- 0x1f23c, 0x1f23f,
- 0x1f249, 0x1f24f,
- 0x1f252, 0x1f25f,
- 0x1f266, 0x1f2ff,
- 0x1f6d8, 0x1f6db,
- 0x1f6ed, 0x1f6ef,
- 0x1f6fd, 0x1f6ff,
- 0x1f777, 0x1f77a,
- 0x1f7da, 0x1f7df,
- 0x1f7ec, 0x1f7ef,
- 0x1f7f1, 0x1f7ff,
- 0x1f80c, 0x1f80f,
- 0x1f848, 0x1f84f,
- 0x1f85a, 0x1f85f,
- 0x1f888, 0x1f88f,
- 0x1f8ae, 0x1f8af,
- 0x1f8b2, 0x1f8ff,
- 0x1fa54, 0x1fa5f,
- 0x1fa6e, 0x1fa6f,
- 0x1fa7d, 0x1fa7f,
- 0x1fa89, 0x1fa8f,
- 0x1fabe, 0x1fabe,
- 0x1fac6, 0x1facd,
- 0x1fadc, 0x1fadf,
- 0x1fae9, 0x1faef,
- 0x1faf9, 0x1faff,
- 0x1fb93, 0x1fb93,
- 0x1fbcb, 0x1fbef,
- 0x1fbfa, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2b73a, 0x2b73f,
- 0x2b81e, 0x2b81f,
- 0x2cea2, 0x2ceaf,
- 0x2ebe1, 0x2ebef,
- 0x2ee5e, 0x2f7ff,
- 0x2fa1e, 0x2ffff,
- 0x3134b, 0x3134f,
- 0x323b0, 0xe0000,
- 0xe0002, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0x10ffff,
-}; /* CR_Unknown */
-
-#ifdef USE_UNICODE_AGE_PROPERTIES
-/* 'Age_1_1': Derived Age 1.1 */
-static const OnigCodePoint CR_Age_1_1[] = {
- 288,
- 0x0000, 0x01f5,
- 0x01fa, 0x0217,
- 0x0250, 0x02a8,
- 0x02b0, 0x02de,
- 0x02e0, 0x02e9,
- 0x0300, 0x0345,
- 0x0360, 0x0361,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d6,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03f3,
- 0x0401, 0x040c,
- 0x040e, 0x044f,
- 0x0451, 0x045c,
- 0x045e, 0x0486,
- 0x0490, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04eb,
- 0x04ee, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x0589,
- 0x05b0, 0x05b9,
- 0x05bb, 0x05c3,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0652,
- 0x0660, 0x066d,
- 0x0670, 0x06b7,
- 0x06ba, 0x06be,
- 0x06c0, 0x06ce,
- 0x06d0, 0x06ed,
- 0x06f0, 0x06f9,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1e00, 0x1e9a,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x202e,
- 0x2030, 0x2046,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20aa,
- 0x20d0, 0x20e1,
- 0x2100, 0x2138,
- 0x2153, 0x2182,
- 0x2190, 0x21ea,
- 0x2200, 0x22f1,
- 0x2300, 0x2300,
- 0x2302, 0x237a,
- 0x2400, 0x2424,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25ef,
- 0x2600, 0x2613,
- 0x261a, 0x266f,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x3000, 0x3037,
- 0x303f, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x319f,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x4e00, 0x9fa5,
- 0xe000, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1e, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffd, 0xffff,
-}; /* CR_Age_1_1 */
-
-/* 'Age_2_0': Derived Age 2.0 */
-static const OnigCodePoint CR_Age_2_0[] = {
- 312,
- 0x0000, 0x01f5,
- 0x01fa, 0x0217,
- 0x0250, 0x02a8,
- 0x02b0, 0x02de,
- 0x02e0, 0x02e9,
- 0x0300, 0x0345,
- 0x0360, 0x0361,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d6,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03f3,
- 0x0401, 0x040c,
- 0x040e, 0x044f,
- 0x0451, 0x045c,
- 0x045e, 0x0486,
- 0x0490, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04eb,
- 0x04ee, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x0589,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0652,
- 0x0660, 0x066d,
- 0x0670, 0x06b7,
- 0x06ba, 0x06be,
- 0x06c0, 0x06ce,
- 0x06d0, 0x06ed,
- 0x06f0, 0x06f9,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f69,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f95,
- 0x0f97, 0x0f97,
- 0x0f99, 0x0fad,
- 0x0fb1, 0x0fb7,
- 0x0fb9, 0x0fb9,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x202e,
- 0x2030, 0x2046,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20ab,
- 0x20d0, 0x20e1,
- 0x2100, 0x2138,
- 0x2153, 0x2182,
- 0x2190, 0x21ea,
- 0x2200, 0x22f1,
- 0x2300, 0x2300,
- 0x2302, 0x237a,
- 0x2400, 0x2424,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25ef,
- 0x2600, 0x2613,
- 0x261a, 0x266f,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x3000, 0x3037,
- 0x303f, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x319f,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x4e00, 0x9fa5,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1e, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffd, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_2_0 */
-
-/* 'Age_2_1': Derived Age 2.1 */
-static const OnigCodePoint CR_Age_2_1[] = {
- 312,
- 0x0000, 0x01f5,
- 0x01fa, 0x0217,
- 0x0250, 0x02a8,
- 0x02b0, 0x02de,
- 0x02e0, 0x02e9,
- 0x0300, 0x0345,
- 0x0360, 0x0361,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d6,
- 0x03da, 0x03da,
- 0x03dc, 0x03dc,
- 0x03de, 0x03de,
- 0x03e0, 0x03e0,
- 0x03e2, 0x03f3,
- 0x0401, 0x040c,
- 0x040e, 0x044f,
- 0x0451, 0x045c,
- 0x045e, 0x0486,
- 0x0490, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04eb,
- 0x04ee, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x0589,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0652,
- 0x0660, 0x066d,
- 0x0670, 0x06b7,
- 0x06ba, 0x06be,
- 0x06c0, 0x06ce,
- 0x06d0, 0x06ed,
- 0x06f0, 0x06f9,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f69,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f95,
- 0x0f97, 0x0f97,
- 0x0f99, 0x0fad,
- 0x0fb1, 0x0fb7,
- 0x0fb9, 0x0fb9,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x202e,
- 0x2030, 0x2046,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20ac,
- 0x20d0, 0x20e1,
- 0x2100, 0x2138,
- 0x2153, 0x2182,
- 0x2190, 0x21ea,
- 0x2200, 0x22f1,
- 0x2300, 0x2300,
- 0x2302, 0x237a,
- 0x2400, 0x2424,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25ef,
- 0x2600, 0x2613,
- 0x261a, 0x266f,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x3000, 0x3037,
- 0x303f, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x319f,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x4e00, 0x9fa5,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1e, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfffc, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_2_1 */
-
-/* 'Age_3_0': Derived Age 3.0 */
-static const OnigCodePoint CR_Age_3_0[] = {
- 369,
- 0x0000, 0x021f,
- 0x0222, 0x0233,
- 0x0250, 0x02ad,
- 0x02b0, 0x02ee,
- 0x0300, 0x034e,
- 0x0360, 0x0362,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d7,
- 0x03da, 0x03f3,
- 0x0400, 0x0486,
- 0x0488, 0x0489,
- 0x048c, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0655,
- 0x0660, 0x066d,
- 0x0670, 0x06ed,
- 0x06f0, 0x06fe,
- 0x0700, 0x070d,
- 0x070f, 0x072c,
- 0x0730, 0x074a,
- 0x0780, 0x07b0,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1780, 0x17dc,
- 0x17e0, 0x17e9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2046,
- 0x2048, 0x204d,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20af,
- 0x20d0, 0x20e3,
- 0x2100, 0x213a,
- 0x2153, 0x2183,
- 0x2190, 0x21f3,
- 0x2200, 0x22f1,
- 0x2300, 0x237b,
- 0x237d, 0x239a,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25f7,
- 0x2600, 0x2613,
- 0x2619, 0x2671,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x2800, 0x28ff,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303a,
- 0x303e, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4a1,
- 0xa4a4, 0xa4b3,
- 0xa4b5, 0xa4c0,
- 0xa4c2, 0xa4c4,
- 0xa4c6, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xffff,
- 0x1fffe, 0x1ffff,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_3_0 */
-
-/* 'Age_3_1': Derived Age 3.1 */
-static const OnigCodePoint CR_Age_3_1[] = {
- 402,
- 0x0000, 0x021f,
- 0x0222, 0x0233,
- 0x0250, 0x02ad,
- 0x02b0, 0x02ee,
- 0x0300, 0x034e,
- 0x0360, 0x0362,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03d7,
- 0x03da, 0x03f5,
- 0x0400, 0x0486,
- 0x0488, 0x0489,
- 0x048c, 0x04c4,
- 0x04c7, 0x04c8,
- 0x04cb, 0x04cc,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0655,
- 0x0660, 0x066d,
- 0x0670, 0x06ed,
- 0x06f0, 0x06fe,
- 0x0700, 0x070d,
- 0x070f, 0x072c,
- 0x0730, 0x074a,
- 0x0780, 0x07b0,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f6,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1780, 0x17dc,
- 0x17e0, 0x17e9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2046,
- 0x2048, 0x204d,
- 0x206a, 0x2070,
- 0x2074, 0x208e,
- 0x20a0, 0x20af,
- 0x20d0, 0x20e3,
- 0x2100, 0x213a,
- 0x2153, 0x2183,
- 0x2190, 0x21f3,
- 0x2200, 0x22f1,
- 0x2300, 0x237b,
- 0x237d, 0x239a,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x24ea,
- 0x2500, 0x2595,
- 0x25a0, 0x25f7,
- 0x2600, 0x2613,
- 0x2619, 0x2671,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2767,
- 0x2776, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x2800, 0x28ff,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303a,
- 0x303e, 0x303f,
- 0x3041, 0x3094,
- 0x3099, 0x309e,
- 0x30a1, 0x30fe,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x3200, 0x321c,
- 0x3220, 0x3243,
- 0x3260, 0x327b,
- 0x327f, 0x32b0,
- 0x32c0, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4a1,
- 0xa4a4, 0xa4b3,
- 0xa4b5, 0xa4c0,
- 0xa4c2, 0xa4c4,
- 0xa4c6, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfb,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe44,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe72,
- 0xfe74, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xff5e,
- 0xff61, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xffff,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10400, 0x10425,
- 0x10428, 0x1044d,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d400, 0x1d454,
- 0x1d456, 0x1d49c,
- 0x1d49e, 0x1d49f,
- 0x1d4a2, 0x1d4a2,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c0,
- 0x1d4c2, 0x1d4c3,
- 0x1d4c5, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d51e, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d546, 0x1d546,
- 0x1d54a, 0x1d550,
- 0x1d552, 0x1d6a3,
- 0x1d6a8, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_3_1 */
-
-/* 'Age_3_2': Derived Age 3.2 */
-static const OnigCodePoint CR_Age_3_2[] = {
- 397,
- 0x0000, 0x0220,
- 0x0222, 0x0233,
- 0x0250, 0x02ad,
- 0x02b0, 0x02ee,
- 0x0300, 0x034f,
- 0x0360, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03f6,
- 0x0400, 0x0486,
- 0x0488, 0x04ce,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0500, 0x050f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x060c, 0x060c,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0655,
- 0x0660, 0x06ed,
- 0x06f0, 0x06fe,
- 0x0700, 0x070d,
- 0x070f, 0x072c,
- 0x0730, 0x074a,
- 0x0780, 0x07b1,
- 0x0901, 0x0903,
- 0x0905, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09bc,
- 0x09be, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a02, 0x0a02,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8b,
- 0x0a8d, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae0,
- 0x0ae6, 0x0aef,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b36, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b70,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bf2,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbe, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f8,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dc,
- 0x17e0, 0x17e9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2052,
- 0x2057, 0x2057,
- 0x205f, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x20a0, 0x20b1,
- 0x20d0, 0x20ea,
- 0x2100, 0x213a,
- 0x213d, 0x214b,
- 0x2153, 0x2183,
- 0x2190, 0x23ce,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x24fe,
- 0x2500, 0x2613,
- 0x2616, 0x2617,
- 0x2619, 0x267d,
- 0x2680, 0x2689,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2aff,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31f0, 0x321c,
- 0x3220, 0x3243,
- 0x3251, 0x327b,
- 0x327f, 0x32cb,
- 0x32d0, 0x32fe,
- 0x3300, 0x3376,
- 0x337b, 0x33dd,
- 0x33e0, 0x33fe,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfc,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe46,
- 0xfe49, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0xffff,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10400, 0x10425,
- 0x10428, 0x1044d,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d400, 0x1d454,
- 0x1d456, 0x1d49c,
- 0x1d49e, 0x1d49f,
- 0x1d4a2, 0x1d4a2,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b9,
- 0x1d4bb, 0x1d4bb,
- 0x1d4bd, 0x1d4c0,
- 0x1d4c2, 0x1d4c3,
- 0x1d4c5, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d51e, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d546, 0x1d546,
- 0x1d54a, 0x1d550,
- 0x1d552, 0x1d6a3,
- 0x1d6a8, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_3_2 */
-
-/* 'Age_4_0': Derived Age 4.0 */
-static const OnigCodePoint CR_Age_4_0[] = {
- 412,
- 0x0000, 0x0236,
- 0x0250, 0x0357,
- 0x035d, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03fb,
- 0x0400, 0x0486,
- 0x0488, 0x04ce,
- 0x04d0, 0x04f5,
- 0x04f8, 0x04f9,
- 0x0500, 0x050f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05a1,
- 0x05a3, 0x05b9,
- 0x05bb, 0x05c4,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x060c, 0x0615,
- 0x061b, 0x061b,
- 0x061f, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x0658,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x074f,
- 0x0780, 0x07b1,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb5,
- 0x0bb7, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be7, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fcf,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10f8,
- 0x10fb, 0x10fb,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1206,
- 0x1208, 0x1246,
- 0x1248, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125a, 0x125d,
- 0x1260, 0x1286,
- 0x1288, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12ae,
- 0x12b0, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c0, 0x12c0,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12ce,
- 0x12d0, 0x12d6,
- 0x12d8, 0x12ee,
- 0x12f0, 0x130e,
- 0x1310, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x131e,
- 0x1320, 0x1346,
- 0x1348, 0x135a,
- 0x1361, 0x137c,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x19e0, 0x19ff,
- 0x1d00, 0x1d6b,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2054,
- 0x2057, 0x2057,
- 0x205f, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x20a0, 0x20b1,
- 0x20d0, 0x20ea,
- 0x2100, 0x213b,
- 0x213d, 0x214b,
- 0x2153, 0x2183,
- 0x2190, 0x23d0,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2617,
- 0x2619, 0x267d,
- 0x2680, 0x2691,
- 0x26a0, 0x26a1,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2b0d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x327d,
- 0x327f, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fa5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1013f,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x1039f,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d300, 0x1d356,
- 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, 0x1d6a3,
- 0x1d6a8, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_4_0 */
-
-/* 'Age_4_1': Derived Age 4.1 */
-static const OnigCodePoint CR_Age_4_1[] = {
- 430,
- 0x0000, 0x0241,
- 0x0250, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037a,
- 0x037e, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x0486,
- 0x0488, 0x04ce,
- 0x04d0, 0x04f9,
- 0x0500, 0x050f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05b9,
- 0x05bb, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x060b, 0x0615,
- 0x061b, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x076d,
- 0x0780, 0x07b1,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x097d, 0x097d,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce1,
- 0x0ce6, 0x0cef,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fd1,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a1f,
- 0x1d00, 0x1dc3,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b5,
- 0x20d0, 0x20eb,
- 0x2100, 0x214c,
- 0x2153, 0x2183,
- 0x2190, 0x23db,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x269c,
- 0x26a0, 0x26b1,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27c6,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2b13,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c80, 0x2cea,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2e00, 0x2e17,
- 0x2e1c, 0x2e1d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31cf,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fbb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa700, 0xa716,
- 0xa800, 0xa82b,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 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, 0x1d7c9,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_4_1 */
-
-/* 'Age_5_0': Derived Age 5.0 */
-static const OnigCodePoint CR_Age_5_0[] = {
- 440,
- 0x0000, 0x036f,
- 0x0374, 0x0375,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x0486,
- 0x0488, 0x0513,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x060b, 0x0615,
- 0x061b, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x063a,
- 0x0640, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x076d,
- 0x0780, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0970,
- 0x097b, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a74,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b43,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3e, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c60, 0x0c61,
- 0x0c66, 0x0c6f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3e, 0x0d43,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d61,
- 0x0d66, 0x0d6f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fcf, 0x0fd1,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x102c, 0x1032,
- 0x1036, 0x1039,
- 0x1040, 0x1059,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18a9,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a1f,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1d00, 0x1dca,
- 0x1dfe, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2063,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b5,
- 0x20d0, 0x20ef,
- 0x2100, 0x214e,
- 0x2153, 0x2184,
- 0x2190, 0x23e7,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x269c,
- 0x26a0, 0x26b2,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27ca,
- 0x27d0, 0x27eb,
- 0x27f0, 0x2b1a,
- 0x2b20, 0x2b23,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2c6c,
- 0x2c74, 0x2c77,
- 0x2c80, 0x2cea,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2e00, 0x2e17,
- 0x2e1c, 0x2e1d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31cf,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fbb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa700, 0xa71a,
- 0xa720, 0xa721,
- 0xa800, 0xa82b,
- 0xa840, 0xa877,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe23,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x10900, 0x10919,
- 0x1091f, 0x1091f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d12a, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_5_0 */
-
-/* 'Age_5_1': Derived Age 5.1 */
-static const OnigCodePoint CR_Age_5_1[] = {
- 455,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0523,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x0606, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0901, 0x0939,
- 0x093c, 0x094d,
- 0x0950, 0x0954,
- 0x0958, 0x0972,
- 0x097b, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fa,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fd4,
- 0x1000, 0x1099,
- 0x109e, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1401, 0x1676,
- 0x1680, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19d9,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a1f,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1baa,
- 0x1bae, 0x1bb9,
- 0x1c00, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1d00, 0x1de6,
- 0x1dfe, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b5,
- 0x20d0, 0x20f0,
- 0x2100, 0x214f,
- 0x2153, 0x2188,
- 0x2190, 0x23e7,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x269d,
- 0x26a0, 0x26bc,
- 0x26c0, 0x26c3,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x2756,
- 0x2758, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27ca,
- 0x27cc, 0x27cc,
- 0x27d0, 0x2b4c,
- 0x2b50, 0x2b54,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2c6f,
- 0x2c71, 0x2c7d,
- 0x2c80, 0x2cea,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e30,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x3243,
- 0x3250, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fc3,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa500, 0xa62b,
- 0xa640, 0xa65f,
- 0xa662, 0xa673,
- 0xa67c, 0xa697,
- 0xa700, 0xa78c,
- 0xa7fb, 0xa82b,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa900, 0xa953,
- 0xa95f, 0xa95f,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa5f,
- 0xac00, 0xd7a3,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x1083f,
- 0x10900, 0x10919,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1fffe, 0x2a6d6,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_5_1 */
-
-/* 'Age_5_2': Derived Age 5.2 */
-static const OnigCodePoint CR_Age_5_2[] = {
- 495,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0525,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x0606, 0x061b,
- 0x061e, 0x061f,
- 0x0621, 0x065e,
- 0x0660, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0900, 0x0939,
- 0x093c, 0x094e,
- 0x0950, 0x0955,
- 0x0958, 0x0972,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b71,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f8b,
- 0x0f90, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fd8,
- 0x1000, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 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,
- 0x135f, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1baa,
- 0x1bae, 0x1bb9,
- 0x1c00, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cd0, 0x1cf2,
- 0x1d00, 0x1de6,
- 0x1dfd, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x2094,
- 0x20a0, 0x20b8,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23e8,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26cd,
- 0x26cf, 0x26e1,
- 0x26e3, 0x26e3,
- 0x26e8, 0x26ff,
- 0x2701, 0x2704,
- 0x2706, 0x2709,
- 0x270c, 0x2727,
- 0x2729, 0x274b,
- 0x274d, 0x274d,
- 0x274f, 0x2752,
- 0x2756, 0x275e,
- 0x2761, 0x2794,
- 0x2798, 0x27af,
- 0x27b1, 0x27be,
- 0x27c0, 0x27ca,
- 0x27cc, 0x27cc,
- 0x27d0, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf1,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d6f,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e31,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31b7,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa65f,
- 0xa662, 0xa673,
- 0xa67c, 0xa697,
- 0xa6a0, 0xa6f7,
- 0xa700, 0xa78c,
- 0xa7fb, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaadf,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11080, 0x110c1,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f131, 0x1f131,
- 0x1f13d, 0x1f13d,
- 0x1f13f, 0x1f13f,
- 0x1f142, 0x1f142,
- 0x1f146, 0x1f146,
- 0x1f14a, 0x1f14e,
- 0x1f157, 0x1f157,
- 0x1f15f, 0x1f15f,
- 0x1f179, 0x1f179,
- 0x1f17b, 0x1f17c,
- 0x1f17f, 0x1f17f,
- 0x1f18a, 0x1f18d,
- 0x1f190, 0x1f190,
- 0x1f200, 0x1f200,
- 0x1f210, 0x1f231,
- 0x1f240, 0x1f248,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_5_2 */
-
-/* 'Age_6_0': Derived Age 6.0 */
-static const OnigCodePoint CR_Age_6_0[] = {
- 511,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0603,
- 0x0606, 0x061b,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0aef,
- 0x0af1, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edd,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10d0, 0x10fc,
- 0x1100, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1baa,
- 0x1bae, 0x1bb9,
- 0x1bc0, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cd0, 0x1cf2,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20b9,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x27ca,
- 0x27cc, 0x27cc,
- 0x27ce, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf1,
- 0x2cf9, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e31,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcb,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa673,
- 0xa67c, 0xa697,
- 0xa6a0, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa791,
- 0xa7a0, 0xa7a9,
- 0xa7fa, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaadf,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa2d,
- 0xfa30, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f169,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f5ff,
- 0x1f601, 0x1f610,
- 0x1f612, 0x1f614,
- 0x1f616, 0x1f616,
- 0x1f618, 0x1f618,
- 0x1f61a, 0x1f61a,
- 0x1f61c, 0x1f61e,
- 0x1f620, 0x1f625,
- 0x1f628, 0x1f62b,
- 0x1f62d, 0x1f62d,
- 0x1f630, 0x1f633,
- 0x1f635, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_0 */
-
-/* 'Age_6_1': Derived Age 6.1 */
-static const OnigCodePoint CR_Age_6_1[] = {
- 549,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058f, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0604,
- 0x0606, 0x061b,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08a0,
- 0x08a2, 0x08ac,
- 0x08e4, 0x08fe,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20b9,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e3b,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11180, 0x111c8,
- 0x111d0, 0x111d9,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f540, 0x1f543,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_1 */
-
-/* 'Age_6_2': Derived Age 6.2 */
-static const OnigCodePoint CR_Age_6_2[] = {
- 549,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058f, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0604,
- 0x0606, 0x061b,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08a0,
- 0x08a2, 0x08ac,
- 0x08e4, 0x08fe,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x206a, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20ba,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e3b,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11180, 0x111c8,
- 0x111d0, 0x111d9,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f540, 0x1f543,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_2 */
-
-/* 'Age_6_3': Derived Age 6.3 */
-static const OnigCodePoint CR_Age_6_3[] = {
- 549,
- 0x0000, 0x0377,
- 0x037a, 0x037e,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x0527,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058f, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x0604,
- 0x0606, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08a0,
- 0x08a2, 0x08ac,
- 0x08e4, 0x08fe,
- 0x0900, 0x0977,
- 0x0979, 0x097f,
- 0x0981, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c01, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c82, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d02, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f0,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1d00, 0x1de6,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20ba,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23f3,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x26ff,
- 0x2701, 0x2b4c,
- 0x2b50, 0x2b59,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e3b,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa697,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa793,
- 0xa7a0, 0xa7aa,
- 0xa7f8, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9df,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaa7b,
- 0xaa80, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe26,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018a,
- 0x10190, 0x1019b,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10320, 0x10323,
- 0x10330, 0x1034a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1085f,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a7f,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b7f,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x11080, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11180, 0x111c8,
- 0x111d0, 0x111d9,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x12000, 0x1236e,
- 0x12400, 0x12462,
- 0x12470, 0x12473,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0be,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0df,
- 0x1f100, 0x1f10a,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f320,
- 0x1f330, 0x1f335,
- 0x1f337, 0x1f37c,
- 0x1f380, 0x1f393,
- 0x1f3a0, 0x1f3c4,
- 0x1f3c6, 0x1f3ca,
- 0x1f3e0, 0x1f3f0,
- 0x1f400, 0x1f43e,
- 0x1f440, 0x1f440,
- 0x1f442, 0x1f4f7,
- 0x1f4f9, 0x1f4fc,
- 0x1f500, 0x1f53d,
- 0x1f540, 0x1f543,
- 0x1f550, 0x1f567,
- 0x1f5fb, 0x1f640,
- 0x1f645, 0x1f64f,
- 0x1f680, 0x1f6c5,
- 0x1f700, 0x1f773,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_6_3 */
-
-/* 'Age_7_0': Derived Age 7.0 */
-static const OnigCodePoint CR_Age_7_0[] = {
- 610,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08b2,
- 0x08e4, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c81, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d01, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d60, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f4,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1cf8, 0x1cf9,
- 0x1d00, 0x1df5,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bd,
- 0x20d0, 0x20f0,
- 0x2100, 0x2189,
- 0x2190, 0x23fa,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd1,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e42,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fcc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa69d,
- 0xa69f, 0xa6f7,
- 0xa700, 0xa78e,
- 0xa790, 0xa7ad,
- 0xa7b0, 0xa7b1,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fb,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab5f,
- 0xab64, 0xab65,
- 0xabc0, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe2d,
- 0xfe30, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018c,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x10330, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x10900, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109be, 0x109bf,
- 0x10a00, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111c8,
- 0x111cd, 0x111cd,
- 0x111d0, 0x111da,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123d,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11301, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115c9,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11ac0, 0x11af8,
- 0x12000, 0x12398,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x13000, 0x1342e,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1dd,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1d7ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f32c,
- 0x1f330, 0x1f37d,
- 0x1f380, 0x1f3ce,
- 0x1f3d4, 0x1f3f7,
- 0x1f400, 0x1f4fe,
- 0x1f500, 0x1f54a,
- 0x1f550, 0x1f579,
- 0x1f57b, 0x1f5a3,
- 0x1f5a5, 0x1f642,
- 0x1f645, 0x1f6cf,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f3,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_7_0 */
-
-/* 'Age_8_0': Derived Age 8.0 */
-static const OnigCodePoint CR_Age_8_0[] = {
- 623,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08b4,
- 0x08e3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0af9,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c7f,
- 0x0c81, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d01, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4e,
- 0x0d57, 0x0d57,
- 0x0d5f, 0x0d63,
- 0x0d66, 0x0d75,
- 0x0d79, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c7f,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1cf8, 0x1cf9,
- 0x1d00, 0x1df5,
- 0x1dfc, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20be,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x23fa,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd1,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e42,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fd5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ad,
- 0xa7b0, 0xa7b7,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c4,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018c,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x10330, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123d,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x11719,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11ac0, 0x11af8,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x1b000, 0x1b001,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f19a,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23a,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f579,
- 0x1f57b, 0x1f5a3,
- 0x1f5a5, 0x1f6d0,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f3,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f910, 0x1f918,
- 0x1f980, 0x1f984,
- 0x1f9c0, 0x1f9c0,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_8_0 */
-
-/* 'Age_9_0': Derived Age 9.0 */
-static const OnigCodePoint CR_Age_9_0[] = {
- 648,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d4, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fb,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0af9,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d01, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d3a,
- 0x0d3d, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf6,
- 0x1cf8, 0x1cf9,
- 0x1d00, 0x1df5,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20be,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x23fe,
- 0x2400, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd1,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e44,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fd5,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ae,
- 0xa7b0, 0xa7b7,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x10330, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145d,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x11719,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe0,
- 0x17000, 0x187ec,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b001,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94a,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f300, 0x1f6d2,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f6,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f910, 0x1f91e,
- 0x1f920, 0x1f927,
- 0x1f930, 0x1f930,
- 0x1f933, 0x1f93e,
- 0x1f940, 0x1f94b,
- 0x1f950, 0x1f95e,
- 0x1f980, 0x1f991,
- 0x1f9c0, 0x1f9c0,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_9_0 */
-
-/* 'Age_10_0': Derived Age 10.0 */
-static const OnigCodePoint CR_Age_10_0[] = {
- 659,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x055f,
- 0x0561, 0x0587,
- 0x0589, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x0800, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d4, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fd,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a75,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c03,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c83,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1877,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1cc0, 0x1cc7,
- 0x1cd0, 0x1cf9,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bc8,
- 0x2bca, 0x2bd2,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e49,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312e,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fea,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ae,
- 0xa7b0, 0xa7b7,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a47,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10cff,
- 0x10e60, 0x10e7e,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11143,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133c, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145d,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x11719,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11a83,
- 0x11a86, 0x11a9c,
- 0x11a9e, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x17000, 0x187ec,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d371,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94a,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f12e,
- 0x1f130, 0x1f16b,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d4,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f8,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d4,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f910, 0x1f93e,
- 0x1f940, 0x1f94c,
- 0x1f950, 0x1f96b,
- 0x1f980, 0x1f997,
- 0x1f9c0, 0x1f9c0,
- 0x1f9d0, 0x1f9e6,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_10_0 */
-
-/* 'Age_11_0': Derived Age 11.0 */
-static const OnigCodePoint CR_Age_11_0[] = {
- 668,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c78, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e87, 0x0e88,
- 0x0e8a, 0x0e8a,
- 0x0e8d, 0x0e8d,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ea7,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb9,
- 0x0ebb, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cf9,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2bc8,
- 0x2bca, 0x2bfe,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e4e,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fef,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7b9,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab65,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11146,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145e,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b7,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11a83,
- 0x11a86, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x12000, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f44,
- 0x16f50, 0x16f7e,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe1,
- 0x17000, 0x187f1,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94a,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f16b,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d4,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6f9,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f910, 0x1f93e,
- 0x1f940, 0x1f970,
- 0x1f973, 0x1f976,
- 0x1f97a, 0x1f97a,
- 0x1f97c, 0x1f9a2,
- 0x1f9b0, 0x1f9b9,
- 0x1f9c0, 0x1f9c2,
- 0x1f9d0, 0x1f9ff,
- 0x1fa60, 0x1fa6d,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_11_0 */
-
-/* 'Age_12_0': Derived Age 12.0 */
-static const OnigCodePoint CR_Age_12_0[] = {
- 677,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e4f,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x32fe,
- 0x3300, 0x4db5,
- 0x4dc0, 0x9fef,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7bf,
- 0xa7c2, 0xa7c6,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab67,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11146,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145f,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f16c,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d5,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6fa,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f90d, 0x1f971,
- 0x1f973, 0x1f976,
- 0x1f97a, 0x1f9a2,
- 0x1f9a5, 0x1f9aa,
- 0x1f9ae, 0x1f9ca,
- 0x1f9cd, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa73,
- 0x1fa78, 0x1fa7a,
- 0x1fa80, 0x1fa82,
- 0x1fa90, 0x1fa95,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_12_0 */
-
-/* 'Age_12_1': Derived Age 12.1 */
-static const OnigCodePoint CR_Age_12_1[] = {
- 676,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08bd,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b56, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d03,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d82, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1abe,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b98, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e4f,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31ba,
- 0x31c0, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x4db5,
- 0x4dc0, 0x9fef,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7bf,
- 0xa7c2, 0xa7c6,
- 0xa7f7, 0xa82b,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab67,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019b,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11146,
- 0x11150, 0x11176,
- 0x11180, 0x111cd,
- 0x111d0, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x11459,
- 0x1145b, 0x1145b,
- 0x1145d, 0x1145f,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x118ff,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe3,
- 0x17000, 0x187f7,
- 0x18800, 0x18af2,
- 0x1b000, 0x1b11e,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f10c,
- 0x1f110, 0x1f16c,
- 0x1f170, 0x1f1ac,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d5,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6fa,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f900, 0x1f90b,
- 0x1f90d, 0x1f971,
- 0x1f973, 0x1f976,
- 0x1f97a, 0x1f9a2,
- 0x1f9a5, 0x1f9aa,
- 0x1f9ae, 0x1f9ca,
- 0x1f9cd, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa73,
- 0x1fa78, 0x1fa7a,
- 0x1fa80, 0x1fa82,
- 0x1fa90, 0x1fa95,
- 0x1fffe, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x2ffff,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_12_1 */
-
-/* 'Age_13_0': Derived Age 13.0 */
-static const OnigCodePoint CR_Age_13_0[] = {
- 686,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x061c,
- 0x061e, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x08a0, 0x08b4,
- 0x08b6, 0x08c7,
- 0x08d3, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3d, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cde, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x170c,
- 0x170e, 0x1714,
- 0x1720, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x180e,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ac0,
- 0x1b00, 0x1b4b,
- 0x1b50, 0x1b7c,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1df9,
- 0x1dfb, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20bf,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e52,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0x9ffc,
- 0xa000, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7bf,
- 0xa7c2, 0xa7ca,
- 0xa7f5, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc1,
- 0xfbd3, 0xfd3f,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdd0, 0xfdfd,
- 0xfe00, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 0x1056f,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083c, 0x1083c,
- 0x1083f, 0x10855,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x1106f,
- 0x1107f, 0x110c1,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b8,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x1173f,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ac0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16a6f,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18d00, 0x18d08,
- 0x1b000, 0x1b11e,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1e8,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6e0, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1f978,
- 0x1f97a, 0x1f9cb,
- 0x1f9cd, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa74,
- 0x1fa78, 0x1fa7a,
- 0x1fa80, 0x1fa86,
- 0x1fa90, 0x1faa8,
- 0x1fab0, 0x1fab6,
- 0x1fac0, 0x1fac2,
- 0x1fad0, 0x1fad6,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6dd,
- 0x2a700, 0x2b734,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_13_0 */
-
-/* 'Age_14_0': Derived Age 14.0 */
-static const OnigCodePoint CR_Age_14_0[] = {
- 706,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf2,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ecd,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10f00, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x1123e,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x1342e,
- 0x13430, 0x13438,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 0x16ff0, 0x16ff1,
- 0x17000, 0x187f7,
- 0x18800, 0x18cd5,
- 0x18d00, 0x18d08,
- 0x1aff0, 0x1aff3,
- 0x1aff5, 0x1affb,
- 0x1affd, 0x1affe,
- 0x1b000, 0x1b122,
- 0x1b150, 0x1b152,
- 0x1b164, 0x1b167,
- 0x1b170, 0x1b2fb,
- 0x1bc00, 0x1bc6a,
- 0x1bc70, 0x1bc7c,
- 0x1bc80, 0x1bc88,
- 0x1bc90, 0x1bc99,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dd, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f773,
- 0x1f780, 0x1f7d8,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa74,
- 0x1fa78, 0x1fa7c,
- 0x1fa80, 0x1fa86,
- 0x1fa90, 0x1faac,
- 0x1fab0, 0x1faba,
- 0x1fac0, 0x1fac5,
- 0x1fad0, 0x1fad9,
- 0x1fae0, 0x1fae7,
- 0x1faf0, 0x1faf6,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b738,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_14_0 */
-
-/* 'Age_15_0': Derived Age 15.0 */
-static const OnigCodePoint CR_Age_15_0[] = {
- 715,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x2ffb,
- 0x3000, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31f0, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x31350, 0x323af,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_15_0 */
-
-/* 'Age_15_1': Derived Age 15.1 */
-static const OnigCodePoint CR_Age_15_1[] = {
- 715,
- 0x0000, 0x0377,
- 0x037a, 0x037f,
- 0x0384, 0x038a,
- 0x038c, 0x038c,
- 0x038e, 0x03a1,
- 0x03a3, 0x052f,
- 0x0531, 0x0556,
- 0x0559, 0x058a,
- 0x058d, 0x058f,
- 0x0591, 0x05c7,
- 0x05d0, 0x05ea,
- 0x05ef, 0x05f4,
- 0x0600, 0x070d,
- 0x070f, 0x074a,
- 0x074d, 0x07b1,
- 0x07c0, 0x07fa,
- 0x07fd, 0x082d,
- 0x0830, 0x083e,
- 0x0840, 0x085b,
- 0x085e, 0x085e,
- 0x0860, 0x086a,
- 0x0870, 0x088e,
- 0x0890, 0x0891,
- 0x0898, 0x0983,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b2, 0x09b2,
- 0x09b6, 0x09b9,
- 0x09bc, 0x09c4,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09ce,
- 0x09d7, 0x09d7,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e3,
- 0x09e6, 0x09fe,
- 0x0a01, 0x0a03,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a3c, 0x0a3c,
- 0x0a3e, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a59, 0x0a5c,
- 0x0a5e, 0x0a5e,
- 0x0a66, 0x0a76,
- 0x0a81, 0x0a83,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0abc, 0x0ac5,
- 0x0ac7, 0x0ac9,
- 0x0acb, 0x0acd,
- 0x0ad0, 0x0ad0,
- 0x0ae0, 0x0ae3,
- 0x0ae6, 0x0af1,
- 0x0af9, 0x0aff,
- 0x0b01, 0x0b03,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b3c, 0x0b44,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b63,
- 0x0b66, 0x0b77,
- 0x0b82, 0x0b83,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9c, 0x0b9c,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0bbe, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcd,
- 0x0bd0, 0x0bd0,
- 0x0bd7, 0x0bd7,
- 0x0be6, 0x0bfa,
- 0x0c00, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c39,
- 0x0c3c, 0x0c44,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c58, 0x0c5a,
- 0x0c5d, 0x0c5d,
- 0x0c60, 0x0c63,
- 0x0c66, 0x0c6f,
- 0x0c77, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0cbc, 0x0cc4,
- 0x0cc6, 0x0cc8,
- 0x0cca, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0cdd, 0x0cde,
- 0x0ce0, 0x0ce3,
- 0x0ce6, 0x0cef,
- 0x0cf1, 0x0cf3,
- 0x0d00, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d44,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4f,
- 0x0d54, 0x0d63,
- 0x0d66, 0x0d7f,
- 0x0d81, 0x0d83,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dbd, 0x0dbd,
- 0x0dc0, 0x0dc6,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0dd8, 0x0ddf,
- 0x0de6, 0x0def,
- 0x0df2, 0x0df4,
- 0x0e01, 0x0e3a,
- 0x0e3f, 0x0e5b,
- 0x0e81, 0x0e82,
- 0x0e84, 0x0e84,
- 0x0e86, 0x0e8a,
- 0x0e8c, 0x0ea3,
- 0x0ea5, 0x0ea5,
- 0x0ea7, 0x0ebd,
- 0x0ec0, 0x0ec4,
- 0x0ec6, 0x0ec6,
- 0x0ec8, 0x0ece,
- 0x0ed0, 0x0ed9,
- 0x0edc, 0x0edf,
- 0x0f00, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f71, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fbe, 0x0fcc,
- 0x0fce, 0x0fda,
- 0x1000, 0x10c5,
- 0x10c7, 0x10c7,
- 0x10cd, 0x10cd,
- 0x10d0, 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,
- 0x135d, 0x137c,
- 0x1380, 0x1399,
- 0x13a0, 0x13f5,
- 0x13f8, 0x13fd,
- 0x1400, 0x169c,
- 0x16a0, 0x16f8,
- 0x1700, 0x1715,
- 0x171f, 0x1736,
- 0x1740, 0x1753,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17dd,
- 0x17e0, 0x17e9,
- 0x17f0, 0x17f9,
- 0x1800, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18aa,
- 0x18b0, 0x18f5,
- 0x1900, 0x191e,
- 0x1920, 0x192b,
- 0x1930, 0x193b,
- 0x1940, 0x1940,
- 0x1944, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19b0, 0x19c9,
- 0x19d0, 0x19da,
- 0x19de, 0x1a1b,
- 0x1a1e, 0x1a5e,
- 0x1a60, 0x1a7c,
- 0x1a7f, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1aa0, 0x1aad,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b4c,
- 0x1b50, 0x1b7e,
- 0x1b80, 0x1bf3,
- 0x1bfc, 0x1c37,
- 0x1c3b, 0x1c49,
- 0x1c4d, 0x1c88,
- 0x1c90, 0x1cba,
- 0x1cbd, 0x1cc7,
- 0x1cd0, 0x1cfa,
- 0x1d00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f59, 0x1f59,
- 0x1f5b, 0x1f5b,
- 0x1f5d, 0x1f5d,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fc4,
- 0x1fc6, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fdd, 0x1fef,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffe,
- 0x2000, 0x2064,
- 0x2066, 0x2071,
- 0x2074, 0x208e,
- 0x2090, 0x209c,
- 0x20a0, 0x20c0,
- 0x20d0, 0x20f0,
- 0x2100, 0x218b,
- 0x2190, 0x2426,
- 0x2440, 0x244a,
- 0x2460, 0x2b73,
- 0x2b76, 0x2b95,
- 0x2b97, 0x2cf3,
- 0x2cf9, 0x2d25,
- 0x2d27, 0x2d27,
- 0x2d2d, 0x2d2d,
- 0x2d30, 0x2d67,
- 0x2d6f, 0x2d70,
- 0x2d7f, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x2de0, 0x2e5d,
- 0x2e80, 0x2e99,
- 0x2e9b, 0x2ef3,
- 0x2f00, 0x2fd5,
- 0x2ff0, 0x303f,
- 0x3041, 0x3096,
- 0x3099, 0x30ff,
- 0x3105, 0x312f,
- 0x3131, 0x318e,
- 0x3190, 0x31e3,
- 0x31ef, 0x321e,
- 0x3220, 0xa48c,
- 0xa490, 0xa4c6,
- 0xa4d0, 0xa62b,
- 0xa640, 0xa6f7,
- 0xa700, 0xa7ca,
- 0xa7d0, 0xa7d1,
- 0xa7d3, 0xa7d3,
- 0xa7d5, 0xa7d9,
- 0xa7f2, 0xa82c,
- 0xa830, 0xa839,
- 0xa840, 0xa877,
- 0xa880, 0xa8c5,
- 0xa8ce, 0xa8d9,
- 0xa8e0, 0xa953,
- 0xa95f, 0xa97c,
- 0xa980, 0xa9cd,
- 0xa9cf, 0xa9d9,
- 0xa9de, 0xa9fe,
- 0xaa00, 0xaa36,
- 0xaa40, 0xaa4d,
- 0xaa50, 0xaa59,
- 0xaa5c, 0xaac2,
- 0xaadb, 0xaaf6,
- 0xab01, 0xab06,
- 0xab09, 0xab0e,
- 0xab11, 0xab16,
- 0xab20, 0xab26,
- 0xab28, 0xab2e,
- 0xab30, 0xab6b,
- 0xab70, 0xabed,
- 0xabf0, 0xabf9,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xd800, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1d, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb3e, 0xfb3e,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbc2,
- 0xfbd3, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdcf, 0xfe19,
- 0xfe20, 0xfe52,
- 0xfe54, 0xfe66,
- 0xfe68, 0xfe6b,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xfeff, 0xfeff,
- 0xff01, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0xffe0, 0xffe6,
- 0xffe8, 0xffee,
- 0xfff9, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10100, 0x10102,
- 0x10107, 0x10133,
- 0x10137, 0x1018e,
- 0x10190, 0x1019c,
- 0x101a0, 0x101a0,
- 0x101d0, 0x101fd,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x102e0, 0x102fb,
- 0x10300, 0x10323,
- 0x1032d, 0x1034a,
- 0x10350, 0x1037a,
- 0x10380, 0x1039d,
- 0x1039f, 0x103c3,
- 0x103c8, 0x103d5,
- 0x10400, 0x1049d,
- 0x104a0, 0x104a9,
- 0x104b0, 0x104d3,
- 0x104d8, 0x104fb,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x1056f, 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,
- 0x10857, 0x1089e,
- 0x108a7, 0x108af,
- 0x108e0, 0x108f2,
- 0x108f4, 0x108f5,
- 0x108fb, 0x1091b,
- 0x1091f, 0x10939,
- 0x1093f, 0x1093f,
- 0x10980, 0x109b7,
- 0x109bc, 0x109cf,
- 0x109d2, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a35,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a48,
- 0x10a50, 0x10a58,
- 0x10a60, 0x10a9f,
- 0x10ac0, 0x10ae6,
- 0x10aeb, 0x10af6,
- 0x10b00, 0x10b35,
- 0x10b39, 0x10b55,
- 0x10b58, 0x10b72,
- 0x10b78, 0x10b91,
- 0x10b99, 0x10b9c,
- 0x10ba9, 0x10baf,
- 0x10c00, 0x10c48,
- 0x10c80, 0x10cb2,
- 0x10cc0, 0x10cf2,
- 0x10cfa, 0x10d27,
- 0x10d30, 0x10d39,
- 0x10e60, 0x10e7e,
- 0x10e80, 0x10ea9,
- 0x10eab, 0x10ead,
- 0x10eb0, 0x10eb1,
- 0x10efd, 0x10f27,
- 0x10f30, 0x10f59,
- 0x10f70, 0x10f89,
- 0x10fb0, 0x10fcb,
- 0x10fe0, 0x10ff6,
- 0x11000, 0x1104d,
- 0x11052, 0x11075,
- 0x1107f, 0x110c2,
- 0x110cd, 0x110cd,
- 0x110d0, 0x110e8,
- 0x110f0, 0x110f9,
- 0x11100, 0x11134,
- 0x11136, 0x11147,
- 0x11150, 0x11176,
- 0x11180, 0x111df,
- 0x111e1, 0x111f4,
- 0x11200, 0x11211,
- 0x11213, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128a, 0x1128d,
- 0x1128f, 0x1129d,
- 0x1129f, 0x112a9,
- 0x112b0, 0x112ea,
- 0x112f0, 0x112f9,
- 0x11300, 0x11303,
- 0x11305, 0x1130c,
- 0x1130f, 0x11310,
- 0x11313, 0x11328,
- 0x1132a, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133b, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135d, 0x11363,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11400, 0x1145b,
- 0x1145d, 0x11461,
- 0x11480, 0x114c7,
- 0x114d0, 0x114d9,
- 0x11580, 0x115b5,
- 0x115b8, 0x115dd,
- 0x11600, 0x11644,
- 0x11650, 0x11659,
- 0x11660, 0x1166c,
- 0x11680, 0x116b9,
- 0x116c0, 0x116c9,
- 0x11700, 0x1171a,
- 0x1171d, 0x1172b,
- 0x11730, 0x11746,
- 0x11800, 0x1183b,
- 0x118a0, 0x118f2,
- 0x118ff, 0x11906,
- 0x11909, 0x11909,
- 0x1190c, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193b, 0x11946,
- 0x11950, 0x11959,
- 0x119a0, 0x119a7,
- 0x119aa, 0x119d7,
- 0x119da, 0x119e4,
- 0x11a00, 0x11a47,
- 0x11a50, 0x11aa2,
- 0x11ab0, 0x11af8,
- 0x11b00, 0x11b09,
- 0x11c00, 0x11c08,
- 0x11c0a, 0x11c36,
- 0x11c38, 0x11c45,
- 0x11c50, 0x11c6c,
- 0x11c70, 0x11c8f,
- 0x11c92, 0x11ca7,
- 0x11ca9, 0x11cb6,
- 0x11d00, 0x11d06,
- 0x11d08, 0x11d09,
- 0x11d0b, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d47,
- 0x11d50, 0x11d59,
- 0x11d60, 0x11d65,
- 0x11d67, 0x11d68,
- 0x11d6a, 0x11d8e,
- 0x11d90, 0x11d91,
- 0x11d93, 0x11d98,
- 0x11da0, 0x11da9,
- 0x11ee0, 0x11ef8,
- 0x11f00, 0x11f10,
- 0x11f12, 0x11f3a,
- 0x11f3e, 0x11f59,
- 0x11fb0, 0x11fb0,
- 0x11fc0, 0x11ff1,
- 0x11fff, 0x12399,
- 0x12400, 0x1246e,
- 0x12470, 0x12474,
- 0x12480, 0x12543,
- 0x12f90, 0x12ff2,
- 0x13000, 0x13455,
- 0x14400, 0x14646,
- 0x16800, 0x16a38,
- 0x16a40, 0x16a5e,
- 0x16a60, 0x16a69,
- 0x16a6e, 0x16abe,
- 0x16ac0, 0x16ac9,
- 0x16ad0, 0x16aed,
- 0x16af0, 0x16af5,
- 0x16b00, 0x16b45,
- 0x16b50, 0x16b59,
- 0x16b5b, 0x16b61,
- 0x16b63, 0x16b77,
- 0x16b7d, 0x16b8f,
- 0x16e40, 0x16e9a,
- 0x16f00, 0x16f4a,
- 0x16f4f, 0x16f87,
- 0x16f8f, 0x16f9f,
- 0x16fe0, 0x16fe4,
- 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,
- 0x1bc9c, 0x1bca3,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1cf50, 0x1cfc3,
- 0x1d000, 0x1d0f5,
- 0x1d100, 0x1d126,
- 0x1d129, 0x1d1ea,
- 0x1d200, 0x1d245,
- 0x1d2c0, 0x1d2d3,
- 0x1d2e0, 0x1d2f3,
- 0x1d300, 0x1d356,
- 0x1d360, 0x1d378,
- 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, 0x1d7cb,
- 0x1d7ce, 0x1da8b,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1df00, 0x1df1e,
- 0x1df25, 0x1df2a,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e030, 0x1e06d,
- 0x1e08f, 0x1e08f,
- 0x1e100, 0x1e12c,
- 0x1e130, 0x1e13d,
- 0x1e140, 0x1e149,
- 0x1e14e, 0x1e14f,
- 0x1e290, 0x1e2ae,
- 0x1e2c0, 0x1e2f9,
- 0x1e2ff, 0x1e2ff,
- 0x1e4d0, 0x1e4f9,
- 0x1e7e0, 0x1e7e6,
- 0x1e7e8, 0x1e7eb,
- 0x1e7ed, 0x1e7ee,
- 0x1e7f0, 0x1e7fe,
- 0x1e800, 0x1e8c4,
- 0x1e8c7, 0x1e8d6,
- 0x1e900, 0x1e94b,
- 0x1e950, 0x1e959,
- 0x1e95e, 0x1e95f,
- 0x1ec71, 0x1ecb4,
- 0x1ed01, 0x1ed3d,
- 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,
- 0x1eef0, 0x1eef1,
- 0x1f000, 0x1f02b,
- 0x1f030, 0x1f093,
- 0x1f0a0, 0x1f0ae,
- 0x1f0b1, 0x1f0bf,
- 0x1f0c1, 0x1f0cf,
- 0x1f0d1, 0x1f0f5,
- 0x1f100, 0x1f1ad,
- 0x1f1e6, 0x1f202,
- 0x1f210, 0x1f23b,
- 0x1f240, 0x1f248,
- 0x1f250, 0x1f251,
- 0x1f260, 0x1f265,
- 0x1f300, 0x1f6d7,
- 0x1f6dc, 0x1f6ec,
- 0x1f6f0, 0x1f6fc,
- 0x1f700, 0x1f776,
- 0x1f77b, 0x1f7d9,
- 0x1f7e0, 0x1f7eb,
- 0x1f7f0, 0x1f7f0,
- 0x1f800, 0x1f80b,
- 0x1f810, 0x1f847,
- 0x1f850, 0x1f859,
- 0x1f860, 0x1f887,
- 0x1f890, 0x1f8ad,
- 0x1f8b0, 0x1f8b1,
- 0x1f900, 0x1fa53,
- 0x1fa60, 0x1fa6d,
- 0x1fa70, 0x1fa7c,
- 0x1fa80, 0x1fa88,
- 0x1fa90, 0x1fabd,
- 0x1fabf, 0x1fac5,
- 0x1face, 0x1fadb,
- 0x1fae0, 0x1fae8,
- 0x1faf0, 0x1faf8,
- 0x1fb00, 0x1fb92,
- 0x1fb94, 0x1fbca,
- 0x1fbf0, 0x1fbf9,
- 0x1fffe, 0x2a6df,
- 0x2a700, 0x2b739,
- 0x2b740, 0x2b81d,
- 0x2b820, 0x2cea1,
- 0x2ceb0, 0x2ebe0,
- 0x2ebf0, 0x2ee5d,
- 0x2f800, 0x2fa1d,
- 0x2fffe, 0x3134a,
- 0x31350, 0x323af,
- 0x3fffe, 0x3ffff,
- 0x4fffe, 0x4ffff,
- 0x5fffe, 0x5ffff,
- 0x6fffe, 0x6ffff,
- 0x7fffe, 0x7ffff,
- 0x8fffe, 0x8ffff,
- 0x9fffe, 0x9ffff,
- 0xafffe, 0xaffff,
- 0xbfffe, 0xbffff,
- 0xcfffe, 0xcffff,
- 0xdfffe, 0xdffff,
- 0xe0001, 0xe0001,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
- 0xefffe, 0x10ffff,
-}; /* CR_Age_15_1 */
-
-#endif /* USE_UNICODE_AGE_PROPERTIES */
-/* 'Grapheme_Cluster_Break_Prepend': Grapheme_Cluster_Break=Prepend */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_Prepend[] = {
- 15,
- 0x0600, 0x0605,
- 0x06dd, 0x06dd,
- 0x070f, 0x070f,
- 0x0890, 0x0891,
- 0x08e2, 0x08e2,
- 0x0d4e, 0x0d4e,
- 0x110bd, 0x110bd,
- 0x110cd, 0x110cd,
- 0x111c2, 0x111c3,
- 0x1193f, 0x1193f,
- 0x11941, 0x11941,
- 0x11a3a, 0x11a3a,
- 0x11a84, 0x11a89,
- 0x11d46, 0x11d46,
- 0x11f02, 0x11f02,
-}; /* CR_Grapheme_Cluster_Break_Prepend */
-
-/* 'Grapheme_Cluster_Break_CR': Grapheme_Cluster_Break=CR */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_CR[] = {
- 1,
- 0x000d, 0x000d,
-}; /* CR_Grapheme_Cluster_Break_CR */
-
-/* 'Grapheme_Cluster_Break_LF': Grapheme_Cluster_Break=LF */
-#define CR_Grapheme_Cluster_Break_LF CR_NEWLINE
-
-/* 'Grapheme_Cluster_Break_Control': Grapheme_Cluster_Break=Control */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_Control[] = {
- 19,
- 0x0000, 0x0009,
- 0x000b, 0x000c,
- 0x000e, 0x001f,
- 0x007f, 0x009f,
- 0x00ad, 0x00ad,
- 0x061c, 0x061c,
- 0x180e, 0x180e,
- 0x200b, 0x200b,
- 0x200e, 0x200f,
- 0x2028, 0x202e,
- 0x2060, 0x206f,
- 0xfeff, 0xfeff,
- 0xfff0, 0xfffb,
- 0x13430, 0x1343f,
- 0x1bca0, 0x1bca3,
- 0x1d173, 0x1d17a,
- 0xe0000, 0xe001f,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xe0fff,
-}; /* CR_Grapheme_Cluster_Break_Control */
-
-/* 'Grapheme_Cluster_Break_Extend': Grapheme_Cluster_Break=Extend */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_Extend[] = {
- 364,
- 0x0300, 0x036f,
- 0x0483, 0x0489,
- 0x0591, 0x05bd,
- 0x05bf, 0x05bf,
- 0x05c1, 0x05c2,
- 0x05c4, 0x05c5,
- 0x05c7, 0x05c7,
- 0x0610, 0x061a,
- 0x064b, 0x065f,
- 0x0670, 0x0670,
- 0x06d6, 0x06dc,
- 0x06df, 0x06e4,
- 0x06e7, 0x06e8,
- 0x06ea, 0x06ed,
- 0x0711, 0x0711,
- 0x0730, 0x074a,
- 0x07a6, 0x07b0,
- 0x07eb, 0x07f3,
- 0x07fd, 0x07fd,
- 0x0816, 0x0819,
- 0x081b, 0x0823,
- 0x0825, 0x0827,
- 0x0829, 0x082d,
- 0x0859, 0x085b,
- 0x0898, 0x089f,
- 0x08ca, 0x08e1,
- 0x08e3, 0x0902,
- 0x093a, 0x093a,
- 0x093c, 0x093c,
- 0x0941, 0x0948,
- 0x094d, 0x094d,
- 0x0951, 0x0957,
- 0x0962, 0x0963,
- 0x0981, 0x0981,
- 0x09bc, 0x09bc,
- 0x09be, 0x09be,
- 0x09c1, 0x09c4,
- 0x09cd, 0x09cd,
- 0x09d7, 0x09d7,
- 0x09e2, 0x09e3,
- 0x09fe, 0x09fe,
- 0x0a01, 0x0a02,
- 0x0a3c, 0x0a3c,
- 0x0a41, 0x0a42,
- 0x0a47, 0x0a48,
- 0x0a4b, 0x0a4d,
- 0x0a51, 0x0a51,
- 0x0a70, 0x0a71,
- 0x0a75, 0x0a75,
- 0x0a81, 0x0a82,
- 0x0abc, 0x0abc,
- 0x0ac1, 0x0ac5,
- 0x0ac7, 0x0ac8,
- 0x0acd, 0x0acd,
- 0x0ae2, 0x0ae3,
- 0x0afa, 0x0aff,
- 0x0b01, 0x0b01,
- 0x0b3c, 0x0b3c,
- 0x0b3e, 0x0b3f,
- 0x0b41, 0x0b44,
- 0x0b4d, 0x0b4d,
- 0x0b55, 0x0b57,
- 0x0b62, 0x0b63,
- 0x0b82, 0x0b82,
- 0x0bbe, 0x0bbe,
- 0x0bc0, 0x0bc0,
- 0x0bcd, 0x0bcd,
- 0x0bd7, 0x0bd7,
- 0x0c00, 0x0c00,
- 0x0c04, 0x0c04,
- 0x0c3c, 0x0c3c,
- 0x0c3e, 0x0c40,
- 0x0c46, 0x0c48,
- 0x0c4a, 0x0c4d,
- 0x0c55, 0x0c56,
- 0x0c62, 0x0c63,
- 0x0c81, 0x0c81,
- 0x0cbc, 0x0cbc,
- 0x0cbf, 0x0cbf,
- 0x0cc2, 0x0cc2,
- 0x0cc6, 0x0cc6,
- 0x0ccc, 0x0ccd,
- 0x0cd5, 0x0cd6,
- 0x0ce2, 0x0ce3,
- 0x0d00, 0x0d01,
- 0x0d3b, 0x0d3c,
- 0x0d3e, 0x0d3e,
- 0x0d41, 0x0d44,
- 0x0d4d, 0x0d4d,
- 0x0d57, 0x0d57,
- 0x0d62, 0x0d63,
- 0x0d81, 0x0d81,
- 0x0dca, 0x0dca,
- 0x0dcf, 0x0dcf,
- 0x0dd2, 0x0dd4,
- 0x0dd6, 0x0dd6,
- 0x0ddf, 0x0ddf,
- 0x0e31, 0x0e31,
- 0x0e34, 0x0e3a,
- 0x0e47, 0x0e4e,
- 0x0eb1, 0x0eb1,
- 0x0eb4, 0x0ebc,
- 0x0ec8, 0x0ece,
- 0x0f18, 0x0f19,
- 0x0f35, 0x0f35,
- 0x0f37, 0x0f37,
- 0x0f39, 0x0f39,
- 0x0f71, 0x0f7e,
- 0x0f80, 0x0f84,
- 0x0f86, 0x0f87,
- 0x0f8d, 0x0f97,
- 0x0f99, 0x0fbc,
- 0x0fc6, 0x0fc6,
- 0x102d, 0x1030,
- 0x1032, 0x1037,
- 0x1039, 0x103a,
- 0x103d, 0x103e,
- 0x1058, 0x1059,
- 0x105e, 0x1060,
- 0x1071, 0x1074,
- 0x1082, 0x1082,
- 0x1085, 0x1086,
- 0x108d, 0x108d,
- 0x109d, 0x109d,
- 0x135d, 0x135f,
- 0x1712, 0x1714,
- 0x1732, 0x1733,
- 0x1752, 0x1753,
- 0x1772, 0x1773,
- 0x17b4, 0x17b5,
- 0x17b7, 0x17bd,
- 0x17c6, 0x17c6,
- 0x17c9, 0x17d3,
- 0x17dd, 0x17dd,
- 0x180b, 0x180d,
- 0x180f, 0x180f,
- 0x1885, 0x1886,
- 0x18a9, 0x18a9,
- 0x1920, 0x1922,
- 0x1927, 0x1928,
- 0x1932, 0x1932,
- 0x1939, 0x193b,
- 0x1a17, 0x1a18,
- 0x1a1b, 0x1a1b,
- 0x1a56, 0x1a56,
- 0x1a58, 0x1a5e,
- 0x1a60, 0x1a60,
- 0x1a62, 0x1a62,
- 0x1a65, 0x1a6c,
- 0x1a73, 0x1a7c,
- 0x1a7f, 0x1a7f,
- 0x1ab0, 0x1ace,
- 0x1b00, 0x1b03,
- 0x1b34, 0x1b3a,
- 0x1b3c, 0x1b3c,
- 0x1b42, 0x1b42,
- 0x1b6b, 0x1b73,
- 0x1b80, 0x1b81,
- 0x1ba2, 0x1ba5,
- 0x1ba8, 0x1ba9,
- 0x1bab, 0x1bad,
- 0x1be6, 0x1be6,
- 0x1be8, 0x1be9,
- 0x1bed, 0x1bed,
- 0x1bef, 0x1bf1,
- 0x1c2c, 0x1c33,
- 0x1c36, 0x1c37,
- 0x1cd0, 0x1cd2,
- 0x1cd4, 0x1ce0,
- 0x1ce2, 0x1ce8,
- 0x1ced, 0x1ced,
- 0x1cf4, 0x1cf4,
- 0x1cf8, 0x1cf9,
- 0x1dc0, 0x1dff,
- 0x200c, 0x200c,
- 0x20d0, 0x20f0,
- 0x2cef, 0x2cf1,
- 0x2d7f, 0x2d7f,
- 0x2de0, 0x2dff,
- 0x302a, 0x302f,
- 0x3099, 0x309a,
- 0xa66f, 0xa672,
- 0xa674, 0xa67d,
- 0xa69e, 0xa69f,
- 0xa6f0, 0xa6f1,
- 0xa802, 0xa802,
- 0xa806, 0xa806,
- 0xa80b, 0xa80b,
- 0xa825, 0xa826,
- 0xa82c, 0xa82c,
- 0xa8c4, 0xa8c5,
- 0xa8e0, 0xa8f1,
- 0xa8ff, 0xa8ff,
- 0xa926, 0xa92d,
- 0xa947, 0xa951,
- 0xa980, 0xa982,
- 0xa9b3, 0xa9b3,
- 0xa9b6, 0xa9b9,
- 0xa9bc, 0xa9bd,
- 0xa9e5, 0xa9e5,
- 0xaa29, 0xaa2e,
- 0xaa31, 0xaa32,
- 0xaa35, 0xaa36,
- 0xaa43, 0xaa43,
- 0xaa4c, 0xaa4c,
- 0xaa7c, 0xaa7c,
- 0xaab0, 0xaab0,
- 0xaab2, 0xaab4,
- 0xaab7, 0xaab8,
- 0xaabe, 0xaabf,
- 0xaac1, 0xaac1,
- 0xaaec, 0xaaed,
- 0xaaf6, 0xaaf6,
- 0xabe5, 0xabe5,
- 0xabe8, 0xabe8,
- 0xabed, 0xabed,
- 0xfb1e, 0xfb1e,
- 0xfe00, 0xfe0f,
- 0xfe20, 0xfe2f,
- 0xff9e, 0xff9f,
- 0x101fd, 0x101fd,
- 0x102e0, 0x102e0,
- 0x10376, 0x1037a,
- 0x10a01, 0x10a03,
- 0x10a05, 0x10a06,
- 0x10a0c, 0x10a0f,
- 0x10a38, 0x10a3a,
- 0x10a3f, 0x10a3f,
- 0x10ae5, 0x10ae6,
- 0x10d24, 0x10d27,
- 0x10eab, 0x10eac,
- 0x10efd, 0x10eff,
- 0x10f46, 0x10f50,
- 0x10f82, 0x10f85,
- 0x11001, 0x11001,
- 0x11038, 0x11046,
- 0x11070, 0x11070,
- 0x11073, 0x11074,
- 0x1107f, 0x11081,
- 0x110b3, 0x110b6,
- 0x110b9, 0x110ba,
- 0x110c2, 0x110c2,
- 0x11100, 0x11102,
- 0x11127, 0x1112b,
- 0x1112d, 0x11134,
- 0x11173, 0x11173,
- 0x11180, 0x11181,
- 0x111b6, 0x111be,
- 0x111c9, 0x111cc,
- 0x111cf, 0x111cf,
- 0x1122f, 0x11231,
- 0x11234, 0x11234,
- 0x11236, 0x11237,
- 0x1123e, 0x1123e,
- 0x11241, 0x11241,
- 0x112df, 0x112df,
- 0x112e3, 0x112ea,
- 0x11300, 0x11301,
- 0x1133b, 0x1133c,
- 0x1133e, 0x1133e,
- 0x11340, 0x11340,
- 0x11357, 0x11357,
- 0x11366, 0x1136c,
- 0x11370, 0x11374,
- 0x11438, 0x1143f,
- 0x11442, 0x11444,
- 0x11446, 0x11446,
- 0x1145e, 0x1145e,
- 0x114b0, 0x114b0,
- 0x114b3, 0x114b8,
- 0x114ba, 0x114ba,
- 0x114bd, 0x114bd,
- 0x114bf, 0x114c0,
- 0x114c2, 0x114c3,
- 0x115af, 0x115af,
- 0x115b2, 0x115b5,
- 0x115bc, 0x115bd,
- 0x115bf, 0x115c0,
- 0x115dc, 0x115dd,
- 0x11633, 0x1163a,
- 0x1163d, 0x1163d,
- 0x1163f, 0x11640,
- 0x116ab, 0x116ab,
- 0x116ad, 0x116ad,
- 0x116b0, 0x116b5,
- 0x116b7, 0x116b7,
- 0x1171d, 0x1171f,
- 0x11722, 0x11725,
- 0x11727, 0x1172b,
- 0x1182f, 0x11837,
- 0x11839, 0x1183a,
- 0x11930, 0x11930,
- 0x1193b, 0x1193c,
- 0x1193e, 0x1193e,
- 0x11943, 0x11943,
- 0x119d4, 0x119d7,
- 0x119da, 0x119db,
- 0x119e0, 0x119e0,
- 0x11a01, 0x11a0a,
- 0x11a33, 0x11a38,
- 0x11a3b, 0x11a3e,
- 0x11a47, 0x11a47,
- 0x11a51, 0x11a56,
- 0x11a59, 0x11a5b,
- 0x11a8a, 0x11a96,
- 0x11a98, 0x11a99,
- 0x11c30, 0x11c36,
- 0x11c38, 0x11c3d,
- 0x11c3f, 0x11c3f,
- 0x11c92, 0x11ca7,
- 0x11caa, 0x11cb0,
- 0x11cb2, 0x11cb3,
- 0x11cb5, 0x11cb6,
- 0x11d31, 0x11d36,
- 0x11d3a, 0x11d3a,
- 0x11d3c, 0x11d3d,
- 0x11d3f, 0x11d45,
- 0x11d47, 0x11d47,
- 0x11d90, 0x11d91,
- 0x11d95, 0x11d95,
- 0x11d97, 0x11d97,
- 0x11ef3, 0x11ef4,
- 0x11f00, 0x11f01,
- 0x11f36, 0x11f3a,
- 0x11f40, 0x11f40,
- 0x11f42, 0x11f42,
- 0x13440, 0x13440,
- 0x13447, 0x13455,
- 0x16af0, 0x16af4,
- 0x16b30, 0x16b36,
- 0x16f4f, 0x16f4f,
- 0x16f8f, 0x16f92,
- 0x16fe4, 0x16fe4,
- 0x1bc9d, 0x1bc9e,
- 0x1cf00, 0x1cf2d,
- 0x1cf30, 0x1cf46,
- 0x1d165, 0x1d165,
- 0x1d167, 0x1d169,
- 0x1d16e, 0x1d172,
- 0x1d17b, 0x1d182,
- 0x1d185, 0x1d18b,
- 0x1d1aa, 0x1d1ad,
- 0x1d242, 0x1d244,
- 0x1da00, 0x1da36,
- 0x1da3b, 0x1da6c,
- 0x1da75, 0x1da75,
- 0x1da84, 0x1da84,
- 0x1da9b, 0x1da9f,
- 0x1daa1, 0x1daaf,
- 0x1e000, 0x1e006,
- 0x1e008, 0x1e018,
- 0x1e01b, 0x1e021,
- 0x1e023, 0x1e024,
- 0x1e026, 0x1e02a,
- 0x1e08f, 0x1e08f,
- 0x1e130, 0x1e136,
- 0x1e2ae, 0x1e2ae,
- 0x1e2ec, 0x1e2ef,
- 0x1e4ec, 0x1e4ef,
- 0x1e8d0, 0x1e8d6,
- 0x1e944, 0x1e94a,
- 0x1f3fb, 0x1f3ff,
- 0xe0020, 0xe007f,
- 0xe0100, 0xe01ef,
-}; /* CR_Grapheme_Cluster_Break_Extend */
-
-/* 'Grapheme_Cluster_Break_Regional_Indicator': Grapheme_Cluster_Break=Regional_Indicator */
-#define CR_Grapheme_Cluster_Break_Regional_Indicator CR_Regional_Indicator
-
-/* 'Grapheme_Cluster_Break_SpacingMark': Grapheme_Cluster_Break=SpacingMark */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_SpacingMark[] = {
- 165,
- 0x0903, 0x0903,
- 0x093b, 0x093b,
- 0x093e, 0x0940,
- 0x0949, 0x094c,
- 0x094e, 0x094f,
- 0x0982, 0x0983,
- 0x09bf, 0x09c0,
- 0x09c7, 0x09c8,
- 0x09cb, 0x09cc,
- 0x0a03, 0x0a03,
- 0x0a3e, 0x0a40,
- 0x0a83, 0x0a83,
- 0x0abe, 0x0ac0,
- 0x0ac9, 0x0ac9,
- 0x0acb, 0x0acc,
- 0x0b02, 0x0b03,
- 0x0b40, 0x0b40,
- 0x0b47, 0x0b48,
- 0x0b4b, 0x0b4c,
- 0x0bbf, 0x0bbf,
- 0x0bc1, 0x0bc2,
- 0x0bc6, 0x0bc8,
- 0x0bca, 0x0bcc,
- 0x0c01, 0x0c03,
- 0x0c41, 0x0c44,
- 0x0c82, 0x0c83,
- 0x0cbe, 0x0cbe,
- 0x0cc0, 0x0cc1,
- 0x0cc3, 0x0cc4,
- 0x0cc7, 0x0cc8,
- 0x0cca, 0x0ccb,
- 0x0cf3, 0x0cf3,
- 0x0d02, 0x0d03,
- 0x0d3f, 0x0d40,
- 0x0d46, 0x0d48,
- 0x0d4a, 0x0d4c,
- 0x0d82, 0x0d83,
- 0x0dd0, 0x0dd1,
- 0x0dd8, 0x0dde,
- 0x0df2, 0x0df3,
- 0x0e33, 0x0e33,
- 0x0eb3, 0x0eb3,
- 0x0f3e, 0x0f3f,
- 0x0f7f, 0x0f7f,
- 0x1031, 0x1031,
- 0x103b, 0x103c,
- 0x1056, 0x1057,
- 0x1084, 0x1084,
- 0x1715, 0x1715,
- 0x1734, 0x1734,
- 0x17b6, 0x17b6,
- 0x17be, 0x17c5,
- 0x17c7, 0x17c8,
- 0x1923, 0x1926,
- 0x1929, 0x192b,
- 0x1930, 0x1931,
- 0x1933, 0x1938,
- 0x1a19, 0x1a1a,
- 0x1a55, 0x1a55,
- 0x1a57, 0x1a57,
- 0x1a6d, 0x1a72,
- 0x1b04, 0x1b04,
- 0x1b3b, 0x1b3b,
- 0x1b3d, 0x1b41,
- 0x1b43, 0x1b44,
- 0x1b82, 0x1b82,
- 0x1ba1, 0x1ba1,
- 0x1ba6, 0x1ba7,
- 0x1baa, 0x1baa,
- 0x1be7, 0x1be7,
- 0x1bea, 0x1bec,
- 0x1bee, 0x1bee,
- 0x1bf2, 0x1bf3,
- 0x1c24, 0x1c2b,
- 0x1c34, 0x1c35,
- 0x1ce1, 0x1ce1,
- 0x1cf7, 0x1cf7,
- 0xa823, 0xa824,
- 0xa827, 0xa827,
- 0xa880, 0xa881,
- 0xa8b4, 0xa8c3,
- 0xa952, 0xa953,
- 0xa983, 0xa983,
- 0xa9b4, 0xa9b5,
- 0xa9ba, 0xa9bb,
- 0xa9be, 0xa9c0,
- 0xaa2f, 0xaa30,
- 0xaa33, 0xaa34,
- 0xaa4d, 0xaa4d,
- 0xaaeb, 0xaaeb,
- 0xaaee, 0xaaef,
- 0xaaf5, 0xaaf5,
- 0xabe3, 0xabe4,
- 0xabe6, 0xabe7,
- 0xabe9, 0xabea,
- 0xabec, 0xabec,
- 0x11000, 0x11000,
- 0x11002, 0x11002,
- 0x11082, 0x11082,
- 0x110b0, 0x110b2,
- 0x110b7, 0x110b8,
- 0x1112c, 0x1112c,
- 0x11145, 0x11146,
- 0x11182, 0x11182,
- 0x111b3, 0x111b5,
- 0x111bf, 0x111c0,
- 0x111ce, 0x111ce,
- 0x1122c, 0x1122e,
- 0x11232, 0x11233,
- 0x11235, 0x11235,
- 0x112e0, 0x112e2,
- 0x11302, 0x11303,
- 0x1133f, 0x1133f,
- 0x11341, 0x11344,
- 0x11347, 0x11348,
- 0x1134b, 0x1134d,
- 0x11362, 0x11363,
- 0x11435, 0x11437,
- 0x11440, 0x11441,
- 0x11445, 0x11445,
- 0x114b1, 0x114b2,
- 0x114b9, 0x114b9,
- 0x114bb, 0x114bc,
- 0x114be, 0x114be,
- 0x114c1, 0x114c1,
- 0x115b0, 0x115b1,
- 0x115b8, 0x115bb,
- 0x115be, 0x115be,
- 0x11630, 0x11632,
- 0x1163b, 0x1163c,
- 0x1163e, 0x1163e,
- 0x116ac, 0x116ac,
- 0x116ae, 0x116af,
- 0x116b6, 0x116b6,
- 0x11726, 0x11726,
- 0x1182c, 0x1182e,
- 0x11838, 0x11838,
- 0x11931, 0x11935,
- 0x11937, 0x11938,
- 0x1193d, 0x1193d,
- 0x11940, 0x11940,
- 0x11942, 0x11942,
- 0x119d1, 0x119d3,
- 0x119dc, 0x119df,
- 0x119e4, 0x119e4,
- 0x11a39, 0x11a39,
- 0x11a57, 0x11a58,
- 0x11a97, 0x11a97,
- 0x11c2f, 0x11c2f,
- 0x11c3e, 0x11c3e,
- 0x11ca9, 0x11ca9,
- 0x11cb1, 0x11cb1,
- 0x11cb4, 0x11cb4,
- 0x11d8a, 0x11d8e,
- 0x11d93, 0x11d94,
- 0x11d96, 0x11d96,
- 0x11ef5, 0x11ef6,
- 0x11f03, 0x11f03,
- 0x11f34, 0x11f35,
- 0x11f3e, 0x11f3f,
- 0x11f41, 0x11f41,
- 0x16f51, 0x16f87,
- 0x16ff0, 0x16ff1,
- 0x1d166, 0x1d166,
- 0x1d16d, 0x1d16d,
-}; /* CR_Grapheme_Cluster_Break_SpacingMark */
-
-/* 'Grapheme_Cluster_Break_L': Grapheme_Cluster_Break=L */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_L[] = {
- 2,
- 0x1100, 0x115f,
- 0xa960, 0xa97c,
-}; /* CR_Grapheme_Cluster_Break_L */
-
-/* 'Grapheme_Cluster_Break_V': Grapheme_Cluster_Break=V */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_V[] = {
- 2,
- 0x1160, 0x11a7,
- 0xd7b0, 0xd7c6,
-}; /* CR_Grapheme_Cluster_Break_V */
-
-/* 'Grapheme_Cluster_Break_T': Grapheme_Cluster_Break=T */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_T[] = {
- 2,
- 0x11a8, 0x11ff,
- 0xd7cb, 0xd7fb,
-}; /* CR_Grapheme_Cluster_Break_T */
-
-/* 'Grapheme_Cluster_Break_LV': Grapheme_Cluster_Break=LV */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_LV[] = {
- 399,
- 0xac00, 0xac00,
- 0xac1c, 0xac1c,
- 0xac38, 0xac38,
- 0xac54, 0xac54,
- 0xac70, 0xac70,
- 0xac8c, 0xac8c,
- 0xaca8, 0xaca8,
- 0xacc4, 0xacc4,
- 0xace0, 0xace0,
- 0xacfc, 0xacfc,
- 0xad18, 0xad18,
- 0xad34, 0xad34,
- 0xad50, 0xad50,
- 0xad6c, 0xad6c,
- 0xad88, 0xad88,
- 0xada4, 0xada4,
- 0xadc0, 0xadc0,
- 0xaddc, 0xaddc,
- 0xadf8, 0xadf8,
- 0xae14, 0xae14,
- 0xae30, 0xae30,
- 0xae4c, 0xae4c,
- 0xae68, 0xae68,
- 0xae84, 0xae84,
- 0xaea0, 0xaea0,
- 0xaebc, 0xaebc,
- 0xaed8, 0xaed8,
- 0xaef4, 0xaef4,
- 0xaf10, 0xaf10,
- 0xaf2c, 0xaf2c,
- 0xaf48, 0xaf48,
- 0xaf64, 0xaf64,
- 0xaf80, 0xaf80,
- 0xaf9c, 0xaf9c,
- 0xafb8, 0xafb8,
- 0xafd4, 0xafd4,
- 0xaff0, 0xaff0,
- 0xb00c, 0xb00c,
- 0xb028, 0xb028,
- 0xb044, 0xb044,
- 0xb060, 0xb060,
- 0xb07c, 0xb07c,
- 0xb098, 0xb098,
- 0xb0b4, 0xb0b4,
- 0xb0d0, 0xb0d0,
- 0xb0ec, 0xb0ec,
- 0xb108, 0xb108,
- 0xb124, 0xb124,
- 0xb140, 0xb140,
- 0xb15c, 0xb15c,
- 0xb178, 0xb178,
- 0xb194, 0xb194,
- 0xb1b0, 0xb1b0,
- 0xb1cc, 0xb1cc,
- 0xb1e8, 0xb1e8,
- 0xb204, 0xb204,
- 0xb220, 0xb220,
- 0xb23c, 0xb23c,
- 0xb258, 0xb258,
- 0xb274, 0xb274,
- 0xb290, 0xb290,
- 0xb2ac, 0xb2ac,
- 0xb2c8, 0xb2c8,
- 0xb2e4, 0xb2e4,
- 0xb300, 0xb300,
- 0xb31c, 0xb31c,
- 0xb338, 0xb338,
- 0xb354, 0xb354,
- 0xb370, 0xb370,
- 0xb38c, 0xb38c,
- 0xb3a8, 0xb3a8,
- 0xb3c4, 0xb3c4,
- 0xb3e0, 0xb3e0,
- 0xb3fc, 0xb3fc,
- 0xb418, 0xb418,
- 0xb434, 0xb434,
- 0xb450, 0xb450,
- 0xb46c, 0xb46c,
- 0xb488, 0xb488,
- 0xb4a4, 0xb4a4,
- 0xb4c0, 0xb4c0,
- 0xb4dc, 0xb4dc,
- 0xb4f8, 0xb4f8,
- 0xb514, 0xb514,
- 0xb530, 0xb530,
- 0xb54c, 0xb54c,
- 0xb568, 0xb568,
- 0xb584, 0xb584,
- 0xb5a0, 0xb5a0,
- 0xb5bc, 0xb5bc,
- 0xb5d8, 0xb5d8,
- 0xb5f4, 0xb5f4,
- 0xb610, 0xb610,
- 0xb62c, 0xb62c,
- 0xb648, 0xb648,
- 0xb664, 0xb664,
- 0xb680, 0xb680,
- 0xb69c, 0xb69c,
- 0xb6b8, 0xb6b8,
- 0xb6d4, 0xb6d4,
- 0xb6f0, 0xb6f0,
- 0xb70c, 0xb70c,
- 0xb728, 0xb728,
- 0xb744, 0xb744,
- 0xb760, 0xb760,
- 0xb77c, 0xb77c,
- 0xb798, 0xb798,
- 0xb7b4, 0xb7b4,
- 0xb7d0, 0xb7d0,
- 0xb7ec, 0xb7ec,
- 0xb808, 0xb808,
- 0xb824, 0xb824,
- 0xb840, 0xb840,
- 0xb85c, 0xb85c,
- 0xb878, 0xb878,
- 0xb894, 0xb894,
- 0xb8b0, 0xb8b0,
- 0xb8cc, 0xb8cc,
- 0xb8e8, 0xb8e8,
- 0xb904, 0xb904,
- 0xb920, 0xb920,
- 0xb93c, 0xb93c,
- 0xb958, 0xb958,
- 0xb974, 0xb974,
- 0xb990, 0xb990,
- 0xb9ac, 0xb9ac,
- 0xb9c8, 0xb9c8,
- 0xb9e4, 0xb9e4,
- 0xba00, 0xba00,
- 0xba1c, 0xba1c,
- 0xba38, 0xba38,
- 0xba54, 0xba54,
- 0xba70, 0xba70,
- 0xba8c, 0xba8c,
- 0xbaa8, 0xbaa8,
- 0xbac4, 0xbac4,
- 0xbae0, 0xbae0,
- 0xbafc, 0xbafc,
- 0xbb18, 0xbb18,
- 0xbb34, 0xbb34,
- 0xbb50, 0xbb50,
- 0xbb6c, 0xbb6c,
- 0xbb88, 0xbb88,
- 0xbba4, 0xbba4,
- 0xbbc0, 0xbbc0,
- 0xbbdc, 0xbbdc,
- 0xbbf8, 0xbbf8,
- 0xbc14, 0xbc14,
- 0xbc30, 0xbc30,
- 0xbc4c, 0xbc4c,
- 0xbc68, 0xbc68,
- 0xbc84, 0xbc84,
- 0xbca0, 0xbca0,
- 0xbcbc, 0xbcbc,
- 0xbcd8, 0xbcd8,
- 0xbcf4, 0xbcf4,
- 0xbd10, 0xbd10,
- 0xbd2c, 0xbd2c,
- 0xbd48, 0xbd48,
- 0xbd64, 0xbd64,
- 0xbd80, 0xbd80,
- 0xbd9c, 0xbd9c,
- 0xbdb8, 0xbdb8,
- 0xbdd4, 0xbdd4,
- 0xbdf0, 0xbdf0,
- 0xbe0c, 0xbe0c,
- 0xbe28, 0xbe28,
- 0xbe44, 0xbe44,
- 0xbe60, 0xbe60,
- 0xbe7c, 0xbe7c,
- 0xbe98, 0xbe98,
- 0xbeb4, 0xbeb4,
- 0xbed0, 0xbed0,
- 0xbeec, 0xbeec,
- 0xbf08, 0xbf08,
- 0xbf24, 0xbf24,
- 0xbf40, 0xbf40,
- 0xbf5c, 0xbf5c,
- 0xbf78, 0xbf78,
- 0xbf94, 0xbf94,
- 0xbfb0, 0xbfb0,
- 0xbfcc, 0xbfcc,
- 0xbfe8, 0xbfe8,
- 0xc004, 0xc004,
- 0xc020, 0xc020,
- 0xc03c, 0xc03c,
- 0xc058, 0xc058,
- 0xc074, 0xc074,
- 0xc090, 0xc090,
- 0xc0ac, 0xc0ac,
- 0xc0c8, 0xc0c8,
- 0xc0e4, 0xc0e4,
- 0xc100, 0xc100,
- 0xc11c, 0xc11c,
- 0xc138, 0xc138,
- 0xc154, 0xc154,
- 0xc170, 0xc170,
- 0xc18c, 0xc18c,
- 0xc1a8, 0xc1a8,
- 0xc1c4, 0xc1c4,
- 0xc1e0, 0xc1e0,
- 0xc1fc, 0xc1fc,
- 0xc218, 0xc218,
- 0xc234, 0xc234,
- 0xc250, 0xc250,
- 0xc26c, 0xc26c,
- 0xc288, 0xc288,
- 0xc2a4, 0xc2a4,
- 0xc2c0, 0xc2c0,
- 0xc2dc, 0xc2dc,
- 0xc2f8, 0xc2f8,
- 0xc314, 0xc314,
- 0xc330, 0xc330,
- 0xc34c, 0xc34c,
- 0xc368, 0xc368,
- 0xc384, 0xc384,
- 0xc3a0, 0xc3a0,
- 0xc3bc, 0xc3bc,
- 0xc3d8, 0xc3d8,
- 0xc3f4, 0xc3f4,
- 0xc410, 0xc410,
- 0xc42c, 0xc42c,
- 0xc448, 0xc448,
- 0xc464, 0xc464,
- 0xc480, 0xc480,
- 0xc49c, 0xc49c,
- 0xc4b8, 0xc4b8,
- 0xc4d4, 0xc4d4,
- 0xc4f0, 0xc4f0,
- 0xc50c, 0xc50c,
- 0xc528, 0xc528,
- 0xc544, 0xc544,
- 0xc560, 0xc560,
- 0xc57c, 0xc57c,
- 0xc598, 0xc598,
- 0xc5b4, 0xc5b4,
- 0xc5d0, 0xc5d0,
- 0xc5ec, 0xc5ec,
- 0xc608, 0xc608,
- 0xc624, 0xc624,
- 0xc640, 0xc640,
- 0xc65c, 0xc65c,
- 0xc678, 0xc678,
- 0xc694, 0xc694,
- 0xc6b0, 0xc6b0,
- 0xc6cc, 0xc6cc,
- 0xc6e8, 0xc6e8,
- 0xc704, 0xc704,
- 0xc720, 0xc720,
- 0xc73c, 0xc73c,
- 0xc758, 0xc758,
- 0xc774, 0xc774,
- 0xc790, 0xc790,
- 0xc7ac, 0xc7ac,
- 0xc7c8, 0xc7c8,
- 0xc7e4, 0xc7e4,
- 0xc800, 0xc800,
- 0xc81c, 0xc81c,
- 0xc838, 0xc838,
- 0xc854, 0xc854,
- 0xc870, 0xc870,
- 0xc88c, 0xc88c,
- 0xc8a8, 0xc8a8,
- 0xc8c4, 0xc8c4,
- 0xc8e0, 0xc8e0,
- 0xc8fc, 0xc8fc,
- 0xc918, 0xc918,
- 0xc934, 0xc934,
- 0xc950, 0xc950,
- 0xc96c, 0xc96c,
- 0xc988, 0xc988,
- 0xc9a4, 0xc9a4,
- 0xc9c0, 0xc9c0,
- 0xc9dc, 0xc9dc,
- 0xc9f8, 0xc9f8,
- 0xca14, 0xca14,
- 0xca30, 0xca30,
- 0xca4c, 0xca4c,
- 0xca68, 0xca68,
- 0xca84, 0xca84,
- 0xcaa0, 0xcaa0,
- 0xcabc, 0xcabc,
- 0xcad8, 0xcad8,
- 0xcaf4, 0xcaf4,
- 0xcb10, 0xcb10,
- 0xcb2c, 0xcb2c,
- 0xcb48, 0xcb48,
- 0xcb64, 0xcb64,
- 0xcb80, 0xcb80,
- 0xcb9c, 0xcb9c,
- 0xcbb8, 0xcbb8,
- 0xcbd4, 0xcbd4,
- 0xcbf0, 0xcbf0,
- 0xcc0c, 0xcc0c,
- 0xcc28, 0xcc28,
- 0xcc44, 0xcc44,
- 0xcc60, 0xcc60,
- 0xcc7c, 0xcc7c,
- 0xcc98, 0xcc98,
- 0xccb4, 0xccb4,
- 0xccd0, 0xccd0,
- 0xccec, 0xccec,
- 0xcd08, 0xcd08,
- 0xcd24, 0xcd24,
- 0xcd40, 0xcd40,
- 0xcd5c, 0xcd5c,
- 0xcd78, 0xcd78,
- 0xcd94, 0xcd94,
- 0xcdb0, 0xcdb0,
- 0xcdcc, 0xcdcc,
- 0xcde8, 0xcde8,
- 0xce04, 0xce04,
- 0xce20, 0xce20,
- 0xce3c, 0xce3c,
- 0xce58, 0xce58,
- 0xce74, 0xce74,
- 0xce90, 0xce90,
- 0xceac, 0xceac,
- 0xcec8, 0xcec8,
- 0xcee4, 0xcee4,
- 0xcf00, 0xcf00,
- 0xcf1c, 0xcf1c,
- 0xcf38, 0xcf38,
- 0xcf54, 0xcf54,
- 0xcf70, 0xcf70,
- 0xcf8c, 0xcf8c,
- 0xcfa8, 0xcfa8,
- 0xcfc4, 0xcfc4,
- 0xcfe0, 0xcfe0,
- 0xcffc, 0xcffc,
- 0xd018, 0xd018,
- 0xd034, 0xd034,
- 0xd050, 0xd050,
- 0xd06c, 0xd06c,
- 0xd088, 0xd088,
- 0xd0a4, 0xd0a4,
- 0xd0c0, 0xd0c0,
- 0xd0dc, 0xd0dc,
- 0xd0f8, 0xd0f8,
- 0xd114, 0xd114,
- 0xd130, 0xd130,
- 0xd14c, 0xd14c,
- 0xd168, 0xd168,
- 0xd184, 0xd184,
- 0xd1a0, 0xd1a0,
- 0xd1bc, 0xd1bc,
- 0xd1d8, 0xd1d8,
- 0xd1f4, 0xd1f4,
- 0xd210, 0xd210,
- 0xd22c, 0xd22c,
- 0xd248, 0xd248,
- 0xd264, 0xd264,
- 0xd280, 0xd280,
- 0xd29c, 0xd29c,
- 0xd2b8, 0xd2b8,
- 0xd2d4, 0xd2d4,
- 0xd2f0, 0xd2f0,
- 0xd30c, 0xd30c,
- 0xd328, 0xd328,
- 0xd344, 0xd344,
- 0xd360, 0xd360,
- 0xd37c, 0xd37c,
- 0xd398, 0xd398,
- 0xd3b4, 0xd3b4,
- 0xd3d0, 0xd3d0,
- 0xd3ec, 0xd3ec,
- 0xd408, 0xd408,
- 0xd424, 0xd424,
- 0xd440, 0xd440,
- 0xd45c, 0xd45c,
- 0xd478, 0xd478,
- 0xd494, 0xd494,
- 0xd4b0, 0xd4b0,
- 0xd4cc, 0xd4cc,
- 0xd4e8, 0xd4e8,
- 0xd504, 0xd504,
- 0xd520, 0xd520,
- 0xd53c, 0xd53c,
- 0xd558, 0xd558,
- 0xd574, 0xd574,
- 0xd590, 0xd590,
- 0xd5ac, 0xd5ac,
- 0xd5c8, 0xd5c8,
- 0xd5e4, 0xd5e4,
- 0xd600, 0xd600,
- 0xd61c, 0xd61c,
- 0xd638, 0xd638,
- 0xd654, 0xd654,
- 0xd670, 0xd670,
- 0xd68c, 0xd68c,
- 0xd6a8, 0xd6a8,
- 0xd6c4, 0xd6c4,
- 0xd6e0, 0xd6e0,
- 0xd6fc, 0xd6fc,
- 0xd718, 0xd718,
- 0xd734, 0xd734,
- 0xd750, 0xd750,
- 0xd76c, 0xd76c,
- 0xd788, 0xd788,
-}; /* CR_Grapheme_Cluster_Break_LV */
-
-/* 'Grapheme_Cluster_Break_LVT': Grapheme_Cluster_Break=LVT */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_LVT[] = {
- 399,
- 0xac01, 0xac1b,
- 0xac1d, 0xac37,
- 0xac39, 0xac53,
- 0xac55, 0xac6f,
- 0xac71, 0xac8b,
- 0xac8d, 0xaca7,
- 0xaca9, 0xacc3,
- 0xacc5, 0xacdf,
- 0xace1, 0xacfb,
- 0xacfd, 0xad17,
- 0xad19, 0xad33,
- 0xad35, 0xad4f,
- 0xad51, 0xad6b,
- 0xad6d, 0xad87,
- 0xad89, 0xada3,
- 0xada5, 0xadbf,
- 0xadc1, 0xaddb,
- 0xaddd, 0xadf7,
- 0xadf9, 0xae13,
- 0xae15, 0xae2f,
- 0xae31, 0xae4b,
- 0xae4d, 0xae67,
- 0xae69, 0xae83,
- 0xae85, 0xae9f,
- 0xaea1, 0xaebb,
- 0xaebd, 0xaed7,
- 0xaed9, 0xaef3,
- 0xaef5, 0xaf0f,
- 0xaf11, 0xaf2b,
- 0xaf2d, 0xaf47,
- 0xaf49, 0xaf63,
- 0xaf65, 0xaf7f,
- 0xaf81, 0xaf9b,
- 0xaf9d, 0xafb7,
- 0xafb9, 0xafd3,
- 0xafd5, 0xafef,
- 0xaff1, 0xb00b,
- 0xb00d, 0xb027,
- 0xb029, 0xb043,
- 0xb045, 0xb05f,
- 0xb061, 0xb07b,
- 0xb07d, 0xb097,
- 0xb099, 0xb0b3,
- 0xb0b5, 0xb0cf,
- 0xb0d1, 0xb0eb,
- 0xb0ed, 0xb107,
- 0xb109, 0xb123,
- 0xb125, 0xb13f,
- 0xb141, 0xb15b,
- 0xb15d, 0xb177,
- 0xb179, 0xb193,
- 0xb195, 0xb1af,
- 0xb1b1, 0xb1cb,
- 0xb1cd, 0xb1e7,
- 0xb1e9, 0xb203,
- 0xb205, 0xb21f,
- 0xb221, 0xb23b,
- 0xb23d, 0xb257,
- 0xb259, 0xb273,
- 0xb275, 0xb28f,
- 0xb291, 0xb2ab,
- 0xb2ad, 0xb2c7,
- 0xb2c9, 0xb2e3,
- 0xb2e5, 0xb2ff,
- 0xb301, 0xb31b,
- 0xb31d, 0xb337,
- 0xb339, 0xb353,
- 0xb355, 0xb36f,
- 0xb371, 0xb38b,
- 0xb38d, 0xb3a7,
- 0xb3a9, 0xb3c3,
- 0xb3c5, 0xb3df,
- 0xb3e1, 0xb3fb,
- 0xb3fd, 0xb417,
- 0xb419, 0xb433,
- 0xb435, 0xb44f,
- 0xb451, 0xb46b,
- 0xb46d, 0xb487,
- 0xb489, 0xb4a3,
- 0xb4a5, 0xb4bf,
- 0xb4c1, 0xb4db,
- 0xb4dd, 0xb4f7,
- 0xb4f9, 0xb513,
- 0xb515, 0xb52f,
- 0xb531, 0xb54b,
- 0xb54d, 0xb567,
- 0xb569, 0xb583,
- 0xb585, 0xb59f,
- 0xb5a1, 0xb5bb,
- 0xb5bd, 0xb5d7,
- 0xb5d9, 0xb5f3,
- 0xb5f5, 0xb60f,
- 0xb611, 0xb62b,
- 0xb62d, 0xb647,
- 0xb649, 0xb663,
- 0xb665, 0xb67f,
- 0xb681, 0xb69b,
- 0xb69d, 0xb6b7,
- 0xb6b9, 0xb6d3,
- 0xb6d5, 0xb6ef,
- 0xb6f1, 0xb70b,
- 0xb70d, 0xb727,
- 0xb729, 0xb743,
- 0xb745, 0xb75f,
- 0xb761, 0xb77b,
- 0xb77d, 0xb797,
- 0xb799, 0xb7b3,
- 0xb7b5, 0xb7cf,
- 0xb7d1, 0xb7eb,
- 0xb7ed, 0xb807,
- 0xb809, 0xb823,
- 0xb825, 0xb83f,
- 0xb841, 0xb85b,
- 0xb85d, 0xb877,
- 0xb879, 0xb893,
- 0xb895, 0xb8af,
- 0xb8b1, 0xb8cb,
- 0xb8cd, 0xb8e7,
- 0xb8e9, 0xb903,
- 0xb905, 0xb91f,
- 0xb921, 0xb93b,
- 0xb93d, 0xb957,
- 0xb959, 0xb973,
- 0xb975, 0xb98f,
- 0xb991, 0xb9ab,
- 0xb9ad, 0xb9c7,
- 0xb9c9, 0xb9e3,
- 0xb9e5, 0xb9ff,
- 0xba01, 0xba1b,
- 0xba1d, 0xba37,
- 0xba39, 0xba53,
- 0xba55, 0xba6f,
- 0xba71, 0xba8b,
- 0xba8d, 0xbaa7,
- 0xbaa9, 0xbac3,
- 0xbac5, 0xbadf,
- 0xbae1, 0xbafb,
- 0xbafd, 0xbb17,
- 0xbb19, 0xbb33,
- 0xbb35, 0xbb4f,
- 0xbb51, 0xbb6b,
- 0xbb6d, 0xbb87,
- 0xbb89, 0xbba3,
- 0xbba5, 0xbbbf,
- 0xbbc1, 0xbbdb,
- 0xbbdd, 0xbbf7,
- 0xbbf9, 0xbc13,
- 0xbc15, 0xbc2f,
- 0xbc31, 0xbc4b,
- 0xbc4d, 0xbc67,
- 0xbc69, 0xbc83,
- 0xbc85, 0xbc9f,
- 0xbca1, 0xbcbb,
- 0xbcbd, 0xbcd7,
- 0xbcd9, 0xbcf3,
- 0xbcf5, 0xbd0f,
- 0xbd11, 0xbd2b,
- 0xbd2d, 0xbd47,
- 0xbd49, 0xbd63,
- 0xbd65, 0xbd7f,
- 0xbd81, 0xbd9b,
- 0xbd9d, 0xbdb7,
- 0xbdb9, 0xbdd3,
- 0xbdd5, 0xbdef,
- 0xbdf1, 0xbe0b,
- 0xbe0d, 0xbe27,
- 0xbe29, 0xbe43,
- 0xbe45, 0xbe5f,
- 0xbe61, 0xbe7b,
- 0xbe7d, 0xbe97,
- 0xbe99, 0xbeb3,
- 0xbeb5, 0xbecf,
- 0xbed1, 0xbeeb,
- 0xbeed, 0xbf07,
- 0xbf09, 0xbf23,
- 0xbf25, 0xbf3f,
- 0xbf41, 0xbf5b,
- 0xbf5d, 0xbf77,
- 0xbf79, 0xbf93,
- 0xbf95, 0xbfaf,
- 0xbfb1, 0xbfcb,
- 0xbfcd, 0xbfe7,
- 0xbfe9, 0xc003,
- 0xc005, 0xc01f,
- 0xc021, 0xc03b,
- 0xc03d, 0xc057,
- 0xc059, 0xc073,
- 0xc075, 0xc08f,
- 0xc091, 0xc0ab,
- 0xc0ad, 0xc0c7,
- 0xc0c9, 0xc0e3,
- 0xc0e5, 0xc0ff,
- 0xc101, 0xc11b,
- 0xc11d, 0xc137,
- 0xc139, 0xc153,
- 0xc155, 0xc16f,
- 0xc171, 0xc18b,
- 0xc18d, 0xc1a7,
- 0xc1a9, 0xc1c3,
- 0xc1c5, 0xc1df,
- 0xc1e1, 0xc1fb,
- 0xc1fd, 0xc217,
- 0xc219, 0xc233,
- 0xc235, 0xc24f,
- 0xc251, 0xc26b,
- 0xc26d, 0xc287,
- 0xc289, 0xc2a3,
- 0xc2a5, 0xc2bf,
- 0xc2c1, 0xc2db,
- 0xc2dd, 0xc2f7,
- 0xc2f9, 0xc313,
- 0xc315, 0xc32f,
- 0xc331, 0xc34b,
- 0xc34d, 0xc367,
- 0xc369, 0xc383,
- 0xc385, 0xc39f,
- 0xc3a1, 0xc3bb,
- 0xc3bd, 0xc3d7,
- 0xc3d9, 0xc3f3,
- 0xc3f5, 0xc40f,
- 0xc411, 0xc42b,
- 0xc42d, 0xc447,
- 0xc449, 0xc463,
- 0xc465, 0xc47f,
- 0xc481, 0xc49b,
- 0xc49d, 0xc4b7,
- 0xc4b9, 0xc4d3,
- 0xc4d5, 0xc4ef,
- 0xc4f1, 0xc50b,
- 0xc50d, 0xc527,
- 0xc529, 0xc543,
- 0xc545, 0xc55f,
- 0xc561, 0xc57b,
- 0xc57d, 0xc597,
- 0xc599, 0xc5b3,
- 0xc5b5, 0xc5cf,
- 0xc5d1, 0xc5eb,
- 0xc5ed, 0xc607,
- 0xc609, 0xc623,
- 0xc625, 0xc63f,
- 0xc641, 0xc65b,
- 0xc65d, 0xc677,
- 0xc679, 0xc693,
- 0xc695, 0xc6af,
- 0xc6b1, 0xc6cb,
- 0xc6cd, 0xc6e7,
- 0xc6e9, 0xc703,
- 0xc705, 0xc71f,
- 0xc721, 0xc73b,
- 0xc73d, 0xc757,
- 0xc759, 0xc773,
- 0xc775, 0xc78f,
- 0xc791, 0xc7ab,
- 0xc7ad, 0xc7c7,
- 0xc7c9, 0xc7e3,
- 0xc7e5, 0xc7ff,
- 0xc801, 0xc81b,
- 0xc81d, 0xc837,
- 0xc839, 0xc853,
- 0xc855, 0xc86f,
- 0xc871, 0xc88b,
- 0xc88d, 0xc8a7,
- 0xc8a9, 0xc8c3,
- 0xc8c5, 0xc8df,
- 0xc8e1, 0xc8fb,
- 0xc8fd, 0xc917,
- 0xc919, 0xc933,
- 0xc935, 0xc94f,
- 0xc951, 0xc96b,
- 0xc96d, 0xc987,
- 0xc989, 0xc9a3,
- 0xc9a5, 0xc9bf,
- 0xc9c1, 0xc9db,
- 0xc9dd, 0xc9f7,
- 0xc9f9, 0xca13,
- 0xca15, 0xca2f,
- 0xca31, 0xca4b,
- 0xca4d, 0xca67,
- 0xca69, 0xca83,
- 0xca85, 0xca9f,
- 0xcaa1, 0xcabb,
- 0xcabd, 0xcad7,
- 0xcad9, 0xcaf3,
- 0xcaf5, 0xcb0f,
- 0xcb11, 0xcb2b,
- 0xcb2d, 0xcb47,
- 0xcb49, 0xcb63,
- 0xcb65, 0xcb7f,
- 0xcb81, 0xcb9b,
- 0xcb9d, 0xcbb7,
- 0xcbb9, 0xcbd3,
- 0xcbd5, 0xcbef,
- 0xcbf1, 0xcc0b,
- 0xcc0d, 0xcc27,
- 0xcc29, 0xcc43,
- 0xcc45, 0xcc5f,
- 0xcc61, 0xcc7b,
- 0xcc7d, 0xcc97,
- 0xcc99, 0xccb3,
- 0xccb5, 0xcccf,
- 0xccd1, 0xcceb,
- 0xcced, 0xcd07,
- 0xcd09, 0xcd23,
- 0xcd25, 0xcd3f,
- 0xcd41, 0xcd5b,
- 0xcd5d, 0xcd77,
- 0xcd79, 0xcd93,
- 0xcd95, 0xcdaf,
- 0xcdb1, 0xcdcb,
- 0xcdcd, 0xcde7,
- 0xcde9, 0xce03,
- 0xce05, 0xce1f,
- 0xce21, 0xce3b,
- 0xce3d, 0xce57,
- 0xce59, 0xce73,
- 0xce75, 0xce8f,
- 0xce91, 0xceab,
- 0xcead, 0xcec7,
- 0xcec9, 0xcee3,
- 0xcee5, 0xceff,
- 0xcf01, 0xcf1b,
- 0xcf1d, 0xcf37,
- 0xcf39, 0xcf53,
- 0xcf55, 0xcf6f,
- 0xcf71, 0xcf8b,
- 0xcf8d, 0xcfa7,
- 0xcfa9, 0xcfc3,
- 0xcfc5, 0xcfdf,
- 0xcfe1, 0xcffb,
- 0xcffd, 0xd017,
- 0xd019, 0xd033,
- 0xd035, 0xd04f,
- 0xd051, 0xd06b,
- 0xd06d, 0xd087,
- 0xd089, 0xd0a3,
- 0xd0a5, 0xd0bf,
- 0xd0c1, 0xd0db,
- 0xd0dd, 0xd0f7,
- 0xd0f9, 0xd113,
- 0xd115, 0xd12f,
- 0xd131, 0xd14b,
- 0xd14d, 0xd167,
- 0xd169, 0xd183,
- 0xd185, 0xd19f,
- 0xd1a1, 0xd1bb,
- 0xd1bd, 0xd1d7,
- 0xd1d9, 0xd1f3,
- 0xd1f5, 0xd20f,
- 0xd211, 0xd22b,
- 0xd22d, 0xd247,
- 0xd249, 0xd263,
- 0xd265, 0xd27f,
- 0xd281, 0xd29b,
- 0xd29d, 0xd2b7,
- 0xd2b9, 0xd2d3,
- 0xd2d5, 0xd2ef,
- 0xd2f1, 0xd30b,
- 0xd30d, 0xd327,
- 0xd329, 0xd343,
- 0xd345, 0xd35f,
- 0xd361, 0xd37b,
- 0xd37d, 0xd397,
- 0xd399, 0xd3b3,
- 0xd3b5, 0xd3cf,
- 0xd3d1, 0xd3eb,
- 0xd3ed, 0xd407,
- 0xd409, 0xd423,
- 0xd425, 0xd43f,
- 0xd441, 0xd45b,
- 0xd45d, 0xd477,
- 0xd479, 0xd493,
- 0xd495, 0xd4af,
- 0xd4b1, 0xd4cb,
- 0xd4cd, 0xd4e7,
- 0xd4e9, 0xd503,
- 0xd505, 0xd51f,
- 0xd521, 0xd53b,
- 0xd53d, 0xd557,
- 0xd559, 0xd573,
- 0xd575, 0xd58f,
- 0xd591, 0xd5ab,
- 0xd5ad, 0xd5c7,
- 0xd5c9, 0xd5e3,
- 0xd5e5, 0xd5ff,
- 0xd601, 0xd61b,
- 0xd61d, 0xd637,
- 0xd639, 0xd653,
- 0xd655, 0xd66f,
- 0xd671, 0xd68b,
- 0xd68d, 0xd6a7,
- 0xd6a9, 0xd6c3,
- 0xd6c5, 0xd6df,
- 0xd6e1, 0xd6fb,
- 0xd6fd, 0xd717,
- 0xd719, 0xd733,
- 0xd735, 0xd74f,
- 0xd751, 0xd76b,
- 0xd76d, 0xd787,
- 0xd789, 0xd7a3,
-}; /* CR_Grapheme_Cluster_Break_LVT */
-
-/* 'Grapheme_Cluster_Break_ZWJ': Grapheme_Cluster_Break=ZWJ */
-static const OnigCodePoint CR_Grapheme_Cluster_Break_ZWJ[] = {
- 1,
- 0x200d, 0x200d,
-}; /* CR_Grapheme_Cluster_Break_ZWJ */
-
-/* 'In_Basic_Latin': Block */
-#define CR_In_Basic_Latin CR_ASCII
-
-/* 'In_Latin_1_Supplement': Block */
-static const OnigCodePoint CR_In_Latin_1_Supplement[] = {
- 1,
- 0x0080, 0x00ff,
-}; /* CR_In_Latin_1_Supplement */
-
-/* 'In_Latin_Extended_A': Block */
-static const OnigCodePoint CR_In_Latin_Extended_A[] = {
- 1,
- 0x0100, 0x017f,
-}; /* CR_In_Latin_Extended_A */
-
-/* 'In_Latin_Extended_B': Block */
-static const OnigCodePoint CR_In_Latin_Extended_B[] = {
- 1,
- 0x0180, 0x024f,
-}; /* CR_In_Latin_Extended_B */
-
-/* 'In_IPA_Extensions': Block */
-static const OnigCodePoint CR_In_IPA_Extensions[] = {
- 1,
- 0x0250, 0x02af,
-}; /* CR_In_IPA_Extensions */
-
-/* 'In_Spacing_Modifier_Letters': Block */
-static const OnigCodePoint CR_In_Spacing_Modifier_Letters[] = {
- 1,
- 0x02b0, 0x02ff,
-}; /* CR_In_Spacing_Modifier_Letters */
-
-/* 'In_Combining_Diacritical_Marks': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks[] = {
- 1,
- 0x0300, 0x036f,
-}; /* CR_In_Combining_Diacritical_Marks */
-
-/* 'In_Greek_and_Coptic': Block */
-static const OnigCodePoint CR_In_Greek_and_Coptic[] = {
- 1,
- 0x0370, 0x03ff,
-}; /* CR_In_Greek_and_Coptic */
-
-/* 'In_Cyrillic': Block */
-static const OnigCodePoint CR_In_Cyrillic[] = {
- 1,
- 0x0400, 0x04ff,
-}; /* CR_In_Cyrillic */
-
-/* 'In_Cyrillic_Supplement': Block */
-static const OnigCodePoint CR_In_Cyrillic_Supplement[] = {
- 1,
- 0x0500, 0x052f,
-}; /* CR_In_Cyrillic_Supplement */
-
-/* 'In_Armenian': Block */
-static const OnigCodePoint CR_In_Armenian[] = {
- 1,
- 0x0530, 0x058f,
-}; /* CR_In_Armenian */
-
-/* 'In_Hebrew': Block */
-static const OnigCodePoint CR_In_Hebrew[] = {
- 1,
- 0x0590, 0x05ff,
-}; /* CR_In_Hebrew */
-
-/* 'In_Arabic': Block */
-static const OnigCodePoint CR_In_Arabic[] = {
- 1,
- 0x0600, 0x06ff,
-}; /* CR_In_Arabic */
-
-/* 'In_Syriac': Block */
-static const OnigCodePoint CR_In_Syriac[] = {
- 1,
- 0x0700, 0x074f,
-}; /* CR_In_Syriac */
-
-/* 'In_Arabic_Supplement': Block */
-static const OnigCodePoint CR_In_Arabic_Supplement[] = {
- 1,
- 0x0750, 0x077f,
-}; /* CR_In_Arabic_Supplement */
-
-/* 'In_Thaana': Block */
-static const OnigCodePoint CR_In_Thaana[] = {
- 1,
- 0x0780, 0x07bf,
-}; /* CR_In_Thaana */
-
-/* 'In_NKo': Block */
-static const OnigCodePoint CR_In_NKo[] = {
- 1,
- 0x07c0, 0x07ff,
-}; /* CR_In_NKo */
-
-/* 'In_Samaritan': Block */
-static const OnigCodePoint CR_In_Samaritan[] = {
- 1,
- 0x0800, 0x083f,
-}; /* CR_In_Samaritan */
-
-/* 'In_Mandaic': Block */
-static const OnigCodePoint CR_In_Mandaic[] = {
- 1,
- 0x0840, 0x085f,
-}; /* CR_In_Mandaic */
-
-/* 'In_Syriac_Supplement': Block */
-static const OnigCodePoint CR_In_Syriac_Supplement[] = {
- 1,
- 0x0860, 0x086f,
-}; /* CR_In_Syriac_Supplement */
-
-/* 'In_Arabic_Extended_B': Block */
-static const OnigCodePoint CR_In_Arabic_Extended_B[] = {
- 1,
- 0x0870, 0x089f,
-}; /* CR_In_Arabic_Extended_B */
-
-/* 'In_Arabic_Extended_A': Block */
-static const OnigCodePoint CR_In_Arabic_Extended_A[] = {
- 1,
- 0x08a0, 0x08ff,
-}; /* CR_In_Arabic_Extended_A */
-
-/* 'In_Devanagari': Block */
-static const OnigCodePoint CR_In_Devanagari[] = {
- 1,
- 0x0900, 0x097f,
-}; /* CR_In_Devanagari */
-
-/* 'In_Bengali': Block */
-static const OnigCodePoint CR_In_Bengali[] = {
- 1,
- 0x0980, 0x09ff,
-}; /* CR_In_Bengali */
-
-/* 'In_Gurmukhi': Block */
-static const OnigCodePoint CR_In_Gurmukhi[] = {
- 1,
- 0x0a00, 0x0a7f,
-}; /* CR_In_Gurmukhi */
-
-/* 'In_Gujarati': Block */
-static const OnigCodePoint CR_In_Gujarati[] = {
- 1,
- 0x0a80, 0x0aff,
-}; /* CR_In_Gujarati */
-
-/* 'In_Oriya': Block */
-static const OnigCodePoint CR_In_Oriya[] = {
- 1,
- 0x0b00, 0x0b7f,
-}; /* CR_In_Oriya */
-
-/* 'In_Tamil': Block */
-static const OnigCodePoint CR_In_Tamil[] = {
- 1,
- 0x0b80, 0x0bff,
-}; /* CR_In_Tamil */
-
-/* 'In_Telugu': Block */
-static const OnigCodePoint CR_In_Telugu[] = {
- 1,
- 0x0c00, 0x0c7f,
-}; /* CR_In_Telugu */
-
-/* 'In_Kannada': Block */
-static const OnigCodePoint CR_In_Kannada[] = {
- 1,
- 0x0c80, 0x0cff,
-}; /* CR_In_Kannada */
-
-/* 'In_Malayalam': Block */
-static const OnigCodePoint CR_In_Malayalam[] = {
- 1,
- 0x0d00, 0x0d7f,
-}; /* CR_In_Malayalam */
-
-/* 'In_Sinhala': Block */
-static const OnigCodePoint CR_In_Sinhala[] = {
- 1,
- 0x0d80, 0x0dff,
-}; /* CR_In_Sinhala */
-
-/* 'In_Thai': Block */
-static const OnigCodePoint CR_In_Thai[] = {
- 1,
- 0x0e00, 0x0e7f,
-}; /* CR_In_Thai */
-
-/* 'In_Lao': Block */
-static const OnigCodePoint CR_In_Lao[] = {
- 1,
- 0x0e80, 0x0eff,
-}; /* CR_In_Lao */
-
-/* 'In_Tibetan': Block */
-static const OnigCodePoint CR_In_Tibetan[] = {
- 1,
- 0x0f00, 0x0fff,
-}; /* CR_In_Tibetan */
-
-/* 'In_Myanmar': Block */
-static const OnigCodePoint CR_In_Myanmar[] = {
- 1,
- 0x1000, 0x109f,
-}; /* CR_In_Myanmar */
-
-/* 'In_Georgian': Block */
-static const OnigCodePoint CR_In_Georgian[] = {
- 1,
- 0x10a0, 0x10ff,
-}; /* CR_In_Georgian */
-
-/* 'In_Hangul_Jamo': Block */
-static const OnigCodePoint CR_In_Hangul_Jamo[] = {
- 1,
- 0x1100, 0x11ff,
-}; /* CR_In_Hangul_Jamo */
-
-/* 'In_Ethiopic': Block */
-static const OnigCodePoint CR_In_Ethiopic[] = {
- 1,
- 0x1200, 0x137f,
-}; /* CR_In_Ethiopic */
-
-/* 'In_Ethiopic_Supplement': Block */
-static const OnigCodePoint CR_In_Ethiopic_Supplement[] = {
- 1,
- 0x1380, 0x139f,
-}; /* CR_In_Ethiopic_Supplement */
-
-/* 'In_Cherokee': Block */
-static const OnigCodePoint CR_In_Cherokee[] = {
- 1,
- 0x13a0, 0x13ff,
-}; /* CR_In_Cherokee */
-
-/* 'In_Unified_Canadian_Aboriginal_Syllabics': Block */
-static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics[] = {
- 1,
- 0x1400, 0x167f,
-}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics */
-
-/* 'In_Ogham': Block */
-static const OnigCodePoint CR_In_Ogham[] = {
- 1,
- 0x1680, 0x169f,
-}; /* CR_In_Ogham */
-
-/* 'In_Runic': Block */
-static const OnigCodePoint CR_In_Runic[] = {
- 1,
- 0x16a0, 0x16ff,
-}; /* CR_In_Runic */
-
-/* 'In_Tagalog': Block */
-static const OnigCodePoint CR_In_Tagalog[] = {
- 1,
- 0x1700, 0x171f,
-}; /* CR_In_Tagalog */
-
-/* 'In_Hanunoo': Block */
-static const OnigCodePoint CR_In_Hanunoo[] = {
- 1,
- 0x1720, 0x173f,
-}; /* CR_In_Hanunoo */
-
-/* 'In_Buhid': Block */
-static const OnigCodePoint CR_In_Buhid[] = {
- 1,
- 0x1740, 0x175f,
-}; /* CR_In_Buhid */
-
-/* 'In_Tagbanwa': Block */
-static const OnigCodePoint CR_In_Tagbanwa[] = {
- 1,
- 0x1760, 0x177f,
-}; /* CR_In_Tagbanwa */
-
-/* 'In_Khmer': Block */
-static const OnigCodePoint CR_In_Khmer[] = {
- 1,
- 0x1780, 0x17ff,
-}; /* CR_In_Khmer */
-
-/* 'In_Mongolian': Block */
-static const OnigCodePoint CR_In_Mongolian[] = {
- 1,
- 0x1800, 0x18af,
-}; /* CR_In_Mongolian */
-
-/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended': Block */
-static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended[] = {
- 1,
- 0x18b0, 0x18ff,
-}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended */
-
-/* 'In_Limbu': Block */
-static const OnigCodePoint CR_In_Limbu[] = {
- 1,
- 0x1900, 0x194f,
-}; /* CR_In_Limbu */
-
-/* 'In_Tai_Le': Block */
-static const OnigCodePoint CR_In_Tai_Le[] = {
- 1,
- 0x1950, 0x197f,
-}; /* CR_In_Tai_Le */
-
-/* 'In_New_Tai_Lue': Block */
-static const OnigCodePoint CR_In_New_Tai_Lue[] = {
- 1,
- 0x1980, 0x19df,
-}; /* CR_In_New_Tai_Lue */
-
-/* 'In_Khmer_Symbols': Block */
-static const OnigCodePoint CR_In_Khmer_Symbols[] = {
- 1,
- 0x19e0, 0x19ff,
-}; /* CR_In_Khmer_Symbols */
-
-/* 'In_Buginese': Block */
-static const OnigCodePoint CR_In_Buginese[] = {
- 1,
- 0x1a00, 0x1a1f,
-}; /* CR_In_Buginese */
-
-/* 'In_Tai_Tham': Block */
-static const OnigCodePoint CR_In_Tai_Tham[] = {
- 1,
- 0x1a20, 0x1aaf,
-}; /* CR_In_Tai_Tham */
-
-/* 'In_Combining_Diacritical_Marks_Extended': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Extended[] = {
- 1,
- 0x1ab0, 0x1aff,
-}; /* CR_In_Combining_Diacritical_Marks_Extended */
-
-/* 'In_Balinese': Block */
-static const OnigCodePoint CR_In_Balinese[] = {
- 1,
- 0x1b00, 0x1b7f,
-}; /* CR_In_Balinese */
-
-/* 'In_Sundanese': Block */
-static const OnigCodePoint CR_In_Sundanese[] = {
- 1,
- 0x1b80, 0x1bbf,
-}; /* CR_In_Sundanese */
-
-/* 'In_Batak': Block */
-static const OnigCodePoint CR_In_Batak[] = {
- 1,
- 0x1bc0, 0x1bff,
-}; /* CR_In_Batak */
-
-/* 'In_Lepcha': Block */
-static const OnigCodePoint CR_In_Lepcha[] = {
- 1,
- 0x1c00, 0x1c4f,
-}; /* CR_In_Lepcha */
-
-/* 'In_Ol_Chiki': Block */
-#define CR_In_Ol_Chiki CR_Ol_Chiki
-
-/* 'In_Cyrillic_Extended_C': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_C[] = {
- 1,
- 0x1c80, 0x1c8f,
-}; /* CR_In_Cyrillic_Extended_C */
-
-/* 'In_Georgian_Extended': Block */
-static const OnigCodePoint CR_In_Georgian_Extended[] = {
- 1,
- 0x1c90, 0x1cbf,
-}; /* CR_In_Georgian_Extended */
-
-/* 'In_Sundanese_Supplement': Block */
-static const OnigCodePoint CR_In_Sundanese_Supplement[] = {
- 1,
- 0x1cc0, 0x1ccf,
-}; /* CR_In_Sundanese_Supplement */
-
-/* 'In_Vedic_Extensions': Block */
-static const OnigCodePoint CR_In_Vedic_Extensions[] = {
- 1,
- 0x1cd0, 0x1cff,
-}; /* CR_In_Vedic_Extensions */
-
-/* 'In_Phonetic_Extensions': Block */
-static const OnigCodePoint CR_In_Phonetic_Extensions[] = {
- 1,
- 0x1d00, 0x1d7f,
-}; /* CR_In_Phonetic_Extensions */
-
-/* 'In_Phonetic_Extensions_Supplement': Block */
-static const OnigCodePoint CR_In_Phonetic_Extensions_Supplement[] = {
- 1,
- 0x1d80, 0x1dbf,
-}; /* CR_In_Phonetic_Extensions_Supplement */
-
-/* 'In_Combining_Diacritical_Marks_Supplement': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Supplement[] = {
- 1,
- 0x1dc0, 0x1dff,
-}; /* CR_In_Combining_Diacritical_Marks_Supplement */
-
-/* 'In_Latin_Extended_Additional': Block */
-static const OnigCodePoint CR_In_Latin_Extended_Additional[] = {
- 1,
- 0x1e00, 0x1eff,
-}; /* CR_In_Latin_Extended_Additional */
-
-/* 'In_Greek_Extended': Block */
-static const OnigCodePoint CR_In_Greek_Extended[] = {
- 1,
- 0x1f00, 0x1fff,
-}; /* CR_In_Greek_Extended */
-
-/* 'In_General_Punctuation': Block */
-static const OnigCodePoint CR_In_General_Punctuation[] = {
- 1,
- 0x2000, 0x206f,
-}; /* CR_In_General_Punctuation */
-
-/* 'In_Superscripts_and_Subscripts': Block */
-static const OnigCodePoint CR_In_Superscripts_and_Subscripts[] = {
- 1,
- 0x2070, 0x209f,
-}; /* CR_In_Superscripts_and_Subscripts */
-
-/* 'In_Currency_Symbols': Block */
-static const OnigCodePoint CR_In_Currency_Symbols[] = {
- 1,
- 0x20a0, 0x20cf,
-}; /* CR_In_Currency_Symbols */
-
-/* 'In_Combining_Diacritical_Marks_for_Symbols': Block */
-static const OnigCodePoint CR_In_Combining_Diacritical_Marks_for_Symbols[] = {
- 1,
- 0x20d0, 0x20ff,
-}; /* CR_In_Combining_Diacritical_Marks_for_Symbols */
-
-/* 'In_Letterlike_Symbols': Block */
-static const OnigCodePoint CR_In_Letterlike_Symbols[] = {
- 1,
- 0x2100, 0x214f,
-}; /* CR_In_Letterlike_Symbols */
-
-/* 'In_Number_Forms': Block */
-static const OnigCodePoint CR_In_Number_Forms[] = {
- 1,
- 0x2150, 0x218f,
-}; /* CR_In_Number_Forms */
-
-/* 'In_Arrows': Block */
-static const OnigCodePoint CR_In_Arrows[] = {
- 1,
- 0x2190, 0x21ff,
-}; /* CR_In_Arrows */
-
-/* 'In_Mathematical_Operators': Block */
-static const OnigCodePoint CR_In_Mathematical_Operators[] = {
- 1,
- 0x2200, 0x22ff,
-}; /* CR_In_Mathematical_Operators */
-
-/* 'In_Miscellaneous_Technical': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Technical[] = {
- 1,
- 0x2300, 0x23ff,
-}; /* CR_In_Miscellaneous_Technical */
-
-/* 'In_Control_Pictures': Block */
-static const OnigCodePoint CR_In_Control_Pictures[] = {
- 1,
- 0x2400, 0x243f,
-}; /* CR_In_Control_Pictures */
-
-/* 'In_Optical_Character_Recognition': Block */
-static const OnigCodePoint CR_In_Optical_Character_Recognition[] = {
- 1,
- 0x2440, 0x245f,
-}; /* CR_In_Optical_Character_Recognition */
-
-/* 'In_Enclosed_Alphanumerics': Block */
-static const OnigCodePoint CR_In_Enclosed_Alphanumerics[] = {
- 1,
- 0x2460, 0x24ff,
-}; /* CR_In_Enclosed_Alphanumerics */
-
-/* 'In_Box_Drawing': Block */
-static const OnigCodePoint CR_In_Box_Drawing[] = {
- 1,
- 0x2500, 0x257f,
-}; /* CR_In_Box_Drawing */
-
-/* 'In_Block_Elements': Block */
-static const OnigCodePoint CR_In_Block_Elements[] = {
- 1,
- 0x2580, 0x259f,
-}; /* CR_In_Block_Elements */
-
-/* 'In_Geometric_Shapes': Block */
-static const OnigCodePoint CR_In_Geometric_Shapes[] = {
- 1,
- 0x25a0, 0x25ff,
-}; /* CR_In_Geometric_Shapes */
-
-/* 'In_Miscellaneous_Symbols': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Symbols[] = {
- 1,
- 0x2600, 0x26ff,
-}; /* CR_In_Miscellaneous_Symbols */
-
-/* 'In_Dingbats': Block */
-static const OnigCodePoint CR_In_Dingbats[] = {
- 1,
- 0x2700, 0x27bf,
-}; /* CR_In_Dingbats */
-
-/* 'In_Miscellaneous_Mathematical_Symbols_A': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_A[] = {
- 1,
- 0x27c0, 0x27ef,
-}; /* CR_In_Miscellaneous_Mathematical_Symbols_A */
-
-/* 'In_Supplemental_Arrows_A': Block */
-static const OnigCodePoint CR_In_Supplemental_Arrows_A[] = {
- 1,
- 0x27f0, 0x27ff,
-}; /* CR_In_Supplemental_Arrows_A */
-
-/* 'In_Braille_Patterns': Block */
-#define CR_In_Braille_Patterns CR_Braille
-
-/* 'In_Supplemental_Arrows_B': Block */
-static const OnigCodePoint CR_In_Supplemental_Arrows_B[] = {
- 1,
- 0x2900, 0x297f,
-}; /* CR_In_Supplemental_Arrows_B */
-
-/* 'In_Miscellaneous_Mathematical_Symbols_B': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_B[] = {
- 1,
- 0x2980, 0x29ff,
-}; /* CR_In_Miscellaneous_Mathematical_Symbols_B */
-
-/* 'In_Supplemental_Mathematical_Operators': Block */
-static const OnigCodePoint CR_In_Supplemental_Mathematical_Operators[] = {
- 1,
- 0x2a00, 0x2aff,
-}; /* CR_In_Supplemental_Mathematical_Operators */
-
-/* 'In_Miscellaneous_Symbols_and_Arrows': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Arrows[] = {
- 1,
- 0x2b00, 0x2bff,
-}; /* CR_In_Miscellaneous_Symbols_and_Arrows */
-
-/* 'In_Glagolitic': Block */
-static const OnigCodePoint CR_In_Glagolitic[] = {
- 1,
- 0x2c00, 0x2c5f,
-}; /* CR_In_Glagolitic */
-
-/* 'In_Latin_Extended_C': Block */
-static const OnigCodePoint CR_In_Latin_Extended_C[] = {
- 1,
- 0x2c60, 0x2c7f,
-}; /* CR_In_Latin_Extended_C */
-
-/* 'In_Coptic': Block */
-static const OnigCodePoint CR_In_Coptic[] = {
- 1,
- 0x2c80, 0x2cff,
-}; /* CR_In_Coptic */
-
-/* 'In_Georgian_Supplement': Block */
-static const OnigCodePoint CR_In_Georgian_Supplement[] = {
- 1,
- 0x2d00, 0x2d2f,
-}; /* CR_In_Georgian_Supplement */
-
-/* 'In_Tifinagh': Block */
-static const OnigCodePoint CR_In_Tifinagh[] = {
- 1,
- 0x2d30, 0x2d7f,
-}; /* CR_In_Tifinagh */
-
-/* 'In_Ethiopic_Extended': Block */
-static const OnigCodePoint CR_In_Ethiopic_Extended[] = {
- 1,
- 0x2d80, 0x2ddf,
-}; /* CR_In_Ethiopic_Extended */
-
-/* 'In_Cyrillic_Extended_A': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_A[] = {
- 1,
- 0x2de0, 0x2dff,
-}; /* CR_In_Cyrillic_Extended_A */
-
-/* 'In_Supplemental_Punctuation': Block */
-static const OnigCodePoint CR_In_Supplemental_Punctuation[] = {
- 1,
- 0x2e00, 0x2e7f,
-}; /* CR_In_Supplemental_Punctuation */
-
-/* 'In_CJK_Radicals_Supplement': Block */
-static const OnigCodePoint CR_In_CJK_Radicals_Supplement[] = {
- 1,
- 0x2e80, 0x2eff,
-}; /* CR_In_CJK_Radicals_Supplement */
-
-/* 'In_Kangxi_Radicals': Block */
-static const OnigCodePoint CR_In_Kangxi_Radicals[] = {
- 1,
- 0x2f00, 0x2fdf,
-}; /* CR_In_Kangxi_Radicals */
-
-/* 'In_Ideographic_Description_Characters': Block */
-static const OnigCodePoint CR_In_Ideographic_Description_Characters[] = {
- 1,
- 0x2ff0, 0x2fff,
-}; /* CR_In_Ideographic_Description_Characters */
-
-/* 'In_CJK_Symbols_and_Punctuation': Block */
-static const OnigCodePoint CR_In_CJK_Symbols_and_Punctuation[] = {
- 1,
- 0x3000, 0x303f,
-}; /* CR_In_CJK_Symbols_and_Punctuation */
-
-/* 'In_Hiragana': Block */
-static const OnigCodePoint CR_In_Hiragana[] = {
- 1,
- 0x3040, 0x309f,
-}; /* CR_In_Hiragana */
-
-/* 'In_Katakana': Block */
-static const OnigCodePoint CR_In_Katakana[] = {
- 1,
- 0x30a0, 0x30ff,
-}; /* CR_In_Katakana */
-
-/* 'In_Bopomofo': Block */
-static const OnigCodePoint CR_In_Bopomofo[] = {
- 1,
- 0x3100, 0x312f,
-}; /* CR_In_Bopomofo */
-
-/* 'In_Hangul_Compatibility_Jamo': Block */
-static const OnigCodePoint CR_In_Hangul_Compatibility_Jamo[] = {
- 1,
- 0x3130, 0x318f,
-}; /* CR_In_Hangul_Compatibility_Jamo */
-
-/* 'In_Kanbun': Block */
-static const OnigCodePoint CR_In_Kanbun[] = {
- 1,
- 0x3190, 0x319f,
-}; /* CR_In_Kanbun */
-
-/* 'In_Bopomofo_Extended': Block */
-static const OnigCodePoint CR_In_Bopomofo_Extended[] = {
- 1,
- 0x31a0, 0x31bf,
-}; /* CR_In_Bopomofo_Extended */
-
-/* 'In_CJK_Strokes': Block */
-static const OnigCodePoint CR_In_CJK_Strokes[] = {
- 1,
- 0x31c0, 0x31ef,
-}; /* CR_In_CJK_Strokes */
-
-/* 'In_Katakana_Phonetic_Extensions': Block */
-static const OnigCodePoint CR_In_Katakana_Phonetic_Extensions[] = {
- 1,
- 0x31f0, 0x31ff,
-}; /* CR_In_Katakana_Phonetic_Extensions */
-
-/* 'In_Enclosed_CJK_Letters_and_Months': Block */
-static const OnigCodePoint CR_In_Enclosed_CJK_Letters_and_Months[] = {
- 1,
- 0x3200, 0x32ff,
-}; /* CR_In_Enclosed_CJK_Letters_and_Months */
-
-/* 'In_CJK_Compatibility': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility[] = {
- 1,
- 0x3300, 0x33ff,
-}; /* CR_In_CJK_Compatibility */
-
-/* 'In_CJK_Unified_Ideographs_Extension_A': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_A[] = {
- 1,
- 0x3400, 0x4dbf,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_A */
-
-/* 'In_Yijing_Hexagram_Symbols': Block */
-static const OnigCodePoint CR_In_Yijing_Hexagram_Symbols[] = {
- 1,
- 0x4dc0, 0x4dff,
-}; /* CR_In_Yijing_Hexagram_Symbols */
-
-/* 'In_CJK_Unified_Ideographs': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs[] = {
- 1,
- 0x4e00, 0x9fff,
-}; /* CR_In_CJK_Unified_Ideographs */
-
-/* 'In_Yi_Syllables': Block */
-static const OnigCodePoint CR_In_Yi_Syllables[] = {
- 1,
- 0xa000, 0xa48f,
-}; /* CR_In_Yi_Syllables */
-
-/* 'In_Yi_Radicals': Block */
-static const OnigCodePoint CR_In_Yi_Radicals[] = {
- 1,
- 0xa490, 0xa4cf,
-}; /* CR_In_Yi_Radicals */
-
-/* 'In_Lisu': Block */
-static const OnigCodePoint CR_In_Lisu[] = {
- 1,
- 0xa4d0, 0xa4ff,
-}; /* CR_In_Lisu */
-
-/* 'In_Vai': Block */
-static const OnigCodePoint CR_In_Vai[] = {
- 1,
- 0xa500, 0xa63f,
-}; /* CR_In_Vai */
-
-/* 'In_Cyrillic_Extended_B': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_B[] = {
- 1,
- 0xa640, 0xa69f,
-}; /* CR_In_Cyrillic_Extended_B */
-
-/* 'In_Bamum': Block */
-static const OnigCodePoint CR_In_Bamum[] = {
- 1,
- 0xa6a0, 0xa6ff,
-}; /* CR_In_Bamum */
-
-/* 'In_Modifier_Tone_Letters': Block */
-static const OnigCodePoint CR_In_Modifier_Tone_Letters[] = {
- 1,
- 0xa700, 0xa71f,
-}; /* CR_In_Modifier_Tone_Letters */
-
-/* 'In_Latin_Extended_D': Block */
-static const OnigCodePoint CR_In_Latin_Extended_D[] = {
- 1,
- 0xa720, 0xa7ff,
-}; /* CR_In_Latin_Extended_D */
-
-/* 'In_Syloti_Nagri': Block */
-static const OnigCodePoint CR_In_Syloti_Nagri[] = {
- 1,
- 0xa800, 0xa82f,
-}; /* CR_In_Syloti_Nagri */
-
-/* 'In_Common_Indic_Number_Forms': Block */
-static const OnigCodePoint CR_In_Common_Indic_Number_Forms[] = {
- 1,
- 0xa830, 0xa83f,
-}; /* CR_In_Common_Indic_Number_Forms */
-
-/* 'In_Phags_pa': Block */
-static const OnigCodePoint CR_In_Phags_pa[] = {
- 1,
- 0xa840, 0xa87f,
-}; /* CR_In_Phags_pa */
-
-/* 'In_Saurashtra': Block */
-static const OnigCodePoint CR_In_Saurashtra[] = {
- 1,
- 0xa880, 0xa8df,
-}; /* CR_In_Saurashtra */
-
-/* 'In_Devanagari_Extended': Block */
-static const OnigCodePoint CR_In_Devanagari_Extended[] = {
- 1,
- 0xa8e0, 0xa8ff,
-}; /* CR_In_Devanagari_Extended */
-
-/* 'In_Kayah_Li': Block */
-static const OnigCodePoint CR_In_Kayah_Li[] = {
- 1,
- 0xa900, 0xa92f,
-}; /* CR_In_Kayah_Li */
-
-/* 'In_Rejang': Block */
-static const OnigCodePoint CR_In_Rejang[] = {
- 1,
- 0xa930, 0xa95f,
-}; /* CR_In_Rejang */
-
-/* 'In_Hangul_Jamo_Extended_A': Block */
-static const OnigCodePoint CR_In_Hangul_Jamo_Extended_A[] = {
- 1,
- 0xa960, 0xa97f,
-}; /* CR_In_Hangul_Jamo_Extended_A */
-
-/* 'In_Javanese': Block */
-static const OnigCodePoint CR_In_Javanese[] = {
- 1,
- 0xa980, 0xa9df,
-}; /* CR_In_Javanese */
-
-/* 'In_Myanmar_Extended_B': Block */
-static const OnigCodePoint CR_In_Myanmar_Extended_B[] = {
- 1,
- 0xa9e0, 0xa9ff,
-}; /* CR_In_Myanmar_Extended_B */
-
-/* 'In_Cham': Block */
-static const OnigCodePoint CR_In_Cham[] = {
- 1,
- 0xaa00, 0xaa5f,
-}; /* CR_In_Cham */
-
-/* 'In_Myanmar_Extended_A': Block */
-static const OnigCodePoint CR_In_Myanmar_Extended_A[] = {
- 1,
- 0xaa60, 0xaa7f,
-}; /* CR_In_Myanmar_Extended_A */
-
-/* 'In_Tai_Viet': Block */
-static const OnigCodePoint CR_In_Tai_Viet[] = {
- 1,
- 0xaa80, 0xaadf,
-}; /* CR_In_Tai_Viet */
-
-/* 'In_Meetei_Mayek_Extensions': Block */
-static const OnigCodePoint CR_In_Meetei_Mayek_Extensions[] = {
- 1,
- 0xaae0, 0xaaff,
-}; /* CR_In_Meetei_Mayek_Extensions */
-
-/* 'In_Ethiopic_Extended_A': Block */
-static const OnigCodePoint CR_In_Ethiopic_Extended_A[] = {
- 1,
- 0xab00, 0xab2f,
-}; /* CR_In_Ethiopic_Extended_A */
-
-/* 'In_Latin_Extended_E': Block */
-static const OnigCodePoint CR_In_Latin_Extended_E[] = {
- 1,
- 0xab30, 0xab6f,
-}; /* CR_In_Latin_Extended_E */
-
-/* 'In_Cherokee_Supplement': Block */
-static const OnigCodePoint CR_In_Cherokee_Supplement[] = {
- 1,
- 0xab70, 0xabbf,
-}; /* CR_In_Cherokee_Supplement */
-
-/* 'In_Meetei_Mayek': Block */
-static const OnigCodePoint CR_In_Meetei_Mayek[] = {
- 1,
- 0xabc0, 0xabff,
-}; /* CR_In_Meetei_Mayek */
-
-/* 'In_Hangul_Syllables': Block */
-static const OnigCodePoint CR_In_Hangul_Syllables[] = {
- 1,
- 0xac00, 0xd7af,
-}; /* CR_In_Hangul_Syllables */
-
-/* 'In_Hangul_Jamo_Extended_B': Block */
-static const OnigCodePoint CR_In_Hangul_Jamo_Extended_B[] = {
- 1,
- 0xd7b0, 0xd7ff,
-}; /* CR_In_Hangul_Jamo_Extended_B */
-
-/* 'In_High_Surrogates': Block */
-static const OnigCodePoint CR_In_High_Surrogates[] = {
- 1,
- 0xd800, 0xdb7f,
-}; /* CR_In_High_Surrogates */
-
-/* 'In_High_Private_Use_Surrogates': Block */
-static const OnigCodePoint CR_In_High_Private_Use_Surrogates[] = {
- 1,
- 0xdb80, 0xdbff,
-}; /* CR_In_High_Private_Use_Surrogates */
-
-/* 'In_Low_Surrogates': Block */
-static const OnigCodePoint CR_In_Low_Surrogates[] = {
- 1,
- 0xdc00, 0xdfff,
-}; /* CR_In_Low_Surrogates */
-
-/* 'In_Private_Use_Area': Block */
-static const OnigCodePoint CR_In_Private_Use_Area[] = {
- 1,
- 0xe000, 0xf8ff,
-}; /* CR_In_Private_Use_Area */
-
-/* 'In_CJK_Compatibility_Ideographs': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs[] = {
- 1,
- 0xf900, 0xfaff,
-}; /* CR_In_CJK_Compatibility_Ideographs */
-
-/* 'In_Alphabetic_Presentation_Forms': Block */
-static const OnigCodePoint CR_In_Alphabetic_Presentation_Forms[] = {
- 1,
- 0xfb00, 0xfb4f,
-}; /* CR_In_Alphabetic_Presentation_Forms */
-
-/* 'In_Arabic_Presentation_Forms_A': Block */
-static const OnigCodePoint CR_In_Arabic_Presentation_Forms_A[] = {
- 1,
- 0xfb50, 0xfdff,
-}; /* CR_In_Arabic_Presentation_Forms_A */
-
-/* 'In_Variation_Selectors': Block */
-static const OnigCodePoint CR_In_Variation_Selectors[] = {
- 1,
- 0xfe00, 0xfe0f,
-}; /* CR_In_Variation_Selectors */
-
-/* 'In_Vertical_Forms': Block */
-static const OnigCodePoint CR_In_Vertical_Forms[] = {
- 1,
- 0xfe10, 0xfe1f,
-}; /* CR_In_Vertical_Forms */
-
-/* 'In_Combining_Half_Marks': Block */
-static const OnigCodePoint CR_In_Combining_Half_Marks[] = {
- 1,
- 0xfe20, 0xfe2f,
-}; /* CR_In_Combining_Half_Marks */
-
-/* 'In_CJK_Compatibility_Forms': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility_Forms[] = {
- 1,
- 0xfe30, 0xfe4f,
-}; /* CR_In_CJK_Compatibility_Forms */
-
-/* 'In_Small_Form_Variants': Block */
-static const OnigCodePoint CR_In_Small_Form_Variants[] = {
- 1,
- 0xfe50, 0xfe6f,
-}; /* CR_In_Small_Form_Variants */
-
-/* 'In_Arabic_Presentation_Forms_B': Block */
-static const OnigCodePoint CR_In_Arabic_Presentation_Forms_B[] = {
- 1,
- 0xfe70, 0xfeff,
-}; /* CR_In_Arabic_Presentation_Forms_B */
-
-/* 'In_Halfwidth_and_Fullwidth_Forms': Block */
-static const OnigCodePoint CR_In_Halfwidth_and_Fullwidth_Forms[] = {
- 1,
- 0xff00, 0xffef,
-}; /* CR_In_Halfwidth_and_Fullwidth_Forms */
-
-/* 'In_Specials': Block */
-static const OnigCodePoint CR_In_Specials[] = {
- 1,
- 0xfff0, 0xffff,
-}; /* CR_In_Specials */
-
-/* 'In_Linear_B_Syllabary': Block */
-static const OnigCodePoint CR_In_Linear_B_Syllabary[] = {
- 1,
- 0x10000, 0x1007f,
-}; /* CR_In_Linear_B_Syllabary */
-
-/* 'In_Linear_B_Ideograms': Block */
-static const OnigCodePoint CR_In_Linear_B_Ideograms[] = {
- 1,
- 0x10080, 0x100ff,
-}; /* CR_In_Linear_B_Ideograms */
-
-/* 'In_Aegean_Numbers': Block */
-static const OnigCodePoint CR_In_Aegean_Numbers[] = {
- 1,
- 0x10100, 0x1013f,
-}; /* CR_In_Aegean_Numbers */
-
-/* 'In_Ancient_Greek_Numbers': Block */
-static const OnigCodePoint CR_In_Ancient_Greek_Numbers[] = {
- 1,
- 0x10140, 0x1018f,
-}; /* CR_In_Ancient_Greek_Numbers */
-
-/* 'In_Ancient_Symbols': Block */
-static const OnigCodePoint CR_In_Ancient_Symbols[] = {
- 1,
- 0x10190, 0x101cf,
-}; /* CR_In_Ancient_Symbols */
-
-/* 'In_Phaistos_Disc': Block */
-static const OnigCodePoint CR_In_Phaistos_Disc[] = {
- 1,
- 0x101d0, 0x101ff,
-}; /* CR_In_Phaistos_Disc */
-
-/* 'In_Lycian': Block */
-static const OnigCodePoint CR_In_Lycian[] = {
- 1,
- 0x10280, 0x1029f,
-}; /* CR_In_Lycian */
-
-/* 'In_Carian': Block */
-static const OnigCodePoint CR_In_Carian[] = {
- 1,
- 0x102a0, 0x102df,
-}; /* CR_In_Carian */
-
-/* 'In_Coptic_Epact_Numbers': Block */
-static const OnigCodePoint CR_In_Coptic_Epact_Numbers[] = {
- 1,
- 0x102e0, 0x102ff,
-}; /* CR_In_Coptic_Epact_Numbers */
-
-/* 'In_Old_Italic': Block */
-static const OnigCodePoint CR_In_Old_Italic[] = {
- 1,
- 0x10300, 0x1032f,
-}; /* CR_In_Old_Italic */
-
-/* 'In_Gothic': Block */
-static const OnigCodePoint CR_In_Gothic[] = {
- 1,
- 0x10330, 0x1034f,
-}; /* CR_In_Gothic */
-
-/* 'In_Old_Permic': Block */
-static const OnigCodePoint CR_In_Old_Permic[] = {
- 1,
- 0x10350, 0x1037f,
-}; /* CR_In_Old_Permic */
-
-/* 'In_Ugaritic': Block */
-static const OnigCodePoint CR_In_Ugaritic[] = {
- 1,
- 0x10380, 0x1039f,
-}; /* CR_In_Ugaritic */
-
-/* 'In_Old_Persian': Block */
-static const OnigCodePoint CR_In_Old_Persian[] = {
- 1,
- 0x103a0, 0x103df,
-}; /* CR_In_Old_Persian */
-
-/* 'In_Deseret': Block */
-#define CR_In_Deseret CR_Deseret
-
-/* 'In_Shavian': Block */
-#define CR_In_Shavian CR_Shavian
-
-/* 'In_Osmanya': Block */
-static const OnigCodePoint CR_In_Osmanya[] = {
- 1,
- 0x10480, 0x104af,
-}; /* CR_In_Osmanya */
-
-/* 'In_Osage': Block */
-static const OnigCodePoint CR_In_Osage[] = {
- 1,
- 0x104b0, 0x104ff,
-}; /* CR_In_Osage */
-
-/* 'In_Elbasan': Block */
-static const OnigCodePoint CR_In_Elbasan[] = {
- 1,
- 0x10500, 0x1052f,
-}; /* CR_In_Elbasan */
-
-/* 'In_Caucasian_Albanian': Block */
-static const OnigCodePoint CR_In_Caucasian_Albanian[] = {
- 1,
- 0x10530, 0x1056f,
-}; /* CR_In_Caucasian_Albanian */
-
-/* 'In_Vithkuqi': Block */
-static const OnigCodePoint CR_In_Vithkuqi[] = {
- 1,
- 0x10570, 0x105bf,
-}; /* CR_In_Vithkuqi */
-
-/* 'In_Linear_A': Block */
-static const OnigCodePoint CR_In_Linear_A[] = {
- 1,
- 0x10600, 0x1077f,
-}; /* CR_In_Linear_A */
-
-/* 'In_Latin_Extended_F': Block */
-static const OnigCodePoint CR_In_Latin_Extended_F[] = {
- 1,
- 0x10780, 0x107bf,
-}; /* CR_In_Latin_Extended_F */
-
-/* 'In_Cypriot_Syllabary': Block */
-static const OnigCodePoint CR_In_Cypriot_Syllabary[] = {
- 1,
- 0x10800, 0x1083f,
-}; /* CR_In_Cypriot_Syllabary */
-
-/* 'In_Imperial_Aramaic': Block */
-static const OnigCodePoint CR_In_Imperial_Aramaic[] = {
- 1,
- 0x10840, 0x1085f,
-}; /* CR_In_Imperial_Aramaic */
-
-/* 'In_Palmyrene': Block */
-#define CR_In_Palmyrene CR_Palmyrene
-
-/* 'In_Nabataean': Block */
-static const OnigCodePoint CR_In_Nabataean[] = {
- 1,
- 0x10880, 0x108af,
-}; /* CR_In_Nabataean */
-
-/* 'In_Hatran': Block */
-static const OnigCodePoint CR_In_Hatran[] = {
- 1,
- 0x108e0, 0x108ff,
-}; /* CR_In_Hatran */
-
-/* 'In_Phoenician': Block */
-static const OnigCodePoint CR_In_Phoenician[] = {
- 1,
- 0x10900, 0x1091f,
-}; /* CR_In_Phoenician */
-
-/* 'In_Lydian': Block */
-static const OnigCodePoint CR_In_Lydian[] = {
- 1,
- 0x10920, 0x1093f,
-}; /* CR_In_Lydian */
-
-/* 'In_Meroitic_Hieroglyphs': Block */
-#define CR_In_Meroitic_Hieroglyphs CR_Meroitic_Hieroglyphs
-
-/* 'In_Meroitic_Cursive': Block */
-static const OnigCodePoint CR_In_Meroitic_Cursive[] = {
- 1,
- 0x109a0, 0x109ff,
-}; /* CR_In_Meroitic_Cursive */
-
-/* 'In_Kharoshthi': Block */
-static const OnigCodePoint CR_In_Kharoshthi[] = {
- 1,
- 0x10a00, 0x10a5f,
-}; /* CR_In_Kharoshthi */
-
-/* 'In_Old_South_Arabian': Block */
-#define CR_In_Old_South_Arabian CR_Old_South_Arabian
-
-/* 'In_Old_North_Arabian': Block */
-#define CR_In_Old_North_Arabian CR_Old_North_Arabian
-
-/* 'In_Manichaean': Block */
-static const OnigCodePoint CR_In_Manichaean[] = {
- 1,
- 0x10ac0, 0x10aff,
-}; /* CR_In_Manichaean */
-
-/* 'In_Avestan': Block */
-static const OnigCodePoint CR_In_Avestan[] = {
- 1,
- 0x10b00, 0x10b3f,
-}; /* CR_In_Avestan */
-
-/* 'In_Inscriptional_Parthian': Block */
-static const OnigCodePoint CR_In_Inscriptional_Parthian[] = {
- 1,
- 0x10b40, 0x10b5f,
-}; /* CR_In_Inscriptional_Parthian */
-
-/* 'In_Inscriptional_Pahlavi': Block */
-static const OnigCodePoint CR_In_Inscriptional_Pahlavi[] = {
- 1,
- 0x10b60, 0x10b7f,
-}; /* CR_In_Inscriptional_Pahlavi */
-
-/* 'In_Psalter_Pahlavi': Block */
-static const OnigCodePoint CR_In_Psalter_Pahlavi[] = {
- 1,
- 0x10b80, 0x10baf,
-}; /* CR_In_Psalter_Pahlavi */
-
-/* 'In_Old_Turkic': Block */
-static const OnigCodePoint CR_In_Old_Turkic[] = {
- 1,
- 0x10c00, 0x10c4f,
-}; /* CR_In_Old_Turkic */
-
-/* 'In_Old_Hungarian': Block */
-static const OnigCodePoint CR_In_Old_Hungarian[] = {
- 1,
- 0x10c80, 0x10cff,
-}; /* CR_In_Old_Hungarian */
-
-/* 'In_Hanifi_Rohingya': Block */
-static const OnigCodePoint CR_In_Hanifi_Rohingya[] = {
- 1,
- 0x10d00, 0x10d3f,
-}; /* CR_In_Hanifi_Rohingya */
-
-/* 'In_Rumi_Numeral_Symbols': Block */
-static const OnigCodePoint CR_In_Rumi_Numeral_Symbols[] = {
- 1,
- 0x10e60, 0x10e7f,
-}; /* CR_In_Rumi_Numeral_Symbols */
-
-/* 'In_Yezidi': Block */
-static const OnigCodePoint CR_In_Yezidi[] = {
- 1,
- 0x10e80, 0x10ebf,
-}; /* CR_In_Yezidi */
-
-/* 'In_Arabic_Extended_C': Block */
-static const OnigCodePoint CR_In_Arabic_Extended_C[] = {
- 1,
- 0x10ec0, 0x10eff,
-}; /* CR_In_Arabic_Extended_C */
-
-/* 'In_Old_Sogdian': Block */
-static const OnigCodePoint CR_In_Old_Sogdian[] = {
- 1,
- 0x10f00, 0x10f2f,
-}; /* CR_In_Old_Sogdian */
-
-/* 'In_Sogdian': Block */
-static const OnigCodePoint CR_In_Sogdian[] = {
- 1,
- 0x10f30, 0x10f6f,
-}; /* CR_In_Sogdian */
-
-/* 'In_Old_Uyghur': Block */
-static const OnigCodePoint CR_In_Old_Uyghur[] = {
- 1,
- 0x10f70, 0x10faf,
-}; /* CR_In_Old_Uyghur */
-
-/* 'In_Chorasmian': Block */
-static const OnigCodePoint CR_In_Chorasmian[] = {
- 1,
- 0x10fb0, 0x10fdf,
-}; /* CR_In_Chorasmian */
-
-/* 'In_Elymaic': Block */
-static const OnigCodePoint CR_In_Elymaic[] = {
- 1,
- 0x10fe0, 0x10fff,
-}; /* CR_In_Elymaic */
-
-/* 'In_Brahmi': Block */
-static const OnigCodePoint CR_In_Brahmi[] = {
- 1,
- 0x11000, 0x1107f,
-}; /* CR_In_Brahmi */
-
-/* 'In_Kaithi': Block */
-static const OnigCodePoint CR_In_Kaithi[] = {
- 1,
- 0x11080, 0x110cf,
-}; /* CR_In_Kaithi */
-
-/* 'In_Sora_Sompeng': Block */
-static const OnigCodePoint CR_In_Sora_Sompeng[] = {
- 1,
- 0x110d0, 0x110ff,
-}; /* CR_In_Sora_Sompeng */
-
-/* 'In_Chakma': Block */
-static const OnigCodePoint CR_In_Chakma[] = {
- 1,
- 0x11100, 0x1114f,
-}; /* CR_In_Chakma */
-
-/* 'In_Mahajani': Block */
-static const OnigCodePoint CR_In_Mahajani[] = {
- 1,
- 0x11150, 0x1117f,
-}; /* CR_In_Mahajani */
-
-/* 'In_Sharada': Block */
-#define CR_In_Sharada CR_Sharada
-
-/* 'In_Sinhala_Archaic_Numbers': Block */
-static const OnigCodePoint CR_In_Sinhala_Archaic_Numbers[] = {
- 1,
- 0x111e0, 0x111ff,
-}; /* CR_In_Sinhala_Archaic_Numbers */
-
-/* 'In_Khojki': Block */
-static const OnigCodePoint CR_In_Khojki[] = {
- 1,
- 0x11200, 0x1124f,
-}; /* CR_In_Khojki */
-
-/* 'In_Multani': Block */
-static const OnigCodePoint CR_In_Multani[] = {
- 1,
- 0x11280, 0x112af,
-}; /* CR_In_Multani */
-
-/* 'In_Khudawadi': Block */
-static const OnigCodePoint CR_In_Khudawadi[] = {
- 1,
- 0x112b0, 0x112ff,
-}; /* CR_In_Khudawadi */
-
-/* 'In_Grantha': Block */
-static const OnigCodePoint CR_In_Grantha[] = {
- 1,
- 0x11300, 0x1137f,
-}; /* CR_In_Grantha */
-
-/* 'In_Newa': Block */
-static const OnigCodePoint CR_In_Newa[] = {
- 1,
- 0x11400, 0x1147f,
-}; /* CR_In_Newa */
-
-/* 'In_Tirhuta': Block */
-static const OnigCodePoint CR_In_Tirhuta[] = {
- 1,
- 0x11480, 0x114df,
-}; /* CR_In_Tirhuta */
-
-/* 'In_Siddham': Block */
-static const OnigCodePoint CR_In_Siddham[] = {
- 1,
- 0x11580, 0x115ff,
-}; /* CR_In_Siddham */
-
-/* 'In_Modi': Block */
-static const OnigCodePoint CR_In_Modi[] = {
- 1,
- 0x11600, 0x1165f,
-}; /* CR_In_Modi */
-
-/* 'In_Mongolian_Supplement': Block */
-static const OnigCodePoint CR_In_Mongolian_Supplement[] = {
- 1,
- 0x11660, 0x1167f,
-}; /* CR_In_Mongolian_Supplement */
-
-/* 'In_Takri': Block */
-static const OnigCodePoint CR_In_Takri[] = {
- 1,
- 0x11680, 0x116cf,
-}; /* CR_In_Takri */
-
-/* 'In_Ahom': Block */
-static const OnigCodePoint CR_In_Ahom[] = {
- 1,
- 0x11700, 0x1174f,
-}; /* CR_In_Ahom */
-
-/* 'In_Dogra': Block */
-static const OnigCodePoint CR_In_Dogra[] = {
- 1,
- 0x11800, 0x1184f,
-}; /* CR_In_Dogra */
-
-/* 'In_Warang_Citi': Block */
-static const OnigCodePoint CR_In_Warang_Citi[] = {
- 1,
- 0x118a0, 0x118ff,
-}; /* CR_In_Warang_Citi */
-
-/* 'In_Dives_Akuru': Block */
-static const OnigCodePoint CR_In_Dives_Akuru[] = {
- 1,
- 0x11900, 0x1195f,
-}; /* CR_In_Dives_Akuru */
-
-/* 'In_Nandinagari': Block */
-static const OnigCodePoint CR_In_Nandinagari[] = {
- 1,
- 0x119a0, 0x119ff,
-}; /* CR_In_Nandinagari */
-
-/* 'In_Zanabazar_Square': Block */
-static const OnigCodePoint CR_In_Zanabazar_Square[] = {
- 1,
- 0x11a00, 0x11a4f,
-}; /* CR_In_Zanabazar_Square */
-
-/* 'In_Soyombo': Block */
-static const OnigCodePoint CR_In_Soyombo[] = {
- 1,
- 0x11a50, 0x11aaf,
-}; /* CR_In_Soyombo */
-
-/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended_A': Block */
-static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A[] = {
- 1,
- 0x11ab0, 0x11abf,
-}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A */
-
-/* 'In_Pau_Cin_Hau': Block */
-static const OnigCodePoint CR_In_Pau_Cin_Hau[] = {
- 1,
- 0x11ac0, 0x11aff,
-}; /* CR_In_Pau_Cin_Hau */
-
-/* 'In_Devanagari_Extended_A': Block */
-static const OnigCodePoint CR_In_Devanagari_Extended_A[] = {
- 1,
- 0x11b00, 0x11b5f,
-}; /* CR_In_Devanagari_Extended_A */
-
-/* 'In_Bhaiksuki': Block */
-static const OnigCodePoint CR_In_Bhaiksuki[] = {
- 1,
- 0x11c00, 0x11c6f,
-}; /* CR_In_Bhaiksuki */
-
-/* 'In_Marchen': Block */
-static const OnigCodePoint CR_In_Marchen[] = {
- 1,
- 0x11c70, 0x11cbf,
-}; /* CR_In_Marchen */
-
-/* 'In_Masaram_Gondi': Block */
-static const OnigCodePoint CR_In_Masaram_Gondi[] = {
- 1,
- 0x11d00, 0x11d5f,
-}; /* CR_In_Masaram_Gondi */
-
-/* 'In_Gunjala_Gondi': Block */
-static const OnigCodePoint CR_In_Gunjala_Gondi[] = {
- 1,
- 0x11d60, 0x11daf,
-}; /* CR_In_Gunjala_Gondi */
-
-/* 'In_Makasar': Block */
-static const OnigCodePoint CR_In_Makasar[] = {
- 1,
- 0x11ee0, 0x11eff,
-}; /* CR_In_Makasar */
-
-/* 'In_Kawi': Block */
-static const OnigCodePoint CR_In_Kawi[] = {
- 1,
- 0x11f00, 0x11f5f,
-}; /* CR_In_Kawi */
-
-/* 'In_Lisu_Supplement': Block */
-static const OnigCodePoint CR_In_Lisu_Supplement[] = {
- 1,
- 0x11fb0, 0x11fbf,
-}; /* CR_In_Lisu_Supplement */
-
-/* 'In_Tamil_Supplement': Block */
-static const OnigCodePoint CR_In_Tamil_Supplement[] = {
- 1,
- 0x11fc0, 0x11fff,
-}; /* CR_In_Tamil_Supplement */
-
-/* 'In_Cuneiform': Block */
-static const OnigCodePoint CR_In_Cuneiform[] = {
- 1,
- 0x12000, 0x123ff,
-}; /* CR_In_Cuneiform */
-
-/* 'In_Cuneiform_Numbers_and_Punctuation': Block */
-static const OnigCodePoint CR_In_Cuneiform_Numbers_and_Punctuation[] = {
- 1,
- 0x12400, 0x1247f,
-}; /* CR_In_Cuneiform_Numbers_and_Punctuation */
-
-/* 'In_Early_Dynastic_Cuneiform': Block */
-static const OnigCodePoint CR_In_Early_Dynastic_Cuneiform[] = {
- 1,
- 0x12480, 0x1254f,
-}; /* CR_In_Early_Dynastic_Cuneiform */
-
-/* 'In_Cypro_Minoan': Block */
-static const OnigCodePoint CR_In_Cypro_Minoan[] = {
- 1,
- 0x12f90, 0x12fff,
-}; /* CR_In_Cypro_Minoan */
-
-/* 'In_Egyptian_Hieroglyphs': Block */
-static const OnigCodePoint CR_In_Egyptian_Hieroglyphs[] = {
- 1,
- 0x13000, 0x1342f,
-}; /* CR_In_Egyptian_Hieroglyphs */
-
-/* 'In_Egyptian_Hieroglyph_Format_Controls': Block */
-static const OnigCodePoint CR_In_Egyptian_Hieroglyph_Format_Controls[] = {
- 1,
- 0x13430, 0x1345f,
-}; /* CR_In_Egyptian_Hieroglyph_Format_Controls */
-
-/* 'In_Anatolian_Hieroglyphs': Block */
-static const OnigCodePoint CR_In_Anatolian_Hieroglyphs[] = {
- 1,
- 0x14400, 0x1467f,
-}; /* CR_In_Anatolian_Hieroglyphs */
-
-/* 'In_Bamum_Supplement': Block */
-static const OnigCodePoint CR_In_Bamum_Supplement[] = {
- 1,
- 0x16800, 0x16a3f,
-}; /* CR_In_Bamum_Supplement */
-
-/* 'In_Mro': Block */
-static const OnigCodePoint CR_In_Mro[] = {
- 1,
- 0x16a40, 0x16a6f,
-}; /* CR_In_Mro */
-
-/* 'In_Tangsa': Block */
-static const OnigCodePoint CR_In_Tangsa[] = {
- 1,
- 0x16a70, 0x16acf,
-}; /* CR_In_Tangsa */
-
-/* 'In_Bassa_Vah': Block */
-static const OnigCodePoint CR_In_Bassa_Vah[] = {
- 1,
- 0x16ad0, 0x16aff,
-}; /* CR_In_Bassa_Vah */
-
-/* 'In_Pahawh_Hmong': Block */
-static const OnigCodePoint CR_In_Pahawh_Hmong[] = {
- 1,
- 0x16b00, 0x16b8f,
-}; /* CR_In_Pahawh_Hmong */
-
-/* 'In_Medefaidrin': Block */
-static const OnigCodePoint CR_In_Medefaidrin[] = {
- 1,
- 0x16e40, 0x16e9f,
-}; /* CR_In_Medefaidrin */
-
-/* 'In_Miao': Block */
-static const OnigCodePoint CR_In_Miao[] = {
- 1,
- 0x16f00, 0x16f9f,
-}; /* CR_In_Miao */
-
-/* 'In_Ideographic_Symbols_and_Punctuation': Block */
-static const OnigCodePoint CR_In_Ideographic_Symbols_and_Punctuation[] = {
- 1,
- 0x16fe0, 0x16fff,
-}; /* CR_In_Ideographic_Symbols_and_Punctuation */
-
-/* 'In_Tangut': Block */
-static const OnigCodePoint CR_In_Tangut[] = {
- 1,
- 0x17000, 0x187ff,
-}; /* CR_In_Tangut */
-
-/* 'In_Tangut_Components': Block */
-static const OnigCodePoint CR_In_Tangut_Components[] = {
- 1,
- 0x18800, 0x18aff,
-}; /* CR_In_Tangut_Components */
-
-/* 'In_Khitan_Small_Script': Block */
-static const OnigCodePoint CR_In_Khitan_Small_Script[] = {
- 1,
- 0x18b00, 0x18cff,
-}; /* CR_In_Khitan_Small_Script */
-
-/* 'In_Tangut_Supplement': Block */
-static const OnigCodePoint CR_In_Tangut_Supplement[] = {
- 1,
- 0x18d00, 0x18d7f,
-}; /* CR_In_Tangut_Supplement */
-
-/* 'In_Kana_Extended_B': Block */
-static const OnigCodePoint CR_In_Kana_Extended_B[] = {
- 1,
- 0x1aff0, 0x1afff,
-}; /* CR_In_Kana_Extended_B */
-
-/* 'In_Kana_Supplement': Block */
-static const OnigCodePoint CR_In_Kana_Supplement[] = {
- 1,
- 0x1b000, 0x1b0ff,
-}; /* CR_In_Kana_Supplement */
-
-/* 'In_Kana_Extended_A': Block */
-static const OnigCodePoint CR_In_Kana_Extended_A[] = {
- 1,
- 0x1b100, 0x1b12f,
-}; /* CR_In_Kana_Extended_A */
-
-/* 'In_Small_Kana_Extension': Block */
-static const OnigCodePoint CR_In_Small_Kana_Extension[] = {
- 1,
- 0x1b130, 0x1b16f,
-}; /* CR_In_Small_Kana_Extension */
-
-/* 'In_Nushu': Block */
-static const OnigCodePoint CR_In_Nushu[] = {
- 1,
- 0x1b170, 0x1b2ff,
-}; /* CR_In_Nushu */
-
-/* 'In_Duployan': Block */
-static const OnigCodePoint CR_In_Duployan[] = {
- 1,
- 0x1bc00, 0x1bc9f,
-}; /* CR_In_Duployan */
-
-/* 'In_Shorthand_Format_Controls': Block */
-static const OnigCodePoint CR_In_Shorthand_Format_Controls[] = {
- 1,
- 0x1bca0, 0x1bcaf,
-}; /* CR_In_Shorthand_Format_Controls */
-
-/* 'In_Znamenny_Musical_Notation': Block */
-static const OnigCodePoint CR_In_Znamenny_Musical_Notation[] = {
- 1,
- 0x1cf00, 0x1cfcf,
-}; /* CR_In_Znamenny_Musical_Notation */
-
-/* 'In_Byzantine_Musical_Symbols': Block */
-static const OnigCodePoint CR_In_Byzantine_Musical_Symbols[] = {
- 1,
- 0x1d000, 0x1d0ff,
-}; /* CR_In_Byzantine_Musical_Symbols */
-
-/* 'In_Musical_Symbols': Block */
-static const OnigCodePoint CR_In_Musical_Symbols[] = {
- 1,
- 0x1d100, 0x1d1ff,
-}; /* CR_In_Musical_Symbols */
-
-/* 'In_Ancient_Greek_Musical_Notation': Block */
-static const OnigCodePoint CR_In_Ancient_Greek_Musical_Notation[] = {
- 1,
- 0x1d200, 0x1d24f,
-}; /* CR_In_Ancient_Greek_Musical_Notation */
-
-/* 'In_Kaktovik_Numerals': Block */
-static const OnigCodePoint CR_In_Kaktovik_Numerals[] = {
- 1,
- 0x1d2c0, 0x1d2df,
-}; /* CR_In_Kaktovik_Numerals */
-
-/* 'In_Mayan_Numerals': Block */
-static const OnigCodePoint CR_In_Mayan_Numerals[] = {
- 1,
- 0x1d2e0, 0x1d2ff,
-}; /* CR_In_Mayan_Numerals */
-
-/* 'In_Tai_Xuan_Jing_Symbols': Block */
-static const OnigCodePoint CR_In_Tai_Xuan_Jing_Symbols[] = {
- 1,
- 0x1d300, 0x1d35f,
-}; /* CR_In_Tai_Xuan_Jing_Symbols */
-
-/* 'In_Counting_Rod_Numerals': Block */
-static const OnigCodePoint CR_In_Counting_Rod_Numerals[] = {
- 1,
- 0x1d360, 0x1d37f,
-}; /* CR_In_Counting_Rod_Numerals */
-
-/* 'In_Mathematical_Alphanumeric_Symbols': Block */
-static const OnigCodePoint CR_In_Mathematical_Alphanumeric_Symbols[] = {
- 1,
- 0x1d400, 0x1d7ff,
-}; /* CR_In_Mathematical_Alphanumeric_Symbols */
-
-/* 'In_Sutton_SignWriting': Block */
-static const OnigCodePoint CR_In_Sutton_SignWriting[] = {
- 1,
- 0x1d800, 0x1daaf,
-}; /* CR_In_Sutton_SignWriting */
-
-/* 'In_Latin_Extended_G': Block */
-static const OnigCodePoint CR_In_Latin_Extended_G[] = {
- 1,
- 0x1df00, 0x1dfff,
-}; /* CR_In_Latin_Extended_G */
-
-/* 'In_Glagolitic_Supplement': Block */
-static const OnigCodePoint CR_In_Glagolitic_Supplement[] = {
- 1,
- 0x1e000, 0x1e02f,
-}; /* CR_In_Glagolitic_Supplement */
-
-/* 'In_Cyrillic_Extended_D': Block */
-static const OnigCodePoint CR_In_Cyrillic_Extended_D[] = {
- 1,
- 0x1e030, 0x1e08f,
-}; /* CR_In_Cyrillic_Extended_D */
-
-/* 'In_Nyiakeng_Puachue_Hmong': Block */
-static const OnigCodePoint CR_In_Nyiakeng_Puachue_Hmong[] = {
- 1,
- 0x1e100, 0x1e14f,
-}; /* CR_In_Nyiakeng_Puachue_Hmong */
-
-/* 'In_Toto': Block */
-static const OnigCodePoint CR_In_Toto[] = {
- 1,
- 0x1e290, 0x1e2bf,
-}; /* CR_In_Toto */
-
-/* 'In_Wancho': Block */
-static const OnigCodePoint CR_In_Wancho[] = {
- 1,
- 0x1e2c0, 0x1e2ff,
-}; /* CR_In_Wancho */
-
-/* 'In_Nag_Mundari': Block */
-static const OnigCodePoint CR_In_Nag_Mundari[] = {
- 1,
- 0x1e4d0, 0x1e4ff,
-}; /* CR_In_Nag_Mundari */
-
-/* 'In_Ethiopic_Extended_B': Block */
-static const OnigCodePoint CR_In_Ethiopic_Extended_B[] = {
- 1,
- 0x1e7e0, 0x1e7ff,
-}; /* CR_In_Ethiopic_Extended_B */
-
-/* 'In_Mende_Kikakui': Block */
-static const OnigCodePoint CR_In_Mende_Kikakui[] = {
- 1,
- 0x1e800, 0x1e8df,
-}; /* CR_In_Mende_Kikakui */
-
-/* 'In_Adlam': Block */
-static const OnigCodePoint CR_In_Adlam[] = {
- 1,
- 0x1e900, 0x1e95f,
-}; /* CR_In_Adlam */
-
-/* 'In_Indic_Siyaq_Numbers': Block */
-static const OnigCodePoint CR_In_Indic_Siyaq_Numbers[] = {
- 1,
- 0x1ec70, 0x1ecbf,
-}; /* CR_In_Indic_Siyaq_Numbers */
-
-/* 'In_Ottoman_Siyaq_Numbers': Block */
-static const OnigCodePoint CR_In_Ottoman_Siyaq_Numbers[] = {
- 1,
- 0x1ed00, 0x1ed4f,
-}; /* CR_In_Ottoman_Siyaq_Numbers */
-
-/* 'In_Arabic_Mathematical_Alphabetic_Symbols': Block */
-static const OnigCodePoint CR_In_Arabic_Mathematical_Alphabetic_Symbols[] = {
- 1,
- 0x1ee00, 0x1eeff,
-}; /* CR_In_Arabic_Mathematical_Alphabetic_Symbols */
-
-/* 'In_Mahjong_Tiles': Block */
-static const OnigCodePoint CR_In_Mahjong_Tiles[] = {
- 1,
- 0x1f000, 0x1f02f,
-}; /* CR_In_Mahjong_Tiles */
-
-/* 'In_Domino_Tiles': Block */
-static const OnigCodePoint CR_In_Domino_Tiles[] = {
- 1,
- 0x1f030, 0x1f09f,
-}; /* CR_In_Domino_Tiles */
-
-/* 'In_Playing_Cards': Block */
-static const OnigCodePoint CR_In_Playing_Cards[] = {
- 1,
- 0x1f0a0, 0x1f0ff,
-}; /* CR_In_Playing_Cards */
-
-/* 'In_Enclosed_Alphanumeric_Supplement': Block */
-static const OnigCodePoint CR_In_Enclosed_Alphanumeric_Supplement[] = {
- 1,
- 0x1f100, 0x1f1ff,
-}; /* CR_In_Enclosed_Alphanumeric_Supplement */
-
-/* 'In_Enclosed_Ideographic_Supplement': Block */
-static const OnigCodePoint CR_In_Enclosed_Ideographic_Supplement[] = {
- 1,
- 0x1f200, 0x1f2ff,
-}; /* CR_In_Enclosed_Ideographic_Supplement */
-
-/* 'In_Miscellaneous_Symbols_and_Pictographs': Block */
-static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Pictographs[] = {
- 1,
- 0x1f300, 0x1f5ff,
-}; /* CR_In_Miscellaneous_Symbols_and_Pictographs */
-
-/* 'In_Emoticons': Block */
-static const OnigCodePoint CR_In_Emoticons[] = {
- 1,
- 0x1f600, 0x1f64f,
-}; /* CR_In_Emoticons */
-
-/* 'In_Ornamental_Dingbats': Block */
-static const OnigCodePoint CR_In_Ornamental_Dingbats[] = {
- 1,
- 0x1f650, 0x1f67f,
-}; /* CR_In_Ornamental_Dingbats */
-
-/* 'In_Transport_and_Map_Symbols': Block */
-static const OnigCodePoint CR_In_Transport_and_Map_Symbols[] = {
- 1,
- 0x1f680, 0x1f6ff,
-}; /* CR_In_Transport_and_Map_Symbols */
-
-/* 'In_Alchemical_Symbols': Block */
-static const OnigCodePoint CR_In_Alchemical_Symbols[] = {
- 1,
- 0x1f700, 0x1f77f,
-}; /* CR_In_Alchemical_Symbols */
-
-/* 'In_Geometric_Shapes_Extended': Block */
-static const OnigCodePoint CR_In_Geometric_Shapes_Extended[] = {
- 1,
- 0x1f780, 0x1f7ff,
-}; /* CR_In_Geometric_Shapes_Extended */
-
-/* 'In_Supplemental_Arrows_C': Block */
-static const OnigCodePoint CR_In_Supplemental_Arrows_C[] = {
- 1,
- 0x1f800, 0x1f8ff,
-}; /* CR_In_Supplemental_Arrows_C */
-
-/* 'In_Supplemental_Symbols_and_Pictographs': Block */
-static const OnigCodePoint CR_In_Supplemental_Symbols_and_Pictographs[] = {
- 1,
- 0x1f900, 0x1f9ff,
-}; /* CR_In_Supplemental_Symbols_and_Pictographs */
-
-/* 'In_Chess_Symbols': Block */
-static const OnigCodePoint CR_In_Chess_Symbols[] = {
- 1,
- 0x1fa00, 0x1fa6f,
-}; /* CR_In_Chess_Symbols */
-
-/* 'In_Symbols_and_Pictographs_Extended_A': Block */
-static const OnigCodePoint CR_In_Symbols_and_Pictographs_Extended_A[] = {
- 1,
- 0x1fa70, 0x1faff,
-}; /* CR_In_Symbols_and_Pictographs_Extended_A */
-
-/* 'In_Symbols_for_Legacy_Computing': Block */
-static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing[] = {
- 1,
- 0x1fb00, 0x1fbff,
-}; /* CR_In_Symbols_for_Legacy_Computing */
-
-/* 'In_CJK_Unified_Ideographs_Extension_B': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_B[] = {
- 1,
- 0x20000, 0x2a6df,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_B */
-
-/* 'In_CJK_Unified_Ideographs_Extension_C': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_C[] = {
- 1,
- 0x2a700, 0x2b73f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_C */
-
-/* 'In_CJK_Unified_Ideographs_Extension_D': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_D[] = {
- 1,
- 0x2b740, 0x2b81f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_D */
-
-/* 'In_CJK_Unified_Ideographs_Extension_E': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_E[] = {
- 1,
- 0x2b820, 0x2ceaf,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_E */
-
-/* 'In_CJK_Unified_Ideographs_Extension_F': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_F[] = {
- 1,
- 0x2ceb0, 0x2ebef,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_F */
-
-/* 'In_CJK_Unified_Ideographs_Extension_I': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_I[] = {
- 1,
- 0x2ebf0, 0x2ee5f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_I */
-
-/* 'In_CJK_Compatibility_Ideographs_Supplement': Block */
-static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs_Supplement[] = {
- 1,
- 0x2f800, 0x2fa1f,
-}; /* CR_In_CJK_Compatibility_Ideographs_Supplement */
-
-/* 'In_CJK_Unified_Ideographs_Extension_G': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_G[] = {
- 1,
- 0x30000, 0x3134f,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_G */
-
-/* 'In_CJK_Unified_Ideographs_Extension_H': Block */
-static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_H[] = {
- 1,
- 0x31350, 0x323af,
-}; /* CR_In_CJK_Unified_Ideographs_Extension_H */
-
-/* 'In_Tags': Block */
-static const OnigCodePoint CR_In_Tags[] = {
- 1,
- 0xe0000, 0xe007f,
-}; /* CR_In_Tags */
-
-/* 'In_Variation_Selectors_Supplement': Block */
-static const OnigCodePoint CR_In_Variation_Selectors_Supplement[] = {
- 1,
- 0xe0100, 0xe01ef,
-}; /* CR_In_Variation_Selectors_Supplement */
-
-/* 'In_Supplementary_Private_Use_Area_A': Block */
-static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_A[] = {
- 1,
- 0xf0000, 0xfffff,
-}; /* CR_In_Supplementary_Private_Use_Area_A */
-
-/* 'In_Supplementary_Private_Use_Area_B': Block */
-static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_B[] = {
- 1,
- 0x100000, 0x10ffff,
-}; /* CR_In_Supplementary_Private_Use_Area_B */
-
-/* 'In_No_Block': Block */
-static const OnigCodePoint CR_In_No_Block[] = {
- 51,
- 0x2fe0, 0x2fef,
- 0x10200, 0x1027f,
- 0x103e0, 0x103ff,
- 0x105c0, 0x105ff,
- 0x107c0, 0x107ff,
- 0x108b0, 0x108df,
- 0x10940, 0x1097f,
- 0x10aa0, 0x10abf,
- 0x10bb0, 0x10bff,
- 0x10c50, 0x10c7f,
- 0x10d40, 0x10e5f,
- 0x11250, 0x1127f,
- 0x11380, 0x113ff,
- 0x114e0, 0x1157f,
- 0x116d0, 0x116ff,
- 0x11750, 0x117ff,
- 0x11850, 0x1189f,
- 0x11960, 0x1199f,
- 0x11b60, 0x11bff,
- 0x11cc0, 0x11cff,
- 0x11db0, 0x11edf,
- 0x11f60, 0x11faf,
- 0x12550, 0x12f8f,
- 0x13460, 0x143ff,
- 0x14680, 0x167ff,
- 0x16b90, 0x16e3f,
- 0x16ea0, 0x16eff,
- 0x16fa0, 0x16fdf,
- 0x18d80, 0x1afef,
- 0x1b300, 0x1bbff,
- 0x1bcb0, 0x1ceff,
- 0x1cfd0, 0x1cfff,
- 0x1d250, 0x1d2bf,
- 0x1d380, 0x1d3ff,
- 0x1dab0, 0x1deff,
- 0x1e090, 0x1e0ff,
- 0x1e150, 0x1e28f,
- 0x1e300, 0x1e4cf,
- 0x1e500, 0x1e7df,
- 0x1e8e0, 0x1e8ff,
- 0x1e960, 0x1ec6f,
- 0x1ecc0, 0x1ecff,
- 0x1ed50, 0x1edff,
- 0x1ef00, 0x1efff,
- 0x1fc00, 0x1ffff,
- 0x2a6e0, 0x2a6ff,
- 0x2ee60, 0x2f7ff,
- 0x2fa20, 0x2ffff,
- 0x323b0, 0xdffff,
- 0xe0080, 0xe00ff,
- 0xe01f0, 0xeffff,
-}; /* CR_In_No_Block */
-
-#endif /* USE_UNICODE_PROPERTIES */
-static const OnigCodePoint* const CodeRanges[] = {
- CR_NEWLINE,
- CR_Alpha,
- CR_Blank,
- CR_Cntrl,
- CR_Digit,
- CR_Graph,
- CR_Lower,
- CR_Print,
- CR_XPosixPunct,
- CR_Space,
- CR_Upper,
- CR_XDigit,
- CR_Word,
- CR_Alnum,
- CR_ASCII,
- CR_Punct,
-#ifdef USE_UNICODE_PROPERTIES
- CR_Any,
- CR_Assigned,
- CR_C,
- CR_Cc,
- CR_Cf,
- CR_Cn,
- CR_Co,
- CR_Cs,
- CR_L,
- CR_LC,
- CR_Ll,
- CR_Lm,
- CR_Lo,
- CR_Lt,
- CR_Lu,
- CR_M,
- CR_Mc,
- CR_Me,
- CR_Mn,
- CR_N,
- CR_Nd,
- CR_Nl,
- CR_No,
- CR_P,
- CR_Pc,
- CR_Pd,
- CR_Pe,
- CR_Pf,
- CR_Pi,
- CR_Po,
- CR_Ps,
- CR_S,
- CR_Sc,
- CR_Sk,
- CR_Sm,
- CR_So,
- CR_Z,
- CR_Zl,
- CR_Zp,
- CR_Zs,
- CR_Math,
- CR_Alphabetic,
- CR_Lowercase,
- CR_Uppercase,
- CR_Cased,
- CR_Case_Ignorable,
- CR_Changes_When_Lowercased,
- CR_Changes_When_Uppercased,
- CR_Changes_When_Titlecased,
- CR_Changes_When_Casefolded,
- CR_Changes_When_Casemapped,
- CR_ID_Start,
- CR_ID_Continue,
- CR_XID_Start,
- CR_XID_Continue,
- CR_Default_Ignorable_Code_Point,
- CR_Grapheme_Extend,
- CR_Grapheme_Base,
- CR_Grapheme_Link,
- CR_InCB_Linker,
- CR_InCB_Consonant,
- CR_InCB_Extend,
- CR_Common,
- CR_Latin,
- CR_Greek,
- CR_Cyrillic,
- CR_Armenian,
- CR_Hebrew,
- CR_Arabic,
- CR_Syriac,
- CR_Thaana,
- CR_Devanagari,
- CR_Bengali,
- CR_Gurmukhi,
- CR_Gujarati,
- CR_Oriya,
- CR_Tamil,
- CR_Telugu,
- CR_Kannada,
- CR_Malayalam,
- CR_Sinhala,
- CR_Thai,
- CR_Lao,
- CR_Tibetan,
- CR_Myanmar,
- CR_Georgian,
- CR_Hangul,
- CR_Ethiopic,
- CR_Cherokee,
- CR_Canadian_Aboriginal,
- CR_Ogham,
- CR_Runic,
- CR_Khmer,
- CR_Mongolian,
- CR_Hiragana,
- CR_Katakana,
- CR_Bopomofo,
- CR_Han,
- CR_Yi,
- CR_Old_Italic,
- CR_Gothic,
- CR_Deseret,
- CR_Inherited,
- CR_Tagalog,
- CR_Hanunoo,
- CR_Buhid,
- CR_Tagbanwa,
- CR_Limbu,
- CR_Tai_Le,
- CR_Linear_B,
- CR_Ugaritic,
- CR_Shavian,
- CR_Osmanya,
- CR_Cypriot,
- CR_Braille,
- CR_Buginese,
- CR_Coptic,
- CR_New_Tai_Lue,
- CR_Glagolitic,
- CR_Tifinagh,
- CR_Syloti_Nagri,
- CR_Old_Persian,
- CR_Kharoshthi,
- CR_Balinese,
- CR_Cuneiform,
- CR_Phoenician,
- CR_Phags_Pa,
- CR_Nko,
- CR_Sundanese,
- CR_Lepcha,
- CR_Ol_Chiki,
- CR_Vai,
- CR_Saurashtra,
- CR_Kayah_Li,
- CR_Rejang,
- CR_Lycian,
- CR_Carian,
- CR_Lydian,
- CR_Cham,
- CR_Tai_Tham,
- CR_Tai_Viet,
- CR_Avestan,
- CR_Egyptian_Hieroglyphs,
- CR_Samaritan,
- CR_Lisu,
- CR_Bamum,
- CR_Javanese,
- CR_Meetei_Mayek,
- CR_Imperial_Aramaic,
- CR_Old_South_Arabian,
- CR_Inscriptional_Parthian,
- CR_Inscriptional_Pahlavi,
- CR_Old_Turkic,
- CR_Kaithi,
- CR_Batak,
- CR_Brahmi,
- CR_Mandaic,
- CR_Chakma,
- CR_Meroitic_Cursive,
- CR_Meroitic_Hieroglyphs,
- CR_Miao,
- CR_Sharada,
- CR_Sora_Sompeng,
- CR_Takri,
- CR_Caucasian_Albanian,
- CR_Bassa_Vah,
- CR_Duployan,
- CR_Elbasan,
- CR_Grantha,
- CR_Pahawh_Hmong,
- CR_Khojki,
- CR_Linear_A,
- CR_Mahajani,
- CR_Manichaean,
- CR_Mende_Kikakui,
- CR_Modi,
- CR_Mro,
- CR_Old_North_Arabian,
- CR_Nabataean,
- CR_Palmyrene,
- CR_Pau_Cin_Hau,
- CR_Old_Permic,
- CR_Psalter_Pahlavi,
- CR_Siddham,
- CR_Khudawadi,
- CR_Tirhuta,
- CR_Warang_Citi,
- CR_Ahom,
- CR_Anatolian_Hieroglyphs,
- CR_Hatran,
- CR_Multani,
- CR_Old_Hungarian,
- CR_SignWriting,
- CR_Adlam,
- CR_Bhaiksuki,
- CR_Marchen,
- CR_Newa,
- CR_Osage,
- CR_Tangut,
- CR_Masaram_Gondi,
- CR_Nushu,
- CR_Soyombo,
- CR_Zanabazar_Square,
- CR_Dogra,
- CR_Gunjala_Gondi,
- CR_Makasar,
- CR_Medefaidrin,
- CR_Hanifi_Rohingya,
- CR_Sogdian,
- CR_Old_Sogdian,
- CR_Elymaic,
- CR_Nandinagari,
- CR_Nyiakeng_Puachue_Hmong,
- CR_Wancho,
- CR_Chorasmian,
- CR_Dives_Akuru,
- CR_Khitan_Small_Script,
- CR_Yezidi,
- CR_Cypro_Minoan,
- CR_Old_Uyghur,
- CR_Tangsa,
- CR_Toto,
- CR_Vithkuqi,
- CR_Kawi,
- CR_Nag_Mundari,
- CR_White_Space,
- CR_Bidi_Control,
- CR_Join_Control,
- CR_Dash,
- CR_Hyphen,
- CR_Quotation_Mark,
- CR_Terminal_Punctuation,
- CR_Other_Math,
- CR_Hex_Digit,
- CR_ASCII_Hex_Digit,
- CR_Other_Alphabetic,
- CR_Ideographic,
- CR_Diacritic,
- CR_Extender,
- CR_Other_Lowercase,
- CR_Other_Uppercase,
- CR_Noncharacter_Code_Point,
- CR_Other_Grapheme_Extend,
- CR_IDS_Binary_Operator,
- CR_IDS_Trinary_Operator,
- CR_IDS_Unary_Operator,
- CR_Radical,
- CR_Unified_Ideograph,
- CR_Other_Default_Ignorable_Code_Point,
- CR_Deprecated,
- CR_Soft_Dotted,
- CR_Logical_Order_Exception,
- CR_Other_ID_Start,
- CR_Other_ID_Continue,
- CR_ID_Compat_Math_Continue,
- CR_ID_Compat_Math_Start,
- CR_Sentence_Terminal,
- CR_Variation_Selector,
- CR_Pattern_White_Space,
- CR_Pattern_Syntax,
- CR_Prepended_Concatenation_Mark,
- CR_Regional_Indicator,
- CR_Emoji,
- CR_Emoji_Presentation,
- CR_Emoji_Modifier,
- CR_Emoji_Modifier_Base,
- CR_Emoji_Component,
- CR_Extended_Pictographic,
- CR_Unknown,
-#ifdef USE_UNICODE_AGE_PROPERTIES
- CR_Age_1_1,
- CR_Age_2_0,
- CR_Age_2_1,
- CR_Age_3_0,
- CR_Age_3_1,
- CR_Age_3_2,
- CR_Age_4_0,
- CR_Age_4_1,
- CR_Age_5_0,
- CR_Age_5_1,
- CR_Age_5_2,
- CR_Age_6_0,
- CR_Age_6_1,
- CR_Age_6_2,
- CR_Age_6_3,
- CR_Age_7_0,
- CR_Age_8_0,
- CR_Age_9_0,
- CR_Age_10_0,
- CR_Age_11_0,
- CR_Age_12_0,
- CR_Age_12_1,
- CR_Age_13_0,
- CR_Age_14_0,
- CR_Age_15_0,
- CR_Age_15_1,
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- CR_Grapheme_Cluster_Break_Prepend,
- CR_Grapheme_Cluster_Break_CR,
- CR_Grapheme_Cluster_Break_LF,
- CR_Grapheme_Cluster_Break_Control,
- CR_Grapheme_Cluster_Break_Extend,
- CR_Grapheme_Cluster_Break_Regional_Indicator,
- CR_Grapheme_Cluster_Break_SpacingMark,
- CR_Grapheme_Cluster_Break_L,
- CR_Grapheme_Cluster_Break_V,
- CR_Grapheme_Cluster_Break_T,
- CR_Grapheme_Cluster_Break_LV,
- CR_Grapheme_Cluster_Break_LVT,
- CR_Grapheme_Cluster_Break_ZWJ,
- CR_In_Basic_Latin,
- CR_In_Latin_1_Supplement,
- CR_In_Latin_Extended_A,
- CR_In_Latin_Extended_B,
- CR_In_IPA_Extensions,
- CR_In_Spacing_Modifier_Letters,
- CR_In_Combining_Diacritical_Marks,
- CR_In_Greek_and_Coptic,
- CR_In_Cyrillic,
- CR_In_Cyrillic_Supplement,
- CR_In_Armenian,
- CR_In_Hebrew,
- CR_In_Arabic,
- CR_In_Syriac,
- CR_In_Arabic_Supplement,
- CR_In_Thaana,
- CR_In_NKo,
- CR_In_Samaritan,
- CR_In_Mandaic,
- CR_In_Syriac_Supplement,
- CR_In_Arabic_Extended_B,
- CR_In_Arabic_Extended_A,
- CR_In_Devanagari,
- CR_In_Bengali,
- CR_In_Gurmukhi,
- CR_In_Gujarati,
- CR_In_Oriya,
- CR_In_Tamil,
- CR_In_Telugu,
- CR_In_Kannada,
- CR_In_Malayalam,
- CR_In_Sinhala,
- CR_In_Thai,
- CR_In_Lao,
- CR_In_Tibetan,
- CR_In_Myanmar,
- CR_In_Georgian,
- CR_In_Hangul_Jamo,
- CR_In_Ethiopic,
- CR_In_Ethiopic_Supplement,
- CR_In_Cherokee,
- CR_In_Unified_Canadian_Aboriginal_Syllabics,
- CR_In_Ogham,
- CR_In_Runic,
- CR_In_Tagalog,
- CR_In_Hanunoo,
- CR_In_Buhid,
- CR_In_Tagbanwa,
- CR_In_Khmer,
- CR_In_Mongolian,
- CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended,
- CR_In_Limbu,
- CR_In_Tai_Le,
- CR_In_New_Tai_Lue,
- CR_In_Khmer_Symbols,
- CR_In_Buginese,
- CR_In_Tai_Tham,
- CR_In_Combining_Diacritical_Marks_Extended,
- CR_In_Balinese,
- CR_In_Sundanese,
- CR_In_Batak,
- CR_In_Lepcha,
- CR_In_Ol_Chiki,
- CR_In_Cyrillic_Extended_C,
- CR_In_Georgian_Extended,
- CR_In_Sundanese_Supplement,
- CR_In_Vedic_Extensions,
- CR_In_Phonetic_Extensions,
- CR_In_Phonetic_Extensions_Supplement,
- CR_In_Combining_Diacritical_Marks_Supplement,
- CR_In_Latin_Extended_Additional,
- CR_In_Greek_Extended,
- CR_In_General_Punctuation,
- CR_In_Superscripts_and_Subscripts,
- CR_In_Currency_Symbols,
- CR_In_Combining_Diacritical_Marks_for_Symbols,
- CR_In_Letterlike_Symbols,
- CR_In_Number_Forms,
- CR_In_Arrows,
- CR_In_Mathematical_Operators,
- CR_In_Miscellaneous_Technical,
- CR_In_Control_Pictures,
- CR_In_Optical_Character_Recognition,
- CR_In_Enclosed_Alphanumerics,
- CR_In_Box_Drawing,
- CR_In_Block_Elements,
- CR_In_Geometric_Shapes,
- CR_In_Miscellaneous_Symbols,
- CR_In_Dingbats,
- CR_In_Miscellaneous_Mathematical_Symbols_A,
- CR_In_Supplemental_Arrows_A,
- CR_In_Braille_Patterns,
- CR_In_Supplemental_Arrows_B,
- CR_In_Miscellaneous_Mathematical_Symbols_B,
- CR_In_Supplemental_Mathematical_Operators,
- CR_In_Miscellaneous_Symbols_and_Arrows,
- CR_In_Glagolitic,
- CR_In_Latin_Extended_C,
- CR_In_Coptic,
- CR_In_Georgian_Supplement,
- CR_In_Tifinagh,
- CR_In_Ethiopic_Extended,
- CR_In_Cyrillic_Extended_A,
- CR_In_Supplemental_Punctuation,
- CR_In_CJK_Radicals_Supplement,
- CR_In_Kangxi_Radicals,
- CR_In_Ideographic_Description_Characters,
- CR_In_CJK_Symbols_and_Punctuation,
- CR_In_Hiragana,
- CR_In_Katakana,
- CR_In_Bopomofo,
- CR_In_Hangul_Compatibility_Jamo,
- CR_In_Kanbun,
- CR_In_Bopomofo_Extended,
- CR_In_CJK_Strokes,
- CR_In_Katakana_Phonetic_Extensions,
- CR_In_Enclosed_CJK_Letters_and_Months,
- CR_In_CJK_Compatibility,
- CR_In_CJK_Unified_Ideographs_Extension_A,
- CR_In_Yijing_Hexagram_Symbols,
- CR_In_CJK_Unified_Ideographs,
- CR_In_Yi_Syllables,
- CR_In_Yi_Radicals,
- CR_In_Lisu,
- CR_In_Vai,
- CR_In_Cyrillic_Extended_B,
- CR_In_Bamum,
- CR_In_Modifier_Tone_Letters,
- CR_In_Latin_Extended_D,
- CR_In_Syloti_Nagri,
- CR_In_Common_Indic_Number_Forms,
- CR_In_Phags_pa,
- CR_In_Saurashtra,
- CR_In_Devanagari_Extended,
- CR_In_Kayah_Li,
- CR_In_Rejang,
- CR_In_Hangul_Jamo_Extended_A,
- CR_In_Javanese,
- CR_In_Myanmar_Extended_B,
- CR_In_Cham,
- CR_In_Myanmar_Extended_A,
- CR_In_Tai_Viet,
- CR_In_Meetei_Mayek_Extensions,
- CR_In_Ethiopic_Extended_A,
- CR_In_Latin_Extended_E,
- CR_In_Cherokee_Supplement,
- CR_In_Meetei_Mayek,
- CR_In_Hangul_Syllables,
- CR_In_Hangul_Jamo_Extended_B,
- CR_In_High_Surrogates,
- CR_In_High_Private_Use_Surrogates,
- CR_In_Low_Surrogates,
- CR_In_Private_Use_Area,
- CR_In_CJK_Compatibility_Ideographs,
- CR_In_Alphabetic_Presentation_Forms,
- CR_In_Arabic_Presentation_Forms_A,
- CR_In_Variation_Selectors,
- CR_In_Vertical_Forms,
- CR_In_Combining_Half_Marks,
- CR_In_CJK_Compatibility_Forms,
- CR_In_Small_Form_Variants,
- CR_In_Arabic_Presentation_Forms_B,
- CR_In_Halfwidth_and_Fullwidth_Forms,
- CR_In_Specials,
- CR_In_Linear_B_Syllabary,
- CR_In_Linear_B_Ideograms,
- CR_In_Aegean_Numbers,
- CR_In_Ancient_Greek_Numbers,
- CR_In_Ancient_Symbols,
- CR_In_Phaistos_Disc,
- CR_In_Lycian,
- CR_In_Carian,
- CR_In_Coptic_Epact_Numbers,
- CR_In_Old_Italic,
- CR_In_Gothic,
- CR_In_Old_Permic,
- CR_In_Ugaritic,
- CR_In_Old_Persian,
- CR_In_Deseret,
- CR_In_Shavian,
- CR_In_Osmanya,
- CR_In_Osage,
- CR_In_Elbasan,
- CR_In_Caucasian_Albanian,
- CR_In_Vithkuqi,
- CR_In_Linear_A,
- CR_In_Latin_Extended_F,
- CR_In_Cypriot_Syllabary,
- CR_In_Imperial_Aramaic,
- CR_In_Palmyrene,
- CR_In_Nabataean,
- CR_In_Hatran,
- CR_In_Phoenician,
- CR_In_Lydian,
- CR_In_Meroitic_Hieroglyphs,
- CR_In_Meroitic_Cursive,
- CR_In_Kharoshthi,
- CR_In_Old_South_Arabian,
- CR_In_Old_North_Arabian,
- CR_In_Manichaean,
- CR_In_Avestan,
- CR_In_Inscriptional_Parthian,
- CR_In_Inscriptional_Pahlavi,
- CR_In_Psalter_Pahlavi,
- CR_In_Old_Turkic,
- CR_In_Old_Hungarian,
- CR_In_Hanifi_Rohingya,
- CR_In_Rumi_Numeral_Symbols,
- CR_In_Yezidi,
- CR_In_Arabic_Extended_C,
- CR_In_Old_Sogdian,
- CR_In_Sogdian,
- CR_In_Old_Uyghur,
- CR_In_Chorasmian,
- CR_In_Elymaic,
- CR_In_Brahmi,
- CR_In_Kaithi,
- CR_In_Sora_Sompeng,
- CR_In_Chakma,
- CR_In_Mahajani,
- CR_In_Sharada,
- CR_In_Sinhala_Archaic_Numbers,
- CR_In_Khojki,
- CR_In_Multani,
- CR_In_Khudawadi,
- CR_In_Grantha,
- CR_In_Newa,
- CR_In_Tirhuta,
- CR_In_Siddham,
- CR_In_Modi,
- CR_In_Mongolian_Supplement,
- CR_In_Takri,
- CR_In_Ahom,
- CR_In_Dogra,
- CR_In_Warang_Citi,
- CR_In_Dives_Akuru,
- CR_In_Nandinagari,
- CR_In_Zanabazar_Square,
- CR_In_Soyombo,
- CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A,
- CR_In_Pau_Cin_Hau,
- CR_In_Devanagari_Extended_A,
- CR_In_Bhaiksuki,
- CR_In_Marchen,
- CR_In_Masaram_Gondi,
- CR_In_Gunjala_Gondi,
- CR_In_Makasar,
- CR_In_Kawi,
- CR_In_Lisu_Supplement,
- CR_In_Tamil_Supplement,
- CR_In_Cuneiform,
- CR_In_Cuneiform_Numbers_and_Punctuation,
- CR_In_Early_Dynastic_Cuneiform,
- CR_In_Cypro_Minoan,
- CR_In_Egyptian_Hieroglyphs,
- CR_In_Egyptian_Hieroglyph_Format_Controls,
- CR_In_Anatolian_Hieroglyphs,
- CR_In_Bamum_Supplement,
- CR_In_Mro,
- CR_In_Tangsa,
- CR_In_Bassa_Vah,
- CR_In_Pahawh_Hmong,
- CR_In_Medefaidrin,
- CR_In_Miao,
- CR_In_Ideographic_Symbols_and_Punctuation,
- CR_In_Tangut,
- CR_In_Tangut_Components,
- CR_In_Khitan_Small_Script,
- CR_In_Tangut_Supplement,
- CR_In_Kana_Extended_B,
- CR_In_Kana_Supplement,
- CR_In_Kana_Extended_A,
- CR_In_Small_Kana_Extension,
- CR_In_Nushu,
- CR_In_Duployan,
- CR_In_Shorthand_Format_Controls,
- CR_In_Znamenny_Musical_Notation,
- CR_In_Byzantine_Musical_Symbols,
- CR_In_Musical_Symbols,
- CR_In_Ancient_Greek_Musical_Notation,
- CR_In_Kaktovik_Numerals,
- CR_In_Mayan_Numerals,
- CR_In_Tai_Xuan_Jing_Symbols,
- CR_In_Counting_Rod_Numerals,
- CR_In_Mathematical_Alphanumeric_Symbols,
- CR_In_Sutton_SignWriting,
- CR_In_Latin_Extended_G,
- CR_In_Glagolitic_Supplement,
- CR_In_Cyrillic_Extended_D,
- CR_In_Nyiakeng_Puachue_Hmong,
- CR_In_Toto,
- CR_In_Wancho,
- CR_In_Nag_Mundari,
- CR_In_Ethiopic_Extended_B,
- CR_In_Mende_Kikakui,
- CR_In_Adlam,
- CR_In_Indic_Siyaq_Numbers,
- CR_In_Ottoman_Siyaq_Numbers,
- CR_In_Arabic_Mathematical_Alphabetic_Symbols,
- CR_In_Mahjong_Tiles,
- CR_In_Domino_Tiles,
- CR_In_Playing_Cards,
- CR_In_Enclosed_Alphanumeric_Supplement,
- CR_In_Enclosed_Ideographic_Supplement,
- CR_In_Miscellaneous_Symbols_and_Pictographs,
- CR_In_Emoticons,
- CR_In_Ornamental_Dingbats,
- CR_In_Transport_and_Map_Symbols,
- CR_In_Alchemical_Symbols,
- CR_In_Geometric_Shapes_Extended,
- CR_In_Supplemental_Arrows_C,
- CR_In_Supplemental_Symbols_and_Pictographs,
- CR_In_Chess_Symbols,
- CR_In_Symbols_and_Pictographs_Extended_A,
- CR_In_Symbols_for_Legacy_Computing,
- CR_In_CJK_Unified_Ideographs_Extension_B,
- CR_In_CJK_Unified_Ideographs_Extension_C,
- CR_In_CJK_Unified_Ideographs_Extension_D,
- CR_In_CJK_Unified_Ideographs_Extension_E,
- CR_In_CJK_Unified_Ideographs_Extension_F,
- CR_In_CJK_Unified_Ideographs_Extension_I,
- CR_In_CJK_Compatibility_Ideographs_Supplement,
- CR_In_CJK_Unified_Ideographs_Extension_G,
- CR_In_CJK_Unified_Ideographs_Extension_H,
- CR_In_Tags,
- CR_In_Variation_Selectors_Supplement,
- CR_In_Supplementary_Private_Use_Area_A,
- CR_In_Supplementary_Private_Use_Area_B,
- CR_In_No_Block,
-#endif /* USE_UNICODE_PROPERTIES */
-};
-struct uniname2ctype_struct {
- short name;
- unsigned short ctype;
-};
-#define uniname2ctype_offset(str) offsetof(struct uniname2ctype_pool_t, uniname2ctype_pool_##str)
-
-static const struct uniname2ctype_struct *uniname2ctype_p(register const char *str, register size_t len);
-
-#ifndef USE_UNICODE_PROPERTIES
-#define TOTAL_KEYWORDS 15
-#define MIN_WORD_LENGTH 4
-#define MAX_WORD_LENGTH 11
-#define MIN_HASH_VALUE 6
-#define MAX_HASH_VALUE 20
-/* maximum key range = 15, duplicates = 0 */
-#else /* USE_UNICODE_PROPERTIES */
-#ifndef USE_UNICODE_AGE_PROPERTIES
-#define TOTAL_KEYWORDS 874
-#else /* USE_UNICODE_AGE_PROPERTIES */
-#define TOTAL_KEYWORDS 900
-#endif /* USE_UNICODE_AGE_PROPERTIES */
-#define MIN_WORD_LENGTH 1
-#define MAX_WORD_LENGTH 45
-#define MIN_HASH_VALUE 11
-#define MAX_HASH_VALUE 6262
-/* maximum key range = 6252, duplicates = 0 */
-#endif /* USE_UNICODE_PROPERTIES */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-uniname2ctype_hash (register const char *str, register size_t len)
-{
-#ifndef USE_UNICODE_PROPERTIES
- static const unsigned char asso_values[] =
-#else /* USE_UNICODE_PROPERTIES */
- static const unsigned short asso_values[] =
-#endif /* USE_UNICODE_PROPERTIES */
- {
-#ifndef USE_UNICODE_PROPERTIES
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 3, 12, 5,
- 4, 21, 21, 10, 21, 1, 21, 21, 11, 21,
- 2, 1, 1, 21, 1, 7, 4, 6, 21, 1,
- 4, 21, 21, 21, 21, 21, 21, 21
-#else /* USE_UNICODE_PROPERTIES */
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
-#ifndef USE_UNICODE_AGE_PROPERTIES
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
-#else /* USE_UNICODE_AGE_PROPERTIES */
- 6263, 6263, 6263, 6263, 6263, 6263, 7, 6263, 2, 1,
- 4, 17, 31, 11, 22, 9, 2, 1, 6263, 6263,
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- 6263, 3, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263, 6263,
- 6263, 6263, 6263, 6263, 6263, 6263, 6263, 1, 1373, 113,
- 437, 37, 1454, 772, 1164, 4, 1647, 9, 500, 88,
- 8, 18, 1443, 1275, 54, 203, 310, 619, 2080, 678,
- 576, 1502, 33, 1, 3, 6263, 6263, 6263, 6263, 6263
-#endif /* USE_UNICODE_PROPERTIES */
- };
-#ifndef USE_UNICODE_PROPERTIES
- return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
-#else /* USE_UNICODE_PROPERTIES */
- register unsigned int hval = (unsigned int)len;
-
- switch (hval)
- {
- default:
- hval += asso_values[(unsigned char)str[15]];
- /*FALLTHROUGH*/
- case 15:
- case 14:
- case 13:
- case 12:
- hval += asso_values[(unsigned char)str[11]];
- /*FALLTHROUGH*/
- case 11:
- case 10:
- case 9:
- case 8:
- case 7:
- case 6:
- hval += asso_values[(unsigned char)str[5]];
- /*FALLTHROUGH*/
- case 5:
- hval += asso_values[(unsigned char)str[4]];
- /*FALLTHROUGH*/
- case 4:
- case 3:
- hval += asso_values[(unsigned char)str[2]];
- /*FALLTHROUGH*/
- case 2:
- hval += asso_values[(unsigned char)str[1]];
- /*FALLTHROUGH*/
- case 1:
- hval += asso_values[(unsigned char)str[0]+2];
- break;
- }
- return hval + asso_values[(unsigned char)str[len - 1]];
-#endif /* USE_UNICODE_PROPERTIES */
-}
-
-struct uniname2ctype_pool_t
- {
-#ifndef USE_UNICODE_PROPERTIES
- char uniname2ctype_pool_str6[sizeof("word")];
- char uniname2ctype_pool_str7[sizeof("print")];
- char uniname2ctype_pool_str8[sizeof("punct")];
- char uniname2ctype_pool_str9[sizeof("alpha")];
- char uniname2ctype_pool_str10[sizeof("alnum")];
- char uniname2ctype_pool_str11[sizeof("xdigit")];
- char uniname2ctype_pool_str12[sizeof("upper")];
- char uniname2ctype_pool_str13[sizeof("ascii")];
- char uniname2ctype_pool_str14[sizeof("cntrl")];
- char uniname2ctype_pool_str15[sizeof("space")];
- char uniname2ctype_pool_str16[sizeof("xposixpunct")];
- char uniname2ctype_pool_str17[sizeof("lower")];
- char uniname2ctype_pool_str18[sizeof("graph")];
- char uniname2ctype_pool_str19[sizeof("digit")];
- char uniname2ctype_pool_str20[sizeof("blank")];
-#else /* USE_UNICODE_PROPERTIES */
- char uniname2ctype_pool_str11[sizeof("yi")];
- char uniname2ctype_pool_str17[sizeof("yiii")];
- char uniname2ctype_pool_str22[sizeof("lana")];
- char uniname2ctype_pool_str25[sizeof("lina")];
- char uniname2ctype_pool_str33[sizeof("maka")];
- char uniname2ctype_pool_str35[sizeof("mani")];
- char uniname2ctype_pool_str36[sizeof("mn")];
- char uniname2ctype_pool_str37[sizeof("z")];
- char uniname2ctype_pool_str45[sizeof("miao")];
- char uniname2ctype_pool_str46[sizeof("lo")];
- char uniname2ctype_pool_str47[sizeof("ci")];
- char uniname2ctype_pool_str48[sizeof("lao")];
- char uniname2ctype_pool_str49[sizeof("laoo")];
- char uniname2ctype_pool_str52[sizeof("inkannada")];
- char uniname2ctype_pool_str55[sizeof("cn")];
- char uniname2ctype_pool_str64[sizeof("pi")];
- char uniname2ctype_pool_str66[sizeof("innko")];
- char uniname2ctype_pool_str71[sizeof("gran")];
- char uniname2ctype_pool_str75[sizeof("co")];
- char uniname2ctype_pool_str79[sizeof("yezi")];
- char uniname2ctype_pool_str83[sizeof("lineara")];
- char uniname2ctype_pool_str86[sizeof("mark")];
- char uniname2ctype_pool_str92[sizeof("po")];
- char uniname2ctype_pool_str94[sizeof("me")];
- char uniname2ctype_pool_str100[sizeof("cari")];
- char uniname2ctype_pool_str101[sizeof("inkharoshthi")];
- char uniname2ctype_pool_str102[sizeof("kana")];
- char uniname2ctype_pool_str103[sizeof("loe")];
- char uniname2ctype_pool_str106[sizeof("zzzz")];
- char uniname2ctype_pool_str107[sizeof("m")];
- char uniname2ctype_pool_str108[sizeof("grek")];
- char uniname2ctype_pool_str111[sizeof("mro")];
- char uniname2ctype_pool_str112[sizeof("mroo")];
- char uniname2ctype_pool_str115[sizeof("carian")];
- char uniname2ctype_pool_str117[sizeof("geor")];
- char uniname2ctype_pool_str118[sizeof("greek")];
- char uniname2ctype_pool_str122[sizeof("gonm")];
- char uniname2ctype_pool_str129[sizeof("mendekikakui")];
- char uniname2ctype_pool_str130[sizeof("pe")];
- char uniname2ctype_pool_str131[sizeof("mero")];
- char uniname2ctype_pool_str134[sizeof("inosmanya")];
- char uniname2ctype_pool_str139[sizeof("cakm")];
- char uniname2ctype_pool_str145[sizeof("inmanichaean")];
- char uniname2ctype_pool_str146[sizeof("inmro")];
- char uniname2ctype_pool_str148[sizeof("inmiao")];
- char uniname2ctype_pool_str149[sizeof("inchakma")];
- char uniname2ctype_pool_str151[sizeof("c")];
- char uniname2ctype_pool_str152[sizeof("mandaic")];
- char uniname2ctype_pool_str153[sizeof("meeteimayek")];
- char uniname2ctype_pool_str161[sizeof("inarmenian")];
- char uniname2ctype_pool_str177[sizeof("inmyanmar")];
- char uniname2ctype_pool_str178[sizeof("inmakasar")];
- char uniname2ctype_pool_str183[sizeof("common")];
- char uniname2ctype_pool_str186[sizeof("lm")];
- char uniname2ctype_pool_str190[sizeof("marc")];
- char uniname2ctype_pool_str203[sizeof("inrunic")];
- char uniname2ctype_pool_str204[sizeof("incarian")];
- char uniname2ctype_pool_str210[sizeof("inideographicsymbolsandpunctuation")];
- char uniname2ctype_pool_str212[sizeof("inkhmer")];
- char uniname2ctype_pool_str213[sizeof("qaai")];
- char uniname2ctype_pool_str218[sizeof("inahom")];
- char uniname2ctype_pool_str226[sizeof("merc")];
- char uniname2ctype_pool_str230[sizeof("inchorasmian")];
- char uniname2ctype_pool_str231[sizeof("combiningmark")];
- char uniname2ctype_pool_str236[sizeof("lc")];
- char uniname2ctype_pool_str237[sizeof("perm")];
- char uniname2ctype_pool_str246[sizeof("mc")];
- char uniname2ctype_pool_str250[sizeof("connectorpunctuation")];
- char uniname2ctype_pool_str253[sizeof("cans")];
- char uniname2ctype_pool_str260[sizeof("incuneiformnumbersandpunctuation")];
- char uniname2ctype_pool_str263[sizeof("armi")];
- char uniname2ctype_pool_str265[sizeof("cc")];
- char uniname2ctype_pool_str267[sizeof("armn")];
- char uniname2ctype_pool_str268[sizeof("incherokee")];
- char uniname2ctype_pool_str270[sizeof("prependedconcatenationmark")];
- char uniname2ctype_pool_str274[sizeof("incuneiform")];
- char uniname2ctype_pool_str275[sizeof("inavestan")];
- char uniname2ctype_pool_str281[sizeof("inipaextensions")];
- char uniname2ctype_pool_str282[sizeof("pc")];
- char uniname2ctype_pool_str283[sizeof("armenian")];
- char uniname2ctype_pool_str285[sizeof("insharada")];
- char uniname2ctype_pool_str289[sizeof("inmarchen")];
- char uniname2ctype_pool_str293[sizeof("makasar")];
- char uniname2ctype_pool_str297[sizeof("masaramgondi")];
- char uniname2ctype_pool_str301[sizeof("inarrows")];
- char uniname2ctype_pool_str311[sizeof("incyrillic")];
- char uniname2ctype_pool_str313[sizeof("incham")];
- char uniname2ctype_pool_str315[sizeof("qmark")];
- char uniname2ctype_pool_str320[sizeof("ri")];
- char uniname2ctype_pool_str322[sizeof("qaac")];
- char uniname2ctype_pool_str328[sizeof("insamaritan")];
- char uniname2ctype_pool_str331[sizeof("latn")];
- char uniname2ctype_pool_str335[sizeof("inmasaramgondi")];
- char uniname2ctype_pool_str338[sizeof("inthaana")];
- char uniname2ctype_pool_str340[sizeof("latin")];
- char uniname2ctype_pool_str342[sizeof("inthai")];
- char uniname2ctype_pool_str345[sizeof("lineseparator")];
- char uniname2ctype_pool_str346[sizeof("pcm")];
- char uniname2ctype_pool_str348[sizeof("inkatakana")];
- char uniname2ctype_pool_str352[sizeof("inkaithi")];
- char uniname2ctype_pool_str362[sizeof("inscriptionalparthian")];
- char uniname2ctype_pool_str366[sizeof("initialpunctuation")];
- char uniname2ctype_pool_str370[sizeof("inzanabazarsquare")];
- char uniname2ctype_pool_str373[sizeof("mtei")];
- char uniname2ctype_pool_str386[sizeof("inkhmersymbols")];
- char uniname2ctype_pool_str399[sizeof("insyriac")];
- char uniname2ctype_pool_str401[sizeof("intakri")];
- char uniname2ctype_pool_str404[sizeof("arabic")];
- char uniname2ctype_pool_str411[sizeof("zs")];
- char uniname2ctype_pool_str418[sizeof("katakana")];
- char uniname2ctype_pool_str426[sizeof("prti")];
- char uniname2ctype_pool_str442[sizeof("ascii")];
- char uniname2ctype_pool_str445[sizeof("cs")];
- char uniname2ctype_pool_str462[sizeof("ps")];
- char uniname2ctype_pool_str468[sizeof("mand")];
- char uniname2ctype_pool_str470[sizeof("privateuse")];
- char uniname2ctype_pool_str475[sizeof("inruminumeralsymbols")];
- char uniname2ctype_pool_str480[sizeof("inmyanmarextendeda")];
- char uniname2ctype_pool_str481[sizeof("modi")];
- char uniname2ctype_pool_str486[sizeof("incjkcompatibilityforms")];
- char uniname2ctype_pool_str488[sizeof("inkanaextendeda")];
- char uniname2ctype_pool_str491[sizeof("incjkcompatibilityideographs")];
- char uniname2ctype_pool_str500[sizeof("brai")];
- char uniname2ctype_pool_str504[sizeof("mend")];
- char uniname2ctype_pool_str505[sizeof("ideo")];
- char uniname2ctype_pool_str506[sizeof("letter")];
- char uniname2ctype_pool_str509[sizeof("l")];
- char uniname2ctype_pool_str511[sizeof("inmeeteimayek")];
- char uniname2ctype_pool_str520[sizeof("inideographicdescriptioncharacters")];
- char uniname2ctype_pool_str522[sizeof("yezidi")];
- char uniname2ctype_pool_str538[sizeof("knda")];
- char uniname2ctype_pool_str541[sizeof("innandinagari")];
- char uniname2ctype_pool_str543[sizeof("kannada")];
- char uniname2ctype_pool_str548[sizeof("xidcontinue")];
- char uniname2ctype_pool_str556[sizeof("inmodi")];
- char uniname2ctype_pool_str558[sizeof("inlao")];
- char uniname2ctype_pool_str560[sizeof("inoldnortharabian")];
- char uniname2ctype_pool_str565[sizeof("intransportandmapsymbols")];
- char uniname2ctype_pool_str566[sizeof("letternumber")];
- char uniname2ctype_pool_str568[sizeof("gothic")];
- char uniname2ctype_pool_str571[sizeof("incb=consonant")];
- char uniname2ctype_pool_str572[sizeof("inlineara")];
- char uniname2ctype_pool_str577[sizeof("inmendekikakui")];
- char uniname2ctype_pool_str579[sizeof("mongolian")];
- char uniname2ctype_pool_str582[sizeof("inmiscellaneousmathematicalsymbolsa")];
- char uniname2ctype_pool_str583[sizeof("inspecials")];
- char uniname2ctype_pool_str588[sizeof("vai")];
- char uniname2ctype_pool_str589[sizeof("vaii")];
- char uniname2ctype_pool_str590[sizeof("grlink")];
- char uniname2ctype_pool_str591[sizeof("xidc")];
- char uniname2ctype_pool_str594[sizeof("brahmi")];
- char uniname2ctype_pool_str596[sizeof("inemoticons")];
- char uniname2ctype_pool_str597[sizeof("kali")];
- char uniname2ctype_pool_str600[sizeof("inolditalic")];
- char uniname2ctype_pool_str604[sizeof("inmedefaidrin")];
- char uniname2ctype_pool_str605[sizeof("inchesssymbols")];
- char uniname2ctype_pool_str608[sizeof("incjkcompatibilityideographssupplement")];
- char uniname2ctype_pool_str609[sizeof("kits")];
- char uniname2ctype_pool_str614[sizeof("inadlam")];
- char uniname2ctype_pool_str618[sizeof("incb=extend")];
- char uniname2ctype_pool_str624[sizeof("psalterpahlavi")];
- char uniname2ctype_pool_str625[sizeof("incommonindicnumberforms")];
- char uniname2ctype_pool_str630[sizeof("lt")];
- char uniname2ctype_pool_str639[sizeof("sk")];
- char uniname2ctype_pool_str642[sizeof("control")];
- char uniname2ctype_pool_str645[sizeof("inancientsymbols")];
- char uniname2ctype_pool_str647[sizeof("palm")];
- char uniname2ctype_pool_str650[sizeof("inlycian")];
- char uniname2ctype_pool_str657[sizeof("so")];
- char uniname2ctype_pool_str660[sizeof("patternwhitespace")];
- char uniname2ctype_pool_str672[sizeof("inmandaic")];
- char uniname2ctype_pool_str675[sizeof("idc")];
- char uniname2ctype_pool_str678[sizeof("meroiticcursive")];
- char uniname2ctype_pool_str679[sizeof("intoto")];
- char uniname2ctype_pool_str681[sizeof("xids")];
- char uniname2ctype_pool_str696[sizeof("sora")];
- char uniname2ctype_pool_str697[sizeof("inopticalcharacterrecognition")];
- char uniname2ctype_pool_str698[sizeof("incb=linker")];
- char uniname2ctype_pool_str703[sizeof("inoldsogdian")];
- char uniname2ctype_pool_str705[sizeof("inmalayalam")];
- char uniname2ctype_pool_str707[sizeof("bamum")];
- char uniname2ctype_pool_str708[sizeof("inkanasupplement")];
- char uniname2ctype_pool_str711[sizeof("innewa")];
- char uniname2ctype_pool_str713[sizeof("insundanese")];
- char uniname2ctype_pool_str718[sizeof("inkawi")];
- char uniname2ctype_pool_str720[sizeof("grext")];
- char uniname2ctype_pool_str737[sizeof("print")];
- char uniname2ctype_pool_str738[sizeof("intaitham")];
- char uniname2ctype_pool_str753[sizeof("joinc")];
- char uniname2ctype_pool_str755[sizeof("inoldsoutharabian")];
- char uniname2ctype_pool_str760[sizeof("incjkstrokes")];
- char uniname2ctype_pool_str761[sizeof("batk")];
- char uniname2ctype_pool_str766[sizeof("samr")];
- char uniname2ctype_pool_str770[sizeof("inwarangciti")];
- char uniname2ctype_pool_str771[sizeof("batak")];
- char uniname2ctype_pool_str775[sizeof("kawi")];
- char uniname2ctype_pool_str776[sizeof("patws")];
- char uniname2ctype_pool_str783[sizeof("samaritan")];
- char uniname2ctype_pool_str787[sizeof("idsbinaryoperator")];
- char uniname2ctype_pool_str791[sizeof("pauc")];
- char uniname2ctype_pool_str792[sizeof("inznamennymusicalnotation")];
- char uniname2ctype_pool_str794[sizeof("insmallkanaextension")];
- char uniname2ctype_pool_str797[sizeof("sm")];
- char uniname2ctype_pool_str799[sizeof("indominotiles")];
- char uniname2ctype_pool_str802[sizeof("alnum")];
- char uniname2ctype_pool_str806[sizeof("gong")];
- char uniname2ctype_pool_str808[sizeof("ingrantha")];
- char uniname2ctype_pool_str809[sizeof("insylotinagri")];
- char uniname2ctype_pool_str814[sizeof("inugaritic")];
- char uniname2ctype_pool_str817[sizeof("lower")];
- char uniname2ctype_pool_str818[sizeof("incontrolpictures")];
- char uniname2ctype_pool_str820[sizeof("mong")];
- char uniname2ctype_pool_str821[sizeof("inlinearbideograms")];
- char uniname2ctype_pool_str822[sizeof("inmusicalsymbols")];
- char uniname2ctype_pool_str823[sizeof("s")];
- char uniname2ctype_pool_str824[sizeof("ital")];
- char uniname2ctype_pool_str825[sizeof("inmodifiertoneletters")];
- char uniname2ctype_pool_str828[sizeof("inancientgreekmusicalnotation")];
- char uniname2ctype_pool_str836[sizeof("idsunaryoperator")];
- char uniname2ctype_pool_str838[sizeof("lisu")];
- char uniname2ctype_pool_str842[sizeof("inwancho")];
- char uniname2ctype_pool_str847[sizeof("sc")];
- char uniname2ctype_pool_str848[sizeof("bass")];
- char uniname2ctype_pool_str851[sizeof("georgian")];
- char uniname2ctype_pool_str852[sizeof("inosage")];
- char uniname2ctype_pool_str855[sizeof("ids")];
- char uniname2ctype_pool_str857[sizeof("inlatinextendeda")];
- char uniname2ctype_pool_str871[sizeof("ingeneralpunctuation")];
- char uniname2ctype_pool_str875[sizeof("intaile")];
- char uniname2ctype_pool_str879[sizeof("ingeorgian")];
- char uniname2ctype_pool_str886[sizeof("inmiscellaneoussymbols")];
- char uniname2ctype_pool_str891[sizeof("emoji")];
- char uniname2ctype_pool_str895[sizeof("inmiscellaneoussymbolsandarrows")];
- char uniname2ctype_pool_str898[sizeof("incaucasianalbanian")];
- char uniname2ctype_pool_str900[sizeof("inmiscellaneoussymbolsandpictographs")];
- char uniname2ctype_pool_str904[sizeof("inmongolian")];
- char uniname2ctype_pool_str905[sizeof("innagmundari")];
- char uniname2ctype_pool_str906[sizeof("inoldturkic")];
- char uniname2ctype_pool_str907[sizeof("insaurashtra")];
- char uniname2ctype_pool_str917[sizeof("lowercase")];
- char uniname2ctype_pool_str920[sizeof("cwcm")];
- char uniname2ctype_pool_str924[sizeof("idcontinue")];
- char uniname2ctype_pool_str926[sizeof("intamil")];
- char uniname2ctype_pool_str928[sizeof("inmultani")];
- char uniname2ctype_pool_str929[sizeof("inlatinextendede")];
- char uniname2ctype_pool_str930[sizeof("pd")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str934[sizeof("age=11.0")];
- char uniname2ctype_pool_str935[sizeof("age=10.0")];
- char uniname2ctype_pool_str936[sizeof("age=12.1")];
- char uniname2ctype_pool_str937[sizeof("age=12.0")];
- char uniname2ctype_pool_str938[sizeof("age=1.1")];
- char uniname2ctype_pool_str939[sizeof("age=9.0")];
- char uniname2ctype_pool_str940[sizeof("age=8.0")];
- char uniname2ctype_pool_str941[sizeof("age=2.1")];
- char uniname2ctype_pool_str942[sizeof("age=2.0")];
- char uniname2ctype_pool_str943[sizeof("age=15.1")];
- char uniname2ctype_pool_str944[sizeof("age=15.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str945[sizeof("ingurmukhi")];
- char uniname2ctype_pool_str946[sizeof("bali")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str947[sizeof("age=7.0")];
- char uniname2ctype_pool_str948[sizeof("age=5.1")];
- char uniname2ctype_pool_str949[sizeof("age=5.0")];
- char uniname2ctype_pool_str950[sizeof("age=13.0")];
- char uniname2ctype_pool_str951[sizeof("age=5.2")];
- char uniname2ctype_pool_str954[sizeof("age=3.1")];
- char uniname2ctype_pool_str955[sizeof("age=3.0")];
- char uniname2ctype_pool_str957[sizeof("age=3.2")];
- char uniname2ctype_pool_str959[sizeof("age=6.1")];
- char uniname2ctype_pool_str960[sizeof("age=6.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str961[sizeof("blank")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str962[sizeof("age=6.2")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str963[sizeof("idst")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str964[sizeof("age=14.0")];
- char uniname2ctype_pool_str968[sizeof("age=4.1")];
- char uniname2ctype_pool_str969[sizeof("age=4.0")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str974[sizeof("inlydian")];
-#ifdef USE_UNICODE_AGE_PROPERTIES
- char uniname2ctype_pool_str975[sizeof("age=6.3")];
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- char uniname2ctype_pool_str984[sizeof("vs")];
- char uniname2ctype_pool_str994[sizeof("bengali")];
- char uniname2ctype_pool_str995[sizeof("runr")];
- char uniname2ctype_pool_str1005[sizeof("zl")];
- char uniname2ctype_pool_str1010[sizeof("ll")];
- char uniname2ctype_pool_str1013[sizeof("indeseret")];
- char uniname2ctype_pool_str1015[sizeof("inancientgreeknumbers")];
- char uniname2ctype_pool_str1021[sizeof("idstart")];
- char uniname2ctype_pool_str1025[sizeof("inmeeteimayekextensions")];
- char uniname2ctype_pool_str1028[sizeof("balinese")];
- char uniname2ctype_pool_str1032[sizeof("logicalorderexception")];
- char uniname2ctype_pool_str1035[sizeof("inspacingmodifierletters")];
- char uniname2ctype_pool_str1036[sizeof("inearlydynasticcuneiform")];
- char uniname2ctype_pool_str1046[sizeof("patternsyntax")];
- char uniname2ctype_pool_str1049[sizeof("plrd")];
- char uniname2ctype_pool_str1061[sizeof("innewtailue")];
- char uniname2ctype_pool_str1067[sizeof("canadianaboriginal")];
- char uniname2ctype_pool_str1068[sizeof("insorasompeng")];
- char uniname2ctype_pool_str1072[sizeof("sind")];
- char uniname2ctype_pool_str1074[sizeof("emojimodifier")];
- char uniname2ctype_pool_str1081[sizeof("inlatinextendedc")];
- char uniname2ctype_pool_str1087[sizeof("incountingrodnumerals")];
- char uniname2ctype_pool_str1097[sizeof("inkhudawadi")];
- char uniname2ctype_pool_str1103[sizeof("xidstart")];
- char uniname2ctype_pool_str1104[sizeof("xdigit")];
- char uniname2ctype_pool_str1109[sizeof("bidic")];
- char uniname2ctype_pool_str1116[sizeof("intangsa")];
- char uniname2ctype_pool_str1120[sizeof("cased")];
- char uniname2ctype_pool_str1123[sizeof("ingreekandcoptic")];
- char uniname2ctype_pool_str1140[sizeof("sinhala")];
- char uniname2ctype_pool_str1142[sizeof("adlm")];
- char uniname2ctype_pool_str1146[sizeof("glagolitic")];
- char uniname2ctype_pool_str1147[sizeof("sterm")];
- char uniname2ctype_pool_str1149[sizeof("bamu")];
- char uniname2ctype_pool_str1152[sizeof("gunjalagondi")];
- char uniname2ctype_pool_str1156[sizeof("inolduyghur")];
- char uniname2ctype_pool_str1157[sizeof("multani")];
- char uniname2ctype_pool_str1160[sizeof("uideo")];
- char uniname2ctype_pool_str1164[sizeof("joincontrol")];
- char uniname2ctype_pool_str1168[sizeof("runic")];
- char uniname2ctype_pool_str1174[sizeof("incyrillicsupplement")];
- char uniname2ctype_pool_str1177[sizeof("inmeroitichieroglyphs")];
- char uniname2ctype_pool_str1183[sizeof("zinh")];
- char uniname2ctype_pool_str1186[sizeof("inkaktoviknumerals")];
- char uniname2ctype_pool_str1190[sizeof("enclosingmark")];
- char uniname2ctype_pool_str1191[sizeof("insiddham")];
- char uniname2ctype_pool_str1207[sizeof("incherokeesupplement")];
- char uniname2ctype_pool_str1215[sizeof("inhanifirohingya")];
- char uniname2ctype_pool_str1221[sizeof("incyrillicextendeda")];
- char uniname2ctype_pool_str1223[sizeof("inkhitansmallscript")];
- char uniname2ctype_pool_str1226[sizeof("intaixuanjingsymbols")];
- char uniname2ctype_pool_str1227[sizeof("quotationmark")];
- char uniname2ctype_pool_str1231[sizeof("adlam")];
- char uniname2ctype_pool_str1232[sizeof("inkangxiradicals")];
- char uniname2ctype_pool_str1238[sizeof("regionalindicator")];
- char uniname2ctype_pool_str1243[sizeof("casedletter")];
- char uniname2ctype_pool_str1246[sizeof("incjkunifiedideographsextensiona")];
- char uniname2ctype_pool_str1247[sizeof("inhiragana")];
- char uniname2ctype_pool_str1248[sizeof("lu")];
- char uniname2ctype_pool_str1249[sizeof("incjkunifiedideographsextensioni")];
- char uniname2ctype_pool_str1250[sizeof("lowercaseletter")];
- char uniname2ctype_pool_str1254[sizeof("intamilsupplement")];
- char uniname2ctype_pool_str1258[sizeof("beng")];
- char uniname2ctype_pool_str1264[sizeof("emojimodifierbase")];
- char uniname2ctype_pool_str1266[sizeof("phoenician")];
- char uniname2ctype_pool_str1271[sizeof("kaithi")];
- char uniname2ctype_pool_str1272[sizeof("idsu")];
- char uniname2ctype_pool_str1281[sizeof("glag")];
- char uniname2ctype_pool_str1282[sizeof("incjkunifiedideographsextensione")];
- char uniname2ctype_pool_str1284[sizeof("inmahajani")];
- char uniname2ctype_pool_str1288[sizeof("indogra")];
- char uniname2ctype_pool_str1289[sizeof("marchen")];
- char uniname2ctype_pool_str1290[sizeof("graphemelink")];
- char uniname2ctype_pool_str1292[sizeof("inmiscellaneoustechnical")];
- char uniname2ctype_pool_str1293[sizeof("khojki")];
- char uniname2ctype_pool_str1294[sizeof("cham")];
- char uniname2ctype_pool_str1295[sizeof("inogham")];
- char uniname2ctype_pool_str1296[sizeof("cher")];
- char uniname2ctype_pool_str1297[sizeof("saur")];
- char uniname2ctype_pool_str1298[sizeof("chakma")];
- char uniname2ctype_pool_str1300[sizeof("guru")];
- char uniname2ctype_pool_str1301[sizeof("sundanese")];
- char uniname2ctype_pool_str1306[sizeof("punct")];
- char uniname2ctype_pool_str1310[sizeof("cherokee")];
- char uniname2ctype_pool_str1311[sizeof("khar")];
- char uniname2ctype_pool_str1314[sizeof("paucinhau")];
- char uniname2ctype_pool_str1317[sizeof("gurmukhi")];
- char uniname2ctype_pool_str1319[sizeof("emod")];
- char uniname2ctype_pool_str1322[sizeof("manichaean")];
- char uniname2ctype_pool_str1323[sizeof("ingreekextended")];
- char uniname2ctype_pool_str1325[sizeof("inolchiki")];
- char uniname2ctype_pool_str1333[sizeof("incyrillicextendedc")];
- char uniname2ctype_pool_str1338[sizeof("cwt")];
- char uniname2ctype_pool_str1340[sizeof("oriya")];
- char uniname2ctype_pool_str1341[sizeof("unassigned")];
- char uniname2ctype_pool_str1343[sizeof("limbu")];
- char uniname2ctype_pool_str1345[sizeof("inethiopic")];
- char uniname2ctype_pool_str1346[sizeof("graphemebase")];
- char uniname2ctype_pool_str1355[sizeof("ingeometricshapes")];
- char uniname2ctype_pool_str1356[sizeof("emojicomponent")];
- char uniname2ctype_pool_str1358[sizeof("incjkunifiedideographsextensionc")];
- char uniname2ctype_pool_str1360[sizeof("cntrl")];
- char uniname2ctype_pool_str1365[sizeof("inlatinextendedadditional")];
- char uniname2ctype_pool_str1369[sizeof("radical")];
- char uniname2ctype_pool_str1387[sizeof("ahom")];
- char uniname2ctype_pool_str1389[sizeof("zanb")];
- char uniname2ctype_pool_str1397[sizeof("linb")];
- char uniname2ctype_pool_str1398[sizeof("khmr")];
- char uniname2ctype_pool_str1400[sizeof("anatolianhieroglyphs")];
- char uniname2ctype_pool_str1401[sizeof("inenclosedalphanumerics")];
- char uniname2ctype_pool_str1402[sizeof("insinhala")];
- char uniname2ctype_pool_str1406[sizeof("unknown")];
- char uniname2ctype_pool_str1410[sizeof("inbhaiksuki")];
- char uniname2ctype_pool_str1418[sizeof("innabataean")];
- char uniname2ctype_pool_str1423[sizeof("inkanbun")];
- char uniname2ctype_pool_str1425[sizeof("intangut")];
- char uniname2ctype_pool_str1429[sizeof("sogdian")];
- char uniname2ctype_pool_str1431[sizeof("sogo")];
- char uniname2ctype_pool_str1433[sizeof("ideographic")];
- char uniname2ctype_pool_str1435[sizeof("xsux")];
- char uniname2ctype_pool_str1438[sizeof("incjkunifiedideographs")];
- char uniname2ctype_pool_str1441[sizeof("chorasmian")];
- char uniname2ctype_pool_str1445[sizeof("inelbasan")];
- char uniname2ctype_pool_str1446[sizeof("insogdian")];
- char uniname2ctype_pool_str1447[sizeof("indingbats")];
- char uniname2ctype_pool_str1451[sizeof("mult")];
- char uniname2ctype_pool_str1452[sizeof("n")];
- char uniname2ctype_pool_str1453[sizeof("khmer")];
- char uniname2ctype_pool_str1454[sizeof("saurashtra")];
- char uniname2ctype_pool_str1455[sizeof("linearb")];
- char uniname2ctype_pool_str1462[sizeof("chrs")];
- char uniname2ctype_pool_str1463[sizeof("dia")];
- char uniname2ctype_pool_str1464[sizeof("di")];
- char uniname2ctype_pool_str1467[sizeof("inscriptionalpahlavi")];
- char uniname2ctype_pool_str1472[sizeof("diak")];
- char uniname2ctype_pool_str1477[sizeof("limb")];
- char uniname2ctype_pool_str1479[sizeof("nandinagari")];
- char uniname2ctype_pool_str1481[sizeof("no")];
- char uniname2ctype_pool_str1488[sizeof("kharoshthi")];
- char uniname2ctype_pool_str1491[sizeof("nko")];
- char uniname2ctype_pool_str1492[sizeof("nkoo")];
- char uniname2ctype_pool_str1495[sizeof("sd")];
- char uniname2ctype_pool_str1497[sizeof("math")];
- char uniname2ctype_pool_str1498[sizeof("p")];
- char uniname2ctype_pool_str1499[sizeof("inenclosedideographicsupplement")];
- char uniname2ctype_pool_str1500[sizeof("goth")];
- char uniname2ctype_pool_str1501[sizeof("sidd")];
- char uniname2ctype_pool_str1509[sizeof("ugar")];
- char uniname2ctype_pool_str1511[sizeof("intags")];
- char uniname2ctype_pool_str1513[sizeof("inarabic")];
- char uniname2ctype_pool_str1517[sizeof("inenclosedalphanumericsupplement")];
- char uniname2ctype_pool_str1520[sizeof("bidicontrol")];
- char uniname2ctype_pool_str1530[sizeof("vithkuqi")];
- char uniname2ctype_pool_str1531[sizeof("variationselector")];
- char uniname2ctype_pool_str1535[sizeof("xpeo")];
- char uniname2ctype_pool_str1536[sizeof("braille")];
- char uniname2ctype_pool_str1539[sizeof("inornamentaldingbats")];
- char uniname2ctype_pool_str1541[sizeof("grantha")];
- char uniname2ctype_pool_str1542[sizeof("inkayahli")];
- char uniname2ctype_pool_str1543[sizeof("inphoenician")];
- char uniname2ctype_pool_str1545[sizeof("arab")];
- char uniname2ctype_pool_str1549[sizeof("inoriya")];
- char uniname2ctype_pool_str1555[sizeof("intirhuta")];
- char uniname2ctype_pool_str1558[sizeof("osage")];
- char uniname2ctype_pool_str1561[sizeof("inhatran")];
- char uniname2ctype_pool_str1562[sizeof("wara")];
- char uniname2ctype_pool_str1567[sizeof("caseignorable")];
- char uniname2ctype_pool_str1568[sizeof("inyezidi")];
- char uniname2ctype_pool_str1570[sizeof("kthi")];
- char uniname2ctype_pool_str1571[sizeof("osma")];
- char uniname2ctype_pool_str1580[sizeof("cpmn")];
- char uniname2ctype_pool_str1596[sizeof("inphaistosdisc")];
- char uniname2ctype_pool_str1597[sizeof("ingeometricshapesextended")];
- char uniname2ctype_pool_str1605[sizeof("lepc")];
- char uniname2ctype_pool_str1617[sizeof("inlowsurrogates")];
- char uniname2ctype_pool_str1623[sizeof("inarabicpresentationformsa")];
- char uniname2ctype_pool_str1625[sizeof("inbasiclatin")];
- char uniname2ctype_pool_str1629[sizeof("punctuation")];
- char uniname2ctype_pool_str1631[sizeof("lyci")];
- char uniname2ctype_pool_str1639[sizeof("diacritic")];
- char uniname2ctype_pool_str1646[sizeof("lycian")];
- char uniname2ctype_pool_str1649[sizeof("incyprominoan")];
- char uniname2ctype_pool_str1657[sizeof("incyrillicextendedd")];
- char uniname2ctype_pool_str1660[sizeof("brah")];
- char uniname2ctype_pool_str1662[sizeof("inoldhungarian")];
- char uniname2ctype_pool_str1664[sizeof("hani")];
- char uniname2ctype_pool_str1666[sizeof("mymr")];
- char uniname2ctype_pool_str1667[sizeof("han")];
- char uniname2ctype_pool_str1671[sizeof("myanmar")];
- char uniname2ctype_pool_str1678[sizeof("hano")];
- char uniname2ctype_pool_str1682[sizeof("incjkunifiedideographsextensiond")];
- char uniname2ctype_pool_str1685[sizeof("inherited")];
- char uniname2ctype_pool_str1687[sizeof("sund")];
- char uniname2ctype_pool_str1689[sizeof("inimperialaramaic")];
- char uniname2ctype_pool_str1695[sizeof("sorasompeng")];
- char uniname2ctype_pool_str1699[sizeof("insundanesesupplement")];
- char uniname2ctype_pool_str1703[sizeof("inkhojki")];
- char uniname2ctype_pool_str1707[sizeof("hanunoo")];
- char uniname2ctype_pool_str1710[sizeof("hira")];
- char uniname2ctype_pool_str1714[sizeof("grbase")];
- char uniname2ctype_pool_str1717[sizeof("inbatak")];
- char uniname2ctype_pool_str1718[sizeof("cwl")];
- char uniname2ctype_pool_str1723[sizeof("odi")];
- char uniname2ctype_pool_str1726[sizeof("phli")];
- char uniname2ctype_pool_str1729[sizeof("inlatinextendedd")];
- char uniname2ctype_pool_str1734[sizeof("coptic")];
- char uniname2ctype_pool_str1736[sizeof("inanatolianhieroglyphs")];
- char uniname2ctype_pool_str1744[sizeof("assigned")];
- char uniname2ctype_pool_str1748[sizeof("graphemeextend")];
- char uniname2ctype_pool_str1754[sizeof("intibetan")];
- char uniname2ctype_pool_str1766[sizeof("inelymaic")];
- char uniname2ctype_pool_str1767[sizeof("insoyombo")];
- char uniname2ctype_pool_str1776[sizeof("inblockelements")];
- char uniname2ctype_pool_str1780[sizeof("incjkcompatibility")];
- char uniname2ctype_pool_str1790[sizeof("innumberforms")];
- char uniname2ctype_pool_str1797[sizeof("decimalnumber")];
- char uniname2ctype_pool_str1799[sizeof("sinh")];
- char uniname2ctype_pool_str1800[sizeof("inglagolitic")];
- char uniname2ctype_pool_str1804[sizeof("shavian")];
- char uniname2ctype_pool_str1806[sizeof("phnx")];
- char uniname2ctype_pool_str1812[sizeof("copt")];
- char uniname2ctype_pool_str1813[sizeof("sentenceterminal")];
- char uniname2ctype_pool_str1814[sizeof("imperialaramaic")];
- char uniname2ctype_pool_str1817[sizeof("bhks")];
- char uniname2ctype_pool_str1824[sizeof("ininscriptionalpahlavi")];
- char uniname2ctype_pool_str1827[sizeof("bhaiksuki")];
- char uniname2ctype_pool_str1829[sizeof("ininscriptionalparthian")];
- char uniname2ctype_pool_str1833[sizeof("oidc")];
- char uniname2ctype_pool_str1835[sizeof("inhanunoo")];
- char uniname2ctype_pool_str1836[sizeof("bugi")];
- char uniname2ctype_pool_str1844[sizeof("insinhalaarchaicnumbers")];
- char uniname2ctype_pool_str1847[sizeof("ingeorgiansupplement")];
- char uniname2ctype_pool_str1848[sizeof("cprt")];
- char uniname2ctype_pool_str1850[sizeof("sogd")];
- char uniname2ctype_pool_str1852[sizeof("inmyanmarextendedb")];
- char uniname2ctype_pool_str1853[sizeof("inbyzantinemusicalsymbols")];
- char uniname2ctype_pool_str1860[sizeof("inkanaextendedb")];
- char uniname2ctype_pool_str1863[sizeof("format")];
- char uniname2ctype_pool_str1880[sizeof("inmayannumerals")];
- char uniname2ctype_pool_str1881[sizeof("intagalog")];
- char uniname2ctype_pool_str1884[sizeof("inarabicextendeda")];
- char uniname2ctype_pool_str1886[sizeof("ugaritic")];
- char uniname2ctype_pool_str1889[sizeof("patsyn")];
- char uniname2ctype_pool_str1893[sizeof("nand")];
- char uniname2ctype_pool_str1894[sizeof("ahex")];
- char uniname2ctype_pool_str1901[sizeof("olck")];
- char uniname2ctype_pool_str1912[sizeof("olchiki")];
- char uniname2ctype_pool_str1916[sizeof("innoblock")];
- char uniname2ctype_pool_str1918[sizeof("buginese")];
- char uniname2ctype_pool_str1919[sizeof("inmongoliansupplement")];
- char uniname2ctype_pool_str1920[sizeof("bopo")];
- char uniname2ctype_pool_str1923[sizeof("oids")];
- char uniname2ctype_pool_str1924[sizeof("asciihexdigit")];
- char uniname2ctype_pool_str1933[sizeof("inbraillepatterns")];
- char uniname2ctype_pool_str1941[sizeof("inbalinese")];
- char uniname2ctype_pool_str1943[sizeof("inoldpersian")];
- char uniname2ctype_pool_str1944[sizeof("olower")];
- char uniname2ctype_pool_str1949[sizeof("insuttonsignwriting")];
- char uniname2ctype_pool_str1950[sizeof("medf")];
- char uniname2ctype_pool_str1954[sizeof("inmiscellaneousmathematicalsymbolsb")];
- char uniname2ctype_pool_str1955[sizeof("lydi")];
- char uniname2ctype_pool_str1956[sizeof("cwu")];
- char uniname2ctype_pool_str1964[sizeof("inlisu")];
- char uniname2ctype_pool_str1966[sizeof("medefaidrin")];
- char uniname2ctype_pool_str1970[sizeof("lydian")];
- char uniname2ctype_pool_str1971[sizeof("ext")];
- char uniname2ctype_pool_str1975[sizeof("inshorthandformatcontrols")];
- char uniname2ctype_pool_str1981[sizeof("hatran")];
- char uniname2ctype_pool_str1992[sizeof("inyiradicals")];
- char uniname2ctype_pool_str1995[sizeof("phag")];
- char uniname2ctype_pool_str1996[sizeof("inarabicextendedc")];
- char uniname2ctype_pool_str2004[sizeof("incoptic")];
- char uniname2ctype_pool_str2009[sizeof("inhanguljamo")];
- char uniname2ctype_pool_str2012[sizeof("inlisusupplement")];
- char uniname2ctype_pool_str2015[sizeof("word")];
- char uniname2ctype_pool_str2016[sizeof("hatr")];
- char uniname2ctype_pool_str2017[sizeof("incjkunifiedideographsextensiong")];
- char uniname2ctype_pool_str2018[sizeof("innushu")];
- char uniname2ctype_pool_str2022[sizeof("incjksymbolsandpunctuation")];
- char uniname2ctype_pool_str2025[sizeof("dsrt")];
- char uniname2ctype_pool_str2026[sizeof("idsb")];
- char uniname2ctype_pool_str2030[sizeof("bopomofo")];
- char uniname2ctype_pool_str2038[sizeof("inhanguljamoextendeda")];
- char uniname2ctype_pool_str2039[sizeof("inoldpermic")];
- char uniname2ctype_pool_str2042[sizeof("inkatakanaphoneticextensions")];
- char uniname2ctype_pool_str2051[sizeof("sarb")];
- char uniname2ctype_pool_str2057[sizeof("zanabazarsquare")];
- char uniname2ctype_pool_str2058[sizeof("vith")];
- char uniname2ctype_pool_str2062[sizeof("innyiakengpuachuehmong")];
- char uniname2ctype_pool_str2063[sizeof("alpha")];
- char uniname2ctype_pool_str2068[sizeof("closepunctuation")];
- char uniname2ctype_pool_str2073[sizeof("intelugu")];
- char uniname2ctype_pool_str2081[sizeof("sgnw")];
- char uniname2ctype_pool_str2082[sizeof("inlepcha")];
- char uniname2ctype_pool_str2086[sizeof("insyriacsupplement")];
- char uniname2ctype_pool_str2092[sizeof("extpict")];
- char uniname2ctype_pool_str2095[sizeof("spacingmark")];
- char uniname2ctype_pool_str2096[sizeof("inpalmyrene")];
- char uniname2ctype_pool_str2097[sizeof("cyrl")];
- char uniname2ctype_pool_str2102[sizeof("deseret")];
- char uniname2ctype_pool_str2103[sizeof("takri")];
- char uniname2ctype_pool_str2110[sizeof("invai")];
- char uniname2ctype_pool_str2112[sizeof("mlym")];
- char uniname2ctype_pool_str2119[sizeof("malayalam")];
- char uniname2ctype_pool_str2128[sizeof("surrogate")];
- char uniname2ctype_pool_str2140[sizeof("ogam")];
- char uniname2ctype_pool_str2142[sizeof("space")];
- char uniname2ctype_pool_str2148[sizeof("takr")];
- char uniname2ctype_pool_str2149[sizeof("inunifiedcanadianaboriginalsyllabicsextendeda")];
- char uniname2ctype_pool_str2157[sizeof("palmyrene")];
- char uniname2ctype_pool_str2161[sizeof("soyo")];
- char uniname2ctype_pool_str2163[sizeof("newa")];
- char uniname2ctype_pool_str2164[sizeof("taile")];
- char uniname2ctype_pool_str2165[sizeof("extender")];
- char uniname2ctype_pool_str2183[sizeof("inbengali")];
- char uniname2ctype_pool_str2192[sizeof("inbamum")];
- char uniname2ctype_pool_str2201[sizeof("meroitichieroglyphs")];
- char uniname2ctype_pool_str2208[sizeof("inethiopicsupplement")];
- char uniname2ctype_pool_str2209[sizeof("newtailue")];
- char uniname2ctype_pool_str2213[sizeof("inbuginese")];
- char uniname2ctype_pool_str2217[sizeof("separator")];
- char uniname2ctype_pool_str2219[sizeof("cuneiform")];
- char uniname2ctype_pool_str2225[sizeof("ebase")];
- char uniname2ctype_pool_str2230[sizeof("sharada")];
- char uniname2ctype_pool_str2243[sizeof("inphagspa")];
- char uniname2ctype_pool_str2251[sizeof("dogra")];
- char uniname2ctype_pool_str2254[sizeof("ethi")];
- char uniname2ctype_pool_str2255[sizeof("inethiopicextendeda")];
- char uniname2ctype_pool_str2260[sizeof("caucasianalbanian")];
- char uniname2ctype_pool_str2263[sizeof("term")];
- char uniname2ctype_pool_str2268[sizeof("rohg")];
- char uniname2ctype_pool_str2278[sizeof("shrd")];
- char uniname2ctype_pool_str2286[sizeof("cwcf")];
- char uniname2ctype_pool_str2291[sizeof("osge")];
- char uniname2ctype_pool_str2292[sizeof("syrc")];
- char uniname2ctype_pool_str2296[sizeof("tnsa")];
- char uniname2ctype_pool_str2300[sizeof("tangsa")];
- char uniname2ctype_pool_str2301[sizeof("number")];
- char uniname2ctype_pool_str2302[sizeof("dogr")];
- char uniname2ctype_pool_str2307[sizeof("incopticepactnumbers")];
- char uniname2ctype_pool_str2308[sizeof("nagm")];
- char uniname2ctype_pool_str2309[sizeof("modifierletter")];
- char uniname2ctype_pool_str2312[sizeof("incombiningdiacriticalmarks")];
- char uniname2ctype_pool_str2318[sizeof("inshavian")];
- char uniname2ctype_pool_str2319[sizeof("nd")];
- char uniname2ctype_pool_str2320[sizeof("siddham")];
- char uniname2ctype_pool_str2321[sizeof("oldpersian")];
- char uniname2ctype_pool_str2322[sizeof("incombiningdiacriticalmarksforsymbols")];
- char uniname2ctype_pool_str2328[sizeof("gujr")];
- char uniname2ctype_pool_str2329[sizeof("ingeorgianextended")];
- char uniname2ctype_pool_str2337[sizeof("gujarati")];
- char uniname2ctype_pool_str2342[sizeof("inunifiedcanadianaboriginalsyllabics")];
- char uniname2ctype_pool_str2351[sizeof("warangciti")];
- char uniname2ctype_pool_str2384[sizeof("ingothic")];
- char uniname2ctype_pool_str2392[sizeof("graph")];
- char uniname2ctype_pool_str2395[sizeof("xposixpunct")];
- char uniname2ctype_pool_str2399[sizeof("inlatinextendedg")];
- char uniname2ctype_pool_str2408[sizeof("syriac")];
- char uniname2ctype_pool_str2409[sizeof("incjkunifiedideographsextensionh")];
- char uniname2ctype_pool_str2415[sizeof("induployan")];
- char uniname2ctype_pool_str2418[sizeof("inaegeannumbers")];
- char uniname2ctype_pool_str2425[sizeof("oldpermic")];
- char uniname2ctype_pool_str2428[sizeof("inmathematicalalphanumericsymbols")];
- char uniname2ctype_pool_str2429[sizeof("incombiningdiacriticalmarkssupplement")];
- char uniname2ctype_pool_str2430[sizeof("toto")];
- char uniname2ctype_pool_str2432[sizeof("hang")];
- char uniname2ctype_pool_str2443[sizeof("taiviet")];
- char uniname2ctype_pool_str2445[sizeof("nl")];
- char uniname2ctype_pool_str2451[sizeof("ingujarati")];
- char uniname2ctype_pool_str2460[sizeof("incurrencysymbols")];
- char uniname2ctype_pool_str2461[sizeof("insymbolsandpictographsextendeda")];
- char uniname2ctype_pool_str2466[sizeof("shaw")];
- char uniname2ctype_pool_str2469[sizeof("incjkradicalssupplement")];
- char uniname2ctype_pool_str2470[sizeof("ingunjalagondi")];
- char uniname2ctype_pool_str2483[sizeof("intagbanwa")];
- char uniname2ctype_pool_str2487[sizeof("hiragana")];
- char uniname2ctype_pool_str2488[sizeof("inphoneticextensions")];
- char uniname2ctype_pool_str2499[sizeof("inrejang")];
- char uniname2ctype_pool_str2506[sizeof("orkh")];
- char uniname2ctype_pool_str2519[sizeof("hmng")];
- char uniname2ctype_pool_str2532[sizeof("idstrinaryoperator")];
- char uniname2ctype_pool_str2535[sizeof("insymbolsforlegacycomputing")];
- char uniname2ctype_pool_str2544[sizeof("mathsymbol")];
- char uniname2ctype_pool_str2547[sizeof("extendedpictographic")];
- char uniname2ctype_pool_str2554[sizeof("incombiningdiacriticalmarksextended")];
- char uniname2ctype_pool_str2555[sizeof("indevanagari")];
- char uniname2ctype_pool_str2556[sizeof("avestan")];
- char uniname2ctype_pool_str2563[sizeof("khudawadi")];
- char uniname2ctype_pool_str2567[sizeof("inbrahmi")];
- char uniname2ctype_pool_str2583[sizeof("inlinearbsyllabary")];
- char uniname2ctype_pool_str2584[sizeof("inunifiedcanadianaboriginalsyllabicsextended")];
- char uniname2ctype_pool_str2586[sizeof("java")];
- char uniname2ctype_pool_str2593[sizeof("incyrillicextendedb")];
- char uniname2ctype_pool_str2598[sizeof("indevanagariextendeda")];
- char uniname2ctype_pool_str2604[sizeof("inlimbu")];
- char uniname2ctype_pool_str2605[sizeof("inphoneticextensionssupplement")];
- char uniname2ctype_pool_str2618[sizeof("incjkunifiedideographsextensionb")];
- char uniname2ctype_pool_str2622[sizeof("tale")];
- char uniname2ctype_pool_str2633[sizeof("terminalpunctuation")];
- char uniname2ctype_pool_str2639[sizeof("inlatin1supplement")];
- char uniname2ctype_pool_str2642[sizeof("currencysymbol")];
- char uniname2ctype_pool_str2643[sizeof("sylo")];
- char uniname2ctype_pool_str2645[sizeof("olditalic")];
- char uniname2ctype_pool_str2650[sizeof("elba")];
- char uniname2ctype_pool_str2660[sizeof("lepcha")];
- char uniname2ctype_pool_str2661[sizeof("buhd")];
- char uniname2ctype_pool_str2670[sizeof("changeswhencasemapped")];
- char uniname2ctype_pool_str2671[sizeof("javanese")];
- char uniname2ctype_pool_str2673[sizeof("taml")];
- char uniname2ctype_pool_str2678[sizeof("emojipresentation")];
- char uniname2ctype_pool_str2680[sizeof("epres")];
- char uniname2ctype_pool_str2681[sizeof("spaceseparator")];
- char uniname2ctype_pool_str2690[sizeof("inethiopicextended")];
- char uniname2ctype_pool_str2694[sizeof("invariationselectors")];
- char uniname2ctype_pool_str2697[sizeof("inverticalforms")];
- char uniname2ctype_pool_str2699[sizeof("incjkunifiedideographsextensionf")];
- char uniname2ctype_pool_str2708[sizeof("inottomansiyaqnumbers")];
- char uniname2ctype_pool_str2710[sizeof("avst")];
- char uniname2ctype_pool_str2714[sizeof("cyrillic")];
- char uniname2ctype_pool_str2717[sizeof("wancho")];
- char uniname2ctype_pool_str2718[sizeof("inhangulsyllables")];
- char uniname2ctype_pool_str2724[sizeof("ougr")];
- char uniname2ctype_pool_str2730[sizeof("intaiviet")];
- char uniname2ctype_pool_str2741[sizeof("rjng")];
- char uniname2ctype_pool_str2760[sizeof("paragraphseparator")];
- char uniname2ctype_pool_str2769[sizeof("inletterlikesymbols")];
- char uniname2ctype_pool_str2774[sizeof("invedicextensions")];
- char uniname2ctype_pool_str2779[sizeof("intangutcomponents")];
- char uniname2ctype_pool_str2801[sizeof("wcho")];
- char uniname2ctype_pool_str2811[sizeof("invariationselectorssupplement")];
- char uniname2ctype_pool_str2816[sizeof("changeswhentitlecased")];
- char uniname2ctype_pool_str2822[sizeof("inpaucinhau")];
- char uniname2ctype_pool_str2826[sizeof("dash")];
- char uniname2ctype_pool_str2833[sizeof("nchar")];
- char uniname2ctype_pool_str2834[sizeof("mahj")];
- char uniname2ctype_pool_str2836[sizeof("orya")];
- char uniname2ctype_pool_str2839[sizeof("hex")];
- char uniname2ctype_pool_str2843[sizeof("mahajani")];
- char uniname2ctype_pool_str2855[sizeof("digit")];
- char uniname2ctype_pool_str2856[sizeof("inenclosedcjklettersandmonths")];
- char uniname2ctype_pool_str2857[sizeof("nagmundari")];
- char uniname2ctype_pool_str2862[sizeof("other")];
- char uniname2ctype_pool_str2863[sizeof("otheridcontinue")];
- char uniname2ctype_pool_str2864[sizeof("elbasan")];
- char uniname2ctype_pool_str2865[sizeof("tang")];
- char uniname2ctype_pool_str2866[sizeof("elym")];
- char uniname2ctype_pool_str2867[sizeof("oldhungarian")];
- char uniname2ctype_pool_str2871[sizeof("tagbanwa")];
- char uniname2ctype_pool_str2873[sizeof("phagspa")];
- char uniname2ctype_pool_str2875[sizeof("narb")];
- char uniname2ctype_pool_str2876[sizeof("othernumber")];
- char uniname2ctype_pool_str2877[sizeof("graphemeclusterbreak=spacingmark")];
- char uniname2ctype_pool_str2879[sizeof("inbopomofo")];
- char uniname2ctype_pool_str2891[sizeof("zp")];
- char uniname2ctype_pool_str2899[sizeof("elymaic")];
- char uniname2ctype_pool_str2910[sizeof("signwriting")];
- char uniname2ctype_pool_str2913[sizeof("graphemeclusterbreak=cr")];
- char uniname2ctype_pool_str2915[sizeof("intangutsupplement")];
- char uniname2ctype_pool_str2921[sizeof("khoj")];
- char uniname2ctype_pool_str2923[sizeof("titlecaseletter")];
- char uniname2ctype_pool_str2928[sizeof("graphemeclusterbreak=regionalindicator")];
- char uniname2ctype_pool_str2930[sizeof("inmeroiticcursive")];
- char uniname2ctype_pool_str2932[sizeof("inbamumsupplement")];
- char uniname2ctype_pool_str2937[sizeof("nonspacingmark")];
- char uniname2ctype_pool_str2947[sizeof("cf")];
- char uniname2ctype_pool_str2948[sizeof("oalpha")];
- char uniname2ctype_pool_str2950[sizeof("sylotinagri")];
- char uniname2ctype_pool_str2957[sizeof("whitespace")];
- char uniname2ctype_pool_str2959[sizeof("intifinagh")];
- char uniname2ctype_pool_str2964[sizeof("pf")];
- char uniname2ctype_pool_str2969[sizeof("otheralphabetic")];
- char uniname2ctype_pool_str2970[sizeof("inbassavah")];
- char uniname2ctype_pool_str2993[sizeof("softdotted")];
- char uniname2ctype_pool_str2995[sizeof("inarabicpresentationformsb")];
- char uniname2ctype_pool_str3002[sizeof("inbuhid")];
- char uniname2ctype_pool_str3007[sizeof("oldturkic")];
- char uniname2ctype_pool_str3020[sizeof("oldsogdian")];
- char uniname2ctype_pool_str3023[sizeof("changeswhenlowercased")];
- char uniname2ctype_pool_str3024[sizeof("insmallformvariants")];
- char uniname2ctype_pool_str3033[sizeof("indevanagariextended")];
- char uniname2ctype_pool_str3050[sizeof("hung")];
- char uniname2ctype_pool_str3056[sizeof("noncharactercodepoint")];
- char uniname2ctype_pool_str3066[sizeof("incombininghalfmarks")];
- char uniname2ctype_pool_str3075[sizeof("tirhuta")];
- char uniname2ctype_pool_str3084[sizeof("osmanya")];
- char uniname2ctype_pool_str3099[sizeof("buhid")];
- char uniname2ctype_pool_str3106[sizeof("inarabicmathematicalalphabeticsymbols")];
- char uniname2ctype_pool_str3107[sizeof("cyprominoan")];
- char uniname2ctype_pool_str3115[sizeof("hebr")];
- char uniname2ctype_pool_str3128[sizeof("any")];
- char uniname2ctype_pool_str3131[sizeof("nbat")];
- char uniname2ctype_pool_str3142[sizeof("changeswhenuppercased")];
- char uniname2ctype_pool_str3145[sizeof("nabataean")];
- char uniname2ctype_pool_str3149[sizeof("inpsalterpahlavi")];
- char uniname2ctype_pool_str3152[sizeof("finalpunctuation")];
- char uniname2ctype_pool_str3165[sizeof("phlp")];
- char uniname2ctype_pool_str3168[sizeof("graphemeclusterbreak=t")];
- char uniname2ctype_pool_str3170[sizeof("graphemeclusterbreak=lvt")];
- char uniname2ctype_pool_str3173[sizeof("inalphabeticpresentationforms")];
- char uniname2ctype_pool_str3174[sizeof("tamil")];
- char uniname2ctype_pool_str3190[sizeof("hmnp")];
- char uniname2ctype_pool_str3200[sizeof("inarabicsupplement")];
- char uniname2ctype_pool_str3204[sizeof("talu")];
- char uniname2ctype_pool_str3233[sizeof("symbol")];
- char uniname2ctype_pool_str3234[sizeof("inplayingcards")];
- char uniname2ctype_pool_str3238[sizeof("khitansmallscript")];
- char uniname2ctype_pool_str3240[sizeof("telu")];
- char uniname2ctype_pool_str3250[sizeof("thaa")];
- char uniname2ctype_pool_str3253[sizeof("thai")];
- char uniname2ctype_pool_str3256[sizeof("inarabicextendedb")];
- char uniname2ctype_pool_str3261[sizeof("thaana")];
- char uniname2ctype_pool_str3266[sizeof("kayahli")];
- char uniname2ctype_pool_str3281[sizeof("hangul")];
- char uniname2ctype_pool_str3294[sizeof("inhebrew")];
- char uniname2ctype_pool_str3300[sizeof("graphemeclusterbreak=extend")];
- char uniname2ctype_pool_str3301[sizeof("graphemeclusterbreak=prepend")];
- char uniname2ctype_pool_str3303[sizeof("ogrext")];
- char uniname2ctype_pool_str3306[sizeof("tirh")];
- char uniname2ctype_pool_str3321[sizeof("cypriot")];
- char uniname2ctype_pool_str3332[sizeof("inindicsiyaqnumbers")];
- char uniname2ctype_pool_str3334[sizeof("tangut")];
- char uniname2ctype_pool_str3341[sizeof("wspace")];
- char uniname2ctype_pool_str3345[sizeof("taitham")];
- char uniname2ctype_pool_str3354[sizeof("hexdigit")];
- char uniname2ctype_pool_str3355[sizeof("otherlowercase")];
- char uniname2ctype_pool_str3358[sizeof("graphemeclusterbreak=l")];
- char uniname2ctype_pool_str3361[sizeof("inmathematicaloperators")];
- char uniname2ctype_pool_str3364[sizeof("graphemeclusterbreak=control")];
- char uniname2ctype_pool_str3368[sizeof("otherletter")];
- char uniname2ctype_pool_str3381[sizeof("insuperscriptsandsubscripts")];
- char uniname2ctype_pool_str3390[sizeof("inalchemicalsymbols")];
- char uniname2ctype_pool_str3392[sizeof("ogham")];
- char uniname2ctype_pool_str3410[sizeof("inhanguljamoextendedb")];
- char uniname2ctype_pool_str3418[sizeof("inpahawhhmong")];
- char uniname2ctype_pool_str3426[sizeof("aghb")];
- char uniname2ctype_pool_str3433[sizeof("nshu")];
- char uniname2ctype_pool_str3439[sizeof("otheridstart")];
- char uniname2ctype_pool_str3448[sizeof("hluw")];
- char uniname2ctype_pool_str3450[sizeof("inglagoliticsupplement")];
- char uniname2ctype_pool_str3474[sizeof("otheruppercase")];
- char uniname2ctype_pool_str3477[sizeof("inyisyllables")];
- char uniname2ctype_pool_str3485[sizeof("inyijinghexagramsymbols")];
- char uniname2ctype_pool_str3488[sizeof("oupper")];
- char uniname2ctype_pool_str3492[sizeof("insupplementalarrowsa")];
- char uniname2ctype_pool_str3508[sizeof("nushu")];
- char uniname2ctype_pool_str3517[sizeof("othersymbol")];
- char uniname2ctype_pool_str3531[sizeof("deprecated")];
- char uniname2ctype_pool_str3552[sizeof("rejang")];
- char uniname2ctype_pool_str3553[sizeof("alphabetic")];
- char uniname2ctype_pool_str3576[sizeof("deva")];
- char uniname2ctype_pool_str3585[sizeof("invithkuqi")];
- char uniname2ctype_pool_str3594[sizeof("devanagari")];
- char uniname2ctype_pool_str3599[sizeof("inprivateusearea")];
- char uniname2ctype_pool_str3601[sizeof("inlatinextendedb")];
- char uniname2ctype_pool_str3604[sizeof("insupplementalarrowsc")];
- char uniname2ctype_pool_str3621[sizeof("idcompatmathcontinue")];
- char uniname2ctype_pool_str3625[sizeof("soyombo")];
- char uniname2ctype_pool_str3627[sizeof("inethiopicextendedb")];
- char uniname2ctype_pool_str3633[sizeof("inmahjongtiles")];
- char uniname2ctype_pool_str3635[sizeof("idcompatmathstart")];
- char uniname2ctype_pool_str3648[sizeof("incypriotsyllabary")];
- char uniname2ctype_pool_str3655[sizeof("insupplementalmathematicaloperators")];
- char uniname2ctype_pool_str3677[sizeof("upper")];
- char uniname2ctype_pool_str3680[sizeof("oldnortharabian")];
- char uniname2ctype_pool_str3693[sizeof("inhighprivateusesurrogates")];
- char uniname2ctype_pool_str3697[sizeof("omath")];
- char uniname2ctype_pool_str3763[sizeof("inlatinextendedf")];
- char uniname2ctype_pool_str3771[sizeof("tibt")];
- char uniname2ctype_pool_str3777[sizeof("uppercase")];
- char uniname2ctype_pool_str3783[sizeof("tibetan")];
- char uniname2ctype_pool_str3792[sizeof("injavanese")];
- char uniname2ctype_pool_str3794[sizeof("ecomp")];
- char uniname2ctype_pool_str3818[sizeof("modifiersymbol")];
- char uniname2ctype_pool_str3821[sizeof("indivesakuru")];
- char uniname2ctype_pool_str3828[sizeof("ethiopic")];
- char uniname2ctype_pool_str3844[sizeof("pahawhhmong")];
- char uniname2ctype_pool_str3847[sizeof("unifiedideograph")];
- char uniname2ctype_pool_str3894[sizeof("bassavah")];
- char uniname2ctype_pool_str3901[sizeof("hanifirohingya")];
- char uniname2ctype_pool_str3908[sizeof("otherdefaultignorablecodepoint")];
- char uniname2ctype_pool_str3959[sizeof("inboxdrawing")];
- char uniname2ctype_pool_str3986[sizeof("inhalfwidthandfullwidthforms")];
- char uniname2ctype_pool_str3999[sizeof("inegyptianhieroglyphs")];
- char uniname2ctype_pool_str4012[sizeof("inegyptianhieroglyphformatcontrols")];
- char uniname2ctype_pool_str4020[sizeof("dupl")];
- char uniname2ctype_pool_str4036[sizeof("changeswhencasefolded")];
- char uniname2ctype_pool_str4053[sizeof("dashpunctuation")];
- char uniname2ctype_pool_str4064[sizeof("othermath")];
- char uniname2ctype_pool_str4068[sizeof("insupplementalpunctuation")];
- char uniname2ctype_pool_str4110[sizeof("uppercaseletter")];
- char uniname2ctype_pool_str4128[sizeof("tglg")];
- char uniname2ctype_pool_str4150[sizeof("tagalog")];
- char uniname2ctype_pool_str4230[sizeof("tagb")];
- char uniname2ctype_pool_str4245[sizeof("oldsoutharabian")];
- char uniname2ctype_pool_str4279[sizeof("otherpunctuation")];
- char uniname2ctype_pool_str4311[sizeof("inhighsurrogates")];
- char uniname2ctype_pool_str4313[sizeof("graphemeclusterbreak=lf")];
- char uniname2ctype_pool_str4318[sizeof("tfng")];
- char uniname2ctype_pool_str4319[sizeof("inbopomofoextended")];
- char uniname2ctype_pool_str4371[sizeof("divesakuru")];
- char uniname2ctype_pool_str4380[sizeof("dep")];
- char uniname2ctype_pool_str4429[sizeof("othergraphemeextend")];
- char uniname2ctype_pool_str4456[sizeof("hebrew")];
- char uniname2ctype_pool_str4475[sizeof("tavt")];
- char uniname2ctype_pool_str4490[sizeof("defaultignorablecodepoint")];
- char uniname2ctype_pool_str4493[sizeof("egyp")];
- char uniname2ctype_pool_str4507[sizeof("graphemeclusterbreak=zwj")];
- char uniname2ctype_pool_str4513[sizeof("zyyy")];
- char uniname2ctype_pool_str4549[sizeof("olduyghur")];
- char uniname2ctype_pool_str4633[sizeof("telugu")];
- char uniname2ctype_pool_str4651[sizeof("hyphen")];
- char uniname2ctype_pool_str4719[sizeof("tifinagh")];
- char uniname2ctype_pool_str4820[sizeof("inhangulcompatibilityjamo")];
- char uniname2ctype_pool_str4864[sizeof("insupplementalarrowsb")];
- char uniname2ctype_pool_str4890[sizeof("insupplementaryprivateuseareaa")];
- char uniname2ctype_pool_str4938[sizeof("graphemeclusterbreak=v")];
- char uniname2ctype_pool_str4939[sizeof("graphemeclusterbreak=lv")];
- char uniname2ctype_pool_str5052[sizeof("duployan")];
- char uniname2ctype_pool_str5064[sizeof("nyiakengpuachuehmong")];
- char uniname2ctype_pool_str5138[sizeof("egyptianhieroglyphs")];
- char uniname2ctype_pool_str5150[sizeof("openpunctuation")];
- char uniname2ctype_pool_str5156[sizeof("insupplementalsymbolsandpictographs")];
- char uniname2ctype_pool_str6262[sizeof("insupplementaryprivateuseareab")];
-#endif /* USE_UNICODE_PROPERTIES */
- };
-static const struct uniname2ctype_pool_t uniname2ctype_pool_contents =
- {
-#ifndef USE_UNICODE_PROPERTIES
- "word",
-#else /* USE_UNICODE_PROPERTIES */
- "yi",
- "yiii",
- "lana",
- "lina",
- "maka",
- "mani",
- "mn",
- "z",
- "miao",
- "lo",
- "ci",
- "lao",
- "laoo",
- "inkannada",
- "cn",
- "pi",
- "innko",
- "gran",
- "co",
- "yezi",
- "lineara",
- "mark",
- "po",
- "me",
- "cari",
- "inkharoshthi",
- "kana",
- "loe",
- "zzzz",
- "m",
- "grek",
- "mro",
- "mroo",
- "carian",
- "geor",
- "greek",
- "gonm",
- "mendekikakui",
- "pe",
- "mero",
- "inosmanya",
- "cakm",
- "inmanichaean",
- "inmro",
- "inmiao",
- "inchakma",
- "c",
- "mandaic",
- "meeteimayek",
- "inarmenian",
- "inmyanmar",
- "inmakasar",
- "common",
- "lm",
- "marc",
- "inrunic",
- "incarian",
- "inideographicsymbolsandpunctuation",
- "inkhmer",
- "qaai",
- "inahom",
- "merc",
- "inchorasmian",
- "combiningmark",
- "lc",
- "perm",
- "mc",
- "connectorpunctuation",
- "cans",
- "incuneiformnumbersandpunctuation",
- "armi",
- "cc",
- "armn",
- "incherokee",
- "prependedconcatenationmark",
- "incuneiform",
- "inavestan",
- "inipaextensions",
- "pc",
- "armenian",
- "insharada",
- "inmarchen",
- "makasar",
- "masaramgondi",
- "inarrows",
- "incyrillic",
- "incham",
- "qmark",
- "ri",
- "qaac",
- "insamaritan",
- "latn",
- "inmasaramgondi",
- "inthaana",
- "latin",
- "inthai",
- "lineseparator",
- "pcm",
- "inkatakana",
- "inkaithi",
- "inscriptionalparthian",
- "initialpunctuation",
- "inzanabazarsquare",
- "mtei",
- "inkhmersymbols",
- "insyriac",
- "intakri",
- "arabic",
- "zs",
- "katakana",
- "prti",
- "ascii",
- "cs",
- "ps",
- "mand",
- "privateuse",
- "inruminumeralsymbols",
- "inmyanmarextendeda",
- "modi",
- "incjkcompatibilityforms",
- "inkanaextendeda",
- "incjkcompatibilityideographs",
- "brai",
- "mend",
- "ideo",
- "letter",
- "l",
- "inmeeteimayek",
- "inideographicdescriptioncharacters",
- "yezidi",
- "knda",
- "innandinagari",
- "kannada",
- "xidcontinue",
- "inmodi",
- "inlao",
- "inoldnortharabian",
- "intransportandmapsymbols",
- "letternumber",
- "gothic",
- "incb=consonant",
- "inlineara",
- "inmendekikakui",
- "mongolian",
- "inmiscellaneousmathematicalsymbolsa",
- "inspecials",
- "vai",
- "vaii",
- "grlink",
- "xidc",
- "brahmi",
- "inemoticons",
- "kali",
- "inolditalic",
- "inmedefaidrin",
- "inchesssymbols",
- "incjkcompatibilityideographssupplement",
- "kits",
- "inadlam",
- "incb=extend",
- "psalterpahlavi",
- "incommonindicnumberforms",
- "lt",
- "sk",
- "control",
- "inancientsymbols",
- "palm",
- "inlycian",
- "so",
- "patternwhitespace",
- "inmandaic",
- "idc",
- "meroiticcursive",
- "intoto",
- "xids",
- "sora",
- "inopticalcharacterrecognition",
- "incb=linker",
- "inoldsogdian",
- "inmalayalam",
- "bamum",
- "inkanasupplement",
- "innewa",
- "insundanese",
- "inkawi",
- "grext",
-#endif /* USE_UNICODE_PROPERTIES */
- "print",
-#ifndef USE_UNICODE_PROPERTIES
- "punct",
- "alpha",
-#else /* USE_UNICODE_PROPERTIES */
- "intaitham",
- "joinc",
- "inoldsoutharabian",
- "incjkstrokes",
- "batk",
- "samr",
- "inwarangciti",
- "batak",
- "kawi",
- "patws",
- "samaritan",
- "idsbinaryoperator",
- "pauc",
- "inznamennymusicalnotation",
- "insmallkanaextension",
- "sm",
- "indominotiles",
-#endif /* USE_UNICODE_PROPERTIES */
- "alnum",
-#ifdef USE_UNICODE_PROPERTIES
- "gong",
- "ingrantha",
- "insylotinagri",
- "inugaritic",
- "lower",
- "incontrolpictures",
- "mong",
- "inlinearbideograms",
- "inmusicalsymbols",
- "s",
- "ital",
- "inmodifiertoneletters",
- "inancientgreekmusicalnotation",
- "idsunaryoperator",
- "lisu",
- "inwancho",
- "sc",
- "bass",
- "georgian",
- "inosage",
- "ids",
- "inlatinextendeda",
- "ingeneralpunctuation",
- "intaile",
- "ingeorgian",
- "inmiscellaneoussymbols",
- "emoji",
- "inmiscellaneoussymbolsandarrows",
- "incaucasianalbanian",
- "inmiscellaneoussymbolsandpictographs",
- "inmongolian",
- "innagmundari",
- "inoldturkic",
- "insaurashtra",
- "lowercase",
- "cwcm",
- "idcontinue",
- "intamil",
- "inmultani",
- "inlatinextendede",
- "pd",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=11.0",
- "age=10.0",
- "age=12.1",
- "age=12.0",
- "age=1.1",
- "age=9.0",
- "age=8.0",
- "age=2.1",
- "age=2.0",
- "age=15.1",
- "age=15.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "ingurmukhi",
- "bali",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=7.0",
- "age=5.1",
- "age=5.0",
- "age=13.0",
- "age=5.2",
- "age=3.1",
- "age=3.0",
- "age=3.2",
- "age=6.1",
- "age=6.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "blank",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=6.2",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "idst",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=14.0",
- "age=4.1",
- "age=4.0",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "inlydian",
-#ifdef USE_UNICODE_AGE_PROPERTIES
- "age=6.3",
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- "vs",
- "bengali",
- "runr",
- "zl",
- "ll",
- "indeseret",
- "inancientgreeknumbers",
- "idstart",
- "inmeeteimayekextensions",
- "balinese",
- "logicalorderexception",
- "inspacingmodifierletters",
- "inearlydynasticcuneiform",
- "patternsyntax",
- "plrd",
- "innewtailue",
- "canadianaboriginal",
- "insorasompeng",
- "sind",
- "emojimodifier",
- "inlatinextendedc",
- "incountingrodnumerals",
- "inkhudawadi",
- "xidstart",
-#endif /* USE_UNICODE_PROPERTIES */
- "xdigit",
-#ifndef USE_UNICODE_PROPERTIES
- "upper",
- "ascii",
-#else /* USE_UNICODE_PROPERTIES */
- "bidic",
- "intangsa",
- "cased",
- "ingreekandcoptic",
- "sinhala",
- "adlm",
- "glagolitic",
- "sterm",
- "bamu",
- "gunjalagondi",
- "inolduyghur",
- "multani",
- "uideo",
- "joincontrol",
- "runic",
- "incyrillicsupplement",
- "inmeroitichieroglyphs",
- "zinh",
- "inkaktoviknumerals",
- "enclosingmark",
- "insiddham",
- "incherokeesupplement",
- "inhanifirohingya",
- "incyrillicextendeda",
- "inkhitansmallscript",
- "intaixuanjingsymbols",
- "quotationmark",
- "adlam",
- "inkangxiradicals",
- "regionalindicator",
- "casedletter",
- "incjkunifiedideographsextensiona",
- "inhiragana",
- "lu",
- "incjkunifiedideographsextensioni",
- "lowercaseletter",
- "intamilsupplement",
- "beng",
- "emojimodifierbase",
- "phoenician",
- "kaithi",
- "idsu",
- "glag",
- "incjkunifiedideographsextensione",
- "inmahajani",
- "indogra",
- "marchen",
- "graphemelink",
- "inmiscellaneoustechnical",
- "khojki",
- "cham",
- "inogham",
- "cher",
- "saur",
- "chakma",
- "guru",
- "sundanese",
- "punct",
- "cherokee",
- "khar",
- "paucinhau",
- "gurmukhi",
- "emod",
- "manichaean",
- "ingreekextended",
- "inolchiki",
- "incyrillicextendedc",
- "cwt",
- "oriya",
- "unassigned",
- "limbu",
- "inethiopic",
- "graphemebase",
- "ingeometricshapes",
- "emojicomponent",
- "incjkunifiedideographsextensionc",
-#endif /* USE_UNICODE_PROPERTIES */
- "cntrl",
-#ifdef USE_UNICODE_PROPERTIES
- "inlatinextendedadditional",
- "radical",
- "ahom",
- "zanb",
- "linb",
- "khmr",
- "anatolianhieroglyphs",
- "inenclosedalphanumerics",
- "insinhala",
- "unknown",
- "inbhaiksuki",
- "innabataean",
- "inkanbun",
- "intangut",
- "sogdian",
- "sogo",
- "ideographic",
- "xsux",
- "incjkunifiedideographs",
- "chorasmian",
- "inelbasan",
- "insogdian",
- "indingbats",
- "mult",
- "n",
- "khmer",
- "saurashtra",
- "linearb",
- "chrs",
- "dia",
- "di",
- "inscriptionalpahlavi",
- "diak",
- "limb",
- "nandinagari",
- "no",
- "kharoshthi",
- "nko",
- "nkoo",
- "sd",
- "math",
- "p",
- "inenclosedideographicsupplement",
- "goth",
- "sidd",
- "ugar",
- "intags",
- "inarabic",
- "inenclosedalphanumericsupplement",
- "bidicontrol",
- "vithkuqi",
- "variationselector",
- "xpeo",
- "braille",
- "inornamentaldingbats",
- "grantha",
- "inkayahli",
- "inphoenician",
- "arab",
- "inoriya",
- "intirhuta",
- "osage",
- "inhatran",
- "wara",
- "caseignorable",
- "inyezidi",
- "kthi",
- "osma",
- "cpmn",
- "inphaistosdisc",
- "ingeometricshapesextended",
- "lepc",
- "inlowsurrogates",
- "inarabicpresentationformsa",
- "inbasiclatin",
- "punctuation",
- "lyci",
- "diacritic",
- "lycian",
- "incyprominoan",
- "incyrillicextendedd",
- "brah",
- "inoldhungarian",
- "hani",
- "mymr",
- "han",
- "myanmar",
- "hano",
- "incjkunifiedideographsextensiond",
- "inherited",
- "sund",
- "inimperialaramaic",
- "sorasompeng",
- "insundanesesupplement",
- "inkhojki",
- "hanunoo",
- "hira",
- "grbase",
- "inbatak",
- "cwl",
- "odi",
- "phli",
- "inlatinextendedd",
- "coptic",
- "inanatolianhieroglyphs",
- "assigned",
- "graphemeextend",
- "intibetan",
- "inelymaic",
- "insoyombo",
- "inblockelements",
- "incjkcompatibility",
- "innumberforms",
- "decimalnumber",
- "sinh",
- "inglagolitic",
- "shavian",
- "phnx",
- "copt",
- "sentenceterminal",
- "imperialaramaic",
- "bhks",
- "ininscriptionalpahlavi",
- "bhaiksuki",
- "ininscriptionalparthian",
- "oidc",
- "inhanunoo",
- "bugi",
- "insinhalaarchaicnumbers",
- "ingeorgiansupplement",
- "cprt",
- "sogd",
- "inmyanmarextendedb",
- "inbyzantinemusicalsymbols",
- "inkanaextendedb",
- "format",
- "inmayannumerals",
- "intagalog",
- "inarabicextendeda",
- "ugaritic",
- "patsyn",
- "nand",
- "ahex",
- "olck",
- "olchiki",
- "innoblock",
- "buginese",
- "inmongoliansupplement",
- "bopo",
- "oids",
- "asciihexdigit",
- "inbraillepatterns",
- "inbalinese",
- "inoldpersian",
- "olower",
- "insuttonsignwriting",
- "medf",
- "inmiscellaneousmathematicalsymbolsb",
- "lydi",
- "cwu",
- "inlisu",
- "medefaidrin",
- "lydian",
- "ext",
- "inshorthandformatcontrols",
- "hatran",
- "inyiradicals",
- "phag",
- "inarabicextendedc",
- "incoptic",
- "inhanguljamo",
- "inlisusupplement",
- "word",
- "hatr",
- "incjkunifiedideographsextensiong",
- "innushu",
- "incjksymbolsandpunctuation",
- "dsrt",
- "idsb",
- "bopomofo",
- "inhanguljamoextendeda",
- "inoldpermic",
- "inkatakanaphoneticextensions",
- "sarb",
- "zanabazarsquare",
- "vith",
- "innyiakengpuachuehmong",
- "alpha",
- "closepunctuation",
- "intelugu",
- "sgnw",
- "inlepcha",
- "insyriacsupplement",
- "extpict",
- "spacingmark",
- "inpalmyrene",
- "cyrl",
- "deseret",
- "takri",
- "invai",
- "mlym",
- "malayalam",
- "surrogate",
- "ogam",
-#endif /* USE_UNICODE_PROPERTIES */
- "space",
-#ifndef USE_UNICODE_PROPERTIES
- "xposixpunct",
- "lower",
-#else /* USE_UNICODE_PROPERTIES */
- "takr",
- "inunifiedcanadianaboriginalsyllabicsextendeda",
- "palmyrene",
- "soyo",
- "newa",
- "taile",
- "extender",
- "inbengali",
- "inbamum",
- "meroitichieroglyphs",
- "inethiopicsupplement",
- "newtailue",
- "inbuginese",
- "separator",
- "cuneiform",
- "ebase",
- "sharada",
- "inphagspa",
- "dogra",
- "ethi",
- "inethiopicextendeda",
- "caucasianalbanian",
- "term",
- "rohg",
- "shrd",
- "cwcf",
- "osge",
- "syrc",
- "tnsa",
- "tangsa",
- "number",
- "dogr",
- "incopticepactnumbers",
- "nagm",
- "modifierletter",
- "incombiningdiacriticalmarks",
- "inshavian",
- "nd",
- "siddham",
- "oldpersian",
- "incombiningdiacriticalmarksforsymbols",
- "gujr",
- "ingeorgianextended",
- "gujarati",
- "inunifiedcanadianaboriginalsyllabics",
- "warangciti",
- "ingothic",
-#endif /* USE_UNICODE_PROPERTIES */
- "graph",
-#ifdef USE_UNICODE_PROPERTIES
- "xposixpunct",
- "inlatinextendedg",
- "syriac",
- "incjkunifiedideographsextensionh",
- "induployan",
- "inaegeannumbers",
- "oldpermic",
- "inmathematicalalphanumericsymbols",
- "incombiningdiacriticalmarkssupplement",
- "toto",
- "hang",
- "taiviet",
- "nl",
- "ingujarati",
- "incurrencysymbols",
- "insymbolsandpictographsextendeda",
- "shaw",
- "incjkradicalssupplement",
- "ingunjalagondi",
- "intagbanwa",
- "hiragana",
- "inphoneticextensions",
- "inrejang",
- "orkh",
- "hmng",
- "idstrinaryoperator",
- "insymbolsforlegacycomputing",
- "mathsymbol",
- "extendedpictographic",
- "incombiningdiacriticalmarksextended",
- "indevanagari",
- "avestan",
- "khudawadi",
- "inbrahmi",
- "inlinearbsyllabary",
- "inunifiedcanadianaboriginalsyllabicsextended",
- "java",
- "incyrillicextendedb",
- "indevanagariextendeda",
- "inlimbu",
- "inphoneticextensionssupplement",
- "incjkunifiedideographsextensionb",
- "tale",
- "terminalpunctuation",
- "inlatin1supplement",
- "currencysymbol",
- "sylo",
- "olditalic",
- "elba",
- "lepcha",
- "buhd",
- "changeswhencasemapped",
- "javanese",
- "taml",
- "emojipresentation",
- "epres",
- "spaceseparator",
- "inethiopicextended",
- "invariationselectors",
- "inverticalforms",
- "incjkunifiedideographsextensionf",
- "inottomansiyaqnumbers",
- "avst",
- "cyrillic",
- "wancho",
- "inhangulsyllables",
- "ougr",
- "intaiviet",
- "rjng",
- "paragraphseparator",
- "inletterlikesymbols",
- "invedicextensions",
- "intangutcomponents",
- "wcho",
- "invariationselectorssupplement",
- "changeswhentitlecased",
- "inpaucinhau",
- "dash",
- "nchar",
- "mahj",
- "orya",
- "hex",
- "mahajani",
-#endif /* USE_UNICODE_PROPERTIES */
- "digit",
-#ifndef USE_UNICODE_PROPERTIES
- "blank"
-#else /* USE_UNICODE_PROPERTIES */
- "inenclosedcjklettersandmonths",
- "nagmundari",
- "other",
- "otheridcontinue",
- "elbasan",
- "tang",
- "elym",
- "oldhungarian",
- "tagbanwa",
- "phagspa",
- "narb",
- "othernumber",
- "graphemeclusterbreak=spacingmark",
- "inbopomofo",
- "zp",
- "elymaic",
- "signwriting",
- "graphemeclusterbreak=cr",
- "intangutsupplement",
- "khoj",
- "titlecaseletter",
- "graphemeclusterbreak=regionalindicator",
- "inmeroiticcursive",
- "inbamumsupplement",
- "nonspacingmark",
- "cf",
- "oalpha",
- "sylotinagri",
- "whitespace",
- "intifinagh",
- "pf",
- "otheralphabetic",
- "inbassavah",
- "softdotted",
- "inarabicpresentationformsb",
- "inbuhid",
- "oldturkic",
- "oldsogdian",
- "changeswhenlowercased",
- "insmallformvariants",
- "indevanagariextended",
- "hung",
- "noncharactercodepoint",
- "incombininghalfmarks",
- "tirhuta",
- "osmanya",
- "buhid",
- "inarabicmathematicalalphabeticsymbols",
- "cyprominoan",
- "hebr",
- "any",
- "nbat",
- "changeswhenuppercased",
- "nabataean",
- "inpsalterpahlavi",
- "finalpunctuation",
- "phlp",
- "graphemeclusterbreak=t",
- "graphemeclusterbreak=lvt",
- "inalphabeticpresentationforms",
- "tamil",
- "hmnp",
- "inarabicsupplement",
- "talu",
- "symbol",
- "inplayingcards",
- "khitansmallscript",
- "telu",
- "thaa",
- "thai",
- "inarabicextendedb",
- "thaana",
- "kayahli",
- "hangul",
- "inhebrew",
- "graphemeclusterbreak=extend",
- "graphemeclusterbreak=prepend",
- "ogrext",
- "tirh",
- "cypriot",
- "inindicsiyaqnumbers",
- "tangut",
- "wspace",
- "taitham",
- "hexdigit",
- "otherlowercase",
- "graphemeclusterbreak=l",
- "inmathematicaloperators",
- "graphemeclusterbreak=control",
- "otherletter",
- "insuperscriptsandsubscripts",
- "inalchemicalsymbols",
- "ogham",
- "inhanguljamoextendedb",
- "inpahawhhmong",
- "aghb",
- "nshu",
- "otheridstart",
- "hluw",
- "inglagoliticsupplement",
- "otheruppercase",
- "inyisyllables",
- "inyijinghexagramsymbols",
- "oupper",
- "insupplementalarrowsa",
- "nushu",
- "othersymbol",
- "deprecated",
- "rejang",
- "alphabetic",
- "deva",
- "invithkuqi",
- "devanagari",
- "inprivateusearea",
- "inlatinextendedb",
- "insupplementalarrowsc",
- "idcompatmathcontinue",
- "soyombo",
- "inethiopicextendedb",
- "inmahjongtiles",
- "idcompatmathstart",
- "incypriotsyllabary",
- "insupplementalmathematicaloperators",
- "upper",
- "oldnortharabian",
- "inhighprivateusesurrogates",
- "omath",
- "inlatinextendedf",
- "tibt",
- "uppercase",
- "tibetan",
- "injavanese",
- "ecomp",
- "modifiersymbol",
- "indivesakuru",
- "ethiopic",
- "pahawhhmong",
- "unifiedideograph",
- "bassavah",
- "hanifirohingya",
- "otherdefaultignorablecodepoint",
- "inboxdrawing",
- "inhalfwidthandfullwidthforms",
- "inegyptianhieroglyphs",
- "inegyptianhieroglyphformatcontrols",
- "dupl",
- "changeswhencasefolded",
- "dashpunctuation",
- "othermath",
- "insupplementalpunctuation",
- "uppercaseletter",
- "tglg",
- "tagalog",
- "tagb",
- "oldsoutharabian",
- "otherpunctuation",
- "inhighsurrogates",
- "graphemeclusterbreak=lf",
- "tfng",
- "inbopomofoextended",
- "divesakuru",
- "dep",
- "othergraphemeextend",
- "hebrew",
- "tavt",
- "defaultignorablecodepoint",
- "egyp",
- "graphemeclusterbreak=zwj",
- "zyyy",
- "olduyghur",
- "telugu",
- "hyphen",
- "tifinagh",
- "inhangulcompatibilityjamo",
- "insupplementalarrowsb",
- "insupplementaryprivateuseareaa",
- "graphemeclusterbreak=v",
- "graphemeclusterbreak=lv",
- "duployan",
- "nyiakengpuachuehmong",
- "egyptianhieroglyphs",
- "openpunctuation",
- "insupplementalsymbolsandpictographs",
- "insupplementaryprivateuseareab"
-#endif /* USE_UNICODE_PROPERTIES */
- };
-#define uniname2ctype_pool ((const char *) &uniname2ctype_pool_contents)
-const struct uniname2ctype_struct *
-uniname2ctype_p (register const char *str, register size_t len)
-{
- static const struct uniname2ctype_struct wordlist[] =
- {
-#ifdef USE_UNICODE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str11), 114},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str17), 114},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str22), 155},
- {-1}, {-1},
- {uniname2ctype_offset(str25), 187},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str33), 221},
- {-1},
- {uniname2ctype_offset(str35), 189},
- {uniname2ctype_offset(str36), 34},
- {uniname2ctype_offset(str37), 52},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str45), 176},
- {uniname2ctype_offset(str46), 28},
- {uniname2ctype_offset(str47), 61},
- {uniname2ctype_offset(str48), 98},
- {uniname2ctype_offset(str49), 98},
- {-1}, {-1},
- {uniname2ctype_offset(str52), 353},
- {-1}, {-1},
- {uniname2ctype_offset(str55), 21},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str64), 44},
- {-1},
- {uniname2ctype_offset(str66), 340},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str71), 184},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str75), 22},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str79), 233},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str83), 187},
- {-1}, {-1},
- {uniname2ctype_offset(str86), 31},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str92), 45},
- {-1},
- {uniname2ctype_offset(str94), 33},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str100), 152},
- {uniname2ctype_offset(str101), 520},
- {uniname2ctype_offset(str102), 111},
- {uniname2ctype_offset(str103), 267},
- {-1}, {-1},
- {uniname2ctype_offset(str106), 284},
- {uniname2ctype_offset(str107), 31},
- {uniname2ctype_offset(str108), 80},
- {-1}, {-1},
- {uniname2ctype_offset(str111), 192},
- {uniname2ctype_offset(str112), 192},
- {-1}, {-1},
- {uniname2ctype_offset(str115), 152},
- {-1},
- {uniname2ctype_offset(str117), 101},
- {uniname2ctype_offset(str118), 80},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str122), 215},
-#endif /* USE_UNICODE_PROPERTIES */
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#ifndef USE_UNICODE_PROPERTIES
- {uniname2ctype_offset(str6), 12},
- {uniname2ctype_offset(str7), 7},
- {uniname2ctype_offset(str8), 15},
- {uniname2ctype_offset(str9), 1},
- {uniname2ctype_offset(str10), 13},
- {uniname2ctype_offset(str11), 11},
- {uniname2ctype_offset(str12), 10},
- {uniname2ctype_offset(str13), 14},
- {uniname2ctype_offset(str14), 3},
- {uniname2ctype_offset(str15), 9},
- {uniname2ctype_offset(str16), 8},
- {uniname2ctype_offset(str17), 6},
- {uniname2ctype_offset(str18), 5},
- {uniname2ctype_offset(str19), 4},
- {uniname2ctype_offset(str20), 2}
-#else /* USE_UNICODE_PROPERTIES */
- {uniname2ctype_offset(str129), 190},
- {uniname2ctype_offset(str130), 42},
- {uniname2ctype_offset(str131), 175},
- {-1}, {-1},
- {uniname2ctype_offset(str134), 504},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str139), 173},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str145), 523},
- {uniname2ctype_offset(str146), 582},
- {-1},
- {uniname2ctype_offset(str148), 587},
- {uniname2ctype_offset(str149), 542},
- {-1},
- {uniname2ctype_offset(str151), 18},
- {uniname2ctype_offset(str152), 172},
- {uniname2ctype_offset(str153), 163},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str161), 334},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str177), 359},
- {uniname2ctype_offset(str178), 570},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str183), 78},
- {-1}, {-1},
- {uniname2ctype_offset(str186), 27},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str190), 211},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str203), 367},
- {uniname2ctype_offset(str204), 495},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str210), 588},
- {-1},
- {uniname2ctype_offset(str212), 372},
- {uniname2ctype_offset(str213), 118},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str218), 556},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str226), 174},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str230), 537},
- {uniname2ctype_offset(str231), 31},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str236), 25},
- {uniname2ctype_offset(str237), 197},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str246), 32},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str250), 40},
- {-1}, {-1},
- {uniname2ctype_offset(str253), 105},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str260), 575},
- {-1}, {-1},
- {uniname2ctype_offset(str263), 164},
- {-1},
- {uniname2ctype_offset(str265), 19},
- {-1},
- {uniname2ctype_offset(str267), 82},
- {uniname2ctype_offset(str268), 364},
- {-1},
- {uniname2ctype_offset(str270), 276},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str274), 574},
- {uniname2ctype_offset(str275), 524},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str281), 328},
- {uniname2ctype_offset(str282), 40},
- {uniname2ctype_offset(str283), 82},
- {-1},
- {uniname2ctype_offset(str285), 544},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str289), 567},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str293), 221},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str297), 215},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str301), 402},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str311), 332},
- {-1},
- {uniname2ctype_offset(str313), 463},
- {-1},
- {uniname2ctype_offset(str315), 246},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str320), 277},
- {-1},
- {uniname2ctype_offset(str322), 132},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str328), 341},
- {-1}, {-1},
- {uniname2ctype_offset(str331), 79},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str335), 568},
- {-1}, {-1},
- {uniname2ctype_offset(str338), 339},
- {-1},
- {uniname2ctype_offset(str340), 79},
- {-1},
- {uniname2ctype_offset(str342), 356},
- {-1}, {-1},
- {uniname2ctype_offset(str345), 53},
- {uniname2ctype_offset(str346), 276},
- {-1},
- {uniname2ctype_offset(str348), 433},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str352), 540},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str362), 166},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str366), 44},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str370), 561},
- {-1}, {-1},
- {uniname2ctype_offset(str373), 163},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str386), 378},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str399), 337},
- {-1},
- {uniname2ctype_offset(str401), 555},
- {-1}, {-1},
- {uniname2ctype_offset(str404), 84},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str411), 55},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str418), 111},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str426), 166},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str442), 14},
- {-1}, {-1},
- {uniname2ctype_offset(str445), 23},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str462), 46},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str468), 172},
- {-1},
- {uniname2ctype_offset(str470), 22},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str475), 531},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str480), 464},
- {uniname2ctype_offset(str481), 191},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str486), 483},
- {-1},
- {uniname2ctype_offset(str488), 595},
- {-1}, {-1},
- {uniname2ctype_offset(str491), 477},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str500), 130},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str504), 190},
- {uniname2ctype_offset(str505), 252},
- {uniname2ctype_offset(str506), 24},
- {-1}, {-1},
- {uniname2ctype_offset(str509), 24},
- {-1},
- {uniname2ctype_offset(str511), 470},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str520), 430},
- {-1},
- {uniname2ctype_offset(str522), 233},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str538), 94},
- {-1}, {-1},
- {uniname2ctype_offset(str541), 560},
- {-1},
- {uniname2ctype_offset(str543), 94},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str548), 70},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str556), 553},
- {-1},
- {uniname2ctype_offset(str558), 357},
- {-1},
- {uniname2ctype_offset(str560), 522},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str565), 631},
- {uniname2ctype_offset(str566), 37},
- {-1},
- {uniname2ctype_offset(str568), 116},
- {-1}, {-1},
- {uniname2ctype_offset(str571), 76},
- {uniname2ctype_offset(str572), 509},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str577), 618},
- {-1},
- {uniname2ctype_offset(str579), 109},
- {-1}, {-1},
- {uniname2ctype_offset(str582), 413},
- {uniname2ctype_offset(str583), 487},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str588), 147},
- {uniname2ctype_offset(str589), 147},
- {uniname2ctype_offset(str590), 74},
- {uniname2ctype_offset(str591), 70},
- {-1}, {-1},
- {uniname2ctype_offset(str594), 171},
- {-1},
- {uniname2ctype_offset(str596), 629},
- {uniname2ctype_offset(str597), 149},
- {-1}, {-1},
- {uniname2ctype_offset(str600), 497},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str604), 586},
- {uniname2ctype_offset(str605), 636},
- {-1}, {-1},
- {uniname2ctype_offset(str608), 645},
- {uniname2ctype_offset(str609), 232},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str614), 619},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str618), 77},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str624), 198},
- {uniname2ctype_offset(str625), 454},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str630), 29},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str639), 49},
- {-1}, {-1},
- {uniname2ctype_offset(str642), 19},
- {-1}, {-1},
- {uniname2ctype_offset(str645), 492},
- {-1},
- {uniname2ctype_offset(str647), 195},
- {-1}, {-1},
- {uniname2ctype_offset(str650), 494},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str657), 51},
- {-1}, {-1},
- {uniname2ctype_offset(str660), 274},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str672), 342},
- {-1}, {-1},
- {uniname2ctype_offset(str675), 68},
- {-1}, {-1},
- {uniname2ctype_offset(str678), 174},
- {uniname2ctype_offset(str679), 614},
- {-1},
- {uniname2ctype_offset(str681), 69},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str696), 178},
- {uniname2ctype_offset(str697), 406},
- {uniname2ctype_offset(str698), 75},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str703), 534},
- {-1},
- {uniname2ctype_offset(str705), 354},
- {-1},
- {uniname2ctype_offset(str707), 161},
- {uniname2ctype_offset(str708), 594},
- {-1}, {-1},
- {uniname2ctype_offset(str711), 550},
- {-1},
- {uniname2ctype_offset(str713), 383},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str718), 571},
- {-1},
- {uniname2ctype_offset(str720), 72},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str737), 7},
- {uniname2ctype_offset(str738), 380},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str753), 243},
- {-1},
- {uniname2ctype_offset(str755), 521},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str760), 438},
- {uniname2ctype_offset(str761), 170},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str766), 159},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str770), 558},
- {uniname2ctype_offset(str771), 170},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str775), 239},
- {uniname2ctype_offset(str776), 274},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str783), 159},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str787), 259},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str791), 196},
- {uniname2ctype_offset(str792), 600},
- {-1},
- {uniname2ctype_offset(str794), 596},
- {-1}, {-1},
- {uniname2ctype_offset(str797), 50},
- {-1},
- {uniname2ctype_offset(str799), 624},
- {-1}, {-1},
- {uniname2ctype_offset(str802), 13},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str806), 220},
- {-1},
- {uniname2ctype_offset(str808), 549},
- {uniname2ctype_offset(str809), 453},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str814), 500},
- {-1}, {-1},
- {uniname2ctype_offset(str817), 6},
- {uniname2ctype_offset(str818), 405},
- {-1},
- {uniname2ctype_offset(str820), 109},
- {uniname2ctype_offset(str821), 489},
- {uniname2ctype_offset(str822), 602},
- {uniname2ctype_offset(str823), 47},
- {uniname2ctype_offset(str824), 115},
- {uniname2ctype_offset(str825), 451},
- {-1}, {-1},
- {uniname2ctype_offset(str828), 603},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str836), 261},
- {-1},
- {uniname2ctype_offset(str838), 160},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str842), 615},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str847), 48},
- {uniname2ctype_offset(str848), 181},
- {-1}, {-1},
- {uniname2ctype_offset(str851), 101},
- {uniname2ctype_offset(str852), 505},
- {-1}, {-1},
- {uniname2ctype_offset(str855), 67},
- {-1},
- {uniname2ctype_offset(str857), 326},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str871), 396},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str875), 376},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str879), 360},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str886), 411},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str891), 278},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str895), 419},
- {-1}, {-1},
- {uniname2ctype_offset(str898), 507},
- {-1},
- {uniname2ctype_offset(str900), 628},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str904), 373},
- {uniname2ctype_offset(str905), 616},
- {uniname2ctype_offset(str906), 528},
- {uniname2ctype_offset(str907), 456},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str917), 58},
- {-1}, {-1},
- {uniname2ctype_offset(str920), 66},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str924), 68},
- {-1},
- {uniname2ctype_offset(str926), 351},
- {-1},
- {uniname2ctype_offset(str928), 547},
- {uniname2ctype_offset(str929), 468},
- {uniname2ctype_offset(str930), 41},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str934), 304},
- {uniname2ctype_offset(str935), 303},
- {uniname2ctype_offset(str936), 306},
- {uniname2ctype_offset(str937), 305},
- {uniname2ctype_offset(str938), 285},
- {uniname2ctype_offset(str939), 302},
- {uniname2ctype_offset(str940), 301},
- {uniname2ctype_offset(str941), 287},
- {uniname2ctype_offset(str942), 286},
- {uniname2ctype_offset(str943), 310},
- {uniname2ctype_offset(str944), 309},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str945), 348},
- {uniname2ctype_offset(str946), 139},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str961), 2},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str947), 300},
- {uniname2ctype_offset(str948), 294},
- {uniname2ctype_offset(str949), 293},
- {uniname2ctype_offset(str950), 307},
- {uniname2ctype_offset(str951), 295},
- {-1}, {-1},
- {uniname2ctype_offset(str954), 289},
- {uniname2ctype_offset(str955), 288},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {-1},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {uniname2ctype_offset(str963), 260},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str957), 290},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {-1},
-#ifdef USE_UNICODE_AGE_PROPERTIES
- {uniname2ctype_offset(str959), 297},
- {uniname2ctype_offset(str960), 296},
- {uniname2ctype_offset(str961), 2},
- {uniname2ctype_offset(str962), 298},
- {uniname2ctype_offset(str963), 260},
- {uniname2ctype_offset(str964), 308},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str968), 292},
- {uniname2ctype_offset(str969), 291},
- {-1}, {-1}, {-1}, {-1},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str974), 517},
-#ifndef USE_UNICODE_AGE_PROPERTIES
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#else /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str975), 299},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#endif /* USE_UNICODE_AGE_PROPERTIES */
- {uniname2ctype_offset(str984), 273},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str994), 88},
- {uniname2ctype_offset(str995), 107},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1005), 53},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1010), 26},
- {-1}, {-1},
- {uniname2ctype_offset(str1013), 502},
- {-1},
- {uniname2ctype_offset(str1015), 491},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1021), 67},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1025), 466},
- {-1}, {-1},
- {uniname2ctype_offset(str1028), 139},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1032), 267},
- {-1}, {-1},
- {uniname2ctype_offset(str1035), 329},
- {uniname2ctype_offset(str1036), 576},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1046), 275},
- {-1}, {-1},
- {uniname2ctype_offset(str1049), 176},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1061), 377},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1067), 105},
- {uniname2ctype_offset(str1068), 541},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1072), 200},
- {-1},
- {uniname2ctype_offset(str1074), 280},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1081), 421},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1087), 607},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1097), 548},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1103), 69},
- {uniname2ctype_offset(str1104), 11},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1109), 242},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1116), 583},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1120), 60},
- {-1}, {-1},
- {uniname2ctype_offset(str1123), 331},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1140), 96},
- {-1},
- {uniname2ctype_offset(str1142), 209},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1146), 134},
- {uniname2ctype_offset(str1147), 272},
- {-1},
- {uniname2ctype_offset(str1149), 161},
- {-1}, {-1},
- {uniname2ctype_offset(str1152), 220},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1156), 536},
- {uniname2ctype_offset(str1157), 206},
- {-1}, {-1},
- {uniname2ctype_offset(str1160), 263},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1164), 243},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1168), 107},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1174), 333},
- {-1}, {-1},
- {uniname2ctype_offset(str1177), 518},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1183), 118},
- {-1}, {-1},
- {uniname2ctype_offset(str1186), 604},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1190), 33},
- {uniname2ctype_offset(str1191), 552},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1207), 469},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1215), 530},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1221), 426},
- {-1},
- {uniname2ctype_offset(str1223), 591},
- {-1}, {-1},
- {uniname2ctype_offset(str1226), 606},
- {uniname2ctype_offset(str1227), 246},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1231), 209},
- {uniname2ctype_offset(str1232), 429},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1238), 277},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1243), 25},
- {-1}, {-1},
- {uniname2ctype_offset(str1246), 442},
- {uniname2ctype_offset(str1247), 432},
- {uniname2ctype_offset(str1248), 30},
- {uniname2ctype_offset(str1249), 644},
- {uniname2ctype_offset(str1250), 26},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1254), 573},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1258), 88},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1264), 281},
- {-1},
- {uniname2ctype_offset(str1266), 141},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1271), 169},
- {uniname2ctype_offset(str1272), 261},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1281), 134},
- {uniname2ctype_offset(str1282), 642},
- {-1},
- {uniname2ctype_offset(str1284), 543},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1288), 557},
- {uniname2ctype_offset(str1289), 211},
- {uniname2ctype_offset(str1290), 74},
- {-1},
- {uniname2ctype_offset(str1292), 404},
- {uniname2ctype_offset(str1293), 186},
- {uniname2ctype_offset(str1294), 154},
- {uniname2ctype_offset(str1295), 366},
- {uniname2ctype_offset(str1296), 104},
- {uniname2ctype_offset(str1297), 148},
- {uniname2ctype_offset(str1298), 173},
- {-1},
- {uniname2ctype_offset(str1300), 89},
- {uniname2ctype_offset(str1301), 144},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1306), 15},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1310), 104},
- {uniname2ctype_offset(str1311), 138},
- {-1}, {-1},
- {uniname2ctype_offset(str1314), 196},
- {-1}, {-1},
- {uniname2ctype_offset(str1317), 89},
- {-1},
- {uniname2ctype_offset(str1319), 280},
- {-1}, {-1},
- {uniname2ctype_offset(str1322), 189},
- {uniname2ctype_offset(str1323), 395},
- {-1},
- {uniname2ctype_offset(str1325), 386},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1333), 387},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1338), 64},
- {-1},
- {uniname2ctype_offset(str1340), 91},
- {uniname2ctype_offset(str1341), 21},
- {-1},
- {uniname2ctype_offset(str1343), 123},
- {-1},
- {uniname2ctype_offset(str1345), 362},
- {uniname2ctype_offset(str1346), 73},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1355), 410},
- {uniname2ctype_offset(str1356), 282},
- {-1},
- {uniname2ctype_offset(str1358), 640},
- {-1},
- {uniname2ctype_offset(str1360), 3},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1365), 394},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1369), 262},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1387), 203},
- {-1},
- {uniname2ctype_offset(str1389), 218},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1397), 125},
- {uniname2ctype_offset(str1398), 108},
- {-1},
- {uniname2ctype_offset(str1400), 204},
- {uniname2ctype_offset(str1401), 407},
- {uniname2ctype_offset(str1402), 355},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1406), 284},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1410), 566},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1418), 514},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1423), 436},
- {-1},
- {uniname2ctype_offset(str1425), 589},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1429), 224},
- {-1},
- {uniname2ctype_offset(str1431), 225},
- {-1},
- {uniname2ctype_offset(str1433), 252},
- {-1},
- {uniname2ctype_offset(str1435), 140},
- {-1}, {-1},
- {uniname2ctype_offset(str1438), 444},
- {-1}, {-1},
- {uniname2ctype_offset(str1441), 230},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1445), 506},
- {uniname2ctype_offset(str1446), 535},
- {uniname2ctype_offset(str1447), 412},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1451), 206},
- {uniname2ctype_offset(str1452), 35},
- {uniname2ctype_offset(str1453), 108},
- {uniname2ctype_offset(str1454), 148},
- {uniname2ctype_offset(str1455), 125},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1462), 230},
- {uniname2ctype_offset(str1463), 253},
- {uniname2ctype_offset(str1464), 71},
- {-1}, {-1},
- {uniname2ctype_offset(str1467), 167},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1472), 231},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1477), 123},
- {-1},
- {uniname2ctype_offset(str1479), 227},
- {-1},
- {uniname2ctype_offset(str1481), 38},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1488), 138},
- {-1}, {-1},
- {uniname2ctype_offset(str1491), 143},
- {uniname2ctype_offset(str1492), 143},
- {-1}, {-1},
- {uniname2ctype_offset(str1495), 266},
- {-1},
- {uniname2ctype_offset(str1497), 56},
- {uniname2ctype_offset(str1498), 39},
- {uniname2ctype_offset(str1499), 627},
- {uniname2ctype_offset(str1500), 116},
- {uniname2ctype_offset(str1501), 199},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1509), 126},
- {-1},
- {uniname2ctype_offset(str1511), 648},
- {-1},
- {uniname2ctype_offset(str1513), 336},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1517), 626},
- {-1}, {-1},
- {uniname2ctype_offset(str1520), 242},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1530), 238},
- {uniname2ctype_offset(str1531), 273},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1535), 137},
- {uniname2ctype_offset(str1536), 130},
- {-1}, {-1},
- {uniname2ctype_offset(str1539), 630},
- {-1},
- {uniname2ctype_offset(str1541), 184},
- {uniname2ctype_offset(str1542), 458},
- {uniname2ctype_offset(str1543), 516},
- {-1},
- {uniname2ctype_offset(str1545), 84},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1549), 350},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1555), 551},
- {-1}, {-1},
- {uniname2ctype_offset(str1558), 213},
- {-1}, {-1},
- {uniname2ctype_offset(str1561), 515},
- {uniname2ctype_offset(str1562), 202},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1567), 61},
- {uniname2ctype_offset(str1568), 532},
- {-1},
- {uniname2ctype_offset(str1570), 169},
- {uniname2ctype_offset(str1571), 128},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1580), 234},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1596), 493},
- {uniname2ctype_offset(str1597), 633},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1605), 145},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1617), 475},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1623), 479},
- {-1},
- {uniname2ctype_offset(str1625), 324},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1629), 39},
- {-1},
- {uniname2ctype_offset(str1631), 151},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1639), 253},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1646), 151},
- {-1}, {-1},
- {uniname2ctype_offset(str1649), 577},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1657), 612},
- {-1}, {-1},
- {uniname2ctype_offset(str1660), 171},
- {-1},
- {uniname2ctype_offset(str1662), 529},
- {-1},
- {uniname2ctype_offset(str1664), 113},
- {-1},
- {uniname2ctype_offset(str1666), 100},
- {uniname2ctype_offset(str1667), 113},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1671), 100},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1678), 120},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1682), 641},
- {-1}, {-1},
- {uniname2ctype_offset(str1685), 118},
- {-1},
- {uniname2ctype_offset(str1687), 144},
- {-1},
- {uniname2ctype_offset(str1689), 512},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1695), 178},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1699), 389},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1703), 546},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1707), 120},
- {-1}, {-1},
- {uniname2ctype_offset(str1710), 110},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1714), 73},
- {-1}, {-1},
- {uniname2ctype_offset(str1717), 384},
- {uniname2ctype_offset(str1718), 62},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1723), 264},
- {-1}, {-1},
- {uniname2ctype_offset(str1726), 167},
- {-1}, {-1},
- {uniname2ctype_offset(str1729), 452},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1734), 132},
- {-1},
- {uniname2ctype_offset(str1736), 580},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1744), 17},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1748), 72},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1754), 358},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str1766), 538},
- {uniname2ctype_offset(str1767), 562},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1776), 409},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1780), 441},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1790), 401},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1797), 36},
- {-1},
- {uniname2ctype_offset(str1799), 96},
- {uniname2ctype_offset(str1800), 420},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1804), 127},
- {-1},
- {uniname2ctype_offset(str1806), 141},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1812), 132},
- {uniname2ctype_offset(str1813), 272},
- {uniname2ctype_offset(str1814), 164},
- {-1}, {-1},
- {uniname2ctype_offset(str1817), 210},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1824), 526},
- {-1}, {-1},
- {uniname2ctype_offset(str1827), 210},
- {-1},
- {uniname2ctype_offset(str1829), 525},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1833), 269},
- {-1},
- {uniname2ctype_offset(str1835), 369},
- {uniname2ctype_offset(str1836), 131},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1844), 545},
- {-1}, {-1},
- {uniname2ctype_offset(str1847), 423},
- {uniname2ctype_offset(str1848), 129},
- {-1},
- {uniname2ctype_offset(str1850), 224},
- {-1},
- {uniname2ctype_offset(str1852), 462},
- {uniname2ctype_offset(str1853), 601},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1860), 593},
- {-1}, {-1},
- {uniname2ctype_offset(str1863), 20},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1880), 605},
- {uniname2ctype_offset(str1881), 368},
- {-1}, {-1},
- {uniname2ctype_offset(str1884), 345},
- {-1},
- {uniname2ctype_offset(str1886), 126},
- {-1}, {-1},
- {uniname2ctype_offset(str1889), 275},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1893), 227},
- {uniname2ctype_offset(str1894), 250},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1901), 146},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str1912), 146},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1916), 652},
- {-1},
- {uniname2ctype_offset(str1918), 131},
- {uniname2ctype_offset(str1919), 554},
- {uniname2ctype_offset(str1920), 112},
- {-1}, {-1},
- {uniname2ctype_offset(str1923), 268},
- {uniname2ctype_offset(str1924), 250},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1933), 415},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1941), 382},
- {-1},
- {uniname2ctype_offset(str1943), 501},
- {uniname2ctype_offset(str1944), 255},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1949), 609},
- {uniname2ctype_offset(str1950), 222},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1954), 417},
- {uniname2ctype_offset(str1955), 153},
- {uniname2ctype_offset(str1956), 63},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1964), 447},
- {-1},
- {uniname2ctype_offset(str1966), 222},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1970), 153},
- {uniname2ctype_offset(str1971), 254},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1975), 599},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str1981), 205},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str1992), 446},
- {-1}, {-1},
- {uniname2ctype_offset(str1995), 142},
- {uniname2ctype_offset(str1996), 533},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2004), 422},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2009), 361},
- {-1}, {-1},
- {uniname2ctype_offset(str2012), 572},
- {-1}, {-1},
- {uniname2ctype_offset(str2015), 12},
- {uniname2ctype_offset(str2016), 205},
- {uniname2ctype_offset(str2017), 646},
- {uniname2ctype_offset(str2018), 597},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2022), 431},
- {-1}, {-1},
- {uniname2ctype_offset(str2025), 117},
- {uniname2ctype_offset(str2026), 259},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2030), 112},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2038), 460},
- {uniname2ctype_offset(str2039), 499},
- {-1}, {-1},
- {uniname2ctype_offset(str2042), 439},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2051), 165},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2057), 218},
- {uniname2ctype_offset(str2058), 238},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2062), 613},
- {uniname2ctype_offset(str2063), 1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2068), 42},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2073), 352},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2081), 208},
- {uniname2ctype_offset(str2082), 385},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2086), 343},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2092), 283},
- {-1}, {-1},
- {uniname2ctype_offset(str2095), 32},
- {uniname2ctype_offset(str2096), 513},
- {uniname2ctype_offset(str2097), 81},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2102), 117},
- {uniname2ctype_offset(str2103), 179},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2110), 448},
- {-1},
- {uniname2ctype_offset(str2112), 95},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2119), 95},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2128), 23},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2140), 106},
- {-1},
- {uniname2ctype_offset(str2142), 9},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2148), 179},
- {uniname2ctype_offset(str2149), 563},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2157), 195},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2161), 217},
- {-1},
- {uniname2ctype_offset(str2163), 212},
- {uniname2ctype_offset(str2164), 124},
- {uniname2ctype_offset(str2165), 254},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2183), 347},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2192), 450},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2201), 175},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2208), 363},
- {uniname2ctype_offset(str2209), 133},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2213), 379},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2217), 52},
- {-1},
- {uniname2ctype_offset(str2219), 140},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2225), 281},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2230), 177},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2243), 455},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2251), 219},
- {-1}, {-1},
- {uniname2ctype_offset(str2254), 103},
- {uniname2ctype_offset(str2255), 467},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2260), 180},
- {-1}, {-1},
- {uniname2ctype_offset(str2263), 247},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2268), 223},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2278), 177},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2286), 65},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2291), 213},
- {uniname2ctype_offset(str2292), 85},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2296), 236},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2300), 236},
- {uniname2ctype_offset(str2301), 35},
- {uniname2ctype_offset(str2302), 219},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2307), 496},
- {uniname2ctype_offset(str2308), 240},
- {uniname2ctype_offset(str2309), 27},
- {-1}, {-1},
- {uniname2ctype_offset(str2312), 330},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2318), 503},
- {uniname2ctype_offset(str2319), 36},
- {uniname2ctype_offset(str2320), 199},
- {uniname2ctype_offset(str2321), 137},
- {uniname2ctype_offset(str2322), 399},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2328), 90},
- {uniname2ctype_offset(str2329), 388},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2337), 90},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2342), 365},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2351), 202},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2384), 498},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2392), 5},
- {-1}, {-1},
- {uniname2ctype_offset(str2395), 8},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2399), 610},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2408), 85},
- {uniname2ctype_offset(str2409), 647},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2415), 598},
- {-1}, {-1},
- {uniname2ctype_offset(str2418), 490},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2425), 197},
- {-1}, {-1},
- {uniname2ctype_offset(str2428), 608},
- {uniname2ctype_offset(str2429), 393},
- {uniname2ctype_offset(str2430), 237},
- {-1},
- {uniname2ctype_offset(str2432), 102},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2443), 156},
- {-1},
- {uniname2ctype_offset(str2445), 37},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2451), 349},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2460), 398},
- {uniname2ctype_offset(str2461), 637},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2466), 127},
- {-1}, {-1},
- {uniname2ctype_offset(str2469), 428},
- {uniname2ctype_offset(str2470), 569},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2483), 371},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2487), 110},
- {uniname2ctype_offset(str2488), 391},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2499), 459},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2506), 168},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2519), 185},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2532), 260},
- {-1}, {-1},
- {uniname2ctype_offset(str2535), 638},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2544), 50},
- {-1}, {-1},
- {uniname2ctype_offset(str2547), 283},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2554), 381},
- {uniname2ctype_offset(str2555), 346},
- {uniname2ctype_offset(str2556), 157},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2563), 200},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2567), 539},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2583), 488},
- {uniname2ctype_offset(str2584), 374},
- {-1},
- {uniname2ctype_offset(str2586), 162},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2593), 449},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2598), 565},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2604), 375},
- {uniname2ctype_offset(str2605), 392},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2618), 639},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2622), 124},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2633), 247},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2639), 325},
- {-1}, {-1},
- {uniname2ctype_offset(str2642), 48},
- {uniname2ctype_offset(str2643), 136},
- {-1},
- {uniname2ctype_offset(str2645), 115},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2650), 183},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2660), 145},
- {uniname2ctype_offset(str2661), 121},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2670), 66},
- {uniname2ctype_offset(str2671), 162},
- {-1},
- {uniname2ctype_offset(str2673), 92},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2678), 279},
- {-1},
- {uniname2ctype_offset(str2680), 279},
- {uniname2ctype_offset(str2681), 55},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2690), 425},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2694), 480},
- {-1}, {-1},
- {uniname2ctype_offset(str2697), 481},
- {-1},
- {uniname2ctype_offset(str2699), 643},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2708), 621},
- {-1},
- {uniname2ctype_offset(str2710), 157},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2714), 81},
- {-1}, {-1},
- {uniname2ctype_offset(str2717), 229},
- {uniname2ctype_offset(str2718), 471},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2724), 235},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2730), 465},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2741), 150},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2760), 54},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2769), 400},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2774), 390},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2779), 590},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2801), 229},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2811), 649},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2816), 64},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2822), 564},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2826), 244},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2833), 257},
- {uniname2ctype_offset(str2834), 188},
- {-1},
- {uniname2ctype_offset(str2836), 91},
- {-1}, {-1},
- {uniname2ctype_offset(str2839), 249},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2843), 188},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2855), 4},
- {uniname2ctype_offset(str2856), 440},
- {uniname2ctype_offset(str2857), 240},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2862), 18},
- {uniname2ctype_offset(str2863), 269},
- {uniname2ctype_offset(str2864), 183},
- {uniname2ctype_offset(str2865), 214},
- {uniname2ctype_offset(str2866), 226},
- {uniname2ctype_offset(str2867), 207},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2871), 122},
- {-1},
- {uniname2ctype_offset(str2873), 142},
- {-1},
- {uniname2ctype_offset(str2875), 193},
- {uniname2ctype_offset(str2876), 38},
- {uniname2ctype_offset(str2877), 317},
- {-1},
- {uniname2ctype_offset(str2879), 434},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str2891), 54},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2899), 226},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str2910), 208},
- {-1}, {-1},
- {uniname2ctype_offset(str2913), 312},
- {-1},
- {uniname2ctype_offset(str2915), 592},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2921), 186},
- {-1},
- {uniname2ctype_offset(str2923), 29},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2928), 316},
- {-1},
- {uniname2ctype_offset(str2930), 519},
- {-1},
- {uniname2ctype_offset(str2932), 581},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2937), 34},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2947), 20},
- {uniname2ctype_offset(str2948), 251},
- {-1},
- {uniname2ctype_offset(str2950), 136},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2957), 241},
- {-1},
- {uniname2ctype_offset(str2959), 424},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2964), 43},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2969), 251},
- {uniname2ctype_offset(str2970), 584},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str2993), 266},
- {-1},
- {uniname2ctype_offset(str2995), 485},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3002), 370},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3007), 168},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3020), 225},
- {-1}, {-1},
- {uniname2ctype_offset(str3023), 62},
- {uniname2ctype_offset(str3024), 484},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3033), 457},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3050), 207},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3056), 257},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3066), 482},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3075), 201},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3084), 128},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3099), 121},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3106), 622},
- {uniname2ctype_offset(str3107), 234},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3115), 83},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3128), 16},
- {-1}, {-1},
- {uniname2ctype_offset(str3131), 194},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3142), 63},
- {-1}, {-1},
- {uniname2ctype_offset(str3145), 194},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3149), 527},
- {-1}, {-1},
- {uniname2ctype_offset(str3152), 43},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3165), 198},
- {-1}, {-1},
- {uniname2ctype_offset(str3168), 320},
- {-1},
- {uniname2ctype_offset(str3170), 322},
- {-1}, {-1},
- {uniname2ctype_offset(str3173), 478},
- {uniname2ctype_offset(str3174), 92},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3190), 228},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3200), 338},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3204), 133},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3233), 47},
- {uniname2ctype_offset(str3234), 625},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3238), 232},
- {-1},
- {uniname2ctype_offset(str3240), 93},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3250), 86},
- {-1}, {-1},
- {uniname2ctype_offset(str3253), 97},
- {-1}, {-1},
- {uniname2ctype_offset(str3256), 344},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3261), 86},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3266), 149},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3281), 102},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3294), 335},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3300), 315},
- {uniname2ctype_offset(str3301), 311},
- {-1},
- {uniname2ctype_offset(str3303), 258},
- {-1}, {-1},
- {uniname2ctype_offset(str3306), 201},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3321), 129},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3332), 620},
- {-1},
- {uniname2ctype_offset(str3334), 214},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3341), 241},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3345), 155},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3354), 249},
- {uniname2ctype_offset(str3355), 255},
- {-1}, {-1},
- {uniname2ctype_offset(str3358), 318},
- {-1}, {-1},
- {uniname2ctype_offset(str3361), 403},
- {-1}, {-1},
- {uniname2ctype_offset(str3364), 314},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3368), 28},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3381), 397},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3390), 632},
- {-1},
- {uniname2ctype_offset(str3392), 106},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3410), 472},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3418), 585},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3426), 180},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3433), 216},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3439), 268},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3448), 204},
- {-1},
- {uniname2ctype_offset(str3450), 611},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3474), 256},
- {-1}, {-1},
- {uniname2ctype_offset(str3477), 445},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3485), 443},
- {-1}, {-1},
- {uniname2ctype_offset(str3488), 256},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3492), 414},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3508), 216},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3517), 51},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3531), 265},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str3552), 150},
- {uniname2ctype_offset(str3553), 57},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3576), 87},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3585), 508},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3594), 87},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3599), 476},
- {-1},
- {uniname2ctype_offset(str3601), 327},
- {-1}, {-1},
- {uniname2ctype_offset(str3604), 634},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3621), 270},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3625), 217},
- {-1},
- {uniname2ctype_offset(str3627), 617},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3633), 623},
- {-1},
- {uniname2ctype_offset(str3635), 271},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3648), 511},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3655), 418},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3677), 10},
- {-1}, {-1},
- {uniname2ctype_offset(str3680), 193},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3693), 474},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3697), 248},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str3763), 510},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3771), 99},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3777), 59},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3783), 99},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3792), 461},
- {-1},
- {uniname2ctype_offset(str3794), 282},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3818), 49},
- {-1}, {-1},
- {uniname2ctype_offset(str3821), 559},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3828), 103},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3844), 185},
- {-1}, {-1},
- {uniname2ctype_offset(str3847), 263},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str3894), 181},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3901), 223},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3908), 264},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3959), 408},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3986), 486},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str3999), 578},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4012), 579},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4020), 182},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4036), 65},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4053), 41},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4064), 248},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4068), 427},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4110), 30},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4128), 119},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4150), 119},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4230), 122},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4245), 165},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4279), 45},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4311), 473},
- {-1},
- {uniname2ctype_offset(str4313), 313},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4318), 135},
- {uniname2ctype_offset(str4319), 437},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4371), 231},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4380), 265},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4429), 258},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4456), 83},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4475), 156},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4490), 71},
- {-1}, {-1},
- {uniname2ctype_offset(str4493), 158},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4507), 323},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4513), 78},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4549), 235},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str4633), 93},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4651), 245},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4719), 135},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str4820), 435},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4864), 416},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str4890), 650},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str4938), 319},
- {uniname2ctype_offset(str4939), 321},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5052), 182},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str5064), 228},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1},
- {uniname2ctype_offset(str5138), 158},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1},
- {uniname2ctype_offset(str5150), 46},
- {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str5156), 635},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
- {uniname2ctype_offset(str6262), 651}
-#endif /* USE_UNICODE_PROPERTIES */
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register unsigned int key = uniname2ctype_hash (str, len);
-
- if (key <= MAX_HASH_VALUE)
- {
- register int o = wordlist[key].name;
- if (o >= 0)
- {
- register const char *s = o + uniname2ctype_pool;
-
- if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
- return &wordlist[key];
- }
- }
- }
- return 0;
-}
-
-static int
-uniname2ctype(const UChar *name, unsigned int len)
-{
- const struct uniname2ctype_struct *p = uniname2ctype_p((const char *)name, len);
- if (p) return p->ctype;
- return -1;
-}
-#if defined ONIG_UNICODE_VERSION_STRING && !( \
- ONIG_UNICODE_VERSION_MAJOR == 15 && \
- ONIG_UNICODE_VERSION_MINOR == 1 && \
- ONIG_UNICODE_VERSION_TEENY == 0 && \
- 1)
-# error ONIG_UNICODE_VERSION_STRING mismatch
-#endif
-#define ONIG_UNICODE_VERSION_STRING "15.1.0"
-#define ONIG_UNICODE_VERSION_MAJOR 15
-#define ONIG_UNICODE_VERSION_MINOR 1
-#define ONIG_UNICODE_VERSION_TEENY 0
-#if defined ONIG_UNICODE_EMOJI_VERSION_STRING && !( \
- ONIG_UNICODE_EMOJI_VERSION_MAJOR == 15 && \
- ONIG_UNICODE_EMOJI_VERSION_MINOR == 1 && \
- 1)
-# error ONIG_UNICODE_EMOJI_VERSION_STRING mismatch
-#endif
-#define ONIG_UNICODE_EMOJI_VERSION_STRING "15.1"
-#define ONIG_UNICODE_EMOJI_VERSION_MAJOR 15
-#define ONIG_UNICODE_EMOJI_VERSION_MINOR 1
diff --git a/enc/unicode/17.0.0/casefold.h b/enc/unicode/17.0.0/casefold.h
new file mode 100644
index 0000000000..82439f35fb
--- /dev/null
+++ b/enc/unicode/17.0.0/casefold.h
@@ -0,0 +1,8013 @@
+/* DO NOT EDIT THIS FILE. */
+/* Generated by enc-case-folding.rb */
+
+#if defined ONIG_UNICODE_VERSION_STRING && !( \
+ ONIG_UNICODE_VERSION_MAJOR == 17 && \
+ ONIG_UNICODE_VERSION_MINOR == 0 && \
+ ONIG_UNICODE_VERSION_TEENY == 0 && \
+ 1)
+# error ONIG_UNICODE_VERSION_STRING mismatch
+#endif
+#define ONIG_UNICODE_VERSION_STRING "17.0.0"
+#define ONIG_UNICODE_VERSION_MAJOR 17
+#define ONIG_UNICODE_VERSION_MINOR 0
+#define ONIG_UNICODE_VERSION_TEENY 0
+
+static const CaseFold_11_Type CaseFold_11_Table[] = {
+#define CaseFold (*(CaseFold_11_Type (*)[1583])(CaseFold_11_Table+0))
+ {0x0041, {1|F|D, {0x0061}}},
+ {0x0042, {1|F|D, {0x0062}}},
+ {0x0043, {1|F|D, {0x0063}}},
+ {0x0044, {1|F|D, {0x0064}}},
+ {0x0045, {1|F|D, {0x0065}}},
+ {0x0046, {1|F|D, {0x0066}}},
+ {0x0047, {1|F|D, {0x0067}}},
+ {0x0048, {1|F|D, {0x0068}}},
+ {0x004a, {1|F|D, {0x006a}}},
+ {0x004b, {1|F|D, {0x006b}}},
+ {0x004c, {1|F|D, {0x006c}}},
+ {0x004d, {1|F|D, {0x006d}}},
+ {0x004e, {1|F|D, {0x006e}}},
+ {0x004f, {1|F|D, {0x006f}}},
+ {0x0050, {1|F|D, {0x0070}}},
+ {0x0051, {1|F|D, {0x0071}}},
+ {0x0052, {1|F|D, {0x0072}}},
+ {0x0053, {1|F|D, {0x0073}}},
+ {0x0054, {1|F|D, {0x0074}}},
+ {0x0055, {1|F|D, {0x0075}}},
+ {0x0056, {1|F|D, {0x0076}}},
+ {0x0057, {1|F|D, {0x0077}}},
+ {0x0058, {1|F|D, {0x0078}}},
+ {0x0059, {1|F|D, {0x0079}}},
+ {0x005a, {1|F|D, {0x007a}}},
+ {0x00b5, {1|F|SU|I(0), {0x03bc}}},
+ {0x00c0, {1|F|D, {0x00e0}}},
+ {0x00c1, {1|F|D, {0x00e1}}},
+ {0x00c2, {1|F|D, {0x00e2}}},
+ {0x00c3, {1|F|D, {0x00e3}}},
+ {0x00c4, {1|F|D, {0x00e4}}},
+ {0x00c5, {1|F|D, {0x00e5}}},
+ {0x00c6, {1|F|D, {0x00e6}}},
+ {0x00c7, {1|F|D, {0x00e7}}},
+ {0x00c8, {1|F|D, {0x00e8}}},
+ {0x00c9, {1|F|D, {0x00e9}}},
+ {0x00ca, {1|F|D, {0x00ea}}},
+ {0x00cb, {1|F|D, {0x00eb}}},
+ {0x00cc, {1|F|D, {0x00ec}}},
+ {0x00cd, {1|F|D, {0x00ed}}},
+ {0x00ce, {1|F|D, {0x00ee}}},
+ {0x00cf, {1|F|D, {0x00ef}}},
+ {0x00d0, {1|F|D, {0x00f0}}},
+ {0x00d1, {1|F|D, {0x00f1}}},
+ {0x00d2, {1|F|D, {0x00f2}}},
+ {0x00d3, {1|F|D, {0x00f3}}},
+ {0x00d4, {1|F|D, {0x00f4}}},
+ {0x00d5, {1|F|D, {0x00f5}}},
+ {0x00d6, {1|F|D, {0x00f6}}},
+ {0x00d8, {1|F|D, {0x00f8}}},
+ {0x00d9, {1|F|D, {0x00f9}}},
+ {0x00da, {1|F|D, {0x00fa}}},
+ {0x00db, {1|F|D, {0x00fb}}},
+ {0x00dc, {1|F|D, {0x00fc}}},
+ {0x00dd, {1|F|D, {0x00fd}}},
+ {0x00de, {1|F|D, {0x00fe}}},
+ {0x00df, {2|F|ST|SU|I(1), {0x0073, 0x0073}}},
+ {0x0100, {1|F|D, {0x0101}}},
+ {0x0102, {1|F|D, {0x0103}}},
+ {0x0104, {1|F|D, {0x0105}}},
+ {0x0106, {1|F|D, {0x0107}}},
+ {0x0108, {1|F|D, {0x0109}}},
+ {0x010a, {1|F|D, {0x010b}}},
+ {0x010c, {1|F|D, {0x010d}}},
+ {0x010e, {1|F|D, {0x010f}}},
+ {0x0110, {1|F|D, {0x0111}}},
+ {0x0112, {1|F|D, {0x0113}}},
+ {0x0114, {1|F|D, {0x0115}}},
+ {0x0116, {1|F|D, {0x0117}}},
+ {0x0118, {1|F|D, {0x0119}}},
+ {0x011a, {1|F|D, {0x011b}}},
+ {0x011c, {1|F|D, {0x011d}}},
+ {0x011e, {1|F|D, {0x011f}}},
+ {0x0120, {1|F|D, {0x0121}}},
+ {0x0122, {1|F|D, {0x0123}}},
+ {0x0124, {1|F|D, {0x0125}}},
+ {0x0126, {1|F|D, {0x0127}}},
+ {0x0128, {1|F|D, {0x0129}}},
+ {0x012a, {1|F|D, {0x012b}}},
+ {0x012c, {1|F|D, {0x012d}}},
+ {0x012e, {1|F|D, {0x012f}}},
+ {0x0132, {1|F|D, {0x0133}}},
+ {0x0134, {1|F|D, {0x0135}}},
+ {0x0136, {1|F|D, {0x0137}}},
+ {0x0139, {1|F|D, {0x013a}}},
+ {0x013b, {1|F|D, {0x013c}}},
+ {0x013d, {1|F|D, {0x013e}}},
+ {0x013f, {1|F|D, {0x0140}}},
+ {0x0141, {1|F|D, {0x0142}}},
+ {0x0143, {1|F|D, {0x0144}}},
+ {0x0145, {1|F|D, {0x0146}}},
+ {0x0147, {1|F|D, {0x0148}}},
+ {0x0149, {2|F|SU|I(5), {0x02bc, 0x006e}}},
+ {0x014a, {1|F|D, {0x014b}}},
+ {0x014c, {1|F|D, {0x014d}}},
+ {0x014e, {1|F|D, {0x014f}}},
+ {0x0150, {1|F|D, {0x0151}}},
+ {0x0152, {1|F|D, {0x0153}}},
+ {0x0154, {1|F|D, {0x0155}}},
+ {0x0156, {1|F|D, {0x0157}}},
+ {0x0158, {1|F|D, {0x0159}}},
+ {0x015a, {1|F|D, {0x015b}}},
+ {0x015c, {1|F|D, {0x015d}}},
+ {0x015e, {1|F|D, {0x015f}}},
+ {0x0160, {1|F|D, {0x0161}}},
+ {0x0162, {1|F|D, {0x0163}}},
+ {0x0164, {1|F|D, {0x0165}}},
+ {0x0166, {1|F|D, {0x0167}}},
+ {0x0168, {1|F|D, {0x0169}}},
+ {0x016a, {1|F|D, {0x016b}}},
+ {0x016c, {1|F|D, {0x016d}}},
+ {0x016e, {1|F|D, {0x016f}}},
+ {0x0170, {1|F|D, {0x0171}}},
+ {0x0172, {1|F|D, {0x0173}}},
+ {0x0174, {1|F|D, {0x0175}}},
+ {0x0176, {1|F|D, {0x0177}}},
+ {0x0178, {1|F|D, {0x00ff}}},
+ {0x0179, {1|F|D, {0x017a}}},
+ {0x017b, {1|F|D, {0x017c}}},
+ {0x017d, {1|F|D, {0x017e}}},
+ {0x017f, {1|F|SU|I(7), {0x0073}}},
+ {0x0181, {1|F|D, {0x0253}}},
+ {0x0182, {1|F|D, {0x0183}}},
+ {0x0184, {1|F|D, {0x0185}}},
+ {0x0186, {1|F|D, {0x0254}}},
+ {0x0187, {1|F|D, {0x0188}}},
+ {0x0189, {1|F|D, {0x0256}}},
+ {0x018a, {1|F|D, {0x0257}}},
+ {0x018b, {1|F|D, {0x018c}}},
+ {0x018e, {1|F|D, {0x01dd}}},
+ {0x018f, {1|F|D, {0x0259}}},
+ {0x0190, {1|F|D, {0x025b}}},
+ {0x0191, {1|F|D, {0x0192}}},
+ {0x0193, {1|F|D, {0x0260}}},
+ {0x0194, {1|F|D, {0x0263}}},
+ {0x0196, {1|F|D, {0x0269}}},
+ {0x0197, {1|F|D, {0x0268}}},
+ {0x0198, {1|F|D, {0x0199}}},
+ {0x019c, {1|F|D, {0x026f}}},
+ {0x019d, {1|F|D, {0x0272}}},
+ {0x019f, {1|F|D, {0x0275}}},
+ {0x01a0, {1|F|D, {0x01a1}}},
+ {0x01a2, {1|F|D, {0x01a3}}},
+ {0x01a4, {1|F|D, {0x01a5}}},
+ {0x01a6, {1|F|D, {0x0280}}},
+ {0x01a7, {1|F|D, {0x01a8}}},
+ {0x01a9, {1|F|D, {0x0283}}},
+ {0x01ac, {1|F|D, {0x01ad}}},
+ {0x01ae, {1|F|D, {0x0288}}},
+ {0x01af, {1|F|D, {0x01b0}}},
+ {0x01b1, {1|F|D, {0x028a}}},
+ {0x01b2, {1|F|D, {0x028b}}},
+ {0x01b3, {1|F|D, {0x01b4}}},
+ {0x01b5, {1|F|D, {0x01b6}}},
+ {0x01b7, {1|F|D, {0x0292}}},
+ {0x01b8, {1|F|D, {0x01b9}}},
+ {0x01bc, {1|F|D, {0x01bd}}},
+ {0x01c4, {1|F|D|ST|I(8), {0x01c6}}},
+ {0x01c5, {1|F|D|IT|SU|I(9), {0x01c6}}},
+ {0x01c7, {1|F|D|ST|I(12), {0x01c9}}},
+ {0x01c8, {1|F|D|IT|SU|I(13), {0x01c9}}},
+ {0x01ca, {1|F|D|ST|I(16), {0x01cc}}},
+ {0x01cb, {1|F|D|IT|SU|I(17), {0x01cc}}},
+ {0x01cd, {1|F|D, {0x01ce}}},
+ {0x01cf, {1|F|D, {0x01d0}}},
+ {0x01d1, {1|F|D, {0x01d2}}},
+ {0x01d3, {1|F|D, {0x01d4}}},
+ {0x01d5, {1|F|D, {0x01d6}}},
+ {0x01d7, {1|F|D, {0x01d8}}},
+ {0x01d9, {1|F|D, {0x01da}}},
+ {0x01db, {1|F|D, {0x01dc}}},
+ {0x01de, {1|F|D, {0x01df}}},
+ {0x01e0, {1|F|D, {0x01e1}}},
+ {0x01e2, {1|F|D, {0x01e3}}},
+ {0x01e4, {1|F|D, {0x01e5}}},
+ {0x01e6, {1|F|D, {0x01e7}}},
+ {0x01e8, {1|F|D, {0x01e9}}},
+ {0x01ea, {1|F|D, {0x01eb}}},
+ {0x01ec, {1|F|D, {0x01ed}}},
+ {0x01ee, {1|F|D, {0x01ef}}},
+ {0x01f0, {2|F|SU|I(20), {0x006a, 0x030c}}},
+ {0x01f1, {1|F|D|ST|I(22), {0x01f3}}},
+ {0x01f2, {1|F|D|IT|SU|I(23), {0x01f3}}},
+ {0x01f4, {1|F|D, {0x01f5}}},
+ {0x01f6, {1|F|D, {0x0195}}},
+ {0x01f7, {1|F|D, {0x01bf}}},
+ {0x01f8, {1|F|D, {0x01f9}}},
+ {0x01fa, {1|F|D, {0x01fb}}},
+ {0x01fc, {1|F|D, {0x01fd}}},
+ {0x01fe, {1|F|D, {0x01ff}}},
+ {0x0200, {1|F|D, {0x0201}}},
+ {0x0202, {1|F|D, {0x0203}}},
+ {0x0204, {1|F|D, {0x0205}}},
+ {0x0206, {1|F|D, {0x0207}}},
+ {0x0208, {1|F|D, {0x0209}}},
+ {0x020a, {1|F|D, {0x020b}}},
+ {0x020c, {1|F|D, {0x020d}}},
+ {0x020e, {1|F|D, {0x020f}}},
+ {0x0210, {1|F|D, {0x0211}}},
+ {0x0212, {1|F|D, {0x0213}}},
+ {0x0214, {1|F|D, {0x0215}}},
+ {0x0216, {1|F|D, {0x0217}}},
+ {0x0218, {1|F|D, {0x0219}}},
+ {0x021a, {1|F|D, {0x021b}}},
+ {0x021c, {1|F|D, {0x021d}}},
+ {0x021e, {1|F|D, {0x021f}}},
+ {0x0220, {1|F|D, {0x019e}}},
+ {0x0222, {1|F|D, {0x0223}}},
+ {0x0224, {1|F|D, {0x0225}}},
+ {0x0226, {1|F|D, {0x0227}}},
+ {0x0228, {1|F|D, {0x0229}}},
+ {0x022a, {1|F|D, {0x022b}}},
+ {0x022c, {1|F|D, {0x022d}}},
+ {0x022e, {1|F|D, {0x022f}}},
+ {0x0230, {1|F|D, {0x0231}}},
+ {0x0232, {1|F|D, {0x0233}}},
+ {0x023a, {1|F|D, {0x2c65}}},
+ {0x023b, {1|F|D, {0x023c}}},
+ {0x023d, {1|F|D, {0x019a}}},
+ {0x023e, {1|F|D, {0x2c66}}},
+ {0x0241, {1|F|D, {0x0242}}},
+ {0x0243, {1|F|D, {0x0180}}},
+ {0x0244, {1|F|D, {0x0289}}},
+ {0x0245, {1|F|D, {0x028c}}},
+ {0x0246, {1|F|D, {0x0247}}},
+ {0x0248, {1|F|D, {0x0249}}},
+ {0x024a, {1|F|D, {0x024b}}},
+ {0x024c, {1|F|D, {0x024d}}},
+ {0x024e, {1|F|D, {0x024f}}},
+ {0x0345, {1|F|SU|I(26), {0x03b9}}},
+ {0x0370, {1|F|D, {0x0371}}},
+ {0x0372, {1|F|D, {0x0373}}},
+ {0x0376, {1|F|D, {0x0377}}},
+ {0x037f, {1|F|D, {0x03f3}}},
+ {0x0386, {1|F|D, {0x03ac}}},
+ {0x0388, {1|F|D, {0x03ad}}},
+ {0x0389, {1|F|D, {0x03ae}}},
+ {0x038a, {1|F|D, {0x03af}}},
+ {0x038c, {1|F|D, {0x03cc}}},
+ {0x038e, {1|F|D, {0x03cd}}},
+ {0x038f, {1|F|D, {0x03ce}}},
+ {0x0390, {3|F|SU|I(27), {0x03b9, 0x0308, 0x0301}}},
+ {0x0391, {1|F|D, {0x03b1}}},
+ {0x0392, {1|F|D, {0x03b2}}},
+ {0x0393, {1|F|D, {0x03b3}}},
+ {0x0394, {1|F|D, {0x03b4}}},
+ {0x0395, {1|F|D, {0x03b5}}},
+ {0x0396, {1|F|D, {0x03b6}}},
+ {0x0397, {1|F|D, {0x03b7}}},
+ {0x0398, {1|F|D, {0x03b8}}},
+ {0x0399, {1|F|D, {0x03b9}}},
+ {0x039a, {1|F|D, {0x03ba}}},
+ {0x039b, {1|F|D, {0x03bb}}},
+ {0x039c, {1|F|D, {0x03bc}}},
+ {0x039d, {1|F|D, {0x03bd}}},
+ {0x039e, {1|F|D, {0x03be}}},
+ {0x039f, {1|F|D, {0x03bf}}},
+ {0x03a0, {1|F|D, {0x03c0}}},
+ {0x03a1, {1|F|D, {0x03c1}}},
+ {0x03a3, {1|F|D, {0x03c3}}},
+ {0x03a4, {1|F|D, {0x03c4}}},
+ {0x03a5, {1|F|D, {0x03c5}}},
+ {0x03a6, {1|F|D, {0x03c6}}},
+ {0x03a7, {1|F|D, {0x03c7}}},
+ {0x03a8, {1|F|D, {0x03c8}}},
+ {0x03a9, {1|F|D, {0x03c9}}},
+ {0x03aa, {1|F|D, {0x03ca}}},
+ {0x03ab, {1|F|D, {0x03cb}}},
+ {0x03b0, {3|F|SU|I(30), {0x03c5, 0x0308, 0x0301}}},
+ {0x03c2, {1|F|SU|I(33), {0x03c3}}},
+ {0x03cf, {1|F|D, {0x03d7}}},
+ {0x03d0, {1|F|SU|I(34), {0x03b2}}},
+ {0x03d1, {1|F|SU|I(35), {0x03b8}}},
+ {0x03d5, {1|F|SU|I(36), {0x03c6}}},
+ {0x03d6, {1|F|SU|I(37), {0x03c0}}},
+ {0x03d8, {1|F|D, {0x03d9}}},
+ {0x03da, {1|F|D, {0x03db}}},
+ {0x03dc, {1|F|D, {0x03dd}}},
+ {0x03de, {1|F|D, {0x03df}}},
+ {0x03e0, {1|F|D, {0x03e1}}},
+ {0x03e2, {1|F|D, {0x03e3}}},
+ {0x03e4, {1|F|D, {0x03e5}}},
+ {0x03e6, {1|F|D, {0x03e7}}},
+ {0x03e8, {1|F|D, {0x03e9}}},
+ {0x03ea, {1|F|D, {0x03eb}}},
+ {0x03ec, {1|F|D, {0x03ed}}},
+ {0x03ee, {1|F|D, {0x03ef}}},
+ {0x03f0, {1|F|SU|I(38), {0x03ba}}},
+ {0x03f1, {1|F|SU|I(39), {0x03c1}}},
+ {0x03f4, {1|F|D, {0x03b8}}},
+ {0x03f5, {1|F|SU|I(40), {0x03b5}}},
+ {0x03f7, {1|F|D, {0x03f8}}},
+ {0x03f9, {1|F|D, {0x03f2}}},
+ {0x03fa, {1|F|D, {0x03fb}}},
+ {0x03fd, {1|F|D, {0x037b}}},
+ {0x03fe, {1|F|D, {0x037c}}},
+ {0x03ff, {1|F|D, {0x037d}}},
+ {0x0400, {1|F|D, {0x0450}}},
+ {0x0401, {1|F|D, {0x0451}}},
+ {0x0402, {1|F|D, {0x0452}}},
+ {0x0403, {1|F|D, {0x0453}}},
+ {0x0404, {1|F|D, {0x0454}}},
+ {0x0405, {1|F|D, {0x0455}}},
+ {0x0406, {1|F|D, {0x0456}}},
+ {0x0407, {1|F|D, {0x0457}}},
+ {0x0408, {1|F|D, {0x0458}}},
+ {0x0409, {1|F|D, {0x0459}}},
+ {0x040a, {1|F|D, {0x045a}}},
+ {0x040b, {1|F|D, {0x045b}}},
+ {0x040c, {1|F|D, {0x045c}}},
+ {0x040d, {1|F|D, {0x045d}}},
+ {0x040e, {1|F|D, {0x045e}}},
+ {0x040f, {1|F|D, {0x045f}}},
+ {0x0410, {1|F|D, {0x0430}}},
+ {0x0411, {1|F|D, {0x0431}}},
+ {0x0412, {1|F|D, {0x0432}}},
+ {0x0413, {1|F|D, {0x0433}}},
+ {0x0414, {1|F|D, {0x0434}}},
+ {0x0415, {1|F|D, {0x0435}}},
+ {0x0416, {1|F|D, {0x0436}}},
+ {0x0417, {1|F|D, {0x0437}}},
+ {0x0418, {1|F|D, {0x0438}}},
+ {0x0419, {1|F|D, {0x0439}}},
+ {0x041a, {1|F|D, {0x043a}}},
+ {0x041b, {1|F|D, {0x043b}}},
+ {0x041c, {1|F|D, {0x043c}}},
+ {0x041d, {1|F|D, {0x043d}}},
+ {0x041e, {1|F|D, {0x043e}}},
+ {0x041f, {1|F|D, {0x043f}}},
+ {0x0420, {1|F|D, {0x0440}}},
+ {0x0421, {1|F|D, {0x0441}}},
+ {0x0422, {1|F|D, {0x0442}}},
+ {0x0423, {1|F|D, {0x0443}}},
+ {0x0424, {1|F|D, {0x0444}}},
+ {0x0425, {1|F|D, {0x0445}}},
+ {0x0426, {1|F|D, {0x0446}}},
+ {0x0427, {1|F|D, {0x0447}}},
+ {0x0428, {1|F|D, {0x0448}}},
+ {0x0429, {1|F|D, {0x0449}}},
+ {0x042a, {1|F|D, {0x044a}}},
+ {0x042b, {1|F|D, {0x044b}}},
+ {0x042c, {1|F|D, {0x044c}}},
+ {0x042d, {1|F|D, {0x044d}}},
+ {0x042e, {1|F|D, {0x044e}}},
+ {0x042f, {1|F|D, {0x044f}}},
+ {0x0460, {1|F|D, {0x0461}}},
+ {0x0462, {1|F|D, {0x0463}}},
+ {0x0464, {1|F|D, {0x0465}}},
+ {0x0466, {1|F|D, {0x0467}}},
+ {0x0468, {1|F|D, {0x0469}}},
+ {0x046a, {1|F|D, {0x046b}}},
+ {0x046c, {1|F|D, {0x046d}}},
+ {0x046e, {1|F|D, {0x046f}}},
+ {0x0470, {1|F|D, {0x0471}}},
+ {0x0472, {1|F|D, {0x0473}}},
+ {0x0474, {1|F|D, {0x0475}}},
+ {0x0476, {1|F|D, {0x0477}}},
+ {0x0478, {1|F|D, {0x0479}}},
+ {0x047a, {1|F|D, {0x047b}}},
+ {0x047c, {1|F|D, {0x047d}}},
+ {0x047e, {1|F|D, {0x047f}}},
+ {0x0480, {1|F|D, {0x0481}}},
+ {0x048a, {1|F|D, {0x048b}}},
+ {0x048c, {1|F|D, {0x048d}}},
+ {0x048e, {1|F|D, {0x048f}}},
+ {0x0490, {1|F|D, {0x0491}}},
+ {0x0492, {1|F|D, {0x0493}}},
+ {0x0494, {1|F|D, {0x0495}}},
+ {0x0496, {1|F|D, {0x0497}}},
+ {0x0498, {1|F|D, {0x0499}}},
+ {0x049a, {1|F|D, {0x049b}}},
+ {0x049c, {1|F|D, {0x049d}}},
+ {0x049e, {1|F|D, {0x049f}}},
+ {0x04a0, {1|F|D, {0x04a1}}},
+ {0x04a2, {1|F|D, {0x04a3}}},
+ {0x04a4, {1|F|D, {0x04a5}}},
+ {0x04a6, {1|F|D, {0x04a7}}},
+ {0x04a8, {1|F|D, {0x04a9}}},
+ {0x04aa, {1|F|D, {0x04ab}}},
+ {0x04ac, {1|F|D, {0x04ad}}},
+ {0x04ae, {1|F|D, {0x04af}}},
+ {0x04b0, {1|F|D, {0x04b1}}},
+ {0x04b2, {1|F|D, {0x04b3}}},
+ {0x04b4, {1|F|D, {0x04b5}}},
+ {0x04b6, {1|F|D, {0x04b7}}},
+ {0x04b8, {1|F|D, {0x04b9}}},
+ {0x04ba, {1|F|D, {0x04bb}}},
+ {0x04bc, {1|F|D, {0x04bd}}},
+ {0x04be, {1|F|D, {0x04bf}}},
+ {0x04c0, {1|F|D, {0x04cf}}},
+ {0x04c1, {1|F|D, {0x04c2}}},
+ {0x04c3, {1|F|D, {0x04c4}}},
+ {0x04c5, {1|F|D, {0x04c6}}},
+ {0x04c7, {1|F|D, {0x04c8}}},
+ {0x04c9, {1|F|D, {0x04ca}}},
+ {0x04cb, {1|F|D, {0x04cc}}},
+ {0x04cd, {1|F|D, {0x04ce}}},
+ {0x04d0, {1|F|D, {0x04d1}}},
+ {0x04d2, {1|F|D, {0x04d3}}},
+ {0x04d4, {1|F|D, {0x04d5}}},
+ {0x04d6, {1|F|D, {0x04d7}}},
+ {0x04d8, {1|F|D, {0x04d9}}},
+ {0x04da, {1|F|D, {0x04db}}},
+ {0x04dc, {1|F|D, {0x04dd}}},
+ {0x04de, {1|F|D, {0x04df}}},
+ {0x04e0, {1|F|D, {0x04e1}}},
+ {0x04e2, {1|F|D, {0x04e3}}},
+ {0x04e4, {1|F|D, {0x04e5}}},
+ {0x04e6, {1|F|D, {0x04e7}}},
+ {0x04e8, {1|F|D, {0x04e9}}},
+ {0x04ea, {1|F|D, {0x04eb}}},
+ {0x04ec, {1|F|D, {0x04ed}}},
+ {0x04ee, {1|F|D, {0x04ef}}},
+ {0x04f0, {1|F|D, {0x04f1}}},
+ {0x04f2, {1|F|D, {0x04f3}}},
+ {0x04f4, {1|F|D, {0x04f5}}},
+ {0x04f6, {1|F|D, {0x04f7}}},
+ {0x04f8, {1|F|D, {0x04f9}}},
+ {0x04fa, {1|F|D, {0x04fb}}},
+ {0x04fc, {1|F|D, {0x04fd}}},
+ {0x04fe, {1|F|D, {0x04ff}}},
+ {0x0500, {1|F|D, {0x0501}}},
+ {0x0502, {1|F|D, {0x0503}}},
+ {0x0504, {1|F|D, {0x0505}}},
+ {0x0506, {1|F|D, {0x0507}}},
+ {0x0508, {1|F|D, {0x0509}}},
+ {0x050a, {1|F|D, {0x050b}}},
+ {0x050c, {1|F|D, {0x050d}}},
+ {0x050e, {1|F|D, {0x050f}}},
+ {0x0510, {1|F|D, {0x0511}}},
+ {0x0512, {1|F|D, {0x0513}}},
+ {0x0514, {1|F|D, {0x0515}}},
+ {0x0516, {1|F|D, {0x0517}}},
+ {0x0518, {1|F|D, {0x0519}}},
+ {0x051a, {1|F|D, {0x051b}}},
+ {0x051c, {1|F|D, {0x051d}}},
+ {0x051e, {1|F|D, {0x051f}}},
+ {0x0520, {1|F|D, {0x0521}}},
+ {0x0522, {1|F|D, {0x0523}}},
+ {0x0524, {1|F|D, {0x0525}}},
+ {0x0526, {1|F|D, {0x0527}}},
+ {0x0528, {1|F|D, {0x0529}}},
+ {0x052a, {1|F|D, {0x052b}}},
+ {0x052c, {1|F|D, {0x052d}}},
+ {0x052e, {1|F|D, {0x052f}}},
+ {0x0531, {1|F|D, {0x0561}}},
+ {0x0532, {1|F|D, {0x0562}}},
+ {0x0533, {1|F|D, {0x0563}}},
+ {0x0534, {1|F|D, {0x0564}}},
+ {0x0535, {1|F|D, {0x0565}}},
+ {0x0536, {1|F|D, {0x0566}}},
+ {0x0537, {1|F|D, {0x0567}}},
+ {0x0538, {1|F|D, {0x0568}}},
+ {0x0539, {1|F|D, {0x0569}}},
+ {0x053a, {1|F|D, {0x056a}}},
+ {0x053b, {1|F|D, {0x056b}}},
+ {0x053c, {1|F|D, {0x056c}}},
+ {0x053d, {1|F|D, {0x056d}}},
+ {0x053e, {1|F|D, {0x056e}}},
+ {0x053f, {1|F|D, {0x056f}}},
+ {0x0540, {1|F|D, {0x0570}}},
+ {0x0541, {1|F|D, {0x0571}}},
+ {0x0542, {1|F|D, {0x0572}}},
+ {0x0543, {1|F|D, {0x0573}}},
+ {0x0544, {1|F|D, {0x0574}}},
+ {0x0545, {1|F|D, {0x0575}}},
+ {0x0546, {1|F|D, {0x0576}}},
+ {0x0547, {1|F|D, {0x0577}}},
+ {0x0548, {1|F|D, {0x0578}}},
+ {0x0549, {1|F|D, {0x0579}}},
+ {0x054a, {1|F|D, {0x057a}}},
+ {0x054b, {1|F|D, {0x057b}}},
+ {0x054c, {1|F|D, {0x057c}}},
+ {0x054d, {1|F|D, {0x057d}}},
+ {0x054e, {1|F|D, {0x057e}}},
+ {0x054f, {1|F|D, {0x057f}}},
+ {0x0550, {1|F|D, {0x0580}}},
+ {0x0551, {1|F|D, {0x0581}}},
+ {0x0552, {1|F|D, {0x0582}}},
+ {0x0553, {1|F|D, {0x0583}}},
+ {0x0554, {1|F|D, {0x0584}}},
+ {0x0555, {1|F|D, {0x0585}}},
+ {0x0556, {1|F|D, {0x0586}}},
+ {0x0587, {2|F|ST|SU|I(41), {0x0565, 0x0582}}},
+ {0x10a0, {1|F|D, {0x2d00}}},
+ {0x10a1, {1|F|D, {0x2d01}}},
+ {0x10a2, {1|F|D, {0x2d02}}},
+ {0x10a3, {1|F|D, {0x2d03}}},
+ {0x10a4, {1|F|D, {0x2d04}}},
+ {0x10a5, {1|F|D, {0x2d05}}},
+ {0x10a6, {1|F|D, {0x2d06}}},
+ {0x10a7, {1|F|D, {0x2d07}}},
+ {0x10a8, {1|F|D, {0x2d08}}},
+ {0x10a9, {1|F|D, {0x2d09}}},
+ {0x10aa, {1|F|D, {0x2d0a}}},
+ {0x10ab, {1|F|D, {0x2d0b}}},
+ {0x10ac, {1|F|D, {0x2d0c}}},
+ {0x10ad, {1|F|D, {0x2d0d}}},
+ {0x10ae, {1|F|D, {0x2d0e}}},
+ {0x10af, {1|F|D, {0x2d0f}}},
+ {0x10b0, {1|F|D, {0x2d10}}},
+ {0x10b1, {1|F|D, {0x2d11}}},
+ {0x10b2, {1|F|D, {0x2d12}}},
+ {0x10b3, {1|F|D, {0x2d13}}},
+ {0x10b4, {1|F|D, {0x2d14}}},
+ {0x10b5, {1|F|D, {0x2d15}}},
+ {0x10b6, {1|F|D, {0x2d16}}},
+ {0x10b7, {1|F|D, {0x2d17}}},
+ {0x10b8, {1|F|D, {0x2d18}}},
+ {0x10b9, {1|F|D, {0x2d19}}},
+ {0x10ba, {1|F|D, {0x2d1a}}},
+ {0x10bb, {1|F|D, {0x2d1b}}},
+ {0x10bc, {1|F|D, {0x2d1c}}},
+ {0x10bd, {1|F|D, {0x2d1d}}},
+ {0x10be, {1|F|D, {0x2d1e}}},
+ {0x10bf, {1|F|D, {0x2d1f}}},
+ {0x10c0, {1|F|D, {0x2d20}}},
+ {0x10c1, {1|F|D, {0x2d21}}},
+ {0x10c2, {1|F|D, {0x2d22}}},
+ {0x10c3, {1|F|D, {0x2d23}}},
+ {0x10c4, {1|F|D, {0x2d24}}},
+ {0x10c5, {1|F|D, {0x2d25}}},
+ {0x10c7, {1|F|D, {0x2d27}}},
+ {0x10cd, {1|F|D, {0x2d2d}}},
+ {0x13f8, {1|F|U, {0x13f0}}},
+ {0x13f9, {1|F|U, {0x13f1}}},
+ {0x13fa, {1|F|U, {0x13f2}}},
+ {0x13fb, {1|F|U, {0x13f3}}},
+ {0x13fc, {1|F|U, {0x13f4}}},
+ {0x13fd, {1|F|U, {0x13f5}}},
+ {0x1c80, {1|F|SU|I(45), {0x0432}}},
+ {0x1c81, {1|F|SU|I(46), {0x0434}}},
+ {0x1c82, {1|F|SU|I(47), {0x043e}}},
+ {0x1c83, {1|F|SU|I(48), {0x0441}}},
+ {0x1c84, {1|F|SU|I(49), {0x0442}}},
+ {0x1c85, {1|F|SU|I(50), {0x0442}}},
+ {0x1c86, {1|F|SU|I(51), {0x044a}}},
+ {0x1c87, {1|F|SU|I(52), {0x0463}}},
+ {0x1c88, {1|F|SU|I(53), {0xa64b}}},
+ {0x1c89, {1|F|D, {0x1c8a}}},
+ {0x1c90, {1|F|D, {0x10d0}}},
+ {0x1c91, {1|F|D, {0x10d1}}},
+ {0x1c92, {1|F|D, {0x10d2}}},
+ {0x1c93, {1|F|D, {0x10d3}}},
+ {0x1c94, {1|F|D, {0x10d4}}},
+ {0x1c95, {1|F|D, {0x10d5}}},
+ {0x1c96, {1|F|D, {0x10d6}}},
+ {0x1c97, {1|F|D, {0x10d7}}},
+ {0x1c98, {1|F|D, {0x10d8}}},
+ {0x1c99, {1|F|D, {0x10d9}}},
+ {0x1c9a, {1|F|D, {0x10da}}},
+ {0x1c9b, {1|F|D, {0x10db}}},
+ {0x1c9c, {1|F|D, {0x10dc}}},
+ {0x1c9d, {1|F|D, {0x10dd}}},
+ {0x1c9e, {1|F|D, {0x10de}}},
+ {0x1c9f, {1|F|D, {0x10df}}},
+ {0x1ca0, {1|F|D, {0x10e0}}},
+ {0x1ca1, {1|F|D, {0x10e1}}},
+ {0x1ca2, {1|F|D, {0x10e2}}},
+ {0x1ca3, {1|F|D, {0x10e3}}},
+ {0x1ca4, {1|F|D, {0x10e4}}},
+ {0x1ca5, {1|F|D, {0x10e5}}},
+ {0x1ca6, {1|F|D, {0x10e6}}},
+ {0x1ca7, {1|F|D, {0x10e7}}},
+ {0x1ca8, {1|F|D, {0x10e8}}},
+ {0x1ca9, {1|F|D, {0x10e9}}},
+ {0x1caa, {1|F|D, {0x10ea}}},
+ {0x1cab, {1|F|D, {0x10eb}}},
+ {0x1cac, {1|F|D, {0x10ec}}},
+ {0x1cad, {1|F|D, {0x10ed}}},
+ {0x1cae, {1|F|D, {0x10ee}}},
+ {0x1caf, {1|F|D, {0x10ef}}},
+ {0x1cb0, {1|F|D, {0x10f0}}},
+ {0x1cb1, {1|F|D, {0x10f1}}},
+ {0x1cb2, {1|F|D, {0x10f2}}},
+ {0x1cb3, {1|F|D, {0x10f3}}},
+ {0x1cb4, {1|F|D, {0x10f4}}},
+ {0x1cb5, {1|F|D, {0x10f5}}},
+ {0x1cb6, {1|F|D, {0x10f6}}},
+ {0x1cb7, {1|F|D, {0x10f7}}},
+ {0x1cb8, {1|F|D, {0x10f8}}},
+ {0x1cb9, {1|F|D, {0x10f9}}},
+ {0x1cba, {1|F|D, {0x10fa}}},
+ {0x1cbd, {1|F|D, {0x10fd}}},
+ {0x1cbe, {1|F|D, {0x10fe}}},
+ {0x1cbf, {1|F|D, {0x10ff}}},
+ {0x1e00, {1|F|D, {0x1e01}}},
+ {0x1e02, {1|F|D, {0x1e03}}},
+ {0x1e04, {1|F|D, {0x1e05}}},
+ {0x1e06, {1|F|D, {0x1e07}}},
+ {0x1e08, {1|F|D, {0x1e09}}},
+ {0x1e0a, {1|F|D, {0x1e0b}}},
+ {0x1e0c, {1|F|D, {0x1e0d}}},
+ {0x1e0e, {1|F|D, {0x1e0f}}},
+ {0x1e10, {1|F|D, {0x1e11}}},
+ {0x1e12, {1|F|D, {0x1e13}}},
+ {0x1e14, {1|F|D, {0x1e15}}},
+ {0x1e16, {1|F|D, {0x1e17}}},
+ {0x1e18, {1|F|D, {0x1e19}}},
+ {0x1e1a, {1|F|D, {0x1e1b}}},
+ {0x1e1c, {1|F|D, {0x1e1d}}},
+ {0x1e1e, {1|F|D, {0x1e1f}}},
+ {0x1e20, {1|F|D, {0x1e21}}},
+ {0x1e22, {1|F|D, {0x1e23}}},
+ {0x1e24, {1|F|D, {0x1e25}}},
+ {0x1e26, {1|F|D, {0x1e27}}},
+ {0x1e28, {1|F|D, {0x1e29}}},
+ {0x1e2a, {1|F|D, {0x1e2b}}},
+ {0x1e2c, {1|F|D, {0x1e2d}}},
+ {0x1e2e, {1|F|D, {0x1e2f}}},
+ {0x1e30, {1|F|D, {0x1e31}}},
+ {0x1e32, {1|F|D, {0x1e33}}},
+ {0x1e34, {1|F|D, {0x1e35}}},
+ {0x1e36, {1|F|D, {0x1e37}}},
+ {0x1e38, {1|F|D, {0x1e39}}},
+ {0x1e3a, {1|F|D, {0x1e3b}}},
+ {0x1e3c, {1|F|D, {0x1e3d}}},
+ {0x1e3e, {1|F|D, {0x1e3f}}},
+ {0x1e40, {1|F|D, {0x1e41}}},
+ {0x1e42, {1|F|D, {0x1e43}}},
+ {0x1e44, {1|F|D, {0x1e45}}},
+ {0x1e46, {1|F|D, {0x1e47}}},
+ {0x1e48, {1|F|D, {0x1e49}}},
+ {0x1e4a, {1|F|D, {0x1e4b}}},
+ {0x1e4c, {1|F|D, {0x1e4d}}},
+ {0x1e4e, {1|F|D, {0x1e4f}}},
+ {0x1e50, {1|F|D, {0x1e51}}},
+ {0x1e52, {1|F|D, {0x1e53}}},
+ {0x1e54, {1|F|D, {0x1e55}}},
+ {0x1e56, {1|F|D, {0x1e57}}},
+ {0x1e58, {1|F|D, {0x1e59}}},
+ {0x1e5a, {1|F|D, {0x1e5b}}},
+ {0x1e5c, {1|F|D, {0x1e5d}}},
+ {0x1e5e, {1|F|D, {0x1e5f}}},
+ {0x1e60, {1|F|D, {0x1e61}}},
+ {0x1e62, {1|F|D, {0x1e63}}},
+ {0x1e64, {1|F|D, {0x1e65}}},
+ {0x1e66, {1|F|D, {0x1e67}}},
+ {0x1e68, {1|F|D, {0x1e69}}},
+ {0x1e6a, {1|F|D, {0x1e6b}}},
+ {0x1e6c, {1|F|D, {0x1e6d}}},
+ {0x1e6e, {1|F|D, {0x1e6f}}},
+ {0x1e70, {1|F|D, {0x1e71}}},
+ {0x1e72, {1|F|D, {0x1e73}}},
+ {0x1e74, {1|F|D, {0x1e75}}},
+ {0x1e76, {1|F|D, {0x1e77}}},
+ {0x1e78, {1|F|D, {0x1e79}}},
+ {0x1e7a, {1|F|D, {0x1e7b}}},
+ {0x1e7c, {1|F|D, {0x1e7d}}},
+ {0x1e7e, {1|F|D, {0x1e7f}}},
+ {0x1e80, {1|F|D, {0x1e81}}},
+ {0x1e82, {1|F|D, {0x1e83}}},
+ {0x1e84, {1|F|D, {0x1e85}}},
+ {0x1e86, {1|F|D, {0x1e87}}},
+ {0x1e88, {1|F|D, {0x1e89}}},
+ {0x1e8a, {1|F|D, {0x1e8b}}},
+ {0x1e8c, {1|F|D, {0x1e8d}}},
+ {0x1e8e, {1|F|D, {0x1e8f}}},
+ {0x1e90, {1|F|D, {0x1e91}}},
+ {0x1e92, {1|F|D, {0x1e93}}},
+ {0x1e94, {1|F|D, {0x1e95}}},
+ {0x1e96, {2|F|SU|I(54), {0x0068, 0x0331}}},
+ {0x1e97, {2|F|SU|I(56), {0x0074, 0x0308}}},
+ {0x1e98, {2|F|SU|I(58), {0x0077, 0x030a}}},
+ {0x1e99, {2|F|SU|I(60), {0x0079, 0x030a}}},
+ {0x1e9a, {2|F|SU|I(62), {0x0061, 0x02be}}},
+ {0x1e9b, {1|F|SU|I(64), {0x1e61}}},
+ {0x1e9e, {2|F|SL|I(65), {0x0073, 0x0073}}},
+ {0x1ea0, {1|F|D, {0x1ea1}}},
+ {0x1ea2, {1|F|D, {0x1ea3}}},
+ {0x1ea4, {1|F|D, {0x1ea5}}},
+ {0x1ea6, {1|F|D, {0x1ea7}}},
+ {0x1ea8, {1|F|D, {0x1ea9}}},
+ {0x1eaa, {1|F|D, {0x1eab}}},
+ {0x1eac, {1|F|D, {0x1ead}}},
+ {0x1eae, {1|F|D, {0x1eaf}}},
+ {0x1eb0, {1|F|D, {0x1eb1}}},
+ {0x1eb2, {1|F|D, {0x1eb3}}},
+ {0x1eb4, {1|F|D, {0x1eb5}}},
+ {0x1eb6, {1|F|D, {0x1eb7}}},
+ {0x1eb8, {1|F|D, {0x1eb9}}},
+ {0x1eba, {1|F|D, {0x1ebb}}},
+ {0x1ebc, {1|F|D, {0x1ebd}}},
+ {0x1ebe, {1|F|D, {0x1ebf}}},
+ {0x1ec0, {1|F|D, {0x1ec1}}},
+ {0x1ec2, {1|F|D, {0x1ec3}}},
+ {0x1ec4, {1|F|D, {0x1ec5}}},
+ {0x1ec6, {1|F|D, {0x1ec7}}},
+ {0x1ec8, {1|F|D, {0x1ec9}}},
+ {0x1eca, {1|F|D, {0x1ecb}}},
+ {0x1ecc, {1|F|D, {0x1ecd}}},
+ {0x1ece, {1|F|D, {0x1ecf}}},
+ {0x1ed0, {1|F|D, {0x1ed1}}},
+ {0x1ed2, {1|F|D, {0x1ed3}}},
+ {0x1ed4, {1|F|D, {0x1ed5}}},
+ {0x1ed6, {1|F|D, {0x1ed7}}},
+ {0x1ed8, {1|F|D, {0x1ed9}}},
+ {0x1eda, {1|F|D, {0x1edb}}},
+ {0x1edc, {1|F|D, {0x1edd}}},
+ {0x1ede, {1|F|D, {0x1edf}}},
+ {0x1ee0, {1|F|D, {0x1ee1}}},
+ {0x1ee2, {1|F|D, {0x1ee3}}},
+ {0x1ee4, {1|F|D, {0x1ee5}}},
+ {0x1ee6, {1|F|D, {0x1ee7}}},
+ {0x1ee8, {1|F|D, {0x1ee9}}},
+ {0x1eea, {1|F|D, {0x1eeb}}},
+ {0x1eec, {1|F|D, {0x1eed}}},
+ {0x1eee, {1|F|D, {0x1eef}}},
+ {0x1ef0, {1|F|D, {0x1ef1}}},
+ {0x1ef2, {1|F|D, {0x1ef3}}},
+ {0x1ef4, {1|F|D, {0x1ef5}}},
+ {0x1ef6, {1|F|D, {0x1ef7}}},
+ {0x1ef8, {1|F|D, {0x1ef9}}},
+ {0x1efa, {1|F|D, {0x1efb}}},
+ {0x1efc, {1|F|D, {0x1efd}}},
+ {0x1efe, {1|F|D, {0x1eff}}},
+ {0x1f08, {1|F|D, {0x1f00}}},
+ {0x1f09, {1|F|D, {0x1f01}}},
+ {0x1f0a, {1|F|D, {0x1f02}}},
+ {0x1f0b, {1|F|D, {0x1f03}}},
+ {0x1f0c, {1|F|D, {0x1f04}}},
+ {0x1f0d, {1|F|D, {0x1f05}}},
+ {0x1f0e, {1|F|D, {0x1f06}}},
+ {0x1f0f, {1|F|D, {0x1f07}}},
+ {0x1f18, {1|F|D, {0x1f10}}},
+ {0x1f19, {1|F|D, {0x1f11}}},
+ {0x1f1a, {1|F|D, {0x1f12}}},
+ {0x1f1b, {1|F|D, {0x1f13}}},
+ {0x1f1c, {1|F|D, {0x1f14}}},
+ {0x1f1d, {1|F|D, {0x1f15}}},
+ {0x1f28, {1|F|D, {0x1f20}}},
+ {0x1f29, {1|F|D, {0x1f21}}},
+ {0x1f2a, {1|F|D, {0x1f22}}},
+ {0x1f2b, {1|F|D, {0x1f23}}},
+ {0x1f2c, {1|F|D, {0x1f24}}},
+ {0x1f2d, {1|F|D, {0x1f25}}},
+ {0x1f2e, {1|F|D, {0x1f26}}},
+ {0x1f2f, {1|F|D, {0x1f27}}},
+ {0x1f38, {1|F|D, {0x1f30}}},
+ {0x1f39, {1|F|D, {0x1f31}}},
+ {0x1f3a, {1|F|D, {0x1f32}}},
+ {0x1f3b, {1|F|D, {0x1f33}}},
+ {0x1f3c, {1|F|D, {0x1f34}}},
+ {0x1f3d, {1|F|D, {0x1f35}}},
+ {0x1f3e, {1|F|D, {0x1f36}}},
+ {0x1f3f, {1|F|D, {0x1f37}}},
+ {0x1f48, {1|F|D, {0x1f40}}},
+ {0x1f49, {1|F|D, {0x1f41}}},
+ {0x1f4a, {1|F|D, {0x1f42}}},
+ {0x1f4b, {1|F|D, {0x1f43}}},
+ {0x1f4c, {1|F|D, {0x1f44}}},
+ {0x1f4d, {1|F|D, {0x1f45}}},
+ {0x1f50, {2|F|SU|I(66), {0x03c5, 0x0313}}},
+ {0x1f52, {3|F|SU|I(68), {0x03c5, 0x0313, 0x0300}}},
+ {0x1f54, {3|F|SU|I(71), {0x03c5, 0x0313, 0x0301}}},
+ {0x1f56, {3|F|SU|I(74), {0x03c5, 0x0313, 0x0342}}},
+ {0x1f59, {1|F|D, {0x1f51}}},
+ {0x1f5b, {1|F|D, {0x1f53}}},
+ {0x1f5d, {1|F|D, {0x1f55}}},
+ {0x1f5f, {1|F|D, {0x1f57}}},
+ {0x1f68, {1|F|D, {0x1f60}}},
+ {0x1f69, {1|F|D, {0x1f61}}},
+ {0x1f6a, {1|F|D, {0x1f62}}},
+ {0x1f6b, {1|F|D, {0x1f63}}},
+ {0x1f6c, {1|F|D, {0x1f64}}},
+ {0x1f6d, {1|F|D, {0x1f65}}},
+ {0x1f6e, {1|F|D, {0x1f66}}},
+ {0x1f6f, {1|F|D, {0x1f67}}},
+ {0x1f80, {2|F|ST|SU|I(77), {0x1f00, 0x03b9}}},
+ {0x1f81, {2|F|ST|SU|I(80), {0x1f01, 0x03b9}}},
+ {0x1f82, {2|F|ST|SU|I(83), {0x1f02, 0x03b9}}},
+ {0x1f83, {2|F|ST|SU|I(86), {0x1f03, 0x03b9}}},
+ {0x1f84, {2|F|ST|SU|I(89), {0x1f04, 0x03b9}}},
+ {0x1f85, {2|F|ST|SU|I(92), {0x1f05, 0x03b9}}},
+ {0x1f86, {2|F|ST|SU|I(95), {0x1f06, 0x03b9}}},
+ {0x1f87, {2|F|ST|SU|I(98), {0x1f07, 0x03b9}}},
+ {0x1f88, {2|F|IT|SL|SU|I(101), {0x1f00, 0x03b9}}},
+ {0x1f89, {2|F|IT|SL|SU|I(106), {0x1f01, 0x03b9}}},
+ {0x1f8a, {2|F|IT|SL|SU|I(111), {0x1f02, 0x03b9}}},
+ {0x1f8b, {2|F|IT|SL|SU|I(116), {0x1f03, 0x03b9}}},
+ {0x1f8c, {2|F|IT|SL|SU|I(121), {0x1f04, 0x03b9}}},
+ {0x1f8d, {2|F|IT|SL|SU|I(126), {0x1f05, 0x03b9}}},
+ {0x1f8e, {2|F|IT|SL|SU|I(131), {0x1f06, 0x03b9}}},
+ {0x1f8f, {2|F|IT|SL|SU|I(136), {0x1f07, 0x03b9}}},
+ {0x1f90, {2|F|ST|SU|I(141), {0x1f20, 0x03b9}}},
+ {0x1f91, {2|F|ST|SU|I(144), {0x1f21, 0x03b9}}},
+ {0x1f92, {2|F|ST|SU|I(147), {0x1f22, 0x03b9}}},
+ {0x1f93, {2|F|ST|SU|I(150), {0x1f23, 0x03b9}}},
+ {0x1f94, {2|F|ST|SU|I(153), {0x1f24, 0x03b9}}},
+ {0x1f95, {2|F|ST|SU|I(156), {0x1f25, 0x03b9}}},
+ {0x1f96, {2|F|ST|SU|I(159), {0x1f26, 0x03b9}}},
+ {0x1f97, {2|F|ST|SU|I(162), {0x1f27, 0x03b9}}},
+ {0x1f98, {2|F|IT|SL|SU|I(165), {0x1f20, 0x03b9}}},
+ {0x1f99, {2|F|IT|SL|SU|I(170), {0x1f21, 0x03b9}}},
+ {0x1f9a, {2|F|IT|SL|SU|I(175), {0x1f22, 0x03b9}}},
+ {0x1f9b, {2|F|IT|SL|SU|I(180), {0x1f23, 0x03b9}}},
+ {0x1f9c, {2|F|IT|SL|SU|I(185), {0x1f24, 0x03b9}}},
+ {0x1f9d, {2|F|IT|SL|SU|I(190), {0x1f25, 0x03b9}}},
+ {0x1f9e, {2|F|IT|SL|SU|I(195), {0x1f26, 0x03b9}}},
+ {0x1f9f, {2|F|IT|SL|SU|I(200), {0x1f27, 0x03b9}}},
+ {0x1fa0, {2|F|ST|SU|I(205), {0x1f60, 0x03b9}}},
+ {0x1fa1, {2|F|ST|SU|I(208), {0x1f61, 0x03b9}}},
+ {0x1fa2, {2|F|ST|SU|I(211), {0x1f62, 0x03b9}}},
+ {0x1fa3, {2|F|ST|SU|I(214), {0x1f63, 0x03b9}}},
+ {0x1fa4, {2|F|ST|SU|I(217), {0x1f64, 0x03b9}}},
+ {0x1fa5, {2|F|ST|SU|I(220), {0x1f65, 0x03b9}}},
+ {0x1fa6, {2|F|ST|SU|I(223), {0x1f66, 0x03b9}}},
+ {0x1fa7, {2|F|ST|SU|I(226), {0x1f67, 0x03b9}}},
+ {0x1fa8, {2|F|IT|SL|SU|I(229), {0x1f60, 0x03b9}}},
+ {0x1fa9, {2|F|IT|SL|SU|I(234), {0x1f61, 0x03b9}}},
+ {0x1faa, {2|F|IT|SL|SU|I(239), {0x1f62, 0x03b9}}},
+ {0x1fab, {2|F|IT|SL|SU|I(244), {0x1f63, 0x03b9}}},
+ {0x1fac, {2|F|IT|SL|SU|I(249), {0x1f64, 0x03b9}}},
+ {0x1fad, {2|F|IT|SL|SU|I(254), {0x1f65, 0x03b9}}},
+ {0x1fae, {2|F|IT|SL|SU|I(259), {0x1f66, 0x03b9}}},
+ {0x1faf, {2|F|IT|SL|SU|I(264), {0x1f67, 0x03b9}}},
+ {0x1fb2, {2|F|ST|SU|I(269), {0x1f70, 0x03b9}}},
+ {0x1fb3, {2|F|ST|SU|I(273), {0x03b1, 0x03b9}}},
+ {0x1fb4, {2|F|ST|SU|I(276), {0x03ac, 0x03b9}}},
+ {0x1fb6, {2|F|SU|I(280), {0x03b1, 0x0342}}},
+ {0x1fb7, {3|F|ST|SU|I(282), {0x03b1, 0x0342, 0x03b9}}},
+ {0x1fb8, {1|F|D, {0x1fb0}}},
+ {0x1fb9, {1|F|D, {0x1fb1}}},
+ {0x1fba, {1|F|D, {0x1f70}}},
+ {0x1fbb, {1|F|D, {0x1f71}}},
+ {0x1fbc, {2|F|IT|SL|SU|I(288), {0x03b1, 0x03b9}}},
+ {0x1fbe, {1|F|SU|I(293), {0x03b9}}},
+ {0x1fc2, {2|F|ST|SU|I(294), {0x1f74, 0x03b9}}},
+ {0x1fc3, {2|F|ST|SU|I(298), {0x03b7, 0x03b9}}},
+ {0x1fc4, {2|F|ST|SU|I(301), {0x03ae, 0x03b9}}},
+ {0x1fc6, {2|F|SU|I(305), {0x03b7, 0x0342}}},
+ {0x1fc7, {3|F|ST|SU|I(307), {0x03b7, 0x0342, 0x03b9}}},
+ {0x1fc8, {1|F|D, {0x1f72}}},
+ {0x1fc9, {1|F|D, {0x1f73}}},
+ {0x1fca, {1|F|D, {0x1f74}}},
+ {0x1fcb, {1|F|D, {0x1f75}}},
+ {0x1fcc, {2|F|IT|SL|SU|I(313), {0x03b7, 0x03b9}}},
+ {0x1fd2, {3|F|SU|I(318), {0x03b9, 0x0308, 0x0300}}},
+ {0x1fd3, {3|F|SU|I(321), {0x03b9, 0x0308, 0x0301}}},
+ {0x1fd6, {2|F|SU|I(324), {0x03b9, 0x0342}}},
+ {0x1fd7, {3|F|SU|I(326), {0x03b9, 0x0308, 0x0342}}},
+ {0x1fd8, {1|F|D, {0x1fd0}}},
+ {0x1fd9, {1|F|D, {0x1fd1}}},
+ {0x1fda, {1|F|D, {0x1f76}}},
+ {0x1fdb, {1|F|D, {0x1f77}}},
+ {0x1fe2, {3|F|SU|I(329), {0x03c5, 0x0308, 0x0300}}},
+ {0x1fe3, {3|F|SU|I(332), {0x03c5, 0x0308, 0x0301}}},
+ {0x1fe4, {2|F|SU|I(335), {0x03c1, 0x0313}}},
+ {0x1fe6, {2|F|SU|I(337), {0x03c5, 0x0342}}},
+ {0x1fe7, {3|F|SU|I(339), {0x03c5, 0x0308, 0x0342}}},
+ {0x1fe8, {1|F|D, {0x1fe0}}},
+ {0x1fe9, {1|F|D, {0x1fe1}}},
+ {0x1fea, {1|F|D, {0x1f7a}}},
+ {0x1feb, {1|F|D, {0x1f7b}}},
+ {0x1fec, {1|F|D, {0x1fe5}}},
+ {0x1ff2, {2|F|ST|SU|I(342), {0x1f7c, 0x03b9}}},
+ {0x1ff3, {2|F|ST|SU|I(346), {0x03c9, 0x03b9}}},
+ {0x1ff4, {2|F|ST|SU|I(349), {0x03ce, 0x03b9}}},
+ {0x1ff6, {2|F|SU|I(353), {0x03c9, 0x0342}}},
+ {0x1ff7, {3|F|ST|SU|I(355), {0x03c9, 0x0342, 0x03b9}}},
+ {0x1ff8, {1|F|D, {0x1f78}}},
+ {0x1ff9, {1|F|D, {0x1f79}}},
+ {0x1ffa, {1|F|D, {0x1f7c}}},
+ {0x1ffb, {1|F|D, {0x1f7d}}},
+ {0x1ffc, {2|F|IT|SL|SU|I(361), {0x03c9, 0x03b9}}},
+ {0x2126, {1|F|D, {0x03c9}}},
+ {0x212a, {1|F|D, {0x006b}}},
+ {0x212b, {1|F|D, {0x00e5}}},
+ {0x2132, {1|F|D, {0x214e}}},
+ {0x2160, {1|F|D, {0x2170}}},
+ {0x2161, {1|F|D, {0x2171}}},
+ {0x2162, {1|F|D, {0x2172}}},
+ {0x2163, {1|F|D, {0x2173}}},
+ {0x2164, {1|F|D, {0x2174}}},
+ {0x2165, {1|F|D, {0x2175}}},
+ {0x2166, {1|F|D, {0x2176}}},
+ {0x2167, {1|F|D, {0x2177}}},
+ {0x2168, {1|F|D, {0x2178}}},
+ {0x2169, {1|F|D, {0x2179}}},
+ {0x216a, {1|F|D, {0x217a}}},
+ {0x216b, {1|F|D, {0x217b}}},
+ {0x216c, {1|F|D, {0x217c}}},
+ {0x216d, {1|F|D, {0x217d}}},
+ {0x216e, {1|F|D, {0x217e}}},
+ {0x216f, {1|F|D, {0x217f}}},
+ {0x2183, {1|F|D, {0x2184}}},
+ {0x24b6, {1|F|D, {0x24d0}}},
+ {0x24b7, {1|F|D, {0x24d1}}},
+ {0x24b8, {1|F|D, {0x24d2}}},
+ {0x24b9, {1|F|D, {0x24d3}}},
+ {0x24ba, {1|F|D, {0x24d4}}},
+ {0x24bb, {1|F|D, {0x24d5}}},
+ {0x24bc, {1|F|D, {0x24d6}}},
+ {0x24bd, {1|F|D, {0x24d7}}},
+ {0x24be, {1|F|D, {0x24d8}}},
+ {0x24bf, {1|F|D, {0x24d9}}},
+ {0x24c0, {1|F|D, {0x24da}}},
+ {0x24c1, {1|F|D, {0x24db}}},
+ {0x24c2, {1|F|D, {0x24dc}}},
+ {0x24c3, {1|F|D, {0x24dd}}},
+ {0x24c4, {1|F|D, {0x24de}}},
+ {0x24c5, {1|F|D, {0x24df}}},
+ {0x24c6, {1|F|D, {0x24e0}}},
+ {0x24c7, {1|F|D, {0x24e1}}},
+ {0x24c8, {1|F|D, {0x24e2}}},
+ {0x24c9, {1|F|D, {0x24e3}}},
+ {0x24ca, {1|F|D, {0x24e4}}},
+ {0x24cb, {1|F|D, {0x24e5}}},
+ {0x24cc, {1|F|D, {0x24e6}}},
+ {0x24cd, {1|F|D, {0x24e7}}},
+ {0x24ce, {1|F|D, {0x24e8}}},
+ {0x24cf, {1|F|D, {0x24e9}}},
+ {0x2c00, {1|F|D, {0x2c30}}},
+ {0x2c01, {1|F|D, {0x2c31}}},
+ {0x2c02, {1|F|D, {0x2c32}}},
+ {0x2c03, {1|F|D, {0x2c33}}},
+ {0x2c04, {1|F|D, {0x2c34}}},
+ {0x2c05, {1|F|D, {0x2c35}}},
+ {0x2c06, {1|F|D, {0x2c36}}},
+ {0x2c07, {1|F|D, {0x2c37}}},
+ {0x2c08, {1|F|D, {0x2c38}}},
+ {0x2c09, {1|F|D, {0x2c39}}},
+ {0x2c0a, {1|F|D, {0x2c3a}}},
+ {0x2c0b, {1|F|D, {0x2c3b}}},
+ {0x2c0c, {1|F|D, {0x2c3c}}},
+ {0x2c0d, {1|F|D, {0x2c3d}}},
+ {0x2c0e, {1|F|D, {0x2c3e}}},
+ {0x2c0f, {1|F|D, {0x2c3f}}},
+ {0x2c10, {1|F|D, {0x2c40}}},
+ {0x2c11, {1|F|D, {0x2c41}}},
+ {0x2c12, {1|F|D, {0x2c42}}},
+ {0x2c13, {1|F|D, {0x2c43}}},
+ {0x2c14, {1|F|D, {0x2c44}}},
+ {0x2c15, {1|F|D, {0x2c45}}},
+ {0x2c16, {1|F|D, {0x2c46}}},
+ {0x2c17, {1|F|D, {0x2c47}}},
+ {0x2c18, {1|F|D, {0x2c48}}},
+ {0x2c19, {1|F|D, {0x2c49}}},
+ {0x2c1a, {1|F|D, {0x2c4a}}},
+ {0x2c1b, {1|F|D, {0x2c4b}}},
+ {0x2c1c, {1|F|D, {0x2c4c}}},
+ {0x2c1d, {1|F|D, {0x2c4d}}},
+ {0x2c1e, {1|F|D, {0x2c4e}}},
+ {0x2c1f, {1|F|D, {0x2c4f}}},
+ {0x2c20, {1|F|D, {0x2c50}}},
+ {0x2c21, {1|F|D, {0x2c51}}},
+ {0x2c22, {1|F|D, {0x2c52}}},
+ {0x2c23, {1|F|D, {0x2c53}}},
+ {0x2c24, {1|F|D, {0x2c54}}},
+ {0x2c25, {1|F|D, {0x2c55}}},
+ {0x2c26, {1|F|D, {0x2c56}}},
+ {0x2c27, {1|F|D, {0x2c57}}},
+ {0x2c28, {1|F|D, {0x2c58}}},
+ {0x2c29, {1|F|D, {0x2c59}}},
+ {0x2c2a, {1|F|D, {0x2c5a}}},
+ {0x2c2b, {1|F|D, {0x2c5b}}},
+ {0x2c2c, {1|F|D, {0x2c5c}}},
+ {0x2c2d, {1|F|D, {0x2c5d}}},
+ {0x2c2e, {1|F|D, {0x2c5e}}},
+ {0x2c2f, {1|F|D, {0x2c5f}}},
+ {0x2c60, {1|F|D, {0x2c61}}},
+ {0x2c62, {1|F|D, {0x026b}}},
+ {0x2c63, {1|F|D, {0x1d7d}}},
+ {0x2c64, {1|F|D, {0x027d}}},
+ {0x2c67, {1|F|D, {0x2c68}}},
+ {0x2c69, {1|F|D, {0x2c6a}}},
+ {0x2c6b, {1|F|D, {0x2c6c}}},
+ {0x2c6d, {1|F|D, {0x0251}}},
+ {0x2c6e, {1|F|D, {0x0271}}},
+ {0x2c6f, {1|F|D, {0x0250}}},
+ {0x2c70, {1|F|D, {0x0252}}},
+ {0x2c72, {1|F|D, {0x2c73}}},
+ {0x2c75, {1|F|D, {0x2c76}}},
+ {0x2c7e, {1|F|D, {0x023f}}},
+ {0x2c7f, {1|F|D, {0x0240}}},
+ {0x2c80, {1|F|D, {0x2c81}}},
+ {0x2c82, {1|F|D, {0x2c83}}},
+ {0x2c84, {1|F|D, {0x2c85}}},
+ {0x2c86, {1|F|D, {0x2c87}}},
+ {0x2c88, {1|F|D, {0x2c89}}},
+ {0x2c8a, {1|F|D, {0x2c8b}}},
+ {0x2c8c, {1|F|D, {0x2c8d}}},
+ {0x2c8e, {1|F|D, {0x2c8f}}},
+ {0x2c90, {1|F|D, {0x2c91}}},
+ {0x2c92, {1|F|D, {0x2c93}}},
+ {0x2c94, {1|F|D, {0x2c95}}},
+ {0x2c96, {1|F|D, {0x2c97}}},
+ {0x2c98, {1|F|D, {0x2c99}}},
+ {0x2c9a, {1|F|D, {0x2c9b}}},
+ {0x2c9c, {1|F|D, {0x2c9d}}},
+ {0x2c9e, {1|F|D, {0x2c9f}}},
+ {0x2ca0, {1|F|D, {0x2ca1}}},
+ {0x2ca2, {1|F|D, {0x2ca3}}},
+ {0x2ca4, {1|F|D, {0x2ca5}}},
+ {0x2ca6, {1|F|D, {0x2ca7}}},
+ {0x2ca8, {1|F|D, {0x2ca9}}},
+ {0x2caa, {1|F|D, {0x2cab}}},
+ {0x2cac, {1|F|D, {0x2cad}}},
+ {0x2cae, {1|F|D, {0x2caf}}},
+ {0x2cb0, {1|F|D, {0x2cb1}}},
+ {0x2cb2, {1|F|D, {0x2cb3}}},
+ {0x2cb4, {1|F|D, {0x2cb5}}},
+ {0x2cb6, {1|F|D, {0x2cb7}}},
+ {0x2cb8, {1|F|D, {0x2cb9}}},
+ {0x2cba, {1|F|D, {0x2cbb}}},
+ {0x2cbc, {1|F|D, {0x2cbd}}},
+ {0x2cbe, {1|F|D, {0x2cbf}}},
+ {0x2cc0, {1|F|D, {0x2cc1}}},
+ {0x2cc2, {1|F|D, {0x2cc3}}},
+ {0x2cc4, {1|F|D, {0x2cc5}}},
+ {0x2cc6, {1|F|D, {0x2cc7}}},
+ {0x2cc8, {1|F|D, {0x2cc9}}},
+ {0x2cca, {1|F|D, {0x2ccb}}},
+ {0x2ccc, {1|F|D, {0x2ccd}}},
+ {0x2cce, {1|F|D, {0x2ccf}}},
+ {0x2cd0, {1|F|D, {0x2cd1}}},
+ {0x2cd2, {1|F|D, {0x2cd3}}},
+ {0x2cd4, {1|F|D, {0x2cd5}}},
+ {0x2cd6, {1|F|D, {0x2cd7}}},
+ {0x2cd8, {1|F|D, {0x2cd9}}},
+ {0x2cda, {1|F|D, {0x2cdb}}},
+ {0x2cdc, {1|F|D, {0x2cdd}}},
+ {0x2cde, {1|F|D, {0x2cdf}}},
+ {0x2ce0, {1|F|D, {0x2ce1}}},
+ {0x2ce2, {1|F|D, {0x2ce3}}},
+ {0x2ceb, {1|F|D, {0x2cec}}},
+ {0x2ced, {1|F|D, {0x2cee}}},
+ {0x2cf2, {1|F|D, {0x2cf3}}},
+ {0xa640, {1|F|D, {0xa641}}},
+ {0xa642, {1|F|D, {0xa643}}},
+ {0xa644, {1|F|D, {0xa645}}},
+ {0xa646, {1|F|D, {0xa647}}},
+ {0xa648, {1|F|D, {0xa649}}},
+ {0xa64a, {1|F|D, {0xa64b}}},
+ {0xa64c, {1|F|D, {0xa64d}}},
+ {0xa64e, {1|F|D, {0xa64f}}},
+ {0xa650, {1|F|D, {0xa651}}},
+ {0xa652, {1|F|D, {0xa653}}},
+ {0xa654, {1|F|D, {0xa655}}},
+ {0xa656, {1|F|D, {0xa657}}},
+ {0xa658, {1|F|D, {0xa659}}},
+ {0xa65a, {1|F|D, {0xa65b}}},
+ {0xa65c, {1|F|D, {0xa65d}}},
+ {0xa65e, {1|F|D, {0xa65f}}},
+ {0xa660, {1|F|D, {0xa661}}},
+ {0xa662, {1|F|D, {0xa663}}},
+ {0xa664, {1|F|D, {0xa665}}},
+ {0xa666, {1|F|D, {0xa667}}},
+ {0xa668, {1|F|D, {0xa669}}},
+ {0xa66a, {1|F|D, {0xa66b}}},
+ {0xa66c, {1|F|D, {0xa66d}}},
+ {0xa680, {1|F|D, {0xa681}}},
+ {0xa682, {1|F|D, {0xa683}}},
+ {0xa684, {1|F|D, {0xa685}}},
+ {0xa686, {1|F|D, {0xa687}}},
+ {0xa688, {1|F|D, {0xa689}}},
+ {0xa68a, {1|F|D, {0xa68b}}},
+ {0xa68c, {1|F|D, {0xa68d}}},
+ {0xa68e, {1|F|D, {0xa68f}}},
+ {0xa690, {1|F|D, {0xa691}}},
+ {0xa692, {1|F|D, {0xa693}}},
+ {0xa694, {1|F|D, {0xa695}}},
+ {0xa696, {1|F|D, {0xa697}}},
+ {0xa698, {1|F|D, {0xa699}}},
+ {0xa69a, {1|F|D, {0xa69b}}},
+ {0xa722, {1|F|D, {0xa723}}},
+ {0xa724, {1|F|D, {0xa725}}},
+ {0xa726, {1|F|D, {0xa727}}},
+ {0xa728, {1|F|D, {0xa729}}},
+ {0xa72a, {1|F|D, {0xa72b}}},
+ {0xa72c, {1|F|D, {0xa72d}}},
+ {0xa72e, {1|F|D, {0xa72f}}},
+ {0xa732, {1|F|D, {0xa733}}},
+ {0xa734, {1|F|D, {0xa735}}},
+ {0xa736, {1|F|D, {0xa737}}},
+ {0xa738, {1|F|D, {0xa739}}},
+ {0xa73a, {1|F|D, {0xa73b}}},
+ {0xa73c, {1|F|D, {0xa73d}}},
+ {0xa73e, {1|F|D, {0xa73f}}},
+ {0xa740, {1|F|D, {0xa741}}},
+ {0xa742, {1|F|D, {0xa743}}},
+ {0xa744, {1|F|D, {0xa745}}},
+ {0xa746, {1|F|D, {0xa747}}},
+ {0xa748, {1|F|D, {0xa749}}},
+ {0xa74a, {1|F|D, {0xa74b}}},
+ {0xa74c, {1|F|D, {0xa74d}}},
+ {0xa74e, {1|F|D, {0xa74f}}},
+ {0xa750, {1|F|D, {0xa751}}},
+ {0xa752, {1|F|D, {0xa753}}},
+ {0xa754, {1|F|D, {0xa755}}},
+ {0xa756, {1|F|D, {0xa757}}},
+ {0xa758, {1|F|D, {0xa759}}},
+ {0xa75a, {1|F|D, {0xa75b}}},
+ {0xa75c, {1|F|D, {0xa75d}}},
+ {0xa75e, {1|F|D, {0xa75f}}},
+ {0xa760, {1|F|D, {0xa761}}},
+ {0xa762, {1|F|D, {0xa763}}},
+ {0xa764, {1|F|D, {0xa765}}},
+ {0xa766, {1|F|D, {0xa767}}},
+ {0xa768, {1|F|D, {0xa769}}},
+ {0xa76a, {1|F|D, {0xa76b}}},
+ {0xa76c, {1|F|D, {0xa76d}}},
+ {0xa76e, {1|F|D, {0xa76f}}},
+ {0xa779, {1|F|D, {0xa77a}}},
+ {0xa77b, {1|F|D, {0xa77c}}},
+ {0xa77d, {1|F|D, {0x1d79}}},
+ {0xa77e, {1|F|D, {0xa77f}}},
+ {0xa780, {1|F|D, {0xa781}}},
+ {0xa782, {1|F|D, {0xa783}}},
+ {0xa784, {1|F|D, {0xa785}}},
+ {0xa786, {1|F|D, {0xa787}}},
+ {0xa78b, {1|F|D, {0xa78c}}},
+ {0xa78d, {1|F|D, {0x0265}}},
+ {0xa790, {1|F|D, {0xa791}}},
+ {0xa792, {1|F|D, {0xa793}}},
+ {0xa796, {1|F|D, {0xa797}}},
+ {0xa798, {1|F|D, {0xa799}}},
+ {0xa79a, {1|F|D, {0xa79b}}},
+ {0xa79c, {1|F|D, {0xa79d}}},
+ {0xa79e, {1|F|D, {0xa79f}}},
+ {0xa7a0, {1|F|D, {0xa7a1}}},
+ {0xa7a2, {1|F|D, {0xa7a3}}},
+ {0xa7a4, {1|F|D, {0xa7a5}}},
+ {0xa7a6, {1|F|D, {0xa7a7}}},
+ {0xa7a8, {1|F|D, {0xa7a9}}},
+ {0xa7aa, {1|F|D, {0x0266}}},
+ {0xa7ab, {1|F|D, {0x025c}}},
+ {0xa7ac, {1|F|D, {0x0261}}},
+ {0xa7ad, {1|F|D, {0x026c}}},
+ {0xa7ae, {1|F|D, {0x026a}}},
+ {0xa7b0, {1|F|D, {0x029e}}},
+ {0xa7b1, {1|F|D, {0x0287}}},
+ {0xa7b2, {1|F|D, {0x029d}}},
+ {0xa7b3, {1|F|D, {0xab53}}},
+ {0xa7b4, {1|F|D, {0xa7b5}}},
+ {0xa7b6, {1|F|D, {0xa7b7}}},
+ {0xa7b8, {1|F|D, {0xa7b9}}},
+ {0xa7ba, {1|F|D, {0xa7bb}}},
+ {0xa7bc, {1|F|D, {0xa7bd}}},
+ {0xa7be, {1|F|D, {0xa7bf}}},
+ {0xa7c0, {1|F|D, {0xa7c1}}},
+ {0xa7c2, {1|F|D, {0xa7c3}}},
+ {0xa7c4, {1|F|D, {0xa794}}},
+ {0xa7c5, {1|F|D, {0x0282}}},
+ {0xa7c6, {1|F|D, {0x1d8e}}},
+ {0xa7c7, {1|F|D, {0xa7c8}}},
+ {0xa7c9, {1|F|D, {0xa7ca}}},
+ {0xa7cb, {1|F|D, {0x0264}}},
+ {0xa7cc, {1|F|D, {0xa7cd}}},
+ {0xa7ce, {1|F|D, {0xa7cf}}},
+ {0xa7d0, {1|F|D, {0xa7d1}}},
+ {0xa7d2, {1|F|D, {0xa7d3}}},
+ {0xa7d4, {1|F|D, {0xa7d5}}},
+ {0xa7d6, {1|F|D, {0xa7d7}}},
+ {0xa7d8, {1|F|D, {0xa7d9}}},
+ {0xa7da, {1|F|D, {0xa7db}}},
+ {0xa7dc, {1|F|D, {0x019b}}},
+ {0xa7f5, {1|F|D, {0xa7f6}}},
+ {0xab70, {1|F|U, {0x13a0}}},
+ {0xab71, {1|F|U, {0x13a1}}},
+ {0xab72, {1|F|U, {0x13a2}}},
+ {0xab73, {1|F|U, {0x13a3}}},
+ {0xab74, {1|F|U, {0x13a4}}},
+ {0xab75, {1|F|U, {0x13a5}}},
+ {0xab76, {1|F|U, {0x13a6}}},
+ {0xab77, {1|F|U, {0x13a7}}},
+ {0xab78, {1|F|U, {0x13a8}}},
+ {0xab79, {1|F|U, {0x13a9}}},
+ {0xab7a, {1|F|U, {0x13aa}}},
+ {0xab7b, {1|F|U, {0x13ab}}},
+ {0xab7c, {1|F|U, {0x13ac}}},
+ {0xab7d, {1|F|U, {0x13ad}}},
+ {0xab7e, {1|F|U, {0x13ae}}},
+ {0xab7f, {1|F|U, {0x13af}}},
+ {0xab80, {1|F|U, {0x13b0}}},
+ {0xab81, {1|F|U, {0x13b1}}},
+ {0xab82, {1|F|U, {0x13b2}}},
+ {0xab83, {1|F|U, {0x13b3}}},
+ {0xab84, {1|F|U, {0x13b4}}},
+ {0xab85, {1|F|U, {0x13b5}}},
+ {0xab86, {1|F|U, {0x13b6}}},
+ {0xab87, {1|F|U, {0x13b7}}},
+ {0xab88, {1|F|U, {0x13b8}}},
+ {0xab89, {1|F|U, {0x13b9}}},
+ {0xab8a, {1|F|U, {0x13ba}}},
+ {0xab8b, {1|F|U, {0x13bb}}},
+ {0xab8c, {1|F|U, {0x13bc}}},
+ {0xab8d, {1|F|U, {0x13bd}}},
+ {0xab8e, {1|F|U, {0x13be}}},
+ {0xab8f, {1|F|U, {0x13bf}}},
+ {0xab90, {1|F|U, {0x13c0}}},
+ {0xab91, {1|F|U, {0x13c1}}},
+ {0xab92, {1|F|U, {0x13c2}}},
+ {0xab93, {1|F|U, {0x13c3}}},
+ {0xab94, {1|F|U, {0x13c4}}},
+ {0xab95, {1|F|U, {0x13c5}}},
+ {0xab96, {1|F|U, {0x13c6}}},
+ {0xab97, {1|F|U, {0x13c7}}},
+ {0xab98, {1|F|U, {0x13c8}}},
+ {0xab99, {1|F|U, {0x13c9}}},
+ {0xab9a, {1|F|U, {0x13ca}}},
+ {0xab9b, {1|F|U, {0x13cb}}},
+ {0xab9c, {1|F|U, {0x13cc}}},
+ {0xab9d, {1|F|U, {0x13cd}}},
+ {0xab9e, {1|F|U, {0x13ce}}},
+ {0xab9f, {1|F|U, {0x13cf}}},
+ {0xaba0, {1|F|U, {0x13d0}}},
+ {0xaba1, {1|F|U, {0x13d1}}},
+ {0xaba2, {1|F|U, {0x13d2}}},
+ {0xaba3, {1|F|U, {0x13d3}}},
+ {0xaba4, {1|F|U, {0x13d4}}},
+ {0xaba5, {1|F|U, {0x13d5}}},
+ {0xaba6, {1|F|U, {0x13d6}}},
+ {0xaba7, {1|F|U, {0x13d7}}},
+ {0xaba8, {1|F|U, {0x13d8}}},
+ {0xaba9, {1|F|U, {0x13d9}}},
+ {0xabaa, {1|F|U, {0x13da}}},
+ {0xabab, {1|F|U, {0x13db}}},
+ {0xabac, {1|F|U, {0x13dc}}},
+ {0xabad, {1|F|U, {0x13dd}}},
+ {0xabae, {1|F|U, {0x13de}}},
+ {0xabaf, {1|F|U, {0x13df}}},
+ {0xabb0, {1|F|U, {0x13e0}}},
+ {0xabb1, {1|F|U, {0x13e1}}},
+ {0xabb2, {1|F|U, {0x13e2}}},
+ {0xabb3, {1|F|U, {0x13e3}}},
+ {0xabb4, {1|F|U, {0x13e4}}},
+ {0xabb5, {1|F|U, {0x13e5}}},
+ {0xabb6, {1|F|U, {0x13e6}}},
+ {0xabb7, {1|F|U, {0x13e7}}},
+ {0xabb8, {1|F|U, {0x13e8}}},
+ {0xabb9, {1|F|U, {0x13e9}}},
+ {0xabba, {1|F|U, {0x13ea}}},
+ {0xabbb, {1|F|U, {0x13eb}}},
+ {0xabbc, {1|F|U, {0x13ec}}},
+ {0xabbd, {1|F|U, {0x13ed}}},
+ {0xabbe, {1|F|U, {0x13ee}}},
+ {0xabbf, {1|F|U, {0x13ef}}},
+ {0xfb00, {2|F|ST|SU|I(366), {0x0066, 0x0066}}},
+ {0xfb01, {2|F|ST|SU|I(370), {0x0066, 0x0069}}},
+ {0xfb02, {2|F|ST|SU|I(374), {0x0066, 0x006c}}},
+ {0xfb03, {3|F|ST|SU|I(378), {0x0066, 0x0066, 0x0069}}},
+ {0xfb04, {3|F|ST|SU|I(384), {0x0066, 0x0066, 0x006c}}},
+ {0xfb05, {2|F|ST|SU|I(390), {0x0073, 0x0074}}},
+ {0xfb06, {2|F|ST|SU|I(394), {0x0073, 0x0074}}},
+ {0xfb13, {2|F|ST|SU|I(398), {0x0574, 0x0576}}},
+ {0xfb14, {2|F|ST|SU|I(402), {0x0574, 0x0565}}},
+ {0xfb15, {2|F|ST|SU|I(406), {0x0574, 0x056b}}},
+ {0xfb16, {2|F|ST|SU|I(410), {0x057e, 0x0576}}},
+ {0xfb17, {2|F|ST|SU|I(414), {0x0574, 0x056d}}},
+ {0xff21, {1|F|D, {0xff41}}},
+ {0xff22, {1|F|D, {0xff42}}},
+ {0xff23, {1|F|D, {0xff43}}},
+ {0xff24, {1|F|D, {0xff44}}},
+ {0xff25, {1|F|D, {0xff45}}},
+ {0xff26, {1|F|D, {0xff46}}},
+ {0xff27, {1|F|D, {0xff47}}},
+ {0xff28, {1|F|D, {0xff48}}},
+ {0xff29, {1|F|D, {0xff49}}},
+ {0xff2a, {1|F|D, {0xff4a}}},
+ {0xff2b, {1|F|D, {0xff4b}}},
+ {0xff2c, {1|F|D, {0xff4c}}},
+ {0xff2d, {1|F|D, {0xff4d}}},
+ {0xff2e, {1|F|D, {0xff4e}}},
+ {0xff2f, {1|F|D, {0xff4f}}},
+ {0xff30, {1|F|D, {0xff50}}},
+ {0xff31, {1|F|D, {0xff51}}},
+ {0xff32, {1|F|D, {0xff52}}},
+ {0xff33, {1|F|D, {0xff53}}},
+ {0xff34, {1|F|D, {0xff54}}},
+ {0xff35, {1|F|D, {0xff55}}},
+ {0xff36, {1|F|D, {0xff56}}},
+ {0xff37, {1|F|D, {0xff57}}},
+ {0xff38, {1|F|D, {0xff58}}},
+ {0xff39, {1|F|D, {0xff59}}},
+ {0xff3a, {1|F|D, {0xff5a}}},
+ {0x10400, {1|F|D, {0x10428}}},
+ {0x10401, {1|F|D, {0x10429}}},
+ {0x10402, {1|F|D, {0x1042a}}},
+ {0x10403, {1|F|D, {0x1042b}}},
+ {0x10404, {1|F|D, {0x1042c}}},
+ {0x10405, {1|F|D, {0x1042d}}},
+ {0x10406, {1|F|D, {0x1042e}}},
+ {0x10407, {1|F|D, {0x1042f}}},
+ {0x10408, {1|F|D, {0x10430}}},
+ {0x10409, {1|F|D, {0x10431}}},
+ {0x1040a, {1|F|D, {0x10432}}},
+ {0x1040b, {1|F|D, {0x10433}}},
+ {0x1040c, {1|F|D, {0x10434}}},
+ {0x1040d, {1|F|D, {0x10435}}},
+ {0x1040e, {1|F|D, {0x10436}}},
+ {0x1040f, {1|F|D, {0x10437}}},
+ {0x10410, {1|F|D, {0x10438}}},
+ {0x10411, {1|F|D, {0x10439}}},
+ {0x10412, {1|F|D, {0x1043a}}},
+ {0x10413, {1|F|D, {0x1043b}}},
+ {0x10414, {1|F|D, {0x1043c}}},
+ {0x10415, {1|F|D, {0x1043d}}},
+ {0x10416, {1|F|D, {0x1043e}}},
+ {0x10417, {1|F|D, {0x1043f}}},
+ {0x10418, {1|F|D, {0x10440}}},
+ {0x10419, {1|F|D, {0x10441}}},
+ {0x1041a, {1|F|D, {0x10442}}},
+ {0x1041b, {1|F|D, {0x10443}}},
+ {0x1041c, {1|F|D, {0x10444}}},
+ {0x1041d, {1|F|D, {0x10445}}},
+ {0x1041e, {1|F|D, {0x10446}}},
+ {0x1041f, {1|F|D, {0x10447}}},
+ {0x10420, {1|F|D, {0x10448}}},
+ {0x10421, {1|F|D, {0x10449}}},
+ {0x10422, {1|F|D, {0x1044a}}},
+ {0x10423, {1|F|D, {0x1044b}}},
+ {0x10424, {1|F|D, {0x1044c}}},
+ {0x10425, {1|F|D, {0x1044d}}},
+ {0x10426, {1|F|D, {0x1044e}}},
+ {0x10427, {1|F|D, {0x1044f}}},
+ {0x104b0, {1|F|D, {0x104d8}}},
+ {0x104b1, {1|F|D, {0x104d9}}},
+ {0x104b2, {1|F|D, {0x104da}}},
+ {0x104b3, {1|F|D, {0x104db}}},
+ {0x104b4, {1|F|D, {0x104dc}}},
+ {0x104b5, {1|F|D, {0x104dd}}},
+ {0x104b6, {1|F|D, {0x104de}}},
+ {0x104b7, {1|F|D, {0x104df}}},
+ {0x104b8, {1|F|D, {0x104e0}}},
+ {0x104b9, {1|F|D, {0x104e1}}},
+ {0x104ba, {1|F|D, {0x104e2}}},
+ {0x104bb, {1|F|D, {0x104e3}}},
+ {0x104bc, {1|F|D, {0x104e4}}},
+ {0x104bd, {1|F|D, {0x104e5}}},
+ {0x104be, {1|F|D, {0x104e6}}},
+ {0x104bf, {1|F|D, {0x104e7}}},
+ {0x104c0, {1|F|D, {0x104e8}}},
+ {0x104c1, {1|F|D, {0x104e9}}},
+ {0x104c2, {1|F|D, {0x104ea}}},
+ {0x104c3, {1|F|D, {0x104eb}}},
+ {0x104c4, {1|F|D, {0x104ec}}},
+ {0x104c5, {1|F|D, {0x104ed}}},
+ {0x104c6, {1|F|D, {0x104ee}}},
+ {0x104c7, {1|F|D, {0x104ef}}},
+ {0x104c8, {1|F|D, {0x104f0}}},
+ {0x104c9, {1|F|D, {0x104f1}}},
+ {0x104ca, {1|F|D, {0x104f2}}},
+ {0x104cb, {1|F|D, {0x104f3}}},
+ {0x104cc, {1|F|D, {0x104f4}}},
+ {0x104cd, {1|F|D, {0x104f5}}},
+ {0x104ce, {1|F|D, {0x104f6}}},
+ {0x104cf, {1|F|D, {0x104f7}}},
+ {0x104d0, {1|F|D, {0x104f8}}},
+ {0x104d1, {1|F|D, {0x104f9}}},
+ {0x104d2, {1|F|D, {0x104fa}}},
+ {0x104d3, {1|F|D, {0x104fb}}},
+ {0x10570, {1|F|D, {0x10597}}},
+ {0x10571, {1|F|D, {0x10598}}},
+ {0x10572, {1|F|D, {0x10599}}},
+ {0x10573, {1|F|D, {0x1059a}}},
+ {0x10574, {1|F|D, {0x1059b}}},
+ {0x10575, {1|F|D, {0x1059c}}},
+ {0x10576, {1|F|D, {0x1059d}}},
+ {0x10577, {1|F|D, {0x1059e}}},
+ {0x10578, {1|F|D, {0x1059f}}},
+ {0x10579, {1|F|D, {0x105a0}}},
+ {0x1057a, {1|F|D, {0x105a1}}},
+ {0x1057c, {1|F|D, {0x105a3}}},
+ {0x1057d, {1|F|D, {0x105a4}}},
+ {0x1057e, {1|F|D, {0x105a5}}},
+ {0x1057f, {1|F|D, {0x105a6}}},
+ {0x10580, {1|F|D, {0x105a7}}},
+ {0x10581, {1|F|D, {0x105a8}}},
+ {0x10582, {1|F|D, {0x105a9}}},
+ {0x10583, {1|F|D, {0x105aa}}},
+ {0x10584, {1|F|D, {0x105ab}}},
+ {0x10585, {1|F|D, {0x105ac}}},
+ {0x10586, {1|F|D, {0x105ad}}},
+ {0x10587, {1|F|D, {0x105ae}}},
+ {0x10588, {1|F|D, {0x105af}}},
+ {0x10589, {1|F|D, {0x105b0}}},
+ {0x1058a, {1|F|D, {0x105b1}}},
+ {0x1058c, {1|F|D, {0x105b3}}},
+ {0x1058d, {1|F|D, {0x105b4}}},
+ {0x1058e, {1|F|D, {0x105b5}}},
+ {0x1058f, {1|F|D, {0x105b6}}},
+ {0x10590, {1|F|D, {0x105b7}}},
+ {0x10591, {1|F|D, {0x105b8}}},
+ {0x10592, {1|F|D, {0x105b9}}},
+ {0x10594, {1|F|D, {0x105bb}}},
+ {0x10595, {1|F|D, {0x105bc}}},
+ {0x10c80, {1|F|D, {0x10cc0}}},
+ {0x10c81, {1|F|D, {0x10cc1}}},
+ {0x10c82, {1|F|D, {0x10cc2}}},
+ {0x10c83, {1|F|D, {0x10cc3}}},
+ {0x10c84, {1|F|D, {0x10cc4}}},
+ {0x10c85, {1|F|D, {0x10cc5}}},
+ {0x10c86, {1|F|D, {0x10cc6}}},
+ {0x10c87, {1|F|D, {0x10cc7}}},
+ {0x10c88, {1|F|D, {0x10cc8}}},
+ {0x10c89, {1|F|D, {0x10cc9}}},
+ {0x10c8a, {1|F|D, {0x10cca}}},
+ {0x10c8b, {1|F|D, {0x10ccb}}},
+ {0x10c8c, {1|F|D, {0x10ccc}}},
+ {0x10c8d, {1|F|D, {0x10ccd}}},
+ {0x10c8e, {1|F|D, {0x10cce}}},
+ {0x10c8f, {1|F|D, {0x10ccf}}},
+ {0x10c90, {1|F|D, {0x10cd0}}},
+ {0x10c91, {1|F|D, {0x10cd1}}},
+ {0x10c92, {1|F|D, {0x10cd2}}},
+ {0x10c93, {1|F|D, {0x10cd3}}},
+ {0x10c94, {1|F|D, {0x10cd4}}},
+ {0x10c95, {1|F|D, {0x10cd5}}},
+ {0x10c96, {1|F|D, {0x10cd6}}},
+ {0x10c97, {1|F|D, {0x10cd7}}},
+ {0x10c98, {1|F|D, {0x10cd8}}},
+ {0x10c99, {1|F|D, {0x10cd9}}},
+ {0x10c9a, {1|F|D, {0x10cda}}},
+ {0x10c9b, {1|F|D, {0x10cdb}}},
+ {0x10c9c, {1|F|D, {0x10cdc}}},
+ {0x10c9d, {1|F|D, {0x10cdd}}},
+ {0x10c9e, {1|F|D, {0x10cde}}},
+ {0x10c9f, {1|F|D, {0x10cdf}}},
+ {0x10ca0, {1|F|D, {0x10ce0}}},
+ {0x10ca1, {1|F|D, {0x10ce1}}},
+ {0x10ca2, {1|F|D, {0x10ce2}}},
+ {0x10ca3, {1|F|D, {0x10ce3}}},
+ {0x10ca4, {1|F|D, {0x10ce4}}},
+ {0x10ca5, {1|F|D, {0x10ce5}}},
+ {0x10ca6, {1|F|D, {0x10ce6}}},
+ {0x10ca7, {1|F|D, {0x10ce7}}},
+ {0x10ca8, {1|F|D, {0x10ce8}}},
+ {0x10ca9, {1|F|D, {0x10ce9}}},
+ {0x10caa, {1|F|D, {0x10cea}}},
+ {0x10cab, {1|F|D, {0x10ceb}}},
+ {0x10cac, {1|F|D, {0x10cec}}},
+ {0x10cad, {1|F|D, {0x10ced}}},
+ {0x10cae, {1|F|D, {0x10cee}}},
+ {0x10caf, {1|F|D, {0x10cef}}},
+ {0x10cb0, {1|F|D, {0x10cf0}}},
+ {0x10cb1, {1|F|D, {0x10cf1}}},
+ {0x10cb2, {1|F|D, {0x10cf2}}},
+ {0x10d50, {1|F|D, {0x10d70}}},
+ {0x10d51, {1|F|D, {0x10d71}}},
+ {0x10d52, {1|F|D, {0x10d72}}},
+ {0x10d53, {1|F|D, {0x10d73}}},
+ {0x10d54, {1|F|D, {0x10d74}}},
+ {0x10d55, {1|F|D, {0x10d75}}},
+ {0x10d56, {1|F|D, {0x10d76}}},
+ {0x10d57, {1|F|D, {0x10d77}}},
+ {0x10d58, {1|F|D, {0x10d78}}},
+ {0x10d59, {1|F|D, {0x10d79}}},
+ {0x10d5a, {1|F|D, {0x10d7a}}},
+ {0x10d5b, {1|F|D, {0x10d7b}}},
+ {0x10d5c, {1|F|D, {0x10d7c}}},
+ {0x10d5d, {1|F|D, {0x10d7d}}},
+ {0x10d5e, {1|F|D, {0x10d7e}}},
+ {0x10d5f, {1|F|D, {0x10d7f}}},
+ {0x10d60, {1|F|D, {0x10d80}}},
+ {0x10d61, {1|F|D, {0x10d81}}},
+ {0x10d62, {1|F|D, {0x10d82}}},
+ {0x10d63, {1|F|D, {0x10d83}}},
+ {0x10d64, {1|F|D, {0x10d84}}},
+ {0x10d65, {1|F|D, {0x10d85}}},
+ {0x118a0, {1|F|D, {0x118c0}}},
+ {0x118a1, {1|F|D, {0x118c1}}},
+ {0x118a2, {1|F|D, {0x118c2}}},
+ {0x118a3, {1|F|D, {0x118c3}}},
+ {0x118a4, {1|F|D, {0x118c4}}},
+ {0x118a5, {1|F|D, {0x118c5}}},
+ {0x118a6, {1|F|D, {0x118c6}}},
+ {0x118a7, {1|F|D, {0x118c7}}},
+ {0x118a8, {1|F|D, {0x118c8}}},
+ {0x118a9, {1|F|D, {0x118c9}}},
+ {0x118aa, {1|F|D, {0x118ca}}},
+ {0x118ab, {1|F|D, {0x118cb}}},
+ {0x118ac, {1|F|D, {0x118cc}}},
+ {0x118ad, {1|F|D, {0x118cd}}},
+ {0x118ae, {1|F|D, {0x118ce}}},
+ {0x118af, {1|F|D, {0x118cf}}},
+ {0x118b0, {1|F|D, {0x118d0}}},
+ {0x118b1, {1|F|D, {0x118d1}}},
+ {0x118b2, {1|F|D, {0x118d2}}},
+ {0x118b3, {1|F|D, {0x118d3}}},
+ {0x118b4, {1|F|D, {0x118d4}}},
+ {0x118b5, {1|F|D, {0x118d5}}},
+ {0x118b6, {1|F|D, {0x118d6}}},
+ {0x118b7, {1|F|D, {0x118d7}}},
+ {0x118b8, {1|F|D, {0x118d8}}},
+ {0x118b9, {1|F|D, {0x118d9}}},
+ {0x118ba, {1|F|D, {0x118da}}},
+ {0x118bb, {1|F|D, {0x118db}}},
+ {0x118bc, {1|F|D, {0x118dc}}},
+ {0x118bd, {1|F|D, {0x118dd}}},
+ {0x118be, {1|F|D, {0x118de}}},
+ {0x118bf, {1|F|D, {0x118df}}},
+ {0x16e40, {1|F|D, {0x16e60}}},
+ {0x16e41, {1|F|D, {0x16e61}}},
+ {0x16e42, {1|F|D, {0x16e62}}},
+ {0x16e43, {1|F|D, {0x16e63}}},
+ {0x16e44, {1|F|D, {0x16e64}}},
+ {0x16e45, {1|F|D, {0x16e65}}},
+ {0x16e46, {1|F|D, {0x16e66}}},
+ {0x16e47, {1|F|D, {0x16e67}}},
+ {0x16e48, {1|F|D, {0x16e68}}},
+ {0x16e49, {1|F|D, {0x16e69}}},
+ {0x16e4a, {1|F|D, {0x16e6a}}},
+ {0x16e4b, {1|F|D, {0x16e6b}}},
+ {0x16e4c, {1|F|D, {0x16e6c}}},
+ {0x16e4d, {1|F|D, {0x16e6d}}},
+ {0x16e4e, {1|F|D, {0x16e6e}}},
+ {0x16e4f, {1|F|D, {0x16e6f}}},
+ {0x16e50, {1|F|D, {0x16e70}}},
+ {0x16e51, {1|F|D, {0x16e71}}},
+ {0x16e52, {1|F|D, {0x16e72}}},
+ {0x16e53, {1|F|D, {0x16e73}}},
+ {0x16e54, {1|F|D, {0x16e74}}},
+ {0x16e55, {1|F|D, {0x16e75}}},
+ {0x16e56, {1|F|D, {0x16e76}}},
+ {0x16e57, {1|F|D, {0x16e77}}},
+ {0x16e58, {1|F|D, {0x16e78}}},
+ {0x16e59, {1|F|D, {0x16e79}}},
+ {0x16e5a, {1|F|D, {0x16e7a}}},
+ {0x16e5b, {1|F|D, {0x16e7b}}},
+ {0x16e5c, {1|F|D, {0x16e7c}}},
+ {0x16e5d, {1|F|D, {0x16e7d}}},
+ {0x16e5e, {1|F|D, {0x16e7e}}},
+ {0x16e5f, {1|F|D, {0x16e7f}}},
+ {0x16ea0, {1|F|D, {0x16ebb}}},
+ {0x16ea1, {1|F|D, {0x16ebc}}},
+ {0x16ea2, {1|F|D, {0x16ebd}}},
+ {0x16ea3, {1|F|D, {0x16ebe}}},
+ {0x16ea4, {1|F|D, {0x16ebf}}},
+ {0x16ea5, {1|F|D, {0x16ec0}}},
+ {0x16ea6, {1|F|D, {0x16ec1}}},
+ {0x16ea7, {1|F|D, {0x16ec2}}},
+ {0x16ea8, {1|F|D, {0x16ec3}}},
+ {0x16ea9, {1|F|D, {0x16ec4}}},
+ {0x16eaa, {1|F|D, {0x16ec5}}},
+ {0x16eab, {1|F|D, {0x16ec6}}},
+ {0x16eac, {1|F|D, {0x16ec7}}},
+ {0x16ead, {1|F|D, {0x16ec8}}},
+ {0x16eae, {1|F|D, {0x16ec9}}},
+ {0x16eaf, {1|F|D, {0x16eca}}},
+ {0x16eb0, {1|F|D, {0x16ecb}}},
+ {0x16eb1, {1|F|D, {0x16ecc}}},
+ {0x16eb2, {1|F|D, {0x16ecd}}},
+ {0x16eb3, {1|F|D, {0x16ece}}},
+ {0x16eb4, {1|F|D, {0x16ecf}}},
+ {0x16eb5, {1|F|D, {0x16ed0}}},
+ {0x16eb6, {1|F|D, {0x16ed1}}},
+ {0x16eb7, {1|F|D, {0x16ed2}}},
+ {0x16eb8, {1|F|D, {0x16ed3}}},
+ {0x1e900, {1|F|D, {0x1e922}}},
+ {0x1e901, {1|F|D, {0x1e923}}},
+ {0x1e902, {1|F|D, {0x1e924}}},
+ {0x1e903, {1|F|D, {0x1e925}}},
+ {0x1e904, {1|F|D, {0x1e926}}},
+ {0x1e905, {1|F|D, {0x1e927}}},
+ {0x1e906, {1|F|D, {0x1e928}}},
+ {0x1e907, {1|F|D, {0x1e929}}},
+ {0x1e908, {1|F|D, {0x1e92a}}},
+ {0x1e909, {1|F|D, {0x1e92b}}},
+ {0x1e90a, {1|F|D, {0x1e92c}}},
+ {0x1e90b, {1|F|D, {0x1e92d}}},
+ {0x1e90c, {1|F|D, {0x1e92e}}},
+ {0x1e90d, {1|F|D, {0x1e92f}}},
+ {0x1e90e, {1|F|D, {0x1e930}}},
+ {0x1e90f, {1|F|D, {0x1e931}}},
+ {0x1e910, {1|F|D, {0x1e932}}},
+ {0x1e911, {1|F|D, {0x1e933}}},
+ {0x1e912, {1|F|D, {0x1e934}}},
+ {0x1e913, {1|F|D, {0x1e935}}},
+ {0x1e914, {1|F|D, {0x1e936}}},
+ {0x1e915, {1|F|D, {0x1e937}}},
+ {0x1e916, {1|F|D, {0x1e938}}},
+ {0x1e917, {1|F|D, {0x1e939}}},
+ {0x1e918, {1|F|D, {0x1e93a}}},
+ {0x1e919, {1|F|D, {0x1e93b}}},
+ {0x1e91a, {1|F|D, {0x1e93c}}},
+ {0x1e91b, {1|F|D, {0x1e93d}}},
+ {0x1e91c, {1|F|D, {0x1e93e}}},
+ {0x1e91d, {1|F|D, {0x1e93f}}},
+ {0x1e91e, {1|F|D, {0x1e940}}},
+ {0x1e91f, {1|F|D, {0x1e941}}},
+ {0x1e920, {1|F|D, {0x1e942}}},
+ {0x1e921, {1|F|D, {0x1e943}}},
+#define CaseFold_Locale (*(CaseFold_11_Type (*)[2])(CaseFold_11_Table+1583))
+ {0x0049, {1|F|D, {0x0069}}},
+ {0x0130, {2|F|D, {0x0069, 0x0307}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseFold_11_hash -N onigenc_unicode_CaseFold_11_lookup -n */
+
+/* maximum key range = 3756, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseFold_11_hash(const OnigCodePoint code)
+{
+ static const unsigned short asso_values[] =
+ {
+ 2, 107, 6, 43, 1, 5, 70, 14, 5, 396,
+ 239, 925, 3763, 3763, 3763, 3763, 3763, 3763, 3763, 3763,
+ 3763, 3763, 3763, 3763, 3763, 45, 404, 3763, 3763, 3763,
+ 3763, 3763, 3763, 400, 3763, 3763, 3763, 3763, 3763, 20,
+ 3763, 3763, 3763, 3763, 3763, 3763, 3763, 3763, 3763, 472,
+ 3763, 3763, 3763, 3763, 3763, 3763, 3763, 163, 3763, 3763,
+ 311, 310, 445, 3, 3763, 3763, 482, 10, 3763, 3763,
+ 3763, 3763, 3763, 604, 3763, 3763, 315, 863, 428, 38,
+ 2198, 226, 42, 182, 240, 94, 1542, 7, 12, 24,
+ 2250, 764, 872, 684, 2182, 168, 1933, 308, 2170, 153,
+ 2106, 108, 1653, 261, 1889, 426, 1851, 484, 470, 506,
+ 2234, 286, 1417, 411, 1461, 366, 1436, 352, 60, 667,
+ 1357, 551, 1110, 611, 1440, 597, 631, 614, 1630, 691,
+ 1762, 821, 1950, 747, 1682, 542, 1752, 740, 1949, 855,
+ 1912, 845, 1840, 1230, 1928, 1106, 1572, 1003, 1323, 1223,
+ 500, 1203, 1783, 1094, 1602, 957, 1472, 1157, 2059, 1188,
+ 2140, 947, 937, 1257, 1395, 1168, 196, 1317, 258, 1246,
+ 141, 1587, 38, 1563, 3, 1663, 53, 1371, 178, 1480,
+ 41, 1745, 57, 1723, 356, 1698, 122, 1609, 77, 1726,
+ 76, 1710, 44, 1740, 2, 1815, 568, 2094, 146, 2214,
+ 340, 2126, 73, 408, 101, 1980, 149
+ };
+ return asso_values[bits_of(code, 2)+79] + asso_values[bits_of(code, 1)] + asso_values[bits_of(code, 0)];
+}
+
+static const CodePointList3 *
+onigenc_unicode_CaseFold_11_lookup(const OnigCodePoint code)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x41,
+ MAX_CODE_VALUE = 0x1e921,
+ TOTAL_KEYWORDS = 1585,
+ MIN_WORD_LENGTH = 3,
+ MAX_WORD_LENGTH = 3,
+ MIN_HASH_VALUE = 7,
+ MAX_HASH_VALUE = 3762
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x1ff3*/ 856,
+ -1, -1,
+ /*0x0208*/ 194,
+ -1,
+ /*0x1f88*/ 776,
+ /*0x10408*/ 1284,
+ /*0x0408*/ 305,
+ /*0x0108*/ 61,
+ -1,
+ /*0x1f89*/ 777,
+ /*0x10409*/ 1285,
+ /*0x0409*/ 306,
+ /*0xab88*/ 1182,
+ /*0x2c08*/ 920,
+ -1,
+ /*0x0388*/ 235,
+ -1,
+ /*0xab89*/ 1183,
+ /*0x2c09*/ 921,
+ /*0x020a*/ 195,
+ /*0x0389*/ 236,
+ /*0x1f8a*/ 778,
+ /*0x1040a*/ 1286,
+ /*0x040a*/ 307,
+ /*0x010a*/ 62,
+ /*0x2c88*/ 979,
+ -1, -1, -1,
+ /*0xab8a*/ 1184,
+ /*0x2c0a*/ 922,
+ -1,
+ /*0x038a*/ 237,
+ /*0x0200*/ 190,
+ -1,
+ /*0x1f80*/ 768,
+ /*0x10400*/ 1276,
+ /*0x0400*/ 297,
+ /*0x0100*/ 57,
+ /*0x1f83*/ 771,
+ /*0x10403*/ 1279,
+ /*0x0403*/ 300,
+ /*0x2c8a*/ 980,
+ /*0xab80*/ 1174,
+ /*0x2c00*/ 912,
+ /*0x10c88*/ 1395,
+ /*0x2183*/ 885,
+ /*0xab83*/ 1177,
+ /*0x2c03*/ 915,
+ /*0x0189*/ 126,
+ /*0x10c89*/ 1396,
+ -1,
+ /*0x03f1*/ 288,
+ -1,
+ /*0x1fe7*/ 849,
+ /*0x1e908*/ 1557,
+ /*0x2c80*/ 975,
+ /*0x1fa7*/ 807,
+ /*0x10427*/ 1315,
+ /*0x0427*/ 336,
+ /*0x1e909*/ 1558,
+ /*0x018a*/ 127,
+ /*0x10c8a*/ 1397,
+ /*0x2c67*/ 964,
+ -1,
+ /*0xaba7*/ 1213,
+ /*0x2c27*/ 951,
+ -1,
+ /*0x03a7*/ 263,
+ -1,
+ /*0x1ffb*/ 863,
+ -1,
+ /*0x1e90a*/ 1559,
+ /*0x017b*/ 118,
+ /*0xa780*/ 1107,
+ -1,
+ /*0x10c80*/ 1387,
+ -1, -1, -1,
+ /*0x10c83*/ 1390,
+ /*0x01f1*/ 181,
+ /*0x2c6f*/ 969,
+ /*0x2c6d*/ 967,
+ -1, -1,
+ /*0x1e900*/ 1549,
+ /*0x13fb*/ 527,
+ -1,
+ /*0x0206*/ 193,
+ /*0x1e903*/ 1552,
+ /*0x1f86*/ 774,
+ /*0x10406*/ 1282,
+ /*0x0406*/ 303,
+ /*0x0106*/ 60,
+ /*0x2ced*/ 1026,
+ -1,
+ /*0x01a7*/ 145,
+ /*0x10ca7*/ 1426,
+ /*0xab86*/ 1180,
+ /*0x2c06*/ 918,
+ /*0x017d*/ 119,
+ /*0x0386*/ 234,
+ /*0x0216*/ 201,
+ /*0x00df*/ 56,
+ /*0x1f96*/ 790,
+ /*0x10416*/ 1298,
+ /*0x0416*/ 319,
+ /*0x0116*/ 68,
+ /*0x03fd*/ 294,
+ -1, -1,
+ /*0x2c86*/ 978,
+ /*0xab96*/ 1196,
+ /*0x2c16*/ 934,
+ /*0x13fd*/ 529,
+ /*0x0396*/ 247,
+ -1, -1,
+ /*0x1feb*/ 853,
+ -1, -1, -1, -1, -1, -1,
+ /*0x2c96*/ 986,
+ -1,
+ /*0x2c6b*/ 966,
+ -1,
+ /*0xa786*/ 1110,
+ /*0x0186*/ 124,
+ /*0x10c86*/ 1393,
+ /*0xfb00*/ 1238,
+ -1, -1, -1,
+ /*0xfb03*/ 1241,
+ /*0x1fdb*/ 844,
+ /*0x00dd*/ 54,
+ /*0x2ceb*/ 1025,
+ -1,
+ /*0x1e906*/ 1555,
+ /*0x1ff7*/ 859,
+ /*0xa796*/ 1115,
+ /*0x0196*/ 135,
+ /*0x10c96*/ 1409,
+ -1,
+ /*0x0214*/ 200,
+ /*0x017f*/ 120,
+ /*0x1f94*/ 788,
+ /*0x10414*/ 1296,
+ /*0x0414*/ 317,
+ /*0x0114*/ 67,
+ /*0x03f7*/ 291,
+ /*0x2c7f*/ 974,
+ /*0x1e916*/ 1571,
+ /*0x03ff*/ 296,
+ /*0xab94*/ 1194,
+ /*0x2c14*/ 932,
+ -1,
+ /*0x0394*/ 245,
+ -1,
+ /*0x0210*/ 198,
+ /*0x1c88*/ 538,
+ /*0x1f90*/ 784,
+ /*0x10410*/ 1292,
+ /*0x0410*/ 313,
+ /*0x0110*/ 65,
+ /*0x1c89*/ 539,
+ -1,
+ /*0x2c94*/ 985,
+ -1,
+ /*0xab90*/ 1190,
+ /*0x2c10*/ 928,
+ /*0x1fe3*/ 846,
+ /*0x0390*/ 241,
+ /*0x0204*/ 192,
+ /*0x01db*/ 170,
+ /*0x1f84*/ 772,
+ /*0x10404*/ 1280,
+ /*0x0404*/ 301,
+ /*0x0104*/ 59,
+ /*0x01f7*/ 185,
+ /*0x2c63*/ 962,
+ -1,
+ /*0x2c90*/ 983,
+ /*0xab84*/ 1178,
+ /*0x2c04*/ 916,
+ /*0xfb06*/ 1244,
+ /*0x0194*/ 134,
+ /*0x10c94*/ 1407,
+ /*0x0057*/ 21,
+ /*0x1fd7*/ 840,
+ -1,
+ /*0x1c80*/ 530,
+ -1, -1, -1,
+ /*0x1c83*/ 533,
+ /*0x2c84*/ 977,
+ /*0x1e914*/ 1569,
+ -1,
+ /*0xfb16*/ 1248,
+ /*0xa790*/ 1113,
+ /*0x0190*/ 131,
+ /*0x10c90*/ 1403,
+ -1, -1, -1, -1, -1, -1,
+ /*0x037f*/ 233,
+ -1, -1,
+ /*0x1e910*/ 1565,
+ /*0x1ca7*/ 563,
+ /*0xa784*/ 1109,
+ /*0x0184*/ 123,
+ /*0x10c84*/ 1391,
+ /*0x0202*/ 191,
+ -1,
+ /*0x1f82*/ 770,
+ /*0x10402*/ 1278,
+ /*0x0402*/ 299,
+ /*0x0102*/ 58,
+ -1, -1, -1,
+ /*0x1e904*/ 1553,
+ /*0xab82*/ 1176,
+ /*0x2c02*/ 914,
+ /*0x01d7*/ 168,
+ /*0x10573*/ 1355,
+ -1, -1,
+ /*0x1f85*/ 773,
+ /*0x10405*/ 1281,
+ /*0x0405*/ 302,
+ /*0x0508*/ 425,
+ -1,
+ /*0x00db*/ 52,
+ -1,
+ /*0x2c82*/ 976,
+ /*0xab85*/ 1179,
+ /*0x2c05*/ 917,
+ -1,
+ /*0xfb14*/ 1246,
+ -1, -1,
+ /*0x1c86*/ 536,
+ -1, -1,
+ /*0x0059*/ 23,
+ /*0x1fd9*/ 842,
+ /*0x0218*/ 202,
+ /*0x050a*/ 426,
+ /*0x1f98*/ 792,
+ /*0x10418*/ 1300,
+ /*0x0418*/ 321,
+ /*0x0118*/ 69,
+ /*0xa782*/ 1108,
+ /*0x0182*/ 122,
+ /*0x10c82*/ 1389,
+ /*0x1c96*/ 546,
+ /*0xab98*/ 1198,
+ /*0x2c18*/ 936,
+ -1,
+ /*0x0398*/ 249,
+ -1,
+ /*0x0500*/ 421,
+ -1, -1,
+ /*0x1e902*/ 1551,
+ -1,
+ /*0x10571*/ 1353,
+ /*0xfb04*/ 1242,
+ /*0x10c85*/ 1392,
+ /*0x2c98*/ 987,
+ -1,
+ /*0x0220*/ 206,
+ -1,
+ /*0x1fa0*/ 800,
+ /*0x10420*/ 1308,
+ /*0x0420*/ 329,
+ /*0x0120*/ 73,
+ -1,
+ /*0x1e905*/ 1554,
+ -1, -1,
+ /*0xaba0*/ 1206,
+ /*0x2c20*/ 944,
+ -1,
+ /*0x03a0*/ 257,
+ /*0x01d9*/ 169,
+ -1,
+ /*0xa798*/ 1116,
+ /*0x0198*/ 137,
+ /*0x10c98*/ 1411,
+ -1, -1, -1,
+ /*0x0212*/ 199,
+ /*0x2ca0*/ 991,
+ /*0x1f92*/ 786,
+ /*0x10412*/ 1294,
+ /*0x0412*/ 315,
+ /*0x0112*/ 66,
+ /*0x1e918*/ 1573,
+ /*0x1c94*/ 544,
+ /*0x1e88*/ 654,
+ /*0x1e08*/ 590,
+ /*0xab92*/ 1192,
+ /*0x2c12*/ 930,
+ -1,
+ /*0x0392*/ 243,
+ -1, -1, -1, -1,
+ /*0xfb02*/ 1240,
+ /*0xa7a0*/ 1120,
+ /*0x01a0*/ 141,
+ /*0x10ca0*/ 1419,
+ /*0x1c90*/ 540,
+ /*0x2c92*/ 984,
+ /*0x0506*/ 424,
+ /*0x1e8a*/ 655,
+ /*0x1e0a*/ 591,
+ -1, -1, -1,
+ /*0x1057d*/ 1364,
+ /*0x1e920*/ 1581,
+ /*0xfb05*/ 1243,
+ -1,
+ /*0x1ff9*/ 861,
+ -1,
+ /*0x1c84*/ 534,
+ /*0x0179*/ 117,
+ /*0x0516*/ 432,
+ /*0x1e80*/ 650,
+ /*0x1e00*/ 586,
+ /*0xa792*/ 1114,
+ -1,
+ /*0x10c92*/ 1405,
+ /*0x0226*/ 209,
+ /*0x03f9*/ 292,
+ /*0x1fa6*/ 806,
+ /*0x10426*/ 1314,
+ /*0x0426*/ 335,
+ /*0x0126*/ 76,
+ /*0x1fe9*/ 851,
+ /*0x13f9*/ 525,
+ -1,
+ /*0x1e912*/ 1567,
+ /*0xaba6*/ 1212,
+ /*0x2c26*/ 950,
+ /*0x00d9*/ 50,
+ /*0x03a6*/ 262,
+ /*0x0224*/ 208,
+ /*0x2c69*/ 965,
+ /*0x1fa4*/ 804,
+ /*0x10424*/ 1312,
+ /*0x0424*/ 333,
+ /*0x0124*/ 75,
+ -1, -1, -1,
+ /*0x2ca6*/ 994,
+ /*0xaba4*/ 1210,
+ /*0x2c24*/ 948,
+ -1,
+ /*0x03a4*/ 260,
+ -1, -1, -1,
+ /*0x10577*/ 1359,
+ -1, -1,
+ /*0x1057f*/ 1366,
+ -1,
+ /*0x1c82*/ 532,
+ /*0x2ca4*/ 993,
+ -1,
+ /*0x0514*/ 431,
+ -1,
+ /*0xa7a6*/ 1123,
+ /*0x01a6*/ 144,
+ /*0x10ca6*/ 1425,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1c85*/ 535,
+ /*0x1e86*/ 653,
+ /*0x1e06*/ 589,
+ /*0x10d5f*/ 1453,
+ /*0x0510*/ 429,
+ /*0xa7a4*/ 1122,
+ /*0x01a4*/ 143,
+ /*0x10ca4*/ 1423,
+ /*0x1ffc*/ 864,
+ /*0x0222*/ 207,
+ /*0x047c*/ 359,
+ /*0x1fa2*/ 802,
+ /*0x10422*/ 1310,
+ /*0x0422*/ 331,
+ /*0x0122*/ 74,
+ /*0x1e96*/ 661,
+ /*0x1e16*/ 597,
+ /*0x048a*/ 362,
+ /*0x0504*/ 423,
+ /*0xaba2*/ 1208,
+ /*0x2c22*/ 946,
+ /*0x1c98*/ 548,
+ -1, -1,
+ /*0x021a*/ 203,
+ /*0x13fc*/ 528,
+ /*0x1f9a*/ 794,
+ /*0x1041a*/ 1302,
+ /*0x041a*/ 323,
+ /*0x011a*/ 70,
+ -1,
+ /*0x0480*/ 361,
+ /*0x2ca2*/ 992,
+ -1,
+ /*0xab9a*/ 1200,
+ /*0x2c1a*/ 938,
+ -1,
+ /*0x039a*/ 251,
+ /*0x10d5d*/ 1451,
+ -1, -1,
+ /*0x10d65*/ 1459,
+ -1, -1, -1,
+ /*0x1f5f*/ 759,
+ /*0x1ca0*/ 556,
+ /*0x2c9a*/ 988,
+ /*0x01fc*/ 188,
+ /*0x1f08*/ 716,
+ /*0xa7a2*/ 1121,
+ /*0x01a2*/ 142,
+ /*0x10ca2*/ 1421,
+ /*0x10d61*/ 1455,
+ /*0x1f09*/ 717,
+ -1, -1,
+ /*0x10a7*/ 491,
+ -1, -1,
+ /*0x1e94*/ 660,
+ /*0x1e14*/ 596,
+ /*0x0502*/ 422,
+ -1, -1,
+ /*0xa79a*/ 1117,
+ /*0x1f0a*/ 718,
+ /*0x10c9a*/ 1413,
+ /*0x1c92*/ 542,
+ -1,
+ /*0x1f9d*/ 797,
+ /*0x1041d*/ 1305,
+ /*0x041d*/ 326,
+ -1, -1,
+ /*0x1e90*/ 658,
+ /*0x1e10*/ 594,
+ /*0x1e91a*/ 1575,
+ /*0xab9d*/ 1203,
+ /*0x2c1d*/ 941,
+ /*0x1f5d*/ 758,
+ /*0x039d*/ 254,
+ /*0x021c*/ 204,
+ -1,
+ /*0x1f9c*/ 796,
+ /*0x1041c*/ 1304,
+ /*0x041c*/ 325,
+ /*0x011c*/ 71,
+ -1,
+ /*0x1e84*/ 652,
+ /*0x1e04*/ 588,
+ -1,
+ /*0xab9c*/ 1202,
+ /*0x2c1c*/ 940,
+ -1,
+ /*0x039c*/ 253,
+ -1,
+ /*0x0518*/ 433,
+ -1,
+ /*0x0047*/ 6,
+ /*0x1fc7*/ 831,
+ /*0x0496*/ 368,
+ /*0xa77b*/ 1104,
+ /*0x0147*/ 91,
+ /*0x021e*/ 205,
+ /*0x2c9c*/ 989,
+ /*0x1f9e*/ 798,
+ /*0x1041e*/ 1306,
+ /*0x041e*/ 327,
+ /*0x011e*/ 72,
+ /*0x019d*/ 139,
+ /*0x10c9d*/ 1416,
+ /*0x1ca6*/ 562,
+ -1,
+ /*0xab9e*/ 1204,
+ /*0x2c1e*/ 942,
+ -1,
+ /*0x039e*/ 255,
+ /*0x1f6f*/ 767,
+ /*0x1f6d*/ 765,
+ /*0x2165*/ 874,
+ /*0x1e91d*/ 1578,
+ /*0x0520*/ 437,
+ /*0xa79c*/ 1118,
+ /*0x019c*/ 138,
+ /*0x10c9c*/ 1415,
+ /*0x1ca4*/ 560,
+ /*0x2c9e*/ 990,
+ /*0x118a7*/ 1467,
+ -1,
+ /*0xa77d*/ 1105,
+ -1,
+ /*0x2161*/ 870,
+ /*0x1e82*/ 651,
+ /*0x1e02*/ 587,
+ /*0x1e91c*/ 1577,
+ /*0x2167*/ 876,
+ -1, -1,
+ /*0xa7c7*/ 1145,
+ /*0x01c7*/ 159,
+ /*0x10d5b*/ 1449,
+ /*0x1fb8*/ 821,
+ -1,
+ /*0x0512*/ 430,
+ /*0xa79e*/ 1119,
+ /*0x0494*/ 367,
+ /*0x10c9e*/ 1417,
+ -1,
+ /*0x022a*/ 211,
+ /*0xabb8*/ 1230,
+ /*0x1faa*/ 810,
+ -1,
+ /*0x042a*/ 339,
+ /*0x012a*/ 78,
+ /*0x216f*/ 884,
+ /*0x216d*/ 882,
+ /*0x1e91e*/ 1579,
+ -1,
+ /*0xabaa*/ 1216,
+ /*0x2c2a*/ 954,
+ /*0x0490*/ 365,
+ /*0x03aa*/ 266,
+ /*0x2cb8*/ 1003,
+ /*0x1f6b*/ 763,
+ -1, -1, -1,
+ /*0x1e98*/ 663,
+ /*0x1e18*/ 598,
+ -1,
+ /*0x1ca2*/ 558,
+ /*0x2caa*/ 996,
+ -1, -1,
+ /*0x10579*/ 1361,
+ -1,
+ /*0x2c75*/ 972,
+ /*0x10d63*/ 1457,
+ /*0x03f5*/ 290,
+ -1,
+ /*0xa7b8*/ 1136,
+ /*0x01b8*/ 155,
+ /*0x1f5b*/ 757,
+ -1, -1,
+ /*0x1c9a*/ 550,
+ -1,
+ /*0x0526*/ 440,
+ -1,
+ /*0xa7aa*/ 1125,
+ -1,
+ /*0x10caa*/ 1429,
+ /*0x1ea0*/ 668,
+ /*0x1e20*/ 602,
+ /*0x022e*/ 213,
+ /*0x10d57*/ 1445,
+ /*0x1fae*/ 814,
+ -1,
+ /*0x042e*/ 343,
+ /*0x012e*/ 80,
+ /*0x216b*/ 880,
+ /*0x0524*/ 439,
+ -1,
+ /*0x00c7*/ 33,
+ /*0xabae*/ 1220,
+ /*0x2c2e*/ 958,
+ /*0xa7f5*/ 1157,
+ -1,
+ /*0x022c*/ 212,
+ -1,
+ /*0x1fac*/ 812,
+ /*0x0230*/ 214,
+ /*0x042c*/ 341,
+ /*0x012c*/ 79,
+ /*0x1e92*/ 659,
+ /*0x1e12*/ 595,
+ /*0x0130*/ 1584,
+ /*0x2cae*/ 998,
+ /*0xabac*/ 1218,
+ /*0x2c2c*/ 956,
+ -1,
+ /*0xabb0*/ 1222,
+ -1, -1,
+ /*0x03b0*/ 268,
+ -1, -1, -1, -1,
+ /*0x1c9d*/ 553,
+ /*0x1faf*/ 815,
+ /*0x2cac*/ 997,
+ /*0x042f*/ 344,
+ -1,
+ /*0x2cb0*/ 999,
+ /*0xa7ae*/ 1129,
+ /*0x01ae*/ 148,
+ /*0x10cae*/ 1433,
+ /*0xabaf*/ 1221,
+ /*0x2c2f*/ 959,
+ -1, -1,
+ /*0x1057c*/ 1363,
+ /*0x1c9c*/ 552,
+ -1, -1,
+ /*0x0522*/ 438,
+ -1, -1,
+ /*0xa7ac*/ 1127,
+ /*0x01ac*/ 147,
+ /*0x10cac*/ 1431,
+ /*0xa7b0*/ 1130,
+ /*0x0498*/ 369,
+ /*0x10cb0*/ 1435,
+ -1,
+ /*0x2163*/ 872,
+ /*0x10d59*/ 1447,
+ /*0x1ea6*/ 671,
+ /*0x1e26*/ 605,
+ -1,
+ /*0x051a*/ 434,
+ -1, -1,
+ /*0x0228*/ 210,
+ /*0x1c9e*/ 554,
+ /*0x1fa8*/ 808,
+ -1,
+ /*0x0428*/ 337,
+ /*0x0128*/ 77,
+ /*0x01af*/ 149,
+ /*0x10caf*/ 1434,
+ /*0x1ea4*/ 670,
+ /*0x1e24*/ 604,
+ /*0xaba8*/ 1214,
+ /*0x2c28*/ 952,
+ -1,
+ /*0x03a8*/ 264,
+ /*0x04a0*/ 373,
+ -1, -1,
+ /*0x020e*/ 197,
+ /*0x10a0*/ 484,
+ /*0x1f8e*/ 782,
+ /*0x1040e*/ 1290,
+ /*0x040e*/ 311,
+ /*0x010e*/ 64,
+ /*0x2ca8*/ 995,
+ /*0x0232*/ 215,
+ -1,
+ /*0x1fb2*/ 816,
+ /*0xab8e*/ 1188,
+ /*0x2c0e*/ 926,
+ /*0x0132*/ 81,
+ /*0x038e*/ 239,
+ -1, -1, -1,
+ /*0xabb2*/ 1224,
+ /*0x1f59*/ 756,
+ /*0x0492*/ 366,
+ /*0x1cb8*/ 580,
+ /*0x1f18*/ 724,
+ -1,
+ /*0x2c8e*/ 982,
+ /*0xa7a8*/ 1124,
+ -1,
+ /*0x10ca8*/ 1427,
+ -1, -1,
+ /*0x1caa*/ 566,
+ /*0x2cb2*/ 1000,
+ -1, -1,
+ /*0x1efc*/ 714,
+ /*0x1e7c*/ 648,
+ -1,
+ /*0x1ea2*/ 669,
+ /*0x1e22*/ 603,
+ /*0x051c*/ 435,
+ -1, -1, -1,
+ /*0x018e*/ 129,
+ /*0x10c8e*/ 1401,
+ -1, -1, -1,
+ /*0xff27*/ 1256,
+ /*0xa7b2*/ 1132,
+ /*0x01b2*/ 151,
+ /*0x10cb2*/ 1437,
+ /*0x1e9a*/ 665,
+ /*0x1e1a*/ 599,
+ /*0x1e90e*/ 1563,
+ /*0x0547*/ 467,
+ -1,
+ /*0x023a*/ 216,
+ -1,
+ /*0x1fba*/ 823,
+ -1,
+ /*0x051e*/ 436,
+ -1,
+ /*0x16ea7*/ 1531,
+ /*0x04a6*/ 376,
+ -1,
+ /*0x1fb6*/ 819,
+ /*0xabba*/ 1232,
+ /*0x10a6*/ 490,
+ /*0x0136*/ 83,
+ -1, -1, -1,
+ /*0x118a0*/ 1460,
+ /*0xabb6*/ 1228,
+ -1,
+ /*0x1cae*/ 570,
+ -1,
+ /*0x04a4*/ 375,
+ -1,
+ /*0x2cba*/ 1004,
+ /*0x020c*/ 196,
+ /*0x10a4*/ 488,
+ /*0x1f8c*/ 780,
+ /*0x1040c*/ 1288,
+ /*0x040c*/ 309,
+ /*0x010c*/ 63,
+ /*0x2cb6*/ 1002,
+ /*0xa779*/ 1103,
+ -1,
+ /*0x1cac*/ 568,
+ /*0xab8c*/ 1186,
+ /*0x2c0c*/ 924,
+ /*0x1cb0*/ 572,
+ /*0x038c*/ 238,
+ -1, -1,
+ /*0x0538*/ 452,
+ /*0xa7ba*/ 1137,
+ -1,
+ /*0xa726*/ 1067,
+ -1, -1, -1,
+ /*0x2c8c*/ 981,
+ /*0xa7b6*/ 1135,
+ /*0x052a*/ 442,
+ -1, -1, -1,
+ /*0x1caf*/ 571,
+ /*0x1e1c*/ 600,
+ -1, -1,
+ /*0xa724*/ 1066,
+ -1, -1,
+ /*0x1f69*/ 761,
+ -1, -1,
+ /*0x04fc*/ 419,
+ -1,
+ /*0x10575*/ 1357,
+ /*0x04a2*/ 374,
+ /*0x10c8c*/ 1399,
+ -1, -1,
+ /*0x10a2*/ 486,
+ -1, -1, -1, -1,
+ /*0x1e9e*/ 667,
+ /*0x1e1e*/ 601,
+ /*0x1e90c*/ 1561,
+ -1, -1, -1,
+ /*0x049a*/ 370,
+ /*0x118a6*/ 1466,
+ /*0x1fb4*/ 818,
+ -1, -1,
+ /*0x0134*/ 82,
+ -1, -1,
+ /*0x1ca8*/ 564,
+ -1,
+ /*0xabb4*/ 1226,
+ -1,
+ /*0x2126*/ 865,
+ -1,
+ /*0x052e*/ 444,
+ /*0x118a4*/ 1464,
+ /*0x2169*/ 878,
+ -1, -1, -1, -1,
+ /*0xa722*/ 1065,
+ -1,
+ /*0x2cb4*/ 1001,
+ /*0x023e*/ 219,
+ -1,
+ /*0x1fbe*/ 826,
+ -1,
+ /*0x052c*/ 443,
+ -1,
+ /*0x1eb8*/ 680,
+ /*0x1e38*/ 614,
+ /*0x1cb2*/ 574,
+ -1,
+ /*0xabbe*/ 1236,
+ -1,
+ /*0x1fbc*/ 825,
+ -1, -1,
+ /*0x1eaa*/ 673,
+ /*0x1e2a*/ 607,
+ /*0xa7b4*/ 1134,
+ -1, -1,
+ /*0xabbc*/ 1234,
+ -1, -1,
+ /*0x2cbe*/ 1006,
+ -1,
+ /*0x1f1a*/ 726,
+ -1, -1,
+ /*0xa688*/ 1055,
+ /*0x1f8d*/ 781,
+ /*0x1040d*/ 1289,
+ /*0x040d*/ 310,
+ /*0x16e5f*/ 1523,
+ /*0x2cbc*/ 1005,
+ /*0x049c*/ 371,
+ -1,
+ /*0x118a2*/ 1462,
+ /*0xab8d*/ 1187,
+ /*0x2c0d*/ 925,
+ -1, -1,
+ /*0xa7be*/ 1139,
+ -1, -1, -1,
+ /*0xa68a*/ 1056,
+ -1, -1, -1,
+ /*0x104c7*/ 1339,
+ /*0x04c7*/ 393,
+ /*0xa7bc*/ 1138,
+ /*0x01bc*/ 156,
+ -1,
+ /*0x10c7*/ 522,
+ -1,
+ /*0x049e*/ 372,
+ /*0x1cba*/ 582,
+ -1,
+ /*0xa680*/ 1051,
+ /*0x0528*/ 441,
+ /*0x1eae*/ 675,
+ /*0x1e2e*/ 609,
+ -1,
+ /*0x1cb6*/ 578,
+ -1, -1,
+ /*0x16e5d*/ 1521,
+ /*0xa78d*/ 1112,
+ /*0x1f1d*/ 729,
+ /*0x10c8d*/ 1400,
+ -1, -1, -1, -1,
+ /*0x1eac*/ 674,
+ /*0x1e2c*/ 608,
+ /*0x050e*/ 428,
+ /*0x1eb0*/ 676,
+ /*0x1e30*/ 610,
+ /*0x1e90d*/ 1562,
+ -1, -1,
+ /*0x1f1c*/ 728,
+ /*0x0532*/ 446,
+ /*0x10588*/ 1375,
+ -1, -1, -1, -1,
+ /*0x10589*/ 1376,
+ /*0x104b8*/ 1324,
+ /*0x04b8*/ 385,
+ /*0x0053*/ 17,
+ /*0x1fd3*/ 838,
+ -1,
+ /*0x10b8*/ 508,
+ -1, -1, -1, -1,
+ /*0x04aa*/ 378,
+ /*0x1058a*/ 1377,
+ /*0x0052*/ 16,
+ /*0x1fd2*/ 837,
+ /*0x10aa*/ 494,
+ -1,
+ /*0x0152*/ 97,
+ -1, -1, -1, -1,
+ /*0x024c*/ 227,
+ /*0x004c*/ 10,
+ /*0x1fcc*/ 836,
+ /*0xa686*/ 1054,
+ /*0x10580*/ 1367,
+ /*0x014c*/ 94,
+ -1, -1,
+ /*0x10583*/ 1370,
+ -1, -1, -1, -1,
+ /*0x2cd2*/ 1016,
+ -1,
+ /*0x16ea0*/ 1524,
+ /*0xa738*/ 1075,
+ /*0xa696*/ 1062,
+ -1,
+ /*0x1ea8*/ 672,
+ /*0x1e28*/ 606,
+ /*0x053a*/ 454,
+ /*0x01d3*/ 166,
+ /*0x2ccc*/ 1013,
+ -1,
+ /*0xa72a*/ 1069,
+ /*0x1cb4*/ 576,
+ -1,
+ /*0x0536*/ 450,
+ /*0x1f38*/ 738,
+ -1,
+ /*0xa7d2*/ 1151,
+ -1, -1, -1,
+ /*0x04ae*/ 380,
+ /*0x1e8e*/ 657,
+ /*0x1e0e*/ 593,
+ /*0x1f2a*/ 732,
+ /*0x10ae*/ 498,
+ -1,
+ /*0xa7cc*/ 1148,
+ -1,
+ /*0x1eb2*/ 677,
+ /*0x1e32*/ 611,
+ /*0x050c*/ 427,
+ /*0x0244*/ 222,
+ /*0x0044*/ 3,
+ /*0x1fc4*/ 829,
+ /*0x04ac*/ 379,
+ /*0x1cbe*/ 584,
+ /*0x104b0*/ 1316,
+ /*0x04b0*/ 381,
+ /*0x10ac*/ 496,
+ -1,
+ /*0x118b8*/ 1484,
+ /*0x10b0*/ 500,
+ -1,
+ /*0x16e5b*/ 1519,
+ -1,
+ /*0x10586*/ 1373,
+ -1,
+ /*0xa694*/ 1061,
+ -1,
+ /*0x118aa*/ 1470,
+ -1,
+ /*0xff26*/ 1255,
+ -1, -1,
+ /*0x2cc4*/ 1009,
+ -1,
+ /*0xa72e*/ 1071,
+ -1,
+ /*0x10af*/ 499,
+ -1,
+ /*0x212a*/ 866,
+ -1,
+ /*0xa690*/ 1059,
+ -1, -1,
+ /*0xff24*/ 1253,
+ /*0x16ea6*/ 1530,
+ -1, -1,
+ /*0x1f2e*/ 736,
+ /*0xa72c*/ 1070,
+ /*0x00d3*/ 45,
+ /*0xa7c4*/ 1142,
+ /*0x01c4*/ 157,
+ -1, -1,
+ /*0xa684*/ 1053,
+ /*0x1eba*/ 681,
+ /*0x1e3a*/ 615,
+ -1,
+ /*0x16ea4*/ 1528,
+ /*0x00d2*/ 44,
+ -1,
+ /*0x1f2c*/ 734,
+ /*0x1eb6*/ 679,
+ /*0x1e36*/ 613,
+ -1,
+ /*0x0534*/ 448,
+ -1, -1,
+ /*0x04a8*/ 377,
+ /*0x00cc*/ 38,
+ -1, -1,
+ /*0x10a8*/ 492,
+ /*0x118ae*/ 1474,
+ -1, -1,
+ /*0x16e57*/ 1515,
+ -1, -1,
+ /*0x1e8c*/ 656,
+ /*0x1e0c*/ 592,
+ /*0x1f2f*/ 737,
+ /*0x10594*/ 1385,
+ -1, -1,
+ /*0x048e*/ 364,
+ -1,
+ /*0x118ac*/ 1472,
+ /*0xff22*/ 1251,
+ /*0x053e*/ 458,
+ /*0x118b0*/ 1476,
+ /*0x104b2*/ 1318,
+ /*0x04b2*/ 382,
+ -1, -1, -1,
+ /*0x10b2*/ 502,
+ /*0x10590*/ 1382,
+ /*0xa682*/ 1052,
+ /*0x053c*/ 456,
+ /*0x024a*/ 226,
+ /*0x004a*/ 8,
+ /*0x1fca*/ 834,
+ /*0x16ea2*/ 1526,
+ /*0xa728*/ 1068,
+ /*0x014a*/ 93,
+ -1,
+ /*0x118af*/ 1475,
+ -1,
+ /*0x24c7*/ 903,
+ -1,
+ /*0x10584*/ 1371,
+ -1,
+ /*0x0042*/ 1,
+ /*0x1fc2*/ 827,
+ /*0x00c4*/ 30,
+ -1,
+ /*0x1f28*/ 730,
+ /*0x1fab*/ 811,
+ -1,
+ /*0x042b*/ 340,
+ -1, -1,
+ /*0x2cca*/ 1012,
+ -1,
+ /*0x03c2*/ 269,
+ /*0xabab*/ 1217,
+ /*0x2c2b*/ 955,
+ /*0xa732*/ 1072,
+ /*0x03ab*/ 267,
+ -1, -1, -1,
+ /*0xa698*/ 1063,
+ /*0x1f0e*/ 722,
+ /*0x2cc2*/ 1008,
+ /*0x1eb4*/ 678,
+ /*0x1e34*/ 612,
+ /*0x16e59*/ 1517,
+ -1,
+ /*0x104ba*/ 1326,
+ /*0x04ba*/ 386,
+ /*0x01ca*/ 161,
+ /*0x118a8*/ 1468,
+ -1,
+ /*0x10ba*/ 510,
+ -1,
+ /*0x104b6*/ 1322,
+ /*0x04b6*/ 384,
+ -1, -1,
+ /*0x24b8*/ 888,
+ /*0x10b6*/ 506,
+ /*0xa7c2*/ 1141,
+ -1,
+ /*0x10582*/ 1369,
+ -1,
+ /*0xa7ab*/ 1126,
+ -1,
+ /*0x10cab*/ 1430,
+ /*0x1ebe*/ 683,
+ /*0x1e3e*/ 617,
+ -1,
+ /*0x024e*/ 228,
+ /*0x004e*/ 12,
+ /*0x048c*/ 363,
+ -1,
+ /*0x118b2*/ 1478,
+ /*0x014e*/ 95,
+ /*0x10585*/ 1372,
+ /*0x1ebc*/ 682,
+ /*0x1e3c*/ 616,
+ -1, -1, -1,
+ /*0x0056*/ 20,
+ /*0x1fd6*/ 839,
+ /*0xa73a*/ 1076,
+ /*0x2132*/ 868,
+ /*0x0156*/ 99,
+ /*0xa692*/ 1060,
+ /*0x0553*/ 479,
+ -1, -1,
+ /*0xa736*/ 1074,
+ -1,
+ /*0x2cce*/ 1014,
+ /*0x03d6*/ 274,
+ -1, -1,
+ /*0x1f3a*/ 740,
+ /*0x0552*/ 478,
+ -1, -1, -1,
+ /*0x0050*/ 14,
+ -1,
+ /*0x2cd6*/ 1018,
+ -1,
+ /*0x0150*/ 96,
+ -1,
+ /*0x054c*/ 472,
+ -1, -1,
+ /*0xa7ce*/ 1149,
+ -1,
+ /*0x00ca*/ 36,
+ /*0x03d0*/ 271,
+ -1,
+ /*0x0248*/ 225,
+ /*0x0048*/ 7,
+ /*0x1fc8*/ 832,
+ -1, -1,
+ /*0x1f0c*/ 720,
+ /*0xa7d6*/ 1153,
+ /*0x118ba*/ 1486,
+ /*0x2cd0*/ 1015,
+ /*0x00c2*/ 28,
+ /*0xff38*/ 1273,
+ -1,
+ /*0x104b4*/ 1320,
+ /*0x04b4*/ 383,
+ /*0x118b6*/ 1482,
+ -1, -1,
+ /*0x10b4*/ 504,
+ -1,
+ /*0xff2a*/ 1259,
+ /*0x0246*/ 224,
+ /*0x0046*/ 5,
+ /*0x1fc6*/ 830,
+ /*0x2cc8*/ 1011,
+ -1,
+ /*0x16eb8*/ 1548,
+ /*0xa7d0*/ 1150,
+ -1,
+ /*0x10592*/ 1384,
+ -1, -1, -1, -1, -1,
+ /*0x16eaa*/ 1534,
+ -1,
+ /*0x104be*/ 1330,
+ /*0x04be*/ 388,
+ /*0x0544*/ 464,
+ -1, -1,
+ /*0x10be*/ 514,
+ /*0x01c8*/ 160,
+ /*0x2cc6*/ 1010,
+ /*0x005a*/ 24,
+ /*0x1fda*/ 843,
+ /*0x104bc*/ 1328,
+ /*0x04bc*/ 387,
+ /*0x015a*/ 101,
+ /*0xa734*/ 1073,
+ /*0x2cc0*/ 1007,
+ /*0x10bc*/ 512,
+ -1,
+ /*0x1ed2*/ 693,
+ /*0x1e52*/ 627,
+ /*0x0054*/ 18,
+ /*0x03da*/ 276,
+ -1, -1,
+ /*0x0154*/ 98,
+ /*0x00ce*/ 40,
+ /*0xa7c6*/ 1144,
+ /*0xa652*/ 1037,
+ /*0x1ecc*/ 690,
+ /*0x1e4c*/ 624,
+ /*0xff2e*/ 1263,
+ /*0x2cda*/ 1020,
+ -1,
+ /*0xa7c0*/ 1140,
+ /*0x1cab*/ 567,
+ -1,
+ /*0x00d6*/ 48,
+ /*0xa64c*/ 1034,
+ /*0xa73e*/ 1078,
+ -1, -1, -1,
+ /*0x2cd4*/ 1017,
+ -1,
+ /*0xff2c*/ 1261,
+ /*0x16eae*/ 1538,
+ -1,
+ /*0xff30*/ 1265,
+ /*0xa73c*/ 1077,
+ /*0xa7da*/ 1155,
+ -1,
+ /*0x1f3e*/ 744,
+ -1,
+ /*0x118b4*/ 1480,
+ /*0xa69a*/ 1064,
+ -1,
+ /*0x00d0*/ 42,
+ -1, -1,
+ /*0x16eac*/ 1536,
+ /*0xa7d4*/ 1152,
+ /*0x1f3c*/ 742,
+ /*0x16eb0*/ 1540,
+ -1,
+ /*0xff2f*/ 1264,
+ -1, -1, -1, -1, -1, -1,
+ /*0x00c8*/ 34,
+ -1, -1,
+ /*0x1ec4*/ 686,
+ /*0x1e44*/ 620,
+ -1,
+ /*0x118be*/ 1490,
+ /*0x1f0d*/ 721,
+ /*0x16eaf*/ 1539,
+ /*0x0058*/ 22,
+ /*0x1fd8*/ 841,
+ -1,
+ /*0xa644*/ 1030,
+ /*0x0158*/ 100,
+ /*0x0245*/ 223,
+ /*0x0045*/ 4,
+ /*0x118bc*/ 1488,
+ -1, -1,
+ /*0x0145*/ 90,
+ /*0x00c6*/ 32,
+ /*0x03d8*/ 275,
+ /*0x104d3*/ 1351,
+ /*0x054a*/ 470,
+ -1, -1, -1,
+ /*0x00c0*/ 26,
+ -1,
+ /*0xff28*/ 1257,
+ /*0x10d53*/ 1441,
+ /*0x2cd8*/ 1019,
+ /*0x104d2*/ 1350,
+ /*0x04d2*/ 398,
+ /*0x24ba*/ 890,
+ /*0x0542*/ 462,
+ -1, -1, -1, -1,
+ /*0x10d52*/ 1440,
+ /*0x24b6*/ 886,
+ /*0x104cc*/ 1344,
+ /*0x00da*/ 51,
+ /*0x16ea8*/ 1532,
+ -1, -1, -1, -1,
+ /*0xa7d8*/ 1154,
+ /*0x1fa9*/ 809,
+ -1,
+ /*0x0429*/ 338,
+ /*0xff32*/ 1267,
+ /*0x00d4*/ 46,
+ /*0xa7c5*/ 1143,
+ /*0x01c5*/ 158,
+ -1,
+ /*0xaba9*/ 1215,
+ /*0x2c29*/ 953,
+ -1,
+ /*0x03a9*/ 265,
+ -1, -1,
+ /*0x1fe2*/ 845,
+ /*0x16e47*/ 1499,
+ /*0x0462*/ 346,
+ /*0x0162*/ 105,
+ /*0x16eb2*/ 1542,
+ /*0xa752*/ 1088,
+ -1, -1, -1,
+ /*0x2c62*/ 961,
+ -1,
+ /*0x03e2*/ 280,
+ -1, -1, -1,
+ /*0xa74c*/ 1085,
+ -1, -1,
+ /*0x1f52*/ 753,
+ /*0x0345*/ 229,
+ -1,
+ /*0x2ce2*/ 1024,
+ /*0x054e*/ 474,
+ /*0x0055*/ 19,
+ /*0x104c4*/ 1336,
+ -1,
+ /*0x01a9*/ 146,
+ /*0x10ca9*/ 1428,
+ /*0x1f4c*/ 750,
+ /*0x10c4*/ 520,
+ /*0x1eca*/ 689,
+ /*0x1e4a*/ 623,
+ -1,
+ /*0x0556*/ 482,
+ -1,
+ /*0x03d5*/ 273,
+ -1, -1,
+ /*0xff3a*/ 1275,
+ /*0xa64a*/ 1033,
+ /*0x01e2*/ 173,
+ -1,
+ /*0x1ec2*/ 685,
+ /*0x1e42*/ 619,
+ -1,
+ /*0xff36*/ 1271,
+ /*0x1fa1*/ 801,
+ /*0x10421*/ 1309,
+ /*0x0421*/ 330,
+ -1,
+ /*0x00d8*/ 49,
+ /*0xa642*/ 1029,
+ -1,
+ /*0x0550*/ 476,
+ /*0xaba1*/ 1207,
+ /*0x2c21*/ 945,
+ /*0x00c5*/ 31,
+ /*0x03a1*/ 258,
+ -1, -1,
+ /*0x16eb6*/ 1546,
+ /*0xa744*/ 1081,
+ -1, -1,
+ /*0x01d5*/ 167,
+ /*0x1fa5*/ 805,
+ /*0x10425*/ 1313,
+ /*0x0425*/ 334,
+ /*0x0548*/ 468,
+ /*0x1fad*/ 813,
+ -1,
+ /*0x042d*/ 342,
+ -1,
+ /*0xaba5*/ 1211,
+ /*0x2c25*/ 949,
+ /*0x24be*/ 894,
+ /*0x03a5*/ 261,
+ /*0xabad*/ 1219,
+ /*0x2c2d*/ 957,
+ -1, -1, -1, -1, -1, -1,
+ /*0x24bc*/ 892,
+ -1,
+ /*0x10ca1*/ 1420,
+ /*0x0546*/ 466,
+ -1,
+ /*0x1fa3*/ 803,
+ /*0x10423*/ 1311,
+ /*0x0423*/ 332,
+ /*0x1ece*/ 691,
+ /*0x1e4e*/ 625,
+ /*0x0540*/ 460,
+ -1,
+ /*0x1e921*/ 1582,
+ /*0xaba3*/ 1209,
+ /*0x2c23*/ 947,
+ /*0x004d*/ 11,
+ /*0x03a3*/ 259,
+ /*0xa64e*/ 1035,
+ -1,
+ /*0x1ed6*/ 695,
+ /*0x1e56*/ 629,
+ /*0x10ca5*/ 1424,
+ -1,
+ /*0xa7ad*/ 1128,
+ /*0x1fe4*/ 847,
+ /*0x10cad*/ 1432,
+ /*0x0464*/ 347,
+ /*0x0164*/ 106,
+ /*0xa656*/ 1039,
+ -1,
+ /*0x104ca*/ 1342,
+ -1, -1,
+ /*0x2c64*/ 963,
+ /*0xff34*/ 1269,
+ /*0x03e4*/ 281,
+ -1,
+ /*0x0554*/ 480,
+ -1,
+ /*0x1ed0*/ 692,
+ /*0x1e50*/ 626,
+ -1,
+ /*0x104c2*/ 1334,
+ /*0x00d5*/ 47,
+ -1, -1,
+ /*0x10ca3*/ 1422,
+ /*0x10c2*/ 518,
+ /*0xa650*/ 1036,
+ /*0x16eb4*/ 1544,
+ -1,
+ /*0x10ab*/ 495,
+ -1, -1,
+ /*0x1ec8*/ 688,
+ /*0x1e48*/ 622,
+ /*0x01cd*/ 163,
+ -1, -1, -1, -1,
+ /*0x1ca9*/ 565,
+ -1,
+ /*0xa648*/ 1032,
+ /*0x01e4*/ 174,
+ -1, -1,
+ /*0xa74a*/ 1084,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1ec6*/ 687,
+ /*0x1e46*/ 621,
+ -1, -1, -1,
+ /*0xa742*/ 1080,
+ /*0x1f4a*/ 748,
+ /*0x1ec0*/ 684,
+ /*0x1e40*/ 618,
+ /*0xa646*/ 1031,
+ -1, -1,
+ /*0x1f87*/ 775,
+ /*0x10407*/ 1283,
+ /*0x0407*/ 304,
+ /*0xab73*/ 1161,
+ /*0xa640*/ 1028,
+ -1,
+ /*0xa68e*/ 1058,
+ /*0x104ce*/ 1346,
+ /*0xab87*/ 1181,
+ /*0x2c07*/ 919,
+ /*0x1f2b*/ 733,
+ /*0x1eda*/ 697,
+ /*0x1e5a*/ 631,
+ -1, -1, -1,
+ /*0x24cc*/ 908,
+ /*0x0545*/ 465,
+ -1,
+ /*0x04d6*/ 400,
+ /*0xa65a*/ 1041,
+ -1,
+ /*0x1ed4*/ 694,
+ /*0x1e54*/ 628,
+ /*0x015e*/ 103,
+ -1,
+ /*0x10d56*/ 1444,
+ -1,
+ /*0x0243*/ 221,
+ /*0x0043*/ 2,
+ /*0x1fc3*/ 828,
+ /*0xa654*/ 1038,
+ /*0x03de*/ 278,
+ /*0x0143*/ 89,
+ /*0x00cd*/ 39,
+ /*0x1ca1*/ 557,
+ /*0x118ab*/ 1471,
+ -1,
+ /*0x104d0*/ 1348,
+ /*0x04d0*/ 397,
+ /*0x0187*/ 125,
+ /*0x10c87*/ 1394,
+ /*0x2cde*/ 1022,
+ -1,
+ /*0xa74e*/ 1086,
+ /*0xab71*/ 1159,
+ /*0x10d50*/ 1438,
+ /*0x212b*/ 867,
+ /*0x015c*/ 102,
+ -1, -1,
+ /*0x1e907*/ 1556,
+ -1,
+ /*0x104c8*/ 1340,
+ /*0x1ca5*/ 561,
+ /*0xa756*/ 1090,
+ /*0x03dc*/ 277,
+ -1,
+ /*0x1cad*/ 569,
+ /*0x004b*/ 9,
+ /*0x1fcb*/ 835,
+ /*0x01de*/ 171,
+ /*0x24c4*/ 900,
+ /*0x1058e*/ 1380,
+ -1, -1,
+ /*0x2cdc*/ 1021,
+ /*0x1fec*/ 854,
+ /*0x1f56*/ 755,
+ /*0x046c*/ 351,
+ /*0x016c*/ 110,
+ -1, -1,
+ /*0x104c6*/ 1338,
+ /*0xab7b*/ 1169,
+ /*0xa750*/ 1087,
+ -1, -1,
+ /*0x03ec*/ 285,
+ /*0x1ca3*/ 559,
+ /*0x104c0*/ 1332,
+ /*0x04c0*/ 389,
+ /*0x1ed8*/ 696,
+ /*0x1e58*/ 630,
+ /*0xa7dc*/ 1156,
+ /*0x10c0*/ 516,
+ /*0xa68c*/ 1057,
+ -1,
+ /*0x1f50*/ 752,
+ /*0x0555*/ 481,
+ /*0xa748*/ 1083,
+ /*0xa658*/ 1040,
+ -1, -1, -1, -1,
+ /*0xabb1*/ 1223,
+ /*0x04da*/ 402,
+ -1,
+ /*0xa7cb*/ 1147,
+ /*0x01cb*/ 162,
+ -1,
+ /*0xab7d*/ 1171,
+ /*0x1f48*/ 746,
+ /*0x10d5a*/ 1448,
+ -1, -1,
+ /*0x01ec*/ 178,
+ /*0x04d4*/ 399,
+ -1,
+ /*0xa746*/ 1082,
+ /*0x1f97*/ 791,
+ /*0x10417*/ 1299,
+ /*0x0417*/ 320,
+ -1,
+ /*0x10d54*/ 1442,
+ -1,
+ /*0xa740*/ 1079,
+ -1,
+ /*0xab97*/ 1197,
+ /*0x2c17*/ 935,
+ -1,
+ /*0x0397*/ 248,
+ /*0x0460*/ 345,
+ /*0x0160*/ 104,
+ /*0x00de*/ 55,
+ -1,
+ /*0xa7b1*/ 1131,
+ /*0x01b1*/ 150,
+ /*0x10cb1*/ 1436,
+ /*0x2c60*/ 960,
+ -1,
+ /*0x03e0*/ 279,
+ /*0xa75a*/ 1092,
+ /*0x00c3*/ 29,
+ -1,
+ /*0x1ee2*/ 701,
+ /*0x1e62*/ 635,
+ -1, -1,
+ /*0x1fb7*/ 820,
+ -1,
+ /*0x2ce0*/ 1023,
+ /*0x1058c*/ 1378,
+ /*0xa754*/ 1089,
+ /*0xa662*/ 1045,
+ -1,
+ /*0xab77*/ 1165,
+ /*0xabb7*/ 1229,
+ /*0x00dc*/ 53,
+ /*0xab7f*/ 1173,
+ /*0x0197*/ 136,
+ /*0x10c97*/ 1410,
+ /*0x24ca*/ 906,
+ -1, -1,
+ /*0x1fea*/ 852,
+ /*0x1f54*/ 754,
+ /*0x046a*/ 350,
+ /*0x016a*/ 109,
+ /*0x1c87*/ 537,
+ /*0x01e0*/ 172,
+ /*0x1e917*/ 1572,
+ -1,
+ /*0x00cb*/ 37,
+ /*0x24c2*/ 898,
+ /*0x054d*/ 473,
+ /*0x03ea*/ 284,
+ /*0x04d8*/ 401,
+ -1,
+ /*0x0470*/ 353,
+ /*0x0170*/ 112,
+ -1,
+ /*0x104c5*/ 1337,
+ /*0x04c5*/ 392,
+ /*0x10d58*/ 1446,
+ -1,
+ /*0x2c70*/ 970,
+ /*0x10c5*/ 521,
+ /*0x03f0*/ 287,
+ /*0x01b7*/ 154,
+ /*0x1fe8*/ 850,
+ -1,
+ /*0x0468*/ 349,
+ /*0x0168*/ 108,
+ -1,
+ /*0x046e*/ 352,
+ /*0x016e*/ 111,
+ -1, -1, -1, -1,
+ /*0x03e8*/ 283,
+ /*0x2c6e*/ 968,
+ -1,
+ /*0x03ee*/ 286,
+ /*0x01ea*/ 177,
+ -1,
+ /*0x1ff2*/ 855,
+ -1,
+ /*0x0472*/ 354,
+ /*0x0172*/ 113,
+ -1,
+ /*0x1fe6*/ 848,
+ /*0xa758*/ 1091,
+ /*0x0466*/ 348,
+ /*0x0166*/ 107,
+ /*0x2c72*/ 971,
+ /*0x01f0*/ 180,
+ /*0xfb17*/ 1249,
+ /*0x1fb9*/ 822,
+ -1,
+ /*0x10a9*/ 493,
+ /*0x0139*/ 84,
+ /*0x03e6*/ 282,
+ -1,
+ /*0x24ce*/ 910,
+ -1,
+ /*0xabb9*/ 1231,
+ /*0x2cf2*/ 1027,
+ /*0x1fb3*/ 817,
+ /*0x01e8*/ 176,
+ /*0x04e2*/ 406,
+ -1,
+ /*0x01ee*/ 179,
+ -1, -1, -1,
+ /*0xabb3*/ 1225,
+ /*0x10d62*/ 1456,
+ -1, -1, -1, -1, -1,
+ /*0x0370*/ 230,
+ -1,
+ /*0xff2b*/ 1260,
+ /*0x01f2*/ 182,
+ -1,
+ /*0x0049*/ 1583,
+ /*0x1fc9*/ 833,
+ -1,
+ /*0x01e6*/ 175,
+ /*0x0149*/ 92,
+ /*0x1ee4*/ 702,
+ /*0x1e64*/ 636,
+ -1,
+ /*0x1cb1*/ 573,
+ -1, -1,
+ /*0x1058d*/ 1379,
+ /*0x16eab*/ 1535,
+ /*0x10d55*/ 1443,
+ /*0xa664*/ 1046,
+ -1, -1,
+ /*0x1f29*/ 731,
+ /*0xa762*/ 1096,
+ /*0xa7b3*/ 1133,
+ /*0x01b3*/ 152,
+ -1,
+ /*0x24c8*/ 904,
+ -1, -1,
+ /*0x0372*/ 231,
+ /*0x0543*/ 463,
+ /*0x16e53*/ 1511,
+ -1, -1, -1,
+ /*0x1c97*/ 547,
+ /*0x10a1*/ 485,
+ /*0x1ff4*/ 857,
+ -1,
+ /*0x0474*/ 355,
+ /*0x0174*/ 114,
+ /*0x16e52*/ 1510,
+ -1, -1,
+ /*0xa7c9*/ 1146,
+ -1,
+ /*0x24c6*/ 902,
+ /*0x118a9*/ 1469,
+ /*0x03f4*/ 289,
+ -1, -1,
+ /*0x16e4c*/ 1504,
+ -1,
+ /*0x24c0*/ 896,
+ -1,
+ /*0x10a5*/ 489,
+ -1, -1, -1,
+ /*0x10ad*/ 497,
+ /*0x054b*/ 471,
+ -1, -1, -1,
+ /*0x1cb7*/ 579,
+ /*0x013f*/ 87,
+ -1, -1, -1, -1,
+ /*0xabbf*/ 1237,
+ -1,
+ /*0x2162*/ 871,
+ /*0x1f9b*/ 795,
+ /*0x1041b*/ 1303,
+ /*0x041b*/ 324,
+ -1,
+ /*0x01f4*/ 183,
+ -1, -1,
+ /*0x10a3*/ 487,
+ /*0xab9b*/ 1201,
+ /*0x2c1b*/ 939,
+ -1,
+ /*0x039b*/ 252,
+ -1,
+ /*0x104cd*/ 1345,
+ /*0x04cd*/ 396,
+ /*0x0531*/ 445,
+ -1, -1,
+ /*0x10cd*/ 523,
+ /*0x1ede*/ 699,
+ /*0x1e5e*/ 633,
+ -1,
+ /*0x04e4*/ 407,
+ -1,
+ /*0x16e44*/ 1496,
+ -1, -1, -1,
+ /*0xa65e*/ 1043,
+ /*0x10d64*/ 1458,
+ -1,
+ /*0x1f2d*/ 735,
+ /*0xab79*/ 1167,
+ -1,
+ /*0x118a1*/ 1461,
+ -1,
+ /*0x00c9*/ 35,
+ -1,
+ /*0x1f99*/ 793,
+ /*0x10419*/ 1301,
+ /*0x0419*/ 322,
+ /*0x10c9b*/ 1414,
+ -1,
+ /*0x1edc*/ 698,
+ /*0x1e5c*/ 632,
+ -1,
+ /*0xab99*/ 1199,
+ /*0x2c19*/ 937,
+ -1,
+ /*0x0399*/ 250,
+ -1,
+ /*0x1e91b*/ 1576,
+ /*0xa65c*/ 1042,
+ /*0x118a5*/ 1465,
+ -1, -1, -1,
+ /*0x118ad*/ 1473,
+ /*0xa764*/ 1097,
+ /*0x023d*/ 218,
+ -1,
+ /*0x1cb9*/ 581,
+ -1,
+ /*0x1f4d*/ 751,
+ /*0x013d*/ 86,
+ /*0x1eec*/ 706,
+ /*0x1e6c*/ 640,
+ /*0x0537*/ 451,
+ -1,
+ /*0xabbd*/ 1235,
+ -1,
+ /*0x1cb3*/ 575,
+ -1,
+ /*0x24c5*/ 901,
+ /*0xa66c*/ 1050,
+ /*0x0241*/ 220,
+ /*0x0041*/ 0,
+ -1,
+ /*0x118a3*/ 1463,
+ /*0x10c99*/ 1412,
+ /*0x0141*/ 88,
+ -1,
+ /*0x1f91*/ 785,
+ /*0x10411*/ 1293,
+ /*0x0411*/ 314,
+ -1, -1, -1, -1,
+ /*0x1e919*/ 1574,
+ /*0xab91*/ 1191,
+ /*0x2c11*/ 929,
+ -1,
+ /*0x0391*/ 242,
+ /*0x10570*/ 1352,
+ -1,
+ /*0x023b*/ 217,
+ -1,
+ /*0x1fbb*/ 824,
+ -1,
+ /*0xab7c*/ 1170,
+ /*0x013b*/ 85,
+ -1, -1, -1,
+ /*0x04de*/ 404,
+ /*0xabbb*/ 1233,
+ /*0xabb5*/ 1227,
+ /*0x2164*/ 873,
+ /*0x1e97*/ 662,
+ -1, -1,
+ /*0x10d5e*/ 1452,
+ /*0x104c3*/ 1335,
+ /*0x04c3*/ 391,
+ /*0x16e4a*/ 1502,
+ -1, -1,
+ /*0x10c3*/ 519,
+ /*0x1ee0*/ 700,
+ /*0x1e60*/ 634,
+ -1,
+ /*0x0191*/ 132,
+ /*0x10c91*/ 1404,
+ /*0x10572*/ 1354,
+ -1, -1,
+ /*0x16e42*/ 1494,
+ /*0xa660*/ 1044,
+ /*0x04dc*/ 403,
+ -1,
+ /*0x047e*/ 360,
+ -1,
+ /*0x1e911*/ 1566,
+ -1, -1,
+ /*0x10d5c*/ 1450,
+ /*0x0539*/ 453,
+ /*0x2c7e*/ 973,
+ /*0x01b5*/ 153,
+ /*0x03fe*/ 295,
+ /*0xa75e*/ 1094,
+ -1,
+ /*0x104cb*/ 1343,
+ /*0x04cb*/ 395,
+ -1, -1,
+ /*0x0533*/ 447,
+ -1,
+ /*0x1cbf*/ 585,
+ -1,
+ /*0x04ec*/ 411,
+ -1, -1,
+ /*0x1eea*/ 705,
+ /*0x1e6a*/ 639,
+ -1, -1, -1, -1,
+ /*0x1c9b*/ 551,
+ -1, -1,
+ /*0xa66a*/ 1049,
+ -1,
+ /*0xa75c*/ 1093,
+ /*0x1ef0*/ 708,
+ /*0x1e70*/ 642,
+ /*0x0549*/ 469,
+ /*0x01fe*/ 189,
+ -1,
+ /*0x104b1*/ 1317,
+ -1, -1, -1,
+ /*0xff29*/ 1258,
+ /*0x10b1*/ 501,
+ -1,
+ /*0x16e4e*/ 1506,
+ /*0x1ee8*/ 704,
+ /*0x1e68*/ 638,
+ /*0x00c1*/ 27,
+ /*0x1eee*/ 707,
+ /*0x1e6e*/ 641,
+ -1, -1, -1,
+ /*0xa76c*/ 1101,
+ /*0xa668*/ 1048,
+ /*0x16e56*/ 1514,
+ /*0x16ea9*/ 1533,
+ -1, -1,
+ /*0x1f4b*/ 749,
+ -1, -1,
+ /*0x1ef2*/ 709,
+ /*0x1e72*/ 643,
+ /*0x1c99*/ 549,
+ /*0x10574*/ 1356,
+ /*0x1f6c*/ 764,
+ /*0x1ee6*/ 703,
+ /*0x1e66*/ 637,
+ /*0x00b5*/ 25,
+ -1,
+ /*0x04e0*/ 405,
+ -1,
+ /*0x004f*/ 13,
+ -1,
+ /*0x16e50*/ 1508,
+ /*0xa666*/ 1047,
+ -1,
+ /*0x10d60*/ 1454,
+ -1, -1, -1, -1, -1, -1,
+ /*0x03cf*/ 270,
+ -1,
+ /*0x1cbd*/ 583,
+ /*0x24cd*/ 909,
+ /*0x104b7*/ 1323,
+ /*0x16e48*/ 1500,
+ /*0x053f*/ 459,
+ -1, -1,
+ /*0x10b7*/ 507,
+ -1, -1, -1, -1, -1, -1,
+ /*0xff21*/ 1250,
+ -1,
+ /*0x216c*/ 881,
+ -1, -1,
+ /*0x04ea*/ 410,
+ /*0xa760*/ 1095,
+ /*0x1c91*/ 541,
+ /*0x1ff6*/ 858,
+ /*0x16e46*/ 1498,
+ /*0x0476*/ 356,
+ /*0x0176*/ 115,
+ /*0x118b1*/ 1477,
+ /*0x01cf*/ 164,
+ -1,
+ /*0x16ea1*/ 1525,
+ /*0x16e40*/ 1492,
+ /*0x04f0*/ 413,
+ -1,
+ /*0xff25*/ 1254,
+ /*0x1f95*/ 789,
+ /*0x10415*/ 1297,
+ /*0x0415*/ 318,
+ /*0xff2d*/ 1262,
+ /*0x1cb5*/ 577,
+ /*0xab75*/ 1163,
+ -1, -1,
+ /*0xab95*/ 1195,
+ /*0x2c15*/ 933,
+ /*0x04e8*/ 409,
+ /*0x0395*/ 246,
+ /*0x16e5a*/ 1518,
+ /*0x04ee*/ 412,
+ /*0x16ea5*/ 1529,
+ -1,
+ /*0x1ef4*/ 710,
+ /*0x1e74*/ 644,
+ /*0x16ead*/ 1537,
+ -1,
+ /*0x1ffa*/ 862,
+ /*0xa76a*/ 1100,
+ /*0x047a*/ 358,
+ /*0x16e54*/ 1512,
+ /*0xff23*/ 1252,
+ -1, -1,
+ /*0x04f2*/ 414,
+ /*0x01f6*/ 184,
+ -1, -1,
+ /*0x03fa*/ 293,
+ /*0x04e6*/ 408,
+ /*0x0051*/ 15,
+ /*0x1f6a*/ 762,
+ -1,
+ /*0x2160*/ 869,
+ /*0x13fa*/ 526,
+ /*0x104b9*/ 1325,
+ /*0x16ea3*/ 1527,
+ -1,
+ /*0x10c95*/ 1408,
+ /*0x053d*/ 457,
+ /*0x10b9*/ 509,
+ /*0x118b7*/ 1483,
+ /*0x03d1*/ 272,
+ /*0xa768*/ 1099,
+ -1,
+ /*0x104b3*/ 1319,
+ /*0xa76e*/ 1102,
+ -1,
+ /*0x1e915*/ 1570,
+ /*0x1e9b*/ 666,
+ /*0x10b3*/ 503,
+ -1,
+ /*0x0376*/ 232,
+ -1,
+ /*0x00cf*/ 41,
+ /*0x0541*/ 461,
+ /*0x1f68*/ 760,
+ /*0x01fa*/ 187,
+ -1,
+ /*0x1f6e*/ 766,
+ -1,
+ /*0x1f93*/ 787,
+ /*0x10413*/ 1295,
+ /*0x0413*/ 316,
+ /*0x24c3*/ 899,
+ /*0xa766*/ 1098,
+ /*0x104c9*/ 1341,
+ /*0x04c9*/ 394,
+ /*0x216a*/ 879,
+ /*0xab93*/ 1193,
+ /*0x2c13*/ 931,
+ /*0x01d1*/ 165,
+ /*0x0393*/ 244,
+ /*0x1f8f*/ 783,
+ /*0x1040f*/ 1291,
+ /*0x040f*/ 312,
+ /*0x053b*/ 455,
+ /*0x0535*/ 449,
+ -1, -1,
+ /*0x16e58*/ 1516,
+ /*0xab8f*/ 1189,
+ /*0x2c0f*/ 927,
+ -1,
+ /*0x038f*/ 240,
+ /*0x1f39*/ 739,
+ /*0x16e45*/ 1497,
+ /*0x1e99*/ 664,
+ -1,
+ /*0x1f81*/ 769,
+ /*0x10401*/ 1277,
+ /*0x0401*/ 298,
+ -1,
+ /*0x2168*/ 877,
+ /*0x24cb*/ 907,
+ /*0xfb15*/ 1247,
+ /*0x216e*/ 883,
+ /*0xab81*/ 1175,
+ /*0x2c01*/ 913,
+ /*0x04f4*/ 415,
+ -1,
+ /*0x0193*/ 133,
+ /*0x10c93*/ 1406,
+ -1, -1,
+ /*0x1ff8*/ 860,
+ /*0x1057e*/ 1365,
+ /*0x0478*/ 357,
+ /*0x0178*/ 116,
+ -1, -1,
+ /*0x118b9*/ 1485,
+ /*0x1e913*/ 1568,
+ /*0x018f*/ 130,
+ /*0x10c8f*/ 1402,
+ /*0x2166*/ 875,
+ /*0x1f49*/ 747,
+ -1, -1, -1, -1,
+ /*0x118b3*/ 1479,
+ /*0x13f8*/ 524,
+ /*0x104bf*/ 1331,
+ /*0x1e90f*/ 1564,
+ /*0x1f9f*/ 799,
+ /*0x1041f*/ 1307,
+ /*0x041f*/ 328,
+ /*0x10bf*/ 515,
+ /*0x0181*/ 121,
+ /*0x10c81*/ 1388,
+ -1, -1,
+ /*0xab9f*/ 1205,
+ /*0x2c1f*/ 943,
+ /*0x00d1*/ 43,
+ /*0x039f*/ 256,
+ -1, -1, -1,
+ /*0x1e901*/ 1550,
+ /*0x1f8b*/ 779,
+ /*0x1040b*/ 1287,
+ /*0x040b*/ 308,
+ -1,
+ /*0x01f8*/ 186,
+ -1, -1, -1,
+ /*0xab8b*/ 1185,
+ /*0x2c0b*/ 923,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1c95*/ 545,
+ /*0x16e55*/ 1513,
+ /*0xfb13*/ 1245,
+ -1, -1, -1, -1, -1,
+ /*0x019f*/ 140,
+ /*0x10c9f*/ 1418,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1f3f*/ 745,
+ /*0x24b7*/ 887,
+ -1,
+ /*0x1e91f*/ 1580,
+ -1,
+ /*0x1efe*/ 715,
+ /*0x1e7e*/ 649,
+ /*0xa78b*/ 1111,
+ /*0x018b*/ 128,
+ /*0x10c8b*/ 1398,
+ -1,
+ /*0x1f1b*/ 727,
+ -1,
+ /*0x054f*/ 475,
+ /*0xfb01*/ 1239,
+ -1, -1,
+ /*0xff31*/ 1266,
+ -1,
+ /*0x1e90b*/ 1560,
+ -1, -1,
+ /*0x104bd*/ 1329,
+ -1, -1, -1,
+ /*0x118bf*/ 1491,
+ /*0x10bd*/ 513,
+ -1, -1, -1, -1,
+ /*0x16eb1*/ 1541,
+ -1, -1, -1, -1, -1,
+ /*0x104c1*/ 1333,
+ /*0x04c1*/ 390,
+ -1, -1, -1,
+ /*0x10c1*/ 517,
+ -1, -1, -1,
+ /*0x10576*/ 1358,
+ /*0x1c93*/ 543,
+ /*0x1f19*/ 725,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x104bb*/ 1327,
+ /*0x104b5*/ 1321,
+ -1,
+ /*0x16e4d*/ 1505,
+ -1,
+ /*0x10bb*/ 511,
+ /*0x10b5*/ 505,
+ -1, -1, -1,
+ /*0xff37*/ 1272,
+ -1,
+ /*0x24b9*/ 889,
+ /*0x1f3d*/ 743,
+ -1, -1, -1,
+ /*0x1c81*/ 531,
+ -1, -1,
+ /*0x1057a*/ 1362,
+ -1, -1, -1, -1,
+ /*0x16eb7*/ 1547,
+ -1, -1, -1, -1, -1, -1,
+ /*0x04fe*/ 420,
+ -1, -1,
+ /*0x0551*/ 477,
+ -1, -1, -1,
+ /*0x118bd*/ 1489,
+ -1, -1, -1,
+ /*0x24c9*/ 905,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1f3b*/ 741,
+ -1, -1,
+ /*0x1c9f*/ 555,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1ef6*/ 711,
+ /*0x1e76*/ 645,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa77e*/ 1106,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x118bb*/ 1487,
+ /*0x118b5*/ 1481,
+ -1, -1,
+ /*0xff39*/ 1274,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0xff33*/ 1268,
+ -1,
+ /*0x1efa*/ 713,
+ /*0x1e7a*/ 647,
+ /*0x16e5e*/ 1522,
+ -1, -1, -1, -1, -1,
+ /*0x24bf*/ 895,
+ -1, -1,
+ /*0x16e43*/ 1495,
+ -1,
+ /*0x16eb3*/ 1543,
+ -1, -1,
+ /*0x10578*/ 1360,
+ -1,
+ /*0x104cf*/ 1347,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x16e5c*/ 1520,
+ -1, -1, -1,
+ /*0x10587*/ 1374,
+ /*0x0587*/ 483,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x16e4b*/ 1503,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x04f6*/ 416,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x24bd*/ 893,
+ -1, -1, -1, -1, -1,
+ /*0x04fa*/ 418,
+ -1,
+ /*0x1ef8*/ 712,
+ /*0x1e78*/ 646,
+ -1, -1, -1, -1, -1, -1,
+ /*0x24c1*/ 897,
+ -1, -1,
+ /*0x104d1*/ 1349,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x10d51*/ 1439,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x24bb*/ 891,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x04f8*/ 417,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xff35*/ 1270,
+ -1, -1, -1, -1,
+ /*0x1f0f*/ 723,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x16eb5*/ 1545,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x16e49*/ 1501,
+ -1, -1, -1, -1,
+ /*0x24cf*/ 911,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x1f0b*/ 719,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x16e41*/ 1493,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x10591*/ 1383,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0x16e4f*/ 1507,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x16e51*/ 1509,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x10595*/ 1386,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x1058f*/ 1381,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x10581*/ 1368,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xab70*/ 1158,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xab72*/ 1160,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0xab74*/ 1162,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0xab7e*/ 1172,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xab76*/ 1164,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xab7a*/ 1168,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0xab78*/ 1166
+ };
+
+ if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseFold_11_hash(code);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code1_equal(code, CaseFold_11_Table[s].from))
+ return &CaseFold_11_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const CaseUnfold_11_Type CaseUnfold_11_Table[] = {
+#define CaseUnfold_11 (*(CaseUnfold_11_Type (*)[1450])(CaseUnfold_11_Table+0))
+ {0x0061, {1|U, {0x0041}}},
+ {0x0062, {1|U, {0x0042}}},
+ {0x0063, {1|U, {0x0043}}},
+ {0x0064, {1|U, {0x0044}}},
+ {0x0065, {1|U, {0x0045}}},
+ {0x0066, {1|U, {0x0046}}},
+ {0x0067, {1|U, {0x0047}}},
+ {0x0068, {1|U, {0x0048}}},
+ {0x006a, {1|U, {0x004a}}},
+ {0x006b, {2|U, {0x004b, 0x212a}}},
+ {0x006c, {1|U, {0x004c}}},
+ {0x006d, {1|U, {0x004d}}},
+ {0x006e, {1|U, {0x004e}}},
+ {0x006f, {1|U, {0x004f}}},
+ {0x0070, {1|U, {0x0050}}},
+ {0x0071, {1|U, {0x0051}}},
+ {0x0072, {1|U, {0x0052}}},
+ {0x0073, {2|U, {0x0053, 0x017f}}},
+ {0x0074, {1|U, {0x0054}}},
+ {0x0075, {1|U, {0x0055}}},
+ {0x0076, {1|U, {0x0056}}},
+ {0x0077, {1|U, {0x0057}}},
+ {0x0078, {1|U, {0x0058}}},
+ {0x0079, {1|U, {0x0059}}},
+ {0x007a, {1|U, {0x005a}}},
+ {0x00e0, {1|U, {0x00c0}}},
+ {0x00e1, {1|U, {0x00c1}}},
+ {0x00e2, {1|U, {0x00c2}}},
+ {0x00e3, {1|U, {0x00c3}}},
+ {0x00e4, {1|U, {0x00c4}}},
+ {0x00e5, {2|U, {0x00c5, 0x212b}}},
+ {0x00e6, {1|U, {0x00c6}}},
+ {0x00e7, {1|U, {0x00c7}}},
+ {0x00e8, {1|U, {0x00c8}}},
+ {0x00e9, {1|U, {0x00c9}}},
+ {0x00ea, {1|U, {0x00ca}}},
+ {0x00eb, {1|U, {0x00cb}}},
+ {0x00ec, {1|U, {0x00cc}}},
+ {0x00ed, {1|U, {0x00cd}}},
+ {0x00ee, {1|U, {0x00ce}}},
+ {0x00ef, {1|U, {0x00cf}}},
+ {0x00f0, {1|U, {0x00d0}}},
+ {0x00f1, {1|U, {0x00d1}}},
+ {0x00f2, {1|U, {0x00d2}}},
+ {0x00f3, {1|U, {0x00d3}}},
+ {0x00f4, {1|U, {0x00d4}}},
+ {0x00f5, {1|U, {0x00d5}}},
+ {0x00f6, {1|U, {0x00d6}}},
+ {0x00f8, {1|U, {0x00d8}}},
+ {0x00f9, {1|U, {0x00d9}}},
+ {0x00fa, {1|U, {0x00da}}},
+ {0x00fb, {1|U, {0x00db}}},
+ {0x00fc, {1|U, {0x00dc}}},
+ {0x00fd, {1|U, {0x00dd}}},
+ {0x00fe, {1|U, {0x00de}}},
+ {0x00ff, {1|U, {0x0178}}},
+ {0x0101, {1|U, {0x0100}}},
+ {0x0103, {1|U, {0x0102}}},
+ {0x0105, {1|U, {0x0104}}},
+ {0x0107, {1|U, {0x0106}}},
+ {0x0109, {1|U, {0x0108}}},
+ {0x010b, {1|U, {0x010a}}},
+ {0x010d, {1|U, {0x010c}}},
+ {0x010f, {1|U, {0x010e}}},
+ {0x0111, {1|U, {0x0110}}},
+ {0x0113, {1|U, {0x0112}}},
+ {0x0115, {1|U, {0x0114}}},
+ {0x0117, {1|U, {0x0116}}},
+ {0x0119, {1|U, {0x0118}}},
+ {0x011b, {1|U, {0x011a}}},
+ {0x011d, {1|U, {0x011c}}},
+ {0x011f, {1|U, {0x011e}}},
+ {0x0121, {1|U, {0x0120}}},
+ {0x0123, {1|U, {0x0122}}},
+ {0x0125, {1|U, {0x0124}}},
+ {0x0127, {1|U, {0x0126}}},
+ {0x0129, {1|U, {0x0128}}},
+ {0x012b, {1|U, {0x012a}}},
+ {0x012d, {1|U, {0x012c}}},
+ {0x012f, {1|U, {0x012e}}},
+ {0x0133, {1|U, {0x0132}}},
+ {0x0135, {1|U, {0x0134}}},
+ {0x0137, {1|U, {0x0136}}},
+ {0x013a, {1|U, {0x0139}}},
+ {0x013c, {1|U, {0x013b}}},
+ {0x013e, {1|U, {0x013d}}},
+ {0x0140, {1|U, {0x013f}}},
+ {0x0142, {1|U, {0x0141}}},
+ {0x0144, {1|U, {0x0143}}},
+ {0x0146, {1|U, {0x0145}}},
+ {0x0148, {1|U, {0x0147}}},
+ {0x014b, {1|U, {0x014a}}},
+ {0x014d, {1|U, {0x014c}}},
+ {0x014f, {1|U, {0x014e}}},
+ {0x0151, {1|U, {0x0150}}},
+ {0x0153, {1|U, {0x0152}}},
+ {0x0155, {1|U, {0x0154}}},
+ {0x0157, {1|U, {0x0156}}},
+ {0x0159, {1|U, {0x0158}}},
+ {0x015b, {1|U, {0x015a}}},
+ {0x015d, {1|U, {0x015c}}},
+ {0x015f, {1|U, {0x015e}}},
+ {0x0161, {1|U, {0x0160}}},
+ {0x0163, {1|U, {0x0162}}},
+ {0x0165, {1|U, {0x0164}}},
+ {0x0167, {1|U, {0x0166}}},
+ {0x0169, {1|U, {0x0168}}},
+ {0x016b, {1|U, {0x016a}}},
+ {0x016d, {1|U, {0x016c}}},
+ {0x016f, {1|U, {0x016e}}},
+ {0x0171, {1|U, {0x0170}}},
+ {0x0173, {1|U, {0x0172}}},
+ {0x0175, {1|U, {0x0174}}},
+ {0x0177, {1|U, {0x0176}}},
+ {0x017a, {1|U, {0x0179}}},
+ {0x017c, {1|U, {0x017b}}},
+ {0x017e, {1|U, {0x017d}}},
+ {0x0180, {1|U, {0x0243}}},
+ {0x0183, {1|U, {0x0182}}},
+ {0x0185, {1|U, {0x0184}}},
+ {0x0188, {1|U, {0x0187}}},
+ {0x018c, {1|U, {0x018b}}},
+ {0x0192, {1|U, {0x0191}}},
+ {0x0195, {1|U, {0x01f6}}},
+ {0x0199, {1|U, {0x0198}}},
+ {0x019a, {1|U, {0x023d}}},
+ {0x019b, {1|U, {0xa7dc}}},
+ {0x019e, {1|U, {0x0220}}},
+ {0x01a1, {1|U, {0x01a0}}},
+ {0x01a3, {1|U, {0x01a2}}},
+ {0x01a5, {1|U, {0x01a4}}},
+ {0x01a8, {1|U, {0x01a7}}},
+ {0x01ad, {1|U, {0x01ac}}},
+ {0x01b0, {1|U, {0x01af}}},
+ {0x01b4, {1|U, {0x01b3}}},
+ {0x01b6, {1|U, {0x01b5}}},
+ {0x01b9, {1|U, {0x01b8}}},
+ {0x01bd, {1|U, {0x01bc}}},
+ {0x01bf, {1|U, {0x01f7}}},
+ {0x01c6, {2|U|ST, {0x01c4, 0x01c5}}},
+ {0x01c9, {2|U|ST, {0x01c7, 0x01c8}}},
+ {0x01cc, {2|U|ST, {0x01ca, 0x01cb}}},
+ {0x01ce, {1|U, {0x01cd}}},
+ {0x01d0, {1|U, {0x01cf}}},
+ {0x01d2, {1|U, {0x01d1}}},
+ {0x01d4, {1|U, {0x01d3}}},
+ {0x01d6, {1|U, {0x01d5}}},
+ {0x01d8, {1|U, {0x01d7}}},
+ {0x01da, {1|U, {0x01d9}}},
+ {0x01dc, {1|U, {0x01db}}},
+ {0x01dd, {1|U, {0x018e}}},
+ {0x01df, {1|U, {0x01de}}},
+ {0x01e1, {1|U, {0x01e0}}},
+ {0x01e3, {1|U, {0x01e2}}},
+ {0x01e5, {1|U, {0x01e4}}},
+ {0x01e7, {1|U, {0x01e6}}},
+ {0x01e9, {1|U, {0x01e8}}},
+ {0x01eb, {1|U, {0x01ea}}},
+ {0x01ed, {1|U, {0x01ec}}},
+ {0x01ef, {1|U, {0x01ee}}},
+ {0x01f3, {2|U|ST, {0x01f1, 0x01f2}}},
+ {0x01f5, {1|U, {0x01f4}}},
+ {0x01f9, {1|U, {0x01f8}}},
+ {0x01fb, {1|U, {0x01fa}}},
+ {0x01fd, {1|U, {0x01fc}}},
+ {0x01ff, {1|U, {0x01fe}}},
+ {0x0201, {1|U, {0x0200}}},
+ {0x0203, {1|U, {0x0202}}},
+ {0x0205, {1|U, {0x0204}}},
+ {0x0207, {1|U, {0x0206}}},
+ {0x0209, {1|U, {0x0208}}},
+ {0x020b, {1|U, {0x020a}}},
+ {0x020d, {1|U, {0x020c}}},
+ {0x020f, {1|U, {0x020e}}},
+ {0x0211, {1|U, {0x0210}}},
+ {0x0213, {1|U, {0x0212}}},
+ {0x0215, {1|U, {0x0214}}},
+ {0x0217, {1|U, {0x0216}}},
+ {0x0219, {1|U, {0x0218}}},
+ {0x021b, {1|U, {0x021a}}},
+ {0x021d, {1|U, {0x021c}}},
+ {0x021f, {1|U, {0x021e}}},
+ {0x0223, {1|U, {0x0222}}},
+ {0x0225, {1|U, {0x0224}}},
+ {0x0227, {1|U, {0x0226}}},
+ {0x0229, {1|U, {0x0228}}},
+ {0x022b, {1|U, {0x022a}}},
+ {0x022d, {1|U, {0x022c}}},
+ {0x022f, {1|U, {0x022e}}},
+ {0x0231, {1|U, {0x0230}}},
+ {0x0233, {1|U, {0x0232}}},
+ {0x023c, {1|U, {0x023b}}},
+ {0x023f, {1|U, {0x2c7e}}},
+ {0x0240, {1|U, {0x2c7f}}},
+ {0x0242, {1|U, {0x0241}}},
+ {0x0247, {1|U, {0x0246}}},
+ {0x0249, {1|U, {0x0248}}},
+ {0x024b, {1|U, {0x024a}}},
+ {0x024d, {1|U, {0x024c}}},
+ {0x024f, {1|U, {0x024e}}},
+ {0x0250, {1|U, {0x2c6f}}},
+ {0x0251, {1|U, {0x2c6d}}},
+ {0x0252, {1|U, {0x2c70}}},
+ {0x0253, {1|U, {0x0181}}},
+ {0x0254, {1|U, {0x0186}}},
+ {0x0256, {1|U, {0x0189}}},
+ {0x0257, {1|U, {0x018a}}},
+ {0x0259, {1|U, {0x018f}}},
+ {0x025b, {1|U, {0x0190}}},
+ {0x025c, {1|U, {0xa7ab}}},
+ {0x0260, {1|U, {0x0193}}},
+ {0x0261, {1|U, {0xa7ac}}},
+ {0x0263, {1|U, {0x0194}}},
+ {0x0264, {1|U, {0xa7cb}}},
+ {0x0265, {1|U, {0xa78d}}},
+ {0x0266, {1|U, {0xa7aa}}},
+ {0x0268, {1|U, {0x0197}}},
+ {0x0269, {1|U, {0x0196}}},
+ {0x026a, {1|U, {0xa7ae}}},
+ {0x026b, {1|U, {0x2c62}}},
+ {0x026c, {1|U, {0xa7ad}}},
+ {0x026f, {1|U, {0x019c}}},
+ {0x0271, {1|U, {0x2c6e}}},
+ {0x0272, {1|U, {0x019d}}},
+ {0x0275, {1|U, {0x019f}}},
+ {0x027d, {1|U, {0x2c64}}},
+ {0x0280, {1|U, {0x01a6}}},
+ {0x0282, {1|U, {0xa7c5}}},
+ {0x0283, {1|U, {0x01a9}}},
+ {0x0287, {1|U, {0xa7b1}}},
+ {0x0288, {1|U, {0x01ae}}},
+ {0x0289, {1|U, {0x0244}}},
+ {0x028a, {1|U, {0x01b1}}},
+ {0x028b, {1|U, {0x01b2}}},
+ {0x028c, {1|U, {0x0245}}},
+ {0x0292, {1|U, {0x01b7}}},
+ {0x029d, {1|U, {0xa7b2}}},
+ {0x029e, {1|U, {0xa7b0}}},
+ {0x0371, {1|U, {0x0370}}},
+ {0x0373, {1|U, {0x0372}}},
+ {0x0377, {1|U, {0x0376}}},
+ {0x037b, {1|U, {0x03fd}}},
+ {0x037c, {1|U, {0x03fe}}},
+ {0x037d, {1|U, {0x03ff}}},
+ {0x03ac, {1|U, {0x0386}}},
+ {0x03ad, {1|U, {0x0388}}},
+ {0x03ae, {1|U, {0x0389}}},
+ {0x03af, {1|U, {0x038a}}},
+ {0x03b1, {1|U, {0x0391}}},
+ {0x03b2, {2|U, {0x0392, 0x03d0}}},
+ {0x03b3, {1|U, {0x0393}}},
+ {0x03b4, {1|U, {0x0394}}},
+ {0x03b5, {2|U, {0x0395, 0x03f5}}},
+ {0x03b6, {1|U, {0x0396}}},
+ {0x03b7, {1|U, {0x0397}}},
+ {0x03b8, {3|U, {0x0398, 0x03d1, 0x03f4}}},
+ {0x03b9, {3|U, {0x0399, 0x0345, 0x1fbe}}},
+ {0x03ba, {2|U, {0x039a, 0x03f0}}},
+ {0x03bb, {1|U, {0x039b}}},
+ {0x03bc, {2|U, {0x039c, 0x00b5}}},
+ {0x03bd, {1|U, {0x039d}}},
+ {0x03be, {1|U, {0x039e}}},
+ {0x03bf, {1|U, {0x039f}}},
+ {0x03c0, {2|U, {0x03a0, 0x03d6}}},
+ {0x03c1, {2|U, {0x03a1, 0x03f1}}},
+ {0x03c3, {2|U, {0x03a3, 0x03c2}}},
+ {0x03c4, {1|U, {0x03a4}}},
+ {0x03c5, {1|U, {0x03a5}}},
+ {0x03c6, {2|U, {0x03a6, 0x03d5}}},
+ {0x03c7, {1|U, {0x03a7}}},
+ {0x03c8, {1|U, {0x03a8}}},
+ {0x03c9, {2|U, {0x03a9, 0x2126}}},
+ {0x03ca, {1|U, {0x03aa}}},
+ {0x03cb, {1|U, {0x03ab}}},
+ {0x03cc, {1|U, {0x038c}}},
+ {0x03cd, {1|U, {0x038e}}},
+ {0x03ce, {1|U, {0x038f}}},
+ {0x03d7, {1|U, {0x03cf}}},
+ {0x03d9, {1|U, {0x03d8}}},
+ {0x03db, {1|U, {0x03da}}},
+ {0x03dd, {1|U, {0x03dc}}},
+ {0x03df, {1|U, {0x03de}}},
+ {0x03e1, {1|U, {0x03e0}}},
+ {0x03e3, {1|U, {0x03e2}}},
+ {0x03e5, {1|U, {0x03e4}}},
+ {0x03e7, {1|U, {0x03e6}}},
+ {0x03e9, {1|U, {0x03e8}}},
+ {0x03eb, {1|U, {0x03ea}}},
+ {0x03ed, {1|U, {0x03ec}}},
+ {0x03ef, {1|U, {0x03ee}}},
+ {0x03f2, {1|U, {0x03f9}}},
+ {0x03f3, {1|U, {0x037f}}},
+ {0x03f8, {1|U, {0x03f7}}},
+ {0x03fb, {1|U, {0x03fa}}},
+ {0x0430, {1|U, {0x0410}}},
+ {0x0431, {1|U, {0x0411}}},
+ {0x0432, {2|U, {0x0412, 0x1c80}}},
+ {0x0433, {1|U, {0x0413}}},
+ {0x0434, {2|U, {0x0414, 0x1c81}}},
+ {0x0435, {1|U, {0x0415}}},
+ {0x0436, {1|U, {0x0416}}},
+ {0x0437, {1|U, {0x0417}}},
+ {0x0438, {1|U, {0x0418}}},
+ {0x0439, {1|U, {0x0419}}},
+ {0x043a, {1|U, {0x041a}}},
+ {0x043b, {1|U, {0x041b}}},
+ {0x043c, {1|U, {0x041c}}},
+ {0x043d, {1|U, {0x041d}}},
+ {0x043e, {2|U, {0x041e, 0x1c82}}},
+ {0x043f, {1|U, {0x041f}}},
+ {0x0440, {1|U, {0x0420}}},
+ {0x0441, {2|U, {0x0421, 0x1c83}}},
+ {0x0442, {3|U, {0x0422, 0x1c84, 0x1c85}}},
+ {0x0443, {1|U, {0x0423}}},
+ {0x0444, {1|U, {0x0424}}},
+ {0x0445, {1|U, {0x0425}}},
+ {0x0446, {1|U, {0x0426}}},
+ {0x0447, {1|U, {0x0427}}},
+ {0x0448, {1|U, {0x0428}}},
+ {0x0449, {1|U, {0x0429}}},
+ {0x044a, {2|U, {0x042a, 0x1c86}}},
+ {0x044b, {1|U, {0x042b}}},
+ {0x044c, {1|U, {0x042c}}},
+ {0x044d, {1|U, {0x042d}}},
+ {0x044e, {1|U, {0x042e}}},
+ {0x044f, {1|U, {0x042f}}},
+ {0x0450, {1|U, {0x0400}}},
+ {0x0451, {1|U, {0x0401}}},
+ {0x0452, {1|U, {0x0402}}},
+ {0x0453, {1|U, {0x0403}}},
+ {0x0454, {1|U, {0x0404}}},
+ {0x0455, {1|U, {0x0405}}},
+ {0x0456, {1|U, {0x0406}}},
+ {0x0457, {1|U, {0x0407}}},
+ {0x0458, {1|U, {0x0408}}},
+ {0x0459, {1|U, {0x0409}}},
+ {0x045a, {1|U, {0x040a}}},
+ {0x045b, {1|U, {0x040b}}},
+ {0x045c, {1|U, {0x040c}}},
+ {0x045d, {1|U, {0x040d}}},
+ {0x045e, {1|U, {0x040e}}},
+ {0x045f, {1|U, {0x040f}}},
+ {0x0461, {1|U, {0x0460}}},
+ {0x0463, {2|U, {0x0462, 0x1c87}}},
+ {0x0465, {1|U, {0x0464}}},
+ {0x0467, {1|U, {0x0466}}},
+ {0x0469, {1|U, {0x0468}}},
+ {0x046b, {1|U, {0x046a}}},
+ {0x046d, {1|U, {0x046c}}},
+ {0x046f, {1|U, {0x046e}}},
+ {0x0471, {1|U, {0x0470}}},
+ {0x0473, {1|U, {0x0472}}},
+ {0x0475, {1|U, {0x0474}}},
+ {0x0477, {1|U, {0x0476}}},
+ {0x0479, {1|U, {0x0478}}},
+ {0x047b, {1|U, {0x047a}}},
+ {0x047d, {1|U, {0x047c}}},
+ {0x047f, {1|U, {0x047e}}},
+ {0x0481, {1|U, {0x0480}}},
+ {0x048b, {1|U, {0x048a}}},
+ {0x048d, {1|U, {0x048c}}},
+ {0x048f, {1|U, {0x048e}}},
+ {0x0491, {1|U, {0x0490}}},
+ {0x0493, {1|U, {0x0492}}},
+ {0x0495, {1|U, {0x0494}}},
+ {0x0497, {1|U, {0x0496}}},
+ {0x0499, {1|U, {0x0498}}},
+ {0x049b, {1|U, {0x049a}}},
+ {0x049d, {1|U, {0x049c}}},
+ {0x049f, {1|U, {0x049e}}},
+ {0x04a1, {1|U, {0x04a0}}},
+ {0x04a3, {1|U, {0x04a2}}},
+ {0x04a5, {1|U, {0x04a4}}},
+ {0x04a7, {1|U, {0x04a6}}},
+ {0x04a9, {1|U, {0x04a8}}},
+ {0x04ab, {1|U, {0x04aa}}},
+ {0x04ad, {1|U, {0x04ac}}},
+ {0x04af, {1|U, {0x04ae}}},
+ {0x04b1, {1|U, {0x04b0}}},
+ {0x04b3, {1|U, {0x04b2}}},
+ {0x04b5, {1|U, {0x04b4}}},
+ {0x04b7, {1|U, {0x04b6}}},
+ {0x04b9, {1|U, {0x04b8}}},
+ {0x04bb, {1|U, {0x04ba}}},
+ {0x04bd, {1|U, {0x04bc}}},
+ {0x04bf, {1|U, {0x04be}}},
+ {0x04c2, {1|U, {0x04c1}}},
+ {0x04c4, {1|U, {0x04c3}}},
+ {0x04c6, {1|U, {0x04c5}}},
+ {0x04c8, {1|U, {0x04c7}}},
+ {0x04ca, {1|U, {0x04c9}}},
+ {0x04cc, {1|U, {0x04cb}}},
+ {0x04ce, {1|U, {0x04cd}}},
+ {0x04cf, {1|U, {0x04c0}}},
+ {0x04d1, {1|U, {0x04d0}}},
+ {0x04d3, {1|U, {0x04d2}}},
+ {0x04d5, {1|U, {0x04d4}}},
+ {0x04d7, {1|U, {0x04d6}}},
+ {0x04d9, {1|U, {0x04d8}}},
+ {0x04db, {1|U, {0x04da}}},
+ {0x04dd, {1|U, {0x04dc}}},
+ {0x04df, {1|U, {0x04de}}},
+ {0x04e1, {1|U, {0x04e0}}},
+ {0x04e3, {1|U, {0x04e2}}},
+ {0x04e5, {1|U, {0x04e4}}},
+ {0x04e7, {1|U, {0x04e6}}},
+ {0x04e9, {1|U, {0x04e8}}},
+ {0x04eb, {1|U, {0x04ea}}},
+ {0x04ed, {1|U, {0x04ec}}},
+ {0x04ef, {1|U, {0x04ee}}},
+ {0x04f1, {1|U, {0x04f0}}},
+ {0x04f3, {1|U, {0x04f2}}},
+ {0x04f5, {1|U, {0x04f4}}},
+ {0x04f7, {1|U, {0x04f6}}},
+ {0x04f9, {1|U, {0x04f8}}},
+ {0x04fb, {1|U, {0x04fa}}},
+ {0x04fd, {1|U, {0x04fc}}},
+ {0x04ff, {1|U, {0x04fe}}},
+ {0x0501, {1|U, {0x0500}}},
+ {0x0503, {1|U, {0x0502}}},
+ {0x0505, {1|U, {0x0504}}},
+ {0x0507, {1|U, {0x0506}}},
+ {0x0509, {1|U, {0x0508}}},
+ {0x050b, {1|U, {0x050a}}},
+ {0x050d, {1|U, {0x050c}}},
+ {0x050f, {1|U, {0x050e}}},
+ {0x0511, {1|U, {0x0510}}},
+ {0x0513, {1|U, {0x0512}}},
+ {0x0515, {1|U, {0x0514}}},
+ {0x0517, {1|U, {0x0516}}},
+ {0x0519, {1|U, {0x0518}}},
+ {0x051b, {1|U, {0x051a}}},
+ {0x051d, {1|U, {0x051c}}},
+ {0x051f, {1|U, {0x051e}}},
+ {0x0521, {1|U, {0x0520}}},
+ {0x0523, {1|U, {0x0522}}},
+ {0x0525, {1|U, {0x0524}}},
+ {0x0527, {1|U, {0x0526}}},
+ {0x0529, {1|U, {0x0528}}},
+ {0x052b, {1|U, {0x052a}}},
+ {0x052d, {1|U, {0x052c}}},
+ {0x052f, {1|U, {0x052e}}},
+ {0x0561, {1|U, {0x0531}}},
+ {0x0562, {1|U, {0x0532}}},
+ {0x0563, {1|U, {0x0533}}},
+ {0x0564, {1|U, {0x0534}}},
+ {0x0565, {1|U, {0x0535}}},
+ {0x0566, {1|U, {0x0536}}},
+ {0x0567, {1|U, {0x0537}}},
+ {0x0568, {1|U, {0x0538}}},
+ {0x0569, {1|U, {0x0539}}},
+ {0x056a, {1|U, {0x053a}}},
+ {0x056b, {1|U, {0x053b}}},
+ {0x056c, {1|U, {0x053c}}},
+ {0x056d, {1|U, {0x053d}}},
+ {0x056e, {1|U, {0x053e}}},
+ {0x056f, {1|U, {0x053f}}},
+ {0x0570, {1|U, {0x0540}}},
+ {0x0571, {1|U, {0x0541}}},
+ {0x0572, {1|U, {0x0542}}},
+ {0x0573, {1|U, {0x0543}}},
+ {0x0574, {1|U, {0x0544}}},
+ {0x0575, {1|U, {0x0545}}},
+ {0x0576, {1|U, {0x0546}}},
+ {0x0577, {1|U, {0x0547}}},
+ {0x0578, {1|U, {0x0548}}},
+ {0x0579, {1|U, {0x0549}}},
+ {0x057a, {1|U, {0x054a}}},
+ {0x057b, {1|U, {0x054b}}},
+ {0x057c, {1|U, {0x054c}}},
+ {0x057d, {1|U, {0x054d}}},
+ {0x057e, {1|U, {0x054e}}},
+ {0x057f, {1|U, {0x054f}}},
+ {0x0580, {1|U, {0x0550}}},
+ {0x0581, {1|U, {0x0551}}},
+ {0x0582, {1|U, {0x0552}}},
+ {0x0583, {1|U, {0x0553}}},
+ {0x0584, {1|U, {0x0554}}},
+ {0x0585, {1|U, {0x0555}}},
+ {0x0586, {1|U, {0x0556}}},
+ {0x10d0, {1|U|IT, {0x1c90}}},
+ {0x10d1, {1|U|IT, {0x1c91}}},
+ {0x10d2, {1|U|IT, {0x1c92}}},
+ {0x10d3, {1|U|IT, {0x1c93}}},
+ {0x10d4, {1|U|IT, {0x1c94}}},
+ {0x10d5, {1|U|IT, {0x1c95}}},
+ {0x10d6, {1|U|IT, {0x1c96}}},
+ {0x10d7, {1|U|IT, {0x1c97}}},
+ {0x10d8, {1|U|IT, {0x1c98}}},
+ {0x10d9, {1|U|IT, {0x1c99}}},
+ {0x10da, {1|U|IT, {0x1c9a}}},
+ {0x10db, {1|U|IT, {0x1c9b}}},
+ {0x10dc, {1|U|IT, {0x1c9c}}},
+ {0x10dd, {1|U|IT, {0x1c9d}}},
+ {0x10de, {1|U|IT, {0x1c9e}}},
+ {0x10df, {1|U|IT, {0x1c9f}}},
+ {0x10e0, {1|U|IT, {0x1ca0}}},
+ {0x10e1, {1|U|IT, {0x1ca1}}},
+ {0x10e2, {1|U|IT, {0x1ca2}}},
+ {0x10e3, {1|U|IT, {0x1ca3}}},
+ {0x10e4, {1|U|IT, {0x1ca4}}},
+ {0x10e5, {1|U|IT, {0x1ca5}}},
+ {0x10e6, {1|U|IT, {0x1ca6}}},
+ {0x10e7, {1|U|IT, {0x1ca7}}},
+ {0x10e8, {1|U|IT, {0x1ca8}}},
+ {0x10e9, {1|U|IT, {0x1ca9}}},
+ {0x10ea, {1|U|IT, {0x1caa}}},
+ {0x10eb, {1|U|IT, {0x1cab}}},
+ {0x10ec, {1|U|IT, {0x1cac}}},
+ {0x10ed, {1|U|IT, {0x1cad}}},
+ {0x10ee, {1|U|IT, {0x1cae}}},
+ {0x10ef, {1|U|IT, {0x1caf}}},
+ {0x10f0, {1|U|IT, {0x1cb0}}},
+ {0x10f1, {1|U|IT, {0x1cb1}}},
+ {0x10f2, {1|U|IT, {0x1cb2}}},
+ {0x10f3, {1|U|IT, {0x1cb3}}},
+ {0x10f4, {1|U|IT, {0x1cb4}}},
+ {0x10f5, {1|U|IT, {0x1cb5}}},
+ {0x10f6, {1|U|IT, {0x1cb6}}},
+ {0x10f7, {1|U|IT, {0x1cb7}}},
+ {0x10f8, {1|U|IT, {0x1cb8}}},
+ {0x10f9, {1|U|IT, {0x1cb9}}},
+ {0x10fa, {1|U|IT, {0x1cba}}},
+ {0x10fd, {1|U|IT, {0x1cbd}}},
+ {0x10fe, {1|U|IT, {0x1cbe}}},
+ {0x10ff, {1|U|IT, {0x1cbf}}},
+ {0x13a0, {1|D, {0xab70}}},
+ {0x13a1, {1|D, {0xab71}}},
+ {0x13a2, {1|D, {0xab72}}},
+ {0x13a3, {1|D, {0xab73}}},
+ {0x13a4, {1|D, {0xab74}}},
+ {0x13a5, {1|D, {0xab75}}},
+ {0x13a6, {1|D, {0xab76}}},
+ {0x13a7, {1|D, {0xab77}}},
+ {0x13a8, {1|D, {0xab78}}},
+ {0x13a9, {1|D, {0xab79}}},
+ {0x13aa, {1|D, {0xab7a}}},
+ {0x13ab, {1|D, {0xab7b}}},
+ {0x13ac, {1|D, {0xab7c}}},
+ {0x13ad, {1|D, {0xab7d}}},
+ {0x13ae, {1|D, {0xab7e}}},
+ {0x13af, {1|D, {0xab7f}}},
+ {0x13b0, {1|D, {0xab80}}},
+ {0x13b1, {1|D, {0xab81}}},
+ {0x13b2, {1|D, {0xab82}}},
+ {0x13b3, {1|D, {0xab83}}},
+ {0x13b4, {1|D, {0xab84}}},
+ {0x13b5, {1|D, {0xab85}}},
+ {0x13b6, {1|D, {0xab86}}},
+ {0x13b7, {1|D, {0xab87}}},
+ {0x13b8, {1|D, {0xab88}}},
+ {0x13b9, {1|D, {0xab89}}},
+ {0x13ba, {1|D, {0xab8a}}},
+ {0x13bb, {1|D, {0xab8b}}},
+ {0x13bc, {1|D, {0xab8c}}},
+ {0x13bd, {1|D, {0xab8d}}},
+ {0x13be, {1|D, {0xab8e}}},
+ {0x13bf, {1|D, {0xab8f}}},
+ {0x13c0, {1|D, {0xab90}}},
+ {0x13c1, {1|D, {0xab91}}},
+ {0x13c2, {1|D, {0xab92}}},
+ {0x13c3, {1|D, {0xab93}}},
+ {0x13c4, {1|D, {0xab94}}},
+ {0x13c5, {1|D, {0xab95}}},
+ {0x13c6, {1|D, {0xab96}}},
+ {0x13c7, {1|D, {0xab97}}},
+ {0x13c8, {1|D, {0xab98}}},
+ {0x13c9, {1|D, {0xab99}}},
+ {0x13ca, {1|D, {0xab9a}}},
+ {0x13cb, {1|D, {0xab9b}}},
+ {0x13cc, {1|D, {0xab9c}}},
+ {0x13cd, {1|D, {0xab9d}}},
+ {0x13ce, {1|D, {0xab9e}}},
+ {0x13cf, {1|D, {0xab9f}}},
+ {0x13d0, {1|D, {0xaba0}}},
+ {0x13d1, {1|D, {0xaba1}}},
+ {0x13d2, {1|D, {0xaba2}}},
+ {0x13d3, {1|D, {0xaba3}}},
+ {0x13d4, {1|D, {0xaba4}}},
+ {0x13d5, {1|D, {0xaba5}}},
+ {0x13d6, {1|D, {0xaba6}}},
+ {0x13d7, {1|D, {0xaba7}}},
+ {0x13d8, {1|D, {0xaba8}}},
+ {0x13d9, {1|D, {0xaba9}}},
+ {0x13da, {1|D, {0xabaa}}},
+ {0x13db, {1|D, {0xabab}}},
+ {0x13dc, {1|D, {0xabac}}},
+ {0x13dd, {1|D, {0xabad}}},
+ {0x13de, {1|D, {0xabae}}},
+ {0x13df, {1|D, {0xabaf}}},
+ {0x13e0, {1|D, {0xabb0}}},
+ {0x13e1, {1|D, {0xabb1}}},
+ {0x13e2, {1|D, {0xabb2}}},
+ {0x13e3, {1|D, {0xabb3}}},
+ {0x13e4, {1|D, {0xabb4}}},
+ {0x13e5, {1|D, {0xabb5}}},
+ {0x13e6, {1|D, {0xabb6}}},
+ {0x13e7, {1|D, {0xabb7}}},
+ {0x13e8, {1|D, {0xabb8}}},
+ {0x13e9, {1|D, {0xabb9}}},
+ {0x13ea, {1|D, {0xabba}}},
+ {0x13eb, {1|D, {0xabbb}}},
+ {0x13ec, {1|D, {0xabbc}}},
+ {0x13ed, {1|D, {0xabbd}}},
+ {0x13ee, {1|D, {0xabbe}}},
+ {0x13ef, {1|D, {0xabbf}}},
+ {0x13f0, {1|D, {0x13f8}}},
+ {0x13f1, {1|D, {0x13f9}}},
+ {0x13f2, {1|D, {0x13fa}}},
+ {0x13f3, {1|D, {0x13fb}}},
+ {0x13f4, {1|D, {0x13fc}}},
+ {0x13f5, {1|D, {0x13fd}}},
+ {0x1c8a, {1|U, {0x1c89}}},
+ {0x1d79, {1|U, {0xa77d}}},
+ {0x1d7d, {1|U, {0x2c63}}},
+ {0x1d8e, {1|U, {0xa7c6}}},
+ {0x1e01, {1|U, {0x1e00}}},
+ {0x1e03, {1|U, {0x1e02}}},
+ {0x1e05, {1|U, {0x1e04}}},
+ {0x1e07, {1|U, {0x1e06}}},
+ {0x1e09, {1|U, {0x1e08}}},
+ {0x1e0b, {1|U, {0x1e0a}}},
+ {0x1e0d, {1|U, {0x1e0c}}},
+ {0x1e0f, {1|U, {0x1e0e}}},
+ {0x1e11, {1|U, {0x1e10}}},
+ {0x1e13, {1|U, {0x1e12}}},
+ {0x1e15, {1|U, {0x1e14}}},
+ {0x1e17, {1|U, {0x1e16}}},
+ {0x1e19, {1|U, {0x1e18}}},
+ {0x1e1b, {1|U, {0x1e1a}}},
+ {0x1e1d, {1|U, {0x1e1c}}},
+ {0x1e1f, {1|U, {0x1e1e}}},
+ {0x1e21, {1|U, {0x1e20}}},
+ {0x1e23, {1|U, {0x1e22}}},
+ {0x1e25, {1|U, {0x1e24}}},
+ {0x1e27, {1|U, {0x1e26}}},
+ {0x1e29, {1|U, {0x1e28}}},
+ {0x1e2b, {1|U, {0x1e2a}}},
+ {0x1e2d, {1|U, {0x1e2c}}},
+ {0x1e2f, {1|U, {0x1e2e}}},
+ {0x1e31, {1|U, {0x1e30}}},
+ {0x1e33, {1|U, {0x1e32}}},
+ {0x1e35, {1|U, {0x1e34}}},
+ {0x1e37, {1|U, {0x1e36}}},
+ {0x1e39, {1|U, {0x1e38}}},
+ {0x1e3b, {1|U, {0x1e3a}}},
+ {0x1e3d, {1|U, {0x1e3c}}},
+ {0x1e3f, {1|U, {0x1e3e}}},
+ {0x1e41, {1|U, {0x1e40}}},
+ {0x1e43, {1|U, {0x1e42}}},
+ {0x1e45, {1|U, {0x1e44}}},
+ {0x1e47, {1|U, {0x1e46}}},
+ {0x1e49, {1|U, {0x1e48}}},
+ {0x1e4b, {1|U, {0x1e4a}}},
+ {0x1e4d, {1|U, {0x1e4c}}},
+ {0x1e4f, {1|U, {0x1e4e}}},
+ {0x1e51, {1|U, {0x1e50}}},
+ {0x1e53, {1|U, {0x1e52}}},
+ {0x1e55, {1|U, {0x1e54}}},
+ {0x1e57, {1|U, {0x1e56}}},
+ {0x1e59, {1|U, {0x1e58}}},
+ {0x1e5b, {1|U, {0x1e5a}}},
+ {0x1e5d, {1|U, {0x1e5c}}},
+ {0x1e5f, {1|U, {0x1e5e}}},
+ {0x1e61, {2|U, {0x1e60, 0x1e9b}}},
+ {0x1e63, {1|U, {0x1e62}}},
+ {0x1e65, {1|U, {0x1e64}}},
+ {0x1e67, {1|U, {0x1e66}}},
+ {0x1e69, {1|U, {0x1e68}}},
+ {0x1e6b, {1|U, {0x1e6a}}},
+ {0x1e6d, {1|U, {0x1e6c}}},
+ {0x1e6f, {1|U, {0x1e6e}}},
+ {0x1e71, {1|U, {0x1e70}}},
+ {0x1e73, {1|U, {0x1e72}}},
+ {0x1e75, {1|U, {0x1e74}}},
+ {0x1e77, {1|U, {0x1e76}}},
+ {0x1e79, {1|U, {0x1e78}}},
+ {0x1e7b, {1|U, {0x1e7a}}},
+ {0x1e7d, {1|U, {0x1e7c}}},
+ {0x1e7f, {1|U, {0x1e7e}}},
+ {0x1e81, {1|U, {0x1e80}}},
+ {0x1e83, {1|U, {0x1e82}}},
+ {0x1e85, {1|U, {0x1e84}}},
+ {0x1e87, {1|U, {0x1e86}}},
+ {0x1e89, {1|U, {0x1e88}}},
+ {0x1e8b, {1|U, {0x1e8a}}},
+ {0x1e8d, {1|U, {0x1e8c}}},
+ {0x1e8f, {1|U, {0x1e8e}}},
+ {0x1e91, {1|U, {0x1e90}}},
+ {0x1e93, {1|U, {0x1e92}}},
+ {0x1e95, {1|U, {0x1e94}}},
+ {0x1ea1, {1|U, {0x1ea0}}},
+ {0x1ea3, {1|U, {0x1ea2}}},
+ {0x1ea5, {1|U, {0x1ea4}}},
+ {0x1ea7, {1|U, {0x1ea6}}},
+ {0x1ea9, {1|U, {0x1ea8}}},
+ {0x1eab, {1|U, {0x1eaa}}},
+ {0x1ead, {1|U, {0x1eac}}},
+ {0x1eaf, {1|U, {0x1eae}}},
+ {0x1eb1, {1|U, {0x1eb0}}},
+ {0x1eb3, {1|U, {0x1eb2}}},
+ {0x1eb5, {1|U, {0x1eb4}}},
+ {0x1eb7, {1|U, {0x1eb6}}},
+ {0x1eb9, {1|U, {0x1eb8}}},
+ {0x1ebb, {1|U, {0x1eba}}},
+ {0x1ebd, {1|U, {0x1ebc}}},
+ {0x1ebf, {1|U, {0x1ebe}}},
+ {0x1ec1, {1|U, {0x1ec0}}},
+ {0x1ec3, {1|U, {0x1ec2}}},
+ {0x1ec5, {1|U, {0x1ec4}}},
+ {0x1ec7, {1|U, {0x1ec6}}},
+ {0x1ec9, {1|U, {0x1ec8}}},
+ {0x1ecb, {1|U, {0x1eca}}},
+ {0x1ecd, {1|U, {0x1ecc}}},
+ {0x1ecf, {1|U, {0x1ece}}},
+ {0x1ed1, {1|U, {0x1ed0}}},
+ {0x1ed3, {1|U, {0x1ed2}}},
+ {0x1ed5, {1|U, {0x1ed4}}},
+ {0x1ed7, {1|U, {0x1ed6}}},
+ {0x1ed9, {1|U, {0x1ed8}}},
+ {0x1edb, {1|U, {0x1eda}}},
+ {0x1edd, {1|U, {0x1edc}}},
+ {0x1edf, {1|U, {0x1ede}}},
+ {0x1ee1, {1|U, {0x1ee0}}},
+ {0x1ee3, {1|U, {0x1ee2}}},
+ {0x1ee5, {1|U, {0x1ee4}}},
+ {0x1ee7, {1|U, {0x1ee6}}},
+ {0x1ee9, {1|U, {0x1ee8}}},
+ {0x1eeb, {1|U, {0x1eea}}},
+ {0x1eed, {1|U, {0x1eec}}},
+ {0x1eef, {1|U, {0x1eee}}},
+ {0x1ef1, {1|U, {0x1ef0}}},
+ {0x1ef3, {1|U, {0x1ef2}}},
+ {0x1ef5, {1|U, {0x1ef4}}},
+ {0x1ef7, {1|U, {0x1ef6}}},
+ {0x1ef9, {1|U, {0x1ef8}}},
+ {0x1efb, {1|U, {0x1efa}}},
+ {0x1efd, {1|U, {0x1efc}}},
+ {0x1eff, {1|U, {0x1efe}}},
+ {0x1f00, {1|U, {0x1f08}}},
+ {0x1f01, {1|U, {0x1f09}}},
+ {0x1f02, {1|U, {0x1f0a}}},
+ {0x1f03, {1|U, {0x1f0b}}},
+ {0x1f04, {1|U, {0x1f0c}}},
+ {0x1f05, {1|U, {0x1f0d}}},
+ {0x1f06, {1|U, {0x1f0e}}},
+ {0x1f07, {1|U, {0x1f0f}}},
+ {0x1f10, {1|U, {0x1f18}}},
+ {0x1f11, {1|U, {0x1f19}}},
+ {0x1f12, {1|U, {0x1f1a}}},
+ {0x1f13, {1|U, {0x1f1b}}},
+ {0x1f14, {1|U, {0x1f1c}}},
+ {0x1f15, {1|U, {0x1f1d}}},
+ {0x1f20, {1|U, {0x1f28}}},
+ {0x1f21, {1|U, {0x1f29}}},
+ {0x1f22, {1|U, {0x1f2a}}},
+ {0x1f23, {1|U, {0x1f2b}}},
+ {0x1f24, {1|U, {0x1f2c}}},
+ {0x1f25, {1|U, {0x1f2d}}},
+ {0x1f26, {1|U, {0x1f2e}}},
+ {0x1f27, {1|U, {0x1f2f}}},
+ {0x1f30, {1|U, {0x1f38}}},
+ {0x1f31, {1|U, {0x1f39}}},
+ {0x1f32, {1|U, {0x1f3a}}},
+ {0x1f33, {1|U, {0x1f3b}}},
+ {0x1f34, {1|U, {0x1f3c}}},
+ {0x1f35, {1|U, {0x1f3d}}},
+ {0x1f36, {1|U, {0x1f3e}}},
+ {0x1f37, {1|U, {0x1f3f}}},
+ {0x1f40, {1|U, {0x1f48}}},
+ {0x1f41, {1|U, {0x1f49}}},
+ {0x1f42, {1|U, {0x1f4a}}},
+ {0x1f43, {1|U, {0x1f4b}}},
+ {0x1f44, {1|U, {0x1f4c}}},
+ {0x1f45, {1|U, {0x1f4d}}},
+ {0x1f51, {1|U, {0x1f59}}},
+ {0x1f53, {1|U, {0x1f5b}}},
+ {0x1f55, {1|U, {0x1f5d}}},
+ {0x1f57, {1|U, {0x1f5f}}},
+ {0x1f60, {1|U, {0x1f68}}},
+ {0x1f61, {1|U, {0x1f69}}},
+ {0x1f62, {1|U, {0x1f6a}}},
+ {0x1f63, {1|U, {0x1f6b}}},
+ {0x1f64, {1|U, {0x1f6c}}},
+ {0x1f65, {1|U, {0x1f6d}}},
+ {0x1f66, {1|U, {0x1f6e}}},
+ {0x1f67, {1|U, {0x1f6f}}},
+ {0x1f70, {1|U, {0x1fba}}},
+ {0x1f71, {1|U, {0x1fbb}}},
+ {0x1f72, {1|U, {0x1fc8}}},
+ {0x1f73, {1|U, {0x1fc9}}},
+ {0x1f74, {1|U, {0x1fca}}},
+ {0x1f75, {1|U, {0x1fcb}}},
+ {0x1f76, {1|U, {0x1fda}}},
+ {0x1f77, {1|U, {0x1fdb}}},
+ {0x1f78, {1|U, {0x1ff8}}},
+ {0x1f79, {1|U, {0x1ff9}}},
+ {0x1f7a, {1|U, {0x1fea}}},
+ {0x1f7b, {1|U, {0x1feb}}},
+ {0x1f7c, {1|U, {0x1ffa}}},
+ {0x1f7d, {1|U, {0x1ffb}}},
+ {0x1fb0, {1|U, {0x1fb8}}},
+ {0x1fb1, {1|U, {0x1fb9}}},
+ {0x1fd0, {1|U, {0x1fd8}}},
+ {0x1fd1, {1|U, {0x1fd9}}},
+ {0x1fe0, {1|U, {0x1fe8}}},
+ {0x1fe1, {1|U, {0x1fe9}}},
+ {0x1fe5, {1|U, {0x1fec}}},
+ {0x214e, {1|U, {0x2132}}},
+ {0x2170, {1|U, {0x2160}}},
+ {0x2171, {1|U, {0x2161}}},
+ {0x2172, {1|U, {0x2162}}},
+ {0x2173, {1|U, {0x2163}}},
+ {0x2174, {1|U, {0x2164}}},
+ {0x2175, {1|U, {0x2165}}},
+ {0x2176, {1|U, {0x2166}}},
+ {0x2177, {1|U, {0x2167}}},
+ {0x2178, {1|U, {0x2168}}},
+ {0x2179, {1|U, {0x2169}}},
+ {0x217a, {1|U, {0x216a}}},
+ {0x217b, {1|U, {0x216b}}},
+ {0x217c, {1|U, {0x216c}}},
+ {0x217d, {1|U, {0x216d}}},
+ {0x217e, {1|U, {0x216e}}},
+ {0x217f, {1|U, {0x216f}}},
+ {0x2184, {1|U, {0x2183}}},
+ {0x24d0, {1|U, {0x24b6}}},
+ {0x24d1, {1|U, {0x24b7}}},
+ {0x24d2, {1|U, {0x24b8}}},
+ {0x24d3, {1|U, {0x24b9}}},
+ {0x24d4, {1|U, {0x24ba}}},
+ {0x24d5, {1|U, {0x24bb}}},
+ {0x24d6, {1|U, {0x24bc}}},
+ {0x24d7, {1|U, {0x24bd}}},
+ {0x24d8, {1|U, {0x24be}}},
+ {0x24d9, {1|U, {0x24bf}}},
+ {0x24da, {1|U, {0x24c0}}},
+ {0x24db, {1|U, {0x24c1}}},
+ {0x24dc, {1|U, {0x24c2}}},
+ {0x24dd, {1|U, {0x24c3}}},
+ {0x24de, {1|U, {0x24c4}}},
+ {0x24df, {1|U, {0x24c5}}},
+ {0x24e0, {1|U, {0x24c6}}},
+ {0x24e1, {1|U, {0x24c7}}},
+ {0x24e2, {1|U, {0x24c8}}},
+ {0x24e3, {1|U, {0x24c9}}},
+ {0x24e4, {1|U, {0x24ca}}},
+ {0x24e5, {1|U, {0x24cb}}},
+ {0x24e6, {1|U, {0x24cc}}},
+ {0x24e7, {1|U, {0x24cd}}},
+ {0x24e8, {1|U, {0x24ce}}},
+ {0x24e9, {1|U, {0x24cf}}},
+ {0x2c30, {1|U, {0x2c00}}},
+ {0x2c31, {1|U, {0x2c01}}},
+ {0x2c32, {1|U, {0x2c02}}},
+ {0x2c33, {1|U, {0x2c03}}},
+ {0x2c34, {1|U, {0x2c04}}},
+ {0x2c35, {1|U, {0x2c05}}},
+ {0x2c36, {1|U, {0x2c06}}},
+ {0x2c37, {1|U, {0x2c07}}},
+ {0x2c38, {1|U, {0x2c08}}},
+ {0x2c39, {1|U, {0x2c09}}},
+ {0x2c3a, {1|U, {0x2c0a}}},
+ {0x2c3b, {1|U, {0x2c0b}}},
+ {0x2c3c, {1|U, {0x2c0c}}},
+ {0x2c3d, {1|U, {0x2c0d}}},
+ {0x2c3e, {1|U, {0x2c0e}}},
+ {0x2c3f, {1|U, {0x2c0f}}},
+ {0x2c40, {1|U, {0x2c10}}},
+ {0x2c41, {1|U, {0x2c11}}},
+ {0x2c42, {1|U, {0x2c12}}},
+ {0x2c43, {1|U, {0x2c13}}},
+ {0x2c44, {1|U, {0x2c14}}},
+ {0x2c45, {1|U, {0x2c15}}},
+ {0x2c46, {1|U, {0x2c16}}},
+ {0x2c47, {1|U, {0x2c17}}},
+ {0x2c48, {1|U, {0x2c18}}},
+ {0x2c49, {1|U, {0x2c19}}},
+ {0x2c4a, {1|U, {0x2c1a}}},
+ {0x2c4b, {1|U, {0x2c1b}}},
+ {0x2c4c, {1|U, {0x2c1c}}},
+ {0x2c4d, {1|U, {0x2c1d}}},
+ {0x2c4e, {1|U, {0x2c1e}}},
+ {0x2c4f, {1|U, {0x2c1f}}},
+ {0x2c50, {1|U, {0x2c20}}},
+ {0x2c51, {1|U, {0x2c21}}},
+ {0x2c52, {1|U, {0x2c22}}},
+ {0x2c53, {1|U, {0x2c23}}},
+ {0x2c54, {1|U, {0x2c24}}},
+ {0x2c55, {1|U, {0x2c25}}},
+ {0x2c56, {1|U, {0x2c26}}},
+ {0x2c57, {1|U, {0x2c27}}},
+ {0x2c58, {1|U, {0x2c28}}},
+ {0x2c59, {1|U, {0x2c29}}},
+ {0x2c5a, {1|U, {0x2c2a}}},
+ {0x2c5b, {1|U, {0x2c2b}}},
+ {0x2c5c, {1|U, {0x2c2c}}},
+ {0x2c5d, {1|U, {0x2c2d}}},
+ {0x2c5e, {1|U, {0x2c2e}}},
+ {0x2c5f, {1|U, {0x2c2f}}},
+ {0x2c61, {1|U, {0x2c60}}},
+ {0x2c65, {1|U, {0x023a}}},
+ {0x2c66, {1|U, {0x023e}}},
+ {0x2c68, {1|U, {0x2c67}}},
+ {0x2c6a, {1|U, {0x2c69}}},
+ {0x2c6c, {1|U, {0x2c6b}}},
+ {0x2c73, {1|U, {0x2c72}}},
+ {0x2c76, {1|U, {0x2c75}}},
+ {0x2c81, {1|U, {0x2c80}}},
+ {0x2c83, {1|U, {0x2c82}}},
+ {0x2c85, {1|U, {0x2c84}}},
+ {0x2c87, {1|U, {0x2c86}}},
+ {0x2c89, {1|U, {0x2c88}}},
+ {0x2c8b, {1|U, {0x2c8a}}},
+ {0x2c8d, {1|U, {0x2c8c}}},
+ {0x2c8f, {1|U, {0x2c8e}}},
+ {0x2c91, {1|U, {0x2c90}}},
+ {0x2c93, {1|U, {0x2c92}}},
+ {0x2c95, {1|U, {0x2c94}}},
+ {0x2c97, {1|U, {0x2c96}}},
+ {0x2c99, {1|U, {0x2c98}}},
+ {0x2c9b, {1|U, {0x2c9a}}},
+ {0x2c9d, {1|U, {0x2c9c}}},
+ {0x2c9f, {1|U, {0x2c9e}}},
+ {0x2ca1, {1|U, {0x2ca0}}},
+ {0x2ca3, {1|U, {0x2ca2}}},
+ {0x2ca5, {1|U, {0x2ca4}}},
+ {0x2ca7, {1|U, {0x2ca6}}},
+ {0x2ca9, {1|U, {0x2ca8}}},
+ {0x2cab, {1|U, {0x2caa}}},
+ {0x2cad, {1|U, {0x2cac}}},
+ {0x2caf, {1|U, {0x2cae}}},
+ {0x2cb1, {1|U, {0x2cb0}}},
+ {0x2cb3, {1|U, {0x2cb2}}},
+ {0x2cb5, {1|U, {0x2cb4}}},
+ {0x2cb7, {1|U, {0x2cb6}}},
+ {0x2cb9, {1|U, {0x2cb8}}},
+ {0x2cbb, {1|U, {0x2cba}}},
+ {0x2cbd, {1|U, {0x2cbc}}},
+ {0x2cbf, {1|U, {0x2cbe}}},
+ {0x2cc1, {1|U, {0x2cc0}}},
+ {0x2cc3, {1|U, {0x2cc2}}},
+ {0x2cc5, {1|U, {0x2cc4}}},
+ {0x2cc7, {1|U, {0x2cc6}}},
+ {0x2cc9, {1|U, {0x2cc8}}},
+ {0x2ccb, {1|U, {0x2cca}}},
+ {0x2ccd, {1|U, {0x2ccc}}},
+ {0x2ccf, {1|U, {0x2cce}}},
+ {0x2cd1, {1|U, {0x2cd0}}},
+ {0x2cd3, {1|U, {0x2cd2}}},
+ {0x2cd5, {1|U, {0x2cd4}}},
+ {0x2cd7, {1|U, {0x2cd6}}},
+ {0x2cd9, {1|U, {0x2cd8}}},
+ {0x2cdb, {1|U, {0x2cda}}},
+ {0x2cdd, {1|U, {0x2cdc}}},
+ {0x2cdf, {1|U, {0x2cde}}},
+ {0x2ce1, {1|U, {0x2ce0}}},
+ {0x2ce3, {1|U, {0x2ce2}}},
+ {0x2cec, {1|U, {0x2ceb}}},
+ {0x2cee, {1|U, {0x2ced}}},
+ {0x2cf3, {1|U, {0x2cf2}}},
+ {0x2d00, {1|U, {0x10a0}}},
+ {0x2d01, {1|U, {0x10a1}}},
+ {0x2d02, {1|U, {0x10a2}}},
+ {0x2d03, {1|U, {0x10a3}}},
+ {0x2d04, {1|U, {0x10a4}}},
+ {0x2d05, {1|U, {0x10a5}}},
+ {0x2d06, {1|U, {0x10a6}}},
+ {0x2d07, {1|U, {0x10a7}}},
+ {0x2d08, {1|U, {0x10a8}}},
+ {0x2d09, {1|U, {0x10a9}}},
+ {0x2d0a, {1|U, {0x10aa}}},
+ {0x2d0b, {1|U, {0x10ab}}},
+ {0x2d0c, {1|U, {0x10ac}}},
+ {0x2d0d, {1|U, {0x10ad}}},
+ {0x2d0e, {1|U, {0x10ae}}},
+ {0x2d0f, {1|U, {0x10af}}},
+ {0x2d10, {1|U, {0x10b0}}},
+ {0x2d11, {1|U, {0x10b1}}},
+ {0x2d12, {1|U, {0x10b2}}},
+ {0x2d13, {1|U, {0x10b3}}},
+ {0x2d14, {1|U, {0x10b4}}},
+ {0x2d15, {1|U, {0x10b5}}},
+ {0x2d16, {1|U, {0x10b6}}},
+ {0x2d17, {1|U, {0x10b7}}},
+ {0x2d18, {1|U, {0x10b8}}},
+ {0x2d19, {1|U, {0x10b9}}},
+ {0x2d1a, {1|U, {0x10ba}}},
+ {0x2d1b, {1|U, {0x10bb}}},
+ {0x2d1c, {1|U, {0x10bc}}},
+ {0x2d1d, {1|U, {0x10bd}}},
+ {0x2d1e, {1|U, {0x10be}}},
+ {0x2d1f, {1|U, {0x10bf}}},
+ {0x2d20, {1|U, {0x10c0}}},
+ {0x2d21, {1|U, {0x10c1}}},
+ {0x2d22, {1|U, {0x10c2}}},
+ {0x2d23, {1|U, {0x10c3}}},
+ {0x2d24, {1|U, {0x10c4}}},
+ {0x2d25, {1|U, {0x10c5}}},
+ {0x2d27, {1|U, {0x10c7}}},
+ {0x2d2d, {1|U, {0x10cd}}},
+ {0xa641, {1|U, {0xa640}}},
+ {0xa643, {1|U, {0xa642}}},
+ {0xa645, {1|U, {0xa644}}},
+ {0xa647, {1|U, {0xa646}}},
+ {0xa649, {1|U, {0xa648}}},
+ {0xa64b, {2|U, {0xa64a, 0x1c88}}},
+ {0xa64d, {1|U, {0xa64c}}},
+ {0xa64f, {1|U, {0xa64e}}},
+ {0xa651, {1|U, {0xa650}}},
+ {0xa653, {1|U, {0xa652}}},
+ {0xa655, {1|U, {0xa654}}},
+ {0xa657, {1|U, {0xa656}}},
+ {0xa659, {1|U, {0xa658}}},
+ {0xa65b, {1|U, {0xa65a}}},
+ {0xa65d, {1|U, {0xa65c}}},
+ {0xa65f, {1|U, {0xa65e}}},
+ {0xa661, {1|U, {0xa660}}},
+ {0xa663, {1|U, {0xa662}}},
+ {0xa665, {1|U, {0xa664}}},
+ {0xa667, {1|U, {0xa666}}},
+ {0xa669, {1|U, {0xa668}}},
+ {0xa66b, {1|U, {0xa66a}}},
+ {0xa66d, {1|U, {0xa66c}}},
+ {0xa681, {1|U, {0xa680}}},
+ {0xa683, {1|U, {0xa682}}},
+ {0xa685, {1|U, {0xa684}}},
+ {0xa687, {1|U, {0xa686}}},
+ {0xa689, {1|U, {0xa688}}},
+ {0xa68b, {1|U, {0xa68a}}},
+ {0xa68d, {1|U, {0xa68c}}},
+ {0xa68f, {1|U, {0xa68e}}},
+ {0xa691, {1|U, {0xa690}}},
+ {0xa693, {1|U, {0xa692}}},
+ {0xa695, {1|U, {0xa694}}},
+ {0xa697, {1|U, {0xa696}}},
+ {0xa699, {1|U, {0xa698}}},
+ {0xa69b, {1|U, {0xa69a}}},
+ {0xa723, {1|U, {0xa722}}},
+ {0xa725, {1|U, {0xa724}}},
+ {0xa727, {1|U, {0xa726}}},
+ {0xa729, {1|U, {0xa728}}},
+ {0xa72b, {1|U, {0xa72a}}},
+ {0xa72d, {1|U, {0xa72c}}},
+ {0xa72f, {1|U, {0xa72e}}},
+ {0xa733, {1|U, {0xa732}}},
+ {0xa735, {1|U, {0xa734}}},
+ {0xa737, {1|U, {0xa736}}},
+ {0xa739, {1|U, {0xa738}}},
+ {0xa73b, {1|U, {0xa73a}}},
+ {0xa73d, {1|U, {0xa73c}}},
+ {0xa73f, {1|U, {0xa73e}}},
+ {0xa741, {1|U, {0xa740}}},
+ {0xa743, {1|U, {0xa742}}},
+ {0xa745, {1|U, {0xa744}}},
+ {0xa747, {1|U, {0xa746}}},
+ {0xa749, {1|U, {0xa748}}},
+ {0xa74b, {1|U, {0xa74a}}},
+ {0xa74d, {1|U, {0xa74c}}},
+ {0xa74f, {1|U, {0xa74e}}},
+ {0xa751, {1|U, {0xa750}}},
+ {0xa753, {1|U, {0xa752}}},
+ {0xa755, {1|U, {0xa754}}},
+ {0xa757, {1|U, {0xa756}}},
+ {0xa759, {1|U, {0xa758}}},
+ {0xa75b, {1|U, {0xa75a}}},
+ {0xa75d, {1|U, {0xa75c}}},
+ {0xa75f, {1|U, {0xa75e}}},
+ {0xa761, {1|U, {0xa760}}},
+ {0xa763, {1|U, {0xa762}}},
+ {0xa765, {1|U, {0xa764}}},
+ {0xa767, {1|U, {0xa766}}},
+ {0xa769, {1|U, {0xa768}}},
+ {0xa76b, {1|U, {0xa76a}}},
+ {0xa76d, {1|U, {0xa76c}}},
+ {0xa76f, {1|U, {0xa76e}}},
+ {0xa77a, {1|U, {0xa779}}},
+ {0xa77c, {1|U, {0xa77b}}},
+ {0xa77f, {1|U, {0xa77e}}},
+ {0xa781, {1|U, {0xa780}}},
+ {0xa783, {1|U, {0xa782}}},
+ {0xa785, {1|U, {0xa784}}},
+ {0xa787, {1|U, {0xa786}}},
+ {0xa78c, {1|U, {0xa78b}}},
+ {0xa791, {1|U, {0xa790}}},
+ {0xa793, {1|U, {0xa792}}},
+ {0xa794, {1|U, {0xa7c4}}},
+ {0xa797, {1|U, {0xa796}}},
+ {0xa799, {1|U, {0xa798}}},
+ {0xa79b, {1|U, {0xa79a}}},
+ {0xa79d, {1|U, {0xa79c}}},
+ {0xa79f, {1|U, {0xa79e}}},
+ {0xa7a1, {1|U, {0xa7a0}}},
+ {0xa7a3, {1|U, {0xa7a2}}},
+ {0xa7a5, {1|U, {0xa7a4}}},
+ {0xa7a7, {1|U, {0xa7a6}}},
+ {0xa7a9, {1|U, {0xa7a8}}},
+ {0xa7b5, {1|U, {0xa7b4}}},
+ {0xa7b7, {1|U, {0xa7b6}}},
+ {0xa7b9, {1|U, {0xa7b8}}},
+ {0xa7bb, {1|U, {0xa7ba}}},
+ {0xa7bd, {1|U, {0xa7bc}}},
+ {0xa7bf, {1|U, {0xa7be}}},
+ {0xa7c1, {1|U, {0xa7c0}}},
+ {0xa7c3, {1|U, {0xa7c2}}},
+ {0xa7c8, {1|U, {0xa7c7}}},
+ {0xa7ca, {1|U, {0xa7c9}}},
+ {0xa7cd, {1|U, {0xa7cc}}},
+ {0xa7cf, {1|U, {0xa7ce}}},
+ {0xa7d1, {1|U, {0xa7d0}}},
+ {0xa7d3, {1|U, {0xa7d2}}},
+ {0xa7d5, {1|U, {0xa7d4}}},
+ {0xa7d7, {1|U, {0xa7d6}}},
+ {0xa7d9, {1|U, {0xa7d8}}},
+ {0xa7db, {1|U, {0xa7da}}},
+ {0xa7f6, {1|U, {0xa7f5}}},
+ {0xab53, {1|U, {0xa7b3}}},
+ {0xff41, {1|U, {0xff21}}},
+ {0xff42, {1|U, {0xff22}}},
+ {0xff43, {1|U, {0xff23}}},
+ {0xff44, {1|U, {0xff24}}},
+ {0xff45, {1|U, {0xff25}}},
+ {0xff46, {1|U, {0xff26}}},
+ {0xff47, {1|U, {0xff27}}},
+ {0xff48, {1|U, {0xff28}}},
+ {0xff49, {1|U, {0xff29}}},
+ {0xff4a, {1|U, {0xff2a}}},
+ {0xff4b, {1|U, {0xff2b}}},
+ {0xff4c, {1|U, {0xff2c}}},
+ {0xff4d, {1|U, {0xff2d}}},
+ {0xff4e, {1|U, {0xff2e}}},
+ {0xff4f, {1|U, {0xff2f}}},
+ {0xff50, {1|U, {0xff30}}},
+ {0xff51, {1|U, {0xff31}}},
+ {0xff52, {1|U, {0xff32}}},
+ {0xff53, {1|U, {0xff33}}},
+ {0xff54, {1|U, {0xff34}}},
+ {0xff55, {1|U, {0xff35}}},
+ {0xff56, {1|U, {0xff36}}},
+ {0xff57, {1|U, {0xff37}}},
+ {0xff58, {1|U, {0xff38}}},
+ {0xff59, {1|U, {0xff39}}},
+ {0xff5a, {1|U, {0xff3a}}},
+ {0x10428, {1|U, {0x10400}}},
+ {0x10429, {1|U, {0x10401}}},
+ {0x1042a, {1|U, {0x10402}}},
+ {0x1042b, {1|U, {0x10403}}},
+ {0x1042c, {1|U, {0x10404}}},
+ {0x1042d, {1|U, {0x10405}}},
+ {0x1042e, {1|U, {0x10406}}},
+ {0x1042f, {1|U, {0x10407}}},
+ {0x10430, {1|U, {0x10408}}},
+ {0x10431, {1|U, {0x10409}}},
+ {0x10432, {1|U, {0x1040a}}},
+ {0x10433, {1|U, {0x1040b}}},
+ {0x10434, {1|U, {0x1040c}}},
+ {0x10435, {1|U, {0x1040d}}},
+ {0x10436, {1|U, {0x1040e}}},
+ {0x10437, {1|U, {0x1040f}}},
+ {0x10438, {1|U, {0x10410}}},
+ {0x10439, {1|U, {0x10411}}},
+ {0x1043a, {1|U, {0x10412}}},
+ {0x1043b, {1|U, {0x10413}}},
+ {0x1043c, {1|U, {0x10414}}},
+ {0x1043d, {1|U, {0x10415}}},
+ {0x1043e, {1|U, {0x10416}}},
+ {0x1043f, {1|U, {0x10417}}},
+ {0x10440, {1|U, {0x10418}}},
+ {0x10441, {1|U, {0x10419}}},
+ {0x10442, {1|U, {0x1041a}}},
+ {0x10443, {1|U, {0x1041b}}},
+ {0x10444, {1|U, {0x1041c}}},
+ {0x10445, {1|U, {0x1041d}}},
+ {0x10446, {1|U, {0x1041e}}},
+ {0x10447, {1|U, {0x1041f}}},
+ {0x10448, {1|U, {0x10420}}},
+ {0x10449, {1|U, {0x10421}}},
+ {0x1044a, {1|U, {0x10422}}},
+ {0x1044b, {1|U, {0x10423}}},
+ {0x1044c, {1|U, {0x10424}}},
+ {0x1044d, {1|U, {0x10425}}},
+ {0x1044e, {1|U, {0x10426}}},
+ {0x1044f, {1|U, {0x10427}}},
+ {0x104d8, {1|U, {0x104b0}}},
+ {0x104d9, {1|U, {0x104b1}}},
+ {0x104da, {1|U, {0x104b2}}},
+ {0x104db, {1|U, {0x104b3}}},
+ {0x104dc, {1|U, {0x104b4}}},
+ {0x104dd, {1|U, {0x104b5}}},
+ {0x104de, {1|U, {0x104b6}}},
+ {0x104df, {1|U, {0x104b7}}},
+ {0x104e0, {1|U, {0x104b8}}},
+ {0x104e1, {1|U, {0x104b9}}},
+ {0x104e2, {1|U, {0x104ba}}},
+ {0x104e3, {1|U, {0x104bb}}},
+ {0x104e4, {1|U, {0x104bc}}},
+ {0x104e5, {1|U, {0x104bd}}},
+ {0x104e6, {1|U, {0x104be}}},
+ {0x104e7, {1|U, {0x104bf}}},
+ {0x104e8, {1|U, {0x104c0}}},
+ {0x104e9, {1|U, {0x104c1}}},
+ {0x104ea, {1|U, {0x104c2}}},
+ {0x104eb, {1|U, {0x104c3}}},
+ {0x104ec, {1|U, {0x104c4}}},
+ {0x104ed, {1|U, {0x104c5}}},
+ {0x104ee, {1|U, {0x104c6}}},
+ {0x104ef, {1|U, {0x104c7}}},
+ {0x104f0, {1|U, {0x104c8}}},
+ {0x104f1, {1|U, {0x104c9}}},
+ {0x104f2, {1|U, {0x104ca}}},
+ {0x104f3, {1|U, {0x104cb}}},
+ {0x104f4, {1|U, {0x104cc}}},
+ {0x104f5, {1|U, {0x104cd}}},
+ {0x104f6, {1|U, {0x104ce}}},
+ {0x104f7, {1|U, {0x104cf}}},
+ {0x104f8, {1|U, {0x104d0}}},
+ {0x104f9, {1|U, {0x104d1}}},
+ {0x104fa, {1|U, {0x104d2}}},
+ {0x104fb, {1|U, {0x104d3}}},
+ {0x10597, {1|U, {0x10570}}},
+ {0x10598, {1|U, {0x10571}}},
+ {0x10599, {1|U, {0x10572}}},
+ {0x1059a, {1|U, {0x10573}}},
+ {0x1059b, {1|U, {0x10574}}},
+ {0x1059c, {1|U, {0x10575}}},
+ {0x1059d, {1|U, {0x10576}}},
+ {0x1059e, {1|U, {0x10577}}},
+ {0x1059f, {1|U, {0x10578}}},
+ {0x105a0, {1|U, {0x10579}}},
+ {0x105a1, {1|U, {0x1057a}}},
+ {0x105a3, {1|U, {0x1057c}}},
+ {0x105a4, {1|U, {0x1057d}}},
+ {0x105a5, {1|U, {0x1057e}}},
+ {0x105a6, {1|U, {0x1057f}}},
+ {0x105a7, {1|U, {0x10580}}},
+ {0x105a8, {1|U, {0x10581}}},
+ {0x105a9, {1|U, {0x10582}}},
+ {0x105aa, {1|U, {0x10583}}},
+ {0x105ab, {1|U, {0x10584}}},
+ {0x105ac, {1|U, {0x10585}}},
+ {0x105ad, {1|U, {0x10586}}},
+ {0x105ae, {1|U, {0x10587}}},
+ {0x105af, {1|U, {0x10588}}},
+ {0x105b0, {1|U, {0x10589}}},
+ {0x105b1, {1|U, {0x1058a}}},
+ {0x105b3, {1|U, {0x1058c}}},
+ {0x105b4, {1|U, {0x1058d}}},
+ {0x105b5, {1|U, {0x1058e}}},
+ {0x105b6, {1|U, {0x1058f}}},
+ {0x105b7, {1|U, {0x10590}}},
+ {0x105b8, {1|U, {0x10591}}},
+ {0x105b9, {1|U, {0x10592}}},
+ {0x105bb, {1|U, {0x10594}}},
+ {0x105bc, {1|U, {0x10595}}},
+ {0x10cc0, {1|U, {0x10c80}}},
+ {0x10cc1, {1|U, {0x10c81}}},
+ {0x10cc2, {1|U, {0x10c82}}},
+ {0x10cc3, {1|U, {0x10c83}}},
+ {0x10cc4, {1|U, {0x10c84}}},
+ {0x10cc5, {1|U, {0x10c85}}},
+ {0x10cc6, {1|U, {0x10c86}}},
+ {0x10cc7, {1|U, {0x10c87}}},
+ {0x10cc8, {1|U, {0x10c88}}},
+ {0x10cc9, {1|U, {0x10c89}}},
+ {0x10cca, {1|U, {0x10c8a}}},
+ {0x10ccb, {1|U, {0x10c8b}}},
+ {0x10ccc, {1|U, {0x10c8c}}},
+ {0x10ccd, {1|U, {0x10c8d}}},
+ {0x10cce, {1|U, {0x10c8e}}},
+ {0x10ccf, {1|U, {0x10c8f}}},
+ {0x10cd0, {1|U, {0x10c90}}},
+ {0x10cd1, {1|U, {0x10c91}}},
+ {0x10cd2, {1|U, {0x10c92}}},
+ {0x10cd3, {1|U, {0x10c93}}},
+ {0x10cd4, {1|U, {0x10c94}}},
+ {0x10cd5, {1|U, {0x10c95}}},
+ {0x10cd6, {1|U, {0x10c96}}},
+ {0x10cd7, {1|U, {0x10c97}}},
+ {0x10cd8, {1|U, {0x10c98}}},
+ {0x10cd9, {1|U, {0x10c99}}},
+ {0x10cda, {1|U, {0x10c9a}}},
+ {0x10cdb, {1|U, {0x10c9b}}},
+ {0x10cdc, {1|U, {0x10c9c}}},
+ {0x10cdd, {1|U, {0x10c9d}}},
+ {0x10cde, {1|U, {0x10c9e}}},
+ {0x10cdf, {1|U, {0x10c9f}}},
+ {0x10ce0, {1|U, {0x10ca0}}},
+ {0x10ce1, {1|U, {0x10ca1}}},
+ {0x10ce2, {1|U, {0x10ca2}}},
+ {0x10ce3, {1|U, {0x10ca3}}},
+ {0x10ce4, {1|U, {0x10ca4}}},
+ {0x10ce5, {1|U, {0x10ca5}}},
+ {0x10ce6, {1|U, {0x10ca6}}},
+ {0x10ce7, {1|U, {0x10ca7}}},
+ {0x10ce8, {1|U, {0x10ca8}}},
+ {0x10ce9, {1|U, {0x10ca9}}},
+ {0x10cea, {1|U, {0x10caa}}},
+ {0x10ceb, {1|U, {0x10cab}}},
+ {0x10cec, {1|U, {0x10cac}}},
+ {0x10ced, {1|U, {0x10cad}}},
+ {0x10cee, {1|U, {0x10cae}}},
+ {0x10cef, {1|U, {0x10caf}}},
+ {0x10cf0, {1|U, {0x10cb0}}},
+ {0x10cf1, {1|U, {0x10cb1}}},
+ {0x10cf2, {1|U, {0x10cb2}}},
+ {0x10d70, {1|U, {0x10d50}}},
+ {0x10d71, {1|U, {0x10d51}}},
+ {0x10d72, {1|U, {0x10d52}}},
+ {0x10d73, {1|U, {0x10d53}}},
+ {0x10d74, {1|U, {0x10d54}}},
+ {0x10d75, {1|U, {0x10d55}}},
+ {0x10d76, {1|U, {0x10d56}}},
+ {0x10d77, {1|U, {0x10d57}}},
+ {0x10d78, {1|U, {0x10d58}}},
+ {0x10d79, {1|U, {0x10d59}}},
+ {0x10d7a, {1|U, {0x10d5a}}},
+ {0x10d7b, {1|U, {0x10d5b}}},
+ {0x10d7c, {1|U, {0x10d5c}}},
+ {0x10d7d, {1|U, {0x10d5d}}},
+ {0x10d7e, {1|U, {0x10d5e}}},
+ {0x10d7f, {1|U, {0x10d5f}}},
+ {0x10d80, {1|U, {0x10d60}}},
+ {0x10d81, {1|U, {0x10d61}}},
+ {0x10d82, {1|U, {0x10d62}}},
+ {0x10d83, {1|U, {0x10d63}}},
+ {0x10d84, {1|U, {0x10d64}}},
+ {0x10d85, {1|U, {0x10d65}}},
+ {0x118c0, {1|U, {0x118a0}}},
+ {0x118c1, {1|U, {0x118a1}}},
+ {0x118c2, {1|U, {0x118a2}}},
+ {0x118c3, {1|U, {0x118a3}}},
+ {0x118c4, {1|U, {0x118a4}}},
+ {0x118c5, {1|U, {0x118a5}}},
+ {0x118c6, {1|U, {0x118a6}}},
+ {0x118c7, {1|U, {0x118a7}}},
+ {0x118c8, {1|U, {0x118a8}}},
+ {0x118c9, {1|U, {0x118a9}}},
+ {0x118ca, {1|U, {0x118aa}}},
+ {0x118cb, {1|U, {0x118ab}}},
+ {0x118cc, {1|U, {0x118ac}}},
+ {0x118cd, {1|U, {0x118ad}}},
+ {0x118ce, {1|U, {0x118ae}}},
+ {0x118cf, {1|U, {0x118af}}},
+ {0x118d0, {1|U, {0x118b0}}},
+ {0x118d1, {1|U, {0x118b1}}},
+ {0x118d2, {1|U, {0x118b2}}},
+ {0x118d3, {1|U, {0x118b3}}},
+ {0x118d4, {1|U, {0x118b4}}},
+ {0x118d5, {1|U, {0x118b5}}},
+ {0x118d6, {1|U, {0x118b6}}},
+ {0x118d7, {1|U, {0x118b7}}},
+ {0x118d8, {1|U, {0x118b8}}},
+ {0x118d9, {1|U, {0x118b9}}},
+ {0x118da, {1|U, {0x118ba}}},
+ {0x118db, {1|U, {0x118bb}}},
+ {0x118dc, {1|U, {0x118bc}}},
+ {0x118dd, {1|U, {0x118bd}}},
+ {0x118de, {1|U, {0x118be}}},
+ {0x118df, {1|U, {0x118bf}}},
+ {0x16e60, {1|U, {0x16e40}}},
+ {0x16e61, {1|U, {0x16e41}}},
+ {0x16e62, {1|U, {0x16e42}}},
+ {0x16e63, {1|U, {0x16e43}}},
+ {0x16e64, {1|U, {0x16e44}}},
+ {0x16e65, {1|U, {0x16e45}}},
+ {0x16e66, {1|U, {0x16e46}}},
+ {0x16e67, {1|U, {0x16e47}}},
+ {0x16e68, {1|U, {0x16e48}}},
+ {0x16e69, {1|U, {0x16e49}}},
+ {0x16e6a, {1|U, {0x16e4a}}},
+ {0x16e6b, {1|U, {0x16e4b}}},
+ {0x16e6c, {1|U, {0x16e4c}}},
+ {0x16e6d, {1|U, {0x16e4d}}},
+ {0x16e6e, {1|U, {0x16e4e}}},
+ {0x16e6f, {1|U, {0x16e4f}}},
+ {0x16e70, {1|U, {0x16e50}}},
+ {0x16e71, {1|U, {0x16e51}}},
+ {0x16e72, {1|U, {0x16e52}}},
+ {0x16e73, {1|U, {0x16e53}}},
+ {0x16e74, {1|U, {0x16e54}}},
+ {0x16e75, {1|U, {0x16e55}}},
+ {0x16e76, {1|U, {0x16e56}}},
+ {0x16e77, {1|U, {0x16e57}}},
+ {0x16e78, {1|U, {0x16e58}}},
+ {0x16e79, {1|U, {0x16e59}}},
+ {0x16e7a, {1|U, {0x16e5a}}},
+ {0x16e7b, {1|U, {0x16e5b}}},
+ {0x16e7c, {1|U, {0x16e5c}}},
+ {0x16e7d, {1|U, {0x16e5d}}},
+ {0x16e7e, {1|U, {0x16e5e}}},
+ {0x16e7f, {1|U, {0x16e5f}}},
+ {0x16ebb, {1|U, {0x16ea0}}},
+ {0x16ebc, {1|U, {0x16ea1}}},
+ {0x16ebd, {1|U, {0x16ea2}}},
+ {0x16ebe, {1|U, {0x16ea3}}},
+ {0x16ebf, {1|U, {0x16ea4}}},
+ {0x16ec0, {1|U, {0x16ea5}}},
+ {0x16ec1, {1|U, {0x16ea6}}},
+ {0x16ec2, {1|U, {0x16ea7}}},
+ {0x16ec3, {1|U, {0x16ea8}}},
+ {0x16ec4, {1|U, {0x16ea9}}},
+ {0x16ec5, {1|U, {0x16eaa}}},
+ {0x16ec6, {1|U, {0x16eab}}},
+ {0x16ec7, {1|U, {0x16eac}}},
+ {0x16ec8, {1|U, {0x16ead}}},
+ {0x16ec9, {1|U, {0x16eae}}},
+ {0x16eca, {1|U, {0x16eaf}}},
+ {0x16ecb, {1|U, {0x16eb0}}},
+ {0x16ecc, {1|U, {0x16eb1}}},
+ {0x16ecd, {1|U, {0x16eb2}}},
+ {0x16ece, {1|U, {0x16eb3}}},
+ {0x16ecf, {1|U, {0x16eb4}}},
+ {0x16ed0, {1|U, {0x16eb5}}},
+ {0x16ed1, {1|U, {0x16eb6}}},
+ {0x16ed2, {1|U, {0x16eb7}}},
+ {0x16ed3, {1|U, {0x16eb8}}},
+ {0x1e922, {1|U, {0x1e900}}},
+ {0x1e923, {1|U, {0x1e901}}},
+ {0x1e924, {1|U, {0x1e902}}},
+ {0x1e925, {1|U, {0x1e903}}},
+ {0x1e926, {1|U, {0x1e904}}},
+ {0x1e927, {1|U, {0x1e905}}},
+ {0x1e928, {1|U, {0x1e906}}},
+ {0x1e929, {1|U, {0x1e907}}},
+ {0x1e92a, {1|U, {0x1e908}}},
+ {0x1e92b, {1|U, {0x1e909}}},
+ {0x1e92c, {1|U, {0x1e90a}}},
+ {0x1e92d, {1|U, {0x1e90b}}},
+ {0x1e92e, {1|U, {0x1e90c}}},
+ {0x1e92f, {1|U, {0x1e90d}}},
+ {0x1e930, {1|U, {0x1e90e}}},
+ {0x1e931, {1|U, {0x1e90f}}},
+ {0x1e932, {1|U, {0x1e910}}},
+ {0x1e933, {1|U, {0x1e911}}},
+ {0x1e934, {1|U, {0x1e912}}},
+ {0x1e935, {1|U, {0x1e913}}},
+ {0x1e936, {1|U, {0x1e914}}},
+ {0x1e937, {1|U, {0x1e915}}},
+ {0x1e938, {1|U, {0x1e916}}},
+ {0x1e939, {1|U, {0x1e917}}},
+ {0x1e93a, {1|U, {0x1e918}}},
+ {0x1e93b, {1|U, {0x1e919}}},
+ {0x1e93c, {1|U, {0x1e91a}}},
+ {0x1e93d, {1|U, {0x1e91b}}},
+ {0x1e93e, {1|U, {0x1e91c}}},
+ {0x1e93f, {1|U, {0x1e91d}}},
+ {0x1e940, {1|U, {0x1e91e}}},
+ {0x1e941, {1|U, {0x1e91f}}},
+ {0x1e942, {1|U, {0x1e920}}},
+ {0x1e943, {1|U, {0x1e921}}},
+#define CaseUnfold_11_Locale (*(CaseUnfold_11_Type (*)[1])(CaseUnfold_11_Table+1450))
+ {0x0069, {1|U, {0x0049}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_11_hash -N onigenc_unicode_CaseUnfold_11_lookup -n */
+
+/* maximum key range = 2881, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseUnfold_11_hash(const OnigCodePoint code)
+{
+ static const unsigned short asso_values[] =
+ {
+ 1, 2884, 2, 29, 4, 134, 9, 131, 10, 229,
+ 121, 246, 2, 3, 540, 359, 2884, 2884, 2884, 2884,
+ 2884, 2884, 2884, 2884, 2884, 2884, 2884, 2884, 2884, 103,
+ 401, 111, 2884, 2884, 2884, 2884, 2884, 127, 2884, 2884,
+ 2884, 2884, 2884, 1, 2884, 2884, 2884, 2884, 2884, 2884,
+ 2884, 2884, 2884, 339, 2884, 2884, 2884, 2884, 2884, 2884,
+ 2884, 15, 9, 1, 7, 8, 341, 797, 60, 1080,
+ 101, 804, 35, 1589, 7, 1841, 17, 16, 58, 1709,
+ 216, 1040, 47, 103, 64, 1339, 219, 1539, 4, 1704,
+ 52, 1508, 344, 11, 501, 1733, 526, 347, 133, 1161,
+ 340, 913, 104, 883, 170, 743, 339, 1103, 398, 1465,
+ 376, 829, 138, 1092, 280, 967, 1876, 785, 1694, 774,
+ 1640, 721, 1852, 951, 1830, 937, 1573, 925, 1736, 666,
+ 897, 502, 693, 475, 1385, 651, 1356, 639, 1184, 532,
+ 1532, 520, 1479, 420, 1225, 203, 1248, 82, 1277, 115,
+ 1758, 289, 1673, 93, 1686, 71, 1666, 60, 1650, 256,
+ 1789, 232, 1552, 1, 1649, 27, 1489, 38, 1247, 144,
+ 1445, 49, 1624, 221, 1418, 327, 1769, 312, 1306, 584,
+ 1075, 363, 1506, 609, 1405, 1213, 1074, 1065, 1362, 1151,
+ 1556, 863, 726, 1429
+ };
+ return asso_values[bits_of(code, 2)+66] + asso_values[bits_of(code, 1)+4] + asso_values[bits_of(code, 0)];
+}
+
+static const CodePointList3 *
+onigenc_unicode_CaseUnfold_11_lookup(const OnigCodePoint code)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x61,
+ MAX_CODE_VALUE = 0x1e943,
+ TOTAL_KEYWORDS = 1451,
+ MIN_WORD_LENGTH = 3,
+ MAX_WORD_LENGTH = 3,
+ MIN_HASH_VALUE = 3,
+ MAX_HASH_VALUE = 2883
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1,
+ /*0x13e1*/ 591,
+ /*0x0461*/ 342,
+ /*0x04e1*/ 402,
+ /*0x0061*/ 0,
+ -1,
+ /*0x104e1*/ 1192,
+ /*0x1e61*/ 664,
+ /*0x1ee1*/ 723,
+ /*0x0161*/ 102,
+ /*0x0261*/ 211,
+ /*0x2ce1*/ 956,
+ -1,
+ /*0x049b*/ 367,
+ -1, -1,
+ /*0x24e1*/ 843,
+ /*0x1e1b*/ 629,
+ /*0x048b*/ 359,
+ /*0x011b*/ 69,
+ /*0x021b*/ 179,
+ /*0x2c9b*/ 921,
+ /*0x1e0b*/ 621,
+ /*0x1e8b*/ 685,
+ /*0x010b*/ 61,
+ /*0x020b*/ 171,
+ /*0x2c8b*/ 913,
+ /*0x13e3*/ 593,
+ /*0x0463*/ 343,
+ /*0x04e3*/ 403,
+ /*0x0063*/ 2,
+ /*0x1c8a*/ 612,
+ /*0x104e3*/ 1194,
+ /*0x1e63*/ 665,
+ /*0x1ee3*/ 724,
+ /*0x0163*/ 103,
+ /*0x0263*/ 212,
+ /*0x2ce3*/ 957,
+ /*0x13e5*/ 595,
+ /*0x0465*/ 344,
+ /*0x04e5*/ 404,
+ /*0x0065*/ 4,
+ /*0x24e3*/ 845,
+ /*0x104e5*/ 1196,
+ /*0x1e65*/ 666,
+ /*0x1ee5*/ 725,
+ /*0x0165*/ 104,
+ /*0x0265*/ 214,
+ /*0xa761*/ 1068,
+ /*0x13e9*/ 599,
+ /*0x0469*/ 346,
+ /*0x04e9*/ 406,
+ /*0x0069*/ 1450,
+ /*0x24e5*/ 847,
+ /*0x104e9*/ 1200,
+ /*0x1e69*/ 668,
+ /*0x1ee9*/ 727,
+ /*0x0169*/ 106,
+ /*0x0269*/ 217,
+ -1,
+ /*0x13db*/ 585,
+ /*0x045b*/ 337,
+ /*0x04db*/ 399,
+ -1,
+ /*0x24e9*/ 851,
+ /*0x104db*/ 1186,
+ /*0x1e5b*/ 661,
+ /*0x1edb*/ 720,
+ /*0x015b*/ 99,
+ /*0x025b*/ 208,
+ /*0x2cdb*/ 953,
+ /*0x13d9*/ 583,
+ /*0x0459*/ 335,
+ /*0x04d9*/ 398,
+ /*0xa763*/ 1069,
+ /*0x24db*/ 837,
+ /*0x104d9*/ 1184,
+ /*0x1e59*/ 660,
+ /*0x1ed9*/ 719,
+ /*0x0159*/ 98,
+ /*0x0259*/ 207,
+ /*0x2cd9*/ 952,
+ /*0x13d1*/ 575,
+ /*0x0451*/ 327,
+ /*0x04d1*/ 394,
+ /*0xa765*/ 1070,
+ /*0x24d9*/ 835,
+ -1,
+ /*0x1e51*/ 656,
+ /*0x1ed1*/ 715,
+ /*0x0151*/ 94,
+ /*0x0251*/ 201,
+ /*0x2cd1*/ 948,
+ /*0x13d7*/ 581,
+ /*0x0457*/ 333,
+ /*0x04d7*/ 397,
+ /*0xa769*/ 1072,
+ /*0x24d1*/ 827,
+ -1,
+ /*0x1e57*/ 659,
+ /*0x1ed7*/ 718,
+ /*0x0157*/ 97,
+ /*0x0257*/ 206,
+ /*0x2cd7*/ 951,
+ /*0x13a4*/ 530,
+ /*0x0491*/ 362,
+ /*0x10ce1*/ 1287,
+ /*0xa75b*/ 1065,
+ /*0x24d7*/ 833,
+ /*0x1e11*/ 624,
+ /*0x1e91*/ 688,
+ /*0x0111*/ 64,
+ /*0x0211*/ 174,
+ /*0x2c91*/ 916,
+ /*0xa79b*/ 1089,
+ /*0x13d3*/ 577,
+ /*0x0453*/ 329,
+ /*0x04d3*/ 395,
+ /*0xa759*/ 1064,
+ -1, -1,
+ /*0x1e53*/ 657,
+ /*0x1ed3*/ 716,
+ /*0x0153*/ 95,
+ /*0x0253*/ 203,
+ /*0x2cd3*/ 949,
+ -1,
+ /*0x10e1*/ 497,
+ -1,
+ /*0xa751*/ 1060,
+ /*0x24d3*/ 829,
+ /*0x01e1*/ 152,
+ /*0x10ce3*/ 1289,
+ /*0x13a0*/ 526,
+ /*0x00e1*/ 26,
+ -1, -1,
+ /*0x0188*/ 120,
+ /*0x13ae*/ 540,
+ -1,
+ /*0xa757*/ 1063,
+ /*0x019b*/ 126,
+ /*0x1042e*/ 1149,
+ /*0x10ce5*/ 1291,
+ /*0x13e7*/ 597,
+ /*0x0467*/ 345,
+ /*0x04e7*/ 405,
+ /*0x0067*/ 6,
+ -1,
+ /*0x104e7*/ 1198,
+ /*0x1e67*/ 667,
+ /*0x1ee7*/ 726,
+ /*0x0167*/ 105,
+ /*0x10e3*/ 499,
+ /*0x10ce9*/ 1295,
+ -1, -1,
+ /*0x01e3*/ 153,
+ -1,
+ /*0x24e7*/ 849,
+ /*0x00e3*/ 28,
+ /*0xa78c*/ 1083,
+ /*0xa753*/ 1061,
+ /*0xa7db*/ 1114,
+ /*0x10e5*/ 501,
+ /*0x10cdb*/ 1281,
+ -1,
+ /*0xab53*/ 1116,
+ /*0x01e5*/ 154,
+ -1,
+ /*0x13a6*/ 532,
+ /*0x00e5*/ 30,
+ -1,
+ /*0x10d82*/ 1323,
+ /*0xa7d9*/ 1113,
+ /*0x10e9*/ 505,
+ /*0x10cd9*/ 1279,
+ -1, -1,
+ /*0x01e9*/ 156,
+ -1, -1,
+ /*0x00e9*/ 34,
+ -1, -1,
+ /*0xa7d1*/ 1109,
+ /*0x10db*/ 491,
+ /*0x10cd1*/ 1271,
+ /*0x018c*/ 121,
+ -1, -1,
+ /*0xa767*/ 1071,
+ -1, -1,
+ /*0x0192*/ 122,
+ -1,
+ /*0xa7d7*/ 1112,
+ /*0x10d9*/ 489,
+ /*0x10cd7*/ 1277,
+ -1, -1, -1, -1,
+ /*0x13cf*/ 573,
+ /*0x044f*/ 325,
+ /*0x04cf*/ 393,
+ /*0xa791*/ 1084,
+ /*0x1044f*/ 1182,
+ /*0x10d1*/ 481,
+ /*0x1e4f*/ 655,
+ /*0x1ecf*/ 714,
+ /*0x014f*/ 93,
+ /*0x024f*/ 199,
+ /*0x2ccf*/ 947,
+ /*0x10d84*/ 1325,
+ -1,
+ /*0x1d8e*/ 615,
+ /*0xa661*/ 1017,
+ /*0xa7d3*/ 1110,
+ /*0x10d7*/ 487,
+ /*0x10cd3*/ 1273,
+ /*0x13eb*/ 601,
+ /*0x046b*/ 347,
+ /*0x04eb*/ 407,
+ /*0x006b*/ 9,
+ -1,
+ /*0x104eb*/ 1202,
+ /*0x1e6b*/ 669,
+ /*0x1eeb*/ 728,
+ /*0x016b*/ 107,
+ /*0x026b*/ 219,
+ -1,
+ /*0x13df*/ 589,
+ /*0x045f*/ 341,
+ /*0x04df*/ 401,
+ /*0x0288*/ 230,
+ -1,
+ /*0x104df*/ 1190,
+ /*0x1e5f*/ 663,
+ /*0x1edf*/ 722,
+ /*0x015f*/ 101,
+ /*0x10d3*/ 483,
+ /*0x2cdf*/ 955,
+ /*0xa663*/ 1018,
+ /*0x028b*/ 233,
+ /*0x028a*/ 232,
+ /*0x03e1*/ 282,
+ /*0x24df*/ 841,
+ -1,
+ /*0x10ce7*/ 1293,
+ /*0xa74f*/ 1059,
+ -1, -1, -1,
+ /*0xa665*/ 1019,
+ -1,
+ /*0x13dd*/ 587,
+ /*0x045d*/ 339,
+ /*0x04dd*/ 400,
+ -1, -1,
+ /*0x104dd*/ 1188,
+ /*0x1e5d*/ 662,
+ /*0x1edd*/ 721,
+ /*0x015d*/ 100,
+ /*0xa669*/ 1021,
+ /*0x2cdd*/ 954,
+ -1,
+ /*0xa76b*/ 1073,
+ -1,
+ /*0x10e7*/ 503,
+ /*0x24dd*/ 839,
+ /*0x03e3*/ 283,
+ -1,
+ /*0x01e7*/ 155,
+ -1,
+ /*0xa65b*/ 1014,
+ /*0x00e7*/ 32,
+ -1,
+ /*0xa75f*/ 1067,
+ /*0x13b0*/ 542,
+ /*0x0430*/ 294,
+ -1,
+ /*0x03e5*/ 284,
+ /*0x10430*/ 1151,
+ -1,
+ /*0x028c*/ 234,
+ /*0xa659*/ 1013,
+ /*0x0282*/ 227,
+ /*0x13d5*/ 579,
+ /*0x0455*/ 331,
+ /*0x04d5*/ 396,
+ /*0x0292*/ 235,
+ -1,
+ /*0x03e9*/ 286,
+ /*0x1e55*/ 658,
+ /*0x1ed5*/ 717,
+ /*0x0155*/ 96,
+ /*0xa651*/ 1009,
+ /*0x2cd5*/ 950,
+ -1, -1, -1,
+ /*0xa75d*/ 1066,
+ /*0x24d5*/ 831,
+ /*0x03db*/ 279,
+ /*0xa7cf*/ 1108,
+ -1,
+ /*0x10ccf*/ 1269,
+ /*0xa657*/ 1012,
+ -1, -1,
+ /*0x13ef*/ 605,
+ /*0x046f*/ 349,
+ /*0x04ef*/ 409,
+ /*0x006f*/ 13,
+ /*0x03d9*/ 278,
+ /*0x104ef*/ 1206,
+ /*0x1e6f*/ 671,
+ /*0x1eef*/ 730,
+ /*0x016f*/ 109,
+ /*0x026f*/ 221,
+ /*0xa794*/ 1086,
+ -1, -1, -1,
+ /*0x10ceb*/ 1297,
+ /*0x13ed*/ 603,
+ /*0x046d*/ 348,
+ /*0x04ed*/ 408,
+ /*0x006d*/ 11,
+ /*0xa653*/ 1010,
+ /*0x104ed*/ 1204,
+ /*0x1e6d*/ 670,
+ /*0x1eed*/ 729,
+ /*0x016d*/ 108,
+ /*0xa755*/ 1062,
+ /*0x10cdf*/ 1285,
+ /*0x03d7*/ 277,
+ /*0x13a8*/ 534,
+ /*0x13a2*/ 528,
+ /*0x1f61*/ 780,
+ -1,
+ /*0x10428*/ 1143,
+ /*0x2c61*/ 900,
+ -1, -1,
+ /*0x10eb*/ 507,
+ -1,
+ /*0x049f*/ 369,
+ -1,
+ /*0x01eb*/ 157,
+ -1,
+ /*0x1e1f*/ 631,
+ /*0x00eb*/ 36,
+ /*0x011f*/ 71,
+ /*0x021f*/ 181,
+ /*0x2c9f*/ 923,
+ /*0x10df*/ 495,
+ /*0xa76f*/ 1075,
+ /*0xa667*/ 1020,
+ /*0x10cdd*/ 1283,
+ /*0x01df*/ 151,
+ /*0x13f3*/ 609,
+ /*0x0473*/ 351,
+ /*0x04f3*/ 411,
+ /*0x0073*/ 17,
+ /*0x1f63*/ 782,
+ /*0x104f3*/ 1210,
+ /*0x1e73*/ 673,
+ /*0x1ef3*/ 732,
+ /*0x0173*/ 111,
+ /*0x1059b*/ 1223,
+ /*0x2cf3*/ 960,
+ /*0xa76d*/ 1074,
+ /*0x1f06*/ 745,
+ /*0x13ac*/ 538,
+ -1,
+ /*0x1f65*/ 784,
+ -1,
+ /*0x1042c*/ 1147,
+ /*0x2c65*/ 901,
+ /*0x10dd*/ 493,
+ /*0x03ae*/ 246,
+ -1, -1,
+ /*0x01dd*/ 150,
+ /*0x1f10*/ 747,
+ -1,
+ /*0x03e7*/ 285,
+ -1, -1,
+ /*0xa7d5*/ 1111,
+ /*0x0586*/ 479,
+ /*0x10cd5*/ 1275,
+ -1, -1, -1,
+ /*0x13aa*/ 536,
+ -1,
+ /*0x1f02*/ 741,
+ /*0x118db*/ 1354,
+ /*0x1042a*/ 1145,
+ /*0x2c5b*/ 895,
+ /*0x1f12*/ 749,
+ -1, -1, -1, -1, -1,
+ /*0x01b0*/ 133,
+ -1,
+ /*0x118d9*/ 1352,
+ /*0x10598*/ 1220,
+ /*0x2c59*/ 893,
+ /*0x10d5*/ 485,
+ -1,
+ /*0x10cef*/ 1301,
+ /*0x0582*/ 475,
+ /*0xa64f*/ 1008,
+ /*0x13cd*/ 571,
+ /*0x044d*/ 323,
+ /*0x1f51*/ 775,
+ /*0x118d1*/ 1344,
+ /*0x1044d*/ 1180,
+ /*0x2c51*/ 885,
+ /*0x1e4d*/ 654,
+ /*0x1ecd*/ 713,
+ /*0x014d*/ 92,
+ /*0x024d*/ 198,
+ /*0x2ccd*/ 946,
+ -1,
+ /*0x10ced*/ 1299,
+ /*0x1f57*/ 778,
+ /*0x118d7*/ 1350,
+ -1,
+ /*0x2c57*/ 891,
+ /*0xa66b*/ 1022,
+ /*0x10ef*/ 511,
+ -1, -1,
+ /*0x1f04*/ 743,
+ /*0x01ef*/ 159,
+ /*0x1f11*/ 748,
+ /*0x1f24*/ 757,
+ /*0x00ef*/ 40,
+ -1, -1,
+ /*0xa65f*/ 1016,
+ -1,
+ /*0xa79f*/ 1091,
+ -1,
+ /*0x1e924*/ 1418,
+ /*0x10ed*/ 509,
+ /*0x10d80*/ 1321,
+ /*0x1f53*/ 776,
+ /*0x118d3*/ 1346,
+ /*0x01ed*/ 158,
+ /*0x2c53*/ 887,
+ /*0x0584*/ 477,
+ /*0x00ed*/ 38,
+ -1, -1,
+ /*0x2173*/ 812,
+ -1,
+ /*0x105a4*/ 1231,
+ /*0x03eb*/ 287,
+ /*0xa74d*/ 1058,
+ -1,
+ /*0x01a8*/ 131,
+ -1,
+ /*0x0180*/ 117,
+ /*0xa65d*/ 1015,
+ /*0x1f20*/ 753,
+ /*0x019a*/ 125,
+ /*0x13c3*/ 561,
+ /*0x0443*/ 313,
+ /*0x03df*/ 281,
+ -1,
+ /*0x10443*/ 1170,
+ -1,
+ /*0x1e43*/ 649,
+ /*0x1ec3*/ 708,
+ /*0x0373*/ 239,
+ /*0x1f67*/ 786,
+ /*0x2cc3*/ 941,
+ /*0x1e92e*/ 1428,
+ -1, -1,
+ /*0x10f3*/ 515,
+ -1, -1, -1,
+ /*0x01f3*/ 160,
+ /*0x105a0*/ 1228,
+ -1,
+ /*0x00f3*/ 44,
+ -1, -1,
+ /*0x105ae*/ 1241,
+ -1,
+ /*0x03dd*/ 280,
+ /*0x13c1*/ 559,
+ /*0x0441*/ 311,
+ /*0x2d16*/ 983,
+ /*0xa655*/ 1011,
+ /*0x10441*/ 1168,
+ /*0x2d08*/ 969,
+ /*0x1e41*/ 648,
+ /*0x1ec1*/ 707,
+ /*0x1f26*/ 759,
+ /*0x2d1b*/ 988,
+ /*0x2cc1*/ 940,
+ -1, -1, -1,
+ /*0x2d0b*/ 972,
+ /*0x2d0a*/ 971,
+ /*0x1e926*/ 1420,
+ -1,
+ /*0x13cb*/ 569,
+ /*0x044b*/ 321,
+ /*0xa743*/ 1053,
+ /*0xa7cd*/ 1107,
+ /*0x1044b*/ 1178,
+ /*0x10ccd*/ 1267,
+ /*0x1e4b*/ 653,
+ /*0x1ecb*/ 712,
+ /*0x014b*/ 91,
+ /*0x024b*/ 197,
+ /*0x2ccb*/ 945,
+ /*0x105a6*/ 1233,
+ /*0x13c9*/ 567,
+ /*0x0449*/ 319,
+ -1,
+ /*0x2d06*/ 967,
+ /*0x10449*/ 1176,
+ -1,
+ /*0x1e49*/ 652,
+ /*0x1ec9*/ 711,
+ /*0x0561*/ 442,
+ /*0x0249*/ 196,
+ /*0x2cc9*/ 944,
+ /*0xa66d*/ 1023,
+ /*0x118cf*/ 1342,
+ -1,
+ /*0x2c4f*/ 883,
+ /*0x2d10*/ 977,
+ -1,
+ /*0xa741*/ 1052,
+ /*0x051b*/ 431,
+ -1,
+ /*0x2d18*/ 985,
+ -1, -1,
+ /*0x050b*/ 423,
+ -1,
+ /*0x03ef*/ 289,
+ /*0x2d0c*/ 973,
+ /*0x1f14*/ 751,
+ /*0x2d02*/ 963,
+ /*0x16ed1*/ 1413,
+ -1, -1,
+ /*0x2d12*/ 979,
+ -1,
+ /*0x0563*/ 444,
+ /*0xa74b*/ 1057,
+ -1,
+ /*0x0280*/ 226,
+ -1, -1,
+ /*0x03ed*/ 288,
+ /*0x118df*/ 1358,
+ -1,
+ /*0x2c5f*/ 899,
+ -1,
+ /*0x0565*/ 446,
+ /*0xa7c3*/ 1104,
+ /*0xa749*/ 1056,
+ /*0x10cc3*/ 1257,
+ -1, -1, -1,
+ /*0x13f1*/ 607,
+ /*0x0471*/ 350,
+ /*0x04f1*/ 410,
+ /*0x0071*/ 15,
+ /*0x0569*/ 450,
+ /*0x104f1*/ 1208,
+ /*0x1e71*/ 672,
+ /*0x1ef1*/ 731,
+ /*0x0171*/ 110,
+ /*0x0271*/ 222,
+ /*0x16ed3*/ 1415,
+ -1, -1,
+ /*0x118dd*/ 1356,
+ -1,
+ /*0x2c5d*/ 897,
+ -1,
+ /*0x2d04*/ 965,
+ -1,
+ /*0x2d11*/ 978,
+ /*0x2d24*/ 997,
+ /*0xa7c1*/ 1103,
+ -1,
+ /*0x10cc1*/ 1255,
+ /*0x03f3*/ 291,
+ /*0x13f5*/ 611,
+ /*0x0475*/ 352,
+ /*0x04f5*/ 412,
+ /*0x0075*/ 19,
+ -1,
+ /*0x104f5*/ 1212,
+ /*0x1e75*/ 674,
+ /*0x1ef5*/ 733,
+ /*0x0175*/ 112,
+ /*0x0275*/ 224,
+ -1,
+ /*0x1f30*/ 761,
+ /*0x03ac*/ 244,
+ -1,
+ /*0x2c30*/ 852,
+ -1,
+ /*0x10ccb*/ 1265,
+ -1, -1,
+ /*0x1e930*/ 1430,
+ /*0x1f55*/ 777,
+ /*0x118d5*/ 1348,
+ -1,
+ /*0x2c55*/ 889,
+ /*0x2d20*/ 993,
+ -1, -1,
+ /*0xa64d*/ 1007,
+ /*0x10cc9*/ 1263,
+ -1,
+ /*0x13c7*/ 565,
+ /*0x0447*/ 317,
+ /*0x105b0*/ 1243,
+ /*0x0511*/ 426,
+ /*0x10447*/ 1174,
+ -1,
+ /*0x1e47*/ 651,
+ /*0x1ec7*/ 710,
+ -1,
+ /*0x0247*/ 195,
+ /*0x2cc7*/ 943,
+ -1,
+ /*0x13c5*/ 563,
+ /*0x0445*/ 315,
+ -1, -1,
+ /*0x10445*/ 1172,
+ /*0x019e*/ 127,
+ /*0x1e45*/ 650,
+ /*0x1ec5*/ 709,
+ /*0x16e61*/ 1360,
+ -1,
+ /*0x2cc5*/ 942,
+ /*0x01c9*/ 140,
+ -1, -1,
+ /*0x03cd*/ 275,
+ /*0x13bf*/ 557,
+ /*0x043f*/ 309,
+ /*0x04bf*/ 385,
+ -1,
+ /*0x1043f*/ 1166,
+ -1,
+ /*0x1e3f*/ 647,
+ /*0x1ebf*/ 706,
+ -1,
+ /*0x023f*/ 192,
+ /*0x2cbf*/ 939,
+ -1, -1, -1,
+ /*0x1f22*/ 755,
+ /*0x1f00*/ 739,
+ /*0x16ecf*/ 1411,
+ /*0x0567*/ 448,
+ /*0x2171*/ 810,
+ /*0x16e63*/ 1362,
+ /*0xa747*/ 1055,
+ /*0x1e928*/ 1422,
+ /*0x1e922*/ 1416,
+ /*0x10cf1*/ 1303,
+ -1,
+ /*0xa643*/ 1002,
+ -1,
+ /*0x13c2*/ 560,
+ /*0x0442*/ 312,
+ /*0x04c2*/ 386,
+ /*0x16e65*/ 1364,
+ /*0x10442*/ 1169,
+ /*0xa745*/ 1054,
+ /*0x0580*/ 473,
+ /*0x105a8*/ 1235,
+ /*0x0142*/ 87,
+ /*0x0242*/ 194,
+ /*0x1f73*/ 790,
+ /*0x0371*/ 238,
+ /*0x1059a*/ 1222,
+ /*0x2c73*/ 906,
+ /*0x16e69*/ 1368,
+ /*0x1059f*/ 1227,
+ /*0x2175*/ 814,
+ /*0x10f1*/ 513,
+ -1, -1,
+ /*0xa73f*/ 1051,
+ -1, -1,
+ /*0x2d0e*/ 975,
+ /*0x00f1*/ 42,
+ /*0xa641*/ 1001,
+ /*0x2d14*/ 981,
+ /*0x03c3*/ 265,
+ /*0x13b7*/ 549,
+ /*0x0437*/ 301,
+ /*0x04b7*/ 381,
+ /*0x1e92c*/ 1426,
+ /*0x10437*/ 1158,
+ -1,
+ /*0x1e37*/ 643,
+ /*0x1eb7*/ 702,
+ /*0x0137*/ 82,
+ -1,
+ /*0x2cb7*/ 935,
+ -1, -1,
+ /*0x017e*/ 116,
+ /*0x10f5*/ 517,
+ /*0xa64b*/ 1006,
+ /*0x105ac*/ 1239,
+ -1,
+ /*0x01f5*/ 161,
+ -1, -1,
+ /*0x00f5*/ 46,
+ /*0x13a7*/ 533,
+ /*0x10cc7*/ 1261,
+ /*0x04a7*/ 373,
+ /*0x1e92a*/ 1424,
+ /*0x03c1*/ 264,
+ /*0xa649*/ 1005,
+ /*0x1e27*/ 635,
+ /*0x1ea7*/ 694,
+ /*0x0127*/ 75,
+ /*0x0227*/ 184,
+ /*0x2ca7*/ 927,
+ /*0x029e*/ 237,
+ -1,
+ /*0x10cc5*/ 1259,
+ -1, -1,
+ /*0x105aa*/ 1237,
+ /*0x056b*/ 452,
+ /*0x118cd*/ 1340,
+ -1,
+ /*0x2c4d*/ 881,
+ -1,
+ /*0x03cb*/ 273,
+ /*0x10d73*/ 1308,
+ -1,
+ /*0xa737*/ 1047,
+ /*0xa7bf*/ 1102,
+ -1, -1, -1, -1,
+ /*0x13b5*/ 547,
+ /*0x0435*/ 299,
+ /*0x04b5*/ 380,
+ /*0x03c9*/ 271,
+ /*0x10435*/ 1156,
+ -1,
+ /*0x1e35*/ 642,
+ /*0x1eb5*/ 701,
+ /*0x0135*/ 81,
+ -1,
+ /*0x2cb5*/ 934,
+ /*0x13b3*/ 545,
+ /*0x0433*/ 297,
+ /*0x04b3*/ 379,
+ -1,
+ /*0x10433*/ 1154,
+ /*0xa727*/ 1040,
+ /*0x1e33*/ 641,
+ /*0x1eb3*/ 700,
+ /*0x0133*/ 80,
+ /*0x0233*/ 190,
+ /*0x2cb3*/ 933,
+ /*0x01bf*/ 138,
+ /*0x1fe1*/ 806,
+ /*0x10cc2*/ 1256,
+ /*0x0481*/ 358,
+ -1, -1,
+ /*0x16e67*/ 1366,
+ /*0x1e01*/ 616,
+ /*0x1e81*/ 680,
+ /*0x0101*/ 56,
+ /*0x0201*/ 166,
+ /*0x2c81*/ 908,
+ -1, -1,
+ /*0x1e05*/ 618,
+ /*0x1e85*/ 682,
+ /*0x0105*/ 58,
+ /*0x0205*/ 168,
+ /*0x2c85*/ 910,
+ /*0x1f43*/ 772,
+ /*0x118c3*/ 1330,
+ -1,
+ /*0x2c43*/ 871,
+ -1, -1,
+ /*0xa735*/ 1046,
+ -1,
+ /*0x1e943*/ 1449,
+ /*0xa7b7*/ 1098,
+ -1,
+ /*0x217e*/ 823,
+ -1, -1,
+ /*0x13ad*/ 539,
+ -1,
+ /*0x04ad*/ 376,
+ /*0xa733*/ 1045,
+ /*0x1042d*/ 1148,
+ /*0x1fe5*/ 807,
+ /*0x1e2d*/ 638,
+ /*0x1ead*/ 697,
+ /*0x012d*/ 78,
+ /*0x022d*/ 187,
+ /*0x2cad*/ 930,
+ /*0x2d22*/ 995,
+ /*0x2d00*/ 961,
+ /*0x1f41*/ 770,
+ /*0x118c1*/ 1328,
+ /*0x2d1a*/ 987,
+ /*0x2c41*/ 869,
+ /*0xa7a7*/ 1095,
+ /*0x2d1f*/ 992,
+ -1, -1,
+ /*0x1e941*/ 1447,
+ /*0x056f*/ 456,
+ /*0x10fe*/ 524,
+ -1, -1,
+ /*0xa647*/ 1004,
+ -1, -1, -1,
+ /*0x00fe*/ 54,
+ -1,
+ /*0x118cb*/ 1338,
+ /*0x1059c*/ 1224,
+ /*0x2c4b*/ 879,
+ /*0x047d*/ 356,
+ /*0x04fd*/ 416,
+ /*0x056d*/ 454,
+ /*0xa645*/ 1003,
+ -1,
+ /*0x1e7d*/ 678,
+ /*0x1efd*/ 737,
+ /*0x1d7d*/ 614,
+ /*0x027d*/ 225,
+ /*0x118c9*/ 1336,
+ -1,
+ /*0x2c49*/ 877,
+ /*0xa72d*/ 1043,
+ /*0xa7b5*/ 1097,
+ /*0x1fd1*/ 804,
+ /*0x16e6b*/ 1370,
+ -1, -1, -1,
+ /*0x13a5*/ 531,
+ /*0x03c7*/ 269,
+ /*0x04a5*/ 372,
+ /*0x051f*/ 433,
+ /*0x1059e*/ 1226,
+ -1,
+ /*0x1e25*/ 634,
+ /*0x1ea5*/ 693,
+ /*0x0125*/ 74,
+ /*0x0225*/ 183,
+ /*0x2ca5*/ 926,
+ -1, -1,
+ /*0x03c5*/ 267,
+ /*0x13c0*/ 558,
+ /*0x0440*/ 310,
+ /*0x16ecd*/ 1409,
+ /*0xa781*/ 1079,
+ /*0x10440*/ 1167,
+ /*0x0573*/ 460,
+ -1,
+ /*0x2184*/ 825,
+ /*0x0140*/ 86,
+ /*0x0240*/ 193,
+ /*0xa785*/ 1081,
+ -1, -1,
+ /*0x10d81*/ 1322,
+ /*0x03bf*/ 262,
+ -1,
+ /*0x13a3*/ 529,
+ -1,
+ /*0x04a3*/ 371,
+ -1,
+ /*0x10d85*/ 1326,
+ -1,
+ /*0x1e23*/ 633,
+ /*0x1ea3*/ 692,
+ /*0x0123*/ 73,
+ /*0x0223*/ 182,
+ /*0x2ca3*/ 925,
+ /*0x1f71*/ 788,
+ /*0x13bd*/ 555,
+ /*0x043d*/ 307,
+ /*0x04bd*/ 384,
+ -1,
+ /*0x1043d*/ 1164,
+ /*0xa725*/ 1039,
+ /*0x1e3d*/ 646,
+ /*0x1ebd*/ 705,
+ -1,
+ /*0x0185*/ 119,
+ /*0x2cbd*/ 938,
+ -1,
+ /*0x13bb*/ 553,
+ /*0x043b*/ 305,
+ /*0x04bb*/ 383,
+ -1,
+ /*0x1043b*/ 1162,
+ -1,
+ /*0x1e3b*/ 645,
+ /*0x1ebb*/ 704,
+ -1, -1,
+ /*0x2cbb*/ 937,
+ -1,
+ /*0x1f75*/ 792,
+ -1,
+ /*0x13b9*/ 551,
+ /*0x0439*/ 303,
+ /*0x04b9*/ 382,
+ /*0x16ec3*/ 1399,
+ /*0x10439*/ 1160,
+ -1,
+ /*0x1e39*/ 644,
+ /*0x1eb9*/ 703,
+ /*0x01ad*/ 132,
+ /*0xa723*/ 1038,
+ /*0x2cb9*/ 936,
+ -1,
+ /*0x217d*/ 822,
+ -1, -1,
+ /*0x03b7*/ 254,
+ /*0x13b1*/ 543,
+ /*0x0431*/ 295,
+ /*0x04b1*/ 378,
+ /*0x16e6f*/ 1374,
+ /*0x10431*/ 1152,
+ /*0xa73d*/ 1050,
+ /*0x1e31*/ 640,
+ /*0x1eb1*/ 699,
+ -1,
+ /*0x0231*/ 189,
+ /*0x2cb1*/ 932,
+ -1, -1,
+ /*0x118c7*/ 1334,
+ /*0x16ec1*/ 1397,
+ /*0x2c47*/ 875,
+ /*0x037d*/ 243,
+ /*0xa73b*/ 1049,
+ /*0x16e6d*/ 1372,
+ /*0xa7a5*/ 1094,
+ /*0x10d71*/ 1306,
+ -1,
+ /*0x10fd*/ 523,
+ -1,
+ /*0x1f45*/ 774,
+ /*0x118c5*/ 1332,
+ /*0x01fd*/ 164,
+ /*0x2c45*/ 873,
+ /*0xff59*/ 1141,
+ /*0x00fd*/ 53,
+ -1,
+ /*0xa739*/ 1048,
+ /*0x16ecb*/ 1407,
+ -1,
+ /*0x2d1c*/ 989,
+ /*0x10cc0*/ 1254,
+ -1, -1, -1,
+ /*0xff51*/ 1133,
+ -1, -1,
+ /*0x2c3f*/ 867,
+ -1,
+ /*0x16ec9*/ 1405,
+ /*0x10d75*/ 1310,
+ /*0x01a5*/ 130,
+ /*0x1e93f*/ 1445,
+ -1,
+ /*0xa7a3*/ 1093,
+ /*0xff57*/ 1139,
+ -1,
+ /*0x03b5*/ 252,
+ -1,
+ /*0x16e73*/ 1378,
+ -1, -1, -1, -1,
+ /*0x2d1e*/ 991,
+ -1,
+ /*0xa7bd*/ 1101,
+ -1,
+ /*0x03b3*/ 250,
+ -1, -1,
+ /*0x1f42*/ 771,
+ /*0x118c2*/ 1329,
+ -1,
+ /*0x2c42*/ 870,
+ -1, -1,
+ /*0xff53*/ 1135,
+ /*0xa7bb*/ 1100,
+ /*0x1e942*/ 1448,
+ /*0x048f*/ 361,
+ /*0x01a3*/ 129,
+ -1, -1,
+ /*0x1e0f*/ 623,
+ /*0x1e8f*/ 687,
+ /*0x010f*/ 63,
+ /*0x020f*/ 173,
+ /*0x2c8f*/ 915,
+ /*0xa69b*/ 1037,
+ -1, -1,
+ /*0xa7b9*/ 1099,
+ /*0x01bd*/ 137,
+ /*0xa68b*/ 1029,
+ -1, -1, -1, -1,
+ /*0x1f37*/ 768,
+ -1, -1,
+ /*0x2c37*/ 859,
+ -1,
+ /*0x0479*/ 354,
+ /*0x04f9*/ 414,
+ /*0x0079*/ 23,
+ /*0x1e937*/ 1437,
+ /*0x104f9*/ 1216,
+ /*0x1e79*/ 676,
+ /*0x1ef9*/ 735,
+ /*0x1d79*/ 613,
+ /*0x03ad*/ 245,
+ /*0x13f2*/ 608,
+ /*0x1fb0*/ 801,
+ /*0x0078*/ 22,
+ /*0x0072*/ 16,
+ /*0x104f8*/ 1215,
+ /*0x104f2*/ 1209,
+ /*0x01b9*/ 136,
+ /*0x105b7*/ 1249,
+ /*0x1f27*/ 760,
+ /*0x0272*/ 223,
+ -1,
+ /*0x1e03*/ 617,
+ /*0x1e83*/ 681,
+ /*0x0103*/ 57,
+ /*0x0203*/ 167,
+ /*0x2c83*/ 909,
+ /*0x1e927*/ 1421,
+ /*0x13af*/ 541,
+ -1,
+ /*0x04af*/ 377,
+ -1,
+ /*0x1042f*/ 1150,
+ -1,
+ /*0x1e2f*/ 639,
+ /*0x1eaf*/ 698,
+ /*0x012f*/ 79,
+ /*0x022f*/ 188,
+ /*0x2caf*/ 931,
+ /*0x13a9*/ 535,
+ /*0x105a7*/ 1234,
+ /*0x04a9*/ 374,
+ -1,
+ /*0x10429*/ 1144,
+ -1,
+ /*0x1e29*/ 636,
+ /*0x1ea9*/ 695,
+ /*0x0129*/ 76,
+ /*0x0229*/ 185,
+ /*0x2ca9*/ 928,
+ /*0x1f35*/ 766,
+ -1, -1,
+ /*0x2c35*/ 857,
+ /*0x16ec7*/ 1403,
+ -1, -1, -1,
+ /*0x1e935*/ 1435,
+ /*0x0571*/ 458,
+ -1,
+ /*0x1f33*/ 764,
+ -1,
+ /*0xff4f*/ 1131,
+ /*0x2c33*/ 855,
+ /*0x10d7e*/ 1319,
+ /*0x16ec5*/ 1401,
+ -1, -1,
+ /*0x1e933*/ 1433,
+ -1,
+ /*0x105b5*/ 1247,
+ -1,
+ /*0x1f01*/ 740,
+ -1,
+ /*0xa72f*/ 1044,
+ -1, -1,
+ /*0x03c0*/ 263,
+ /*0xa691*/ 1032,
+ /*0x1f05*/ 744,
+ /*0x16ebf*/ 1395,
+ /*0x105b3*/ 1245,
+ -1,
+ /*0x0575*/ 462,
+ -1,
+ /*0xa729*/ 1041,
+ -1,
+ /*0x047b*/ 355,
+ /*0x04fb*/ 415,
+ -1,
+ /*0x0581*/ 474,
+ /*0x104fb*/ 1218,
+ /*0x1e7b*/ 677,
+ /*0x1efb*/ 736,
+ -1, -1,
+ /*0x13a1*/ 527,
+ /*0x0585*/ 478,
+ /*0x04a1*/ 370,
+ -1,
+ /*0x2179*/ 818,
+ -1,
+ /*0x1e21*/ 632,
+ /*0x1ea1*/ 691,
+ /*0x0121*/ 72,
+ /*0x03bd*/ 260,
+ /*0x2ca1*/ 924,
+ /*0x16ec2*/ 1398,
+ -1,
+ /*0x2178*/ 817,
+ /*0x2172*/ 811,
+ -1,
+ /*0x1e92d*/ 1427,
+ -1, -1,
+ /*0x10cf2*/ 1304,
+ -1,
+ /*0x03bb*/ 258,
+ /*0xa783*/ 1080,
+ /*0x13c8*/ 566,
+ /*0x0448*/ 318,
+ /*0x04c8*/ 389,
+ -1,
+ /*0x10448*/ 1175,
+ -1,
+ /*0x105ad*/ 1240,
+ /*0x10f9*/ 521,
+ /*0x0148*/ 90,
+ /*0x10d83*/ 1324,
+ -1,
+ /*0x01f9*/ 162,
+ /*0x03b9*/ 256,
+ -1,
+ /*0x00f9*/ 49,
+ -1,
+ /*0x10f8*/ 520,
+ /*0x10f2*/ 514,
+ -1,
+ /*0x1f7d*/ 800,
+ -1, -1,
+ /*0xa7a9*/ 1096,
+ /*0x00f8*/ 48,
+ /*0x00f2*/ 43,
+ -1,
+ /*0x0183*/ 118,
+ -1,
+ /*0x03b1*/ 248,
+ /*0xff55*/ 1137,
+ /*0x0477*/ 353,
+ /*0x04f7*/ 413,
+ /*0x0077*/ 21,
+ -1,
+ /*0x104f7*/ 1214,
+ /*0x1e77*/ 675,
+ /*0x1ef7*/ 734,
+ /*0x0177*/ 113,
+ -1,
+ /*0x1f25*/ 758,
+ -1,
+ /*0x13ce*/ 572,
+ /*0x044e*/ 324,
+ /*0x04ce*/ 392,
+ -1,
+ /*0x1044e*/ 1181,
+ -1,
+ /*0x1e925*/ 1419,
+ -1, -1, -1, -1, -1,
+ /*0x1f40*/ 769,
+ /*0x118c0*/ 1327,
+ -1,
+ /*0x2c40*/ 868,
+ -1,
+ /*0x16e71*/ 1376,
+ /*0x2d27*/ 999,
+ /*0x105a5*/ 1232,
+ /*0x1e940*/ 1446,
+ -1,
+ /*0x13e6*/ 596,
+ /*0x13d0*/ 574,
+ /*0x0450*/ 326,
+ /*0x0066*/ 5,
+ /*0x217b*/ 820,
+ /*0x104e6*/ 1197,
+ /*0x1f23*/ 756,
+ -1, -1,
+ /*0x0266*/ 215,
+ /*0x0250*/ 200,
+ -1, -1, -1,
+ /*0x1e923*/ 1417,
+ /*0x24e6*/ 848,
+ /*0x24d0*/ 826,
+ /*0xa7a1*/ 1092,
+ /*0x057e*/ 471,
+ /*0x10d7d*/ 1318,
+ /*0x16e75*/ 1380,
+ /*0x2c3d*/ 865,
+ -1, -1,
+ /*0x037b*/ 241,
+ -1,
+ /*0x1e93d*/ 1443,
+ /*0x105a3*/ 1230,
+ -1, -1,
+ /*0x13d2*/ 576,
+ /*0x0452*/ 328,
+ -1,
+ /*0x2c3b*/ 863,
+ /*0x01fb*/ 163,
+ /*0x0527*/ 437,
+ -1,
+ /*0x00fb*/ 51,
+ /*0x1e93b*/ 1441,
+ /*0x0252*/ 202,
+ /*0xa7c8*/ 1105,
+ -1,
+ /*0x10cc8*/ 1262,
+ -1,
+ /*0x01a1*/ 128,
+ /*0x24d2*/ 828,
+ -1,
+ /*0x2c39*/ 861,
+ -1, -1,
+ /*0x2d01*/ 962,
+ /*0x105bb*/ 1252,
+ /*0x1e939*/ 1439,
+ -1, -1, -1, -1,
+ /*0x2d05*/ 966,
+ -1,
+ /*0x13f0*/ 606,
+ /*0x1f31*/ 762,
+ /*0x0283*/ 228,
+ /*0x0070*/ 14,
+ /*0x2c31*/ 853,
+ /*0x104f0*/ 1207,
+ /*0x105b9*/ 1251,
+ /*0x2177*/ 816,
+ -1,
+ /*0x1e931*/ 1431,
+ -1, -1, -1,
+ /*0x03f8*/ 292,
+ /*0x03f2*/ 290,
+ -1, -1, -1, -1,
+ /*0x214e*/ 808,
+ -1, -1,
+ /*0x105b1*/ 1244,
+ /*0x2d2d*/ 1000,
+ /*0x10cce*/ 1268,
+ -1, -1,
+ /*0x0377*/ 240,
+ -1, -1,
+ /*0x0501*/ 418,
+ /*0x03af*/ 247,
+ -1,
+ /*0x10f7*/ 519,
+ -1,
+ /*0x0493*/ 363,
+ -1,
+ /*0x0505*/ 420,
+ /*0xff4d*/ 1129,
+ /*0x1e13*/ 625,
+ /*0x1e93*/ 689,
+ /*0x0113*/ 65,
+ /*0x0213*/ 175,
+ /*0x2c93*/ 917,
+ -1, -1,
+ /*0x10ce6*/ 1292,
+ /*0x10cd0*/ 1270,
+ -1,
+ /*0x01ce*/ 142,
+ /*0x13c6*/ 564,
+ /*0x0446*/ 316,
+ /*0x04c6*/ 388,
+ -1,
+ /*0x10446*/ 1173,
+ -1, -1, -1,
+ /*0x0146*/ 89,
+ /*0x007a*/ 24,
+ -1,
+ /*0x104fa*/ 1217,
+ /*0x052d*/ 440,
+ -1,
+ /*0x017a*/ 114,
+ -1, -1,
+ /*0x10e6*/ 502,
+ /*0x10d0*/ 480,
+ -1,
+ /*0x16ec0*/ 1396,
+ -1,
+ /*0x01d0*/ 143,
+ -1,
+ /*0x00e6*/ 31,
+ -1,
+ /*0x10cd2*/ 1272,
+ /*0x2d25*/ 998,
+ /*0x16e7e*/ 1389,
+ /*0x13c4*/ 562,
+ /*0x0444*/ 314,
+ /*0x04c4*/ 387,
+ -1,
+ /*0x10444*/ 1171,
+ -1, -1, -1,
+ /*0x0144*/ 88,
+ -1, -1,
+ /*0x03fb*/ 293,
+ -1, -1,
+ /*0xff43*/ 1119,
+ -1, -1,
+ /*0x057d*/ 470,
+ /*0x10d2*/ 482,
+ /*0x16ebd*/ 1393,
+ /*0x1f79*/ 796,
+ /*0x2170*/ 809,
+ /*0x01d2*/ 144,
+ /*0x0076*/ 20,
+ /*0xa77a*/ 1076,
+ /*0x104f6*/ 1213,
+ /*0x10cf0*/ 1302,
+ -1,
+ /*0x2d23*/ 996,
+ /*0x1f78*/ 795,
+ /*0x1f72*/ 789,
+ /*0x16ebb*/ 1391,
+ -1,
+ /*0x13ec*/ 602,
+ -1,
+ /*0x1f03*/ 742,
+ /*0x006c*/ 10,
+ /*0x0525*/ 436,
+ /*0x104ec*/ 1203,
+ -1, -1,
+ /*0xff41*/ 1117,
+ /*0x026c*/ 220,
+ /*0x2cec*/ 958,
+ /*0x03c8*/ 270,
+ /*0x047f*/ 357,
+ /*0x04ff*/ 417,
+ /*0x10f0*/ 512,
+ -1, -1,
+ /*0x1e7f*/ 679,
+ /*0x1eff*/ 738,
+ -1,
+ /*0x0583*/ 476,
+ /*0x00f0*/ 41,
+ /*0x1e92f*/ 1429,
+ -1,
+ /*0xa793*/ 1085,
+ -1,
+ /*0xff4b*/ 1127,
+ /*0x13e8*/ 598,
+ -1, -1,
+ /*0x0068*/ 7,
+ -1,
+ /*0x104e8*/ 1199,
+ /*0x1e929*/ 1423,
+ /*0x0523*/ 435,
+ /*0x105af*/ 1242,
+ /*0x0268*/ 216,
+ -1,
+ /*0xff49*/ 1125,
+ -1, -1, -1,
+ /*0x24e8*/ 850,
+ /*0x10cc6*/ 1260,
+ /*0x217a*/ 819,
+ -1,
+ /*0x105a9*/ 1236,
+ /*0x13ab*/ 537,
+ -1,
+ /*0x04ab*/ 375,
+ /*0x10d79*/ 1314,
+ /*0x1042b*/ 1146,
+ /*0x03ce*/ 276,
+ /*0x1e2b*/ 637,
+ /*0x1eab*/ 696,
+ /*0x012b*/ 77,
+ /*0x022b*/ 186,
+ /*0x2cab*/ 929,
+ /*0xa77f*/ 1078,
+ /*0x10d78*/ 1313,
+ /*0x10d72*/ 1307,
+ /*0x13cc*/ 570,
+ /*0x044c*/ 322,
+ /*0x04cc*/ 391,
+ -1,
+ /*0x1044c*/ 1179,
+ -1, -1,
+ /*0x01c6*/ 139,
+ -1,
+ /*0x10fa*/ 522,
+ /*0x13e4*/ 594,
+ /*0x10cc4*/ 1258,
+ /*0x1f7b*/ 798,
+ /*0x0064*/ 3,
+ -1,
+ /*0x104e4*/ 1195,
+ /*0x00fa*/ 50,
+ -1, -1,
+ /*0x0264*/ 213,
+ -1, -1,
+ /*0x1f21*/ 754,
+ -1, -1,
+ /*0x24e4*/ 846,
+ /*0x2176*/ 815,
+ /*0x13f4*/ 610,
+ -1,
+ /*0xa7f6*/ 1115,
+ /*0x0074*/ 18,
+ /*0x0499*/ 366,
+ /*0x104f4*/ 1211,
+ /*0xa72b*/ 1042,
+ -1,
+ /*0x1e19*/ 628,
+ -1,
+ /*0x0119*/ 68,
+ /*0x0219*/ 178,
+ /*0x2c99*/ 920,
+ -1, -1,
+ /*0x16e7d*/ 1388,
+ /*0x105a1*/ 1229,
+ /*0x10cec*/ 1298,
+ -1,
+ /*0x118c8*/ 1335,
+ -1,
+ /*0x2c48*/ 876,
+ -1,
+ /*0x217f*/ 824,
+ -1,
+ /*0x10f6*/ 518,
+ /*0x13ca*/ 568,
+ /*0x044a*/ 320,
+ /*0x04ca*/ 390,
+ -1,
+ /*0x1044a*/ 1177,
+ -1,
+ /*0x00f6*/ 47,
+ -1,
+ /*0x2d0f*/ 976,
+ /*0x0495*/ 364,
+ -1, -1,
+ /*0x10ec*/ 508,
+ /*0x1e15*/ 626,
+ /*0x1e95*/ 690,
+ /*0x0115*/ 66,
+ /*0x0215*/ 176,
+ /*0x2c95*/ 918,
+ /*0x10ce8*/ 1294,
+ /*0x00ec*/ 37,
+ /*0x13e0*/ 590,
+ /*0x1f77*/ 794,
+ /*0x10d7b*/ 1316,
+ /*0x10ff*/ 525,
+ -1,
+ /*0x104e0*/ 1191,
+ -1,
+ /*0x01ff*/ 165,
+ -1,
+ /*0x0260*/ 210,
+ /*0x00ff*/ 55,
+ /*0xff47*/ 1123,
+ /*0x017c*/ 115,
+ -1,
+ /*0x118ce*/ 1341,
+ /*0x24e0*/ 842,
+ /*0x2c4e*/ 882,
+ -1, -1,
+ /*0x10e8*/ 504,
+ -1,
+ /*0x13bc*/ 554,
+ /*0x043c*/ 306,
+ /*0xff45*/ 1121,
+ -1,
+ /*0x1043c*/ 1163,
+ /*0x00e8*/ 33,
+ /*0x050f*/ 425,
+ /*0x2d03*/ 964,
+ /*0x013c*/ 84,
+ /*0x023c*/ 191,
+ -1,
+ /*0x10ccc*/ 1266,
+ -1, -1,
+ /*0x1f66*/ 785,
+ -1,
+ /*0x118d0*/ 1343,
+ /*0x2c66*/ 902,
+ /*0x2c50*/ 884,
+ -1, -1,
+ /*0x10ce4*/ 1290,
+ /*0x1e07*/ 619,
+ /*0x1e87*/ 683,
+ /*0x0107*/ 59,
+ /*0x0207*/ 169,
+ /*0x2c87*/ 911,
+ -1,
+ /*0x03c6*/ 268,
+ -1,
+ /*0xa77c*/ 1077,
+ /*0x0579*/ 466,
+ -1,
+ /*0x2174*/ 813,
+ -1, -1,
+ /*0x01cc*/ 141,
+ -1,
+ /*0xa799*/ 1088,
+ -1,
+ /*0x0578*/ 465,
+ /*0x0572*/ 459,
+ /*0x10e4*/ 500,
+ /*0x10d77*/ 1312,
+ /*0xff42*/ 1118,
+ /*0x118d2*/ 1345,
+ /*0x0503*/ 419,
+ /*0x2c52*/ 886,
+ -1,
+ /*0x00e4*/ 29,
+ -1,
+ /*0x13ea*/ 600,
+ -1, -1,
+ /*0x006a*/ 8,
+ -1,
+ /*0x104ea*/ 1201,
+ /*0x03c4*/ 266,
+ /*0x052f*/ 441,
+ /*0x10f4*/ 516,
+ /*0x026a*/ 218,
+ -1,
+ /*0xa7ca*/ 1106,
+ -1,
+ /*0x10cca*/ 1264,
+ /*0x0199*/ 124,
+ /*0x00f4*/ 45,
+ /*0x13b6*/ 548,
+ /*0x0436*/ 300,
+ /*0x0529*/ 438,
+ -1,
+ /*0x10436*/ 1157,
+ -1,
+ /*0x1f70*/ 787,
+ -1, -1,
+ /*0x13e2*/ 592,
+ /*0x13dc*/ 586,
+ /*0x045c*/ 338,
+ /*0x0062*/ 1,
+ -1,
+ /*0x104e2*/ 1193,
+ /*0x104dc*/ 1187,
+ /*0x217c*/ 821,
+ /*0x10ce0*/ 1286,
+ -1,
+ /*0x025c*/ 209,
+ -1,
+ /*0x2d21*/ 994,
+ -1,
+ /*0x16ec8*/ 1404,
+ /*0x24e2*/ 844,
+ /*0x24dc*/ 838,
+ /*0x13da*/ 584,
+ /*0x045a*/ 336,
+ -1,
+ /*0x0195*/ 123,
+ -1,
+ /*0x104da*/ 1185,
+ -1,
+ /*0x13d6*/ 580,
+ /*0x0456*/ 332,
+ -1,
+ /*0x037c*/ 242,
+ -1,
+ /*0x10e0*/ 496,
+ /*0x1f13*/ 750,
+ -1,
+ /*0x24da*/ 836,
+ /*0x0256*/ 205,
+ -1, -1,
+ /*0x00e0*/ 25,
+ /*0x13d8*/ 582,
+ /*0x0458*/ 334,
+ /*0x24d6*/ 832,
+ /*0x00fc*/ 52,
+ /*0x057b*/ 468,
+ /*0x104d8*/ 1183,
+ /*0xa787*/ 1082,
+ -1,
+ /*0x13b4*/ 546,
+ /*0x0434*/ 298,
+ -1,
+ /*0x118c6*/ 1333,
+ /*0x10434*/ 1155,
+ /*0x2c46*/ 874,
+ /*0x0521*/ 434,
+ /*0x24d8*/ 834,
+ /*0x1f7a*/ 797,
+ -1,
+ /*0x16ece*/ 1410,
+ -1,
+ /*0x0497*/ 365,
+ -1, -1,
+ /*0x10d70*/ 1305,
+ /*0x1e17*/ 627,
+ /*0x048d*/ 360,
+ /*0x0117*/ 67,
+ /*0x0217*/ 177,
+ /*0x2c97*/ 919,
+ /*0x1e0d*/ 622,
+ /*0x1e8d*/ 686,
+ /*0x010d*/ 62,
+ /*0x020d*/ 172,
+ /*0x2c8d*/ 914,
+ -1, -1, -1,
+ /*0x16e79*/ 1384,
+ /*0x03cc*/ 274,
+ /*0x1f44*/ 773,
+ /*0x118c4*/ 1331,
+ /*0x16ed0*/ 1412,
+ /*0x2c44*/ 872,
+ /*0x10cea*/ 1296,
+ -1, -1,
+ /*0x16e78*/ 1383,
+ /*0x16e72*/ 1377,
+ -1,
+ /*0x049d*/ 368,
+ /*0x13be*/ 556,
+ /*0x043e*/ 308,
+ -1,
+ /*0x1e1d*/ 630,
+ /*0x1043e*/ 1165,
+ /*0x011d*/ 70,
+ /*0x021d*/ 180,
+ /*0x2c9d*/ 922,
+ /*0x013e*/ 85,
+ /*0x1f76*/ 793,
+ -1, -1,
+ /*0x2c76*/ 907,
+ -1,
+ /*0x10ea*/ 506,
+ -1,
+ /*0x0577*/ 464,
+ -1,
+ /*0x10ce2*/ 1288,
+ /*0x10cdc*/ 1282,
+ /*0x16ed2*/ 1414,
+ /*0x00ea*/ 35,
+ /*0x13d4*/ 578,
+ /*0x0454*/ 330,
+ -1,
+ /*0x2c6c*/ 905,
+ -1,
+ /*0x1fb1*/ 802,
+ -1,
+ /*0x10d7a*/ 1315,
+ -1,
+ /*0x0254*/ 204,
+ -1,
+ /*0x13ee*/ 604,
+ /*0x01b6*/ 135,
+ /*0x10cda*/ 1280,
+ /*0x006e*/ 12,
+ /*0x24d4*/ 830,
+ /*0x104ee*/ 1205,
+ /*0x10e2*/ 498,
+ /*0x10dc*/ 492,
+ /*0x03ca*/ 272,
+ /*0x10cd6*/ 1276,
+ /*0x2cee*/ 959,
+ /*0x01dc*/ 149,
+ -1,
+ /*0x00e2*/ 27,
+ -1, -1, -1,
+ /*0x0566*/ 447,
+ -1,
+ /*0x2c68*/ 903,
+ /*0x13de*/ 588,
+ /*0x045e*/ 340,
+ /*0x10cd8*/ 1278,
+ /*0x10da*/ 490,
+ -1,
+ /*0x104de*/ 1189,
+ -1,
+ /*0x01da*/ 148,
+ -1, -1,
+ /*0x10d6*/ 486,
+ -1, -1, -1,
+ /*0x01d6*/ 146,
+ /*0x24de*/ 840,
+ -1, -1,
+ /*0xa797*/ 1087,
+ /*0x10d76*/ 1311,
+ /*0x16e7b*/ 1386,
+ -1, -1,
+ /*0x10d8*/ 488,
+ /*0x1e92b*/ 1425,
+ -1, -1,
+ /*0x01d8*/ 147,
+ /*0x0287*/ 229,
+ /*0x03bc*/ 259,
+ -1,
+ /*0x118cc*/ 1339,
+ -1,
+ /*0x2c4c*/ 880,
+ -1,
+ /*0x01b4*/ 134,
+ -1,
+ /*0x105ab*/ 1238,
+ -1, -1,
+ /*0x1f64*/ 783,
+ /*0x13ba*/ 552,
+ /*0x043a*/ 304,
+ /*0x10d7f*/ 1320,
+ -1,
+ /*0x1043a*/ 1161,
+ /*0x16ec6*/ 1402,
+ /*0xa79d*/ 1090,
+ /*0xa681*/ 1024,
+ /*0x013a*/ 83,
+ /*0x2d13*/ 980,
+ -1, -1, -1, -1,
+ /*0xa685*/ 1026,
+ /*0x0570*/ 457,
+ /*0x1f74*/ 791,
+ /*0x1e09*/ 620,
+ /*0x1e89*/ 684,
+ /*0x0109*/ 60,
+ /*0x0209*/ 170,
+ /*0x2c89*/ 912,
+ /*0x13b8*/ 550,
+ /*0x0438*/ 302,
+ -1, -1,
+ /*0x10438*/ 1159,
+ -1, -1, -1, -1, -1, -1,
+ /*0x10cd4*/ 1274,
+ /*0x16ec4*/ 1400,
+ -1, -1, -1, -1,
+ /*0x10599*/ 1221,
+ -1,
+ /*0x16e77*/ 1382,
+ -1,
+ /*0x118ca*/ 1337,
+ /*0x10cee*/ 1300,
+ /*0x2c4a*/ 878,
+ /*0x13b2*/ 544,
+ /*0x0432*/ 296,
+ /*0x0513*/ 427,
+ /*0x1f15*/ 752,
+ /*0x10432*/ 1153,
+ -1, -1, -1,
+ /*0x10d4*/ 484,
+ /*0x03b6*/ 253,
+ -1, -1,
+ /*0x01d4*/ 145,
+ -1, -1, -1,
+ /*0x1f60*/ 779,
+ -1,
+ /*0x10cde*/ 1284,
+ /*0x10ee*/ 510,
+ /*0x1f7c*/ 799,
+ -1, -1, -1, -1,
+ /*0x057a*/ 467,
+ /*0x00ee*/ 39,
+ -1, -1,
+ /*0x16e66*/ 1365,
+ -1, -1, -1,
+ /*0x10d74*/ 1309,
+ -1, -1, -1, -1, -1,
+ /*0x10de*/ 494,
+ /*0x2c3c*/ 864,
+ -1, -1, -1, -1,
+ /*0x1e93c*/ 1442,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x1f07*/ 746,
+ -1, -1, -1, -1,
+ /*0x105bc*/ 1253,
+ -1, -1, -1, -1,
+ /*0x03b4*/ 251,
+ -1, -1, -1, -1,
+ /*0x0576*/ 463,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x056c*/ 453,
+ /*0x16ecc*/ 1408,
+ /*0x10d7c*/ 1317,
+ -1,
+ /*0x029d*/ 236,
+ -1, -1,
+ /*0x16e70*/ 1375,
+ -1, -1,
+ /*0x2c6a*/ 904,
+ /*0x057f*/ 472,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x1f36*/ 767,
+ /*0x03be*/ 261,
+ -1,
+ /*0x2c36*/ 858,
+ /*0x0568*/ 449,
+ -1, -1, -1,
+ /*0x1e936*/ 1436,
+ /*0x1f62*/ 781,
+ -1,
+ /*0x118dc*/ 1355,
+ -1,
+ /*0x2c5c*/ 896,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x105b6*/ 1248,
+ -1, -1,
+ /*0x052b*/ 439,
+ -1, -1,
+ /*0x118da*/ 1353,
+ /*0x2d19*/ 986,
+ /*0x2c5a*/ 894,
+ -1,
+ /*0x16eca*/ 1406,
+ -1, -1,
+ /*0x118d6*/ 1349,
+ -1,
+ /*0x2c56*/ 890,
+ -1, -1, -1,
+ /*0x16e7a*/ 1385,
+ -1, -1, -1, -1, -1, -1,
+ /*0x118d8*/ 1351,
+ /*0x0564*/ 445,
+ /*0x2c58*/ 892,
+ -1, -1, -1, -1,
+ /*0x1f34*/ 765,
+ -1, -1,
+ /*0x2c34*/ 856,
+ -1,
+ /*0x2d15*/ 982,
+ -1, -1,
+ /*0x1e934*/ 1434,
+ -1,
+ /*0x1fd0*/ 803,
+ /*0x0574*/ 461,
+ -1,
+ /*0x0519*/ 430,
+ -1, -1, -1, -1,
+ /*0x16ebc*/ 1392,
+ -1, -1,
+ /*0x105b4*/ 1246,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x16e76*/ 1381,
+ -1,
+ /*0x10597*/ 1219,
+ -1, -1, -1,
+ /*0x0289*/ 231,
+ -1, -1, -1, -1, -1,
+ /*0x03ba*/ 257,
+ /*0x16e6c*/ 1371,
+ -1,
+ /*0x0515*/ 428,
+ /*0x2c3e*/ 866,
+ /*0xa68f*/ 1031,
+ -1, -1, -1,
+ /*0x1e93e*/ 1444,
+ -1, -1,
+ /*0x16e7f*/ 1390,
+ -1,
+ /*0x2d07*/ 968,
+ -1, -1, -1, -1,
+ /*0x1059d*/ 1225,
+ /*0x057c*/ 469,
+ -1,
+ /*0x03b8*/ 255,
+ -1,
+ /*0x118d4*/ 1347,
+ -1,
+ /*0x2c54*/ 888,
+ -1,
+ /*0x16e68*/ 1367,
+ -1, -1, -1, -1,
+ /*0xff48*/ 1124,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xa683*/ 1025,
+ /*0x03b2*/ 249,
+ -1, -1, -1, -1, -1, -1,
+ /*0x0507*/ 421,
+ -1,
+ /*0x118de*/ 1357,
+ -1,
+ /*0x2c5e*/ 898,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x16e64*/ 1363,
+ -1,
+ /*0xff4e*/ 1130,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x056a*/ 451,
+ /*0x16e74*/ 1379,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xff50*/ 1132,
+ /*0x2c3a*/ 862,
+ -1, -1, -1, -1,
+ /*0x1e93a*/ 1440,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x0562*/ 443,
+ -1, -1, -1, -1, -1, -1,
+ /*0x2c38*/ 860,
+ -1, -1, -1, -1,
+ /*0x1e938*/ 1438,
+ /*0xff52*/ 1134,
+ -1, -1,
+ /*0x2d17*/ 984,
+ -1, -1, -1, -1,
+ /*0x2d0d*/ 974,
+ /*0x16e60*/ 1359,
+ -1, -1,
+ /*0x105b8*/ 1250,
+ /*0x16e7c*/ 1387,
+ /*0x16ebe*/ 1394,
+ /*0x1f32*/ 763,
+ -1, -1,
+ /*0x2c32*/ 854,
+ -1, -1, -1, -1,
+ /*0x1e932*/ 1432,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1,
+ /*0x2d1d*/ 990,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x0517*/ 429,
+ -1, -1, -1, -1,
+ /*0x050d*/ 424,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x051d*/ 432,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xff46*/ 1122,
+ -1,
+ /*0x16e6a*/ 1369,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x16e62*/ 1361,
+ /*0x056e*/ 455,
+ /*0xff44*/ 1120,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0x2d09*/ 970,
+ -1, -1, -1, -1, -1, -1,
+ /*0x1fe0*/ 805,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa693*/ 1033,
+ /*0x0509*/ 422,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff4c*/ 1128,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x16e6e*/ 1373,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff4a*/ 1126,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xa699*/ 1036,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa695*/ 1034,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff5a*/ 1142,
+ -1, -1, -1, -1, -1, -1,
+ /*0xff56*/ 1138,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xff58*/ 1140,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0xa687*/ 1027,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ /*0xff54*/ 1136,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1,
+ /*0xa697*/ 1035,
+ -1, -1, -1, -1,
+ /*0xa68d*/ 1030,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0xa689*/ 1028
+ };
+
+ if (code <= MAX_CODE_VALUE && code >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseUnfold_11_hash(code);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code1_equal(code, CaseUnfold_11_Table[s].from))
+ return &CaseUnfold_11_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const CaseUnfold_12_Type CaseUnfold_12_Table[] = {
+#define CaseUnfold_12 (*(CaseUnfold_12_Type (*)[58])(CaseUnfold_12_Table+0))
+ {{0x0061, 0x02be}, {1, {0x1e9a}}},
+ {{0x0066, 0x0066}, {1, {0xfb00}}},
+ {{0x0066, 0x0069}, {1, {0xfb01}}},
+ {{0x0066, 0x006c}, {1, {0xfb02}}},
+ {{0x0068, 0x0331}, {1, {0x1e96}}},
+ {{0x006a, 0x030c}, {1, {0x01f0}}},
+ {{0x0073, 0x0073}, {2, {0x00df, 0x1e9e}}},
+ {{0x0073, 0x0074}, {2, {0xfb05, 0xfb06}}},
+ {{0x0074, 0x0308}, {1, {0x1e97}}},
+ {{0x0077, 0x030a}, {1, {0x1e98}}},
+ {{0x0079, 0x030a}, {1, {0x1e99}}},
+ {{0x02bc, 0x006e}, {1, {0x0149}}},
+ {{0x03ac, 0x03b9}, {1, {0x1fb4}}},
+ {{0x03ae, 0x03b9}, {1, {0x1fc4}}},
+ {{0x03b1, 0x0342}, {1, {0x1fb6}}},
+ {{0x03b1, 0x03b9}, {2, {0x1fb3, 0x1fbc}}},
+ {{0x03b7, 0x0342}, {1, {0x1fc6}}},
+ {{0x03b7, 0x03b9}, {2, {0x1fc3, 0x1fcc}}},
+ {{0x03b9, 0x0342}, {1, {0x1fd6}}},
+ {{0x03c1, 0x0313}, {1, {0x1fe4}}},
+ {{0x03c5, 0x0313}, {1, {0x1f50}}},
+ {{0x03c5, 0x0342}, {1, {0x1fe6}}},
+ {{0x03c9, 0x0342}, {1, {0x1ff6}}},
+ {{0x03c9, 0x03b9}, {2, {0x1ff3, 0x1ffc}}},
+ {{0x03ce, 0x03b9}, {1, {0x1ff4}}},
+ {{0x0565, 0x0582}, {1, {0x0587}}},
+ {{0x0574, 0x0565}, {1, {0xfb14}}},
+ {{0x0574, 0x056b}, {1, {0xfb15}}},
+ {{0x0574, 0x056d}, {1, {0xfb17}}},
+ {{0x0574, 0x0576}, {1, {0xfb13}}},
+ {{0x057e, 0x0576}, {1, {0xfb16}}},
+ {{0x1f00, 0x03b9}, {2, {0x1f80, 0x1f88}}},
+ {{0x1f01, 0x03b9}, {2, {0x1f81, 0x1f89}}},
+ {{0x1f02, 0x03b9}, {2, {0x1f82, 0x1f8a}}},
+ {{0x1f03, 0x03b9}, {2, {0x1f83, 0x1f8b}}},
+ {{0x1f04, 0x03b9}, {2, {0x1f84, 0x1f8c}}},
+ {{0x1f05, 0x03b9}, {2, {0x1f85, 0x1f8d}}},
+ {{0x1f06, 0x03b9}, {2, {0x1f86, 0x1f8e}}},
+ {{0x1f07, 0x03b9}, {2, {0x1f87, 0x1f8f}}},
+ {{0x1f20, 0x03b9}, {2, {0x1f90, 0x1f98}}},
+ {{0x1f21, 0x03b9}, {2, {0x1f91, 0x1f99}}},
+ {{0x1f22, 0x03b9}, {2, {0x1f92, 0x1f9a}}},
+ {{0x1f23, 0x03b9}, {2, {0x1f93, 0x1f9b}}},
+ {{0x1f24, 0x03b9}, {2, {0x1f94, 0x1f9c}}},
+ {{0x1f25, 0x03b9}, {2, {0x1f95, 0x1f9d}}},
+ {{0x1f26, 0x03b9}, {2, {0x1f96, 0x1f9e}}},
+ {{0x1f27, 0x03b9}, {2, {0x1f97, 0x1f9f}}},
+ {{0x1f60, 0x03b9}, {2, {0x1fa0, 0x1fa8}}},
+ {{0x1f61, 0x03b9}, {2, {0x1fa1, 0x1fa9}}},
+ {{0x1f62, 0x03b9}, {2, {0x1fa2, 0x1faa}}},
+ {{0x1f63, 0x03b9}, {2, {0x1fa3, 0x1fab}}},
+ {{0x1f64, 0x03b9}, {2, {0x1fa4, 0x1fac}}},
+ {{0x1f65, 0x03b9}, {2, {0x1fa5, 0x1fad}}},
+ {{0x1f66, 0x03b9}, {2, {0x1fa6, 0x1fae}}},
+ {{0x1f67, 0x03b9}, {2, {0x1fa7, 0x1faf}}},
+ {{0x1f70, 0x03b9}, {1, {0x1fb2}}},
+ {{0x1f74, 0x03b9}, {1, {0x1fc2}}},
+ {{0x1f7c, 0x03b9}, {1, {0x1ff2}}},
+#define CaseUnfold_12_Locale (*(CaseUnfold_12_Type (*)[1])(CaseUnfold_12_Table+58))
+ {{0x0069, 0x0307}, {1, {0x0130}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3,4,5,6 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_12_hash -N onigenc_unicode_CaseUnfold_12_lookup -n */
+
+/* maximum key range = 71, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseUnfold_12_hash(const OnigCodePoint *codes)
+{
+ static const unsigned char asso_values[] =
+ {
+ 3, 58, 54, 57, 56, 16, 8, 2, 43, 82,
+ 3, 1, 23, 82, 82, 82, 82, 82, 82, 4,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 52, 51, 50, 49, 48, 47, 46, 45,
+ 82, 82, 82, 82, 43, 82, 42, 82, 82, 13,
+ 82, 82, 82, 82, 82, 11, 82, 1, 82, 82,
+ 14, 82, 1, 82, 82, 31, 3, 82, 82, 30,
+ 82, 82, 82, 10, 82, 82, 82, 82, 37, 82,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 82, 82, 82, 82, 37, 15, 36, 35,
+ 34, 17, 1, 33, 12, 4, 23, 23, 26, 21,
+ 13, 82, 27, 82, 82, 2, 5, 82, 11, 16,
+ 82, 15, 82, 82, 23, 82, 8, 82
+ };
+ return asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
+}
+
+static const CodePointList2 *
+onigenc_unicode_CaseUnfold_12_lookup(const OnigCodePoint *codes)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x61,
+ MAX_CODE_VALUE = 0x1f7c,
+ TOTAL_KEYWORDS = 59,
+ MIN_WORD_LENGTH = 6,
+ MAX_WORD_LENGTH = 6,
+ MIN_HASH_VALUE = 11,
+ MAX_HASH_VALUE = 81
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1,
+ /*0x1f66,0x03b9*/ 53,
+ /*0x1f07,0x03b9*/ 38,
+ /*0x1f00,0x03b9*/ 31,
+ /*0x0066,0x0066*/ 1,
+ /*0x1f74,0x03b9*/ 56,
+ /*0x0073,0x0073*/ 6,
+ /*0x0066,0x0069*/ 2,
+ /*0x1f06,0x03b9*/ 37,
+ /*0x0073,0x0074*/ 7,
+ /*0x03b9,0x0342*/ 18,
+ /*0x03c9,0x03b9*/ 23,
+ /*0x03b7,0x03b9*/ 17,
+ /*0x0069,0x0307*/ 58,
+ /*0x03b1,0x03b9*/ 15,
+ /*0x1f61,0x03b9*/ 48,
+ /*0x1f05,0x03b9*/ 36,
+ /*0x1f65,0x03b9*/ 52,
+ /*0x0574,0x0576*/ 29,
+ /*0x03c9,0x0342*/ 22,
+ /*0x03b7,0x0342*/ 16,
+ /*0x057e,0x0576*/ 30,
+ /*0x03b1,0x0342*/ 14,
+ /*0x1f7c,0x03b9*/ 57,
+ /*0x0574,0x0565*/ 26,
+ /*0x0079,0x030a*/ 10,
+ /*0x0077,0x030a*/ 9,
+ /*0x1f70,0x03b9*/ 55,
+ /*0x0574,0x056d*/ 28,
+ /*0x0066,0x006c*/ 3,
+ /*0x0574,0x056b*/ 27,
+ /*0x0061,0x02be*/ 0,
+ /*0x0068,0x0331*/ 4,
+ /*0x1f67,0x03b9*/ 54,
+ /*0x1f64,0x03b9*/ 51,
+ /*0x1f63,0x03b9*/ 50,
+ /*0x1f62,0x03b9*/ 49,
+ /*0x1f60,0x03b9*/ 47,
+ /*0x03ce,0x03b9*/ 24,
+ /*0x03c5,0x0342*/ 21,
+ /*0x03c5,0x0313*/ 20,
+ /*0x03c1,0x0313*/ 19,
+ /*0x02bc,0x006e*/ 11,
+ /*0x03ae,0x03b9*/ 13,
+ /*0x03ac,0x03b9*/ 12,
+ /*0x1f27,0x03b9*/ 46,
+ /*0x1f26,0x03b9*/ 45,
+ /*0x1f25,0x03b9*/ 44,
+ /*0x1f24,0x03b9*/ 43,
+ /*0x1f23,0x03b9*/ 42,
+ /*0x1f22,0x03b9*/ 41,
+ /*0x1f21,0x03b9*/ 40,
+ /*0x1f20,0x03b9*/ 39,
+ /*0x006a,0x030c*/ 5,
+ /*0x1f02,0x03b9*/ 33,
+ /*0x0074,0x0308*/ 8,
+ /*0x1f04,0x03b9*/ 35,
+ /*0x1f03,0x03b9*/ 34,
+ /*0x1f01,0x03b9*/ 32,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ /*0x0565,0x0582*/ 25
+ };
+
+ if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
+ codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseUnfold_12_hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code2_equal(codes, CaseUnfold_12_Table[s].from))
+ return &CaseUnfold_12_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const CaseUnfold_13_Type CaseUnfold_13_Table[] = {
+#define CaseUnfold_13 (*(CaseUnfold_13_Type (*)[14])(CaseUnfold_13_Table+0))
+ {{0x0066, 0x0066, 0x0069}, {1, {0xfb03}}},
+ {{0x0066, 0x0066, 0x006c}, {1, {0xfb04}}},
+ {{0x03b1, 0x0342, 0x03b9}, {1, {0x1fb7}}},
+ {{0x03b7, 0x0342, 0x03b9}, {1, {0x1fc7}}},
+ {{0x03b9, 0x0308, 0x0300}, {1, {0x1fd2}}},
+ {{0x03b9, 0x0308, 0x0301}, {2, {0x0390, 0x1fd3}}},
+ {{0x03b9, 0x0308, 0x0342}, {1, {0x1fd7}}},
+ {{0x03c5, 0x0308, 0x0300}, {1, {0x1fe2}}},
+ {{0x03c5, 0x0308, 0x0301}, {2, {0x03b0, 0x1fe3}}},
+ {{0x03c5, 0x0308, 0x0342}, {1, {0x1fe7}}},
+ {{0x03c5, 0x0313, 0x0300}, {1, {0x1f52}}},
+ {{0x03c5, 0x0313, 0x0301}, {1, {0x1f54}}},
+ {{0x03c5, 0x0313, 0x0342}, {1, {0x1f56}}},
+ {{0x03c9, 0x0342, 0x03b9}, {1, {0x1ff7}}},
+};
+
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -k1,2,3,4,5,6,7,8,9 -F,-1 -c -j1 -i1 -t -T -E -C -H onigenc_unicode_CaseUnfold_13_hash -N onigenc_unicode_CaseUnfold_13_lookup -n */
+
+/* maximum key range = 20, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+/*ARGSUSED*/
+static unsigned int
+onigenc_unicode_CaseUnfold_13_hash(const OnigCodePoint *codes)
+{
+ static const unsigned char asso_values[] =
+ {
+ 7, 4, 47, 47, 47, 47, 1, 1, 2, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 1,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 11,
+ 47, 47, 47, 47, 47, 10, 47, 2, 47, 47,
+ 47, 47, 47, 47, 47, 47, 1, 47, 47, 1,
+ 47, 47, 47, 9, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 1, 47, 47, 2, 47, 47, 1, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47
+ };
+ return asso_values[bits_at(codes, 8)] + asso_values[bits_at(codes, 7)] + asso_values[bits_at(codes, 6)] + asso_values[bits_at(codes, 5)] + asso_values[bits_at(codes, 4)] + asso_values[bits_at(codes, 3)] + asso_values[bits_at(codes, 2)] + asso_values[bits_at(codes, 1)] + asso_values[bits_at(codes, 0)];
+}
+
+static const CodePointList2 *
+onigenc_unicode_CaseUnfold_13_lookup(const OnigCodePoint *codes)
+{
+ enum
+ {
+ MIN_CODE_VALUE = 0x66,
+ MAX_CODE_VALUE = 0x3c9,
+ TOTAL_KEYWORDS = 14,
+ MIN_WORD_LENGTH = 9,
+ MAX_WORD_LENGTH = 9,
+ MIN_HASH_VALUE = 27,
+ MAX_HASH_VALUE = 46
+ };
+
+ static const short wordlist[] =
+ {
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
+ /*0x03c5,0x0313,0x0342*/ 12,
+ /*0x03c5,0x0308,0x0342*/ 9,
+ /*0x03b9,0x0308,0x0342*/ 6,
+ /*0x03c5,0x0313,0x0301*/ 11,
+ /*0x03c5,0x0308,0x0301*/ 8,
+ /*0x03b9,0x0308,0x0301*/ 5,
+ /*0x03c5,0x0313,0x0300*/ 10,
+ /*0x03c5,0x0308,0x0300*/ 7,
+ /*0x03b9,0x0308,0x0300*/ 4,
+ /*0x03c9,0x0342,0x03b9*/ 13,
+ /*0x03b7,0x0342,0x03b9*/ 3,
+ /*0x03b1,0x0342,0x03b9*/ 2,
+ -1, -1, -1, -1, -1, -1,
+ /*0x0066,0x0066,0x006c*/ 1,
+ /*0x0066,0x0066,0x0069*/ 0
+ };
+
+ if (codes[0] <= MAX_CODE_VALUE && codes[0] >= MIN_CODE_VALUE &&
+ codes[1] <= MAX_CODE_VALUE && codes[1] >= MIN_CODE_VALUE &&
+ codes[2] <= MAX_CODE_VALUE && codes[2] >= MIN_CODE_VALUE)
+ {
+ register unsigned int key = onigenc_unicode_CaseUnfold_13_hash(codes);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register short s = wordlist[key];
+
+ if (s >= 0 && code3_equal(codes, CaseUnfold_13_Table[s].from))
+ return &CaseUnfold_13_Table[s].to;
+ }
+ }
+ return 0;
+}
+
+static const OnigCodePoint CaseMappingSpecials[] = {
+ L(1)|0x039C,
+ L(2)|0x0053, 0x0073, L(2)|0x0053, 0x0053,
+ L(2)|0x02BC, 0x004E,
+ L(1)|0x0053,
+ L(1)|0x01C5,
+ L(2)|0x0064, 0x017D, L(1)|0x01C4,
+ L(1)|0x01C8,
+ L(2)|0x006C, 0x004A, L(1)|0x01C7,
+ L(1)|0x01CB,
+ L(2)|0x006E, 0x004A, L(1)|0x01CA,
+ L(2)|0x004A, 0x030C,
+ L(1)|0x01F2,
+ L(2)|0x0064, 0x005A, L(1)|0x01F1,
+ L(1)|0x0399,
+ L(3)|0x0399, 0x0308, 0x0301,
+ L(3)|0x03A5, 0x0308, 0x0301,
+ L(1)|0x03A3,
+ L(1)|0x0392,
+ L(1)|0x0398,
+ L(1)|0x03A6,
+ L(1)|0x03A0,
+ L(1)|0x039A,
+ L(1)|0x03A1,
+ L(1)|0x0395,
+ L(2)|0x0535, 0x0582, L(2)|0x0535, 0x0552,
+ L(1)|0x0412,
+ L(1)|0x0414,
+ L(1)|0x041E,
+ L(1)|0x0421,
+ L(1)|0x0422,
+ L(1)|0x0422,
+ L(1)|0x042A,
+ L(1)|0x0462,
+ L(1)|0xA64A,
+ L(2)|0x0048, 0x0331,
+ L(2)|0x0054, 0x0308,
+ L(2)|0x0057, 0x030A,
+ L(2)|0x0059, 0x030A,
+ L(2)|0x0041, 0x02BE,
+ L(1)|0x1E60,
+ L(1)|0x00DF,
+ L(2)|0x03A5, 0x0313,
+ L(3)|0x03A5, 0x0313, 0x0300,
+ L(3)|0x03A5, 0x0313, 0x0301,
+ L(3)|0x03A5, 0x0313, 0x0342,
+ L(1)|0x1F88, L(2)|0x1F08, 0x0399,
+ L(1)|0x1F89, L(2)|0x1F09, 0x0399,
+ L(1)|0x1F8A, L(2)|0x1F0A, 0x0399,
+ L(1)|0x1F8B, L(2)|0x1F0B, 0x0399,
+ L(1)|0x1F8C, L(2)|0x1F0C, 0x0399,
+ L(1)|0x1F8D, L(2)|0x1F0D, 0x0399,
+ L(1)|0x1F8E, L(2)|0x1F0E, 0x0399,
+ L(1)|0x1F8F, L(2)|0x1F0F, 0x0399,
+ L(2)|0x1F00, 0x0399, L(1)|0x1F80, L(2)|0x1F08, 0x0399,
+ L(2)|0x1F01, 0x0399, L(1)|0x1F81, L(2)|0x1F09, 0x0399,
+ L(2)|0x1F02, 0x0399, L(1)|0x1F82, L(2)|0x1F0A, 0x0399,
+ L(2)|0x1F03, 0x0399, L(1)|0x1F83, L(2)|0x1F0B, 0x0399,
+ L(2)|0x1F04, 0x0399, L(1)|0x1F84, L(2)|0x1F0C, 0x0399,
+ L(2)|0x1F05, 0x0399, L(1)|0x1F85, L(2)|0x1F0D, 0x0399,
+ L(2)|0x1F06, 0x0399, L(1)|0x1F86, L(2)|0x1F0E, 0x0399,
+ L(2)|0x1F07, 0x0399, L(1)|0x1F87, L(2)|0x1F0F, 0x0399,
+ L(1)|0x1F98, L(2)|0x1F28, 0x0399,
+ L(1)|0x1F99, L(2)|0x1F29, 0x0399,
+ L(1)|0x1F9A, L(2)|0x1F2A, 0x0399,
+ L(1)|0x1F9B, L(2)|0x1F2B, 0x0399,
+ L(1)|0x1F9C, L(2)|0x1F2C, 0x0399,
+ L(1)|0x1F9D, L(2)|0x1F2D, 0x0399,
+ L(1)|0x1F9E, L(2)|0x1F2E, 0x0399,
+ L(1)|0x1F9F, L(2)|0x1F2F, 0x0399,
+ L(2)|0x1F20, 0x0399, L(1)|0x1F90, L(2)|0x1F28, 0x0399,
+ L(2)|0x1F21, 0x0399, L(1)|0x1F91, L(2)|0x1F29, 0x0399,
+ L(2)|0x1F22, 0x0399, L(1)|0x1F92, L(2)|0x1F2A, 0x0399,
+ L(2)|0x1F23, 0x0399, L(1)|0x1F93, L(2)|0x1F2B, 0x0399,
+ L(2)|0x1F24, 0x0399, L(1)|0x1F94, L(2)|0x1F2C, 0x0399,
+ L(2)|0x1F25, 0x0399, L(1)|0x1F95, L(2)|0x1F2D, 0x0399,
+ L(2)|0x1F26, 0x0399, L(1)|0x1F96, L(2)|0x1F2E, 0x0399,
+ L(2)|0x1F27, 0x0399, L(1)|0x1F97, L(2)|0x1F2F, 0x0399,
+ L(1)|0x1FA8, L(2)|0x1F68, 0x0399,
+ L(1)|0x1FA9, L(2)|0x1F69, 0x0399,
+ L(1)|0x1FAA, L(2)|0x1F6A, 0x0399,
+ L(1)|0x1FAB, L(2)|0x1F6B, 0x0399,
+ L(1)|0x1FAC, L(2)|0x1F6C, 0x0399,
+ L(1)|0x1FAD, L(2)|0x1F6D, 0x0399,
+ L(1)|0x1FAE, L(2)|0x1F6E, 0x0399,
+ L(1)|0x1FAF, L(2)|0x1F6F, 0x0399,
+ L(2)|0x1F60, 0x0399, L(1)|0x1FA0, L(2)|0x1F68, 0x0399,
+ L(2)|0x1F61, 0x0399, L(1)|0x1FA1, L(2)|0x1F69, 0x0399,
+ L(2)|0x1F62, 0x0399, L(1)|0x1FA2, L(2)|0x1F6A, 0x0399,
+ L(2)|0x1F63, 0x0399, L(1)|0x1FA3, L(2)|0x1F6B, 0x0399,
+ L(2)|0x1F64, 0x0399, L(1)|0x1FA4, L(2)|0x1F6C, 0x0399,
+ L(2)|0x1F65, 0x0399, L(1)|0x1FA5, L(2)|0x1F6D, 0x0399,
+ L(2)|0x1F66, 0x0399, L(1)|0x1FA6, L(2)|0x1F6E, 0x0399,
+ L(2)|0x1F67, 0x0399, L(1)|0x1FA7, L(2)|0x1F6F, 0x0399,
+ L(2)|0x1FBA, 0x0345, L(2)|0x1FBA, 0x0399,
+ L(1)|0x1FBC, L(2)|0x0391, 0x0399,
+ L(2)|0x0386, 0x0345, L(2)|0x0386, 0x0399,
+ L(2)|0x0391, 0x0342,
+ L(3)|0x0391, 0x0342, 0x0345, L(3)|0x0391, 0x0342, 0x0399,
+ L(2)|0x03B1, 0x0399, L(1)|0x1FB3, L(2)|0x0391, 0x0399,
+ L(1)|0x0399,
+ L(2)|0x1FCA, 0x0345, L(2)|0x1FCA, 0x0399,
+ L(1)|0x1FCC, L(2)|0x0397, 0x0399,
+ L(2)|0x0389, 0x0345, L(2)|0x0389, 0x0399,
+ L(2)|0x0397, 0x0342,
+ L(3)|0x0397, 0x0342, 0x0345, L(3)|0x0397, 0x0342, 0x0399,
+ L(2)|0x03B7, 0x0399, L(1)|0x1FC3, L(2)|0x0397, 0x0399,
+ L(3)|0x0399, 0x0308, 0x0300,
+ L(3)|0x0399, 0x0308, 0x0301,
+ L(2)|0x0399, 0x0342,
+ L(3)|0x0399, 0x0308, 0x0342,
+ L(3)|0x03A5, 0x0308, 0x0300,
+ L(3)|0x03A5, 0x0308, 0x0301,
+ L(2)|0x03A1, 0x0313,
+ L(2)|0x03A5, 0x0342,
+ L(3)|0x03A5, 0x0308, 0x0342,
+ L(2)|0x1FFA, 0x0345, L(2)|0x1FFA, 0x0399,
+ L(1)|0x1FFC, L(2)|0x03A9, 0x0399,
+ L(2)|0x038F, 0x0345, L(2)|0x038F, 0x0399,
+ L(2)|0x03A9, 0x0342,
+ L(3)|0x03A9, 0x0342, 0x0345, L(3)|0x03A9, 0x0342, 0x0399,
+ L(2)|0x03C9, 0x0399, L(1)|0x1FF3, L(2)|0x03A9, 0x0399,
+ L(2)|0x0046, 0x0066, L(2)|0x0046, 0x0046,
+ L(2)|0x0046, 0x0069, L(2)|0x0046, 0x0049,
+ L(2)|0x0046, 0x006C, L(2)|0x0046, 0x004C,
+ L(3)|0x0046, 0x0066, 0x0069, L(3)|0x0046, 0x0046, 0x0049,
+ L(3)|0x0046, 0x0066, 0x006C, L(3)|0x0046, 0x0046, 0x004C,
+ L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
+ L(2)|0x0053, 0x0074, L(2)|0x0053, 0x0054,
+ L(2)|0x0544, 0x0576, L(2)|0x0544, 0x0546,
+ L(2)|0x0544, 0x0565, L(2)|0x0544, 0x0535,
+ L(2)|0x0544, 0x056B, L(2)|0x0544, 0x053B,
+ L(2)|0x054E, 0x0576, L(2)|0x054E, 0x0546,
+ L(2)|0x0544, 0x056D, L(2)|0x0544, 0x053D,
+};
diff --git a/enc/unicode/17.0.0/name2ctype.h b/enc/unicode/17.0.0/name2ctype.h
new file mode 100644
index 0000000000..8c1c0659ac
--- /dev/null
+++ b/enc/unicode/17.0.0/name2ctype.h
@@ -0,0 +1,49725 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -7 -c -j1 -i1 -t -C -P -T -H uniname2ctype_hash -Q uniname2ctype_pool -N uniname2ctype_p */
+#ifndef USE_UNICODE_PROPERTIES
+/* Computed positions: -k'1,3' */
+#else /* USE_UNICODE_PROPERTIES */
+/* Computed positions: -k'1-3,5-6,12,16,$' */
+#endif /* USE_UNICODE_PROPERTIES */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+
+
+/* 'NEWLINE': [[:NEWLINE:]] */
+static const OnigCodePoint CR_NEWLINE[] = {
+ 1,
+ 0x000a, 0x000a,
+}; /* CR_NEWLINE */
+
+/* 'Alpha': [[:Alpha:]] */
+static const OnigCodePoint CR_Alpha[] = {
+ 761,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0345, 0x0345,
+ 0x0363, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05b0, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0657,
+ 0x0659, 0x065f,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06e1, 0x06e8,
+ 0x06ed, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x073f,
+ 0x074d, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0817,
+ 0x081a, 0x082c,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x0897,
+ 0x08a0, 0x08c9,
+ 0x08d4, 0x08df,
+ 0x08e3, 0x08e9,
+ 0x08f0, 0x093b,
+ 0x093d, 0x094c,
+ 0x094e, 0x0950,
+ 0x0955, 0x0963,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09ce, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4c,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a70, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0af9, 0x0afc,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccc,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e46,
+ 0x0e4d, 0x0e4d,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ecd, 0x0ecd,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f83,
+ 0x0f88, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 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, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 0x1dd3, 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, 0xa7dc,
+ 0xa7f1, 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 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,
+ 0x10d4a, 0x10d65,
+ 0x10d69, 0x10d69,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10efc,
+ 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,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 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,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 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,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f40,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1612e,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 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, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Alpha */
+
+/* 'Blank': [[:Blank:]] */
+static const OnigCodePoint CR_Blank[] = {
+ 8,
+ 0x0009, 0x0009,
+ 0x0020, 0x0020,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Blank */
+
+/* 'Cntrl': [[:Cntrl:]] */
+static const OnigCodePoint CR_Cntrl[] = {
+ 2,
+ 0x0000, 0x001f,
+ 0x007f, 0x009f,
+}; /* CR_Cntrl */
+
+/* 'Digit': [[:Digit:]] */
+static const OnigCodePoint CR_Digit[] = {
+ 72,
+ 0x0030, 0x0039,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0be6, 0x0bef,
+ 0x0c66, 0x0c6f,
+ 0x0ce6, 0x0cef,
+ 0x0d66, 0x0d6f,
+ 0x0de6, 0x0def,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f29,
+ 0x1040, 0x1049,
+ 0x1090, 0x1099,
+ 0x17e0, 0x17e9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19d9,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1b50, 0x1b59,
+ 0x1bb0, 0x1bb9,
+ 0x1c40, 0x1c49,
+ 0x1c50, 0x1c59,
+ 0xa620, 0xa629,
+ 0xa8d0, 0xa8d9,
+ 0xa900, 0xa909,
+ 0xa9d0, 0xa9d9,
+ 0xa9f0, 0xa9f9,
+ 0xaa50, 0xaa59,
+ 0xabf0, 0xabf9,
+ 0xff10, 0xff19,
+ 0x104a0, 0x104a9,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d49,
+ 0x11066, 0x1106f,
+ 0x110f0, 0x110f9,
+ 0x11136, 0x1113f,
+ 0x111d0, 0x111d9,
+ 0x112f0, 0x112f9,
+ 0x11450, 0x11459,
+ 0x114d0, 0x114d9,
+ 0x11650, 0x11659,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11730, 0x11739,
+ 0x118e0, 0x118e9,
+ 0x11950, 0x11959,
+ 0x11bf0, 0x11bf9,
+ 0x11c50, 0x11c59,
+ 0x11d50, 0x11d59,
+ 0x11da0, 0x11da9,
+ 0x11de0, 0x11de9,
+ 0x11f50, 0x11f59,
+ 0x16130, 0x16139,
+ 0x16a60, 0x16a69,
+ 0x16ac0, 0x16ac9,
+ 0x16b50, 0x16b59,
+ 0x16d70, 0x16d79,
+ 0x1ccf0, 0x1ccf9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1e140, 0x1e149,
+ 0x1e2f0, 0x1e2f9,
+ 0x1e4f0, 0x1e4f9,
+ 0x1e5f1, 0x1e5fa,
+ 0x1e950, 0x1e959,
+ 0x1fbf0, 0x1fbf9,
+}; /* CR_Digit */
+
+/* 'Graph': [[:Graph:]] */
+static const OnigCodePoint CR_Graph[] = {
+ 741,
+ 0x0021, 0x007e,
+ 0x00a1, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x167f,
+ 0x1681, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x200b, 0x2027,
+ 0x202a, 0x202e,
+ 0x2030, 0x205e,
+ 0x2060, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2fff,
+ 0x3001, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xe000, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Graph */
+
+/* 'Lower': [[:Lower:]] */
+static const OnigCodePoint CR_Lower[] = {
+ 677,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0138,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018d,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01aa, 0x01ab,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01ba,
+ 0x01bd, 0x01bf,
+ 0x01c6, 0x01c6,
+ 0x01c9, 0x01c9,
+ 0x01cc, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f0,
+ 0x01f3, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0221, 0x0221,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0239,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0293,
+ 0x0296, 0x02b8,
+ 0x02c0, 0x02c1,
+ 0x02e0, 0x02e4,
+ 0x0345, 0x0345,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037a, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fc,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0560, 0x0588,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x10ff,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d00, 0x1dbf,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9d,
+ 0x1e9f, 0x1e9f,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x210a, 0x210a,
+ 0x210e, 0x210f,
+ 0x2113, 0x2113,
+ 0x212f, 0x212f,
+ 0x2134, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213d,
+ 0x2146, 0x2149,
+ 0x214e, 0x214e,
+ 0x2170, 0x217f,
+ 0x2184, 0x2184,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c71, 0x2c71,
+ 0x2c73, 0x2c74,
+ 0x2c76, 0x2c7d,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce4,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69d,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa731,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa778,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa78e, 0xa78e,
+ 0xa791, 0xa791,
+ 0xa793, 0xa795,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7af, 0xa7af,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f1, 0xa7f4,
+ 0xa7f6, 0xa7f6,
+ 0xa7f8, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10780, 0x10780,
+ 0x10783, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1d41a, 0x1d433,
+ 0x1d44e, 0x1d454,
+ 0x1d456, 0x1d467,
+ 0x1d482, 0x1d49b,
+ 0x1d4b6, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d4cf,
+ 0x1d4ea, 0x1d503,
+ 0x1d51e, 0x1d537,
+ 0x1d552, 0x1d56b,
+ 0x1d586, 0x1d59f,
+ 0x1d5ba, 0x1d5d3,
+ 0x1d5ee, 0x1d607,
+ 0x1d622, 0x1d63b,
+ 0x1d656, 0x1d66f,
+ 0x1d68a, 0x1d6a5,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6e1,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d71b,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d755,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d78f,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7c9,
+ 0x1d7cb, 0x1d7cb,
+ 0x1df00, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e030, 0x1e06d,
+ 0x1e922, 0x1e943,
+}; /* CR_Lower */
+
+/* 'Print': [[:Print:]] */
+static const OnigCodePoint CR_Print[] = {
+ 737,
+ 0x0020, 0x007e,
+ 0x00a0, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2027,
+ 0x202a, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xe000, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Print */
+
+/* 'XPosixPunct': [[:Punct:]] */
+static const OnigCodePoint CR_XPosixPunct[] = {
+ 194,
+ 0x0021, 0x002f,
+ 0x003a, 0x0040,
+ 0x005b, 0x0060,
+ 0x007b, 0x007e,
+ 0x00a1, 0x00a1,
+ 0x00a7, 0x00a7,
+ 0x00ab, 0x00ab,
+ 0x00b6, 0x00b7,
+ 0x00bb, 0x00bb,
+ 0x00bf, 0x00bf,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x055a, 0x055f,
+ 0x0589, 0x058a,
+ 0x05be, 0x05be,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05f3, 0x05f4,
+ 0x0609, 0x060a,
+ 0x060c, 0x060d,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x066a, 0x066d,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070d,
+ 0x07f7, 0x07f9,
+ 0x0830, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0970, 0x0970,
+ 0x09fd, 0x09fd,
+ 0x0a76, 0x0a76,
+ 0x0af0, 0x0af0,
+ 0x0c77, 0x0c77,
+ 0x0c84, 0x0c84,
+ 0x0df4, 0x0df4,
+ 0x0e4f, 0x0e4f,
+ 0x0e5a, 0x0e5b,
+ 0x0f04, 0x0f12,
+ 0x0f14, 0x0f14,
+ 0x0f3a, 0x0f3d,
+ 0x0f85, 0x0f85,
+ 0x0fd0, 0x0fd4,
+ 0x0fd9, 0x0fda,
+ 0x104a, 0x104f,
+ 0x10fb, 0x10fb,
+ 0x1360, 0x1368,
+ 0x1400, 0x1400,
+ 0x166e, 0x166e,
+ 0x169b, 0x169c,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17d8, 0x17da,
+ 0x1800, 0x180a,
+ 0x1944, 0x1945,
+ 0x1a1e, 0x1a1f,
+ 0x1aa0, 0x1aa6,
+ 0x1aa8, 0x1aad,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b60,
+ 0x1b7d, 0x1b7f,
+ 0x1bfc, 0x1bff,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x2010, 0x2027,
+ 0x2030, 0x2043,
+ 0x2045, 0x2051,
+ 0x2053, 0x205e,
+ 0x207d, 0x207e,
+ 0x208d, 0x208e,
+ 0x2308, 0x230b,
+ 0x2329, 0x232a,
+ 0x2768, 0x2775,
+ 0x27c5, 0x27c6,
+ 0x27e6, 0x27ef,
+ 0x2983, 0x2998,
+ 0x29d8, 0x29db,
+ 0x29fc, 0x29fd,
+ 0x2cf9, 0x2cfc,
+ 0x2cfe, 0x2cff,
+ 0x2d70, 0x2d70,
+ 0x2e00, 0x2e2e,
+ 0x2e30, 0x2e4f,
+ 0x2e52, 0x2e5d,
+ 0x3001, 0x3003,
+ 0x3008, 0x3011,
+ 0x3014, 0x301f,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x30a0, 0x30a0,
+ 0x30fb, 0x30fb,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa67e,
+ 0xa6f2, 0xa6f7,
+ 0xa874, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa8f8, 0xa8fa,
+ 0xa8fc, 0xa8fc,
+ 0xa92e, 0xa92f,
+ 0xa95f, 0xa95f,
+ 0xa9c1, 0xa9cd,
+ 0xa9de, 0xa9df,
+ 0xaa5c, 0xaa5f,
+ 0xaade, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfd3e, 0xfd3f,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe61,
+ 0xfe63, 0xfe63,
+ 0xfe68, 0xfe68,
+ 0xfe6a, 0xfe6b,
+ 0xff01, 0xff03,
+ 0xff05, 0xff0a,
+ 0xff0c, 0xff0f,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff20,
+ 0xff3b, 0xff3d,
+ 0xff3f, 0xff3f,
+ 0xff5b, 0xff5b,
+ 0xff5d, 0xff5d,
+ 0xff5f, 0xff65,
+ 0x10100, 0x10102,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x1056f, 0x1056f,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x1093f, 0x1093f,
+ 0x10a50, 0x10a58,
+ 0x10a7f, 0x10a7f,
+ 0x10af0, 0x10af6,
+ 0x10b39, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+ 0x10ed0, 0x10ed0,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x11140, 0x11143,
+ 0x11174, 0x11175,
+ 0x111c5, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111db, 0x111db,
+ 0x111dd, 0x111df,
+ 0x11238, 0x1123d,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x1144b, 0x1144f,
+ 0x1145a, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x114c6, 0x114c6,
+ 0x115c1, 0x115d7,
+ 0x11641, 0x11643,
+ 0x11660, 0x1166c,
+ 0x116b9, 0x116b9,
+ 0x1173c, 0x1173e,
+ 0x1183b, 0x1183b,
+ 0x11944, 0x11946,
+ 0x119e2, 0x119e2,
+ 0x11a3f, 0x11a46,
+ 0x11a9a, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11b00, 0x11b09,
+ 0x11be1, 0x11be1,
+ 0x11c41, 0x11c45,
+ 0x11c70, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f4f,
+ 0x11fff, 0x11fff,
+ 0x12470, 0x12474,
+ 0x12ff1, 0x12ff2,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b3b,
+ 0x16b44, 0x16b44,
+ 0x16d6d, 0x16d6f,
+ 0x16e97, 0x16e9a,
+ 0x16fe2, 0x16fe2,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8b,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e95e, 0x1e95f,
+}; /* CR_XPosixPunct */
+
+/* 'Space': [[:Space:]] */
+static const OnigCodePoint CR_Space[] = {
+ 10,
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Space */
+
+/* 'Upper': [[:Upper:]] */
+static const OnigCodePoint CR_Upper[] = {
+ 660,
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x014a, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c4,
+ 0x01c7, 0x01c7,
+ 0x01ca, 0x01ca,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f1,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03cf, 0x03cf,
+ 0x03d2, 0x03d4,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f4, 0x03f4,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13a0, 0x13f5,
+ 0x1c89, 0x1c89,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 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,
+}; /* CR_Upper */
+
+/* 'XDigit': [[:XDigit:]] */
+static const OnigCodePoint CR_XDigit[] = {
+ 3,
+ 0x0030, 0x0039,
+ 0x0041, 0x0046,
+ 0x0061, 0x0066,
+}; /* CR_XDigit */
+
+/* 'Word': [[:Word:]] */
+static const OnigCodePoint CR_Word[] = {
+ 802,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x005f, 0x005f,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0300, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x0483, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0800, 0x082d,
+ 0x0840, 0x085b,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e4e,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f18, 0x0f19,
+ 0x0f20, 0x0f29,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x1000, 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,
+ 0x135d, 0x135f,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1734,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x180b, 0x180d,
+ 0x180f, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1946, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x1a00, 0x1a1b,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b59,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1bf3,
+ 0x1c00, 0x1c37,
+ 0x1c40, 0x1c49,
+ 0x1c4d, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1cfa,
+ 0x1d00, 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,
+ 0x200c, 0x200d,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20f0,
+ 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, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2dff,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3007,
+ 0x3021, 0x302f,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x3099, 0x309a,
+ 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, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa6f1,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa840, 0xa873,
+ 0xa880, 0xa8c5,
+ 0xa8d0, 0xa8d9,
+ 0xa8e0, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa92d,
+ 0xa930, 0xa953,
+ 0xa960, 0xa97c,
+ 0xa980, 0xa9c0,
+ 0xa9cf, 0xa9d9,
+ 0xa9e0, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaef,
+ 0xaaf2, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabea,
+ 0xabec, 0xabed,
+ 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,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff10, 0xff19,
+ 0xff21, 0xff3a,
+ 0xff3f, 0xff3f,
+ 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,
+ 0x101fd, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102e0,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae6,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f50,
+ 0x10f70, 0x10f85,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11046,
+ 0x11066, 0x11075,
+ 0x1107f, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x1113f,
+ 0x11144, 0x11147,
+ 0x11150, 0x11173,
+ 0x11176, 0x11176,
+ 0x11180, 0x111c4,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x11237,
+ 0x1123e, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1144a,
+ 0x11450, 0x11459,
+ 0x1145e, 0x11461,
+ 0x11480, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115d8, 0x115dd,
+ 0x11600, 0x11640,
+ 0x11644, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11739,
+ 0x11740, 0x11746,
+ 0x11800, 0x1183a,
+ 0x118a0, 0x118e9,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11943,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e1,
+ 0x119e3, 0x119e4,
+ 0x11a00, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a50, 0x11a99,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c40,
+ 0x11c50, 0x11c59,
+ 0x11c72, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f50, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13440, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af4,
+ 0x16b00, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9d, 0x1bc9e,
+ 0x1ccf0, 0x1ccf9,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 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,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e900, 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, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0100, 0xe01ef,
+}; /* CR_Word */
+
+/* 'Alnum': [[:Alnum:]] */
+static const OnigCodePoint CR_Alnum[] = {
+ 807,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0345, 0x0345,
+ 0x0363, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05b0, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0657,
+ 0x0659, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06e1, 0x06e8,
+ 0x06ed, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x073f,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0817,
+ 0x081a, 0x082c,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x0897,
+ 0x08a0, 0x08c9,
+ 0x08d4, 0x08df,
+ 0x08e3, 0x08e9,
+ 0x08f0, 0x093b,
+ 0x093d, 0x094c,
+ 0x094e, 0x0950,
+ 0x0955, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09ce, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4c,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0afc,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccc,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e46,
+ 0x0e4d, 0x0e4d,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ecd, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f20, 0x0f29,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f83,
+ 0x0f88, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 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, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 0x1dd3, 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, 0xa7dc,
+ 0xa7f1, 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 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,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d69,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10efc,
+ 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,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 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,
+ 0x116d0, 0x116e3,
+ 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,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 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,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f40,
+ 0x11f50, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1612e,
+ 0x16130, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1ccf0, 0x1ccf9,
+ 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,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 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, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Alnum */
+
+/* 'ASCII': [[:ASCII:]] */
+static const OnigCodePoint CR_ASCII[] = {
+ 1,
+ 0x0000, 0x007f,
+}; /* CR_ASCII */
+
+/* 'Punct': [[:Punct:]] */
+static const OnigCodePoint CR_Punct[] = {
+ 199,
+ 0x0021, 0x0023,
+ 0x0025, 0x002a,
+ 0x002c, 0x002f,
+ 0x003a, 0x003b,
+ 0x003f, 0x0040,
+ 0x005b, 0x005d,
+ 0x005f, 0x005f,
+ 0x007b, 0x007b,
+ 0x007d, 0x007d,
+ 0x00a1, 0x00a1,
+ 0x00a7, 0x00a7,
+ 0x00ab, 0x00ab,
+ 0x00b6, 0x00b7,
+ 0x00bb, 0x00bb,
+ 0x00bf, 0x00bf,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x055a, 0x055f,
+ 0x0589, 0x058a,
+ 0x05be, 0x05be,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05f3, 0x05f4,
+ 0x0609, 0x060a,
+ 0x060c, 0x060d,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x066a, 0x066d,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070d,
+ 0x07f7, 0x07f9,
+ 0x0830, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0970, 0x0970,
+ 0x09fd, 0x09fd,
+ 0x0a76, 0x0a76,
+ 0x0af0, 0x0af0,
+ 0x0c77, 0x0c77,
+ 0x0c84, 0x0c84,
+ 0x0df4, 0x0df4,
+ 0x0e4f, 0x0e4f,
+ 0x0e5a, 0x0e5b,
+ 0x0f04, 0x0f12,
+ 0x0f14, 0x0f14,
+ 0x0f3a, 0x0f3d,
+ 0x0f85, 0x0f85,
+ 0x0fd0, 0x0fd4,
+ 0x0fd9, 0x0fda,
+ 0x104a, 0x104f,
+ 0x10fb, 0x10fb,
+ 0x1360, 0x1368,
+ 0x1400, 0x1400,
+ 0x166e, 0x166e,
+ 0x169b, 0x169c,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17d8, 0x17da,
+ 0x1800, 0x180a,
+ 0x1944, 0x1945,
+ 0x1a1e, 0x1a1f,
+ 0x1aa0, 0x1aa6,
+ 0x1aa8, 0x1aad,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b60,
+ 0x1b7d, 0x1b7f,
+ 0x1bfc, 0x1bff,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x2010, 0x2027,
+ 0x2030, 0x2043,
+ 0x2045, 0x2051,
+ 0x2053, 0x205e,
+ 0x207d, 0x207e,
+ 0x208d, 0x208e,
+ 0x2308, 0x230b,
+ 0x2329, 0x232a,
+ 0x2768, 0x2775,
+ 0x27c5, 0x27c6,
+ 0x27e6, 0x27ef,
+ 0x2983, 0x2998,
+ 0x29d8, 0x29db,
+ 0x29fc, 0x29fd,
+ 0x2cf9, 0x2cfc,
+ 0x2cfe, 0x2cff,
+ 0x2d70, 0x2d70,
+ 0x2e00, 0x2e2e,
+ 0x2e30, 0x2e4f,
+ 0x2e52, 0x2e5d,
+ 0x3001, 0x3003,
+ 0x3008, 0x3011,
+ 0x3014, 0x301f,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x30a0, 0x30a0,
+ 0x30fb, 0x30fb,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa67e,
+ 0xa6f2, 0xa6f7,
+ 0xa874, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa8f8, 0xa8fa,
+ 0xa8fc, 0xa8fc,
+ 0xa92e, 0xa92f,
+ 0xa95f, 0xa95f,
+ 0xa9c1, 0xa9cd,
+ 0xa9de, 0xa9df,
+ 0xaa5c, 0xaa5f,
+ 0xaade, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfd3e, 0xfd3f,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe61,
+ 0xfe63, 0xfe63,
+ 0xfe68, 0xfe68,
+ 0xfe6a, 0xfe6b,
+ 0xff01, 0xff03,
+ 0xff05, 0xff0a,
+ 0xff0c, 0xff0f,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff20,
+ 0xff3b, 0xff3d,
+ 0xff3f, 0xff3f,
+ 0xff5b, 0xff5b,
+ 0xff5d, 0xff5d,
+ 0xff5f, 0xff65,
+ 0x10100, 0x10102,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x1056f, 0x1056f,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x1093f, 0x1093f,
+ 0x10a50, 0x10a58,
+ 0x10a7f, 0x10a7f,
+ 0x10af0, 0x10af6,
+ 0x10b39, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+ 0x10ed0, 0x10ed0,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x11140, 0x11143,
+ 0x11174, 0x11175,
+ 0x111c5, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111db, 0x111db,
+ 0x111dd, 0x111df,
+ 0x11238, 0x1123d,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x1144b, 0x1144f,
+ 0x1145a, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x114c6, 0x114c6,
+ 0x115c1, 0x115d7,
+ 0x11641, 0x11643,
+ 0x11660, 0x1166c,
+ 0x116b9, 0x116b9,
+ 0x1173c, 0x1173e,
+ 0x1183b, 0x1183b,
+ 0x11944, 0x11946,
+ 0x119e2, 0x119e2,
+ 0x11a3f, 0x11a46,
+ 0x11a9a, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11b00, 0x11b09,
+ 0x11be1, 0x11be1,
+ 0x11c41, 0x11c45,
+ 0x11c70, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f4f,
+ 0x11fff, 0x11fff,
+ 0x12470, 0x12474,
+ 0x12ff1, 0x12ff2,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b3b,
+ 0x16b44, 0x16b44,
+ 0x16d6d, 0x16d6f,
+ 0x16e97, 0x16e9a,
+ 0x16fe2, 0x16fe2,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8b,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e95e, 0x1e95f,
+}; /* CR_Punct */
+
+#ifdef USE_UNICODE_PROPERTIES
+/* 'Any': - */
+static const OnigCodePoint CR_Any[] = {
+ 1,
+ 0x0000, 0x10ffff,
+}; /* CR_Any */
+
+/* 'Assigned': - */
+static const OnigCodePoint CR_Assigned[] = {
+ 735,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Assigned */
+
+/* 'C': Major Category */
+static const OnigCodePoint CR_C[] = {
+ 741,
+ 0x0000, 0x001f,
+ 0x007f, 0x009f,
+ 0x00ad, 0x00ad,
+ 0x0378, 0x0379,
+ 0x0380, 0x0383,
+ 0x038b, 0x038b,
+ 0x038d, 0x038d,
+ 0x03a2, 0x03a2,
+ 0x0530, 0x0530,
+ 0x0557, 0x0558,
+ 0x058b, 0x058c,
+ 0x0590, 0x0590,
+ 0x05c8, 0x05cf,
+ 0x05eb, 0x05ee,
+ 0x05f5, 0x0605,
+ 0x061c, 0x061c,
+ 0x06dd, 0x06dd,
+ 0x070e, 0x070f,
+ 0x074b, 0x074c,
+ 0x07b2, 0x07bf,
+ 0x07fb, 0x07fc,
+ 0x082e, 0x082f,
+ 0x083f, 0x083f,
+ 0x085c, 0x085d,
+ 0x085f, 0x085f,
+ 0x086b, 0x086f,
+ 0x0890, 0x0896,
+ 0x08e2, 0x08e2,
+ 0x0984, 0x0984,
+ 0x098d, 0x098e,
+ 0x0991, 0x0992,
+ 0x09a9, 0x09a9,
+ 0x09b1, 0x09b1,
+ 0x09b3, 0x09b5,
+ 0x09ba, 0x09bb,
+ 0x09c5, 0x09c6,
+ 0x09c9, 0x09ca,
+ 0x09cf, 0x09d6,
+ 0x09d8, 0x09db,
+ 0x09de, 0x09de,
+ 0x09e4, 0x09e5,
+ 0x09ff, 0x0a00,
+ 0x0a04, 0x0a04,
+ 0x0a0b, 0x0a0e,
+ 0x0a11, 0x0a12,
+ 0x0a29, 0x0a29,
+ 0x0a31, 0x0a31,
+ 0x0a34, 0x0a34,
+ 0x0a37, 0x0a37,
+ 0x0a3a, 0x0a3b,
+ 0x0a3d, 0x0a3d,
+ 0x0a43, 0x0a46,
+ 0x0a49, 0x0a4a,
+ 0x0a4e, 0x0a50,
+ 0x0a52, 0x0a58,
+ 0x0a5d, 0x0a5d,
+ 0x0a5f, 0x0a65,
+ 0x0a77, 0x0a80,
+ 0x0a84, 0x0a84,
+ 0x0a8e, 0x0a8e,
+ 0x0a92, 0x0a92,
+ 0x0aa9, 0x0aa9,
+ 0x0ab1, 0x0ab1,
+ 0x0ab4, 0x0ab4,
+ 0x0aba, 0x0abb,
+ 0x0ac6, 0x0ac6,
+ 0x0aca, 0x0aca,
+ 0x0ace, 0x0acf,
+ 0x0ad1, 0x0adf,
+ 0x0ae4, 0x0ae5,
+ 0x0af2, 0x0af8,
+ 0x0b00, 0x0b00,
+ 0x0b04, 0x0b04,
+ 0x0b0d, 0x0b0e,
+ 0x0b11, 0x0b12,
+ 0x0b29, 0x0b29,
+ 0x0b31, 0x0b31,
+ 0x0b34, 0x0b34,
+ 0x0b3a, 0x0b3b,
+ 0x0b45, 0x0b46,
+ 0x0b49, 0x0b4a,
+ 0x0b4e, 0x0b54,
+ 0x0b58, 0x0b5b,
+ 0x0b5e, 0x0b5e,
+ 0x0b64, 0x0b65,
+ 0x0b78, 0x0b81,
+ 0x0b84, 0x0b84,
+ 0x0b8b, 0x0b8d,
+ 0x0b91, 0x0b91,
+ 0x0b96, 0x0b98,
+ 0x0b9b, 0x0b9b,
+ 0x0b9d, 0x0b9d,
+ 0x0ba0, 0x0ba2,
+ 0x0ba5, 0x0ba7,
+ 0x0bab, 0x0bad,
+ 0x0bba, 0x0bbd,
+ 0x0bc3, 0x0bc5,
+ 0x0bc9, 0x0bc9,
+ 0x0bce, 0x0bcf,
+ 0x0bd1, 0x0bd6,
+ 0x0bd8, 0x0be5,
+ 0x0bfb, 0x0bff,
+ 0x0c0d, 0x0c0d,
+ 0x0c11, 0x0c11,
+ 0x0c29, 0x0c29,
+ 0x0c3a, 0x0c3b,
+ 0x0c45, 0x0c45,
+ 0x0c49, 0x0c49,
+ 0x0c4e, 0x0c54,
+ 0x0c57, 0x0c57,
+ 0x0c5b, 0x0c5b,
+ 0x0c5e, 0x0c5f,
+ 0x0c64, 0x0c65,
+ 0x0c70, 0x0c76,
+ 0x0c8d, 0x0c8d,
+ 0x0c91, 0x0c91,
+ 0x0ca9, 0x0ca9,
+ 0x0cb4, 0x0cb4,
+ 0x0cba, 0x0cbb,
+ 0x0cc5, 0x0cc5,
+ 0x0cc9, 0x0cc9,
+ 0x0cce, 0x0cd4,
+ 0x0cd7, 0x0cdb,
+ 0x0cdf, 0x0cdf,
+ 0x0ce4, 0x0ce5,
+ 0x0cf0, 0x0cf0,
+ 0x0cf4, 0x0cff,
+ 0x0d0d, 0x0d0d,
+ 0x0d11, 0x0d11,
+ 0x0d45, 0x0d45,
+ 0x0d49, 0x0d49,
+ 0x0d50, 0x0d53,
+ 0x0d64, 0x0d65,
+ 0x0d80, 0x0d80,
+ 0x0d84, 0x0d84,
+ 0x0d97, 0x0d99,
+ 0x0db2, 0x0db2,
+ 0x0dbc, 0x0dbc,
+ 0x0dbe, 0x0dbf,
+ 0x0dc7, 0x0dc9,
+ 0x0dcb, 0x0dce,
+ 0x0dd5, 0x0dd5,
+ 0x0dd7, 0x0dd7,
+ 0x0de0, 0x0de5,
+ 0x0df0, 0x0df1,
+ 0x0df5, 0x0e00,
+ 0x0e3b, 0x0e3e,
+ 0x0e5c, 0x0e80,
+ 0x0e83, 0x0e83,
+ 0x0e85, 0x0e85,
+ 0x0e8b, 0x0e8b,
+ 0x0ea4, 0x0ea4,
+ 0x0ea6, 0x0ea6,
+ 0x0ebe, 0x0ebf,
+ 0x0ec5, 0x0ec5,
+ 0x0ec7, 0x0ec7,
+ 0x0ecf, 0x0ecf,
+ 0x0eda, 0x0edb,
+ 0x0ee0, 0x0eff,
+ 0x0f48, 0x0f48,
+ 0x0f6d, 0x0f70,
+ 0x0f98, 0x0f98,
+ 0x0fbd, 0x0fbd,
+ 0x0fcd, 0x0fcd,
+ 0x0fdb, 0x0fff,
+ 0x10c6, 0x10c6,
+ 0x10c8, 0x10cc,
+ 0x10ce, 0x10cf,
+ 0x1249, 0x1249,
+ 0x124e, 0x124f,
+ 0x1257, 0x1257,
+ 0x1259, 0x1259,
+ 0x125e, 0x125f,
+ 0x1289, 0x1289,
+ 0x128e, 0x128f,
+ 0x12b1, 0x12b1,
+ 0x12b6, 0x12b7,
+ 0x12bf, 0x12bf,
+ 0x12c1, 0x12c1,
+ 0x12c6, 0x12c7,
+ 0x12d7, 0x12d7,
+ 0x1311, 0x1311,
+ 0x1316, 0x1317,
+ 0x135b, 0x135c,
+ 0x137d, 0x137f,
+ 0x139a, 0x139f,
+ 0x13f6, 0x13f7,
+ 0x13fe, 0x13ff,
+ 0x169d, 0x169f,
+ 0x16f9, 0x16ff,
+ 0x1716, 0x171e,
+ 0x1737, 0x173f,
+ 0x1754, 0x175f,
+ 0x176d, 0x176d,
+ 0x1771, 0x1771,
+ 0x1774, 0x177f,
+ 0x17de, 0x17df,
+ 0x17ea, 0x17ef,
+ 0x17fa, 0x17ff,
+ 0x180e, 0x180e,
+ 0x181a, 0x181f,
+ 0x1879, 0x187f,
+ 0x18ab, 0x18af,
+ 0x18f6, 0x18ff,
+ 0x191f, 0x191f,
+ 0x192c, 0x192f,
+ 0x193c, 0x193f,
+ 0x1941, 0x1943,
+ 0x196e, 0x196f,
+ 0x1975, 0x197f,
+ 0x19ac, 0x19af,
+ 0x19ca, 0x19cf,
+ 0x19db, 0x19dd,
+ 0x1a1c, 0x1a1d,
+ 0x1a5f, 0x1a5f,
+ 0x1a7d, 0x1a7e,
+ 0x1a8a, 0x1a8f,
+ 0x1a9a, 0x1a9f,
+ 0x1aae, 0x1aaf,
+ 0x1ade, 0x1adf,
+ 0x1aec, 0x1aff,
+ 0x1b4d, 0x1b4d,
+ 0x1bf4, 0x1bfb,
+ 0x1c38, 0x1c3a,
+ 0x1c4a, 0x1c4c,
+ 0x1c8b, 0x1c8f,
+ 0x1cbb, 0x1cbc,
+ 0x1cc8, 0x1ccf,
+ 0x1cfb, 0x1cff,
+ 0x1f16, 0x1f17,
+ 0x1f1e, 0x1f1f,
+ 0x1f46, 0x1f47,
+ 0x1f4e, 0x1f4f,
+ 0x1f58, 0x1f58,
+ 0x1f5a, 0x1f5a,
+ 0x1f5c, 0x1f5c,
+ 0x1f5e, 0x1f5e,
+ 0x1f7e, 0x1f7f,
+ 0x1fb5, 0x1fb5,
+ 0x1fc5, 0x1fc5,
+ 0x1fd4, 0x1fd5,
+ 0x1fdc, 0x1fdc,
+ 0x1ff0, 0x1ff1,
+ 0x1ff5, 0x1ff5,
+ 0x1fff, 0x1fff,
+ 0x200b, 0x200f,
+ 0x202a, 0x202e,
+ 0x2060, 0x206f,
+ 0x2072, 0x2073,
+ 0x208f, 0x208f,
+ 0x209d, 0x209f,
+ 0x20c2, 0x20cf,
+ 0x20f1, 0x20ff,
+ 0x218c, 0x218f,
+ 0x242a, 0x243f,
+ 0x244b, 0x245f,
+ 0x2b74, 0x2b75,
+ 0x2cf4, 0x2cf8,
+ 0x2d26, 0x2d26,
+ 0x2d28, 0x2d2c,
+ 0x2d2e, 0x2d2f,
+ 0x2d68, 0x2d6e,
+ 0x2d71, 0x2d7e,
+ 0x2d97, 0x2d9f,
+ 0x2da7, 0x2da7,
+ 0x2daf, 0x2daf,
+ 0x2db7, 0x2db7,
+ 0x2dbf, 0x2dbf,
+ 0x2dc7, 0x2dc7,
+ 0x2dcf, 0x2dcf,
+ 0x2dd7, 0x2dd7,
+ 0x2ddf, 0x2ddf,
+ 0x2e5e, 0x2e7f,
+ 0x2e9a, 0x2e9a,
+ 0x2ef4, 0x2eff,
+ 0x2fd6, 0x2fef,
+ 0x3040, 0x3040,
+ 0x3097, 0x3098,
+ 0x3100, 0x3104,
+ 0x3130, 0x3130,
+ 0x318f, 0x318f,
+ 0x31e6, 0x31ee,
+ 0x321f, 0x321f,
+ 0xa48d, 0xa48f,
+ 0xa4c7, 0xa4cf,
+ 0xa62c, 0xa63f,
+ 0xa6f8, 0xa6ff,
+ 0xa7dd, 0xa7f0,
+ 0xa82d, 0xa82f,
+ 0xa83a, 0xa83f,
+ 0xa878, 0xa87f,
+ 0xa8c6, 0xa8cd,
+ 0xa8da, 0xa8df,
+ 0xa954, 0xa95e,
+ 0xa97d, 0xa97f,
+ 0xa9ce, 0xa9ce,
+ 0xa9da, 0xa9dd,
+ 0xa9ff, 0xa9ff,
+ 0xaa37, 0xaa3f,
+ 0xaa4e, 0xaa4f,
+ 0xaa5a, 0xaa5b,
+ 0xaac3, 0xaada,
+ 0xaaf7, 0xab00,
+ 0xab07, 0xab08,
+ 0xab0f, 0xab10,
+ 0xab17, 0xab1f,
+ 0xab27, 0xab27,
+ 0xab2f, 0xab2f,
+ 0xab6c, 0xab6f,
+ 0xabee, 0xabef,
+ 0xabfa, 0xabff,
+ 0xd7a4, 0xd7af,
+ 0xd7c7, 0xd7ca,
+ 0xd7fc, 0xf8ff,
+ 0xfa6e, 0xfa6f,
+ 0xfada, 0xfaff,
+ 0xfb07, 0xfb12,
+ 0xfb18, 0xfb1c,
+ 0xfb37, 0xfb37,
+ 0xfb3d, 0xfb3d,
+ 0xfb3f, 0xfb3f,
+ 0xfb42, 0xfb42,
+ 0xfb45, 0xfb45,
+ 0xfdd0, 0xfdef,
+ 0xfe1a, 0xfe1f,
+ 0xfe53, 0xfe53,
+ 0xfe67, 0xfe67,
+ 0xfe6c, 0xfe6f,
+ 0xfe75, 0xfe75,
+ 0xfefd, 0xff00,
+ 0xffbf, 0xffc1,
+ 0xffc8, 0xffc9,
+ 0xffd0, 0xffd1,
+ 0xffd8, 0xffd9,
+ 0xffdd, 0xffdf,
+ 0xffe7, 0xffe7,
+ 0xffef, 0xfffb,
+ 0xfffe, 0xffff,
+ 0x1000c, 0x1000c,
+ 0x10027, 0x10027,
+ 0x1003b, 0x1003b,
+ 0x1003e, 0x1003e,
+ 0x1004e, 0x1004f,
+ 0x1005e, 0x1007f,
+ 0x100fb, 0x100ff,
+ 0x10103, 0x10106,
+ 0x10134, 0x10136,
+ 0x1018f, 0x1018f,
+ 0x1019d, 0x1019f,
+ 0x101a1, 0x101cf,
+ 0x101fe, 0x1027f,
+ 0x1029d, 0x1029f,
+ 0x102d1, 0x102df,
+ 0x102fc, 0x102ff,
+ 0x10324, 0x1032c,
+ 0x1034b, 0x1034f,
+ 0x1037b, 0x1037f,
+ 0x1039e, 0x1039e,
+ 0x103c4, 0x103c7,
+ 0x103d6, 0x103ff,
+ 0x1049e, 0x1049f,
+ 0x104aa, 0x104af,
+ 0x104d4, 0x104d7,
+ 0x104fc, 0x104ff,
+ 0x10528, 0x1052f,
+ 0x10564, 0x1056e,
+ 0x1057b, 0x1057b,
+ 0x1058b, 0x1058b,
+ 0x10593, 0x10593,
+ 0x10596, 0x10596,
+ 0x105a2, 0x105a2,
+ 0x105b2, 0x105b2,
+ 0x105ba, 0x105ba,
+ 0x105bd, 0x105bf,
+ 0x105f4, 0x105ff,
+ 0x10737, 0x1073f,
+ 0x10756, 0x1075f,
+ 0x10768, 0x1077f,
+ 0x10786, 0x10786,
+ 0x107b1, 0x107b1,
+ 0x107bb, 0x107ff,
+ 0x10806, 0x10807,
+ 0x10809, 0x10809,
+ 0x10836, 0x10836,
+ 0x10839, 0x1083b,
+ 0x1083d, 0x1083e,
+ 0x10856, 0x10856,
+ 0x1089f, 0x108a6,
+ 0x108b0, 0x108df,
+ 0x108f3, 0x108f3,
+ 0x108f6, 0x108fa,
+ 0x1091c, 0x1091e,
+ 0x1093a, 0x1093e,
+ 0x1095a, 0x1097f,
+ 0x109b8, 0x109bb,
+ 0x109d0, 0x109d1,
+ 0x10a04, 0x10a04,
+ 0x10a07, 0x10a0b,
+ 0x10a14, 0x10a14,
+ 0x10a18, 0x10a18,
+ 0x10a36, 0x10a37,
+ 0x10a3b, 0x10a3e,
+ 0x10a49, 0x10a4f,
+ 0x10a59, 0x10a5f,
+ 0x10aa0, 0x10abf,
+ 0x10ae7, 0x10aea,
+ 0x10af7, 0x10aff,
+ 0x10b36, 0x10b38,
+ 0x10b56, 0x10b57,
+ 0x10b73, 0x10b77,
+ 0x10b92, 0x10b98,
+ 0x10b9d, 0x10ba8,
+ 0x10bb0, 0x10bff,
+ 0x10c49, 0x10c7f,
+ 0x10cb3, 0x10cbf,
+ 0x10cf3, 0x10cf9,
+ 0x10d28, 0x10d2f,
+ 0x10d3a, 0x10d3f,
+ 0x10d66, 0x10d68,
+ 0x10d86, 0x10d8d,
+ 0x10d90, 0x10e5f,
+ 0x10e7f, 0x10e7f,
+ 0x10eaa, 0x10eaa,
+ 0x10eae, 0x10eaf,
+ 0x10eb2, 0x10ec1,
+ 0x10ec8, 0x10ecf,
+ 0x10ed9, 0x10ef9,
+ 0x10f28, 0x10f2f,
+ 0x10f5a, 0x10f6f,
+ 0x10f8a, 0x10faf,
+ 0x10fcc, 0x10fdf,
+ 0x10ff7, 0x10fff,
+ 0x1104e, 0x11051,
+ 0x11076, 0x1107e,
+ 0x110bd, 0x110bd,
+ 0x110c3, 0x110cf,
+ 0x110e9, 0x110ef,
+ 0x110fa, 0x110ff,
+ 0x11135, 0x11135,
+ 0x11148, 0x1114f,
+ 0x11177, 0x1117f,
+ 0x111e0, 0x111e0,
+ 0x111f5, 0x111ff,
+ 0x11212, 0x11212,
+ 0x11242, 0x1127f,
+ 0x11287, 0x11287,
+ 0x11289, 0x11289,
+ 0x1128e, 0x1128e,
+ 0x1129e, 0x1129e,
+ 0x112aa, 0x112af,
+ 0x112eb, 0x112ef,
+ 0x112fa, 0x112ff,
+ 0x11304, 0x11304,
+ 0x1130d, 0x1130e,
+ 0x11311, 0x11312,
+ 0x11329, 0x11329,
+ 0x11331, 0x11331,
+ 0x11334, 0x11334,
+ 0x1133a, 0x1133a,
+ 0x11345, 0x11346,
+ 0x11349, 0x1134a,
+ 0x1134e, 0x1134f,
+ 0x11351, 0x11356,
+ 0x11358, 0x1135c,
+ 0x11364, 0x11365,
+ 0x1136d, 0x1136f,
+ 0x11375, 0x1137f,
+ 0x1138a, 0x1138a,
+ 0x1138c, 0x1138d,
+ 0x1138f, 0x1138f,
+ 0x113b6, 0x113b6,
+ 0x113c1, 0x113c1,
+ 0x113c3, 0x113c4,
+ 0x113c6, 0x113c6,
+ 0x113cb, 0x113cb,
+ 0x113d6, 0x113d6,
+ 0x113d9, 0x113e0,
+ 0x113e3, 0x113ff,
+ 0x1145c, 0x1145c,
+ 0x11462, 0x1147f,
+ 0x114c8, 0x114cf,
+ 0x114da, 0x1157f,
+ 0x115b6, 0x115b7,
+ 0x115de, 0x115ff,
+ 0x11645, 0x1164f,
+ 0x1165a, 0x1165f,
+ 0x1166d, 0x1167f,
+ 0x116ba, 0x116bf,
+ 0x116ca, 0x116cf,
+ 0x116e4, 0x116ff,
+ 0x1171b, 0x1171c,
+ 0x1172c, 0x1172f,
+ 0x11747, 0x117ff,
+ 0x1183c, 0x1189f,
+ 0x118f3, 0x118fe,
+ 0x11907, 0x11908,
+ 0x1190a, 0x1190b,
+ 0x11914, 0x11914,
+ 0x11917, 0x11917,
+ 0x11936, 0x11936,
+ 0x11939, 0x1193a,
+ 0x11947, 0x1194f,
+ 0x1195a, 0x1199f,
+ 0x119a8, 0x119a9,
+ 0x119d8, 0x119d9,
+ 0x119e5, 0x119ff,
+ 0x11a48, 0x11a4f,
+ 0x11aa3, 0x11aaf,
+ 0x11af9, 0x11aff,
+ 0x11b0a, 0x11b5f,
+ 0x11b68, 0x11bbf,
+ 0x11be2, 0x11bef,
+ 0x11bfa, 0x11bff,
+ 0x11c09, 0x11c09,
+ 0x11c37, 0x11c37,
+ 0x11c46, 0x11c4f,
+ 0x11c6d, 0x11c6f,
+ 0x11c90, 0x11c91,
+ 0x11ca8, 0x11ca8,
+ 0x11cb7, 0x11cff,
+ 0x11d07, 0x11d07,
+ 0x11d0a, 0x11d0a,
+ 0x11d37, 0x11d39,
+ 0x11d3b, 0x11d3b,
+ 0x11d3e, 0x11d3e,
+ 0x11d48, 0x11d4f,
+ 0x11d5a, 0x11d5f,
+ 0x11d66, 0x11d66,
+ 0x11d69, 0x11d69,
+ 0x11d8f, 0x11d8f,
+ 0x11d92, 0x11d92,
+ 0x11d99, 0x11d9f,
+ 0x11daa, 0x11daf,
+ 0x11ddc, 0x11ddf,
+ 0x11dea, 0x11edf,
+ 0x11ef9, 0x11eff,
+ 0x11f11, 0x11f11,
+ 0x11f3b, 0x11f3d,
+ 0x11f5b, 0x11faf,
+ 0x11fb1, 0x11fbf,
+ 0x11ff2, 0x11ffe,
+ 0x1239a, 0x123ff,
+ 0x1246f, 0x1246f,
+ 0x12475, 0x1247f,
+ 0x12544, 0x12f8f,
+ 0x12ff3, 0x12fff,
+ 0x13430, 0x1343f,
+ 0x13456, 0x1345f,
+ 0x143fb, 0x143ff,
+ 0x14647, 0x160ff,
+ 0x1613a, 0x167ff,
+ 0x16a39, 0x16a3f,
+ 0x16a5f, 0x16a5f,
+ 0x16a6a, 0x16a6d,
+ 0x16abf, 0x16abf,
+ 0x16aca, 0x16acf,
+ 0x16aee, 0x16aef,
+ 0x16af6, 0x16aff,
+ 0x16b46, 0x16b4f,
+ 0x16b5a, 0x16b5a,
+ 0x16b62, 0x16b62,
+ 0x16b78, 0x16b7c,
+ 0x16b90, 0x16d3f,
+ 0x16d7a, 0x16e3f,
+ 0x16e9b, 0x16e9f,
+ 0x16eb9, 0x16eba,
+ 0x16ed4, 0x16eff,
+ 0x16f4b, 0x16f4e,
+ 0x16f88, 0x16f8e,
+ 0x16fa0, 0x16fdf,
+ 0x16fe5, 0x16fef,
+ 0x16ff7, 0x16fff,
+ 0x18cd6, 0x18cfe,
+ 0x18d1f, 0x18d7f,
+ 0x18df3, 0x1afef,
+ 0x1aff4, 0x1aff4,
+ 0x1affc, 0x1affc,
+ 0x1afff, 0x1afff,
+ 0x1b123, 0x1b131,
+ 0x1b133, 0x1b14f,
+ 0x1b153, 0x1b154,
+ 0x1b156, 0x1b163,
+ 0x1b168, 0x1b16f,
+ 0x1b2fc, 0x1bbff,
+ 0x1bc6b, 0x1bc6f,
+ 0x1bc7d, 0x1bc7f,
+ 0x1bc89, 0x1bc8f,
+ 0x1bc9a, 0x1bc9b,
+ 0x1bca0, 0x1cbff,
+ 0x1ccfd, 0x1ccff,
+ 0x1ceb4, 0x1ceb9,
+ 0x1ced1, 0x1cedf,
+ 0x1cef1, 0x1ceff,
+ 0x1cf2e, 0x1cf2f,
+ 0x1cf47, 0x1cf4f,
+ 0x1cfc4, 0x1cfff,
+ 0x1d0f6, 0x1d0ff,
+ 0x1d127, 0x1d128,
+ 0x1d173, 0x1d17a,
+ 0x1d1eb, 0x1d1ff,
+ 0x1d246, 0x1d2bf,
+ 0x1d2d4, 0x1d2df,
+ 0x1d2f4, 0x1d2ff,
+ 0x1d357, 0x1d35f,
+ 0x1d379, 0x1d3ff,
+ 0x1d455, 0x1d455,
+ 0x1d49d, 0x1d49d,
+ 0x1d4a0, 0x1d4a1,
+ 0x1d4a3, 0x1d4a4,
+ 0x1d4a7, 0x1d4a8,
+ 0x1d4ad, 0x1d4ad,
+ 0x1d4ba, 0x1d4ba,
+ 0x1d4bc, 0x1d4bc,
+ 0x1d4c4, 0x1d4c4,
+ 0x1d506, 0x1d506,
+ 0x1d50b, 0x1d50c,
+ 0x1d515, 0x1d515,
+ 0x1d51d, 0x1d51d,
+ 0x1d53a, 0x1d53a,
+ 0x1d53f, 0x1d53f,
+ 0x1d545, 0x1d545,
+ 0x1d547, 0x1d549,
+ 0x1d551, 0x1d551,
+ 0x1d6a6, 0x1d6a7,
+ 0x1d7cc, 0x1d7cd,
+ 0x1da8c, 0x1da9a,
+ 0x1daa0, 0x1daa0,
+ 0x1dab0, 0x1deff,
+ 0x1df1f, 0x1df24,
+ 0x1df2b, 0x1dfff,
+ 0x1e007, 0x1e007,
+ 0x1e019, 0x1e01a,
+ 0x1e022, 0x1e022,
+ 0x1e025, 0x1e025,
+ 0x1e02b, 0x1e02f,
+ 0x1e06e, 0x1e08e,
+ 0x1e090, 0x1e0ff,
+ 0x1e12d, 0x1e12f,
+ 0x1e13e, 0x1e13f,
+ 0x1e14a, 0x1e14d,
+ 0x1e150, 0x1e28f,
+ 0x1e2af, 0x1e2bf,
+ 0x1e2fa, 0x1e2fe,
+ 0x1e300, 0x1e4cf,
+ 0x1e4fa, 0x1e5cf,
+ 0x1e5fb, 0x1e5fe,
+ 0x1e600, 0x1e6bf,
+ 0x1e6df, 0x1e6df,
+ 0x1e6f6, 0x1e6fd,
+ 0x1e700, 0x1e7df,
+ 0x1e7e7, 0x1e7e7,
+ 0x1e7ec, 0x1e7ec,
+ 0x1e7ef, 0x1e7ef,
+ 0x1e7ff, 0x1e7ff,
+ 0x1e8c5, 0x1e8c6,
+ 0x1e8d7, 0x1e8ff,
+ 0x1e94c, 0x1e94f,
+ 0x1e95a, 0x1e95d,
+ 0x1e960, 0x1ec70,
+ 0x1ecb5, 0x1ed00,
+ 0x1ed3e, 0x1edff,
+ 0x1ee04, 0x1ee04,
+ 0x1ee20, 0x1ee20,
+ 0x1ee23, 0x1ee23,
+ 0x1ee25, 0x1ee26,
+ 0x1ee28, 0x1ee28,
+ 0x1ee33, 0x1ee33,
+ 0x1ee38, 0x1ee38,
+ 0x1ee3a, 0x1ee3a,
+ 0x1ee3c, 0x1ee41,
+ 0x1ee43, 0x1ee46,
+ 0x1ee48, 0x1ee48,
+ 0x1ee4a, 0x1ee4a,
+ 0x1ee4c, 0x1ee4c,
+ 0x1ee50, 0x1ee50,
+ 0x1ee53, 0x1ee53,
+ 0x1ee55, 0x1ee56,
+ 0x1ee58, 0x1ee58,
+ 0x1ee5a, 0x1ee5a,
+ 0x1ee5c, 0x1ee5c,
+ 0x1ee5e, 0x1ee5e,
+ 0x1ee60, 0x1ee60,
+ 0x1ee63, 0x1ee63,
+ 0x1ee65, 0x1ee66,
+ 0x1ee6b, 0x1ee6b,
+ 0x1ee73, 0x1ee73,
+ 0x1ee78, 0x1ee78,
+ 0x1ee7d, 0x1ee7d,
+ 0x1ee7f, 0x1ee7f,
+ 0x1ee8a, 0x1ee8a,
+ 0x1ee9c, 0x1eea0,
+ 0x1eea4, 0x1eea4,
+ 0x1eeaa, 0x1eeaa,
+ 0x1eebc, 0x1eeef,
+ 0x1eef2, 0x1efff,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0d0, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f203, 0x1f20f,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f24f,
+ 0x1f252, 0x1f25f,
+ 0x1f266, 0x1f2ff,
+ 0x1f6d9, 0x1f6db,
+ 0x1f6ed, 0x1f6ef,
+ 0x1f6fd, 0x1f6ff,
+ 0x1f7da, 0x1f7df,
+ 0x1f7ec, 0x1f7ef,
+ 0x1f7f1, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1fa6f,
+ 0x1fa7d, 0x1fa7f,
+ 0x1fa8b, 0x1fa8d,
+ 0x1fac7, 0x1fac7,
+ 0x1fac9, 0x1facc,
+ 0x1fadd, 0x1fade,
+ 0x1faeb, 0x1faee,
+ 0x1faf9, 0x1faff,
+ 0x1fb93, 0x1fb93,
+ 0x1fbfb, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2b81e, 0x2b81f,
+ 0x2ceae, 0x2ceaf,
+ 0x2ebe1, 0x2ebef,
+ 0x2ee5e, 0x2f7ff,
+ 0x2fa1e, 0x2ffff,
+ 0x3134b, 0x3134f,
+ 0x3347a, 0xe00ff,
+ 0xe01f0, 0x10ffff,
+}; /* CR_C */
+
+/* 'Cc': General Category */
+#define CR_Cc CR_Cntrl
+
+/* 'Cf': General Category */
+static const OnigCodePoint CR_Cf[] = {
+ 21,
+ 0x00ad, 0x00ad,
+ 0x0600, 0x0605,
+ 0x061c, 0x061c,
+ 0x06dd, 0x06dd,
+ 0x070f, 0x070f,
+ 0x0890, 0x0891,
+ 0x08e2, 0x08e2,
+ 0x180e, 0x180e,
+ 0x200b, 0x200f,
+ 0x202a, 0x202e,
+ 0x2060, 0x2064,
+ 0x2066, 0x206f,
+ 0xfeff, 0xfeff,
+ 0xfff9, 0xfffb,
+ 0x110bd, 0x110bd,
+ 0x110cd, 0x110cd,
+ 0x13430, 0x1343f,
+ 0x1bca0, 0x1bca3,
+ 0x1d173, 0x1d17a,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+}; /* CR_Cf */
+
+/* 'Cn': General Category */
+static const OnigCodePoint CR_Cn[] = {
+ 735,
+ 0x0378, 0x0379,
+ 0x0380, 0x0383,
+ 0x038b, 0x038b,
+ 0x038d, 0x038d,
+ 0x03a2, 0x03a2,
+ 0x0530, 0x0530,
+ 0x0557, 0x0558,
+ 0x058b, 0x058c,
+ 0x0590, 0x0590,
+ 0x05c8, 0x05cf,
+ 0x05eb, 0x05ee,
+ 0x05f5, 0x05ff,
+ 0x070e, 0x070e,
+ 0x074b, 0x074c,
+ 0x07b2, 0x07bf,
+ 0x07fb, 0x07fc,
+ 0x082e, 0x082f,
+ 0x083f, 0x083f,
+ 0x085c, 0x085d,
+ 0x085f, 0x085f,
+ 0x086b, 0x086f,
+ 0x0892, 0x0896,
+ 0x0984, 0x0984,
+ 0x098d, 0x098e,
+ 0x0991, 0x0992,
+ 0x09a9, 0x09a9,
+ 0x09b1, 0x09b1,
+ 0x09b3, 0x09b5,
+ 0x09ba, 0x09bb,
+ 0x09c5, 0x09c6,
+ 0x09c9, 0x09ca,
+ 0x09cf, 0x09d6,
+ 0x09d8, 0x09db,
+ 0x09de, 0x09de,
+ 0x09e4, 0x09e5,
+ 0x09ff, 0x0a00,
+ 0x0a04, 0x0a04,
+ 0x0a0b, 0x0a0e,
+ 0x0a11, 0x0a12,
+ 0x0a29, 0x0a29,
+ 0x0a31, 0x0a31,
+ 0x0a34, 0x0a34,
+ 0x0a37, 0x0a37,
+ 0x0a3a, 0x0a3b,
+ 0x0a3d, 0x0a3d,
+ 0x0a43, 0x0a46,
+ 0x0a49, 0x0a4a,
+ 0x0a4e, 0x0a50,
+ 0x0a52, 0x0a58,
+ 0x0a5d, 0x0a5d,
+ 0x0a5f, 0x0a65,
+ 0x0a77, 0x0a80,
+ 0x0a84, 0x0a84,
+ 0x0a8e, 0x0a8e,
+ 0x0a92, 0x0a92,
+ 0x0aa9, 0x0aa9,
+ 0x0ab1, 0x0ab1,
+ 0x0ab4, 0x0ab4,
+ 0x0aba, 0x0abb,
+ 0x0ac6, 0x0ac6,
+ 0x0aca, 0x0aca,
+ 0x0ace, 0x0acf,
+ 0x0ad1, 0x0adf,
+ 0x0ae4, 0x0ae5,
+ 0x0af2, 0x0af8,
+ 0x0b00, 0x0b00,
+ 0x0b04, 0x0b04,
+ 0x0b0d, 0x0b0e,
+ 0x0b11, 0x0b12,
+ 0x0b29, 0x0b29,
+ 0x0b31, 0x0b31,
+ 0x0b34, 0x0b34,
+ 0x0b3a, 0x0b3b,
+ 0x0b45, 0x0b46,
+ 0x0b49, 0x0b4a,
+ 0x0b4e, 0x0b54,
+ 0x0b58, 0x0b5b,
+ 0x0b5e, 0x0b5e,
+ 0x0b64, 0x0b65,
+ 0x0b78, 0x0b81,
+ 0x0b84, 0x0b84,
+ 0x0b8b, 0x0b8d,
+ 0x0b91, 0x0b91,
+ 0x0b96, 0x0b98,
+ 0x0b9b, 0x0b9b,
+ 0x0b9d, 0x0b9d,
+ 0x0ba0, 0x0ba2,
+ 0x0ba5, 0x0ba7,
+ 0x0bab, 0x0bad,
+ 0x0bba, 0x0bbd,
+ 0x0bc3, 0x0bc5,
+ 0x0bc9, 0x0bc9,
+ 0x0bce, 0x0bcf,
+ 0x0bd1, 0x0bd6,
+ 0x0bd8, 0x0be5,
+ 0x0bfb, 0x0bff,
+ 0x0c0d, 0x0c0d,
+ 0x0c11, 0x0c11,
+ 0x0c29, 0x0c29,
+ 0x0c3a, 0x0c3b,
+ 0x0c45, 0x0c45,
+ 0x0c49, 0x0c49,
+ 0x0c4e, 0x0c54,
+ 0x0c57, 0x0c57,
+ 0x0c5b, 0x0c5b,
+ 0x0c5e, 0x0c5f,
+ 0x0c64, 0x0c65,
+ 0x0c70, 0x0c76,
+ 0x0c8d, 0x0c8d,
+ 0x0c91, 0x0c91,
+ 0x0ca9, 0x0ca9,
+ 0x0cb4, 0x0cb4,
+ 0x0cba, 0x0cbb,
+ 0x0cc5, 0x0cc5,
+ 0x0cc9, 0x0cc9,
+ 0x0cce, 0x0cd4,
+ 0x0cd7, 0x0cdb,
+ 0x0cdf, 0x0cdf,
+ 0x0ce4, 0x0ce5,
+ 0x0cf0, 0x0cf0,
+ 0x0cf4, 0x0cff,
+ 0x0d0d, 0x0d0d,
+ 0x0d11, 0x0d11,
+ 0x0d45, 0x0d45,
+ 0x0d49, 0x0d49,
+ 0x0d50, 0x0d53,
+ 0x0d64, 0x0d65,
+ 0x0d80, 0x0d80,
+ 0x0d84, 0x0d84,
+ 0x0d97, 0x0d99,
+ 0x0db2, 0x0db2,
+ 0x0dbc, 0x0dbc,
+ 0x0dbe, 0x0dbf,
+ 0x0dc7, 0x0dc9,
+ 0x0dcb, 0x0dce,
+ 0x0dd5, 0x0dd5,
+ 0x0dd7, 0x0dd7,
+ 0x0de0, 0x0de5,
+ 0x0df0, 0x0df1,
+ 0x0df5, 0x0e00,
+ 0x0e3b, 0x0e3e,
+ 0x0e5c, 0x0e80,
+ 0x0e83, 0x0e83,
+ 0x0e85, 0x0e85,
+ 0x0e8b, 0x0e8b,
+ 0x0ea4, 0x0ea4,
+ 0x0ea6, 0x0ea6,
+ 0x0ebe, 0x0ebf,
+ 0x0ec5, 0x0ec5,
+ 0x0ec7, 0x0ec7,
+ 0x0ecf, 0x0ecf,
+ 0x0eda, 0x0edb,
+ 0x0ee0, 0x0eff,
+ 0x0f48, 0x0f48,
+ 0x0f6d, 0x0f70,
+ 0x0f98, 0x0f98,
+ 0x0fbd, 0x0fbd,
+ 0x0fcd, 0x0fcd,
+ 0x0fdb, 0x0fff,
+ 0x10c6, 0x10c6,
+ 0x10c8, 0x10cc,
+ 0x10ce, 0x10cf,
+ 0x1249, 0x1249,
+ 0x124e, 0x124f,
+ 0x1257, 0x1257,
+ 0x1259, 0x1259,
+ 0x125e, 0x125f,
+ 0x1289, 0x1289,
+ 0x128e, 0x128f,
+ 0x12b1, 0x12b1,
+ 0x12b6, 0x12b7,
+ 0x12bf, 0x12bf,
+ 0x12c1, 0x12c1,
+ 0x12c6, 0x12c7,
+ 0x12d7, 0x12d7,
+ 0x1311, 0x1311,
+ 0x1316, 0x1317,
+ 0x135b, 0x135c,
+ 0x137d, 0x137f,
+ 0x139a, 0x139f,
+ 0x13f6, 0x13f7,
+ 0x13fe, 0x13ff,
+ 0x169d, 0x169f,
+ 0x16f9, 0x16ff,
+ 0x1716, 0x171e,
+ 0x1737, 0x173f,
+ 0x1754, 0x175f,
+ 0x176d, 0x176d,
+ 0x1771, 0x1771,
+ 0x1774, 0x177f,
+ 0x17de, 0x17df,
+ 0x17ea, 0x17ef,
+ 0x17fa, 0x17ff,
+ 0x181a, 0x181f,
+ 0x1879, 0x187f,
+ 0x18ab, 0x18af,
+ 0x18f6, 0x18ff,
+ 0x191f, 0x191f,
+ 0x192c, 0x192f,
+ 0x193c, 0x193f,
+ 0x1941, 0x1943,
+ 0x196e, 0x196f,
+ 0x1975, 0x197f,
+ 0x19ac, 0x19af,
+ 0x19ca, 0x19cf,
+ 0x19db, 0x19dd,
+ 0x1a1c, 0x1a1d,
+ 0x1a5f, 0x1a5f,
+ 0x1a7d, 0x1a7e,
+ 0x1a8a, 0x1a8f,
+ 0x1a9a, 0x1a9f,
+ 0x1aae, 0x1aaf,
+ 0x1ade, 0x1adf,
+ 0x1aec, 0x1aff,
+ 0x1b4d, 0x1b4d,
+ 0x1bf4, 0x1bfb,
+ 0x1c38, 0x1c3a,
+ 0x1c4a, 0x1c4c,
+ 0x1c8b, 0x1c8f,
+ 0x1cbb, 0x1cbc,
+ 0x1cc8, 0x1ccf,
+ 0x1cfb, 0x1cff,
+ 0x1f16, 0x1f17,
+ 0x1f1e, 0x1f1f,
+ 0x1f46, 0x1f47,
+ 0x1f4e, 0x1f4f,
+ 0x1f58, 0x1f58,
+ 0x1f5a, 0x1f5a,
+ 0x1f5c, 0x1f5c,
+ 0x1f5e, 0x1f5e,
+ 0x1f7e, 0x1f7f,
+ 0x1fb5, 0x1fb5,
+ 0x1fc5, 0x1fc5,
+ 0x1fd4, 0x1fd5,
+ 0x1fdc, 0x1fdc,
+ 0x1ff0, 0x1ff1,
+ 0x1ff5, 0x1ff5,
+ 0x1fff, 0x1fff,
+ 0x2065, 0x2065,
+ 0x2072, 0x2073,
+ 0x208f, 0x208f,
+ 0x209d, 0x209f,
+ 0x20c2, 0x20cf,
+ 0x20f1, 0x20ff,
+ 0x218c, 0x218f,
+ 0x242a, 0x243f,
+ 0x244b, 0x245f,
+ 0x2b74, 0x2b75,
+ 0x2cf4, 0x2cf8,
+ 0x2d26, 0x2d26,
+ 0x2d28, 0x2d2c,
+ 0x2d2e, 0x2d2f,
+ 0x2d68, 0x2d6e,
+ 0x2d71, 0x2d7e,
+ 0x2d97, 0x2d9f,
+ 0x2da7, 0x2da7,
+ 0x2daf, 0x2daf,
+ 0x2db7, 0x2db7,
+ 0x2dbf, 0x2dbf,
+ 0x2dc7, 0x2dc7,
+ 0x2dcf, 0x2dcf,
+ 0x2dd7, 0x2dd7,
+ 0x2ddf, 0x2ddf,
+ 0x2e5e, 0x2e7f,
+ 0x2e9a, 0x2e9a,
+ 0x2ef4, 0x2eff,
+ 0x2fd6, 0x2fef,
+ 0x3040, 0x3040,
+ 0x3097, 0x3098,
+ 0x3100, 0x3104,
+ 0x3130, 0x3130,
+ 0x318f, 0x318f,
+ 0x31e6, 0x31ee,
+ 0x321f, 0x321f,
+ 0xa48d, 0xa48f,
+ 0xa4c7, 0xa4cf,
+ 0xa62c, 0xa63f,
+ 0xa6f8, 0xa6ff,
+ 0xa7dd, 0xa7f0,
+ 0xa82d, 0xa82f,
+ 0xa83a, 0xa83f,
+ 0xa878, 0xa87f,
+ 0xa8c6, 0xa8cd,
+ 0xa8da, 0xa8df,
+ 0xa954, 0xa95e,
+ 0xa97d, 0xa97f,
+ 0xa9ce, 0xa9ce,
+ 0xa9da, 0xa9dd,
+ 0xa9ff, 0xa9ff,
+ 0xaa37, 0xaa3f,
+ 0xaa4e, 0xaa4f,
+ 0xaa5a, 0xaa5b,
+ 0xaac3, 0xaada,
+ 0xaaf7, 0xab00,
+ 0xab07, 0xab08,
+ 0xab0f, 0xab10,
+ 0xab17, 0xab1f,
+ 0xab27, 0xab27,
+ 0xab2f, 0xab2f,
+ 0xab6c, 0xab6f,
+ 0xabee, 0xabef,
+ 0xabfa, 0xabff,
+ 0xd7a4, 0xd7af,
+ 0xd7c7, 0xd7ca,
+ 0xd7fc, 0xd7ff,
+ 0xfa6e, 0xfa6f,
+ 0xfada, 0xfaff,
+ 0xfb07, 0xfb12,
+ 0xfb18, 0xfb1c,
+ 0xfb37, 0xfb37,
+ 0xfb3d, 0xfb3d,
+ 0xfb3f, 0xfb3f,
+ 0xfb42, 0xfb42,
+ 0xfb45, 0xfb45,
+ 0xfdd0, 0xfdef,
+ 0xfe1a, 0xfe1f,
+ 0xfe53, 0xfe53,
+ 0xfe67, 0xfe67,
+ 0xfe6c, 0xfe6f,
+ 0xfe75, 0xfe75,
+ 0xfefd, 0xfefe,
+ 0xff00, 0xff00,
+ 0xffbf, 0xffc1,
+ 0xffc8, 0xffc9,
+ 0xffd0, 0xffd1,
+ 0xffd8, 0xffd9,
+ 0xffdd, 0xffdf,
+ 0xffe7, 0xffe7,
+ 0xffef, 0xfff8,
+ 0xfffe, 0xffff,
+ 0x1000c, 0x1000c,
+ 0x10027, 0x10027,
+ 0x1003b, 0x1003b,
+ 0x1003e, 0x1003e,
+ 0x1004e, 0x1004f,
+ 0x1005e, 0x1007f,
+ 0x100fb, 0x100ff,
+ 0x10103, 0x10106,
+ 0x10134, 0x10136,
+ 0x1018f, 0x1018f,
+ 0x1019d, 0x1019f,
+ 0x101a1, 0x101cf,
+ 0x101fe, 0x1027f,
+ 0x1029d, 0x1029f,
+ 0x102d1, 0x102df,
+ 0x102fc, 0x102ff,
+ 0x10324, 0x1032c,
+ 0x1034b, 0x1034f,
+ 0x1037b, 0x1037f,
+ 0x1039e, 0x1039e,
+ 0x103c4, 0x103c7,
+ 0x103d6, 0x103ff,
+ 0x1049e, 0x1049f,
+ 0x104aa, 0x104af,
+ 0x104d4, 0x104d7,
+ 0x104fc, 0x104ff,
+ 0x10528, 0x1052f,
+ 0x10564, 0x1056e,
+ 0x1057b, 0x1057b,
+ 0x1058b, 0x1058b,
+ 0x10593, 0x10593,
+ 0x10596, 0x10596,
+ 0x105a2, 0x105a2,
+ 0x105b2, 0x105b2,
+ 0x105ba, 0x105ba,
+ 0x105bd, 0x105bf,
+ 0x105f4, 0x105ff,
+ 0x10737, 0x1073f,
+ 0x10756, 0x1075f,
+ 0x10768, 0x1077f,
+ 0x10786, 0x10786,
+ 0x107b1, 0x107b1,
+ 0x107bb, 0x107ff,
+ 0x10806, 0x10807,
+ 0x10809, 0x10809,
+ 0x10836, 0x10836,
+ 0x10839, 0x1083b,
+ 0x1083d, 0x1083e,
+ 0x10856, 0x10856,
+ 0x1089f, 0x108a6,
+ 0x108b0, 0x108df,
+ 0x108f3, 0x108f3,
+ 0x108f6, 0x108fa,
+ 0x1091c, 0x1091e,
+ 0x1093a, 0x1093e,
+ 0x1095a, 0x1097f,
+ 0x109b8, 0x109bb,
+ 0x109d0, 0x109d1,
+ 0x10a04, 0x10a04,
+ 0x10a07, 0x10a0b,
+ 0x10a14, 0x10a14,
+ 0x10a18, 0x10a18,
+ 0x10a36, 0x10a37,
+ 0x10a3b, 0x10a3e,
+ 0x10a49, 0x10a4f,
+ 0x10a59, 0x10a5f,
+ 0x10aa0, 0x10abf,
+ 0x10ae7, 0x10aea,
+ 0x10af7, 0x10aff,
+ 0x10b36, 0x10b38,
+ 0x10b56, 0x10b57,
+ 0x10b73, 0x10b77,
+ 0x10b92, 0x10b98,
+ 0x10b9d, 0x10ba8,
+ 0x10bb0, 0x10bff,
+ 0x10c49, 0x10c7f,
+ 0x10cb3, 0x10cbf,
+ 0x10cf3, 0x10cf9,
+ 0x10d28, 0x10d2f,
+ 0x10d3a, 0x10d3f,
+ 0x10d66, 0x10d68,
+ 0x10d86, 0x10d8d,
+ 0x10d90, 0x10e5f,
+ 0x10e7f, 0x10e7f,
+ 0x10eaa, 0x10eaa,
+ 0x10eae, 0x10eaf,
+ 0x10eb2, 0x10ec1,
+ 0x10ec8, 0x10ecf,
+ 0x10ed9, 0x10ef9,
+ 0x10f28, 0x10f2f,
+ 0x10f5a, 0x10f6f,
+ 0x10f8a, 0x10faf,
+ 0x10fcc, 0x10fdf,
+ 0x10ff7, 0x10fff,
+ 0x1104e, 0x11051,
+ 0x11076, 0x1107e,
+ 0x110c3, 0x110cc,
+ 0x110ce, 0x110cf,
+ 0x110e9, 0x110ef,
+ 0x110fa, 0x110ff,
+ 0x11135, 0x11135,
+ 0x11148, 0x1114f,
+ 0x11177, 0x1117f,
+ 0x111e0, 0x111e0,
+ 0x111f5, 0x111ff,
+ 0x11212, 0x11212,
+ 0x11242, 0x1127f,
+ 0x11287, 0x11287,
+ 0x11289, 0x11289,
+ 0x1128e, 0x1128e,
+ 0x1129e, 0x1129e,
+ 0x112aa, 0x112af,
+ 0x112eb, 0x112ef,
+ 0x112fa, 0x112ff,
+ 0x11304, 0x11304,
+ 0x1130d, 0x1130e,
+ 0x11311, 0x11312,
+ 0x11329, 0x11329,
+ 0x11331, 0x11331,
+ 0x11334, 0x11334,
+ 0x1133a, 0x1133a,
+ 0x11345, 0x11346,
+ 0x11349, 0x1134a,
+ 0x1134e, 0x1134f,
+ 0x11351, 0x11356,
+ 0x11358, 0x1135c,
+ 0x11364, 0x11365,
+ 0x1136d, 0x1136f,
+ 0x11375, 0x1137f,
+ 0x1138a, 0x1138a,
+ 0x1138c, 0x1138d,
+ 0x1138f, 0x1138f,
+ 0x113b6, 0x113b6,
+ 0x113c1, 0x113c1,
+ 0x113c3, 0x113c4,
+ 0x113c6, 0x113c6,
+ 0x113cb, 0x113cb,
+ 0x113d6, 0x113d6,
+ 0x113d9, 0x113e0,
+ 0x113e3, 0x113ff,
+ 0x1145c, 0x1145c,
+ 0x11462, 0x1147f,
+ 0x114c8, 0x114cf,
+ 0x114da, 0x1157f,
+ 0x115b6, 0x115b7,
+ 0x115de, 0x115ff,
+ 0x11645, 0x1164f,
+ 0x1165a, 0x1165f,
+ 0x1166d, 0x1167f,
+ 0x116ba, 0x116bf,
+ 0x116ca, 0x116cf,
+ 0x116e4, 0x116ff,
+ 0x1171b, 0x1171c,
+ 0x1172c, 0x1172f,
+ 0x11747, 0x117ff,
+ 0x1183c, 0x1189f,
+ 0x118f3, 0x118fe,
+ 0x11907, 0x11908,
+ 0x1190a, 0x1190b,
+ 0x11914, 0x11914,
+ 0x11917, 0x11917,
+ 0x11936, 0x11936,
+ 0x11939, 0x1193a,
+ 0x11947, 0x1194f,
+ 0x1195a, 0x1199f,
+ 0x119a8, 0x119a9,
+ 0x119d8, 0x119d9,
+ 0x119e5, 0x119ff,
+ 0x11a48, 0x11a4f,
+ 0x11aa3, 0x11aaf,
+ 0x11af9, 0x11aff,
+ 0x11b0a, 0x11b5f,
+ 0x11b68, 0x11bbf,
+ 0x11be2, 0x11bef,
+ 0x11bfa, 0x11bff,
+ 0x11c09, 0x11c09,
+ 0x11c37, 0x11c37,
+ 0x11c46, 0x11c4f,
+ 0x11c6d, 0x11c6f,
+ 0x11c90, 0x11c91,
+ 0x11ca8, 0x11ca8,
+ 0x11cb7, 0x11cff,
+ 0x11d07, 0x11d07,
+ 0x11d0a, 0x11d0a,
+ 0x11d37, 0x11d39,
+ 0x11d3b, 0x11d3b,
+ 0x11d3e, 0x11d3e,
+ 0x11d48, 0x11d4f,
+ 0x11d5a, 0x11d5f,
+ 0x11d66, 0x11d66,
+ 0x11d69, 0x11d69,
+ 0x11d8f, 0x11d8f,
+ 0x11d92, 0x11d92,
+ 0x11d99, 0x11d9f,
+ 0x11daa, 0x11daf,
+ 0x11ddc, 0x11ddf,
+ 0x11dea, 0x11edf,
+ 0x11ef9, 0x11eff,
+ 0x11f11, 0x11f11,
+ 0x11f3b, 0x11f3d,
+ 0x11f5b, 0x11faf,
+ 0x11fb1, 0x11fbf,
+ 0x11ff2, 0x11ffe,
+ 0x1239a, 0x123ff,
+ 0x1246f, 0x1246f,
+ 0x12475, 0x1247f,
+ 0x12544, 0x12f8f,
+ 0x12ff3, 0x12fff,
+ 0x13456, 0x1345f,
+ 0x143fb, 0x143ff,
+ 0x14647, 0x160ff,
+ 0x1613a, 0x167ff,
+ 0x16a39, 0x16a3f,
+ 0x16a5f, 0x16a5f,
+ 0x16a6a, 0x16a6d,
+ 0x16abf, 0x16abf,
+ 0x16aca, 0x16acf,
+ 0x16aee, 0x16aef,
+ 0x16af6, 0x16aff,
+ 0x16b46, 0x16b4f,
+ 0x16b5a, 0x16b5a,
+ 0x16b62, 0x16b62,
+ 0x16b78, 0x16b7c,
+ 0x16b90, 0x16d3f,
+ 0x16d7a, 0x16e3f,
+ 0x16e9b, 0x16e9f,
+ 0x16eb9, 0x16eba,
+ 0x16ed4, 0x16eff,
+ 0x16f4b, 0x16f4e,
+ 0x16f88, 0x16f8e,
+ 0x16fa0, 0x16fdf,
+ 0x16fe5, 0x16fef,
+ 0x16ff7, 0x16fff,
+ 0x18cd6, 0x18cfe,
+ 0x18d1f, 0x18d7f,
+ 0x18df3, 0x1afef,
+ 0x1aff4, 0x1aff4,
+ 0x1affc, 0x1affc,
+ 0x1afff, 0x1afff,
+ 0x1b123, 0x1b131,
+ 0x1b133, 0x1b14f,
+ 0x1b153, 0x1b154,
+ 0x1b156, 0x1b163,
+ 0x1b168, 0x1b16f,
+ 0x1b2fc, 0x1bbff,
+ 0x1bc6b, 0x1bc6f,
+ 0x1bc7d, 0x1bc7f,
+ 0x1bc89, 0x1bc8f,
+ 0x1bc9a, 0x1bc9b,
+ 0x1bca4, 0x1cbff,
+ 0x1ccfd, 0x1ccff,
+ 0x1ceb4, 0x1ceb9,
+ 0x1ced1, 0x1cedf,
+ 0x1cef1, 0x1ceff,
+ 0x1cf2e, 0x1cf2f,
+ 0x1cf47, 0x1cf4f,
+ 0x1cfc4, 0x1cfff,
+ 0x1d0f6, 0x1d0ff,
+ 0x1d127, 0x1d128,
+ 0x1d1eb, 0x1d1ff,
+ 0x1d246, 0x1d2bf,
+ 0x1d2d4, 0x1d2df,
+ 0x1d2f4, 0x1d2ff,
+ 0x1d357, 0x1d35f,
+ 0x1d379, 0x1d3ff,
+ 0x1d455, 0x1d455,
+ 0x1d49d, 0x1d49d,
+ 0x1d4a0, 0x1d4a1,
+ 0x1d4a3, 0x1d4a4,
+ 0x1d4a7, 0x1d4a8,
+ 0x1d4ad, 0x1d4ad,
+ 0x1d4ba, 0x1d4ba,
+ 0x1d4bc, 0x1d4bc,
+ 0x1d4c4, 0x1d4c4,
+ 0x1d506, 0x1d506,
+ 0x1d50b, 0x1d50c,
+ 0x1d515, 0x1d515,
+ 0x1d51d, 0x1d51d,
+ 0x1d53a, 0x1d53a,
+ 0x1d53f, 0x1d53f,
+ 0x1d545, 0x1d545,
+ 0x1d547, 0x1d549,
+ 0x1d551, 0x1d551,
+ 0x1d6a6, 0x1d6a7,
+ 0x1d7cc, 0x1d7cd,
+ 0x1da8c, 0x1da9a,
+ 0x1daa0, 0x1daa0,
+ 0x1dab0, 0x1deff,
+ 0x1df1f, 0x1df24,
+ 0x1df2b, 0x1dfff,
+ 0x1e007, 0x1e007,
+ 0x1e019, 0x1e01a,
+ 0x1e022, 0x1e022,
+ 0x1e025, 0x1e025,
+ 0x1e02b, 0x1e02f,
+ 0x1e06e, 0x1e08e,
+ 0x1e090, 0x1e0ff,
+ 0x1e12d, 0x1e12f,
+ 0x1e13e, 0x1e13f,
+ 0x1e14a, 0x1e14d,
+ 0x1e150, 0x1e28f,
+ 0x1e2af, 0x1e2bf,
+ 0x1e2fa, 0x1e2fe,
+ 0x1e300, 0x1e4cf,
+ 0x1e4fa, 0x1e5cf,
+ 0x1e5fb, 0x1e5fe,
+ 0x1e600, 0x1e6bf,
+ 0x1e6df, 0x1e6df,
+ 0x1e6f6, 0x1e6fd,
+ 0x1e700, 0x1e7df,
+ 0x1e7e7, 0x1e7e7,
+ 0x1e7ec, 0x1e7ec,
+ 0x1e7ef, 0x1e7ef,
+ 0x1e7ff, 0x1e7ff,
+ 0x1e8c5, 0x1e8c6,
+ 0x1e8d7, 0x1e8ff,
+ 0x1e94c, 0x1e94f,
+ 0x1e95a, 0x1e95d,
+ 0x1e960, 0x1ec70,
+ 0x1ecb5, 0x1ed00,
+ 0x1ed3e, 0x1edff,
+ 0x1ee04, 0x1ee04,
+ 0x1ee20, 0x1ee20,
+ 0x1ee23, 0x1ee23,
+ 0x1ee25, 0x1ee26,
+ 0x1ee28, 0x1ee28,
+ 0x1ee33, 0x1ee33,
+ 0x1ee38, 0x1ee38,
+ 0x1ee3a, 0x1ee3a,
+ 0x1ee3c, 0x1ee41,
+ 0x1ee43, 0x1ee46,
+ 0x1ee48, 0x1ee48,
+ 0x1ee4a, 0x1ee4a,
+ 0x1ee4c, 0x1ee4c,
+ 0x1ee50, 0x1ee50,
+ 0x1ee53, 0x1ee53,
+ 0x1ee55, 0x1ee56,
+ 0x1ee58, 0x1ee58,
+ 0x1ee5a, 0x1ee5a,
+ 0x1ee5c, 0x1ee5c,
+ 0x1ee5e, 0x1ee5e,
+ 0x1ee60, 0x1ee60,
+ 0x1ee63, 0x1ee63,
+ 0x1ee65, 0x1ee66,
+ 0x1ee6b, 0x1ee6b,
+ 0x1ee73, 0x1ee73,
+ 0x1ee78, 0x1ee78,
+ 0x1ee7d, 0x1ee7d,
+ 0x1ee7f, 0x1ee7f,
+ 0x1ee8a, 0x1ee8a,
+ 0x1ee9c, 0x1eea0,
+ 0x1eea4, 0x1eea4,
+ 0x1eeaa, 0x1eeaa,
+ 0x1eebc, 0x1eeef,
+ 0x1eef2, 0x1efff,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0d0, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f203, 0x1f20f,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f24f,
+ 0x1f252, 0x1f25f,
+ 0x1f266, 0x1f2ff,
+ 0x1f6d9, 0x1f6db,
+ 0x1f6ed, 0x1f6ef,
+ 0x1f6fd, 0x1f6ff,
+ 0x1f7da, 0x1f7df,
+ 0x1f7ec, 0x1f7ef,
+ 0x1f7f1, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1fa6f,
+ 0x1fa7d, 0x1fa7f,
+ 0x1fa8b, 0x1fa8d,
+ 0x1fac7, 0x1fac7,
+ 0x1fac9, 0x1facc,
+ 0x1fadd, 0x1fade,
+ 0x1faeb, 0x1faee,
+ 0x1faf9, 0x1faff,
+ 0x1fb93, 0x1fb93,
+ 0x1fbfb, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2b81e, 0x2b81f,
+ 0x2ceae, 0x2ceaf,
+ 0x2ebe1, 0x2ebef,
+ 0x2ee5e, 0x2f7ff,
+ 0x2fa1e, 0x2ffff,
+ 0x3134b, 0x3134f,
+ 0x3347a, 0xe0000,
+ 0xe0002, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xeffff,
+ 0xffffe, 0xfffff,
+ 0x10fffe, 0x10ffff,
+}; /* CR_Cn */
+
+/* 'Co': General Category */
+static const OnigCodePoint CR_Co[] = {
+ 3,
+ 0xe000, 0xf8ff,
+ 0xf0000, 0xffffd,
+ 0x100000, 0x10fffd,
+}; /* CR_Co */
+
+/* 'Cs': General Category */
+static const OnigCodePoint CR_Cs[] = {
+ 1,
+ 0xd800, 0xdfff,
+}; /* CR_Cs */
+
+/* 'L': Major Category */
+static const OnigCodePoint CR_L[] = {
+ 684,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0971, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 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,
+ 0x16f1, 0x16f8,
+ 0x1700, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1878,
+ 0x1880, 0x1884,
+ 0x1887, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1aa7, 0x1aa7,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 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,
+ 0x2183, 0x2184,
+ 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,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3006,
+ 0x3031, 0x3035,
+ 0x303b, 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,
+ 0xa67f, 0xa69d,
+ 0xa6a0, 0xa6e5,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9cf, 0xa9cf,
+ 0xa9e0, 0xa9e4,
+ 0xa9e6, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 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,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031f,
+ 0x1032d, 0x10340,
+ 0x10342, 0x10349,
+ 0x10350, 0x10375,
+ 0x10380, 0x1039d,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103cf,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 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, 0x10d23,
+ 0x10d4a, 0x10d65,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118a0, 0x118df,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff3,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 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,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e900, 0x1e943,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_L */
+
+/* 'LC': General Category */
+static const OnigCodePoint CR_LC[] = {
+ 144,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x01ba,
+ 0x01bc, 0x01bf,
+ 0x01c4, 0x0293,
+ 0x0296, 0x02af,
+ 0x0370, 0x0373,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0560, 0x0588,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1d00, 0x1d2b,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1d9a,
+ 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,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2119, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x212d,
+ 0x212f, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2183, 0x2184,
+ 0x2c00, 0x2c7b,
+ 0x2c7e, 0x2ce4,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa640, 0xa66d,
+ 0xa680, 0xa69b,
+ 0xa722, 0xa76f,
+ 0xa771, 0xa787,
+ 0xa78b, 0xa78e,
+ 0xa790, 0xa7dc,
+ 0xa7f5, 0xa7f6,
+ 0xa7fa, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab60, 0xab68,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10400, 0x1044f,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d50, 0x10d65,
+ 0x10d70, 0x10d85,
+ 0x118a0, 0x118df,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 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, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e900, 0x1e943,
+}; /* CR_LC */
+
+/* 'Ll': General Category */
+static const OnigCodePoint CR_Ll[] = {
+ 664,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0138,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018d,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01aa, 0x01ab,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01ba,
+ 0x01bd, 0x01bf,
+ 0x01c6, 0x01c6,
+ 0x01c9, 0x01c9,
+ 0x01cc, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f0,
+ 0x01f3, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0221, 0x0221,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0239,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0293,
+ 0x0296, 0x02af,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037b, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fc,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0560, 0x0588,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d00, 0x1d2b,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1d9a,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9d,
+ 0x1e9f, 0x1e9f,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x210a, 0x210a,
+ 0x210e, 0x210f,
+ 0x2113, 0x2113,
+ 0x212f, 0x212f,
+ 0x2134, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213d,
+ 0x2146, 0x2149,
+ 0x214e, 0x214e,
+ 0x2184, 0x2184,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c71, 0x2c71,
+ 0x2c73, 0x2c74,
+ 0x2c76, 0x2c7b,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce4,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69b,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa731,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa76f,
+ 0xa771, 0xa778,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa78e, 0xa78e,
+ 0xa791, 0xa791,
+ 0xa793, 0xa795,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7af, 0xa7af,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f6, 0xa7f6,
+ 0xa7fa, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab60, 0xab68,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1d41a, 0x1d433,
+ 0x1d44e, 0x1d454,
+ 0x1d456, 0x1d467,
+ 0x1d482, 0x1d49b,
+ 0x1d4b6, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d4cf,
+ 0x1d4ea, 0x1d503,
+ 0x1d51e, 0x1d537,
+ 0x1d552, 0x1d56b,
+ 0x1d586, 0x1d59f,
+ 0x1d5ba, 0x1d5d3,
+ 0x1d5ee, 0x1d607,
+ 0x1d622, 0x1d63b,
+ 0x1d656, 0x1d66f,
+ 0x1d68a, 0x1d6a5,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6e1,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d71b,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d755,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d78f,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7c9,
+ 0x1d7cb, 0x1d7cb,
+ 0x1df00, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e922, 0x1e943,
+}; /* CR_Ll */
+
+/* 'Lm': General Category */
+static const OnigCodePoint CR_Lm[] = {
+ 79,
+ 0x02b0, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0374, 0x0374,
+ 0x037a, 0x037a,
+ 0x0559, 0x0559,
+ 0x0640, 0x0640,
+ 0x06e5, 0x06e6,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x08c9, 0x08c9,
+ 0x0971, 0x0971,
+ 0x0e46, 0x0e46,
+ 0x0ec6, 0x0ec6,
+ 0x10fc, 0x10fc,
+ 0x17d7, 0x17d7,
+ 0x1843, 0x1843,
+ 0x1aa7, 0x1aa7,
+ 0x1c78, 0x1c7d,
+ 0x1d2c, 0x1d6a,
+ 0x1d78, 0x1d78,
+ 0x1d9b, 0x1dbf,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x2c7c, 0x2c7d,
+ 0x2d6f, 0x2d6f,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3005,
+ 0x3031, 0x3035,
+ 0x303b, 0x303b,
+ 0x309d, 0x309e,
+ 0x30fc, 0x30fe,
+ 0xa015, 0xa015,
+ 0xa4f8, 0xa4fd,
+ 0xa60c, 0xa60c,
+ 0xa67f, 0xa67f,
+ 0xa69c, 0xa69d,
+ 0xa717, 0xa71f,
+ 0xa770, 0xa770,
+ 0xa788, 0xa788,
+ 0xa7f1, 0xa7f4,
+ 0xa7f8, 0xa7f9,
+ 0xa9cf, 0xa9cf,
+ 0xa9e6, 0xa9e6,
+ 0xaa70, 0xaa70,
+ 0xaadd, 0xaadd,
+ 0xaaf3, 0xaaf4,
+ 0xab5c, 0xab5f,
+ 0xab69, 0xab69,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10d4e, 0x10d4e,
+ 0x10d6f, 0x10d6f,
+ 0x10ec5, 0x10ec5,
+ 0x11dd9, 0x11dd9,
+ 0x16b40, 0x16b43,
+ 0x16d40, 0x16d42,
+ 0x16d6b, 0x16d6c,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff3,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1e030, 0x1e06d,
+ 0x1e137, 0x1e13d,
+ 0x1e4eb, 0x1e4eb,
+ 0x1e6ff, 0x1e6ff,
+ 0x1e94b, 0x1e94b,
+}; /* CR_Lm */
+
+/* 'Lo': General Category */
+static const OnigCodePoint CR_Lo[] = {
+ 537,
+ 0x00aa, 0x00aa,
+ 0x00ba, 0x00ba,
+ 0x01bb, 0x01bb,
+ 0x01c0, 0x01c3,
+ 0x0294, 0x0295,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x063f,
+ 0x0641, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x0800, 0x0815,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c8,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0972, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e45,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 0x1100, 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,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16f1, 0x16f8,
+ 0x1700, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1842,
+ 0x1844, 0x1878,
+ 0x1880, 0x1884,
+ 0x1887, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c77,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x2135, 0x2138,
+ 0x2d30, 0x2d67,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x3006, 0x3006,
+ 0x303c, 0x303c,
+ 0x3041, 0x3096,
+ 0x309f, 0x309f,
+ 0x30a1, 0x30fa,
+ 0x30ff, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31bf,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0xa014,
+ 0xa016, 0xa48c,
+ 0xa4d0, 0xa4f7,
+ 0xa500, 0xa60b,
+ 0xa610, 0xa61f,
+ 0xa62a, 0xa62b,
+ 0xa66e, 0xa66e,
+ 0xa6a0, 0xa6e5,
+ 0xa78f, 0xa78f,
+ 0xa7f7, 0xa7f7,
+ 0xa7fb, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9e0, 0xa9e4,
+ 0xa9e7, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa6f,
+ 0xaa71, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadc,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf2,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 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,
+ 0xff66, 0xff6f,
+ 0xff71, 0xff9d,
+ 0xffa0, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031f,
+ 0x1032d, 0x10340,
+ 0x10342, 0x10349,
+ 0x10350, 0x10375,
+ 0x10380, 0x1039d,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103cf,
+ 0x10450, 0x1049d,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10860, 0x10876,
+ 0x10880, 0x1089e,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x10900, 0x10915,
+ 0x10920, 0x10939,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae4,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10d00, 0x10d23,
+ 0x10d4a, 0x10d4d,
+ 0x10d4f, 0x10d4f,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec4,
+ 0x10ec6, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11dd8,
+ 0x11dda, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d43, 0x16d6a,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 0x1b000, 0x1b122,
+ 0x1b132, 0x1b132,
+ 0x1b150, 0x1b152,
+ 0x1b155, 0x1b155,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1df0a, 0x1df0a,
+ 0x1e100, 0x1e12c,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4ea,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6fe,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Lo */
+
+/* 'Lt': General Category */
+static const OnigCodePoint CR_Lt[] = {
+ 10,
+ 0x01c5, 0x01c5,
+ 0x01c8, 0x01c8,
+ 0x01cb, 0x01cb,
+ 0x01f2, 0x01f2,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fbc, 0x1fbc,
+ 0x1fcc, 0x1fcc,
+ 0x1ffc, 0x1ffc,
+}; /* CR_Lt */
+
+/* 'Lu': General Category */
+static const OnigCodePoint CR_Lu[] = {
+ 655,
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x014a, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c4,
+ 0x01c7, 0x01c7,
+ 0x01ca, 0x01ca,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f1,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03cf, 0x03cf,
+ 0x03d2, 0x03d4,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f4, 0x03f4,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13a0, 0x13f5,
+ 0x1c89, 0x1c89,
+ 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,
+ 0x2183, 0x2183,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 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,
+}; /* CR_Lu */
+
+/* 'M': Major Category */
+static const OnigCodePoint CR_M[] = {
+ 327,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0903,
+ 0x093a, 0x093c,
+ 0x093e, 0x094f,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0983,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0abc, 0x0abc,
+ 0x0abe, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c83,
+ 0x0cbc, 0x0cbc,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0cf3, 0x0cf3,
+ 0x0d00, 0x0d03,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d83,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f3f,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102b, 0x103e,
+ 0x1056, 0x1059,
+ 0x105e, 0x1060,
+ 0x1062, 0x1064,
+ 0x1067, 0x106d,
+ 0x1071, 0x1074,
+ 0x1082, 0x108d,
+ 0x108f, 0x108f,
+ 0x109a, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1a17, 0x1a1b,
+ 0x1a55, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b04,
+ 0x1b34, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b82,
+ 0x1ba1, 0x1bad,
+ 0x1be6, 0x1bf3,
+ 0x1c24, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf7, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa823, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa953,
+ 0xa980, 0xa983,
+ 0xa9b3, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4d,
+ 0xaa7b, 0xaa7d,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaeb, 0xaaef,
+ 0xaaf5, 0xaaf6,
+ 0xabe3, 0xabea,
+ 0xabec, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11000, 0x11002,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11082,
+ 0x110b0, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x11134,
+ 0x11145, 0x11146,
+ 0x11173, 0x11173,
+ 0x11180, 0x11182,
+ 0x111b3, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111cf,
+ 0x1122c, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112ea,
+ 0x11300, 0x11303,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11362, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11435, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114c3,
+ 0x115af, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11630, 0x11640,
+ 0x116ab, 0x116b7,
+ 0x1171d, 0x1172b,
+ 0x1182c, 0x1183a,
+ 0x11930, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x1193e,
+ 0x11940, 0x11940,
+ 0x11942, 0x11943,
+ 0x119d1, 0x119d7,
+ 0x119da, 0x119e0,
+ 0x119e4, 0x119e4,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a39,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a5b,
+ 0x11a8a, 0x11a99,
+ 0x11b60, 0x11b67,
+ 0x11c2f, 0x11c36,
+ 0x11c38, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d8a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d97,
+ 0x11ef3, 0x11ef6,
+ 0x11f00, 0x11f01,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f51, 0x16f87,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0xe0100, 0xe01ef,
+}; /* CR_M */
+
+/* 'Mc': General Category */
+static const OnigCodePoint CR_Mc[] = {
+ 193,
+ 0x0903, 0x0903,
+ 0x093b, 0x093b,
+ 0x093e, 0x0940,
+ 0x0949, 0x094c,
+ 0x094e, 0x094f,
+ 0x0982, 0x0983,
+ 0x09be, 0x09c0,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09d7, 0x09d7,
+ 0x0a03, 0x0a03,
+ 0x0a3e, 0x0a40,
+ 0x0a83, 0x0a83,
+ 0x0abe, 0x0ac0,
+ 0x0ac9, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0b02, 0x0b03,
+ 0x0b3e, 0x0b3e,
+ 0x0b40, 0x0b40,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b57, 0x0b57,
+ 0x0bbe, 0x0bbf,
+ 0x0bc1, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd7, 0x0bd7,
+ 0x0c01, 0x0c03,
+ 0x0c41, 0x0c44,
+ 0x0c82, 0x0c83,
+ 0x0cbe, 0x0cbe,
+ 0x0cc0, 0x0cc4,
+ 0x0cc7, 0x0cc8,
+ 0x0cca, 0x0ccb,
+ 0x0cd5, 0x0cd6,
+ 0x0cf3, 0x0cf3,
+ 0x0d02, 0x0d03,
+ 0x0d3e, 0x0d40,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d57, 0x0d57,
+ 0x0d82, 0x0d83,
+ 0x0dcf, 0x0dd1,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0f3e, 0x0f3f,
+ 0x0f7f, 0x0f7f,
+ 0x102b, 0x102c,
+ 0x1031, 0x1031,
+ 0x1038, 0x1038,
+ 0x103b, 0x103c,
+ 0x1056, 0x1057,
+ 0x1062, 0x1064,
+ 0x1067, 0x106d,
+ 0x1083, 0x1084,
+ 0x1087, 0x108c,
+ 0x108f, 0x108f,
+ 0x109a, 0x109c,
+ 0x1715, 0x1715,
+ 0x1734, 0x1734,
+ 0x17b6, 0x17b6,
+ 0x17be, 0x17c5,
+ 0x17c7, 0x17c8,
+ 0x1923, 0x1926,
+ 0x1929, 0x192b,
+ 0x1930, 0x1931,
+ 0x1933, 0x1938,
+ 0x1a19, 0x1a1a,
+ 0x1a55, 0x1a55,
+ 0x1a57, 0x1a57,
+ 0x1a61, 0x1a61,
+ 0x1a63, 0x1a64,
+ 0x1a6d, 0x1a72,
+ 0x1b04, 0x1b04,
+ 0x1b35, 0x1b35,
+ 0x1b3b, 0x1b3b,
+ 0x1b3d, 0x1b41,
+ 0x1b43, 0x1b44,
+ 0x1b82, 0x1b82,
+ 0x1ba1, 0x1ba1,
+ 0x1ba6, 0x1ba7,
+ 0x1baa, 0x1baa,
+ 0x1be7, 0x1be7,
+ 0x1bea, 0x1bec,
+ 0x1bee, 0x1bee,
+ 0x1bf2, 0x1bf3,
+ 0x1c24, 0x1c2b,
+ 0x1c34, 0x1c35,
+ 0x1ce1, 0x1ce1,
+ 0x1cf7, 0x1cf7,
+ 0x302e, 0x302f,
+ 0xa823, 0xa824,
+ 0xa827, 0xa827,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c3,
+ 0xa952, 0xa953,
+ 0xa983, 0xa983,
+ 0xa9b4, 0xa9b5,
+ 0xa9ba, 0xa9bb,
+ 0xa9be, 0xa9c0,
+ 0xaa2f, 0xaa30,
+ 0xaa33, 0xaa34,
+ 0xaa4d, 0xaa4d,
+ 0xaa7b, 0xaa7b,
+ 0xaa7d, 0xaa7d,
+ 0xaaeb, 0xaaeb,
+ 0xaaee, 0xaaef,
+ 0xaaf5, 0xaaf5,
+ 0xabe3, 0xabe4,
+ 0xabe6, 0xabe7,
+ 0xabe9, 0xabea,
+ 0xabec, 0xabec,
+ 0x11000, 0x11000,
+ 0x11002, 0x11002,
+ 0x11082, 0x11082,
+ 0x110b0, 0x110b2,
+ 0x110b7, 0x110b8,
+ 0x1112c, 0x1112c,
+ 0x11145, 0x11146,
+ 0x11182, 0x11182,
+ 0x111b3, 0x111b5,
+ 0x111bf, 0x111c0,
+ 0x111ce, 0x111ce,
+ 0x1122c, 0x1122e,
+ 0x11232, 0x11233,
+ 0x11235, 0x11235,
+ 0x112e0, 0x112e2,
+ 0x11302, 0x11303,
+ 0x1133e, 0x1133f,
+ 0x11341, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11362, 0x11363,
+ 0x113b8, 0x113ba,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113cf, 0x113cf,
+ 0x11435, 0x11437,
+ 0x11440, 0x11441,
+ 0x11445, 0x11445,
+ 0x114b0, 0x114b2,
+ 0x114b9, 0x114b9,
+ 0x114bb, 0x114be,
+ 0x114c1, 0x114c1,
+ 0x115af, 0x115b1,
+ 0x115b8, 0x115bb,
+ 0x115be, 0x115be,
+ 0x11630, 0x11632,
+ 0x1163b, 0x1163c,
+ 0x1163e, 0x1163e,
+ 0x116ac, 0x116ac,
+ 0x116ae, 0x116af,
+ 0x116b6, 0x116b6,
+ 0x1171e, 0x1171e,
+ 0x11720, 0x11721,
+ 0x11726, 0x11726,
+ 0x1182c, 0x1182e,
+ 0x11838, 0x11838,
+ 0x11930, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193d, 0x1193d,
+ 0x11940, 0x11940,
+ 0x11942, 0x11942,
+ 0x119d1, 0x119d3,
+ 0x119dc, 0x119df,
+ 0x119e4, 0x119e4,
+ 0x11a39, 0x11a39,
+ 0x11a57, 0x11a58,
+ 0x11a97, 0x11a97,
+ 0x11b61, 0x11b61,
+ 0x11b65, 0x11b65,
+ 0x11b67, 0x11b67,
+ 0x11c2f, 0x11c2f,
+ 0x11c3e, 0x11c3e,
+ 0x11ca9, 0x11ca9,
+ 0x11cb1, 0x11cb1,
+ 0x11cb4, 0x11cb4,
+ 0x11d8a, 0x11d8e,
+ 0x11d93, 0x11d94,
+ 0x11d96, 0x11d96,
+ 0x11ef5, 0x11ef6,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f35,
+ 0x11f3e, 0x11f3f,
+ 0x11f41, 0x11f41,
+ 0x1612a, 0x1612c,
+ 0x16f51, 0x16f87,
+ 0x16ff0, 0x16ff1,
+ 0x1d165, 0x1d166,
+ 0x1d16d, 0x1d172,
+}; /* CR_Mc */
+
+/* 'Me': General Category */
+static const OnigCodePoint CR_Me[] = {
+ 5,
+ 0x0488, 0x0489,
+ 0x1abe, 0x1abe,
+ 0x20dd, 0x20e0,
+ 0x20e2, 0x20e4,
+ 0xa670, 0xa672,
+}; /* CR_Me */
+
+/* 'Mn': General Category */
+static const OnigCodePoint CR_Mn[] = {
+ 365,
+ 0x0300, 0x036f,
+ 0x0483, 0x0487,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3f, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b56,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cbf,
+ 0x0cc6, 0x0cc6,
+ 0x0ccc, 0x0ccd,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1714,
+ 0x1732, 0x1733,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1abd,
+ 0x1abf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b34,
+ 0x1b36, 0x1b3a,
+ 0x1b3c, 0x1b3c,
+ 0x1b42, 0x1b42,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1ba9,
+ 0x1bab, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf1,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302d,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa66f,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xaaf6, 0xaaf6,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11234,
+ 0x11236, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x11340, 0x11340,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113bb, 0x113c0,
+ 0x113ce, 0x113ce,
+ 0x113d0, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b5,
+ 0x116b7, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x1193b, 0x1193c,
+ 0x1193e, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f40,
+ 0x11f42, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0xe0100, 0xe01ef,
+}; /* CR_Mn */
+
+/* 'N': Major Category */
+static const OnigCodePoint CR_N[] = {
+ 146,
+ 0x0030, 0x0039,
+ 0x00b2, 0x00b3,
+ 0x00b9, 0x00b9,
+ 0x00bc, 0x00be,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x09f4, 0x09f9,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0b72, 0x0b77,
+ 0x0be6, 0x0bf2,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7e,
+ 0x0ce6, 0x0cef,
+ 0x0d58, 0x0d5e,
+ 0x0d66, 0x0d78,
+ 0x0de6, 0x0def,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f33,
+ 0x1040, 0x1049,
+ 0x1090, 0x1099,
+ 0x1369, 0x137c,
+ 0x16ee, 0x16f0,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19da,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1b50, 0x1b59,
+ 0x1bb0, 0x1bb9,
+ 0x1c40, 0x1c49,
+ 0x1c50, 0x1c59,
+ 0x2070, 0x2070,
+ 0x2074, 0x2079,
+ 0x2080, 0x2089,
+ 0x2150, 0x2182,
+ 0x2185, 0x2189,
+ 0x2460, 0x249b,
+ 0x24ea, 0x24ff,
+ 0x2776, 0x2793,
+ 0x2cfd, 0x2cfd,
+ 0x3007, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303a,
+ 0x3192, 0x3195,
+ 0x3220, 0x3229,
+ 0x3248, 0x324f,
+ 0x3251, 0x325f,
+ 0x3280, 0x3289,
+ 0x32b1, 0x32bf,
+ 0xa620, 0xa629,
+ 0xa6e6, 0xa6ef,
+ 0xa830, 0xa835,
+ 0xa8d0, 0xa8d9,
+ 0xa900, 0xa909,
+ 0xa9d0, 0xa9d9,
+ 0xa9f0, 0xa9f9,
+ 0xaa50, 0xaa59,
+ 0xabf0, 0xabf9,
+ 0xff10, 0xff19,
+ 0x10107, 0x10133,
+ 0x10140, 0x10178,
+ 0x1018a, 0x1018b,
+ 0x102e1, 0x102fb,
+ 0x10320, 0x10323,
+ 0x10341, 0x10341,
+ 0x1034a, 0x1034a,
+ 0x103d1, 0x103d5,
+ 0x104a0, 0x104a9,
+ 0x10858, 0x1085f,
+ 0x10879, 0x1087f,
+ 0x108a7, 0x108af,
+ 0x108fb, 0x108ff,
+ 0x10916, 0x1091b,
+ 0x109bc, 0x109bd,
+ 0x109c0, 0x109cf,
+ 0x109d2, 0x109ff,
+ 0x10a40, 0x10a48,
+ 0x10a7d, 0x10a7e,
+ 0x10a9d, 0x10a9f,
+ 0x10aeb, 0x10aef,
+ 0x10b58, 0x10b5f,
+ 0x10b78, 0x10b7f,
+ 0x10ba9, 0x10baf,
+ 0x10cfa, 0x10cff,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d49,
+ 0x10e60, 0x10e7e,
+ 0x10f1d, 0x10f26,
+ 0x10f51, 0x10f54,
+ 0x10fc5, 0x10fcb,
+ 0x11052, 0x1106f,
+ 0x110f0, 0x110f9,
+ 0x11136, 0x1113f,
+ 0x111d0, 0x111d9,
+ 0x111e1, 0x111f4,
+ 0x112f0, 0x112f9,
+ 0x11450, 0x11459,
+ 0x114d0, 0x114d9,
+ 0x11650, 0x11659,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11730, 0x1173b,
+ 0x118e0, 0x118f2,
+ 0x11950, 0x11959,
+ 0x11bf0, 0x11bf9,
+ 0x11c50, 0x11c6c,
+ 0x11d50, 0x11d59,
+ 0x11da0, 0x11da9,
+ 0x11de0, 0x11de9,
+ 0x11f50, 0x11f59,
+ 0x11fc0, 0x11fd4,
+ 0x12400, 0x1246e,
+ 0x16130, 0x16139,
+ 0x16a60, 0x16a69,
+ 0x16ac0, 0x16ac9,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16d70, 0x16d79,
+ 0x16e80, 0x16e96,
+ 0x16ff4, 0x16ff6,
+ 0x1ccf0, 0x1ccf9,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d360, 0x1d378,
+ 0x1d7ce, 0x1d7ff,
+ 0x1e140, 0x1e149,
+ 0x1e2f0, 0x1e2f9,
+ 0x1e4f0, 0x1e4f9,
+ 0x1e5f1, 0x1e5fa,
+ 0x1e8c7, 0x1e8cf,
+ 0x1e950, 0x1e959,
+ 0x1ec71, 0x1ecab,
+ 0x1ecad, 0x1ecaf,
+ 0x1ecb1, 0x1ecb4,
+ 0x1ed01, 0x1ed2d,
+ 0x1ed2f, 0x1ed3d,
+ 0x1f100, 0x1f10c,
+ 0x1fbf0, 0x1fbf9,
+}; /* CR_N */
+
+/* 'Nd': General Category */
+#define CR_Nd CR_Digit
+
+/* 'Nl': General Category */
+static const OnigCodePoint CR_Nl[] = {
+ 13,
+ 0x16ee, 0x16f0,
+ 0x2160, 0x2182,
+ 0x2185, 0x2188,
+ 0x3007, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303a,
+ 0xa6e6, 0xa6ef,
+ 0x10140, 0x10174,
+ 0x10341, 0x10341,
+ 0x1034a, 0x1034a,
+ 0x103d1, 0x103d5,
+ 0x12400, 0x1246e,
+ 0x16ff4, 0x16ff6,
+}; /* CR_Nl */
+
+/* 'No': General Category */
+static const OnigCodePoint CR_No[] = {
+ 72,
+ 0x00b2, 0x00b3,
+ 0x00b9, 0x00b9,
+ 0x00bc, 0x00be,
+ 0x09f4, 0x09f9,
+ 0x0b72, 0x0b77,
+ 0x0bf0, 0x0bf2,
+ 0x0c78, 0x0c7e,
+ 0x0d58, 0x0d5e,
+ 0x0d70, 0x0d78,
+ 0x0f2a, 0x0f33,
+ 0x1369, 0x137c,
+ 0x17f0, 0x17f9,
+ 0x19da, 0x19da,
+ 0x2070, 0x2070,
+ 0x2074, 0x2079,
+ 0x2080, 0x2089,
+ 0x2150, 0x215f,
+ 0x2189, 0x2189,
+ 0x2460, 0x249b,
+ 0x24ea, 0x24ff,
+ 0x2776, 0x2793,
+ 0x2cfd, 0x2cfd,
+ 0x3192, 0x3195,
+ 0x3220, 0x3229,
+ 0x3248, 0x324f,
+ 0x3251, 0x325f,
+ 0x3280, 0x3289,
+ 0x32b1, 0x32bf,
+ 0xa830, 0xa835,
+ 0x10107, 0x10133,
+ 0x10175, 0x10178,
+ 0x1018a, 0x1018b,
+ 0x102e1, 0x102fb,
+ 0x10320, 0x10323,
+ 0x10858, 0x1085f,
+ 0x10879, 0x1087f,
+ 0x108a7, 0x108af,
+ 0x108fb, 0x108ff,
+ 0x10916, 0x1091b,
+ 0x109bc, 0x109bd,
+ 0x109c0, 0x109cf,
+ 0x109d2, 0x109ff,
+ 0x10a40, 0x10a48,
+ 0x10a7d, 0x10a7e,
+ 0x10a9d, 0x10a9f,
+ 0x10aeb, 0x10aef,
+ 0x10b58, 0x10b5f,
+ 0x10b78, 0x10b7f,
+ 0x10ba9, 0x10baf,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x10f1d, 0x10f26,
+ 0x10f51, 0x10f54,
+ 0x10fc5, 0x10fcb,
+ 0x11052, 0x11065,
+ 0x111e1, 0x111f4,
+ 0x1173a, 0x1173b,
+ 0x118ea, 0x118f2,
+ 0x11c5a, 0x11c6c,
+ 0x11fc0, 0x11fd4,
+ 0x16b5b, 0x16b61,
+ 0x16e80, 0x16e96,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d360, 0x1d378,
+ 0x1e8c7, 0x1e8cf,
+ 0x1ec71, 0x1ecab,
+ 0x1ecad, 0x1ecaf,
+ 0x1ecb1, 0x1ecb4,
+ 0x1ed01, 0x1ed2d,
+ 0x1ed2f, 0x1ed3d,
+ 0x1f100, 0x1f10c,
+}; /* CR_No */
+
+/* 'P': Major Category */
+#define CR_P CR_Punct
+
+/* 'Pc': General Category */
+static const OnigCodePoint CR_Pc[] = {
+ 6,
+ 0x005f, 0x005f,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xff3f, 0xff3f,
+}; /* CR_Pc */
+
+/* 'Pd': General Category */
+static const OnigCodePoint CR_Pd[] = {
+ 20,
+ 0x002d, 0x002d,
+ 0x058a, 0x058a,
+ 0x05be, 0x05be,
+ 0x1400, 0x1400,
+ 0x1806, 0x1806,
+ 0x2010, 0x2015,
+ 0x2e17, 0x2e17,
+ 0x2e1a, 0x2e1a,
+ 0x2e3a, 0x2e3b,
+ 0x2e40, 0x2e40,
+ 0x2e5d, 0x2e5d,
+ 0x301c, 0x301c,
+ 0x3030, 0x3030,
+ 0x30a0, 0x30a0,
+ 0xfe31, 0xfe32,
+ 0xfe58, 0xfe58,
+ 0xfe63, 0xfe63,
+ 0xff0d, 0xff0d,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+}; /* CR_Pd */
+
+/* 'Pe': General Category */
+static const OnigCodePoint CR_Pe[] = {
+ 76,
+ 0x0029, 0x0029,
+ 0x005d, 0x005d,
+ 0x007d, 0x007d,
+ 0x0f3b, 0x0f3b,
+ 0x0f3d, 0x0f3d,
+ 0x169c, 0x169c,
+ 0x2046, 0x2046,
+ 0x207e, 0x207e,
+ 0x208e, 0x208e,
+ 0x2309, 0x2309,
+ 0x230b, 0x230b,
+ 0x232a, 0x232a,
+ 0x2769, 0x2769,
+ 0x276b, 0x276b,
+ 0x276d, 0x276d,
+ 0x276f, 0x276f,
+ 0x2771, 0x2771,
+ 0x2773, 0x2773,
+ 0x2775, 0x2775,
+ 0x27c6, 0x27c6,
+ 0x27e7, 0x27e7,
+ 0x27e9, 0x27e9,
+ 0x27eb, 0x27eb,
+ 0x27ed, 0x27ed,
+ 0x27ef, 0x27ef,
+ 0x2984, 0x2984,
+ 0x2986, 0x2986,
+ 0x2988, 0x2988,
+ 0x298a, 0x298a,
+ 0x298c, 0x298c,
+ 0x298e, 0x298e,
+ 0x2990, 0x2990,
+ 0x2992, 0x2992,
+ 0x2994, 0x2994,
+ 0x2996, 0x2996,
+ 0x2998, 0x2998,
+ 0x29d9, 0x29d9,
+ 0x29db, 0x29db,
+ 0x29fd, 0x29fd,
+ 0x2e23, 0x2e23,
+ 0x2e25, 0x2e25,
+ 0x2e27, 0x2e27,
+ 0x2e29, 0x2e29,
+ 0x2e56, 0x2e56,
+ 0x2e58, 0x2e58,
+ 0x2e5a, 0x2e5a,
+ 0x2e5c, 0x2e5c,
+ 0x3009, 0x3009,
+ 0x300b, 0x300b,
+ 0x300d, 0x300d,
+ 0x300f, 0x300f,
+ 0x3011, 0x3011,
+ 0x3015, 0x3015,
+ 0x3017, 0x3017,
+ 0x3019, 0x3019,
+ 0x301b, 0x301b,
+ 0x301e, 0x301f,
+ 0xfd3e, 0xfd3e,
+ 0xfe18, 0xfe18,
+ 0xfe36, 0xfe36,
+ 0xfe38, 0xfe38,
+ 0xfe3a, 0xfe3a,
+ 0xfe3c, 0xfe3c,
+ 0xfe3e, 0xfe3e,
+ 0xfe40, 0xfe40,
+ 0xfe42, 0xfe42,
+ 0xfe44, 0xfe44,
+ 0xfe48, 0xfe48,
+ 0xfe5a, 0xfe5a,
+ 0xfe5c, 0xfe5c,
+ 0xfe5e, 0xfe5e,
+ 0xff09, 0xff09,
+ 0xff3d, 0xff3d,
+ 0xff5d, 0xff5d,
+ 0xff60, 0xff60,
+ 0xff63, 0xff63,
+}; /* CR_Pe */
+
+/* 'Pf': General Category */
+static const OnigCodePoint CR_Pf[] = {
+ 10,
+ 0x00bb, 0x00bb,
+ 0x2019, 0x2019,
+ 0x201d, 0x201d,
+ 0x203a, 0x203a,
+ 0x2e03, 0x2e03,
+ 0x2e05, 0x2e05,
+ 0x2e0a, 0x2e0a,
+ 0x2e0d, 0x2e0d,
+ 0x2e1d, 0x2e1d,
+ 0x2e21, 0x2e21,
+}; /* CR_Pf */
+
+/* 'Pi': General Category */
+static const OnigCodePoint CR_Pi[] = {
+ 11,
+ 0x00ab, 0x00ab,
+ 0x2018, 0x2018,
+ 0x201b, 0x201c,
+ 0x201f, 0x201f,
+ 0x2039, 0x2039,
+ 0x2e02, 0x2e02,
+ 0x2e04, 0x2e04,
+ 0x2e09, 0x2e09,
+ 0x2e0c, 0x2e0c,
+ 0x2e1c, 0x2e1c,
+ 0x2e20, 0x2e20,
+}; /* CR_Pi */
+
+/* 'Po': General Category */
+static const OnigCodePoint CR_Po[] = {
+ 194,
+ 0x0021, 0x0023,
+ 0x0025, 0x0027,
+ 0x002a, 0x002a,
+ 0x002c, 0x002c,
+ 0x002e, 0x002f,
+ 0x003a, 0x003b,
+ 0x003f, 0x0040,
+ 0x005c, 0x005c,
+ 0x00a1, 0x00a1,
+ 0x00a7, 0x00a7,
+ 0x00b6, 0x00b7,
+ 0x00bf, 0x00bf,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x055a, 0x055f,
+ 0x0589, 0x0589,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05f3, 0x05f4,
+ 0x0609, 0x060a,
+ 0x060c, 0x060d,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x066a, 0x066d,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070d,
+ 0x07f7, 0x07f9,
+ 0x0830, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0970, 0x0970,
+ 0x09fd, 0x09fd,
+ 0x0a76, 0x0a76,
+ 0x0af0, 0x0af0,
+ 0x0c77, 0x0c77,
+ 0x0c84, 0x0c84,
+ 0x0df4, 0x0df4,
+ 0x0e4f, 0x0e4f,
+ 0x0e5a, 0x0e5b,
+ 0x0f04, 0x0f12,
+ 0x0f14, 0x0f14,
+ 0x0f85, 0x0f85,
+ 0x0fd0, 0x0fd4,
+ 0x0fd9, 0x0fda,
+ 0x104a, 0x104f,
+ 0x10fb, 0x10fb,
+ 0x1360, 0x1368,
+ 0x166e, 0x166e,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17d8, 0x17da,
+ 0x1800, 0x1805,
+ 0x1807, 0x180a,
+ 0x1944, 0x1945,
+ 0x1a1e, 0x1a1f,
+ 0x1aa0, 0x1aa6,
+ 0x1aa8, 0x1aad,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b60,
+ 0x1b7d, 0x1b7f,
+ 0x1bfc, 0x1bff,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x2016, 0x2017,
+ 0x2020, 0x2027,
+ 0x2030, 0x2038,
+ 0x203b, 0x203e,
+ 0x2041, 0x2043,
+ 0x2047, 0x2051,
+ 0x2053, 0x2053,
+ 0x2055, 0x205e,
+ 0x2cf9, 0x2cfc,
+ 0x2cfe, 0x2cff,
+ 0x2d70, 0x2d70,
+ 0x2e00, 0x2e01,
+ 0x2e06, 0x2e08,
+ 0x2e0b, 0x2e0b,
+ 0x2e0e, 0x2e16,
+ 0x2e18, 0x2e19,
+ 0x2e1b, 0x2e1b,
+ 0x2e1e, 0x2e1f,
+ 0x2e2a, 0x2e2e,
+ 0x2e30, 0x2e39,
+ 0x2e3c, 0x2e3f,
+ 0x2e41, 0x2e41,
+ 0x2e43, 0x2e4f,
+ 0x2e52, 0x2e54,
+ 0x3001, 0x3003,
+ 0x303d, 0x303d,
+ 0x30fb, 0x30fb,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa67e,
+ 0xa6f2, 0xa6f7,
+ 0xa874, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa8f8, 0xa8fa,
+ 0xa8fc, 0xa8fc,
+ 0xa92e, 0xa92f,
+ 0xa95f, 0xa95f,
+ 0xa9c1, 0xa9cd,
+ 0xa9de, 0xa9df,
+ 0xaa5c, 0xaa5f,
+ 0xaade, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfe10, 0xfe16,
+ 0xfe19, 0xfe19,
+ 0xfe30, 0xfe30,
+ 0xfe45, 0xfe46,
+ 0xfe49, 0xfe4c,
+ 0xfe50, 0xfe52,
+ 0xfe54, 0xfe57,
+ 0xfe5f, 0xfe61,
+ 0xfe68, 0xfe68,
+ 0xfe6a, 0xfe6b,
+ 0xff01, 0xff03,
+ 0xff05, 0xff07,
+ 0xff0a, 0xff0a,
+ 0xff0c, 0xff0c,
+ 0xff0e, 0xff0f,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff20,
+ 0xff3c, 0xff3c,
+ 0xff61, 0xff61,
+ 0xff64, 0xff65,
+ 0x10100, 0x10102,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x1056f, 0x1056f,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x1093f, 0x1093f,
+ 0x10a50, 0x10a58,
+ 0x10a7f, 0x10a7f,
+ 0x10af0, 0x10af6,
+ 0x10b39, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10ed0, 0x10ed0,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x11140, 0x11143,
+ 0x11174, 0x11175,
+ 0x111c5, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111db, 0x111db,
+ 0x111dd, 0x111df,
+ 0x11238, 0x1123d,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x1144b, 0x1144f,
+ 0x1145a, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x114c6, 0x114c6,
+ 0x115c1, 0x115d7,
+ 0x11641, 0x11643,
+ 0x11660, 0x1166c,
+ 0x116b9, 0x116b9,
+ 0x1173c, 0x1173e,
+ 0x1183b, 0x1183b,
+ 0x11944, 0x11946,
+ 0x119e2, 0x119e2,
+ 0x11a3f, 0x11a46,
+ 0x11a9a, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11b00, 0x11b09,
+ 0x11be1, 0x11be1,
+ 0x11c41, 0x11c45,
+ 0x11c70, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f4f,
+ 0x11fff, 0x11fff,
+ 0x12470, 0x12474,
+ 0x12ff1, 0x12ff2,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b3b,
+ 0x16b44, 0x16b44,
+ 0x16d6d, 0x16d6f,
+ 0x16e97, 0x16e9a,
+ 0x16fe2, 0x16fe2,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8b,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e95e, 0x1e95f,
+}; /* CR_Po */
+
+/* 'Ps': General Category */
+static const OnigCodePoint CR_Ps[] = {
+ 79,
+ 0x0028, 0x0028,
+ 0x005b, 0x005b,
+ 0x007b, 0x007b,
+ 0x0f3a, 0x0f3a,
+ 0x0f3c, 0x0f3c,
+ 0x169b, 0x169b,
+ 0x201a, 0x201a,
+ 0x201e, 0x201e,
+ 0x2045, 0x2045,
+ 0x207d, 0x207d,
+ 0x208d, 0x208d,
+ 0x2308, 0x2308,
+ 0x230a, 0x230a,
+ 0x2329, 0x2329,
+ 0x2768, 0x2768,
+ 0x276a, 0x276a,
+ 0x276c, 0x276c,
+ 0x276e, 0x276e,
+ 0x2770, 0x2770,
+ 0x2772, 0x2772,
+ 0x2774, 0x2774,
+ 0x27c5, 0x27c5,
+ 0x27e6, 0x27e6,
+ 0x27e8, 0x27e8,
+ 0x27ea, 0x27ea,
+ 0x27ec, 0x27ec,
+ 0x27ee, 0x27ee,
+ 0x2983, 0x2983,
+ 0x2985, 0x2985,
+ 0x2987, 0x2987,
+ 0x2989, 0x2989,
+ 0x298b, 0x298b,
+ 0x298d, 0x298d,
+ 0x298f, 0x298f,
+ 0x2991, 0x2991,
+ 0x2993, 0x2993,
+ 0x2995, 0x2995,
+ 0x2997, 0x2997,
+ 0x29d8, 0x29d8,
+ 0x29da, 0x29da,
+ 0x29fc, 0x29fc,
+ 0x2e22, 0x2e22,
+ 0x2e24, 0x2e24,
+ 0x2e26, 0x2e26,
+ 0x2e28, 0x2e28,
+ 0x2e42, 0x2e42,
+ 0x2e55, 0x2e55,
+ 0x2e57, 0x2e57,
+ 0x2e59, 0x2e59,
+ 0x2e5b, 0x2e5b,
+ 0x3008, 0x3008,
+ 0x300a, 0x300a,
+ 0x300c, 0x300c,
+ 0x300e, 0x300e,
+ 0x3010, 0x3010,
+ 0x3014, 0x3014,
+ 0x3016, 0x3016,
+ 0x3018, 0x3018,
+ 0x301a, 0x301a,
+ 0x301d, 0x301d,
+ 0xfd3f, 0xfd3f,
+ 0xfe17, 0xfe17,
+ 0xfe35, 0xfe35,
+ 0xfe37, 0xfe37,
+ 0xfe39, 0xfe39,
+ 0xfe3b, 0xfe3b,
+ 0xfe3d, 0xfe3d,
+ 0xfe3f, 0xfe3f,
+ 0xfe41, 0xfe41,
+ 0xfe43, 0xfe43,
+ 0xfe47, 0xfe47,
+ 0xfe59, 0xfe59,
+ 0xfe5b, 0xfe5b,
+ 0xfe5d, 0xfe5d,
+ 0xff08, 0xff08,
+ 0xff3b, 0xff3b,
+ 0xff5b, 0xff5b,
+ 0xff5f, 0xff5f,
+ 0xff62, 0xff62,
+}; /* CR_Ps */
+
+/* 'S': Major Category */
+static const OnigCodePoint CR_S[] = {
+ 242,
+ 0x0024, 0x0024,
+ 0x002b, 0x002b,
+ 0x003c, 0x003e,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x007c, 0x007c,
+ 0x007e, 0x007e,
+ 0x00a2, 0x00a6,
+ 0x00a8, 0x00a9,
+ 0x00ac, 0x00ac,
+ 0x00ae, 0x00b1,
+ 0x00b4, 0x00b4,
+ 0x00b8, 0x00b8,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x02c2, 0x02c5,
+ 0x02d2, 0x02df,
+ 0x02e5, 0x02eb,
+ 0x02ed, 0x02ed,
+ 0x02ef, 0x02ff,
+ 0x0375, 0x0375,
+ 0x0384, 0x0385,
+ 0x03f6, 0x03f6,
+ 0x0482, 0x0482,
+ 0x058d, 0x058f,
+ 0x0606, 0x0608,
+ 0x060b, 0x060b,
+ 0x060e, 0x060f,
+ 0x06de, 0x06de,
+ 0x06e9, 0x06e9,
+ 0x06fd, 0x06fe,
+ 0x07f6, 0x07f6,
+ 0x07fe, 0x07ff,
+ 0x0888, 0x0888,
+ 0x09f2, 0x09f3,
+ 0x09fa, 0x09fb,
+ 0x0af1, 0x0af1,
+ 0x0b70, 0x0b70,
+ 0x0bf3, 0x0bfa,
+ 0x0c7f, 0x0c7f,
+ 0x0d4f, 0x0d4f,
+ 0x0d79, 0x0d79,
+ 0x0e3f, 0x0e3f,
+ 0x0f01, 0x0f03,
+ 0x0f13, 0x0f13,
+ 0x0f15, 0x0f17,
+ 0x0f1a, 0x0f1f,
+ 0x0f34, 0x0f34,
+ 0x0f36, 0x0f36,
+ 0x0f38, 0x0f38,
+ 0x0fbe, 0x0fc5,
+ 0x0fc7, 0x0fcc,
+ 0x0fce, 0x0fcf,
+ 0x0fd5, 0x0fd8,
+ 0x109e, 0x109f,
+ 0x1390, 0x1399,
+ 0x166d, 0x166d,
+ 0x17db, 0x17db,
+ 0x1940, 0x1940,
+ 0x19de, 0x19ff,
+ 0x1b61, 0x1b6a,
+ 0x1b74, 0x1b7c,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x2044, 0x2044,
+ 0x2052, 0x2052,
+ 0x207a, 0x207c,
+ 0x208a, 0x208c,
+ 0x20a0, 0x20c1,
+ 0x2100, 0x2101,
+ 0x2103, 0x2106,
+ 0x2108, 0x2109,
+ 0x2114, 0x2114,
+ 0x2116, 0x2118,
+ 0x211e, 0x2123,
+ 0x2125, 0x2125,
+ 0x2127, 0x2127,
+ 0x2129, 0x2129,
+ 0x212e, 0x212e,
+ 0x213a, 0x213b,
+ 0x2140, 0x2144,
+ 0x214a, 0x214d,
+ 0x214f, 0x214f,
+ 0x218a, 0x218b,
+ 0x2190, 0x2307,
+ 0x230c, 0x2328,
+ 0x232b, 0x2429,
+ 0x2440, 0x244a,
+ 0x249c, 0x24e9,
+ 0x2500, 0x2767,
+ 0x2794, 0x27c4,
+ 0x27c7, 0x27e5,
+ 0x27f0, 0x2982,
+ 0x2999, 0x29d7,
+ 0x29dc, 0x29fb,
+ 0x29fe, 0x2b73,
+ 0x2b76, 0x2bff,
+ 0x2ce5, 0x2cea,
+ 0x2e50, 0x2e51,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2fff,
+ 0x3004, 0x3004,
+ 0x3012, 0x3013,
+ 0x3020, 0x3020,
+ 0x3036, 0x3037,
+ 0x303e, 0x303f,
+ 0x309b, 0x309c,
+ 0x3190, 0x3191,
+ 0x3196, 0x319f,
+ 0x31c0, 0x31e5,
+ 0x31ef, 0x31ef,
+ 0x3200, 0x321e,
+ 0x322a, 0x3247,
+ 0x3250, 0x3250,
+ 0x3260, 0x327f,
+ 0x328a, 0x32b0,
+ 0x32c0, 0x33ff,
+ 0x4dc0, 0x4dff,
+ 0xa490, 0xa4c6,
+ 0xa700, 0xa716,
+ 0xa720, 0xa721,
+ 0xa789, 0xa78a,
+ 0xa828, 0xa82b,
+ 0xa836, 0xa839,
+ 0xaa77, 0xaa79,
+ 0xab5b, 0xab5b,
+ 0xab6a, 0xab6b,
+ 0xfb29, 0xfb29,
+ 0xfbb2, 0xfbd2,
+ 0xfd40, 0xfd4f,
+ 0xfd90, 0xfd91,
+ 0xfdc8, 0xfdcf,
+ 0xfdfc, 0xfdff,
+ 0xfe62, 0xfe62,
+ 0xfe64, 0xfe66,
+ 0xfe69, 0xfe69,
+ 0xff04, 0xff04,
+ 0xff0b, 0xff0b,
+ 0xff1c, 0xff1e,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xff5c, 0xff5c,
+ 0xff5e, 0xff5e,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffc, 0xfffd,
+ 0x10137, 0x1013f,
+ 0x10179, 0x10189,
+ 0x1018c, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fc,
+ 0x10877, 0x10878,
+ 0x10ac8, 0x10ac8,
+ 0x10d8e, 0x10d8f,
+ 0x10ed1, 0x10ed8,
+ 0x1173f, 0x1173f,
+ 0x11fd5, 0x11ff1,
+ 0x16b3c, 0x16b3f,
+ 0x16b45, 0x16b45,
+ 0x1bc9c, 0x1bc9c,
+ 0x1cc00, 0x1ccef,
+ 0x1ccfa, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d164,
+ 0x1d16a, 0x1d16c,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d200, 0x1d241,
+ 0x1d245, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+ 0x1d800, 0x1d9ff,
+ 0x1da37, 0x1da3a,
+ 0x1da6d, 0x1da74,
+ 0x1da76, 0x1da83,
+ 0x1da85, 0x1da86,
+ 0x1e14f, 0x1e14f,
+ 0x1e2ff, 0x1e2ff,
+ 0x1ecac, 0x1ecac,
+ 0x1ecb0, 0x1ecb0,
+ 0x1ed2e, 0x1ed2e,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f10d, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbef,
+ 0x1fbfa, 0x1fbfa,
+}; /* CR_S */
+
+/* 'Sc': General Category */
+static const OnigCodePoint CR_Sc[] = {
+ 21,
+ 0x0024, 0x0024,
+ 0x00a2, 0x00a5,
+ 0x058f, 0x058f,
+ 0x060b, 0x060b,
+ 0x07fe, 0x07ff,
+ 0x09f2, 0x09f3,
+ 0x09fb, 0x09fb,
+ 0x0af1, 0x0af1,
+ 0x0bf9, 0x0bf9,
+ 0x0e3f, 0x0e3f,
+ 0x17db, 0x17db,
+ 0x20a0, 0x20c1,
+ 0xa838, 0xa838,
+ 0xfdfc, 0xfdfc,
+ 0xfe69, 0xfe69,
+ 0xff04, 0xff04,
+ 0xffe0, 0xffe1,
+ 0xffe5, 0xffe6,
+ 0x11fdd, 0x11fe0,
+ 0x1e2ff, 0x1e2ff,
+ 0x1ecb0, 0x1ecb0,
+}; /* CR_Sc */
+
+/* 'Sk': General Category */
+static const OnigCodePoint CR_Sk[] = {
+ 31,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x00a8, 0x00a8,
+ 0x00af, 0x00af,
+ 0x00b4, 0x00b4,
+ 0x00b8, 0x00b8,
+ 0x02c2, 0x02c5,
+ 0x02d2, 0x02df,
+ 0x02e5, 0x02eb,
+ 0x02ed, 0x02ed,
+ 0x02ef, 0x02ff,
+ 0x0375, 0x0375,
+ 0x0384, 0x0385,
+ 0x0888, 0x0888,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x309b, 0x309c,
+ 0xa700, 0xa716,
+ 0xa720, 0xa721,
+ 0xa789, 0xa78a,
+ 0xab5b, 0xab5b,
+ 0xab6a, 0xab6b,
+ 0xfbb2, 0xfbc2,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xffe3, 0xffe3,
+ 0x1f3fb, 0x1f3ff,
+}; /* CR_Sk */
+
+/* 'Sm': General Category */
+static const OnigCodePoint CR_Sm[] = {
+ 67,
+ 0x002b, 0x002b,
+ 0x003c, 0x003e,
+ 0x007c, 0x007c,
+ 0x007e, 0x007e,
+ 0x00ac, 0x00ac,
+ 0x00b1, 0x00b1,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x03f6, 0x03f6,
+ 0x0606, 0x0608,
+ 0x2044, 0x2044,
+ 0x2052, 0x2052,
+ 0x207a, 0x207c,
+ 0x208a, 0x208c,
+ 0x2118, 0x2118,
+ 0x2140, 0x2144,
+ 0x214b, 0x214b,
+ 0x2190, 0x2194,
+ 0x219a, 0x219b,
+ 0x21a0, 0x21a0,
+ 0x21a3, 0x21a3,
+ 0x21a6, 0x21a6,
+ 0x21ae, 0x21ae,
+ 0x21ce, 0x21cf,
+ 0x21d2, 0x21d2,
+ 0x21d4, 0x21d4,
+ 0x21f4, 0x22ff,
+ 0x2320, 0x2321,
+ 0x237c, 0x237c,
+ 0x239b, 0x23b3,
+ 0x23dc, 0x23e1,
+ 0x25b7, 0x25b7,
+ 0x25c1, 0x25c1,
+ 0x25f8, 0x25ff,
+ 0x266f, 0x266f,
+ 0x27c0, 0x27c4,
+ 0x27c7, 0x27e5,
+ 0x27f0, 0x27ff,
+ 0x2900, 0x2982,
+ 0x2999, 0x29d7,
+ 0x29dc, 0x29fb,
+ 0x29fe, 0x2aff,
+ 0x2b30, 0x2b44,
+ 0x2b47, 0x2b4c,
+ 0xfb29, 0xfb29,
+ 0xfe62, 0xfe62,
+ 0xfe64, 0xfe66,
+ 0xff0b, 0xff0b,
+ 0xff1c, 0xff1e,
+ 0xff5c, 0xff5c,
+ 0xff5e, 0xff5e,
+ 0xffe2, 0xffe2,
+ 0xffe9, 0xffec,
+ 0x10d8e, 0x10d8f,
+ 0x1cef0, 0x1cef0,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+ 0x1eef0, 0x1eef1,
+ 0x1f8d0, 0x1f8d8,
+}; /* CR_Sm */
+
+/* 'So': General Category */
+static const OnigCodePoint CR_So[] = {
+ 193,
+ 0x00a6, 0x00a6,
+ 0x00a9, 0x00a9,
+ 0x00ae, 0x00ae,
+ 0x00b0, 0x00b0,
+ 0x0482, 0x0482,
+ 0x058d, 0x058e,
+ 0x060e, 0x060f,
+ 0x06de, 0x06de,
+ 0x06e9, 0x06e9,
+ 0x06fd, 0x06fe,
+ 0x07f6, 0x07f6,
+ 0x09fa, 0x09fa,
+ 0x0b70, 0x0b70,
+ 0x0bf3, 0x0bf8,
+ 0x0bfa, 0x0bfa,
+ 0x0c7f, 0x0c7f,
+ 0x0d4f, 0x0d4f,
+ 0x0d79, 0x0d79,
+ 0x0f01, 0x0f03,
+ 0x0f13, 0x0f13,
+ 0x0f15, 0x0f17,
+ 0x0f1a, 0x0f1f,
+ 0x0f34, 0x0f34,
+ 0x0f36, 0x0f36,
+ 0x0f38, 0x0f38,
+ 0x0fbe, 0x0fc5,
+ 0x0fc7, 0x0fcc,
+ 0x0fce, 0x0fcf,
+ 0x0fd5, 0x0fd8,
+ 0x109e, 0x109f,
+ 0x1390, 0x1399,
+ 0x166d, 0x166d,
+ 0x1940, 0x1940,
+ 0x19de, 0x19ff,
+ 0x1b61, 0x1b6a,
+ 0x1b74, 0x1b7c,
+ 0x2100, 0x2101,
+ 0x2103, 0x2106,
+ 0x2108, 0x2109,
+ 0x2114, 0x2114,
+ 0x2116, 0x2117,
+ 0x211e, 0x2123,
+ 0x2125, 0x2125,
+ 0x2127, 0x2127,
+ 0x2129, 0x2129,
+ 0x212e, 0x212e,
+ 0x213a, 0x213b,
+ 0x214a, 0x214a,
+ 0x214c, 0x214d,
+ 0x214f, 0x214f,
+ 0x218a, 0x218b,
+ 0x2195, 0x2199,
+ 0x219c, 0x219f,
+ 0x21a1, 0x21a2,
+ 0x21a4, 0x21a5,
+ 0x21a7, 0x21ad,
+ 0x21af, 0x21cd,
+ 0x21d0, 0x21d1,
+ 0x21d3, 0x21d3,
+ 0x21d5, 0x21f3,
+ 0x2300, 0x2307,
+ 0x230c, 0x231f,
+ 0x2322, 0x2328,
+ 0x232b, 0x237b,
+ 0x237d, 0x239a,
+ 0x23b4, 0x23db,
+ 0x23e2, 0x2429,
+ 0x2440, 0x244a,
+ 0x249c, 0x24e9,
+ 0x2500, 0x25b6,
+ 0x25b8, 0x25c0,
+ 0x25c2, 0x25f7,
+ 0x2600, 0x266e,
+ 0x2670, 0x2767,
+ 0x2794, 0x27bf,
+ 0x2800, 0x28ff,
+ 0x2b00, 0x2b2f,
+ 0x2b45, 0x2b46,
+ 0x2b4d, 0x2b73,
+ 0x2b76, 0x2bff,
+ 0x2ce5, 0x2cea,
+ 0x2e50, 0x2e51,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2fff,
+ 0x3004, 0x3004,
+ 0x3012, 0x3013,
+ 0x3020, 0x3020,
+ 0x3036, 0x3037,
+ 0x303e, 0x303f,
+ 0x3190, 0x3191,
+ 0x3196, 0x319f,
+ 0x31c0, 0x31e5,
+ 0x31ef, 0x31ef,
+ 0x3200, 0x321e,
+ 0x322a, 0x3247,
+ 0x3250, 0x3250,
+ 0x3260, 0x327f,
+ 0x328a, 0x32b0,
+ 0x32c0, 0x33ff,
+ 0x4dc0, 0x4dff,
+ 0xa490, 0xa4c6,
+ 0xa828, 0xa82b,
+ 0xa836, 0xa837,
+ 0xa839, 0xa839,
+ 0xaa77, 0xaa79,
+ 0xfbc3, 0xfbd2,
+ 0xfd40, 0xfd4f,
+ 0xfd90, 0xfd91,
+ 0xfdc8, 0xfdcf,
+ 0xfdfd, 0xfdff,
+ 0xffe4, 0xffe4,
+ 0xffe8, 0xffe8,
+ 0xffed, 0xffee,
+ 0xfffc, 0xfffd,
+ 0x10137, 0x1013f,
+ 0x10179, 0x10189,
+ 0x1018c, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fc,
+ 0x10877, 0x10878,
+ 0x10ac8, 0x10ac8,
+ 0x10ed1, 0x10ed8,
+ 0x1173f, 0x1173f,
+ 0x11fd5, 0x11fdc,
+ 0x11fe1, 0x11ff1,
+ 0x16b3c, 0x16b3f,
+ 0x16b45, 0x16b45,
+ 0x1bc9c, 0x1bc9c,
+ 0x1cc00, 0x1ccef,
+ 0x1ccfa, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1ceef,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d164,
+ 0x1d16a, 0x1d16c,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d200, 0x1d241,
+ 0x1d245, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d800, 0x1d9ff,
+ 0x1da37, 0x1da3a,
+ 0x1da6d, 0x1da74,
+ 0x1da76, 0x1da83,
+ 0x1da85, 0x1da86,
+ 0x1e14f, 0x1e14f,
+ 0x1ecac, 0x1ecac,
+ 0x1ed2e, 0x1ed2e,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f10d, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f3fa,
+ 0x1f400, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbef,
+ 0x1fbfa, 0x1fbfa,
+}; /* CR_So */
+
+/* 'Z': Major Category */
+static const OnigCodePoint CR_Z[] = {
+ 8,
+ 0x0020, 0x0020,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Z */
+
+/* 'Zl': General Category */
+static const OnigCodePoint CR_Zl[] = {
+ 1,
+ 0x2028, 0x2028,
+}; /* CR_Zl */
+
+/* 'Zp': General Category */
+static const OnigCodePoint CR_Zp[] = {
+ 1,
+ 0x2029, 0x2029,
+}; /* CR_Zp */
+
+/* 'Zs': General Category */
+static const OnigCodePoint CR_Zs[] = {
+ 7,
+ 0x0020, 0x0020,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x2000, 0x200a,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+}; /* CR_Zs */
+
+/* 'Math': Derived Property */
+static const OnigCodePoint CR_Math[] = {
+ 141,
+ 0x002b, 0x002b,
+ 0x003c, 0x003e,
+ 0x005e, 0x005e,
+ 0x007c, 0x007c,
+ 0x007e, 0x007e,
+ 0x00ac, 0x00ac,
+ 0x00b1, 0x00b1,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x03d0, 0x03d2,
+ 0x03d5, 0x03d5,
+ 0x03f0, 0x03f1,
+ 0x03f4, 0x03f6,
+ 0x0606, 0x0608,
+ 0x2016, 0x2016,
+ 0x2032, 0x2034,
+ 0x2040, 0x2040,
+ 0x2044, 0x2044,
+ 0x2052, 0x2052,
+ 0x2061, 0x2064,
+ 0x207a, 0x207e,
+ 0x208a, 0x208e,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20e6,
+ 0x20eb, 0x20ef,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2128, 0x2129,
+ 0x212c, 0x212d,
+ 0x212f, 0x2131,
+ 0x2133, 0x2138,
+ 0x213c, 0x2149,
+ 0x214b, 0x214b,
+ 0x2190, 0x21a7,
+ 0x21a9, 0x21ae,
+ 0x21b0, 0x21b1,
+ 0x21b6, 0x21b7,
+ 0x21bc, 0x21db,
+ 0x21dd, 0x21dd,
+ 0x21e4, 0x21e5,
+ 0x21f4, 0x22ff,
+ 0x2308, 0x230b,
+ 0x2320, 0x2321,
+ 0x237c, 0x237c,
+ 0x239b, 0x23b5,
+ 0x23b7, 0x23b7,
+ 0x23d0, 0x23d0,
+ 0x23dc, 0x23e2,
+ 0x25a0, 0x25a1,
+ 0x25ae, 0x25b7,
+ 0x25bc, 0x25c1,
+ 0x25c6, 0x25c7,
+ 0x25ca, 0x25cb,
+ 0x25cf, 0x25d3,
+ 0x25e2, 0x25e2,
+ 0x25e4, 0x25e4,
+ 0x25e7, 0x25ec,
+ 0x25f8, 0x25ff,
+ 0x2605, 0x2606,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2660, 0x2663,
+ 0x266d, 0x266f,
+ 0x27c0, 0x27ff,
+ 0x2900, 0x2aff,
+ 0x2b30, 0x2b44,
+ 0x2b47, 0x2b4c,
+ 0xfb29, 0xfb29,
+ 0xfe61, 0xfe66,
+ 0xfe68, 0xfe68,
+ 0xff0b, 0xff0b,
+ 0xff1c, 0xff1e,
+ 0xff3c, 0xff3c,
+ 0xff3e, 0xff3e,
+ 0xff5c, 0xff5c,
+ 0xff5e, 0xff5e,
+ 0xffe2, 0xffe2,
+ 0xffe9, 0xffec,
+ 0x10d8e, 0x10d8f,
+ 0x1cef0, 0x1cef0,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f8d0, 0x1f8d8,
+}; /* CR_Math */
+
+/* 'Alphabetic': Derived Property */
+#define CR_Alphabetic CR_Alpha
+
+/* 'Lowercase': Derived Property */
+#define CR_Lowercase CR_Lower
+
+/* 'Uppercase': Derived Property */
+#define CR_Uppercase CR_Upper
+
+/* 'Cased': Derived Property */
+static const OnigCodePoint CR_Cased[] = {
+ 158,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x01ba,
+ 0x01bc, 0x01bf,
+ 0x01c4, 0x0293,
+ 0x0296, 0x02b8,
+ 0x02c0, 0x02c1,
+ 0x02e0, 0x02e4,
+ 0x0345, 0x0345,
+ 0x0370, 0x0373,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0560, 0x0588,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x10ff,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1d00, 0x1dbf,
+ 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, 0x2134,
+ 0x2139, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x217f,
+ 0x2183, 0x2184,
+ 0x24b6, 0x24e9,
+ 0x2c00, 0x2ce4,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa640, 0xa66d,
+ 0xa680, 0xa69d,
+ 0xa722, 0xa787,
+ 0xa78b, 0xa78e,
+ 0xa790, 0xa7dc,
+ 0xa7f1, 0xa7f6,
+ 0xa7f8, 0xa7fa,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10400, 0x1044f,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10780, 0x10780,
+ 0x10783, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d50, 0x10d65,
+ 0x10d70, 0x10d85,
+ 0x118a0, 0x118df,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 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, 0x1df09,
+ 0x1df0b, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e030, 0x1e06d,
+ 0x1e900, 0x1e943,
+ 0x1f130, 0x1f149,
+ 0x1f150, 0x1f169,
+ 0x1f170, 0x1f189,
+}; /* CR_Cased */
+
+/* 'Case_Ignorable': Derived Property */
+static const OnigCodePoint CR_Case_Ignorable[] = {
+ 464,
+ 0x0027, 0x0027,
+ 0x002e, 0x002e,
+ 0x003a, 0x003a,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x00a8, 0x00a8,
+ 0x00ad, 0x00ad,
+ 0x00af, 0x00af,
+ 0x00b4, 0x00b4,
+ 0x00b7, 0x00b8,
+ 0x02b0, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x0384, 0x0385,
+ 0x0387, 0x0387,
+ 0x0483, 0x0489,
+ 0x0559, 0x0559,
+ 0x055f, 0x055f,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05f4, 0x05f4,
+ 0x0600, 0x0605,
+ 0x0610, 0x061a,
+ 0x061c, 0x061c,
+ 0x0640, 0x0640,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dd,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x070f, 0x070f,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x082d,
+ 0x0859, 0x085b,
+ 0x0888, 0x0888,
+ 0x0890, 0x0891,
+ 0x0897, 0x089f,
+ 0x08c9, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0971, 0x0971,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3f, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b56,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cbf,
+ 0x0cc6, 0x0cc6,
+ 0x0ccc, 0x0ccd,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e46, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x10fc, 0x10fc,
+ 0x135d, 0x135f,
+ 0x1712, 0x1714,
+ 0x1732, 0x1733,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180f,
+ 0x1843, 0x1843,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b34,
+ 0x1b36, 0x1b3a,
+ 0x1b3c, 0x1b3c,
+ 0x1b42, 0x1b42,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1ba9,
+ 0x1bab, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf1,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1c78, 0x1c7d,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1d2c, 0x1d6a,
+ 0x1d78, 0x1d78,
+ 0x1d9b, 0x1dff,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x200b, 0x200f,
+ 0x2018, 0x2019,
+ 0x2024, 0x2024,
+ 0x2027, 0x2027,
+ 0x202a, 0x202e,
+ 0x2060, 0x2064,
+ 0x2066, 0x206f,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20f0,
+ 0x2c7c, 0x2c7d,
+ 0x2cef, 0x2cf1,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x2e2f, 0x2e2f,
+ 0x3005, 0x3005,
+ 0x302a, 0x302d,
+ 0x3031, 0x3035,
+ 0x303b, 0x303b,
+ 0x3099, 0x309e,
+ 0x30fc, 0x30fe,
+ 0xa015, 0xa015,
+ 0xa4f8, 0xa4fd,
+ 0xa60c, 0xa60c,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa67f,
+ 0xa69c, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa700, 0xa721,
+ 0xa770, 0xa770,
+ 0xa788, 0xa78a,
+ 0xa7f1, 0xa7f4,
+ 0xa7f8, 0xa7f9,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9cf, 0xa9cf,
+ 0xa9e5, 0xa9e6,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa70, 0xaa70,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaadd, 0xaadd,
+ 0xaaec, 0xaaed,
+ 0xaaf3, 0xaaf4,
+ 0xaaf6, 0xaaf6,
+ 0xab5b, 0xab5f,
+ 0xab69, 0xab6b,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfbb2, 0xfbc2,
+ 0xfe00, 0xfe0f,
+ 0xfe13, 0xfe13,
+ 0xfe20, 0xfe2f,
+ 0xfe52, 0xfe52,
+ 0xfe55, 0xfe55,
+ 0xfeff, 0xfeff,
+ 0xff07, 0xff07,
+ 0xff0e, 0xff0e,
+ 0xff1a, 0xff1a,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0xffe3, 0xffe3,
+ 0xfff9, 0xfffb,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d4e, 0x10d4e,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d6f,
+ 0x10eab, 0x10eac,
+ 0x10ec5, 0x10ec5,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110bd, 0x110bd,
+ 0x110c2, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11234,
+ 0x11236, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x11340, 0x11340,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113bb, 0x113c0,
+ 0x113ce, 0x113ce,
+ 0x113d0, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b5,
+ 0x116b7, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x1193b, 0x1193c,
+ 0x1193e, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11dd9, 0x11dd9,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f40,
+ 0x11f42, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13430, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16d40, 0x16d42,
+ 0x16d6b, 0x16d6c,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff2, 0x16ff3,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1bc9d, 0x1bc9e,
+ 0x1bca0, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d173, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e13d,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4eb, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e6ff, 0x1e6ff,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94b,
+ 0x1f3fb, 0x1f3ff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Case_Ignorable */
+
+/* 'Changes_When_Lowercased': Derived Property */
+static const OnigCodePoint CR_Changes_When_Lowercased[] = {
+ 618,
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x014a, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c5,
+ 0x01c7, 0x01c8,
+ 0x01ca, 0x01cb,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f2,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03cf, 0x03cf,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f4, 0x03f4,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13a0, 0x13f5,
+ 0x1c89, 0x1c89,
+ 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,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fb8, 0x1fbc,
+ 0x1fc8, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffc,
+ 0x2126, 0x2126,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 0x1e900, 0x1e921,
+}; /* CR_Changes_When_Lowercased */
+
+/* 'Changes_When_Uppercased': Derived Property */
+static const OnigCodePoint CR_Changes_When_Uppercased[] = {
+ 634,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0137,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018c,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01b9,
+ 0x01bd, 0x01bd,
+ 0x01bf, 0x01bf,
+ 0x01c5, 0x01c6,
+ 0x01c8, 0x01c9,
+ 0x01cb, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f0,
+ 0x01f2, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0233,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0254,
+ 0x0256, 0x0257,
+ 0x0259, 0x0259,
+ 0x025b, 0x025c,
+ 0x0260, 0x0261,
+ 0x0263, 0x0266,
+ 0x0268, 0x026c,
+ 0x026f, 0x026f,
+ 0x0271, 0x0272,
+ 0x0275, 0x0275,
+ 0x027d, 0x027d,
+ 0x0280, 0x0280,
+ 0x0282, 0x0283,
+ 0x0287, 0x028c,
+ 0x0292, 0x0292,
+ 0x029d, 0x029e,
+ 0x0345, 0x0345,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037b, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fb,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0561, 0x0587,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d79, 0x1d79,
+ 0x1d7d, 0x1d7d,
+ 0x1d8e, 0x1d8e,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9b,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbc, 0x1fbc,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fcc, 0x1fcc,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x1ffc, 0x1ffc,
+ 0x214e, 0x214e,
+ 0x2170, 0x217f,
+ 0x2184, 0x2184,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c73, 0x2c73,
+ 0x2c76, 0x2c76,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce3,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69b,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa72f,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa76f,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa791, 0xa791,
+ 0xa793, 0xa794,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f6, 0xa7f6,
+ 0xab53, 0xab53,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1e922, 0x1e943,
+}; /* CR_Changes_When_Uppercased */
+
+/* 'Changes_When_Titlecased': Derived Property */
+static const OnigCodePoint CR_Changes_When_Titlecased[] = {
+ 633,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0101, 0x0101,
+ 0x0103, 0x0103,
+ 0x0105, 0x0105,
+ 0x0107, 0x0107,
+ 0x0109, 0x0109,
+ 0x010b, 0x010b,
+ 0x010d, 0x010d,
+ 0x010f, 0x010f,
+ 0x0111, 0x0111,
+ 0x0113, 0x0113,
+ 0x0115, 0x0115,
+ 0x0117, 0x0117,
+ 0x0119, 0x0119,
+ 0x011b, 0x011b,
+ 0x011d, 0x011d,
+ 0x011f, 0x011f,
+ 0x0121, 0x0121,
+ 0x0123, 0x0123,
+ 0x0125, 0x0125,
+ 0x0127, 0x0127,
+ 0x0129, 0x0129,
+ 0x012b, 0x012b,
+ 0x012d, 0x012d,
+ 0x012f, 0x012f,
+ 0x0131, 0x0131,
+ 0x0133, 0x0133,
+ 0x0135, 0x0135,
+ 0x0137, 0x0137,
+ 0x013a, 0x013a,
+ 0x013c, 0x013c,
+ 0x013e, 0x013e,
+ 0x0140, 0x0140,
+ 0x0142, 0x0142,
+ 0x0144, 0x0144,
+ 0x0146, 0x0146,
+ 0x0148, 0x0149,
+ 0x014b, 0x014b,
+ 0x014d, 0x014d,
+ 0x014f, 0x014f,
+ 0x0151, 0x0151,
+ 0x0153, 0x0153,
+ 0x0155, 0x0155,
+ 0x0157, 0x0157,
+ 0x0159, 0x0159,
+ 0x015b, 0x015b,
+ 0x015d, 0x015d,
+ 0x015f, 0x015f,
+ 0x0161, 0x0161,
+ 0x0163, 0x0163,
+ 0x0165, 0x0165,
+ 0x0167, 0x0167,
+ 0x0169, 0x0169,
+ 0x016b, 0x016b,
+ 0x016d, 0x016d,
+ 0x016f, 0x016f,
+ 0x0171, 0x0171,
+ 0x0173, 0x0173,
+ 0x0175, 0x0175,
+ 0x0177, 0x0177,
+ 0x017a, 0x017a,
+ 0x017c, 0x017c,
+ 0x017e, 0x0180,
+ 0x0183, 0x0183,
+ 0x0185, 0x0185,
+ 0x0188, 0x0188,
+ 0x018c, 0x018c,
+ 0x0192, 0x0192,
+ 0x0195, 0x0195,
+ 0x0199, 0x019b,
+ 0x019e, 0x019e,
+ 0x01a1, 0x01a1,
+ 0x01a3, 0x01a3,
+ 0x01a5, 0x01a5,
+ 0x01a8, 0x01a8,
+ 0x01ad, 0x01ad,
+ 0x01b0, 0x01b0,
+ 0x01b4, 0x01b4,
+ 0x01b6, 0x01b6,
+ 0x01b9, 0x01b9,
+ 0x01bd, 0x01bd,
+ 0x01bf, 0x01bf,
+ 0x01c4, 0x01c4,
+ 0x01c6, 0x01c7,
+ 0x01c9, 0x01ca,
+ 0x01cc, 0x01cc,
+ 0x01ce, 0x01ce,
+ 0x01d0, 0x01d0,
+ 0x01d2, 0x01d2,
+ 0x01d4, 0x01d4,
+ 0x01d6, 0x01d6,
+ 0x01d8, 0x01d8,
+ 0x01da, 0x01da,
+ 0x01dc, 0x01dd,
+ 0x01df, 0x01df,
+ 0x01e1, 0x01e1,
+ 0x01e3, 0x01e3,
+ 0x01e5, 0x01e5,
+ 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9,
+ 0x01eb, 0x01eb,
+ 0x01ed, 0x01ed,
+ 0x01ef, 0x01f1,
+ 0x01f3, 0x01f3,
+ 0x01f5, 0x01f5,
+ 0x01f9, 0x01f9,
+ 0x01fb, 0x01fb,
+ 0x01fd, 0x01fd,
+ 0x01ff, 0x01ff,
+ 0x0201, 0x0201,
+ 0x0203, 0x0203,
+ 0x0205, 0x0205,
+ 0x0207, 0x0207,
+ 0x0209, 0x0209,
+ 0x020b, 0x020b,
+ 0x020d, 0x020d,
+ 0x020f, 0x020f,
+ 0x0211, 0x0211,
+ 0x0213, 0x0213,
+ 0x0215, 0x0215,
+ 0x0217, 0x0217,
+ 0x0219, 0x0219,
+ 0x021b, 0x021b,
+ 0x021d, 0x021d,
+ 0x021f, 0x021f,
+ 0x0223, 0x0223,
+ 0x0225, 0x0225,
+ 0x0227, 0x0227,
+ 0x0229, 0x0229,
+ 0x022b, 0x022b,
+ 0x022d, 0x022d,
+ 0x022f, 0x022f,
+ 0x0231, 0x0231,
+ 0x0233, 0x0233,
+ 0x023c, 0x023c,
+ 0x023f, 0x0240,
+ 0x0242, 0x0242,
+ 0x0247, 0x0247,
+ 0x0249, 0x0249,
+ 0x024b, 0x024b,
+ 0x024d, 0x024d,
+ 0x024f, 0x0254,
+ 0x0256, 0x0257,
+ 0x0259, 0x0259,
+ 0x025b, 0x025c,
+ 0x0260, 0x0261,
+ 0x0263, 0x0266,
+ 0x0268, 0x026c,
+ 0x026f, 0x026f,
+ 0x0271, 0x0272,
+ 0x0275, 0x0275,
+ 0x027d, 0x027d,
+ 0x0280, 0x0280,
+ 0x0282, 0x0283,
+ 0x0287, 0x028c,
+ 0x0292, 0x0292,
+ 0x029d, 0x029e,
+ 0x0345, 0x0345,
+ 0x0371, 0x0371,
+ 0x0373, 0x0373,
+ 0x0377, 0x0377,
+ 0x037b, 0x037d,
+ 0x0390, 0x0390,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03d9, 0x03d9,
+ 0x03db, 0x03db,
+ 0x03dd, 0x03dd,
+ 0x03df, 0x03df,
+ 0x03e1, 0x03e1,
+ 0x03e3, 0x03e3,
+ 0x03e5, 0x03e5,
+ 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9,
+ 0x03eb, 0x03eb,
+ 0x03ed, 0x03ed,
+ 0x03ef, 0x03f3,
+ 0x03f5, 0x03f5,
+ 0x03f8, 0x03f8,
+ 0x03fb, 0x03fb,
+ 0x0430, 0x045f,
+ 0x0461, 0x0461,
+ 0x0463, 0x0463,
+ 0x0465, 0x0465,
+ 0x0467, 0x0467,
+ 0x0469, 0x0469,
+ 0x046b, 0x046b,
+ 0x046d, 0x046d,
+ 0x046f, 0x046f,
+ 0x0471, 0x0471,
+ 0x0473, 0x0473,
+ 0x0475, 0x0475,
+ 0x0477, 0x0477,
+ 0x0479, 0x0479,
+ 0x047b, 0x047b,
+ 0x047d, 0x047d,
+ 0x047f, 0x047f,
+ 0x0481, 0x0481,
+ 0x048b, 0x048b,
+ 0x048d, 0x048d,
+ 0x048f, 0x048f,
+ 0x0491, 0x0491,
+ 0x0493, 0x0493,
+ 0x0495, 0x0495,
+ 0x0497, 0x0497,
+ 0x0499, 0x0499,
+ 0x049b, 0x049b,
+ 0x049d, 0x049d,
+ 0x049f, 0x049f,
+ 0x04a1, 0x04a1,
+ 0x04a3, 0x04a3,
+ 0x04a5, 0x04a5,
+ 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9,
+ 0x04ab, 0x04ab,
+ 0x04ad, 0x04ad,
+ 0x04af, 0x04af,
+ 0x04b1, 0x04b1,
+ 0x04b3, 0x04b3,
+ 0x04b5, 0x04b5,
+ 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9,
+ 0x04bb, 0x04bb,
+ 0x04bd, 0x04bd,
+ 0x04bf, 0x04bf,
+ 0x04c2, 0x04c2,
+ 0x04c4, 0x04c4,
+ 0x04c6, 0x04c6,
+ 0x04c8, 0x04c8,
+ 0x04ca, 0x04ca,
+ 0x04cc, 0x04cc,
+ 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1,
+ 0x04d3, 0x04d3,
+ 0x04d5, 0x04d5,
+ 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9,
+ 0x04db, 0x04db,
+ 0x04dd, 0x04dd,
+ 0x04df, 0x04df,
+ 0x04e1, 0x04e1,
+ 0x04e3, 0x04e3,
+ 0x04e5, 0x04e5,
+ 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9,
+ 0x04eb, 0x04eb,
+ 0x04ed, 0x04ed,
+ 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1,
+ 0x04f3, 0x04f3,
+ 0x04f5, 0x04f5,
+ 0x04f7, 0x04f7,
+ 0x04f9, 0x04f9,
+ 0x04fb, 0x04fb,
+ 0x04fd, 0x04fd,
+ 0x04ff, 0x04ff,
+ 0x0501, 0x0501,
+ 0x0503, 0x0503,
+ 0x0505, 0x0505,
+ 0x0507, 0x0507,
+ 0x0509, 0x0509,
+ 0x050b, 0x050b,
+ 0x050d, 0x050d,
+ 0x050f, 0x050f,
+ 0x0511, 0x0511,
+ 0x0513, 0x0513,
+ 0x0515, 0x0515,
+ 0x0517, 0x0517,
+ 0x0519, 0x0519,
+ 0x051b, 0x051b,
+ 0x051d, 0x051d,
+ 0x051f, 0x051f,
+ 0x0521, 0x0521,
+ 0x0523, 0x0523,
+ 0x0525, 0x0525,
+ 0x0527, 0x0527,
+ 0x0529, 0x0529,
+ 0x052b, 0x052b,
+ 0x052d, 0x052d,
+ 0x052f, 0x052f,
+ 0x0561, 0x0587,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c88,
+ 0x1c8a, 0x1c8a,
+ 0x1d79, 0x1d79,
+ 0x1d7d, 0x1d7d,
+ 0x1d8e, 0x1d8e,
+ 0x1e01, 0x1e01,
+ 0x1e03, 0x1e03,
+ 0x1e05, 0x1e05,
+ 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09,
+ 0x1e0b, 0x1e0b,
+ 0x1e0d, 0x1e0d,
+ 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11,
+ 0x1e13, 0x1e13,
+ 0x1e15, 0x1e15,
+ 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19,
+ 0x1e1b, 0x1e1b,
+ 0x1e1d, 0x1e1d,
+ 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21,
+ 0x1e23, 0x1e23,
+ 0x1e25, 0x1e25,
+ 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29,
+ 0x1e2b, 0x1e2b,
+ 0x1e2d, 0x1e2d,
+ 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31,
+ 0x1e33, 0x1e33,
+ 0x1e35, 0x1e35,
+ 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39,
+ 0x1e3b, 0x1e3b,
+ 0x1e3d, 0x1e3d,
+ 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41,
+ 0x1e43, 0x1e43,
+ 0x1e45, 0x1e45,
+ 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49,
+ 0x1e4b, 0x1e4b,
+ 0x1e4d, 0x1e4d,
+ 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51,
+ 0x1e53, 0x1e53,
+ 0x1e55, 0x1e55,
+ 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59,
+ 0x1e5b, 0x1e5b,
+ 0x1e5d, 0x1e5d,
+ 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61,
+ 0x1e63, 0x1e63,
+ 0x1e65, 0x1e65,
+ 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69,
+ 0x1e6b, 0x1e6b,
+ 0x1e6d, 0x1e6d,
+ 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71,
+ 0x1e73, 0x1e73,
+ 0x1e75, 0x1e75,
+ 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79,
+ 0x1e7b, 0x1e7b,
+ 0x1e7d, 0x1e7d,
+ 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81,
+ 0x1e83, 0x1e83,
+ 0x1e85, 0x1e85,
+ 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89,
+ 0x1e8b, 0x1e8b,
+ 0x1e8d, 0x1e8d,
+ 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91,
+ 0x1e93, 0x1e93,
+ 0x1e95, 0x1e9b,
+ 0x1ea1, 0x1ea1,
+ 0x1ea3, 0x1ea3,
+ 0x1ea5, 0x1ea5,
+ 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9,
+ 0x1eab, 0x1eab,
+ 0x1ead, 0x1ead,
+ 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1,
+ 0x1eb3, 0x1eb3,
+ 0x1eb5, 0x1eb5,
+ 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9,
+ 0x1ebb, 0x1ebb,
+ 0x1ebd, 0x1ebd,
+ 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1,
+ 0x1ec3, 0x1ec3,
+ 0x1ec5, 0x1ec5,
+ 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9,
+ 0x1ecb, 0x1ecb,
+ 0x1ecd, 0x1ecd,
+ 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1,
+ 0x1ed3, 0x1ed3,
+ 0x1ed5, 0x1ed5,
+ 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9,
+ 0x1edb, 0x1edb,
+ 0x1edd, 0x1edd,
+ 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1,
+ 0x1ee3, 0x1ee3,
+ 0x1ee5, 0x1ee5,
+ 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9,
+ 0x1eeb, 0x1eeb,
+ 0x1eed, 0x1eed,
+ 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1,
+ 0x1ef3, 0x1ef3,
+ 0x1ef5, 0x1ef5,
+ 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9,
+ 0x1efb, 0x1efb,
+ 0x1efd, 0x1efd,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fbe, 0x1fbe,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x214e, 0x214e,
+ 0x2170, 0x217f,
+ 0x2184, 0x2184,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5f,
+ 0x2c61, 0x2c61,
+ 0x2c65, 0x2c66,
+ 0x2c68, 0x2c68,
+ 0x2c6a, 0x2c6a,
+ 0x2c6c, 0x2c6c,
+ 0x2c73, 0x2c73,
+ 0x2c76, 0x2c76,
+ 0x2c81, 0x2c81,
+ 0x2c83, 0x2c83,
+ 0x2c85, 0x2c85,
+ 0x2c87, 0x2c87,
+ 0x2c89, 0x2c89,
+ 0x2c8b, 0x2c8b,
+ 0x2c8d, 0x2c8d,
+ 0x2c8f, 0x2c8f,
+ 0x2c91, 0x2c91,
+ 0x2c93, 0x2c93,
+ 0x2c95, 0x2c95,
+ 0x2c97, 0x2c97,
+ 0x2c99, 0x2c99,
+ 0x2c9b, 0x2c9b,
+ 0x2c9d, 0x2c9d,
+ 0x2c9f, 0x2c9f,
+ 0x2ca1, 0x2ca1,
+ 0x2ca3, 0x2ca3,
+ 0x2ca5, 0x2ca5,
+ 0x2ca7, 0x2ca7,
+ 0x2ca9, 0x2ca9,
+ 0x2cab, 0x2cab,
+ 0x2cad, 0x2cad,
+ 0x2caf, 0x2caf,
+ 0x2cb1, 0x2cb1,
+ 0x2cb3, 0x2cb3,
+ 0x2cb5, 0x2cb5,
+ 0x2cb7, 0x2cb7,
+ 0x2cb9, 0x2cb9,
+ 0x2cbb, 0x2cbb,
+ 0x2cbd, 0x2cbd,
+ 0x2cbf, 0x2cbf,
+ 0x2cc1, 0x2cc1,
+ 0x2cc3, 0x2cc3,
+ 0x2cc5, 0x2cc5,
+ 0x2cc7, 0x2cc7,
+ 0x2cc9, 0x2cc9,
+ 0x2ccb, 0x2ccb,
+ 0x2ccd, 0x2ccd,
+ 0x2ccf, 0x2ccf,
+ 0x2cd1, 0x2cd1,
+ 0x2cd3, 0x2cd3,
+ 0x2cd5, 0x2cd5,
+ 0x2cd7, 0x2cd7,
+ 0x2cd9, 0x2cd9,
+ 0x2cdb, 0x2cdb,
+ 0x2cdd, 0x2cdd,
+ 0x2cdf, 0x2cdf,
+ 0x2ce1, 0x2ce1,
+ 0x2ce3, 0x2ce3,
+ 0x2cec, 0x2cec,
+ 0x2cee, 0x2cee,
+ 0x2cf3, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa641, 0xa641,
+ 0xa643, 0xa643,
+ 0xa645, 0xa645,
+ 0xa647, 0xa647,
+ 0xa649, 0xa649,
+ 0xa64b, 0xa64b,
+ 0xa64d, 0xa64d,
+ 0xa64f, 0xa64f,
+ 0xa651, 0xa651,
+ 0xa653, 0xa653,
+ 0xa655, 0xa655,
+ 0xa657, 0xa657,
+ 0xa659, 0xa659,
+ 0xa65b, 0xa65b,
+ 0xa65d, 0xa65d,
+ 0xa65f, 0xa65f,
+ 0xa661, 0xa661,
+ 0xa663, 0xa663,
+ 0xa665, 0xa665,
+ 0xa667, 0xa667,
+ 0xa669, 0xa669,
+ 0xa66b, 0xa66b,
+ 0xa66d, 0xa66d,
+ 0xa681, 0xa681,
+ 0xa683, 0xa683,
+ 0xa685, 0xa685,
+ 0xa687, 0xa687,
+ 0xa689, 0xa689,
+ 0xa68b, 0xa68b,
+ 0xa68d, 0xa68d,
+ 0xa68f, 0xa68f,
+ 0xa691, 0xa691,
+ 0xa693, 0xa693,
+ 0xa695, 0xa695,
+ 0xa697, 0xa697,
+ 0xa699, 0xa699,
+ 0xa69b, 0xa69b,
+ 0xa723, 0xa723,
+ 0xa725, 0xa725,
+ 0xa727, 0xa727,
+ 0xa729, 0xa729,
+ 0xa72b, 0xa72b,
+ 0xa72d, 0xa72d,
+ 0xa72f, 0xa72f,
+ 0xa733, 0xa733,
+ 0xa735, 0xa735,
+ 0xa737, 0xa737,
+ 0xa739, 0xa739,
+ 0xa73b, 0xa73b,
+ 0xa73d, 0xa73d,
+ 0xa73f, 0xa73f,
+ 0xa741, 0xa741,
+ 0xa743, 0xa743,
+ 0xa745, 0xa745,
+ 0xa747, 0xa747,
+ 0xa749, 0xa749,
+ 0xa74b, 0xa74b,
+ 0xa74d, 0xa74d,
+ 0xa74f, 0xa74f,
+ 0xa751, 0xa751,
+ 0xa753, 0xa753,
+ 0xa755, 0xa755,
+ 0xa757, 0xa757,
+ 0xa759, 0xa759,
+ 0xa75b, 0xa75b,
+ 0xa75d, 0xa75d,
+ 0xa75f, 0xa75f,
+ 0xa761, 0xa761,
+ 0xa763, 0xa763,
+ 0xa765, 0xa765,
+ 0xa767, 0xa767,
+ 0xa769, 0xa769,
+ 0xa76b, 0xa76b,
+ 0xa76d, 0xa76d,
+ 0xa76f, 0xa76f,
+ 0xa77a, 0xa77a,
+ 0xa77c, 0xa77c,
+ 0xa77f, 0xa77f,
+ 0xa781, 0xa781,
+ 0xa783, 0xa783,
+ 0xa785, 0xa785,
+ 0xa787, 0xa787,
+ 0xa78c, 0xa78c,
+ 0xa791, 0xa791,
+ 0xa793, 0xa794,
+ 0xa797, 0xa797,
+ 0xa799, 0xa799,
+ 0xa79b, 0xa79b,
+ 0xa79d, 0xa79d,
+ 0xa79f, 0xa79f,
+ 0xa7a1, 0xa7a1,
+ 0xa7a3, 0xa7a3,
+ 0xa7a5, 0xa7a5,
+ 0xa7a7, 0xa7a7,
+ 0xa7a9, 0xa7a9,
+ 0xa7b5, 0xa7b5,
+ 0xa7b7, 0xa7b7,
+ 0xa7b9, 0xa7b9,
+ 0xa7bb, 0xa7bb,
+ 0xa7bd, 0xa7bd,
+ 0xa7bf, 0xa7bf,
+ 0xa7c1, 0xa7c1,
+ 0xa7c3, 0xa7c3,
+ 0xa7c8, 0xa7c8,
+ 0xa7ca, 0xa7ca,
+ 0xa7cd, 0xa7cd,
+ 0xa7cf, 0xa7cf,
+ 0xa7d1, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d5,
+ 0xa7d7, 0xa7d7,
+ 0xa7d9, 0xa7d9,
+ 0xa7db, 0xa7db,
+ 0xa7f6, 0xa7f6,
+ 0xab53, 0xab53,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x104d8, 0x104fb,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10cc0, 0x10cf2,
+ 0x10d70, 0x10d85,
+ 0x118c0, 0x118df,
+ 0x16e60, 0x16e7f,
+ 0x16ebb, 0x16ed3,
+ 0x1e922, 0x1e943,
+}; /* CR_Changes_When_Titlecased */
+
+/* 'Changes_When_Casefolded': Derived Property */
+static const OnigCodePoint CR_Changes_When_Casefolded[] = {
+ 630,
+ 0x0041, 0x005a,
+ 0x00b5, 0x00b5,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00df,
+ 0x0100, 0x0100,
+ 0x0102, 0x0102,
+ 0x0104, 0x0104,
+ 0x0106, 0x0106,
+ 0x0108, 0x0108,
+ 0x010a, 0x010a,
+ 0x010c, 0x010c,
+ 0x010e, 0x010e,
+ 0x0110, 0x0110,
+ 0x0112, 0x0112,
+ 0x0114, 0x0114,
+ 0x0116, 0x0116,
+ 0x0118, 0x0118,
+ 0x011a, 0x011a,
+ 0x011c, 0x011c,
+ 0x011e, 0x011e,
+ 0x0120, 0x0120,
+ 0x0122, 0x0122,
+ 0x0124, 0x0124,
+ 0x0126, 0x0126,
+ 0x0128, 0x0128,
+ 0x012a, 0x012a,
+ 0x012c, 0x012c,
+ 0x012e, 0x012e,
+ 0x0130, 0x0130,
+ 0x0132, 0x0132,
+ 0x0134, 0x0134,
+ 0x0136, 0x0136,
+ 0x0139, 0x0139,
+ 0x013b, 0x013b,
+ 0x013d, 0x013d,
+ 0x013f, 0x013f,
+ 0x0141, 0x0141,
+ 0x0143, 0x0143,
+ 0x0145, 0x0145,
+ 0x0147, 0x0147,
+ 0x0149, 0x014a,
+ 0x014c, 0x014c,
+ 0x014e, 0x014e,
+ 0x0150, 0x0150,
+ 0x0152, 0x0152,
+ 0x0154, 0x0154,
+ 0x0156, 0x0156,
+ 0x0158, 0x0158,
+ 0x015a, 0x015a,
+ 0x015c, 0x015c,
+ 0x015e, 0x015e,
+ 0x0160, 0x0160,
+ 0x0162, 0x0162,
+ 0x0164, 0x0164,
+ 0x0166, 0x0166,
+ 0x0168, 0x0168,
+ 0x016a, 0x016a,
+ 0x016c, 0x016c,
+ 0x016e, 0x016e,
+ 0x0170, 0x0170,
+ 0x0172, 0x0172,
+ 0x0174, 0x0174,
+ 0x0176, 0x0176,
+ 0x0178, 0x0179,
+ 0x017b, 0x017b,
+ 0x017d, 0x017d,
+ 0x017f, 0x017f,
+ 0x0181, 0x0182,
+ 0x0184, 0x0184,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a2, 0x01a2,
+ 0x01a4, 0x01a4,
+ 0x01a6, 0x01a7,
+ 0x01a9, 0x01a9,
+ 0x01ac, 0x01ac,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b5, 0x01b5,
+ 0x01b7, 0x01b8,
+ 0x01bc, 0x01bc,
+ 0x01c4, 0x01c5,
+ 0x01c7, 0x01c8,
+ 0x01ca, 0x01cb,
+ 0x01cd, 0x01cd,
+ 0x01cf, 0x01cf,
+ 0x01d1, 0x01d1,
+ 0x01d3, 0x01d3,
+ 0x01d5, 0x01d5,
+ 0x01d7, 0x01d7,
+ 0x01d9, 0x01d9,
+ 0x01db, 0x01db,
+ 0x01de, 0x01de,
+ 0x01e0, 0x01e0,
+ 0x01e2, 0x01e2,
+ 0x01e4, 0x01e4,
+ 0x01e6, 0x01e6,
+ 0x01e8, 0x01e8,
+ 0x01ea, 0x01ea,
+ 0x01ec, 0x01ec,
+ 0x01ee, 0x01ee,
+ 0x01f1, 0x01f2,
+ 0x01f4, 0x01f4,
+ 0x01f6, 0x01f8,
+ 0x01fa, 0x01fa,
+ 0x01fc, 0x01fc,
+ 0x01fe, 0x01fe,
+ 0x0200, 0x0200,
+ 0x0202, 0x0202,
+ 0x0204, 0x0204,
+ 0x0206, 0x0206,
+ 0x0208, 0x0208,
+ 0x020a, 0x020a,
+ 0x020c, 0x020c,
+ 0x020e, 0x020e,
+ 0x0210, 0x0210,
+ 0x0212, 0x0212,
+ 0x0214, 0x0214,
+ 0x0216, 0x0216,
+ 0x0218, 0x0218,
+ 0x021a, 0x021a,
+ 0x021c, 0x021c,
+ 0x021e, 0x021e,
+ 0x0220, 0x0220,
+ 0x0222, 0x0222,
+ 0x0224, 0x0224,
+ 0x0226, 0x0226,
+ 0x0228, 0x0228,
+ 0x022a, 0x022a,
+ 0x022c, 0x022c,
+ 0x022e, 0x022e,
+ 0x0230, 0x0230,
+ 0x0232, 0x0232,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0241, 0x0241,
+ 0x0243, 0x0246,
+ 0x0248, 0x0248,
+ 0x024a, 0x024a,
+ 0x024c, 0x024c,
+ 0x024e, 0x024e,
+ 0x0345, 0x0345,
+ 0x0370, 0x0370,
+ 0x0372, 0x0372,
+ 0x0376, 0x0376,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03c2, 0x03c2,
+ 0x03cf, 0x03d1,
+ 0x03d5, 0x03d6,
+ 0x03d8, 0x03d8,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03e2,
+ 0x03e4, 0x03e4,
+ 0x03e6, 0x03e6,
+ 0x03e8, 0x03e8,
+ 0x03ea, 0x03ea,
+ 0x03ec, 0x03ec,
+ 0x03ee, 0x03ee,
+ 0x03f0, 0x03f1,
+ 0x03f4, 0x03f5,
+ 0x03f7, 0x03f7,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x0460, 0x0460,
+ 0x0462, 0x0462,
+ 0x0464, 0x0464,
+ 0x0466, 0x0466,
+ 0x0468, 0x0468,
+ 0x046a, 0x046a,
+ 0x046c, 0x046c,
+ 0x046e, 0x046e,
+ 0x0470, 0x0470,
+ 0x0472, 0x0472,
+ 0x0474, 0x0474,
+ 0x0476, 0x0476,
+ 0x0478, 0x0478,
+ 0x047a, 0x047a,
+ 0x047c, 0x047c,
+ 0x047e, 0x047e,
+ 0x0480, 0x0480,
+ 0x048a, 0x048a,
+ 0x048c, 0x048c,
+ 0x048e, 0x048e,
+ 0x0490, 0x0490,
+ 0x0492, 0x0492,
+ 0x0494, 0x0494,
+ 0x0496, 0x0496,
+ 0x0498, 0x0498,
+ 0x049a, 0x049a,
+ 0x049c, 0x049c,
+ 0x049e, 0x049e,
+ 0x04a0, 0x04a0,
+ 0x04a2, 0x04a2,
+ 0x04a4, 0x04a4,
+ 0x04a6, 0x04a6,
+ 0x04a8, 0x04a8,
+ 0x04aa, 0x04aa,
+ 0x04ac, 0x04ac,
+ 0x04ae, 0x04ae,
+ 0x04b0, 0x04b0,
+ 0x04b2, 0x04b2,
+ 0x04b4, 0x04b4,
+ 0x04b6, 0x04b6,
+ 0x04b8, 0x04b8,
+ 0x04ba, 0x04ba,
+ 0x04bc, 0x04bc,
+ 0x04be, 0x04be,
+ 0x04c0, 0x04c1,
+ 0x04c3, 0x04c3,
+ 0x04c5, 0x04c5,
+ 0x04c7, 0x04c7,
+ 0x04c9, 0x04c9,
+ 0x04cb, 0x04cb,
+ 0x04cd, 0x04cd,
+ 0x04d0, 0x04d0,
+ 0x04d2, 0x04d2,
+ 0x04d4, 0x04d4,
+ 0x04d6, 0x04d6,
+ 0x04d8, 0x04d8,
+ 0x04da, 0x04da,
+ 0x04dc, 0x04dc,
+ 0x04de, 0x04de,
+ 0x04e0, 0x04e0,
+ 0x04e2, 0x04e2,
+ 0x04e4, 0x04e4,
+ 0x04e6, 0x04e6,
+ 0x04e8, 0x04e8,
+ 0x04ea, 0x04ea,
+ 0x04ec, 0x04ec,
+ 0x04ee, 0x04ee,
+ 0x04f0, 0x04f0,
+ 0x04f2, 0x04f2,
+ 0x04f4, 0x04f4,
+ 0x04f6, 0x04f6,
+ 0x04f8, 0x04f8,
+ 0x04fa, 0x04fa,
+ 0x04fc, 0x04fc,
+ 0x04fe, 0x04fe,
+ 0x0500, 0x0500,
+ 0x0502, 0x0502,
+ 0x0504, 0x0504,
+ 0x0506, 0x0506,
+ 0x0508, 0x0508,
+ 0x050a, 0x050a,
+ 0x050c, 0x050c,
+ 0x050e, 0x050e,
+ 0x0510, 0x0510,
+ 0x0512, 0x0512,
+ 0x0514, 0x0514,
+ 0x0516, 0x0516,
+ 0x0518, 0x0518,
+ 0x051a, 0x051a,
+ 0x051c, 0x051c,
+ 0x051e, 0x051e,
+ 0x0520, 0x0520,
+ 0x0522, 0x0522,
+ 0x0524, 0x0524,
+ 0x0526, 0x0526,
+ 0x0528, 0x0528,
+ 0x052a, 0x052a,
+ 0x052c, 0x052c,
+ 0x052e, 0x052e,
+ 0x0531, 0x0556,
+ 0x0587, 0x0587,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c89,
+ 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,
+ 0x1e9a, 0x1e9b,
+ 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,
+ 0x1f80, 0x1faf,
+ 0x1fb2, 0x1fb4,
+ 0x1fb7, 0x1fbc,
+ 0x1fc2, 0x1fc4,
+ 0x1fc7, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff2, 0x1ff4,
+ 0x1ff7, 0x1ffc,
+ 0x2126, 0x2126,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 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,
+ 0xa7cb, 0xa7cc,
+ 0xa7ce, 0xa7ce,
+ 0xa7d0, 0xa7d0,
+ 0xa7d2, 0xa7d2,
+ 0xa7d4, 0xa7d4,
+ 0xa7d6, 0xa7d6,
+ 0xa7d8, 0xa7d8,
+ 0xa7da, 0xa7da,
+ 0xa7dc, 0xa7dc,
+ 0xa7f5, 0xa7f5,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x104b0, 0x104d3,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10c80, 0x10cb2,
+ 0x10d50, 0x10d65,
+ 0x118a0, 0x118bf,
+ 0x16e40, 0x16e5f,
+ 0x16ea0, 0x16eb8,
+ 0x1e900, 0x1e921,
+}; /* CR_Changes_When_Casefolded */
+
+/* 'Changes_When_Casemapped': Derived Property */
+static const OnigCodePoint CR_Changes_When_Casemapped[] = {
+ 131,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00b5, 0x00b5,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x0137,
+ 0x0139, 0x018c,
+ 0x018e, 0x01a9,
+ 0x01ac, 0x01b9,
+ 0x01bc, 0x01bd,
+ 0x01bf, 0x01bf,
+ 0x01c4, 0x0220,
+ 0x0222, 0x0233,
+ 0x023a, 0x0254,
+ 0x0256, 0x0257,
+ 0x0259, 0x0259,
+ 0x025b, 0x025c,
+ 0x0260, 0x0261,
+ 0x0263, 0x0266,
+ 0x0268, 0x026c,
+ 0x026f, 0x026f,
+ 0x0271, 0x0272,
+ 0x0275, 0x0275,
+ 0x027d, 0x027d,
+ 0x0280, 0x0280,
+ 0x0282, 0x0283,
+ 0x0287, 0x028c,
+ 0x0292, 0x0292,
+ 0x029d, 0x029e,
+ 0x0345, 0x0345,
+ 0x0370, 0x0373,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03d1,
+ 0x03d5, 0x03f5,
+ 0x03f7, 0x03fb,
+ 0x03fd, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0561, 0x0587,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fd, 0x10ff,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1d79, 0x1d79,
+ 0x1d7d, 0x1d7d,
+ 0x1d8e, 0x1d8e,
+ 0x1e00, 0x1e9b,
+ 0x1e9e, 0x1e9e,
+ 0x1ea0, 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,
+ 0x2126, 0x2126,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 0x214e, 0x214e,
+ 0x2160, 0x217f,
+ 0x2183, 0x2184,
+ 0x24b6, 0x24e9,
+ 0x2c00, 0x2c70,
+ 0x2c72, 0x2c73,
+ 0x2c75, 0x2c76,
+ 0x2c7e, 0x2ce3,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0xa640, 0xa66d,
+ 0xa680, 0xa69b,
+ 0xa722, 0xa72f,
+ 0xa732, 0xa76f,
+ 0xa779, 0xa787,
+ 0xa78b, 0xa78d,
+ 0xa790, 0xa794,
+ 0xa796, 0xa7ae,
+ 0xa7b0, 0xa7dc,
+ 0xa7f5, 0xa7f6,
+ 0xab53, 0xab53,
+ 0xab70, 0xabbf,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10400, 0x1044f,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d50, 0x10d65,
+ 0x10d70, 0x10d85,
+ 0x118a0, 0x118df,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x1e900, 0x1e943,
+}; /* CR_Changes_When_Casemapped */
+
+/* 'ID_Start': Derived Property */
+static const OnigCodePoint CR_ID_Start[] = {
+ 684,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0971, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 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, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1878,
+ 0x1880, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1aa7, 0x1aa7,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 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,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 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,
+ 0x3005, 0x3007,
+ 0x3021, 0x3029,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x309b, 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,
+ 0xa67f, 0xa69d,
+ 0xa6a0, 0xa6ef,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9cf, 0xa9cf,
+ 0xa9e0, 0xa9e4,
+ 0xa9e6, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 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, 0x10375,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 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, 0x10d23,
+ 0x10d4a, 0x10d65,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118a0, 0x118df,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 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,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e900, 0x1e943,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_ID_Start */
+
+/* 'ID_Continue': Derived Property */
+static const OnigCodePoint CR_ID_Continue[] = {
+ 799,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x005f, 0x005f,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00b7, 0x00b7,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0300, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x0483, 0x0487,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0800, 0x082d,
+ 0x0840, 0x085b,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e4e,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f18, 0x0f19,
+ 0x0f20, 0x0f29,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x1000, 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,
+ 0x135d, 0x135f,
+ 0x1369, 0x1371,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1734,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x180b, 0x180d,
+ 0x180f, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1946, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x1a00, 0x1a1b,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1abd,
+ 0x1abf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b59,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1bf3,
+ 0x1c00, 0x1c37,
+ 0x1c40, 0x1c49,
+ 0x1c4d, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1cfa,
+ 0x1d00, 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,
+ 0x200c, 0x200d,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20f0,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 0x2c00, 0x2ce4,
+ 0x2ceb, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2dff,
+ 0x3005, 0x3007,
+ 0x3021, 0x302f,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x3099, 0x309f,
+ 0x30a1, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31bf,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0xa48c,
+ 0xa4d0, 0xa4fd,
+ 0xa500, 0xa60c,
+ 0xa610, 0xa62b,
+ 0xa640, 0xa66f,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa6f1,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa840, 0xa873,
+ 0xa880, 0xa8c5,
+ 0xa8d0, 0xa8d9,
+ 0xa8e0, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa92d,
+ 0xa930, 0xa953,
+ 0xa960, 0xa97c,
+ 0xa980, 0xa9c0,
+ 0xa9cf, 0xa9d9,
+ 0xa9e0, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaef,
+ 0xaaf2, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabea,
+ 0xabec, 0xabed,
+ 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,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff10, 0xff19,
+ 0xff21, 0xff3a,
+ 0xff3f, 0xff3f,
+ 0xff41, 0xff5a,
+ 0xff65, 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,
+ 0x101fd, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102e0,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae6,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f50,
+ 0x10f70, 0x10f85,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11046,
+ 0x11066, 0x11075,
+ 0x1107f, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x1113f,
+ 0x11144, 0x11147,
+ 0x11150, 0x11173,
+ 0x11176, 0x11176,
+ 0x11180, 0x111c4,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x11237,
+ 0x1123e, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1144a,
+ 0x11450, 0x11459,
+ 0x1145e, 0x11461,
+ 0x11480, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115d8, 0x115dd,
+ 0x11600, 0x11640,
+ 0x11644, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11739,
+ 0x11740, 0x11746,
+ 0x11800, 0x1183a,
+ 0x118a0, 0x118e9,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11943,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e1,
+ 0x119e3, 0x119e4,
+ 0x11a00, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a50, 0x11a99,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c40,
+ 0x11c50, 0x11c59,
+ 0x11c72, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f50, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13440, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af4,
+ 0x16b00, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9d, 0x1bc9e,
+ 0x1ccf0, 0x1ccf9,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 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,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e900, 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,
+ 0x1fbf0, 0x1fbf9,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0100, 0xe01ef,
+}; /* CR_ID_Continue */
+
+/* 'XID_Start': Derived Property */
+static const OnigCodePoint CR_XID_Start[] = {
+ 691,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06d5, 0x06d5,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x0800, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0840, 0x0858,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0904, 0x0939,
+ 0x093d, 0x093d,
+ 0x0950, 0x0950,
+ 0x0958, 0x0961,
+ 0x0971, 0x0980,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0abd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0af9, 0x0af9,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b71, 0x0b71,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bd0, 0x0bd0,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c80, 0x0c80,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbd,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d04, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d4e, 0x0d4e,
+ 0x0d54, 0x0d56,
+ 0x0d5f, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e32,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb2,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 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, 0x1711,
+ 0x171f, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dc,
+ 0x1820, 0x1878,
+ 0x1880, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1aa7, 0x1aa7,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf6,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 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,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 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,
+ 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,
+ 0xa67f, 0xa69d,
+ 0xa6a0, 0xa6ef,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa8fe,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xa9cf, 0xa9cf,
+ 0xa9e0, 0xa9e4,
+ 0xa9e6, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 0xfb28,
+ 0xfb2a, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfc5d,
+ 0xfc64, 0xfd3d,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdf9,
+ 0xfe71, 0xfe71,
+ 0xfe73, 0xfe73,
+ 0xfe77, 0xfe77,
+ 0xfe79, 0xfe79,
+ 0xfe7b, 0xfe7b,
+ 0xfe7d, 0xfe7d,
+ 0xfe7f, 0xfefc,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0xff66, 0xff9d,
+ 0xffa0, 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, 0x10375,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a00,
+ 0x10a10, 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, 0x10d23,
+ 0x10d4a, 0x10d65,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10f00, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f70, 0x10f81,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11003, 0x11037,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11150, 0x11172,
+ 0x11176, 0x11176,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x111da, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122b,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112de,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11361,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d3,
+ 0x11400, 0x11434,
+ 0x11447, 0x1144a,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114c4, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x11580, 0x115ae,
+ 0x115d8, 0x115db,
+ 0x11600, 0x1162f,
+ 0x11644, 0x11644,
+ 0x11680, 0x116aa,
+ 0x116b8, 0x116b8,
+ 0x11700, 0x1171a,
+ 0x11740, 0x11746,
+ 0x11800, 0x1182b,
+ 0x118a0, 0x118df,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d0,
+ 0x119e1, 0x119e1,
+ 0x119e3, 0x119e3,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a3a, 0x11a3a,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a89,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11bc0, 0x11be0,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2e,
+ 0x11c40, 0x11c40,
+ 0x11c72, 0x11c8f,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d89,
+ 0x11d98, 0x11d98,
+ 0x11db0, 0x11ddb,
+ 0x11ee0, 0x11ef2,
+ 0x11f02, 0x11f02,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a70, 0x16abe,
+ 0x16ad0, 0x16aed,
+ 0x16b00, 0x16b2f,
+ 0x16b40, 0x16b43,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f50,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 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,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5f0,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e900, 0x1e943,
+ 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,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_XID_Start */
+
+/* 'XID_Continue': Derived Property */
+static const OnigCodePoint CR_XID_Continue[] = {
+ 806,
+ 0x0030, 0x0039,
+ 0x0041, 0x005a,
+ 0x005f, 0x005f,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00b5, 0x00b5,
+ 0x00b7, 0x00b7,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x02ec, 0x02ec,
+ 0x02ee, 0x02ee,
+ 0x0300, 0x0374,
+ 0x0376, 0x0377,
+ 0x037b, 0x037d,
+ 0x037f, 0x037f,
+ 0x0386, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x0483, 0x0487,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x0559,
+ 0x0560, 0x0588,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f2,
+ 0x0610, 0x061a,
+ 0x0620, 0x0669,
+ 0x066e, 0x06d3,
+ 0x06d5, 0x06dc,
+ 0x06df, 0x06e8,
+ 0x06ea, 0x06fc,
+ 0x06ff, 0x06ff,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07f5,
+ 0x07fa, 0x07fa,
+ 0x07fd, 0x07fd,
+ 0x0800, 0x082d,
+ 0x0840, 0x085b,
+ 0x0860, 0x086a,
+ 0x0870, 0x0887,
+ 0x0889, 0x088f,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x0963,
+ 0x0966, 0x096f,
+ 0x0971, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09f1,
+ 0x09fc, 0x09fc,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b6f,
+ 0x0b71, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bef,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c80, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d54, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d6f,
+ 0x0d7a, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df3,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e4e,
+ 0x0e50, 0x0e59,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f00,
+ 0x0f18, 0x0f19,
+ 0x0f20, 0x0f29,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f84,
+ 0x0f86, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x1000, 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,
+ 0x135d, 0x135f,
+ 0x1369, 0x1371,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1734,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17d3,
+ 0x17d7, 0x17d7,
+ 0x17dc, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x180b, 0x180d,
+ 0x180f, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1946, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x1a00, 0x1a1b,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa7, 0x1aa7,
+ 0x1ab0, 0x1abd,
+ 0x1abf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b59,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1bf3,
+ 0x1c00, 0x1c37,
+ 0x1c40, 0x1c49,
+ 0x1c4d, 0x1c7d,
+ 0x1c80, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1cfa,
+ 0x1d00, 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,
+ 0x200c, 0x200d,
+ 0x203f, 0x2040,
+ 0x2054, 0x2054,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20f0,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2118, 0x211d,
+ 0x2124, 0x2124,
+ 0x2126, 0x2126,
+ 0x2128, 0x2128,
+ 0x212a, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 0x2c00, 0x2ce4,
+ 0x2ceb, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d6f,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2dff,
+ 0x3005, 0x3007,
+ 0x3021, 0x302f,
+ 0x3031, 0x3035,
+ 0x3038, 0x303c,
+ 0x3041, 0x3096,
+ 0x3099, 0x309a,
+ 0x309d, 0x309f,
+ 0x30a1, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31bf,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0xa48c,
+ 0xa4d0, 0xa4fd,
+ 0xa500, 0xa60c,
+ 0xa610, 0xa62b,
+ 0xa640, 0xa66f,
+ 0xa674, 0xa67d,
+ 0xa67f, 0xa6f1,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa827,
+ 0xa82c, 0xa82c,
+ 0xa840, 0xa873,
+ 0xa880, 0xa8c5,
+ 0xa8d0, 0xa8d9,
+ 0xa8e0, 0xa8f7,
+ 0xa8fb, 0xa8fb,
+ 0xa8fd, 0xa92d,
+ 0xa930, 0xa953,
+ 0xa960, 0xa97c,
+ 0xa980, 0xa9c0,
+ 0xa9cf, 0xa9d9,
+ 0xa9e0, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa60, 0xaa76,
+ 0xaa7a, 0xaac2,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaef,
+ 0xaaf2, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab69,
+ 0xab70, 0xabea,
+ 0xabec, 0xabed,
+ 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, 0xfc5d,
+ 0xfc64, 0xfd3d,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdf9,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xfe33, 0xfe34,
+ 0xfe4d, 0xfe4f,
+ 0xfe71, 0xfe71,
+ 0xfe73, 0xfe73,
+ 0xfe77, 0xfe77,
+ 0xfe79, 0xfe79,
+ 0xfe7b, 0xfe7b,
+ 0xfe7d, 0xfe7d,
+ 0xfe7f, 0xfefc,
+ 0xff10, 0xff19,
+ 0xff21, 0xff3a,
+ 0xff3f, 0xff3f,
+ 0xff41, 0xff5a,
+ 0xff65, 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,
+ 0x101fd, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102e0,
+ 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,
+ 0x105c0, 0x105f3,
+ 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,
+ 0x10940, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10a60, 0x10a7c,
+ 0x10a80, 0x10a9c,
+ 0x10ac0, 0x10ac7,
+ 0x10ac9, 0x10ae6,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10b80, 0x10b91,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d6d,
+ 0x10d6f, 0x10d85,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10eac,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10efa, 0x10f1c,
+ 0x10f27, 0x10f27,
+ 0x10f30, 0x10f50,
+ 0x10f70, 0x10f85,
+ 0x10fb0, 0x10fc4,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11046,
+ 0x11066, 0x11075,
+ 0x1107f, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x1113f,
+ 0x11144, 0x11147,
+ 0x11150, 0x11173,
+ 0x11176, 0x11176,
+ 0x11180, 0x111c4,
+ 0x111c9, 0x111cc,
+ 0x111ce, 0x111da,
+ 0x111dc, 0x111dc,
+ 0x11200, 0x11211,
+ 0x11213, 0x11237,
+ 0x1123e, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a8,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1144a,
+ 0x11450, 0x11459,
+ 0x1145e, 0x11461,
+ 0x11480, 0x114c5,
+ 0x114c7, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c0,
+ 0x115d8, 0x115dd,
+ 0x11600, 0x11640,
+ 0x11644, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11739,
+ 0x11740, 0x11746,
+ 0x11800, 0x1183a,
+ 0x118a0, 0x118e9,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11943,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e1,
+ 0x119e3, 0x119e4,
+ 0x11a00, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a50, 0x11a99,
+ 0x11a9d, 0x11a9d,
+ 0x11ab0, 0x11af8,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be0,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c40,
+ 0x11c50, 0x11c59,
+ 0x11c72, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef6,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f42,
+ 0x11f50, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff0,
+ 0x13000, 0x1342f,
+ 0x13440, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af4,
+ 0x16b00, 0x16b36,
+ 0x16b40, 0x16b43,
+ 0x16b50, 0x16b59,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d6c,
+ 0x16d70, 0x16d79,
+ 0x16e40, 0x16e7f,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9d, 0x1bc9e,
+ 0x1ccf0, 0x1ccf9,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 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,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14e,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e900, 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,
+ 0x1fbf0, 0x1fbf9,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+ 0xe0100, 0xe01ef,
+}; /* CR_XID_Continue */
+
+/* 'Default_Ignorable_Code_Point': Derived Property */
+static const OnigCodePoint CR_Default_Ignorable_Code_Point[] = {
+ 17,
+ 0x00ad, 0x00ad,
+ 0x034f, 0x034f,
+ 0x061c, 0x061c,
+ 0x115f, 0x1160,
+ 0x17b4, 0x17b5,
+ 0x180b, 0x180f,
+ 0x200b, 0x200f,
+ 0x202a, 0x202e,
+ 0x2060, 0x206f,
+ 0x3164, 0x3164,
+ 0xfe00, 0xfe0f,
+ 0xfeff, 0xfeff,
+ 0xffa0, 0xffa0,
+ 0xfff0, 0xfff8,
+ 0x1bca0, 0x1bca3,
+ 0x1d173, 0x1d17a,
+ 0xe0000, 0xe0fff,
+}; /* CR_Default_Ignorable_Code_Point */
+
+/* 'Grapheme_Extend': Derived Property */
+static const OnigCodePoint CR_Grapheme_Extend[] = {
+ 383,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09be,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bbe,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d3e,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dcf,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0ddf, 0x0ddf,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b3d,
+ 0x1b42, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf3,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200c, 0x200c,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa953, 0xa953,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9c0, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xaaf6, 0xaaf6,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xff9e, 0xff9f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c0, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x1133e,
+ 0x11340, 0x11340,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113b8,
+ 0x113bb, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113ce, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114b0,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bd, 0x114bd,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115af, 0x115af,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x11930, 0x11930,
+ 0x1193b, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Grapheme_Extend */
+
+/* 'Grapheme_Base': Derived Property */
+static const OnigCodePoint CR_Grapheme_Base[] = {
+ 904,
+ 0x0020, 0x007e,
+ 0x00a0, 0x00ac,
+ 0x00ae, 0x02ff,
+ 0x0370, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0482,
+ 0x048a, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x05be, 0x05be,
+ 0x05c0, 0x05c0,
+ 0x05c3, 0x05c3,
+ 0x05c6, 0x05c6,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0606, 0x060f,
+ 0x061b, 0x061b,
+ 0x061d, 0x064a,
+ 0x0660, 0x066f,
+ 0x0671, 0x06d5,
+ 0x06de, 0x06de,
+ 0x06e5, 0x06e6,
+ 0x06e9, 0x06e9,
+ 0x06ee, 0x070d,
+ 0x0710, 0x0710,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07b1, 0x07b1,
+ 0x07c0, 0x07ea,
+ 0x07f4, 0x07fa,
+ 0x07fe, 0x0815,
+ 0x081a, 0x081a,
+ 0x0824, 0x0824,
+ 0x0828, 0x0828,
+ 0x0830, 0x083e,
+ 0x0840, 0x0858,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088f,
+ 0x08a0, 0x08c9,
+ 0x0903, 0x0939,
+ 0x093b, 0x093b,
+ 0x093d, 0x0940,
+ 0x0949, 0x094c,
+ 0x094e, 0x0950,
+ 0x0958, 0x0961,
+ 0x0964, 0x0980,
+ 0x0982, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bd, 0x09bd,
+ 0x09bf, 0x09c0,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09ce, 0x09ce,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09e6, 0x09fd,
+ 0x0a03, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3e, 0x0a40,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a6f,
+ 0x0a72, 0x0a74,
+ 0x0a76, 0x0a76,
+ 0x0a83, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abd, 0x0ac0,
+ 0x0ac9, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae1,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0af9,
+ 0x0b02, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3d, 0x0b3d,
+ 0x0b40, 0x0b40,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b77,
+ 0x0b83, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbf, 0x0bbf,
+ 0x0bc1, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd0, 0x0bd0,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c3d,
+ 0x0c41, 0x0c44,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c80,
+ 0x0c82, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbd, 0x0cbe,
+ 0x0cc1, 0x0cc1,
+ 0x0cc3, 0x0cc4,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d02, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d3d,
+ 0x0d3f, 0x0d40,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d4e, 0x0d4f,
+ 0x0d54, 0x0d56,
+ 0x0d58, 0x0d61,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dd0, 0x0dd1,
+ 0x0dd8, 0x0dde,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e3f, 0x0e46,
+ 0x0e4f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ebd, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f17,
+ 0x0f1a, 0x0f34,
+ 0x0f36, 0x0f36,
+ 0x0f38, 0x0f38,
+ 0x0f3a, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f7f, 0x0f7f,
+ 0x0f85, 0x0f85,
+ 0x0f88, 0x0f8c,
+ 0x0fbe, 0x0fc5,
+ 0x0fc7, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x102c,
+ 0x1031, 0x1031,
+ 0x1038, 0x1038,
+ 0x103b, 0x103c,
+ 0x103f, 0x1057,
+ 0x105a, 0x105d,
+ 0x1061, 0x1070,
+ 0x1075, 0x1081,
+ 0x1083, 0x1084,
+ 0x1087, 0x108c,
+ 0x108e, 0x109c,
+ 0x109e, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x1360, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1711,
+ 0x171f, 0x1731,
+ 0x1735, 0x1736,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x17b6, 0x17b6,
+ 0x17be, 0x17c5,
+ 0x17c7, 0x17c8,
+ 0x17d4, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180a,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x1884,
+ 0x1887, 0x18a8,
+ 0x18aa, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1923, 0x1926,
+ 0x1929, 0x192b,
+ 0x1930, 0x1931,
+ 0x1933, 0x1938,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a16,
+ 0x1a19, 0x1a1a,
+ 0x1a1e, 0x1a55,
+ 0x1a57, 0x1a57,
+ 0x1a61, 0x1a61,
+ 0x1a63, 0x1a64,
+ 0x1a6d, 0x1a72,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b04, 0x1b33,
+ 0x1b3e, 0x1b41,
+ 0x1b45, 0x1b4c,
+ 0x1b4e, 0x1b6a,
+ 0x1b74, 0x1b7f,
+ 0x1b82, 0x1ba1,
+ 0x1ba6, 0x1ba7,
+ 0x1bae, 0x1be5,
+ 0x1be7, 0x1be7,
+ 0x1bea, 0x1bec,
+ 0x1bee, 0x1bee,
+ 0x1bfc, 0x1c2b,
+ 0x1c34, 0x1c35,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd3, 0x1cd3,
+ 0x1ce1, 0x1ce1,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf7,
+ 0x1cfa, 0x1cfa,
+ 0x1d00, 0x1dbf,
+ 0x1e00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x200a,
+ 0x2010, 0x2027,
+ 0x202f, 0x205f,
+ 0x2070, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2e00, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x3029,
+ 0x3030, 0x303f,
+ 0x3041, 0x3096,
+ 0x309b, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa66e,
+ 0xa673, 0xa673,
+ 0xa67e, 0xa69d,
+ 0xa6a0, 0xa6ef,
+ 0xa6f2, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa824,
+ 0xa827, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c3,
+ 0xa8ce, 0xa8d9,
+ 0xa8f2, 0xa8fe,
+ 0xa900, 0xa925,
+ 0xa92e, 0xa946,
+ 0xa952, 0xa952,
+ 0xa95f, 0xa97c,
+ 0xa983, 0xa9b2,
+ 0xa9b4, 0xa9b5,
+ 0xa9ba, 0xa9bb,
+ 0xa9be, 0xa9bf,
+ 0xa9c1, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9e4,
+ 0xa9e6, 0xa9fe,
+ 0xaa00, 0xaa28,
+ 0xaa2f, 0xaa30,
+ 0xaa33, 0xaa34,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa4d, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa7d, 0xaaaf,
+ 0xaab1, 0xaab1,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaac0, 0xaac0,
+ 0xaac2, 0xaac2,
+ 0xaadb, 0xaaeb,
+ 0xaaee, 0xaaf5,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabe4,
+ 0xabe6, 0xabe7,
+ 0xabe9, 0xabec,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb1d,
+ 0xfb1f, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfdcf,
+ 0xfdf0, 0xfdff,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff01, 0xff9d,
+ 0xffa0, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffc, 0xfffd,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fc,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e1, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x10375,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a00,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a40, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae4,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d23,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d6e, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10ead, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f45,
+ 0x10f51, 0x10f59,
+ 0x10f70, 0x10f81,
+ 0x10f86, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x11000,
+ 0x11002, 0x11037,
+ 0x11047, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11071, 0x11072,
+ 0x11075, 0x11075,
+ 0x11082, 0x110b2,
+ 0x110b7, 0x110b8,
+ 0x110bb, 0x110bc,
+ 0x110be, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11103, 0x11126,
+ 0x1112c, 0x1112c,
+ 0x11136, 0x11147,
+ 0x11150, 0x11172,
+ 0x11174, 0x11176,
+ 0x11182, 0x111b5,
+ 0x111bf, 0x111bf,
+ 0x111c1, 0x111c8,
+ 0x111cd, 0x111ce,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1122e,
+ 0x11232, 0x11233,
+ 0x11238, 0x1123d,
+ 0x1123f, 0x11240,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112de,
+ 0x112e0, 0x112e2,
+ 0x112f0, 0x112f9,
+ 0x11302, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133d, 0x1133d,
+ 0x1133f, 0x1133f,
+ 0x11341, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134c,
+ 0x11350, 0x11350,
+ 0x1135d, 0x11363,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113b7,
+ 0x113b9, 0x113ba,
+ 0x113ca, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x113d1, 0x113d1,
+ 0x113d3, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x11400, 0x11437,
+ 0x11440, 0x11441,
+ 0x11445, 0x11445,
+ 0x11447, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x1145f, 0x11461,
+ 0x11480, 0x114af,
+ 0x114b1, 0x114b2,
+ 0x114b9, 0x114b9,
+ 0x114bb, 0x114bc,
+ 0x114be, 0x114be,
+ 0x114c1, 0x114c1,
+ 0x114c4, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115ae,
+ 0x115b0, 0x115b1,
+ 0x115b8, 0x115bb,
+ 0x115be, 0x115be,
+ 0x115c1, 0x115db,
+ 0x11600, 0x11632,
+ 0x1163b, 0x1163c,
+ 0x1163e, 0x1163e,
+ 0x11641, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116aa,
+ 0x116ac, 0x116ac,
+ 0x116ae, 0x116af,
+ 0x116b8, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171e, 0x1171e,
+ 0x11720, 0x11721,
+ 0x11726, 0x11726,
+ 0x11730, 0x11746,
+ 0x11800, 0x1182e,
+ 0x11838, 0x11838,
+ 0x1183b, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x11931, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193f, 0x11942,
+ 0x11944, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d3,
+ 0x119dc, 0x119df,
+ 0x119e1, 0x119e4,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a39, 0x11a3a,
+ 0x11a3f, 0x11a46,
+ 0x11a50, 0x11a50,
+ 0x11a57, 0x11a58,
+ 0x11a5c, 0x11a89,
+ 0x11a97, 0x11a97,
+ 0x11a9a, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b61, 0x11b61,
+ 0x11b65, 0x11b65,
+ 0x11b67, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c2f,
+ 0x11c3e, 0x11c3e,
+ 0x11c40, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11ca9, 0x11ca9,
+ 0x11cb1, 0x11cb1,
+ 0x11cb4, 0x11cb4,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d30,
+ 0x11d46, 0x11d46,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d93, 0x11d94,
+ 0x11d96, 0x11d96,
+ 0x11d98, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef2,
+ 0x11ef5, 0x11ef8,
+ 0x11f02, 0x11f10,
+ 0x11f12, 0x11f35,
+ 0x11f3e, 0x11f3f,
+ 0x11f43, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x1342f,
+ 0x13441, 0x13446,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x1611d,
+ 0x1612a, 0x1612c,
+ 0x16130, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af5, 0x16af5,
+ 0x16b00, 0x16b2f,
+ 0x16b37, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f50, 0x16f87,
+ 0x16f93, 0x16f9f,
+ 0x16fe0, 0x16fe3,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bc9c,
+ 0x1bc9f, 0x1bc9f,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d164,
+ 0x1d16a, 0x1d16c,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d200, 0x1d241,
+ 0x1d245, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d9ff,
+ 0x1da37, 0x1da3a,
+ 0x1da6d, 0x1da74,
+ 0x1da76, 0x1da83,
+ 0x1da85, 0x1da8b,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e030, 0x1e06d,
+ 0x1e100, 0x1e12c,
+ 0x1e137, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ad,
+ 0x1e2c0, 0x1e2eb,
+ 0x1e2f0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4eb,
+ 0x1e4f0, 0x1e4f9,
+ 0x1e5d0, 0x1e5ed,
+ 0x1e5f0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6e2,
+ 0x1e6e4, 0x1e6e5,
+ 0x1e6e7, 0x1e6ed,
+ 0x1e6f0, 0x1e6f4,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8cf,
+ 0x1e900, 0x1e943,
+ 0x1e94b, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Grapheme_Base */
+
+/* 'Grapheme_Link': Derived Property */
+static const OnigCodePoint CR_Grapheme_Link[] = {
+ 58,
+ 0x094d, 0x094d,
+ 0x09cd, 0x09cd,
+ 0x0a4d, 0x0a4d,
+ 0x0acd, 0x0acd,
+ 0x0b4d, 0x0b4d,
+ 0x0bcd, 0x0bcd,
+ 0x0c4d, 0x0c4d,
+ 0x0ccd, 0x0ccd,
+ 0x0d3b, 0x0d3c,
+ 0x0d4d, 0x0d4d,
+ 0x0dca, 0x0dca,
+ 0x0e3a, 0x0e3a,
+ 0x0eba, 0x0eba,
+ 0x0f84, 0x0f84,
+ 0x1039, 0x103a,
+ 0x1714, 0x1715,
+ 0x1734, 0x1734,
+ 0x17d2, 0x17d2,
+ 0x1a60, 0x1a60,
+ 0x1b44, 0x1b44,
+ 0x1baa, 0x1bab,
+ 0x1bf2, 0x1bf3,
+ 0x2d7f, 0x2d7f,
+ 0xa806, 0xa806,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c4,
+ 0xa953, 0xa953,
+ 0xa9c0, 0xa9c0,
+ 0xaaf6, 0xaaf6,
+ 0xabed, 0xabed,
+ 0x10a3f, 0x10a3f,
+ 0x11046, 0x11046,
+ 0x11070, 0x11070,
+ 0x1107f, 0x1107f,
+ 0x110b9, 0x110b9,
+ 0x11133, 0x11134,
+ 0x111c0, 0x111c0,
+ 0x11235, 0x11235,
+ 0x112ea, 0x112ea,
+ 0x1134d, 0x1134d,
+ 0x113ce, 0x113d0,
+ 0x11442, 0x11442,
+ 0x114c2, 0x114c2,
+ 0x115bf, 0x115bf,
+ 0x1163f, 0x1163f,
+ 0x116b6, 0x116b6,
+ 0x1172b, 0x1172b,
+ 0x11839, 0x11839,
+ 0x1193d, 0x1193e,
+ 0x119e0, 0x119e0,
+ 0x11a34, 0x11a34,
+ 0x11a47, 0x11a47,
+ 0x11a99, 0x11a99,
+ 0x11c3f, 0x11c3f,
+ 0x11d44, 0x11d45,
+ 0x11d97, 0x11d97,
+ 0x11f41, 0x11f42,
+ 0x1612f, 0x1612f,
+}; /* CR_Grapheme_Link */
+
+/* 'InCB_Linker': Derived Property */
+static const OnigCodePoint CR_InCB_Linker[] = {
+ 20,
+ 0x094d, 0x094d,
+ 0x09cd, 0x09cd,
+ 0x0acd, 0x0acd,
+ 0x0b4d, 0x0b4d,
+ 0x0c4d, 0x0c4d,
+ 0x0d4d, 0x0d4d,
+ 0x1039, 0x1039,
+ 0x17d2, 0x17d2,
+ 0x1a60, 0x1a60,
+ 0x1b44, 0x1b44,
+ 0x1bab, 0x1bab,
+ 0xa9c0, 0xa9c0,
+ 0xaaf6, 0xaaf6,
+ 0x10a3f, 0x10a3f,
+ 0x11133, 0x11133,
+ 0x113d0, 0x113d0,
+ 0x1193e, 0x1193e,
+ 0x11a47, 0x11a47,
+ 0x11a99, 0x11a99,
+ 0x11f42, 0x11f42,
+}; /* CR_InCB_Linker */
+
+/* 'InCB_Consonant': Derived Property */
+static const OnigCodePoint CR_InCB_Consonant[] = {
+ 76,
+ 0x0915, 0x0939,
+ 0x0958, 0x095f,
+ 0x0978, 0x097f,
+ 0x0995, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09df,
+ 0x09f0, 0x09f1,
+ 0x0a95, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0af9, 0x0af9,
+ 0x0b15, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b5f,
+ 0x0b71, 0x0b71,
+ 0x0c15, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c58, 0x0c5a,
+ 0x0d15, 0x0d3a,
+ 0x1000, 0x102a,
+ 0x103f, 0x103f,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1061, 0x1061,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x108e, 0x108e,
+ 0x1780, 0x17b3,
+ 0x1a20, 0x1a54,
+ 0x1b0b, 0x1b0c,
+ 0x1b13, 0x1b33,
+ 0x1b45, 0x1b4c,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bbb, 0x1bbd,
+ 0xa989, 0xa98b,
+ 0xa98f, 0xa9b2,
+ 0xa9e0, 0xa9e4,
+ 0xa9e7, 0xa9ef,
+ 0xa9fa, 0xa9fe,
+ 0xaa60, 0xaa6f,
+ 0xaa71, 0xaa73,
+ 0xaa7a, 0xaa7a,
+ 0xaa7e, 0xaa7f,
+ 0xaae0, 0xaaea,
+ 0xabc0, 0xabda,
+ 0x10a00, 0x10a00,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x11103, 0x11126,
+ 0x11144, 0x11144,
+ 0x11147, 0x11147,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x11900, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x1192f,
+ 0x11a00, 0x11a00,
+ 0x11a0b, 0x11a32,
+ 0x11a50, 0x11a50,
+ 0x11a5c, 0x11a83,
+ 0x11f04, 0x11f10,
+ 0x11f12, 0x11f33,
+}; /* CR_InCB_Consonant */
+
+/* 'InCB_Extend': Derived Property */
+static const OnigCodePoint CR_InCB_Extend[] = {
+ 377,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09be,
+ 0x09c1, 0x09c4,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bbe,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d3e,
+ 0x0d41, 0x0d44,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dcf,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0ddf, 0x0ddf,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x103a, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d1,
+ 0x17d3, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b3d,
+ 0x1b42, 0x1b43,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1baa,
+ 0x1bac, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf3,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200d, 0x200d,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa953, 0xa953,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xff9e, 0xff9f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11132,
+ 0x11134, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c0, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x1133e,
+ 0x11340, 0x11340,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113b8,
+ 0x113bb, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113ce, 0x113cf,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114b0,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bd, 0x114bd,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115af, 0x115af,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x11930, 0x11930,
+ 0x1193b, 0x1193d,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a98,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f41,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0x1f3fb, 0x1f3ff,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_InCB_Extend */
+
+/* 'Common': Script */
+static const OnigCodePoint CR_Common[] = {
+ 176,
+ 0x0000, 0x0040,
+ 0x005b, 0x0060,
+ 0x007b, 0x00a9,
+ 0x00ab, 0x00b9,
+ 0x00bb, 0x00bf,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x02b9, 0x02df,
+ 0x02e5, 0x02e9,
+ 0x02ec, 0x02ff,
+ 0x0374, 0x0374,
+ 0x037e, 0x037e,
+ 0x0385, 0x0385,
+ 0x0387, 0x0387,
+ 0x0605, 0x0605,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0640, 0x0640,
+ 0x06dd, 0x06dd,
+ 0x08e2, 0x08e2,
+ 0x0964, 0x0965,
+ 0x0e3f, 0x0e3f,
+ 0x0fd5, 0x0fd8,
+ 0x10fb, 0x10fb,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x1802, 0x1803,
+ 0x1805, 0x1805,
+ 0x1cd3, 0x1cd3,
+ 0x1ce1, 0x1ce1,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf3,
+ 0x1cf5, 0x1cf7,
+ 0x1cfa, 0x1cfa,
+ 0x2000, 0x200b,
+ 0x200e, 0x2064,
+ 0x2066, 0x2070,
+ 0x2074, 0x207e,
+ 0x2080, 0x208e,
+ 0x20a0, 0x20c1,
+ 0x2100, 0x2125,
+ 0x2127, 0x2129,
+ 0x212c, 0x2131,
+ 0x2133, 0x214d,
+ 0x214f, 0x215f,
+ 0x2189, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x27ff,
+ 0x2900, 0x2b73,
+ 0x2b76, 0x2bff,
+ 0x2e00, 0x2e5d,
+ 0x2ff0, 0x3004,
+ 0x3006, 0x3006,
+ 0x3008, 0x3020,
+ 0x3030, 0x3037,
+ 0x303c, 0x303f,
+ 0x309b, 0x309c,
+ 0x30a0, 0x30a0,
+ 0x30fb, 0x30fc,
+ 0x3190, 0x319f,
+ 0x31c0, 0x31e5,
+ 0x31ef, 0x31ef,
+ 0x3220, 0x325f,
+ 0x327f, 0x32cf,
+ 0x32ff, 0x32ff,
+ 0x3358, 0x33ff,
+ 0x4dc0, 0x4dff,
+ 0xa700, 0xa721,
+ 0xa788, 0xa78a,
+ 0xa830, 0xa839,
+ 0xa92e, 0xa92e,
+ 0xa9cf, 0xa9cf,
+ 0xab5b, 0xab5b,
+ 0xab6a, 0xab6b,
+ 0xfd3e, 0xfd3f,
+ 0xfe10, 0xfe19,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff20,
+ 0xff3b, 0xff40,
+ 0xff5b, 0xff65,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xfffd,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1013f,
+ 0x10190, 0x1019c,
+ 0x101d0, 0x101fc,
+ 0x102e1, 0x102fb,
+ 0x1bca0, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d166,
+ 0x1d16a, 0x1d17a,
+ 0x1d183, 0x1d184,
+ 0x1d18c, 0x1d1a9,
+ 0x1d1ae, 0x1d1ea,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f201, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+}; /* CR_Common */
+
+/* 'Latin': Script */
+static const OnigCodePoint CR_Latin[] = {
+ 36,
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00aa, 0x00aa,
+ 0x00ba, 0x00ba,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02b8,
+ 0x02e0, 0x02e4,
+ 0x1d00, 0x1d25,
+ 0x1d2c, 0x1d5c,
+ 0x1d62, 0x1d65,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1dbe,
+ 0x1e00, 0x1eff,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x212a, 0x212b,
+ 0x2132, 0x2132,
+ 0x214e, 0x214e,
+ 0x2160, 0x2188,
+ 0x2c60, 0x2c7f,
+ 0xa722, 0xa787,
+ 0xa78b, 0xa7dc,
+ 0xa7f1, 0xa7ff,
+ 0xab30, 0xab5a,
+ 0xab5c, 0xab64,
+ 0xab66, 0xab69,
+ 0xfb00, 0xfb06,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+}; /* CR_Latin */
+
+/* 'Greek': Script */
+static const OnigCodePoint CR_Greek[] = {
+ 36,
+ 0x0370, 0x0373,
+ 0x0375, 0x0377,
+ 0x037a, 0x037d,
+ 0x037f, 0x037f,
+ 0x0384, 0x0384,
+ 0x0386, 0x0386,
+ 0x0388, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03e1,
+ 0x03f0, 0x03ff,
+ 0x1d26, 0x1d2a,
+ 0x1d5d, 0x1d61,
+ 0x1d66, 0x1d6a,
+ 0x1dbf, 0x1dbf,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2126, 0x2126,
+ 0xab65, 0xab65,
+ 0x10140, 0x1018e,
+ 0x101a0, 0x101a0,
+ 0x1d200, 0x1d245,
+}; /* CR_Greek */
+
+/* 'Cyrillic': Script */
+static const OnigCodePoint CR_Cyrillic[] = {
+ 10,
+ 0x0400, 0x0484,
+ 0x0487, 0x052f,
+ 0x1c80, 0x1c8a,
+ 0x1d2b, 0x1d2b,
+ 0x1d78, 0x1d78,
+ 0x2de0, 0x2dff,
+ 0xa640, 0xa69f,
+ 0xfe2e, 0xfe2f,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+}; /* CR_Cyrillic */
+
+/* 'Armenian': Script */
+static const OnigCodePoint CR_Armenian[] = {
+ 4,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0xfb13, 0xfb17,
+}; /* CR_Armenian */
+
+/* 'Hebrew': Script */
+static const OnigCodePoint CR_Hebrew[] = {
+ 9,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfb4f,
+}; /* CR_Hebrew */
+
+/* 'Arabic': Script */
+static const OnigCodePoint CR_Arabic[] = {
+ 56,
+ 0x0600, 0x0604,
+ 0x0606, 0x060b,
+ 0x060d, 0x061a,
+ 0x061c, 0x061e,
+ 0x0620, 0x063f,
+ 0x0641, 0x064a,
+ 0x0656, 0x066f,
+ 0x0671, 0x06dc,
+ 0x06de, 0x06ff,
+ 0x0750, 0x077f,
+ 0x0870, 0x0891,
+ 0x0897, 0x08e1,
+ 0x08e3, 0x08ff,
+ 0xfb50, 0xfd3d,
+ 0xfd40, 0xfdcf,
+ 0xfdf0, 0xfdff,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0x10e60, 0x10e7e,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10eff,
+ 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,
+ 0x1eef0, 0x1eef1,
+}; /* CR_Arabic */
+
+/* 'Syriac': Script */
+static const OnigCodePoint CR_Syriac[] = {
+ 4,
+ 0x0700, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x074f,
+ 0x0860, 0x086a,
+}; /* CR_Syriac */
+
+/* 'Thaana': Script */
+static const OnigCodePoint CR_Thaana[] = {
+ 1,
+ 0x0780, 0x07b1,
+}; /* CR_Thaana */
+
+/* 'Devanagari': Script */
+static const OnigCodePoint CR_Devanagari[] = {
+ 5,
+ 0x0900, 0x0950,
+ 0x0955, 0x0963,
+ 0x0966, 0x097f,
+ 0xa8e0, 0xa8ff,
+ 0x11b00, 0x11b09,
+}; /* CR_Devanagari */
+
+/* 'Bengali': Script */
+static const OnigCodePoint CR_Bengali[] = {
+ 14,
+ 0x0980, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+}; /* CR_Bengali */
+
+/* 'Gurmukhi': Script */
+static const OnigCodePoint CR_Gurmukhi[] = {
+ 16,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+}; /* CR_Gurmukhi */
+
+/* 'Gujarati': Script */
+static const OnigCodePoint CR_Gujarati[] = {
+ 14,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+}; /* CR_Gujarati */
+
+/* 'Oriya': Script */
+static const OnigCodePoint CR_Oriya[] = {
+ 14,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+}; /* CR_Oriya */
+
+/* 'Tamil': Script */
+static const OnigCodePoint CR_Tamil[] = {
+ 18,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x11fff,
+}; /* CR_Tamil */
+
+/* 'Telugu': Script */
+static const OnigCodePoint CR_Telugu[] = {
+ 13,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c7f,
+}; /* CR_Telugu */
+
+/* 'Kannada': Script */
+static const OnigCodePoint CR_Kannada[] = {
+ 13,
+ 0x0c80, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+}; /* CR_Kannada */
+
+/* 'Malayalam': Script */
+static const OnigCodePoint CR_Malayalam[] = {
+ 7,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+}; /* CR_Malayalam */
+
+/* 'Sinhala': Script */
+static const OnigCodePoint CR_Sinhala[] = {
+ 13,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x111e1, 0x111f4,
+}; /* CR_Sinhala */
+
+/* 'Thai': Script */
+static const OnigCodePoint CR_Thai[] = {
+ 2,
+ 0x0e01, 0x0e3a,
+ 0x0e40, 0x0e5b,
+}; /* CR_Thai */
+
+/* 'Lao': Script */
+static const OnigCodePoint CR_Lao[] = {
+ 11,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+}; /* CR_Lao */
+
+/* 'Tibetan': Script */
+static const OnigCodePoint CR_Tibetan[] = {
+ 7,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fd4,
+ 0x0fd9, 0x0fda,
+}; /* CR_Tibetan */
+
+/* 'Myanmar': Script */
+static const OnigCodePoint CR_Myanmar[] = {
+ 4,
+ 0x1000, 0x109f,
+ 0xa9e0, 0xa9fe,
+ 0xaa60, 0xaa7f,
+ 0x116d0, 0x116e3,
+}; /* CR_Myanmar */
+
+/* 'Georgian': Script */
+static const OnigCodePoint CR_Georgian[] = {
+ 10,
+ 0x10a0, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x10ff,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cbf,
+ 0x2d00, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+}; /* CR_Georgian */
+
+/* 'Hangul': Script */
+static const OnigCodePoint CR_Hangul[] = {
+ 14,
+ 0x1100, 0x11ff,
+ 0x302e, 0x302f,
+ 0x3131, 0x318e,
+ 0x3200, 0x321e,
+ 0x3260, 0x327e,
+ 0xa960, 0xa97c,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xffa0, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+}; /* CR_Hangul */
+
+/* 'Ethiopic': Script */
+static const OnigCodePoint CR_Ethiopic[] = {
+ 36,
+ 0x1200, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+}; /* CR_Ethiopic */
+
+/* 'Cherokee': Script */
+static const OnigCodePoint CR_Cherokee[] = {
+ 3,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0xab70, 0xabbf,
+}; /* CR_Cherokee */
+
+/* 'Canadian_Aboriginal': Script */
+static const OnigCodePoint CR_Canadian_Aboriginal[] = {
+ 3,
+ 0x1400, 0x167f,
+ 0x18b0, 0x18f5,
+ 0x11ab0, 0x11abf,
+}; /* CR_Canadian_Aboriginal */
+
+/* 'Ogham': Script */
+static const OnigCodePoint CR_Ogham[] = {
+ 1,
+ 0x1680, 0x169c,
+}; /* CR_Ogham */
+
+/* 'Runic': Script */
+static const OnigCodePoint CR_Runic[] = {
+ 2,
+ 0x16a0, 0x16ea,
+ 0x16ee, 0x16f8,
+}; /* CR_Runic */
+
+/* 'Khmer': Script */
+static const OnigCodePoint CR_Khmer[] = {
+ 4,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x19e0, 0x19ff,
+}; /* CR_Khmer */
+
+/* 'Mongolian': Script */
+static const OnigCodePoint CR_Mongolian[] = {
+ 6,
+ 0x1800, 0x1801,
+ 0x1804, 0x1804,
+ 0x1806, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x11660, 0x1166c,
+}; /* CR_Mongolian */
+
+/* 'Hiragana': Script */
+static const OnigCodePoint CR_Hiragana[] = {
+ 6,
+ 0x3041, 0x3096,
+ 0x309d, 0x309f,
+ 0x1b001, 0x1b11f,
+ 0x1b132, 0x1b132,
+ 0x1b150, 0x1b152,
+ 0x1f200, 0x1f200,
+}; /* CR_Hiragana */
+
+/* 'Katakana': Script */
+static const OnigCodePoint CR_Katakana[] = {
+ 14,
+ 0x30a1, 0x30fa,
+ 0x30fd, 0x30ff,
+ 0x31f0, 0x31ff,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3357,
+ 0xff66, 0xff6f,
+ 0xff71, 0xff9d,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1b000, 0x1b000,
+ 0x1b120, 0x1b122,
+ 0x1b155, 0x1b155,
+ 0x1b164, 0x1b167,
+}; /* CR_Katakana */
+
+/* 'Bopomofo': Script */
+static const OnigCodePoint CR_Bopomofo[] = {
+ 3,
+ 0x02ea, 0x02eb,
+ 0x3105, 0x312f,
+ 0x31a0, 0x31bf,
+}; /* CR_Bopomofo */
+
+/* 'Han': Script */
+static const OnigCodePoint CR_Han[] = {
+ 21,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x3005, 0x3005,
+ 0x3007, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303b,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0x9fff,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0x16fe2, 0x16fe3,
+ 0x16ff0, 0x16ff6,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Han */
+
+/* 'Yi': Script */
+static const OnigCodePoint CR_Yi[] = {
+ 2,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+}; /* CR_Yi */
+
+/* 'Old_Italic': Script */
+static const OnigCodePoint CR_Old_Italic[] = {
+ 2,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1032f,
+}; /* CR_Old_Italic */
+
+/* 'Gothic': Script */
+static const OnigCodePoint CR_Gothic[] = {
+ 1,
+ 0x10330, 0x1034a,
+}; /* CR_Gothic */
+
+/* 'Deseret': Script */
+static const OnigCodePoint CR_Deseret[] = {
+ 1,
+ 0x10400, 0x1044f,
+}; /* CR_Deseret */
+
+/* 'Inherited': Script */
+static const OnigCodePoint CR_Inherited[] = {
+ 30,
+ 0x0300, 0x036f,
+ 0x0485, 0x0486,
+ 0x064b, 0x0655,
+ 0x0670, 0x0670,
+ 0x0951, 0x0954,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200c, 0x200d,
+ 0x20d0, 0x20f0,
+ 0x302a, 0x302d,
+ 0x3099, 0x309a,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2d,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x1133b, 0x1133b,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0xe0100, 0xe01ef,
+}; /* CR_Inherited */
+
+/* 'Tagalog': Script */
+static const OnigCodePoint CR_Tagalog[] = {
+ 2,
+ 0x1700, 0x1715,
+ 0x171f, 0x171f,
+}; /* CR_Tagalog */
+
+/* 'Hanunoo': Script */
+static const OnigCodePoint CR_Hanunoo[] = {
+ 1,
+ 0x1720, 0x1734,
+}; /* CR_Hanunoo */
+
+/* 'Buhid': Script */
+static const OnigCodePoint CR_Buhid[] = {
+ 1,
+ 0x1740, 0x1753,
+}; /* CR_Buhid */
+
+/* 'Tagbanwa': Script */
+static const OnigCodePoint CR_Tagbanwa[] = {
+ 3,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+}; /* CR_Tagbanwa */
+
+/* 'Limbu': Script */
+static const OnigCodePoint CR_Limbu[] = {
+ 5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x194f,
+}; /* CR_Limbu */
+
+/* 'Tai_Le': Script */
+static const OnigCodePoint CR_Tai_Le[] = {
+ 2,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+}; /* CR_Tai_Le */
+
+/* 'Linear_B': Script */
+static const OnigCodePoint CR_Linear_B[] = {
+ 7,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+}; /* CR_Linear_B */
+
+/* 'Ugaritic': Script */
+static const OnigCodePoint CR_Ugaritic[] = {
+ 2,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x1039f,
+}; /* CR_Ugaritic */
+
+/* 'Shavian': Script */
+static const OnigCodePoint CR_Shavian[] = {
+ 1,
+ 0x10450, 0x1047f,
+}; /* CR_Shavian */
+
+/* 'Osmanya': Script */
+static const OnigCodePoint CR_Osmanya[] = {
+ 2,
+ 0x10480, 0x1049d,
+ 0x104a0, 0x104a9,
+}; /* CR_Osmanya */
+
+/* 'Cypriot': Script */
+static const OnigCodePoint CR_Cypriot[] = {
+ 6,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+}; /* CR_Cypriot */
+
+/* 'Braille': Script */
+static const OnigCodePoint CR_Braille[] = {
+ 1,
+ 0x2800, 0x28ff,
+}; /* CR_Braille */
+
+/* 'Buginese': Script */
+static const OnigCodePoint CR_Buginese[] = {
+ 2,
+ 0x1a00, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+}; /* CR_Buginese */
+
+/* 'Coptic': Script */
+static const OnigCodePoint CR_Coptic[] = {
+ 3,
+ 0x03e2, 0x03ef,
+ 0x2c80, 0x2cf3,
+ 0x2cf9, 0x2cff,
+}; /* CR_Coptic */
+
+/* 'New_Tai_Lue': Script */
+static const OnigCodePoint CR_New_Tai_Lue[] = {
+ 4,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x19df,
+}; /* CR_New_Tai_Lue */
+
+/* 'Glagolitic': Script */
+static const OnigCodePoint CR_Glagolitic[] = {
+ 6,
+ 0x2c00, 0x2c5f,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+}; /* CR_Glagolitic */
+
+/* 'Tifinagh': Script */
+static const OnigCodePoint CR_Tifinagh[] = {
+ 3,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d7f,
+}; /* CR_Tifinagh */
+
+/* 'Syloti_Nagri': Script */
+static const OnigCodePoint CR_Syloti_Nagri[] = {
+ 1,
+ 0xa800, 0xa82c,
+}; /* CR_Syloti_Nagri */
+
+/* 'Old_Persian': Script */
+static const OnigCodePoint CR_Old_Persian[] = {
+ 2,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103d5,
+}; /* CR_Old_Persian */
+
+/* 'Kharoshthi': Script */
+static const OnigCodePoint CR_Kharoshthi[] = {
+ 8,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+}; /* CR_Kharoshthi */
+
+/* 'Balinese': Script */
+static const OnigCodePoint CR_Balinese[] = {
+ 2,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1b7f,
+}; /* CR_Balinese */
+
+/* 'Cuneiform': Script */
+static const OnigCodePoint CR_Cuneiform[] = {
+ 4,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+}; /* CR_Cuneiform */
+
+/* 'Phoenician': Script */
+static const OnigCodePoint CR_Phoenician[] = {
+ 2,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x1091f,
+}; /* CR_Phoenician */
+
+/* 'Phags_Pa': Script */
+static const OnigCodePoint CR_Phags_Pa[] = {
+ 1,
+ 0xa840, 0xa877,
+}; /* CR_Phags_Pa */
+
+/* 'Nko': Script */
+static const OnigCodePoint CR_Nko[] = {
+ 2,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x07ff,
+}; /* CR_Nko */
+
+/* 'Sundanese': Script */
+static const OnigCodePoint CR_Sundanese[] = {
+ 2,
+ 0x1b80, 0x1bbf,
+ 0x1cc0, 0x1cc7,
+}; /* CR_Sundanese */
+
+/* 'Lepcha': Script */
+static const OnigCodePoint CR_Lepcha[] = {
+ 3,
+ 0x1c00, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c4f,
+}; /* CR_Lepcha */
+
+/* 'Ol_Chiki': Script */
+static const OnigCodePoint CR_Ol_Chiki[] = {
+ 1,
+ 0x1c50, 0x1c7f,
+}; /* CR_Ol_Chiki */
+
+/* 'Vai': Script */
+static const OnigCodePoint CR_Vai[] = {
+ 1,
+ 0xa500, 0xa62b,
+}; /* CR_Vai */
+
+/* 'Saurashtra': Script */
+static const OnigCodePoint CR_Saurashtra[] = {
+ 2,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+}; /* CR_Saurashtra */
+
+/* 'Kayah_Li': Script */
+static const OnigCodePoint CR_Kayah_Li[] = {
+ 2,
+ 0xa900, 0xa92d,
+ 0xa92f, 0xa92f,
+}; /* CR_Kayah_Li */
+
+/* 'Rejang': Script */
+static const OnigCodePoint CR_Rejang[] = {
+ 2,
+ 0xa930, 0xa953,
+ 0xa95f, 0xa95f,
+}; /* CR_Rejang */
+
+/* 'Lycian': Script */
+static const OnigCodePoint CR_Lycian[] = {
+ 1,
+ 0x10280, 0x1029c,
+}; /* CR_Lycian */
+
+/* 'Carian': Script */
+static const OnigCodePoint CR_Carian[] = {
+ 1,
+ 0x102a0, 0x102d0,
+}; /* CR_Carian */
+
+/* 'Lydian': Script */
+static const OnigCodePoint CR_Lydian[] = {
+ 2,
+ 0x10920, 0x10939,
+ 0x1093f, 0x1093f,
+}; /* CR_Lydian */
+
+/* 'Cham': Script */
+static const OnigCodePoint CR_Cham[] = {
+ 4,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa5f,
+}; /* CR_Cham */
+
+/* 'Tai_Tham': Script */
+static const OnigCodePoint CR_Tai_Tham[] = {
+ 5,
+ 0x1a20, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+}; /* CR_Tai_Tham */
+
+/* 'Tai_Viet': Script */
+static const OnigCodePoint CR_Tai_Viet[] = {
+ 2,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+}; /* CR_Tai_Viet */
+
+/* 'Avestan': Script */
+static const OnigCodePoint CR_Avestan[] = {
+ 2,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b3f,
+}; /* CR_Avestan */
+
+/* 'Egyptian_Hieroglyphs': Script */
+static const OnigCodePoint CR_Egyptian_Hieroglyphs[] = {
+ 2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+}; /* CR_Egyptian_Hieroglyphs */
+
+/* 'Samaritan': Script */
+static const OnigCodePoint CR_Samaritan[] = {
+ 2,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+}; /* CR_Samaritan */
+
+/* 'Lisu': Script */
+static const OnigCodePoint CR_Lisu[] = {
+ 2,
+ 0xa4d0, 0xa4ff,
+ 0x11fb0, 0x11fb0,
+}; /* CR_Lisu */
+
+/* 'Bamum': Script */
+static const OnigCodePoint CR_Bamum[] = {
+ 2,
+ 0xa6a0, 0xa6f7,
+ 0x16800, 0x16a38,
+}; /* CR_Bamum */
+
+/* 'Javanese': Script */
+static const OnigCodePoint CR_Javanese[] = {
+ 3,
+ 0xa980, 0xa9cd,
+ 0xa9d0, 0xa9d9,
+ 0xa9de, 0xa9df,
+}; /* CR_Javanese */
+
+/* 'Meetei_Mayek': Script */
+static const OnigCodePoint CR_Meetei_Mayek[] = {
+ 3,
+ 0xaae0, 0xaaf6,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+}; /* CR_Meetei_Mayek */
+
+/* 'Imperial_Aramaic': Script */
+static const OnigCodePoint CR_Imperial_Aramaic[] = {
+ 2,
+ 0x10840, 0x10855,
+ 0x10857, 0x1085f,
+}; /* CR_Imperial_Aramaic */
+
+/* 'Old_South_Arabian': Script */
+static const OnigCodePoint CR_Old_South_Arabian[] = {
+ 1,
+ 0x10a60, 0x10a7f,
+}; /* CR_Old_South_Arabian */
+
+/* 'Inscriptional_Parthian': Script */
+static const OnigCodePoint CR_Inscriptional_Parthian[] = {
+ 2,
+ 0x10b40, 0x10b55,
+ 0x10b58, 0x10b5f,
+}; /* CR_Inscriptional_Parthian */
+
+/* 'Inscriptional_Pahlavi': Script */
+static const OnigCodePoint CR_Inscriptional_Pahlavi[] = {
+ 2,
+ 0x10b60, 0x10b72,
+ 0x10b78, 0x10b7f,
+}; /* CR_Inscriptional_Pahlavi */
+
+/* 'Old_Turkic': Script */
+static const OnigCodePoint CR_Old_Turkic[] = {
+ 1,
+ 0x10c00, 0x10c48,
+}; /* CR_Old_Turkic */
+
+/* 'Kaithi': Script */
+static const OnigCodePoint CR_Kaithi[] = {
+ 2,
+ 0x11080, 0x110c2,
+ 0x110cd, 0x110cd,
+}; /* CR_Kaithi */
+
+/* 'Batak': Script */
+static const OnigCodePoint CR_Batak[] = {
+ 2,
+ 0x1bc0, 0x1bf3,
+ 0x1bfc, 0x1bff,
+}; /* CR_Batak */
+
+/* 'Brahmi': Script */
+static const OnigCodePoint CR_Brahmi[] = {
+ 3,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x1107f,
+}; /* CR_Brahmi */
+
+/* 'Mandaic': Script */
+static const OnigCodePoint CR_Mandaic[] = {
+ 2,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+}; /* CR_Mandaic */
+
+/* 'Chakma': Script */
+static const OnigCodePoint CR_Chakma[] = {
+ 2,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+}; /* CR_Chakma */
+
+/* 'Meroitic_Cursive': Script */
+static const OnigCodePoint CR_Meroitic_Cursive[] = {
+ 3,
+ 0x109a0, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x109ff,
+}; /* CR_Meroitic_Cursive */
+
+/* 'Meroitic_Hieroglyphs': Script */
+static const OnigCodePoint CR_Meroitic_Hieroglyphs[] = {
+ 1,
+ 0x10980, 0x1099f,
+}; /* CR_Meroitic_Hieroglyphs */
+
+/* 'Miao': Script */
+static const OnigCodePoint CR_Miao[] = {
+ 3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+}; /* CR_Miao */
+
+/* 'Sharada': Script */
+static const OnigCodePoint CR_Sharada[] = {
+ 2,
+ 0x11180, 0x111df,
+ 0x11b60, 0x11b67,
+}; /* CR_Sharada */
+
+/* 'Sora_Sompeng': Script */
+static const OnigCodePoint CR_Sora_Sompeng[] = {
+ 2,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+}; /* CR_Sora_Sompeng */
+
+/* 'Takri': Script */
+static const OnigCodePoint CR_Takri[] = {
+ 2,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+}; /* CR_Takri */
+
+/* 'Caucasian_Albanian': Script */
+static const OnigCodePoint CR_Caucasian_Albanian[] = {
+ 2,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+}; /* CR_Caucasian_Albanian */
+
+/* 'Bassa_Vah': Script */
+static const OnigCodePoint CR_Bassa_Vah[] = {
+ 2,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+}; /* CR_Bassa_Vah */
+
+/* 'Duployan': Script */
+static const OnigCodePoint CR_Duployan[] = {
+ 5,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bc9f,
+}; /* CR_Duployan */
+
+/* 'Elbasan': Script */
+static const OnigCodePoint CR_Elbasan[] = {
+ 1,
+ 0x10500, 0x10527,
+}; /* CR_Elbasan */
+
+/* 'Grantha': Script */
+static const OnigCodePoint CR_Grantha[] = {
+ 15,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+}; /* CR_Grantha */
+
+/* 'Pahawh_Hmong': Script */
+static const OnigCodePoint CR_Pahawh_Hmong[] = {
+ 5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+}; /* CR_Pahawh_Hmong */
+
+/* 'Khojki': Script */
+static const OnigCodePoint CR_Khojki[] = {
+ 2,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+}; /* CR_Khojki */
+
+/* 'Linear_A': Script */
+static const OnigCodePoint CR_Linear_A[] = {
+ 3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+}; /* CR_Linear_A */
+
+/* 'Mahajani': Script */
+static const OnigCodePoint CR_Mahajani[] = {
+ 1,
+ 0x11150, 0x11176,
+}; /* CR_Mahajani */
+
+/* 'Manichaean': Script */
+static const OnigCodePoint CR_Manichaean[] = {
+ 2,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+}; /* CR_Manichaean */
+
+/* 'Mende_Kikakui': Script */
+static const OnigCodePoint CR_Mende_Kikakui[] = {
+ 2,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+}; /* CR_Mende_Kikakui */
+
+/* 'Modi': Script */
+static const OnigCodePoint CR_Modi[] = {
+ 2,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+}; /* CR_Modi */
+
+/* 'Mro': Script */
+static const OnigCodePoint CR_Mro[] = {
+ 3,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+}; /* CR_Mro */
+
+/* 'Old_North_Arabian': Script */
+static const OnigCodePoint CR_Old_North_Arabian[] = {
+ 1,
+ 0x10a80, 0x10a9f,
+}; /* CR_Old_North_Arabian */
+
+/* 'Nabataean': Script */
+static const OnigCodePoint CR_Nabataean[] = {
+ 2,
+ 0x10880, 0x1089e,
+ 0x108a7, 0x108af,
+}; /* CR_Nabataean */
+
+/* 'Palmyrene': Script */
+static const OnigCodePoint CR_Palmyrene[] = {
+ 1,
+ 0x10860, 0x1087f,
+}; /* CR_Palmyrene */
+
+/* 'Pau_Cin_Hau': Script */
+static const OnigCodePoint CR_Pau_Cin_Hau[] = {
+ 1,
+ 0x11ac0, 0x11af8,
+}; /* CR_Pau_Cin_Hau */
+
+/* 'Old_Permic': Script */
+static const OnigCodePoint CR_Old_Permic[] = {
+ 1,
+ 0x10350, 0x1037a,
+}; /* CR_Old_Permic */
+
+/* 'Psalter_Pahlavi': Script */
+static const OnigCodePoint CR_Psalter_Pahlavi[] = {
+ 3,
+ 0x10b80, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+}; /* CR_Psalter_Pahlavi */
+
+/* 'Siddham': Script */
+static const OnigCodePoint CR_Siddham[] = {
+ 2,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+}; /* CR_Siddham */
+
+/* 'Khudawadi': Script */
+static const OnigCodePoint CR_Khudawadi[] = {
+ 2,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+}; /* CR_Khudawadi */
+
+/* 'Tirhuta': Script */
+static const OnigCodePoint CR_Tirhuta[] = {
+ 2,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+}; /* CR_Tirhuta */
+
+/* 'Warang_Citi': Script */
+static const OnigCodePoint CR_Warang_Citi[] = {
+ 2,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+}; /* CR_Warang_Citi */
+
+/* 'Ahom': Script */
+static const OnigCodePoint CR_Ahom[] = {
+ 3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+}; /* CR_Ahom */
+
+/* 'Anatolian_Hieroglyphs': Script */
+static const OnigCodePoint CR_Anatolian_Hieroglyphs[] = {
+ 1,
+ 0x14400, 0x14646,
+}; /* CR_Anatolian_Hieroglyphs */
+
+/* 'Hatran': Script */
+static const OnigCodePoint CR_Hatran[] = {
+ 3,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x108ff,
+}; /* CR_Hatran */
+
+/* 'Multani': Script */
+static const OnigCodePoint CR_Multani[] = {
+ 5,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+}; /* CR_Multani */
+
+/* 'Old_Hungarian': Script */
+static const OnigCodePoint CR_Old_Hungarian[] = {
+ 3,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+}; /* CR_Old_Hungarian */
+
+/* 'SignWriting': Script */
+static const OnigCodePoint CR_SignWriting[] = {
+ 3,
+ 0x1d800, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+}; /* CR_SignWriting */
+
+/* 'Adlam': Script */
+static const OnigCodePoint CR_Adlam[] = {
+ 3,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+}; /* CR_Adlam */
+
+/* 'Bhaiksuki': Script */
+static const OnigCodePoint CR_Bhaiksuki[] = {
+ 4,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+}; /* CR_Bhaiksuki */
+
+/* 'Marchen': Script */
+static const OnigCodePoint CR_Marchen[] = {
+ 3,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+}; /* CR_Marchen */
+
+/* 'Newa': Script */
+static const OnigCodePoint CR_Newa[] = {
+ 2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+}; /* CR_Newa */
+
+/* 'Osage': Script */
+static const OnigCodePoint CR_Osage[] = {
+ 2,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+}; /* CR_Osage */
+
+/* 'Tangut': Script */
+static const OnigCodePoint CR_Tangut[] = {
+ 4,
+ 0x16fe0, 0x16fe0,
+ 0x17000, 0x18aff,
+ 0x18d00, 0x18d1e,
+ 0x18d80, 0x18df2,
+}; /* CR_Tangut */
+
+/* 'Masaram_Gondi': Script */
+static const OnigCodePoint CR_Masaram_Gondi[] = {
+ 7,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+}; /* CR_Masaram_Gondi */
+
+/* 'Nushu': Script */
+static const OnigCodePoint CR_Nushu[] = {
+ 2,
+ 0x16fe1, 0x16fe1,
+ 0x1b170, 0x1b2fb,
+}; /* CR_Nushu */
+
+/* 'Soyombo': Script */
+static const OnigCodePoint CR_Soyombo[] = {
+ 1,
+ 0x11a50, 0x11aa2,
+}; /* CR_Soyombo */
+
+/* 'Zanabazar_Square': Script */
+static const OnigCodePoint CR_Zanabazar_Square[] = {
+ 1,
+ 0x11a00, 0x11a47,
+}; /* CR_Zanabazar_Square */
+
+/* 'Dogra': Script */
+static const OnigCodePoint CR_Dogra[] = {
+ 1,
+ 0x11800, 0x1183b,
+}; /* CR_Dogra */
+
+/* 'Gunjala_Gondi': Script */
+static const OnigCodePoint CR_Gunjala_Gondi[] = {
+ 6,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+}; /* CR_Gunjala_Gondi */
+
+/* 'Makasar': Script */
+static const OnigCodePoint CR_Makasar[] = {
+ 1,
+ 0x11ee0, 0x11ef8,
+}; /* CR_Makasar */
+
+/* 'Medefaidrin': Script */
+static const OnigCodePoint CR_Medefaidrin[] = {
+ 1,
+ 0x16e40, 0x16e9a,
+}; /* CR_Medefaidrin */
+
+/* 'Hanifi_Rohingya': Script */
+static const OnigCodePoint CR_Hanifi_Rohingya[] = {
+ 2,
+ 0x10d00, 0x10d27,
+ 0x10d30, 0x10d39,
+}; /* CR_Hanifi_Rohingya */
+
+/* 'Sogdian': Script */
+static const OnigCodePoint CR_Sogdian[] = {
+ 1,
+ 0x10f30, 0x10f59,
+}; /* CR_Sogdian */
+
+/* 'Old_Sogdian': Script */
+static const OnigCodePoint CR_Old_Sogdian[] = {
+ 1,
+ 0x10f00, 0x10f27,
+}; /* CR_Old_Sogdian */
+
+/* 'Elymaic': Script */
+static const OnigCodePoint CR_Elymaic[] = {
+ 1,
+ 0x10fe0, 0x10ff6,
+}; /* CR_Elymaic */
+
+/* 'Nandinagari': Script */
+static const OnigCodePoint CR_Nandinagari[] = {
+ 3,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+}; /* CR_Nandinagari */
+
+/* 'Nyiakeng_Puachue_Hmong': Script */
+static const OnigCodePoint CR_Nyiakeng_Puachue_Hmong[] = {
+ 4,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+}; /* CR_Nyiakeng_Puachue_Hmong */
+
+/* 'Wancho': Script */
+static const OnigCodePoint CR_Wancho[] = {
+ 2,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+}; /* CR_Wancho */
+
+/* 'Chorasmian': Script */
+static const OnigCodePoint CR_Chorasmian[] = {
+ 1,
+ 0x10fb0, 0x10fcb,
+}; /* CR_Chorasmian */
+
+/* 'Dives_Akuru': Script */
+static const OnigCodePoint CR_Dives_Akuru[] = {
+ 8,
+ 0x11900, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+}; /* CR_Dives_Akuru */
+
+/* 'Khitan_Small_Script': Script */
+static const OnigCodePoint CR_Khitan_Small_Script[] = {
+ 3,
+ 0x16fe4, 0x16fe4,
+ 0x18b00, 0x18cd5,
+ 0x18cff, 0x18cff,
+}; /* CR_Khitan_Small_Script */
+
+/* 'Yezidi': Script */
+static const OnigCodePoint CR_Yezidi[] = {
+ 3,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+}; /* CR_Yezidi */
+
+/* 'Cypro_Minoan': Script */
+static const OnigCodePoint CR_Cypro_Minoan[] = {
+ 1,
+ 0x12f90, 0x12ff2,
+}; /* CR_Cypro_Minoan */
+
+/* 'Old_Uyghur': Script */
+static const OnigCodePoint CR_Old_Uyghur[] = {
+ 1,
+ 0x10f70, 0x10f89,
+}; /* CR_Old_Uyghur */
+
+/* 'Tangsa': Script */
+static const OnigCodePoint CR_Tangsa[] = {
+ 2,
+ 0x16a70, 0x16abe,
+ 0x16ac0, 0x16ac9,
+}; /* CR_Tangsa */
+
+/* 'Toto': Script */
+static const OnigCodePoint CR_Toto[] = {
+ 1,
+ 0x1e290, 0x1e2ae,
+}; /* CR_Toto */
+
+/* 'Vithkuqi': Script */
+static const OnigCodePoint CR_Vithkuqi[] = {
+ 8,
+ 0x10570, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+}; /* CR_Vithkuqi */
+
+/* 'Kawi': Script */
+static const OnigCodePoint CR_Kawi[] = {
+ 3,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+}; /* CR_Kawi */
+
+/* 'Nag_Mundari': Script */
+static const OnigCodePoint CR_Nag_Mundari[] = {
+ 1,
+ 0x1e4d0, 0x1e4f9,
+}; /* CR_Nag_Mundari */
+
+/* 'Garay': Script */
+static const OnigCodePoint CR_Garay[] = {
+ 3,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+}; /* CR_Garay */
+
+/* 'Gurung_Khema': Script */
+static const OnigCodePoint CR_Gurung_Khema[] = {
+ 1,
+ 0x16100, 0x16139,
+}; /* CR_Gurung_Khema */
+
+/* 'Kirat_Rai': Script */
+static const OnigCodePoint CR_Kirat_Rai[] = {
+ 1,
+ 0x16d40, 0x16d79,
+}; /* CR_Kirat_Rai */
+
+/* 'Ol_Onal': Script */
+static const OnigCodePoint CR_Ol_Onal[] = {
+ 2,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+}; /* CR_Ol_Onal */
+
+/* 'Sunuwar': Script */
+static const OnigCodePoint CR_Sunuwar[] = {
+ 2,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+}; /* CR_Sunuwar */
+
+/* 'Todhri': Script */
+static const OnigCodePoint CR_Todhri[] = {
+ 1,
+ 0x105c0, 0x105f3,
+}; /* CR_Todhri */
+
+/* 'Tulu_Tigalari': Script */
+static const OnigCodePoint CR_Tulu_Tigalari[] = {
+ 11,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+}; /* CR_Tulu_Tigalari */
+
+/* 'Sidetic': Script */
+static const OnigCodePoint CR_Sidetic[] = {
+ 1,
+ 0x10940, 0x10959,
+}; /* CR_Sidetic */
+
+/* 'Tai_Yo': Script */
+static const OnigCodePoint CR_Tai_Yo[] = {
+ 3,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+}; /* CR_Tai_Yo */
+
+/* 'Tolong_Siki': Script */
+static const OnigCodePoint CR_Tolong_Siki[] = {
+ 2,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+}; /* CR_Tolong_Siki */
+
+/* 'Beria_Erfe': Script */
+static const OnigCodePoint CR_Beria_Erfe[] = {
+ 2,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+}; /* CR_Beria_Erfe */
+
+/* 'White_Space': Binary Property */
+#define CR_White_Space CR_Space
+
+/* 'Bidi_Control': Binary Property */
+static const OnigCodePoint CR_Bidi_Control[] = {
+ 4,
+ 0x061c, 0x061c,
+ 0x200e, 0x200f,
+ 0x202a, 0x202e,
+ 0x2066, 0x2069,
+}; /* CR_Bidi_Control */
+
+/* 'Join_Control': Binary Property */
+static const OnigCodePoint CR_Join_Control[] = {
+ 1,
+ 0x200c, 0x200d,
+}; /* CR_Join_Control */
+
+/* 'Dash': Binary Property */
+static const OnigCodePoint CR_Dash[] = {
+ 24,
+ 0x002d, 0x002d,
+ 0x058a, 0x058a,
+ 0x05be, 0x05be,
+ 0x1400, 0x1400,
+ 0x1806, 0x1806,
+ 0x2010, 0x2015,
+ 0x2053, 0x2053,
+ 0x207b, 0x207b,
+ 0x208b, 0x208b,
+ 0x2212, 0x2212,
+ 0x2e17, 0x2e17,
+ 0x2e1a, 0x2e1a,
+ 0x2e3a, 0x2e3b,
+ 0x2e40, 0x2e40,
+ 0x2e5d, 0x2e5d,
+ 0x301c, 0x301c,
+ 0x3030, 0x3030,
+ 0x30a0, 0x30a0,
+ 0xfe31, 0xfe32,
+ 0xfe58, 0xfe58,
+ 0xfe63, 0xfe63,
+ 0xff0d, 0xff0d,
+ 0x10d6e, 0x10d6e,
+ 0x10ead, 0x10ead,
+}; /* CR_Dash */
+
+/* 'Hyphen': Binary Property */
+static const OnigCodePoint CR_Hyphen[] = {
+ 10,
+ 0x002d, 0x002d,
+ 0x00ad, 0x00ad,
+ 0x058a, 0x058a,
+ 0x1806, 0x1806,
+ 0x2010, 0x2011,
+ 0x2e17, 0x2e17,
+ 0x30fb, 0x30fb,
+ 0xfe63, 0xfe63,
+ 0xff0d, 0xff0d,
+ 0xff65, 0xff65,
+}; /* CR_Hyphen */
+
+/* 'Quotation_Mark': Binary Property */
+static const OnigCodePoint CR_Quotation_Mark[] = {
+ 13,
+ 0x0022, 0x0022,
+ 0x0027, 0x0027,
+ 0x00ab, 0x00ab,
+ 0x00bb, 0x00bb,
+ 0x2018, 0x201f,
+ 0x2039, 0x203a,
+ 0x2e42, 0x2e42,
+ 0x300c, 0x300f,
+ 0x301d, 0x301f,
+ 0xfe41, 0xfe44,
+ 0xff02, 0xff02,
+ 0xff07, 0xff07,
+ 0xff62, 0xff63,
+}; /* CR_Quotation_Mark */
+
+/* 'Terminal_Punctuation': Binary Property */
+static const OnigCodePoint CR_Terminal_Punctuation[] = {
+ 116,
+ 0x0021, 0x0021,
+ 0x002c, 0x002c,
+ 0x002e, 0x002e,
+ 0x003a, 0x003b,
+ 0x003f, 0x003f,
+ 0x037e, 0x037e,
+ 0x0387, 0x0387,
+ 0x0589, 0x0589,
+ 0x05c3, 0x05c3,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061d, 0x061f,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x070a,
+ 0x070c, 0x070c,
+ 0x07f8, 0x07f9,
+ 0x0830, 0x0835,
+ 0x0837, 0x083e,
+ 0x085e, 0x085e,
+ 0x0964, 0x0965,
+ 0x0e5a, 0x0e5b,
+ 0x0f08, 0x0f08,
+ 0x0f0d, 0x0f12,
+ 0x104a, 0x104b,
+ 0x1361, 0x1368,
+ 0x166e, 0x166e,
+ 0x16eb, 0x16ed,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d6,
+ 0x17da, 0x17da,
+ 0x1802, 0x1805,
+ 0x1808, 0x1809,
+ 0x1944, 0x1945,
+ 0x1aa8, 0x1aab,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b5b,
+ 0x1b5d, 0x1b5f,
+ 0x1b7d, 0x1b7f,
+ 0x1c3b, 0x1c3f,
+ 0x1c7e, 0x1c7f,
+ 0x2024, 0x2024,
+ 0x203c, 0x203d,
+ 0x2047, 0x2049,
+ 0x2cf9, 0x2cfb,
+ 0x2e2e, 0x2e2e,
+ 0x2e3c, 0x2e3c,
+ 0x2e41, 0x2e41,
+ 0x2e4c, 0x2e4c,
+ 0x2e4e, 0x2e4f,
+ 0x2e53, 0x2e54,
+ 0x3001, 0x3002,
+ 0xa4fe, 0xa4ff,
+ 0xa60d, 0xa60f,
+ 0xa6f3, 0xa6f7,
+ 0xa876, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa92f, 0xa92f,
+ 0xa9c7, 0xa9c9,
+ 0xaa5d, 0xaa5f,
+ 0xaadf, 0xaadf,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfe12, 0xfe12,
+ 0xfe15, 0xfe16,
+ 0xfe50, 0xfe52,
+ 0xfe54, 0xfe57,
+ 0xff01, 0xff01,
+ 0xff0c, 0xff0c,
+ 0xff0e, 0xff0e,
+ 0xff1a, 0xff1b,
+ 0xff1f, 0xff1f,
+ 0xff61, 0xff61,
+ 0xff64, 0xff64,
+ 0x1039f, 0x1039f,
+ 0x103d0, 0x103d0,
+ 0x10857, 0x10857,
+ 0x1091f, 0x1091f,
+ 0x10a56, 0x10a57,
+ 0x10af0, 0x10af5,
+ 0x10b3a, 0x10b3f,
+ 0x10b99, 0x10b9c,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x1104d,
+ 0x110be, 0x110c1,
+ 0x11141, 0x11143,
+ 0x111c5, 0x111c6,
+ 0x111cd, 0x111cd,
+ 0x111de, 0x111df,
+ 0x11238, 0x1123c,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x1144b, 0x1144d,
+ 0x1145a, 0x1145b,
+ 0x115c2, 0x115c5,
+ 0x115c9, 0x115d7,
+ 0x11641, 0x11642,
+ 0x1173c, 0x1173e,
+ 0x11944, 0x11944,
+ 0x11946, 0x11946,
+ 0x11a42, 0x11a43,
+ 0x11a9b, 0x11a9c,
+ 0x11aa1, 0x11aa2,
+ 0x11c41, 0x11c43,
+ 0x11c71, 0x11c71,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f44,
+ 0x12470, 0x12474,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b39,
+ 0x16b44, 0x16b44,
+ 0x16d6e, 0x16d6f,
+ 0x16e97, 0x16e98,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da87, 0x1da8a,
+}; /* CR_Terminal_Punctuation */
+
+/* 'Other_Math': Binary Property */
+static const OnigCodePoint CR_Other_Math[] = {
+ 134,
+ 0x005e, 0x005e,
+ 0x03d0, 0x03d2,
+ 0x03d5, 0x03d5,
+ 0x03f0, 0x03f1,
+ 0x03f4, 0x03f5,
+ 0x2016, 0x2016,
+ 0x2032, 0x2034,
+ 0x2040, 0x2040,
+ 0x2061, 0x2064,
+ 0x207d, 0x207e,
+ 0x208d, 0x208e,
+ 0x20d0, 0x20dc,
+ 0x20e1, 0x20e1,
+ 0x20e5, 0x20e6,
+ 0x20eb, 0x20ef,
+ 0x2102, 0x2102,
+ 0x2107, 0x2107,
+ 0x210a, 0x2113,
+ 0x2115, 0x2115,
+ 0x2119, 0x211d,
+ 0x2124, 0x2124,
+ 0x2128, 0x2129,
+ 0x212c, 0x212d,
+ 0x212f, 0x2131,
+ 0x2133, 0x2138,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x2195, 0x2199,
+ 0x219c, 0x219f,
+ 0x21a1, 0x21a2,
+ 0x21a4, 0x21a5,
+ 0x21a7, 0x21a7,
+ 0x21a9, 0x21ad,
+ 0x21b0, 0x21b1,
+ 0x21b6, 0x21b7,
+ 0x21bc, 0x21cd,
+ 0x21d0, 0x21d1,
+ 0x21d3, 0x21d3,
+ 0x21d5, 0x21db,
+ 0x21dd, 0x21dd,
+ 0x21e4, 0x21e5,
+ 0x2308, 0x230b,
+ 0x23b4, 0x23b5,
+ 0x23b7, 0x23b7,
+ 0x23d0, 0x23d0,
+ 0x23e2, 0x23e2,
+ 0x25a0, 0x25a1,
+ 0x25ae, 0x25b6,
+ 0x25bc, 0x25c0,
+ 0x25c6, 0x25c7,
+ 0x25ca, 0x25cb,
+ 0x25cf, 0x25d3,
+ 0x25e2, 0x25e2,
+ 0x25e4, 0x25e4,
+ 0x25e7, 0x25ec,
+ 0x2605, 0x2606,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2660, 0x2663,
+ 0x266d, 0x266e,
+ 0x27c5, 0x27c6,
+ 0x27e6, 0x27ef,
+ 0x2983, 0x2998,
+ 0x29d8, 0x29db,
+ 0x29fc, 0x29fd,
+ 0xfe61, 0xfe61,
+ 0xfe63, 0xfe63,
+ 0xfe68, 0xfe68,
+ 0xff3c, 0xff3c,
+ 0xff3e, 0xff3e,
+ 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,
+ 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,
+}; /* CR_Other_Math */
+
+/* 'Hex_Digit': Binary Property */
+static const OnigCodePoint CR_Hex_Digit[] = {
+ 6,
+ 0x0030, 0x0039,
+ 0x0041, 0x0046,
+ 0x0061, 0x0066,
+ 0xff10, 0xff19,
+ 0xff21, 0xff26,
+ 0xff41, 0xff46,
+}; /* CR_Hex_Digit */
+
+/* 'ASCII_Hex_Digit': Binary Property */
+#define CR_ASCII_Hex_Digit CR_XDigit
+
+/* 'Other_Alphabetic': Binary Property */
+static const OnigCodePoint CR_Other_Alphabetic[] = {
+ 255,
+ 0x0345, 0x0345,
+ 0x0363, 0x036f,
+ 0x05b0, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x0657,
+ 0x0659, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06e1, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ed, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x073f,
+ 0x07a6, 0x07b0,
+ 0x0816, 0x0817,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082c,
+ 0x0897, 0x0897,
+ 0x08d4, 0x08df,
+ 0x08e3, 0x08e9,
+ 0x08f0, 0x0903,
+ 0x093a, 0x093b,
+ 0x093e, 0x094c,
+ 0x094e, 0x094f,
+ 0x0955, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0983,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x0a01, 0x0a03,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4c,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0abe, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0afc,
+ 0x0b01, 0x0b03,
+ 0x0b3e, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0b56, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c04,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4c,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c83,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccc,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0cf3, 0x0cf3,
+ 0x0d00, 0x0d03,
+ 0x0d3e, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d83,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df3,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e4d, 0x0e4d,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0eb9,
+ 0x0ebb, 0x0ebc,
+ 0x0ecd, 0x0ecd,
+ 0x0f71, 0x0f83,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x102b, 0x1036,
+ 0x1038, 0x1038,
+ 0x103b, 0x103e,
+ 0x1056, 0x1059,
+ 0x105e, 0x1060,
+ 0x1062, 0x1064,
+ 0x1067, 0x106d,
+ 0x1071, 0x1074,
+ 0x1082, 0x108d,
+ 0x108f, 0x108f,
+ 0x109a, 0x109d,
+ 0x1712, 0x1713,
+ 0x1732, 0x1733,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b6, 0x17c8,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x192b,
+ 0x1930, 0x1938,
+ 0x1a17, 0x1a1b,
+ 0x1a55, 0x1a5e,
+ 0x1a61, 0x1a74,
+ 0x1abf, 0x1ac0,
+ 0x1acc, 0x1ace,
+ 0x1b00, 0x1b04,
+ 0x1b35, 0x1b43,
+ 0x1b80, 0x1b82,
+ 0x1ba1, 0x1ba9,
+ 0x1bac, 0x1bad,
+ 0x1be7, 0x1bf1,
+ 0x1c24, 0x1c36,
+ 0x1dd3, 0x1df4,
+ 0x24b6, 0x24e9,
+ 0x2de0, 0x2dff,
+ 0xa674, 0xa67b,
+ 0xa69e, 0xa69f,
+ 0xa802, 0xa802,
+ 0xa80b, 0xa80b,
+ 0xa823, 0xa827,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c3,
+ 0xa8c5, 0xa8c5,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92a,
+ 0xa947, 0xa952,
+ 0xa980, 0xa983,
+ 0xa9b4, 0xa9bf,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4d,
+ 0xaa7b, 0xaa7d,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabe,
+ 0xaaeb, 0xaaef,
+ 0xaaf5, 0xaaf5,
+ 0xabe3, 0xabea,
+ 0xfb1e, 0xfb1e,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d69,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10efc,
+ 0x11000, 0x11002,
+ 0x11038, 0x11045,
+ 0x11073, 0x11074,
+ 0x11080, 0x11082,
+ 0x110b0, 0x110b8,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x11132,
+ 0x11145, 0x11146,
+ 0x11180, 0x11182,
+ 0x111b3, 0x111bf,
+ 0x111ce, 0x111cf,
+ 0x1122c, 0x11234,
+ 0x11237, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112e8,
+ 0x11300, 0x11303,
+ 0x1133e, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134c,
+ 0x11357, 0x11357,
+ 0x11362, 0x11363,
+ 0x113b8, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x11435, 0x11441,
+ 0x11443, 0x11445,
+ 0x114b0, 0x114c1,
+ 0x115af, 0x115b5,
+ 0x115b8, 0x115be,
+ 0x115dc, 0x115dd,
+ 0x11630, 0x1163e,
+ 0x11640, 0x11640,
+ 0x116ab, 0x116b5,
+ 0x1171d, 0x1172a,
+ 0x1182c, 0x11838,
+ 0x11930, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x1193c,
+ 0x11940, 0x11940,
+ 0x11942, 0x11942,
+ 0x119d1, 0x119d7,
+ 0x119da, 0x119df,
+ 0x119e4, 0x119e4,
+ 0x11a01, 0x11a0a,
+ 0x11a35, 0x11a39,
+ 0x11a3b, 0x11a3e,
+ 0x11a51, 0x11a5b,
+ 0x11a8a, 0x11a97,
+ 0x11b60, 0x11b67,
+ 0x11c2f, 0x11c36,
+ 0x11c38, 0x11c3e,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d41,
+ 0x11d43, 0x11d43,
+ 0x11d47, 0x11d47,
+ 0x11d8a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d96,
+ 0x11ef3, 0x11ef6,
+ 0x11f00, 0x11f01,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f3a,
+ 0x11f3e, 0x11f40,
+ 0x1611e, 0x1612e,
+ 0x16f4f, 0x16f4f,
+ 0x16f51, 0x16f87,
+ 0x16f8f, 0x16f92,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9e, 0x1bc9e,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e947, 0x1e947,
+ 0x1f130, 0x1f149,
+ 0x1f150, 0x1f169,
+ 0x1f170, 0x1f189,
+}; /* CR_Other_Alphabetic */
+
+/* 'Ideographic': Binary Property */
+static const OnigCodePoint CR_Ideographic[] = {
+ 21,
+ 0x3006, 0x3007,
+ 0x3021, 0x3029,
+ 0x3038, 0x303a,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0x9fff,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0x16fe4, 0x16fe4,
+ 0x16ff2, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 0x1b170, 0x1b2fb,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Ideographic */
+
+/* 'Diacritic': Binary Property */
+static const OnigCodePoint CR_Diacritic[] = {
+ 220,
+ 0x005e, 0x005e,
+ 0x0060, 0x0060,
+ 0x00a8, 0x00a8,
+ 0x00af, 0x00af,
+ 0x00b4, 0x00b4,
+ 0x00b7, 0x00b8,
+ 0x02b0, 0x034e,
+ 0x0350, 0x0357,
+ 0x035d, 0x0362,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x0384, 0x0385,
+ 0x0483, 0x0487,
+ 0x0559, 0x0559,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x064b, 0x0652,
+ 0x0657, 0x0658,
+ 0x06df, 0x06e0,
+ 0x06e5, 0x06e6,
+ 0x06ea, 0x06ec,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f5,
+ 0x0818, 0x0819,
+ 0x0898, 0x089f,
+ 0x08c9, 0x08d2,
+ 0x08e3, 0x08fe,
+ 0x093c, 0x093c,
+ 0x094d, 0x094d,
+ 0x0951, 0x0954,
+ 0x0971, 0x0971,
+ 0x09bc, 0x09bc,
+ 0x09cd, 0x09cd,
+ 0x0a3c, 0x0a3c,
+ 0x0a4d, 0x0a4d,
+ 0x0abc, 0x0abc,
+ 0x0acd, 0x0acd,
+ 0x0afd, 0x0aff,
+ 0x0b3c, 0x0b3c,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b55,
+ 0x0bcd, 0x0bcd,
+ 0x0c3c, 0x0c3c,
+ 0x0c4d, 0x0c4d,
+ 0x0cbc, 0x0cbc,
+ 0x0ccd, 0x0ccd,
+ 0x0d3b, 0x0d3c,
+ 0x0d4d, 0x0d4d,
+ 0x0dca, 0x0dca,
+ 0x0e3a, 0x0e3a,
+ 0x0e47, 0x0e4c,
+ 0x0e4e, 0x0e4e,
+ 0x0eba, 0x0eba,
+ 0x0ec8, 0x0ecc,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f3e, 0x0f3f,
+ 0x0f82, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0fc6, 0x0fc6,
+ 0x1037, 0x1037,
+ 0x1039, 0x103a,
+ 0x1063, 0x1064,
+ 0x1069, 0x106d,
+ 0x1087, 0x108d,
+ 0x108f, 0x108f,
+ 0x109a, 0x109b,
+ 0x135d, 0x135f,
+ 0x1714, 0x1715,
+ 0x1734, 0x1734,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x1939, 0x193b,
+ 0x1a60, 0x1a60,
+ 0x1a75, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1abe,
+ 0x1ac1, 0x1acb,
+ 0x1acf, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b34, 0x1b34,
+ 0x1b44, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1baa, 0x1bab,
+ 0x1be6, 0x1be6,
+ 0x1bf2, 0x1bf3,
+ 0x1c36, 0x1c37,
+ 0x1c78, 0x1c7d,
+ 0x1cd0, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf7, 0x1cf9,
+ 0x1d2c, 0x1d6a,
+ 0x1d9b, 0x1dbe,
+ 0x1dc4, 0x1dcf,
+ 0x1df5, 0x1dff,
+ 0x1fbd, 0x1fbd,
+ 0x1fbf, 0x1fc1,
+ 0x1fcd, 0x1fcf,
+ 0x1fdd, 0x1fdf,
+ 0x1fed, 0x1fef,
+ 0x1ffd, 0x1ffe,
+ 0x2cef, 0x2cf1,
+ 0x2e2f, 0x2e2f,
+ 0x302a, 0x302f,
+ 0x3099, 0x309c,
+ 0x30fc, 0x30fc,
+ 0xa66f, 0xa66f,
+ 0xa67c, 0xa67d,
+ 0xa67f, 0xa67f,
+ 0xa69c, 0xa69d,
+ 0xa6f0, 0xa6f1,
+ 0xa700, 0xa721,
+ 0xa788, 0xa78a,
+ 0xa7f1, 0xa7f1,
+ 0xa7f8, 0xa7f9,
+ 0xa806, 0xa806,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c4,
+ 0xa8e0, 0xa8f1,
+ 0xa92b, 0xa92e,
+ 0xa953, 0xa953,
+ 0xa9b3, 0xa9b3,
+ 0xa9c0, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa7b, 0xaa7d,
+ 0xaabf, 0xaac2,
+ 0xaaf6, 0xaaf6,
+ 0xab5b, 0xab5f,
+ 0xab69, 0xab6b,
+ 0xabec, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe20, 0xfe2f,
+ 0xff3e, 0xff3e,
+ 0xff40, 0xff40,
+ 0xff70, 0xff70,
+ 0xff9e, 0xff9f,
+ 0xffe3, 0xffe3,
+ 0x102e0, 0x102e0,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d22, 0x10d27,
+ 0x10d4e, 0x10d4e,
+ 0x10d69, 0x10d6d,
+ 0x10efa, 0x10efa,
+ 0x10efd, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11046, 0x11046,
+ 0x11070, 0x11070,
+ 0x110b9, 0x110ba,
+ 0x11133, 0x11134,
+ 0x11173, 0x11173,
+ 0x111c0, 0x111c0,
+ 0x111ca, 0x111cc,
+ 0x11235, 0x11236,
+ 0x112e9, 0x112ea,
+ 0x1133b, 0x1133c,
+ 0x1134d, 0x1134d,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113ce, 0x113d0,
+ 0x113d2, 0x113d3,
+ 0x113e1, 0x113e2,
+ 0x11442, 0x11442,
+ 0x11446, 0x11446,
+ 0x114c2, 0x114c3,
+ 0x115bf, 0x115c0,
+ 0x1163f, 0x1163f,
+ 0x116b6, 0x116b7,
+ 0x1172b, 0x1172b,
+ 0x11839, 0x1183a,
+ 0x1193d, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119e0, 0x119e0,
+ 0x11a34, 0x11a34,
+ 0x11a47, 0x11a47,
+ 0x11a99, 0x11a99,
+ 0x11c3f, 0x11c3f,
+ 0x11d42, 0x11d42,
+ 0x11d44, 0x11d45,
+ 0x11d97, 0x11d97,
+ 0x11dd9, 0x11dd9,
+ 0x11f41, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13447, 0x13455,
+ 0x1612f, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16d6b, 0x16d6c,
+ 0x16f8f, 0x16f9f,
+ 0x16ff0, 0x16ff1,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d167, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1e030, 0x1e06d,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e946,
+ 0x1e948, 0x1e94a,
+}; /* CR_Diacritic */
+
+/* 'Extender': Binary Property */
+static const OnigCodePoint CR_Extender[] = {
+ 43,
+ 0x00b7, 0x00b7,
+ 0x02d0, 0x02d1,
+ 0x0640, 0x0640,
+ 0x07fa, 0x07fa,
+ 0x0a71, 0x0a71,
+ 0x0afb, 0x0afb,
+ 0x0b55, 0x0b55,
+ 0x0e46, 0x0e46,
+ 0x0ec6, 0x0ec6,
+ 0x180a, 0x180a,
+ 0x1843, 0x1843,
+ 0x1aa7, 0x1aa7,
+ 0x1c36, 0x1c36,
+ 0x1c7b, 0x1c7b,
+ 0x3005, 0x3005,
+ 0x3031, 0x3035,
+ 0x309d, 0x309e,
+ 0x30fc, 0x30fe,
+ 0xa015, 0xa015,
+ 0xa60c, 0xa60c,
+ 0xa9cf, 0xa9cf,
+ 0xa9e6, 0xa9e6,
+ 0xaa70, 0xaa70,
+ 0xaadd, 0xaadd,
+ 0xaaf3, 0xaaf4,
+ 0xff70, 0xff70,
+ 0x10781, 0x10782,
+ 0x10d4e, 0x10d4e,
+ 0x10d6a, 0x10d6a,
+ 0x10d6f, 0x10d6f,
+ 0x11237, 0x11237,
+ 0x1135d, 0x1135d,
+ 0x113d2, 0x113d3,
+ 0x115c6, 0x115c8,
+ 0x11a98, 0x11a98,
+ 0x11dd9, 0x11dd9,
+ 0x16b42, 0x16b43,
+ 0x16fe0, 0x16fe1,
+ 0x16fe3, 0x16fe3,
+ 0x16ff2, 0x16ff3,
+ 0x1e13c, 0x1e13d,
+ 0x1e5ef, 0x1e5ef,
+ 0x1e944, 0x1e946,
+}; /* CR_Extender */
+
+/* 'Other_Lowercase': Binary Property */
+static const OnigCodePoint CR_Other_Lowercase[] = {
+ 28,
+ 0x00aa, 0x00aa,
+ 0x00ba, 0x00ba,
+ 0x02b0, 0x02b8,
+ 0x02c0, 0x02c1,
+ 0x02e0, 0x02e4,
+ 0x0345, 0x0345,
+ 0x037a, 0x037a,
+ 0x10fc, 0x10fc,
+ 0x1d2c, 0x1d6a,
+ 0x1d78, 0x1d78,
+ 0x1d9b, 0x1dbf,
+ 0x2071, 0x2071,
+ 0x207f, 0x207f,
+ 0x2090, 0x209c,
+ 0x2170, 0x217f,
+ 0x24d0, 0x24e9,
+ 0x2c7c, 0x2c7d,
+ 0xa69c, 0xa69d,
+ 0xa770, 0xa770,
+ 0xa7f1, 0xa7f4,
+ 0xa7f8, 0xa7f9,
+ 0xab5c, 0xab5f,
+ 0xab69, 0xab69,
+ 0x10780, 0x10780,
+ 0x10783, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x1e030, 0x1e06d,
+}; /* CR_Other_Lowercase */
+
+/* 'Other_Uppercase': Binary Property */
+static const OnigCodePoint CR_Other_Uppercase[] = {
+ 5,
+ 0x2160, 0x216f,
+ 0x24b6, 0x24cf,
+ 0x1f130, 0x1f149,
+ 0x1f150, 0x1f169,
+ 0x1f170, 0x1f189,
+}; /* CR_Other_Uppercase */
+
+/* 'Noncharacter_Code_Point': Binary Property */
+static const OnigCodePoint CR_Noncharacter_Code_Point[] = {
+ 18,
+ 0xfdd0, 0xfdef,
+ 0xfffe, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0xeffff,
+ 0xffffe, 0xfffff,
+ 0x10fffe, 0x10ffff,
+}; /* CR_Noncharacter_Code_Point */
+
+/* 'Other_Grapheme_Extend': Binary Property */
+static const OnigCodePoint CR_Other_Grapheme_Extend[] = {
+ 49,
+ 0x09be, 0x09be,
+ 0x09d7, 0x09d7,
+ 0x0b3e, 0x0b3e,
+ 0x0b57, 0x0b57,
+ 0x0bbe, 0x0bbe,
+ 0x0bd7, 0x0bd7,
+ 0x0cc0, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc7, 0x0cc8,
+ 0x0cca, 0x0ccb,
+ 0x0cd5, 0x0cd6,
+ 0x0d3e, 0x0d3e,
+ 0x0d57, 0x0d57,
+ 0x0dcf, 0x0dcf,
+ 0x0ddf, 0x0ddf,
+ 0x1715, 0x1715,
+ 0x1734, 0x1734,
+ 0x1b35, 0x1b35,
+ 0x1b3b, 0x1b3b,
+ 0x1b3d, 0x1b3d,
+ 0x1b43, 0x1b44,
+ 0x1baa, 0x1baa,
+ 0x1bf2, 0x1bf3,
+ 0x200c, 0x200c,
+ 0x302e, 0x302f,
+ 0xa953, 0xa953,
+ 0xa9c0, 0xa9c0,
+ 0xff9e, 0xff9f,
+ 0x111c0, 0x111c0,
+ 0x11235, 0x11235,
+ 0x1133e, 0x1133e,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x113b8, 0x113b8,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113cf, 0x113cf,
+ 0x114b0, 0x114b0,
+ 0x114bd, 0x114bd,
+ 0x115af, 0x115af,
+ 0x116b6, 0x116b6,
+ 0x11930, 0x11930,
+ 0x1193d, 0x1193d,
+ 0x11f41, 0x11f41,
+ 0x16ff0, 0x16ff1,
+ 0x1d165, 0x1d166,
+ 0x1d16d, 0x1d172,
+ 0xe0020, 0xe007f,
+}; /* CR_Other_Grapheme_Extend */
+
+/* 'IDS_Binary_Operator': Binary Property */
+static const OnigCodePoint CR_IDS_Binary_Operator[] = {
+ 3,
+ 0x2ff0, 0x2ff1,
+ 0x2ff4, 0x2ffd,
+ 0x31ef, 0x31ef,
+}; /* CR_IDS_Binary_Operator */
+
+/* 'IDS_Trinary_Operator': Binary Property */
+static const OnigCodePoint CR_IDS_Trinary_Operator[] = {
+ 1,
+ 0x2ff2, 0x2ff3,
+}; /* CR_IDS_Trinary_Operator */
+
+/* 'IDS_Unary_Operator': Binary Property */
+static const OnigCodePoint CR_IDS_Unary_Operator[] = {
+ 1,
+ 0x2ffe, 0x2fff,
+}; /* CR_IDS_Unary_Operator */
+
+/* 'Radical': Binary Property */
+static const OnigCodePoint CR_Radical[] = {
+ 3,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+}; /* CR_Radical */
+
+/* 'Unified_Ideograph': Binary Property */
+static const OnigCodePoint CR_Unified_Ideograph[] = {
+ 16,
+ 0x3400, 0x4dbf,
+ 0x4e00, 0x9fff,
+ 0xfa0e, 0xfa0f,
+ 0xfa11, 0xfa11,
+ 0xfa13, 0xfa14,
+ 0xfa1f, 0xfa1f,
+ 0xfa21, 0xfa21,
+ 0xfa23, 0xfa24,
+ 0xfa27, 0xfa29,
+ 0x20000, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x30000, 0x3134a,
+ 0x31350, 0x33479,
+}; /* CR_Unified_Ideograph */
+
+/* 'Other_Default_Ignorable_Code_Point': Binary Property */
+static const OnigCodePoint CR_Other_Default_Ignorable_Code_Point[] = {
+ 11,
+ 0x034f, 0x034f,
+ 0x115f, 0x1160,
+ 0x17b4, 0x17b5,
+ 0x2065, 0x2065,
+ 0x3164, 0x3164,
+ 0xffa0, 0xffa0,
+ 0xfff0, 0xfff8,
+ 0xe0000, 0xe0000,
+ 0xe0002, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xe0fff,
+}; /* CR_Other_Default_Ignorable_Code_Point */
+
+/* 'Deprecated': Binary Property */
+static const OnigCodePoint CR_Deprecated[] = {
+ 8,
+ 0x0149, 0x0149,
+ 0x0673, 0x0673,
+ 0x0f77, 0x0f77,
+ 0x0f79, 0x0f79,
+ 0x17a3, 0x17a4,
+ 0x206a, 0x206f,
+ 0x2329, 0x232a,
+ 0xe0001, 0xe0001,
+}; /* CR_Deprecated */
+
+/* 'Soft_Dotted': Binary Property */
+static const OnigCodePoint CR_Soft_Dotted[] = {
+ 34,
+ 0x0069, 0x006a,
+ 0x012f, 0x012f,
+ 0x0249, 0x0249,
+ 0x0268, 0x0268,
+ 0x029d, 0x029d,
+ 0x02b2, 0x02b2,
+ 0x03f3, 0x03f3,
+ 0x0456, 0x0456,
+ 0x0458, 0x0458,
+ 0x1d62, 0x1d62,
+ 0x1d96, 0x1d96,
+ 0x1da4, 0x1da4,
+ 0x1da8, 0x1da8,
+ 0x1e2d, 0x1e2d,
+ 0x1ecb, 0x1ecb,
+ 0x2071, 0x2071,
+ 0x2148, 0x2149,
+ 0x2c7c, 0x2c7c,
+ 0x1d422, 0x1d423,
+ 0x1d456, 0x1d457,
+ 0x1d48a, 0x1d48b,
+ 0x1d4be, 0x1d4bf,
+ 0x1d4f2, 0x1d4f3,
+ 0x1d526, 0x1d527,
+ 0x1d55a, 0x1d55b,
+ 0x1d58e, 0x1d58f,
+ 0x1d5c2, 0x1d5c3,
+ 0x1d5f6, 0x1d5f7,
+ 0x1d62a, 0x1d62b,
+ 0x1d65e, 0x1d65f,
+ 0x1d692, 0x1d693,
+ 0x1df1a, 0x1df1a,
+ 0x1e04c, 0x1e04d,
+ 0x1e068, 0x1e068,
+}; /* CR_Soft_Dotted */
+
+/* 'Logical_Order_Exception': Binary Property */
+static const OnigCodePoint CR_Logical_Order_Exception[] = {
+ 7,
+ 0x0e40, 0x0e44,
+ 0x0ec0, 0x0ec4,
+ 0x19b5, 0x19b7,
+ 0x19ba, 0x19ba,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaab9,
+ 0xaabb, 0xaabc,
+}; /* CR_Logical_Order_Exception */
+
+/* 'Other_ID_Start': Binary Property */
+static const OnigCodePoint CR_Other_ID_Start[] = {
+ 4,
+ 0x1885, 0x1886,
+ 0x2118, 0x2118,
+ 0x212e, 0x212e,
+ 0x309b, 0x309c,
+}; /* CR_Other_ID_Start */
+
+/* 'Other_ID_Continue': Binary Property */
+static const OnigCodePoint CR_Other_ID_Continue[] = {
+ 7,
+ 0x00b7, 0x00b7,
+ 0x0387, 0x0387,
+ 0x1369, 0x1371,
+ 0x19da, 0x19da,
+ 0x200c, 0x200d,
+ 0x30fb, 0x30fb,
+ 0xff65, 0xff65,
+}; /* CR_Other_ID_Continue */
+
+/* 'ID_Compat_Math_Continue': Binary Property */
+static const OnigCodePoint CR_ID_Compat_Math_Continue[] = {
+ 18,
+ 0x00b2, 0x00b3,
+ 0x00b9, 0x00b9,
+ 0x2070, 0x2070,
+ 0x2074, 0x207e,
+ 0x2080, 0x208e,
+ 0x2202, 0x2202,
+ 0x2207, 0x2207,
+ 0x221e, 0x221e,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+}; /* CR_ID_Compat_Math_Continue */
+
+/* 'ID_Compat_Math_Start': Binary Property */
+static const OnigCodePoint CR_ID_Compat_Math_Start[] = {
+ 13,
+ 0x2202, 0x2202,
+ 0x2207, 0x2207,
+ 0x221e, 0x221e,
+ 0x1d6c1, 0x1d6c1,
+ 0x1d6db, 0x1d6db,
+ 0x1d6fb, 0x1d6fb,
+ 0x1d715, 0x1d715,
+ 0x1d735, 0x1d735,
+ 0x1d74f, 0x1d74f,
+ 0x1d76f, 0x1d76f,
+ 0x1d789, 0x1d789,
+ 0x1d7a9, 0x1d7a9,
+ 0x1d7c3, 0x1d7c3,
+}; /* CR_ID_Compat_Math_Start */
+
+/* 'Sentence_Terminal': Binary Property */
+static const OnigCodePoint CR_Sentence_Terminal[] = {
+ 88,
+ 0x0021, 0x0021,
+ 0x002e, 0x002e,
+ 0x003f, 0x003f,
+ 0x0589, 0x0589,
+ 0x061d, 0x061f,
+ 0x06d4, 0x06d4,
+ 0x0700, 0x0702,
+ 0x07f9, 0x07f9,
+ 0x0837, 0x0837,
+ 0x0839, 0x0839,
+ 0x083d, 0x083e,
+ 0x0964, 0x0965,
+ 0x104a, 0x104b,
+ 0x1362, 0x1362,
+ 0x1367, 0x1368,
+ 0x166e, 0x166e,
+ 0x1735, 0x1736,
+ 0x17d4, 0x17d5,
+ 0x1803, 0x1803,
+ 0x1809, 0x1809,
+ 0x1944, 0x1945,
+ 0x1aa8, 0x1aab,
+ 0x1b4e, 0x1b4f,
+ 0x1b5a, 0x1b5b,
+ 0x1b5e, 0x1b5f,
+ 0x1b7d, 0x1b7f,
+ 0x1c3b, 0x1c3c,
+ 0x1c7e, 0x1c7f,
+ 0x2024, 0x2024,
+ 0x203c, 0x203d,
+ 0x2047, 0x2049,
+ 0x2cf9, 0x2cfb,
+ 0x2e2e, 0x2e2e,
+ 0x2e3c, 0x2e3c,
+ 0x2e53, 0x2e54,
+ 0x3002, 0x3002,
+ 0xa4ff, 0xa4ff,
+ 0xa60e, 0xa60f,
+ 0xa6f3, 0xa6f3,
+ 0xa6f7, 0xa6f7,
+ 0xa876, 0xa877,
+ 0xa8ce, 0xa8cf,
+ 0xa92f, 0xa92f,
+ 0xa9c8, 0xa9c9,
+ 0xaa5d, 0xaa5f,
+ 0xaaf0, 0xaaf1,
+ 0xabeb, 0xabeb,
+ 0xfe12, 0xfe12,
+ 0xfe15, 0xfe16,
+ 0xfe52, 0xfe52,
+ 0xfe56, 0xfe57,
+ 0xff01, 0xff01,
+ 0xff0e, 0xff0e,
+ 0xff1f, 0xff1f,
+ 0xff61, 0xff61,
+ 0x10a56, 0x10a57,
+ 0x10f55, 0x10f59,
+ 0x10f86, 0x10f89,
+ 0x11047, 0x11048,
+ 0x110be, 0x110c1,
+ 0x11141, 0x11143,
+ 0x111c5, 0x111c6,
+ 0x111cd, 0x111cd,
+ 0x111de, 0x111df,
+ 0x11238, 0x11239,
+ 0x1123b, 0x1123c,
+ 0x112a9, 0x112a9,
+ 0x113d4, 0x113d5,
+ 0x1144b, 0x1144c,
+ 0x115c2, 0x115c3,
+ 0x115c9, 0x115d7,
+ 0x11641, 0x11642,
+ 0x1173c, 0x1173e,
+ 0x11944, 0x11944,
+ 0x11946, 0x11946,
+ 0x11a42, 0x11a43,
+ 0x11a9b, 0x11a9c,
+ 0x11c41, 0x11c42,
+ 0x11ef7, 0x11ef8,
+ 0x11f43, 0x11f44,
+ 0x16a6e, 0x16a6f,
+ 0x16af5, 0x16af5,
+ 0x16b37, 0x16b38,
+ 0x16b44, 0x16b44,
+ 0x16d6e, 0x16d6f,
+ 0x16e98, 0x16e98,
+ 0x1bc9f, 0x1bc9f,
+ 0x1da88, 0x1da88,
+}; /* CR_Sentence_Terminal */
+
+/* 'Variation_Selector': Binary Property */
+static const OnigCodePoint CR_Variation_Selector[] = {
+ 4,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0xfe00, 0xfe0f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Variation_Selector */
+
+/* 'Pattern_White_Space': Binary Property */
+static const OnigCodePoint CR_Pattern_White_Space[] = {
+ 5,
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x200e, 0x200f,
+ 0x2028, 0x2029,
+}; /* CR_Pattern_White_Space */
+
+/* 'Pattern_Syntax': Binary Property */
+static const OnigCodePoint CR_Pattern_Syntax[] = {
+ 28,
+ 0x0021, 0x002f,
+ 0x003a, 0x0040,
+ 0x005b, 0x005e,
+ 0x0060, 0x0060,
+ 0x007b, 0x007e,
+ 0x00a1, 0x00a7,
+ 0x00a9, 0x00a9,
+ 0x00ab, 0x00ac,
+ 0x00ae, 0x00ae,
+ 0x00b0, 0x00b1,
+ 0x00b6, 0x00b6,
+ 0x00bb, 0x00bb,
+ 0x00bf, 0x00bf,
+ 0x00d7, 0x00d7,
+ 0x00f7, 0x00f7,
+ 0x2010, 0x2027,
+ 0x2030, 0x203e,
+ 0x2041, 0x2053,
+ 0x2055, 0x205e,
+ 0x2190, 0x245f,
+ 0x2500, 0x2775,
+ 0x2794, 0x2bff,
+ 0x2e00, 0x2e7f,
+ 0x3001, 0x3003,
+ 0x3008, 0x3020,
+ 0x3030, 0x3030,
+ 0xfd3e, 0xfd3f,
+ 0xfe45, 0xfe46,
+}; /* CR_Pattern_Syntax */
+
+/* 'Prepended_Concatenation_Mark': Binary Property */
+static const OnigCodePoint CR_Prepended_Concatenation_Mark[] = {
+ 7,
+ 0x0600, 0x0605,
+ 0x06dd, 0x06dd,
+ 0x070f, 0x070f,
+ 0x0890, 0x0891,
+ 0x08e2, 0x08e2,
+ 0x110bd, 0x110bd,
+ 0x110cd, 0x110cd,
+}; /* CR_Prepended_Concatenation_Mark */
+
+/* 'Regional_Indicator': Binary Property */
+static const OnigCodePoint CR_Regional_Indicator[] = {
+ 1,
+ 0x1f1e6, 0x1f1ff,
+}; /* CR_Regional_Indicator */
+
+/* 'Modifier_Combining_Mark': Binary Property */
+static const OnigCodePoint CR_Modifier_Combining_Mark[] = {
+ 9,
+ 0x0654, 0x0655,
+ 0x0658, 0x0658,
+ 0x06dc, 0x06dc,
+ 0x06e3, 0x06e3,
+ 0x06e7, 0x06e8,
+ 0x08ca, 0x08cb,
+ 0x08cd, 0x08cf,
+ 0x08d3, 0x08d3,
+ 0x08f3, 0x08f3,
+}; /* CR_Modifier_Combining_Mark */
+
+/* 'Emoji': Emoji */
+static const OnigCodePoint CR_Emoji[] = {
+ 151,
+ 0x0023, 0x0023,
+ 0x002a, 0x002a,
+ 0x0030, 0x0039,
+ 0x00a9, 0x00a9,
+ 0x00ae, 0x00ae,
+ 0x203c, 0x203c,
+ 0x2049, 0x2049,
+ 0x2122, 0x2122,
+ 0x2139, 0x2139,
+ 0x2194, 0x2199,
+ 0x21a9, 0x21aa,
+ 0x231a, 0x231b,
+ 0x2328, 0x2328,
+ 0x23cf, 0x23cf,
+ 0x23e9, 0x23f3,
+ 0x23f8, 0x23fa,
+ 0x24c2, 0x24c2,
+ 0x25aa, 0x25ab,
+ 0x25b6, 0x25b6,
+ 0x25c0, 0x25c0,
+ 0x25fb, 0x25fe,
+ 0x2600, 0x2604,
+ 0x260e, 0x260e,
+ 0x2611, 0x2611,
+ 0x2614, 0x2615,
+ 0x2618, 0x2618,
+ 0x261d, 0x261d,
+ 0x2620, 0x2620,
+ 0x2622, 0x2623,
+ 0x2626, 0x2626,
+ 0x262a, 0x262a,
+ 0x262e, 0x262f,
+ 0x2638, 0x263a,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2648, 0x2653,
+ 0x265f, 0x2660,
+ 0x2663, 0x2663,
+ 0x2665, 0x2666,
+ 0x2668, 0x2668,
+ 0x267b, 0x267b,
+ 0x267e, 0x267f,
+ 0x2692, 0x2697,
+ 0x2699, 0x2699,
+ 0x269b, 0x269c,
+ 0x26a0, 0x26a1,
+ 0x26a7, 0x26a7,
+ 0x26aa, 0x26ab,
+ 0x26b0, 0x26b1,
+ 0x26bd, 0x26be,
+ 0x26c4, 0x26c5,
+ 0x26c8, 0x26c8,
+ 0x26ce, 0x26cf,
+ 0x26d1, 0x26d1,
+ 0x26d3, 0x26d4,
+ 0x26e9, 0x26ea,
+ 0x26f0, 0x26f5,
+ 0x26f7, 0x26fa,
+ 0x26fd, 0x26fd,
+ 0x2702, 0x2702,
+ 0x2705, 0x2705,
+ 0x2708, 0x270d,
+ 0x270f, 0x270f,
+ 0x2712, 0x2712,
+ 0x2714, 0x2714,
+ 0x2716, 0x2716,
+ 0x271d, 0x271d,
+ 0x2721, 0x2721,
+ 0x2728, 0x2728,
+ 0x2733, 0x2734,
+ 0x2744, 0x2744,
+ 0x2747, 0x2747,
+ 0x274c, 0x274c,
+ 0x274e, 0x274e,
+ 0x2753, 0x2755,
+ 0x2757, 0x2757,
+ 0x2763, 0x2764,
+ 0x2795, 0x2797,
+ 0x27a1, 0x27a1,
+ 0x27b0, 0x27b0,
+ 0x27bf, 0x27bf,
+ 0x2934, 0x2935,
+ 0x2b05, 0x2b07,
+ 0x2b1b, 0x2b1c,
+ 0x2b50, 0x2b50,
+ 0x2b55, 0x2b55,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x3297, 0x3297,
+ 0x3299, 0x3299,
+ 0x1f004, 0x1f004,
+ 0x1f0cf, 0x1f0cf,
+ 0x1f170, 0x1f171,
+ 0x1f17e, 0x1f17f,
+ 0x1f18e, 0x1f18e,
+ 0x1f191, 0x1f19a,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f201, 0x1f202,
+ 0x1f21a, 0x1f21a,
+ 0x1f22f, 0x1f22f,
+ 0x1f232, 0x1f23a,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f321,
+ 0x1f324, 0x1f393,
+ 0x1f396, 0x1f397,
+ 0x1f399, 0x1f39b,
+ 0x1f39e, 0x1f3f0,
+ 0x1f3f3, 0x1f3f5,
+ 0x1f3f7, 0x1f4fd,
+ 0x1f4ff, 0x1f53d,
+ 0x1f549, 0x1f54e,
+ 0x1f550, 0x1f567,
+ 0x1f56f, 0x1f570,
+ 0x1f573, 0x1f57a,
+ 0x1f587, 0x1f587,
+ 0x1f58a, 0x1f58d,
+ 0x1f590, 0x1f590,
+ 0x1f595, 0x1f596,
+ 0x1f5a4, 0x1f5a5,
+ 0x1f5a8, 0x1f5a8,
+ 0x1f5b1, 0x1f5b2,
+ 0x1f5bc, 0x1f5bc,
+ 0x1f5c2, 0x1f5c4,
+ 0x1f5d1, 0x1f5d3,
+ 0x1f5dc, 0x1f5de,
+ 0x1f5e1, 0x1f5e1,
+ 0x1f5e3, 0x1f5e3,
+ 0x1f5e8, 0x1f5e8,
+ 0x1f5ef, 0x1f5ef,
+ 0x1f5f3, 0x1f5f3,
+ 0x1f5fa, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f6cb, 0x1f6d2,
+ 0x1f6d5, 0x1f6d8,
+ 0x1f6dc, 0x1f6e5,
+ 0x1f6e9, 0x1f6e9,
+ 0x1f6eb, 0x1f6ec,
+ 0x1f6f0, 0x1f6f0,
+ 0x1f6f3, 0x1f6fc,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f90c, 0x1f93a,
+ 0x1f93c, 0x1f945,
+ 0x1f947, 0x1f9ff,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+}; /* CR_Emoji */
+
+/* 'Emoji_Presentation': Emoji */
+static const OnigCodePoint CR_Emoji_Presentation[] = {
+ 81,
+ 0x231a, 0x231b,
+ 0x23e9, 0x23ec,
+ 0x23f0, 0x23f0,
+ 0x23f3, 0x23f3,
+ 0x25fd, 0x25fe,
+ 0x2614, 0x2615,
+ 0x2648, 0x2653,
+ 0x267f, 0x267f,
+ 0x2693, 0x2693,
+ 0x26a1, 0x26a1,
+ 0x26aa, 0x26ab,
+ 0x26bd, 0x26be,
+ 0x26c4, 0x26c5,
+ 0x26ce, 0x26ce,
+ 0x26d4, 0x26d4,
+ 0x26ea, 0x26ea,
+ 0x26f2, 0x26f3,
+ 0x26f5, 0x26f5,
+ 0x26fa, 0x26fa,
+ 0x26fd, 0x26fd,
+ 0x2705, 0x2705,
+ 0x270a, 0x270b,
+ 0x2728, 0x2728,
+ 0x274c, 0x274c,
+ 0x274e, 0x274e,
+ 0x2753, 0x2755,
+ 0x2757, 0x2757,
+ 0x2795, 0x2797,
+ 0x27b0, 0x27b0,
+ 0x27bf, 0x27bf,
+ 0x2b1b, 0x2b1c,
+ 0x2b50, 0x2b50,
+ 0x2b55, 0x2b55,
+ 0x1f004, 0x1f004,
+ 0x1f0cf, 0x1f0cf,
+ 0x1f18e, 0x1f18e,
+ 0x1f191, 0x1f19a,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f201, 0x1f201,
+ 0x1f21a, 0x1f21a,
+ 0x1f22f, 0x1f22f,
+ 0x1f232, 0x1f236,
+ 0x1f238, 0x1f23a,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f32d, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f37e, 0x1f393,
+ 0x1f3a0, 0x1f3ca,
+ 0x1f3cf, 0x1f3d3,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f3f4, 0x1f3f4,
+ 0x1f3f8, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4fc,
+ 0x1f4ff, 0x1f53d,
+ 0x1f54b, 0x1f54e,
+ 0x1f550, 0x1f567,
+ 0x1f57a, 0x1f57a,
+ 0x1f595, 0x1f596,
+ 0x1f5a4, 0x1f5a4,
+ 0x1f5fb, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f6cc, 0x1f6cc,
+ 0x1f6d0, 0x1f6d2,
+ 0x1f6d5, 0x1f6d8,
+ 0x1f6dc, 0x1f6df,
+ 0x1f6eb, 0x1f6ec,
+ 0x1f6f4, 0x1f6fc,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f90c, 0x1f93a,
+ 0x1f93c, 0x1f945,
+ 0x1f947, 0x1f9ff,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+}; /* CR_Emoji_Presentation */
+
+/* 'Emoji_Modifier': Emoji */
+static const OnigCodePoint CR_Emoji_Modifier[] = {
+ 1,
+ 0x1f3fb, 0x1f3ff,
+}; /* CR_Emoji_Modifier */
+
+/* 'Emoji_Modifier_Base': Emoji */
+static const OnigCodePoint CR_Emoji_Modifier_Base[] = {
+ 40,
+ 0x261d, 0x261d,
+ 0x26f9, 0x26f9,
+ 0x270a, 0x270d,
+ 0x1f385, 0x1f385,
+ 0x1f3c2, 0x1f3c4,
+ 0x1f3c7, 0x1f3c7,
+ 0x1f3ca, 0x1f3cc,
+ 0x1f442, 0x1f443,
+ 0x1f446, 0x1f450,
+ 0x1f466, 0x1f478,
+ 0x1f47c, 0x1f47c,
+ 0x1f481, 0x1f483,
+ 0x1f485, 0x1f487,
+ 0x1f48f, 0x1f48f,
+ 0x1f491, 0x1f491,
+ 0x1f4aa, 0x1f4aa,
+ 0x1f574, 0x1f575,
+ 0x1f57a, 0x1f57a,
+ 0x1f590, 0x1f590,
+ 0x1f595, 0x1f596,
+ 0x1f645, 0x1f647,
+ 0x1f64b, 0x1f64f,
+ 0x1f6a3, 0x1f6a3,
+ 0x1f6b4, 0x1f6b6,
+ 0x1f6c0, 0x1f6c0,
+ 0x1f6cc, 0x1f6cc,
+ 0x1f90c, 0x1f90c,
+ 0x1f90f, 0x1f90f,
+ 0x1f918, 0x1f91f,
+ 0x1f926, 0x1f926,
+ 0x1f930, 0x1f939,
+ 0x1f93c, 0x1f93e,
+ 0x1f977, 0x1f977,
+ 0x1f9b5, 0x1f9b6,
+ 0x1f9b8, 0x1f9b9,
+ 0x1f9bb, 0x1f9bb,
+ 0x1f9cd, 0x1f9cf,
+ 0x1f9d1, 0x1f9dd,
+ 0x1fac3, 0x1fac5,
+ 0x1faf0, 0x1faf8,
+}; /* CR_Emoji_Modifier_Base */
+
+/* 'Emoji_Component': Emoji */
+static const OnigCodePoint CR_Emoji_Component[] = {
+ 10,
+ 0x0023, 0x0023,
+ 0x002a, 0x002a,
+ 0x0030, 0x0039,
+ 0x200d, 0x200d,
+ 0x20e3, 0x20e3,
+ 0xfe0f, 0xfe0f,
+ 0x1f1e6, 0x1f1ff,
+ 0x1f3fb, 0x1f3ff,
+ 0x1f9b0, 0x1f9b3,
+ 0xe0020, 0xe007f,
+}; /* CR_Emoji_Component */
+
+/* 'Extended_Pictographic': Emoji */
+static const OnigCodePoint CR_Extended_Pictographic[] = {
+ 156,
+ 0x00a9, 0x00a9,
+ 0x00ae, 0x00ae,
+ 0x203c, 0x203c,
+ 0x2049, 0x2049,
+ 0x2122, 0x2122,
+ 0x2139, 0x2139,
+ 0x2194, 0x2199,
+ 0x21a9, 0x21aa,
+ 0x231a, 0x231b,
+ 0x2328, 0x2328,
+ 0x23cf, 0x23cf,
+ 0x23e9, 0x23f3,
+ 0x23f8, 0x23fa,
+ 0x24c2, 0x24c2,
+ 0x25aa, 0x25ab,
+ 0x25b6, 0x25b6,
+ 0x25c0, 0x25c0,
+ 0x25fb, 0x25fe,
+ 0x2600, 0x2604,
+ 0x260e, 0x260e,
+ 0x2611, 0x2611,
+ 0x2614, 0x2615,
+ 0x2618, 0x2618,
+ 0x261d, 0x261d,
+ 0x2620, 0x2620,
+ 0x2622, 0x2623,
+ 0x2626, 0x2626,
+ 0x262a, 0x262a,
+ 0x262e, 0x262f,
+ 0x2638, 0x263a,
+ 0x2640, 0x2640,
+ 0x2642, 0x2642,
+ 0x2648, 0x2653,
+ 0x265f, 0x2660,
+ 0x2663, 0x2663,
+ 0x2665, 0x2666,
+ 0x2668, 0x2668,
+ 0x267b, 0x267b,
+ 0x267e, 0x267f,
+ 0x2692, 0x2697,
+ 0x2699, 0x2699,
+ 0x269b, 0x269c,
+ 0x26a0, 0x26a1,
+ 0x26a7, 0x26a7,
+ 0x26aa, 0x26ab,
+ 0x26b0, 0x26b1,
+ 0x26bd, 0x26be,
+ 0x26c4, 0x26c5,
+ 0x26c8, 0x26c8,
+ 0x26ce, 0x26cf,
+ 0x26d1, 0x26d1,
+ 0x26d3, 0x26d4,
+ 0x26e9, 0x26ea,
+ 0x26f0, 0x26f5,
+ 0x26f7, 0x26fa,
+ 0x26fd, 0x26fd,
+ 0x2702, 0x2702,
+ 0x2705, 0x2705,
+ 0x2708, 0x270d,
+ 0x270f, 0x270f,
+ 0x2712, 0x2712,
+ 0x2714, 0x2714,
+ 0x2716, 0x2716,
+ 0x271d, 0x271d,
+ 0x2721, 0x2721,
+ 0x2728, 0x2728,
+ 0x2733, 0x2734,
+ 0x2744, 0x2744,
+ 0x2747, 0x2747,
+ 0x274c, 0x274c,
+ 0x274e, 0x274e,
+ 0x2753, 0x2755,
+ 0x2757, 0x2757,
+ 0x2763, 0x2764,
+ 0x2795, 0x2797,
+ 0x27a1, 0x27a1,
+ 0x27b0, 0x27b0,
+ 0x27bf, 0x27bf,
+ 0x2934, 0x2935,
+ 0x2b05, 0x2b07,
+ 0x2b1b, 0x2b1c,
+ 0x2b50, 0x2b50,
+ 0x2b55, 0x2b55,
+ 0x3030, 0x3030,
+ 0x303d, 0x303d,
+ 0x3297, 0x3297,
+ 0x3299, 0x3299,
+ 0x1f004, 0x1f004,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0cf, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f170, 0x1f171,
+ 0x1f17e, 0x1f17f,
+ 0x1f18e, 0x1f18e,
+ 0x1f191, 0x1f19a,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f201, 0x1f20f,
+ 0x1f21a, 0x1f21a,
+ 0x1f22f, 0x1f22f,
+ 0x1f232, 0x1f23a,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f25f,
+ 0x1f266, 0x1f321,
+ 0x1f324, 0x1f393,
+ 0x1f396, 0x1f397,
+ 0x1f399, 0x1f39b,
+ 0x1f39e, 0x1f3f0,
+ 0x1f3f3, 0x1f3f5,
+ 0x1f3f7, 0x1f3fa,
+ 0x1f400, 0x1f4fd,
+ 0x1f4ff, 0x1f53d,
+ 0x1f549, 0x1f54e,
+ 0x1f550, 0x1f567,
+ 0x1f56f, 0x1f570,
+ 0x1f573, 0x1f57a,
+ 0x1f587, 0x1f587,
+ 0x1f58a, 0x1f58d,
+ 0x1f590, 0x1f590,
+ 0x1f595, 0x1f596,
+ 0x1f5a4, 0x1f5a5,
+ 0x1f5a8, 0x1f5a8,
+ 0x1f5b1, 0x1f5b2,
+ 0x1f5bc, 0x1f5bc,
+ 0x1f5c2, 0x1f5c4,
+ 0x1f5d1, 0x1f5d3,
+ 0x1f5dc, 0x1f5de,
+ 0x1f5e1, 0x1f5e1,
+ 0x1f5e3, 0x1f5e3,
+ 0x1f5e8, 0x1f5e8,
+ 0x1f5ef, 0x1f5ef,
+ 0x1f5f3, 0x1f5f3,
+ 0x1f5fa, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f6cb, 0x1f6d2,
+ 0x1f6d5, 0x1f6e5,
+ 0x1f6e9, 0x1f6e9,
+ 0x1f6eb, 0x1f6f0,
+ 0x1f6f3, 0x1f6ff,
+ 0x1f7da, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1f90c, 0x1f93a,
+ 0x1f93c, 0x1f945,
+ 0x1f947, 0x1f9ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1faff,
+ 0x1fc00, 0x1fffd,
+}; /* CR_Extended_Pictographic */
+
+/* 'Unknown': Script */
+static const OnigCodePoint CR_Unknown[] = {
+ 733,
+ 0x0378, 0x0379,
+ 0x0380, 0x0383,
+ 0x038b, 0x038b,
+ 0x038d, 0x038d,
+ 0x03a2, 0x03a2,
+ 0x0530, 0x0530,
+ 0x0557, 0x0558,
+ 0x058b, 0x058c,
+ 0x0590, 0x0590,
+ 0x05c8, 0x05cf,
+ 0x05eb, 0x05ee,
+ 0x05f5, 0x05ff,
+ 0x070e, 0x070e,
+ 0x074b, 0x074c,
+ 0x07b2, 0x07bf,
+ 0x07fb, 0x07fc,
+ 0x082e, 0x082f,
+ 0x083f, 0x083f,
+ 0x085c, 0x085d,
+ 0x085f, 0x085f,
+ 0x086b, 0x086f,
+ 0x0892, 0x0896,
+ 0x0984, 0x0984,
+ 0x098d, 0x098e,
+ 0x0991, 0x0992,
+ 0x09a9, 0x09a9,
+ 0x09b1, 0x09b1,
+ 0x09b3, 0x09b5,
+ 0x09ba, 0x09bb,
+ 0x09c5, 0x09c6,
+ 0x09c9, 0x09ca,
+ 0x09cf, 0x09d6,
+ 0x09d8, 0x09db,
+ 0x09de, 0x09de,
+ 0x09e4, 0x09e5,
+ 0x09ff, 0x0a00,
+ 0x0a04, 0x0a04,
+ 0x0a0b, 0x0a0e,
+ 0x0a11, 0x0a12,
+ 0x0a29, 0x0a29,
+ 0x0a31, 0x0a31,
+ 0x0a34, 0x0a34,
+ 0x0a37, 0x0a37,
+ 0x0a3a, 0x0a3b,
+ 0x0a3d, 0x0a3d,
+ 0x0a43, 0x0a46,
+ 0x0a49, 0x0a4a,
+ 0x0a4e, 0x0a50,
+ 0x0a52, 0x0a58,
+ 0x0a5d, 0x0a5d,
+ 0x0a5f, 0x0a65,
+ 0x0a77, 0x0a80,
+ 0x0a84, 0x0a84,
+ 0x0a8e, 0x0a8e,
+ 0x0a92, 0x0a92,
+ 0x0aa9, 0x0aa9,
+ 0x0ab1, 0x0ab1,
+ 0x0ab4, 0x0ab4,
+ 0x0aba, 0x0abb,
+ 0x0ac6, 0x0ac6,
+ 0x0aca, 0x0aca,
+ 0x0ace, 0x0acf,
+ 0x0ad1, 0x0adf,
+ 0x0ae4, 0x0ae5,
+ 0x0af2, 0x0af8,
+ 0x0b00, 0x0b00,
+ 0x0b04, 0x0b04,
+ 0x0b0d, 0x0b0e,
+ 0x0b11, 0x0b12,
+ 0x0b29, 0x0b29,
+ 0x0b31, 0x0b31,
+ 0x0b34, 0x0b34,
+ 0x0b3a, 0x0b3b,
+ 0x0b45, 0x0b46,
+ 0x0b49, 0x0b4a,
+ 0x0b4e, 0x0b54,
+ 0x0b58, 0x0b5b,
+ 0x0b5e, 0x0b5e,
+ 0x0b64, 0x0b65,
+ 0x0b78, 0x0b81,
+ 0x0b84, 0x0b84,
+ 0x0b8b, 0x0b8d,
+ 0x0b91, 0x0b91,
+ 0x0b96, 0x0b98,
+ 0x0b9b, 0x0b9b,
+ 0x0b9d, 0x0b9d,
+ 0x0ba0, 0x0ba2,
+ 0x0ba5, 0x0ba7,
+ 0x0bab, 0x0bad,
+ 0x0bba, 0x0bbd,
+ 0x0bc3, 0x0bc5,
+ 0x0bc9, 0x0bc9,
+ 0x0bce, 0x0bcf,
+ 0x0bd1, 0x0bd6,
+ 0x0bd8, 0x0be5,
+ 0x0bfb, 0x0bff,
+ 0x0c0d, 0x0c0d,
+ 0x0c11, 0x0c11,
+ 0x0c29, 0x0c29,
+ 0x0c3a, 0x0c3b,
+ 0x0c45, 0x0c45,
+ 0x0c49, 0x0c49,
+ 0x0c4e, 0x0c54,
+ 0x0c57, 0x0c57,
+ 0x0c5b, 0x0c5b,
+ 0x0c5e, 0x0c5f,
+ 0x0c64, 0x0c65,
+ 0x0c70, 0x0c76,
+ 0x0c8d, 0x0c8d,
+ 0x0c91, 0x0c91,
+ 0x0ca9, 0x0ca9,
+ 0x0cb4, 0x0cb4,
+ 0x0cba, 0x0cbb,
+ 0x0cc5, 0x0cc5,
+ 0x0cc9, 0x0cc9,
+ 0x0cce, 0x0cd4,
+ 0x0cd7, 0x0cdb,
+ 0x0cdf, 0x0cdf,
+ 0x0ce4, 0x0ce5,
+ 0x0cf0, 0x0cf0,
+ 0x0cf4, 0x0cff,
+ 0x0d0d, 0x0d0d,
+ 0x0d11, 0x0d11,
+ 0x0d45, 0x0d45,
+ 0x0d49, 0x0d49,
+ 0x0d50, 0x0d53,
+ 0x0d64, 0x0d65,
+ 0x0d80, 0x0d80,
+ 0x0d84, 0x0d84,
+ 0x0d97, 0x0d99,
+ 0x0db2, 0x0db2,
+ 0x0dbc, 0x0dbc,
+ 0x0dbe, 0x0dbf,
+ 0x0dc7, 0x0dc9,
+ 0x0dcb, 0x0dce,
+ 0x0dd5, 0x0dd5,
+ 0x0dd7, 0x0dd7,
+ 0x0de0, 0x0de5,
+ 0x0df0, 0x0df1,
+ 0x0df5, 0x0e00,
+ 0x0e3b, 0x0e3e,
+ 0x0e5c, 0x0e80,
+ 0x0e83, 0x0e83,
+ 0x0e85, 0x0e85,
+ 0x0e8b, 0x0e8b,
+ 0x0ea4, 0x0ea4,
+ 0x0ea6, 0x0ea6,
+ 0x0ebe, 0x0ebf,
+ 0x0ec5, 0x0ec5,
+ 0x0ec7, 0x0ec7,
+ 0x0ecf, 0x0ecf,
+ 0x0eda, 0x0edb,
+ 0x0ee0, 0x0eff,
+ 0x0f48, 0x0f48,
+ 0x0f6d, 0x0f70,
+ 0x0f98, 0x0f98,
+ 0x0fbd, 0x0fbd,
+ 0x0fcd, 0x0fcd,
+ 0x0fdb, 0x0fff,
+ 0x10c6, 0x10c6,
+ 0x10c8, 0x10cc,
+ 0x10ce, 0x10cf,
+ 0x1249, 0x1249,
+ 0x124e, 0x124f,
+ 0x1257, 0x1257,
+ 0x1259, 0x1259,
+ 0x125e, 0x125f,
+ 0x1289, 0x1289,
+ 0x128e, 0x128f,
+ 0x12b1, 0x12b1,
+ 0x12b6, 0x12b7,
+ 0x12bf, 0x12bf,
+ 0x12c1, 0x12c1,
+ 0x12c6, 0x12c7,
+ 0x12d7, 0x12d7,
+ 0x1311, 0x1311,
+ 0x1316, 0x1317,
+ 0x135b, 0x135c,
+ 0x137d, 0x137f,
+ 0x139a, 0x139f,
+ 0x13f6, 0x13f7,
+ 0x13fe, 0x13ff,
+ 0x169d, 0x169f,
+ 0x16f9, 0x16ff,
+ 0x1716, 0x171e,
+ 0x1737, 0x173f,
+ 0x1754, 0x175f,
+ 0x176d, 0x176d,
+ 0x1771, 0x1771,
+ 0x1774, 0x177f,
+ 0x17de, 0x17df,
+ 0x17ea, 0x17ef,
+ 0x17fa, 0x17ff,
+ 0x181a, 0x181f,
+ 0x1879, 0x187f,
+ 0x18ab, 0x18af,
+ 0x18f6, 0x18ff,
+ 0x191f, 0x191f,
+ 0x192c, 0x192f,
+ 0x193c, 0x193f,
+ 0x1941, 0x1943,
+ 0x196e, 0x196f,
+ 0x1975, 0x197f,
+ 0x19ac, 0x19af,
+ 0x19ca, 0x19cf,
+ 0x19db, 0x19dd,
+ 0x1a1c, 0x1a1d,
+ 0x1a5f, 0x1a5f,
+ 0x1a7d, 0x1a7e,
+ 0x1a8a, 0x1a8f,
+ 0x1a9a, 0x1a9f,
+ 0x1aae, 0x1aaf,
+ 0x1ade, 0x1adf,
+ 0x1aec, 0x1aff,
+ 0x1b4d, 0x1b4d,
+ 0x1bf4, 0x1bfb,
+ 0x1c38, 0x1c3a,
+ 0x1c4a, 0x1c4c,
+ 0x1c8b, 0x1c8f,
+ 0x1cbb, 0x1cbc,
+ 0x1cc8, 0x1ccf,
+ 0x1cfb, 0x1cff,
+ 0x1f16, 0x1f17,
+ 0x1f1e, 0x1f1f,
+ 0x1f46, 0x1f47,
+ 0x1f4e, 0x1f4f,
+ 0x1f58, 0x1f58,
+ 0x1f5a, 0x1f5a,
+ 0x1f5c, 0x1f5c,
+ 0x1f5e, 0x1f5e,
+ 0x1f7e, 0x1f7f,
+ 0x1fb5, 0x1fb5,
+ 0x1fc5, 0x1fc5,
+ 0x1fd4, 0x1fd5,
+ 0x1fdc, 0x1fdc,
+ 0x1ff0, 0x1ff1,
+ 0x1ff5, 0x1ff5,
+ 0x1fff, 0x1fff,
+ 0x2065, 0x2065,
+ 0x2072, 0x2073,
+ 0x208f, 0x208f,
+ 0x209d, 0x209f,
+ 0x20c2, 0x20cf,
+ 0x20f1, 0x20ff,
+ 0x218c, 0x218f,
+ 0x242a, 0x243f,
+ 0x244b, 0x245f,
+ 0x2b74, 0x2b75,
+ 0x2cf4, 0x2cf8,
+ 0x2d26, 0x2d26,
+ 0x2d28, 0x2d2c,
+ 0x2d2e, 0x2d2f,
+ 0x2d68, 0x2d6e,
+ 0x2d71, 0x2d7e,
+ 0x2d97, 0x2d9f,
+ 0x2da7, 0x2da7,
+ 0x2daf, 0x2daf,
+ 0x2db7, 0x2db7,
+ 0x2dbf, 0x2dbf,
+ 0x2dc7, 0x2dc7,
+ 0x2dcf, 0x2dcf,
+ 0x2dd7, 0x2dd7,
+ 0x2ddf, 0x2ddf,
+ 0x2e5e, 0x2e7f,
+ 0x2e9a, 0x2e9a,
+ 0x2ef4, 0x2eff,
+ 0x2fd6, 0x2fef,
+ 0x3040, 0x3040,
+ 0x3097, 0x3098,
+ 0x3100, 0x3104,
+ 0x3130, 0x3130,
+ 0x318f, 0x318f,
+ 0x31e6, 0x31ee,
+ 0x321f, 0x321f,
+ 0xa48d, 0xa48f,
+ 0xa4c7, 0xa4cf,
+ 0xa62c, 0xa63f,
+ 0xa6f8, 0xa6ff,
+ 0xa7dd, 0xa7f0,
+ 0xa82d, 0xa82f,
+ 0xa83a, 0xa83f,
+ 0xa878, 0xa87f,
+ 0xa8c6, 0xa8cd,
+ 0xa8da, 0xa8df,
+ 0xa954, 0xa95e,
+ 0xa97d, 0xa97f,
+ 0xa9ce, 0xa9ce,
+ 0xa9da, 0xa9dd,
+ 0xa9ff, 0xa9ff,
+ 0xaa37, 0xaa3f,
+ 0xaa4e, 0xaa4f,
+ 0xaa5a, 0xaa5b,
+ 0xaac3, 0xaada,
+ 0xaaf7, 0xab00,
+ 0xab07, 0xab08,
+ 0xab0f, 0xab10,
+ 0xab17, 0xab1f,
+ 0xab27, 0xab27,
+ 0xab2f, 0xab2f,
+ 0xab6c, 0xab6f,
+ 0xabee, 0xabef,
+ 0xabfa, 0xabff,
+ 0xd7a4, 0xd7af,
+ 0xd7c7, 0xd7ca,
+ 0xd7fc, 0xf8ff,
+ 0xfa6e, 0xfa6f,
+ 0xfada, 0xfaff,
+ 0xfb07, 0xfb12,
+ 0xfb18, 0xfb1c,
+ 0xfb37, 0xfb37,
+ 0xfb3d, 0xfb3d,
+ 0xfb3f, 0xfb3f,
+ 0xfb42, 0xfb42,
+ 0xfb45, 0xfb45,
+ 0xfdd0, 0xfdef,
+ 0xfe1a, 0xfe1f,
+ 0xfe53, 0xfe53,
+ 0xfe67, 0xfe67,
+ 0xfe6c, 0xfe6f,
+ 0xfe75, 0xfe75,
+ 0xfefd, 0xfefe,
+ 0xff00, 0xff00,
+ 0xffbf, 0xffc1,
+ 0xffc8, 0xffc9,
+ 0xffd0, 0xffd1,
+ 0xffd8, 0xffd9,
+ 0xffdd, 0xffdf,
+ 0xffe7, 0xffe7,
+ 0xffef, 0xfff8,
+ 0xfffe, 0xffff,
+ 0x1000c, 0x1000c,
+ 0x10027, 0x10027,
+ 0x1003b, 0x1003b,
+ 0x1003e, 0x1003e,
+ 0x1004e, 0x1004f,
+ 0x1005e, 0x1007f,
+ 0x100fb, 0x100ff,
+ 0x10103, 0x10106,
+ 0x10134, 0x10136,
+ 0x1018f, 0x1018f,
+ 0x1019d, 0x1019f,
+ 0x101a1, 0x101cf,
+ 0x101fe, 0x1027f,
+ 0x1029d, 0x1029f,
+ 0x102d1, 0x102df,
+ 0x102fc, 0x102ff,
+ 0x10324, 0x1032c,
+ 0x1034b, 0x1034f,
+ 0x1037b, 0x1037f,
+ 0x1039e, 0x1039e,
+ 0x103c4, 0x103c7,
+ 0x103d6, 0x103ff,
+ 0x1049e, 0x1049f,
+ 0x104aa, 0x104af,
+ 0x104d4, 0x104d7,
+ 0x104fc, 0x104ff,
+ 0x10528, 0x1052f,
+ 0x10564, 0x1056e,
+ 0x1057b, 0x1057b,
+ 0x1058b, 0x1058b,
+ 0x10593, 0x10593,
+ 0x10596, 0x10596,
+ 0x105a2, 0x105a2,
+ 0x105b2, 0x105b2,
+ 0x105ba, 0x105ba,
+ 0x105bd, 0x105bf,
+ 0x105f4, 0x105ff,
+ 0x10737, 0x1073f,
+ 0x10756, 0x1075f,
+ 0x10768, 0x1077f,
+ 0x10786, 0x10786,
+ 0x107b1, 0x107b1,
+ 0x107bb, 0x107ff,
+ 0x10806, 0x10807,
+ 0x10809, 0x10809,
+ 0x10836, 0x10836,
+ 0x10839, 0x1083b,
+ 0x1083d, 0x1083e,
+ 0x10856, 0x10856,
+ 0x1089f, 0x108a6,
+ 0x108b0, 0x108df,
+ 0x108f3, 0x108f3,
+ 0x108f6, 0x108fa,
+ 0x1091c, 0x1091e,
+ 0x1093a, 0x1093e,
+ 0x1095a, 0x1097f,
+ 0x109b8, 0x109bb,
+ 0x109d0, 0x109d1,
+ 0x10a04, 0x10a04,
+ 0x10a07, 0x10a0b,
+ 0x10a14, 0x10a14,
+ 0x10a18, 0x10a18,
+ 0x10a36, 0x10a37,
+ 0x10a3b, 0x10a3e,
+ 0x10a49, 0x10a4f,
+ 0x10a59, 0x10a5f,
+ 0x10aa0, 0x10abf,
+ 0x10ae7, 0x10aea,
+ 0x10af7, 0x10aff,
+ 0x10b36, 0x10b38,
+ 0x10b56, 0x10b57,
+ 0x10b73, 0x10b77,
+ 0x10b92, 0x10b98,
+ 0x10b9d, 0x10ba8,
+ 0x10bb0, 0x10bff,
+ 0x10c49, 0x10c7f,
+ 0x10cb3, 0x10cbf,
+ 0x10cf3, 0x10cf9,
+ 0x10d28, 0x10d2f,
+ 0x10d3a, 0x10d3f,
+ 0x10d66, 0x10d68,
+ 0x10d86, 0x10d8d,
+ 0x10d90, 0x10e5f,
+ 0x10e7f, 0x10e7f,
+ 0x10eaa, 0x10eaa,
+ 0x10eae, 0x10eaf,
+ 0x10eb2, 0x10ec1,
+ 0x10ec8, 0x10ecf,
+ 0x10ed9, 0x10ef9,
+ 0x10f28, 0x10f2f,
+ 0x10f5a, 0x10f6f,
+ 0x10f8a, 0x10faf,
+ 0x10fcc, 0x10fdf,
+ 0x10ff7, 0x10fff,
+ 0x1104e, 0x11051,
+ 0x11076, 0x1107e,
+ 0x110c3, 0x110cc,
+ 0x110ce, 0x110cf,
+ 0x110e9, 0x110ef,
+ 0x110fa, 0x110ff,
+ 0x11135, 0x11135,
+ 0x11148, 0x1114f,
+ 0x11177, 0x1117f,
+ 0x111e0, 0x111e0,
+ 0x111f5, 0x111ff,
+ 0x11212, 0x11212,
+ 0x11242, 0x1127f,
+ 0x11287, 0x11287,
+ 0x11289, 0x11289,
+ 0x1128e, 0x1128e,
+ 0x1129e, 0x1129e,
+ 0x112aa, 0x112af,
+ 0x112eb, 0x112ef,
+ 0x112fa, 0x112ff,
+ 0x11304, 0x11304,
+ 0x1130d, 0x1130e,
+ 0x11311, 0x11312,
+ 0x11329, 0x11329,
+ 0x11331, 0x11331,
+ 0x11334, 0x11334,
+ 0x1133a, 0x1133a,
+ 0x11345, 0x11346,
+ 0x11349, 0x1134a,
+ 0x1134e, 0x1134f,
+ 0x11351, 0x11356,
+ 0x11358, 0x1135c,
+ 0x11364, 0x11365,
+ 0x1136d, 0x1136f,
+ 0x11375, 0x1137f,
+ 0x1138a, 0x1138a,
+ 0x1138c, 0x1138d,
+ 0x1138f, 0x1138f,
+ 0x113b6, 0x113b6,
+ 0x113c1, 0x113c1,
+ 0x113c3, 0x113c4,
+ 0x113c6, 0x113c6,
+ 0x113cb, 0x113cb,
+ 0x113d6, 0x113d6,
+ 0x113d9, 0x113e0,
+ 0x113e3, 0x113ff,
+ 0x1145c, 0x1145c,
+ 0x11462, 0x1147f,
+ 0x114c8, 0x114cf,
+ 0x114da, 0x1157f,
+ 0x115b6, 0x115b7,
+ 0x115de, 0x115ff,
+ 0x11645, 0x1164f,
+ 0x1165a, 0x1165f,
+ 0x1166d, 0x1167f,
+ 0x116ba, 0x116bf,
+ 0x116ca, 0x116cf,
+ 0x116e4, 0x116ff,
+ 0x1171b, 0x1171c,
+ 0x1172c, 0x1172f,
+ 0x11747, 0x117ff,
+ 0x1183c, 0x1189f,
+ 0x118f3, 0x118fe,
+ 0x11907, 0x11908,
+ 0x1190a, 0x1190b,
+ 0x11914, 0x11914,
+ 0x11917, 0x11917,
+ 0x11936, 0x11936,
+ 0x11939, 0x1193a,
+ 0x11947, 0x1194f,
+ 0x1195a, 0x1199f,
+ 0x119a8, 0x119a9,
+ 0x119d8, 0x119d9,
+ 0x119e5, 0x119ff,
+ 0x11a48, 0x11a4f,
+ 0x11aa3, 0x11aaf,
+ 0x11af9, 0x11aff,
+ 0x11b0a, 0x11b5f,
+ 0x11b68, 0x11bbf,
+ 0x11be2, 0x11bef,
+ 0x11bfa, 0x11bff,
+ 0x11c09, 0x11c09,
+ 0x11c37, 0x11c37,
+ 0x11c46, 0x11c4f,
+ 0x11c6d, 0x11c6f,
+ 0x11c90, 0x11c91,
+ 0x11ca8, 0x11ca8,
+ 0x11cb7, 0x11cff,
+ 0x11d07, 0x11d07,
+ 0x11d0a, 0x11d0a,
+ 0x11d37, 0x11d39,
+ 0x11d3b, 0x11d3b,
+ 0x11d3e, 0x11d3e,
+ 0x11d48, 0x11d4f,
+ 0x11d5a, 0x11d5f,
+ 0x11d66, 0x11d66,
+ 0x11d69, 0x11d69,
+ 0x11d8f, 0x11d8f,
+ 0x11d92, 0x11d92,
+ 0x11d99, 0x11d9f,
+ 0x11daa, 0x11daf,
+ 0x11ddc, 0x11ddf,
+ 0x11dea, 0x11edf,
+ 0x11ef9, 0x11eff,
+ 0x11f11, 0x11f11,
+ 0x11f3b, 0x11f3d,
+ 0x11f5b, 0x11faf,
+ 0x11fb1, 0x11fbf,
+ 0x11ff2, 0x11ffe,
+ 0x1239a, 0x123ff,
+ 0x1246f, 0x1246f,
+ 0x12475, 0x1247f,
+ 0x12544, 0x12f8f,
+ 0x12ff3, 0x12fff,
+ 0x13456, 0x1345f,
+ 0x143fb, 0x143ff,
+ 0x14647, 0x160ff,
+ 0x1613a, 0x167ff,
+ 0x16a39, 0x16a3f,
+ 0x16a5f, 0x16a5f,
+ 0x16a6a, 0x16a6d,
+ 0x16abf, 0x16abf,
+ 0x16aca, 0x16acf,
+ 0x16aee, 0x16aef,
+ 0x16af6, 0x16aff,
+ 0x16b46, 0x16b4f,
+ 0x16b5a, 0x16b5a,
+ 0x16b62, 0x16b62,
+ 0x16b78, 0x16b7c,
+ 0x16b90, 0x16d3f,
+ 0x16d7a, 0x16e3f,
+ 0x16e9b, 0x16e9f,
+ 0x16eb9, 0x16eba,
+ 0x16ed4, 0x16eff,
+ 0x16f4b, 0x16f4e,
+ 0x16f88, 0x16f8e,
+ 0x16fa0, 0x16fdf,
+ 0x16fe5, 0x16fef,
+ 0x16ff7, 0x16fff,
+ 0x18cd6, 0x18cfe,
+ 0x18d1f, 0x18d7f,
+ 0x18df3, 0x1afef,
+ 0x1aff4, 0x1aff4,
+ 0x1affc, 0x1affc,
+ 0x1afff, 0x1afff,
+ 0x1b123, 0x1b131,
+ 0x1b133, 0x1b14f,
+ 0x1b153, 0x1b154,
+ 0x1b156, 0x1b163,
+ 0x1b168, 0x1b16f,
+ 0x1b2fc, 0x1bbff,
+ 0x1bc6b, 0x1bc6f,
+ 0x1bc7d, 0x1bc7f,
+ 0x1bc89, 0x1bc8f,
+ 0x1bc9a, 0x1bc9b,
+ 0x1bca4, 0x1cbff,
+ 0x1ccfd, 0x1ccff,
+ 0x1ceb4, 0x1ceb9,
+ 0x1ced1, 0x1cedf,
+ 0x1cef1, 0x1ceff,
+ 0x1cf2e, 0x1cf2f,
+ 0x1cf47, 0x1cf4f,
+ 0x1cfc4, 0x1cfff,
+ 0x1d0f6, 0x1d0ff,
+ 0x1d127, 0x1d128,
+ 0x1d1eb, 0x1d1ff,
+ 0x1d246, 0x1d2bf,
+ 0x1d2d4, 0x1d2df,
+ 0x1d2f4, 0x1d2ff,
+ 0x1d357, 0x1d35f,
+ 0x1d379, 0x1d3ff,
+ 0x1d455, 0x1d455,
+ 0x1d49d, 0x1d49d,
+ 0x1d4a0, 0x1d4a1,
+ 0x1d4a3, 0x1d4a4,
+ 0x1d4a7, 0x1d4a8,
+ 0x1d4ad, 0x1d4ad,
+ 0x1d4ba, 0x1d4ba,
+ 0x1d4bc, 0x1d4bc,
+ 0x1d4c4, 0x1d4c4,
+ 0x1d506, 0x1d506,
+ 0x1d50b, 0x1d50c,
+ 0x1d515, 0x1d515,
+ 0x1d51d, 0x1d51d,
+ 0x1d53a, 0x1d53a,
+ 0x1d53f, 0x1d53f,
+ 0x1d545, 0x1d545,
+ 0x1d547, 0x1d549,
+ 0x1d551, 0x1d551,
+ 0x1d6a6, 0x1d6a7,
+ 0x1d7cc, 0x1d7cd,
+ 0x1da8c, 0x1da9a,
+ 0x1daa0, 0x1daa0,
+ 0x1dab0, 0x1deff,
+ 0x1df1f, 0x1df24,
+ 0x1df2b, 0x1dfff,
+ 0x1e007, 0x1e007,
+ 0x1e019, 0x1e01a,
+ 0x1e022, 0x1e022,
+ 0x1e025, 0x1e025,
+ 0x1e02b, 0x1e02f,
+ 0x1e06e, 0x1e08e,
+ 0x1e090, 0x1e0ff,
+ 0x1e12d, 0x1e12f,
+ 0x1e13e, 0x1e13f,
+ 0x1e14a, 0x1e14d,
+ 0x1e150, 0x1e28f,
+ 0x1e2af, 0x1e2bf,
+ 0x1e2fa, 0x1e2fe,
+ 0x1e300, 0x1e4cf,
+ 0x1e4fa, 0x1e5cf,
+ 0x1e5fb, 0x1e5fe,
+ 0x1e600, 0x1e6bf,
+ 0x1e6df, 0x1e6df,
+ 0x1e6f6, 0x1e6fd,
+ 0x1e700, 0x1e7df,
+ 0x1e7e7, 0x1e7e7,
+ 0x1e7ec, 0x1e7ec,
+ 0x1e7ef, 0x1e7ef,
+ 0x1e7ff, 0x1e7ff,
+ 0x1e8c5, 0x1e8c6,
+ 0x1e8d7, 0x1e8ff,
+ 0x1e94c, 0x1e94f,
+ 0x1e95a, 0x1e95d,
+ 0x1e960, 0x1ec70,
+ 0x1ecb5, 0x1ed00,
+ 0x1ed3e, 0x1edff,
+ 0x1ee04, 0x1ee04,
+ 0x1ee20, 0x1ee20,
+ 0x1ee23, 0x1ee23,
+ 0x1ee25, 0x1ee26,
+ 0x1ee28, 0x1ee28,
+ 0x1ee33, 0x1ee33,
+ 0x1ee38, 0x1ee38,
+ 0x1ee3a, 0x1ee3a,
+ 0x1ee3c, 0x1ee41,
+ 0x1ee43, 0x1ee46,
+ 0x1ee48, 0x1ee48,
+ 0x1ee4a, 0x1ee4a,
+ 0x1ee4c, 0x1ee4c,
+ 0x1ee50, 0x1ee50,
+ 0x1ee53, 0x1ee53,
+ 0x1ee55, 0x1ee56,
+ 0x1ee58, 0x1ee58,
+ 0x1ee5a, 0x1ee5a,
+ 0x1ee5c, 0x1ee5c,
+ 0x1ee5e, 0x1ee5e,
+ 0x1ee60, 0x1ee60,
+ 0x1ee63, 0x1ee63,
+ 0x1ee65, 0x1ee66,
+ 0x1ee6b, 0x1ee6b,
+ 0x1ee73, 0x1ee73,
+ 0x1ee78, 0x1ee78,
+ 0x1ee7d, 0x1ee7d,
+ 0x1ee7f, 0x1ee7f,
+ 0x1ee8a, 0x1ee8a,
+ 0x1ee9c, 0x1eea0,
+ 0x1eea4, 0x1eea4,
+ 0x1eeaa, 0x1eeaa,
+ 0x1eebc, 0x1eeef,
+ 0x1eef2, 0x1efff,
+ 0x1f02c, 0x1f02f,
+ 0x1f094, 0x1f09f,
+ 0x1f0af, 0x1f0b0,
+ 0x1f0c0, 0x1f0c0,
+ 0x1f0d0, 0x1f0d0,
+ 0x1f0f6, 0x1f0ff,
+ 0x1f1ae, 0x1f1e5,
+ 0x1f203, 0x1f20f,
+ 0x1f23c, 0x1f23f,
+ 0x1f249, 0x1f24f,
+ 0x1f252, 0x1f25f,
+ 0x1f266, 0x1f2ff,
+ 0x1f6d9, 0x1f6db,
+ 0x1f6ed, 0x1f6ef,
+ 0x1f6fd, 0x1f6ff,
+ 0x1f7da, 0x1f7df,
+ 0x1f7ec, 0x1f7ef,
+ 0x1f7f1, 0x1f7ff,
+ 0x1f80c, 0x1f80f,
+ 0x1f848, 0x1f84f,
+ 0x1f85a, 0x1f85f,
+ 0x1f888, 0x1f88f,
+ 0x1f8ae, 0x1f8af,
+ 0x1f8bc, 0x1f8bf,
+ 0x1f8c2, 0x1f8cf,
+ 0x1f8d9, 0x1f8ff,
+ 0x1fa58, 0x1fa5f,
+ 0x1fa6e, 0x1fa6f,
+ 0x1fa7d, 0x1fa7f,
+ 0x1fa8b, 0x1fa8d,
+ 0x1fac7, 0x1fac7,
+ 0x1fac9, 0x1facc,
+ 0x1fadd, 0x1fade,
+ 0x1faeb, 0x1faee,
+ 0x1faf9, 0x1faff,
+ 0x1fb93, 0x1fb93,
+ 0x1fbfb, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2b81e, 0x2b81f,
+ 0x2ceae, 0x2ceaf,
+ 0x2ebe1, 0x2ebef,
+ 0x2ee5e, 0x2f7ff,
+ 0x2fa1e, 0x2ffff,
+ 0x3134b, 0x3134f,
+ 0x3347a, 0xe0000,
+ 0xe0002, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0x10ffff,
+}; /* CR_Unknown */
+
+#ifdef USE_UNICODE_AGE_PROPERTIES
+/* 'Age_1_1': Derived Age 1.1 */
+static const OnigCodePoint CR_Age_1_1[] = {
+ 288,
+ 0x0000, 0x01f5,
+ 0x01fa, 0x0217,
+ 0x0250, 0x02a8,
+ 0x02b0, 0x02de,
+ 0x02e0, 0x02e9,
+ 0x0300, 0x0345,
+ 0x0360, 0x0361,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d6,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03f3,
+ 0x0401, 0x040c,
+ 0x040e, 0x044f,
+ 0x0451, 0x045c,
+ 0x045e, 0x0486,
+ 0x0490, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04eb,
+ 0x04ee, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x0589,
+ 0x05b0, 0x05b9,
+ 0x05bb, 0x05c3,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0652,
+ 0x0660, 0x066d,
+ 0x0670, 0x06b7,
+ 0x06ba, 0x06be,
+ 0x06c0, 0x06ce,
+ 0x06d0, 0x06ed,
+ 0x06f0, 0x06f9,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1e00, 0x1e9a,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x202e,
+ 0x2030, 0x2046,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20aa,
+ 0x20d0, 0x20e1,
+ 0x2100, 0x2138,
+ 0x2153, 0x2182,
+ 0x2190, 0x21ea,
+ 0x2200, 0x22f1,
+ 0x2300, 0x2300,
+ 0x2302, 0x237a,
+ 0x2400, 0x2424,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25ef,
+ 0x2600, 0x2613,
+ 0x261a, 0x266f,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x3000, 0x3037,
+ 0x303f, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x319f,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x4e00, 0x9fa5,
+ 0xe000, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1e, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffd, 0xffff,
+}; /* CR_Age_1_1 */
+
+/* 'Age_2_0': Derived Age 2.0 */
+static const OnigCodePoint CR_Age_2_0[] = {
+ 312,
+ 0x0000, 0x01f5,
+ 0x01fa, 0x0217,
+ 0x0250, 0x02a8,
+ 0x02b0, 0x02de,
+ 0x02e0, 0x02e9,
+ 0x0300, 0x0345,
+ 0x0360, 0x0361,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d6,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03f3,
+ 0x0401, 0x040c,
+ 0x040e, 0x044f,
+ 0x0451, 0x045c,
+ 0x045e, 0x0486,
+ 0x0490, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04eb,
+ 0x04ee, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x0589,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0652,
+ 0x0660, 0x066d,
+ 0x0670, 0x06b7,
+ 0x06ba, 0x06be,
+ 0x06c0, 0x06ce,
+ 0x06d0, 0x06ed,
+ 0x06f0, 0x06f9,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f69,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f95,
+ 0x0f97, 0x0f97,
+ 0x0f99, 0x0fad,
+ 0x0fb1, 0x0fb7,
+ 0x0fb9, 0x0fb9,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x202e,
+ 0x2030, 0x2046,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20ab,
+ 0x20d0, 0x20e1,
+ 0x2100, 0x2138,
+ 0x2153, 0x2182,
+ 0x2190, 0x21ea,
+ 0x2200, 0x22f1,
+ 0x2300, 0x2300,
+ 0x2302, 0x237a,
+ 0x2400, 0x2424,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25ef,
+ 0x2600, 0x2613,
+ 0x261a, 0x266f,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x3000, 0x3037,
+ 0x303f, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x319f,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x4e00, 0x9fa5,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1e, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffd, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_2_0 */
+
+/* 'Age_2_1': Derived Age 2.1 */
+static const OnigCodePoint CR_Age_2_1[] = {
+ 312,
+ 0x0000, 0x01f5,
+ 0x01fa, 0x0217,
+ 0x0250, 0x02a8,
+ 0x02b0, 0x02de,
+ 0x02e0, 0x02e9,
+ 0x0300, 0x0345,
+ 0x0360, 0x0361,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d6,
+ 0x03da, 0x03da,
+ 0x03dc, 0x03dc,
+ 0x03de, 0x03de,
+ 0x03e0, 0x03e0,
+ 0x03e2, 0x03f3,
+ 0x0401, 0x040c,
+ 0x040e, 0x044f,
+ 0x0451, 0x045c,
+ 0x045e, 0x0486,
+ 0x0490, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04eb,
+ 0x04ee, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x0589,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0652,
+ 0x0660, 0x066d,
+ 0x0670, 0x06b7,
+ 0x06ba, 0x06be,
+ 0x06c0, 0x06ce,
+ 0x06d0, 0x06ed,
+ 0x06f0, 0x06f9,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f69,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f95,
+ 0x0f97, 0x0f97,
+ 0x0f99, 0x0fad,
+ 0x0fb1, 0x0fb7,
+ 0x0fb9, 0x0fb9,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x202e,
+ 0x2030, 0x2046,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20ac,
+ 0x20d0, 0x20e1,
+ 0x2100, 0x2138,
+ 0x2153, 0x2182,
+ 0x2190, 0x21ea,
+ 0x2200, 0x22f1,
+ 0x2300, 0x2300,
+ 0x2302, 0x237a,
+ 0x2400, 0x2424,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25ef,
+ 0x2600, 0x2613,
+ 0x261a, 0x266f,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x3000, 0x3037,
+ 0x303f, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x319f,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x4e00, 0x9fa5,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1e, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfffc, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_2_1 */
+
+/* 'Age_3_0': Derived Age 3.0 */
+static const OnigCodePoint CR_Age_3_0[] = {
+ 369,
+ 0x0000, 0x021f,
+ 0x0222, 0x0233,
+ 0x0250, 0x02ad,
+ 0x02b0, 0x02ee,
+ 0x0300, 0x034e,
+ 0x0360, 0x0362,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d7,
+ 0x03da, 0x03f3,
+ 0x0400, 0x0486,
+ 0x0488, 0x0489,
+ 0x048c, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0655,
+ 0x0660, 0x066d,
+ 0x0670, 0x06ed,
+ 0x06f0, 0x06fe,
+ 0x0700, 0x070d,
+ 0x070f, 0x072c,
+ 0x0730, 0x074a,
+ 0x0780, 0x07b0,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1780, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2046,
+ 0x2048, 0x204d,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20af,
+ 0x20d0, 0x20e3,
+ 0x2100, 0x213a,
+ 0x2153, 0x2183,
+ 0x2190, 0x21f3,
+ 0x2200, 0x22f1,
+ 0x2300, 0x237b,
+ 0x237d, 0x239a,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25f7,
+ 0x2600, 0x2613,
+ 0x2619, 0x2671,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x2800, 0x28ff,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303a,
+ 0x303e, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4a1,
+ 0xa4a4, 0xa4b3,
+ 0xa4b5, 0xa4c0,
+ 0xa4c2, 0xa4c4,
+ 0xa4c6, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xffff,
+ 0x1fffe, 0x1ffff,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_3_0 */
+
+/* 'Age_3_1': Derived Age 3.1 */
+static const OnigCodePoint CR_Age_3_1[] = {
+ 402,
+ 0x0000, 0x021f,
+ 0x0222, 0x0233,
+ 0x0250, 0x02ad,
+ 0x02b0, 0x02ee,
+ 0x0300, 0x034e,
+ 0x0360, 0x0362,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03d7,
+ 0x03da, 0x03f5,
+ 0x0400, 0x0486,
+ 0x0488, 0x0489,
+ 0x048c, 0x04c4,
+ 0x04c7, 0x04c8,
+ 0x04cb, 0x04cc,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0655,
+ 0x0660, 0x066d,
+ 0x0670, 0x06ed,
+ 0x06f0, 0x06fe,
+ 0x0700, 0x070d,
+ 0x070f, 0x072c,
+ 0x0730, 0x074a,
+ 0x0780, 0x07b0,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f6,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1780, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2046,
+ 0x2048, 0x204d,
+ 0x206a, 0x2070,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20af,
+ 0x20d0, 0x20e3,
+ 0x2100, 0x213a,
+ 0x2153, 0x2183,
+ 0x2190, 0x21f3,
+ 0x2200, 0x22f1,
+ 0x2300, 0x237b,
+ 0x237d, 0x239a,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x24ea,
+ 0x2500, 0x2595,
+ 0x25a0, 0x25f7,
+ 0x2600, 0x2613,
+ 0x2619, 0x2671,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2767,
+ 0x2776, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x2800, 0x28ff,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303a,
+ 0x303e, 0x303f,
+ 0x3041, 0x3094,
+ 0x3099, 0x309e,
+ 0x30a1, 0x30fe,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x3200, 0x321c,
+ 0x3220, 0x3243,
+ 0x3260, 0x327b,
+ 0x327f, 0x32b0,
+ 0x32c0, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4a1,
+ 0xa4a4, 0xa4b3,
+ 0xa4b5, 0xa4c0,
+ 0xa4c2, 0xa4c4,
+ 0xa4c6, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfb,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe44,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe72,
+ 0xfe74, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xff5e,
+ 0xff61, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xffff,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10400, 0x10425,
+ 0x10428, 0x1044d,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d400, 0x1d454,
+ 0x1d456, 0x1d49c,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a2, 0x1d4a2,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c0,
+ 0x1d4c2, 0x1d4c3,
+ 0x1d4c5, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d51e, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d546, 0x1d546,
+ 0x1d54a, 0x1d550,
+ 0x1d552, 0x1d6a3,
+ 0x1d6a8, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_3_1 */
+
+/* 'Age_3_2': Derived Age 3.2 */
+static const OnigCodePoint CR_Age_3_2[] = {
+ 397,
+ 0x0000, 0x0220,
+ 0x0222, 0x0233,
+ 0x0250, 0x02ad,
+ 0x02b0, 0x02ee,
+ 0x0300, 0x034f,
+ 0x0360, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03f6,
+ 0x0400, 0x0486,
+ 0x0488, 0x04ce,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0500, 0x050f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x060c, 0x060c,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0655,
+ 0x0660, 0x06ed,
+ 0x06f0, 0x06fe,
+ 0x0700, 0x070d,
+ 0x070f, 0x072c,
+ 0x0730, 0x074a,
+ 0x0780, 0x07b1,
+ 0x0901, 0x0903,
+ 0x0905, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a02, 0x0a02,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8b,
+ 0x0a8d, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae0,
+ 0x0ae6, 0x0aef,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b36, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b70,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bf2,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbe, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f8,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dc,
+ 0x17e0, 0x17e9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2052,
+ 0x2057, 0x2057,
+ 0x205f, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20b1,
+ 0x20d0, 0x20ea,
+ 0x2100, 0x213a,
+ 0x213d, 0x214b,
+ 0x2153, 0x2183,
+ 0x2190, 0x23ce,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x24fe,
+ 0x2500, 0x2613,
+ 0x2616, 0x2617,
+ 0x2619, 0x267d,
+ 0x2680, 0x2689,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2aff,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31f0, 0x321c,
+ 0x3220, 0x3243,
+ 0x3251, 0x327b,
+ 0x327f, 0x32cb,
+ 0x32d0, 0x32fe,
+ 0x3300, 0x3376,
+ 0x337b, 0x33dd,
+ 0x33e0, 0x33fe,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfc,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe46,
+ 0xfe49, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0xffff,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10400, 0x10425,
+ 0x10428, 0x1044d,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d400, 0x1d454,
+ 0x1d456, 0x1d49c,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a2, 0x1d4a2,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b9,
+ 0x1d4bb, 0x1d4bb,
+ 0x1d4bd, 0x1d4c0,
+ 0x1d4c2, 0x1d4c3,
+ 0x1d4c5, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d51e, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d546, 0x1d546,
+ 0x1d54a, 0x1d550,
+ 0x1d552, 0x1d6a3,
+ 0x1d6a8, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_3_2 */
+
+/* 'Age_4_0': Derived Age 4.0 */
+static const OnigCodePoint CR_Age_4_0[] = {
+ 412,
+ 0x0000, 0x0236,
+ 0x0250, 0x0357,
+ 0x035d, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x03fb,
+ 0x0400, 0x0486,
+ 0x0488, 0x04ce,
+ 0x04d0, 0x04f5,
+ 0x04f8, 0x04f9,
+ 0x0500, 0x050f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05a1,
+ 0x05a3, 0x05b9,
+ 0x05bb, 0x05c4,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x060c, 0x0615,
+ 0x061b, 0x061b,
+ 0x061f, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x0658,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x074f,
+ 0x0780, 0x07b1,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb5,
+ 0x0bb7, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be7, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fcf,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10f8,
+ 0x10fb, 0x10fb,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 0x1206,
+ 0x1208, 0x1246,
+ 0x1248, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x1258, 0x1258,
+ 0x125a, 0x125d,
+ 0x1260, 0x1286,
+ 0x1288, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12ae,
+ 0x12b0, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c0, 0x12c0,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12ce,
+ 0x12d0, 0x12d6,
+ 0x12d8, 0x12ee,
+ 0x12f0, 0x130e,
+ 0x1310, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x131e,
+ 0x1320, 0x1346,
+ 0x1348, 0x135a,
+ 0x1361, 0x137c,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x19e0, 0x19ff,
+ 0x1d00, 0x1d6b,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2054,
+ 0x2057, 0x2057,
+ 0x205f, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x20a0, 0x20b1,
+ 0x20d0, 0x20ea,
+ 0x2100, 0x213b,
+ 0x213d, 0x214b,
+ 0x2153, 0x2183,
+ 0x2190, 0x23d0,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2617,
+ 0x2619, 0x267d,
+ 0x2680, 0x2691,
+ 0x26a0, 0x26a1,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2b0d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x327d,
+ 0x327f, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fa5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1013f,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x1039f,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d300, 0x1d356,
+ 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, 0x1d6a3,
+ 0x1d6a8, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_4_0 */
+
+/* 'Age_4_1': Derived Age 4.1 */
+static const OnigCodePoint CR_Age_4_1[] = {
+ 430,
+ 0x0000, 0x0241,
+ 0x0250, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037a,
+ 0x037e, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x0486,
+ 0x0488, 0x04ce,
+ 0x04d0, 0x04f9,
+ 0x0500, 0x050f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05b9,
+ 0x05bb, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x060b, 0x0615,
+ 0x061b, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x076d,
+ 0x0780, 0x07b1,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x097d, 0x097d,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce1,
+ 0x0ce6, 0x0cef,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fd1,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+ 0x1d00, 0x1dc3,
+ 0x1e00, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b5,
+ 0x20d0, 0x20eb,
+ 0x2100, 0x214c,
+ 0x2153, 0x2183,
+ 0x2190, 0x23db,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x269c,
+ 0x26a0, 0x26b1,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27c6,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2b13,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c80, 0x2cea,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2e00, 0x2e17,
+ 0x2e1c, 0x2e1d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31cf,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fbb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa700, 0xa716,
+ 0xa800, 0xa82b,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 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, 0x1d7c9,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_4_1 */
+
+/* 'Age_5_0': Derived Age 5.0 */
+static const OnigCodePoint CR_Age_5_0[] = {
+ 440,
+ 0x0000, 0x036f,
+ 0x0374, 0x0375,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03ce,
+ 0x03d0, 0x0486,
+ 0x0488, 0x0513,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x060b, 0x0615,
+ 0x061b, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x063a,
+ 0x0640, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x076d,
+ 0x0780, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0970,
+ 0x097b, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a74,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b43,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3e, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c60, 0x0c61,
+ 0x0c66, 0x0c6f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3e, 0x0d43,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d61,
+ 0x0d66, 0x0d6f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6a,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fcf, 0x0fd1,
+ 0x1000, 0x1021,
+ 0x1023, 0x1027,
+ 0x1029, 0x102a,
+ 0x102c, 0x1032,
+ 0x1036, 0x1039,
+ 0x1040, 0x1059,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a9,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1d00, 0x1dca,
+ 0x1dfe, 0x1e9b,
+ 0x1ea0, 0x1ef9,
+ 0x1f00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2063,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b5,
+ 0x20d0, 0x20ef,
+ 0x2100, 0x214e,
+ 0x2153, 0x2184,
+ 0x2190, 0x23e7,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x269c,
+ 0x26a0, 0x26b2,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27ca,
+ 0x27d0, 0x27eb,
+ 0x27f0, 0x2b1a,
+ 0x2b20, 0x2b23,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2c6c,
+ 0x2c74, 0x2c77,
+ 0x2c80, 0x2cea,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2e00, 0x2e17,
+ 0x2e1c, 0x2e1d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312c,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31cf,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fbb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa700, 0xa71a,
+ 0xa720, 0xa721,
+ 0xa800, 0xa82b,
+ 0xa840, 0xa877,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe23,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x10900, 0x10919,
+ 0x1091f, 0x1091f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d12a, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_5_0 */
+
+/* 'Age_5_1': Derived Age 5.1 */
+static const OnigCodePoint CR_Age_5_1[] = {
+ 455,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0523,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x0606, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0901, 0x0939,
+ 0x093c, 0x094d,
+ 0x0950, 0x0954,
+ 0x0958, 0x0972,
+ 0x097b, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fa,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fd4,
+ 0x1000, 0x1099,
+ 0x109e, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x1159,
+ 0x115f, 0x11a2,
+ 0x11a8, 0x11f9,
+ 0x1200, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x1676,
+ 0x1680, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19a9,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19d9,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a1f,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1c00, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1d00, 0x1de6,
+ 0x1dfe, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b5,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x214f,
+ 0x2153, 0x2188,
+ 0x2190, 0x23e7,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x269d,
+ 0x26a0, 0x26bc,
+ 0x26c0, 0x26c3,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x2756,
+ 0x2758, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27ca,
+ 0x27cc, 0x27cc,
+ 0x27d0, 0x2b4c,
+ 0x2b50, 0x2b54,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2c6f,
+ 0x2c71, 0x2c7d,
+ 0x2c80, 0x2cea,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e30,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x3243,
+ 0x3250, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fc3,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa500, 0xa62b,
+ 0xa640, 0xa65f,
+ 0xa662, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa700, 0xa78c,
+ 0xa7fb, 0xa82b,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa95f,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa5f,
+ 0xac00, 0xd7a3,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6a,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x1083f,
+ 0x10900, 0x10919,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1fffe, 0x2a6d6,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_5_1 */
+
+/* 'Age_5_2': Derived Age 5.2 */
+static const OnigCodePoint CR_Age_5_2[] = {
+ 495,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0525,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x0606, 0x061b,
+ 0x061e, 0x061f,
+ 0x0621, 0x065e,
+ 0x0660, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0900, 0x0939,
+ 0x093c, 0x094e,
+ 0x0950, 0x0955,
+ 0x0958, 0x0972,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b71,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d28,
+ 0x0d2a, 0x0d39,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f8b,
+ 0x0f90, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fd8,
+ 0x1000, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 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,
+ 0x135f, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1c00, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cd0, 0x1cf2,
+ 0x1d00, 0x1de6,
+ 0x1dfd, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x2094,
+ 0x20a0, 0x20b8,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23e8,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26cd,
+ 0x26cf, 0x26e1,
+ 0x26e3, 0x26e3,
+ 0x26e8, 0x26ff,
+ 0x2701, 0x2704,
+ 0x2706, 0x2709,
+ 0x270c, 0x2727,
+ 0x2729, 0x274b,
+ 0x274d, 0x274d,
+ 0x274f, 0x2752,
+ 0x2756, 0x275e,
+ 0x2761, 0x2794,
+ 0x2798, 0x27af,
+ 0x27b1, 0x27be,
+ 0x27c0, 0x27ca,
+ 0x27cc, 0x27cc,
+ 0x27d0, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf1,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d6f,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e31,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31b7,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa65f,
+ 0xa662, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa6a0, 0xa6f7,
+ 0xa700, 0xa78c,
+ 0xa7fb, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11080, 0x110c1,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f131, 0x1f131,
+ 0x1f13d, 0x1f13d,
+ 0x1f13f, 0x1f13f,
+ 0x1f142, 0x1f142,
+ 0x1f146, 0x1f146,
+ 0x1f14a, 0x1f14e,
+ 0x1f157, 0x1f157,
+ 0x1f15f, 0x1f15f,
+ 0x1f179, 0x1f179,
+ 0x1f17b, 0x1f17c,
+ 0x1f17f, 0x1f17f,
+ 0x1f18a, 0x1f18d,
+ 0x1f190, 0x1f190,
+ 0x1f200, 0x1f200,
+ 0x1f210, 0x1f231,
+ 0x1f240, 0x1f248,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_5_2 */
+
+/* 'Age_6_0': Derived Age 6.0 */
+static const OnigCodePoint CR_Age_6_0[] = {
+ 511,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0603,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0aef,
+ 0x0af1, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1bc0, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cd0, 0x1cf2,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20b9,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x27ca,
+ 0x27cc, 0x27cc,
+ 0x27ce, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf1,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e31,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa6a0, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa791,
+ 0xa7a0, 0xa7a9,
+ 0xa7fa, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa2d,
+ 0xfa30, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f169,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f5ff,
+ 0x1f601, 0x1f610,
+ 0x1f612, 0x1f614,
+ 0x1f616, 0x1f616,
+ 0x1f618, 0x1f618,
+ 0x1f61a, 0x1f61a,
+ 0x1f61c, 0x1f61e,
+ 0x1f620, 0x1f625,
+ 0x1f628, 0x1f62b,
+ 0x1f62d, 0x1f62d,
+ 0x1f630, 0x1f633,
+ 0x1f635, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_0 */
+
+/* 'Age_6_1': Derived Age 6.1 */
+static const OnigCodePoint CR_Age_6_1[] = {
+ 549,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058f, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0604,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08a0,
+ 0x08a2, 0x08ac,
+ 0x08e4, 0x08fe,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20b9,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e3b,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa697,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11180, 0x111c8,
+ 0x111d0, 0x111d9,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f540, 0x1f543,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_1 */
+
+/* 'Age_6_2': Derived Age 6.2 */
+static const OnigCodePoint CR_Age_6_2[] = {
+ 549,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058f, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0604,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08a0,
+ 0x08a2, 0x08ac,
+ 0x08e4, 0x08fe,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x206a, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20ba,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e3b,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa697,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11180, 0x111c8,
+ 0x111d0, 0x111d9,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f540, 0x1f543,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_2 */
+
+/* 'Age_6_3': Derived Age 6.3 */
+static const OnigCodePoint CR_Age_6_3[] = {
+ 549,
+ 0x0000, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058f, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x0604,
+ 0x0606, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08a0,
+ 0x08a2, 0x08ac,
+ 0x08e4, 0x08fe,
+ 0x0900, 0x0977,
+ 0x0979, 0x097f,
+ 0x0981, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d02, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20ba,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x26ff,
+ 0x2701, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e3b,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa697,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018a,
+ 0x10190, 0x1019b,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10320, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1085f,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a7f,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b7f,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x11080, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11180, 0x111c8,
+ 0x111d0, 0x111d9,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x12000, 0x1236e,
+ 0x12400, 0x12462,
+ 0x12470, 0x12473,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0be,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0df,
+ 0x1f100, 0x1f10a,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f320,
+ 0x1f330, 0x1f335,
+ 0x1f337, 0x1f37c,
+ 0x1f380, 0x1f393,
+ 0x1f3a0, 0x1f3c4,
+ 0x1f3c6, 0x1f3ca,
+ 0x1f3e0, 0x1f3f0,
+ 0x1f400, 0x1f43e,
+ 0x1f440, 0x1f440,
+ 0x1f442, 0x1f4f7,
+ 0x1f4f9, 0x1f4fc,
+ 0x1f500, 0x1f53d,
+ 0x1f540, 0x1f543,
+ 0x1f550, 0x1f567,
+ 0x1f5fb, 0x1f640,
+ 0x1f645, 0x1f64f,
+ 0x1f680, 0x1f6c5,
+ 0x1f700, 0x1f773,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_6_3 */
+
+/* 'Age_7_0': Derived Age 7.0 */
+static const OnigCodePoint CR_Age_7_0[] = {
+ 610,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08b2,
+ 0x08e4, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c81, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d01, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1cf8, 0x1cf9,
+ 0x1d00, 0x1df5,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bd,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23fa,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd1,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e42,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa69d,
+ 0xa69f, 0xa6f7,
+ 0xa700, 0xa78e,
+ 0xa790, 0xa7ad,
+ 0xa7b0, 0xa7b1,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab5f,
+ 0xab64, 0xab65,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe2d,
+ 0xfe30, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018c,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x10900, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a00, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111c8,
+ 0x111cd, 0x111cd,
+ 0x111d0, 0x111da,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123d,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11301, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115c9,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11ac0, 0x11af8,
+ 0x12000, 0x12398,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1dd,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1d7ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f32c,
+ 0x1f330, 0x1f37d,
+ 0x1f380, 0x1f3ce,
+ 0x1f3d4, 0x1f3f7,
+ 0x1f400, 0x1f4fe,
+ 0x1f500, 0x1f54a,
+ 0x1f550, 0x1f579,
+ 0x1f57b, 0x1f5a3,
+ 0x1f5a5, 0x1f642,
+ 0x1f645, 0x1f6cf,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f3,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_7_0 */
+
+/* 'Age_8_0': Derived Age 8.0 */
+static const OnigCodePoint CR_Age_8_0[] = {
+ 623,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08b4,
+ 0x08e3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0af9,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c81, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d01, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d5f, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1cf8, 0x1cf9,
+ 0x1d00, 0x1df5,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20be,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x23fa,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd1,
+ 0x2bec, 0x2bef,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e42,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fd5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ad,
+ 0xa7b0, 0xa7b7,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fd,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018c,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123d,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x11719,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11ac0, 0x11af8,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f19a,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23a,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f579,
+ 0x1f57b, 0x1f5a3,
+ 0x1f5a5, 0x1f6d0,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f3,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f910, 0x1f918,
+ 0x1f980, 0x1f984,
+ 0x1f9c0, 0x1f9c0,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_8_0 */
+
+/* 'Age_9_0': Derived Age 9.0 */
+static const OnigCodePoint CR_Age_9_0[] = {
+ 648,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d4, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0af9,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d01, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d3d, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf6,
+ 0x1cf8, 0x1cf9,
+ 0x1d00, 0x1df5,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20be,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x23fe,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd1,
+ 0x2bec, 0x2bef,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e44,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fd5,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ae,
+ 0xa7b0, 0xa7b7,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fd,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x10330, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x11719,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe0,
+ 0x17000, 0x187ec,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b001,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94a,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f300, 0x1f6d2,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f6,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f910, 0x1f91e,
+ 0x1f920, 0x1f927,
+ 0x1f930, 0x1f930,
+ 0x1f933, 0x1f93e,
+ 0x1f940, 0x1f94b,
+ 0x1f950, 0x1f95e,
+ 0x1f980, 0x1f991,
+ 0x1f9c0, 0x1f9c0,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_9_0 */
+
+/* 'Age_10_0': Derived Age 10.0 */
+static const OnigCodePoint CR_Age_10_0[] = {
+ 659,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x055f,
+ 0x0561, 0x0587,
+ 0x0589, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d4, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fd,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c03,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c83,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1cc0, 0x1cc7,
+ 0x1cd0, 0x1cf9,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bb9,
+ 0x2bbd, 0x2bc8,
+ 0x2bca, 0x2bd2,
+ 0x2bec, 0x2bef,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e49,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312e,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fea,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ae,
+ 0xa7b0, 0xa7b7,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fd,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a47,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10cff,
+ 0x10e60, 0x10e7e,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11143,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133c, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145d,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x11719,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11a83,
+ 0x11a86, 0x11a9c,
+ 0x11a9e, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x17000, 0x187ec,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d371,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94a,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f12e,
+ 0x1f130, 0x1f16b,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d4,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f8,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d4,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f910, 0x1f93e,
+ 0x1f940, 0x1f94c,
+ 0x1f950, 0x1f96b,
+ 0x1f980, 0x1f997,
+ 0x1f9c0, 0x1f9c0,
+ 0x1f9d0, 0x1f9e6,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_10_0 */
+
+/* 'Age_11_0': Derived Age 11.0 */
+static const OnigCodePoint CR_Age_11_0[] = {
+ 668,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e87, 0x0e88,
+ 0x0e8a, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ea7,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb9,
+ 0x0ebb, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cf9,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2bc8,
+ 0x2bca, 0x2bfe,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e4e,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fef,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7b9,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab65,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11146,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145e,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b7,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11a83,
+ 0x11a86, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x12000, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f44,
+ 0x16f50, 0x16f7e,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe1,
+ 0x17000, 0x187f1,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94a,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f16b,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d4,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6f9,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f910, 0x1f93e,
+ 0x1f940, 0x1f970,
+ 0x1f973, 0x1f976,
+ 0x1f97a, 0x1f97a,
+ 0x1f97c, 0x1f9a2,
+ 0x1f9b0, 0x1f9b9,
+ 0x1f9c0, 0x1f9c2,
+ 0x1f9d0, 0x1f9ff,
+ 0x1fa60, 0x1fa6d,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_11_0 */
+
+/* 'Age_12_0': Derived Age 12.0 */
+static const OnigCodePoint CR_Age_12_0[] = {
+ 677,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e4f,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x32fe,
+ 0x3300, 0x4db5,
+ 0x4dc0, 0x9fef,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7bf,
+ 0xa7c2, 0xa7c6,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab67,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11146,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145f,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe3,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f16c,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d5,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6fa,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f90d, 0x1f971,
+ 0x1f973, 0x1f976,
+ 0x1f97a, 0x1f9a2,
+ 0x1f9a5, 0x1f9aa,
+ 0x1f9ae, 0x1f9ca,
+ 0x1f9cd, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa73,
+ 0x1fa78, 0x1fa7a,
+ 0x1fa80, 0x1fa82,
+ 0x1fa90, 0x1fa95,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_12_0 */
+
+/* 'Age_12_1': Derived Age 12.1 */
+static const OnigCodePoint CR_Age_12_1[] = {
+ 676,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08bd,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d03,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d82, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1abe,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b98, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e4f,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x4db5,
+ 0x4dc0, 0x9fef,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7bf,
+ 0xa7c2, 0xa7c6,
+ 0xa7f7, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab67,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019b,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11146,
+ 0x11150, 0x11176,
+ 0x11180, 0x111cd,
+ 0x111d0, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x11459,
+ 0x1145b, 0x1145b,
+ 0x1145d, 0x1145f,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x118ff,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe3,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18af2,
+ 0x1b000, 0x1b11e,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f10c,
+ 0x1f110, 0x1f16c,
+ 0x1f170, 0x1f1ac,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d5,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6fa,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f900, 0x1f90b,
+ 0x1f90d, 0x1f971,
+ 0x1f973, 0x1f976,
+ 0x1f97a, 0x1f9a2,
+ 0x1f9a5, 0x1f9aa,
+ 0x1f9ae, 0x1f9ca,
+ 0x1f9cd, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa73,
+ 0x1fa78, 0x1fa7a,
+ 0x1fa80, 0x1fa82,
+ 0x1fa90, 0x1fa95,
+ 0x1fffe, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x2ffff,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_12_1 */
+
+/* 'Age_13_0': Derived Age 13.0 */
+static const OnigCodePoint CR_Age_13_0[] = {
+ 686,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x061c,
+ 0x061e, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x08a0, 0x08b4,
+ 0x08b6, 0x08c7,
+ 0x08d3, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3d, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x170c,
+ 0x170e, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180e,
+ 0x1810, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ac0,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1df9,
+ 0x1dfb, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20bf,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e52,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0x9ffc,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7bf,
+ 0xa7c2, 0xa7ca,
+ 0xa7f5, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdd0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1056f,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x1106f,
+ 0x1107f, 0x110c1,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b8,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x1173f,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ac0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16a6f,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18cd5,
+ 0x18d00, 0x18d08,
+ 0x1b000, 0x1b11e,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1e8,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6e0, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1f978,
+ 0x1f97a, 0x1f9cb,
+ 0x1f9cd, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa74,
+ 0x1fa78, 0x1fa7a,
+ 0x1fa80, 0x1fa86,
+ 0x1fa90, 0x1faa8,
+ 0x1fab0, 0x1fab6,
+ 0x1fac0, 0x1fac2,
+ 0x1fad0, 0x1fad6,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6dd,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_13_0 */
+
+/* 'Age_14_0': Derived Age 14.0 */
+static const OnigCodePoint CR_Age_14_0[] = {
+ 706,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0898, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf2,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b7e,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ca,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d9,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 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,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10f00, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x1123e,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x1342e,
+ 0x13430, 0x13438,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18cd5,
+ 0x18d00, 0x18d08,
+ 0x1aff0, 0x1aff3,
+ 0x1aff5, 0x1affb,
+ 0x1affd, 0x1affe,
+ 0x1b000, 0x1b122,
+ 0x1b150, 0x1b152,
+ 0x1b164, 0x1b167,
+ 0x1b170, 0x1b2fb,
+ 0x1bc00, 0x1bc6a,
+ 0x1bc70, 0x1bc7c,
+ 0x1bc80, 0x1bc88,
+ 0x1bc90, 0x1bc99,
+ 0x1bc9c, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dd, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f773,
+ 0x1f780, 0x1f7d8,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa74,
+ 0x1fa78, 0x1fa7c,
+ 0x1fa80, 0x1fa86,
+ 0x1fa90, 0x1faac,
+ 0x1fab0, 0x1faba,
+ 0x1fac0, 0x1fac5,
+ 0x1fad0, 0x1fad9,
+ 0x1fae0, 0x1fae7,
+ 0x1faf0, 0x1faf6,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b738,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_14_0 */
+
+/* 'Age_15_0': Derived Age 15.0 */
+static const OnigCodePoint CR_Age_15_0[] = {
+ 715,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0898, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b7e,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3000, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31f0, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ca,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d9,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 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,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10efd, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f776,
+ 0x1f77b, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa88,
+ 0x1fa90, 0x1fabd,
+ 0x1fabf, 0x1fac5,
+ 0x1face, 0x1fadb,
+ 0x1fae0, 0x1fae8,
+ 0x1faf0, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b739,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x323af,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_15_0 */
+
+/* 'Age_15_1': Derived Age 15.1 */
+static const OnigCodePoint CR_Age_15_1[] = {
+ 715,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0898, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b50, 0x1b7e,
+ 0x1b80, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c88,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e3,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7ca,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7d9,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 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,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10efd, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f59,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x14400, 0x14646,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f776,
+ 0x1f77b, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8b1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa88,
+ 0x1fa90, 0x1fabd,
+ 0x1fabf, 0x1fac5,
+ 0x1face, 0x1fadb,
+ 0x1fae0, 0x1fae8,
+ 0x1faf0, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbca,
+ 0x1fbf0, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b739,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x323af,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_15_1 */
+
+/* 'Age_16_0': Derived Age 16.0 */
+static const OnigCodePoint CR_Age_16_0[] = {
+ 739,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x088e,
+ 0x0890, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5d, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdd, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1ace,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c0,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2b95,
+ 0x2b97, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7cd,
+ 0xa7d0, 0xa7d1,
+ 0xa7d3, 0xa7d3,
+ 0xa7d5, 0xa7dc,
+ 0xa7f2, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbc2,
+ 0xfbd3, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdcf, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x1093f,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec4,
+ 0x10efc, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x17000, 0x187f7,
+ 0x18800, 0x18cd5,
+ 0x18cff, 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccf9,
+ 0x1cd00, 0x1ceb3,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d7,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f776,
+ 0x1f77b, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f900, 0x1fa53,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa89,
+ 0x1fa8f, 0x1fac6,
+ 0x1face, 0x1fadc,
+ 0x1fadf, 0x1fae9,
+ 0x1faf0, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbf9,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b739,
+ 0x2b740, 0x2b81d,
+ 0x2b820, 0x2cea1,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x323af,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_16_0 */
+
+/* 'Age_17_0': Derived Age 17.0 */
+static const OnigCodePoint CR_Age_17_0[] = {
+ 743,
+ 0x0000, 0x0377,
+ 0x037a, 0x037f,
+ 0x0384, 0x038a,
+ 0x038c, 0x038c,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x052f,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x058d, 0x058f,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05ef, 0x05f4,
+ 0x0600, 0x070d,
+ 0x070f, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x07fd, 0x082d,
+ 0x0830, 0x083e,
+ 0x0840, 0x085b,
+ 0x085e, 0x085e,
+ 0x0860, 0x086a,
+ 0x0870, 0x0891,
+ 0x0897, 0x0983,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b2, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e3,
+ 0x09e6, 0x09fe,
+ 0x0a01, 0x0a03,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a3c, 0x0a3c,
+ 0x0a3e, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5c,
+ 0x0a5e, 0x0a5e,
+ 0x0a66, 0x0a76,
+ 0x0a81, 0x0a83,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0abc, 0x0ac5,
+ 0x0ac7, 0x0ac9,
+ 0x0acb, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0af9, 0x0aff,
+ 0x0b01, 0x0b03,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b83,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9c, 0x0b9c,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c00, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c39,
+ 0x0c3c, 0x0c44,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c58, 0x0c5a,
+ 0x0c5c, 0x0c5d,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c77, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0cbc, 0x0cc4,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cdc, 0x0cde,
+ 0x0ce0, 0x0ce3,
+ 0x0ce6, 0x0cef,
+ 0x0cf1, 0x0cf3,
+ 0x0d00, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d44,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4f,
+ 0x0d54, 0x0d63,
+ 0x0d66, 0x0d7f,
+ 0x0d81, 0x0d83,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dbd, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0dd8, 0x0ddf,
+ 0x0de6, 0x0def,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e82,
+ 0x0e84, 0x0e84,
+ 0x0e86, 0x0e8a,
+ 0x0e8c, 0x0ea3,
+ 0x0ea5, 0x0ea5,
+ 0x0ea7, 0x0ebd,
+ 0x0ec0, 0x0ec4,
+ 0x0ec6, 0x0ec6,
+ 0x0ec8, 0x0ece,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edf,
+ 0x0f00, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f71, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fbe, 0x0fcc,
+ 0x0fce, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10c7, 0x10c7,
+ 0x10cd, 0x10cd,
+ 0x10d0, 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,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f5,
+ 0x13f8, 0x13fd,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f8,
+ 0x1700, 0x1715,
+ 0x171f, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1772, 0x1773,
+ 0x1780, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x1819,
+ 0x1820, 0x1878,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191e,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a5e,
+ 0x1a60, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b4c,
+ 0x1b4e, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c8a,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
+ 0x1cd0, 0x1cfa,
+ 0x1d00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f59, 0x1f59,
+ 0x1f5b, 0x1f5b,
+ 0x1f5d, 0x1f5d,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fc4,
+ 0x1fc6, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fdd, 0x1fef,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffe,
+ 0x2000, 0x2064,
+ 0x2066, 0x2071,
+ 0x2074, 0x208e,
+ 0x2090, 0x209c,
+ 0x20a0, 0x20c1,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x218b,
+ 0x2190, 0x2429,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b73,
+ 0x2b76, 0x2cf3,
+ 0x2cf9, 0x2d25,
+ 0x2d27, 0x2d27,
+ 0x2d2d, 0x2d2d,
+ 0x2d30, 0x2d67,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x2de0, 0x2e5d,
+ 0x2e80, 0x2e99,
+ 0x2e9b, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x303f,
+ 0x3041, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312f,
+ 0x3131, 0x318e,
+ 0x3190, 0x31e5,
+ 0x31ef, 0x321e,
+ 0x3220, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa6f7,
+ 0xa700, 0xa7dc,
+ 0xa7f1, 0xa82c,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c5,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9cd,
+ 0xa9cf, 0xa9d9,
+ 0xa9de, 0xa9fe,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaac2,
+ 0xaadb, 0xaaf6,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xab30, 0xab6b,
+ 0xab70, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xd800, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb3e, 0xfb3e,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfe19,
+ 0xfe20, 0xfe52,
+ 0xfe54, 0xfe66,
+ 0xfe68, 0xfe6b,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xfeff, 0xfeff,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffe6,
+ 0xffe8, 0xffee,
+ 0xfff9, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10100, 0x10102,
+ 0x10107, 0x10133,
+ 0x10137, 0x1018e,
+ 0x10190, 0x1019c,
+ 0x101a0, 0x101a0,
+ 0x101d0, 0x101fd,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x102e0, 0x102fb,
+ 0x10300, 0x10323,
+ 0x1032d, 0x1034a,
+ 0x10350, 0x1037a,
+ 0x10380, 0x1039d,
+ 0x1039f, 0x103c3,
+ 0x103c8, 0x103d5,
+ 0x10400, 0x1049d,
+ 0x104a0, 0x104a9,
+ 0x104b0, 0x104d3,
+ 0x104d8, 0x104fb,
+ 0x10500, 0x10527,
+ 0x10530, 0x10563,
+ 0x1056f, 0x1057a,
+ 0x1057c, 0x1058a,
+ 0x1058c, 0x10592,
+ 0x10594, 0x10595,
+ 0x10597, 0x105a1,
+ 0x105a3, 0x105b1,
+ 0x105b3, 0x105b9,
+ 0x105bb, 0x105bc,
+ 0x105c0, 0x105f3,
+ 0x10600, 0x10736,
+ 0x10740, 0x10755,
+ 0x10760, 0x10767,
+ 0x10780, 0x10785,
+ 0x10787, 0x107b0,
+ 0x107b2, 0x107ba,
+ 0x10800, 0x10805,
+ 0x10808, 0x10808,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083c, 0x1083c,
+ 0x1083f, 0x10855,
+ 0x10857, 0x1089e,
+ 0x108a7, 0x108af,
+ 0x108e0, 0x108f2,
+ 0x108f4, 0x108f5,
+ 0x108fb, 0x1091b,
+ 0x1091f, 0x10939,
+ 0x1093f, 0x10959,
+ 0x10980, 0x109b7,
+ 0x109bc, 0x109cf,
+ 0x109d2, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a35,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a48,
+ 0x10a50, 0x10a58,
+ 0x10a60, 0x10a9f,
+ 0x10ac0, 0x10ae6,
+ 0x10aeb, 0x10af6,
+ 0x10b00, 0x10b35,
+ 0x10b39, 0x10b55,
+ 0x10b58, 0x10b72,
+ 0x10b78, 0x10b91,
+ 0x10b99, 0x10b9c,
+ 0x10ba9, 0x10baf,
+ 0x10c00, 0x10c48,
+ 0x10c80, 0x10cb2,
+ 0x10cc0, 0x10cf2,
+ 0x10cfa, 0x10d27,
+ 0x10d30, 0x10d39,
+ 0x10d40, 0x10d65,
+ 0x10d69, 0x10d85,
+ 0x10d8e, 0x10d8f,
+ 0x10e60, 0x10e7e,
+ 0x10e80, 0x10ea9,
+ 0x10eab, 0x10ead,
+ 0x10eb0, 0x10eb1,
+ 0x10ec2, 0x10ec7,
+ 0x10ed0, 0x10ed8,
+ 0x10efa, 0x10f27,
+ 0x10f30, 0x10f59,
+ 0x10f70, 0x10f89,
+ 0x10fb0, 0x10fcb,
+ 0x10fe0, 0x10ff6,
+ 0x11000, 0x1104d,
+ 0x11052, 0x11075,
+ 0x1107f, 0x110c2,
+ 0x110cd, 0x110cd,
+ 0x110d0, 0x110e8,
+ 0x110f0, 0x110f9,
+ 0x11100, 0x11134,
+ 0x11136, 0x11147,
+ 0x11150, 0x11176,
+ 0x11180, 0x111df,
+ 0x111e1, 0x111f4,
+ 0x11200, 0x11211,
+ 0x11213, 0x11241,
+ 0x11280, 0x11286,
+ 0x11288, 0x11288,
+ 0x1128a, 0x1128d,
+ 0x1128f, 0x1129d,
+ 0x1129f, 0x112a9,
+ 0x112b0, 0x112ea,
+ 0x112f0, 0x112f9,
+ 0x11300, 0x11303,
+ 0x11305, 0x1130c,
+ 0x1130f, 0x11310,
+ 0x11313, 0x11328,
+ 0x1132a, 0x11330,
+ 0x11332, 0x11333,
+ 0x11335, 0x11339,
+ 0x1133b, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134d,
+ 0x11350, 0x11350,
+ 0x11357, 0x11357,
+ 0x1135d, 0x11363,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x11380, 0x11389,
+ 0x1138b, 0x1138b,
+ 0x1138e, 0x1138e,
+ 0x11390, 0x113b5,
+ 0x113b7, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113ca,
+ 0x113cc, 0x113d5,
+ 0x113d7, 0x113d8,
+ 0x113e1, 0x113e2,
+ 0x11400, 0x1145b,
+ 0x1145d, 0x11461,
+ 0x11480, 0x114c7,
+ 0x114d0, 0x114d9,
+ 0x11580, 0x115b5,
+ 0x115b8, 0x115dd,
+ 0x11600, 0x11644,
+ 0x11650, 0x11659,
+ 0x11660, 0x1166c,
+ 0x11680, 0x116b9,
+ 0x116c0, 0x116c9,
+ 0x116d0, 0x116e3,
+ 0x11700, 0x1171a,
+ 0x1171d, 0x1172b,
+ 0x11730, 0x11746,
+ 0x11800, 0x1183b,
+ 0x118a0, 0x118f2,
+ 0x118ff, 0x11906,
+ 0x11909, 0x11909,
+ 0x1190c, 0x11913,
+ 0x11915, 0x11916,
+ 0x11918, 0x11935,
+ 0x11937, 0x11938,
+ 0x1193b, 0x11946,
+ 0x11950, 0x11959,
+ 0x119a0, 0x119a7,
+ 0x119aa, 0x119d7,
+ 0x119da, 0x119e4,
+ 0x11a00, 0x11a47,
+ 0x11a50, 0x11aa2,
+ 0x11ab0, 0x11af8,
+ 0x11b00, 0x11b09,
+ 0x11b60, 0x11b67,
+ 0x11bc0, 0x11be1,
+ 0x11bf0, 0x11bf9,
+ 0x11c00, 0x11c08,
+ 0x11c0a, 0x11c36,
+ 0x11c38, 0x11c45,
+ 0x11c50, 0x11c6c,
+ 0x11c70, 0x11c8f,
+ 0x11c92, 0x11ca7,
+ 0x11ca9, 0x11cb6,
+ 0x11d00, 0x11d06,
+ 0x11d08, 0x11d09,
+ 0x11d0b, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d47,
+ 0x11d50, 0x11d59,
+ 0x11d60, 0x11d65,
+ 0x11d67, 0x11d68,
+ 0x11d6a, 0x11d8e,
+ 0x11d90, 0x11d91,
+ 0x11d93, 0x11d98,
+ 0x11da0, 0x11da9,
+ 0x11db0, 0x11ddb,
+ 0x11de0, 0x11de9,
+ 0x11ee0, 0x11ef8,
+ 0x11f00, 0x11f10,
+ 0x11f12, 0x11f3a,
+ 0x11f3e, 0x11f5a,
+ 0x11fb0, 0x11fb0,
+ 0x11fc0, 0x11ff1,
+ 0x11fff, 0x12399,
+ 0x12400, 0x1246e,
+ 0x12470, 0x12474,
+ 0x12480, 0x12543,
+ 0x12f90, 0x12ff2,
+ 0x13000, 0x13455,
+ 0x13460, 0x143fa,
+ 0x14400, 0x14646,
+ 0x16100, 0x16139,
+ 0x16800, 0x16a38,
+ 0x16a40, 0x16a5e,
+ 0x16a60, 0x16a69,
+ 0x16a6e, 0x16abe,
+ 0x16ac0, 0x16ac9,
+ 0x16ad0, 0x16aed,
+ 0x16af0, 0x16af5,
+ 0x16b00, 0x16b45,
+ 0x16b50, 0x16b59,
+ 0x16b5b, 0x16b61,
+ 0x16b63, 0x16b77,
+ 0x16b7d, 0x16b8f,
+ 0x16d40, 0x16d79,
+ 0x16e40, 0x16e9a,
+ 0x16ea0, 0x16eb8,
+ 0x16ebb, 0x16ed3,
+ 0x16f00, 0x16f4a,
+ 0x16f4f, 0x16f87,
+ 0x16f8f, 0x16f9f,
+ 0x16fe0, 0x16fe4,
+ 0x16ff0, 0x16ff6,
+ 0x17000, 0x18cd5,
+ 0x18cff, 0x18d1e,
+ 0x18d80, 0x18df2,
+ 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,
+ 0x1bc9c, 0x1bca3,
+ 0x1cc00, 0x1ccfc,
+ 0x1cd00, 0x1ceb3,
+ 0x1ceba, 0x1ced0,
+ 0x1cee0, 0x1cef0,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1cf50, 0x1cfc3,
+ 0x1d000, 0x1d0f5,
+ 0x1d100, 0x1d126,
+ 0x1d129, 0x1d1ea,
+ 0x1d200, 0x1d245,
+ 0x1d2c0, 0x1d2d3,
+ 0x1d2e0, 0x1d2f3,
+ 0x1d300, 0x1d356,
+ 0x1d360, 0x1d378,
+ 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, 0x1d7cb,
+ 0x1d7ce, 0x1da8b,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1df00, 0x1df1e,
+ 0x1df25, 0x1df2a,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e030, 0x1e06d,
+ 0x1e08f, 0x1e08f,
+ 0x1e100, 0x1e12c,
+ 0x1e130, 0x1e13d,
+ 0x1e140, 0x1e149,
+ 0x1e14e, 0x1e14f,
+ 0x1e290, 0x1e2ae,
+ 0x1e2c0, 0x1e2f9,
+ 0x1e2ff, 0x1e2ff,
+ 0x1e4d0, 0x1e4f9,
+ 0x1e5d0, 0x1e5fa,
+ 0x1e5ff, 0x1e5ff,
+ 0x1e6c0, 0x1e6de,
+ 0x1e6e0, 0x1e6f5,
+ 0x1e6fe, 0x1e6ff,
+ 0x1e7e0, 0x1e7e6,
+ 0x1e7e8, 0x1e7eb,
+ 0x1e7ed, 0x1e7ee,
+ 0x1e7f0, 0x1e7fe,
+ 0x1e800, 0x1e8c4,
+ 0x1e8c7, 0x1e8d6,
+ 0x1e900, 0x1e94b,
+ 0x1e950, 0x1e959,
+ 0x1e95e, 0x1e95f,
+ 0x1ec71, 0x1ecb4,
+ 0x1ed01, 0x1ed3d,
+ 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,
+ 0x1eef0, 0x1eef1,
+ 0x1f000, 0x1f02b,
+ 0x1f030, 0x1f093,
+ 0x1f0a0, 0x1f0ae,
+ 0x1f0b1, 0x1f0bf,
+ 0x1f0c1, 0x1f0cf,
+ 0x1f0d1, 0x1f0f5,
+ 0x1f100, 0x1f1ad,
+ 0x1f1e6, 0x1f202,
+ 0x1f210, 0x1f23b,
+ 0x1f240, 0x1f248,
+ 0x1f250, 0x1f251,
+ 0x1f260, 0x1f265,
+ 0x1f300, 0x1f6d8,
+ 0x1f6dc, 0x1f6ec,
+ 0x1f6f0, 0x1f6fc,
+ 0x1f700, 0x1f7d9,
+ 0x1f7e0, 0x1f7eb,
+ 0x1f7f0, 0x1f7f0,
+ 0x1f800, 0x1f80b,
+ 0x1f810, 0x1f847,
+ 0x1f850, 0x1f859,
+ 0x1f860, 0x1f887,
+ 0x1f890, 0x1f8ad,
+ 0x1f8b0, 0x1f8bb,
+ 0x1f8c0, 0x1f8c1,
+ 0x1f8d0, 0x1f8d8,
+ 0x1f900, 0x1fa57,
+ 0x1fa60, 0x1fa6d,
+ 0x1fa70, 0x1fa7c,
+ 0x1fa80, 0x1fa8a,
+ 0x1fa8e, 0x1fac6,
+ 0x1fac8, 0x1fac8,
+ 0x1facd, 0x1fadc,
+ 0x1fadf, 0x1faea,
+ 0x1faef, 0x1faf8,
+ 0x1fb00, 0x1fb92,
+ 0x1fb94, 0x1fbfa,
+ 0x1fffe, 0x2a6df,
+ 0x2a700, 0x2b81d,
+ 0x2b820, 0x2cead,
+ 0x2ceb0, 0x2ebe0,
+ 0x2ebf0, 0x2ee5d,
+ 0x2f800, 0x2fa1d,
+ 0x2fffe, 0x3134a,
+ 0x31350, 0x33479,
+ 0x3fffe, 0x3ffff,
+ 0x4fffe, 0x4ffff,
+ 0x5fffe, 0x5ffff,
+ 0x6fffe, 0x6ffff,
+ 0x7fffe, 0x7ffff,
+ 0x8fffe, 0x8ffff,
+ 0x9fffe, 0x9ffff,
+ 0xafffe, 0xaffff,
+ 0xbfffe, 0xbffff,
+ 0xcfffe, 0xcffff,
+ 0xdfffe, 0xdffff,
+ 0xe0001, 0xe0001,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+ 0xefffe, 0x10ffff,
+}; /* CR_Age_17_0 */
+
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+/* 'Grapheme_Cluster_Break_Prepend': Grapheme_Cluster_Break=Prepend */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_Prepend[] = {
+ 15,
+ 0x0600, 0x0605,
+ 0x06dd, 0x06dd,
+ 0x070f, 0x070f,
+ 0x0890, 0x0891,
+ 0x08e2, 0x08e2,
+ 0x0d4e, 0x0d4e,
+ 0x110bd, 0x110bd,
+ 0x110cd, 0x110cd,
+ 0x111c2, 0x111c3,
+ 0x113d1, 0x113d1,
+ 0x1193f, 0x1193f,
+ 0x11941, 0x11941,
+ 0x11a84, 0x11a89,
+ 0x11d46, 0x11d46,
+ 0x11f02, 0x11f02,
+}; /* CR_Grapheme_Cluster_Break_Prepend */
+
+/* 'Grapheme_Cluster_Break_CR': Grapheme_Cluster_Break=CR */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_CR[] = {
+ 1,
+ 0x000d, 0x000d,
+}; /* CR_Grapheme_Cluster_Break_CR */
+
+/* 'Grapheme_Cluster_Break_LF': Grapheme_Cluster_Break=LF */
+#define CR_Grapheme_Cluster_Break_LF CR_NEWLINE
+
+/* 'Grapheme_Cluster_Break_Control': Grapheme_Cluster_Break=Control */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_Control[] = {
+ 19,
+ 0x0000, 0x0009,
+ 0x000b, 0x000c,
+ 0x000e, 0x001f,
+ 0x007f, 0x009f,
+ 0x00ad, 0x00ad,
+ 0x061c, 0x061c,
+ 0x180e, 0x180e,
+ 0x200b, 0x200b,
+ 0x200e, 0x200f,
+ 0x2028, 0x202e,
+ 0x2060, 0x206f,
+ 0xfeff, 0xfeff,
+ 0xfff0, 0xfffb,
+ 0x13430, 0x1343f,
+ 0x1bca0, 0x1bca3,
+ 0x1d173, 0x1d17a,
+ 0xe0000, 0xe001f,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xe0fff,
+}; /* CR_Grapheme_Cluster_Break_Control */
+
+/* 'Grapheme_Cluster_Break_Extend': Grapheme_Cluster_Break=Extend */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_Extend[] = {
+ 384,
+ 0x0300, 0x036f,
+ 0x0483, 0x0489,
+ 0x0591, 0x05bd,
+ 0x05bf, 0x05bf,
+ 0x05c1, 0x05c2,
+ 0x05c4, 0x05c5,
+ 0x05c7, 0x05c7,
+ 0x0610, 0x061a,
+ 0x064b, 0x065f,
+ 0x0670, 0x0670,
+ 0x06d6, 0x06dc,
+ 0x06df, 0x06e4,
+ 0x06e7, 0x06e8,
+ 0x06ea, 0x06ed,
+ 0x0711, 0x0711,
+ 0x0730, 0x074a,
+ 0x07a6, 0x07b0,
+ 0x07eb, 0x07f3,
+ 0x07fd, 0x07fd,
+ 0x0816, 0x0819,
+ 0x081b, 0x0823,
+ 0x0825, 0x0827,
+ 0x0829, 0x082d,
+ 0x0859, 0x085b,
+ 0x0897, 0x089f,
+ 0x08ca, 0x08e1,
+ 0x08e3, 0x0902,
+ 0x093a, 0x093a,
+ 0x093c, 0x093c,
+ 0x0941, 0x0948,
+ 0x094d, 0x094d,
+ 0x0951, 0x0957,
+ 0x0962, 0x0963,
+ 0x0981, 0x0981,
+ 0x09bc, 0x09bc,
+ 0x09be, 0x09be,
+ 0x09c1, 0x09c4,
+ 0x09cd, 0x09cd,
+ 0x09d7, 0x09d7,
+ 0x09e2, 0x09e3,
+ 0x09fe, 0x09fe,
+ 0x0a01, 0x0a02,
+ 0x0a3c, 0x0a3c,
+ 0x0a41, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a70, 0x0a71,
+ 0x0a75, 0x0a75,
+ 0x0a81, 0x0a82,
+ 0x0abc, 0x0abc,
+ 0x0ac1, 0x0ac5,
+ 0x0ac7, 0x0ac8,
+ 0x0acd, 0x0acd,
+ 0x0ae2, 0x0ae3,
+ 0x0afa, 0x0aff,
+ 0x0b01, 0x0b01,
+ 0x0b3c, 0x0b3c,
+ 0x0b3e, 0x0b3f,
+ 0x0b41, 0x0b44,
+ 0x0b4d, 0x0b4d,
+ 0x0b55, 0x0b57,
+ 0x0b62, 0x0b63,
+ 0x0b82, 0x0b82,
+ 0x0bbe, 0x0bbe,
+ 0x0bc0, 0x0bc0,
+ 0x0bcd, 0x0bcd,
+ 0x0bd7, 0x0bd7,
+ 0x0c00, 0x0c00,
+ 0x0c04, 0x0c04,
+ 0x0c3c, 0x0c3c,
+ 0x0c3e, 0x0c40,
+ 0x0c46, 0x0c48,
+ 0x0c4a, 0x0c4d,
+ 0x0c55, 0x0c56,
+ 0x0c62, 0x0c63,
+ 0x0c81, 0x0c81,
+ 0x0cbc, 0x0cbc,
+ 0x0cbf, 0x0cc0,
+ 0x0cc2, 0x0cc2,
+ 0x0cc6, 0x0cc8,
+ 0x0cca, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0ce2, 0x0ce3,
+ 0x0d00, 0x0d01,
+ 0x0d3b, 0x0d3c,
+ 0x0d3e, 0x0d3e,
+ 0x0d41, 0x0d44,
+ 0x0d4d, 0x0d4d,
+ 0x0d57, 0x0d57,
+ 0x0d62, 0x0d63,
+ 0x0d81, 0x0d81,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0dcf,
+ 0x0dd2, 0x0dd4,
+ 0x0dd6, 0x0dd6,
+ 0x0ddf, 0x0ddf,
+ 0x0e31, 0x0e31,
+ 0x0e34, 0x0e3a,
+ 0x0e47, 0x0e4e,
+ 0x0eb1, 0x0eb1,
+ 0x0eb4, 0x0ebc,
+ 0x0ec8, 0x0ece,
+ 0x0f18, 0x0f19,
+ 0x0f35, 0x0f35,
+ 0x0f37, 0x0f37,
+ 0x0f39, 0x0f39,
+ 0x0f71, 0x0f7e,
+ 0x0f80, 0x0f84,
+ 0x0f86, 0x0f87,
+ 0x0f8d, 0x0f97,
+ 0x0f99, 0x0fbc,
+ 0x0fc6, 0x0fc6,
+ 0x102d, 0x1030,
+ 0x1032, 0x1037,
+ 0x1039, 0x103a,
+ 0x103d, 0x103e,
+ 0x1058, 0x1059,
+ 0x105e, 0x1060,
+ 0x1071, 0x1074,
+ 0x1082, 0x1082,
+ 0x1085, 0x1086,
+ 0x108d, 0x108d,
+ 0x109d, 0x109d,
+ 0x135d, 0x135f,
+ 0x1712, 0x1715,
+ 0x1732, 0x1734,
+ 0x1752, 0x1753,
+ 0x1772, 0x1773,
+ 0x17b4, 0x17b5,
+ 0x17b7, 0x17bd,
+ 0x17c6, 0x17c6,
+ 0x17c9, 0x17d3,
+ 0x17dd, 0x17dd,
+ 0x180b, 0x180d,
+ 0x180f, 0x180f,
+ 0x1885, 0x1886,
+ 0x18a9, 0x18a9,
+ 0x1920, 0x1922,
+ 0x1927, 0x1928,
+ 0x1932, 0x1932,
+ 0x1939, 0x193b,
+ 0x1a17, 0x1a18,
+ 0x1a1b, 0x1a1b,
+ 0x1a56, 0x1a56,
+ 0x1a58, 0x1a5e,
+ 0x1a60, 0x1a60,
+ 0x1a62, 0x1a62,
+ 0x1a65, 0x1a6c,
+ 0x1a73, 0x1a7c,
+ 0x1a7f, 0x1a7f,
+ 0x1ab0, 0x1add,
+ 0x1ae0, 0x1aeb,
+ 0x1b00, 0x1b03,
+ 0x1b34, 0x1b3d,
+ 0x1b42, 0x1b44,
+ 0x1b6b, 0x1b73,
+ 0x1b80, 0x1b81,
+ 0x1ba2, 0x1ba5,
+ 0x1ba8, 0x1bad,
+ 0x1be6, 0x1be6,
+ 0x1be8, 0x1be9,
+ 0x1bed, 0x1bed,
+ 0x1bef, 0x1bf3,
+ 0x1c2c, 0x1c33,
+ 0x1c36, 0x1c37,
+ 0x1cd0, 0x1cd2,
+ 0x1cd4, 0x1ce0,
+ 0x1ce2, 0x1ce8,
+ 0x1ced, 0x1ced,
+ 0x1cf4, 0x1cf4,
+ 0x1cf8, 0x1cf9,
+ 0x1dc0, 0x1dff,
+ 0x200c, 0x200c,
+ 0x20d0, 0x20f0,
+ 0x2cef, 0x2cf1,
+ 0x2d7f, 0x2d7f,
+ 0x2de0, 0x2dff,
+ 0x302a, 0x302f,
+ 0x3099, 0x309a,
+ 0xa66f, 0xa672,
+ 0xa674, 0xa67d,
+ 0xa69e, 0xa69f,
+ 0xa6f0, 0xa6f1,
+ 0xa802, 0xa802,
+ 0xa806, 0xa806,
+ 0xa80b, 0xa80b,
+ 0xa825, 0xa826,
+ 0xa82c, 0xa82c,
+ 0xa8c4, 0xa8c5,
+ 0xa8e0, 0xa8f1,
+ 0xa8ff, 0xa8ff,
+ 0xa926, 0xa92d,
+ 0xa947, 0xa951,
+ 0xa953, 0xa953,
+ 0xa980, 0xa982,
+ 0xa9b3, 0xa9b3,
+ 0xa9b6, 0xa9b9,
+ 0xa9bc, 0xa9bd,
+ 0xa9c0, 0xa9c0,
+ 0xa9e5, 0xa9e5,
+ 0xaa29, 0xaa2e,
+ 0xaa31, 0xaa32,
+ 0xaa35, 0xaa36,
+ 0xaa43, 0xaa43,
+ 0xaa4c, 0xaa4c,
+ 0xaa7c, 0xaa7c,
+ 0xaab0, 0xaab0,
+ 0xaab2, 0xaab4,
+ 0xaab7, 0xaab8,
+ 0xaabe, 0xaabf,
+ 0xaac1, 0xaac1,
+ 0xaaec, 0xaaed,
+ 0xaaf6, 0xaaf6,
+ 0xabe5, 0xabe5,
+ 0xabe8, 0xabe8,
+ 0xabed, 0xabed,
+ 0xfb1e, 0xfb1e,
+ 0xfe00, 0xfe0f,
+ 0xfe20, 0xfe2f,
+ 0xff9e, 0xff9f,
+ 0x101fd, 0x101fd,
+ 0x102e0, 0x102e0,
+ 0x10376, 0x1037a,
+ 0x10a01, 0x10a03,
+ 0x10a05, 0x10a06,
+ 0x10a0c, 0x10a0f,
+ 0x10a38, 0x10a3a,
+ 0x10a3f, 0x10a3f,
+ 0x10ae5, 0x10ae6,
+ 0x10d24, 0x10d27,
+ 0x10d69, 0x10d6d,
+ 0x10eab, 0x10eac,
+ 0x10efa, 0x10eff,
+ 0x10f46, 0x10f50,
+ 0x10f82, 0x10f85,
+ 0x11001, 0x11001,
+ 0x11038, 0x11046,
+ 0x11070, 0x11070,
+ 0x11073, 0x11074,
+ 0x1107f, 0x11081,
+ 0x110b3, 0x110b6,
+ 0x110b9, 0x110ba,
+ 0x110c2, 0x110c2,
+ 0x11100, 0x11102,
+ 0x11127, 0x1112b,
+ 0x1112d, 0x11134,
+ 0x11173, 0x11173,
+ 0x11180, 0x11181,
+ 0x111b6, 0x111be,
+ 0x111c0, 0x111c0,
+ 0x111c9, 0x111cc,
+ 0x111cf, 0x111cf,
+ 0x1122f, 0x11231,
+ 0x11234, 0x11237,
+ 0x1123e, 0x1123e,
+ 0x11241, 0x11241,
+ 0x112df, 0x112df,
+ 0x112e3, 0x112ea,
+ 0x11300, 0x11301,
+ 0x1133b, 0x1133c,
+ 0x1133e, 0x1133e,
+ 0x11340, 0x11340,
+ 0x1134d, 0x1134d,
+ 0x11357, 0x11357,
+ 0x11366, 0x1136c,
+ 0x11370, 0x11374,
+ 0x113b8, 0x113b8,
+ 0x113bb, 0x113c0,
+ 0x113c2, 0x113c2,
+ 0x113c5, 0x113c5,
+ 0x113c7, 0x113c9,
+ 0x113ce, 0x113d0,
+ 0x113d2, 0x113d2,
+ 0x113e1, 0x113e2,
+ 0x11438, 0x1143f,
+ 0x11442, 0x11444,
+ 0x11446, 0x11446,
+ 0x1145e, 0x1145e,
+ 0x114b0, 0x114b0,
+ 0x114b3, 0x114b8,
+ 0x114ba, 0x114ba,
+ 0x114bd, 0x114bd,
+ 0x114bf, 0x114c0,
+ 0x114c2, 0x114c3,
+ 0x115af, 0x115af,
+ 0x115b2, 0x115b5,
+ 0x115bc, 0x115bd,
+ 0x115bf, 0x115c0,
+ 0x115dc, 0x115dd,
+ 0x11633, 0x1163a,
+ 0x1163d, 0x1163d,
+ 0x1163f, 0x11640,
+ 0x116ab, 0x116ab,
+ 0x116ad, 0x116ad,
+ 0x116b0, 0x116b7,
+ 0x1171d, 0x1171d,
+ 0x1171f, 0x1171f,
+ 0x11722, 0x11725,
+ 0x11727, 0x1172b,
+ 0x1182f, 0x11837,
+ 0x11839, 0x1183a,
+ 0x11930, 0x11930,
+ 0x1193b, 0x1193e,
+ 0x11943, 0x11943,
+ 0x119d4, 0x119d7,
+ 0x119da, 0x119db,
+ 0x119e0, 0x119e0,
+ 0x11a01, 0x11a0a,
+ 0x11a33, 0x11a38,
+ 0x11a3b, 0x11a3e,
+ 0x11a47, 0x11a47,
+ 0x11a51, 0x11a56,
+ 0x11a59, 0x11a5b,
+ 0x11a8a, 0x11a96,
+ 0x11a98, 0x11a99,
+ 0x11b60, 0x11b60,
+ 0x11b62, 0x11b64,
+ 0x11b66, 0x11b66,
+ 0x11c30, 0x11c36,
+ 0x11c38, 0x11c3d,
+ 0x11c3f, 0x11c3f,
+ 0x11c92, 0x11ca7,
+ 0x11caa, 0x11cb0,
+ 0x11cb2, 0x11cb3,
+ 0x11cb5, 0x11cb6,
+ 0x11d31, 0x11d36,
+ 0x11d3a, 0x11d3a,
+ 0x11d3c, 0x11d3d,
+ 0x11d3f, 0x11d45,
+ 0x11d47, 0x11d47,
+ 0x11d90, 0x11d91,
+ 0x11d95, 0x11d95,
+ 0x11d97, 0x11d97,
+ 0x11ef3, 0x11ef4,
+ 0x11f00, 0x11f01,
+ 0x11f36, 0x11f3a,
+ 0x11f40, 0x11f42,
+ 0x11f5a, 0x11f5a,
+ 0x13440, 0x13440,
+ 0x13447, 0x13455,
+ 0x1611e, 0x16129,
+ 0x1612d, 0x1612f,
+ 0x16af0, 0x16af4,
+ 0x16b30, 0x16b36,
+ 0x16f4f, 0x16f4f,
+ 0x16f8f, 0x16f92,
+ 0x16fe4, 0x16fe4,
+ 0x16ff0, 0x16ff1,
+ 0x1bc9d, 0x1bc9e,
+ 0x1cf00, 0x1cf2d,
+ 0x1cf30, 0x1cf46,
+ 0x1d165, 0x1d169,
+ 0x1d16d, 0x1d172,
+ 0x1d17b, 0x1d182,
+ 0x1d185, 0x1d18b,
+ 0x1d1aa, 0x1d1ad,
+ 0x1d242, 0x1d244,
+ 0x1da00, 0x1da36,
+ 0x1da3b, 0x1da6c,
+ 0x1da75, 0x1da75,
+ 0x1da84, 0x1da84,
+ 0x1da9b, 0x1da9f,
+ 0x1daa1, 0x1daaf,
+ 0x1e000, 0x1e006,
+ 0x1e008, 0x1e018,
+ 0x1e01b, 0x1e021,
+ 0x1e023, 0x1e024,
+ 0x1e026, 0x1e02a,
+ 0x1e08f, 0x1e08f,
+ 0x1e130, 0x1e136,
+ 0x1e2ae, 0x1e2ae,
+ 0x1e2ec, 0x1e2ef,
+ 0x1e4ec, 0x1e4ef,
+ 0x1e5ee, 0x1e5ef,
+ 0x1e6e3, 0x1e6e3,
+ 0x1e6e6, 0x1e6e6,
+ 0x1e6ee, 0x1e6ef,
+ 0x1e6f5, 0x1e6f5,
+ 0x1e8d0, 0x1e8d6,
+ 0x1e944, 0x1e94a,
+ 0x1f3fb, 0x1f3ff,
+ 0xe0020, 0xe007f,
+ 0xe0100, 0xe01ef,
+}; /* CR_Grapheme_Cluster_Break_Extend */
+
+/* 'Grapheme_Cluster_Break_Regional_Indicator': Grapheme_Cluster_Break=Regional_Indicator */
+#define CR_Grapheme_Cluster_Break_Regional_Indicator CR_Regional_Indicator
+
+/* 'Grapheme_Cluster_Break_SpacingMark': Grapheme_Cluster_Break=SpacingMark */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_SpacingMark[] = {
+ 158,
+ 0x0903, 0x0903,
+ 0x093b, 0x093b,
+ 0x093e, 0x0940,
+ 0x0949, 0x094c,
+ 0x094e, 0x094f,
+ 0x0982, 0x0983,
+ 0x09bf, 0x09c0,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09cc,
+ 0x0a03, 0x0a03,
+ 0x0a3e, 0x0a40,
+ 0x0a83, 0x0a83,
+ 0x0abe, 0x0ac0,
+ 0x0ac9, 0x0ac9,
+ 0x0acb, 0x0acc,
+ 0x0b02, 0x0b03,
+ 0x0b40, 0x0b40,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4c,
+ 0x0bbf, 0x0bbf,
+ 0x0bc1, 0x0bc2,
+ 0x0bc6, 0x0bc8,
+ 0x0bca, 0x0bcc,
+ 0x0c01, 0x0c03,
+ 0x0c41, 0x0c44,
+ 0x0c82, 0x0c83,
+ 0x0cbe, 0x0cbe,
+ 0x0cc1, 0x0cc1,
+ 0x0cc3, 0x0cc4,
+ 0x0cf3, 0x0cf3,
+ 0x0d02, 0x0d03,
+ 0x0d3f, 0x0d40,
+ 0x0d46, 0x0d48,
+ 0x0d4a, 0x0d4c,
+ 0x0d82, 0x0d83,
+ 0x0dd0, 0x0dd1,
+ 0x0dd8, 0x0dde,
+ 0x0df2, 0x0df3,
+ 0x0e33, 0x0e33,
+ 0x0eb3, 0x0eb3,
+ 0x0f3e, 0x0f3f,
+ 0x0f7f, 0x0f7f,
+ 0x1031, 0x1031,
+ 0x103b, 0x103c,
+ 0x1056, 0x1057,
+ 0x1084, 0x1084,
+ 0x17b6, 0x17b6,
+ 0x17be, 0x17c5,
+ 0x17c7, 0x17c8,
+ 0x1923, 0x1926,
+ 0x1929, 0x192b,
+ 0x1930, 0x1931,
+ 0x1933, 0x1938,
+ 0x1a19, 0x1a1a,
+ 0x1a55, 0x1a55,
+ 0x1a57, 0x1a57,
+ 0x1a6d, 0x1a72,
+ 0x1b04, 0x1b04,
+ 0x1b3e, 0x1b41,
+ 0x1b82, 0x1b82,
+ 0x1ba1, 0x1ba1,
+ 0x1ba6, 0x1ba7,
+ 0x1be7, 0x1be7,
+ 0x1bea, 0x1bec,
+ 0x1bee, 0x1bee,
+ 0x1c24, 0x1c2b,
+ 0x1c34, 0x1c35,
+ 0x1ce1, 0x1ce1,
+ 0x1cf7, 0x1cf7,
+ 0xa823, 0xa824,
+ 0xa827, 0xa827,
+ 0xa880, 0xa881,
+ 0xa8b4, 0xa8c3,
+ 0xa952, 0xa952,
+ 0xa983, 0xa983,
+ 0xa9b4, 0xa9b5,
+ 0xa9ba, 0xa9bb,
+ 0xa9be, 0xa9bf,
+ 0xaa2f, 0xaa30,
+ 0xaa33, 0xaa34,
+ 0xaa4d, 0xaa4d,
+ 0xaaeb, 0xaaeb,
+ 0xaaee, 0xaaef,
+ 0xaaf5, 0xaaf5,
+ 0xabe3, 0xabe4,
+ 0xabe6, 0xabe7,
+ 0xabe9, 0xabea,
+ 0xabec, 0xabec,
+ 0x11000, 0x11000,
+ 0x11002, 0x11002,
+ 0x11082, 0x11082,
+ 0x110b0, 0x110b2,
+ 0x110b7, 0x110b8,
+ 0x1112c, 0x1112c,
+ 0x11145, 0x11146,
+ 0x11182, 0x11182,
+ 0x111b3, 0x111b5,
+ 0x111bf, 0x111bf,
+ 0x111ce, 0x111ce,
+ 0x1122c, 0x1122e,
+ 0x11232, 0x11233,
+ 0x112e0, 0x112e2,
+ 0x11302, 0x11303,
+ 0x1133f, 0x1133f,
+ 0x11341, 0x11344,
+ 0x11347, 0x11348,
+ 0x1134b, 0x1134c,
+ 0x11362, 0x11363,
+ 0x113b9, 0x113ba,
+ 0x113ca, 0x113ca,
+ 0x113cc, 0x113cd,
+ 0x11435, 0x11437,
+ 0x11440, 0x11441,
+ 0x11445, 0x11445,
+ 0x114b1, 0x114b2,
+ 0x114b9, 0x114b9,
+ 0x114bb, 0x114bc,
+ 0x114be, 0x114be,
+ 0x114c1, 0x114c1,
+ 0x115b0, 0x115b1,
+ 0x115b8, 0x115bb,
+ 0x115be, 0x115be,
+ 0x11630, 0x11632,
+ 0x1163b, 0x1163c,
+ 0x1163e, 0x1163e,
+ 0x116ac, 0x116ac,
+ 0x116ae, 0x116af,
+ 0x1171e, 0x1171e,
+ 0x11726, 0x11726,
+ 0x1182c, 0x1182e,
+ 0x11838, 0x11838,
+ 0x11931, 0x11935,
+ 0x11937, 0x11938,
+ 0x11940, 0x11940,
+ 0x11942, 0x11942,
+ 0x119d1, 0x119d3,
+ 0x119dc, 0x119df,
+ 0x119e4, 0x119e4,
+ 0x11a39, 0x11a39,
+ 0x11a57, 0x11a58,
+ 0x11a97, 0x11a97,
+ 0x11b61, 0x11b61,
+ 0x11b65, 0x11b65,
+ 0x11b67, 0x11b67,
+ 0x11c2f, 0x11c2f,
+ 0x11c3e, 0x11c3e,
+ 0x11ca9, 0x11ca9,
+ 0x11cb1, 0x11cb1,
+ 0x11cb4, 0x11cb4,
+ 0x11d8a, 0x11d8e,
+ 0x11d93, 0x11d94,
+ 0x11d96, 0x11d96,
+ 0x11ef5, 0x11ef6,
+ 0x11f03, 0x11f03,
+ 0x11f34, 0x11f35,
+ 0x11f3e, 0x11f3f,
+ 0x1612a, 0x1612c,
+ 0x16f51, 0x16f87,
+}; /* CR_Grapheme_Cluster_Break_SpacingMark */
+
+/* 'Grapheme_Cluster_Break_L': Grapheme_Cluster_Break=L */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_L[] = {
+ 2,
+ 0x1100, 0x115f,
+ 0xa960, 0xa97c,
+}; /* CR_Grapheme_Cluster_Break_L */
+
+/* 'Grapheme_Cluster_Break_V': Grapheme_Cluster_Break=V */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_V[] = {
+ 4,
+ 0x1160, 0x11a7,
+ 0xd7b0, 0xd7c6,
+ 0x16d63, 0x16d63,
+ 0x16d67, 0x16d6a,
+}; /* CR_Grapheme_Cluster_Break_V */
+
+/* 'Grapheme_Cluster_Break_T': Grapheme_Cluster_Break=T */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_T[] = {
+ 2,
+ 0x11a8, 0x11ff,
+ 0xd7cb, 0xd7fb,
+}; /* CR_Grapheme_Cluster_Break_T */
+
+/* 'Grapheme_Cluster_Break_LV': Grapheme_Cluster_Break=LV */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_LV[] = {
+ 399,
+ 0xac00, 0xac00,
+ 0xac1c, 0xac1c,
+ 0xac38, 0xac38,
+ 0xac54, 0xac54,
+ 0xac70, 0xac70,
+ 0xac8c, 0xac8c,
+ 0xaca8, 0xaca8,
+ 0xacc4, 0xacc4,
+ 0xace0, 0xace0,
+ 0xacfc, 0xacfc,
+ 0xad18, 0xad18,
+ 0xad34, 0xad34,
+ 0xad50, 0xad50,
+ 0xad6c, 0xad6c,
+ 0xad88, 0xad88,
+ 0xada4, 0xada4,
+ 0xadc0, 0xadc0,
+ 0xaddc, 0xaddc,
+ 0xadf8, 0xadf8,
+ 0xae14, 0xae14,
+ 0xae30, 0xae30,
+ 0xae4c, 0xae4c,
+ 0xae68, 0xae68,
+ 0xae84, 0xae84,
+ 0xaea0, 0xaea0,
+ 0xaebc, 0xaebc,
+ 0xaed8, 0xaed8,
+ 0xaef4, 0xaef4,
+ 0xaf10, 0xaf10,
+ 0xaf2c, 0xaf2c,
+ 0xaf48, 0xaf48,
+ 0xaf64, 0xaf64,
+ 0xaf80, 0xaf80,
+ 0xaf9c, 0xaf9c,
+ 0xafb8, 0xafb8,
+ 0xafd4, 0xafd4,
+ 0xaff0, 0xaff0,
+ 0xb00c, 0xb00c,
+ 0xb028, 0xb028,
+ 0xb044, 0xb044,
+ 0xb060, 0xb060,
+ 0xb07c, 0xb07c,
+ 0xb098, 0xb098,
+ 0xb0b4, 0xb0b4,
+ 0xb0d0, 0xb0d0,
+ 0xb0ec, 0xb0ec,
+ 0xb108, 0xb108,
+ 0xb124, 0xb124,
+ 0xb140, 0xb140,
+ 0xb15c, 0xb15c,
+ 0xb178, 0xb178,
+ 0xb194, 0xb194,
+ 0xb1b0, 0xb1b0,
+ 0xb1cc, 0xb1cc,
+ 0xb1e8, 0xb1e8,
+ 0xb204, 0xb204,
+ 0xb220, 0xb220,
+ 0xb23c, 0xb23c,
+ 0xb258, 0xb258,
+ 0xb274, 0xb274,
+ 0xb290, 0xb290,
+ 0xb2ac, 0xb2ac,
+ 0xb2c8, 0xb2c8,
+ 0xb2e4, 0xb2e4,
+ 0xb300, 0xb300,
+ 0xb31c, 0xb31c,
+ 0xb338, 0xb338,
+ 0xb354, 0xb354,
+ 0xb370, 0xb370,
+ 0xb38c, 0xb38c,
+ 0xb3a8, 0xb3a8,
+ 0xb3c4, 0xb3c4,
+ 0xb3e0, 0xb3e0,
+ 0xb3fc, 0xb3fc,
+ 0xb418, 0xb418,
+ 0xb434, 0xb434,
+ 0xb450, 0xb450,
+ 0xb46c, 0xb46c,
+ 0xb488, 0xb488,
+ 0xb4a4, 0xb4a4,
+ 0xb4c0, 0xb4c0,
+ 0xb4dc, 0xb4dc,
+ 0xb4f8, 0xb4f8,
+ 0xb514, 0xb514,
+ 0xb530, 0xb530,
+ 0xb54c, 0xb54c,
+ 0xb568, 0xb568,
+ 0xb584, 0xb584,
+ 0xb5a0, 0xb5a0,
+ 0xb5bc, 0xb5bc,
+ 0xb5d8, 0xb5d8,
+ 0xb5f4, 0xb5f4,
+ 0xb610, 0xb610,
+ 0xb62c, 0xb62c,
+ 0xb648, 0xb648,
+ 0xb664, 0xb664,
+ 0xb680, 0xb680,
+ 0xb69c, 0xb69c,
+ 0xb6b8, 0xb6b8,
+ 0xb6d4, 0xb6d4,
+ 0xb6f0, 0xb6f0,
+ 0xb70c, 0xb70c,
+ 0xb728, 0xb728,
+ 0xb744, 0xb744,
+ 0xb760, 0xb760,
+ 0xb77c, 0xb77c,
+ 0xb798, 0xb798,
+ 0xb7b4, 0xb7b4,
+ 0xb7d0, 0xb7d0,
+ 0xb7ec, 0xb7ec,
+ 0xb808, 0xb808,
+ 0xb824, 0xb824,
+ 0xb840, 0xb840,
+ 0xb85c, 0xb85c,
+ 0xb878, 0xb878,
+ 0xb894, 0xb894,
+ 0xb8b0, 0xb8b0,
+ 0xb8cc, 0xb8cc,
+ 0xb8e8, 0xb8e8,
+ 0xb904, 0xb904,
+ 0xb920, 0xb920,
+ 0xb93c, 0xb93c,
+ 0xb958, 0xb958,
+ 0xb974, 0xb974,
+ 0xb990, 0xb990,
+ 0xb9ac, 0xb9ac,
+ 0xb9c8, 0xb9c8,
+ 0xb9e4, 0xb9e4,
+ 0xba00, 0xba00,
+ 0xba1c, 0xba1c,
+ 0xba38, 0xba38,
+ 0xba54, 0xba54,
+ 0xba70, 0xba70,
+ 0xba8c, 0xba8c,
+ 0xbaa8, 0xbaa8,
+ 0xbac4, 0xbac4,
+ 0xbae0, 0xbae0,
+ 0xbafc, 0xbafc,
+ 0xbb18, 0xbb18,
+ 0xbb34, 0xbb34,
+ 0xbb50, 0xbb50,
+ 0xbb6c, 0xbb6c,
+ 0xbb88, 0xbb88,
+ 0xbba4, 0xbba4,
+ 0xbbc0, 0xbbc0,
+ 0xbbdc, 0xbbdc,
+ 0xbbf8, 0xbbf8,
+ 0xbc14, 0xbc14,
+ 0xbc30, 0xbc30,
+ 0xbc4c, 0xbc4c,
+ 0xbc68, 0xbc68,
+ 0xbc84, 0xbc84,
+ 0xbca0, 0xbca0,
+ 0xbcbc, 0xbcbc,
+ 0xbcd8, 0xbcd8,
+ 0xbcf4, 0xbcf4,
+ 0xbd10, 0xbd10,
+ 0xbd2c, 0xbd2c,
+ 0xbd48, 0xbd48,
+ 0xbd64, 0xbd64,
+ 0xbd80, 0xbd80,
+ 0xbd9c, 0xbd9c,
+ 0xbdb8, 0xbdb8,
+ 0xbdd4, 0xbdd4,
+ 0xbdf0, 0xbdf0,
+ 0xbe0c, 0xbe0c,
+ 0xbe28, 0xbe28,
+ 0xbe44, 0xbe44,
+ 0xbe60, 0xbe60,
+ 0xbe7c, 0xbe7c,
+ 0xbe98, 0xbe98,
+ 0xbeb4, 0xbeb4,
+ 0xbed0, 0xbed0,
+ 0xbeec, 0xbeec,
+ 0xbf08, 0xbf08,
+ 0xbf24, 0xbf24,
+ 0xbf40, 0xbf40,
+ 0xbf5c, 0xbf5c,
+ 0xbf78, 0xbf78,
+ 0xbf94, 0xbf94,
+ 0xbfb0, 0xbfb0,
+ 0xbfcc, 0xbfcc,
+ 0xbfe8, 0xbfe8,
+ 0xc004, 0xc004,
+ 0xc020, 0xc020,
+ 0xc03c, 0xc03c,
+ 0xc058, 0xc058,
+ 0xc074, 0xc074,
+ 0xc090, 0xc090,
+ 0xc0ac, 0xc0ac,
+ 0xc0c8, 0xc0c8,
+ 0xc0e4, 0xc0e4,
+ 0xc100, 0xc100,
+ 0xc11c, 0xc11c,
+ 0xc138, 0xc138,
+ 0xc154, 0xc154,
+ 0xc170, 0xc170,
+ 0xc18c, 0xc18c,
+ 0xc1a8, 0xc1a8,
+ 0xc1c4, 0xc1c4,
+ 0xc1e0, 0xc1e0,
+ 0xc1fc, 0xc1fc,
+ 0xc218, 0xc218,
+ 0xc234, 0xc234,
+ 0xc250, 0xc250,
+ 0xc26c, 0xc26c,
+ 0xc288, 0xc288,
+ 0xc2a4, 0xc2a4,
+ 0xc2c0, 0xc2c0,
+ 0xc2dc, 0xc2dc,
+ 0xc2f8, 0xc2f8,
+ 0xc314, 0xc314,
+ 0xc330, 0xc330,
+ 0xc34c, 0xc34c,
+ 0xc368, 0xc368,
+ 0xc384, 0xc384,
+ 0xc3a0, 0xc3a0,
+ 0xc3bc, 0xc3bc,
+ 0xc3d8, 0xc3d8,
+ 0xc3f4, 0xc3f4,
+ 0xc410, 0xc410,
+ 0xc42c, 0xc42c,
+ 0xc448, 0xc448,
+ 0xc464, 0xc464,
+ 0xc480, 0xc480,
+ 0xc49c, 0xc49c,
+ 0xc4b8, 0xc4b8,
+ 0xc4d4, 0xc4d4,
+ 0xc4f0, 0xc4f0,
+ 0xc50c, 0xc50c,
+ 0xc528, 0xc528,
+ 0xc544, 0xc544,
+ 0xc560, 0xc560,
+ 0xc57c, 0xc57c,
+ 0xc598, 0xc598,
+ 0xc5b4, 0xc5b4,
+ 0xc5d0, 0xc5d0,
+ 0xc5ec, 0xc5ec,
+ 0xc608, 0xc608,
+ 0xc624, 0xc624,
+ 0xc640, 0xc640,
+ 0xc65c, 0xc65c,
+ 0xc678, 0xc678,
+ 0xc694, 0xc694,
+ 0xc6b0, 0xc6b0,
+ 0xc6cc, 0xc6cc,
+ 0xc6e8, 0xc6e8,
+ 0xc704, 0xc704,
+ 0xc720, 0xc720,
+ 0xc73c, 0xc73c,
+ 0xc758, 0xc758,
+ 0xc774, 0xc774,
+ 0xc790, 0xc790,
+ 0xc7ac, 0xc7ac,
+ 0xc7c8, 0xc7c8,
+ 0xc7e4, 0xc7e4,
+ 0xc800, 0xc800,
+ 0xc81c, 0xc81c,
+ 0xc838, 0xc838,
+ 0xc854, 0xc854,
+ 0xc870, 0xc870,
+ 0xc88c, 0xc88c,
+ 0xc8a8, 0xc8a8,
+ 0xc8c4, 0xc8c4,
+ 0xc8e0, 0xc8e0,
+ 0xc8fc, 0xc8fc,
+ 0xc918, 0xc918,
+ 0xc934, 0xc934,
+ 0xc950, 0xc950,
+ 0xc96c, 0xc96c,
+ 0xc988, 0xc988,
+ 0xc9a4, 0xc9a4,
+ 0xc9c0, 0xc9c0,
+ 0xc9dc, 0xc9dc,
+ 0xc9f8, 0xc9f8,
+ 0xca14, 0xca14,
+ 0xca30, 0xca30,
+ 0xca4c, 0xca4c,
+ 0xca68, 0xca68,
+ 0xca84, 0xca84,
+ 0xcaa0, 0xcaa0,
+ 0xcabc, 0xcabc,
+ 0xcad8, 0xcad8,
+ 0xcaf4, 0xcaf4,
+ 0xcb10, 0xcb10,
+ 0xcb2c, 0xcb2c,
+ 0xcb48, 0xcb48,
+ 0xcb64, 0xcb64,
+ 0xcb80, 0xcb80,
+ 0xcb9c, 0xcb9c,
+ 0xcbb8, 0xcbb8,
+ 0xcbd4, 0xcbd4,
+ 0xcbf0, 0xcbf0,
+ 0xcc0c, 0xcc0c,
+ 0xcc28, 0xcc28,
+ 0xcc44, 0xcc44,
+ 0xcc60, 0xcc60,
+ 0xcc7c, 0xcc7c,
+ 0xcc98, 0xcc98,
+ 0xccb4, 0xccb4,
+ 0xccd0, 0xccd0,
+ 0xccec, 0xccec,
+ 0xcd08, 0xcd08,
+ 0xcd24, 0xcd24,
+ 0xcd40, 0xcd40,
+ 0xcd5c, 0xcd5c,
+ 0xcd78, 0xcd78,
+ 0xcd94, 0xcd94,
+ 0xcdb0, 0xcdb0,
+ 0xcdcc, 0xcdcc,
+ 0xcde8, 0xcde8,
+ 0xce04, 0xce04,
+ 0xce20, 0xce20,
+ 0xce3c, 0xce3c,
+ 0xce58, 0xce58,
+ 0xce74, 0xce74,
+ 0xce90, 0xce90,
+ 0xceac, 0xceac,
+ 0xcec8, 0xcec8,
+ 0xcee4, 0xcee4,
+ 0xcf00, 0xcf00,
+ 0xcf1c, 0xcf1c,
+ 0xcf38, 0xcf38,
+ 0xcf54, 0xcf54,
+ 0xcf70, 0xcf70,
+ 0xcf8c, 0xcf8c,
+ 0xcfa8, 0xcfa8,
+ 0xcfc4, 0xcfc4,
+ 0xcfe0, 0xcfe0,
+ 0xcffc, 0xcffc,
+ 0xd018, 0xd018,
+ 0xd034, 0xd034,
+ 0xd050, 0xd050,
+ 0xd06c, 0xd06c,
+ 0xd088, 0xd088,
+ 0xd0a4, 0xd0a4,
+ 0xd0c0, 0xd0c0,
+ 0xd0dc, 0xd0dc,
+ 0xd0f8, 0xd0f8,
+ 0xd114, 0xd114,
+ 0xd130, 0xd130,
+ 0xd14c, 0xd14c,
+ 0xd168, 0xd168,
+ 0xd184, 0xd184,
+ 0xd1a0, 0xd1a0,
+ 0xd1bc, 0xd1bc,
+ 0xd1d8, 0xd1d8,
+ 0xd1f4, 0xd1f4,
+ 0xd210, 0xd210,
+ 0xd22c, 0xd22c,
+ 0xd248, 0xd248,
+ 0xd264, 0xd264,
+ 0xd280, 0xd280,
+ 0xd29c, 0xd29c,
+ 0xd2b8, 0xd2b8,
+ 0xd2d4, 0xd2d4,
+ 0xd2f0, 0xd2f0,
+ 0xd30c, 0xd30c,
+ 0xd328, 0xd328,
+ 0xd344, 0xd344,
+ 0xd360, 0xd360,
+ 0xd37c, 0xd37c,
+ 0xd398, 0xd398,
+ 0xd3b4, 0xd3b4,
+ 0xd3d0, 0xd3d0,
+ 0xd3ec, 0xd3ec,
+ 0xd408, 0xd408,
+ 0xd424, 0xd424,
+ 0xd440, 0xd440,
+ 0xd45c, 0xd45c,
+ 0xd478, 0xd478,
+ 0xd494, 0xd494,
+ 0xd4b0, 0xd4b0,
+ 0xd4cc, 0xd4cc,
+ 0xd4e8, 0xd4e8,
+ 0xd504, 0xd504,
+ 0xd520, 0xd520,
+ 0xd53c, 0xd53c,
+ 0xd558, 0xd558,
+ 0xd574, 0xd574,
+ 0xd590, 0xd590,
+ 0xd5ac, 0xd5ac,
+ 0xd5c8, 0xd5c8,
+ 0xd5e4, 0xd5e4,
+ 0xd600, 0xd600,
+ 0xd61c, 0xd61c,
+ 0xd638, 0xd638,
+ 0xd654, 0xd654,
+ 0xd670, 0xd670,
+ 0xd68c, 0xd68c,
+ 0xd6a8, 0xd6a8,
+ 0xd6c4, 0xd6c4,
+ 0xd6e0, 0xd6e0,
+ 0xd6fc, 0xd6fc,
+ 0xd718, 0xd718,
+ 0xd734, 0xd734,
+ 0xd750, 0xd750,
+ 0xd76c, 0xd76c,
+ 0xd788, 0xd788,
+}; /* CR_Grapheme_Cluster_Break_LV */
+
+/* 'Grapheme_Cluster_Break_LVT': Grapheme_Cluster_Break=LVT */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_LVT[] = {
+ 399,
+ 0xac01, 0xac1b,
+ 0xac1d, 0xac37,
+ 0xac39, 0xac53,
+ 0xac55, 0xac6f,
+ 0xac71, 0xac8b,
+ 0xac8d, 0xaca7,
+ 0xaca9, 0xacc3,
+ 0xacc5, 0xacdf,
+ 0xace1, 0xacfb,
+ 0xacfd, 0xad17,
+ 0xad19, 0xad33,
+ 0xad35, 0xad4f,
+ 0xad51, 0xad6b,
+ 0xad6d, 0xad87,
+ 0xad89, 0xada3,
+ 0xada5, 0xadbf,
+ 0xadc1, 0xaddb,
+ 0xaddd, 0xadf7,
+ 0xadf9, 0xae13,
+ 0xae15, 0xae2f,
+ 0xae31, 0xae4b,
+ 0xae4d, 0xae67,
+ 0xae69, 0xae83,
+ 0xae85, 0xae9f,
+ 0xaea1, 0xaebb,
+ 0xaebd, 0xaed7,
+ 0xaed9, 0xaef3,
+ 0xaef5, 0xaf0f,
+ 0xaf11, 0xaf2b,
+ 0xaf2d, 0xaf47,
+ 0xaf49, 0xaf63,
+ 0xaf65, 0xaf7f,
+ 0xaf81, 0xaf9b,
+ 0xaf9d, 0xafb7,
+ 0xafb9, 0xafd3,
+ 0xafd5, 0xafef,
+ 0xaff1, 0xb00b,
+ 0xb00d, 0xb027,
+ 0xb029, 0xb043,
+ 0xb045, 0xb05f,
+ 0xb061, 0xb07b,
+ 0xb07d, 0xb097,
+ 0xb099, 0xb0b3,
+ 0xb0b5, 0xb0cf,
+ 0xb0d1, 0xb0eb,
+ 0xb0ed, 0xb107,
+ 0xb109, 0xb123,
+ 0xb125, 0xb13f,
+ 0xb141, 0xb15b,
+ 0xb15d, 0xb177,
+ 0xb179, 0xb193,
+ 0xb195, 0xb1af,
+ 0xb1b1, 0xb1cb,
+ 0xb1cd, 0xb1e7,
+ 0xb1e9, 0xb203,
+ 0xb205, 0xb21f,
+ 0xb221, 0xb23b,
+ 0xb23d, 0xb257,
+ 0xb259, 0xb273,
+ 0xb275, 0xb28f,
+ 0xb291, 0xb2ab,
+ 0xb2ad, 0xb2c7,
+ 0xb2c9, 0xb2e3,
+ 0xb2e5, 0xb2ff,
+ 0xb301, 0xb31b,
+ 0xb31d, 0xb337,
+ 0xb339, 0xb353,
+ 0xb355, 0xb36f,
+ 0xb371, 0xb38b,
+ 0xb38d, 0xb3a7,
+ 0xb3a9, 0xb3c3,
+ 0xb3c5, 0xb3df,
+ 0xb3e1, 0xb3fb,
+ 0xb3fd, 0xb417,
+ 0xb419, 0xb433,
+ 0xb435, 0xb44f,
+ 0xb451, 0xb46b,
+ 0xb46d, 0xb487,
+ 0xb489, 0xb4a3,
+ 0xb4a5, 0xb4bf,
+ 0xb4c1, 0xb4db,
+ 0xb4dd, 0xb4f7,
+ 0xb4f9, 0xb513,
+ 0xb515, 0xb52f,
+ 0xb531, 0xb54b,
+ 0xb54d, 0xb567,
+ 0xb569, 0xb583,
+ 0xb585, 0xb59f,
+ 0xb5a1, 0xb5bb,
+ 0xb5bd, 0xb5d7,
+ 0xb5d9, 0xb5f3,
+ 0xb5f5, 0xb60f,
+ 0xb611, 0xb62b,
+ 0xb62d, 0xb647,
+ 0xb649, 0xb663,
+ 0xb665, 0xb67f,
+ 0xb681, 0xb69b,
+ 0xb69d, 0xb6b7,
+ 0xb6b9, 0xb6d3,
+ 0xb6d5, 0xb6ef,
+ 0xb6f1, 0xb70b,
+ 0xb70d, 0xb727,
+ 0xb729, 0xb743,
+ 0xb745, 0xb75f,
+ 0xb761, 0xb77b,
+ 0xb77d, 0xb797,
+ 0xb799, 0xb7b3,
+ 0xb7b5, 0xb7cf,
+ 0xb7d1, 0xb7eb,
+ 0xb7ed, 0xb807,
+ 0xb809, 0xb823,
+ 0xb825, 0xb83f,
+ 0xb841, 0xb85b,
+ 0xb85d, 0xb877,
+ 0xb879, 0xb893,
+ 0xb895, 0xb8af,
+ 0xb8b1, 0xb8cb,
+ 0xb8cd, 0xb8e7,
+ 0xb8e9, 0xb903,
+ 0xb905, 0xb91f,
+ 0xb921, 0xb93b,
+ 0xb93d, 0xb957,
+ 0xb959, 0xb973,
+ 0xb975, 0xb98f,
+ 0xb991, 0xb9ab,
+ 0xb9ad, 0xb9c7,
+ 0xb9c9, 0xb9e3,
+ 0xb9e5, 0xb9ff,
+ 0xba01, 0xba1b,
+ 0xba1d, 0xba37,
+ 0xba39, 0xba53,
+ 0xba55, 0xba6f,
+ 0xba71, 0xba8b,
+ 0xba8d, 0xbaa7,
+ 0xbaa9, 0xbac3,
+ 0xbac5, 0xbadf,
+ 0xbae1, 0xbafb,
+ 0xbafd, 0xbb17,
+ 0xbb19, 0xbb33,
+ 0xbb35, 0xbb4f,
+ 0xbb51, 0xbb6b,
+ 0xbb6d, 0xbb87,
+ 0xbb89, 0xbba3,
+ 0xbba5, 0xbbbf,
+ 0xbbc1, 0xbbdb,
+ 0xbbdd, 0xbbf7,
+ 0xbbf9, 0xbc13,
+ 0xbc15, 0xbc2f,
+ 0xbc31, 0xbc4b,
+ 0xbc4d, 0xbc67,
+ 0xbc69, 0xbc83,
+ 0xbc85, 0xbc9f,
+ 0xbca1, 0xbcbb,
+ 0xbcbd, 0xbcd7,
+ 0xbcd9, 0xbcf3,
+ 0xbcf5, 0xbd0f,
+ 0xbd11, 0xbd2b,
+ 0xbd2d, 0xbd47,
+ 0xbd49, 0xbd63,
+ 0xbd65, 0xbd7f,
+ 0xbd81, 0xbd9b,
+ 0xbd9d, 0xbdb7,
+ 0xbdb9, 0xbdd3,
+ 0xbdd5, 0xbdef,
+ 0xbdf1, 0xbe0b,
+ 0xbe0d, 0xbe27,
+ 0xbe29, 0xbe43,
+ 0xbe45, 0xbe5f,
+ 0xbe61, 0xbe7b,
+ 0xbe7d, 0xbe97,
+ 0xbe99, 0xbeb3,
+ 0xbeb5, 0xbecf,
+ 0xbed1, 0xbeeb,
+ 0xbeed, 0xbf07,
+ 0xbf09, 0xbf23,
+ 0xbf25, 0xbf3f,
+ 0xbf41, 0xbf5b,
+ 0xbf5d, 0xbf77,
+ 0xbf79, 0xbf93,
+ 0xbf95, 0xbfaf,
+ 0xbfb1, 0xbfcb,
+ 0xbfcd, 0xbfe7,
+ 0xbfe9, 0xc003,
+ 0xc005, 0xc01f,
+ 0xc021, 0xc03b,
+ 0xc03d, 0xc057,
+ 0xc059, 0xc073,
+ 0xc075, 0xc08f,
+ 0xc091, 0xc0ab,
+ 0xc0ad, 0xc0c7,
+ 0xc0c9, 0xc0e3,
+ 0xc0e5, 0xc0ff,
+ 0xc101, 0xc11b,
+ 0xc11d, 0xc137,
+ 0xc139, 0xc153,
+ 0xc155, 0xc16f,
+ 0xc171, 0xc18b,
+ 0xc18d, 0xc1a7,
+ 0xc1a9, 0xc1c3,
+ 0xc1c5, 0xc1df,
+ 0xc1e1, 0xc1fb,
+ 0xc1fd, 0xc217,
+ 0xc219, 0xc233,
+ 0xc235, 0xc24f,
+ 0xc251, 0xc26b,
+ 0xc26d, 0xc287,
+ 0xc289, 0xc2a3,
+ 0xc2a5, 0xc2bf,
+ 0xc2c1, 0xc2db,
+ 0xc2dd, 0xc2f7,
+ 0xc2f9, 0xc313,
+ 0xc315, 0xc32f,
+ 0xc331, 0xc34b,
+ 0xc34d, 0xc367,
+ 0xc369, 0xc383,
+ 0xc385, 0xc39f,
+ 0xc3a1, 0xc3bb,
+ 0xc3bd, 0xc3d7,
+ 0xc3d9, 0xc3f3,
+ 0xc3f5, 0xc40f,
+ 0xc411, 0xc42b,
+ 0xc42d, 0xc447,
+ 0xc449, 0xc463,
+ 0xc465, 0xc47f,
+ 0xc481, 0xc49b,
+ 0xc49d, 0xc4b7,
+ 0xc4b9, 0xc4d3,
+ 0xc4d5, 0xc4ef,
+ 0xc4f1, 0xc50b,
+ 0xc50d, 0xc527,
+ 0xc529, 0xc543,
+ 0xc545, 0xc55f,
+ 0xc561, 0xc57b,
+ 0xc57d, 0xc597,
+ 0xc599, 0xc5b3,
+ 0xc5b5, 0xc5cf,
+ 0xc5d1, 0xc5eb,
+ 0xc5ed, 0xc607,
+ 0xc609, 0xc623,
+ 0xc625, 0xc63f,
+ 0xc641, 0xc65b,
+ 0xc65d, 0xc677,
+ 0xc679, 0xc693,
+ 0xc695, 0xc6af,
+ 0xc6b1, 0xc6cb,
+ 0xc6cd, 0xc6e7,
+ 0xc6e9, 0xc703,
+ 0xc705, 0xc71f,
+ 0xc721, 0xc73b,
+ 0xc73d, 0xc757,
+ 0xc759, 0xc773,
+ 0xc775, 0xc78f,
+ 0xc791, 0xc7ab,
+ 0xc7ad, 0xc7c7,
+ 0xc7c9, 0xc7e3,
+ 0xc7e5, 0xc7ff,
+ 0xc801, 0xc81b,
+ 0xc81d, 0xc837,
+ 0xc839, 0xc853,
+ 0xc855, 0xc86f,
+ 0xc871, 0xc88b,
+ 0xc88d, 0xc8a7,
+ 0xc8a9, 0xc8c3,
+ 0xc8c5, 0xc8df,
+ 0xc8e1, 0xc8fb,
+ 0xc8fd, 0xc917,
+ 0xc919, 0xc933,
+ 0xc935, 0xc94f,
+ 0xc951, 0xc96b,
+ 0xc96d, 0xc987,
+ 0xc989, 0xc9a3,
+ 0xc9a5, 0xc9bf,
+ 0xc9c1, 0xc9db,
+ 0xc9dd, 0xc9f7,
+ 0xc9f9, 0xca13,
+ 0xca15, 0xca2f,
+ 0xca31, 0xca4b,
+ 0xca4d, 0xca67,
+ 0xca69, 0xca83,
+ 0xca85, 0xca9f,
+ 0xcaa1, 0xcabb,
+ 0xcabd, 0xcad7,
+ 0xcad9, 0xcaf3,
+ 0xcaf5, 0xcb0f,
+ 0xcb11, 0xcb2b,
+ 0xcb2d, 0xcb47,
+ 0xcb49, 0xcb63,
+ 0xcb65, 0xcb7f,
+ 0xcb81, 0xcb9b,
+ 0xcb9d, 0xcbb7,
+ 0xcbb9, 0xcbd3,
+ 0xcbd5, 0xcbef,
+ 0xcbf1, 0xcc0b,
+ 0xcc0d, 0xcc27,
+ 0xcc29, 0xcc43,
+ 0xcc45, 0xcc5f,
+ 0xcc61, 0xcc7b,
+ 0xcc7d, 0xcc97,
+ 0xcc99, 0xccb3,
+ 0xccb5, 0xcccf,
+ 0xccd1, 0xcceb,
+ 0xcced, 0xcd07,
+ 0xcd09, 0xcd23,
+ 0xcd25, 0xcd3f,
+ 0xcd41, 0xcd5b,
+ 0xcd5d, 0xcd77,
+ 0xcd79, 0xcd93,
+ 0xcd95, 0xcdaf,
+ 0xcdb1, 0xcdcb,
+ 0xcdcd, 0xcde7,
+ 0xcde9, 0xce03,
+ 0xce05, 0xce1f,
+ 0xce21, 0xce3b,
+ 0xce3d, 0xce57,
+ 0xce59, 0xce73,
+ 0xce75, 0xce8f,
+ 0xce91, 0xceab,
+ 0xcead, 0xcec7,
+ 0xcec9, 0xcee3,
+ 0xcee5, 0xceff,
+ 0xcf01, 0xcf1b,
+ 0xcf1d, 0xcf37,
+ 0xcf39, 0xcf53,
+ 0xcf55, 0xcf6f,
+ 0xcf71, 0xcf8b,
+ 0xcf8d, 0xcfa7,
+ 0xcfa9, 0xcfc3,
+ 0xcfc5, 0xcfdf,
+ 0xcfe1, 0xcffb,
+ 0xcffd, 0xd017,
+ 0xd019, 0xd033,
+ 0xd035, 0xd04f,
+ 0xd051, 0xd06b,
+ 0xd06d, 0xd087,
+ 0xd089, 0xd0a3,
+ 0xd0a5, 0xd0bf,
+ 0xd0c1, 0xd0db,
+ 0xd0dd, 0xd0f7,
+ 0xd0f9, 0xd113,
+ 0xd115, 0xd12f,
+ 0xd131, 0xd14b,
+ 0xd14d, 0xd167,
+ 0xd169, 0xd183,
+ 0xd185, 0xd19f,
+ 0xd1a1, 0xd1bb,
+ 0xd1bd, 0xd1d7,
+ 0xd1d9, 0xd1f3,
+ 0xd1f5, 0xd20f,
+ 0xd211, 0xd22b,
+ 0xd22d, 0xd247,
+ 0xd249, 0xd263,
+ 0xd265, 0xd27f,
+ 0xd281, 0xd29b,
+ 0xd29d, 0xd2b7,
+ 0xd2b9, 0xd2d3,
+ 0xd2d5, 0xd2ef,
+ 0xd2f1, 0xd30b,
+ 0xd30d, 0xd327,
+ 0xd329, 0xd343,
+ 0xd345, 0xd35f,
+ 0xd361, 0xd37b,
+ 0xd37d, 0xd397,
+ 0xd399, 0xd3b3,
+ 0xd3b5, 0xd3cf,
+ 0xd3d1, 0xd3eb,
+ 0xd3ed, 0xd407,
+ 0xd409, 0xd423,
+ 0xd425, 0xd43f,
+ 0xd441, 0xd45b,
+ 0xd45d, 0xd477,
+ 0xd479, 0xd493,
+ 0xd495, 0xd4af,
+ 0xd4b1, 0xd4cb,
+ 0xd4cd, 0xd4e7,
+ 0xd4e9, 0xd503,
+ 0xd505, 0xd51f,
+ 0xd521, 0xd53b,
+ 0xd53d, 0xd557,
+ 0xd559, 0xd573,
+ 0xd575, 0xd58f,
+ 0xd591, 0xd5ab,
+ 0xd5ad, 0xd5c7,
+ 0xd5c9, 0xd5e3,
+ 0xd5e5, 0xd5ff,
+ 0xd601, 0xd61b,
+ 0xd61d, 0xd637,
+ 0xd639, 0xd653,
+ 0xd655, 0xd66f,
+ 0xd671, 0xd68b,
+ 0xd68d, 0xd6a7,
+ 0xd6a9, 0xd6c3,
+ 0xd6c5, 0xd6df,
+ 0xd6e1, 0xd6fb,
+ 0xd6fd, 0xd717,
+ 0xd719, 0xd733,
+ 0xd735, 0xd74f,
+ 0xd751, 0xd76b,
+ 0xd76d, 0xd787,
+ 0xd789, 0xd7a3,
+}; /* CR_Grapheme_Cluster_Break_LVT */
+
+/* 'Grapheme_Cluster_Break_ZWJ': Grapheme_Cluster_Break=ZWJ */
+static const OnigCodePoint CR_Grapheme_Cluster_Break_ZWJ[] = {
+ 1,
+ 0x200d, 0x200d,
+}; /* CR_Grapheme_Cluster_Break_ZWJ */
+
+/* 'In_Basic_Latin': Block */
+#define CR_In_Basic_Latin CR_ASCII
+
+/* 'In_Latin_1_Supplement': Block */
+static const OnigCodePoint CR_In_Latin_1_Supplement[] = {
+ 1,
+ 0x0080, 0x00ff,
+}; /* CR_In_Latin_1_Supplement */
+
+/* 'In_Latin_Extended_A': Block */
+static const OnigCodePoint CR_In_Latin_Extended_A[] = {
+ 1,
+ 0x0100, 0x017f,
+}; /* CR_In_Latin_Extended_A */
+
+/* 'In_Latin_Extended_B': Block */
+static const OnigCodePoint CR_In_Latin_Extended_B[] = {
+ 1,
+ 0x0180, 0x024f,
+}; /* CR_In_Latin_Extended_B */
+
+/* 'In_IPA_Extensions': Block */
+static const OnigCodePoint CR_In_IPA_Extensions[] = {
+ 1,
+ 0x0250, 0x02af,
+}; /* CR_In_IPA_Extensions */
+
+/* 'In_Spacing_Modifier_Letters': Block */
+static const OnigCodePoint CR_In_Spacing_Modifier_Letters[] = {
+ 1,
+ 0x02b0, 0x02ff,
+}; /* CR_In_Spacing_Modifier_Letters */
+
+/* 'In_Combining_Diacritical_Marks': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks[] = {
+ 1,
+ 0x0300, 0x036f,
+}; /* CR_In_Combining_Diacritical_Marks */
+
+/* 'In_Greek_and_Coptic': Block */
+static const OnigCodePoint CR_In_Greek_and_Coptic[] = {
+ 1,
+ 0x0370, 0x03ff,
+}; /* CR_In_Greek_and_Coptic */
+
+/* 'In_Cyrillic': Block */
+static const OnigCodePoint CR_In_Cyrillic[] = {
+ 1,
+ 0x0400, 0x04ff,
+}; /* CR_In_Cyrillic */
+
+/* 'In_Cyrillic_Supplement': Block */
+static const OnigCodePoint CR_In_Cyrillic_Supplement[] = {
+ 1,
+ 0x0500, 0x052f,
+}; /* CR_In_Cyrillic_Supplement */
+
+/* 'In_Armenian': Block */
+static const OnigCodePoint CR_In_Armenian[] = {
+ 1,
+ 0x0530, 0x058f,
+}; /* CR_In_Armenian */
+
+/* 'In_Hebrew': Block */
+static const OnigCodePoint CR_In_Hebrew[] = {
+ 1,
+ 0x0590, 0x05ff,
+}; /* CR_In_Hebrew */
+
+/* 'In_Arabic': Block */
+static const OnigCodePoint CR_In_Arabic[] = {
+ 1,
+ 0x0600, 0x06ff,
+}; /* CR_In_Arabic */
+
+/* 'In_Syriac': Block */
+static const OnigCodePoint CR_In_Syriac[] = {
+ 1,
+ 0x0700, 0x074f,
+}; /* CR_In_Syriac */
+
+/* 'In_Arabic_Supplement': Block */
+static const OnigCodePoint CR_In_Arabic_Supplement[] = {
+ 1,
+ 0x0750, 0x077f,
+}; /* CR_In_Arabic_Supplement */
+
+/* 'In_Thaana': Block */
+static const OnigCodePoint CR_In_Thaana[] = {
+ 1,
+ 0x0780, 0x07bf,
+}; /* CR_In_Thaana */
+
+/* 'In_NKo': Block */
+static const OnigCodePoint CR_In_NKo[] = {
+ 1,
+ 0x07c0, 0x07ff,
+}; /* CR_In_NKo */
+
+/* 'In_Samaritan': Block */
+static const OnigCodePoint CR_In_Samaritan[] = {
+ 1,
+ 0x0800, 0x083f,
+}; /* CR_In_Samaritan */
+
+/* 'In_Mandaic': Block */
+static const OnigCodePoint CR_In_Mandaic[] = {
+ 1,
+ 0x0840, 0x085f,
+}; /* CR_In_Mandaic */
+
+/* 'In_Syriac_Supplement': Block */
+static const OnigCodePoint CR_In_Syriac_Supplement[] = {
+ 1,
+ 0x0860, 0x086f,
+}; /* CR_In_Syriac_Supplement */
+
+/* 'In_Arabic_Extended_B': Block */
+static const OnigCodePoint CR_In_Arabic_Extended_B[] = {
+ 1,
+ 0x0870, 0x089f,
+}; /* CR_In_Arabic_Extended_B */
+
+/* 'In_Arabic_Extended_A': Block */
+static const OnigCodePoint CR_In_Arabic_Extended_A[] = {
+ 1,
+ 0x08a0, 0x08ff,
+}; /* CR_In_Arabic_Extended_A */
+
+/* 'In_Devanagari': Block */
+static const OnigCodePoint CR_In_Devanagari[] = {
+ 1,
+ 0x0900, 0x097f,
+}; /* CR_In_Devanagari */
+
+/* 'In_Bengali': Block */
+static const OnigCodePoint CR_In_Bengali[] = {
+ 1,
+ 0x0980, 0x09ff,
+}; /* CR_In_Bengali */
+
+/* 'In_Gurmukhi': Block */
+static const OnigCodePoint CR_In_Gurmukhi[] = {
+ 1,
+ 0x0a00, 0x0a7f,
+}; /* CR_In_Gurmukhi */
+
+/* 'In_Gujarati': Block */
+static const OnigCodePoint CR_In_Gujarati[] = {
+ 1,
+ 0x0a80, 0x0aff,
+}; /* CR_In_Gujarati */
+
+/* 'In_Oriya': Block */
+static const OnigCodePoint CR_In_Oriya[] = {
+ 1,
+ 0x0b00, 0x0b7f,
+}; /* CR_In_Oriya */
+
+/* 'In_Tamil': Block */
+static const OnigCodePoint CR_In_Tamil[] = {
+ 1,
+ 0x0b80, 0x0bff,
+}; /* CR_In_Tamil */
+
+/* 'In_Telugu': Block */
+static const OnigCodePoint CR_In_Telugu[] = {
+ 1,
+ 0x0c00, 0x0c7f,
+}; /* CR_In_Telugu */
+
+/* 'In_Kannada': Block */
+static const OnigCodePoint CR_In_Kannada[] = {
+ 1,
+ 0x0c80, 0x0cff,
+}; /* CR_In_Kannada */
+
+/* 'In_Malayalam': Block */
+static const OnigCodePoint CR_In_Malayalam[] = {
+ 1,
+ 0x0d00, 0x0d7f,
+}; /* CR_In_Malayalam */
+
+/* 'In_Sinhala': Block */
+static const OnigCodePoint CR_In_Sinhala[] = {
+ 1,
+ 0x0d80, 0x0dff,
+}; /* CR_In_Sinhala */
+
+/* 'In_Thai': Block */
+static const OnigCodePoint CR_In_Thai[] = {
+ 1,
+ 0x0e00, 0x0e7f,
+}; /* CR_In_Thai */
+
+/* 'In_Lao': Block */
+static const OnigCodePoint CR_In_Lao[] = {
+ 1,
+ 0x0e80, 0x0eff,
+}; /* CR_In_Lao */
+
+/* 'In_Tibetan': Block */
+static const OnigCodePoint CR_In_Tibetan[] = {
+ 1,
+ 0x0f00, 0x0fff,
+}; /* CR_In_Tibetan */
+
+/* 'In_Myanmar': Block */
+static const OnigCodePoint CR_In_Myanmar[] = {
+ 1,
+ 0x1000, 0x109f,
+}; /* CR_In_Myanmar */
+
+/* 'In_Georgian': Block */
+static const OnigCodePoint CR_In_Georgian[] = {
+ 1,
+ 0x10a0, 0x10ff,
+}; /* CR_In_Georgian */
+
+/* 'In_Hangul_Jamo': Block */
+static const OnigCodePoint CR_In_Hangul_Jamo[] = {
+ 1,
+ 0x1100, 0x11ff,
+}; /* CR_In_Hangul_Jamo */
+
+/* 'In_Ethiopic': Block */
+static const OnigCodePoint CR_In_Ethiopic[] = {
+ 1,
+ 0x1200, 0x137f,
+}; /* CR_In_Ethiopic */
+
+/* 'In_Ethiopic_Supplement': Block */
+static const OnigCodePoint CR_In_Ethiopic_Supplement[] = {
+ 1,
+ 0x1380, 0x139f,
+}; /* CR_In_Ethiopic_Supplement */
+
+/* 'In_Cherokee': Block */
+static const OnigCodePoint CR_In_Cherokee[] = {
+ 1,
+ 0x13a0, 0x13ff,
+}; /* CR_In_Cherokee */
+
+/* 'In_Unified_Canadian_Aboriginal_Syllabics': Block */
+static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics[] = {
+ 1,
+ 0x1400, 0x167f,
+}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics */
+
+/* 'In_Ogham': Block */
+static const OnigCodePoint CR_In_Ogham[] = {
+ 1,
+ 0x1680, 0x169f,
+}; /* CR_In_Ogham */
+
+/* 'In_Runic': Block */
+static const OnigCodePoint CR_In_Runic[] = {
+ 1,
+ 0x16a0, 0x16ff,
+}; /* CR_In_Runic */
+
+/* 'In_Tagalog': Block */
+static const OnigCodePoint CR_In_Tagalog[] = {
+ 1,
+ 0x1700, 0x171f,
+}; /* CR_In_Tagalog */
+
+/* 'In_Hanunoo': Block */
+static const OnigCodePoint CR_In_Hanunoo[] = {
+ 1,
+ 0x1720, 0x173f,
+}; /* CR_In_Hanunoo */
+
+/* 'In_Buhid': Block */
+static const OnigCodePoint CR_In_Buhid[] = {
+ 1,
+ 0x1740, 0x175f,
+}; /* CR_In_Buhid */
+
+/* 'In_Tagbanwa': Block */
+static const OnigCodePoint CR_In_Tagbanwa[] = {
+ 1,
+ 0x1760, 0x177f,
+}; /* CR_In_Tagbanwa */
+
+/* 'In_Khmer': Block */
+static const OnigCodePoint CR_In_Khmer[] = {
+ 1,
+ 0x1780, 0x17ff,
+}; /* CR_In_Khmer */
+
+/* 'In_Mongolian': Block */
+static const OnigCodePoint CR_In_Mongolian[] = {
+ 1,
+ 0x1800, 0x18af,
+}; /* CR_In_Mongolian */
+
+/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended': Block */
+static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended[] = {
+ 1,
+ 0x18b0, 0x18ff,
+}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended */
+
+/* 'In_Limbu': Block */
+static const OnigCodePoint CR_In_Limbu[] = {
+ 1,
+ 0x1900, 0x194f,
+}; /* CR_In_Limbu */
+
+/* 'In_Tai_Le': Block */
+static const OnigCodePoint CR_In_Tai_Le[] = {
+ 1,
+ 0x1950, 0x197f,
+}; /* CR_In_Tai_Le */
+
+/* 'In_New_Tai_Lue': Block */
+static const OnigCodePoint CR_In_New_Tai_Lue[] = {
+ 1,
+ 0x1980, 0x19df,
+}; /* CR_In_New_Tai_Lue */
+
+/* 'In_Khmer_Symbols': Block */
+static const OnigCodePoint CR_In_Khmer_Symbols[] = {
+ 1,
+ 0x19e0, 0x19ff,
+}; /* CR_In_Khmer_Symbols */
+
+/* 'In_Buginese': Block */
+static const OnigCodePoint CR_In_Buginese[] = {
+ 1,
+ 0x1a00, 0x1a1f,
+}; /* CR_In_Buginese */
+
+/* 'In_Tai_Tham': Block */
+static const OnigCodePoint CR_In_Tai_Tham[] = {
+ 1,
+ 0x1a20, 0x1aaf,
+}; /* CR_In_Tai_Tham */
+
+/* 'In_Combining_Diacritical_Marks_Extended': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Extended[] = {
+ 1,
+ 0x1ab0, 0x1aff,
+}; /* CR_In_Combining_Diacritical_Marks_Extended */
+
+/* 'In_Balinese': Block */
+static const OnigCodePoint CR_In_Balinese[] = {
+ 1,
+ 0x1b00, 0x1b7f,
+}; /* CR_In_Balinese */
+
+/* 'In_Sundanese': Block */
+static const OnigCodePoint CR_In_Sundanese[] = {
+ 1,
+ 0x1b80, 0x1bbf,
+}; /* CR_In_Sundanese */
+
+/* 'In_Batak': Block */
+static const OnigCodePoint CR_In_Batak[] = {
+ 1,
+ 0x1bc0, 0x1bff,
+}; /* CR_In_Batak */
+
+/* 'In_Lepcha': Block */
+static const OnigCodePoint CR_In_Lepcha[] = {
+ 1,
+ 0x1c00, 0x1c4f,
+}; /* CR_In_Lepcha */
+
+/* 'In_Ol_Chiki': Block */
+#define CR_In_Ol_Chiki CR_Ol_Chiki
+
+/* 'In_Cyrillic_Extended_C': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_C[] = {
+ 1,
+ 0x1c80, 0x1c8f,
+}; /* CR_In_Cyrillic_Extended_C */
+
+/* 'In_Georgian_Extended': Block */
+static const OnigCodePoint CR_In_Georgian_Extended[] = {
+ 1,
+ 0x1c90, 0x1cbf,
+}; /* CR_In_Georgian_Extended */
+
+/* 'In_Sundanese_Supplement': Block */
+static const OnigCodePoint CR_In_Sundanese_Supplement[] = {
+ 1,
+ 0x1cc0, 0x1ccf,
+}; /* CR_In_Sundanese_Supplement */
+
+/* 'In_Vedic_Extensions': Block */
+static const OnigCodePoint CR_In_Vedic_Extensions[] = {
+ 1,
+ 0x1cd0, 0x1cff,
+}; /* CR_In_Vedic_Extensions */
+
+/* 'In_Phonetic_Extensions': Block */
+static const OnigCodePoint CR_In_Phonetic_Extensions[] = {
+ 1,
+ 0x1d00, 0x1d7f,
+}; /* CR_In_Phonetic_Extensions */
+
+/* 'In_Phonetic_Extensions_Supplement': Block */
+static const OnigCodePoint CR_In_Phonetic_Extensions_Supplement[] = {
+ 1,
+ 0x1d80, 0x1dbf,
+}; /* CR_In_Phonetic_Extensions_Supplement */
+
+/* 'In_Combining_Diacritical_Marks_Supplement': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks_Supplement[] = {
+ 1,
+ 0x1dc0, 0x1dff,
+}; /* CR_In_Combining_Diacritical_Marks_Supplement */
+
+/* 'In_Latin_Extended_Additional': Block */
+static const OnigCodePoint CR_In_Latin_Extended_Additional[] = {
+ 1,
+ 0x1e00, 0x1eff,
+}; /* CR_In_Latin_Extended_Additional */
+
+/* 'In_Greek_Extended': Block */
+static const OnigCodePoint CR_In_Greek_Extended[] = {
+ 1,
+ 0x1f00, 0x1fff,
+}; /* CR_In_Greek_Extended */
+
+/* 'In_General_Punctuation': Block */
+static const OnigCodePoint CR_In_General_Punctuation[] = {
+ 1,
+ 0x2000, 0x206f,
+}; /* CR_In_General_Punctuation */
+
+/* 'In_Superscripts_and_Subscripts': Block */
+static const OnigCodePoint CR_In_Superscripts_and_Subscripts[] = {
+ 1,
+ 0x2070, 0x209f,
+}; /* CR_In_Superscripts_and_Subscripts */
+
+/* 'In_Currency_Symbols': Block */
+static const OnigCodePoint CR_In_Currency_Symbols[] = {
+ 1,
+ 0x20a0, 0x20cf,
+}; /* CR_In_Currency_Symbols */
+
+/* 'In_Combining_Diacritical_Marks_for_Symbols': Block */
+static const OnigCodePoint CR_In_Combining_Diacritical_Marks_for_Symbols[] = {
+ 1,
+ 0x20d0, 0x20ff,
+}; /* CR_In_Combining_Diacritical_Marks_for_Symbols */
+
+/* 'In_Letterlike_Symbols': Block */
+static const OnigCodePoint CR_In_Letterlike_Symbols[] = {
+ 1,
+ 0x2100, 0x214f,
+}; /* CR_In_Letterlike_Symbols */
+
+/* 'In_Number_Forms': Block */
+static const OnigCodePoint CR_In_Number_Forms[] = {
+ 1,
+ 0x2150, 0x218f,
+}; /* CR_In_Number_Forms */
+
+/* 'In_Arrows': Block */
+static const OnigCodePoint CR_In_Arrows[] = {
+ 1,
+ 0x2190, 0x21ff,
+}; /* CR_In_Arrows */
+
+/* 'In_Mathematical_Operators': Block */
+static const OnigCodePoint CR_In_Mathematical_Operators[] = {
+ 1,
+ 0x2200, 0x22ff,
+}; /* CR_In_Mathematical_Operators */
+
+/* 'In_Miscellaneous_Technical': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Technical[] = {
+ 1,
+ 0x2300, 0x23ff,
+}; /* CR_In_Miscellaneous_Technical */
+
+/* 'In_Control_Pictures': Block */
+static const OnigCodePoint CR_In_Control_Pictures[] = {
+ 1,
+ 0x2400, 0x243f,
+}; /* CR_In_Control_Pictures */
+
+/* 'In_Optical_Character_Recognition': Block */
+static const OnigCodePoint CR_In_Optical_Character_Recognition[] = {
+ 1,
+ 0x2440, 0x245f,
+}; /* CR_In_Optical_Character_Recognition */
+
+/* 'In_Enclosed_Alphanumerics': Block */
+static const OnigCodePoint CR_In_Enclosed_Alphanumerics[] = {
+ 1,
+ 0x2460, 0x24ff,
+}; /* CR_In_Enclosed_Alphanumerics */
+
+/* 'In_Box_Drawing': Block */
+static const OnigCodePoint CR_In_Box_Drawing[] = {
+ 1,
+ 0x2500, 0x257f,
+}; /* CR_In_Box_Drawing */
+
+/* 'In_Block_Elements': Block */
+static const OnigCodePoint CR_In_Block_Elements[] = {
+ 1,
+ 0x2580, 0x259f,
+}; /* CR_In_Block_Elements */
+
+/* 'In_Geometric_Shapes': Block */
+static const OnigCodePoint CR_In_Geometric_Shapes[] = {
+ 1,
+ 0x25a0, 0x25ff,
+}; /* CR_In_Geometric_Shapes */
+
+/* 'In_Miscellaneous_Symbols': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols[] = {
+ 1,
+ 0x2600, 0x26ff,
+}; /* CR_In_Miscellaneous_Symbols */
+
+/* 'In_Dingbats': Block */
+static const OnigCodePoint CR_In_Dingbats[] = {
+ 1,
+ 0x2700, 0x27bf,
+}; /* CR_In_Dingbats */
+
+/* 'In_Miscellaneous_Mathematical_Symbols_A': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_A[] = {
+ 1,
+ 0x27c0, 0x27ef,
+}; /* CR_In_Miscellaneous_Mathematical_Symbols_A */
+
+/* 'In_Supplemental_Arrows_A': Block */
+static const OnigCodePoint CR_In_Supplemental_Arrows_A[] = {
+ 1,
+ 0x27f0, 0x27ff,
+}; /* CR_In_Supplemental_Arrows_A */
+
+/* 'In_Braille_Patterns': Block */
+#define CR_In_Braille_Patterns CR_Braille
+
+/* 'In_Supplemental_Arrows_B': Block */
+static const OnigCodePoint CR_In_Supplemental_Arrows_B[] = {
+ 1,
+ 0x2900, 0x297f,
+}; /* CR_In_Supplemental_Arrows_B */
+
+/* 'In_Miscellaneous_Mathematical_Symbols_B': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Mathematical_Symbols_B[] = {
+ 1,
+ 0x2980, 0x29ff,
+}; /* CR_In_Miscellaneous_Mathematical_Symbols_B */
+
+/* 'In_Supplemental_Mathematical_Operators': Block */
+static const OnigCodePoint CR_In_Supplemental_Mathematical_Operators[] = {
+ 1,
+ 0x2a00, 0x2aff,
+}; /* CR_In_Supplemental_Mathematical_Operators */
+
+/* 'In_Miscellaneous_Symbols_and_Arrows': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Arrows[] = {
+ 1,
+ 0x2b00, 0x2bff,
+}; /* CR_In_Miscellaneous_Symbols_and_Arrows */
+
+/* 'In_Glagolitic': Block */
+static const OnigCodePoint CR_In_Glagolitic[] = {
+ 1,
+ 0x2c00, 0x2c5f,
+}; /* CR_In_Glagolitic */
+
+/* 'In_Latin_Extended_C': Block */
+static const OnigCodePoint CR_In_Latin_Extended_C[] = {
+ 1,
+ 0x2c60, 0x2c7f,
+}; /* CR_In_Latin_Extended_C */
+
+/* 'In_Coptic': Block */
+static const OnigCodePoint CR_In_Coptic[] = {
+ 1,
+ 0x2c80, 0x2cff,
+}; /* CR_In_Coptic */
+
+/* 'In_Georgian_Supplement': Block */
+static const OnigCodePoint CR_In_Georgian_Supplement[] = {
+ 1,
+ 0x2d00, 0x2d2f,
+}; /* CR_In_Georgian_Supplement */
+
+/* 'In_Tifinagh': Block */
+static const OnigCodePoint CR_In_Tifinagh[] = {
+ 1,
+ 0x2d30, 0x2d7f,
+}; /* CR_In_Tifinagh */
+
+/* 'In_Ethiopic_Extended': Block */
+static const OnigCodePoint CR_In_Ethiopic_Extended[] = {
+ 1,
+ 0x2d80, 0x2ddf,
+}; /* CR_In_Ethiopic_Extended */
+
+/* 'In_Cyrillic_Extended_A': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_A[] = {
+ 1,
+ 0x2de0, 0x2dff,
+}; /* CR_In_Cyrillic_Extended_A */
+
+/* 'In_Supplemental_Punctuation': Block */
+static const OnigCodePoint CR_In_Supplemental_Punctuation[] = {
+ 1,
+ 0x2e00, 0x2e7f,
+}; /* CR_In_Supplemental_Punctuation */
+
+/* 'In_CJK_Radicals_Supplement': Block */
+static const OnigCodePoint CR_In_CJK_Radicals_Supplement[] = {
+ 1,
+ 0x2e80, 0x2eff,
+}; /* CR_In_CJK_Radicals_Supplement */
+
+/* 'In_Kangxi_Radicals': Block */
+static const OnigCodePoint CR_In_Kangxi_Radicals[] = {
+ 1,
+ 0x2f00, 0x2fdf,
+}; /* CR_In_Kangxi_Radicals */
+
+/* 'In_Ideographic_Description_Characters': Block */
+static const OnigCodePoint CR_In_Ideographic_Description_Characters[] = {
+ 1,
+ 0x2ff0, 0x2fff,
+}; /* CR_In_Ideographic_Description_Characters */
+
+/* 'In_CJK_Symbols_and_Punctuation': Block */
+static const OnigCodePoint CR_In_CJK_Symbols_and_Punctuation[] = {
+ 1,
+ 0x3000, 0x303f,
+}; /* CR_In_CJK_Symbols_and_Punctuation */
+
+/* 'In_Hiragana': Block */
+static const OnigCodePoint CR_In_Hiragana[] = {
+ 1,
+ 0x3040, 0x309f,
+}; /* CR_In_Hiragana */
+
+/* 'In_Katakana': Block */
+static const OnigCodePoint CR_In_Katakana[] = {
+ 1,
+ 0x30a0, 0x30ff,
+}; /* CR_In_Katakana */
+
+/* 'In_Bopomofo': Block */
+static const OnigCodePoint CR_In_Bopomofo[] = {
+ 1,
+ 0x3100, 0x312f,
+}; /* CR_In_Bopomofo */
+
+/* 'In_Hangul_Compatibility_Jamo': Block */
+static const OnigCodePoint CR_In_Hangul_Compatibility_Jamo[] = {
+ 1,
+ 0x3130, 0x318f,
+}; /* CR_In_Hangul_Compatibility_Jamo */
+
+/* 'In_Kanbun': Block */
+static const OnigCodePoint CR_In_Kanbun[] = {
+ 1,
+ 0x3190, 0x319f,
+}; /* CR_In_Kanbun */
+
+/* 'In_Bopomofo_Extended': Block */
+static const OnigCodePoint CR_In_Bopomofo_Extended[] = {
+ 1,
+ 0x31a0, 0x31bf,
+}; /* CR_In_Bopomofo_Extended */
+
+/* 'In_CJK_Strokes': Block */
+static const OnigCodePoint CR_In_CJK_Strokes[] = {
+ 1,
+ 0x31c0, 0x31ef,
+}; /* CR_In_CJK_Strokes */
+
+/* 'In_Katakana_Phonetic_Extensions': Block */
+static const OnigCodePoint CR_In_Katakana_Phonetic_Extensions[] = {
+ 1,
+ 0x31f0, 0x31ff,
+}; /* CR_In_Katakana_Phonetic_Extensions */
+
+/* 'In_Enclosed_CJK_Letters_and_Months': Block */
+static const OnigCodePoint CR_In_Enclosed_CJK_Letters_and_Months[] = {
+ 1,
+ 0x3200, 0x32ff,
+}; /* CR_In_Enclosed_CJK_Letters_and_Months */
+
+/* 'In_CJK_Compatibility': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility[] = {
+ 1,
+ 0x3300, 0x33ff,
+}; /* CR_In_CJK_Compatibility */
+
+/* 'In_CJK_Unified_Ideographs_Extension_A': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_A[] = {
+ 1,
+ 0x3400, 0x4dbf,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_A */
+
+/* 'In_Yijing_Hexagram_Symbols': Block */
+static const OnigCodePoint CR_In_Yijing_Hexagram_Symbols[] = {
+ 1,
+ 0x4dc0, 0x4dff,
+}; /* CR_In_Yijing_Hexagram_Symbols */
+
+/* 'In_CJK_Unified_Ideographs': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs[] = {
+ 1,
+ 0x4e00, 0x9fff,
+}; /* CR_In_CJK_Unified_Ideographs */
+
+/* 'In_Yi_Syllables': Block */
+static const OnigCodePoint CR_In_Yi_Syllables[] = {
+ 1,
+ 0xa000, 0xa48f,
+}; /* CR_In_Yi_Syllables */
+
+/* 'In_Yi_Radicals': Block */
+static const OnigCodePoint CR_In_Yi_Radicals[] = {
+ 1,
+ 0xa490, 0xa4cf,
+}; /* CR_In_Yi_Radicals */
+
+/* 'In_Lisu': Block */
+static const OnigCodePoint CR_In_Lisu[] = {
+ 1,
+ 0xa4d0, 0xa4ff,
+}; /* CR_In_Lisu */
+
+/* 'In_Vai': Block */
+static const OnigCodePoint CR_In_Vai[] = {
+ 1,
+ 0xa500, 0xa63f,
+}; /* CR_In_Vai */
+
+/* 'In_Cyrillic_Extended_B': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_B[] = {
+ 1,
+ 0xa640, 0xa69f,
+}; /* CR_In_Cyrillic_Extended_B */
+
+/* 'In_Bamum': Block */
+static const OnigCodePoint CR_In_Bamum[] = {
+ 1,
+ 0xa6a0, 0xa6ff,
+}; /* CR_In_Bamum */
+
+/* 'In_Modifier_Tone_Letters': Block */
+static const OnigCodePoint CR_In_Modifier_Tone_Letters[] = {
+ 1,
+ 0xa700, 0xa71f,
+}; /* CR_In_Modifier_Tone_Letters */
+
+/* 'In_Latin_Extended_D': Block */
+static const OnigCodePoint CR_In_Latin_Extended_D[] = {
+ 1,
+ 0xa720, 0xa7ff,
+}; /* CR_In_Latin_Extended_D */
+
+/* 'In_Syloti_Nagri': Block */
+static const OnigCodePoint CR_In_Syloti_Nagri[] = {
+ 1,
+ 0xa800, 0xa82f,
+}; /* CR_In_Syloti_Nagri */
+
+/* 'In_Common_Indic_Number_Forms': Block */
+static const OnigCodePoint CR_In_Common_Indic_Number_Forms[] = {
+ 1,
+ 0xa830, 0xa83f,
+}; /* CR_In_Common_Indic_Number_Forms */
+
+/* 'In_Phags_pa': Block */
+static const OnigCodePoint CR_In_Phags_pa[] = {
+ 1,
+ 0xa840, 0xa87f,
+}; /* CR_In_Phags_pa */
+
+/* 'In_Saurashtra': Block */
+static const OnigCodePoint CR_In_Saurashtra[] = {
+ 1,
+ 0xa880, 0xa8df,
+}; /* CR_In_Saurashtra */
+
+/* 'In_Devanagari_Extended': Block */
+static const OnigCodePoint CR_In_Devanagari_Extended[] = {
+ 1,
+ 0xa8e0, 0xa8ff,
+}; /* CR_In_Devanagari_Extended */
+
+/* 'In_Kayah_Li': Block */
+static const OnigCodePoint CR_In_Kayah_Li[] = {
+ 1,
+ 0xa900, 0xa92f,
+}; /* CR_In_Kayah_Li */
+
+/* 'In_Rejang': Block */
+static const OnigCodePoint CR_In_Rejang[] = {
+ 1,
+ 0xa930, 0xa95f,
+}; /* CR_In_Rejang */
+
+/* 'In_Hangul_Jamo_Extended_A': Block */
+static const OnigCodePoint CR_In_Hangul_Jamo_Extended_A[] = {
+ 1,
+ 0xa960, 0xa97f,
+}; /* CR_In_Hangul_Jamo_Extended_A */
+
+/* 'In_Javanese': Block */
+static const OnigCodePoint CR_In_Javanese[] = {
+ 1,
+ 0xa980, 0xa9df,
+}; /* CR_In_Javanese */
+
+/* 'In_Myanmar_Extended_B': Block */
+static const OnigCodePoint CR_In_Myanmar_Extended_B[] = {
+ 1,
+ 0xa9e0, 0xa9ff,
+}; /* CR_In_Myanmar_Extended_B */
+
+/* 'In_Cham': Block */
+static const OnigCodePoint CR_In_Cham[] = {
+ 1,
+ 0xaa00, 0xaa5f,
+}; /* CR_In_Cham */
+
+/* 'In_Myanmar_Extended_A': Block */
+static const OnigCodePoint CR_In_Myanmar_Extended_A[] = {
+ 1,
+ 0xaa60, 0xaa7f,
+}; /* CR_In_Myanmar_Extended_A */
+
+/* 'In_Tai_Viet': Block */
+static const OnigCodePoint CR_In_Tai_Viet[] = {
+ 1,
+ 0xaa80, 0xaadf,
+}; /* CR_In_Tai_Viet */
+
+/* 'In_Meetei_Mayek_Extensions': Block */
+static const OnigCodePoint CR_In_Meetei_Mayek_Extensions[] = {
+ 1,
+ 0xaae0, 0xaaff,
+}; /* CR_In_Meetei_Mayek_Extensions */
+
+/* 'In_Ethiopic_Extended_A': Block */
+static const OnigCodePoint CR_In_Ethiopic_Extended_A[] = {
+ 1,
+ 0xab00, 0xab2f,
+}; /* CR_In_Ethiopic_Extended_A */
+
+/* 'In_Latin_Extended_E': Block */
+static const OnigCodePoint CR_In_Latin_Extended_E[] = {
+ 1,
+ 0xab30, 0xab6f,
+}; /* CR_In_Latin_Extended_E */
+
+/* 'In_Cherokee_Supplement': Block */
+static const OnigCodePoint CR_In_Cherokee_Supplement[] = {
+ 1,
+ 0xab70, 0xabbf,
+}; /* CR_In_Cherokee_Supplement */
+
+/* 'In_Meetei_Mayek': Block */
+static const OnigCodePoint CR_In_Meetei_Mayek[] = {
+ 1,
+ 0xabc0, 0xabff,
+}; /* CR_In_Meetei_Mayek */
+
+/* 'In_Hangul_Syllables': Block */
+static const OnigCodePoint CR_In_Hangul_Syllables[] = {
+ 1,
+ 0xac00, 0xd7af,
+}; /* CR_In_Hangul_Syllables */
+
+/* 'In_Hangul_Jamo_Extended_B': Block */
+static const OnigCodePoint CR_In_Hangul_Jamo_Extended_B[] = {
+ 1,
+ 0xd7b0, 0xd7ff,
+}; /* CR_In_Hangul_Jamo_Extended_B */
+
+/* 'In_High_Surrogates': Block */
+static const OnigCodePoint CR_In_High_Surrogates[] = {
+ 1,
+ 0xd800, 0xdb7f,
+}; /* CR_In_High_Surrogates */
+
+/* 'In_High_Private_Use_Surrogates': Block */
+static const OnigCodePoint CR_In_High_Private_Use_Surrogates[] = {
+ 1,
+ 0xdb80, 0xdbff,
+}; /* CR_In_High_Private_Use_Surrogates */
+
+/* 'In_Low_Surrogates': Block */
+static const OnigCodePoint CR_In_Low_Surrogates[] = {
+ 1,
+ 0xdc00, 0xdfff,
+}; /* CR_In_Low_Surrogates */
+
+/* 'In_Private_Use_Area': Block */
+static const OnigCodePoint CR_In_Private_Use_Area[] = {
+ 1,
+ 0xe000, 0xf8ff,
+}; /* CR_In_Private_Use_Area */
+
+/* 'In_CJK_Compatibility_Ideographs': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs[] = {
+ 1,
+ 0xf900, 0xfaff,
+}; /* CR_In_CJK_Compatibility_Ideographs */
+
+/* 'In_Alphabetic_Presentation_Forms': Block */
+static const OnigCodePoint CR_In_Alphabetic_Presentation_Forms[] = {
+ 1,
+ 0xfb00, 0xfb4f,
+}; /* CR_In_Alphabetic_Presentation_Forms */
+
+/* 'In_Arabic_Presentation_Forms_A': Block */
+static const OnigCodePoint CR_In_Arabic_Presentation_Forms_A[] = {
+ 1,
+ 0xfb50, 0xfdff,
+}; /* CR_In_Arabic_Presentation_Forms_A */
+
+/* 'In_Variation_Selectors': Block */
+static const OnigCodePoint CR_In_Variation_Selectors[] = {
+ 1,
+ 0xfe00, 0xfe0f,
+}; /* CR_In_Variation_Selectors */
+
+/* 'In_Vertical_Forms': Block */
+static const OnigCodePoint CR_In_Vertical_Forms[] = {
+ 1,
+ 0xfe10, 0xfe1f,
+}; /* CR_In_Vertical_Forms */
+
+/* 'In_Combining_Half_Marks': Block */
+static const OnigCodePoint CR_In_Combining_Half_Marks[] = {
+ 1,
+ 0xfe20, 0xfe2f,
+}; /* CR_In_Combining_Half_Marks */
+
+/* 'In_CJK_Compatibility_Forms': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility_Forms[] = {
+ 1,
+ 0xfe30, 0xfe4f,
+}; /* CR_In_CJK_Compatibility_Forms */
+
+/* 'In_Small_Form_Variants': Block */
+static const OnigCodePoint CR_In_Small_Form_Variants[] = {
+ 1,
+ 0xfe50, 0xfe6f,
+}; /* CR_In_Small_Form_Variants */
+
+/* 'In_Arabic_Presentation_Forms_B': Block */
+static const OnigCodePoint CR_In_Arabic_Presentation_Forms_B[] = {
+ 1,
+ 0xfe70, 0xfeff,
+}; /* CR_In_Arabic_Presentation_Forms_B */
+
+/* 'In_Halfwidth_and_Fullwidth_Forms': Block */
+static const OnigCodePoint CR_In_Halfwidth_and_Fullwidth_Forms[] = {
+ 1,
+ 0xff00, 0xffef,
+}; /* CR_In_Halfwidth_and_Fullwidth_Forms */
+
+/* 'In_Specials': Block */
+static const OnigCodePoint CR_In_Specials[] = {
+ 1,
+ 0xfff0, 0xffff,
+}; /* CR_In_Specials */
+
+/* 'In_Linear_B_Syllabary': Block */
+static const OnigCodePoint CR_In_Linear_B_Syllabary[] = {
+ 1,
+ 0x10000, 0x1007f,
+}; /* CR_In_Linear_B_Syllabary */
+
+/* 'In_Linear_B_Ideograms': Block */
+static const OnigCodePoint CR_In_Linear_B_Ideograms[] = {
+ 1,
+ 0x10080, 0x100ff,
+}; /* CR_In_Linear_B_Ideograms */
+
+/* 'In_Aegean_Numbers': Block */
+static const OnigCodePoint CR_In_Aegean_Numbers[] = {
+ 1,
+ 0x10100, 0x1013f,
+}; /* CR_In_Aegean_Numbers */
+
+/* 'In_Ancient_Greek_Numbers': Block */
+static const OnigCodePoint CR_In_Ancient_Greek_Numbers[] = {
+ 1,
+ 0x10140, 0x1018f,
+}; /* CR_In_Ancient_Greek_Numbers */
+
+/* 'In_Ancient_Symbols': Block */
+static const OnigCodePoint CR_In_Ancient_Symbols[] = {
+ 1,
+ 0x10190, 0x101cf,
+}; /* CR_In_Ancient_Symbols */
+
+/* 'In_Phaistos_Disc': Block */
+static const OnigCodePoint CR_In_Phaistos_Disc[] = {
+ 1,
+ 0x101d0, 0x101ff,
+}; /* CR_In_Phaistos_Disc */
+
+/* 'In_Lycian': Block */
+static const OnigCodePoint CR_In_Lycian[] = {
+ 1,
+ 0x10280, 0x1029f,
+}; /* CR_In_Lycian */
+
+/* 'In_Carian': Block */
+static const OnigCodePoint CR_In_Carian[] = {
+ 1,
+ 0x102a0, 0x102df,
+}; /* CR_In_Carian */
+
+/* 'In_Coptic_Epact_Numbers': Block */
+static const OnigCodePoint CR_In_Coptic_Epact_Numbers[] = {
+ 1,
+ 0x102e0, 0x102ff,
+}; /* CR_In_Coptic_Epact_Numbers */
+
+/* 'In_Old_Italic': Block */
+static const OnigCodePoint CR_In_Old_Italic[] = {
+ 1,
+ 0x10300, 0x1032f,
+}; /* CR_In_Old_Italic */
+
+/* 'In_Gothic': Block */
+static const OnigCodePoint CR_In_Gothic[] = {
+ 1,
+ 0x10330, 0x1034f,
+}; /* CR_In_Gothic */
+
+/* 'In_Old_Permic': Block */
+static const OnigCodePoint CR_In_Old_Permic[] = {
+ 1,
+ 0x10350, 0x1037f,
+}; /* CR_In_Old_Permic */
+
+/* 'In_Ugaritic': Block */
+static const OnigCodePoint CR_In_Ugaritic[] = {
+ 1,
+ 0x10380, 0x1039f,
+}; /* CR_In_Ugaritic */
+
+/* 'In_Old_Persian': Block */
+static const OnigCodePoint CR_In_Old_Persian[] = {
+ 1,
+ 0x103a0, 0x103df,
+}; /* CR_In_Old_Persian */
+
+/* 'In_Deseret': Block */
+#define CR_In_Deseret CR_Deseret
+
+/* 'In_Shavian': Block */
+#define CR_In_Shavian CR_Shavian
+
+/* 'In_Osmanya': Block */
+static const OnigCodePoint CR_In_Osmanya[] = {
+ 1,
+ 0x10480, 0x104af,
+}; /* CR_In_Osmanya */
+
+/* 'In_Osage': Block */
+static const OnigCodePoint CR_In_Osage[] = {
+ 1,
+ 0x104b0, 0x104ff,
+}; /* CR_In_Osage */
+
+/* 'In_Elbasan': Block */
+static const OnigCodePoint CR_In_Elbasan[] = {
+ 1,
+ 0x10500, 0x1052f,
+}; /* CR_In_Elbasan */
+
+/* 'In_Caucasian_Albanian': Block */
+static const OnigCodePoint CR_In_Caucasian_Albanian[] = {
+ 1,
+ 0x10530, 0x1056f,
+}; /* CR_In_Caucasian_Albanian */
+
+/* 'In_Vithkuqi': Block */
+static const OnigCodePoint CR_In_Vithkuqi[] = {
+ 1,
+ 0x10570, 0x105bf,
+}; /* CR_In_Vithkuqi */
+
+/* 'In_Todhri': Block */
+static const OnigCodePoint CR_In_Todhri[] = {
+ 1,
+ 0x105c0, 0x105ff,
+}; /* CR_In_Todhri */
+
+/* 'In_Linear_A': Block */
+static const OnigCodePoint CR_In_Linear_A[] = {
+ 1,
+ 0x10600, 0x1077f,
+}; /* CR_In_Linear_A */
+
+/* 'In_Latin_Extended_F': Block */
+static const OnigCodePoint CR_In_Latin_Extended_F[] = {
+ 1,
+ 0x10780, 0x107bf,
+}; /* CR_In_Latin_Extended_F */
+
+/* 'In_Cypriot_Syllabary': Block */
+static const OnigCodePoint CR_In_Cypriot_Syllabary[] = {
+ 1,
+ 0x10800, 0x1083f,
+}; /* CR_In_Cypriot_Syllabary */
+
+/* 'In_Imperial_Aramaic': Block */
+static const OnigCodePoint CR_In_Imperial_Aramaic[] = {
+ 1,
+ 0x10840, 0x1085f,
+}; /* CR_In_Imperial_Aramaic */
+
+/* 'In_Palmyrene': Block */
+#define CR_In_Palmyrene CR_Palmyrene
+
+/* 'In_Nabataean': Block */
+static const OnigCodePoint CR_In_Nabataean[] = {
+ 1,
+ 0x10880, 0x108af,
+}; /* CR_In_Nabataean */
+
+/* 'In_Hatran': Block */
+static const OnigCodePoint CR_In_Hatran[] = {
+ 1,
+ 0x108e0, 0x108ff,
+}; /* CR_In_Hatran */
+
+/* 'In_Phoenician': Block */
+static const OnigCodePoint CR_In_Phoenician[] = {
+ 1,
+ 0x10900, 0x1091f,
+}; /* CR_In_Phoenician */
+
+/* 'In_Lydian': Block */
+static const OnigCodePoint CR_In_Lydian[] = {
+ 1,
+ 0x10920, 0x1093f,
+}; /* CR_In_Lydian */
+
+/* 'In_Sidetic': Block */
+static const OnigCodePoint CR_In_Sidetic[] = {
+ 1,
+ 0x10940, 0x1095f,
+}; /* CR_In_Sidetic */
+
+/* 'In_Meroitic_Hieroglyphs': Block */
+#define CR_In_Meroitic_Hieroglyphs CR_Meroitic_Hieroglyphs
+
+/* 'In_Meroitic_Cursive': Block */
+static const OnigCodePoint CR_In_Meroitic_Cursive[] = {
+ 1,
+ 0x109a0, 0x109ff,
+}; /* CR_In_Meroitic_Cursive */
+
+/* 'In_Kharoshthi': Block */
+static const OnigCodePoint CR_In_Kharoshthi[] = {
+ 1,
+ 0x10a00, 0x10a5f,
+}; /* CR_In_Kharoshthi */
+
+/* 'In_Old_South_Arabian': Block */
+#define CR_In_Old_South_Arabian CR_Old_South_Arabian
+
+/* 'In_Old_North_Arabian': Block */
+#define CR_In_Old_North_Arabian CR_Old_North_Arabian
+
+/* 'In_Manichaean': Block */
+static const OnigCodePoint CR_In_Manichaean[] = {
+ 1,
+ 0x10ac0, 0x10aff,
+}; /* CR_In_Manichaean */
+
+/* 'In_Avestan': Block */
+static const OnigCodePoint CR_In_Avestan[] = {
+ 1,
+ 0x10b00, 0x10b3f,
+}; /* CR_In_Avestan */
+
+/* 'In_Inscriptional_Parthian': Block */
+static const OnigCodePoint CR_In_Inscriptional_Parthian[] = {
+ 1,
+ 0x10b40, 0x10b5f,
+}; /* CR_In_Inscriptional_Parthian */
+
+/* 'In_Inscriptional_Pahlavi': Block */
+static const OnigCodePoint CR_In_Inscriptional_Pahlavi[] = {
+ 1,
+ 0x10b60, 0x10b7f,
+}; /* CR_In_Inscriptional_Pahlavi */
+
+/* 'In_Psalter_Pahlavi': Block */
+static const OnigCodePoint CR_In_Psalter_Pahlavi[] = {
+ 1,
+ 0x10b80, 0x10baf,
+}; /* CR_In_Psalter_Pahlavi */
+
+/* 'In_Old_Turkic': Block */
+static const OnigCodePoint CR_In_Old_Turkic[] = {
+ 1,
+ 0x10c00, 0x10c4f,
+}; /* CR_In_Old_Turkic */
+
+/* 'In_Old_Hungarian': Block */
+static const OnigCodePoint CR_In_Old_Hungarian[] = {
+ 1,
+ 0x10c80, 0x10cff,
+}; /* CR_In_Old_Hungarian */
+
+/* 'In_Hanifi_Rohingya': Block */
+static const OnigCodePoint CR_In_Hanifi_Rohingya[] = {
+ 1,
+ 0x10d00, 0x10d3f,
+}; /* CR_In_Hanifi_Rohingya */
+
+/* 'In_Garay': Block */
+static const OnigCodePoint CR_In_Garay[] = {
+ 1,
+ 0x10d40, 0x10d8f,
+}; /* CR_In_Garay */
+
+/* 'In_Rumi_Numeral_Symbols': Block */
+static const OnigCodePoint CR_In_Rumi_Numeral_Symbols[] = {
+ 1,
+ 0x10e60, 0x10e7f,
+}; /* CR_In_Rumi_Numeral_Symbols */
+
+/* 'In_Yezidi': Block */
+static const OnigCodePoint CR_In_Yezidi[] = {
+ 1,
+ 0x10e80, 0x10ebf,
+}; /* CR_In_Yezidi */
+
+/* 'In_Arabic_Extended_C': Block */
+static const OnigCodePoint CR_In_Arabic_Extended_C[] = {
+ 1,
+ 0x10ec0, 0x10eff,
+}; /* CR_In_Arabic_Extended_C */
+
+/* 'In_Old_Sogdian': Block */
+static const OnigCodePoint CR_In_Old_Sogdian[] = {
+ 1,
+ 0x10f00, 0x10f2f,
+}; /* CR_In_Old_Sogdian */
+
+/* 'In_Sogdian': Block */
+static const OnigCodePoint CR_In_Sogdian[] = {
+ 1,
+ 0x10f30, 0x10f6f,
+}; /* CR_In_Sogdian */
+
+/* 'In_Old_Uyghur': Block */
+static const OnigCodePoint CR_In_Old_Uyghur[] = {
+ 1,
+ 0x10f70, 0x10faf,
+}; /* CR_In_Old_Uyghur */
+
+/* 'In_Chorasmian': Block */
+static const OnigCodePoint CR_In_Chorasmian[] = {
+ 1,
+ 0x10fb0, 0x10fdf,
+}; /* CR_In_Chorasmian */
+
+/* 'In_Elymaic': Block */
+static const OnigCodePoint CR_In_Elymaic[] = {
+ 1,
+ 0x10fe0, 0x10fff,
+}; /* CR_In_Elymaic */
+
+/* 'In_Brahmi': Block */
+static const OnigCodePoint CR_In_Brahmi[] = {
+ 1,
+ 0x11000, 0x1107f,
+}; /* CR_In_Brahmi */
+
+/* 'In_Kaithi': Block */
+static const OnigCodePoint CR_In_Kaithi[] = {
+ 1,
+ 0x11080, 0x110cf,
+}; /* CR_In_Kaithi */
+
+/* 'In_Sora_Sompeng': Block */
+static const OnigCodePoint CR_In_Sora_Sompeng[] = {
+ 1,
+ 0x110d0, 0x110ff,
+}; /* CR_In_Sora_Sompeng */
+
+/* 'In_Chakma': Block */
+static const OnigCodePoint CR_In_Chakma[] = {
+ 1,
+ 0x11100, 0x1114f,
+}; /* CR_In_Chakma */
+
+/* 'In_Mahajani': Block */
+static const OnigCodePoint CR_In_Mahajani[] = {
+ 1,
+ 0x11150, 0x1117f,
+}; /* CR_In_Mahajani */
+
+/* 'In_Sharada': Block */
+static const OnigCodePoint CR_In_Sharada[] = {
+ 1,
+ 0x11180, 0x111df,
+}; /* CR_In_Sharada */
+
+/* 'In_Sinhala_Archaic_Numbers': Block */
+static const OnigCodePoint CR_In_Sinhala_Archaic_Numbers[] = {
+ 1,
+ 0x111e0, 0x111ff,
+}; /* CR_In_Sinhala_Archaic_Numbers */
+
+/* 'In_Khojki': Block */
+static const OnigCodePoint CR_In_Khojki[] = {
+ 1,
+ 0x11200, 0x1124f,
+}; /* CR_In_Khojki */
+
+/* 'In_Multani': Block */
+static const OnigCodePoint CR_In_Multani[] = {
+ 1,
+ 0x11280, 0x112af,
+}; /* CR_In_Multani */
+
+/* 'In_Khudawadi': Block */
+static const OnigCodePoint CR_In_Khudawadi[] = {
+ 1,
+ 0x112b0, 0x112ff,
+}; /* CR_In_Khudawadi */
+
+/* 'In_Grantha': Block */
+static const OnigCodePoint CR_In_Grantha[] = {
+ 1,
+ 0x11300, 0x1137f,
+}; /* CR_In_Grantha */
+
+/* 'In_Tulu_Tigalari': Block */
+static const OnigCodePoint CR_In_Tulu_Tigalari[] = {
+ 1,
+ 0x11380, 0x113ff,
+}; /* CR_In_Tulu_Tigalari */
+
+/* 'In_Newa': Block */
+static const OnigCodePoint CR_In_Newa[] = {
+ 1,
+ 0x11400, 0x1147f,
+}; /* CR_In_Newa */
+
+/* 'In_Tirhuta': Block */
+static const OnigCodePoint CR_In_Tirhuta[] = {
+ 1,
+ 0x11480, 0x114df,
+}; /* CR_In_Tirhuta */
+
+/* 'In_Siddham': Block */
+static const OnigCodePoint CR_In_Siddham[] = {
+ 1,
+ 0x11580, 0x115ff,
+}; /* CR_In_Siddham */
+
+/* 'In_Modi': Block */
+static const OnigCodePoint CR_In_Modi[] = {
+ 1,
+ 0x11600, 0x1165f,
+}; /* CR_In_Modi */
+
+/* 'In_Mongolian_Supplement': Block */
+static const OnigCodePoint CR_In_Mongolian_Supplement[] = {
+ 1,
+ 0x11660, 0x1167f,
+}; /* CR_In_Mongolian_Supplement */
+
+/* 'In_Takri': Block */
+static const OnigCodePoint CR_In_Takri[] = {
+ 1,
+ 0x11680, 0x116cf,
+}; /* CR_In_Takri */
+
+/* 'In_Myanmar_Extended_C': Block */
+static const OnigCodePoint CR_In_Myanmar_Extended_C[] = {
+ 1,
+ 0x116d0, 0x116ff,
+}; /* CR_In_Myanmar_Extended_C */
+
+/* 'In_Ahom': Block */
+static const OnigCodePoint CR_In_Ahom[] = {
+ 1,
+ 0x11700, 0x1174f,
+}; /* CR_In_Ahom */
+
+/* 'In_Dogra': Block */
+static const OnigCodePoint CR_In_Dogra[] = {
+ 1,
+ 0x11800, 0x1184f,
+}; /* CR_In_Dogra */
+
+/* 'In_Warang_Citi': Block */
+static const OnigCodePoint CR_In_Warang_Citi[] = {
+ 1,
+ 0x118a0, 0x118ff,
+}; /* CR_In_Warang_Citi */
+
+/* 'In_Dives_Akuru': Block */
+static const OnigCodePoint CR_In_Dives_Akuru[] = {
+ 1,
+ 0x11900, 0x1195f,
+}; /* CR_In_Dives_Akuru */
+
+/* 'In_Nandinagari': Block */
+static const OnigCodePoint CR_In_Nandinagari[] = {
+ 1,
+ 0x119a0, 0x119ff,
+}; /* CR_In_Nandinagari */
+
+/* 'In_Zanabazar_Square': Block */
+static const OnigCodePoint CR_In_Zanabazar_Square[] = {
+ 1,
+ 0x11a00, 0x11a4f,
+}; /* CR_In_Zanabazar_Square */
+
+/* 'In_Soyombo': Block */
+static const OnigCodePoint CR_In_Soyombo[] = {
+ 1,
+ 0x11a50, 0x11aaf,
+}; /* CR_In_Soyombo */
+
+/* 'In_Unified_Canadian_Aboriginal_Syllabics_Extended_A': Block */
+static const OnigCodePoint CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A[] = {
+ 1,
+ 0x11ab0, 0x11abf,
+}; /* CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A */
+
+/* 'In_Pau_Cin_Hau': Block */
+static const OnigCodePoint CR_In_Pau_Cin_Hau[] = {
+ 1,
+ 0x11ac0, 0x11aff,
+}; /* CR_In_Pau_Cin_Hau */
+
+/* 'In_Devanagari_Extended_A': Block */
+static const OnigCodePoint CR_In_Devanagari_Extended_A[] = {
+ 1,
+ 0x11b00, 0x11b5f,
+}; /* CR_In_Devanagari_Extended_A */
+
+/* 'In_Sharada_Supplement': Block */
+static const OnigCodePoint CR_In_Sharada_Supplement[] = {
+ 1,
+ 0x11b60, 0x11b7f,
+}; /* CR_In_Sharada_Supplement */
+
+/* 'In_Sunuwar': Block */
+static const OnigCodePoint CR_In_Sunuwar[] = {
+ 1,
+ 0x11bc0, 0x11bff,
+}; /* CR_In_Sunuwar */
+
+/* 'In_Bhaiksuki': Block */
+static const OnigCodePoint CR_In_Bhaiksuki[] = {
+ 1,
+ 0x11c00, 0x11c6f,
+}; /* CR_In_Bhaiksuki */
+
+/* 'In_Marchen': Block */
+static const OnigCodePoint CR_In_Marchen[] = {
+ 1,
+ 0x11c70, 0x11cbf,
+}; /* CR_In_Marchen */
+
+/* 'In_Masaram_Gondi': Block */
+static const OnigCodePoint CR_In_Masaram_Gondi[] = {
+ 1,
+ 0x11d00, 0x11d5f,
+}; /* CR_In_Masaram_Gondi */
+
+/* 'In_Gunjala_Gondi': Block */
+static const OnigCodePoint CR_In_Gunjala_Gondi[] = {
+ 1,
+ 0x11d60, 0x11daf,
+}; /* CR_In_Gunjala_Gondi */
+
+/* 'In_Tolong_Siki': Block */
+static const OnigCodePoint CR_In_Tolong_Siki[] = {
+ 1,
+ 0x11db0, 0x11def,
+}; /* CR_In_Tolong_Siki */
+
+/* 'In_Makasar': Block */
+static const OnigCodePoint CR_In_Makasar[] = {
+ 1,
+ 0x11ee0, 0x11eff,
+}; /* CR_In_Makasar */
+
+/* 'In_Kawi': Block */
+static const OnigCodePoint CR_In_Kawi[] = {
+ 1,
+ 0x11f00, 0x11f5f,
+}; /* CR_In_Kawi */
+
+/* 'In_Lisu_Supplement': Block */
+static const OnigCodePoint CR_In_Lisu_Supplement[] = {
+ 1,
+ 0x11fb0, 0x11fbf,
+}; /* CR_In_Lisu_Supplement */
+
+/* 'In_Tamil_Supplement': Block */
+static const OnigCodePoint CR_In_Tamil_Supplement[] = {
+ 1,
+ 0x11fc0, 0x11fff,
+}; /* CR_In_Tamil_Supplement */
+
+/* 'In_Cuneiform': Block */
+static const OnigCodePoint CR_In_Cuneiform[] = {
+ 1,
+ 0x12000, 0x123ff,
+}; /* CR_In_Cuneiform */
+
+/* 'In_Cuneiform_Numbers_and_Punctuation': Block */
+static const OnigCodePoint CR_In_Cuneiform_Numbers_and_Punctuation[] = {
+ 1,
+ 0x12400, 0x1247f,
+}; /* CR_In_Cuneiform_Numbers_and_Punctuation */
+
+/* 'In_Early_Dynastic_Cuneiform': Block */
+static const OnigCodePoint CR_In_Early_Dynastic_Cuneiform[] = {
+ 1,
+ 0x12480, 0x1254f,
+}; /* CR_In_Early_Dynastic_Cuneiform */
+
+/* 'In_Cypro_Minoan': Block */
+static const OnigCodePoint CR_In_Cypro_Minoan[] = {
+ 1,
+ 0x12f90, 0x12fff,
+}; /* CR_In_Cypro_Minoan */
+
+/* 'In_Egyptian_Hieroglyphs': Block */
+static const OnigCodePoint CR_In_Egyptian_Hieroglyphs[] = {
+ 1,
+ 0x13000, 0x1342f,
+}; /* CR_In_Egyptian_Hieroglyphs */
+
+/* 'In_Egyptian_Hieroglyph_Format_Controls': Block */
+static const OnigCodePoint CR_In_Egyptian_Hieroglyph_Format_Controls[] = {
+ 1,
+ 0x13430, 0x1345f,
+}; /* CR_In_Egyptian_Hieroglyph_Format_Controls */
+
+/* 'In_Egyptian_Hieroglyphs_Extended_A': Block */
+static const OnigCodePoint CR_In_Egyptian_Hieroglyphs_Extended_A[] = {
+ 1,
+ 0x13460, 0x143ff,
+}; /* CR_In_Egyptian_Hieroglyphs_Extended_A */
+
+/* 'In_Anatolian_Hieroglyphs': Block */
+static const OnigCodePoint CR_In_Anatolian_Hieroglyphs[] = {
+ 1,
+ 0x14400, 0x1467f,
+}; /* CR_In_Anatolian_Hieroglyphs */
+
+/* 'In_Gurung_Khema': Block */
+static const OnigCodePoint CR_In_Gurung_Khema[] = {
+ 1,
+ 0x16100, 0x1613f,
+}; /* CR_In_Gurung_Khema */
+
+/* 'In_Bamum_Supplement': Block */
+static const OnigCodePoint CR_In_Bamum_Supplement[] = {
+ 1,
+ 0x16800, 0x16a3f,
+}; /* CR_In_Bamum_Supplement */
+
+/* 'In_Mro': Block */
+static const OnigCodePoint CR_In_Mro[] = {
+ 1,
+ 0x16a40, 0x16a6f,
+}; /* CR_In_Mro */
+
+/* 'In_Tangsa': Block */
+static const OnigCodePoint CR_In_Tangsa[] = {
+ 1,
+ 0x16a70, 0x16acf,
+}; /* CR_In_Tangsa */
+
+/* 'In_Bassa_Vah': Block */
+static const OnigCodePoint CR_In_Bassa_Vah[] = {
+ 1,
+ 0x16ad0, 0x16aff,
+}; /* CR_In_Bassa_Vah */
+
+/* 'In_Pahawh_Hmong': Block */
+static const OnigCodePoint CR_In_Pahawh_Hmong[] = {
+ 1,
+ 0x16b00, 0x16b8f,
+}; /* CR_In_Pahawh_Hmong */
+
+/* 'In_Kirat_Rai': Block */
+static const OnigCodePoint CR_In_Kirat_Rai[] = {
+ 1,
+ 0x16d40, 0x16d7f,
+}; /* CR_In_Kirat_Rai */
+
+/* 'In_Medefaidrin': Block */
+static const OnigCodePoint CR_In_Medefaidrin[] = {
+ 1,
+ 0x16e40, 0x16e9f,
+}; /* CR_In_Medefaidrin */
+
+/* 'In_Beria_Erfe': Block */
+static const OnigCodePoint CR_In_Beria_Erfe[] = {
+ 1,
+ 0x16ea0, 0x16edf,
+}; /* CR_In_Beria_Erfe */
+
+/* 'In_Miao': Block */
+static const OnigCodePoint CR_In_Miao[] = {
+ 1,
+ 0x16f00, 0x16f9f,
+}; /* CR_In_Miao */
+
+/* 'In_Ideographic_Symbols_and_Punctuation': Block */
+static const OnigCodePoint CR_In_Ideographic_Symbols_and_Punctuation[] = {
+ 1,
+ 0x16fe0, 0x16fff,
+}; /* CR_In_Ideographic_Symbols_and_Punctuation */
+
+/* 'In_Tangut': Block */
+static const OnigCodePoint CR_In_Tangut[] = {
+ 1,
+ 0x17000, 0x187ff,
+}; /* CR_In_Tangut */
+
+/* 'In_Tangut_Components': Block */
+static const OnigCodePoint CR_In_Tangut_Components[] = {
+ 1,
+ 0x18800, 0x18aff,
+}; /* CR_In_Tangut_Components */
+
+/* 'In_Khitan_Small_Script': Block */
+static const OnigCodePoint CR_In_Khitan_Small_Script[] = {
+ 1,
+ 0x18b00, 0x18cff,
+}; /* CR_In_Khitan_Small_Script */
+
+/* 'In_Tangut_Supplement': Block */
+static const OnigCodePoint CR_In_Tangut_Supplement[] = {
+ 1,
+ 0x18d00, 0x18d7f,
+}; /* CR_In_Tangut_Supplement */
+
+/* 'In_Tangut_Components_Supplement': Block */
+static const OnigCodePoint CR_In_Tangut_Components_Supplement[] = {
+ 1,
+ 0x18d80, 0x18dff,
+}; /* CR_In_Tangut_Components_Supplement */
+
+/* 'In_Kana_Extended_B': Block */
+static const OnigCodePoint CR_In_Kana_Extended_B[] = {
+ 1,
+ 0x1aff0, 0x1afff,
+}; /* CR_In_Kana_Extended_B */
+
+/* 'In_Kana_Supplement': Block */
+static const OnigCodePoint CR_In_Kana_Supplement[] = {
+ 1,
+ 0x1b000, 0x1b0ff,
+}; /* CR_In_Kana_Supplement */
+
+/* 'In_Kana_Extended_A': Block */
+static const OnigCodePoint CR_In_Kana_Extended_A[] = {
+ 1,
+ 0x1b100, 0x1b12f,
+}; /* CR_In_Kana_Extended_A */
+
+/* 'In_Small_Kana_Extension': Block */
+static const OnigCodePoint CR_In_Small_Kana_Extension[] = {
+ 1,
+ 0x1b130, 0x1b16f,
+}; /* CR_In_Small_Kana_Extension */
+
+/* 'In_Nushu': Block */
+static const OnigCodePoint CR_In_Nushu[] = {
+ 1,
+ 0x1b170, 0x1b2ff,
+}; /* CR_In_Nushu */
+
+/* 'In_Duployan': Block */
+static const OnigCodePoint CR_In_Duployan[] = {
+ 1,
+ 0x1bc00, 0x1bc9f,
+}; /* CR_In_Duployan */
+
+/* 'In_Shorthand_Format_Controls': Block */
+static const OnigCodePoint CR_In_Shorthand_Format_Controls[] = {
+ 1,
+ 0x1bca0, 0x1bcaf,
+}; /* CR_In_Shorthand_Format_Controls */
+
+/* 'In_Symbols_for_Legacy_Computing_Supplement': Block */
+static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing_Supplement[] = {
+ 1,
+ 0x1cc00, 0x1cebf,
+}; /* CR_In_Symbols_for_Legacy_Computing_Supplement */
+
+/* 'In_Miscellaneous_Symbols_Supplement': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols_Supplement[] = {
+ 1,
+ 0x1cec0, 0x1ceff,
+}; /* CR_In_Miscellaneous_Symbols_Supplement */
+
+/* 'In_Znamenny_Musical_Notation': Block */
+static const OnigCodePoint CR_In_Znamenny_Musical_Notation[] = {
+ 1,
+ 0x1cf00, 0x1cfcf,
+}; /* CR_In_Znamenny_Musical_Notation */
+
+/* 'In_Byzantine_Musical_Symbols': Block */
+static const OnigCodePoint CR_In_Byzantine_Musical_Symbols[] = {
+ 1,
+ 0x1d000, 0x1d0ff,
+}; /* CR_In_Byzantine_Musical_Symbols */
+
+/* 'In_Musical_Symbols': Block */
+static const OnigCodePoint CR_In_Musical_Symbols[] = {
+ 1,
+ 0x1d100, 0x1d1ff,
+}; /* CR_In_Musical_Symbols */
+
+/* 'In_Ancient_Greek_Musical_Notation': Block */
+static const OnigCodePoint CR_In_Ancient_Greek_Musical_Notation[] = {
+ 1,
+ 0x1d200, 0x1d24f,
+}; /* CR_In_Ancient_Greek_Musical_Notation */
+
+/* 'In_Kaktovik_Numerals': Block */
+static const OnigCodePoint CR_In_Kaktovik_Numerals[] = {
+ 1,
+ 0x1d2c0, 0x1d2df,
+}; /* CR_In_Kaktovik_Numerals */
+
+/* 'In_Mayan_Numerals': Block */
+static const OnigCodePoint CR_In_Mayan_Numerals[] = {
+ 1,
+ 0x1d2e0, 0x1d2ff,
+}; /* CR_In_Mayan_Numerals */
+
+/* 'In_Tai_Xuan_Jing_Symbols': Block */
+static const OnigCodePoint CR_In_Tai_Xuan_Jing_Symbols[] = {
+ 1,
+ 0x1d300, 0x1d35f,
+}; /* CR_In_Tai_Xuan_Jing_Symbols */
+
+/* 'In_Counting_Rod_Numerals': Block */
+static const OnigCodePoint CR_In_Counting_Rod_Numerals[] = {
+ 1,
+ 0x1d360, 0x1d37f,
+}; /* CR_In_Counting_Rod_Numerals */
+
+/* 'In_Mathematical_Alphanumeric_Symbols': Block */
+static const OnigCodePoint CR_In_Mathematical_Alphanumeric_Symbols[] = {
+ 1,
+ 0x1d400, 0x1d7ff,
+}; /* CR_In_Mathematical_Alphanumeric_Symbols */
+
+/* 'In_Sutton_SignWriting': Block */
+static const OnigCodePoint CR_In_Sutton_SignWriting[] = {
+ 1,
+ 0x1d800, 0x1daaf,
+}; /* CR_In_Sutton_SignWriting */
+
+/* 'In_Latin_Extended_G': Block */
+static const OnigCodePoint CR_In_Latin_Extended_G[] = {
+ 1,
+ 0x1df00, 0x1dfff,
+}; /* CR_In_Latin_Extended_G */
+
+/* 'In_Glagolitic_Supplement': Block */
+static const OnigCodePoint CR_In_Glagolitic_Supplement[] = {
+ 1,
+ 0x1e000, 0x1e02f,
+}; /* CR_In_Glagolitic_Supplement */
+
+/* 'In_Cyrillic_Extended_D': Block */
+static const OnigCodePoint CR_In_Cyrillic_Extended_D[] = {
+ 1,
+ 0x1e030, 0x1e08f,
+}; /* CR_In_Cyrillic_Extended_D */
+
+/* 'In_Nyiakeng_Puachue_Hmong': Block */
+static const OnigCodePoint CR_In_Nyiakeng_Puachue_Hmong[] = {
+ 1,
+ 0x1e100, 0x1e14f,
+}; /* CR_In_Nyiakeng_Puachue_Hmong */
+
+/* 'In_Toto': Block */
+static const OnigCodePoint CR_In_Toto[] = {
+ 1,
+ 0x1e290, 0x1e2bf,
+}; /* CR_In_Toto */
+
+/* 'In_Wancho': Block */
+static const OnigCodePoint CR_In_Wancho[] = {
+ 1,
+ 0x1e2c0, 0x1e2ff,
+}; /* CR_In_Wancho */
+
+/* 'In_Nag_Mundari': Block */
+static const OnigCodePoint CR_In_Nag_Mundari[] = {
+ 1,
+ 0x1e4d0, 0x1e4ff,
+}; /* CR_In_Nag_Mundari */
+
+/* 'In_Ol_Onal': Block */
+static const OnigCodePoint CR_In_Ol_Onal[] = {
+ 1,
+ 0x1e5d0, 0x1e5ff,
+}; /* CR_In_Ol_Onal */
+
+/* 'In_Tai_Yo': Block */
+static const OnigCodePoint CR_In_Tai_Yo[] = {
+ 1,
+ 0x1e6c0, 0x1e6ff,
+}; /* CR_In_Tai_Yo */
+
+/* 'In_Ethiopic_Extended_B': Block */
+static const OnigCodePoint CR_In_Ethiopic_Extended_B[] = {
+ 1,
+ 0x1e7e0, 0x1e7ff,
+}; /* CR_In_Ethiopic_Extended_B */
+
+/* 'In_Mende_Kikakui': Block */
+static const OnigCodePoint CR_In_Mende_Kikakui[] = {
+ 1,
+ 0x1e800, 0x1e8df,
+}; /* CR_In_Mende_Kikakui */
+
+/* 'In_Adlam': Block */
+static const OnigCodePoint CR_In_Adlam[] = {
+ 1,
+ 0x1e900, 0x1e95f,
+}; /* CR_In_Adlam */
+
+/* 'In_Indic_Siyaq_Numbers': Block */
+static const OnigCodePoint CR_In_Indic_Siyaq_Numbers[] = {
+ 1,
+ 0x1ec70, 0x1ecbf,
+}; /* CR_In_Indic_Siyaq_Numbers */
+
+/* 'In_Ottoman_Siyaq_Numbers': Block */
+static const OnigCodePoint CR_In_Ottoman_Siyaq_Numbers[] = {
+ 1,
+ 0x1ed00, 0x1ed4f,
+}; /* CR_In_Ottoman_Siyaq_Numbers */
+
+/* 'In_Arabic_Mathematical_Alphabetic_Symbols': Block */
+static const OnigCodePoint CR_In_Arabic_Mathematical_Alphabetic_Symbols[] = {
+ 1,
+ 0x1ee00, 0x1eeff,
+}; /* CR_In_Arabic_Mathematical_Alphabetic_Symbols */
+
+/* 'In_Mahjong_Tiles': Block */
+static const OnigCodePoint CR_In_Mahjong_Tiles[] = {
+ 1,
+ 0x1f000, 0x1f02f,
+}; /* CR_In_Mahjong_Tiles */
+
+/* 'In_Domino_Tiles': Block */
+static const OnigCodePoint CR_In_Domino_Tiles[] = {
+ 1,
+ 0x1f030, 0x1f09f,
+}; /* CR_In_Domino_Tiles */
+
+/* 'In_Playing_Cards': Block */
+static const OnigCodePoint CR_In_Playing_Cards[] = {
+ 1,
+ 0x1f0a0, 0x1f0ff,
+}; /* CR_In_Playing_Cards */
+
+/* 'In_Enclosed_Alphanumeric_Supplement': Block */
+static const OnigCodePoint CR_In_Enclosed_Alphanumeric_Supplement[] = {
+ 1,
+ 0x1f100, 0x1f1ff,
+}; /* CR_In_Enclosed_Alphanumeric_Supplement */
+
+/* 'In_Enclosed_Ideographic_Supplement': Block */
+static const OnigCodePoint CR_In_Enclosed_Ideographic_Supplement[] = {
+ 1,
+ 0x1f200, 0x1f2ff,
+}; /* CR_In_Enclosed_Ideographic_Supplement */
+
+/* 'In_Miscellaneous_Symbols_and_Pictographs': Block */
+static const OnigCodePoint CR_In_Miscellaneous_Symbols_and_Pictographs[] = {
+ 1,
+ 0x1f300, 0x1f5ff,
+}; /* CR_In_Miscellaneous_Symbols_and_Pictographs */
+
+/* 'In_Emoticons': Block */
+static const OnigCodePoint CR_In_Emoticons[] = {
+ 1,
+ 0x1f600, 0x1f64f,
+}; /* CR_In_Emoticons */
+
+/* 'In_Ornamental_Dingbats': Block */
+static const OnigCodePoint CR_In_Ornamental_Dingbats[] = {
+ 1,
+ 0x1f650, 0x1f67f,
+}; /* CR_In_Ornamental_Dingbats */
+
+/* 'In_Transport_and_Map_Symbols': Block */
+static const OnigCodePoint CR_In_Transport_and_Map_Symbols[] = {
+ 1,
+ 0x1f680, 0x1f6ff,
+}; /* CR_In_Transport_and_Map_Symbols */
+
+/* 'In_Alchemical_Symbols': Block */
+static const OnigCodePoint CR_In_Alchemical_Symbols[] = {
+ 1,
+ 0x1f700, 0x1f77f,
+}; /* CR_In_Alchemical_Symbols */
+
+/* 'In_Geometric_Shapes_Extended': Block */
+static const OnigCodePoint CR_In_Geometric_Shapes_Extended[] = {
+ 1,
+ 0x1f780, 0x1f7ff,
+}; /* CR_In_Geometric_Shapes_Extended */
+
+/* 'In_Supplemental_Arrows_C': Block */
+static const OnigCodePoint CR_In_Supplemental_Arrows_C[] = {
+ 1,
+ 0x1f800, 0x1f8ff,
+}; /* CR_In_Supplemental_Arrows_C */
+
+/* 'In_Supplemental_Symbols_and_Pictographs': Block */
+static const OnigCodePoint CR_In_Supplemental_Symbols_and_Pictographs[] = {
+ 1,
+ 0x1f900, 0x1f9ff,
+}; /* CR_In_Supplemental_Symbols_and_Pictographs */
+
+/* 'In_Chess_Symbols': Block */
+static const OnigCodePoint CR_In_Chess_Symbols[] = {
+ 1,
+ 0x1fa00, 0x1fa6f,
+}; /* CR_In_Chess_Symbols */
+
+/* 'In_Symbols_and_Pictographs_Extended_A': Block */
+static const OnigCodePoint CR_In_Symbols_and_Pictographs_Extended_A[] = {
+ 1,
+ 0x1fa70, 0x1faff,
+}; /* CR_In_Symbols_and_Pictographs_Extended_A */
+
+/* 'In_Symbols_for_Legacy_Computing': Block */
+static const OnigCodePoint CR_In_Symbols_for_Legacy_Computing[] = {
+ 1,
+ 0x1fb00, 0x1fbff,
+}; /* CR_In_Symbols_for_Legacy_Computing */
+
+/* 'In_CJK_Unified_Ideographs_Extension_B': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_B[] = {
+ 1,
+ 0x20000, 0x2a6df,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_B */
+
+/* 'In_CJK_Unified_Ideographs_Extension_C': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_C[] = {
+ 1,
+ 0x2a700, 0x2b73f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_C */
+
+/* 'In_CJK_Unified_Ideographs_Extension_D': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_D[] = {
+ 1,
+ 0x2b740, 0x2b81f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_D */
+
+/* 'In_CJK_Unified_Ideographs_Extension_E': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_E[] = {
+ 1,
+ 0x2b820, 0x2ceaf,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_E */
+
+/* 'In_CJK_Unified_Ideographs_Extension_F': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_F[] = {
+ 1,
+ 0x2ceb0, 0x2ebef,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_F */
+
+/* 'In_CJK_Unified_Ideographs_Extension_I': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_I[] = {
+ 1,
+ 0x2ebf0, 0x2ee5f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_I */
+
+/* 'In_CJK_Compatibility_Ideographs_Supplement': Block */
+static const OnigCodePoint CR_In_CJK_Compatibility_Ideographs_Supplement[] = {
+ 1,
+ 0x2f800, 0x2fa1f,
+}; /* CR_In_CJK_Compatibility_Ideographs_Supplement */
+
+/* 'In_CJK_Unified_Ideographs_Extension_G': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_G[] = {
+ 1,
+ 0x30000, 0x3134f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_G */
+
+/* 'In_CJK_Unified_Ideographs_Extension_H': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_H[] = {
+ 1,
+ 0x31350, 0x323af,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_H */
+
+/* 'In_CJK_Unified_Ideographs_Extension_J': Block */
+static const OnigCodePoint CR_In_CJK_Unified_Ideographs_Extension_J[] = {
+ 1,
+ 0x323b0, 0x3347f,
+}; /* CR_In_CJK_Unified_Ideographs_Extension_J */
+
+/* 'In_Tags': Block */
+static const OnigCodePoint CR_In_Tags[] = {
+ 1,
+ 0xe0000, 0xe007f,
+}; /* CR_In_Tags */
+
+/* 'In_Variation_Selectors_Supplement': Block */
+static const OnigCodePoint CR_In_Variation_Selectors_Supplement[] = {
+ 1,
+ 0xe0100, 0xe01ef,
+}; /* CR_In_Variation_Selectors_Supplement */
+
+/* 'In_Supplementary_Private_Use_Area_A': Block */
+static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_A[] = {
+ 1,
+ 0xf0000, 0xfffff,
+}; /* CR_In_Supplementary_Private_Use_Area_A */
+
+/* 'In_Supplementary_Private_Use_Area_B': Block */
+static const OnigCodePoint CR_In_Supplementary_Private_Use_Area_B[] = {
+ 1,
+ 0x100000, 0x10ffff,
+}; /* CR_In_Supplementary_Private_Use_Area_B */
+
+/* 'In_No_Block': Block */
+static const OnigCodePoint CR_In_No_Block[] = {
+ 51,
+ 0x2fe0, 0x2fef,
+ 0x10200, 0x1027f,
+ 0x103e0, 0x103ff,
+ 0x107c0, 0x107ff,
+ 0x108b0, 0x108df,
+ 0x10960, 0x1097f,
+ 0x10aa0, 0x10abf,
+ 0x10bb0, 0x10bff,
+ 0x10c50, 0x10c7f,
+ 0x10d90, 0x10e5f,
+ 0x11250, 0x1127f,
+ 0x114e0, 0x1157f,
+ 0x11750, 0x117ff,
+ 0x11850, 0x1189f,
+ 0x11960, 0x1199f,
+ 0x11b80, 0x11bbf,
+ 0x11cc0, 0x11cff,
+ 0x11df0, 0x11edf,
+ 0x11f60, 0x11faf,
+ 0x12550, 0x12f8f,
+ 0x14680, 0x160ff,
+ 0x16140, 0x167ff,
+ 0x16b90, 0x16d3f,
+ 0x16d80, 0x16e3f,
+ 0x16ee0, 0x16eff,
+ 0x16fa0, 0x16fdf,
+ 0x18e00, 0x1afef,
+ 0x1b300, 0x1bbff,
+ 0x1bcb0, 0x1cbff,
+ 0x1cfd0, 0x1cfff,
+ 0x1d250, 0x1d2bf,
+ 0x1d380, 0x1d3ff,
+ 0x1dab0, 0x1deff,
+ 0x1e090, 0x1e0ff,
+ 0x1e150, 0x1e28f,
+ 0x1e300, 0x1e4cf,
+ 0x1e500, 0x1e5cf,
+ 0x1e600, 0x1e6bf,
+ 0x1e700, 0x1e7df,
+ 0x1e8e0, 0x1e8ff,
+ 0x1e960, 0x1ec6f,
+ 0x1ecc0, 0x1ecff,
+ 0x1ed50, 0x1edff,
+ 0x1ef00, 0x1efff,
+ 0x1fc00, 0x1ffff,
+ 0x2a6e0, 0x2a6ff,
+ 0x2ee60, 0x2f7ff,
+ 0x2fa20, 0x2ffff,
+ 0x33480, 0xdffff,
+ 0xe0080, 0xe00ff,
+ 0xe01f0, 0xeffff,
+}; /* CR_In_No_Block */
+
+#endif /* USE_UNICODE_PROPERTIES */
+static const OnigCodePoint* const CodeRanges[] = {
+ CR_NEWLINE,
+ CR_Alpha,
+ CR_Blank,
+ CR_Cntrl,
+ CR_Digit,
+ CR_Graph,
+ CR_Lower,
+ CR_Print,
+ CR_XPosixPunct,
+ CR_Space,
+ CR_Upper,
+ CR_XDigit,
+ CR_Word,
+ CR_Alnum,
+ CR_ASCII,
+ CR_Punct,
+#ifdef USE_UNICODE_PROPERTIES
+ CR_Any,
+ CR_Assigned,
+ CR_C,
+ CR_Cc,
+ CR_Cf,
+ CR_Cn,
+ CR_Co,
+ CR_Cs,
+ CR_L,
+ CR_LC,
+ CR_Ll,
+ CR_Lm,
+ CR_Lo,
+ CR_Lt,
+ CR_Lu,
+ CR_M,
+ CR_Mc,
+ CR_Me,
+ CR_Mn,
+ CR_N,
+ CR_Nd,
+ CR_Nl,
+ CR_No,
+ CR_P,
+ CR_Pc,
+ CR_Pd,
+ CR_Pe,
+ CR_Pf,
+ CR_Pi,
+ CR_Po,
+ CR_Ps,
+ CR_S,
+ CR_Sc,
+ CR_Sk,
+ CR_Sm,
+ CR_So,
+ CR_Z,
+ CR_Zl,
+ CR_Zp,
+ CR_Zs,
+ CR_Math,
+ CR_Alphabetic,
+ CR_Lowercase,
+ CR_Uppercase,
+ CR_Cased,
+ CR_Case_Ignorable,
+ CR_Changes_When_Lowercased,
+ CR_Changes_When_Uppercased,
+ CR_Changes_When_Titlecased,
+ CR_Changes_When_Casefolded,
+ CR_Changes_When_Casemapped,
+ CR_ID_Start,
+ CR_ID_Continue,
+ CR_XID_Start,
+ CR_XID_Continue,
+ CR_Default_Ignorable_Code_Point,
+ CR_Grapheme_Extend,
+ CR_Grapheme_Base,
+ CR_Grapheme_Link,
+ CR_InCB_Linker,
+ CR_InCB_Consonant,
+ CR_InCB_Extend,
+ CR_Common,
+ CR_Latin,
+ CR_Greek,
+ CR_Cyrillic,
+ CR_Armenian,
+ CR_Hebrew,
+ CR_Arabic,
+ CR_Syriac,
+ CR_Thaana,
+ CR_Devanagari,
+ CR_Bengali,
+ CR_Gurmukhi,
+ CR_Gujarati,
+ CR_Oriya,
+ CR_Tamil,
+ CR_Telugu,
+ CR_Kannada,
+ CR_Malayalam,
+ CR_Sinhala,
+ CR_Thai,
+ CR_Lao,
+ CR_Tibetan,
+ CR_Myanmar,
+ CR_Georgian,
+ CR_Hangul,
+ CR_Ethiopic,
+ CR_Cherokee,
+ CR_Canadian_Aboriginal,
+ CR_Ogham,
+ CR_Runic,
+ CR_Khmer,
+ CR_Mongolian,
+ CR_Hiragana,
+ CR_Katakana,
+ CR_Bopomofo,
+ CR_Han,
+ CR_Yi,
+ CR_Old_Italic,
+ CR_Gothic,
+ CR_Deseret,
+ CR_Inherited,
+ CR_Tagalog,
+ CR_Hanunoo,
+ CR_Buhid,
+ CR_Tagbanwa,
+ CR_Limbu,
+ CR_Tai_Le,
+ CR_Linear_B,
+ CR_Ugaritic,
+ CR_Shavian,
+ CR_Osmanya,
+ CR_Cypriot,
+ CR_Braille,
+ CR_Buginese,
+ CR_Coptic,
+ CR_New_Tai_Lue,
+ CR_Glagolitic,
+ CR_Tifinagh,
+ CR_Syloti_Nagri,
+ CR_Old_Persian,
+ CR_Kharoshthi,
+ CR_Balinese,
+ CR_Cuneiform,
+ CR_Phoenician,
+ CR_Phags_Pa,
+ CR_Nko,
+ CR_Sundanese,
+ CR_Lepcha,
+ CR_Ol_Chiki,
+ CR_Vai,
+ CR_Saurashtra,
+ CR_Kayah_Li,
+ CR_Rejang,
+ CR_Lycian,
+ CR_Carian,
+ CR_Lydian,
+ CR_Cham,
+ CR_Tai_Tham,
+ CR_Tai_Viet,
+ CR_Avestan,
+ CR_Egyptian_Hieroglyphs,
+ CR_Samaritan,
+ CR_Lisu,
+ CR_Bamum,
+ CR_Javanese,
+ CR_Meetei_Mayek,
+ CR_Imperial_Aramaic,
+ CR_Old_South_Arabian,
+ CR_Inscriptional_Parthian,
+ CR_Inscriptional_Pahlavi,
+ CR_Old_Turkic,
+ CR_Kaithi,
+ CR_Batak,
+ CR_Brahmi,
+ CR_Mandaic,
+ CR_Chakma,
+ CR_Meroitic_Cursive,
+ CR_Meroitic_Hieroglyphs,
+ CR_Miao,
+ CR_Sharada,
+ CR_Sora_Sompeng,
+ CR_Takri,
+ CR_Caucasian_Albanian,
+ CR_Bassa_Vah,
+ CR_Duployan,
+ CR_Elbasan,
+ CR_Grantha,
+ CR_Pahawh_Hmong,
+ CR_Khojki,
+ CR_Linear_A,
+ CR_Mahajani,
+ CR_Manichaean,
+ CR_Mende_Kikakui,
+ CR_Modi,
+ CR_Mro,
+ CR_Old_North_Arabian,
+ CR_Nabataean,
+ CR_Palmyrene,
+ CR_Pau_Cin_Hau,
+ CR_Old_Permic,
+ CR_Psalter_Pahlavi,
+ CR_Siddham,
+ CR_Khudawadi,
+ CR_Tirhuta,
+ CR_Warang_Citi,
+ CR_Ahom,
+ CR_Anatolian_Hieroglyphs,
+ CR_Hatran,
+ CR_Multani,
+ CR_Old_Hungarian,
+ CR_SignWriting,
+ CR_Adlam,
+ CR_Bhaiksuki,
+ CR_Marchen,
+ CR_Newa,
+ CR_Osage,
+ CR_Tangut,
+ CR_Masaram_Gondi,
+ CR_Nushu,
+ CR_Soyombo,
+ CR_Zanabazar_Square,
+ CR_Dogra,
+ CR_Gunjala_Gondi,
+ CR_Makasar,
+ CR_Medefaidrin,
+ CR_Hanifi_Rohingya,
+ CR_Sogdian,
+ CR_Old_Sogdian,
+ CR_Elymaic,
+ CR_Nandinagari,
+ CR_Nyiakeng_Puachue_Hmong,
+ CR_Wancho,
+ CR_Chorasmian,
+ CR_Dives_Akuru,
+ CR_Khitan_Small_Script,
+ CR_Yezidi,
+ CR_Cypro_Minoan,
+ CR_Old_Uyghur,
+ CR_Tangsa,
+ CR_Toto,
+ CR_Vithkuqi,
+ CR_Kawi,
+ CR_Nag_Mundari,
+ CR_Garay,
+ CR_Gurung_Khema,
+ CR_Kirat_Rai,
+ CR_Ol_Onal,
+ CR_Sunuwar,
+ CR_Todhri,
+ CR_Tulu_Tigalari,
+ CR_Sidetic,
+ CR_Tai_Yo,
+ CR_Tolong_Siki,
+ CR_Beria_Erfe,
+ CR_White_Space,
+ CR_Bidi_Control,
+ CR_Join_Control,
+ CR_Dash,
+ CR_Hyphen,
+ CR_Quotation_Mark,
+ CR_Terminal_Punctuation,
+ CR_Other_Math,
+ CR_Hex_Digit,
+ CR_ASCII_Hex_Digit,
+ CR_Other_Alphabetic,
+ CR_Ideographic,
+ CR_Diacritic,
+ CR_Extender,
+ CR_Other_Lowercase,
+ CR_Other_Uppercase,
+ CR_Noncharacter_Code_Point,
+ CR_Other_Grapheme_Extend,
+ CR_IDS_Binary_Operator,
+ CR_IDS_Trinary_Operator,
+ CR_IDS_Unary_Operator,
+ CR_Radical,
+ CR_Unified_Ideograph,
+ CR_Other_Default_Ignorable_Code_Point,
+ CR_Deprecated,
+ CR_Soft_Dotted,
+ CR_Logical_Order_Exception,
+ CR_Other_ID_Start,
+ CR_Other_ID_Continue,
+ CR_ID_Compat_Math_Continue,
+ CR_ID_Compat_Math_Start,
+ CR_Sentence_Terminal,
+ CR_Variation_Selector,
+ CR_Pattern_White_Space,
+ CR_Pattern_Syntax,
+ CR_Prepended_Concatenation_Mark,
+ CR_Regional_Indicator,
+ CR_Modifier_Combining_Mark,
+ CR_Emoji,
+ CR_Emoji_Presentation,
+ CR_Emoji_Modifier,
+ CR_Emoji_Modifier_Base,
+ CR_Emoji_Component,
+ CR_Extended_Pictographic,
+ CR_Unknown,
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ CR_Age_1_1,
+ CR_Age_2_0,
+ CR_Age_2_1,
+ CR_Age_3_0,
+ CR_Age_3_1,
+ CR_Age_3_2,
+ CR_Age_4_0,
+ CR_Age_4_1,
+ CR_Age_5_0,
+ CR_Age_5_1,
+ CR_Age_5_2,
+ CR_Age_6_0,
+ CR_Age_6_1,
+ CR_Age_6_2,
+ CR_Age_6_3,
+ CR_Age_7_0,
+ CR_Age_8_0,
+ CR_Age_9_0,
+ CR_Age_10_0,
+ CR_Age_11_0,
+ CR_Age_12_0,
+ CR_Age_12_1,
+ CR_Age_13_0,
+ CR_Age_14_0,
+ CR_Age_15_0,
+ CR_Age_15_1,
+ CR_Age_16_0,
+ CR_Age_17_0,
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ CR_Grapheme_Cluster_Break_Prepend,
+ CR_Grapheme_Cluster_Break_CR,
+ CR_Grapheme_Cluster_Break_LF,
+ CR_Grapheme_Cluster_Break_Control,
+ CR_Grapheme_Cluster_Break_Extend,
+ CR_Grapheme_Cluster_Break_Regional_Indicator,
+ CR_Grapheme_Cluster_Break_SpacingMark,
+ CR_Grapheme_Cluster_Break_L,
+ CR_Grapheme_Cluster_Break_V,
+ CR_Grapheme_Cluster_Break_T,
+ CR_Grapheme_Cluster_Break_LV,
+ CR_Grapheme_Cluster_Break_LVT,
+ CR_Grapheme_Cluster_Break_ZWJ,
+ CR_In_Basic_Latin,
+ CR_In_Latin_1_Supplement,
+ CR_In_Latin_Extended_A,
+ CR_In_Latin_Extended_B,
+ CR_In_IPA_Extensions,
+ CR_In_Spacing_Modifier_Letters,
+ CR_In_Combining_Diacritical_Marks,
+ CR_In_Greek_and_Coptic,
+ CR_In_Cyrillic,
+ CR_In_Cyrillic_Supplement,
+ CR_In_Armenian,
+ CR_In_Hebrew,
+ CR_In_Arabic,
+ CR_In_Syriac,
+ CR_In_Arabic_Supplement,
+ CR_In_Thaana,
+ CR_In_NKo,
+ CR_In_Samaritan,
+ CR_In_Mandaic,
+ CR_In_Syriac_Supplement,
+ CR_In_Arabic_Extended_B,
+ CR_In_Arabic_Extended_A,
+ CR_In_Devanagari,
+ CR_In_Bengali,
+ CR_In_Gurmukhi,
+ CR_In_Gujarati,
+ CR_In_Oriya,
+ CR_In_Tamil,
+ CR_In_Telugu,
+ CR_In_Kannada,
+ CR_In_Malayalam,
+ CR_In_Sinhala,
+ CR_In_Thai,
+ CR_In_Lao,
+ CR_In_Tibetan,
+ CR_In_Myanmar,
+ CR_In_Georgian,
+ CR_In_Hangul_Jamo,
+ CR_In_Ethiopic,
+ CR_In_Ethiopic_Supplement,
+ CR_In_Cherokee,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics,
+ CR_In_Ogham,
+ CR_In_Runic,
+ CR_In_Tagalog,
+ CR_In_Hanunoo,
+ CR_In_Buhid,
+ CR_In_Tagbanwa,
+ CR_In_Khmer,
+ CR_In_Mongolian,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended,
+ CR_In_Limbu,
+ CR_In_Tai_Le,
+ CR_In_New_Tai_Lue,
+ CR_In_Khmer_Symbols,
+ CR_In_Buginese,
+ CR_In_Tai_Tham,
+ CR_In_Combining_Diacritical_Marks_Extended,
+ CR_In_Balinese,
+ CR_In_Sundanese,
+ CR_In_Batak,
+ CR_In_Lepcha,
+ CR_In_Ol_Chiki,
+ CR_In_Cyrillic_Extended_C,
+ CR_In_Georgian_Extended,
+ CR_In_Sundanese_Supplement,
+ CR_In_Vedic_Extensions,
+ CR_In_Phonetic_Extensions,
+ CR_In_Phonetic_Extensions_Supplement,
+ CR_In_Combining_Diacritical_Marks_Supplement,
+ CR_In_Latin_Extended_Additional,
+ CR_In_Greek_Extended,
+ CR_In_General_Punctuation,
+ CR_In_Superscripts_and_Subscripts,
+ CR_In_Currency_Symbols,
+ CR_In_Combining_Diacritical_Marks_for_Symbols,
+ CR_In_Letterlike_Symbols,
+ CR_In_Number_Forms,
+ CR_In_Arrows,
+ CR_In_Mathematical_Operators,
+ CR_In_Miscellaneous_Technical,
+ CR_In_Control_Pictures,
+ CR_In_Optical_Character_Recognition,
+ CR_In_Enclosed_Alphanumerics,
+ CR_In_Box_Drawing,
+ CR_In_Block_Elements,
+ CR_In_Geometric_Shapes,
+ CR_In_Miscellaneous_Symbols,
+ CR_In_Dingbats,
+ CR_In_Miscellaneous_Mathematical_Symbols_A,
+ CR_In_Supplemental_Arrows_A,
+ CR_In_Braille_Patterns,
+ CR_In_Supplemental_Arrows_B,
+ CR_In_Miscellaneous_Mathematical_Symbols_B,
+ CR_In_Supplemental_Mathematical_Operators,
+ CR_In_Miscellaneous_Symbols_and_Arrows,
+ CR_In_Glagolitic,
+ CR_In_Latin_Extended_C,
+ CR_In_Coptic,
+ CR_In_Georgian_Supplement,
+ CR_In_Tifinagh,
+ CR_In_Ethiopic_Extended,
+ CR_In_Cyrillic_Extended_A,
+ CR_In_Supplemental_Punctuation,
+ CR_In_CJK_Radicals_Supplement,
+ CR_In_Kangxi_Radicals,
+ CR_In_Ideographic_Description_Characters,
+ CR_In_CJK_Symbols_and_Punctuation,
+ CR_In_Hiragana,
+ CR_In_Katakana,
+ CR_In_Bopomofo,
+ CR_In_Hangul_Compatibility_Jamo,
+ CR_In_Kanbun,
+ CR_In_Bopomofo_Extended,
+ CR_In_CJK_Strokes,
+ CR_In_Katakana_Phonetic_Extensions,
+ CR_In_Enclosed_CJK_Letters_and_Months,
+ CR_In_CJK_Compatibility,
+ CR_In_CJK_Unified_Ideographs_Extension_A,
+ CR_In_Yijing_Hexagram_Symbols,
+ CR_In_CJK_Unified_Ideographs,
+ CR_In_Yi_Syllables,
+ CR_In_Yi_Radicals,
+ CR_In_Lisu,
+ CR_In_Vai,
+ CR_In_Cyrillic_Extended_B,
+ CR_In_Bamum,
+ CR_In_Modifier_Tone_Letters,
+ CR_In_Latin_Extended_D,
+ CR_In_Syloti_Nagri,
+ CR_In_Common_Indic_Number_Forms,
+ CR_In_Phags_pa,
+ CR_In_Saurashtra,
+ CR_In_Devanagari_Extended,
+ CR_In_Kayah_Li,
+ CR_In_Rejang,
+ CR_In_Hangul_Jamo_Extended_A,
+ CR_In_Javanese,
+ CR_In_Myanmar_Extended_B,
+ CR_In_Cham,
+ CR_In_Myanmar_Extended_A,
+ CR_In_Tai_Viet,
+ CR_In_Meetei_Mayek_Extensions,
+ CR_In_Ethiopic_Extended_A,
+ CR_In_Latin_Extended_E,
+ CR_In_Cherokee_Supplement,
+ CR_In_Meetei_Mayek,
+ CR_In_Hangul_Syllables,
+ CR_In_Hangul_Jamo_Extended_B,
+ CR_In_High_Surrogates,
+ CR_In_High_Private_Use_Surrogates,
+ CR_In_Low_Surrogates,
+ CR_In_Private_Use_Area,
+ CR_In_CJK_Compatibility_Ideographs,
+ CR_In_Alphabetic_Presentation_Forms,
+ CR_In_Arabic_Presentation_Forms_A,
+ CR_In_Variation_Selectors,
+ CR_In_Vertical_Forms,
+ CR_In_Combining_Half_Marks,
+ CR_In_CJK_Compatibility_Forms,
+ CR_In_Small_Form_Variants,
+ CR_In_Arabic_Presentation_Forms_B,
+ CR_In_Halfwidth_and_Fullwidth_Forms,
+ CR_In_Specials,
+ CR_In_Linear_B_Syllabary,
+ CR_In_Linear_B_Ideograms,
+ CR_In_Aegean_Numbers,
+ CR_In_Ancient_Greek_Numbers,
+ CR_In_Ancient_Symbols,
+ CR_In_Phaistos_Disc,
+ CR_In_Lycian,
+ CR_In_Carian,
+ CR_In_Coptic_Epact_Numbers,
+ CR_In_Old_Italic,
+ CR_In_Gothic,
+ CR_In_Old_Permic,
+ CR_In_Ugaritic,
+ CR_In_Old_Persian,
+ CR_In_Deseret,
+ CR_In_Shavian,
+ CR_In_Osmanya,
+ CR_In_Osage,
+ CR_In_Elbasan,
+ CR_In_Caucasian_Albanian,
+ CR_In_Vithkuqi,
+ CR_In_Todhri,
+ CR_In_Linear_A,
+ CR_In_Latin_Extended_F,
+ CR_In_Cypriot_Syllabary,
+ CR_In_Imperial_Aramaic,
+ CR_In_Palmyrene,
+ CR_In_Nabataean,
+ CR_In_Hatran,
+ CR_In_Phoenician,
+ CR_In_Lydian,
+ CR_In_Sidetic,
+ CR_In_Meroitic_Hieroglyphs,
+ CR_In_Meroitic_Cursive,
+ CR_In_Kharoshthi,
+ CR_In_Old_South_Arabian,
+ CR_In_Old_North_Arabian,
+ CR_In_Manichaean,
+ CR_In_Avestan,
+ CR_In_Inscriptional_Parthian,
+ CR_In_Inscriptional_Pahlavi,
+ CR_In_Psalter_Pahlavi,
+ CR_In_Old_Turkic,
+ CR_In_Old_Hungarian,
+ CR_In_Hanifi_Rohingya,
+ CR_In_Garay,
+ CR_In_Rumi_Numeral_Symbols,
+ CR_In_Yezidi,
+ CR_In_Arabic_Extended_C,
+ CR_In_Old_Sogdian,
+ CR_In_Sogdian,
+ CR_In_Old_Uyghur,
+ CR_In_Chorasmian,
+ CR_In_Elymaic,
+ CR_In_Brahmi,
+ CR_In_Kaithi,
+ CR_In_Sora_Sompeng,
+ CR_In_Chakma,
+ CR_In_Mahajani,
+ CR_In_Sharada,
+ CR_In_Sinhala_Archaic_Numbers,
+ CR_In_Khojki,
+ CR_In_Multani,
+ CR_In_Khudawadi,
+ CR_In_Grantha,
+ CR_In_Tulu_Tigalari,
+ CR_In_Newa,
+ CR_In_Tirhuta,
+ CR_In_Siddham,
+ CR_In_Modi,
+ CR_In_Mongolian_Supplement,
+ CR_In_Takri,
+ CR_In_Myanmar_Extended_C,
+ CR_In_Ahom,
+ CR_In_Dogra,
+ CR_In_Warang_Citi,
+ CR_In_Dives_Akuru,
+ CR_In_Nandinagari,
+ CR_In_Zanabazar_Square,
+ CR_In_Soyombo,
+ CR_In_Unified_Canadian_Aboriginal_Syllabics_Extended_A,
+ CR_In_Pau_Cin_Hau,
+ CR_In_Devanagari_Extended_A,
+ CR_In_Sharada_Supplement,
+ CR_In_Sunuwar,
+ CR_In_Bhaiksuki,
+ CR_In_Marchen,
+ CR_In_Masaram_Gondi,
+ CR_In_Gunjala_Gondi,
+ CR_In_Tolong_Siki,
+ CR_In_Makasar,
+ CR_In_Kawi,
+ CR_In_Lisu_Supplement,
+ CR_In_Tamil_Supplement,
+ CR_In_Cuneiform,
+ CR_In_Cuneiform_Numbers_and_Punctuation,
+ CR_In_Early_Dynastic_Cuneiform,
+ CR_In_Cypro_Minoan,
+ CR_In_Egyptian_Hieroglyphs,
+ CR_In_Egyptian_Hieroglyph_Format_Controls,
+ CR_In_Egyptian_Hieroglyphs_Extended_A,
+ CR_In_Anatolian_Hieroglyphs,
+ CR_In_Gurung_Khema,
+ CR_In_Bamum_Supplement,
+ CR_In_Mro,
+ CR_In_Tangsa,
+ CR_In_Bassa_Vah,
+ CR_In_Pahawh_Hmong,
+ CR_In_Kirat_Rai,
+ CR_In_Medefaidrin,
+ CR_In_Beria_Erfe,
+ CR_In_Miao,
+ CR_In_Ideographic_Symbols_and_Punctuation,
+ CR_In_Tangut,
+ CR_In_Tangut_Components,
+ CR_In_Khitan_Small_Script,
+ CR_In_Tangut_Supplement,
+ CR_In_Tangut_Components_Supplement,
+ CR_In_Kana_Extended_B,
+ CR_In_Kana_Supplement,
+ CR_In_Kana_Extended_A,
+ CR_In_Small_Kana_Extension,
+ CR_In_Nushu,
+ CR_In_Duployan,
+ CR_In_Shorthand_Format_Controls,
+ CR_In_Symbols_for_Legacy_Computing_Supplement,
+ CR_In_Miscellaneous_Symbols_Supplement,
+ CR_In_Znamenny_Musical_Notation,
+ CR_In_Byzantine_Musical_Symbols,
+ CR_In_Musical_Symbols,
+ CR_In_Ancient_Greek_Musical_Notation,
+ CR_In_Kaktovik_Numerals,
+ CR_In_Mayan_Numerals,
+ CR_In_Tai_Xuan_Jing_Symbols,
+ CR_In_Counting_Rod_Numerals,
+ CR_In_Mathematical_Alphanumeric_Symbols,
+ CR_In_Sutton_SignWriting,
+ CR_In_Latin_Extended_G,
+ CR_In_Glagolitic_Supplement,
+ CR_In_Cyrillic_Extended_D,
+ CR_In_Nyiakeng_Puachue_Hmong,
+ CR_In_Toto,
+ CR_In_Wancho,
+ CR_In_Nag_Mundari,
+ CR_In_Ol_Onal,
+ CR_In_Tai_Yo,
+ CR_In_Ethiopic_Extended_B,
+ CR_In_Mende_Kikakui,
+ CR_In_Adlam,
+ CR_In_Indic_Siyaq_Numbers,
+ CR_In_Ottoman_Siyaq_Numbers,
+ CR_In_Arabic_Mathematical_Alphabetic_Symbols,
+ CR_In_Mahjong_Tiles,
+ CR_In_Domino_Tiles,
+ CR_In_Playing_Cards,
+ CR_In_Enclosed_Alphanumeric_Supplement,
+ CR_In_Enclosed_Ideographic_Supplement,
+ CR_In_Miscellaneous_Symbols_and_Pictographs,
+ CR_In_Emoticons,
+ CR_In_Ornamental_Dingbats,
+ CR_In_Transport_and_Map_Symbols,
+ CR_In_Alchemical_Symbols,
+ CR_In_Geometric_Shapes_Extended,
+ CR_In_Supplemental_Arrows_C,
+ CR_In_Supplemental_Symbols_and_Pictographs,
+ CR_In_Chess_Symbols,
+ CR_In_Symbols_and_Pictographs_Extended_A,
+ CR_In_Symbols_for_Legacy_Computing,
+ CR_In_CJK_Unified_Ideographs_Extension_B,
+ CR_In_CJK_Unified_Ideographs_Extension_C,
+ CR_In_CJK_Unified_Ideographs_Extension_D,
+ CR_In_CJK_Unified_Ideographs_Extension_E,
+ CR_In_CJK_Unified_Ideographs_Extension_F,
+ CR_In_CJK_Unified_Ideographs_Extension_I,
+ CR_In_CJK_Compatibility_Ideographs_Supplement,
+ CR_In_CJK_Unified_Ideographs_Extension_G,
+ CR_In_CJK_Unified_Ideographs_Extension_H,
+ CR_In_CJK_Unified_Ideographs_Extension_J,
+ CR_In_Tags,
+ CR_In_Variation_Selectors_Supplement,
+ CR_In_Supplementary_Private_Use_Area_A,
+ CR_In_Supplementary_Private_Use_Area_B,
+ CR_In_No_Block,
+#endif /* USE_UNICODE_PROPERTIES */
+};
+struct uniname2ctype_struct {
+ short name;
+ unsigned short ctype;
+};
+#define uniname2ctype_offset(str) offsetof(struct uniname2ctype_pool_t, uniname2ctype_pool_##str)
+
+static const struct uniname2ctype_struct *uniname2ctype_p(register const char *str, register size_t len);
+
+#ifndef USE_UNICODE_PROPERTIES
+#define TOTAL_KEYWORDS 15
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 11
+#define MIN_HASH_VALUE 6
+#define MAX_HASH_VALUE 20
+/* maximum key range = 15, duplicates = 0 */
+#else /* USE_UNICODE_PROPERTIES */
+#ifndef USE_UNICODE_AGE_PROPERTIES
+#define TOTAL_KEYWORDS 916
+#else /* USE_UNICODE_AGE_PROPERTIES */
+#define TOTAL_KEYWORDS 944
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+#define MIN_WORD_LENGTH 1
+#define MAX_WORD_LENGTH 45
+#define MIN_HASH_VALUE 10
+#define MAX_HASH_VALUE 6068
+/* maximum key range = 6059, duplicates = 0 */
+#endif /* USE_UNICODE_PROPERTIES */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+uniname2ctype_hash (register const char *str, register size_t len)
+{
+#ifndef USE_UNICODE_PROPERTIES
+ static const unsigned char asso_values[] =
+#else /* USE_UNICODE_PROPERTIES */
+ static const unsigned short asso_values[] =
+#endif /* USE_UNICODE_PROPERTIES */
+ {
+#ifndef USE_UNICODE_PROPERTIES
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 3, 12, 5,
+ 4, 21, 21, 10, 21, 1, 21, 21, 11, 21,
+ 2, 1, 1, 21, 1, 7, 4, 6, 21, 1,
+ 4, 21, 21, 21, 21, 21, 21, 21
+#else /* USE_UNICODE_PROPERTIES */
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ 6069, 6069, 6069, 6069, 6069, 6069, 8, 6069, 2, 1,
+ 4, 31, 11, 20, 27, 15, 23, 17, 6069, 6069,
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ 6069, 1, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069, 6069,
+ 6069, 6069, 6069, 6069, 6069, 6069, 6069, 22, 28, 165,
+ 250, 131, 1160, 1288, 949, 4, 12, 1918, 452, 7,
+ 8, 1, 756, 2041, 623, 20, 68, 1025, 1509, 246,
+ 1475, 944, 814, 2, 6069, 6069, 6069, 6069, 6069
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+#ifndef USE_UNICODE_PROPERTIES
+ return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]];
+#else /* USE_UNICODE_PROPERTIES */
+ register unsigned int hval = (unsigned int)len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[15]];
+ /*FALLTHROUGH*/
+ case 15:
+ case 14:
+ case 13:
+ case 12:
+ hval += asso_values[(unsigned char)str[11]];
+ /*FALLTHROUGH*/
+ case 11:
+ case 10:
+ case 9:
+ case 8:
+ case 7:
+ case 6:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ hval += asso_values[(unsigned char)str[4]];
+ /*FALLTHROUGH*/
+ case 4:
+ case 3:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ hval += asso_values[(unsigned char)str[1]+1];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]+1];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+#endif /* USE_UNICODE_PROPERTIES */
+}
+
+struct uniname2ctype_pool_t
+ {
+#ifndef USE_UNICODE_PROPERTIES
+ char uniname2ctype_pool_str6[sizeof("word")];
+ char uniname2ctype_pool_str7[sizeof("print")];
+ char uniname2ctype_pool_str8[sizeof("punct")];
+ char uniname2ctype_pool_str9[sizeof("alpha")];
+ char uniname2ctype_pool_str10[sizeof("alnum")];
+ char uniname2ctype_pool_str11[sizeof("xdigit")];
+ char uniname2ctype_pool_str12[sizeof("upper")];
+ char uniname2ctype_pool_str13[sizeof("ascii")];
+ char uniname2ctype_pool_str14[sizeof("cntrl")];
+ char uniname2ctype_pool_str15[sizeof("space")];
+ char uniname2ctype_pool_str16[sizeof("xposixpunct")];
+ char uniname2ctype_pool_str17[sizeof("lower")];
+ char uniname2ctype_pool_str18[sizeof("graph")];
+ char uniname2ctype_pool_str19[sizeof("digit")];
+ char uniname2ctype_pool_str20[sizeof("blank")];
+#else /* USE_UNICODE_PROPERTIES */
+ char uniname2ctype_pool_str10[sizeof("n")];
+ char uniname2ctype_pool_str16[sizeof("m")];
+ char uniname2ctype_pool_str19[sizeof("mn")];
+ char uniname2ctype_pool_str24[sizeof("lm")];
+ char uniname2ctype_pool_str27[sizeof("inmro")];
+ char uniname2ctype_pool_str28[sizeof("innko")];
+ char uniname2ctype_pool_str33[sizeof("mro")];
+ char uniname2ctype_pool_str34[sizeof("mroo")];
+ char uniname2ctype_pool_str38[sizeof("ri")];
+ char uniname2ctype_pool_str40[sizeof("lao")];
+ char uniname2ctype_pool_str41[sizeof("laoo")];
+ char uniname2ctype_pool_str44[sizeof("ahom")];
+ char uniname2ctype_pool_str45[sizeof("hano")];
+ char uniname2ctype_pool_str47[sizeof("miao")];
+ char uniname2ctype_pool_str48[sizeof("hani")];
+ char uniname2ctype_pool_str50[sizeof("inmiao")];
+ char uniname2ctype_pool_str51[sizeof("han")];
+ char uniname2ctype_pool_str52[sizeof("mani")];
+ char uniname2ctype_pool_str53[sizeof("lina")];
+ char uniname2ctype_pool_str56[sizeof("inahom")];
+ char uniname2ctype_pool_str57[sizeof("hanunoo")];
+ char uniname2ctype_pool_str58[sizeof("limb")];
+ char uniname2ctype_pool_str59[sizeof("linb")];
+ char uniname2ctype_pool_str60[sizeof("inmanichaean")];
+ char uniname2ctype_pool_str62[sizeof("alnum")];
+ char uniname2ctype_pool_str63[sizeof("armi")];
+ char uniname2ctype_pool_str64[sizeof("nandinagari")];
+ char uniname2ctype_pool_str67[sizeof("armn")];
+ char uniname2ctype_pool_str69[sizeof("lana")];
+ char uniname2ctype_pool_str70[sizeof("zanb")];
+ char uniname2ctype_pool_str74[sizeof("inosmanya")];
+ char uniname2ctype_pool_str81[sizeof("insamaritan")];
+ char uniname2ctype_pool_str82[sizeof("inbhaiksuki")];
+ char uniname2ctype_pool_str83[sizeof("armenian")];
+ char uniname2ctype_pool_str85[sizeof("sm")];
+ char uniname2ctype_pool_str88[sizeof("inmasaramgondi")];
+ char uniname2ctype_pool_str89[sizeof("s")];
+ char uniname2ctype_pool_str90[sizeof("innabataean")];
+ char uniname2ctype_pool_str92[sizeof("zs")];
+ char uniname2ctype_pool_str93[sizeof("inbasiclatin")];
+ char uniname2ctype_pool_str96[sizeof("innumberforms")];
+ char uniname2ctype_pool_str102[sizeof("arab")];
+ char uniname2ctype_pool_str107[sizeof("inmusicalsymbols")];
+ char uniname2ctype_pool_str115[sizeof("latn")];
+ char uniname2ctype_pool_str117[sizeof("inthai")];
+ char uniname2ctype_pool_str124[sizeof("latin")];
+ char uniname2ctype_pool_str135[sizeof("shavian")];
+ char uniname2ctype_pool_str141[sizeof("initialpunctuation")];
+ char uniname2ctype_pool_str144[sizeof("hatran")];
+ char uniname2ctype_pool_str149[sizeof("di")];
+ char uniname2ctype_pool_str155[sizeof("inthaana")];
+ char uniname2ctype_pool_str157[sizeof("intoto")];
+ char uniname2ctype_pool_str164[sizeof("nabataean")];
+ char uniname2ctype_pool_str169[sizeof("intaitham")];
+ char uniname2ctype_pool_str175[sizeof("inarabicpresentationformsa")];
+ char uniname2ctype_pool_str180[sizeof("inbraillepatterns")];
+ char uniname2ctype_pool_str181[sizeof("inarabicpresentationformsb")];
+ char uniname2ctype_pool_str186[sizeof("ids")];
+ char uniname2ctype_pool_str190[sizeof("dia")];
+ char uniname2ctype_pool_str191[sizeof("inarmenian")];
+ char uniname2ctype_pool_str195[sizeof("idsb")];
+ char uniname2ctype_pool_str199[sizeof("intransportandmapsymbols")];
+ char uniname2ctype_pool_str202[sizeof("inideographicsymbolsandpunctuation")];
+ char uniname2ctype_pool_str203[sizeof("inavestan")];
+ char uniname2ctype_pool_str209[sizeof("inipaextensions")];
+ char uniname2ctype_pool_str211[sizeof("inelbasan")];
+ char uniname2ctype_pool_str213[sizeof("inopticalcharacterrecognition")];
+ char uniname2ctype_pool_str215[sizeof("brai")];
+ char uniname2ctype_pool_str219[sizeof("bamum")];
+ char uniname2ctype_pool_str220[sizeof("incham")];
+ char uniname2ctype_pool_str227[sizeof("inideographicdescriptioncharacters")];
+ char uniname2ctype_pool_str228[sizeof("brahmi")];
+ char uniname2ctype_pool_str235[sizeof("idst")];
+ char uniname2ctype_pool_str237[sizeof("bass")];
+ char uniname2ctype_pool_str242[sizeof("mandaic")];
+ char uniname2ctype_pool_str244[sizeof("inemoticons")];
+ char uniname2ctype_pool_str247[sizeof("incommonindicnumberforms")];
+ char uniname2ctype_pool_str257[sizeof("intibetan")];
+ char uniname2ctype_pool_str258[sizeof("inarabic")];
+ char uniname2ctype_pool_str260[sizeof("nbat")];
+ char uniname2ctype_pool_str261[sizeof("cn")];
+ char uniname2ctype_pool_str267[sizeof("inancientsymbols")];
+ char uniname2ctype_pool_str268[sizeof("ci")];
+ char uniname2ctype_pool_str274[sizeof("ascii")];
+ char uniname2ctype_pool_str275[sizeof("mcm")];
+ char uniname2ctype_pool_str279[sizeof("ideo")];
+ char uniname2ctype_pool_str284[sizeof("inmodi")];
+ char uniname2ctype_pool_str285[sizeof("vai")];
+ char uniname2ctype_pool_str286[sizeof("vaii")];
+ char uniname2ctype_pool_str287[sizeof("cham")];
+ char uniname2ctype_pool_str289[sizeof("inmyanmarextendeda")];
+ char uniname2ctype_pool_str291[sizeof("nand")];
+ char uniname2ctype_pool_str295[sizeof("inmyanmarextendedb")];
+ char uniname2ctype_pool_str298[sizeof("mand")];
+ char uniname2ctype_pool_str310[sizeof("cans")];
+ char uniname2ctype_pool_str312[sizeof("inoldsogdian")];
+ char uniname2ctype_pool_str315[sizeof("chorasmian")];
+ char uniname2ctype_pool_str317[sizeof("innewa")];
+ char uniname2ctype_pool_str333[sizeof("chakma")];
+ char uniname2ctype_pool_str335[sizeof("incuneiform")];
+ char uniname2ctype_pool_str336[sizeof("vs")];
+ char uniname2ctype_pool_str340[sizeof("cs")];
+ char uniname2ctype_pool_str342[sizeof("sind")];
+ char uniname2ctype_pool_str344[sizeof("shaw")];
+ char uniname2ctype_pool_str359[sizeof("inspecials")];
+ char uniname2ctype_pool_str364[sizeof("inchesssymbols")];
+ char uniname2ctype_pool_str366[sizeof("avst")];
+ char uniname2ctype_pool_str373[sizeof("inblockelements")];
+ char uniname2ctype_pool_str384[sizeof("nd")];
+ char uniname2ctype_pool_str395[sizeof("sharada")];
+ char uniname2ctype_pool_str398[sizeof("inmiscellaneoussymbols")];
+ char uniname2ctype_pool_str400[sizeof("inmiscellaneousmathematicalsymbolsa")];
+ char uniname2ctype_pool_str402[sizeof("sidt")];
+ char uniname2ctype_pool_str406[sizeof("inmiscellaneousmathematicalsymbolsb")];
+ char uniname2ctype_pool_str407[sizeof("inmiscellaneoussymbolsandarrows")];
+ char uniname2ctype_pool_str410[sizeof("arabic")];
+ char uniname2ctype_pool_str412[sizeof("inmiscellaneoussymbolsandpictographs")];
+ char uniname2ctype_pool_str416[sizeof("c")];
+ char uniname2ctype_pool_str424[sizeof("lc")];
+ char uniname2ctype_pool_str425[sizeof("mc")];
+ char uniname2ctype_pool_str426[sizeof("inmedefaidrin")];
+ char uniname2ctype_pool_str432[sizeof("inmyanmarextendedc")];
+ char uniname2ctype_pool_str433[sizeof("insundanese")];
+ char uniname2ctype_pool_str438[sizeof("indominotiles")];
+ char uniname2ctype_pool_str440[sizeof("insymbolsandpictographsextendeda")];
+ char uniname2ctype_pool_str441[sizeof("inwancho")];
+ char uniname2ctype_pool_str444[sizeof("inolditalic")];
+ char uniname2ctype_pool_str447[sizeof("inmodifiertoneletters")];
+ char uniname2ctype_pool_str448[sizeof("incb=consonant")];
+ char uniname2ctype_pool_str451[sizeof("sd")];
+ char uniname2ctype_pool_str452[sizeof("inmandaic")];
+ char uniname2ctype_pool_str456[sizeof("inmiscellaneoussymbolssupplement")];
+ char uniname2ctype_pool_str458[sizeof("nko")];
+ char uniname2ctype_pool_str459[sizeof("nkoo")];
+ char uniname2ctype_pool_str460[sizeof("l")];
+ char uniname2ctype_pool_str461[sizeof("inmeeteimayekextensions")];
+ char uniname2ctype_pool_str462[sizeof("nl")];
+ char uniname2ctype_pool_str463[sizeof("zl")];
+ char uniname2ctype_pool_str468[sizeof("ll")];
+ char uniname2ctype_pool_str472[sizeof("inlao")];
+ char uniname2ctype_pool_str473[sizeof("khoj")];
+ char uniname2ctype_pool_str476[sizeof("idc")];
+ char uniname2ctype_pool_str477[sizeof("innewtailue")];
+ char uniname2ctype_pool_str483[sizeof("inolonal")];
+ char uniname2ctype_pool_str485[sizeof("sc")];
+ char uniname2ctype_pool_str491[sizeof("indeseret")];
+ char uniname2ctype_pool_str496[sizeof("incuneiformnumbersandpunctuation")];
+ char uniname2ctype_pool_str502[sizeof("krai")];
+ char uniname2ctype_pool_str505[sizeof("inarabicextendeda")];
+ char uniname2ctype_pool_str508[sizeof("inoldturkic")];
+ char uniname2ctype_pool_str510[sizeof("avestan")];
+ char uniname2ctype_pool_str511[sizeof("inarabicextendedb")];
+ char uniname2ctype_pool_str512[sizeof("inmalayalam")];
+ char uniname2ctype_pool_str513[sizeof("kharoshthi")];
+ char uniname2ctype_pool_str514[sizeof("kana")];
+ char uniname2ctype_pool_str523[sizeof("inadlam")];
+ char uniname2ctype_pool_str525[sizeof("idcontinue")];
+ char uniname2ctype_pool_str549[sizeof("insiddham")];
+ char uniname2ctype_pool_str551[sizeof("intamil")];
+ char uniname2ctype_pool_str553[sizeof("inmultani")];
+ char uniname2ctype_pool_str554[sizeof("intolongsiki")];
+ char uniname2ctype_pool_str556[sizeof("kits")];
+ char uniname2ctype_pool_str571[sizeof("incb=extend")];
+ char uniname2ctype_pool_str574[sizeof("sidetic")];
+ char uniname2ctype_pool_str584[sizeof("sidd")];
+ char uniname2ctype_pool_str587[sizeof("incontrolpictures")];
+ char uniname2ctype_pool_str588[sizeof("insidetic")];
+ char uniname2ctype_pool_str591[sizeof("sinhala")];
+ char uniname2ctype_pool_str605[sizeof("inlatinextendeda")];
+ char uniname2ctype_pool_str617[sizeof("inlatinextendedb")];
+ char uniname2ctype_pool_str622[sizeof("adlm")];
+ char uniname2ctype_pool_str630[sizeof("adlam")];
+ char uniname2ctype_pool_str635[sizeof("inlineara")];
+ char uniname2ctype_pool_str637[sizeof("intamilsupplement")];
+ char uniname2ctype_pool_str638[sizeof("inbalinese")];
+ char uniname2ctype_pool_str645[sizeof("inspacingmodifierletters")];
+ char uniname2ctype_pool_str648[sizeof("inarabicextendedc")];
+ char uniname2ctype_pool_str650[sizeof("inlycian")];
+ char uniname2ctype_pool_str653[sizeof("bali")];
+ char uniname2ctype_pool_str665[sizeof("hira")];
+ char uniname2ctype_pool_str667[sizeof("cc")];
+ char uniname2ctype_pool_str674[sizeof("insmallkanaextension")];
+ char uniname2ctype_pool_str675[sizeof("intaile")];
+ char uniname2ctype_pool_str681[sizeof("qaai")];
+ char uniname2ctype_pool_str682[sizeof("inmyanmar")];
+ char uniname2ctype_pool_str684[sizeof("narb")];
+ char uniname2ctype_pool_str687[sizeof("inarrows")];
+ char uniname2ctype_pool_str701[sizeof("lineara")];
+ char uniname2ctype_pool_str707[sizeof("linearb")];
+ char uniname2ctype_pool_str709[sizeof("insharada")];
+ char uniname2ctype_pool_str716[sizeof("inruminumeralsymbols")];
+ char uniname2ctype_pool_str721[sizeof("masaramgondi")];
+ char uniname2ctype_pool_str727[sizeof("hatr")];
+ char uniname2ctype_pool_str729[sizeof("knda")];
+ char uniname2ctype_pool_str730[sizeof("samr")];
+ char uniname2ctype_pool_str734[sizeof("kawi")];
+ char uniname2ctype_pool_str735[sizeof("inlydian")];
+ char uniname2ctype_pool_str747[sizeof("samaritan")];
+ char uniname2ctype_pool_str751[sizeof("sarb")];
+ char uniname2ctype_pool_str760[sizeof("no")];
+ char uniname2ctype_pool_str762[sizeof("bidic")];
+ char uniname2ctype_pool_str766[sizeof("lo")];
+ char uniname2ctype_pool_str780[sizeof("hmnp")];
+ char uniname2ctype_pool_str784[sizeof("onao")];
+ char uniname2ctype_pool_str788[sizeof("inlowsurrogates")];
+ char uniname2ctype_pool_str789[sizeof("kannada")];
+ char uniname2ctype_pool_str795[sizeof("inlinearbideograms")];
+ char uniname2ctype_pool_str799[sizeof("inletterlikesymbols")];
+ char uniname2ctype_pool_str803[sizeof("cased")];
+ char uniname2ctype_pool_str809[sizeof("inbopomofo")];
+ char uniname2ctype_pool_str810[sizeof("inberiaerfe")];
+ char uniname2ctype_pool_str815[sizeof("lineseparator")];
+ char uniname2ctype_pool_str817[sizeof("z")];
+ char uniname2ctype_pool_str818[sizeof("insymbolsforlegacycomputingsupplement")];
+ char uniname2ctype_pool_str820[sizeof("inrunic")];
+ char uniname2ctype_pool_str821[sizeof("incarian")];
+ char uniname2ctype_pool_str823[sizeof("inlatinextendede")];
+ char uniname2ctype_pool_str825[sizeof("inmarchen")];
+ char uniname2ctype_pool_str827[sizeof("so")];
+ char uniname2ctype_pool_str828[sizeof("marc")];
+ char uniname2ctype_pool_str829[sizeof("oriya")];
+ char uniname2ctype_pool_str830[sizeof("inchorasmian")];
+ char uniname2ctype_pool_str832[sizeof("yi")];
+ char uniname2ctype_pool_str833[sizeof("insyriac")];
+ char uniname2ctype_pool_str838[sizeof("yiii")];
+ char uniname2ctype_pool_str840[sizeof("alpha")];
+ char uniname2ctype_pool_str842[sizeof("qaac")];
+ char uniname2ctype_pool_str852[sizeof("insundanesesupplement")];
+ char uniname2ctype_pool_str857[sizeof("osma")];
+ char uniname2ctype_pool_str880[sizeof("inmiscellaneoustechnical")];
+ char uniname2ctype_pool_str883[sizeof("idstart")];
+ char uniname2ctype_pool_str890[sizeof("inenclosedcjklettersandmonths")];
+ char uniname2ctype_pool_str891[sizeof("inlatinextendedc")];
+ char uniname2ctype_pool_str894[sizeof("dsrt")];
+ char uniname2ctype_pool_str898[sizeof("odi")];
+ char uniname2ctype_pool_str901[sizeof("chrs")];
+ char uniname2ctype_pool_str909[sizeof("cari")];
+ char uniname2ctype_pool_str919[sizeof("innandinagari")];
+ char uniname2ctype_pool_str923[sizeof("balinese")];
+ char uniname2ctype_pool_str924[sizeof("inwarangciti")];
+ char uniname2ctype_pool_str929[sizeof("inphoenician")];
+ char uniname2ctype_pool_str940[sizeof("kali")];
+ char uniname2ctype_pool_str942[sizeof("inoldnortharabian")];
+ char uniname2ctype_pool_str944[sizeof("radical")];
+ char uniname2ctype_pool_str945[sizeof("carian")];
+ char uniname2ctype_pool_str947[sizeof("idsbinaryoperator")];
+ char uniname2ctype_pool_str949[sizeof("shrd")];
+ char uniname2ctype_pool_str954[sizeof("inoldsoutharabian")];
+ char uniname2ctype_pool_str966[sizeof("diacritic")];
+ char uniname2ctype_pool_str970[sizeof("mlym")];
+ char uniname2ctype_pool_str975[sizeof("zinh")];
+ char uniname2ctype_pool_str978[sizeof("inphaistosdisc")];
+ char uniname2ctype_pool_str980[sizeof("incyrillic")];
+ char uniname2ctype_pool_str985[sizeof("ininscriptionalpahlavi")];
+ char uniname2ctype_pool_str988[sizeof("insoyombo")];
+ char uniname2ctype_pool_str990[sizeof("ininscriptionalparthian")];
+ char uniname2ctype_pool_str991[sizeof("inoriya")];
+ char uniname2ctype_pool_str994[sizeof("lyci")];
+ char uniname2ctype_pool_str999[sizeof("inogham")];
+ char uniname2ctype_pool_str1001[sizeof("mahj")];
+ char uniname2ctype_pool_str1003[sizeof("gran")];
+ char uniname2ctype_pool_str1005[sizeof("inmahajani")];
+ char uniname2ctype_pool_str1009[sizeof("co")];
+ char uniname2ctype_pool_str1012[sizeof("cher")];
+ char uniname2ctype_pool_str1016[sizeof("alphabetic")];
+ char uniname2ctype_pool_str1021[sizeof("insinhala")];
+ char uniname2ctype_pool_str1022[sizeof("modi")];
+ char uniname2ctype_pool_str1024[sizeof("inbrahmi")];
+ char uniname2ctype_pool_str1028[sizeof("loe")];
+ char uniname2ctype_pool_str1030[sizeof("lycian")];
+ char uniname2ctype_pool_str1031[sizeof("mahajani")];
+ char uniname2ctype_pool_str1036[sizeof("common")];
+ char uniname2ctype_pool_str1037[sizeof("intaiyo")];
+ char uniname2ctype_pool_str1038[sizeof("inhanifirohingya")];
+ char uniname2ctype_pool_str1040[sizeof("inbassavah")];
+ char uniname2ctype_pool_str1041[sizeof("sinh")];
+ char uniname2ctype_pool_str1042[sizeof("oids")];
+ char uniname2ctype_pool_str1044[sizeof("inlatinextendedadditional")];
+ char uniname2ctype_pool_str1045[sizeof("inyijinghexagramsymbols")];
+ char uniname2ctype_pool_str1048[sizeof("inoldpersian")];
+ char uniname2ctype_pool_str1056[sizeof("bidicontrol")];
+ char uniname2ctype_pool_str1057[sizeof("math")];
+ char uniname2ctype_pool_str1058[sizeof("inarabicsupplement")];
+ char uniname2ctype_pool_str1059[sizeof("thai")];
+ char uniname2ctype_pool_str1061[sizeof("inlatinextendedd")];
+ char uniname2ctype_pool_str1064[sizeof("taiyo")];
+ char uniname2ctype_pool_str1068[sizeof("lisu")];
+ char uniname2ctype_pool_str1072[sizeof("tnsa")];
+ char uniname2ctype_pool_str1073[sizeof("incherokee")];
+ char uniname2ctype_pool_str1077[sizeof("thaa")];
+ char uniname2ctype_pool_str1079[sizeof("lydi")];
+ char uniname2ctype_pool_str1087[sizeof("inbamum")];
+ char uniname2ctype_pool_str1090[sizeof("khmr")];
+ char uniname2ctype_pool_str1094[sizeof("inbyzantinemusicalsymbols")];
+ char uniname2ctype_pool_str1102[sizeof("lt")];
+ char uniname2ctype_pool_str1105[sizeof("khar")];
+ char uniname2ctype_pool_str1109[sizeof("thaana")];
+ char uniname2ctype_pool_str1113[sizeof("osage")];
+ char uniname2ctype_pool_str1115[sizeof("lydian")];
+ char uniname2ctype_pool_str1117[sizeof("inanatolianhieroglyphs")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1120[sizeof("age=11.0")];
+ char uniname2ctype_pool_str1121[sizeof("age=10.0")];
+ char uniname2ctype_pool_str1122[sizeof("age=12.1")];
+ char uniname2ctype_pool_str1123[sizeof("age=12.0")];
+ char uniname2ctype_pool_str1125[sizeof("age=1.1")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1126[sizeof("insylotinagri")];
+ char uniname2ctype_pool_str1127[sizeof("anatolianhieroglyphs")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1128[sizeof("age=2.1")];
+ char uniname2ctype_pool_str1129[sizeof("age=2.0")];
+ char uniname2ctype_pool_str1130[sizeof("age=14.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1131[sizeof("tangsa")];
+ char uniname2ctype_pool_str1132[sizeof("dash")];
+ char uniname2ctype_pool_str1133[sizeof("incombiningdiacriticalmarks")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1134[sizeof("age=17.0")];
+ char uniname2ctype_pool_str1135[sizeof("age=4.1")];
+ char uniname2ctype_pool_str1136[sizeof("age=4.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1137[sizeof("tibt")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1138[sizeof("age=15.1")];
+ char uniname2ctype_pool_str1139[sizeof("age=15.0")];
+ char uniname2ctype_pool_str1140[sizeof("age=7.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1141[sizeof("inolchiki")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1142[sizeof("age=9.0")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1143[sizeof("incombiningdiacriticalmarksforsymbols")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1144[sizeof("age=5.1")];
+ char uniname2ctype_pool_str1145[sizeof("age=5.0")];
+ char uniname2ctype_pool_str1146[sizeof("age=16.0")];
+ char uniname2ctype_pool_str1147[sizeof("age=5.2")];
+ char uniname2ctype_pool_str1148[sizeof("age=8.0")];
+ char uniname2ctype_pool_str1150[sizeof("age=13.0")];
+ char uniname2ctype_pool_str1151[sizeof("age=6.1")];
+ char uniname2ctype_pool_str1152[sizeof("age=6.0")];
+ char uniname2ctype_pool_str1154[sizeof("age=6.2")];
+ char uniname2ctype_pool_str1155[sizeof("age=3.1")];
+ char uniname2ctype_pool_str1156[sizeof("age=3.0")];
+ char uniname2ctype_pool_str1158[sizeof("age=3.2")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1159[sizeof("inarabicmathematicalalphabeticsymbols")];
+ char uniname2ctype_pool_str1160[sizeof("brah")];
+ char uniname2ctype_pool_str1170[sizeof("tibetan")];
+ char uniname2ctype_pool_str1172[sizeof("mtei")];
+ char uniname2ctype_pool_str1175[sizeof("incoptic")];
+ char uniname2ctype_pool_str1176[sizeof("manichaean")];
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ char uniname2ctype_pool_str1181[sizeof("age=6.3")];
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ char uniname2ctype_pool_str1182[sizeof("emoji")];
+ char uniname2ctype_pool_str1187[sizeof("oidc")];
+ char uniname2ctype_pool_str1191[sizeof("incombiningdiacriticalmarkssupplement")];
+ char uniname2ctype_pool_str1192[sizeof("idsu")];
+ char uniname2ctype_pool_str1195[sizeof("saurashtra")];
+ char uniname2ctype_pool_str1196[sizeof("inoldpermic")];
+ char uniname2ctype_pool_str1199[sizeof("closepunctuation")];
+ char uniname2ctype_pool_str1209[sizeof("incombininghalfmarks")];
+ char uniname2ctype_pool_str1214[sizeof("incopticepactnumbers")];
+ char uniname2ctype_pool_str1221[sizeof("elba")];
+ char uniname2ctype_pool_str1225[sizeof("xdigit")];
+ char uniname2ctype_pool_str1228[sizeof("cntrl")];
+ char uniname2ctype_pool_str1229[sizeof("bamu")];
+ char uniname2ctype_pool_str1230[sizeof("xids")];
+ char uniname2ctype_pool_str1239[sizeof("inoldhungarian")];
+ char uniname2ctype_pool_str1241[sizeof("grext")];
+ char uniname2ctype_pool_str1242[sizeof("mongolian")];
+ char uniname2ctype_pool_str1243[sizeof("sterm")];
+ char uniname2ctype_pool_str1249[sizeof("braille")];
+ char uniname2ctype_pool_str1251[sizeof("inbuhid")];
+ char uniname2ctype_pool_str1252[sizeof("elbasan")];
+ char uniname2ctype_pool_str1259[sizeof("zanabazarsquare")];
+ char uniname2ctype_pool_str1260[sizeof("incountingrodnumerals")];
+ char uniname2ctype_pool_str1264[sizeof("inenclosedalphanumerics")];
+ char uniname2ctype_pool_str1265[sizeof("incb=linker")];
+ char uniname2ctype_pool_str1267[sizeof("taiviet")];
+ char uniname2ctype_pool_str1269[sizeof("inelymaic")];
+ char uniname2ctype_pool_str1272[sizeof("inethiopic")];
+ char uniname2ctype_pool_str1275[sizeof("sgnw")];
+ char uniname2ctype_pool_str1277[sizeof("olditalic")];
+ char uniname2ctype_pool_str1279[sizeof("vith")];
+ char uniname2ctype_pool_str1285[sizeof("grbase")];
+ char uniname2ctype_pool_str1286[sizeof("hluw")];
+ char uniname2ctype_pool_str1292[sizeof("intodhri")];
+ char uniname2ctype_pool_str1299[sizeof("asciihexdigit")];
+ char uniname2ctype_pool_str1301[sizeof("me")];
+ char uniname2ctype_pool_str1312[sizeof("hmng")];
+ char uniname2ctype_pool_str1315[sizeof("siddham")];
+ char uniname2ctype_pool_str1321[sizeof("inenclosedalphanumericsupplement")];
+ char uniname2ctype_pool_str1324[sizeof("taile")];
+ char uniname2ctype_pool_str1328[sizeof("nagm")];
+ char uniname2ctype_pool_str1332[sizeof("hang")];
+ char uniname2ctype_pool_str1334[sizeof("inscriptionalparthian")];
+ char uniname2ctype_pool_str1335[sizeof("inmongolian")];
+ char uniname2ctype_pool_str1336[sizeof("innagmundari")];
+ char uniname2ctype_pool_str1339[sizeof("sylo")];
+ char uniname2ctype_pool_str1347[sizeof("ingunjalagondi")];
+ char uniname2ctype_pool_str1349[sizeof("ingujarati")];
+ char uniname2ctype_pool_str1350[sizeof("inbengali")];
+ char uniname2ctype_pool_str1351[sizeof("khitansmallscript")];
+ char uniname2ctype_pool_str1357[sizeof("xidcontinue")];
+ char uniname2ctype_pool_str1362[sizeof("ingrantha")];
+ char uniname2ctype_pool_str1363[sizeof("insinhalaarchaicnumbers")];
+ char uniname2ctype_pool_str1368[sizeof("connectorpunctuation")];
+ char uniname2ctype_pool_str1370[sizeof("inpalmyrene")];
+ char uniname2ctype_pool_str1371[sizeof("incombiningdiacriticalmarksextended")];
+ char uniname2ctype_pool_str1372[sizeof("xidstart")];
+ char uniname2ctype_pool_str1375[sizeof("xidc")];
+ char uniname2ctype_pool_str1397[sizeof("inancientgreekmusicalnotation")];
+ char uniname2ctype_pool_str1401[sizeof("inancientgreeknumbers")];
+ char uniname2ctype_pool_str1407[sizeof("intangsa")];
+ char uniname2ctype_pool_str1415[sizeof("intags")];
+ char uniname2ctype_pool_str1416[sizeof("inlepcha")];
+ char uniname2ctype_pool_str1420[sizeof("caucasianalbanian")];
+ char uniname2ctype_pool_str1421[sizeof("sylotinagri")];
+ char uniname2ctype_pool_str1423[sizeof("emod")];
+ char uniname2ctype_pool_str1425[sizeof("incaucasianalbanian")];
+ char uniname2ctype_pool_str1429[sizeof("intagbanwa")];
+ char uniname2ctype_pool_str1430[sizeof("mend")];
+ char uniname2ctype_pool_str1433[sizeof("newa")];
+ char uniname2ctype_pool_str1435[sizeof("inearlydynasticcuneiform")];
+ char uniname2ctype_pool_str1447[sizeof("kaithi")];
+ char uniname2ctype_pool_str1453[sizeof("intangut")];
+ char uniname2ctype_pool_str1456[sizeof("mymr")];
+ char uniname2ctype_pool_str1462[sizeof("inosage")];
+ char uniname2ctype_pool_str1467[sizeof("inmahjongtiles")];
+ char uniname2ctype_pool_str1470[sizeof("malayalam")];
+ char uniname2ctype_pool_str1473[sizeof("sora")];
+ char uniname2ctype_pool_str1474[sizeof("inbuginese")];
+ char uniname2ctype_pool_str1479[sizeof("emojimodifierbase")];
+ char uniname2ctype_pool_str1489[sizeof("induployan")];
+ char uniname2ctype_pool_str1497[sizeof("ingeometricshapes")];
+ char uniname2ctype_pool_str1498[sizeof("ingeneralpunctuation")];
+ char uniname2ctype_pool_str1503[sizeof("myanmar")];
+ char uniname2ctype_pool_str1510[sizeof("inlatin1supplement")];
+ char uniname2ctype_pool_str1515[sizeof("ital")];
+ char uniname2ctype_pool_str1516[sizeof("taml")];
+ char uniname2ctype_pool_str1517[sizeof("inaegeannumbers")];
+ char uniname2ctype_pool_str1528[sizeof("insharadasupplement")];
+ char uniname2ctype_pool_str1530[sizeof("mathsymbol")];
+ char uniname2ctype_pool_str1532[sizeof("inlimbu")];
+ char uniname2ctype_pool_str1535[sizeof("invai")];
+ char uniname2ctype_pool_str1551[sizeof("emojicomponent")];
+ char uniname2ctype_pool_str1552[sizeof("insuttonsignwriting")];
+ char uniname2ctype_pool_str1572[sizeof("digit")];
+ char uniname2ctype_pool_str1573[sizeof("newtailue")];
+ char uniname2ctype_pool_str1581[sizeof("inshavian")];
+ char uniname2ctype_pool_str1588[sizeof("insogdian")];
+ char uniname2ctype_pool_str1589[sizeof("indingbats")];
+ char uniname2ctype_pool_str1590[sizeof("imperialaramaic")];
+ char uniname2ctype_pool_str1598[sizeof("intulutigalari")];
+ char uniname2ctype_pool_str1600[sizeof("incyprominoan")];
+ char uniname2ctype_pool_str1606[sizeof("glagolitic")];
+ char uniname2ctype_pool_str1614[sizeof("ebase")];
+ char uniname2ctype_pool_str1615[sizeof("intaixuanjingsymbols")];
+ char uniname2ctype_pool_str1618[sizeof("inbamumsupplement")];
+ char uniname2ctype_pool_str1626[sizeof("gara")];
+ char uniname2ctype_pool_str1633[sizeof("insyriacsupplement")];
+ char uniname2ctype_pool_str1634[sizeof("casedletter")];
+ char uniname2ctype_pool_str1636[sizeof("zzzz")];
+ char uniname2ctype_pool_str1639[sizeof("inhiragana")];
+ char uniname2ctype_pool_str1640[sizeof("tale")];
+ char uniname2ctype_pool_str1641[sizeof("canadianaboriginal")];
+ char uniname2ctype_pool_str1642[sizeof("ahex")];
+ char uniname2ctype_pool_str1644[sizeof("inmayannumerals")];
+ char uniname2ctype_pool_str1648[sizeof("inzanabazarsquare")];
+ char uniname2ctype_pool_str1654[sizeof("inyiradicals")];
+ char uniname2ctype_pool_str1655[sizeof("inscriptionalpahlavi")];
+ char uniname2ctype_pool_str1668[sizeof("inalchemicalsymbols")];
+ char uniname2ctype_pool_str1669[sizeof("inhatran")];
+ char uniname2ctype_pool_str1670[sizeof("assigned")];
+ char uniname2ctype_pool_str1671[sizeof("intaiviet")];
+ char uniname2ctype_pool_str1674[sizeof("syrc")];
+ char uniname2ctype_pool_str1682[sizeof("bopo")];
+ char uniname2ctype_pool_str1684[sizeof("intirhuta")];
+ char uniname2ctype_pool_str1688[sizeof("oldnortharabian")];
+ char uniname2ctype_pool_str1690[sizeof("insupplementalmathematicaloperators")];
+ char uniname2ctype_pool_str1694[sizeof("bopomofo")];
+ char uniname2ctype_pool_str1696[sizeof("olonal")];
+ char uniname2ctype_pool_str1697[sizeof("injavanese")];
+ char uniname2ctype_pool_str1698[sizeof("insunuwar")];
+ char uniname2ctype_pool_str1707[sizeof("inmathematicalalphanumericsymbols")];
+ char uniname2ctype_pool_str1713[sizeof("inimperialaramaic")];
+ char uniname2ctype_pool_str1714[sizeof("khmer")];
+ char uniname2ctype_pool_str1724[sizeof("gonm")];
+ char uniname2ctype_pool_str1727[sizeof("hyphen")];
+ char uniname2ctype_pool_str1731[sizeof("insuperscriptsandsubscripts")];
+ char uniname2ctype_pool_str1733[sizeof("inenclosedideographicsupplement")];
+ char uniname2ctype_pool_str1735[sizeof("ingeometricshapesextended")];
+ char uniname2ctype_pool_str1737[sizeof("insaurashtra")];
+ char uniname2ctype_pool_str1738[sizeof("ogam")];
+ char uniname2ctype_pool_str1746[sizeof("orya")];
+ char uniname2ctype_pool_str1748[sizeof("saur")];
+ char uniname2ctype_pool_str1754[sizeof("marchen")];
+ char uniname2ctype_pool_str1755[sizeof("sundanese")];
+ char uniname2ctype_pool_str1762[sizeof("khudawadi")];
+ char uniname2ctype_pool_str1773[sizeof("soyo")];
+ char uniname2ctype_pool_str1775[sizeof("whitespace")];
+ char uniname2ctype_pool_str1778[sizeof("uideo")];
+ char uniname2ctype_pool_str1785[sizeof("oldpersian")];
+ char uniname2ctype_pool_str1787[sizeof("inyezidi")];
+ char uniname2ctype_pool_str1790[sizeof("kiratrai")];
+ char uniname2ctype_pool_str1793[sizeof("inlisusupplement")];
+ char uniname2ctype_pool_str1796[sizeof("mero")];
+ char uniname2ctype_pool_str1800[sizeof("symbol")];
+ char uniname2ctype_pool_str1811[sizeof("soyombo")];
+ char uniname2ctype_pool_str1812[sizeof("osmanya")];
+ char uniname2ctype_pool_str1814[sizeof("indevanagari")];
+ char uniname2ctype_pool_str1816[sizeof("unassigned")];
+ char uniname2ctype_pool_str1818[sizeof("bengali")];
+ char uniname2ctype_pool_str1819[sizeof("hebr")];
+ char uniname2ctype_pool_str1821[sizeof("hebrew")];
+ char uniname2ctype_pool_str1824[sizeof("inornamentaldingbats")];
+ char uniname2ctype_pool_str1829[sizeof("invedicextensions")];
+ char uniname2ctype_pool_str1834[sizeof("copt")];
+ char uniname2ctype_pool_str1836[sizeof("ingreekextended")];
+ char uniname2ctype_pool_str1839[sizeof("sund")];
+ char uniname2ctype_pool_str1847[sizeof("cyprominoan")];
+ char uniname2ctype_pool_str1848[sizeof("inherited")];
+ char uniname2ctype_pool_str1854[sizeof("toto")];
+ char uniname2ctype_pool_str1858[sizeof("inugaritic")];
+ char uniname2ctype_pool_str1863[sizeof("syriac")];
+ char uniname2ctype_pool_str1864[sizeof("cwt")];
+ char uniname2ctype_pool_str1867[sizeof("inhebrew")];
+ char uniname2ctype_pool_str1872[sizeof("runic")];
+ char uniname2ctype_pool_str1877[sizeof("inmongoliansupplement")];
+ char uniname2ctype_pool_str1884[sizeof("inshorthandformatcontrols")];
+ char uniname2ctype_pool_str1900[sizeof("cypriot")];
+ char uniname2ctype_pool_str1901[sizeof("cwcm")];
+ char uniname2ctype_pool_str1910[sizeof("ingreekandcoptic")];
+ char uniname2ctype_pool_str1920[sizeof("any")];
+ char uniname2ctype_pool_str1923[sizeof("inolduyghur")];
+ char uniname2ctype_pool_str1936[sizeof("inznamennymusicalnotation")];
+ char uniname2ctype_pool_str1937[sizeof("lowercase")];
+ char uniname2ctype_pool_str1941[sizeof("oldpermic")];
+ char uniname2ctype_pool_str1943[sizeof("ingeorgian")];
+ char uniname2ctype_pool_str1945[sizeof("ingurmukhi")];
+ char uniname2ctype_pool_str1947[sizeof("emojimodifier")];
+ char uniname2ctype_pool_str1956[sizeof("inkhojki")];
+ char uniname2ctype_pool_str1958[sizeof("aghb")];
+ char uniname2ctype_pool_str1960[sizeof("merc")];
+ char uniname2ctype_pool_str1966[sizeof("inrejang")];
+ char uniname2ctype_pool_str1969[sizeof("tamil")];
+ char uniname2ctype_pool_str1972[sizeof("indevanagariextendeda")];
+ char uniname2ctype_pool_str1974[sizeof("inalphabeticpresentationforms")];
+ char uniname2ctype_pool_str1975[sizeof("hangul")];
+ char uniname2ctype_pool_str1977[sizeof("inmeroitichieroglyphs")];
+ char uniname2ctype_pool_str1978[sizeof("inkannada")];
+ char uniname2ctype_pool_str1979[sizeof("hiragana")];
+ char uniname2ctype_pool_str1980[sizeof("maka")];
+ char uniname2ctype_pool_str1983[sizeof("inkanbun")];
+ char uniname2ctype_pool_str1987[sizeof("insorasompeng")];
+ char uniname2ctype_pool_str2001[sizeof("inmathematicaloperators")];
+ char uniname2ctype_pool_str2002[sizeof("tayo")];
+ char uniname2ctype_pool_str2005[sizeof("inhanunoo")];
+ char uniname2ctype_pool_str2010[sizeof("multani")];
+ char uniname2ctype_pool_str2015[sizeof("inkaithi")];
+ char uniname2ctype_pool_str2022[sizeof("innushu")];
+ char uniname2ctype_pool_str2023[sizeof("emojipresentation")];
+ char uniname2ctype_pool_str2028[sizeof("insymbolsforlegacycomputing")];
+ char uniname2ctype_pool_str2029[sizeof("meroiticcursive")];
+ char uniname2ctype_pool_str2037[sizeof("grantha")];
+ char uniname2ctype_pool_str2040[sizeof("inlinearbsyllabary")];
+ char uniname2ctype_pool_str2041[sizeof("mult")];
+ char uniname2ctype_pool_str2042[sizeof("taitham")];
+ char uniname2ctype_pool_str2047[sizeof("nshu")];
+ char uniname2ctype_pool_str2049[sizeof("incyrillicsupplement")];
+ char uniname2ctype_pool_str2051[sizeof("dashpunctuation")];
+ char uniname2ctype_pool_str2053[sizeof("inkatakana")];
+ char uniname2ctype_pool_str2056[sizeof("inbatak")];
+ char uniname2ctype_pool_str2059[sizeof("pi")];
+ char uniname2ctype_pool_str2064[sizeof("mong")];
+ char uniname2ctype_pool_str2074[sizeof("oldhungarian")];
+ char uniname2ctype_pool_str2076[sizeof("phoenician")];
+ char uniname2ctype_pool_str2077[sizeof("insmallformvariants")];
+ char uniname2ctype_pool_str2078[sizeof("idsunaryoperator")];
+ char uniname2ctype_pool_str2080[sizeof("variationselector")];
+ char uniname2ctype_pool_str2081[sizeof("limbu")];
+ char uniname2ctype_pool_str2085[sizeof("inyisyllables")];
+ char uniname2ctype_pool_str2087[sizeof("diak")];
+ char uniname2ctype_pool_str2090[sizeof("oldsoutharabian")];
+ char uniname2ctype_pool_str2092[sizeof("lepc")];
+ char uniname2ctype_pool_str2093[sizeof("inottomansiyaqnumbers")];
+ char uniname2ctype_pool_str2097[sizeof("control")];
+ char uniname2ctype_pool_str2102[sizeof("coptic")];
+ char uniname2ctype_pool_str2104[sizeof("inkhmersymbols")];
+ char uniname2ctype_pool_str2107[sizeof("titlecaseletter")];
+ char uniname2ctype_pool_str2110[sizeof("inphagspa")];
+ char uniname2ctype_pool_str2111[sizeof("bhks")];
+ char uniname2ctype_pool_str2113[sizeof("gothic")];
+ char uniname2ctype_pool_str2117[sizeof("sogo")];
+ char uniname2ctype_pool_str2122[sizeof("elym")];
+ char uniname2ctype_pool_str2131[sizeof("ps")];
+ char uniname2ctype_pool_str2137[sizeof("prti")];
+ char uniname2ctype_pool_str2138[sizeof("changeswhencasemapped")];
+ char uniname2ctype_pool_str2140[sizeof("deseret")];
+ char uniname2ctype_pool_str2142[sizeof("bhaiksuki")];
+ char uniname2ctype_pool_str2143[sizeof("cyrl")];
+ char uniname2ctype_pool_str2147[sizeof("olower")];
+ char uniname2ctype_pool_str2148[sizeof("inchakma")];
+ char uniname2ctype_pool_str2152[sizeof("wara")];
+ char uniname2ctype_pool_str2153[sizeof("sogdian")];
+ char uniname2ctype_pool_str2155[sizeof("graphemeclusterbreak=zwj")];
+ char uniname2ctype_pool_str2164[sizeof("runr")];
+ char uniname2ctype_pool_str2165[sizeof("changeswhentitlecased")];
+ char uniname2ctype_pool_str2168[sizeof("incjkstrokes")];
+ char uniname2ctype_pool_str2176[sizeof("incherokeesupplement")];
+ char uniname2ctype_pool_str2179[sizeof("intangutcomponents")];
+ char uniname2ctype_pool_str2182[sizeof("patws")];
+ char uniname2ctype_pool_str2183[sizeof("batk")];
+ char uniname2ctype_pool_str2186[sizeof("caseignorable")];
+ char uniname2ctype_pool_str2191[sizeof("inkawi")];
+ char uniname2ctype_pool_str2199[sizeof("indevanagariextended")];
+ char uniname2ctype_pool_str2203[sizeof("indogra")];
+ char uniname2ctype_pool_str2204[sizeof("intifinagh")];
+ char uniname2ctype_pool_str2206[sizeof("print")];
+ char uniname2ctype_pool_str2207[sizeof("cakm")];
+ char uniname2ctype_pool_str2209[sizeof("graphemeclusterbreak=t")];
+ char uniname2ctype_pool_str2211[sizeof("graphemeclusterbreak=lvt")];
+ char uniname2ctype_pool_str2214[sizeof("inmendekikakui")];
+ char uniname2ctype_pool_str2216[sizeof("inpsalterpahlavi")];
+ char uniname2ctype_pool_str2224[sizeof("dogra")];
+ char uniname2ctype_pool_str2228[sizeof("tangut")];
+ char uniname2ctype_pool_str2235[sizeof("oalpha")];
+ char uniname2ctype_pool_str2237[sizeof("intangutcomponentssupplement")];
+ char uniname2ctype_pool_str2239[sizeof("idcompatmathcontinue")];
+ char uniname2ctype_pool_str2241[sizeof("beriaerfe")];
+ char uniname2ctype_pool_str2243[sizeof("ext")];
+ char uniname2ctype_pool_str2244[sizeof("inkanasupplement")];
+ char uniname2ctype_pool_str2247[sizeof("osge")];
+ char uniname2ctype_pool_str2248[sizeof("inkanaextendeda")];
+ char uniname2ctype_pool_str2249[sizeof("inverticalforms")];
+ char uniname2ctype_pool_str2252[sizeof("decimalnumber")];
+ char uniname2ctype_pool_str2254[sizeof("inkanaextendedb")];
+ char uniname2ctype_pool_str2255[sizeof("idstrinaryoperator")];
+ char uniname2ctype_pool_str2257[sizeof("tols")];
+ char uniname2ctype_pool_str2260[sizeof("lower")];
+ char uniname2ctype_pool_str2270[sizeof("glag")];
+ char uniname2ctype_pool_str2272[sizeof("inhanguljamo")];
+ char uniname2ctype_pool_str2279[sizeof("insupplementalarrowsa")];
+ char uniname2ctype_pool_str2281[sizeof("inmeeteimayek")];
+ char uniname2ctype_pool_str2285[sizeof("insupplementalarrowsb")];
+ char uniname2ctype_pool_str2288[sizeof("inunifiedcanadianaboriginalsyllabics")];
+ char uniname2ctype_pool_str2296[sizeof("privateuse")];
+ char uniname2ctype_pool_str2299[sizeof("inunifiedcanadianaboriginalsyllabicsextendeda")];
+ char uniname2ctype_pool_str2302[sizeof("sentenceterminal")];
+ char uniname2ctype_pool_str2308[sizeof("pcm")];
+ char uniname2ctype_pool_str2309[sizeof("elymaic")];
+ char uniname2ctype_pool_str2310[sizeof("cpmn")];
+ char uniname2ctype_pool_str2312[sizeof("incjkcompatibilityforms")];
+ char uniname2ctype_pool_str2313[sizeof("inphoneticextensions")];
+ char uniname2ctype_pool_str2317[sizeof("incjkcompatibilityideographs")];
+ char uniname2ctype_pool_str2320[sizeof("oldsogdian")];
+ char uniname2ctype_pool_str2341[sizeof("inethiopicsupplement")];
+ char uniname2ctype_pool_str2345[sizeof("graphemebase")];
+ char uniname2ctype_pool_str2350[sizeof("intangutsupplement")];
+ char uniname2ctype_pool_str2353[sizeof("tang")];
+ char uniname2ctype_pool_str2361[sizeof("ideographic")];
+ char uniname2ctype_pool_str2364[sizeof("nagmundari")];
+ char uniname2ctype_pool_str2366[sizeof("sogd")];
+ char uniname2ctype_pool_str2370[sizeof("psalterpahlavi")];
+ char uniname2ctype_pool_str2371[sizeof("inphoneticextensionssupplement")];
+ char uniname2ctype_pool_str2373[sizeof("tagb")];
+ char uniname2ctype_pool_str2374[sizeof("invariationselectors")];
+ char uniname2ctype_pool_str2375[sizeof("incjkcompatibilityideographssupplement")];
+ char uniname2ctype_pool_str2379[sizeof("inindicsiyaqnumbers")];
+ char uniname2ctype_pool_str2389[sizeof("khojki")];
+ char uniname2ctype_pool_str2392[sizeof("inplayingcards")];
+ char uniname2ctype_pool_str2396[sizeof("graphemeclusterbreak=extend")];
+ char uniname2ctype_pool_str2397[sizeof("graphemeclusterbreak=prepend")];
+ char uniname2ctype_pool_str2398[sizeof("space")];
+ char uniname2ctype_pool_str2401[sizeof("tagbanwa")];
+ char uniname2ctype_pool_str2416[sizeof("extpict")];
+ char uniname2ctype_pool_str2421[sizeof("insupplementaryprivateuseareaa")];
+ char uniname2ctype_pool_str2422[sizeof("insupplementalarrowsc")];
+ char uniname2ctype_pool_str2424[sizeof("pd")];
+ char uniname2ctype_pool_str2427[sizeof("insupplementaryprivateuseareab")];
+ char uniname2ctype_pool_str2428[sizeof("innoblock")];
+ char uniname2ctype_pool_str2432[sizeof("invariationselectorssupplement")];
+ char uniname2ctype_pool_str2433[sizeof("inhanguljamoextendeda")];
+ char uniname2ctype_pool_str2434[sizeof("kthi")];
+ char uniname2ctype_pool_str2439[sizeof("inhanguljamoextendedb")];
+ char uniname2ctype_pool_str2440[sizeof("sk")];
+ char uniname2ctype_pool_str2443[sizeof("cherokee")];
+ char uniname2ctype_pool_str2451[sizeof("nchar")];
+ char uniname2ctype_pool_str2458[sizeof("pc")];
+ char uniname2ctype_pool_str2466[sizeof("graphemeextend")];
+ char uniname2ctype_pool_str2468[sizeof("wancho")];
+ char uniname2ctype_pool_str2473[sizeof("inprivateusearea")];
+ char uniname2ctype_pool_str2483[sizeof("sunuwar")];
+ char uniname2ctype_pool_str2491[sizeof("ingothic")];
+ char uniname2ctype_pool_str2495[sizeof("softdotted")];
+ char uniname2ctype_pool_str2503[sizeof("lowercaseletter")];
+ char uniname2ctype_pool_str2505[sizeof("phli")];
+ char uniname2ctype_pool_str2518[sizeof("katakana")];
+ char uniname2ctype_pool_str2526[sizeof("inunifiedcanadianaboriginalsyllabicsextended")];
+ char uniname2ctype_pool_str2528[sizeof("hanifirohingya")];
+ char uniname2ctype_pool_str2532[sizeof("palm")];
+ char uniname2ctype_pool_str2534[sizeof("talu")];
+ char uniname2ctype_pool_str2541[sizeof("inlisu")];
+ char uniname2ctype_pool_str2543[sizeof("lu")];
+ char uniname2ctype_pool_str2553[sizeof("invithkuqi")];
+ char uniname2ctype_pool_str2570[sizeof("finalpunctuation")];
+ char uniname2ctype_pool_str2571[sizeof("incyrillicextendeda")];
+ char uniname2ctype_pool_str2577[sizeof("incyrillicextendedb")];
+ char uniname2ctype_pool_str2579[sizeof("noncharactercodepoint")];
+ char uniname2ctype_pool_str2581[sizeof("mark")];
+ char uniname2ctype_pool_str2582[sizeof("medf")];
+ char uniname2ctype_pool_str2590[sizeof("inkiratrai")];
+ char uniname2ctype_pool_str2591[sizeof("intelugu")];
+ char uniname2ctype_pool_str2592[sizeof("inmakasar")];
+ char uniname2ctype_pool_str2593[sizeof("graphemeclusterbreak=l")];
+ char uniname2ctype_pool_str2596[sizeof("inkharoshthi")];
+ char uniname2ctype_pool_str2599[sizeof("graphemeclusterbreak=control")];
+ char uniname2ctype_pool_str2603[sizeof("deprecated")];
+ char uniname2ctype_pool_str2612[sizeof("insupplementalsymbolsandpictographs")];
+ char uniname2ctype_pool_str2613[sizeof("tirh")];
+ char uniname2ctype_pool_str2614[sizeof("sunu")];
+ char uniname2ctype_pool_str2618[sizeof("letter")];
+ char uniname2ctype_pool_str2619[sizeof("medefaidrin")];
+ char uniname2ctype_pool_str2625[sizeof("beng")];
+ char uniname2ctype_pool_str2626[sizeof("makasar")];
+ char uniname2ctype_pool_str2632[sizeof("cwl")];
+ char uniname2ctype_pool_str2633[sizeof("intakri")];
+ char uniname2ctype_pool_str2634[sizeof("tavt")];
+ char uniname2ctype_pool_str2658[sizeof("todr")];
+ char uniname2ctype_pool_str2668[sizeof("todhri")];
+ char uniname2ctype_pool_str2671[sizeof("insupplementalpunctuation")];
+ char uniname2ctype_pool_str2672[sizeof("modifiersymbol")];
+ char uniname2ctype_pool_str2673[sizeof("ogham")];
+ char uniname2ctype_pool_str2679[sizeof("wcho")];
+ char uniname2ctype_pool_str2688[sizeof("intagalog")];
+ char uniname2ctype_pool_str2689[sizeof("omath")];
+ char uniname2ctype_pool_str2699[sizeof("inkhmer")];
+ char uniname2ctype_pool_str2700[sizeof("cf")];
+ char uniname2ctype_pool_str2701[sizeof("bassavah")];
+ char uniname2ctype_pool_str2705[sizeof("extendedpictographic")];
+ char uniname2ctype_pool_str2708[sizeof("zyyy")];
+ char uniname2ctype_pool_str2714[sizeof("incyrillicextendedc")];
+ char uniname2ctype_pool_str2725[sizeof("ugaritic")];
+ char uniname2ctype_pool_str2726[sizeof("goth")];
+ char uniname2ctype_pool_str2728[sizeof("idcompatmathstart")];
+ char uniname2ctype_pool_str2729[sizeof("divesakuru")];
+ char uniname2ctype_pool_str2732[sizeof("wspace")];
+ char uniname2ctype_pool_str2737[sizeof("geor")];
+ char uniname2ctype_pool_str2764[sizeof("cyrillic")];
+ char uniname2ctype_pool_str2765[sizeof("graphemeclusterbreak=cr")];
+ char uniname2ctype_pool_str2767[sizeof("sorasompeng")];
+ char uniname2ctype_pool_str2780[sizeof("graphemeclusterbreak=regionalindicator")];
+ char uniname2ctype_pool_str2782[sizeof("tirhuta")];
+ char uniname2ctype_pool_str2791[sizeof("inbopomofoextended")];
+ char uniname2ctype_pool_str2796[sizeof("yezi")];
+ char uniname2ctype_pool_str2798[sizeof("p")];
+ char uniname2ctype_pool_str2799[sizeof("incyrillicextendedd")];
+ char uniname2ctype_pool_str2800[sizeof("po")];
+ char uniname2ctype_pool_str2801[sizeof("zp")];
+ char uniname2ctype_pool_str2802[sizeof("dogr")];
+ char uniname2ctype_pool_str2806[sizeof("dep")];
+ char uniname2ctype_pool_str2813[sizeof("hung")];
+ char uniname2ctype_pool_str2819[sizeof("term")];
+ char uniname2ctype_pool_str2826[sizeof("deva")];
+ char uniname2ctype_pool_str2831[sizeof("format")];
+ char uniname2ctype_pool_str2835[sizeof("oldturkic")];
+ char uniname2ctype_pool_str2836[sizeof("kayahli")];
+ char uniname2ctype_pool_str2844[sizeof("devanagari")];
+ char uniname2ctype_pool_str2850[sizeof("olck")];
+ char uniname2ctype_pool_str2852[sizeof("dupl")];
+ char uniname2ctype_pool_str2857[sizeof("incurrencysymbols")];
+ char uniname2ctype_pool_str2861[sizeof("olchiki")];
+ char uniname2ctype_pool_str2863[sizeof("inethiopicextendeda")];
+ char uniname2ctype_pool_str2869[sizeof("inethiopicextendedb")];
+ char uniname2ctype_pool_str2872[sizeof("phagspa")];
+ char uniname2ctype_pool_str2877[sizeof("buhd")];
+ char uniname2ctype_pool_str2878[sizeof("inhangulsyllables")];
+ char uniname2ctype_pool_str2881[sizeof("inlatinextendedf")];
+ char uniname2ctype_pool_str2883[sizeof("modifierletter")];
+ char uniname2ctype_pool_str2894[sizeof("graph")];
+ char uniname2ctype_pool_str2897[sizeof("ingaray")];
+ char uniname2ctype_pool_str2900[sizeof("number")];
+ char uniname2ctype_pool_str2910[sizeof("inkayahli")];
+ char uniname2ctype_pool_str2922[sizeof("lepcha")];
+ char uniname2ctype_pool_str2925[sizeof("plrd")];
+ char uniname2ctype_pool_str2926[sizeof("incjksymbolsandpunctuation")];
+ char uniname2ctype_pool_str2928[sizeof("ecomp")];
+ char uniname2ctype_pool_str2947[sizeof("cuneiform")];
+ char uniname2ctype_pool_str2953[sizeof("inglagolitic")];
+ char uniname2ctype_pool_str2960[sizeof("gunjalagondi")];
+ char uniname2ctype_pool_str2970[sizeof("bugi")];
+ char uniname2ctype_pool_str2984[sizeof("takri")];
+ char uniname2ctype_pool_str2986[sizeof("cprt")];
+ char uniname2ctype_pool_str2987[sizeof("spaceseparator")];
+ char uniname2ctype_pool_str2991[sizeof("ingurungkhema")];
+ char uniname2ctype_pool_str2993[sizeof("incypriotsyllabary")];
+ char uniname2ctype_pool_str2995[sizeof("inpaucinhau")];
+ char uniname2ctype_pool_str3005[sizeof("gong")];
+ char uniname2ctype_pool_str3013[sizeof("joinc")];
+ char uniname2ctype_pool_str3015[sizeof("currencysymbol")];
+ char uniname2ctype_pool_str3017[sizeof("rohg")];
+ char uniname2ctype_pool_str3021[sizeof("logicalorderexception")];
+ char uniname2ctype_pool_str3022[sizeof("grek")];
+ char uniname2ctype_pool_str3041[sizeof("changeswhenlowercased")];
+ char uniname2ctype_pool_str3049[sizeof("inpahawhhmong")];
+ char uniname2ctype_pool_str3052[sizeof("yezidi")];
+ char uniname2ctype_pool_str3054[sizeof("cwcf")];
+ char uniname2ctype_pool_str3061[sizeof("extender")];
+ char uniname2ctype_pool_str3068[sizeof("inhangulcompatibilityjamo")];
+ char uniname2ctype_pool_str3078[sizeof("tulutigalari")];
+ char uniname2ctype_pool_str3080[sizeof("terminalpunctuation")];
+ char uniname2ctype_pool_str3086[sizeof("inkatakanaphoneticextensions")];
+ char uniname2ctype_pool_str3090[sizeof("inethiopicextended")];
+ char uniname2ctype_pool_str3097[sizeof("gujr")];
+ char uniname2ctype_pool_str3103[sizeof("patsyn")];
+ char uniname2ctype_pool_str3107[sizeof("ugar")];
+ char uniname2ctype_pool_str3108[sizeof("word")];
+ char uniname2ctype_pool_str3112[sizeof("berf")];
+ char uniname2ctype_pool_str3121[sizeof("xpeo")];
+ char uniname2ctype_pool_str3122[sizeof("regionalindicator")];
+ char uniname2ctype_pool_str3127[sizeof("gujarati")];
+ char uniname2ctype_pool_str3128[sizeof("buhid")];
+ char uniname2ctype_pool_str3137[sizeof("inlatinextendedg")];
+ char uniname2ctype_pool_str3142[sizeof("ethi")];
+ char uniname2ctype_pool_str3165[sizeof("inkhitansmallscript")];
+ char uniname2ctype_pool_str3169[sizeof("ingeorgiansupplement")];
+ char uniname2ctype_pool_str3177[sizeof("inegyptianhieroglyphs")];
+ char uniname2ctype_pool_str3184[sizeof("tifinagh")];
+ char uniname2ctype_pool_str3188[sizeof("inegyptianhieroglyphsextendeda")];
+ char uniname2ctype_pool_str3190[sizeof("inegyptianhieroglyphformatcontrols")];
+ char uniname2ctype_pool_str3221[sizeof("inkhudawadi")];
+ char uniname2ctype_pool_str3231[sizeof("incjkcompatibility")];
+ char uniname2ctype_pool_str3238[sizeof("rjng")];
+ char uniname2ctype_pool_str3240[sizeof("buginese")];
+ char uniname2ctype_pool_str3245[sizeof("mendekikakui")];
+ char uniname2ctype_pool_str3247[sizeof("letternumber")];
+ char uniname2ctype_pool_str3257[sizeof("phlp")];
+ char uniname2ctype_pool_str3261[sizeof("separator")];
+ char uniname2ctype_pool_str3263[sizeof("pauc")];
+ char uniname2ctype_pool_str3281[sizeof("vithkuqi")];
+ char uniname2ctype_pool_str3287[sizeof("inkangxiradicals")];
+ char uniname2ctype_pool_str3291[sizeof("changeswhencasefolded")];
+ char uniname2ctype_pool_str3302[sizeof("graphemeclusterbreak=lf")];
+ char uniname2ctype_pool_str3307[sizeof("joincontrol")];
+ char uniname2ctype_pool_str3326[sizeof("inmeroiticcursive")];
+ char uniname2ctype_pool_str3334[sizeof("pe")];
+ char uniname2ctype_pool_str3335[sizeof("patternwhitespace")];
+ char uniname2ctype_pool_str3357[sizeof("duployan")];
+ char uniname2ctype_pool_str3359[sizeof("phag")];
+ char uniname2ctype_pool_str3363[sizeof("meeteimayek")];
+ char uniname2ctype_pool_str3407[sizeof("innyiakengpuachuehmong")];
+ char uniname2ctype_pool_str3408[sizeof("incjkunifiedideographsextensioni")];
+ char uniname2ctype_pool_str3414[sizeof("incjkunifiedideographs")];
+ char uniname2ctype_pool_str3416[sizeof("incjkunifiedideographsextensionj")];
+ char uniname2ctype_pool_str3418[sizeof("georgian")];
+ char uniname2ctype_pool_str3426[sizeof("incjkunifiedideographsextensiona")];
+ char uniname2ctype_pool_str3432[sizeof("incjkunifiedideographsextensionb")];
+ char uniname2ctype_pool_str3436[sizeof("warangciti")];
+ char uniname2ctype_pool_str3444[sizeof("inhighprivateusesurrogates")];
+ char uniname2ctype_pool_str3469[sizeof("meroitichieroglyphs")];
+ char uniname2ctype_pool_str3481[sizeof("java")];
+ char uniname2ctype_pool_str3493[sizeof("garay")];
+ char uniname2ctype_pool_str3497[sizeof("nonspacingmark")];
+ char uniname2ctype_pool_str3505[sizeof("otheridstart")];
+ char uniname2ctype_pool_str3507[sizeof("otheridcontinue")];
+ char uniname2ctype_pool_str3516[sizeof("xsux")];
+ char uniname2ctype_pool_str3532[sizeof("phnx")];
+ char uniname2ctype_pool_str3535[sizeof("incjkunifiedideographsextensione")];
+ char uniname2ctype_pool_str3536[sizeof("signwriting")];
+ char uniname2ctype_pool_str3543[sizeof("tolongsiki")];
+ char uniname2ctype_pool_str3569[sizeof("incjkunifiedideographsextensionc")];
+ char uniname2ctype_pool_str3579[sizeof("combiningmark")];
+ char uniname2ctype_pool_str3585[sizeof("nushu")];
+ char uniname2ctype_pool_str3598[sizeof("takr")];
+ char uniname2ctype_pool_str3613[sizeof("tfng")];
+ char uniname2ctype_pool_str3614[sizeof("changeswhenuppercased")];
+ char uniname2ctype_pool_str3622[sizeof("inglagoliticsupplement")];
+ char uniname2ctype_pool_str3629[sizeof("surrogate")];
+ char uniname2ctype_pool_str3647[sizeof("orkh")];
+ char uniname2ctype_pool_str3650[sizeof("graphemeclusterbreak=v")];
+ char uniname2ctype_pool_str3651[sizeof("graphemeclusterbreak=lv")];
+ char uniname2ctype_pool_str3654[sizeof("incjkunifiedideographsextensiond")];
+ char uniname2ctype_pool_str3666[sizeof("telu")];
+ char uniname2ctype_pool_str3669[sizeof("inhalfwidthandfullwidthforms")];
+ char uniname2ctype_pool_str3686[sizeof("otheralphabetic")];
+ char uniname2ctype_pool_str3690[sizeof("unknown")];
+ char uniname2ctype_pool_str3699[sizeof("punct")];
+ char uniname2ctype_pool_str3718[sizeof("tglg")];
+ char uniname2ctype_pool_str3733[sizeof("javanese")];
+ char uniname2ctype_pool_str3770[sizeof("otherdefaultignorablecodepoint")];
+ char uniname2ctype_pool_str3778[sizeof("cwu")];
+ char uniname2ctype_pool_str3782[sizeof("rejang")];
+ char uniname2ctype_pool_str3813[sizeof("egyp")];
+ char uniname2ctype_pool_str3835[sizeof("perm")];
+ char uniname2ctype_pool_str3836[sizeof("othersymbol")];
+ char uniname2ctype_pool_str3869[sizeof("epres")];
+ char uniname2ctype_pool_str3877[sizeof("olduyghur")];
+ char uniname2ctype_pool_str3894[sizeof("tutg")];
+ char uniname2ctype_pool_str3901[sizeof("enclosingmark")];
+ char uniname2ctype_pool_str3918[sizeof("ingeorgianextended")];
+ char uniname2ctype_pool_str3945[sizeof("ogrext")];
+ char uniname2ctype_pool_str3965[sizeof("indivesakuru")];
+ char uniname2ctype_pool_str3972[sizeof("otherlowercase")];
+ char uniname2ctype_pool_str3981[sizeof("other")];
+ char uniname2ctype_pool_str3995[sizeof("othernumber")];
+ char uniname2ctype_pool_str4007[sizeof("hexdigit")];
+ char uniname2ctype_pool_str4018[sizeof("incjkradicalssupplement")];
+ char uniname2ctype_pool_str4035[sizeof("blank")];
+ char uniname2ctype_pool_str4064[sizeof("ethiopic")];
+ char uniname2ctype_pool_str4069[sizeof("graphemeclusterbreak=spacingmark")];
+ char uniname2ctype_pool_str4072[sizeof("spacingmark")];
+ char uniname2ctype_pool_str4089[sizeof("tagalog")];
+ char uniname2ctype_pool_str4102[sizeof("batak")];
+ char uniname2ctype_pool_str4110[sizeof("guru")];
+ char uniname2ctype_pool_str4117[sizeof("hex")];
+ char uniname2ctype_pool_str4140[sizeof("paucinhau")];
+ char uniname2ctype_pool_str4153[sizeof("modifiercombiningmark")];
+ char uniname2ctype_pool_str4163[sizeof("otherpunctuation")];
+ char uniname2ctype_pool_str4180[sizeof("ougr")];
+ char uniname2ctype_pool_str4228[sizeof("palmyrene")];
+ char uniname2ctype_pool_str4318[sizeof("othermath")];
+ char uniname2ctype_pool_str4353[sizeof("incjkunifiedideographsextensionh")];
+ char uniname2ctype_pool_str4354[sizeof("inboxdrawing")];
+ char uniname2ctype_pool_str4401[sizeof("patternsyntax")];
+ char uniname2ctype_pool_str4404[sizeof("oupper")];
+ char uniname2ctype_pool_str4410[sizeof("gurungkhema")];
+ char uniname2ctype_pool_str4414[sizeof("prependedconcatenationmark")];
+ char uniname2ctype_pool_str4439[sizeof("otherletter")];
+ char uniname2ctype_pool_str4491[sizeof("pf")];
+ char uniname2ctype_pool_str4494[sizeof("qmark")];
+ char uniname2ctype_pool_str4543[sizeof("inhighsurrogates")];
+ char uniname2ctype_pool_str4544[sizeof("xposixpunct")];
+ char uniname2ctype_pool_str4545[sizeof("otheruppercase")];
+ char uniname2ctype_pool_str4564[sizeof("incjkunifiedideographsextensionf")];
+ char uniname2ctype_pool_str4670[sizeof("punctuation")];
+ char uniname2ctype_pool_str4692[sizeof("incjkunifiedideographsextensiong")];
+ char uniname2ctype_pool_str4731[sizeof("egyptianhieroglyphs")];
+ char uniname2ctype_pool_str4775[sizeof("defaultignorablecodepoint")];
+ char uniname2ctype_pool_str4777[sizeof("quotationmark")];
+ char uniname2ctype_pool_str4800[sizeof("openpunctuation")];
+ char uniname2ctype_pool_str4851[sizeof("unifiedideograph")];
+ char uniname2ctype_pool_str4941[sizeof("greek")];
+ char uniname2ctype_pool_str4985[sizeof("othergraphemeextend")];
+ char uniname2ctype_pool_str5002[sizeof("inkaktoviknumerals")];
+ char uniname2ctype_pool_str5234[sizeof("uppercase")];
+ char uniname2ctype_pool_str5271[sizeof("grlink")];
+ char uniname2ctype_pool_str5290[sizeof("nyiakengpuachuehmong")];
+ char uniname2ctype_pool_str5329[sizeof("gukh")];
+ char uniname2ctype_pool_str5512[sizeof("pahawhhmong")];
+ char uniname2ctype_pool_str5557[sizeof("upper")];
+ char uniname2ctype_pool_str5800[sizeof("uppercaseletter")];
+ char uniname2ctype_pool_str5919[sizeof("graphemelink")];
+ char uniname2ctype_pool_str5981[sizeof("telugu")];
+ char uniname2ctype_pool_str6036[sizeof("gurmukhi")];
+ char uniname2ctype_pool_str6068[sizeof("paragraphseparator")];
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+static const struct uniname2ctype_pool_t uniname2ctype_pool_contents =
+ {
+#ifndef USE_UNICODE_PROPERTIES
+ "word",
+ "print",
+ "punct",
+ "alpha",
+#else /* USE_UNICODE_PROPERTIES */
+ "n",
+ "m",
+ "mn",
+ "lm",
+ "inmro",
+ "innko",
+ "mro",
+ "mroo",
+ "ri",
+ "lao",
+ "laoo",
+ "ahom",
+ "hano",
+ "miao",
+ "hani",
+ "inmiao",
+ "han",
+ "mani",
+ "lina",
+ "inahom",
+ "hanunoo",
+ "limb",
+ "linb",
+ "inmanichaean",
+#endif /* USE_UNICODE_PROPERTIES */
+ "alnum",
+#ifndef USE_UNICODE_PROPERTIES
+ "xdigit",
+ "upper",
+#else /* USE_UNICODE_PROPERTIES */
+ "armi",
+ "nandinagari",
+ "armn",
+ "lana",
+ "zanb",
+ "inosmanya",
+ "insamaritan",
+ "inbhaiksuki",
+ "armenian",
+ "sm",
+ "inmasaramgondi",
+ "s",
+ "innabataean",
+ "zs",
+ "inbasiclatin",
+ "innumberforms",
+ "arab",
+ "inmusicalsymbols",
+ "latn",
+ "inthai",
+ "latin",
+ "shavian",
+ "initialpunctuation",
+ "hatran",
+ "di",
+ "inthaana",
+ "intoto",
+ "nabataean",
+ "intaitham",
+ "inarabicpresentationformsa",
+ "inbraillepatterns",
+ "inarabicpresentationformsb",
+ "ids",
+ "dia",
+ "inarmenian",
+ "idsb",
+ "intransportandmapsymbols",
+ "inideographicsymbolsandpunctuation",
+ "inavestan",
+ "inipaextensions",
+ "inelbasan",
+ "inopticalcharacterrecognition",
+ "brai",
+ "bamum",
+ "incham",
+ "inideographicdescriptioncharacters",
+ "brahmi",
+ "idst",
+ "bass",
+ "mandaic",
+ "inemoticons",
+ "incommonindicnumberforms",
+ "intibetan",
+ "inarabic",
+ "nbat",
+ "cn",
+ "inancientsymbols",
+ "ci",
+#endif /* USE_UNICODE_PROPERTIES */
+ "ascii",
+#ifdef USE_UNICODE_PROPERTIES
+ "mcm",
+ "ideo",
+ "inmodi",
+ "vai",
+ "vaii",
+ "cham",
+ "inmyanmarextendeda",
+ "nand",
+ "inmyanmarextendedb",
+ "mand",
+ "cans",
+ "inoldsogdian",
+ "chorasmian",
+ "innewa",
+ "chakma",
+ "incuneiform",
+ "vs",
+ "cs",
+ "sind",
+ "shaw",
+ "inspecials",
+ "inchesssymbols",
+ "avst",
+ "inblockelements",
+ "nd",
+ "sharada",
+ "inmiscellaneoussymbols",
+ "inmiscellaneousmathematicalsymbolsa",
+ "sidt",
+ "inmiscellaneousmathematicalsymbolsb",
+ "inmiscellaneoussymbolsandarrows",
+ "arabic",
+ "inmiscellaneoussymbolsandpictographs",
+ "c",
+ "lc",
+ "mc",
+ "inmedefaidrin",
+ "inmyanmarextendedc",
+ "insundanese",
+ "indominotiles",
+ "insymbolsandpictographsextendeda",
+ "inwancho",
+ "inolditalic",
+ "inmodifiertoneletters",
+ "incb=consonant",
+ "sd",
+ "inmandaic",
+ "inmiscellaneoussymbolssupplement",
+ "nko",
+ "nkoo",
+ "l",
+ "inmeeteimayekextensions",
+ "nl",
+ "zl",
+ "ll",
+ "inlao",
+ "khoj",
+ "idc",
+ "innewtailue",
+ "inolonal",
+ "sc",
+ "indeseret",
+ "incuneiformnumbersandpunctuation",
+ "krai",
+ "inarabicextendeda",
+ "inoldturkic",
+ "avestan",
+ "inarabicextendedb",
+ "inmalayalam",
+ "kharoshthi",
+ "kana",
+ "inadlam",
+ "idcontinue",
+ "insiddham",
+ "intamil",
+ "inmultani",
+ "intolongsiki",
+ "kits",
+ "incb=extend",
+ "sidetic",
+ "sidd",
+ "incontrolpictures",
+ "insidetic",
+ "sinhala",
+ "inlatinextendeda",
+ "inlatinextendedb",
+ "adlm",
+ "adlam",
+ "inlineara",
+ "intamilsupplement",
+ "inbalinese",
+ "inspacingmodifierletters",
+ "inarabicextendedc",
+ "inlycian",
+ "bali",
+ "hira",
+ "cc",
+ "insmallkanaextension",
+ "intaile",
+ "qaai",
+ "inmyanmar",
+ "narb",
+ "inarrows",
+ "lineara",
+ "linearb",
+ "insharada",
+ "inruminumeralsymbols",
+ "masaramgondi",
+ "hatr",
+ "knda",
+ "samr",
+ "kawi",
+ "inlydian",
+ "samaritan",
+ "sarb",
+ "no",
+ "bidic",
+ "lo",
+ "hmnp",
+ "onao",
+ "inlowsurrogates",
+ "kannada",
+ "inlinearbideograms",
+ "inletterlikesymbols",
+ "cased",
+ "inbopomofo",
+ "inberiaerfe",
+ "lineseparator",
+ "z",
+ "insymbolsforlegacycomputingsupplement",
+ "inrunic",
+ "incarian",
+ "inlatinextendede",
+ "inmarchen",
+ "so",
+ "marc",
+ "oriya",
+ "inchorasmian",
+ "yi",
+ "insyriac",
+ "yiii",
+ "alpha",
+ "qaac",
+ "insundanesesupplement",
+ "osma",
+ "inmiscellaneoustechnical",
+ "idstart",
+ "inenclosedcjklettersandmonths",
+ "inlatinextendedc",
+ "dsrt",
+ "odi",
+ "chrs",
+ "cari",
+ "innandinagari",
+ "balinese",
+ "inwarangciti",
+ "inphoenician",
+ "kali",
+ "inoldnortharabian",
+ "radical",
+ "carian",
+ "idsbinaryoperator",
+ "shrd",
+ "inoldsoutharabian",
+ "diacritic",
+ "mlym",
+ "zinh",
+ "inphaistosdisc",
+ "incyrillic",
+ "ininscriptionalpahlavi",
+ "insoyombo",
+ "ininscriptionalparthian",
+ "inoriya",
+ "lyci",
+ "inogham",
+ "mahj",
+ "gran",
+ "inmahajani",
+ "co",
+ "cher",
+ "alphabetic",
+ "insinhala",
+ "modi",
+ "inbrahmi",
+ "loe",
+ "lycian",
+ "mahajani",
+ "common",
+ "intaiyo",
+ "inhanifirohingya",
+ "inbassavah",
+ "sinh",
+ "oids",
+ "inlatinextendedadditional",
+ "inyijinghexagramsymbols",
+ "inoldpersian",
+ "bidicontrol",
+ "math",
+ "inarabicsupplement",
+ "thai",
+ "inlatinextendedd",
+ "taiyo",
+ "lisu",
+ "tnsa",
+ "incherokee",
+ "thaa",
+ "lydi",
+ "inbamum",
+ "khmr",
+ "inbyzantinemusicalsymbols",
+ "lt",
+ "khar",
+ "thaana",
+ "osage",
+ "lydian",
+ "inanatolianhieroglyphs",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=11.0",
+ "age=10.0",
+ "age=12.1",
+ "age=12.0",
+ "age=1.1",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "insylotinagri",
+ "anatolianhieroglyphs",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=2.1",
+ "age=2.0",
+ "age=14.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "tangsa",
+ "dash",
+ "incombiningdiacriticalmarks",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=17.0",
+ "age=4.1",
+ "age=4.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "tibt",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=15.1",
+ "age=15.0",
+ "age=7.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "inolchiki",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=9.0",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "incombiningdiacriticalmarksforsymbols",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=5.1",
+ "age=5.0",
+ "age=16.0",
+ "age=5.2",
+ "age=8.0",
+ "age=13.0",
+ "age=6.1",
+ "age=6.0",
+ "age=6.2",
+ "age=3.1",
+ "age=3.0",
+ "age=3.2",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "inarabicmathematicalalphabeticsymbols",
+ "brah",
+ "tibetan",
+ "mtei",
+ "incoptic",
+ "manichaean",
+#ifdef USE_UNICODE_AGE_PROPERTIES
+ "age=6.3",
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ "emoji",
+ "oidc",
+ "incombiningdiacriticalmarkssupplement",
+ "idsu",
+ "saurashtra",
+ "inoldpermic",
+ "closepunctuation",
+ "incombininghalfmarks",
+ "incopticepactnumbers",
+ "elba",
+ "xdigit",
+#endif /* USE_UNICODE_PROPERTIES */
+ "cntrl",
+#ifndef USE_UNICODE_PROPERTIES
+ "space",
+ "xposixpunct",
+#else /* USE_UNICODE_PROPERTIES */
+ "bamu",
+ "xids",
+ "inoldhungarian",
+ "grext",
+ "mongolian",
+ "sterm",
+ "braille",
+ "inbuhid",
+ "elbasan",
+ "zanabazarsquare",
+ "incountingrodnumerals",
+ "inenclosedalphanumerics",
+ "incb=linker",
+ "taiviet",
+ "inelymaic",
+ "inethiopic",
+ "sgnw",
+ "olditalic",
+ "vith",
+ "grbase",
+ "hluw",
+ "intodhri",
+ "asciihexdigit",
+ "me",
+ "hmng",
+ "siddham",
+ "inenclosedalphanumericsupplement",
+ "taile",
+ "nagm",
+ "hang",
+ "inscriptionalparthian",
+ "inmongolian",
+ "innagmundari",
+ "sylo",
+ "ingunjalagondi",
+ "ingujarati",
+ "inbengali",
+ "khitansmallscript",
+ "xidcontinue",
+ "ingrantha",
+ "insinhalaarchaicnumbers",
+ "connectorpunctuation",
+ "inpalmyrene",
+ "incombiningdiacriticalmarksextended",
+ "xidstart",
+ "xidc",
+ "inancientgreekmusicalnotation",
+ "inancientgreeknumbers",
+ "intangsa",
+ "intags",
+ "inlepcha",
+ "caucasianalbanian",
+ "sylotinagri",
+ "emod",
+ "incaucasianalbanian",
+ "intagbanwa",
+ "mend",
+ "newa",
+ "inearlydynasticcuneiform",
+ "kaithi",
+ "intangut",
+ "mymr",
+ "inosage",
+ "inmahjongtiles",
+ "malayalam",
+ "sora",
+ "inbuginese",
+ "emojimodifierbase",
+ "induployan",
+ "ingeometricshapes",
+ "ingeneralpunctuation",
+ "myanmar",
+ "inlatin1supplement",
+ "ital",
+ "taml",
+ "inaegeannumbers",
+ "insharadasupplement",
+ "mathsymbol",
+ "inlimbu",
+ "invai",
+ "emojicomponent",
+ "insuttonsignwriting",
+ "digit",
+ "newtailue",
+ "inshavian",
+ "insogdian",
+ "indingbats",
+ "imperialaramaic",
+ "intulutigalari",
+ "incyprominoan",
+ "glagolitic",
+ "ebase",
+ "intaixuanjingsymbols",
+ "inbamumsupplement",
+ "gara",
+ "insyriacsupplement",
+ "casedletter",
+ "zzzz",
+ "inhiragana",
+ "tale",
+ "canadianaboriginal",
+ "ahex",
+ "inmayannumerals",
+ "inzanabazarsquare",
+ "inyiradicals",
+ "inscriptionalpahlavi",
+ "inalchemicalsymbols",
+ "inhatran",
+ "assigned",
+ "intaiviet",
+ "syrc",
+ "bopo",
+ "intirhuta",
+ "oldnortharabian",
+ "insupplementalmathematicaloperators",
+ "bopomofo",
+ "olonal",
+ "injavanese",
+ "insunuwar",
+ "inmathematicalalphanumericsymbols",
+ "inimperialaramaic",
+ "khmer",
+ "gonm",
+ "hyphen",
+ "insuperscriptsandsubscripts",
+ "inenclosedideographicsupplement",
+ "ingeometricshapesextended",
+ "insaurashtra",
+ "ogam",
+ "orya",
+ "saur",
+ "marchen",
+ "sundanese",
+ "khudawadi",
+ "soyo",
+ "whitespace",
+ "uideo",
+ "oldpersian",
+ "inyezidi",
+ "kiratrai",
+ "inlisusupplement",
+ "mero",
+ "symbol",
+ "soyombo",
+ "osmanya",
+ "indevanagari",
+ "unassigned",
+ "bengali",
+ "hebr",
+ "hebrew",
+ "inornamentaldingbats",
+ "invedicextensions",
+ "copt",
+ "ingreekextended",
+ "sund",
+ "cyprominoan",
+ "inherited",
+ "toto",
+ "inugaritic",
+ "syriac",
+ "cwt",
+ "inhebrew",
+ "runic",
+ "inmongoliansupplement",
+ "inshorthandformatcontrols",
+ "cypriot",
+ "cwcm",
+ "ingreekandcoptic",
+ "any",
+ "inolduyghur",
+ "inznamennymusicalnotation",
+ "lowercase",
+ "oldpermic",
+ "ingeorgian",
+ "ingurmukhi",
+ "emojimodifier",
+ "inkhojki",
+ "aghb",
+ "merc",
+ "inrejang",
+ "tamil",
+ "indevanagariextendeda",
+ "inalphabeticpresentationforms",
+ "hangul",
+ "inmeroitichieroglyphs",
+ "inkannada",
+ "hiragana",
+ "maka",
+ "inkanbun",
+ "insorasompeng",
+ "inmathematicaloperators",
+ "tayo",
+ "inhanunoo",
+ "multani",
+ "inkaithi",
+ "innushu",
+ "emojipresentation",
+ "insymbolsforlegacycomputing",
+ "meroiticcursive",
+ "grantha",
+ "inlinearbsyllabary",
+ "mult",
+ "taitham",
+ "nshu",
+ "incyrillicsupplement",
+ "dashpunctuation",
+ "inkatakana",
+ "inbatak",
+ "pi",
+ "mong",
+ "oldhungarian",
+ "phoenician",
+ "insmallformvariants",
+ "idsunaryoperator",
+ "variationselector",
+ "limbu",
+ "inyisyllables",
+ "diak",
+ "oldsoutharabian",
+ "lepc",
+ "inottomansiyaqnumbers",
+ "control",
+ "coptic",
+ "inkhmersymbols",
+ "titlecaseletter",
+ "inphagspa",
+ "bhks",
+ "gothic",
+ "sogo",
+ "elym",
+ "ps",
+ "prti",
+ "changeswhencasemapped",
+ "deseret",
+ "bhaiksuki",
+ "cyrl",
+ "olower",
+ "inchakma",
+ "wara",
+ "sogdian",
+ "graphemeclusterbreak=zwj",
+ "runr",
+ "changeswhentitlecased",
+ "incjkstrokes",
+ "incherokeesupplement",
+ "intangutcomponents",
+ "patws",
+ "batk",
+ "caseignorable",
+ "inkawi",
+ "indevanagariextended",
+ "indogra",
+ "intifinagh",
+ "print",
+ "cakm",
+ "graphemeclusterbreak=t",
+ "graphemeclusterbreak=lvt",
+ "inmendekikakui",
+ "inpsalterpahlavi",
+ "dogra",
+ "tangut",
+ "oalpha",
+ "intangutcomponentssupplement",
+ "idcompatmathcontinue",
+ "beriaerfe",
+ "ext",
+ "inkanasupplement",
+ "osge",
+ "inkanaextendeda",
+ "inverticalforms",
+ "decimalnumber",
+ "inkanaextendedb",
+ "idstrinaryoperator",
+ "tols",
+#endif /* USE_UNICODE_PROPERTIES */
+ "lower",
+#ifdef USE_UNICODE_PROPERTIES
+ "glag",
+ "inhanguljamo",
+ "insupplementalarrowsa",
+ "inmeeteimayek",
+ "insupplementalarrowsb",
+ "inunifiedcanadianaboriginalsyllabics",
+ "privateuse",
+ "inunifiedcanadianaboriginalsyllabicsextendeda",
+ "sentenceterminal",
+ "pcm",
+ "elymaic",
+ "cpmn",
+ "incjkcompatibilityforms",
+ "inphoneticextensions",
+ "incjkcompatibilityideographs",
+ "oldsogdian",
+ "inethiopicsupplement",
+ "graphemebase",
+ "intangutsupplement",
+ "tang",
+ "ideographic",
+ "nagmundari",
+ "sogd",
+ "psalterpahlavi",
+ "inphoneticextensionssupplement",
+ "tagb",
+ "invariationselectors",
+ "incjkcompatibilityideographssupplement",
+ "inindicsiyaqnumbers",
+ "khojki",
+ "inplayingcards",
+ "graphemeclusterbreak=extend",
+ "graphemeclusterbreak=prepend",
+ "space",
+ "tagbanwa",
+ "extpict",
+ "insupplementaryprivateuseareaa",
+ "insupplementalarrowsc",
+ "pd",
+ "insupplementaryprivateuseareab",
+ "innoblock",
+ "invariationselectorssupplement",
+ "inhanguljamoextendeda",
+ "kthi",
+ "inhanguljamoextendedb",
+ "sk",
+ "cherokee",
+ "nchar",
+ "pc",
+ "graphemeextend",
+ "wancho",
+ "inprivateusearea",
+ "sunuwar",
+ "ingothic",
+ "softdotted",
+ "lowercaseletter",
+ "phli",
+ "katakana",
+ "inunifiedcanadianaboriginalsyllabicsextended",
+ "hanifirohingya",
+ "palm",
+ "talu",
+ "inlisu",
+ "lu",
+ "invithkuqi",
+ "finalpunctuation",
+ "incyrillicextendeda",
+ "incyrillicextendedb",
+ "noncharactercodepoint",
+ "mark",
+ "medf",
+ "inkiratrai",
+ "intelugu",
+ "inmakasar",
+ "graphemeclusterbreak=l",
+ "inkharoshthi",
+ "graphemeclusterbreak=control",
+ "deprecated",
+ "insupplementalsymbolsandpictographs",
+ "tirh",
+ "sunu",
+ "letter",
+ "medefaidrin",
+ "beng",
+ "makasar",
+ "cwl",
+ "intakri",
+ "tavt",
+ "todr",
+ "todhri",
+ "insupplementalpunctuation",
+ "modifiersymbol",
+ "ogham",
+ "wcho",
+ "intagalog",
+ "omath",
+ "inkhmer",
+ "cf",
+ "bassavah",
+ "extendedpictographic",
+ "zyyy",
+ "incyrillicextendedc",
+ "ugaritic",
+ "goth",
+ "idcompatmathstart",
+ "divesakuru",
+ "wspace",
+ "geor",
+ "cyrillic",
+ "graphemeclusterbreak=cr",
+ "sorasompeng",
+ "graphemeclusterbreak=regionalindicator",
+ "tirhuta",
+ "inbopomofoextended",
+ "yezi",
+ "p",
+ "incyrillicextendedd",
+ "po",
+ "zp",
+ "dogr",
+ "dep",
+ "hung",
+ "term",
+ "deva",
+ "format",
+ "oldturkic",
+ "kayahli",
+ "devanagari",
+ "olck",
+ "dupl",
+ "incurrencysymbols",
+ "olchiki",
+ "inethiopicextendeda",
+ "inethiopicextendedb",
+ "phagspa",
+ "buhd",
+ "inhangulsyllables",
+ "inlatinextendedf",
+ "modifierletter",
+#endif /* USE_UNICODE_PROPERTIES */
+ "graph",
+#ifndef USE_UNICODE_PROPERTIES
+ "digit",
+ "blank"
+#else /* USE_UNICODE_PROPERTIES */
+ "ingaray",
+ "number",
+ "inkayahli",
+ "lepcha",
+ "plrd",
+ "incjksymbolsandpunctuation",
+ "ecomp",
+ "cuneiform",
+ "inglagolitic",
+ "gunjalagondi",
+ "bugi",
+ "takri",
+ "cprt",
+ "spaceseparator",
+ "ingurungkhema",
+ "incypriotsyllabary",
+ "inpaucinhau",
+ "gong",
+ "joinc",
+ "currencysymbol",
+ "rohg",
+ "logicalorderexception",
+ "grek",
+ "changeswhenlowercased",
+ "inpahawhhmong",
+ "yezidi",
+ "cwcf",
+ "extender",
+ "inhangulcompatibilityjamo",
+ "tulutigalari",
+ "terminalpunctuation",
+ "inkatakanaphoneticextensions",
+ "inethiopicextended",
+ "gujr",
+ "patsyn",
+ "ugar",
+ "word",
+ "berf",
+ "xpeo",
+ "regionalindicator",
+ "gujarati",
+ "buhid",
+ "inlatinextendedg",
+ "ethi",
+ "inkhitansmallscript",
+ "ingeorgiansupplement",
+ "inegyptianhieroglyphs",
+ "tifinagh",
+ "inegyptianhieroglyphsextendeda",
+ "inegyptianhieroglyphformatcontrols",
+ "inkhudawadi",
+ "incjkcompatibility",
+ "rjng",
+ "buginese",
+ "mendekikakui",
+ "letternumber",
+ "phlp",
+ "separator",
+ "pauc",
+ "vithkuqi",
+ "inkangxiradicals",
+ "changeswhencasefolded",
+ "graphemeclusterbreak=lf",
+ "joincontrol",
+ "inmeroiticcursive",
+ "pe",
+ "patternwhitespace",
+ "duployan",
+ "phag",
+ "meeteimayek",
+ "innyiakengpuachuehmong",
+ "incjkunifiedideographsextensioni",
+ "incjkunifiedideographs",
+ "incjkunifiedideographsextensionj",
+ "georgian",
+ "incjkunifiedideographsextensiona",
+ "incjkunifiedideographsextensionb",
+ "warangciti",
+ "inhighprivateusesurrogates",
+ "meroitichieroglyphs",
+ "java",
+ "garay",
+ "nonspacingmark",
+ "otheridstart",
+ "otheridcontinue",
+ "xsux",
+ "phnx",
+ "incjkunifiedideographsextensione",
+ "signwriting",
+ "tolongsiki",
+ "incjkunifiedideographsextensionc",
+ "combiningmark",
+ "nushu",
+ "takr",
+ "tfng",
+ "changeswhenuppercased",
+ "inglagoliticsupplement",
+ "surrogate",
+ "orkh",
+ "graphemeclusterbreak=v",
+ "graphemeclusterbreak=lv",
+ "incjkunifiedideographsextensiond",
+ "telu",
+ "inhalfwidthandfullwidthforms",
+ "otheralphabetic",
+ "unknown",
+ "punct",
+ "tglg",
+ "javanese",
+ "otherdefaultignorablecodepoint",
+ "cwu",
+ "rejang",
+ "egyp",
+ "perm",
+ "othersymbol",
+ "epres",
+ "olduyghur",
+ "tutg",
+ "enclosingmark",
+ "ingeorgianextended",
+ "ogrext",
+ "indivesakuru",
+ "otherlowercase",
+ "other",
+ "othernumber",
+ "hexdigit",
+ "incjkradicalssupplement",
+ "blank",
+ "ethiopic",
+ "graphemeclusterbreak=spacingmark",
+ "spacingmark",
+ "tagalog",
+ "batak",
+ "guru",
+ "hex",
+ "paucinhau",
+ "modifiercombiningmark",
+ "otherpunctuation",
+ "ougr",
+ "palmyrene",
+ "othermath",
+ "incjkunifiedideographsextensionh",
+ "inboxdrawing",
+ "patternsyntax",
+ "oupper",
+ "gurungkhema",
+ "prependedconcatenationmark",
+ "otherletter",
+ "pf",
+ "qmark",
+ "inhighsurrogates",
+ "xposixpunct",
+ "otheruppercase",
+ "incjkunifiedideographsextensionf",
+ "punctuation",
+ "incjkunifiedideographsextensiong",
+ "egyptianhieroglyphs",
+ "defaultignorablecodepoint",
+ "quotationmark",
+ "openpunctuation",
+ "unifiedideograph",
+ "greek",
+ "othergraphemeextend",
+ "inkaktoviknumerals",
+ "uppercase",
+ "grlink",
+ "nyiakengpuachuehmong",
+ "gukh",
+ "pahawhhmong",
+ "upper",
+ "uppercaseletter",
+ "graphemelink",
+ "telugu",
+ "gurmukhi",
+ "paragraphseparator"
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+#define uniname2ctype_pool ((const char *) &uniname2ctype_pool_contents)
+const struct uniname2ctype_struct *
+uniname2ctype_p (register const char *str, register size_t len)
+{
+ static const struct uniname2ctype_struct wordlist[] =
+ {
+#ifdef USE_UNICODE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str10), 35},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str16), 31},
+ {-1}, {-1},
+ {uniname2ctype_offset(str19), 34},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str24), 27},
+ {-1}, {-1},
+ {uniname2ctype_offset(str27), 606},
+ {uniname2ctype_offset(str28), 354},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str33), 192},
+ {uniname2ctype_offset(str34), 192},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str38), 288},
+ {-1},
+ {uniname2ctype_offset(str40), 98},
+ {uniname2ctype_offset(str41), 98},
+ {-1}, {-1},
+ {uniname2ctype_offset(str44), 203},
+ {uniname2ctype_offset(str45), 120},
+ {-1},
+ {uniname2ctype_offset(str47), 176},
+ {uniname2ctype_offset(str48), 113},
+ {-1},
+ {uniname2ctype_offset(str50), 613},
+ {uniname2ctype_offset(str51), 113},
+ {uniname2ctype_offset(str52), 189},
+ {uniname2ctype_offset(str53), 187},
+ {-1}, {-1},
+ {uniname2ctype_offset(str56), 575},
+ {uniname2ctype_offset(str57), 120},
+ {uniname2ctype_offset(str58), 123},
+ {uniname2ctype_offset(str59), 125},
+ {uniname2ctype_offset(str60), 539},
+ {-1},
+ {uniname2ctype_offset(str62), 13},
+ {uniname2ctype_offset(str63), 164},
+ {uniname2ctype_offset(str64), 227},
+ {-1}, {-1},
+ {uniname2ctype_offset(str67), 82},
+ {-1},
+ {uniname2ctype_offset(str69), 155},
+ {uniname2ctype_offset(str70), 218},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str74), 518},
+#endif /* USE_UNICODE_PROPERTIES */
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#ifndef USE_UNICODE_PROPERTIES
+ {uniname2ctype_offset(str6), 12},
+ {uniname2ctype_offset(str7), 7},
+ {uniname2ctype_offset(str8), 15},
+ {uniname2ctype_offset(str9), 1},
+ {uniname2ctype_offset(str10), 13},
+ {uniname2ctype_offset(str11), 11},
+ {uniname2ctype_offset(str12), 10},
+ {uniname2ctype_offset(str13), 14},
+ {uniname2ctype_offset(str14), 3},
+ {uniname2ctype_offset(str15), 9},
+ {uniname2ctype_offset(str16), 8},
+ {uniname2ctype_offset(str17), 6},
+ {uniname2ctype_offset(str18), 5},
+ {uniname2ctype_offset(str19), 4},
+ {uniname2ctype_offset(str20), 2}
+#else /* USE_UNICODE_PROPERTIES */
+ {uniname2ctype_offset(str81), 355},
+ {uniname2ctype_offset(str82), 587},
+ {uniname2ctype_offset(str83), 82},
+ {-1},
+ {uniname2ctype_offset(str85), 50},
+ {-1}, {-1},
+ {uniname2ctype_offset(str88), 589},
+ {uniname2ctype_offset(str89), 47},
+ {uniname2ctype_offset(str90), 529},
+ {-1},
+ {uniname2ctype_offset(str92), 55},
+ {uniname2ctype_offset(str93), 338},
+ {-1}, {-1},
+ {uniname2ctype_offset(str96), 415},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str102), 84},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str107), 631},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str115), 79},
+ {-1},
+ {uniname2ctype_offset(str117), 370},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str124), 79},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str135), 127},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str141), 44},
+ {-1}, {-1},
+ {uniname2ctype_offset(str144), 205},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str149), 71},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str155), 353},
+ {-1},
+ {uniname2ctype_offset(str157), 643},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str164), 194},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str169), 394},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str175), 493},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str180), 429},
+ {uniname2ctype_offset(str181), 499},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str186), 67},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str190), 264},
+ {uniname2ctype_offset(str191), 348},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str195), 270},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str199), 662},
+ {-1}, {-1},
+ {uniname2ctype_offset(str202), 614},
+ {uniname2ctype_offset(str203), 540},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str209), 342},
+ {-1},
+ {uniname2ctype_offset(str211), 520},
+ {-1},
+ {uniname2ctype_offset(str213), 420},
+ {-1},
+ {uniname2ctype_offset(str215), 130},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str219), 161},
+ {uniname2ctype_offset(str220), 477},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str227), 444},
+ {uniname2ctype_offset(str228), 171},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str235), 271},
+ {-1},
+ {uniname2ctype_offset(str237), 181},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str242), 172},
+ {-1},
+ {uniname2ctype_offset(str244), 660},
+ {-1}, {-1},
+ {uniname2ctype_offset(str247), 468},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str257), 372},
+ {uniname2ctype_offset(str258), 350},
+ {-1},
+ {uniname2ctype_offset(str260), 194},
+ {uniname2ctype_offset(str261), 21},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str267), 506},
+ {uniname2ctype_offset(str268), 61},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str274), 14},
+ {uniname2ctype_offset(str275), 289},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str279), 263},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str284), 571},
+ {uniname2ctype_offset(str285), 147},
+ {uniname2ctype_offset(str286), 147},
+ {uniname2ctype_offset(str287), 154},
+ {-1},
+ {uniname2ctype_offset(str289), 478},
+ {-1},
+ {uniname2ctype_offset(str291), 227},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str295), 476},
+ {-1}, {-1},
+ {uniname2ctype_offset(str298), 172},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str310), 105},
+ {-1},
+ {uniname2ctype_offset(str312), 551},
+ {-1}, {-1},
+ {uniname2ctype_offset(str315), 230},
+ {-1},
+ {uniname2ctype_offset(str317), 568},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str333), 173},
+ {-1},
+ {uniname2ctype_offset(str335), 596},
+ {uniname2ctype_offset(str336), 284},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str340), 23},
+ {-1},
+ {uniname2ctype_offset(str342), 200},
+ {-1},
+ {uniname2ctype_offset(str344), 127},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str359), 501},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str364), 667},
+ {-1},
+ {uniname2ctype_offset(str366), 157},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str373), 423},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str384), 36},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str395), 177},
+ {-1}, {-1},
+ {uniname2ctype_offset(str398), 425},
+ {-1},
+ {uniname2ctype_offset(str400), 427},
+ {-1},
+ {uniname2ctype_offset(str402), 248},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str406), 431},
+ {uniname2ctype_offset(str407), 433},
+ {-1}, {-1},
+ {uniname2ctype_offset(str410), 84},
+ {-1},
+ {uniname2ctype_offset(str412), 659},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str416), 18},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str424), 25},
+ {uniname2ctype_offset(str425), 32},
+ {uniname2ctype_offset(str426), 611},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str432), 574},
+ {uniname2ctype_offset(str433), 397},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str438), 655},
+ {-1},
+ {uniname2ctype_offset(str440), 668},
+ {uniname2ctype_offset(str441), 644},
+ {-1}, {-1},
+ {uniname2ctype_offset(str444), 511},
+ {-1}, {-1},
+ {uniname2ctype_offset(str447), 465},
+ {uniname2ctype_offset(str448), 76},
+ {-1}, {-1},
+ {uniname2ctype_offset(str451), 277},
+ {uniname2ctype_offset(str452), 356},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str456), 628},
+ {-1},
+ {uniname2ctype_offset(str458), 143},
+ {uniname2ctype_offset(str459), 143},
+ {uniname2ctype_offset(str460), 24},
+ {uniname2ctype_offset(str461), 480},
+ {uniname2ctype_offset(str462), 37},
+ {uniname2ctype_offset(str463), 53},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str468), 26},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str472), 371},
+ {uniname2ctype_offset(str473), 186},
+ {-1}, {-1},
+ {uniname2ctype_offset(str476), 68},
+ {uniname2ctype_offset(str477), 391},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str483), 646},
+ {-1},
+ {uniname2ctype_offset(str485), 48},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str491), 516},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str496), 597},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str502), 243},
+ {-1}, {-1},
+ {uniname2ctype_offset(str505), 359},
+ {-1}, {-1},
+ {uniname2ctype_offset(str508), 544},
+ {-1},
+ {uniname2ctype_offset(str510), 157},
+ {uniname2ctype_offset(str511), 358},
+ {uniname2ctype_offset(str512), 368},
+ {uniname2ctype_offset(str513), 138},
+ {uniname2ctype_offset(str514), 111},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str523), 650},
+ {-1},
+ {uniname2ctype_offset(str525), 68},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str549), 570},
+ {-1},
+ {uniname2ctype_offset(str551), 365},
+ {-1},
+ {uniname2ctype_offset(str553), 564},
+ {uniname2ctype_offset(str554), 591},
+ {-1},
+ {uniname2ctype_offset(str556), 232},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str571), 77},
+ {-1}, {-1},
+ {uniname2ctype_offset(str574), 248},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str584), 199},
+ {-1}, {-1},
+ {uniname2ctype_offset(str587), 419},
+ {uniname2ctype_offset(str588), 533},
+ {-1}, {-1},
+ {uniname2ctype_offset(str591), 96},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str605), 340},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str617), 341},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str622), 209},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str630), 209},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str635), 524},
+ {-1},
+ {uniname2ctype_offset(str637), 595},
+ {uniname2ctype_offset(str638), 396},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str645), 343},
+ {-1}, {-1},
+ {uniname2ctype_offset(str648), 550},
+ {-1},
+ {uniname2ctype_offset(str650), 508},
+ {-1}, {-1},
+ {uniname2ctype_offset(str653), 139},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str665), 110},
+ {-1},
+ {uniname2ctype_offset(str667), 19},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str674), 623},
+ {uniname2ctype_offset(str675), 390},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str681), 118},
+ {uniname2ctype_offset(str682), 373},
+ {-1},
+ {uniname2ctype_offset(str684), 193},
+ {-1}, {-1},
+ {uniname2ctype_offset(str687), 416},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str701), 187},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str707), 125},
+ {-1},
+ {uniname2ctype_offset(str709), 561},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str716), 548},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str721), 215},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str727), 205},
+ {-1},
+ {uniname2ctype_offset(str729), 94},
+ {uniname2ctype_offset(str730), 159},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str734), 239},
+ {uniname2ctype_offset(str735), 532},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str747), 159},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str751), 165},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str760), 38},
+ {-1},
+ {uniname2ctype_offset(str762), 253},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str766), 28},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str780), 228},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str784), 244},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str788), 489},
+ {uniname2ctype_offset(str789), 94},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str795), 503},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str799), 414},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str803), 60},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str809), 448},
+ {uniname2ctype_offset(str810), 612},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str815), 53},
+ {-1},
+ {uniname2ctype_offset(str817), 52},
+ {uniname2ctype_offset(str818), 627},
+ {-1},
+ {uniname2ctype_offset(str820), 381},
+ {uniname2ctype_offset(str821), 509},
+ {-1},
+ {uniname2ctype_offset(str823), 482},
+ {-1},
+ {uniname2ctype_offset(str825), 588},
+ {-1},
+ {uniname2ctype_offset(str827), 51},
+ {uniname2ctype_offset(str828), 211},
+ {uniname2ctype_offset(str829), 91},
+ {uniname2ctype_offset(str830), 554},
+ {-1},
+ {uniname2ctype_offset(str832), 114},
+ {uniname2ctype_offset(str833), 351},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str838), 114},
+ {-1},
+ {uniname2ctype_offset(str840), 1},
+ {-1},
+ {uniname2ctype_offset(str842), 132},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str852), 403},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str857), 128},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str880), 418},
+ {-1}, {-1},
+ {uniname2ctype_offset(str883), 67},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str890), 454},
+ {uniname2ctype_offset(str891), 435},
+ {-1}, {-1},
+ {uniname2ctype_offset(str894), 117},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str898), 275},
+ {-1}, {-1},
+ {uniname2ctype_offset(str901), 230},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str909), 152},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str919), 579},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str923), 139},
+ {uniname2ctype_offset(str924), 577},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str929), 531},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str940), 149},
+ {-1},
+ {uniname2ctype_offset(str942), 538},
+ {-1},
+ {uniname2ctype_offset(str944), 273},
+ {uniname2ctype_offset(str945), 152},
+ {-1},
+ {uniname2ctype_offset(str947), 270},
+ {-1},
+ {uniname2ctype_offset(str949), 177},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str954), 537},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str966), 264},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str970), 95},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str975), 118},
+ {-1}, {-1},
+ {uniname2ctype_offset(str978), 507},
+ {-1},
+ {uniname2ctype_offset(str980), 346},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str985), 542},
+ {-1}, {-1},
+ {uniname2ctype_offset(str988), 581},
+ {-1},
+ {uniname2ctype_offset(str990), 541},
+ {uniname2ctype_offset(str991), 364},
+ {-1}, {-1},
+ {uniname2ctype_offset(str994), 151},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str999), 380},
+ {-1},
+ {uniname2ctype_offset(str1001), 188},
+ {-1},
+ {uniname2ctype_offset(str1003), 184},
+ {-1},
+ {uniname2ctype_offset(str1005), 560},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1009), 22},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1012), 104},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1016), 57},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1021), 369},
+ {uniname2ctype_offset(str1022), 191},
+ {-1},
+ {uniname2ctype_offset(str1024), 556},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1028), 278},
+ {-1},
+ {uniname2ctype_offset(str1030), 151},
+ {uniname2ctype_offset(str1031), 188},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1036), 78},
+ {uniname2ctype_offset(str1037), 647},
+ {uniname2ctype_offset(str1038), 546},
+ {-1},
+ {uniname2ctype_offset(str1040), 608},
+ {uniname2ctype_offset(str1041), 96},
+ {uniname2ctype_offset(str1042), 279},
+ {-1},
+ {uniname2ctype_offset(str1044), 408},
+ {uniname2ctype_offset(str1045), 457},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1048), 515},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1056), 253},
+ {uniname2ctype_offset(str1057), 56},
+ {uniname2ctype_offset(str1058), 352},
+ {uniname2ctype_offset(str1059), 97},
+ {-1},
+ {uniname2ctype_offset(str1061), 466},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1064), 249},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1068), 160},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1072), 236},
+ {uniname2ctype_offset(str1073), 378},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1077), 86},
+ {-1},
+ {uniname2ctype_offset(str1079), 153},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1087), 464},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1090), 108},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1094), 630},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1102), 29},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1105), 138},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1109), 86},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1113), 213},
+ {-1},
+ {uniname2ctype_offset(str1115), 153},
+ {-1},
+ {uniname2ctype_offset(str1117), 603},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {-1}, {-1},
+ {uniname2ctype_offset(str1120), 316},
+ {uniname2ctype_offset(str1121), 315},
+ {uniname2ctype_offset(str1122), 318},
+ {uniname2ctype_offset(str1123), 317},
+ {-1},
+ {uniname2ctype_offset(str1125), 297},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1126), 467},
+ {uniname2ctype_offset(str1127), 204},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1128), 299},
+ {uniname2ctype_offset(str1129), 298},
+ {uniname2ctype_offset(str1130), 320},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1131), 236},
+ {uniname2ctype_offset(str1132), 255},
+ {uniname2ctype_offset(str1133), 344},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1134), 324},
+ {uniname2ctype_offset(str1135), 304},
+ {uniname2ctype_offset(str1136), 303},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1137), 99},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1138), 322},
+ {uniname2ctype_offset(str1139), 321},
+ {uniname2ctype_offset(str1140), 312},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1141), 400},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1142), 314},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1143), 413},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1144), 306},
+ {uniname2ctype_offset(str1145), 305},
+ {uniname2ctype_offset(str1146), 323},
+ {uniname2ctype_offset(str1147), 307},
+ {uniname2ctype_offset(str1148), 313},
+ {-1},
+ {uniname2ctype_offset(str1150), 319},
+ {uniname2ctype_offset(str1151), 309},
+ {uniname2ctype_offset(str1152), 308},
+ {-1},
+ {uniname2ctype_offset(str1154), 310},
+ {uniname2ctype_offset(str1155), 301},
+ {uniname2ctype_offset(str1156), 300},
+ {-1},
+ {uniname2ctype_offset(str1158), 302},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1159), 653},
+ {uniname2ctype_offset(str1160), 171},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1170), 99},
+ {-1},
+ {uniname2ctype_offset(str1172), 163},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1175), 436},
+ {uniname2ctype_offset(str1176), 189},
+#ifndef USE_UNICODE_AGE_PROPERTIES
+ {-1}, {-1}, {-1}, {-1}, {-1},
+#else /* USE_UNICODE_AGE_PROPERTIES */
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1181), 311},
+#endif /* USE_UNICODE_AGE_PROPERTIES */
+ {uniname2ctype_offset(str1182), 290},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1187), 280},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1191), 407},
+ {uniname2ctype_offset(str1192), 272},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1195), 148},
+ {uniname2ctype_offset(str1196), 513},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1199), 42},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1209), 496},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1214), 510},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1221), 183},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1225), 11},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1228), 3},
+ {uniname2ctype_offset(str1229), 161},
+ {uniname2ctype_offset(str1230), 69},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1239), 545},
+ {-1},
+ {uniname2ctype_offset(str1241), 72},
+ {uniname2ctype_offset(str1242), 109},
+ {uniname2ctype_offset(str1243), 283},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1249), 130},
+ {-1},
+ {uniname2ctype_offset(str1251), 384},
+ {uniname2ctype_offset(str1252), 183},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1259), 218},
+ {uniname2ctype_offset(str1260), 636},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1264), 421},
+ {uniname2ctype_offset(str1265), 75},
+ {-1},
+ {uniname2ctype_offset(str1267), 156},
+ {-1},
+ {uniname2ctype_offset(str1269), 555},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1272), 376},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1275), 208},
+ {-1},
+ {uniname2ctype_offset(str1277), 115},
+ {-1},
+ {uniname2ctype_offset(str1279), 238},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1285), 73},
+ {uniname2ctype_offset(str1286), 204},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1292), 523},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1299), 261},
+ {-1},
+ {uniname2ctype_offset(str1301), 33},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1312), 185},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1315), 199},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1321), 657},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1324), 124},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1328), 240},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1332), 102},
+ {-1},
+ {uniname2ctype_offset(str1334), 166},
+ {uniname2ctype_offset(str1335), 387},
+ {uniname2ctype_offset(str1336), 645},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1339), 136},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1347), 590},
+ {-1},
+ {uniname2ctype_offset(str1349), 363},
+ {uniname2ctype_offset(str1350), 361},
+ {uniname2ctype_offset(str1351), 232},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1357), 70},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1362), 566},
+ {uniname2ctype_offset(str1363), 562},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1368), 40},
+ {-1},
+ {uniname2ctype_offset(str1370), 528},
+ {uniname2ctype_offset(str1371), 395},
+ {uniname2ctype_offset(str1372), 69},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1375), 70},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1397), 632},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1401), 505},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1407), 607},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1415), 680},
+ {uniname2ctype_offset(str1416), 399},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1420), 180},
+ {uniname2ctype_offset(str1421), 136},
+ {-1},
+ {uniname2ctype_offset(str1423), 292},
+ {-1},
+ {uniname2ctype_offset(str1425), 521},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1429), 385},
+ {uniname2ctype_offset(str1430), 190},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1433), 212},
+ {-1},
+ {uniname2ctype_offset(str1435), 598},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1447), 169},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1453), 615},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1456), 100},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1462), 519},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1467), 654},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1470), 95},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1473), 178},
+ {uniname2ctype_offset(str1474), 393},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1479), 293},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1489), 625},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1497), 424},
+ {uniname2ctype_offset(str1498), 410},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1503), 100},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1510), 339},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1515), 115},
+ {uniname2ctype_offset(str1516), 92},
+ {uniname2ctype_offset(str1517), 504},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1528), 585},
+ {-1},
+ {uniname2ctype_offset(str1530), 50},
+ {-1},
+ {uniname2ctype_offset(str1532), 389},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1535), 462},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1551), 294},
+ {uniname2ctype_offset(str1552), 638},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1572), 4},
+ {uniname2ctype_offset(str1573), 133},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1581), 517},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1588), 552},
+ {uniname2ctype_offset(str1589), 426},
+ {uniname2ctype_offset(str1590), 164},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1598), 567},
+ {-1},
+ {uniname2ctype_offset(str1600), 599},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1606), 134},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1614), 293},
+ {uniname2ctype_offset(str1615), 635},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1618), 605},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1626), 241},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1633), 357},
+ {uniname2ctype_offset(str1634), 25},
+ {-1},
+ {uniname2ctype_offset(str1636), 296},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1639), 446},
+ {uniname2ctype_offset(str1640), 124},
+ {uniname2ctype_offset(str1641), 105},
+ {uniname2ctype_offset(str1642), 261},
+ {-1},
+ {uniname2ctype_offset(str1644), 634},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1648), 580},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1654), 460},
+ {uniname2ctype_offset(str1655), 167},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1668), 663},
+ {uniname2ctype_offset(str1669), 530},
+ {uniname2ctype_offset(str1670), 17},
+ {uniname2ctype_offset(str1671), 479},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1674), 85},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1682), 112},
+ {-1},
+ {uniname2ctype_offset(str1684), 569},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1688), 193},
+ {-1},
+ {uniname2ctype_offset(str1690), 432},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1694), 112},
+ {-1},
+ {uniname2ctype_offset(str1696), 244},
+ {uniname2ctype_offset(str1697), 475},
+ {uniname2ctype_offset(str1698), 586},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1707), 637},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1713), 527},
+ {uniname2ctype_offset(str1714), 108},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1724), 215},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1727), 256},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1731), 411},
+ {-1},
+ {uniname2ctype_offset(str1733), 658},
+ {-1},
+ {uniname2ctype_offset(str1735), 664},
+ {-1},
+ {uniname2ctype_offset(str1737), 470},
+ {uniname2ctype_offset(str1738), 106},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1746), 91},
+ {-1},
+ {uniname2ctype_offset(str1748), 148},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1754), 211},
+ {uniname2ctype_offset(str1755), 144},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1762), 200},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1773), 217},
+ {-1},
+ {uniname2ctype_offset(str1775), 252},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1778), 274},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1785), 137},
+ {-1},
+ {uniname2ctype_offset(str1787), 549},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1790), 243},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1793), 594},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1796), 175},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1800), 47},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str1811), 217},
+ {uniname2ctype_offset(str1812), 128},
+ {-1},
+ {uniname2ctype_offset(str1814), 360},
+ {-1},
+ {uniname2ctype_offset(str1816), 21},
+ {-1},
+ {uniname2ctype_offset(str1818), 88},
+ {uniname2ctype_offset(str1819), 83},
+ {-1},
+ {uniname2ctype_offset(str1821), 83},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1824), 661},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1829), 404},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1834), 132},
+ {-1},
+ {uniname2ctype_offset(str1836), 409},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1839), 144},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1847), 234},
+ {uniname2ctype_offset(str1848), 118},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1854), 237},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1858), 514},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1863), 85},
+ {uniname2ctype_offset(str1864), 64},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1867), 349},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1872), 107},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1877), 572},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1884), 626},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1900), 129},
+ {uniname2ctype_offset(str1901), 66},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1910), 345},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1920), 16},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1923), 553},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1936), 629},
+ {uniname2ctype_offset(str1937), 58},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1941), 197},
+ {-1},
+ {uniname2ctype_offset(str1943), 374},
+ {-1},
+ {uniname2ctype_offset(str1945), 362},
+ {-1},
+ {uniname2ctype_offset(str1947), 292},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1956), 563},
+ {-1},
+ {uniname2ctype_offset(str1958), 180},
+ {-1},
+ {uniname2ctype_offset(str1960), 174},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1966), 473},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1969), 92},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1972), 584},
+ {-1},
+ {uniname2ctype_offset(str1974), 492},
+ {uniname2ctype_offset(str1975), 102},
+ {-1},
+ {uniname2ctype_offset(str1977), 534},
+ {uniname2ctype_offset(str1978), 367},
+ {uniname2ctype_offset(str1979), 110},
+ {uniname2ctype_offset(str1980), 221},
+ {-1}, {-1},
+ {uniname2ctype_offset(str1983), 450},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str1987), 558},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2001), 417},
+ {uniname2ctype_offset(str2002), 249},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2005), 383},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2010), 206},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2015), 557},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2022), 624},
+ {uniname2ctype_offset(str2023), 291},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2028), 669},
+ {uniname2ctype_offset(str2029), 174},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2037), 184},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2040), 502},
+ {uniname2ctype_offset(str2041), 206},
+ {uniname2ctype_offset(str2042), 155},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2047), 216},
+ {-1},
+ {uniname2ctype_offset(str2049), 347},
+ {-1},
+ {uniname2ctype_offset(str2051), 41},
+ {-1},
+ {uniname2ctype_offset(str2053), 447},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2056), 398},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2059), 44},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2064), 109},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2074), 207},
+ {-1},
+ {uniname2ctype_offset(str2076), 141},
+ {uniname2ctype_offset(str2077), 498},
+ {uniname2ctype_offset(str2078), 272},
+ {-1},
+ {uniname2ctype_offset(str2080), 284},
+ {uniname2ctype_offset(str2081), 123},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2085), 459},
+ {-1},
+ {uniname2ctype_offset(str2087), 231},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2090), 165},
+ {-1},
+ {uniname2ctype_offset(str2092), 145},
+ {uniname2ctype_offset(str2093), 652},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2097), 19},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2102), 132},
+ {-1},
+ {uniname2ctype_offset(str2104), 392},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2107), 29},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2110), 469},
+ {uniname2ctype_offset(str2111), 210},
+ {-1},
+ {uniname2ctype_offset(str2113), 116},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2117), 225},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2122), 226},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2131), 46},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2137), 166},
+ {uniname2ctype_offset(str2138), 66},
+ {-1},
+ {uniname2ctype_offset(str2140), 117},
+ {-1},
+ {uniname2ctype_offset(str2142), 210},
+ {uniname2ctype_offset(str2143), 81},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2147), 266},
+ {uniname2ctype_offset(str2148), 559},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2152), 202},
+ {uniname2ctype_offset(str2153), 224},
+ {-1},
+ {uniname2ctype_offset(str2155), 337},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2164), 107},
+ {uniname2ctype_offset(str2165), 64},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2168), 452},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2176), 483},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2179), 616},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2182), 285},
+ {uniname2ctype_offset(str2183), 170},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2186), 61},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2191), 593},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2199), 471},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2203), 576},
+ {uniname2ctype_offset(str2204), 438},
+ {-1},
+ {uniname2ctype_offset(str2206), 7},
+ {uniname2ctype_offset(str2207), 173},
+ {-1},
+ {uniname2ctype_offset(str2209), 334},
+ {-1},
+ {uniname2ctype_offset(str2211), 336},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2214), 649},
+ {-1},
+ {uniname2ctype_offset(str2216), 543},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2224), 219},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2228), 214},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2235), 262},
+ {-1},
+ {uniname2ctype_offset(str2237), 619},
+ {-1},
+ {uniname2ctype_offset(str2239), 281},
+ {-1},
+ {uniname2ctype_offset(str2241), 251},
+ {-1},
+ {uniname2ctype_offset(str2243), 265},
+ {uniname2ctype_offset(str2244), 621},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2247), 213},
+ {uniname2ctype_offset(str2248), 622},
+ {uniname2ctype_offset(str2249), 495},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2252), 36},
+ {-1},
+ {uniname2ctype_offset(str2254), 620},
+ {uniname2ctype_offset(str2255), 271},
+ {-1},
+ {uniname2ctype_offset(str2257), 250},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2260), 6},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2270), 134},
+ {-1},
+ {uniname2ctype_offset(str2272), 375},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2279), 428},
+ {-1},
+ {uniname2ctype_offset(str2281), 484},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2285), 430},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2288), 379},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2296), 22},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2299), 582},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2302), 283},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2308), 287},
+ {uniname2ctype_offset(str2309), 226},
+ {uniname2ctype_offset(str2310), 234},
+ {-1},
+ {uniname2ctype_offset(str2312), 497},
+ {uniname2ctype_offset(str2313), 405},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2317), 491},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2320), 225},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2341), 377},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2345), 73},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2350), 618},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2353), 214},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2361), 263},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2364), 240},
+ {-1},
+ {uniname2ctype_offset(str2366), 224},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2370), 198},
+ {uniname2ctype_offset(str2371), 406},
+ {-1},
+ {uniname2ctype_offset(str2373), 122},
+ {uniname2ctype_offset(str2374), 494},
+ {uniname2ctype_offset(str2375), 676},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2379), 651},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2389), 186},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2392), 656},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2396), 329},
+ {uniname2ctype_offset(str2397), 325},
+ {uniname2ctype_offset(str2398), 9},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2401), 122},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2416), 295},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2421), 682},
+ {uniname2ctype_offset(str2422), 665},
+ {-1},
+ {uniname2ctype_offset(str2424), 41},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2427), 683},
+ {uniname2ctype_offset(str2428), 684},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2432), 681},
+ {uniname2ctype_offset(str2433), 474},
+ {uniname2ctype_offset(str2434), 169},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2439), 486},
+ {uniname2ctype_offset(str2440), 49},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2443), 104},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2451), 268},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2458), 40},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2466), 72},
+ {-1},
+ {uniname2ctype_offset(str2468), 229},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2473), 490},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2483), 245},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2491), 512},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2495), 277},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2503), 26},
+ {-1},
+ {uniname2ctype_offset(str2505), 167},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2518), 111},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2526), 388},
+ {-1},
+ {uniname2ctype_offset(str2528), 223},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2532), 195},
+ {-1},
+ {uniname2ctype_offset(str2534), 133},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2541), 461},
+ {-1},
+ {uniname2ctype_offset(str2543), 30},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2553), 522},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2570), 43},
+ {uniname2ctype_offset(str2571), 440},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2577), 463},
+ {-1},
+ {uniname2ctype_offset(str2579), 268},
+ {-1},
+ {uniname2ctype_offset(str2581), 31},
+ {uniname2ctype_offset(str2582), 222},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2590), 610},
+ {uniname2ctype_offset(str2591), 366},
+ {uniname2ctype_offset(str2592), 592},
+ {uniname2ctype_offset(str2593), 332},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2596), 536},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2599), 328},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2603), 276},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2612), 666},
+ {uniname2ctype_offset(str2613), 201},
+ {uniname2ctype_offset(str2614), 245},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2618), 24},
+ {uniname2ctype_offset(str2619), 222},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2625), 88},
+ {uniname2ctype_offset(str2626), 221},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2632), 62},
+ {uniname2ctype_offset(str2633), 573},
+ {uniname2ctype_offset(str2634), 156},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2658), 246},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2668), 246},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2671), 441},
+ {uniname2ctype_offset(str2672), 49},
+ {uniname2ctype_offset(str2673), 106},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2679), 229},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2688), 382},
+ {uniname2ctype_offset(str2689), 259},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2699), 386},
+ {uniname2ctype_offset(str2700), 20},
+ {uniname2ctype_offset(str2701), 181},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2705), 295},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2708), 78},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2714), 401},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str2725), 126},
+ {uniname2ctype_offset(str2726), 116},
+ {-1},
+ {uniname2ctype_offset(str2728), 282},
+ {uniname2ctype_offset(str2729), 231},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2732), 252},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2737), 101},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2764), 81},
+ {uniname2ctype_offset(str2765), 326},
+ {-1},
+ {uniname2ctype_offset(str2767), 178},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2780), 330},
+ {-1},
+ {uniname2ctype_offset(str2782), 201},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2791), 451},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2796), 233},
+ {-1},
+ {uniname2ctype_offset(str2798), 39},
+ {uniname2ctype_offset(str2799), 641},
+ {uniname2ctype_offset(str2800), 45},
+ {uniname2ctype_offset(str2801), 54},
+ {uniname2ctype_offset(str2802), 219},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2806), 276},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2813), 207},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2819), 258},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2826), 87},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2831), 20},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2835), 168},
+ {uniname2ctype_offset(str2836), 149},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2844), 87},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2850), 146},
+ {-1},
+ {uniname2ctype_offset(str2852), 182},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2857), 412},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2861), 146},
+ {-1},
+ {uniname2ctype_offset(str2863), 481},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2869), 648},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2872), 142},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2877), 121},
+ {uniname2ctype_offset(str2878), 485},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2881), 525},
+ {-1},
+ {uniname2ctype_offset(str2883), 27},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str2894), 5},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2897), 547},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2900), 35},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2910), 472},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2922), 145},
+ {-1}, {-1},
+ {uniname2ctype_offset(str2925), 176},
+ {uniname2ctype_offset(str2926), 445},
+ {-1},
+ {uniname2ctype_offset(str2928), 294},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2947), 140},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2953), 434},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2960), 220},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2970), 131},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2984), 179},
+ {-1},
+ {uniname2ctype_offset(str2986), 129},
+ {uniname2ctype_offset(str2987), 55},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str2991), 604},
+ {-1},
+ {uniname2ctype_offset(str2993), 526},
+ {-1},
+ {uniname2ctype_offset(str2995), 583},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3005), 220},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3013), 254},
+ {-1},
+ {uniname2ctype_offset(str3015), 48},
+ {-1},
+ {uniname2ctype_offset(str3017), 223},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3021), 278},
+ {uniname2ctype_offset(str3022), 80},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3041), 62},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3049), 609},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3052), 233},
+ {-1},
+ {uniname2ctype_offset(str3054), 65},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3061), 265},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3068), 449},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3078), 247},
+ {-1},
+ {uniname2ctype_offset(str3080), 258},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3086), 453},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3090), 439},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3097), 90},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3103), 286},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3107), 126},
+ {uniname2ctype_offset(str3108), 12},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3112), 251},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3121), 137},
+ {uniname2ctype_offset(str3122), 288},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3127), 90},
+ {uniname2ctype_offset(str3128), 121},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3137), 639},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3142), 103},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3165), 617},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3169), 437},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3177), 600},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3184), 135},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3188), 602},
+ {-1},
+ {uniname2ctype_offset(str3190), 601},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3221), 565},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3231), 455},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3238), 150},
+ {-1},
+ {uniname2ctype_offset(str3240), 131},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3245), 190},
+ {-1},
+ {uniname2ctype_offset(str3247), 37},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3257), 198},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3261), 52},
+ {-1},
+ {uniname2ctype_offset(str3263), 196},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3281), 238},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3287), 443},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3291), 65},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str3302), 327},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3307), 254},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3326), 535},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3334), 42},
+ {uniname2ctype_offset(str3335), 285},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3357), 182},
+ {-1},
+ {uniname2ctype_offset(str3359), 142},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3363), 163},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3407), 642},
+ {uniname2ctype_offset(str3408), 675},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3414), 458},
+ {-1},
+ {uniname2ctype_offset(str3416), 679},
+ {-1},
+ {uniname2ctype_offset(str3418), 101},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3426), 456},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3432), 670},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3436), 202},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3444), 488},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3469), 175},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3481), 162},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3493), 241},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3497), 34},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3505), 279},
+ {-1},
+ {uniname2ctype_offset(str3507), 280},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3516), 140},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3532), 141},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3535), 673},
+ {uniname2ctype_offset(str3536), 208},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3543), 250},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3569), 671},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3579), 31},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3585), 216},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3598), 179},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3613), 135},
+ {uniname2ctype_offset(str3614), 63},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3622), 640},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3629), 23},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3647), 168},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3650), 333},
+ {uniname2ctype_offset(str3651), 335},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3654), 672},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3666), 93},
+ {-1}, {-1},
+ {uniname2ctype_offset(str3669), 500},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3686), 262},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3690), 296},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3699), 15},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3718), 119},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3733), 162},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3770), 275},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3778), 63},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3782), 150},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3813), 158},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3835), 197},
+ {uniname2ctype_offset(str3836), 51},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3869), 291},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3877), 235},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3894), 247},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3901), 33},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3918), 402},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3945), 269},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str3965), 578},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3972), 266},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3981), 18},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str3995), 38},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4007), 260},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str4018), 442},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4035), 2},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str4064), 103},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4069), 331},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4072), 32},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4089), 119},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4102), 170},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4110), 89},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4117), 260},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4140), 196},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4153), 289},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4163), 45},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4180), 235},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4228), 195},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4318), 259},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4353), 678},
+ {uniname2ctype_offset(str4354), 422},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str4401), 286},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4404), 267},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4410), 242},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4414), 287},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4439), 28},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4491), 43},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4494), 257},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4543), 487},
+ {uniname2ctype_offset(str4544), 8},
+ {uniname2ctype_offset(str4545), 267},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4564), 674},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4670), 39},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4692), 677},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str4731), 158},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4775), 71},
+ {-1},
+ {uniname2ctype_offset(str4777), 257},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4800), 46},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4851), 274},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4941), 80},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str4985), 269},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5002), 633},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5234), 59},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5271), 74},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5290), 228},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str5329), 242},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1},
+ {uniname2ctype_offset(str5512), 185},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5557), 10},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5800), 30},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1},
+ {uniname2ctype_offset(str5919), 74},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str5981), 93},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str6036), 89},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1},
+ {uniname2ctype_offset(str6068), 54}
+#endif /* USE_UNICODE_PROPERTIES */
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = uniname2ctype_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register int o = wordlist[key].name;
+ if (o >= 0)
+ {
+ register const char *s = o + uniname2ctype_pool;
+
+ if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+ return &wordlist[key];
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+uniname2ctype(const UChar *name, unsigned int len)
+{
+ const struct uniname2ctype_struct *p = uniname2ctype_p((const char *)name, len);
+ if (p) return p->ctype;
+ return -1;
+}
+#if defined ONIG_UNICODE_VERSION_STRING && !( \
+ ONIG_UNICODE_VERSION_MAJOR == 17 && \
+ ONIG_UNICODE_VERSION_MINOR == 0 && \
+ ONIG_UNICODE_VERSION_TEENY == 0 && \
+ 1)
+# error ONIG_UNICODE_VERSION_STRING mismatch
+#endif
+#define ONIG_UNICODE_VERSION_STRING "17.0.0"
+#define ONIG_UNICODE_VERSION_MAJOR 17
+#define ONIG_UNICODE_VERSION_MINOR 0
+#define ONIG_UNICODE_VERSION_TEENY 0
+#if defined ONIG_UNICODE_EMOJI_VERSION_STRING && !( \
+ ONIG_UNICODE_EMOJI_VERSION_MAJOR == 17 && \
+ ONIG_UNICODE_EMOJI_VERSION_MINOR == 0 && \
+ 1)
+# error ONIG_UNICODE_EMOJI_VERSION_STRING mismatch
+#endif
+#define ONIG_UNICODE_EMOJI_VERSION_STRING "17.0"
+#define ONIG_UNICODE_EMOJI_VERSION_MAJOR 17
+#define ONIG_UNICODE_EMOJI_VERSION_MINOR 0
diff --git a/enc/us_ascii.c b/enc/us_ascii.c
index 08f9072c43..253ee69572 100644
--- a/enc/us_ascii.c
+++ b/enc/us_ascii.c
@@ -32,7 +32,11 @@ OnigEncodingDefine(us_ascii, US_ASCII) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_single_byte_ascii_only_case_map,
+#else
+ NULL,
+#endif
ENCINDEX_US_ASCII,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/utf_16be.c b/enc/utf_16be.c
index f9dd7119d6..0086040b5d 100644
--- a/enc/utf_16be.c
+++ b/enc/utf_16be.c
@@ -249,7 +249,11 @@ OnigEncodingDefine(utf_16be, UTF_16BE) = {
onigenc_utf16_32_get_ctype_code_range,
utf16be_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_16le.c b/enc/utf_16le.c
index 2c8438d0be..ca0fce5387 100644
--- a/enc/utf_16le.c
+++ b/enc/utf_16le.c
@@ -242,7 +242,11 @@ OnigEncodingDefine(utf_16le, UTF_16LE) = {
onigenc_utf16_32_get_ctype_code_range,
utf16le_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_32be.c b/enc/utf_32be.c
index 17841e52a4..e05cfaf1b2 100644
--- a/enc/utf_32be.c
+++ b/enc/utf_32be.c
@@ -199,7 +199,11 @@ OnigEncodingDefine(utf_32be, UTF_32BE) = {
onigenc_utf16_32_get_ctype_code_range,
utf32be_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_32le.c b/enc/utf_32le.c
index 18b798f102..651efdcec5 100644
--- a/enc/utf_32le.c
+++ b/enc/utf_32le.c
@@ -199,7 +199,11 @@ OnigEncodingDefine(utf_32le, UTF_32LE) = {
onigenc_utf16_32_get_ctype_code_range,
utf32le_left_adjust_char_head,
onigenc_always_false_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/utf_8.c b/enc/utf_8.c
index cdf2510d84..ae7c98469d 100644
--- a/enc/utf_8.c
+++ b/enc/utf_8.c
@@ -431,7 +431,11 @@ OnigEncodingDefine(utf_8, UTF_8) = {
get_ctype_code_range,
left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_unicode_case_map,
+#else
+ NULL,
+#endif
ENCINDEX_UTF_8,
ONIGENC_FLAG_UNICODE,
};
diff --git a/enc/windows_1250.c b/enc/windows_1250.c
index daf23e9d1e..d38d50a01d 100644
--- a/enc/windows_1250.c
+++ b/enc/windows_1250.c
@@ -190,6 +190,7 @@ cp1250_get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -239,6 +240,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1250, Windows_1250) = {
onigenc_single_byte_mbc_enc_len,
@@ -257,7 +259,11 @@ OnigEncodingDefine(windows_1250, Windows_1250) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1251.c b/enc/windows_1251.c
index 6c892c1b8c..81641d0337 100644
--- a/enc/windows_1251.c
+++ b/enc/windows_1251.c
@@ -180,6 +180,7 @@ cp1251_get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -221,6 +222,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1251, Windows_1251) = {
onigenc_single_byte_mbc_enc_len,
@@ -239,7 +241,11 @@ OnigEncodingDefine(windows_1251, Windows_1251) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1252.c b/enc/windows_1252.c
index b685878d3f..6aece95c0a 100644
--- a/enc/windows_1252.c
+++ b/enc/windows_1252.c
@@ -181,6 +181,7 @@ cp1252_get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -228,6 +229,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1252, Windows_1252) = {
onigenc_single_byte_mbc_enc_len,
@@ -246,7 +248,11 @@ OnigEncodingDefine(windows_1252, Windows_1252) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1253.c b/enc/windows_1253.c
index b2a43581c3..c95ea3f41c 100644
--- a/enc/windows_1253.c
+++ b/enc/windows_1253.c
@@ -213,6 +213,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
static int
case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
@@ -272,6 +273,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1253, Windows_1253) = {
onigenc_single_byte_mbc_enc_len,
@@ -290,7 +292,11 @@ OnigEncodingDefine(windows_1253, Windows_1253) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1254.c b/enc/windows_1254.c
index 5e6d92d3d2..c8d5991686 100644
--- a/enc/windows_1254.c
+++ b/enc/windows_1254.c
@@ -221,6 +221,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xFD)
#define I_WITH_DOT_ABOVE (0xDD)
static int
@@ -277,6 +278,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1254, Windows_1254) = {
onigenc_single_byte_mbc_enc_len,
@@ -295,7 +297,11 @@ OnigEncodingDefine(windows_1254, Windows_1254) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_1257.c b/enc/windows_1257.c
index ada03b72bf..def13c8c49 100644
--- a/enc/windows_1257.c
+++ b/enc/windows_1257.c
@@ -225,6 +225,7 @@ get_case_fold_codes_by_str(OnigCaseFoldType flag,
flag, p, end, items);
}
+#ifdef USE_CASE_MAP_API
#define DOTLESS_i (0xB9)
#define I_WITH_DOT_ABOVE (0xA9)
static int
@@ -279,6 +280,7 @@ case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
*flagP = flags;
return (int )(to - to_start);
}
+#endif
OnigEncodingDefine(windows_1257, Windows_1257) = {
onigenc_single_byte_mbc_enc_len,
@@ -297,7 +299,11 @@ OnigEncodingDefine(windows_1257, Windows_1257) = {
onigenc_not_support_get_ctype_code_range,
onigenc_single_byte_left_adjust_char_head,
onigenc_always_true_is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/enc/windows_31j.c b/enc/windows_31j.c
index 1eb859596a..cd8bd83fdd 100644
--- a/enc/windows_31j.c
+++ b/enc/windows_31j.c
@@ -48,7 +48,11 @@ OnigEncodingDefine(windows_31j, Windows_31J) = {
get_ctype_code_range,
left_adjust_char_head,
is_allowed_reverse_match,
+#ifdef USE_CASE_MAP_API
onigenc_ascii_only_case_map,
+#else
+ NULL,
+#endif
0,
ONIGENC_FLAG_NONE,
};
diff --git a/encoding.c b/encoding.c
index e6b49ef145..c17f118eef 100644
--- a/encoding.c
+++ b/encoding.c
@@ -24,10 +24,13 @@
#include "internal/string.h"
#include "internal/vm.h"
#include "regenc.h"
+#include "ruby/atomic.h"
#include "ruby/encoding.h"
#include "ruby/util.h"
+#include "ruby/ractor.h"
#include "ruby_assert.h"
#include "vm_sync.h"
+#include "ruby_atomic.h"
#ifndef ENC_DEBUG
#define ENC_DEBUG 0
@@ -53,13 +56,14 @@ int rb_encdb_alias(const char *alias, const char *orig);
#pragma GCC visibility pop
#endif
-static ID id_encoding;
+static ID id_encoding, id_i_name;
VALUE rb_cEncoding;
#define ENCODING_LIST_CAPA 256
static VALUE rb_encoding_list;
struct rb_encoding_entry {
+ rb_atomic_t loaded;
const char *name;
rb_encoding *enc;
rb_encoding *base;
@@ -93,15 +97,14 @@ static rb_encoding *global_enc_ascii,
*global_enc_utf_8,
*global_enc_us_ascii;
-#define GLOBAL_ENC_TABLE_ENTER(enc_table) struct enc_table *enc_table = &global_enc_table; RB_VM_LOCK_ENTER()
-#define GLOBAL_ENC_TABLE_LEAVE() RB_VM_LOCK_LEAVE()
-#define GLOBAL_ENC_TABLE_EVAL(enc_table, expr) do { \
- GLOBAL_ENC_TABLE_ENTER(enc_table); \
- { \
- expr; \
- } \
- GLOBAL_ENC_TABLE_LEAVE(); \
-} while (0)
+static int filesystem_encindex = ENCINDEX_ASCII_8BIT;
+static rb_atomic_t locale_alias_registered;
+
+#define GLOBAL_ENC_TABLE_LOCKING(tbl) \
+ for (struct enc_table *tbl = &global_enc_table, **locking = &tbl; \
+ locking; \
+ locking = NULL) \
+ RB_VM_LOCKING()
#define ENC_DUMMY_FLAG (1<<24)
@@ -123,8 +126,9 @@ static const rb_data_type_t encoding_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
-#define is_data_encoding(obj) (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj) == &encoding_data_type)
-#define is_obj_encoding(obj) (RB_TYPE_P((obj), T_DATA) && is_data_encoding(obj))
+#define is_encoding_type(obj) (RTYPEDDATA_TYPE(obj) == &encoding_data_type)
+#define is_data_encoding(obj) is_encoding_type(obj)
+#define is_obj_encoding(obj) (rbimpl_obj_typeddata_p(obj) && is_encoding_type(obj))
int
rb_data_is_encoding(VALUE obj)
@@ -136,8 +140,8 @@ static VALUE
enc_new(rb_encoding *encoding)
{
VALUE enc = TypedData_Wrap_Struct(rb_cEncoding, &encoding_data_type, (void *)encoding);
- rb_obj_freeze(enc);
- FL_SET_RAW(enc, RUBY_FL_SHAREABLE);
+ rb_ivar_set(enc, id_i_name, rb_fstring_cstr(encoding->name));
+ RB_OBJ_SET_FROZEN_SHAREABLE(enc);
return enc;
}
@@ -146,10 +150,16 @@ enc_list_update(int index, rb_raw_encoding *encoding)
{
RUBY_ASSERT(index < ENCODING_LIST_CAPA);
- VALUE list = rb_encoding_list;
+ VALUE list = RUBY_ATOMIC_VALUE_LOAD(rb_encoding_list);
+
if (list && NIL_P(rb_ary_entry(list, index))) {
+ VALUE new_list = rb_ary_dup(list);
+ RBASIC_CLEAR_CLASS(new_list);
/* initialize encoding data */
- rb_ary_store(list, index, enc_new(encoding));
+ rb_ary_store(new_list, index, enc_new(encoding));
+ rb_ary_freeze(new_list);
+ FL_SET_RAW(new_list, RUBY_FL_SHAREABLE);
+ RUBY_ATOMIC_VALUE_SET(rb_encoding_list, new_list);
}
}
@@ -159,7 +169,7 @@ enc_list_lookup(int idx)
VALUE list, enc = Qnil;
if (idx < ENCODING_LIST_CAPA) {
- list = rb_encoding_list;
+ list = RUBY_ATOMIC_VALUE_LOAD(rb_encoding_list);
RUBY_ASSERT(list);
enc = rb_ary_entry(list, idx);
}
@@ -217,7 +227,7 @@ enc_check_encoding(VALUE obj)
if (!is_obj_encoding(obj)) {
return -1;
}
- return check_encoding(RDATA(obj)->data);
+ return check_encoding(RTYPEDDATA_GET_DATA(obj));
}
NORETURN(static void not_encoding(VALUE enc));
@@ -235,7 +245,7 @@ must_encoding(VALUE enc)
if (index < 0) {
not_encoding(enc);
}
- return DATA_PTR(enc);
+ return RTYPEDDATA_GET_DATA(enc);
}
static rb_encoding *
@@ -246,20 +256,21 @@ must_encindex(int index)
rb_raise(rb_eEncodingError, "encoding index out of bound: %d",
index);
}
- if (ENC_TO_ENCINDEX(enc) != (int)(index & ENC_INDEX_MASK)) {
- rb_raise(rb_eEncodingError, "wrong encoding index %d for %s (expected %d)",
- index, rb_enc_name(enc), ENC_TO_ENCINDEX(enc));
- }
if (rb_enc_autoload_p(enc) && rb_enc_autoload(enc) == -1) {
rb_loaderror("failed to load encoding (%s)",
rb_enc_name(enc));
}
+ if (ENC_TO_ENCINDEX(enc) != (int)(index & ENC_INDEX_MASK)) {
+ rb_raise(rb_eEncodingError, "wrong encoding index %d for %s (expected %d)",
+ index, rb_enc_name(enc), ENC_TO_ENCINDEX(enc));
+ }
return enc;
}
int
rb_to_encoding_index(VALUE enc)
{
+ ASSERT_vm_unlocking(); // can load encoding, so must not hold VM lock
int idx;
const char *name;
@@ -322,7 +333,7 @@ str_to_encoding(VALUE enc)
rb_encoding *
rb_to_encoding(VALUE enc)
{
- if (enc_check_encoding(enc) >= 0) return RDATA(enc)->data;
+ if (enc_check_encoding(enc) >= 0) return RTYPEDDATA_GET_DATA(enc);
return str_to_encoding(enc);
}
@@ -330,7 +341,7 @@ rb_encoding *
rb_find_encoding(VALUE enc)
{
int idx;
- if (enc_check_encoding(enc) >= 0) return RDATA(enc)->data;
+ if (enc_check_encoding(enc) >= 0) return RTYPEDDATA_GET_DATA(enc);
idx = str_find_encindex(enc);
if (idx < 0) return NULL;
return rb_enc_from_index(idx);
@@ -345,41 +356,81 @@ enc_table_expand(struct enc_table *enc_table, int newsize)
return newsize;
}
+/* Load an encoding using the values from base_encoding */
+static void
+enc_load_from_base(struct enc_table *enc_table, int index, rb_encoding *base_encoding)
+{
+ ASSERT_vm_locking();
+
+ struct rb_encoding_entry *ent = &enc_table->list[index];
+
+ if (ent->loaded) {
+ return;
+ }
+
+ rb_raw_encoding *encoding = (rb_raw_encoding *)ent->enc;
+ RUBY_ASSERT(encoding);
+
+ // FIXME: Before the base is loaded, the encoding may be accessed
+ // concurrently by other Ractors.
+ // We're copying all fields from base_encoding except name and
+ // ruby_encoding_index which we preserve from the original. Since these are
+ // the only fields other threads should read it is likely safe despite
+ // technically being a data race.
+ rb_raw_encoding tmp_encoding = *base_encoding;
+ tmp_encoding.name = encoding->name;
+ tmp_encoding.ruby_encoding_index = encoding->ruby_encoding_index;
+ *encoding = tmp_encoding;
+
+ RUBY_ATOMIC_SET(ent->loaded, encoding->max_enc_len);
+}
+
static int
enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_encoding *base_encoding)
{
+ ASSERT_vm_locking();
+
struct rb_encoding_entry *ent = &enc_table->list[index];
rb_raw_encoding *encoding;
- if (!valid_encoding_name_p(name)) return -1;
- if (!ent->name) {
- ent->name = name = strdup(name);
- }
- else if (STRCASECMP(name, ent->name)) {
- return -1;
- }
- encoding = (rb_raw_encoding *)ent->enc;
- if (!encoding) {
- encoding = xmalloc(sizeof(rb_encoding));
+ RUBY_ASSERT(!ent->loaded);
+ RUBY_ASSERT(!ent->name);
+ RUBY_ASSERT(!ent->enc);
+ RUBY_ASSERT(!ent->base);
+
+ RUBY_ASSERT(valid_encoding_name_p(name));
+
+ ent->name = name = strdup(name);
+
+ encoding = ZALLOC(rb_raw_encoding);
+ encoding->name = name;
+ encoding->ruby_encoding_index = index;
+ ent->enc = encoding;
+
+ if (st_insert(enc_table->names, (st_data_t)name, (st_data_t)index)) {
+ rb_bug("encoding name was somehow registered twice");
}
+
+ enc_list_update(index, encoding);
+
if (base_encoding) {
- *encoding = *base_encoding;
+ enc_load_from_base(enc_table, index, base_encoding);
}
else {
- memset(encoding, 0, sizeof(*ent->enc));
+ /* it should not be loaded yet */
+ RUBY_ASSERT(!encoding->max_enc_len);
}
- encoding->name = name;
- encoding->ruby_encoding_index = index;
- ent->enc = encoding;
- st_insert(enc_table->names, (st_data_t)name, (st_data_t)index);
- enc_list_update(index, encoding);
return index;
}
static int
enc_register(struct enc_table *enc_table, const char *name, rb_encoding *encoding)
{
+ ASSERT_vm_locking();
+
+ if (!valid_encoding_name_p(name)) return -1;
+
int index = enc_table->count;
enc_table->count = enc_table_expand(enc_table, index + 1);
@@ -395,7 +446,9 @@ enc_from_index(struct enc_table *enc_table, int index)
if (UNLIKELY(index < 0 || enc_table->count <= (index &= ENC_INDEX_MASK))) {
return 0;
}
- return enc_table->list[index].enc;
+ rb_encoding *enc = enc_table->list[index].enc;
+ RUBY_ASSERT(ENC_TO_ENCINDEX(enc) == index);
+ return enc;
}
rb_encoding *
@@ -409,8 +462,7 @@ rb_enc_register(const char *name, rb_encoding *encoding)
{
int index;
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
index = enc_registered(enc_table, name);
if (index >= 0) {
@@ -419,7 +471,7 @@ rb_enc_register(const char *name, rb_encoding *encoding)
index = enc_register(enc_table, name, encoding);
}
else if (rb_enc_autoload_p(oldenc) || !ENC_DUMMY_P(oldenc)) {
- enc_register_at(enc_table, index, name, encoding);
+ enc_load_from_base(enc_table, index, encoding);
}
else {
rb_raise(rb_eArgError, "encoding %s is already registered", name);
@@ -430,13 +482,13 @@ rb_enc_register(const char *name, rb_encoding *encoding)
set_encoding_const(name, rb_enc_from_index(index));
}
}
- GLOBAL_ENC_TABLE_LEAVE();
return index;
}
int
enc_registered(struct enc_table *enc_table, const char *name)
{
+ ASSERT_vm_locking();
st_data_t idx = 0;
if (!name) return -1;
@@ -447,18 +499,26 @@ enc_registered(struct enc_table *enc_table, const char *name)
return -1;
}
+int
+rb_enc_registered(const char *name)
+{
+ int idx;
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ idx = enc_registered(enc_table, name);
+ }
+ return idx;
+}
+
void
rb_encdb_declare(const char *name)
{
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
int idx = enc_registered(enc_table, name);
if (idx < 0) {
idx = enc_register(enc_table, name, 0);
}
set_encoding_const(name, rb_enc_from_index(idx));
}
- GLOBAL_ENC_TABLE_LEAVE();
}
static void
@@ -490,13 +550,11 @@ set_base_encoding(struct enc_table *enc_table, int index, rb_encoding *base)
void
rb_enc_set_base(const char *name, const char *orig)
{
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
int idx = enc_registered(enc_table, name);
int origidx = enc_registered(enc_table, orig);
set_base_encoding(enc_table, idx, rb_enc_from_index(origidx));
}
- GLOBAL_ENC_TABLE_LEAVE();
}
/* for encdb.h
@@ -530,7 +588,7 @@ enc_replicate_with_index(struct enc_table *enc_table, const char *name, rb_encod
idx = enc_register(enc_table, name, origenc);
}
else {
- idx = enc_register_at(enc_table, idx, name, origenc);
+ enc_load_from_base(enc_table, idx, origenc);
}
if (idx >= 0) {
set_base_encoding(enc_table, idx, origenc);
@@ -547,8 +605,7 @@ rb_encdb_replicate(const char *name, const char *orig)
{
int r;
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
int origidx = enc_registered(enc_table, orig);
int idx = enc_registered(enc_table, name);
@@ -557,7 +614,6 @@ rb_encdb_replicate(const char *name, const char *orig)
}
r = enc_replicate_with_index(enc_table, name, rb_enc_from_index(origidx), idx);
}
- GLOBAL_ENC_TABLE_LEAVE();
return r;
}
@@ -567,13 +623,11 @@ rb_define_dummy_encoding(const char *name)
{
int index;
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
index = enc_replicate(enc_table, name, rb_ascii8bit_encoding());
rb_encoding *enc = enc_table->list[index].enc;
ENC_SET_DUMMY((rb_raw_encoding *)enc);
}
- GLOBAL_ENC_TABLE_LEAVE();
return index;
}
@@ -583,15 +637,13 @@ rb_encdb_dummy(const char *name)
{
int index;
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
index = enc_replicate_with_index(enc_table, name,
rb_ascii8bit_encoding(),
enc_registered(enc_table, name));
rb_encoding *enc = enc_table->list[index].enc;
ENC_SET_DUMMY((rb_raw_encoding *)enc);
}
- GLOBAL_ENC_TABLE_LEAVE();
return index;
}
@@ -653,6 +705,7 @@ enc_dup_name(st_data_t name)
static int
enc_alias_internal(struct enc_table *enc_table, const char *alias, int idx)
{
+ ASSERT_vm_locking();
return st_insert2(enc_table->names, (st_data_t)alias, (st_data_t)idx,
enc_dup_name);
}
@@ -670,18 +723,16 @@ int
rb_enc_alias(const char *alias, const char *orig)
{
int idx, r;
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ enc_check_addable(enc_table, alias); // can raise
+ }
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
- enc_check_addable(enc_table, alias);
- if ((idx = rb_enc_find_index(orig)) < 0) {
- r = -1;
- }
- else {
- r = enc_alias(enc_table, alias, idx);
- }
+ idx = rb_enc_find_index(orig);
+ if (idx < 0) return -1;
+
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ r = enc_alias(enc_table, alias, idx);
}
- GLOBAL_ENC_TABLE_LEAVE();
return r;
}
@@ -691,8 +742,7 @@ rb_encdb_alias(const char *alias, const char *orig)
{
int r;
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
int idx = enc_registered(enc_table, orig);
if (idx < 0) {
@@ -700,7 +750,6 @@ rb_encdb_alias(const char *alias, const char *orig)
}
r = enc_alias(enc_table, alias, idx);
}
- GLOBAL_ENC_TABLE_LEAVE();
return r;
}
@@ -708,6 +757,7 @@ rb_encdb_alias(const char *alias, const char *orig)
static void
rb_enc_init(struct enc_table *enc_table)
{
+ ASSERT_vm_locking();
enc_table_expand(enc_table, ENCODING_COUNT + 1);
if (!enc_table->names) {
enc_table->names = st_init_strcasetable_with_size(ENCODING_LIST_CAPA);
@@ -748,6 +798,7 @@ int rb_require_internal_silent(VALUE fname);
static int
load_encoding(const char *name)
{
+ ASSERT_vm_unlocking();
VALUE enclib = rb_sprintf("enc/%s.so", name);
VALUE debug = ruby_debug;
VALUE errinfo;
@@ -763,12 +814,11 @@ load_encoding(const char *name)
enclib = rb_fstring(enclib);
ruby_debug = Qfalse;
errinfo = rb_errinfo();
- loaded = rb_require_internal_silent(enclib);
+ loaded = rb_require_internal_silent(enclib); // must run without VM_LOCK
ruby_debug = debug;
rb_set_errinfo(errinfo);
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
if (loaded < 0 || 1 < loaded) {
idx = -1;
}
@@ -779,51 +829,73 @@ load_encoding(const char *name)
idx = -1;
}
}
- GLOBAL_ENC_TABLE_LEAVE();
return idx;
}
static int
-enc_autoload_body(struct enc_table *enc_table, rb_encoding *enc)
+enc_autoload_body(rb_encoding *enc)
{
- rb_encoding *base = enc_table->list[ENC_TO_ENCINDEX(enc)].base;
+ rb_encoding *base;
+ int i = 0;
+ ASSERT_vm_unlocking();
+
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ base = enc_table->list[ENC_TO_ENCINDEX(enc)].base;
+ }
if (base) {
- int i = 0;
- do {
- if (i >= enc_table->count) return -1;
- } while (enc_table->list[i].enc != base && (++i, 1));
+ bool do_register = true;
if (rb_enc_autoload_p(base)) {
- if (rb_enc_autoload(base) < 0) return -1;
+ if (rb_enc_autoload(base) < 0) {
+ do_register = false;
+ i = -1;
+ }
+ }
+
+ if (do_register) {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ i = ENC_TO_ENCINDEX(enc);
+ enc_load_from_base(enc_table, i, base);
+ RUBY_ASSERT(((rb_raw_encoding *)enc)->ruby_encoding_index == i);
+ }
}
- i = enc->ruby_encoding_index;
- enc_register_at(enc_table, i & ENC_INDEX_MASK, rb_enc_name(enc), base);
- ((rb_raw_encoding *)enc)->ruby_encoding_index = i;
- i &= ENC_INDEX_MASK;
- return i;
}
else {
- return -2;
+ i = -2;
}
+
+ return i;
}
int
rb_enc_autoload(rb_encoding *enc)
{
- int i;
- GLOBAL_ENC_TABLE_EVAL(enc_table, i = enc_autoload_body(enc_table, enc));
+ ASSERT_vm_unlocking();
+ int i = enc_autoload_body(enc);
if (i == -2) {
i = load_encoding(rb_enc_name(enc));
}
return i;
}
+bool
+rb_enc_autoload_p(rb_encoding *enc)
+{
+ int idx = ENC_TO_ENCINDEX(enc);
+ RUBY_ASSERT(rb_enc_from_index(idx) == enc);
+ return !RUBY_ATOMIC_LOAD(global_enc_table.list[idx].loaded);
+}
+
/* Return encoding index or UNSPECIFIED_ENCODING from encoding name */
int
rb_enc_find_index(const char *name)
{
- int i = enc_registered(&global_enc_table, name);
+ int i;
+ ASSERT_vm_unlocking(); // it needs to be unlocked so it can call `load_encoding` if necessary
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ i = enc_registered(enc_table, name);
+ }
rb_encoding *enc;
if (i < 0) {
@@ -996,7 +1068,6 @@ rb_enc_associate_index(VALUE obj, int idx)
rb_encoding *enc;
int oldidx, oldtermlen, termlen;
-/* enc_check_capable(obj);*/
rb_check_frozen(obj);
oldidx = rb_enc_get_index(obj);
if (oldidx == idx)
@@ -1154,9 +1225,12 @@ rb_enc_copy(VALUE obj1, VALUE obj2)
/*
* call-seq:
- * obj.encoding -> encoding
+ * encoding -> encoding
+ *
+ * Returns an Encoding object that represents the encoding of +self+;
+ * see {Encodings}[rdoc-ref:encodings.rdoc].
*
- * Returns the Encoding object that represents the encoding of obj.
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
VALUE
@@ -1273,10 +1347,10 @@ enc_inspect(VALUE self)
{
rb_encoding *enc;
- if (!is_data_encoding(self)) {
+ if (!is_obj_encoding(self)) { /* do not resolve autoload */
not_encoding(self);
}
- if (!(enc = DATA_PTR(self)) || rb_enc_from_index(rb_enc_to_index(enc)) != enc) {
+ if (!(enc = RTYPEDDATA_GET_DATA(self)) || rb_enc_from_index(rb_enc_to_index(enc)) != enc) {
rb_raise(rb_eTypeError, "broken Encoding");
}
@@ -1287,20 +1361,6 @@ enc_inspect(VALUE self)
rb_enc_autoload_p(enc) ? " (autoload)" : "");
}
-/*
- * call-seq:
- * enc.name -> string
- * enc.to_s -> string
- *
- * Returns the name of the encoding.
- *
- * Encoding::UTF_8.name #=> "UTF-8"
- */
-static VALUE
-enc_name(VALUE self)
-{
- return rb_fstring_cstr(rb_enc_name((rb_encoding*)DATA_PTR(self)));
-}
static int
enc_names_i(st_data_t name, st_data_t idx, st_data_t args)
@@ -1329,7 +1389,10 @@ enc_names(VALUE self)
args[0] = (VALUE)rb_to_encoding_index(self);
args[1] = rb_ary_new2(0);
- st_foreach(global_enc_table.names, enc_names_i, (st_data_t)args);
+
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ st_foreach(enc_table->names, enc_names_i, (st_data_t)args);
+ }
return args[1];
}
@@ -1354,9 +1417,8 @@ enc_names(VALUE self)
static VALUE
enc_list(VALUE klass)
{
- VALUE ary = rb_ary_new2(0);
- rb_ary_replace(ary, rb_encoding_list);
- return ary;
+ VALUE list = RUBY_ATOMIC_VALUE_LOAD(rb_encoding_list);
+ return rb_ary_dup(list);
}
/*
@@ -1442,7 +1504,7 @@ static VALUE
enc_dump(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 1);
- return enc_name(self);
+ return rb_attr_get(self, id_i_name);
}
/* :nodoc: */
@@ -1500,20 +1562,24 @@ int rb_locale_charmap_index(void);
int
rb_locale_encindex(void)
{
+ // `rb_locale_charmap_index` can call `enc_find_index`, which can
+ // load an encoding. This needs to be done without VM lock held.
+ ASSERT_vm_unlocking();
int idx = rb_locale_charmap_index();
if (idx < 0) idx = ENCINDEX_UTF_8;
- if (enc_registered(&global_enc_table, "locale") < 0) {
+ if (!RUBY_ATOMIC_LOAD(locale_alias_registered)) {
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ if (enc_registered(enc_table, "locale") < 0) {
# if defined _WIN32
- void Init_w32_codepage(void);
- Init_w32_codepage();
+ void Init_w32_codepage(void);
+ Init_w32_codepage();
# endif
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
- enc_alias_internal(enc_table, "locale", idx);
+ enc_alias_internal(enc_table, "locale", idx);
+ }
+ RUBY_ATOMIC_SET(locale_alias_registered, 1);
}
- GLOBAL_ENC_TABLE_LEAVE();
}
return idx;
@@ -1528,9 +1594,7 @@ rb_locale_encoding(void)
int
rb_filesystem_encindex(void)
{
- int idx = enc_registered(&global_enc_table, "filesystem");
- if (idx < 0) idx = ENCINDEX_ASCII_8BIT;
- return idx;
+ return filesystem_encindex;
}
rb_encoding *
@@ -1555,8 +1619,13 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
/* Already set */
overridden = TRUE;
- GLOBAL_ENC_TABLE_ENTER(enc_table);
- {
+ int index = 0;
+ if (!NIL_P(encoding)) {
+ enc_check_encoding(encoding); // loads it if necessary. Needs to be done outside of VM lock.
+ index = rb_enc_to_index(rb_to_encoding(encoding));
+ }
+
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
if (NIL_P(encoding)) {
def->index = -1;
def->enc = 0;
@@ -1571,16 +1640,17 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
(st_data_t)UNSPECIFIED_ENCODING);
}
else {
- def->index = rb_enc_to_index(rb_to_encoding(encoding));
+ def->index = index;
def->enc = 0;
enc_alias_internal(enc_table, name, def->index);
}
if (def == &default_external) {
- enc_alias_internal(enc_table, "filesystem", Init_enc_set_filesystem_encoding());
+ int fs_idx = Init_enc_set_filesystem_encoding();
+ enc_alias_internal(enc_table, "filesystem", fs_idx);
+ filesystem_encindex = fs_idx;
}
}
- GLOBAL_ENC_TABLE_LEAVE();
return overridden;
}
@@ -1827,8 +1897,11 @@ rb_enc_name_list_i(st_data_t name, st_data_t idx, st_data_t arg)
static VALUE
rb_enc_name_list(VALUE klass)
{
- VALUE ary = rb_ary_new2(global_enc_table.names->num_entries);
- st_foreach(global_enc_table.names, rb_enc_name_list_i, (st_data_t)ary);
+ VALUE ary;
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ ary = rb_ary_new2(enc_table->names->num_entries);
+ st_foreach(enc_table->names, rb_enc_name_list_i, (st_data_t)ary);
+ }
return ary;
}
@@ -1874,7 +1947,9 @@ rb_enc_aliases(VALUE klass)
aliases[0] = rb_hash_new();
aliases[1] = rb_ary_new();
- st_foreach(global_enc_table.names, rb_enc_aliases_enc_i, (st_data_t)aliases);
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ st_foreach(enc_table->names, rb_enc_aliases_enc_i, (st_data_t)aliases);
+ }
return aliases[0];
}
@@ -1916,12 +1991,19 @@ Init_Encoding(void)
VALUE list;
int i;
+ id_i_name = rb_intern_const("@name");
rb_cEncoding = rb_define_class("Encoding", rb_cObject);
rb_define_alloc_func(rb_cEncoding, enc_s_alloc);
rb_undef_method(CLASS_OF(rb_cEncoding), "new");
- rb_define_method(rb_cEncoding, "to_s", enc_name, 0);
+
+ /* The name of the encoding.
+ *
+ * Encoding::UTF_8.name #=> "UTF-8"
+ */
+ rb_attr(rb_cEncoding, rb_intern("name"), TRUE, FALSE, Qfalse);
+ rb_define_alias(rb_cEncoding, "to_s", "name");
+
rb_define_method(rb_cEncoding, "inspect", enc_inspect, 0);
- rb_define_method(rb_cEncoding, "name", enc_name, 0);
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);
@@ -1942,9 +2024,9 @@ Init_Encoding(void)
struct enc_table *enc_table = &global_enc_table;
+ rb_gc_register_address(&rb_encoding_list);
list = rb_encoding_list = rb_ary_new2(ENCODING_LIST_CAPA);
RBASIC_CLEAR_CLASS(list);
- rb_vm_register_global_object(list);
for (i = 0; i < enc_table->count; ++i) {
rb_ary_push(list, enc_new(enc_table->list[i].enc));
@@ -1954,6 +2036,18 @@ Init_Encoding(void)
}
void
+Init_unicode_version(void)
+{
+ extern const char onigenc_unicode_version_string[];
+
+ VALUE str = rb_usascii_str_new_static(onigenc_unicode_version_string,
+ strlen(onigenc_unicode_version_string));
+ OBJ_FREEZE(str);
+ /* The supported Unicode version. */
+ rb_define_const(rb_cEncoding, "UNICODE_VERSION", str);
+}
+
+void
Init_encodings(void)
{
rb_enc_init(&global_enc_table);
@@ -1964,5 +2058,7 @@ Init_encodings(void)
void
rb_enc_foreach_name(int (*func)(st_data_t name, st_data_t idx, st_data_t arg), st_data_t arg)
{
- st_foreach(global_enc_table.names, func, arg);
+ GLOBAL_ENC_TABLE_LOCKING(enc_table) {
+ st_foreach(enc_table->names, func, arg);
+ }
}
diff --git a/enum.c b/enum.c
index adaa660001..a2941dd7dd 100644
--- a/enum.c
+++ b/enum.c
@@ -127,7 +127,7 @@ static VALUE
enum_grep0(VALUE obj, VALUE pat, VALUE test)
{
VALUE ary = rb_ary_new();
- struct MEMO *memo = MEMO_NEW(pat, ary, test);
+ struct MEMO *memo = rb_imemo_memo_new_value(pat, ary, test);
rb_block_call_func_t fn;
if (rb_block_given_p()) {
fn = grep_iter_i;
@@ -207,27 +207,32 @@ enum_grep_v(VALUE obj, VALUE pat)
return enum_grep0(obj, pat, Qfalse);
}
-#define COUNT_BIGNUM IMEMO_FL_USER0
-#define MEMO_V3_SET(m, v) RB_OBJ_WRITE((m), &(m)->u3.value, (v))
+static inline void
+MEMO_V3_SET(struct MEMO *m, VALUE v)
+{
+ RB_OBJ_WRITE(m, &m->u3.value, v);
+ m->flags |= MEMO_U3_IS_VALUE;
+}
static void
imemo_count_up(struct MEMO *memo)
{
- if (memo->flags & COUNT_BIGNUM) {
+ if (memo->flags & MEMO_U3_IS_VALUE) {
+ RUBY_ASSERT(RB_TYPE_P(memo->u3.value, T_BIGNUM));
MEMO_V3_SET(memo, rb_int_succ(memo->u3.value));
}
else if (++memo->u3.cnt == 0) {
/* overflow */
unsigned long buf[2] = {0, 1};
MEMO_V3_SET(memo, rb_big_unpack(buf, 2));
- memo->flags |= COUNT_BIGNUM;
}
}
static VALUE
imemo_count_value(struct MEMO *memo)
{
- if (memo->flags & COUNT_BIGNUM) {
+ if (memo->flags & MEMO_U3_IS_VALUE) {
+ RUBY_ASSERT(RB_TYPE_P(memo->u3.value, T_BIGNUM));
return memo->u3.value;
}
else {
@@ -317,14 +322,15 @@ enum_count(int argc, VALUE *argv, VALUE obj)
func = count_i;
}
- memo = MEMO_NEW(item, 0, 0);
+ memo = rb_imemo_memo_new(item, 0, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return imemo_count_value(memo);
}
NORETURN(static void found(VALUE i, VALUE memop));
static void
-found(VALUE i, VALUE memop) {
+found(VALUE i, VALUE memop)
+{
struct MEMO *memo = MEMO_CAST(memop);
MEMO_V1_SET(memo, i);
memo->u3.cnt = 1;
@@ -381,7 +387,7 @@ enum_find(int argc, VALUE *argv, VALUE obj)
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
RETURN_ENUMERATOR(obj, argc, argv);
- memo = MEMO_NEW(Qundef, 0, 0);
+ memo = rb_imemo_memo_new(Qundef, 0, 0);
if (rb_block_pair_yield_optimizable())
rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
else
@@ -466,7 +472,7 @@ enum_find_index(int argc, VALUE *argv, VALUE obj)
func = find_index_i;
}
- memo = MEMO_NEW(Qnil, condition_value, 0);
+ memo = rb_imemo_memo_new(Qnil, condition_value, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return memo->v1;
}
@@ -1083,7 +1089,7 @@ enum_inject(int argc, VALUE *argv, VALUE obj)
return ary_inject_op(obj, init, op);
}
- memo = MEMO_NEW(init, Qnil, op);
+ memo = rb_imemo_memo_new_value(init, Qnil, op);
rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
if (UNDEF_P(memo->v1)) return Qnil;
return memo->v1;
@@ -1141,7 +1147,7 @@ enum_partition(VALUE obj)
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
- memo = MEMO_NEW(rb_ary_new(), rb_ary_new(), 0);
+ memo = rb_imemo_memo_new(rb_ary_new(), rb_ary_new(), 0);
rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
return rb_assoc_new(memo->v1, memo->v2);
@@ -1214,14 +1220,15 @@ tally_up(st_data_t *group, st_data_t *value, st_data_t arg, int existing)
RB_OBJ_WRITTEN(hash, Qundef, tally);
}
*value = (st_data_t)tally;
- if (!SPECIAL_CONST_P(*group)) RB_OBJ_WRITTEN(hash, Qundef, *group);
return ST_CONTINUE;
}
static VALUE
rb_enum_tally_up(VALUE hash, VALUE group)
{
- rb_hash_stlike_update(hash, group, tally_up, (st_data_t)hash);
+ if (!rb_hash_stlike_update(hash, group, tally_up, (st_data_t)hash)) {
+ RB_OBJ_WRITTEN(hash, Qundef, group);
+ }
return hash;
}
@@ -1343,7 +1350,7 @@ enum_first(int argc, VALUE *argv, VALUE obj)
return enum_take(obj, argv[0]);
}
else {
- memo = MEMO_NEW(Qnil, 0, 0);
+ memo = rb_imemo_memo_new(Qnil, 0, 0);
rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
return memo->v1;
}
@@ -1720,7 +1727,7 @@ enum_sort_by(VALUE obj)
RBASIC_CLEAR_CLASS(ary);
buf = rb_ary_hidden_new(SORT_BY_BUFSIZE*2);
rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
- memo = MEMO_NEW(0, 0, 0);
+ memo = rb_imemo_memo_new(0, 0, 0);
data = (struct sort_by_data *)&memo->v1;
RB_OBJ_WRITE(memo, &data->ary, ary);
RB_OBJ_WRITE(memo, &data->buf, buf);
@@ -1764,7 +1771,7 @@ enum_sort_by(VALUE obj)
#define ENUM_BLOCK_CALL(name) \
rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(name), (VALUE)memo, rb_block_given_p() && rb_block_pair_yield_optimizable() ? RB_BLOCK_NO_USE_PACKED_ARGS : 0);
-#define MEMO_ENUM_NEW(v1) (rb_check_arity(argc, 0, 1), MEMO_NEW((v1), (argc ? *argv : 0), 0))
+#define MEMO_ENUM_NEW(v1) (rb_check_arity(argc, 0, 1), rb_imemo_memo_new((v1), (argc ? *argv : 0), 0))
#define DEFINE_ENUMFUNCS(name) \
static VALUE enum_##name##_func(VALUE result, struct MEMO *memo); \
@@ -2752,7 +2759,7 @@ enum_min_by(int argc, VALUE *argv, VALUE obj)
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 0, 0);
- memo = MEMO_NEW(Qundef, Qnil, 0);
+ memo = rb_imemo_memo_new(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
return memo->v2;
}
@@ -2826,7 +2833,7 @@ enum_max_by(int argc, VALUE *argv, VALUE obj)
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 1, 0);
- memo = MEMO_NEW(Qundef, Qnil, 0);
+ memo = rb_imemo_memo_new(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
return memo->v2;
}
@@ -2977,7 +2984,7 @@ member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args))
static VALUE
enum_member(VALUE obj, VALUE val)
{
- struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);
+ struct MEMO *memo = rb_imemo_memo_new(val, Qfalse, 0);
rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
return memo->v2;
@@ -3229,7 +3236,7 @@ enum_each_slice(VALUE obj, VALUE n)
size = limit_by_enum_size(obj, size);
ary = rb_ary_new2(size);
arity = rb_block_arity();
- memo = MEMO_NEW(ary, dont_recycle_block_arg(arity), size);
+ memo = rb_imemo_memo_new(ary, dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
ary = memo->v1;
if (RARRAY_LEN(ary) > 0) rb_yield(ary);
@@ -3305,7 +3312,7 @@ enum_each_cons(VALUE obj, VALUE n)
RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
arity = rb_block_arity();
if (enum_size_over_p(obj, size)) return obj;
- memo = MEMO_NEW(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
+ memo = rb_imemo_memo_new(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
return obj;
@@ -3534,7 +3541,7 @@ enum_zip(int argc, VALUE *argv, VALUE obj)
}
/* TODO: use NODE_DOT2 as memo(v, v, -) */
- memo = MEMO_NEW(result, args, 0);
+ memo = rb_imemo_memo_new(result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
@@ -3577,7 +3584,7 @@ enum_take(VALUE obj, VALUE n)
if (len == 0) return rb_ary_new2(0);
result = rb_ary_new2(len);
- memo = MEMO_NEW(result, 0, len);
+ memo = rb_imemo_memo_new(result, 0, len);
rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
return result;
}
@@ -3665,7 +3672,7 @@ enum_drop(VALUE obj, VALUE n)
}
result = rb_ary_new();
- memo = MEMO_NEW(result, 0, len);
+ memo = rb_imemo_memo_new(result, 0, len);
rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
return result;
}
@@ -3703,6 +3710,17 @@ drop_while_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
*
* With no block given, returns an Enumerator.
*
+ * e = (1..4).drop_while
+ * p e #=> #<Enumerator: 1..4:drop_while>
+ * i = e.next; p i; e.feed(i < 3) #=> 1
+ * i = e.next; p i; e.feed(i < 3) #=> 2
+ * i = e.next; p i; e.feed(i < 3) #=> 3
+ * begin
+ * e.next
+ * rescue StopIteration
+ * p $!.result #=> [3, 4]
+ * end
+ *
*/
static VALUE
@@ -3713,7 +3731,7 @@ enum_drop_while(VALUE obj)
RETURN_ENUMERATOR(obj, 0, 0);
result = rb_ary_new();
- memo = MEMO_NEW(result, 0, FALSE);
+ memo = rb_imemo_memo_new(result, 0, FALSE);
rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
return result;
}
@@ -3933,7 +3951,7 @@ chunk_i(RB_BLOCK_CALL_FUNC_ARGLIST(yielder, enumerator))
* ["F", 6860]
*
* You can use the special symbol <tt>:_alone</tt> to force an element
- * into its own separate chuck:
+ * into its own separate chunk:
*
* a = [0, 0, 1, 1]
* e = a.chunk{|i| i.even? ? :_alone : true }
@@ -5107,6 +5125,82 @@ enum_compact(VALUE obj)
* 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.
*
+ * == Extended Methods
+ *
+ * A Enumerable class may define extended methods. This section describes the standard
+ * behavior of extension methods for reference purposes.
+ *
+ * === #size
+ *
+ * \Enumerator has a #size method.
+ * It uses the size function argument passed to +Enumerator.new+.
+ *
+ * e = Enumerator.new(-> { 3 }) {|y| p y; y.yield :a; y.yield :b; y.yield :c; :z }
+ * p e.size #=> 3
+ * p e.next #=> :a
+ * p e.next #=> :b
+ * p e.next #=> :c
+ * begin
+ * e.next
+ * rescue StopIteration
+ * p $!.result #=> :z
+ * end
+ *
+ * The result of the size function should represent the number of iterations
+ * (i.e., the number of times you yield to the block argument).
+ * In the above example, the block calls #yield three times, and
+ * the size function, +-> { 3 }+, returns 3 accordingly.
+ * The result of the size function can be an integer, +Float::INFINITY+,
+ * or +nil+.
+ * An integer means the exact number of times #yield will be called,
+ * as shown above.
+ * +Float::INFINITY+ indicates an infinite number of #yield calls.
+ * +nil+ means the number of #yield calls is difficult or impossible to
+ * determine.
+ *
+ * Many iteration methods return an \Enumerator object with an
+ * appropriate size function if no block is given.
+ *
+ * Examples:
+ *
+ * ["a", "b", "c"].each.size #=> 3
+ * {a: "x", b: "y", c: "z"}.each.size #=> 3
+ * (0..20).to_a.permutation.size #=> 51090942171709440000
+ * loop.size #=> Float::INFINITY
+ * (1..100).drop_while.size #=> nil # size depends on the block's behavior
+ * STDIN.each.size #=> nil # cannot be computed without consuming input
+ * File.open("/etc/resolv.conf").each.size #=> nil # cannot be computed without reading the file
+ *
+ * The behavior of #size for Range-based enumerators depends on the #begin element:
+ *
+ * - If the #begin element is an Integer, the #size method returns an Integer or +Float::INFINITY+.
+ * - If the #begin element is an object with a #succ method (other than Integer), #size returns +nil+.
+ * (Computing the size would require repeatedly calling #succ, which may be too slow.)
+ * - If the #begin element does not have a #succ method, #size raises a TypeError.
+ *
+ * Examples:
+ *
+ * (10..42).each.size #=> 33
+ * (10..42.9).each.size #=> 33 (the #end element may be a non-integer numeric)
+ * (10..).each.size #=> Float::INFINITY
+ * ("a".."z").each.size #=> nil
+ * ("a"..).each.size #=> nil
+ * (1.0..9.0).each.size # raises TypeError (Float does not have #succ)
+ * (..10).each.size # raises TypeError (beginless range has nil as its #begin)
+ *
+ * The \Enumerable module itself does not define a #size method.
+ * A class that includes \Enumerable may define its own #size method.
+ * It is recommended that such a #size method be consistent with
+ * Enumerator#size.
+ *
+ * Array and Hash implement #size and return values consistent with
+ * Enumerator#size.
+ * IO and Dir do not define #size, which is also consistent because the
+ * corresponding enumerator's size function returns +nil+.
+ *
+ * However, it is not strictly required for a class's #size method to match Enumerator#size.
+ * For example, File#size returns the number of bytes in the file, not the number of lines.
+ *
*/
void
diff --git a/enumerator.c b/enumerator.c
index faaa77cb49..69c96b2d8f 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -18,6 +18,7 @@
#include <float.h>
#endif
+#include <limits.h>
#include "id.h"
#include "internal.h"
#include "internal/class.h"
@@ -33,79 +34,93 @@
/*
* Document-class: Enumerator
*
- * A class which allows both internal and external iteration.
+ * \Class \Enumerator supports:
*
- * An Enumerator can be created by the following methods.
- * - Object#to_enum
- * - Object#enum_for
- * - Enumerator.new
+ * - {External iteration}[rdoc-ref:Enumerator@External+Iteration].
+ * - {Internal iteration}[rdoc-ref:Enumerator@Internal+Iteration].
*
- * Most methods have two forms: a block form where the contents
- * are evaluated for each item in the enumeration, and a non-block form
- * which returns a new Enumerator wrapping the iteration.
+ * An \Enumerator may be created by the following methods:
*
- * enumerator = %w(one two three).each
- * puts enumerator.class # => Enumerator
+ * - Object#to_enum.
+ * - Object#enum_for.
+ * - Enumerator.new.
*
- * enumerator.each_with_object("foo") do |item, obj|
- * puts "#{obj}: #{item}"
- * end
+ * In addition, certain Ruby methods return \Enumerator objects:
+ * a Ruby iterator method that accepts a block
+ * may return an \Enumerator if no block is given.
+ * There are many such methods, for example, in classes Array and Hash.
+ * (In the documentation for those classes, search for `new_enumerator`.)
*
- * # foo: one
- * # foo: two
- * # foo: three
+ * == Internal Iteration
*
- * enum_with_obj = enumerator.each_with_object("foo")
- * puts enum_with_obj.class # => Enumerator
+ * In _internal iteration_, an iterator method drives the iteration
+ * and the caller's block handles the processing;
+ * this example uses method #each_with_index:
*
- * enum_with_obj.each do |item, obj|
- * puts "#{obj}: #{item}"
- * end
+ * words = %w[foo bar baz] # => ["foo", "bar", "baz"]
+ * enumerator = words.each # => #<Enumerator: ...>
+ * enumerator.each_with_index {|word, i| puts "#{i}: #{word}" }
+ * 0: foo
+ * 1: bar
+ * 2: baz
*
- * # foo: one
- * # foo: two
- * # foo: three
+ * Iterator methods in class \Enumerator include:
*
- * This allows you to chain Enumerators together. For example, you
- * can map a list's elements to strings containing the index
- * and the element as a string via:
+ * - #each:
+ * passes each item to the block.
+ * - #each_with_index:
+ * passes each item and its index to the block.
+ * - #each_with_object (aliased as #with_object):
+ * passes each item and a given object to the block.
+ * - #with_index:
+ * like #each_with_index, but starting at a given offset (instead of zero).
*
- * puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
- * # => ["0:foo", "1:bar", "2:baz"]
+ * \Class \Enumerator includes module Enumerable,
+ * which provides many more iterator methods.
*
* == External Iteration
*
- * An Enumerator can also be used as an external iterator.
- * For example, Enumerator#next returns the next value of the iterator
- * or raises StopIteration if the Enumerator is at the end.
- *
- * e = [1,2,3].each # returns an enumerator object.
- * puts e.next # => 1
- * puts e.next # => 2
- * 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).
- *
- * 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
+ * In _external iteration_, the user's program both drives the iteration
+ * and handles the processing in stream-like fashion;
+ * this example uses method #next:
+ *
+ * words = %w[foo bar baz]
+ * enumerator = words.each
+ * enumerator.next # => "foo"
+ * enumerator.next # => "bar"
+ * enumerator.next # => "baz"
+ * enumerator.next # Raises StopIteration: iteration reached an end
+ *
+ * External iteration methods in class \Enumerator include:
+ *
+ * - #feed:
+ * sets the value that is next to be returned.
+ * - #next:
+ * returns the next value and increments the position.
+ * - #next_values:
+ * returns the next value in a 1-element array and increments the position.
+ * - #peek:
+ * returns the next value but does not increment the position.
+ * - #peek_values:
+ * returns the next value in a 1-element array but does not increment the position.
+ * - #rewind:
+ * sets the position to zero.
+ *
+ * Each of these methods raises FrozenError if called from a frozen \Enumerator.
+ *
+ * == External Iteration and \Fiber
+ *
+ * External iteration that uses Fiber differs *significantly* from internal iteration:
+ *
+ * - Using \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:
@@ -125,7 +140,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
+ * == Converting External Iteration to Internal Iteration
*
* You can use an external iterator to implement an internal iterator as follows:
*
@@ -162,10 +177,9 @@
*/
VALUE rb_cEnumerator;
static VALUE rb_cLazy;
-static ID id_rewind, id_new, id_to_enum, id_each_entry;
+static ID id_rewind, id_to_enum, id_each_entry;
static ID id_next, id_result, id_receiver, id_arguments, id_memo, id_method, id_force;
-static ID id_begin, id_end, id_step, id_exclude_end;
-static VALUE sym_each, sym_cycle, sym_yield;
+static VALUE sym_each, sym_yield;
static VALUE lazy_use_super_method;
@@ -222,6 +236,7 @@ struct yielder {
struct producer {
VALUE init;
VALUE proc;
+ VALUE size;
};
typedef struct MEMO *lazyenum_proc_func(VALUE, struct MEMO *, VALUE, long);
@@ -281,28 +296,20 @@ enumerator_ptr(VALUE obj)
}
static void
-proc_entry_mark(void *p)
-{
- struct proc_entry *ptr = p;
- rb_gc_mark_movable(ptr->proc);
- rb_gc_mark_movable(ptr->memo);
-}
-
-static void
-proc_entry_compact(void *p)
+proc_entry_mark_and_move(void *p)
{
struct proc_entry *ptr = p;
- ptr->proc = rb_gc_location(ptr->proc);
- ptr->memo = rb_gc_location(ptr->memo);
+ rb_gc_mark_and_move(&ptr->proc);
+ rb_gc_mark_and_move(&ptr->memo);
}
static const rb_data_type_t proc_entry_data_type = {
"proc_entry",
{
- proc_entry_mark,
+ proc_entry_mark_and_move,
RUBY_TYPED_DEFAULT_FREE,
NULL, // Nothing allocated externally, so don't need a memsize function
- proc_entry_compact,
+ proc_entry_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -452,28 +459,31 @@ convert_to_feasible_size_value(VALUE obj)
/*
* call-seq:
- * Enumerator.new(size = nil) { |yielder| ... }
+ * Enumerator.new(size = nil) {|yielder| ... }
*
- * Creates a new Enumerator object, which can be used as an
- * Enumerable.
+ * Returns a new \Enumerator object that can be used for iteration.
*
- * Iteration is defined by the given block, in
- * which a "yielder" object, given as block parameter, can be used to
- * yield a value by calling the +yield+ method (aliased as <code><<</code>):
+ * The given block defines the iteration;
+ * it is called with a "yielder" object that can yield an object
+ * via a call to method <tt>yielder.yield</tt>:
*
- * fib = Enumerator.new do |y|
- * a = b = 1
- * loop do
- * y << a
- * a, b = b, a + b
+ * fib = Enumerator.new do |yielder|
+ * n = next_n = 1
+ * while true do
+ * yielder.yield(n)
+ * n, next_n = next_n, n + next_n
* end
* end
*
* fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
*
- * The optional parameter can be used to specify how to calculate the size
- * in a lazy fashion (see Enumerator#size). It can either be a value or
- * a callable object.
+ * Parameter +size+ specifies how the size is to be calculated (see #size);
+ * it can either be a value or a callable object:
+ *
+ * Enumerator.new{}.size # => nil
+ * Enumerator.new(42){}.size # => 42
+ * Enumerator.new(-> {42}){}.size # => 42
+ *
*/
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
@@ -679,7 +689,7 @@ enumerator_with_index(int argc, VALUE *argv, VALUE obj)
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);
memo = (!argc || NIL_P(memo = argv[0])) ? INT2FIX(0) : rb_to_int(memo);
- return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)MEMO_NEW(memo, 0, 0));
+ return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)rb_imemo_memo_new(memo, 0, 0));
}
/*
@@ -1093,6 +1103,7 @@ enumerator_rewind(VALUE obj)
static struct generator *generator_ptr(VALUE obj);
static VALUE append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args);
+static VALUE append_method_args(VALUE obj, VALUE str, VALUE default_args);
static VALUE
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
@@ -1165,7 +1176,7 @@ kwd_append(VALUE key, VALUE val, VALUE str)
static VALUE
append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
{
- VALUE method, eargs;
+ VALUE method;
method = rb_attr_get(obj, id_method);
if (method != Qfalse) {
@@ -1179,6 +1190,13 @@ append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
rb_str_buf_cat2(str, ":");
rb_str_buf_append(str, method);
}
+ return append_method_args(obj, str, default_args);
+}
+
+static VALUE
+append_method_args(VALUE obj, VALUE str, VALUE default_args)
+{
+ VALUE eargs;
eargs = rb_attr_get(obj, id_arguments);
if (NIL_P(eargs)) {
@@ -1208,10 +1226,11 @@ append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
if (!NIL_P(kwds)) {
rb_hash_foreach(kwds, kwd_append, str);
}
- rb_str_set_len(str, RSTRING_LEN(str)-2);
+ rb_str_set_len(str, RSTRING_LEN(str)-2); /* drop the last ", " */
rb_str_buf_cat2(str, ")");
}
}
+ RB_GC_GUARD(eargs);
return str;
}
@@ -1238,6 +1257,24 @@ enumerator_inspect(VALUE obj)
* (1..100).to_a.permutation(4).size # => 94109400
* loop.size # => Float::INFINITY
* (1..100).drop_while.size # => nil
+ *
+ * Note that enumerator size might be inaccurate, and should be rather treated as a hint.
+ * For example, there is no check that the size provided to ::new is accurate:
+ *
+ * e = Enumerator.new(5) { |y| 2.times { y << it} }
+ * e.size # => 5
+ * e.to_a.size # => 2
+ *
+ * Another example is an enumerator created by ::produce without a +size+ argument.
+ * Such enumerators return +Infinity+ for size, but this is inaccurate if the passed
+ * block raises StopIteration:
+ *
+ * e = Enumerator.produce(1) { it + 1 }
+ * e.size # => Infinity
+ *
+ * e = Enumerator.produce(1) { it > 3 ? raise(StopIteration) : it + 1 }
+ * e.size # => Infinity
+ * e.to_a.size # => 4
*/
static VALUE
@@ -1281,26 +1318,19 @@ enumerator_size(VALUE obj)
* Yielder
*/
static void
-yielder_mark(void *p)
+yielder_mark_and_move(void *p)
{
struct yielder *ptr = p;
- rb_gc_mark_movable(ptr->proc);
-}
-
-static void
-yielder_compact(void *p)
-{
- struct yielder *ptr = p;
- ptr->proc = rb_gc_location(ptr->proc);
+ rb_gc_mark_and_move(&ptr->proc);
}
static const rb_data_type_t yielder_data_type = {
"yielder",
{
- yielder_mark,
+ yielder_mark_and_move,
RUBY_TYPED_DEFAULT_FREE,
NULL,
- yielder_compact,
+ yielder_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -1411,28 +1441,20 @@ yielder_new(void)
* Generator
*/
static void
-generator_mark(void *p)
-{
- struct generator *ptr = p;
- rb_gc_mark_movable(ptr->proc);
- rb_gc_mark_movable(ptr->obj);
-}
-
-static void
-generator_compact(void *p)
+generator_mark_and_move(void *p)
{
struct generator *ptr = p;
- ptr->proc = rb_gc_location(ptr->proc);
- ptr->obj = rb_gc_location(ptr->obj);
+ rb_gc_mark_and_move(&ptr->proc);
+ rb_gc_mark_and_move(&ptr->obj);
}
static const rb_data_type_t generator_data_type = {
"generator",
{
- generator_mark,
+ generator_mark_and_move,
RUBY_TYPED_DEFAULT_FREE,
NULL,
- generator_compact,
+ generator_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -1603,6 +1625,11 @@ lazy_init_block_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, m))
#define LAZY_MEMO_SET_PACKED(memo) ((memo)->memo_flags |= LAZY_MEMO_PACKED)
#define LAZY_MEMO_RESET_PACKED(memo) ((memo)->memo_flags &= ~LAZY_MEMO_PACKED)
+#define LAZY_NEED_BLOCK(func) \
+ if (!rb_block_given_p()) { \
+ rb_raise(rb_eArgError, "tried to call lazy " #func " without a block"); \
+ }
+
static VALUE lazy_yielder_result(struct MEMO *result, VALUE yielder, VALUE procs_array, VALUE memos, long i);
static VALUE
@@ -1613,7 +1640,7 @@ lazy_init_yielder(RB_BLOCK_CALL_FUNC_ARGLIST(_, m))
VALUE memos = rb_attr_get(yielder, id_memo);
struct MEMO *result;
- result = MEMO_NEW(m, rb_enum_values_pack(argc, argv),
+ result = rb_imemo_memo_new(m, rb_enum_values_pack(argc, argv),
argc > 1 ? LAZY_MEMO_PACKED : 0);
return lazy_yielder_result(result, yielder, procs_array, memos, 0);
}
@@ -1806,9 +1833,7 @@ lazy_initialize(int argc, VALUE *argv, VALUE self)
VALUE generator;
rb_check_arity(argc, 1, 2);
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy new without a block");
- }
+ LAZY_NEED_BLOCK(new);
obj = argv[0];
if (argc > 1) {
size = argv[1];
@@ -2066,10 +2091,7 @@ static const lazyenum_funcs lazy_map_funcs = {
static VALUE
lazy_map(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy map without a block");
- }
-
+ LAZY_NEED_BLOCK(map);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_map_funcs);
}
@@ -2151,10 +2173,7 @@ static const lazyenum_funcs lazy_flat_map_funcs = {
static VALUE
lazy_flat_map(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
- }
-
+ LAZY_NEED_BLOCK(flat_map);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_flat_map_funcs);
}
@@ -2181,10 +2200,7 @@ static const lazyenum_funcs lazy_select_funcs = {
static VALUE
lazy_select(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy select without a block");
- }
-
+ LAZY_NEED_BLOCK(select);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_select_funcs);
}
@@ -2215,10 +2231,7 @@ static const lazyenum_funcs lazy_filter_map_funcs = {
static VALUE
lazy_filter_map(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy filter_map without a block");
- }
-
+ LAZY_NEED_BLOCK(filter_map);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_filter_map_funcs);
}
@@ -2244,10 +2257,7 @@ static const lazyenum_funcs lazy_reject_funcs = {
static VALUE
lazy_reject(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy reject without a block");
- }
-
+ LAZY_NEED_BLOCK(reject);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_reject_funcs);
}
@@ -2530,10 +2540,7 @@ static const lazyenum_funcs lazy_take_while_funcs = {
static VALUE
lazy_take_while(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy take_while without a block");
- }
-
+ LAZY_NEED_BLOCK(take_while);
return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_take_while_funcs);
}
@@ -2628,10 +2635,7 @@ static const lazyenum_funcs lazy_drop_while_funcs = {
static VALUE
lazy_drop_while(VALUE obj)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eArgError, "tried to call lazy drop_while without a block");
- }
-
+ LAZY_NEED_BLOCK(drop_while);
return lazy_add_method(obj, 0, 0, Qfalse, Qnil, &lazy_drop_while_funcs);
}
@@ -2776,6 +2780,52 @@ lazy_with_index(int argc, VALUE *argv, VALUE obj)
return lazy_add_method(obj, 0, 0, memo, rb_ary_new_from_values(1, &memo), &lazy_with_index_funcs);
}
+static struct MEMO *
+lazy_tap_each_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index)
+{
+ struct proc_entry *entry = proc_entry_ptr(proc_entry);
+
+ rb_proc_call_with_block(entry->proc, 1, &result->memo_value, Qnil);
+
+ return result;
+}
+
+static const lazyenum_funcs lazy_tap_each_funcs = {
+ lazy_tap_each_proc, 0,
+};
+
+/*
+ * call-seq:
+ * lazy.tap_each { |item| ... } -> lazy_enumerator
+ *
+ * Passes each element through to the block for side effects only,
+ * without modifying the element or affecting the enumeration.
+ * Returns a new lazy enumerator.
+ *
+ * This is useful for debugging or logging inside lazy chains,
+ * without breaking laziness or misusing +map+.
+ *
+ * (1..).lazy
+ * .tap_each { |x| puts "got #{x}" }
+ * .select(&:even?)
+ * .first(3)
+ * # prints: got 1, got 2, ..., got 6
+ * # returns: [2, 4, 6]
+ *
+ * Similar in intent to Java's Stream#peek.
+ */
+
+static VALUE
+lazy_tap_each(VALUE obj)
+{
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "tried to call lazy tap_each without a block");
+ }
+
+ return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_tap_each_funcs);
+}
+
#if 0 /* for RDoc */
/*
@@ -2913,19 +2963,12 @@ stop_result(VALUE self)
*/
static void
-producer_mark(void *p)
-{
- struct producer *ptr = p;
- rb_gc_mark_movable(ptr->init);
- rb_gc_mark_movable(ptr->proc);
-}
-
-static void
-producer_compact(void *p)
+producer_mark_and_move(void *p)
{
struct producer *ptr = p;
- ptr->init = rb_gc_location(ptr->init);
- ptr->proc = rb_gc_location(ptr->proc);
+ rb_gc_mark_and_move(&ptr->init);
+ rb_gc_mark_and_move(&ptr->proc);
+ rb_gc_mark_and_move(&ptr->size);
}
#define producer_free RUBY_TYPED_DEFAULT_FREE
@@ -2939,10 +2982,10 @@ producer_memsize(const void *p)
static const rb_data_type_t producer_data_type = {
"producer",
{
- producer_mark,
+ producer_mark_and_move,
producer_free,
producer_memsize,
- producer_compact,
+ producer_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -2969,12 +3012,13 @@ producer_allocate(VALUE klass)
obj = TypedData_Make_Struct(klass, struct producer, &producer_data_type, ptr);
ptr->init = Qundef;
ptr->proc = Qundef;
+ ptr->size = Qnil;
return obj;
}
static VALUE
-producer_init(VALUE obj, VALUE init, VALUE proc)
+producer_init(VALUE obj, VALUE init, VALUE proc, VALUE size)
{
struct producer *ptr;
@@ -2986,6 +3030,7 @@ producer_init(VALUE obj, VALUE init, VALUE proc)
RB_OBJ_WRITE(obj, &ptr->init, init);
RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ RB_OBJ_WRITE(obj, &ptr->size, size);
return obj;
}
@@ -3036,12 +3081,18 @@ producer_each(VALUE obj)
static VALUE
producer_size(VALUE obj, VALUE args, VALUE eobj)
{
- return DBL2NUM(HUGE_VAL);
+ struct producer *ptr = producer_ptr(obj);
+ VALUE size = ptr->size;
+
+ if (NIL_P(size)) return Qnil;
+ if (RB_INTEGER_TYPE_P(size) || RB_FLOAT_TYPE_P(size)) return size;
+
+ return rb_funcall(size, id_call, 0);
}
/*
* call-seq:
- * Enumerator.produce(initial = nil) { |prev| block } -> enumerator
+ * Enumerator.produce(initial = nil, size: nil) { |prev| block } -> enumerator
*
* Creates an infinite enumerator from any block, just called over and
* over. The result of the previous iteration is passed to the next one.
@@ -3073,19 +3124,50 @@ producer_size(VALUE obj, VALUE args, VALUE eobj)
* PATTERN = %r{\d+|[-/+*]}
* Enumerator.produce { scanner.scan(PATTERN) }.slice_after { scanner.eos? }.first
* # => ["7", "+", "38", "/", "6"]
+ *
+ * The optional +size+ keyword argument specifies the size of the enumerator,
+ * which can be retrieved by Enumerator#size. It can be an integer,
+ * +Float::INFINITY+, a callable object (such as a lambda), or +nil+ to
+ * indicate unknown size. When not specified, the size defaults to
+ * +Float::INFINITY+.
+ *
+ * # Infinite enumerator
+ * enum = Enumerator.produce(1, size: Float::INFINITY, &:succ)
+ * enum.size # => Float::INFINITY
+ *
+ * # Finite enumerator with known/computable size
+ * abs_dir = File.expand_path("./baz") # => "/foo/bar/baz"
+ * traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) {
+ * raise StopIteration if it == "/"
+ * File.dirname(it)
+ * }
+ * traverser.size # => 4
+ *
+ * # Finite enumerator with unknown size
+ * calendar = Enumerator.produce(Date.today, size: nil) {
+ * it.monday? ? raise(StopIteration) : it + 1
+ * }
+ * calendar.size # => nil
*/
static VALUE
enumerator_s_produce(int argc, VALUE *argv, VALUE klass)
{
- VALUE init, producer;
+ VALUE init, producer, opts, size;
+ ID keyword_ids[1];
if (!rb_block_given_p()) rb_raise(rb_eArgError, "no block given");
- if (rb_scan_args(argc, argv, "01", &init) == 0) {
+ keyword_ids[0] = rb_intern("size");
+ rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, argc, argv, "01:", &init, &opts);
+ rb_get_kwargs(opts, keyword_ids, 0, 1, &size);
+
+ size = UNDEF_P(size) ? DBL2NUM(HUGE_VAL) : convert_to_feasible_size_value(size);
+
+ if (argc == 0 || (argc == 1 && !NIL_P(opts))) {
init = Qundef;
}
- producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc());
+ producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc(), size);
return rb_enumeratorize_with_size_kw(producer, sym_each, 0, 0, producer_size, RB_NO_KEYWORDS);
}
@@ -3101,17 +3183,10 @@ enumerator_s_produce(int argc, VALUE *argv, VALUE klass)
*/
static void
-enum_chain_mark(void *p)
-{
- struct enum_chain *ptr = p;
- rb_gc_mark_movable(ptr->enums);
-}
-
-static void
-enum_chain_compact(void *p)
+enum_chain_mark_and_move(void *p)
{
struct enum_chain *ptr = p;
- ptr->enums = rb_gc_location(ptr->enums);
+ rb_gc_mark_and_move(&ptr->enums);
}
#define enum_chain_free RUBY_TYPED_DEFAULT_FREE
@@ -3125,12 +3200,12 @@ enum_chain_memsize(const void *p)
static const rb_data_type_t enum_chain_data_type = {
"chain",
{
- enum_chain_mark,
+ enum_chain_mark_and_move,
enum_chain_free,
enum_chain_memsize,
- enum_chain_compact,
+ enum_chain_mark_and_move,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static struct enum_chain *
@@ -3180,7 +3255,7 @@ enum_chain_initialize(VALUE obj, VALUE enums)
if (!ptr) rb_raise(rb_eArgError, "unallocated chain");
- ptr->enums = rb_ary_freeze(enums);
+ RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums));
ptr->pos = -1;
return obj;
@@ -3214,7 +3289,7 @@ enum_chain_init_copy(VALUE obj, VALUE orig)
if (!ptr1) rb_raise(rb_eArgError, "unallocated chain");
- ptr1->enums = ptr0->enums;
+ RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums);
ptr1->pos = ptr0->pos;
return obj;
@@ -3423,17 +3498,10 @@ enumerator_plus(VALUE obj, VALUE eobj)
*/
static void
-enum_product_mark(void *p)
+enum_product_mark_and_move(void *p)
{
struct enum_product *ptr = p;
- rb_gc_mark_movable(ptr->enums);
-}
-
-static void
-enum_product_compact(void *p)
-{
- struct enum_product *ptr = p;
- ptr->enums = rb_gc_location(ptr->enums);
+ rb_gc_mark_and_move(&ptr->enums);
}
#define enum_product_free RUBY_TYPED_DEFAULT_FREE
@@ -3447,12 +3515,12 @@ enum_product_memsize(const void *p)
static const rb_data_type_t enum_product_data_type = {
"product",
{
- enum_product_mark,
+ enum_product_mark_and_move,
enum_product_free,
enum_product_memsize,
- enum_product_compact,
+ enum_product_mark_and_move,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static struct enum_product *
@@ -3508,7 +3576,7 @@ enum_product_initialize(int argc, VALUE *argv, VALUE obj)
if (!ptr) rb_raise(rb_eArgError, "unallocated product");
- ptr->enums = rb_ary_freeze(enums);
+ RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums));
return obj;
}
@@ -3526,7 +3594,7 @@ enum_product_init_copy(VALUE obj, VALUE orig)
if (!ptr1) rb_raise(rb_eArgError, "unallocated product");
- ptr1->enums = ptr0->enums;
+ RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums);
return obj;
}
@@ -3586,9 +3654,9 @@ enum_product_enum_size(VALUE obj, VALUE args, VALUE eobj)
struct product_state {
VALUE obj;
VALUE block;
+ int index;
int argc;
VALUE *argv;
- int index;
};
static VALUE product_each(VALUE, struct product_state *);
@@ -3627,15 +3695,23 @@ enum_product_run(VALUE obj, VALUE block)
{
struct enum_product *ptr = enum_product_ptr(obj);
int argc = RARRAY_LENINT(ptr->enums);
+ if (argc == 0) { /* no need to allocate state.argv */
+ rb_funcall(block, id_call, 1, rb_ary_new());
+ return obj;
+ }
+
+ VALUE argsbuf = 0;
struct product_state state = {
.obj = obj,
.block = block,
.index = 0,
.argc = argc,
- .argv = ALLOCA_N(VALUE, argc),
+ .argv = ALLOCV_N(VALUE, argsbuf, argc),
};
- return product_each(obj, &state);
+ VALUE ret = product_each(obj, &state);
+ ALLOCV_END(argsbuf);
+ return ret;
}
/*
@@ -3748,6 +3824,55 @@ enumerator_s_product(int argc, VALUE *argv, VALUE klass)
return obj;
}
+struct arith_seq {
+ struct enumerator enumerator;
+ VALUE begin;
+ VALUE end;
+ VALUE step;
+ bool exclude_end;
+};
+
+RUBY_REFERENCES(arith_seq_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_EDGE(struct arith_seq, begin),
+ RUBY_REF_EDGE(struct arith_seq, end),
+ RUBY_REF_EDGE(struct arith_seq, step),
+ RUBY_REF_END
+};
+
+static const rb_data_type_t arith_seq_data_type = {
+ "arithmetic_sequence",
+ {
+ RUBY_REFS_LIST_PTR(arith_seq_refs),
+ RUBY_TYPED_DEFAULT_FREE,
+ NULL, // Nothing allocated externally, so don't need a memsize function
+ NULL,
+ },
+ .parent = &enumerator_data_type,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
+};
+
+static VALUE
+arith_seq_allocate(VALUE klass)
+{
+ struct arith_seq *ptr;
+ VALUE enum_obj;
+
+ enum_obj = TypedData_Make_Struct(klass, struct arith_seq, &arith_seq_data_type, ptr);
+ ptr->enumerator.obj = Qundef;
+
+ return enum_obj;
+}
+
/*
* Document-class: Enumerator::ArithmeticSequence
*
@@ -3765,12 +3890,16 @@ rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv,
rb_enumerator_size_func *size_fn,
VALUE beg, VALUE end, VALUE step, int excl)
{
- VALUE aseq = enumerator_init(enumerator_allocate(rb_cArithSeq),
+ VALUE aseq = enumerator_init(arith_seq_allocate(rb_cArithSeq),
obj, meth, argc, argv, size_fn, Qnil, rb_keyword_given_p());
- rb_ivar_set(aseq, id_begin, beg);
- rb_ivar_set(aseq, id_end, end);
- rb_ivar_set(aseq, id_step, step);
- rb_ivar_set(aseq, id_exclude_end, RBOOL(excl));
+ struct arith_seq *ptr;
+ TypedData_Get_Struct(aseq, struct arith_seq, &enumerator_data_type, ptr);
+
+ RB_OBJ_WRITE(aseq, &ptr->begin, beg);
+ RB_OBJ_WRITE(aseq, &ptr->end, end);
+ RB_OBJ_WRITE(aseq, &ptr->step, step);
+ ptr->exclude_end = excl;
+
return aseq;
}
@@ -3783,7 +3912,9 @@ rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv,
static inline VALUE
arith_seq_begin(VALUE self)
{
- return rb_ivar_get(self, id_begin);
+ struct arith_seq *ptr;
+ TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
+ return ptr->begin;
}
/*
@@ -3794,7 +3925,9 @@ arith_seq_begin(VALUE self)
static inline VALUE
arith_seq_end(VALUE self)
{
- return rb_ivar_get(self, id_end);
+ struct arith_seq *ptr;
+ TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
+ return ptr->end;
}
/*
@@ -3806,7 +3939,9 @@ arith_seq_end(VALUE self)
static inline VALUE
arith_seq_step(VALUE self)
{
- return rb_ivar_get(self, id_step);
+ struct arith_seq *ptr;
+ TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
+ return ptr->step;
}
/*
@@ -3817,13 +3952,17 @@ arith_seq_step(VALUE self)
static inline VALUE
arith_seq_exclude_end(VALUE self)
{
- return rb_ivar_get(self, id_exclude_end);
+ struct arith_seq *ptr;
+ TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
+ return RBOOL(ptr->exclude_end);
}
static inline int
arith_seq_exclude_end_p(VALUE self)
{
- return RTEST(arith_seq_exclude_end(self));
+ struct arith_seq *ptr;
+ TypedData_Get_Struct(self, struct arith_seq, &enumerator_data_type, ptr);
+ return ptr->exclude_end;
}
int
@@ -3890,46 +4029,14 @@ rb_arithmetic_sequence_beg_len_step(VALUE obj, long *begp, long *lenp, long *ste
return Qnil;
}
-/*
- * call-seq:
- * aseq.first -> num or nil
- * aseq.first(n) -> an_array
- *
- * Returns the first number in this arithmetic sequence,
- * or an array of the first +n+ elements.
- */
static VALUE
-arith_seq_first(int argc, VALUE *argv, VALUE self)
+arith_seq_take(VALUE self, VALUE num)
{
VALUE b, e, s, ary;
long n;
int x;
- rb_check_arity(argc, 0, 1);
-
- b = arith_seq_begin(self);
- e = arith_seq_end(self);
- s = arith_seq_step(self);
- if (argc == 0) {
- if (NIL_P(b)) {
- return Qnil;
- }
- if (!NIL_P(e)) {
- VALUE zero = INT2FIX(0);
- int r = rb_cmpint(rb_num_coerce_cmp(s, zero, idCmp), s, zero);
- if (r > 0 && RTEST(rb_funcall(b, '>', 1, e))) {
- return Qnil;
- }
- if (r < 0 && RTEST(rb_funcall(b, '<', 1, e))) {
- return Qnil;
- }
- }
- return b;
- }
-
- // TODO: the following code should be extracted as arith_seq_take
-
- n = NUM2LONG(argv[0]);
+ n = NUM2LONG(num);
if (n < 0) {
rb_raise(rb_eArgError, "attempt to take negative size");
}
@@ -3937,6 +4044,9 @@ arith_seq_first(int argc, VALUE *argv, VALUE self)
return rb_ary_new_capa(0);
}
+ b = arith_seq_begin(self);
+ e = arith_seq_end(self);
+ s = arith_seq_step(self);
x = arith_seq_exclude_end_p(self);
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(s)) {
@@ -3971,7 +4081,7 @@ arith_seq_first(int argc, VALUE *argv, VALUE self)
ary = rb_ary_new_capa((n < len) ? n : len);
while (n > 0 && i < end) {
rb_ary_push(ary, LONG2FIX(i));
- if (i + unit < i) break;
+ if (i > LONG_MAX - unit) break;
i += unit;
--n;
}
@@ -3984,7 +4094,7 @@ arith_seq_first(int argc, VALUE *argv, VALUE self)
ary = rb_ary_new_capa((n < len) ? n : len);
while (n > 0 && i > end) {
rb_ary_push(ary, LONG2FIX(i));
- if (i + unit > i) break;
+ if (i < LONG_MIN - unit) break;
i += unit;
--n;
}
@@ -4031,7 +4141,49 @@ arith_seq_first(int argc, VALUE *argv, VALUE self)
return ary;
}
- return rb_call_super(argc, argv);
+ {
+ VALUE argv[1];
+ argv[0] = num;
+ return rb_call_super(1, argv);
+ }
+}
+
+/*
+ * call-seq:
+ * aseq.first -> num or nil
+ * aseq.first(n) -> an_array
+ *
+ * Returns the first number in this arithmetic sequence,
+ * or an array of the first +n+ elements.
+ */
+static VALUE
+arith_seq_first(int argc, VALUE *argv, VALUE self)
+{
+ VALUE b, e, s;
+
+ rb_check_arity(argc, 0, 1);
+
+ b = arith_seq_begin(self);
+ e = arith_seq_end(self);
+ s = arith_seq_step(self);
+ if (argc == 0) {
+ if (NIL_P(b)) {
+ return Qnil;
+ }
+ if (!NIL_P(e)) {
+ VALUE zero = INT2FIX(0);
+ int r = rb_cmpint(rb_num_coerce_cmp(s, zero, idCmp), s, zero);
+ if (r > 0 && RTEST(rb_funcall(b, '>', 1, e))) {
+ return Qnil;
+ }
+ if (r < 0 && RTEST(rb_funcall(b, '<', 1, e))) {
+ return Qnil;
+ }
+ }
+ return b;
+ }
+
+ return arith_seq_take(self, argv[0]);
}
static inline VALUE
@@ -4197,7 +4349,7 @@ static VALUE
arith_seq_inspect(VALUE self)
{
struct enumerator *e;
- VALUE eobj, str, eargs;
+ VALUE eobj, str;
int range_p;
TypedData_Get_Struct(self, struct enumerator, &enumerator_data_type, e);
@@ -4211,39 +4363,7 @@ arith_seq_inspect(VALUE self)
str = rb_sprintf("(%s%"PRIsVALUE"%s.", range_p ? "(" : "", eobj, range_p ? ")" : "");
rb_str_buf_append(str, rb_id2str(e->meth));
-
- eargs = rb_attr_get(eobj, id_arguments);
- if (NIL_P(eargs)) {
- eargs = e->args;
- }
- if (eargs != Qfalse) {
- long argc = RARRAY_LEN(eargs);
- const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
-
- if (argc > 0) {
- VALUE kwds = Qnil;
-
- rb_str_buf_cat2(str, "(");
-
- if (RB_TYPE_P(argv[argc-1], T_HASH)) {
- int all_key = TRUE;
- rb_hash_foreach(argv[argc-1], key_symbol_p, (VALUE)&all_key);
- if (all_key) kwds = argv[--argc];
- }
-
- while (argc--) {
- VALUE arg = *argv++;
-
- rb_str_append(str, rb_inspect(arg));
- rb_str_buf_cat2(str, ", ");
- }
- if (!NIL_P(kwds)) {
- rb_hash_foreach(kwds, kwd_append, str);
- }
- rb_str_set_len(str, RSTRING_LEN(str)-2); /* drop the last ", " */
- rb_str_buf_cat2(str, ")");
- }
- }
+ append_method_args(eobj, str, e->args);
rb_str_buf_cat2(str, ")");
@@ -4549,6 +4669,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cLazy, "uniq", lazy_uniq, 0);
rb_define_method(rb_cLazy, "compact", lazy_compact, 0);
rb_define_method(rb_cLazy, "with_index", lazy_with_index, -1);
+ rb_define_method(rb_cLazy, "tap_each", lazy_tap_each, 0);
lazy_use_super_method = rb_hash_new_with_size(18);
rb_hash_aset(lazy_use_super_method, sym("map"), sym("_enumerable_map"));
@@ -4585,7 +4706,7 @@ InitVM_Enumerator(void)
rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
rb_define_method(rb_eStopIteration, "result", stop_result, 0);
- /* Generator */
+ /* :nodoc: Generator */
rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject);
rb_include_module(rb_cGenerator, rb_mEnumerable);
rb_define_alloc_func(rb_cGenerator, generator_allocate);
@@ -4593,7 +4714,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cGenerator, "initialize_copy", generator_init_copy, 1);
rb_define_method(rb_cGenerator, "each", generator_each, -1);
- /* Yielder */
+ /* :nodoc: Yielder */
rb_cYielder = rb_define_class_under(rb_cEnumerator, "Yielder", rb_cObject);
rb_define_alloc_func(rb_cYielder, yielder_allocate);
rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0);
@@ -4601,7 +4722,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cYielder, "<<", yielder_yield_push, 1);
rb_define_method(rb_cYielder, "to_proc", yielder_to_proc, 0);
- /* Producer */
+ /* :nodoc: Producer */
rb_cEnumProducer = rb_define_class_under(rb_cEnumerator, "Producer", rb_cObject);
rb_define_alloc_func(rb_cEnumProducer, producer_allocate);
rb_define_method(rb_cEnumProducer, "each", producer_each, 0);
@@ -4664,7 +4785,6 @@ void
Init_Enumerator(void)
{
id_rewind = rb_intern_const("rewind");
- id_new = rb_intern_const("new");
id_next = rb_intern_const("next");
id_result = rb_intern_const("result");
id_receiver = rb_intern_const("receiver");
@@ -4674,12 +4794,7 @@ Init_Enumerator(void)
id_force = rb_intern_const("force");
id_to_enum = rb_intern_const("to_enum");
id_each_entry = rb_intern_const("each_entry");
- id_begin = rb_intern_const("begin");
- id_end = rb_intern_const("end");
- id_step = rb_intern_const("step");
- id_exclude_end = rb_intern_const("exclude_end");
sym_each = ID2SYM(id_each);
- sym_cycle = ID2SYM(rb_intern_const("cycle"));
sym_yield = ID2SYM(rb_intern_const("yield"));
InitVM(Enumerator);
diff --git a/error.c b/error.c
index 1a8a4cd430..7a08fd2b9e 100644
--- a/error.c
+++ b/error.c
@@ -50,6 +50,7 @@
#include "ruby_assert.h"
#include "vm_core.h"
#include "yjit.h"
+#include "zjit.h"
#include "builtin.h"
@@ -908,6 +909,10 @@ bug_report_file(const char *file, int line, rb_pid_t *pid)
int len = err_position_0(buf, sizeof(buf), file, line);
if (out) {
+ /* Disable buffering so crash report output is not lost if
+ * rb_vm_bugreport() triggers a secondary crash (e.g. SIGSEGV
+ * while walking JIT frames). */
+ setvbuf(out, NULL, _IONBF, 0);
if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len) return out;
fclose(out);
}
@@ -1077,9 +1082,14 @@ static void
die(void)
{
#if defined(_WIN32) && defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 80
+ /* mingw32 declares in stdlib.h but does not provide. */
_set_abort_behavior( 0, _CALL_REPORTFAULT);
#endif
+ /* Reset SIGABRT to default so that abort() does not trigger our custom
+ * handler (sigabrt), which would re-open the crash report file with "w"
+ * and truncate the report already written by rb_bug(). */
+ signal(SIGABRT, SIG_DFL);
abort();
}
@@ -1090,7 +1100,7 @@ rb_bug_without_die_internal(const char *fmt, va_list args)
const char *file = NULL;
int line = 0;
- if (GET_EC()) {
+ if (rb_current_execution_context(false)) {
file = rb_source_location_cstr(&line);
}
@@ -1123,7 +1133,7 @@ rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const voi
const char *file = NULL;
int line = 0;
- if (GET_EC()) {
+ if (rb_current_execution_context(false)) {
file = rb_source_location_cstr(&line);
}
@@ -1312,6 +1322,20 @@ rb_builtin_class_name(VALUE x)
COLDFUNC NORETURN(static void unexpected_type(VALUE, int, int));
#define UNDEF_LEAKED "undef leaked to the Ruby space"
+void
+rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected)
+{
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
+ actual->wrap_struct_name, expected->wrap_struct_name);
+}
+
+void
+rb_unexpected_object_type(VALUE obj, const char *expected)
+{
+ rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)",
+ displaying_class_of(obj), expected);
+}
+
static void
unexpected_type(VALUE x, int xt, int t)
{
@@ -1319,9 +1343,7 @@ unexpected_type(VALUE x, int xt, int t)
VALUE mesg, exc = rb_eFatal;
if (tname) {
- mesg = rb_sprintf("wrong argument type %"PRIsVALUE" (expected %s)",
- displaying_class_of(x), tname);
- exc = rb_eTypeError;
+ rb_unexpected_object_type(x, tname);
}
else if (xt > T_MASK && xt <= 0x3f) {
mesg = rb_sprintf("unknown type 0x%x (0x%x given, probably comes"
@@ -1342,8 +1364,7 @@ rb_check_type(VALUE x, int t)
rb_bug(UNDEF_LEAKED);
}
- xt = TYPE(x);
- if (xt != t || (xt == T_DATA && rbimpl_rtypeddata_p(x))) {
+ if (t == T_DATA) {
/*
* Typed data is not simple `T_DATA`, but in a sense an
* extension of `struct RVALUE`, which are incompatible with
@@ -1352,6 +1373,10 @@ rb_check_type(VALUE x, int t)
* So it is not enough to just check `T_DATA`, it must be
* identified by its `type` using `Check_TypedStruct` instead.
*/
+ rb_unexpected_object_type(x, builtin_types[t]);
+ }
+ xt = TYPE(x);
+ if (xt != t) {
unexpected_type(x, xt, t);
}
}
@@ -1366,24 +1391,18 @@ rb_unexpected_type(VALUE x, int t)
unexpected_type(x, TYPE(x), t);
}
+#undef rb_typeddata_inherited_p
int
rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent)
{
- while (child) {
- if (child == parent) return 1;
- child = child->parent;
- }
- return 0;
+ return rbimpl_typeddata_inherited_p_inline(child, parent);
}
+#undef rb_typeddata_is_kind_of
int
rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
{
- if (!RB_TYPE_P(obj, T_DATA) ||
- !RTYPEDDATA_P(obj) || !rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type)) {
- return 0;
- }
- return 1;
+ return rbimpl_typeddata_is_kind_of_inline(obj, data_type);
}
#undef rb_typeddata_is_instance_of
@@ -1396,26 +1415,7 @@ rb_typeddata_is_instance_of(VALUE obj, const rb_data_type_t *data_type)
void *
rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
{
- VALUE actual;
-
- if (!RB_TYPE_P(obj, T_DATA)) {
- actual = displaying_class_of(obj);
- }
- else if (!RTYPEDDATA_P(obj)) {
- actual = displaying_class_of(obj);
- }
- else if (!rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type)) {
- const char *name = RTYPEDDATA_TYPE(obj)->wrap_struct_name;
- actual = rb_str_new_cstr(name); /* or rb_fstring_cstr? not sure... */
- }
- else {
- return RTYPEDDATA_GET_DATA(obj);
- }
-
- const char *expected = data_type->wrap_struct_name;
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)",
- actual, expected);
- UNREACHABLE_RETURN(NULL);
+ return rbimpl_check_typeddata(obj, data_type);
}
/* exception classes */
@@ -1536,7 +1536,7 @@ exc_initialize(int argc, VALUE *argv, VALUE exc)
*
* x0 = StandardError.new('Boom') # => #<StandardError: Boom>
* x1 = x0.exception # => #<StandardError: Boom>
- * x0.__id__ == x1.__id__ # => true
+ * x0.equal?(x1) # => true
*
* With {string-convertible object}[rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects]
* +message+ (even the same as the original message),
@@ -1544,7 +1544,7 @@ exc_initialize(int argc, VALUE *argv, VALUE exc)
* and whose message is the given +message+:
*
* x1 = x0.exception('Boom') # => #<StandardError: Boom>
- * x0..equal?(x1) # => false
+ * x0.equal?(x1) # => false
*
*/
@@ -1686,7 +1686,7 @@ check_order_keyword(VALUE opt)
* - If the value of keyword +order+ is +:top+ (the default),
* lists the error message and the innermost backtrace entry first.
* - If the value of keyword +order+ is +:bottom+,
- * lists the error message the the innermost entry last.
+ * lists the error message the innermost entry last.
*
* Example:
*
@@ -1883,7 +1883,7 @@ exc_inspect(VALUE exc)
* # String
* end
*
- * The value returned by this method migth be adjusted when raising (see Kernel#raise),
+ * The value returned by this method might be adjusted when raising (see Kernel#raise),
* or during intermediate handling by #set_backtrace.
*
* See also #backtrace_locations that provide the same value, as structured objects.
@@ -2171,9 +2171,9 @@ try_convert_to_exception(VALUE obj)
/*
* call-seq:
- * self == object -> true or false
+ * self == other -> true or false
*
- * Returns whether +object+ is the same class as +self+
+ * Returns whether +other+ is the same class as +self+
* and its #message and #backtrace are equal to those of +self+.
*
*/
@@ -2379,7 +2379,7 @@ name_err_init_attr(VALUE exc, VALUE recv, VALUE method)
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));
+ rb_ivar_set(exc, id_iseq, rb_iseqw_new(CFP_ISEQ(cfp)));
}
return exc;
}
@@ -2517,30 +2517,21 @@ typedef struct name_error_message_struct {
} name_error_message_t;
static void
-name_err_mesg_mark(void *p)
+name_err_mesg_mark_and_move(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);
-}
-
-static void
-name_err_mesg_update(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);
+ rb_gc_mark_and_move(&ptr->mesg);
+ rb_gc_mark_and_move(&ptr->recv);
+ rb_gc_mark_and_move(&ptr->name);
}
static const rb_data_type_t name_err_mesg_data_type = {
"name_err_mesg",
{
- name_err_mesg_mark,
+ name_err_mesg_mark_and_move,
RUBY_TYPED_DEFAULT_FREE,
NULL, // No external memory to report,
- name_err_mesg_update,
+ name_err_mesg_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -2628,7 +2619,7 @@ name_err_mesg_to_str(VALUE obj)
VALUE mesg = ptr->mesg;
if (NIL_P(mesg)) return Qnil;
else {
- struct RString s_str, c_str, d_str;
+ struct RString s_str = {RBASIC_INIT}, c_str = {RBASIC_INIT}, d_str = {RBASIC_INIT};
VALUE c, s, d = 0, args[4], c2;
int state = 0;
rb_encoding *usascii = rb_usascii_encoding();
@@ -2779,6 +2770,68 @@ nometh_err_private_call_p(VALUE self)
return rb_attr_get(self, id_private_call_p);
}
+static const char *
+type_err_cname(VALUE val)
+{
+ if (NIL_P(val)) {
+ return "nil";
+ }
+ else if (val == Qtrue) {
+ return "true";
+ }
+ else if (val == Qfalse) {
+ return "false";
+ }
+ return NULL;
+}
+
+NORETURN(static void type_err_raise(VALUE val, const char *tname, const char *msg));
+static void
+type_err_raise(VALUE val, const char *tname, const char *msg)
+{
+ const char *cname = type_err_cname(val);
+ rb_encoding *enc = rb_utf8_encoding();
+ if (cname) {
+ rb_enc_raise(enc, rb_eTypeError, "%s %s into %s", msg, cname, tname);
+ }
+ rb_enc_raise(enc, rb_eTypeError, "%s %"PRIsVALUE" into %s", msg, rb_obj_class(val), tname);
+}
+
+NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname));
+void
+rb_no_implicit_conversion(VALUE val, const char *tname)
+{
+ type_err_raise(val, tname, "no implicit conversion of");
+}
+
+NORETURN(void rb_cant_convert(VALUE val, const char *tname));
+void
+rb_cant_convert(VALUE val, const char *tname)
+{
+ type_err_raise(val, tname, "can't convert");
+}
+
+NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret));
+void
+rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret)
+{
+ const char *cname = type_err_cname(val);
+ rb_encoding *enc = rb_utf8_encoding();
+ if (cname) {
+ rb_enc_raise(
+ enc, rb_eTypeError, "can't convert %s into %s (%s#%s gives %s)",
+ cname, tname, cname, method_name, type_err_cname(ret));
+ }
+ VALUE klass = rb_obj_class(val);
+ const char *retname = type_err_cname(ret);
+ if (!retname) {
+ retname = rb_obj_classname(ret);
+ }
+ rb_enc_raise(
+ enc, rb_eTypeError, "can't convert %"PRIsVALUE" into %s (%"PRIsVALUE"#%s gives %s)",
+ klass, tname, klass, method_name, retname);
+}
+
void
rb_invalid_str(const char *str, const char *type)
{
@@ -3500,6 +3553,18 @@ syserr_eqq(VALUE self, VALUE exc)
*/
/*
+ * Document-class: NoMatchingPatternError
+ *
+ * Raised when matching pattern not found.
+ */
+
+/*
+ * Document-class: NoMatchingPatternKeyError
+ *
+ * Raised when matching key not found.
+ */
+
+/*
* Document-class: fatal
*
* +fatal+ is an Exception that is raised when Ruby has encountered a fatal
@@ -4159,7 +4224,7 @@ rb_error_frozen_object(VALUE frozen_obj)
rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
VALUE mesg = rb_sprintf("can't modify frozen %"PRIsVALUE": ",
- CLASS_OF(frozen_obj));
+ rb_obj_class(frozen_obj));
VALUE exc = rb_exc_new_str(rb_eFrozenError, mesg);
rb_ivar_set(exc, id_recv, frozen_obj);
@@ -4195,7 +4260,8 @@ rb_warn_unchilled_literal(VALUE obj)
VALUE created = get_created_info(str, &line);
if (NIL_P(created)) {
rb_str_cat2(mesg, " (run with --debug-frozen-string-literal for more information)\n");
- } else {
+ }
+ else {
rb_str_cat2(mesg, "\n");
rb_str_append(mesg, created);
if (line) rb_str_catf(mesg, ":%d", line);
diff --git a/eval.c b/eval.c
index dba196c170..b6fedf11f3 100644
--- a/eval.c
+++ b/eval.c
@@ -37,6 +37,7 @@
#include "ruby/vm.h"
#include "vm_core.h"
#include "ractor_core.h"
+#include "zjit.h"
NORETURN(static void rb_raise_jump(VALUE, VALUE));
void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec);
@@ -78,7 +79,10 @@ ruby_setup(void)
#endif
Init_BareVM();
rb_vm_encoded_insn_data_table_init();
+ Init_enable_box();
Init_vm_objects();
+ Init_master_box();
+ Init_fstring_table();
EC_PUSH_TAG(GET_EC());
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
@@ -326,17 +330,24 @@ ruby_exec_node(void *n)
/*
* call-seq:
- * Module.nesting -> array
- *
- * Returns the list of +Modules+ nested at the point of call.
+ * Module.nesting -> array
+ *
+ * Returns nested module as an array of Module objects:
+ *
+ * module M0
+ * def self.speak = Module.nesting
+ * module M1
+ * def self.speak = Module.nesting
+ * module M2
+ * def self.speak = Module.nesting
+ * end
+ * end
+ * end
+ * M0.speak # => [M0]
+ * M0.speak.first.class # => Module
+ * M0::M1.speak # => [M0::M1, M0]
+ * M0::M1::M2.speak # => [M0::M1::M2, M0::M1, M0]
*
- * module M1
- * module M2
- * $a = Module.nesting
- * end
- * end
- * $a #=> [M1::M2, M1]
- * $a[0].name #=> "M1::M2"
*/
static VALUE
@@ -421,43 +432,14 @@ rb_class_modify_check(VALUE klass)
Check_Type(klass, T_CLASS);
}
if (RB_TYPE_P(klass, T_MODULE)) {
- rb_module_set_initialized(klass);
+ // TODO: shouldn't this only happen in a few places?
+ rb_class_set_initialized(klass);
}
if (OBJ_FROZEN(klass)) {
- const char *desc;
-
if (RCLASS_SINGLETON_P(klass)) {
- desc = "object";
klass = RCLASS_ATTACHED_OBJECT(klass);
- if (!SPECIAL_CONST_P(klass)) {
- switch (BUILTIN_TYPE(klass)) {
- case T_MODULE:
- case T_ICLASS:
- desc = "Module";
- break;
- case T_CLASS:
- desc = "Class";
- break;
- default:
- break;
- }
- }
- }
- else {
- switch (BUILTIN_TYPE(klass)) {
- case T_MODULE:
- case T_ICLASS:
- desc = "module";
- break;
- case T_CLASS:
- desc = "class";
- break;
- default:
- Check_Type(klass, T_CLASS);
- UNREACHABLE;
- }
}
- rb_frozen_error_raise(klass, "can't modify frozen %s: %"PRIsVALUE, desc, klass);
+ rb_error_frozen_object(klass);
}
}
@@ -528,10 +510,14 @@ exc_setup_message(const rb_execution_context_t *ec, VALUE mesg, VALUE *cause)
rb_exc_check_circular_cause(*cause);
#else
VALUE c = *cause;
- while (!NIL_P(c = rb_attr_get(c, id_cause))) {
+ while (!NIL_P(c)) {
if (c == mesg) {
rb_raise(rb_eArgError, "circular causes");
}
+ if (THROW_DATA_P(c)) {
+ break;
+ }
+ c = rb_attr_get(c, id_cause);
}
#endif
}
@@ -696,49 +682,142 @@ rb_interrupt(void)
rb_exc_raise(rb_exc_new(rb_eInterrupt, 0, 0));
}
-enum {raise_opt_cause, raise_max_opt}; /*< \private */
-
static int
-extract_raise_opts(int argc, VALUE *argv, VALUE *opts)
+extract_raise_options(int argc, VALUE *argv, VALUE *cause)
{
- int i;
+ // Keyword arguments:
+ static ID keywords[1] = {0};
+ if (!keywords[0]) {
+ CONST_ID(keywords[0], "cause");
+ }
+
if (argc > 0) {
- VALUE opt;
- argc = rb_scan_args(argc, argv, "*:", NULL, &opt);
- if (!NIL_P(opt)) {
- if (!RHASH_EMPTY_P(opt)) {
- ID keywords[1];
- CONST_ID(keywords[0], "cause");
- rb_get_kwargs(opt, keywords, 0, -1-raise_max_opt, opts);
- if (!RHASH_EMPTY_P(opt)) argv[argc++] = opt;
- return argc;
+ VALUE options;
+ argc = rb_scan_args(argc, argv, "*:", NULL, &options);
+
+ if (!NIL_P(options)) {
+ if (!RHASH_EMPTY_P(options)) {
+ // Extract optional cause keyword argument, leaving any other options alone:
+ rb_get_kwargs(options, keywords, 0, -2, cause);
+
+ // If there were any other options, add them back to the arguments:
+ if (!RHASH_EMPTY_P(options)) argv[argc++] = options;
}
}
}
- for (i = 0; i < raise_max_opt; ++i) {
- opts[i] = Qundef;
- }
+
return argc;
}
+/**
+ * Complete exception setup for cross-context raises (Thread#raise, Fiber#raise).
+ * Handles keyword extraction, validation, exception creation, and cause assignment.
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Argument array (will be modified for keyword extraction)
+ * @return Prepared exception object with cause applied
+ */
+VALUE
+rb_exception_setup(int argc, VALUE *argv)
+{
+ rb_execution_context_t *ec = GET_EC();
+
+ // Extract cause keyword argument:
+ VALUE cause = Qundef;
+ argc = extract_raise_options(argc, argv, &cause);
+
+ // Validate cause-only case:
+ if (argc == 0 && !UNDEF_P(cause)) {
+ rb_raise(rb_eArgError, "only cause is given with no arguments");
+ }
+
+ // Create exception:
+ VALUE exception;
+ if (argc == 0) {
+ exception = rb_exc_new(rb_eRuntimeError, 0, 0);
+ }
+ else {
+ exception = rb_make_exception(argc, argv);
+ }
+
+ VALUE resolved_cause = Qnil;
+
+ // Resolve cause with validation:
+ if (UNDEF_P(cause)) {
+ // No explicit cause - use automatic cause chaining from calling context:
+ resolved_cause = rb_ec_get_errinfo(ec);
+
+ // Prevent self-referential cause (e.g. `raise $!`):
+ if (resolved_cause == exception) {
+ resolved_cause = Qnil;
+ }
+ }
+ else if (NIL_P(cause)) {
+ // Explicit nil cause - prevent chaining:
+ resolved_cause = Qnil;
+ }
+ else {
+ // Explicit cause - validate and assign:
+ if (!rb_obj_is_kind_of(cause, rb_eException)) {
+ rb_raise(rb_eTypeError, "exception object expected");
+ }
+
+ if (cause == exception) {
+ // Prevent self-referential cause (e.g. `raise error, cause: error`) - although I'm not sure this is good behaviour, it's inherited from `Kernel#raise`.
+ resolved_cause = Qnil;
+ }
+ else {
+ // Check for circular causes:
+ VALUE current_cause = cause;
+ while (!NIL_P(current_cause)) {
+ // We guarantee that the cause chain is always terminated. Then, creating an exception with an existing cause is not circular as long as exception is not an existing cause of any other exception.
+ if (current_cause == exception) {
+ rb_raise(rb_eArgError, "circular causes");
+ }
+ if (THROW_DATA_P(current_cause)) {
+ break;
+ }
+ current_cause = rb_attr_get(current_cause, id_cause);
+ }
+ resolved_cause = cause;
+ }
+ }
+
+ // Apply cause to exception object (duplicate if frozen):
+ if (!UNDEF_P(resolved_cause)) {
+ if (OBJ_FROZEN(exception)) {
+ exception = rb_obj_dup(exception);
+ }
+ rb_ivar_set(exception, id_cause, resolved_cause);
+ }
+
+ return exception;
+}
+
VALUE
rb_f_raise(int argc, VALUE *argv)
{
- VALUE err;
- VALUE opts[raise_max_opt], *const cause = &opts[raise_opt_cause];
+ VALUE cause = Qundef;
+ argc = extract_raise_options(argc, argv, &cause);
- argc = extract_raise_opts(argc, argv, opts);
+ VALUE exception;
+
+ // Bare re-raise case:
if (argc == 0) {
- if (!UNDEF_P(*cause)) {
+ // Cause was extracted, but no arguments were provided:
+ if (!UNDEF_P(cause)) {
rb_raise(rb_eArgError, "only cause is given with no arguments");
}
- err = get_errinfo();
- if (!NIL_P(err)) {
+
+ // Otherwise, re-raise the current exception:
+ exception = get_errinfo();
+ if (!NIL_P(exception)) {
argc = 1;
- argv = &err;
+ argv = &exception;
}
}
- rb_raise_jump(rb_make_exception(argc, argv), *cause);
+
+ rb_raise_jump(rb_make_exception(argc, argv), cause);
UNREACHABLE_RETURN(Qnil);
}
@@ -851,6 +930,9 @@ rb_f_raise(int argc, VALUE *argv)
* With argument +exception+ not given,
* argument +message+ and keyword argument +cause+ may be given,
* but argument +backtrace+ may not be given.
+ *
+ * +cause+ can not be given as an only argument.
+ *
*/
static VALUE
@@ -1062,12 +1144,11 @@ rb_protect(VALUE (* proc) (VALUE), VALUE data, int *pstate)
}
VALUE
-rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
+rb_ec_ensure(rb_execution_context_t *ec, VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
{
enum ruby_tag_type state;
volatile VALUE result = Qnil;
VALUE errinfo;
- rb_execution_context_t * volatile ec = GET_EC();
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
result = (*b_proc) (data1);
@@ -1084,6 +1165,12 @@ rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE dat
return result;
}
+VALUE
+rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
+{
+ return rb_ec_ensure(GET_EC(), b_proc, data1, e_proc, data2);
+}
+
static ID
frame_func_id(const rb_control_frame_t *cfp)
{
@@ -1191,6 +1278,8 @@ rb_mod_append_features(VALUE module, VALUE include)
return module;
}
+static VALUE refinement_import_methods(int argc, VALUE *argv, VALUE refinement);
+
/*
* call-seq:
* include(module, ...) -> self
@@ -1344,9 +1433,11 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module)
}
superclass = refinement_superclass(superclass);
c = iclass = rb_include_class_new(module, superclass);
- RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass);
+ RCLASS_SET_REFINED_CLASS(c, klass);
- RCLASS_M_TBL(c) = RCLASS_M_TBL(module);
+ RCLASS_WRITE_M_TBL(c, RCLASS_M_TBL(module));
+
+ rb_class_subclass_add(klass, iclass);
rb_hash_aset(CREF_REFINEMENTS(cref), klass, iclass);
}
@@ -1401,6 +1492,12 @@ rb_using_module(const rb_cref_t *cref, VALUE module)
rb_clear_all_refinement_method_cache();
}
+void
+rb_vm_using_module(VALUE module)
+{
+ rb_using_module(rb_vm_cref_replace_with_duplicated_cref(), module);
+}
+
/*
* call-seq:
* target -> class_or_module
@@ -1441,43 +1538,26 @@ add_activated_refinement(VALUE activated_refinements,
}
superclass = refinement_superclass(superclass);
c = iclass = rb_include_class_new(refinement, superclass);
- RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass);
+ RCLASS_SET_REFINED_CLASS(c, klass);
+ rb_class_subclass_add(klass, iclass);
refinement = RCLASS_SUPER(refinement);
while (refinement && refinement != klass) {
- c = RCLASS_SET_SUPER(c, rb_include_class_new(refinement, RCLASS_SUPER(c)));
- RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass);
+ c = rb_class_set_super(c, rb_include_class_new(refinement, RCLASS_SUPER(c)));
+ RCLASS_SET_REFINED_CLASS(c, klass);
+ rb_class_subclass_add(klass, c);
refinement = RCLASS_SUPER(refinement);
}
rb_hash_aset(activated_refinements, klass, iclass);
}
-/*
- * call-seq:
- * refine(mod) { block } -> module
- *
- * Refine <i>mod</i> in the receiver.
- *
- * Returns a module, where refined methods are defined.
- */
-
-static VALUE
-rb_mod_refine(VALUE module, VALUE klass)
+void
+rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass)
{
VALUE refinement;
ID id_refinements, id_activated_refinements,
id_refined_class, id_defined_at;
VALUE refinements, activated_refinements;
- rb_thread_t *th = GET_THREAD();
- VALUE block_handler = rb_vm_frame_block_handler(th->ec->cfp);
- if (block_handler == VM_BLOCK_HANDLER_NONE) {
- rb_raise(rb_eArgError, "no block given");
- }
- if (vm_block_handler_type(block_handler) != block_handler_type_iseq) {
- rb_raise(rb_eArgError, "can't pass a Proc as a block to Module#refine");
- }
-
- ensure_class_or_module(klass);
CONST_ID(id_refinements, "__refinements__");
refinements = rb_attr_get(module, id_refinements);
if (NIL_P(refinements)) {
@@ -1495,7 +1575,7 @@ rb_mod_refine(VALUE module, VALUE klass)
if (NIL_P(refinement)) {
VALUE superclass = refinement_superclass(klass);
refinement = rb_refinement_new();
- RCLASS_SET_SUPER(refinement, superclass);
+ rb_class_set_super(refinement, superclass);
RUBY_ASSERT(BUILTIN_TYPE(refinement) == T_MODULE);
FL_SET(refinement, RMODULE_IS_REFINEMENT);
CONST_ID(id_refined_class, "__refined_class__");
@@ -1505,8 +1585,41 @@ rb_mod_refine(VALUE module, VALUE klass)
rb_hash_aset(refinements, klass, refinement);
add_activated_refinement(activated_refinements, klass, refinement);
}
- rb_yield_refine_block(refinement, activated_refinements);
- return refinement;
+
+ data->refinement = refinement;
+ data->refinements = activated_refinements;
+}
+
+/*
+ * call-seq:
+ * refine(mod) { block } -> module
+ *
+ * Refine <i>mod</i> in the receiver.
+ *
+ * Returns a module, where refined methods are defined.
+ */
+
+static VALUE
+rb_mod_refine(VALUE module, VALUE klass)
+{
+ /* module is the receiver of #refine, klass is a module to be refined (`mod` in the doc) */
+ rb_thread_t *th = GET_THREAD();
+ VALUE block_handler = rb_vm_frame_block_handler(th->ec->cfp);
+ struct rb_refinements_data data;
+
+ if (block_handler == VM_BLOCK_HANDLER_NONE) {
+ rb_raise(rb_eArgError, "no block given");
+ }
+ if (vm_block_handler_type(block_handler) != block_handler_type_iseq) {
+ rb_raise(rb_eArgError, "can't pass a Proc as a block to Module#refine");
+ }
+
+ ensure_class_or_module(klass);
+
+ rb_refinement_setup(&data, module, klass);
+
+ rb_yield_refine_block(data.refinement, data.refinements);
+ return data.refinement;
}
static void
@@ -1898,10 +2011,10 @@ errinfo_place(const rb_execution_context_t *ec)
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
if (VM_FRAME_RUBYFRAME_P(cfp)) {
- if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_RESCUE) {
+ if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_RESCUE) {
return &cfp->ep[VM_ENV_INDEX_LAST_LVAR];
}
- else if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_ENSURE &&
+ else if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_ENSURE &&
!THROW_DATA_P(cfp->ep[VM_ENV_INDEX_LAST_LVAR]) &&
!FIXNUM_P(cfp->ep[VM_ENV_INDEX_LAST_LVAR])) {
return &cfp->ep[VM_ENV_INDEX_LAST_LVAR];
@@ -2111,6 +2224,9 @@ Init_eval(void)
rb_gvar_ractor_local("$@");
rb_gvar_ractor_local("$!");
+ rb_gvar_box_dynamic("$@");
+ rb_gvar_box_dynamic("$!");
+
rb_define_global_function("raise", f_raise, -1);
rb_define_global_function("fail", f_raise, -1);
diff --git a/eval_intern.h b/eval_intern.h
index 49229fa82d..954ba6a184 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -3,6 +3,7 @@
#include "ruby/ruby.h"
#include "vm_core.h"
+#include "zjit.h"
static inline void
vm_passed_block_handler_set(rb_execution_context_t *ec, VALUE block_handler)
@@ -102,11 +103,21 @@ 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);
+ EC_SAVE_TAG_CFP(_tag, _ec); \
+ rb_vm_tag_jmpbuf_init(&_tag.buf); \
+
+// Remember the CFP as of EC_PUSH_TAG so that ZJIT can materialize frames
+// only up to longjmp's target CFP. When a C method does longjmp inside it,
+// the target CFP may not be equal to the VM_FRAME_FLAG_FINISH frame.
+#if USE_ZJIT
+# define EC_SAVE_TAG_CFP(_tag, _ec) _tag.cfp = _ec->cfp
+#else
+# define EC_SAVE_TAG_CFP(_tag, _ec)
+#endif
#define EC_POP_TAG() \
_ec->tag = _tag.prev; \
- rb_vm_tag_jmpbuf_deinit(&_tag); \
+ rb_vm_tag_jmpbuf_deinit(&_tag.buf); \
} while (0)
#define EC_TMPPOP_TAG() \
@@ -155,6 +166,9 @@ static inline void
rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
{
RUBY_ASSERT(st > TAG_NONE && st <= TAG_FATAL, ": Invalid tag jump: %d", (int)st);
+#if USE_ZJIT
+ rb_zjit_materialize_frames(ec, ec->cfp);
+#endif
ec->tag->state = st;
ruby_longjmp(RB_VM_TAG_JMPBUF_GET(ec->tag->buf), 1);
}
@@ -172,9 +186,10 @@ rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
/* CREF operators */
-#define CREF_FL_PUSHED_BY_EVAL IMEMO_FL_USER1
-#define CREF_FL_OMOD_SHARED IMEMO_FL_USER2
-#define CREF_FL_SINGLETON IMEMO_FL_USER3
+#define CREF_FL_PUSHED_BY_EVAL IMEMO_FL_USER1
+#define CREF_FL_OMOD_SHARED IMEMO_FL_USER2
+#define CREF_FL_SINGLETON IMEMO_FL_USER3
+#define CREF_FL_DYNAMIC_CREF IMEMO_FL_USER4
static inline int CREF_SINGLETON(const rb_cref_t *cref);
@@ -260,6 +275,18 @@ CREF_OMOD_SHARED_SET(rb_cref_t *cref)
cref->flags |= CREF_FL_OMOD_SHARED;
}
+static inline int
+CREF_DYNAMIC(const rb_cref_t *cref)
+{
+ return cref->flags & CREF_FL_DYNAMIC_CREF;
+}
+
+static inline void
+CREF_DYNAMIC_SET(rb_cref_t *cref)
+{
+ cref->flags |= CREF_FL_DYNAMIC_CREF;
+}
+
static inline void
CREF_OMOD_SHARED_UNSET(rb_cref_t *cref)
{
@@ -296,6 +323,11 @@ VALUE rb_vm_make_jump_tag_but_local_jump(enum ruby_tag_type state, VALUE val);
rb_cref_t *rb_vm_cref(void);
rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void);
VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename);
+VALUE rb_vm_call_cfunc_in_box(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE filename, const rb_box_t *box);
+void rb_vm_frame_flag_set_box_require(const rb_execution_context_t *ec);
+const rb_box_t *rb_vm_current_box(const rb_execution_context_t *ec);
+const rb_box_t *rb_vm_caller_box(const rb_execution_context_t *ec);
+const rb_box_t *rb_vm_loading_box(const rb_execution_context_t *ec);
void rb_vm_set_progname(VALUE filename);
VALUE rb_vm_cbase(void);
diff --git a/eval_jump.c b/eval_jump.c
index 7593a35e36..6ee8ff4a6f 100644
--- a/eval_jump.c
+++ b/eval_jump.c
@@ -101,7 +101,7 @@ exec_end_procs_chain(struct end_proc_data *volatile *procs, VALUE *errp)
while ((link = *procs) != 0) {
*procs = link->next;
endproc = *link;
- xfree(link);
+ SIZED_FREE(link);
(*endproc.func) (endproc.data);
*errp = errinfo;
}
diff --git a/ext/-test-/RUBY_ALIGNOF/depend b/ext/-test-/RUBY_ALIGNOF/depend
index 25364e55fb..103d20b33c 100644
--- a/ext/-test-/RUBY_ALIGNOF/depend
+++ b/ext/-test-/RUBY_ALIGNOF/depend
@@ -128,6 +128,7 @@ c.o: $(hdrdir)/ruby/internal/intern/re.h
c.o: $(hdrdir)/ruby/internal/intern/ruby.h
c.o: $(hdrdir)/ruby/internal/intern/select.h
c.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+c.o: $(hdrdir)/ruby/internal/intern/set.h
c.o: $(hdrdir)/ruby/internal/intern/signal.h
c.o: $(hdrdir)/ruby/internal/intern/sprintf.h
c.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/abi/depend b/ext/-test-/abi/depend
new file mode 100644
index 0000000000..716a7b1356
--- /dev/null
+++ b/ext/-test-/abi/depend
@@ -0,0 +1,3 @@
+# AUTOGENERATED DEPENDENCIES START
+abi.o: abi.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/arith_seq/beg_len_step/depend b/ext/-test-/arith_seq/beg_len_step/depend
index 702a0037a8..098c8ff1f0 100644
--- a/ext/-test-/arith_seq/beg_len_step/depend
+++ b/ext/-test-/arith_seq/beg_len_step/depend
@@ -127,6 +127,7 @@ beg_len_step.o: $(hdrdir)/ruby/internal/intern/re.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/ruby.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/select.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+beg_len_step.o: $(hdrdir)/ruby/internal/intern/set.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/signal.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/sprintf.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/arith_seq/extract/depend b/ext/-test-/arith_seq/extract/depend
index fdbd71dfbc..5c07cea4b4 100644
--- a/ext/-test-/arith_seq/extract/depend
+++ b/ext/-test-/arith_seq/extract/depend
@@ -127,6 +127,7 @@ extract.o: $(hdrdir)/ruby/internal/intern/re.h
extract.o: $(hdrdir)/ruby/internal/intern/ruby.h
extract.o: $(hdrdir)/ruby/internal/intern/select.h
extract.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+extract.o: $(hdrdir)/ruby/internal/intern/set.h
extract.o: $(hdrdir)/ruby/internal/intern/signal.h
extract.o: $(hdrdir)/ruby/internal/intern/sprintf.h
extract.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/array/concat/depend b/ext/-test-/array/concat/depend
index f2213a42ea..8edf45465f 100644
--- a/ext/-test-/array/concat/depend
+++ b/ext/-test-/array/concat/depend
@@ -128,6 +128,7 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/intern/re.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/ruby.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/select.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/intern/set.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/signal.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/array/resize/depend b/ext/-test-/array/resize/depend
index f88a9d03c1..e6a228b43d 100644
--- a/ext/-test-/array/resize/depend
+++ b/ext/-test-/array/resize/depend
@@ -127,6 +127,7 @@ resize.o: $(hdrdir)/ruby/internal/intern/re.h
resize.o: $(hdrdir)/ruby/internal/intern/ruby.h
resize.o: $(hdrdir)/ruby/internal/intern/select.h
resize.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+resize.o: $(hdrdir)/ruby/internal/intern/set.h
resize.o: $(hdrdir)/ruby/internal/intern/signal.h
resize.o: $(hdrdir)/ruby/internal/intern/sprintf.h
resize.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/asan/asan.c b/ext/-test-/asan/asan.c
deleted file mode 100644
index 45b6253fda..0000000000
--- a/ext/-test-/asan/asan.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "ruby/ruby.h"
-
-static VALUE
-asan_enabled_p(VALUE self)
-{
-#if defined(__has_feature)
- /* clang uses __has_feature for determining asan */
- return __has_feature(address_sanitizer) ? Qtrue : Qfalse;
-#elif defined(__SANITIZE_ADDRESS__)
- /* GCC sets __SANITIZE_ADDRESS__ for determining asan */
- return Qtrue;
-#else
- return Qfalse;
-#endif
-}
-
-void
-Init_asan(void)
-{
- VALUE m = rb_define_module("Test");
- VALUE c = rb_define_class_under(m, "ASAN", rb_cObject);
- rb_define_singleton_method(c, "enabled?", asan_enabled_p, 0);
-}
-
diff --git a/ext/-test-/asan/extconf.rb b/ext/-test-/asan/extconf.rb
deleted file mode 100644
index ec02742b81..0000000000
--- a/ext/-test-/asan/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'mkmf'
-create_makefile('-test-/asan')
diff --git a/ext/-test-/bignum/depend b/ext/-test-/bignum/depend
index 078915ab72..82972f1032 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -6,6 +6,7 @@ big2str.o: $(hdrdir)/ruby/backward.h
big2str.o: $(hdrdir)/ruby/backward/2/assume.h
big2str.o: $(hdrdir)/ruby/backward/2/attributes.h
big2str.o: $(hdrdir)/ruby/backward/2/bool.h
+big2str.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
big2str.o: $(hdrdir)/ruby/backward/2/inttypes.h
big2str.o: $(hdrdir)/ruby/backward/2/limits.h
big2str.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -127,6 +128,7 @@ big2str.o: $(hdrdir)/ruby/internal/intern/re.h
big2str.o: $(hdrdir)/ruby/internal/intern/ruby.h
big2str.o: $(hdrdir)/ruby/internal/intern/select.h
big2str.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+big2str.o: $(hdrdir)/ruby/internal/intern/set.h
big2str.o: $(hdrdir)/ruby/internal/intern/signal.h
big2str.o: $(hdrdir)/ruby/internal/intern/sprintf.h
big2str.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -158,6 +160,7 @@ big2str.o: $(hdrdir)/ruby/ruby.h
big2str.o: $(hdrdir)/ruby/st.h
big2str.o: $(hdrdir)/ruby/subst.h
big2str.o: $(top_srcdir)/internal/bignum.h
+big2str.o: $(top_srcdir)/internal/compilers.h
big2str.o: big2str.c
bigzero.o: $(RUBY_EXTCONF_H)
bigzero.o: $(arch_hdrdir)/ruby/config.h
@@ -166,6 +169,7 @@ bigzero.o: $(hdrdir)/ruby/backward.h
bigzero.o: $(hdrdir)/ruby/backward/2/assume.h
bigzero.o: $(hdrdir)/ruby/backward/2/attributes.h
bigzero.o: $(hdrdir)/ruby/backward/2/bool.h
+bigzero.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
bigzero.o: $(hdrdir)/ruby/backward/2/inttypes.h
bigzero.o: $(hdrdir)/ruby/backward/2/limits.h
bigzero.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -287,6 +291,7 @@ bigzero.o: $(hdrdir)/ruby/internal/intern/re.h
bigzero.o: $(hdrdir)/ruby/internal/intern/ruby.h
bigzero.o: $(hdrdir)/ruby/internal/intern/select.h
bigzero.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bigzero.o: $(hdrdir)/ruby/internal/intern/set.h
bigzero.o: $(hdrdir)/ruby/internal/intern/signal.h
bigzero.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bigzero.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -318,6 +323,7 @@ bigzero.o: $(hdrdir)/ruby/ruby.h
bigzero.o: $(hdrdir)/ruby/st.h
bigzero.o: $(hdrdir)/ruby/subst.h
bigzero.o: $(top_srcdir)/internal/bignum.h
+bigzero.o: $(top_srcdir)/internal/compilers.h
bigzero.o: bigzero.c
div.o: $(RUBY_EXTCONF_H)
div.o: $(arch_hdrdir)/ruby/config.h
@@ -326,6 +332,7 @@ div.o: $(hdrdir)/ruby/backward.h
div.o: $(hdrdir)/ruby/backward/2/assume.h
div.o: $(hdrdir)/ruby/backward/2/attributes.h
div.o: $(hdrdir)/ruby/backward/2/bool.h
+div.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
div.o: $(hdrdir)/ruby/backward/2/inttypes.h
div.o: $(hdrdir)/ruby/backward/2/limits.h
div.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -447,6 +454,7 @@ div.o: $(hdrdir)/ruby/internal/intern/re.h
div.o: $(hdrdir)/ruby/internal/intern/ruby.h
div.o: $(hdrdir)/ruby/internal/intern/select.h
div.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+div.o: $(hdrdir)/ruby/internal/intern/set.h
div.o: $(hdrdir)/ruby/internal/intern/signal.h
div.o: $(hdrdir)/ruby/internal/intern/sprintf.h
div.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -478,6 +486,7 @@ div.o: $(hdrdir)/ruby/ruby.h
div.o: $(hdrdir)/ruby/st.h
div.o: $(hdrdir)/ruby/subst.h
div.o: $(top_srcdir)/internal/bignum.h
+div.o: $(top_srcdir)/internal/compilers.h
div.o: div.c
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
@@ -608,6 +617,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -646,6 +656,7 @@ intpack.o: $(hdrdir)/ruby/backward.h
intpack.o: $(hdrdir)/ruby/backward/2/assume.h
intpack.o: $(hdrdir)/ruby/backward/2/attributes.h
intpack.o: $(hdrdir)/ruby/backward/2/bool.h
+intpack.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
intpack.o: $(hdrdir)/ruby/backward/2/inttypes.h
intpack.o: $(hdrdir)/ruby/backward/2/limits.h
intpack.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -767,6 +778,7 @@ intpack.o: $(hdrdir)/ruby/internal/intern/re.h
intpack.o: $(hdrdir)/ruby/internal/intern/ruby.h
intpack.o: $(hdrdir)/ruby/internal/intern/select.h
intpack.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+intpack.o: $(hdrdir)/ruby/internal/intern/set.h
intpack.o: $(hdrdir)/ruby/internal/intern/signal.h
intpack.o: $(hdrdir)/ruby/internal/intern/sprintf.h
intpack.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -798,6 +810,7 @@ intpack.o: $(hdrdir)/ruby/ruby.h
intpack.o: $(hdrdir)/ruby/st.h
intpack.o: $(hdrdir)/ruby/subst.h
intpack.o: $(top_srcdir)/internal/bignum.h
+intpack.o: $(top_srcdir)/internal/compilers.h
intpack.o: intpack.c
mul.o: $(RUBY_EXTCONF_H)
mul.o: $(arch_hdrdir)/ruby/config.h
@@ -806,6 +819,7 @@ mul.o: $(hdrdir)/ruby/backward.h
mul.o: $(hdrdir)/ruby/backward/2/assume.h
mul.o: $(hdrdir)/ruby/backward/2/attributes.h
mul.o: $(hdrdir)/ruby/backward/2/bool.h
+mul.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
mul.o: $(hdrdir)/ruby/backward/2/inttypes.h
mul.o: $(hdrdir)/ruby/backward/2/limits.h
mul.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -927,6 +941,7 @@ mul.o: $(hdrdir)/ruby/internal/intern/re.h
mul.o: $(hdrdir)/ruby/internal/intern/ruby.h
mul.o: $(hdrdir)/ruby/internal/intern/select.h
mul.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+mul.o: $(hdrdir)/ruby/internal/intern/set.h
mul.o: $(hdrdir)/ruby/internal/intern/signal.h
mul.o: $(hdrdir)/ruby/internal/intern/sprintf.h
mul.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -958,6 +973,7 @@ mul.o: $(hdrdir)/ruby/ruby.h
mul.o: $(hdrdir)/ruby/st.h
mul.o: $(hdrdir)/ruby/subst.h
mul.o: $(top_srcdir)/internal/bignum.h
+mul.o: $(top_srcdir)/internal/compilers.h
mul.o: mul.c
str2big.o: $(RUBY_EXTCONF_H)
str2big.o: $(arch_hdrdir)/ruby/config.h
@@ -966,6 +982,7 @@ str2big.o: $(hdrdir)/ruby/backward.h
str2big.o: $(hdrdir)/ruby/backward/2/assume.h
str2big.o: $(hdrdir)/ruby/backward/2/attributes.h
str2big.o: $(hdrdir)/ruby/backward/2/bool.h
+str2big.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
str2big.o: $(hdrdir)/ruby/backward/2/inttypes.h
str2big.o: $(hdrdir)/ruby/backward/2/limits.h
str2big.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -1087,6 +1104,7 @@ str2big.o: $(hdrdir)/ruby/internal/intern/re.h
str2big.o: $(hdrdir)/ruby/internal/intern/ruby.h
str2big.o: $(hdrdir)/ruby/internal/intern/select.h
str2big.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+str2big.o: $(hdrdir)/ruby/internal/intern/set.h
str2big.o: $(hdrdir)/ruby/internal/intern/signal.h
str2big.o: $(hdrdir)/ruby/internal/intern/sprintf.h
str2big.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1118,5 +1136,6 @@ str2big.o: $(hdrdir)/ruby/ruby.h
str2big.o: $(hdrdir)/ruby/st.h
str2big.o: $(hdrdir)/ruby/subst.h
str2big.o: $(top_srcdir)/internal/bignum.h
+str2big.o: $(top_srcdir)/internal/compilers.h
str2big.o: str2big.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/box/yay1/extconf.rb b/ext/-test-/box/yay1/extconf.rb
new file mode 100644
index 0000000000..54387cedf1
--- /dev/null
+++ b/ext/-test-/box/yay1/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/box/yay1')
diff --git a/ext/-test-/box/yay1/yay1.c b/ext/-test-/box/yay1/yay1.c
new file mode 100644
index 0000000000..564a221c8c
--- /dev/null
+++ b/ext/-test-/box/yay1/yay1.c
@@ -0,0 +1,28 @@
+#include "yay1.h"
+
+VALUE
+yay_value(void)
+{
+ return rb_str_new_cstr("yay");
+}
+
+static VALUE
+yay1_f_version(VALUE klass)
+{
+ return rb_str_new_cstr("1.0.0");
+}
+
+static VALUE
+yay1_yay(VALUE klass)
+{
+ return yay_value();
+}
+
+void
+Init_yay1(void)
+{
+ VALUE mod = rb_define_module("Yay");
+ rb_define_const(mod, "VERSION", rb_str_new_cstr("1.0.0"));
+ rb_define_singleton_method(mod, "version", yay1_f_version, 0);
+ rb_define_singleton_method(mod, "yay", yay1_yay, 0);
+}
diff --git a/ext/-test-/box/yay1/yay1.def b/ext/-test-/box/yay1/yay1.def
new file mode 100644
index 0000000000..510fbe7017
--- /dev/null
+++ b/ext/-test-/box/yay1/yay1.def
@@ -0,0 +1,3 @@
+EXPORTS
+ Init_yay1
+ yay_value
diff --git a/ext/-test-/box/yay1/yay1.h b/ext/-test-/box/yay1/yay1.h
new file mode 100644
index 0000000000..c4dade928a
--- /dev/null
+++ b/ext/-test-/box/yay1/yay1.h
@@ -0,0 +1,4 @@
+#include <ruby.h>
+#include "ruby/internal/dllexport.h"
+
+RUBY_FUNC_EXPORTED VALUE yay_value(void);
diff --git a/ext/-test-/box/yay2/extconf.rb b/ext/-test-/box/yay2/extconf.rb
new file mode 100644
index 0000000000..850ef3edc9
--- /dev/null
+++ b/ext/-test-/box/yay2/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/box/yay2')
diff --git a/ext/-test-/box/yay2/yay2.c b/ext/-test-/box/yay2/yay2.c
new file mode 100644
index 0000000000..b632ae8495
--- /dev/null
+++ b/ext/-test-/box/yay2/yay2.c
@@ -0,0 +1,28 @@
+#include "yay2.h"
+
+VALUE
+yay_value(void)
+{
+ return rb_str_new_cstr("yaaay");
+}
+
+static VALUE
+yay2_f_version(VALUE klass)
+{
+ return rb_str_new_cstr("2.0.0");
+}
+
+static VALUE
+yay2_yay(VALUE klass)
+{
+ return yay_value();
+}
+
+void
+Init_yay2(void)
+{
+ VALUE mod = rb_define_module("Yay");
+ rb_define_const(mod, "VERSION", rb_str_new_cstr("2.0.0"));
+ rb_define_singleton_method(mod, "version", yay2_f_version, 0);
+ rb_define_singleton_method(mod, "yay", yay2_yay, 0);
+}
diff --git a/ext/-test-/box/yay2/yay2.def b/ext/-test-/box/yay2/yay2.def
new file mode 100644
index 0000000000..163fc44c04
--- /dev/null
+++ b/ext/-test-/box/yay2/yay2.def
@@ -0,0 +1,3 @@
+EXPORTS
+ Init_yay2
+ yay_value
diff --git a/ext/-test-/box/yay2/yay2.h b/ext/-test-/box/yay2/yay2.h
new file mode 100644
index 0000000000..c4dade928a
--- /dev/null
+++ b/ext/-test-/box/yay2/yay2.h
@@ -0,0 +1,4 @@
+#include <ruby.h>
+#include "ruby/internal/dllexport.h"
+
+RUBY_FUNC_EXPORTED VALUE yay_value(void);
diff --git a/ext/-test-/bug-14834/depend b/ext/-test-/bug-14834/depend
index 38429918b1..f83939d559 100644
--- a/ext/-test-/bug-14834/depend
+++ b/ext/-test-/bug-14834/depend
@@ -128,6 +128,7 @@ bug-14834.o: $(hdrdir)/ruby/internal/intern/re.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/select.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug-14834.o: $(hdrdir)/ruby/internal/intern/set.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/signal.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/bug-3571/depend b/ext/-test-/bug-3571/depend
index 84517a9c15..69c970b6f2 100644
--- a/ext/-test-/bug-3571/depend
+++ b/ext/-test-/bug-3571/depend
@@ -128,6 +128,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/re.h
bug.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug.o: $(hdrdir)/ruby/internal/intern/select.h
bug.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug.o: $(hdrdir)/ruby/internal/intern/set.h
bug.o: $(hdrdir)/ruby/internal/intern/signal.h
bug.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/bug-5832/depend b/ext/-test-/bug-5832/depend
index 84517a9c15..69c970b6f2 100644
--- a/ext/-test-/bug-5832/depend
+++ b/ext/-test-/bug-5832/depend
@@ -128,6 +128,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/re.h
bug.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug.o: $(hdrdir)/ruby/internal/intern/select.h
bug.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug.o: $(hdrdir)/ruby/internal/intern/set.h
bug.o: $(hdrdir)/ruby/internal/intern/signal.h
bug.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/bug_reporter/depend b/ext/-test-/bug_reporter/depend
index 1c73234247..e9993c3295 100644
--- a/ext/-test-/bug_reporter/depend
+++ b/ext/-test-/bug_reporter/depend
@@ -128,6 +128,7 @@ bug_reporter.o: $(hdrdir)/ruby/internal/intern/re.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/select.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug_reporter.o: $(hdrdir)/ruby/internal/intern/set.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/signal.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/class/depend b/ext/-test-/class/depend
index b0595fdc46..557206cefb 100644
--- a/ext/-test-/class/depend
+++ b/ext/-test-/class/depend
@@ -127,6 +127,7 @@ class2name.o: $(hdrdir)/ruby/internal/intern/re.h
class2name.o: $(hdrdir)/ruby/internal/intern/ruby.h
class2name.o: $(hdrdir)/ruby/internal/intern/select.h
class2name.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+class2name.o: $(hdrdir)/ruby/internal/intern/set.h
class2name.o: $(hdrdir)/ruby/internal/intern/signal.h
class2name.o: $(hdrdir)/ruby/internal/intern/sprintf.h
class2name.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -287,6 +288,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/cxxanyargs/cxxanyargs.cpp b/ext/-test-/cxxanyargs/cxxanyargs.cpp
index eded13e2ee..c7df7f9038 100644
--- a/ext/-test-/cxxanyargs/cxxanyargs.cpp
+++ b/ext/-test-/cxxanyargs/cxxanyargs.cpp
@@ -97,31 +97,6 @@ struct test_rb_define_hooked_variable {
};
VALUE test_rb_define_hooked_variable::v = Qundef;
-namespace test_rb_iterate {
- VALUE
- iter(VALUE self)
- {
- return rb_funcall(self, rb_intern("yield"), 0);
- }
-
- VALUE
- block(RB_BLOCK_CALL_FUNC_ARGLIST(arg, param))
- {
- return rb_funcall(arg, rb_intern("=="), 1, param);
- }
-
- VALUE
- test(VALUE self)
- {
-#ifdef HAVE_NULLPTR
- rb_iterate(iter, self, nullptr, self);
-#endif
-
- rb_iterate(iter, self, RUBY_METHOD_FUNC(block), self); // old
- return rb_iterate(iter, self, block, self); // new
- }
-}
-
namespace test_rb_block_call {
VALUE
block(RB_BLOCK_CALL_FUNC_ARGLIST(arg, param))
@@ -936,7 +911,6 @@ Init_cxxanyargs(void)
test(rb_define_virtual_variable);
test(rb_define_hooked_variable);
- test(rb_iterate);
test(rb_block_call);
test(rb_rescue);
test(rb_rescue2);
diff --git a/ext/-test-/debug/depend b/ext/-test-/debug/depend
index 67e32c6aa6..4ae0378ef2 100644
--- a/ext/-test-/debug/depend
+++ b/ext/-test-/debug/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ inspector.o: $(hdrdir)/ruby/internal/intern/re.h
inspector.o: $(hdrdir)/ruby/internal/intern/ruby.h
inspector.o: $(hdrdir)/ruby/internal/intern/select.h
inspector.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+inspector.o: $(hdrdir)/ruby/internal/intern/set.h
inspector.o: $(hdrdir)/ruby/internal/intern/signal.h
inspector.o: $(hdrdir)/ruby/internal/intern/sprintf.h
inspector.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ profile_frames.o: $(hdrdir)/ruby/internal/intern/re.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/ruby.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/select.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+profile_frames.o: $(hdrdir)/ruby/internal/intern/set.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/signal.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/sprintf.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/dln/empty/depend b/ext/-test-/dln/empty/depend
index d3e606df57..58f1508598 100644
--- a/ext/-test-/dln/empty/depend
+++ b/ext/-test-/dln/empty/depend
@@ -128,6 +128,7 @@ empty.o: $(hdrdir)/ruby/internal/intern/re.h
empty.o: $(hdrdir)/ruby/internal/intern/ruby.h
empty.o: $(hdrdir)/ruby/internal/intern/select.h
empty.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+empty.o: $(hdrdir)/ruby/internal/intern/set.h
empty.o: $(hdrdir)/ruby/internal/intern/signal.h
empty.o: $(hdrdir)/ruby/internal/intern/sprintf.h
empty.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/econv/depend b/ext/-test-/econv/depend
new file mode 100644
index 0000000000..3a5bc9c659
--- /dev/null
+++ b/ext/-test-/econv/depend
@@ -0,0 +1,336 @@
+# AUTOGENERATED DEPENDENCIES START
+append.o: $(RUBY_EXTCONF_H)
+append.o: $(arch_hdrdir)/ruby/config.h
+append.o: $(hdrdir)/ruby.h
+append.o: $(hdrdir)/ruby/assert.h
+append.o: $(hdrdir)/ruby/backward.h
+append.o: $(hdrdir)/ruby/backward/2/assume.h
+append.o: $(hdrdir)/ruby/backward/2/attributes.h
+append.o: $(hdrdir)/ruby/backward/2/bool.h
+append.o: $(hdrdir)/ruby/backward/2/inttypes.h
+append.o: $(hdrdir)/ruby/backward/2/limits.h
+append.o: $(hdrdir)/ruby/backward/2/long_long.h
+append.o: $(hdrdir)/ruby/backward/2/stdalign.h
+append.o: $(hdrdir)/ruby/backward/2/stdarg.h
+append.o: $(hdrdir)/ruby/defines.h
+append.o: $(hdrdir)/ruby/encoding.h
+append.o: $(hdrdir)/ruby/intern.h
+append.o: $(hdrdir)/ruby/internal/abi.h
+append.o: $(hdrdir)/ruby/internal/anyargs.h
+append.o: $(hdrdir)/ruby/internal/arithmetic.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+append.o: $(hdrdir)/ruby/internal/assume.h
+append.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+append.o: $(hdrdir)/ruby/internal/attr/artificial.h
+append.o: $(hdrdir)/ruby/internal/attr/cold.h
+append.o: $(hdrdir)/ruby/internal/attr/const.h
+append.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+append.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+append.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+append.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+append.o: $(hdrdir)/ruby/internal/attr/error.h
+append.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+append.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+append.o: $(hdrdir)/ruby/internal/attr/format.h
+append.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+append.o: $(hdrdir)/ruby/internal/attr/noalias.h
+append.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+append.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+append.o: $(hdrdir)/ruby/internal/attr/noinline.h
+append.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+append.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+append.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+append.o: $(hdrdir)/ruby/internal/attr/pure.h
+append.o: $(hdrdir)/ruby/internal/attr/restrict.h
+append.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+append.o: $(hdrdir)/ruby/internal/attr/warning.h
+append.o: $(hdrdir)/ruby/internal/attr/weakref.h
+append.o: $(hdrdir)/ruby/internal/cast.h
+append.o: $(hdrdir)/ruby/internal/compiler_is.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+append.o: $(hdrdir)/ruby/internal/compiler_since.h
+append.o: $(hdrdir)/ruby/internal/config.h
+append.o: $(hdrdir)/ruby/internal/constant_p.h
+append.o: $(hdrdir)/ruby/internal/core.h
+append.o: $(hdrdir)/ruby/internal/core/rarray.h
+append.o: $(hdrdir)/ruby/internal/core/rbasic.h
+append.o: $(hdrdir)/ruby/internal/core/rbignum.h
+append.o: $(hdrdir)/ruby/internal/core/rclass.h
+append.o: $(hdrdir)/ruby/internal/core/rdata.h
+append.o: $(hdrdir)/ruby/internal/core/rfile.h
+append.o: $(hdrdir)/ruby/internal/core/rhash.h
+append.o: $(hdrdir)/ruby/internal/core/robject.h
+append.o: $(hdrdir)/ruby/internal/core/rregexp.h
+append.o: $(hdrdir)/ruby/internal/core/rstring.h
+append.o: $(hdrdir)/ruby/internal/core/rstruct.h
+append.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+append.o: $(hdrdir)/ruby/internal/ctype.h
+append.o: $(hdrdir)/ruby/internal/dllexport.h
+append.o: $(hdrdir)/ruby/internal/dosish.h
+append.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+append.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+append.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+append.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+append.o: $(hdrdir)/ruby/internal/encoding/re.h
+append.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+append.o: $(hdrdir)/ruby/internal/encoding/string.h
+append.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+append.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+append.o: $(hdrdir)/ruby/internal/error.h
+append.o: $(hdrdir)/ruby/internal/eval.h
+append.o: $(hdrdir)/ruby/internal/event.h
+append.o: $(hdrdir)/ruby/internal/fl_type.h
+append.o: $(hdrdir)/ruby/internal/gc.h
+append.o: $(hdrdir)/ruby/internal/glob.h
+append.o: $(hdrdir)/ruby/internal/globals.h
+append.o: $(hdrdir)/ruby/internal/has/attribute.h
+append.o: $(hdrdir)/ruby/internal/has/builtin.h
+append.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+append.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+append.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+append.o: $(hdrdir)/ruby/internal/has/extension.h
+append.o: $(hdrdir)/ruby/internal/has/feature.h
+append.o: $(hdrdir)/ruby/internal/has/warning.h
+append.o: $(hdrdir)/ruby/internal/intern/array.h
+append.o: $(hdrdir)/ruby/internal/intern/bignum.h
+append.o: $(hdrdir)/ruby/internal/intern/class.h
+append.o: $(hdrdir)/ruby/internal/intern/compar.h
+append.o: $(hdrdir)/ruby/internal/intern/complex.h
+append.o: $(hdrdir)/ruby/internal/intern/cont.h
+append.o: $(hdrdir)/ruby/internal/intern/dir.h
+append.o: $(hdrdir)/ruby/internal/intern/enum.h
+append.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+append.o: $(hdrdir)/ruby/internal/intern/error.h
+append.o: $(hdrdir)/ruby/internal/intern/eval.h
+append.o: $(hdrdir)/ruby/internal/intern/file.h
+append.o: $(hdrdir)/ruby/internal/intern/hash.h
+append.o: $(hdrdir)/ruby/internal/intern/io.h
+append.o: $(hdrdir)/ruby/internal/intern/load.h
+append.o: $(hdrdir)/ruby/internal/intern/marshal.h
+append.o: $(hdrdir)/ruby/internal/intern/numeric.h
+append.o: $(hdrdir)/ruby/internal/intern/object.h
+append.o: $(hdrdir)/ruby/internal/intern/parse.h
+append.o: $(hdrdir)/ruby/internal/intern/proc.h
+append.o: $(hdrdir)/ruby/internal/intern/process.h
+append.o: $(hdrdir)/ruby/internal/intern/random.h
+append.o: $(hdrdir)/ruby/internal/intern/range.h
+append.o: $(hdrdir)/ruby/internal/intern/rational.h
+append.o: $(hdrdir)/ruby/internal/intern/re.h
+append.o: $(hdrdir)/ruby/internal/intern/ruby.h
+append.o: $(hdrdir)/ruby/internal/intern/select.h
+append.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+append.o: $(hdrdir)/ruby/internal/intern/set.h
+append.o: $(hdrdir)/ruby/internal/intern/signal.h
+append.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+append.o: $(hdrdir)/ruby/internal/intern/string.h
+append.o: $(hdrdir)/ruby/internal/intern/struct.h
+append.o: $(hdrdir)/ruby/internal/intern/thread.h
+append.o: $(hdrdir)/ruby/internal/intern/time.h
+append.o: $(hdrdir)/ruby/internal/intern/variable.h
+append.o: $(hdrdir)/ruby/internal/intern/vm.h
+append.o: $(hdrdir)/ruby/internal/interpreter.h
+append.o: $(hdrdir)/ruby/internal/iterator.h
+append.o: $(hdrdir)/ruby/internal/memory.h
+append.o: $(hdrdir)/ruby/internal/method.h
+append.o: $(hdrdir)/ruby/internal/module.h
+append.o: $(hdrdir)/ruby/internal/newobj.h
+append.o: $(hdrdir)/ruby/internal/scan_args.h
+append.o: $(hdrdir)/ruby/internal/special_consts.h
+append.o: $(hdrdir)/ruby/internal/static_assert.h
+append.o: $(hdrdir)/ruby/internal/stdalign.h
+append.o: $(hdrdir)/ruby/internal/stdbool.h
+append.o: $(hdrdir)/ruby/internal/stdckdint.h
+append.o: $(hdrdir)/ruby/internal/symbol.h
+append.o: $(hdrdir)/ruby/internal/value.h
+append.o: $(hdrdir)/ruby/internal/value_type.h
+append.o: $(hdrdir)/ruby/internal/variable.h
+append.o: $(hdrdir)/ruby/internal/warning_push.h
+append.o: $(hdrdir)/ruby/internal/xmalloc.h
+append.o: $(hdrdir)/ruby/missing.h
+append.o: $(hdrdir)/ruby/onigmo.h
+append.o: $(hdrdir)/ruby/oniguruma.h
+append.o: $(hdrdir)/ruby/ruby.h
+append.o: $(hdrdir)/ruby/st.h
+append.o: $(hdrdir)/ruby/subst.h
+append.o: append.c
+init.o: $(RUBY_EXTCONF_H)
+init.o: $(arch_hdrdir)/ruby/config.h
+init.o: $(hdrdir)/ruby.h
+init.o: $(hdrdir)/ruby/assert.h
+init.o: $(hdrdir)/ruby/backward.h
+init.o: $(hdrdir)/ruby/backward/2/assume.h
+init.o: $(hdrdir)/ruby/backward/2/attributes.h
+init.o: $(hdrdir)/ruby/backward/2/bool.h
+init.o: $(hdrdir)/ruby/backward/2/inttypes.h
+init.o: $(hdrdir)/ruby/backward/2/limits.h
+init.o: $(hdrdir)/ruby/backward/2/long_long.h
+init.o: $(hdrdir)/ruby/backward/2/stdalign.h
+init.o: $(hdrdir)/ruby/backward/2/stdarg.h
+init.o: $(hdrdir)/ruby/defines.h
+init.o: $(hdrdir)/ruby/intern.h
+init.o: $(hdrdir)/ruby/internal/abi.h
+init.o: $(hdrdir)/ruby/internal/anyargs.h
+init.o: $(hdrdir)/ruby/internal/arithmetic.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+init.o: $(hdrdir)/ruby/internal/assume.h
+init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+init.o: $(hdrdir)/ruby/internal/attr/artificial.h
+init.o: $(hdrdir)/ruby/internal/attr/cold.h
+init.o: $(hdrdir)/ruby/internal/attr/const.h
+init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+init.o: $(hdrdir)/ruby/internal/attr/error.h
+init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+init.o: $(hdrdir)/ruby/internal/attr/format.h
+init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+init.o: $(hdrdir)/ruby/internal/attr/noalias.h
+init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+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
+init.o: $(hdrdir)/ruby/internal/attr/warning.h
+init.o: $(hdrdir)/ruby/internal/attr/weakref.h
+init.o: $(hdrdir)/ruby/internal/cast.h
+init.o: $(hdrdir)/ruby/internal/compiler_is.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+init.o: $(hdrdir)/ruby/internal/compiler_since.h
+init.o: $(hdrdir)/ruby/internal/config.h
+init.o: $(hdrdir)/ruby/internal/constant_p.h
+init.o: $(hdrdir)/ruby/internal/core.h
+init.o: $(hdrdir)/ruby/internal/core/rarray.h
+init.o: $(hdrdir)/ruby/internal/core/rbasic.h
+init.o: $(hdrdir)/ruby/internal/core/rbignum.h
+init.o: $(hdrdir)/ruby/internal/core/rclass.h
+init.o: $(hdrdir)/ruby/internal/core/rdata.h
+init.o: $(hdrdir)/ruby/internal/core/rfile.h
+init.o: $(hdrdir)/ruby/internal/core/rhash.h
+init.o: $(hdrdir)/ruby/internal/core/robject.h
+init.o: $(hdrdir)/ruby/internal/core/rregexp.h
+init.o: $(hdrdir)/ruby/internal/core/rstring.h
+init.o: $(hdrdir)/ruby/internal/core/rstruct.h
+init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+init.o: $(hdrdir)/ruby/internal/ctype.h
+init.o: $(hdrdir)/ruby/internal/dllexport.h
+init.o: $(hdrdir)/ruby/internal/dosish.h
+init.o: $(hdrdir)/ruby/internal/error.h
+init.o: $(hdrdir)/ruby/internal/eval.h
+init.o: $(hdrdir)/ruby/internal/event.h
+init.o: $(hdrdir)/ruby/internal/fl_type.h
+init.o: $(hdrdir)/ruby/internal/gc.h
+init.o: $(hdrdir)/ruby/internal/glob.h
+init.o: $(hdrdir)/ruby/internal/globals.h
+init.o: $(hdrdir)/ruby/internal/has/attribute.h
+init.o: $(hdrdir)/ruby/internal/has/builtin.h
+init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/extension.h
+init.o: $(hdrdir)/ruby/internal/has/feature.h
+init.o: $(hdrdir)/ruby/internal/has/warning.h
+init.o: $(hdrdir)/ruby/internal/intern/array.h
+init.o: $(hdrdir)/ruby/internal/intern/bignum.h
+init.o: $(hdrdir)/ruby/internal/intern/class.h
+init.o: $(hdrdir)/ruby/internal/intern/compar.h
+init.o: $(hdrdir)/ruby/internal/intern/complex.h
+init.o: $(hdrdir)/ruby/internal/intern/cont.h
+init.o: $(hdrdir)/ruby/internal/intern/dir.h
+init.o: $(hdrdir)/ruby/internal/intern/enum.h
+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/hash.h
+init.o: $(hdrdir)/ruby/internal/intern/io.h
+init.o: $(hdrdir)/ruby/internal/intern/load.h
+init.o: $(hdrdir)/ruby/internal/intern/marshal.h
+init.o: $(hdrdir)/ruby/internal/intern/numeric.h
+init.o: $(hdrdir)/ruby/internal/intern/object.h
+init.o: $(hdrdir)/ruby/internal/intern/parse.h
+init.o: $(hdrdir)/ruby/internal/intern/proc.h
+init.o: $(hdrdir)/ruby/internal/intern/process.h
+init.o: $(hdrdir)/ruby/internal/intern/random.h
+init.o: $(hdrdir)/ruby/internal/intern/range.h
+init.o: $(hdrdir)/ruby/internal/intern/rational.h
+init.o: $(hdrdir)/ruby/internal/intern/re.h
+init.o: $(hdrdir)/ruby/internal/intern/ruby.h
+init.o: $(hdrdir)/ruby/internal/intern/select.h
+init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
+init.o: $(hdrdir)/ruby/internal/intern/signal.h
+init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+init.o: $(hdrdir)/ruby/internal/intern/string.h
+init.o: $(hdrdir)/ruby/internal/intern/struct.h
+init.o: $(hdrdir)/ruby/internal/intern/thread.h
+init.o: $(hdrdir)/ruby/internal/intern/time.h
+init.o: $(hdrdir)/ruby/internal/intern/variable.h
+init.o: $(hdrdir)/ruby/internal/intern/vm.h
+init.o: $(hdrdir)/ruby/internal/interpreter.h
+init.o: $(hdrdir)/ruby/internal/iterator.h
+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/scan_args.h
+init.o: $(hdrdir)/ruby/internal/special_consts.h
+init.o: $(hdrdir)/ruby/internal/static_assert.h
+init.o: $(hdrdir)/ruby/internal/stdalign.h
+init.o: $(hdrdir)/ruby/internal/stdbool.h
+init.o: $(hdrdir)/ruby/internal/stdckdint.h
+init.o: $(hdrdir)/ruby/internal/symbol.h
+init.o: $(hdrdir)/ruby/internal/value.h
+init.o: $(hdrdir)/ruby/internal/value_type.h
+init.o: $(hdrdir)/ruby/internal/variable.h
+init.o: $(hdrdir)/ruby/internal/warning_push.h
+init.o: $(hdrdir)/ruby/internal/xmalloc.h
+init.o: $(hdrdir)/ruby/missing.h
+init.o: $(hdrdir)/ruby/ruby.h
+init.o: $(hdrdir)/ruby/st.h
+init.o: $(hdrdir)/ruby/subst.h
+init.o: init.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/ensure_and_callcc/depend b/ext/-test-/ensure_and_callcc/depend
new file mode 100644
index 0000000000..54431847a6
--- /dev/null
+++ b/ext/-test-/ensure_and_callcc/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+ensure_and_callcc.o: $(RUBY_EXTCONF_H)
+ensure_and_callcc.o: $(arch_hdrdir)/ruby/config.h
+ensure_and_callcc.o: $(hdrdir)/ruby.h
+ensure_and_callcc.o: $(hdrdir)/ruby/assert.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/assume.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/attributes.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/bool.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/inttypes.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/limits.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/long_long.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/stdalign.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/stdarg.h
+ensure_and_callcc.o: $(hdrdir)/ruby/defines.h
+ensure_and_callcc.o: $(hdrdir)/ruby/intern.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/abi.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/anyargs.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/assume.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/artificial.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/cold.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/const.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/error.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/format.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noalias.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noinline.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/pure.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/restrict.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/warning.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/weakref.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/cast.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_since.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/config.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/constant_p.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rarray.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rbasic.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rbignum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rclass.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rdata.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rfile.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rhash.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/robject.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rregexp.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rstring.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rstruct.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/ctype.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/dllexport.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/dosish.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/error.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/eval.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/event.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/fl_type.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/gc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/glob.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/globals.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/builtin.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/extension.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/feature.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/warning.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/array.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/bignum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/class.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/compar.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/complex.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/cont.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/dir.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/enum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/error.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/eval.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/file.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/hash.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/io.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/load.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/marshal.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/numeric.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/object.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/parse.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/proc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/process.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/random.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/range.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/rational.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/re.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/ruby.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/select.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/set.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/signal.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/string.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/struct.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/thread.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/time.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/variable.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/vm.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/interpreter.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/iterator.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/memory.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/method.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/module.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/newobj.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/scan_args.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/special_consts.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/static_assert.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/stdalign.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/stdbool.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/stdckdint.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/symbol.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/value.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/value_type.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/variable.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/warning_push.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/xmalloc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/missing.h
+ensure_and_callcc.o: $(hdrdir)/ruby/ruby.h
+ensure_and_callcc.o: $(hdrdir)/ruby/st.h
+ensure_and_callcc.o: $(hdrdir)/ruby/subst.h
+ensure_and_callcc.o: ensure_and_callcc.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/enumerator_kw/depend b/ext/-test-/enumerator_kw/depend
index 85daa55b53..b6d2f0a998 100644
--- a/ext/-test-/enumerator_kw/depend
+++ b/ext/-test-/enumerator_kw/depend
@@ -128,6 +128,7 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/intern/re.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/ruby.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/select.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/intern/set.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/signal.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/eval/depend b/ext/-test-/eval/depend
new file mode 100644
index 0000000000..03a1c7d7ef
--- /dev/null
+++ b/ext/-test-/eval/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+eval.o: $(RUBY_EXTCONF_H)
+eval.o: $(arch_hdrdir)/ruby/config.h
+eval.o: $(hdrdir)/ruby/assert.h
+eval.o: $(hdrdir)/ruby/backward.h
+eval.o: $(hdrdir)/ruby/backward/2/assume.h
+eval.o: $(hdrdir)/ruby/backward/2/attributes.h
+eval.o: $(hdrdir)/ruby/backward/2/bool.h
+eval.o: $(hdrdir)/ruby/backward/2/inttypes.h
+eval.o: $(hdrdir)/ruby/backward/2/limits.h
+eval.o: $(hdrdir)/ruby/backward/2/long_long.h
+eval.o: $(hdrdir)/ruby/backward/2/stdalign.h
+eval.o: $(hdrdir)/ruby/backward/2/stdarg.h
+eval.o: $(hdrdir)/ruby/defines.h
+eval.o: $(hdrdir)/ruby/intern.h
+eval.o: $(hdrdir)/ruby/internal/abi.h
+eval.o: $(hdrdir)/ruby/internal/anyargs.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+eval.o: $(hdrdir)/ruby/internal/assume.h
+eval.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+eval.o: $(hdrdir)/ruby/internal/attr/artificial.h
+eval.o: $(hdrdir)/ruby/internal/attr/cold.h
+eval.o: $(hdrdir)/ruby/internal/attr/const.h
+eval.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+eval.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+eval.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+eval.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+eval.o: $(hdrdir)/ruby/internal/attr/error.h
+eval.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+eval.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+eval.o: $(hdrdir)/ruby/internal/attr/format.h
+eval.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+eval.o: $(hdrdir)/ruby/internal/attr/noalias.h
+eval.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+eval.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+eval.o: $(hdrdir)/ruby/internal/attr/noinline.h
+eval.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+eval.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+eval.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+eval.o: $(hdrdir)/ruby/internal/attr/pure.h
+eval.o: $(hdrdir)/ruby/internal/attr/restrict.h
+eval.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+eval.o: $(hdrdir)/ruby/internal/attr/warning.h
+eval.o: $(hdrdir)/ruby/internal/attr/weakref.h
+eval.o: $(hdrdir)/ruby/internal/cast.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+eval.o: $(hdrdir)/ruby/internal/compiler_since.h
+eval.o: $(hdrdir)/ruby/internal/config.h
+eval.o: $(hdrdir)/ruby/internal/constant_p.h
+eval.o: $(hdrdir)/ruby/internal/core.h
+eval.o: $(hdrdir)/ruby/internal/core/rarray.h
+eval.o: $(hdrdir)/ruby/internal/core/rbasic.h
+eval.o: $(hdrdir)/ruby/internal/core/rbignum.h
+eval.o: $(hdrdir)/ruby/internal/core/rclass.h
+eval.o: $(hdrdir)/ruby/internal/core/rdata.h
+eval.o: $(hdrdir)/ruby/internal/core/rfile.h
+eval.o: $(hdrdir)/ruby/internal/core/rhash.h
+eval.o: $(hdrdir)/ruby/internal/core/robject.h
+eval.o: $(hdrdir)/ruby/internal/core/rregexp.h
+eval.o: $(hdrdir)/ruby/internal/core/rstring.h
+eval.o: $(hdrdir)/ruby/internal/core/rstruct.h
+eval.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+eval.o: $(hdrdir)/ruby/internal/ctype.h
+eval.o: $(hdrdir)/ruby/internal/dllexport.h
+eval.o: $(hdrdir)/ruby/internal/dosish.h
+eval.o: $(hdrdir)/ruby/internal/error.h
+eval.o: $(hdrdir)/ruby/internal/eval.h
+eval.o: $(hdrdir)/ruby/internal/event.h
+eval.o: $(hdrdir)/ruby/internal/fl_type.h
+eval.o: $(hdrdir)/ruby/internal/gc.h
+eval.o: $(hdrdir)/ruby/internal/glob.h
+eval.o: $(hdrdir)/ruby/internal/globals.h
+eval.o: $(hdrdir)/ruby/internal/has/attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/builtin.h
+eval.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/extension.h
+eval.o: $(hdrdir)/ruby/internal/has/feature.h
+eval.o: $(hdrdir)/ruby/internal/has/warning.h
+eval.o: $(hdrdir)/ruby/internal/intern/array.h
+eval.o: $(hdrdir)/ruby/internal/intern/bignum.h
+eval.o: $(hdrdir)/ruby/internal/intern/class.h
+eval.o: $(hdrdir)/ruby/internal/intern/compar.h
+eval.o: $(hdrdir)/ruby/internal/intern/complex.h
+eval.o: $(hdrdir)/ruby/internal/intern/cont.h
+eval.o: $(hdrdir)/ruby/internal/intern/dir.h
+eval.o: $(hdrdir)/ruby/internal/intern/enum.h
+eval.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+eval.o: $(hdrdir)/ruby/internal/intern/error.h
+eval.o: $(hdrdir)/ruby/internal/intern/eval.h
+eval.o: $(hdrdir)/ruby/internal/intern/file.h
+eval.o: $(hdrdir)/ruby/internal/intern/hash.h
+eval.o: $(hdrdir)/ruby/internal/intern/io.h
+eval.o: $(hdrdir)/ruby/internal/intern/load.h
+eval.o: $(hdrdir)/ruby/internal/intern/marshal.h
+eval.o: $(hdrdir)/ruby/internal/intern/numeric.h
+eval.o: $(hdrdir)/ruby/internal/intern/object.h
+eval.o: $(hdrdir)/ruby/internal/intern/parse.h
+eval.o: $(hdrdir)/ruby/internal/intern/proc.h
+eval.o: $(hdrdir)/ruby/internal/intern/process.h
+eval.o: $(hdrdir)/ruby/internal/intern/random.h
+eval.o: $(hdrdir)/ruby/internal/intern/range.h
+eval.o: $(hdrdir)/ruby/internal/intern/rational.h
+eval.o: $(hdrdir)/ruby/internal/intern/re.h
+eval.o: $(hdrdir)/ruby/internal/intern/ruby.h
+eval.o: $(hdrdir)/ruby/internal/intern/select.h
+eval.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+eval.o: $(hdrdir)/ruby/internal/intern/set.h
+eval.o: $(hdrdir)/ruby/internal/intern/signal.h
+eval.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+eval.o: $(hdrdir)/ruby/internal/intern/string.h
+eval.o: $(hdrdir)/ruby/internal/intern/struct.h
+eval.o: $(hdrdir)/ruby/internal/intern/thread.h
+eval.o: $(hdrdir)/ruby/internal/intern/time.h
+eval.o: $(hdrdir)/ruby/internal/intern/variable.h
+eval.o: $(hdrdir)/ruby/internal/intern/vm.h
+eval.o: $(hdrdir)/ruby/internal/interpreter.h
+eval.o: $(hdrdir)/ruby/internal/iterator.h
+eval.o: $(hdrdir)/ruby/internal/memory.h
+eval.o: $(hdrdir)/ruby/internal/method.h
+eval.o: $(hdrdir)/ruby/internal/module.h
+eval.o: $(hdrdir)/ruby/internal/newobj.h
+eval.o: $(hdrdir)/ruby/internal/scan_args.h
+eval.o: $(hdrdir)/ruby/internal/special_consts.h
+eval.o: $(hdrdir)/ruby/internal/static_assert.h
+eval.o: $(hdrdir)/ruby/internal/stdalign.h
+eval.o: $(hdrdir)/ruby/internal/stdbool.h
+eval.o: $(hdrdir)/ruby/internal/stdckdint.h
+eval.o: $(hdrdir)/ruby/internal/symbol.h
+eval.o: $(hdrdir)/ruby/internal/value.h
+eval.o: $(hdrdir)/ruby/internal/value_type.h
+eval.o: $(hdrdir)/ruby/internal/variable.h
+eval.o: $(hdrdir)/ruby/internal/warning_push.h
+eval.o: $(hdrdir)/ruby/internal/xmalloc.h
+eval.o: $(hdrdir)/ruby/missing.h
+eval.o: $(hdrdir)/ruby/ruby.h
+eval.o: $(hdrdir)/ruby/st.h
+eval.o: $(hdrdir)/ruby/subst.h
+eval.o: eval.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/exception/depend b/ext/-test-/exception/depend
index 7a0544b1e1..690e5ad377 100644
--- a/ext/-test-/exception/depend
+++ b/ext/-test-/exception/depend
@@ -127,6 +127,7 @@ dataerror.o: $(hdrdir)/ruby/internal/intern/re.h
dataerror.o: $(hdrdir)/ruby/internal/intern/ruby.h
dataerror.o: $(hdrdir)/ruby/internal/intern/select.h
dataerror.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+dataerror.o: $(hdrdir)/ruby/internal/intern/set.h
dataerror.o: $(hdrdir)/ruby/internal/intern/signal.h
dataerror.o: $(hdrdir)/ruby/internal/intern/sprintf.h
dataerror.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -297,6 +298,7 @@ enc_raise.o: $(hdrdir)/ruby/internal/intern/re.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/select.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_raise.o: $(hdrdir)/ruby/internal/intern/set.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -459,6 +461,7 @@ ensured.o: $(hdrdir)/ruby/internal/intern/re.h
ensured.o: $(hdrdir)/ruby/internal/intern/ruby.h
ensured.o: $(hdrdir)/ruby/internal/intern/select.h
ensured.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ensured.o: $(hdrdir)/ruby/internal/intern/set.h
ensured.o: $(hdrdir)/ruby/internal/intern/signal.h
ensured.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ensured.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -619,6 +622,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/fatal/depend b/ext/-test-/fatal/depend
index 36b0ad4205..306bc9099c 100644
--- a/ext/-test-/fatal/depend
+++ b/ext/-test-/fatal/depend
@@ -129,6 +129,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -289,6 +290,7 @@ invalid.o: $(hdrdir)/ruby/internal/intern/re.h
invalid.o: $(hdrdir)/ruby/internal/intern/ruby.h
invalid.o: $(hdrdir)/ruby/internal/intern/select.h
invalid.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+invalid.o: $(hdrdir)/ruby/internal/intern/set.h
invalid.o: $(hdrdir)/ruby/internal/intern/signal.h
invalid.o: $(hdrdir)/ruby/internal/intern/sprintf.h
invalid.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -449,6 +451,7 @@ rb_fatal.o: $(hdrdir)/ruby/internal/intern/re.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/select.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_fatal.o: $(hdrdir)/ruby/internal/intern/set.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/fatal/invalid.c b/ext/-test-/fatal/invalid.c
index 393465416a..6fd970b181 100644
--- a/ext/-test-/fatal/invalid.c
+++ b/ext/-test-/fatal/invalid.c
@@ -1,11 +1,5 @@
#include <ruby.h>
-#if SIZEOF_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) NUM2ULONG(x)
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) NUM2ULL(x)
-#endif
-
static VALUE
invalid_call(VALUE obj, VALUE address)
{
diff --git a/ext/-test-/file/depend b/ext/-test-/file/depend
index e985f914b2..fe320f3d44 100644
--- a/ext/-test-/file/depend
+++ b/ext/-test-/file/depend
@@ -137,6 +137,7 @@ fs.o: $(hdrdir)/ruby/internal/intern/re.h
fs.o: $(hdrdir)/ruby/internal/intern/ruby.h
fs.o: $(hdrdir)/ruby/internal/intern/select.h
fs.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+fs.o: $(hdrdir)/ruby/internal/intern/set.h
fs.o: $(hdrdir)/ruby/internal/intern/signal.h
fs.o: $(hdrdir)/ruby/internal/intern/sprintf.h
fs.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -300,6 +301,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -469,6 +471,7 @@ newline_conv.o: $(hdrdir)/ruby/internal/intern/re.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/ruby.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/select.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+newline_conv.o: $(hdrdir)/ruby/internal/intern/set.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/signal.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/sprintf.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -641,6 +644,7 @@ stat.o: $(hdrdir)/ruby/internal/intern/re.h
stat.o: $(hdrdir)/ruby/internal/intern/ruby.h
stat.o: $(hdrdir)/ruby/internal/intern/select.h
stat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stat.o: $(hdrdir)/ruby/internal/intern/set.h
stat.o: $(hdrdir)/ruby/internal/intern/signal.h
stat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
stat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/float/depend b/ext/-test-/float/depend
index 3e34818d5f..334ed33c3b 100644
--- a/ext/-test-/float/depend
+++ b/ext/-test-/float/depend
@@ -131,6 +131,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -291,6 +292,7 @@ nextafter.o: $(hdrdir)/ruby/internal/intern/re.h
nextafter.o: $(hdrdir)/ruby/internal/intern/ruby.h
nextafter.o: $(hdrdir)/ruby/internal/intern/select.h
nextafter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nextafter.o: $(hdrdir)/ruby/internal/intern/set.h
nextafter.o: $(hdrdir)/ruby/internal/intern/signal.h
nextafter.o: $(hdrdir)/ruby/internal/intern/sprintf.h
nextafter.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/funcall/depend b/ext/-test-/funcall/depend
index a5a30873ac..e54370306f 100644
--- a/ext/-test-/funcall/depend
+++ b/ext/-test-/funcall/depend
@@ -128,6 +128,7 @@ funcall.o: $(hdrdir)/ruby/internal/intern/re.h
funcall.o: $(hdrdir)/ruby/internal/intern/ruby.h
funcall.o: $(hdrdir)/ruby/internal/intern/select.h
funcall.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+funcall.o: $(hdrdir)/ruby/internal/intern/set.h
funcall.o: $(hdrdir)/ruby/internal/intern/signal.h
funcall.o: $(hdrdir)/ruby/internal/intern/sprintf.h
funcall.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/gvl/call_without_gvl/depend b/ext/-test-/gvl/call_without_gvl/depend
index 6463d4527d..236d1e1d3b 100644
--- a/ext/-test-/gvl/call_without_gvl/depend
+++ b/ext/-test-/gvl/call_without_gvl/depend
@@ -127,6 +127,7 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/intern/re.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/ruby.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/select.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/intern/set.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/signal.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/hash/depend b/ext/-test-/hash/depend
index 4bc4bfcdd6..416b93f9de 100644
--- a/ext/-test-/hash/depend
+++ b/ext/-test-/hash/depend
@@ -128,6 +128,7 @@ delete.o: $(hdrdir)/ruby/internal/intern/re.h
delete.o: $(hdrdir)/ruby/internal/intern/ruby.h
delete.o: $(hdrdir)/ruby/internal/intern/select.h
delete.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+delete.o: $(hdrdir)/ruby/internal/intern/set.h
delete.o: $(hdrdir)/ruby/internal/intern/signal.h
delete.o: $(hdrdir)/ruby/internal/intern/sprintf.h
delete.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/integer/depend b/ext/-test-/integer/depend
index d89965e3d9..d0589b5e5d 100644
--- a/ext/-test-/integer/depend
+++ b/ext/-test-/integer/depend
@@ -128,6 +128,7 @@ core_ext.o: $(hdrdir)/ruby/internal/intern/re.h
core_ext.o: $(hdrdir)/ruby/internal/intern/ruby.h
core_ext.o: $(hdrdir)/ruby/internal/intern/select.h
core_ext.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+core_ext.o: $(hdrdir)/ruby/internal/intern/set.h
core_ext.o: $(hdrdir)/ruby/internal/intern/signal.h
core_ext.o: $(hdrdir)/ruby/internal/intern/sprintf.h
core_ext.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -158,8 +159,11 @@ core_ext.o: $(hdrdir)/ruby/missing.h
core_ext.o: $(hdrdir)/ruby/ruby.h
core_ext.o: $(hdrdir)/ruby/st.h
core_ext.o: $(hdrdir)/ruby/subst.h
+core_ext.o: $(top_srcdir)/internal.h
+core_ext.o: $(top_srcdir)/internal/basic_operators.h
core_ext.o: $(top_srcdir)/internal/bignum.h
core_ext.o: $(top_srcdir)/internal/bits.h
+core_ext.o: $(top_srcdir)/internal/compar.h
core_ext.o: $(top_srcdir)/internal/compilers.h
core_ext.o: $(top_srcdir)/internal/fixnum.h
core_ext.o: $(top_srcdir)/internal/numeric.h
@@ -296,6 +300,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -456,6 +461,7 @@ my_integer.o: $(hdrdir)/ruby/internal/intern/re.h
my_integer.o: $(hdrdir)/ruby/internal/intern/ruby.h
my_integer.o: $(hdrdir)/ruby/internal/intern/select.h
my_integer.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+my_integer.o: $(hdrdir)/ruby/internal/intern/set.h
my_integer.o: $(hdrdir)/ruby/internal/intern/signal.h
my_integer.o: $(hdrdir)/ruby/internal/intern/sprintf.h
my_integer.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/iseq_load/depend b/ext/-test-/iseq_load/depend
index fd07b3199c..9361ddb938 100644
--- a/ext/-test-/iseq_load/depend
+++ b/ext/-test-/iseq_load/depend
@@ -128,6 +128,7 @@ iseq_load.o: $(hdrdir)/ruby/internal/intern/re.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/ruby.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/select.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+iseq_load.o: $(hdrdir)/ruby/internal/intern/set.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/signal.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/sprintf.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/iter/depend b/ext/-test-/iter/depend
index cff4b1bb43..161947382c 100644
--- a/ext/-test-/iter/depend
+++ b/ext/-test-/iter/depend
@@ -128,6 +128,7 @@ break.o: $(hdrdir)/ruby/internal/intern/re.h
break.o: $(hdrdir)/ruby/internal/intern/ruby.h
break.o: $(hdrdir)/ruby/internal/intern/select.h
break.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+break.o: $(hdrdir)/ruby/internal/intern/set.h
break.o: $(hdrdir)/ruby/internal/intern/signal.h
break.o: $(hdrdir)/ruby/internal/intern/sprintf.h
break.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ yield.o: $(hdrdir)/ruby/internal/intern/re.h
yield.o: $(hdrdir)/ruby/internal/intern/ruby.h
yield.o: $(hdrdir)/ruby/internal/intern/select.h
yield.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+yield.o: $(hdrdir)/ruby/internal/intern/set.h
yield.o: $(hdrdir)/ruby/internal/intern/signal.h
yield.o: $(hdrdir)/ruby/internal/intern/sprintf.h
yield.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/load/dot.dot/depend b/ext/-test-/load/dot.dot/depend
index f9be79e957..339837d183 100644
--- a/ext/-test-/load/dot.dot/depend
+++ b/ext/-test-/load/dot.dot/depend
@@ -128,6 +128,7 @@ dot.dot.o: $(hdrdir)/ruby/internal/intern/re.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/ruby.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/select.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+dot.dot.o: $(hdrdir)/ruby/internal/intern/set.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/signal.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/sprintf.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/load/protect/depend b/ext/-test-/load/protect/depend
index 324c17237a..c76c6f88ed 100644
--- a/ext/-test-/load/protect/depend
+++ b/ext/-test-/load/protect/depend
@@ -128,6 +128,7 @@ protect.o: $(hdrdir)/ruby/internal/intern/re.h
protect.o: $(hdrdir)/ruby/internal/intern/ruby.h
protect.o: $(hdrdir)/ruby/internal/intern/select.h
protect.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+protect.o: $(hdrdir)/ruby/internal/intern/set.h
protect.o: $(hdrdir)/ruby/internal/intern/signal.h
protect.o: $(hdrdir)/ruby/internal/intern/sprintf.h
protect.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/load/resolve_symbol_resolver/depend b/ext/-test-/load/resolve_symbol_resolver/depend
new file mode 100644
index 0000000000..f422898b69
--- /dev/null
+++ b/ext/-test-/load/resolve_symbol_resolver/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+resolve_symbol_resolver.o: $(RUBY_EXTCONF_H)
+resolve_symbol_resolver.o: $(arch_hdrdir)/ruby/config.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/assert.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/assume.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/attributes.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/bool.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/inttypes.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/limits.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/long_long.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/stdalign.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/stdarg.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/defines.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/intern.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/abi.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/anyargs.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/assume.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/artificial.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/cold.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/const.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/error.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/format.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noalias.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noinline.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/pure.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/restrict.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/warning.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/weakref.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/cast.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_since.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/config.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/constant_p.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rarray.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rbasic.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rbignum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rclass.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rdata.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rfile.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rhash.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/robject.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rregexp.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rstring.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rstruct.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/ctype.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/dllexport.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/dosish.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/error.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/eval.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/event.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/fl_type.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/gc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/glob.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/globals.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/builtin.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/extension.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/feature.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/warning.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/array.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/bignum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/class.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/compar.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/complex.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/cont.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/dir.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/enum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/error.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/eval.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/file.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/hash.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/io.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/load.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/marshal.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/numeric.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/object.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/parse.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/proc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/process.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/random.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/range.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/rational.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/re.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/ruby.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/select.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/set.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/signal.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/string.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/struct.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/thread.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/time.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/variable.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/vm.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/interpreter.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/iterator.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/memory.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/method.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/module.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/newobj.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/scan_args.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/special_consts.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/static_assert.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/stdalign.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/stdbool.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/stdckdint.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/symbol.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/value.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/value_type.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/variable.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/warning_push.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/xmalloc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/missing.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/ruby.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/st.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/subst.h
+resolve_symbol_resolver.o: resolve_symbol_resolver.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/load/resolve_symbol_target/depend b/ext/-test-/load/resolve_symbol_target/depend
new file mode 100644
index 0000000000..aa0b5327be
--- /dev/null
+++ b/ext/-test-/load/resolve_symbol_target/depend
@@ -0,0 +1,164 @@
+# AUTOGENERATED DEPENDENCIES START
+resolve_symbol_target.o: $(RUBY_EXTCONF_H)
+resolve_symbol_target.o: $(arch_hdrdir)/ruby/config.h
+resolve_symbol_target.o: $(hdrdir)/ruby.h
+resolve_symbol_target.o: $(hdrdir)/ruby/assert.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/assume.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/attributes.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/bool.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/inttypes.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/limits.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/long_long.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/stdalign.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/stdarg.h
+resolve_symbol_target.o: $(hdrdir)/ruby/defines.h
+resolve_symbol_target.o: $(hdrdir)/ruby/intern.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/abi.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/anyargs.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/assume.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/artificial.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/cold.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/const.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/error.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/format.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noalias.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noinline.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/pure.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/restrict.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/warning.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/weakref.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/cast.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_since.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/config.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/constant_p.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rarray.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rbasic.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rbignum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rclass.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rdata.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rfile.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rhash.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/robject.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rregexp.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rstring.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rstruct.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/ctype.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/dllexport.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/dosish.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/error.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/eval.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/event.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/fl_type.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/gc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/glob.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/globals.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/builtin.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/extension.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/feature.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/warning.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/array.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/bignum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/class.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/compar.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/complex.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/cont.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/dir.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/enum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/error.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/eval.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/file.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/hash.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/io.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/load.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/marshal.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/numeric.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/object.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/parse.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/proc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/process.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/random.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/range.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/rational.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/re.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/ruby.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/select.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/set.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/signal.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/string.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/struct.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/thread.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/time.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/variable.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/vm.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/interpreter.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/iterator.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/memory.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/method.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/module.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/newobj.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/scan_args.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/special_consts.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/static_assert.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/stdalign.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/stdbool.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/stdckdint.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/symbol.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/value.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/value_type.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/variable.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/warning_push.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/xmalloc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/missing.h
+resolve_symbol_target.o: $(hdrdir)/ruby/ruby.h
+resolve_symbol_target.o: $(hdrdir)/ruby/st.h
+resolve_symbol_target.o: $(hdrdir)/ruby/subst.h
+resolve_symbol_target.o: resolve_symbol_target.c
+resolve_symbol_target.o: resolve_symbol_target.h
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/load/stringify_symbols/depend b/ext/-test-/load/stringify_symbols/depend
new file mode 100644
index 0000000000..2d4d79a7b7
--- /dev/null
+++ b/ext/-test-/load/stringify_symbols/depend
@@ -0,0 +1,164 @@
+# AUTOGENERATED DEPENDENCIES START
+stringify_symbols.o: $(RUBY_EXTCONF_H)
+stringify_symbols.o: $(arch_hdrdir)/ruby/config.h
+stringify_symbols.o: $(hdrdir)/ruby.h
+stringify_symbols.o: $(hdrdir)/ruby/assert.h
+stringify_symbols.o: $(hdrdir)/ruby/backward.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/assume.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/attributes.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/bool.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/inttypes.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/limits.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/long_long.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/stdalign.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/stdarg.h
+stringify_symbols.o: $(hdrdir)/ruby/defines.h
+stringify_symbols.o: $(hdrdir)/ruby/intern.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/abi.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/anyargs.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/assume.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/artificial.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/cold.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/const.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/error.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/format.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noalias.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noinline.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/pure.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/restrict.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/warning.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/weakref.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/cast.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_since.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/config.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/constant_p.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rarray.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rbasic.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rbignum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rclass.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rdata.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rfile.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rhash.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/robject.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rregexp.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rstring.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rstruct.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/ctype.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/dllexport.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/dosish.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/error.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/eval.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/event.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/fl_type.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/gc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/glob.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/globals.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/builtin.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/extension.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/feature.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/warning.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/array.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/bignum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/class.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/compar.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/complex.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/cont.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/dir.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/enum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/error.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/eval.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/file.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/hash.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/io.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/load.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/marshal.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/numeric.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/object.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/parse.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/proc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/process.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/random.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/range.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/rational.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/re.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/ruby.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/select.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/set.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/signal.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/string.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/struct.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/thread.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/time.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/variable.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/vm.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/interpreter.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/iterator.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/memory.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/method.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/module.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/newobj.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/scan_args.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/special_consts.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/static_assert.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/stdalign.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/stdbool.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/stdckdint.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/symbol.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/value.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/value_type.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/variable.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/warning_push.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/xmalloc.h
+stringify_symbols.o: $(hdrdir)/ruby/missing.h
+stringify_symbols.o: $(hdrdir)/ruby/ruby.h
+stringify_symbols.o: $(hdrdir)/ruby/st.h
+stringify_symbols.o: $(hdrdir)/ruby/subst.h
+stringify_symbols.o: $(hdrdir)/ruby/util.h
+stringify_symbols.o: stringify_symbols.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/load/stringify_target/depend b/ext/-test-/load/stringify_target/depend
new file mode 100644
index 0000000000..c66575d4e4
--- /dev/null
+++ b/ext/-test-/load/stringify_target/depend
@@ -0,0 +1,164 @@
+# AUTOGENERATED DEPENDENCIES START
+stringify_target.o: $(RUBY_EXTCONF_H)
+stringify_target.o: $(arch_hdrdir)/ruby/config.h
+stringify_target.o: $(hdrdir)/ruby.h
+stringify_target.o: $(hdrdir)/ruby/assert.h
+stringify_target.o: $(hdrdir)/ruby/backward.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/assume.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/attributes.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/bool.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/inttypes.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/limits.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/long_long.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/stdalign.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/stdarg.h
+stringify_target.o: $(hdrdir)/ruby/defines.h
+stringify_target.o: $(hdrdir)/ruby/intern.h
+stringify_target.o: $(hdrdir)/ruby/internal/abi.h
+stringify_target.o: $(hdrdir)/ruby/internal/anyargs.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/assume.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/artificial.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/cold.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/const.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/error.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/format.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noalias.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noinline.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/pure.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/restrict.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/warning.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/weakref.h
+stringify_target.o: $(hdrdir)/ruby/internal/cast.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_since.h
+stringify_target.o: $(hdrdir)/ruby/internal/config.h
+stringify_target.o: $(hdrdir)/ruby/internal/constant_p.h
+stringify_target.o: $(hdrdir)/ruby/internal/core.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rarray.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rbasic.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rbignum.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rclass.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rdata.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rfile.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rhash.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/robject.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rregexp.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rstring.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rstruct.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+stringify_target.o: $(hdrdir)/ruby/internal/ctype.h
+stringify_target.o: $(hdrdir)/ruby/internal/dllexport.h
+stringify_target.o: $(hdrdir)/ruby/internal/dosish.h
+stringify_target.o: $(hdrdir)/ruby/internal/error.h
+stringify_target.o: $(hdrdir)/ruby/internal/eval.h
+stringify_target.o: $(hdrdir)/ruby/internal/event.h
+stringify_target.o: $(hdrdir)/ruby/internal/fl_type.h
+stringify_target.o: $(hdrdir)/ruby/internal/gc.h
+stringify_target.o: $(hdrdir)/ruby/internal/glob.h
+stringify_target.o: $(hdrdir)/ruby/internal/globals.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/builtin.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/extension.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/feature.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/warning.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/array.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/bignum.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/class.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/compar.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/complex.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/cont.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/dir.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/enum.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/error.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/eval.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/file.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/hash.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/io.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/load.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/marshal.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/numeric.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/object.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/parse.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/proc.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/process.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/random.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/range.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/rational.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/re.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/ruby.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/select.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/set.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/signal.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/string.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/struct.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/thread.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/time.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/variable.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/vm.h
+stringify_target.o: $(hdrdir)/ruby/internal/interpreter.h
+stringify_target.o: $(hdrdir)/ruby/internal/iterator.h
+stringify_target.o: $(hdrdir)/ruby/internal/memory.h
+stringify_target.o: $(hdrdir)/ruby/internal/method.h
+stringify_target.o: $(hdrdir)/ruby/internal/module.h
+stringify_target.o: $(hdrdir)/ruby/internal/newobj.h
+stringify_target.o: $(hdrdir)/ruby/internal/scan_args.h
+stringify_target.o: $(hdrdir)/ruby/internal/special_consts.h
+stringify_target.o: $(hdrdir)/ruby/internal/static_assert.h
+stringify_target.o: $(hdrdir)/ruby/internal/stdalign.h
+stringify_target.o: $(hdrdir)/ruby/internal/stdbool.h
+stringify_target.o: $(hdrdir)/ruby/internal/stdckdint.h
+stringify_target.o: $(hdrdir)/ruby/internal/symbol.h
+stringify_target.o: $(hdrdir)/ruby/internal/value.h
+stringify_target.o: $(hdrdir)/ruby/internal/value_type.h
+stringify_target.o: $(hdrdir)/ruby/internal/variable.h
+stringify_target.o: $(hdrdir)/ruby/internal/warning_push.h
+stringify_target.o: $(hdrdir)/ruby/internal/xmalloc.h
+stringify_target.o: $(hdrdir)/ruby/missing.h
+stringify_target.o: $(hdrdir)/ruby/ruby.h
+stringify_target.o: $(hdrdir)/ruby/st.h
+stringify_target.o: $(hdrdir)/ruby/subst.h
+stringify_target.o: stringify_target.c
+stringify_target.o: stringify_target.h
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/marshal/compat/depend b/ext/-test-/marshal/compat/depend
index 8bcd9f8b5e..36b9235c23 100644
--- a/ext/-test-/marshal/compat/depend
+++ b/ext/-test-/marshal/compat/depend
@@ -128,6 +128,7 @@ usrcompat.o: $(hdrdir)/ruby/internal/intern/re.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/ruby.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/select.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+usrcompat.o: $(hdrdir)/ruby/internal/intern/set.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/signal.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/marshal/internal_ivar/depend b/ext/-test-/marshal/internal_ivar/depend
index f8be031efc..a2e093d809 100644
--- a/ext/-test-/marshal/internal_ivar/depend
+++ b/ext/-test-/marshal/internal_ivar/depend
@@ -128,6 +128,7 @@ internal_ivar.o: $(hdrdir)/ruby/internal/intern/re.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/ruby.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/select.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+internal_ivar.o: $(hdrdir)/ruby/internal/intern/set.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/signal.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/sprintf.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/marshal/usr/depend b/ext/-test-/marshal/usr/depend
index 09e8207d3a..5ffb8c58de 100644
--- a/ext/-test-/marshal/usr/depend
+++ b/ext/-test-/marshal/usr/depend
@@ -128,6 +128,7 @@ usrmarshal.o: $(hdrdir)/ruby/internal/intern/re.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/ruby.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/select.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+usrmarshal.o: $(hdrdir)/ruby/internal/intern/set.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/signal.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/sprintf.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/memory_view/depend b/ext/-test-/memory_view/depend
index 0c92fc1236..a6ffd76f45 100644
--- a/ext/-test-/memory_view/depend
+++ b/ext/-test-/memory_view/depend
@@ -128,6 +128,7 @@ memory_view.o: $(hdrdir)/ruby/internal/intern/re.h
memory_view.o: $(hdrdir)/ruby/internal/intern/ruby.h
memory_view.o: $(hdrdir)/ruby/internal/intern/select.h
memory_view.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+memory_view.o: $(hdrdir)/ruby/internal/intern/set.h
memory_view.o: $(hdrdir)/ruby/internal/intern/signal.h
memory_view.o: $(hdrdir)/ruby/internal/intern/sprintf.h
memory_view.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/method/depend b/ext/-test-/method/depend
index dce2a815a4..95745b3dae 100644
--- a/ext/-test-/method/depend
+++ b/ext/-test-/method/depend
@@ -128,6 +128,7 @@ arity.o: $(hdrdir)/ruby/internal/intern/re.h
arity.o: $(hdrdir)/ruby/internal/intern/ruby.h
arity.o: $(hdrdir)/ruby/internal/intern/select.h
arity.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+arity.o: $(hdrdir)/ruby/internal/intern/set.h
arity.o: $(hdrdir)/ruby/internal/intern/signal.h
arity.o: $(hdrdir)/ruby/internal/intern/sprintf.h
arity.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/notimplement/depend b/ext/-test-/notimplement/depend
index 84517a9c15..69c970b6f2 100644
--- a/ext/-test-/notimplement/depend
+++ b/ext/-test-/notimplement/depend
@@ -128,6 +128,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/re.h
bug.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug.o: $(hdrdir)/ruby/internal/intern/select.h
bug.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug.o: $(hdrdir)/ruby/internal/intern/set.h
bug.o: $(hdrdir)/ruby/internal/intern/signal.h
bug.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/num2int/depend b/ext/-test-/num2int/depend
index 5550033be7..75536363ac 100644
--- a/ext/-test-/num2int/depend
+++ b/ext/-test-/num2int/depend
@@ -128,6 +128,7 @@ num2int.o: $(hdrdir)/ruby/internal/intern/re.h
num2int.o: $(hdrdir)/ruby/internal/intern/ruby.h
num2int.o: $(hdrdir)/ruby/internal/intern/select.h
num2int.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+num2int.o: $(hdrdir)/ruby/internal/intern/set.h
num2int.o: $(hdrdir)/ruby/internal/intern/signal.h
num2int.o: $(hdrdir)/ruby/internal/intern/sprintf.h
num2int.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/path_to_class/depend b/ext/-test-/path_to_class/depend
index a1657c9574..e535058e09 100644
--- a/ext/-test-/path_to_class/depend
+++ b/ext/-test-/path_to_class/depend
@@ -128,6 +128,7 @@ path_to_class.o: $(hdrdir)/ruby/internal/intern/re.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/ruby.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/select.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+path_to_class.o: $(hdrdir)/ruby/internal/intern/set.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/signal.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/sprintf.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/popen_deadlock/depend b/ext/-test-/popen_deadlock/depend
index 1904e64e59..0b8932e8b8 100644
--- a/ext/-test-/popen_deadlock/depend
+++ b/ext/-test-/popen_deadlock/depend
@@ -128,6 +128,7 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/re.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/ruby.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/select.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/set.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/signal.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/sprintf.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/postponed_job/depend b/ext/-test-/postponed_job/depend
index 72250896b0..ff567e3921 100644
--- a/ext/-test-/postponed_job/depend
+++ b/ext/-test-/postponed_job/depend
@@ -129,6 +129,7 @@ postponed_job.o: $(hdrdir)/ruby/internal/intern/re.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/ruby.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/select.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+postponed_job.o: $(hdrdir)/ruby/internal/intern/set.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/signal.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/sprintf.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c
index 9ac866ae77..4426fc3104 100644
--- a/ext/-test-/postponed_job/postponed_job.c
+++ b/ext/-test-/postponed_job/postponed_job.c
@@ -36,38 +36,6 @@ pjob_callback(void *data)
}
static VALUE
-pjob_register(VALUE self, VALUE obj)
-{
- counter = 0;
- rb_postponed_job_register(0, pjob_callback, (void *)obj);
- rb_gc_start();
- counter++;
- rb_gc_start();
- counter++;
- rb_gc_start();
- counter++;
- return self;
-}
-
-static void
-pjob_one_callback(void *data)
-{
- VALUE ary = (VALUE)data;
- Check_Type(ary, T_ARRAY);
-
- rb_ary_push(ary, INT2FIX(1));
-}
-
-static VALUE
-pjob_register_one(VALUE self, VALUE obj)
-{
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- return self;
-}
-
-static VALUE
pjob_call_direct(VALUE self, VALUE obj)
{
counter = 0;
@@ -83,48 +51,6 @@ pjob_call_direct(VALUE self, VALUE obj)
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>
-
-static void *
-pjob_register_in_c_thread_i(void *obj)
-{
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
- return NULL;
-}
-
-static VALUE
-pjob_register_in_c_thread(VALUE self, VALUE obj)
-{
- pthread_t thread;
- if (pthread_create(&thread, NULL, pjob_register_in_c_thread_i, (void *)obj)) {
- return Qfalse;
- }
-
- if (pthread_join(thread, NULL)) {
- return Qfalse;
- }
-
- return Qtrue;
-}
-#endif
-
static void
pjob_preregistered_callback(void *data)
{
@@ -216,13 +142,7 @@ void
Init_postponed_job(VALUE self)
{
VALUE mBug = rb_define_module("Bug");
- 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);
diff --git a/ext/-test-/printf/depend b/ext/-test-/printf/depend
index 0530df78bf..be895cf769 100644
--- a/ext/-test-/printf/depend
+++ b/ext/-test-/printf/depend
@@ -138,6 +138,7 @@ printf.o: $(hdrdir)/ruby/internal/intern/re.h
printf.o: $(hdrdir)/ruby/internal/intern/ruby.h
printf.o: $(hdrdir)/ruby/internal/intern/select.h
printf.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+printf.o: $(hdrdir)/ruby/internal/intern/set.h
printf.o: $(hdrdir)/ruby/internal/intern/signal.h
printf.o: $(hdrdir)/ruby/internal/intern/sprintf.h
printf.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/proc/depend b/ext/-test-/proc/depend
index 45e12bcd09..97834db0a2 100644
--- a/ext/-test-/proc/depend
+++ b/ext/-test-/proc/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ receiver.o: $(hdrdir)/ruby/internal/intern/re.h
receiver.o: $(hdrdir)/ruby/internal/intern/ruby.h
receiver.o: $(hdrdir)/ruby/internal/intern/select.h
receiver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+receiver.o: $(hdrdir)/ruby/internal/intern/set.h
receiver.o: $(hdrdir)/ruby/internal/intern/signal.h
receiver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
receiver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ super.o: $(hdrdir)/ruby/internal/intern/re.h
super.o: $(hdrdir)/ruby/internal/intern/ruby.h
super.o: $(hdrdir)/ruby/internal/intern/select.h
super.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+super.o: $(hdrdir)/ruby/internal/intern/set.h
super.o: $(hdrdir)/ruby/internal/intern/signal.h
super.o: $(hdrdir)/ruby/internal/intern/sprintf.h
super.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/random/depend b/ext/-test-/random/depend
index 71f5f6e1e6..380c30fbe4 100644
--- a/ext/-test-/random/depend
+++ b/ext/-test-/random/depend
@@ -127,6 +127,7 @@ bad_version.o: $(hdrdir)/ruby/internal/intern/re.h
bad_version.o: $(hdrdir)/ruby/internal/intern/ruby.h
bad_version.o: $(hdrdir)/ruby/internal/intern/select.h
bad_version.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bad_version.o: $(hdrdir)/ruby/internal/intern/set.h
bad_version.o: $(hdrdir)/ruby/internal/intern/signal.h
bad_version.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bad_version.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -447,6 +449,7 @@ loop.o: $(hdrdir)/ruby/internal/intern/re.h
loop.o: $(hdrdir)/ruby/internal/intern/ruby.h
loop.o: $(hdrdir)/ruby/internal/intern/select.h
loop.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+loop.o: $(hdrdir)/ruby/internal/intern/set.h
loop.o: $(hdrdir)/ruby/internal/intern/signal.h
loop.o: $(hdrdir)/ruby/internal/intern/sprintf.h
loop.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/rational/depend b/ext/-test-/rational/depend
index 363d779302..d949fca66b 100644
--- a/ext/-test-/rational/depend
+++ b/ext/-test-/rational/depend
@@ -132,6 +132,7 @@ rat.o: $(hdrdir)/ruby/internal/intern/re.h
rat.o: $(hdrdir)/ruby/internal/intern/ruby.h
rat.o: $(hdrdir)/ruby/internal/intern/select.h
rat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rat.o: $(hdrdir)/ruby/internal/intern/set.h
rat.o: $(hdrdir)/ruby/internal/intern/signal.h
rat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rat.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -162,8 +163,11 @@ rat.o: $(hdrdir)/ruby/missing.h
rat.o: $(hdrdir)/ruby/ruby.h
rat.o: $(hdrdir)/ruby/st.h
rat.o: $(hdrdir)/ruby/subst.h
+rat.o: $(top_srcdir)/internal.h
+rat.o: $(top_srcdir)/internal/basic_operators.h
rat.o: $(top_srcdir)/internal/bignum.h
rat.o: $(top_srcdir)/internal/bits.h
+rat.o: $(top_srcdir)/internal/compar.h
rat.o: $(top_srcdir)/internal/compilers.h
rat.o: $(top_srcdir)/internal/fixnum.h
rat.o: $(top_srcdir)/internal/gc.h
diff --git a/ext/-test-/rb_call_super_kw/depend b/ext/-test-/rb_call_super_kw/depend
index 04a0fac12c..bf34323ca7 100644
--- a/ext/-test-/rb_call_super_kw/depend
+++ b/ext/-test-/rb_call_super_kw/depend
@@ -128,6 +128,7 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/re.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/select.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/set.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/recursion/depend b/ext/-test-/recursion/depend
index 2a65c98b09..b6487eb4df 100644
--- a/ext/-test-/recursion/depend
+++ b/ext/-test-/recursion/depend
@@ -128,6 +128,7 @@ recursion.o: $(hdrdir)/ruby/internal/intern/re.h
recursion.o: $(hdrdir)/ruby/internal/intern/ruby.h
recursion.o: $(hdrdir)/ruby/internal/intern/select.h
recursion.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+recursion.o: $(hdrdir)/ruby/internal/intern/set.h
recursion.o: $(hdrdir)/ruby/internal/intern/signal.h
recursion.o: $(hdrdir)/ruby/internal/intern/sprintf.h
recursion.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/regexp/depend b/ext/-test-/regexp/depend
index 0127a66a2e..5ba1b92f18 100644
--- a/ext/-test-/regexp/depend
+++ b/ext/-test-/regexp/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/re.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/ruby.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/select.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/set.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/signal.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/sprintf.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/sanitizers/depend b/ext/-test-/sanitizers/depend
new file mode 100644
index 0000000000..0e6e632803
--- /dev/null
+++ b/ext/-test-/sanitizers/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+sanitizers.o: $(RUBY_EXTCONF_H)
+sanitizers.o: $(arch_hdrdir)/ruby/config.h
+sanitizers.o: $(hdrdir)/ruby/assert.h
+sanitizers.o: $(hdrdir)/ruby/backward.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/assume.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/attributes.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/bool.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/inttypes.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/limits.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/long_long.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/stdalign.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/stdarg.h
+sanitizers.o: $(hdrdir)/ruby/defines.h
+sanitizers.o: $(hdrdir)/ruby/intern.h
+sanitizers.o: $(hdrdir)/ruby/internal/abi.h
+sanitizers.o: $(hdrdir)/ruby/internal/anyargs.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/assume.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/artificial.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/cold.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/const.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/format.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noalias.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noinline.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/pure.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/restrict.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/warning.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/weakref.h
+sanitizers.o: $(hdrdir)/ruby/internal/cast.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_since.h
+sanitizers.o: $(hdrdir)/ruby/internal/config.h
+sanitizers.o: $(hdrdir)/ruby/internal/constant_p.h
+sanitizers.o: $(hdrdir)/ruby/internal/core.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rarray.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rbasic.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rbignum.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rclass.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rdata.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rfile.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rhash.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/robject.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rregexp.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rstring.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rstruct.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+sanitizers.o: $(hdrdir)/ruby/internal/ctype.h
+sanitizers.o: $(hdrdir)/ruby/internal/dllexport.h
+sanitizers.o: $(hdrdir)/ruby/internal/dosish.h
+sanitizers.o: $(hdrdir)/ruby/internal/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/eval.h
+sanitizers.o: $(hdrdir)/ruby/internal/event.h
+sanitizers.o: $(hdrdir)/ruby/internal/fl_type.h
+sanitizers.o: $(hdrdir)/ruby/internal/gc.h
+sanitizers.o: $(hdrdir)/ruby/internal/glob.h
+sanitizers.o: $(hdrdir)/ruby/internal/globals.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/builtin.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/extension.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/feature.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/warning.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/array.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/bignum.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/class.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/compar.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/complex.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/cont.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/dir.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/enum.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/eval.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/file.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/hash.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/io.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/load.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/marshal.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/numeric.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/object.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/parse.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/proc.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/process.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/random.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/range.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/rational.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/re.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/ruby.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/select.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/set.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/signal.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/string.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/struct.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/thread.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/time.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/variable.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/vm.h
+sanitizers.o: $(hdrdir)/ruby/internal/interpreter.h
+sanitizers.o: $(hdrdir)/ruby/internal/iterator.h
+sanitizers.o: $(hdrdir)/ruby/internal/memory.h
+sanitizers.o: $(hdrdir)/ruby/internal/method.h
+sanitizers.o: $(hdrdir)/ruby/internal/module.h
+sanitizers.o: $(hdrdir)/ruby/internal/newobj.h
+sanitizers.o: $(hdrdir)/ruby/internal/scan_args.h
+sanitizers.o: $(hdrdir)/ruby/internal/special_consts.h
+sanitizers.o: $(hdrdir)/ruby/internal/static_assert.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdalign.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdbool.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdckdint.h
+sanitizers.o: $(hdrdir)/ruby/internal/symbol.h
+sanitizers.o: $(hdrdir)/ruby/internal/value.h
+sanitizers.o: $(hdrdir)/ruby/internal/value_type.h
+sanitizers.o: $(hdrdir)/ruby/internal/variable.h
+sanitizers.o: $(hdrdir)/ruby/internal/warning_push.h
+sanitizers.o: $(hdrdir)/ruby/internal/xmalloc.h
+sanitizers.o: $(hdrdir)/ruby/missing.h
+sanitizers.o: $(hdrdir)/ruby/ruby.h
+sanitizers.o: $(hdrdir)/ruby/st.h
+sanitizers.o: $(hdrdir)/ruby/subst.h
+sanitizers.o: sanitizers.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/sanitizers/extconf.rb b/ext/-test-/sanitizers/extconf.rb
new file mode 100644
index 0000000000..c94a96de6c
--- /dev/null
+++ b/ext/-test-/sanitizers/extconf.rb
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile('-test-/sanitizers')
diff --git a/ext/-test-/sanitizers/sanitizers.c b/ext/-test-/sanitizers/sanitizers.c
new file mode 100644
index 0000000000..97a85b26ef
--- /dev/null
+++ b/ext/-test-/sanitizers/sanitizers.c
@@ -0,0 +1,36 @@
+#include "ruby/ruby.h"
+
+static VALUE
+asan_enabled_p(VALUE self)
+{
+#if defined(__has_feature)
+ /* clang uses __has_feature for determining asan */
+ return __has_feature(address_sanitizer) ? Qtrue : Qfalse;
+#elif defined(__SANITIZE_ADDRESS__)
+ /* GCC sets __SANITIZE_ADDRESS__ for determining asan */
+ return Qtrue;
+#else
+ return Qfalse;
+#endif
+}
+
+static VALUE
+lsan_enabled_p(VALUE self)
+{
+#if defined(__has_feature)
+ /* clang uses __has_feature for determining LSAN */
+ return __has_feature(leak_sanitizer) ? Qtrue : Qfalse;
+#else
+ return Qfalse;
+#endif
+}
+
+void
+Init_sanitizers(void)
+{
+ VALUE m = rb_define_module("Test");
+ VALUE c = rb_define_class_under(m, "Sanitizers", rb_cObject);
+ rb_define_singleton_method(c, "asan_enabled?", asan_enabled_p, 0);
+ rb_define_singleton_method(c, "lsan_enabled?", lsan_enabled_p, 0);
+}
+
diff --git a/ext/-test-/scan_args/depend b/ext/-test-/scan_args/depend
index 922e5bbd5c..ca0fc19238 100644
--- a/ext/-test-/scan_args/depend
+++ b/ext/-test-/scan_args/depend
@@ -128,6 +128,7 @@ scan_args.o: $(hdrdir)/ruby/internal/intern/re.h
scan_args.o: $(hdrdir)/ruby/internal/intern/ruby.h
scan_args.o: $(hdrdir)/ruby/internal/intern/select.h
scan_args.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+scan_args.o: $(hdrdir)/ruby/internal/intern/set.h
scan_args.o: $(hdrdir)/ruby/internal/intern/signal.h
scan_args.o: $(hdrdir)/ruby/internal/intern/sprintf.h
scan_args.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/scheduler/extconf.rb b/ext/-test-/scheduler/extconf.rb
new file mode 100644
index 0000000000..159699bd8e
--- /dev/null
+++ b/ext/-test-/scheduler/extconf.rb
@@ -0,0 +1,2 @@
+# frozen_string_literal: false
+create_makefile("-test-/scheduler")
diff --git a/ext/-test-/scheduler/scheduler.c b/ext/-test-/scheduler/scheduler.c
new file mode 100644
index 0000000000..b742a5573b
--- /dev/null
+++ b/ext/-test-/scheduler/scheduler.c
@@ -0,0 +1,92 @@
+#include "ruby/ruby.h"
+#include "ruby/thread.h"
+#include "ruby/io.h"
+#include "ruby/fiber/scheduler.h"
+
+/*
+ * Test extension for reproducing the gRPC interrupt handling bug.
+ *
+ * This reproduces the exact issue from grpc/grpc commit 69f229e (June 2025):
+ * https://github.com/grpc/grpc/commit/69f229edd1d79ab7a7dfda98e3aef6fd807adcad
+ *
+ * The bug occurs when:
+ * 1. A fiber scheduler uses Thread.handle_interrupt(::SignalException => :never)
+ * (like Async::Scheduler does)
+ * 2. Native code uses rb_thread_call_without_gvl in a retry loop that checks
+ * the interrupted flag and retries (like gRPC's completion queue)
+ * 3. A signal (SIGINT/SIGTERM) is sent
+ * 4. The unblock_func sets interrupted=1, but Thread.handle_interrupt defers the signal
+ * 5. The loop sees interrupted=1 and retries without yielding to the scheduler
+ * 6. The deferred interrupt never gets processed -> infinite hang
+ *
+ * The fix is in vm_check_ints_blocking() in thread.c, which should yield to
+ * the fiber scheduler when interrupts are pending, allowing the scheduler to
+ * detect Thread.pending_interrupt? and exit its run loop.
+ */
+
+struct blocking_state {
+ int notify_descriptor;
+ volatile int interrupted;
+};
+
+static void
+unblock_callback(void *argument)
+{
+ struct blocking_state *blocking_state = (struct blocking_state *)argument;
+ blocking_state->interrupted = 1;
+}
+
+static void *
+blocking_operation(void *argument)
+{
+ struct blocking_state *blocking_state = (struct blocking_state *)argument;
+
+ ssize_t ret = write(blocking_state->notify_descriptor, "x", 1);
+ (void)ret; // ignore the result for now
+
+ while (!blocking_state->interrupted) {
+ struct timeval tv = {1, 0}; // 1 second timeout.
+ int result = select(0, NULL, NULL, NULL, &tv);
+
+ if (result == -1 && errno == EINTR) {
+ blocking_state->interrupted = 1;
+ }
+
+ // Otherwise, timeout -> loop again.
+ }
+
+ return NULL;
+}
+
+static VALUE
+scheduler_blocking_loop(VALUE self, VALUE notify)
+{
+ struct blocking_state blocking_state = {
+ .notify_descriptor = rb_io_descriptor(notify),
+ .interrupted = 0,
+ };
+
+ while (true) {
+ blocking_state.interrupted = 0;
+
+ rb_thread_call_without_gvl(
+ blocking_operation, &blocking_state,
+ unblock_callback, &blocking_state
+ );
+
+ // The bug: When interrupted, loop retries without yielding to scheduler.
+ // With Thread.handle_interrupt(:never), this causes an infinite hang,
+ // because the deferred interrupt never gets a chance to be processed.
+ } while (blocking_state.interrupted);
+
+ return Qnil;
+}
+
+void
+Init_scheduler(void)
+{
+ VALUE mBug = rb_define_module("Bug");
+ VALUE mScheduler = rb_define_module_under(mBug, "Scheduler");
+
+ rb_define_module_function(mScheduler, "blocking_loop", scheduler_blocking_loop, 1);
+}
diff --git a/ext/-test-/st/foreach/depend b/ext/-test-/st/foreach/depend
index 36273f8df8..29aab2bb29 100644
--- a/ext/-test-/st/foreach/depend
+++ b/ext/-test-/st/foreach/depend
@@ -128,6 +128,7 @@ foreach.o: $(hdrdir)/ruby/internal/intern/re.h
foreach.o: $(hdrdir)/ruby/internal/intern/ruby.h
foreach.o: $(hdrdir)/ruby/internal/intern/select.h
foreach.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+foreach.o: $(hdrdir)/ruby/internal/intern/set.h
foreach.o: $(hdrdir)/ruby/internal/intern/signal.h
foreach.o: $(hdrdir)/ruby/internal/intern/sprintf.h
foreach.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/st/foreach/foreach.c b/ext/-test-/st/foreach/foreach.c
index 7fbf064694..5c1bfd1631 100644
--- a/ext/-test-/st/foreach/foreach.c
+++ b/ext/-test-/st/foreach/foreach.c
@@ -14,13 +14,9 @@ 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");
-
/* 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 (key != c->nr) {
@@ -84,8 +80,6 @@ unp_fec(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
-
st_foreach_check(tbl, unp_fec_i, (st_data_t)&c, -1);
if (c.test == ID2SYM(rb_intern("delete2"))) {
@@ -98,8 +92,6 @@ unp_fec(VALUE self, VALUE test)
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
-
st_free_table(tbl);
return Qnil;
@@ -145,8 +137,6 @@ unp_fe(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
-
st_foreach(tbl, unp_fe_i, (st_data_t)&c);
if (c.test == ID2SYM(rb_intern("unpack_delete"))) {
@@ -159,8 +149,6 @@ unp_fe(VALUE self, VALUE test)
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
-
st_free_table(tbl);
return Qnil;
diff --git a/ext/-test-/st/numhash/depend b/ext/-test-/st/numhash/depend
index a0916183b6..18320d55f5 100644
--- a/ext/-test-/st/numhash/depend
+++ b/ext/-test-/st/numhash/depend
@@ -128,6 +128,7 @@ numhash.o: $(hdrdir)/ruby/internal/intern/re.h
numhash.o: $(hdrdir)/ruby/internal/intern/ruby.h
numhash.o: $(hdrdir)/ruby/internal/intern/select.h
numhash.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+numhash.o: $(hdrdir)/ruby/internal/intern/set.h
numhash.o: $(hdrdir)/ruby/internal/intern/signal.h
numhash.o: $(hdrdir)/ruby/internal/intern/sprintf.h
numhash.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/st/update/depend b/ext/-test-/st/update/depend
index 96ba194df0..247f0efd6b 100644
--- a/ext/-test-/st/update/depend
+++ b/ext/-test-/st/update/depend
@@ -128,6 +128,7 @@ update.o: $(hdrdir)/ruby/internal/intern/re.h
update.o: $(hdrdir)/ruby/internal/intern/ruby.h
update.o: $(hdrdir)/ruby/internal/intern/select.h
update.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+update.o: $(hdrdir)/ruby/internal/intern/set.h
update.o: $(hdrdir)/ruby/internal/intern/signal.h
update.o: $(hdrdir)/ruby/internal/intern/sprintf.h
update.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/stack/depend b/ext/-test-/stack/depend
new file mode 100644
index 0000000000..77e93bb201
--- /dev/null
+++ b/ext/-test-/stack/depend
@@ -0,0 +1,179 @@
+# AUTOGENERATED DEPENDENCIES START
+stack.o: $(RUBY_EXTCONF_H)
+stack.o: $(arch_hdrdir)/ruby/config.h
+stack.o: $(hdrdir)/ruby.h
+stack.o: $(hdrdir)/ruby/assert.h
+stack.o: $(hdrdir)/ruby/backward.h
+stack.o: $(hdrdir)/ruby/backward/2/assume.h
+stack.o: $(hdrdir)/ruby/backward/2/attributes.h
+stack.o: $(hdrdir)/ruby/backward/2/bool.h
+stack.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+stack.o: $(hdrdir)/ruby/backward/2/inttypes.h
+stack.o: $(hdrdir)/ruby/backward/2/limits.h
+stack.o: $(hdrdir)/ruby/backward/2/long_long.h
+stack.o: $(hdrdir)/ruby/backward/2/stdalign.h
+stack.o: $(hdrdir)/ruby/backward/2/stdarg.h
+stack.o: $(hdrdir)/ruby/defines.h
+stack.o: $(hdrdir)/ruby/encoding.h
+stack.o: $(hdrdir)/ruby/intern.h
+stack.o: $(hdrdir)/ruby/internal/abi.h
+stack.o: $(hdrdir)/ruby/internal/anyargs.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+stack.o: $(hdrdir)/ruby/internal/assume.h
+stack.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+stack.o: $(hdrdir)/ruby/internal/attr/artificial.h
+stack.o: $(hdrdir)/ruby/internal/attr/cold.h
+stack.o: $(hdrdir)/ruby/internal/attr/const.h
+stack.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+stack.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+stack.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+stack.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+stack.o: $(hdrdir)/ruby/internal/attr/error.h
+stack.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+stack.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+stack.o: $(hdrdir)/ruby/internal/attr/format.h
+stack.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+stack.o: $(hdrdir)/ruby/internal/attr/noalias.h
+stack.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+stack.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+stack.o: $(hdrdir)/ruby/internal/attr/noinline.h
+stack.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+stack.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+stack.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+stack.o: $(hdrdir)/ruby/internal/attr/pure.h
+stack.o: $(hdrdir)/ruby/internal/attr/restrict.h
+stack.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+stack.o: $(hdrdir)/ruby/internal/attr/warning.h
+stack.o: $(hdrdir)/ruby/internal/attr/weakref.h
+stack.o: $(hdrdir)/ruby/internal/cast.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+stack.o: $(hdrdir)/ruby/internal/compiler_since.h
+stack.o: $(hdrdir)/ruby/internal/config.h
+stack.o: $(hdrdir)/ruby/internal/constant_p.h
+stack.o: $(hdrdir)/ruby/internal/core.h
+stack.o: $(hdrdir)/ruby/internal/core/rarray.h
+stack.o: $(hdrdir)/ruby/internal/core/rbasic.h
+stack.o: $(hdrdir)/ruby/internal/core/rbignum.h
+stack.o: $(hdrdir)/ruby/internal/core/rclass.h
+stack.o: $(hdrdir)/ruby/internal/core/rdata.h
+stack.o: $(hdrdir)/ruby/internal/core/rfile.h
+stack.o: $(hdrdir)/ruby/internal/core/rhash.h
+stack.o: $(hdrdir)/ruby/internal/core/robject.h
+stack.o: $(hdrdir)/ruby/internal/core/rregexp.h
+stack.o: $(hdrdir)/ruby/internal/core/rstring.h
+stack.o: $(hdrdir)/ruby/internal/core/rstruct.h
+stack.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+stack.o: $(hdrdir)/ruby/internal/ctype.h
+stack.o: $(hdrdir)/ruby/internal/dllexport.h
+stack.o: $(hdrdir)/ruby/internal/dosish.h
+stack.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+stack.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+stack.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+stack.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+stack.o: $(hdrdir)/ruby/internal/encoding/re.h
+stack.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+stack.o: $(hdrdir)/ruby/internal/encoding/string.h
+stack.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+stack.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+stack.o: $(hdrdir)/ruby/internal/error.h
+stack.o: $(hdrdir)/ruby/internal/eval.h
+stack.o: $(hdrdir)/ruby/internal/event.h
+stack.o: $(hdrdir)/ruby/internal/fl_type.h
+stack.o: $(hdrdir)/ruby/internal/gc.h
+stack.o: $(hdrdir)/ruby/internal/glob.h
+stack.o: $(hdrdir)/ruby/internal/globals.h
+stack.o: $(hdrdir)/ruby/internal/has/attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/builtin.h
+stack.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/extension.h
+stack.o: $(hdrdir)/ruby/internal/has/feature.h
+stack.o: $(hdrdir)/ruby/internal/has/warning.h
+stack.o: $(hdrdir)/ruby/internal/intern/array.h
+stack.o: $(hdrdir)/ruby/internal/intern/bignum.h
+stack.o: $(hdrdir)/ruby/internal/intern/class.h
+stack.o: $(hdrdir)/ruby/internal/intern/compar.h
+stack.o: $(hdrdir)/ruby/internal/intern/complex.h
+stack.o: $(hdrdir)/ruby/internal/intern/cont.h
+stack.o: $(hdrdir)/ruby/internal/intern/dir.h
+stack.o: $(hdrdir)/ruby/internal/intern/enum.h
+stack.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+stack.o: $(hdrdir)/ruby/internal/intern/error.h
+stack.o: $(hdrdir)/ruby/internal/intern/eval.h
+stack.o: $(hdrdir)/ruby/internal/intern/file.h
+stack.o: $(hdrdir)/ruby/internal/intern/hash.h
+stack.o: $(hdrdir)/ruby/internal/intern/io.h
+stack.o: $(hdrdir)/ruby/internal/intern/load.h
+stack.o: $(hdrdir)/ruby/internal/intern/marshal.h
+stack.o: $(hdrdir)/ruby/internal/intern/numeric.h
+stack.o: $(hdrdir)/ruby/internal/intern/object.h
+stack.o: $(hdrdir)/ruby/internal/intern/parse.h
+stack.o: $(hdrdir)/ruby/internal/intern/proc.h
+stack.o: $(hdrdir)/ruby/internal/intern/process.h
+stack.o: $(hdrdir)/ruby/internal/intern/random.h
+stack.o: $(hdrdir)/ruby/internal/intern/range.h
+stack.o: $(hdrdir)/ruby/internal/intern/rational.h
+stack.o: $(hdrdir)/ruby/internal/intern/re.h
+stack.o: $(hdrdir)/ruby/internal/intern/ruby.h
+stack.o: $(hdrdir)/ruby/internal/intern/select.h
+stack.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stack.o: $(hdrdir)/ruby/internal/intern/set.h
+stack.o: $(hdrdir)/ruby/internal/intern/signal.h
+stack.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+stack.o: $(hdrdir)/ruby/internal/intern/string.h
+stack.o: $(hdrdir)/ruby/internal/intern/struct.h
+stack.o: $(hdrdir)/ruby/internal/intern/thread.h
+stack.o: $(hdrdir)/ruby/internal/intern/time.h
+stack.o: $(hdrdir)/ruby/internal/intern/variable.h
+stack.o: $(hdrdir)/ruby/internal/intern/vm.h
+stack.o: $(hdrdir)/ruby/internal/interpreter.h
+stack.o: $(hdrdir)/ruby/internal/iterator.h
+stack.o: $(hdrdir)/ruby/internal/memory.h
+stack.o: $(hdrdir)/ruby/internal/method.h
+stack.o: $(hdrdir)/ruby/internal/module.h
+stack.o: $(hdrdir)/ruby/internal/newobj.h
+stack.o: $(hdrdir)/ruby/internal/scan_args.h
+stack.o: $(hdrdir)/ruby/internal/special_consts.h
+stack.o: $(hdrdir)/ruby/internal/static_assert.h
+stack.o: $(hdrdir)/ruby/internal/stdalign.h
+stack.o: $(hdrdir)/ruby/internal/stdbool.h
+stack.o: $(hdrdir)/ruby/internal/stdckdint.h
+stack.o: $(hdrdir)/ruby/internal/symbol.h
+stack.o: $(hdrdir)/ruby/internal/value.h
+stack.o: $(hdrdir)/ruby/internal/value_type.h
+stack.o: $(hdrdir)/ruby/internal/variable.h
+stack.o: $(hdrdir)/ruby/internal/warning_push.h
+stack.o: $(hdrdir)/ruby/internal/xmalloc.h
+stack.o: $(hdrdir)/ruby/missing.h
+stack.o: $(hdrdir)/ruby/onigmo.h
+stack.o: $(hdrdir)/ruby/oniguruma.h
+stack.o: $(hdrdir)/ruby/ruby.h
+stack.o: $(hdrdir)/ruby/st.h
+stack.o: $(hdrdir)/ruby/subst.h
+stack.o: $(top_srcdir)/encindex.h
+stack.o: $(top_srcdir)/internal/compilers.h
+stack.o: $(top_srcdir)/internal/string.h
+stack.o: stack.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/stack/extconf.rb b/ext/-test-/stack/extconf.rb
new file mode 100644
index 0000000000..d786b15db9
--- /dev/null
+++ b/ext/-test-/stack/extconf.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: false
+require_relative "../auto_ext.rb"
+auto_ext(inc: true)
diff --git a/ext/-test-/stack/stack.c b/ext/-test-/stack/stack.c
new file mode 100644
index 0000000000..f0e65e74b2
--- /dev/null
+++ b/ext/-test-/stack/stack.c
@@ -0,0 +1,35 @@
+#include "ruby.h"
+#include "internal/string.h"
+
+static VALUE
+stack_overflow(VALUE self)
+{
+ size_t i = 0;
+
+ while (1) {
+ // Allocate and touch memory to force actual stack usage:
+ volatile char *stack = alloca(1024);
+ stack[0] = (char)i;
+ stack[1023] = (char)i;
+ i++;
+ }
+
+ return Qnil;
+}
+
+static VALUE
+asan_p(VALUE klass)
+{
+#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
+ return Qtrue;
+#else
+ return Qfalse;
+#endif
+}
+
+void
+Init_stack(VALUE klass)
+{
+ rb_define_singleton_method(rb_cThread, "stack_overflow", stack_overflow, 0);
+ rb_define_singleton_method(rb_cThread, "asan?", asan_p, 0);
+}
diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c
index b0b1ef5374..931220b46b 100644
--- a/ext/-test-/string/cstr.c
+++ b/ext/-test-/string/cstr.c
@@ -111,9 +111,10 @@ bug_str_s_cstr_noembed(VALUE self, VALUE str)
FL_SET((str2), STR_NOEMBED);
memcpy(buf, RSTRING_PTR(str), capacity);
RBASIC(str2)->flags &= ~(STR_SHARED | FL_USER5 | FL_USER6);
- RSTRING(str2)->as.heap.aux.capa = capacity;
+ RSTRING(str2)->as.heap.aux.capa = RSTRING_LEN(str);
RSTRING(str2)->as.heap.ptr = buf;
RSTRING(str2)->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 044b6109ff..478ae3b82b 100644
--- a/ext/-test-/string/depend
+++ b/ext/-test-/string/depend
@@ -139,6 +139,7 @@ capacity.o: $(hdrdir)/ruby/internal/intern/re.h
capacity.o: $(hdrdir)/ruby/internal/intern/ruby.h
capacity.o: $(hdrdir)/ruby/internal/intern/select.h
capacity.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+capacity.o: $(hdrdir)/ruby/internal/intern/set.h
capacity.o: $(hdrdir)/ruby/internal/intern/signal.h
capacity.o: $(hdrdir)/ruby/internal/intern/sprintf.h
capacity.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -171,6 +172,7 @@ capacity.o: $(hdrdir)/ruby/oniguruma.h
capacity.o: $(hdrdir)/ruby/ruby.h
capacity.o: $(hdrdir)/ruby/st.h
capacity.o: $(hdrdir)/ruby/subst.h
+capacity.o: $(top_srcdir)/encindex.h
capacity.o: $(top_srcdir)/internal/compilers.h
capacity.o: $(top_srcdir)/internal/string.h
capacity.o: capacity.c
@@ -472,6 +474,7 @@ coderange.o: $(hdrdir)/ruby/internal/intern/re.h
coderange.o: $(hdrdir)/ruby/internal/intern/ruby.h
coderange.o: $(hdrdir)/ruby/internal/intern/select.h
coderange.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+coderange.o: $(hdrdir)/ruby/internal/intern/set.h
coderange.o: $(hdrdir)/ruby/internal/intern/signal.h
coderange.o: $(hdrdir)/ruby/internal/intern/sprintf.h
coderange.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -644,6 +647,7 @@ cstr.o: $(hdrdir)/ruby/internal/intern/re.h
cstr.o: $(hdrdir)/ruby/internal/intern/ruby.h
cstr.o: $(hdrdir)/ruby/internal/intern/select.h
cstr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+cstr.o: $(hdrdir)/ruby/internal/intern/set.h
cstr.o: $(hdrdir)/ruby/internal/intern/signal.h
cstr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
cstr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -676,6 +680,7 @@ cstr.o: $(hdrdir)/ruby/oniguruma.h
cstr.o: $(hdrdir)/ruby/ruby.h
cstr.o: $(hdrdir)/ruby/st.h
cstr.o: $(hdrdir)/ruby/subst.h
+cstr.o: $(top_srcdir)/encindex.h
cstr.o: $(top_srcdir)/internal.h
cstr.o: $(top_srcdir)/internal/compilers.h
cstr.o: $(top_srcdir)/internal/string.h
@@ -809,6 +814,7 @@ ellipsize.o: $(hdrdir)/ruby/internal/intern/re.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/ruby.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/select.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ellipsize.o: $(hdrdir)/ruby/internal/intern/set.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/signal.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -979,6 +985,7 @@ enc_associate.o: $(hdrdir)/ruby/internal/intern/re.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/select.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_associate.o: $(hdrdir)/ruby/internal/intern/set.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1151,6 +1158,7 @@ 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/set.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
@@ -1322,6 +1330,7 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/re.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/select.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/set.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1495,6 +1504,7 @@ fstring.o: $(hdrdir)/ruby/internal/intern/re.h
fstring.o: $(hdrdir)/ruby/internal/intern/ruby.h
fstring.o: $(hdrdir)/ruby/internal/intern/select.h
fstring.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+fstring.o: $(hdrdir)/ruby/internal/intern/set.h
fstring.o: $(hdrdir)/ruby/internal/intern/signal.h
fstring.o: $(hdrdir)/ruby/internal/intern/sprintf.h
fstring.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1527,6 +1537,7 @@ 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)/encindex.h
fstring.o: $(top_srcdir)/internal/compilers.h
fstring.o: $(top_srcdir)/internal/string.h
fstring.o: fstring.c
@@ -1659,6 +1670,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1819,6 +1831,7 @@ modify.o: $(hdrdir)/ruby/internal/intern/re.h
modify.o: $(hdrdir)/ruby/internal/intern/ruby.h
modify.o: $(hdrdir)/ruby/internal/intern/select.h
modify.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+modify.o: $(hdrdir)/ruby/internal/intern/set.h
modify.o: $(hdrdir)/ruby/internal/intern/signal.h
modify.o: $(hdrdir)/ruby/internal/intern/sprintf.h
modify.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1989,6 +2002,7 @@ new.o: $(hdrdir)/ruby/internal/intern/re.h
new.o: $(hdrdir)/ruby/internal/intern/ruby.h
new.o: $(hdrdir)/ruby/internal/intern/select.h
new.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+new.o: $(hdrdir)/ruby/internal/intern/set.h
new.o: $(hdrdir)/ruby/internal/intern/signal.h
new.o: $(hdrdir)/ruby/internal/intern/sprintf.h
new.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2151,6 +2165,7 @@ nofree.o: $(hdrdir)/ruby/internal/intern/re.h
nofree.o: $(hdrdir)/ruby/internal/intern/ruby.h
nofree.o: $(hdrdir)/ruby/internal/intern/select.h
nofree.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nofree.o: $(hdrdir)/ruby/internal/intern/set.h
nofree.o: $(hdrdir)/ruby/internal/intern/signal.h
nofree.o: $(hdrdir)/ruby/internal/intern/sprintf.h
nofree.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2320,6 +2335,7 @@ normalize.o: $(hdrdir)/ruby/internal/intern/re.h
normalize.o: $(hdrdir)/ruby/internal/intern/ruby.h
normalize.o: $(hdrdir)/ruby/internal/intern/select.h
normalize.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+normalize.o: $(hdrdir)/ruby/internal/intern/set.h
normalize.o: $(hdrdir)/ruby/internal/intern/signal.h
normalize.o: $(hdrdir)/ruby/internal/intern/sprintf.h
normalize.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2493,6 +2509,7 @@ qsort.o: $(hdrdir)/ruby/internal/intern/re.h
qsort.o: $(hdrdir)/ruby/internal/intern/ruby.h
qsort.o: $(hdrdir)/ruby/internal/intern/select.h
qsort.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+qsort.o: $(hdrdir)/ruby/internal/intern/set.h
qsort.o: $(hdrdir)/ruby/internal/intern/signal.h
qsort.o: $(hdrdir)/ruby/internal/intern/sprintf.h
qsort.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2656,6 +2673,7 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/intern/re.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/select.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/intern/set.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2816,6 +2834,7 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/intern/re.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/select.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/intern/set.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2976,6 +2995,7 @@ set_len.o: $(hdrdir)/ruby/internal/intern/re.h
set_len.o: $(hdrdir)/ruby/internal/intern/ruby.h
set_len.o: $(hdrdir)/ruby/internal/intern/select.h
set_len.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+set_len.o: $(hdrdir)/ruby/internal/intern/set.h
set_len.o: $(hdrdir)/ruby/internal/intern/signal.h
set_len.o: $(hdrdir)/ruby/internal/intern/sprintf.h
set_len.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/string/fstring.c b/ext/-test-/string/fstring.c
index 71c4b7f97e..0b5940f28c 100644
--- a/ext/-test-/string/fstring.c
+++ b/ext/-test-/string/fstring.c
@@ -12,20 +12,20 @@ VALUE
bug_s_fstring_fake_str(VALUE self)
{
static const char literal[] = "abcdefghijklmnopqrstuvwxyz";
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
return rb_str_to_interned_str(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, NIL_P(encoding) ? NULL : RTYPEDDATA_GET_DATA(encoding));
}
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, NIL_P(encoding) ? NULL : RTYPEDDATA_GET_DATA(encoding));
}
void
diff --git a/ext/-test-/struct/depend b/ext/-test-/struct/depend
index 951dddd5dd..e2638e4cdf 100644
--- a/ext/-test-/struct/depend
+++ b/ext/-test-/struct/depend
@@ -128,6 +128,7 @@ 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/set.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
@@ -288,6 +289,7 @@ duplicate.o: $(hdrdir)/ruby/internal/intern/re.h
duplicate.o: $(hdrdir)/ruby/internal/intern/ruby.h
duplicate.o: $(hdrdir)/ruby/internal/intern/select.h
duplicate.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+duplicate.o: $(hdrdir)/ruby/internal/intern/set.h
duplicate.o: $(hdrdir)/ruby/internal/intern/signal.h
duplicate.o: $(hdrdir)/ruby/internal/intern/sprintf.h
duplicate.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -608,6 +611,7 @@ len.o: $(hdrdir)/ruby/internal/intern/re.h
len.o: $(hdrdir)/ruby/internal/intern/ruby.h
len.o: $(hdrdir)/ruby/internal/intern/select.h
len.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+len.o: $(hdrdir)/ruby/internal/intern/set.h
len.o: $(hdrdir)/ruby/internal/intern/signal.h
len.o: $(hdrdir)/ruby/internal/intern/sprintf.h
len.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -768,6 +772,7 @@ member.o: $(hdrdir)/ruby/internal/intern/re.h
member.o: $(hdrdir)/ruby/internal/intern/ruby.h
member.o: $(hdrdir)/ruby/internal/intern/select.h
member.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+member.o: $(hdrdir)/ruby/internal/intern/set.h
member.o: $(hdrdir)/ruby/internal/intern/signal.h
member.o: $(hdrdir)/ruby/internal/intern/sprintf.h
member.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/symbol/depend b/ext/-test-/symbol/depend
index 7c76596fdf..b1d8e1aab6 100644
--- a/ext/-test-/symbol/depend
+++ b/ext/-test-/symbol/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ type.o: $(hdrdir)/ruby/internal/intern/re.h
type.o: $(hdrdir)/ruby/internal/intern/ruby.h
type.o: $(hdrdir)/ruby/internal/intern/select.h
type.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+type.o: $(hdrdir)/ruby/internal/intern/set.h
type.o: $(hdrdir)/ruby/internal/intern/signal.h
type.o: $(hdrdir)/ruby/internal/intern/sprintf.h
type.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/thread/id/depend b/ext/-test-/thread/id/depend
new file mode 100644
index 0000000000..6b76b31ddc
--- /dev/null
+++ b/ext/-test-/thread/id/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+id.o: $(RUBY_EXTCONF_H)
+id.o: $(arch_hdrdir)/ruby/config.h
+id.o: $(hdrdir)/ruby.h
+id.o: $(hdrdir)/ruby/assert.h
+id.o: $(hdrdir)/ruby/backward.h
+id.o: $(hdrdir)/ruby/backward/2/assume.h
+id.o: $(hdrdir)/ruby/backward/2/attributes.h
+id.o: $(hdrdir)/ruby/backward/2/bool.h
+id.o: $(hdrdir)/ruby/backward/2/inttypes.h
+id.o: $(hdrdir)/ruby/backward/2/limits.h
+id.o: $(hdrdir)/ruby/backward/2/long_long.h
+id.o: $(hdrdir)/ruby/backward/2/stdalign.h
+id.o: $(hdrdir)/ruby/backward/2/stdarg.h
+id.o: $(hdrdir)/ruby/defines.h
+id.o: $(hdrdir)/ruby/intern.h
+id.o: $(hdrdir)/ruby/internal/abi.h
+id.o: $(hdrdir)/ruby/internal/anyargs.h
+id.o: $(hdrdir)/ruby/internal/arithmetic.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+id.o: $(hdrdir)/ruby/internal/assume.h
+id.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+id.o: $(hdrdir)/ruby/internal/attr/artificial.h
+id.o: $(hdrdir)/ruby/internal/attr/cold.h
+id.o: $(hdrdir)/ruby/internal/attr/const.h
+id.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+id.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+id.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+id.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+id.o: $(hdrdir)/ruby/internal/attr/error.h
+id.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+id.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+id.o: $(hdrdir)/ruby/internal/attr/format.h
+id.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+id.o: $(hdrdir)/ruby/internal/attr/noalias.h
+id.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+id.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+id.o: $(hdrdir)/ruby/internal/attr/noinline.h
+id.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+id.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+id.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+id.o: $(hdrdir)/ruby/internal/attr/pure.h
+id.o: $(hdrdir)/ruby/internal/attr/restrict.h
+id.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+id.o: $(hdrdir)/ruby/internal/attr/warning.h
+id.o: $(hdrdir)/ruby/internal/attr/weakref.h
+id.o: $(hdrdir)/ruby/internal/cast.h
+id.o: $(hdrdir)/ruby/internal/compiler_is.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+id.o: $(hdrdir)/ruby/internal/compiler_since.h
+id.o: $(hdrdir)/ruby/internal/config.h
+id.o: $(hdrdir)/ruby/internal/constant_p.h
+id.o: $(hdrdir)/ruby/internal/core.h
+id.o: $(hdrdir)/ruby/internal/core/rarray.h
+id.o: $(hdrdir)/ruby/internal/core/rbasic.h
+id.o: $(hdrdir)/ruby/internal/core/rbignum.h
+id.o: $(hdrdir)/ruby/internal/core/rclass.h
+id.o: $(hdrdir)/ruby/internal/core/rdata.h
+id.o: $(hdrdir)/ruby/internal/core/rfile.h
+id.o: $(hdrdir)/ruby/internal/core/rhash.h
+id.o: $(hdrdir)/ruby/internal/core/robject.h
+id.o: $(hdrdir)/ruby/internal/core/rregexp.h
+id.o: $(hdrdir)/ruby/internal/core/rstring.h
+id.o: $(hdrdir)/ruby/internal/core/rstruct.h
+id.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+id.o: $(hdrdir)/ruby/internal/ctype.h
+id.o: $(hdrdir)/ruby/internal/dllexport.h
+id.o: $(hdrdir)/ruby/internal/dosish.h
+id.o: $(hdrdir)/ruby/internal/error.h
+id.o: $(hdrdir)/ruby/internal/eval.h
+id.o: $(hdrdir)/ruby/internal/event.h
+id.o: $(hdrdir)/ruby/internal/fl_type.h
+id.o: $(hdrdir)/ruby/internal/gc.h
+id.o: $(hdrdir)/ruby/internal/glob.h
+id.o: $(hdrdir)/ruby/internal/globals.h
+id.o: $(hdrdir)/ruby/internal/has/attribute.h
+id.o: $(hdrdir)/ruby/internal/has/builtin.h
+id.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+id.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+id.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+id.o: $(hdrdir)/ruby/internal/has/extension.h
+id.o: $(hdrdir)/ruby/internal/has/feature.h
+id.o: $(hdrdir)/ruby/internal/has/warning.h
+id.o: $(hdrdir)/ruby/internal/intern/array.h
+id.o: $(hdrdir)/ruby/internal/intern/bignum.h
+id.o: $(hdrdir)/ruby/internal/intern/class.h
+id.o: $(hdrdir)/ruby/internal/intern/compar.h
+id.o: $(hdrdir)/ruby/internal/intern/complex.h
+id.o: $(hdrdir)/ruby/internal/intern/cont.h
+id.o: $(hdrdir)/ruby/internal/intern/dir.h
+id.o: $(hdrdir)/ruby/internal/intern/enum.h
+id.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+id.o: $(hdrdir)/ruby/internal/intern/error.h
+id.o: $(hdrdir)/ruby/internal/intern/eval.h
+id.o: $(hdrdir)/ruby/internal/intern/file.h
+id.o: $(hdrdir)/ruby/internal/intern/hash.h
+id.o: $(hdrdir)/ruby/internal/intern/io.h
+id.o: $(hdrdir)/ruby/internal/intern/load.h
+id.o: $(hdrdir)/ruby/internal/intern/marshal.h
+id.o: $(hdrdir)/ruby/internal/intern/numeric.h
+id.o: $(hdrdir)/ruby/internal/intern/object.h
+id.o: $(hdrdir)/ruby/internal/intern/parse.h
+id.o: $(hdrdir)/ruby/internal/intern/proc.h
+id.o: $(hdrdir)/ruby/internal/intern/process.h
+id.o: $(hdrdir)/ruby/internal/intern/random.h
+id.o: $(hdrdir)/ruby/internal/intern/range.h
+id.o: $(hdrdir)/ruby/internal/intern/rational.h
+id.o: $(hdrdir)/ruby/internal/intern/re.h
+id.o: $(hdrdir)/ruby/internal/intern/ruby.h
+id.o: $(hdrdir)/ruby/internal/intern/select.h
+id.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+id.o: $(hdrdir)/ruby/internal/intern/set.h
+id.o: $(hdrdir)/ruby/internal/intern/signal.h
+id.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+id.o: $(hdrdir)/ruby/internal/intern/string.h
+id.o: $(hdrdir)/ruby/internal/intern/struct.h
+id.o: $(hdrdir)/ruby/internal/intern/thread.h
+id.o: $(hdrdir)/ruby/internal/intern/time.h
+id.o: $(hdrdir)/ruby/internal/intern/variable.h
+id.o: $(hdrdir)/ruby/internal/intern/vm.h
+id.o: $(hdrdir)/ruby/internal/interpreter.h
+id.o: $(hdrdir)/ruby/internal/iterator.h
+id.o: $(hdrdir)/ruby/internal/memory.h
+id.o: $(hdrdir)/ruby/internal/method.h
+id.o: $(hdrdir)/ruby/internal/module.h
+id.o: $(hdrdir)/ruby/internal/newobj.h
+id.o: $(hdrdir)/ruby/internal/scan_args.h
+id.o: $(hdrdir)/ruby/internal/special_consts.h
+id.o: $(hdrdir)/ruby/internal/static_assert.h
+id.o: $(hdrdir)/ruby/internal/stdalign.h
+id.o: $(hdrdir)/ruby/internal/stdbool.h
+id.o: $(hdrdir)/ruby/internal/stdckdint.h
+id.o: $(hdrdir)/ruby/internal/symbol.h
+id.o: $(hdrdir)/ruby/internal/value.h
+id.o: $(hdrdir)/ruby/internal/value_type.h
+id.o: $(hdrdir)/ruby/internal/variable.h
+id.o: $(hdrdir)/ruby/internal/warning_push.h
+id.o: $(hdrdir)/ruby/internal/xmalloc.h
+id.o: $(hdrdir)/ruby/missing.h
+id.o: $(hdrdir)/ruby/ruby.h
+id.o: $(hdrdir)/ruby/st.h
+id.o: $(hdrdir)/ruby/subst.h
+id.o: id.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/thread/instrumentation/depend b/ext/-test-/thread/instrumentation/depend
index a37e4d5675..63e1c7e44f 100644
--- a/ext/-test-/thread/instrumentation/depend
+++ b/ext/-test-/thread/instrumentation/depend
@@ -128,6 +128,7 @@ instrumentation.o: $(hdrdir)/ruby/internal/intern/re.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/ruby.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/select.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+instrumentation.o: $(hdrdir)/ruby/internal/intern/set.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/signal.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/sprintf.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/thread/instrumentation/instrumentation.c b/ext/-test-/thread/instrumentation/instrumentation.c
index d81bc0f2a7..25e2902a78 100644
--- a/ext/-test-/thread/instrumentation/instrumentation.c
+++ b/ext/-test-/thread/instrumentation/instrumentation.c
@@ -6,7 +6,6 @@
# define RB_THREAD_LOCAL_SPECIFIER
#endif
-static VALUE last_thread = Qnil;
static VALUE timeline_value = Qnil;
struct thread_event {
@@ -211,9 +210,8 @@ 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);
+ timeline_value = TypedData_Wrap_Struct(0, &event_timeline_type, (void *)1);
- rb_global_variable(&last_thread);
rb_define_singleton_method(klass, "register_callback", thread_register_callback, 1);
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/lock_native_thread/depend b/ext/-test-/thread/lock_native_thread/depend
new file mode 100644
index 0000000000..a32843e531
--- /dev/null
+++ b/ext/-test-/thread/lock_native_thread/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+lock_native_thread.o: $(RUBY_EXTCONF_H)
+lock_native_thread.o: $(arch_hdrdir)/ruby/config.h
+lock_native_thread.o: $(hdrdir)/ruby/assert.h
+lock_native_thread.o: $(hdrdir)/ruby/backward.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/assume.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/attributes.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/bool.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/inttypes.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/limits.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/long_long.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/stdalign.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/stdarg.h
+lock_native_thread.o: $(hdrdir)/ruby/defines.h
+lock_native_thread.o: $(hdrdir)/ruby/intern.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/abi.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/anyargs.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/assume.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/artificial.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/cold.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/const.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/error.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/format.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noalias.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noinline.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/pure.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/restrict.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/warning.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/weakref.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/cast.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_since.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/config.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/constant_p.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rarray.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rbasic.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rbignum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rclass.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rdata.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rfile.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rhash.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/robject.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rregexp.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rstring.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rstruct.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/ctype.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/dllexport.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/dosish.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/error.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/eval.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/event.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/fl_type.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/gc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/glob.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/globals.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/builtin.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/extension.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/feature.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/warning.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/array.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/bignum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/class.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/compar.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/complex.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/cont.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/dir.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/enum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/error.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/eval.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/file.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/hash.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/io.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/load.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/marshal.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/numeric.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/object.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/parse.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/proc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/process.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/random.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/range.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/rational.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/re.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/ruby.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/select.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/set.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/signal.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/string.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/struct.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/thread.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/time.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/variable.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/vm.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/interpreter.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/iterator.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/memory.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/method.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/module.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/newobj.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/scan_args.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/special_consts.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/static_assert.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/stdalign.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/stdbool.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/stdckdint.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/symbol.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/value.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/value_type.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/variable.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/warning_push.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/xmalloc.h
+lock_native_thread.o: $(hdrdir)/ruby/missing.h
+lock_native_thread.o: $(hdrdir)/ruby/ruby.h
+lock_native_thread.o: $(hdrdir)/ruby/st.h
+lock_native_thread.o: $(hdrdir)/ruby/subst.h
+lock_native_thread.o: $(hdrdir)/ruby/thread.h
+lock_native_thread.o: lock_native_thread.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/thread_fd/depend b/ext/-test-/thread_fd/depend
deleted file mode 100644
index 0fda9f6dbf..0000000000
--- a/ext/-test-/thread_fd/depend
+++ /dev/null
@@ -1,161 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-thread_fd.o: $(RUBY_EXTCONF_H)
-thread_fd.o: $(arch_hdrdir)/ruby/config.h
-thread_fd.o: $(hdrdir)/ruby/assert.h
-thread_fd.o: $(hdrdir)/ruby/backward.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/assume.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/attributes.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/bool.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/inttypes.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/limits.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/long_long.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/stdalign.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/stdarg.h
-thread_fd.o: $(hdrdir)/ruby/defines.h
-thread_fd.o: $(hdrdir)/ruby/intern.h
-thread_fd.o: $(hdrdir)/ruby/internal/abi.h
-thread_fd.o: $(hdrdir)/ruby/internal/anyargs.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/assume.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/artificial.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/cold.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/const.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/error.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/format.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/noalias.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-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
-thread_fd.o: $(hdrdir)/ruby/internal/attr/warning.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/weakref.h
-thread_fd.o: $(hdrdir)/ruby/internal/cast.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_since.h
-thread_fd.o: $(hdrdir)/ruby/internal/config.h
-thread_fd.o: $(hdrdir)/ruby/internal/constant_p.h
-thread_fd.o: $(hdrdir)/ruby/internal/core.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rarray.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rbasic.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rbignum.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rclass.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rdata.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rfile.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rhash.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/robject.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rregexp.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rstring.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rstruct.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-thread_fd.o: $(hdrdir)/ruby/internal/ctype.h
-thread_fd.o: $(hdrdir)/ruby/internal/dllexport.h
-thread_fd.o: $(hdrdir)/ruby/internal/dosish.h
-thread_fd.o: $(hdrdir)/ruby/internal/error.h
-thread_fd.o: $(hdrdir)/ruby/internal/eval.h
-thread_fd.o: $(hdrdir)/ruby/internal/event.h
-thread_fd.o: $(hdrdir)/ruby/internal/fl_type.h
-thread_fd.o: $(hdrdir)/ruby/internal/gc.h
-thread_fd.o: $(hdrdir)/ruby/internal/glob.h
-thread_fd.o: $(hdrdir)/ruby/internal/globals.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/builtin.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/extension.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/feature.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/warning.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/array.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/bignum.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/class.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/compar.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/complex.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/cont.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/dir.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/enum.h
-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/hash.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/io.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/load.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/marshal.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/numeric.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/object.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/parse.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/proc.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/process.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/random.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/range.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/rational.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/re.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/ruby.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/select.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/signal.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/string.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/struct.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/thread.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/time.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/variable.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/vm.h
-thread_fd.o: $(hdrdir)/ruby/internal/interpreter.h
-thread_fd.o: $(hdrdir)/ruby/internal/iterator.h
-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/scan_args.h
-thread_fd.o: $(hdrdir)/ruby/internal/special_consts.h
-thread_fd.o: $(hdrdir)/ruby/internal/static_assert.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdalign.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdbool.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdckdint.h
-thread_fd.o: $(hdrdir)/ruby/internal/symbol.h
-thread_fd.o: $(hdrdir)/ruby/internal/value.h
-thread_fd.o: $(hdrdir)/ruby/internal/value_type.h
-thread_fd.o: $(hdrdir)/ruby/internal/variable.h
-thread_fd.o: $(hdrdir)/ruby/internal/warning_push.h
-thread_fd.o: $(hdrdir)/ruby/internal/xmalloc.h
-thread_fd.o: $(hdrdir)/ruby/missing.h
-thread_fd.o: $(hdrdir)/ruby/ruby.h
-thread_fd.o: $(hdrdir)/ruby/st.h
-thread_fd.o: $(hdrdir)/ruby/subst.h
-thread_fd.o: thread_fd.c
-# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/thread_fd/extconf.rb b/ext/-test-/thread_fd/extconf.rb
deleted file mode 100644
index a8bbe9d169..0000000000
--- a/ext/-test-/thread_fd/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# frozen_string_literal: true
-create_makefile('-test-/thread_fd')
diff --git a/ext/-test-/thread_fd/thread_fd.c b/ext/-test-/thread_fd/thread_fd.c
deleted file mode 100644
index 042b799dc8..0000000000
--- a/ext/-test-/thread_fd/thread_fd.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "ruby/ruby.h"
-
-static VALUE
-thread_fd_close(VALUE ign, VALUE fd)
-{
- rb_thread_fd_close(NUM2INT(fd));
- return Qnil;
-}
-
-static VALUE
-thread_fd_wait(VALUE ign, VALUE fd)
-{
- int ret = rb_thread_wait_fd(NUM2INT(fd));
- return INT2NUM(ret);
-}
-
-static VALUE
-thread_fd_writable(VALUE ign, VALUE fd)
-{
- int ret = rb_thread_fd_writable(NUM2INT(fd));
- return INT2NUM(ret);
-}
-
-void
-Init_thread_fd(void)
-{
- rb_define_singleton_method(rb_cIO, "thread_fd_close", thread_fd_close, 1);
- rb_define_singleton_method(rb_cIO, "thread_fd_wait", thread_fd_wait, 1);
- rb_define_singleton_method(rb_cIO, "thread_fd_writable", thread_fd_writable, 1);
-}
diff --git a/ext/-test-/time/depend b/ext/-test-/time/depend
index 5ed791bcc5..e5b05f3113 100644
--- a/ext/-test-/time/depend
+++ b/ext/-test-/time/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -289,6 +290,7 @@ leap_second.o: $(hdrdir)/ruby/internal/intern/re.h
leap_second.o: $(hdrdir)/ruby/internal/intern/ruby.h
leap_second.o: $(hdrdir)/ruby/internal/intern/select.h
leap_second.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+leap_second.o: $(hdrdir)/ruby/internal/intern/set.h
leap_second.o: $(hdrdir)/ruby/internal/intern/signal.h
leap_second.o: $(hdrdir)/ruby/internal/intern/sprintf.h
leap_second.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -453,6 +455,7 @@ new.o: $(hdrdir)/ruby/internal/intern/re.h
new.o: $(hdrdir)/ruby/internal/intern/ruby.h
new.o: $(hdrdir)/ruby/internal/intern/select.h
new.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+new.o: $(hdrdir)/ruby/internal/intern/set.h
new.o: $(hdrdir)/ruby/internal/intern/signal.h
new.o: $(hdrdir)/ruby/internal/intern/sprintf.h
new.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/time/leap_second.c b/ext/-test-/time/leap_second.c
deleted file mode 100644
index ee7011fa97..0000000000
--- a/ext/-test-/time/leap_second.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "ruby.h"
-#include "internal/time.h"
-
-static VALUE
-bug_time_s_reset_leap_second_info(VALUE klass)
-{
- ruby_reset_leap_second_info();
- return Qnil;
-}
-
-void
-Init_time_leap_second(VALUE klass)
-{
- rb_define_singleton_method(klass, "reset_leap_second_info", bug_time_s_reset_leap_second_info, 0);
-}
diff --git a/ext/-test-/tracepoint/depend b/ext/-test-/tracepoint/depend
index 133663b3bd..014ba83b16 100644
--- a/ext/-test-/tracepoint/depend
+++ b/ext/-test-/tracepoint/depend
@@ -128,6 +128,7 @@ gc_hook.o: $(hdrdir)/ruby/internal/intern/re.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/ruby.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/select.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+gc_hook.o: $(hdrdir)/ruby/internal/intern/set.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/signal.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/sprintf.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ tracepoint.o: $(hdrdir)/ruby/internal/intern/re.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/ruby.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/select.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tracepoint.o: $(hdrdir)/ruby/internal/intern/set.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/signal.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/tracepoint/gc_hook.c b/ext/-test-/tracepoint/gc_hook.c
index 54c06c54a5..525be6da63 100644
--- a/ext/-test-/tracepoint/gc_hook.c
+++ b/ext/-test-/tracepoint/gc_hook.c
@@ -2,6 +2,7 @@
#include "ruby/debug.h"
static int invoking; /* TODO: should not be global variable */
+extern VALUE tp_mBug;
static VALUE
invoke_proc_ensure(VALUE _)
@@ -17,9 +18,9 @@ invoke_proc_begin(VALUE proc)
}
static void
-invoke_proc(void *data)
+invoke_proc(void *ivar_name)
{
- VALUE proc = (VALUE)data;
+ VALUE proc = rb_ivar_get(tp_mBug, rb_intern(ivar_name));
invoking += 1;
rb_ensure(invoke_proc_begin, proc, invoke_proc_ensure, 0);
}
@@ -40,16 +41,16 @@ gc_start_end_i(VALUE tpval, void *data)
}
static VALUE
-set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
+set_gc_hook(VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
{
VALUE tpval;
ID tp_key = rb_intern(tp_str);
/* disable previous keys */
- if (rb_ivar_defined(module, tp_key) != 0 &&
- RTEST(tpval = rb_ivar_get(module, tp_key))) {
+ if (rb_ivar_defined(tp_mBug, tp_key) != 0 &&
+ RTEST(tpval = rb_ivar_get(tp_mBug, tp_key))) {
rb_tracepoint_disable(tpval);
- rb_ivar_set(module, tp_key, Qnil);
+ rb_ivar_set(tp_mBug, tp_key, Qnil);
}
if (RTEST(proc)) {
@@ -57,8 +58,9 @@ set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str,
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
}
- tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc);
- rb_ivar_set(module, tp_key, tpval);
+ rb_ivar_set(tp_mBug, rb_intern(proc_str), proc);
+ tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc_str);
+ rb_ivar_set(tp_mBug, tp_key, tpval);
rb_tracepoint_enable(tpval);
}
@@ -66,16 +68,16 @@ set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str,
}
static VALUE
-set_after_gc_start(VALUE module, VALUE proc)
+set_after_gc_start(VALUE _self, VALUE proc)
{
- return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_START,
+ return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_START,
"__set_after_gc_start_tpval__", "__set_after_gc_start_proc__");
}
static VALUE
-start_after_gc_exit(VALUE module, VALUE proc)
+start_after_gc_exit(VALUE _self, VALUE proc)
{
- return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_EXIT,
+ return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_EXIT,
"__set_after_gc_exit_tpval__", "__set_after_gc_exit_proc__");
}
diff --git a/ext/-test-/tracepoint/tracepoint.c b/ext/-test-/tracepoint/tracepoint.c
index 2826cc038c..001d9513b2 100644
--- a/ext/-test-/tracepoint/tracepoint.c
+++ b/ext/-test-/tracepoint/tracepoint.c
@@ -1,6 +1,8 @@
#include "ruby/ruby.h"
#include "ruby/debug.h"
+VALUE tp_mBug;
+
struct tracepoint_track {
size_t newobj_count;
size_t free_count;
@@ -89,8 +91,8 @@ void Init_gc_hook(VALUE);
void
Init_tracepoint(void)
{
- VALUE mBug = rb_define_module("Bug");
- Init_gc_hook(mBug);
- rb_define_module_function(mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
- rb_define_module_function(mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
+ tp_mBug = rb_define_module("Bug"); // GC root
+ Init_gc_hook(tp_mBug);
+ rb_define_module_function(tp_mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
+ rb_define_module_function(tp_mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
}
diff --git a/ext/-test-/typeddata/depend b/ext/-test-/typeddata/depend
index 6c0847c82d..b9b4915eee 100644
--- a/ext/-test-/typeddata/depend
+++ b/ext/-test-/typeddata/depend
@@ -128,6 +128,7 @@ typeddata.o: $(hdrdir)/ruby/internal/intern/re.h
typeddata.o: $(hdrdir)/ruby/internal/intern/ruby.h
typeddata.o: $(hdrdir)/ruby/internal/intern/select.h
typeddata.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+typeddata.o: $(hdrdir)/ruby/internal/intern/set.h
typeddata.o: $(hdrdir)/ruby/internal/intern/signal.h
typeddata.o: $(hdrdir)/ruby/internal/intern/sprintf.h
typeddata.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/vm/depend b/ext/-test-/vm/depend
index 422b40a32d..9313f2ee36 100644
--- a/ext/-test-/vm/depend
+++ b/ext/-test-/vm/depend
@@ -127,6 +127,7 @@ at_exit.o: $(hdrdir)/ruby/internal/intern/re.h
at_exit.o: $(hdrdir)/ruby/internal/intern/ruby.h
at_exit.o: $(hdrdir)/ruby/internal/intern/select.h
at_exit.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+at_exit.o: $(hdrdir)/ruby/internal/intern/set.h
at_exit.o: $(hdrdir)/ruby/internal/intern/signal.h
at_exit.o: $(hdrdir)/ruby/internal/intern/sprintf.h
at_exit.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/wait/depend b/ext/-test-/wait/depend
index 7997a16709..f793d84831 100644
--- a/ext/-test-/wait/depend
+++ b/ext/-test-/wait/depend
@@ -137,6 +137,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/re.h
wait.o: $(hdrdir)/ruby/internal/intern/ruby.h
wait.o: $(hdrdir)/ruby/internal/intern/select.h
wait.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+wait.o: $(hdrdir)/ruby/internal/intern/set.h
wait.o: $(hdrdir)/ruby/internal/intern/signal.h
wait.o: $(hdrdir)/ruby/internal/intern/sprintf.h
wait.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/.document b/ext/.document
index 0efd511a61..d75c5c3d35 100644
--- a/ext/.document
+++ b/ext/.document
@@ -1,7 +1,5 @@
# Add files to this as they become documented
-bigdecimal/bigdecimal.c
-bigdecimal/lib
cgi/escape/escape.c
continuation/continuation.c
coverage/coverage.c
@@ -21,24 +19,12 @@ digest/sha2/sha2init.c
digest/sha2/lib
etc/etc.c
fcntl/fcntl.c
-fiddle/closure.c
-fiddle/conversions.c
-fiddle/fiddle.c
-fiddle/function.c
-fiddle/pinned.c
-fiddle/pointer.c
-fiddle/handle.c
-fiddle/lib
io/console/
io/nonblock/nonblock.c
io/wait/wait.c
json/generator/generator.c
json/lib
json/parser/parser.c
-monitor/lib
-monitor/monitor.c
-nkf/lib
-nkf/nkf.c
objspace/objspace.c
objspace/objspace_dump.c
objspace/object_tracing.c
@@ -76,8 +62,6 @@ openssl/ossl_x509name.c
openssl/ossl_x509req.c
openssl/ossl_x509revoked.c
openssl/ossl_x509store.c
-pathname/lib
-pathname/pathname.c
psych/lib
psych/psych.c
psych/psych_emitter.c
@@ -86,17 +70,12 @@ psych/psych_to_ruby.c
psych/psych_yaml_tree.c
pty/lib
pty/pty.c
-racc/cparse/cparse.c
rbconfig/sizeof/*.c
-readline/readline.c
ripper/lib
socket
stringio/stringio.c
+strscan/lib
strscan/strscan.c
-syslog/syslog.c
-syslog/lib
win32/lib
win32/resolv/*.c
-win32ole/lib
-win32ole/*.c
zlib/zlib.c
diff --git a/ext/Setup b/ext/Setup
index 9c3e2f48fe..5cd4e95e27 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -1,39 +1,34 @@
#option nodynamic
-#bigdecimal
#cgi/escape
#continuation
#coverage
#date
-#digest/bubblebabble
#digest
+#digest/bubblebabble
#digest/md5
#digest/rmd160
#digest/sha1
#digest/sha2
+#erb/escape
#etc
#fcntl
-#fiddle
#io/console
#io/nonblock
#io/wait
#json
#json/generator
#json/parser
-#nkf
#objspace
#openssl
-#pathname
#psych
#pty
-#racc/cparse
#rbconfig/sizeof
-#readline
#ripper
+#rubyvm
#socket
#stringio
#strscan
-#syslog
#win32
-#win32ole
+#win32/resolv
#zlib
diff --git a/ext/Setup.atheos b/ext/Setup.atheos
index 91f73f32f9..73c8d5d5a8 100644
--- a/ext/Setup.atheos
+++ b/ext/Setup.atheos
@@ -1,24 +1,23 @@
option nodynamic
-bigdecimal
cgi/escape
-digest
-digest/md5
-digest/rmd160
-digest/sha1
-digest/sha2
+continuation
+coverage
+date
+digest/*
+erb/escape
etc
fcntl
-io/wait
-nkf
+io/*
+json
+json/*
+objspace
#openssl
pty
-#racc/cparse
-readline
+rbconfig/sizeof
ripper
socket
stringio
strscan
syslog
-#win32ole
zlib
diff --git a/ext/Setup.nt b/ext/Setup.nt
index 1278f183e4..a9e87249d3 100644
--- a/ext/Setup.nt
+++ b/ext/Setup.nt
@@ -1,25 +1,23 @@
#option platform cygwin|mingw|mswin
#option nodynamic
-bigdecimal
cgi/escape
-digest
-digest/md5
-digest/rmd160
-digest/sha1
-digest/sha2
+continuation
+coverage
+date
+digest/*
+erb/escape
etc
fcntl
-#io/wait
-nkf
+io/*
+json
+json/*
+objspace
#openssl
-#pty
-#racc/cparse
-#readline
+rbconfig/sizeof
#ripper
socket
stringio
strscan
#syslog
-win32ole
#zlib
diff --git a/ext/cgi/escape/depend b/ext/cgi/escape/depend
index 746b47246a..05b59bfdea 100644
--- a/ext/cgi/escape/depend
+++ b/ext/cgi/escape/depend
@@ -138,6 +138,7 @@ escape.o: $(hdrdir)/ruby/internal/intern/re.h
escape.o: $(hdrdir)/ruby/internal/intern/ruby.h
escape.o: $(hdrdir)/ruby/internal/intern/select.h
escape.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+escape.o: $(hdrdir)/ruby/internal/intern/set.h
escape.o: $(hdrdir)/ruby/internal/intern/signal.h
escape.o: $(hdrdir)/ruby/internal/intern/sprintf.h
escape.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index 495ad83aa3..4773186603 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -8,7 +8,7 @@ RUBY_EXTERN const signed char ruby_digit36_to_number_table[];
#define upper_hexdigits (ruby_hexdigits+16)
#define char_to_number(c) ruby_digit36_to_number_table[(unsigned char)(c)]
-static VALUE rb_cCGI, rb_mUtil, rb_mEscape;
+static VALUE rb_cCGI, rb_mEscape, rb_mEscapeExt;
static ID id_accept_charset;
#define HTML_ESCAPE_MAX_LEN 6
@@ -45,6 +45,7 @@ escaped_length(VALUE str)
static VALUE
optimized_escape_html(VALUE str)
{
+ VALUE escaped;
VALUE vbuf;
char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
const char *cstr = RSTRING_PTR(str);
@@ -63,7 +64,6 @@ optimized_escape_html(VALUE str)
}
}
- VALUE escaped;
if (RSTRING_LEN(str) < (dest - buf)) {
escaped = rb_str_new(buf, dest - buf);
preserve_original_state(str, escaped);
@@ -471,17 +471,17 @@ Init_escape(void)
void
InitVM_escape(void)
{
- rb_cCGI = rb_define_class("CGI", rb_cObject);
- rb_mEscape = rb_define_module_under(rb_cCGI, "Escape");
- rb_mUtil = rb_define_module_under(rb_cCGI, "Util");
- 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);
- rb_extend_object(rb_cCGI, rb_mEscape);
+ rb_cCGI = rb_define_class("CGI", rb_cObject);
+ rb_mEscapeExt = rb_define_module_under(rb_cCGI, "EscapeExt");
+ rb_mEscape = rb_define_module_under(rb_cCGI, "Escape");
+ rb_define_method(rb_mEscapeExt, "escapeHTML", cgiesc_escape_html, 1);
+ rb_define_method(rb_mEscapeExt, "unescapeHTML", cgiesc_unescape_html, 1);
+ rb_define_method(rb_mEscapeExt, "escapeURIComponent", cgiesc_escape_uri_component, 1);
+ rb_define_alias(rb_mEscapeExt, "escape_uri_component", "escapeURIComponent");
+ rb_define_method(rb_mEscapeExt, "unescapeURIComponent", cgiesc_unescape_uri_component, -1);
+ rb_define_alias(rb_mEscapeExt, "unescape_uri_component", "unescapeURIComponent");
+ rb_define_method(rb_mEscapeExt, "escape", cgiesc_escape, 1);
+ rb_define_method(rb_mEscapeExt, "unescape", cgiesc_unescape, -1);
+ rb_prepend_module(rb_mEscape, rb_mEscapeExt);
+ rb_extend_object(rb_cCGI, rb_mEscapeExt);
}
diff --git a/ext/continuation/depend b/ext/continuation/depend
index b40e52e29b..b395d3d4d7 100644
--- a/ext/continuation/depend
+++ b/ext/continuation/depend
@@ -127,6 +127,7 @@ continuation.o: $(hdrdir)/ruby/internal/intern/re.h
continuation.o: $(hdrdir)/ruby/internal/intern/ruby.h
continuation.o: $(hdrdir)/ruby/internal/intern/select.h
continuation.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+continuation.o: $(hdrdir)/ruby/internal/intern/set.h
continuation.o: $(hdrdir)/ruby/internal/intern/signal.h
continuation.o: $(hdrdir)/ruby/internal/intern/sprintf.h
continuation.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index 1519b559cd..1b0280b460 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -52,17 +52,29 @@ rb_coverage_supported(VALUE self, VALUE _mode)
/*
* call-seq:
- * Coverage.setup => nil
- * Coverage.setup(:all) => nil
- * Coverage.setup(lines: bool, branches: bool, methods: bool, eval: bool) => nil
- * Coverage.setup(oneshot_lines: true) => nil
+ * Coverage.setup -> nil
+ * Coverage.setup(type) -> nil
+ * Coverage.setup(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false) -> nil
*
- * Set up the coverage measurement.
+ * Performs setup for coverage measurement, but does not start coverage measurement.
+ * To start coverage measurement, use Coverage.resume.
*
- * Note that this method does not start the measurement itself.
- * Use Coverage.resume to start the measurement.
+ * To perform both setup and start coverage measurement, Coverage.start can be used.
*
- * You may want to use Coverage.start to setup and then start the measurement.
+ * With argument +type+ given and +type+ is symbol +:all+, enables all types of coverage
+ * (lines, branches, methods, and eval).
+ *
+ * Keyword arguments or hash +type+ can be given with each of the following keys:
+ *
+ * - +lines+: Enables line coverage that records the number of times each line was executed.
+ * If +lines+ is enabled, +oneshot_lines+ cannot be enabled.
+ * See {Lines Coverage}[rdoc-ref:Coverage@Lines+Coverage].
+ * - +branches+: Enables branch coverage that records the number of times each
+ * branch in each conditional was executed. See {Branches Coverage}[rdoc-ref:Coverage@Branches+Coverage].
+ * - +methods+: Enables method coverage that records the number of times each method was exectued.
+ * See {Methods Coverage}[rdoc-ref:Coverage@Methods+Coverage].
+ * - +eval+: Enables coverage for evaluations (e.g. Kernel#eval, Module#class_eval).
+ * See {Eval Coverage}[rdoc-ref:Coverage@Eval+Coverage].
*/
static VALUE
rb_coverage_setup(int argc, VALUE *argv, VALUE klass)
@@ -152,14 +164,14 @@ rb_coverage_resume(VALUE klass)
/*
* call-seq:
- * Coverage.start => nil
- * Coverage.start(:all) => nil
- * Coverage.start(lines: bool, branches: bool, methods: bool, eval: bool) => nil
- * Coverage.start(oneshot_lines: true) => nil
- *
- * Enables the coverage measurement.
- * See the documentation of Coverage class in detail.
- * This is equivalent to Coverage.setup and Coverage.resume.
+ * Coverage.start -> nil
+ * Coverage.start(type) -> nil
+ * Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false) -> nil
+ *
+ * Enables coverage measurement.
+ * This method is equivalent to calling Coverage.setup with the arguments provided,
+ * and then calling Coverage.resume. See their respective documentation for more
+ * details.
*/
static VALUE
rb_coverage_start(int argc, VALUE *argv, VALUE klass)
@@ -337,7 +349,7 @@ coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
* Coverage.peek_result => hash
*
* Returns a hash that contains filename as key and coverage array as value.
- * This is the same as `Coverage.result(stop: false, clear: false)`.
+ * This is the same as <tt>Coverage.result(stop: false, clear: false)</tt>.
*
* {
* "file.rb" => [1, 2, nil],
@@ -352,7 +364,6 @@ rb_coverage_peek_result(VALUE klass)
if (!RTEST(coverages)) {
rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
}
- OBJ_WB_UNPROTECT(coverages);
rb_hash_foreach(coverages, coverage_peek_result_i, ncoverages);
@@ -468,151 +479,217 @@ rb_coverage_running(VALUE klass)
return current_state == RUNNING ? Qtrue : Qfalse;
}
-/* Coverage provides coverage measurement feature for Ruby.
- * This feature is experimental, so these APIs may be changed in future.
+/* \Coverage provides coverage measurement feature for Ruby.
*
- * Caveat: Currently, only process-global coverage measurement is supported.
- * You cannot measure per-thread coverage.
+ * Only process-global coverage measurement is supported, meaning
+ * that coverage cannot be measure on a per-thread basis.
*
- * = Usage
+ * = Quick Start
*
- * 1. require "coverage"
- * 2. do Coverage.start
- * 3. require or load Ruby source file
- * 4. Coverage.result will return a hash that contains filename as key and
- * coverage array as value. A coverage array gives, for each line, the
- * number of line execution by the interpreter. A +nil+ value means
- * coverage is disabled for this line (lines like +else+ and +end+).
+ * 1. Load coverage using <tt>require "coverage"</tt>.
+ * 2. Call Coverage.start to set up and begin coverage measurement.
+ * 3. All Ruby code loaded following the call to Coverage.start will have
+ * coverage measurement.
+ * 4. Coverage results can be fetched by calling Coverage.result, which returns a
+ * hash that contains filenames as the keys and coverage arrays as the values.
+ * Each element of the coverage array gives the number of times each line was
+ * executed. A +nil+ value means coverage was disabled for that line (e.g.
+ * lines like +else+ and +end+).
*
* = Examples
*
- * [foo.rb]
- * s = 0
- * 10.times do |x|
- * s += x
- * end
+ * In file +fib.rb+:
*
- * if s == 45
- * p :ok
- * else
- * p :ng
+ * def fibonacci(n)
+ * if n == 0
+ * 0
+ * elsif n == 1
+ * 1
+ * else
+ * fibonacci(n - 1) + fibonacci(n - 2)
+ * end
* end
- * [EOF]
+ *
+ * puts fibonacci(10)
+ *
+ * In another file, coverage can be measured:
*
* require "coverage"
* Coverage.start
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}
+ * require "fib.rb"
+ * Coverage.result # => {"fib.rb" => [1, 177, 34, 143, 55, nil, 88, nil, nil, nil, 1]}
*
- * == Lines Coverage
+ * == Lines \Coverage
*
- * If a coverage mode is not explicitly specified when starting coverage, lines
- * coverage is what will run. It reports the number of line executions for each
- * line.
+ * Lines coverage reports the number of line executions for each line.
+ * If the coverage mode is not explicitly specified when starting coverage,
+ * lines coverage is used as the default.
*
* require "coverage"
* Coverage.start(lines: true)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}}
+ * require "fib"
+ * Coverage.result # => {"fib.rb" => {lines: [1, 177, 34, 143, 55, nil, 88, nil, nil, nil, 1]}}
+ *
+ * The returned hash differs depending on how Coverage.setup or Coverage.start
+ * was executed.
+ *
+ * If Coverage.start or Coverage.setup was called with no arguments, it returns a
+ * hash which contains filenames as the keys and coverage arrays as the values.
*
- * The value of the lines coverage result is an array containing how many times
- * each line was executed. Order in this array is important. For example, the
- * first item in this array, at index 0, reports how many times line 1 of this
- * file was executed while coverage was run (which, in this example, is one
- * time).
+ * If Coverage.start or Coverage.setup was called with <tt>line: true</tt>, it
+ * returns a hash which contains filenames as the keys and hashes as the values.
+ * The value hash has a key +:lines+ where the value is a coverage array.
*
- * A +nil+ value means coverage is disabled for this line (lines like +else+
- * and +end+).
+ * Each element of the coverage array gives the number of times the line was
+ * executed. A +nil+ value in the coverage array means coverage was disabled
+ * for that line (e.g. lines like +else+ and +end+).
*
- * == Oneshot Lines Coverage
+ * == Oneshot Lines \Coverage
*
- * Oneshot lines coverage tracks and reports on the executed lines while
- * coverage is running. It will not report how many times a line was executed,
- * only that it was executed.
+ * Oneshot lines coverage is similar to lines coverage, but instead of reporting
+ * the number of times a line was executed, it only reports the lines that were
+ * executed.
*
* require "coverage"
* Coverage.start(oneshot_lines: true)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:oneshot_lines=>[1, 2, 3, 6, 7]}}
+ * require "fib"
+ * Coverage.result # => {"fib.rb" => {oneshot_lines: [1, 11, 2, 4, 7, 5, 3]}}
*
* The value of the oneshot lines coverage result is an array containing the
* line numbers that were executed.
*
- * == Branches Coverage
+ * == Branches \Coverage
*
- * Branches coverage reports how many times each branch within each conditional
+ * Branches coverage reports the number of times each branch within each conditional
* was executed.
*
* require "coverage"
* Coverage.start(branches: true)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}}}
+ * require "fib"
+ * Coverage.result
+ * # => {"fib.rb" => {
+ * # branches: {
+ * # [:if, 0, 2, 2, 8, 5] => {
+ * # [:then, 1, 3, 4, 3, 5] => 34,
+ * # [:else, 2, 4, 2, 8, 5] => 143},
+ * # [:if, 3, 4, 2, 8, 5] => {
+ * # [:then, 4, 5, 4, 5, 5] => 55,
+ * # [:else, 5, 7, 4, 7, 39] => 88}}}}
*
* Each entry within the branches hash is a conditional, the value of which is
- * another hash where each entry is a branch in that conditional. The values
- * are the number of times the method was executed, and the keys are identifying
- * information about the branch.
+ * another hash where each entry is a branch in that conditional. The keys are
+ * arrays containing information about the branch and the values are the number
+ * of times the branch was executed.
*
- * The information that makes up each key identifying branches or conditionals
- * is the following, from left to right:
+ * The information that makes up the array that are the keys for conditional or
+ * branches are the following, from left to right:
*
- * 1. A label for the type of branch or conditional.
+ * 1. A label for the type of branch or conditional (e.g. +:if+, +:then+, +:else+).
* 2. A unique identifier.
- * 3. The starting line number it appears on in the file.
- * 4. The starting column number it appears on in the file.
- * 5. The ending line number it appears on in the file.
- * 6. The ending column number it appears on in the file.
+ * 3. Starting line number.
+ * 4. Starting column number.
+ * 5. Ending line number.
+ * 6. Ending column number.
*
- * == Methods Coverage
+ * == Methods \Coverage
*
* Methods coverage reports how many times each method was executed.
*
- * [foo_method.rb]
- * class Greeter
- * def greet
- * "welcome!"
- * end
- * end
- *
- * def hello
- * "Hi"
- * end
- *
- * hello()
- * Greeter.new.greet()
- * [EOF]
- *
* require "coverage"
* Coverage.start(methods: true)
- * require "foo_method.rb"
- * p Coverage.result #=> {"foo_method.rb"=>{:methods=>{[Object, :hello, 7, 0, 9, 3]=>1, [Greeter, :greet, 2, 2, 4, 5]=>1}}}
+ * require "fib"
+ * p Coverage.result #=> {"fib.rb" => {methods: {[Object, :fibonacci, 1, 0, 9, 3] => 177}}}
*
- * Each entry within the methods hash represents a method. The values in this
- * hash are the number of times the method was executed, and the keys are
+ * Each entry within the methods hash represents a method. The keys are arrays
+ * containing hash are the number of times the method was executed, and the keys are
* identifying information about the method.
*
* The information that makes up each key identifying a method is the following,
* from left to right:
*
- * 1. The class.
- * 2. The method name.
- * 3. The starting line number the method appears on in the file.
- * 4. The starting column number the method appears on in the file.
- * 5. The ending line number the method appears on in the file.
- * 6. The ending column number the method appears on in the file.
+ * 1. Class that the method was defined in.
+ * 2. Method name as a Symbol.
+ * 3. Starting line number of the method.
+ * 4. Starting column number of the method.
+ * 5. Ending line number of the method.
+ * 6. Ending column number of the method.
*
- * == All Coverage Modes
+ * == Eval \Coverage
*
- * You can also run all modes of coverage simultaneously with this shortcut.
- * Note that running all coverage modes does not run both lines and oneshot
- * lines. Those modes cannot be run simultaneously. Lines coverage is run in
- * this case, because you can still use it to determine whether or not a line
- * was executed.
+ * Eval coverage can be combined with the coverage types above to track
+ * coverage for eval.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY, nil, "eval 1")
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result # => {"eval 1" => {lines: [1, 1, 10, nil]}}
+ *
+ * Note that the eval must have a filename assigned, otherwise coverage
+ * will not be measured.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result # => {"(eval)" => {lines: [nil, nil, nil, nil]}}
+ *
+ * Also note that if a line number is assigned to the eval and it is not 1,
+ * then the resulting coverage will be padded with +nil+ if the line number is
+ * greater than 1, and truncated if the line number is less than 1.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY, nil, "eval 1", 3)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * eval(<<~RUBY, nil, "eval 2", -1)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result
+ * # => {"eval 1" => {lines: [nil, nil, 1, 1, 10, nil]}, "eval 2" => {lines: [10, nil]}}
+ *
+ * == All \Coverage Modes
+ *
+ * All modes of coverage can be enabled simultaneously using the Symbol +:all+.
+ * However, note that this mode runs lines coverage and not oneshot lines since
+ * they cannot be ran simultaneously.
*
* require "coverage"
* Coverage.start(:all)
- * require "foo.rb"
- * p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil], :branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}, :methods=>{}}}
+ * require "fib"
+ * Coverage.result
+ * # => {"fib.rb" => {
+ * # lines: [1, 177, 34, 143, 55, nil, 88, nil, nil, nil, 1],
+ * # branches: {
+ * # [:if, 0, 2, 2, 8, 5] => {
+ * # [:then, 1, 3, 4, 3, 5] => 34,
+ * # [:else, 2, 4, 2, 8, 5] => 143},
+ * # [:if, 3, 4, 2, 8, 5] => {
+ * # [:then, 4, 5, 4, 5, 5] => 55,
+ * # [:else, 5, 7, 4, 7, 39] => 88}}}},
+ * # methods: {[Object, :fibonacci, 1, 0, 9, 3] => 177}}}
*/
void
Init_coverage(void)
diff --git a/ext/coverage/depend b/ext/coverage/depend
index 1be81c5e9a..fb7f9a95af 100644
--- a/ext/coverage/depend
+++ b/ext/coverage/depend
@@ -140,6 +140,7 @@ coverage.o: $(hdrdir)/ruby/internal/intern/re.h
coverage.o: $(hdrdir)/ruby/internal/intern/ruby.h
coverage.o: $(hdrdir)/ruby/internal/intern/select.h
coverage.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+coverage.o: $(hdrdir)/ruby/internal/intern/set.h
coverage.o: $(hdrdir)/ruby/internal/intern/signal.h
coverage.o: $(hdrdir)/ruby/internal/intern/sprintf.h
coverage.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -182,12 +183,14 @@ coverage.o: $(top_srcdir)/id_table.h
coverage.o: $(top_srcdir)/internal.h
coverage.o: $(top_srcdir)/internal/array.h
coverage.o: $(top_srcdir)/internal/basic_operators.h
+coverage.o: $(top_srcdir)/internal/box.h
coverage.o: $(top_srcdir)/internal/compilers.h
coverage.o: $(top_srcdir)/internal/gc.h
coverage.o: $(top_srcdir)/internal/hash.h
coverage.o: $(top_srcdir)/internal/imemo.h
coverage.o: $(top_srcdir)/internal/sanitizers.h
coverage.o: $(top_srcdir)/internal/serial.h
+coverage.o: $(top_srcdir)/internal/set_table.h
coverage.o: $(top_srcdir)/internal/static_assert.h
coverage.o: $(top_srcdir)/internal/thread.h
coverage.o: $(top_srcdir)/internal/variable.h
diff --git a/ext/coverage/lib/coverage.rb b/ext/coverage/lib/coverage.rb
index f1923ef366..4bd20e22cb 100644
--- a/ext/coverage/lib/coverage.rb
+++ b/ext/coverage/lib/coverage.rb
@@ -1,6 +1,11 @@
require "coverage.so"
module Coverage
+ # call-seq:
+ # line_stub(file) -> array
+ #
+ # A simple helper function that creates the "stub" of line coverage
+ # from a given source code.
def self.line_stub(file)
lines = File.foreach(file).map { nil }
iseqs = [RubyVM::InstructionSequence.compile_file(file)]
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index b80d948b00..72d697c8ea 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -27,7 +27,7 @@ static VALUE eDateError;
static VALUE half_days_in_day, day_in_nanoseconds;
static double positive_inf, negative_inf;
-// used by deconstruct_keys
+/* used by deconstruct_keys */
static VALUE sym_year, sym_month, sym_day, sym_yday, sym_wday;
static VALUE sym_hour, sym_min, sym_sec, sym_sec_fraction, sym_zone;
@@ -452,11 +452,43 @@ do {\
static int c_valid_civil_p(int, int, int, double,
int *, int *, int *, int *);
+/* Check if using pure Gregorian calendar (sg == -Infinity) */
+#define c_gregorian_only_p(sg) (isinf(sg) && (sg) < 0)
+
+/*
+ * Fast path macros for pure Gregorian calendar.
+ * Sets *rjd to the JD value, *ns to 1 (new style), and returns.
+ */
+#define GREGORIAN_JD_FAST_PATH_RET(sg, jd_expr, rjd, ns) \
+ if (c_gregorian_only_p(sg)) { \
+ *(rjd) = (jd_expr); \
+ *(ns) = 1; \
+ return 1; \
+ }
+
+#define GREGORIAN_JD_FAST_PATH(sg, jd_expr, rjd, ns) \
+ if (c_gregorian_only_p(sg)) { \
+ *(rjd) = (jd_expr); \
+ *(ns) = 1; \
+ return; \
+ }
+
+/* Forward declarations for Neri-Schneider optimized functions */
+static int c_gregorian_civil_to_jd(int y, int m, int d);
+static void c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd);
+static int c_gregorian_fdoy(int y);
+static int c_gregorian_ldoy(int y);
+static int c_gregorian_ldom_jd(int y, int m);
+static int ns_jd_in_range(int jd);
+
static int
c_find_fdoy(int y, double sg, int *rjd, int *ns)
{
int d, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_fdoy(y), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (d = 1; d < 31; d++)
if (c_valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns))
return 1;
@@ -468,6 +500,9 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns)
{
int i, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldoy(y), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (i = 0; i < 30; i++)
if (c_valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns))
return 1;
@@ -493,6 +528,9 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
{
int i, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldom_jd(y, m), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (i = 0; i < 30; i++)
if (c_valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns))
return 1;
@@ -502,55 +540,69 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
static void
c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns)
{
- double a, b, jd;
+ int jd;
+
+ GREGORIAN_JD_FAST_PATH(sg, c_gregorian_civil_to_jd(y, m, d), rjd, ns);
+
+ /* Calculate Gregorian JD using optimized algorithm */
+ jd = c_gregorian_civil_to_jd(y, m, d);
- if (m <= 2) {
- y -= 1;
- m += 12;
- }
- a = floor(y / 100.0);
- b = 2 - a + floor(a / 4.0);
- jd = floor(365.25 * (y + 4716)) +
- floor(30.6001 * (m + 1)) +
- d + b - 1524;
if (jd < sg) {
- jd -= b;
+ /* Before Gregorian switchover - use Julian calendar */
+ int y2 = y, m2 = m;
+ if (m2 <= 2) {
+ y2 -= 1;
+ m2 += 12;
+ }
+ jd = (int)(floor(365.25 * (y2 + 4716)) +
+ floor(30.6001 * (m2 + 1)) +
+ d - 1524);
*ns = 0;
}
- else
+ else {
*ns = 1;
+ }
- *rjd = (int)jd;
+ *rjd = jd;
}
static void
c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom)
{
- double x, a, b, c, d, e, y, m, dom;
-
- if (jd < sg)
- a = jd;
- else {
- x = floor((jd - 1867216.25) / 36524.25);
- a = jd + 1 + x - floor(x / 4.0);
- }
- b = a + 1524;
- c = floor((b - 122.1) / 365.25);
- d = floor(365.25 * c);
- e = floor((b - d) / 30.6001);
- dom = b - d - floor(30.6001 * e);
- if (e <= 13) {
- m = e - 1;
- y = c - 4716;
- }
- else {
- m = e - 13;
- y = c - 4715;
+ /* Fast path: pure Gregorian or date after switchover, within safe range */
+ if ((c_gregorian_only_p(sg) || jd >= sg) && ns_jd_in_range(jd)) {
+ c_gregorian_jd_to_civil(jd, ry, rm, rdom);
+ return;
}
- *ry = (int)y;
- *rm = (int)m;
- *rdom = (int)dom;
+ /* Original algorithm for Julian calendar or extreme dates */
+ {
+ double x, a, b, c, d, e, y, m, dom;
+
+ if (jd < sg)
+ a = jd;
+ else {
+ x = floor((jd - 1867216.25) / 36524.25);
+ a = jd + 1 + x - floor(x / 4.0);
+ }
+ b = a + 1524;
+ c = floor((b - 122.1) / 365.25);
+ d = floor(365.25 * c);
+ e = floor((b - d) / 30.6001);
+ dom = b - d - floor(30.6001 * e);
+ if (e <= 13) {
+ m = e - 1;
+ y = c - 4716;
+ }
+ else {
+ m = e - 13;
+ y = c - 4715;
+ }
+
+ *ry = (int)y;
+ *rm = (int)m;
+ *rdom = (int)dom;
+ }
}
static void
@@ -725,6 +777,147 @@ c_gregorian_last_day_of_month(int y, int m)
return monthtab[c_gregorian_leap_p(y) ? 1 : 0][m];
}
+/*
+ * Neri-Schneider algorithm for optimized Gregorian date conversion.
+ * Reference: Neri & Schneider, "Euclidean Affine Functions and Applications
+ * to Calendar Algorithms", Software: Practice and Experience, 2023.
+ * https://arxiv.org/abs/2102.06959
+ *
+ * This algorithm provides ~2-3x speedup over traditional floating-point
+ * implementations by using pure integer arithmetic with multiplication
+ * and bit-shifts instead of expensive division operations.
+ */
+
+/* JDN of March 1, Year 0 in proleptic Gregorian calendar */
+#define NS_EPOCH 1721120
+
+/* Days in a 4-year cycle (3 normal years + 1 leap year) */
+#define NS_DAYS_IN_4_YEARS 1461
+
+/* Days in a 400-year Gregorian cycle (97 leap years in 400 years) */
+#define NS_DAYS_IN_400_YEARS 146097
+
+/* Years per century */
+#define NS_YEARS_PER_CENTURY 100
+
+/*
+ * Multiplier for extracting year within century using fixed-point arithmetic.
+ * This is ceil(2^32 / NS_DAYS_IN_4_YEARS) for the Euclidean affine function.
+ */
+#define NS_YEAR_MULTIPLIER 2939745
+
+/*
+ * Coefficients for month calculation from day-of-year.
+ * Maps day-of-year to month using: month = (NS_MONTH_COEFF * doy + NS_MONTH_OFFSET) >> 16
+ */
+#define NS_MONTH_COEFF 2141
+#define NS_MONTH_OFFSET 197913
+
+/*
+ * Coefficients for civil date to JDN month contribution.
+ * Maps month to accumulated days: days = (NS_CIVIL_MONTH_COEFF * m - NS_CIVIL_MONTH_OFFSET) / 32
+ */
+#define NS_CIVIL_MONTH_COEFF 979
+#define NS_CIVIL_MONTH_OFFSET 2919
+#define NS_CIVIL_MONTH_DIVISOR 32
+
+/* Days from March 1 to December 31 (for Jan/Feb year adjustment) */
+#define NS_DAYS_BEFORE_NEW_YEAR 306
+
+/*
+ * Safe bounds for Neri-Schneider algorithm to avoid integer overflow.
+ * These correspond to approximately years -1,000,000 to +1,000,000.
+ */
+#define NS_JD_MIN -364000000
+#define NS_JD_MAX 538000000
+
+inline static int
+ns_jd_in_range(int jd)
+{
+ return jd >= NS_JD_MIN && jd <= NS_JD_MAX;
+}
+
+/* Optimized: Gregorian date -> Julian Day Number */
+static int
+c_gregorian_civil_to_jd(int y, int m, int d)
+{
+ /* Shift epoch to March 1 of year 0 (Jan/Feb belong to previous year) */
+ int j = (m < 3) ? 1 : 0;
+ int y0 = y - j;
+ int m0 = j ? m + 12 : m;
+ int d0 = d - 1;
+
+ /* Calculate year contribution with leap year correction */
+ int q1 = DIV(y0, NS_YEARS_PER_CENTURY);
+ int yc = DIV(NS_DAYS_IN_4_YEARS * y0, 4) - q1 + DIV(q1, 4);
+
+ /* Calculate month contribution using integer arithmetic */
+ int mc = (NS_CIVIL_MONTH_COEFF * m0 - NS_CIVIL_MONTH_OFFSET) / NS_CIVIL_MONTH_DIVISOR;
+
+ /* Combine and add epoch offset to get JDN */
+ return yc + mc + d0 + NS_EPOCH;
+}
+
+/* Optimized: Julian Day Number -> Gregorian date */
+static void
+c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd)
+{
+ int r0, n1, q1, r1, n2, q2, r2, n3, q3, r3, y0, j;
+ uint64_t u2;
+
+ /* Convert JDN to rata die (March 1, Year 0 epoch) */
+ r0 = jd - NS_EPOCH;
+
+ /* Extract century and day within 400-year cycle */
+ /* Use Euclidean (floor) division for negative values */
+ n1 = 4 * r0 + 3;
+ q1 = DIV(n1, NS_DAYS_IN_400_YEARS);
+ r1 = MOD(n1, NS_DAYS_IN_400_YEARS) / 4;
+
+ /* Calculate year within century and day of year */
+ n2 = 4 * r1 + 3;
+ /* Use 64-bit arithmetic to avoid overflow */
+ u2 = (uint64_t)NS_YEAR_MULTIPLIER * (uint64_t)n2;
+ q2 = (int)(u2 >> 32);
+ r2 = (int)((uint32_t)u2 / NS_YEAR_MULTIPLIER / 4);
+
+ /* Calculate month and day using integer arithmetic */
+ n3 = NS_MONTH_COEFF * r2 + NS_MONTH_OFFSET;
+ q3 = n3 >> 16;
+ r3 = (n3 & 0xFFFF) / NS_MONTH_COEFF;
+
+ /* Combine century and year */
+ y0 = NS_YEARS_PER_CENTURY * q1 + q2;
+
+ /* Adjust for January/February (shift from fiscal year) */
+ j = (r2 >= NS_DAYS_BEFORE_NEW_YEAR) ? 1 : 0;
+
+ *ry = y0 + j;
+ *rm = j ? q3 - 12 : q3;
+ *rd = r3 + 1;
+}
+
+/* O(1) first day of year for Gregorian calendar */
+inline static int
+c_gregorian_fdoy(int y)
+{
+ return c_gregorian_civil_to_jd(y, 1, 1);
+}
+
+/* O(1) last day of year for Gregorian calendar */
+inline static int
+c_gregorian_ldoy(int y)
+{
+ return c_gregorian_civil_to_jd(y, 12, 31);
+}
+
+/* O(1) last day of month (JDN) for Gregorian calendar */
+inline static int
+c_gregorian_ldom_jd(int y, int m)
+{
+ return c_gregorian_civil_to_jd(y, m, c_gregorian_last_day_of_month(y, m));
+}
+
static int
c_valid_julian_p(int y, int m, int d, int *rm, int *rd)
{
@@ -1599,7 +1792,7 @@ m_ajd(union DateData *x)
if (simple_dat_p(x)) {
r = m_real_jd(x);
- if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2)) {
+ if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2) && FIX2LONG(r) >= (FIXNUM_MIN + 1) / 2) {
long ir = FIX2LONG(r);
ir = ir * 2 - 1;
return rb_rational_new2(LONG2FIX(ir), INT2FIX(2));
@@ -2498,7 +2691,7 @@ date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass)
*
* Date.valid_jd?(2451944) # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd.
*/
@@ -2592,7 +2785,7 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
* Date.valid_date?(2001, 2, 29) # => false
* Date.valid_date?(2001, 2, -1) # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new.
*/
@@ -2680,7 +2873,7 @@ date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
* Date.valid_ordinal?(2001, 34) # => true
* Date.valid_ordinal?(2001, 366) # => false
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.ordinal.
*/
@@ -2770,7 +2963,7 @@ date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass)
*
* See Date.commercial.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.commercial.
*/
@@ -3350,7 +3543,7 @@ static VALUE d_lite_plus(VALUE, VALUE);
*
* Date.jd(Date::ITALY - 1).julian? # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.new.
*/
@@ -3415,7 +3608,7 @@ date_s_jd(int argc, VALUE *argv, VALUE klass)
*
* Raises an exception if +yday+ is zero or out of range.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new.
*/
@@ -3492,7 +3685,7 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
* where +n+ is the number of days in the month;
* when the argument is negative, counts backward from the end of the month.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd.
*/
@@ -3598,7 +3791,7 @@ date_initialize(int argc, VALUE *argv, VALUE self)
* Date.commercial(2020, 1, 1).to_s # => "2019-12-30"
Date.commercial(2020, 1, 7).to_s # => "2020-01-05"
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new, Date.ordinal.
*/
@@ -3783,7 +3976,7 @@ static void set_sg(union DateData *, double);
*
* Date.today.to_s # => "2022-07-06"
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -3878,7 +4071,6 @@ static VALUE
rt_complete_frags(VALUE klass, VALUE hash)
{
static VALUE tab = Qnil;
- int g;
long e;
VALUE k, a, d;
@@ -3975,9 +4167,13 @@ rt_complete_frags(VALUE klass, VALUE hash)
rb_gc_register_mark_object(tab);
}
+ k = a = Qnil;
+
{
- long i, eno = 0, idx = 0;
+ long i, eno = 0;
+ VALUE t = Qnil;
+ e = 0;
for (i = 0; i < RARRAY_LEN(tab); i++) {
VALUE x, a;
@@ -3992,23 +4188,20 @@ rt_complete_frags(VALUE klass, VALUE hash)
n++;
if (n > eno) {
eno = n;
- idx = i;
+ t = x;
}
}
}
- if (eno == 0)
- g = 0;
- else {
- g = 1;
- k = RARRAY_AREF(RARRAY_AREF(tab, idx), 0);
- a = RARRAY_AREF(RARRAY_AREF(tab, idx), 1);
- e = eno;
+ if (eno > 0) {
+ k = RARRAY_AREF(t, 0);
+ a = RARRAY_AREF(t, 1);
}
+ e = eno;
}
d = Qnil;
- if (g && !NIL_P(k) && (RARRAY_LEN(a) - e)) {
+ if (!NIL_P(k) && (RARRAY_LEN(a) > e)) {
if (k == sym("ordinal")) {
if (NIL_P(ref_hash("year"))) {
if (NIL_P(d))
@@ -4095,7 +4288,7 @@ rt_complete_frags(VALUE klass, VALUE hash)
}
}
- if (g && k == sym("time")) {
+ if (k == sym("time")) {
if (f_le_p(klass, cDateTime)) {
if (NIL_P(d))
d = date_s_today(0, (VALUE *)0, cDate);
@@ -4335,6 +4528,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
rb_scan_args(argc, argv, "11", &vstr, &vfmt);
StringValue(vstr);
+ if (argc > 1) StringValue(vfmt);
if (!rb_enc_str_asciicompat_p(vstr))
rb_raise(rb_eArgError,
"string should have ASCII compatible encoding");
@@ -4345,7 +4539,6 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
flen = strlen(default_fmt);
}
else {
- StringValue(vfmt);
if (!rb_enc_str_asciicompat_p(vfmt))
rb_raise(rb_eArgError,
"format should have ASCII compatible encoding");
@@ -4383,7 +4576,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
* Date._strptime('2001-02-03', '%Y-%m-%d') # => {:year=>2001, :mon=>2, :mday=>3}
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
* (Unlike Date.strftime, does not support flags and width.)
*
* See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html].
@@ -4412,10 +4605,10 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass)
* Date.strptime('sat3feb01', '%a%d%b%y') # => #<Date: 2001-02-03>
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
* (Unlike Date.strftime, does not support flags and width.)
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html].
*
@@ -4464,11 +4657,10 @@ get_limit(VALUE opt)
#define rb_category_warn(category, fmt) rb_warn(fmt)
#endif
-static void
+static VALUE
check_limit(VALUE str, VALUE opt)
{
size_t slen, limit;
- if (NIL_P(str)) return;
StringValue(str);
slen = RSTRING_LEN(str);
limit = get_limit(opt);
@@ -4476,6 +4668,7 @@ check_limit(VALUE str, VALUE opt)
rb_raise(rb_eArgError,
"string length (%"PRI_SIZE_PREFIX"u) exceeds the limit %"PRI_SIZE_PREFIX"u", slen, limit);
}
+ return str;
}
static VALUE
@@ -4484,8 +4677,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
VALUE vstr, vcomp, hash, opt;
argc = rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt);
- check_limit(vstr, opt);
- StringValue(vstr);
+ vstr = check_limit(vstr, opt);
if (!rb_enc_str_asciicompat_p(vstr))
rb_raise(rb_eArgError,
"string should have ASCII compatible encoding");
@@ -4505,7 +4697,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
* This method recognizes many forms in +string+,
* but it is not a validator.
* For formats, see
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
*
* If +string+ does not specify a valid date,
* the result is unpredictable;
@@ -4540,7 +4732,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
* This method recognizes many forms in +string+,
* but it is not a validator.
* For formats, see
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
* If +string+ does not specify a valid date,
* the result is unpredictable;
* consider using Date._strptime instead.
@@ -4560,7 +4752,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._parse (returns a hash).
@@ -4604,7 +4796,7 @@ VALUE date__jisx0301(VALUE);
* Date._iso8601(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should contain
- * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
+ * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
*
* d = Date.new(2001, 2, 3)
* s = d.iso8601 # => "2001-02-03"
@@ -4620,7 +4812,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__iso8601(str);
}
@@ -4631,7 +4823,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should contain
- * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
+ * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
*
* d = Date.new(2001, 2, 3)
* s = d.iso8601 # => "2001-02-03"
@@ -4639,7 +4831,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._iso8601 (returns a hash).
@@ -4673,7 +4865,7 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass)
* Date._rfc3339(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]:
+ * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
@@ -4690,7 +4882,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__rfc3339(str);
}
@@ -4701,7 +4893,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]:
+ * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
@@ -4709,7 +4901,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._rfc3339 (returns a hash).
@@ -4759,7 +4951,7 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__xmlschema(str);
}
@@ -4777,7 +4969,7 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._xmlschema (returns a hash).
@@ -4811,7 +5003,7 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
* Date._rfc2822(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]:
+ * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
@@ -4828,7 +5020,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__rfc2822(str);
}
@@ -4839,7 +5031,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]:
+ * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
@@ -4847,7 +5039,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._rfc2822 (returns a hash).
@@ -4881,7 +5073,7 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
* Date._httpdate(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]:
+ * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
@@ -4896,7 +5088,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__httpdate(str);
}
@@ -4907,7 +5099,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]:
+ * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]:
*
* d = Date.new(2001, 2, 3)
s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
@@ -4915,7 +5107,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._httpdate (returns a hash).
@@ -4949,7 +5141,7 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass)
* Date._jisx0301(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {JIS X 0301 date format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]:
+ * {JIS X 0301 date format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.jisx0301 # => "H13.02.03"
@@ -4965,7 +5157,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__jisx0301(str);
}
@@ -4975,7 +5167,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
* Date.jisx0301(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date
*
* Returns a new \Date object with values parsed from +string+,
- * which should be a valid {JIS X 0301 format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]:
+ * which should be a valid {JIS X 0301 format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.jisx0301 # => "H13.02.03"
@@ -4987,7 +5179,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._jisx0301 (returns a hash).
@@ -5745,7 +5937,7 @@ d_lite_leap_p(VALUE self)
* Date.new(2001, 2, 3, Date::GREGORIAN).start # => -Infinity
* Date.new(2001, 2, 3, Date::JULIAN).start # => Infinity
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -5811,7 +6003,7 @@ dup_obj_with_new_start(VALUE obj, double sg)
/*
* call-seq:
- * new_start(start = Date::ITALY]) -> new_date
+ * new_start(start = Date::ITALY) -> new_date
*
* Returns a copy of +self+ with the given +start+ value:
*
@@ -5820,7 +6012,7 @@ dup_obj_with_new_start(VALUE obj, double sg)
* d1 = d0.new_start(Date::JULIAN)
* d1.julian? # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -6936,13 +7128,24 @@ d_lite_eql_p(VALUE self, VALUE other)
static VALUE
d_lite_hash(VALUE self)
{
- st_index_t v, h[4];
+ st_index_t v, h[5];
+ VALUE nth;
get_d1(self);
- h[0] = m_nth(dat);
- h[1] = m_jd(dat);
- h[2] = m_df(dat);
- h[3] = m_sf(dat);
+ nth = m_nth(dat);
+
+ if (FIXNUM_P(nth)) {
+ h[0] = 0;
+ h[1] = (st_index_t)nth;
+ } else {
+ h[0] = 1;
+ h[1] = (st_index_t)FIX2LONG(rb_hash(nth));
+ }
+
+ h[2] = m_jd(dat);
+ h[3] = m_df(dat);
+ h[4] = m_sf(dat);
+
v = rb_memhash(h, sizeof(h));
return ST2FIX(v);
}
@@ -6957,7 +7160,7 @@ static VALUE strftimev(const char *, VALUE,
* to_s -> string
*
* Returns a string representation of the date in +self+
- * in {ISO 8601 extended date format}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]
+ * in {ISO 8601 extended date format}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]
* (<tt>'%Y-%m-%d'</tt>):
*
* Date.new(2001, 2, 3).to_s # => "2001-02-03"
@@ -7238,7 +7441,7 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self,
* Date.new(2001, 2, 3).strftime # => "2001-02-03"
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
*
*/
static VALUE
@@ -7270,12 +7473,12 @@ strftimev(const char *fmt, VALUE self,
* asctime -> string
*
* Equivalent to #strftime with argument <tt>'%a %b %e %T %Y'</tt>
- * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
+ * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
* <tt>'%c'</tt>):
*
* Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001"
*
- * See {asctime}[https://linux.die.net/man/3/asctime].
+ * See {asctime}[https://man7.org/linux/man-pages/man3/asctime.3p.html].
*
*/
static VALUE
@@ -7289,7 +7492,7 @@ d_lite_asctime(VALUE self)
* iso8601 -> string
*
* Equivalent to #strftime with argument <tt>'%Y-%m-%d'</tt>
- * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
+ * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
* <tt>'%F'</tt>);
*
* Date.new(2001, 2, 3).iso8601 # => "2001-02-03"
@@ -7306,7 +7509,7 @@ d_lite_iso8601(VALUE self)
* rfc3339 -> string
*
* Equivalent to #strftime with argument <tt>'%FT%T%:z'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).rfc3339 # => "2001-02-03T00:00:00+00:00"
*
@@ -7322,7 +7525,7 @@ d_lite_rfc3339(VALUE self)
* rfc2822 -> string
*
* Equivalent to #strftime with argument <tt>'%a, %-d %b %Y %T %z'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
*
@@ -7338,7 +7541,7 @@ d_lite_rfc2822(VALUE self)
* httpdate -> string
*
* Equivalent to #strftime with argument <tt>'%a, %d %b %Y %T GMT'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
*
@@ -7517,10 +7720,7 @@ d_lite_marshal_dump_old(VALUE self)
m_of_in_day(dat),
DBL2NUM(m_sg(dat)));
- if (FL_TEST(self, FL_EXIVAR)) {
- rb_copy_generic_ivar(a, self);
- FL_SET(a, FL_EXIVAR);
- }
+ rb_copy_generic_ivar(a, self);
return a;
}
@@ -7542,10 +7742,8 @@ d_lite_marshal_dump(VALUE self)
INT2FIX(m_of(dat)),
DBL2NUM(m_sg(dat)));
- if (FL_TEST(self, FL_EXIVAR)) {
- rb_copy_generic_ivar(a, self);
- FL_SET(a, FL_EXIVAR);
- }
+
+ rb_copy_generic_ivar(a, self);
return a;
}
@@ -7618,10 +7816,7 @@ d_lite_marshal_load(VALUE self, VALUE a)
HAVE_JD | HAVE_DF);
}
- if (FL_TEST(a, FL_EXIVAR)) {
- rb_copy_generic_ivar(self, a);
- FL_SET(self, FL_EXIVAR);
- }
+ rb_copy_generic_ivar(self, a);
return self;
}
@@ -8715,7 +8910,7 @@ 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]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
*/
static VALUE
@@ -9494,6 +9689,7 @@ Init_date_core(void)
sym_zone = ID2SYM(rb_intern_const("zone"));
half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2));
+ rb_gc_register_mark_object(half_days_in_day);
#if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS *
@@ -9505,8 +9701,6 @@ Init_date_core(void)
day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS),
INT2FIX(SECOND_IN_NANOSECONDS));
#endif
-
- rb_gc_register_mark_object(half_days_in_day);
rb_gc_register_mark_object(day_in_nanoseconds);
positive_inf = +INFINITY;
@@ -9522,7 +9716,7 @@ Init_date_core(void)
*
* - You need both dates and times; \Date handles only dates.
* - You need only Gregorian dates (and not Julian dates);
- * see {Julian and Gregorian Calendars}[rdoc-ref:date/calendars.rdoc].
+ * see {Julian and Gregorian Calendars}[rdoc-ref:language/calendars.rdoc].
*
* A \Date object, once created, is immutable, and cannot be modified.
*
@@ -9569,7 +9763,7 @@ Init_date_core(void)
* Date.strptime('fri31dec99', '%a%d%b%y') # => #<Date: 1999-12-31>
*
* See also the specialized methods in
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
*
* == Argument +limit+
*
diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c
index f1c8201de8..1dde5fa3ec 100644
--- a/ext/date/date_strptime.c
+++ b/ext/date/date_strptime.c
@@ -661,6 +661,9 @@ date__strptime(const char *str, size_t slen,
si = date__strptime_internal(str, slen, fmt, flen, hash);
+ if (fail_p())
+ return Qnil;
+
if (slen > si) {
VALUE s;
@@ -668,9 +671,6 @@ date__strptime(const char *str, size_t slen,
set_hash("leftover", s);
}
- if (fail_p())
- return Qnil;
-
cent = del_hash("_cent");
if (!NIL_P(cent)) {
VALUE year;
diff --git a/ext/date/depend b/ext/date/depend
index d07f10a593..4fb78149a1 100644
--- a/ext/date/depend
+++ b/ext/date/depend
@@ -138,6 +138,7 @@ date_core.o: $(hdrdir)/ruby/internal/intern/re.h
date_core.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_core.o: $(hdrdir)/ruby/internal/intern/select.h
date_core.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_core.o: $(hdrdir)/ruby/internal/intern/set.h
date_core.o: $(hdrdir)/ruby/internal/intern/signal.h
date_core.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_core.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -313,6 +314,7 @@ date_parse.o: $(hdrdir)/ruby/internal/intern/re.h
date_parse.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_parse.o: $(hdrdir)/ruby/internal/intern/select.h
date_parse.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_parse.o: $(hdrdir)/ruby/internal/intern/set.h
date_parse.o: $(hdrdir)/ruby/internal/intern/signal.h
date_parse.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_parse.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -478,6 +480,7 @@ date_strftime.o: $(hdrdir)/ruby/internal/intern/re.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/select.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_strftime.o: $(hdrdir)/ruby/internal/intern/set.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/signal.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -650,6 +653,7 @@ date_strptime.o: $(hdrdir)/ruby/internal/intern/re.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/select.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_strptime.o: $(hdrdir)/ruby/internal/intern/set.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/signal.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb
index aa630eb6d1..0cb763017f 100644
--- a/ext/date/lib/date.rb
+++ b/ext/date/lib/date.rb
@@ -4,7 +4,7 @@
require 'date_core'
class Date
- VERSION = "3.4.1" # :nodoc:
+ VERSION = "3.5.1" # :nodoc:
# call-seq:
# infinite? -> false
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
index 0da9c223ee..02d88e960c 100644
--- a/ext/digest/bubblebabble/depend
+++ b/ext/digest/bubblebabble/depend
@@ -128,6 +128,7 @@ bubblebabble.o: $(hdrdir)/ruby/internal/intern/re.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/ruby.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/select.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bubblebabble.o: $(hdrdir)/ruby/internal/intern/set.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/signal.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/defs.h b/ext/digest/defs.h
index 77a134f364..9b11f4eca9 100644
--- a/ext/digest/defs.h
+++ b/ext/digest/defs.h
@@ -16,4 +16,26 @@
# define __END_DECLS
#endif
+#define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
+#ifdef RBIMPL_WARNING_IGNORED
+# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
+# define RB_DIGEST_WARNING_PUSH() RBIMPL_WARNING_PUSH()
+# define RB_DIGEST_WARNING_POP() RBIMPL_WARNING_POP()
+#elif defined(__clang__)
+# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
+# define RB_DIGEST_WARNING_PUSH() _Pragma("clang diagnostic push")
+# define RB_DIGEST_WARNING_POP() _Pragma("clang diagnostic pop")
+#else /* __GNUC__ */
+# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
+# define RB_DIGEST_WARNING_PUSH() _Pragma("GCC diagnostic push")
+# define RB_DIGEST_WARNING_POP() _Pragma("GCC diagnostic pop")
+#endif
+#ifdef RBIMPL_HAS_WARNING
+# define RB_DIGEST_HAS_WARNING(_) RBIMPL_HAS_WARNING(_)
+#elif defined(__has_warning)
+# define RB_DIGEST_HAS_WARNING(_) __has_warning(_)
+#else
+# define RB_DIGEST_HAS_WARNING(_) 0
+#endif
+
#endif /* DEFS_H */
diff --git a/ext/digest/depend b/ext/digest/depend
index cb9e8d4813..3eabb1d1d6 100644
--- a/ext/digest/depend
+++ b/ext/digest/depend
@@ -128,6 +128,7 @@ digest.o: $(hdrdir)/ruby/internal/intern/re.h
digest.o: $(hdrdir)/ruby/internal/intern/ruby.h
digest.o: $(hdrdir)/ruby/internal/intern/select.h
digest.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+digest.o: $(hdrdir)/ruby/internal/intern/set.h
digest.o: $(hdrdir)/ruby/internal/intern/signal.h
digest.o: $(hdrdir)/ruby/internal/intern/sprintf.h
digest.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index bd8d3e815f..28f6022754 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -571,7 +571,7 @@ static rb_digest_metadata_t *
get_digest_base_metadata(VALUE klass)
{
VALUE p;
- VALUE obj;
+ VALUE obj = Qnil;
rb_digest_metadata_t *algo;
for (p = klass; !NIL_P(p); p = rb_class_superclass(p)) {
diff --git a/ext/digest/digest_conf.rb b/ext/digest/digest_conf.rb
index 36a7d75289..099d20fcbe 100644
--- a/ext/digest/digest_conf.rb
+++ b/ext/digest/digest_conf.rb
@@ -2,14 +2,16 @@
def digest_conf(name)
unless with_config("bundled-#{name}")
- cc = with_config("common-digest")
- if cc != false or /\b#{name}\b/ =~ cc
- if File.exist?("#$srcdir/#{name}cc.h") and
- have_header("CommonCrypto/CommonDigest.h")
- $defs << "-D#{name.upcase}_USE_COMMONDIGEST"
- $headers << "#{name}cc.h"
- return :commondigest
- end
+ case cc = with_config("common-digest", true)
+ when true, false
+ else
+ cc = cc.split(/[\s,]++/).any? {|pat| File.fnmatch?(pat, name)}
+ end
+ if cc and File.exist?("#$srcdir/#{name}cc.h") and
+ have_header("CommonCrypto/CommonDigest.h")
+ $defs << "-D#{name.upcase}_USE_COMMONDIGEST"
+ $headers << "#{name}cc.h"
+ return :commondigest
end
end
$objs << "#{name}.#{$OBJEXT}"
diff --git a/ext/digest/lib/digest/version.rb b/ext/digest/lib/digest/version.rb
index 854106165c..a56e80c54e 100644
--- a/ext/digest/lib/digest/version.rb
+++ b/ext/digest/lib/digest/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module Digest
- VERSION = "3.2.0"
+ # The version string
+ VERSION = "3.2.1"
end
diff --git a/ext/digest/md5/depend b/ext/digest/md5/depend
index e71915e5b4..d1c25c28c8 100644
--- a/ext/digest/md5/depend
+++ b/ext/digest/md5/depend
@@ -131,6 +131,7 @@ md5.o: $(hdrdir)/ruby/internal/intern/re.h
md5.o: $(hdrdir)/ruby/internal/intern/ruby.h
md5.o: $(hdrdir)/ruby/internal/intern/select.h
md5.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+md5.o: $(hdrdir)/ruby/internal/intern/set.h
md5.o: $(hdrdir)/ruby/internal/intern/signal.h
md5.o: $(hdrdir)/ruby/internal/intern/sprintf.h
md5.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ md5init.o: $(hdrdir)/ruby/internal/intern/re.h
md5init.o: $(hdrdir)/ruby/internal/intern/ruby.h
md5init.o: $(hdrdir)/ruby/internal/intern/select.h
md5init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+md5init.o: $(hdrdir)/ruby/internal/intern/set.h
md5init.o: $(hdrdir)/ruby/internal/intern/signal.h
md5init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
md5init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/md5/md5cc.h b/ext/digest/md5/md5cc.h
index 657f573f85..a002c17604 100644
--- a/ext/digest/md5/md5cc.h
+++ b/ext/digest/md5/md5cc.h
@@ -2,14 +2,6 @@
#include <CommonCrypto/CommonDigest.h>
#ifdef __GNUC__
-# define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
-# ifdef RBIMPL_WARNING_IGNORED
-# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
-# elif defined(__clang__)
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
-# else /* __GNUC__ */
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
-# endif
RB_DIGEST_WARNING_IGNORED(-Wdeprecated-declarations)
/* Suppress deprecation warnings of MD5 from Xcode 11.1 */
/* Although we know MD5 is deprecated too, provide just for backward
diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c
index b81fd94864..c919060587 100644
--- a/ext/digest/md5/md5init.c
+++ b/ext/digest/md5/md5init.c
@@ -3,6 +3,7 @@
#include <ruby/ruby.h>
#include "../digest.h"
+#include "../defs.h"
#if defined(MD5_USE_COMMONDIGEST)
#include "md5cc.h"
#else
diff --git a/ext/digest/rmd160/depend b/ext/digest/rmd160/depend
index 09558ad92b..aec484f7b3 100644
--- a/ext/digest/rmd160/depend
+++ b/ext/digest/rmd160/depend
@@ -131,6 +131,7 @@ rmd160.o: $(hdrdir)/ruby/internal/intern/re.h
rmd160.o: $(hdrdir)/ruby/internal/intern/ruby.h
rmd160.o: $(hdrdir)/ruby/internal/intern/select.h
rmd160.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rmd160.o: $(hdrdir)/ruby/internal/intern/set.h
rmd160.o: $(hdrdir)/ruby/internal/intern/signal.h
rmd160.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rmd160.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ rmd160init.o: $(hdrdir)/ruby/internal/intern/re.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/ruby.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/select.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rmd160init.o: $(hdrdir)/ruby/internal/intern/set.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/signal.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/sha1/depend b/ext/digest/sha1/depend
index 827b8a0852..e6bd9d8f73 100644
--- a/ext/digest/sha1/depend
+++ b/ext/digest/sha1/depend
@@ -131,6 +131,7 @@ sha1.o: $(hdrdir)/ruby/internal/intern/re.h
sha1.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha1.o: $(hdrdir)/ruby/internal/intern/select.h
sha1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha1.o: $(hdrdir)/ruby/internal/intern/set.h
sha1.o: $(hdrdir)/ruby/internal/intern/signal.h
sha1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha1.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ sha1init.o: $(hdrdir)/ruby/internal/intern/re.h
sha1init.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha1init.o: $(hdrdir)/ruby/internal/intern/select.h
sha1init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha1init.o: $(hdrdir)/ruby/internal/intern/set.h
sha1init.o: $(hdrdir)/ruby/internal/intern/signal.h
sha1init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha1init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c
index 5311227549..003c87d224 100644
--- a/ext/digest/sha1/sha1.c
+++ b/ext/digest/sha1/sha1.c
@@ -220,20 +220,28 @@ int SHA1_Init(SHA1_CTX *context)
*/
void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len)
{
- uint32_t i, j;
+ size_t i;
+ uint32_t j;
_DIAGASSERT(context != 0);
_DIAGASSERT(data != 0);
j = context->count[0];
if ((context->count[0] += len << 3) < j)
- context->count[1] += (len>>29)+1;
+ context->count[1]++;
+ context->count[1] += (uint32_t)(len >> 29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
(void)memcpy(&context->buffer[j], data, (i = 64-j));
SHA1_Transform(context->state, context->buffer);
- for ( ; i + 63 < len; i += 64)
+ for ( ; i + 63 < len; i += 64) {
+ RB_DIGEST_WARNING_PUSH();
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11
+ RB_DIGEST_WARNING_IGNORED(-Wstringop-overread);
+#endif
SHA1_Transform(context->state, &data[i]);
+ RB_DIGEST_WARNING_POP();
+ }
j = 0;
} else {
i = 0;
diff --git a/ext/digest/sha2/depend b/ext/digest/sha2/depend
index af1600d346..2b74776b3e 100644
--- a/ext/digest/sha2/depend
+++ b/ext/digest/sha2/depend
@@ -131,6 +131,7 @@ sha2.o: $(hdrdir)/ruby/internal/intern/re.h
sha2.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha2.o: $(hdrdir)/ruby/internal/intern/select.h
sha2.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha2.o: $(hdrdir)/ruby/internal/intern/set.h
sha2.o: $(hdrdir)/ruby/internal/intern/signal.h
sha2.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha2.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ sha2init.o: $(hdrdir)/ruby/internal/intern/re.h
sha2init.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha2init.o: $(hdrdir)/ruby/internal/intern/select.h
sha2init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha2init.o: $(hdrdir)/ruby/internal/intern/set.h
sha2init.o: $(hdrdir)/ruby/internal/intern/signal.h
sha2init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha2init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/erb/escape/escape.c b/ext/erb/escape/escape.c
index 67b2d1ef34..1794fc30eb 100644
--- a/ext/erb/escape/escape.c
+++ b/ext/erb/escape/escape.c
@@ -39,35 +39,50 @@ static VALUE
optimized_escape_html(VALUE str)
{
VALUE vbuf;
- char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ char *buf = NULL;
const char *cstr = RSTRING_PTR(str);
const char *end = cstr + RSTRING_LEN(str);
- char *dest = buf;
+ const char *segment_start = cstr;
+ char *dest = NULL;
while (cstr < end) {
const unsigned char c = *cstr++;
uint8_t len = html_escape_table[c].len;
if (len) {
+ size_t segment_len = cstr - segment_start - 1;
+ if (!buf) {
+ buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ dest = buf;
+ }
+ if (segment_len) {
+ memcpy(dest, segment_start, segment_len);
+ dest += segment_len;
+ }
+ segment_start = cstr;
memcpy(dest, html_escape_table[c].str, len);
dest += len;
}
- else {
- *dest++ = c;
- }
}
-
VALUE escaped = str;
- if (RSTRING_LEN(str) < (dest - buf)) {
+ if (buf) {
+ size_t segment_len = cstr - segment_start;
+ if (segment_len) {
+ memcpy(dest, segment_start, segment_len);
+ dest += segment_len;
+ }
escaped = rb_str_new(buf, dest - buf);
preserve_original_state(str, escaped);
+ ALLOCV_END(vbuf);
}
- ALLOCV_END(vbuf);
return escaped;
}
-// ERB::Util.html_escape is different from CGI.escapeHTML in the following two parts:
-// * ERB::Util.html_escape converts an argument with #to_s first (only if it's not T_STRING)
-// * ERB::Util.html_escape does not allocate a new string when nothing needs to be escaped
+/*
+ * ERB::Util.html_escape is similar to CGI.escapeHTML but different in the following two parts:
+ *
+ * * ERB::Util.html_escape converts an argument with #to_s first (only if it's not T_STRING)
+ * * ERB::Util.html_escape does not allocate a new string when nothing needs to be escaped
+ */
static VALUE
erb_escape_html(VALUE self, VALUE str)
{
@@ -86,6 +101,10 @@ erb_escape_html(VALUE self, VALUE str)
void
Init_escape(void)
{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
rb_cERB = rb_define_class("ERB", rb_cObject);
rb_mEscape = rb_define_module_under(rb_cERB, "Escape");
rb_define_module_function(rb_mEscape, "html_escape", erb_escape_html, 1);
diff --git a/ext/erb/escape/extconf.rb b/ext/erb/escape/extconf.rb
index 783e8c1f55..b211a9783f 100644
--- a/ext/erb/escape/extconf.rb
+++ b/ext/erb/escape/extconf.rb
@@ -4,5 +4,6 @@ case RUBY_ENGINE
when 'jruby', 'truffleruby'
File.write('Makefile', dummy_makefile($srcdir).join)
else
+ have_func("rb_ext_ractor_safe", "ruby.h")
create_makefile 'erb/escape'
end
diff --git a/ext/etc/depend b/ext/etc/depend
index 675699b129..77fe56a6bf 100644
--- a/ext/etc/depend
+++ b/ext/etc/depend
@@ -143,6 +143,7 @@ etc.o: $(hdrdir)/ruby/internal/intern/re.h
etc.o: $(hdrdir)/ruby/internal/intern/ruby.h
etc.o: $(hdrdir)/ruby/internal/intern/select.h
etc.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+etc.o: $(hdrdir)/ruby/internal/intern/set.h
etc.o: $(hdrdir)/ruby/internal/intern/signal.h
etc.o: $(hdrdir)/ruby/internal/intern/sprintf.h
etc.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 157c6772ec..8d50a96a62 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -56,7 +56,7 @@ static VALUE sGroup;
#endif
RUBY_EXTERN char *getlogin(void);
-#define RUBY_ETC_VERSION "1.4.5"
+#define RUBY_ETC_VERSION "1.4.6"
#define SYMBOL_LIT(str) ID2SYM(rb_intern_const(str ""))
@@ -832,11 +832,7 @@ etc_uname(VALUE obj)
rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding()));
rb_hash_aset(result, SYMBOL_LIT("version"), version);
-# if defined _MSC_VER && _MSC_VER < 1300
-# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen)
-# else
# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen)
-# endif
GET_COMPUTER_NAME(NULL, &len);
buf = ALLOCV_N(WCHAR, vbuf, len);
if (GET_COMPUTER_NAME(buf, &len)) {
@@ -1311,4 +1307,8 @@ Init_etc(void)
rb_extend_object(sGroup, rb_mEnumerable);
rb_define_singleton_method(sGroup, "each", etc_each_group, 0);
#endif
+
+#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
+ (void)safe_setup_str;
+#endif
}
diff --git a/ext/etc/etc.gemspec b/ext/etc/etc.gemspec
index 3facc74866..0e9803dc62 100644
--- a/ext/etc/etc.gemspec
+++ b/ext/etc/etc.gemspec
@@ -40,5 +40,5 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.extensions = %w{ext/etc/extconf.rb}
- spec.required_ruby_version = ">= 2.6.0"
+ spec.required_ruby_version = ">= 2.7.0"
end
diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb
index 2e28d58037..497303a4fa 100644
--- a/ext/etc/extconf.rb
+++ b/ext/etc/extconf.rb
@@ -10,8 +10,30 @@ headers = []
have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4
have_func("uname((struct utsname *)NULL)", headers)
have_func("getlogin")
-have_func("getpwent")
-have_func("getgrent")
+if have_func("getpwent")
+ have_struct_member('struct passwd', 'pw_gecos', 'pwd.h')
+ have_struct_member('struct passwd', 'pw_change', 'pwd.h')
+ have_struct_member('struct passwd', 'pw_quota', 'pwd.h')
+ if have_struct_member('struct passwd', 'pw_age', 'pwd.h')
+ case what_type?('struct passwd', 'pw_age', 'pwd.h')
+ when "string"
+ f = "safe_setup_str"
+ when "long long"
+ f = "LL2NUM"
+ else
+ f = "INT2NUM"
+ end
+ $defs.push("-DPW_AGE2VAL="+f)
+ end
+ have_struct_member('struct passwd', 'pw_class', 'pwd.h')
+ have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM
+ have_struct_member('struct passwd', 'pw_expire', 'pwd.h')
+ have_struct_member('struct passwd', 'pw_passwd', 'pwd.h')
+end
+if have_func("getgrent")
+ have_struct_member('struct group', 'gr_passwd', 'grp.h')
+end
+
if (sysconfdir = RbConfig::CONFIG["sysconfdir"] and
!RbConfig.expand(sysconfdir.dup, "prefix"=>"", "DESTDIR"=>"").empty?)
$defs.push("-DSYSCONFDIR=#{Shellwords.escape(sysconfdir.dump)}")
@@ -21,26 +43,6 @@ have_func("sysconf")
have_func("confstr")
have_func("fpathconf")
-have_struct_member('struct passwd', 'pw_gecos', 'pwd.h')
-have_struct_member('struct passwd', 'pw_change', 'pwd.h')
-have_struct_member('struct passwd', 'pw_quota', 'pwd.h')
-if have_struct_member('struct passwd', 'pw_age', 'pwd.h')
- case what_type?('struct passwd', 'pw_age', 'pwd.h')
- when "string"
- f = "safe_setup_str"
- when "long long"
- f = "LL2NUM"
- else
- f = "INT2NUM"
- end
- $defs.push("-DPW_AGE2VAL="+f)
-end
-have_struct_member('struct passwd', 'pw_class', 'pwd.h')
-have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM
-have_struct_member('struct passwd', 'pw_expire', 'pwd.h')
-have_struct_member('struct passwd', 'pw_passwd', 'pwd.h')
-have_struct_member('struct group', 'gr_passwd', 'grp.h')
-
# for https://github.com/ruby/etc
srcdir = File.expand_path("..", __FILE__)
constdefs = "#{srcdir}/constdefs.h"
@@ -58,7 +60,7 @@ 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")
+have_func("rb_io_descriptor", "ruby/io.h")
$distcleanfiles << "constdefs.h"
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 39cbce1bc9..f5244f72c8 100755
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -8,8 +8,6 @@ module Gem
RbConfig::CONFIG
end
end
-# only needs Gem::Platform
-require 'rubygems/platform'
# :stopdoc:
$extension = nil
@@ -36,13 +34,16 @@ DUMMY_SIGNATURE = "***DUMMY MAKEFILE***"
srcdir = File.dirname(File.dirname(__FILE__))
unless defined?(CROSS_COMPILING) and CROSS_COMPILING
- $:.replace([File.expand_path("lib", srcdir), Dir.pwd])
+ $:.replace([Dir.pwd, File.expand_path("lib", srcdir)])
end
-$:.unshift(srcdir)
require 'rbconfig'
+# only needs Gem::Platform
+require 'rubygems/platform'
+
$topdir = "."
$top_srcdir = srcdir
+$extmk = true
inplace = File.identical?($top_srcdir, $topdir)
$" << "mkmf.rb"
@@ -138,14 +139,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
@@ -566,6 +559,7 @@ extend Module.new {
if $static and (target = args.first).include?("/")
base = File.basename(target)
$defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
+ $defs << "-DInitVM_#{base}=InitVM_#{target.tr('/', '_')}"
end
return super
end
@@ -598,6 +592,7 @@ gem = #{@gemname}
build_complete = $(TARGET_GEM_DIR)/gem.build_complete
install-so: build_complete
clean-so:: clean-build_complete
+$(build_complete) $(OBJS): $(TARGET_SO_DIR_TIMESTAMP)
build_complete: $(build_complete)
$(build_complete): $(TARGET_SO)
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
index 5ed652563b..57ea0f2106 100644
--- a/ext/fcntl/depend
+++ b/ext/fcntl/depend
@@ -128,6 +128,7 @@ fcntl.o: $(hdrdir)/ruby/internal/intern/re.h
fcntl.o: $(hdrdir)/ruby/internal/intern/ruby.h
fcntl.o: $(hdrdir)/ruby/internal/intern/select.h
fcntl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+fcntl.o: $(hdrdir)/ruby/internal/intern/set.h
fcntl.o: $(hdrdir)/ruby/internal/intern/signal.h
fcntl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
fcntl.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index 86bee5fb45..b987e237dd 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -65,7 +65,7 @@ pack up your own arguments to pass as args for locking functions, etc.
*
*/
-#define FCNTL_VERSION "1.2.0"
+#define FCNTL_VERSION "1.3.0"
void
Init_fcntl(void)
@@ -251,4 +251,50 @@ Init_fcntl(void)
*/
rb_define_const(mFcntl, "F_DUP2FD_CLOEXEC", INT2NUM(F_DUP2FD_CLOEXEC));
#endif
+
+#ifdef F_PREALLOCATE
+ /*
+ * macOS specific flag used for preallocating file space.
+ */
+ rb_define_const(mFcntl, "F_PREALLOCATE", INT2NUM(F_PREALLOCATE));
+#endif
+
+#ifdef F_ALLOCATECONTIG
+ /*
+ * macOS specific flag used with F_PREALLOCATE for allocating contiguous
+ * space.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATECONTIG", INT2NUM(F_ALLOCATECONTIG));
+#endif
+
+#ifdef F_ALLOCATEALL
+ /*
+ * macOS specific flag used with F_PREALLOCATE for allocating all contiguous
+ * space or no space.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATEALL", INT2NUM(F_ALLOCATEALL));
+#endif
+
+#ifdef F_ALLOCATEPERSIST
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate space that is not
+ * freed when close is called.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATEPERSIST", INT2NUM(F_ALLOCATEPERSIST));
+#endif
+
+#ifdef F_PEOFPOSMODE
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate from the physical
+ * end of file
+ */
+ rb_define_const(mFcntl, "F_PEOFPOSMODE", INT2NUM(F_PEOFPOSMODE));
+#endif
+
+#ifdef F_VOLPOSMODE
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate from the volume offset.
+ */
+ rb_define_const(mFcntl, "F_VOLPOSMODE", INT2NUM(F_VOLPOSMODE));
+#endif
}
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 80c1cddd5a..5f3c9478f7 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -4,7 +4,7 @@
*/
static const char *const
-IO_CONSOLE_VERSION = "0.8.0";
+IO_CONSOLE_VERSION = "0.8.2";
#include "ruby.h"
#include "ruby/io.h"
@@ -840,6 +840,9 @@ console_winsize(VALUE io)
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}
+static VALUE console_scroll(VALUE io, int line);
+static VALUE console_goto(VALUE io, VALUE y, VALUE x);
+
/*
* call-seq:
* io.winsize = [rows, columns]
@@ -856,7 +859,8 @@ console_set_winsize(VALUE io, VALUE size)
#if defined _WIN32
HANDLE wh;
int newrow, newcol;
- BOOL ret;
+ COORD oldsize;
+ SMALL_RECT oldwindow;
#endif
VALUE row, col, xpixel, ypixel;
const VALUE *sz;
@@ -891,18 +895,62 @@ console_set_winsize(VALUE io, VALUE size)
if (!GetConsoleScreenBufferInfo(wh, &ws)) {
rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
}
+ oldsize = ws.dwSize;
+ oldwindow = ws.srWindow;
+ if (ws.srWindow.Right + 1 < newcol) {
+ ws.dwSize.X = newcol;
+ }
+ if (ws.dwSize.Y < newrow) {
+ ws.dwSize.Y = newrow;
+ }
+ /* expand screen buffer first if needed */
+ if (!SetConsoleScreenBufferSize(wh, ws.dwSize)) {
+ rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
+ }
+ /* refresh ws for new dwMaximumWindowSize */
+ if (!GetConsoleScreenBufferInfo(wh, &ws)) {
+ rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
+ }
+ /* check new size before modifying buffer content */
+ if (newrow <= 0 || newcol <= 0 ||
+ newrow > ws.dwMaximumWindowSize.Y ||
+ newcol > ws.dwMaximumWindowSize.X) {
+ SetConsoleScreenBufferSize(wh, oldsize);
+ /* remove scrollbar if possible */
+ SetConsoleWindowInfo(wh, TRUE, &oldwindow);
+ rb_raise(rb_eArgError, "out of range winsize: [%d, %d]", newrow, newcol);
+ }
+ /* shrink screen buffer width */
ws.dwSize.X = newcol;
- ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
+ /* shrink screen buffer height if window height were the same */
+ if (oldsize.Y == ws.srWindow.Bottom - ws.srWindow.Top + 1) {
+ ws.dwSize.Y = newrow;
+ }
ws.srWindow.Left = 0;
- ws.srWindow.Top = 0;
- ws.srWindow.Right = newcol-1;
- ws.srWindow.Bottom = newrow-1;
+ ws.srWindow.Right = newcol - 1;
+ ws.srWindow.Bottom = ws.srWindow.Top + newrow -1;
+ if (ws.dwCursorPosition.Y > ws.srWindow.Bottom) {
+ console_scroll(io, ws.dwCursorPosition.Y - ws.srWindow.Bottom);
+ ws.dwCursorPosition.Y = ws.srWindow.Bottom;
+ console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X));
+ }
+ if (ws.srWindow.Bottom > ws.dwSize.Y - 1) {
+ console_scroll(io, ws.srWindow.Bottom - (ws.dwSize.Y - 1));
+ ws.dwCursorPosition.Y -= ws.srWindow.Bottom - (ws.dwSize.Y - 1);
+ console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X));
+ ws.srWindow.Bottom = ws.dwSize.Y - 1;
+ }
+ ws.srWindow.Top = ws.srWindow.Bottom - (newrow - 1);
+ /* perform changes to winsize */
if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
- rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
+ int last_error = LAST_ERROR;
+ SetConsoleScreenBufferSize(wh, oldsize);
+ rb_syserr_fail(last_error, "SetConsoleWindowInfo");
}
- /* retry when shrinking buffer after shrunk window */
- if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
- rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
+ /* perform screen buffer shrinking if necessary */
+ if ((ws.dwSize.Y < oldsize.Y || ws.dwSize.X < oldsize.X) &&
+ !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
+ rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
}
/* remove scrollbar if possible */
if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
@@ -1221,7 +1269,7 @@ console_cursor_pos(VALUE 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));
+ return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y - ws.srWindow.Top), UINT2NUM(ws.dwCursorPosition.X));
#else
static const struct query_args query = {"\033[6n", 0};
VALUE resp = console_vt_response(0, 0, io, &query);
@@ -1254,11 +1302,17 @@ 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)) {
+ 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 = NUM2UINT(x);
+ pos->Y = ws.srWindow.Top + NUM2UINT(y);
+ if (!SetConsoleCursorPosition(h, *pos)) {
rb_syserr_fail(LAST_ERROR, 0);
}
#else
@@ -1651,13 +1705,11 @@ console_dev(int argc, VALUE *argv, VALUE klass)
VALUE con = 0;
VALUE sym = 0;
- rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
-
if (argc) {
Check_Type(sym = argv[0], T_SYMBOL);
}
- // Force the class to be File.
+ /* Force the class to be File. */
if (klass == rb_cIO) klass = rb_cFile;
if (console_dev_get(klass, &con)) {
@@ -1948,14 +2000,13 @@ InitVM_console(void)
rb_define_method(rb_cIO, "ttyname", console_ttyname, 0);
rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
{
- /* :stopdoc: */
+ /* :nodoc: */
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
- /* :startdoc: */
rb_define_method(mReadable, "getch", io_getch, -1);
rb_define_method(mReadable, "getpass", io_getpass, -1);
}
{
- /* :stopdoc: */
+ /* :nodoc: */
cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
rb_define_const(cConmode, "VERSION", rb_obj_freeze(rb_str_new_cstr(IO_CONSOLE_VERSION)));
rb_define_alloc_func(cConmode, conmode_alloc);
@@ -1964,6 +2015,5 @@ InitVM_console(void)
rb_define_method(cConmode, "echo=", conmode_set_echo, 1);
rb_define_method(cConmode, "raw!", conmode_set_raw, -1);
rb_define_method(cConmode, "raw", conmode_raw_new, -1);
- /* :startdoc: */
}
}
diff --git a/ext/io/console/depend b/ext/io/console/depend
index e66b6f4f5d..150a138d4d 100644
--- a/ext/io/console/depend
+++ b/ext/io/console/depend
@@ -139,6 +139,7 @@ console.o: $(hdrdir)/ruby/internal/intern/re.h
console.o: $(hdrdir)/ruby/internal/intern/ruby.h
console.o: $(hdrdir)/ruby/internal/intern/select.h
console.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+console.o: $(hdrdir)/ruby/internal/intern/set.h
console.o: $(hdrdir)/ruby/internal/intern/signal.h
console.o: $(hdrdir)/ruby/internal/intern/sprintf.h
console.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb
index 4ad7ed6996..dd3d221ae5 100644
--- a/ext/io/console/extconf.rb
+++ b/ext/io/console/extconf.rb
@@ -10,11 +10,11 @@ have_func("rb_syserr_new_str(0, Qnil)") or
abort
have_func("rb_interned_str_cstr")
-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")
+have_func("rb_io_path", "ruby/io.h")
+have_func("rb_io_descriptor", "ruby/io.h")
+have_func("rb_io_get_write_io", "ruby/io.h")
+have_func("rb_io_closed_p", "ruby/io.h")
+have_func("rb_io_open_descriptor", "ruby/io.h")
have_func("rb_ractor_local_storage_value_newkey")
is_wasi = /wasi/ =~ MakeMakefile::RbConfig::CONFIG["platform"]
diff --git a/ext/io/nonblock/depend b/ext/io/nonblock/depend
index 20a96f1252..e78a05c316 100644
--- a/ext/io/nonblock/depend
+++ b/ext/io/nonblock/depend
@@ -138,6 +138,7 @@ nonblock.o: $(hdrdir)/ruby/internal/intern/re.h
nonblock.o: $(hdrdir)/ruby/internal/intern/ruby.h
nonblock.o: $(hdrdir)/ruby/internal/intern/select.h
nonblock.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nonblock.o: $(hdrdir)/ruby/internal/intern/set.h
nonblock.o: $(hdrdir)/ruby/internal/intern/signal.h
nonblock.o: $(hdrdir)/ruby/internal/intern/sprintf.h
nonblock.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/io/nonblock/extconf.rb b/ext/io/nonblock/extconf.rb
index a1e6075c9b..505c9e6252 100644
--- a/ext/io/nonblock/extconf.rb
+++ b/ext/io/nonblock/extconf.rb
@@ -7,7 +7,7 @@ unless RUBY_ENGINE == 'ruby'
return
end
-have_func("rb_io_descriptor")
+have_func("rb_io_descriptor", "ruby/io.h")
hdr = %w"fcntl.h"
if have_macro("O_NONBLOCK", hdr) and
diff --git a/ext/io/nonblock/io-nonblock.gemspec b/ext/io/nonblock/io-nonblock.gemspec
index 2df8b8e3a6..4f5b8cef6f 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.1"
+ spec.version = "0.3.2"
spec.authors = ["Nobu Nakada"]
spec.email = ["nobu@ruby-lang.org"]
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
spec.description = %q{Enables non-blocking mode with IO class}
spec.homepage = "https://github.com/ruby/io-nonblock"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
diff --git a/ext/io/wait/depend b/ext/io/wait/depend
index 70317b1497..41d53c1400 100644
--- a/ext/io/wait/depend
+++ b/ext/io/wait/depend
@@ -1,5 +1,4 @@
# AUTOGENERATED DEPENDENCIES START
-# wait.o: $(hdrdir)/ruby/assert.h # not in 2.6
wait.o: $(RUBY_EXTCONF_H)
wait.o: $(arch_hdrdir)/ruby/config.h
wait.o: $(hdrdir)/ruby.h
@@ -139,6 +138,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/re.h
wait.o: $(hdrdir)/ruby/internal/intern/ruby.h
wait.o: $(hdrdir)/ruby/internal/intern/select.h
wait.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+wait.o: $(hdrdir)/ruby/internal/intern/set.h
wait.o: $(hdrdir)/ruby/internal/intern/signal.h
wait.o: $(hdrdir)/ruby/internal/intern/sprintf.h
wait.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb
index e63c046187..00c455a45c 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -1,25 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
-if RUBY_VERSION < "2.6"
- File.write("Makefile", dummy_makefile($srcdir).join(""))
-else
- target = "io/wait"
- have_func("rb_io_wait")
- have_func("rb_io_descriptor")
- 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|
- have_macro("FIONREAD", [h, ioctl_h].compact)
- end
- if fionread
- $defs << "-DFIONREAD_HEADER=\"<#{fionread}>\""
- create_makefile(target)
- end
- else
- if have_func("rb_w32_ioctlsocket", "ruby.h")
- have_func("rb_w32_is_socket", "ruby.h")
- create_makefile(target)
- end
- end
-end
+create_makefile("io/wait")
diff --git a/ext/io/wait/io-wait.gemspec b/ext/io/wait/io-wait.gemspec
index e850e10bf9..c1c6172589 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.4.0"
Gem::Specification.new do |spec|
spec.name = "io-wait"
@@ -10,24 +10,25 @@ Gem::Specification.new do |spec|
spec.description = %q{Waits until IO is readable or writable without blocking.}
spec.homepage = "https://github.com/ruby/io-wait"
spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2")
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`.split("\x0").reject do |f|
- File.identical?(f, __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
- end
- end
+ jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby'
+ dir, gemspec = File.split(__FILE__)
+ excludes = [
+ *%w[:^/.git* :^/Gemfile* :^/Rakefile* :^/bin/ :^/test/ :^/rakelib/ :^*.java],
+ *(jruby ? %w[:^/ext/io] : %w[:^/ext/java]),
+ ":(exclude,literal,top)#{gemspec}"
+ ]
+ files = IO.popen(%w[git ls-files -z --] + excludes, chdir: dir, &:read).split("\x0")
+
+ spec.files = files
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
- jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby'
- spec.files.delete_if do |f|
- f.end_with?(".java") or
- f.start_with?("ext/") && (jruby ^ f.start_with?("ext/java/"))
- end
if jruby
spec.platform = 'java'
spec.files << "lib/io/wait.jar"
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 8835670e59..f7575191fe 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -11,427 +11,13 @@
**********************************************************************/
-#include "ruby.h"
-#include "ruby/io.h"
-
-#include <sys/types.h>
-#if defined(HAVE_UNISTD_H) && (defined(__sun))
-#include <unistd.h>
-#endif
-#if defined(HAVE_SYS_IOCTL_H)
-#include <sys/ioctl.h>
-#endif
-#if defined(FIONREAD_HEADER)
-#include FIONREAD_HEADER
-#endif
-
-#ifdef HAVE_RB_W32_IOCTLSOCKET
-#define ioctl ioctlsocket
-#define ioctl_arg u_long
-#define ioctl_arg2num(i) ULONG2NUM(i)
-#else
-#define ioctl_arg int
-#define ioctl_arg2num(i) INT2NUM(i)
-#endif
-
-#ifdef HAVE_RB_W32_IS_SOCKET
-#define FIONREAD_POSSIBLE_P(fd) rb_w32_is_socket(fd)
-#else
-#define FIONREAD_POSSIBLE_P(fd) ((void)(fd),Qtrue)
-#endif
-
-#ifndef HAVE_RB_IO_WAIT
-static struct timeval *
-get_timeout(int argc, VALUE *argv, struct timeval *timerec)
-{
- VALUE timeout = Qnil;
- rb_check_arity(argc, 0, 1);
- if (!argc || NIL_P(timeout = argv[0])) {
- return NULL;
- }
- else {
- *timerec = rb_time_interval(timeout);
- return timerec;
- }
-}
-
-static int
-wait_for_single_fd(rb_io_t *fptr, int events, struct timeval *tv)
-{
- int i = rb_wait_for_single_fd(fptr->fd, events, tv);
- if (i < 0)
- rb_sys_fail(0);
- rb_io_check_closed(fptr);
- return (i & events);
-}
-#endif
-
-/*
- * call-seq:
- * io.nread -> int
- *
- * Returns number of bytes that can be read without blocking.
- * Returns zero if no information available.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_nread(VALUE io)
-{
- rb_io_t *fptr;
- int len;
- ioctl_arg n;
-
- GetOpenFile(io, fptr);
- 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 (n > 0) return ioctl_arg2num(n);
- return INT2FIX(0);
-}
-
-#ifdef HAVE_RB_IO_WAIT
-static VALUE
-io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
-{
- VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
-
- if (!RB_TEST(result)) {
- return Qnil;
- }
-
- int mask = RB_NUM2INT(result);
-
- if (mask & event) {
- if (return_io)
- return io;
- else
- return result;
- }
- else {
- return Qfalse;
- }
-}
-#endif
-
-/*
- * call-seq:
- * io.ready? -> truthy or falsy
- *
- * Returns a truthy value if input available without blocking, or a
- * falsy value.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_ready_p(VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval tv = {0, 0};
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
- if (rb_io_read_pending(fptr)) return Qtrue;
-
-#ifndef HAVE_RB_IO_WAIT
- return wait_for_single_fd(fptr, RB_WAITFD_IN, &tv) ? Qtrue : Qfalse;
-#else
- return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0), 1);
-#endif
-}
-
-/* Ruby 3.2+ can define these methods. This macro indicates that case. */
-#ifndef RUBY_IO_WAIT_METHODS
-
-/*
- * call-seq:
- * io.wait_readable -> truthy or falsy
- * io.wait_readable(timeout) -> truthy or falsy
- *
- * Waits until IO is readable and returns a truthy value, or a falsy
- * value when times out. Returns a truthy value immediately when
- * buffered data is available.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_wait_readable(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval timerec;
- struct timeval *tv;
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
-
-#ifndef HAVE_RB_IO_WAIT
- tv = get_timeout(argc, argv, &timerec);
-#endif
- if (rb_io_read_pending(fptr)) return Qtrue;
-
-#ifndef HAVE_RB_IO_WAIT
- if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
- return io;
- }
- return Qnil;
-#else
- rb_check_arity(argc, 0, 1);
- VALUE timeout = (argc == 1 ? argv[0] : Qnil);
-
- return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
-#endif
-}
+#include "ruby.h" /* abi_version */
/*
- * call-seq:
- * io.wait_writable -> truthy or falsy
- * io.wait_writable(timeout) -> truthy or falsy
- *
- * Waits until IO is writable and returns a truthy value or a falsy
- * value when times out.
- *
- * You must require 'io/wait' to use this method.
- */
-static VALUE
-io_wait_writable(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval timerec;
- struct timeval *tv;
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_writable(fptr);
-
-#ifndef HAVE_RB_IO_WAIT
- tv = get_timeout(argc, argv, &timerec);
- if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
- return io;
- }
- return Qnil;
-#else
- rb_check_arity(argc, 0, 1);
- VALUE timeout = (argc == 1 ? argv[0] : Qnil);
-
- return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
-#endif
-}
-
-#ifdef HAVE_RB_IO_WAIT
-/*
- * call-seq:
- * io.wait_priority -> truthy or falsy
- * io.wait_priority(timeout) -> truthy or falsy
- *
- * Waits until IO is priority and returns a truthy value or a falsy
- * value when times out. Priority data is sent and received using
- * the Socket::MSG_OOB flag and is typically limited to streams.
- *
- * You must require 'io/wait' to use this method.
- */
-static VALUE
-io_wait_priority(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr = NULL;
-
- RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
-
- if (rb_io_read_pending(fptr)) return Qtrue;
-
- rb_check_arity(argc, 0, 1);
- VALUE timeout = argc == 1 ? argv[0] : Qnil;
-
- return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
-}
-#endif
-
-static int
-wait_mode_sym(VALUE mode)
-{
- if (mode == ID2SYM(rb_intern("r"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("read"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("readable"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("w"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("write"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("writable"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("rw"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("read_write"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("readable_writable"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
- return 0;
-}
-
-#ifdef HAVE_RB_IO_WAIT
-static inline rb_io_event_t
-io_event_from_value(VALUE value)
-{
- int events = RB_NUM2INT(value);
-
- if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
-
- return events;
-}
-#endif
-
-/*
- * call-seq:
- * io.wait(events, timeout) -> event mask, false or nil
- * io.wait(timeout = nil, mode = :read) -> self, true, or false
- *
- * Waits until the IO becomes ready for the specified events and returns the
- * subset of events that become ready, or a falsy value when times out.
- *
- * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
- * +IO::PRIORITY+.
- *
- * Returns a truthy value immediately when buffered data is available.
- *
- * Optional parameter +mode+ is one of +:read+, +:write+, or
- * +:read_write+.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_wait(int argc, VALUE *argv, VALUE io)
-{
-#ifndef HAVE_RB_IO_WAIT
- rb_io_t *fptr;
- struct timeval timerec;
- struct timeval *tv = NULL;
- int event = 0;
- int i;
-
- GetOpenFile(io, fptr);
- for (i = 0; i < argc; ++i) {
- if (SYMBOL_P(argv[i])) {
- event |= wait_mode_sym(argv[i]);
- }
- else {
- *(tv = &timerec) = rb_time_interval(argv[i]);
- }
- }
- /* rb_time_interval() and might_mode() might convert the argument */
- rb_io_check_closed(fptr);
- if (!event) event = RB_WAITFD_IN;
- if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
- return Qtrue;
- if (wait_for_single_fd(fptr, event, tv))
- return io;
- return Qnil;
-#else
- VALUE timeout = Qundef;
- rb_io_event_t events = 0;
- int i, return_io = 0;
-
- /* The documented signature for this method is actually incorrect.
- * A single timeout is allowed in any position, and multiple symbols can be given.
- * Whether this is intentional or not, I don't know, and as such I consider this to
- * be a legacy/slow path. */
- if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
- /* We'd prefer to return the actual mask, but this form would return the io itself: */
- return_io = 1;
-
- /* Slow/messy path: */
- for (i = 0; i < argc; i += 1) {
- if (RB_SYMBOL_P(argv[i])) {
- events |= wait_mode_sym(argv[i]);
- }
- else if (timeout == Qundef) {
- rb_time_interval(timeout = argv[i]);
- }
- else {
- rb_raise(rb_eArgError, "timeout given more than once");
- }
- }
-
- if (timeout == Qundef) timeout = Qnil;
-
- if (events == 0) {
- events = RUBY_IO_READABLE;
- }
- }
- else /* argc == 2 and neither are symbols */ {
- /* This is the fast path: */
- events = io_event_from_value(argv[0]);
- timeout = argv[1];
- }
-
- if (events & RUBY_IO_READABLE) {
- rb_io_t *fptr = NULL;
- RB_IO_POINTER(io, fptr);
-
- if (rb_io_read_pending(fptr)) {
- /* This was the original behaviour: */
- if (return_io) return Qtrue;
- /* New behaviour always returns an event mask: */
- else return RB_INT2NUM(RUBY_IO_READABLE);
- }
- }
-
- return io_wait_event(io, events, timeout, return_io);
-#endif
-}
-
-#endif /* RUBY_IO_WAIT_METHODS */
-
-/*
- * IO wait methods
+ * IO wait methods are built in ruby now, just for backward compatibility.
*/
void
Init_wait(void)
{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- RB_EXT_RACTOR_SAFE(true);
-#endif
-
- rb_define_method(rb_cIO, "nread", io_nread, 0);
- rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
-
-#ifndef RUBY_IO_WAIT_METHODS
- rb_define_method(rb_cIO, "wait", io_wait, -1);
-
- rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
- rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
-#ifdef HAVE_RB_IO_WAIT
- rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
-#endif
-#endif
}
diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h
index b8a4e983d6..b4f5266ca5 100644
--- a/ext/json/fbuffer/fbuffer.h
+++ b/ext/json/fbuffer/fbuffer.h
@@ -1,41 +1,9 @@
#ifndef _FBUFFER_H_
#define _FBUFFER_H_
-#include "ruby.h"
-#include "ruby/encoding.h"
+#include "../json.h"
#include "../vendor/jeaiii-ltoa.h"
-/* shims */
-/* This is the fallback definition from Ruby 3.4 */
-
-#ifndef RBIMPL_STDBOOL_H
-#if defined(__cplusplus)
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#elif defined(HAVE_STDBOOL_H)
-# include <stdbool.h>
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
-#endif
-#endif
-
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
-#ifndef RB_LIKELY
-#define RB_LIKELY(expr) expr
-#endif
-
-#ifndef MAYBE_UNUSED
-# define MAYBE_UNUSED(x) x
-#endif
-
enum fbuffer_type {
FBUFFER_HEAP_ALLOCATED = 0,
FBUFFER_STACK_ALLOCATED = 1,
@@ -43,9 +11,12 @@ enum fbuffer_type {
typedef struct FBufferStruct {
enum fbuffer_type type;
- unsigned long initial_length;
- unsigned long len;
- unsigned long capa;
+ size_t initial_length;
+ size_t len;
+ size_t capa;
+#if JSON_DEBUG
+ size_t requested;
+#endif
char *ptr;
VALUE io;
} FBuffer;
@@ -61,12 +32,12 @@ typedef struct FBufferStruct {
static void fbuffer_free(FBuffer *fb);
static void fbuffer_clear(FBuffer *fb);
-static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
+static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len);
static void fbuffer_append_long(FBuffer *fb, long number);
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
static VALUE fbuffer_finalize(FBuffer *fb);
-static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
+static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size)
{
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
if (stack_buffer) {
@@ -74,12 +45,26 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
fb->ptr = stack_buffer;
fb->capa = stack_buffer_size;
}
+#if JSON_DEBUG
+ fb->requested = 0;
+#endif
+}
+
+static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
+{
+#if JSON_DEBUG
+ if (consumed > fb->requested) {
+ rb_bug("fbuffer: Out of bound write");
+ }
+ fb->requested = 0;
+#endif
+ fb->len += consumed;
}
static void fbuffer_free(FBuffer *fb)
{
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
- ruby_xfree(fb->ptr);
+ JSON_SIZED_FREE_N(fb->ptr, fb->capa);
}
}
@@ -94,7 +79,7 @@ static void fbuffer_flush(FBuffer *fb)
fbuffer_clear(fb);
}
-static void fbuffer_realloc(FBuffer *fb, unsigned long required)
+static void fbuffer_realloc(FBuffer *fb, size_t required)
{
if (required > fb->capa) {
if (fb->type == FBUFFER_STACK_ALLOCATED) {
@@ -103,13 +88,13 @@ static void fbuffer_realloc(FBuffer *fb, unsigned long required)
fb->type = FBUFFER_HEAP_ALLOCATED;
MEMCPY(fb->ptr, old_buffer, char, fb->len);
} else {
- REALLOC_N(fb->ptr, char, required);
+ JSON_SIZED_REALLOC_N(fb->ptr, char, required, fb->capa);
}
fb->capa = required;
}
}
-static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
+static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
{
if (RB_UNLIKELY(fb->io)) {
if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
@@ -123,7 +108,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
}
}
- unsigned long required;
+ size_t required;
if (RB_UNLIKELY(!fb->ptr)) {
fb->ptr = ALLOC_N(char, fb->initial_length);
@@ -135,44 +120,86 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
fbuffer_realloc(fb, required);
}
-static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
+static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
{
+#if JSON_DEBUG
+ fb->requested = requested;
+#endif
+
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
fbuffer_do_inc_capa(fb, requested);
}
}
-static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
+static inline size_t fbuffer_size_mul_or_raise(size_t a, size_t b)
+{
+ size_t result = a * b;
+ if (RB_UNLIKELY(a != 0 && (result / a) != b)) {
+ rb_raise(rb_eArgError, "Buffer overflow, the resulting document is too large to be generated");
+ }
+ return result;
+}
+
+static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len)
+{
+ MEMCPY(fb->ptr + fb->len, newstr, char, len);
+ fbuffer_consumed(fb, len);
+}
+
+static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len)
{
if (len > 0) {
fbuffer_inc_capa(fb, len);
- MEMCPY(fb->ptr + fb->len, newstr, char, len);
- fb->len += len;
+ fbuffer_append_reserved(fb, newstr, len);
}
}
/* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
{
+#if JSON_DEBUG
+ if (fb->requested < 1) {
+ rb_bug("fbuffer: unreserved write");
+ }
+ fb->requested--;
+#endif
+
fb->ptr[fb->len] = chr;
- fb->len += 1;
+ fb->len++;
}
static void fbuffer_append_str(FBuffer *fb, VALUE str)
{
- const char *newstr = StringValuePtr(str);
- unsigned long len = RSTRING_LEN(str);
+ const char *ptr;
+ size_t len;
+ RSTRING_GETMEM(str, ptr, len);
+ fbuffer_append(fb, ptr, len);
RB_GC_GUARD(str);
+}
- fbuffer_append(fb, newstr, len);
+static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
+{
+ const char *ptr;
+ size_t len;
+ RSTRING_GETMEM(str, ptr, len);
+
+ fbuffer_inc_capa(fb, fbuffer_size_mul_or_raise(repeat, len));
+ while (repeat) {
+#if JSON_DEBUG
+ fb->requested = len;
+#endif
+ fbuffer_append_reserved(fb, ptr, len);
+ repeat--;
+ }
+ RB_GC_GUARD(str);
}
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
{
fbuffer_inc_capa(fb, 1);
*(fb->ptr + fb->len) = newchr;
- fb->len++;
+ fbuffer_consumed(fb, 1);
}
static inline char *fbuffer_cursor(FBuffer *fb)
@@ -182,7 +209,7 @@ static inline char *fbuffer_cursor(FBuffer *fb)
static inline void fbuffer_advance_to(FBuffer *fb, char *end)
{
- fb->len = end - fb->ptr;
+ fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
}
/*
@@ -223,14 +250,11 @@ static VALUE fbuffer_finalize(FBuffer *fb)
{
if (fb->io) {
fbuffer_flush(fb);
- fbuffer_free(fb);
rb_io_flush(fb->io);
return fb->io;
} else {
- VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
- fbuffer_free(fb);
- return result;
+ return rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
}
}
-#endif
+#endif // _FBUFFER_H_
diff --git a/ext/json/generator/depend b/ext/json/generator/depend
index d9160673a2..3ba4acfdd2 100644
--- a/ext/json/generator/depend
+++ b/ext/json/generator/depend
@@ -142,6 +142,7 @@ generator.o: $(hdrdir)/ruby/internal/intern/re.h
generator.o: $(hdrdir)/ruby/internal/intern/ruby.h
generator.o: $(hdrdir)/ruby/internal/intern/select.h
generator.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+generator.o: $(hdrdir)/ruby/internal/intern/set.h
generator.o: $(hdrdir)/ruby/internal/intern/signal.h
generator.o: $(hdrdir)/ruby/internal/intern/sprintf.h
generator.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -177,6 +178,8 @@ generator.o: $(hdrdir)/ruby/ruby.h
generator.o: $(hdrdir)/ruby/st.h
generator.o: $(hdrdir)/ruby/subst.h
generator.o: $(srcdir)/../fbuffer/fbuffer.h
+generator.o: $(srcdir)/../json.h
+generator.o: $(srcdir)/../simd/simd.h
generator.o: $(srcdir)/../vendor/fpconv.c
generator.o: $(srcdir)/../vendor/jeaiii-ltoa.h
generator.o: generator.c
diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb
index 078068cf63..33af03ea30 100644
--- a/ext/json/generator/extconf.rb
+++ b/ext/json/generator/extconf.rb
@@ -5,6 +5,15 @@ if RUBY_ENGINE == 'truffleruby'
File.write('Makefile', dummy_makefile("").join)
else
append_cflags("-std=c99")
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
+ have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1
+
$defs << "-DJSON_GENERATOR"
+ $defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
+
+ if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
+ load __dir__ + "/../simd/conf.rb"
+ end
+
create_makefile 'json/ext/generator'
end
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 428f5e21ff..110b5f6b32 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -1,12 +1,20 @@
-#include "ruby.h"
+#include "../json.h"
#include "../fbuffer/fbuffer.h"
#include "../vendor/fpconv.c"
#include <math.h>
#include <ctype.h>
+#include "../simd/simd.h"
+
/* ruby api and some helpers */
+enum duplicate_key_action {
+ JSON_DEPRECATED = 0,
+ JSON_IGNORE,
+ JSON_RAISE,
+};
+
typedef struct JSON_Generator_StateStruct {
VALUE indent;
VALUE space;
@@ -19,20 +27,19 @@ typedef struct JSON_Generator_StateStruct {
long depth;
long buffer_initial_length;
+ enum duplicate_key_action on_duplicate_key;
+
+ bool as_json_single_arg;
bool allow_nan;
bool ascii_only;
bool script_safe;
bool strict;
} JSON_Generator_State;
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(cond) (cond)
-#endif
-
-static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
+static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8;
-static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
-static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
+static ID i_to_s, i_to_json, i_new, i_encode;
+static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
@@ -45,7 +52,7 @@ static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_n
struct generate_json_data;
-typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
+typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
struct generate_json_data {
FBuffer *buffer;
@@ -53,44 +60,39 @@ struct generate_json_data {
JSON_Generator_State *state;
VALUE obj;
generator_func func;
+ long depth;
};
+static SIMD_Implementation simd_impl;
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
-static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-#ifdef RUBY_INTEGER_UNIFICATION
-static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-#endif
-static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
+static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
static int usascii_encindex, utf8_encindex, binary_encindex;
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_generator_error_str(VALUE invalid_object, VALUE str)
+NORETURN(static void) raise_generator_error_str(VALUE invalid_object, VALUE str)
{
+ rb_enc_associate_index(str, utf8_encindex);
VALUE exc = rb_exc_new_str(eGeneratorError, str);
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
rb_exc_raise(exc);
}
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
#ifdef RBIMPL_ATTR_FORMAT
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
#endif
-static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
+NORETURN(static void) raise_generator_error(VALUE invalid_object, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -109,12 +111,34 @@ typedef struct _search_state {
const char *end;
const char *cursor;
FBuffer *buffer;
+
+#ifdef HAVE_SIMD
+ const char *chunk_base;
+ const char *chunk_end;
+ bool has_matches;
+
+#if defined(HAVE_SIMD_NEON)
+ uint64_t matches_mask;
+#elif defined(HAVE_SIMD_SSE2)
+ int matches_mask;
+#else
+#error "Unknown SIMD Implementation."
+#endif /* HAVE_SIMD_NEON */
+#endif /* HAVE_SIMD */
} search_state;
-static inline void search_flush(search_state *search)
-{
- fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
- search->cursor = search->ptr;
+ALWAYS_INLINE(static) void search_flush(search_state *search)
+{
+ // Do not remove this conditional without profiling, specifically escape-heavy text.
+ // escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush).
+ // For back-to-back characters that need to be escaped, specifically for the SIMD code paths, this method
+ // will be called just before calling escape_UTF8_char_basic. There will be no characters to append for the
+ // consecutive characters that need to be escaped. While the fbuffer_append is a no-op if
+ // nothing needs to be flushed, we can save a few memory references with this conditional.
+ if (search->ptr > search->cursor) {
+ fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
+ search->cursor = search->ptr;
+ }
}
static const unsigned char escape_table_basic[256] = {
@@ -144,7 +168,8 @@ static inline unsigned char search_escape_basic(search_state *search)
return 0;
}
-static inline void escape_UTF8_char_basic(search_state *search) {
+ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
+{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch) {
case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
@@ -184,14 +209,43 @@ static inline void escape_UTF8_char_basic(search_state *search) {
* Everything else (should be UTF-8) is just passed through and
* appended to the result.
*/
+
+
+#if defined(HAVE_SIMD_NEON)
+static inline unsigned char search_escape_basic_neon(search_state *search);
+#elif defined(HAVE_SIMD_SSE2)
+static inline unsigned char search_escape_basic_sse2(search_state *search);
+#endif
+
+static inline unsigned char search_escape_basic(search_state *search);
+
static inline void convert_UTF8_to_JSON(search_state *search)
{
+#ifdef HAVE_SIMD
+#if defined(HAVE_SIMD_NEON)
+ while (search_escape_basic_neon(search)) {
+ escape_UTF8_char_basic(search);
+ }
+#elif defined(HAVE_SIMD_SSE2)
+ if (simd_impl == SIMD_SSE2) {
+ while (search_escape_basic_sse2(search)) {
+ escape_UTF8_char_basic(search);
+ }
+ return;
+ }
+ while (search_escape_basic(search)) {
+ escape_UTF8_char_basic(search);
+ }
+#endif
+#else
while (search_escape_basic(search)) {
escape_UTF8_char_basic(search);
}
+#endif /* HAVE_SIMD */
}
-static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) {
+static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
+{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch_len) {
case 1: {
@@ -227,6 +281,236 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
search->cursor = (search->ptr += ch_len);
}
+#ifdef HAVE_SIMD
+
+ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
+{
+ RBIMPL_ASSERT_OR_ASSUME(len < vec_len);
+
+ // Flush the buffer so everything up until the last 'len' characters are unflushed.
+ search_flush(search);
+
+ FBuffer *buf = search->buffer;
+ fbuffer_inc_capa(buf, vec_len);
+
+ char *s = (buf->ptr + buf->len);
+
+ // Pad the buffer with dummy characters that won't need escaping.
+ // This seem wasteful at first sight, but memset of vector length is very fast.
+ // This is a space as it can be directly represented as an immediate on AArch64.
+ memset(s, ' ', vec_len);
+
+ // Optimistically copy the remaining 'len' characters to the output FBuffer. If there are no characters
+ // to escape, then everything ends up in the correct spot. Otherwise it was convenient temporary storage.
+ if (vec_len == 16) {
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD);
+ json_fast_memcpy16(s, search->ptr, len);
+ } else {
+ MEMCPY(s, search->ptr, char, len);
+ }
+
+ return s;
+}
+
+#ifdef HAVE_SIMD_NEON
+
+ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
+{
+ uint64_t mask = search->matches_mask;
+ uint32_t index = trailing_zeros64(mask) >> 2;
+
+ // It is assumed escape_UTF8_char_basic will only ever increase search->ptr by at most one character.
+ // If we want to use a similar approach for full escaping we'll need to ensure:
+ // search->chunk_base + index >= search->ptr
+ // However, since we know escape_UTF8_char_basic only increases search->ptr by one, if the next match
+ // is one byte after the previous match then:
+ // search->chunk_base + index == search->ptr
+ search->ptr = search->chunk_base + index;
+ mask &= mask - 1;
+ search->matches_mask = mask;
+ search_flush(search);
+ return 1;
+}
+
+static inline unsigned char search_escape_basic_neon(search_state *search)
+{
+ if (RB_UNLIKELY(search->has_matches)) {
+ // There are more matches if search->matches_mask > 0.
+ if (search->matches_mask > 0) {
+ return neon_next_match(search);
+ } else {
+ // neon_next_match will only advance search->ptr up to the last matching character.
+ // Skip over any characters in the last chunk that occur after the last match.
+ search->has_matches = false;
+ search->ptr = search->chunk_end;
+ }
+ }
+
+ /*
+ * The code below implements an SIMD-based algorithm to determine if N bytes at a time
+ * need to be escaped.
+ *
+ * Assume the ptr = "Te\sting!" (the double quotes are included in the string)
+ *
+ * The explanation will be limited to the first 8 bytes of the string for simplicity. However
+ * the vector insructions may work on larger vectors.
+ *
+ * First, we load three constants 'lower_bound', 'backslash' and 'dblquote" in vector registers.
+ *
+ * lower_bound: [20 20 20 20 20 20 20 20]
+ * backslash: [5C 5C 5C 5C 5C 5C 5C 5C]
+ * dblquote: [22 22 22 22 22 22 22 22]
+ *
+ * Next we load the first chunk of the ptr:
+ * [22 54 65 5C 73 74 69 6E] (" T e \ s t i n)
+ *
+ * First we check if any byte in chunk is less than 32 (0x20). This returns the following vector
+ * as no bytes are less than 32 (0x20):
+ * [0 0 0 0 0 0 0 0]
+ *
+ * Next, we check if any byte in chunk is equal to a backslash:
+ * [0 0 0 FF 0 0 0 0]
+ *
+ * Finally we check if any byte in chunk is equal to a double quote:
+ * [FF 0 0 0 0 0 0 0]
+ *
+ * Now we have three vectors where each byte indicates if the corresponding byte in chunk
+ * needs to be escaped. We combine these vectors with a series of logical OR instructions.
+ * This is the needs_escape vector and it is equal to:
+ * [FF 0 0 FF 0 0 0 0]
+ *
+ * Next we compute the bitwise AND between each byte and 0x1 and compute the horizontal sum of
+ * the values in the vector. This computes how many bytes need to be escaped within this chunk.
+ *
+ * Finally we compute a mask that indicates which bytes need to be escaped. If the mask is 0 then,
+ * no bytes need to be escaped and we can continue to the next chunk. If the mask is not 0 then we
+ * have at least one byte that needs to be escaped.
+ */
+
+ if (string_scan_simd_neon(&search->ptr, search->end, &search->matches_mask)) {
+ search->has_matches = true;
+ search->chunk_base = search->ptr;
+ search->chunk_end = search->ptr + sizeof(uint8x16_t);
+ return neon_next_match(search);
+ }
+
+ // There are fewer than 16 bytes left.
+ unsigned long remaining = (search->end - search->ptr);
+ if (remaining >= SIMD_MINIMUM_THRESHOLD) {
+ char *s = copy_remaining_bytes(search, sizeof(uint8x16_t), remaining);
+
+ uint64_t mask = compute_chunk_mask_neon(s);
+
+ if (!mask) {
+ // Nothing to escape, ensure search_flush doesn't do anything by setting
+ // search->cursor to search->ptr.
+ fbuffer_consumed(search->buffer, remaining);
+ search->ptr = search->end;
+ search->cursor = search->end;
+ return 0;
+ }
+
+ search->matches_mask = mask;
+ search->has_matches = true;
+ search->chunk_end = search->end;
+ search->chunk_base = search->ptr;
+ return neon_next_match(search);
+ }
+
+ if (search->ptr < search->end) {
+ return search_escape_basic(search);
+ }
+
+ search_flush(search);
+ return 0;
+}
+#endif /* HAVE_SIMD_NEON */
+
+#ifdef HAVE_SIMD_SSE2
+
+ALWAYS_INLINE(static) unsigned char sse2_next_match(search_state *search)
+{
+ int mask = search->matches_mask;
+ int index = trailing_zeros(mask);
+
+ // It is assumed escape_UTF8_char_basic will only ever increase search->ptr by at most one character.
+ // If we want to use a similar approach for full escaping we'll need to ensure:
+ // search->chunk_base + index >= search->ptr
+ // However, since we know escape_UTF8_char_basic only increases search->ptr by one, if the next match
+ // is one byte after the previous match then:
+ // search->chunk_base + index == search->ptr
+ search->ptr = search->chunk_base + index;
+ mask &= mask - 1;
+ search->matches_mask = mask;
+ search_flush(search);
+ return 1;
+}
+
+#if defined(__clang__) || defined(__GNUC__)
+#define TARGET_SSE2 __attribute__((target("sse2")))
+#else
+#define TARGET_SSE2
+#endif
+
+ALWAYS_INLINE(static) TARGET_SSE2 unsigned char search_escape_basic_sse2(search_state *search)
+{
+ if (RB_UNLIKELY(search->has_matches)) {
+ // There are more matches if search->matches_mask > 0.
+ if (search->matches_mask > 0) {
+ return sse2_next_match(search);
+ } else {
+ // sse2_next_match will only advance search->ptr up to the last matching character.
+ // Skip over any characters in the last chunk that occur after the last match.
+ search->has_matches = false;
+ if (RB_UNLIKELY(search->chunk_base + sizeof(__m128i) >= search->end)) {
+ search->ptr = search->end;
+ } else {
+ search->ptr = search->chunk_base + sizeof(__m128i);
+ }
+ }
+ }
+
+ if (string_scan_simd_sse2(&search->ptr, search->end, &search->matches_mask)) {
+ search->has_matches = true;
+ search->chunk_base = search->ptr;
+ search->chunk_end = search->ptr + sizeof(__m128i);
+ return sse2_next_match(search);
+ }
+
+ // There are fewer than 16 bytes left.
+ unsigned long remaining = (search->end - search->ptr);
+ if (remaining >= SIMD_MINIMUM_THRESHOLD) {
+ char *s = copy_remaining_bytes(search, sizeof(__m128i), remaining);
+
+ int needs_escape_mask = compute_chunk_mask_sse2(s);
+
+ if (needs_escape_mask == 0) {
+ // Nothing to escape, ensure search_flush doesn't do anything by setting
+ // search->cursor to search->ptr.
+ fbuffer_consumed(search->buffer, remaining);
+ search->ptr = search->end;
+ search->cursor = search->end;
+ return 0;
+ }
+
+ search->has_matches = true;
+ search->matches_mask = needs_escape_mask;
+ search->chunk_base = search->ptr;
+ return sse2_next_match(search);
+ }
+
+ if (search->ptr < search->end) {
+ return search_escape_basic(search);
+ }
+
+ search_flush(search);
+ return 0;
+}
+
+#endif /* HAVE_SIMD_SSE2 */
+
+#endif /* HAVE_SIMD */
+
static const unsigned char script_safe_escape_table[256] = {
// ASCII Control Characters
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -330,7 +614,8 @@ static inline unsigned char search_ascii_only_escape(search_state *search, const
return 0;
}
-static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len) {
+static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len)
+{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch_len) {
case 1: {
@@ -360,7 +645,7 @@ static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_
uint32_t wchar = 0;
- switch(ch_len) {
+ switch (ch_len) {
case 2:
wchar = ch & 0x1F;
break;
@@ -415,288 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
}
}
-/*
- * Document-module: JSON::Ext::Generator
- *
- * This is the JSON generator implemented as a C extension. It can be
- * configured to be used by setting
- *
- * JSON.generator = JSON::Ext::Generator
- *
- * with the method generator= in JSON.
- *
- */
-
-/* Explanation of the following: that's the only way to not pollute
- * standard library's docs with GeneratorMethods::<ClassName> which
- * are uninformative and take a large place in a list of classes
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
- * :nodoc:
- */
-
-/*
- * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
- * :nodoc:
- */
-
-/*
- * call-seq: to_json(state = nil)
- *
- * Returns a JSON string containing a JSON object, that is generated from
- * this Hash instance.
- * _state_ is a JSON::State object, that can also be used to configure the
- * produced JSON string output further.
- */
-static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
-}
-
-/*
- * call-seq: to_json(state = nil)
- *
- * Returns a JSON string containing a JSON array, that is generated from
- * this Array instance.
- * _state_ is a JSON::State object, that can also be used to configure the
- * produced JSON string output further.
- */
-static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
-}
-
-#ifdef RUBY_INTEGER_UNIFICATION
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Integer number.
- */
-static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
-}
-
-#else
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Integer number.
- */
-static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Integer number.
- */
-static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
-}
-#endif
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string representation for this Float number.
- */
-static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
-}
-
-/*
- * call-seq: String.included(modul)
- *
- * Extends _modul_ with the String::Extend module.
- */
-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;
-}
-
-/*
- * call-seq: to_json(*)
- *
- * This string should be encoded with UTF-8 A call to this method
- * returns a JSON string encoded with UTF16 big endian characters as
- * \u????.
- */
-static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
- return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
-}
-
-/*
- * call-seq: to_json_raw_object()
- *
- * This method creates a raw object hash, that can be nested into
- * other data structures and will be generated as a raw string. This
- * method should be used, if you want to convert raw strings to JSON
- * instead of UTF-8 strings, e. g. binary data.
- */
-static VALUE mString_to_json_raw_object(VALUE self)
-{
- VALUE ary;
- VALUE result = rb_hash_new();
- rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
- ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
- rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
- return result;
-}
-
-/*
- * call-seq: to_json_raw(*args)
- *
- * This method creates a JSON text from the result of a call to
- * to_json_raw_object of this String.
- */
-static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
-{
- VALUE obj = mString_to_json_raw_object(self);
- Check_Type(obj, T_HASH);
- return mHash_to_json(argc, argv, obj);
-}
-
-/*
- * call-seq: json_create(o)
- *
- * Raw Strings are JSON Objects (the raw bytes are stored in an array for the
- * key "raw"). The Ruby String can be created by this module method.
- */
-static VALUE mString_Extend_json_create(VALUE self, VALUE o)
-{
- VALUE ary;
- Check_Type(o, T_HASH);
- ary = rb_hash_aref(o, rb_str_new2("raw"));
- return rb_funcall(ary, i_pack, 1, rb_str_new2("C*"));
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string for true: 'true'.
- */
-static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return rb_utf8_str_new("true", 4);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string for false: 'false'.
- */
-static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return rb_utf8_str_new("false", 5);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Returns a JSON string for nil: 'null'.
- */
-static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return rb_utf8_str_new("null", 4);
-}
-
-/*
- * call-seq: to_json(*)
- *
- * Converts this object to a string (calling #to_s), converts
- * it to a JSON string, and returns the result. This is a fallback, if no
- * special method #to_json was defined for some object.
- */
-static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
-{
- VALUE state;
- VALUE string = rb_funcall(self, i_to_s, 0);
- rb_scan_args(argc, argv, "01", &state);
- Check_Type(string, T_STRING);
- state = cState_from_state_s(cState, state);
- return cState_partial_generate(state, string, generate_json_string, Qfalse);
-}
-
static void State_mark(void *ptr)
{
JSON_Generator_State *state = ptr;
@@ -719,32 +722,20 @@ static void State_compact(void *ptr)
state->as_json = rb_gc_location(state->as_json);
}
-static void State_free(void *ptr)
-{
- JSON_Generator_State *state = ptr;
- ruby_xfree(state);
-}
-
static size_t State_memsize(const void *ptr)
{
return sizeof(JSON_Generator_State);
}
-#ifndef HAVE_RB_EXT_RACTOR_SAFE
-# undef RUBY_TYPED_FROZEN_SHAREABLE
-# define RUBY_TYPED_FROZEN_SHAREABLE 0
-#endif
-
static const rb_data_type_t JSON_Generator_State_type = {
- "JSON/Generator/State",
- {
+ .wrap_struct_name = "JSON/Generator/State",
+ .function = {
.dmark = State_mark,
- .dfree = State_free,
+ .dfree = RUBY_DEFAULT_FREE,
.dsize = State_memsize,
.dcompact = State_compact,
},
- 0, 0,
- RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
+ .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
};
static void state_init(JSON_Generator_State *state)
@@ -776,19 +767,193 @@ static void vstate_spill(struct generate_json_data *data)
RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
}
-static inline VALUE vstate_get(struct generate_json_data *data)
+static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
{
if (RB_UNLIKELY(!data->vstate)) {
vstate_spill(data);
}
- return data->vstate;
+ GET_STATE(data->vstate);
+ state->depth = data->depth;
+ VALUE tmp = rb_funcall(obj, i_to_json, 1, data->vstate);
+ // no need to restore state->depth, vstate is just a temporary State
+ return tmp;
+}
+
+static VALUE
+json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
+{
+ VALUE proc_args[2] = {object, is_key};
+ return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
+}
+
+static VALUE
+convert_string_subclass(VALUE key)
+{
+ VALUE key_to_s = rb_funcall(key, i_to_s, 0);
+
+ if (RB_UNLIKELY(!RB_TYPE_P(key_to_s, T_STRING))) {
+ VALUE cname = rb_obj_class(key);
+ rb_raise(rb_eTypeError,
+ "can't convert %"PRIsVALUE" to %s (%"PRIsVALUE"#%s gives %"PRIsVALUE")",
+ cname, "String", cname, "to_s", rb_obj_class(key_to_s));
+ }
+
+ return key_to_s;
+}
+
+static bool enc_utf8_compatible_p(int enc_idx)
+{
+ if (enc_idx == usascii_encindex) return true;
+ if (enc_idx == utf8_encindex) return true;
+ return false;
+}
+
+static VALUE encode_json_string_try(VALUE str)
+{
+ return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
+}
+
+static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
+{
+ raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
+ return Qundef;
+}
+
+static inline int json_str_coderange(VALUE str) {
+ int coderange = RB_ENC_CODERANGE(str);
+ if (coderange == RUBY_ENC_CODERANGE_UNKNOWN) {
+ coderange = rb_enc_str_coderange(str);
+ }
+ return coderange;
+}
+
+static inline bool valid_json_string_p(VALUE str)
+{
+ int coderange = json_str_coderange(str);
+
+ if (RB_LIKELY(coderange == ENC_CODERANGE_7BIT)) {
+ return true;
+ }
+
+ if (RB_LIKELY(coderange == ENC_CODERANGE_VALID)) {
+ return enc_utf8_compatible_p(RB_ENCODING_GET_INLINED(str));
+ }
+
+ return false;
+}
+
+NOINLINE(static) VALUE convert_invalid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
+{
+ if (!as_json_called && data->state->strict && RTEST(data->state->as_json)) {
+ VALUE coerced_str = json_call_as_json(data->state, str, Qfalse);
+ if (coerced_str != str) {
+ if (RB_TYPE_P(coerced_str, T_STRING)) {
+ if (!valid_json_string_p(coerced_str)) {
+ raise_generator_error(str, "source sequence is illegal/malformed utf-8");
+ }
+ } else {
+ // as_json could return another type than T_STRING
+ if (is_key) {
+ raise_generator_error(coerced_str, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(coerced_str));
+ }
+ }
+
+ return coerced_str;
+ }
+ }
+
+ if (RB_ENCODING_GET_INLINED(str) == binary_encindex) {
+ VALUE utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
+ switch (rb_enc_str_coderange(utf8_string)) {
+ case ENC_CODERANGE_7BIT:
+ return utf8_string;
+ case ENC_CODERANGE_VALID:
+ // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
+ // TODO: Raise in 3.0.0
+ rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
+ return utf8_string;
+ break;
+ }
+ }
+
+ return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
+}
+
+ALWAYS_INLINE(static) VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
+{
+ if (RB_LIKELY(valid_json_string_p(str))) {
+ return str;
+ }
+ else {
+ return convert_invalid_encoding(data, str, as_json_called, is_key);
+ }
+}
+
+static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ fbuffer_append_char(buffer, '"');
+
+ long len;
+ search_state search;
+ search.buffer = buffer;
+ RSTRING_GETMEM(obj, search.ptr, len);
+ search.cursor = search.ptr;
+ search.end = search.ptr + len;
+
+#ifdef HAVE_SIMD
+ search.matches_mask = 0;
+ search.has_matches = false;
+ search.chunk_base = NULL;
+ search.chunk_end = NULL;
+#endif /* HAVE_SIMD */
+
+ switch (json_str_coderange(obj)) {
+ case ENC_CODERANGE_7BIT:
+ case ENC_CODERANGE_VALID:
+ if (RB_UNLIKELY(data->state->ascii_only)) {
+ convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
+ } else if (RB_UNLIKELY(data->state->script_safe)) {
+ convert_UTF8_to_script_safe_JSON(&search);
+ } else {
+ convert_UTF8_to_JSON(&search);
+ }
+ break;
+ default:
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
+ break;
+ }
+ fbuffer_append_char(buffer, '"');
+}
+
+static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ obj = ensure_valid_encoding(data, obj, false, false);
+ raw_generate_json_string(buffer, data, obj);
}
struct hash_foreach_arg {
+ VALUE hash;
struct generate_json_data *data;
- int iter;
+ int first_key_type;
+ bool first;
+ bool mixed_keys_encountered;
};
+NOINLINE(static) void
+json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
+{
+ if (arg->mixed_keys_encountered) {
+ return;
+ }
+ arg->mixed_keys_encountered = true;
+
+ JSON_Generator_State *state = arg->data->state;
+ if (state->on_duplicate_key != JSON_IGNORE) {
+ VALUE do_raise = state->on_duplicate_key == JSON_RAISE ? Qtrue : Qfalse;
+ rb_funcall(mJSON, rb_intern("on_mixed_keys_hash"), 2, arg->hash, do_raise);
+ }
+}
+
static int
json_object_i(VALUE key, VALUE val, VALUE _arg)
{
@@ -798,272 +963,210 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
FBuffer *buffer = data->buffer;
JSON_Generator_State *state = data->state;
- long depth = state->depth;
- int j;
+ long depth = data->depth;
+ int key_type = rb_type(key);
- if (arg->iter > 0) fbuffer_append_char(buffer, ',');
- if (RB_UNLIKELY(state->object_nl)) {
- fbuffer_append_str(buffer, state->object_nl);
+ if (arg->first) {
+ arg->first = false;
+ arg->first_key_type = key_type;
}
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ else {
+ fbuffer_append_char(buffer, ',');
+ }
+
+ if (RB_UNLIKELY(data->state->object_nl)) {
+ fbuffer_append_str(buffer, data->state->object_nl);
+ }
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
VALUE key_to_s;
- switch(rb_type(key)) {
+ bool as_json_called = false;
+
+ start:
+ switch (key_type) {
case T_STRING:
+ if (RB_UNLIKELY(arg->first_key_type != T_STRING)) {
+ json_inspect_hash_with_mixed_keys(arg);
+ }
+
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
key_to_s = key;
} else {
- key_to_s = rb_funcall(key, i_to_s, 0);
+ key_to_s = convert_string_subclass(key);
}
break;
case T_SYMBOL:
+ if (RB_UNLIKELY(arg->first_key_type != T_SYMBOL)) {
+ json_inspect_hash_with_mixed_keys(arg);
+ }
+
key_to_s = rb_sym2str(key);
break;
default:
+ if (data->state->strict) {
+ if (RTEST(data->state->as_json) && !as_json_called) {
+ key = json_call_as_json(data->state, key, Qtrue);
+ key_type = rb_type(key);
+ as_json_called = true;
+ goto start;
+ } else {
+ raise_generator_error(key, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(key));
+ }
+ }
key_to_s = rb_convert_type(key, T_STRING, "String", "to_s");
break;
}
+ key_to_s = ensure_valid_encoding(data, key_to_s, as_json_called, true);
+
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
- generate_json_string(buffer, data, state, key_to_s);
+ raw_generate_json_string(buffer, data, key_to_s);
} else {
- generate_json(buffer, data, state, key_to_s);
+ generate_json(buffer, data, key_to_s);
}
- if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
+ if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, data->state->space_before);
fbuffer_append_char(buffer, ':');
- if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
- generate_json(buffer, data, state, val);
+ if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, data->state->space);
+ generate_json(buffer, data, val);
- arg->iter++;
return ST_CONTINUE;
}
-static inline long increase_depth(JSON_Generator_State *state)
+static inline long increase_depth(struct generate_json_data *data)
{
- long depth = ++state->depth;
+ JSON_Generator_State *state = data->state;
+ long depth = ++data->depth;
if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
- rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
+ rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
}
return depth;
}
-static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- int j;
- long depth = increase_depth(state);
+ long depth = increase_depth(data);
if (RHASH_SIZE(obj) == 0) {
fbuffer_append(buffer, "{}", 2);
- --state->depth;
+ --data->depth;
return;
}
fbuffer_append_char(buffer, '{');
struct hash_foreach_arg arg = {
+ .hash = obj,
.data = data,
- .iter = 0,
+ .first = true,
};
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
- depth = --state->depth;
- if (RB_UNLIKELY(state->object_nl)) {
- fbuffer_append_str(buffer, state->object_nl);
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ depth = --data->depth;
+ if (RB_UNLIKELY(data->state->object_nl)) {
+ fbuffer_append_str(buffer, data->state->object_nl);
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
}
fbuffer_append_char(buffer, '}');
}
-static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- int i, j;
- long depth = increase_depth(state);
+ long depth = increase_depth(data);
if (RARRAY_LEN(obj) == 0) {
fbuffer_append(buffer, "[]", 2);
- --state->depth;
+ --data->depth;
return;
}
fbuffer_append_char(buffer, '[');
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
- for(i = 0; i < RARRAY_LEN(obj); i++) {
+ if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
+ for (int i = 0; i < RARRAY_LEN(obj); i++) {
if (i > 0) {
fbuffer_append_char(buffer, ',');
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
+ if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
}
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
- generate_json(buffer, data, state, RARRAY_AREF(obj, i));
+ generate_json(buffer, data, RARRAY_AREF(obj, i));
}
- state->depth = --depth;
- if (RB_UNLIKELY(state->array_nl)) {
- fbuffer_append_str(buffer, state->array_nl);
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ data->depth = --depth;
+ if (RB_UNLIKELY(data->state->array_nl)) {
+ fbuffer_append_str(buffer, data->state->array_nl);
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
}
fbuffer_append_char(buffer, ']');
}
-static inline int enc_utf8_compatible_p(int enc_idx)
-{
- if (enc_idx == usascii_encindex) return 1;
- if (enc_idx == utf8_encindex) return 1;
- return 0;
-}
-
-static VALUE encode_json_string_try(VALUE str)
-{
- return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
-}
-
-static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
-{
- raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
- return Qundef;
-}
-
-static inline VALUE ensure_valid_encoding(VALUE str)
-{
- int encindex = RB_ENCODING_GET(str);
- VALUE utf8_string;
- if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
- if (encindex == binary_encindex) {
- utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
- switch (rb_enc_str_coderange(utf8_string)) {
- case ENC_CODERANGE_7BIT:
- return utf8_string;
- case ENC_CODERANGE_VALID:
- // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
- // TODO: Raise in 3.0.0
- rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
- return utf8_string;
- break;
- }
- }
-
- str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
- }
- return str;
-}
-
-static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
-{
- obj = ensure_valid_encoding(obj);
-
- fbuffer_append_char(buffer, '"');
-
- long len;
- search_state search;
- search.buffer = buffer;
- RSTRING_GETMEM(obj, search.ptr, len);
- search.cursor = search.ptr;
- search.end = search.ptr + len;
-
- switch(rb_enc_str_coderange(obj)) {
- case ENC_CODERANGE_7BIT:
- case ENC_CODERANGE_VALID:
- if (RB_UNLIKELY(state->ascii_only)) {
- convert_UTF8_to_ASCII_only_JSON(&search, state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
- } else if (RB_UNLIKELY(state->script_safe)) {
- convert_UTF8_to_script_safe_JSON(&search);
- } else {
- convert_UTF8_to_JSON(&search);
- }
- break;
- default:
- raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
- break;
- }
- fbuffer_append_char(buffer, '"');
-}
-
-static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE tmp;
if (rb_respond_to(obj, i_to_json)) {
- tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
+ tmp = json_call_to_json(data, obj);
Check_Type(tmp, T_STRING);
fbuffer_append_str(buffer, tmp);
} else {
tmp = rb_funcall(obj, i_to_s, 0);
Check_Type(tmp, T_STRING);
- generate_json_string(buffer, data, state, tmp);
+ generate_json_string(buffer, data, tmp);
}
}
-static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- if (state->strict) {
- generate_json_string(buffer, data, state, rb_sym2str(obj));
+ if (data->state->strict) {
+ generate_json_string(buffer, data, rb_sym2str(obj));
} else {
- generate_json_fallback(buffer, data, state, obj);
+ generate_json_fallback(buffer, data, obj);
}
}
-static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append(buffer, "null", 4);
}
-static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append(buffer, "false", 5);
}
-static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append(buffer, "true", 4);
}
-static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append_long(buffer, FIX2LONG(obj));
}
-static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE tmp = rb_funcall(obj, i_to_s, 0);
- fbuffer_append_str(buffer, tmp);
-}
-
-#ifdef RUBY_INTEGER_UNIFICATION
-static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
-{
- if (FIXNUM_P(obj))
- generate_json_fixnum(buffer, data, state, obj);
- else
- generate_json_bignum(buffer, data, state, obj);
+ fbuffer_append_str(buffer, StringValue(tmp));
}
-#endif
-static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
double value = RFLOAT_VALUE(obj);
- char allow_nan = state->allow_nan;
+ char allow_nan = data->state->allow_nan;
if (isinf(value) || isnan(value)) {
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
if (!allow_nan) {
- if (state->strict && state->as_json) {
- VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
+ if (data->state->strict && data->state->as_json) {
+ VALUE casted_obj = json_call_as_json(data->state, obj, Qfalse);
if (casted_obj != obj) {
- increase_depth(state);
- generate_json(buffer, data, state, casted_obj);
- state->depth--;
+ increase_depth(data);
+ generate_json(buffer, data, casted_obj);
+ data->depth--;
return;
}
}
@@ -1076,43 +1179,41 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
}
/* This implementation writes directly into the buffer. We reserve
- * the 24 characters that fpconv_dtoa states as its maximum, plus
- * 2 more characters for the potential ".0" suffix.
+ * the 32 characters that fpconv_dtoa states as its maximum.
*/
- fbuffer_inc_capa(buffer, 26);
+ fbuffer_inc_capa(buffer, 32);
char* d = buffer->ptr + buffer->len;
int len = fpconv_dtoa(value, d);
-
/* fpconv_dtoa converts a float to its shortest string representation,
* but it adds a ".0" if this is a plain integer.
*/
- buffer->len += len;
+ fbuffer_consumed(buffer, len);
}
-static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE fragment = RSTRUCT_GET(obj, 0);
Check_Type(fragment, T_STRING);
fbuffer_append_str(buffer, fragment);
}
-static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
{
bool as_json_called = false;
start:
if (obj == Qnil) {
- generate_json_null(buffer, data, state, obj);
+ generate_json_null(buffer, data, obj);
} else if (obj == Qfalse) {
- generate_json_false(buffer, data, state, obj);
+ generate_json_false(buffer, data, obj);
} else if (obj == Qtrue) {
- generate_json_true(buffer, data, state, obj);
+ generate_json_true(buffer, data, obj);
} else if (RB_SPECIAL_CONST_P(obj)) {
if (RB_FIXNUM_P(obj)) {
- generate_json_fixnum(buffer, data, state, obj);
+ generate_json_fixnum(buffer, data, obj);
} else if (RB_FLONUM_P(obj)) {
- generate_json_float(buffer, data, state, obj);
+ generate_json_float(buffer, data, obj);
} else if (RB_STATIC_SYM_P(obj)) {
- generate_json_symbol(buffer, data, state, obj);
+ generate_json_symbol(buffer, data, obj);
} else {
goto general;
}
@@ -1120,68 +1221,85 @@ start:
VALUE klass = RBASIC_CLASS(obj);
switch (RB_BUILTIN_TYPE(obj)) {
case T_BIGNUM:
- generate_json_bignum(buffer, data, state, obj);
+ generate_json_bignum(buffer, data, obj);
break;
case T_HASH:
- if (klass != rb_cHash) goto general;
- generate_json_object(buffer, data, state, obj);
+ if (fallback && klass != rb_cHash) goto general;
+ generate_json_object(buffer, data, obj);
break;
case T_ARRAY:
- if (klass != rb_cArray) goto general;
- generate_json_array(buffer, data, state, obj);
+ if (fallback && klass != rb_cArray) goto general;
+ generate_json_array(buffer, data, obj);
break;
case T_STRING:
- if (klass != rb_cString) goto general;
- generate_json_string(buffer, data, state, obj);
+ if (fallback && klass != rb_cString) goto general;
+
+ if (RB_LIKELY(valid_json_string_p(obj))) {
+ raw_generate_json_string(buffer, data, obj);
+ } else if (as_json_called) {
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
+ } else {
+ obj = ensure_valid_encoding(data, obj, false, false);
+ as_json_called = true;
+ goto start;
+ }
break;
case T_SYMBOL:
- generate_json_symbol(buffer, data, state, obj);
+ generate_json_symbol(buffer, data, obj);
break;
case T_FLOAT:
- if (klass != rb_cFloat) goto general;
- generate_json_float(buffer, data, state, obj);
+ if (fallback && klass != rb_cFloat) goto general;
+ generate_json_float(buffer, data, obj);
break;
case T_STRUCT:
if (klass != cFragment) goto general;
- generate_json_fragment(buffer, data, state, obj);
+ generate_json_fragment(buffer, data, obj);
break;
default:
general:
- if (state->strict) {
- if (RTEST(state->as_json) && !as_json_called) {
- obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
+ if (data->state->strict) {
+ if (RTEST(data->state->as_json) && !as_json_called) {
+ obj = json_call_as_json(data->state, obj, Qfalse);
as_json_called = true;
goto start;
} else {
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
}
} else {
- generate_json_fallback(buffer, data, state, obj);
+ generate_json_fallback(buffer, data, obj);
}
}
}
}
+static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ generate_json_general(buffer, data, obj, true);
+}
+
+static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ generate_json_general(buffer, data, obj, false);
+}
+
static VALUE generate_json_try(VALUE d)
{
struct generate_json_data *data = (struct generate_json_data *)d;
- data->func(data->buffer, data, data->state, data->obj);
+ data->func(data->buffer, data, data->obj);
- return Qnil;
+ return fbuffer_finalize(data->buffer);
}
-static VALUE generate_json_rescue(VALUE d, VALUE exc)
+static VALUE generate_json_ensure(VALUE d)
{
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, generator_func func, VALUE io)
+static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
{
GET_STATE(self);
@@ -1193,14 +1311,13 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
struct generate_json_data data = {
.buffer = &buffer,
- .vstate = self,
+ .vstate = Qfalse, // don't use self as it may be frozen and its depth is mutated when calling to_json
.state = state,
+ .depth = state->depth,
.obj = obj,
.func = func
};
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
-
- return fbuffer_finalize(&buffer);
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
}
/* call-seq:
@@ -1216,10 +1333,16 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 1, 2);
VALUE obj = argv[0];
VALUE io = argc > 1 ? argv[1] : Qnil;
- VALUE result = cState_partial_generate(self, obj, generate_json, io);
- GET_STATE(self);
- (void)state;
- return result;
+ return cState_partial_generate(self, obj, generate_json, io);
+}
+
+/* :nodoc: */
+static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
+{
+ rb_check_arity(argc, 1, 2);
+ VALUE obj = argv[0];
+ VALUE io = argc > 1 ? argv[1] : Qnil;
+ return cState_partial_generate(self, obj, generate_json_no_fallback, io);
}
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
@@ -1244,12 +1367,14 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
MEMCPY(objState, origState, JSON_Generator_State, 1);
- objState->indent = origState->indent;
- objState->space = origState->space;
- objState->space_before = origState->space_before;
- objState->object_nl = origState->object_nl;
- objState->array_nl = origState->array_nl;
- objState->as_json = origState->as_json;
+
+ RB_OBJ_WRITTEN(obj, Qundef, objState->indent);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->space);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->space_before);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->object_nl);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->array_nl);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->as_json);
+
return obj;
}
@@ -1300,6 +1425,7 @@ static VALUE string_config(VALUE config)
*/
static VALUE cState_indent_set(VALUE self, VALUE indent)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
return Qnil;
@@ -1325,6 +1451,7 @@ static VALUE cState_space(VALUE self)
*/
static VALUE cState_space_set(VALUE self, VALUE space)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->space, string_config(space));
return Qnil;
@@ -1348,6 +1475,7 @@ static VALUE cState_space_before(VALUE self)
*/
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
return Qnil;
@@ -1373,6 +1501,7 @@ static VALUE cState_object_nl(VALUE self)
*/
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
return Qnil;
@@ -1396,6 +1525,7 @@ static VALUE cState_array_nl(VALUE self)
*/
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
return Qnil;
@@ -1419,6 +1549,7 @@ static VALUE cState_as_json(VALUE self)
*/
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
return Qnil;
@@ -1450,7 +1581,21 @@ static VALUE cState_max_nesting(VALUE self)
static long long_config(VALUE num)
{
- return RTEST(num) ? FIX2LONG(num) : 0;
+ return RTEST(num) ? NUM2LONG(num) : 0;
+}
+
+// depth must never be negative; reject early with a clear error.
+static long depth_config(VALUE num)
+{
+ if (!RTEST(num)) return 0;
+ long d = NUM2LONG(num);
+ if (RB_UNLIKELY(d < 0)) {
+ rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
+ }
+ if (RB_UNLIKELY(d > INT_MAX)) {
+ rb_raise(rb_eArgError, "depth is too large (got %ld)", d);
+ }
+ return d;
}
/*
@@ -1461,6 +1606,7 @@ static long long_config(VALUE num)
*/
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->max_nesting = long_config(depth);
return Qnil;
@@ -1486,6 +1632,7 @@ static VALUE cState_script_safe(VALUE self)
*/
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->script_safe = RTEST(enable);
return Qnil;
@@ -1517,6 +1664,7 @@ static VALUE cState_strict(VALUE self)
*/
static VALUE cState_strict_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->strict = RTEST(enable);
return Qnil;
@@ -1541,6 +1689,7 @@ static VALUE cState_allow_nan_p(VALUE self)
*/
static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->allow_nan = RTEST(enable);
return Qnil;
@@ -1565,11 +1714,25 @@ static VALUE cState_ascii_only_p(VALUE self)
*/
static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->ascii_only = RTEST(enable);
return Qnil;
}
+static VALUE cState_allow_duplicate_key_p(VALUE self)
+{
+ GET_STATE(self);
+ switch (state->on_duplicate_key) {
+ case JSON_IGNORE:
+ return Qtrue;
+ case JSON_DEPRECATED:
+ return Qnil;
+ default:
+ return Qfalse;
+ }
+}
+
/*
* call-seq: depth
*
@@ -1589,8 +1752,9 @@ static VALUE cState_depth(VALUE self)
*/
static VALUE cState_depth_set(VALUE self, VALUE depth)
{
+ rb_check_frozen(self);
GET_STATE(self);
- state->depth = long_config(depth);
+ state->depth = depth_config(depth);
return Qnil;
}
@@ -1622,33 +1786,54 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
*/
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
{
+ rb_check_frozen(self);
GET_STATE(self);
buffer_initial_length_set(state, buffer_initial_length);
return Qnil;
}
+struct configure_state_data {
+ JSON_Generator_State *state;
+ VALUE vstate; // Ruby object that owns the state, or Qfalse if stack-allocated
+};
+
+static inline void state_write_value(struct configure_state_data *data, VALUE *field, VALUE value)
+{
+ if (RTEST(data->vstate)) {
+ RB_OBJ_WRITE(data->vstate, field, value);
+ } else {
+ *field = value;
+ }
+}
+
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
{
- JSON_Generator_State *state = (JSON_Generator_State *)_arg;
+ struct configure_state_data *data = (struct configure_state_data *)_arg;
+ JSON_Generator_State *state = data->state;
- if (key == sym_indent) { state->indent = string_config(val); }
- else if (key == sym_space) { state->space = string_config(val); }
- else if (key == sym_space_before) { state->space_before = string_config(val); }
- else if (key == sym_object_nl) { state->object_nl = string_config(val); }
- else if (key == sym_array_nl) { state->array_nl = string_config(val); }
+ if (key == sym_indent) { state_write_value(data, &state->indent, string_config(val)); }
+ else if (key == sym_space) { state_write_value(data, &state->space, string_config(val)); }
+ else if (key == sym_space_before) { state_write_value(data, &state->space_before, string_config(val)); }
+ else if (key == sym_object_nl) { state_write_value(data, &state->object_nl, string_config(val)); }
+ else if (key == sym_array_nl) { state_write_value(data, &state->array_nl, string_config(val)); }
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
- else if (key == sym_depth) { state->depth = long_config(val); }
+ else if (key == sym_depth) { state->depth = depth_config(val); }
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
else if (key == sym_strict) { state->strict = RTEST(val); }
- else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
+ else if (key == sym_allow_duplicate_key) { state->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
+ else if (key == sym_as_json) {
+ VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
+ state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
+ state_write_value(data, &state->as_json, proc);
+ }
return ST_CONTINUE;
}
-static void configure_state(JSON_Generator_State *state, VALUE config)
+static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE config)
{
if (!RTEST(config)) return;
@@ -1656,23 +1841,29 @@ static void configure_state(JSON_Generator_State *state, VALUE config)
if (!RHASH_SIZE(config)) return;
+ struct configure_state_data data = {
+ .state = state,
+ .vstate = vstate
+ };
+
// We assume in most cases few keys are set so it's faster to go over
// the provided keys than to check all possible keys.
- rb_hash_foreach(config, configure_state_i, (VALUE)state);
+ rb_hash_foreach(config, configure_state_i, (VALUE)&data);
}
static VALUE cState_configure(VALUE self, VALUE opts)
{
+ rb_check_frozen(self);
GET_STATE(self);
- configure_state(state, opts);
+ configure_state(state, self, opts);
return self;
}
-static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
+static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
{
JSON_Generator_State state = {0};
state_init(&state);
- configure_state(&state, opts);
+ configure_state(&state, Qfalse, opts);
char stack_buffer[FBUFFER_STACK_SIZE];
FBuffer buffer = {
@@ -1684,17 +1875,23 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
.buffer = &buffer,
.vstate = Qfalse,
.state = &state,
+ .depth = state.depth,
.obj = obj,
- .func = generate_json,
+ .func = func,
};
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
+}
- return fbuffer_finalize(&buffer);
+static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
+{
+ return cState_m_do_generate(klass, obj, opts, io, generate_json);
+}
+
+static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
+{
+ return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
}
-/*
- *
- */
void Init_generator(void)
{
#ifdef HAVE_RB_EXT_RACTOR_SAFE
@@ -1759,51 +1956,12 @@ void Init_generator(void)
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
rb_define_method(cState, "generate", cState_generate, -1);
- rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
+ rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
- rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
+ rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
- VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
-
- VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
- rb_define_method(mObject, "to_json", mObject_to_json, -1);
-
- VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
- rb_define_method(mHash, "to_json", mHash_to_json, -1);
-
- VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
- rb_define_method(mArray, "to_json", mArray_to_json, -1);
-
-#ifdef RUBY_INTEGER_UNIFICATION
- VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
- rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
-#else
- VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
- rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
-
- VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
- rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
-#endif
- VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
- rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
-
- VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
- rb_define_singleton_method(mString, "included", mString_included_s, 1);
- rb_define_method(mString, "to_json", mString_to_json, -1);
- rb_define_method(mString, "to_json_raw", mString_to_json_raw, -1);
- rb_define_method(mString, "to_json_raw_object", mString_to_json_raw_object, 0);
-
- mString_Extend = rb_define_module_under(mString, "Extend");
- rb_define_method(mString_Extend, "json_create", mString_Extend_json_create, 1);
-
- VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
- rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
-
- VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
- rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
-
- VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
- rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
+ rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
+ rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
rb_global_variable(&Encoding_UTF_8);
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
@@ -1811,10 +1969,6 @@ void Init_generator(void)
i_to_s = rb_intern("to_s");
i_to_json = rb_intern("to_json");
i_new = rb_intern("new");
- i_pack = rb_intern("pack");
- i_unpack = rb_intern("unpack");
- i_create_id = rb_intern("create_id");
- i_extend = rb_intern("extend");
i_encode = rb_intern("encode");
sym_indent = ID2SYM(rb_intern("indent"));
@@ -1831,10 +1985,13 @@ void Init_generator(void)
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
sym_strict = ID2SYM(rb_intern("strict"));
sym_as_json = ID2SYM(rb_intern("as_json"));
+ sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
usascii_encindex = rb_usascii_encindex();
utf8_encindex = rb_utf8_encindex();
binary_encindex = rb_ascii8bit_encindex();
rb_require("json/ext/generator/state");
+
+ simd_impl = find_simd_implementation();
}
diff --git a/ext/json/json.gemspec b/ext/json/json.gemspec
index 943c78aab9..5575731025 100644
--- a/ext/json/json.gemspec
+++ b/ext/json/json.gemspec
@@ -44,15 +44,14 @@ spec = Gem::Specification.new do |s|
"LEGAL",
"README.md",
"json.gemspec",
- *Dir["lib/**/*.rb"],
- ]
+ ] + Dir.glob("lib/**/*.rb", base: File.expand_path("..", __FILE__))
if java_ext
s.platform = 'java'
s.files += Dir["lib/json/ext/**/*.jar"]
else
s.extensions = Dir["ext/json/**/extconf.rb"]
- s.files += Dir["ext/json/**/*.{c,h}"]
+ s.files += Dir["ext/json/**/*.{c,h,rb}"]
end
end
diff --git a/ext/json/json.h b/ext/json/json.h
new file mode 100644
index 0000000000..cf9420d4dd
--- /dev/null
+++ b/ext/json/json.h
@@ -0,0 +1,134 @@
+#ifndef _JSON_H_
+#define _JSON_H_
+
+#include "ruby.h"
+#include "ruby/encoding.h"
+#include <stdint.h>
+
+#ifndef RBIMPL_ASSERT_OR_ASSUME
+# define RBIMPL_ASSERT_OR_ASSUME(x)
+#endif
+
+#if defined(RUBY_DEBUG) && RUBY_DEBUG
+# define JSON_ASSERT RUBY_ASSERT
+#else
+# ifdef JSON_DEBUG
+# include <assert.h>
+# define JSON_ASSERT(x) assert(x)
+# else
+# define JSON_ASSERT(x)
+# endif
+#endif
+
+/* shims */
+
+#if SIZEOF_UINT64_T == SIZEOF_LONG_LONG
+# define INT64T2NUM(x) LL2NUM(x)
+# define UINT64T2NUM(x) ULL2NUM(x)
+#elif SIZEOF_UINT64_T == SIZEOF_LONG
+# define INT64T2NUM(x) LONG2NUM(x)
+# define UINT64T2NUM(x) ULONG2NUM(x)
+#else
+# error No uint64_t conversion
+#endif
+
+/* This is the fallback definition from Ruby 3.4 */
+#ifndef RBIMPL_STDBOOL_H
+#if defined(__cplusplus)
+# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
+# include <cstdbool>
+# endif
+#elif defined(HAVE_STDBOOL_H)
+# include <stdbool.h>
+#elif !defined(HAVE__BOOL)
+typedef unsigned char _Bool;
+# define bool _Bool
+# define true ((_Bool)+1)
+# define false ((_Bool)+0)
+# define __bool_true_false_are_defined
+#endif
+#endif
+
+#ifndef HAVE_RUBY_XFREE_SIZED
+static inline void ruby_xfree_sized(void *ptr, size_t oldsize)
+{
+ ruby_xfree(ptr);
+}
+
+static inline void *ruby_xrealloc2_sized(void *ptr, size_t new_elems, size_t elem_size, size_t old_elems)
+{
+ return ruby_xrealloc2(ptr, new_elems, elem_size);
+}
+#endif
+
+# define JSON_SIZED_REALLOC_N(v, T, m, n) \
+ ((v) = (T *)ruby_xrealloc2_sized((void *)(v), (m), sizeof(T), (n)))
+
+# define JSON_SIZED_FREE(v) ruby_xfree_sized((void *)(v), sizeof(*(v)))
+# define JSON_SIZED_FREE_N(v, n) ruby_xfree_sized((void *)(v), sizeof(*(v)) * (n))
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+# undef RUBY_TYPED_FROZEN_SHAREABLE
+# define RUBY_TYPED_FROZEN_SHAREABLE 0
+#endif
+
+#ifdef RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+#else
+# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
+# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+# else
+# define RUBY_TYPED_EMBEDDABLE 0
+# endif
+#endif
+
+#ifndef NORETURN
+#if defined(__has_attribute) && __has_attribute(noreturn)
+#define NORETURN(x) __attribute__((noreturn)) x
+#else
+#define NORETURN(x) x
+#endif
+#endif
+
+#ifndef NOINLINE
+#if defined(__has_attribute) && __has_attribute(noinline)
+#define NOINLINE(x) __attribute__((noinline)) x
+#else
+#define NOINLINE(x) x
+#endif
+#endif
+
+#ifndef ALWAYS_INLINE
+#if defined(__has_attribute) && __has_attribute(always_inline)
+#define ALWAYS_INLINE(x) inline __attribute__((always_inline)) x
+#else
+#define ALWAYS_INLINE(x) inline x
+#endif
+#endif
+
+#ifndef RB_UNLIKELY
+#define RB_UNLIKELY(expr) expr
+#endif
+
+#ifndef RB_LIKELY
+#define RB_LIKELY(expr) expr
+#endif
+
+#ifndef MAYBE_UNUSED
+# define MAYBE_UNUSED(x) x
+#endif
+
+#ifdef RUBY_DEBUG
+#ifndef JSON_DEBUG
+#define JSON_DEBUG RUBY_DEBUG
+#endif
+#endif
+
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && INTPTR_MAX == INT64_MAX
+#define JSON_CPU_LITTLE_ENDIAN_64BITS 1
+#else
+#define JSON_CPU_LITTLE_ENDIAN_64BITS 0
+#endif
+
+#endif // _JSON_H_
diff --git a/ext/json/lib/json.rb b/ext/json/lib/json.rb
index dfd9b7dfc2..26d601926f 100644
--- a/ext/json/lib/json.rb
+++ b/ext/json/lib/json.rb
@@ -6,6 +6,15 @@ require 'json/common'
#
# \JSON is a lightweight data-interchange format.
#
+# \JSON is easy for us humans to read and write,
+# and equally simple for machines to read (parse) and write (generate).
+#
+# \JSON is language-independent, making it an ideal interchange format
+# for applications in differing programming languages
+# and on differing operating systems.
+#
+# == \JSON Values
+#
# A \JSON value is one of the following:
# - Double-quoted text: <tt>"foo"</tt>.
# - Number: +1+, +1.0+, +2.0e2+.
@@ -127,6 +136,24 @@ require 'json/common'
#
# ---
#
+# Option +allow_duplicate_key+ specifies whether duplicate keys in objects
+# should be ignored or cause an error to be raised:
+#
+# When not specified:
+# # The last value is used and a deprecation warning emitted.
+# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
+# # warning: detected duplicate keys in JSON object.
+# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
+#
+# When set to `+true+`
+# # The last value is used.
+# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
+#
+# When set to `+false+`, the future default:
+# JSON.parse('{"a": 1, "a":2}') => duplicate key at line 1 column 1 (JSON::ParserError)
+#
+# ---
+#
# Option +allow_nan+ (boolean) specifies whether to allow
# NaN, Infinity, and MinusInfinity in +source+;
# defaults to +false+.
@@ -143,8 +170,47 @@ require 'json/common'
# ruby = JSON.parse(source, {allow_nan: true})
# ruby # => [NaN, Infinity, -Infinity]
#
+# ---
+#
+# Option +allow_trailing_comma+ (boolean) specifies whether to allow
+# trailing commas in objects and arrays;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse('[1,]') # unexpected character: ']' at line 1 column 4 (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
+#
+# ---
+#
+# Option +allow_control_characters+ (boolean) specifies whether to allow
+# unescaped ASCII control characters, such as newlines, in strings;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse(%{"Hello\nWorld"}) # invalid ASCII control character in string (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
+#
+# ---
+#
+# Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
+# by an invalid escape character in strings;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
+#
# ====== Output Options
#
+# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
+# defaults to +false+.
+#
# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
# should be Symbols;
# defaults to +false+ (use Strings).
@@ -269,8 +335,27 @@ require 'json/common'
# JSON.generate(JSON::MinusInfinity)
#
# Allow:
-# ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
-# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
+# ruby = [Float::NAN, Float::INFINITY, JSON::NaN, JSON::Infinity, JSON::MinusInfinity]
+# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,NaN,Infinity,-Infinity]'
+#
+# ---
+#
+# Option +allow_duplicate_key+ (boolean) specifies whether
+# hashes with duplicate keys should be allowed or produce an error.
+# defaults to emit a deprecation warning.
+#
+# With the default, (not set):
+# Warning[:deprecated] = true
+# JSON.generate({ foo: 1, "foo" => 2 })
+# # warning: detected duplicate key "foo" in {foo: 1, "foo" => 2}.
+# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
+# # => '{"foo":1,"foo":2}'
+#
+# With <tt>false</tt>
+# JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: false)
+# # detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)
+#
+# In version 3.0, <tt>false</tt> will become the default.
#
# ---
#
@@ -351,6 +436,9 @@ require 'json/common'
#
# == \JSON Additions
#
+# Note that JSON Additions must only be used with trusted data, and is
+# deprecated.
+#
# When you "round trip" a non-\String object from Ruby to \JSON and back,
# you have a new \String, instead of the object you began with:
# ruby0 = Range.new(0, 2)
diff --git a/ext/json/lib/json/add/core.rb b/ext/json/lib/json/add/core.rb
index 485f097fff..61ff454212 100644
--- a/ext/json/lib/json/add/core.rb
+++ b/ext/json/lib/json/add/core.rb
@@ -7,6 +7,7 @@ require 'json/add/date_time'
require 'json/add/exception'
require 'json/add/range'
require 'json/add/regexp'
+require 'json/add/string'
require 'json/add/struct'
require 'json/add/symbol'
require 'json/add/time'
diff --git a/ext/json/lib/json/add/string.rb b/ext/json/lib/json/add/string.rb
new file mode 100644
index 0000000000..9c3bde27fb
--- /dev/null
+++ b/ext/json/lib/json/add/string.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+
+class String
+ # call-seq: json_create(o)
+ #
+ # Raw Strings are JSON Objects (the raw bytes are stored in an array for the
+ # key "raw"). The Ruby String can be created by this class method.
+ def self.json_create(object)
+ object["raw"].pack("C*")
+ end
+
+ # call-seq: to_json_raw_object()
+ #
+ # This method creates a raw object hash, that can be nested into
+ # other data structures and will be generated as a raw string. This
+ # method should be used, if you want to convert raw strings to JSON
+ # instead of UTF-8 strings, e. g. binary data.
+ def to_json_raw_object
+ {
+ JSON.create_id => self.class.name,
+ "raw" => unpack("C*"),
+ }
+ end
+
+ # call-seq: to_json_raw(*args)
+ #
+ # This method creates a JSON text from the result of a call to
+ # to_json_raw_object of this String.
+ def to_json_raw(...)
+ to_json_raw_object.to_json(...)
+ end
+end
diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb
index a542bdb361..230bf08012 100644
--- a/ext/json/lib/json/common.rb
+++ b/ext/json/lib/json/common.rb
@@ -48,7 +48,7 @@ module JSON
end
end
- # TODO: exact :create_additions support to another gem for version 3.0
+ # TODO: extract :create_additions support to another gem for version 3.0
def create_additions_proc(opts)
if opts[:symbolize_names]
raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
@@ -71,9 +71,14 @@ module JSON
end
when object_class
if opts[:create_additions] != false
- if class_name = object[JSON.create_id]
- klass = JSON.deep_const_get(class_name)
- if (klass.respond_to?(:json_creatable?) && klass.json_creatable?) || klass.respond_to?(:json_create)
+ if class_path = object[JSON.create_id]
+ klass = begin
+ Object.const_get(class_path)
+ rescue NameError => e
+ raise ArgumentError, "can't get const #{class_path}: #{e}"
+ end
+
+ if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
create_additions_warning if create_additions.nil?
object = klass.json_create(object)
end
@@ -87,31 +92,32 @@ module JSON
opts
end
- GEM_ROOT = File.expand_path("../../../", __FILE__) + "/"
def create_additions_warning
- message = "JSON.load implicit support for `create_additions: true` is deprecated " \
+ JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
"pass `create_additions: true`"
+ end
+ end
+ end
- uplevel = 4
- caller_locations(uplevel, 10).each do |frame|
- if frame.path.nil? || frame.path.start_with?(GEM_ROOT) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
- uplevel += 1
- else
- break
- end
- end
-
- if RUBY_VERSION >= "3.0"
- warn(message, uplevel: uplevel - 1, category: :deprecated)
+ class << self
+ def deprecation_warning(message, uplevel = 3) # :nodoc:
+ gem_root = File.expand_path("..", __dir__) + "/"
+ caller_locations(uplevel, 10).each do |frame|
+ if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
+ uplevel += 1
else
- warn(message, uplevel: uplevel - 1)
+ break
end
end
+
+ if RUBY_VERSION >= "3.0"
+ warn(message, uplevel: uplevel, category: :deprecated)
+ else
+ warn(message, uplevel: uplevel)
+ end
end
- end
- class << self
# :call-seq:
# JSON[object] -> new_array or new_string
#
@@ -123,7 +129,7 @@ module JSON
# Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
# ruby = [0, 1, nil]
# JSON[ruby] # => '[0,1,null]'
- def [](object, opts = {})
+ def [](object, opts = nil)
if object.is_a?(String)
return JSON.parse(object, opts)
elsif object.respond_to?(:to_str)
@@ -146,33 +152,25 @@ module JSON
const_set :Parser, parser
end
- # Return the constant located at _path_. The format of _path_ has to be
- # either ::A::B::C or A::B::C. In any case, A has to be located at the top
- # level (absolute namespace path?). If there doesn't exist a constant at
- # the given path, an ArgumentError is raised.
- def deep_const_get(path) # :nodoc:
- Object.const_get(path)
- rescue NameError => e
- raise ArgumentError, "can't get const #{path}: #{e}"
- end
-
# Set the module _generator_ to be used by JSON.
def generator=(generator) # :nodoc:
old, $VERBOSE = $VERBOSE, nil
@generator = generator
- generator_methods = generator::GeneratorMethods
- for const in generator_methods.constants
- klass = const_get(const)
- modul = generator_methods.const_get(const)
- klass.class_eval do
- instance_methods(false).each do |m|
- m.to_s == 'to_json' and remove_method m
+ if generator.const_defined?(:GeneratorMethods)
+ generator_methods = generator::GeneratorMethods
+ for const in generator_methods.constants
+ klass = const_get(const)
+ modul = generator_methods.const_get(const)
+ klass.class_eval do
+ instance_methods(false).each do |m|
+ m.to_s == 'to_json' and remove_method m
+ end
+ include modul
end
- include modul
end
end
self.state = generator::State
- const_set :State, self.state
+ const_set :State, state
ensure
$VERBOSE = old
end
@@ -185,6 +183,25 @@ module JSON
private
+ # Called from the extension when a hash has both string and symbol keys
+ def on_mixed_keys_hash(hash, do_raise)
+ set = {}
+ hash.each_key do |key|
+ key_str = key.to_s
+
+ if set[key_str]
+ message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
+ if do_raise
+ raise GeneratorError, message
+ else
+ deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
+ end
+ else
+ set[key_str] = true
+ end
+ end
+ end
+
def deprecated_singleton_attr_accessor(*attrs)
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
attrs.each do |attr|
@@ -220,32 +237,24 @@ module JSON
Thread.current[:"JSON.create_id"] || 'json_class'
end
- NaN = 0.0/0
+ NaN = Float::NAN
- Infinity = 1.0/0
+ Infinity = Float::INFINITY
MinusInfinity = -Infinity
# The base exception for JSON errors.
- class JSONError < StandardError
- def self.wrap(exception)
- obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}")
- obj.set_backtrace exception.backtrace
- obj
- end
- end
+ class JSONError < StandardError; end
# This exception is raised if a parser error occurs.
- class ParserError < JSONError; end
+ class ParserError < JSONError
+ attr_reader :line, :column
+ end
# This exception is raised if the nesting of parsed data structures is too
# deep.
class NestingError < ParserError; end
- # :stopdoc:
- class CircularDatastructure < NestingError; end
- # :startdoc:
-
# This exception is raised if a generator or unparser error occurs.
class GeneratorError < JSONError
attr_reader :invalid_object
@@ -276,7 +285,7 @@ module JSON
# to string interpolation.
#
# Note: no validation is performed on the provided string. It is the
- # responsability of the caller to ensure the string contains valid JSON.
+ # responsibility of the caller to ensure the string contains valid JSON.
Fragment = Struct.new(:json) do
def initialize(json)
unless string = String.try_convert(json)
@@ -398,7 +407,7 @@ module JSON
#
# Returns a \String containing the generated \JSON data.
#
- # See also JSON.fast_generate, JSON.pretty_generate.
+ # See also JSON.pretty_generate.
#
# Argument +obj+ is the Ruby object to be converted to \JSON.
#
@@ -498,7 +507,7 @@ module JSON
# }
#
def pretty_generate(obj, opts = nil)
- return state.generate(obj) if State === opts
+ return opts.generate(obj) if State === opts
options = PRETTY_GENERATE_OPTIONS
@@ -543,6 +552,7 @@ module JSON
:create_additions => nil,
}
# :call-seq:
+ # JSON.unsafe_load(source, options = {}) -> object
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
#
# Returns the Ruby objects created by parsing the given +source+.
@@ -650,6 +660,7 @@ module JSON
# when Array
# obj.map! {|v| deserialize_obj v }
# end
+ # obj
# })
# pp ruby
# Output:
@@ -673,7 +684,12 @@ module JSON
#
def unsafe_load(source, proc = nil, options = nil)
opts = if options.nil?
- _unsafe_load_default_options
+ if proc && proc.is_a?(Hash)
+ options, proc = proc, nil
+ options
+ else
+ _unsafe_load_default_options
+ end
else
_unsafe_load_default_options.merge(options)
end
@@ -691,12 +707,17 @@ module JSON
if opts[:allow_blank] && (source.nil? || source.empty?)
source = 'null'
end
- result = parse(source, opts)
- recurse_proc(result, &proc) if proc
- result
+
+ if proc
+ opts = opts.dup
+ opts[:on_load] = proc.to_proc
+ end
+
+ parse(source, opts)
end
# :call-seq:
+ # JSON.load(source, options = {}) -> object
# JSON.load(source, proc = nil, options = {}) -> object
#
# Returns the Ruby objects created by parsing the given +source+.
@@ -810,6 +831,7 @@ module JSON
# when Array
# obj.map! {|v| deserialize_obj v }
# end
+ # obj
# })
# pp ruby
# Output:
@@ -832,8 +854,18 @@ module JSON
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
#
def load(source, proc = nil, options = nil)
+ if proc && options.nil? && proc.is_a?(Hash)
+ options = proc
+ proc = nil
+ end
+
opts = if options.nil?
- _load_default_options
+ if proc && proc.is_a?(Hash)
+ options, proc = proc, nil
+ options
+ else
+ _load_default_options
+ end
else
_load_default_options.merge(options)
end
@@ -848,7 +880,7 @@ module JSON
end
end
- if opts[:allow_blank] && (source.nil? || source.empty?)
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
source = 'null'
end
@@ -929,6 +961,68 @@ module JSON
end
end
+ # :stopdoc:
+ # All these were meant to be deprecated circa 2009, but were just set as undocumented
+ # so usage still exist in the wild.
+ def unparse(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
+ end
+ generate(...)
+ end
+ module_function :unparse
+
+ def fast_unparse(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
+ end
+ generate(...)
+ end
+ module_function :fast_unparse
+
+ def pretty_unparse(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
+ end
+ pretty_generate(...)
+ end
+ module_function :fast_unparse
+
+ def restore(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
+ end
+ load(...)
+ end
+ module_function :restore
+
+ class << self
+ private
+
+ def const_missing(const_name)
+ case const_name
+ when :PRETTY_STATE_PROTOTYPE
+ if RUBY_VERSION >= "3.0"
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
+ end
+ state.new(PRETTY_GENERATE_OPTIONS)
+ else
+ super
+ end
+ end
+ end
+ # :startdoc:
+
# JSON::Coder holds a parser and generator configuration.
#
# module MyApp
@@ -944,10 +1038,11 @@ module JSON
# JSON.new(options = nil, &block)
#
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
- # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
#
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
- # encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
+ # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
# \JSON counterpart:
#
# module MyApp
@@ -973,7 +1068,7 @@ module JSON
options[:as_json] = as_json if as_json
@state = State.new(options).freeze
- @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
+ @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
end
# call-seq:
@@ -982,7 +1077,7 @@ module JSON
#
# Serialize the given object into a \JSON document.
def dump(object, io = nil)
- @state.generate_new(object, io)
+ @state.generate(object, io)
end
alias_method :generate, :dump
@@ -1003,6 +1098,30 @@ module JSON
load(File.read(path, encoding: Encoding::UTF_8))
end
end
+
+ module GeneratorMethods
+ # call-seq: to_json(*)
+ #
+ # Converts this object into a JSON string.
+ # If this object doesn't directly maps to a JSON native type,
+ # first convert it to a string (calling #to_s), then converts
+ # it to a JSON string, and returns the result.
+ # This is a fallback, if no special method #to_json was defined for some object.
+ def to_json(state = nil, *)
+ obj = case self
+ when nil, false, true, Integer, Float, Array, Hash
+ self
+ else
+ "#{self}"
+ end
+
+ if state.nil?
+ JSON::State._generate_no_fallback(obj, nil, nil)
+ else
+ JSON::State.from_state(state)._generate_no_fallback(obj)
+ end
+ end
+ end
end
module ::Kernel
@@ -1011,8 +1130,14 @@ module ::Kernel
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
# one line.
def j(*objs)
+ if RUBY_VERSION >= "3.0"
+ warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
+ else
+ warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
+ end
+
objs.each do |obj|
- puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
+ puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
end
nil
end
@@ -1020,8 +1145,14 @@ module ::Kernel
# Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
# indentation and over many lines.
def jj(*objs)
+ if RUBY_VERSION >= "3.0"
+ warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
+ else
+ warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
+ end
+
objs.each do |obj|
- puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
+ puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
end
nil
end
@@ -1032,16 +1163,11 @@ module ::Kernel
#
# The _opts_ argument is passed through to generate/parse respectively. See
# generate and parse for their documentation.
- def JSON(object, *args)
- if object.is_a?(String)
- return JSON.parse(object, args.first)
- elsif object.respond_to?(:to_str)
- str = object.to_str
- if str.is_a?(String)
- return JSON.parse(object.to_str, args.first)
- end
- end
-
- JSON.generate(object, args.first)
+ def JSON(object, opts = nil)
+ JSON[object, opts]
end
end
+
+class Object
+ include JSON::GeneratorMethods
+end
diff --git a/ext/json/lib/json/ext.rb b/ext/json/lib/json/ext.rb
index 1db5ea122c..5bacc5e371 100644
--- a/ext/json/lib/json/ext.rb
+++ b/ext/json/lib/json/ext.rb
@@ -34,12 +34,12 @@ module JSON
if RUBY_ENGINE == 'truffleruby'
require 'json/truffle_ruby/generator'
- JSON.generator = ::JSON::TruffleRuby::Generator
+ JSON.generator = JSON::TruffleRuby::Generator
else
require 'json/ext/generator'
JSON.generator = Generator
end
end
- JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
+ JSON_LOADED = true unless defined?(JSON::JSON_LOADED)
end
diff --git a/ext/json/lib/json/ext/generator/state.rb b/ext/json/lib/json/ext/generator/state.rb
index d40c3b5ec3..e4f425af6a 100644
--- a/ext/json/lib/json/ext/generator/state.rb
+++ b/ext/json/lib/json/ext/generator/state.rb
@@ -8,20 +8,8 @@ module JSON
#
# Instantiates a new State object, configured by _opts_.
#
- # _opts_ can have the following keys:
- #
- # * *indent*: a string used to indent levels (default: ''),
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
- # generated, otherwise an exception is thrown, if these values are
- # encountered. This options defaults to false.
- # * *ascii_only*: true if only ASCII characters should be generated. This
- # option defaults to false.
- # * *buffer_initial_length*: sets the initial length of the generator's
- # internal buffer.
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
+ # See {Generating Options}[rdoc-ref:JSON@Generating+Options].
def initialize(opts = nil)
if opts && !opts.empty?
configure(opts)
@@ -68,6 +56,11 @@ module JSON
buffer_initial_length: buffer_initial_length,
}
+ allow_duplicate_key = allow_duplicate_key?
+ unless allow_duplicate_key.nil?
+ result[:allow_duplicate_key] = allow_duplicate_key
+ end
+
instance_variables.each do |iv|
iv = iv.to_s[1..-1]
result[iv.to_sym] = self[iv]
@@ -82,6 +75,8 @@ module JSON
#
# Returns the value returned by method +name+.
def [](name)
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
+
if respond_to?(name)
__send__(name)
else
@@ -94,6 +89,8 @@ module JSON
#
# Sets the attribute name to value.
def []=(name, value)
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
+
if respond_to?(name_writer = "#{name}=")
__send__ name_writer, value
else
diff --git a/ext/json/lib/json/generic_object.rb b/ext/json/lib/json/generic_object.rb
index ec5aa9dcb2..5c8ace354b 100644
--- a/ext/json/lib/json/generic_object.rb
+++ b/ext/json/lib/json/generic_object.rb
@@ -52,14 +52,6 @@ module JSON
table
end
- def [](name)
- __send__(name)
- end unless method_defined?(:[])
-
- def []=(name, value)
- __send__("#{name}=", value)
- end unless method_defined?(:[]=)
-
def |(other)
self.class[other.to_hash.merge(to_hash)]
end
diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb
index 9c21f18b35..30c0a71d2f 100644
--- a/ext/json/lib/json/version.rb
+++ b/ext/json/lib/json/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module JSON
- VERSION = '2.10.2'
+ VERSION = '2.19.8'
end
diff --git a/ext/json/parser/depend b/ext/json/parser/depend
index 0c1becfb60..d4737b1dfb 100644
--- a/ext/json/parser/depend
+++ b/ext/json/parser/depend
@@ -141,6 +141,7 @@ parser.o: $(hdrdir)/ruby/internal/intern/re.h
parser.o: $(hdrdir)/ruby/internal/intern/ruby.h
parser.o: $(hdrdir)/ruby/internal/intern/select.h
parser.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+parser.o: $(hdrdir)/ruby/internal/intern/set.h
parser.o: $(hdrdir)/ruby/internal/intern/signal.h
parser.o: $(hdrdir)/ruby/internal/intern/sprintf.h
parser.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -174,5 +175,8 @@ parser.o: $(hdrdir)/ruby/ruby.h
parser.o: $(hdrdir)/ruby/st.h
parser.o: $(hdrdir)/ruby/subst.h
parser.o: $(srcdir)/../fbuffer/fbuffer.h
+parser.o: $(srcdir)/../json.h
+parser.o: $(srcdir)/../simd/simd.h
+parser.o: $(srcdir)/../vendor/ryu.h
parser.o: parser.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb
index 09c9637788..a9d740c755 100644
--- a/ext/json/parser/extconf.rb
+++ b/ext/json/parser/extconf.rb
@@ -1,11 +1,21 @@
# frozen_string_literal: true
require 'mkmf'
-have_func("rb_enc_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
+$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
+have_func("rb_enc_interned_str", "ruby/encoding.h") # RUBY_VERSION >= 3.0
+have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
-have_func("strnlen", "string.h") # Missing on Solaris 10
+have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1
+
+if RUBY_ENGINE == "ruby"
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
+end
append_cflags("-std=c99")
+if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
+ load __dir__ + "/../simd/conf.rb"
+end
+
create_makefile 'json/ext/parser'
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index f20769a365..d0482f6861 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -1,48 +1,22 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-/* shims */
-/* This is the fallback definition from Ruby 3.4 */
-
-#ifndef RBIMPL_STDBOOL_H
-#if defined(__cplusplus)
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#elif defined(HAVE_STDBOOL_H)
-# include <stdbool.h>
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
-#endif
-#endif
-
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
-#ifndef RB_LIKELY
-#define RB_LIKELY(expr) expr
-#endif
+#include "../json.h"
+#include "../vendor/ryu.h"
+#include "../simd/simd.h"
static VALUE mJSON, eNestingError, Encoding_UTF_8;
static VALUE CNaN, CInfinity, CMinusInfinity;
-static ID i_chr, i_aset, i_aref,
- i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
+static ID i_new, i_try_convert, i_uminus, i_encode;
-static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
- sym_decimal_class, sym_on_load;
+static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
+ sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
+ sym_allow_duplicate_key;
static int binary_encindex;
static int utf8_encindex;
#ifndef HAVE_RB_HASH_BULK_INSERT
// For TruffleRuby
-void
+static void
rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
{
long index = 0;
@@ -59,6 +33,12 @@ rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
#define rb_hash_new_capa(n) rb_hash_new()
#endif
+#ifndef HAVE_RB_STR_TO_INTERNED_STR
+static VALUE rb_str_to_interned_str(VALUE str)
+{
+ return rb_funcall(rb_str_freeze(str), i_uminus, 0);
+}
+#endif
/* name cache */
@@ -104,116 +84,104 @@ static void rvalue_cache_insert_at(rvalue_cache *cache, int index, VALUE rstring
cache->entries[index] = rstring;
}
-static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
+#define rstring_cache_memcmp memcmp
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+#if __has_builtin(__builtin_bswap64)
+#undef rstring_cache_memcmp
+ALWAYS_INLINE(static) int rstring_cache_memcmp(const char *str, const char *rptr, const long length)
{
- long rstring_length = RSTRING_LEN(rstring);
- if (length == rstring_length) {
- return memcmp(str, RSTRING_PTR(rstring), length);
- } else {
- return (int)(length - rstring_length);
+ // The libc memcmp has numerous complex optimizations, but in this particular case,
+ // we know the string is small (JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH), so being able to
+ // inline a simpler memcmp outperforms calling the libc version.
+ long i = 0;
+
+ for (; i + 8 <= length; i += 8) {
+ uint64_t a, b;
+ memcpy(&a, str + i, 8);
+ memcpy(&b, rptr + i, 8);
+ if (a != b) {
+ a = __builtin_bswap64(a);
+ b = __builtin_bswap64(b);
+ return (a < b) ? -1 : 1;
+ }
+ }
+
+ for (; i < length; i++) {
+ if (str[i] != rptr[i]) {
+ return (str[i] < rptr[i]) ? -1 : 1;
+ }
}
+
+ return 0;
}
+#endif
+#endif
-static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
+ALWAYS_INLINE(static) int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
{
- if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
- // Common names aren't likely to be very long. So we just don't
- // cache names above an arbitrary threshold.
- return Qfalse;
- }
+ const char *rstring_ptr;
+ long rstring_length;
+
+ RSTRING_GETMEM(rstring, rstring_ptr, rstring_length);
- if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) {
- // Simple heuristic, if the first character isn't a letter,
- // we're much less likely to see this string again.
- // We mostly want to cache strings that are likely to be repeated.
- return Qfalse;
+ if (length == rstring_length) {
+ return rstring_cache_memcmp(str, rstring_ptr, length);
+ } else {
+ return (int)(length - rstring_length);
}
+}
+ALWAYS_INLINE(static) VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
+{
int low = 0;
int high = cache->length - 1;
- int mid = 0;
- int last_cmp = 0;
while (low <= high) {
- mid = (high + low) >> 1;
+ int mid = (high + low) >> 1;
VALUE entry = cache->entries[mid];
- last_cmp = rstring_cache_cmp(str, length, entry);
+ int cmp = rstring_cache_cmp(str, length, entry);
- if (last_cmp == 0) {
+ if (cmp == 0) {
return entry;
- } else if (last_cmp > 0) {
+ } else if (cmp > 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rstring = build_interned_string(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
- if (last_cmp > 0) {
- mid += 1;
- }
-
- rvalue_cache_insert_at(cache, mid, rstring);
+ rvalue_cache_insert_at(cache, low, rstring);
}
return rstring;
}
static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const long length)
{
- if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
- // Common names aren't likely to be very long. So we just don't
- // cache names above an arbitrary threshold.
- return Qfalse;
- }
-
- if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) {
- // Simple heuristic, if the first character isn't a letter,
- // we're much less likely to see this string again.
- // We mostly want to cache strings that are likely to be repeated.
- return Qfalse;
- }
-
int low = 0;
int high = cache->length - 1;
- int mid = 0;
- int last_cmp = 0;
while (low <= high) {
- mid = (high + low) >> 1;
+ int mid = (high + low) >> 1;
VALUE entry = cache->entries[mid];
- last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
+ int cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
- if (last_cmp == 0) {
+ if (cmp == 0) {
return entry;
- } else if (last_cmp > 0) {
+ } else if (cmp > 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rsymbol = build_symbol(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
- if (last_cmp > 0) {
- mid += 1;
- }
-
- rvalue_cache_insert_at(cache, mid, rsymbol);
+ rvalue_cache_insert_at(cache, low, rsymbol);
}
return rsymbol;
}
@@ -243,7 +211,7 @@ static rvalue_stack *rvalue_stack_grow(rvalue_stack *stack, VALUE *handle, rvalu
if (stack->type == RVALUE_STACK_STACK_ALLOCATED) {
stack = rvalue_stack_spill(stack, handle, stack_ref);
} else {
- REALLOC_N(stack->ptr, VALUE, required);
+ JSON_SIZED_REALLOC_N(stack->ptr, VALUE, required, stack->capa);
stack->capa = required;
}
return stack;
@@ -273,17 +241,27 @@ static void rvalue_stack_mark(void *ptr)
{
rvalue_stack *stack = (rvalue_stack *)ptr;
long index;
- for (index = 0; index < stack->head; index++) {
- rb_gc_mark(stack->ptr[index]);
+ if (stack && stack->ptr) {
+ for (index = 0; index < stack->head; index++) {
+ rb_gc_mark(stack->ptr[index]);
+ }
}
}
+static void rvalue_stack_free_buffer(rvalue_stack *stack)
+{
+ JSON_SIZED_FREE_N(stack->ptr, stack->capa);
+ stack->ptr = NULL;
+}
+
static void rvalue_stack_free(void *ptr)
{
rvalue_stack *stack = (rvalue_stack *)ptr;
if (stack) {
- ruby_xfree(stack->ptr);
- ruby_xfree(stack);
+ rvalue_stack_free_buffer(stack);
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ JSON_SIZED_FREE(stack);
+#endif
}
}
@@ -294,14 +272,13 @@ static size_t rvalue_stack_memsize(const void *ptr)
}
static const rb_data_type_t JSON_Parser_rvalue_stack_type = {
- "JSON::Ext::Parser/rvalue_stack",
- {
+ .wrap_struct_name = "JSON::Ext::Parser/rvalue_stack",
+ .function = {
.dmark = rvalue_stack_mark,
.dfree = rvalue_stack_free,
.dsize = rvalue_stack_memsize,
},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
};
static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref)
@@ -323,85 +300,13 @@ static void rvalue_stack_eagerly_release(VALUE handle)
if (handle) {
rvalue_stack *stack;
TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
- RTYPEDDATA_DATA(handle) = NULL;
+#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
+ rvalue_stack_free_buffer(stack);
+#else
rvalue_stack_free(stack);
- }
-}
-
-
-#ifndef HAVE_STRNLEN
-static size_t strnlen(const char *s, size_t maxlen)
-{
- char *p;
- return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
-}
-#endif
-
-#define PARSE_ERROR_FRAGMENT_LEN 32
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
+ RTYPEDDATA_DATA(handle) = NULL;
#endif
-static void raise_parse_error(const char *format, const char *start)
-{
- unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
-
- size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
- const char *ptr = start;
-
- if (len == PARSE_ERROR_FRAGMENT_LEN) {
- MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
-
- while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
- len--;
- }
-
- if (buffer[len - 1] >= 0xC0) { // multibyte character start
- len--;
- }
-
- buffer[len] = '\0';
- ptr = (const char *)buffer;
}
-
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
-}
-
-/* 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
-};
-
-static uint32_t unescape_unicode(const unsigned char *p)
-{
- signed char b;
- uint32_t result = 0;
- b = digit_values[p[0]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[1]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[2]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[3]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- return result;
}
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
@@ -430,90 +335,276 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
return len;
}
+enum duplicate_key_action {
+ JSON_DEPRECATED = 0,
+ JSON_IGNORE,
+ JSON_RAISE,
+};
+
typedef struct JSON_ParserStruct {
VALUE on_load_proc;
VALUE decimal_class;
ID decimal_method_id;
+ enum duplicate_key_action on_duplicate_key;
int max_nesting;
bool allow_nan;
bool allow_trailing_comma;
- bool parsing_name;
+ bool allow_control_characters;
+ bool allow_invalid_escape;
bool symbolize_names;
bool freeze;
} JSON_ParserConfig;
typedef struct JSON_ParserStateStruct {
- VALUE stack_handle;
+ VALUE *stack_handle;
+ const char *start;
const char *cursor;
const char *end;
rvalue_stack *stack;
rvalue_cache name_cache;
int in_array;
int current_nesting;
+ unsigned int emitted_deprecations;
} JSON_ParserState;
+static inline size_t rest(JSON_ParserState *state) {
+ return state->end - state->cursor;
+}
+
+static inline bool eos(JSON_ParserState *state) {
+ return state->cursor >= state->end;
+}
+
+static inline char peek(JSON_ParserState *state)
+{
+ if (RB_UNLIKELY(eos(state))) {
+ return 0;
+ }
+ return *state->cursor;
+}
+
+static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out)
+{
+ JSON_ASSERT(state->cursor <= state->end);
+
+ // Redundant but helpful for hardening
+ if (RB_UNLIKELY(state->cursor > state->end)) {
+ state->cursor = state->end;
+ }
+
+ const char *cursor = state->cursor;
+ long column = 0;
+ long line = 1;
+
+ while (cursor >= state->start) {
+ if (*cursor-- == '\n') {
+ break;
+ }
+ column++;
+ }
+
+ while (cursor >= state->start) {
+ if (*cursor-- == '\n') {
+ line++;
+ }
+ }
+ *line_out = line;
+ *column_out = column;
+}
+
+static void emit_parse_warning(const char *message, JSON_ParserState *state)
+{
+ long line, column;
+ cursor_position(state, &line, &column);
+
+ VALUE warning = rb_sprintf("%s at line %ld column %ld", message, line, column);
+ rb_funcall(mJSON, rb_intern("deprecation_warning"), 1, warning);
+}
+
+#define PARSE_ERROR_FRAGMENT_LEN 32
+
+static VALUE build_parse_error_message(const char *format, JSON_ParserState *state, long line, long column)
+{
+ unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
+
+ const char *ptr = "EOF";
+ if (state->cursor && state->cursor < state->end) {
+ ptr = state->cursor;
+ size_t len = 0;
+ while (len < PARSE_ERROR_FRAGMENT_LEN) {
+ char ch = ptr[len];
+ if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
+ break;
+ }
+ len++;
+ }
+
+ if (len) {
+ buffer[0] = '\'';
+ MEMCPY(buffer + 1, ptr, char, len);
+
+ while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
+ len--;
+ }
+
+ if (buffer[len] >= 0xC0) { // multibyte character start
+ len--;
+ }
+
+ buffer[len + 1] = '\'';
+ buffer[len + 2] = '\0';
+ ptr = (const char *)buffer;
+ }
+ }
+
+ VALUE message = rb_enc_sprintf(enc_utf8, format, ptr);
+ rb_str_catf(message, " at line %ld column %ld", line, column);
+ return message;
+}
+
+static VALUE parse_error_new(VALUE message, long line, long column)
+{
+ VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
+ rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
+ rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
+ return exc;
+}
+
+NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state)
+{
+ long line, column;
+ cursor_position(state, &line, &column);
+ VALUE message = build_parse_error_message(format, state, line, column);
+ rb_exc_raise(parse_error_new(message, line, column));
+}
+
+NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
+{
+ state->cursor = at;
+ raise_parse_error(format, state);
+}
+
+/* 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
+};
+
+static uint32_t unescape_unicode(JSON_ParserState *state, const char *sp, const char *spe)
+{
+ if (RB_UNLIKELY(sp > spe - 4)) {
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, sp - 2);
+ }
+
+ const unsigned char *p = (const unsigned char *)sp;
+
+ const signed char b0 = digit_values[p[0]];
+ const signed char b1 = digit_values[p[1]];
+ const signed char b2 = digit_values[p[2]];
+ const signed char b3 = digit_values[p[3]];
+
+ if (RB_UNLIKELY((signed char)(b0 | b1 | b2 | b3) < 0)) {
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, sp - 2);
+ }
+
+ return ((uint32_t)b0 << 12) | ((uint32_t)b1 << 8) | ((uint32_t)b2 << 4) | (uint32_t)b3;
+}
+
#define GET_PARSER_CONFIG \
JSON_ParserConfig *config; \
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
static const rb_data_type_t JSON_ParserConfig_type;
-static const bool whitespace[256] = {
- [' '] = 1,
- ['\t'] = 1,
- ['\n'] = 1,
- ['\r'] = 1,
- ['/'] = 1,
-};
-
-static void
+NOINLINE(static) void
json_eat_comments(JSON_ParserState *state)
{
- if (state->cursor + 1 < state->end) {
- switch(state->cursor[1]) {
- case '/': {
- state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
- if (!state->cursor) {
- state->cursor = state->end;
- } else {
- state->cursor++;
- }
- break;
+ const char *start = state->cursor;
+ state->cursor++;
+
+ switch (peek(state)) {
+ case '/': {
+ state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
+ if (!state->cursor) {
+ state->cursor = state->end;
+ } else {
+ state->cursor++;
}
- case '*': {
- state->cursor += 2;
- while (true) {
- state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
- if (!state->cursor) {
- state->cursor = state->end;
- raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
- } else {
- state->cursor++;
- if (state->cursor < state->end && *state->cursor == '/') {
- state->cursor++;
- break;
- }
- }
+ break;
+ }
+ case '*': {
+ state->cursor++;
+
+ while (true) {
+ const char *next_match = memchr(state->cursor, '*', state->end - state->cursor);
+ if (!next_match) {
+ raise_parse_error_at("unterminated comment, expected closing '*/'", state, start);
+ }
+
+ state->cursor = next_match + 1;
+ if (peek(state) == '/') {
+ state->cursor++;
+ break;
}
- break;
}
- default:
- raise_parse_error("unexpected token at '%s'", state->cursor);
- break;
+ break;
}
- } else {
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ default:
+ raise_parse_error_at("unexpected token %s", state, start);
+ break;
}
}
-static inline void
+ALWAYS_INLINE(static) void
json_eat_whitespace(JSON_ParserState *state)
{
- while (state->cursor < state->end && RB_UNLIKELY(whitespace[(unsigned char)*state->cursor])) {
- if (RB_LIKELY(*state->cursor != '/')) {
- state->cursor++;
- } else {
- json_eat_comments(state);
+ while (true) {
+ switch (peek(state)) {
+ case ' ':
+ state->cursor++;
+ break;
+ case '\n':
+ state->cursor++;
+
+ // Heuristic: if we see a newline, there is likely consecutive spaces after it.
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+ while (rest(state) > 8) {
+ uint64_t chunk;
+ memcpy(&chunk, state->cursor, sizeof(uint64_t));
+ if (chunk == 0x2020202020202020) {
+ state->cursor += 8;
+ continue;
+ }
+
+ uint32_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
+ state->cursor += consecutive_spaces;
+ break;
+ }
+#endif
+ break;
+ case '\t':
+ case '\r':
+ state->cursor++;
+ break;
+ case '/':
+ json_eat_comments(state);
+ break;
+
+ default:
+ return;
}
}
}
@@ -544,11 +635,22 @@ static inline VALUE build_string(const char *start, const char *end, bool intern
return result;
}
-static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize)
+static inline bool json_string_cacheable_p(const char *string, size_t length)
+{
+ // We mostly want to cache strings that are likely to be repeated.
+ // Simple heuristics:
+ // - Common names aren't likely to be very long. So we just don't cache names above an arbitrary threshold.
+ // - If the first character isn't a letter, we're much less likely to see this string again.
+ return length <= JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH && rb_isalpha(string[0]);
+}
+
+static inline VALUE json_string_fastpath(JSON_ParserState *state, JSON_ParserConfig *config, const char *string, const char *stringEnd, bool is_name)
{
+ bool intern = is_name || config->freeze;
+ bool symbolize = is_name && config->symbolize_names;
size_t bufferSize = stringEnd - string;
- if (is_name && state->in_array) {
+ if (is_name && state->in_array && RB_LIKELY(json_string_cacheable_p(string, bufferSize))) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
@@ -564,104 +666,129 @@ static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *st
return build_string(string, stringEnd, intern, symbolize);
}
-static VALUE json_string_unescape(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize)
-{
- size_t bufferSize = stringEnd - string;
- const char *p = string, *pe = string, *unescape, *bufferStart;
- char *buffer;
- int unescape_len;
- char buf[4];
+#define JSON_MAX_UNESCAPE_POSITIONS 16
+typedef struct _json_unescape_positions {
+ long size;
+ const char **positions;
+ unsigned long additional_backslashes;
+} JSON_UnescapePositions;
- if (is_name && state->in_array) {
- VALUE cached_key;
- if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
- } else {
- cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize);
+static inline const char *json_next_backslash(const char *pe, const char *stringEnd, JSON_UnescapePositions *positions)
+{
+ while (positions->size) {
+ positions->size--;
+ const char *next_position = positions->positions[0];
+ positions->positions++;
+ if (next_position >= pe) {
+ return next_position;
}
+ }
- if (RB_LIKELY(cached_key)) {
- return cached_key;
- }
+ if (positions->additional_backslashes) {
+ positions->additional_backslashes--;
+ return memchr(pe, '\\', stringEnd - pe);
}
+ return NULL;
+}
+
+NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_ParserConfig *config, const char *string, const char *stringEnd, bool is_name, JSON_UnescapePositions *positions)
+{
+ bool intern = is_name || config->freeze;
+ bool symbolize = is_name && config->symbolize_names;
+ size_t bufferSize = stringEnd - string;
+ const char *p = string, *pe = string, *bufferStart;
+ char *buffer;
+
VALUE result = rb_str_buf_new(bufferSize);
rb_enc_associate_index(result, utf8_encindex);
buffer = RSTRING_PTR(result);
bufferStart = buffer;
- while (pe < stringEnd && (pe = memchr(pe, '\\', stringEnd - pe))) {
- unescape = (char *) "?";
- unescape_len = 1;
+#define APPEND_CHAR(chr) *buffer++ = chr; p = ++pe;
+
+ while (pe < stringEnd && (pe = json_next_backslash(pe, stringEnd, positions))) {
if (pe > p) {
MEMCPY(buffer, p, char, pe - p);
buffer += pe - p;
}
switch (*++pe) {
+ case '"':
+ case '/':
+ p = pe; // nothing to unescape just need to skip the backslash
+ break;
+ case '\\':
+ APPEND_CHAR('\\');
+ break;
case 'n':
- unescape = (char *) "\n";
+ APPEND_CHAR('\n');
break;
case 'r':
- unescape = (char *) "\r";
+ APPEND_CHAR('\r');
break;
case 't':
- unescape = (char *) "\t";
- break;
- case '"':
- unescape = (char *) "\"";
- break;
- case '\\':
- unescape = (char *) "\\";
+ APPEND_CHAR('\t');
break;
case 'b':
- unescape = (char *) "\b";
+ APPEND_CHAR('\b');
break;
case 'f':
- unescape = (char *) "\f";
+ APPEND_CHAR('\f');
break;
- case 'u':
- if (pe > stringEnd - 5) {
- raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
- } else {
- uint32_t ch = unescape_unicode((unsigned char *) ++pe);
- pe += 3;
- /* To handle values above U+FFFF, we take a sequence of
- * \uXXXX escapes in the U+D800..U+DBFF then
- * U+DC00..U+DFFF ranges, take the low 10 bits from each
- * to make a 20-bit number, then add 0x10000 to get the
- * final codepoint.
- *
- * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling
- * Surrogate Pairs in UTF-16", and 23.6 "Surrogates
- * Area".
- */
- if ((ch & 0xFC00) == 0xD800) {
- pe++;
- if (pe > stringEnd - 6) {
- raise_parse_error("incomplete surrogate pair at '%s'", p);
- }
- if (pe[0] == '\\' && pe[1] == 'u') {
- uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
- ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
- | (sur & 0x3FF));
- pe += 5;
- } else {
- unescape = (char *) "?";
- break;
+ case 'u': {
+ uint32_t ch = unescape_unicode(state, ++pe, stringEnd);
+ pe += 3;
+ /* To handle values above U+FFFF, we take a sequence of
+ * \uXXXX escapes in the U+D800..U+DBFF then
+ * U+DC00..U+DFFF ranges, take the low 10 bits from each
+ * to make a 20-bit number, then add 0x10000 to get the
+ * final codepoint.
+ *
+ * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling
+ * Surrogate Pairs in UTF-16", and 23.6 "Surrogates
+ * Area".
+ */
+ if ((ch & 0xFC00) == 0xD800) {
+ pe++;
+ if (RB_LIKELY((pe <= stringEnd - 6) && memcmp(pe, "\\u", 2) == 0)) {
+ uint32_t sur = unescape_unicode(state, pe + 2, stringEnd);
+
+ if (RB_UNLIKELY((sur & 0xFC00) != 0xDC00)) {
+ raise_parse_error_at("invalid surrogate pair at %s", state, p);
}
+
+ ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16) | (sur & 0x3FF));
+ pe += 5;
+ } else {
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
+ break;
}
- unescape_len = convert_UTF32_to_UTF8(buf, ch);
- unescape = buf;
}
+
+ int unescape_len = convert_UTF32_to_UTF8(buffer, ch);
+ buffer += unescape_len;
+ p = ++pe;
break;
+ }
default:
- p = pe;
- continue;
+ if ((unsigned char)*pe < 0x20) {
+ if (!config->allow_control_characters) {
+ if (*pe == '\n') {
+ raise_parse_error_at("Invalid unescaped newline character (\\n) in string: %s", state, pe - 1);
+ }
+ raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
+ }
+ }
+
+ if (config->allow_invalid_escape) {
+ APPEND_CHAR(*pe);
+ } else {
+ raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
+ }
+ break;
}
- MEMCPY(buffer, unescape, char, unescape_len);
- buffer += unescape_len;
- p = ++pe;
}
+#undef APPEND_CHAR
if (stringEnd > p) {
MEMCPY(buffer, p, char, stringEnd - p);
@@ -672,81 +799,93 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
if (symbolize) {
result = rb_str_intern(result);
} else if (intern) {
- result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
+ result = rb_str_to_interned_str(result);
}
return result;
}
#define MAX_FAST_INTEGER_SIZE 18
-static inline VALUE fast_decode_integer(const char *p, const char *pe)
-{
- bool negative = false;
- if (*p == '-') {
- negative = true;
- p++;
- }
+#define MAX_NUMBER_STACK_BUFFER 128
- long long memo = 0;
- while (p < pe) {
- memo *= 10;
- memo += *p - '0';
- p++;
- }
+typedef VALUE (*json_number_decode_func_t)(const char *ptr);
- if (negative) {
- memo = -memo;
+static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func)
+{
+ if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) {
+ char buffer[MAX_NUMBER_STACK_BUFFER];
+ MEMCPY(buffer, start, char, len);
+ buffer[len] = '\0';
+ return func(buffer);
+ } else {
+ VALUE buffer_v = rb_str_tmp_new(len);
+ char *buffer = RSTRING_PTR(buffer_v);
+ MEMCPY(buffer, start, char, len);
+ buffer[len] = '\0';
+ VALUE number = func(buffer);
+ RB_GC_GUARD(buffer_v);
+ return number;
}
- return LL2NUM(memo);
}
-static VALUE json_decode_large_integer(const char *start, long len)
+static VALUE json_decode_inum(const char *buffer)
+{
+ return rb_cstr2inum(buffer, 10);
+}
+
+NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
{
- VALUE buffer_v;
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- VALUE number = rb_cstr2inum(buffer, 10);
- RB_ALLOCV_END(buffer_v);
- return number;
+ return json_decode_large_number(start, len, json_decode_inum);
}
-static inline VALUE
-json_decode_integer(const char *start, const char *end)
+static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
{
- long len = end - start;
- if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
- return fast_decode_integer(start, end);
+ if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
+ if (negative) {
+ return INT64T2NUM(-((int64_t)mantissa));
}
- return json_decode_large_integer(start, len);
+ return UINT64T2NUM(mantissa);
+ }
+
+ return json_decode_large_integer(start, end - start);
}
-static VALUE json_decode_large_float(const char *start, long len)
+static VALUE json_decode_dnum(const char *buffer)
{
- VALUE buffer_v;
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1));
- RB_ALLOCV_END(buffer_v);
- return number;
+ return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
}
-static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, const char *end)
+NOINLINE(static) VALUE json_decode_large_float(const char *start, long len)
{
- long len = end - start;
+ return json_decode_large_number(start, len, json_decode_dnum);
+}
+/* Ruby JSON optimized float decoder using vendored Ryu algorithm
+ * Accepts pre-extracted mantissa and exponent from first-pass validation
+ */
+static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int64_t exponent, bool negative,
+ const char *start, const char *end)
+{
if (RB_UNLIKELY(config->decimal_class)) {
- VALUE text = rb_str_new(start, len);
+ VALUE text = rb_str_new(start, end - start);
return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text);
- } else if (RB_LIKELY(len < 64)) {
- char buffer[64];
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
- } else {
- return json_decode_large_float(start, len);
}
+
+ if (RB_UNLIKELY(exponent > INT32_MAX)) {
+ return negative ? CMinusInfinity : CInfinity;
+ }
+
+ if (RB_UNLIKELY(exponent < INT32_MIN)) {
+ return rb_float_new(negative ? -0.0 : 0.0);
+ }
+
+ // Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case)
+ // Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308)
+ if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) {
+ return json_decode_large_float(start, end - start);
+ }
+
+ return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, (int32_t)exponent, negative));
}
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
@@ -761,32 +900,79 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
return array;
}
-static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
+static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
{
- VALUE object = rb_hash_new_capa(count);
- rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
+ VALUE set = rb_hash_new_capa(count / 2);
+ for (size_t index = 0; index < count; index += 2) {
+ size_t before = RHASH_SIZE(set);
+ VALUE key = pairs[index];
+ rb_hash_aset(set, key, Qtrue);
+ if (RHASH_SIZE(set) == before) {
+ if (RB_SYMBOL_P(key)) {
+ return rb_sym2str(key);
+ }
+ return key;
+ }
+ }
+ return Qfalse;
+}
- rvalue_stack_pop(state->stack, count);
+NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
+{
+ VALUE message = rb_sprintf(
+ "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
+ rb_inspect(duplicate_key)
+ );
- if (config->freeze) {
- RB_OBJ_FREEZE(object);
- }
+ emit_parse_warning(RSTRING_PTR(message), state);
+ RB_GC_GUARD(message);
+}
- return object;
+NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
+{
+ VALUE message = rb_sprintf(
+ "duplicate key %"PRIsVALUE,
+ rb_inspect(duplicate_key)
+ );
+
+ long line, column;
+ cursor_position(state, &line, &column);
+ rb_str_concat(message, build_parse_error_message("", state, line, column)) ;
+ rb_exc_raise(parse_error_new(message, line, column));
}
-static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
+static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
{
- VALUE string;
- bool intern = is_name || config->freeze;
- bool symbolize = is_name && config->symbolize_names;
- if (escaped) {
- string = json_string_unescape(state, start, end, is_name, intern, symbolize);
- } else {
- string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
+ size_t entries_count = count / 2;
+ VALUE object = rb_hash_new_capa(entries_count);
+ const VALUE *pairs = rvalue_stack_peek(state->stack, count);
+ rb_hash_bulk_insert(count, pairs, object);
+
+ if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
+ switch (config->on_duplicate_key) {
+ case JSON_IGNORE:
+ break;
+ case JSON_DEPRECATED:
+ // Only emit the first few deprecations to avoid spamming.
+ if (state->emitted_deprecations < 5) {
+ emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
+ state->emitted_deprecations++;
+ }
+
+ break;
+ case JSON_RAISE:
+ raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
+ break;
+ }
+ }
+
+ rvalue_stack_pop(state->stack, count);
+
+ if (config->freeze) {
+ RB_OBJ_FREEZE(object);
}
- return string;
+ return object;
}
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
@@ -794,11 +980,11 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
if (RB_UNLIKELY(config->on_load_proc)) {
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
}
- rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
+ rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack);
return value;
}
-static const bool string_scan[256] = {
+static const bool string_scan_table[256] = {
// ASCII Control Characters
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -811,157 +997,319 @@ static const bool string_scan[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
+#ifdef HAVE_SIMD
+static SIMD_Implementation simd_impl = SIMD_NONE;
+#endif /* HAVE_SIMD */
+
+ALWAYS_INLINE(static) bool string_scan(JSON_ParserState *state)
{
- state->cursor++;
- const char *start = state->cursor;
- bool escaped = false;
+#ifdef HAVE_SIMD
+#if defined(HAVE_SIMD_NEON)
- while (state->cursor < state->end) {
- if (RB_UNLIKELY(string_scan[(unsigned char)*state->cursor])) {
- switch (*state->cursor) {
- case '"': {
- VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
- state->cursor++;
- return json_push_value(state, config, string);
- }
- case '\\': {
- state->cursor++;
- escaped = true;
- if ((unsigned char)*state->cursor < 0x20) {
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
- }
- break;
+ uint64_t mask = 0;
+ if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
+ state->cursor += trailing_zeros64(mask) >> 2;
+ return true;
+ }
+
+#elif defined(HAVE_SIMD_SSE2)
+ if (simd_impl == SIMD_SSE2) {
+ int mask = 0;
+ if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
+ state->cursor += trailing_zeros(mask);
+ return true;
+ }
+ }
+#endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
+#endif /* HAVE_SIMD */
+
+ while (!eos(state)) {
+ if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
+ return true;
+ }
+ state->cursor++;
+ }
+
+ // If the string ended with an unterminated escape sequence, we might
+ // have gone past the end.
+ if (RB_UNLIKELY(state->cursor > state->end)) {
+ state->cursor = state->end;
+ }
+
+ return false;
+}
+
+static VALUE json_parse_escaped_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name, const char *start)
+{
+ const char *backslashes[JSON_MAX_UNESCAPE_POSITIONS];
+ JSON_UnescapePositions positions = {
+ .size = 0,
+ .positions = backslashes,
+ .additional_backslashes = 0,
+ };
+
+ do {
+ switch (*state->cursor) {
+ case '"': {
+ VALUE string = json_string_unescape(state, config, start, state->cursor, is_name, &positions);
+ state->cursor++;
+ return json_push_value(state, config, string);
+ }
+ case '\\': {
+ if (RB_LIKELY(positions.size < JSON_MAX_UNESCAPE_POSITIONS)) {
+ backslashes[positions.size] = state->cursor;
+ positions.size++;
+ } else {
+ positions.additional_backslashes++;
}
- default:
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
- break;
+ state->cursor++;
+ break;
}
+ default:
+ if (!config->allow_control_characters) {
+ raise_parse_error("invalid ASCII control character in string: %s", state);
+ }
+ break;
}
state->cursor++;
- }
+ } while (string_scan(state));
- raise_parse_error("unexpected end of input, expected closing \"", state->cursor);
+ raise_parse_error("unexpected end of input, expected closing \"", state);
return Qfalse;
}
+ALWAYS_INLINE(static) VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
+{
+ state->cursor++;
+ const char *start = state->cursor;
+
+ if (RB_UNLIKELY(!string_scan(state))) {
+ raise_parse_error("unexpected end of input, expected closing \"", state);
+ }
+
+ if (RB_LIKELY(*state->cursor == '"')) {
+ VALUE string = json_string_fastpath(state, config, start, state->cursor, is_name);
+ state->cursor++;
+ return json_push_value(state, config, string);
+ }
+ return json_parse_escaped_string(state, config, is_name, start);
+}
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+// From: https://lemire.me/blog/2022/01/21/swar-explained-parsing-eight-digits/
+// Additional References:
+// https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+// http://0x80.pl/notesen/2014-10-12-parsing-decimal-numbers-part-1-swar.html
+static inline uint64_t decode_8digits_unrolled(uint64_t val) {
+ const uint64_t mask = 0x000000FF000000FF;
+ const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
+ const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
+ val -= 0x3030303030303030;
+ val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
+ val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
+ return val;
+}
+
+static inline uint64_t decode_4digits_unrolled(uint32_t val) {
+ const uint32_t mask = 0x000000FF;
+ const uint32_t mul1 = 100;
+ val -= 0x30303030;
+ val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
+ val = ((val & mask) * mul1) + (((val >> 16) & mask));
+ return val;
+}
+#endif
+
+static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulator)
+{
+ const char *start = state->cursor;
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+ while (rest(state) >= sizeof(uint64_t)) {
+ uint64_t next_8bytes;
+ memcpy(&next_8bytes, state->cursor, sizeof(uint64_t));
+
+ // From: https://github.com/simdjson/simdjson/blob/32b301893c13d058095a07d9868edaaa42ee07aa/include/simdjson/generic/numberparsing.h#L333
+ // Branchless version of: http://0x80.pl/articles/swar-digits-validate.html
+ uint64_t match = (next_8bytes & 0xF0F0F0F0F0F0F0F0) | (((next_8bytes + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4);
+
+ if (match == 0x3333333333333333) { // 8 consecutive digits
+ *accumulator = (*accumulator * 100000000) + decode_8digits_unrolled(next_8bytes);
+ state->cursor += 8;
+ continue;
+ }
+
+ uint32_t consecutive_digits = trailing_zeros64(match ^ 0x3333333333333333) / CHAR_BIT;
+
+ if (consecutive_digits >= 4) {
+ *accumulator = (*accumulator * 10000) + decode_4digits_unrolled((uint32_t)next_8bytes);
+ state->cursor += 4;
+ consecutive_digits -= 4;
+ }
+
+ while (consecutive_digits) {
+ *accumulator = *accumulator * 10 + (*state->cursor - '0');
+ consecutive_digits--;
+ state->cursor++;
+ }
+
+ return (int)(state->cursor - start);
+ }
+#endif
+
+ char next_char;
+ while (rb_isdigit(next_char = peek(state))) {
+ *accumulator = *accumulator * 10 + (next_char - '0');
+ state->cursor++;
+ }
+ return (int)(state->cursor - start);
+}
+
+static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig *config, bool negative, const char *start)
+{
+ bool integer = true;
+ const char first_digit = *state->cursor;
+
+ // Variables for Ryu optimization - extract digits during parsing
+ int64_t exponent = 0;
+ int decimal_point_pos = -1;
+ uint64_t mantissa = 0;
+
+ // Parse integer part and extract mantissa digits
+ int mantissa_digits = json_parse_digits(state, &mantissa);
+
+ if (RB_UNLIKELY((first_digit == '0' && mantissa_digits > 1) || (negative && mantissa_digits == 0))) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+
+ // Parse fractional part
+ if (peek(state) == '.') {
+ integer = false;
+ decimal_point_pos = mantissa_digits; // Remember position of decimal point
+ state->cursor++;
+
+ int fractional_digits = json_parse_digits(state, &mantissa);
+ mantissa_digits += fractional_digits;
+
+ if (RB_UNLIKELY(!fractional_digits)) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+ }
+
+ // Parse exponent
+ if (rb_tolower(peek(state)) == 'e') {
+ integer = false;
+ state->cursor++;
+
+ bool negative_exponent = false;
+ const char next_char = peek(state);
+ if (next_char == '-' || next_char == '+') {
+ negative_exponent = next_char == '-';
+ state->cursor++;
+ }
+
+ uint64_t abs_exponent = 0;
+ int exponent_digits = json_parse_digits(state, &abs_exponent);
+
+ if (RB_UNLIKELY(!exponent_digits)) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+
+ if (RB_UNLIKELY(exponent_digits >= 20 || abs_exponent > (uint64_t)INT64_MAX)) {
+ exponent = negative_exponent ? INT64_MIN : INT64_MAX;
+ } else {
+ exponent = negative_exponent ? -(int64_t)abs_exponent : (int64_t)abs_exponent;
+ }
+ }
+
+ if (integer) {
+ return json_decode_integer(mantissa, mantissa_digits, negative, start, state->cursor);
+ }
+
+ // Adjust exponent based on decimal point position
+ if (decimal_point_pos >= 0) {
+ exponent -= (mantissa_digits - decimal_point_pos);
+ }
+
+ return json_decode_float(config, mantissa, mantissa_digits, exponent, negative, start, state->cursor);
+}
+
+static inline VALUE json_parse_positive_number(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ return json_parse_number(state, config, false, state->cursor);
+}
+
+static inline VALUE json_parse_negative_number(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ const char *start = state->cursor;
+ state->cursor++;
+ return json_parse_number(state, config, true, start);
+}
+
static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
{
json_eat_whitespace(state);
- if (state->cursor >= state->end) {
- raise_parse_error("unexpected end of input", state->cursor);
- }
- switch (*state->cursor) {
+ switch (peek(state)) {
case 'n':
- if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
+ if (rest(state) >= 4 && (memcmp(state->cursor, "null", 4) == 0)) {
state->cursor += 4;
return json_push_value(state, config, Qnil);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 't':
- if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
+ if (rest(state) >= 4 && (memcmp(state->cursor, "true", 4) == 0)) {
state->cursor += 4;
return json_push_value(state, config, Qtrue);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 'f':
// Note: memcmp with a small power of two compile to an integer comparison
- if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
+ if (rest(state) >= 5 && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
state->cursor += 5;
return json_push_value(state, config, Qfalse);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 'N':
// Note: memcmp with a small power of two compile to an integer comparison
- if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
+ if (config->allow_nan && rest(state) >= 3 && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
state->cursor += 3;
return json_push_value(state, config, CNaN);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 'I':
- if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
+ if (config->allow_nan && rest(state) >= 8 && (memcmp(state->cursor, "Infinity", 8) == 0)) {
state->cursor += 8;
return json_push_value(state, config, CInfinity);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
- case '-':
+ case '-': {
// Note: memcmp with a small power of two compile to an integer comparison
- if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
+ if (rest(state) >= 9 && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
if (config->allow_nan) {
state->cursor += 9;
return json_push_value(state, config, CMinusInfinity);
} else {
- raise_parse_error("unexpected token at '%s'", state->cursor);
- }
- }
- // Fallthrough
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
- bool integer = true;
-
- // /\A-?(0|[1-9]\d*)(\.\d+)?([Ee][-+]?\d+)?/
- const char *start = state->cursor;
- state->cursor++;
-
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
- }
-
- long integer_length = state->cursor - start;
-
- if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
- raise_parse_error("invalid number: %s", start);
- } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
- raise_parse_error("invalid number: %s", start);
- } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
- raise_parse_error("invalid number: %s", start);
- }
-
- if ((state->cursor < state->end) && (*state->cursor == '.')) {
- integer = false;
- state->cursor++;
-
- if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
- raise_parse_error("invalid number: %s", state->cursor);
- }
-
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
- }
- }
-
- if ((state->cursor < state->end) && ((*state->cursor == 'e') || (*state->cursor == 'E'))) {
- integer = false;
- state->cursor++;
- if ((state->cursor < state->end) && ((*state->cursor == '+') || (*state->cursor == '-'))) {
- state->cursor++;
- }
-
- if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
- raise_parse_error("invalid number: %s", state->cursor);
- }
-
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
+ raise_parse_error("unexpected token %s", state);
}
}
-
- if (integer) {
- return json_push_value(state, config, json_decode_integer(start, state->cursor));
- }
- return json_push_value(state, config, json_decode_float(config, start, state->cursor));
+ return json_push_value(state, config, json_parse_negative_number(state, config));
+ break;
}
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
+ return json_push_value(state, config, json_parse_positive_number(state, config));
+ break;
case '"': {
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
return json_parse_string(state, config, false);
@@ -972,7 +1320,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
json_eat_whitespace(state);
long stack_head = state->stack->head;
- if ((state->cursor < state->end) && (*state->cursor == ']')) {
+ if (peek(state) == ']') {
state->cursor++;
return json_push_value(state, config, json_decode_array(state, config, 0));
} else {
@@ -987,38 +1335,40 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
while (true) {
json_eat_whitespace(state);
- if (state->cursor < state->end) {
- if (*state->cursor == ']') {
- state->cursor++;
- long count = state->stack->head - stack_head;
- state->current_nesting--;
- state->in_array--;
- return json_push_value(state, config, json_decode_array(state, config, count));
- }
+ const char next_char = peek(state);
- if (*state->cursor == ',') {
- state->cursor++;
- if (config->allow_trailing_comma) {
- json_eat_whitespace(state);
- if ((state->cursor < state->end) && (*state->cursor == ']')) {
- continue;
- }
+ if (RB_LIKELY(next_char == ',')) {
+ state->cursor++;
+ if (config->allow_trailing_comma) {
+ json_eat_whitespace(state);
+ if (peek(state) == ']') {
+ continue;
}
- json_parse_any(state, config);
- continue;
}
+ json_parse_any(state, config);
+ continue;
}
- raise_parse_error("expected ',' or ']' after array value", state->cursor);
+ if (next_char == ']') {
+ state->cursor++;
+ long count = state->stack->head - stack_head;
+ state->current_nesting--;
+ state->in_array--;
+ return json_push_value(state, config, json_decode_array(state, config, count));
+ }
+
+ raise_parse_error("expected ',' or ']' after array value", state);
}
break;
}
case '{': {
+ const char *object_start_cursor = state->cursor;
+
state->cursor++;
json_eat_whitespace(state);
long stack_head = state->stack->head;
- if ((state->cursor < state->end) && (*state->cursor == '}')) {
+ if (peek(state) == '}') {
state->cursor++;
return json_push_value(state, config, json_decode_object(state, config, 0));
} else {
@@ -1027,14 +1377,14 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting);
}
- if (*state->cursor != '"') {
- raise_parse_error("expected object key, got '%s", state->cursor);
+ if (peek(state) != '"') {
+ raise_parse_error("expected object key, got %s", state);
}
json_parse_string(state, config, true);
json_eat_whitespace(state);
- if ((state->cursor >= state->end) || (*state->cursor != ':')) {
- raise_parse_error("expected ':' after object key", state->cursor);
+ if (peek(state) != ':') {
+ raise_parse_error("expected ':' after object key", state);
}
state->cursor++;
@@ -1044,59 +1394,70 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
while (true) {
json_eat_whitespace(state);
- if (state->cursor < state->end) {
- if (*state->cursor == '}') {
- state->cursor++;
- state->current_nesting--;
- long count = state->stack->head - stack_head;
- return json_push_value(state, config, json_decode_object(state, config, count));
- }
+ const char next_char = peek(state);
+ if (next_char == '}') {
+ state->cursor++;
+ state->current_nesting--;
+ size_t count = state->stack->head - stack_head;
- if (*state->cursor == ',') {
- state->cursor++;
- json_eat_whitespace(state);
+ // Temporary rewind cursor in case an error is raised
+ const char *final_cursor = state->cursor;
+ state->cursor = object_start_cursor;
+ VALUE object = json_decode_object(state, config, count);
+ state->cursor = final_cursor;
- if (config->allow_trailing_comma) {
- if ((state->cursor < state->end) && (*state->cursor == '}')) {
- continue;
- }
- }
+ return json_push_value(state, config, object);
+ }
- if (*state->cursor != '"') {
- raise_parse_error("expected object key, got: '%s'", state->cursor);
- }
- json_parse_string(state, config, true);
+ if (next_char == ',') {
+ state->cursor++;
+ json_eat_whitespace(state);
- json_eat_whitespace(state);
- if ((state->cursor >= state->end) || (*state->cursor != ':')) {
- raise_parse_error("expected ':' after object key, got: '%s", state->cursor);
+ if (config->allow_trailing_comma) {
+ if (peek(state) == '}') {
+ continue;
}
- state->cursor++;
+ }
- json_parse_any(state, config);
+ if (RB_UNLIKELY(peek(state) != '"')) {
+ raise_parse_error("expected object key, got: %s", state);
+ }
+ json_parse_string(state, config, true);
- continue;
+ json_eat_whitespace(state);
+ if (RB_UNLIKELY(peek(state) != ':')) {
+ raise_parse_error("expected ':' after object key, got: %s", state);
}
+ state->cursor++;
+
+ json_parse_any(state, config);
+
+ continue;
}
- raise_parse_error("expected ',' or '}' after object value, got: '%s'", state->cursor);
+ raise_parse_error("expected ',' or '}' after object value, got: %s", state);
}
break;
}
+ case 0:
+ raise_parse_error("unexpected end of input", state);
+ break;
+
default:
- raise_parse_error("unexpected character: '%s'", state->cursor);
+ raise_parse_error("unexpected character: %s", state);
break;
}
- raise_parse_error("unreacheable: '%s'", state->cursor);
+ raise_parse_error("unreachable: %s", state);
+ return Qundef;
}
static void json_ensure_eof(JSON_ParserState *state)
{
json_eat_whitespace(state);
- if (state->cursor != state->end) {
- raise_parse_error("unexpected token at end of stream '%s'", state->cursor);
+ if (!eos(state)) {
+ raise_parse_error("unexpected token at end of stream %s", state);
}
}
@@ -1114,37 +1475,56 @@ static void json_ensure_eof(JSON_ParserState *state)
static VALUE convert_encoding(VALUE source)
{
- int encindex = RB_ENCODING_GET(source);
+ StringValue(source);
+ int encindex = RB_ENCODING_GET(source);
- if (RB_LIKELY(encindex == utf8_encindex)) {
+ if (RB_LIKELY(encindex == utf8_encindex)) {
+ return source;
+ }
+
+ if (encindex == binary_encindex) {
+ // For historical reason, we silently reinterpret binary strings as UTF-8
+ return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
+ }
+
+ source = rb_funcall(source, i_encode, 1, Encoding_UTF_8);
+ StringValue(source);
return source;
- }
+}
- if (encindex == binary_encindex) {
- // For historical reason, we silently reinterpret binary strings as UTF-8
- return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
- }
+struct parser_config_init_args {
+ JSON_ParserConfig *config;
+ VALUE self;
+};
- return rb_funcall(source, i_encode, 1, Encoding_UTF_8);
+static void parser_config_wb_write(VALUE self, VALUE *dest, VALUE val)
+{
+ *dest = val;
+ if (self) RB_OBJ_WRITTEN(self, Qundef, val);
}
static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
{
- JSON_ParserConfig *config = (JSON_ParserConfig *)data;
-
- if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
- else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
- else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
- else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
- else if (key == sym_freeze) { config->freeze = RTEST(val); }
- else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
- else if (key == sym_decimal_class) {
+ struct parser_config_init_args *args = (struct parser_config_init_args *)data;
+ JSON_ParserConfig *config = args->config;
+ VALUE self = args->self;
+
+ if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
+ else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
+ else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
+ else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
+ else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
+ else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
+ else if (key == sym_freeze) { config->freeze = RTEST(val); }
+ else if (key == sym_on_load) { parser_config_wb_write(self, &config->on_load_proc, RTEST(val) ? val : Qfalse); }
+ else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
+ else if (key == sym_decimal_class) {
if (RTEST(val)) {
if (rb_respond_to(val, i_try_convert)) {
- config->decimal_class = val;
+ parser_config_wb_write(self, &config->decimal_class, val);
config->decimal_method_id = i_try_convert;
} else if (rb_respond_to(val, i_new)) {
- config->decimal_class = val;
+ parser_config_wb_write(self, &config->decimal_class, val);
config->decimal_method_id = i_new;
} else if (RB_TYPE_P(val, T_CLASS)) {
VALUE name = rb_class_name(val);
@@ -1153,7 +1533,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
if (last_colon) {
const char *mod_path_end = last_colon - 1;
VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
- config->decimal_class = rb_path_to_class(mod_path);
+ parser_config_wb_write(self, &config->decimal_class, rb_path_to_class(mod_path));
const char *method_name_beg = last_colon + 1;
long before_len = method_name_beg - name_cstr;
@@ -1161,7 +1541,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
VALUE method_name = rb_str_substr(name, before_len, len);
config->decimal_method_id = SYM2ID(rb_str_intern(method_name));
} else {
- config->decimal_class = rb_mKernel;
+ parser_config_wb_write(self, &config->decimal_class, rb_mKernel);
config->decimal_method_id = SYM2ID(rb_str_intern(name));
}
}
@@ -1171,16 +1551,21 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
return ST_CONTINUE;
}
-static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
+static void parser_config_init(JSON_ParserConfig *config, VALUE opts, VALUE self)
{
config->max_nesting = 100;
+ struct parser_config_init_args args = {
+ .config = config,
+ .self = self,
+ };
+
if (!NIL_P(opts)) {
Check_Type(opts, T_HASH);
if (RHASH_SIZE(opts) > 0) {
// We assume in most cases few keys are set so it's faster to go over
// the provided keys than to check all possible keys.
- rb_hash_foreach(opts, parser_config_init_i, (VALUE)config);
+ rb_hash_foreach(opts, parser_config_init_i, (VALUE)&args);
}
}
@@ -1211,19 +1596,24 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
*/
static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
{
+ rb_check_frozen(self);
GET_PARSER_CONFIG;
- parser_config_init(config, opts);
-
- RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
+ parser_config_init(config, opts, self);
return self;
}
-static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
+static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src)
{
- Vsource = convert_encoding(StringValue(Vsource));
- StringValue(Vsource);
+ VALUE Vsource = convert_encoding(src);
+
+ // Ensure the string isn't mutated under us.
+ // The classic API to use is `rb_str_locktmp`, but then we'd
+ // need to use `rb_protect` to make sure we always unlock.
+ if (Vsource == src) {
+ Vsource = rb_str_new_frozen(Vsource);
+ }
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
rvalue_stack stack = {
@@ -1232,10 +1622,18 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
.capa = RVALUE_STACK_INITIAL_CAPA,
};
+ long len;
+ const char *start;
+
+ RSTRING_GETMEM(Vsource, start, len);
+
+ VALUE stack_handle = 0;
JSON_ParserState _state = {
- .cursor = RSTRING_PTR(Vsource),
- .end = RSTRING_END(Vsource),
+ .start = start,
+ .cursor = start,
+ .end = start + len,
.stack = &stack,
+ .stack_handle = &stack_handle,
};
JSON_ParserState *state = &_state;
@@ -1243,8 +1641,9 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
// This may be skipped in case of exception, but
// it won't cause a leak.
- rvalue_stack_eagerly_release(state->stack_handle);
-
+ rvalue_stack_eagerly_release(stack_handle);
+ RB_GC_GUARD(stack_handle);
+ RB_GC_GUARD(Vsource);
json_ensure_eof(state);
return result;
@@ -1265,12 +1664,9 @@ static VALUE cParserConfig_parse(VALUE self, VALUE Vsource)
static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
{
- Vsource = convert_encoding(StringValue(Vsource));
- StringValue(Vsource);
-
JSON_ParserConfig _config = {0};
JSON_ParserConfig *config = &_config;
- parser_config_init(config, opts);
+ parser_config_init(config, opts, false);
return cParser_parse(config, Vsource);
}
@@ -1282,26 +1678,19 @@ static void JSON_ParserConfig_mark(void *ptr)
rb_gc_mark(config->decimal_class);
}
-static void JSON_ParserConfig_free(void *ptr)
-{
- JSON_ParserConfig *config = ptr;
- ruby_xfree(config);
-}
-
static size_t JSON_ParserConfig_memsize(const void *ptr)
{
return sizeof(JSON_ParserConfig);
}
static const rb_data_type_t JSON_ParserConfig_type = {
- "JSON::Ext::Parser/ParserConfig",
- {
+ .wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
+ .function = {
JSON_ParserConfig_mark,
- JSON_ParserConfig_free,
+ RUBY_DEFAULT_FREE,
JSON_ParserConfig_memsize,
},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
};
static VALUE cJSON_parser_s_allocate(VALUE klass)
@@ -1345,15 +1734,14 @@ void Init_parser(void)
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
+ sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
+ sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
sym_freeze = ID2SYM(rb_intern("freeze"));
sym_on_load = ID2SYM(rb_intern("on_load"));
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
+ sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
- i_chr = rb_intern("chr");
- 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_uminus = rb_intern("-@");
@@ -1362,4 +1750,8 @@ void Init_parser(void)
binary_encindex = rb_ascii8bit_encindex();
utf8_encindex = rb_utf8_encindex();
enc_utf8 = rb_utf8_encoding();
+
+#ifdef HAVE_SIMD
+ simd_impl = find_simd_implementation();
+#endif
}
diff --git a/ext/json/simd/conf.rb b/ext/json/simd/conf.rb
new file mode 100644
index 0000000000..76f774bc97
--- /dev/null
+++ b/ext/json/simd/conf.rb
@@ -0,0 +1,24 @@
+case RbConfig::CONFIG['host_cpu']
+when /^(arm|aarch64)/
+ # Try to compile a small program using NEON instructions
+ header, type, init, extra = 'arm_neon.h', 'uint8x16_t', 'vdupq_n_u8(32)', nil
+when /^(x86_64|x64)/
+ header, type, init, extra = 'x86intrin.h', '__m128i', '_mm_set1_epi8(32)', 'if (__builtin_cpu_supports("sse2")) { printf("OK"); }'
+end
+if header
+ if have_header(header) && try_compile(<<~SRC, '-Werror=implicit-function-declaration')
+ #{cpp_include(header)}
+ int main(int argc, char **argv) {
+ #{type} test = #{init};
+ #{extra}
+ if (argc > 100000) printf("%p", &test);
+ return 0;
+ }
+ SRC
+ $defs.push("-DJSON_ENABLE_SIMD")
+ else
+ puts "Disable SIMD"
+ end
+end
+
+have_header('cpuid.h')
diff --git a/ext/json/simd/simd.h b/ext/json/simd/simd.h
new file mode 100644
index 0000000000..611b41b066
--- /dev/null
+++ b/ext/json/simd/simd.h
@@ -0,0 +1,208 @@
+#include "../json.h"
+
+typedef enum {
+ SIMD_NONE,
+ SIMD_NEON,
+ SIMD_SSE2
+} SIMD_Implementation;
+
+#ifndef __has_builtin // Optional of course.
+ #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifdef __clang__
+# if __has_builtin(__builtin_ctzll)
+# define HAVE_BUILTIN_CTZLL 1
+# else
+# define HAVE_BUILTIN_CTZLL 0
+# endif
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+# define HAVE_BUILTIN_CTZLL 1
+#else
+# define HAVE_BUILTIN_CTZLL 0
+#endif
+
+static inline uint32_t trailing_zeros64(uint64_t input)
+{
+ JSON_ASSERT(input > 0); // __builtin_ctz(0) is undefined behavior
+
+#if HAVE_BUILTIN_CTZLL
+ return __builtin_ctzll(input);
+#else
+ uint32_t trailing_zeros = 0;
+ uint64_t temp = input;
+ while ((temp & 1) == 0 && temp > 0) {
+ trailing_zeros++;
+ temp >>= 1;
+ }
+ return trailing_zeros;
+#endif
+}
+
+static inline int trailing_zeros(int input)
+{
+ JSON_ASSERT(input > 0); // __builtin_ctz(0) is undefined behavior
+
+#if HAVE_BUILTIN_CTZLL
+ return __builtin_ctz(input);
+#else
+ int trailing_zeros = 0;
+ int temp = input;
+ while ((temp & 1) == 0 && temp > 0) {
+ trailing_zeros++;
+ temp >>= 1;
+ }
+ return trailing_zeros;
+#endif
+}
+
+#ifdef JSON_ENABLE_SIMD
+
+#define SIMD_MINIMUM_THRESHOLD 4
+
+ALWAYS_INLINE(static) void json_fast_memcpy16(char *dst, const char *src, size_t len)
+{
+ RBIMPL_ASSERT_OR_ASSUME(len < 16);
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD); // 4
+#if defined(__has_builtin) && __has_builtin(__builtin_memcpy)
+ // If __builtin_memcpy is available, use it to copy between SIMD_MINIMUM_THRESHOLD (4) and vec_len-1 (15) bytes.
+ // These copies overlap. The first copy will copy the first 8 (or 4) bytes. The second copy will copy
+ // the last 8 (or 4) bytes but overlap with the first copy. The overlapping bytes will be in the correct
+ // position in both copies.
+
+ // Please do not attempt to replace __builtin_memcpy with memcpy without profiling and/or looking at the
+ // generated assembly. On clang-specifically (tested on Apple clang version 17.0.0 (clang-1700.0.13.3)),
+ // when using memcpy, the compiler will notice the only difference is a 4 or 8 and generate a conditional
+ // select instruction instead of direct loads and stores with a branch. This ends up slower than the branch
+ // plus two loads and stores generated when using __builtin_memcpy.
+ if (len >= 8) {
+ __builtin_memcpy(dst, src, 8);
+ __builtin_memcpy(dst + len - 8, src + len - 8, 8);
+ } else {
+ __builtin_memcpy(dst, src, 4);
+ __builtin_memcpy(dst + len - 4, src + len - 4, 4);
+ }
+#else
+ MEMCPY(dst, src, char, len);
+#endif
+}
+
+#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
+#include <arm_neon.h>
+
+#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
+static inline SIMD_Implementation find_simd_implementation(void)
+{
+ return SIMD_NEON;
+}
+
+#define HAVE_SIMD 1
+#define HAVE_SIMD_NEON 1
+
+// See: https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon
+ALWAYS_INLINE(static) uint64_t neon_match_mask(uint8x16_t matches)
+{
+ const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches), 4);
+ const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
+ return mask & 0x8888888888888888ull;
+}
+
+ALWAYS_INLINE(static) uint64_t compute_chunk_mask_neon(const char *ptr)
+{
+ uint8x16_t chunk = vld1q_u8((const unsigned char *)ptr);
+
+ // Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
+ // https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/
+ const uint8x16_t too_low_or_dbl_quote = vcltq_u8(veorq_u8(chunk, vdupq_n_u8(2)), vdupq_n_u8(33));
+
+ uint8x16_t has_backslash = vceqq_u8(chunk, vdupq_n_u8('\\'));
+ uint8x16_t needs_escape = vorrq_u8(too_low_or_dbl_quote, has_backslash);
+ return neon_match_mask(needs_escape);
+}
+
+ALWAYS_INLINE(static) int string_scan_simd_neon(const char **ptr, const char *end, uint64_t *mask)
+{
+ while (*ptr + sizeof(uint8x16_t) <= end) {
+ uint64_t chunk_mask = compute_chunk_mask_neon(*ptr);
+ if (chunk_mask) {
+ *mask = chunk_mask;
+ return 1;
+ }
+ *ptr += sizeof(uint8x16_t);
+ }
+ return 0;
+}
+
+#endif /* ARM Neon Support.*/
+
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+
+#ifdef HAVE_X86INTRIN_H
+#include <x86intrin.h>
+
+#define HAVE_SIMD 1
+#define HAVE_SIMD_SSE2 1
+
+#ifdef HAVE_CPUID_H
+#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
+
+#if defined(__clang__) || defined(__GNUC__)
+#define TARGET_SSE2 __attribute__((target("sse2")))
+#else
+#define TARGET_SSE2
+#endif
+
+#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a)
+#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a)
+#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1))
+#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a)
+
+ALWAYS_INLINE(static) TARGET_SSE2 int compute_chunk_mask_sse2(const char *ptr)
+{
+ __m128i chunk = _mm_loadu_si128((__m128i const*)ptr);
+ // Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
+ // https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/
+ __m128i too_low_or_dbl_quote = _mm_cmplt_epu8(_mm_xor_si128(chunk, _mm_set1_epi8(2)), _mm_set1_epi8(33));
+ __m128i has_backslash = _mm_cmpeq_epi8(chunk, _mm_set1_epi8('\\'));
+ __m128i needs_escape = _mm_or_si128(too_low_or_dbl_quote, has_backslash);
+ return _mm_movemask_epi8(needs_escape);
+}
+
+ALWAYS_INLINE(static) TARGET_SSE2 int string_scan_simd_sse2(const char **ptr, const char *end, int *mask)
+{
+ while (*ptr + sizeof(__m128i) <= end) {
+ int chunk_mask = compute_chunk_mask_sse2(*ptr);
+ if (chunk_mask) {
+ *mask = chunk_mask;
+ return 1;
+ }
+ *ptr += sizeof(__m128i);
+ }
+
+ return 0;
+}
+
+#include <cpuid.h>
+#endif /* HAVE_CPUID_H */
+
+static inline SIMD_Implementation find_simd_implementation(void)
+{
+ // TODO Revisit. I think the SSE version now only uses SSE2 instructions.
+ if (__builtin_cpu_supports("sse2")) {
+ return SIMD_SSE2;
+ }
+
+ return SIMD_NONE;
+}
+
+#endif /* HAVE_X86INTRIN_H */
+#endif /* X86_64 Support */
+
+#endif /* JSON_ENABLE_SIMD */
+
+#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
+static inline SIMD_Implementation find_simd_implementation(void)
+{
+ return SIMD_NONE;
+}
+#endif
diff --git a/ext/json/vendor/fpconv.c b/ext/json/vendor/fpconv.c
index 2887c64885..6c9bc2c103 100644
--- a/ext/json/vendor/fpconv.c
+++ b/ext/json/vendor/fpconv.c
@@ -29,6 +29,10 @@
#include <string.h>
#include <stdint.h>
+#if JSON_DEBUG
+#include <assert.h>
+#endif
+
#define npowers 87
#define steppowers 8
#define firstpower -348 /* 10 ^ -348 */
@@ -41,7 +45,7 @@ typedef struct Fp {
int exp;
} Fp;
-static Fp powers_ten[] = {
+static const Fp powers_ten[] = {
{ 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
{ 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
{ 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
@@ -92,7 +96,7 @@ static Fp find_cachedpow10(int exp, int* k)
{
const double one_log_ten = 0.30102999566398114;
- int approx = -(exp + npowers) * one_log_ten;
+ int approx = (int)(-(exp + npowers) * one_log_ten);
int idx = (approx - firstpower) / steppowers;
while(1) {
@@ -123,7 +127,7 @@ static Fp find_cachedpow10(int exp, int* k)
#define absv(n) ((n) < 0 ? -(n) : (n))
#define minv(a, b) ((a) < (b) ? (a) : (b))
-static uint64_t tens[] = {
+static const uint64_t tens[] = {
10000000000000000000U, 1000000000000000000U, 100000000000000000U,
10000000000000000U, 1000000000000000U, 100000000000000U,
10000000000000U, 1000000000000U, 100000000000U,
@@ -244,7 +248,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
uint64_t part2 = upper->frac & (one.frac - 1);
int idx = 0, kappa = 10;
- uint64_t* divp;
+ const uint64_t* divp;
/* 1000000000 */
for(divp = tens + 10; kappa > 0; divp++) {
@@ -268,7 +272,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
}
/* 10 */
- uint64_t* unit = tens + 18;
+ const uint64_t* unit = tens + 18;
while(true) {
part2 *= 10;
@@ -320,15 +324,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
{
int exp = absv(K + ndigits - 1);
- int max_trailing_zeros = 7;
-
- if(neg) {
- max_trailing_zeros -= 1;
- }
-
- /* write plain integer */
- if(K >= 0 && (exp < (ndigits + max_trailing_zeros))) {
-
+ if(K >= 0 && exp < 15) {
memcpy(dest, digits, ndigits);
memset(dest + ndigits, '0', K);
@@ -340,7 +336,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
}
/* write decimal w/o scientific notation */
- if(K < 0 && (K > -7 || exp < 4)) {
+ if(K < 0 && (K > -7 || exp < 10)) {
int offset = ndigits - absv(K);
/* fp < 1.0 -> write leading zero */
if(offset <= 0) {
@@ -432,10 +428,12 @@ static int filter_special(double fp, char* dest)
*
* Input:
* fp -> the double to convert, dest -> destination buffer.
- * The generated string will never be longer than 24 characters.
- * Make sure to pass a pointer to at least 24 bytes of memory.
+ * The generated string will never be longer than 32 characters.
+ * Make sure to pass a pointer to at least 32 bytes of memory.
* The emitted string will not be null terminated.
*
+ *
+ *
* Output:
* The number of written characters.
*
@@ -443,7 +441,7 @@ static int filter_special(double fp, char* dest)
*
* void print(double d)
* {
- * char buf[24 + 1] // plus null terminator
+ * char buf[28 + 1] // plus null terminator
* int str_len = fpconv_dtoa(d, buf);
*
* buf[str_len] = '\0';
@@ -451,7 +449,7 @@ static int filter_special(double fp, char* dest)
* }
*
*/
-static int fpconv_dtoa(double d, char dest[24])
+static int fpconv_dtoa(double d, char dest[32])
{
char digits[18];
@@ -474,6 +472,9 @@ static int fpconv_dtoa(double d, char dest[24])
int ndigits = grisu2(d, digits, &K);
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
+#if JSON_DEBUG
+ assert(str_len <= 32);
+#endif
return str_len;
}
diff --git a/ext/json/vendor/jeaiii-ltoa.h b/ext/json/vendor/jeaiii-ltoa.h
index c8e2a1288c..ba4f497fc8 100644
--- a/ext/json/vendor/jeaiii-ltoa.h
+++ b/ext/json/vendor/jeaiii-ltoa.h
@@ -35,12 +35,6 @@ SOFTWARE.
typedef uint_fast32_t u32_t;
typedef uint_fast64_t u64_t;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wshorten-64-to-32"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmissing-braces"
-
#define u32(x) ((u32_t)(x))
#define u64(x) ((u64_t)(x))
@@ -91,7 +85,7 @@ jeaiii_ultoa(char *b, u64_t n)
if (n < u32(1e6)) {
if (n < u32(1e4)) {
- u32_t f0 = u32(10 * (1 << 24) / 1e3 + 1) * n;
+ u32_t f0 = u32((10 * (1 << 24) / 1e3 + 1) * n);
COPY(b, digits_fd[f0 >> 24]);
b -= n < u32(1e3);
@@ -161,7 +155,7 @@ jeaiii_ultoa(char *b, u64_t n)
}
else if (u < u32(1e6)) {
if (u < u32(1e4)) {
- u32_t f0 = u32(10 * (1 << 24) / 1e3 + 1) * u;
+ u32_t f0 = u32((10 * (1 << 24) / 1e3 + 1) * u);
COPY(b, digits_fd[f0 >> 24]);
b -= u < u32(1e3);
@@ -226,7 +220,7 @@ jeaiii_ultoa(char *b, u64_t n)
b += 2;
}
else {
- u32_t f0 = u32(10 * (1 << 24) / 1e3 + 1) * u;
+ u32_t f0 = u32((10 * (1 << 24) / 1e3 + 1) * u);
COPY(b, digits_fd[f0 >> 24]);
b -= u < u32(1e3);
@@ -270,8 +264,4 @@ jeaiii_ultoa(char *b, u64_t n)
#undef u64
#undef COPY
-#pragma clang diagnostic pop
-#pragma GCC diagnostic pop
-
#endif // JEAIII_TO_TEXT_H_
-
diff --git a/ext/json/vendor/ryu.h b/ext/json/vendor/ryu.h
new file mode 100644
index 0000000000..f06ec814b4
--- /dev/null
+++ b/ext/json/vendor/ryu.h
@@ -0,0 +1,819 @@
+// Copyright 2018 Ulf Adams
+//
+// The contents of this file may be used under the terms of the Apache License,
+// Version 2.0.
+//
+// Alternatively, the contents of this file may be used under the terms of
+// the Boost Software License, Version 1.0.
+//
+// Unless required by applicable law or agreed to in writing, this software
+// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.
+//
+// ---
+//
+// Apache License
+// Version 2.0, January 2004
+// http://www.apache.org/licenses/
+//
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+//
+// 1. Definitions.
+//
+// "License" shall mean the terms and conditions for use, reproduction,
+// and distribution as defined by Sections 1 through 9 of this document.
+//
+// "Licensor" shall mean the copyright owner or entity authorized by
+// the copyright owner that is granting the License.
+//
+// "Legal Entity" shall mean the union of the acting entity and all
+// other entities that control, are controlled by, or are under common
+// control with that entity. For the purposes of this definition,
+// "control" means (i) the power, direct or indirect, to cause the
+// direction or management of such entity, whether by contract or
+// otherwise, or (ii) ownership of fifty percent (50%) or more of the
+// outstanding shares, or (iii) beneficial ownership of such entity.
+//
+// "You" (or "Your") shall mean an individual or Legal Entity
+// exercising permissions granted by this License.
+//
+// "Source" form shall mean the preferred form for making modifications,
+// including but not limited to software source code, documentation
+// source, and configuration files.
+//
+// "Object" form shall mean any form resulting from mechanical
+// transformation or translation of a Source form, including but
+// not limited to compiled object code, generated documentation,
+// and conversions to other media types.
+//
+// "Work" shall mean the work of authorship, whether in Source or
+// Object form, made available under the License, as indicated by a
+// copyright notice that is included in or attached to the work
+// (an example is provided in the Appendix below).
+//
+// "Derivative Works" shall mean any work, whether in Source or Object
+// form, that is based on (or derived from) the Work and for which the
+// editorial revisions, annotations, elaborations, or other modifications
+// represent, as a whole, an original work of authorship. For the purposes
+// of this License, Derivative Works shall not include works that remain
+// separable from, or merely link (or bind by name) to the interfaces of,
+// the Work and Derivative Works thereof.
+//
+// "Contribution" shall mean any work of authorship, including
+// the original version of the Work and any modifications or additions
+// to that Work or Derivative Works thereof, that is intentionally
+// submitted to Licensor for inclusion in the Work by the copyright owner
+// or by an individual or Legal Entity authorized to submit on behalf of
+// the copyright owner. For the purposes of this definition, "submitted"
+// means any form of electronic, verbal, or written communication sent
+// to the Licensor or its representatives, including but not limited to
+// communication on electronic mailing lists, source code control systems,
+// and issue tracking systems that are managed by, or on behalf of, the
+// Licensor for the purpose of discussing and improving the Work, but
+// excluding communication that is conspicuously marked or otherwise
+// designated in writing by the copyright owner as "Not a Contribution."
+//
+// "Contributor" shall mean Licensor and any individual or Legal Entity
+// on behalf of whom a Contribution has been received by Licensor and
+// subsequently incorporated within the Work.
+//
+// 2. Grant of Copyright License. Subject to the terms and conditions of
+// this License, each Contributor hereby grants to You a perpetual,
+// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+// copyright license to reproduce, prepare Derivative Works of,
+// publicly display, publicly perform, sublicense, and distribute the
+// Work and such Derivative Works in Source or Object form.
+//
+// 3. Grant of Patent License. Subject to the terms and conditions of
+// this License, each Contributor hereby grants to You a perpetual,
+// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+// (except as stated in this section) patent license to make, have made,
+// use, offer to sell, sell, import, and otherwise transfer the Work,
+// where such license applies only to those patent claims licensable
+// by such Contributor that are necessarily infringed by their
+// Contribution(s) alone or by combination of their Contribution(s)
+// with the Work to which such Contribution(s) was submitted. If You
+// institute patent litigation against any entity (including a
+// cross-claim or counterclaim in a lawsuit) alleging that the Work
+// or a Contribution incorporated within the Work constitutes direct
+// or contributory patent infringement, then any patent licenses
+// granted to You under this License for that Work shall terminate
+// as of the date such litigation is filed.
+//
+// 4. Redistribution. You may reproduce and distribute copies of the
+// Work or Derivative Works thereof in any medium, with or without
+// modifications, and in Source or Object form, provided that You
+// meet the following conditions:
+//
+// (a) You must give any other recipients of the Work or
+// Derivative Works a copy of this License; and
+//
+// (b) You must cause any modified files to carry prominent notices
+// stating that You changed the files; and
+//
+// (c) You must retain, in the Source form of any Derivative Works
+// that You distribute, all copyright, patent, trademark, and
+// attribution notices from the Source form of the Work,
+// excluding those notices that do not pertain to any part of
+// the Derivative Works; and
+//
+// (d) If the Work includes a "NOTICE" text file as part of its
+// distribution, then any Derivative Works that You distribute must
+// include a readable copy of the attribution notices contained
+// within such NOTICE file, excluding those notices that do not
+// pertain to any part of the Derivative Works, in at least one
+// of the following places: within a NOTICE text file distributed
+// as part of the Derivative Works; within the Source form or
+// documentation, if provided along with the Derivative Works; or,
+// within a display generated by the Derivative Works, if and
+// wherever such third-party notices normally appear. The contents
+// of the NOTICE file are for informational purposes only and
+// do not modify the License. You may add Your own attribution
+// notices within Derivative Works that You distribute, alongside
+// or as an addendum to the NOTICE text from the Work, provided
+// that such additional attribution notices cannot be construed
+// as modifying the License.
+//
+// You may add Your own copyright statement to Your modifications and
+// may provide additional or different license terms and conditions
+// for use, reproduction, or distribution of Your modifications, or
+// for any such Derivative Works as a whole, provided Your use,
+// reproduction, and distribution of the Work otherwise complies with
+// the conditions stated in this License.
+//
+// 5. Submission of Contributions. Unless You explicitly state otherwise,
+// any Contribution intentionally submitted for inclusion in the Work
+// by You to the Licensor shall be under the terms and conditions of
+// this License, without any additional terms or conditions.
+// Notwithstanding the above, nothing herein shall supersede or modify
+// the terms of any separate license agreement you may have executed
+// with Licensor regarding such Contributions.
+//
+// 6. Trademarks. This License does not grant permission to use the trade
+// names, trademarks, service marks, or product names of the Licensor,
+// except as required for reasonable and customary use in describing the
+// origin of the Work and reproducing the content of the NOTICE file.
+//
+// 7. Disclaimer of Warranty. Unless required by applicable law or
+// agreed to in writing, Licensor provides the Work (and each
+// Contributor provides its Contributions) on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied, including, without limitation, any warranties or conditions
+// of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+// PARTICULAR PURPOSE. You are solely responsible for determining the
+// appropriateness of using or redistributing the Work and assume any
+// risks associated with Your exercise of permissions under this License.
+//
+// 8. Limitation of Liability. In no event and under no legal theory,
+// whether in tort (including negligence), contract, or otherwise,
+// unless required by applicable law (such as deliberate and grossly
+// negligent acts) or agreed to in writing, shall any Contributor be
+// liable to You for damages, including any direct, indirect, special,
+// incidental, or consequential damages of any character arising as a
+// result of this License or out of the use or inability to use the
+// Work (including but not limited to damages for loss of goodwill,
+// work stoppage, computer failure or malfunction, or any and all
+// other commercial damages or losses), even if such Contributor
+// has been advised of the possibility of such damages.
+//
+// 9. Accepting Warranty or Additional Liability. While redistributing
+// the Work or Derivative Works thereof, You may choose to offer,
+// and charge a fee for, acceptance of support, warranty, indemnity,
+// or other liability obligations and/or rights consistent with this
+// License. However, in accepting such obligations, You may act only
+// on Your own behalf and on Your sole responsibility, not on behalf
+// of any other Contributor, and only if You agree to indemnify,
+// defend, and hold each Contributor harmless for any liability
+// incurred by, or claims asserted against, such Contributor by reason
+// of your accepting any such warranty or additional liability.
+//
+// END OF TERMS AND CONDITIONS
+//
+// APPENDIX: How to apply the Apache License to your work.
+//
+// To apply the Apache License to your work, attach the following
+// boilerplate notice, with the fields enclosed by brackets "[]"
+// replaced with your own identifying information. (Don't include
+// the brackets!) The text should be enclosed in the appropriate
+// comment syntax for the file format. We also recommend that a
+// file or class name and description of purpose be included on the
+// same "printed page" as the copyright notice for easier
+// identification within third-party archives.
+//
+// Copyright [yyyy] [name of copyright owner]
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// ---
+//
+// Boost Software License - Version 1.0 - August 17th, 2003
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// ---
+// Minimal Ryu implementation adapted for Ruby JSON gem by Josef Šimánek
+// Optimized for pre-extracted mantissa/exponent from JSON parsing
+// This is a stripped-down version containing only what's needed for
+// converting decimal mantissa+exponent to IEEE 754 double precision.
+
+#ifndef RYU_H
+#define RYU_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+// Detect __builtin_clzll availability (for floor_log2)
+// Note: MSVC doesn't have __builtin_clzll, so we provide a fallback
+#ifdef __clang__
+ #if __has_builtin(__builtin_clzll)
+ #define RYU_HAVE_BUILTIN_CLZLL 1
+ #else
+ #define RYU_HAVE_BUILTIN_CLZLL 0
+ #endif
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ #define RYU_HAVE_BUILTIN_CLZLL 1
+#else
+ #define RYU_HAVE_BUILTIN_CLZLL 0
+#endif
+
+// Count leading zeros (for floor_log2)
+static inline uint32_t ryu_leading_zeros64(uint64_t input)
+{
+#if RYU_HAVE_BUILTIN_CLZLL
+ return __builtin_clzll(input);
+#else
+ // Fallback: binary search for the highest set bit
+ // This works on MSVC and other compilers without __builtin_clzll
+ if (input == 0) return 64;
+ uint32_t n = 0;
+ if (input <= 0x00000000FFFFFFFFULL) { n += 32; input <<= 32; }
+ if (input <= 0x0000FFFFFFFFFFFFULL) { n += 16; input <<= 16; }
+ if (input <= 0x00FFFFFFFFFFFFFFULL) { n += 8; input <<= 8; }
+ if (input <= 0x0FFFFFFFFFFFFFFFULL) { n += 4; input <<= 4; }
+ if (input <= 0x3FFFFFFFFFFFFFFFULL) { n += 2; input <<= 2; }
+ if (input <= 0x7FFFFFFFFFFFFFFFULL) { n += 1; }
+ return n;
+#endif
+}
+
+// These tables are generated by PrintDoubleLookupTable.
+#define DOUBLE_POW5_INV_BITCOUNT 125
+#define DOUBLE_POW5_BITCOUNT 125
+
+#define DOUBLE_POW5_INV_TABLE_SIZE 342
+#define DOUBLE_POW5_TABLE_SIZE 326
+
+static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
+ { 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
+ { 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u },
+ { 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u },
+ { 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u },
+ { 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
+ { 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
+ { 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u },
+ { 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u },
+ { 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u },
+ { 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
+ { 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
+ { 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
+ { 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u },
+ { 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u },
+ { 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
+ { 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
+ { 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u },
+ { 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
+ { 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
+ { 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
+ { 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u },
+ { 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u },
+ { 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u },
+ { 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
+ { 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
+ { 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
+ { 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
+ { 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
+ { 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u },
+ { 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u },
+ { 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u },
+ { 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
+ { 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u },
+ { 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
+ { 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
+ { 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
+ { 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u },
+ { 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u },
+ { 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u },
+ { 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
+ { 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u },
+ { 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
+ { 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u },
+ { 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
+ { 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u },
+ { 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u },
+ { 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
+ { 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u },
+ { 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
+ { 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
+ { 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u },
+ { 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
+ { 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
+ { 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u },
+ { 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u },
+ { 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
+ { 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u },
+ { 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
+ { 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u },
+ { 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
+ { 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u },
+ { 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
+ { 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
+ { 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
+ { 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u },
+ { 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
+ { 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u },
+ { 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u },
+ { 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
+ { 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
+ { 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u },
+ { 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u },
+ { 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u },
+ { 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u },
+ { 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
+ { 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
+ { 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u },
+ { 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u },
+ { 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
+ { 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u },
+ { 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u },
+ { 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u },
+ { 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
+ { 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
+ { 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
+ { 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u },
+ { 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
+ { 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u },
+ { 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
+ { 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u },
+ { 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u },
+ { 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u },
+ { 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
+ { 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u },
+ { 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
+ { 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u },
+ { 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
+ { 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
+ { 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
+ { 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u },
+ { 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u },
+ { 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u },
+ { 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
+ { 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u },
+ { 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
+ { 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
+ { 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u },
+ { 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
+ { 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
+ { 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u },
+ { 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
+ { 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
+ { 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u },
+ { 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u },
+ { 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u },
+ { 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u },
+ { 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u },
+ { 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
+ { 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u },
+ { 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
+ { 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u },
+ { 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u },
+ { 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
+ { 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
+ { 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
+ { 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
+ { 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u },
+ { 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u },
+ { 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u },
+ { 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u },
+ { 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u },
+ { 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u },
+ { 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u },
+ { 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u },
+ { 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u },
+ { 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u },
+ { 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u },
+ { 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u },
+ { 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u },
+ { 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
+ { 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
+ { 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
+ { 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
+ { 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
+ { 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
+ { 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u },
+ { 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u },
+ { 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u },
+ { 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u },
+ { 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
+ { 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
+ { 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
+ { 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u },
+ { 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u },
+ { 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
+ { 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u },
+ { 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u },
+ { 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u },
+ { 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u },
+ { 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u },
+ { 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
+ { 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u },
+ { 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u },
+ { 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u },
+ { 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u },
+ { 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u },
+ { 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u },
+ { 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u },
+ { 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u },
+ { 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u },
+ { 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u }
+};
+
+static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
+ { 0u, 1152921504606846976u }, { 0u, 1441151880758558720u },
+ { 0u, 1801439850948198400u }, { 0u, 2251799813685248000u },
+ { 0u, 1407374883553280000u }, { 0u, 1759218604441600000u },
+ { 0u, 2199023255552000000u }, { 0u, 1374389534720000000u },
+ { 0u, 1717986918400000000u }, { 0u, 2147483648000000000u },
+ { 0u, 1342177280000000000u }, { 0u, 1677721600000000000u },
+ { 0u, 2097152000000000000u }, { 0u, 1310720000000000000u },
+ { 0u, 1638400000000000000u }, { 0u, 2048000000000000000u },
+ { 0u, 1280000000000000000u }, { 0u, 1600000000000000000u },
+ { 0u, 2000000000000000000u }, { 0u, 1250000000000000000u },
+ { 0u, 1562500000000000000u }, { 0u, 1953125000000000000u },
+ { 0u, 1220703125000000000u }, { 0u, 1525878906250000000u },
+ { 0u, 1907348632812500000u }, { 0u, 1192092895507812500u },
+ { 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u },
+ { 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
+ { 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
+ { 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
+ { 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u },
+ { 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u },
+ { 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u },
+ { 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
+ { 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u },
+ { 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u },
+ { 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
+ { 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u },
+ { 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u },
+ { 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u },
+ { 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
+ { 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
+ { 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u },
+ { 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
+ { 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
+ { 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u },
+ { 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u },
+ { 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u },
+ { 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
+ { 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
+ { 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
+ { 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u },
+ { 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
+ { 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
+ { 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u },
+ { 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u },
+ { 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u },
+ { 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u },
+ { 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u },
+ { 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u },
+ { 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u },
+ { 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
+ { 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
+ { 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
+ { 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u },
+ { 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u },
+ { 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
+ { 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u },
+ { 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
+ { 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
+ { 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
+ { 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
+ { 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
+ { 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
+ { 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
+ { 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u },
+ { 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
+ { 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
+ { 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u },
+ { 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
+ { 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
+ { 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u },
+ { 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u },
+ { 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u },
+ { 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
+ { 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u },
+ { 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
+ { 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
+ { 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
+ { 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u },
+ { 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
+ { 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
+ { 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
+ { 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
+ { 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
+ { 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
+ { 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u },
+ { 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u },
+ { 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
+ { 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
+ { 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
+ { 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u },
+ { 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
+ { 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u },
+ { 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
+ { 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
+ { 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u },
+ { 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u },
+ { 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
+ { 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u },
+ { 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u },
+ { 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u },
+ { 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
+ { 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
+ { 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u },
+ { 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
+ { 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u },
+ { 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u },
+ { 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
+ { 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
+ { 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
+ { 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u },
+ { 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u },
+ { 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
+ { 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u },
+ { 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u },
+ { 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u },
+ { 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u },
+ { 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u },
+ { 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u },
+ { 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
+ { 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
+ { 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u },
+ { 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
+ { 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u },
+ { 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u },
+ { 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
+ { 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
+ { 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
+ { 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u },
+ { 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u },
+ { 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u },
+ { 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
+ { 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u },
+ { 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u },
+ { 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
+ { 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u },
+ { 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u },
+ { 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u },
+ { 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u },
+ { 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
+ { 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u },
+ { 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u },
+ { 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
+ { 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u },
+ { 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u },
+ { 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u },
+ { 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
+ { 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
+ { 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
+ { 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u },
+ { 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
+ { 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
+ { 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u },
+ { 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
+ { 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
+ { 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
+ { 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u },
+ { 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u },
+ { 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u },
+ { 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u },
+ { 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u },
+ { 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
+ { 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u },
+ { 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u },
+ { 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u }
+};
+
+// IEEE 754 double precision constants
+#define DOUBLE_MANTISSA_BITS 52
+#define DOUBLE_EXPONENT_BITS 11
+#define DOUBLE_EXPONENT_BIAS 1023
+
+// Helper: floor(log2(value)) using ryu_leading_zeros64
+static inline uint32_t floor_log2(const uint64_t value) {
+ return 63 - ryu_leading_zeros64(value);
+}
+
+// Helper: log2(5^e) approximation
+static inline int32_t log2pow5(const int32_t e) {
+ return (int32_t) ((((uint32_t) e) * 1217359) >> 19);
+}
+
+// Helper: ceil(log2(5^e))
+static inline int32_t ceil_log2pow5(const int32_t e) {
+ return log2pow5(e) + 1;
+}
+
+// Helper: max of two int32
+static inline int32_t max32(int32_t a, int32_t b) {
+ return a < b ? b : a;
+}
+
+// Helper: convert uint64 bits to double
+static inline double int64Bits2Double(uint64_t bits) {
+ double f;
+ memcpy(&f, &bits, sizeof(double));
+ return f;
+}
+
+// Check if value is multiple of 2^p
+static inline bool multipleOfPowerOf2(const uint64_t value, const uint32_t p) {
+ return (value & ((1ull << p) - 1)) == 0;
+}
+
+// Count how many times value is divisible by 5
+// Uses modular inverse to avoid expensive division
+static inline uint32_t pow5Factor(uint64_t value) {
+ const uint64_t m_inv_5 = 14757395258967641293u; // 5 * m_inv_5 = 1 (mod 2^64)
+ const uint64_t n_div_5 = 3689348814741910323u; // 2^64 / 5
+ uint32_t count = 0;
+ for (;;) {
+ value *= m_inv_5;
+ if (value > n_div_5)
+ break;
+ ++count;
+ }
+ return count;
+}
+
+// Check if value is multiple of 5^p
+// Optimized: uses modular inverse instead of division
+static inline bool multipleOfPowerOf5(const uint64_t value, const uint32_t p) {
+ return pow5Factor(value) >= p;
+}
+
+// 128-bit multiplication with shift
+// This is the core operation for converting decimal to binary
+#if defined(__SIZEOF_INT128__)
+// Use native 128-bit integers if available (GCC/Clang)
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+ const unsigned __int128 b0 = ((unsigned __int128) m) * mul[0];
+ const unsigned __int128 b2 = ((unsigned __int128) m) * mul[1];
+ return (uint64_t) (((b0 >> 64) + b2) >> (j - 64));
+}
+#else
+// Fallback for systems without 128-bit integers
+static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
+ const uint32_t aLo = (uint32_t)a;
+ const uint32_t aHi = (uint32_t)(a >> 32);
+ const uint32_t bLo = (uint32_t)b;
+ const uint32_t bHi = (uint32_t)(b >> 32);
+
+ const uint64_t b00 = (uint64_t)aLo * bLo;
+ const uint64_t b01 = (uint64_t)aLo * bHi;
+ const uint64_t b10 = (uint64_t)aHi * bLo;
+ const uint64_t b11 = (uint64_t)aHi * bHi;
+
+ const uint32_t b00Lo = (uint32_t)b00;
+ const uint32_t b00Hi = (uint32_t)(b00 >> 32);
+
+ const uint64_t mid1 = b10 + b00Hi;
+ const uint32_t mid1Lo = (uint32_t)(mid1);
+ const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
+
+ const uint64_t mid2 = b01 + mid1Lo;
+ const uint32_t mid2Lo = (uint32_t)(mid2);
+ const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
+
+ const uint64_t pHi = b11 + mid1Hi + mid2Hi;
+ const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
+
+ *productHi = pHi;
+ return pLo;
+}
+
+static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
+ return (hi << (64 - dist)) | (lo >> dist);
+}
+
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+ uint64_t high1;
+ const uint64_t low1 = umul128(m, mul[1], &high1);
+ uint64_t high0;
+ umul128(m, mul[0], &high0);
+ const uint64_t sum = high0 + low1;
+ if (sum < high0) {
+ ++high1;
+ }
+ return shiftright128(sum, high1, j - 64);
+}
+#endif
+
+// Main conversion function: decimal mantissa+exponent to IEEE 754 double
+// Optimized for JSON parsing with fast paths for edge cases
+static inline double ryu_s2d_from_parts(uint64_t m10, int m10digits, int32_t e10, bool signedM) {
+ // Fast path: handle zero explicitly (e.g., "0.0", "0e0")
+ if (m10 == 0) {
+ return int64Bits2Double(((uint64_t) signedM) << 63);
+ }
+
+ // Fast path: handle overflow/underflow early
+ if (m10digits + e10 <= -324) {
+ // Underflow to zero
+ return int64Bits2Double(((uint64_t) signedM) << 63);
+ }
+
+ if (m10digits + e10 >= 310) {
+ // Overflow to infinity
+ return int64Bits2Double((((uint64_t) signedM) << 63) | 0x7ff0000000000000ULL);
+ }
+
+ // Convert decimal to binary: m10 * 10^e10 = m2 * 2^e2
+ int32_t e2;
+ uint64_t m2;
+ bool trailingZeros;
+
+ if (e10 >= 0) {
+ // Positive exponent: multiply by 5^e10 and adjust binary exponent
+ e2 = floor_log2(m10) + e10 + log2pow5(e10) - (DOUBLE_MANTISSA_BITS + 1);
+ int j = e2 - e10 - ceil_log2pow5(e10) + DOUBLE_POW5_BITCOUNT;
+ m2 = mulShift64(m10, DOUBLE_POW5_SPLIT[e10], j);
+ trailingZeros = e2 < e10 || (e2 - e10 < 64 && multipleOfPowerOf2(m10, e2 - e10));
+ } else {
+ // Negative exponent: divide by 5^(-e10)
+ e2 = floor_log2(m10) + e10 - ceil_log2pow5(-e10) - (DOUBLE_MANTISSA_BITS + 1);
+ int j = e2 - e10 + ceil_log2pow5(-e10) - 1 + DOUBLE_POW5_INV_BITCOUNT;
+ m2 = mulShift64(m10, DOUBLE_POW5_INV_SPLIT[-e10], j);
+ trailingZeros = multipleOfPowerOf5(m10, -e10);
+ }
+
+ // Compute IEEE 754 exponent
+ uint32_t ieee_e2 = (uint32_t) max32(0, e2 + DOUBLE_EXPONENT_BIAS + floor_log2(m2));
+
+ if (ieee_e2 > 0x7fe) {
+ // Overflow to infinity
+ return int64Bits2Double((((uint64_t) signedM) << 63) | 0x7ff0000000000000ULL);
+ }
+
+ // Compute shift amount for rounding
+ int32_t shift = (ieee_e2 == 0 ? 1 : ieee_e2) - e2 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
+
+ // IEEE 754 round-to-even (banker's rounding)
+ trailingZeros &= (m2 & ((1ull << (shift - 1)) - 1)) == 0;
+ uint64_t lastRemovedBit = (m2 >> (shift - 1)) & 1;
+ bool roundUp = (lastRemovedBit != 0) && (!trailingZeros || (((m2 >> shift) & 1) != 0));
+
+ uint64_t ieee_m2 = (m2 >> shift) + roundUp;
+ ieee_m2 &= (1ull << DOUBLE_MANTISSA_BITS) - 1;
+
+ if (ieee_m2 == 0 && roundUp) {
+ ieee_e2++;
+ }
+
+ // Pack sign, exponent, and mantissa into IEEE 754 format
+ // Match original Ryu: group sign+exponent, then shift and add mantissa
+ uint64_t ieee = (((((uint64_t) signedM) << DOUBLE_EXPONENT_BITS) | (uint64_t)ieee_e2) << DOUBLE_MANTISSA_BITS) | ieee_m2;
+ return int64Bits2Double(ieee);
+}
+
+#endif // RYU_H
diff --git a/ext/monitor/depend b/ext/monitor/depend
deleted file mode 100644
index bc7ead0d32..0000000000
--- a/ext/monitor/depend
+++ /dev/null
@@ -1,161 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-monitor.o: $(RUBY_EXTCONF_H)
-monitor.o: $(arch_hdrdir)/ruby/config.h
-monitor.o: $(hdrdir)/ruby/assert.h
-monitor.o: $(hdrdir)/ruby/backward.h
-monitor.o: $(hdrdir)/ruby/backward/2/assume.h
-monitor.o: $(hdrdir)/ruby/backward/2/attributes.h
-monitor.o: $(hdrdir)/ruby/backward/2/bool.h
-monitor.o: $(hdrdir)/ruby/backward/2/inttypes.h
-monitor.o: $(hdrdir)/ruby/backward/2/limits.h
-monitor.o: $(hdrdir)/ruby/backward/2/long_long.h
-monitor.o: $(hdrdir)/ruby/backward/2/stdalign.h
-monitor.o: $(hdrdir)/ruby/backward/2/stdarg.h
-monitor.o: $(hdrdir)/ruby/defines.h
-monitor.o: $(hdrdir)/ruby/intern.h
-monitor.o: $(hdrdir)/ruby/internal/abi.h
-monitor.o: $(hdrdir)/ruby/internal/anyargs.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-monitor.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-monitor.o: $(hdrdir)/ruby/internal/assume.h
-monitor.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-monitor.o: $(hdrdir)/ruby/internal/attr/artificial.h
-monitor.o: $(hdrdir)/ruby/internal/attr/cold.h
-monitor.o: $(hdrdir)/ruby/internal/attr/const.h
-monitor.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-monitor.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-monitor.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-monitor.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-monitor.o: $(hdrdir)/ruby/internal/attr/error.h
-monitor.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-monitor.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-monitor.o: $(hdrdir)/ruby/internal/attr/format.h
-monitor.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-monitor.o: $(hdrdir)/ruby/internal/attr/noalias.h
-monitor.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-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
-monitor.o: $(hdrdir)/ruby/internal/attr/warning.h
-monitor.o: $(hdrdir)/ruby/internal/attr/weakref.h
-monitor.o: $(hdrdir)/ruby/internal/cast.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-monitor.o: $(hdrdir)/ruby/internal/compiler_since.h
-monitor.o: $(hdrdir)/ruby/internal/config.h
-monitor.o: $(hdrdir)/ruby/internal/constant_p.h
-monitor.o: $(hdrdir)/ruby/internal/core.h
-monitor.o: $(hdrdir)/ruby/internal/core/rarray.h
-monitor.o: $(hdrdir)/ruby/internal/core/rbasic.h
-monitor.o: $(hdrdir)/ruby/internal/core/rbignum.h
-monitor.o: $(hdrdir)/ruby/internal/core/rclass.h
-monitor.o: $(hdrdir)/ruby/internal/core/rdata.h
-monitor.o: $(hdrdir)/ruby/internal/core/rfile.h
-monitor.o: $(hdrdir)/ruby/internal/core/rhash.h
-monitor.o: $(hdrdir)/ruby/internal/core/robject.h
-monitor.o: $(hdrdir)/ruby/internal/core/rregexp.h
-monitor.o: $(hdrdir)/ruby/internal/core/rstring.h
-monitor.o: $(hdrdir)/ruby/internal/core/rstruct.h
-monitor.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-monitor.o: $(hdrdir)/ruby/internal/ctype.h
-monitor.o: $(hdrdir)/ruby/internal/dllexport.h
-monitor.o: $(hdrdir)/ruby/internal/dosish.h
-monitor.o: $(hdrdir)/ruby/internal/error.h
-monitor.o: $(hdrdir)/ruby/internal/eval.h
-monitor.o: $(hdrdir)/ruby/internal/event.h
-monitor.o: $(hdrdir)/ruby/internal/fl_type.h
-monitor.o: $(hdrdir)/ruby/internal/gc.h
-monitor.o: $(hdrdir)/ruby/internal/glob.h
-monitor.o: $(hdrdir)/ruby/internal/globals.h
-monitor.o: $(hdrdir)/ruby/internal/has/attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/builtin.h
-monitor.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-monitor.o: $(hdrdir)/ruby/internal/has/extension.h
-monitor.o: $(hdrdir)/ruby/internal/has/feature.h
-monitor.o: $(hdrdir)/ruby/internal/has/warning.h
-monitor.o: $(hdrdir)/ruby/internal/intern/array.h
-monitor.o: $(hdrdir)/ruby/internal/intern/bignum.h
-monitor.o: $(hdrdir)/ruby/internal/intern/class.h
-monitor.o: $(hdrdir)/ruby/internal/intern/compar.h
-monitor.o: $(hdrdir)/ruby/internal/intern/complex.h
-monitor.o: $(hdrdir)/ruby/internal/intern/cont.h
-monitor.o: $(hdrdir)/ruby/internal/intern/dir.h
-monitor.o: $(hdrdir)/ruby/internal/intern/enum.h
-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/hash.h
-monitor.o: $(hdrdir)/ruby/internal/intern/io.h
-monitor.o: $(hdrdir)/ruby/internal/intern/load.h
-monitor.o: $(hdrdir)/ruby/internal/intern/marshal.h
-monitor.o: $(hdrdir)/ruby/internal/intern/numeric.h
-monitor.o: $(hdrdir)/ruby/internal/intern/object.h
-monitor.o: $(hdrdir)/ruby/internal/intern/parse.h
-monitor.o: $(hdrdir)/ruby/internal/intern/proc.h
-monitor.o: $(hdrdir)/ruby/internal/intern/process.h
-monitor.o: $(hdrdir)/ruby/internal/intern/random.h
-monitor.o: $(hdrdir)/ruby/internal/intern/range.h
-monitor.o: $(hdrdir)/ruby/internal/intern/rational.h
-monitor.o: $(hdrdir)/ruby/internal/intern/re.h
-monitor.o: $(hdrdir)/ruby/internal/intern/ruby.h
-monitor.o: $(hdrdir)/ruby/internal/intern/select.h
-monitor.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-monitor.o: $(hdrdir)/ruby/internal/intern/signal.h
-monitor.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-monitor.o: $(hdrdir)/ruby/internal/intern/string.h
-monitor.o: $(hdrdir)/ruby/internal/intern/struct.h
-monitor.o: $(hdrdir)/ruby/internal/intern/thread.h
-monitor.o: $(hdrdir)/ruby/internal/intern/time.h
-monitor.o: $(hdrdir)/ruby/internal/intern/variable.h
-monitor.o: $(hdrdir)/ruby/internal/intern/vm.h
-monitor.o: $(hdrdir)/ruby/internal/interpreter.h
-monitor.o: $(hdrdir)/ruby/internal/iterator.h
-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/scan_args.h
-monitor.o: $(hdrdir)/ruby/internal/special_consts.h
-monitor.o: $(hdrdir)/ruby/internal/static_assert.h
-monitor.o: $(hdrdir)/ruby/internal/stdalign.h
-monitor.o: $(hdrdir)/ruby/internal/stdbool.h
-monitor.o: $(hdrdir)/ruby/internal/stdckdint.h
-monitor.o: $(hdrdir)/ruby/internal/symbol.h
-monitor.o: $(hdrdir)/ruby/internal/value.h
-monitor.o: $(hdrdir)/ruby/internal/value_type.h
-monitor.o: $(hdrdir)/ruby/internal/variable.h
-monitor.o: $(hdrdir)/ruby/internal/warning_push.h
-monitor.o: $(hdrdir)/ruby/internal/xmalloc.h
-monitor.o: $(hdrdir)/ruby/missing.h
-monitor.o: $(hdrdir)/ruby/ruby.h
-monitor.o: $(hdrdir)/ruby/st.h
-monitor.o: $(hdrdir)/ruby/subst.h
-monitor.o: monitor.c
-# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/monitor/extconf.rb b/ext/monitor/extconf.rb
deleted file mode 100644
index 78c53fa0c5..0000000000
--- a/ext/monitor/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'mkmf'
-create_makefile('monitor')
diff --git a/ext/monitor/lib/monitor.rb b/ext/monitor/lib/monitor.rb
deleted file mode 100644
index 82d0a75c56..0000000000
--- a/ext/monitor/lib/monitor.rb
+++ /dev/null
@@ -1,289 +0,0 @@
-# frozen_string_literal: false
-# = monitor.rb
-#
-# Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
-#
-# This library is distributed under the terms of the Ruby license.
-# 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
-# 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].
-#
-# == Examples
-#
-# === Simple object.extend
-#
-# require 'monitor.rb'
-#
-# buf = []
-# buf.extend(MonitorMixin)
-# empty_cond = buf.new_cond
-#
-# # consumer
-# Thread.start do
-# loop do
-# buf.synchronize do
-# empty_cond.wait_while { buf.empty? }
-# print buf.shift
-# end
-# end
-# end
-#
-# # producer
-# while line = ARGF.gets
-# buf.synchronize do
-# buf.push(line)
-# empty_cond.signal
-# end
-# 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
-# line from ARGF and pushes it into buf then calls <tt>empty_cond.signal</tt>
-# to notify the consumer thread of new data.
-#
-# === Simple Class include
-#
-# require 'monitor'
-#
-# class SynchronizedArray < Array
-#
-# include MonitorMixin
-#
-# def initialize(*args)
-# super(*args)
-# end
-#
-# alias :old_shift :shift
-# alias :old_unshift :unshift
-#
-# def shift(n=1)
-# self.synchronize do
-# self.old_shift(n)
-# end
-# end
-#
-# def unshift(item)
-# self.synchronize do
-# self.old_unshift(item)
-# end
-# end
-#
-# # other methods ...
-# end
-#
-# +SynchronizedArray+ implements an Array with synchronized access to items.
-# This Class is implemented as subclass of Array which includes the
-# MonitorMixin module.
-#
-module MonitorMixin
- #
- # FIXME: This isn't documented in Nutshell.
- #
- # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
- # above calls while_wait and signal, this class should be documented.
- #
- class ConditionVariable
- #
- # Releases the lock held in the associated monitor and waits; reacquires the lock on wakeup.
- #
- # If +timeout+ is given, this method returns after +timeout+ seconds passed,
- # even if no other thread doesn't signal.
- #
- def wait(timeout = nil)
- @monitor.mon_check_owner
- @monitor.wait_for_cond(@cond, timeout)
- end
-
- #
- # Calls wait repeatedly while the given block yields a truthy value.
- #
- def wait_while
- while yield
- wait
- end
- end
-
- #
- # Calls wait repeatedly until the given block yields a truthy value.
- #
- def wait_until
- until yield
- wait
- end
- end
-
- #
- # Wakes up the first thread in line waiting for this lock.
- #
- def signal
- @monitor.mon_check_owner
- @cond.signal
- end
-
- #
- # Wakes up all threads waiting for this lock.
- #
- def broadcast
- @monitor.mon_check_owner
- @cond.broadcast
- end
-
- private
-
- def initialize(monitor) # :nodoc:
- @monitor = monitor
- @cond = Thread::ConditionVariable.new
- end
- end
-
- def self.extend_object(obj) # :nodoc:
- super(obj)
- obj.__send__(:mon_initialize)
- end
-
- #
- # Attempts to enter exclusive section. Returns +false+ if lock fails.
- #
- def mon_try_enter
- @mon_data.try_enter
- end
- # For backward compatibility
- alias try_mon_enter mon_try_enter
-
- #
- # Enters exclusive section.
- #
- def mon_enter
- @mon_data.enter
- end
-
- #
- # Leaves exclusive section.
- #
- def mon_exit
- mon_check_owner
- @mon_data.exit
- end
-
- #
- # Returns true if this monitor is locked by any thread
- #
- def mon_locked?
- @mon_data.mon_locked?
- end
-
- #
- # Returns true if this monitor is locked by current thread.
- #
- def mon_owned?
- @mon_data.mon_owned?
- end
-
- #
- # Enters exclusive section and executes the block. Leaves the exclusive
- # section automatically when the block exits. See example under
- # +MonitorMixin+.
- #
- def mon_synchronize(&b)
- @mon_data.synchronize(&b)
- end
- alias synchronize mon_synchronize
-
- #
- # Creates a new MonitorMixin::ConditionVariable associated with the
- # Monitor object.
- #
- def new_cond
- unless defined?(@mon_data)
- mon_initialize
- @mon_initialized_by_new_cond = true
- end
- return ConditionVariable.new(@mon_data)
- end
-
- private
-
- # Use <tt>extend MonitorMixin</tt> or <tt>include MonitorMixin</tt> instead
- # of this constructor. Have look at the examples above to understand how to
- # use this module.
- def initialize(...)
- super
- mon_initialize
- end
-
- # Initializes the MonitorMixin after being included in a class or when an
- # object has been extended with the MonitorMixin
- def mon_initialize
- if defined?(@mon_data)
- if defined?(@mon_initialized_by_new_cond)
- return # already initialized.
- elsif @mon_data_owner_object_id == self.object_id
- raise ThreadError, "already initialized"
- end
- end
- @mon_data = ::Monitor.new
- @mon_data_owner_object_id = self.object_id
- end
-
- # Ensures that the MonitorMixin is owned by the current thread,
- # otherwise raises an exception.
- def mon_check_owner
- @mon_data.mon_check_owner
- end
-end
-
-# Use the Monitor class when you want to have a lock object for blocks with
-# mutual exclusion.
-#
-# require 'monitor'
-#
-# lock = Monitor.new
-# lock.synchronize do
-# # exclusive access
-# end
-#
-class Monitor
- #
- # Creates a new MonitorMixin::ConditionVariable associated with the
- # Monitor object.
- #
- def new_cond
- ::MonitorMixin::ConditionVariable.new(self)
- end
-
- # for compatibility
- alias try_mon_enter try_enter
- alias mon_try_enter try_enter
- alias mon_enter enter
- alias mon_exit exit
- alias mon_synchronize synchronize
-end
-
-# Documentation comments:
-# - All documentation comes from Nutshell.
-# - MonitorMixin.new_cond appears in the example, but is not documented in
-# Nutshell.
-# - All the internals (internal modules Accessible and Initializable, class
-# ConditionVariable) appear in RDoc. It might be good to hide them, by
-# making them private, or marking them :nodoc:, etc.
-# - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
-# not synchronize.
-# - mon_owner is in Nutshell, but appears as an accessor in a separate module
-# here, so is hard/impossible to RDoc. Some other useful accessors
-# (mon_count and some queue stuff) are also in this module, and don't appear
-# directly in the RDoc output.
-# - in short, it may be worth changing the code layout in this file to make the
-# documentation easier
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
deleted file mode 100644
index 819c6e7699..0000000000
--- a/ext/monitor/monitor.c
+++ /dev/null
@@ -1,255 +0,0 @@
-#include "ruby/ruby.h"
-
-/* Thread::Monitor */
-
-struct rb_monitor {
- long count;
- const VALUE owner;
- const VALUE mutex;
-};
-
-static void
-monitor_mark(void *ptr)
-{
- struct rb_monitor *mc = ptr;
- rb_gc_mark(mc->owner);
- rb_gc_mark(mc->mutex);
-}
-
-static size_t
-monitor_memsize(const void *ptr)
-{
- return sizeof(struct rb_monitor);
-}
-
-static const rb_data_type_t monitor_data_type = {
- "monitor",
- {monitor_mark, RUBY_TYPED_DEFAULT_FREE, monitor_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
-};
-
-static VALUE
-monitor_alloc(VALUE klass)
-{
- struct rb_monitor *mc;
- VALUE obj;
-
- obj = TypedData_Make_Struct(klass, struct rb_monitor, &monitor_data_type, mc);
- RB_OBJ_WRITE(obj, &mc->mutex, rb_mutex_new());
- RB_OBJ_WRITE(obj, &mc->owner, Qnil);
- mc->count = 0;
-
- return obj;
-}
-
-static struct rb_monitor *
-monitor_ptr(VALUE monitor)
-{
- struct rb_monitor *mc;
- TypedData_Get_Struct(monitor, struct rb_monitor, &monitor_data_type, mc);
- return mc;
-}
-
-static int
-mc_owner_p(struct rb_monitor *mc)
-{
- return mc->owner == rb_fiber_current();
-}
-
-/*
- * call-seq:
- * try_enter -> true or false
- *
- * Attempts to enter exclusive section. Returns +false+ if lock fails.
- */
-static VALUE
-monitor_try_enter(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
-
- if (!mc_owner_p(mc)) {
- if (!rb_mutex_trylock(mc->mutex)) {
- return Qfalse;
- }
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
- mc->count = 0;
- }
- mc->count += 1;
- return Qtrue;
-}
-
-/*
- * call-seq:
- * enter -> nil
- *
- * Enters exclusive section.
- */
-static VALUE
-monitor_enter(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_mutex_lock(mc->mutex);
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
- mc->count = 0;
- }
- mc->count++;
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-monitor_check_owner(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_raise(rb_eThreadError, "current fiber not owner");
- }
- return Qnil;
-}
-
-/*
- * call-seq:
- * exit -> nil
- *
- * Leaves exclusive section.
- */
-static VALUE
-monitor_exit(VALUE monitor)
-{
- monitor_check_owner(monitor);
-
- struct rb_monitor *mc = monitor_ptr(monitor);
-
- if (mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)mc->count);
- mc->count--;
-
- if (mc->count == 0) {
- RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
- rb_mutex_unlock(mc->mutex);
- }
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-monitor_locked_p(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- return rb_mutex_locked_p(mc->mutex);
-}
-
-/* :nodoc: */
-static VALUE
-monitor_owned_p(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- return (rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc)) ? Qtrue : Qfalse;
-}
-
-static VALUE
-monitor_exit_for_cond(VALUE monitor)
-{
- struct rb_monitor *mc = monitor_ptr(monitor);
- long cnt = mc->count;
- RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
- mc->count = 0;
- return LONG2NUM(cnt);
-}
-
-struct wait_for_cond_data {
- VALUE monitor;
- VALUE cond;
- VALUE timeout;
- VALUE count;
-};
-
-static VALUE
-monitor_wait_for_cond_body(VALUE v)
-{
- struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
- struct rb_monitor *mc = monitor_ptr(data->monitor);
- // cond.wait(monitor.mutex, timeout)
- VALUE signaled = rb_funcall(data->cond, rb_intern("wait"), 2, mc->mutex, data->timeout);
- return RTEST(signaled) ? Qtrue : Qfalse;
-}
-
-static VALUE
-monitor_enter_for_cond(VALUE v)
-{
- // assert(rb_mutex_owned_p(mc->mutex) == Qtrue)
- // but rb_mutex_owned_p is not exported...
-
- struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
- struct rb_monitor *mc = monitor_ptr(data->monitor);
- RB_OBJ_WRITE(data->monitor, &mc->owner, rb_fiber_current());
- mc->count = NUM2LONG(data->count);
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-monitor_wait_for_cond(VALUE monitor, VALUE cond, VALUE timeout)
-{
- VALUE count = monitor_exit_for_cond(monitor);
- struct wait_for_cond_data data = {
- monitor,
- cond,
- timeout,
- count,
- };
-
- return rb_ensure(monitor_wait_for_cond_body, (VALUE)&data,
- monitor_enter_for_cond, (VALUE)&data);
-}
-
-static VALUE
-monitor_sync_body(VALUE monitor)
-{
- return rb_yield_values(0);
-}
-
-static VALUE
-monitor_sync_ensure(VALUE monitor)
-{
- return monitor_exit(monitor);
-}
-
-/*
- * call-seq:
- * synchronize { } -> result of the block
- *
- * Enters exclusive section and executes the block. Leaves the exclusive
- * section automatically when the block exits. See example under
- * +MonitorMixin+.
- */
-static VALUE
-monitor_synchronize(VALUE monitor)
-{
- monitor_enter(monitor);
- return rb_ensure(monitor_sync_body, monitor, monitor_sync_ensure, monitor);
-}
-
-void
-Init_monitor(void)
-{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
-#endif
-
- VALUE rb_cMonitor = rb_define_class("Monitor", rb_cObject);
- rb_define_alloc_func(rb_cMonitor, monitor_alloc);
-
- rb_define_method(rb_cMonitor, "try_enter", monitor_try_enter, 0);
- rb_define_method(rb_cMonitor, "enter", monitor_enter, 0);
- rb_define_method(rb_cMonitor, "exit", monitor_exit, 0);
- rb_define_method(rb_cMonitor, "synchronize", monitor_synchronize, 0);
-
- /* internal methods for MonitorMixin */
- rb_define_method(rb_cMonitor, "mon_locked?", monitor_locked_p, 0);
- rb_define_method(rb_cMonitor, "mon_check_owner", monitor_check_owner, 0);
- rb_define_method(rb_cMonitor, "mon_owned?", monitor_owned_p, 0);
-
- /* internal methods for MonitorMixin::ConditionVariable */
- rb_define_method(rb_cMonitor, "wait_for_cond", monitor_wait_for_cond, 2);
-}
diff --git a/ext/objspace/depend b/ext/objspace/depend
index a02168b06a..d9dfc0c42b 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -140,6 +140,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/intern/re.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/ruby.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/select.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/set.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/signal.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/sprintf.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -177,14 +178,17 @@ 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)/id_table.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/box.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/sanitizers.h
object_tracing.o: $(top_srcdir)/internal/serial.h
+object_tracing.o: $(top_srcdir)/internal/set_table.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
@@ -340,6 +344,7 @@ objspace.o: $(hdrdir)/ruby/internal/intern/re.h
objspace.o: $(hdrdir)/ruby/internal/intern/ruby.h
objspace.o: $(hdrdir)/ruby/internal/intern/select.h
objspace.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+objspace.o: $(hdrdir)/ruby/internal/intern/set.h
objspace.o: $(hdrdir)/ruby/internal/intern/signal.h
objspace.o: $(hdrdir)/ruby/internal/intern/sprintf.h
objspace.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -386,6 +391,7 @@ 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/box.h
objspace.o: $(top_srcdir)/internal/class.h
objspace.o: $(top_srcdir)/internal/compilers.h
objspace.o: $(top_srcdir)/internal/gc.h
@@ -393,7 +399,9 @@ objspace.o: $(top_srcdir)/internal/hash.h
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/set_table.h
objspace.o: $(top_srcdir)/internal/static_assert.h
+objspace.o: $(top_srcdir)/internal/struct.h
objspace.o: $(top_srcdir)/internal/variable.h
objspace.o: $(top_srcdir)/internal/vm.h
objspace.o: $(top_srcdir)/internal/warnings.h
@@ -552,6 +560,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/intern/re.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/ruby.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/select.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/set.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/signal.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/sprintf.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -593,10 +602,12 @@ 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)/encindex.h
objspace_dump.o: $(top_srcdir)/id_table.h
objspace_dump.o: $(top_srcdir)/internal.h
objspace_dump.o: $(top_srcdir)/internal/array.h
objspace_dump.o: $(top_srcdir)/internal/basic_operators.h
+objspace_dump.o: $(top_srcdir)/internal/box.h
objspace_dump.o: $(top_srcdir)/internal/class.h
objspace_dump.o: $(top_srcdir)/internal/compilers.h
objspace_dump.o: $(top_srcdir)/internal/gc.h
@@ -605,8 +616,10 @@ 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/set_table.h
objspace_dump.o: $(top_srcdir)/internal/static_assert.h
objspace_dump.o: $(top_srcdir)/internal/string.h
+objspace_dump.o: $(top_srcdir)/internal/struct.h
objspace_dump.o: $(top_srcdir)/internal/variable.h
objspace_dump.o: $(top_srcdir)/internal/vm.h
objspace_dump.o: $(top_srcdir)/internal/warnings.h
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index 0156642ef2..1c18bf02ee 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -91,7 +91,7 @@ newobj_i(VALUE tpval, void *data)
VALUE klass = rb_tracearg_defined_class(tparg);
struct allocation_info *info;
const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
- VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_class_path_cached(klass) : Qnil;
+ VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_mod_name(klass) : Qnil;
const char *class_path_cstr = RTEST(class_path) ? make_unique_str(arg->str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0;
st_data_t v;
@@ -203,6 +203,8 @@ allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t va
st_table *table = (st_table *)data;
if (!rb_gc_pointer_to_heap_p(key)) {
+ struct allocation_info *info = (struct allocation_info *)value;
+ xfree(info);
return ST_DELETE;
}
@@ -411,6 +413,13 @@ object_allocations_reporter(FILE *out, void *ptr)
fprintf(out, "== object_allocations_reporter: END\n");
}
+/*
+ * call-seq: trace_object_allocations_debug_start
+ *
+ * Starts tracing object allocations for GC debugging.
+ * If you encounter the BUG "... is T_NONE" (and so on) on your
+ * application, please try this method at the beginning of your app.
+ */
static VALUE
trace_object_allocations_debug_start(VALUE self)
{
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index 0ead94713a..112355ad27 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -38,10 +38,11 @@
* information as only a *HINT*. Especially, the size of +T_DATA+ may not be
* correct.
*
- * This method is only expected to work with C Ruby.
+ * This method is only expected to work with CRuby.
*
- * From Ruby 2.2, memsize_of(obj) returns a memory size includes
- * sizeof(RVALUE).
+ * From Ruby 3.2 with Variable Width Allocation, it returns the actual slot
+ * size used plus any additional memory allocated outside the slot (such
+ * as external strings, arrays, or hash tables).
*/
static VALUE
@@ -107,28 +108,24 @@ each_object_with_flags(each_obj_with_flags cb, void *ctx)
/*
* call-seq:
- * ObjectSpace.memsize_of_all([klass]) -> Integer
- *
- * Return consuming memory size of all living objects in bytes.
+ * ObjectSpace.memsize_of_all(klass = nil) -> integer
*
- * If +klass+ (should be Class object) is given, return the total memory size
- * of instances of the given class.
+ * Returns the total memory size of all living objects in bytes.
*
- * Note that the returned size is incomplete. You need to deal with this
- * information as only a *HINT*. Especially, the size of +T_DATA+ may not be
- * correct.
+ * ObjectSpace.memsize_of_all # => 12502001
*
- * Note that this method does *NOT* return total malloc'ed memory size.
+ * If +klass+ is given (which must be a Class or Module), returns the total
+ * memory size of objects whose class is, or is a subclass, of +klass+.
*
- * This method can be defined by the following Ruby code:
+ * class MyClass; end
+ * ObjectSpace.memsize_of_all(MyClass) # => 0
+ * o = MyClass.new
+ * ObjectSpace.memsize_of_all(MyClass) # => 40
*
- * def memsize_of_all klass = false
- * total = 0
- * ObjectSpace.each_object{|e|
- * total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass)
- * }
- * total
- * end
+ * Note that the value returned may be an underestimate of the actual amount
+ * of memory used. Therefore, the value returned should only be used as a hint,
+ * rather than a source of truth. In particular, the size of +T_DATA+ objects may
+ * not be correct.
*
* This method is only expected to work with C Ruby.
*/
@@ -140,6 +137,7 @@ memsize_of_all_m(int argc, VALUE *argv, VALUE self)
if (argc > 0) {
rb_scan_args(argc, argv, "01", &data.klass);
+ if (!NIL_P(data.klass)) rb_obj_is_kind_of(Qnil, data.klass);
}
each_object_with_flags(total_i, &data);
@@ -223,23 +221,26 @@ type2sym(enum ruby_value_type i)
/*
* call-seq:
- * ObjectSpace.count_objects_size([result_hash]) -> hash
+ * ObjectSpace.count_objects_size(result_hash = {}) -> result_hash
*
* Counts objects size (in bytes) for each type.
*
- * Note that this information is incomplete. You need to deal with
- * this information as only a *HINT*. Especially, total size of
- * T_DATA may be wrong.
+ * Note that the returned size may not be accurate, so it should only
+ * be used as a hint. Specifically, the size for +T_DATA+ may be
+ * inaccurate because these are custom objects defined in Ruby and
+ * native extensions and so they may not accurately report their
+ * memory size.
*
- * It returns a hash as:
- * {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
+ * It returns a hash that looks like:
*
- * If the optional argument, result_hash, is given,
- * it is overwritten and returned.
- * This is intended to avoid probe effect.
+ * {TOTAL: 1461154, T_CLASS: 158280, T_MODULE: 20672, T_STRING: 527249, ...}
+ *
+ * The contents of the returned hash are implementation specific and
+ * may be changed in future versions without notice.
*
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
+ * If the optional argument, +result_hash+, is given,
+ * it is overwritten and returned.
+ * This is intended to avoid the probe effect.
*
* This method is only expected to work with C Ruby.
*/
@@ -294,28 +295,27 @@ size_t rb_sym_immortal_count(void);
/*
* call-seq:
- * ObjectSpace.count_symbols([result_hash]) -> hash
+ * ObjectSpace.count_symbols(result_hash = nil) -> hash
*
- * Counts symbols for each Symbol type.
+ * Returns a hash containing the number of objects for each Symbol type.
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * The types of Symbols are the following:
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * - +mortal_dynamic_symbol+: Symbols that are garbage collectable.
+ * - +immortal_dynamic_symbol+: Symbols that are objects allocated from the
+ * garbage collector, but are not garbage collectable.
+ * - +immortal_static_symbol+: Symbols that are not allocated from the
+ * garbage collector, and are thus not garbage collectable.
+ * - +immortal_symbol+: the sum of +immortal_dynamic_symbol+ and +immortal_static_symbol+.
*
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * This method is only expected to work with C Ruby.
- *
- * On this version of MRI, they have 3 types of Symbols (and 1 total counts).
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
- * * mortal_dynamic_symbol: GC target symbols (collected by GC)
- * * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC)
- * * immortal_static_symbol: Immortal symbols (do not collected by GC)
- * * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol)
+ * This method is only expected to work with C Ruby.
*/
static VALUE
@@ -335,35 +335,6 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}
-/*
- * call-seq:
- * ObjectSpace.count_nodes([result_hash]) -> hash
- *
- * Counts nodes for each node type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
- *
- * It returns a hash as:
- *
- * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
- *
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
- *
- * This method is only expected to work with C Ruby.
- */
-
-static VALUE
-count_nodes(int argc, VALUE *argv, VALUE os)
-{
- return setup_hash(argc, argv);
-}
-
static void
cto_i(VALUE v, void *data)
{
@@ -393,32 +364,22 @@ cto_i(VALUE v, void *data)
/*
* call-seq:
- * ObjectSpace.count_tdata_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_DATA+ type.
+ * ObjectSpace.count_tdata_objects(result_hash = nil) -> hash
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * Returns a hash containing the number of objects for each +T_DATA+ type.
+ * The keys are Class objects when the +T_DATA+ object has an associated class,
+ * or Symbol objects of the name defined in the +rb_data_type_struct+ for internal
+ * +T_DATA+ objects.
*
- * It returns a hash as:
+ * ObjectSpace.count_tdata_objects
+ * # => {RBS::Location => 39255, marshal_compat_table: 1, Encoding => 103, mutex: 1, ... }
*
- * {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6,
- * :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99,
- * ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1,
- * Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2}
- * # T_DATA objects existing at startup on r32276.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * The contents of the returned hash is implementation specific and may change
- * in the future.
- *
- * In this version, keys are Class object or Symbol object.
- *
- * If object is kind of normal (accessible) object, the key is Class object.
- * If object is not a kind of normal (internal) object, the key is symbol
- * name, registered by rb_data_type_struct.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -457,28 +418,22 @@ count_imemo_objects_i(VALUE v, void *data)
/*
* call-seq:
- * ObjectSpace.count_imemo_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_IMEMO+ type.
+ * ObjectSpace.count_imemo_objects(result_hash = nil) -> hash
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * Returns a hash containing the number of objects for each +T_IMEMO+ type.
+ * The keys are Symbol objects of the +T_IMEMO+ type name.
+ * +T_IMEMO+ objects are Ruby internal objects that are not visible to Ruby
+ * programs.
*
- * It returns a hash as:
+ * ObjectSpace.count_imemo_objects
+ * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... }
*
- * {:imemo_ifunc=>8,
- * :imemo_svar=>7,
- * :imemo_cref=>509,
- * :imemo_memo=>1,
- * :imemo_throw_data=>1}
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * The contents of the returned hash is implementation specific and may change
- * in the future.
- *
- * In this version, keys are symbol objects.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -499,11 +454,13 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self)
INIT_IMEMO_TYPE_ID(imemo_ment);
INIT_IMEMO_TYPE_ID(imemo_iseq);
INIT_IMEMO_TYPE_ID(imemo_tmpbuf);
- INIT_IMEMO_TYPE_ID(imemo_ast);
- INIT_IMEMO_TYPE_ID(imemo_parser_strterm);
+ INIT_IMEMO_TYPE_ID(imemo_cvar_entry);
INIT_IMEMO_TYPE_ID(imemo_callinfo);
INIT_IMEMO_TYPE_ID(imemo_callcache);
INIT_IMEMO_TYPE_ID(imemo_constcache);
+ INIT_IMEMO_TYPE_ID(imemo_fields);
+ INIT_IMEMO_TYPE_ID(imemo_subclasses);
+ INIT_IMEMO_TYPE_ID(imemo_cdhash);
#undef INIT_IMEMO_TYPE_ID
}
@@ -602,42 +559,37 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
* call-seq:
* ObjectSpace.reachable_objects_from(obj) -> array or nil
*
- * [MRI specific feature] Return all reachable objects from `obj'.
+ * Returns all reachable objects from +obj+ as an array:
*
- * This method returns all reachable objects from `obj'.
+ * ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
+ * #=> [Array, 'a', 'b', 'c']
*
- * If `obj' has two or more references to the same object `x', then returned
- * array only includes one `x' object.
+ * The returned array is deduplicated, meaning that if +obj+ refers
+ * to another object more than once, it will only be added to the array
+ * once:
*
- * If `obj' is a non-markable (non-heap management) object such as true,
- * false, nil, symbols and Fixnums (and Flonum) then it simply returns nil.
+ * ObjectSpace.reachable_objects_from([v = 'a', v, v])
+ * #=> [Array, 'a']
*
- * If `obj' has references to an internal object, then it returns instances of
- * ObjectSpace::InternalObjectWrapper class. This object contains a reference
- * to an internal object and you can check the type of internal object with
- * `type' method.
+ * Returns +nil+ if +obj+ is not a markable object (i.e. non-heap
+ * managed) object. Non-markable objects include +true+, +false+,
+ * +nil+, certain symbols, small integers, and floats:
*
- * If `obj' is instance of ObjectSpace::InternalObjectWrapper class, then this
- * method returns all reachable object from an internal object, which is
- * pointed by `obj'.
+ * ObjectSpace.reachable_objects_from(1)
+ * #=> nil
*
- * With this method, you can find memory leaks.
+ * All references to internal objects in the returned array are wrapped
+ * using ObjectSpace::InternalObjectWrapper objects. This object contains
+ * a reference to the internal object and the type of the object can
+ * be accessed using the ObjectSpace::InternalObjectWrapper#type method.
*
- * This method is only expected to work with C Ruby.
+ * If +obj+ is instance of ObjectSpace::InternalObjectWrapper, then this
+ * method returns all reachable object from the internal object.
*
- * Example:
- * ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
- * #=> [Array, 'a', 'b', 'c']
- *
- * ObjectSpace.reachable_objects_from(['a', 'a', 'a'])
- * #=> [Array, 'a', 'a', 'a'] # all 'a' strings have different object id
- *
- * ObjectSpace.reachable_objects_from([v = 'a', v, v])
- * #=> [Array, 'a']
- *
- * ObjectSpace.reachable_objects_from(1)
- * #=> nil # 1 is not markable (heap managed) object
+ * This method is useful for debugging purposes, such as finding
+ * memory leaks.
*
+ * This method is only expected to work with C Ruby.
*/
static VALUE
@@ -713,7 +665,30 @@ collect_values_of_values(VALUE category, VALUE category_objects, VALUE categorie
* call-seq:
* ObjectSpace.reachable_objects_from_root -> hash
*
- * [MRI specific feature] Return all reachable objects from root.
+ * Returns a hash of objects directly reachable from the VM roots,
+ * grouped by the root that reaches them.
+ *
+ * The roots are the entry points the garbage collector starts from when it
+ * marks live objects, such as the virtual machine and the global variable
+ * table. The keys of the returned hash are strings naming each root, and each
+ * value is an array of the objects reachable from that root:
+ *
+ * require 'objspace'
+ *
+ * reachable = ObjectSpace.reachable_objects_from_root
+ * reachable.keys # => ["vm", "global_tbl", "machine_context", "global_symbols"]
+ * reachable.values.first # => [#<Ractor:#1 running>, ...]
+ *
+ * The returned hash compares its keys by identity, so it cannot be indexed
+ * with a string literal; iterate over it (or over its #values) instead.
+ *
+ * Any reference to an internal object is wrapped in an
+ * ObjectSpace::InternalObjectWrapper object.
+ *
+ * This method is useful for debugging the object graph, for example when
+ * tracking down the cause of a memory leak.
+ *
+ * This method is only expected to work with C Ruby.
*/
static VALUE
reachable_objects_from_root(VALUE self)
@@ -745,12 +720,28 @@ wrap_klass_iow(VALUE klass)
/*
* call-seq:
- * ObjectSpace.internal_class_of(obj) -> Class or Module
+ * ObjectSpace.internal_class_of(obj) -> class or module
*
- * [MRI specific feature] Return internal class of obj.
- * obj can be an instance of InternalObjectWrapper.
+ * Returns the real class of +obj+, which may differ from the class returned
+ * by Object#class.
+ *
+ * Ruby inserts hidden classes into an object's ancestry, such as a singleton
+ * class or an included module's iclass. Object#class skips over these, but
+ * this method returns the first one, including any hidden class:
+ *
+ * require 'objspace'
+ *
+ * s = "x"
+ * def s.foo; end # gives +s+ a singleton class
+ * s.class # => String
+ * ObjectSpace.internal_class_of(s) # => #<Class:#<String:0x000000012574c1f8>>
+ *
+ * +obj+ may be an ObjectSpace::InternalObjectWrapper, in which case the class
+ * of the wrapped internal object is returned.
*
* Note that you should not use this method in your application.
+ *
+ * This method is only expected to work with C Ruby.
*/
static VALUE
objspace_internal_class_of(VALUE self, VALUE obj)
@@ -792,7 +783,7 @@ objspace_internal_super_of(VALUE self, VALUE obj)
case T_MODULE:
case T_CLASS:
case T_ICLASS:
- super = RCLASS_SUPER(obj);
+ super = rb_class_super_of(obj);
break;
default:
rb_raise(rb_eArgError, "class or module is expected");
@@ -834,7 +825,6 @@ Init_objspace(void)
rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1);
- rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1);
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index dd0459bf56..68ada01af3 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -29,7 +29,7 @@
#include "ruby/util.h"
#include "ruby/io.h"
#include "vm_callinfo.h"
-#include "vm_core.h"
+#include "vm_sync.h"
RUBY_EXTERN const char ruby_hexdigits[];
@@ -394,9 +394,10 @@ dump_object(VALUE obj, struct dump_config *dc)
dc->cur_obj = obj;
dc->cur_obj_references = 0;
- if (BUILTIN_TYPE(obj) == T_NODE || BUILTIN_TYPE(obj) == T_IMEMO) {
+ if (BUILTIN_TYPE(obj) == T_NODE || (BUILTIN_TYPE(obj) == T_IMEMO && !IMEMO_TYPE_P(obj, imemo_fields))) {
dc->cur_obj_klass = 0;
- } else {
+ }
+ else {
dc->cur_obj_klass = RBASIC_CLASS(obj);
}
@@ -414,9 +415,11 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, obj_type(obj));
dump_append(dc, "\"");
- size_t shape_id = rb_shape_get_shape_id(obj);
- dump_append(dc, ", \"shape_id\":");
- dump_append_sizet(dc, shape_id);
+ if (BUILTIN_TYPE(obj) != T_IMEMO || IMEMO_TYPE_P(obj, imemo_fields)) {
+ size_t shape_id = rb_obj_shape_id(obj) & SHAPE_ID_OFFSET_MASK;
+ dump_append(dc, ", \"shape_id\":");
+ dump_append_sizet(dc, shape_id);
+ }
dump_append(dc, ", \"slot_size\":");
dump_append_sizet(dc, dc->cur_page_slot_size);
@@ -448,13 +451,16 @@ dump_object(VALUE obj, struct dump_config *dc)
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) {
+ if (klass != Qundef) {
+ mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
+ if (mid != 0) {
+ dump_append(dc, ", \"called_id\":");
+ dump_append_id(dc, mid);
+
+ }
+
dump_append(dc, ", \"receiver_class\":");
dump_append_ref(dc, klass);
}
@@ -537,7 +543,7 @@ dump_object(VALUE obj, struct dump_config *dc)
case T_CLASS:
dump_append(dc, ", \"variation_count\":");
- dump_append_d(dc, RCLASS_EXT(obj)->variation_count);
+ dump_append_d(dc, rb_class_variation_count(obj));
case T_MODULE:
if (rb_class_get_superclass(obj)) {
@@ -560,17 +566,22 @@ dump_object(VALUE obj, struct dump_config *dc)
}
}
- if (RCLASS_SINGLETON_P(obj)) {
+ if (rb_class_singleton_p(obj)) {
dump_append(dc, ", \"singleton\":true");
}
}
break;
case T_DATA:
- if (RTYPEDDATA_P(obj)) {
+ {
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
dump_append(dc, ", \"struct\":\"");
- dump_append(dc, RTYPEDDATA_TYPE(obj)->wrap_struct_name);
+ dump_append(dc, type->wrap_struct_name);
dump_append(dc, "\"");
+ if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY) &&
+ type->function.dfree != RUBY_DEFAULT_FREE) {
+ dump_append(dc, ", \"free_immediately\":false");
+ }
}
break;
@@ -581,14 +592,14 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case T_OBJECT:
- if (FL_TEST(obj, ROBJECT_EMBED)) {
+ if (!FL_TEST_RAW(obj, ROBJECT_HEAP)) {
dump_append(dc, ", \"embedded\":true");
}
dump_append(dc, ", \"ivars\":");
- dump_append_lu(dc, ROBJECT_IV_COUNT(obj));
- if (rb_shape_obj_too_complex(obj)) {
- dump_append(dc, ", \"too_complex_shape\":true");
+ dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj));
+ if (rb_obj_shape_complex_p(obj)) {
+ dump_append(dc, ", \"complex_shape\":true");
}
break;
@@ -765,15 +776,16 @@ dump_result(struct dump_config *dc)
return dc->given_output;
}
-/* :nodoc: */
static VALUE
-objspace_dump(VALUE os, VALUE obj, VALUE output)
+dump_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE obj = ((VALUE*)args_p)[0];
+ VALUE output = ((VALUE*)args_p)[1];
+
if (!RB_SPECIAL_CONST_P(obj)) {
dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
}
-
dump_output(&dc, output, Qnil, Qnil, Qnil);
dump_object(obj, &dc);
@@ -781,69 +793,73 @@ objspace_dump(VALUE os, VALUE obj, VALUE output)
return dump_result(&dc);
}
+/* :nodoc: */
+static VALUE
+objspace_dump(VALUE os, VALUE obj, VALUE output)
+{
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = output;
+ return rb_vm_lock_with_barrier(dump_locked, (void*)args);
+}
+
static void
-shape_i(rb_shape_t *shape, void *data)
+shape_id_i(shape_id_t shape_id, void *data)
{
struct dump_config *dc = (struct dump_config *)data;
- size_t shape_id = rb_shape_id(shape);
if (shape_id < dc->shapes_since) {
return;
}
dump_append(dc, "{\"address\":");
- dump_append_ref(dc, (VALUE)shape);
+ dump_append_ref(dc, (VALUE)RSHAPE(shape_id));
dump_append(dc, ", \"type\":\"SHAPE\", \"id\":");
dump_append_sizet(dc, shape_id);
- if (shape->type != SHAPE_ROOT) {
+ if (RSHAPE_TYPE(shape_id) != SHAPE_ROOT) {
dump_append(dc, ", \"parent_id\":");
- dump_append_lu(dc, shape->parent_id);
+ dump_append_lu(dc, RSHAPE_PARENT_OFFSET(shape_id));
}
dump_append(dc, ", \"depth\":");
- dump_append_sizet(dc, rb_shape_depth(shape));
+ dump_append_sizet(dc, rb_shape_depth(shape_id));
- dump_append(dc, ", \"shape_type\":");
- switch((enum shape_type)shape->type) {
+ switch (RSHAPE_TYPE(shape_id)) {
case SHAPE_ROOT:
- dump_append(dc, "\"ROOT\"");
+ dump_append(dc, ", \"shape_type\":\"ROOT\"");
break;
case SHAPE_IVAR:
- dump_append(dc, "\"IVAR\"");
+ dump_append(dc, ", \"shape_type\":\"IVAR\"");
dump_append(dc, ",\"edge_name\":");
- dump_append_id(dc, shape->edge_name);
+ dump_append_id(dc, RSHAPE_EDGE_NAME(shape_id));
break;
- case SHAPE_FROZEN:
- dump_append(dc, "\"FROZEN\"");
+ case SHAPE_OBJ_ID:
+ dump_append(dc, ", \"shape_type\":\"OBJ_ID\"");
break;
- case SHAPE_T_OBJECT:
- dump_append(dc, "\"T_OBJECT\"");
- break;
- case SHAPE_OBJ_TOO_COMPLEX:
- dump_append(dc, "\"OBJ_TOO_COMPLEX\"");
- break;
- default:
- rb_bug("[objspace] unexpected shape type");
}
dump_append(dc, ", \"edges\":");
- dump_append_sizet(dc, rb_shape_edges_count(shape));
+ dump_append_sizet(dc, rb_shape_edges_count(shape_id));
dump_append(dc, ", \"memsize\":");
- dump_append_sizet(dc, rb_shape_memsize(shape));
+ dump_append_sizet(dc, rb_shape_memsize(shape_id));
dump_append(dc, "}\n");
}
-/* :nodoc: */
static VALUE
-objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+dump_all_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE full = ((VALUE*)args_p)[1];
+ VALUE since = ((VALUE*)args_p)[2];
+ VALUE shapes = ((VALUE*)args_p)[3];
+
dump_output(&dc, output, full, since, shapes);
if (!dc.partial_dump || dc.since == 0) {
@@ -853,7 +869,7 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
}
if (RTEST(shapes)) {
- rb_shape_each_shape(shape_i, &dc);
+ rb_shape_each_shape_id(shape_id_i, &dc);
}
/* dump all objects */
@@ -864,17 +880,41 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
/* :nodoc: */
static VALUE
-objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+{
+ VALUE args[4];
+ args[0] = output;
+ args[1] = full;
+ args[2] = since;
+ args[3] = shapes;
+ return rb_vm_lock_with_barrier(dump_all_locked, (void*)args);
+}
+
+static VALUE
+dump_shapes_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE shapes = ((VALUE*)args_p)[1];
+
dump_output(&dc, output, Qfalse, Qnil, shapes);
if (RTEST(shapes)) {
- rb_shape_each_shape(shape_i, &dc);
+ rb_shape_each_shape_id(shape_id_i, &dc);
}
return dump_result(&dc);
}
+/* :nodoc: */
+static VALUE
+objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+{
+ VALUE args[2];
+ args[0] = output;
+ args[1] = shapes;
+ return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args);
+}
+
void
Init_objspace_dump(VALUE rb_mObjSpace)
{
@@ -882,6 +922,9 @@ Init_objspace_dump(VALUE rb_mObjSpace)
#if 0
rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
#endif
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ RB_EXT_RACTOR_SAFE(true);
+#endif
rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4);
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index ad3417f9d0..ce01b3e0f2 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,3 +1,132 @@
+Version 4.0.2
+=============
+
+Merged changes in 3.2.4 and 3.3.3.
+
+
+Version 4.0.1
+=============
+
+Notable changes
+---------------
+
+* Add `sync_close` keyword argument to `OpenSSL::SSL::SSLSocket.new` as a
+ short-hand for setting `sync_close` attribute on the created `SSLSocket`
+ instance.
+ [[GitHub #955]](https://github.com/ruby/openssl/issues/955)
+ [[GitHub #996]](https://github.com/ruby/openssl/pull/996)
+
+
+Bug fixes
+---------
+
+* Fix uninitialized variables in `OpenSSL::OCSP::BasicResponse#status`.
+ [[GitHub #1004]](https://github.com/ruby/openssl/pull/1004)
+
+
+Version 4.0.0
+=============
+
+Compatibility
+-------------
+
+* Ruby >= 2.7
+* OpenSSL >= 1.1.1, LibreSSL >= 3.9, and AWS-LC 1.66.0
+ - Removed support for OpenSSL 1.0.2-1.1.0 and LibreSSL 3.1-3.8.
+ [[GitHub #835]](https://github.com/ruby/openssl/issues/835)
+ - Added support for AWS-LC.
+ [[GitHub #833]](https://github.com/ruby/openssl/issues/833)
+
+
+Notable changes
+---------------
+
+* `OpenSSL::SSL`
+ - Reduce overhead when writing to `OpenSSL::SSL::SSLSocket`. `#syswrite` no
+ longer creates a temporary String object.
+ [[GitHub #831]](https://github.com/ruby/openssl/pull/831)
+ - Make `OpenSSL::SSL::SSLContext#min_version=` and `#max_version=` wrap the
+ corresponding OpenSSL APIs directly, and remove the fallback to SSL options.
+ [[GitHub #849]](https://github.com/ruby/openssl/pull/849)
+ - Add `OpenSSL::SSL::SSLContext#sigalgs=` and `#client_sigalgs=` for
+ specifying signature algorithms to use for connections.
+ [[GitHub #895]](https://github.com/ruby/openssl/pull/895)
+ - Rename `OpenSSL::SSL::SSLContext#ecdh_curves=` to `#groups=` following
+ the underlying OpenSSL API rename. This method is no longer specific to
+ ECDHE. The old method remains as an alias.
+ [[GitHub #900]](https://github.com/ruby/openssl/pull/900)
+ - Add `OpenSSL::SSL::SSLSocket#sigalg`, `#peer_sigalg`, and `#group` for
+ getting the signature algorithm and the key agreement group used in the
+ current connection.
+ [[GitHub #908]](https://github.com/ruby/openssl/pull/908)
+ - Enable `SSL_CTX_set_dh_auto()` for servers by default.
+ [[GitHub #924]](https://github.com/ruby/openssl/pull/924)
+ - Improve Ractor compatibility. Note that the internal-use constant
+ `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` is now frozen.
+ [[GitHub #925]](https://github.com/ruby/openssl/pull/925)
+* `OpenSSL::PKey`
+ - Remove `OpenSSL::PKey::EC::Point#mul` support with array arguments. The
+ underlying OpenSSL API has been removed, and the method has been deprecated
+ since ruby/openssl v3.0.0.
+ [[GitHub #843]](https://github.com/ruby/openssl/pull/843)
+ - `OpenSSL::PKey::{RSA,DSA,DH}#params` uses `nil` to indicate missing fields
+ instead of the number `0`.
+ [[GitHub #774]](https://github.com/ruby/openssl/pull/774)
+ - Unify `OpenSSL::PKey::PKeyError` classes. The former subclasses
+ `OpenSSL::PKey::DHError`, `OpenSSL::PKey::DSAError`,
+ `OpenSSL::PKey::ECError`, and `OpenSSL::PKey::RSAError` have been merged
+ into a single class.
+ [[GitHub #929]](https://github.com/ruby/openssl/pull/929)
+* `OpenSSL::Cipher`
+ - `OpenSSL::Cipher#encrypt` and `#decrypt` no longer accept arguments.
+ Passing passwords has been deprecated since Ruby 1.8.2 (released in 2004).
+ [[GitHub #887]](https://github.com/ruby/openssl/pull/887)
+ - `OpenSSL::Cipher#final` raises `OpenSSL::Cipher::AuthTagError` when the
+ integrity check fails for AEAD ciphers. `OpenSSL::Cipher::AuthTagError` is a
+ new subclass of `OpenSSL::Cipher::CipherError`, which was previously raised.
+ [[GitHub #939]](https://github.com/ruby/openssl/pull/939)
+ - `OpenSSL::Cipher.new` now raises `OpenSSL::Cipher::CipherError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" cipher algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::Digest`
+ - `OpenSSL::Digest.new` now raises `OpenSSL::Digest::DigestError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" digest algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::ASN1.decode` now assumes a 1950-2049 year range for `UTCTime`
+ according to RFC 5280. It previously used a 1969-2068 range. The encoder
+ has always used the 1950-2049 range.
+ [[GitHub #909]](https://github.com/ruby/openssl/pull/909)
+* `OpenSSL::OpenSSLError`, the base class for all ruby/openssl errors, carry
+ an additional attribute `#errors` to keep the content of OpenSSL's error
+ queue. Also, add `#detailed_message` for Ruby 3.2 or later.
+ [[GitHub #976]](https://github.com/ruby/openssl/pull/976)
+* `OpenSSL::PKCS7.new` raises `OpenSSL::PKCS7::PKCS7Error` instead of
+ `ArgumentError` on error to be consistent with other constructors.
+ [[GitHub #983]](https://github.com/ruby/openssl/pull/983)
+
+
+Version 3.3.3
+=============
+
+Merged changes in 3.2.4.
+
+
+Version 3.3.2
+=============
+
+Merged changes in 3.1.3 and 3.2.3.
+
+
+Version 3.3.1
+=============
+
+Merged changes in 3.1.2 and 3.2.2.
+
+
Version 3.3.0
=============
@@ -74,6 +203,28 @@ And various non-user-visible changes and bug fixes. Please see the commit
history for more details.
+Version 3.2.4
+=============
+
+Notable changes
+---------------
+
+* Add support for OpenSSL 4.0.
+ [[GitHub #1051]](https://github.com/ruby/openssl/pull/1051)
+
+
+Version 3.2.3
+=============
+
+Merged changes in 3.1.3.
+
+
+Version 3.2.2
+=============
+
+Merged changes in 3.1.2.
+
+
Version 3.2.1
=============
@@ -120,6 +271,33 @@ Notable changes
[[GitHub #141]](https://github.com/ruby/openssl/pull/141)
+Version 3.1.3
+=============
+
+Bug fixes
+---------
+
+* Fix missing NULL check for `EVP_PKEY_get0()` functions with OpenSSL 3.x.
+ [[GitHub #957]](https://github.com/ruby/openssl/pull/957)
+
+
+Version 3.1.2
+=============
+
+Bug fixes
+---------
+
+* Fix crash when attempting to export an incomplete `OpenSSL::PKey::DSA` key.
+ [[GitHub #845]](https://github.com/ruby/openssl/issues/845)
+ [[GitHub #847]](https://github.com/ruby/openssl/pull/847)
+* Remove the `OpenSSL::X509::V_FLAG_CRL_CHECK_ALL` flag from the default store
+ used by `OpenSSL::SSL::SSLContext#set_params`. It causes certificate
+ verification to fail with OpenSSL 3.6.0. It has no effect with any other
+ OpenSSL versions.
+ [[GitHub #949]](https://github.com/ruby/openssl/issues/949)
+ [[GitHub #950]](https://github.com/ruby/openssl/pull/950)
+
+
Version 3.1.1
=============
diff --git a/ext/openssl/depend b/ext/openssl/depend
index 0a8800a94a..435f4a1c68 100644
--- a/ext/openssl/depend
+++ b/ext/openssl/depend
@@ -142,6 +142,7 @@ ossl.o: $(hdrdir)/ruby/internal/intern/re.h
ossl.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl.o: $(hdrdir)/ruby/internal/intern/select.h
ossl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl.o: $(hdrdir)/ruby/internal/intern/set.h
ossl.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -338,6 +339,7 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -534,6 +536,7 @@ ossl_bio.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_bio.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -730,6 +733,7 @@ ossl_bn.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_bn.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -926,6 +930,7 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1122,6 +1127,7 @@ ossl_config.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_config.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1318,6 +1324,7 @@ ossl_digest.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_digest.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1514,6 +1521,7 @@ ossl_engine.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_engine.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1710,6 +1718,7 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1906,6 +1915,7 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2102,6 +2112,7 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2298,6 +2309,7 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2494,6 +2506,7 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2690,6 +2703,7 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2886,6 +2900,7 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3082,6 +3097,7 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3278,6 +3294,7 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3474,6 +3491,7 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3670,6 +3688,7 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3866,6 +3885,7 @@ 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/set.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
@@ -4062,6 +4082,7 @@ ossl_rand.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_rand.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4258,6 +4279,7 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4454,6 +4476,7 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4650,6 +4673,7 @@ ossl_ts.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ts.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4846,6 +4870,7 @@ ossl_x509.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5042,6 +5067,7 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5238,6 +5264,7 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5434,6 +5461,7 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5630,6 +5658,7 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5826,6 +5855,7 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -6022,6 +6052,7 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -6218,6 +6249,7 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -6414,6 +6446,7 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 5bb045e895..1f32980940 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -38,8 +38,12 @@ Logging::message "=== OpenSSL for Ruby configurator ===\n"
$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
+# Missing in TruffleRuby
+have_func("rb_call_super_kw(0, NULL, 0)", "ruby.h")
+# Ruby 3.1
+have_func("rb_io_descriptor", "ruby/io.h")
+have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h")
+# Ruby 3.2
have_func("rb_io_timeout", "ruby/io.h")
Logging::message "=== Checking for system dependent stuff... ===\n"
@@ -131,18 +135,27 @@ Logging::message "=== Checking for OpenSSL features... ===\n"
evp_h = "openssl/evp.h".freeze
ts_h = "openssl/ts.h".freeze
ssl_h = "openssl/ssl.h".freeze
+stack_h = "openssl/stack.h".freeze
# compile options
have_func("RAND_egd()", "openssl/rand.h")
+# added in OpenSSL 1.0.2, not in LibreSSL yet
+have_func("SSL_CTX_set1_sigalgs_list(NULL, NULL)", ssl_h)
+# added in OpenSSL 1.0.2, not in LibreSSL or AWS-LC yet
+have_func("SSL_CTX_set1_client_sigalgs_list(NULL, NULL)", ssl_h)
+
# added in 1.1.0, currently not in LibreSSL
have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0)", evp_h)
# added in OpenSSL 1.1.1 and LibreSSL 3.5.0, then removed in LibreSSL 4.0.0
have_func("EVP_PKEY_check(NULL)", evp_h)
+# added in OpenSSL 1.1.1, currently not in LibreSSL
+have_func("OPENSSL_sk_new_reserve(NULL, 0)", stack_h)
+
# added in 3.0.0
-have_func("SSL_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
+have_func("SSL_CTX_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
have_func("ERR_get_error_all(NULL, NULL, NULL, NULL, NULL)", "openssl/err.h")
have_func("SSL_CTX_load_verify_file(NULL, \"\")", ssl_h)
have_func("BN_check_prime(NULL, NULL, NULL)", "openssl/bn.h")
@@ -151,9 +164,18 @@ have_func("EVP_MD_CTX_get_pkey_ctx(NULL)", evp_h)
have_func("EVP_PKEY_eq(NULL, NULL)", evp_h)
have_func("EVP_PKEY_dup(NULL)", evp_h)
+# added in 3.2.0
+have_func("SSL_get0_group_name(NULL)", ssl_h)
+
# added in 3.4.0
have_func("TS_VERIFY_CTX_set0_certs(NULL, NULL)", ts_h)
+# added in 3.5.0
+have_func("SSL_get0_peer_signature_name(NULL, NULL)", ssl_h)
+
+# added in 4.0.0
+have_func("ASN1_BIT_STRING_set1(NULL, NULL, 0, 0)", "openssl/asn1.h")
+
Logging::message "=== Checking done. ===\n"
# Append flags from environment variables.
diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb
index 0889923890..98fa8d39f2 100644
--- a/ext/openssl/lib/openssl.rb
+++ b/ext/openssl/lib/openssl.rb
@@ -13,23 +13,26 @@
require 'openssl.so'
require_relative 'openssl/bn'
-require_relative 'openssl/asn1'
-require_relative 'openssl/pkey'
require_relative 'openssl/cipher'
require_relative 'openssl/digest'
require_relative 'openssl/hmac'
-require_relative 'openssl/x509'
-require_relative 'openssl/ssl'
require_relative 'openssl/pkcs5'
+require_relative 'openssl/pkey'
+require_relative 'openssl/ssl'
require_relative 'openssl/version'
+require_relative 'openssl/x509'
module OpenSSL
- # call-seq:
- # OpenSSL.secure_compare(string, string) -> boolean
+ # :call-seq:
+ # OpenSSL.secure_compare(string, string) -> true or false
#
# Constant time memory comparison. Inputs are hashed using SHA-256 to mask
# the length of the secret. Returns +true+ if the strings are identical,
# +false+ otherwise.
+ #
+ # This method is expensive due to the SHA-256 hashing. In most cases, where
+ # the input lengths are known to be equal or are not sensitive,
+ # OpenSSL.fixed_length_secure_compare should be used instead.
def self.secure_compare(a, b)
hashed_a = OpenSSL::Digest.digest('SHA256', a)
hashed_b = OpenSSL::Digest.digest('SHA256', b)
diff --git a/ext/openssl/lib/openssl/asn1.rb b/ext/openssl/lib/openssl/asn1.rb
deleted file mode 100644
index 89fa28e1fb..0000000000
--- a/ext/openssl/lib/openssl/asn1.rb
+++ /dev/null
@@ -1,188 +0,0 @@
-# frozen_string_literal: true
-#--
-#
-# = Ruby-space definitions that completes C-space funcs for ASN.1
-#
-# = Licence
-# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
-#++
-
-module OpenSSL
- module ASN1
- class ASN1Data
- #
- # Carries the value of a ASN.1 type.
- # Please confer Constructive and Primitive for the mappings between
- # ASN.1 data types and Ruby classes.
- #
- attr_accessor :value
-
- # An Integer representing the tag number of this ASN1Data. Never +nil+.
- attr_accessor :tag
-
- # A Symbol representing the tag class of this ASN1Data. Never +nil+.
- # See ASN1Data for possible values.
- attr_accessor :tag_class
-
- #
- # Never +nil+. A boolean value indicating whether the encoding uses
- # indefinite length (in the case of parsing) or whether an indefinite
- # length form shall be used (in the encoding case).
- # In DER, every value uses definite length form. But in scenarios where
- # large amounts of data need to be transferred it might be desirable to
- # have some kind of streaming support available.
- # For example, huge OCTET STRINGs are preferably sent in smaller-sized
- # chunks, each at a time.
- # This is possible in BER by setting the length bytes of an encoding
- # to zero and by this indicating that the following value will be
- # sent in chunks. Indefinite length encodings are always constructed.
- # The end of such a stream of chunks is indicated by sending a EOC
- # (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
- # encoding, but also primitive types such as e.g. OCTET STRINGS or
- # BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
- #
- attr_accessor :indefinite_length
-
- alias infinite_length indefinite_length
- alias infinite_length= indefinite_length=
-
- #
- # :call-seq:
- # OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
- #
- # _value_: Please have a look at Constructive and Primitive to see how Ruby
- # types are mapped to ASN.1 types and vice versa.
- #
- # _tag_: An Integer indicating the tag number.
- #
- # _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
- # possible values.
- #
- # == Example
- # asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
- # tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
- #
- def initialize(value, tag, tag_class)
- raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
-
- @tag = tag
- @value = value
- @tag_class = tag_class
- @indefinite_length = false
- end
- end
-
- module TaggedASN1Data
- #
- # May be used as a hint for encoding a value either implicitly or
- # explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
- # _tagging_ is not set when a ASN.1 structure is parsed using
- # OpenSSL::ASN1.decode.
- #
- attr_accessor :tagging
-
- # :call-seq:
- # OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
- #
- # _value_: is mandatory.
- #
- # _tag_: optional, may be specified for tagged values. If no _tag_ is
- # specified, the UNIVERSAL tag corresponding to the Primitive sub-class
- # is used by default.
- #
- # _tagging_: may be used as an encoding hint to encode a value either
- # explicitly or implicitly, see ASN1 for possible values.
- #
- # _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
- # +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
- # +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
- # cf. ASN1.
- #
- # == Example
- # int = OpenSSL::ASN1::Integer.new(42)
- # zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
- # private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
- #
- def initialize(value, tag = nil, tagging = nil, tag_class = nil)
- tag ||= ASN1.take_default_tag(self.class)
-
- raise ASN1Error, "must specify tag number" unless tag
-
- if tagging
- raise ASN1Error, "invalid tagging method" unless tagging.is_a?(Symbol)
- end
-
- tag_class ||= tagging ? :CONTEXT_SPECIFIC : :UNIVERSAL
-
- raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
-
- @tagging = tagging
- super(value ,tag, tag_class)
- end
- end
-
- class Primitive < ASN1Data
- include TaggedASN1Data
-
- undef_method :indefinite_length=
- undef_method :infinite_length=
- end
-
- class Constructive < ASN1Data
- include TaggedASN1Data
- include Enumerable
-
- # :call-seq:
- # asn1_ary.each { |asn1| block } => asn1_ary
- #
- # Calls the given block once for each element in self, passing that element
- # as parameter _asn1_. If no block is given, an enumerator is returned
- # instead.
- #
- # == Example
- # asn1_ary.each do |asn1|
- # puts asn1
- # end
- #
- def each(&blk)
- @value.each(&blk)
-
- self
- end
- end
-
- class Boolean < Primitive ; end
- class Integer < Primitive ; end
- class Enumerated < Primitive ; end
-
- class BitString < Primitive
- attr_accessor :unused_bits
-
- def initialize(*)
- super
-
- @unused_bits = 0
- end
- end
-
- class EndOfContent < ASN1Data
- def initialize
- super("", 0, :UNIVERSAL)
- end
- end
-
- # :nodoc:
- def self.take_default_tag(klass)
- tag = CLASS_TAG_MAP[klass]
-
- return tag if tag
-
- sklass = klass.superclass
-
- return unless sklass
-
- take_default_tag(sklass)
- end
- end
-end
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 5cda1e931c..4e6dea8d03 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -27,17 +27,21 @@ module OpenSSL
end
%w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512).each do |name|
- klass = Class.new(self) {
- define_method(:initialize, ->(data = nil) {super(name, data)})
- }
-
- singleton = (class << klass; self; end)
-
- singleton.class_eval{
- define_method(:digest) {|data| new.digest(data)}
- define_method(:hexdigest) {|data| new.hexdigest(data)}
- }
+ klass = Class.new(self)
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def initialize(data = nil)
+ super("#{name}", data)
+ end
+ RUBY
+ klass.singleton_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def digest(data)
+ new.digest(data)
+ end
+ def hexdigest(data)
+ new.hexdigest(data)
+ end
+ RUBY
const_set(name.tr('-', '_'), klass)
end
@@ -57,7 +61,7 @@ module OpenSSL
# OpenSSL::Digest("MD5")
# # => OpenSSL::Digest::MD5
#
- # Digest("Foo")
+ # OpenSSL::Digest("Foo")
# # => NameError: wrong constant name Foo
def Digest(name)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index 3d1e8885ca..39871e15dd 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -7,6 +7,9 @@
require_relative 'marshal'
module OpenSSL::PKey
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ DHError = PKeyError
+
class DH
include OpenSSL::Marshal
@@ -102,7 +105,7 @@ module OpenSSL::PKey
# puts dh0.pub_key == dh.pub_key #=> false
def generate_key!
if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000
- raise DHError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
+ raise PKeyError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
"use OpenSSL::PKey.generate_key instead"
end
@@ -147,6 +150,9 @@ module OpenSSL::PKey
end
end
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ DSAError = PKeyError
+
class DSA
include OpenSSL::Marshal
@@ -242,13 +248,9 @@ module OpenSSL::PKey
# sig = dsa.sign_raw(nil, digest)
# p dsa.verify_raw(nil, sig, digest) #=> true
def syssign(string)
- q or raise OpenSSL::PKey::DSAError, "incomplete DSA"
- private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!"
- begin
- sign_raw(nil, string)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::DSAError, $!.message
- end
+ q or raise PKeyError, "incomplete DSA"
+ private? or raise PKeyError, "Private DSA key needed!"
+ sign_raw(nil, string)
end
# :call-seq:
@@ -266,12 +268,13 @@ module OpenSSL::PKey
# A \DSA signature value.
def sysverify(digest, sig)
verify_raw(nil, sig, digest)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::DSAError, $!.message
end
end
if defined?(EC)
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ ECError = PKeyError
+
class EC
include OpenSSL::Marshal
@@ -282,8 +285,6 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
def dsa_sign_asn1(data)
sign_raw(nil, data)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::ECError, $!.message
end
# :call-seq:
@@ -293,8 +294,6 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
def dsa_verify_asn1(data, sig)
verify_raw(nil, sig, data)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::ECError, $!.message
end
# :call-seq:
@@ -334,6 +333,9 @@ module OpenSSL::PKey
end
end
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ RSAError = PKeyError
+
class RSA
include OpenSSL::Marshal
@@ -407,15 +409,11 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
# PKey::PKey#verify_recover instead.
def private_encrypt(string, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- private? or raise OpenSSL::PKey::RSAError, "private key needed."
- begin
- sign_raw(nil, string, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ private? or raise PKeyError, "private key needed."
+ sign_raw(nil, string, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -430,14 +428,10 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
# PKey::PKey#verify_recover instead.
def public_decrypt(string, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- begin
- verify_recover(nil, string, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ verify_recover(nil, string, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -452,14 +446,10 @@ module OpenSSL::PKey
# <b>Deprecated in version 3.0</b>.
# Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
def public_encrypt(data, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- begin
- encrypt(data, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ encrypt(data, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -473,15 +463,11 @@ module OpenSSL::PKey
# <b>Deprecated in version 3.0</b>.
# Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
def private_decrypt(data, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- private? or raise OpenSSL::PKey::RSAError, "private key needed."
- begin
- decrypt(data, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ private? or raise PKeyError, "private key needed."
+ decrypt(data, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
PKCS1_PADDING = 1
@@ -500,7 +486,7 @@ module OpenSSL::PKey
when PKCS1_OAEP_PADDING
"oaep"
else
- raise OpenSSL::PKey::PKeyError, "unsupported padding mode"
+ raise PKeyError, "unsupported padding mode"
end
end
end
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index a0ad5dc3a6..3268c126b9 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -32,25 +32,6 @@ module OpenSSL
}.call
}
- if defined?(OpenSSL::PKey::DH)
- DH_ffdhe2048 = 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==
------END DH PARAMETERS-----
- _end_of_pem_
- private_constant :DH_ffdhe2048
-
- DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
- warn "using default DH parameters." if $VERBOSE
- DH_ffdhe2048
- }
- end
-
if !OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL")
DEFAULT_PARAMS.merge!(
min_version: OpenSSL::SSL::TLS1_VERSION,
@@ -85,26 +66,13 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
AES256-SHA256
AES128-SHA
AES256-SHA
- }.join(":"),
+ }.join(":").freeze,
)
end
+ DEFAULT_PARAMS.freeze
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:
DEFAULT_CERT_STORE.set_default_paths
- DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
-
- # A callback invoked when DH parameters are required for ephemeral DH key
- # exchange.
- #
- # The callback is invoked with the SSLSocket, a
- # flag indicating the use of an export cipher and the keylength
- # required.
- #
- # The callback must return an OpenSSL::PKey::DH instance of the correct
- # key length.
- #
- # <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
- attr_accessor :tmp_dh_callback
# A callback invoked at connect time to distinguish between multiple
# server names.
@@ -147,7 +115,14 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
params.each{|name, value| self.__send__("#{name}=", value) }
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
unless self.ca_file or self.ca_path or self.cert_store
- self.cert_store = DEFAULT_CERT_STORE
+ if not defined?(Ractor) or Ractor.current == Ractor.main
+ self.cert_store = DEFAULT_CERT_STORE
+ else
+ self.cert_store = Ractor.current[:__openssl_default_store__] ||=
+ OpenSSL::X509::Store.new.tap { |store|
+ store.set_default_paths
+ }
+ end
end
end
return params
@@ -457,10 +432,6 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
@context.client_cert_cb
end
- def tmp_dh_callback
- @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK
- end
-
def session_new_cb
@context.session_new_cb
end
diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb
index 3398fe39cc..395a720a31 100644
--- a/ext/openssl/lib/openssl/version.rb
+++ b/ext/openssl/lib/openssl/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module OpenSSL
- VERSION = "3.3.0"
+ # The version string of Ruby/OpenSSL.
+ VERSION = "4.0.2"
end
diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb
index 6459d37b12..66765ffeab 100644
--- a/ext/openssl/lib/openssl/x509.rb
+++ b/ext/openssl/lib/openssl/x509.rb
@@ -346,6 +346,15 @@ module OpenSSL
include Extension::CRLDistributionPoints
include Extension::AuthorityInfoAccess
+ def inspect
+ "#<#{self.class}: " \
+ "subject=#{subject.inspect}, " \
+ "issuer=#{issuer.inspect}, " \
+ "serial=#{serial.inspect}, " \
+ "not_before=#{not_before.inspect rescue "(error)"}, " \
+ "not_after=#{not_after.inspect rescue "(error)"}>"
+ end
+
def pretty_print(q)
q.object_group(self) {
q.breakable
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index 9f7c718592..af1775e3b0 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "openssl"
- spec.version = "3.3.0"
+ spec.version = "4.0.2"
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}
@@ -13,7 +13,8 @@ Gem::Specification.new do |spec|
spec.files = []
spec.add_runtime_dependency('jruby-openssl', '~> 0.14')
else
- spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "COPYING"]
+ spec.files = Dir.glob(["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md"], base: File.expand_path("..", __FILE__)) +
+ ["BSDL", "COPYING"]
spec.require_paths = ["lib"]
spec.extensions = ["ext/openssl/extconf.rb"]
end
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 6592f9ccea..ed3b5b7c0f 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -29,4 +29,27 @@
# define EVP_PKEY_eq(a, b) EVP_PKEY_cmp(a, b)
#endif
+/* added in 4.0.0 */
+#ifndef HAVE_ASN1_BIT_STRING_SET1
+static inline int
+ASN1_BIT_STRING_set1(ASN1_BIT_STRING *bitstr, const uint8_t *data,
+ size_t length, int unused_bits)
+{
+ if (length > INT_MAX || !ASN1_STRING_set(bitstr, data, (int)length))
+ return 0;
+ bitstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ bitstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits;
+ return 1;
+}
+
+static inline int
+ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *bitstr, size_t *length,
+ int *unused_bits)
+{
+ *length = bitstr->length;
+ *unused_bits = bitstr->flags & 0x07;
+ return 1;
+}
+#endif
+
#endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 60780790b0..5716e6f100 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -13,71 +13,75 @@
/*
* Data Conversion
*/
-#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
-VALUE \
-ossl_##name##_ary2sk0(VALUE ary) \
-{ \
- STACK_OF(type) *sk; \
- VALUE val; \
- type *x; \
- int i; \
- \
- Check_Type(ary, T_ARRAY); \
- sk = sk_##type##_new_null(); \
- if (!sk) ossl_raise(eOSSLError, NULL); \
- \
- for (i = 0; i < RARRAY_LEN(ary); i++) { \
- val = rb_ary_entry(ary, i); \
- if (!rb_obj_is_kind_of(val, expected_class)) { \
- sk_##type##_pop_free(sk, type##_free); \
- ossl_raise(eOSSLError, "object in array not" \
- " of class ##type##"); \
- } \
- x = dup(val); /* NEED TO DUP */ \
- sk_##type##_push(sk, x); \
- } \
- return (VALUE)sk; \
-} \
- \
-STACK_OF(type) * \
-ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
-{ \
- return (STACK_OF(type)*)rb_protect( \
- (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \
- ary, \
- status); \
-} \
- \
-STACK_OF(type) * \
-ossl_##name##_ary2sk(VALUE ary) \
-{ \
- STACK_OF(type) *sk; \
- int status = 0; \
- \
- sk = ossl_protect_##name##_ary2sk(ary, &status); \
- if (status) rb_jump_tag(status); \
- \
- return sk; \
+#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
+VALUE \
+ossl_##name##_ary2sk0(VALUE ary) \
+{ \
+ STACK_OF(type) *sk; \
+ VALUE val; \
+ type *x; \
+ int i; \
+ \
+ Check_Type(ary, T_ARRAY); \
+ sk = sk_##type##_new_null(); \
+ if (!sk) ossl_raise(eOSSLError, NULL); \
+ \
+ for (i = 0; i < RARRAY_LEN(ary); i++) { \
+ val = rb_ary_entry(ary, i); \
+ if (!rb_obj_is_kind_of(val, expected_class)) { \
+ sk_##type##_pop_free(sk, type##_free); \
+ ossl_raise(eOSSLError, "object in array not" \
+ " of class ##type##"); \
+ } \
+ x = dup(val); /* NEED TO DUP */ \
+ if (!sk_##type##_push(sk, x)) { \
+ type##_free(x); \
+ sk_##type##_pop_free(sk, type##_free); \
+ ossl_raise(eOSSLError, NULL); \
+ } \
+ } \
+ return (VALUE)sk; \
+} \
+ \
+STACK_OF(type) * \
+ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
+{ \
+ return (STACK_OF(type)*)rb_protect( \
+ (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \
+ ary, \
+ status); \
+} \
+ \
+STACK_OF(type) * \
+ossl_##name##_ary2sk(VALUE ary) \
+{ \
+ STACK_OF(type) *sk; \
+ int status = 0; \
+ \
+ sk = ossl_protect_##name##_ary2sk(ary, &status); \
+ if (status) rb_jump_tag(status); \
+ \
+ return sk; \
}
OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr)
-#define OSSL_IMPL_SK2ARY(name, type) \
-VALUE \
-ossl_##name##_sk2ary(const STACK_OF(type) *sk) \
-{ \
- type *t; \
- int i, num; \
- VALUE ary; \
- \
- RUBY_ASSERT(sk != NULL); \
- num = sk_##type##_num(sk); \
- ary = rb_ary_new_capa(num); \
- \
- for (i=0; i<num; i++) { \
- t = sk_##type##_value(sk, i); \
- rb_ary_push(ary, ossl_##name##_new(t)); \
- } \
- return ary; \
+#define OSSL_IMPL_SK2ARY(name, type) \
+VALUE \
+ossl_##name##_sk2ary(const STACK_OF(type) *sk) \
+{ \
+ type *t; \
+ int i, num; \
+ VALUE ary; \
+ \
+ RUBY_ASSERT(sk != NULL); \
+ num = sk_##type##_num(sk); \
+ ary = rb_ary_new_capa(num); \
+ \
+ for (i=0; i<num; i++) { \
+ t = sk_##type##_value(sk, i); \
+ rb_ary_push(ary, ossl_##name##_new(t)); \
+ } \
+ return ary; \
}
OSSL_IMPL_SK2ARY(x509, X509)
OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
@@ -97,14 +101,14 @@ ossl_str_new(const char *ptr, long len, int *pstate)
str = rb_protect(ossl_str_new_i, len, &state);
if (pstate)
- *pstate = state;
+ *pstate = state;
if (state) {
- if (!pstate)
- rb_set_errinfo(Qnil);
- return Qnil;
+ if (!pstate)
+ rb_set_errinfo(Qnil);
+ return Qnil;
}
if (ptr)
- memcpy(RSTRING_PTR(str), ptr, len);
+ memcpy(RSTRING_PTR(str), ptr, len);
return str;
}
@@ -117,22 +121,22 @@ ossl_buf2str(char *buf, int len)
str = ossl_str_new(buf, len, &state);
OPENSSL_free(buf);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return str;
}
void
-ossl_bin2hex(unsigned char *in, char *out, size_t inlen)
+ossl_bin2hex(const unsigned char *in, char *out, size_t inlen)
{
const char *hex = "0123456789abcdef";
size_t i;
assert(inlen <= LONG_MAX / 2);
for (i = 0; i < inlen; i++) {
- unsigned char p = in[i];
+ unsigned char p = in[i];
- out[i * 2 + 0] = hex[p >> 4];
- out[i * 2 + 1] = hex[p & 0x0f];
+ out[i * 2 + 0] = hex[p >> 4];
+ out[i * 2 + 1] = hex[p & 0x0f];
}
}
@@ -143,14 +147,14 @@ VALUE
ossl_pem_passwd_value(VALUE pass)
{
if (NIL_P(pass))
- return Qnil;
+ return Qnil;
StringValue(pass);
/* PEM_BUFSIZE is currently used as the second argument of pem_password_cb,
* that is +max_len+ of ossl_pem_passwd_cb() */
if (RSTRING_LEN(pass) > PEM_BUFSIZE)
- ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE);
+ ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE);
return pass;
}
@@ -160,7 +164,7 @@ ossl_pem_passwd_cb0(VALUE flag)
{
VALUE pass = rb_yield(flag);
if (NIL_P(pass))
- return Qnil;
+ return Qnil;
StringValue(pass);
return pass;
}
@@ -173,46 +177,46 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
VALUE rflag, pass = (VALUE)pwd_;
if (RTEST(pass)) {
- /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not
- * work because it does not allow NUL characters and truncates to 1024
- * bytes silently if the input is over 1024 bytes */
- if (RB_TYPE_P(pass, T_STRING)) {
- len = RSTRING_LEN(pass);
- if (len <= max_len) {
- memcpy(buf, RSTRING_PTR(pass), len);
- return (int)len;
- }
- }
- OSSL_Debug("passed data is not valid String???");
- return -1;
+ /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not
+ * work because it does not allow NUL characters and truncates to 1024
+ * bytes silently if the input is over 1024 bytes */
+ if (RB_TYPE_P(pass, T_STRING)) {
+ len = RSTRING_LEN(pass);
+ if (len <= max_len) {
+ memcpy(buf, RSTRING_PTR(pass), len);
+ return (int)len;
+ }
+ }
+ OSSL_Debug("passed data is not valid String???");
+ return -1;
}
if (!rb_block_given_p()) {
- return PEM_def_callback(buf, max_len, flag, NULL);
+ return PEM_def_callback(buf, max_len, flag, NULL);
}
while (1) {
- /*
- * when the flag is nonzero, this password
- * will be used to perform encryption; otherwise it will
- * be used to perform decryption.
- */
- rflag = flag ? Qtrue : Qfalse;
- pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
- if (status) {
- /* ignore an exception raised. */
- rb_set_errinfo(Qnil);
- return -1;
- }
- if (NIL_P(pass))
- return -1;
- len = RSTRING_LEN(pass);
- if (len > max_len) {
- rb_warning("password must not be longer than %d bytes", max_len);
- continue;
- }
- memcpy(buf, RSTRING_PTR(pass), len);
- break;
+ /*
+ * when the flag is nonzero, this password
+ * will be used to perform encryption; otherwise it will
+ * be used to perform decryption.
+ */
+ rflag = flag ? Qtrue : Qfalse;
+ pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
+ if (status) {
+ /* ignore an exception raised. */
+ rb_set_errinfo(Qnil);
+ return -1;
+ }
+ if (NIL_P(pass))
+ return -1;
+ len = RSTRING_LEN(pass);
+ if (len > max_len) {
+ rb_warning("password must not be longer than %d bytes", max_len);
+ continue;
+ }
+ memcpy(buf, RSTRING_PTR(pass), len);
+ break;
}
return (int)len;
}
@@ -247,19 +251,24 @@ VALUE
ossl_to_der_if_possible(VALUE obj)
{
if(rb_respond_to(obj, ossl_s_to_der))
- return ossl_to_der(obj);
+ return ossl_to_der(obj);
return obj;
}
/*
* Errors
*/
+static ID id_i_errors;
+
+static void collect_errors_into(VALUE ary);
+
VALUE
ossl_make_error(VALUE exc, VALUE str)
{
unsigned long e;
const char *data;
int flags;
+ VALUE errors = rb_ary_new();
if (NIL_P(str))
str = rb_str_new(NULL, 0);
@@ -276,10 +285,12 @@ ossl_make_error(VALUE exc, VALUE str)
rb_str_cat_cstr(str, msg ? msg : "(null)");
if (flags & ERR_TXT_STRING && data)
rb_str_catf(str, " (%s)", data);
- ossl_clear_error();
+ collect_errors_into(errors);
}
- return rb_exc_new_str(exc, str);
+ VALUE obj = rb_exc_new_str(exc, str);
+ rb_ivar_set(obj, id_i_errors, errors);
+ return obj;
}
void
@@ -289,24 +300,23 @@ ossl_raise(VALUE exc, const char *fmt, ...)
VALUE err;
if (fmt) {
- va_start(args, fmt);
- err = rb_vsprintf(fmt, args);
- va_end(args);
+ va_start(args, fmt);
+ err = rb_vsprintf(fmt, args);
+ va_end(args);
}
else {
- err = Qnil;
+ err = Qnil;
}
rb_exc_raise(ossl_make_error(exc, err));
}
-void
-ossl_clear_error(void)
+static void
+collect_errors_into(VALUE ary)
{
- if (dOSSL == Qtrue) {
+ if (dOSSL == Qtrue || !NIL_P(ary)) {
unsigned long e;
const char *file, *data, *func, *lib, *reason;
- char append[256] = "";
int line, flags;
#ifdef HAVE_ERR_GET_ERROR_ALL
@@ -318,13 +328,18 @@ ossl_clear_error(void)
lib = ERR_lib_error_string(e);
reason = ERR_reason_error_string(e);
+ VALUE str = rb_sprintf("error:%08lX:%s:%s:%s", e, lib ? lib : "",
+ func ? func : "", reason ? reason : "");
if (flags & ERR_TXT_STRING) {
if (!data)
data = "(null)";
- snprintf(append, sizeof(append), " (%s)", data);
+ rb_str_catf(str, " (%s)", data);
}
- rb_warn("error on stack: error:%08lX:%s:%s:%s%s", e, lib ? lib : "",
- func ? func : "", reason ? reason : "", append);
+
+ if (dOSSL == Qtrue)
+ rb_warn("error on stack: %"PRIsVALUE, str);
+ if (!NIL_P(ary))
+ rb_ary_push(ary, str);
}
}
else {
@@ -332,14 +347,59 @@ ossl_clear_error(void)
}
}
+void
+ossl_clear_error(void)
+{
+ collect_errors_into(Qnil);
+}
+
+/*
+ * call-seq:
+ * ossl_error.detailed_message(**) -> string
+ *
+ * Returns the exception message decorated with the captured \OpenSSL error
+ * queue entries.
+ */
+static VALUE
+osslerror_detailed_message(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str;
+#ifdef HAVE_RB_CALL_SUPER_KW
+ // Ruby >= 3.2
+ if (RTEST(rb_funcall(rb_eException, rb_intern("method_defined?"), 1,
+ ID2SYM(rb_intern("detailed_message")))))
+ str = rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
+ else
+#endif
+ str = rb_funcall(self, rb_intern("message"), 0);
+ VALUE errors = rb_attr_get(self, id_i_errors);
+
+ // OpenSSLError was not created by ossl_make_error()
+ if (!RB_TYPE_P(errors, T_ARRAY))
+ return str;
+
+ str = rb_str_resurrect(str);
+ rb_str_catf(str, "\nOpenSSL error queue reported %ld errors:",
+ RARRAY_LEN(errors));
+ for (long i = 0; i < RARRAY_LEN(errors); i++) {
+ VALUE err = RARRAY_AREF(errors, i);
+ rb_str_catf(str, "\n%"PRIsVALUE, err);
+ }
+ return str;
+}
+
/*
* call-seq:
* OpenSSL.errors -> [String...]
*
- * See any remaining errors held in queue.
+ * Returns any remaining errors held in the \OpenSSL thread-local error queue
+ * and clears the queue. This should normally return an empty array.
+ *
+ * This is intended for debugging Ruby/OpenSSL. If you see any errors here,
+ * it likely indicates a bug in the extension. Please file an issue at
+ * https://github.com/ruby/openssl.
*
- * Any errors you see here are probably due to a bug in Ruby's OpenSSL
- * implementation.
+ * For debugging your program, OpenSSL.debug= may be useful.
*/
static VALUE
ossl_get_errors(VALUE _)
@@ -363,6 +423,8 @@ VALUE dOSSL;
/*
* call-seq:
* OpenSSL.debug -> true | false
+ *
+ * Returns whether Ruby/OpenSSL's debug mode is currently enabled.
*/
static VALUE
ossl_debug_get(VALUE self)
@@ -372,9 +434,9 @@ ossl_debug_get(VALUE self)
/*
* call-seq:
- * OpenSSL.debug = boolean -> boolean
+ * OpenSSL.debug = boolean
*
- * Turns on or off debug mode. With debug mode, all errors added to the OpenSSL
+ * Turns on or off debug mode. With debug mode, all errors added to the \OpenSSL
* error queue will be printed to stderr.
*/
static VALUE
@@ -388,6 +450,8 @@ ossl_debug_set(VALUE self, VALUE val)
/*
* call-seq:
* OpenSSL.fips_mode -> true | false
+ *
+ * Returns whether the FIPS mode is currently enabled.
*/
static VALUE
ossl_fips_mode_get(VALUE self)
@@ -408,10 +472,10 @@ ossl_fips_mode_get(VALUE self)
/*
* call-seq:
- * OpenSSL.fips_mode = boolean -> boolean
+ * OpenSSL.fips_mode = boolean
*
* Turns FIPS mode on or off. Turning on FIPS mode will obviously only have an
- * effect for FIPS-capable installations of the OpenSSL library. Trying to do
+ * effect for FIPS-capable installations of the \OpenSSL library. Trying to do
* so otherwise will result in an error.
*
* === Examples
@@ -434,52 +498,60 @@ ossl_fips_mode_set(VALUE self, VALUE enabled)
return enabled;
#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC)
if (RTEST(enabled)) {
- int mode = FIPS_mode();
- if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
- ossl_raise(eOSSLError, "Turning on FIPS mode failed");
+ int mode = FIPS_mode();
+ if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
+ ossl_raise(eOSSLError, "Turning on FIPS mode failed");
} else {
- if(!FIPS_mode_set(0)) /* turning off twice is OK */
- ossl_raise(eOSSLError, "Turning off FIPS mode failed");
+ if(!FIPS_mode_set(0)) /* turning off twice is OK */
+ ossl_raise(eOSSLError, "Turning off FIPS mode failed");
}
return enabled;
#else
if (RTEST(enabled))
- ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
+ ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
return enabled;
#endif
}
/*
* call-seq:
- * OpenSSL.fixed_length_secure_compare(string, string) -> boolean
+ * OpenSSL.fixed_length_secure_compare(string, string) -> true or false
*
* Constant time memory comparison for fixed length strings, such as results
- * of HMAC calculations.
+ * of \HMAC calculations.
*
* Returns +true+ if the strings are identical, +false+ if they are of the same
- * length but not identical. If the length is different, +ArgumentError+ is
+ * length but not identical. If the length is different, ArgumentError is
* raised.
*/
static VALUE
ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
{
- const unsigned char *p1 = (const unsigned char *)StringValuePtr(str1);
- const unsigned char *p2 = (const unsigned char *)StringValuePtr(str2);
- long len1 = RSTRING_LEN(str1);
- long len2 = RSTRING_LEN(str2);
+ const unsigned char *p1;
+ const unsigned char *p2;
+ long len1;
+ long len2;
+
+ StringValue(str1);
+ StringValue(str2);
+
+ p1 = (const unsigned char *)RSTRING_PTR(str1);
+ p2 = (const unsigned char *)RSTRING_PTR(str2);
+ len1 = RSTRING_LEN(str1);
+ len2 = RSTRING_LEN(str2);
if (len1 != len2) {
ossl_raise(rb_eArgError, "inputs must be of equal length");
}
switch (CRYPTO_memcmp(p1, p2, len1)) {
- case 0: return Qtrue;
- default: return Qfalse;
+ case 0: return Qtrue;
+ default: return Qfalse;
}
}
/*
- * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
+ * OpenSSL provides \SSL, TLS and general purpose cryptography. It wraps the
* OpenSSL[https://www.openssl.org/] library.
*
* = Examples
@@ -534,7 +606,7 @@ 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.
+ * \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
* loading the key:
*
@@ -597,7 +669,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* == PBKDF2 Password-based Encryption
*
- * If supported by the underlying OpenSSL version used, Password-based
+ * If supported by the underlying \OpenSSL version used, Password-based
* Encryption should use the features of PKCS5. If not supported or if
* required by legacy applications, the older, less secure methods specified
* in RFC 2898 are also supported (see below).
@@ -656,7 +728,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* decrypted = cipher.update encrypted
* decrypted << cipher.final
*
- * == X509 Certificates
+ * == \X509 Certificates
*
* === Creating a Certificate
*
@@ -693,7 +765,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* extension_factory.create_extension('subjectKeyIdentifier', 'hash')
*
* The list of supported extensions (and in some cases their possible values)
- * can be derived from the "objects.h" file in the OpenSSL source code.
+ * can be derived from the "objects.h" file in the \OpenSSL source code.
*
* === Signing a Certificate
*
@@ -847,23 +919,23 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* io.write csr_cert.to_pem
* end
*
- * == SSL and TLS Connections
+ * == \SSL and TLS Connections
*
- * Using our created key and certificate we can create an SSL or TLS connection.
- * An SSLContext is used to set up an SSL session.
+ * Using our created key and certificate we can create an \SSL or TLS
+ * connection. An OpenSSL::SSL::SSLContext is used to set up an \SSL session.
*
* context = OpenSSL::SSL::SSLContext.new
*
- * === SSL Server
+ * === \SSL Server
*
- * An SSL server requires the certificate and private key to communicate
+ * An \SSL server requires the certificate and private key to communicate
* securely with its clients:
*
* context.cert = cert
* context.key = key
*
- * Then create an SSLServer with a TCP server socket and the context. Use the
- * SSLServer like an ordinary TCP server.
+ * Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the
+ * context. Use the SSLServer like an ordinary TCP server.
*
* require 'socket'
*
@@ -882,14 +954,15 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* ssl_connection.close
* end
*
- * === SSL client
+ * === \SSL client
*
- * An SSL client is created with a TCP socket and the context.
- * SSLSocket#connect must be called to initiate the SSL handshake and start
- * encryption. A key and certificate are not required for the client socket.
+ * An \SSL client is created with a TCP socket and the context.
+ * OpenSSL::SSL::SSLSocket#connect must be called to initiate the \SSL handshake
+ * and start encryption. A key and certificate are not required for the client
+ * socket.
*
- * Note that SSLSocket#close doesn't close the underlying socket by default. Set
- * SSLSocket#sync_close to true if you want.
+ * Note that OpenSSL::SSL::SSLSocket#close doesn't close the underlying socket
+ * by default. Set OpenSSL::SSL::SSLSocket#sync_close to true if you want.
*
* require 'socket'
*
@@ -905,7 +978,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Peer Verification
*
- * An unverified SSL connection does not provide much security. For enhanced
+ * An unverified \SSL connection does not provide much security. For enhanced
* security the client or server can verify the certificate of its peer.
*
* The client can be modified to verify the server's certificate against the
@@ -956,22 +1029,34 @@ Init_openssl(void)
rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2);
/*
- * Version of OpenSSL the ruby OpenSSL extension was built with
+ * \OpenSSL library version string used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+ rb_define_const(mOSSL, "OPENSSL_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OPENSSL_VERSION_TEXT)));
/*
- * Version of OpenSSL the ruby OpenSSL extension is running with
+ * \OpenSSL library version string currently used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
+ rb_define_const(
+ mOSSL,
+ "OPENSSL_LIBRARY_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION)))
+ );
/*
- * Version number of OpenSSL the ruby OpenSSL extension was built with
- * (base 16). The formats are below.
+ * \OpenSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * The version number is encoded into a single integer value. The number
+ * follows the format:
*
- * [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>
+ * [\OpenSSL 3.0.0 or later]
+ * <tt>0xMNN00PP0</tt> (major minor 00 patch 0)
+ * [\OpenSSL 1.1.1 or earlier]
+ * <tt>0xMNNFFPPS</tt> (major minor fix patch status)
+ * [LibreSSL]
+ * <tt>0x20000000</tt> (a fixed value)
*
* See also the man page OPENSSL_VERSION_NUMBER(3).
*/
@@ -979,9 +1064,12 @@ Init_openssl(void)
#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.
+ * LibreSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * This constant is only defined if the extension was compiled against
+ * LibreSSL. The number follows the format:
+ * <tt>0xMNNFF00f</tt> (major minor fix 00 status).
*
* See also the man page LIBRESSL_VERSION_NUMBER(3).
*/
@@ -989,30 +1077,50 @@ Init_openssl(void)
#endif
/*
- * Boolean indicating whether OpenSSL is FIPS-capable or not
+ * Boolean indicating whether the \OpenSSL library is FIPS-capable or not.
+ * Always <tt>true</tt> for \OpenSSL 3.0 and later.
+ *
+ * This is obsolete and will be removed in the future.
+ * See also OpenSSL.fips_mode.
*/
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)
- Qtrue
+ Qtrue
#elif defined(OPENSSL_IS_AWSLC) // AWS-LC FIPS can only be enabled during compile time.
- FIPS_mode() ? Qtrue : Qfalse
+ FIPS_mode() ? Qtrue : Qfalse
#else
- Qfalse
+ Qfalse
#endif
- );
+ );
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
+ * Generic error class for OpenSSL. All error classes in this library
+ * inherit from this class.
+ *
+ * This class indicates that an error was reported by the underlying
+ * \OpenSSL library.
+ */
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
+ /*
+ * \OpenSSL error queue entries captured at the time the exception was
+ * raised. The same information is printed to stderr if OpenSSL.debug is
+ * set to +true+.
+ *
+ * This is an array of zero or more strings, ordered from the oldest to the
+ * newest. The format of the strings is not stable and may vary across
+ * versions of \OpenSSL or versions of this Ruby extension.
+ *
+ * See also the man page ERR_get_error(3).
*/
- eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_attr(eOSSLError, rb_intern_const("errors"), 1, 0, 0);
+ rb_define_method(eOSSLError, "detailed_message", osslerror_detailed_message, -1);
/*
* Init debug core
@@ -1028,6 +1136,7 @@ Init_openssl(void)
* Get ID of to_der
*/
ossl_s_to_der = rb_intern("to_der");
+ id_i_errors = rb_intern("@errors");
/*
* Init components
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 9b20829b3f..0b479a7200 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -71,6 +71,11 @@
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
# define OSSL_USE_PROVIDER
+# include <openssl/provider.h>
+#endif
+
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+# define OSSL_HAVE_IMMUTABLE_PKEY
#endif
/*
@@ -87,10 +92,10 @@ extern VALUE eOSSLError;
* CheckTypes
*/
#define OSSL_Check_Kind(obj, klass) do {\
- if (!rb_obj_is_kind_of((obj), (klass))) {\
- ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\
- rb_obj_class(obj), (klass));\
- }\
+ if (!rb_obj_is_kind_of((obj), (klass))) {\
+ ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\
+ rb_obj_class(obj), (klass));\
+ }\
} while (0)
/*
@@ -126,7 +131,7 @@ do{\
* Convert binary string to hex string. The caller is responsible for
* ensuring out has (2 * len) bytes of capacity.
*/
-void ossl_bin2hex(unsigned char *in, char *out, size_t len);
+void ossl_bin2hex(const unsigned char *in, char *out, size_t len);
/*
* Our default PEM callback
@@ -169,11 +174,11 @@ VALUE ossl_to_der_if_possible(VALUE);
extern VALUE dOSSL;
#define OSSL_Debug(...) do { \
- if (dOSSL == Qtrue) { \
- fprintf(stderr, "OSSL_DEBUG: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
- } \
+ if (dOSSL == Qtrue) { \
+ fprintf(stderr, "OSSL_DEBUG: "); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
+ } \
} while (0)
/*
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index ea3ec2f210..517212b4d5 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -9,63 +9,81 @@
*/
#include "ossl.h"
-static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
- int depth, int yield, long *num_read);
+/********/
+/*
+ * ASN1 module
+ */
+#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
+#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
+#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
+#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
+#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
+
+#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
+#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
+#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
+#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
+#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
+
+VALUE mASN1;
+static VALUE eASN1Error;
+
+VALUE cASN1Data;
+static VALUE cASN1Primitive;
+static VALUE cASN1Constructive;
+
+static VALUE cASN1EndOfContent;
+static VALUE cASN1Boolean; /* BOOLEAN */
+static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
+static VALUE cASN1BitString; /* BIT STRING */
+static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
+static VALUE cASN1NumericString, cASN1PrintableString;
+static VALUE cASN1T61String, cASN1VideotexString;
+static VALUE cASN1IA5String, cASN1GraphicString;
+static VALUE cASN1ISO64String, cASN1GeneralString;
+static VALUE cASN1UniversalString, cASN1BMPString;
+static VALUE cASN1Null; /* NULL */
+static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
+static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
+static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
+
+static VALUE sym_IMPLICIT, sym_EXPLICIT;
+static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
+static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
+static ID id_each;
/*
* DATE conversion
*/
+static VALUE
+time_utc_new(VALUE args)
+{
+ return rb_funcallv(rb_cTime, rb_intern("utc"), 6, (VALUE *)args);
+}
+
+static VALUE
+time_utc_new_rescue(VALUE args, VALUE exc)
+{
+ rb_raise(eASN1Error, "invalid time");
+}
+
VALUE
asn1time_to_time(const ASN1_TIME *time)
{
struct tm tm;
- VALUE argv[6];
- int count;
-
- memset(&tm, 0, sizeof(struct tm));
-
- switch (time->type) {
- case V_ASN1_UTCTIME:
- count = sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
- &tm.tm_sec);
-
- if (count == 5) {
- tm.tm_sec = 0;
- } else if (count != 6) {
- ossl_raise(rb_eTypeError, "bad UTCTIME format: \"%s\"",
- time->data);
- }
- if (tm.tm_year < 69) {
- tm.tm_year += 2000;
- } else {
- tm.tm_year += 1900;
- }
- break;
- case V_ASN1_GENERALIZEDTIME:
- count = sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
- &tm.tm_sec);
- if (count == 5) {
- tm.tm_sec = 0;
- }
- else if (count != 6) {
- ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format: \"%s\"",
- time->data);
- }
- break;
- default:
- rb_warning("unknown time format");
- return Qnil;
- }
- argv[0] = INT2NUM(tm.tm_year);
- argv[1] = INT2NUM(tm.tm_mon);
- argv[2] = INT2NUM(tm.tm_mday);
- argv[3] = INT2NUM(tm.tm_hour);
- argv[4] = INT2NUM(tm.tm_min);
- argv[5] = INT2NUM(tm.tm_sec);
-
- return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
+ if (!ASN1_TIME_to_tm(time, &tm))
+ ossl_raise(eASN1Error, "ASN1_TIME_to_tm");
+
+ VALUE args[] = {
+ INT2NUM(tm.tm_year + 1900),
+ INT2NUM(tm.tm_mon + 1),
+ INT2NUM(tm.tm_mday),
+ INT2NUM(tm.tm_hour),
+ INT2NUM(tm.tm_min),
+ INT2NUM(tm.tm_sec),
+ };
+ return rb_rescue2(time_utc_new, (VALUE)args, time_utc_new_rescue, Qnil,
+ rb_eArgError, 0);
}
static VALUE
@@ -80,13 +98,13 @@ ossl_time_split(VALUE time, time_t *sec, int *days)
VALUE num = rb_Integer(time);
if (FIXNUM_P(num)) {
- time_t t = FIX2LONG(num);
- *sec = t % 86400;
- *days = rb_long2int(t / 86400);
+ time_t t = FIX2LONG(num);
+ *sec = t % 86400;
+ *days = rb_long2int(t / 86400);
}
else {
- *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400)));
- *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400)));
+ *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400)));
+ *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400)));
}
}
@@ -96,7 +114,8 @@ ossl_time_split(VALUE time, time_t *sec, int *days)
VALUE
asn1str_to_str(const ASN1_STRING *str)
{
- return rb_str_new((const char *)str->data, str->length);
+ return rb_str_new((const char *)ASN1_STRING_get0_data(str),
+ ASN1_STRING_length(str));
}
/*
@@ -109,18 +128,19 @@ asn1integer_to_num(const ASN1_INTEGER *ai)
VALUE num;
if (!ai) {
- ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
+ ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
}
- if (ai->type == V_ASN1_ENUMERATED)
- /* const_cast: workaround for old OpenSSL */
- bn = ASN1_ENUMERATED_to_BN((ASN1_ENUMERATED *)ai, NULL);
+
+ num = ossl_bn_new(BN_value_one());
+ bn = GetBNPtr(num);
+
+ if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED)
+ bn = ASN1_ENUMERATED_to_BN(ai, bn);
else
- bn = ASN1_INTEGER_to_BN(ai, NULL);
+ bn = ASN1_INTEGER_to_BN(ai, bn);
if (!bn)
- ossl_raise(eOSSLError, NULL);
- num = ossl_bn_new(bn);
- BN_free(bn);
+ ossl_raise(eOSSLError, NULL);
return num;
}
@@ -131,12 +151,12 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
BIGNUM *bn;
if (NIL_P(obj))
- ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
+ ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
bn = GetBNPtr(obj);
if (!(ai = BN_to_ASN1_INTEGER(bn, ai)))
- ossl_raise(eOSSLError, NULL);
+ ossl_raise(eOSSLError, NULL);
return ai;
}
@@ -147,43 +167,47 @@ asn1integer_to_num_i(VALUE arg)
return asn1integer_to_num((ASN1_INTEGER *)arg);
}
-/********/
/*
- * ASN1 module
+ * ASN1_OBJECT conversions
*/
-#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
-#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
-#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
-#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
-#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
-
-#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
-
-VALUE mASN1;
-VALUE eASN1Error;
+VALUE
+ossl_asn1obj_to_string_oid(const ASN1_OBJECT *a1obj)
+{
+ VALUE str;
+ int len;
-VALUE cASN1Data;
-static VALUE cASN1Primitive;
-static VALUE cASN1Constructive;
+ str = rb_usascii_str_new(NULL, 127);
+ len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
+ if (len <= 0 || len == INT_MAX)
+ ossl_raise(eOSSLError, "OBJ_obj2txt");
+ if (len > RSTRING_LEN(str)) {
+ /* +1 is for the \0 terminator added by OBJ_obj2txt() */
+ rb_str_resize(str, len + 1);
+ len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
+ if (len <= 0)
+ ossl_raise(eOSSLError, "OBJ_obj2txt");
+ }
+ rb_str_set_len(str, len);
+ return str;
+}
-static VALUE cASN1EndOfContent;
-static VALUE cASN1Boolean; /* BOOLEAN */
-static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
-static VALUE cASN1BitString; /* BIT STRING */
-static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
-static VALUE cASN1NumericString, cASN1PrintableString;
-static VALUE cASN1T61String, cASN1VideotexString;
-static VALUE cASN1IA5String, cASN1GraphicString;
-static VALUE cASN1ISO64String, cASN1GeneralString;
-static VALUE cASN1UniversalString, cASN1BMPString;
-static VALUE cASN1Null; /* NULL */
-static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
-static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
-static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
+VALUE
+ossl_asn1obj_to_string(const ASN1_OBJECT *obj)
+{
+ int nid = OBJ_obj2nid(obj);
+ if (nid != NID_undef)
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
+ return ossl_asn1obj_to_string_oid(obj);
+}
-static VALUE sym_IMPLICIT, sym_EXPLICIT;
-static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
-static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
+VALUE
+ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)
+{
+ int nid = OBJ_obj2nid(obj);
+ if (nid != NID_undef)
+ return rb_str_new_cstr(OBJ_nid2ln(nid));
+ return ossl_asn1obj_to_string_oid(obj);
+}
/*
* Ruby to ASN1 converters
@@ -192,9 +216,9 @@ static ASN1_BOOLEAN
obj_to_asn1bool(VALUE obj)
{
if (NIL_P(obj))
- ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
+ ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
- return RTEST(obj) ? 0xff : 0x0;
+ return RTEST(obj) ? 0xff : 0x0;
}
static ASN1_INTEGER*
@@ -204,19 +228,19 @@ obj_to_asn1int(VALUE obj)
}
static ASN1_BIT_STRING*
-obj_to_asn1bstr(VALUE obj, long unused_bits)
+obj_to_asn1bstr(VALUE obj, int unused_bits)
{
ASN1_BIT_STRING *bstr;
if (unused_bits < 0 || unused_bits > 7)
- ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\
- "the range 0 to 7");
+ ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\
+ "the range 0 to 7");
StringValue(obj);
- if(!(bstr = ASN1_BIT_STRING_new()))
- ossl_raise(eASN1Error, NULL);
- ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LENINT(obj));
- bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
- bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits;
+ if (!(bstr = ASN1_BIT_STRING_new()))
+ ossl_raise(eASN1Error, "ASN1_BIT_STRING_new");
+ if (!ASN1_BIT_STRING_set1(bstr, (uint8_t *)RSTRING_PTR(obj),
+ RSTRING_LEN(obj), unused_bits))
+ ossl_raise(eASN1Error, "ASN1_BIT_STRING_set1");
return bstr;
}
@@ -228,8 +252,11 @@ obj_to_asn1str(VALUE obj)
StringValue(obj);
if(!(str = ASN1_STRING_new()))
- ossl_raise(eASN1Error, NULL);
- ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj));
+ ossl_raise(eASN1Error, NULL);
+ if(!ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj))) {
+ ASN1_STRING_free(str);
+ ossl_raise(eASN1Error, NULL);
+ }
return str;
}
@@ -240,15 +267,15 @@ obj_to_asn1null(VALUE obj)
ASN1_NULL *null;
if(!NIL_P(obj))
- ossl_raise(eASN1Error, "nil expected");
+ ossl_raise(eASN1Error, "nil expected");
if(!(null = ASN1_NULL_new()))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return null;
}
-static ASN1_OBJECT*
-obj_to_asn1obj(VALUE obj)
+ASN1_OBJECT *
+ossl_to_asn1obj(VALUE obj)
{
ASN1_OBJECT *a1obj;
@@ -270,7 +297,7 @@ obj_to_asn1utime(VALUE time)
ossl_time_split(time, &sec, &off_days);
if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return t;
}
@@ -285,7 +312,7 @@ obj_to_asn1gtime(VALUE time)
ossl_time_split(time, &sec, &off_days);
if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return t;
}
@@ -298,8 +325,11 @@ obj_to_asn1derstr(VALUE obj)
str = ossl_to_der(obj);
if(!(a1str = ASN1_STRING_new()))
- ossl_raise(eASN1Error, NULL);
- ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str));
+ ossl_raise(eASN1Error, NULL);
+ if(!ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str))) {
+ ASN1_STRING_free(a1str);
+ ossl_raise(eASN1Error, NULL);
+ }
return a1str;
}
@@ -313,9 +343,9 @@ decode_bool(unsigned char* der, long length)
const unsigned char *p = der;
if (length != 3)
- ossl_raise(eASN1Error, "invalid length for BOOLEAN");
+ ossl_raise(eASN1Error, "invalid length for BOOLEAN");
if (p[0] != 1 || p[1] != 1)
- ossl_raise(eASN1Error, "invalid BOOLEAN");
+ ossl_raise(eASN1Error, "invalid BOOLEAN");
return p[2] ? Qtrue : Qfalse;
}
@@ -330,9 +360,9 @@ decode_int(unsigned char* der, long length)
p = der;
if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1integer_to_num_i,
- (VALUE)ai, &status);
+ (VALUE)ai, &status);
ASN1_INTEGER_free(ai);
if(status) rb_jump_tag(status);
@@ -340,22 +370,25 @@ decode_int(unsigned char* der, long length)
}
static VALUE
-decode_bstr(unsigned char* der, long length, long *unused_bits)
+decode_bstr(unsigned char* der, long length, int *unused_bits)
{
ASN1_BIT_STRING *bstr;
const unsigned char *p;
- long len;
+ size_t len;
VALUE ret;
+ int state;
p = der;
- if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
- len = bstr->length;
- *unused_bits = 0;
- if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
- *unused_bits = bstr->flags & 0x07;
- ret = rb_str_new((const char *)bstr->data, len);
+ if (!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
+ ossl_raise(eASN1Error, "d2i_ASN1_BIT_STRING");
+ if (!ASN1_BIT_STRING_get_length(bstr, &len, unused_bits)) {
+ ASN1_BIT_STRING_free(bstr);
+ ossl_raise(eASN1Error, "ASN1_BIT_STRING_get_length");
+ }
+ ret = ossl_str_new((const char *)ASN1_STRING_get0_data(bstr), len, &state);
ASN1_BIT_STRING_free(bstr);
+ if (state)
+ rb_jump_tag(state);
return ret;
}
@@ -370,9 +403,9 @@ decode_enum(unsigned char* der, long length)
p = der;
if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1integer_to_num_i,
- (VALUE)ai, &status);
+ (VALUE)ai, &status);
ASN1_ENUMERATED_free(ai);
if(status) rb_jump_tag(status);
@@ -387,38 +420,33 @@ decode_null(unsigned char* der, long length)
p = der;
if(!(null = d2i_ASN1_NULL(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ASN1_NULL_free(null);
return Qnil;
}
+VALUE
+asn1obj_to_string_i(VALUE arg)
+{
+ return ossl_asn1obj_to_string((const ASN1_OBJECT *)arg);
+}
+
static VALUE
decode_obj(unsigned char* der, long length)
{
ASN1_OBJECT *obj;
const unsigned char *p;
VALUE ret;
- int nid;
- BIO *bio;
+ int state;
p = der;
- if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
- if((nid = OBJ_obj2nid(obj)) != NID_undef){
- ASN1_OBJECT_free(obj);
- ret = rb_str_new2(OBJ_nid2sn(nid));
- }
- else{
- if(!(bio = BIO_new(BIO_s_mem()))){
- ASN1_OBJECT_free(obj);
- ossl_raise(eASN1Error, NULL);
- }
- i2a_ASN1_OBJECT(bio, obj);
- ASN1_OBJECT_free(obj);
- ret = ossl_membio2str(bio);
- }
-
+ if (!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
+ ossl_raise(eASN1Error, "d2i_ASN1_OBJECT");
+ ret = rb_protect(asn1obj_to_string_i, (VALUE)obj, &state);
+ ASN1_OBJECT_free(obj);
+ if (state)
+ rb_jump_tag(state);
return ret;
}
@@ -432,9 +460,9 @@ decode_time(unsigned char* der, long length)
p = der;
if(!(time = d2i_ASN1_TIME(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1time_to_time_i,
- (VALUE)time, &status);
+ (VALUE)time, &status);
ASN1_TIME_free(time);
if(status) rb_jump_tag(status);
@@ -445,7 +473,7 @@ static VALUE
decode_eoc(unsigned char *der, long length)
{
if (length != 2 || !(der[0] == 0x00 && der[1] == 0x00))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return rb_str_new("", 0);
}
@@ -510,62 +538,62 @@ ossl_asn1_get_asn1type(VALUE obj)
tag = ossl_asn1_default_tag(obj);
value = ossl_asn1_get_value(obj);
switch(tag){
- case V_ASN1_BOOLEAN:
- ptr = (void*)(VALUE)obj_to_asn1bool(value);
- free_func = NULL;
- break;
- case V_ASN1_INTEGER: /* FALLTHROUGH */
- case V_ASN1_ENUMERATED:
- ptr = obj_to_asn1int(value);
- free_func = (free_func_type *)ASN1_INTEGER_free;
- break;
- case V_ASN1_BIT_STRING:
+ case V_ASN1_BOOLEAN:
+ ptr = (void*)(VALUE)obj_to_asn1bool(value);
+ free_func = NULL;
+ break;
+ case V_ASN1_INTEGER: /* FALLTHROUGH */
+ case V_ASN1_ENUMERATED:
+ ptr = obj_to_asn1int(value);
+ free_func = (free_func_type *)ASN1_INTEGER_free;
+ break;
+ case V_ASN1_BIT_STRING:
rflag = rb_attr_get(obj, sivUNUSED_BITS);
- ptr = obj_to_asn1bstr(value, NUM2INT(rflag));
- free_func = (free_func_type *)ASN1_BIT_STRING_free;
- break;
- case V_ASN1_NULL:
- ptr = obj_to_asn1null(value);
- free_func = (free_func_type *)ASN1_NULL_free;
- break;
- case V_ASN1_OCTET_STRING: /* FALLTHROUGH */
- case V_ASN1_UTF8STRING: /* FALLTHROUGH */
- case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */
- case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
- case V_ASN1_T61STRING: /* FALLTHROUGH */
- case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */
- case V_ASN1_IA5STRING: /* FALLTHROUGH */
- case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */
- case V_ASN1_ISO64STRING: /* FALLTHROUGH */
- case V_ASN1_GENERALSTRING: /* FALLTHROUGH */
- case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
- case V_ASN1_BMPSTRING:
- ptr = obj_to_asn1str(value);
- free_func = (free_func_type *)ASN1_STRING_free;
- break;
- case V_ASN1_OBJECT:
- ptr = obj_to_asn1obj(value);
- free_func = (free_func_type *)ASN1_OBJECT_free;
- break;
- case V_ASN1_UTCTIME:
- ptr = obj_to_asn1utime(value);
- free_func = (free_func_type *)ASN1_TIME_free;
- break;
- case V_ASN1_GENERALIZEDTIME:
- ptr = obj_to_asn1gtime(value);
- free_func = (free_func_type *)ASN1_TIME_free;
- break;
- case V_ASN1_SET: /* FALLTHROUGH */
- case V_ASN1_SEQUENCE:
- ptr = obj_to_asn1derstr(obj);
- free_func = (free_func_type *)ASN1_STRING_free;
- break;
- default:
- ossl_raise(eASN1Error, "unsupported ASN.1 type");
+ ptr = obj_to_asn1bstr(value, NUM2INT(rflag));
+ free_func = (free_func_type *)ASN1_BIT_STRING_free;
+ break;
+ case V_ASN1_NULL:
+ ptr = obj_to_asn1null(value);
+ free_func = (free_func_type *)ASN1_NULL_free;
+ break;
+ case V_ASN1_OCTET_STRING: /* FALLTHROUGH */
+ case V_ASN1_UTF8STRING: /* FALLTHROUGH */
+ case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */
+ case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
+ case V_ASN1_T61STRING: /* FALLTHROUGH */
+ case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */
+ case V_ASN1_IA5STRING: /* FALLTHROUGH */
+ case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */
+ case V_ASN1_ISO64STRING: /* FALLTHROUGH */
+ case V_ASN1_GENERALSTRING: /* FALLTHROUGH */
+ case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
+ case V_ASN1_BMPSTRING:
+ ptr = obj_to_asn1str(value);
+ free_func = (free_func_type *)ASN1_STRING_free;
+ break;
+ case V_ASN1_OBJECT:
+ ptr = ossl_to_asn1obj(value);
+ free_func = (free_func_type *)ASN1_OBJECT_free;
+ break;
+ case V_ASN1_UTCTIME:
+ ptr = obj_to_asn1utime(value);
+ free_func = (free_func_type *)ASN1_TIME_free;
+ break;
+ case V_ASN1_GENERALIZEDTIME:
+ ptr = obj_to_asn1gtime(value);
+ free_func = (free_func_type *)ASN1_TIME_free;
+ break;
+ case V_ASN1_SET: /* FALLTHROUGH */
+ case V_ASN1_SEQUENCE:
+ ptr = obj_to_asn1derstr(obj);
+ free_func = (free_func_type *)ASN1_STRING_free;
+ break;
+ default:
+ ossl_raise(eASN1Error, "unsupported ASN.1 type");
}
if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){
- if(free_func) free_func(ptr);
- ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
+ if(free_func) free_func(ptr);
+ ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
}
memset(ret, 0, sizeof(ASN1_TYPE));
ASN1_TYPE_set(ret, tag, ptr);
@@ -580,10 +608,10 @@ ossl_asn1_default_tag(VALUE obj)
tmp_class = CLASS_OF(obj);
while (!NIL_P(tmp_class)) {
- tag = rb_hash_lookup(class_tag_map, tmp_class);
- if (tag != Qnil)
- return NUM2INT(tag);
- tmp_class = rb_class_superclass(tmp_class);
+ tag = rb_hash_lookup(class_tag_map, tmp_class);
+ if (tag != Qnil)
+ return NUM2INT(tag);
+ tmp_class = rb_class_superclass(tmp_class);
}
return -1;
@@ -596,7 +624,7 @@ ossl_asn1_tag(VALUE obj)
tag = ossl_asn1_get_tag(obj);
if(NIL_P(tag))
- ossl_raise(eASN1Error, "tag number not specified");
+ ossl_raise(eASN1Error, "tag number not specified");
return NUM2INT(tag);
}
@@ -608,28 +636,57 @@ ossl_asn1_tag_class(VALUE obj)
s = ossl_asn1_get_tag_class(obj);
if (NIL_P(s) || s == sym_UNIVERSAL)
- return V_ASN1_UNIVERSAL;
+ return V_ASN1_UNIVERSAL;
else if (s == sym_APPLICATION)
- return V_ASN1_APPLICATION;
+ return V_ASN1_APPLICATION;
else if (s == sym_CONTEXT_SPECIFIC)
- return V_ASN1_CONTEXT_SPECIFIC;
+ return V_ASN1_CONTEXT_SPECIFIC;
else if (s == sym_PRIVATE)
- return V_ASN1_PRIVATE;
+ return V_ASN1_PRIVATE;
else
- ossl_raise(eASN1Error, "invalid tag class");
+ ossl_raise(eASN1Error, "invalid tag class");
}
static VALUE
ossl_asn1_class2sym(int tc)
{
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- return sym_PRIVATE;
+ return sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- return sym_CONTEXT_SPECIFIC;
+ return sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- return sym_APPLICATION;
+ return sym_APPLICATION;
else
- return sym_UNIVERSAL;
+ return sym_UNIVERSAL;
+}
+
+/*
+ * call-seq:
+ * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
+ *
+ * _value_: Please have a look at Constructive and Primitive to see how Ruby
+ * types are mapped to ASN.1 types and vice versa.
+ *
+ * _tag_: An Integer indicating the tag number.
+ *
+ * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
+ * possible values.
+ *
+ * == Example
+ * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
+ * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
+ */
+static VALUE
+ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
+{
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+
+ return self;
}
static VALUE
@@ -645,35 +702,35 @@ to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
body_length = RSTRING_LENINT(body);
if (ossl_asn1_get_tagging(self) == sym_EXPLICIT) {
- int inner_length, e_encoding = indef_len ? 2 : 1;
-
- if (default_tag_number == -1)
- ossl_raise(eASN1Error, "explicit tagging of unknown tag");
-
- inner_length = ASN1_object_size(encoding, body_length, default_tag_number);
- total_length = ASN1_object_size(e_encoding, inner_length, tag_number);
- str = rb_str_new(NULL, total_length);
- p = (unsigned char *)RSTRING_PTR(str);
- /* Put explicit tag */
- ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);
- /* Append inner object */
- ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);
- memcpy(p, RSTRING_PTR(body), body_length);
- p += body_length;
- if (indef_len) {
- ASN1_put_eoc(&p); /* For inner object */
- ASN1_put_eoc(&p); /* For wrapper object */
- }
+ int inner_length, e_encoding = indef_len ? 2 : 1;
+
+ if (default_tag_number == -1)
+ ossl_raise(eASN1Error, "explicit tagging of unknown tag");
+
+ inner_length = ASN1_object_size(encoding, body_length, default_tag_number);
+ total_length = ASN1_object_size(e_encoding, inner_length, tag_number);
+ str = rb_str_new(NULL, total_length);
+ p = (unsigned char *)RSTRING_PTR(str);
+ /* Put explicit tag */
+ ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);
+ /* Append inner object */
+ ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);
+ memcpy(p, RSTRING_PTR(body), body_length);
+ p += body_length;
+ if (indef_len) {
+ ASN1_put_eoc(&p); /* For inner object */
+ ASN1_put_eoc(&p); /* For wrapper object */
+ }
}
else {
- total_length = ASN1_object_size(encoding, body_length, tag_number);
- str = rb_str_new(NULL, total_length);
- p = (unsigned char *)RSTRING_PTR(str);
- ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);
- memcpy(p, RSTRING_PTR(body), body_length);
- p += body_length;
- if (indef_len)
- ASN1_put_eoc(&p);
+ total_length = ASN1_object_size(encoding, body_length, tag_number);
+ str = rb_str_new(NULL, total_length);
+ p = (unsigned char *)RSTRING_PTR(str);
+ ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);
+ memcpy(p, RSTRING_PTR(body), body_length);
+ p += body_length;
+ if (indef_len)
+ ASN1_put_eoc(&p);
}
assert(p - (unsigned char *)RSTRING_PTR(str) == total_length);
return str;
@@ -696,83 +753,88 @@ ossl_asn1data_to_der(VALUE self)
VALUE value = ossl_asn1_get_value(self);
if (rb_obj_is_kind_of(value, rb_cArray))
- return ossl_asn1cons_to_der(self);
+ return ossl_asn1cons_to_der(self);
else {
- if (RTEST(ossl_asn1_get_indefinite_length(self)))
- ossl_raise(eASN1Error, "indefinite length form cannot be used " \
- "with primitive encoding");
- return ossl_asn1prim_to_der(self);
+ if (RTEST(ossl_asn1_get_indefinite_length(self)))
+ ossl_raise(eASN1Error, "indefinite length form cannot be used " \
+ "with primitive encoding");
+ return ossl_asn1prim_to_der(self);
}
}
+static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);
+static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
+ int depth, int yield, long *num_read);
+
static VALUE
int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
- VALUE tc, long *num_read)
+ VALUE tc, long *num_read)
{
VALUE value, asn1data;
unsigned char *p;
- long flag = 0;
+ int flag = 0;
p = *pp;
if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) {
- switch(tag){
- case V_ASN1_EOC:
- value = decode_eoc(p, hlen+length);
- break;
- case V_ASN1_BOOLEAN:
- value = decode_bool(p, hlen+length);
- break;
- case V_ASN1_INTEGER:
- value = decode_int(p, hlen+length);
- break;
- case V_ASN1_BIT_STRING:
- value = decode_bstr(p, hlen+length, &flag);
- break;
- case V_ASN1_NULL:
- value = decode_null(p, hlen+length);
- break;
- case V_ASN1_ENUMERATED:
- value = decode_enum(p, hlen+length);
- break;
- case V_ASN1_OBJECT:
- value = decode_obj(p, hlen+length);
- break;
- case V_ASN1_UTCTIME: /* FALLTHROUGH */
- case V_ASN1_GENERALIZEDTIME:
- value = decode_time(p, hlen+length);
- break;
- default:
- /* use original value */
- p += hlen;
- value = rb_str_new((const char *)p, length);
- break;
- }
+ switch(tag){
+ case V_ASN1_EOC:
+ value = decode_eoc(p, hlen+length);
+ break;
+ case V_ASN1_BOOLEAN:
+ value = decode_bool(p, hlen+length);
+ break;
+ case V_ASN1_INTEGER:
+ value = decode_int(p, hlen+length);
+ break;
+ case V_ASN1_BIT_STRING:
+ value = decode_bstr(p, hlen+length, &flag);
+ break;
+ case V_ASN1_NULL:
+ value = decode_null(p, hlen+length);
+ break;
+ case V_ASN1_ENUMERATED:
+ value = decode_enum(p, hlen+length);
+ break;
+ case V_ASN1_OBJECT:
+ value = decode_obj(p, hlen+length);
+ break;
+ case V_ASN1_UTCTIME: /* FALLTHROUGH */
+ case V_ASN1_GENERALIZEDTIME:
+ value = decode_time(p, hlen+length);
+ break;
+ default:
+ /* use original value */
+ p += hlen;
+ value = rb_str_new((const char *)p, length);
+ break;
+ }
}
else {
- p += hlen;
- value = rb_str_new((const char *)p, length);
+ p += hlen;
+ value = rb_str_new((const char *)p, length);
}
*pp += hlen + length;
*num_read = hlen + length;
if (tc == sym_UNIVERSAL &&
- tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
- VALUE klass = *ossl_asn1_info[tag].klass;
- if (tag == V_ASN1_EOC)
- asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
- else {
- VALUE args[4] = { value, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(klass, rb_intern("new"), 4, args);
- }
- if(tag == V_ASN1_BIT_STRING){
- rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
- }
+ tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
+ VALUE klass = *ossl_asn1_info[tag].klass;
+ VALUE args[4];
+ args[0] = value;
+ args[1] = INT2NUM(tag);
+ args[2] = Qnil;
+ args[3] = tc;
+ asn1data = rb_obj_alloc(klass);
+ ossl_asn1_initialize(4, args, asn1data);
+ if(tag == V_ASN1_BIT_STRING){
+ rb_ivar_set(asn1data, sivUNUSED_BITS, INT2NUM(flag));
+ }
}
else {
- VALUE args[3] = { value, INT2NUM(tag), tc };
- asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
+ asn1data = rb_obj_alloc(cASN1Data);
+ ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
}
return asn1data;
@@ -780,8 +842,8 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
static VALUE
int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
- long *offset, int depth, int yield, int j,
- int tag, VALUE tc, long *num_read)
+ long *offset, int depth, int yield, int j,
+ int tag, VALUE tc, long *num_read)
{
VALUE value, asn1data, ary;
int indefinite;
@@ -792,48 +854,52 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
available_len = indefinite ? max_len : length;
while (available_len > 0) {
- long inner_read = 0;
- value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
- *num_read += inner_read;
- available_len -= inner_read;
-
- if (indefinite &&
- ossl_asn1_tag(value) == V_ASN1_EOC &&
- ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) {
- break;
- }
- rb_ary_push(ary, value);
+ long inner_read = 0;
+ value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
+ *num_read += inner_read;
+ available_len -= inner_read;
+
+ if (indefinite) {
+ if (ossl_asn1_tag(value) == V_ASN1_EOC &&
+ ossl_asn1_get_tag_class(value) == sym_UNIVERSAL)
+ break;
+ if (available_len == 0)
+ ossl_raise(eASN1Error, "EOC missing in indefinite length encoding");
+ }
+ rb_ary_push(ary, value);
}
if (tc == sym_UNIVERSAL) {
- if (tag == V_ASN1_SEQUENCE) {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Sequence, rb_intern("new"), 4, args);
- } else if (tag == V_ASN1_SET) {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Set, rb_intern("new"), 4, args);
- } else {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Constructive, rb_intern("new"), 4, args);
- }
+ VALUE args[4];
+ if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)
+ asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);
+ else
+ asn1data = rb_obj_alloc(cASN1Constructive);
+ args[0] = ary;
+ args[1] = INT2NUM(tag);
+ args[2] = Qnil;
+ args[3] = tc;
+ ossl_asn1_initialize(4, args, asn1data);
}
else {
- VALUE args[3] = {ary, INT2NUM(tag), tc};
- asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
+ asn1data = rb_obj_alloc(cASN1Data);
+ ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
}
if (indefinite)
- ossl_asn1_set_indefinite_length(asn1data, Qtrue);
+ ossl_asn1_set_indefinite_length(asn1data, Qtrue);
else
- ossl_asn1_set_indefinite_length(asn1data, Qfalse);
+ ossl_asn1_set_indefinite_length(asn1data, Qfalse);
*offset = off;
return asn1data;
}
+#define MAX_NESTING_DEPTH 200
+
static VALUE
ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
- int yield, long *num_read)
+ int yield, long *num_read)
{
unsigned char *start, *p;
const unsigned char *p0;
@@ -841,6 +907,10 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
int tag, tc, j;
VALUE asn1data, tag_class;
+ if (depth > MAX_NESTING_DEPTH) {
+ ossl_raise(eASN1Error, "nesting depth %d exceeds limit", depth);
+ }
+
p = *pp;
start = p;
p0 = p;
@@ -849,46 +919,46 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
if(j & 0x80) ossl_raise(eASN1Error, NULL);
if(len > length) ossl_raise(eASN1Error, "value is too short");
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- tag_class = sym_PRIVATE;
+ tag_class = sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- tag_class = sym_CONTEXT_SPECIFIC;
+ tag_class = sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- tag_class = sym_APPLICATION;
+ tag_class = sym_APPLICATION;
else
- tag_class = sym_UNIVERSAL;
+ tag_class = sym_UNIVERSAL;
hlen = p - start;
if(yield) {
- VALUE arg = rb_ary_new();
- rb_ary_push(arg, LONG2NUM(depth));
- rb_ary_push(arg, LONG2NUM(*offset));
- rb_ary_push(arg, LONG2NUM(hlen));
- rb_ary_push(arg, LONG2NUM(len));
- rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
- rb_ary_push(arg, ossl_asn1_class2sym(tc));
- rb_ary_push(arg, INT2NUM(tag));
- rb_yield(arg);
+ VALUE arg = rb_ary_new();
+ rb_ary_push(arg, LONG2NUM(depth));
+ rb_ary_push(arg, LONG2NUM(*offset));
+ rb_ary_push(arg, LONG2NUM(hlen));
+ rb_ary_push(arg, LONG2NUM(len));
+ rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
+ rb_ary_push(arg, ossl_asn1_class2sym(tc));
+ rb_ary_push(arg, INT2NUM(tag));
+ rb_yield(arg);
}
if(j & V_ASN1_CONSTRUCTED) {
- *pp += hlen;
- off += hlen;
- asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
- inner_read += hlen;
+ *pp += hlen;
+ off += hlen;
+ asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
+ inner_read += hlen;
}
else {
- if ((j & 0x01) && (len == 0))
- ossl_raise(eASN1Error, "indefinite length for primitive value");
- asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
- off += hlen + len;
+ if ((j & 0x01) && (len == 0))
+ ossl_raise(eASN1Error, "indefinite length for primitive value");
+ asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
+ off += hlen + len;
}
if (num_read)
- *num_read = inner_read;
+ *num_read = inner_read;
if (len != 0 && inner_read != hlen + len) {
- ossl_raise(eASN1Error,
- "Type mismatch. Bytes read: %ld Bytes available: %ld",
- inner_read, hlen + len);
+ ossl_raise(eASN1Error,
+ "Type mismatch. Bytes read: %ld Bytes available: %ld",
+ inner_read, hlen + len);
}
*offset = off;
@@ -899,9 +969,9 @@ static void
int_ossl_decode_sanity_check(long len, long read, long offset)
{
if (len != 0 && (read != len || offset != len)) {
- ossl_raise(eASN1Error,
- "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
- read, len, offset);
+ ossl_raise(eASN1Error,
+ "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
+ read, len, offset);
}
}
@@ -1001,17 +1071,94 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
tmp_len = len;
ary = rb_ary_new();
while (tmp_len > 0) {
- long tmp_read = 0;
- val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
- rb_ary_push(ary, val);
- read += tmp_read;
- tmp_len -= tmp_read;
+ long tmp_read = 0;
+ val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
+ rb_ary_push(ary, val);
+ read += tmp_read;
+ tmp_len -= tmp_read;
}
RB_GC_GUARD(tmp);
int_ossl_decode_sanity_check(len, read, offset);
return ary;
}
+/*
+ * call-seq:
+ * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
+ *
+ * _value_: is mandatory.
+ *
+ * _tag_: optional, may be specified for tagged values. If no _tag_ is
+ * specified, the UNIVERSAL tag corresponding to the Primitive sub-class
+ * is used by default.
+ *
+ * _tagging_: may be used as an encoding hint to encode a value either
+ * explicitly or implicitly, see ASN1 for possible values.
+ *
+ * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
+ * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
+ * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
+ * cf. ASN1.
+ *
+ * == Example
+ * int = OpenSSL::ASN1::Integer.new(42)
+ * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
+ * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
+ */
+static VALUE
+ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
+{
+ VALUE value, tag, tagging, tag_class;
+ int default_tag;
+
+ rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
+ default_tag = ossl_asn1_default_tag(self);
+
+ if (default_tag == -1 || argc > 1) {
+ if(NIL_P(tag))
+ ossl_raise(eASN1Error, "must specify tag number");
+ if(!NIL_P(tagging) && !SYMBOL_P(tagging))
+ ossl_raise(eASN1Error, "invalid tagging method");
+ if(NIL_P(tag_class)) {
+ if (NIL_P(tagging))
+ tag_class = sym_UNIVERSAL;
+ else
+ tag_class = sym_CONTEXT_SPECIFIC;
+ }
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+ }
+ else{
+ tag = INT2NUM(default_tag);
+ tagging = Qnil;
+ tag_class = sym_UNIVERSAL;
+ }
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tagging(self, tagging);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+ if (default_tag == V_ASN1_BIT_STRING)
+ rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));
+
+ return self;
+}
+
+static VALUE
+ossl_asn1eoc_initialize(VALUE self) {
+ VALUE tag, tagging, tag_class, value;
+ tag = INT2FIX(0);
+ tagging = Qnil;
+ tag_class = sym_UNIVERSAL;
+ value = rb_str_new("", 0);
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tagging(self, tagging);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+ return self;
+}
+
static VALUE
ossl_asn1eoc_to_der(VALUE self)
{
@@ -1034,20 +1181,20 @@ ossl_asn1prim_to_der(VALUE self)
VALUE str;
if (ossl_asn1_default_tag(self) == -1) {
- str = ossl_asn1_get_value(self);
- return to_der_internal(self, 0, 0, StringValue(str));
+ str = ossl_asn1_get_value(self);
+ return to_der_internal(self, 0, 0, StringValue(str));
}
asn1 = ossl_asn1_get_asn1type(self);
alllen = i2d_ASN1_TYPE(asn1, NULL);
if (alllen < 0) {
- ASN1_TYPE_free(asn1);
- ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
+ ASN1_TYPE_free(asn1);
+ ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
}
str = ossl_str_new(NULL, alllen, &state);
if (state) {
- ASN1_TYPE_free(asn1);
- rb_jump_tag(state);
+ ASN1_TYPE_free(asn1);
+ rb_jump_tag(state);
}
p0 = p1 = (unsigned char *)RSTRING_PTR(str);
if (i2d_ASN1_TYPE(asn1, &p0) < 0) {
@@ -1060,7 +1207,7 @@ ossl_asn1prim_to_der(VALUE self)
/* Strip header since to_der_internal() wants only the payload */
j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen);
if (j & 0x80)
- ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */
+ ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */
return to_der_internal(self, 0, 0, rb_str_drop_bytes(str, alllen - bodylen));
}
@@ -1082,22 +1229,22 @@ ossl_asn1cons_to_der(VALUE self)
ary = rb_convert_type(ossl_asn1_get_value(self), T_ARRAY, "Array", "to_a");
str = rb_str_new(NULL, 0);
for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE item = RARRAY_AREF(ary, i);
-
- if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {
- if (i != RARRAY_LEN(ary) - 1)
- ossl_raise(eASN1Error, "illegal EOC octets in value");
-
- /*
- * EOC is not really part of the content, but we required to add one
- * at the end in the past.
- */
- break;
- }
-
- item = ossl_to_der_if_possible(item);
- StringValue(item);
- rb_str_append(str, item);
+ VALUE item = RARRAY_AREF(ary, i);
+
+ if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {
+ if (i != RARRAY_LEN(ary) - 1)
+ ossl_raise(eASN1Error, "illegal EOC octets in value");
+
+ /*
+ * EOC is not really part of the content, but we required to add one
+ * at the end in the past.
+ */
+ break;
+ }
+
+ item = ossl_to_der_if_possible(item);
+ StringValue(item);
+ rb_str_append(str, item);
}
return to_der_internal(self, 1, indef_len, str);
@@ -1105,6 +1252,27 @@ ossl_asn1cons_to_der(VALUE self)
/*
* call-seq:
+ * asn1_ary.each { |asn1| block } => asn1_ary
+ *
+ * Calls the given block once for each element in self, passing that element
+ * as parameter _asn1_. If no block is given, an enumerator is returned
+ * instead.
+ *
+ * == Example
+ * asn1_ary.each do |asn1|
+ * puts asn1
+ * end
+ */
+static VALUE
+ossl_asn1cons_each(VALUE self)
+{
+ rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);
+
+ return self;
+}
+
+/*
+ * call-seq:
* OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
*
* This adds a new ObjectId to the internal tables. Where _object_id_ is the
@@ -1122,7 +1290,7 @@ ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)
StringValueCStr(ln);
if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return Qtrue;
}
@@ -1142,7 +1310,7 @@ ossl_asn1obj_get_sn(VALUE self)
val = ossl_asn1_get_value(self);
if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
+ ret = rb_str_new2(OBJ_nid2sn(nid));
return ret;
}
@@ -1162,7 +1330,7 @@ ossl_asn1obj_get_ln(VALUE self)
val = ossl_asn1_get_value(self);
if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)
- ret = rb_str_new2(OBJ_nid2ln(nid));
+ ret = rb_str_new2(OBJ_nid2ln(nid));
return ret;
}
@@ -1170,23 +1338,7 @@ ossl_asn1obj_get_ln(VALUE self)
static VALUE
asn1obj_get_oid_i(VALUE vobj)
{
- ASN1_OBJECT *a1obj = (void *)vobj;
- VALUE str;
- int len;
-
- str = rb_usascii_str_new(NULL, 127);
- len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
- if (len <= 0 || len == INT_MAX)
- ossl_raise(eASN1Error, "OBJ_obj2txt");
- if (len > RSTRING_LEN(str)) {
- /* +1 is for the \0 terminator added by OBJ_obj2txt() */
- rb_str_resize(str, len + 1);
- len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
- if (len <= 0)
- ossl_raise(eASN1Error, "OBJ_obj2txt");
- }
- rb_str_set_len(str, len);
- return str;
+ return ossl_asn1obj_to_string_oid((const ASN1_OBJECT *)vobj);
}
/*
@@ -1203,11 +1355,11 @@ ossl_asn1obj_get_oid(VALUE self)
ASN1_OBJECT *a1obj;
int state;
- a1obj = obj_to_asn1obj(ossl_asn1_get_value(self));
+ a1obj = ossl_to_asn1obj(ossl_asn1_get_value(self));
str = rb_protect(asn1obj_get_oid_i, (VALUE)a1obj, &state);
ASN1_OBJECT_free(a1obj);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return str;
}
@@ -1232,7 +1384,7 @@ ossl_asn1obj_eq(VALUE self, VALUE other)
#define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \
static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
-{ return rb_funcallv_public(cASN1##klass, rb_intern("new"), argc, argv); }
+{ return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); }
OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
OSSL_ASN1_IMPL_FACTORY_METHOD(Integer)
@@ -1262,13 +1414,6 @@ void
Init_ossl_asn1(void)
{
#undef rb_intern
- VALUE ary;
- int i;
-
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL"));
sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC"));
@@ -1418,17 +1563,20 @@ Init_ossl_asn1(void)
rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1);
rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1);
rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1);
- ary = rb_ary_new();
+ VALUE ary = rb_ary_new_capa(ossl_asn1_info_size);
+ for (int i = 0; i < ossl_asn1_info_size; i++) {
+ const char *name = ossl_asn1_info[i].name;
+ if (name[0] == '[')
+ continue;
+ rb_define_const(mASN1, name, INT2NUM(i));
+ rb_ary_store(ary, i, rb_obj_freeze(rb_str_new_cstr(name)));
+ }
+ rb_obj_freeze(ary);
/*
* Array storing tag names at the tag's index.
*/
rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary);
- for(i = 0; i < ossl_asn1_info_size; i++){
- if(ossl_asn1_info[i].name[0] == '[') continue;
- rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i));
- rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name));
- }
/* Document-class: OpenSSL::ASN1::ASN1Data
*
@@ -1518,6 +1666,42 @@ Init_ossl_asn1(void)
* puts int2.value # => 1
*/
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
+ /*
+ * Carries the value of a ASN.1 type.
+ * Please confer Constructive and Primitive for the mappings between
+ * ASN.1 data types and Ruby classes.
+ */
+ rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
+ /*
+ * An Integer representing the tag number of this ASN1Data. Never +nil+.
+ */
+ rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
+ /*
+ * A Symbol representing the tag class of this ASN1Data. Never +nil+.
+ * See ASN1Data for possible values.
+ */
+ rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
+ /*
+ * Never +nil+. A boolean value indicating whether the encoding uses
+ * indefinite length (in the case of parsing) or whether an indefinite
+ * length form shall be used (in the encoding case).
+ * In DER, every value uses definite length form. But in scenarios where
+ * large amounts of data need to be transferred it might be desirable to
+ * have some kind of streaming support available.
+ * For example, huge OCTET STRINGs are preferably sent in smaller-sized
+ * chunks, each at a time.
+ * This is possible in BER by setting the length bytes of an encoding
+ * to zero and by this indicating that the following value will be
+ * sent in chunks. Indefinite length encodings are always constructed.
+ * The end of such a stream of chunks is indicated by sending a EOC
+ * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
+ * encoding, but also primitive types such as e.g. OCTET STRINGS or
+ * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
+ */
+ rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0);
+ rb_define_alias(cASN1Data, "infinite_length", "indefinite_length");
+ rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length=");
+ rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
/* Document-class: OpenSSL::ASN1::Primitive
@@ -1585,6 +1769,16 @@ Init_ossl_asn1(void)
* prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
*/
cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
+ /*
+ * May be used as a hint for encoding a value either implicitly or
+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ * _tagging_ is not set when a ASN.1 structure is parsed using
+ * OpenSSL::ASN1.decode.
+ */
+ rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
+ rb_undef_method(cASN1Primitive, "indefinite_length=");
+ rb_undef_method(cASN1Primitive, "infinite_length=");
+ rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
/* Document-class: OpenSSL::ASN1::Constructive
@@ -1615,7 +1809,17 @@ Init_ossl_asn1(void)
* set = OpenSSL::ASN1::Set.new( [ int, str ] )
*/
cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
+ rb_include_module(cASN1Constructive, rb_mEnumerable);
+ /*
+ * May be used as a hint for encoding a value either implicitly or
+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ * _tagging_ is not set when a ASN.1 structure is parsed using
+ * OpenSSL::ASN1.decode.
+ */
+ rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
+ rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
+ rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
#define OSSL_ASN1_DEFINE_CLASS(name, super) \
do{\
@@ -1664,10 +1868,13 @@ do{\
rb_define_alias(cASN1ObjectId, "short_name", "sn");
rb_define_alias(cASN1ObjectId, "long_name", "ln");
rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1);
+ rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
+ rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0);
class_tag_map = rb_hash_new();
+ rb_gc_register_mark_object(class_tag_map);
rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));
rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));
rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));
@@ -1691,5 +1898,7 @@ do{\
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
- rb_define_const(mASN1, "CLASS_TAG_MAP", class_tag_map);
+ rb_obj_freeze(class_tag_map);
+
+ id_each = rb_intern_const("each");
}
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h
index 3b689c0ee7..b605df8f3f 100644
--- a/ext/openssl/ossl_asn1.h
+++ b/ext/openssl/ossl_asn1.h
@@ -32,10 +32,24 @@ VALUE asn1integer_to_num(const ASN1_INTEGER *);
ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);
/*
+ * ASN1_OBJECT conversions
+ */
+ASN1_OBJECT *ossl_to_asn1obj(VALUE obj);
+/*
+ * Returns the short name if available, the dotted decimal notation otherwise.
+ * This is the most common way to return ASN1_OBJECT to Ruby.
+ */
+VALUE ossl_asn1obj_to_string(const ASN1_OBJECT *a1obj);
+/*
+ * However, some places use long names instead. This is likely unintentional,
+ * but we keep the current behavior in existing methods.
+ */
+VALUE ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *a1obj);
+
+/*
* ASN1 module
*/
extern VALUE mASN1;
-extern VALUE eASN1Error;
extern VALUE cASN1Data;
diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c
index 2ef2080507..cc03c5d5f7 100644
--- a/ext/openssl/ossl_bio.c
+++ b/ext/openssl/ossl_bio.c
@@ -16,11 +16,11 @@ ossl_obj2bio(volatile VALUE *pobj)
BIO *bio;
if (RB_TYPE_P(obj, T_FILE))
- obj = rb_funcallv(obj, rb_intern("read"), 0, NULL);
+ obj = rb_funcallv(obj, rb_intern("read"), 0, NULL);
StringValue(obj);
bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj));
if (!bio)
- ossl_raise(eOSSLError, "BIO_new_mem_buf");
+ ossl_raise(eOSSLError, "BIO_new_mem_buf");
*pobj = obj;
return bio;
}
@@ -32,11 +32,15 @@ ossl_membio2str(BIO *bio)
int state;
BUF_MEM *buf;
- BIO_get_mem_ptr(bio, &buf);
+ if (BIO_get_mem_ptr(bio, &buf) <= 0) {
+ BIO_free(bio);
+ ossl_raise(eOSSLError, "BIO_get_mem_ptr");
+ }
+
ret = ossl_str_new(buf->data, buf->length, &state);
BIO_free(bio);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return ret;
}
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index 8699ce8ec5..9014f2df2b 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -11,19 +11,19 @@
#include "ossl.h"
#define NewBN(klass) \
- TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
+ TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
#define SetBN(obj, bn) do { \
- if (!(bn)) { \
- ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
- } \
- RTYPEDDATA_DATA(obj) = (bn); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+ RTYPEDDATA_DATA(obj) = (bn); \
} while (0)
#define GetBN(obj, bn) do { \
- TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
- if (!(bn)) { \
- ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
- } \
+ TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
} while (0)
static void
@@ -35,7 +35,7 @@ ossl_bn_free(void *ptr)
static const rb_data_type_t ossl_bn_type = {
"OpenSSL/BN",
{
- 0, ossl_bn_free,
+ 0, ossl_bn_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
};
@@ -61,10 +61,9 @@ ossl_bn_new(const BIGNUM *bn)
VALUE obj;
obj = NewBN(cBN);
- newbn = bn ? BN_dup(bn) : BN_new();
- if (!newbn) {
- ossl_raise(eBNError, NULL);
- }
+ newbn = BN_dup(bn);
+ if (!newbn)
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, newbn);
return obj;
@@ -76,40 +75,40 @@ integer_to_bnptr(VALUE obj, BIGNUM *orig)
BIGNUM *bn;
if (FIXNUM_P(obj)) {
- long i;
- unsigned char bin[sizeof(long)];
- long n = FIX2LONG(obj);
- unsigned long un = labs(n);
-
- for (i = sizeof(long) - 1; 0 <= i; i--) {
- bin[i] = un & 0xff;
- un >>= 8;
- }
-
- bn = BN_bin2bn(bin, sizeof(bin), orig);
- if (!bn)
- ossl_raise(eBNError, "BN_bin2bn");
- if (n < 0)
- BN_set_negative(bn, 1);
+ long i;
+ unsigned char bin[sizeof(long)];
+ long n = FIX2LONG(obj);
+ unsigned long un = labs(n);
+
+ for (i = sizeof(long) - 1; 0 <= i; i--) {
+ bin[i] = un & 0xff;
+ un >>= 8;
+ }
+
+ bn = BN_bin2bn(bin, sizeof(bin), orig);
+ if (!bn)
+ ossl_raise(eBNError, "BN_bin2bn");
+ if (n < 0)
+ BN_set_negative(bn, 1);
}
else { /* assuming Bignum */
- size_t len = rb_absint_size(obj, NULL);
- unsigned char *bin;
- VALUE buf;
- int sign;
-
- if (INT_MAX < len) {
- rb_raise(eBNError, "bignum too long");
- }
- bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
- sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
-
- bn = BN_bin2bn(bin, (int)len, orig);
- ALLOCV_END(buf);
- if (!bn)
- ossl_raise(eBNError, "BN_bin2bn");
- if (sign < 0)
- BN_set_negative(bn, 1);
+ size_t len = rb_absint_size(obj, NULL);
+ unsigned char *bin;
+ VALUE buf;
+ int sign;
+
+ if (INT_MAX < len) {
+ rb_raise(eBNError, "bignum too long");
+ }
+ bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
+ sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
+
+ bn = BN_bin2bn(bin, (int)len, orig);
+ ALLOCV_END(buf);
+ if (!bn)
+ ossl_raise(eBNError, "BN_bin2bn");
+ if (sign < 0)
+ BN_set_negative(bn, 1);
}
return bn;
@@ -122,11 +121,11 @@ try_convert_to_bn(VALUE obj)
VALUE newobj = Qnil;
if (rb_obj_is_kind_of(obj, cBN))
- return obj;
+ return obj;
if (RB_INTEGER_TYPE_P(obj)) {
- newobj = NewBN(cBN); /* Handle potential mem leaks */
- bn = integer_to_bnptr(obj, NULL);
- SetBN(newobj, bn);
+ newobj = NewBN(cBN); /* Handle potential mem leaks */
+ bn = integer_to_bnptr(obj, NULL);
+ SetBN(newobj, bn);
}
return newobj;
@@ -140,7 +139,7 @@ ossl_bn_value_ptr(volatile VALUE *ptr)
tmp = try_convert_to_bn(*ptr);
if (NIL_P(tmp))
- ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
+ ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
GetBN(tmp, bn);
*ptr = tmp;
@@ -210,7 +209,7 @@ ossl_bn_alloc(VALUE klass)
VALUE obj = NewBN(klass);
if (!(bn = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj, bn);
@@ -252,7 +251,7 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
char *ptr;
if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
- base = NUM2INT(bs);
+ base = NUM2INT(bs);
}
if (NIL_P(str)) {
@@ -261,49 +260,49 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (RB_INTEGER_TYPE_P(str)) {
- GetBN(self, bn);
- integer_to_bnptr(str, bn);
+ GetBN(self, bn);
+ integer_to_bnptr(str, bn);
- return self;
+ return self;
}
if (RTEST(rb_obj_is_kind_of(str, cBN))) {
- BIGNUM *other;
-
- GetBN(self, bn);
- GetBN(str, other); /* Safe - we checked kind_of? above */
- if (!BN_copy(bn, other)) {
- ossl_raise(eBNError, NULL);
- }
- return self;
+ BIGNUM *other;
+
+ GetBN(self, bn);
+ GetBN(str, other); /* Safe - we checked kind_of? above */
+ if (!BN_copy(bn, other)) {
+ ossl_raise(eBNError, NULL);
+ }
+ return self;
}
GetBN(self, bn);
switch (base) {
- case 0:
+ case 0:
ptr = StringValuePtr(str);
if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 2:
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 2:
ptr = StringValuePtr(str);
if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 10:
- if (!BN_dec2bn(&bn, StringValueCStr(str))) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 16:
- if (!BN_hex2bn(&bn, StringValueCStr(str))) {
- ossl_raise(eBNError, NULL);
- }
- break;
- default:
- ossl_raise(rb_eArgError, "invalid radix %d", base);
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 10:
+ if (!BN_dec2bn(&bn, StringValueCStr(str))) {
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 16:
+ if (!BN_hex2bn(&bn, StringValueCStr(str))) {
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ default:
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return self;
}
@@ -335,32 +334,32 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
char *buf;
if (rb_scan_args(argc, argv, "01", &bs) == 1) {
- base = NUM2INT(bs);
+ base = NUM2INT(bs);
}
GetBN(self, bn);
switch (base) {
- case 0:
- len = BN_bn2mpi(bn, NULL);
+ case 0:
+ len = BN_bn2mpi(bn, NULL);
str = rb_str_new(0, len);
- if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
- ossl_raise(eBNError, NULL);
- break;
- case 2:
- len = BN_num_bytes(bn);
+ if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+ ossl_raise(eBNError, NULL);
+ break;
+ case 2:
+ len = BN_num_bytes(bn);
str = rb_str_new(0, len);
- if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
- ossl_raise(eBNError, NULL);
- break;
- case 10:
- if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
- str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
- break;
- case 16:
- if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
- str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
- break;
- default:
- ossl_raise(rb_eArgError, "invalid radix %d", base);
+ if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+ ossl_raise(eBNError, NULL);
+ break;
+ case 10:
+ if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
+ str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+ break;
+ case 16:
+ if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
+ str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+ break;
+ default:
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return str;
@@ -380,7 +379,7 @@ ossl_bn_to_i(VALUE self)
GetBN(self, bn);
if (!(txt = BN_bn2hex(bn))) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
num = rb_cstr_to_inum(txt, 16, Qtrue);
OPENSSL_free(txt);
@@ -398,31 +397,31 @@ static VALUE
ossl_bn_coerce(VALUE self, VALUE other)
{
switch(TYPE(other)) {
- case T_STRING:
- self = ossl_bn_to_s(0, NULL, self);
- break;
- case T_FIXNUM:
- case T_BIGNUM:
- self = ossl_bn_to_i(self);
- break;
- default:
- if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
- ossl_raise(rb_eTypeError, "Don't know how to coerce");
- }
+ case T_STRING:
+ self = ossl_bn_to_s(0, NULL, self);
+ break;
+ case T_FIXNUM:
+ case T_BIGNUM:
+ self = ossl_bn_to_i(self);
+ break;
+ default:
+ if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
+ ossl_raise(rb_eTypeError, "Don't know how to coerce");
+ }
}
return rb_assoc_new(other, self);
}
-#define BIGNUM_BOOL1(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn; \
- GetBN(self, bn); \
- if (BN_##func(bn)) { \
- return Qtrue; \
- } \
- return Qfalse; \
+#define BIGNUM_BOOL1(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn; \
+ GetBN(self, bn); \
+ if (BN_##func(bn)) { \
+ return Qtrue; \
+ } \
+ return Qfalse; \
}
/*
@@ -457,27 +456,27 @@ ossl_bn_is_negative(VALUE self)
GetBN(self, bn);
if (BN_is_zero(bn))
- return Qfalse;
+ return Qfalse;
return BN_is_negative(bn) ? Qtrue : Qfalse;
}
-#define BIGNUM_1c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn, *result; \
- VALUE obj; \
- GetBN(self, bn); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_1c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn, *result; \
+ VALUE obj; \
+ GetBN(self, bn); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -487,23 +486,23 @@ ossl_bn_is_negative(VALUE self)
*/
BIGNUM_1c(sqr)
-#define BIGNUM_2(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -520,23 +519,23 @@ BIGNUM_2(add)
*/
BIGNUM_2(sub)
-#define BIGNUM_2c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -574,18 +573,18 @@ BIGNUM_2c(gcd)
*/
BIGNUM_2c(mod_sqr)
-#define BIGNUM_2cr(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \
- ossl_raise(eBNError, NULL); \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2cr(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \
+ ossl_raise(eBNError, NULL); \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -620,16 +619,16 @@ ossl_bn_div(VALUE self, VALUE other)
obj1 = NewBN(klass);
obj2 = NewBN(klass);
if (!(r1 = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
if (!(r2 = BN_new())) {
- BN_free(r1);
- ossl_raise(eBNError, NULL);
+ BN_free(r1);
+ ossl_raise(eBNError, NULL);
}
if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
- BN_free(r1);
- BN_free(r2);
- ossl_raise(eBNError, NULL);
+ BN_free(r1);
+ BN_free(r2);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj1, r1);
SetBN(obj2, r2);
@@ -637,24 +636,24 @@ ossl_bn_div(VALUE self, VALUE other)
return rb_ary_new3(2, obj1, obj2);
}
-#define BIGNUM_3c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
- BIGNUM *bn3 = GetBNPtr(other2), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_3c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
+ BIGNUM *bn3 = GetBNPtr(other2), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -685,17 +684,17 @@ BIGNUM_3c(mod_mul)
*/
BIGNUM_3c(mod_exp)
-#define BIGNUM_BIT(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE bit) \
- { \
- BIGNUM *bn; \
- rb_check_frozen(self); \
- GetBN(self, bn); \
- if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
- ossl_raise(eBNError, NULL); \
- } \
- return self; \
+#define BIGNUM_BIT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bit) \
+ { \
+ BIGNUM *bn; \
+ rb_check_frozen(self); \
+ GetBN(self, bn); \
+ if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ return self; \
}
/*
@@ -734,30 +733,30 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit)
b = NUM2INT(bit);
GetBN(self, bn);
if (BN_is_bit_set(bn, b)) {
- return Qtrue;
+ return Qtrue;
}
return Qfalse;
}
-#define BIGNUM_SHIFT(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE bits) \
- { \
- BIGNUM *bn, *result; \
- int b; \
- VALUE obj; \
- b = NUM2INT(bits); \
- GetBN(self, bn); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn, b) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_SHIFT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn, *result; \
+ int b; \
+ VALUE obj; \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn, b) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -774,18 +773,18 @@ BIGNUM_SHIFT(lshift)
*/
BIGNUM_SHIFT(rshift)
-#define BIGNUM_SELF_SHIFT(func) \
- static VALUE \
- ossl_bn_self_##func(VALUE self, VALUE bits) \
- { \
- BIGNUM *bn; \
- int b; \
- rb_check_frozen(self); \
- b = NUM2INT(bits); \
- GetBN(self, bn); \
- if (BN_##func(bn, bn, b) <= 0) \
- ossl_raise(eBNError, NULL); \
- return self; \
+#define BIGNUM_SELF_SHIFT(func) \
+ static VALUE \
+ ossl_bn_self_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn; \
+ int b; \
+ rb_check_frozen(self); \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ if (BN_##func(bn, bn, b) <= 0) \
+ ossl_raise(eBNError, NULL); \
+ return self; \
}
/*
@@ -887,32 +886,32 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
num = NUM2INT(vnum);
if (vsafe == Qfalse) {
- safe = 0;
+ safe = 0;
}
if (!NIL_P(vadd)) {
- add = GetBNPtr(vadd);
- rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
+ add = GetBNPtr(vadd);
+ rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
}
obj = NewBN(klass);
if (!(result = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) {
- BN_free(result);
- ossl_raise(eBNError, NULL);
+ BN_free(result);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj, result);
return obj;
}
-#define BIGNUM_NUM(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn; \
- GetBN(self, bn); \
- return INT2NUM(BN_##func(bn)); \
+#define BIGNUM_NUM(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn; \
+ GetBN(self, bn); \
+ return INT2NUM(BN_##func(bn)); \
}
/*
@@ -943,7 +942,7 @@ ossl_bn_copy(VALUE self, VALUE other)
bn2 = GetBNPtr(other);
if (!BN_copy(bn1, bn2)) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
return self;
}
@@ -962,7 +961,7 @@ ossl_bn_uplus(VALUE self)
obj = NewBN(cBN);
bn2 = BN_dup(bn1);
if (!bn2)
- ossl_raise(eBNError, "BN_dup");
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, bn2);
return obj;
@@ -982,7 +981,7 @@ ossl_bn_uminus(VALUE self)
obj = NewBN(cBN);
bn2 = BN_dup(bn1);
if (!bn2)
- ossl_raise(eBNError, "BN_dup");
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, bn2);
BN_set_negative(bn2, !BN_is_negative(bn2));
@@ -1007,13 +1006,13 @@ ossl_bn_abs(VALUE self)
}
}
-#define BIGNUM_CMP(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other); \
- GetBN(self, bn1); \
- return INT2NUM(BN_##func(bn1, bn2)); \
+#define BIGNUM_CMP(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other); \
+ GetBN(self, bn1); \
+ return INT2NUM(BN_##func(bn1, bn2)); \
}
/*
@@ -1050,11 +1049,11 @@ ossl_bn_eq(VALUE self, VALUE other)
GetBN(self, bn1);
other = try_convert_to_bn(other);
if (NIL_P(other))
- return Qfalse;
+ return Qfalse;
GetBN(other, bn2);
if (!BN_cmp(bn1, bn2)) {
- return Qtrue;
+ return Qtrue;
}
return Qfalse;
}
@@ -1073,7 +1072,7 @@ ossl_bn_eql(VALUE self, VALUE other)
BIGNUM *bn1, *bn2;
if (!rb_obj_is_kind_of(other, cBN))
- return Qfalse;
+ return Qfalse;
GetBN(self, bn1);
GetBN(other, bn2);
@@ -1100,8 +1099,8 @@ ossl_bn_hash(VALUE self)
len = BN_num_bytes(bn);
buf = ALLOCV(tmp, len);
if (BN_bn2bin(bn, buf) != len) {
- ALLOCV_END(tmp);
- ossl_raise(eBNError, "BN_bn2bin");
+ ALLOCV_END(tmp);
+ ossl_raise(eBNError, "BN_bn2bin");
}
hash = ST2FIX(rb_memhash(buf, len));
@@ -1203,11 +1202,6 @@ ossl_bn_set_flags(VALUE self, VALUE arg)
void
Init_ossl_bn(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
#ifdef HAVE_RB_EXT_RACTOR_SAFE
ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type);
#else
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index d737fa74ff..e9dcd943e3 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -14,7 +14,7 @@
#define AllocCipher(obj, ctx) do { \
(ctx) = EVP_CIPHER_CTX_new(); \
if (!(ctx)) \
- ossl_raise(rb_eRuntimeError, NULL); \
+ ossl_raise(rb_eRuntimeError, NULL); \
RTYPEDDATA_DATA(obj) = (ctx); \
} while (0)
#define GetCipherInit(obj, ctx) do { \
@@ -23,7 +23,7 @@
#define GetCipher(obj, ctx) do { \
GetCipherInit((obj), (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
} \
} while (0)
@@ -32,7 +32,8 @@
*/
static VALUE cCipher;
static VALUE eCipherError;
-static ID id_auth_tag_len, id_key_set;
+static VALUE eAuthTagError;
+static ID id_auth_tag_len, id_key_set, id_cipher_holder;
static VALUE ossl_cipher_alloc(VALUE klass);
static void ossl_cipher_free(void *ptr);
@@ -40,35 +41,63 @@ static void ossl_cipher_free(void *ptr);
static const rb_data_type_t ossl_cipher_type = {
"OpenSSL/Cipher",
{
- 0, ossl_cipher_free,
+ 0, ossl_cipher_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
+#ifdef OSSL_USE_PROVIDER
+static void
+ossl_evp_cipher_free(void *ptr)
+{
+ // This is safe to call against const EVP_CIPHER * returned by
+ // EVP_get_cipherbyname()
+ EVP_CIPHER_free(ptr);
+}
+
+static const rb_data_type_t ossl_evp_cipher_holder_type = {
+ "OpenSSL/EVP_CIPHER",
+ {
+ .dfree = ossl_evp_cipher_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+#endif
+
/*
* PUBLIC
*/
const EVP_CIPHER *
-ossl_evp_get_cipherbyname(VALUE obj)
+ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder)
{
+ *holder = Qnil;
if (rb_obj_is_kind_of(obj, cCipher)) {
- EVP_CIPHER_CTX *ctx;
-
- GetCipher(obj, ctx);
-
- return EVP_CIPHER_CTX_cipher(ctx);
+ EVP_CIPHER_CTX *ctx;
+ GetCipher(obj, ctx);
+ EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_CIPHER_CTX_cipher(ctx);
+#ifdef OSSL_USE_PROVIDER
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
+ if (!EVP_CIPHER_up_ref(cipher))
+ ossl_raise(eCipherError, "EVP_CIPHER_up_ref");
+ RTYPEDDATA_DATA(*holder) = cipher;
+#endif
+ return cipher;
}
- else {
- const EVP_CIPHER *cipher;
- StringValueCStr(obj);
- cipher = EVP_get_cipherbyname(RSTRING_PTR(obj));
- if (!cipher)
- ossl_raise(rb_eArgError,
- "unsupported cipher algorithm: %"PRIsVALUE, obj);
-
- return cipher;
+ const char *name = StringValueCStr(obj);
+ EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name);
+#ifdef OSSL_USE_PROVIDER
+ if (!cipher) {
+ ossl_clear_error();
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
+ cipher = EVP_CIPHER_fetch(NULL, name, NULL);
+ RTYPEDDATA_DATA(*holder) = cipher;
}
+#endif
+ if (!cipher)
+ ossl_raise(eCipherError, "unsupported cipher algorithm: %"PRIsVALUE,
+ obj);
+ return cipher;
}
VALUE
@@ -77,10 +106,13 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
VALUE ret;
EVP_CIPHER_CTX *ctx;
+ // NOTE: This does not set id_cipher_holder because this function should
+ // only be called from ossl_engine.c, which will not use any
+ // reference-counted ciphers.
ret = ossl_cipher_alloc(cCipher);
AllocCipher(ret, ctx);
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return ret;
}
@@ -113,19 +145,17 @@ ossl_cipher_initialize(VALUE self, VALUE str)
{
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
- char *name;
+ VALUE cipher_holder;
- name = StringValueCStr(str);
GetCipherInit(self, ctx);
if (ctx) {
- ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
+ ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
}
+ cipher = ossl_evp_cipher_fetch(str, &cipher_holder);
AllocCipher(self, ctx);
- if (!(cipher = EVP_get_cipherbyname(name))) {
- ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
- }
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, "EVP_CipherInit_ex");
+ rb_ivar_set(self, id_cipher_holder, cipher_holder);
return self;
}
@@ -141,11 +171,11 @@ ossl_cipher_copy(VALUE self, VALUE other)
GetCipherInit(self, ctx1);
if (!ctx1) {
- AllocCipher(self, ctx1);
+ AllocCipher(self, ctx1);
}
GetCipher(other, ctx2);
if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return self;
}
@@ -170,8 +200,8 @@ ossl_s_ciphers(VALUE self)
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
- add_cipher_name_to_ary,
- (void*)ary);
+ add_cipher_name_to_ary,
+ (void*)ary);
return ary;
}
@@ -192,53 +222,22 @@ ossl_cipher_reset(VALUE self)
GetCipher(self, ctx);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return self;
}
static VALUE
-ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
+ossl_cipher_init(VALUE self, int enc)
{
EVP_CIPHER_CTX *ctx;
- unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL;
- unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL;
- VALUE pass, init_v;
-
- if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){
- /*
- * oops. this code mistakes salt for IV.
- * We deprecated the arguments for this method, but we decided
- * keeping this behaviour for backward compatibility.
- */
- VALUE cname = rb_class_path(rb_obj_class(self));
- rb_warn("arguments for %"PRIsVALUE"#encrypt and %"PRIsVALUE"#decrypt were deprecated; "
- "use %"PRIsVALUE"#pkcs5_keyivgen to derive key and IV",
- cname, cname, cname);
- StringValue(pass);
- GetCipher(self, ctx);
- if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
- else{
- StringValue(init_v);
- if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) {
- memset(iv, 0, EVP_MAX_IV_LENGTH);
- memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v));
- }
- else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv));
- }
- EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
- (unsigned char *)RSTRING_PTR(pass), RSTRING_LENINT(pass), 1, key, NULL);
- p_key = key;
- p_iv = iv;
- }
- else {
- GetCipher(self, ctx);
- }
- if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) {
- ossl_raise(eCipherError, NULL);
+
+ GetCipher(self, ctx);
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, enc) != 1) {
+ ossl_raise(eCipherError, "EVP_CipherInit_ex");
}
- rb_ivar_set(self, id_key_set, p_key ? Qtrue : Qfalse);
+ rb_ivar_set(self, id_key_set, Qfalse);
return self;
}
@@ -249,16 +248,15 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
*
* Initializes the Cipher for encryption.
*
- * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
- * following methods:
- * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
+ * Make sure to call either #encrypt or #decrypt before using the Cipher for
+ * any operation or setting any parameters.
*
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
*/
static VALUE
-ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
+ossl_cipher_encrypt(VALUE self)
{
- return ossl_cipher_init(argc, argv, self, 1);
+ return ossl_cipher_init(self, 1);
}
/*
@@ -267,16 +265,15 @@ ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
*
* Initializes the Cipher for decryption.
*
- * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
- * following methods:
- * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
+ * Make sure to call either #encrypt or #decrypt before using the Cipher for
+ * any operation or setting any parameters.
*
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
*/
static VALUE
-ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
+ossl_cipher_decrypt(VALUE self)
{
- return ossl_cipher_init(argc, argv, self, 0);
+ return ossl_cipher_init(self, 0);
}
/*
@@ -285,46 +282,42 @@ ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
*
* Generates and sets the key/IV based on a password.
*
- * *WARNING*: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40,
- * or DES with MD5 or SHA1. Using anything else (like AES) will generate the
- * key/iv using an OpenSSL specific method. This method is deprecated and
- * should no longer be used. Use a PKCS5 v2 key generation method from
- * OpenSSL::PKCS5 instead.
+ * *WARNING*: This method is deprecated and should not be used. This method
+ * corresponds to EVP_BytesToKey(), a non-standard OpenSSL extension of the
+ * legacy PKCS #5 v1.5 key derivation function. See OpenSSL::KDF for other
+ * options to derive keys from passwords.
*
* === Parameters
* * _salt_ must be an 8 byte string if provided.
* * _iterations_ is an integer with a default of 2048.
* * _digest_ is a Digest object that defaults to 'MD5'
- *
- * A minimum of 1000 iterations is recommended.
- *
*/
static VALUE
ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
const EVP_MD *digest;
- VALUE vpass, vsalt, viter, vdigest;
+ VALUE vpass, vsalt, viter, vdigest, md_holder;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
int iter;
rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
StringValue(vpass);
if(!NIL_P(vsalt)){
- StringValue(vsalt);
- if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
- ossl_raise(eCipherError, "salt must be an 8-octet string");
- salt = (unsigned char *)RSTRING_PTR(vsalt);
+ StringValue(vsalt);
+ if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
+ ossl_raise(eCipherError, "salt must be an 8-octet string");
+ salt = (unsigned char *)RSTRING_PTR(vsalt);
}
iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
if (iter <= 0)
- rb_raise(rb_eArgError, "iterations must be a positive integer");
- digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_get_digestbyname(vdigest);
+ rb_raise(rb_eArgError, "iterations must be a positive integer");
+ digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder);
GetCipher(self, ctx);
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
- (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
+ (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
OPENSSL_cleanse(key, sizeof key);
OPENSSL_cleanse(iv, sizeof iv);
@@ -335,25 +328,25 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
static int
ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr,
- const unsigned char *in, long in_len)
+ const unsigned char *in, long in_len)
{
int out_part_len;
int limit = INT_MAX / 2 + 1;
long out_len = 0;
do {
- int in_part_len = in_len > limit ? limit : (int)in_len;
+ int in_part_len = in_len > limit ? limit : (int)in_len;
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
- &out_part_len, in, in_part_len))
- return 0;
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
+ &out_part_len, in, in_part_len))
+ return 0;
- out_len += out_part_len;
- in += in_part_len;
+ out_len += out_part_len;
+ in += in_part_len;
} while ((in_len -= limit) > 0);
if (out_len_ptr)
- *out_len_ptr = out_len;
+ *out_len_ptr = out_len;
return 1;
}
@@ -369,6 +362,9 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p
*
* If _buffer_ is given, the encryption/decryption result will be written to
* it. _buffer_ will be resized automatically.
+ *
+ * *NOTE*: When decrypting using an AEAD cipher, the integrity of the output
+ * is not verified until #final has been called.
*/
static VALUE
ossl_cipher_update(int argc, VALUE *argv, VALUE self)
@@ -381,7 +377,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &data, &str);
if (!RTEST(rb_attr_get(self, id_key_set)))
- ossl_raise(eCipherError, "key not set");
+ ossl_raise(eCipherError, "key not set");
StringValue(data);
in = (unsigned char *)RSTRING_PTR(data);
@@ -400,14 +396,14 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
* currently implemented in OpenSSL, but this can change in the future.
*/
if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) {
- ossl_raise(rb_eRangeError,
- "data too big to make output buffer: %ld bytes", in_len);
+ ossl_raise(rb_eRangeError,
+ "data too big to make output buffer: %ld bytes", in_len);
}
out_len = in_len + EVP_MAX_BLOCK_LENGTH;
- if (NIL_P(str)) {
- str = rb_str_new(0, out_len);
- } else {
+ if (NIL_P(str))
+ str = rb_str_buf_new(out_len);
+ else {
StringValue(str);
if ((long)rb_str_capacity(str) >= out_len)
rb_str_modify(str);
@@ -415,9 +411,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_str_modify_expand(str, out_len - RSTRING_LEN(str));
}
- if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
- ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING_LEN(str));
+ if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str),
+ &out_len, in, in_len))
+ ossl_raise(eCipherError, "EVP_CipherUpdate");
rb_str_set_len(str, out_len);
return str;
@@ -428,14 +424,17 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
* cipher.final -> string
*
* Returns the remaining data held in the cipher object. Further calls to
- * Cipher#update or Cipher#final will return garbage. This call should always
+ * Cipher#update or Cipher#final are invalid. This call should always
* be made as the last call of an encryption or decryption operation, after
* having fed the entire plaintext or ciphertext to the Cipher instance.
*
- * If an authenticated cipher was used, a CipherError is raised if the tag
- * could not be authenticated successfully. Only call this method after
- * setting the authentication tag and passing the entire contents of the
- * ciphertext into the cipher.
+ * When encrypting using an AEAD cipher, the authentication tag can be
+ * retrieved by #auth_tag after #final has been called.
+ *
+ * When decrypting using an AEAD cipher, this method will verify the integrity
+ * of the ciphertext and the associated data with the authentication tag,
+ * which must be set by #auth_tag= prior to calling this method.
+ * If the verification fails, CipherError will be raised.
*/
static VALUE
ossl_cipher_final(VALUE self)
@@ -446,9 +445,17 @@ ossl_cipher_final(VALUE self)
GetCipher(self, ctx);
str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
- if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
- ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING_LEN(str));
+ if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) {
+ /* For AEAD ciphers, this is likely an authentication failure */
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) {
+ /* For AEAD ciphers, EVP_CipherFinal_ex failures are authentication tag verification failures */
+ ossl_raise(eAuthTagError, "AEAD authentication tag verification failed");
+ }
+ else {
+ /* For non-AEAD ciphers */
+ ossl_raise(eCipherError, "cipher final failed");
+ }
+ }
rb_str_set_len(str, out_len);
return str;
@@ -473,7 +480,7 @@ ossl_cipher_name(VALUE self)
/*
* call-seq:
- * cipher.key = string -> string
+ * cipher.key = string
*
* Sets the cipher key. To generate a key, you should either use a secure
* random byte string or, if the key is to be derived from a password, you
@@ -481,6 +488,8 @@ ossl_cipher_name(VALUE self)
* generate a secure random-based key, Cipher#random_key may be used.
*
* Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ *
+ * See also the man page EVP_CipherInit_ex(3).
*/
static VALUE
ossl_cipher_set_key(VALUE self, VALUE key)
@@ -493,10 +502,10 @@ ossl_cipher_set_key(VALUE self, VALUE key)
key_len = EVP_CIPHER_CTX_key_length(ctx);
if (RSTRING_LEN(key) != key_len)
- ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
+ ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
rb_ivar_set(self, id_key_set, Qtrue);
@@ -505,15 +514,21 @@ ossl_cipher_set_key(VALUE self, VALUE key)
/*
* call-seq:
- * cipher.iv = string -> string
+ * cipher.iv = string
*
* Sets the cipher IV. Please note that since you should never be using ECB
* mode, an IV is always explicitly required and should be set prior to
- * encryption. The IV itself can be safely transmitted in public, but it
- * should be unpredictable to prevent certain kinds of attacks. You may use
- * Cipher#random_iv to create a secure random IV.
+ * encryption. The IV itself can be safely transmitted in public.
*
- * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ * This method expects the String to have the length equal to #iv_len. To use
+ * a different IV length with an AEAD cipher, #iv_len= must be set prior to
+ * calling this method.
+ *
+ * *NOTE*: In OpenSSL API conventions, the IV value may correspond to the
+ * "nonce" instead in some cipher modes. Refer to the OpenSSL man pages for
+ * details.
+ *
+ * See also the man page EVP_CipherInit_ex(3).
*/
static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
@@ -525,14 +540,14 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
- iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
+ iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len)
- iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
if (RSTRING_LEN(iv) != iv_len)
- ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
+ ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return iv;
}
@@ -541,8 +556,7 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
* call-seq:
* cipher.authenticated? -> true | false
*
- * Indicated whether this Cipher instance uses an Authenticated Encryption
- * mode.
+ * Indicates whether this Cipher instance uses an AEAD mode.
*/
static VALUE
ossl_cipher_is_authenticated(VALUE self)
@@ -556,21 +570,23 @@ ossl_cipher_is_authenticated(VALUE self)
/*
* call-seq:
- * cipher.auth_data = string -> string
+ * cipher.auth_data = string
+ *
+ * Sets additional authenticated data (AAD), also called associated data, for
+ * this Cipher. This method is available for AEAD ciphers.
*
- * Sets the cipher's additional authenticated data. This field must be
- * set when using AEAD cipher modes such as GCM or CCM. If no associated
- * data shall be used, this method must *still* be called with a value of "".
* The contents of this field should be non-sensitive data which will be
* added to the ciphertext to generate the authentication tag which validates
* the contents of the ciphertext.
*
- * The AAD must be set prior to encryption or decryption. In encryption mode,
- * it must be set after calling Cipher#encrypt and setting Cipher#key= and
- * Cipher#iv=. When decrypting, the authenticated data must be set after key,
- * iv and especially *after* the authentication tag has been set. I.e. set it
- * only after calling Cipher#decrypt, Cipher#key=, Cipher#iv= and
- * Cipher#auth_tag= first.
+ * This method must be called after #key= and #iv= have been set, but before
+ * starting actual encryption or decryption with #update. In some cipher modes,
+ * #auth_tag_len= and #ccm_data_len= may also need to be called before this
+ * method.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CipherUpdate() with the output buffer
+ * set to NULL.
*/
static VALUE
ossl_cipher_set_auth_data(VALUE self, VALUE data)
@@ -586,7 +602,7 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "AEAD not supported by this cipher");
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data");
@@ -598,16 +614,17 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
* call-seq:
* cipher.auth_tag(tag_len = 16) -> String
*
- * Gets the authentication tag generated by Authenticated Encryption Cipher
- * modes (GCM for example). This tag may be stored along with the ciphertext,
- * then set on the decryption cipher to authenticate the contents of the
- * ciphertext against changes. If the optional integer parameter _tag_len_ is
- * given, the returned tag will be _tag_len_ bytes long. If the parameter is
- * omitted, the default length of 16 bytes or the length previously set by
- * #auth_tag_len= will be used. For maximum security, the longest possible
- * should be chosen.
+ * Gets the generated authentication tag. This method is available for AEAD
+ * ciphers, and should be called after encryption has been finalized by calling
+ * #final.
+ *
+ * The returned tag will be _tag_len_ bytes long. Some cipher modes require
+ * the desired length in advance using a separate call to #auth_tag_len=,
+ * before starting encryption.
*
- * The tag may only be retrieved after calling Cipher#final.
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_GET_TAG.
*/
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
@@ -618,34 +635,42 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &vtag_len);
if (NIL_P(vtag_len))
- vtag_len = rb_attr_get(self, id_auth_tag_len);
+ vtag_len = rb_attr_get(self, id_auth_tag_len);
if (!NIL_P(vtag_len))
- tag_len = NUM2INT(vtag_len);
+ tag_len = NUM2INT(vtag_len);
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "authentication tag not supported by this cipher");
+ ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len);
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
- ossl_raise(eCipherError, "retrieving the authentication tag failed");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)) <= 0)
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
return ret;
}
/*
* call-seq:
- * cipher.auth_tag = string -> string
+ * cipher.auth_tag = string
*
* Sets the authentication tag to verify the integrity of the ciphertext.
- * This can be called only when the cipher supports AE. The tag must be set
- * after calling Cipher#decrypt, Cipher#key= and Cipher#iv=, but before
- * calling Cipher#final. After all decryption is performed, the tag is
- * verified automatically in the call to Cipher#final.
*
- * For OCB mode, the tag length must be supplied with #auth_tag_len=
- * beforehand.
+ * The authentication tag must be set before #final is called. The tag is
+ * verified during the #final call.
+ *
+ * Note that, for CCM mode and OCB mode, the expected length of the tag must
+ * be set before starting decryption by a separate call to #auth_tag_len=.
+ * The content of the tag can be provided at any time before #final is called.
+ *
+ * *NOTE*: The caller must ensure that the String passed to this method has
+ * the desired length. Some cipher modes support variable tag lengths, and
+ * this method may accept a truncated tag without raising an exception.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_TAG.
*/
static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
@@ -660,24 +685,27 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "authentication tag not supported by this cipher");
+ ossl_raise(eCipherError, "authentication tag not supported by this cipher");
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
- ossl_raise(eCipherError, "unable to set AEAD tag");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag) <= 0)
+ ossl_raise(eCipherError, "unable to set AEAD tag");
return vtag;
}
/*
* call-seq:
- * cipher.auth_tag_len = Integer -> Integer
+ * cipher.auth_tag_len = integer
+ *
+ * Sets the length of the expected authentication tag for this Cipher. This
+ * method is available for some of AEAD ciphers that require the length to be
+ * set before starting encryption or decryption, such as CCM mode or OCB mode.
*
- * Sets the length of the authentication tag to be generated or to be given for
- * AEAD ciphers that requires it as in input parameter. Note that not all AEAD
- * ciphers support this method.
+ * For CCM mode and OCB mode, the tag length must be set before #iv= is set.
*
- * In OCB mode, the length must be supplied both when encrypting and when
- * decrypting, and must be before specifying an IV.
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_TAG and a NULL buffer.
*/
static VALUE
ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
@@ -687,10 +715,10 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "AEAD not supported by this cipher");
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
- ossl_raise(eCipherError, "unable to set authentication tag length");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL) <= 0)
+ ossl_raise(eCipherError, "unable to set authentication tag length");
/* for #auth_tag */
rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));
@@ -700,11 +728,16 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
/*
* call-seq:
- * cipher.iv_len = integer -> integer
+ * cipher.iv_len = integer
*
- * Sets the IV/nonce length of the Cipher. Normally block ciphers don't allow
- * changing the IV length, but some make use of IV for 'nonce'. You may need
- * this for interoperability with other applications.
+ * Sets the IV/nonce length for this Cipher. This method is available for AEAD
+ * ciphers that support variable IV lengths. This method can be called if a
+ * different IV length than OpenSSL's default is desired, prior to calling
+ * #iv=.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_IVLEN.
*/
static VALUE
ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
@@ -714,10 +747,10 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "cipher does not support AEAD");
+ ossl_raise(eCipherError, "cipher does not support AEAD");
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
- ossl_raise(eCipherError, "unable to set IV length");
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL) <= 0)
+ ossl_raise(eCipherError, "unable to set IV length");
/*
* EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save
@@ -730,13 +763,14 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
/*
* call-seq:
- * cipher.key_len = integer -> integer
+ * cipher.key_len = integer
*
* Sets the key length of the cipher. If the cipher is a fixed length cipher
* then attempting to set the key length to any value other than the fixed
* value is an error.
*
- * Under normal circumstances you do not need to call this method (and probably shouldn't).
+ * Under normal circumstances you do not need to call this method (and
+ * probably shouldn't).
*
* See EVP_CIPHER_CTX_set_key_length for further information.
*/
@@ -753,13 +787,16 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length)
return key_length;
}
+// TODO: Should #padding= take a boolean value instead?
/*
* call-seq:
- * cipher.padding = integer -> integer
+ * cipher.padding = 1 or 0
*
- * Enables or disables padding. By default encryption operations are padded using standard block padding and the
- * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the
- * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.
+ * Enables or disables padding. By default encryption operations are padded
+ * using standard block padding and the padding is checked and removed when
+ * decrypting. If the pad parameter is zero then no padding is performed, the
+ * total amount of data encrypted or decrypted must then be a multiple of the
+ * block size or an error will occur.
*
* See EVP_CIPHER_CTX_set_padding for further information.
*/
@@ -771,7 +808,7 @@ ossl_cipher_set_padding(VALUE self, VALUE padding)
GetCipher(self, ctx);
if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return padding;
}
@@ -805,9 +842,9 @@ ossl_cipher_iv_length(VALUE self)
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
- len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
+ len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len)
- len = EVP_CIPHER_CTX_iv_length(ctx);
+ len = EVP_CIPHER_CTX_iv_length(ctx);
return INT2NUM(len);
}
@@ -830,13 +867,17 @@ ossl_cipher_block_size(VALUE self)
/*
* call-seq:
- * cipher.ccm_data_len = integer -> integer
+ * cipher.ccm_data_len = integer
*
- * Sets the length of the plaintext / ciphertext message that will be
- * processed in CCM mode. Make sure to call this method after #key= and
- * #iv= have been set, and before #auth_data=.
+ * Sets the total length of the plaintext / ciphertext message that will be
+ * processed by #update in CCM mode.
*
- * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ * Make sure to call this method after #key= and #iv= have been set, and
+ * before #auth_data= or #update are called.
+ *
+ * This method is only available for CCM mode ciphers.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
*/
static VALUE
ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
@@ -859,11 +900,6 @@ ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
void
Init_ossl_cipher(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Cipher
*
* Provides symmetric algorithms for encryption and decryption. The
@@ -1019,24 +1055,28 @@ Init_ossl_cipher(void)
* could otherwise be exploited to modify ciphertexts in ways beneficial to
* potential attackers.
*
- * An associated data is used where there is additional information, such as
+ * Associated data, also called additional authenticated data (AAD), is
+ * optionally used where there is additional information, such as
* headers or some metadata, that must be also authenticated but not
- * necessarily need to be encrypted. If no associated data is needed for
- * encryption and later decryption, the OpenSSL library still requires a
- * value to be set - "" may be used in case none is available.
+ * necessarily need to be encrypted.
*
* An example using the GCM (Galois/Counter Mode). You have 16 bytes _key_,
* 12 bytes (96 bits) _nonce_ and the associated data _auth_data_. Be sure
* not to reuse the _key_ and _nonce_ pair. Reusing an nonce ruins the
* security guarantees of GCM mode.
*
+ * key = OpenSSL::Random.random_bytes(16)
+ * nonce = OpenSSL::Random.random_bytes(12)
+ * auth_data = "authenticated but unencrypted data"
+ * data = "encrypted data"
+ *
* cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt
* cipher.key = key
* cipher.iv = nonce
* cipher.auth_data = auth_data
*
* encrypted = cipher.update(data) + cipher.final
- * tag = cipher.auth_tag # produces 16 bytes tag by default
+ * tag = cipher.auth_tag(16)
*
* Now you are the receiver. You know the _key_ and have received _nonce_,
* _auth_data_, _encrypted_ and _tag_ through an untrusted network. Note
@@ -1049,23 +1089,29 @@ Init_ossl_cipher(void)
* decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt
* decipher.key = key
* decipher.iv = nonce
- * decipher.auth_tag = tag
+ * decipher.auth_tag = tag # could be called at any time before #final
* decipher.auth_data = auth_data
*
* decrypted = decipher.update(encrypted) + decipher.final
*
* puts data == decrypted #=> true
+ *
+ * Note that other AEAD ciphers may require additional steps, such as
+ * setting the expected tag length (#auth_tag_len=) or the total data
+ * length (#ccm_data_len=) in advance. Make sure to read the relevant man
+ * page for details.
*/
cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
+ eAuthTagError = rb_define_class_under(cCipher, "AuthTagError", eCipherError);
rb_define_alloc_func(cCipher, ossl_cipher_alloc);
rb_define_method(cCipher, "initialize_copy", ossl_cipher_copy, 1);
rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0);
rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
- rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
- rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
+ rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, 0);
+ rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, 0);
rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
rb_define_method(cCipher, "update", ossl_cipher_update, -1);
rb_define_method(cCipher, "final", ossl_cipher_final, 0);
@@ -1087,4 +1133,5 @@ Init_ossl_cipher(void)
id_auth_tag_len = rb_intern_const("auth_tag_len");
id_key_set = rb_intern_const("key_set");
+ id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h
index 12da68ca3e..fba63a140f 100644
--- a/ext/openssl/ossl_cipher.h
+++ b/ext/openssl/ossl_cipher.h
@@ -10,7 +10,16 @@
#if !defined(_OSSL_CIPHER_H_)
#define _OSSL_CIPHER_H_
-const EVP_CIPHER *ossl_evp_get_cipherbyname(VALUE);
+/*
+ * Gets EVP_CIPHER from a String or an OpenSSL::Digest instance (discouraged,
+ * but still supported for compatibility). A holder object is created if the
+ * EVP_CIPHER is a "fetched" algorithm.
+ */
+const EVP_CIPHER *ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder);
+/*
+ * This is meant for OpenSSL::Engine#cipher. EVP_CIPHER must not be a fetched
+ * one.
+ */
VALUE ossl_cipher_new(const EVP_CIPHER *);
void Init_ossl_cipher(void);
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c
index ee2ff6786f..274875a978 100644
--- a/ext/openssl/ossl_config.c
+++ b/ext/openssl/ossl_config.c
@@ -413,11 +413,6 @@ Init_ossl_config(void)
char *path;
VALUE path_str;
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Config
*
* Configuration for the openssl library.
@@ -426,7 +421,7 @@ Init_ossl_config(void)
* configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for
* the location of the file for your host.
*
- * See also http://www.openssl.org/docs/apps/config.html
+ * See also https://docs.openssl.org/master/man5/config/
*/
cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject);
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 329de6c1ba..e23968b1e3 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -12,7 +12,7 @@
#define GetDigest(obj, ctx) do { \
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
} \
} while (0)
@@ -21,6 +21,7 @@
*/
static VALUE cDigest;
static VALUE eDigestError;
+static ID id_md_holder;
static VALUE ossl_digest_alloc(VALUE klass);
@@ -33,39 +34,67 @@ ossl_digest_free(void *ctx)
static const rb_data_type_t ossl_digest_type = {
"OpenSSL/Digest",
{
- 0, ossl_digest_free,
+ 0, ossl_digest_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
+#ifdef OSSL_USE_PROVIDER
+static void
+ossl_evp_md_free(void *ptr)
+{
+ // This is safe to call against const EVP_MD * returned by
+ // EVP_get_digestbyname()
+ EVP_MD_free(ptr);
+}
+
+static const rb_data_type_t ossl_evp_md_holder_type = {
+ "OpenSSL/EVP_MD",
+ {
+ .dfree = ossl_evp_md_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+#endif
+
/*
* Public
*/
const EVP_MD *
-ossl_evp_get_digestbyname(VALUE obj)
+ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder)
{
- const EVP_MD *md;
- ASN1_OBJECT *oid = NULL;
-
- if (RB_TYPE_P(obj, T_STRING)) {
- const char *name = StringValueCStr(obj);
-
- md = EVP_get_digestbyname(name);
- if (!md) {
- oid = OBJ_txt2obj(name, 0);
- md = EVP_get_digestbyobj(oid);
- ASN1_OBJECT_free(oid);
- }
- if(!md)
- ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%"PRIsVALUE").", obj);
- } else {
+ *holder = Qnil;
+ if (rb_obj_is_kind_of(obj, cDigest)) {
EVP_MD_CTX *ctx;
-
GetDigest(obj, ctx);
-
- md = EVP_MD_CTX_get0_md(ctx);
+ EVP_MD *md = (EVP_MD *)EVP_MD_CTX_get0_md(ctx);
+#ifdef OSSL_USE_PROVIDER
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
+ if (!EVP_MD_up_ref(md))
+ ossl_raise(eDigestError, "EVP_MD_up_ref");
+ RTYPEDDATA_DATA(*holder) = md;
+#endif
+ return md;
}
+ const char *name = StringValueCStr(obj);
+ EVP_MD *md = (EVP_MD *)EVP_get_digestbyname(name);
+ if (!md) {
+ ASN1_OBJECT *oid = OBJ_txt2obj(name, 0);
+ md = (EVP_MD *)EVP_get_digestbyobj(oid);
+ ASN1_OBJECT_free(oid);
+ }
+#ifdef OSSL_USE_PROVIDER
+ if (!md) {
+ ossl_clear_error();
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
+ md = EVP_MD_fetch(NULL, name, NULL);
+ RTYPEDDATA_DATA(*holder) = md;
+ }
+#endif
+ if (!md)
+ ossl_raise(eDigestError, "unsupported digest algorithm: %"PRIsVALUE,
+ obj);
return md;
}
@@ -75,14 +104,17 @@ ossl_digest_new(const EVP_MD *md)
VALUE ret;
EVP_MD_CTX *ctx;
+ // NOTE: This does not set id_md_holder because this function should
+ // only be called from ossl_engine.c, which will not use any
+ // reference-counted digests.
ret = ossl_digest_alloc(cDigest);
ctx = EVP_MD_CTX_new();
if (!ctx)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
RTYPEDDATA_DATA(ret) = ctx;
if (!EVP_DigestInit_ex(ctx, md, NULL))
- ossl_raise(eDigestError, "Digest initialization failed");
+ ossl_raise(eDigestError, "Digest initialization failed");
return ret;
}
@@ -121,21 +153,22 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
const EVP_MD *md;
- VALUE type, data;
+ VALUE type, data, md_holder;
rb_scan_args(argc, argv, "11", &type, &data);
- md = ossl_evp_get_digestbyname(type);
+ md = ossl_evp_md_fetch(type, &md_holder);
if (!NIL_P(data)) StringValue(data);
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);
if (!ctx) {
- RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
- if (!ctx)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
if (!EVP_DigestInit_ex(ctx, md, NULL))
- ossl_raise(eDigestError, "Digest initialization failed");
+ ossl_raise(eDigestError, "Digest initialization failed");
+ rb_ivar_set(self, id_md_holder, md_holder);
if (!NIL_P(data)) return ossl_digest_update(self, data);
return self;
@@ -152,14 +185,14 @@ ossl_digest_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1);
if (!ctx1) {
- RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
- if (!ctx1)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
+ if (!ctx1)
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
GetDigest(other, ctx2);
if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
- ossl_raise(eDigestError, NULL);
+ ossl_raise(eDigestError, NULL);
}
return self;
}
@@ -184,8 +217,8 @@ ossl_s_digests(VALUE self)
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
- add_digest_name_to_ary,
- (void*)ary);
+ add_digest_name_to_ary,
+ (void*)ary);
return ary;
}
@@ -205,7 +238,7 @@ ossl_digest_reset(VALUE self)
GetDigest(self, ctx);
if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {
- ossl_raise(eDigestError, "Digest initialization failed.");
+ ossl_raise(eDigestError, "Digest initialization failed.");
}
return self;
@@ -235,7 +268,7 @@ ossl_digest_update(VALUE self, VALUE data)
GetDigest(self, ctx);
if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)))
- ossl_raise(eDigestError, "EVP_DigestUpdate");
+ ossl_raise(eDigestError, "EVP_DigestUpdate");
return self;
}
@@ -254,7 +287,7 @@ ossl_digest_finish(VALUE self)
GetDigest(self, ctx);
str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL))
- ossl_raise(eDigestError, "EVP_DigestFinal_ex");
+ ossl_raise(eDigestError, "EVP_DigestFinal_ex");
return str;
}
@@ -332,11 +365,6 @@ ossl_digest_block_length(VALUE self)
void
Init_ossl_digest(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Digest
*
* OpenSSL::Digest allows you to compute message digests (sometimes
@@ -442,4 +470,6 @@ Init_ossl_digest(void)
rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
rb_define_method(cDigest, "name", ossl_digest_name, 0);
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
}
diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h
index 588a0c6f57..9c3bb2b149 100644
--- a/ext/openssl/ossl_digest.h
+++ b/ext/openssl/ossl_digest.h
@@ -10,7 +10,15 @@
#if !defined(_OSSL_DIGEST_H_)
#define _OSSL_DIGEST_H_
-const EVP_MD *ossl_evp_get_digestbyname(VALUE);
+/*
+ * Gets EVP_MD from a String or an OpenSSL::Digest instance (discouraged, but
+ * still supported for compatibility). A holder object is created if the EVP_MD
+ * is a "fetched" algorithm.
+ */
+const EVP_MD *ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder);
+/*
+ * This is meant for OpenSSL::Engine#digest. EVP_MD must not be a fetched one.
+ */
VALUE ossl_digest_new(const EVP_MD *);
void Init_ossl_digest(void);
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index cb08049a82..a2bcb07ea4 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -16,7 +16,7 @@
TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)
#define SetEngine(obj, engine) do { \
if (!(engine)) { \
- ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (engine); \
} while(0)
@@ -49,12 +49,12 @@ static VALUE eEngineError;
*/
#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
do{\
- if(!strcmp(#engine_name, RSTRING_PTR(name))){\
- if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
- return Qtrue;\
- else\
- ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
- }\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
+ return Qtrue;\
+ else\
+ ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
+ }\
}while(0)
static void
@@ -66,7 +66,7 @@ ossl_engine_free(void *engine)
static const rb_data_type_t ossl_engine_type = {
"OpenSSL/Engine",
{
- 0, ossl_engine_free,
+ 0, ossl_engine_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -130,12 +130,12 @@ ossl_engine_s_engines(VALUE klass)
ary = rb_ary_new();
for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
- obj = NewEngine(klass);
- /* Need a ref count of two here because of ENGINE_free being
- * called internally by OpenSSL when moving to the next ENGINE
- * and by us when releasing the ENGINE reference */
- ENGINE_up_ref(e);
- SetEngine(obj, e);
+ obj = NewEngine(klass);
+ /* Need a ref count of two here because of ENGINE_free being
+ * called internally by OpenSSL when moving to the next ENGINE
+ * and by us when releasing the ENGINE reference */
+ ENGINE_up_ref(e);
+ SetEngine(obj, e);
rb_ary_push(ary, obj);
}
@@ -163,13 +163,13 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
ossl_engine_s_load(1, &id, klass);
obj = NewEngine(klass);
if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
- ossl_raise(eEngineError, NULL);
+ ossl_raise(eEngineError, NULL);
SetEngine(obj, e);
if(rb_block_given_p()) rb_yield(obj);
if(!ENGINE_init(e))
- ossl_raise(eEngineError, NULL);
+ ossl_raise(eEngineError, NULL);
ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
- 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
+ 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
ossl_clear_error();
return obj;
@@ -184,7 +184,7 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
* OpenSSL::Engine.load
* OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
* OpenSSL::Engine.engines.first.id
- * #=> "rsax"
+ * #=> "rsax"
*/
static VALUE
ossl_engine_get_id(VALUE self)
@@ -203,7 +203,7 @@ ossl_engine_get_id(VALUE self)
* OpenSSL::Engine.load
* OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
* OpenSSL::Engine.engines.first.name
- * #=> "RSAX engine support"
+ * #=> "RSAX engine support"
*
*/
static VALUE
@@ -274,11 +274,11 @@ ossl_engine_get_cipher(VALUE self, VALUE name)
* Will raise an EngineError if the digest is unavailable.
*
* e = OpenSSL::Engine.by_id("openssl")
- * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
+ * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
* e.digest("SHA1")
- * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
+ * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
* e.digest("zomg")
- * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
+ * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
*/
static VALUE
ossl_engine_get_digest(VALUE self, VALUE name)
@@ -320,7 +320,7 @@ ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
GetEngine(self, e);
pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
if (!pkey) ossl_raise(eEngineError, NULL);
- obj = ossl_pkey_new(pkey);
+ obj = ossl_pkey_wrap(pkey);
OSSL_PKEY_SET_PRIVATE(obj);
return obj;
@@ -350,7 +350,7 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
if (!pkey) ossl_raise(eEngineError, NULL);
- return ossl_pkey_new(pkey);
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -365,7 +365,7 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
* your OS.
*
* [All flags] 0xFFFF
- * [No flags] 0x0000
+ * [No flags] 0x0000
*
* See also <openssl/engine.h>
*/
@@ -399,7 +399,7 @@ ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
GetEngine(self, e);
rb_scan_args(argc, argv, "11", &cmd, &val);
ret = ENGINE_ctrl_cmd_string(e, StringValueCStr(cmd),
- NIL_P(val) ? NULL : StringValueCStr(val), 0);
+ NIL_P(val) ? NULL : StringValueCStr(val), 0);
if (!ret) ossl_raise(eEngineError, NULL);
return self;
@@ -409,11 +409,11 @@ static VALUE
ossl_engine_cmd_flag_to_name(int flag)
{
switch(flag){
- case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
- case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
- case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
- case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
- default: return rb_str_new2("UNKNOWN");
+ case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
+ case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
+ case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
+ case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
+ default: return rb_str_new2("UNKNOWN");
}
}
@@ -433,13 +433,13 @@ ossl_engine_get_cmds(VALUE self)
GetEngine(self, e);
ary = rb_ary_new();
if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
- for (p = defn; p->cmd_num > 0; p++){
- tmp = rb_ary_new();
- rb_ary_push(tmp, rb_str_new2(p->cmd_name));
- rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
- rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
- rb_ary_push(ary, tmp);
- }
+ for (p = defn; p->cmd_num > 0; p++){
+ tmp = rb_ary_new();
+ rb_ary_push(tmp, rb_str_new2(p->cmd_name));
+ rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
+ rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
+ rb_ary_push(ary, tmp);
+ }
}
return ary;
@@ -458,7 +458,7 @@ ossl_engine_inspect(VALUE self)
GetEngine(self, e);
return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">",
- rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
+ rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
}
#define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
@@ -466,11 +466,6 @@ ossl_engine_inspect(VALUE self)
void
Init_ossl_engine(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index b304827579..ddcc6a5f8d 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -14,7 +14,7 @@
#define GetHMAC(obj, ctx) do { \
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
+ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
} \
} while (0)
@@ -23,6 +23,7 @@
*/
static VALUE cHMAC;
static VALUE eHMACError;
+static ID id_md_holder;
/*
* Public
@@ -40,7 +41,7 @@ ossl_hmac_free(void *ctx)
static const rb_data_type_t ossl_hmac_type = {
"OpenSSL/HMAC",
{
- 0, ossl_hmac_free,
+ 0, ossl_hmac_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -73,17 +74,17 @@ ossl_hmac_alloc(VALUE klass)
*
* === Example
*
- * key = 'key'
- * instance = OpenSSL::HMAC.new(key, 'SHA1')
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
- * instance.class
- * #=> OpenSSL::HMAC
+ * key = 'key'
+ * instance = OpenSSL::HMAC.new(key, 'SHA1')
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * instance.class
+ * #=> OpenSSL::HMAC
*
* === A note about comparisons
*
* Two instances can be securely compared with #== in constant time:
*
- * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
+ * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
* instance == other_instance
* #=> true
@@ -94,19 +95,22 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
{
EVP_MD_CTX *ctx;
EVP_PKEY *pkey;
+ const EVP_MD *md;
+ VALUE md_holder;
GetHMAC(self, ctx);
StringValue(key);
+ md = ossl_evp_md_fetch(digest, &md_holder);
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
(unsigned char *)RSTRING_PTR(key),
RSTRING_LENINT(key));
if (!pkey)
ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key");
- if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
- NULL, pkey) != 1) {
+ if (EVP_DigestSignInit(ctx, NULL, md, NULL, pkey) != 1) {
EVP_PKEY_free(pkey);
ossl_raise(eHMACError, "EVP_DigestSignInit");
}
+ rb_ivar_set(self, id_md_holder, md_holder);
/* Decrement reference counter; EVP_MD_CTX still keeps it */
EVP_PKEY_free(pkey);
@@ -138,13 +142,13 @@ ossl_hmac_copy(VALUE self, VALUE other)
*
* === Example
*
- * first_chunk = 'The quick brown fox jumps '
- * second_chunk = 'over the lazy dog'
+ * first_chunk = 'The quick brown fox jumps '
+ * second_chunk = 'over the lazy dog'
*
- * instance.update(first_chunk)
- * #=> 5b9a8038a65d571076d97fe783989e52278a492a
- * instance.update(second_chunk)
- * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
+ * instance.update(first_chunk)
+ * #=> 5b9a8038a65d571076d97fe783989e52278a492a
+ * instance.update(second_chunk)
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
*
*/
static VALUE
@@ -222,14 +226,14 @@ ossl_hmac_hexdigest(VALUE self)
*
* === Example
*
- * data = "The quick brown fox jumps over the lazy dog"
- * instance = OpenSSL::HMAC.new('key', 'SHA1')
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * data = "The quick brown fox jumps over the lazy dog"
+ * instance = OpenSSL::HMAC.new('key', 'SHA1')
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
- * instance.update(data)
- * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
- * instance.reset
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * instance.update(data)
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
+ * instance.reset
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
*/
static VALUE
@@ -252,11 +256,6 @@ ossl_hmac_reset(VALUE self)
void
Init_ossl_hmac(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Document-class: OpenSSL::HMAC
*
@@ -300,4 +299,6 @@ Init_ossl_hmac(void)
rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
rb_define_alias(cHMAC, "inspect", "hexdigest");
rb_define_alias(cHMAC, "to_s", "hexdigest");
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
}
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index f349939a80..99a3589b39 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -7,6 +7,27 @@
static VALUE mKDF, eKDF;
+struct pbkdf2_hmac_args {
+ char *pass;
+ int passlen;
+ unsigned char *salt;
+ int saltlen;
+ int iters;
+ const EVP_MD *md;
+ int len;
+ unsigned char *out;
+};
+
+static void *
+pbkdf2_hmac_nogvl(void *args_)
+{
+ struct pbkdf2_hmac_args *args = (struct pbkdf2_hmac_args *)args_;
+ int ret = PKCS5_PBKDF2_HMAC(args->pass, args->passlen, args->salt,
+ args->saltlen, args->iters, args->md,
+ args->len, args->out);
+ return (void *)(uintptr_t)ret;
+}
+
/*
* call-seq:
* KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
@@ -18,6 +39,10 @@ static VALUE mKDF, eKDF;
* For more information about PBKDF2, see RFC 2898 Section 5.2
* (https://www.rfc-editor.org/rfc/rfc2898#section-5.2).
*
+ * *NOTE*: This method cannot be interrupted by Timeout.timeout from the
+ * "timeout" library. Do not take parameters from untrusted sources without
+ * enforcing reasonable limits.
+ *
* === Parameters
* pass :: The password.
* salt :: The salt. Salts prevent attacks based on dictionaries of common
@@ -35,16 +60,16 @@ static VALUE mKDF, eKDF;
static VALUE
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, salt, opts, kwargs[4], str;
+ VALUE pass, salt, opts, kwargs[4], str, md_holder, pass_tmp, salt_tmp;
static ID kwargs_ids[4];
- int iters, len;
+ int passlen, saltlen, iters, len;
const EVP_MD *md;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("iterations");
- kwargs_ids[2] = rb_intern_const("length");
- kwargs_ids[3] = rb_intern_const("hash");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("iterations");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
@@ -53,19 +78,57 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
salt = StringValue(kwargs[0]);
iters = NUM2INT(kwargs[1]);
len = NUM2INT(kwargs[2]);
- md = ossl_evp_get_digestbyname(kwargs[3]);
-
- str = rb_str_new(0, len);
- if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
- (unsigned char *)RSTRING_PTR(salt),
- RSTRING_LENINT(salt), iters, md, len,
- (unsigned char *)RSTRING_PTR(str)))
- ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
-
+ md = ossl_evp_md_fetch(kwargs[3], &md_holder);
+ passlen = RSTRING_LENINT(pass);
+ saltlen = RSTRING_LENINT(salt);
+ str = rb_str_new(NULL, len);
+ struct pbkdf2_hmac_args args = {
+ .pass = ALLOCV(pass_tmp, passlen),
+ .passlen = passlen,
+ .salt = ALLOCV(salt_tmp, saltlen),
+ .saltlen = saltlen,
+ .iters = iters,
+ .md = md,
+ .len = len,
+ .out = (unsigned char *)RSTRING_PTR(str),
+ };
+ memcpy(args.pass, RSTRING_PTR(pass), passlen);
+ memcpy(args.salt, RSTRING_PTR(salt), saltlen);
+ if (!rb_thread_call_without_gvl(pbkdf2_hmac_nogvl, &args, NULL, NULL))
+ ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
+ OPENSSL_cleanse(args.pass, passlen);
+ ALLOCV_END(pass_tmp);
+ ALLOCV_END(salt_tmp);
return str;
}
#if defined(HAVE_EVP_PBE_SCRYPT)
+struct scrypt_args {
+ char *pass;
+ size_t passlen;
+ unsigned char *salt;
+ size_t saltlen;
+ uint64_t N, r, p;
+ size_t len;
+ unsigned char *out;
+};
+
+static void *
+scrypt_nogvl(void *args_)
+{
+ struct scrypt_args *args = (struct scrypt_args *)args_;
+ /*
+ * OpenSSL uses 32MB by default (if zero is specified), which is too
+ * small. Let's not limit memory consumption but just let malloc() fail
+ * inside OpenSSL. The amount is controllable by other parameters.
+ */
+ uint64_t maxmem = UINT64_MAX;
+ int ret = EVP_PBE_scrypt(args->pass, args->passlen,
+ args->salt, args->saltlen, args->N, args->r,
+ args->p, maxmem, args->out, args->len);
+ return (void *)(uintptr_t)ret;
+}
+
/*
* call-seq:
* KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
@@ -84,6 +147,10 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
*
* See RFC 7914 (https://www.rfc-editor.org/rfc/rfc7914) for more information.
*
+ * *NOTE*: This method cannot be interrupted by Timeout.timeout from the
+ * "timeout" library. Do not take parameters from untrusted sources without
+ * enforcing reasonable limits.
+ *
* === Parameters
* pass :: Passphrase.
* salt :: Salt.
@@ -101,17 +168,18 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_scrypt(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, salt, opts, kwargs[5], str;
+ VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;
static ID kwargs_ids[5];
- size_t len;
- uint64_t N, r, p, maxmem;
+ size_t passlen, saltlen;
+ long len;
+ uint64_t N, r, p;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("N");
- kwargs_ids[2] = rb_intern_const("r");
- kwargs_ids[3] = rb_intern_const("p");
- kwargs_ids[4] = rb_intern_const("length");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("N");
+ kwargs_ids[2] = rb_intern_const("r");
+ kwargs_ids[3] = rb_intern_const("p");
+ kwargs_ids[4] = rb_intern_const("length");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
@@ -122,19 +190,27 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
r = NUM2UINT64T(kwargs[2]);
p = NUM2UINT64T(kwargs[3]);
len = NUM2LONG(kwargs[4]);
- /*
- * OpenSSL uses 32MB by default (if zero is specified), which is too small.
- * Let's not limit memory consumption but just let malloc() fail inside
- * OpenSSL. The amount is controllable by other parameters.
- */
- maxmem = SIZE_MAX;
-
- str = rb_str_new(0, len);
- if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
- (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
- N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
- ossl_raise(eKDF, "EVP_PBE_scrypt");
-
+ passlen = RSTRING_LEN(pass);
+ saltlen = RSTRING_LEN(salt);
+ str = rb_str_new(NULL, len);
+ struct scrypt_args args = {
+ .pass = ALLOCV(pass_tmp, passlen),
+ .passlen = passlen,
+ .salt = ALLOCV(salt_tmp, saltlen),
+ .saltlen = saltlen,
+ .N = N,
+ .r = r,
+ .p = p,
+ .len = len,
+ .out = (unsigned char *)RSTRING_PTR(str),
+ };
+ memcpy(args.pass, RSTRING_PTR(pass), passlen);
+ memcpy(args.salt, RSTRING_PTR(salt), saltlen);
+ if (!rb_thread_call_without_gvl(scrypt_nogvl, &args, NULL, NULL))
+ ossl_raise(eKDF, "EVP_PBE_scrypt");
+ OPENSSL_cleanse(args.pass, passlen);
+ ALLOCV_END(pass_tmp);
+ ALLOCV_END(salt_tmp);
return str;
}
#endif
@@ -172,7 +248,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_hkdf(int argc, VALUE *argv, VALUE self)
{
- VALUE ikm, salt, info, opts, kwargs[4], str;
+ VALUE ikm, salt, info, opts, kwargs[4], str, md_holder;
static ID kwargs_ids[4];
int saltlen, ikmlen, infolen;
size_t len;
@@ -180,10 +256,10 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
EVP_PKEY_CTX *pctx;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("info");
- kwargs_ids[2] = rb_intern_const("length");
- kwargs_ids[3] = rb_intern_const("hash");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("info");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
}
rb_scan_args(argc, argv, "1:", &ikm, &opts);
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
@@ -196,39 +272,39 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
infolen = RSTRING_LENINT(info);
len = (size_t)NUM2LONG(kwargs[2]);
if (len > LONG_MAX)
- rb_raise(rb_eArgError, "length must be non-negative");
- md = ossl_evp_get_digestbyname(kwargs[3]);
+ rb_raise(rb_eArgError, "length must be non-negative");
+ md = ossl_evp_md_fetch(kwargs[3], &md_holder);
str = rb_str_new(NULL, (long)len);
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!pctx)
- ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
if (EVP_PKEY_derive_init(pctx) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_derive_init");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
}
if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
}
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
- saltlen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
+ saltlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
}
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
- ikmlen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
+ ikmlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
}
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
- infolen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
+ infolen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
}
if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_derive");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive");
}
rb_str_set_len(str, (long)len);
EVP_PKEY_CTX_free(pctx);
@@ -239,11 +315,6 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
void
Init_ossl_kdf(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Document-module: OpenSSL::KDF
*
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index 445aeeba15..8440c2ee82 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, 0)
#define SetSPKI(obj, spki) do { \
if (!(spki)) { \
- ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (spki); \
} while (0)
#define GetSPKI(obj, spki) do { \
TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \
if (!(spki)) { \
- ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
} \
} while (0)
@@ -48,7 +48,7 @@ ossl_netscape_spki_free(void *spki)
static const rb_data_type_t ossl_netscape_spki_type = {
"OpenSSL/NETSCAPE_SPKI",
{
- 0, ossl_netscape_spki_free,
+ 0, ossl_netscape_spki_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -61,7 +61,7 @@ ossl_spki_alloc(VALUE klass)
obj = NewSPKI(klass);
if (!(spki = NETSCAPE_SPKI_new())) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
SetSPKI(obj, spki);
@@ -83,15 +83,15 @@ ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
const unsigned char *p;
if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
- return self;
+ return self;
}
StringValue(buffer);
if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), RSTRING_LENINT(buffer)))) {
- ossl_clear_error();
- p = (unsigned char *)RSTRING_PTR(buffer);
- if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
- ossl_raise(eSPKIError, NULL);
- }
+ ossl_clear_error();
+ p = (unsigned char *)RSTRING_PTR(buffer);
+ if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
+ ossl_raise(eSPKIError, NULL);
+ }
}
NETSCAPE_SPKI_free(DATA_PTR(self));
SetSPKI(self, spki);
@@ -140,7 +140,7 @@ ossl_spki_to_pem(VALUE self)
GetSPKI(self, spki);
if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
str = ossl_buf2str(data, rb_long2int(strlen(data)));
@@ -162,11 +162,11 @@ ossl_spki_print(VALUE self)
GetSPKI(self, spki);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
if (!NETSCAPE_SPKI_print(out, spki)) {
- BIO_free(out);
- ossl_raise(eSPKIError, NULL);
+ BIO_free(out);
+ ossl_raise(eSPKIError, NULL);
}
return ossl_membio2str(out);
@@ -187,10 +187,10 @@ ossl_spki_get_public_key(VALUE self)
GetSPKI(self, spki);
if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
- return ossl_pkey_new(pkey); /* NO DUP - OK */
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -214,7 +214,7 @@ ossl_spki_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))
- ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
return key;
}
@@ -230,13 +230,12 @@ ossl_spki_get_challenge(VALUE self)
NETSCAPE_SPKI *spki;
GetSPKI(self, spki);
- if (spki->spkac->challenge->length <= 0) {
- OSSL_Debug("Challenge.length <= 0?");
- return rb_str_new(0, 0);
+ if (ASN1_STRING_length(spki->spkac->challenge) <= 0) {
+ OSSL_Debug("Challenge.length <= 0?");
+ return rb_str_new(0, 0);
}
- return rb_str_new((const char *)spki->spkac->challenge->data,
- spki->spkac->challenge->length);
+ return asn1str_to_str(spki->spkac->challenge);
}
/*
@@ -257,8 +256,8 @@ ossl_spki_set_challenge(VALUE self, VALUE str)
StringValue(str);
GetSPKI(self, spki);
if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),
- RSTRING_LENINT(str))) {
- ossl_raise(eSPKIError, NULL);
+ RSTRING_LENINT(str))) {
+ ossl_raise(eSPKIError, NULL);
}
return str;
@@ -283,13 +282,13 @@ ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
NETSCAPE_SPKI *spki;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
GetSPKI(self, spki);
- if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
- ossl_raise(eSPKIError, NULL);
- }
+ if (!NETSCAPE_SPKI_sign(spki, pkey, md))
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_sign");
return self;
}
@@ -315,12 +314,12 @@ ossl_spki_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (NETSCAPE_SPKI_verify(spki, pkey)) {
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
case 1:
- return Qtrue;
+ return Qtrue;
default:
- ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
}
}
@@ -378,11 +377,6 @@ ossl_spki_verify(VALUE self, VALUE key)
void
Init_ossl_ns_spki(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
mNetscape = rb_define_module_under(mOSSL, "Netscape");
eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError);
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index cb2f1a62d0..9dd4b466d2 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -84,7 +84,7 @@ ossl_ocsp_request_free(void *ptr)
static const rb_data_type_t ossl_ocsp_request_type = {
"OpenSSL/OCSP/REQUEST",
{
- 0, ossl_ocsp_request_free,
+ 0, ossl_ocsp_request_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -98,7 +98,7 @@ ossl_ocsp_response_free(void *ptr)
static const rb_data_type_t ossl_ocsp_response_type = {
"OpenSSL/OCSP/RESPONSE",
{
- 0, ossl_ocsp_response_free,
+ 0, ossl_ocsp_response_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -112,7 +112,7 @@ ossl_ocsp_basicresp_free(void *ptr)
static const rb_data_type_t ossl_ocsp_basicresp_type = {
"OpenSSL/OCSP/BASICRESP",
{
- 0, ossl_ocsp_basicresp_free,
+ 0, ossl_ocsp_basicresp_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -126,7 +126,7 @@ ossl_ocsp_singleresp_free(void *ptr)
static const rb_data_type_t ossl_ocsp_singleresp_type = {
"OpenSSL/OCSP/SINGLERESP",
{
- 0, ossl_ocsp_singleresp_free,
+ 0, ossl_ocsp_singleresp_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -140,7 +140,7 @@ ossl_ocsp_certid_free(void *ptr)
static const rb_data_type_t ossl_ocsp_certid_type = {
"OpenSSL/OCSP/CERTID",
{
- 0, ossl_ocsp_certid_free,
+ 0, ossl_ocsp_certid_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -149,10 +149,14 @@ static const rb_data_type_t ossl_ocsp_certid_type = {
* Public
*/
static VALUE
-ossl_ocspcertid_new(OCSP_CERTID *cid)
+ossl_ocspcid_new(const OCSP_CERTID *cid)
{
VALUE obj = NewOCSPCertId(cOCSPCertId);
- SetOCSPCertId(obj, cid);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ OCSP_CERTID *cid_new = OCSP_CERTID_dup((OCSP_CERTID *)cid);
+ if (!cid_new)
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ SetOCSPCertId(obj, cid_new);
return obj;
}
@@ -167,7 +171,7 @@ ossl_ocspreq_alloc(VALUE klass)
obj = NewOCSPReq(klass);
if (!(req = OCSP_REQUEST_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPReq(obj, req);
return obj;
@@ -185,7 +189,7 @@ ossl_ocspreq_initialize_copy(VALUE self, VALUE other)
req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req);
if (!req_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPReq(self, req_new);
OCSP_REQUEST_free(req_old);
@@ -211,15 +215,15 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- GetOCSPReq(self, req);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));
- if (!req_new)
- ossl_raise(eOCSPError, "d2i_OCSP_REQUEST");
- SetOCSPReq(self, req_new);
- OCSP_REQUEST_free(req);
+ GetOCSPReq(self, req);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));
+ if (!req_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_REQUEST");
+ SetOCSPReq(self, req_new);
+ OCSP_REQUEST_free(req);
}
return self;
@@ -245,13 +249,13 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &val);
if(NIL_P(val)) {
- GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, NULL, -1);
+ GetOCSPReq(self, req);
+ ret = OCSP_request_add1_nonce(req, NULL, -1);
}
else{
- StringValue(val);
- GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+ StringValue(val);
+ GetOCSPReq(self, req);
+ ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -308,10 +312,10 @@ ossl_ocspreq_add_certid(VALUE self, VALUE certid)
GetOCSPCertId(certid, id);
if (!(id_new = OCSP_CERTID_dup(id)))
- ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
if (!OCSP_request_add0_id(req, id_new)) {
- OCSP_CERTID_free(id_new);
- ossl_raise(eOCSPError, "OCSP_request_add0_id");
+ OCSP_CERTID_free(id_new);
+ ossl_raise(eOCSPError, "OCSP_request_add0_id");
}
return self;
@@ -328,21 +332,19 @@ static VALUE
ossl_ocspreq_get_certid(VALUE self)
{
OCSP_REQUEST *req;
- OCSP_ONEREQ *one;
- OCSP_CERTID *id;
- VALUE ary, tmp;
- int i, count;
GetOCSPReq(self, req);
- count = OCSP_request_onereq_count(req);
- ary = (count > 0) ? rb_ary_new() : Qnil;
- for(i = 0; i < count; i++){
- one = OCSP_request_onereq_get0(req, i);
- tmp = NewOCSPCertId(cOCSPCertId);
- if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one))))
- ossl_raise(eOCSPError, NULL);
- SetOCSPCertId(tmp, id);
- rb_ary_push(ary, tmp);
+ int count = OCSP_request_onereq_count(req);
+ if (count < 0)
+ ossl_raise(eOCSPError, "OCSP_request_onereq_count");
+ if (count == 0)
+ return Qnil;
+
+ VALUE ary = rb_ary_new_capa(count);
+ for (int i = 0; i < count; i++) {
+ OCSP_ONEREQ *one = OCSP_request_onereq_get0(req, i);
+ OCSP_CERTID *cid = OCSP_onereq_get0_id(one);
+ rb_ary_push(ary, ossl_ocspcid_new(cid));
}
return ary;
@@ -367,7 +369,7 @@ ossl_ocspreq_get_certid(VALUE self)
static VALUE
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags, digest;
+ VALUE signer_cert, signer_key, certs, flags, digest, md_holder;
OCSP_REQUEST *req;
X509 *signer;
EVP_PKEY *key;
@@ -381,19 +383,17 @@ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
if (!NIL_P(flags))
- flg = NUM2INT(flags);
- if (NIL_P(digest))
- md = NULL;
- else
- md = ossl_evp_get_digestbyname(digest);
+ flg = NUM2INT(flags);
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
if (NIL_P(certs))
- flg |= OCSP_NOCERTS;
+ flg |= OCSP_NOCERTS;
else
- x509s = ossl_x509_ary2sk(certs);
+ x509s = ossl_x509_ary2sk(certs);
ret = OCSP_request_sign(req, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if (!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret)
+ ossl_raise(eOCSPError, "OCSP_request_sign");
return self;
}
@@ -427,7 +427,7 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
result = OCSP_request_verify(req, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
if (result <= 0)
- ossl_clear_error();
+ ossl_clear_error();
return result > 0 ? Qtrue : Qfalse;
}
@@ -446,11 +446,11 @@ ossl_ocspreq_to_der(VALUE self)
GetOCSPReq(self, req);
if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_OCSP_REQUEST(req, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -494,7 +494,7 @@ ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */
obj = NewOCSPRes(klass);
if(!(res = OCSP_response_create(st, bs)))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPRes(obj, res);
return obj;
@@ -508,7 +508,7 @@ ossl_ocspres_alloc(VALUE klass)
obj = NewOCSPRes(klass);
if(!(res = OCSP_RESPONSE_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPRes(obj, res);
return obj;
@@ -526,7 +526,7 @@ ossl_ocspres_initialize_copy(VALUE self, VALUE other)
res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res);
if (!res_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPRes(self, res_new);
OCSP_RESPONSE_free(res_old);
@@ -552,15 +552,15 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- GetOCSPRes(self, res);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));
- if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE");
- SetOCSPRes(self, res_new);
- OCSP_RESPONSE_free(res);
+ GetOCSPRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));
+ if (!res_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE");
+ SetOCSPRes(self, res_new);
+ OCSP_RESPONSE_free(res);
}
return self;
@@ -621,7 +621,7 @@ ossl_ocspres_get_basic(VALUE self)
GetOCSPRes(self, res);
ret = NewOCSPBasicRes(cOCSPBasicRes);
if(!(bs = OCSP_response_get1_basic(res)))
- return Qnil;
+ return Qnil;
SetOCSPBasicRes(ret, bs);
return ret;
@@ -644,11 +644,11 @@ ossl_ocspres_to_der(VALUE self)
GetOCSPRes(self, res);
if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_OCSP_RESPONSE(res, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -665,7 +665,7 @@ ossl_ocspbres_alloc(VALUE klass)
obj = NewOCSPBasicRes(klass);
if(!(bs = OCSP_BASICRESP_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPBasicRes(obj, bs);
return obj;
@@ -683,7 +683,7 @@ ossl_ocspbres_initialize_copy(VALUE self, VALUE other)
bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);
if (!bs_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPBasicRes(self, bs_new);
OCSP_BASICRESP_free(bs_old);
@@ -708,15 +708,15 @@ ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) {
- GetOCSPBasicRes(self, res);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));
- if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
- SetOCSPBasicRes(self, res_new);
- OCSP_BASICRESP_free(res);
+ GetOCSPBasicRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));
+ if (!res_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
+ SetOCSPBasicRes(self, res_new);
+ OCSP_BASICRESP_free(res);
}
return self;
@@ -761,13 +761,13 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &val);
if(NIL_P(val)) {
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, NULL, -1);
+ GetOCSPBasicRes(self, bs);
+ ret = OCSP_basic_add1_nonce(bs, NULL, -1);
}
else{
- StringValue(val);
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+ StringValue(val);
+ GetOCSPBasicRes(self, bs);
+ ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -780,12 +780,12 @@ add_status_convert_time(VALUE obj)
ASN1_TIME *time;
if (RB_INTEGER_TYPE_P(obj))
- time = X509_gmtime_adj(NULL, NUM2INT(obj));
+ time = X509_gmtime_adj(NULL, NUM2INT(obj));
else
- time = ossl_x509_time_adjust(NULL, obj);
+ time = ossl_x509_time_adjust(NULL, obj);
if (!time)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
return (VALUE)time;
}
@@ -819,8 +819,8 @@ add_status_convert_time(VALUE obj)
*/
static VALUE
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
- VALUE reason, VALUE revtime,
- VALUE thisupd, VALUE nextupd, VALUE ext)
+ VALUE reason, VALUE revtime,
+ VALUE thisupd, VALUE nextupd, VALUE ext)
{
OCSP_BASICRESP *bs;
OCSP_SINGLERESP *single;
@@ -834,16 +834,16 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
GetOCSPCertId(cid, id);
st = NUM2INT(status);
if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */
- ext = rb_check_array_type(ext);
- for (i = 0; i < RARRAY_LEN(ext); i++)
- OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
+ ext = rb_check_array_type(ext);
+ for (i = 0; i < RARRAY_LEN(ext); i++)
+ OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
}
if (st == V_OCSP_CERTSTATUS_REVOKED) {
- rsn = NUM2INT(reason);
- tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
- if (rstatus) goto err;
- rev = (ASN1_TIME *)tmp;
+ rsn = NUM2INT(reason);
+ tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
+ if (rstatus) goto err;
+ rev = (ASN1_TIME *)tmp;
}
tmp = rb_protect(add_status_convert_time, thisupd, &rstatus);
@@ -851,29 +851,29 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
ths = (ASN1_TIME *)tmp;
if (!NIL_P(nextupd)) {
- tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
- if (rstatus) goto err;
- nxt = (ASN1_TIME *)tmp;
+ tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
+ if (rstatus) goto err;
+ nxt = (ASN1_TIME *)tmp;
}
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
- error = 1;
- goto err;
+ error = 1;
+ goto err;
}
if(!NIL_P(ext)){
- X509_EXTENSION *x509ext;
-
- for(i = 0; i < RARRAY_LEN(ext); i++){
- x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));
- if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
- error = 1;
- goto err;
- }
- }
+ X509_EXTENSION *x509ext;
+
+ for(i = 0; i < RARRAY_LEN(ext); i++){
+ x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));
+ if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
+ error = 1;
+ goto err;
+ }
+ }
}
- err:
+ err:
ASN1_TIME_free(ths);
ASN1_TIME_free(nxt);
ASN1_TIME_free(rev);
@@ -899,48 +899,40 @@ static VALUE
ossl_ocspbres_get_status(VALUE self)
{
OCSP_BASICRESP *bs;
- OCSP_SINGLERESP *single;
- OCSP_CERTID *cid;
- ASN1_TIME *revtime, *thisupd, *nextupd;
- int status, reason;
- X509_EXTENSION *x509ext;
- VALUE ret, ary, ext;
- int count, ext_count, i, j;
GetOCSPBasicRes(self, bs);
- ret = rb_ary_new();
- count = OCSP_resp_count(bs);
- for(i = 0; i < count; i++){
- single = OCSP_resp_get0(bs, i);
- if(!single) continue;
-
- revtime = thisupd = nextupd = NULL;
- status = OCSP_single_get0_status(single, &reason, &revtime,
- &thisupd, &nextupd);
- if(status < 0) continue;
- if(!(cid = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(single)))) /* FIXME */
- ossl_raise(eOCSPError, NULL);
- ary = rb_ary_new();
- rb_ary_push(ary, ossl_ocspcertid_new(cid));
- rb_ary_push(ary, INT2NUM(status));
- rb_ary_push(ary, INT2NUM(reason));
- rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
- rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
- rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
- ext = rb_ary_new();
- ext_count = OCSP_SINGLERESP_get_ext_count(single);
- for(j = 0; j < ext_count; j++){
- x509ext = OCSP_SINGLERESP_get_ext(single, j);
- rb_ary_push(ext, ossl_x509ext_new(x509ext));
- }
- rb_ary_push(ary, ext);
- rb_ary_push(ret, ary);
+ VALUE ret = rb_ary_new();
+ int count = OCSP_resp_count(bs);
+ for (int i = 0; i < count; i++) {
+ OCSP_SINGLERESP *single = OCSP_resp_get0(bs, i);
+ ASN1_TIME *revtime = NULL, *thisupd = NULL, *nextupd = NULL;
+ int reason = -1;
+
+ int status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+ VALUE ary = rb_ary_new();
+ rb_ary_push(ary, ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(single)));
+ rb_ary_push(ary, INT2NUM(status));
+ rb_ary_push(ary, INT2NUM(reason));
+ rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
+ rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
+ rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
+ VALUE ext = rb_ary_new();
+ int ext_count = OCSP_SINGLERESP_get_ext_count(single);
+ for (int j = 0; j < ext_count; j++) {
+ const X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j);
+ rb_ary_push(ext, ossl_x509ext_new(x509ext));
+ }
+ rb_ary_push(ary, ext);
+ rb_ary_push(ret, ary);
}
return ret;
}
-static VALUE ossl_ocspsres_new(OCSP_SINGLERESP *);
+static VALUE ossl_ocspsres_new(const OCSP_SINGLERESP *);
/*
* call-seq:
@@ -958,17 +950,10 @@ ossl_ocspbres_get_responses(VALUE self)
GetOCSPBasicRes(self, bs);
count = OCSP_resp_count(bs);
- ret = rb_ary_new2(count);
+ ret = rb_ary_new_capa(count);
for (i = 0; i < count; i++) {
- OCSP_SINGLERESP *sres, *sres_new;
-
- sres = OCSP_resp_get0(bs, i);
- sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
- if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
-
- rb_ary_push(ret, ossl_ocspsres_new(sres_new));
+ rb_ary_push(ret, ossl_ocspsres_new(OCSP_resp_get0(bs, i)));
}
return ret;
@@ -986,7 +971,6 @@ static VALUE
ossl_ocspbres_find_response(VALUE self, VALUE target)
{
OCSP_BASICRESP *bs;
- OCSP_SINGLERESP *sres, *sres_new;
OCSP_CERTID *id;
int n;
@@ -994,14 +978,8 @@ ossl_ocspbres_find_response(VALUE self, VALUE target)
GetOCSPBasicRes(self, bs);
if ((n = OCSP_resp_find(bs, id, -1)) == -1)
- return Qnil;
-
- sres = OCSP_resp_get0(bs, n);
- sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
- if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
-
- return ossl_ocspsres_new(sres_new);
+ return Qnil;
+ return ossl_ocspsres_new(OCSP_resp_get0(bs, n));
}
/*
@@ -1020,7 +998,7 @@ ossl_ocspbres_find_response(VALUE self, VALUE target)
static VALUE
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags, digest;
+ VALUE signer_cert, signer_key, certs, flags, digest, md_holder;
OCSP_BASICRESP *bs;
X509 *signer;
EVP_PKEY *key;
@@ -1034,19 +1012,17 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
if (!NIL_P(flags))
- flg = NUM2INT(flags);
- if (NIL_P(digest))
- md = NULL;
- else
- md = ossl_evp_get_digestbyname(digest);
+ flg = NUM2INT(flags);
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
if (NIL_P(certs))
- flg |= OCSP_NOCERTS;
+ flg |= OCSP_NOCERTS;
else
- x509s = ossl_x509_ary2sk(certs);
+ x509s = ossl_x509_ary2sk(certs);
ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if (!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret)
+ ossl_raise(eOCSPError, "OCSP_basic_sign");
return self;
}
@@ -1075,7 +1051,7 @@ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
result = OCSP_basic_verify(bs, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
if (result <= 0)
- ossl_clear_error();
+ ossl_clear_error();
return result > 0 ? Qtrue : Qfalse;
}
@@ -1096,11 +1072,11 @@ ossl_ocspbres_to_der(VALUE self)
GetOCSPBasicRes(self, res);
if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_BASICRESP(res, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1110,12 +1086,18 @@ ossl_ocspbres_to_der(VALUE self)
* OCSP::SingleResponse
*/
static VALUE
-ossl_ocspsres_new(OCSP_SINGLERESP *sres)
+ossl_ocspsres_new(const OCSP_SINGLERESP *sres)
{
VALUE obj;
+ OCSP_SINGLERESP *sres_new;
obj = NewOCSPSingleRes(cOCSPSingleRes);
- SetOCSPSingleRes(obj, sres);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP),
+ (OCSP_SINGLERESP *)sres);
+ if (!sres_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+ SetOCSPSingleRes(obj, sres_new);
return obj;
}
@@ -1128,7 +1110,7 @@ ossl_ocspsres_alloc(VALUE klass)
obj = NewOCSPSingleRes(klass);
if (!(sres = OCSP_SINGLERESP_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPSingleRes(obj, sres);
return obj;
@@ -1153,7 +1135,7 @@ ossl_ocspsres_initialize(VALUE self, VALUE arg)
p = (unsigned char*)RSTRING_PTR(arg);
res_new = d2i_OCSP_SINGLERESP(NULL, &p, RSTRING_LEN(arg));
if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
+ ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
SetOCSPSingleRes(self, res_new);
OCSP_SINGLERESP_free(res);
@@ -1172,7 +1154,7 @@ ossl_ocspsres_initialize_copy(VALUE self, VALUE other)
sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPSingleRes(self, sres_new);
OCSP_SINGLERESP_free(sres_old);
@@ -1211,15 +1193,15 @@ ossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
ret = OCSP_check_validity(this_update, next_update, nsec, maxsec);
if (ret)
- return Qtrue;
+ return Qtrue;
else {
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
}
}
@@ -1233,12 +1215,9 @@ static VALUE
ossl_ocspsres_get_certid(VALUE self)
{
OCSP_SINGLERESP *sres;
- OCSP_CERTID *id;
GetOCSPSingleRes(self, sres);
- id = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sres)); /* FIXME */
-
- return ossl_ocspcertid_new(id);
+ return ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(sres));
}
/*
@@ -1264,7 +1243,7 @@ ossl_ocspsres_get_cert_status(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
return INT2NUM(status);
}
@@ -1283,9 +1262,9 @@ ossl_ocspsres_get_this_update(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1304,9 +1283,9 @@ ossl_ocspsres_get_next_update(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1325,11 +1304,11 @@ ossl_ocspsres_get_revocation_time(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (status != V_OCSP_CERTSTATUS_REVOKED)
- ossl_raise(eOCSPError, "certificate is not revoked");
+ ossl_raise(eOCSPError, "certificate is not revoked");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1347,9 +1326,9 @@ ossl_ocspsres_get_revocation_reason(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (status != V_OCSP_CERTSTATUS_REVOKED)
- ossl_raise(eOCSPError, "certificate is not revoked");
+ ossl_raise(eOCSPError, "certificate is not revoked");
return INT2NUM(reason);
}
@@ -1362,7 +1341,6 @@ static VALUE
ossl_ocspsres_get_extensions(VALUE self)
{
OCSP_SINGLERESP *sres;
- X509_EXTENSION *ext;
int count, i;
VALUE ary;
@@ -1371,8 +1349,8 @@ ossl_ocspsres_get_extensions(VALUE self)
count = OCSP_SINGLERESP_get_ext_count(sres);
ary = rb_ary_new2(count);
for (i = 0; i < count; i++) {
- ext = OCSP_SINGLERESP_get_ext(sres, i);
- rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
+ const X509_EXTENSION *ext = OCSP_SINGLERESP_get_ext(sres, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
}
return ary;
@@ -1394,11 +1372,11 @@ ossl_ocspsres_to_der(VALUE self)
GetOCSPSingleRes(self, sres);
if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_SINGLERESP(sres, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1416,7 +1394,7 @@ ossl_ocspcid_alloc(VALUE klass)
obj = NewOCSPCertId(klass);
if(!(id = OCSP_CERTID_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPCertId(obj, id);
return obj;
@@ -1434,7 +1412,7 @@ ossl_ocspcid_initialize_copy(VALUE self, VALUE other)
cid_new = OCSP_CERTID_dup(cid);
if (!cid_new)
- ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
SetOCSPCertId(self, cid_new);
OCSP_CERTID_free(cid_old);
@@ -1464,27 +1442,28 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
GetOCSPCertId(self, id);
if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) {
- VALUE arg;
- const unsigned char *p;
-
- arg = ossl_to_der_if_possible(subject);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));
- if (!newid)
- ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
+ VALUE arg;
+ const unsigned char *p;
+
+ arg = ossl_to_der_if_possible(subject);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));
+ if (!newid)
+ ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
}
else {
- X509 *x509s, *x509i;
- const EVP_MD *md;
+ X509 *x509s, *x509i;
+ const EVP_MD *md;
+ VALUE md_holder;
- x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
- x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
- md = !NIL_P(digest) ? ossl_evp_get_digestbyname(digest) : NULL;
+ x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
+ x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
- newid = OCSP_cert_to_id(md, x509s, x509i);
- if (!newid)
- ossl_raise(eOCSPError, "OCSP_cert_to_id");
+ newid = OCSP_cert_to_id(md, x509s, x509i);
+ if (!newid)
+ ossl_raise(eOCSPError, "OCSP_cert_to_id");
}
SetOCSPCertId(self, newid);
@@ -1570,8 +1549,9 @@ ossl_ocspcid_get_issuer_name_hash(VALUE self)
GetOCSPCertId(self, id);
OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id);
- ret = rb_str_new(NULL, name_hash->length * 2);
- ossl_bin2hex(name_hash->data, RSTRING_PTR(ret), name_hash->length);
+ ret = rb_str_new(NULL, ASN1_STRING_length(name_hash) * 2);
+ ossl_bin2hex(ASN1_STRING_get0_data(name_hash), RSTRING_PTR(ret),
+ ASN1_STRING_length(name_hash));
return ret;
}
@@ -1593,8 +1573,9 @@ ossl_ocspcid_get_issuer_key_hash(VALUE self)
GetOCSPCertId(self, id);
OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id);
- ret = rb_str_new(NULL, key_hash->length * 2);
- ossl_bin2hex(key_hash->data, RSTRING_PTR(ret), key_hash->length);
+ ret = rb_str_new(NULL, ASN1_STRING_length(key_hash) * 2);
+ ossl_bin2hex(ASN1_STRING_get0_data(key_hash), RSTRING_PTR(ret),
+ ASN1_STRING_length(key_hash));
return ret;
}
@@ -1611,19 +1592,10 @@ ossl_ocspcid_get_hash_algorithm(VALUE self)
{
OCSP_CERTID *id;
ASN1_OBJECT *oid;
- BIO *out;
GetOCSPCertId(self, id);
OCSP_id_get0_info(NULL, &oid, NULL, NULL, id);
-
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eOCSPError, "BIO_new");
-
- if (!i2a_ASN1_OBJECT(out, oid)) {
- BIO_free(out);
- ossl_raise(eOCSPError, "i2a_ASN1_OBJECT");
- }
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(oid);
}
/*
@@ -1642,11 +1614,11 @@ ossl_ocspcid_to_der(VALUE self)
GetOCSPCertId(self, id);
if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_CERTID(id, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1655,11 +1627,6 @@ ossl_ocspcid_to_der(VALUE self)
void
Init_ossl_ocsp(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* OpenSSL::OCSP implements Online Certificate Status Protocol requests
* and responses.
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c
index be09eb2071..a47c81354c 100644
--- a/ext/openssl/ossl_pkcs12.c
+++ b/ext/openssl/ossl_pkcs12.c
@@ -42,7 +42,7 @@ ossl_pkcs12_free(void *ptr)
static const rb_data_type_t ossl_pkcs12_type = {
"OpenSSL/PKCS12",
{
- 0, ossl_pkcs12_free,
+ 0, ossl_pkcs12_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -72,7 +72,7 @@ ossl_pkcs12_initialize_copy(VALUE self, VALUE other)
p12_new = ASN1_dup((i2d_of_void *)i2d_PKCS12, (d2i_of_void *)d2i_PKCS12, (char *)p12);
if (!p12_new)
- ossl_raise(ePKCS12Error, "ASN1_dup");
+ ossl_raise(ePKCS12Error, "ASN1_dup");
SetPKCS12(self, p12_new);
PKCS12_free(p12_old);
@@ -122,11 +122,11 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
/* TODO: make a VALUE to nid function */
if (!NIL_P(key_nid)) {
if ((nkey = OBJ_txt2nid(StringValueCStr(key_nid))) == NID_undef)
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid);
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid);
}
if (!NIL_P(cert_nid)) {
if ((ncert = OBJ_txt2nid(StringValueCStr(cert_nid))) == NID_undef)
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid);
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid);
}
if (!NIL_P(key_iter))
kiter = NUM2INT(key_iter);
@@ -161,9 +161,9 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
}
static VALUE
-ossl_pkey_new_i(VALUE arg)
+ossl_pkey_wrap_i(VALUE arg)
{
- return ossl_pkey_new((EVP_PKEY *)arg);
+ return ossl_pkey_wrap((EVP_PKEY *)arg);
}
static VALUE
@@ -191,6 +191,7 @@ ossl_x509_sk2ary_i(VALUE arg)
static VALUE
ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
{
+ PKCS12 *p12, *p12_orig = DATA_PTR(self);
BIO *in;
VALUE arg, pass, pkey, cert, ca;
char *passphrase;
@@ -198,29 +199,31 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
X509 *x509;
STACK_OF(X509) *x509s = NULL;
int st = 0;
- PKCS12 *pkcs = DATA_PTR(self);
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self;
passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass);
in = ossl_obj2bio(&arg);
- d2i_PKCS12_bio(in, &pkcs);
- DATA_PTR(self) = pkcs;
+ p12 = d2i_PKCS12_bio(in, NULL);
BIO_free(in);
+ if (!p12)
+ ossl_raise(ePKCS12Error, "d2i_PKCS12_bio");
+ PKCS12_free(p12_orig);
+ RTYPEDDATA_DATA(self) = p12;
pkey = cert = ca = Qnil;
- if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s))
- ossl_raise(ePKCS12Error, "PKCS12_parse");
+ if (!PKCS12_parse(p12, passphrase, &key, &x509, &x509s))
+ ossl_raise(ePKCS12Error, "PKCS12_parse");
if (key) {
- pkey = rb_protect(ossl_pkey_new_i, (VALUE)key, &st);
- if (st) goto err;
+ pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st);
+ if (st) goto err;
}
if (x509) {
- cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);
- if (st) goto err;
+ cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);
+ if (st) goto err;
}
if (x509s) {
- ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);
- if (st) goto err;
+ ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);
+ if (st) goto err;
}
err:
@@ -244,11 +247,11 @@ ossl_pkcs12_to_der(VALUE self)
GetPKCS12(self, p12);
if((len = i2d_PKCS12(p12, NULL)) <= 0)
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_PKCS12(p12, &p) <= 0)
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, NULL);
ossl_str_adjust(str, p);
return str;
@@ -271,7 +274,7 @@ static VALUE
pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
{
PKCS12 *p12;
- VALUE pass, salt, iter, md_name;
+ VALUE pass, salt, iter, md_name, md_holder = Qnil;
int iter_i = 0;
const EVP_MD *md_type = NULL;
@@ -285,7 +288,7 @@ pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
if (!NIL_P(iter))
iter_i = NUM2INT(iter);
if (!NIL_P(md_name))
- md_type = ossl_evp_get_digestbyname(md_name);
+ md_type = ossl_evp_md_fetch(md_name, &md_holder);
if (!PKCS12_set_mac(p12, RSTRING_PTR(pass), RSTRING_LENINT(pass),
!NIL_P(salt) ? (unsigned char *)RSTRING_PTR(salt) : NULL,
@@ -300,11 +303,6 @@ void
Init_ossl_pkcs12(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Defines a file format commonly used to store private keys with
* accompanying public key certificates, protected with a password-based
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index 4d719c96da..44e8cb305b 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -28,14 +28,14 @@
TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, 0)
#define SetPKCS7si(obj, p7si) do { \
if (!(p7si)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (p7si); \
} while (0)
#define GetPKCS7si(obj, p7si) do { \
TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \
if (!(p7si)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
} \
} while (0)
@@ -43,14 +43,14 @@
TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, 0)
#define SetPKCS7ri(obj, p7ri) do { \
if (!(p7ri)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (p7ri); \
} while (0)
#define GetPKCS7ri(obj, p7ri) do { \
TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \
if (!(p7ri)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
} \
} while (0)
@@ -68,6 +68,7 @@ static VALUE cPKCS7;
static VALUE cPKCS7Signer;
static VALUE cPKCS7Recipient;
static VALUE ePKCS7Error;
+static ID id_md_holder, id_cipher_holder;
static void
ossl_pkcs7_free(void *ptr)
@@ -78,7 +79,7 @@ ossl_pkcs7_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_type = {
"OpenSSL/PKCS7",
{
- 0, ossl_pkcs7_free,
+ 0, ossl_pkcs7_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -106,7 +107,7 @@ ossl_pkcs7_signer_info_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_signer_info_type = {
"OpenSSL/PKCS7/SIGNER_INFO",
{
- 0, ossl_pkcs7_signer_info_free,
+ 0, ossl_pkcs7_signer_info_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -120,7 +121,7 @@ ossl_pkcs7_recip_info_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_recip_info_type = {
"OpenSSL/PKCS7/RECIP_INFO",
{
- 0, ossl_pkcs7_recip_info_free,
+ 0, ossl_pkcs7_recip_info_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -143,23 +144,32 @@ ossl_PKCS7_SIGNER_INFO_dup(PKCS7_SIGNER_INFO *si)
}
static PKCS7_RECIP_INFO *
-ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *si)
+ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *ri)
{
- return ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
- (d2i_of_void *)d2i_PKCS7_RECIP_INFO,
- si);
+ PKCS7_RECIP_INFO *ri_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
+ (d2i_of_void *)d2i_PKCS7_RECIP_INFO,
+ ri);
+ if (ri_new && ri->cert) {
+ if (!X509_up_ref(ri->cert)) {
+ PKCS7_RECIP_INFO_free(ri_new);
+ return NULL;
+ }
+ ri_new->cert = ri->cert;
+ }
+ return ri_new;
}
static VALUE
ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
{
- PKCS7_SIGNER_INFO *pkcs7;
+ PKCS7_SIGNER_INFO *p7si_new;
VALUE obj;
obj = NewPKCS7si(cPKCS7Signer);
- pkcs7 = p7si ? ossl_PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new();
- if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
- SetPKCS7si(obj, pkcs7);
+ p7si_new = ossl_PKCS7_SIGNER_INFO_dup(p7si);
+ if (!p7si_new)
+ ossl_raise(ePKCS7Error, "ASN1_dup");
+ SetPKCS7si(obj, p7si_new);
return obj;
}
@@ -167,13 +177,14 @@ ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
static VALUE
ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)
{
- PKCS7_RECIP_INFO *pkcs7;
+ PKCS7_RECIP_INFO *p7ri_new;
VALUE obj;
obj = NewPKCS7ri(cPKCS7Recipient);
- pkcs7 = p7ri ? ossl_PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new();
- if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
- SetPKCS7ri(obj, pkcs7);
+ p7ri_new = ossl_PKCS7_RECIP_INFO_dup(p7ri);
+ if (!p7ri_new)
+ ossl_raise(ePKCS7Error,"ASN1_dup");
+ SetPKCS7ri(obj, p7ri_new);
return obj;
}
@@ -227,7 +238,7 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
GetPKCS7(pkcs7, p7);
if(!NIL_P(data) && PKCS7_is_detached(p7))
- flg |= PKCS7_DETACHED;
+ flg |= PKCS7_DETACHED;
in = NIL_P(data) ? NULL : ossl_obj2bio(&data);
if(!(out = BIO_new(BIO_s_mem()))){
BIO_free(in);
@@ -268,16 +279,16 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
in = ossl_obj2bio(&data);
if(NIL_P(certs)) x509s = NULL;
else{
- x509s = ossl_protect_x509_ary2sk(certs, &status);
- if(status){
- BIO_free(in);
- rb_jump_tag(status);
- }
+ x509s = ossl_protect_x509_ary2sk(certs, &status);
+ if(status){
+ BIO_free(in);
+ rb_jump_tag(status);
+ }
}
if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7(ret, pkcs7);
ossl_pkcs7_set_data(ret, data);
@@ -302,7 +313,7 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
static VALUE
ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
{
- VALUE certs, data, cipher, flags;
+ VALUE certs, data, cipher, flags, cipher_holder;
STACK_OF(X509) *x509s;
BIO *in;
const EVP_CIPHER *ciph;
@@ -316,23 +327,24 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
"cipher must be specified. Before version 3.3, " \
"the default cipher was RC2-40-CBC.");
}
- ciph = ossl_evp_get_cipherbyname(cipher);
+ ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
ret = NewPKCS7(cPKCS7);
in = ossl_obj2bio(&data);
x509s = ossl_protect_x509_ary2sk(certs, &status);
if(status){
- BIO_free(in);
- rb_jump_tag(status);
+ BIO_free(in);
+ rb_jump_tag(status);
}
if (!(p7 = PKCS7_encrypt(x509s, in, ciph, flg))) {
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
BIO_free(in);
SetPKCS7(ret, p7);
ossl_pkcs7_set_data(ret, data);
+ rb_ivar_set(ret, id_cipher_holder, cipher_holder);
sk_X509_pop_free(x509s, X509_free);
return ret;
@@ -346,7 +358,7 @@ ossl_pkcs7_alloc(VALUE klass)
obj = NewPKCS7(klass);
if (!(pkcs7 = PKCS7_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7(obj, pkcs7);
@@ -368,7 +380,7 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
VALUE arg;
if(rb_scan_args(argc, argv, "01", &arg) == 0)
- return self;
+ return self;
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
p7 = d2i_PKCS7_bio(in, NULL);
@@ -378,10 +390,10 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
}
BIO_free(in);
if (!p7)
- ossl_raise(rb_eArgError, "Could not parse the PKCS7");
+ ossl_raise(ePKCS7Error, "Could not parse the PKCS7");
if (!p7->d.ptr) {
PKCS7_free(p7);
- ossl_raise(rb_eArgError, "No content in PKCS7");
+ ossl_raise(ePKCS7Error, "No content in PKCS7");
}
RTYPEDDATA_DATA(self) = p7;
@@ -406,7 +418,7 @@ ossl_pkcs7_copy(VALUE self, VALUE other)
pkcs7 = PKCS7_dup(b);
if (!pkcs7) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
DATA_PTR(self) = pkcs7;
PKCS7_free(a);
@@ -438,13 +450,13 @@ ossl_pkcs7_sym2typeid(VALUE sym)
RSTRING_GETMEM(sym, s, l);
for(i = 0; ; i++){
- if(i == numberof(p7_type_tab))
- ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym);
- if(strlen(p7_type_tab[i].name) != l) continue;
- if(strcmp(p7_type_tab[i].name, s) == 0){
- ret = p7_type_tab[i].nid;
- break;
- }
+ if(i == numberof(p7_type_tab))
+ ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym);
+ if(strlen(p7_type_tab[i].name) != l) continue;
+ if(memcmp(p7_type_tab[i].name, s, l) == 0){
+ ret = p7_type_tab[i].nid;
+ break;
+ }
}
return ret;
@@ -461,7 +473,7 @@ ossl_pkcs7_set_type(VALUE self, VALUE type)
GetPKCS7(self, p7);
if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
return type;
}
@@ -477,15 +489,15 @@ ossl_pkcs7_get_type(VALUE self)
GetPKCS7(self, p7);
if(PKCS7_type_is_signed(p7))
- return ID2SYM(rb_intern("signed"));
+ return ID2SYM(rb_intern("signed"));
if(PKCS7_type_is_encrypted(p7))
- return ID2SYM(rb_intern("encrypted"));
+ return ID2SYM(rb_intern("encrypted"));
if(PKCS7_type_is_enveloped(p7))
- return ID2SYM(rb_intern("enveloped"));
+ return ID2SYM(rb_intern("enveloped"));
if(PKCS7_type_is_signedAndEnveloped(p7))
- return ID2SYM(rb_intern("signedAndEnveloped"));
+ return ID2SYM(rb_intern("signedAndEnveloped"));
if(PKCS7_type_is_data(p7))
- return ID2SYM(rb_intern("data"));
+ return ID2SYM(rb_intern("data"));
return Qnil;
}
@@ -496,9 +508,9 @@ ossl_pkcs7_set_detached(VALUE self, VALUE flag)
GetPKCS7(self, p7);
if(flag != Qtrue && flag != Qfalse)
- ossl_raise(ePKCS7Error, "must specify a boolean");
+ ossl_raise(ePKCS7Error, "must specify a boolean");
if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
return flag;
}
@@ -508,6 +520,8 @@ ossl_pkcs7_get_detached(VALUE self)
{
PKCS7 *p7;
GetPKCS7(self, p7);
+ if (!PKCS7_type_is_signed(p7))
+ return Qfalse;
return PKCS7_get_detached(p7) ? Qtrue : Qfalse;
}
@@ -523,11 +537,14 @@ static VALUE
ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
{
PKCS7 *pkcs7;
+ const EVP_CIPHER *ciph;
+ VALUE cipher_holder;
GetPKCS7(self, pkcs7);
- if (!PKCS7_set_cipher(pkcs7, ossl_evp_get_cipherbyname(cipher))) {
- ossl_raise(ePKCS7Error, NULL);
- }
+ ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ if (!PKCS7_set_cipher(pkcs7, ciph))
+ ossl_raise(ePKCS7Error, "PKCS7_set_cipher");
+ rb_ivar_set(self, id_cipher_holder, cipher_holder);
return cipher;
}
@@ -567,8 +584,8 @@ ossl_pkcs7_get_signer(VALUE self)
num = sk_PKCS7_SIGNER_INFO_num(sk);
ary = rb_ary_new_capa(num);
for (i=0; i<num; i++) {
- PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
- rb_ary_push(ary, ossl_pkcs7si_new(si));
+ PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+ rb_ary_push(ary, ossl_pkcs7si_new(si));
}
return ary;
@@ -605,9 +622,9 @@ ossl_pkcs7_get_recipient(VALUE self)
GetPKCS7(self, pkcs7);
if (PKCS7_type_is_enveloped(pkcs7))
- sk = pkcs7->d.enveloped->recipientinfo;
+ sk = pkcs7->d.enveloped->recipientinfo;
else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
- sk = pkcs7->d.signed_and_enveloped->recipientinfo;
+ sk = pkcs7->d.signed_and_enveloped->recipientinfo;
else sk = NULL;
if (!sk) return rb_ary_new();
num = sk_PKCS7_RECIP_INFO_num(sk);
@@ -629,7 +646,7 @@ ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
GetPKCS7(self, pkcs7);
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
if (!PKCS7_add_certificate(pkcs7, x509)){
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -645,13 +662,13 @@ pkcs7_get_certs(VALUE self)
GetPKCS7(self, pkcs7);
i = OBJ_obj2nid(pkcs7->type);
switch(i){
- case NID_pkcs7_signed:
+ case NID_pkcs7_signed:
certs = pkcs7->d.sign->cert;
break;
- case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_signedAndEnveloped:
certs = pkcs7->d.signed_and_enveloped->cert;
break;
- default:
+ default:
certs = NULL;
}
@@ -668,13 +685,13 @@ pkcs7_get_crls(VALUE self)
GetPKCS7(self, pkcs7);
i = OBJ_obj2nid(pkcs7->type);
switch(i){
- case NID_pkcs7_signed:
+ case NID_pkcs7_signed:
crls = pkcs7->d.sign->crl;
break;
- case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_signedAndEnveloped:
crls = pkcs7->d.signed_and_enveloped->crl;
break;
- default:
+ default:
crls = NULL;
}
@@ -721,7 +738,7 @@ ossl_pkcs7_add_crl(VALUE self, VALUE crl)
GetPKCS7(self, pkcs7); /* NO DUP needed! */
x509crl = GetX509CRLPtr(crl);
if (!PKCS7_add_crl(pkcs7, x509crl)) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -768,7 +785,6 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
BIO *in, *out;
PKCS7 *p7;
VALUE data;
- const char *msg;
GetPKCS7(self, p7);
rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
@@ -778,28 +794,30 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
in = NIL_P(indata) ? NULL : ossl_obj2bio(&indata);
if(NIL_P(certs)) x509s = NULL;
else{
- x509s = ossl_protect_x509_ary2sk(certs, &status);
- if(status){
- BIO_free(in);
- rb_jump_tag(status);
- }
+ x509s = ossl_protect_x509_ary2sk(certs, &status);
+ if(status){
+ BIO_free(in);
+ rb_jump_tag(status);
+ }
}
if(!(out = BIO_new(BIO_s_mem()))){
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
BIO_free(in);
sk_X509_pop_free(x509s, X509_free);
- if (ok < 0) ossl_raise(ePKCS7Error, "PKCS7_verify");
- msg = ERR_reason_error_string(ERR_peek_error());
- ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
- ossl_clear_error();
data = ossl_membio2str(out);
ossl_pkcs7_set_data(self, data);
-
- return (ok == 1) ? Qtrue : Qfalse;
+ if (ok != 1) {
+ const char *msg = ERR_reason_error_string(ERR_peek_error());
+ ossl_pkcs7_set_err_string(self, msg ? rb_str_new_cstr(msg) : Qnil);
+ ossl_clear_error();
+ return Qfalse;
+ }
+ ossl_pkcs7_set_err_string(self, Qnil);
+ return Qtrue;
}
static VALUE
@@ -819,10 +837,10 @@ ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
GetPKCS7(self, p7);
if(!(out = BIO_new(BIO_s_mem())))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
if(!PKCS7_decrypt(p7, key, x509, out, flg)){
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
}
str = ossl_membio2str(out); /* out will be free */
@@ -835,30 +853,38 @@ ossl_pkcs7_add_data(VALUE self, VALUE data)
PKCS7 *pkcs7;
BIO *out, *in;
char buf[4096];
- int len;
+ int len, ret;
GetPKCS7(self, pkcs7);
- if(PKCS7_type_is_signed(pkcs7)){
- if(!PKCS7_content_new(pkcs7, NID_pkcs7_data))
- ossl_raise(ePKCS7Error, NULL);
+ if (PKCS7_type_is_signed(pkcs7)) {
+ if (!PKCS7_content_new(pkcs7, NID_pkcs7_data))
+ ossl_raise(ePKCS7Error, "PKCS7_content_new");
}
in = ossl_obj2bio(&data);
- if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err;
- for(;;){
- if((len = BIO_read(in, buf, sizeof(buf))) <= 0)
- break;
- if(BIO_write(out, buf, len) != len)
- goto err;
+ if (!(out = PKCS7_dataInit(pkcs7, NULL))) {
+ BIO_free(in);
+ ossl_raise(ePKCS7Error, "PKCS7_dataInit");
}
- if(!PKCS7_dataFinal(pkcs7, out)) goto err;
- ossl_pkcs7_set_data(self, Qnil);
-
- err:
+ for (;;) {
+ if ((len = BIO_read(in, buf, sizeof(buf))) <= 0)
+ break;
+ if (BIO_write(out, buf, len) != len) {
+ BIO_free_all(out);
+ BIO_free(in);
+ ossl_raise(ePKCS7Error, "BIO_write");
+ }
+ }
+ if (BIO_flush(out) <= 0) {
+ BIO_free_all(out);
+ BIO_free(in);
+ ossl_raise(ePKCS7Error, "BIO_flush");
+ }
+ ret = PKCS7_dataFinal(pkcs7, out);
BIO_free_all(out);
BIO_free(in);
- if(ERR_peek_error()){
- ossl_raise(ePKCS7Error, NULL);
- }
+ if (!ret)
+ ossl_raise(ePKCS7Error, "PKCS7_dataFinal");
+ ossl_pkcs7_set_data(self, Qnil);
return data;
}
@@ -873,11 +899,11 @@ ossl_pkcs7_to_der(VALUE self)
GetPKCS7(self, pkcs7);
if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_PKCS7(pkcs7, &p) <= 0)
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
ossl_str_adjust(str, p);
return str;
@@ -911,11 +937,11 @@ ossl_pkcs7_to_pem(VALUE self)
GetPKCS7(self, pkcs7);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
if (!PEM_write_bio_PKCS7(out, pkcs7)) {
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
}
str = ossl_membio2str(out);
@@ -933,7 +959,7 @@ ossl_pkcs7si_alloc(VALUE klass)
obj = NewPKCS7si(klass);
if (!(p7si = PKCS7_SIGNER_INFO_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7si(obj, p7si);
@@ -947,14 +973,15 @@ ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
EVP_PKEY *pkey;
X509 *x509;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
GetPKCS7si(self, p7si);
- if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md))) {
- ossl_raise(ePKCS7Error, NULL);
- }
+ if (PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md) <= 0)
+ ossl_raise(ePKCS7Error, "PKCS7_SIGNER_INFO_set");
+ rb_ivar_set(self, id_md_holder, md_holder);
return self;
}
@@ -983,15 +1010,15 @@ static VALUE
ossl_pkcs7si_get_signed_time(VALUE self)
{
PKCS7_SIGNER_INFO *p7si;
- ASN1_TYPE *asn1obj;
+ const ASN1_TYPE *asn1obj;
GetPKCS7si(self, p7si);
if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
if (asn1obj->type == V_ASN1_UTCTIME) {
- return asn1time_to_time(asn1obj->value.utctime);
+ return asn1time_to_time(asn1obj->value.utctime);
}
/*
* OR
@@ -1013,7 +1040,7 @@ ossl_pkcs7ri_alloc(VALUE klass)
obj = NewPKCS7ri(klass);
if (!(p7ri = PKCS7_RECIP_INFO_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7ri(obj, p7ri);
@@ -1028,8 +1055,8 @@ ossl_pkcs7ri_initialize(VALUE self, VALUE cert)
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
GetPKCS7ri(self, p7ri);
- if (!PKCS7_RECIP_INFO_set(p7ri, x509)) {
- ossl_raise(ePKCS7Error, NULL);
+ if (PKCS7_RECIP_INFO_set(p7ri, x509) <= 0) {
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -1072,11 +1099,6 @@ void
Init_ossl_pkcs7(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
@@ -1140,4 +1162,7 @@ Init_ossl_pkcs7(void)
DefPKCS7Const(BINARY);
DefPKCS7Const(NOATTR);
DefPKCS7Const(NOSMIMECAP);
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
+ id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index dc83255f0e..a53332b17e 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -33,13 +33,13 @@ ossl_evp_pkey_free(void *ptr)
const rb_data_type_t ossl_evp_pkey_type = {
"OpenSSL/EVP_PKEY",
{
- 0, ossl_evp_pkey_free,
+ 0, ossl_evp_pkey_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
-pkey_new0(VALUE arg)
+pkey_wrap0(VALUE arg)
{
EVP_PKEY *pkey = (EVP_PKEY *)arg;
VALUE klass, obj;
@@ -65,15 +65,15 @@ pkey_new0(VALUE arg)
}
VALUE
-ossl_pkey_new(EVP_PKEY *pkey)
+ossl_pkey_wrap(EVP_PKEY *pkey)
{
VALUE obj;
int status;
- obj = rb_protect(pkey_new0, (VALUE)pkey, &status);
+ obj = rb_protect(pkey_wrap0, (VALUE)pkey, &status);
if (status) {
- EVP_PKEY_free(pkey);
- rb_jump_tag(status);
+ EVP_PKEY_free(pkey);
+ rb_jump_tag(status);
}
return obj;
@@ -94,7 +94,8 @@ ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
selection, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
+ if (selection == EVP_PKEY_KEYPAIR &&
+ OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
ppass) != 1)
goto out;
while (1) {
@@ -187,23 +188,23 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
EVP_PKEY *pkey;
if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
/* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
- goto out;
+ goto out;
out:
return pkey;
@@ -238,8 +239,8 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
BIO_free(bio);
if (!pkey)
- ossl_raise(ePKeyError, "Could not parse PKey");
- return ossl_pkey_new(pkey);
+ ossl_raise(ePKeyError, "Could not parse PKey");
+ return ossl_pkey_wrap(pkey);
}
static VALUE
@@ -443,7 +444,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
}
}
- return ossl_pkey_new(gen_arg.pkey);
+ return ossl_pkey_wrap(gen_arg.pkey);
}
/*
@@ -507,7 +508,7 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
void
ossl_pkey_check_public_key(const EVP_PKEY *pkey)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
if (EVP_PKEY_missing_parameters(pkey))
ossl_raise(ePKeyError, "parameters missing");
#else
@@ -515,34 +516,34 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
const BIGNUM *n, *e, *pubkey;
if (EVP_PKEY_missing_parameters(pkey))
- ossl_raise(ePKeyError, "parameters missing");
+ ossl_raise(ePKeyError, "parameters missing");
ptr = EVP_PKEY_get0(pkey);
switch (EVP_PKEY_base_id(pkey)) {
case EVP_PKEY_RSA:
- RSA_get0_key(ptr, &n, &e, NULL);
- if (n && e)
- return;
- break;
+ RSA_get0_key(ptr, &n, &e, NULL);
+ if (n && e)
+ return;
+ break;
case EVP_PKEY_DSA:
- DSA_get0_key(ptr, &pubkey, NULL);
- if (pubkey)
- return;
- break;
+ DSA_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
case EVP_PKEY_DH:
- DH_get0_key(ptr, &pubkey, NULL);
- if (pubkey)
- return;
- break;
+ DH_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
#if !defined(OPENSSL_NO_EC)
case EVP_PKEY_EC:
- if (EC_KEY_get0_public_key(ptr))
- return;
- break;
+ if (EC_KEY_get0_public_key(ptr))
+ return;
+ break;
#endif
default:
- /* unsupported type; assuming ok */
- return;
+ /* unsupported type; assuming ok */
+ return;
}
ossl_raise(ePKeyError, "public key missing");
#endif
@@ -609,7 +610,7 @@ static VALUE
ossl_pkey_initialize(VALUE self)
{
if (rb_obj_is_instance_of(self, cPKey)) {
- ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
+ ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
}
return self;
}
@@ -635,6 +636,29 @@ ossl_pkey_initialize_copy(VALUE self, VALUE other)
}
#endif
+#ifndef OSSL_USE_PROVIDER
+static int
+lookup_pkey_type(VALUE type)
+{
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ int pkey_id;
+
+ StringValue(type);
+ /*
+ * XXX: EVP_PKEY_asn1_find_str() looks up a PEM type string. Should we use
+ * OBJ_txt2nid() instead (and then somehow check if the NID is an acceptable
+ * EVP_PKEY type)?
+ * It is probably fine, though, since it can handle all algorithms that
+ * support raw keys in 1.1.1: { X25519, X448, ED25519, ED448, HMAC }.
+ */
+ 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);
+ return pkey_id;
+}
+#endif
+
/*
* call-seq:
* OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey
@@ -646,24 +670,25 @@ 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);
+#ifdef OSSL_USE_PROVIDER
+ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, StringValueCStr(type), NULL,
+ (unsigned char *)RSTRING_PTR(key),
+ keylen);
+ if (!pkey)
+ ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key_ex");
+#else
+ int pkey_id = lookup_pkey_type(type);
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");
+#endif
- return ossl_pkey_new(pkey);
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -677,24 +702,25 @@ 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);
+#ifdef OSSL_USE_PROVIDER
+ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, StringValueCStr(type), NULL,
+ (unsigned char *)RSTRING_PTR(key),
+ keylen);
+ if (!pkey)
+ ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key_ex");
+#else
+ int pkey_id = lookup_pkey_type(type);
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");
+#endif
- return ossl_pkey_new(pkey);
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -711,6 +737,10 @@ ossl_pkey_oid(VALUE self)
GetPKey(self, pkey);
nid = EVP_PKEY_id(pkey);
+#ifdef OSSL_USE_PROVIDER
+ if (nid == EVP_PKEY_KEYMGMT)
+ ossl_raise(ePKeyError, "EVP_PKEY_id");
+#endif
return rb_str_new_cstr(OBJ_nid2sn(nid));
}
@@ -724,13 +754,23 @@ static VALUE
ossl_pkey_inspect(VALUE self)
{
EVP_PKEY *pkey;
- int nid;
GetPKey(self, pkey);
- nid = EVP_PKEY_id(pkey);
- return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
- rb_class_name(CLASS_OF(self)), (void *)self,
- OBJ_nid2sn(nid));
+ VALUE str = rb_sprintf("#<%"PRIsVALUE":%p",
+ rb_obj_class(self), (void *)self);
+ int nid = EVP_PKEY_id(pkey);
+#ifdef OSSL_USE_PROVIDER
+ if (nid != EVP_PKEY_KEYMGMT)
+#endif
+ rb_str_catf(str, " oid=%s", OBJ_nid2sn(nid));
+#ifdef OSSL_USE_PROVIDER
+ rb_str_catf(str, " type_name=%s", EVP_PKEY_get0_type_name(pkey));
+ const OSSL_PROVIDER *prov = EVP_PKEY_get0_provider(pkey);
+ if (prov)
+ rb_str_catf(str, " provider=%s", OSSL_PROVIDER_get0_name(prov));
+#endif
+ rb_str_catf(str, ">");
+ return str;
}
/*
@@ -774,33 +814,33 @@ VALUE
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
{
EVP_PKEY *pkey;
- VALUE cipher, pass;
+ VALUE cipher, pass, cipher_holder;
const EVP_CIPHER *enc = NULL;
BIO *bio;
GetPKey(self, pkey);
rb_scan_args(argc, argv, "02", &cipher, &pass);
if (!NIL_P(cipher)) {
- enc = ossl_evp_get_cipherbyname(cipher);
- pass = ossl_pem_passwd_value(pass);
+ enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ pass = ossl_pem_passwd_value(pass);
}
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PrivateKey_bio(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
- }
+ if (!i2d_PrivateKey_bio(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
+ }
}
else {
- if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb,
- (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
- }
+ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb,
+ (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
+ }
}
return ossl_membio2str(bio);
}
@@ -809,37 +849,37 @@ static VALUE
do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
{
EVP_PKEY *pkey;
- VALUE cipher, pass;
+ VALUE cipher, pass, cipher_holder;
const EVP_CIPHER *enc = NULL;
BIO *bio;
GetPKey(self, pkey);
rb_scan_args(argc, argv, "02", &cipher, &pass);
if (argc > 0) {
- /*
- * TODO: EncryptedPrivateKeyInfo actually has more options.
- * Should they be exposed?
- */
- enc = ossl_evp_get_cipherbyname(cipher);
- pass = ossl_pem_passwd_value(pass);
+ /*
+ * TODO: EncryptedPrivateKeyInfo actually has more options.
+ * Should they be exposed?
+ */
+ enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ pass = ossl_pem_passwd_value(pass);
}
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb, (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
- }
+ if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb, (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
+ }
}
else {
- if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb, (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
- }
+ if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb, (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
+ }
}
return ossl_membio2str(bio);
}
@@ -923,18 +963,18 @@ ossl_pkey_export_spki(VALUE self, int to_der)
ossl_pkey_check_public_key(pkey);
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PUBKEY_bio(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
- }
+ if (!i2d_PUBKEY_bio(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
+ }
}
else {
- if (!PEM_write_bio_PUBKEY(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
- }
+ if (!PEM_write_bio_PUBKEY(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
+ }
}
return ossl_membio2str(bio);
}
@@ -1071,7 +1111,7 @@ static VALUE
ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, data, options, sig;
+ VALUE digest, data, options, sig, md_holder;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
EVP_PKEY_CTX *pctx;
@@ -1081,7 +1121,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
pkey = GetPrivPKeyPtr(self);
rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
ctx = EVP_MD_CTX_new();
@@ -1150,7 +1190,7 @@ static VALUE
ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, data, options;
+ VALUE digest, sig, data, options, md_holder;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
EVP_PKEY_CTX *pctx;
@@ -1160,7 +1200,7 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
StringValue(data);
@@ -1229,7 +1269,7 @@ static VALUE
ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, data, options, sig;
+ VALUE digest, data, options, sig, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
size_t outlen;
@@ -1238,7 +1278,7 @@ ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
GetPKey(self, pkey);
rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
@@ -1305,7 +1345,7 @@ static VALUE
ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, data, options;
+ VALUE digest, sig, data, options, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
int state, ret;
@@ -1314,7 +1354,7 @@ ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
StringValue(data);
@@ -1368,7 +1408,7 @@ static VALUE
ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, options, out;
+ VALUE digest, sig, options, out, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
int state;
@@ -1378,7 +1418,7 @@ ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "21", &digest, &sig, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
@@ -1456,8 +1496,10 @@ ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
EVP_PKEY_CTX_free(ctx);
ossl_raise(ePKeyError, "EVP_PKEY_derive");
}
- if (keylen > LONG_MAX)
+ if (keylen > LONG_MAX) {
+ EVP_PKEY_CTX_free(ctx);
rb_raise(ePKeyError, "derived key would be too large");
+ }
str = ossl_str_new(NULL, (long)keylen, &state);
if (state) {
EVP_PKEY_CTX_free(ctx);
@@ -1618,11 +1660,6 @@ void
Init_ossl_pkey(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-module: OpenSSL::PKey
*
* == Asymmetric Public Key Algorithms
@@ -1678,7 +1715,16 @@ Init_ossl_pkey(void)
/* Document-class: OpenSSL::PKey::PKeyError
*
- *Raised when errors occur during PKey#sign or PKey#verify.
+ * Raised when errors occur during PKey#sign or PKey#verify.
+ *
+ * Before version 4.0.0, OpenSSL::PKey::PKeyError had the following
+ * subclasses. These subclasses have been removed and the constants are
+ * now defined as aliases of OpenSSL::PKey::PKeyError.
+ *
+ * * OpenSSL::PKey::DHError
+ * * OpenSSL::PKey::DSAError
+ * * OpenSSL::PKey::ECError
+ * * OpenSSL::PKey::RSAError
*/
ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index fdc5e94aed..efba33b752 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -22,12 +22,12 @@ extern const rb_data_type_t ossl_evp_pkey_type;
#define GetPKey(obj, pkey) do {\
TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
if (!(pkey)) { \
- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
+ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
} \
} while (0)
/* Takes ownership of the EVP_PKEY */
-VALUE ossl_pkey_new(EVP_PKEY *);
+VALUE ossl_pkey_wrap(EVP_PKEY *);
void ossl_pkey_check_public_key(const EVP_PKEY *);
EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
EVP_PKEY *GetPKeyPtr(VALUE);
@@ -45,7 +45,7 @@ VALUE ossl_pkey_export_spki(VALUE self, int to_der);
* #to_der.
*/
VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,
- int to_der);
+ int to_der);
void Init_ossl_pkey(void);
@@ -71,123 +71,122 @@ void Init_ossl_dh(void);
* EC
*/
extern VALUE cEC;
-VALUE ossl_ec_new(EVP_PKEY *);
void Init_ossl_ec(void);
-#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \
-/* \
- * call-seq: \
- * _keytype##.##_name -> aBN \
- */ \
-static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
-{ \
- const _type *obj; \
- const BIGNUM *bn; \
- \
- Get##_type(self, obj); \
- _get; \
- if (bn == NULL) \
- return Qnil; \
- return ossl_bn_new(bn); \
+#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \
+/* \
+ * call-seq: \
+ * _keytype##.##_name -> aBN \
+ */ \
+static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
+{ \
+ const _type *obj; \
+ const BIGNUM *bn; \
+ \
+ Get##_type(self, obj); \
+ _get; \
+ if (bn == NULL) \
+ return Qnil; \
+ return ossl_bn_new(bn); \
}
-#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
- _type##_get0_##_group(obj, &bn, NULL, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
- _type##_get0_##_group(obj, NULL, &bn, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \
- _type##_get0_##_group(obj, NULL, NULL, &bn))
-
-#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
- _type##_get0_##_group(obj, &bn, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
- _type##_get0_##_group(obj, NULL, &bn))
-
-#if !OSSL_OPENSSL_PREREQ(3, 0, 0)
-#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
-/* \
- * call-seq: \
- * _keytype##.set_##_group(a1, a2, a3) -> self \
- */ \
+#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
+ _type##_get0_##_group(obj, &bn, NULL, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
+ _type##_get0_##_group(obj, NULL, &bn, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \
+ _type##_get0_##_group(obj, NULL, NULL, &bn))
+
+#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
+ _type##_get0_##_group(obj, &bn, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
+ _type##_get0_##_group(obj, NULL, &bn))
+
+#ifndef OSSL_HAVE_IMMUTABLE_PKEY
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+/* \
+ * call-seq: \
+ * _keytype##.set_##_group(a1, a2, a3) -> self \
+ */ \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
-{ \
- _type *obj; \
- BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
- BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
- BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
- \
- Get##_type(self, obj); \
- if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
- (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \
- (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- BN_clear_free(bn3); \
- ossl_raise(ePKeyError, "BN_dup"); \
- } \
- \
- if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- BN_clear_free(bn3); \
- ossl_raise(ePKeyError, #_type"_set0_"#_group); \
- } \
- return self; \
+{ \
+ _type *obj; \
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
+ BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
+ \
+ Get##_type(self, obj); \
+ if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
+ (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \
+ (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ BN_clear_free(bn3); \
+ ossl_raise(ePKeyError, "BN_dup"); \
+ } \
+ \
+ if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ BN_clear_free(bn3); \
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \
+ } \
+ return self; \
}
-#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
-/* \
- * call-seq: \
- * _keytype##.set_##_group(a1, a2) -> self \
- */ \
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+/* \
+ * call-seq: \
+ * _keytype##.set_##_group(a1, a2) -> self \
+ */ \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
-{ \
- _type *obj; \
- BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
- BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
- \
- Get##_type(self, obj); \
- if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
- (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- ossl_raise(ePKeyError, "BN_dup"); \
- } \
- \
- if (!_type##_set0_##_group(obj, bn1, bn2)) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- ossl_raise(ePKeyError, #_type"_set0_"#_group); \
- } \
- return self; \
+{ \
+ _type *obj; \
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
+ \
+ Get##_type(self, obj); \
+ if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
+ (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ ossl_raise(ePKeyError, "BN_dup"); \
+ } \
+ \
+ if (!_type##_set0_##_group(obj, bn1, bn2)) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \
+ } \
+ return self; \
}
#else
-#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
-{ \
- rb_raise(ePKeyError, \
+{ \
+ rb_raise(ePKeyError, \
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
}
-#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
-{ \
- rb_raise(ePKeyError, \
+{ \
+ rb_raise(ePKeyError, \
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
}
#endif
-#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
+#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
-#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
+#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
-#define DEF_OSSL_PKEY_BN(class, keytype, name) \
- rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
+#define DEF_OSSL_PKEY_BN(class, keytype, name) \
+ rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
#endif /* OSSL_PKEY_H */
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 118d29f04f..3f2975c5a3 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -14,20 +14,21 @@
#define GetPKeyDH(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
} \
} while (0)
#define GetDH(obj, dh) do { \
EVP_PKEY *_pkey; \
GetPKeyDH((obj), _pkey); \
(dh) = EVP_PKEY_get0_DH(_pkey); \
+ if ((dh) == NULL) \
+ ossl_raise(ePKeyError, "failed to get DH from EVP_PKEY"); \
} while (0)
/*
* Classes
*/
VALUE cDH;
-static VALUE eDHError;
/*
* Private
@@ -43,6 +44,7 @@ static VALUE eDHError;
* If called without arguments, an empty instance without any parameter or key
* components is created. Use #set_pqg to manually set the parameters afterwards
* (and optionally #set_key to set private and public key components).
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If a String is given, tries to parse it as a DER- or PEM- encoded parameters.
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -58,14 +60,15 @@ static VALUE eDHError;
*
* Examples:
* # Creating an instance from scratch
- * # Note that this is deprecated and will not work on OpenSSL 3.0 or later.
+ * # Note that this is deprecated and will result in ArgumentError when
+ * # using OpenSSL 3.0 or later.
* dh = OpenSSL::PKey::DH.new
* dh.set_pqg(bn_p, nil, bn_g)
*
* # Generating a parameters and a key pair
* dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)
*
- * # Reading DH parameters
+ * # Reading DH parameters from a PEM-encoded string
* dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only
* dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair
*/
@@ -84,10 +87,15 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::DH.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
dh = DH_new();
if (!dh)
- ossl_raise(eDHError, "DH_new");
+ ossl_raise(ePKeyError, "DH_new");
goto legacy;
+#endif
}
arg = ossl_to_der_if_possible(arg);
@@ -105,12 +113,12 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, Qnil);
BIO_free(in);
if (!pkey)
- ossl_raise(eDHError, "could not parse pkey");
+ ossl_raise(ePKeyError, "could not parse pkey");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_DH) {
EVP_PKEY_free(pkey);
- rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -121,7 +129,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
EVP_PKEY_free(pkey);
DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DH");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -143,26 +151,26 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
dh = DHparams_dup(dh_other);
if (!dh)
- ossl_raise(eDHError, "DHparams_dup");
+ ossl_raise(ePKeyError, "DHparams_dup");
DH_get0_key(dh_other, &pub, &priv);
if (pub) {
- BIGNUM *pub2 = BN_dup(pub);
- BIGNUM *priv2 = BN_dup(priv);
+ BIGNUM *pub2 = BN_dup(pub);
+ BIGNUM *priv2 = BN_dup(priv);
if (!pub2 || (priv && !priv2)) {
- BN_clear_free(pub2);
- BN_clear_free(priv2);
- ossl_raise(eDHError, "BN_dup");
- }
- DH_set0_key(dh, pub2, priv2);
+ BN_clear_free(pub2);
+ BN_clear_free(priv2);
+ ossl_raise(ePKeyError, "BN_dup");
+ }
+ DH_set0_key(dh, pub2, priv2);
}
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
EVP_PKEY_free(pkey);
DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DH");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -241,11 +249,11 @@ ossl_dh_export(VALUE self)
GetDH(self, dh);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
if (!PEM_write_bio_DHparams(out, dh)) {
- BIO_free(out);
- ossl_raise(eDHError, NULL);
+ BIO_free(out);
+ ossl_raise(ePKeyError, NULL);
}
str = ossl_membio2str(out);
@@ -275,11 +283,11 @@ ossl_dh_to_der(VALUE self)
GetDH(self, dh);
if((len = i2d_DHparams(dh, NULL)) <= 0)
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_DHparams(dh, &p) < 0)
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -306,7 +314,7 @@ ossl_dh_check_params(VALUE self)
GetPKey(self, pkey);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
- ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
ret = EVP_PKEY_param_check(pctx);
EVP_PKEY_CTX_free(pctx);
#else
@@ -349,19 +357,6 @@ OSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key)
void
Init_ossl_dh(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::DHError
- *
- * Generic exception that is raised if an operation on a DH PKey
- * fails unexpectedly or in case an instantiation of an instance of DH
- * fails due to non-conformant input data.
- */
- eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
/* Document-class: OpenSSL::PKey::DH
*
* An implementation of the Diffie-Hellman key exchange protocol based on
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 9f4f012cfe..041646a058 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -14,13 +14,15 @@
#define GetPKeyDSA(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
} \
} while (0)
#define GetDSA(obj, dsa) do { \
EVP_PKEY *_pkey; \
GetPKeyDSA((obj), _pkey); \
(dsa) = EVP_PKEY_get0_DSA(_pkey); \
+ if ((dsa) == NULL) \
+ ossl_raise(ePKeyError, "failed to get DSA from EVP_PKEY"); \
} while (0)
static inline int
@@ -41,7 +43,6 @@ DSA_PRIVATE(VALUE obj, OSSL_3_const DSA *dsa)
* Classes
*/
VALUE cDSA;
-static VALUE eDSAError;
/*
* Private
@@ -56,6 +57,7 @@ static VALUE eDSAError;
*
* If called without arguments, creates a new instance with no key components
* set. They can be set individually by #set_pqg and #set_key.
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If called with a String, tries to parse as DER or PEM encoding of a \DSA key.
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -96,10 +98,15 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::DSA.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
dsa = DSA_new();
if (!dsa)
- ossl_raise(eDSAError, "DSA_new");
+ ossl_raise(ePKeyError, "DSA_new");
goto legacy;
+#endif
}
pass = ossl_pem_passwd_value(pass);
@@ -117,12 +124,12 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey)
- ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
+ ossl_raise(ePKeyError, "Neither PUB key nor PRIV key");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_DSA) {
EVP_PKEY_free(pkey);
- rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -133,7 +140,7 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
EVP_PKEY_free(pkey);
DSA_free(dsa);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -156,13 +163,13 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other)
(d2i_of_void *)d2i_DSAPrivateKey,
(char *)dsa);
if (!dsa_new)
- ossl_raise(eDSAError, "ASN1_dup");
+ ossl_raise(ePKeyError, "ASN1_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
EVP_PKEY_free(pkey);
DSA_free(dsa_new);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -327,20 +334,6 @@ OSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key)
void
Init_ossl_dsa(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::DSAError
- *
- * Generic exception that is raised if an operation on a DSA PKey
- * fails unexpectedly or in case an instantiation of an instance of DSA
- * fails due to non-conformant input data.
- */
- eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
-
/* Document-class: OpenSSL::PKey::DSA
*
* DSA, the Digital Signature Algorithm, is specified in NIST's
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 4687cf8c9d..35f031819d 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -15,25 +15,27 @@ static const rb_data_type_t ossl_ec_point_type;
#define GetPKeyEC(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
} \
} while (0)
#define GetEC(obj, key) do { \
EVP_PKEY *_pkey; \
GetPKeyEC(obj, _pkey); \
(key) = EVP_PKEY_get0_EC_KEY(_pkey); \
+ if ((key) == NULL) \
+ ossl_raise(ePKeyError, "failed to get EC_KEY from EVP_PKEY"); \
} while (0)
#define GetECGroup(obj, group) do { \
TypedData_Get_Struct(obj, EC_GROUP, &ossl_ec_group_type, group); \
if ((group) == NULL) \
- ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
+ ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
} while (0)
#define GetECPoint(obj, point) do { \
TypedData_Get_Struct(obj, EC_POINT, &ossl_ec_point_type, point); \
if ((point) == NULL) \
- ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
+ ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
} while (0)
#define GetECPointGroup(obj, group) do { \
VALUE _group = rb_attr_get(obj, id_i_group); \
@@ -41,17 +43,13 @@ static const rb_data_type_t ossl_ec_point_type;
} while (0)
VALUE cEC;
-static VALUE eECError;
static VALUE cEC_GROUP;
static VALUE eEC_GROUP;
static VALUE cEC_POINT;
static VALUE eEC_POINT;
-static ID s_GFp, s_GF2m;
-
-static ID ID_uncompressed;
-static ID ID_compressed;
-static ID ID_hybrid;
+static VALUE sym_GFp, sym_GF2m;
+static VALUE sym_uncompressed, sym_compressed, sym_hybrid;
static ID id_i_group;
@@ -68,27 +66,27 @@ ec_key_new_from_group(VALUE arg)
EC_KEY *ec;
if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
- EC_GROUP *group;
+ EC_GROUP *group;
- GetECGroup(arg, group);
- if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, NULL);
+ GetECGroup(arg, group);
+ if (!(ec = EC_KEY_new()))
+ ossl_raise(ePKeyError, NULL);
- if (!EC_KEY_set_group(ec, group)) {
- EC_KEY_free(ec);
- ossl_raise(eECError, NULL);
- }
+ if (!EC_KEY_set_group(ec, group)) {
+ EC_KEY_free(ec);
+ ossl_raise(ePKeyError, NULL);
+ }
} else {
- int nid = OBJ_sn2nid(StringValueCStr(arg));
+ int nid = OBJ_sn2nid(StringValueCStr(arg));
- if (nid == NID_undef)
- ossl_raise(eECError, "invalid curve name");
+ if (nid == NID_undef)
+ ossl_raise(ePKeyError, "invalid curve name");
- if (!(ec = EC_KEY_new_by_curve_name(nid)))
- ossl_raise(eECError, NULL);
+ if (!(ec = EC_KEY_new_by_curve_name(nid)))
+ ossl_raise(ePKeyError, NULL);
- EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
- EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+ EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
+ EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
}
return ec;
@@ -115,12 +113,12 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(obj) = pkey;
if (!EC_KEY_generate_key(ec))
- ossl_raise(eECError, "EC_KEY_generate_key");
+ ossl_raise(ePKeyError, "EC_KEY_generate_key");
return obj;
}
@@ -150,9 +148,14 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "02", &arg, &pass);
if (NIL_P(arg)) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::EC.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, "EC_KEY_new");
+ ossl_raise(ePKeyError, "EC_KEY_new");
goto legacy;
+#endif
}
else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
ec = ec_key_new_from_group(arg);
@@ -174,7 +177,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_EC) {
EVP_PKEY_free(pkey);
- rb_raise(eECError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -184,7 +187,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -205,12 +208,12 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other)
ec_new = EC_KEY_dup(ec);
if (!ec_new)
- ossl_raise(eECError, "EC_KEY_dup");
+ ossl_raise(ePKeyError, "EC_KEY_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
EC_KEY_free(ec_new);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -234,7 +237,7 @@ ossl_ec_key_get_group(VALUE self)
GetEC(self, ec);
group = EC_KEY_get0_group(ec);
if (!group)
- return Qnil;
+ return Qnil;
return ec_group_new(group);
}
@@ -249,7 +252,7 @@ ossl_ec_key_get_group(VALUE self)
static VALUE
ossl_ec_key_set_group(VALUE self, VALUE group_v)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -259,7 +262,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v)
GetECGroup(group_v, group);
if (EC_KEY_set_group(ec, group) != 1)
- ossl_raise(eECError, "EC_KEY_set_group");
+ ossl_raise(ePKeyError, "EC_KEY_set_group");
return group_v;
#endif
@@ -291,7 +294,7 @@ static VALUE ossl_ec_key_get_private_key(VALUE self)
*/
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -302,14 +305,14 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
bn = GetBNPtr(private_key);
switch (EC_KEY_set_private_key(ec, bn)) {
- case 1:
+ case 1:
break;
- case 0:
+ case 0:
if (bn == NULL)
break;
- /* fallthrough */
- default:
- ossl_raise(eECError, "EC_KEY_set_private_key");
+ /* fallthrough */
+ default:
+ ossl_raise(ePKeyError, "EC_KEY_set_private_key");
}
return private_key;
@@ -342,7 +345,7 @@ static VALUE ossl_ec_key_get_public_key(VALUE self)
*/
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -353,14 +356,14 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
GetECPoint(public_key, point);
switch (EC_KEY_set_public_key(ec, point)) {
- case 1:
+ case 1:
break;
- case 0:
+ case 0:
if (point == NULL)
break;
- /* fallthrough */
- default:
- ossl_raise(eECError, "EC_KEY_set_public_key");
+ /* fallthrough */
+ default:
+ ossl_raise(ePKeyError, "EC_KEY_set_public_key");
}
return public_key;
@@ -464,7 +467,7 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- ossl_raise(eECError, "can't export - no public key set");
+ ossl_raise(ePKeyError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(argc, argv, self, 0);
else
@@ -492,7 +495,7 @@ ossl_ec_key_to_der(VALUE self)
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- ossl_raise(eECError, "can't export - no public key set");
+ ossl_raise(ePKeyError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(0, NULL, self, 1);
else
@@ -514,14 +517,14 @@ ossl_ec_key_to_der(VALUE self)
*/
static VALUE ossl_ec_key_generate_key(VALUE self)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_generate_key(ec) != 1)
- ossl_raise(eECError, "EC_KEY_generate_key");
+ ossl_raise(ePKeyError, "EC_KEY_generate_key");
return self;
#endif
@@ -546,18 +549,18 @@ static VALUE ossl_ec_key_check_key(VALUE self)
GetEC(self, ec);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
- ossl_raise(eECError, "EVP_PKEY_CTX_new");
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
if (EC_KEY_get0_private_key(ec) != NULL) {
if (EVP_PKEY_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
- ossl_raise(eECError, "EVP_PKEY_check");
+ ossl_raise(ePKeyError, "EVP_PKEY_check");
}
}
else {
if (EVP_PKEY_public_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
- ossl_raise(eECError, "EVP_PKEY_public_check");
+ ossl_raise(ePKeyError, "EVP_PKEY_public_check");
}
}
@@ -567,7 +570,7 @@ static VALUE ossl_ec_key_check_key(VALUE self)
GetEC(self, ec);
if (EC_KEY_check_key(ec) != 1)
- ossl_raise(eECError, "EC_KEY_check_key");
+ ossl_raise(ePKeyError, "EC_KEY_check_key");
#endif
return Qtrue;
@@ -585,7 +588,7 @@ ossl_ec_group_free(void *ptr)
static const rb_data_type_t ossl_ec_group_type = {
"OpenSSL/ec_group",
{
- 0, ossl_ec_group_free,
+ 0, ossl_ec_group_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -605,7 +608,7 @@ ec_group_new(const EC_GROUP *group)
obj = ossl_ec_group_alloc(cEC_GROUP);
group_new = EC_GROUP_dup(group);
if (!group_new)
- ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
RTYPEDDATA_DATA(obj) = group_new;
return obj;
@@ -633,7 +636,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
- case 1:
+ case 1:
if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
const EC_GROUP *arg1_group;
@@ -645,7 +648,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
if (!group) {
- OSSL_BIO_reset(in);
+ OSSL_BIO_reset(in);
group = d2i_ECPKParameters_bio(in, NULL);
}
@@ -655,7 +658,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
const char *name = StringValueCStr(arg1);
int nid = OBJ_sn2nid(name);
- ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */
+ ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */
if (nid == NID_undef)
ossl_raise(eEC_GROUP, "unknown curve name (%"PRIsVALUE")", arg1);
#if !defined(OPENSSL_IS_AWSLC)
@@ -672,33 +675,34 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
}
break;
- case 4:
+ case 4:
if (SYMBOL_P(arg1)) {
- ID id = SYM2ID(arg1);
EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
const BIGNUM *p = GetBNPtr(arg2);
const BIGNUM *a = GetBNPtr(arg3);
const BIGNUM *b = GetBNPtr(arg4);
- if (id == s_GFp) {
+ if (arg1 == sym_GFp) {
new_curve = EC_GROUP_new_curve_GFp;
+ }
#if !defined(OPENSSL_NO_EC2M)
- } else if (id == s_GF2m) {
+ else if (arg1 == sym_GF2m) {
new_curve = EC_GROUP_new_curve_GF2m;
+ }
#endif
- } else {
+ else {
ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
}
if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
} else {
- ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
+ ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
}
break;
- default:
- ossl_raise(rb_eArgError, "wrong number of arguments");
+ default:
+ ossl_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1 or 4)", argc);
}
ASSUME(group);
@@ -715,12 +719,12 @@ ossl_ec_group_initialize_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group_new);
if (group_new)
- ossl_raise(eEC_GROUP, "EC::Group already initialized");
+ ossl_raise(eEC_GROUP, "EC::Group already initialized");
GetECGroup(other, group);
group_new = EC_GROUP_dup(group);
if (!group_new)
- ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
RTYPEDDATA_DATA(self) = group_new;
return self;
@@ -742,9 +746,9 @@ static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
GetECGroup(b, group2);
switch (EC_GROUP_cmp(group1, group2, ossl_bn_ctx)) {
- case 0: return Qtrue;
- case 1: return Qfalse;
- default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp");
+ case 0: return Qtrue;
+ case 1: return Qfalse;
+ default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp");
}
}
@@ -764,7 +768,7 @@ static VALUE ossl_ec_group_get_generator(VALUE self)
GetECGroup(self, group);
generator = EC_GROUP_get0_generator(group);
if (!generator)
- return Qnil;
+ return Qnil;
return ec_point_new(generator, group);
}
@@ -807,11 +811,10 @@ static VALUE ossl_ec_group_get_order(VALUE self)
{
VALUE bn_obj;
BIGNUM *bn;
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
GetECGroup(self, group);
-
- bn_obj = ossl_bn_new(NULL);
+ bn_obj = ossl_bn_new(BN_value_one());
bn = GetBNPtr(bn_obj);
if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
@@ -832,11 +835,10 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self)
{
VALUE bn_obj;
BIGNUM *bn;
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
GetECGroup(self, group);
-
- bn_obj = ossl_bn_new(NULL);
+ bn_obj = ossl_bn_new(BN_value_one());
bn = GetBNPtr(bn_obj);
if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
@@ -847,25 +849,23 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self)
/*
* call-seq:
- * group.curve_name => String
+ * group.curve_name -> string or nil
*
- * Returns the curve name (sn).
+ * Returns the curve name (short name) corresponding to this group, or +nil+
+ * if \OpenSSL does not have an OID associated with the group.
*
* See the OpenSSL documentation for EC_GROUP_get_curve_name()
*/
static VALUE ossl_ec_group_get_curve_name(VALUE self)
{
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
int nid;
GetECGroup(self, group);
- if (group == NULL)
- return Qnil;
-
nid = EC_GROUP_get_curve_name(group);
-
-/* BUG: an nid or asn1 object should be returned, maybe. */
- return rb_str_new2(OBJ_nid2sn(nid));
+ if (nid == NID_undef)
+ return Qnil;
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
}
/*
@@ -958,37 +958,36 @@ static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
*/
static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
{
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
point_conversion_form_t form;
- VALUE ret;
GetECGroup(self, group);
form = EC_GROUP_get_point_conversion_form(group);
switch (form) {
- case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
- case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
- case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
- default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
+ case POINT_CONVERSION_UNCOMPRESSED:
+ return sym_uncompressed;
+ case POINT_CONVERSION_COMPRESSED:
+ return sym_compressed;
+ case POINT_CONVERSION_HYBRID:
+ return sym_hybrid;
+ default:
+ ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, " \
+ "this module should be updated", form);
}
-
- return ID2SYM(ret);
}
static point_conversion_form_t
parse_point_conversion_form_symbol(VALUE sym)
{
- ID id = SYM2ID(sym);
-
- if (id == ID_uncompressed)
- return POINT_CONVERSION_UNCOMPRESSED;
- else if (id == ID_compressed)
- return POINT_CONVERSION_COMPRESSED;
- else if (id == ID_hybrid)
- return POINT_CONVERSION_HYBRID;
- else
- ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE
- " (expected :compressed, :uncompressed, or :hybrid)", sym);
+ if (sym == sym_uncompressed)
+ return POINT_CONVERSION_UNCOMPRESSED;
+ if (sym == sym_compressed)
+ return POINT_CONVERSION_COMPRESSED;
+ if (sym == sym_hybrid)
+ return POINT_CONVERSION_HYBRID;
+ ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE
+ " (expected :compressed, :uncompressed, or :hybrid)", sym);
}
/*
@@ -1093,20 +1092,20 @@ static VALUE ossl_ec_group_to_string(VALUE self, int format)
ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
switch(format) {
- case EXPORT_PEM:
+ case EXPORT_PEM:
i = PEM_write_bio_ECPKParameters(out, group);
- break;
- case EXPORT_DER:
+ break;
+ case EXPORT_DER:
i = i2d_ECPKParameters_bio(out, group);
- break;
- default:
+ break;
+ default:
BIO_free(out);
- ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
}
if (i != 1) {
BIO_free(out);
- ossl_raise(eECError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
str = ossl_membio2str(out);
@@ -1150,11 +1149,11 @@ static VALUE ossl_ec_group_to_text(VALUE self)
GetECGroup(self, group);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+ ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
}
if (!ECPKParameters_print(out, group, 0)) {
- BIO_free(out);
- ossl_raise(eEC_GROUP, NULL);
+ BIO_free(out);
+ ossl_raise(eEC_GROUP, NULL);
}
str = ossl_membio2str(out);
@@ -1174,7 +1173,7 @@ ossl_ec_point_free(void *ptr)
static const rb_data_type_t ossl_ec_point_type = {
"OpenSSL/EC_POINT",
{
- 0, ossl_ec_point_free,
+ 0, ossl_ec_point_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -1194,7 +1193,7 @@ ec_point_new(const EC_POINT *point, const EC_GROUP *group)
obj = ossl_ec_point_alloc(cEC_POINT);
point_new = EC_POINT_dup(point, group);
if (!point_new)
- ossl_raise(eEC_POINT, "EC_POINT_dup");
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
RTYPEDDATA_DATA(obj) = point_new;
rb_ivar_set(obj, id_i_group, ec_group_new(group));
@@ -1222,39 +1221,39 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point);
if (point)
- rb_raise(eEC_POINT, "EC_POINT already initialized");
+ rb_raise(eEC_POINT, "EC_POINT already initialized");
rb_scan_args(argc, argv, "11", &group_v, &arg2);
if (rb_obj_is_kind_of(group_v, cEC_POINT)) {
- if (argc != 1)
- rb_raise(rb_eArgError, "invalid second argument");
- return ossl_ec_point_initialize_copy(self, group_v);
+ if (argc != 1)
+ rb_raise(rb_eArgError, "invalid second argument");
+ return ossl_ec_point_initialize_copy(self, group_v);
}
GetECGroup(group_v, group);
if (argc == 1) {
- point = EC_POINT_new(group);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_new");
+ point = EC_POINT_new(group);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_new");
}
else {
- if (rb_obj_is_kind_of(arg2, cBN)) {
- point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_bn2point");
- }
- else {
- StringValue(arg2);
- point = EC_POINT_new(group);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_new");
- if (!EC_POINT_oct2point(group, point,
- (unsigned char *)RSTRING_PTR(arg2),
- RSTRING_LEN(arg2), ossl_bn_ctx)) {
- EC_POINT_free(point);
- ossl_raise(eEC_POINT, "EC_POINT_oct2point");
- }
- }
+ if (rb_obj_is_kind_of(arg2, cBN)) {
+ point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_bn2point");
+ }
+ else {
+ StringValue(arg2);
+ point = EC_POINT_new(group);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_new");
+ if (!EC_POINT_oct2point(group, point,
+ (unsigned char *)RSTRING_PTR(arg2),
+ RSTRING_LEN(arg2), ossl_bn_ctx)) {
+ EC_POINT_free(point);
+ ossl_raise(eEC_POINT, "EC_POINT_oct2point");
+ }
+ }
}
RTYPEDDATA_DATA(self) = point;
@@ -1273,7 +1272,7 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point_new);
if (point_new)
- ossl_raise(eEC_POINT, "EC::Point already initialized");
+ ossl_raise(eEC_POINT, "EC::Point already initialized");
GetECPoint(other, point);
group_v = rb_obj_dup(rb_attr_get(other, id_i_group));
@@ -1281,7 +1280,7 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other)
point_new = EC_POINT_dup(point, group);
if (!point_new)
- ossl_raise(eEC_POINT, "EC_POINT_dup");
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
RTYPEDDATA_DATA(self) = point_new;
rb_ivar_set(self, id_i_group, group_v);
@@ -1308,9 +1307,9 @@ static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
GetECGroup(group_v1, group);
switch (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx)) {
- case 0: return Qtrue;
- case 1: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_cmp");
+ case 0: return Qtrue;
+ case 1: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_cmp");
}
UNREACHABLE;
@@ -1329,9 +1328,9 @@ static VALUE ossl_ec_point_is_at_infinity(VALUE self)
GetECPointGroup(self, group);
switch (EC_POINT_is_at_infinity(group, point)) {
- case 1: return Qtrue;
- case 0: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity");
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity");
}
UNREACHABLE;
@@ -1350,9 +1349,9 @@ static VALUE ossl_ec_point_is_on_curve(VALUE self)
GetECPointGroup(self, group);
switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
- case 1: return Qtrue;
- case 0: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve");
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve");
}
UNREACHABLE;
@@ -1373,7 +1372,7 @@ static VALUE ossl_ec_point_make_affine(VALUE self)
GetECPointGroup(self, group);
rb_warn("OpenSSL::PKey::EC::Point#make_affine! is deprecated");
-#if !OSSL_OPENSSL_PREREQ(3, 0, 0) && !defined(OPENSSL_IS_AWSLC)
+#if !defined(OSSL_HAVE_IMMUTABLE_PKEY) && !defined(OPENSSL_IS_AWSLC)
if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
ossl_raise(eEC_POINT, "EC_POINT_make_affine");
#endif
@@ -1444,12 +1443,12 @@ ossl_ec_point_to_octet_string(VALUE self, VALUE conversion_form)
len = EC_POINT_point2oct(group, point, form, NULL, 0, ossl_bn_ctx);
if (!len)
- ossl_raise(eEC_POINT, "EC_POINT_point2oct");
+ ossl_raise(eEC_POINT, "EC_POINT_point2oct");
str = rb_str_new(NULL, (long)len);
if (!EC_POINT_point2oct(group, point, form,
- (unsigned char *)RSTRING_PTR(str), len,
- ossl_bn_ctx))
- ossl_raise(eEC_POINT, "EC_POINT_point2oct");
+ (unsigned char *)RSTRING_PTR(str), len,
+ ossl_bn_ctx))
+ ossl_raise(eEC_POINT, "EC_POINT_point2oct");
return str;
}
@@ -1527,15 +1526,6 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
void Init_ossl_ec(void)
{
#undef rb_intern
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
-
/*
* Document-class: OpenSSL::PKey::EC
*
@@ -1557,12 +1547,12 @@ void Init_ossl_ec(void)
eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
- s_GFp = rb_intern("GFp");
- s_GF2m = rb_intern("GF2m");
+ sym_GFp = ID2SYM(rb_intern_const("GFp"));
+ sym_GF2m = ID2SYM(rb_intern_const("GF2m"));
- ID_uncompressed = rb_intern("uncompressed");
- ID_compressed = rb_intern("compressed");
- ID_hybrid = rb_intern("hybrid");
+ sym_uncompressed = ID2SYM(rb_intern_const("uncompressed"));
+ sym_compressed = ID2SYM(rb_intern_const("compressed"));
+ sym_hybrid = ID2SYM(rb_intern_const("hybrid"));
rb_define_const(cEC, "NAMED_CURVE", INT2NUM(OPENSSL_EC_NAMED_CURVE));
rb_define_const(cEC, "EXPLICIT_CURVE", INT2NUM(OPENSSL_EC_EXPLICIT_CURVE));
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 185b47cbfb..039b2c6a34 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -14,13 +14,15 @@
#define GetPKeyRSA(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
} \
} while (0)
#define GetRSA(obj, rsa) do { \
EVP_PKEY *_pkey; \
GetPKeyRSA((obj), _pkey); \
(rsa) = EVP_PKEY_get0_RSA(_pkey); \
+ if ((rsa) == NULL) \
+ ossl_raise(ePKeyError, "failed to get RSA from EVP_PKEY"); \
} while (0)
static inline int
@@ -42,7 +44,6 @@ RSA_PRIVATE(VALUE obj, OSSL_3_const RSA *rsa)
* Classes
*/
VALUE cRSA;
-static VALUE eRSAError;
/*
* Private
@@ -59,6 +60,7 @@ static VALUE eRSAError;
* If called without arguments, creates a new instance with no key components
* set. They can be set individually by #set_key, #set_factors, and
* #set_crt_params.
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* 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
@@ -89,10 +91,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
- rsa = RSA_new();
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::RSA.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
+ rsa = RSA_new();
if (!rsa)
- ossl_raise(eRSAError, "RSA_new");
+ ossl_raise(ePKeyError, "RSA_new");
goto legacy;
+#endif
}
pass = ossl_pem_passwd_value(pass);
@@ -113,12 +120,12 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey)
- ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
+ ossl_raise(ePKeyError, "Neither PUB key nor PRIV key");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_RSA) {
EVP_PKEY_free(pkey);
- rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -129,7 +136,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
EVP_PKEY_free(pkey);
RSA_free(rsa);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -152,12 +159,12 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other)
(d2i_of_void *)d2i_RSAPrivateKey,
(char *)rsa);
if (!rsa_new)
- ossl_raise(eRSAError, "ASN1_dup");
+ ossl_raise(ePKeyError, "ASN1_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {
RSA_free(rsa_new);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -312,7 +319,7 @@ ossl_rsa_to_der(VALUE self)
* Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns
* the calculated signature.
*
- * RSAError will be raised if an error occurs.
+ * PKeyError will be raised if an error occurs.
*
* See #verify_pss for the verification operation.
*
@@ -341,7 +348,7 @@ ossl_rsa_to_der(VALUE self)
static VALUE
ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
{
- VALUE digest, data, options, kwargs[2], signature;
+ VALUE digest, data, options, kwargs[2], signature, mgf1md_holder, md_holder;
static ID kwargs_ids[2];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pkey_ctx;
@@ -351,46 +358,46 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
int salt_len;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt_length");
- kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
}
rb_scan_args(argc, argv, "2:", &digest, &data, &options);
rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
if (kwargs[0] == ID2SYM(rb_intern("max")))
- salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
+ salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
else if (kwargs[0] == ID2SYM(rb_intern("digest")))
- salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
else
- salt_len = NUM2INT(kwargs[0]);
- mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);
pkey = GetPrivPKeyPtr(self);
buf_len = EVP_PKEY_size(pkey);
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
signature = rb_str_new(NULL, (long)buf_len);
md_ctx = EVP_MD_CTX_new();
if (!md_ctx)
- goto err;
+ goto err;
if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
- goto err;
+ goto err;
if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
- goto err;
+ goto err;
if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1)
- goto err;
+ goto err;
rb_str_set_len(signature, (long)buf_len);
@@ -399,7 +406,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
err:
EVP_MD_CTX_free(md_ctx);
- ossl_raise(eRSAError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
/*
@@ -409,7 +416,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
* Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS).
*
* The return value is +true+ if the signature is valid, +false+ otherwise.
- * RSAError will be raised if an error occurs.
+ * PKeyError will be raised if an error occurs.
*
* See #sign_pss for the signing operation and an example code.
*
@@ -428,7 +435,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
static VALUE
ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
{
- VALUE digest, signature, data, options, kwargs[2];
+ VALUE digest, signature, data, options, kwargs[2], mgf1md_holder, md_holder;
static ID kwargs_ids[2];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pkey_ctx;
@@ -437,62 +444,61 @@ ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
int result, salt_len;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt_length");
- kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
}
rb_scan_args(argc, argv, "3:", &digest, &signature, &data, &options);
rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
if (kwargs[0] == ID2SYM(rb_intern("auto")))
- salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
+ salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
else if (kwargs[0] == ID2SYM(rb_intern("digest")))
- salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
else
- salt_len = NUM2INT(kwargs[0]);
- mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);
GetPKey(self, pkey);
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(signature);
StringValue(data);
md_ctx = EVP_MD_CTX_new();
if (!md_ctx)
- goto err;
+ goto err;
if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
- goto err;
+ goto err;
if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
- goto err;
+ goto err;
result = EVP_DigestVerifyFinal(md_ctx,
- (unsigned char *)RSTRING_PTR(signature),
- RSTRING_LEN(signature));
+ (unsigned char *)RSTRING_PTR(signature),
+ RSTRING_LEN(signature));
+ EVP_MD_CTX_free(md_ctx);
switch (result) {
case 0:
- ossl_clear_error();
- EVP_MD_CTX_free(md_ctx);
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
case 1:
- EVP_MD_CTX_free(md_ctx);
- return Qtrue;
+ return Qtrue;
default:
- goto err;
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
}
err:
EVP_MD_CTX_free(md_ctx);
- ossl_raise(eRSAError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
/*
@@ -530,20 +536,6 @@ OSSL_PKEY_BN_DEF3(rsa, RSA, crt_params, dmp1, dmq1, iqmp)
void
Init_ossl_rsa(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::RSAError
- *
- * Generic exception that is raised if an operation on an RSA PKey
- * fails unexpectedly or in case an instantiation of an instance of RSA
- * fails due to non-conformant input data.
- */
- eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
-
/* Document-class: OpenSSL::PKey::RSA
*
* RSA is an asymmetric public key algorithm that has been formalized in
diff --git a/ext/openssl/ossl_provider.c b/ext/openssl/ossl_provider.c
index d1f6c5d427..ea5abb8e48 100644
--- a/ext/openssl/ossl_provider.c
+++ b/ext/openssl/ossl_provider.c
@@ -5,8 +5,6 @@
#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 { \
@@ -187,11 +185,6 @@ ossl_provider_inspect(VALUE self)
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);
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
index 764900dfc6..753f8b25f7 100644
--- a/ext/openssl/ossl_rand.c
+++ b/ext/openssl/ossl_rand.c
@@ -68,7 +68,7 @@ static VALUE
ossl_rand_load_file(VALUE self, VALUE filename)
{
if(!RAND_load_file(StringValueCStr(filename), -1)) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -85,14 +85,14 @@ static VALUE
ossl_rand_write_file(VALUE self, VALUE filename)
{
if (RAND_write_file(StringValueCStr(filename)) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
/*
* call-seq:
- * random_bytes(length) -> string
+ * random_bytes(length) -> string
*
* Generates a String with _length_ number of cryptographically strong
* pseudo-random bytes.
@@ -112,9 +112,9 @@ ossl_rand_bytes(VALUE self, VALUE len)
str = rb_str_new(0, n);
ret = RAND_bytes((unsigned char *)RSTRING_PTR(str), n);
if (ret == 0) {
- ossl_raise(eRandomError, "RAND_bytes");
+ ossl_raise(eRandomError, "RAND_bytes");
} else if (ret == -1) {
- ossl_raise(eRandomError, "RAND_bytes is not supported");
+ ossl_raise(eRandomError, "RAND_bytes is not supported");
}
return str;
@@ -131,7 +131,7 @@ static VALUE
ossl_rand_egd(VALUE self, VALUE filename)
{
if (RAND_egd(StringValueCStr(filename)) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -151,7 +151,7 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
int n = NUM2INT(len);
if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -175,11 +175,6 @@ ossl_rand_status(VALUE self)
void
Init_ossl_rand(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
mRandom = rb_define_module_under(mOSSL, "Random");
eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError);
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index db44c423f2..3d913a3968 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -25,7 +25,7 @@
#endif
#define GetSSLCTX(obj, ctx) do { \
- TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
+ TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
} while (0)
VALUE mSSL;
@@ -36,19 +36,18 @@ VALUE cSSLSocket;
static VALUE eSSLErrorWaitReadable;
static VALUE eSSLErrorWaitWritable;
-static ID id_call, ID_callback_state, id_tmp_dh_callback,
- id_npn_protocols_encoded, id_each;
+static ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each;
static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode,
- id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
- id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
- id_i_client_cert_cb, id_i_timeout,
- id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
- id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
- id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
- id_i_verify_hostname, id_i_keylog_cb;
-static ID id_i_io, id_i_context, id_i_hostname;
+ id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
+ id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
+ id_i_client_cert_cb, id_i_timeout,
+ id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
+ id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
+ id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
+ id_i_verify_hostname, id_i_keylog_cb, id_i_tmp_dh_callback;
+static ID id_i_io, id_i_context, id_i_hostname, id_i_sync_close;
static int ossl_ssl_ex_ptr_idx;
static int ossl_sslctx_ex_ptr_idx;
@@ -79,9 +78,9 @@ ossl_sslctx_s_alloc(VALUE klass)
{
SSL_CTX *ctx;
long mode = 0 |
- SSL_MODE_ENABLE_PARTIAL_WRITE |
- SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
- SSL_MODE_RELEASE_BUFFERS;
+ SSL_MODE_ENABLE_PARTIAL_WRITE |
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
+ SSL_MODE_RELEASE_BUFFERS;
VALUE obj;
obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0);
@@ -90,8 +89,10 @@ ossl_sslctx_s_alloc(VALUE klass)
ossl_raise(eSSLError, "SSL_CTX_new");
}
SSL_CTX_set_mode(ctx, mode);
+ SSL_CTX_set_dh_auto(ctx, 1);
RTYPEDDATA_DATA(obj) = ctx;
- SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj);
+ if (!SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj))
+ ossl_raise(eSSLError, "SSL_CTX_set_ex_data");
return obj;
}
@@ -104,7 +105,7 @@ ossl_call_client_cert_cb(VALUE obj)
ctx_obj = rb_attr_get(obj, id_i_context);
cb = rb_attr_get(ctx_obj, id_i_client_cert_cb);
if (NIL_P(cb))
- return Qnil;
+ return Qnil;
ary = rb_funcallv(cb, id_call, 1, &obj);
Check_Type(ary, T_ARRAY);
@@ -122,7 +123,7 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
ret = rb_protect(ossl_call_client_cert_cb, obj, NULL);
if (NIL_P(ret))
- return 0;
+ return 0;
*x509 = DupX509CertPtr(RARRAY_AREF(ret, 0));
*pkey = DupPKeyPtr(RARRAY_AREF(ret, 1));
@@ -133,8 +134,6 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
#if !defined(OPENSSL_NO_DH)
struct tmp_dh_callback_args {
VALUE ssl_obj;
- ID id;
- int type;
int is_export;
int keylength;
};
@@ -143,48 +142,36 @@ static VALUE
ossl_call_tmp_dh_callback(VALUE arg)
{
struct tmp_dh_callback_args *args = (struct tmp_dh_callback_args *)arg;
- VALUE cb, dh;
- EVP_PKEY *pkey;
+ VALUE ctx_obj, cb, obj;
+ const DH *dh;
- cb = rb_funcall(args->ssl_obj, args->id, 0);
+ ctx_obj = rb_attr_get(args->ssl_obj, id_i_context);
+ cb = rb_attr_get(ctx_obj, id_i_tmp_dh_callback);
if (NIL_P(cb))
- return (VALUE)NULL;
- dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
- INT2NUM(args->keylength));
- pkey = GetPKeyPtr(dh);
- if (EVP_PKEY_base_id(pkey) != args->type)
- return (VALUE)NULL;
+ return (VALUE)NULL;
+
+ obj = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
+ INT2NUM(args->keylength));
+ // TODO: We should riase if obj is not DH
+ dh = EVP_PKEY_get0_DH(GetPKeyPtr(obj));
+ if (!dh)
+ ossl_clear_error();
- return (VALUE)pkey;
+ return (VALUE)dh;
}
-#endif
-#if !defined(OPENSSL_NO_DH)
static DH *
ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
{
- VALUE rb_ssl;
- EVP_PKEY *pkey;
- struct tmp_dh_callback_args args;
int state;
-
- rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
- args.ssl_obj = rb_ssl;
- args.id = id_tmp_dh_callback;
- args.is_export = is_export;
- args.keylength = keylength;
- args.type = EVP_PKEY_DH;
-
- pkey = (EVP_PKEY *)rb_protect(ossl_call_tmp_dh_callback,
- (VALUE)&args, &state);
+ VALUE rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+ struct tmp_dh_callback_args args = {rb_ssl, is_export, keylength};
+ VALUE ret = rb_protect(ossl_call_tmp_dh_callback, (VALUE)&args, &state);
if (state) {
- rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));
- return NULL;
+ rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));
+ return NULL;
}
- if (!pkey)
- return NULL;
-
- return (DH *)EVP_PKEY_get0_DH(pkey);
+ return (DH *)ret;
}
#endif /* OPENSSL_NO_DH */
@@ -200,13 +187,13 @@ call_verify_certificate_identity(VALUE ctx_v)
hostname = rb_attr_get(ssl_obj, id_i_hostname);
if (!RTEST(hostname)) {
- rb_warning("verify_hostname requires hostname to be set");
- return Qtrue;
+ rb_warning("verify_hostname requires hostname to be set");
+ return Qtrue;
}
cert_obj = ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
return rb_funcall(mSSL, rb_intern("verify_certificate_identity"), 2,
- cert_obj, hostname);
+ cert_obj, hostname);
}
static int
@@ -223,12 +210,12 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
verify_hostname = rb_attr_get(sslctx_obj, id_i_verify_hostname);
if (preverify_ok && RTEST(verify_hostname) && !SSL_is_server(ssl) &&
- !X509_STORE_CTX_get_error_depth(ctx)) {
- ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);
- if (status) {
- rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
- return 0;
- }
+ !X509_STORE_CTX_get_error_depth(ctx)) {
+ ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);
+ if (status) {
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
+ return 0;
+ }
if (ret != Qtrue) {
preverify_ok = 0;
X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH);
@@ -399,7 +386,7 @@ ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
* when SSL_CTX_free() is called.
*/
if (rb_during_gc())
- return;
+ return;
OSSL_Debug("SSL SESSION remove callback entered");
@@ -430,8 +417,9 @@ ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
GetSSLCTX(arg, ctx);
x509 = DupX509CertPtr(i);
- if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){
- ossl_raise(eSSLError, NULL);
+ if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
+ X509_free(x509);
+ ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert");
}
return i;
@@ -461,8 +449,8 @@ ossl_call_servername_cb(VALUE arg)
ossl_raise(eSSLError, "SSL_set_SSL_CTX");
rb_ivar_set(ssl_obj, id_i_context, ret_obj);
} else if (!NIL_P(ret_obj)) {
- ossl_raise(rb_eArgError, "servername_cb must return an "
- "OpenSSL::SSL::SSLContext object or nil");
+ ossl_raise(rb_eArgError, "servername_cb must return an "
+ "OpenSSL::SSL::SSLContext object or nil");
}
return Qnil;
@@ -502,7 +490,7 @@ ssl_npn_encode_protocol_i(RB_BLOCK_CALL_FUNC_ARGLIST(cur, encoded))
int len = RSTRING_LENINT(cur);
char len_byte;
if (len < 1 || len > 255)
- ossl_raise(eSSLError, "Advertised protocol must have length 1..255");
+ ossl_raise(eSSLError, "Advertised protocol must have length 1..255");
/* Encode the length byte */
len_byte = len;
rb_str_buf_cat(encoded, &len_byte, 1);
@@ -536,16 +524,16 @@ npn_select_cb_common_i(VALUE tmp)
/* assume OpenSSL verifies this format */
/* The format is len_1|proto_1|...|len_n|proto_n */
while (in < in_end) {
- l = *in++;
- rb_ary_push(protocols, rb_str_new((const char *)in, l));
- in += l;
+ l = *in++;
+ rb_ary_push(protocols, rb_str_new((const char *)in, l));
+ in += l;
}
selected = rb_funcallv(args->cb, id_call, 1, &protocols);
StringValue(selected);
len = RSTRING_LEN(selected);
if (len < 1 || len >= 256) {
- ossl_raise(eSSLError, "Selected protocol name must have length 1..255");
+ ossl_raise(eSSLError, "Selected protocol name must have length 1..255");
}
return selected;
@@ -553,8 +541,8 @@ npn_select_cb_common_i(VALUE tmp)
static int
ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
- unsigned char *outlen, const unsigned char *in,
- unsigned int inlen)
+ unsigned char *outlen, const unsigned char *in,
+ unsigned int inlen)
{
VALUE selected;
int status;
@@ -566,10 +554,10 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
selected = rb_protect(npn_select_cb_common_i, (VALUE)&args, &status);
if (status) {
- VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+ VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
- rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
- return SSL_TLSEXT_ERR_ALERT_FATAL;
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
*out = (unsigned char *)RSTRING_PTR(selected);
@@ -581,7 +569,7 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
#ifdef OSSL_USE_NEXTPROTONEG
static int
ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,
- void *arg)
+ void *arg)
{
VALUE protocols = rb_attr_get((VALUE)arg, id_npn_protocols_encoded);
@@ -593,7 +581,7 @@ ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,
static int
ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
+ const unsigned char *in, unsigned int inlen, void *arg)
{
VALUE sslctx_obj, cb;
@@ -601,13 +589,13 @@ ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
cb = rb_attr_get(sslctx_obj, id_i_npn_select_cb);
return ssl_npn_select_cb_common(ssl, cb, (const unsigned char **)out,
- outlen, in, inlen);
+ outlen, in, inlen);
}
#endif
static int
ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
+ const unsigned char *in, unsigned int inlen, void *arg)
{
VALUE sslctx_obj, cb;
@@ -624,7 +612,7 @@ ssl_info_cb(const SSL *ssl, int where, int val)
int is_server = SSL_is_server((SSL *)ssl);
if (is_server && where & SSL_CB_HANDSHAKE_START) {
- ssl_renegotiation_cb(ssl);
+ ssl_renegotiation_cb(ssl);
}
}
@@ -670,9 +658,9 @@ ossl_sslctx_set_options(VALUE self, VALUE options)
SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx));
if (NIL_P(options)) {
- SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ SSL_CTX_set_options(ctx, SSL_OP_ALL);
} else {
- SSL_CTX_set_options(ctx, NUM2ULONG(options));
+ SSL_CTX_set_options(ctx, NUM2ULONG(options));
}
return self;
@@ -702,7 +690,10 @@ ossl_sslctx_setup(VALUE self)
GetSSLCTX(self, ctx);
#if !defined(OPENSSL_NO_DH)
- SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+ if (!NIL_P(rb_attr_get(self, id_i_tmp_dh_callback))) {
+ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+ SSL_CTX_set_dh_auto(ctx, 0);
+ }
#endif
#if !defined(OPENSSL_IS_AWSLC) /* AWS-LC has no support for TLS 1.3 PHA. */
@@ -711,14 +702,14 @@ ossl_sslctx_setup(VALUE self)
val = rb_attr_get(self, id_i_cert_store);
if (!NIL_P(val)) {
- X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
- SSL_CTX_set_cert_store(ctx, store);
- X509_STORE_up_ref(store);
+ X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
+ SSL_CTX_set_cert_store(ctx, store);
+ X509_STORE_up_ref(store);
}
val = rb_attr_get(self, id_i_extra_chain_cert);
if(!NIL_P(val)){
- rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
+ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
}
/* private key may be bundled in certificate file. */
@@ -742,22 +733,22 @@ ossl_sslctx_setup(VALUE self)
val = rb_attr_get(self, id_i_client_ca);
if(!NIL_P(val)){
- if (RB_TYPE_P(val, T_ARRAY)) {
- for(i = 0; i < RARRAY_LEN(val); i++){
- client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
- if (!SSL_CTX_add_client_CA(ctx, client_ca)){
- /* Copies X509_NAME => FREE it. */
- ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
- }
- }
+ if (RB_TYPE_P(val, T_ARRAY)) {
+ for(i = 0; i < RARRAY_LEN(val); i++){
+ client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
+ if (!SSL_CTX_add_client_CA(ctx, client_ca)){
+ /* Copies X509_NAME => FREE it. */
+ ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+ }
+ }
}
- else{
- client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
+ else{
+ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
- /* Copies X509_NAME => FREE it. */
- ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+ /* Copies X509_NAME => FREE it. */
+ ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
}
- }
+ }
}
val = rb_attr_get(self, id_i_ca_file);
@@ -780,7 +771,7 @@ ossl_sslctx_setup(VALUE self)
verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
if (RTEST(rb_attr_get(self, id_i_client_cert_cb)))
- SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
+ SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
val = rb_attr_get(self, id_i_timeout);
if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
@@ -791,60 +782,60 @@ ossl_sslctx_setup(VALUE self)
#ifdef OSSL_USE_NEXTPROTONEG
val = rb_attr_get(self, id_i_npn_protocols);
if (!NIL_P(val)) {
- VALUE encoded = ssl_encode_npn_protocols(val);
- rb_ivar_set(self, id_npn_protocols_encoded, encoded);
- SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);
- OSSL_Debug("SSL NPN advertise callback added");
+ VALUE encoded = ssl_encode_npn_protocols(val);
+ rb_ivar_set(self, id_npn_protocols_encoded, encoded);
+ SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);
+ OSSL_Debug("SSL NPN advertise callback added");
}
if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) {
- SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
- OSSL_Debug("SSL NPN select callback added");
+ SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
+ OSSL_Debug("SSL NPN select callback added");
}
#endif
val = rb_attr_get(self, id_i_alpn_protocols);
if (!NIL_P(val)) {
- VALUE rprotos = ssl_encode_npn_protocols(val);
+ VALUE rprotos = ssl_encode_npn_protocols(val);
- /* returns 0 on success */
- if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
- RSTRING_LENINT(rprotos)))
- ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
- OSSL_Debug("SSL ALPN values added");
+ /* returns 0 on success */
+ if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
+ RSTRING_LENINT(rprotos)))
+ ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
+ OSSL_Debug("SSL ALPN values added");
}
if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) {
- SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
- OSSL_Debug("SSL ALPN select callback added");
+ SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
+ OSSL_Debug("SSL ALPN select callback added");
}
rb_obj_freeze(self);
val = rb_attr_get(self, id_i_session_id_context);
if (!NIL_P(val)){
- StringValue(val);
- if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
- RSTRING_LENINT(val))){
- ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
- }
+ StringValue(val);
+ if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
+ RSTRING_LENINT(val))){
+ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
+ }
}
if (RTEST(rb_attr_get(self, id_i_session_get_cb))) {
- SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
- OSSL_Debug("SSL SESSION get callback added");
+ SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
+ OSSL_Debug("SSL SESSION get callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_new_cb))) {
- SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
- OSSL_Debug("SSL SESSION new callback added");
+ SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
+ OSSL_Debug("SSL SESSION new callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) {
- SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
- OSSL_Debug("SSL SESSION remove callback added");
+ SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
+ OSSL_Debug("SSL SESSION remove callback added");
}
val = rb_attr_get(self, id_i_servername_cb);
if (!NIL_P(val)) {
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
- OSSL_Debug("SSL TLSEXT servername callback added");
+ OSSL_Debug("SSL TLSEXT servername callback added");
}
#if !OSSL_IS_LIBRESSL
@@ -867,28 +858,28 @@ parse_proto_version(VALUE str)
{
int i;
static const struct {
- const char *name;
- int version;
+ const char *name;
+ int version;
} map[] = {
- { "SSL2", SSL2_VERSION },
- { "SSL3", SSL3_VERSION },
- { "TLS1", TLS1_VERSION },
- { "TLS1_1", TLS1_1_VERSION },
- { "TLS1_2", TLS1_2_VERSION },
- { "TLS1_3", TLS1_3_VERSION },
+ { "SSL2", SSL2_VERSION },
+ { "SSL3", SSL3_VERSION },
+ { "TLS1", TLS1_VERSION },
+ { "TLS1_1", TLS1_1_VERSION },
+ { "TLS1_2", TLS1_2_VERSION },
+ { "TLS1_3", TLS1_3_VERSION },
};
if (NIL_P(str))
- return 0;
+ return 0;
if (RB_INTEGER_TYPE_P(str))
- return NUM2INT(str);
+ return NUM2INT(str);
if (SYMBOL_P(str))
- str = rb_sym2str(str);
+ str = rb_sym2str(str);
StringValue(str);
for (i = 0; i < numberof(map); i++)
- if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))
- return map[i].version;
+ if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))
+ return map[i].version;
rb_raise(rb_eArgError, "unrecognized version %+"PRIsVALUE, str);
}
@@ -998,11 +989,10 @@ static VALUE
build_cipher_string(VALUE v)
{
VALUE str, elem;
- int i;
if (RB_TYPE_P(v, T_ARRAY)) {
str = rb_str_new(0, 0);
- for (i = 0; i < RARRAY_LEN(v); i++) {
+ for (long i = 0; i < RARRAY_LEN(v); i++) {
elem = rb_ary_entry(v, i);
if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
elem = rb_String(elem);
@@ -1023,9 +1013,14 @@ build_cipher_string(VALUE v)
* ctx.ciphers = [name, ...]
* ctx.ciphers = [[name, version, bits, alg_bits], ...]
*
- * Sets the list of available cipher suites for this context. Note in a server
- * context some ciphers require the appropriate certificates. For example, an
- * RSA cipher suite can only be chosen when an RSA certificate is available.
+ * Sets the list of available cipher suites for TLS 1.2 and below for this
+ * context.
+ *
+ * Note in a server context some ciphers require the appropriate certificates.
+ * For example, an RSA cipher suite can only be chosen when an RSA certificate
+ * is available.
+ *
+ * This method does not affect TLS 1.3 connections. See also #ciphersuites=.
*/
static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
@@ -1034,6 +1029,7 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
VALUE str;
rb_check_frozen(self);
+ // Assigning nil is a no-op for compatibility
if (NIL_P(v))
return v;
@@ -1050,9 +1046,8 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
* call-seq:
* ctx.ciphersuites = "cipher1:cipher2:..."
* ctx.ciphersuites = [name, ...]
- * ctx.ciphersuites = [[name, version, bits, alg_bits], ...]
*
- * Sets the list of available TLSv1.3 cipher suites for this context.
+ * Sets the list of available TLS 1.3 cipher suites for this context.
*/
static VALUE
ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
@@ -1061,6 +1056,7 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
VALUE str;
rb_check_frozen(self);
+ // Assigning nil is a no-op for compatibility
if (NIL_P(v))
return v;
@@ -1073,6 +1069,63 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
return v;
}
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST
+/*
+ * call-seq:
+ * ctx.sigalgs = "sigalg1:sigalg2:..."
+ *
+ * Sets the list of "supported signature algorithms" for this context.
+ *
+ * For a TLS client, the list is used in the "signature_algorithms" extension
+ * in the ClientHello message. For a server, the list is used by OpenSSL to
+ * determine the set of shared signature algorithms. OpenSSL will pick the most
+ * appropriate one from it.
+ *
+ * See also #client_sigalgs= for the client authentication equivalent.
+ */
+static VALUE
+ossl_sslctx_set_sigalgs(VALUE self, VALUE v)
+{
+ SSL_CTX *ctx;
+
+ rb_check_frozen(self);
+ GetSSLCTX(self, ctx);
+
+ if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v)))
+ ossl_raise(eSSLError, "SSL_CTX_set1_sigalgs_list");
+
+ return v;
+}
+#endif
+
+#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST
+/*
+ * call-seq:
+ * ctx.client_sigalgs = "sigalg1:sigalg2:..."
+ *
+ * Sets the list of "supported signature algorithms" for client authentication
+ * for this context.
+ *
+ * For a TLS server, the list is sent to the client as part of the
+ * CertificateRequest message.
+ *
+ * See also #sigalgs= for the server authentication equivalent.
+ */
+static VALUE
+ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
+{
+ SSL_CTX *ctx;
+
+ rb_check_frozen(self);
+ GetSSLCTX(self, ctx);
+
+ if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v)))
+ ossl_raise(eSSLError, "SSL_CTX_set1_client_sigalgs_list");
+
+ return v;
+}
+#endif
+
#ifndef OPENSSL_NO_DH
/*
* call-seq:
@@ -1085,7 +1138,7 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
* contained in the key object, if any, are ignored. The server will always
* generate a new key pair for each handshake.
*
- * Added in version 3.0. See also the man page SSL_set0_tmp_dh_pkey(3).
+ * Added in version 3.0. See also the man page SSL_CTX_set0_tmp_dh_pkey(3).
*
* Example:
* ctx = OpenSSL::SSL::SSLContext.new
@@ -1106,7 +1159,7 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH)
rb_raise(eSSLError, "invalid pkey type %s (expected DH)",
OBJ_nid2sn(EVP_PKEY_base_id(pkey)));
-#ifdef HAVE_SSL_SET0_TMP_DH_PKEY
+#ifdef HAVE_SSL_CTX_SET0_TMP_DH_PKEY
if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
ossl_raise(eSSLError, "SSL_CTX_set0_tmp_dh_pkey");
EVP_PKEY_up_ref(pkey);
@@ -1115,29 +1168,36 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
ossl_raise(eSSLError, "SSL_CTX_set_tmp_dh");
#endif
+ // Turn off the "auto" DH parameters set by ossl_sslctx_s_alloc()
+ SSL_CTX_set_dh_auto(ctx, 0);
+
return arg;
}
#endif
-#if !defined(OPENSSL_NO_EC)
/*
* call-seq:
- * ctx.ecdh_curves = curve_list -> curve_list
+ * ctx.groups = groups_list
+ * ctx.ecdh_curves = groups_list
+ *
+ * Sets the list of supported groups for key agreement for this context.
*
- * Sets the list of "supported elliptic curves" for this context.
+ * For a TLS client, the list is directly used in the "supported_groups"
+ * extension. For a server, the list is used by OpenSSL to determine the set of
+ * shared supported groups. OpenSSL will pick the most appropriate one from it.
*
- * For a TLS client, the list is directly used in the Supported Elliptic Curves
- * Extension. For a server, the list is used by OpenSSL to determine the set of
- * shared curves. OpenSSL will pick the most appropriate one from it.
+ * #ecdh_curves= is a deprecated alias for #groups=.
+ *
+ * See also the man page SSL_CTX_set1_groups_list(3).
*
* === Example
* ctx1 = OpenSSL::SSL::SSLContext.new
- * ctx1.ecdh_curves = "X25519:P-256:P-224"
+ * ctx1.groups = "X25519:P-256:P-224"
* svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)
* Thread.new { svr.accept }
*
* ctx2 = OpenSSL::SSL::SSLContext.new
- * ctx2.ecdh_curves = "P-256"
+ * ctx2.groups = "P-256"
* cli = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx2)
* cli.connect
*
@@ -1145,7 +1205,7 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
* # => "prime256v1" (is an alias for NIST P-256)
*/
static VALUE
-ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
+ossl_sslctx_set_groups(VALUE self, VALUE arg)
{
SSL_CTX *ctx;
@@ -1153,13 +1213,10 @@ ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
GetSSLCTX(self, ctx);
StringValueCStr(arg);
- if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
- ossl_raise(eSSLError, NULL);
+ if (!SSL_CTX_set1_groups_list(ctx, RSTRING_PTR(arg)))
+ ossl_raise(eSSLError, "SSL_CTX_set1_groups_list");
return arg;
}
-#else
-#define ossl_sslctx_set_ecdh_curves rb_f_notimplement
-#endif
/*
* call-seq:
@@ -1288,20 +1345,20 @@ ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
pub_pkey = X509_get_pubkey(x509);
EVP_PKEY_free(pub_pkey);
if (!pub_pkey)
- rb_raise(rb_eArgError, "certificate does not contain public key");
+ rb_raise(rb_eArgError, "certificate does not contain public key");
if (EVP_PKEY_eq(pub_pkey, pkey) != 1)
- rb_raise(rb_eArgError, "public key mismatch");
+ rb_raise(rb_eArgError, "public key mismatch");
if (argc >= 3)
- extra_chain = ossl_x509_ary2sk(extra_chain_ary);
+ extra_chain = ossl_x509_ary2sk(extra_chain_ary);
if (!SSL_CTX_use_certificate(ctx, x509)) {
- sk_X509_pop_free(extra_chain, X509_free);
- ossl_raise(eSSLError, "SSL_CTX_use_certificate");
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_certificate");
}
if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
- sk_X509_pop_free(extra_chain, X509_free);
- ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
}
if (extra_chain && !SSL_CTX_set0_chain(ctx, extra_chain)) {
sk_X509_pop_free(extra_chain, X509_free);
@@ -1534,32 +1591,31 @@ ossl_ssl_s_alloc(VALUE klass)
}
static VALUE
-peer_ip_address(VALUE self)
+peer_ip_address(VALUE io)
{
- VALUE remote_address = rb_funcall(rb_attr_get(self, id_i_io), rb_intern("remote_address"), 0);
+ VALUE remote_address = rb_funcall(io, rb_intern("remote_address"), 0);
return rb_funcall(remote_address, rb_intern("inspect_sockaddr"), 0);
}
static VALUE
-fallback_peer_ip_address(VALUE self, VALUE args)
+fallback_peer_ip_address(VALUE self, VALUE exc)
{
return rb_str_new_cstr("(null)");
}
static VALUE
-peeraddr_ip_str(VALUE self)
+peeraddr_ip_str(VALUE io)
{
- VALUE rb_mErrno = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE rb_eSystemCallError = rb_const_get(rb_mErrno, rb_intern("SystemCallError"));
-
- return rb_rescue2(peer_ip_address, self, fallback_peer_ip_address, (VALUE)0, rb_eSystemCallError, NULL);
+ return rb_rescue2(peer_ip_address, io, fallback_peer_ip_address, Qnil,
+ rb_eSystemCallError, (VALUE)0);
}
/*
* call-seq:
* SSLSocket.new(io) => aSSLSocket
* SSLSocket.new(io, ctx) => aSSLSocket
+ * SSLSocket.new(io, ctx, sync_close:) => aSSLSocket
*
* Creates a new SSL socket from _io_ which must be a real IO object (not an
* IO-like object that responds to read/write).
@@ -1567,6 +1623,10 @@ peeraddr_ip_str(VALUE self)
* If _ctx_ is provided the SSL Sockets initial params will be taken from
* the context.
*
+ * The optional _sync_close_ keyword parameter sets the _sync_close_ instance
+ * variable. Setting this to +true+ will cause the underlying socket to be
+ * closed when the SSL/TLS connection is shut down.
+ *
* The OpenSSL::Buffering module provides additional IO methods.
*
* This method will freeze the SSLContext if one is provided;
@@ -1575,32 +1635,46 @@ peeraddr_ip_str(VALUE self)
static VALUE
ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
{
+ static ID kw_ids[1];
+ VALUE kw_args[1];
+ VALUE opts;
+
VALUE io, v_ctx;
SSL *ssl;
SSL_CTX *ctx;
TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl);
if (ssl)
- ossl_raise(eSSLError, "SSL already initialized");
+ ossl_raise(eSSLError, "SSL already initialized");
- if (rb_scan_args(argc, argv, "11", &io, &v_ctx) == 1)
- v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+ if (rb_scan_args(argc, argv, "11:", &io, &v_ctx, &opts) == 1)
+ v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+
+ if (!kw_ids[0]) {
+ kw_ids[0] = rb_intern_const("sync_close");
+ }
+
+ rb_get_kwargs(opts, kw_ids, 0, 1, kw_args);
+ if (kw_args[0] != Qundef) {
+ rb_ivar_set(self, id_i_sync_close, kw_args[0]);
+ }
GetSSLCTX(v_ctx, ctx);
rb_ivar_set(self, id_i_context, v_ctx);
ossl_sslctx_setup(v_ctx);
if (rb_respond_to(io, rb_intern("nonblock=")))
- rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
+ rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
Check_Type(io, T_FILE);
rb_ivar_set(self, id_i_io, io);
ssl = SSL_new(ctx);
if (!ssl)
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, NULL);
RTYPEDDATA_DATA(self) = ssl;
- SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
+ if (!SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self))
+ ossl_raise(eSSLError, "SSL_set_ex_data");
SSL_set_info_callback(ssl, ssl_info_cb);
rb_call_super(0, NULL);
@@ -1628,7 +1702,7 @@ ossl_ssl_setup(VALUE self)
GetSSL(self, ssl);
if (ssl_started(ssl))
- return Qtrue;
+ return Qtrue;
io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
@@ -1640,24 +1714,28 @@ ossl_ssl_setup(VALUE self)
return Qtrue;
}
+static int
+errno_mapped(void)
+{
#ifdef _WIN32
-#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret)))
+ return rb_w32_map_errno(WSAGetLastError());
#else
-#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
+ return errno;
#endif
+}
static void
write_would_block(int nonblock)
{
if (nonblock)
- ossl_raise(eSSLErrorWaitWritable, "write would block");
+ ossl_raise(eSSLErrorWaitWritable, "write would block");
}
static void
read_would_block(int nonblock)
{
if (nonblock)
- ossl_raise(eSSLErrorWaitReadable, "read would block");
+ ossl_raise(eSSLErrorWaitReadable, "read would block");
}
static int
@@ -1665,7 +1743,7 @@ no_exception_p(VALUE opts)
{
if (RB_TYPE_P(opts, T_HASH) &&
rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse)
- return 1;
+ return 1;
return 0;
}
@@ -1685,13 +1763,13 @@ static void
io_wait_writable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ if (!rb_io_wait(io, INT2NUM(RUBY_IO_WRITABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
- rb_io_wait_writable(fptr->fd);
+ rb_thread_fd_writable(fptr->fd);
#endif
}
@@ -1699,13 +1777,13 @@ static void
io_wait_readable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ if (!rb_io_wait(io, INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
- rb_io_wait_readable(fptr->fd);
+ rb_thread_wait_fd(fptr->fd);
#endif
}
@@ -1713,7 +1791,6 @@ static VALUE
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
{
SSL *ssl;
- int ret, ret2;
VALUE cb_state;
int nonblock = opts != Qfalse;
@@ -1723,7 +1800,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
VALUE io = rb_attr_get(self, id_i_io);
for (;;) {
- ret = func(ssl);
+ int ret = func(ssl);
+ int saved_errno = errno_mapped();
cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
@@ -1735,7 +1813,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
if (ret > 0)
break;
- switch ((ret2 = ssl_get_error(ssl, ret))) {
+ int code = SSL_get_error(ssl, ret);
+ switch (code) {
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
@@ -1749,10 +1828,11 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
/* See ossl_ssl_write_internal() */
- if (errno == EPROTOTYPE)
+ if (saved_errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(funcname);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, funcname));
/* fallthrough */
default: {
VALUE error_append = Qnil;
@@ -1773,10 +1853,10 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
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),
+ code == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
+ code,
+ saved_errno,
+ peeraddr_ip_str(io),
SSL_state_string_long(ssl),
error_append);
}
@@ -1889,9 +1969,9 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
VALUE opts = Qnil;
if (nonblock) {
- rb_scan_args(argc, argv, "11:", &len, &str, &opts);
+ rb_scan_args(argc, argv, "11:", &len, &str, &opts);
} else {
- rb_scan_args(argc, argv, "11", &len, &str);
+ rb_scan_args(argc, argv, "11", &len, &str);
}
GetSSL(self, ssl);
if (!ssl_started(ssl))
@@ -1899,13 +1979,13 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
ilen = NUM2INT(len);
if (NIL_P(str))
- str = rb_str_new(0, ilen);
+ str = rb_str_new(0, ilen);
else {
- StringValue(str);
- if (RSTRING_LEN(str) >= ilen)
- rb_str_modify(str);
- else
- rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
+ StringValue(str);
+ if (RSTRING_LEN(str) >= ilen)
+ rb_str_modify(str);
+ else
+ rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
}
if (ilen == 0) {
@@ -1918,6 +1998,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
for (;;) {
rb_str_locktmp(str);
int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
+ int saved_errno = errno_mapped();
rb_str_unlocktmp(str);
cb_state = rb_attr_get(self, ID_callback_state);
@@ -1927,7 +2008,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
rb_jump_tag(NUM2INT(cb_state));
}
- switch (ssl_get_error(ssl, nread)) {
+ switch (SSL_get_error(ssl, nread)) {
case SSL_ERROR_NONE:
rb_str_set_len(str, nread);
return str;
@@ -1950,8 +2031,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
break;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
- if (errno)
- rb_sys_fail(0);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, "SSL_read"));
else {
/*
* The underlying BIO returned 0. This is actually a
@@ -2036,6 +2117,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
for (;;) {
int nwritten = SSL_write(ssl, RSTRING_PTR(str), num);
+ int saved_errno = errno_mapped();
cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
@@ -2044,7 +2126,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
rb_jump_tag(NUM2INT(cb_state));
}
- switch (ssl_get_error(ssl, nwritten)) {
+ switch (SSL_get_error(ssl, nwritten)) {
case SSL_ERROR_NONE:
return INT2NUM(nwritten);
case SSL_ERROR_WANT_WRITE:
@@ -2065,10 +2147,11 @@ ossl_ssl_write_internal_safe(VALUE _args)
* make the error handling in line with the socket library.
* [Bug #14713] https://bugs.ruby-lang.org/issues/14713
*/
- if (errno == EPROTOTYPE)
+ if (saved_errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(0);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, "SSL_write"));
/* fallthrough */
default:
ossl_raise(eSSLError, "SSL_write");
@@ -2080,14 +2163,13 @@ ossl_ssl_write_internal_safe(VALUE _args)
static VALUE
ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)
{
- VALUE args[3] = {self, str, opts};
- int state;
- str = StringValue(str);
-
+ StringValue(str);
int frozen = RB_OBJ_FROZEN(str);
if (!frozen) {
- str = rb_str_locktmp(str);
+ rb_str_locktmp(str);
}
+ int state;
+ VALUE args[3] = {self, str, opts};
VALUE result = rb_protect(ossl_ssl_write_internal_safe, (VALUE)args, &state);
if (!frozen) {
rb_str_unlocktmp(str);
@@ -2114,9 +2196,12 @@ ossl_ssl_write(VALUE self, VALUE str)
/*
* call-seq:
* ssl.syswrite_nonblock(string) => Integer
+ * ssl.syswrite_nonblock(string, opts) => Integer
*
* Writes _string_ to the SSL connection in a non-blocking manner. Raises an
- * SSLError if writing would block.
+ * SSLError if writing would block. If "exception: false" is passed, this
+ * method returns a symbol of :wait_readable or :wait_writable, rather than
+ * raising an exception.
*/
static VALUE
ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self)
@@ -2143,12 +2228,12 @@ ossl_ssl_stop(VALUE self)
GetSSL(self, ssl);
if (!ssl_started(ssl))
- return Qnil;
+ return Qnil;
ret = SSL_shutdown(ssl);
if (ret == 1) /* Have already received close_notify */
- return Qnil;
+ return Qnil;
if (ret == 0) /* Sent close_notify, but we don't wait for reply */
- return Qnil;
+ return Qnil;
/*
* XXX: Something happened. Possibly it failed because the underlying socket
@@ -2234,20 +2319,20 @@ ossl_ssl_get_peer_cert_chain(VALUE self)
num = sk_X509_num(chain);
ary = rb_ary_new2(num);
for (i = 0; i < num; i++){
- cert = sk_X509_value(chain, i);
- rb_ary_push(ary, ossl_x509_new(cert));
+ cert = sk_X509_value(chain, i);
+ rb_ary_push(ary, ossl_x509_new(cert));
}
return ary;
}
/*
-* call-seq:
-* ssl.ssl_version => String
-*
-* Returns a String representing the SSL/TLS version that was negotiated
-* for the connection, for example "TLSv1.2".
-*/
+ * call-seq:
+ * ssl.ssl_version => String
+ *
+ * Returns a String representing the SSL/TLS version that was negotiated
+ * for the connection, for example "TLSv1.2".
+ */
static VALUE
ossl_ssl_get_version(VALUE self)
{
@@ -2368,10 +2453,10 @@ ossl_ssl_set_hostname(VALUE self, VALUE arg)
GetSSL(self, ssl);
if (!NIL_P(arg))
- hostname = StringValueCStr(arg);
+ hostname = StringValueCStr(arg);
if (!SSL_set_tlsext_host_name(ssl, hostname))
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, NULL);
/* for SSLSocket#hostname */
rb_ivar_set(self, id_i_hostname, arg);
@@ -2400,16 +2485,15 @@ ossl_ssl_get_verify_result(VALUE self)
/*
* call-seq:
- * ssl.finished_message => "finished message"
- *
- * Returns the last *Finished* message sent
+ * ssl.finished_message -> string or nil
*
+ * Returns the contents of the last +Finished+ message sent to the peer.
*/
static VALUE
ossl_ssl_get_finished(VALUE self)
{
SSL *ssl;
- char sizer[1], *buf;
+ char sizer[1];
size_t len;
GetSSL(self, ssl);
@@ -2418,23 +2502,23 @@ ossl_ssl_get_finished(VALUE self)
if (len == 0)
return Qnil;
- buf = ALLOCA_N(char, len);
- SSL_get_finished(ssl, buf, len);
- return rb_str_new(buf, len);
+ VALUE str = rb_str_new(NULL, len);
+ SSL_get_finished(ssl, RSTRING_PTR(str), len);
+ return str;
}
/*
* call-seq:
- * ssl.peer_finished_message => "peer finished message"
- *
- * Returns the last *Finished* message received
+ * ssl.peer_finished_message -> string or nil
*
+ * Returns the contents of the last +Finished+ message expected to be sent
+ * by the peer.
*/
static VALUE
ossl_ssl_get_peer_finished(VALUE self)
{
SSL *ssl;
- char sizer[1], *buf;
+ char sizer[1];
size_t len;
GetSSL(self, ssl);
@@ -2443,9 +2527,9 @@ ossl_ssl_get_peer_finished(VALUE self)
if (len == 0)
return Qnil;
- buf = ALLOCA_N(char, len);
- SSL_get_peer_finished(ssl, buf, len);
- return rb_str_new(buf, len);
+ VALUE str = rb_str_new(NULL, len);
+ SSL_get_peer_finished(ssl, RSTRING_PTR(str), len);
+ return str;
}
/*
@@ -2492,9 +2576,9 @@ ossl_ssl_npn_protocol(VALUE self)
SSL_get0_next_proto_negotiated(ssl, &out, &outlen);
if (!outlen)
- return Qnil;
+ return Qnil;
else
- return rb_str_new((const char *) out, outlen);
+ return rb_str_new((const char *) out, outlen);
}
# endif
@@ -2516,9 +2600,9 @@ ossl_ssl_alpn_protocol(VALUE self)
SSL_get0_alpn_selected(ssl, &out, &outlen);
if (!outlen)
- return Qnil;
+ return Qnil;
else
- return rb_str_new((const char *) out, outlen);
+ return rb_str_new((const char *) out, outlen);
}
/*
@@ -2551,15 +2635,15 @@ ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self)
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (!NIL_P(context)) {
- use_ctx = 1;
- StringValue(context);
- ctx = (unsigned char *)RSTRING_PTR(context);
- ctx_len = RSTRING_LEN(context);
+ use_ctx = 1;
+ StringValue(context);
+ ctx = (unsigned char *)RSTRING_PTR(context);
+ ctx_len = RSTRING_LEN(context);
}
ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label),
- RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
+ RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
if (ret == 0 || ret == -1) {
- ossl_raise(eSSLError, "SSL_export_keying_material");
+ ossl_raise(eSSLError, "SSL_export_keying_material");
}
return str;
}
@@ -2578,17 +2662,77 @@ ossl_ssl_tmp_key(VALUE self)
GetSSL(self, ssl);
if (!SSL_get_server_tmp_key(ssl, &key))
- return Qnil;
- return ossl_pkey_new(key);
+ return Qnil;
+ return ossl_pkey_wrap(key);
+}
+
+#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME
+/*
+ * call-seq:
+ * ssl.sigalg => String or nil
+ *
+ * Returns the signature algorithm name, the IANA name of the signature scheme
+ * used by the local to sign the TLS handshake.
+ */
+static VALUE
+ossl_ssl_get_sigalg(VALUE self)
+{
+ SSL *ssl;
+ const char *name;
+
+ GetSSL(self, ssl);
+ if (!SSL_get0_signature_name(ssl, &name))
+ return Qnil;
+ return rb_str_new_cstr(name);
+}
+
+/*
+ * call-seq:
+ * ssl.peer_sigalg => String or nil
+ *
+ * Returns the signature algorithm name, the IANA name of the signature scheme
+ * used by the peer to sign the TLS handshake.
+ */
+static VALUE
+ossl_ssl_get_peer_sigalg(VALUE self)
+{
+ SSL *ssl;
+ const char *name;
+
+ GetSSL(self, ssl);
+ if (!SSL_get0_peer_signature_name(ssl, &name))
+ return Qnil;
+ return rb_str_new_cstr(name);
}
+#endif
+
+#ifdef HAVE_SSL_GET0_GROUP_NAME
+/*
+ * call-seq:
+ * ssl.group => String or nil
+ *
+ * Returns the name of the group that was used for the key agreement of the
+ * current TLS session establishment.
+ */
+static VALUE
+ossl_ssl_get_group(VALUE self)
+{
+ SSL *ssl;
+ const char *name;
+
+ GetSSL(self, ssl);
+ if (!(name = SSL_get0_group_name(ssl)))
+ return Qnil;
+ return rb_str_new_cstr(name);
+}
+#endif
+
#endif /* !defined(OPENSSL_NO_SOCK) */
void
Init_ossl_ssl(void)
{
#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
#endif
@@ -2599,10 +2743,10 @@ Init_ossl_ssl(void)
ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_ptr_idx", 0, 0, 0);
if (ossl_ssl_ex_ptr_idx < 0)
- ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
+ ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_ptr_idx", 0, 0, 0);
if (ossl_sslctx_ex_ptr_idx < 0)
- ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
+ ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
/* Document-module: OpenSSL::SSL
*
@@ -2740,6 +2884,23 @@ Init_ossl_ssl(void)
*/
rb_attr(cSSLContext, rb_intern_const("client_cert_cb"), 1, 1, Qfalse);
+#ifndef OPENSSL_NO_DH
+ /*
+ * A callback invoked when DH parameters are required for ephemeral DH key
+ * exchange.
+ *
+ * The callback is invoked with the SSLSocket, a
+ * flag indicating the use of an export cipher and the keylength
+ * required.
+ *
+ * The callback must return an OpenSSL::PKey::DH instance of the correct
+ * key length.
+ *
+ * <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
+ */
+ rb_attr(cSSLContext, rb_intern_const("tmp_dh_callback"), 1, 1, Qfalse);
+#endif
+
/*
* Sets the context in which a session can be reused. This allows
* sessions for multiple applications to be distinguished, for example, by
@@ -2887,10 +3048,17 @@ Init_ossl_ssl(void)
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1);
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST // Not in LibreSSL yet
+ rb_define_method(cSSLContext, "sigalgs=", ossl_sslctx_set_sigalgs, 1);
+#endif
+#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST // Not in LibreSSL or AWS-LC yet
+ rb_define_method(cSSLContext, "client_sigalgs=", ossl_sslctx_set_client_sigalgs, 1);
+#endif
#ifndef OPENSSL_NO_DH
rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
#endif
- rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
+ rb_define_method(cSSLContext, "groups=", ossl_sslctx_set_groups, 1);
+ rb_define_alias(cSSLContext, "ecdh_curves=", "groups=");
rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
#ifdef SSL_MODE_SEND_FALLBACK_SCSV
@@ -2997,6 +3165,13 @@ Init_ossl_ssl(void)
# ifdef OSSL_USE_NEXTPROTONEG
rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0);
# endif
+#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME
+ rb_define_method(cSSLSocket, "sigalg", ossl_ssl_get_sigalg, 0);
+ rb_define_method(cSSLSocket, "peer_sigalg", ossl_ssl_get_peer_sigalg, 0);
+#endif
+#ifdef HAVE_SSL_GET0_GROUP_NAME
+ rb_define_method(cSSLSocket, "group", ossl_ssl_get_group, 0);
+#endif
rb_define_const(mSSL, "VERIFY_NONE", INT2NUM(SSL_VERIFY_NONE));
rb_define_const(mSSL, "VERIFY_PEER", INT2NUM(SSL_VERIFY_PEER));
@@ -3119,7 +3294,6 @@ Init_ossl_ssl(void)
sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
- id_tmp_dh_callback = rb_intern_const("tmp_dh_callback");
id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded");
id_each = rb_intern_const("each");
@@ -3150,9 +3324,11 @@ Init_ossl_ssl(void)
DefIVarID(servername_cb);
DefIVarID(verify_hostname);
DefIVarID(keylog_cb);
+ DefIVarID(tmp_dh_callback);
DefIVarID(io);
DefIVarID(context);
DefIVarID(hostname);
+ DefIVarID(sync_close);
#endif /* !defined(OPENSSL_NO_SOCK) */
}
diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h
index a92985c601..a87e62d450 100644
--- a/ext/openssl/ossl_ssl.h
+++ b/ext/openssl/ossl_ssl.h
@@ -11,17 +11,17 @@
#define _OSSL_SSL_H_
#define GetSSL(obj, ssl) do { \
- TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
- if (!(ssl)) { \
- ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
- } \
+ TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
+ if (!(ssl)) { \
+ ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
+ } \
} while (0)
#define GetSSLSession(obj, sess) do { \
- TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
- if (!(sess)) { \
- ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
- } \
+ TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
+ if (!(sess)) { \
+ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+ } \
} while (0)
extern const rb_data_type_t ossl_ssl_type;
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
index 55b9d6c6d5..8a2fbf4100 100644
--- a/ext/openssl/ossl_ssl_session.c
+++ b/ext/openssl/ossl_ssl_session.c
@@ -17,14 +17,14 @@ ossl_ssl_session_free(void *ptr)
const rb_data_type_t ossl_ssl_session_type = {
"OpenSSL/SSL/Session",
{
- 0, ossl_ssl_session_free,
+ 0, ossl_ssl_session_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE ossl_ssl_session_alloc(VALUE klass)
{
- return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
+ return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
}
/*
@@ -80,9 +80,9 @@ ossl_ssl_session_initialize_copy(VALUE self, VALUE other)
GetSSLSession(other, sess_other);
sess_new = ASN1_dup((i2d_of_void *)i2d_SSL_SESSION, (d2i_of_void *)d2i_SSL_SESSION,
- (char *)sess_other);
+ (char *)sess_other);
if (!sess_new)
- ossl_raise(eSSLSession, "ASN1_dup");
+ ossl_raise(eSSLSession, "ASN1_dup");
RTYPEDDATA_DATA(self) = sess_new;
SSL_SESSION_free(sess);
@@ -99,9 +99,9 @@ ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
const unsigned char *b_sid = SSL_SESSION_get_id(b, &b_len);
if (SSL_SESSION_get_protocol_version(a) != SSL_SESSION_get_protocol_version(b))
- return 1;
+ return 1;
if (a_len != b_len)
- return 1;
+ return 1;
return CRYPTO_memcmp(a_sid, b_sid, a_len);
}
@@ -114,15 +114,15 @@ ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
*/
static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)
{
- SSL_SESSION *ctx1, *ctx2;
+ SSL_SESSION *ctx1, *ctx2;
- GetSSLSession(val1, ctx1);
- GetSSLSession(val2, ctx2);
+ GetSSLSession(val1, ctx1);
+ GetSSLSession(val2, ctx2);
- switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {
- case 0: return Qtrue;
- default: return Qfalse;
- }
+ switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {
+ case 0: return Qtrue;
+ default: return Qfalse;
+ }
}
/*
@@ -140,7 +140,7 @@ ossl_ssl_session_get_time(VALUE self)
GetSSLSession(self, ctx);
t = SSL_SESSION_get_time(ctx);
if (t == 0)
- return Qnil;
+ return Qnil;
return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t));
}
@@ -175,16 +175,16 @@ ossl_ssl_session_get_timeout(VALUE self)
*/
static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
{
- SSL_SESSION *ctx;
- long t;
-
- GetSSLSession(self, ctx);
- if (rb_obj_is_instance_of(time_v, rb_cTime)) {
- time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
- }
- t = NUM2LONG(time_v);
- SSL_SESSION_set_time(ctx, t);
- return ossl_ssl_session_get_time(self);
+ SSL_SESSION *ctx;
+ long t;
+
+ GetSSLSession(self, ctx);
+ if (rb_obj_is_instance_of(time_v, rb_cTime)) {
+ time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
+ }
+ t = NUM2LONG(time_v);
+ SSL_SESSION_set_time(ctx, t);
+ return ossl_ssl_session_get_time(self);
}
/*
@@ -195,13 +195,13 @@ static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
*/
static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
{
- SSL_SESSION *ctx;
- long t;
+ SSL_SESSION *ctx;
+ long t;
- GetSSLSession(self, ctx);
- t = NUM2LONG(time_v);
- SSL_SESSION_set_timeout(ctx, t);
- return ossl_ssl_session_get_timeout(self);
+ GetSSLSession(self, ctx);
+ t = NUM2LONG(time_v);
+ SSL_SESSION_set_timeout(ctx, t);
+ return ossl_ssl_session_get_timeout(self);
}
/*
@@ -209,18 +209,18 @@ static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
* session.id -> String
*
* Returns the Session ID.
-*/
+ */
static VALUE ossl_ssl_session_get_id(VALUE self)
{
- SSL_SESSION *ctx;
- const unsigned char *p = NULL;
- unsigned int i = 0;
+ SSL_SESSION *ctx;
+ const unsigned char *p = NULL;
+ unsigned int i = 0;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- p = SSL_SESSION_get_id(ctx, &i);
+ p = SSL_SESSION_get_id(ctx, &i);
- return rb_str_new((const char *) p, i);
+ return rb_str_new((const char *) p, i);
}
/*
@@ -231,22 +231,22 @@ static VALUE ossl_ssl_session_get_id(VALUE self)
*/
static VALUE ossl_ssl_session_to_der(VALUE self)
{
- SSL_SESSION *ctx;
- unsigned char *p;
- int len;
- VALUE str;
-
- GetSSLSession(self, ctx);
- len = i2d_SSL_SESSION(ctx, NULL);
- if (len <= 0) {
- ossl_raise(eSSLSession, "i2d_SSL_SESSION");
- }
-
- str = rb_str_new(0, len);
- p = (unsigned char *)RSTRING_PTR(str);
- i2d_SSL_SESSION(ctx, &p);
- ossl_str_adjust(str, p);
- return str;
+ SSL_SESSION *ctx;
+ unsigned char *p;
+ int len;
+ VALUE str;
+
+ GetSSLSession(self, ctx);
+ len = i2d_SSL_SESSION(ctx, NULL);
+ if (len <= 0) {
+ ossl_raise(eSSLSession, "i2d_SSL_SESSION");
+ }
+
+ str = rb_str_new(0, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ i2d_SSL_SESSION(ctx, &p);
+ ossl_str_adjust(str, p);
+ return str;
}
/*
@@ -257,22 +257,22 @@ static VALUE ossl_ssl_session_to_der(VALUE self)
*/
static VALUE ossl_ssl_session_to_pem(VALUE self)
{
- SSL_SESSION *ctx;
- BIO *out;
+ SSL_SESSION *ctx;
+ BIO *out;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSSLSession, "BIO_s_mem()");
- }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
- if (!PEM_write_bio_SSL_SESSION(out, ctx)) {
- BIO_free(out);
- ossl_raise(eSSLSession, "SSL_SESSION_print()");
- }
+ if (!PEM_write_bio_SSL_SESSION(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
- return ossl_membio2str(out);
+ return ossl_membio2str(out);
}
@@ -284,49 +284,44 @@ static VALUE ossl_ssl_session_to_pem(VALUE self)
*/
static VALUE ossl_ssl_session_to_text(VALUE self)
{
- SSL_SESSION *ctx;
- BIO *out;
+ SSL_SESSION *ctx;
+ BIO *out;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSSLSession, "BIO_s_mem()");
- }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
- if (!SSL_SESSION_print(out, ctx)) {
- BIO_free(out);
- ossl_raise(eSSLSession, "SSL_SESSION_print()");
- }
+ if (!SSL_SESSION_print(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
- return ossl_membio2str(out);
+ return ossl_membio2str(out);
}
#endif /* !defined(OPENSSL_NO_SOCK) */
void Init_ossl_ssl_session(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- mSSL = rb_define_module_under(mOSSL, "SSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
#ifndef OPENSSL_NO_SOCK
- cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
- eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
-
- rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
- rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
- rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1);
-
- rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
-
- rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
- rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
- rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
- rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
- rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
- rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
- rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
- rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
+ cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
+ eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
+
+ rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
+ rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
+ rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1);
+
+ rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
+
+ rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
+ rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
+ rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
+ rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
+ rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
+ rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
+ rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
+ rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
#endif /* !defined(OPENSSL_NO_SOCK) */
}
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index c7d2bd271b..317f7786aa 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -103,7 +103,7 @@ static const rb_data_type_t ossl_ts_resp_type = {
static void
ossl_ts_token_info_free(void *ptr)
{
- TS_TST_INFO_free(ptr);
+ TS_TST_INFO_free(ptr);
}
static const rb_data_type_t ossl_ts_token_info_type = {
@@ -132,44 +132,10 @@ asn1_to_der(void *template, int (*i2d)(void *template, unsigned char **pp))
return str;
}
-static ASN1_OBJECT*
-obj_to_asn1obj(VALUE obj)
-{
- ASN1_OBJECT *a1obj;
-
- StringValue(obj);
- a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);
- if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);
- if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID");
-
- return a1obj;
-}
-
static VALUE
obj_to_asn1obj_i(VALUE obj)
{
- return (VALUE)obj_to_asn1obj(obj);
-}
-
-static VALUE
-get_asn1obj(const ASN1_OBJECT *obj)
-{
- BIO *out;
- VALUE ret;
- int nid;
- if ((nid = OBJ_obj2nid(obj)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eTimestampError, "BIO_new(BIO_s_mem())");
- if (i2a_ASN1_OBJECT(out, obj) <= 0) {
- BIO_free(out);
- ossl_raise(eTimestampError, "i2a_ASN1_OBJECT");
- }
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return (VALUE)ossl_to_asn1obj(obj);
}
static VALUE
@@ -202,7 +168,7 @@ ossl_ts_req_alloc(VALUE klass)
static VALUE
ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self)
{
- TS_REQ *ts_req = DATA_PTR(self);
+ TS_REQ *req, *req_orig = DATA_PTR(self);
BIO *in;
VALUE arg;
@@ -212,13 +178,14 @@ ossl_ts_req_initialize(int argc, VALUE *argv, VALUE self)
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
- ts_req = d2i_TS_REQ_bio(in, &ts_req);
+ req = d2i_TS_REQ_bio(in, NULL);
BIO_free(in);
- if (!ts_req) {
- DATA_PTR(self) = NULL;
- ossl_raise(eTimestampError, "Error when decoding the timestamp request");
+ if (!req) {
+ ossl_raise(eTimestampError,
+ "Error when decoding the timestamp request");
}
- DATA_PTR(self) = ts_req;
+ TS_REQ_free(req_orig);
+ RTYPEDDATA_DATA(self) = req;
return self;
}
@@ -242,7 +209,7 @@ ossl_ts_req_get_algorithm(VALUE self)
mi = TS_REQ_get_msg_imprint(req);
algor = TS_MSG_IMPRINT_get_algo(mi);
X509_ALGOR_get0(&obj, NULL, NULL, algor);
- return get_asn1obj(obj);
+ return ossl_asn1obj_to_string(obj);
}
/*
@@ -264,7 +231,7 @@ ossl_ts_req_set_algorithm(VALUE self, VALUE algo)
X509_ALGOR *algor;
GetTSRequest(self, req);
- obj = obj_to_asn1obj(algo);
+ obj = ossl_to_asn1obj(algo);
mi = TS_REQ_get_msg_imprint(req);
algor = TS_MSG_IMPRINT_get_algo(mi);
if (!X509_ALGOR_set0(algor, obj, V_ASN1_NULL, NULL)) {
@@ -293,7 +260,7 @@ ossl_ts_req_get_msg_imprint(VALUE self)
mi = TS_REQ_get_msg_imprint(req);
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length);
+ ret = asn1str_to_str(hashed_msg);
return ret;
}
@@ -371,7 +338,7 @@ ossl_ts_req_get_policy_id(VALUE self)
GetTSRequest(self, req);
if (!TS_REQ_get_policy_id(req))
return Qnil;
- return get_asn1obj(TS_REQ_get_policy_id(req));
+ return ossl_asn1obj_to_string(TS_REQ_get_policy_id(req));
}
/*
@@ -394,7 +361,7 @@ ossl_ts_req_set_policy_id(VALUE self, VALUE oid)
int ok;
GetTSRequest(self, req);
- obj = obj_to_asn1obj(oid);
+ obj = ossl_to_asn1obj(oid);
ok = TS_REQ_set_policy_id(req, obj);
ASN1_OBJECT_free(obj);
if (!ok)
@@ -504,7 +471,7 @@ ossl_ts_req_to_der(VALUE self)
ossl_raise(eTimestampError, "Message imprint missing algorithm");
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- if (!hashed_msg->length)
+ if (!ASN1_STRING_length(hashed_msg))
ossl_raise(eTimestampError, "Message imprint missing hashed message");
return asn1_to_der((void *)req, (int (*)(void *, unsigned char **))i2d_TS_REQ);
@@ -556,18 +523,19 @@ ossl_ts_resp_alloc(VALUE klass)
static VALUE
ossl_ts_resp_initialize(VALUE self, VALUE der)
{
- TS_RESP *ts_resp = DATA_PTR(self);
+ TS_RESP *resp, *resp_orig = DATA_PTR(self);
BIO *in;
der = ossl_to_der_if_possible(der);
- in = ossl_obj2bio(&der);
- ts_resp = d2i_TS_RESP_bio(in, &ts_resp);
+ in = ossl_obj2bio(&der);
+ resp = d2i_TS_RESP_bio(in, NULL);
BIO_free(in);
- if (!ts_resp) {
- DATA_PTR(self) = NULL;
- ossl_raise(eTimestampError, "Error when decoding the timestamp response");
+ if (!resp) {
+ ossl_raise(eTimestampError,
+ "Error when decoding the timestamp response");
}
- DATA_PTR(self) = ts_resp;
+ TS_RESP_free(resp_orig);
+ RTYPEDDATA_DATA(self) = resp;
return self;
}
@@ -740,7 +708,7 @@ ossl_ts_resp_get_tsa_certificate(VALUE self)
TS_RESP *resp;
PKCS7 *p7;
PKCS7_SIGNER_INFO *ts_info;
- X509 *cert;
+ const X509 *cert;
GetTSResponse(self, resp);
if (!(p7 = TS_RESP_get_token(resp)))
@@ -910,18 +878,19 @@ ossl_ts_token_info_alloc(VALUE klass)
static VALUE
ossl_ts_token_info_initialize(VALUE self, VALUE der)
{
- TS_TST_INFO *info = DATA_PTR(self);
+ TS_TST_INFO *info, *info_orig = DATA_PTR(self);
BIO *in;
der = ossl_to_der_if_possible(der);
- in = ossl_obj2bio(&der);
- info = d2i_TS_TST_INFO_bio(in, &info);
+ in = ossl_obj2bio(&der);
+ info = d2i_TS_TST_INFO_bio(in, NULL);
BIO_free(in);
if (!info) {
- DATA_PTR(self) = NULL;
- ossl_raise(eTimestampError, "Error when decoding the timestamp token info");
+ ossl_raise(eTimestampError,
+ "Error when decoding the timestamp token info");
}
- DATA_PTR(self) = info;
+ TS_TST_INFO_free(info_orig);
+ RTYPEDDATA_DATA(self) = info;
return self;
}
@@ -961,7 +930,7 @@ ossl_ts_token_info_get_policy_id(VALUE self)
TS_TST_INFO *info;
GetTSTokenInfo(self, info);
- return get_asn1obj(TS_TST_INFO_get_policy_id(info));
+ return ossl_asn1obj_to_string(TS_TST_INFO_get_policy_id(info));
}
/*
@@ -989,7 +958,7 @@ ossl_ts_token_info_get_algorithm(VALUE self)
mi = TS_TST_INFO_get_msg_imprint(info);
algo = TS_MSG_IMPRINT_get_algo(mi);
X509_ALGOR_get0(&obj, NULL, NULL, algo);
- return get_asn1obj(obj);
+ return ossl_asn1obj_to_string(obj);
}
/*
@@ -1015,7 +984,7 @@ ossl_ts_token_info_get_msg_imprint(VALUE self)
GetTSTokenInfo(self, info);
mi = TS_TST_INFO_get_msg_imprint(info);
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length);
+ ret = asn1str_to_str(hashed_msg);
return ret;
}
@@ -1155,9 +1124,14 @@ ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec)
}
static VALUE
-ossl_evp_get_digestbyname_i(VALUE arg)
+ossl_evp_md_fetch_i(VALUE args_)
{
- return (VALUE)ossl_evp_get_digestbyname(arg);
+ VALUE *args = (VALUE *)args_, md_holder;
+ const EVP_MD *md;
+
+ md = ossl_evp_md_fetch(args[1], &md_holder);
+ rb_ary_push(args[0], md_holder);
+ return (VALUE)md;
}
static VALUE
@@ -1193,7 +1167,8 @@ ossl_obj2bio_i(VALUE arg)
static VALUE
ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
{
- VALUE serial_number, def_policy_id, gen_time, additional_certs, allowed_digests;
+ VALUE serial_number, def_policy_id, gen_time, additional_certs,
+ allowed_digests, allowed_digests_tmp = Qnil;
VALUE str;
STACK_OF(X509) *inter_certs;
VALUE tsresp, ret = Qnil;
@@ -1254,7 +1229,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {
inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status);
if (status)
- goto end;
+ goto end;
/* this dups the sk_X509 and ups each cert's ref count */
TS_RESP_CTX_set_certs(ctx, inter_certs);
@@ -1270,16 +1245,18 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
allowed_digests = ossl_tsfac_get_allowed_digests(self);
if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {
- int i;
- VALUE rbmd;
- const EVP_MD *md;
-
- for (i = 0; i < RARRAY_LEN(allowed_digests); i++) {
- rbmd = rb_ary_entry(allowed_digests, i);
- md = (const EVP_MD *)rb_protect(ossl_evp_get_digestbyname_i, rbmd, &status);
+ allowed_digests_tmp = rb_ary_new_capa(RARRAY_LEN(allowed_digests));
+ for (long i = 0; i < RARRAY_LEN(allowed_digests); i++) {
+ VALUE args[] = {
+ allowed_digests_tmp,
+ rb_ary_entry(allowed_digests, i),
+ };
+ const EVP_MD *md = (const EVP_MD *)rb_protect(ossl_evp_md_fetch_i,
+ (VALUE)args, &status);
if (status)
goto end;
- TS_RESP_CTX_add_md(ctx, md);
+ if (!TS_RESP_CTX_add_md(ctx, md))
+ goto end;
}
}
@@ -1293,6 +1270,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
response = TS_RESP_create_response(ctx, req_bio);
BIO_free(req_bio);
+ RB_GC_GUARD(allowed_digests_tmp);
if (!response) {
err_msg = "Error during response generation";
@@ -1306,7 +1284,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
SetTSResponse(tsresp, response);
ret = tsresp;
-end:
+ end:
ASN1_INTEGER_free(asn1_serial);
ASN1_OBJECT_free(def_policy_id_obj);
TS_RESP_CTX_free(ctx);
@@ -1323,10 +1301,6 @@ end:
void
Init_ossl_ts(void)
{
- #if 0
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
- #endif
-
/*
* Possible return value for +Response#failure_info+. Indicates that the
* timestamp server rejects the message imprint algorithm used in the
@@ -1536,65 +1510,39 @@ Init_ossl_ts(void)
* fac.default_policy_id = '1.2.3.4.5'
* fac.additional_certificates = [ inter1, inter2 ]
* timestamp = fac.create_timestamp(p12.key, p12.certificate, req)
- *
- * ==Attributes
- *
- * ===default_policy_id
+ */
+ cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject);
+ /*
+ * The list of digest algorithms that the factory is allowed
+ * create timestamps for. Known vulnerable or weak algorithms should not be
+ * allowed where possible. Must be an Array of String or OpenSSL::Digest
+ * subclass instances.
+ */
+ rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0);
+ /*
+ * A String representing the default policy object identifier, or +nil+.
*
* Request#policy_id will always be preferred over this if present in the
- * Request, only if Request#policy_id is nil default_policy will be used.
+ * Request, only if Request#policy_id is +nil+ default_policy will be used.
* If none of both is present, a TimestampError will be raised when trying
* to create a Response.
- *
- * call-seq:
- * factory.default_policy_id = "string" -> string
- * factory.default_policy_id -> string or nil
- *
- * ===serial_number
- *
- * Sets or retrieves the serial number to be used for timestamp creation.
- * Must be present for timestamp creation.
- *
- * call-seq:
- * factory.serial_number = number -> number
- * factory.serial_number -> number or nil
- *
- * ===gen_time
- *
- * Sets or retrieves the Time value to be used in the Response. Must be
- * present for timestamp creation.
- *
- * call-seq:
- * factory.gen_time = Time -> Time
- * factory.gen_time -> Time or nil
- *
- * ===additional_certs
- *
- * Sets or retrieves additional certificates apart from the timestamp
- * certificate (e.g. intermediate certificates) to be added to the Response.
- * Must be an Array of OpenSSL::X509::Certificate.
- *
- * call-seq:
- * factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ]
- * factory.additional_certs -> array or nil
- *
- * ===allowed_digests
- *
- * Sets or retrieves the digest algorithms that the factory is allowed
- * create timestamps for. Known vulnerable or weak algorithms should not be
- * allowed where possible.
- * Must be an Array of String or OpenSSL::Digest subclass instances.
- *
- * call-seq:
- * factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ]
- * factory.allowed_digests -> array or nil
- *
*/
- cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject);
- rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0);
rb_attr(cTimestampFactory, rb_intern_const("default_policy_id"), 1, 1, 0);
+ /*
+ * The serial number to be used for timestamp creation. Must be present for
+ * timestamp creation. Must be an instance of OpenSSL::BN or Integer.
+ */
rb_attr(cTimestampFactory, rb_intern_const("serial_number"), 1, 1, 0);
+ /*
+ * The Time value to be used in the Response. Must be present for timestamp
+ * creation.
+ */
rb_attr(cTimestampFactory, rb_intern_const("gen_time"), 1, 1, 0);
+ /*
+ * Additional certificates apart from the timestamp certificate (e.g.
+ * intermediate certificates) to be added to the Response.
+ * Must be an Array of OpenSSL::X509::Certificate, or +nil+.
+ */
rb_attr(cTimestampFactory, rb_intern_const("additional_certs"), 1, 1, 0);
rb_define_method(cTimestampFactory, "create_timestamp", ossl_tsfac_create_ts, 3);
}
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c
index 2d552d7847..bc3914fda2 100644
--- a/ext/openssl/ossl_x509.c
+++ b/ext/openssl/ossl_x509.c
@@ -13,7 +13,8 @@ VALUE mX509;
#define DefX509Const(x) rb_define_const(mX509, #x, INT2NUM(X509_##x))
#define DefX509Default(x,i) \
- rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i()))
+ rb_define_const(mX509, "DEFAULT_" #x, \
+ rb_obj_freeze(rb_str_new_cstr(X509_get_default_##i())))
ASN1_TIME *
ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
@@ -29,10 +30,6 @@ ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
void
Init_ossl_x509(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
-#endif
-
mX509 = rb_define_module_under(mOSSL, "X509");
Init_ossl_x509attr();
diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h
index d25167ee7b..71932ef1a9 100644
--- a/ext/openssl/ossl_x509.h
+++ b/ext/openssl/ossl_x509.h
@@ -29,7 +29,7 @@ void Init_ossl_x509(void);
*/
extern VALUE cX509Attr;
-VALUE ossl_x509attr_new(X509_ATTRIBUTE *);
+VALUE ossl_x509attr_new(const X509_ATTRIBUTE *);
X509_ATTRIBUTE *GetX509AttrPtr(VALUE);
void Init_ossl_x509attr(void);
@@ -38,7 +38,7 @@ void Init_ossl_x509attr(void);
*/
extern VALUE cX509Cert;
-VALUE ossl_x509_new(X509 *);
+VALUE ossl_x509_new(const X509 *);
X509 *GetX509CertPtr(VALUE);
X509 *DupX509CertPtr(VALUE);
void Init_ossl_x509cert(void);
@@ -46,7 +46,7 @@ void Init_ossl_x509cert(void);
/*
* X509CRL
*/
-VALUE ossl_x509crl_new(X509_CRL *);
+VALUE ossl_x509crl_new(const X509_CRL *);
X509_CRL *GetX509CRLPtr(VALUE);
void Init_ossl_x509crl(void);
@@ -55,14 +55,14 @@ void Init_ossl_x509crl(void);
*/
extern VALUE cX509Ext;
-VALUE ossl_x509ext_new(X509_EXTENSION *);
+VALUE ossl_x509ext_new(const X509_EXTENSION *);
X509_EXTENSION *GetX509ExtPtr(VALUE);
void Init_ossl_x509ext(void);
/*
* X509Name
*/
-VALUE ossl_x509name_new(X509_NAME *);
+VALUE ossl_x509name_new(const X509_NAME *);
X509_NAME *GetX509NamePtr(VALUE);
void Init_ossl_x509name(void);
@@ -77,7 +77,7 @@ void Init_ossl_x509req(void);
*/
extern VALUE cX509Rev;
-VALUE ossl_x509revoked_new(X509_REVOKED *);
+VALUE ossl_x509revoked_new(const X509_REVOKED *);
X509_REVOKED *DupX509RevokedPtr(VALUE);
void Init_ossl_x509revoked(void);
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index 3f6b89bdde..38600b9b00 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509attr_type, 0)
#define SetX509Attr(obj, attr) do { \
if (!(attr)) { \
- ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (attr); \
} while (0)
#define GetX509Attr(obj, attr) do { \
TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \
if (!(attr)) { \
- ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509attr_free(void *ptr)
static const rb_data_type_t ossl_x509attr_type = {
"OpenSSL/X509/ATTRIBUTE",
{
- 0, ossl_x509attr_free,
+ 0, ossl_x509attr_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -48,20 +48,16 @@ static const rb_data_type_t ossl_x509attr_type = {
* Public
*/
VALUE
-ossl_x509attr_new(X509_ATTRIBUTE *attr)
+ossl_x509attr_new(const X509_ATTRIBUTE *attr)
{
X509_ATTRIBUTE *new;
VALUE obj;
obj = NewX509Attr(cX509Attr);
- if (!attr) {
- new = X509_ATTRIBUTE_new();
- } else {
- new = X509_ATTRIBUTE_dup(attr);
- }
- if (!new) {
- ossl_raise(eX509AttrError, NULL);
- }
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_ATTRIBUTE_dup((X509_ATTRIBUTE *)attr);
+ if (!new)
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
SetX509Attr(obj, new);
return obj;
@@ -88,7 +84,7 @@ ossl_x509attr_alloc(VALUE klass)
obj = NewX509Attr(klass);
if (!(attr = X509_ATTRIBUTE_new()))
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
SetX509Attr(obj, attr);
return obj;
@@ -107,15 +103,15 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
GetX509Attr(self, attr);
if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){
- oid = ossl_to_der_if_possible(oid);
- StringValue(oid);
- p = (unsigned char *)RSTRING_PTR(oid);
- x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
- DATA_PTR(self) = attr;
- if(!x){
- ossl_raise(eX509AttrError, NULL);
- }
- return self;
+ oid = ossl_to_der_if_possible(oid);
+ StringValue(oid);
+ p = (unsigned char *)RSTRING_PTR(oid);
+ x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
+ DATA_PTR(self) = attr;
+ if(!x){
+ ossl_raise(eX509AttrError, NULL);
+ }
+ return self;
}
rb_funcall(self, rb_intern("oid="), 1, oid);
rb_funcall(self, rb_intern("value="), 1, value);
@@ -135,7 +131,7 @@ ossl_x509attr_initialize_copy(VALUE self, VALUE other)
attr_new = X509_ATTRIBUTE_dup(attr_other);
if (!attr_new)
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
SetX509Attr(self, attr_new);
X509_ATTRIBUTE_free(attr);
@@ -159,8 +155,8 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
obj = OBJ_txt2obj(s, 0);
if(!obj) ossl_raise(eX509AttrError, NULL);
if (!X509_ATTRIBUTE_set1_object(attr, obj)) {
- ASN1_OBJECT_free(obj);
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
+ ASN1_OBJECT_free(obj);
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
}
ASN1_OBJECT_free(obj);
@@ -169,29 +165,18 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
/*
* call-seq:
- * attr.oid => string
+ * attr.oid -> string
+ *
+ * Returns the OID of the attribute. Returns the short name or the dotted
+ * decimal notation.
*/
static VALUE
ossl_x509attr_get_oid(VALUE self)
{
X509_ATTRIBUTE *attr;
- ASN1_OBJECT *oid;
- BIO *out;
- VALUE ret;
- int nid;
GetX509Attr(self, attr);
- oid = X509_ATTRIBUTE_get0_object(attr);
- if ((nid = OBJ_obj2nid(oid)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509AttrError, NULL);
- i2a_ASN1_OBJECT(out, oid);
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return ossl_asn1obj_to_string(X509_ATTRIBUTE_get0_object(attr));
}
/*
@@ -212,7 +197,7 @@ ossl_x509attr_set_value(VALUE self, VALUE value)
ossl_raise(eX509AttrError, "attribute value must be ASN1::Set");
if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */
- ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
+ const ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1);
if (!new_attr) {
sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
@@ -250,23 +235,32 @@ ossl_x509attr_get_value(VALUE self)
unsigned char *p;
GetX509Attr(self, attr);
+ count = X509_ATTRIBUTE_count(attr);
/* there is no X509_ATTRIBUTE_get0_set() :( */
+#ifdef HAVE_OPENSSL_SK_NEW_RESERVE
+ if (!(sk = sk_ASN1_TYPE_new_reserve(NULL, count)))
+ ossl_raise(eX509AttrError, "sk_new_reserve");
+#else
if (!(sk = sk_ASN1_TYPE_new_null()))
- ossl_raise(eX509AttrError, "sk_new");
+ ossl_raise(eX509AttrError, "sk_new");
+#endif
- count = X509_ATTRIBUTE_count(attr);
- for (i = 0; i < count; i++)
- sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
+ for (i = 0; i < count; i++) {
+ if (!sk_ASN1_TYPE_push(sk, (ASN1_TYPE *)X509_ATTRIBUTE_get0_type(attr, i))) {
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
+ }
+ }
if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) {
- sk_ASN1_TYPE_free(sk);
- ossl_raise(eX509AttrError, NULL);
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
}
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_ASN1_SET_ANY(sk, &p) <= 0) {
- sk_ASN1_TYPE_free(sk);
- ossl_raise(eX509AttrError, NULL);
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
}
ossl_str_adjust(str, p);
sk_ASN1_TYPE_free(sk);
@@ -288,11 +282,11 @@ ossl_x509attr_to_der(VALUE self)
GetX509Attr(self, attr);
if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -304,12 +298,6 @@ ossl_x509attr_to_der(VALUE self)
void
Init_ossl_x509attr(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject);
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 4734602bef..08dd184a0c 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509_type, 0)
#define SetX509(obj, x509) do { \
if (!(x509)) { \
- ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (x509); \
} while (0)
#define GetX509(obj, x509) do { \
TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \
if (!(x509)) { \
- ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509_free(void *ptr)
static const rb_data_type_t ossl_x509_type = {
"OpenSSL/X509",
{
- 0, ossl_x509_free,
+ 0, ossl_x509_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -48,20 +48,16 @@ static const rb_data_type_t ossl_x509_type = {
* Public
*/
VALUE
-ossl_x509_new(X509 *x509)
+ossl_x509_new(const X509 *x509)
{
X509 *new;
VALUE obj;
obj = NewX509(cX509Cert);
- if (!x509) {
- new = X509_new();
- } else {
- new = X509_dup(x509);
- }
- if (!new) {
- ossl_raise(eX509CertError, NULL);
- }
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_dup((X509 *)x509);
+ if (!new)
+ ossl_raise(eX509CertError, "X509_dup");
SetX509(obj, new);
return obj;
@@ -120,8 +116,8 @@ ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- /* create just empty X509Cert */
- return self;
+ /* create just empty X509Cert */
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -175,11 +171,11 @@ ossl_x509_to_der(VALUE self)
GetX509(self, x509);
if ((len = i2d_X509(x509, NULL)) <= 0)
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509(x509, &p) <= 0)
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -201,8 +197,8 @@ ossl_x509_to_pem(VALUE self)
if (!out) ossl_raise(eX509CertError, NULL);
if (!PEM_write_bio_X509(out, x509)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
@@ -226,8 +222,8 @@ ossl_x509_to_text(VALUE self)
if (!out) ossl_raise(eX509CertError, NULL);
if (!X509_print(out, x509)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
@@ -247,7 +243,7 @@ ossl_x509_to_req(VALUE self)
GetX509(self, x509);
if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
obj = ossl_x509req_new(req);
X509_REQ_free(req);
@@ -281,11 +277,11 @@ ossl_x509_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509CertError, "version must be >= 0!");
+ ossl_raise(eX509CertError, "version must be >= 0!");
}
GetX509(self, x509);
if (!X509_set_version(x509, ver)) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return version;
@@ -315,7 +311,9 @@ ossl_x509_set_serial(VALUE self, VALUE num)
X509 *x509;
GetX509(self, x509);
- X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509)));
+ if (!X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509)))) {
+ ossl_raise(eX509CertError, NULL);
+ }
return num;
}
@@ -323,27 +321,23 @@ ossl_x509_set_serial(VALUE self, VALUE num)
/*
* call-seq:
* cert.signature_algorithm => string
+ *
+ * Returns the signature algorithm used to sign this certificate. This returns
+ * the algorithm name found in the TBSCertificate structure, not the outer
+ * \Certificate structure.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
*/
static VALUE
ossl_x509_get_signature_algorithm(VALUE self)
{
X509 *x509;
- BIO *out;
const ASN1_OBJECT *obj;
- VALUE str;
GetX509(self, x509);
- out = BIO_new(BIO_s_mem());
- if (!out) ossl_raise(eX509CertError, NULL);
-
X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509));
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
+ return ossl_asn1obj_to_string_long_name(obj);
}
/*
@@ -354,11 +348,11 @@ static VALUE
ossl_x509_get_subject(VALUE self)
{
X509 *x509;
- X509_NAME *name;
+ const X509_NAME *name;
GetX509(self, x509);
if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
@@ -375,7 +369,7 @@ ossl_x509_set_subject(VALUE self, VALUE subject)
GetX509(self, x509);
if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return subject;
@@ -389,11 +383,11 @@ static VALUE
ossl_x509_get_issuer(VALUE self)
{
X509 *x509;
- X509_NAME *name;
+ const X509_NAME *name;
GetX509(self, x509);
if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
@@ -410,7 +404,7 @@ ossl_x509_set_issuer(VALUE self, VALUE issuer)
GetX509(self, x509);
if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return issuer;
@@ -428,7 +422,7 @@ ossl_x509_get_not_before(VALUE self)
GetX509(self, x509);
if (!(asn1time = X509_get0_notBefore(x509))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
@@ -447,8 +441,8 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notBefore(x509, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CertError, "X509_set_notBefore");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CertError, "X509_set_notBefore");
}
ASN1_TIME_free(asn1time);
@@ -467,7 +461,7 @@ ossl_x509_get_not_after(VALUE self)
GetX509(self, x509);
if (!(asn1time = X509_get0_notAfter(x509))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
@@ -486,8 +480,8 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notAfter(x509, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CertError, "X509_set_notAfter");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CertError, "X509_set_notAfter");
}
ASN1_TIME_free(asn1time);
@@ -506,10 +500,10 @@ ossl_x509_get_public_key(VALUE self)
GetX509(self, x509);
if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
- return ossl_pkey_new(pkey); /* NO DUP - OK */
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -526,7 +520,7 @@ ossl_x509_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_set_pubkey(x509, pkey))
- ossl_raise(eX509CertError, "X509_set_pubkey");
+ ossl_raise(eX509CertError, "X509_set_pubkey");
return key;
}
@@ -540,17 +534,14 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
X509 *x509;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
GetX509(self, x509);
- if (!X509_sign(x509, pkey, md)) {
- ossl_raise(eX509CertError, NULL);
- }
+ if (!X509_sign(x509, pkey, md))
+ ossl_raise(eX509CertError, "X509_sign");
return self;
}
@@ -573,12 +564,12 @@ ossl_x509_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_verify(x509, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
}
@@ -599,8 +590,8 @@ ossl_x509_check_private_key(VALUE self, VALUE key)
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509);
if (!X509_check_private_key(x509, pkey)) {
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
}
return Qtrue;
@@ -615,15 +606,14 @@ ossl_x509_get_extensions(VALUE self)
{
X509 *x509;
int count, i;
- X509_EXTENSION *ext;
VALUE ary;
GetX509(self, x509);
count = X509_get_ext_count(x509);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ const X509_EXTENSION *ext = X509_get_ext(x509, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -643,16 +633,16 @@ ossl_x509_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary's members should be X509Extension */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509(self, x509);
for (i = X509_get_ext_count(x509); i > 0; i--)
X509_EXTENSION_free(X509_delete_ext(x509, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
- if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
- ossl_raise(eX509CertError, "X509_add_ext");
- }
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
+ if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
+ ossl_raise(eX509CertError, "X509_add_ext");
+ }
}
return ary;
@@ -671,32 +661,24 @@ ossl_x509_add_extension(VALUE self, VALUE extension)
GetX509(self, x509);
ext = GetX509ExtPtr(extension);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return extension;
}
-static VALUE
-ossl_x509_inspect(VALUE self)
-{
- return rb_sprintf("#<%"PRIsVALUE": subject=%+"PRIsVALUE", "
- "issuer=%+"PRIsVALUE", serial=%+"PRIsVALUE", "
- "not_before=%+"PRIsVALUE", not_after=%+"PRIsVALUE">",
- rb_obj_class(self),
- ossl_x509_get_subject(self),
- ossl_x509_get_issuer(self),
- ossl_x509_get_serial(self),
- ossl_x509_get_not_before(self),
- ossl_x509_get_not_after(self));
-}
-
/*
* call-seq:
* cert1 == cert2 -> true | false
*
* Compares the two certificates. Note that this takes into account all fields,
* not just the issuer name and the serial number.
+ *
+ * This method uses X509_cmp() from OpenSSL, which compares certificates based
+ * on their cached DER encodings. The comparison can be unreliable if a
+ * certificate is incomplete.
+ *
+ * See also the man page X509_cmp(3).
*/
static VALUE
ossl_x509_eq(VALUE self, VALUE other)
@@ -705,7 +687,7 @@ ossl_x509_eq(VALUE self, VALUE other)
GetX509(self, a);
if (!rb_obj_is_kind_of(other, cX509Cert))
- return Qfalse;
+ return Qfalse;
GetX509(other, b);
return !X509_cmp(a, b) ? Qtrue : Qfalse;
@@ -800,7 +782,7 @@ load_chained_certificates_PEM(BIO *in) {
certificates = load_chained_certificates_append(Qnil, certificate);
while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
- load_chained_certificates_append(certificates, certificate);
+ load_chained_certificates_append(certificates, certificate);
}
/* We tried to read one more certificate but could not read start line: */
@@ -898,12 +880,6 @@ ossl_x509_load(VALUE klass, VALUE buffer)
void
Init_ossl_x509cert(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError);
/* Document-class: OpenSSL::X509::Certificate
@@ -1031,7 +1007,6 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0);
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
- rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
rb_define_method(cX509Cert, "tbs_bytes", ossl_x509_tbs_bytes, 0);
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 135dfe3d75..9b59bda9e2 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509crl_type, 0)
#define SetX509CRL(obj, crl) do { \
if (!(crl)) { \
- ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (crl); \
} while (0)
#define GetX509CRL(obj, crl) do { \
TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \
if (!(crl)) { \
- ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509crl_free(void *ptr)
static const rb_data_type_t ossl_x509crl_type = {
"OpenSSL/X509/CRL",
{
- 0, ossl_x509crl_free,
+ 0, ossl_x509crl_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -58,14 +58,16 @@ GetX509CRLPtr(VALUE obj)
}
VALUE
-ossl_x509crl_new(X509_CRL *crl)
+ossl_x509crl_new(const X509_CRL *crl)
{
X509_CRL *tmp;
VALUE obj;
obj = NewX509CRL(cX509CRL);
- tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new();
- if(!tmp) ossl_raise(eX509CRLError, NULL);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ tmp = X509_CRL_dup((X509_CRL *)crl);
+ if (!tmp)
+ ossl_raise(eX509CRLError, "X509_CRL_dup");
SetX509CRL(obj, tmp);
return obj;
@@ -82,7 +84,7 @@ ossl_x509crl_alloc(VALUE klass)
obj = NewX509CRL(klass);
if (!(crl = X509_CRL_new())) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
SetX509CRL(obj, crl);
@@ -98,7 +100,7 @@ ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return self;
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -128,7 +130,7 @@ ossl_x509crl_copy(VALUE self, VALUE other)
GetX509CRL(self, a);
GetX509CRL(other, b);
if (!(crl = X509_CRL_dup(b))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
X509_CRL_free(a);
DATA_PTR(self) = crl;
@@ -155,36 +157,36 @@ ossl_x509crl_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509CRLError, "version must be >= 0!");
+ ossl_raise(eX509CRLError, "version must be >= 0!");
}
GetX509CRL(self, crl);
if (!X509_CRL_set_version(crl, ver)) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return version;
}
+/*
+ * call-seq:
+ * crl.signature_algorithm -> string
+ *
+ * Returns the signature algorithm used to sign this CRL.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
+ */
static VALUE
ossl_x509crl_get_signature_algorithm(VALUE self)
{
X509_CRL *crl;
const X509_ALGOR *alg;
const ASN1_OBJECT *obj;
- BIO *out;
GetX509CRL(self, crl);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
- }
X509_CRL_get0_signature(crl, NULL, &alg);
X509_ALGOR_get0(&obj, NULL, NULL, alg);
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
- }
-
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(obj);
}
static VALUE
@@ -205,7 +207,7 @@ ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
GetX509CRL(self, crl);
if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return issuer;
}
@@ -219,7 +221,7 @@ ossl_x509crl_get_last_update(VALUE self)
GetX509CRL(self, crl);
time = X509_CRL_get0_lastUpdate(crl);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -233,8 +235,8 @@ ossl_x509crl_set_last_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_CRL_set1_lastUpdate(crl, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
}
ASN1_TIME_free(asn1time);
@@ -250,7 +252,7 @@ ossl_x509crl_get_next_update(VALUE self)
GetX509CRL(self, crl);
time = X509_CRL_get0_nextUpdate(crl);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -264,8 +266,8 @@ ossl_x509crl_set_next_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_CRL_set1_nextUpdate(crl, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
}
ASN1_TIME_free(asn1time);
@@ -288,8 +290,8 @@ ossl_x509crl_get_revoked(VALUE self)
num = sk_X509_REVOKED_num(sk);
ary = rb_ary_new_capa(num);
for(i=0; i<num; i++) {
- X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);
- rb_ary_push(ary, ossl_x509revoked_new(rev));
+ const X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);
+ rb_ary_push(ary, ossl_x509revoked_new(rev));
}
return ary;
@@ -306,19 +308,19 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Revoked */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);
}
GetX509CRL(self, crl);
if ((sk = X509_CRL_get_REVOKED(crl))) {
- while ((rev = sk_X509_REVOKED_pop(sk)))
- X509_REVOKED_free(rev);
+ while ((rev = sk_X509_REVOKED_pop(sk)))
+ X509_REVOKED_free(rev);
}
for (i=0; i<RARRAY_LEN(ary); i++) {
- rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));
- if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
- X509_REVOKED_free(rev);
- ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
- }
+ rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));
+ if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
+ X509_REVOKED_free(rev);
+ ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
+ }
}
X509_CRL_sort(crl);
@@ -334,8 +336,8 @@ ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
GetX509CRL(self, crl);
rev = DupX509RevokedPtr(revoked);
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
- X509_REVOKED_free(rev);
- ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
+ X509_REVOKED_free(rev);
+ ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
}
X509_CRL_sort(crl);
@@ -348,17 +350,14 @@ ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
X509_CRL *crl;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
GetX509CRL(self, crl);
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
- if (!X509_CRL_sign(crl, pkey, md)) {
- ossl_raise(eX509CRLError, NULL);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
+ if (!X509_CRL_sign(crl, pkey, md))
+ ossl_raise(eX509CRLError, "X509_CRL_sign");
return self;
}
@@ -374,12 +373,12 @@ ossl_x509crl_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_CRL_verify(crl, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
}
@@ -391,11 +390,11 @@ ossl_x509crl_to_der(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!i2d_X509_CRL_bio(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -409,11 +408,11 @@ ossl_x509crl_to_pem(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!PEM_write_bio_X509_CRL(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -427,11 +426,11 @@ ossl_x509crl_to_text(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!X509_CRL_print(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -445,15 +444,14 @@ ossl_x509crl_get_extensions(VALUE self)
{
X509_CRL *crl;
int count, i;
- X509_EXTENSION *ext;
VALUE ary;
GetX509CRL(self, crl);
count = X509_CRL_get_ext_count(crl);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ const X509_EXTENSION *ext = X509_CRL_get_ext(crl, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -472,16 +470,16 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Extensions */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509CRL(self, crl);
for (i = X509_CRL_get_ext_count(crl); i > 0; i--)
X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
- if (!X509_CRL_add_ext(crl, ext, -1)) {
- ossl_raise(eX509CRLError, "X509_CRL_add_ext");
- }
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
+ if (!X509_CRL_add_ext(crl, ext, -1)) {
+ ossl_raise(eX509CRLError, "X509_CRL_add_ext");
+ }
}
return ary;
@@ -496,7 +494,7 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
GetX509CRL(self, crl);
ext = GetX509ExtPtr(extension);
if (!X509_CRL_add_ext(crl, ext, -1)) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return extension;
@@ -508,12 +506,6 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
void
Init_ossl_x509crl(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject);
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c
index 9b0d9aa651..1fe727d3f1 100644
--- a/ext/openssl/ossl_x509ext.c
+++ b/ext/openssl/ossl_x509ext.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509ext_type, 0)
#define SetX509Ext(obj, ext) do { \
if (!(ext)) { \
- ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (ext); \
} while (0)
#define GetX509Ext(obj, ext) do { \
TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \
if (!(ext)) { \
- ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
} \
} while (0)
#define MakeX509ExtFactory(klass, obj, ctx) do { \
@@ -33,7 +33,7 @@
#define GetX509ExtFactory(obj, ctx) do { \
TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
} \
} while (0)
@@ -53,7 +53,7 @@ ossl_x509ext_free(void *ptr)
static const rb_data_type_t ossl_x509ext_type = {
"OpenSSL/X509/EXTENSION",
{
- 0, ossl_x509ext_free,
+ 0, ossl_x509ext_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -62,20 +62,16 @@ static const rb_data_type_t ossl_x509ext_type = {
* Public
*/
VALUE
-ossl_x509ext_new(X509_EXTENSION *ext)
+ossl_x509ext_new(const X509_EXTENSION *ext)
{
X509_EXTENSION *new;
VALUE obj;
obj = NewX509Ext(cX509Ext);
- if (!ext) {
- new = X509_EXTENSION_new();
- } else {
- new = X509_EXTENSION_dup(ext);
- }
- if (!new) {
- ossl_raise(eX509ExtError, NULL);
- }
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_EXTENSION_dup((X509_EXTENSION *)ext);
+ if (!new)
+ ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
SetX509Ext(obj, new);
return obj;
@@ -106,7 +102,7 @@ ossl_x509extfactory_free(void *ctx)
static const rb_data_type_t ossl_x509extfactory_type = {
"OpenSSL/X509/EXTENSION/Factory",
{
- 0, ossl_x509extfactory_free,
+ 0, ossl_x509extfactory_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -180,15 +176,15 @@ ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
/*GetX509ExtFactory(self, ctx);*/
rb_scan_args(argc, argv, "04",
- &issuer_cert, &subject_cert, &subject_req, &crl);
+ &issuer_cert, &subject_cert, &subject_req, &crl);
if (!NIL_P(issuer_cert))
- ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
+ ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
if (!NIL_P(subject_cert))
- ossl_x509extfactory_set_subject_cert(self, subject_cert);
+ ossl_x509extfactory_set_subject_cert(self, subject_cert);
if (!NIL_P(subject_req))
- ossl_x509extfactory_set_subject_req(self, subject_req);
+ ossl_x509extfactory_set_subject_req(self, subject_req);
if (!NIL_P(crl))
- ossl_x509extfactory_set_crl(self, crl);
+ ossl_x509extfactory_set_crl(self, crl);
return self;
}
@@ -218,7 +214,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
oid_cstr = StringValueCStr(oid);
nid = OBJ_ln2nid(oid_cstr);
if (nid != NID_undef)
- oid_cstr = OBJ_nid2sn(nid);
+ oid_cstr = OBJ_nid2sn(nid);
valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
rb_str_append(valstr, value);
@@ -233,7 +229,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));
X509V3_set_ctx_nodb(ctx);
if (!ext){
- ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
+ ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
}
SetX509Ext(obj, ext);
@@ -251,7 +247,7 @@ ossl_x509ext_alloc(VALUE klass)
obj = NewX509Ext(klass);
if(!(ext = X509_EXTENSION_new())){
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
}
SetX509Ext(obj, ext);
@@ -279,14 +275,14 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
GetX509Ext(self, ext);
if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
- oid = ossl_to_der_if_possible(oid);
- StringValue(oid);
- p = (unsigned char *)RSTRING_PTR(oid);
- x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
- DATA_PTR(self) = ext;
- if(!x)
- ossl_raise(eX509ExtError, NULL);
- return self;
+ oid = ossl_to_der_if_possible(oid);
+ StringValue(oid);
+ p = (unsigned char *)RSTRING_PTR(oid);
+ x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
+ DATA_PTR(self) = ext;
+ if(!x)
+ ossl_raise(eX509ExtError, NULL);
+ return self;
}
rb_funcall(self, rb_intern("oid="), 1, oid);
rb_funcall(self, rb_intern("value="), 1, value);
@@ -307,7 +303,7 @@ ossl_x509ext_initialize_copy(VALUE self, VALUE other)
ext_new = X509_EXTENSION_dup(ext_other);
if (!ext_new)
- ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
+ ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
SetX509Ext(self, ext_new);
X509_EXTENSION_free(ext);
@@ -324,10 +320,10 @@ ossl_x509ext_set_oid(VALUE self, VALUE oid)
GetX509Ext(self, ext);
obj = OBJ_txt2obj(StringValueCStr(oid), 0);
if (!obj)
- ossl_raise(eX509ExtError, "OBJ_txt2obj");
+ ossl_raise(eX509ExtError, "OBJ_txt2obj");
if (!X509_EXTENSION_set_object(ext, obj)) {
- ASN1_OBJECT_free(obj);
- ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
+ ASN1_OBJECT_free(obj);
+ ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
}
ASN1_OBJECT_free(obj);
@@ -343,12 +339,20 @@ ossl_x509ext_set_value(VALUE self, VALUE data)
GetX509Ext(self, ext);
data = ossl_to_der_if_possible(data);
StringValue(data);
- asn1s = X509_EXTENSION_get_data(ext);
+ asn1s = ASN1_OCTET_STRING_new();
+ if (!asn1s)
+ ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_new");
if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data),
- RSTRING_LENINT(data))) {
- ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
+ RSTRING_LENINT(data))) {
+ ASN1_OCTET_STRING_free(asn1s);
+ ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
}
+ if (!X509_EXTENSION_set_data(ext, asn1s)) {
+ ASN1_OCTET_STRING_free(asn1s);
+ ossl_raise(eX509ExtError, "X509_EXTENSION_set_data");
+ }
+ ASN1_OCTET_STRING_free(asn1s);
return data;
}
@@ -364,27 +368,20 @@ ossl_x509ext_set_critical(VALUE self, VALUE flag)
return flag;
}
+/*
+ * call-seq:
+ * ext.oid -> string
+ *
+ * Returns the OID of the extension. Returns the short name or the dotted
+ * decimal notation.
+ */
static VALUE
ossl_x509ext_get_oid(VALUE obj)
{
X509_EXTENSION *ext;
- ASN1_OBJECT *extobj;
- BIO *out;
- VALUE ret;
- int nid;
GetX509Ext(obj, ext);
- extobj = X509_EXTENSION_get_object(ext);
- if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509ExtError, NULL);
- i2a_ASN1_OBJECT(out, extobj);
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return ossl_asn1obj_to_string(X509_EXTENSION_get_object(ext));
}
static VALUE
@@ -396,9 +393,9 @@ ossl_x509ext_get_value(VALUE obj)
GetX509Ext(obj, ext);
if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
if (!X509V3_EXT_print(out, ext, 0, 0))
- ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
+ ASN1_STRING_print(out, X509_EXTENSION_get_data(ext));
ret = ossl_membio2str(out);
return ret;
@@ -408,13 +405,13 @@ static VALUE
ossl_x509ext_get_value_der(VALUE obj)
{
X509_EXTENSION *ext;
- ASN1_OCTET_STRING *value;
+ const ASN1_OCTET_STRING *value;
GetX509Ext(obj, ext);
if ((value = X509_EXTENSION_get_data(ext)) == NULL)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
- return rb_str_new((const char *)value->data, value->length);
+ return asn1str_to_str(value);
}
static VALUE
@@ -436,11 +433,11 @@ ossl_x509ext_to_der(VALUE obj)
GetX509Ext(obj, ext);
if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_EXTENSION(ext, &p) < 0)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -453,12 +450,6 @@ void
Init_ossl_x509ext(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index b3791aefa3..eb97b23c02 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -13,21 +13,21 @@
TypedData_Wrap_Struct((klass), &ossl_x509name_type, 0)
#define SetX509Name(obj, name) do { \
if (!(name)) { \
- ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (name); \
} while (0)
#define GetX509Name(obj, name) do { \
TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \
if (!(name)) { \
- ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
} \
} while (0)
#define OBJECT_TYPE_TEMPLATE \
- rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
+ rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
#define DEFAULT_OBJECT_TYPE \
- rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
+ rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
/*
* Classes
@@ -44,7 +44,7 @@ ossl_x509name_free(void *ptr)
static const rb_data_type_t ossl_x509name_type = {
"OpenSSL/X509/NAME",
{
- 0, ossl_x509name_free,
+ 0, ossl_x509name_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -53,20 +53,16 @@ static const rb_data_type_t ossl_x509name_type = {
* Public
*/
VALUE
-ossl_x509name_new(X509_NAME *name)
+ossl_x509name_new(const X509_NAME *name)
{
X509_NAME *new;
VALUE obj;
obj = NewX509Name(cX509Name);
- if (!name) {
- new = X509_NAME_new();
- } else {
- new = X509_NAME_dup(name);
- }
- if (!new) {
- ossl_raise(eX509NameError, NULL);
- }
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_NAME_dup((X509_NAME *)name);
+ if (!new)
+ ossl_raise(eX509NameError, "X509_NAME_dup");
SetX509Name(obj, new);
return obj;
@@ -93,7 +89,7 @@ ossl_x509name_alloc(VALUE klass)
obj = NewX509Name(klass);
if (!(name = X509_NAME_new())) {
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
}
SetX509Name(obj, name);
@@ -150,28 +146,28 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
GetX509Name(self, name);
if (rb_scan_args(argc, argv, "02", &arg, &template) == 0) {
- return self;
+ return self;
}
else {
- VALUE tmp = rb_check_array_type(arg);
- if (!NIL_P(tmp)) {
- VALUE args;
- if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
- args = rb_ary_new3(2, self, template);
- rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
- }
- else{
- const unsigned char *p;
- VALUE str = ossl_to_der_if_possible(arg);
- X509_NAME *x;
- StringValue(str);
- p = (unsigned char *)RSTRING_PTR(str);
- x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
- DATA_PTR(self) = name;
- if(!x){
- ossl_raise(eX509NameError, NULL);
- }
- }
+ VALUE tmp = rb_check_array_type(arg);
+ if (!NIL_P(tmp)) {
+ VALUE args;
+ if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
+ args = rb_ary_new3(2, self, template);
+ rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
+ }
+ else{
+ const unsigned char *p;
+ VALUE str = ossl_to_der_if_possible(arg);
+ X509_NAME *x;
+ StringValue(str);
+ p = (unsigned char *)RSTRING_PTR(str);
+ x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
+ DATA_PTR(self) = name;
+ if(!x){
+ ossl_raise(eX509NameError, NULL);
+ }
+ }
}
return self;
@@ -189,7 +185,7 @@ ossl_x509name_initialize_copy(VALUE self, VALUE other)
name_new = X509_NAME_dup(name_other);
if (!name_new)
- ossl_raise(eX509NameError, "X509_NAME_dup");
+ ossl_raise(eX509NameError, "X509_NAME_dup");
SetX509Name(self, name_new);
X509_NAME_free(name);
@@ -226,8 +222,8 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
int loc = -1, set = 0;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("loc");
- kwargs_ids[1] = rb_intern_const("set");
+ kwargs_ids[0] = rb_intern_const("loc");
+ kwargs_ids[1] = rb_intern_const("set");
}
rb_scan_args(argc, argv, "21:", &oid, &value, &type, &opts);
rb_get_kwargs(opts, kwargs_ids, 0, 2, kwargs);
@@ -235,14 +231,14 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
StringValue(value);
if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid);
if (kwargs[0] != Qundef)
- loc = NUM2INT(kwargs[0]);
+ loc = NUM2INT(kwargs[0]);
if (kwargs[1] != Qundef)
- set = NUM2INT(kwargs[1]);
+ set = NUM2INT(kwargs[1]);
GetX509Name(self, name);
if (!X509_NAME_add_entry_by_txt(name, oid_name, NUM2INT(type),
- (unsigned char *)RSTRING_PTR(value),
- RSTRING_LENINT(value), loc, set))
- ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt");
+ (unsigned char *)RSTRING_PTR(value),
+ RSTRING_LENINT(value), loc, set))
+ ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt");
return self;
}
@@ -255,7 +251,7 @@ ossl_x509name_to_s_old(VALUE self)
GetX509Name(self, name);
buf = X509_NAME_oneline(name, NULL, 0);
if (!buf)
- ossl_raise(eX509NameError, "X509_NAME_oneline");
+ ossl_raise(eX509NameError, "X509_NAME_oneline");
return ossl_buf2str(buf, rb_long2int(strlen(buf)));
}
@@ -269,11 +265,11 @@ x509name_print(VALUE self, unsigned long iflag)
GetX509Name(self, name);
out = BIO_new(BIO_s_mem());
if (!out)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
ret = X509_NAME_print_ex(out, name, 0, iflag);
if (ret < 0 || (iflag == XN_FLAG_COMPAT && ret == 0)) {
- BIO_free(out);
- ossl_raise(eX509NameError, "X509_NAME_print_ex");
+ BIO_free(out);
+ ossl_raise(eX509NameError, "X509_NAME_print_ex");
}
return ossl_membio2str(out);
}
@@ -307,9 +303,9 @@ ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 0, 1);
/* name.to_s(nil) was allowed */
if (!argc || NIL_P(argv[0]))
- return ossl_x509name_to_s_old(self);
+ return ossl_x509name_to_s_old(self);
else
- return x509name_print(self, NUM2ULONG(argv[0]));
+ return x509name_print(self, NUM2ULONG(argv[0]));
}
/*
@@ -332,7 +328,7 @@ static VALUE
ossl_x509name_inspect(VALUE self)
{
return rb_enc_sprintf(rb_utf8_encoding(), "#<%"PRIsVALUE" %"PRIsVALUE">",
- rb_obj_class(self), ossl_x509name_to_utf8(self));
+ rb_obj_class(self), ossl_x509name_to_utf8(self));
}
/*
@@ -346,34 +342,22 @@ static VALUE
ossl_x509name_to_a(VALUE self)
{
X509_NAME *name;
- X509_NAME_ENTRY *entry;
- int i,entries,nid;
- char long_name[512];
- const char *short_name;
- VALUE ary, vname, ret;
- ASN1_STRING *value;
+ int entries;
+ VALUE ret;
GetX509Name(self, name);
entries = X509_NAME_entry_count(name);
ret = rb_ary_new_capa(entries);
- for (i=0; i<entries; i++) {
- if (!(entry = X509_NAME_get_entry(name, i))) {
- ossl_raise(eX509NameError, NULL);
- }
- if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name),
- X509_NAME_ENTRY_get_object(entry))) {
- ossl_raise(eX509NameError, NULL);
- }
- nid = OBJ_ln2nid(long_name);
- if (nid == NID_undef) {
- vname = rb_str_new2((const char *) &long_name);
- } else {
- short_name = OBJ_nid2sn(nid);
- vname = rb_str_new2(short_name); /*do not free*/
- }
- value = X509_NAME_ENTRY_get_data(entry);
- ary = rb_ary_new3(3, vname, asn1str_to_str(value), INT2NUM(value->type));
- rb_ary_push(ret, ary);
+ for (int i = 0; i < entries; i++) {
+ const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
+ if (!entry)
+ ossl_raise(eX509NameError, "X509_NAME_get_entry");
+ const ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(entry);
+ VALUE vname = ossl_asn1obj_to_string(obj);
+ const ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);
+ VALUE vdata = asn1str_to_str(data);
+ VALUE type = INT2NUM(ASN1_STRING_type(data));
+ rb_ary_push(ret, rb_ary_new_from_args(3, vname, vdata, type));
}
return ret;
}
@@ -382,11 +366,17 @@ static int
ossl_x509name_cmp0(VALUE self, VALUE other)
{
X509_NAME *name1, *name2;
+ int result;
GetX509Name(self, name1);
GetX509Name(other, name2);
- return X509_NAME_cmp(name1, name2);
+ result = X509_NAME_cmp(name1, name2);
+ if (result == -2) {
+ ossl_raise(eX509NameError, NULL);
+ }
+
+ return result;
}
/*
@@ -404,7 +394,7 @@ ossl_x509name_cmp(VALUE self, VALUE other)
int result;
if (!rb_obj_is_kind_of(other, cX509Name))
- return Qnil;
+ return Qnil;
result = ossl_x509name_cmp0(self, other);
if (result < 0) return INT2FIX(-1);
@@ -423,7 +413,7 @@ static VALUE
ossl_x509name_eql(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cX509Name))
- return Qfalse;
+ return Qfalse;
return ossl_x509name_cmp0(self, other) == 0 ? Qtrue : Qfalse;
}
@@ -483,11 +473,11 @@ ossl_x509name_to_der(VALUE self)
GetX509Name(self, name);
if((len = i2d_X509_NAME(name, NULL)) <= 0)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_NAME(name, &p) <= 0)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -513,12 +503,6 @@ Init_ossl_x509name(void)
#undef rb_intern
VALUE utf8str, ptrstr, ia5str, hash;
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
id_aref = rb_intern("[]");
eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError);
cX509Name = rb_define_class_under(mX509, "Name", rb_cObject);
@@ -557,6 +541,7 @@ Init_ossl_x509name(void)
rb_hash_aset(hash, rb_str_new2("DC"), ia5str);
rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str);
rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str);
+ rb_obj_freeze(hash);
/*
* The default object type template for name entries.
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index add1f8d077..ad5dd08033 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509req_type, 0)
#define SetX509Req(obj, req) do { \
if (!(req)) { \
- ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (req); \
} while (0)
#define GetX509Req(obj, req) do { \
TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \
if (!(req)) { \
- ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509req_free(void *ptr)
static const rb_data_type_t ossl_x509req_type = {
"OpenSSL/X509/REQ",
{
- 0, ossl_x509req_free,
+ 0, ossl_x509req_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -68,7 +68,7 @@ ossl_x509req_alloc(VALUE klass)
obj = NewX509Req(klass);
if (!(req = X509_REQ_new())) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
SetX509Req(obj, req);
@@ -84,7 +84,7 @@ ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return self;
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -114,7 +114,7 @@ ossl_x509req_copy(VALUE self, VALUE other)
GetX509Req(self, a);
GetX509Req(other, b);
if (!(req = X509_REQ_dup(b))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
X509_REQ_free(a);
DATA_PTR(self) = req;
@@ -130,11 +130,11 @@ ossl_x509req_to_pem(VALUE self)
GetX509Req(self, req);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
if (!PEM_write_bio_X509_REQ(out, req)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_membio2str(out);
@@ -150,11 +150,11 @@ ossl_x509req_to_der(VALUE self)
GetX509Req(self, req);
if ((len = i2d_X509_REQ(req, NULL)) <= 0)
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509_REQ(req, &p) <= 0)
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -168,11 +168,11 @@ ossl_x509req_to_text(VALUE self)
GetX509Req(self, req);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
if (!X509_REQ_print(out, req)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_membio2str(out);
@@ -191,7 +191,7 @@ ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)
GetX509Req(self, req);
...
if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_x509_new(x509);
@@ -217,11 +217,11 @@ ossl_x509req_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509ReqError, "version must be >= 0!");
+ ossl_raise(eX509ReqError, "version must be >= 0!");
}
GetX509Req(self, req);
if (!X509_REQ_set_version(req, ver)) {
- ossl_raise(eX509ReqError, "X509_REQ_set_version");
+ ossl_raise(eX509ReqError, "X509_REQ_set_version");
}
return version;
@@ -231,11 +231,11 @@ static VALUE
ossl_x509req_get_subject(VALUE self)
{
X509_REQ *req;
- X509_NAME *name;
+ const X509_NAME *name;
GetX509Req(self, req);
if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_x509name_new(name);
@@ -249,33 +249,32 @@ ossl_x509req_set_subject(VALUE self, VALUE subject)
GetX509Req(self, req);
/* DUPs name */
if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return subject;
}
+/*
+ * call-seq:
+ * req.signature_algorithm -> string
+ *
+ * Returns the signature algorithm used to sign this request.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
+ */
static VALUE
ossl_x509req_get_signature_algorithm(VALUE self)
{
X509_REQ *req;
const X509_ALGOR *alg;
const ASN1_OBJECT *obj;
- BIO *out;
GetX509Req(self, req);
-
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
- }
X509_REQ_get0_signature(req, NULL, &alg);
X509_ALGOR_get0(&obj, NULL, NULL, alg);
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
- }
-
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(obj);
}
static VALUE
@@ -286,10 +285,10 @@ ossl_x509req_get_public_key(VALUE self)
GetX509Req(self, req);
if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
- return ossl_pkey_new(pkey); /* NO DUP - OK */
+ return ossl_pkey_wrap(pkey);
}
static VALUE
@@ -302,7 +301,7 @@ ossl_x509req_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_REQ_set_pubkey(req, pkey))
- ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
+ ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
return key;
}
@@ -312,17 +311,14 @@ ossl_x509req_sign(VALUE self, VALUE key, VALUE digest)
X509_REQ *req;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
GetX509Req(self, req);
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
- if (!X509_REQ_sign(req, pkey, md)) {
- ossl_raise(eX509ReqError, NULL);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
+ if (!X509_REQ_sign(req, pkey, md))
+ ossl_raise(eX509ReqError, "X509_REQ_sign");
return self;
}
@@ -341,12 +337,12 @@ ossl_x509req_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_REQ_verify(req, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
}
@@ -355,20 +351,20 @@ ossl_x509req_get_attributes(VALUE self)
{
X509_REQ *req;
int count, i;
- X509_ATTRIBUTE *attr;
+ const X509_ATTRIBUTE *attr;
VALUE ary;
GetX509Req(self, req);
count = X509_REQ_get_attr_count(req);
if (count < 0) {
- OSSL_Debug("count < 0???");
- return rb_ary_new();
+ OSSL_Debug("count < 0???");
+ return rb_ary_new();
}
ary = rb_ary_new2(count);
for (i=0; i<count; i++) {
- attr = X509_REQ_get_attr(req, i);
- rb_ary_push(ary, ossl_x509attr_new(attr));
+ attr = X509_REQ_get_attr(req, i);
+ rb_ary_push(ary, ossl_x509attr_new(attr));
}
return ary;
@@ -384,17 +380,17 @@ ossl_x509req_set_attributes(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
for (i=0;i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);
}
GetX509Req(self, req);
for (i = X509_REQ_get_attr_count(req); i > 0; i--)
X509_ATTRIBUTE_free(X509_REQ_delete_attr(req, 0));
for (i=0;i<RARRAY_LEN(ary); i++) {
- item = RARRAY_AREF(ary, i);
- attr = GetX509AttrPtr(item);
- if (!X509_REQ_add1_attr(req, attr)) {
- ossl_raise(eX509ReqError, "X509_REQ_add1_attr");
- }
+ item = RARRAY_AREF(ary, i);
+ attr = GetX509AttrPtr(item);
+ if (!X509_REQ_add1_attr(req, attr)) {
+ ossl_raise(eX509ReqError, "X509_REQ_add1_attr");
+ }
}
return ary;
}
@@ -406,7 +402,7 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
GetX509Req(self, req);
if (!X509_REQ_add1_attr(req, GetX509AttrPtr(attr))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return attr;
@@ -418,12 +414,6 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
void
Init_ossl_x509req(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError);
cX509Req = rb_define_class_under(mX509, "Request", rb_cObject);
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 1eff5dd355..0151961e9f 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509rev_type, 0)
#define SetX509Rev(obj, rev) do { \
if (!(rev)) { \
- ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (rev); \
} while (0)
#define GetX509Rev(obj, rev) do { \
TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \
if (!(rev)) { \
- ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509rev_free(void *ptr)
static const rb_data_type_t ossl_x509rev_type = {
"OpenSSL/X509/REV",
{
- 0, ossl_x509rev_free,
+ 0, ossl_x509rev_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -48,20 +48,16 @@ static const rb_data_type_t ossl_x509rev_type = {
* PUBLIC
*/
VALUE
-ossl_x509revoked_new(X509_REVOKED *rev)
+ossl_x509revoked_new(const X509_REVOKED *rev)
{
X509_REVOKED *new;
VALUE obj;
obj = NewX509Rev(cX509Rev);
- if (!rev) {
- new = X509_REVOKED_new();
- } else {
- new = X509_REVOKED_dup(rev);
- }
- if (!new) {
- ossl_raise(eX509RevError, NULL);
- }
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ new = X509_REVOKED_dup((X509_REVOKED *)rev);
+ if (!new)
+ ossl_raise(eX509RevError, "X509_REVOKED_dup");
SetX509Rev(obj, new);
return obj;
@@ -74,7 +70,7 @@ DupX509RevokedPtr(VALUE obj)
GetX509Rev(obj, rev);
if (!(new = X509_REVOKED_dup(rev))) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
return new;
@@ -91,7 +87,7 @@ ossl_x509revoked_alloc(VALUE klass)
obj = NewX509Rev(klass);
if (!(rev = X509_REVOKED_new())) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
SetX509Rev(obj, rev);
@@ -117,7 +113,7 @@ ossl_x509revoked_initialize_copy(VALUE self, VALUE other)
rev_new = X509_REVOKED_dup(rev_other);
if (!rev_new)
- ossl_raise(eX509RevError, "X509_REVOKED_dup");
+ ossl_raise(eX509RevError, "X509_REVOKED_dup");
SetX509Rev(self, rev_new);
X509_REVOKED_free(rev);
@@ -144,8 +140,8 @@ ossl_x509revoked_set_serial(VALUE self, VALUE num)
GetX509Rev(self, rev);
asn1int = num_to_asn1integer(num, NULL);
if (!X509_REVOKED_set_serialNumber(rev, asn1int)) {
- ASN1_INTEGER_free(asn1int);
- ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber");
+ ASN1_INTEGER_free(asn1int);
+ ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber");
}
ASN1_INTEGER_free(asn1int);
@@ -161,7 +157,7 @@ ossl_x509revoked_get_time(VALUE self)
GetX509Rev(self, rev);
time = X509_REVOKED_get0_revocationDate(rev);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -175,8 +171,8 @@ ossl_x509revoked_set_time(VALUE self, VALUE time)
GetX509Rev(self, rev);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_REVOKED_set_revocationDate(rev, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate");
}
ASN1_TIME_free(asn1time);
@@ -190,15 +186,15 @@ ossl_x509revoked_get_extensions(VALUE self)
{
X509_REVOKED *rev;
int count, i;
- X509_EXTENSION *ext;
+ const X509_EXTENSION *ext;
VALUE ary;
GetX509Rev(self, rev);
count = X509_REVOKED_get_ext_count(rev);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_REVOKED_get_ext(rev, i);
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ ext = X509_REVOKED_get_ext(rev, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -217,17 +213,17 @@ ossl_x509revoked_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509Rev(self, rev);
for (i = X509_REVOKED_get_ext_count(rev); i > 0; i--)
X509_EXTENSION_free(X509_REVOKED_delete_ext(rev, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- item = RARRAY_AREF(ary, i);
- ext = GetX509ExtPtr(item);
- if(!X509_REVOKED_add_ext(rev, ext, -1)) {
- ossl_raise(eX509RevError, "X509_REVOKED_add_ext");
- }
+ item = RARRAY_AREF(ary, i);
+ ext = GetX509ExtPtr(item);
+ if(!X509_REVOKED_add_ext(rev, ext, -1)) {
+ ossl_raise(eX509RevError, "X509_REVOKED_add_ext");
+ }
}
return ary;
@@ -240,7 +236,7 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
GetX509Rev(self, rev);
if (!X509_REVOKED_add_ext(rev, GetX509ExtPtr(ext), -1)) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
return ext;
@@ -257,11 +253,11 @@ ossl_x509revoked_to_der(VALUE self)
GetX509Rev(self, rev);
len = i2d_X509_REVOKED(rev, NULL);
if (len <= 0)
- ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
str = rb_str_new(NULL, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509_REVOKED(rev, &p) <= 0)
- ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
ossl_str_adjust(str, p);
return str;
}
@@ -272,12 +268,6 @@ ossl_x509revoked_to_der(VALUE self)
void
Init_ossl_x509revoked(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError);
cX509Rev = rb_define_class_under(mX509, "Revoked", rb_cObject);
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index 18acdc8ad0..9e43336c44 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509store_type, 0)
#define SetX509Store(obj, st) do { \
if (!(st)) { \
- ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (st); \
} while (0)
#define GetX509Store(obj, st) do { \
TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \
if (!(st)) { \
- ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
} \
} while (0)
@@ -28,14 +28,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, 0)
#define SetX509StCtx(obj, ctx) do { \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (ctx); \
} while (0)
#define GetX509StCtx(obj, ctx) do { \
TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
} \
} while (0)
@@ -62,7 +62,7 @@ call_verify_cb_proc(VALUE arg)
{
struct ossl_verify_cb_args *args = (struct ossl_verify_cb_args *)arg;
return rb_funcall(args->proc, rb_intern("call"), 2,
- args->preverify_ok, args->store_ctx);
+ args->preverify_ok, args->store_ctx);
}
int
@@ -73,33 +73,33 @@ ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx)
int state;
if (NIL_P(proc))
- return ok;
+ return ok;
ret = Qfalse;
rctx = rb_protect(ossl_x509stctx_new_i, (VALUE)ctx, &state);
if (state) {
- rb_set_errinfo(Qnil);
- rb_warn("StoreContext initialization failure");
+ rb_set_errinfo(Qnil);
+ rb_warn("StoreContext initialization failure");
}
else {
- args.proc = proc;
- args.preverify_ok = ok ? Qtrue : Qfalse;
- args.store_ctx = rctx;
- ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);
- if (state) {
- rb_set_errinfo(Qnil);
- rb_warn("exception in verify_callback is ignored");
- }
- RTYPEDDATA_DATA(rctx) = NULL;
+ args.proc = proc;
+ args.preverify_ok = ok ? Qtrue : Qfalse;
+ args.store_ctx = rctx;
+ ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);
+ if (state) {
+ rb_set_errinfo(Qnil);
+ rb_warn("exception in verify_callback is ignored");
+ }
+ RTYPEDDATA_DATA(rctx) = NULL;
}
if (ret == Qtrue) {
- X509_STORE_CTX_set_error(ctx, X509_V_OK);
- ok = 1;
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ ok = 1;
}
else {
- if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
- X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
- ok = 0;
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+ ok = 0;
}
return ok;
@@ -159,10 +159,10 @@ x509store_verify_cb(int ok, X509_STORE_CTX *ctx)
proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx);
if (!proc)
- proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),
- store_ex_verify_cb_idx);
+ proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),
+ store_ex_verify_cb_idx);
if (!proc)
- return ok;
+ return ok;
return ossl_verify_cb_call(proc, ok, ctx);
}
@@ -190,9 +190,10 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
X509_STORE *store;
GetX509Store(self, store);
+ if (!X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb))
+ ossl_raise(eX509StoreError, "X509_STORE_set_ex_data");
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_OBJ_WRITTEN(self, Qundef, cb);
return cb;
}
@@ -484,7 +485,7 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &cert, &chain);
ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
proc = rb_block_given_p() ? rb_block_proc() :
- rb_iv_get(self, "@verify_callback");
+ rb_iv_get(self, "@verify_callback");
rb_iv_set(ctx, "@verify_callback", proc);
result = rb_funcall(ctx, rb_intern("verify"), 0);
@@ -512,10 +513,8 @@ static void
ossl_x509stctx_free(void *ptr)
{
X509_STORE_CTX *ctx = ptr;
- if (X509_STORE_CTX_get0_untrusted(ctx))
- sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);
- if (X509_STORE_CTX_get0_cert(ctx))
- X509_free(X509_STORE_CTX_get0_cert(ctx));
+ sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);
+ X509_free((X509 *)X509_STORE_CTX_get0_cert(ctx));
X509_STORE_CTX_free(ctx);
}
@@ -610,7 +609,9 @@ ossl_x509stctx_verify(VALUE self)
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);
+ if (!X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb))
+ ossl_raise(eX509StoreError, "X509_STORE_CTX_set_ex_data");
+ RB_OBJ_WRITTEN(self, Qundef, cb);
switch (X509_verify_cert(ctx)) {
case 1:
@@ -735,10 +736,14 @@ static VALUE
ossl_x509stctx_get_curr_cert(VALUE self)
{
X509_STORE_CTX *ctx;
+ const X509 *x509;
GetX509StCtx(self, ctx);
+ x509 = X509_STORE_CTX_get_current_cert(ctx);
+ if (!x509)
+ return Qnil;
- return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
+ return ossl_x509_new(x509);
}
/*
@@ -753,12 +758,12 @@ static VALUE
ossl_x509stctx_get_curr_crl(VALUE self)
{
X509_STORE_CTX *ctx;
- X509_CRL *crl;
+ const X509_CRL *crl;
GetX509StCtx(self, ctx);
crl = X509_STORE_CTX_get0_current_crl(ctx);
if (!crl)
- return Qnil;
+ return Qnil;
return ossl_x509crl_new(crl);
}
@@ -854,19 +859,13 @@ void
Init_ossl_x509store(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
/* Register ext_data slot for verify callback Proc */
stctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"stctx_ex_verify_cb_idx", 0, 0, 0);
if (stctx_ex_verify_cb_idx < 0)
- ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
+ ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"store_ex_verify_cb_idx", 0, 0, 0);
if (store_ex_verify_cb_idx < 0)
- ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index");
+ ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index");
eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
diff --git a/ext/pathname/depend b/ext/pathname/depend
deleted file mode 100644
index cca7877dad..0000000000
--- a/ext/pathname/depend
+++ /dev/null
@@ -1,174 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-pathname.o: $(RUBY_EXTCONF_H)
-pathname.o: $(arch_hdrdir)/ruby/config.h
-pathname.o: $(hdrdir)/ruby.h
-pathname.o: $(hdrdir)/ruby/assert.h
-pathname.o: $(hdrdir)/ruby/backward.h
-pathname.o: $(hdrdir)/ruby/backward/2/assume.h
-pathname.o: $(hdrdir)/ruby/backward/2/attributes.h
-pathname.o: $(hdrdir)/ruby/backward/2/bool.h
-pathname.o: $(hdrdir)/ruby/backward/2/inttypes.h
-pathname.o: $(hdrdir)/ruby/backward/2/limits.h
-pathname.o: $(hdrdir)/ruby/backward/2/long_long.h
-pathname.o: $(hdrdir)/ruby/backward/2/stdalign.h
-pathname.o: $(hdrdir)/ruby/backward/2/stdarg.h
-pathname.o: $(hdrdir)/ruby/defines.h
-pathname.o: $(hdrdir)/ruby/encoding.h
-pathname.o: $(hdrdir)/ruby/intern.h
-pathname.o: $(hdrdir)/ruby/internal/abi.h
-pathname.o: $(hdrdir)/ruby/internal/anyargs.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-pathname.o: $(hdrdir)/ruby/internal/assume.h
-pathname.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-pathname.o: $(hdrdir)/ruby/internal/attr/artificial.h
-pathname.o: $(hdrdir)/ruby/internal/attr/cold.h
-pathname.o: $(hdrdir)/ruby/internal/attr/const.h
-pathname.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-pathname.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-pathname.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-pathname.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-pathname.o: $(hdrdir)/ruby/internal/attr/error.h
-pathname.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-pathname.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-pathname.o: $(hdrdir)/ruby/internal/attr/format.h
-pathname.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-pathname.o: $(hdrdir)/ruby/internal/attr/noalias.h
-pathname.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-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
-pathname.o: $(hdrdir)/ruby/internal/attr/warning.h
-pathname.o: $(hdrdir)/ruby/internal/attr/weakref.h
-pathname.o: $(hdrdir)/ruby/internal/cast.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_since.h
-pathname.o: $(hdrdir)/ruby/internal/config.h
-pathname.o: $(hdrdir)/ruby/internal/constant_p.h
-pathname.o: $(hdrdir)/ruby/internal/core.h
-pathname.o: $(hdrdir)/ruby/internal/core/rarray.h
-pathname.o: $(hdrdir)/ruby/internal/core/rbasic.h
-pathname.o: $(hdrdir)/ruby/internal/core/rbignum.h
-pathname.o: $(hdrdir)/ruby/internal/core/rclass.h
-pathname.o: $(hdrdir)/ruby/internal/core/rdata.h
-pathname.o: $(hdrdir)/ruby/internal/core/rfile.h
-pathname.o: $(hdrdir)/ruby/internal/core/rhash.h
-pathname.o: $(hdrdir)/ruby/internal/core/robject.h
-pathname.o: $(hdrdir)/ruby/internal/core/rregexp.h
-pathname.o: $(hdrdir)/ruby/internal/core/rstring.h
-pathname.o: $(hdrdir)/ruby/internal/core/rstruct.h
-pathname.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-pathname.o: $(hdrdir)/ruby/internal/ctype.h
-pathname.o: $(hdrdir)/ruby/internal/dllexport.h
-pathname.o: $(hdrdir)/ruby/internal/dosish.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/re.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/string.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-pathname.o: $(hdrdir)/ruby/internal/error.h
-pathname.o: $(hdrdir)/ruby/internal/eval.h
-pathname.o: $(hdrdir)/ruby/internal/event.h
-pathname.o: $(hdrdir)/ruby/internal/fl_type.h
-pathname.o: $(hdrdir)/ruby/internal/gc.h
-pathname.o: $(hdrdir)/ruby/internal/glob.h
-pathname.o: $(hdrdir)/ruby/internal/globals.h
-pathname.o: $(hdrdir)/ruby/internal/has/attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/builtin.h
-pathname.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/extension.h
-pathname.o: $(hdrdir)/ruby/internal/has/feature.h
-pathname.o: $(hdrdir)/ruby/internal/has/warning.h
-pathname.o: $(hdrdir)/ruby/internal/intern/array.h
-pathname.o: $(hdrdir)/ruby/internal/intern/bignum.h
-pathname.o: $(hdrdir)/ruby/internal/intern/class.h
-pathname.o: $(hdrdir)/ruby/internal/intern/compar.h
-pathname.o: $(hdrdir)/ruby/internal/intern/complex.h
-pathname.o: $(hdrdir)/ruby/internal/intern/cont.h
-pathname.o: $(hdrdir)/ruby/internal/intern/dir.h
-pathname.o: $(hdrdir)/ruby/internal/intern/enum.h
-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/hash.h
-pathname.o: $(hdrdir)/ruby/internal/intern/io.h
-pathname.o: $(hdrdir)/ruby/internal/intern/load.h
-pathname.o: $(hdrdir)/ruby/internal/intern/marshal.h
-pathname.o: $(hdrdir)/ruby/internal/intern/numeric.h
-pathname.o: $(hdrdir)/ruby/internal/intern/object.h
-pathname.o: $(hdrdir)/ruby/internal/intern/parse.h
-pathname.o: $(hdrdir)/ruby/internal/intern/proc.h
-pathname.o: $(hdrdir)/ruby/internal/intern/process.h
-pathname.o: $(hdrdir)/ruby/internal/intern/random.h
-pathname.o: $(hdrdir)/ruby/internal/intern/range.h
-pathname.o: $(hdrdir)/ruby/internal/intern/rational.h
-pathname.o: $(hdrdir)/ruby/internal/intern/re.h
-pathname.o: $(hdrdir)/ruby/internal/intern/ruby.h
-pathname.o: $(hdrdir)/ruby/internal/intern/select.h
-pathname.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-pathname.o: $(hdrdir)/ruby/internal/intern/signal.h
-pathname.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-pathname.o: $(hdrdir)/ruby/internal/intern/string.h
-pathname.o: $(hdrdir)/ruby/internal/intern/struct.h
-pathname.o: $(hdrdir)/ruby/internal/intern/thread.h
-pathname.o: $(hdrdir)/ruby/internal/intern/time.h
-pathname.o: $(hdrdir)/ruby/internal/intern/variable.h
-pathname.o: $(hdrdir)/ruby/internal/intern/vm.h
-pathname.o: $(hdrdir)/ruby/internal/interpreter.h
-pathname.o: $(hdrdir)/ruby/internal/iterator.h
-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/scan_args.h
-pathname.o: $(hdrdir)/ruby/internal/special_consts.h
-pathname.o: $(hdrdir)/ruby/internal/static_assert.h
-pathname.o: $(hdrdir)/ruby/internal/stdalign.h
-pathname.o: $(hdrdir)/ruby/internal/stdbool.h
-pathname.o: $(hdrdir)/ruby/internal/stdckdint.h
-pathname.o: $(hdrdir)/ruby/internal/symbol.h
-pathname.o: $(hdrdir)/ruby/internal/value.h
-pathname.o: $(hdrdir)/ruby/internal/value_type.h
-pathname.o: $(hdrdir)/ruby/internal/variable.h
-pathname.o: $(hdrdir)/ruby/internal/warning_push.h
-pathname.o: $(hdrdir)/ruby/internal/xmalloc.h
-pathname.o: $(hdrdir)/ruby/missing.h
-pathname.o: $(hdrdir)/ruby/onigmo.h
-pathname.o: $(hdrdir)/ruby/oniguruma.h
-pathname.o: $(hdrdir)/ruby/ruby.h
-pathname.o: $(hdrdir)/ruby/st.h
-pathname.o: $(hdrdir)/ruby/subst.h
-pathname.o: pathname.c
-# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/pathname/extconf.rb b/ext/pathname/extconf.rb
deleted file mode 100644
index b4e1617b9e..0000000000
--- a/ext/pathname/extconf.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: false
-require 'mkmf'
-create_makefile('pathname')
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
deleted file mode 100644
index 35fd778561..0000000000
--- a/ext/pathname/lib/pathname.rb
+++ /dev/null
@@ -1,621 +0,0 @@
-# frozen_string_literal: true
-#
-# = pathname.rb
-#
-# Object-Oriented Pathname Class
-#
-# Author:: Tanaka Akira <akr@m17n.org>
-# Documentation:: Author and Gavin Sinclair
-#
-# For documentation, see class Pathname.
-#
-
-require 'pathname.so'
-
-class Pathname
-
- VERSION = "0.4.0"
-
- # :stopdoc:
-
- # to_path is implemented so Pathname objects are usable with File.open, etc.
- TO_PATH = :to_path
-
- SAME_PATHS = if File::FNM_SYSCASE.nonzero?
- # Avoid #zero? here because #casecmp can return nil.
- proc {|a, b| a.casecmp(b) == 0}
- else
- proc {|a, b| a == b}
- end
-
-
- if File::ALT_SEPARATOR
- SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}"
- SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
- else
- SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}"
- SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
- end
-
- if File.dirname('A:') == 'A:.' # DOSish drive letter
- ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o
- else
- ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o
- end
- private_constant :ABSOLUTE_PATH
-
- # :startdoc:
-
- # chop_basename(path) -> [pre-basename, basename] or nil
- def chop_basename(path) # :nodoc:
- base = File.basename(path)
- if /\A#{SEPARATOR_PAT}?\z/o.match?(base)
- return nil
- else
- return path[0, path.rindex(base)], base
- end
- end
- private :chop_basename
-
- # split_names(path) -> prefix, [name, ...]
- def split_names(path) # :nodoc:
- names = []
- while r = chop_basename(path)
- path, basename = r
- names.unshift basename
- end
- return path, names
- end
- private :split_names
-
- def prepend_prefix(prefix, relpath) # :nodoc:
- if relpath.empty?
- File.dirname(prefix)
- elsif /#{SEPARATOR_PAT}/o.match?(prefix)
- prefix = File.dirname(prefix)
- prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
- prefix + relpath
- else
- prefix + relpath
- end
- end
- private :prepend_prefix
-
- # Returns clean pathname of +self+ with consecutive slashes and useless dots
- # removed. The filesystem is not accessed.
- #
- # If +consider_symlink+ is +true+, then a more conservative algorithm is used
- # to avoid breaking symbolic linkages. This may retain more +..+
- # entries than absolutely necessary, but without accessing the filesystem,
- # this can't be avoided.
- #
- # See Pathname#realpath.
- #
- def cleanpath(consider_symlink=false)
- if consider_symlink
- cleanpath_conservative
- else
- cleanpath_aggressive
- end
- end
-
- #
- # Clean the path simply by resolving and removing excess +.+ and +..+ entries.
- # Nothing more, nothing less.
- #
- def cleanpath_aggressive # :nodoc:
- path = @path
- names = []
- pre = path
- while r = chop_basename(pre)
- pre, base = r
- case base
- when '.'
- when '..'
- names.unshift base
- else
- if names[0] == '..'
- names.shift
- else
- names.unshift base
- end
- end
- end
- pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
- if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
- names.shift while names[0] == '..'
- end
- self.class.new(prepend_prefix(pre, File.join(*names)))
- end
- private :cleanpath_aggressive
-
- # has_trailing_separator?(path) -> bool
- def has_trailing_separator?(path) # :nodoc:
- if r = chop_basename(path)
- pre, basename = r
- pre.length + basename.length < path.length
- else
- false
- end
- end
- private :has_trailing_separator?
-
- # add_trailing_separator(path) -> path
- def add_trailing_separator(path) # :nodoc:
- if File.basename(path + 'a') == 'a'
- path
- else
- File.join(path, "") # xxx: Is File.join is appropriate to add separator?
- end
- end
- private :add_trailing_separator
-
- def del_trailing_separator(path) # :nodoc:
- if r = chop_basename(path)
- pre, basename = r
- pre + basename
- elsif /#{SEPARATOR_PAT}+\z/o =~ path
- $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
- else
- path
- end
- end
- private :del_trailing_separator
-
- def cleanpath_conservative # :nodoc:
- path = @path
- names = []
- pre = path
- while r = chop_basename(pre)
- pre, base = r
- names.unshift base if base != '.'
- end
- pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
- if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
- names.shift while names[0] == '..'
- end
- if names.empty?
- self.class.new(File.dirname(pre))
- else
- if names.last != '..' && File.basename(path) == '.'
- names << '.'
- end
- result = prepend_prefix(pre, File.join(*names))
- if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
- self.class.new(add_trailing_separator(result))
- else
- self.class.new(result)
- end
- end
- end
- private :cleanpath_conservative
-
- # Returns the parent directory.
- #
- # This is same as <code>self + '..'</code>.
- def parent
- self + '..'
- end
-
- # Returns +true+ if +self+ points to a mountpoint.
- def mountpoint?
- begin
- stat1 = self.lstat
- stat2 = self.parent.lstat
- stat1.dev != stat2.dev || stat1.ino == stat2.ino
- rescue Errno::ENOENT
- false
- end
- end
-
- #
- # Predicate method for root directories. Returns +true+ if the
- # pathname consists of consecutive slashes.
- #
- # It doesn't access the filesystem. So it may return +false+ for some
- # pathnames which points to roots such as <tt>/usr/..</tt>.
- #
- def root?
- chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o.match?(@path)
- end
-
- # Predicate method for testing whether a path is absolute.
- #
- # It returns +true+ if the pathname begins with a slash.
- #
- # p = Pathname.new('/im/sure')
- # p.absolute?
- # #=> true
- #
- # p = Pathname.new('not/so/sure')
- # p.absolute?
- # #=> false
- def absolute?
- ABSOLUTE_PATH.match? @path
- end
-
- # The opposite of Pathname#absolute?
- #
- # It returns +false+ if the pathname begins with a slash.
- #
- # p = Pathname.new('/im/sure')
- # p.relative?
- # #=> false
- #
- # p = Pathname.new('not/so/sure')
- # p.relative?
- # #=> true
- def relative?
- !absolute?
- end
-
- #
- # Iterates over each component of the path.
- #
- # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
- # # yields "usr", "bin", and "ruby".
- #
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").each_filename
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields "usr", "bin", and "ruby".
- #
- def each_filename # :yield: filename
- return to_enum(__method__) unless block_given?
- _, names = split_names(@path)
- names.each {|filename| yield filename }
- nil
- end
-
- # Iterates over and yields a new Pathname object
- # for each element in the given path in descending order.
- #
- # Pathname.new('/path/to/some/file.rb').descend {|v| p v}
- # #<Pathname:/>
- # #<Pathname:/path>
- # #<Pathname:/path/to>
- # #<Pathname:/path/to/some>
- # #<Pathname:/path/to/some/file.rb>
- #
- # Pathname.new('path/to/some/file.rb').descend {|v| p v}
- # #<Pathname:path>
- # #<Pathname:path/to>
- # #<Pathname:path/to/some>
- # #<Pathname:path/to/some/file.rb>
- #
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").descend
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.
- #
- # It doesn't access the filesystem.
- #
- def descend
- return to_enum(__method__) unless block_given?
- vs = []
- ascend {|v| vs << v }
- vs.reverse_each {|v| yield v }
- nil
- end
-
- # Iterates over and yields a new Pathname object
- # for each element in the given path in ascending order.
- #
- # Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
- # #<Pathname:/path/to/some/file.rb>
- # #<Pathname:/path/to/some>
- # #<Pathname:/path/to>
- # #<Pathname:/path>
- # #<Pathname:/>
- #
- # Pathname.new('path/to/some/file.rb').ascend {|v| p v}
- # #<Pathname:path/to/some/file.rb>
- # #<Pathname:path/to/some>
- # #<Pathname:path/to>
- # #<Pathname:path>
- #
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").ascend
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.
- #
- # It doesn't access the filesystem.
- #
- def ascend
- return to_enum(__method__) unless block_given?
- path = @path
- yield self
- while r = chop_basename(path)
- path, = r
- break if path.empty?
- yield self.class.new(del_trailing_separator(path))
- end
- end
-
- #
- # Appends a pathname fragment to +self+ to produce a new Pathname object.
- # Since +other+ is considered as a path relative to +self+, if +other+ is
- # an absolute path, the new Pathname object is created from just +other+.
- #
- # p1 = Pathname.new("/usr") # Pathname:/usr
- # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
- # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
- #
- # # / is aliased to +.
- # p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby
- # p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd
- #
- # This method doesn't access the file system; it is pure string manipulation.
- #
- def +(other)
- other = Pathname.new(other) unless Pathname === other
- Pathname.new(plus(@path, other.to_s))
- end
- alias / +
-
- def plus(path1, path2) # -> path # :nodoc:
- prefix2 = path2
- index_list2 = []
- basename_list2 = []
- while r2 = chop_basename(prefix2)
- prefix2, basename2 = r2
- index_list2.unshift prefix2.length
- basename_list2.unshift basename2
- end
- return path2 if prefix2 != ''
- prefix1 = path1
- while true
- while !basename_list2.empty? && basename_list2.first == '.'
- index_list2.shift
- basename_list2.shift
- end
- break unless r1 = chop_basename(prefix1)
- prefix1, basename1 = r1
- next if basename1 == '.'
- if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
- prefix1 = prefix1 + basename1
- break
- end
- index_list2.shift
- basename_list2.shift
- end
- r1 = chop_basename(prefix1)
- if !r1 && (r1 = /#{SEPARATOR_PAT}/o.match?(File.basename(prefix1)))
- while !basename_list2.empty? && basename_list2.first == '..'
- index_list2.shift
- basename_list2.shift
- end
- end
- if !basename_list2.empty?
- suffix2 = path2[index_list2.first..-1]
- r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
- else
- r1 ? prefix1 : File.dirname(prefix1)
- end
- end
- private :plus
-
- #
- # Joins the given pathnames onto +self+ to create a new Pathname object.
- # This is effectively the same as using Pathname#+ to append +self+ and
- # all arguments sequentially.
- #
- # path0 = Pathname.new("/usr") # Pathname:/usr
- # path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby
- # # is the same as
- # path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby
- # path0 == path1
- # #=> true
- #
- def join(*args)
- return self if args.empty?
- result = args.pop
- result = Pathname.new(result) unless Pathname === result
- return result if result.absolute?
- args.reverse_each {|arg|
- arg = Pathname.new(arg) unless Pathname === arg
- result = arg + result
- return result if result.absolute?
- }
- self + result
- end
-
- #
- # Returns the children of the directory (files and subdirectories, not
- # recursive) as an array of Pathname objects.
- #
- # By default, the returned pathnames will have enough information to access
- # the files. If you set +with_directory+ to +false+, then the returned
- # pathnames will contain the filename only.
- #
- # For example:
- # pn = Pathname("/usr/lib/ruby/1.8")
- # pn.children
- # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
- # Pathname:/usr/lib/ruby/1.8/Env.rb,
- # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
- # pn.children(false)
- # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
- #
- # Note that the results never contain the entries +.+ and +..+ in
- # the directory because they are not children.
- #
- def children(with_directory=true)
- with_directory = false if @path == '.'
- result = []
- Dir.foreach(@path) {|e|
- next if e == '.' || e == '..'
- if with_directory
- result << self.class.new(File.join(@path, e))
- else
- result << self.class.new(e)
- end
- }
- result
- end
-
- # Iterates over the children of the directory
- # (files and subdirectories, not recursive).
- #
- # It yields Pathname object for each child.
- #
- # By default, the yielded pathnames will have enough information to access
- # the files.
- #
- # If you set +with_directory+ to +false+, then the returned pathnames will
- # contain the filename only.
- #
- # Pathname("/usr/local").each_child {|f| p f }
- # #=> #<Pathname:/usr/local/share>
- # # #<Pathname:/usr/local/bin>
- # # #<Pathname:/usr/local/games>
- # # #<Pathname:/usr/local/lib>
- # # #<Pathname:/usr/local/include>
- # # #<Pathname:/usr/local/sbin>
- # # #<Pathname:/usr/local/src>
- # # #<Pathname:/usr/local/man>
- #
- # Pathname("/usr/local").each_child(false) {|f| p f }
- # #=> #<Pathname:share>
- # # #<Pathname:bin>
- # # #<Pathname:games>
- # # #<Pathname:lib>
- # # #<Pathname:include>
- # # #<Pathname:sbin>
- # # #<Pathname:src>
- # # #<Pathname:man>
- #
- # Note that the results never contain the entries +.+ and +..+ in
- # the directory because they are not children.
- #
- # See Pathname#children
- #
- def each_child(with_directory=true, &b)
- children(with_directory).each(&b)
- end
-
- #
- # Returns a relative path from the given +base_directory+ to the receiver.
- #
- # If +self+ is absolute, then +base_directory+ must be absolute too.
- #
- # If +self+ is relative, then +base_directory+ must be relative too.
- #
- # This method doesn't access the filesystem. It assumes no symlinks.
- #
- # ArgumentError is raised when it cannot find a relative path.
- #
- # Note that this method does not handle situations where the case sensitivity
- # of the filesystem in use differs from the operating system default.
- #
- def relative_path_from(base_directory)
- base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
- dest_directory = self.cleanpath.to_s
- base_directory = base_directory.cleanpath.to_s
- dest_prefix = dest_directory
- dest_names = []
- while r = chop_basename(dest_prefix)
- dest_prefix, basename = r
- dest_names.unshift basename if basename != '.'
- end
- base_prefix = base_directory
- base_names = []
- while r = chop_basename(base_prefix)
- base_prefix, basename = r
- base_names.unshift basename if basename != '.'
- end
- unless SAME_PATHS[dest_prefix, base_prefix]
- raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
- end
- while !dest_names.empty? &&
- !base_names.empty? &&
- SAME_PATHS[dest_names.first, base_names.first]
- dest_names.shift
- base_names.shift
- end
- if base_names.include? '..'
- raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
- end
- base_names.fill('..')
- relpath_names = base_names + dest_names
- if relpath_names.empty?
- Pathname.new('.')
- else
- Pathname.new(File.join(*relpath_names))
- end
- end
-end
-
-
-class Pathname # * Find *
- #
- # Iterates over the directory tree in a depth first manner, yielding a
- # Pathname for each file under "this" directory.
- #
- # Returns an Enumerator if no block is given.
- #
- # Since it is implemented by the standard library module Find, Find.prune can
- # be used to control the traversal.
- #
- # If +self+ is +.+, yielded pathnames begin with a filename in the
- # current directory, not +./+.
- #
- # See Find.find
- #
- def find(ignore_error: true) # :yield: pathname
- return to_enum(__method__, ignore_error: ignore_error) unless block_given?
- require 'find'
- if @path == '.'
- Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) }
- else
- Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
- end
- end
-end
-
-
-class Pathname # * FileUtils *
- # Creates a full path, including any intermediate directories that don't yet
- # exist.
- #
- # See FileUtils.mkpath and FileUtils.mkdir_p
- def mkpath(mode: nil)
- require 'fileutils'
- FileUtils.mkpath(@path, mode: mode)
- self
- end
-
- # Recursively deletes a directory, including all directories beneath it.
- #
- # See FileUtils.rm_rf
- def rmtree(noop: nil, verbose: nil, secure: nil)
- # The name "rmtree" is borrowed from File::Path of Perl.
- # File::Path provides "mkpath" and "rmtree".
- require 'fileutils'
- FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure)
- self
- end
-end
-
-class Pathname # * tmpdir *
- # Creates a tmp directory and wraps the returned path in a Pathname object.
- #
- # See Dir.mktmpdir
- def self.mktmpdir
- require 'tmpdir' unless defined?(Dir.mktmpdir)
- if block_given?
- Dir.mktmpdir do |dir|
- dir = self.new(dir)
- yield dir
- end
- else
- self.new(Dir.mktmpdir)
- end
- end
-end
diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c
deleted file mode 100644
index cdecb3f897..0000000000
--- a/ext/pathname/pathname.c
+++ /dev/null
@@ -1,1668 +0,0 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-static VALUE rb_cPathname;
-static ID id_ENOTDIR;
-static ID id_at_path;
-static ID id_atime;
-static ID id_base;
-static ID id_basename;
-static ID id_binread;
-static ID id_binwrite;
-static ID id_birthtime;
-static ID id_blockdev_p;
-static ID id_chardev_p;
-static ID id_chmod;
-static ID id_chown;
-static ID id_ctime;
-static ID id_directory_p;
-static ID id_dirname;
-static ID id_empty_p;
-static ID id_entries;
-static ID id_executable_p;
-static ID id_executable_real_p;
-static ID id_exist_p;
-static ID id_expand_path;
-static ID id_extname;
-static ID id_file_p;
-static ID id_fnmatch;
-static ID id_foreach;
-static ID id_ftype;
-static ID id_getwd;
-static ID id_glob;
-static ID id_grpowned_p;
-static ID id_lchmod;
-static ID id_lchown;
-static ID id_link;
-static ID id_lstat;
-static ID id_lutime;
-static ID id_mkdir;
-static ID id_mtime;
-static ID id_open;
-static ID id_owned_p;
-static ID id_pipe_p;
-static ID id_read;
-static ID id_readable_p;
-static ID id_readable_real_p;
-static ID id_readlines;
-static ID id_readlink;
-static ID id_realdirpath;
-static ID id_realpath;
-static ID id_rename;
-static ID id_rmdir;
-static ID id_setgid_p;
-static ID id_setuid_p;
-static ID id_size;
-static ID id_size_p;
-static ID id_socket_p;
-static ID id_split;
-static ID id_stat;
-static ID id_sticky_p;
-static ID id_sub;
-static ID id_symlink;
-static ID id_symlink_p;
-static ID id_sysopen;
-static ID id_to_path;
-static ID id_truncate;
-static ID id_unlink;
-static ID id_utime;
-static ID id_world_readable_p;
-static ID id_world_writable_p;
-static ID id_writable_p;
-static ID id_writable_real_p;
-static ID id_write;
-static ID id_zero_p;
-
-static VALUE
-get_strpath(VALUE obj)
-{
- VALUE strpath;
- strpath = rb_ivar_get(obj, id_at_path);
- if (!RB_TYPE_P(strpath, T_STRING))
- rb_raise(rb_eTypeError, "unexpected @path");
- return strpath;
-}
-
-static void
-set_strpath(VALUE obj, VALUE val)
-{
- rb_ivar_set(obj, id_at_path, val);
-}
-
-/*
- * Create a Pathname object from the given String (or String-like object).
- * If +path+ contains a NULL character (<tt>\0</tt>), an ArgumentError is raised.
- */
-static VALUE
-path_initialize(VALUE self, VALUE arg)
-{
- VALUE str;
- if (RB_TYPE_P(arg, T_STRING)) {
- str = arg;
- }
- else {
- str = rb_check_funcall(arg, id_to_path, 0, NULL);
- if (str == Qundef)
- str = arg;
- StringValue(str);
- }
- if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str)))
- rb_raise(rb_eArgError, "pathname contains null byte");
- str = rb_obj_dup(str);
-
- set_strpath(self, str);
- return self;
-}
-
-/*
- * call-seq:
- * pathname.freeze -> obj
- *
- * Freezes this Pathname.
- *
- * See Object.freeze.
- */
-static VALUE
-path_freeze(VALUE self)
-{
- rb_call_super(0, 0);
- rb_str_freeze(get_strpath(self));
- 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.
- */
-static VALUE
-path_eq(VALUE self, VALUE other)
-{
- if (!rb_obj_is_kind_of(other, rb_cPathname))
- return Qfalse;
- return rb_str_equal(get_strpath(self), get_strpath(other));
-}
-
-/*
- * Provides a case-sensitive comparison operator for pathnames.
- *
- * Pathname.new('/usr') <=> Pathname.new('/usr/bin')
- * #=> -1
- * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
- * #=> 0
- * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
- * #=> 1
- *
- * It will return +-1+, +0+ or +1+ depending on the value of the left argument
- * relative to the right argument. Or it will return +nil+ if the arguments
- * are not comparable.
- */
-static VALUE
-path_cmp(VALUE self, VALUE other)
-{
- VALUE s1, s2;
- char *p1, *p2;
- char *e1, *e2;
- if (!rb_obj_is_kind_of(other, rb_cPathname))
- return Qnil;
- s1 = get_strpath(self);
- s2 = get_strpath(other);
- p1 = RSTRING_PTR(s1);
- p2 = RSTRING_PTR(s2);
- e1 = p1 + RSTRING_LEN(s1);
- e2 = p2 + RSTRING_LEN(s2);
- while (p1 < e1 && p2 < e2) {
- int c1, c2;
- c1 = (unsigned char)*p1++;
- c2 = (unsigned char)*p2++;
- if (c1 == '/') c1 = '\0';
- if (c2 == '/') c2 = '\0';
- if (c1 != c2) {
- if (c1 < c2)
- return INT2FIX(-1);
- else
- return INT2FIX(1);
- }
- }
- if (p1 < e1)
- return INT2FIX(1);
- if (p2 < e2)
- return INT2FIX(-1);
- return INT2FIX(0);
-}
-
-#ifndef ST2FIX
-#define ST2FIX(h) LONG2FIX((long)(h))
-#endif
-
-/* :nodoc: */
-static VALUE
-path_hash(VALUE self)
-{
- return ST2FIX(rb_str_hash(get_strpath(self)));
-}
-
-/*
- * call-seq:
- * pathname.to_s -> string
- * pathname.to_path -> string
- *
- * Return the path as a String.
- *
- * to_path is implemented so Pathname objects are usable with File.open, etc.
- */
-static VALUE
-path_to_s(VALUE self)
-{
- return rb_obj_dup(get_strpath(self));
-}
-
-/* :nodoc: */
-static VALUE
-path_inspect(VALUE self)
-{
- const char *c = rb_obj_classname(self);
- VALUE str = get_strpath(self);
- return rb_sprintf("#<%s:%"PRIsVALUE">", c, str);
-}
-
-/*
- * Return a pathname which is substituted by String#sub.
- *
- * path1 = Pathname.new('/usr/bin/perl')
- * path1.sub('perl', 'ruby')
- * #=> #<Pathname:/usr/bin/ruby>
- */
-static VALUE
-path_sub(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
-
- if (rb_block_given_p()) {
- str = rb_block_call(str, id_sub, argc, argv, 0, 0);
- }
- else {
- str = rb_funcallv(str, id_sub, argc, argv);
- }
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Return a pathname with +repl+ added as a suffix to the basename.
- *
- * If self has no extension part, +repl+ is appended.
- *
- * Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
- * #=> #<Pathname:/usr/bin/shutdown.rb>
- */
-static VALUE
-path_sub_ext(VALUE self, VALUE repl)
-{
- VALUE str = get_strpath(self);
- VALUE str2;
- long extlen;
- const char *ext;
- const char *p;
-
- StringValue(repl);
- p = RSTRING_PTR(str);
- extlen = RSTRING_LEN(str);
- ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
- if (ext == NULL) {
- ext = p + RSTRING_LEN(str);
- }
- else if (extlen <= 1) {
- ext += extlen;
- }
- str2 = rb_str_subseq(str, 0, ext-p);
- rb_str_append(str2, repl);
- return rb_class_new_instance(1, &str2, rb_obj_class(self));
-}
-
-/* Facade for File */
-
-/*
- * Returns the real (absolute) pathname for +self+ in the actual
- * filesystem.
- *
- * Does not contain symlinks or useless dots, +..+ and +.+.
- *
- * All components of the pathname must exist when this method is
- * called.
- *
- */
-static VALUE
-path_realpath(int argc, VALUE *argv, VALUE self)
-{
- VALUE basedir, str;
- rb_scan_args(argc, argv, "01", &basedir);
- str = rb_funcall(rb_cFile, id_realpath, 2, get_strpath(self), basedir);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the real (absolute) pathname of +self+ in the actual filesystem.
- *
- * Does not contain symlinks or useless dots, +..+ and +.+.
- *
- * The last component of the real pathname can be nonexistent.
- */
-static VALUE
-path_realdirpath(int argc, VALUE *argv, VALUE self)
-{
- VALUE basedir, str;
- rb_scan_args(argc, argv, "01", &basedir);
- str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * call-seq:
- * pathname.each_line {|line| ... }
- * pathname.each_line(sep=$/ [, open_args]) {|line| block } -> nil
- * pathname.each_line(limit [, open_args]) {|line| block } -> nil
- * pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil
- * pathname.each_line(...) -> an_enumerator
- *
- * Iterates over each line in the file and yields a String object for each.
- */
-static VALUE
-path_each_line(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cFile, id_foreach, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- return rb_funcallv_kw(rb_cFile, id_foreach, 1+n, args, RB_PASS_CALLED_KEYWORDS);
- }
-}
-
-/*
- * call-seq:
- * pathname.read([length [, offset]]) -> string
- * pathname.read([length [, offset]], open_args) -> string
- *
- * Returns all data from the file, or the first +N+ bytes if specified.
- *
- * See File.read.
- *
- */
-static VALUE
-path_read(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_read, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.binread([length [, offset]]) -> string
- *
- * Returns all the bytes from the file, or the first +N+ if specified.
- *
- * See File.binread.
- *
- */
-static VALUE
-path_binread(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
- return rb_funcallv(rb_cFile, id_binread, 1+n, args);
-}
-
-/*
- * call-seq:
- * pathname.write(string, [offset] ) => fixnum
- * pathname.write(string, [offset], open_args ) => fixnum
- *
- * Writes +contents+ to the file.
- *
- * See File.write.
- *
- */
-static VALUE
-path_write(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_write, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.binwrite(string, [offset] ) => fixnum
- * pathname.binwrite(string, [offset], open_args ) => fixnum
- *
- * Writes +contents+ to the file, opening it in binary mode.
- *
- * See File.binwrite.
- *
- */
-static VALUE
-path_binwrite(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_binwrite, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.readlines(sep=$/ [, open_args]) -> array
- * pathname.readlines(limit [, open_args]) -> array
- * pathname.readlines(sep, limit [, open_args]) -> array
- *
- * Returns all the lines from the file.
- *
- * See File.readlines.
- *
- */
-static VALUE
-path_readlines(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_readlines, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.sysopen([mode, [perm]]) -> fixnum
- *
- * See IO.sysopen.
- *
- */
-static VALUE
-path_sysopen(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
- return rb_funcallv(rb_cIO, id_sysopen, 1+n, args);
-}
-
-/*
- * call-seq:
- * pathname.atime -> time
- *
- * Returns the last access time for the file.
- *
- * See File.atime.
- */
-static VALUE
-path_atime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.birthtime -> time
- *
- * Returns the birth time for the file.
- * If the platform doesn't have birthtime, raises NotImplementedError.
- *
- * See File.birthtime.
- */
-static VALUE
-path_birthtime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.ctime -> time
- *
- * Returns the last change time, using directory information, not the file itself.
- *
- * See File.ctime.
- */
-static VALUE
-path_ctime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_ctime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.mtime -> time
- *
- * Returns the last modified time of the file.
- *
- * See File.mtime.
- */
-static VALUE
-path_mtime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.chmod(mode_int) -> integer
- *
- * Changes file permissions.
- *
- * See File.chmod.
- */
-static VALUE
-path_chmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.lchmod(mode_int) -> integer
- *
- * Same as Pathname.chmod, but does not follow symbolic links.
- *
- * See File.lchmod.
- */
-static VALUE
-path_lchmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_lchmod, 2, mode, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.chown(owner_int, group_int) -> integer
- *
- * Change owner and group of the file.
- *
- * See File.chown.
- */
-static VALUE
-path_chown(VALUE self, VALUE owner, VALUE group)
-{
- return rb_funcall(rb_cFile, id_chown, 3, owner, group, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.lchown(owner_int, group_int) -> integer
- *
- * Same as Pathname.chown, but does not follow symbolic links.
- *
- * See File.lchown.
- */
-static VALUE
-path_lchown(VALUE self, VALUE owner, VALUE group)
-{
- return rb_funcall(rb_cFile, id_lchown, 3, owner, group, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.fnmatch(pattern, [flags]) -> true or false
- * pathname.fnmatch?(pattern, [flags]) -> true or false
- *
- * Return +true+ if the receiver matches the given pattern.
- *
- * See File.fnmatch.
- */
-static VALUE
-path_fnmatch(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE pattern, flags;
- if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
- return rb_funcall(rb_cFile, id_fnmatch, 2, pattern, str);
- else
- return rb_funcall(rb_cFile, id_fnmatch, 3, pattern, str, flags);
-}
-
-/*
- * call-seq:
- * pathname.ftype -> string
- *
- * Returns "type" of file ("file", "directory", etc).
- *
- * See File.ftype.
- */
-static VALUE
-path_ftype(VALUE self)
-{
- return rb_funcall(rb_cFile, id_ftype, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.make_link(old)
- *
- * Creates a hard link at _pathname_.
- *
- * See File.link.
- */
-static VALUE
-path_make_link(VALUE self, VALUE old)
-{
- return rb_funcall(rb_cFile, id_link, 2, old, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.open()
- * pathname.open(mode="r" [, opt]) -> file
- * pathname.open([mode [, perm]] [, opt]) -> file
- * pathname.open(mode="r" [, opt]) {|file| block } -> obj
- * pathname.open([mode [, perm]] [, opt]) {|file| block } -> obj
- *
- * Opens the file for reading or writing.
- *
- * See File.open.
- */
-static VALUE
-path_open(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cFile, id_open, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- return rb_funcallv_kw(rb_cFile, id_open, 1+n, args, RB_PASS_CALLED_KEYWORDS);
- }
-}
-
-/*
- * Read symbolic link.
- *
- * See File.readlink.
- */
-static VALUE
-path_readlink(VALUE self)
-{
- VALUE str;
- str = rb_funcall(rb_cFile, id_readlink, 1, get_strpath(self));
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Rename the file.
- *
- * See File.rename.
- */
-static VALUE
-path_rename(VALUE self, VALUE to)
-{
- return rb_funcall(rb_cFile, id_rename, 2, get_strpath(self), to);
-}
-
-/*
- * Returns a File::Stat object.
- *
- * See File.stat.
- */
-static VALUE
-path_stat(VALUE self)
-{
- return rb_funcall(rb_cFile, id_stat, 1, get_strpath(self));
-}
-
-/*
- * See File.lstat.
- */
-static VALUE
-path_lstat(VALUE self)
-{
- return rb_funcall(rb_cFile, id_lstat, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.make_symlink(old)
- *
- * Creates a symbolic link.
- *
- * See File.symlink.
- */
-static VALUE
-path_make_symlink(VALUE self, VALUE old)
-{
- return rb_funcall(rb_cFile, id_symlink, 2, old, get_strpath(self));
-}
-
-/*
- * Truncates the file to +length+ bytes.
- *
- * See File.truncate.
- */
-static VALUE
-path_truncate(VALUE self, VALUE length)
-{
- return rb_funcall(rb_cFile, id_truncate, 2, get_strpath(self), length);
-}
-
-/*
- * Update the access and modification times of the file.
- *
- * See File.utime.
- */
-static VALUE
-path_utime(VALUE self, VALUE atime, VALUE mtime)
-{
- return rb_funcall(rb_cFile, id_utime, 3, atime, mtime, get_strpath(self));
-}
-
-/*
- * Update the access and modification times of the file.
- *
- * Same as Pathname#utime, but does not follow symbolic links.
- *
- * See File.lutime.
- */
-static VALUE
-path_lutime(VALUE self, VALUE atime, VALUE mtime)
-{
- return rb_funcall(rb_cFile, id_lutime, 3, atime, mtime, get_strpath(self));
-}
-
-/*
- * Returns the last component of the path.
- *
- * See File.basename.
- */
-static VALUE
-path_basename(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE fext;
- if (rb_scan_args(argc, argv, "01", &fext) == 0)
- str = rb_funcall(rb_cFile, id_basename, 1, str);
- else
- str = rb_funcall(rb_cFile, id_basename, 2, str, fext);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns all but the last component of the path.
- *
- * See File.dirname.
- */
-static VALUE
-path_dirname(VALUE self)
-{
- VALUE str = get_strpath(self);
- str = rb_funcall(rb_cFile, id_dirname, 1, str);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the file's extension.
- *
- * See File.extname.
- */
-static VALUE
-path_extname(VALUE self)
-{
- VALUE str = get_strpath(self);
- return rb_funcall(rb_cFile, id_extname, 1, str);
-}
-
-/*
- * Returns the absolute path for the file.
- *
- * See File.expand_path.
- */
-static VALUE
-path_expand_path(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE dname;
- if (rb_scan_args(argc, argv, "01", &dname) == 0)
- str = rb_funcall(rb_cFile, id_expand_path, 1, str);
- else
- str = rb_funcall(rb_cFile, id_expand_path, 2, str, dname);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the #dirname and the #basename in an Array.
- *
- * See File.split.
- */
-static VALUE
-path_split(VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE ary, dirname, basename;
- ary = rb_funcall(rb_cFile, id_split, 1, str);
- Check_Type(ary, T_ARRAY);
- dirname = rb_ary_entry(ary, 0);
- basename = rb_ary_entry(ary, 1);
- dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self));
- basename = rb_class_new_instance(1, &basename, rb_obj_class(self));
- return rb_ary_new3(2, dirname, basename);
-}
-
-/*
- * See FileTest.blockdev?.
- */
-static VALUE
-path_blockdev_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_blockdev_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.chardev?.
- */
-static VALUE
-path_chardev_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_chardev_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.executable?.
- */
-static VALUE
-path_executable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_executable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.executable_real?.
- */
-static VALUE
-path_executable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_executable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.exist?.
- */
-static VALUE
-path_exist_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_exist_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.grpowned?.
- */
-static VALUE
-path_grpowned_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_grpowned_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.directory?.
- */
-static VALUE
-path_directory_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_directory_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.file?.
- */
-static VALUE
-path_file_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_file_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.pipe?.
- */
-static VALUE
-path_pipe_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_pipe_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.socket?.
- */
-static VALUE
-path_socket_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_socket_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.owned?.
- */
-static VALUE
-path_owned_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_owned_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.readable?.
- */
-static VALUE
-path_readable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_readable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.world_readable?.
- */
-static VALUE
-path_world_readable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_world_readable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.readable_real?.
- */
-static VALUE
-path_readable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_readable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.setuid?.
- */
-static VALUE
-path_setuid_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_setuid_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.setgid?.
- */
-static VALUE
-path_setgid_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_setgid_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.size.
- */
-static VALUE
-path_size(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_size, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.size?.
- */
-static VALUE
-path_size_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_size_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.sticky?.
- */
-static VALUE
-path_sticky_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_sticky_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.symlink?.
- */
-static VALUE
-path_symlink_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_symlink_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.writable?.
- */
-static VALUE
-path_writable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_writable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.world_writable?.
- */
-static VALUE
-path_world_writable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_world_writable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.writable_real?.
- */
-static VALUE
-path_writable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_writable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.zero?.
- */
-static VALUE
-path_zero_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_zero_p, 1, get_strpath(self));
-}
-
-/*
- * Tests the file is empty.
- *
- * See Dir#empty? and FileTest.empty?.
- */
-static VALUE
-path_empty_p(VALUE self)
-{
-
- VALUE path = get_strpath(self);
- if (RTEST(rb_funcall(rb_mFileTest, id_directory_p, 1, path)))
- return rb_funcall(rb_cDir, id_empty_p, 1, path);
- else
- return rb_funcall(rb_mFileTest, id_empty_p, 1, path);
-}
-
-static VALUE
-s_glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
-{
- return rb_yield(rb_class_new_instance(1, &elt, klass));
-}
-
-/*
- * Returns or yields Pathname objects.
- *
- * Pathname.glob("lib/i*.rb")
- * #=> [#<Pathname:lib/ipaddr.rb>, #<Pathname:lib/irb.rb>]
- *
- * See Dir.glob.
- */
-static VALUE
-path_s_glob(int argc, VALUE *argv, VALUE klass)
-{
- VALUE args[3];
- int n;
-
- n = rb_scan_args(argc, argv, "12", &args[0], &args[1], &args[2]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cDir, id_glob, n, args, s_glob_i, klass, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- VALUE ary;
- long i;
- ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_CALLED_KEYWORDS);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_class_new_instance(1, &elt, klass);
- rb_ary_store(ary, i, elt);
- }
- return ary;
- }
-}
-
-static VALUE
-glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, self))
-{
- elt = rb_funcall(self, '+', 1, elt);
- return rb_yield(elt);
-}
-
-/*
- * Returns or yields Pathname objects.
- *
- * Pathname("ruby-2.4.2").glob("R*.md")
- * #=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
- *
- * See Dir.glob.
- * This method uses the +base+ keyword argument of Dir.glob.
- */
-static VALUE
-path_glob(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
- if (n == 1)
- args[1] = INT2FIX(0);
-
- args[2] = rb_hash_new();
- rb_hash_aset(args[2], ID2SYM(id_base), get_strpath(self));
-
- n = 3;
-
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cDir, id_glob, n, args, glob_i, self, RB_PASS_KEYWORDS);
- }
- else {
- VALUE ary;
- long i;
- ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_KEYWORDS);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_funcall(self, '+', 1, elt);
- rb_ary_store(ary, i, elt);
- }
- return ary;
- }
-}
-
-/*
- * Returns the current working directory as a Pathname.
- *
- * Pathname.getwd
- * #=> #<Pathname:/home/zzak/projects/ruby>
- *
- * See Dir.getwd.
- */
-static VALUE
-path_s_getwd(VALUE klass)
-{
- VALUE str;
- str = rb_funcall(rb_cDir, id_getwd, 0);
- return rb_class_new_instance(1, &str, klass);
-}
-
-/*
- * Return the entries (files and subdirectories) in the directory, each as a
- * Pathname object.
- *
- * The results contains just the names in the directory, without any trailing
- * slashes or recursive look-up.
- *
- * pp Pathname.new('/usr/local').entries
- * #=> [#<Pathname:share>,
- * # #<Pathname:lib>,
- * # #<Pathname:..>,
- * # #<Pathname:include>,
- * # #<Pathname:etc>,
- * # #<Pathname:bin>,
- * # #<Pathname:man>,
- * # #<Pathname:games>,
- * # #<Pathname:.>,
- * # #<Pathname:sbin>,
- * # #<Pathname:src>]
- *
- * The result may contain the current directory <code>#<Pathname:.></code> and
- * the parent directory <code>#<Pathname:..></code>.
- *
- * If you don't want +.+ and +..+ and
- * want directories, consider Pathname#children.
- */
-static VALUE
-path_entries(VALUE self)
-{
- VALUE klass, str, ary;
- long i;
- klass = rb_obj_class(self);
- str = get_strpath(self);
- ary = rb_funcall(rb_cDir, id_entries, 1, str);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_class_new_instance(1, &elt, klass);
- rb_ary_store(ary, i, elt);
- }
- return ary;
-}
-
-/*
- * Create the referenced directory.
- *
- * See Dir.mkdir.
- */
-static VALUE
-path_mkdir(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE vmode;
- if (rb_scan_args(argc, argv, "01", &vmode) == 0)
- return rb_funcall(rb_cDir, id_mkdir, 1, str);
- else
- return rb_funcall(rb_cDir, id_mkdir, 2, str, vmode);
-}
-
-/*
- * Remove the referenced directory.
- *
- * See Dir.rmdir.
- */
-static VALUE
-path_rmdir(VALUE self)
-{
- return rb_funcall(rb_cDir, id_rmdir, 1, get_strpath(self));
-}
-
-/*
- * Opens the referenced directory.
- *
- * See Dir.open.
- */
-static VALUE
-path_opendir(VALUE self)
-{
- VALUE args[1];
-
- args[0] = get_strpath(self);
- return rb_block_call(rb_cDir, id_open, 1, args, 0, 0);
-}
-
-static VALUE
-each_entry_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
-{
- return rb_yield(rb_class_new_instance(1, &elt, klass));
-}
-
-/*
- * Iterates over the entries (files and subdirectories) in the directory,
- * yielding a Pathname object for each entry.
- */
-static VALUE
-path_each_entry(VALUE self)
-{
- VALUE args[1];
- RETURN_ENUMERATOR(self, 0, 0);
-
- args[0] = get_strpath(self);
- return rb_block_call(rb_cDir, id_foreach, 1, args, each_entry_i, rb_obj_class(self));
-}
-
-static VALUE
-unlink_body(VALUE str)
-{
- return rb_funcall(rb_cDir, id_unlink, 1, str);
-}
-
-static VALUE
-unlink_rescue(VALUE str, VALUE errinfo)
-{
- return rb_funcall(rb_cFile, id_unlink, 1, str);
-}
-
-/*
- * Removes a file or directory, using File.unlink if +self+ is a file, or
- * Dir.unlink as necessary.
- */
-static VALUE
-path_unlink(VALUE self)
-{
- VALUE eENOTDIR = rb_const_get_at(rb_mErrno, id_ENOTDIR);
- VALUE str = get_strpath(self);
- return rb_rescue2(unlink_body, str, unlink_rescue, str, eENOTDIR, (VALUE)0);
-}
-
-/*
- * :call-seq:
- * Pathname(path) -> pathname
- *
- * Creates a new Pathname object from the given string, +path+, and returns
- * pathname object.
- *
- * In order to use this constructor, you must first require the Pathname
- * standard library extension.
- *
- * require 'pathname'
- * Pathname("/home/zzak")
- * #=> #<Pathname:/home/zzak>
- *
- * See also Pathname::new for more information.
- */
-static VALUE
-path_f_pathname(VALUE self, VALUE str)
-{
- if (CLASS_OF(str) == rb_cPathname)
- return str;
- return rb_class_new_instance(1, &str, rb_cPathname);
-}
-
-/*
- *
- * Pathname represents the name of a file or directory on the filesystem,
- * but not the file itself.
- *
- * The pathname depends on the Operating System: Unix, Windows, etc.
- * This library works with pathnames of local OS, however non-Unix pathnames
- * are supported experimentally.
- *
- * A Pathname can be relative or absolute. It's not until you try to
- * reference the file that it even matters whether the file exists or not.
- *
- * Pathname is immutable. It has no method for destructive update.
- *
- * The goal of this class is to manipulate file path information in a neater
- * way than standard Ruby provides. The examples below demonstrate the
- * difference.
- *
- * *All* functionality from File, FileTest, and some from Dir and FileUtils is
- * included, in an unsurprising way. It is essentially a facade for all of
- * these, and more.
- *
- * == Examples
- *
- * === Example 1: Using Pathname
- *
- * require 'pathname'
- * pn = Pathname.new("/usr/bin/ruby")
- * size = pn.size # 27662
- * isdir = pn.directory? # false
- * dir = pn.dirname # Pathname:/usr/bin
- * base = pn.basename # Pathname:ruby
- * dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby]
- * data = pn.read
- * pn.open { |f| _ }
- * pn.each_line { |line| _ }
- *
- * === Example 2: Using standard Ruby
- *
- * pn = "/usr/bin/ruby"
- * size = File.size(pn) # 27662
- * isdir = File.directory?(pn) # false
- * dir = File.dirname(pn) # "/usr/bin"
- * base = File.basename(pn) # "ruby"
- * dir, base = File.split(pn) # ["/usr/bin", "ruby"]
- * data = File.read(pn)
- * File.open(pn) { |f| _ }
- * File.foreach(pn) { |line| _ }
- *
- * === Example 3: Special features
- *
- * p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib
- * p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8
- * p3 = p1.parent # Pathname:/usr
- * p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8
- * pwd = Pathname.pwd # Pathname:/home/gavin
- * pwd.absolute? # true
- * p5 = Pathname.new "." # Pathname:.
- * p5 = p5 + "music/../articles" # Pathname:music/../articles
- * p5.cleanpath # Pathname:articles
- * p5.realpath # Pathname:/home/gavin/articles
- * p5.children # [Pathname:/home/gavin/articles/linux, ...]
- *
- * == Breakdown of functionality
- *
- * === Core methods
- *
- * These methods are effectively manipulating a String, because that's
- * all a path is. None of these access the file system except for
- * #mountpoint?, #children, #each_child, #realdirpath and #realpath.
- *
- * - +
- * - #join
- * - #parent
- * - #root?
- * - #absolute?
- * - #relative?
- * - #relative_path_from
- * - #each_filename
- * - #cleanpath
- * - #realpath
- * - #realdirpath
- * - #children
- * - #each_child
- * - #mountpoint?
- *
- * === File status predicate methods
- *
- * These methods are a facade for FileTest:
- * - #blockdev?
- * - #chardev?
- * - #directory?
- * - #executable?
- * - #executable_real?
- * - #exist?
- * - #file?
- * - #grpowned?
- * - #owned?
- * - #pipe?
- * - #readable?
- * - #world_readable?
- * - #readable_real?
- * - #setgid?
- * - #setuid?
- * - #size
- * - #size?
- * - #socket?
- * - #sticky?
- * - #symlink?
- * - #writable?
- * - #world_writable?
- * - #writable_real?
- * - #zero?
- *
- * === File property and manipulation methods
- *
- * These methods are a facade for File:
- * - #atime
- * - #birthtime
- * - #ctime
- * - #mtime
- * - #chmod(mode)
- * - #lchmod(mode)
- * - #chown(owner, group)
- * - #lchown(owner, group)
- * - #fnmatch(pattern, *args)
- * - #fnmatch?(pattern, *args)
- * - #ftype
- * - #make_link(old)
- * - #open(*args, &block)
- * - #readlink
- * - #rename(to)
- * - #stat
- * - #lstat
- * - #make_symlink(old)
- * - #truncate(length)
- * - #utime(atime, mtime)
- * - #lutime(atime, mtime)
- * - #basename(*args)
- * - #dirname
- * - #extname
- * - #expand_path(*args)
- * - #split
- *
- * === Directory methods
- *
- * These methods are a facade for Dir:
- * - Pathname.glob(*args)
- * - Pathname.getwd / Pathname.pwd
- * - #rmdir
- * - #entries
- * - #each_entry(&block)
- * - #mkdir(*args)
- * - #opendir(*args)
- *
- * === IO
- *
- * These methods are a facade for IO:
- * - #each_line(*args, &block)
- * - #read(*args)
- * - #binread(*args)
- * - #readlines(*args)
- * - #sysopen(*args)
- * - #write(*args)
- * - #binwrite(*args)
- *
- * === Utilities
- *
- * These methods are a mixture of Find, FileUtils, and others:
- * - #find(&block)
- * - #mkpath
- * - #rmtree
- * - #unlink / #delete
- *
- *
- * == Method documentation
- *
- * As the above section shows, most of the methods in Pathname are facades. The
- * documentation for these methods generally just says, for instance, "See
- * FileTest.writable?", as you should be familiar with the original method
- * anyway, and its documentation (e.g. through +ri+) will contain more
- * information. In some cases, a brief description will follow.
- */
-void
-Init_pathname(void)
-{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
-#endif
-
- InitVM(pathname);
-
- 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, "==", path_eq, 1);
- rb_define_method(rb_cPathname, "===", path_eq, 1);
- rb_define_method(rb_cPathname, "eql?", path_eq, 1);
- rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
- rb_define_method(rb_cPathname, "hash", path_hash, 0);
- rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
- rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
- rb_define_method(rb_cPathname, "inspect", path_inspect, 0);
- rb_define_method(rb_cPathname, "sub", path_sub, -1);
- rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
- rb_define_method(rb_cPathname, "realpath", path_realpath, -1);
- rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
- rb_define_method(rb_cPathname, "each_line", path_each_line, -1);
- rb_define_method(rb_cPathname, "read", path_read, -1);
- rb_define_method(rb_cPathname, "binread", path_binread, -1);
- rb_define_method(rb_cPathname, "readlines", path_readlines, -1);
- rb_define_method(rb_cPathname, "write", path_write, -1);
- rb_define_method(rb_cPathname, "binwrite", path_binwrite, -1);
- rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1);
- rb_define_method(rb_cPathname, "atime", path_atime, 0);
- rb_define_method(rb_cPathname, "birthtime", path_birthtime, 0);
- rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
- rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
- rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
- rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
- rb_define_method(rb_cPathname, "chown", path_chown, 2);
- rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
- rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1);
- rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1);
- rb_define_method(rb_cPathname, "ftype", path_ftype, 0);
- rb_define_method(rb_cPathname, "make_link", path_make_link, 1);
- rb_define_method(rb_cPathname, "open", path_open, -1);
- rb_define_method(rb_cPathname, "readlink", path_readlink, 0);
- rb_define_method(rb_cPathname, "rename", path_rename, 1);
- rb_define_method(rb_cPathname, "stat", path_stat, 0);
- rb_define_method(rb_cPathname, "lstat", path_lstat, 0);
- rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1);
- rb_define_method(rb_cPathname, "truncate", path_truncate, 1);
- rb_define_method(rb_cPathname, "utime", path_utime, 2);
- rb_define_method(rb_cPathname, "lutime", path_lutime, 2);
- rb_define_method(rb_cPathname, "basename", path_basename, -1);
- rb_define_method(rb_cPathname, "dirname", path_dirname, 0);
- rb_define_method(rb_cPathname, "extname", path_extname, 0);
- rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1);
- rb_define_method(rb_cPathname, "split", path_split, 0);
- rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0);
- rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0);
- rb_define_method(rb_cPathname, "executable?", path_executable_p, 0);
- rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0);
- rb_define_method(rb_cPathname, "exist?", path_exist_p, 0);
- rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0);
- rb_define_method(rb_cPathname, "directory?", path_directory_p, 0);
- rb_define_method(rb_cPathname, "file?", path_file_p, 0);
- rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0);
- rb_define_method(rb_cPathname, "socket?", path_socket_p, 0);
- rb_define_method(rb_cPathname, "owned?", path_owned_p, 0);
- rb_define_method(rb_cPathname, "readable?", path_readable_p, 0);
- rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0);
- rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0);
- rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0);
- rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0);
- rb_define_method(rb_cPathname, "size", path_size, 0);
- rb_define_method(rb_cPathname, "size?", path_size_p, 0);
- rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0);
- rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0);
- rb_define_method(rb_cPathname, "writable?", path_writable_p, 0);
- rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0);
- rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0);
- rb_define_method(rb_cPathname, "zero?", path_zero_p, 0);
- rb_define_method(rb_cPathname, "empty?", path_empty_p, 0);
- rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1);
- rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0);
- rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0);
- rb_define_method(rb_cPathname, "glob", path_glob, -1);
- rb_define_method(rb_cPathname, "entries", path_entries, 0);
- rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1);
- rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0);
- rb_define_method(rb_cPathname, "opendir", path_opendir, 0);
- rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0);
- rb_define_method(rb_cPathname, "unlink", path_unlink, 0);
- rb_define_method(rb_cPathname, "delete", path_unlink, 0);
- rb_undef_method(rb_cPathname, "=~");
- rb_define_global_function("Pathname", path_f_pathname, 1);
-}
-
-void
-InitVM_pathname(void)
-{
-#undef rb_intern
- id_at_path = rb_intern("@path");
- id_to_path = rb_intern("to_path");
- id_ENOTDIR = rb_intern("ENOTDIR");
- id_atime = rb_intern("atime");
- id_basename = rb_intern("basename");
- id_base = rb_intern("base");
- id_binread = rb_intern("binread");
- id_binwrite = rb_intern("binwrite");
- id_birthtime = rb_intern("birthtime");
- id_blockdev_p = rb_intern("blockdev?");
- id_chardev_p = rb_intern("chardev?");
- id_chmod = rb_intern("chmod");
- id_chown = rb_intern("chown");
- id_ctime = rb_intern("ctime");
- id_directory_p = rb_intern("directory?");
- id_dirname = rb_intern("dirname");
- id_empty_p = rb_intern("empty?");
- id_entries = rb_intern("entries");
- id_executable_p = rb_intern("executable?");
- id_executable_real_p = rb_intern("executable_real?");
- id_exist_p = rb_intern("exist?");
- id_expand_path = rb_intern("expand_path");
- id_extname = rb_intern("extname");
- id_file_p = rb_intern("file?");
- id_fnmatch = rb_intern("fnmatch");
- id_foreach = rb_intern("foreach");
- id_ftype = rb_intern("ftype");
- id_getwd = rb_intern("getwd");
- id_glob = rb_intern("glob");
- id_grpowned_p = rb_intern("grpowned?");
- id_lchmod = rb_intern("lchmod");
- id_lchown = rb_intern("lchown");
- id_link = rb_intern("link");
- id_lstat = rb_intern("lstat");
- id_lutime = rb_intern("lutime");
- id_mkdir = rb_intern("mkdir");
- id_mtime = rb_intern("mtime");
- id_open = rb_intern("open");
- id_owned_p = rb_intern("owned?");
- id_pipe_p = rb_intern("pipe?");
- id_read = rb_intern("read");
- id_readable_p = rb_intern("readable?");
- id_readable_real_p = rb_intern("readable_real?");
- id_readlines = rb_intern("readlines");
- id_readlink = rb_intern("readlink");
- id_realdirpath = rb_intern("realdirpath");
- id_realpath = rb_intern("realpath");
- id_rename = rb_intern("rename");
- id_rmdir = rb_intern("rmdir");
- id_setgid_p = rb_intern("setgid?");
- id_setuid_p = rb_intern("setuid?");
- id_size = rb_intern("size");
- id_size_p = rb_intern("size?");
- id_socket_p = rb_intern("socket?");
- id_split = rb_intern("split");
- id_stat = rb_intern("stat");
- id_sticky_p = rb_intern("sticky?");
- id_sub = rb_intern("sub");
- id_symlink = rb_intern("symlink");
- id_symlink_p = rb_intern("symlink?");
- id_sysopen = rb_intern("sysopen");
- id_truncate = rb_intern("truncate");
- id_unlink = rb_intern("unlink");
- id_utime = rb_intern("utime");
- id_world_readable_p = rb_intern("world_readable?");
- id_world_writable_p = rb_intern("world_writable?");
- id_writable_p = rb_intern("writable?");
- id_writable_real_p = rb_intern("writable_real?");
- id_write = rb_intern("write");
- id_zero_p = rb_intern("zero?");
-}
diff --git a/ext/pathname/pathname.gemspec b/ext/pathname/pathname.gemspec
deleted file mode 100644
index 890bc2fde9..0000000000
--- a/ext/pathname/pathname.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-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.authors = ["Tanaka Akira"]
- spec.email = ["akr@fsij.org"]
-
- spec.summary = %q{Representation of the name of a file or directory on the filesystem}
- spec.description = %q{Representation of the name of a file or directory on the filesystem}
- spec.homepage = "https://github.com/ruby/pathname"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
- 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`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = []
- spec.require_paths = ["lib"]
- spec.extensions = %w[ext/pathname/extconf.rb]
-end
diff --git a/ext/psych/depend b/ext/psych/depend
index a4d9ca9a6a..95175841a2 100644
--- a/ext/psych/depend
+++ b/ext/psych/depend
@@ -152,6 +152,7 @@ psych.o: $(hdrdir)/ruby/internal/intern/re.h
psych.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych.o: $(hdrdir)/ruby/internal/intern/select.h
psych.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych.o: $(hdrdir)/ruby/internal/intern/set.h
psych.o: $(hdrdir)/ruby/internal/intern/signal.h
psych.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -329,6 +330,7 @@ psych_emitter.o: $(hdrdir)/ruby/internal/intern/re.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/select.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_emitter.o: $(hdrdir)/ruby/internal/intern/set.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -506,6 +508,7 @@ psych_parser.o: $(hdrdir)/ruby/internal/intern/re.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/select.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_parser.o: $(hdrdir)/ruby/internal/intern/set.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -683,6 +686,7 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/re.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/set.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -860,6 +864,7 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/re.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/set.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb
index e7dd0bb60a..589e201c1c 100644
--- a/ext/psych/extconf.rb
+++ b/ext/psych/extconf.rb
@@ -36,8 +36,11 @@ if yaml_source
libyaml = "libyaml.#$LIBEXT"
$cleanfiles << libyaml
$LOCAL_LIBS.prepend("$(LIBYAML) ")
-else # default to pre-installed libyaml
- pkg_config('yaml-0.1')
+
+ # default to pre-installed libyaml
+elsif pkg_config('yaml-0.1')
+ # found with pkg-config
+else
dir_config('libyaml')
find_header('yaml.h') or abort "yaml.h not found"
find_library('yaml', 'yaml_get_version') or abort "libyaml not found"
diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
index a95393c281..850a6d1937 100644
--- a/ext/psych/lib/psych.rb
+++ b/ext/psych/lib/psych.rb
@@ -23,7 +23,6 @@ require_relative 'psych/parser'
require_relative 'psych/omap'
require_relative 'psych/set'
require_relative 'psych/coder'
-require_relative 'psych/core_ext'
require_relative 'psych/stream'
require_relative 'psych/json/tree_builder'
require_relative 'psych/json/stream'
@@ -270,10 +269,10 @@ module Psych
# YAML documents that are supplied via user input. Instead, please use the
# load method or the safe_load method.
#
- def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false
+ def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
result = parse(yaml, filename: filename)
return fallback unless result
- result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer)
+ result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols)
end
###
@@ -321,13 +320,13 @@ module Psych
# Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
# Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
#
- def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
+ def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
result = parse(yaml, filename: filename)
return fallback unless result
class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
permitted_symbols.map(&:to_s))
- scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
visitor = if aliases
Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
else
@@ -367,7 +366,7 @@ module Psych
# Raises a TypeError when `yaml` parameter is NilClass. This method is
# similar to `safe_load` except that `Symbol` objects are allowed by default.
#
- def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
+ def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
safe_load yaml, permitted_classes: permitted_classes,
permitted_symbols: permitted_symbols,
aliases: aliases,
@@ -375,7 +374,8 @@ module Psych
fallback: fallback,
symbolize_names: symbolize_names,
freeze: freeze,
- strict_integer: strict_integer
+ strict_integer: strict_integer,
+ parse_symbols: parse_symbols
end
###
@@ -655,6 +655,35 @@ module Psych
end
###
+ # Load multiple documents given in +yaml+. Returns the parsed documents
+ # as a list.
+ #
+ # Example:
+ #
+ # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
+ #
+ # list = []
+ # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") do |ruby|
+ # list << ruby
+ # end
+ # list # => ['foo', 'bar']
+ #
+ def self.safe_load_stream yaml, filename: nil, permitted_classes: [], aliases: false
+ documents = parse_stream(yaml, filename: filename).children.map do |child|
+ stream = Psych::Nodes::Stream.new
+ stream.children << child
+ safe_load(stream.to_yaml, permitted_classes: permitted_classes, aliases: aliases)
+ end
+
+ if block_given?
+ documents.each { |doc| yield doc }
+ nil
+ else
+ documents
+ end
+ end
+
+ ###
# Load the document contained in +filename+. Returns the yaml contained in
# +filename+ as a Ruby object, or if the file is empty, it returns
# the specified +fallback+ return value, which defaults to +false+.
@@ -761,3 +790,5 @@ module Psych
self.domain_types = {}
# :startdoc:
end
+
+require_relative 'psych/core_ext'
diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb
index 50efc35ee2..c8f509720a 100644
--- a/ext/psych/lib/psych/class_loader.rb
+++ b/ext/psych/lib/psych/class_loader.rb
@@ -6,6 +6,7 @@ module Psych
class ClassLoader # :nodoc:
BIG_DECIMAL = 'BigDecimal'
COMPLEX = 'Complex'
+ DATA = 'Data' unless RUBY_VERSION < "3.2"
DATE = 'Date'
DATE_TIME = 'DateTime'
EXCEPTION = 'Exception'
diff --git a/ext/psych/lib/psych/core_ext.rb b/ext/psych/lib/psych/core_ext.rb
index 0721a133c3..6dfd0f1696 100644
--- a/ext/psych/lib/psych/core_ext.rb
+++ b/ext/psych/lib/psych/core_ext.rb
@@ -14,6 +14,23 @@ class Object
end
end
-if defined?(::IRB)
- require_relative 'y'
+# Up to Ruby 3.4, Set was a regular object and was dumped as such
+# by Pysch.
+# Starting from Ruby 4.0 it's a core class written in C, so we have to implement
+# #encode_with / #init_with to preserve backward compatibility.
+if defined?(::Set) && Set.new.instance_variables.empty?
+ class Set
+ def encode_with(coder)
+ hash = {}
+ each do |m|
+ hash[m] = true
+ end
+ coder["hash"] = hash
+ coder
+ end
+
+ def init_with(coder)
+ replace(coder["hash"].keys)
+ end
+ end
end
diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb
index 6ae5c59148..fc27448f2e 100644
--- a/ext/psych/lib/psych/nodes/node.rb
+++ b/ext/psych/lib/psych/nodes/node.rb
@@ -45,8 +45,8 @@ module Psych
# Convert this node to Ruby.
#
# See also Psych::Visitors::ToRuby
- def to_ruby(symbolize_names: false, freeze: false, strict_integer: false)
- Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer).accept(self)
+ def to_ruby(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
+ Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols).accept(self)
end
alias :transform :to_ruby
diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb
index 8cf868f863..6a556fb3b8 100644
--- a/ext/psych/lib/psych/scalar_scanner.rb
+++ b/ext/psych/lib/psych/scalar_scanner.rb
@@ -27,10 +27,11 @@ module Psych
attr_reader :class_loader
# Create a new scanner
- def initialize class_loader, strict_integer: false
+ def initialize class_loader, strict_integer: false, parse_symbols: true
@symbol_cache = {}
@class_loader = class_loader
@strict_integer = strict_integer
+ @parse_symbols = parse_symbols
end
# Tokenize +string+ returning the Ruby object
@@ -72,7 +73,7 @@ module Psych
-Float::INFINITY
elsif string.match?(/^\.nan$/i)
Float::NAN
- elsif string.match?(/^:./)
+ elsif @parse_symbols && string.match?(/^:./)
if string =~ /^:(["'])(.*)\1/
@symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
else
diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb
index d91563c861..6c1679bf65 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.2.3'
+ VERSION = '5.4.0'
if RUBY_ENGINE == 'jruby'
- DEFAULT_SNAKEYAML_VERSION = '2.9'.freeze
+ DEFAULT_SNAKEYAML_VERSION = '2.10'.freeze
end
end
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index f0b4a94e45..475444e589 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -12,9 +12,13 @@ module Psych
###
# This class walks a YAML AST, converting each node to Ruby
class ToRuby < Psych::Visitors::Visitor
- def self.create(symbolize_names: false, freeze: false, strict_integer: false)
+ unless RUBY_VERSION < "3.2"
+ DATA_INITIALIZE = Data.instance_method(:initialize)
+ end
+
+ def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
class_loader = ClassLoader.new
- scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
new(scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze)
end
@@ -96,11 +100,11 @@ module Psych
Float(@ss.tokenize(o.value))
when "!ruby/regexp"
klass = class_loader.regexp
- o.value =~ /^\/(.*)\/([mixn]*)$/m
- source = $1
+ matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(o.value)
+ source = matches[:string].gsub('\/', '/')
options = 0
lang = nil
- $2&.each_char do |option|
+ matches[:options].each_char do |option|
case option
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
@@ -197,6 +201,32 @@ module Psych
s
end
+ when /^!ruby\/data(-with-ivars)?(?::(.*))?$/
+ data = register(o, resolve_class($2).allocate) if $2
+ members = {}
+
+ if $1 # data-with-ivars
+ ivars = {}
+ o.children.each_slice(2) do |type, vars|
+ case accept(type)
+ when 'members'
+ revive_data_members(members, vars)
+ data ||= allocate_anon_data(o, members)
+ when 'ivars'
+ revive_hash(ivars, vars)
+ end
+ end
+ ivars.each do |ivar, v|
+ data.instance_variable_set ivar, v
+ end
+ else
+ revive_data_members(members, o)
+ end
+ data ||= allocate_anon_data(o, members)
+ DATA_INITIALIZE.bind_call(data, **members)
+ data.freeze
+ data
+
when /^!ruby\/object:?(.*)?$/
name = $1 || 'Object'
@@ -340,6 +370,20 @@ module Psych
list
end
+ def allocate_anon_data node, members
+ klass = class_loader.data.define(*members.keys)
+ register(node, klass.allocate)
+ end
+
+ def revive_data_members hash, o
+ o.children.each_slice(2) do |k,v|
+ name = accept(k)
+ value = accept(v)
+ hash[class_loader.symbolize(name)] = value
+ end
+ hash
+ end
+
def revive_hash hash, o, tagged= false
o.children.each_slice(2) { |k,v|
key = accept(k)
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
index a9476df96e..b6c86f4c94 100644
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -73,7 +73,7 @@ module Psych
method = respond_to?(method) ? method : h[klass.superclass]
- raise(TypeError, "Can't dump #{target.class}") unless method
+ raise(TypeError, "can't dump #{klass.name}") unless method
h[klass] = method
end.compare_by_identity
@@ -162,6 +162,44 @@ module Psych
alias :visit_Delegator :visit_Object
+ def visit_Data o
+ ivars = o.instance_variables
+ if ivars.empty?
+ tag = ['!ruby/data', o.class.name].compact.join(':')
+ register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
+ o.members.each do |member|
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
+ accept o.send member
+ end
+ @emitter.end_mapping
+
+ else
+ tag = ['!ruby/data-with-ivars', o.class.name].compact.join(':')
+ node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
+ register(o, node)
+
+ # Dump the members
+ accept 'members'
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ o.members.each do |member|
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
+ accept o.send member
+ end
+ @emitter.end_mapping
+
+ # Dump the ivars
+ accept 'ivars'
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ ivars.each do |ivar|
+ accept ivar.to_s
+ accept o.instance_variable_get ivar
+ end
+ @emitter.end_mapping
+
+ @emitter.end_mapping
+ end
+ end unless RUBY_VERSION < "3.2"
+
def visit_Struct o
tag = ['!ruby/struct', o.class.name].compact.join(':')
diff --git a/ext/psych/psych_parser.c b/ext/psych/psych_parser.c
index d973496284..00a2207b58 100644
--- a/ext/psych/psych_parser.c
+++ b/ext/psych/psych_parser.c
@@ -32,9 +32,20 @@ static int io_reader(void * data, unsigned char *buf, size_t size, size_t *read)
*read = 0;
if(! NIL_P(string)) {
- void * str = (void *)StringValuePtr(string);
- *read = (size_t)RSTRING_LEN(string);
- memcpy(buf, str, *read);
+ char * str = StringValuePtr(string);
+ size_t len = (size_t)RSTRING_LEN(string);
+
+ /* IO#read(size) is documented to return at most `size` bytes, but a
+ * misbehaving IO-like object may return more. Clamp the copy to the
+ * buffer libyaml gave us to avoid writing past its end, rounding down
+ * to a character boundary so a multibyte character is never split. */
+ if(len > size) {
+ rb_encoding * enc = rb_enc_get(string);
+ len = (size_t)(rb_enc_left_char_head(str, str + size, str + len, enc) - str);
+ }
+
+ *read = len;
+ memcpy(buf, str, len);
}
return 1;
diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c
index ffe0c69c7f..3ab0138b52 100644
--- a/ext/psych/psych_to_ruby.c
+++ b/ext/psych/psych_to_ruby.c
@@ -10,7 +10,11 @@ static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg)
{
VALUE e = rb_obj_alloc(klass);
+#ifdef TRUFFLERUBY
+ rb_exc_set_message(e, mesg);
+#else
rb_iv_set(e, "mesg", mesg);
+#endif
return e;
}
diff --git a/ext/pty/depend b/ext/pty/depend
index adecfff862..8fa018d084 100644
--- a/ext/pty/depend
+++ b/ext/pty/depend
@@ -138,6 +138,7 @@ pty.o: $(hdrdir)/ruby/internal/intern/re.h
pty.o: $(hdrdir)/ruby/internal/intern/ruby.h
pty.o: $(hdrdir)/ruby/internal/intern/select.h
pty.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+pty.o: $(hdrdir)/ruby/internal/intern/set.h
pty.o: $(hdrdir)/ruby/internal/intern/signal.h
pty.o: $(hdrdir)/ruby/internal/intern/sprintf.h
pty.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -172,6 +173,7 @@ pty.o: $(hdrdir)/ruby/ruby.h
pty.o: $(hdrdir)/ruby/st.h
pty.o: $(hdrdir)/ruby/subst.h
pty.o: $(hdrdir)/ruby/util.h
+pty.o: $(top_srcdir)/id_table.h
pty.o: $(top_srcdir)/internal.h
pty.o: $(top_srcdir)/internal/array.h
pty.o: $(top_srcdir)/internal/compilers.h
diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb
index da3655cf4d..ae2cb45d3c 100644
--- a/ext/pty/extconf.rb
+++ b/ext/pty/extconf.rb
@@ -21,6 +21,8 @@ if /mswin|mingw|bccwin/ !~ RUBY_PLATFORM
(util or have_func("openpty")) or
have_func("_getpty") or
have_func("ioctl")
+ have_macro("HAVE_FCHMOD") or have_func("fchmod")
+ have_macro("HAVE_FCHOWN") or have_func("fchown")
create_makefile('pty')
end
end
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 7c79f81e33..3d5977707f 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -274,12 +274,23 @@ ptsname_r(int fd, char *buf, size_t buflen)
# define HAVE_PTSNAME_R 1
#endif
+#ifdef HAVE_FCHMOD
+# define change_mode(name, fd, mode) fchmod(fd, mode)
+#else
+# define change_mode(name, fd, mode) chmod(name, mode)
+#endif
+#ifdef HAVE_FCHOWN
+# define change_owner(name, fd, uid, gid) fchown(fd, uid, gid)
+#else
+# define change_owner(name, fd, uid, gid) chown(name, uid, gid)
+#endif
+
#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME_R)
-static int
-no_mesg(char *slavedevice, int nomesg)
+static inline int
+prevent_messages(const char *slavedevice, int fd, int nomesg)
{
if (nomesg)
- return chmod(slavedevice, 0600);
+ return change_mode(slavedevice, fd, 0600);
else
return 0;
}
@@ -340,8 +351,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if (unlockpt(masterfd) == -1) goto error;
if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
slavedevice = SlaveName;
- if (no_mesg(slavedevice, nomesg) == -1) goto error;
if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
+ if (prevent_messages(slavedevice, slavefd, nomesg) == -1) goto error;
rb_update_max_fd(slavefd);
#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
@@ -375,7 +386,9 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
}
rb_fd_fix_cloexec(*master);
rb_fd_fix_cloexec(*slave);
- if (no_mesg(SlaveName, nomesg) == -1) {
+ if (prevent_messages(SlaveName, *slave, nomesg) == -1) {
+ close(*master);
+ close(*slave);
if (!fail) return -1;
rb_raise(rb_eRuntimeError, "can't chmod slave pty");
}
@@ -424,8 +437,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if(unlockpt(masterfd) == -1) goto error;
if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
slavedevice = SlaveName;
- if (no_mesg(slavedevice, nomesg) == -1) goto error;
if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
+ if (prevent_messages(slavedevice, slavefd, nomesg) == -1) goto error;
rb_update_max_fd(slavefd);
#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
if(ioctl_I_PUSH(slavefd, "ptem") == -1) goto error;
@@ -478,8 +491,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) {
rb_update_max_fd(slavefd);
*slave = slavefd;
- if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
- if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
+ if (change_owner(SlaveName, slavefd, getuid(), getgid()) != 0) goto error;
+ if (change_mode(SlaveName, slavefd, nomesg ? 0600 : 0622) != 0) goto error;
return 0;
}
close(masterfd);
diff --git a/ext/rbconfig/sizeof/depend b/ext/rbconfig/sizeof/depend
index 5f75fa8c76..7e6c950769 100644
--- a/ext/rbconfig/sizeof/depend
+++ b/ext/rbconfig/sizeof/depend
@@ -142,6 +142,7 @@ limits.o: $(hdrdir)/ruby/internal/intern/re.h
limits.o: $(hdrdir)/ruby/internal/intern/ruby.h
limits.o: $(hdrdir)/ruby/internal/intern/select.h
limits.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+limits.o: $(hdrdir)/ruby/internal/intern/set.h
limits.o: $(hdrdir)/ruby/internal/intern/signal.h
limits.o: $(hdrdir)/ruby/internal/intern/sprintf.h
limits.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -301,6 +302,7 @@ sizes.o: $(hdrdir)/ruby/internal/intern/re.h
sizes.o: $(hdrdir)/ruby/internal/intern/ruby.h
sizes.o: $(hdrdir)/ruby/internal/intern/select.h
sizes.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sizes.o: $(hdrdir)/ruby/internal/intern/set.h
sizes.o: $(hdrdir)/ruby/internal/intern/signal.h
sizes.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sizes.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/ripper/depend b/ext/ripper/depend
index 9cca2d315e..db83378a1d 100644
--- a/ext/ripper/depend
+++ b/ext/ripper/depend
@@ -181,6 +181,7 @@ 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/set.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
@@ -352,6 +353,7 @@ 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/set.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
@@ -472,6 +474,7 @@ ripper.o: $(hdrdir)/ruby/internal/core/rclass.h
ripper.o: $(hdrdir)/ruby/internal/core/rdata.h
ripper.o: $(hdrdir)/ruby/internal/core/rfile.h
ripper.o: $(hdrdir)/ruby/internal/core/rhash.h
+ripper.o: $(hdrdir)/ruby/internal/core/rmatch.h
ripper.o: $(hdrdir)/ruby/internal/core/robject.h
ripper.o: $(hdrdir)/ruby/internal/core/rregexp.h
ripper.o: $(hdrdir)/ruby/internal/core/rstring.h
@@ -532,6 +535,7 @@ ripper.o: $(hdrdir)/ruby/internal/intern/re.h
ripper.o: $(hdrdir)/ruby/internal/intern/ruby.h
ripper.o: $(hdrdir)/ruby/internal/intern/select.h
ripper.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ripper.o: $(hdrdir)/ruby/internal/intern/set.h
ripper.o: $(hdrdir)/ruby/internal/intern/signal.h
ripper.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ripper.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -563,6 +567,7 @@ ripper.o: $(hdrdir)/ruby/missing.h
ripper.o: $(hdrdir)/ruby/onigmo.h
ripper.o: $(hdrdir)/ruby/oniguruma.h
ripper.o: $(hdrdir)/ruby/ractor.h
+ripper.o: $(hdrdir)/ruby/re.h
ripper.o: $(hdrdir)/ruby/regex.h
ripper.o: $(hdrdir)/ruby/ruby.h
ripper.o: $(hdrdir)/ruby/st.h
@@ -575,12 +580,15 @@ 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)/encindex.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/box.h
+ripper.o: $(top_srcdir)/internal/compar.h
ripper.o: $(top_srcdir)/internal/compile.h
ripper.o: $(top_srcdir)/internal/compilers.h
ripper.o: $(top_srcdir)/internal/complex.h
@@ -598,8 +606,10 @@ ripper.o: $(top_srcdir)/internal/re.h
ripper.o: $(top_srcdir)/internal/ruby_parser.h
ripper.o: $(top_srcdir)/internal/sanitizers.h
ripper.o: $(top_srcdir)/internal/serial.h
+ripper.o: $(top_srcdir)/internal/set_table.h
ripper.o: $(top_srcdir)/internal/static_assert.h
ripper.o: $(top_srcdir)/internal/string.h
+ripper.o: $(top_srcdir)/internal/struct.h
ripper.o: $(top_srcdir)/internal/symbol.h
ripper.o: $(top_srcdir)/internal/thread.h
ripper.o: $(top_srcdir)/internal/variable.h
@@ -770,6 +780,7 @@ 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/set.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
@@ -804,8 +815,10 @@ 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/basic_operators.h
ripper_init.o: $(top_srcdir)/internal/bignum.h
ripper_init.o: $(top_srcdir)/internal/bits.h
+ripper_init.o: $(top_srcdir)/internal/compar.h
ripper_init.o: $(top_srcdir)/internal/compilers.h
ripper_init.o: $(top_srcdir)/internal/complex.h
ripper_init.o: $(top_srcdir)/internal/fixnum.h
diff --git a/ext/ripper/lib/ripper/lexer.rb b/ext/ripper/lib/ripper/lexer.rb
index 870c79857b..9b849dfeae 100644
--- a/ext/ripper/lib/ripper/lexer.rb
+++ b/ext/ripper/lib/ripper/lexer.rb
@@ -68,7 +68,7 @@ class Ripper
when 0, :to_int
@to_int
when 1, :to_s
- @event
+ @to_s
else
nil
end
diff --git a/ext/socket/depend b/ext/socket/depend
index 750bb0734f..77f6239a3d 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -151,6 +151,7 @@ ancdata.o: $(hdrdir)/ruby/internal/intern/re.h
ancdata.o: $(hdrdir)/ruby/internal/intern/ruby.h
ancdata.o: $(hdrdir)/ruby/internal/intern/select.h
ancdata.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/set.h
ancdata.o: $(hdrdir)/ruby/internal/intern/signal.h
ancdata.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ancdata.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -192,9 +193,12 @@ 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)/encindex.h
+ancdata.o: $(top_srcdir)/id_table.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/box.h
ancdata.o: $(top_srcdir)/internal/compilers.h
ancdata.o: $(top_srcdir)/internal/error.h
ancdata.o: $(top_srcdir)/internal/gc.h
@@ -202,6 +206,7 @@ ancdata.o: $(top_srcdir)/internal/imemo.h
ancdata.o: $(top_srcdir)/internal/io.h
ancdata.o: $(top_srcdir)/internal/sanitizers.h
ancdata.o: $(top_srcdir)/internal/serial.h
+ancdata.o: $(top_srcdir)/internal/set_table.h
ancdata.o: $(top_srcdir)/internal/static_assert.h
ancdata.o: $(top_srcdir)/internal/string.h
ancdata.o: $(top_srcdir)/internal/thread.h
@@ -362,6 +367,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/intern/re.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/select.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/set.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -403,9 +409,12 @@ 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)/encindex.h
+basicsocket.o: $(top_srcdir)/id_table.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/box.h
basicsocket.o: $(top_srcdir)/internal/compilers.h
basicsocket.o: $(top_srcdir)/internal/error.h
basicsocket.o: $(top_srcdir)/internal/gc.h
@@ -413,6 +422,7 @@ basicsocket.o: $(top_srcdir)/internal/imemo.h
basicsocket.o: $(top_srcdir)/internal/io.h
basicsocket.o: $(top_srcdir)/internal/sanitizers.h
basicsocket.o: $(top_srcdir)/internal/serial.h
+basicsocket.o: $(top_srcdir)/internal/set_table.h
basicsocket.o: $(top_srcdir)/internal/static_assert.h
basicsocket.o: $(top_srcdir)/internal/string.h
basicsocket.o: $(top_srcdir)/internal/thread.h
@@ -573,6 +583,7 @@ constants.o: $(hdrdir)/ruby/internal/intern/re.h
constants.o: $(hdrdir)/ruby/internal/intern/ruby.h
constants.o: $(hdrdir)/ruby/internal/intern/select.h
constants.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+constants.o: $(hdrdir)/ruby/internal/intern/set.h
constants.o: $(hdrdir)/ruby/internal/intern/signal.h
constants.o: $(hdrdir)/ruby/internal/intern/sprintf.h
constants.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -614,9 +625,12 @@ 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)/encindex.h
+constants.o: $(top_srcdir)/id_table.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/box.h
constants.o: $(top_srcdir)/internal/compilers.h
constants.o: $(top_srcdir)/internal/error.h
constants.o: $(top_srcdir)/internal/gc.h
@@ -624,6 +638,7 @@ constants.o: $(top_srcdir)/internal/imemo.h
constants.o: $(top_srcdir)/internal/io.h
constants.o: $(top_srcdir)/internal/sanitizers.h
constants.o: $(top_srcdir)/internal/serial.h
+constants.o: $(top_srcdir)/internal/set_table.h
constants.o: $(top_srcdir)/internal/static_assert.h
constants.o: $(top_srcdir)/internal/string.h
constants.o: $(top_srcdir)/internal/thread.h
@@ -785,6 +800,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/intern/re.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/ruby.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/select.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/set.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/signal.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -826,9 +842,12 @@ 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)/encindex.h
+ifaddr.o: $(top_srcdir)/id_table.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/box.h
ifaddr.o: $(top_srcdir)/internal/compilers.h
ifaddr.o: $(top_srcdir)/internal/error.h
ifaddr.o: $(top_srcdir)/internal/gc.h
@@ -836,6 +855,7 @@ ifaddr.o: $(top_srcdir)/internal/imemo.h
ifaddr.o: $(top_srcdir)/internal/io.h
ifaddr.o: $(top_srcdir)/internal/sanitizers.h
ifaddr.o: $(top_srcdir)/internal/serial.h
+ifaddr.o: $(top_srcdir)/internal/set_table.h
ifaddr.o: $(top_srcdir)/internal/static_assert.h
ifaddr.o: $(top_srcdir)/internal/string.h
ifaddr.o: $(top_srcdir)/internal/thread.h
@@ -996,6 +1016,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1037,9 +1058,12 @@ 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)/encindex.h
+init.o: $(top_srcdir)/id_table.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/box.h
init.o: $(top_srcdir)/internal/compilers.h
init.o: $(top_srcdir)/internal/error.h
init.o: $(top_srcdir)/internal/gc.h
@@ -1047,6 +1071,7 @@ init.o: $(top_srcdir)/internal/imemo.h
init.o: $(top_srcdir)/internal/io.h
init.o: $(top_srcdir)/internal/sanitizers.h
init.o: $(top_srcdir)/internal/serial.h
+init.o: $(top_srcdir)/internal/set_table.h
init.o: $(top_srcdir)/internal/static_assert.h
init.o: $(top_srcdir)/internal/string.h
init.o: $(top_srcdir)/internal/thread.h
@@ -1207,6 +1232,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/intern/re.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/select.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/set.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1248,9 +1274,12 @@ 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)/encindex.h
+ipsocket.o: $(top_srcdir)/id_table.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/box.h
ipsocket.o: $(top_srcdir)/internal/compilers.h
ipsocket.o: $(top_srcdir)/internal/error.h
ipsocket.o: $(top_srcdir)/internal/gc.h
@@ -1258,6 +1287,7 @@ ipsocket.o: $(top_srcdir)/internal/imemo.h
ipsocket.o: $(top_srcdir)/internal/io.h
ipsocket.o: $(top_srcdir)/internal/sanitizers.h
ipsocket.o: $(top_srcdir)/internal/serial.h
+ipsocket.o: $(top_srcdir)/internal/set_table.h
ipsocket.o: $(top_srcdir)/internal/static_assert.h
ipsocket.o: $(top_srcdir)/internal/string.h
ipsocket.o: $(top_srcdir)/internal/thread.h
@@ -1418,6 +1448,7 @@ option.o: $(hdrdir)/ruby/internal/intern/re.h
option.o: $(hdrdir)/ruby/internal/intern/ruby.h
option.o: $(hdrdir)/ruby/internal/intern/select.h
option.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+option.o: $(hdrdir)/ruby/internal/intern/set.h
option.o: $(hdrdir)/ruby/internal/intern/signal.h
option.o: $(hdrdir)/ruby/internal/intern/sprintf.h
option.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1459,9 +1490,12 @@ 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)/encindex.h
+option.o: $(top_srcdir)/id_table.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/box.h
option.o: $(top_srcdir)/internal/compilers.h
option.o: $(top_srcdir)/internal/error.h
option.o: $(top_srcdir)/internal/gc.h
@@ -1469,6 +1503,7 @@ option.o: $(top_srcdir)/internal/imemo.h
option.o: $(top_srcdir)/internal/io.h
option.o: $(top_srcdir)/internal/sanitizers.h
option.o: $(top_srcdir)/internal/serial.h
+option.o: $(top_srcdir)/internal/set_table.h
option.o: $(top_srcdir)/internal/static_assert.h
option.o: $(top_srcdir)/internal/string.h
option.o: $(top_srcdir)/internal/thread.h
@@ -1629,6 +1664,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/intern/re.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/ruby.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/select.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/set.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/signal.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/sprintf.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1670,9 +1706,12 @@ 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)/encindex.h
+raddrinfo.o: $(top_srcdir)/id_table.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/box.h
raddrinfo.o: $(top_srcdir)/internal/compilers.h
raddrinfo.o: $(top_srcdir)/internal/error.h
raddrinfo.o: $(top_srcdir)/internal/gc.h
@@ -1680,6 +1719,7 @@ raddrinfo.o: $(top_srcdir)/internal/imemo.h
raddrinfo.o: $(top_srcdir)/internal/io.h
raddrinfo.o: $(top_srcdir)/internal/sanitizers.h
raddrinfo.o: $(top_srcdir)/internal/serial.h
+raddrinfo.o: $(top_srcdir)/internal/set_table.h
raddrinfo.o: $(top_srcdir)/internal/static_assert.h
raddrinfo.o: $(top_srcdir)/internal/string.h
raddrinfo.o: $(top_srcdir)/internal/thread.h
@@ -1840,6 +1880,7 @@ socket.o: $(hdrdir)/ruby/internal/intern/re.h
socket.o: $(hdrdir)/ruby/internal/intern/ruby.h
socket.o: $(hdrdir)/ruby/internal/intern/select.h
socket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+socket.o: $(hdrdir)/ruby/internal/intern/set.h
socket.o: $(hdrdir)/ruby/internal/intern/signal.h
socket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
socket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1881,9 +1922,12 @@ 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)/encindex.h
+socket.o: $(top_srcdir)/id_table.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/box.h
socket.o: $(top_srcdir)/internal/compilers.h
socket.o: $(top_srcdir)/internal/error.h
socket.o: $(top_srcdir)/internal/gc.h
@@ -1891,6 +1935,7 @@ socket.o: $(top_srcdir)/internal/imemo.h
socket.o: $(top_srcdir)/internal/io.h
socket.o: $(top_srcdir)/internal/sanitizers.h
socket.o: $(top_srcdir)/internal/serial.h
+socket.o: $(top_srcdir)/internal/set_table.h
socket.o: $(top_srcdir)/internal/static_assert.h
socket.o: $(top_srcdir)/internal/string.h
socket.o: $(top_srcdir)/internal/thread.h
@@ -2051,6 +2096,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/intern/re.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/select.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/set.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/signal.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2092,9 +2138,12 @@ 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)/encindex.h
+sockssocket.o: $(top_srcdir)/id_table.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/box.h
sockssocket.o: $(top_srcdir)/internal/compilers.h
sockssocket.o: $(top_srcdir)/internal/error.h
sockssocket.o: $(top_srcdir)/internal/gc.h
@@ -2102,6 +2151,7 @@ sockssocket.o: $(top_srcdir)/internal/imemo.h
sockssocket.o: $(top_srcdir)/internal/io.h
sockssocket.o: $(top_srcdir)/internal/sanitizers.h
sockssocket.o: $(top_srcdir)/internal/serial.h
+sockssocket.o: $(top_srcdir)/internal/set_table.h
sockssocket.o: $(top_srcdir)/internal/static_assert.h
sockssocket.o: $(top_srcdir)/internal/string.h
sockssocket.o: $(top_srcdir)/internal/thread.h
@@ -2262,6 +2312,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/intern/re.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/select.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/set.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/signal.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2303,9 +2354,12 @@ 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)/encindex.h
+tcpserver.o: $(top_srcdir)/id_table.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/box.h
tcpserver.o: $(top_srcdir)/internal/compilers.h
tcpserver.o: $(top_srcdir)/internal/error.h
tcpserver.o: $(top_srcdir)/internal/gc.h
@@ -2313,6 +2367,7 @@ tcpserver.o: $(top_srcdir)/internal/imemo.h
tcpserver.o: $(top_srcdir)/internal/io.h
tcpserver.o: $(top_srcdir)/internal/sanitizers.h
tcpserver.o: $(top_srcdir)/internal/serial.h
+tcpserver.o: $(top_srcdir)/internal/set_table.h
tcpserver.o: $(top_srcdir)/internal/static_assert.h
tcpserver.o: $(top_srcdir)/internal/string.h
tcpserver.o: $(top_srcdir)/internal/thread.h
@@ -2473,6 +2528,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/set.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2514,9 +2570,12 @@ 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)/encindex.h
+tcpsocket.o: $(top_srcdir)/id_table.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/box.h
tcpsocket.o: $(top_srcdir)/internal/compilers.h
tcpsocket.o: $(top_srcdir)/internal/error.h
tcpsocket.o: $(top_srcdir)/internal/gc.h
@@ -2524,6 +2583,7 @@ tcpsocket.o: $(top_srcdir)/internal/imemo.h
tcpsocket.o: $(top_srcdir)/internal/io.h
tcpsocket.o: $(top_srcdir)/internal/sanitizers.h
tcpsocket.o: $(top_srcdir)/internal/serial.h
+tcpsocket.o: $(top_srcdir)/internal/set_table.h
tcpsocket.o: $(top_srcdir)/internal/static_assert.h
tcpsocket.o: $(top_srcdir)/internal/string.h
tcpsocket.o: $(top_srcdir)/internal/thread.h
@@ -2684,6 +2744,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/set.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2725,9 +2786,12 @@ 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)/encindex.h
+udpsocket.o: $(top_srcdir)/id_table.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/box.h
udpsocket.o: $(top_srcdir)/internal/compilers.h
udpsocket.o: $(top_srcdir)/internal/error.h
udpsocket.o: $(top_srcdir)/internal/gc.h
@@ -2735,6 +2799,7 @@ udpsocket.o: $(top_srcdir)/internal/imemo.h
udpsocket.o: $(top_srcdir)/internal/io.h
udpsocket.o: $(top_srcdir)/internal/sanitizers.h
udpsocket.o: $(top_srcdir)/internal/serial.h
+udpsocket.o: $(top_srcdir)/internal/set_table.h
udpsocket.o: $(top_srcdir)/internal/static_assert.h
udpsocket.o: $(top_srcdir)/internal/string.h
udpsocket.o: $(top_srcdir)/internal/thread.h
@@ -2895,6 +2960,7 @@ unixserver.o: $(hdrdir)/ruby/internal/intern/re.h
unixserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
unixserver.o: $(hdrdir)/ruby/internal/intern/select.h
unixserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/set.h
unixserver.o: $(hdrdir)/ruby/internal/intern/signal.h
unixserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
unixserver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2936,9 +3002,12 @@ 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)/encindex.h
+unixserver.o: $(top_srcdir)/id_table.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/box.h
unixserver.o: $(top_srcdir)/internal/compilers.h
unixserver.o: $(top_srcdir)/internal/error.h
unixserver.o: $(top_srcdir)/internal/gc.h
@@ -2946,6 +3015,7 @@ unixserver.o: $(top_srcdir)/internal/imemo.h
unixserver.o: $(top_srcdir)/internal/io.h
unixserver.o: $(top_srcdir)/internal/sanitizers.h
unixserver.o: $(top_srcdir)/internal/serial.h
+unixserver.o: $(top_srcdir)/internal/set_table.h
unixserver.o: $(top_srcdir)/internal/static_assert.h
unixserver.o: $(top_srcdir)/internal/string.h
unixserver.o: $(top_srcdir)/internal/thread.h
@@ -3106,6 +3176,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/intern/re.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/select.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/set.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3147,9 +3218,12 @@ 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)/encindex.h
+unixsocket.o: $(top_srcdir)/id_table.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/box.h
unixsocket.o: $(top_srcdir)/internal/compilers.h
unixsocket.o: $(top_srcdir)/internal/error.h
unixsocket.o: $(top_srcdir)/internal/gc.h
@@ -3157,6 +3231,7 @@ unixsocket.o: $(top_srcdir)/internal/imemo.h
unixsocket.o: $(top_srcdir)/internal/io.h
unixsocket.o: $(top_srcdir)/internal/sanitizers.h
unixsocket.o: $(top_srcdir)/internal/serial.h
+unixsocket.o: $(top_srcdir)/internal/set_table.h
unixsocket.o: $(top_srcdir)/internal/static_assert.h
unixsocket.o: $(top_srcdir)/internal/string.h
unixsocket.o: $(top_srcdir)/internal/thread.h
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index d44ce31b0a..a814e21c3a 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -704,6 +704,7 @@ SRC
have_func("pthread_create")
have_func("pthread_detach")
+ have_func("pthread_attr_setdetachstate")
$VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index bf0d90129f..9a65490b1d 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -62,9 +62,6 @@
#endif
#include <unistd.h>
#else
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
@@ -171,9 +168,7 @@ static const char *const ai_errlist[] = {
#define GET_CANONNAME(ai, str) \
if (pai->ai_flags & AI_CANONNAME) {\
- if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
- strcpy((ai)->ai_canonname, (str));\
- } else {\
+ if (((ai)->ai_canonname = strdup(str)) == NULL) {\
error = EAI_MEMORY;\
goto free;\
}\
diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c
index ae5284fab6..98da8c1647 100644
--- a/ext/socket/getnameinfo.c
+++ b/ext/socket/getnameinfo.c
@@ -55,9 +55,6 @@
#endif
#endif
#ifdef _WIN32
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#define snprintf _snprintf
@@ -158,16 +155,14 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
/* what we should do? */
} else if (flags & NI_NUMERICSERV) {
snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
- if (strlen(numserv) + 1 > servlen)
+ if (strlcpy(serv, numserv, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, numserv);
} else {
#if defined(HAVE_GETSERVBYPORT)
struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
if (sp) {
- if (strlen(sp->s_name) + 1 > servlen)
+ if (strlcpy(serv, sp->s_name, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, sp->s_name);
} else
return ENI_NOSERVNAME;
#else
@@ -202,9 +197,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_SYSTEM;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
} else {
#ifdef INET6
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
@@ -218,13 +212,12 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
p = strchr(hp->h_name, '.');
if (p) *p = '\0';
}
- if (strlen(hp->h_name) + 1 > hostlen) {
+ if (strlcpy(host, hp->h_name, hostlen) >= hostlen) {
#ifdef INET6
freehostent(hp);
#endif
return ENI_MEMORY;
}
- strcpy(host, hp->h_name);
#ifdef INET6
freehostent(hp);
#endif
@@ -234,9 +227,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_NOHOSTNAME;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
}
}
return SUCCESS;
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 8e405609ba..6091385561 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -473,7 +473,7 @@ rsock_socket(int domain, int type, int proto)
/* emulate blocking connect behavior on EINTR or non-blocking socket */
static int
-wait_connectable(VALUE self, VALUE timeout)
+wait_connectable(VALUE self, VALUE timeout, const struct sockaddr *sockaddr, int len)
{
int sockerr;
socklen_t sockerrlen;
@@ -514,7 +514,9 @@ wait_connectable(VALUE self, VALUE timeout)
VALUE result = rb_io_wait(self, RB_INT2NUM(RUBY_IO_READABLE|RUBY_IO_WRITABLE), timeout);
if (result == Qfalse) {
- rb_raise(rb_eIOTimeoutError, "Connect timed out!");
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)sockaddr, len, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ rb_raise(rb_eIOTimeoutError, "user specified timeout for %" PRIsVALUE, addr_str);
}
int revents = RB_NUM2INT(result);
@@ -603,7 +605,7 @@ rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, V
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
- return wait_connectable(self, timeout);
+ return wait_connectable(self, timeout, sockaddr, len);
}
}
return status;
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index 60776c16a2..e1943b8496 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -23,8 +23,25 @@ struct inetsock_arg
int type;
VALUE resolv_timeout;
VALUE connect_timeout;
+ VALUE open_timeout;
};
+void
+rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port)
+{
+ VALUE message;
+
+ if (ai && ai->ai_addr) {
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)ai->ai_addr, (socklen_t)ai->ai_addrlen, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str);
+ } else {
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE " port %" PRIsVALUE, host, port);
+ }
+
+ rb_exc_raise(rb_exc_new_str(rb_eIOTimeoutError, message));
+}
+
static VALUE
inetsock_cleanup(VALUE v)
{
@@ -45,6 +62,13 @@ inetsock_cleanup(VALUE v)
}
static VALUE
+current_clocktime(void)
+{
+ VALUE clock_monotnic_const = rb_const_get(rb_mProcess, rb_intern("CLOCK_MONOTONIC"));
+ return rb_funcall(rb_mProcess, rb_intern("clock_gettime"), 1, clock_monotnic_const);
+}
+
+static VALUE
init_inetsock_internal(VALUE v)
{
struct inetsock_arg *arg = (void *)v;
@@ -54,12 +78,18 @@ init_inetsock_internal(VALUE v)
int status = 0, local = 0;
int family = AF_UNSPEC;
const char *syscall = 0;
+ VALUE resolv_timeout = arg->resolv_timeout;
VALUE connect_timeout = arg->connect_timeout;
+ VALUE open_timeout = arg->open_timeout;
+ VALUE timeout;
+ VALUE starts_at;
+
+ timeout = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
+ starts_at = current_clocktime();
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
family, SOCK_STREAM,
- (type == INET_SERVER) ? AI_PASSIVE : 0);
-
+ (type == INET_SERVER) ? AI_PASSIVE : 0, timeout);
/*
* Maybe also accept a local address
@@ -67,7 +97,7 @@ init_inetsock_internal(VALUE v)
if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
- family, SOCK_STREAM, 0);
+ family, SOCK_STREAM, 0, timeout);
}
VALUE io = Qnil;
@@ -122,8 +152,18 @@ init_inetsock_internal(VALUE v)
syscall = "bind(2)";
}
+ if (NIL_P(open_timeout)) {
+ timeout = connect_timeout;
+ } else {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(res, arg->remote.host, arg->remote.serv);
+ }
+ }
+
if (status >= 0) {
- status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), connect_timeout);
+ status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), timeout);
syscall = "connect(2)";
}
}
@@ -172,8 +212,16 @@ init_inetsock_internal(VALUE v)
#if FAST_FALLBACK_INIT_INETSOCK_IMPL == 0
VALUE
-rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE _fast_fallback, VALUE _test_mode_settings)
+rsock_init_inetsock(
+ VALUE self, VALUE remote_host, VALUE remote_serv,
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
+ VALUE _fast_fallback, VALUE _test_mode_settings)
{
+ if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
+ rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
+ }
+
struct inetsock_arg arg;
arg.self = self;
arg.io = Qnil;
@@ -186,6 +234,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
arg.type = type;
arg.resolv_timeout = resolv_timeout;
arg.connect_timeout = connect_timeout;
+ arg.open_timeout = open_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
}
@@ -209,6 +258,21 @@ is_specified_ip_address(const char *hostname)
inet_pton(AF_INET, hostname, &ipv4addr) == 1);
}
+static int
+is_local_port_fixed(const char *portp)
+{
+ if (!portp) return 0;
+
+ char *endp;
+ errno = 0;
+ long port = strtol(portp, &endp, 10);
+
+ if (endp == portp) return 0;
+ if (errno == ERANGE) return 0;
+
+ return port > 0;
+}
+
struct fast_fallback_inetsock_arg
{
VALUE self;
@@ -221,6 +285,7 @@ struct fast_fallback_inetsock_arg
int type;
VALUE resolv_timeout;
VALUE connect_timeout;
+ VALUE open_timeout;
const char *hostp, *portp;
int *families;
@@ -295,7 +360,7 @@ struct hostname_resolution_store
{
struct hostname_resolution_result v6;
struct hostname_resolution_result v4;
- int is_all_finised;
+ int is_all_finished;
};
static int
@@ -380,12 +445,22 @@ select_expires_at(
struct timeval *resolution_delay,
struct timeval *connection_attempt_delay,
struct timeval *user_specified_resolv_timeout_at,
- struct timeval *user_specified_connect_timeout_at
-) {
+ struct timeval *user_specified_connect_timeout_at,
+ struct timeval *user_specified_open_timeout_at)
+{
if (any_addrinfos(resolution_store)) {
- return resolution_delay ? resolution_delay : connection_attempt_delay;
+ struct timeval *delay;
+ delay = resolution_delay ? resolution_delay : connection_attempt_delay;
+
+ if (user_specified_open_timeout_at &&
+ timercmp(user_specified_open_timeout_at, delay, <)) {
+ return user_specified_open_timeout_at;
+ }
+ return delay;
}
+ if (user_specified_open_timeout_at) return user_specified_open_timeout_at;
+
struct timeval *timeout = NULL;
if (user_specified_resolv_timeout_at) {
@@ -474,7 +549,8 @@ in_progress_fds(int fds_size)
}
static void
-remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd) {
+remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd)
+{
int i, j;
for (i = 0; i < *fds_size; i++) {
@@ -503,6 +579,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
VALUE io = arg->io;
VALUE resolv_timeout = arg->resolv_timeout;
VALUE connect_timeout = arg->connect_timeout;
+ VALUE open_timeout = arg->open_timeout;
VALUE test_mode_settings = arg->test_mode_settings;
struct addrinfo *remote_ai = NULL, *local_ai = NULL;
int connected_fd = -1, status = 0, local_status = 0;
@@ -527,7 +604,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval *delay_p = NULL;
struct hostname_resolution_store resolution_store;
- resolution_store.is_all_finised = false;
+ resolution_store.is_all_finished = false;
resolution_store.v6.ai = NULL;
resolution_store.v6.finished = false;
resolution_store.v6.has_error = false;
@@ -549,7 +626,16 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval *user_specified_resolv_timeout_at = NULL;
struct timeval user_specified_connect_timeout_storage;
struct timeval *user_specified_connect_timeout_at = NULL;
+ struct timeval user_specified_open_timeout_storage;
+ struct timeval *user_specified_open_timeout_at = NULL;
struct timespec now = current_clocktime_ts();
+ VALUE starts_at = current_clocktime();
+
+ if (!NIL_P(open_timeout)) {
+ struct timeval open_timeout_tv = rb_time_interval(open_timeout);
+ user_specified_open_timeout_storage = add_ts_to_tv(open_timeout_tv, now);
+ user_specified_open_timeout_at = &user_specified_open_timeout_storage;
+ }
/* start of hostname resolution */
if (arg->family_size == 1) {
@@ -557,12 +643,15 @@ init_fast_fallback_inetsock_internal(VALUE v)
arg->getaddrinfo_shared = NULL;
int family = arg->families[0];
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
+
arg->remote.res = rsock_addrinfo(
arg->remote.host,
arg->remote.serv,
family,
SOCK_STREAM,
- 0
+ 0,
+ t
);
if (family == AF_INET6) {
@@ -574,7 +663,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.v4.finished = true;
resolution_store.v6.finished = true;
}
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
} else {
if (pipe(pipefd) != 0) rb_syserr_fail(errno, "pipe(2)");
hostname_resolution_waiter = pipefd[0];
@@ -640,7 +729,6 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (raddrinfo_pthread_create(&threads[i], fork_safe_do_fast_fallback_getaddrinfo, arg->getaddrinfo_entries[i]) != 0) {
rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN);
}
- pthread_detach(threads[i]);
}
if (NIL_P(resolv_timeout)) {
@@ -664,7 +752,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (remote_ai->ai_family == AF_INET6) {
if (any_addrinfos(&resolution_store)) continue;
if (!in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (resolution_store.is_all_finised) break;
+ if (resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -690,7 +778,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (!local_ai) {
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
/* Use a different family local address if no choice, this
* will cause EAFNOSUPPORT. */
@@ -707,7 +795,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -743,7 +831,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -764,19 +852,31 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store) ||
in_progress_fds(arg->connection_attempt_fds_size) ||
- !resolution_store.is_all_finised) {
+ !resolution_store.is_all_finished) {
socket_nonblock_set(fd);
status = connect(fd, remote_ai->ai_addr, remote_ai->ai_addrlen);
last_family = remote_ai->ai_family;
} else {
- if (!NIL_P(connect_timeout)) {
- user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
- user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ VALUE timeout = Qnil;
+
+ if (!NIL_P(open_timeout)) {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+ }
+ if (NIL_P(timeout)) {
+ if (!NIL_P(connect_timeout)) {
+ user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
+ user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ }
+ timeout =
+ (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
+ Qnil : tv_to_seconds(user_specified_connect_timeout_at);
}
- VALUE timeout =
- (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
- Qnil : tv_to_seconds(user_specified_connect_timeout_at);
io = arg->io = rsock_init_sock(arg->self, fd);
status = rsock_connect(io, remote_ai->ai_addr, remote_ai->ai_addrlen, 0, timeout);
}
@@ -824,7 +924,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -848,7 +948,8 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_delay_expires_at,
connection_attempt_delay_expires_at,
user_specified_resolv_timeout_at,
- user_specified_connect_timeout_at
+ user_specified_connect_timeout_at,
+ user_specified_open_timeout_at
);
if (ends_at) {
delay = tv_to_timeout(ends_at, now);
@@ -922,7 +1023,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -961,7 +1062,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (connected_fd >= 0) break;
if (!in_progress_fds(arg->connection_attempt_fds_size)) {
- if (!any_addrinfos(&resolution_store) && resolution_store.is_all_finised) {
+ if (!any_addrinfos(&resolution_store) && resolution_store.is_all_finished) {
if (local_status < 0) {
host = arg->local.host;
serv = arg->local.serv;
@@ -981,7 +1082,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
/* check for hostname resolution */
- if (!resolution_store.is_all_finised && rb_fd_isset(hostname_resolution_waiter, &arg->readfds)) {
+ if (!resolution_store.is_all_finished && rb_fd_isset(hostname_resolution_waiter, &arg->readfds)) {
while (true) {
resolved_type_size = read(
hostname_resolution_waiter,
@@ -1007,7 +1108,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.v6.ai = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->ai;
}
if (resolution_store.v4.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
break;
@@ -1027,7 +1128,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
if (resolution_store.v6.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
break;
@@ -1055,7 +1156,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
/* For cases where write(2) fails in child threads */
- if (!resolution_store.is_all_finised) {
+ if (!resolution_store.is_all_finished) {
if (!resolution_store.v6.finished && arg->getaddrinfo_entries[IPV6_ENTRY_POS]->has_syserr) {
resolution_store.v6.finished = true;
@@ -1071,7 +1172,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
if (resolution_store.v4.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
}
@@ -1091,7 +1192,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
if (resolution_store.v6.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
} else {
@@ -1101,9 +1202,13 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
}
+ if (is_timeout_tv(user_specified_open_timeout_at, now)) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+
if (!any_addrinfos(&resolution_store)) {
if (!in_progress_fds(arg->connection_attempt_fds_size) &&
- resolution_store.is_all_finised) {
+ resolution_store.is_all_finished) {
if (local_status < 0) {
host = arg->local.host;
serv = arg->local.serv;
@@ -1119,12 +1224,10 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
if ((is_timeout_tv(user_specified_resolv_timeout_at, now) ||
- resolution_store.is_all_finised) &&
+ resolution_store.is_all_finished) &&
(is_timeout_tv(user_specified_connect_timeout_at, now) ||
!in_progress_fds(arg->connection_attempt_fds_size))) {
- VALUE errno_module = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE etimedout_error = rb_const_get(errno_module, rb_intern("ETIMEDOUT"));
- rb_raise(etimedout_error, "user specified timeout");
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
}
}
}
@@ -1159,13 +1262,19 @@ fast_fallback_inetsock_cleanup(VALUE v)
getaddrinfo_shared->notify = -1;
int shared_need_free = 0;
- int need_free[2] = { 0, 0 };
+ struct addrinfo *ais[arg->family_size];
+ for (int i = 0; i < arg->family_size; i++) ais[i] = NULL;
rb_nativethread_lock_lock(&getaddrinfo_shared->lock);
{
for (int i = 0; i < arg->family_size; i++) {
- if (arg->getaddrinfo_entries[i] && --(arg->getaddrinfo_entries[i]->refcount) == 0) {
- need_free[i] = 1;
+ struct fast_fallback_getaddrinfo_entry *getaddrinfo_entry = arg->getaddrinfo_entries[i];
+
+ if (!getaddrinfo_entry) continue;
+
+ if (--(getaddrinfo_entry->refcount) == 0) {
+ ais[i] = getaddrinfo_entry->ai;
+ getaddrinfo_entry->ai = NULL;
}
}
if (--(getaddrinfo_shared->refcount) == 0) {
@@ -1175,9 +1284,7 @@ fast_fallback_inetsock_cleanup(VALUE v)
rb_nativethread_lock_unlock(&getaddrinfo_shared->lock);
for (int i = 0; i < arg->family_size; i++) {
- if (arg->getaddrinfo_entries[i] && need_free[i]) {
- free_fast_fallback_getaddrinfo_entry(&arg->getaddrinfo_entries[i]);
- }
+ if (ais[i]) freeaddrinfo(ais[i]);
}
if (getaddrinfo_shared && shared_need_free) {
free_fast_fallback_getaddrinfo_shared(&getaddrinfo_shared);
@@ -1210,17 +1317,27 @@ fast_fallback_inetsock_cleanup(VALUE v)
}
VALUE
-rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings)
+rsock_init_inetsock(
+ VALUE self, VALUE remote_host, VALUE remote_serv,
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
+ VALUE fast_fallback, VALUE test_mode_settings)
{
+ if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
+ rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
+ }
+
if (type == INET_CLIENT && FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 && RTEST(fast_fallback)) {
struct rb_addrinfo *local_res = NULL;
- char *hostp, *portp;
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ char *hostp, *portp, *local_portp;
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], local_pbuf[NI_MAXSERV];
int additional_flags = 0;
+ int local_flags = 0;
hostp = raddrinfo_host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags);
portp = raddrinfo_port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags);
+ local_portp = raddrinfo_port_str(local_serv, local_pbuf, sizeof(local_pbuf), &local_flags);
- if (!is_specified_ip_address(hostp)) {
+ if (!is_specified_ip_address(hostp) && !is_local_port_fixed(local_portp)) {
int target_families[2] = { 0, 0 };
int resolving_family_size = 0;
@@ -1228,16 +1345,18 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
* Maybe also accept a local address
*/
if (!NIL_P(local_host) || !NIL_P(local_serv)) {
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
local_res = rsock_addrinfo(
local_host,
local_serv,
AF_UNSPEC,
SOCK_STREAM,
- 0
+ 0,
+ t
);
struct addrinfo *tmp_p = local_res->ai;
- for (tmp_p; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
+ for (; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
if (target_families[0] == 0 && tmp_p->ai_family == AF_INET6) {
target_families[0] = AF_INET6;
resolving_family_size++;
@@ -1267,6 +1386,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
fast_fallback_arg.type = type;
fast_fallback_arg.resolv_timeout = resolv_timeout;
fast_fallback_arg.connect_timeout = connect_timeout;
+ fast_fallback_arg.open_timeout = open_timeout;
fast_fallback_arg.hostp = hostp;
fast_fallback_arg.portp = portp;
fast_fallback_arg.additional_flags = additional_flags;
@@ -1303,6 +1423,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
arg.type = type;
arg.resolv_timeout = resolv_timeout;
arg.connect_timeout = connect_timeout;
+ arg.open_timeout = open_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
@@ -1488,7 +1609,7 @@ static VALUE
ip_s_getaddress(VALUE obj, VALUE host)
{
union_sockaddr addr;
- struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, Qnil);
socklen_t len = res->ai->ai_addrlen;
/* just take the first one */
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index ae73b8799e..465b74964f 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -62,7 +62,7 @@ class Addrinfo
break
when :wait_writable
sock.wait_writable(timeout) or
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise Errno::ETIMEDOUT, "user specified timeout for #{self.ip_address}:#{self.ip_port}"
end while true
else
sock.connect(self)
@@ -599,6 +599,7 @@ class Socket < BasicSocket
__accept_nonblock(exception)
end
+ # :stopdoc:
RESOLUTION_DELAY = 0.05
private_constant :RESOLUTION_DELAY
@@ -616,6 +617,7 @@ class Socket < BasicSocket
IPV6_ADDRESS_FORMAT = /\A(?i:(?:(?:[0-9A-F]{1,4}:){7}(?:[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){6}(?:[0-9A-F]{1,4}|:(?:[0-9A-F]{1,4}:){1,5}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){5}(?:(?::[0-9A-F]{1,4}){1,2}|:(?:[0-9A-F]{1,4}:){1,4}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){4}(?:(?::[0-9A-F]{1,4}){1,3}|:(?:[0-9A-F]{1,4}:){1,3}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){3}(?:(?::[0-9A-F]{1,4}){1,4}|:(?:[0-9A-F]{1,4}:){1,2}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){2}(?:(?::[0-9A-F]{1,4}){1,5}|:(?:[0-9A-F]{1,4}:)[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){1}(?:(?::[0-9A-F]{1,4}){1,6}|:(?:[0-9A-F]{1,4}:){0,5}[0-9A-F]{1,4}|:)|(?:::(?:[0-9A-F]{1,4}:){0,7}[0-9A-F]{1,4}|::)))(?:%.+)?\z/
private_constant :IPV6_ADDRESS_FORMAT
+ # :startdoc:
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
@@ -643,6 +645,7 @@ class Socket < BasicSocket
#
# [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts.
# [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled.
+ # [:open_timeout] Specifies the timeout in seconds from the start of the method execution.<br>If this timeout is reached while there are still addresses that have not yet been attempted for connection, no further attempts will be made.<br>If this option is specified together with other timeout options, an +ArgumentError+ will be raised.
# [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default).
#
# If a block is given, the block is called with the socket.
@@ -656,11 +659,15 @@ class Socket < BasicSocket
# sock.close_write
# puts sock.read
# }
- def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
- sock = if fast_fallback && !(host && ip_address?(host))
- tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
+ if open_timeout && (connect_timeout || resolv_timeout)
+ raise ArgumentError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout"
+ end
+
+ sock = if fast_fallback && !(host && ip_address?(host)) && !(local_port && local_port.to_i != 0)
+ tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
else
- tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
end
if block_given?
@@ -674,9 +681,10 @@ class Socket < BasicSocket
end
end
- def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil)
+ # :stopdoc:
+ def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil)
if local_host || local_port
- local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: resolv_timeout)
+ local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: open_timeout || resolv_timeout)
resolving_family_names = local_addrinfos.map { |lai| ADDRESS_FAMILIES.key(lai.afamily) }.uniq
else
local_addrinfos = []
@@ -689,14 +697,17 @@ class Socket < BasicSocket
is_windows_environment ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
now = current_clock_time
+ starts_at = now
resolution_delay_expires_at = nil
connection_attempt_delay_expires_at = nil
user_specified_connect_timeout_at = nil
+ user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil
last_error = nil
+ last_error_from_thread = false
if resolving_family_names.size == 1
family_name = resolving_family_names.first
- addrinfos = Addrinfo.getaddrinfo(host, port, family_name, :STREAM, timeout: resolv_timeout)
+ addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: open_timeout || resolv_timeout)
resolution_store.add_resolved(family_name, addrinfos)
hostname_resolution_result = nil
hostname_resolution_notifier = nil
@@ -713,7 +724,6 @@ class Socket < BasicSocket
thread
}
)
-
user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
end
@@ -725,7 +735,7 @@ class Socket < BasicSocket
if local_addrinfos.any?
local_addrinfo = local_addrinfos.find { |lai| lai.afamily == addrinfo.afamily }
- if local_addrinfo.nil? # Connecting addrinfoと同じアドレスファミリのLocal addrinfoがない
+ if local_addrinfo.nil?
if resolution_store.any_addrinfos?
# Try other Addrinfo in next "while"
next
@@ -747,9 +757,16 @@ class Socket < BasicSocket
socket.bind(local_addrinfo) if local_addrinfo
result = socket.connect_nonblock(addrinfo, exception: false)
else
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
result = socket = local_addrinfo ?
- addrinfo.connect_from(local_addrinfo, timeout: connect_timeout) :
- addrinfo.connect(timeout: connect_timeout)
+ addrinfo.connect_from(local_addrinfo, timeout:) :
+ addrinfo.connect(timeout:)
end
if result == :wait_writable
@@ -783,7 +800,10 @@ class Socket < BasicSocket
ends_at =
if resolution_store.any_addrinfos?
- resolution_delay_expires_at || connection_attempt_delay_expires_at
+ [(resolution_delay_expires_at || connection_attempt_delay_expires_at),
+ user_specified_open_timeout_at].compact.min
+ elsif user_specified_open_timeout_at
+ user_specified_open_timeout_at
else
[user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max
end
@@ -865,6 +885,7 @@ class Socket < BasicSocket
other = family_name == :ipv6 ? :ipv4 : :ipv6
if !resolution_store.resolved?(other) || !resolution_store.resolved_successfully?(other)
last_error = result
+ last_error_from_thread = true
end
end
else
@@ -883,39 +904,47 @@ class Socket < BasicSocket
end
end
+ if expired?(now, user_specified_open_timeout_at)
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
+ end
+
if resolution_store.empty_addrinfos?
if connecting_sockets.empty? && resolution_store.resolved_all_families?
- raise last_error
+ if last_error_from_thread
+ raise last_error.class, last_error.message, cause: last_error
+ else
+ raise last_error
+ end
end
if (expired?(now, user_specified_resolv_timeout_at) || resolution_store.resolved_all_families?) &&
(expired?(now, user_specified_connect_timeout_at) || connecting_sockets.empty?)
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
end
end
end
ensure
- hostname_resolution_threads.each do |thread|
- thread.exit
- end
+ hostname_resolution_threads.each(&:exit).each(&:join)
hostname_resolution_result&.close
- connecting_sockets.each_key do |connecting_socket|
- connecting_socket.close
- end
+ connecting_sockets.each_key(&:close)
end
+ private_class_method :tcp_with_fast_fallback
- def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
last_error = nil
ret = nil
local_addr_list = nil
if local_host != nil || local_port != nil
- local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
+ local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil, timeout: open_timeout || resolv_timeout)
end
- Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai|
+ timeout = open_timeout ? open_timeout : resolv_timeout
+ starts_at = current_clock_time
+
+ Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai|
if local_addr_list
local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
next unless local_addr
@@ -923,9 +952,17 @@ class Socket < BasicSocket
local_addr = nil
end
begin
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
+
sock = local_addr ?
- ai.connect_from(local_addr, timeout: connect_timeout) :
- ai.connect(timeout: connect_timeout)
+ ai.connect_from(local_addr, timeout:) :
+ ai.connect(timeout:)
rescue SystemCallError
last_error = $!
next
@@ -1084,7 +1121,6 @@ class Socket < BasicSocket
end
private_constant :HostnameResolutionStore
- # :stopdoc:
def self.ip_sockets_port0(ai_list, reuseaddr)
sockets = []
begin
@@ -1117,9 +1153,7 @@ class Socket < BasicSocket
end
sockets
end
- class << self
- private :ip_sockets_port0
- end
+ private_class_method :ip_sockets_port0
def self.tcp_server_sockets_port0(host)
ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
@@ -1547,13 +1581,18 @@ class Socket < BasicSocket
end
end
- class << self
- private
-
- def unix_socket_abstract_name?(path)
- /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
+ # :stopdoc:
+ if RUBY_PLATFORM.include?("linux")
+ def self.unix_socket_abstract_name?(path)
+ path.empty? or path.start_with?("\0")
+ end
+ else
+ def self.unix_socket_abstract_name?(path)
+ false
end
end
+ private_class_method :unix_socket_abstract_name?
+ # :startdoc:
# creates a UNIX socket server on _path_.
# It calls the block for each socket accepted.
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index ac47b5b256..f1fbcc35de 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -293,10 +293,22 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
xfree(ai);
}
+static int
+rsock_value_timeout_to_msec(VALUE timeout)
+{
+ double seconds = NUM2DBL(timeout);
+ if (seconds < 0) rb_raise(rb_eArgError, "timeout must not be negative");
+
+ double msec = seconds * 1000.0;
+ if (msec > UINT_MAX) rb_raise(rb_eArgError, "timeout too large");
+
+ return (unsigned int)(msec + 0.5);
+}
+
#if GETADDRINFO_IMPL == 0
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
return getaddrinfo(hostp, portp, hints, ai);
}
@@ -334,7 +346,7 @@ fork_safe_getaddrinfo(void *arg)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
struct getaddrinfo_arg arg;
MEMZERO(&arg, struct getaddrinfo_arg, 1);
@@ -352,13 +364,14 @@ struct getaddrinfo_arg
char *node, *service;
struct addrinfo hints;
struct addrinfo *ai;
- int err, gai_errno, refcount, done, cancelled;
+ int err, gai_errno, refcount, done, cancelled, timedout;
rb_nativethread_lock_t lock;
rb_nativethread_cond_t cond;
+ int timeout;
};
static struct getaddrinfo_arg *
-allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints)
+allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout)
{
size_t hostp_offset = sizeof(struct getaddrinfo_arg);
size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
@@ -374,7 +387,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (hostp) {
arg->node = buf + hostp_offset;
- strcpy(arg->node, hostp);
+ memcpy(arg->node, hostp, portp_offset - hostp_offset);
}
else {
arg->node = NULL;
@@ -382,7 +395,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (portp) {
arg->service = buf + portp_offset;
- strcpy(arg->service, portp);
+ memcpy(arg->service, portp, bufsize - portp_offset);
}
else {
arg->service = NULL;
@@ -392,7 +405,8 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
arg->ai = NULL;
arg->refcount = 2;
- arg->done = arg->cancelled = 0;
+ arg->done = arg->cancelled = arg->timedout = 0;
+ arg->timeout = timeout;
rb_nativethread_lock_initialize(&arg->lock);
rb_native_cond_initialize(&arg->cond);
@@ -451,7 +465,19 @@ 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);
+ long msec = arg->timeout;
+ if (msec == 0) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ } else if (msec > 0) {
+ rb_native_cond_timedwait(&arg->cond, &arg->lock, msec);
+ if (!arg->done) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ }
+ } else {
+ rb_native_cond_wait(&arg->cond, &arg->lock);
+ }
}
rb_nativethread_lock_unlock(&arg->lock);
return 0;
@@ -473,13 +499,49 @@ int
raddrinfo_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg)
{
int limit = 3, ret;
+ int saved_errno;
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ pthread_attr_t attr;
+ pthread_attr_t *attr_p = &attr;
+ int err;
+ int init_retries = 0;
+ int init_retries_max = 3;
+retry_attr_init:
+ if ((err = pthread_attr_init(attr_p)) != 0) {
+ if (err == ENOMEM && init_retries < init_retries_max) {
+ init_retries++;
+ rb_gc();
+ goto retry_attr_init;
+ }
+ return err;
+ }
+ if ((err = pthread_attr_setdetachstate(attr_p, PTHREAD_CREATE_DETACHED)) != 0) {
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ errno = saved_errno;
+ return err; // EINVAL - shouldn't happen
+ }
+#else
+ pthread_attr_t *attr_p = NULL;
+#endif
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);
+ ret = pthread_create(th, attr_p, start_routine, arg);
} while (ret == EAGAIN && limit-- > 0);
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ if (ret != 0) {
+ errno = saved_errno;
+ }
+#else
+ if (ret == 0) {
+ pthread_detach(th); // this can race with shutdown routine of thread in some glibc versions
+ }
+#endif
return ret;
}
@@ -490,16 +552,16 @@ fork_safe_do_getaddrinfo(void *ptr)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout)
{
int retry;
struct getaddrinfo_arg *arg;
- int err = 0, gai_errno = 0;
+ int err = 0, gai_errno = 0, timedout = 0;
start:
retry = 0;
- arg = allocate_getaddrinfo_arg(hostp, portp, hints);
+ arg = allocate_getaddrinfo_arg(hostp, portp, hints, timeout);
if (!arg) {
return EAI_MEMORY;
}
@@ -511,7 +573,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg);
@@ -525,6 +586,7 @@ start:
}
else if (arg->cancelled) {
retry = 1;
+ timedout = arg->timedout;
}
else {
// If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getaddrinfo.
@@ -538,6 +600,12 @@ start:
if (need_free) free_getaddrinfo_arg(arg);
+ if (timedout) {
+ VALUE host = rb_str_new_cstr(hostp);
+ VALUE port = rb_str_new_cstr(portp);
+ rsock_raise_user_specified_timeout(NULL, host, port);
+ }
+
// 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();
@@ -552,6 +620,10 @@ start:
#endif
+#define GETNAMEINFO_WONT_BLOCK(host, serv, flags) \
+ ((!(host) || ((flags) & NI_NUMERICHOST)) && \
+ (!(serv) || ((flags) & NI_NUMERICSERV)))
+
#if GETADDRINFO_IMPL == 0
int
@@ -559,7 +631,7 @@ 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);
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
}
#elif GETADDRINFO_IMPL == 1
@@ -589,6 +661,10 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags)
{
+ if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
+ return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+ }
+
struct getnameinfo_arg arg;
int ret;
arg.sa = sa;
@@ -715,7 +791,11 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
{
int retry;
struct getnameinfo_arg *arg;
- int err, gni_errno = 0;
+ int err = 0, gni_errno = 0;
+
+ if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
+ }
start:
retry = 0;
@@ -732,7 +812,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg);
@@ -941,7 +1020,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
}
struct rb_addrinfo*
-rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
+rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout)
{
struct rb_addrinfo* res = NULL;
struct addrinfo *ai;
@@ -976,7 +1055,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
}
if (!resolved) {
- error = rb_getaddrinfo(hostp, portp, hints, &ai);
+ int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout);
+ error = rb_getaddrinfo(hostp, portp, hints, &ai, t);
if (error == 0) {
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
res->allocated_by_malloc = 0;
@@ -1009,7 +1089,7 @@ rsock_fd_family(int fd)
}
struct rb_addrinfo*
-rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
+rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout)
{
struct addrinfo hints;
@@ -1017,7 +1097,7 @@ rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
hints.ai_family = family;
hints.ai_socktype = socktype;
hints.ai_flags = flags;
- return rsock_getaddrinfo(host, port, &hints, 1);
+ return rsock_getaddrinfo(host, port, &hints, 1, timeout);
}
VALUE
@@ -1211,6 +1291,7 @@ addrinfo_memsize(const void *ptr)
static const rb_data_type_t addrinfo_type = {
"socket/addrinfo",
{addrinfo_mark, addrinfo_free, addrinfo_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
@@ -1248,7 +1329,7 @@ alloc_addrinfo(void)
}
static void
-init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
+init_addrinfo(VALUE self, rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
int pfamily, int socktype, int protocol,
VALUE canonname, VALUE inspectname)
{
@@ -1260,8 +1341,8 @@ init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
rai->pfamily = pfamily;
rai->socktype = socktype;
rai->protocol = protocol;
- rai->canonname = canonname;
- rai->inspectname = inspectname;
+ RB_OBJ_WRITE(self, &rai->canonname, canonname);
+ RB_OBJ_WRITE(self, &rai->inspectname, inspectname);
}
VALUE
@@ -1274,7 +1355,7 @@ rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
a = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(a) = rai = alloc_addrinfo();
- init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
+ init_addrinfo(a, rai, addr, len, family, socktype, protocol, canonname, inspectname);
return a;
}
@@ -1299,7 +1380,7 @@ call_getaddrinfo(VALUE node, VALUE service,
hints.ai_flags = NUM2INT(flags);
}
- res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
+ res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout);
if (res == NULL)
rb_raise(rb_eSocket, "host not found");
@@ -1309,7 +1390,7 @@ call_getaddrinfo(VALUE node, VALUE service,
static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
static void
-init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
+init_addrinfo_getaddrinfo(VALUE self, rb_addrinfo_t *rai, VALUE node, VALUE service,
VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
VALUE inspectnode, VALUE inspectservice)
{
@@ -1323,7 +1404,7 @@ init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
OBJ_FREEZE(canonname);
}
- init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
+ init_addrinfo(self, rai, res->ai->ai_addr, res->ai->ai_addrlen,
NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
canonname, inspectname);
@@ -1435,7 +1516,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
static void
-init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
+init_unix_addrinfo(VALUE self, rb_addrinfo_t *rai, VALUE path, int socktype)
{
struct sockaddr_un un;
socklen_t len;
@@ -1451,7 +1532,7 @@ init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
len = rsock_unix_sockaddr_len(path);
- init_addrinfo(rai, (struct sockaddr *)&un, len,
+ init_addrinfo(self, rai, (struct sockaddr *)&un, len,
PF_UNIX, socktype, 0, Qnil, Qnil);
}
@@ -1555,7 +1636,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
flags |= AI_NUMERICSERV;
#endif
- init_addrinfo_getaddrinfo(rai, numericnode, service,
+ init_addrinfo_getaddrinfo(self, rai, numericnode, service,
INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
INT2NUM(flags),
nodename, service);
@@ -1567,7 +1648,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE path = rb_ary_entry(sockaddr_ary, 1);
StringValue(path);
- init_unix_addrinfo(rai, path, SOCK_STREAM);
+ init_unix_addrinfo(self, rai, path, SOCK_STREAM);
break;
}
#endif
@@ -1580,7 +1661,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
StringValue(sockaddr_arg);
sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
- init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
+ init_addrinfo(self, rai, sockaddr_ptr, sockaddr_len,
i_pfamily, i_socktype, i_protocol,
canonname, inspectname);
}
@@ -2169,7 +2250,7 @@ addrinfo_mload(VALUE self, VALUE ary)
}
DATA_PTR(self) = rai = alloc_addrinfo();
- init_addrinfo(rai, &ss.addr, len,
+ init_addrinfo(self, rai, &ss.addr, len,
pfamily, socktype, protocol,
canonname, inspectname);
return self;
@@ -2937,7 +3018,7 @@ addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
addr = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(addr) = rai = alloc_addrinfo();
- init_unix_addrinfo(rai, path, socktype);
+ init_unix_addrinfo(self, rai, path, socktype);
return addr;
}
@@ -3038,22 +3119,13 @@ free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shared **
*shared = NULL;
}
-void
-free_fast_fallback_getaddrinfo_entry(struct fast_fallback_getaddrinfo_entry **entry)
-{
- if ((*entry)->ai) {
- freeaddrinfo((*entry)->ai);
- (*entry)->ai = NULL;
- }
- *entry = NULL;
-}
-
static void *
do_fast_fallback_getaddrinfo(void *ptr)
{
struct fast_fallback_getaddrinfo_entry *entry = (struct fast_fallback_getaddrinfo_entry *)ptr;
struct fast_fallback_getaddrinfo_shared *shared = entry->shared;
- int err = 0, need_free = 0, shared_need_free = 0;
+ int err = 0, shared_need_free = 0;
+ struct addrinfo *ai = NULL;
sigset_t set;
sigemptyset(&set);
@@ -3102,14 +3174,15 @@ do_fast_fallback_getaddrinfo(void *ptr)
entry->err = errno;
entry->has_syserr = true;
}
- if (--(entry->refcount) == 0) need_free = 1;
+ if (--(entry->refcount) == 0) {
+ ai = entry->ai;
+ entry->ai = NULL;
+ }
if (--(shared->refcount) == 0) shared_need_free = 1;
}
rb_nativethread_lock_unlock(&shared->lock);
- if (need_free && entry) {
- free_fast_fallback_getaddrinfo_entry(&entry);
- }
+ if (ai) freeaddrinfo(ai);
if (shared_need_free && shared) {
free_fast_fallback_getaddrinfo_shared(&shared);
}
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 54a5381da4..2ec3ab335a 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -292,8 +292,8 @@ extern VALUE rb_eResolution;
#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
# ifndef SOCKS5
-void SOCKSinit();
-int Rconnect();
+void SOCKSinit(char *);
+int Rconnect(int, const struct sockaddr *, socklen_t);
# endif
#endif
@@ -327,8 +327,8 @@ void rb_freeaddrinfo(struct rb_addrinfo *ai);
VALUE rsock_freeaddrinfo(VALUE arg);
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
int rsock_fd_family(int fd);
-struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags);
-struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
+struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout);
+struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout);
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);
@@ -355,7 +355,7 @@ int rsock_socket(int domain, int type, int proto);
int rsock_detect_cloexec(int fd);
VALUE rsock_init_sock(VALUE sock, int fd);
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
-VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings);
+VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout, VALUE fast_fallback, VALUE test_mode_settings);
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);
struct rsock_send_arg {
@@ -453,6 +453,8 @@ void free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shar
# endif
#endif
+NORETURN(void rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port));
+
void rsock_init_basicsocket(void);
void rsock_init_ipsocket(void);
void rsock_init_tcpsocket(void);
@@ -507,8 +509,6 @@ extern ID tcp_fast_fallback;
const char *inet_ntop(int, const void *, char *, size_t);
#elif defined __MINGW32__
# define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
-#elif defined _MSC_VER && RUBY_MSVCRT_VERSION < 90
-const char *WSAAPI inet_ntop(int, const void *, char *, size_t);
#endif
#endif
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 8f593ca0bd..a8e5ae8119 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -965,7 +965,7 @@ sock_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, sock_sockaddr);
}
@@ -1183,7 +1183,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
norevlookup = rsock_do_not_reverse_lookup;
}
- res = rsock_getaddrinfo(host, port, &hints, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
ret = make_addrinfo(res, norevlookup);
rb_freeaddrinfo(res);
@@ -1279,7 +1279,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
/* af */
hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
- res = rsock_getaddrinfo(host, port, &hints, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
sap = res->ai->ai_addr;
salen = res->ai->ai_addrlen;
}
@@ -1335,7 +1335,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
- struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, Qnil);
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
rb_freeaddrinfo(res);
diff --git a/ext/socket/sockssocket.c b/ext/socket/sockssocket.c
index 1031812bef..30860ea257 100644
--- a/ext/socket/sockssocket.c
+++ b/ext/socket/sockssocket.c
@@ -30,11 +30,12 @@ socks_init(VALUE sock, VALUE host, VALUE port)
static int init = 0;
if (init == 0) {
- SOCKSinit("ruby");
+ char progname[] = "ruby";
+ SOCKSinit(progname);
init = 1;
}
- return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qfalse, Qnil);
+ return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qnil, Qfalse, Qnil);
}
#ifdef SOCKS5
diff --git a/ext/socket/tcpserver.c b/ext/socket/tcpserver.c
index 8206fe46a9..0069f3c703 100644
--- a/ext/socket/tcpserver.c
+++ b/ext/socket/tcpserver.c
@@ -36,7 +36,7 @@ tcp_svr_init(int argc, VALUE *argv, VALUE sock)
VALUE hostname, port;
rb_scan_args(argc, argv, "011", &hostname, &port);
- return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qfalse, Qnil);
+ return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qnil, Qfalse, Qnil);
}
/*
diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c
index 28527f632f..7ce536e0af 100644
--- a/ext/socket/tcpsocket.c
+++ b/ext/socket/tcpsocket.c
@@ -12,7 +12,7 @@
/*
* call-seq:
- * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, fast_fallback: true)
+ * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, open_timeout: nil, fast_fallback: true)
*
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
* and +local_port+ are specified, then those parameters are used on the local
@@ -35,6 +35,7 @@
*
* [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts.
* [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled.
+ * [:open_timeout] Specifies the timeout in seconds from the start of the method execution.<br>If this timeout is reached while there are still addresses that have not yet been attempted for connection, no further attempts will be made.<br>If this option is specified together with other timeout options, an +ArgumentError+ will be raised.
* [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default).
*/
static VALUE
@@ -43,29 +44,32 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
VALUE remote_host, remote_serv;
VALUE local_host, local_serv;
VALUE opt;
- static ID keyword_ids[4];
- VALUE kwargs[4];
+ static ID keyword_ids[5];
+ VALUE kwargs[5];
VALUE resolv_timeout = Qnil;
VALUE connect_timeout = Qnil;
+ VALUE open_timeout = Qnil;
VALUE fast_fallback = Qnil;
VALUE test_mode_settings = Qnil;
if (!keyword_ids[0]) {
CONST_ID(keyword_ids[0], "resolv_timeout");
CONST_ID(keyword_ids[1], "connect_timeout");
- CONST_ID(keyword_ids[2], "fast_fallback");
- CONST_ID(keyword_ids[3], "test_mode_settings");
+ CONST_ID(keyword_ids[2], "open_timeout");
+ CONST_ID(keyword_ids[3], "fast_fallback");
+ CONST_ID(keyword_ids[4], "test_mode_settings");
}
rb_scan_args(argc, argv, "22:", &remote_host, &remote_serv,
&local_host, &local_serv, &opt);
if (!NIL_P(opt)) {
- rb_get_kwargs(opt, keyword_ids, 0, 4, kwargs);
+ rb_get_kwargs(opt, keyword_ids, 0, 5, kwargs);
if (kwargs[0] != Qundef) { resolv_timeout = kwargs[0]; }
if (kwargs[1] != Qundef) { connect_timeout = kwargs[1]; }
- if (kwargs[2] != Qundef) { fast_fallback = kwargs[2]; }
- if (kwargs[3] != Qundef) { test_mode_settings = kwargs[3]; }
+ if (kwargs[2] != Qundef) { open_timeout = kwargs[2]; }
+ if (kwargs[3] != Qundef) { fast_fallback = kwargs[3]; }
+ if (kwargs[4] != Qundef) { test_mode_settings = kwargs[4]; }
}
if (fast_fallback == Qnil) {
@@ -75,8 +79,8 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
return rsock_init_inetsock(sock, remote_host, remote_serv,
local_host, local_serv, INET_CLIENT,
- resolv_timeout, connect_timeout, fast_fallback,
- test_mode_settings);
+ resolv_timeout, connect_timeout, open_timeout,
+ fast_fallback, test_mode_settings);
}
static VALUE
@@ -109,7 +113,7 @@ tcp_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, tcp_sockaddr);
}
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index a984933c9f..b2bc925538 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -84,7 +84,7 @@ udp_connect(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
int result = (int)rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -129,7 +129,7 @@ udp_bind(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
VALUE result = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -212,7 +212,7 @@ udp_send(int argc, VALUE *argv, VALUE sock)
GetOpenFile(sock, arg.fptr);
arg.sarg.fd = arg.fptr->fd;
arg.sarg.flags = NUM2INT(flags);
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, Qnil);
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 31e2acee04..2ec9376074 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -42,11 +42,12 @@ unixsock_path_value(VALUE path)
}
}
#endif
+ path = rb_get_path(path);
#ifdef _WIN32
/* UNIXSocket requires UTF-8 per spec. */
path = rb_str_export_to_enc(path, rb_utf8_encoding());
#endif
- return rb_get_path(path);
+ return path;
}
VALUE
diff --git a/ext/stringio/depend b/ext/stringio/depend
index b9fba7e9fa..3a82ad0a11 100644
--- a/ext/stringio/depend
+++ b/ext/stringio/depend
@@ -138,6 +138,7 @@ stringio.o: $(hdrdir)/ruby/internal/intern/re.h
stringio.o: $(hdrdir)/ruby/internal/intern/ruby.h
stringio.o: $(hdrdir)/ruby/internal/intern/select.h
stringio.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stringio.o: $(hdrdir)/ruby/internal/intern/set.h
stringio.o: $(hdrdir)/ruby/internal/intern/signal.h
stringio.o: $(hdrdir)/ruby/internal/intern/sprintf.h
stringio.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -171,5 +172,6 @@ stringio.o: $(hdrdir)/ruby/oniguruma.h
stringio.o: $(hdrdir)/ruby/ruby.h
stringio.o: $(hdrdir)/ruby/st.h
stringio.o: $(hdrdir)/ruby/subst.h
+stringio.o: $(hdrdir)/ruby/version.h
stringio.o: stringio.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/stringio/extconf.rb b/ext/stringio/extconf.rb
index 553732f79c..0089766983 100644
--- a/ext/stringio/extconf.rb
+++ b/ext/stringio/extconf.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: false
require 'mkmf'
if RUBY_ENGINE == 'ruby'
+ have_type("rb_io_mode_t", "ruby/io.h")
+
create_makefile('stringio')
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index 89c1ff7c1b..41aa71f893 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -13,13 +13,14 @@
**********************************************************************/
static const char *const
-STRINGIO_VERSION = "3.1.6";
+STRINGIO_VERSION = "3.2.1.dev";
#include <stdbool.h>
#include "ruby.h"
#include "ruby/io.h"
#include "ruby/encoding.h"
+#include "ruby/version.h"
#if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H)
@@ -35,15 +36,33 @@ STRINGIO_VERSION = "3.1.6";
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
#endif
+static inline bool
+str_chilled_p(VALUE str)
+{
+#if (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 4) || RUBY_API_VERSION_MAJOR >= 4
+ // Do not attempt to modify chilled strings on Ruby 3.4+
+ // RUBY_FL_USER2 == STR_CHILLED_LITERAL
+ // RUBY_FL_USER3 == STR_CHILLED_SYMBOL_TO_S
+ return FL_TEST_RAW(str, RUBY_FL_USER2 | RUBY_FL_USER3);
+#else
+ return false;
+#endif
+}
+
+#ifndef HAVE_TYPE_RB_IO_MODE_T
+typedef int rb_io_mode_t;
+#endif
+
struct StringIO {
VALUE string;
rb_encoding *enc;
long pos;
long lineno;
- int flags;
+ rb_io_mode_t flags;
int count;
};
+static struct StringIO *get_strio_for_read(VALUE self);
static VALUE strio_init(int, VALUE *, struct StringIO *, VALUE);
static VALUE strio_unget_bytes(struct StringIO *, const char *, long);
static long strio_write(VALUE self, VALUE str);
@@ -108,8 +127,14 @@ static const rb_data_type_t strio_data_type = {
static struct StringIO*
get_strio(VALUE self)
{
- struct StringIO *ptr = check_strio(rb_io_taint_check(self));
+ rb_check_frozen(self);
+ return get_strio_for_read(self);
+}
+static struct StringIO*
+get_strio_for_read(VALUE self)
+{
+ struct StringIO *ptr = check_strio(self);
if (!ptr) {
rb_raise(rb_eIOError, "uninitialized stream");
}
@@ -136,14 +161,38 @@ strio_substr(struct StringIO *ptr, long pos, long len, rb_encoding *enc)
return enc_subseq(str, pos, len, enc);
}
+static VALUE
+strio_readbuf(struct StringIO *ptr, VALUE str)
+{
+ if (!NIL_P(str)) {
+ StringValue(str);
+ rb_str_modify(str);
+ if (str == ptr->string) {
+ rb_raise(rb_eArgError, "cannot read into the underlying string");
+ }
+ }
+ return str;
+}
+
#define StringIO(obj) get_strio(obj)
+#define StringIOForRead(obj) get_strio_for_read(obj)
#define STRIO_READABLE FL_USER4
#define STRIO_WRITABLE FL_USER5
#define STRIO_READWRITE (STRIO_READABLE|STRIO_WRITABLE)
typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/FMODE_WRITABLE) * 2 - 1];
+#ifndef RB_FL_TEST_RAW
+# define RB_FL_TEST_RAW(obj, bits) (RBASIC(obj)->flags & (bits))
+#endif
+#ifndef RB_FL_SET_RAW
+# define RB_FL_SET_RAW(obj, bits) (RBASIC(obj)->flags |= (bits))
+#endif
+#ifndef RB_FL_UNSET_RAW
+# define RB_FL_UNSET_RAW(obj, bits) (RBASIC(obj)->flags &= ~(bits))
+#endif
+
#define STRIO_MODE_SET_P(strio, mode) \
- ((RBASIC(strio)->flags & STRIO_##mode) && \
+ (RB_FL_TEST_RAW(strio, STRIO_##mode) && \
((struct StringIO*)DATA_PTR(strio))->flags & FMODE_##mode)
#define CLOSED(strio) (!STRIO_MODE_SET_P(strio, READWRITE))
#define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
@@ -154,7 +203,7 @@ static VALUE sym_exception;
static struct StringIO*
readable(VALUE strio)
{
- struct StringIO *ptr = StringIO(strio);
+ struct StringIO *ptr = StringIOForRead(strio);
if (!READABLE(strio)) {
rb_raise(rb_eIOError, "not opened for reading");
}
@@ -185,6 +234,18 @@ check_modifiable(struct StringIO *ptr)
}
}
+static inline bool
+outside_p(struct StringIO *ptr, long pos)
+{
+ return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
+}
+
+static inline bool
+eos_p(struct StringIO *ptr)
+{
+ return outside_p(ptr, ptr->pos);
+}
+
static VALUE
strio_s_allocate(VALUE klass)
{
@@ -195,17 +256,32 @@ strio_s_allocate(VALUE klass)
* call-seq:
* StringIO.new(string = '', mode = 'r+') -> new_stringio
*
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
- *
* Returns a new \StringIO instance formed from +string+ and +mode+;
- * see {Access Modes}[rdoc-ref:File@Access+Modes]:
+ * the instance should be closed when no longer needed:
+ *
+ * strio = StringIO.new
+ * strio.string # => ""
+ * strio.closed_read? # => false
+ * strio.closed_write? # => false
+ * strio.close
+ *
+ * If +string+ is frozen, the default +mode+ is <tt>'r'</tt>:
*
- * strio = StringIO.new # => #<StringIO>
+ * strio = StringIO.new('foo'.freeze)
+ * strio.string # => "foo"
+ * strio.closed_read? # => false
+ * strio.closed_write? # => true
* strio.close
*
- * The instance should be closed when no longer needed.
+ * Argument +mode+ must be a valid
+ * {Access Mode}[rdoc-ref:File@Access+Modes],
+ * which may be a string or an integer constant:
+ *
+ * StringIO.new('foo', 'w+')
+ * StringIO.new('foo', File::RDONLY)
*
- * Related: StringIO.open (accepts block; closes automatically).
+ * Related: StringIO.open
+ * (passes the \StringIO object to the block; closes the object automatically on block exit).
*/
static VALUE
strio_initialize(int argc, VALUE *argv, VALUE self)
@@ -325,14 +401,15 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
ptr->pos = 0;
ptr->lineno = 0;
if (ptr->flags & FMODE_SETENC_BY_BOM) set_encoding_by_bom(ptr);
- RBASIC(self)->flags |= (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE);
+ RB_FL_SET_RAW(self, (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE));
return self;
}
static VALUE
strio_finalize(VALUE self)
{
- struct StringIO *ptr = StringIO(self);
+ struct StringIO *ptr = check_strio(self);
+ if (!ptr) return Qnil;
RB_OBJ_WRITE(self, &ptr->string, Qnil);
ptr->flags &= ~FMODE_READWRITE;
return self;
@@ -340,23 +417,20 @@ strio_finalize(VALUE self)
/*
* call-seq:
- * StringIO.open(string = '', mode = 'r+') {|strio| ... }
- *
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
+ * StringIO.open(string = '', mode = 'r+') -> new_stringio
+ * StringIO.open(string = '', mode = 'r+') {|strio| ... } -> object
*
- * Creates a new \StringIO instance formed from +string+ and +mode+;
- * see {Access Modes}[rdoc-ref:File@Access+Modes].
+ * Creates new \StringIO instance by calling <tt>StringIO.new(string, mode)</tt>.
*
- * With no block, returns the new instance:
+ * With no block given, returns the new instance:
*
* strio = StringIO.open # => #<StringIO>
*
- * With a block, calls the block with the new instance
+ * With a block given, calls the block with the new instance
* and returns the block's value;
- * closes the instance on block exit.
+ * closes the instance on block exit:
*
- * StringIO.open {|strio| p strio }
- * # => #<StringIO>
+ * StringIO.open('foo') {|strio| strio.string.upcase } # => "FOO"
*
* Related: StringIO.new.
*/
@@ -382,42 +456,42 @@ strio_s_new(int argc, VALUE *argv, VALUE klass)
}
/*
- * Returns +false+. Just for compatibility to IO.
+ * Returns +false+; for compatibility with IO.
*/
static VALUE
strio_false(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return Qfalse;
}
/*
- * Returns +nil+. Just for compatibility to IO.
+ * Returns +nil+; for compatibility with IO.
*/
static VALUE
strio_nil(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return Qnil;
}
/*
- * Returns an object itself. Just for compatibility to IO.
+ * Returns +self+; for compatibility with IO.
*/
static VALUE
strio_self(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return self;
}
/*
- * Returns 0. Just for compatibility to IO.
+ * Returns 0; for compatibility with IO.
*/
static VALUE
strio_0(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return INT2FIX(0);
}
@@ -427,7 +501,7 @@ strio_0(VALUE self)
static VALUE
strio_first(VALUE self, VALUE arg)
{
- StringIO(self);
+ StringIOForRead(self);
return arg;
}
@@ -437,7 +511,7 @@ strio_first(VALUE self, VALUE arg)
static VALUE
strio_unimpl(int argc, VALUE *argv, VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
rb_notimplement();
UNREACHABLE;
@@ -465,14 +539,14 @@ strio_unimpl(int argc, VALUE *argv, VALUE self)
static VALUE
strio_get_string(VALUE self)
{
- return StringIO(self)->string;
+ return StringIOForRead(self)->string;
}
/*
* call-seq:
* string = other_string -> other_string
*
- * Assigns the underlying string as +other_string+, and sets position to zero;
+ * Replaces the stored string with +other_string+, and sets the position to zero;
* returns +other_string+:
*
* StringIO.open('foo') do |strio|
@@ -486,7 +560,7 @@ strio_get_string(VALUE self)
* "foo"
* "bar"
*
- * Related: StringIO#string (returns the underlying string).
+ * Related: StringIO#string (returns the stored string).
*/
static VALUE
strio_set_string(VALUE self, VALUE string)
@@ -507,17 +581,22 @@ strio_set_string(VALUE self, VALUE string)
* call-seq:
* close -> nil
*
- * Closes +self+ for both reading and writing.
+ * Closes +self+ for both reading and writing; returns +nil+:
*
- * Raises IOError if reading or writing is attempted.
+ * strio = StringIO.new
+ * strio.closed? # => false
+ * strio.close # => nil
+ * strio.closed? # => true
+ * strio.read # Raises IOError: not opened for reading
+ * strio.write # Raises IOError: not opened for writing
*
- * Related: StringIO#close_read, StringIO#close_write.
+ * Related: StringIO#close_read, StringIO#close_write, StringIO.closed?.
*/
static VALUE
strio_close(VALUE self)
{
StringIO(self);
- RBASIC(self)->flags &= ~STRIO_READWRITE;
+ RB_FL_UNSET_RAW(self, STRIO_READWRITE);
return Qnil;
}
@@ -525,9 +604,16 @@ strio_close(VALUE self)
* call-seq:
* close_read -> nil
*
- * Closes +self+ for reading; closed-write setting remains unchanged.
+ * Closes +self+ for reading;
+ * closed-write setting remains unchanged;
+ * returns +nil+:
*
- * Raises IOError if reading is attempted.
+ * strio = StringIO.new
+ * strio.closed_read? # => false
+ * strio.close_read # => nil
+ * strio.closed_read? # => true
+ * strio.closed_write? # => false
+ * strio.read # Raises IOError: not opened for reading
*
* Related: StringIO#close, StringIO#close_write.
*/
@@ -538,7 +624,7 @@ strio_close_read(VALUE self)
if (!(ptr->flags & FMODE_READABLE)) {
rb_raise(rb_eIOError, "closing non-duplex IO for reading");
}
- RBASIC(self)->flags &= ~STRIO_READABLE;
+ RB_FL_UNSET_RAW(self, STRIO_READABLE);
return Qnil;
}
@@ -546,11 +632,16 @@ strio_close_read(VALUE self)
* call-seq:
* close_write -> nil
*
- * Closes +self+ for writing; closed-read setting remains unchanged.
+ * Closes +self+ for writing; closed-read setting remains unchanged; returns +nil+:
*
- * Raises IOError if writing is attempted.
+ * strio = StringIO.new
+ * strio.closed_write? # => false
+ * strio.close_write # => nil
+ * strio.closed_write? # => true
+ * strio.closed_read? # => false
+ * strio.write('foo') # Raises IOError: not opened for writing
*
- * Related: StringIO#close, StringIO#close_read.
+ * Related: StringIO#close, StringIO#close_read, StringIO#closed_write?.
*/
static VALUE
strio_close_write(VALUE self)
@@ -559,7 +650,7 @@ strio_close_write(VALUE self)
if (!(ptr->flags & FMODE_WRITABLE)) {
rb_raise(rb_eIOError, "closing non-duplex IO for writing");
}
- RBASIC(self)->flags &= ~STRIO_WRITABLE;
+ RB_FL_UNSET_RAW(self, STRIO_WRITABLE);
return Qnil;
}
@@ -567,13 +658,21 @@ strio_close_write(VALUE self)
* call-seq:
* closed? -> true or false
*
- * Returns +true+ if +self+ is closed for both reading and writing,
- * +false+ otherwise.
+ * Returns whether +self+ is closed for both reading and writing:
+ *
+ * strio = StringIO.new
+ * strio.closed? # => false # Open for reading and writing.
+ * strio.close_read
+ * strio.closed? # => false # Still open for writing.
+ * strio.close_write
+ * strio.closed? # => true # Now closed for both.
+ *
+ * Related: StringIO.closed_read?, StringIO.closed_write?.
*/
static VALUE
strio_closed(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
if (!CLOSED(self)) return Qfalse;
return Qtrue;
}
@@ -582,12 +681,19 @@ strio_closed(VALUE self)
* call-seq:
* closed_read? -> true or false
*
- * Returns +true+ if +self+ is closed for reading, +false+ otherwise.
+ * Returns whether +self+ is closed for reading:
+ *
+ * strio = StringIO.new
+ * strio.closed_read? # => false
+ * strio.close_read
+ * strio.closed_read? # => true
+ *
+ * Related: StringIO#closed?, StringIO#closed_write?, StringIO#close_read.
*/
static VALUE
strio_closed_read(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
if (READABLE(self)) return Qfalse;
return Qtrue;
}
@@ -596,12 +702,19 @@ strio_closed_read(VALUE self)
* call-seq:
* closed_write? -> true or false
*
- * Returns +true+ if +self+ is closed for writing, +false+ otherwise.
+ * Returns whether +self+ is closed for writing:
+ *
+ * strio = StringIO.new
+ * strio.closed_write? # => false
+ * strio.close_write
+ * strio.closed_write? # => true
+ *
+ * Related: StringIO#close_write, StringIO#closed?, StringIO#closed_read?.
*/
static VALUE
strio_closed_write(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
if (WRITABLE(self)) return Qfalse;
return Qtrue;
}
@@ -610,19 +723,26 @@ static struct StringIO *
strio_to_read(VALUE self)
{
struct StringIO *ptr = readable(self);
- if (NIL_P(ptr->string)) return NULL;
- if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
- return NULL;
+ if (eos_p(ptr)) return NULL;
+ return ptr;
}
/*
* call-seq:
* eof? -> true or false
*
- * Returns +true+ if positioned at end-of-stream, +false+ otherwise;
- * see {Position}[rdoc-ref:IO@Position].
+ * Returns whether +self+ is positioned at end-of-stream:
+ *
+ * strio = StringIO.new('foo')
+ * strio.pos # => 0
+ * strio.eof? # => false
+ * strio.read # => "foo"
+ * strio.pos # => 3
+ * strio.eof? # => true
+ * strio.close_read
+ * strio.eof? # Raises IOError: not opened for reading
*
- * Raises IOError if the stream is not opened for reading.
+ * Related: StringIO#pos.
*/
static VALUE
strio_eof(VALUE self)
@@ -640,7 +760,7 @@ strio_copy(VALUE copy, VALUE orig)
orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
if (copy == orig) return copy;
- ptr = StringIO(orig);
+ ptr = StringIOForRead(orig);
old_ptr = check_strio(copy);
if (old_ptr) {
old_string = old_ptr->string;
@@ -648,8 +768,8 @@ strio_copy(VALUE copy, VALUE orig)
}
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;
+ RB_FL_UNSET_RAW(copy, STRIO_READWRITE);
+ RB_FL_SET_RAW(copy, RB_FL_TEST_RAW(orig, STRIO_READWRITE));
++ptr->count;
return copy;
}
@@ -659,12 +779,12 @@ strio_copy(VALUE copy, VALUE orig)
* lineno -> current_line_number
*
* Returns the current line number in +self+;
- * see {Line Number}[rdoc-ref:IO@Line+Number].
+ * see {Line Number}[rdoc-ref:StringIO@Line+Number].
*/
static VALUE
strio_get_lineno(VALUE self)
{
- return LONG2NUM(StringIO(self)->lineno);
+ return LONG2NUM(StringIOForRead(self)->lineno);
}
/*
@@ -672,7 +792,7 @@ strio_get_lineno(VALUE self)
* lineno = new_line_number -> new_line_number
*
* Sets the current line number in +self+ to the given +new_line_number+;
- * see {Line Number}[rdoc-ref:IO@Line+Number].
+ * see {Line Number}[rdoc-ref:StringIO@Line+Number].
*/
static VALUE
strio_set_lineno(VALUE self, VALUE lineno)
@@ -686,7 +806,7 @@ strio_set_lineno(VALUE self, VALUE lineno)
* binmode -> self
*
* Sets the data mode in +self+ to binary mode;
- * see {Data Mode}[rdoc-ref:File@Data+Mode].
+ * see {Data Mode}[rdoc-ref:StringIO@Data+Mode].
*
*/
static VALUE
@@ -747,12 +867,12 @@ strio_reopen(int argc, VALUE *argv, VALUE self)
* pos -> stream_position
*
* Returns the current position (in bytes);
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:StringIO@Position].
*/
static VALUE
strio_get_pos(VALUE self)
{
- return LONG2NUM(StringIO(self)->pos);
+ return LONG2NUM(StringIOForRead(self)->pos);
}
/*
@@ -760,7 +880,7 @@ strio_get_pos(VALUE self)
* pos = new_position -> new_position
*
* Sets the current position (in bytes);
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:StringIO@Position].
*/
static VALUE
strio_set_pos(VALUE self, VALUE pos)
@@ -795,9 +915,9 @@ strio_rewind(VALUE self)
* call-seq:
* seek(offset, whence = SEEK_SET) -> 0
*
- * Sets the current position to the given integer +offset+ (in bytes),
+ * Sets the position to the given integer +offset+ (in bytes),
* with respect to a given constant +whence+;
- * see {Position}[rdoc-ref:IO@Position].
+ * see {IO#seek}[rdoc-ref:IO#seek].
*/
static VALUE
strio_seek(int argc, VALUE *argv, VALUE self)
@@ -819,7 +939,11 @@ strio_seek(int argc, VALUE *argv, VALUE self)
offset = ptr->pos;
break;
case 2:
- offset = RSTRING_LEN(ptr->string);
+ if (NIL_P(ptr->string)) {
+ offset = 0;
+ } else {
+ offset = RSTRING_LEN(ptr->string);
+ }
break;
default:
error_inval("invalid whence");
@@ -840,7 +964,7 @@ strio_seek(int argc, VALUE *argv, VALUE self)
static VALUE
strio_get_sync(VALUE self)
{
- StringIO(self);
+ StringIOForRead(self);
return Qtrue;
}
@@ -852,10 +976,9 @@ strio_get_sync(VALUE self)
* call-seq:
* each_byte {|byte| ... } -> self
*
- * With a block given, calls the block with each remaining byte in the stream;
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
+ * :include: stringio/each_byte.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_char, StringIO#each_codepoint, StringIO#each_line.
*/
static VALUE
strio_each_byte(VALUE self)
@@ -873,10 +996,10 @@ strio_each_byte(VALUE self)
/*
* call-seq:
- * getc -> character or nil
+ * getc -> character, byte, or nil
+ *
+ * :include: stringio/getc.rdoc
*
- * Reads and returns the next character from the stream;
- * see {Character IO}[rdoc-ref:IO@Character+IO].
*/
static VALUE
strio_getc(VALUE self)
@@ -888,7 +1011,7 @@ strio_getc(VALUE self)
int len;
char *p;
- if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
+ if (eos_p(ptr)) {
return Qnil;
}
p = RSTRING_PTR(str)+pos;
@@ -899,17 +1022,17 @@ strio_getc(VALUE self)
/*
* call-seq:
- * getbyte -> byte or nil
+ * getbyte -> integer or nil
+ *
+ * :include: stringio/getbyte.rdoc
*
- * Reads and returns the next 8-bit byte from the stream;
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
*/
static VALUE
strio_getbyte(VALUE self)
{
struct StringIO *ptr = readable(self);
int c;
- if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
+ if (eos_p(ptr)) {
return Qnil;
}
c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -1078,12 +1201,11 @@ strio_readbyte(VALUE self)
/*
* call-seq:
- * each_char {|c| ... } -> self
+ * each_char {|char| ... } -> self
*
- * With a block given, calls the block with each remaining character in the stream;
- * see {Character IO}[rdoc-ref:IO@Character+IO].
+ * :include: stringio/each_char.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_byte, StringIO#each_codepoint, StringIO#each_line.
*/
static VALUE
strio_each_char(VALUE self)
@@ -1102,10 +1224,9 @@ strio_each_char(VALUE self)
* call-seq:
* each_codepoint {|codepoint| ... } -> self
*
- * With a block given, calls the block with each remaining codepoint in the stream;
- * see {Codepoint IO}[rdoc-ref:IO@Codepoint+IO].
+ * :include: stringio/each_codepoint.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_byte, StringIO#each_char, StringIO#each_line.
*/
static VALUE
strio_each_codepoint(VALUE self)
@@ -1339,9 +1460,8 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
* gets(limit, chomp: false) -> string or nil
* gets(sep, limit, chomp: false) -> string or nil
*
- * Reads and returns a line from the stream;
- * assigns the return value to <tt>$_</tt>;
- * see {Line IO}[rdoc-ref:IO@Line+IO].
+ * :include: stringio/gets.rdoc
+ *
*/
static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
@@ -1378,15 +1498,15 @@ strio_readline(int argc, VALUE *argv, VALUE self)
}
/*
+ * :markup: markdown
+ *
* call-seq:
* each_line(sep = $/, chomp: false) {|line| ... } -> self
* each_line(limit, chomp: false) {|line| ... } -> self
* each_line(sep, limit, chomp: false) {|line| ... } -> self
*
- * Calls the block with each remaining line read from the stream;
- * does nothing if already at end-of-file;
- * returns +self+.
- * See {Line IO}[rdoc-ref:IO@Line+IO].
+ * :include: stringio/each_line.md
+ *
*/
static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
@@ -1527,9 +1647,10 @@ strio_write(VALUE self, VALUE str)
/*
* call-seq:
- * strio.putc(obj) -> obj
+ * putc(object) -> object
+ *
+ * :include: stringio/putc.rdoc
*
- * See IO#putc.
*/
static VALUE
strio_putc(VALUE self, VALUE ch)
@@ -1561,9 +1682,10 @@ strio_putc(VALUE self, VALUE ch)
/*
* call-seq:
- * strio.read([length [, outbuf]]) -> string, outbuf, or nil
+ * read(maxlen = nil, out_string = nil) → new_string, out_string, or nil
+ *
+ * :include: stringio/read.rdoc
*
- * See IO#read.
*/
static VALUE
strio_read(int argc, VALUE *argv, VALUE self)
@@ -1575,11 +1697,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
switch (argc) {
case 2:
- str = argv[1];
- if (!NIL_P(str)) {
- StringValue(str);
- rb_str_modify(str);
- }
+ str = strio_readbuf(ptr, argv[1]);
/* fall through */
case 1:
if (!NIL_P(argv[0])) {
@@ -1587,10 +1705,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
- if (len > 0 &&
- (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
+ if (eos_p(ptr)) {
if (!NIL_P(str)) rb_str_resize(str, 0);
- return Qnil;
+ return len > 0 ? Qnil : rb_str_new(0, 0);
}
binary = 1;
break;
@@ -1636,15 +1753,17 @@ strio_read(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * pread(maxlen, offset) -> string
- * pread(maxlen, offset, out_string) -> string
+ * pread(maxlen, offset, out_string = nil) -> new_string or out_string
+ *
+ * :include: stringio/pread.rdoc
*
- * See IO#pread.
*/
static VALUE
strio_pread(int argc, VALUE *argv, VALUE self)
{
VALUE rb_len, rb_offset, rb_buf;
+ struct StringIO *ptr = readable(self);
+
rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
long len = NUM2LONG(rb_len);
long offset = NUM2LONG(rb_offset);
@@ -1653,6 +1772,12 @@ strio_pread(int argc, VALUE *argv, VALUE self)
rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
}
+ if (offset < 0) {
+ rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
+ }
+
+ rb_buf = strio_readbuf(ptr, rb_buf);
+
if (len == 0) {
if (NIL_P(rb_buf)) {
return rb_str_new("", 0);
@@ -1660,13 +1785,7 @@ strio_pread(int argc, VALUE *argv, VALUE self)
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)) {
+ if (outside_p(ptr, offset)) {
rb_eof_error();
}
@@ -1756,15 +1875,15 @@ strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * strio.length -> integer
- * strio.size -> integer
+ * size -> integer
+ *
+ * :include: stringio/size.rdoc
*
- * Returns the size of the buffer string.
*/
static VALUE
strio_size(VALUE self)
{
- VALUE string = StringIO(self)->string;
+ VALUE string = StringIOForRead(self)->string;
if (NIL_P(string)) {
return INT2FIX(0);
}
@@ -1797,27 +1916,34 @@ strio_truncate(VALUE self, VALUE len)
}
/*
- * call-seq:
- * strio.external_encoding => encoding
+ * call-seq:
+ * external_encoding -> encoding or nil
+ *
+ * Returns an Encoding object that represents the encoding of the string;
+ * see {Encodings}[rdoc-ref:StringIO@Encodings]:
+ *
+ * strio = StringIO.new('foo')
+ * strio.external_encoding # => #<Encoding:UTF-8>
+ *
+ * Returns +nil+ if +self+ has no string and is in write mode:
+ *
+ * strio = StringIO.new(nil, 'w+')
+ * strio.external_encoding # => nil
*
- * Returns the Encoding object that represents the encoding of the file.
- * If the stream is write mode and no encoding is specified, returns
- * +nil+.
*/
static VALUE
strio_external_encoding(VALUE self)
{
- struct StringIO *ptr = StringIO(self);
+ struct StringIO *ptr = StringIOForRead(self);
return rb_enc_from_encoding(get_enc(ptr));
}
/*
* call-seq:
- * strio.internal_encoding => encoding
+ * internal_encoding -> nil
*
- * Returns the Encoding of the internal string if conversion is
- * specified. Otherwise returns +nil+.
+ * Returns +nil+; for compatibility with IO.
*/
static VALUE
@@ -1852,14 +1978,15 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
enc = rb_find_encoding(ext_enc);
if (!enc) {
rb_io_enc_t convconfig;
- int oflags, fmode;
+ int oflags;
+ rb_io_mode_t fmode;
VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
enc = convconfig.enc2;
}
}
ptr->enc = enc;
- if (!NIL_P(ptr->string) && WRITABLE(self)) {
+ if (!NIL_P(ptr->string) && WRITABLE(self) && !str_chilled_p(ptr->string)) {
rb_enc_associate(ptr->string, enc);
}
@@ -1885,16 +2012,9 @@ strio_set_encoding_by_bom(VALUE self)
}
/*
- * \IO streams for strings, with access similar to
- * {IO}[rdoc-ref:IO];
- * see {IO}[rdoc-ref:IO].
- *
- * === About the Examples
- *
- * Examples on this page assume that \StringIO has been required:
- *
- * require 'stringio'
+ * :markup: markdown
*
+ * :include: stringio/stringio.md
*/
void
Init_stringio(void)
@@ -1902,7 +2022,7 @@ Init_stringio(void)
#undef rb_intern
#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
+ rb_ext_ractor_safe(true);
#endif
VALUE StringIO = rb_define_class("StringIO", rb_cObject);
@@ -1994,7 +2114,9 @@ Init_stringio(void)
rb_define_method(StringIO, "set_encoding_by_bom", strio_set_encoding_by_bom, 0);
{
+ /* :stopdoc: */
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
+ /* :startdoc: */
rb_define_method(mReadable, "readchar", strio_readchar, 0);
rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
rb_define_method(mReadable, "readline", strio_readline, -1);
@@ -2004,7 +2126,9 @@ Init_stringio(void)
rb_include_module(StringIO, mReadable);
}
{
+ /* :stopdoc: */
VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
+ /* :startdoc: */
rb_define_method(mWritable, "<<", strio_addstr, 1);
rb_define_method(mWritable, "print", strio_print, -1);
rb_define_method(mWritable, "printf", strio_printf, -1);
diff --git a/ext/strscan/depend b/ext/strscan/depend
index 8dbae206d4..b40a025230 100644
--- a/ext/strscan/depend
+++ b/ext/strscan/depend
@@ -138,6 +138,7 @@ strscan.o: $(hdrdir)/ruby/internal/intern/re.h
strscan.o: $(hdrdir)/ruby/internal/intern/ruby.h
strscan.o: $(hdrdir)/ruby/internal/intern/select.h
strscan.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+strscan.o: $(hdrdir)/ruby/internal/intern/set.h
strscan.o: $(hdrdir)/ruby/internal/intern/signal.h
strscan.o: $(hdrdir)/ruby/internal/intern/sprintf.h
strscan.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb
index bd65606a4e..4e8d851fdb 100644
--- a/ext/strscan/extconf.rb
+++ b/ext/strscan/extconf.rb
@@ -2,8 +2,12 @@
require 'mkmf'
if RUBY_ENGINE == 'ruby'
$INCFLAGS << " -I$(top_srcdir)" if $extmk
- have_func("onig_region_memsize", "ruby.h")
- have_func("rb_reg_onig_match", "ruby.h")
+ have_func("onig_region_memsize(NULL)")
+ have_func("rb_reg_onig_match", "ruby/re.h")
+ have_func("rb_deprecate_constant")
+ have_func("rb_int_parse_cstr", "ruby.h") # RUBY_VERSION >= 2.5
+ have_func("rb_gc_location", "ruby.h") # RUBY_VERSION >= 2.7
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/strscan/lib/strscan.rb b/ext/strscan/lib/strscan.rb
new file mode 100644
index 0000000000..4e8910d141
--- /dev/null
+++ b/ext/strscan/lib/strscan.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+case RUBY_ENGINE
+when 'ruby'
+ require 'strscan.so'
+ require_relative 'strscan/strscan'
+when 'jruby'
+ require 'strscan.jar'
+ JRuby::Util.load_ext('org.jruby.ext.strscan.StringScannerLibrary')
+ require_relative 'strscan/strscan'
+when 'truffleruby'
+ if RUBY_ENGINE_VERSION.to_i >= 34
+ require 'strscan/truffleruby'
+ else
+ $LOAD_PATH.delete __dir__
+ require 'strscan'
+ end
+else
+ raise NotImplementedError, "Unknown Ruby: #{RUBY_ENGINE}"
+end
diff --git a/ext/strscan/lib/strscan/strscan.rb b/ext/strscan/lib/strscan/strscan.rb
index 46acc7ea82..5e262f4007 100644
--- a/ext/strscan/lib/strscan/strscan.rb
+++ b/ext/strscan/lib/strscan/strscan.rb
@@ -1,17 +1,47 @@
# frozen_string_literal: true
class StringScanner
+ unless method_defined?(:integer_at) # For JRuby
+ def integer_at(specifier, *to_i_args)
+ self[specifier]&.to_i(*to_i_args)
+ end
+ end
+
+ # :markup: markdown
+ #
# call-seq:
- # scan_integer(base: 10)
+ # scan_integer(base: 10) -> integer or nil
+ #
+ # Returns an integer scanned from `self`,
+ # beginning at the current position;
+ # returns `nil` if no such integer was available.
+ #
+ # When `base` is `10` (the default),
+ # equivalent to calling #scan with argument +pattern+
+ # as `'[+-]?\d+'`:
+ #
+ # ```ruby
+ # scanner = StringScanner.new('Form 27B/6')
+ # scanner.scan_integer # => nil # No integer at position 0.
+ # scanner.pos = 5
+ # scanner.scan_integer # => 27
+ # scanner.matched # => "27"
+ # scanner.pos # => 7
+ # ```
#
- # If `base` isn't provided or is `10`, then it is equivalent to calling `#scan` with a `[+-]?\d+` pattern,
- # and returns an Integer or nil.
+ # When `base` is `16` (the only other value allowed),
+ # equivalent to calling #scan with argument `pattern`
+ # as `'[+-]?(0x)?[0-9a-fA-F]+'`:
#
- # If `base` is `16`, then it is equivalent to calling `#scan` with a `[+-]?(0x)?[0-9a-fA-F]+` pattern,
- # and returns an Integer or nil.
+ # ```ruby
+ # scanner.pos = 5
+ # scanner.scan_integer(base: 16) # => 635
+ # scanner.matched # => "27B"
+ # scanner.pos # => 8
+ # ```
#
- # The scanned string must be encoded with an ASCII compatible encoding, otherwise
- # Encoding::CompatibilityError will be raised.
+ # Raises Encoding::CompatibilityError if `self` does not have
+ # an ASCII compatible encoding.
def scan_integer(base: 10)
case base
when 10
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index 2824eeb4d9..dede57218b 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -22,7 +22,15 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
-#define STRSCAN_VERSION "3.1.2"
+#define STRSCAN_VERSION "3.1.9.dev"
+
+
+#ifdef HAVE_RB_DEPRECATE_CONSTANT
+/* In ruby 3.0, defined but exposed in external headers */
+extern void rb_deprecate_constant(VALUE mod, const char *name);
+#else
+# define rb_deprecate_constant(mod, name) ((void)0)
+#endif
/* =======================================================================
Data Type Definitions
@@ -30,7 +38,6 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
static VALUE StringScanner;
static VALUE ScanError;
-static ID id_byteslice;
static int usascii_encindex, utf8_encindex, binary_encindex;
@@ -97,7 +104,6 @@ static VALUE strscan_init_copy _((VALUE vself, VALUE vorig));
static VALUE strscan_s_mustc _((VALUE self));
static VALUE strscan_terminate _((VALUE self));
-static VALUE strscan_clear _((VALUE self));
static VALUE strscan_get_string _((VALUE self));
static VALUE strscan_set_string _((VALUE self, VALUE str));
static VALUE strscan_concat _((VALUE self, VALUE str));
@@ -119,14 +125,11 @@ static VALUE strscan_search_full _((VALUE self, VALUE re,
static void adjust_registers_to_matched _((struct strscanner *p));
static VALUE strscan_getch _((VALUE self));
static VALUE strscan_get_byte _((VALUE self));
-static VALUE strscan_getbyte _((VALUE self));
static VALUE strscan_peek _((VALUE self, VALUE len));
-static VALUE strscan_peep _((VALUE self, VALUE len));
static VALUE strscan_scan_base10_integer _((VALUE self));
static VALUE strscan_unscan _((VALUE self));
static VALUE strscan_bol_p _((VALUE self));
static VALUE strscan_eos_p _((VALUE self));
-static VALUE strscan_empty_p _((VALUE self));
static VALUE strscan_rest_p _((VALUE self));
static VALUE strscan_matched_p _((VALUE self));
static VALUE strscan_matched _((VALUE self));
@@ -179,12 +182,35 @@ extract_beg_len(struct strscanner *p, long beg_i, long len)
Constructor
======================================================================= */
+#ifdef RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+#else
+# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
+# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
+# define HAVE_RUBY_TYPED_EMBEDDABLE 1
+# else
+# define RUBY_TYPED_EMBEDDABLE 0
+# endif
+#endif
+
+#ifdef HAVE_RB_GC_LOCATION
+static void
+strscan_compact(void *ptr)
+{
+ struct strscanner *p = ptr;
+ p->str = rb_gc_location(p->str);
+ p->regex = rb_gc_location(p->regex);
+}
+#else
+#define rb_gc_mark_movable rb_gc_mark
+#endif
+
static void
strscan_mark(void *ptr)
{
struct strscanner *p = ptr;
- rb_gc_mark(p->str);
- rb_gc_mark(p->regex);
+ rb_gc_mark_movable(p->str);
+ rb_gc_mark_movable(p->regex);
}
static void
@@ -192,24 +218,37 @@ strscan_free(void *ptr)
{
struct strscanner *p = ptr;
onig_region_free(&(p->regs), 0);
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
ruby_xfree(p);
+#endif
}
static size_t
strscan_memsize(const void *ptr)
{
- const struct strscanner *p = ptr;
- size_t size = sizeof(*p) - sizeof(p->regs);
+ size_t size = 0;
+#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
+ size += sizeof(struct strscanner);
+#endif
+
#ifdef HAVE_ONIG_REGION_MEMSIZE
- size += onig_region_memsize(&p->regs);
+ const struct strscanner *p = ptr;
+ size += onig_region_memsize(&p->regs) - sizeof(p->regs);
#endif
return size;
}
static const rb_data_type_t strscanner_type = {
- "StringScanner",
- {strscan_mark, strscan_free, strscan_memsize},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ .wrap_struct_name = "StringScanner",
+ .function = {
+ .dmark = strscan_mark,
+ .dfree = strscan_free,
+ .dsize = strscan_memsize,
+#ifdef HAVE_RB_GC_LOCATION
+ .dcompact = strscan_compact,
+#endif
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
static VALUE
@@ -273,7 +312,7 @@ strscan_initialize(int argc, VALUE *argv, VALUE self)
p->fixed_anchor_p = false;
}
StringValue(str);
- p->str = str;
+ RB_OBJ_WRITE(self, &p->str, str);
return self;
}
@@ -303,7 +342,7 @@ strscan_init_copy(VALUE vself, VALUE vorig)
orig = check_strscan(vorig);
if (self != orig) {
self->flags = orig->flags;
- self->str = orig->str;
+ RB_OBJ_WRITE(vself, &self->str, orig->str);
self->prev = orig->prev;
self->curr = orig->curr;
if (rb_reg_region_copy(&self->regs, &orig->regs))
@@ -371,6 +410,9 @@ strscan_reset(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * terminate -> self
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/terminate.md
*/
@@ -386,21 +428,6 @@ strscan_terminate(VALUE self)
}
/*
- * call-seq:
- * clear -> self
- *
- * This method is obsolete; use the equivalent method StringScanner#terminate.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_clear(VALUE self)
-{
- rb_warning("StringScanner#clear is obsolete; use #terminate instead");
- return strscan_terminate(self);
-}
-
-/*
* :markup: markdown
* :include: strscan/link_refs.txt
*
@@ -467,7 +494,7 @@ strscan_set_string(VALUE self, VALUE str)
struct strscanner *p = check_strscan(self);
StringValue(str);
- p->str = str;
+ RB_OBJ_WRITE(self, &p->str, str);
p->curr = 0;
CLEAR_MATCH_STATUS(p);
return str;
@@ -515,6 +542,9 @@ strscan_concat(VALUE self, VALUE str)
/*
* :markup: markdown
+ * :call-seq:
+ * pos -> byte_position
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/get_pos.md
*/
@@ -524,11 +554,14 @@ strscan_get_pos(VALUE self)
struct strscanner *p;
GET_SCANNER(self, p);
- return INT2FIX(p->curr);
+ return LONG2NUM(p->curr);
}
/*
* :markup: markdown
+ * :call-seq:
+ * charpos -> character_position
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/get_charpos.md
*/
@@ -544,6 +577,10 @@ strscan_get_charpos(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * pos = n -> n
+ * pointer = n -> n
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/set_pos.md
*/
@@ -554,7 +591,7 @@ strscan_set_pos(VALUE self, VALUE v)
long i;
GET_SCANNER(self, p);
- i = NUM2INT(v);
+ i = NUM2LONG(v);
if (i < 0) i += S_LEN(p);
if (i < 0) rb_raise(rb_eRangeError, "index out of range");
if (i > S_LEN(p)) rb_raise(rb_eRangeError, "index out of range");
@@ -712,7 +749,7 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
if (RB_TYPE_P(pattern, T_REGEXP)) {
OnigPosition ret;
- p->regex = pattern;
+ RB_OBJ_WRITE(self, &p->regex, pattern);
ret = rb_reg_onig_match(p->regex,
p->str,
headonly ? strscan_match : strscan_search,
@@ -768,6 +805,9 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
/*
* :markup: markdown
+ * :call-seq:
+ * scan(pattern) -> substring or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/scan.md
*/
@@ -782,7 +822,7 @@ strscan_scan(VALUE self, VALUE re)
* :include: strscan/link_refs.txt
*
* call-seq:
- * match?(pattern) -> updated_position or nil
+ * match?(pattern) -> match_size or nil
*
* Attempts to [match][17] the given `pattern`
* at the beginning of the [target substring][3];
@@ -841,6 +881,9 @@ strscan_match_p(VALUE self, VALUE re)
/*
* :markup: markdown
+ * call-seq:
+ * skip(pattern) -> match_size or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/skip.md
*/
@@ -913,7 +956,7 @@ strscan_check(VALUE self, VALUE re)
/*
* call-seq:
- * scan_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or nil
+ * scan_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or length or nil
*
* Equivalent to one of the following:
*
@@ -938,6 +981,9 @@ strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f)
/*
* :markup: markdown
+ * :call-seq:
+ * scan_until(pattern) -> substring or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/scan_until.md
*/
@@ -1012,6 +1058,9 @@ strscan_exist_p(VALUE self, VALUE re)
/*
* :markup: markdown
+ * :call-seq:
+ * skip_until(pattern) -> matched_substring_size or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/skip_until.md
*/
@@ -1123,6 +1172,9 @@ adjust_registers_to_matched(struct strscanner *p)
/*
* :markup: markdown
+ * :call-seq:
+ * getch -> character or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/getch.md
*/
@@ -1150,7 +1202,7 @@ strscan_getch(VALUE self)
/*
* call-seq:
- * scan_byte -> integer_byte
+ * scan_byte -> integer_byte or nil
*
* Scans one byte and returns it as an integer.
* This method is not multibyte character sensitive.
@@ -1196,6 +1248,9 @@ strscan_peek_byte(VALUE self)
/*
* :markup: markdown
+ * :call-seq:
+ * get_byte -> byte_as_character or nil
+ *
* :include: strscan/link_refs.txt
* :include: strscan/methods/get_byte.md
*/
@@ -1219,22 +1274,6 @@ strscan_get_byte(VALUE self)
}
/*
- * call-seq:
- * getbyte
- *
- * Equivalent to #get_byte.
- * This method is obsolete; use #get_byte instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_getbyte(VALUE self)
-{
- rb_warning("StringScanner#getbyte is obsolete; use #get_byte instead");
- return strscan_get_byte(self);
-}
-
-/*
* :markup: markdown
* :include: strscan/link_refs.txt
*
@@ -1269,22 +1308,6 @@ strscan_peek(VALUE self, VALUE vlen)
return extract_beg_len(p, p->curr, len);
}
-/*
- * call-seq:
- * peep
- *
- * Equivalent to #peek.
- * This method is obsolete; use #peek instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_peep(VALUE self, VALUE vlen)
-{
- rb_warning("StringScanner#peep is obsolete; use #peek instead");
- return strscan_peek(self, vlen);
-}
-
static VALUE
strscan_parse_integer(struct strscanner *p, int base, long len)
{
@@ -1305,16 +1328,17 @@ strscan_parse_integer(struct strscanner *p, int base, long len)
}
static inline bool
-strscan_ascii_compat_fastpath(VALUE str) {
+strscan_ascii_compat_fastpath(VALUE str)
+{
int encindex = ENCODING_GET_INLINED(str);
- // The overwhelming majority of strings are in one of these 3 encodings.
+ /* The overwhelming majority of strings are in one of these 3 encodings. */
return encindex == utf8_encindex || encindex == binary_encindex || encindex == usascii_encindex;
}
static inline void
strscan_must_ascii_compat(VALUE str)
{
- // The overwhelming majority of strings are in one of these 3 encodings.
+ /* The overwhelming majority of strings are in one of these 3 encodings. */
if (RB_LIKELY(strscan_ascii_compat_fastpath(str))) {
return;
}
@@ -1322,11 +1346,12 @@ strscan_must_ascii_compat(VALUE str)
rb_must_asciicompat(str);
}
+/* :nodoc: */
static VALUE
strscan_scan_base10_integer(VALUE self)
{
char *ptr;
- long len = 0;
+ long len = 0, remaining_len;
struct strscanner *p;
GET_SCANNER(self, p);
@@ -1336,7 +1361,7 @@ strscan_scan_base10_integer(VALUE self)
ptr = CURPTR(p);
- long remaining_len = S_RESTLEN(p);
+ remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
@@ -1359,11 +1384,12 @@ strscan_scan_base10_integer(VALUE self)
return strscan_parse_integer(p, 10, len);
}
+/* :nodoc: */
static VALUE
strscan_scan_base16_integer(VALUE self)
{
char *ptr;
- long len = 0;
+ long len = 0, remaining_len;
struct strscanner *p;
GET_SCANNER(self, p);
@@ -1373,7 +1399,7 @@ strscan_scan_base16_integer(VALUE self)
ptr = CURPTR(p);
- long remaining_len = S_RESTLEN(p);
+ remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
@@ -1526,26 +1552,9 @@ strscan_eos_p(VALUE self)
/*
* call-seq:
- * empty?
- *
- * Equivalent to #eos?.
- * This method is obsolete, use #eos? instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_empty_p(VALUE self)
-{
- rb_warning("StringScanner#empty? is obsolete; use #eos? instead");
- return strscan_eos_p(self);
-}
-
-/*
- * call-seq:
* rest?
*
* Returns true if and only if there is more data in the string. See #eos?.
- * This method is obsolete; use #eos? instead.
*
* s = StringScanner.new('test string')
* # These two are opposites
@@ -1673,7 +1682,7 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
(const unsigned char* )name_end,
regs);
if (num >= 1) {
- return num;
+ return num;
}
}
rb_enc_raise(enc, rb_eIndexError, "undefined group name reference: %.*s",
@@ -1681,6 +1690,38 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
}
/*
+ * Resolve capture group index from Integer, Symbol, or String.
+ * Returns the resolved register index, or -1 if unmatched/out of range.
+ * For Symbol/String specifiers, raises IndexError if the named group
+ * does not exist.
+ */
+static long
+resolve_capture_index(struct strscanner *p, VALUE specifier)
+{
+ const char *name;
+ long i;
+ if (! MATCHED_P(p)) return -1;
+ switch (TYPE(specifier)) {
+ case T_SYMBOL:
+ specifier = rb_sym2str(specifier);
+ /* fall through */
+ case T_STRING:
+ RSTRING_GETMEM(specifier, name, i);
+ i = name_to_backref_number(&(p->regs), p->regex, name, name + i,
+ rb_enc_get(specifier));
+ break;
+ default:
+ i = NUM2LONG(specifier);
+ }
+ if (i < 0)
+ i += p->regs.num_regs;
+ if (i < 0) return -1;
+ if (i >= p->regs.num_regs) return -1;
+ if (p->regs.beg[i] == -1) return -1;
+ return i;
+}
+
+/*
*
* :markup: markdown
* :include: strscan/link_refs.txt
@@ -1754,30 +1795,12 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
static VALUE
strscan_aref(VALUE self, VALUE idx)
{
- const char *name;
struct strscanner *p;
long i;
GET_SCANNER(self, p);
- if (! MATCHED_P(p)) return Qnil;
-
- switch (TYPE(idx)) {
- case T_SYMBOL:
- idx = rb_sym2str(idx);
- /* fall through */
- case T_STRING:
- RSTRING_GETMEM(idx, name, i);
- i = name_to_backref_number(&(p->regs), p->regex, name, name + i, rb_enc_get(idx));
- break;
- default:
- i = NUM2LONG(idx);
- }
-
- if (i < 0)
- i += p->regs.num_regs;
- if (i < 0) return Qnil;
- if (i >= p->regs.num_regs) return Qnil;
- if (p->regs.beg[i] == -1) return Qnil;
+ i = resolve_capture_index(p, idx);
+ if (i < 0) return Qnil;
return extract_range(p,
adjust_register_position(p, p->regs.beg[i]),
@@ -1786,6 +1809,81 @@ strscan_aref(VALUE self, VALUE idx)
/*
* :markup: markdown
+ *
+ * call-seq:
+ * integer_at(specifier, base=10) -> integer or nil
+ *
+ * Returns the captured substring at the given `specifier` as an Integer,
+ * following the behavior of `String#to_i(base)`.
+ *
+ * `specifier` can be an Integer (positive, negative, or zero), a Symbol,
+ * or a String for named capture groups.
+ *
+ * Returns `nil` if:
+ * - No match has been performed or the last match failed
+ * - The `specifier` is an Integer and is out of range
+ * - The group at `specifier` did not participate in the match
+ *
+ * Raises IndexError if `specifier` is a Symbol or String that does not
+ * correspond to a named capture group, consistent with
+ * `StringScanner#[]`.
+ *
+ * This is semantically equivalent to `self[specifier]&.to_i(base)`
+ * but avoids the allocation of a temporary String when possible.
+ *
+ * ```rb
+ * scanner = StringScanner.new("2024-06-15")
+ * scanner.scan(/(\d{4})-(\d{2})-(\d{2})/)
+ * scanner.integer_at(1) # => 2024
+ * scanner.integer_at(1, 16) # => 8228
+ * ```
+ */
+static VALUE
+strscan_integer_at(int argc, VALUE *argv, VALUE self)
+{
+ struct strscanner *p;
+ long i;
+ long beg, end, len;
+ const char *ptr;
+ VALUE rb_specifier;
+ VALUE rb_base;
+ int base = 10;
+
+ GET_SCANNER(self, p);
+ rb_scan_args(argc, argv, "11", &rb_specifier, &rb_base);
+ if (argc > 1)
+ base = NUM2INT(rb_base);
+ i = resolve_capture_index(p, rb_specifier);
+ if (i < 0)
+ return Qnil;
+
+ beg = adjust_register_position(p, p->regs.beg[i]);
+ end = adjust_register_position(p, p->regs.end[i]);
+ len = end - beg;
+ ptr = S_PBEG(p) + beg;
+#ifdef HAVE_RB_INT_PARSE_CSTR
+ {
+ /*
+ * Ruby 2.5 or later export the rb_int_parse_cstr() symbol but
+ * prototype definition isn't provided. Ruby 4.1 or later
+ * provide prototype definition.
+ */
+# ifndef RB_INT_PARSE_DEFAULT
+ VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp,
+ size_t *ndigits, int base, int flags);
+# define RB_INT_PARSE_DEFAULT 0x07
+# endif
+ char *endp;
+ return rb_int_parse_cstr(ptr, len, &endp, NULL, base,
+ RB_INT_PARSE_DEFAULT);
+ }
+#else
+ return rb_str_to_inum(rb_str_new(ptr, len), base, 0);
+#endif
+}
+
+/*
+ * :markup: markdown
* :include: strscan/link_refs.txt
*
* call-seq:
@@ -2053,22 +2151,6 @@ strscan_rest_size(VALUE self)
return INT2FIX(i);
}
-/*
- * call-seq:
- * restsize
- *
- * <tt>s.restsize</tt> is equivalent to <tt>s.rest_size</tt>.
- * This method is obsolete; use #rest_size instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_restsize(VALUE self)
-{
- rb_warning("StringScanner#restsize is obsolete; use #rest_size instead");
- return strscan_rest_size(self);
-}
-
#define INSPECT_LENGTH 5
/*
@@ -2211,7 +2293,10 @@ named_captures_iter(const OnigUChar *name,
VALUE value = RUBY_Qnil;
int i;
for (i = 0; i < back_num; i++) {
- value = strscan_aref(data->self, INT2NUM(back_refs[i]));
+ VALUE v = strscan_aref(data->self, INT2NUM(back_refs[i]));
+ if (!RB_NIL_P(v)) {
+ value = v;
+ }
}
rb_hash_aset(data->captures, key, value);
return 0;
@@ -2224,8 +2309,8 @@ named_captures_iter(const OnigUChar *name,
* call-seq:
* named_captures -> hash
*
- * Returns the array of captured match values at indexes (1..)
- * if the most recent match attempt succeeded, or nil otherwise;
+ * Returns a hash of named captures for the most recent regexp match,
+ * or an empty hash if there are no named captures;
* see [Captured Match Values][13]:
*
* ```rb
@@ -2265,6 +2350,13 @@ strscan_named_captures(VALUE self)
======================================================================= */
/*
+ * Document-class: StringScanner::Error
+ *
+ * The error class for StringScanner.
+ * See StringScanner#unscan.
+ */
+
+/*
* Document-class: StringScanner
*
* :markup: markdown
@@ -2284,8 +2376,6 @@ Init_strscan(void)
ID id_scanerr = rb_intern("ScanError");
VALUE tmp;
- id_byteslice = rb_intern("byteslice");
-
usascii_encindex = rb_usascii_encindex();
utf8_encindex = rb_utf8_encindex();
binary_encindex = rb_ascii8bit_encindex();
@@ -2294,6 +2384,7 @@ Init_strscan(void)
ScanError = rb_define_class_under(StringScanner, "Error", rb_eStandardError);
if (!rb_const_defined(rb_cObject, id_scanerr)) {
rb_const_set(rb_cObject, id_scanerr, ScanError);
+ rb_deprecate_constant(rb_cObject, "ScanError");
}
tmp = rb_str_new2(STRSCAN_VERSION);
rb_obj_freeze(tmp);
@@ -2301,6 +2392,7 @@ Init_strscan(void)
tmp = rb_str_new2("$Id$");
rb_obj_freeze(tmp);
rb_const_set(StringScanner, rb_intern("Id"), tmp);
+ rb_deprecate_constant(StringScanner, "Id");
rb_define_alloc_func(StringScanner, strscan_s_allocate);
rb_define_private_method(StringScanner, "initialize", strscan_initialize, -1);
@@ -2308,7 +2400,6 @@ Init_strscan(void)
rb_define_singleton_method(StringScanner, "must_C_version", strscan_s_mustc, 0);
rb_define_method(StringScanner, "reset", strscan_reset, 0);
rb_define_method(StringScanner, "terminate", strscan_terminate, 0);
- rb_define_method(StringScanner, "clear", strscan_clear, 0);
rb_define_method(StringScanner, "string", strscan_get_string, 0);
rb_define_method(StringScanner, "string=", strscan_set_string, 1);
rb_define_method(StringScanner, "concat", strscan_concat, 1);
@@ -2333,11 +2424,9 @@ Init_strscan(void)
rb_define_method(StringScanner, "getch", strscan_getch, 0);
rb_define_method(StringScanner, "get_byte", strscan_get_byte, 0);
- rb_define_method(StringScanner, "getbyte", strscan_getbyte, 0);
rb_define_method(StringScanner, "scan_byte", strscan_scan_byte, 0);
rb_define_method(StringScanner, "peek", strscan_peek, 1);
rb_define_method(StringScanner, "peek_byte", strscan_peek_byte, 0);
- rb_define_method(StringScanner, "peep", strscan_peep, 1);
rb_define_private_method(StringScanner, "scan_base10_integer", strscan_scan_base10_integer, 0);
rb_define_private_method(StringScanner, "scan_base16_integer", strscan_scan_base16_integer, 0);
@@ -2347,13 +2436,13 @@ Init_strscan(void)
rb_define_method(StringScanner, "beginning_of_line?", strscan_bol_p, 0);
rb_alias(StringScanner, rb_intern("bol?"), rb_intern("beginning_of_line?"));
rb_define_method(StringScanner, "eos?", strscan_eos_p, 0);
- rb_define_method(StringScanner, "empty?", strscan_empty_p, 0);
rb_define_method(StringScanner, "rest?", strscan_rest_p, 0);
rb_define_method(StringScanner, "matched?", strscan_matched_p, 0);
rb_define_method(StringScanner, "matched", strscan_matched, 0);
rb_define_method(StringScanner, "matched_size", strscan_matched_size, 0);
rb_define_method(StringScanner, "[]", strscan_aref, 1);
+ rb_define_method(StringScanner, "integer_at", strscan_integer_at, -1);
rb_define_method(StringScanner, "pre_match", strscan_pre_match, 0);
rb_define_method(StringScanner, "post_match", strscan_post_match, 0);
rb_define_method(StringScanner, "size", strscan_size, 0);
@@ -2362,13 +2451,10 @@ Init_strscan(void)
rb_define_method(StringScanner, "rest", strscan_rest, 0);
rb_define_method(StringScanner, "rest_size", strscan_rest_size, 0);
- rb_define_method(StringScanner, "restsize", strscan_restsize, 0);
rb_define_method(StringScanner, "inspect", strscan_inspect, 0);
rb_define_method(StringScanner, "fixed_anchor?", strscan_fixed_anchor_p, 0);
rb_define_method(StringScanner, "named_captures", strscan_named_captures, 0);
-
- rb_require("strscan/strscan");
}
diff --git a/ext/strscan/strscan.gemspec b/ext/strscan/strscan.gemspec
index 47180bb8d8..a51285fa7e 100644
--- a/ext/strscan/strscan.gemspec
+++ b/ext/strscan/strscan.gemspec
@@ -16,18 +16,18 @@ Gem::Specification.new do |s|
s.summary = "Provides lexical scanning operations on a String."
s.description = "Provides lexical scanning operations on a String."
- files = [
- "COPYING",
- "LICENSE.txt",
- "lib/strscan/strscan.rb"
+ files = %w[
+ COPYING
+ LICENSE.txt
+ lib/strscan.rb
+ lib/strscan/strscan.rb
+ lib/strscan/truffleruby.rb
]
s.require_paths = %w{lib}
if RUBY_ENGINE == "jruby"
files << "lib/strscan.jar"
- files << "ext/jruby/lib/strscan.rb"
- s.require_paths += %w{ext/jruby/lib}
s.platform = "java"
else
files << "ext/strscan/extconf.rb"
diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb
deleted file mode 100644
index d0cbb6afcf..0000000000
--- a/ext/win32/lib/win32/registry.rb
+++ /dev/null
@@ -1,925 +0,0 @@
-# frozen_string_literal: true
-require 'fiddle/import'
-
-module Win32
-
-=begin rdoc
-= Win32 Registry
-
-win32/registry is registry accessor library for Win32 platform.
-It uses importer to call Win32 Registry APIs.
-
-== example
- Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\foo') do |reg|
- value = reg['foo'] # read a value
- value = reg['foo', Win32::Registry::REG_SZ] # read a value with type
- type, value = reg.read('foo') # read a value
- reg['foo'] = 'bar' # write a value
- reg['foo', Win32::Registry::REG_SZ] = 'bar' # write a value with type
- reg.write('foo', Win32::Registry::REG_SZ, 'bar') # write a value
-
- reg.each_value { |name, type, data| ... } # Enumerate values
- reg.each_key { |key, wtime| ... } # Enumerate subkeys
-
- reg.delete_value(name) # Delete a value
- reg.delete_key(name) # Delete a subkey
- reg.delete_key(name, true) # Delete a subkey recursively
- end
-
-= Reference
-
-== Win32::Registry class
-
---- info
-
---- num_keys
-
---- max_key_length
-
---- num_values
-
---- max_value_name_length
-
---- max_value_length
-
---- descriptor_length
-
---- wtime
- Returns an item of key information.
-
-=== constants
---- HKEY_CLASSES_ROOT
-
---- HKEY_CURRENT_USER
-
---- HKEY_LOCAL_MACHINE
-
---- HKEY_PERFORMANCE_DATA
-
---- HKEY_CURRENT_CONFIG
-
---- HKEY_DYN_DATA
-
- Win32::Registry object whose key is predefined key.
-For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/predefined_keys.asp] article.
-
-=end rdoc
-
- WCHAR = Encoding::UTF_16LE
- WCHAR_NUL = "\0".encode(WCHAR).freeze
- WCHAR_CR = "\r".encode(WCHAR).freeze
- WCHAR_SIZE = WCHAR_NUL.bytesize
- LOCALE = Encoding::UTF_8
-
- class Registry
-
- #
- # For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/registry.asp].
- #
- # --- HKEY_*
- #
- # Predefined key ((*handle*)).
- # These are Integer, not Win32::Registry.
- #
- # --- REG_*
- #
- # Registry value type.
- #
- # --- KEY_*
- #
- # Security access mask.
- #
- # --- KEY_OPTIONS_*
- #
- # Key options.
- #
- # --- REG_CREATED_NEW_KEY
- #
- # --- REG_OPENED_EXISTING_KEY
- #
- # If the key is created newly or opened existing key.
- # See also Registry#disposition method.
- module Constants
- HKEY_CLASSES_ROOT = 0x80000000
- HKEY_CURRENT_USER = 0x80000001
- HKEY_LOCAL_MACHINE = 0x80000002
- HKEY_USERS = 0x80000003
- HKEY_PERFORMANCE_DATA = 0x80000004
- HKEY_PERFORMANCE_TEXT = 0x80000050
- HKEY_PERFORMANCE_NLSTEXT = 0x80000060
- HKEY_CURRENT_CONFIG = 0x80000005
- HKEY_DYN_DATA = 0x80000006
-
- REG_NONE = 0
- REG_SZ = 1
- REG_EXPAND_SZ = 2
- REG_BINARY = 3
- REG_DWORD = 4
- REG_DWORD_LITTLE_ENDIAN = 4
- REG_DWORD_BIG_ENDIAN = 5
- REG_LINK = 6
- REG_MULTI_SZ = 7
- REG_RESOURCE_LIST = 8
- REG_FULL_RESOURCE_DESCRIPTOR = 9
- REG_RESOURCE_REQUIREMENTS_LIST = 10
- REG_QWORD = 11
- REG_QWORD_LITTLE_ENDIAN = 11
-
- STANDARD_RIGHTS_READ = 0x00020000
- STANDARD_RIGHTS_WRITE = 0x00020000
- KEY_QUERY_VALUE = 0x0001
- KEY_SET_VALUE = 0x0002
- KEY_CREATE_SUB_KEY = 0x0004
- KEY_ENUMERATE_SUB_KEYS = 0x0008
- KEY_NOTIFY = 0x0010
- KEY_CREATE_LINK = 0x0020
- KEY_READ = STANDARD_RIGHTS_READ |
- KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY
- KEY_WRITE = STANDARD_RIGHTS_WRITE |
- KEY_SET_VALUE | KEY_CREATE_SUB_KEY
- KEY_EXECUTE = KEY_READ
- KEY_ALL_ACCESS = KEY_READ | KEY_WRITE | KEY_CREATE_LINK
-
- REG_OPTION_RESERVED = 0x0000
- REG_OPTION_NON_VOLATILE = 0x0000
- REG_OPTION_VOLATILE = 0x0001
- REG_OPTION_CREATE_LINK = 0x0002
- REG_OPTION_BACKUP_RESTORE = 0x0004
- REG_OPTION_OPEN_LINK = 0x0008
- REG_LEGAL_OPTION = REG_OPTION_RESERVED |
- REG_OPTION_NON_VOLATILE | REG_OPTION_CREATE_LINK |
- REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK
-
- REG_CREATED_NEW_KEY = 1
- REG_OPENED_EXISTING_KEY = 2
-
- REG_WHOLE_HIVE_VOLATILE = 0x0001
- REG_REFRESH_HIVE = 0x0002
- REG_NO_LAZY_FLUSH = 0x0004
- REG_FORCE_RESTORE = 0x0008
-
- MAX_KEY_LENGTH = 514
- MAX_VALUE_LENGTH = 32768
- end
- include Constants
- include Enumerable
-
- #
- # Error
- #
- class Error < ::StandardError
- module Kernel32
- extend Fiddle::Importer
- dlload "kernel32.dll"
- end
- FormatMessageW = Kernel32.extern "int FormatMessageW(int, void *, int, int, void *, int, void *)", :stdcall
- def initialize(code)
- @code = code
- buff = WCHAR_NUL * 1024
- lang = 0
- begin
- len = FormatMessageW.call(0x1200, nil, code, lang, buff, 1024, nil)
- msg = buff.byteslice(0, len * WCHAR_SIZE)
- msg.delete!(WCHAR_CR)
- msg.chomp!
- msg.encode!(LOCALE)
- rescue EncodingError
- raise unless lang == 0
- lang = 0x0409 # en_US
- retry
- end
- super msg
- end
- attr_reader :code
- end
-
- #
- # Predefined Keys
- #
- class PredefinedKey < Registry
- def initialize(hkey, keyname)
- @hkey = Fiddle::Pointer.new(hkey)
- @parent = nil
- @keyname = keyname
- @disposition = REG_OPENED_EXISTING_KEY
- end
-
- # Predefined keys cannot be closed
- def close
- raise Error.new(5) ## ERROR_ACCESS_DENIED
- end
-
- # Fake #class method for Registry#open, Registry#create
- def class
- Registry
- end
-
- # Make all
- Constants.constants.grep(/^HKEY_/) do |c|
- Registry.const_set c, new(Constants.const_get(c), c.to_s)
- end
- end
-
- #
- # Win32 APIs
- #
- module API
- include Constants
- extend Fiddle::Importer
- dlload "advapi32.dll"
- [
- "long RegOpenKeyExW(void *, void *, long, long, void *)",
- "long RegCreateKeyExW(void *, void *, long, long, long, long, void *, void *, void *)",
- "long RegEnumValueW(void *, long, void *, void *, void *, void *, void *, void *)",
- "long RegEnumKeyExW(void *, long, void *, void *, void *, void *, void *, void *)",
- "long RegQueryValueExW(void *, void *, void *, void *, void *, void *)",
- "long RegSetValueExW(void *, void *, long, long, void *, long)",
- "long RegDeleteValueW(void *, void *)",
- "long RegDeleteKeyW(void *, void *)",
- "long RegFlushKey(void *)",
- "long RegCloseKey(void *)",
- "long RegQueryInfoKeyW(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *)",
- ].each do |fn|
- cfunc = extern fn, :stdcall
- const_set cfunc.name.intern, cfunc
- end
-
- module_function
-
- def check(result)
- raise Error, result, caller(1) if result != 0
- end
-
- def win64?
- /^(?:x64|x86_64)/ =~ RUBY_PLATFORM
- end
-
- TEMPLATE_HANDLE = 'J<'
-
- def packhandle(h)
- [h].pack(TEMPLATE_HANDLE)
- end
-
- def unpackhandle(h)
- (h + [0].pack(TEMPLATE_HANDLE)).unpack1(TEMPLATE_HANDLE)
- end
-
- TEMPLATE_DWORD = 'V'
-
- def packdw(dw)
- [dw].pack(TEMPLATE_DWORD)
- end
-
- def unpackdw(dw)
- (dw + [0].pack(TEMPLATE_DWORD)).unpack1(TEMPLATE_DWORD)
- end
-
- TEMPLATE_QWORD = 'Q<'
-
- def packqw(qw)
- [qw].pack(TEMPLATE_QWORD)
- end
-
- def unpackqw(qw)
- (qw + [0].pack(TEMPLATE_QWORD)).unpack1(TEMPLATE_QWORD)
- end
-
- def make_wstr(str)
- (str+"\0").encode(WCHAR)
- end
-
- def OpenKey(hkey, name, opt, desired)
- result = packhandle(0)
- check RegOpenKeyExW.call(hkey, make_wstr(name), opt, desired, result)
- unpackhandle(result)
- end
-
- def CreateKey(hkey, name, opt, desired)
- result = packhandle(0)
- disp = packdw(0)
- check RegCreateKeyExW.call(hkey, make_wstr(name), 0, 0, opt, desired,
- nil, result, disp)
- [ unpackhandle(result), unpackdw(disp) ]
- end
-
- def EnumValue(hkey, index)
- name = WCHAR_NUL * Constants::MAX_KEY_LENGTH
- size = packdw(Constants::MAX_KEY_LENGTH)
- check RegEnumValueW.call(hkey, index, name, size, nil, nil, nil, nil)
- name.byteslice(0, unpackdw(size) * WCHAR_SIZE)
- end
-
- def EnumKey(hkey, index)
- name = WCHAR_NUL * Constants::MAX_KEY_LENGTH
- size = packdw(Constants::MAX_KEY_LENGTH)
- wtime = ' ' * 8
- check RegEnumKeyExW.call(hkey, index, name, size, nil, nil, nil, wtime)
- [ name.byteslice(0, unpackdw(size) * WCHAR_SIZE), unpackqw(wtime) ]
- end
-
- def QueryValue(hkey, name)
- type = packdw(0)
- size = packdw(0)
- name = make_wstr(name)
- check RegQueryValueExW.call(hkey, name, nil, type, nil, size)
- data = "\0".b * unpackdw(size)
- check RegQueryValueExW.call(hkey, name, nil, type, data, size)
- [ unpackdw(type), data[0, unpackdw(size)] ]
- end
-
- def SetValue(hkey, name, type, data, size)
- case type
- when REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
- data = data.encode(WCHAR)
- size ||= data.bytesize + WCHAR_SIZE
- end
- check RegSetValueExW.call(hkey, make_wstr(name), 0, type, data, size)
- end
-
- def DeleteValue(hkey, name)
- check RegDeleteValueW.call(hkey, make_wstr(name))
- end
-
- def DeleteKey(hkey, name)
- check RegDeleteKeyW.call(hkey, make_wstr(name))
- end
-
- def FlushKey(hkey)
- check RegFlushKey.call(hkey)
- end
-
- def CloseKey(hkey)
- check RegCloseKey.call(hkey)
- end
-
- def QueryInfoKey(hkey)
- subkeys = packdw(0)
- maxsubkeylen = packdw(0)
- values = packdw(0)
- maxvaluenamelen = packdw(0)
- maxvaluelen = packdw(0)
- secdescs = packdw(0)
- wtime = ' ' * 8
- check RegQueryInfoKeyW.call(hkey, 0, 0, 0, subkeys, maxsubkeylen, 0,
- values, maxvaluenamelen, maxvaluelen, secdescs, wtime)
- [ unpackdw(subkeys), unpackdw(maxsubkeylen), unpackdw(values),
- unpackdw(maxvaluenamelen), unpackdw(maxvaluelen),
- unpackdw(secdescs), unpackqw(wtime) ]
- end
- end
-
- #
- # Replace %\w+% into the environment value of what is contained between the %'s
- # This method is used for REG_EXPAND_SZ.
- #
- # For detail, see expandEnvironmentStrings[http://msdn.microsoft.com/library/en-us/sysinfo/base/expandenvironmentstrings.asp] \Win32 \API.
- #
- def self.expand_environ(str)
- str.gsub(Regexp.compile("%([^%]+)%".encode(str.encoding))) {
- v = $1.encode(LOCALE)
- (ENV[v] || ENV[v.upcase])&.encode(str.encoding) || $&
- }
- end
-
- @@type2name = %w[
- REG_NONE REG_SZ REG_EXPAND_SZ REG_BINARY REG_DWORD
- REG_DWORD_BIG_ENDIAN REG_LINK REG_MULTI_SZ
- REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
- REG_RESOURCE_REQUIREMENTS_LIST REG_QWORD
- ].inject([]) do |ary, type|
- ary[Constants.const_get(type)] = type
- ary
- end.freeze
-
- #
- # Convert registry type value to readable string.
- #
- def self.type2name(type)
- @@type2name[type] || type.to_s
- end
-
- #
- # Convert 64-bit FILETIME integer into Time object.
- #
- def self.wtime2time(wtime)
- Time.at((wtime - 116444736000000000) / 10000000)
- end
-
- #
- # Convert Time object or Integer object into 64-bit FILETIME.
- #
- def self.time2wtime(time)
- time.to_i * 10000000 + 116444736000000000
- end
-
- #
- # constructor
- #
- private_class_method :new
-
- #
- # --- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
- #
- # --- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED) { |reg| ... }
- #
- # Open the registry key subkey under key.
- # key is Win32::Registry object of parent key.
- # You can use predefined key HKEY_* (see Constants)
- # desired and opt is access mask and key option.
- # For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/regopenkeyex.asp].
- # If block is given, the key is closed automatically.
- def self.open(hkey, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
- subkey = subkey.chomp('\\')
- newkey = API.OpenKey(hkey.instance_variable_get(:@hkey), subkey, opt, desired)
- obj = new(newkey, hkey, subkey, REG_OPENED_EXISTING_KEY)
- if block_given?
- begin
- yield obj
- ensure
- obj.close
- end
- else
- obj
- end
- end
-
- #
- # --- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
- #
- # --- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED) { |reg| ... }
- #
- # Create or open the registry key subkey under key.
- # You can use predefined key HKEY_* (see Constants)
- #
- # If subkey is already exists, key is opened and Registry#created?
- # method will return false.
- #
- # If block is given, the key is closed automatically.
- #
- def self.create(hkey, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
- newkey, disp = API.CreateKey(hkey.instance_variable_get(:@hkey), subkey, opt, desired)
- obj = new(newkey, hkey, subkey, disp)
- if block_given?
- begin
- yield obj
- ensure
- obj.close
- end
- else
- obj
- end
- end
-
- #
- # finalizer
- #
- @@final = proc { |hkey| proc { API.CloseKey(hkey[0]) if hkey[0] } }
-
- #
- # initialize
- #
- def initialize(hkey, parent, keyname, disposition)
- @hkey = Fiddle::Pointer.new(hkey)
- @parent = parent
- @keyname = keyname
- @disposition = disposition
- @hkeyfinal = [ hkey ]
- ObjectSpace.define_finalizer self, @@final.call(@hkeyfinal)
- end
-
- # Win32::Registry object of parent key, or nil if predefeined key.
- attr_reader :parent
- # Same as subkey value of Registry.open or
- # Registry.create method.
- attr_reader :keyname
- # Disposition value (REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY).
- attr_reader :disposition
-
- # Returns key handle value.
- def hkey
- @hkey.to_i
- end
-
- #
- # Returns if key is created ((*newly*)).
- # (see Registry.create) -- basically you call create
- # then when you call created? on the instance returned
- # it will tell if it was successful or not
- #
- def created?
- @disposition == REG_CREATED_NEW_KEY
- end
-
- #
- # Returns if key is not closed.
- #
- def open?
- !@hkey.nil?
- end
-
- #
- # Full path of key such as 'HKEY_CURRENT_USER\SOFTWARE\foo\bar'.
- #
- def name
- parent = self
- name = @keyname
- while parent = parent.parent
- name = parent.keyname + '\\' + name
- end
- name
- end
-
- def inspect
- "\#<Win32::Registry key=#{name.inspect}>"
- end
-
- #
- # marshalling is not allowed
- #
- def _dump(depth)
- raise TypeError, "can't dump Win32::Registry"
- end
-
- #
- # Same as Win32::Registry.open (self, subkey, desired, opt)
- #
- def open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED, &blk)
- self.class.open(self, subkey, desired, opt, &blk)
- end
-
- #
- # Same as Win32::Registry.create (self, subkey, desired, opt)
- #
- def create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED, &blk)
- self.class.create(self, subkey, desired, opt, &blk)
- end
-
- #
- # Close key.
- #
- # After close, most method raise an error.
- #
- def close
- API.CloseKey(@hkey)
- @hkey = @parent = @keyname = nil
- @hkeyfinal[0] = nil
- end
-
- #
- # Enumerate all values in this registry path.
- #
- # For each value it yields key, type and data.
- #
- # key is a String which contains name of key.
- # type is a type contant kind of Win32::Registry::REG_*
- # data is the value of this key.
- #
- def each_value
- return enum_for(:each_value) unless block_given?
- index = 0
- while true
- begin
- subkey = API.EnumValue(@hkey, index)
- rescue Error
- break
- end
- subkey = export_string(subkey)
- begin
- type, data = read(subkey)
- rescue Error
- else
- yield subkey, type, data
- end
- index += 1
- end
- index
- end
- alias each each_value
-
- #
- # return values as an array
- #
- def values
- vals_ary = []
- each_value { |*, val| vals_ary << val }
- vals_ary
- end
-
- #
- # Enumerate all subkeys.
- #
- # For each subkey it yields subkey and wtime.
- #
- # subkey is String which contains name of subkey.
- # wtime is last write time as FILETIME (64-bit integer).
- # (see Registry.wtime2time)
- #
- def each_key
- return enum_for(:each_key) unless block_given?
- index = 0
- while true
- begin
- subkey, wtime = API.EnumKey(@hkey, index)
- rescue Error
- break
- end
- subkey = export_string(subkey)
- yield subkey, wtime
- index += 1
- end
- index
- end
-
- #
- # return keys as an array
- #
- def keys
- keys_ary = []
- each_key { |key,| keys_ary << key }
- keys_ary
- end
-
- # Read a registry value named name and return array of
- # [ type, data ].
- # When name is nil, the `default' value is read.
- # type is value type. (see Win32::Registry::Constants module)
- # data is value data, its class is:
- # :REG_SZ, REG_EXPAND_SZ
- # String
- # :REG_MULTI_SZ
- # Array of String
- # :REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD
- # Integer
- # :REG_BINARY, REG_NONE
- # String (contains binary data)
- #
- # When rtype is specified, the value type must be included by
- # rtype array, or TypeError is raised.
- def read(name, *rtype)
- type, data = API.QueryValue(@hkey, name)
- unless rtype.empty? or rtype.include?(type)
- raise TypeError, "Type mismatch (expect [#{
- rtype.map{|t|Registry.type2name(t)}.join(', ')}] but #{
- Registry.type2name(type)} present)"
- end
- case type
- when REG_SZ, REG_EXPAND_SZ
- [ type, data.encode(name.encoding, WCHAR).chop ]
- when REG_MULTI_SZ
- [ type, data.encode(name.encoding, WCHAR).split(/\0/) ]
- when REG_BINARY, REG_NONE
- [ type, data ]
- when REG_DWORD
- [ type, API.unpackdw(data) ]
- when REG_DWORD_BIG_ENDIAN
- [ type, data.unpack1('N') ]
- when REG_QWORD
- [ type, API.unpackqw(data) ]
- else
- raise TypeError, "Type #{Registry.type2name(type)} is not supported."
- end
- end
-
- #
- # Read a registry value named name and return its value data.
- # The class of the value is the same as the #read method returns.
- #
- # If the value type is REG_EXPAND_SZ, returns value data whose environment
- # variables are replaced.
- # If the value type is neither REG_SZ, REG_MULTI_SZ, REG_DWORD,
- # REG_DWORD_BIG_ENDIAN, nor REG_QWORD, TypeError is raised.
- #
- # The meaning of rtype is the same as for the #read method.
- #
- def [](name, *rtype)
- type, data = read(name, *rtype)
- case type
- when REG_SZ, REG_DWORD, REG_QWORD, REG_MULTI_SZ
- data
- when REG_EXPAND_SZ
- Registry.expand_environ(data)
- else
- raise TypeError, "Type #{Registry.type2name(type)} is not supported."
- end
- end
-
- # Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
- # registry value named name.
- #
- # If the values type does not match, TypeError is raised.
- def read_s(name)
- read(name, REG_SZ)[1]
- end
-
- #
- # Read a REG_SZ or REG_EXPAND_SZ registry value named name.
- #
- # If the value type is REG_EXPAND_SZ, environment variables are replaced.
- # Unless the value type is REG_SZ or REG_EXPAND_SZ, TypeError is raised.
- #
- def read_s_expand(name)
- type, data = read(name, REG_SZ, REG_EXPAND_SZ)
- if type == REG_EXPAND_SZ
- Registry.expand_environ(data)
- else
- data
- end
- end
-
- #
- # Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
- # registry value named name.
- #
- # If the values type does not match, TypeError is raised.
- #
- def read_i(name)
- read(name, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD)[1]
- end
-
- #
- # Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
- # registry value named name.
- #
- # If the values type does not match, TypeError is raised.
- #
- def read_bin(name)
- read(name, REG_BINARY)[1]
- end
-
- #
- # Write data to a registry value named name.
- # When name is nil, write to the `default' value.
- #
- # type is type value. (see Registry::Constants module)
- # Class of data must be same as which #read
- # method returns.
- #
- def write(name, type, data)
- case type
- when REG_SZ, REG_EXPAND_SZ
- data = data.encode(WCHAR) << WCHAR_NUL
- when REG_MULTI_SZ
- data = data.to_a.map {|s| s.encode(WCHAR)}.join(WCHAR_NUL) << WCHAR_NUL
- when REG_BINARY, REG_NONE
- data = data.to_s
- when REG_DWORD
- data = API.packdw(data.to_i)
- when REG_DWORD_BIG_ENDIAN
- data = [data.to_i].pack('N')
- when REG_QWORD
- data = API.packqw(data.to_i)
- else
- raise TypeError, "Unsupported type #{Registry.type2name(type)}"
- end
- API.SetValue(@hkey, name, type, data, data.bytesize)
- end
-
- #
- # Write value to a registry value named name.
- #
- # If wtype is specified, the value type is it.
- # Otherwise, the value type is depend on class of value:
- # :Integer
- # REG_DWORD
- # :String
- # REG_SZ
- # :Array
- # REG_MULTI_SZ
- #
- def []=(name, rtype, value = nil)
- if value
- write name, rtype, value
- else
- case value = rtype
- when Integer
- write name, REG_DWORD, value
- when String
- write name, REG_SZ, value
- when Array
- write name, REG_MULTI_SZ, value
- else
- raise TypeError, "Unexpected type #{value.class}"
- end
- end
- value
- end
-
- #
- # Write value to a registry value named name.
- #
- # The value type is REG_SZ(write_s), REG_DWORD(write_i), or
- # REG_BINARY(write_bin).
- #
- def write_s(name, value)
- write name, REG_SZ, value.to_s
- end
-
- #
- # Write value to a registry value named name.
- #
- # The value type is REG_SZ(write_s), REG_DWORD(write_i), or
- # REG_BINARY(write_bin).
- #
- def write_i(name, value)
- write name, REG_DWORD, value.to_i
- end
-
- #
- # Write value to a registry value named name.
- #
- # The value type is REG_SZ(write_s), REG_DWORD(write_i), or
- # REG_BINARY(write_bin).
- #
- def write_bin(name, value)
- write name, REG_BINARY, value.to_s
- end
-
- #
- # Delete a registry value named name.
- # We can not delete the `default' value.
- #
- def delete_value(name)
- API.DeleteValue(@hkey, name)
- end
- alias delete delete_value
-
- #
- # Delete a subkey named name and all its values.
- #
- # If recursive is false, the subkey must not have subkeys.
- # Otherwise, this method deletes all subkeys and values recursively.
- #
- def delete_key(name, recursive = false)
- if recursive
- open(name, KEY_ALL_ACCESS) do |reg|
- reg.keys.each do |key|
- begin
- reg.delete_key(key, true)
- rescue Error
- #
- end
- end
- end
- API.DeleteKey(@hkey, name)
- else
- begin
- API.EnumKey @hkey, 0
- rescue Error
- return API.DeleteKey(@hkey, name)
- end
- raise Error.new(5) ## ERROR_ACCESS_DENIED
- end
- end
-
- #
- # Write all the attributes into the registry file.
- #
- def flush
- API.FlushKey @hkey
- end
-
- #
- # Returns key information as Array of:
- # :num_keys
- # The number of subkeys.
- # :max_key_length
- # Maximum length of name of subkeys.
- # :num_values
- # The number of values.
- # :max_value_name_length
- # Maximum length of name of values.
- # :max_value_length
- # Maximum length of value of values.
- # :descriptor_length
- # Length of security descriptor.
- # :wtime
- # Last write time as FILETIME(64-bit integer)
- #
- # For detail, see RegQueryInfoKey[http://msdn.microsoft.com/library/en-us/sysinfo/base/regqueryinfokey.asp] Win32 API.
- #
- def info
- API.QueryInfoKey(@hkey)
- end
-
- #
- # Returns an item of key information.
- #
- %w[
- num_keys max_key_length
- num_values max_value_name_length max_value_length
- descriptor_length wtime
- ].each_with_index do |s, i|
- eval <<-__END__
- def #{s}
- info[#{i}]
- end
- __END__
- end
-
- private
-
- def export_string(str, enc = Encoding.default_internal || LOCALE) # :nodoc:
- str.encode(enc)
- end
- end
-end
diff --git a/ext/win32/lib/win32/resolv.rb b/ext/win32/lib/win32/resolv.rb
index aaa9891456..08fed08563 100644
--- a/ext/win32/lib/win32/resolv.rb
+++ b/ext/win32/lib/win32/resolv.rb
@@ -4,8 +4,24 @@
=end
+require 'win32/resolv.so'
+
+# Generic namespace for Windows platform-specific features.
module Win32
- module Resolv
+ module Resolv # :nodoc:
+ # Error at Win32 API
+ class Error < StandardError
+ # +code+ Win32 Error code
+ # +message+ Formatted message for +code+
+ def initialize(code, message)
+ super(message)
+ @code = code
+ end
+
+ # Win32 error code
+ attr_reader :code
+ end
+
def self.get_hosts_path
path = get_hosts_dir
path = File.expand_path('hosts', path)
@@ -29,115 +45,62 @@ module Win32
end
[ search, nameserver ]
end
- end
-end
-
-begin
- require 'win32/resolv.so'
-rescue LoadError
-end
-
-module Win32
-#====================================================================
-# Windows NT
-#====================================================================
- module Resolv
- begin
- require 'win32/registry'
- module SZ
- refine Registry do
- # ad hoc workaround for broken registry
- def read_s(key)
- type, str = read(key)
- unless type == Registry::REG_SZ
- warn "Broken registry, #{name}\\#{key} was #{Registry.type2name(type)}, ignored"
- return String.new
- end
- str
- end
- end
- end
- using SZ
- rescue LoadError
- require "open3"
- end
-
- TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
class << self
private
def get_hosts_dir
- get_item_property(TCPIP_NT, 'DataBasePath', expand: true)
+ tcpip_params do |params|
+ params.value('DataBasePath')
+ end
end
def get_info
search = nil
nameserver = get_dns_server_list
- slist = get_item_property(TCPIP_NT, 'SearchList')
- search = slist.split(/,\s*/) unless slist.empty?
+ tcpip_params do |params|
+ slist = params.value('SearchList')
+ search = slist.split(/,\s*/) if slist and !slist.empty?
- if add_search = search.nil?
- search = []
- nvdom = get_item_property(TCPIP_NT, 'NV Domain')
+ if add_search = search.nil?
+ search = []
+ domain = params.value('Domain')
- unless nvdom.empty?
- @search = [ nvdom ]
- udmnd = get_item_property(TCPIP_NT, 'UseDomainNameDevolution').to_i
- if udmnd != 0
- if /^\w+\./ =~ nvdom
- devo = $'
+ if domain and !domain.empty?
+ search = [ domain ]
+ udmnd = params.value('UseDomainNameDevolution')
+ if udmnd&.nonzero?
+ if /^\w+\./ =~ domain
+ devo = $'
+ end
end
end
end
- end
- ifs = if defined?(Win32::Registry)
- Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT + '\Interfaces') do |reg|
- reg.keys
- rescue Registry::Error
- []
- end
- else
- cmd = "Get-ChildItem 'HKLM:\\#{TCPIP_NT}\\Interfaces' | ForEach-Object { $_.PSChildName }"
- output, _ = Open3.capture2('powershell', '-Command', cmd)
- output.split(/\n+/)
+ params.open('Interfaces') do |reg|
+ reg.each_key do |iface|
+ next unless ns = %w[NameServer DhcpNameServer].find do |key|
+ ns = iface.value(key)
+ break ns.split(/[,\s]\s*/) if ns and !ns.empty?
end
- ifs.each do |iface|
- next unless ns = %w[NameServer DhcpNameServer].find do |key|
- ns = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
- break ns.split(/[,\s]\s*/) unless ns.empty?
- end
-
- next if (nameserver & ns).empty?
+ next if (nameserver & ns).empty?
- if add_search
- [ 'Domain', 'DhcpDomain' ].each do |key|
- dom = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
- unless dom.empty?
- search.concat(dom.split(/,\s*/))
- break
+ if add_search
+ [ 'Domain', 'DhcpDomain' ].each do |key|
+ dom = iface.value(key)
+ if dom and !dom.empty?
+ search.concat(dom.split(/,\s*/))
+ break
+ end
+ end
end
end
end
- end
- search << devo if add_search and devo
- [ search.uniq, nameserver.uniq ]
- end
- def get_item_property(path, name, expand: false)
- if defined?(Win32::Registry)
- Registry::HKEY_LOCAL_MACHINE.open(path) do |reg|
- expand ? reg.read_s_expand(name) : reg.read_s(name)
- rescue Registry::Error
- ""
- end
- else
- cmd = "Get-ItemProperty -Path 'HKLM:\\#{path}' -Name '#{name}' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty #{name}"
- output, _ = Open3.capture2('powershell', '-Command', cmd)
- output.strip
+ search << devo if add_search and devo
end
+ [ search.uniq, nameserver.uniq ]
end
end
end
diff --git a/ext/win32/resolv/extconf.rb b/ext/win32/resolv/extconf.rb
index 4afbf8a4f6..5ee4c0d7c4 100644
--- a/ext/win32/resolv/extconf.rb
+++ b/ext/win32/resolv/extconf.rb
@@ -1,5 +1,6 @@
require 'mkmf'
-if RUBY_ENGINE == "ruby" and have_library('iphlpapi', 'GetNetworkParams')
+if RUBY_ENGINE == "ruby" and have_library('iphlpapi', 'GetNetworkParams', ['windows.h', 'iphlpapi.h'])
+ have_library('advapi32', 'RegGetValueW', ['windows.h'])
create_makefile('win32/resolv')
else
File.write('Makefile', "all clean install:\n\t@echo Done: $(@)\n")
diff --git a/ext/win32/resolv/resolv.c b/ext/win32/resolv/resolv.c
index af678e1f17..9150df5dc1 100644
--- a/ext/win32/resolv/resolv.c
+++ b/ext/win32/resolv/resolv.c
@@ -1,26 +1,59 @@
#include <ruby.h>
#include <ruby/encoding.h>
#include <windows.h>
+#include <windns.h>
#ifndef NTDDI_VERSION
#define NTDDI_VERSION 0x06000000
#endif
#include <iphlpapi.h>
+#ifndef numberof
+#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
+#endif
+
static VALUE
w32error_make_error(DWORD e)
{
- VALUE code = ULONG2NUM(e);
- return rb_class_new_instance(1, &code, rb_path2class("Win32::Resolv::Error"));
+ char buffer[512], *p;
+ DWORD source = 0;
+ VALUE args[2];
+ if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ buffer, sizeof(buffer), NULL)) {
+ snprintf(buffer, sizeof(buffer), "Unknown Error %lu", (unsigned long)e);
+ }
+ p = buffer;
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ memmove(p, p + 1, strlen(p));
+ if (!p[1]) {
+ p[0] = '\0';
+ break;
+ }
+ }
+ args[0] = ULONG2NUM(e);
+ args[1] = rb_str_new_cstr(buffer);
+ return rb_class_new_instance(2, args, rb_path2class("Win32::Resolv::Error"));
}
-NORETURN(static void w32error_raise(DWORD e));
-
static void
-w32error_raise(DWORD e)
+w32error_check(DWORD e)
+{
+ if (e != NO_ERROR) {
+ rb_exc_raise(w32error_make_error(e));
+ }
+}
+
+static VALUE
+wchar_to_utf8(const WCHAR *w, int n)
{
- rb_exc_raise(w32error_make_error(e));
+ int clen = WideCharToMultiByte(CP_UTF8, 0, w, n, NULL, 0, NULL, NULL);
+ VALUE str = rb_enc_str_new(NULL, clen, rb_utf8_encoding());
+ WideCharToMultiByte(CP_UTF8, 0, w, n, RSTRING_PTR(str), clen, NULL, NULL);
+ return str;
}
+/* :nodoc: */
static VALUE
get_dns_server_list(VALUE self)
{
@@ -30,9 +63,7 @@ get_dns_server_list(VALUE self)
VALUE buf, nameservers = Qnil;
ret = GetNetworkParams(NULL, &buflen);
- if (ret != NO_ERROR && ret != ERROR_BUFFER_OVERFLOW) {
- w32error_raise(ret);
- }
+ if (ret != ERROR_BUFFER_OVERFLOW) w32error_check(ret);
fixedinfo = ALLOCV(buf, buflen);
ret = GetNetworkParams(fixedinfo, &buflen);
if (ret == NO_ERROR) {
@@ -46,18 +77,181 @@ get_dns_server_list(VALUE self)
} while ((ipaddr = ipaddr->Next) != NULL);
}
ALLOCV_END(buf);
- if (ret != NO_ERROR) w32error_raise(ret);
+ w32error_check(ret);
return nameservers;
}
+static const WCHAR TCPIP_Params[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
+
+static void
+hkey_finalize(void *p)
+{
+ RegCloseKey((HKEY)p);
+}
+
+static const rb_data_type_t hkey_type = {
+ "RegKey",
+ {0, hkey_finalize},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static VALUE
+hkey_close(VALUE self)
+{
+ RegCloseKey((HKEY)DATA_PTR(self));
+ DATA_PTR(self) = 0;
+ return self;
+}
+
+static VALUE reg_key_class;
+
+static VALUE
+reg_open_key(VALUE klass, HKEY hkey, const WCHAR *wname)
+{
+ VALUE k = TypedData_Wrap_Struct(klass, &hkey_type, NULL);
+ DWORD e = RegOpenKeyExW(hkey, wname, 0, KEY_READ, (HKEY *)&DATA_PTR(k));
+ if (e == ERROR_FILE_NOT_FOUND) return Qnil;
+ w32error_check(e);
+ return rb_ensure(rb_yield, k, hkey_close, k);
+}
+
+/* :nodoc: */
+static VALUE
+tcpip_params_open(VALUE klass)
+{
+ return reg_open_key(reg_key_class, HKEY_LOCAL_MACHINE, TCPIP_Params);
+}
+
+static int
+to_wname(VALUE *name, WCHAR *wname, int wlen)
+{
+ const char *n = StringValueCStr(*name);
+ int nlen = RSTRING_LEN(*name);
+ int len = MultiByteToWideChar(CP_UTF8, 0, n, nlen, wname, wlen - 1);
+ if (len == 0) w32error_check(GetLastError());
+ if (len >= wlen) rb_raise(rb_eArgError, "too long name");
+ wname[len] = L'\0';
+ return len;
+}
+
+static VALUE
+reg_open(VALUE self, VALUE name)
+{
+ HKEY hkey = DATA_PTR(self);
+ WCHAR wname[256];
+ to_wname(&name, wname, numberof(wname));
+ return reg_open_key(CLASS_OF(self), hkey, wname);
+}
+
+
+static VALUE
+reg_each_key(VALUE self)
+{
+ WCHAR wname[256];
+ HKEY hkey = DATA_PTR(self);
+ VALUE k = TypedData_Wrap_Struct(CLASS_OF(self), &hkey_type, NULL);
+ DWORD i, e, n;
+ for (i = 0; n = numberof(wname), (e = RegEnumKeyExW(hkey, i, wname, &n, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS; i++) {
+ e = RegOpenKeyExW(hkey, wname, 0, KEY_READ, (HKEY *)&DATA_PTR(k));
+ w32error_check(e);
+ rb_ensure(rb_yield, k, hkey_close, k);
+ }
+ if (e != ERROR_NO_MORE_ITEMS) w32error_check(e);
+ return self;
+}
+
+static inline DWORD
+swap_dw(DWORD x)
+{
+#if defined(_MSC_VER)
+ return _byteswap_ulong(x);
+#else
+ return __builtin_bswap32(x);
+#endif
+}
+
+static VALUE
+reg_value(VALUE self, VALUE name)
+{
+ HKEY hkey = DATA_PTR(self);
+ DWORD type = 0, size = 0, e;
+ VALUE result, value_buffer;
+ void *buffer;
+ WCHAR wname[256];
+ to_wname(&name, wname, numberof(wname));
+ e = RegGetValueW(hkey, NULL, wname, RRF_RT_ANY, &type, NULL, &size);
+ if (e == ERROR_FILE_NOT_FOUND) return Qnil;
+ w32error_check(e);
+# define get_value_2nd(data, dsize) do { \
+ DWORD type2 = type; \
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_ANY, &type2, data, dsize)); \
+ if (type != type2) { \
+ rb_raise(rb_eRuntimeError, "registry value type changed %lu -> %lu", \
+ (unsigned long)type, (unsigned long)type2); \
+ } \
+ } while (0)
+
+ switch (type) {
+ case REG_DWORD: case REG_DWORD_BIG_ENDIAN:
+ {
+ DWORD d;
+ if (size != sizeof(d)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_REG_DWORD, &type, &d, &size));
+ if (type == REG_DWORD_BIG_ENDIAN) d = swap_dw(d);
+ return ULONG2NUM(d);
+ }
+ case REG_QWORD:
+ {
+ QWORD q;
+ if (size != sizeof(q)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_REG_QWORD, &type, &q, &size));
+ return ULL2NUM(q);
+ }
+ case REG_SZ: case REG_MULTI_SZ: case REG_EXPAND_SZ:
+ if (size % sizeof(WCHAR)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ buffer = ALLOCV_N(char, value_buffer, size);
+ get_value_2nd(buffer, &size);
+ if (type == REG_MULTI_SZ) {
+ const WCHAR *w = (WCHAR *)buffer;
+ result = rb_ary_new();
+ size /= sizeof(WCHAR);
+ size -= 1;
+ for (size_t i = 0; i < size; ++i) {
+ int n = lstrlenW(w+i);
+ rb_ary_push(result, wchar_to_utf8(w+i, n));
+ i += n;
+ }
+ }
+ else {
+ result = wchar_to_utf8((WCHAR *)buffer, lstrlenW((WCHAR *)buffer));
+ }
+ ALLOCV_END(value_buffer);
+ break;
+ default:
+ result = rb_str_new(0, size);
+ get_value_2nd(RSTRING_PTR(result), &size);
+ rb_str_set_len(result, size);
+ break;
+ }
+ return result;
+}
+
void
InitVM_resolv(void)
{
VALUE mWin32 = rb_define_module("Win32");
VALUE resolv = rb_define_module_under(mWin32, "Resolv");
VALUE singl = rb_singleton_class(resolv);
+ VALUE regkey = rb_define_class_under(resolv, "registry key", rb_cObject);
+
+ reg_key_class = regkey;
+ rb_undef_alloc_func(regkey);
rb_define_private_method(singl, "get_dns_server_list", get_dns_server_list, 0);
+ rb_define_private_method(singl, "tcpip_params", tcpip_params_open, 0);
+ rb_define_method(regkey, "open", reg_open, 1);
+ rb_define_method(regkey, "each_key", reg_each_key, 0);
+ rb_define_method(regkey, "value", reg_value, 1);
}
void
diff --git a/ext/win32/win32-registry.gemspec b/ext/win32/win32-registry.gemspec
deleted file mode 100644
index d747daf458..0000000000
--- a/ext/win32/win32-registry.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-Gem::Specification.new do |spec|
- spec.name = "win32-registry"
- spec.version = "0.1.0"
- spec.authors = ["U.Nakamura"]
- spec.email = ["usa@garbagecollect.jp"]
-
- spec.summary = %q{Provides an interface to the Windows Registry in Ruby}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/win32-registry"
- spec.required_ruby_version = ">= 2.6.0"
-
- 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.
- excludes = %w[
- bin/ test/ spec/ features/ rakelib/
- .git .github .mailmap appveyor Rakefile Gemfile
- ]
- spec.files = Dir.chdir(__dir__) do
- `git ls-files -z`.split("\x0").reject do |f|
- File.identical?(f, __FILE__) || f.start_with?(*excludes)
- end
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-
- spec.add_dependency "fiddle", "~> 1.0"
-end
diff --git a/ext/zlib/depend b/ext/zlib/depend
index bdce420264..22e9ca867a 100644
--- a/ext/zlib/depend
+++ b/ext/zlib/depend
@@ -138,6 +138,7 @@ zlib.o: $(hdrdir)/ruby/internal/intern/re.h
zlib.o: $(hdrdir)/ruby/internal/intern/ruby.h
zlib.o: $(hdrdir)/ruby/internal/intern/select.h
zlib.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+zlib.o: $(hdrdir)/ruby/internal/intern/set.h
zlib.o: $(hdrdir)/ruby/internal/intern/signal.h
zlib.o: $(hdrdir)/ruby/internal/intern/sprintf.h
zlib.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 0b9c4d65ee..481d74b2b6 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.2.1"
+#define RUBY_ZLIB_VERSION "3.2.3"
#ifndef RB_PASS_CALLED_KEYWORDS
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
@@ -860,9 +860,7 @@ zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len)
char *bufptr;
long filled;
- if (NIL_P(z->buf) || (long)rb_str_capacity(z->buf) <= ZSTREAM_BUF_FILLED(z)) {
- zstream_expand_buffer_into(z, len);
- }
+ zstream_expand_buffer_into(z, len);
RSTRING_GETMEM(z->buf, bufptr, filled);
memmove(bufptr + len, bufptr, filled);
@@ -1094,8 +1092,9 @@ zstream_run_func(struct zstream_run_args *args)
break;
}
- if (err != Z_OK && err != Z_BUF_ERROR)
+ if (err != Z_OK && err != Z_BUF_ERROR) {
break;
+ }
if (z->stream.avail_out > 0) {
z->flags |= ZSTREAM_FLAG_IN_STREAM;
@@ -1170,12 +1169,17 @@ loop:
/* retry if no exception is thrown */
if (err == Z_OK && args->interrupt) {
args->interrupt = 0;
- goto loop;
+
+ /* Retry only if both avail_in > 0 (more input to process) and avail_out > 0
+ * (output buffer has space). If avail_out == 0, the buffer is full and should
+ * be consumed by the caller first. If avail_in == 0, there's nothing more to process. */
+ if (z->stream.avail_in > 0 && z->stream.avail_out > 0) {
+ goto loop;
+ }
}
- if (flush != Z_FINISH && err == Z_BUF_ERROR
- && z->stream.avail_out > 0) {
- z->flags |= ZSTREAM_FLAG_IN_STREAM;
+ if (flush != Z_FINISH && err == Z_BUF_ERROR && z->stream.avail_out > 0) {
+ z->flags |= ZSTREAM_FLAG_IN_STREAM;
}
zstream_reset_input(z);
@@ -1456,6 +1460,7 @@ rb_zstream_finish(VALUE obj)
* call-seq:
* flush_next_in -> input
*
+ * Flushes input buffer and returns all data in that buffer.
*/
static VALUE
rb_zstream_flush_next_in(VALUE obj)
@@ -2444,17 +2449,16 @@ struct gzfile {
#define GZFILE_READ_SIZE 2048
+enum { read_raw_arg_len, read_raw_arg_buf, read_raw_arg__count};
struct read_raw_arg {
VALUE io;
- union {
- const VALUE argv[2]; /* for rb_funcallv */
- struct {
- VALUE len;
- VALUE buf;
- } in;
- } as;
+ const VALUE argv[read_raw_arg__count]; /* for rb_funcallv */
};
+#define read_raw_arg_argc(ra) \
+ ((int)read_raw_arg__count - NIL_P((ra)->argv[read_raw_arg__count - 1]))
+#define read_raw_arg_init(io, len, buf) { io, { len, buf } }
+
static void
gzfile_mark(void *p)
{
@@ -2580,9 +2584,9 @@ gzfile_read_raw_partial(VALUE arg)
{
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
VALUE str;
- int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
+ int argc = read_raw_arg_argc(ra);
- str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv);
+ str = rb_funcallv(ra->io, id_readpartial, argc, ra->argv);
Check_Type(str, T_STRING);
return str;
}
@@ -2593,8 +2597,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _)
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
VALUE str = Qnil;
if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
- int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
- str = rb_funcallv(ra->io, id_read, argc, ra->as.argv);
+ int argc = read_raw_arg_argc(ra);
+ str = rb_funcallv(ra->io, id_read, argc, ra->argv);
if (!NIL_P(str)) {
Check_Type(str, T_STRING);
}
@@ -2605,11 +2609,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _)
static VALUE
gzfile_read_raw(struct gzfile *gz, VALUE outbuf)
{
- struct read_raw_arg ra;
-
- ra.io = gz->io;
- ra.as.in.len = INT2FIX(GZFILE_READ_SIZE);
- ra.as.in.buf = outbuf;
+ struct read_raw_arg ra =
+ read_raw_arg_init(gz->io, INT2FIX(GZFILE_READ_SIZE), outbuf);
return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra,
gzfile_read_raw_rescue, (VALUE)&ra,
diff --git a/file.c b/file.c
index 8d97d1de64..c4a531d783 100644
--- a/file.c
+++ b/file.c
@@ -12,6 +12,7 @@
**********************************************************************/
#include "ruby/internal/config.h"
+#include "ruby/internal/attr/nonstring.h"
#ifdef _WIN32
# include "missing/file.h"
@@ -131,6 +132,14 @@ int flock(int, int);
# define STAT(p, s) stat((p), (s))
#endif /* _WIN32 */
+#ifdef HAVE_STRUCT_STATX_STX_BTIME
+# define ST_(name) stx_ ## name
+typedef struct statx_timestamp stat_timestamp;
+#else
+# define ST_(name) st_ ## name
+typedef struct timespec stat_timestamp;
+#endif
+
#if defined _WIN32 || defined __APPLE__
# define USE_OSPATH 1
# define TO_OSPATH(str) rb_str_encode_ospath(str)
@@ -160,6 +169,7 @@ int flock(int, int);
#include "internal.h"
#include "internal/compilers.h"
#include "internal/dir.h"
+#include "internal/encoding.h"
#include "internal/error.h"
#include "internal/file.h"
#include "internal/io.h"
@@ -172,6 +182,13 @@ int flock(int, int);
#include "ruby/thread.h"
#include "ruby/util.h"
+#define UIANY2NUM(x) \
+ ((sizeof(x) <= sizeof(unsigned int)) ? \
+ UINT2NUM((unsigned)(x)) : \
+ (sizeof(x) <= sizeof(unsigned long)) ? \
+ ULONG2NUM((unsigned long)(x)) : \
+ ULL2NUM((unsigned LONG_LONG)(x)))
+
VALUE rb_cFile;
VALUE rb_mFileTest;
VALUE rb_cStat;
@@ -197,15 +214,16 @@ file_path_convert(VALUE name)
return name;
}
-static rb_encoding *
+static void
check_path_encoding(VALUE str)
{
- rb_encoding *enc = rb_enc_get(str);
- if (!rb_enc_asciicompat(enc)) {
- rb_raise(rb_eEncCompatError, "path name must be ASCII-compatible (%s): %"PRIsVALUE,
- rb_enc_name(enc), rb_str_inspect(str));
+ if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
+ rb_encoding *enc = rb_str_enc_get(str);
+ if (!rb_enc_asciicompat(enc)) {
+ rb_raise(rb_eEncCompatError, "path name must be ASCII-compatible (%s): %"PRIsVALUE,
+ rb_enc_name(enc), rb_str_inspect(str));
+ }
}
- return enc;
}
VALUE
@@ -227,13 +245,20 @@ VALUE
rb_get_path_check_convert(VALUE obj)
{
obj = file_path_convert(obj);
+ rb_get_path_check_no_convert(obj);
+ return rb_str_new_frozen(obj);
+}
+/* TODO: name */
+VALUE
+rb_get_path_check_no_convert(VALUE obj)
+{
check_path_encoding(obj);
if (!rb_str_to_cstr(obj)) {
rb_raise(rb_eArgError, "path name contains null byte");
}
- return rb_str_new4(obj);
+ return obj;
}
VALUE
@@ -248,6 +273,19 @@ rb_get_path(VALUE obj)
return rb_get_path_check_convert(rb_get_path_check_to_string(obj));
}
+static inline VALUE
+check_path(VALUE obj, const char **cstr)
+{
+ VALUE str = rb_get_path_check_convert(rb_get_path_check_to_string(obj));
+#if RUBY_DEBUG
+ str = rb_str_new_frozen(str);
+#endif
+ *cstr = RSTRING_PTR(str);
+ return str;
+}
+
+#define CheckPath(str, cstr) RB_GC_GUARD(str) = check_path(str, &cstr);
+
VALUE
rb_str_encode_ospath(VALUE path)
{
@@ -349,16 +387,22 @@ rb_str_normalize_ospath(const char *ptr, long len)
const char *p = ptr;
const char *e = ptr + len;
const char *p1 = p;
- VALUE str = rb_str_buf_new(len);
rb_encoding *enc = rb_utf8_encoding();
- rb_enc_associate(str, enc);
+ VALUE str = rb_utf8_str_new(ptr, len);
+ if (RB_LIKELY(rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)) {
+ return str;
+ }
+ else {
+ str = rb_str_buf_new(len);
+ rb_enc_associate(str, enc);
+ }
while (p < e) {
int l, c;
int r = rb_enc_precise_mbclen(p, e, enc);
if (!MBCLEN_CHARFOUND_P(r)) {
/* invalid byte shall not happen but */
- static const char invalid[3] = "\xEF\xBF\xBD";
+ RBIMPL_ATTR_NONSTRING() static const char invalid[3] = "\xEF\xBF\xBD";
rb_str_append_normalized_ospath(str, p1, p-p1);
rb_str_cat(str, invalid, sizeof(invalid));
p += 1;
@@ -493,6 +537,10 @@ apply2files(int (*func)(const char *, void *), int argc, VALUE *argv, void *arg)
return LONG2FIX(argc);
}
+static stat_timestamp stat_atimespec(const struct stat *st);
+static stat_timestamp stat_mtimespec(const struct stat *st);
+static stat_timestamp stat_ctimespec(const struct stat *st);
+
static const rb_data_type_t stat_data_type = {
"stat",
{
@@ -504,29 +552,67 @@ static const rb_data_type_t stat_data_type = {
};
struct rb_stat {
- struct stat stat;
+ rb_io_stat_data stat;
bool initialized;
};
-static VALUE
-stat_new_0(VALUE klass, const struct stat *st)
+static struct rb_stat *
+stat_alloc(VALUE klass, VALUE *obj)
{
struct rb_stat *rb_st;
- VALUE obj = TypedData_Make_Struct(klass, struct rb_stat, &stat_data_type, rb_st);
+ *obj = TypedData_Make_Struct(klass, struct rb_stat, &stat_data_type, rb_st);
+ return rb_st;
+}
+
+VALUE
+rb_stat_new(const struct stat *st)
+{
+ VALUE obj;
+ struct rb_stat *rb_st = stat_alloc(rb_cStat, &obj);
if (st) {
+#if RUBY_USE_STATX
+# define CP(m) .stx_ ## m = st->st_ ## m
+# define CP_32(m) .stx_ ## m = (uint32_t)st->st_ ## m
+# define CP_TS(m) .stx_ ## m = stat_ ## m ## spec(st)
+ rb_st->stat = (struct statx){
+ .stx_mask = STATX_BASIC_STATS,
+ CP(mode),
+ CP_32(nlink),
+ CP(uid),
+ CP(gid),
+ CP_TS(atime),
+ CP_TS(mtime),
+ CP_TS(ctime),
+ CP(ino),
+ CP(size),
+ CP(blocks),
+ };
+# undef CP
+# undef CP_TS
+#else
rb_st->stat = *st;
+#endif
rb_st->initialized = true;
}
+
return obj;
}
+#ifndef rb_statx_new
VALUE
-rb_stat_new(const struct stat *st)
+rb_statx_new(const rb_io_stat_data *st)
{
- return stat_new_0(rb_cStat, st);
+ VALUE obj;
+ struct rb_stat *rb_st = stat_alloc(rb_cStat, &obj);
+ if (st) {
+ rb_st->stat = *st;
+ rb_st->initialized = true;
+ }
+ return obj;
}
+#endif
-static struct stat*
+static rb_io_stat_data*
get_stat(VALUE self)
{
struct rb_stat* rb_st;
@@ -535,29 +621,51 @@ get_stat(VALUE self)
return &rb_st->stat;
}
-static struct timespec stat_mtimespec(const struct stat *st);
+#if RUBY_USE_STATX
+static stat_timestamp
+statx_mtimespec(const rb_io_stat_data *st)
+{
+ return st->stx_mtime;
+}
+#else
+# define statx_mtimespec stat_mtimespec
+#endif
/*
* call-seq:
- * stat <=> other_stat -> -1, 0, 1, nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+, by comparing their modification times;
+ * that is, by comparing <tt>self.mtime</tt> and <tt>other.mtime</tt>.
*
- * Compares File::Stat objects by comparing their respective modification
- * times.
+ * Returns:
*
- * +nil+ is returned if +other_stat+ is not a File::Stat object
+ * - +-1+, if <tt>self.mtime</tt> is earlier.
+ * - +0+, if the two values are equal.
+ * - +1+, if <tt>self.mtime</tt> is later.
+ * - +nil+, if +other+ is not a File::Stat object.
+ *
+ * Examples:
*
- * f1 = File.new("f1", "w")
- * sleep 1
- * f2 = File.new("f2", "w")
- * f1.stat <=> f2.stat #=> -1
+ * stat0 = File.stat('README.md')
+ * stat1 = File.stat('NEWS.md')
+ * stat0.mtime # => 2025-12-20 15:33:05.6972341 -0600
+ * stat1.mtime # => 2025-12-20 16:02:08.2672945 -0600
+ * stat0 <=> stat1 # => -1
+ * stat0 <=> stat0.dup # => 0
+ * stat1 <=> stat0 # => 1
+ * stat0 <=> :foo # => nil
+ *
+ * \Class \File::Stat includes module Comparable,
+ * each of whose methods uses File::Stat#<=> for comparison.
*/
static VALUE
rb_stat_cmp(VALUE self, VALUE other)
{
if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
- struct timespec ts1 = stat_mtimespec(get_stat(self));
- struct timespec ts2 = stat_mtimespec(get_stat(other));
+ stat_timestamp ts1 = statx_mtimespec(get_stat(self));
+ stat_timestamp ts2 = statx_mtimespec(get_stat(other));
if (ts1.tv_sec == ts2.tv_sec) {
if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
@@ -594,7 +702,11 @@ rb_stat_cmp(VALUE self, VALUE other)
static VALUE
rb_stat_dev(VALUE self)
{
-#if SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_DEV_T
+#if RUBY_USE_STATX
+ unsigned int m = get_stat(self)->stx_dev_major;
+ unsigned int n = get_stat(self)->stx_dev_minor;
+ return ULL2NUM(makedev(m, n));
+#elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_DEV_T
return DEVT2NUM(get_stat(self)->st_dev);
#elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_LONG
return ULONG2NUM(get_stat(self)->st_dev);
@@ -617,7 +729,9 @@ rb_stat_dev(VALUE self)
static VALUE
rb_stat_dev_major(VALUE self)
{
-#if defined(major)
+#if RUBY_USE_STATX
+ return UINT2NUM(get_stat(self)->stx_dev_major);
+#elif defined(major)
return UINT2NUM(major(get_stat(self)->st_dev));
#else
return Qnil;
@@ -638,7 +752,9 @@ rb_stat_dev_major(VALUE self)
static VALUE
rb_stat_dev_minor(VALUE self)
{
-#if defined(minor)
+#if RUBY_USE_STATX
+ return UINT2NUM(get_stat(self)->stx_dev_minor);
+#elif defined(minor)
return UINT2NUM(minor(get_stat(self)->st_dev));
#else
return Qnil;
@@ -658,16 +774,15 @@ rb_stat_dev_minor(VALUE self)
static VALUE
rb_stat_ino(VALUE self)
{
+ rb_io_stat_data *ptr = get_stat(self);
#ifdef HAVE_STRUCT_STAT_ST_INOHIGH
/* assume INTEGER_PACK_LSWORD_FIRST and st_inohigh is just next of st_ino */
- return rb_integer_unpack(&get_stat(self)->st_ino, 2,
+ return rb_integer_unpack(&ptr->st_ino, 2,
SIZEOF_STRUCT_STAT_ST_INO, 0,
INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER|
INTEGER_PACK_2COMP);
-#elif SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG
- return ULL2NUM(get_stat(self)->st_ino);
#else
- return ULONG2NUM(get_stat(self)->st_ino);
+ return UIANY2NUM(ptr->ST_(ino));
#endif
}
@@ -687,7 +802,7 @@ rb_stat_ino(VALUE self)
static VALUE
rb_stat_mode(VALUE self)
{
- return UINT2NUM(ST2UINT(get_stat(self)->st_mode));
+ return UINT2NUM(ST2UINT(get_stat(self)->ST_(mode)));
}
/*
@@ -706,20 +821,9 @@ static VALUE
rb_stat_nlink(VALUE self)
{
/* struct stat::st_nlink is nlink_t in POSIX. Not the case for Windows. */
- const struct stat *ptr = get_stat(self);
+ const rb_io_stat_data *ptr = get_stat(self);
- if (sizeof(ptr->st_nlink) <= sizeof(int)) {
- return UINT2NUM((unsigned)ptr->st_nlink);
- }
- else if (sizeof(ptr->st_nlink) == sizeof(long)) {
- return ULONG2NUM((unsigned long)ptr->st_nlink);
- }
- else if (sizeof(ptr->st_nlink) == sizeof(LONG_LONG)) {
- return ULL2NUM((unsigned LONG_LONG)ptr->st_nlink);
- }
- else {
- rb_bug(":FIXME: don't know what to do");
- }
+ return UIANY2NUM(ptr->ST_(nlink));
}
/*
@@ -735,7 +839,7 @@ rb_stat_nlink(VALUE self)
static VALUE
rb_stat_uid(VALUE self)
{
- return UIDT2NUM(get_stat(self)->st_uid);
+ return UIDT2NUM(get_stat(self)->ST_(uid));
}
/*
@@ -751,7 +855,7 @@ rb_stat_uid(VALUE self)
static VALUE
rb_stat_gid(VALUE self)
{
- return GIDT2NUM(get_stat(self)->st_gid);
+ return GIDT2NUM(get_stat(self)->ST_(gid));
}
/*
@@ -769,16 +873,18 @@ rb_stat_gid(VALUE self)
static VALUE
rb_stat_rdev(VALUE self)
{
-#ifdef HAVE_STRUCT_STAT_ST_RDEV
-# if SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_DEV_T
- return DEVT2NUM(get_stat(self)->st_rdev);
-# elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_LONG
- return ULONG2NUM(get_stat(self)->st_rdev);
-# else
- return ULL2NUM(get_stat(self)->st_rdev);
-# endif
-#else
+#if RUBY_USE_STATX
+ unsigned int m = get_stat(self)->stx_rdev_major;
+ unsigned int n = get_stat(self)->stx_rdev_minor;
+ return ULL2NUM(makedev(m, n));
+#elif !defined(HAVE_STRUCT_STAT_ST_RDEV)
return Qnil;
+#elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_DEV_T
+ return DEVT2NUM(get_stat(self)->ST_(rdev));
+#elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_LONG
+ return ULONG2NUM(get_stat(self)->ST_(rdev));
+#else
+ return ULL2NUM(get_stat(self)->ST_(rdev));
#endif
}
@@ -796,8 +902,10 @@ rb_stat_rdev(VALUE self)
static VALUE
rb_stat_rdev_major(VALUE self)
{
-#if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
- return UINT2NUM(major(get_stat(self)->st_rdev));
+#if RUBY_USE_STATX
+ return UINT2NUM(get_stat(self)->stx_rdev_major);
+#elif defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
+ return UINT2NUM(major(get_stat(self)->ST_(rdev)));
#else
return Qnil;
#endif
@@ -817,8 +925,10 @@ rb_stat_rdev_major(VALUE self)
static VALUE
rb_stat_rdev_minor(VALUE self)
{
-#if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
- return UINT2NUM(minor(get_stat(self)->st_rdev));
+#if RUBY_USE_STATX
+ return UINT2NUM(get_stat(self)->stx_rdev_minor);
+#elif defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
+ return UINT2NUM(minor(get_stat(self)->ST_(rdev)));
#else
return Qnil;
#endif
@@ -836,7 +946,7 @@ rb_stat_rdev_minor(VALUE self)
static VALUE
rb_stat_size(VALUE self)
{
- return OFFT2NUM(get_stat(self)->st_size);
+ return OFFT2NUM(get_stat(self)->ST_(size));
}
/*
@@ -854,7 +964,7 @@ static VALUE
rb_stat_blksize(VALUE self)
{
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- return ULONG2NUM(get_stat(self)->st_blksize);
+ return ULONG2NUM(get_stat(self)->ST_(blksize));
#else
return Qnil;
#endif
@@ -876,34 +986,44 @@ rb_stat_blocks(VALUE self)
{
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
# if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG
- return ULL2NUM(get_stat(self)->st_blocks);
+ return ULL2NUM(get_stat(self)->ST_(blocks));
# else
- return ULONG2NUM(get_stat(self)->st_blocks);
+ return ULONG2NUM(get_stat(self)->ST_(blocks));
# endif
#else
return Qnil;
#endif
}
-static struct timespec
+static stat_timestamp
stat_atimespec(const struct stat *st)
{
- struct timespec ts;
+ stat_timestamp ts;
ts.tv_sec = st->st_atime;
#if defined(HAVE_STRUCT_STAT_ST_ATIM)
- ts.tv_nsec = st->st_atim.tv_nsec;
+ ts.tv_nsec = (uint32_t)st->st_atim.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
- ts.tv_nsec = st->st_atimespec.tv_nsec;
+ ts.tv_nsec = (uint32_t)st->st_atimespec.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
- ts.tv_nsec = (long)st->st_atimensec;
+ ts.tv_nsec = (uint32_t)st->st_atimensec;
#else
- ts.tv_nsec = 0;
+ ts.tv_nsec = 0
#endif
return ts;
}
+#if RUBY_USE_STATX
+static stat_timestamp
+statx_atimespec(const rb_io_stat_data *st)
+{
+ return st->stx_atime;
+}
+#else
+# define statx_atimespec stat_atimespec
+#endif
+
static VALUE
-stat_time(const struct timespec ts)
+stat_time(const stat_timestamp ts)
{
return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
}
@@ -914,17 +1034,17 @@ stat_atime(const struct stat *st)
return stat_time(stat_atimespec(st));
}
-static struct timespec
+static stat_timestamp
stat_mtimespec(const struct stat *st)
{
- struct timespec ts;
+ stat_timestamp ts;
ts.tv_sec = st->st_mtime;
#if defined(HAVE_STRUCT_STAT_ST_MTIM)
- ts.tv_nsec = st->st_mtim.tv_nsec;
+ ts.tv_nsec = (uint32_t)st->st_mtim.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
- ts.tv_nsec = st->st_mtimespec.tv_nsec;
+ ts.tv_nsec = (uint32_t)st->st_mtimespec.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
- ts.tv_nsec = (long)st->st_mtimensec;
+ ts.tv_nsec = (uint32_t)st->st_mtimensec;
#else
ts.tv_nsec = 0;
#endif
@@ -937,23 +1057,33 @@ stat_mtime(const struct stat *st)
return stat_time(stat_mtimespec(st));
}
-static struct timespec
+static stat_timestamp
stat_ctimespec(const struct stat *st)
{
- struct timespec ts;
+ stat_timestamp ts;
ts.tv_sec = st->st_ctime;
#if defined(HAVE_STRUCT_STAT_ST_CTIM)
- ts.tv_nsec = st->st_ctim.tv_nsec;
+ ts.tv_nsec = (uint32_t)st->st_ctim.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
- ts.tv_nsec = st->st_ctimespec.tv_nsec;
+ ts.tv_nsec = (uint32_t)st->st_ctimespec.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
- ts.tv_nsec = (long)st->st_ctimensec;
+ ts.tv_nsec = (uint32_t)st->st_ctimensec;
#else
ts.tv_nsec = 0;
#endif
return ts;
}
+#if RUBY_USE_STATX
+static stat_timestamp
+statx_ctimespec(const rb_io_stat_data *st)
+{
+ return st->stx_ctime;
+}
+#else
+# define statx_ctimespec stat_ctimespec
+#endif
+
static VALUE
stat_ctime(const struct stat *st)
{
@@ -962,35 +1092,50 @@ stat_ctime(const struct stat *st)
#define HAVE_STAT_BIRTHTIME
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
-typedef struct stat statx_data;
static VALUE
-stat_birthtime(const struct stat *st)
+statx_birthtime(const rb_io_stat_data *st)
{
- const struct timespec *ts = &st->st_birthtimespec;
+ const stat_timestamp *ts = &st->ST_(birthtimespec);
return rb_time_nano_new(ts->tv_sec, ts->tv_nsec);
}
+#elif defined(HAVE_STRUCT_STATX_STX_BTIME)
+static VALUE statx_birthtime(const rb_io_stat_data *st);
#elif defined(_WIN32)
-typedef struct stat statx_data;
-# define stat_birthtime stat_ctime
+# define statx_birthtime stat_ctime
#else
# undef HAVE_STAT_BIRTHTIME
#endif /* defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) */
/*
* call-seq:
- * stat.atime -> time
- *
- * Returns the last access time for this file as an object of class
- * Time.
- *
- * File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
- *
+ * atime -> new_time
+ *
+ * Returns a new Time object containing the access time
+ * of the object represented by +self+
+ * at the time +self+ was created;
+ * see {Snapshot}[rdoc-ref:File::Stat@Snapshot]:
+ *
+ * filepath = 't.tmp'
+ * File.write(filepath, 'foo')
+ * file = File.new(filepath, 'w')
+ * stat = File::Stat.new(filepath)
+ * file.atime # => 2026-03-31 16:26:39.5913207 -0500
+ * stat.atime # => 2026-03-31 16:26:39.5913207 -0500
+ * File.write(filepath, 'bar')
+ * file.atime # => 2026-03-31 16:27:01.4981624 -0500 # Changed by access.
+ * stat.atime # => 2026-03-31 16:26:39.5913207 -0500 # Unchanged by access.
+ * stat = File::Stat.new(filepath)
+ * stat.atime # => 2026-03-31 16:27:01.4981624 -0500 # New access time.
+ * file.close
+ * File.delete(filepath)
+ *
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
rb_stat_atime(VALUE self)
{
- return stat_atime(get_stat(self));
+ return stat_time(statx_atimespec(get_stat(self)));
}
/*
@@ -1006,7 +1151,7 @@ rb_stat_atime(VALUE self)
static VALUE
rb_stat_mtime(VALUE self)
{
- return stat_mtime(get_stat(self));
+ return stat_time(statx_mtimespec(get_stat(self)));
}
/*
@@ -1026,36 +1171,34 @@ rb_stat_mtime(VALUE self)
static VALUE
rb_stat_ctime(VALUE self)
{
- return stat_ctime(get_stat(self));
+ return stat_time(statx_ctimespec(get_stat(self)));
}
#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
- * stat.birthtime -> time
- *
- * Returns the birth time for <i>stat</i>.
- *
- * If the platform doesn't have birthtime, raises NotImplementedError.
- *
- * File.write("testfile", "foo")
- * sleep 10
- * File.write("testfile", "bar")
- * sleep 10
- * File.chmod(0644, "testfile")
- * sleep 10
- * File.read("testfile")
- * File.stat("testfile").birthtime #=> 2014-02-24 11:19:17 +0900
- * File.stat("testfile").mtime #=> 2014-02-24 11:19:27 +0900
- * File.stat("testfile").ctime #=> 2014-02-24 11:19:37 +0900
- * File.stat("testfile").atime #=> 2014-02-24 11:19:47 +0900
- *
+ * birthtime -> new_time
+ *
+ * Returns a new Time object containing the create time
+ * of the object represented by +self+
+ * at the time +self+ was created;
+ * see {Snapshot}[rdoc-ref:File::Stat@Snapshot]:
+ *
+ * filename = 't.tmp'
+ * stat = File::Stat.new(filename) # Raises Errno::ENOENT: No such file or directory
+ * File.write(filename, 'foo')
+ * stat = File::Stat.new(filename)
+ * stat.birthtime # => 2026-04-14 10:41:55.5146554 -0500
+ * File.delete(filename)
+ * stat.birthtime # => 2026-04-14 10:41:55.5146554 -0500
+ *
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
rb_stat_birthtime(VALUE self)
{
- return stat_birthtime(get_stat(self));
+ return statx_birthtime(get_stat(self));
}
#else
# define rb_stat_birthtime rb_f_notimplement
@@ -1184,6 +1327,8 @@ stat_without_gvl(const char *path, struct stat *st)
#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
defined(HAVE_STRUCT_STATX_STX_BTIME)
+# define STATX(path, st, mask) statx(AT_FDCWD, path, 0, mask, st)
+
# ifndef HAVE_STATX
# ifdef HAVE_SYSCALL_H
# include <syscall.h>
@@ -1201,18 +1346,18 @@ statx(int dirfd, const char *pathname, int flags,
# endif /* __linux__ */
# endif /* HAVE_STATX */
-typedef struct no_gvl_statx_data {
+typedef struct no_gvl_rb_io_stat_data {
struct statx *stx;
int fd;
const char *path;
int flags;
unsigned int mask;
-} no_gvl_statx_data;
+} no_gvl_rb_io_stat_data;
static VALUE
io_blocking_statx(void *data)
{
- no_gvl_statx_data *arg = data;
+ no_gvl_rb_io_stat_data *arg = data;
return (VALUE)statx(arg->fd, arg->path, arg->flags, arg->mask, arg->stx);
}
@@ -1223,23 +1368,34 @@ no_gvl_statx(void *data)
}
static int
-statx_without_gvl(const char *path, struct statx *stx, unsigned int mask)
+statx_without_gvl(const char *path, rb_io_stat_data *stx, unsigned int mask)
+{
+ no_gvl_rb_io_stat_data data = {stx, AT_FDCWD, path, 0, mask};
+
+ /* call statx(2) with pathname */
+ return IO_WITHOUT_GVL_INT(no_gvl_statx, &data);
+}
+
+static int
+lstatx_without_gvl(const char *path, rb_io_stat_data *stx, unsigned int mask)
{
- no_gvl_statx_data data = {stx, AT_FDCWD, path, 0, mask};
+ no_gvl_rb_io_stat_data data = {stx, AT_FDCWD, path, AT_SYMLINK_NOFOLLOW, mask};
/* call statx(2) with pathname */
return IO_WITHOUT_GVL_INT(no_gvl_statx, &data);
}
static int
-fstatx_without_gvl(rb_io_t *fptr, struct statx *stx, unsigned int mask)
+fstatx_without_gvl(rb_io_t *fptr, rb_io_stat_data *stx, unsigned int mask)
{
- no_gvl_statx_data data = {stx, fptr->fd, "", AT_EMPTY_PATH, mask};
+ no_gvl_rb_io_stat_data data = {stx, fptr->fd, "", AT_EMPTY_PATH, mask};
/* call statx(2) with fd */
return (int)rb_io_blocking_region(fptr, io_blocking_statx, &data);
}
+#define FSTATX(fd, st) statx(fd, "", AT_EMPTY_PATH, STATX_ALL, st)
+
static int
rb_statx(VALUE file, struct statx *stx, unsigned int mask)
{
@@ -1249,6 +1405,7 @@ rb_statx(VALUE file, struct statx *stx, unsigned int mask)
tmp = rb_check_convert_type_with_id(file, T_FILE, "IO", idTo_io);
if (!NIL_P(tmp)) {
rb_io_t *fptr;
+
GetOpenFile(tmp, fptr);
result = fstatx_without_gvl(fptr, stx, mask);
file = tmp;
@@ -1277,7 +1434,7 @@ statx_notimplement(const char *field_name)
}
static VALUE
-statx_birthtime(const struct statx *stx, VALUE fname)
+statx_birthtime(const rb_io_stat_data *stx)
{
if (!statx_has_birthtime(stx)) {
/* birthtime is not supported on the filesystem */
@@ -1286,20 +1443,27 @@ statx_birthtime(const struct statx *stx, VALUE fname)
return rb_time_nano_new((time_t)stx->stx_btime.tv_sec, stx->stx_btime.tv_nsec);
}
-typedef struct statx statx_data;
-# define HAVE_STAT_BIRTHTIME
+#else
-#elif defined(HAVE_STAT_BIRTHTIME)
# define statx_without_gvl(path, st, mask) stat_without_gvl(path, st)
# define fstatx_without_gvl(fptr, st, mask) fstat_without_gvl(fptr, st)
-# define statx_birthtime(st, fname) stat_birthtime(st)
+# define lstatx_without_gvl(path, st, mask) lstat_without_gvl(path, st)
+# define rb_statx(file, stx, mask) rb_stat(file, stx)
+# define STATX(path, st, mask) STAT(path, st)
+
+#if defined(HAVE_STAT_BIRTHTIME)
# define statx_has_birthtime(st) 1
-# define rb_statx(file, st, mask) rb_stat(file, st)
#else
# define statx_has_birthtime(st) 0
+#endif
+
#endif /* !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
defined(HAVE_STRUCT_STATX_STX_BTIME) */
+#ifndef FSTAT
+# define FSTAT(fd, st) fstat(fd, st)
+#endif
+
static int
rb_stat(VALUE file, struct stat *st)
{
@@ -1336,14 +1500,14 @@ rb_stat(VALUE file, struct stat *st)
static VALUE
rb_file_s_stat(VALUE klass, VALUE fname)
{
- struct stat st;
+ rb_io_stat_data st;
FilePathValue(fname);
fname = rb_str_encode_ospath(fname);
- if (stat_without_gvl(RSTRING_PTR(fname), &st) < 0) {
+ if (statx_without_gvl(RSTRING_PTR(fname), &st, STATX_ALL) < 0) {
rb_sys_fail_path(fname);
}
- return rb_stat_new(&st);
+ return rb_statx_new(&st);
}
/*
@@ -1365,13 +1529,13 @@ static VALUE
rb_io_stat(VALUE obj)
{
rb_io_t *fptr;
- struct stat st;
+ rb_io_stat_data st;
GetOpenFile(obj, fptr);
- if (fstat(fptr->fd, &st) == -1) {
+ if (fstatx_without_gvl(fptr, &st, STATX_ALL) == -1) {
rb_sys_fail_path(fptr->pathv);
}
- return rb_stat_new(&st);
+ return rb_statx_new(&st);
}
#ifdef HAVE_LSTAT
@@ -1411,14 +1575,14 @@ static VALUE
rb_file_s_lstat(VALUE klass, VALUE fname)
{
#ifdef HAVE_LSTAT
- struct stat st;
+ rb_io_stat_data st;
FilePathValue(fname);
fname = rb_str_encode_ospath(fname);
- if (lstat_without_gvl(StringValueCStr(fname), &st) == -1) {
+ if (lstatx_without_gvl(StringValueCStr(fname), &st, STATX_ALL) == -1) {
rb_sys_fail_path(fname);
}
- return rb_stat_new(&st);
+ return rb_statx_new(&st);
#else
return rb_file_s_stat(klass, fname);
#endif
@@ -1443,16 +1607,16 @@ rb_file_lstat(VALUE obj)
{
#ifdef HAVE_LSTAT
rb_io_t *fptr;
- struct stat st;
+ rb_io_stat_data st;
VALUE path;
GetOpenFile(obj, fptr);
if (NIL_P(fptr->pathv)) return Qnil;
path = rb_str_encode_ospath(fptr->pathv);
- if (lstat_without_gvl(RSTRING_PTR(path), &st) == -1) {
+ if (lstatx_without_gvl(RSTRING_PTR(path), &st, STATX_ALL) == -1) {
rb_sys_fail_path(fptr->pathv);
}
- return rb_stat_new(&st);
+ return rb_statx_new(&st);
#else
return rb_io_stat(obj);
#endif
@@ -2063,7 +2227,7 @@ rb_file_size_p(VALUE obj, VALUE fname)
* File.owned?(file_name) -> true or false
*
* Returns <code>true</code> if the named file exists and the
- * effective used id of the calling process is the owner of
+ * effective user id of the calling process is the owner of
* the file.
*
* _file_name_ can be an IO object.
@@ -2237,36 +2401,36 @@ rb_file_s_size(VALUE klass, VALUE fname)
}
static VALUE
-rb_file_ftype(const struct stat *st)
+rb_file_ftype(mode_t mode)
{
const char *t;
- if (S_ISREG(st->st_mode)) {
+ if (S_ISREG(mode)) {
t = "file";
}
- else if (S_ISDIR(st->st_mode)) {
+ else if (S_ISDIR(mode)) {
t = "directory";
}
- else if (S_ISCHR(st->st_mode)) {
+ else if (S_ISCHR(mode)) {
t = "characterSpecial";
}
#ifdef S_ISBLK
- else if (S_ISBLK(st->st_mode)) {
+ else if (S_ISBLK(mode)) {
t = "blockSpecial";
}
#endif
#ifdef S_ISFIFO
- else if (S_ISFIFO(st->st_mode)) {
+ else if (S_ISFIFO(mode)) {
t = "fifo";
}
#endif
#ifdef S_ISLNK
- else if (S_ISLNK(st->st_mode)) {
+ else if (S_ISLNK(mode)) {
t = "link";
}
#endif
#ifdef S_ISSOCK
- else if (S_ISSOCK(st->st_mode)) {
+ else if (S_ISSOCK(mode)) {
t = "socket";
}
#endif
@@ -2274,7 +2438,7 @@ rb_file_ftype(const struct stat *st)
t = "unknown";
}
- return rb_usascii_str_new2(t);
+ return rb_fstring_cstr(t);
}
/*
@@ -2303,19 +2467,30 @@ rb_file_s_ftype(VALUE klass, VALUE fname)
rb_sys_fail_path(fname);
}
- return rb_file_ftype(&st);
+ return rb_file_ftype(st.st_mode);
}
/*
* call-seq:
- * File.atime(file_name) -> time
+ * File.atime(object) -> new_time
*
- * Returns the last access time for the named file as a Time object.
+ * Returns a new Time object containing the time of the most recent
+ * access (read or write) to the object,
+ * which may be a string filepath or dirpath, or a File or Dir object:
*
- * _file_name_ can be an IO object.
+ * filepath = 't.tmp'
+ * File.exist?(filepath) # => false
+ * File.atime(filepath) # Raises Errno::ENOENT.
+ * File.write(filepath, 'foo')
+ * File.atime(filepath) # => 2026-03-31 16:39:37.9290772 -0500
+ * File.write(filepath, 'bar')
+ * File.atime(filepath) # => 2026-03-31 16:39:57.7710876 -0500
*
- * File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003
+ * File.atime('.') # => 2026-03-31 16:47:49.0970483 -0500
+ * File.atime(File.new('README.md')) # => 2026-03-31 11:15:27.8215934 -0500
+ * File.atime(Dir.new('.')) # => 2026-03-31 12:39:45.5910591 -0500
*
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -2328,18 +2503,27 @@ rb_file_s_atime(VALUE klass, VALUE fname)
FilePathValue(fname);
rb_syserr_fail_path(e, fname);
}
- return stat_atime(&st);
+ return stat_time(stat_atimespec(&st));
}
/*
* call-seq:
- * file.atime -> time
- *
- * Returns the last access time (a Time object) for <i>file</i>, or
- * epoch if <i>file</i> has not been accessed.
- *
- * File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
- *
+ * atime -> new_time
+ *
+ * Returns a new Time object containing the time of the most recent
+ * access (read or write) to the file represented by +self+:
+ *
+ * filepath = 't.tmp'
+ * file = File.new(filepath, 'a+')
+ * file.atime # => 2026-03-31 17:11:27.7285397 -0500
+ * file.write('foo')
+ * file.atime # => 2026-03-31 17:11:27.7285397 -0500 # Unchanged; not yet written.
+ * file.flush
+ * file.atime # => 2026-03-31 17:12:11.3408054 -0500 # Changed; now written.
+ * file.close
+ * File.delete(filename)
+ *
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
@@ -2352,7 +2536,7 @@ rb_file_atime(VALUE obj)
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail_path(fptr->pathv);
}
- return stat_atime(&st);
+ return stat_time(stat_atimespec(&st));
}
/*
@@ -2377,7 +2561,7 @@ rb_file_s_mtime(VALUE klass, VALUE fname)
FilePathValue(fname);
rb_syserr_fail_path(e, fname);
}
- return stat_mtime(&st);
+ return stat_time(stat_mtimespec(&st));
}
/*
@@ -2400,7 +2584,7 @@ rb_file_mtime(VALUE obj)
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail_path(fptr->pathv);
}
- return stat_mtime(&st);
+ return stat_time(stat_mtimespec(&st));
}
/*
@@ -2429,7 +2613,7 @@ rb_file_s_ctime(VALUE klass, VALUE fname)
FilePathValue(fname);
rb_syserr_fail_path(e, fname);
}
- return stat_ctime(&st);
+ return stat_time(stat_ctimespec(&st));
}
/*
@@ -2455,35 +2639,40 @@ rb_file_ctime(VALUE obj)
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail_path(fptr->pathv);
}
- return stat_ctime(&st);
+ return stat_time(stat_ctimespec(&st));
}
#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
- * File.birthtime(file_name) -> time
- *
- * Returns the birth time for the named file.
+ * File.birthtime(entry_path) -> new_time
*
- * _file_name_ can be an IO object.
- *
- * File.birthtime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
+ * Returns a new Time object containing the create time
+ * of the entry at the given +path+:
*
- * If the platform doesn't have birthtime, raises NotImplementedError.
+ * path = 't.tmp'
+ * File.birthtime(path) # Raises Errno::ENOENT: No such file or directory
+ * File.write(path, 'foo')
+ * File.birthtime(path) # => 2026-04-14 11:10:43.2891695 -0500
+ * File.write(path, 'bar')
+ * File.birthtime(path) # => 2026-04-14 11:10:43.2891695 -0500
+ * File.delete(path)
+ * File.birthtime(path) # Raises Errno::ENOENT: No such file or directory
*
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
VALUE
rb_file_s_birthtime(VALUE klass, VALUE fname)
{
- statx_data st;
+ rb_io_stat_data st;
if (rb_statx(fname, &st, STATX_BTIME) < 0) {
int e = errno;
FilePathValue(fname);
rb_syserr_fail_path(e, fname);
}
- return statx_birthtime(&st, fname);
+ return statx_birthtime(&st);
}
#else
# define rb_file_s_birthtime rb_f_notimplement
@@ -2492,27 +2681,34 @@ rb_file_s_birthtime(VALUE klass, VALUE fname)
#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
- * file.birthtime -> time
- *
- * Returns the birth time for <i>file</i>.
+ * birthtime -> new_time
*
- * File.new("testfile").birthtime #=> Wed Apr 09 08:53:14 CDT 2003
+ * Returns a new Time object containing the create time for +self+:
*
- * If the platform doesn't have birthtime, raises NotImplementedError.
+ * filepath = 't.tmp'
+ * File.write(filepath, 'foo')
+ * file = File.new(filepath)
+ * file.birthtime # => 2026-04-14 15:53:45.002656 -0500
+ * File.write(filepath, 'bar')
+ * file.birthtime # => 2026-04-14 15:53:45.002656 -0500
+ * file.close
+ * File.delete(filepath)
+ * file.birthtime # Raises IOError: closed stream
*
+ * See {File System Timestamps}[rdoc-ref:file/timestamps.md].
*/
static VALUE
rb_file_birthtime(VALUE obj)
{
rb_io_t *fptr;
- statx_data st;
+ rb_io_stat_data st;
GetOpenFile(obj, fptr);
if (fstatx_without_gvl(fptr, &st, STATX_BTIME) == -1) {
rb_sys_fail_path(fptr->pathv);
}
- return statx_birthtime(&st, fptr->pathv);
+ return statx_birthtime(&st);
}
#else
# define rb_file_birthtime rb_f_notimplement
@@ -2625,11 +2821,11 @@ io_blocking_fchmod(void *ptr)
}
static int
-rb_fchmod(int fd, mode_t mode)
+rb_fchmod(struct rb_io* io, mode_t mode)
{
(void)rb_chmod; /* suppress unused-function warning when HAVE_FCHMOD */
- struct nogvl_fchmod_data data = {.fd = fd, .mode = mode};
- return (int)rb_thread_io_blocking_region(io_blocking_fchmod, &data, fd);
+ struct nogvl_fchmod_data data = {.fd = io->fd, .mode = mode};
+ return (int)rb_thread_io_blocking_region(io, io_blocking_fchmod, &data);
}
#endif
@@ -2659,7 +2855,7 @@ rb_file_chmod(VALUE obj, VALUE vmode)
GetOpenFile(obj, fptr);
#ifdef HAVE_FCHMOD
- if (rb_fchmod(fptr->fd, mode) == -1) {
+ if (rb_fchmod(fptr, mode) == -1) {
if (HAVE_FCHMOD || errno != ENOSYS)
rb_sys_fail_path(fptr->pathv);
}
@@ -3028,7 +3224,7 @@ static int
utime_internal(const char *path, void *arg)
{
struct utime_args *v = arg;
- const struct timespec *tsp = v->tsp;
+ const stat_timestamp *tsp = v->tsp;
struct utimbuf utbuf, *utp = NULL;
if (tsp) {
utbuf.actime = tsp[0].tv_sec;
@@ -3287,7 +3483,7 @@ unlink_internal(const char *path, void *arg)
* Since the underlying implementation relies on the
* <code>unlink(2)</code> system call, the type of
* exception raised depends on its error type (see
- * https://linux.die.net/man/2/unlink) and has the form of
+ * https://man7.org/linux/man-pages/man2/unlink.2.html) and has the form of
* e.g. Errno::ENOENT.
*
* See also Dir::rmdir.
@@ -3433,8 +3629,10 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
# define isADS(x) 0
#endif
-#define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc)))
-#define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
+#define enc_mbclen_needed(enc) (!rb_str_encindex_fastpath(rb_enc_to_index(enc)))
+
+#define Next(p, e, mb_enc, enc) ((p) + ((mb_enc) ? rb_enc_mbclen((p), (e), (enc)) : 1))
+#define Inc(p, e, mb_enc, enc) ((p) = Next((p), (e), (mb_enc), (enc)))
#if defined(DOSISH_UNC)
#define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
@@ -3498,7 +3696,7 @@ not_same_drive(VALUE path, int drive)
#endif /* DOSISH_DRIVE_LETTER */
static inline char *
-skiproot(const char *path, const char *end, rb_encoding *enc)
+skiproot(const char *path, const char *end)
{
#ifdef DOSISH_DRIVE_LETTER
if (path + 2 <= end && has_drive_letter(path)) path += 2;
@@ -3507,57 +3705,76 @@ skiproot(const char *path, const char *end, rb_encoding *enc)
return (char *)path;
}
-#define nextdirsep rb_enc_path_next
-char *
-rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
+static inline char *
+enc_path_next(const char *s, const char *e, bool mb_enc, rb_encoding *enc)
{
while (s < e && !isdirsep(*s)) {
- Inc(s, e, enc);
+ Inc(s, e, mb_enc, enc);
}
return (char *)s;
}
+#define nextdirsep rb_enc_path_next
+char *
+rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
+{
+ return enc_path_next(s, e, enc_mbclen_needed(enc), enc);
+}
+
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
-#define skipprefix rb_enc_path_skip_prefix
+#define skipprefix enc_path_skip_prefix
#else
-#define skipprefix(path, end, enc) (path)
+#define skipprefix(path, end, mb_enc, enc) (path)
#endif
-char *
-rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
+static inline char *
+enc_path_skip_prefix(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
{
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
#ifdef DOSISH_UNC
if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
path += 2;
while (path < end && isdirsep(*path)) path++;
- if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
- path = rb_enc_path_next(path + 1, end, enc);
+ if ((path = enc_path_next(path, end, mb_enc, enc)) < end &&
+ path + 2 <= end && !isdirsep(path[1])) {
+ path = enc_path_next(path + 1, end, mb_enc, enc);
+ }
return (char *)path;
}
#endif
#ifdef DOSISH_DRIVE_LETTER
- if (has_drive_letter(path))
+ if (path + 2 <= end && has_drive_letter(path))
return (char *)(path + 2);
#endif
#endif /* defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) */
return (char *)path;
}
+char *
+rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
+{
+ return enc_path_skip_prefix(path, end, enc_mbclen_needed(enc), enc);
+}
+
static inline char *
skipprefixroot(const char *path, const char *end, rb_encoding *enc)
{
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
- char *p = skipprefix(path, end, enc);
- while (isdirsep(*p)) p++;
+ char *p = skipprefix(path, end, enc_mbclen_needed(enc), enc);
+ while (p < end && isdirsep(*p)) p++;
return p;
#else
- return skiproot(path, end, enc);
+ return skiproot(path, end);
#endif
}
-#define strrdirsep rb_enc_path_last_separator
char *
-rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
+rb_enc_path_skip_prefix_root(const char *path, const char *end, rb_encoding *enc)
+{
+ return skipprefixroot(path, end, enc);
+}
+
+static char *
+enc_path_last_separator(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
{
char *last = NULL;
while (path < end) {
@@ -3568,14 +3785,44 @@ rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
last = (char *)tmp;
}
else {
- Inc(path, end, enc);
+ Inc(path, end, mb_enc, enc);
}
}
return last;
}
+char *
+rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
+{
+ return enc_path_last_separator(path, end, enc_mbclen_needed(enc), enc);
+}
+
+static inline char *
+strrdirsep(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
+{
+ if (RB_UNLIKELY(mb_enc)) {
+ return enc_path_last_separator(path, end, mb_enc, enc);
+ }
+
+ const char *cursor = end - 1;
+
+ while (isdirsep(cursor[0])) {
+ cursor--;
+ }
+
+ while (cursor >= path) {
+ if (isdirsep(cursor[0])) {
+ while (cursor > path && isdirsep(cursor[-1])) {
+ cursor--;
+ }
+ return (char *)cursor;
+ }
+ cursor--;
+ }
+ return NULL;
+}
static char *
-chompdirsep(const char *path, const char *end, rb_encoding *enc)
+chompdirsep(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
{
while (path < end) {
if (isdirsep(*path)) {
@@ -3584,7 +3831,7 @@ chompdirsep(const char *path, const char *end, rb_encoding *enc)
if (path >= end) return (char *)last;
}
else {
- Inc(path, end, enc);
+ Inc(path, end, mb_enc, enc);
}
}
return (char *)path;
@@ -3594,13 +3841,13 @@ char *
rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
{
if (path < end && isdirsep(*path)) path++;
- return chompdirsep(path, end, enc);
+ return chompdirsep(path, end, enc_mbclen_needed(enc), enc);
}
static rb_encoding *
fs_enc_check(VALUE path1, VALUE path2)
{
- rb_encoding *enc = rb_enc_check(path1, path2);
+ rb_encoding *enc = rb_enc_check_str(path1, path2);
int encidx = rb_enc_to_index(enc);
if (encidx == ENCINDEX_US_ASCII) {
encidx = rb_enc_get_index(path1);
@@ -3615,6 +3862,7 @@ fs_enc_check(VALUE path1, VALUE path2)
static char *
ntfs_tail(const char *path, const char *end, rb_encoding *enc)
{
+ bool mb_enc = enc_mbclen_needed(enc);
while (path < end && *path == '.') path++;
while (path < end && !isADS(*path)) {
if (istrailinggarbage(*path)) {
@@ -3629,7 +3877,7 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
if (isADS(*path)) path++;
}
else {
- Inc(path, end, enc);
+ Inc(path, end, mb_enc, enc);
}
}
return (char *)path;
@@ -3677,10 +3925,6 @@ static VALUE
copy_home_path(VALUE result, const char *dir)
{
char *buf;
-#if defined DOSISH || defined __CYGWIN__
- char *p, *bend;
- rb_encoding *enc;
-#endif
long dirlen;
int encidx;
@@ -3689,10 +3933,11 @@ copy_home_path(VALUE result, const char *dir)
memcpy(buf = RSTRING_PTR(result), dir, dirlen);
encidx = rb_filesystem_encindex();
rb_enc_associate_index(result, encidx);
-#if defined DOSISH || defined __CYGWIN__
- enc = rb_enc_from_index(encidx);
- for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
- if (*p == '\\') {
+#if defined FILE_ALT_SEPARATOR
+ rb_encoding *enc = rb_enc_from_index(encidx);
+ bool mb_enc = enc_mbclen_needed(enc);
+ for (char *p = buf, *bend = p + dirlen; p < bend; Inc(p, bend, mb_enc, enc)) {
+ if (*p == FILE_ALT_SEPARATOR) {
*p = '/';
}
}
@@ -3845,16 +4090,21 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
s = StringValuePtr(fname);
fend = s + RSTRING_LEN(fname);
- enc = rb_enc_get(fname);
+ enc = rb_str_enc_get(fname);
+ bool mb_enc = enc_mbclen_needed(enc);
+ if (!mb_enc && RTEST(dname)) {
+ mb_enc = enc_mbclen_needed(rb_str_enc_get(dname));
+ }
+
BUFINIT();
- if (s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
+ if (s < fend && s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
long userlen = 0;
- if (isdirsep(s[1]) || s[1] == '\0') {
+ if (s + 1 == fend || isdirsep(s[1])) {
buf = 0;
b = 0;
rb_str_set_len(result, 0);
- if (*++s) ++s;
+ if (++s < fend) ++s;
rb_default_home_dir(result);
}
else {
@@ -3884,8 +4134,8 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
#ifdef DOSISH_DRIVE_LETTER
/* skip drive letter */
- else if (has_drive_letter(s)) {
- if (isdirsep(s[2])) {
+ else if (s + 1 < fend && has_drive_letter(s)) {
+ if (s + 2 < fend && isdirsep(s[2])) {
/* specified drive letter, and full path */
/* skip drive letter */
BUFCHECK(bdiff + 2 >= buflen);
@@ -3914,12 +4164,12 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
rb_enc_associate(result, enc = fs_enc_check(result, fname));
p = pend;
}
- p = chompdirsep(skiproot(buf, p, enc), p, enc);
+ p = chompdirsep(skiproot(buf, p), p, mb_enc, enc);
s += 2;
}
}
#endif /* DOSISH_DRIVE_LETTER */
- else if (!rb_is_absolute_path(s)) {
+ else if (s == fend || !rb_is_absolute_path(s)) {
if (!NIL_P(dname)) {
rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result);
rb_enc_associate(result, fs_enc_check(result, fname));
@@ -3931,20 +4181,20 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
BUFINIT();
p = e;
}
-#if defined DOSISH || defined __CYGWIN__
- if (isdirsep(*s)) {
+#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
+ if (s < fend && isdirsep(*s)) {
/* specified full path, but not drive letter nor UNC */
/* we need to get the drive letter or UNC share name */
- p = skipprefix(buf, p, enc);
+ p = skipprefix(buf, p, mb_enc, enc);
}
else
-#endif /* defined DOSISH || defined __CYGWIN__ */
- p = chompdirsep(skiproot(buf, p, enc), p, enc);
+#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
+ p = chompdirsep(skiproot(buf, p), p, mb_enc, enc);
}
else {
size_t len;
b = s;
- do s++; while (isdirsep(*s));
+ do s++; while (s < fend && isdirsep(*s));
len = s - b;
p = buf + len;
BUFCHECK(bdiff >= buflen);
@@ -3963,23 +4213,24 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
rb_str_set_len(result, p-buf+1);
BUFCHECK(bdiff + 1 >= buflen);
p[1] = 0;
- root = skipprefix(buf, p+1, enc);
+ root = skipprefix(buf, p+1, mb_enc, enc);
b = s;
- while (*s) {
+ while (s < fend) {
switch (*s) {
case '.':
if (b == s++) { /* beginning of path element */
- switch (*s) {
- case '\0':
+ if (s == fend) {
b = s;
break;
+ }
+ switch (*s) {
case '.':
- if (*(s+1) == '\0' || isdirsep(*(s+1))) {
+ if (s+1 == fend || isdirsep(*(s+1))) {
/* We must go back to the parent */
char *n;
*p = '\0';
- if (!(n = strrdirsep(root, p, enc))) {
+ if (!(n = strrdirsep(root, p, mb_enc, enc))) {
*p = '/';
}
else {
@@ -3989,13 +4240,13 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
#if USE_NTFS
else {
- do ++s; while (istrailinggarbage(*s));
+ do ++s; while (s < fend && istrailinggarbage(*s));
}
#endif /* USE_NTFS */
break;
case '/':
-#if defined DOSISH || defined __CYGWIN__
- case '\\':
+#if defined FILE_ALT_SEPARATOR
+ case FILE_ALT_SEPARATOR:
#endif
b = ++s;
break;
@@ -4019,8 +4270,8 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
#endif /* USE_NTFS */
break;
case '/':
-#if defined DOSISH || defined __CYGWIN__
- case '\\':
+#if defined FILE_ALT_SEPARATOR
+ case FILE_ALT_SEPARATOR:
#endif
if (s > b) {
WITH_ROOTDIFF(BUFCOPY(b, s-b));
@@ -4042,7 +4293,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
}
#endif /* __APPLE__ */
- Inc(s, fend, enc);
+ Inc(s, fend, mb_enc, enc);
break;
}
}
@@ -4070,7 +4321,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
BUFCOPY(b, s-b);
rb_str_set_len(result, p-buf);
}
- if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
+ if (p == skiproot(buf, p + !!*p) - 1) p++;
#if USE_NTFS
*p = '\0';
@@ -4228,31 +4479,43 @@ rb_file_s_expand_path(int argc, const VALUE *argv)
}
/*
+ * :markup: markdown
+ *
* call-seq:
- * File.expand_path(file_name [, dir_string] ) -> abs_file_name
+ * File.expand_path(path, dirpath = '.') -> absolute_path
*
- * Converts a pathname to an absolute pathname. Relative paths are
- * referenced from the current working directory of the process unless
- * +dir_string+ is given, in which case it will be used as the
- * starting point. The given pathname may start with a
- * ``<code>~</code>'', which expands to the process owner's home
- * directory (the environment variable +HOME+ must be set
- * correctly). ``<code>~</code><i>user</i>'' expands to the named
- * user's home directory.
+ * Returns the string absolute path for the given `path`.
+ *
+ * Evaluates a relative path with respect to the directory given by `dirpath`:
+ *
+ * ```ruby
+ * Dir.chdir('/snap')
+ * # Default dirpath.
+ * File.expand_path('README') # => "/snap/README"
+ * File.expand_path('bin') # => "/snap/bin"
+ * File.expand_path('bin/../var') # => "/snap/var" # Cleaned.
+ * # Other dirpath.
+ * File.expand_path('../zip', '/usr/bin/ruby') # => "/usr/bin/zip"
+ * Dir.chdir('/usr/bin')
+ * File.expand_path('../../snap', __FILE__) # => "/usr/snap"
+ * ```
*
- * File.expand_path("~oracle/bin") #=> "/home/oracle/bin"
+ * Evaluates an absolute path without respect to `dirpath`:
*
- * A simple example of using +dir_string+ is as follows.
- * File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby"
+ * ```ruby
+ * File.expand_path('/snap') # => "/snap"
+ * File.expand_path('/snap', 'nosuch') # => "/snap"
+ * File.expand_path('/snap/../snap') # => "/snap" # Cleaned.
+ * ```
*
- * A more complex example which also resolves parent directory is as follows.
- * Suppose we are in bin/mygem and want the absolute path of lib/mygem.rb.
+ * More examples:
*
- * File.expand_path("../../lib/mygem.rb", __FILE__)
- * #=> ".../path/to/project/lib/mygem.rb"
+ * ```
+ * Dir.chdir('/usr/bin')
+ * File.expand_path('../../snap', __FILE__) # => "/usr/snap"
+ * File.expand_path('../../snap') # => "/snap"
+ * ```
*
- * So first it resolves the parent of __FILE__, that is bin/, then go to the
- * parent, the root of the project and appends +lib/mygem.rb+.
*/
static VALUE
@@ -4340,9 +4603,10 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
}
else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') {
if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
+ bool mb_enc = enc_mbclen_needed(enc);
const char *resolved_str = RSTRING_PTR(*resolvedp);
const char *resolved_names = resolved_str + *prefixlenp;
- const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc);
+ const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), mb_enc, enc);
long len = lastsep ? lastsep - resolved_names : 0;
rb_str_resize(*resolvedp, *prefixlenp + len);
}
@@ -4482,7 +4746,8 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
root_found:
RSTRING_GETMEM(resolved, prefixptr, prefixlen);
pend = prefixptr + prefixlen;
- ptr = chompdirsep(prefixptr, pend, enc);
+ bool mb_enc = enc_mbclen_needed(enc);
+ ptr = chompdirsep(prefixptr, pend, mb_enc, enc);
if (ptr < pend) {
prefixlen = ++ptr - prefixptr;
rb_str_set_len(resolved, prefixlen);
@@ -4492,7 +4757,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
if (*prefixptr == FILE_ALT_SEPARATOR) {
*prefixptr = '/';
}
- Inc(prefixptr, pend, enc);
+ Inc(prefixptr, pend, mb_enc, enc);
}
#endif
@@ -4528,7 +4793,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
return resolved;
}
-static VALUE rb_file_join(VALUE ary);
+static VALUE rb_file_join(long argc, VALUE *args);
#ifndef HAVE_REALPATH
static VALUE
@@ -4569,17 +4834,22 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
unresolved_path = rb_str_dup_frozen(path);
if (*RSTRING_PTR(unresolved_path) != '/' && !NIL_P(basedir)) {
- unresolved_path = rb_file_join(rb_assoc_new(basedir, unresolved_path));
+ VALUE paths[2] = {basedir, unresolved_path};
+ unresolved_path = rb_file_join(2, paths);
}
if (origenc) unresolved_path = TO_OSPATH(unresolved_path);
if ((resolved_ptr = realpath(RSTRING_PTR(unresolved_path), resolved_buffer)) == NULL) {
- /* glibc realpath(3) does not allow /path/to/file.rb/../other_file.rb,
+ /*
+ wasi-libc 22 and later support realpath(3) but return ENOTSUP
+ when the underlying host syscall returns it.
+ glibc realpath(3) does not allow /path/to/file.rb/../other_file.rb,
returning ENOTDIR in that case.
glibc realpath(3) can also return ENOENT for paths that exist,
such as /dev/fd/5.
Fallback to the emulated approach in either of those cases. */
- if (errno == ENOTDIR ||
+ if (errno == ENOTSUP ||
+ errno == ENOTDIR ||
(errno == ENOENT && rb_file_exist_p(0, unresolved_path))) {
return rb_check_realpath_emulate(basedir, path, origenc, mode);
@@ -4594,7 +4864,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
free(resolved_ptr);
# endif
-# if !defined(__LINUX__) && !defined(__APPLE__)
+# if !defined(__linux__) && !defined(__APPLE__)
/* As `resolved` is a String in the filesystem encoding, no
* conversion is needed */
struct stat st;
@@ -4604,7 +4874,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 /* !defined(__linux__) && !defined(__APPLE__) */
if (origenc && origenc != rb_enc_get(resolved)) {
if (!rb_enc_str_asciionly_p(resolved)) {
@@ -4731,23 +5001,29 @@ rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc)
return 0;
}
-const char *
-ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
+static inline const char *
+enc_find_basename(const char *name, long *baselen, long *alllen, bool mb_enc, rb_encoding *enc)
{
const char *p, *q, *e, *end;
-#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
- const char *root;
-#endif
long f = 0, n = -1;
- end = name + (alllen ? (size_t)*alllen : strlen(name));
- name = skipprefix(name, end, enc);
+ long len = (alllen ? (size_t)*alllen : strlen(name));
+
+ if (len <= 0) {
+ return name;
+ }
+
+ end = name + len;
+ name = skipprefix(name, end, mb_enc, enc);
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
- root = name;
+ const char *root = name;
#endif
- while (isdirsep(*name))
+
+ while (name < end && isdirsep(*name)) {
name++;
- if (!*name) {
+ }
+
+ if (name == end) {
p = name - 1;
f = 1;
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
@@ -4768,91 +5044,127 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
}
else {
- if (!(p = strrdirsep(name, end, enc))) {
+ p = strrdirsep(name, end, mb_enc, enc);
+ if (!p) {
p = name;
}
else {
- while (isdirsep(*p)) p++; /* skip last / */
+ while (isdirsep(*p)) {
+ p++; /* skip last / */
+ }
}
#if USE_NTFS
n = ntfs_tail(p, end, enc) - p;
#else
- n = chompdirsep(p, end, enc) - p;
+ n = chompdirsep(p, end, mb_enc, enc) - p;
#endif
for (q = p; q - p < n && *q == '.'; q++);
- for (e = 0; q - p < n; Inc(q, end, enc)) {
+ for (e = 0; q - p < n; Inc(q, end, mb_enc, enc)) {
if (*q == '.') e = q;
}
- if (e) f = e - p;
- else f = n;
+ if (e) {
+ f = e - p;
+ }
+ else {
+ f = n;
+ }
}
- if (baselen)
+ if (baselen) {
*baselen = f;
- if (alllen)
+ }
+ if (alllen) {
*alllen = n;
+ }
return p;
}
+const char *
+ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
+{
+ return enc_find_basename(name, baselen, alllen, enc_mbclen_needed(enc), enc);
+}
+
/*
* call-seq:
- * File.basename(file_name [, suffix] ) -> base_name
+ * File.basename(path, suffix = '') -> new_string
*
- * Returns the last component of the filename given in
- * <i>file_name</i> (after first stripping trailing separators),
- * which can be formed using both File::SEPARATOR and
- * File::ALT_SEPARATOR as the separator when File::ALT_SEPARATOR is
- * not <code>nil</code>. If <i>suffix</i> is given and present at the
- * end of <i>file_name</i>, it is removed. If <i>suffix</i> is ".*",
- * any extension will be removed.
+ * Returns a new string containing all or part of the last entry of the given +path+.
+ * Entries are delimited by the value of constant File::SEPARATOR
+ * and, if non-nil, the value of constant File::ALT_SEPARATOR.
+ *
+ * When +suffix+ is the empty string <tt>''</tt>,
+ * returns all of the last entry:
+ *
+ * File.basename('foo/bar/baz/bat.txt') # => "bat.txt"
+ * File.basename('foo/bar/baz') # => "baz"
+ *
+ * File::SEPARATOR # => "/"
+ * File.basename('foo/bar.txt////') # => "bar.txt"
+ * File::ALT_SEPARATOR # => "\\" # On Windows.
+ * File.basename('foo/bar.txt//\\\\//') # => "bar.txt"
+ *
+ * When +suffix+ is <tt>'.*'</tt>,
+ * the last {filename extension}[https://en.wikipedia.org/wiki/Filename_extension],
+ * if any, is removed:
+ *
+ * File.basename('foo/bar.txt', '.*') # => "bar"
+ * File.basename('foo/bar.txt.old', '.*') # => "bar.txt"
+ * File.basename('foo/bar', '.*') # => "bar"
+ *
+ * When +suffix+ is any string other than <tt>''</tt> or <tt>'.*'</tt>,
+ * the matching trailing substring, if any, is removed:
+ *
+ * File.basename('foo/bar.txt', '.txt') # => "bar"
+ * File.basename('foo/bar.txt', 'txt') # => "bar."
+ * File.basename('foo/bar.txt', '*') # => "bar.txt"
+ * File.basename('foo/bar.txt', '.') # => "bar.txt"
*
- * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
- * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
- * File.basename("/home/gumby/work/ruby.rb", ".*") #=> "ruby"
*/
static VALUE
rb_file_s_basename(int argc, VALUE *argv, VALUE _)
{
- VALUE fname, fext, basename;
- const char *name, *p;
- long f, n;
+ VALUE fname, fext = Qnil;
+ const char *name, *p, *fp = 0;
+ long f = 0, n;
rb_encoding *enc;
- fext = Qnil;
- if (rb_check_arity(argc, 1, 2) == 2) {
+ argc = rb_check_arity(argc, 1, 2);
+ fname = argv[0];
+ CheckPath(fname, name);
+ if (argc == 2) {
fext = argv[1];
- StringValue(fext);
- enc = check_path_encoding(fext);
+ fp = StringValueCStr(fext);
+ check_path_encoding(fext);
}
- fname = argv[0];
- FilePathStringValue(fname);
if (NIL_P(fext) || !(enc = rb_enc_compatible(fname, fext))) {
- enc = rb_enc_get(fname);
- fext = Qnil;
+ enc = rb_str_enc_get(fname);
}
- if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname)))
- return rb_str_new_shared(fname);
- p = ruby_enc_find_basename(name, &f, &n, enc);
+ n = RSTRING_LEN(fname);
+ if (n <= 0 || !*name) {
+ return rb_enc_str_new(0, 0, enc);
+ }
+
+ bool mb_enc = enc_mbclen_needed(enc);
+ p = enc_find_basename(name, &f, &n, mb_enc, enc);
if (n >= 0) {
- if (NIL_P(fext)) {
+ if (!fp) {
f = n;
}
else {
- const char *fp;
- fp = StringValueCStr(fext);
if (!(f = rmext(p, f, n, fp, RSTRING_LEN(fext), enc))) {
f = n;
}
RB_GC_GUARD(fext);
}
- if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname);
+ if (f == RSTRING_LEN(fname)) {
+ return rb_str_new_shared(fname);
+ }
}
- basename = rb_str_new(p, f);
- rb_enc_copy(basename, fname);
- return basename;
+ return rb_enc_str_new(p, f, enc);
}
static VALUE rb_file_dirname_n(VALUE fname, int n);
@@ -4897,19 +5209,18 @@ rb_file_dirname_n(VALUE fname, int n)
{
const char *name, *root, *p, *end;
VALUE dirname;
- rb_encoding *enc;
- VALUE sepsv = 0;
- const char **seps;
if (n < 0) rb_raise(rb_eArgError, "negative level: %d", n);
- FilePathStringValue(fname);
- name = StringValueCStr(fname);
+ CheckPath(fname, name);
end = name + RSTRING_LEN(fname);
- enc = rb_enc_get(fname);
- root = skiproot(name, end, enc);
+
+ bool mb_enc = !rb_str_enc_fastpath(fname);
+ rb_encoding *enc = rb_str_enc_get(fname);
+
+ root = skiproot(name, end);
#ifdef DOSISH_UNC
if (root > name + 1 && isdirsep(*name))
- root = skipprefix(name = root - 2, end, enc);
+ root = skipprefix(name = root - 2, end, mb_enc, enc);
#else
if (root > name + 1)
name = root - 1;
@@ -4918,72 +5229,41 @@ rb_file_dirname_n(VALUE fname, int n)
p = root;
}
else {
- int i;
- switch (n) {
- case 0:
- p = end;
- break;
- case 1:
- if (!(p = strrdirsep(root, end, enc))) p = root;
- break;
- default:
- seps = ALLOCV_N(const char *, sepsv, n);
- for (i = 0; i < n; ++i) seps[i] = root;
- i = 0;
- for (p = root; p < end; ) {
- if (isdirsep(*p)) {
- const char *tmp = p++;
- while (p < end && isdirsep(*p)) p++;
- if (p >= end) break;
- seps[i++] = tmp;
- if (i == n) i = 0;
- }
- else {
- Inc(p, end, enc);
- }
+ p = end;
+ while (n) {
+ if (!(p = strrdirsep(root, p, mb_enc, enc))) {
+ p = root;
+ break;
}
- p = seps[i];
- ALLOCV_END(sepsv);
- break;
+ n--;
}
}
- if (p == name)
- return rb_usascii_str_new2(".");
+
+ if (p == name) {
+ return rb_enc_str_new(".", 1, enc);
+ }
#ifdef DOSISH_DRIVE_LETTER
- if (has_drive_letter(name) && isdirsep(*(name + 2))) {
- const char *top = skiproot(name + 2, end, enc);
- dirname = rb_str_new(name, 3);
+ if (name + 3 < end && has_drive_letter(name) && isdirsep(*(name + 2))) {
+ const char *top = skiproot(name + 2, end);
+ dirname = rb_enc_str_new(name, 3, enc);
rb_str_cat(dirname, top, p - top);
}
else
#endif
- dirname = rb_str_new(name, p - name);
+ dirname = rb_enc_str_new(name, p - name, enc);
#ifdef DOSISH_DRIVE_LETTER
- if (has_drive_letter(name) && root == name + 2 && p - name == 2)
+ if (root == name + 2 && p == root && name[1] == ':')
rb_str_cat(dirname, ".", 1);
#endif
- rb_enc_copy(dirname, fname);
return dirname;
}
-/*
- * accept a String, and return the pointer of the extension.
- * if len is passed, set the length of extension to it.
- * returned pointer is in ``name'' or NULL.
- * returns *len
- * no dot NULL 0
- * dotfile top 0
- * end with dot dot 1
- * .ext dot len of .ext
- * .ext:stream dot len of .ext without :stream (NTFS only)
- *
- */
-const char *
-ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
+static inline const char *
+enc_find_extname(const char *name, long *len, bool mb_enc, rb_encoding *enc)
{
const char *p, *e, *end = name + (len ? *len : (long)strlen(name));
- p = strrdirsep(name, end, enc); /* get the last path component */
+ p = strrdirsep(name, end, mb_enc, enc); /* get the last path component */
if (!p)
p = name;
else
@@ -5016,7 +5296,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
#endif
else if (isdirsep(*p))
break;
- Inc(p, end, enc);
+ Inc(p, end, mb_enc, enc);
}
if (len) {
@@ -5032,57 +5312,106 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
}
/*
+ * accept a String, and return the pointer of the extension.
+ * if len is passed, set the length of extension to it.
+ * returned pointer is in ``name'' or NULL.
+ * returns *len
+ * no dot NULL 0
+ * dotfile top 0
+ * end with dot dot 1
+ * .ext dot len of .ext
+ * .ext:stream dot len of .ext without :stream (NTFS only)
+ *
+ */
+const char *
+ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
+{
+ return enc_find_extname(name, len, enc_mbclen_needed(enc), enc);
+}
+
+/*
+ * :markup: markdown
+ *
* call-seq:
- * File.extname(path) -> string
+ * File.extname(path) -> extension
+ *
+ * Returns the filename extension --
+ * usually the portion of the string `path`
+ * beginning from the last period:
+ *
+ * ```ruby
+ * File.extname('t.rb') # => ".rb"
+ * File.extname('foo.bar.t.rb') # => ".rb"
+ * File.extname('foo/bar/t.rb') # => ".rb"
+ * File.extname('nosuch.txt') # => ".txt" # Path need not exist.
+ * ```
*
- * Returns the extension (the portion of file name in +path+
- * starting from the last period).
+ * Returns the entire string when there is no period:
*
- * If +path+ is a dotfile, or starts with a period, then the starting
- * dot is not dealt with the start of the extension.
+ * ```ruby
+ * Pathname('foo').extname # => ""
+ * ```
*
- * An empty string will also be returned when the period is the last character
- * in +path+.
+ * Returns an empty string when the only period is the first character:
*
- * On Windows, trailing dots are truncated.
+ * ```ruby
+ * File.extname('.irbrc') # => ""
+ * ```
*
- * File.extname("test.rb") #=> ".rb"
- * File.extname("a/b/d/test.rb") #=> ".rb"
- * File.extname(".a/b/d/test.rb") #=> ".rb"
- * File.extname("foo.") #=> "" on Windows
- * File.extname("foo.") #=> "." on non-Windows
- * File.extname("test") #=> ""
- * File.extname(".profile") #=> ""
- * File.extname(".profile.sh") #=> ".sh"
+ * Returns an empty string or `'.'` when `path` ends with a period:
+ *
+ * ```
+ * File.extname('foo.') # => "" # On Windows.
+ * File.extname('foo.') # => "." # Elsewhere.
+ * File.extname('foo....') # => "" # On Windows.
+ * File.extname('foo....') # => "." # Elsewhere.
+ * ```
*
*/
static VALUE
rb_file_s_extname(VALUE klass, VALUE fname)
{
- const char *name, *e;
- long len;
- VALUE extname;
+ const char *name;
+ CheckPath(fname, name);
+ long len = RSTRING_LEN(fname);
- FilePathStringValue(fname);
- name = StringValueCStr(fname);
- len = RSTRING_LEN(fname);
- e = ruby_enc_find_extname(name, &len, rb_enc_get(fname));
- if (len < 1)
- return rb_str_new(0, 0);
- extname = rb_str_subseq(fname, e - name, len); /* keep the dot, too! */
- return extname;
+ if (len < 1) {
+ return rb_enc_str_new(0, 0, rb_str_enc_get(fname));
+ }
+
+ bool mb_enc = !rb_str_enc_fastpath(fname);
+ rb_encoding *enc = rb_str_enc_get(fname);
+
+ const char *ext = enc_find_extname(name, &len, mb_enc, enc);
+ return rb_enc_str_new(ext, len, enc);
}
/*
- * call-seq:
+ * call-seq:
* File.path(path) -> string
*
- * Returns the string representation of the path
+ * Returns the string representation of the path
*
* File.path(File::NULL) #=> "/dev/null"
* File.path(Pathname.new("/tmp")) #=> "/tmp"
*
+ * If +path+ is not a String:
+ *
+ * 1. If it has the +to_path+ method, that method will be called to
+ * coerce to a String.
+ *
+ * 2. Otherwise, or if the coerced result is not a String too, the
+ * standard coercion using +to_str+ method will take place on that
+ * object. (See also String.try_convert)
+ *
+ * The coerced string must satisfy the following conditions:
+ *
+ * 1. It must be in an ASCII-compatible encoding; otherwise, an
+ * Encoding::CompatibilityError is raised.
+ *
+ * 2. It must not contain the NUL character (<tt>\0</tt>); otherwise,
+ * an ArgumentError is raised.
*/
static VALUE
@@ -5109,15 +5438,17 @@ rb_file_s_split(VALUE klass, VALUE path)
return rb_assoc_new(rb_file_dirname(path), rb_file_s_basename(1,&path,Qundef));
}
+static VALUE rb_file_join_ary(VALUE ary);
+
static VALUE
file_inspect_join(VALUE ary, VALUE arg, int recur)
{
if (recur || ary == arg) rb_raise(rb_eArgError, "recursive array");
- return rb_file_join(arg);
+ return rb_file_join_ary(arg);
}
static VALUE
-rb_file_join(VALUE ary)
+rb_file_join_ary(VALUE ary)
{
long len, i;
VALUE result, tmp;
@@ -5165,11 +5496,11 @@ rb_file_join(VALUE ary)
rb_enc_copy(result, tmp);
}
else {
- tail = chompdirsep(name, name + len, rb_enc_get(result));
- if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) {
+ tail = chompdirsep(name, name + len, true, rb_enc_get(result));
+ if (RSTRING_LEN(tmp) > 0 && isdirsep(RSTRING_PTR(tmp)[0])) {
rb_str_set_len(result, tail - name);
}
- else if (!*tail) {
+ else if (tail == name + len) {
rb_str_cat(result, "/", 1);
}
}
@@ -5182,6 +5513,77 @@ rb_file_join(VALUE ary)
return result;
}
+static inline VALUE
+rb_file_join_fastpath(long argc, VALUE *args)
+{
+ long size = argc;
+
+ long i;
+ for (i = 0; i < argc; i++) {
+ VALUE tmp = args[i];
+ if (RB_LIKELY(RB_TYPE_P(tmp, T_STRING) && rb_str_enc_fastpath(tmp))) {
+ size += RSTRING_LEN(tmp);
+ }
+ else {
+ return 0;
+ }
+ }
+
+ VALUE result = rb_str_buf_new(size);
+
+ int encidx = ENCODING_GET_INLINED(args[0]);
+ ENCODING_SET_INLINED(result, encidx);
+ rb_str_buf_append(result, args[0]);
+
+ const char *name = RSTRING_PTR(result);
+ for (i = 1; i < argc; i++) {
+ VALUE tmp = args[i];
+ long len = RSTRING_LEN(result);
+
+ const char *tmp_s;
+ long tmp_len;
+ RSTRING_GETMEM(tmp, tmp_s, tmp_len);
+
+ if (tmp_len > 0 && isdirsep(tmp_s[0])) {
+ // right side has a leading separator, remove left side separators.
+ long chomp = len;
+ while (chomp > 0 && isdirsep(name[chomp - 1])) {
+ --chomp;
+ }
+ rb_str_set_len(result, chomp);
+ }
+ else if (len < 1 || !isdirsep(name[len - 1])) {
+ // neither side have a separator, append one;
+ rb_str_cat(result, "/", 1);
+ }
+
+ if (RB_UNLIKELY(ENCODING_GET_INLINED(tmp) != encidx)) {
+ rb_encoding *new_enc = fs_enc_check(result, tmp);
+ rb_enc_associate(result, new_enc);
+ encidx = rb_enc_to_index(new_enc);
+ }
+
+ rb_str_buf_cat(result, tmp_s, tmp_len);
+ }
+
+ rb_str_null_check(result);
+ return result;
+}
+
+static inline VALUE
+rb_file_join(long argc, VALUE *args)
+{
+ if (RB_UNLIKELY(argc == 0)) {
+ return rb_str_new(0, 0);
+ }
+
+ VALUE result = rb_file_join_fastpath(argc, args);
+ if (RB_LIKELY(result)) {
+ return result;
+ }
+
+ return rb_file_join_ary(rb_ary_new_from_values(argc, args));
+}
/*
* call-seq:
* File.join(string, ...) -> string
@@ -5194,9 +5596,9 @@ rb_file_join(VALUE ary)
*/
static VALUE
-rb_file_s_join(VALUE klass, VALUE args)
+rb_file_s_join(int argc, VALUE *argv, VALUE klass)
{
- return rb_file_join(args);
+ return rb_file_join(argc, argv);
}
#if defined(HAVE_TRUNCATE)
@@ -5336,7 +5738,7 @@ rb_thread_flock(void *data)
* call-seq:
* flock(locking_constant) -> 0 or false
*
- * Locks or unlocks file +self+ according to the given `locking_constant`,
+ * Locks or unlocks file `self` according to the given `locking_constant`,
* a bitwise OR of the values in the table below.
*
* Not available on all platforms.
@@ -5346,10 +5748,10 @@ rb_thread_flock(void *data)
*
* | Constant | Lock | Effect
* |-----------------|--------------|-----------------------------------------------------------------------------------------------------------------|
- * | +File::LOCK_EX+ | Exclusive | Only one process may hold an exclusive lock for +self+ at a time. |
- * | +File::LOCK_NB+ | Non-blocking | No blocking; may be combined with +File::LOCK_SH+ or +File::LOCK_EX+ using the bitwise OR operator <tt>\|</tt>. |
- * | +File::LOCK_SH+ | Shared | Multiple processes may each hold a shared lock for +self+ at the same time. |
- * | +File::LOCK_UN+ | Unlock | Remove an existing lock held by this process. |
+ * | `File::LOCK_EX` | Exclusive | Only one process may hold an exclusive lock for `self` at a time. |
+ * | `File::LOCK_NB` | Non-blocking | No blocking; may be combined with `File::LOCK_SH` or `File::LOCK_EX` using the bitwise OR operator <tt>\|</tt>. |
+ * | `File::LOCK_SH` | Shared | Multiple processes may each hold a shared lock for `self` at the same time. |
+ * | `File::LOCK_UN` | Unlock | Remove an existing lock held by this process. |
*
* Example:
*
@@ -5476,11 +5878,11 @@ test_check(int n, int argc, VALUE *argv)
* | <tt>'z'</tt> | Whether the entity exists and is of length zero. |
*
* - This test operates only on the entity at `path0`,
- * and returns an integer size or +nil+:
+ * and returns an integer size or `nil`:
*
* | Character | Test |
* |:------------:|:---------------------------------------------------------------------------------------------|
- * | <tt>'s'</tt> | Returns positive integer size if the entity exists and has non-zero length, +nil+ otherwise. |
+ * | <tt>'s'</tt> | Returns positive integer size if the entity exists and has non-zero length, `nil` otherwise. |
*
* - Each of these tests operates only on the entity at `path0`,
* and returns a Time object;
@@ -5622,7 +6024,7 @@ rb_f_test(int argc, VALUE *argv, VALUE _)
if (strchr("=<>", cmd)) {
struct stat st1, st2;
- struct timespec t1, t2;
+ stat_timestamp t1, t2;
CHECK(2);
if (rb_stat(argv[1], &st1) < 0) return Qfalse;
@@ -5662,19 +6064,56 @@ rb_f_test(int argc, VALUE *argv, VALUE _)
/*
* Document-class: File::Stat
*
- * Objects of class File::Stat encapsulate common status information
- * for File objects. The information is recorded at the moment the
- * File::Stat object is created; changes made to the file after that
- * point will not be reflected. File::Stat objects are returned by
- * IO#stat, File::stat, File#lstat, and File::lstat. Many of these
- * methods return platform-specific values, and not all values are
- * meaningful on all systems. See also Kernel#test.
+ * A \File::Stat object contains information about an entry in the file system.
+ *
+ * Each of these methods returns a new \File::Stat object:
+ *
+ * - File#lstat.
+ * - File::Stat.new.
+ * - File::lstat.
+ * - File::stat.
+ * - IO#stat.
+ *
+ * === Snapshot
+ *
+ * A new \File::Stat object takes an immediate "snapshot" of the entry's information;
+ * the captured information is never updated,
+ * regardless of changes in the actual entry:
+ *
+ * The entry must exist when File::Stat.new is called:
+ *
+ * filepath = 't.tmp'
+ * File.exist?(filepath) # => false
+ * File::Stat.new(filepath) # Raises Errno::ENOENT: No such file or directory.
+ * File.write(filepath, 'foo') # Create the file.
+ * stat = File::Stat.new(filepath) # Okay.
+ *
+ * Later changes to the actual entry do not change the \File::Stat object:
+ *
+ * File.atime(filepath) # => 2026-04-01 11:51:38.0014518 -0500
+ * stat.atime # => 2026-04-01 11:51:38.0014518 -0500
+ * File.write(filepath, 'bar')
+ * File.atime(filepath) # => 2026-04-01 11:58:11.922614 -0500
+ * stat.atime # => 2026-04-01 11:51:38.0014518 -0500
+ * File.delete(filepath)
+ * stat.atime # => 2026-04-01 11:51:38.0014518 -0500
+ *
+ * === OS-Dependencies
+ *
+ * Methods in a \File::Stat object may return platform-dependents values,
+ * and not all values are meaningful on all systems;
+ * for example, File::Stat#blocks returns +nil+ on Windows,
+ * but returns an integer on Linux.
+ *
+ * See also Kernel#test.
*/
static VALUE
rb_stat_s_alloc(VALUE klass)
{
- return stat_new_0(klass, 0);
+ VALUE obj;
+ stat_alloc(rb_cStat, &obj);
+ return obj;
}
/*
@@ -5688,11 +6127,11 @@ rb_stat_s_alloc(VALUE klass)
static VALUE
rb_stat_init(VALUE obj, VALUE fname)
{
- struct stat st;
+ rb_io_stat_data st;
FilePathValue(fname);
fname = rb_str_encode_ospath(fname);
- if (STAT(StringValueCStr(fname), &st) == -1) {
+ if (STATX(StringValueCStr(fname), &st, STATX_ALL) == -1) {
rb_sys_fail_path(fname);
}
@@ -5738,7 +6177,7 @@ rb_stat_init_copy(VALUE copy, VALUE orig)
static VALUE
rb_stat_ftype(VALUE obj)
{
- return rb_file_ftype(get_stat(obj));
+ return rb_file_ftype(get_stat(obj)->ST_(mode));
}
/*
@@ -5755,7 +6194,7 @@ rb_stat_ftype(VALUE obj)
static VALUE
rb_stat_d(VALUE obj)
{
- if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISDIR(get_stat(obj)->ST_(mode))) return Qtrue;
return Qfalse;
}
@@ -5771,7 +6210,7 @@ static VALUE
rb_stat_p(VALUE obj)
{
#ifdef S_IFIFO
- if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISFIFO(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
@@ -5797,7 +6236,7 @@ static VALUE
rb_stat_l(VALUE obj)
{
#ifdef S_ISLNK
- if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISLNK(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
}
@@ -5818,7 +6257,7 @@ static VALUE
rb_stat_S(VALUE obj)
{
#ifdef S_ISSOCK
- if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISSOCK(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
@@ -5841,7 +6280,7 @@ static VALUE
rb_stat_b(VALUE obj)
{
#ifdef S_ISBLK
- if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISBLK(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
@@ -5862,7 +6301,7 @@ rb_stat_b(VALUE obj)
static VALUE
rb_stat_c(VALUE obj)
{
- if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISCHR(get_stat(obj)->ST_(mode))) return Qtrue;
return Qfalse;
}
@@ -5882,14 +6321,14 @@ rb_stat_c(VALUE obj)
static VALUE
rb_stat_owned(VALUE obj)
{
- if (get_stat(obj)->st_uid == geteuid()) return Qtrue;
+ if (get_stat(obj)->ST_(uid) == geteuid()) return Qtrue;
return Qfalse;
}
static VALUE
rb_stat_rowned(VALUE obj)
{
- if (get_stat(obj)->st_uid == getuid()) return Qtrue;
+ if (get_stat(obj)->ST_(uid) == getuid()) return Qtrue;
return Qfalse;
}
@@ -5909,7 +6348,7 @@ static VALUE
rb_stat_grpowned(VALUE obj)
{
#ifndef _WIN32
- if (rb_group_member(get_stat(obj)->st_gid)) return Qtrue;
+ if (rb_group_member(get_stat(obj)->ST_(gid))) return Qtrue;
#endif
return Qfalse;
}
@@ -5928,21 +6367,21 @@ rb_stat_grpowned(VALUE obj)
static VALUE
rb_stat_r(VALUE obj)
{
- struct stat *st = get_stat(obj);
+ rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (geteuid() == 0) return Qtrue;
#endif
#ifdef S_IRUSR
if (rb_stat_owned(obj))
- return RBOOL(st->st_mode & S_IRUSR);
+ return RBOOL(st->ST_(mode) & S_IRUSR);
#endif
#ifdef S_IRGRP
if (rb_stat_grpowned(obj))
- return RBOOL(st->st_mode & S_IRGRP);
+ return RBOOL(st->ST_(mode) & S_IRGRP);
#endif
#ifdef S_IROTH
- if (!(st->st_mode & S_IROTH)) return Qfalse;
+ if (!(st->ST_(mode) & S_IROTH)) return Qfalse;
#endif
return Qtrue;
}
@@ -5961,21 +6400,21 @@ rb_stat_r(VALUE obj)
static VALUE
rb_stat_R(VALUE obj)
{
- struct stat *st = get_stat(obj);
+ rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (getuid() == 0) return Qtrue;
#endif
#ifdef S_IRUSR
if (rb_stat_rowned(obj))
- return RBOOL(st->st_mode & S_IRUSR);
+ return RBOOL(st->ST_(mode) & S_IRUSR);
#endif
#ifdef S_IRGRP
- if (rb_group_member(get_stat(obj)->st_gid))
- return RBOOL(st->st_mode & S_IRGRP);
+ if (rb_group_member(get_stat(obj)->ST_(gid)))
+ return RBOOL(st->ST_(mode) & S_IRGRP);
#endif
#ifdef S_IROTH
- if (!(st->st_mode & S_IROTH)) return Qfalse;
+ if (!(st->ST_(mode) & S_IROTH)) return Qfalse;
#endif
return Qtrue;
}
@@ -5997,9 +6436,9 @@ static VALUE
rb_stat_wr(VALUE obj)
{
#ifdef S_IROTH
- struct stat *st = get_stat(obj);
- if ((st->st_mode & (S_IROTH)) == S_IROTH) {
- return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
+ rb_io_stat_data *st = get_stat(obj);
+ if ((st->ST_(mode) & (S_IROTH)) == S_IROTH) {
+ return UINT2NUM(st->ST_(mode) & (S_IRUGO|S_IWUGO|S_IXUGO));
}
#endif
return Qnil;
@@ -6019,21 +6458,21 @@ rb_stat_wr(VALUE obj)
static VALUE
rb_stat_w(VALUE obj)
{
- struct stat *st = get_stat(obj);
+ rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (geteuid() == 0) return Qtrue;
#endif
#ifdef S_IWUSR
if (rb_stat_owned(obj))
- return RBOOL(st->st_mode & S_IWUSR);
+ return RBOOL(st->ST_(mode) & S_IWUSR);
#endif
#ifdef S_IWGRP
if (rb_stat_grpowned(obj))
- return RBOOL(st->st_mode & S_IWGRP);
+ return RBOOL(st->ST_(mode) & S_IWGRP);
#endif
#ifdef S_IWOTH
- if (!(st->st_mode & S_IWOTH)) return Qfalse;
+ if (!(st->ST_(mode) & S_IWOTH)) return Qfalse;
#endif
return Qtrue;
}
@@ -6052,21 +6491,21 @@ rb_stat_w(VALUE obj)
static VALUE
rb_stat_W(VALUE obj)
{
- struct stat *st = get_stat(obj);
+ rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (getuid() == 0) return Qtrue;
#endif
#ifdef S_IWUSR
if (rb_stat_rowned(obj))
- return RBOOL(st->st_mode & S_IWUSR);
+ return RBOOL(st->ST_(mode) & S_IWUSR);
#endif
#ifdef S_IWGRP
- if (rb_group_member(get_stat(obj)->st_gid))
- return RBOOL(st->st_mode & S_IWGRP);
+ if (rb_group_member(get_stat(obj)->ST_(gid)))
+ return RBOOL(st->ST_(mode) & S_IWGRP);
#endif
#ifdef S_IWOTH
- if (!(st->st_mode & S_IWOTH)) return Qfalse;
+ if (!(st->ST_(mode) & S_IWOTH)) return Qfalse;
#endif
return Qtrue;
}
@@ -6088,9 +6527,9 @@ static VALUE
rb_stat_ww(VALUE obj)
{
#ifdef S_IWOTH
- 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));
+ rb_io_stat_data *st = get_stat(obj);
+ if ((st->ST_(mode) & (S_IWOTH)) == S_IWOTH) {
+ return UINT2NUM(st->ST_(mode) & (S_IRUGO|S_IWUGO|S_IXUGO));
}
#endif
return Qnil;
@@ -6112,23 +6551,23 @@ rb_stat_ww(VALUE obj)
static VALUE
rb_stat_x(VALUE obj)
{
- struct stat *st = get_stat(obj);
+ rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (geteuid() == 0) {
- return RBOOL(st->st_mode & S_IXUGO);
+ return RBOOL(st->ST_(mode) & S_IXUGO);
}
#endif
#ifdef S_IXUSR
if (rb_stat_owned(obj))
- return RBOOL(st->st_mode & S_IXUSR);
+ return RBOOL(st->ST_(mode) & S_IXUSR);
#endif
#ifdef S_IXGRP
if (rb_stat_grpowned(obj))
- return RBOOL(st->st_mode & S_IXGRP);
+ return RBOOL(st->ST_(mode) & S_IXGRP);
#endif
#ifdef S_IXOTH
- if (!(st->st_mode & S_IXOTH)) return Qfalse;
+ if (!(st->ST_(mode) & S_IXOTH)) return Qfalse;
#endif
return Qtrue;
}
@@ -6144,23 +6583,23 @@ rb_stat_x(VALUE obj)
static VALUE
rb_stat_X(VALUE obj)
{
- struct stat *st = get_stat(obj);
+ rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (getuid() == 0) {
- return RBOOL(st->st_mode & S_IXUGO);
+ return RBOOL(st->ST_(mode) & S_IXUGO);
}
#endif
#ifdef S_IXUSR
if (rb_stat_rowned(obj))
- return RBOOL(st->st_mode & S_IXUSR);
+ return RBOOL(st->ST_(mode) & S_IXUSR);
#endif
#ifdef S_IXGRP
- if (rb_group_member(get_stat(obj)->st_gid))
- return RBOOL(st->st_mode & S_IXGRP);
+ if (rb_group_member(get_stat(obj)->ST_(gid)))
+ return RBOOL(st->ST_(mode) & S_IXGRP);
#endif
#ifdef S_IXOTH
- if (!(st->st_mode & S_IXOTH)) return Qfalse;
+ if (!(st->ST_(mode) & S_IXOTH)) return Qfalse;
#endif
return Qtrue;
}
@@ -6179,7 +6618,7 @@ rb_stat_X(VALUE obj)
static VALUE
rb_stat_f(VALUE obj)
{
- if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue;
+ if (S_ISREG(get_stat(obj)->ST_(mode))) return Qtrue;
return Qfalse;
}
@@ -6197,7 +6636,7 @@ rb_stat_f(VALUE obj)
static VALUE
rb_stat_z(VALUE obj)
{
- if (get_stat(obj)->st_size == 0) return Qtrue;
+ if (get_stat(obj)->ST_(size) == 0) return Qtrue;
return Qfalse;
}
@@ -6216,7 +6655,7 @@ rb_stat_z(VALUE obj)
static VALUE
rb_stat_s(VALUE obj)
{
- rb_off_t size = get_stat(obj)->st_size;
+ rb_off_t size = get_stat(obj)->ST_(size);
if (size == 0) return Qnil;
return OFFT2NUM(size);
@@ -6237,7 +6676,7 @@ static VALUE
rb_stat_suid(VALUE obj)
{
#ifdef S_ISUID
- if (get_stat(obj)->st_mode & S_ISUID) return Qtrue;
+ if (get_stat(obj)->ST_(mode) & S_ISUID) return Qtrue;
#endif
return Qfalse;
}
@@ -6258,7 +6697,7 @@ static VALUE
rb_stat_sgid(VALUE obj)
{
#ifdef S_ISGID
- if (get_stat(obj)->st_mode & S_ISGID) return Qtrue;
+ if (get_stat(obj)->ST_(mode) & S_ISGID) return Qtrue;
#endif
return Qfalse;
}
@@ -6279,7 +6718,7 @@ static VALUE
rb_stat_sticky(VALUE obj)
{
#ifdef S_ISVTX
- if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue;
+ if (get_stat(obj)->ST_(mode) & S_ISVTX) return Qtrue;
#endif
return Qfalse;
}
@@ -6360,96 +6799,6 @@ rb_is_absolute_path(const char *path)
return 0;
}
-#ifndef ENABLE_PATH_CHECK
-# if defined DOSISH || defined __CYGWIN__
-# define ENABLE_PATH_CHECK 0
-# else
-# define ENABLE_PATH_CHECK 1
-# endif
-#endif
-
-#if ENABLE_PATH_CHECK
-static int
-path_check_0(VALUE path)
-{
- struct stat st;
- const char *p0 = StringValueCStr(path);
- const char *e0;
- rb_encoding *enc;
- char *p = 0, *s;
-
- if (!rb_is_absolute_path(p0)) {
- char *buf = ruby_getcwd();
- VALUE newpath;
-
- newpath = rb_str_new2(buf);
- xfree(buf);
-
- rb_str_cat2(newpath, "/");
- rb_str_cat2(newpath, p0);
- path = newpath;
- p0 = RSTRING_PTR(path);
- }
- e0 = p0 + RSTRING_LEN(path);
- enc = rb_enc_get(path);
- for (;;) {
-#ifndef S_IWOTH
-# define S_IWOTH 002
-#endif
- if (STAT(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
-#ifdef S_ISVTX
- && !(p && (st.st_mode & S_ISVTX))
-#endif
- && !access(p0, W_OK)) {
- rb_enc_warn(enc, "Insecure world writable dir %s in PATH, mode 0%"
-#if SIZEOF_DEV_T > SIZEOF_INT
- PRI_MODET_PREFIX"o",
-#else
- "o",
-#endif
- p0, st.st_mode);
- if (p) *p = '/';
- RB_GC_GUARD(path);
- return 0;
- }
- s = strrdirsep(p0, e0, enc);
- if (p) *p = '/';
- if (!s || s == p0) return 1;
- p = s;
- e0 = p;
- *p = '\0';
- }
-}
-#endif
-
-int
-rb_path_check(const char *path)
-{
- rb_warn_deprecated_to_remove_at(3.6, "rb_path_check", NULL);
-#if ENABLE_PATH_CHECK
- const char *p0, *p, *pend;
- const char sep = PATH_SEP_CHAR;
-
- if (!path) return 1;
-
- pend = path + strlen(path);
- p0 = path;
- p = strchr(path, sep);
- if (!p) p = pend;
-
- for (;;) {
- if (!path_check_0(rb_str_new(p0, p - p0))) {
- return 0; /* not safe */
- }
- p0 = p + 1;
- if (p0 > pend) break;
- p = strchr(p0, sep);
- if (!p) p = pend;
- }
-#endif
- return 1;
-}
-
int
ruby_is_fd_loadable(int fd)
{
@@ -6670,7 +7019,7 @@ const char ruby_null_device[] =
* 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].
+ * {read/write mode}[rdoc-ref:File@ReadWrite+Mode].
* - May also contain a 1-character {data mode}[rdoc-ref:File@Data+Mode].
* - May also contain a 1-character
* {file-create mode}[rdoc-ref:File@File-Create+Mode].
@@ -7311,7 +7660,7 @@ const char ruby_null_device[] =
*
* First, what's elsewhere. Class \File:
*
- * - Inherits from {class IO}[rdoc-ref:IO@What-27s+Here],
+ * - Inherits from {class IO}[rdoc-ref:IO@Whats+Here],
* in particular, methods for creating, reading, and writing files
* - Includes module FileTest,
* which provides dozens of additional methods.
@@ -7526,7 +7875,7 @@ Init_File(void)
/* separates directory parts in path */
rb_define_const(rb_cFile, "SEPARATOR", separator);
rb_define_singleton_method(rb_cFile, "split", rb_file_s_split, 1);
- rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -2);
+ rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -1);
#ifdef DOSISH
/* platform specific alternative separator */
@@ -7830,11 +8179,11 @@ Init_File(void)
*
* ==== File::FNM_EXTGLOB
*
- * Flag File::FNM_EXTGLOB enables pattern <tt>'{_a_,_b_}'</tt>,
+ * 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>):
+ * (e.g., <tt>'(?:a|b)'</tt>):
*
* pattern = '{LEGAL,BSDL}'
* Dir.glob(pattern) # => ["LEGAL", "BSDL"]
diff --git a/gc.c b/gc.c
index a9c91250df..2772f95638 100644
--- a/gc.c
+++ b/gc.c
@@ -11,9 +11,6 @@
**********************************************************************/
-#define rb_data_object_alloc rb_data_object_alloc
-#define rb_data_typed_object_alloc rb_data_typed_object_alloc
-
#include "ruby/internal/config.h"
#ifdef _WIN32
# include "ruby/ruby.h"
@@ -82,7 +79,6 @@
#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/gc.h"
@@ -91,6 +87,7 @@
#include "internal/class.h"
#include "internal/compile.h"
#include "internal/complex.h"
+#include "internal/concurrent_set.h"
#include "internal/cont.h"
#include "internal/error.h"
#include "internal/eval.h"
@@ -102,6 +99,7 @@
#include "internal/object.h"
#include "internal/proc.h"
#include "internal/rational.h"
+#include "internal/re.h"
#include "internal/sanitizers.h"
#include "internal/struct.h"
#include "internal/symbol.h"
@@ -126,50 +124,59 @@
#include "vm_callinfo.h"
#include "ractor_core.h"
#include "yjit.h"
+#include "zjit.h"
#include "builtin.h"
#include "shape.h"
+// TODO: Don't export this function in modular GC, instead MMTk should figure out
+// how to combine GC thread backtrace with mutator thread backtrace.
+void
+rb_gc_print_backtrace(void)
+{
+ rb_print_backtrace(stderr);
+}
+
unsigned int
-rb_gc_vm_lock(void)
+rb_gc_vm_lock(const char *file, int line)
{
- unsigned int lev;
- RB_VM_LOCK_ENTER_LEV(&lev);
+ unsigned int lev = 0;
+ rb_vm_lock_enter(&lev, file, line);
return lev;
}
void
-rb_gc_vm_unlock(unsigned int lev)
+rb_gc_vm_unlock(unsigned int lev, const char *file, int line)
{
- RB_VM_LOCK_LEAVE_LEV(&lev);
+ rb_vm_lock_leave(&lev, file, line);
}
unsigned int
-rb_gc_cr_lock(void)
+rb_gc_cr_lock(const char *file, int line)
{
unsigned int lev;
- RB_VM_LOCK_ENTER_CR_LEV(GET_RACTOR(), &lev);
+ rb_vm_lock_enter_cr(GET_RACTOR(), &lev, file, line);
return lev;
}
void
-rb_gc_cr_unlock(unsigned int lev)
+rb_gc_cr_unlock(unsigned int lev, const char *file, int line)
{
- RB_VM_LOCK_LEAVE_CR_LEV(GET_RACTOR(), &lev);
+ rb_vm_lock_leave_cr(GET_RACTOR(), &lev, file, line);
}
unsigned int
-rb_gc_vm_lock_no_barrier(void)
+rb_gc_vm_lock_no_barrier(const char *file, int line)
{
unsigned int lev = 0;
- RB_VM_LOCK_ENTER_LEV_NB(&lev);
+ rb_vm_lock_enter_nb(&lev, file, line);
return lev;
}
void
-rb_gc_vm_unlock_no_barrier(unsigned int lev)
+rb_gc_vm_unlock_no_barrier(unsigned int lev, const char *file, int line)
{
- RB_VM_LOCK_LEAVE_LEV(&lev);
+ rb_vm_lock_leave_nb(&lev, file, line);
}
void
@@ -178,7 +185,6 @@ rb_gc_vm_barrier(void)
rb_vm_barrier();
}
-#if USE_MODULAR_GC
void *
rb_gc_get_ractor_newobj_cache(void)
{
@@ -192,35 +198,6 @@ rb_gc_initialize_vm_context(struct rb_gc_vm_context *context)
context->ec = GET_EC();
}
-void
-rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context)
-{
- rb_native_mutex_lock(&context->lock);
-
- GC_ASSERT(rb_current_execution_context(false) == NULL);
-
-#ifdef RB_THREAD_LOCAL_SPECIFIER
- rb_current_ec_set(context->ec);
-#else
- native_tls_set(ruby_current_ec_key, context->ec);
-#endif
-}
-
-void
-rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context)
-{
- rb_native_mutex_unlock(&context->lock);
-
- GC_ASSERT(rb_current_execution_context(true) == context->ec);
-
-#ifdef RB_THREAD_LOCAL_SPECIFIER
- rb_current_ec_set(NULL);
-#else
- native_tls_set(ruby_current_ec_key, NULL);
-#endif
-}
-#endif
-
bool
rb_gc_event_hook_required_p(rb_event_flag_t event)
{
@@ -232,10 +209,33 @@ rb_gc_event_hook(VALUE obj, rb_event_flag_t event)
{
if (LIKELY(!rb_gc_event_hook_required_p(event))) return;
- rb_execution_context_t *ec = GET_EC();
+ rb_execution_context_t *ec = rb_gc_get_ec();
if (!ec->cfp) return;
+#if USE_MODULAR_GC
+ bool gc_thread_p = false;
+ if (!GET_EC()) {
+ gc_thread_p = true;
+
+# ifdef RB_THREAD_LOCAL_SPECIFIER
+ rb_current_ec_set(ec);
+# else
+ native_tls_set(ruby_current_ec_key, ec);
+# endif
+ }
+#endif
+
EXEC_EVENT_HOOK(ec, event, ec->cfp->self, 0, 0, 0, obj);
+
+#if USE_MODULAR_GC
+ if (gc_thread_p) {
+# ifdef RB_THREAD_LOCAL_SPECIFIER
+ rb_current_ec_set(NULL);
+# else
+ native_tls_set(ruby_current_ec_key, NULL);
+# endif
+ }
+#endif
}
void *
@@ -244,7 +244,6 @@ rb_gc_get_objspace(void)
return GET_VM()->gc.objspace;
}
-
void
rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data)
{
@@ -288,6 +287,8 @@ rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void
saved.finished = 0;
saved.final = Qundef;
+ ASSERT_vm_unlocking();
+ rb_ractor_ignore_belonging(true);
EC_PUSH_TAG(ec);
enum ruby_tag_type state = EC_EXEC_TAG();
if (state != TAG_NONE) {
@@ -306,6 +307,7 @@ rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void
rb_check_funcall(saved.final, idCall, 1, &objid);
}
EC_POP_TAG();
+ rb_ractor_ignore_belonging(false);
#undef RESTORE_FINALIZER
}
@@ -329,18 +331,21 @@ rb_gc_multi_ractor_p(void)
return rb_multi_ractor_p();
}
-bool rb_obj_is_main_ractor(VALUE gv);
-
bool
rb_gc_shutdown_call_finalizer_p(VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_DATA:
- if (!ruby_free_at_exit_p() && (!DATA_PTR(obj) || !RDATA(obj)->dfree)) return false;
+ if (!ruby_free_at_exit_p()) {
+ if (!RDATA(obj)->type) return false;
+ if (!rbimpl_typeddata_embedded_p(obj) && !RTYPEDDATA(obj)->data) return false;
+ }
if (rb_obj_is_thread(obj)) return false;
if (rb_obj_is_mutex(obj)) return false;
if (rb_obj_is_fiber(obj)) return false;
- if (rb_obj_is_main_ractor(obj)) return false;
+ if (rb_ractor_p(obj)) return false;
+ if (rb_obj_is_fstring_table(obj)) return false;
+ if (rb_obj_is_symbol_table(obj)) return false;
return true;
@@ -348,11 +353,6 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
return true;
case T_SYMBOL:
- if (RSYMBOL(obj)->fstr &&
- (BUILTIN_TYPE(RSYMBOL(obj)->fstr) == T_NONE ||
- BUILTIN_TYPE(RSYMBOL(obj)->fstr) == T_ZOMBIE)) {
- RSYMBOL(obj)->fstr = 0;
- }
return true;
case T_NONE:
@@ -363,38 +363,18 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
}
}
-uint32_t
-rb_gc_get_shape(VALUE obj)
-{
- return (uint32_t)rb_shape_get_shape_id(obj);
-}
-
void
-rb_gc_set_shape(VALUE obj, uint32_t shape_id)
-{
- rb_shape_set_shape_id(obj, (uint32_t)shape_id);
-}
-
-uint32_t
-rb_gc_rebuild_shape(VALUE obj, size_t heap_id)
+rb_gc_obj_changed_pool(VALUE obj, size_t heap_id)
{
- rb_shape_t *orig_shape = rb_shape_get_shape(obj);
-
- if (rb_shape_obj_too_complex(obj)) return (uint32_t)OBJ_TOO_COMPLEX_SHAPE_ID;
-
- rb_shape_t *initial_shape = rb_shape_get_shape_by_id((shape_id_t)(heap_id + FIRST_T_OBJECT_SHAPE_ID));
- rb_shape_t *new_shape = rb_shape_traverse_from_new_root(initial_shape, orig_shape);
-
- if (!new_shape) return 0;
+ RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT));
- return (uint32_t)rb_shape_id(new_shape);
+ RBASIC_SET_SHAPE_ID(obj, rb_obj_shape_transition_heap(obj, heap_id));
}
void rb_vm_update_references(void *ptr);
#define rb_setjmp(env) RUBY_SETJMP(env)
#define rb_jmp_buf rb_jmpbuf_t
-#undef rb_data_object_wrap
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
@@ -409,7 +389,7 @@ void rb_vm_update_references(void *ptr);
#define RMOVED(obj) ((struct RMoved *)(obj))
#define TYPED_UPDATE_IF_MOVED(_objspace, _type, _thing) do { \
- if (rb_gc_impl_object_moved_p((_objspace), (VALUE)(_thing))) { \
+ if (gc_object_moved_p_internal((_objspace), (VALUE)(_thing))) { \
*(_type *)&(_thing) = (_type)gc_location_internal(_objspace, (VALUE)_thing); \
} \
} while (0)
@@ -491,21 +471,21 @@ rb_malloc_grow_capa(size_t current, size_t type_size)
return new_capacity;
}
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
size_mul_add_overflow(size_t x, size_t y, size_t z) /* x * y + z */
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- struct rbimpl_size_mul_overflow_tag u = rbimpl_size_add_overflow(t.right, z);
- return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left, u.right };
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ struct rbimpl_size_overflow_tag u = rbimpl_size_add_overflow(t.result, z);
+ return (struct rbimpl_size_overflow_tag) { t.overflowed || u.overflowed, u.result };
}
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
size_mul_add_mul_overflow(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- struct rbimpl_size_mul_overflow_tag u = rbimpl_size_mul_overflow(z, w);
- struct rbimpl_size_mul_overflow_tag v = rbimpl_size_add_overflow(t.right, u.right);
- return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left || v.left, v.right };
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ struct rbimpl_size_overflow_tag u = rbimpl_size_mul_overflow(z, w);
+ struct rbimpl_size_overflow_tag v = rbimpl_size_add_overflow(t.result, u.result);
+ return (struct rbimpl_size_overflow_tag) { t.overflowed || u.overflowed || v.overflowed, v.result };
}
PRINTF_ARGS(NORETURN(static void gc_raise(VALUE, const char*, ...)), 2, 3);
@@ -513,9 +493,9 @@ PRINTF_ARGS(NORETURN(static void gc_raise(VALUE, const char*, ...)), 2, 3);
static inline size_t
size_mul_or_raise(size_t x, size_t y, VALUE exc)
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- if (LIKELY(!t.left)) {
- return t.right;
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ if (LIKELY(!t.overflowed)) {
+ return t.result;
}
else if (rb_during_gc()) {
rb_memerror(); /* or...? */
@@ -539,9 +519,9 @@ rb_size_mul_or_raise(size_t x, size_t y, VALUE exc)
static inline size_t
size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
{
- struct rbimpl_size_mul_overflow_tag t = size_mul_add_overflow(x, y, z);
- if (LIKELY(!t.left)) {
- return t.right;
+ struct rbimpl_size_overflow_tag t = size_mul_add_overflow(x, y, z);
+ if (LIKELY(!t.overflowed)) {
+ return t.result;
}
else if (rb_during_gc()) {
rb_memerror(); /* or...? */
@@ -566,9 +546,9 @@ rb_size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
static inline size_t
size_mul_add_mul_or_raise(size_t x, size_t y, size_t z, size_t w, VALUE exc)
{
- struct rbimpl_size_mul_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
- if (LIKELY(!t.left)) {
- return t.right;
+ struct rbimpl_size_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
+ if (LIKELY(!t.overflowed)) {
+ return t.result;
}
else if (rb_during_gc()) {
rb_memerror(); /* or...? */
@@ -598,6 +578,7 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
#endif
static const char *obj_type_name(VALUE obj);
+static st_table *id2ref_tbl;
#include "gc/default/default.c"
#if USE_MODULAR_GC && !defined(HAVE_DLOPEN)
@@ -628,15 +609,16 @@ typedef struct gc_function_map {
void (*config_set)(void *objspace_ptr, VALUE hash);
void (*stress_set)(void *objspace_ptr, VALUE flag);
VALUE (*stress_get)(void *objspace_ptr);
+ struct rb_gc_vm_context *(*get_vm_context)(void *objspace_ptr);
// Object allocation
- VALUE (*new_obj)(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size);
+ VALUE (*new_obj)(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size);
size_t (*obj_slot_size)(VALUE obj);
size_t (*heap_id_for_size)(void *objspace_ptr, size_t size);
bool (*size_allocatable_p)(size_t size);
// Malloc
- void *(*malloc)(void *objspace_ptr, size_t size);
- void *(*calloc)(void *objspace_ptr, size_t size);
- void *(*realloc)(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size);
+ void *(*malloc)(void *objspace_ptr, size_t size, bool gc_allowed);
+ void *(*calloc)(void *objspace_ptr, size_t size, bool gc_allowed);
+ void *(*realloc)(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed);
void (*free)(void *objspace_ptr, void *ptr, size_t old_size);
void (*adjust_memory_usage)(void *objspace_ptr, ssize_t diff);
// Marking
@@ -644,9 +626,11 @@ typedef struct gc_function_map {
void (*mark_and_move)(void *objspace_ptr, VALUE *ptr);
void (*mark_and_pin)(void *objspace_ptr, VALUE obj);
void (*mark_maybe)(void *objspace_ptr, VALUE obj);
- void (*mark_weak)(void *objspace_ptr, VALUE *ptr);
- void (*remove_weak)(void *objspace_ptr, VALUE parent_obj, VALUE *ptr);
+ // Weak references
+ void (*declare_weak_references)(void *objspace_ptr, VALUE obj);
+ bool (*handle_weak_references_alive_p)(void *objspace_ptr, VALUE obj);
// Compaction
+ void (*register_pinning_obj)(void *objspace_ptr, VALUE obj);
bool (*object_moved_p)(void *objspace_ptr, VALUE obj);
VALUE (*location)(void *objspace_ptr, VALUE value);
// Write barriers
@@ -662,9 +646,6 @@ typedef struct gc_function_map {
void (*undefine_finalizer)(void *objspace_ptr, VALUE obj);
void (*copy_finalizer)(void *objspace_ptr, VALUE dest, VALUE obj);
void (*shutdown_call_finalizer)(void *objspace_ptr);
- // Object ID
- VALUE (*object_id)(void *objspace_ptr, VALUE obj);
- VALUE (*object_id_to_ref)(void *objspace_ptr, VALUE object_id);
// Forking
void (*before_fork)(void *objspace_ptr);
void (*after_fork)(void *objspace_ptr, rb_pid_t pid);
@@ -716,7 +697,7 @@ ruby_modular_gc_init(void)
break;
default:
fprintf(stderr, "Only alphanumeric, dash, and underscore is allowed in "RUBY_GC_LIBRARY"\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -763,19 +744,21 @@ ruby_modular_gc_init(void)
handle = dlopen(gc_so_path, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
fprintf(stderr, "ruby_modular_gc_init: Shared library %s cannot be opened: %s\n", gc_so_path, dlerror());
- exit(1);
+ exit(EXIT_FAILURE);
}
gc_functions.modular_gc_loaded_p = true;
}
+ unsigned int err_count = 0;
+
# define load_modular_gc_func(name) do { \
if (handle) { \
const char *func_name = "rb_gc_impl_" #name; \
gc_functions.name = dlsym(handle, func_name); \
if (!gc_functions.name) { \
fprintf(stderr, "ruby_modular_gc_init: %s function not exported by library %s\n", func_name, gc_so_path); \
- exit(1); \
+ err_count++; \
} \
} \
else { \
@@ -805,6 +788,7 @@ ruby_modular_gc_init(void)
load_modular_gc_func(config_get);
load_modular_gc_func(stress_set);
load_modular_gc_func(stress_get);
+ load_modular_gc_func(get_vm_context);
// Object allocation
load_modular_gc_func(new_obj);
load_modular_gc_func(obj_slot_size);
@@ -821,9 +805,11 @@ ruby_modular_gc_init(void)
load_modular_gc_func(mark_and_move);
load_modular_gc_func(mark_and_pin);
load_modular_gc_func(mark_maybe);
- load_modular_gc_func(mark_weak);
- load_modular_gc_func(remove_weak);
+ // Weak references
+ load_modular_gc_func(declare_weak_references);
+ load_modular_gc_func(handle_weak_references_alive_p);
// Compaction
+ load_modular_gc_func(register_pinning_obj);
load_modular_gc_func(object_moved_p);
load_modular_gc_func(location);
// Write barriers
@@ -839,9 +825,6 @@ ruby_modular_gc_init(void)
load_modular_gc_func(undefine_finalizer);
load_modular_gc_func(copy_finalizer);
load_modular_gc_func(shutdown_call_finalizer);
- // Object ID
- load_modular_gc_func(object_id);
- load_modular_gc_func(object_id_to_ref);
// Forking
load_modular_gc_func(before_fork);
load_modular_gc_func(after_fork);
@@ -861,6 +844,11 @@ ruby_modular_gc_init(void)
load_modular_gc_func(set_event_hook);
load_modular_gc_func(copy_attributes);
+ if (err_count > 0) {
+ fprintf(stderr, "ruby_modular_gc_init: found %u missing exports in library %s\n", err_count, gc_so_path);
+ exit(EXIT_FAILURE);
+ }
+
# undef load_modular_gc_func
rb_gc_functions = gc_functions;
@@ -888,6 +876,7 @@ ruby_modular_gc_init(void)
# define rb_gc_impl_config_set rb_gc_functions.config_set
# define rb_gc_impl_stress_set rb_gc_functions.stress_set
# define rb_gc_impl_stress_get rb_gc_functions.stress_get
+# define rb_gc_impl_get_vm_context rb_gc_functions.get_vm_context
// Object allocation
# define rb_gc_impl_new_obj rb_gc_functions.new_obj
# define rb_gc_impl_obj_slot_size rb_gc_functions.obj_slot_size
@@ -904,9 +893,11 @@ ruby_modular_gc_init(void)
# define rb_gc_impl_mark_and_move rb_gc_functions.mark_and_move
# define rb_gc_impl_mark_and_pin rb_gc_functions.mark_and_pin
# define rb_gc_impl_mark_maybe rb_gc_functions.mark_maybe
-# define rb_gc_impl_mark_weak rb_gc_functions.mark_weak
-# define rb_gc_impl_remove_weak rb_gc_functions.remove_weak
+// Weak references
+# define rb_gc_impl_declare_weak_references rb_gc_functions.declare_weak_references
+# define rb_gc_impl_handle_weak_references_alive_p rb_gc_functions.handle_weak_references_alive_p
// Compaction
+# define rb_gc_impl_register_pinning_obj rb_gc_functions.register_pinning_obj
# define rb_gc_impl_object_moved_p rb_gc_functions.object_moved_p
# define rb_gc_impl_location rb_gc_functions.location
// Write barriers
@@ -922,9 +913,6 @@ ruby_modular_gc_init(void)
# define rb_gc_impl_undefine_finalizer rb_gc_functions.undefine_finalizer
# define rb_gc_impl_copy_finalizer rb_gc_functions.copy_finalizer
# define rb_gc_impl_shutdown_call_finalizer rb_gc_functions.shutdown_call_finalizer
-// Object ID
-# define rb_gc_impl_object_id rb_gc_functions.object_id
-# define rb_gc_impl_object_id_to_ref rb_gc_functions.object_id_to_ref
// Forking
# define rb_gc_impl_before_fork rb_gc_functions.before_fork
# define rb_gc_impl_after_fork rb_gc_functions.after_fork
@@ -989,59 +977,159 @@ rb_gc_obj_slot_size(VALUE obj)
}
static inline void
-gc_validate_pc(void) {
+gc_validate_pc(VALUE obj)
+{
#if RUBY_DEBUG
+ // IMEMOs and objects without a class (e.g managed id table) are not traceable
+ if (RB_TYPE_P(obj, T_IMEMO) || !CLASS_OF(obj)) return;
+
rb_execution_context_t *ec = GET_EC();
const rb_control_frame_t *cfp = ec->cfp;
- if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc) {
- RUBY_ASSERT(cfp->pc >= ISEQ_BODY(cfp->iseq)->iseq_encoded);
- RUBY_ASSERT(cfp->pc <= ISEQ_BODY(cfp->iseq)->iseq_encoded + ISEQ_BODY(cfp->iseq)->iseq_size);
+ if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && CFP_PC(cfp)) {
+ const VALUE *iseq_encoded = ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
+ const VALUE *iseq_encoded_end = iseq_encoded + ISEQ_BODY(CFP_ISEQ(cfp))->iseq_size;
+ RUBY_ASSERT(CFP_PC(cfp) >= iseq_encoded, "PC not set when allocating, breaking tracing");
+ RUBY_ASSERT(CFP_PC(cfp) <= iseq_encoded_end, "PC not set when allocating, breaking tracing");
}
#endif
}
-static inline VALUE
-newobj_of(rb_ractor_t *cr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t size)
+NOINLINE(static void gc_newobj_hook(VALUE obj));
+static void
+gc_newobj_hook(VALUE obj)
+{
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
+ {
+ size_t slot_size = rb_gc_obj_slot_size(obj);
+ memset((char *)obj + sizeof(struct RBasic), 0, slot_size - sizeof(struct RBasic));
+
+ /* We must disable GC here because the callback could call xmalloc
+ * which could potentially trigger a GC, and a lot of code is unsafe
+ * to trigger a GC right after an object has been allocated because
+ * they perform initialization for the object and assume that the
+ * GC does not trigger before then. */
+ bool gc_disabled = RTEST(rb_gc_disable_no_rest());
+ {
+ rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_NEWOBJ);
+ }
+ if (!gc_disabled) rb_gc_enable();
+ }
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+VALUE
+rb_newobj(rb_execution_context_t *ec, VALUE klass, VALUE flags, shape_id_t shape_id, bool wb_protected, size_t size)
{
- VALUE obj = rb_gc_impl_new_obj(rb_gc_get_objspace(), cr->newobj_cache, klass, flags, v1, v2, v3, wb_protected, size);
+ GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VALUE obj = rb_gc_impl_new_obj(rb_gc_get_objspace(), cr->newobj_cache, klass, flags, wb_protected, size);
+
+#if RACTOR_CHECK_MODE
+ void rb_ractor_setup_belonging(VALUE obj);
+ rb_ractor_setup_belonging(obj);
+#endif
- gc_validate_pc();
+ RBASIC_SET_SHAPE_ID_NO_CHECKS(obj, shape_id);
+
+ gc_validate_pc(obj);
if (UNLIKELY(rb_gc_event_hook_required_p(RUBY_INTERNAL_EVENT_NEWOBJ))) {
- unsigned int lev;
- RB_VM_LOCK_ENTER_CR_LEV(cr, &lev);
- {
- memset((char *)obj + RVALUE_SIZE, 0, rb_gc_obj_slot_size(obj) - RVALUE_SIZE);
-
- /* We must disable GC here because the callback could call xmalloc
- * which could potentially trigger a GC, and a lot of code is unsafe
- * to trigger a GC right after an object has been allocated because
- * they perform initialization for the object and assume that the
- * GC does not trigger before then. */
- bool gc_disabled = RTEST(rb_gc_disable_no_rest());
- {
- rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_NEWOBJ);
- }
- if (!gc_disabled) rb_gc_enable();
- }
- RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
+ gc_newobj_hook(obj);
}
+#if RGENGC_CHECK_MODE
+# ifndef GC_DEBUG_SLOT_FILL_SPECIAL_VALUE
+# define GC_DEBUG_SLOT_FILL_SPECIAL_VALUE 255
+# endif
+
+ memset(
+ (void *)(obj + sizeof(struct RBasic)),
+ GC_DEBUG_SLOT_FILL_SPECIAL_VALUE,
+ rb_gc_obj_slot_size(obj) - sizeof(struct RBasic)
+ );
+#endif
+
return obj;
}
VALUE
-rb_wb_unprotected_newobj_of(VALUE klass, VALUE flags, size_t size)
+rb_ec_newobj_of(rb_execution_context_t *ec, 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);
+ VALUE type = flags & T_MASK;
+ RUBY_ASSERT(type != T_OBJECT);
+ RUBY_ASSERT(type != T_DATA);
+ RUBY_ASSERT(type != T_CLASS);
+ RUBY_ASSERT(type != T_MODULE);
+ RUBY_ASSERT(type != T_ICLASS);
+ (void)type;
+
+ return rb_newobj(ec, klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, true, size);
}
VALUE
-rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size)
+rb_newobj_of_with_shape(VALUE klass, VALUE flags, shape_id_t shape_id, 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 rb_newobj(GET_EC(), klass, flags, shape_id, true, size);
+}
+
+VALUE
+rb_newobj_of(VALUE klass, VALUE flags, size_t size)
+{
+ return rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, true, size);
+}
+
+static
+VALUE class_allocate_complex_instance(VALUE klass, uint32_t capacity)
+{
+ shape_id_t initial_shape_id = rb_shape_id_with_robject_layout(rb_shape_root(rb_gc_heap_id_for_size(sizeof(struct RObject))));
+ VALUE obj = rb_newobj_of_with_shape(klass, T_OBJECT, initial_shape_id, sizeof(struct RObject));
+ rb_obj_init_complex(obj, rb_st_init_numtable_with_size(capacity));
+ return obj;
+}
+
+VALUE
+rb_class_allocate_instance(VALUE klass)
+{
+ uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);
+ VALUE obj;
+
+ // Directly start as COMPLEX if we know we're over the limit.
+ RUBY_ASSERT(rb_shape_tree.max_capacity > 0);
+ if (RB_UNLIKELY(index_tbl_num_entries > rb_shape_tree.max_capacity)) {
+ obj = class_allocate_complex_instance(klass, index_tbl_num_entries);
+ }
+ else {
+ size_t size = rb_obj_embedded_size(index_tbl_num_entries);
+ if (!rb_gc_size_allocatable_p(size)) {
+ size = sizeof(struct RObject);
+ }
+
+ // There might be a NEWOBJ tracepoint callback, and it may set fields.
+ // So the shape must be passed to `NEWOBJ_OF`.
+ obj = rb_newobj_of_with_shape(klass, T_OBJECT, rb_shape_id_with_robject_layout(rb_shape_root(rb_gc_heap_id_for_size(size))), size);
+
+ #if RUBY_DEBUG
+ VALUE *ptr = ROBJECT_FIELDS(obj);
+ size_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (size_t i = fields_count; i < ROBJECT_FIELDS_CAPACITY(obj); i++) {
+ ptr[i] = Qundef;
+ }
+ #endif
+ }
+
+#if RUBY_DEBUG
+ if (rb_obj_class(obj) != rb_class_real(klass)) {
+ rb_bug("Expected rb_class_allocate_instance to set the class correctly");
+ }
+#endif
+
+ return obj;
+}
+
+void
+rb_gc_register_pinning_obj(VALUE obj)
+{
+ rb_gc_impl_register_pinning_obj(rb_gc_get_objspace(), obj);
}
#define UNEXPECTED_NODE(func) \
@@ -1051,27 +1139,16 @@ rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags,
static inline void
rb_data_object_check(VALUE klass)
{
+ RUBY_ASSERT(!RCLASS_SINGLETON_P(klass));
if (klass != rb_cObject && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
rb_undef_alloc_func(klass);
rb_warn("undefining the allocator of T_DATA class %"PRIsVALUE, klass);
}
}
-VALUE
-rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- 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));
-}
-
-VALUE
-rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- VALUE obj = rb_data_object_wrap(klass, 0, dmark, dfree);
- DATA_PTR(obj) = xcalloc(1, size);
- return obj;
-}
+#define RTYPEDDATA_EMBEDDED_P rbimpl_typeddata_embedded_p
+#define RB_DATA_TYPE_EMBEDDABLE_P(type) ((type)->flags & RUBY_TYPED_EMBEDDABLE)
+#define RTYPEDDATA_EMBEDDABLE_P(obj) RB_DATA_TYPE_EMBEDDABLE_P(RTYPEDDATA_TYPE(obj))
static VALUE
typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_t *type, size_t size)
@@ -1079,13 +1156,22 @@ typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_
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 obj = rb_newobj(GET_EC(), klass, T_DATA, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_RDATA, wb_protected, size);
+
+ rb_gc_register_pinning_obj(obj);
+
+ struct RTypedData *data = (struct RTypedData *)obj;
+ data->fields_obj = 0;
+ *(VALUE *)&data->type = ((VALUE)type) | typed_flag;
+ data->data = datap;
+
+ return obj;
}
VALUE
rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
{
- if (UNLIKELY(type->flags & RUBY_TYPED_EMBEDDABLE)) {
+ if (UNLIKELY(RB_DATA_TYPE_EMBEDDABLE_P(type))) {
rb_raise(rb_eTypeError, "Cannot wrap an embeddable TypedData");
}
@@ -1095,7 +1181,7 @@ rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
VALUE
rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
{
- if (type->flags & RUBY_TYPED_EMBEDDABLE) {
+ if (RB_DATA_TYPE_EMBEDDABLE_P(type)) {
if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY)) {
rb_raise(rb_eTypeError, "Embeddable TypedData must be freed immediately");
}
@@ -1114,20 +1200,33 @@ rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type
}
static size_t
+ruby_xmalloc_usable_size(void *ptr)
+{
+#ifdef HAVE_MALLOC_USABLE_SIZE
+#if CALC_EXACT_MALLOC_SIZE
+ struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+ return malloc_usable_size(info) - sizeof(struct malloc_obj_info);
+#else
+ return malloc_usable_size(ptr);
+#endif
+#else
+ return 0;
+#endif
+}
+
+static 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);
+ 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
+ if (ptr) {
+ if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) {
+ size += ruby_xmalloc_usable_size((void *)ptr);
}
- if (ptr && type->function.dsize) {
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
+ if (type->function.dsize) {
size += type->function.dsize(ptr);
}
}
@@ -1138,54 +1237,243 @@ rb_objspace_data_type_memsize(VALUE obj)
const char *
rb_objspace_data_type_name(VALUE obj)
{
- if (RTYPEDDATA_P(obj)) {
- return RTYPEDDATA_TYPE(obj)->wrap_struct_name;
+ return RTYPEDDATA_TYPE(obj)->wrap_struct_name;
+}
+
+void
+rb_gc_declare_weak_references(VALUE obj)
+{
+ rb_gc_impl_declare_weak_references(rb_gc_get_objspace(), obj);
+}
+
+bool
+rb_gc_handle_weak_references_alive_p(VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) return true;
+
+ return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj);
+}
+
+void
+rb_gc_handle_weak_references(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ {
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
+
+ if (type->function.handle_weak_references) {
+ (type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj));
+ }
+ else {
+ rb_bug(
+ "rb_gc_handle_weak_references: TypedData %s does not implement handle_weak_references",
+ RTYPEDDATA_TYPE(obj)->wrap_struct_name
+ );
+ }
+ }
+ break;
+
+ case T_IMEMO: {
+ switch (imemo_type(obj)) {
+ case imemo_callcache: {
+ struct rb_callcache *cc = (struct rb_callcache *)obj;
+ if (cc->klass != Qundef &&
+ (!rb_gc_handle_weak_references_alive_p(cc->klass) ||
+ !rb_gc_handle_weak_references_alive_p((VALUE)cc->cme_))) {
+ vm_cc_invalidate(cc);
+ }
+ break;
+ }
+ case imemo_subclasses: {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ VALUE *entries = rb_imemo_subclasses_entries(obj);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ if (entries[i] && !rb_gc_handle_weak_references_alive_p(entries[i])) {
+ entries[i] = 0;
+ }
+ }
+ break;
+ }
+ default:
+ rb_bug("rb_gc_handle_weak_references: unexpected imemo type");
+ }
+
+ break;
+ }
+ default:
+ rb_bug("rb_gc_handle_weak_references: type not supported\n");
}
- else {
- return 0;
+}
+
+static inline bool
+rb_gc_imemo_needs_cleanup_p(VALUE obj)
+{
+ switch (imemo_type(obj)) {
+ case imemo_constcache:
+ case imemo_cref:
+ case imemo_ifunc:
+ case imemo_memo:
+ case imemo_svar:
+ case imemo_callcache:
+ case imemo_throw_data:
+ case imemo_cvar_entry:
+ return false;
+
+ case imemo_env:
+ case imemo_ment:
+ case imemo_iseq:
+ case imemo_callinfo:
+ case imemo_cdhash:
+ return true;
+
+ case imemo_subclasses:
+ return FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP);
+
+ case imemo_tmpbuf:
+ return ((rb_imemo_tmpbuf_t *)obj)->ptr != NULL;
+
+ case imemo_fields:
+ return FL_TEST_RAW(obj, OBJ_FIELD_HEAP) || (id2ref_tbl && rb_obj_shape_has_id(obj));
}
+ UNREACHABLE_RETURN(true);
}
-static enum rb_id_table_iterator_result
-cvar_table_free_i(VALUE value, void *ctx)
+/*
+ * Returns true if the object requires a full rb_gc_obj_free() call during sweep,
+ * false if it can be freed quickly without calling destructors or cleanup.
+ *
+ * Objects that return false are:
+ * - Simple embedded objects without external allocations
+ * - Objects without finalizers
+ * - Objects without object IDs registered in id2ref
+ * - Objects without generic instance variables
+ *
+ * This is used by the GC sweep fast path to avoid function call overhead
+ * for the majority of simple objects.
+ */
+bool
+rb_gc_obj_needs_cleanup_p(VALUE obj)
{
- xfree((void *)value);
- return ID_TABLE_CONTINUE;
+ VALUE flags = RBASIC(obj)->flags;
+
+ if (flags & FL_FINALIZE) return true;
+
+ switch (flags & RUBY_T_MASK) {
+ case T_IMEMO:
+ return rb_gc_imemo_needs_cleanup_p(obj);
+
+ case T_DATA:
+ case T_OBJECT:
+ case T_STRING:
+ case T_ARRAY:
+ case T_HASH:
+ case T_BIGNUM:
+ case T_STRUCT:
+ case T_FLOAT:
+ case T_RATIONAL:
+ case T_COMPLEX:
+ case T_MATCH:
+ break;
+
+ case T_FILE:
+ case T_SYMBOL:
+ case T_CLASS:
+ case T_ICLASS:
+ case T_MODULE:
+ case T_REGEXP:
+ return true;
+ }
+
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ if (id2ref_tbl && rb_shape_has_object_id(shape_id)) return true;
+
+ switch (flags & RUBY_T_MASK) {
+ case T_OBJECT:
+ if (flags & ROBJECT_HEAP) return true;
+ return false;
+
+ case T_DATA:
+ {
+ uintptr_t type = (uintptr_t)RTYPEDDATA(obj)->type;
+ if (type & TYPED_DATA_EMBEDDED) {
+ RUBY_DATA_FUNC dfree = ((const rb_data_type_t *)(type & TYPED_DATA_PTR_MASK))->function.dfree;
+ if (dfree == RUBY_NEVER_FREE || dfree == RUBY_TYPED_DEFAULT_FREE) {
+ return false;
+ }
+ }
+ }
+ return true;
+
+ case T_STRING:
+ if (flags & (RSTRING_NOEMBED | RSTRING_FSTR)) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_ARRAY:
+ if (!(flags & RARRAY_EMBED_FLAG)) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_HASH:
+ if (flags & RHASH_ST_TABLE_FLAG) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_MATCH:
+ if ((flags & (RMATCH_ONIG | RMATCH_OFFSETS_EXTERNAL)) || USE_DEBUG_COUNTER) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_BIGNUM:
+ if (!(flags & BIGNUM_EMBED_FLAG)) return true;
+ return rb_shape_has_fields(shape_id);
+
+ case T_STRUCT:
+ if (!(flags & RSTRUCT_EMBED_LEN_MASK)) return true;
+ if (flags & RSTRUCT_GEN_FIELDS) return rb_shape_has_fields(shape_id);
+ return false;
+
+ case T_FLOAT:
+ case T_RATIONAL:
+ case T_COMPLEX:
+ return rb_shape_has_fields(shape_id);
+
+ default:
+ UNREACHABLE_RETURN(true);
+ }
+}
+
+static void
+io_fptr_finalize(void *fptr)
+{
+ rb_io_fptr_finalize((struct rb_io *)fptr);
}
static inline void
make_io_zombie(void *objspace, VALUE obj)
{
rb_io_t *fptr = RFILE(obj)->fptr;
- rb_gc_impl_make_zombie(objspace, obj, rb_io_fptr_finalize_internal, fptr);
+ rb_gc_impl_make_zombie(objspace, obj, io_fptr_finalize, fptr);
}
static bool
rb_data_free(void *objspace, VALUE obj)
{
- void *data = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *data = RTYPEDDATA_GET_DATA(obj);
if (data) {
int free_immediately = false;
void (*dfree)(void *);
- if (RTYPEDDATA_P(obj)) {
- free_immediately = (RTYPEDDATA(obj)->type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
- dfree = RTYPEDDATA(obj)->type->function.dfree;
- }
- else {
- dfree = RDATA(obj)->dfree;
- }
+ free_immediately = (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
+ dfree = RTYPEDDATA_TYPE(obj)->function.dfree;
if (dfree) {
if (dfree == RUBY_DEFAULT_FREE) {
- if (!RTYPEDDATA_P(obj) || !RTYPEDDATA_EMBEDDED_P(obj)) {
+ if (!RTYPEDDATA_EMBEDDED_P(obj)) {
xfree(data);
RB_DEBUG_COUNTER_INC(obj_data_xfree);
}
}
else if (free_immediately) {
(*dfree)(data);
- if (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_EMBEDDABLE && !RTYPEDDATA_EMBEDDED_P(obj)) {
+ if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) {
xfree(data);
}
@@ -1205,47 +1493,32 @@ rb_data_free(void *objspace, VALUE obj)
return true;
}
-void
-rb_gc_obj_free_vm_weak_references(VALUE obj)
+struct classext_foreach_args {
+ VALUE klass;
+ rb_objspace_t *objspace; // used for update_*
+};
+
+static void
+classext_free(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
- if (FL_TEST(obj, FL_EXIVAR)) {
- rb_free_generic_ivar((VALUE)obj);
- FL_UNSET(obj, FL_EXIVAR);
- }
+ struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
- switch (BUILTIN_TYPE(obj)) {
- case T_STRING:
- if (FL_TEST(obj, RSTRING_FSTR)) {
- st_data_t fstr = (st_data_t)obj;
- st_delete(rb_vm_fstring_table(), &fstr, NULL);
- RB_DEBUG_COUNTER_INC(obj_str_fstr);
+ rb_class_classext_free(args->klass, ext, is_prime);
+}
- FL_UNSET(obj, RSTRING_FSTR);
- }
- break;
- case T_SYMBOL:
- rb_gc_free_dsymbol(obj);
- break;
- case T_IMEMO:
- switch (imemo_type(obj)) {
- case imemo_callinfo:
- rb_vm_ci_free((const struct rb_callinfo *)obj);
- break;
- case imemo_ment:
- rb_free_method_entry_vm_weak_references((const rb_method_entry_t *)obj);
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
+static void
+classext_iclass_free(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
+{
+ struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
+
+ rb_iclass_classext_free(args->klass, ext, is_prime);
}
bool
rb_gc_obj_free(void *objspace, VALUE obj)
{
+ struct classext_foreach_args args;
+
RB_DEBUG_COUNTER_INC(obj_free);
switch (BUILTIN_TYPE(obj)) {
@@ -1261,43 +1534,30 @@ rb_gc_obj_free(void *objspace, VALUE obj)
switch (BUILTIN_TYPE(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));
- }
- else if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- RB_DEBUG_COUNTER_INC(obj_obj_embed);
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_obj_complex);
+ st_free_table(ROBJECT_FIELDS_HASH(obj));
+ }
+ else {
+ SIZED_FREE_N(ROBJECT(obj)->as.heap.fields, ROBJECT_FIELDS_CAPACITY(obj));
+ RB_DEBUG_COUNTER_INC(obj_obj_ptr);
+ }
}
else {
- xfree(ROBJECT(obj)->as.heap.ivptr);
- RB_DEBUG_COUNTER_INC(obj_obj_ptr);
+ RB_DEBUG_COUNTER_INC(obj_obj_embed);
}
break;
case T_MODULE:
case T_CLASS:
- rb_id_table_free(RCLASS_M_TBL(obj));
- rb_cc_table_free(obj);
- if (rb_shape_obj_too_complex(obj)) {
- st_free_table((st_table *)RCLASS_IVPTR(obj));
- }
- else {
- xfree(RCLASS_IVPTR(obj));
- }
-
- if (RCLASS_CONST_TBL(obj)) {
- rb_free_const_table(RCLASS_CONST_TBL(obj));
- }
- if (RCLASS_CVC_TBL(obj)) {
- rb_id_table_foreach_values(RCLASS_CVC_TBL(obj), cvar_table_free_i, NULL);
- rb_id_table_free(RCLASS_CVC_TBL(obj));
- }
- rb_class_remove_subclass_head(obj);
- rb_class_remove_from_module_subclasses(obj);
- rb_class_remove_from_super_subclasses(obj);
- if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
- xfree(RCLASS_SUPERCLASSES(obj));
+#if USE_ZJIT
+ rb_zjit_klass_free(obj);
+#endif
+ args.klass = obj;
+ rb_class_classext_foreach(obj, classext_free, (void *)&args);
+ if (RCLASS_CLASSEXT_TBL(obj)) {
+ st_free_table(RCLASS_CLASSEXT_TBL(obj));
}
-
(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;
@@ -1362,29 +1622,32 @@ rb_gc_obj_free(void *objspace, VALUE obj)
break;
case T_MATCH:
{
- rb_matchext_t *rm = RMATCH_EXT(obj);
+ struct RMatch *rm = RMATCH(obj);
#if USE_DEBUG_COUNTER
- if (rm->regs.num_regs >= 8) {
+ if (rm->num_regs >= 8) {
RB_DEBUG_COUNTER_INC(obj_match_ge8);
}
- else if (rm->regs.num_regs >= 4) {
+ else if (rm->num_regs >= 4) {
RB_DEBUG_COUNTER_INC(obj_match_ge4);
}
- else if (rm->regs.num_regs >= 1) {
+ else if (rm->num_regs >= 1) {
RB_DEBUG_COUNTER_INC(obj_match_under4);
}
#endif
- onig_region_free(&rm->regs, 0);
- xfree(rm->char_offset);
+ if (FL_TEST_RAW(obj, RMATCH_ONIG)) {
+ onig_region_free(&rm->as.onig, 0);
+ }
+ SIZED_FREE_N(rm->char_offset, rm->char_offset_num_allocated);
RB_DEBUG_COUNTER_INC(obj_match_ptr);
}
break;
case T_FILE:
if (RFILE(obj)->fptr) {
- make_io_zombie(objspace, obj);
+ bool closed = rb_io_fptr_finalize_closed(RFILE(obj)->fptr);
+ if (!closed) make_io_zombie(objspace, obj);
RB_DEBUG_COUNTER_INC(obj_file_ptr);
- return FALSE;
+ return closed;
}
break;
case T_RATIONAL:
@@ -1396,18 +1659,12 @@ rb_gc_obj_free(void *objspace, VALUE obj)
case T_MOVED:
break;
case T_ICLASS:
- /* Basically , T_ICLASS shares table with the module */
- if (RICLASS_OWNS_M_TBL_P(obj)) {
- /* Method table is not shared for origin iclasses of classes */
- rb_id_table_free(RCLASS_M_TBL(obj));
- }
- if (RCLASS_CALLABLE_M_TBL(obj) != NULL) {
- rb_id_table_free(RCLASS_CALLABLE_M_TBL(obj));
+ args.klass = obj;
+
+ rb_class_classext_foreach(obj, classext_iclass_free, (void *)&args);
+ if (RCLASS_CLASSEXT_TBL(obj)) {
+ st_free_table(RCLASS_CLASSEXT_TBL(obj));
}
- rb_class_remove_subclass_head(obj);
- rb_cc_table_free(obj);
- rb_class_remove_from_module_subclasses(obj);
- rb_class_remove_from_super_subclasses(obj);
RB_DEBUG_COUNTER_INC(obj_iclass_ptr);
break;
@@ -1418,7 +1675,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
case T_BIGNUM:
if (!BIGNUM_EMBED_P(obj) && BIGNUM_DIGITS(obj)) {
- xfree(BIGNUM_DIGITS(obj));
+ SIZED_FREE_N(BIGNUM_DIGITS(obj), BIGNUM_LEN(obj));
RB_DEBUG_COUNTER_INC(obj_bignum_ptr);
}
else {
@@ -1436,7 +1693,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_struct_embed);
}
else {
- xfree((void *)RSTRUCT(obj)->as.heap.ptr);
+ SIZED_FREE_N(RSTRUCT(obj)->as.heap.ptr, RSTRUCT(obj)->as.heap.len);
RB_DEBUG_COUNTER_INC(obj_struct_ptr);
}
break;
@@ -1454,7 +1711,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
BUILTIN_TYPE(obj), (void*)obj, RBASIC(obj)->flags);
}
- if (FL_TEST(obj, FL_FINALIZE)) {
+ if (FL_TEST_RAW(obj, FL_FINALIZE)) {
rb_gc_impl_make_zombie(objspace, obj, 0, 0);
return FALSE;
}
@@ -1486,7 +1743,10 @@ internal_object_p(VALUE obj)
case T_ZOMBIE:
break;
case T_CLASS:
- if (!RBASIC(obj)->klass) break;
+ if (obj == rb_mRubyVMFrozenCore)
+ return 1;
+
+ if (!RBASIC_CLASS(obj)) break;
if (RCLASS_SINGLETON_P(obj)) {
return rb_singleton_class_internal_p(obj);
}
@@ -1553,30 +1813,34 @@ os_obj_of(VALUE of)
* Ruby process. If <i>module</i> is specified, calls the block
* for only those classes or modules that match (or are a subclass of)
* <i>module</i>. Returns the number of objects found. Immediate
- * objects (<code>Fixnum</code>s, <code>Symbol</code>s
- * <code>true</code>, <code>false</code>, and <code>nil</code>) are
- * never returned. In the example below, #each_object returns both
- * the numbers we defined and several constants defined in the Math
- * module.
+ * objects (such as <code>Fixnum</code>s, static <code>Symbol</code>s
+ * <code>true</code>, <code>false</code> and <code>nil</code>) are
+ * never returned.
*
* If no block is given, an enumerator is returned instead.
*
- * a = 102.7
- * b = 95 # Won't be returned
- * c = 12345678987654321
- * count = ObjectSpace.each_object(Numeric) {|x| p x }
+ * Job = Class.new
+ * jobs = [Job.new, Job.new]
+ * count = ObjectSpace.each_object(Job) {|x| p x }
* puts "Total count: #{count}"
*
* <em>produces:</em>
*
- * 12345678987654321
- * 102.7
- * 2.71828182845905
- * 3.14159265358979
- * 2.22044604925031e-16
- * 1.7976931348623157e+308
- * 2.2250738585072e-308
- * Total count: 7
+ * #<Job:0x000000011d6cbbf0>
+ * #<Job:0x000000011d6cbc68>
+ * Total count: 2
+ *
+ * Due to a current Ractor implementation issue, this method does not yield
+ * Ractor-unshareable objects when the process is in multi-Ractor mode. Multi-ractor
+ * mode is enabled when <code>Ractor.new</code> has been called for the first time.
+ * See https://bugs.ruby-lang.org/issues/19387 for more information.
+ *
+ * a = 12345678987654321 # shareable
+ * b = [].freeze # shareable
+ * c = {} # not shareable
+ * ObjectSpace.each_object {|x| x } # yields a, b, and c
+ * Ractor.new {} # enter multi-Ractor mode
+ * ObjectSpace.each_object {|x| x } # does not yield c
*
*/
@@ -1641,63 +1905,68 @@ rb_gc_copy_finalizer(VALUE dest, VALUE obj)
/*
* call-seq:
- * ObjectSpace.define_finalizer(obj, aProc=proc())
+ * ObjectSpace.define_finalizer(obj) {|id| ... } -> array
+ * ObjectSpace.define_finalizer(obj, finalizer) -> array
*
- * Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
- * was destroyed. The object ID of the <i>obj</i> will be passed
- * as an argument to <i>aProc</i>. If <i>aProc</i> is a lambda or
- * method, make sure it can be called with a single argument.
+ * Adds a new finalizer for +obj+ that is called when +obj+ is destroyed
+ * by the garbage collector or when Ruby shuts down (which ever comes first).
*
- * The return value is an array <code>[0, aProc]</code>.
+ * With a block given, uses the block as the callback. Without a block given,
+ * uses a callable object +finalizer+ as the callback. The callback is called
+ * when +obj+ is destroyed with a single argument +id+ which is the object
+ * ID of +obj+ (see Object#object_id).
*
- * The two recommended patterns are to either create the finaliser proc
- * in a non-instance method where it can safely capture the needed state,
- * or to use a custom callable object that stores the needed state
- * explicitly as instance variables.
+ * The return value is an array <code>[0, callback]</code>, where +callback+
+ * is a Proc created from the block if one was given or +finalizer+ otherwise.
*
- * class Foo
- * def initialize(data_needed_for_finalization)
- * ObjectSpace.define_finalizer(self, self.class.create_finalizer(data_needed_for_finalization))
- * end
+ * Note that defining a finalizer in an instance method of the object may prevent
+ * the object from being garbage collected since if the block or +finalizer+ refers
+ * to +obj+ then +obj+ will never be reclaimed by the garbage collector. For example,
+ * the following script demonstrates the issue:
*
- * def self.create_finalizer(data_needed_for_finalization)
- * proc {
- * puts "finalizing #{data_needed_for_finalization}"
- * }
+ * class Foo
+ * def define_final
+ * ObjectSpace.define_finalizer(self) do |id|
+ * puts "Running finalizer for #{id}!"
+ * end
* end
* end
*
- * class Bar
- * class Remover
- * def initialize(data_needed_for_finalization)
- * @data_needed_for_finalization = data_needed_for_finalization
- * end
+ * obj = Foo.new
+ * obj.define_final
*
- * def call(id)
- * puts "finalizing #{@data_needed_for_finalization}"
- * end
+ * There are two patterns to solve this issue:
+ *
+ * - Create the finalizer in a non-instance method so it can safely capture
+ * the needed state:
+ *
+ * class Foo
+ * def define_final
+ * ObjectSpace.define_finalizer(self, self.class.create_finalizer)
* end
*
- * def initialize(data_needed_for_finalization)
- * ObjectSpace.define_finalizer(self, Remover.new(data_needed_for_finalization))
+ * def self.create_finalizer
+ * proc do |id|
+ * puts "Running finalizer for #{id}!"
+ * end
* end
* end
*
- * Note that if your finalizer references the object to be
- * finalized it will never be run on GC, although it will still be
- * run at exit. You will get a warning if you capture the object
- * to be finalized as the receiver of the finalizer.
+ * - Use a callable object:
+ *
+ * class Foo
+ * class Finalizer
+ * def call(id)
+ * puts "Running finalizer for #{id}!"
+ * end
+ * end
*
- * class CapturesSelf
- * def initialize(name)
- * ObjectSpace.define_finalizer(self, proc {
- * # this finalizer will only be run on exit
- * puts "finalizing #{name}"
- * })
+ * def define_final
+ * ObjectSpace.define_finalizer(self, Finalizer.new)
* end
* end
*
- * Also note that finalization can be unpredictable and is never guaranteed
+ * Note that finalization can be unpredictable and is never guaranteed
* to be run except on exit.
*/
@@ -1746,7 +2015,7 @@ rb_objspace_free_objects(void *objspace)
int
rb_objspace_garbage_object_p(VALUE obj)
{
- return rb_gc_impl_garbage_object_p(rb_gc_get_objspace(), obj);
+ return !SPECIAL_CONST_P(obj) && rb_gc_impl_garbage_object_p(rb_gc_get_objspace(), obj);
}
bool
@@ -1755,6 +2024,348 @@ rb_gc_pointer_to_heap_p(VALUE obj)
return rb_gc_impl_pointer_to_heap_p(rb_gc_get_objspace(), (void *)obj);
}
+#define OBJ_ID_INCREMENT (RUBY_IMMEDIATE_MASK + 1)
+#define LAST_OBJECT_ID() (object_id_counter * OBJ_ID_INCREMENT)
+static VALUE id2ref_value = 0;
+
+#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+static size_t object_id_counter = 1;
+#else
+static unsigned long long object_id_counter = 1;
+#endif
+
+static inline VALUE
+generate_next_object_id(void)
+{
+#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+ // 64bit atomics are available
+ return SIZET2NUM(RUBY_ATOMIC_SIZE_FETCH_ADD(object_id_counter, 1) * OBJ_ID_INCREMENT);
+#else
+ unsigned int lock_lev = RB_GC_VM_LOCK();
+ VALUE id = ULL2NUM(++object_id_counter * OBJ_ID_INCREMENT);
+ RB_GC_VM_UNLOCK(lock_lev);
+ return id;
+#endif
+}
+
+void
+rb_gc_obj_id_moved(VALUE obj)
+{
+ if (UNLIKELY(id2ref_tbl)) {
+ st_insert(id2ref_tbl, (st_data_t)rb_obj_id(obj), (st_data_t)obj);
+ }
+}
+
+static int
+object_id_cmp(st_data_t x, st_data_t y)
+{
+ if (RB_TYPE_P(x, T_BIGNUM)) {
+ return !rb_big_eql(x, y);
+ }
+ else {
+ return x != y;
+ }
+}
+
+static st_index_t
+object_id_hash(st_data_t n)
+{
+ return FIX2LONG(rb_hash((VALUE)n));
+}
+
+static const struct st_hash_type object_id_hash_type = {
+ object_id_cmp,
+ object_id_hash,
+};
+
+static void gc_mark_tbl_no_pin(st_table *table);
+
+static void
+id2ref_tbl_mark(void *data)
+{
+ st_table *table = (st_table *)data;
+ if (UNLIKELY(!RB_POSFIXABLE(LAST_OBJECT_ID()))) {
+ // It's very unlikely, but if enough object ids were generated, keys may be T_BIGNUM
+ rb_mark_set(table);
+ }
+ // We purposely don't mark values, as they are weak references.
+ // rb_gc_obj_free_vm_weak_references takes care of cleaning them up.
+}
+
+static size_t
+id2ref_tbl_memsize(const void *data)
+{
+ return rb_st_memsize(data);
+}
+
+static void
+id2ref_tbl_free(void *data)
+{
+ id2ref_tbl = NULL; // clear global ref
+ st_table *table = (st_table *)data;
+ st_free_table(table);
+}
+
+static const rb_data_type_t id2ref_tbl_type = {
+ .wrap_struct_name = "VM/_id2ref_table",
+ .function = {
+ .dmark = id2ref_tbl_mark,
+ .dfree = id2ref_tbl_free,
+ .dsize = id2ref_tbl_memsize,
+ // dcompact function not required because the table is reference updated
+ // in rb_gc_vm_weak_table_foreach
+ },
+ .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
+};
+
+static VALUE
+class_object_id(VALUE klass)
+{
+ VALUE id = RUBY_ATOMIC_VALUE_LOAD(RCLASS(klass)->object_id);
+ if (!id) {
+ unsigned int lock_lev = RB_GC_VM_LOCK();
+ id = generate_next_object_id();
+ VALUE existing_id = RUBY_ATOMIC_VALUE_CAS(RCLASS(klass)->object_id, 0, id);
+ if (existing_id) {
+ id = existing_id;
+ }
+ else if (RB_UNLIKELY(id2ref_tbl)) {
+ st_insert(id2ref_tbl, id, klass);
+ }
+ RB_GC_VM_UNLOCK(lock_lev);
+ }
+ return id;
+}
+
+static inline VALUE
+object_id_get(VALUE obj, shape_id_t shape_id)
+{
+ VALUE id;
+ if (rb_shape_complex_p(shape_id)) {
+ id = rb_obj_field_get(obj, ROOT_COMPLEX_WITH_OBJ_ID);
+ }
+ else {
+ id = rb_obj_field_get(obj, rb_shape_object_id(shape_id));
+ }
+
+#if RUBY_DEBUG
+ if (!(FIXNUM_P(id) || RB_TYPE_P(id, T_BIGNUM))) {
+ rb_p(obj);
+ rb_bug("Object's shape includes object_id, but it's missing %s", rb_obj_info(obj));
+ }
+#endif
+
+ return id;
+}
+
+static VALUE
+object_id0(VALUE obj)
+{
+ VALUE id = Qfalse;
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+
+ if (rb_shape_has_object_id(shape_id)) {
+ return object_id_get(obj, shape_id);
+ }
+
+ shape_id_t object_id_shape_id = rb_obj_shape_transition_object_id(obj);
+
+ id = generate_next_object_id();
+ rb_obj_field_set(obj, object_id_shape_id, 0, id);
+
+ RUBY_ASSERT(RBASIC_SHAPE_ID(obj) == object_id_shape_id);
+ RUBY_ASSERT(rb_obj_shape_has_id(obj));
+
+ if (RB_UNLIKELY(id2ref_tbl)) {
+ RB_VM_LOCKING() {
+ st_insert(id2ref_tbl, (st_data_t)id, (st_data_t)obj);
+ }
+ }
+ return id;
+}
+
+static VALUE
+object_id(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ // With Ruby Box, classes and modules have different fields
+ // in different boxes, so we cannot store the object id
+ // in fields.
+ return class_object_id(obj);
+ case T_IMEMO:
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
+ break;
+ default:
+ break;
+ }
+
+ if (UNLIKELY(rb_gc_multi_ractor_p() && rb_ractor_shareable_p(obj))) {
+ unsigned int lock_lev = RB_GC_VM_LOCK();
+ VALUE id = object_id0(obj);
+ RB_GC_VM_UNLOCK(lock_lev);
+ return id;
+ }
+
+ return object_id0(obj);
+}
+
+static void
+build_id2ref_i(VALUE obj, void *data)
+{
+ st_table *id2ref_tbl = (st_table *)data;
+
+ switch (BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
+ if (RCLASS(obj)->object_id) {
+ st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
+ }
+ break;
+ case T_IMEMO:
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
+ if (IMEMO_TYPE_P(obj, imemo_fields) && rb_obj_shape_has_id(obj)) {
+ st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
+ }
+ break;
+ case T_OBJECT:
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
+ if (rb_obj_shape_has_id(obj)) {
+ st_insert(id2ref_tbl, rb_obj_id(obj), obj);
+ }
+ break;
+ default:
+ // For generic_fields, the T_IMEMO/fields is responsible for populating the entry.
+ break;
+ }
+}
+
+static VALUE
+object_id_to_ref(void *objspace_ptr, VALUE object_id)
+{
+ rb_objspace_t *objspace = objspace_ptr;
+
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ if (!id2ref_tbl) {
+ rb_gc_vm_barrier(); // stop other ractors
+
+ // GC Must not trigger while we build the table, otherwise if we end
+ // up freeing an object that had an ID, we might try to delete it from
+ // the table even though it wasn't inserted yet.
+ st_table *tmp_id2ref_tbl = st_init_table(&object_id_hash_type);
+ VALUE tmp_id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, tmp_id2ref_tbl);
+
+ // build_id2ref_i will most certainly malloc, which could trigger GC and sweep
+ // objects we just added to the table.
+ // By calling rb_gc_disable() we also save having to handle potentially garbage objects.
+ bool gc_disabled = RTEST(rb_gc_disable());
+ {
+ id2ref_tbl = tmp_id2ref_tbl;
+ id2ref_value = tmp_id2ref_value;
+
+ rb_gc_impl_each_object(objspace, build_id2ref_i, (void *)id2ref_tbl);
+ }
+ if (!gc_disabled) rb_gc_enable();
+ }
+
+ VALUE obj;
+ bool found = st_lookup(id2ref_tbl, object_id, &obj) && !rb_gc_impl_garbage_object_p(objspace, obj);
+
+ RB_GC_VM_UNLOCK(lev);
+
+ if (found) {
+ return obj;
+ }
+
+ if (rb_funcall(object_id, rb_intern(">="), 1, ULL2NUM(LAST_OBJECT_ID()))) {
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not an id value", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
+ }
+ else {
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is a recycled object", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
+ }
+}
+
+static inline void
+obj_free_object_id(VALUE obj)
+{
+ VALUE obj_id = 0;
+ if (RB_UNLIKELY(id2ref_tbl)) {
+ switch (BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ obj_id = RCLASS(obj)->object_id;
+ break;
+ case T_IMEMO:
+ if (!IMEMO_TYPE_P(obj, imemo_fields)) {
+ return;
+ }
+ // fallthrough
+ case T_OBJECT:
+ {
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ if (rb_shape_has_object_id(shape_id)) {
+ obj_id = object_id_get(obj, shape_id);
+ }
+ break;
+ }
+ default:
+ // For generic_fields, the T_IMEMO/fields is responsible for freeing the id.
+ return;
+ }
+
+ if (RB_UNLIKELY(obj_id)) {
+ RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj_id, T_BIGNUM));
+
+ if (!st_delete(id2ref_tbl, (st_data_t *)&obj_id, NULL)) {
+ // The the object is a T_IMEMO/fields, then it's possible the actual object
+ // has been garbage collected already.
+ if (!RB_TYPE_P(obj, T_IMEMO)) {
+ rb_bug("Object ID seen, but not in _id2ref table: object_id=%llu object=%s", NUM2ULL(obj_id), rb_obj_info(obj));
+ }
+ }
+ }
+ }
+}
+
+void
+rb_gc_obj_free_vm_weak_references(VALUE obj)
+{
+ ASSUME(!RB_SPECIAL_CONST_P(obj));
+ obj_free_object_id(obj);
+
+ if (rb_obj_gen_fields_p(obj)) {
+ rb_free_generic_ivar(obj);
+ }
+
+ switch (BUILTIN_TYPE(obj)) {
+ case T_STRING:
+ if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
+ rb_gc_free_fstring(obj);
+ }
+ break;
+ case T_SYMBOL:
+ rb_gc_free_dsymbol(obj);
+ break;
+ case T_IMEMO:
+ switch (imemo_type(obj)) {
+ case imemo_callinfo:
+ rb_vm_ci_free((const struct rb_callinfo *)obj);
+ break;
+ case imemo_ment:
+ rb_free_method_entry_vm_weak_references((const rb_method_entry_t *)obj);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
/*
* call-seq:
* ObjectSpace._id2ref(object_id) -> an_object
@@ -1768,19 +2379,16 @@ rb_gc_pointer_to_heap_p(VALUE obj)
*
* On multi-ractor mode, if the object is not shareable, it raises
* RangeError.
+ *
+ * This method is deprecated and should no longer be used.
*/
static VALUE
id2ref(VALUE objid)
{
-#if SIZEOF_LONG == SIZEOF_VOIDP
-#define NUM2PTR(x) NUM2ULONG(x)
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-#define NUM2PTR(x) NUM2ULL(x)
-#endif
objid = rb_to_int(objid);
if (FIXNUM_P(objid) || rb_big_size(objid) <= SIZEOF_VOIDP) {
- VALUE ptr = NUM2PTR(objid);
+ VALUE ptr = (VALUE)NUM2PTR(objid);
if (SPECIAL_CONST_P(ptr)) {
if (ptr == Qtrue) return Qtrue;
if (ptr == Qfalse) return Qfalse;
@@ -1794,20 +2402,20 @@ id2ref(VALUE objid)
return ptr;
}
else {
- rb_raise(rb_eRangeError, "%p is not symbol id value", (void *)ptr);
+ rb_raise(rb_eRangeError, "%p is not a symbol id value", (void *)ptr);
}
}
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not id value", rb_int2str(objid, 10));
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not an id value", rb_int2str(objid, 10));
}
}
- VALUE obj = rb_gc_impl_object_id_to_ref(rb_gc_get_objspace(), objid);
+ VALUE obj = object_id_to_ref(rb_gc_get_objspace(), objid);
if (!rb_multi_ractor_p() || rb_ractor_shareable_p(obj)) {
return obj;
}
else {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is id of the unshareable object on multi-ractor", rb_int2str(objid, 10));
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is the id of an unshareable object on multi-ractor", rb_int2str(objid, 10));
}
}
@@ -1815,11 +2423,12 @@ id2ref(VALUE objid)
static VALUE
os_id2ref(VALUE os, VALUE objid)
{
+ rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "ObjectSpace._id2ref is deprecated");
return id2ref(objid);
}
static VALUE
-rb_find_object_id(void *objspace, VALUE obj, VALUE (*get_heap_object_id)(void *, VALUE))
+rb_find_object_id(void *objspace, VALUE obj, VALUE (*get_heap_object_id)(VALUE))
{
if (SPECIAL_CONST_P(obj)) {
#if SIZEOF_LONG == SIZEOF_VOIDP
@@ -1829,11 +2438,11 @@ rb_find_object_id(void *objspace, VALUE obj, VALUE (*get_heap_object_id)(void *,
#endif
}
- return get_heap_object_id(objspace, obj);
+ return get_heap_object_id(obj);
}
static VALUE
-nonspecial_obj_id(void *_objspace, VALUE obj)
+nonspecial_obj_id(VALUE obj)
{
#if SIZEOF_LONG == SIZEOF_VOIDP
return (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG);
@@ -1884,25 +2493,79 @@ rb_obj_id(VALUE obj)
* Otherwise, the object ID is a Numeric that is a non-zero multiple of
* (RUBY_IMMEDIATE_MASK + 1) which guarantees that it does not collide with
* any immediates. */
- return rb_find_object_id(rb_gc_get_objspace(), obj, rb_gc_impl_object_id);
+ return rb_find_object_id(rb_gc_get_objspace(), obj, object_id);
}
-static enum rb_id_table_iterator_result
-cc_table_memsize_i(VALUE ccs_ptr, void *data_ptr)
+bool
+rb_obj_id_p(VALUE obj)
{
- size_t *total_size = data_ptr;
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- *total_size += sizeof(*ccs);
- *total_size += sizeof(ccs->entries[0]) * ccs->capa;
- return ID_TABLE_CONTINUE;
+ return !RB_TYPE_P(obj, T_IMEMO) && rb_obj_shape_has_id(obj);
}
-static size_t
-cc_table_memsize(struct rb_id_table *cc_table)
+/*
+ * GC implementations should call this function before the GC phase that updates references
+ * embedded in the machine code generated by JIT compilers. JIT compilers usually enforce the
+ * "W^X" policy and protect the code memory from being modified during execution. This function
+ * makes the code memory writeable.
+ */
+void
+rb_gc_before_updating_jit_code(void)
+{
+#if USE_YJIT
+ rb_yjit_mark_all_writeable();
+#endif
+#if USE_ZJIT
+ rb_zjit_mark_all_writable();
+#endif
+}
+
+/*
+ * GC implementations should call this function before the GC phase that updates references
+ * embedded in the machine code generated by JIT compilers. This function makes the code memory
+ * executable again.
+ */
+void
+rb_gc_after_updating_jit_code(void)
+{
+#if USE_YJIT
+ rb_yjit_mark_all_executable();
+#endif
+#if USE_ZJIT
+ rb_zjit_mark_all_executable();
+#endif
+}
+
+static void
+classext_memsize(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
+{
+ size_t *size = (size_t *)arg;
+ size_t s = 0;
+
+ if (RCLASSEXT_M_TBL(ext)) {
+ s += rb_id_table_memsize(RCLASSEXT_M_TBL(ext));
+ }
+ if (RCLASSEXT_CONST_TBL(ext)) {
+ s += rb_id_table_memsize(RCLASSEXT_CONST_TBL(ext));
+ }
+ if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
+ s += (RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1) * sizeof(VALUE);
+ }
+ if (!prime) {
+ s += sizeof(rb_classext_t);
+ }
+ *size += s;
+}
+
+static void
+classext_superclasses_memsize(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
{
- size_t total = rb_id_table_memsize(cc_table);
- rb_id_table_foreach_values(cc_table, cc_table_memsize_i, &total);
- return total;
+ size_t *size = (size_t *)arg;
+ size_t array_size;
+ if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
+ RUBY_ASSERT(prime);
+ array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1;
+ *size += array_size * sizeof(VALUE);
+ }
}
size_t
@@ -1914,38 +2577,21 @@ rb_obj_memsize_of(VALUE obj)
return 0;
}
- if (FL_TEST(obj, FL_EXIVAR)) {
- size += rb_generic_ivar_memsize(obj);
- }
-
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- if (rb_shape_obj_too_complex(obj)) {
- size += rb_st_memsize(ROBJECT_IV_HASH(obj));
- }
- else if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
- size += ROBJECT_IV_CAPACITY(obj) * sizeof(VALUE);
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(obj)) {
+ size += rb_st_memsize(ROBJECT_FIELDS_HASH(obj));
+ }
+ else {
+ size += ROBJECT_FIELDS_CAPACITY(obj) * sizeof(VALUE);
+ }
}
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);
- }
+ rb_class_classext_foreach(obj, classext_memsize, (void *)&size);
+ rb_class_classext_foreach(obj, classext_superclasses_memsize, (void *)&size);
break;
case T_ICLASS:
if (RICLASS_OWNS_M_TBL_P(obj)) {
@@ -1953,9 +2599,6 @@ rb_obj_memsize_of(VALUE obj)
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
}
- if (RCLASS_CC_TBL(obj)) {
- size += cc_table_memsize(RCLASS_CC_TBL(obj));
- }
break;
case T_STRING:
size += rb_str_memsize(obj);
@@ -1980,8 +2623,10 @@ rb_obj_memsize_of(VALUE obj)
break;
case T_MATCH:
{
- rb_matchext_t *rm = RMATCH_EXT(obj);
- size += onig_region_memsize(&rm->regs);
+ struct RMatch *rm = RMATCH(obj);
+ if (FL_TEST_RAW(obj, RMATCH_ONIG)) {
+ size += onig_region_memsize(&rm->as.onig);
+ }
size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
}
break;
@@ -2012,9 +2657,8 @@ rb_obj_memsize_of(VALUE obj)
break;
case T_STRUCT:
- if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
- RSTRUCT(obj)->as.heap.ptr) {
- size += sizeof(VALUE) * RSTRUCT_LEN(obj);
+ if (RSTRUCT_EMBED_LEN(obj) == 0) {
+ size += sizeof(VALUE) * RSTRUCT_LEN_RAW(obj);
}
break;
@@ -2062,34 +2706,39 @@ count_objects_i(VALUE obj, void *d)
/*
* call-seq:
- * ObjectSpace.count_objects([result_hash]) -> hash
+ * ObjectSpace.count_objects(result_hash = {}) -> hash
+ *
+ * Counts the number of objects, grouped by type.
*
- * Counts all objects grouped by type.
+ * It returns a hash that looks like:
*
- * It returns a hash, such as:
- * {
- * :TOTAL=>10000,
- * :FREE=>3011,
- * :T_OBJECT=>6,
- * :T_CLASS=>404,
- * # ...
- * }
+ * {
+ * TOTAL: 10000,
+ * FREE: 3011,
+ * T_OBJECT: 6,
+ * T_CLASS: 404,
+ * # ...
+ * }
*
- * The contents of the returned hash are implementation specific.
- * It may be changed in future.
+ * The contents of the returned hash are implementation specific and
+ * may be changed in future versions without notice.
*
- * The keys starting with +:T_+ means live objects.
+ * The keys starting with +:T_+ are live objects of a particular type.
* For example, +:T_ARRAY+ is the number of arrays.
- * +:FREE+ means object slots which is not used now.
- * +:TOTAL+ means sum of above.
+ *
+ * The key +:FREE+ is the number of object slots which are empty.
+ *
+ * The key +:TOTAL+ is the total number of slots (which is the sum of
+ * all of the other values).
*
* If the optional argument +result_hash+ is given,
- * it is overwritten and returned. This is intended to avoid probe effect.
+ * it is overwritten and returned.
+ * This is intended to avoid the probe effect.
*
* h = {}
* ObjectSpace.count_objects(h)
* puts h
- * # => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }
+ * # => { TOTAL: 10000, T_CLASS: 158280, T_MODULE: 20672, T_STRING: 527249 }
*
* This method is only expected to work on C Ruby.
*
@@ -2100,6 +2749,7 @@ count_objects(int argc, VALUE *argv, VALUE os)
{
struct count_objects_data data = { 0 };
VALUE hash = Qnil;
+ VALUE types[T_MASK + 1];
if (rb_check_arity(argc, 0, 1) == 1) {
hash = argv[0];
@@ -2107,6 +2757,17 @@ count_objects(int argc, VALUE *argv, VALUE os)
rb_raise(rb_eTypeError, "non-hash given");
}
+ for (size_t i = 0; i <= T_MASK; i++) {
+ // type_sym can allocate an object,
+ // so we need to create all key symbols in advance
+ // not to disturb the result
+ types[i] = type_sym(i);
+ }
+
+ // Same as type_sym, we need to create all key symbols in advance
+ VALUE total = ID2SYM(rb_intern("TOTAL"));
+ VALUE free = ID2SYM(rb_intern("FREE"));
+
rb_gc_impl_each_object(rb_gc_get_objspace(), count_objects_i, &data);
if (NIL_P(hash)) {
@@ -2115,13 +2776,13 @@ count_objects(int argc, VALUE *argv, VALUE os)
else if (!RHASH_EMPTY_P(hash)) {
rb_hash_stlike_foreach(hash, set_zero, hash);
}
- rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(data.total));
- rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(data.freed));
+ rb_hash_aset(hash, total, SIZET2NUM(data.total));
+ rb_hash_aset(hash, free, SIZET2NUM(data.freed));
for (size_t i = 0; i <= T_MASK; i++) {
- VALUE type = type_sym(i);
- if (data.counts[i])
- rb_hash_aset(hash, type, SIZET2NUM(data.counts[i]));
+ if (data.counts[i]) {
+ rb_hash_aset(hash, types[i], SIZET2NUM(data.counts[i]));
+ }
}
return hash;
@@ -2265,29 +2926,6 @@ rb_gc_mark_maybe(VALUE obj)
gc_mark_maybe_internal(obj);
}
-void
-rb_gc_mark_weak(VALUE *ptr)
-{
- if (RB_SPECIAL_CONST_P(*ptr)) return;
-
- rb_vm_t *vm = GET_VM();
- void *objspace = vm->gc.objspace;
- if (LIKELY(vm->gc.mark_func_data == NULL)) {
- GC_ASSERT(rb_gc_impl_during_gc_p(objspace));
-
- rb_gc_impl_mark_weak(objspace, ptr);
- }
- else {
- GC_ASSERT(!rb_gc_impl_during_gc_p(objspace));
- }
-}
-
-void
-rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr)
-{
- rb_gc_impl_remove_weak(rb_gc_get_objspace(), parent_obj, ptr);
-}
-
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data));
static void
each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data)
@@ -2415,6 +3053,25 @@ mark_m_tbl(void *objspace, struct rb_id_table *tbl)
}
}
+static enum rb_id_table_iterator_result
+mark_const_entry_i(VALUE value, void *objspace)
+{
+ const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
+
+ if (!rb_gc_checking_shareable()) {
+ gc_mark_internal(ce->value);
+ gc_mark_internal(ce->file); // TODO: ce->file should be shareable?
+ }
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+mark_const_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
+{
+ if (!tbl) return;
+ rb_id_table_foreach_values(tbl, mark_const_entry_i, objspace);
+}
+
#if STACK_GROW_DIRECTION < 0
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
#elif STACK_GROW_DIRECTION > 0
@@ -2445,6 +3102,16 @@ gc_mark_machine_stack_location_maybe(VALUE obj, void *data)
#endif
}
+static bool
+gc_object_moved_p_internal(void *objspace, VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) {
+ return false;
+ }
+
+ return rb_gc_impl_object_moved_p(objspace, obj);
+}
+
static VALUE
gc_location_internal(void *objspace, VALUE value)
{
@@ -2577,26 +3244,12 @@ rb_mark_tbl_no_pin(st_table *tbl)
gc_mark_tbl_no_pin(tbl);
}
-static enum rb_id_table_iterator_result
-mark_cvc_tbl_i(VALUE cvc_entry, void *objspace)
+void
+rb_gc_mark_set_no_pin(st_table *tbl)
{
- 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_internal((VALUE)entry->cref);
-
- return ID_TABLE_CONTINUE;
-}
+ if (!tbl || tbl->num_entries == 0) return;
-static void
-mark_cvc_tbl(void *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);
- }
+ st_foreach(tbl, gc_mark_set_no_pin_i, 0);
}
static bool
@@ -2605,21 +3258,23 @@ gc_declarative_marking_p(const rb_data_type_t *type)
return (type->flags & RUBY_TYPED_DECL_MARKING) != 0;
}
-static enum rb_id_table_iterator_result
-mark_const_table_i(VALUE value, void *objspace)
+rb_execution_context_t *
+rb_gc_get_ec(void)
{
- const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
-
- gc_mark_internal(ce->value);
- gc_mark_internal(ce->file);
+ void *objspace = rb_gc_get_objspace();
- return ID_TABLE_CONTINUE;
+ if (RB_LIKELY(rb_gc_impl_during_gc_p(objspace))) {
+ return rb_gc_impl_get_vm_context(objspace)->ec;
+ }
+ else {
+ return GET_EC();
+ }
}
void
rb_gc_mark_roots(void *objspace, const char **categoryp)
{
- rb_execution_context_t *ec = GET_EC();
+ rb_execution_context_t *ec = rb_gc_get_ec();
rb_vm_t *vm = rb_ec_vm_ptr(ec);
#define MARK_CHECKPOINT(category) do { \
@@ -2628,7 +3283,6 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
MARK_CHECKPOINT("vm");
rb_vm_mark(vm);
- if (vm->self) gc_mark_internal(vm->self);
MARK_CHECKPOINT("end_proc");
rb_mark_end_proc();
@@ -2645,42 +3299,102 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
}
#endif
+#if USE_ZJIT
+ void rb_zjit_root_mark(void);
+ if (rb_zjit_enabled_p) {
+ MARK_CHECKPOINT("ZJIT");
+ rb_zjit_root_mark();
+ }
+#endif
+
MARK_CHECKPOINT("machine_context");
mark_current_machine_context(ec);
MARK_CHECKPOINT("global_symbols");
- rb_sym_global_symbols_mark();
+ rb_sym_global_symbols_mark_and_move();
MARK_CHECKPOINT("finish");
#undef MARK_CHECKPOINT
}
-#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA(d)->type->function.dmark
+struct gc_mark_classext_foreach_arg {
+ rb_objspace_t *objspace;
+ VALUE obj;
+};
+
+static void
+gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
+{
+ struct gc_mark_classext_foreach_arg *foreach_arg = (struct gc_mark_classext_foreach_arg *)arg;
+ rb_objspace_t *objspace = foreach_arg->objspace;
+
+ if (RCLASSEXT_SUPER(ext)) {
+ gc_mark_internal(RCLASSEXT_SUPER(ext));
+ }
+ mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
+
+ if (!rb_gc_checking_shareable()) {
+ // unshareable
+ gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext));
+ gc_mark_internal(RCLASSEXT_CVC_TBL(ext));
+ }
+
+ if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) {
+ mark_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
+ }
+ mark_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
+ gc_mark_internal(RCLASSEXT_CC_TBL(ext));
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ gc_mark_internal(RCLASSEXT_SUBCLASSES(ext));
+ }
+ gc_mark_internal(RCLASSEXT_CLASSPATH(ext));
+}
+
+static void
+gc_mark_classext_iclass(rb_classext_t *ext, bool prime, VALUE box_value, void *arg)
+{
+ struct gc_mark_classext_foreach_arg *foreach_arg = (struct gc_mark_classext_foreach_arg *)arg;
+ rb_objspace_t *objspace = foreach_arg->objspace;
+
+ if (RCLASSEXT_SUPER(ext)) {
+ gc_mark_internal(RCLASSEXT_SUPER(ext));
+ }
+ if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
+ mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
+ }
+ if (RCLASSEXT_INCLUDER(ext)) {
+ gc_mark_internal(RCLASSEXT_INCLUDER(ext));
+ }
+ mark_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
+ gc_mark_internal(RCLASSEXT_CC_TBL(ext));
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ gc_mark_internal(RCLASSEXT_SUBCLASSES(ext));
+ }
+}
+
+#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA_TYPE(d)->function.dmark
void
-rb_gc_ractor_moved(VALUE dest, VALUE src)
+rb_gc_move_obj_during_marking(VALUE from, VALUE to)
{
- rb_gc_obj_free(rb_gc_get_objspace(), src);
- MEMZERO((void *)src, char, rb_gc_obj_slot_size(src));
- RBASIC(src)->flags = T_OBJECT | FL_FREEZE; // Avoid mutations using bind_call, etc.
+ if (rb_obj_using_gen_fields_table_p(to)) {
+ rb_mark_generic_ivar(from);
+ }
}
void
rb_gc_mark_children(void *objspace, VALUE obj)
{
- if (FL_TEST(obj, FL_EXIVAR)) {
+ struct gc_mark_classext_foreach_arg foreach_args;
+
+ if (rb_obj_using_gen_fields_table_p(obj)) {
rb_mark_generic_ivar(obj);
}
switch (BUILTIN_TYPE(obj)) {
case T_FLOAT:
case T_BIGNUM:
- case T_SYMBOL:
- /* Not immediates, but does not have references and singleton class.
- *
- * RSYMBOL(obj)->fstr intentionally not marked. See log for 96815f1e
- * ("symbol.c: remove rb_gc_mark_symbols()") */
return;
case T_NIL:
@@ -2704,47 +3418,27 @@ rb_gc_mark_children(void *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
+ if (FL_TEST_RAW(obj, FL_SINGLETON) &&
+ !rb_gc_checking_shareable()) {
gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj));
}
// Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
- if (RCLASS_SUPER(obj)) {
- gc_mark_internal(RCLASS_SUPER(obj));
+ foreach_args.objspace = objspace;
+ foreach_args.obj = obj;
+ rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
+ if (BOX_USER_P(RCLASS_PRIME_BOX(obj))) {
+ gc_mark_internal(RCLASS_PRIME_BOX(obj)->box_object);
}
-
- mark_m_tbl(objspace, RCLASS_M_TBL(obj));
- mark_cvc_tbl(objspace, obj);
- rb_cc_table_mark(obj);
- if (rb_shape_obj_too_complex(obj)) {
- gc_mark_tbl_no_pin((st_table *)RCLASS_IVPTR(obj));
- }
- else {
- for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
- gc_mark_internal(RCLASS_IVPTR(obj)[i]);
- }
- }
-
- if (RCLASS_CONST_TBL(obj)) {
- rb_id_table_foreach_values(RCLASS_CONST_TBL(obj), mark_const_table_i, objspace);
- }
-
- gc_mark_internal(RCLASS_EXT(obj)->classpath);
break;
case T_ICLASS:
- if (RICLASS_OWNS_M_TBL_P(obj)) {
- mark_m_tbl(objspace, RCLASS_M_TBL(obj));
- }
- if (RCLASS_SUPER(obj)) {
- gc_mark_internal(RCLASS_SUPER(obj));
- }
-
- if (RCLASS_INCLUDER(obj)) {
- gc_mark_internal(RCLASS_INCLUDER(obj));
+ foreach_args.objspace = objspace;
+ foreach_args.obj = obj;
+ rb_class_classext_foreach(obj, gc_mark_classext_iclass, (void *)&foreach_args);
+ if (BOX_USER_P(RCLASS_PRIME_BOX(obj))) {
+ gc_mark_internal(RCLASS_PRIME_BOX(obj)->box_object);
}
- mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
- rb_cc_table_mark(obj);
break;
case T_ARRAY:
@@ -2765,6 +3459,10 @@ rb_gc_mark_children(void *objspace, VALUE obj)
mark_hash(obj);
break;
+ case T_SYMBOL:
+ gc_mark_internal(RSYMBOL(obj)->fstr);
+ break;
+
case T_STRING:
if (STR_SHARED_P(obj)) {
if (STR_EMBED_P(RSTRING(obj)->as.heap.aux.shared)) {
@@ -2781,10 +3479,12 @@ rb_gc_mark_children(void *objspace, VALUE obj)
break;
case T_DATA: {
- void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *const ptr = RTYPEDDATA_GET_DATA(obj);
+
+ gc_mark_internal(RTYPEDDATA(obj)->fields_obj);
if (ptr) {
- if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA(obj)->type)) {
+ if (gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
@@ -2792,9 +3492,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
}
}
else {
- RUBY_DATA_FUNC mark_func = RTYPEDDATA_P(obj) ?
- RTYPEDDATA(obj)->type->function.dmark :
- RDATA(obj)->dmark;
+ RUBY_DATA_FUNC mark_func = RTYPEDDATA_TYPE(obj)->function.dmark;
if (mark_func) (*mark_func)(ptr);
}
}
@@ -2803,30 +3501,19 @@ rb_gc_mark_children(void *objspace, VALUE obj)
}
case T_OBJECT: {
- rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
-
- if (rb_shape_obj_too_complex(obj)) {
- gc_mark_tbl_no_pin(ROBJECT_IV_HASH(obj));
+ uint32_t len;
+ if (rb_obj_shape_complex_p(obj)) {
+ gc_mark_tbl_no_pin(ROBJECT_FIELDS_HASH(obj));
+ len = ROBJECT_FIELDS_COUNT_COMPLEX(obj);
}
else {
- const VALUE * const ptr = ROBJECT_IVPTR(obj);
+ const VALUE * const ptr = ROBJECT_FIELDS(obj);
- uint32_t len = ROBJECT_IV_COUNT(obj);
+ len = ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
for (uint32_t i = 0; i < len; i++) {
gc_mark_internal(ptr[i]);
}
}
-
- 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;
- if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) {
- RCLASS_EXT(klass)->max_iv_count = num_of_ivs;
- }
- }
-
break;
}
@@ -2840,6 +3527,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
gc_mark_internal(RFILE(obj)->fptr->encs.ecopts);
gc_mark_internal(RFILE(obj)->fptr->write_lock);
gc_mark_internal(RFILE(obj)->fptr->timeout);
+ gc_mark_internal(RFILE(obj)->fptr->wakeup_mutex);
}
break;
@@ -2872,6 +3560,10 @@ rb_gc_mark_children(void *objspace, VALUE obj)
gc_mark_internal(ptr[i]);
}
+ if (rb_obj_shape_has_fields(obj) && !FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
+ gc_mark_internal(RSTRUCT_FIELDS_OBJ(obj));
+ }
+
break;
}
@@ -2890,21 +3582,48 @@ rb_gc_obj_optimal_size(VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_ARRAY:
- return rb_ary_size_as_embedded(obj);
+ {
+ size_t size = rb_ary_size_as_embedded(obj);
+ if (rb_gc_size_allocatable_p(size)) {
+ return size;
+ }
+ else {
+ return sizeof(struct RArray);
+ }
+ }
case T_OBJECT:
- if (rb_shape_obj_too_complex(obj)) {
+ if (rb_obj_shape_complex_p(obj)) {
return sizeof(struct RObject);
}
else {
- return rb_obj_embedded_size(ROBJECT_IV_CAPACITY(obj));
+ size_t size = rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(obj));
+ if (rb_gc_size_allocatable_p(size)) {
+ return size;
+ }
+ else {
+ return sizeof(struct RObject);
+ }
}
case T_STRING:
- return rb_str_size_as_embedded(obj);
+ {
+ size_t size = rb_str_size_as_embedded(obj);
+ if (rb_gc_size_allocatable_p(size)) {
+ return size;
+ }
+ else {
+ return sizeof(struct RString);
+ }
+ }
case T_HASH:
- return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
+ {
+ if (RB_OBJ_FROZEN(obj) && RHASH_AR_TABLE_P(obj)) {
+ return sizeof(struct RHash) + offsetof(ar_table, pairs) + RHASH_AR_TABLE_BOUND(obj) * sizeof(ar_table_pair);
+ }
+ return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
+ }
default:
return 0;
@@ -2938,14 +3657,11 @@ rb_gc_copy_attributes(VALUE dest, VALUE obj)
rb_gc_impl_copy_attributes(rb_gc_get_objspace(), dest, obj);
}
+#if USE_MODULAR_GC
int
rb_gc_modular_gc_loaded_p(void)
{
-#if USE_MODULAR_GC
return rb_gc_functions.modular_gc_loaded_p;
-#else
- return false;
-#endif
}
const char *
@@ -2961,6 +3677,7 @@ rb_gc_active_gc_name(void)
return gc_name;
}
+#endif
struct rb_gc_object_metadata_entry *
rb_gc_object_metadata(VALUE obj)
@@ -2998,10 +3715,15 @@ rb_gc_register_address(VALUE *addr)
VALUE obj = *addr;
- struct global_object_list *tmp = ALLOC(struct global_object_list);
- tmp->next = vm->global_object_list;
- tmp->varptr = addr;
- vm->global_object_list = tmp;
+ RB_VM_LOCKING() {
+ if (vm->global_object_list_size == vm->global_object_list_capa) {
+ size_t new_capa = vm->global_object_list_capa ? vm->global_object_list_capa * 2 : 64;
+ SIZED_REALLOC_N(vm->global_object_list, VALUE *, new_capa, vm->global_object_list_capa);
+ vm->global_object_list_capa = new_capa;
+ }
+
+ vm->global_object_list[vm->global_object_list_size++] = addr;
+ }
/*
* Because some C extensions have assignment-then-register bugs,
@@ -3019,22 +3741,20 @@ void
rb_gc_unregister_address(VALUE *addr)
{
rb_vm_t *vm = GET_VM();
- struct global_object_list *tmp = vm->global_object_list;
-
- if (tmp->varptr == addr) {
- vm->global_object_list = tmp->next;
- xfree(tmp);
- return;
- }
- while (tmp->next) {
- if (tmp->next->varptr == addr) {
- struct global_object_list *t = tmp->next;
-
- tmp->next = tmp->next->next;
- xfree(t);
- break;
+ RB_VM_LOCKING() {
+ size_t index;
+ for (index = 0; index < vm->global_object_list_size; index++) {
+ if (addr == vm->global_object_list[index]) {
+ MEMMOVE(
+ vm->global_object_list[index],
+ &vm->global_object_list[index + 1],
+ VALUE *,
+ vm->global_object_list_size - index - 1
+ );
+ vm->global_object_list_size--;
+ break;
+ }
}
- tmp = tmp->next;
}
}
@@ -3133,24 +3853,26 @@ gc_ref_update_array(void *objspace, VALUE v)
static void
gc_ref_update_object(void *objspace, VALUE v)
{
- VALUE *ptr = ROBJECT_IVPTR(v);
+ VALUE *ptr = ROBJECT_FIELDS(v);
- if (rb_shape_obj_too_complex(v)) {
- gc_ref_update_table_values_only(ROBJECT_IV_HASH(v));
- return;
- }
+ if (FL_TEST_RAW(v, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(v)) {
+ gc_ref_update_table_values_only(ROBJECT_FIELDS_HASH(v));
+ return;
+ }
- 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);
- ptr = ROBJECT(v)->as.ary;
+ size_t slot_size = rb_gc_obj_slot_size(v);
+ size_t embed_size = rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(v));
+ if (slot_size >= embed_size) {
+ // Object can be re-embedded
+ memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_FIELDS_COUNT(v));
+ SIZED_FREE_N(ptr, ROBJECT_FIELDS_CAPACITY(v));
+ FL_UNSET_RAW(v, ROBJECT_HEAP);
+ ptr = ROBJECT(v)->as.ary;
+ }
}
- for (uint32_t i = 0; i < ROBJECT_IV_COUNT(v); i++) {
+ for (uint32_t i = 0; i < ROBJECT_FIELDS_COUNT(v); i++) {
UPDATE_IF_MOVED(objspace, ptr[i]);
}
}
@@ -3168,6 +3890,36 @@ rb_gc_update_tbl_refs(st_table *ptr)
gc_update_table_refs(ptr);
}
+static int
+rb_gc_update_set_refs_i(st_data_t key, st_data_t value, st_data_t argp, int error)
+{
+ if (rb_gc_location((VALUE)key) != (VALUE)key) {
+ return ST_REPLACE;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+rb_gc_update_set_refs_replace_i(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
+{
+ if (rb_gc_location((VALUE)*key) != (VALUE)*key) {
+ *key = rb_gc_location((VALUE)*key);
+ }
+
+ return ST_CONTINUE;
+}
+
+void
+rb_gc_update_set_refs(st_table *tbl)
+{
+ if (!tbl || tbl->num_entries == 0) return;
+
+ if (st_foreach_with_replace(tbl, rb_gc_update_set_refs_i, rb_gc_update_set_refs_replace_i, 0)) {
+ rb_raise(rb_eRuntimeError, "hash modified during iteration");
+ }
+}
+
static void
gc_ref_update_hash(void *objspace, VALUE v)
{
@@ -3193,7 +3945,7 @@ check_id_table_move(VALUE value, void *data)
{
void *objspace = (void *)data;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) {
+ if (gc_object_moved_p_internal(objspace, (VALUE)value)) {
return ID_TABLE_REPLACE;
}
@@ -3237,7 +3989,7 @@ update_id_table(VALUE *value, void *data, int existing)
{
void *objspace = (void *)data;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) {
+ if (gc_object_moved_p_internal(objspace, (VALUE)*value)) {
*value = gc_location_internal(objspace, (VALUE)*value);
}
@@ -3253,112 +4005,95 @@ update_m_tbl(void *objspace, struct rb_id_table *tbl)
}
static enum rb_id_table_iterator_result
-update_cc_tbl_i(VALUE ccs_ptr, void *objspace)
+update_const_tbl_i(VALUE value, void *objspace)
{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VM_ASSERT(vm_ccs_p(ccs));
+ rb_const_entry_t *ce = (rb_const_entry_t *)value;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)ccs->cme)) {
- ccs->cme = (const rb_callable_method_entry_t *)gc_location_internal(objspace, (VALUE)ccs->cme);
+ if (gc_object_moved_p_internal(objspace, ce->value)) {
+ ce->value = gc_location_internal(objspace, ce->value);
}
- for (int i=0; i<ccs->len; i++) {
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)ccs->entries[i].cc)) {
- ccs->entries[i].cc = (struct rb_callcache *)gc_location_internal(objspace, (VALUE)ccs->entries[i].cc);
- }
+ if (gc_object_moved_p_internal(objspace, ce->file)) {
+ ce->file = gc_location_internal(objspace, ce->file);
}
- // do not replace
return ID_TABLE_CONTINUE;
}
static void
-update_cc_tbl(void *objspace, VALUE klass)
+update_const_tbl(void *objspace, struct rb_id_table *tbl)
{
- struct rb_id_table *tbl = RCLASS_CC_TBL(klass);
- if (tbl) {
- rb_id_table_foreach_values(tbl, update_cc_tbl_i, objspace);
- }
+ if (!tbl) return;
+ rb_id_table_foreach_values(tbl, update_const_tbl_i, objspace);
}
-static enum rb_id_table_iterator_result
-update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
+static void
+update_superclasses(rb_objspace_t *objspace, rb_classext_t *ext)
{
- struct rb_cvar_class_tbl_entry *entry;
-
- entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
-
- if (entry->cref) {
- TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, entry->cref);
+ if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
+ size_t array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1;
+ for (size_t i = 0; i < array_size; i++) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPERCLASSES(ext)[i]);
+ }
}
-
- entry->class_value = gc_location_internal(objspace, entry->class_value);
-
- return ID_TABLE_CONTINUE;
}
static void
-update_cvc_tbl(void *objspace, VALUE klass)
+update_classext_values(rb_objspace_t *objspace, rb_classext_t *ext, bool is_iclass)
{
- struct rb_id_table *tbl = RCLASS_CVC_TBL(klass);
- if (tbl) {
- rb_id_table_foreach_values(tbl, update_cvc_tbl_i, objspace);
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_ORIGIN(ext));
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_REFINED_CLASS(ext));
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CLASSPATH(ext));
+ if (is_iclass) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_INCLUDER(ext));
}
}
-static enum rb_id_table_iterator_result
-update_const_table(VALUE value, void *objspace)
+static void
+update_classext(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
- rb_const_entry_t *ce = (rb_const_entry_t *)value;
+ struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
+ rb_objspace_t *objspace = args->objspace;
- if (rb_gc_impl_object_moved_p(objspace, ce->value)) {
- ce->value = gc_location_internal(objspace, ce->value);
+ if (RCLASSEXT_SUPER(ext)) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPER(ext));
}
- if (rb_gc_impl_object_moved_p(objspace, ce->file)) {
- ce->file = gc_location_internal(objspace, ce->file);
+ update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
+
+ UPDATE_IF_MOVED(objspace, ext->fields_obj);
+ if (!RCLASSEXT_SHARED_CONST_TBL(ext)) {
+ update_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
+ }
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CC_TBL(ext));
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CVC_TBL(ext));
+ update_superclasses(objspace, ext);
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUBCLASSES(ext));
}
- return ID_TABLE_CONTINUE;
+ update_classext_values(objspace, ext, false);
}
static void
-update_const_tbl(void *objspace, struct rb_id_table *tbl)
+update_iclass_classext(rb_classext_t *ext, bool is_prime, VALUE box_value, void *arg)
{
- if (!tbl) return;
- rb_id_table_foreach_values(tbl, update_const_table, objspace);
-}
+ struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
+ rb_objspace_t *objspace = args->objspace;
-static void
-update_subclass_entries(void *objspace, rb_subclass_entry_t *entry)
-{
- while (entry) {
- UPDATE_IF_MOVED(objspace, entry->klass);
- entry = entry->next;
+ if (RCLASSEXT_SUPER(ext)) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPER(ext));
}
-}
-
-static void
-update_class_ext(void *objspace, rb_classext_t *ext)
-{
- UPDATE_IF_MOVED(objspace, ext->origin_);
- UPDATE_IF_MOVED(objspace, ext->includer);
- UPDATE_IF_MOVED(objspace, ext->refined_class);
- update_subclass_entries(objspace, ext->subclasses);
-}
-
-static void
-update_superclasses(void *objspace, VALUE obj)
-{
- if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
- for (size_t i = 0; i < RCLASS_SUPERCLASS_DEPTH(obj) + 1; i++) {
- UPDATE_IF_MOVED(objspace, RCLASS_SUPERCLASSES(obj)[i]);
- }
+ update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
+ update_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CC_TBL(ext));
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_CVC_TBL(ext));
+ if (RCLASSEXT_SUBCLASSES(ext)) {
+ UPDATE_IF_MOVED(objspace, RCLASSEXT_SUBCLASSES(ext));
}
-}
-extern rb_symbols_t ruby_global_symbols;
-#define global_symbols ruby_global_symbols
+ update_classext_values(objspace, ext, true);
+}
struct global_vm_table_foreach_data {
vm_table_foreach_callback_func callback;
@@ -3400,146 +4135,130 @@ vm_weak_table_foreach_update_weak_key(st_data_t *key, st_data_t *value, st_data_
}
static int
-vm_weak_table_str_sym_foreach(st_data_t key, st_data_t value, st_data_t data, int error)
+vm_weak_table_sym_set_foreach(VALUE *sym_ptr, void *data)
{
+ VALUE sym = *sym_ptr;
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
- if (!iter_data->weak_only) {
- int ret = iter_data->callback((VALUE)key, iter_data->data);
- if (ret != ST_CONTINUE) return ret;
- }
-
- if (STATIC_SYM_P(value)) {
- return ST_CONTINUE;
- }
- else {
- return iter_data->callback((VALUE)value, iter_data->data);
- }
-}
+ if (RB_SPECIAL_CONST_P(sym)) return ST_CONTINUE;
-static int
-vm_weak_table_foreach_update_weak_value(st_data_t *key, st_data_t *value, st_data_t data, int existing)
-{
- struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
+ int ret = iter_data->callback(sym, iter_data->data);
- if (!iter_data->weak_only) {
- int ret = iter_data->update_callback((VALUE *)key, iter_data->data);
- if (ret != ST_CONTINUE) return ret;
+ if (ret == ST_REPLACE) {
+ ret = iter_data->update_callback(sym_ptr, iter_data->data);
}
- return iter_data->update_callback((VALUE *)value, iter_data->data);
+ return ret;
}
-static void
-free_gen_ivtbl(VALUE obj, struct gen_ivtbl *ivtbl)
-{
- if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
- st_free_table(ivtbl->as.complex.table);
- }
-
- xfree(ivtbl);
-}
+struct st_table *rb_generic_fields_tbl_get(void);
static int
-vm_weak_table_gen_ivar_foreach_too_complex_i(st_data_t _key, st_data_t value, st_data_t data, int error)
+vm_weak_table_id2ref_foreach(st_data_t key, st_data_t value, st_data_t data, int error)
{
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
- GC_ASSERT(!iter_data->weak_only);
-
- if (SPECIAL_CONST_P((VALUE)value)) return ST_CONTINUE;
+ if (!iter_data->weak_only && !FIXNUM_P((VALUE)key)) {
+ int ret = iter_data->callback((VALUE)key, iter_data->data);
+ if (ret != ST_CONTINUE) return ret;
+ }
return iter_data->callback((VALUE)value, iter_data->data);
}
static int
-vm_weak_table_gen_ivar_foreach_too_complex_replace_i(st_data_t *_key, st_data_t *value, st_data_t data, int existing)
+vm_weak_table_id2ref_foreach_update(st_data_t *key, st_data_t *value, st_data_t data, int existing)
{
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
- GC_ASSERT(!iter_data->weak_only);
+ iter_data->update_callback((VALUE *)value, iter_data->data);
- return iter_data->update_callback((VALUE *)value, iter_data->data);
-}
+ if (!iter_data->weak_only && !FIXNUM_P((VALUE)*key)) {
+ iter_data->update_callback((VALUE *)key, iter_data->data);
+ }
-struct st_table *rb_generic_ivtbl_get(void);
+ return ST_CONTINUE;
+}
static int
-vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data)
+vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data)
{
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
int ret = iter_data->callback((VALUE)key, iter_data->data);
+ VALUE new_value = (VALUE)value;
+ VALUE new_key = (VALUE)key;
+
switch (ret) {
case ST_CONTINUE:
break;
case ST_DELETE:
- free_gen_ivtbl((VALUE)key, (struct gen_ivtbl *)value);
-
- FL_UNSET((VALUE)key, FL_EXIVAR);
+ // When we're removing an object from the weak ref table, we need to
+ // set the shape on it so that the GC finalizer won't try to remove
+ // it again. A "root shape" indicates to the GC that this object
+ // has no fields on it, hence it won't be in the gen fields table.
+ RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
return ST_DELETE;
case ST_REPLACE: {
- VALUE new_key = (VALUE)key;
ret = iter_data->update_callback(&new_key, iter_data->data);
- if (key != new_key) ret = ST_DELETE;
- DURING_GC_COULD_MALLOC_REGION_START();
- {
- st_insert(rb_generic_ivtbl_get(), (st_data_t)new_key, value);
+ if (key != new_key) {
+ ret = ST_DELETE;
}
- DURING_GC_COULD_MALLOC_REGION_END();
- key = (st_data_t)new_key;
break;
}
default:
- return ret;
+ rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ret);
}
if (!iter_data->weak_only) {
- struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)value;
+ int ivar_ret = iter_data->callback(new_value, iter_data->data);
+ switch (ivar_ret) {
+ case ST_CONTINUE:
+ break;
- if (rb_shape_obj_too_complex((VALUE)key)) {
- st_foreach_with_replace(
- ivtbl->as.complex.table,
- vm_weak_table_gen_ivar_foreach_too_complex_i,
- vm_weak_table_gen_ivar_foreach_too_complex_replace_i,
- data
- );
+ case ST_REPLACE:
+ iter_data->update_callback(&new_value, iter_data->data);
+ break;
+
+ default:
+ rb_bug("vm_weak_table_gen_fields_foreach: return value %d not supported", ivar_ret);
}
- else {
- for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
- if (SPECIAL_CONST_P(ivtbl->as.shape.ivptr[i])) continue;
+ }
- int ivar_ret = iter_data->callback(ivtbl->as.shape.ivptr[i], iter_data->data);
- switch (ivar_ret) {
- case ST_CONTINUE:
- break;
- case ST_REPLACE:
- iter_data->update_callback(&ivtbl->as.shape.ivptr[i], iter_data->data);
- break;
- default:
- rb_bug("vm_weak_table_gen_ivar_foreach: return value %d not supported", ivar_ret);
- }
- }
+ if (key != new_key || value != new_value) {
+ DURING_GC_COULD_MALLOC_REGION_START();
+ {
+ st_insert(rb_generic_fields_tbl_get(), (st_data_t)new_key, new_value);
}
+ DURING_GC_COULD_MALLOC_REGION_END();
}
return ret;
}
static int
-vm_weak_table_frozen_strings_foreach(st_data_t key, st_data_t value, st_data_t data, int error)
+vm_weak_table_frozen_strings_foreach(VALUE *str, void *data)
{
- int retval = vm_weak_table_foreach_weak_key(key, value, data, error);
+ // int retval = vm_weak_table_foreach_weak_key(key, value, data, error);
+ struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
+ int retval = iter_data->callback(*str, iter_data->data);
+
+ if (retval == ST_REPLACE) {
+ retval = iter_data->update_callback(str, iter_data->data);
+ }
+
if (retval == ST_DELETE) {
- FL_UNSET((VALUE)key, RSTRING_FSTR);
+ FL_UNSET(*str, RSTRING_FSTR);
}
+
return retval;
}
+void rb_fstring_foreach_with_replace(int (*callback)(VALUE *str, void *data), void *data);
void
rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
vm_table_update_callback_func update_callback,
@@ -3558,60 +4277,61 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
switch (table) {
case RB_GC_VM_CI_TABLE: {
- if (vm->ci_table) {
- st_foreach_with_replace(
- vm->ci_table,
- vm_weak_table_foreach_weak_key,
- vm_weak_table_foreach_update_weak_key,
- (st_data_t)&foreach_data
- );
- }
+ st_foreach_with_replace(
+ &vm->ci_table,
+ vm_weak_table_foreach_weak_key,
+ vm_weak_table_foreach_update_weak_key,
+ (st_data_t)&foreach_data
+ );
break;
}
case RB_GC_VM_OVERLOADED_CME_TABLE: {
- if (vm->overloaded_cme_table) {
- st_foreach_with_replace(
- vm->overloaded_cme_table,
- vm_weak_table_foreach_weak_key,
- vm_weak_table_foreach_update_weak_key,
- (st_data_t)&foreach_data
- );
- }
+ st_foreach_with_replace(
+ &vm->overloaded_cme_table,
+ vm_weak_table_foreach_weak_key,
+ vm_weak_table_foreach_update_weak_key,
+ (st_data_t)&foreach_data
+ );
break;
}
case RB_GC_VM_GLOBAL_SYMBOLS_TABLE: {
- if (global_symbols.str_sym) {
+ rb_sym_global_symbol_table_foreach_weak_reference(
+ vm_weak_table_sym_set_foreach,
+ &foreach_data
+ );
+ break;
+ }
+ case RB_GC_VM_ID2REF_TABLE: {
+ if (id2ref_tbl) {
st_foreach_with_replace(
- global_symbols.str_sym,
- vm_weak_table_str_sym_foreach,
- vm_weak_table_foreach_update_weak_value,
+ id2ref_tbl,
+ vm_weak_table_id2ref_foreach,
+ vm_weak_table_id2ref_foreach_update,
(st_data_t)&foreach_data
);
}
break;
}
- case RB_GC_VM_GENERIC_IV_TABLE: {
- st_table *generic_iv_tbl = rb_generic_ivtbl_get();
- if (generic_iv_tbl) {
+ case RB_GC_VM_GENERIC_FIELDS_TABLE: {
+ st_table *generic_fields_tbl = rb_generic_fields_tbl_get();
+ if (generic_fields_tbl) {
st_foreach(
- generic_iv_tbl,
- vm_weak_table_gen_ivar_foreach,
+ generic_fields_tbl,
+ vm_weak_table_gen_fields_foreach,
(st_data_t)&foreach_data
);
}
break;
}
case RB_GC_VM_FROZEN_STRINGS_TABLE: {
- if (vm->frozen_strings) {
- st_foreach_with_replace(
- vm->frozen_strings,
- vm_weak_table_frozen_strings_foreach,
- vm_weak_table_foreach_update_weak_key,
- (st_data_t)&foreach_data
- );
- }
+ rb_fstring_foreach_with_replace(
+ vm_weak_table_frozen_strings_foreach,
+ &foreach_data
+ );
break;
}
+ case RB_GC_VM_WEAK_TABLE_COUNT:
+ rb_bug("Unreachable");
default:
rb_bug("rb_gc_vm_weak_table_foreach: unknown table %d", table);
}
@@ -3625,7 +4345,7 @@ rb_gc_update_vm_references(void *objspace)
rb_vm_update_references(vm);
rb_gc_update_global_tbl();
- rb_sym_global_symbols_update_references();
+ rb_sym_global_symbols_mark_and_move();
#if USE_YJIT
void rb_yjit_root_update_references(void); // in Rust
@@ -3634,51 +4354,36 @@ rb_gc_update_vm_references(void *objspace)
rb_yjit_root_update_references();
}
#endif
+
+#if USE_ZJIT
+ void rb_zjit_root_update_references(void); // in Rust
+
+ if (rb_zjit_enabled_p) {
+ rb_zjit_root_update_references();
+ }
+#endif
}
void
rb_gc_update_object_references(void *objspace, VALUE obj)
{
+ struct classext_foreach_args args;
+
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
+ if (FL_TEST_RAW(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);
- }
- 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(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]);
- }
- }
-
- update_class_ext(objspace, RCLASS_EXT(obj));
- update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
-
- UPDATE_IF_MOVED(objspace, RCLASS_EXT(obj)->classpath);
+ args.klass = obj;
+ args.objspace = objspace;
+ rb_class_classext_foreach(obj, update_classext, (void *)&args);
break;
case T_ICLASS:
- if (RICLASS_OWNS_M_TBL_P(obj)) {
- update_m_tbl(objspace, RCLASS_M_TBL(obj));
- }
- if (RCLASS_SUPER((VALUE)obj)) {
- UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
- }
- update_class_ext(objspace, RCLASS_EXT(obj));
- update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
- update_cc_tbl(objspace, obj);
+ args.objspace = objspace;
+ rb_class_classext_foreach(obj, update_iclass_classext, (void *)&args);
break;
case T_IMEMO:
@@ -3721,9 +4426,12 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
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 = RTYPEDDATA_GET_DATA(obj);
+
+ UPDATE_IF_MOVED(objspace, RTYPEDDATA(obj)->fields_obj);
+
if (ptr) {
- if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA(obj)->type)) {
+ if (gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
@@ -3731,8 +4439,8 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
*ref = gc_location_internal(objspace, *ref);
}
}
- else if (RTYPEDDATA_P(obj)) {
- RUBY_DATA_FUNC compact_func = RTYPEDDATA(obj)->type->function.dcompact;
+ else {
+ RUBY_DATA_FUNC compact_func = RTYPEDDATA_TYPE(obj)->function.dcompact;
if (compact_func) (*compact_func)(ptr);
}
}
@@ -3752,6 +4460,8 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->writeconv_pre_ecopts);
UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->encs.ecopts);
UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->write_lock);
+ UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->timeout);
+ UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->wakeup_mutex);
}
break;
case T_REGEXP:
@@ -3793,6 +4503,15 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
for (i = 0; i < len; i++) {
UPDATE_IF_MOVED(objspace, ptr[i]);
}
+
+ if (RSTRUCT_EMBED_LEN(obj)) {
+ if (!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
+ UPDATE_IF_MOVED(objspace, ptr[len]);
+ }
+ }
+ else {
+ UPDATE_IF_MOVED(objspace, RSTRUCT(obj)->as.heap.fields_obj);
+ }
}
break;
default:
@@ -3946,7 +4665,7 @@ gc_config_set(rb_execution_context_t *ec, VALUE self, VALUE hash)
rb_gc_impl_config_set(objspace, hash);
- return rb_gc_impl_config_get(objspace);
+ return Qnil;
}
static VALUE
@@ -4039,8 +4758,7 @@ ruby_gc_set_params(void)
void
rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data)
{
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_objspace_reachable_objects_from() is not supported while during GC");
if (!RB_SPECIAL_CONST_P(obj)) {
@@ -4056,7 +4774,6 @@ rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *
vm->gc.mark_func_data = prev_mfd;
}
}
- RB_VM_LOCK_LEAVE();
}
struct root_objects_data {
@@ -4151,7 +4868,7 @@ rb_method_type_name(rb_method_type_t type)
{
switch (type) {
case VM_METHOD_TYPE_ISEQ: return "iseq";
- case VM_METHOD_TYPE_ATTRSET: return "attrest";
+ case VM_METHOD_TYPE_ATTRSET: return "attrset";
case VM_METHOD_TYPE_IVAR: return "ivar";
case VM_METHOD_TYPE_BMETHOD: return "bmethod";
case VM_METHOD_TYPE_ALIAS: return "alias";
@@ -4218,6 +4935,7 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
// const int age = RVALUE_AGE_GET(obj);
if (rb_gc_impl_pointer_to_heap_p(rb_gc_get_objspace(), (void *)obj)) {
+ APPEND_F("%p %s/", (void *)obj, obj_type_name(obj));
// TODO: fixme
// APPEND_F("%p [%d%s%s%s%s%s%s] %s ",
// (void *)obj, age,
@@ -4243,9 +4961,9 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
APPEND_S("(temporary internal)");
}
else if (RTEST(RBASIC(obj)->klass)) {
- VALUE class_path = rb_class_path_cached(RBASIC(obj)->klass);
+ VALUE class_path = rb_mod_name(RBASIC(obj)->klass);
if (!NIL_P(class_path)) {
- APPEND_F("(%s)", RSTRING_PTR(class_path));
+ APPEND_F("%s ", RSTRING_PTR(class_path));
}
}
}
@@ -4271,22 +4989,29 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
APPEND_S("shared -> ");
rb_raw_obj_info(BUFF_ARGS, ARY_SHARED_ROOT(obj));
}
- else if (ARY_EMBED_P(obj)) {
- APPEND_F("[%s%s] len: %ld (embed)",
- C(ARY_EMBED_P(obj), "E"),
- C(ARY_SHARED_P(obj), "S"),
- RARRAY_LEN(obj));
- }
else {
- APPEND_F("[%s%s] len: %ld, capa:%ld ptr:%p",
- C(ARY_EMBED_P(obj), "E"),
+ APPEND_F("[%s%s%s] ",
+ C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
- RARRAY_LEN(obj),
- ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa,
- (void *)RARRAY_CONST_PTR(obj));
+ C(ARY_SHARED_ROOT_P(obj), "R"));
+
+ if (ARY_EMBED_P(obj)) {
+ APPEND_F("len: %ld (embed)",
+ RARRAY_LEN(obj));
+ }
+ else {
+ APPEND_F("len: %ld, capa:%ld ptr:%p",
+ RARRAY_LEN(obj),
+ RARRAY(obj)->as.heap.aux.capa,
+ (void *)RARRAY_CONST_PTR(obj));
+ }
}
break;
case T_STRING: {
+ APPEND_F("[%s%s] ",
+ C(FL_TEST(obj, RSTRING_FSTR), "F"),
+ C(RB_OBJ_FROZEN(obj), "R"));
+
if (STR_SHARED_P(obj)) {
APPEND_F(" [shared] len: %ld", RSTRING_LEN(obj));
}
@@ -4322,7 +5047,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
case T_CLASS:
case T_MODULE:
{
- VALUE class_path = rb_class_path_cached(obj);
+ VALUE class_path = rb_mod_name(obj);
if (!NIL_P(class_path)) {
APPEND_F("%s", RSTRING_PTR(class_path));
}
@@ -4333,7 +5058,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
}
case T_ICLASS:
{
- VALUE class_path = rb_class_path_cached(RBASIC_CLASS(obj));
+ VALUE class_path = rb_mod_name(RBASIC_CLASS(obj));
if (!NIL_P(class_path)) {
APPEND_F("src:%s", RSTRING_PTR(class_path));
}
@@ -4341,21 +5066,18 @@ 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:%zu", hash_len);
- }
- else {
- uint32_t len = ROBJECT_IV_CAPACITY(obj);
-
- if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- APPEND_F("(embed) len:%d", len);
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ if (rb_obj_shape_complex_p(obj)) {
+ size_t hash_len = rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
+ APPEND_F("(complex) len:%zu", hash_len);
}
else {
- VALUE *ptr = ROBJECT_IVPTR(obj);
- APPEND_F("len:%d ptr:%p", len, (void *)ptr);
+ APPEND_F("(embed) len:%d capa:%d", RSHAPE_LEN(RBASIC_SHAPE_ID(obj)), ROBJECT_FIELDS_CAPACITY(obj));
}
}
+ else {
+ APPEND_F("len:%d capa:%d ptr:%p", RSHAPE_LEN(RBASIC_SHAPE_ID(obj)), ROBJECT_FIELDS_CAPACITY(obj), (void *)ROBJECT_FIELDS(obj));
+ }
}
break;
case T_DATA: {
@@ -4373,12 +5095,6 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
APPEND_F("r:%d", r->pub.id);
}
}
- else {
- const char * const type_name = rb_objspace_data_type_name(obj);
- if (type_name) {
- APPEND_F("%s", type_name);
- }
- }
break;
}
case T_IMEMO: {
@@ -4433,11 +5149,11 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
case imemo_callcache:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
- VALUE class_path = cc->klass ? rb_class_path_cached(cc->klass) : Qnil;
+ VALUE class_path = vm_cc_valid(cc) ? rb_mod_name(cc->klass) : Qnil;
const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
APPEND_F("(klass:%s cme:%s%s (%p) call:%p",
- NIL_P(class_path) ? (cc->klass ? "??" : "<NULL>") : RSTRING_PTR(class_path),
+ NIL_P(class_path) ? (vm_cc_valid(cc) ? "??" : "<NULL>") : RSTRING_PTR(class_path),
cme ? rb_id2name(cme->called_id) : "<NULL>",
cme ? (METHOD_ENTRY_INVALIDATED(cme) ? " [inv]" : "") : "",
(void *)cme,
@@ -4459,6 +5175,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
#undef C
+#ifdef RUBY_ASAN_ENABLED
void
rb_asan_poison_object(VALUE obj)
{
@@ -4479,22 +5196,37 @@ rb_asan_poisoned_object_p(VALUE obj)
MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj;
return __asan_region_is_poisoned(ptr, rb_gc_obj_slot_size(obj));
}
+#endif
-#define asan_unpoisoning_object(obj) \
- for (void *poisoned = asan_unpoison_object_temporary(obj), \
- *unpoisoning = &poisoned; /* flag to loop just once */ \
- unpoisoning; \
- unpoisoning = asan_poison_object_restore(obj, poisoned))
+static void
+raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
+{
+ size_t pos = rb_raw_obj_info_common(buff, buff_size, obj);
+ pos = rb_raw_obj_info_buitin_type(buff, buff_size, obj, pos);
+ if (pos >= buff_size) {} // truncated
+}
const char *
rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
{
- asan_unpoisoning_object(obj) {
- size_t pos = rb_raw_obj_info_common(buff, buff_size, obj);
- pos = rb_raw_obj_info_buitin_type(buff, buff_size, obj, pos);
- if (pos >= buff_size) {} // truncated
- }
+ void *objspace = rb_gc_get_objspace();
+ if (SPECIAL_CONST_P(obj)) {
+ raw_obj_info(buff, buff_size, obj);
+ }
+ else if (!rb_gc_impl_pointer_to_heap_p(objspace, (const void *)obj)) {
+ snprintf(buff, buff_size, "out-of-heap:%p", (void *)obj);
+ }
+#if 0 // maybe no need to check it?
+ else if (0 && rb_gc_impl_garbage_object_p(objspace, obj)) {
+ snprintf(buff, buff_size, "garbage:%p", (void *)obj);
+ }
+#endif
+ else {
+ asan_unpoisoning_object(obj) {
+ raw_obj_info(buff, buff_size, obj);
+ }
+ }
return buff;
}
@@ -4502,12 +5234,6 @@ rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
#undef APPEND_F
#undef BUFF_ARGS
-#if RGENGC_OBJ_INFO
-#define OBJ_INFO_BUFFERS_NUM 10
-#define OBJ_INFO_BUFFERS_SIZE 0x100
-static rb_atomic_t obj_info_buffers_index = 0;
-static char obj_info_buffers[OBJ_INFO_BUFFERS_NUM][OBJ_INFO_BUFFERS_SIZE];
-
/* Increments *var atomically and resets *var to 0 when maxval is
* reached. Returns the wraparound old *var value (0...maxval). */
static rb_atomic_t
@@ -4525,17 +5251,18 @@ atomic_inc_wraparound(rb_atomic_t *var, const rb_atomic_t maxval)
static const char *
obj_info(VALUE obj)
{
- rb_atomic_t index = atomic_inc_wraparound(&obj_info_buffers_index, OBJ_INFO_BUFFERS_NUM);
- char *const buff = obj_info_buffers[index];
- return rb_raw_obj_info(buff, OBJ_INFO_BUFFERS_SIZE, obj);
-}
-#else
-static const char *
-obj_info(VALUE obj)
-{
+ if (RGENGC_OBJ_INFO) {
+ static struct {
+ rb_atomic_t index;
+ char buffers[10][0x100];
+ } info = {0};
+
+ rb_atomic_t index = atomic_inc_wraparound(&info.index, numberof(info.buffers));
+ char *const buff = info.buffers[index];
+ return rb_raw_obj_info(buff, sizeof(info.buffers[0]), obj);
+ }
return obj_type_name(obj);
}
-#endif
/*
------------------------ Extended allocator ------------------------
@@ -4564,11 +5291,7 @@ gc_raise(VALUE exc, const char *fmt, ...)
exc, fmt, &ap,
};
- if (ruby_thread_has_gvl_p()) {
- gc_vraise(&argv);
- UNREACHABLE;
- }
- else if (ruby_native_thread_p()) {
+ if (ruby_native_thread_p()) {
rb_thread_call_with_gvl(gc_vraise, &argv);
UNREACHABLE;
}
@@ -4654,11 +5377,6 @@ rb_memerror_reentered(void)
return (ec && rb_ec_raised_p(ec, RAISED_NOMEMORY));
}
-void
-rb_malloc_info_show_results(void)
-{
-}
-
static void *
handle_malloc_failure(void *ptr)
{
@@ -4679,6 +5397,14 @@ ruby_xmalloc(size_t size)
return handle_malloc_failure(ruby_xmalloc_body(size));
}
+static bool
+malloc_gc_allowed(void)
+{
+ rb_ractor_t *r = rb_current_ractor_raw(false);
+
+ return r == NULL || !r->malloc_gc_disabled;
+}
+
static void *
ruby_xmalloc_body(size_t size)
{
@@ -4686,7 +5412,7 @@ ruby_xmalloc_body(size_t size)
negative_size_allocation_error("too large allocation size");
}
- return rb_gc_impl_malloc(rb_gc_get_objspace(), size);
+ return rb_gc_impl_malloc(rb_gc_get_objspace(), size, malloc_gc_allowed());
}
void
@@ -4716,7 +5442,7 @@ ruby_xmalloc2(size_t n, size_t size)
static void *
ruby_xmalloc2_body(size_t n, size_t size)
{
- return rb_gc_impl_malloc(rb_gc_get_objspace(), xmalloc2_size(n, size));
+ return rb_gc_impl_malloc(rb_gc_get_objspace(), xmalloc2_size(n, size), malloc_gc_allowed());
}
static void *ruby_xcalloc_body(size_t n, size_t size);
@@ -4730,65 +5456,65 @@ ruby_xcalloc(size_t n, size_t size)
static void *
ruby_xcalloc_body(size_t n, size_t size)
{
- return rb_gc_impl_calloc(rb_gc_get_objspace(), xmalloc2_size(n, size));
+ return rb_gc_impl_calloc(rb_gc_get_objspace(), xmalloc2_size(n, size), malloc_gc_allowed());
}
-static void *ruby_sized_xrealloc_body(void *ptr, size_t new_size, size_t old_size);
+static void *ruby_xrealloc_sized_body(void *ptr, size_t new_size, size_t old_size);
-#ifdef ruby_sized_xrealloc
-#undef ruby_sized_xrealloc
+#ifdef ruby_xrealloc_sized
+#undef ruby_xrealloc_sized
#endif
void *
-ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size)
+ruby_xrealloc_sized(void *ptr, size_t new_size, size_t old_size)
{
- return handle_malloc_failure(ruby_sized_xrealloc_body(ptr, new_size, old_size));
+ return handle_malloc_failure(ruby_xrealloc_sized_body(ptr, new_size, old_size));
}
static void *
-ruby_sized_xrealloc_body(void *ptr, size_t new_size, size_t old_size)
+ruby_xrealloc_sized_body(void *ptr, size_t new_size, size_t old_size)
{
if ((ssize_t)new_size < 0) {
negative_size_allocation_error("too large allocation size");
}
- return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, new_size, old_size);
+ return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, new_size, old_size, malloc_gc_allowed());
}
void *
ruby_xrealloc(void *ptr, size_t new_size)
{
- return ruby_sized_xrealloc(ptr, new_size, 0);
+ return ruby_xrealloc_sized(ptr, new_size, 0);
}
-static void *ruby_sized_xrealloc2_body(void *ptr, size_t n, size_t size, size_t old_n);
+static void *ruby_xrealloc2_sized_body(void *ptr, size_t n, size_t size, size_t old_n);
-#ifdef ruby_sized_xrealloc2
-#undef ruby_sized_xrealloc2
+#ifdef ruby_xrealloc2_sized
+#undef ruby_xrealloc2_sized
#endif
void *
-ruby_sized_xrealloc2(void *ptr, size_t n, size_t size, size_t old_n)
+ruby_xrealloc2_sized(void *ptr, size_t n, size_t size, size_t old_n)
{
- return handle_malloc_failure(ruby_sized_xrealloc2_body(ptr, n, size, old_n));
+ return handle_malloc_failure(ruby_xrealloc2_sized_body(ptr, n, size, old_n));
}
static void *
-ruby_sized_xrealloc2_body(void *ptr, size_t n, size_t size, size_t old_n)
+ruby_xrealloc2_sized_body(void *ptr, size_t n, size_t size, size_t old_n)
{
size_t len = xmalloc2_size(n, size);
- return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, len, old_n * size);
+ return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, len, old_n * size, malloc_gc_allowed());
}
void *
ruby_xrealloc2(void *ptr, size_t n, size_t size)
{
- return ruby_sized_xrealloc2(ptr, n, size, 0);
+ return ruby_xrealloc2_sized(ptr, n, size, 0);
}
-#ifdef ruby_sized_xfree
-#undef ruby_sized_xfree
+#ifdef ruby_xfree_sized
+#undef ruby_xfree_sized
#endif
void
-ruby_sized_xfree(void *x, size_t size)
+ruby_xfree_sized(void *x, size_t size)
{
if (LIKELY(x)) {
/* It's possible for a C extension's pthread destructor function set by pthread_key_create
@@ -4806,7 +5532,7 @@ ruby_sized_xfree(void *x, size_t size)
void
ruby_xfree(void *x)
{
- ruby_sized_xfree(x, 0);
+ ruby_xfree_sized(x, 0);
}
void *
@@ -4875,11 +5601,11 @@ ruby_mimcalloc(size_t num, size_t size)
{
void *mem;
#if CALC_EXACT_MALLOC_SIZE
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(num, size);
- if (UNLIKELY(t.left)) {
+ struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(num, size);
+ if (UNLIKELY(t.overflowed)) {
return NULL;
}
- size = t.right + sizeof(struct malloc_obj_info);
+ size = t.result + sizeof(struct malloc_obj_info);
mem = calloc1(size);
if (!mem) {
return NULL;
@@ -4947,6 +5673,80 @@ rb_gc_after_fork(rb_pid_t pid)
rb_gc_impl_after_fork(rb_gc_get_objspace(), pid);
}
+bool
+rb_gc_obj_shareable_p(VALUE obj)
+{
+ return RB_OBJ_SHAREABLE_P(obj);
+}
+
+void
+rb_gc_rp(VALUE obj)
+{
+ rp(obj);
+}
+
+struct check_shareable_data {
+ VALUE parent;
+ long err_count;
+};
+
+static void
+check_shareable_i(const VALUE child, void *ptr)
+{
+ struct check_shareable_data *data = (struct check_shareable_data *)ptr;
+
+ if (!rb_gc_obj_shareable_p(child)) {
+ fprintf(stderr, "(a) ");
+ rb_gc_rp(data->parent);
+ fprintf(stderr, "(b) ");
+ rb_gc_rp(child);
+ fprintf(stderr, "check_shareable_i: shareable (a) -> unshareable (b)\n");
+
+ data->err_count++;
+ rb_bug("!! violate shareable constraint !!");
+ }
+}
+
+static bool gc_checking_shareable = false;
+
+static void
+gc_verify_shareable(void *objspace, VALUE obj, void *data)
+{
+ // while gc_checking_shareable is true,
+ // other Ractors should not run the GC, until the flag is not local.
+ // TODO: remove VM locking if the flag is Ractor local
+
+ unsigned int lev = RB_GC_VM_LOCK();
+ {
+ gc_checking_shareable = true;
+ rb_objspace_reachable_objects_from(obj, check_shareable_i, (void *)data);
+ gc_checking_shareable = false;
+ }
+ RB_GC_VM_UNLOCK(lev);
+}
+
+// TODO: only one level (non-recursive)
+void
+rb_gc_verify_shareable(VALUE obj)
+{
+ rb_objspace_t *objspace = rb_gc_get_objspace();
+ struct check_shareable_data data = {
+ .parent = obj,
+ .err_count = 0,
+ };
+ gc_verify_shareable(objspace, obj, &data);
+
+ if (data.err_count > 0) {
+ rb_bug("rb_gc_verify_shareable");
+ }
+}
+
+bool
+rb_gc_checking_shareable(void)
+{
+ return gc_checking_shareable;
+}
+
/*
* Document-module: ObjectSpace
*
@@ -4998,6 +5798,8 @@ void
Init_GC(void)
{
#undef rb_intern
+ rb_gc_register_address(&id2ref_value);
+
malloc_offset = gc_compute_malloc_offset();
rb_mGC = rb_define_module("GC");
diff --git a/gc.rb b/gc.rb
index d3bb8db036..48bed27880 100644
--- a/gc.rb
+++ b/gc.rb
@@ -7,31 +7,39 @@
# You may obtain information about the operation of the \GC through 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 run, meaning all objects are marked. When set to
- # +false+, a minor garbage collection cycle is run, 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 are 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 +immediate_sweep+ keyword argument determines whether or not to defer
- # sweeping (using lazy sweep). When set to +false+, sweeping is performed in
- # steps that are interleaved with future Ruby code execution, so sweeping might
- # not be completed during this method call. When set to +true+, 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.
+ # Initiates garbage collection, even if explicitly disabled by GC.disable.
+ #
+ # Keyword arguments:
+ #
+ # - +full_mark+:
+ # its boolean value determines whether to perform a major garbage collection cycle:
+ #
+ # - +true+: initiates a major garbage collection cycle,
+ # meaning all objects (old and new) are marked.
+ # - +false+: initiates a minor garbage collection cycle,
+ # meaning only young objects are marked.
+ #
+ # - +immediate_mark+:
+ # its boolean value determines whether to perform incremental marking:
+ #
+ # - +true+: marking is completed before the method returns.
+ # - +false+: marking is performed by parts,
+ # interleaved with program execution both before the method returns and afterward;
+ # therefore marking may not be completed before the return.
+ # Note that if +full_mark+ is +false+, marking will always be immediate,
+ # regardless of the value of +immediate_mark+.
+ #
+ # - +immediate_sweep+:
+ # its boolean value determines whether to defer sweeping (using lazy sweep):
+ #
+ # - +true+: sweeping is completed before the method returns.
+ # - +false+: sweeping is performed by parts,
+ # interleaved with program execution both before the method returns and afterward;
+ # therefore sweeping may not be completed before the return.
+ #
+ # Note that these keyword arguments are implementation- and version-dependent,
+ # are not guaranteed to be future-compatible,
+ # and may be ignored in some implementations.
def self.start full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
@@ -42,14 +50,14 @@ module GC
end
# call-seq:
- # GC.enable -> true or false
+ # GC.enable -> true or false
#
- # Enables garbage collection, returning +true+ if garbage
- # collection was previously disabled.
+ # Enables garbage collection;
+ # returns whether garbage collection was disabled:
#
- # GC.disable #=> false
- # GC.enable #=> true
- # GC.enable #=> false
+ # GC.disable
+ # GC.enable # => true
+ # GC.enable # => false
#
def self.enable
Primitive.gc_enable
@@ -58,189 +66,332 @@ module GC
# call-seq:
# GC.disable -> true or false
#
- # Disables garbage collection, returning +true+ if garbage
- # collection was already disabled.
+ # Disables garbage collection (but GC.start remains potent):
+ # returns whether garbage collection was already disabled.
+ #
+ # GC.enable
+ # GC.disable # => false
+ # GC.disable # => true
#
- # GC.disable #=> false
- # GC.disable #=> true
def self.disable
Primitive.gc_disable
end
# call-seq:
- # GC.stress -> integer, true, or false
+ # GC.stress -> setting
#
- # Returns the current status of \GC stress mode.
+ # Returns the current \GC stress-mode setting,
+ # which initially is +false+.
+ #
+ # The stress mode may be set by method GC.stress=.
def self.stress
Primitive.gc_stress_get
end
# call-seq:
- # GC.stress = flag -> flag
+ # GC.stress = value -> value
+ #
+ # Enables or disables stress mode;
+ # enabling stress mode will degrade performance; it is only for debugging.
+ #
+ # Sets the current \GC stress mode to the given value:
#
- # Updates the \GC stress mode.
+ # - If the value is +nil+ or +false+, disables stress mode.
+ # - If the value is an integer,
+ # enables stress mode with certain flags; see below.
+ # - Otherwise, enables stress mode;
+ # \GC is invoked at every \GC opportunity: all memory and object allocations.
#
- # When stress mode is enabled, the \GC is invoked at every \GC opportunity:
- # all memory and object allocations.
+ # The flags are bits in the given integer:
#
- # Enabling stress mode will degrade performance; it is only for debugging.
+ # - +0x01+: No major \GC.
+ # - +0x02+: No immediate sweep.
+ # - +0x04+: Full mark after malloc/calloc/realloc.
#
- # The flag can be true, false, or an integer bitwise-ORed with the following flags:
- # 0x01:: no major GC
- # 0x02:: no immediate sweep
- # 0x04:: full mark after malloc/calloc/realloc
def self.stress=(flag)
Primitive.gc_stress_set_m flag
end
# call-seq:
- # GC.count -> Integer
+ # self.count -> integer
+ #
+ # Returns the total number of times garbage collection has occurred:
+ #
+ # GC.count # => 385
+ # GC.start
+ # GC.count # => 386
#
- # Returns the number of times \GC has occurred since the process started.
def self.count
Primitive.gc_count
end
# call-seq:
- # GC.stat -> Hash
- # GC.stat(hash) -> Hash
- # GC.stat(:key) -> Numeric
- #
- # Returns a Hash containing information about the \GC.
- #
- # The contents of the hash are implementation-specific and may change in
- # the future without notice.
- #
- # The hash includes internal statistics about \GC such as:
- #
- # [count]
+ # GC.stat -> new_hash
+ # GC.stat(key) -> value
+ # GC.stat(hash) -> hash
+ #
+ # This method is implementation-specific to CRuby.
+ #
+ # Returns \GC statistics.
+ # The particular statistics are implementation-specific
+ # and may change in the future without notice.
+ #
+ # With no argument given,
+ # returns information about the most recent garbage collection:
+ #
+ # GC.stat
+ # # =>
+ # {count: 28,
+ # time: 1,
+ # marking_time: 1,
+ # sweeping_time: 0,
+ # heap_allocated_pages: 521,
+ # heap_empty_pages: 0,
+ # heap_allocatable_bytes: 0,
+ # heap_available_slots: 539590,
+ # heap_live_slots: 422243,
+ # heap_free_slots: 117347,
+ # heap_final_slots: 0,
+ # heap_marked_slots: 264877,
+ # heap_eden_pages: 521,
+ # total_allocated_pages: 521,
+ # total_freed_pages: 0,
+ # total_allocated_objects: 2246376,
+ # total_freed_objects: 1824133,
+ # malloc_increase_bytes: 50982,
+ # malloc_increase_bytes_limit: 18535172,
+ # minor_gc_count: 18,
+ # major_gc_count: 10,
+ # compact_count: 0,
+ # read_barrier_faults: 0,
+ # total_moved_objects: 0,
+ # remembered_wb_unprotected_objects: 0,
+ # remembered_wb_unprotected_objects_limit: 2162,
+ # old_objects: 216365,
+ # old_objects_limit: 432540,
+ # oldmalloc_increase_bytes: 1654232,
+ # oldmalloc_increase_bytes_limit: 16846103}
+ #
+ # With symbol argument +key+ given,
+ # returns the value for that key:
+ #
+ # GC.stat(:count) # => 30
+ #
+ # With hash argument +hash+ given,
+ # returns that hash with GC statistics merged into its content;
+ # this form may be useful in minimizing {probe effects}[https://en.wikipedia.org/wiki/Probe_effect]:
+ #
+ # h = {foo: 0, bar: 1}
+ # GC.stat(h)
+ # h.keys.take(5) # => [:foo, :bar, :count, :time, :marking_time]
+ #
+ # The hash includes entries such as:
+ #
+ # - +:count+:
# The total number of garbage collections run since application start
- # (count includes both minor and major garbage collections)
- # [time]
- # The total time spent in garbage collections (in milliseconds)
- # [heap_allocated_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+
- # [heap_live_slots]
- # The total number of slots which contain live objects
- # [heap_free_slots]
- # The total number of slots which do not contain live objects
- # [heap_final_slots]
- # The total number of slots with pending finalizers to be run
- # [heap_marked_slots]
- # The total number of objects marked in the last \GC
- # [heap_eden_pages]
- # The total number of pages which contain at least one live slot
- # [heap_tomb_pages]
- # The total number of pages which do not contain any live slots
- # [total_allocated_pages]
- # The cumulative number of pages allocated since application start
- # [total_freed_pages]
- # The cumulative number of pages freed since application start
- # [total_allocated_objects]
- # The cumulative number of objects allocated since application start
- # [total_freed_objects]
- # The cumulative number of objects freed since application start
- # [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
- # [minor_gc_count]
- # The total number of minor garbage collections run since process start
- # [major_gc_count]
- # The total number of major garbage collections run since process start
- # [compact_count]
- # The total number of compactions run since process start
- # [read_barrier_faults]
- # The total number of times the read barrier was triggered during
- # compaction
- # [total_moved_objects]
- # The total number of objects compaction has moved
- # [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,
- # 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
- # [oldmalloc_increase_bytes]
- # Amount of memory allocated on the heap for objects. Decreased by major \GC
- # [oldmalloc_increase_bytes_limit]
- # When +:oldmalloc_increase_bytes+ crosses this limit, major \GC is triggered
- #
- # If the optional argument, hash, is given,
- # it is overwritten and returned.
- # This is intended to avoid the probe effect.
- #
- # This method is only expected to work on CRuby.
+ # (count includes both minor and major garbage collections).
+ # - +:time+:
+ # The total time spent in garbage collections (in milliseconds).
+ # - +:heap_allocated_pages+:
+ # The total number of allocated pages.
+ # - +:heap_empty_pages+:
+ # The number of pages with no live objects, and that could be released to the system.
+ # - +: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+.
+ # - +:heap_live_slots+:
+ # The total number of slots which contain live objects.
+ # - +:heap_free_slots+:
+ # The total number of slots which do not contain live objects.
+ # - +:heap_final_slots+:
+ # The total number of slots with pending finalizers to be run.
+ # - +:heap_marked_slots+:
+ # The total number of objects marked in the last \GC.
+ # - +:heap_eden_pages+:
+ # The total number of pages which contain at least one live slot.
+ # - +:total_allocated_pages+:
+ # The cumulative number of pages allocated since application start.
+ # - +:total_freed_pages+:
+ # The cumulative number of pages freed since application start.
+ # - +:total_allocated_objects+:
+ # The cumulative number of objects allocated since application start.
+ # - +:total_freed_objects+:
+ # The cumulative number of objects freed since application start.
+ # - +: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.
+ # - +:minor_gc_count+:
+ # The total number of minor garbage collections run since process start.
+ # - +:major_gc_count+:
+ # The total number of major garbage collections run since process start.
+ # - +:compact_count+:
+ # The total number of compactions run since process start.
+ # - +:read_barrier_faults+:
+ # The total number of times the read barrier was triggered during compaction.
+ # - +:total_moved_objects+:
+ # The total number of objects compaction has moved.
+ # - +: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, 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.
+ # - +:oldmalloc_increase_bytes+:
+ # Amount of memory allocated on the heap for objects. Decreased by major \GC.
+ # - +:oldmalloc_increase_bytes_limit+:
+ # When +:oldmalloc_increase_bytes+ crosses this limit, major \GC is triggered.
+ #
def self.stat hash_or_key = nil
Primitive.gc_stat hash_or_key
end
# call-seq:
- # GC.stat_heap -> Hash
- # GC.stat_heap(nil, hash) -> Hash
- # GC.stat_heap(heap_name) -> Hash
- # GC.stat_heap(heap_name, hash) -> Hash
- # GC.stat_heap(heap_name, :key) -> Numeric
- #
- # Returns information for heaps 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.
- #
- # If the second optional argument, +hash_or_key+, is given as a +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+ value for the particular heap.
- #
- # On CRuby, +heap_name+ is of the type +Integer+ but may be of type +String+
- # on other implementations.
- #
- # The contents of the hash are implementation-specific and may change in
- # the future without notice.
- #
- # 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]
+ # GC.stat_heap -> new_hash
+ # GC.stat_heap(heap_id) -> new_hash
+ # GC.stat_heap(heap_id, key) -> value
+ # GC.stat_heap(nil, hash) -> hash
+ # GC.stat_heap(heap_id, hash) -> hash
+ #
+ # This method is implementation-specific to CRuby.
+ #
+ # Returns statistics for \GC heaps.
+ # The particular statistics are implementation-specific
+ # and may change in the future without notice.
+ #
+ # With no argument given, returns statistics for all heaps:
+ #
+ # GC.stat_heap
+ # # =>
+ # {0 =>
+ # {slot_size: 32,
+ # heap_eden_pages: 24,
+ # heap_eden_slots: 12288,
+ # total_allocated_pages: 24,
+ # force_major_gc_count: 0,
+ # force_incremental_marking_finish_count: 0,
+ # total_allocated_objects: 8450,
+ # total_freed_objects: 3120},
+ # 1 =>
+ # {slot_size: 64,
+ # heap_eden_pages: 246,
+ # heap_eden_slots: 402802,
+ # total_allocated_pages: 246,
+ # force_major_gc_count: 2,
+ # force_incremental_marking_finish_count: 1,
+ # total_allocated_objects: 33867152,
+ # total_freed_objects: 33520523},
+ # 2 =>
+ # {slot_size: 128,
+ # heap_eden_pages: 84,
+ # heap_eden_slots: 68746,
+ # total_allocated_pages: 84,
+ # force_major_gc_count: 1,
+ # force_incremental_marking_finish_count: 4,
+ # total_allocated_objects: 147491,
+ # total_freed_objects: 90699},
+ # 3 =>
+ # {slot_size: 256,
+ # heap_eden_pages: 157,
+ # heap_eden_slots: 64182,
+ # total_allocated_pages: 157,
+ # force_major_gc_count: 0,
+ # force_incremental_marking_finish_count: 0,
+ # total_allocated_objects: 211460,
+ # total_freed_objects: 190075},
+ # 4 =>
+ # {slot_size: 512,
+ # heap_eden_pages: 8,
+ # heap_eden_slots: 1631,
+ # total_allocated_pages: 8,
+ # force_major_gc_count: 0,
+ # force_incremental_marking_finish_count: 0,
+ # total_allocated_objects: 1422,
+ # total_freed_objects: 700},
+ # 5 =>
+ # {slot_size: 1024,
+ # heap_eden_pages: 16,
+ # heap_eden_slots: 1628,
+ # total_allocated_pages: 16,
+ # force_major_gc_count: 0,
+ # force_incremental_marking_finish_count: 0,
+ # total_allocated_objects: 1230,
+ # total_freed_objects: 309}}
+ #
+ # In the example above, the keys in the outer hash are the heap identifiers:
+ #
+ # GC.stat_heap.keys # => [0, 1, 2, 3, 4, 5]
+ #
+ # On CRuby, each heap identifier is an integer;
+ # on other implementations, a heap identifier may be a string.
+ #
+ # With only argument +heap_id+ given,
+ # returns statistics for the given heap identifier:
+ #
+ # GC.stat_heap(3)
+ # # =>
+ # {slot_size: 256,
+ # heap_eden_pages: 157,
+ # heap_eden_slots: 64182,
+ # total_allocated_pages: 157,
+ # force_major_gc_count: 0,
+ # force_incremental_marking_finish_count: 0,
+ # total_allocated_objects: 225018,
+ # total_freed_objects: 206647}
+ #
+ # With arguments +heap_id+ and +key+ given,
+ # returns the value for the given key in the given heap:
+ #
+ # GC.stat_heap(3, :slot_size) # => 256
+ #
+ # With arguments +nil+ and +hash+ given,
+ # merges the statistics for all heaps into the given hash:
+ #
+ # h = {foo: 0, bar: 1}
+ # GC.stat_heap(nil, h).keys # => [:foo, :bar, 0, 1, 2, 3, 4]
+ #
+ # With arguments +heap_id+ and +hash+ given,
+ # merges the statistics for the given heap into the given hash:
+ #
+ # h = {foo: 0, bar: 1}
+ # GC.stat_heap(2, h).keys
+ # # =>
+ # [:foo,
+ # :bar,
+ # :slot_size,
+ # :heap_eden_pages,
+ # :heap_eden_slots,
+ # :total_allocated_pages,
+ # :force_major_gc_count,
+ # :force_incremental_marking_finish_count,
+ # :total_allocated_objects,
+ # :total_freed_objects]
+ #
+ # The statistics for a heap may include:
+ #
+ # - +:slot_size+:
# The slot size of the heap in bytes.
- # [heap_allocatable_pages]
+ # - +:heap_allocatable_pages+:
# The number of pages that can be allocated without triggering a new
# garbage collection cycle.
- # [heap_eden_pages]
+ # - +:heap_eden_pages+:
# The number of pages in the eden heap.
- # [heap_eden_slots]
+ # - +: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]
+ # - +:total_allocated_pages+:
# The total number of pages that have been allocated in the heap.
- # [total_freed_pages]
+ # - +: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]
+ # - +:force_major_gc_count+:
# The number of times this heap has forced major garbage collection cycles
# to start due to running out of free slots.
- # [force_incremental_marking_finish_count]
+ # - +:force_incremental_marking_finish_count+:
# The number of times this heap has forced incremental marking to complete
# due to running out of pooled slots.
#
@@ -250,99 +401,111 @@ module GC
# call-seq:
# GC.config -> hash
- # GC.config(hash) -> hash
- #
- # Sets or gets information about the current \GC config.
+ # GC.config(hash_to_merge) -> hash
#
- # Configuration parameters are \GC implementation-specific and may change
- # without notice.
+ # This method is implementation-specific to CRuby.
#
- # This method can be called without parameters to retrieve the current config
- # as a +Hash+ with +Symbol+ keys.
+ # Sets or gets information about the current \GC configuration.
#
- # This method can also be called with a +Hash+ argument to assign values to
- # valid config keys. Config keys missing from the passed +Hash+ will be left
- # unmodified.
+ # Configuration parameters are \GC implementation-specific and may change without notice.
#
- # If a key/value pair is passed to this function that does not correspond to
- # a valid config key for the \GC implementation being used, no config will be
- # updated, the key will be present in the returned Hash, and its value will
- # be +nil+. This is to facilitate easy migration between \GC implementations.
+ # With no argument given, returns a hash containing the configuration:
#
- # In both call-seqs, the return value of <code>GC.config</code> will be a +Hash+
- # containing the most recent full configuration, i.e., all keys and values
- # defined by the specific \GC implementation being used. In the case of a
- # config update, the return value will include the new values being updated.
+ # GC.config
+ # # => {rgengc_allow_full_mark: true, implementation: "default"}
#
- # This method is only expected to work on CRuby.
+ # With argument +hash_to_merge+ given,
+ # merges that hash into the stored configuration hash;
+ # ignores unknown hash keys;
+ # returns the configuration hash:
#
- # === \GC Implementation independent values
+ # GC.config(rgengc_allow_full_mark: false)
+ # # => {rgengc_allow_full_mark: false, implementation: "default"}
+ # GC.config(foo: 'bar')
+ # # => {rgengc_allow_full_mark: false, implementation: "default"}
#
- # The <code>GC.config</code> hash can also contain keys that are global and
- # read-only. These keys are not specific to any one \GC library implementation
- # and attempting to write to them will raise +ArgumentError+.
+ # <b>All-Implementations Configuration</b>
#
- # There is currently only one global, read-only key:
+ # The single read-only entry for all implementations is:
#
- # [implementation]
- # Returns a +String+ containing the name of the currently loaded \GC library,
- # if one has been loaded using +RUBY_GC_LIBRARY+, and "default" in all other
- # cases
+ # - +:implementation+:
+ # the string name of the implementation;
+ # for the Ruby default implementation, <tt>'default'</tt>.
#
- # === \GC Implementation specific values
+ # <b>Implementation-Specific Configuration</b>
#
- # \GC libraries are expected to document their own configuration. Valid keys
- # for Ruby's default \GC implementation are:
+ # A \GC implementation maintains its own implementation-specific configuration.
#
- # [rgengc_allow_full_mark]
- # Controls whether the \GC is allowed to run a full mark (young & old objects).
+ # For Ruby's default implementation the single entry is:
#
- # When +true+, \GC interleaves major and minor collections. This is the default. \GC
- # will function as intended.
+ # - +:rgengc_allow_full_mark+:
+ # Controls whether the \GC is allowed to run a full mark (young & old objects):
#
- # When +false+, the \GC will never trigger a full marking cycle unless
- # explicitly requested by user code. Instead, only a minor mark will run—
- # only young objects will be marked. When the heap space is exhausted, new
- # pages will be allocated immediately instead of running a full mark.
+ # - +true+ (default): \GC interleaves major and minor collections.
+ # A flag is set to notify GC that a full mark has been requested.
+ # This flag is accessible via GC.latest_gc_info(:need_major_by).
+ # - +false+: \GC does not initiate a full marking cycle unless explicitly directed by user code;
+ # see GC.start.
+ # Setting this parameter to +false+ disables young-to-old promotion.
+ # For performance reasons, we recommended warming up the application using Process.warmup
+ # before setting this parameter to +false+.
#
- # A flag will be set to notify that a full mark has been
- # requested. This flag is accessible using
- # <code>GC.latest_gc_info(:need_major_by)</code>
- #
- # The user can trigger a major collection at any time using
- # <code>GC.start(full_mark: true)</code>
- #
- # When +false+, Young to Old object promotion is disabled. For performance
- # reasons, it is recommended to warm up an application using +Process.warmup+
- # before setting this parameter to +false+.
def self.config hash = nil
- return Primitive.gc_config_get unless hash
-
- if(Primitive.cexpr!("RBOOL(RB_TYPE_P(hash, T_HASH))"))
+ if Primitive.cexpr!("RBOOL(RB_TYPE_P(hash, T_HASH))")
if hash.include?(:implementation)
raise ArgumentError, 'Attempting to set read-only key "Implementation"'
end
Primitive.gc_config_set hash
- else
+ elsif hash != nil
raise ArgumentError
end
+
+ Primitive.gc_config_get
end
# call-seq:
- # GC.latest_gc_info -> hash
- # GC.latest_gc_info(hash) -> hash
- # GC.latest_gc_info(key) -> value
- #
- # Returns information about the most recent garbage collection.
- #
- # If the argument +hash+ is given and is a Hash object,
- # it is overwritten and returned.
- # This is intended to avoid the probe effect.
+ # GC.latest_gc_info -> new_hash
+ # GC.latest_gc_info(key) -> value
+ # GC.latest_gc_info(hash) -> hash
+ #
+ # With no argument given,
+ # returns information about the most recent garbage collection:
+ #
+ # GC.latest_gc_info
+ # # =>
+ # {major_by: :force,
+ # need_major_by: nil,
+ # gc_by: :method,
+ # have_finalizer: false,
+ # immediate_sweep: true,
+ # state: :none,
+ # weak_references_count: 0,
+ # retained_weak_references_count: 0}
+ #
+ # With symbol argument +key+ given,
+ # returns the value for that key:
+ #
+ # GC.latest_gc_info(:gc_by) # => :newobj
+ #
+ # With hash argument +hash+ given,
+ # returns that hash with GC information merged into its content;
+ # this form may be useful in minimizing {probe effects}[https://en.wikipedia.org/wiki/Probe_effect]:
+ #
+ # h = {foo: 0, bar: 1}
+ # GC.latest_gc_info(h)
+ # # =>
+ # {foo: 0,
+ # bar: 1,
+ # major_by: nil,
+ # need_major_by: nil,
+ # gc_by: :newobj,
+ # have_finalizer: false,
+ # immediate_sweep: false,
+ # state: :sweeping,
+ # weak_references_count: 0,
+ # retained_weak_references_count: 0}
#
- # If the argument +key+ is given and is a Symbol object,
- # it returns the value associated with the key.
- # This is equivalent to <tt>GC.latest_gc_info[key]</tt>.
def self.latest_gc_info hash_or_key = nil
if hash_or_key == nil
hash_or_key = {}
@@ -356,11 +519,29 @@ module GC
end
# call-seq:
- # GC.measure_total_time = true/false
+ # GC.measure_total_time = setting -> setting
#
- # Enables measuring \GC time.
- # You can get the result with <tt>GC.stat(:time)</tt>.
- # Note that \GC time measurement can cause some performance overhead.
+ # Enables or disables \GC total time measurement;
+ # returns +setting+.
+ # See GC.total_time.
+ #
+ # When argument +object+ is +nil+ or +false+, disables total time measurement;
+ # GC.measure_total_time then returns +false+:
+ #
+ # GC.measure_total_time = nil # => nil
+ # GC.measure_total_time # => false
+ # GC.measure_total_time = false # => false
+ # GC.measure_total_time # => false
+ #
+ # Otherwise, enables total time measurement;
+ # GC.measure_total_time then returns +true+:
+ #
+ # GC.measure_total_time = true # => true
+ # GC.measure_total_time # => true
+ # GC.measure_total_time = :foo # => :foo
+ # GC.measure_total_time # => true
+ #
+ # Note that when enabled, total time measurement affects performance.
def self.measure_total_time=(flag)
Primitive.cstmt! %{
rb_gc_impl_set_measure_total_time(rb_gc_get_objspace(), flag);
@@ -369,10 +550,11 @@ module GC
end
# call-seq:
- # GC.measure_total_time -> true/false
+ # GC.measure_total_time -> true or false
#
- # Returns the measure_total_time flag (default: +true+).
- # Note that measurement can affect the application's performance.
+ # Returns the setting for \GC total time measurement;
+ # the initial setting is +true+.
+ # See GC.total_time.
def self.measure_total_time
Primitive.cexpr! %{
RBOOL(rb_gc_impl_get_measure_total_time(rb_gc_get_objspace()))
@@ -380,9 +562,35 @@ module GC
end
# call-seq:
- # GC.total_time -> int
+ # GC.total_time -> integer
+ #
+ # Returns the \GC total time in nanoseconds:
+ #
+ # GC.total_time # => 156250
+ #
+ # Note that total time accumulates
+ # only when total time measurement is enabled
+ # (that is, when GC.measure_total_time is +true+):
+ #
+ # GC.measure_total_time # => true
+ # GC.total_time # => 625000
+ # GC.start
+ # GC.total_time # => 937500
+ # GC.start
+ # GC.total_time # => 1093750
+ #
+ # GC.measure_total_time = false
+ # GC.total_time # => 1250000
+ # GC.start
+ # GC.total_time # => 1250000
+ # GC.start
+ # GC.total_time # => 1250000
+ #
+ # GC.measure_total_time = true
+ # GC.total_time # => 1250000
+ # GC.start
+ # GC.total_time # => 1406250
#
- # Returns the measured \GC total time in nanoseconds.
def self.total_time
Primitive.cexpr! %{
ULL2NUM(rb_gc_impl_get_total_time(rb_gc_get_objspace()))
diff --git a/gc/README.md b/gc/README.md
index 102b24e24e..cb71357973 100644
--- a/gc/README.md
+++ b/gc/README.md
@@ -15,12 +15,17 @@ Two GC implementations are included in Ruby:
> [!IMPORTANT]
> Ruby's modular GC feature is experimental and subject to change. There may be bugs or performance impacts. Use at your own risk.
+### Building Ruby with Modular GC
+
1. Configure Ruby with the `--with-modular-gc=<dir>` option, where `dir` is the directory you want to place the built GC libraries into.
2. Build Ruby as usual.
-3. Build your desired GC implementation with `make install-modular-gc MODULAR_GC=<impl>`. This will build the GC implementation and place the built library into the `dir` specified in step 1. `impl` can be one of:
+
+### Building GC implementations shipped with Ruby
+
+1. Build your desired GC implementation with `make install-modular-gc MODULAR_GC=<impl>`. This will build the GC implementation and place the built library into the `dir` specified in step 1. `impl` can be one of:
- `default`: The default GC that Ruby ships with.
- `mmtk`: The GC that uses [MMTk](https://www.mmtk.io/) as the back-end. See Ruby-specific details in the [ruby/mmtk](https://github.com/ruby/mmtk) repository.
-4. Run your desired GC implementation by setting the `RUBY_GC_LIBRARY=<lib>` environment variable, where `lib` could be `default`, `mmtk`, or your own implementation (as long as you place it in the `dir` specified in step 1).
+2. Run your desired GC implementation by setting the `RUBY_GC_LIBRARY=<lib>` environment variable, where `lib` could be `default`, `mmtk`, or your own implementation (as long as you place it in the `dir` specified in step 1).
## Modular GC API
diff --git a/gc/default/default.c b/gc/default/default.c
index 1bde4ad033..145140dfbf 100644
--- a/gc/default/default.c
+++ b/gc/default/default.c
@@ -15,11 +15,15 @@
# include <sys/user.h>
#endif
-#include "internal/bits.h"
-#include "internal/hash.h"
+#ifdef BUILDING_MODULAR_GC
+# define nlz_int64(x) (x == 0 ? 64 : (unsigned int)__builtin_clzll((unsigned long long)x))
+#else
+# include "internal/bits.h"
+#endif
#include "ruby/ruby.h"
#include "ruby/atomic.h"
+#include "ruby_atomic.h"
#include "ruby/debug.h"
#include "ruby/thread.h"
#include "ruby/util.h"
@@ -34,8 +38,26 @@
# include "probes.h"
#endif
-#include "debug_counter.h"
-#include "internal/sanitizers.h"
+#ifdef BUILDING_MODULAR_GC
+# define RB_DEBUG_COUNTER_INC(_name) ((void)0)
+# define RB_DEBUG_COUNTER_INC_IF(_name, cond) (!!(cond))
+#else
+# include "debug_counter.h"
+#endif
+
+#ifdef BUILDING_MODULAR_GC
+# define rb_asan_poison_object(obj) ((void)(obj))
+# define rb_asan_unpoison_object(obj, newobj_p) ((void)(obj), (void)(newobj_p))
+# define asan_unpoisoning_object(obj) if ((obj) || true)
+# define asan_poison_memory_region(ptr, size) ((void)(ptr), (void)(size))
+# define asan_unpoison_memory_region(ptr, size, malloc_p) ((void)(ptr), (size), (malloc_p))
+# define asan_unpoisoning_memory_region(ptr, size) if ((ptr) || (size) || true)
+
+# define VALGRIND_MAKE_MEM_DEFINED(ptr, size) ((void)(ptr), (void)(size))
+# define VALGRIND_MAKE_MEM_UNDEFINED(ptr, size) ((void)(ptr), (void)(size))
+#else
+# include "internal/sanitizers.h"
+#endif
/* MALLOC_HEADERS_BEGIN */
#ifndef HAVE_MALLOC_USABLE_SIZE
@@ -75,21 +97,12 @@
# include <mach/mach_port.h>
#endif
-#ifndef VM_CHECK_MODE
-# define VM_CHECK_MODE RUBY_DEBUG
-#endif
-
-// From ractor_core.h
-#ifndef RACTOR_CHECK_MODE
-# define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
-#endif
-
#ifndef RUBY_DEBUG_LOG
# define RUBY_DEBUG_LOG(...)
#endif
-#ifndef GC_HEAP_INIT_SLOTS
-#define GC_HEAP_INIT_SLOTS 10000
+#ifndef GC_HEAP_INIT_BYTES
+#define GC_HEAP_INIT_BYTES (2560 * 1024)
#endif
#ifndef GC_HEAP_FREE_SLOTS
#define GC_HEAP_FREE_SLOTS 4096
@@ -97,8 +110,8 @@
#ifndef GC_HEAP_GROWTH_FACTOR
#define GC_HEAP_GROWTH_FACTOR 1.8
#endif
-#ifndef GC_HEAP_GROWTH_MAX_SLOTS
-#define GC_HEAP_GROWTH_MAX_SLOTS 0 /* 0 is disable */
+#ifndef GC_HEAP_GROWTH_MAX_BYTES
+#define GC_HEAP_GROWTH_MAX_BYTES 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
@@ -137,6 +150,17 @@
#define GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
#endif
+#ifndef GC_MALLOC_INCREASE_LOCAL_THRESHOLD
+#define GC_MALLOC_INCREASE_LOCAL_THRESHOLD (8 * 1024 /* 8KB */)
+#endif
+
+#ifdef RB_THREAD_LOCAL_SPECIFIER
+#define USE_MALLOC_INCREASE_LOCAL 1
+static RB_THREAD_LOCAL_SPECIFIER int malloc_increase_local;
+#else
+#define USE_MALLOC_INCREASE_LOCAL 0
+#endif
+
#ifndef GC_CAN_COMPILE_COMPACTION
#if defined(__wasi__) /* WebAssembly doesn't support signals */
# define GC_CAN_COMPILE_COMPACTION 0
@@ -155,12 +179,28 @@
#define USE_TICK_T (PRINT_ENTER_EXIT_TICK || PRINT_ROOT_TICKS)
#ifndef HEAP_COUNT
-# define HEAP_COUNT 5
+# if SIZEOF_VALUE >= 8
+# define HEAP_COUNT 12
+# else
+# define HEAP_COUNT 5
+# endif
+#endif
+
+/* The reciprocal table and pool_slot_sizes array are both generated from this
+ * single definition, so they can never get out of sync. */
+#if SIZEOF_VALUE >= 8
+# define EACH_POOL_SLOT_SIZE(SLOT) \
+ SLOT(32) SLOT(40) SLOT(64) SLOT(80) SLOT(96) SLOT(128) \
+ SLOT(160) SLOT(256) SLOT(512) SLOT(640) SLOT(768) SLOT(1024)
+#else
+# define EACH_POOL_SLOT_SIZE(SLOT) \
+ SLOT(32) SLOT(64) SLOT(128) SLOT(256) SLOT(512)
#endif
typedef struct ractor_newobj_heap_cache {
struct free_slot *freelist;
struct heap_page *using_page;
+ size_t allocated_objects_count;
} rb_ractor_newobj_heap_cache_t;
typedef struct ractor_newobj_cache {
@@ -169,10 +209,10 @@ typedef struct ractor_newobj_cache {
} rb_ractor_newobj_cache_t;
typedef struct {
- size_t heap_init_slots[HEAP_COUNT];
+ size_t heap_init_bytes;
size_t heap_free_slots;
double growth_factor;
- size_t growth_max_slots;
+ size_t growth_max_bytes;
double heap_free_slots_min_ratio;
double heap_free_slots_goal_ratio;
@@ -190,10 +230,10 @@ typedef struct {
} ruby_gc_params_t;
static ruby_gc_params_t gc_params = {
- { GC_HEAP_INIT_SLOTS },
+ GC_HEAP_INIT_BYTES,
GC_HEAP_FREE_SLOTS,
GC_HEAP_GROWTH_FACTOR,
- GC_HEAP_GROWTH_MAX_SLOTS,
+ GC_HEAP_GROWTH_MAX_BYTES,
GC_HEAP_FREE_SLOTS_MIN_RATIO,
GC_HEAP_FREE_SLOTS_GOAL_RATIO,
@@ -268,9 +308,24 @@ int ruby_rgengc_debug;
#ifndef GC_ENABLE_LAZY_SWEEP
# define GC_ENABLE_LAZY_SWEEP 1
#endif
+
+#ifndef VERIFY_FREE_SIZE
+#if RUBY_DEBUG
+#define VERIFY_FREE_SIZE 1
+#else
+#define VERIFY_FREE_SIZE 0
+#endif
+#endif
+
+#if VERIFY_FREE_SIZE
+#undef CALC_EXACT_MALLOC_SIZE
+#define CALC_EXACT_MALLOC_SIZE 1
+#endif
+
#ifndef CALC_EXACT_MALLOC_SIZE
# define CALC_EXACT_MALLOC_SIZE 0
#endif
+
#if defined(HAVE_MALLOC_USABLE_SIZE) || CALC_EXACT_MALLOC_SIZE > 0
# ifndef MALLOC_ALLOCATED_SIZE
# define MALLOC_ALLOCATED_SIZE 0
@@ -283,7 +338,7 @@ int ruby_rgengc_debug;
#endif
#ifndef GC_DEBUG_STRESS_TO_CLASS
-# define GC_DEBUG_STRESS_TO_CLASS 1
+# define GC_DEBUG_STRESS_TO_CLASS RUBY_DEBUG
#endif
typedef enum {
@@ -363,7 +418,6 @@ struct RMoved {
VALUE flags;
VALUE dummy;
VALUE destination;
- uint32_t original_shape_id;
};
#define RMOVED(obj) ((struct RMoved *)(obj))
@@ -424,7 +478,7 @@ typedef struct rb_heap_struct {
uintptr_t compact_cursor_index;
struct heap_page *pooled_pages;
size_t total_pages; /* total page count in a heap */
- size_t total_slots; /* total slot count (about total_pages * HEAP_PAGE_OBJ_LIMIT) */
+ size_t total_slots; /* total slot count */
} rb_heap_t;
@@ -442,10 +496,35 @@ enum gc_mode {
gc_mode_compacting,
};
+typedef rbimpl_atomic_uint64_t gc_counter_t;
+
+#if !defined(HAVE_GCC_ATOMIC_BUILTINS_64) && !defined(_WIN32) && \
+ !(defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx)))
+# define MALLOC_COUNTERS_NEED_LOCK 1
+#endif
+
+struct gc_malloc_bytes {
+ gc_counter_t malloc;
+ gc_counter_t free;
+
+ /* Snapshots of `malloc` / `free` taken at the end of the last GC */
+ gc_counter_t malloc_at_last_gc;
+ gc_counter_t free_at_last_gc;
+};
+
typedef struct rb_objspace {
struct {
+ struct gc_malloc_bytes counters;
+#if RGENGC_ESTIMATE_OLDMALLOC
+ struct gc_malloc_bytes oldcounters;
+#endif
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ rb_nativethread_lock_t lock;
+#endif
+ } malloc_counters;
+
+ struct {
size_t limit;
- size_t increase;
#if MALLOC_ALLOCATED_SIZE
size_t allocated_size;
size_t allocations;
@@ -465,14 +544,12 @@ typedef struct rb_objspace {
unsigned int during_compacting : 1;
unsigned int during_reference_updating : 1;
unsigned int gc_stressful: 1;
- unsigned int has_newobj_hook: 1;
unsigned int during_minor_gc : 1;
unsigned int during_incremental_marking : 1;
unsigned int measure_gc : 1;
} flags;
rb_event_flag_t hook_events;
- unsigned long long next_object_id;
rb_heap_t heaps[HEAP_COUNT];
size_t empty_pages_count;
@@ -493,7 +570,7 @@ typedef struct rb_objspace {
uintptr_t range[2];
size_t freeable_pages;
- size_t allocatable_slots;
+ size_t allocatable_bytes;
/* final */
VALUE deferred_final;
@@ -540,6 +617,7 @@ typedef struct rb_objspace {
double gc_sweep_start_time;
size_t total_allocated_objects_at_gc_start;
size_t heap_used_at_gc_start;
+ size_t heap_total_slots_at_gc_start;
/* basic statistics */
size_t count;
@@ -550,13 +628,14 @@ typedef struct rb_objspace {
/* Weak references */
size_t weak_references_count;
- size_t retained_weak_references_count;
} profile;
VALUE gc_stress_mode;
struct {
+ bool parent_object_old_p;
VALUE parent_object;
+
int need_major_gc;
size_t last_major_gc;
size_t uncollectible_wb_unprotected_objects;
@@ -565,7 +644,6 @@ typedef struct rb_objspace {
size_t old_objects_limit;
#if RGENGC_ESTIMATE_OLDMALLOC
- size_t oldmalloc_increase;
size_t oldmalloc_increase_limit;
#endif
@@ -591,17 +669,20 @@ typedef struct rb_objspace {
size_t step_slots;
} rincgc;
- st_table *id_to_obj_tbl;
- st_table *obj_to_id_tbl;
-
#if GC_DEBUG_STRESS_TO_CLASS
VALUE stress_to_class;
#endif
- rb_darray(VALUE *) weak_references;
+ rb_darray(VALUE) weak_references;
rb_postponed_job_handle_t finalize_deferred_pjob;
unsigned long live_ractor_cache_count;
+
+ int sweeping_heap_count;
+
+ int fork_vm_lock_lev;
+
+ struct rb_gc_vm_context vm_context;
} rb_objspace_t;
#ifndef HEAP_PAGE_ALIGN_LOG
@@ -609,10 +690,10 @@ typedef struct rb_objspace {
#define HEAP_PAGE_ALIGN_LOG 16
#endif
-#if RACTOR_CHECK_MODE || GC_DEBUG
+#if RB_GC_OBJ_HAS_SUFFIX || GC_DEBUG
struct rvalue_overhead {
-# if RACTOR_CHECK_MODE
- uint32_t _ractor_belonging_id;
+# if RB_GC_OBJ_HAS_SUFFIX
+ struct rb_gc_obj_suffix suffix;
# endif
# if GC_DEBUG
const char *file;
@@ -630,10 +711,37 @@ struct rvalue_overhead {
size_t rb_gc_impl_obj_slot_size(VALUE obj);
# define GET_RVALUE_OVERHEAD(obj) ((struct rvalue_overhead *)((uintptr_t)obj + rb_gc_impl_obj_slot_size(obj)))
#else
-# define RVALUE_OVERHEAD 0
+# ifndef RVALUE_OVERHEAD
+# define RVALUE_OVERHEAD 0
+# endif
#endif
-#define BASE_SLOT_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]) + RVALUE_OVERHEAD)
+#define RVALUE_SLOT_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]) + RVALUE_OVERHEAD)
+
+static const size_t pool_slot_sizes[HEAP_COUNT] = {
+#define SLOT(size) ((size) + RVALUE_OVERHEAD),
+ EACH_POOL_SLOT_SIZE(SLOT)
+#undef SLOT
+};
+
+/* Precomputed reciprocals for fast slot index calculation.
+ * For slot size d: reciprocal = ceil(2^48 / d).
+ * Then offset / d == (uint32_t)((offset * reciprocal) >> 48)
+ * for all offset < HEAP_PAGE_SIZE. */
+#define SLOT_RECIPROCAL_SHIFT 48
+#define SLOT_RECIPROCAL(size) (((1ULL << SLOT_RECIPROCAL_SHIFT) + (size) - 1) / (size))
+
+static const uint64_t heap_slot_reciprocal_table[HEAP_COUNT] = {
+#define SLOT(size) SLOT_RECIPROCAL((size) + RVALUE_OVERHEAD),
+ EACH_POOL_SLOT_SIZE(SLOT)
+#undef SLOT
+};
+
+#if SIZEOF_VALUE >= 8
+static uint8_t size_to_heap_idx[1024 / 8 + 1];
+#else
+static uint8_t size_to_heap_idx[512 / 8 + 1];
+#endif
#ifndef MAX
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
@@ -643,12 +751,12 @@ size_t rb_gc_impl_obj_slot_size(VALUE obj);
#endif
#define roomof(x, y) (((x) + (y) - 1) / (y))
#define CEILDIV(i, mod) roomof(i, mod)
+#define MIN_POOL_SLOT_SIZE 32
enum {
HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG),
HEAP_PAGE_ALIGN_MASK = (~(~0UL << HEAP_PAGE_ALIGN_LOG)),
HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN,
- HEAP_PAGE_OBJ_LIMIT = (unsigned int)((HEAP_PAGE_SIZE - sizeof(struct heap_page_header)) / BASE_SLOT_SIZE),
- HEAP_PAGE_BITMAP_LIMIT = CEILDIV(CEILDIV(HEAP_PAGE_SIZE, BASE_SLOT_SIZE), BITS_BITLENGTH),
+ HEAP_PAGE_BITMAP_LIMIT = CEILDIV(CEILDIV(HEAP_PAGE_SIZE, MIN_POOL_SLOT_SIZE), BITS_BITLENGTH),
HEAP_PAGE_BITMAP_SIZE = (BITS_SIZE * HEAP_PAGE_BITMAP_LIMIT),
};
#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG)
@@ -710,6 +818,10 @@ struct free_slot {
};
struct heap_page {
+ /* Cache line 0: allocation fast path + SLOT_INDEX */
+ struct free_slot *freelist;
+ uintptr_t start;
+ uint64_t slot_size_reciprocal;
unsigned short slot_size;
unsigned short total_slots;
unsigned short free_slots;
@@ -725,8 +837,6 @@ struct heap_page {
struct heap_page *free_next;
struct heap_page_body *body;
- uintptr_t start;
- struct free_slot *freelist;
struct ccan_list_node page_node;
bits_t wb_unprotected_bits[HEAP_PAGE_BITMAP_LIMIT];
@@ -787,44 +897,63 @@ heap_page_in_global_empty_pages_pool(rb_objspace_t *objspace, struct heap_page *
#define GET_PAGE_HEADER(x) (&GET_PAGE_BODY(x)->header)
#define GET_HEAP_PAGE(x) (GET_PAGE_HEADER(x)->page)
-#define NUM_IN_PAGE(p) (((bits_t)(p) & HEAP_PAGE_ALIGN_MASK) / BASE_SLOT_SIZE)
-#define BITMAP_INDEX(p) (NUM_IN_PAGE(p) / BITS_BITLENGTH )
-#define BITMAP_OFFSET(p) (NUM_IN_PAGE(p) & (BITS_BITLENGTH-1))
-#define BITMAP_BIT(p) ((bits_t)1 << BITMAP_OFFSET(p))
+static inline size_t
+slot_index_for_offset(size_t offset, uint64_t reciprocal)
+{
+ return (uint32_t)(((uint64_t)offset * reciprocal) >> SLOT_RECIPROCAL_SHIFT);
+}
+
+#define SLOT_INDEX(page, p) slot_index_for_offset((uintptr_t)(p) - (page)->start, (page)->slot_size_reciprocal)
+#define SLOT_BITMAP_INDEX(page, p) (SLOT_INDEX(page, p) / BITS_BITLENGTH)
+#define SLOT_BITMAP_OFFSET(page, p) (SLOT_INDEX(page, p) & (BITS_BITLENGTH - 1))
+#define SLOT_BITMAP_BIT(page, p) ((bits_t)1 << SLOT_BITMAP_OFFSET(page, p))
-/* Bitmap Operations */
-#define MARKED_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] & BITMAP_BIT(p))
-#define MARK_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] | BITMAP_BIT(p))
-#define CLEAR_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] & ~BITMAP_BIT(p))
+#define _MARKED_IN_BITMAP(bits, page, p) ((bits)[SLOT_BITMAP_INDEX(page, p)] & SLOT_BITMAP_BIT(page, p))
+#define _MARK_IN_BITMAP(bits, page, p) ((bits)[SLOT_BITMAP_INDEX(page, p)] |= SLOT_BITMAP_BIT(page, p))
+#define _CLEAR_IN_BITMAP(bits, page, p) ((bits)[SLOT_BITMAP_INDEX(page, p)] &= ~SLOT_BITMAP_BIT(page, p))
+
+#define MARKED_IN_BITMAP(bits, p) _MARKED_IN_BITMAP(bits, GET_HEAP_PAGE(p), p)
+#define MARK_IN_BITMAP(bits, p) _MARK_IN_BITMAP(bits, GET_HEAP_PAGE(p), p)
+#define CLEAR_IN_BITMAP(bits, p) _CLEAR_IN_BITMAP(bits, GET_HEAP_PAGE(p), p)
-/* getting bitmap */
#define GET_HEAP_MARK_BITS(x) (&GET_HEAP_PAGE(x)->mark_bits[0])
#define GET_HEAP_PINNED_BITS(x) (&GET_HEAP_PAGE(x)->pinned_bits[0])
#define GET_HEAP_UNCOLLECTIBLE_BITS(x) (&GET_HEAP_PAGE(x)->uncollectible_bits[0])
#define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0])
#define GET_HEAP_MARKING_BITS(x) (&GET_HEAP_PAGE(x)->marking_bits[0])
-#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)
-
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;
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ bits_t *age_bits = page->age_bits;
+ size_t slot_idx = SLOT_INDEX(page, obj);
+ size_t idx = (slot_idx / BITS_BITLENGTH) * 2;
+ int shift = (int)(slot_idx & (BITS_BITLENGTH - 1));
+ int lo = (age_bits[idx] >> shift) & 1;
+ int hi = (age_bits[idx + 1] >> shift) & 1;
+ return lo | (hi << 1);
}
static void
-RVALUE_AGE_SET(VALUE obj, int age)
+RVALUE_AGE_SET_BITMAP(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));
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ bits_t *age_bits = page->age_bits;
+ size_t slot_idx = SLOT_INDEX(page, obj);
+ size_t idx = (slot_idx / BITS_BITLENGTH) * 2;
+ int shift = (int)(slot_idx & (BITS_BITLENGTH - 1));
+ bits_t mask = (bits_t)1 << shift;
+
+ age_bits[idx] = (age_bits[idx] & ~mask) | ((bits_t)(age & 1) << shift);
+ age_bits[idx + 1] = (age_bits[idx + 1] & ~mask) | ((bits_t)((age >> 1) & 1) << shift);
+}
+
+static void
+RVALUE_AGE_SET(VALUE obj, int age)
+{
+ RVALUE_AGE_SET_BITMAP(obj, age);
if (age == RVALUE_OLD_AGE) {
RB_FL_SET_RAW(obj, RUBY_FL_PROMOTED);
}
@@ -834,8 +963,112 @@ RVALUE_AGE_SET(VALUE obj, int age)
}
#define malloc_limit objspace->malloc_params.limit
-#define malloc_increase objspace->malloc_params.increase
+#define malloc_increase gc_malloc_counters_increase_unsigned(objspace, &objspace->malloc_counters.counters)
#define malloc_allocated_size objspace->malloc_params.allocated_size
+
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+# define MALLOC_COUNTERS_LOCK(o) rb_native_mutex_lock(&(o)->malloc_counters.lock)
+# define MALLOC_COUNTERS_UNLOCK(o) rb_native_mutex_unlock(&(o)->malloc_counters.lock)
+#else
+# define MALLOC_COUNTERS_LOCK(o) ((void)0)
+# define MALLOC_COUNTERS_UNLOCK(o) ((void)0)
+#endif
+
+static inline void
+gc_counter_add(gc_counter_t *p, size_t delta)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ *p += (gc_counter_t)delta;
+#else
+ rbimpl_atomic_u64_fetch_add_relaxed(p, (uint64_t)delta);
+#endif
+}
+
+static inline gc_counter_t
+gc_counter_load_relaxed(const gc_counter_t *p)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ return *p;
+#else
+ return rbimpl_atomic_u64_load_relaxed(p);
+#endif
+}
+
+static inline gc_counter_t
+gc_counter_load_acquire(const gc_counter_t *p)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ return *p;
+#else
+ return rbimpl_atomic_u64_load_acquire(p);
+#endif
+}
+
+static inline void
+gc_counter_store_release(gc_counter_t *p, gc_counter_t v)
+{
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ *p = v;
+#else
+ rbimpl_atomic_u64_set_release(p, v);
+#endif
+}
+
+static inline int64_t
+gc_malloc_counters_increase(rb_objspace_t *objspace, const struct gc_malloc_bytes *c)
+{
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_t malloc_at = gc_counter_load_acquire(&c->malloc_at_last_gc);
+ gc_counter_t free_at = gc_counter_load_acquire(&c->free_at_last_gc);
+ gc_counter_t malloc_now = gc_counter_load_relaxed(&c->malloc);
+ gc_counter_t free_now = gc_counter_load_relaxed(&c->free);
+ MALLOC_COUNTERS_UNLOCK(objspace);
+
+ gc_counter_t malloc_delta = malloc_now - malloc_at;
+ gc_counter_t free_delta = free_now - free_at;
+
+ if (malloc_delta >= free_delta) {
+ return (int64_t)(malloc_delta - free_delta);
+ }
+ else {
+ return -(int64_t)(free_delta - malloc_delta);
+ }
+}
+
+static inline size_t
+gc_malloc_counters_increase_unsigned(rb_objspace_t *objspace, const struct gc_malloc_bytes *c)
+{
+ int64_t inc = gc_malloc_counters_increase(objspace, c);
+ if (inc <= 0) return 0;
+#if SIZEOF_SIZE_T < 8
+ if ((uint64_t)inc > SIZE_MAX) return SIZE_MAX;
+#endif
+ return (size_t)inc;
+}
+
+static inline int64_t
+gc_malloc_counters_snapshot(rb_objspace_t *objspace, struct gc_malloc_bytes *c)
+{
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_t malloc_now = gc_counter_load_relaxed(&c->malloc);
+ gc_counter_t free_now = gc_counter_load_relaxed(&c->free);
+ gc_counter_t malloc_at = gc_counter_load_relaxed(&c->malloc_at_last_gc);
+ gc_counter_t free_at = gc_counter_load_relaxed(&c->free_at_last_gc);
+ gc_counter_store_release(&c->malloc_at_last_gc, malloc_now);
+ gc_counter_store_release(&c->free_at_last_gc, free_now);
+ MALLOC_COUNTERS_UNLOCK(objspace);
+
+ gc_counter_t malloc_delta = malloc_now - malloc_at;
+ gc_counter_t free_delta = free_now - free_at;
+
+ if (malloc_delta >= free_delta) {
+ return (int64_t)(malloc_delta - free_delta);
+ }
+ else {
+ return -(int64_t)(free_delta - malloc_delta);
+ }
+}
+
#define heap_pages_lomem objspace->heap_pages.range[0]
#define heap_pages_himem objspace->heap_pages.range[1]
#define heap_pages_freeable_pages objspace->heap_pages.freeable_pages
@@ -901,12 +1134,7 @@ gc_mode_verify(enum gc_mode mode)
static inline bool
has_sweeping_pages(rb_objspace_t *objspace)
{
- for (int i = 0; i < HEAP_COUNT; i++) {
- if ((&heaps[i])->sweeping_page) {
- return TRUE;
- }
- }
- return FALSE;
+ return objspace->sweeping_heap_count != 0;
}
static inline size_t
@@ -961,9 +1189,22 @@ total_final_slots_count(rb_objspace_t *objspace)
#define is_full_marking(objspace) ((objspace)->flags.during_minor_gc == FALSE)
#define is_incremental_marking(objspace) ((objspace)->flags.during_incremental_marking != FALSE)
#define will_be_incremental_marking(objspace) ((objspace)->rgengc.need_major_gc != GPR_FLAG_NONE)
-#define GC_INCREMENTAL_SWEEP_SLOT_COUNT 2048
-#define GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT 1024
+/*
+ * Byte budget for incremental sweep steps. Each step sweeps at most
+ * this many bytes worth of slots before yielding. The effective slot
+ * count per step is GC_INCREMENTAL_SWEEP_BYTES / heap->slot_size,
+ * so larger slot pools (which are less heavily used) naturally get
+ * fewer slots swept per step.
+ *
+ * Baseline: 2048 slots * RVALUE_SLOT_SIZE = 2048 * 40 = 81920 bytes,
+ * preserving the historical behavior for the smallest heap.
+ */
+#define GC_INCREMENTAL_SWEEP_BYTES (2048 * RVALUE_SLOT_SIZE)
+#define GC_INCREMENTAL_SWEEP_POOL_BYTES (1024 * RVALUE_SLOT_SIZE)
#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
+/* In lazy sweeping or the previous incremental marking finished and did not yield a free page. */
+#define needs_continue_sweeping(objspace, heap) \
+ ((heap)->free_pages == NULL && is_lazy_sweeping(objspace))
#if SIZEOF_LONG == SIZEOF_VOIDP
# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
@@ -975,7 +1216,7 @@ total_final_slots_count(rb_objspace_t *objspace)
#endif
struct RZombie {
- struct RBasic basic;
+ VALUE flags;
VALUE next;
void (*dfree)(void *);
void *data;
@@ -1089,10 +1330,10 @@ tick(void)
return val;
}
+#elif defined(__POWERPC__) && defined(__APPLE__)
/* Implementation for macOS PPC by @nobu
* See: https://github.com/ruby/ruby/pull/5975#discussion_r890045558
*/
-#elif defined(__POWERPC__) && defined(__APPLE__)
typedef unsigned long long tick_t;
#define PRItick "llu"
@@ -1211,7 +1452,7 @@ check_rvalue_consistency_force(rb_objspace_t *objspace, const VALUE obj, int ter
{
int err = 0;
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
if (SPECIAL_CONST_P(obj)) {
fprintf(stderr, "check_rvalue_consistency: %p is a special const.\n", (void *)obj);
@@ -1301,7 +1542,7 @@ check_rvalue_consistency_force(rb_objspace_t *objspace, const VALUE obj, int ter
}
}
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
if (err > 0 && terminate) {
rb_bug("check_rvalue_consistency_force: there is %d errors.", err);
@@ -1327,16 +1568,12 @@ check_rvalue_consistency(rb_objspace_t *objspace, const VALUE obj)
static inline bool
gc_object_moved_p(rb_objspace_t *objspace, VALUE obj)
{
- if (RB_SPECIAL_CONST_P(obj)) {
- return FALSE;
- }
- else {
- int ret;
- asan_unpoisoning_object(obj) {
- ret = BUILTIN_TYPE(obj) == T_MOVED;
- }
- return ret;
+
+ bool ret;
+ asan_unpoisoning_object(obj) {
+ ret = BUILTIN_TYPE(obj) == T_MOVED;
}
+ return ret;
}
static inline int
@@ -1477,7 +1714,6 @@ rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event)
{
rb_objspace_t *objspace = objspace_ptr;
objspace->hook_events = event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK;
- objspace->flags.has_newobj_hook = !!(objspace->hook_events & RUBY_INTERNAL_EVENT_NEWOBJ);
}
unsigned long long
@@ -1507,38 +1743,6 @@ rb_gc_impl_get_measure_total_time(void *objspace_ptr)
return objspace->flags.measure_gc;
}
-static size_t
-minimum_slots_for_heap(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- size_t heap_idx = heap - heaps;
- return gc_params.heap_init_slots[heap_idx];
-}
-
-static int
-object_id_cmp(st_data_t x, st_data_t y)
-{
- if (RB_TYPE_P(x, T_BIGNUM)) {
- return !rb_big_eql(x, y);
- }
- else {
- return x != y;
- }
-}
-
-static st_index_t
-object_id_hash(st_data_t n)
-{
- return FIX2LONG(rb_hash((VALUE)n));
-}
-
-#define OBJ_ID_INCREMENT (RUBY_IMMEDIATE_MASK + 1)
-#define OBJ_ID_INITIAL (OBJ_ID_INCREMENT)
-
-static const struct st_hash_type object_id_hash_type = {
- object_id_cmp,
- object_id_hash,
-};
-
/* garbage objects will be collected soon. */
bool
rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE ptr)
@@ -1564,54 +1768,12 @@ rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE ptr)
!RVALUE_MARKED(objspace, ptr);
}
-VALUE
-rb_gc_impl_object_id(void *objspace_ptr, VALUE obj)
+struct rb_gc_vm_context *
+rb_gc_impl_get_vm_context(void *objspace_ptr)
{
- VALUE id;
rb_objspace_t *objspace = objspace_ptr;
- unsigned int lev = rb_gc_vm_lock();
- if (FL_TEST(obj, FL_SEEN_OBJ_ID)) {
- st_data_t val;
- if (st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, &val)) {
- id = (VALUE)val;
- }
- else {
- rb_bug("rb_gc_impl_object_id: FL_SEEN_OBJ_ID flag set but not found in table");
- }
- }
- else {
- GC_ASSERT(!st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, NULL));
-
- id = ULL2NUM(objspace->next_object_id);
- objspace->next_object_id += OBJ_ID_INCREMENT;
-
- st_insert(objspace->obj_to_id_tbl, (st_data_t)obj, (st_data_t)id);
- st_insert(objspace->id_to_obj_tbl, (st_data_t)id, (st_data_t)obj);
- FL_SET(obj, FL_SEEN_OBJ_ID);
- }
- rb_gc_vm_unlock(lev);
-
- return id;
-}
-
-VALUE
-rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- VALUE obj;
- if (st_lookup(objspace->id_to_obj_tbl, object_id, &obj) &&
- !rb_gc_impl_garbage_object_p(objspace, obj)) {
- return obj;
- }
-
- if (rb_funcall(object_id, rb_intern(">="), 1, ULL2NUM(objspace->next_object_id))) {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not id value", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
- }
- else {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is recycled object", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
- }
+ return &objspace->vm_context;
}
static void free_stack_chunks(mark_stack_t *);
@@ -1631,13 +1793,14 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj
page->freelist = slot;
asan_lock_freelist(page);
- RVALUE_AGE_RESET(obj);
+ // Should have already been reset
+ GC_ASSERT(RVALUE_AGE_GET(obj) == 0);
if (RGENGC_CHECK_MODE &&
/* obj should belong to page */
!(page->start <= (uintptr_t)obj &&
(uintptr_t)obj < ((uintptr_t)page->start + (page->total_slots * page->slot_size)) &&
- obj % BASE_SLOT_SIZE == 0)) {
+ obj % sizeof(VALUE) == 0)) {
rb_bug("heap_page_add_freeobj: %p is not rvalue.", (void *)obj);
}
@@ -1646,8 +1809,8 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj
}
static void
-heap_allocatable_slots_expand(rb_objspace_t *objspace,
- rb_heap_t *heap, size_t free_slots, size_t total_slots)
+heap_allocatable_bytes_expand(rb_objspace_t *objspace,
+ rb_heap_t *heap, size_t free_slots, size_t total_slots, size_t slot_size)
{
double goal_ratio = gc_params.heap_free_slots_goal_ratio;
size_t target_total_slots;
@@ -1656,7 +1819,7 @@ heap_allocatable_slots_expand(rb_objspace_t *objspace,
target_total_slots = (size_t)(total_slots * gc_params.growth_factor);
}
else if (total_slots == 0) {
- target_total_slots = minimum_slots_for_heap(objspace, heap);
+ target_total_slots = gc_params.heap_init_bytes / slot_size;
}
else {
/* Find `f' where free_slots = f * total_slots * goal_ratio
@@ -1679,8 +1842,8 @@ heap_allocatable_slots_expand(rb_objspace_t *objspace,
}
}
- if (gc_params.growth_max_slots > 0) {
- size_t max_total_slots = (size_t)(total_slots + gc_params.growth_max_slots);
+ if (gc_params.growth_max_bytes > 0) {
+ size_t max_total_slots = total_slots + gc_params.growth_max_bytes / slot_size;
if (target_total_slots > max_total_slots) target_total_slots = max_total_slots;
}
@@ -1688,7 +1851,7 @@ heap_allocatable_slots_expand(rb_objspace_t *objspace,
/* Extend by at least 1 page. */
if (extend_slot_count == 0) extend_slot_count = 1;
- objspace->heap_pages.allocatable_slots += extend_slot_count;
+ objspace->heap_pages.allocatable_bytes += extend_slot_count * slot_size;
}
static inline void
@@ -1771,13 +1934,7 @@ heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
static void
heap_pages_free_unused_pages(rb_objspace_t *objspace)
{
- size_t pages_to_keep_count =
- // Get number of pages estimated for the smallest size pool
- CEILDIV(objspace->heap_pages.allocatable_slots, HEAP_PAGE_OBJ_LIMIT) *
- // Estimate the average slot size multiple
- (1 << (HEAP_COUNT / 2));
-
- if (objspace->empty_pages != NULL && objspace->empty_pages_count > pages_to_keep_count) {
+ if (objspace->empty_pages != NULL && heap_pages_freeable_pages > 0) {
GC_ASSERT(objspace->empty_pages_count > 0);
objspace->empty_pages = NULL;
objspace->empty_pages_count = 0;
@@ -1786,15 +1943,15 @@ heap_pages_free_unused_pages(rb_objspace_t *objspace)
for (i = j = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
struct heap_page *page = rb_darray_get(objspace->heap_pages.sorted, i);
- if (heap_page_in_global_empty_pages_pool(objspace, page) && pages_to_keep_count == 0) {
+ if (heap_page_in_global_empty_pages_pool(objspace, page) && heap_pages_freeable_pages > 0) {
heap_page_free(objspace, page);
+ heap_pages_freeable_pages--;
}
else {
- if (heap_page_in_global_empty_pages_pool(objspace, page) && pages_to_keep_count > 0) {
+ if (heap_page_in_global_empty_pages_pool(objspace, page)) {
page->free_next = objspace->empty_pages;
objspace->empty_pages = page;
objspace->empty_pages_count++;
- pages_to_keep_count--;
}
if (i != j) {
@@ -1916,7 +2073,10 @@ static struct heap_page *
heap_page_resurrect(rb_objspace_t *objspace)
{
struct heap_page *page = NULL;
- if (objspace->empty_pages != NULL) {
+ if (objspace->empty_pages == NULL) {
+ GC_ASSERT(objspace->empty_pages_count == 0);
+ }
+ else {
GC_ASSERT(objspace->empty_pages_count > 0);
objspace->empty_pages_count--;
page = objspace->empty_pages;
@@ -1981,31 +2141,22 @@ heap_add_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
GC_ASSERT(!heap->sweeping_page);
GC_ASSERT(heap_page_in_global_empty_pages_pool(objspace, page));
- /* adjust obj_limit (object number available in this page) */
+ /* Align start to slot_size boundary */
uintptr_t start = (uintptr_t)page->body + sizeof(struct heap_page_header);
- if (start % BASE_SLOT_SIZE != 0) {
- int delta = BASE_SLOT_SIZE - (start % BASE_SLOT_SIZE);
- start = start + delta;
- GC_ASSERT(NUM_IN_PAGE(start) == 0 || NUM_IN_PAGE(start) == 1);
-
- /* Find a num in page that is evenly divisible by `stride`.
- * This is to ensure that objects are aligned with bit planes.
- * In other words, ensure there are an even number of objects
- * per bit plane. */
- if (NUM_IN_PAGE(start) == 1) {
- start += heap->slot_size - BASE_SLOT_SIZE;
- }
-
- GC_ASSERT(NUM_IN_PAGE(start) * BASE_SLOT_SIZE % heap->slot_size == 0);
- }
+ uintptr_t rem = start % heap->slot_size;
+ if (rem) start += heap->slot_size - rem;
int slot_count = (int)((HEAP_PAGE_SIZE - (start - (uintptr_t)page->body))/heap->slot_size);
page->start = start;
page->total_slots = slot_count;
page->slot_size = heap->slot_size;
+ page->slot_size_reciprocal = heap_slot_reciprocal_table[heap - heaps];
page->heap = heap;
+ memset(&page->wb_unprotected_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
+ memset(&page->age_bits[0], 0, sizeof(page->age_bits));
+
asan_unlock_freelist(page);
page->freelist = NULL;
asan_unpoison_memory_region(page->body, HEAP_PAGE_SIZE, false);
@@ -2026,47 +2177,56 @@ heap_add_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
static int
heap_page_allocate_and_initialize(rb_objspace_t *objspace, rb_heap_t *heap)
{
- if (objspace->heap_pages.allocatable_slots > 0) {
- gc_report(1, objspace, "heap_page_allocate_and_initialize: rb_darray_size(objspace->heap_pages.sorted): %"PRIdSIZE", "
- "allocatable_slots: %"PRIdSIZE", heap->total_pages: %"PRIdSIZE"\n",
- rb_darray_size(objspace->heap_pages.sorted), objspace->heap_pages.allocatable_slots, heap->total_pages);
+ gc_report(1, objspace, "heap_page_allocate_and_initialize: rb_darray_size(objspace->heap_pages.sorted): %"PRIdSIZE", "
+ "allocatable_bytes: %"PRIdSIZE", heap->total_pages: %"PRIdSIZE"\n",
+ rb_darray_size(objspace->heap_pages.sorted), objspace->heap_pages.allocatable_bytes, heap->total_pages);
- struct heap_page *page = heap_page_resurrect(objspace);
- if (page == NULL) {
- page = heap_page_allocate(objspace);
- }
+ bool allocated = false;
+ struct heap_page *page = heap_page_resurrect(objspace);
+
+ if (page == NULL && objspace->heap_pages.allocatable_bytes > 0) {
+ page = heap_page_allocate(objspace);
+ allocated = true;
+
+ GC_ASSERT(page != NULL);
+ }
+
+ if (page != NULL) {
heap_add_page(objspace, heap, page);
heap_add_freepage(heap, page);
- if (objspace->heap_pages.allocatable_slots > (size_t)page->total_slots) {
- objspace->heap_pages.allocatable_slots -= page->total_slots;
- }
- else {
- objspace->heap_pages.allocatable_slots = 0;
+ if (allocated) {
+ size_t page_bytes = (size_t)page->total_slots * page->slot_size;
+ if (objspace->heap_pages.allocatable_bytes > page_bytes) {
+ objspace->heap_pages.allocatable_bytes -= page_bytes;
+ }
+ else {
+ objspace->heap_pages.allocatable_bytes = 0;
+ }
}
-
- return true;
}
- return false;
+ return page != NULL;
}
static void
heap_page_allocate_and_initialize_force(rb_objspace_t *objspace, rb_heap_t *heap)
{
- size_t prev_allocatable_slots = objspace->heap_pages.allocatable_slots;
- // Set allocatable slots to 1 to force a page to be created.
- objspace->heap_pages.allocatable_slots = 1;
+ size_t prev_allocatable_bytes = objspace->heap_pages.allocatable_bytes;
+ objspace->heap_pages.allocatable_bytes = HEAP_PAGE_SIZE;
heap_page_allocate_and_initialize(objspace, heap);
GC_ASSERT(heap->free_pages != NULL);
- objspace->heap_pages.allocatable_slots = prev_allocatable_slots;
+ objspace->heap_pages.allocatable_bytes = prev_allocatable_bytes;
}
static void
gc_continue(rb_objspace_t *objspace, rb_heap_t *heap)
{
unsigned int lock_lev;
- gc_enter(objspace, gc_enter_event_continue, &lock_lev);
+ bool needs_gc = is_incremental_marking(objspace) || needs_continue_sweeping(objspace, heap);
+ if (!needs_gc) return;
+
+ gc_enter(objspace, gc_enter_event_continue, &lock_lev); // takes vm barrier, try to avoid
/* Continue marking if in incremental marking. */
if (is_incremental_marking(objspace)) {
@@ -2075,9 +2235,7 @@ gc_continue(rb_objspace_t *objspace, rb_heap_t *heap)
}
}
- /* Continue sweeping if in lazy sweeping or the previous incremental
- * marking finished and did not yield a free page. */
- if (heap->free_pages == NULL && is_lazy_sweeping(objspace)) {
+ if (needs_continue_sweeping(objspace, heap)) {
gc_sweep_continue(objspace, heap);
}
@@ -2089,7 +2247,7 @@ heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
{
GC_ASSERT(heap->free_pages == NULL);
- if (heap->total_slots < gc_params.heap_init_slots[heap - heaps] &&
+ if (heap->total_slots < gc_params.heap_init_bytes / heap->slot_size &&
heap->sweeping_page == NULL) {
heap_page_allocate_and_initialize_force(objspace, heap);
GC_ASSERT(heap->free_pages != NULL);
@@ -2106,15 +2264,18 @@ heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
/* If we still don't have a free page and not allowed to create a new page,
* we should start a new GC cycle. */
if (heap->free_pages == NULL) {
+ GC_ASSERT(objspace->empty_pages_count == 0);
+ GC_ASSERT(objspace->heap_pages.allocatable_bytes == 0);
+
if (gc_start(objspace, GPR_FLAG_NEWOBJ) == FALSE) {
rb_memerror();
}
else {
- if (objspace->heap_pages.allocatable_slots == 0 && !gc_config_full_mark_val) {
- heap_allocatable_slots_expand(objspace, heap,
+ if (objspace->heap_pages.allocatable_bytes == 0 && !gc_config_full_mark_val) {
+ heap_allocatable_bytes_expand(objspace, heap,
heap->freed_slots + heap->empty_slots,
- heap->total_slots);
- GC_ASSERT(objspace->heap_pages.allocatable_slots > 0);
+ heap->total_slots, heap->slot_size);
+ GC_ASSERT(objspace->heap_pages.allocatable_bytes > 0);
}
/* Do steps of incremental marking or lazy sweeping if the GC run permits. */
gc_continue(objspace, heap);
@@ -2147,16 +2308,6 @@ heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
GC_ASSERT(heap->free_pages != NULL);
}
-static inline VALUE
-newobj_fill(VALUE obj, VALUE v1, VALUE v2, VALUE v3)
-{
- VALUE *p = (VALUE *)obj;
- p[2] = v1;
- p[3] = v2;
- p[4] = v3;
- return obj;
-}
-
#if GC_DEBUG
static inline const char*
rb_gc_impl_source_location_cstr(int *ptr)
@@ -2178,27 +2329,16 @@ rb_gc_impl_source_location_cstr(int *ptr)
static inline VALUE
newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace, VALUE obj)
{
-#if !__has_feature(memory_sanitizer)
GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
-#endif
RBASIC(obj)->flags = flags;
*((VALUE *)&RBASIC(obj)->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
- void rb_ractor_setup_belonging(VALUE obj);
- rb_ractor_setup_belonging(obj);
+#if RBASIC_SHAPE_ID_FIELD
+ RBASIC(obj)->shape_id = 0;
#endif
#if RGENGC_CHECK_MODE
- newobj_fill(obj, 0, 0, 0);
-
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
check_rvalue_consistency(objspace, obj);
@@ -2209,7 +2349,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
if (RVALUE_REMEMBERED(objspace, obj)) rb_bug("newobj: %s is remembered.", rb_obj_info(obj));
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
#endif
if (RB_UNLIKELY(wb_protected == FALSE)) {
@@ -2238,7 +2378,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
gc_report(5, objspace, "newobj: %s\n", rb_obj_info(obj));
- RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, rb_obj_info(obj));
+ // RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, rb_obj_info(obj));
return obj;
}
@@ -2253,22 +2393,26 @@ heap_slot_size(unsigned char pool_id)
{
GC_ASSERT(pool_id < HEAP_COUNT);
- size_t slot_size = (1 << pool_id) * BASE_SLOT_SIZE;
-
-#if RGENGC_CHECK_MODE
- rb_objspace_t *objspace = rb_gc_get_objspace();
- GC_ASSERT(heaps[pool_id].slot_size == (short)slot_size);
-#endif
-
- slot_size -= RVALUE_OVERHEAD;
-
- return slot_size;
+ return pool_slot_sizes[pool_id] - RVALUE_OVERHEAD;
}
bool
rb_gc_impl_size_allocatable_p(size_t size)
{
- return size <= heap_slot_size(HEAP_COUNT - 1);
+ return size + RVALUE_OVERHEAD <= pool_slot_sizes[HEAP_COUNT - 1];
+}
+
+static const size_t ALLOCATED_COUNT_STEP = 1024;
+static void
+ractor_cache_flush_count(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache)
+{
+ for (int heap_idx = 0; heap_idx < HEAP_COUNT; heap_idx++) {
+ rb_ractor_newobj_heap_cache_t *heap_cache = &cache->heap_caches[heap_idx];
+
+ rb_heap_t *heap = &heaps[heap_idx];
+ RUBY_ATOMIC_SIZE_ADD(heap->total_allocated_objects, heap_cache->allocated_objects_count);
+ heap_cache->allocated_objects_count = 0;
+ }
}
static inline VALUE
@@ -2293,6 +2437,14 @@ ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *ca
VALUE obj = (VALUE)p;
rb_asan_unpoison_object(obj, true);
heap_cache->freelist = p->next;
+
+ heap_cache->allocated_objects_count++;
+ rb_heap_t *heap = &heaps[heap_idx];
+ if (heap_cache->allocated_objects_count >= ALLOCATED_COUNT_STEP) {
+ RUBY_ATOMIC_SIZE_ADD(heap->total_allocated_objects, heap_cache->allocated_objects_count);
+ heap_cache->allocated_objects_count = 0;
+ }
+
#if RGENGC_CHECK_MODE
GC_ASSERT(rb_gc_impl_obj_slot_size(obj) == heap_slot_size(heap_idx));
// zero clear
@@ -2346,28 +2498,30 @@ ractor_cache_set_page(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache,
rb_asan_poison_object((VALUE)heap_cache->freelist);
}
+static void
+init_size_to_heap_idx(void)
+{
+ for (size_t i = 0; i < sizeof(size_to_heap_idx); i++) {
+ size_t effective = i * 8 + RVALUE_OVERHEAD;
+ uint8_t idx;
+ for (idx = 0; idx < HEAP_COUNT; idx++) {
+ if (effective <= pool_slot_sizes[idx]) break;
+ }
+ size_to_heap_idx[i] = idx;
+ }
+}
+
static inline size_t
heap_idx_for_size(size_t size)
{
- size += RVALUE_OVERHEAD;
-
- size_t slot_count = CEILDIV(size, BASE_SLOT_SIZE);
-
- /* heap_idx is ceil(log2(slot_count)) */
- size_t heap_idx = 64 - nlz_int64(slot_count - 1);
-
- if (heap_idx >= HEAP_COUNT) {
- rb_bug("heap_idx_for_size: allocation size too large "
- "(size=%"PRIuSIZE"u, heap_idx=%"PRIuSIZE"u)", size, heap_idx);
+ size_t compressed = (size + 7) >> 3;
+ if (compressed < sizeof(size_to_heap_idx)) {
+ size_t heap_idx = size_to_heap_idx[compressed];
+ if (RB_LIKELY(heap_idx < HEAP_COUNT)) return heap_idx;
}
-#if RGENGC_CHECK_MODE
- rb_objspace_t *objspace = rb_gc_get_objspace();
- GC_ASSERT(size <= (size_t)heaps[heap_idx].slot_size);
- if (heap_idx > 0) GC_ASSERT(size > (size_t)heaps[heap_idx - 1].slot_size);
-#endif
-
- return heap_idx;
+ rb_bug("heap_idx_for_size: allocation size too large "
+ "(size=%"PRIuSIZE")", size);
}
size_t
@@ -2403,7 +2557,7 @@ newobj_cache_miss(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size
bool unlock_vm = false;
if (!vm_locked) {
- lev = rb_gc_cr_lock();
+ lev = RB_GC_CR_LOCK();
unlock_vm = true;
}
@@ -2427,7 +2581,7 @@ newobj_cache_miss(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size
}
if (unlock_vm) {
- rb_gc_cr_unlock(lev);
+ RB_GC_CR_UNLOCK(lev);
}
if (RB_UNLIKELY(obj == Qfalse)) {
@@ -2445,12 +2599,6 @@ newobj_alloc(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t he
obj = newobj_cache_miss(objspace, cache, heap_idx, vm_locked);
}
- rb_heap_t *heap = &heaps[heap_idx];
- heap->total_allocated_objects++;
- GC_ASSERT(rb_gc_multi_ractor_p() ||
- heap->total_slots >=
- (heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count));
-
return obj;
}
@@ -2462,7 +2610,7 @@ newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_new
VALUE obj;
unsigned int lev;
- lev = rb_gc_cr_lock();
+ lev = RB_GC_CR_LOCK();
{
if (RB_UNLIKELY(during_gc || ruby_gc_stressful)) {
if (during_gc) {
@@ -2484,7 +2632,7 @@ newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_new
obj = newobj_alloc(objspace, cache, heap_idx, true);
newobj_init(klass, flags, wb_protected, objspace, obj);
}
- rb_gc_cr_unlock(lev);
+ RB_GC_CR_UNLOCK(lev);
return obj;
}
@@ -2507,7 +2655,7 @@ newobj_slowpath_wb_unprotected(VALUE klass, VALUE flags, rb_objspace_t *objspace
}
VALUE
-rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size)
+rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
{
VALUE obj;
rb_objspace_t *objspace = objspace_ptr;
@@ -2516,7 +2664,7 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
(void)RB_DEBUG_COUNTER_INC_IF(obj_newobj_wb_unprotected, !wb_protected);
if (RB_UNLIKELY(stress_to_class)) {
- if (RTEST(rb_hash_has_key(stress_to_class, klass))) {
+ if (rb_hash_lookup2(stress_to_class, klass, Qundef) != Qundef) {
rb_memerror();
}
}
@@ -2538,7 +2686,7 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
newobj_slowpath_wb_unprotected(klass, flags, objspace, cache, heap_idx);
}
- return newobj_fill(obj, v1, v2, v3);
+ return obj;
}
static int
@@ -2590,7 +2738,7 @@ is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr)
if (p < heap_pages_lomem || p > heap_pages_himem) return FALSE;
RB_DEBUG_COUNTER_INC(gc_isptr_range);
- if (p % BASE_SLOT_SIZE != 0) return FALSE;
+ if (p % sizeof(VALUE) != 0) return FALSE;
RB_DEBUG_COUNTER_INC(gc_isptr_align);
page = heap_page_for_ptr(objspace, (uintptr_t)ptr);
@@ -2602,7 +2750,7 @@ is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr)
else {
if (p < page->start) return FALSE;
if (p >= page->start + (page->total_slots * page->slot_size)) return FALSE;
- if ((NUM_IN_PAGE(p) * BASE_SLOT_SIZE) % page->slot_size != 0) return FALSE;
+ if ((p - page->start) % page->slot_size != 0) return FALSE;
return TRUE;
}
@@ -2616,7 +2764,7 @@ rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr)
return is_pointer_to_heap(objspace_ptr, ptr);
}
-#define ZOMBIE_OBJ_KEPT_FLAGS (FL_SEEN_OBJ_ID | FL_FINALIZE)
+#define ZOMBIE_OBJ_KEPT_FLAGS (FL_FINALIZE)
void
rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data)
@@ -2624,7 +2772,7 @@ rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), voi
rb_objspace_t *objspace = objspace_ptr;
struct RZombie *zombie = RZOMBIE(obj);
- zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & ZOMBIE_OBJ_KEPT_FLAGS);
+ zombie->flags = T_ZOMBIE | (zombie->flags & ZOMBIE_OBJ_KEPT_FLAGS);
zombie->dfree = dfree;
zombie->data = data;
VALUE prev, next = heap_pages_deferred_final;
@@ -2638,23 +2786,6 @@ rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), voi
page->heap->final_slots_count++;
}
-static void
-obj_free_object_id(rb_objspace_t *objspace, VALUE obj)
-{
- st_data_t o = (st_data_t)obj, id;
-
- GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE || FL_TEST(obj, FL_SEEN_OBJ_ID));
- FL_UNSET(obj, FL_SEEN_OBJ_ID);
-
- if (st_delete(objspace->obj_to_id_tbl, &o, &id)) {
- GC_ASSERT(id);
- st_delete(objspace->id_to_obj_tbl, &id, NULL);
- }
- else {
- rb_bug("Object ID seen, but not in mapping table: %s", rb_obj_info(obj));
- }
-}
-
typedef int each_obj_callback(void *, void *, size_t, void *);
typedef int each_page_callback(struct heap_page *, void *);
@@ -2816,30 +2947,38 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
RBASIC(obj)->flags |= FL_FINALIZE;
+ unsigned int lev = RB_GC_VM_LOCK();
+
if (st_lookup(finalizer_table, obj, &data)) {
table = (VALUE)data;
+ VALUE dup_table = rb_ary_dup(table);
+ RB_GC_VM_UNLOCK(lev);
/* 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)) {
+ VALUE recv = RARRAY_AREF(dup_table, i);
+ if (rb_equal(recv, block)) { // can't be called with VM lock held
return recv;
}
}
}
+ lev = RB_GC_VM_LOCK();
+ RB_GC_GUARD(dup_table);
rb_ary_push(table, block);
}
else {
- table = rb_ary_new3(1, block);
+ table = rb_ary_new3(2, rb_obj_id(obj), block);
rb_obj_hide(table);
st_add_direct(finalizer_table, obj, table);
}
+ RB_GC_VM_UNLOCK(lev);
+
return block;
}
@@ -2851,7 +2990,11 @@ rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
GC_ASSERT(!OBJ_FROZEN(obj));
st_data_t data = obj;
+
+ int lev = RB_GC_VM_LOCK();
st_delete(finalizer_table, &data, 0);
+ RB_GC_VM_UNLOCK(lev);
+
FL_UNSET(obj, FL_FINALIZE);
}
@@ -2864,27 +3007,17 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
if (!FL_TEST(obj, FL_FINALIZE)) return;
+ int lev = RB_GC_VM_LOCK();
if (RB_LIKELY(st_lookup(finalizer_table, obj, &data))) {
- table = (VALUE)data;
+ table = rb_ary_dup((VALUE)data);
+ RARRAY_ASET(table, 0, rb_obj_id(dest));
st_insert(finalizer_table, dest, table);
FL_SET(dest, FL_FINALIZE);
}
else {
rb_bug("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s", rb_obj_info(obj));
}
-}
-
-static VALUE
-get_object_id_in_finalizer(rb_objspace_t *objspace, VALUE obj)
-{
- if (FL_TEST_RAW(obj, FL_SEEN_OBJ_ID)) {
- return rb_gc_impl_object_id(objspace, obj);
- }
- else {
- VALUE id = ULL2NUM(objspace->next_object_id);
- objspace->next_object_id += OBJ_ID_INCREMENT;
- return id;
- }
+ RB_GC_VM_UNLOCK(lev);
}
static VALUE
@@ -2892,11 +3025,11 @@ get_final(long i, void *data)
{
VALUE table = (VALUE)data;
- return RARRAY_AREF(table, i);
+ return RARRAY_AREF(table, i + 1);
}
-static void
-run_final(rb_objspace_t *objspace, VALUE zombie)
+static unsigned int
+run_final(rb_objspace_t *objspace, VALUE zombie, unsigned int lev)
{
if (RZOMBIE(zombie)->dfree) {
RZOMBIE(zombie)->dfree(RZOMBIE(zombie)->data);
@@ -2907,7 +3040,9 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
FL_UNSET(zombie, FL_FINALIZE);
st_data_t table;
if (st_delete(finalizer_table, &key, &table)) {
- rb_gc_run_obj_finalizer(get_object_id_in_finalizer(objspace, zombie), RARRAY_LEN(table), get_final, (void *)table);
+ RB_GC_VM_UNLOCK(lev);
+ rb_gc_run_obj_finalizer(RARRAY_AREF(table, 0), RARRAY_LEN(table) - 1, get_final, (void *)table);
+ lev = RB_GC_VM_LOCK();
}
else {
rb_bug("FL_FINALIZE flag is set, but finalizers are not found");
@@ -2916,6 +3051,7 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
else {
GC_ASSERT(!st_lookup(finalizer_table, key, NULL));
}
+ return lev;
}
static void
@@ -2928,25 +3064,22 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
next_zombie = RZOMBIE(zombie)->next;
page = GET_HEAP_PAGE(zombie);
- run_final(objspace, zombie);
+ unsigned int lev = RB_GC_VM_LOCK();
- int lev = rb_gc_vm_lock();
+ lev = run_final(objspace, zombie, lev);
{
GC_ASSERT(BUILTIN_TYPE(zombie) == T_ZOMBIE);
- if (FL_TEST_RAW(zombie, FL_SEEN_OBJ_ID)) {
- obj_free_object_id(objspace, zombie);
- }
-
GC_ASSERT(page->heap->final_slots_count > 0);
GC_ASSERT(page->final_slots > 0);
page->heap->final_slots_count--;
page->final_slots--;
page->free_slots++;
+ RVALUE_AGE_SET_BITMAP(zombie, 0);
heap_page_add_freeobj(objspace, page, zombie);
page->heap->total_freed_objects++;
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
zombie = next_zombie;
}
@@ -3002,6 +3135,7 @@ gc_abort(void *objspace_ptr)
}
if (is_lazy_sweeping(objspace)) {
+ objspace->sweeping_heap_count = 0;
for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
@@ -3048,16 +3182,15 @@ rb_gc_impl_shutdown_free_objects(void *objspace_ptr)
}
static int
-rb_gc_impl_shutdown_call_finalizer_i(st_data_t key, st_data_t val, st_data_t data)
+rb_gc_impl_shutdown_call_finalizer_i(st_data_t key, st_data_t val, st_data_t _data)
{
- rb_objspace_t *objspace = (rb_objspace_t *)data;
VALUE obj = (VALUE)key;
VALUE table = (VALUE)val;
GC_ASSERT(RB_FL_TEST(obj, FL_FINALIZE));
GC_ASSERT(RB_BUILTIN_TYPE(val) == T_ARRAY);
- rb_gc_run_obj_finalizer(rb_gc_impl_object_id(objspace, obj), RARRAY_LEN(table), get_final, (void *)table);
+ rb_gc_run_obj_finalizer(RARRAY_AREF(table, 0), RARRAY_LEN(table) - 1, get_final, (void *)table);
FL_UNSET(obj, FL_FINALIZE);
@@ -3084,7 +3217,7 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
}
while (finalizer_table->num_entries) {
- st_foreach(finalizer_table, rb_gc_impl_shutdown_call_finalizer_i, (st_data_t)objspace);
+ st_foreach(finalizer_table, rb_gc_impl_shutdown_call_finalizer_i, 0);
}
/* run finalizers */
@@ -3188,7 +3321,7 @@ gc_setup_mark_bits(struct heap_page *page)
}
static int gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj);
-static VALUE gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, size_t slot_size);
+static VALUE gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, struct heap_page *src_page, struct heap_page *dest_page);
#if defined(_WIN32)
enum {HEAP_PAGE_LOCK = PAGE_NOACCESS, HEAP_PAGE_UNLOCK = PAGE_READWRITE};
@@ -3271,7 +3404,7 @@ try_move(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *free_page,
objspace->rcompactor.moved_count_table[BUILTIN_TYPE(src)]++;
objspace->rcompactor.total_moved++;
- gc_move(objspace, src, dest, src_page->slot_size, free_page->slot_size);
+ gc_move(objspace, src, dest, src_page, free_page);
gc_pin(objspace, src);
free_page->free_slots--;
@@ -3316,7 +3449,7 @@ read_barrier_handler(uintptr_t address)
rb_bug("read_barrier_handler: segmentation fault at %p", (void *)address);
}
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
{
unlock_page_body(objspace, page_body);
@@ -3324,7 +3457,7 @@ read_barrier_handler(uintptr_t address)
invalidate_moved_page(objspace, GET_HEAP_PAGE(address));
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
}
#endif
@@ -3509,18 +3642,35 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
{
struct heap_page *sweep_page = ctx->page;
short slot_size = sweep_page->slot_size;
- short slot_bits = slot_size / BASE_SLOT_SIZE;
- GC_ASSERT(slot_bits > 0);
do {
VALUE vp = (VALUE)p;
- GC_ASSERT(vp % BASE_SLOT_SIZE == 0);
+ GC_ASSERT(vp % sizeof(VALUE) == 0);
rb_asan_unpoison_object(vp, false);
if (bitset & 1) {
switch (BUILTIN_TYPE(vp)) {
- default: /* majority case */
- gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
+ case T_MOVED:
+ if (objspace->flags.during_compacting) {
+ /* The sweep cursor shouldn't have made it to any
+ * T_MOVED slots while the compact flag is enabled.
+ * 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");
+ }
+ gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
+ ctx->empty_slots++;
+ heap_page_add_freeobj(objspace, sweep_page, vp);
+ break;
+ case T_ZOMBIE:
+ /* already counted */
+ break;
+ case T_NONE:
+ ctx->empty_slots++; /* already freed */
+ break;
+
+ default:
#if RGENGC_CHECK_MODE
if (!is_full_marking(objspace)) {
if (RVALUE_OLD_P(objspace, vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p);
@@ -3528,8 +3678,6 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
}
#endif
- if (RVALUE_WB_UNPROTECTED(objspace, vp)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(vp), vp);
-
#if RGENGC_CHECK_MODE
#define CHECK(x) if (x(objspace, vp) != FALSE) rb_bug("obj_free: " #x "(%s) != FALSE", rb_obj_info(vp))
CHECK(RVALUE_WB_UNPROTECTED);
@@ -3539,49 +3687,37 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
#undef CHECK
#endif
- rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ);
-
- bool has_object_id = FL_TEST_RAW(vp, FL_SEEN_OBJ_ID);
- rb_gc_obj_free_vm_weak_references(vp);
- if (rb_gc_obj_free(objspace, vp)) {
- if (has_object_id) {
- obj_free_object_id(objspace, vp);
+ if (!rb_gc_obj_needs_cleanup_p(vp)) {
+ if (RB_UNLIKELY(objspace->hook_events & RUBY_INTERNAL_EVENT_FREEOBJ)) {
+ rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ);
}
- // always add free slots back to the swept pages freelist,
- // so that if we're compacting, we can re-use the slots
- (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE);
+
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, slot_size);
heap_page_add_freeobj(objspace, sweep_page, vp);
- gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
+ gc_report(3, objspace, "page_sweep: %s (fast path) added to freelist\n", rb_obj_info(vp));
ctx->freed_slots++;
}
else {
- ctx->final_slots++;
- }
- break;
+ gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
- case T_MOVED:
- if (objspace->flags.during_compacting) {
- /* The sweep cursor shouldn't have made it to any
- * T_MOVED slots while the compact flag is enabled.
- * 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_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ);
+
+ rb_gc_obj_free_vm_weak_references(vp);
+ if (rb_gc_obj_free(objspace, vp)) {
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, slot_size);
+ heap_page_add_freeobj(objspace, sweep_page, vp);
+ gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
+ ctx->freed_slots++;
+ }
+ else {
+ ctx->final_slots++;
+ }
}
- gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
- ctx->empty_slots++;
- heap_page_add_freeobj(objspace, sweep_page, vp);
- break;
- case T_ZOMBIE:
- /* already counted */
- break;
- case T_NONE:
- ctx->empty_slots++; /* already freed */
break;
}
}
p += slot_size;
- bitset >>= slot_bits;
+ bitset >>= 1;
} while (bitset);
}
@@ -3606,34 +3742,33 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
p = (uintptr_t)sweep_page->start;
bits = sweep_page->mark_bits;
+ short slot_size = sweep_page->slot_size;
+ int total_slots = sweep_page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
- int page_rvalue_count = sweep_page->total_slots * (sweep_page->slot_size / BASE_SLOT_SIZE);
- int out_of_range_bits = (NUM_IN_PAGE(p) + page_rvalue_count) % BITS_BITLENGTH;
- if (out_of_range_bits != 0) { // sizeof(RVALUE) == 64
- bits[BITMAP_INDEX(p) + page_rvalue_count / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1);
+ int out_of_range_bits = total_slots % BITS_BITLENGTH;
+ if (out_of_range_bits != 0) {
+ bits[bitmap_plane_count - 1] |= ~(((bits_t)1 << out_of_range_bits) - 1);
}
- /* The last bitmap plane may not be used if the last plane does not
- * have enough space for the slot_size. In that case, the last plane must
- * be skipped since none of the bits will be set. */
- int bitmap_plane_count = CEILDIV(NUM_IN_PAGE(p) + page_rvalue_count, BITS_BITLENGTH);
- GC_ASSERT(bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT - 1 ||
- bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT);
-
- // Skip out of range slots at the head of the page
- bitset = ~bits[0];
- bitset >>= NUM_IN_PAGE(p);
- if (bitset) {
- gc_sweep_plane(objspace, heap, p, bitset, ctx);
+ // Clear wb_unprotected and age bits for all unmarked slots
+ {
+ bits_t *wb_unprotected_bits = sweep_page->wb_unprotected_bits;
+ bits_t *age_bits = sweep_page->age_bits;
+ for (int i = 0; i < bitmap_plane_count; i++) {
+ bits_t unmarked = ~bits[i];
+ wb_unprotected_bits[i] &= ~unmarked;
+ age_bits[i * 2] &= ~unmarked;
+ age_bits[i * 2 + 1] &= ~unmarked;
+ }
}
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
- for (int i = 1; i < bitmap_plane_count; i++) {
+ for (int i = 0; i < bitmap_plane_count; i++) {
bitset = ~bits[i];
if (bitset) {
gc_sweep_plane(objspace, heap, p, bitset, ctx);
}
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ p += BITS_BITLENGTH * slot_size;
}
if (!heap->compact_cursor) {
@@ -3735,6 +3870,9 @@ static void
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);
+ if (heap->sweeping_page) {
+ objspace->sweeping_heap_count++;
+ }
heap->free_pages = NULL;
heap->pooled_pages = NULL;
if (!objspace->flags.immediate_sweep) {
@@ -3758,13 +3896,19 @@ static int compare_pinned_slots(const void *left, const void *right, void *d);
static void
gc_ractor_newobj_cache_clear(void *c, void *data)
{
+ rb_objspace_t *objspace = rb_gc_get_objspace();
rb_ractor_newobj_cache_t *newobj_cache = c;
newobj_cache->incremental_mark_step_allocated_slots = 0;
for (size_t heap_idx = 0; heap_idx < HEAP_COUNT; heap_idx++) {
+
rb_ractor_newobj_heap_cache_t *cache = &newobj_cache->heap_caches[heap_idx];
+ rb_heap_t *heap = &heaps[heap_idx];
+ RUBY_ATOMIC_SIZE_ADD(heap->total_allocated_objects, cache->allocated_objects_count);
+ cache->allocated_objects_count = 0;
+
struct heap_page *page = cache->using_page;
struct free_slot *freelist = cache->freelist;
RUBY_DEBUG_LOG("ractor using_page:%p freelist:%p", (void *)page, (void *)freelist);
@@ -3781,7 +3925,6 @@ gc_sweep_start(rb_objspace_t *objspace)
{
gc_mode_transition(objspace, gc_mode_sweeping);
objspace->rincgc.pooled_slots = 0;
- objspace->heap_pages.allocatable_slots = 0;
#if GC_CAN_COMPILE_COMPACTION
if (objspace->flags.during_compacting) {
@@ -3813,12 +3956,12 @@ gc_sweep_finish_heap(rb_objspace_t *objspace, rb_heap_t *heap)
size_t total_slots = heap->total_slots;
size_t swept_slots = heap->freed_slots + heap->empty_slots;
- size_t init_slots = gc_params.heap_init_slots[heap - heaps];
+ size_t init_slots = gc_params.heap_init_bytes / heap->slot_size;
size_t min_free_slots = (size_t)(MAX(total_slots, init_slots) * gc_params.heap_free_slots_min_ratio);
if (swept_slots < min_free_slots &&
/* The heap is a growth heap if it freed more slots than had empty slots. */
- (heap->empty_slots == 0 || heap->freed_slots > heap->empty_slots)) {
+ ((heap->empty_slots == 0 && total_slots > 0) || heap->freed_slots > heap->empty_slots)) {
/* 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
@@ -3834,12 +3977,15 @@ gc_sweep_finish_heap(rb_objspace_t *objspace, rb_heap_t *heap)
if (swept_slots < min_free_slots) {
/* Grow this heap if we are in a major GC or if we haven't run at least
- * RVALUE_OLD_AGE minor GC since the last major GC. */
+ * RVALUE_OLD_AGE minor GC since the last major GC. */
if (is_full_marking(objspace) ||
objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
- heap_allocatable_slots_expand(objspace, heap, swept_slots, heap->total_slots);
+ if (objspace->heap_pages.allocatable_bytes < min_free_slots * heap->slot_size) {
+ heap_allocatable_bytes_expand(objspace, heap, swept_slots, heap->total_slots, heap->slot_size);
+ }
}
- else {
+ else if (swept_slots < min_free_slots * 7 / 8 &&
+ objspace->heap_pages.allocatable_bytes < (min_free_slots * 7 / 8 - swept_slots) * heap->slot_size) {
gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
heap->force_major_gc_count++;
}
@@ -3875,6 +4021,13 @@ gc_sweep_finish(rb_objspace_t *objspace)
}
}
+ (void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.counters);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ if (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) {
+ (void)gc_malloc_counters_snapshot(objspace, &objspace->malloc_counters.oldcounters);
+ }
+#endif
+
rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
gc_mode_transition(objspace, gc_mode_none);
@@ -3887,9 +4040,10 @@ static int
gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
{
struct heap_page *sweep_page = heap->sweeping_page;
- int unlink_limit = GC_SWEEP_PAGES_FREEABLE_PER_STEP;
int swept_slots = 0;
int pooled_slots = 0;
+ int sweep_budget = GC_INCREMENTAL_SWEEP_BYTES / heap->slot_size;
+ int pool_budget = GC_INCREMENTAL_SWEEP_POOL_BYTES / heap->slot_size;
if (sweep_page == NULL) return FALSE;
@@ -3911,11 +4065,7 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
heap->sweeping_page = ccan_list_next(&heap->pages, sweep_page, page_node);
- if (free_slots == sweep_page->total_slots &&
- heap_pages_freeable_pages > 0 &&
- unlink_limit > 0) {
- heap_pages_freeable_pages--;
- unlink_limit--;
+ if (free_slots == sweep_page->total_slots) {
/* There are no living objects, so move this page to the global empty pages. */
heap_unlink_page(objspace, heap, sweep_page);
@@ -3939,14 +4089,14 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
heap->freed_slots += ctx.freed_slots;
heap->empty_slots += ctx.empty_slots;
- if (pooled_slots < GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT) {
+ if (pooled_slots < pool_budget) {
heap_add_poolpage(objspace, heap, sweep_page);
pooled_slots += free_slots;
}
else {
heap_add_freepage(heap, sweep_page);
swept_slots += free_slots;
- if (swept_slots > GC_INCREMENTAL_SWEEP_SLOT_COUNT) {
+ if (swept_slots > sweep_budget) {
break;
}
}
@@ -3957,6 +4107,8 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
} while ((sweep_page = heap->sweeping_page));
if (!heap->sweeping_page) {
+ objspace->sweeping_heap_count--;
+ GC_ASSERT(objspace->sweeping_heap_count >= 0);
gc_sweep_finish_heap(objspace, heap);
if (!has_sweeping_pages(objspace)) {
@@ -3993,12 +4145,29 @@ gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *sweep_heap)
for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
- if (!gc_sweep_step(objspace, heap)) {
- /* sweep_heap requires a free slot but sweeping did not yield any
- * and we cannot allocate a new page. */
- if (heap == sweep_heap && objspace->heap_pages.allocatable_slots == 0) {
+ if (gc_sweep_step(objspace, heap)) {
+ GC_ASSERT(heap->free_pages != NULL);
+ }
+ else if (heap == sweep_heap) {
+ if (objspace->empty_pages_count > 0 || objspace->heap_pages.allocatable_bytes > 0) {
+ /* [Bug #21548]
+ *
+ * If this heap is the heap we want to sweep, but we weren't able
+ * to free any slots, but we also either have empty pages or could
+ * allocate new pages, then we want to preemptively claim a page
+ * because it's possible that sweeping another heap will call
+ * gc_sweep_finish_heap, which may use up all of the
+ * empty/allocatable pages. If other heaps are not finished sweeping
+ * then we do not finish this GC and we will end up triggering a new
+ * GC cycle during this GC phase. */
+ heap_page_allocate_and_initialize(objspace, heap);
+
+ GC_ASSERT(heap->free_pages != NULL);
+ }
+ else {
/* Not allowed to create a new page so finish sweeping. */
gc_sweep_rest(objspace);
+ GC_ASSERT(gc_mode(objspace) == gc_mode_none);
break;
}
}
@@ -4042,22 +4211,13 @@ invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_
CLEAR_IN_BITMAP(GET_HEAP_PINNED_BITS(forwarding_object), forwarding_object);
object = rb_gc_impl_location(objspace, forwarding_object);
-
- uint32_t original_shape_id = 0;
- if (RB_TYPE_P(object, T_OBJECT)) {
- original_shape_id = RMOVED(forwarding_object)->original_shape_id;
- }
-
- gc_move(objspace, object, forwarding_object, GET_HEAP_PAGE(object)->slot_size, page->slot_size);
+ gc_move(objspace, object, forwarding_object, GET_HEAP_PAGE(object), page);
/* forwarding_object is now our actual object, and "object"
* is the free slot for the original page */
- if (original_shape_id) {
- rb_gc_set_shape(forwarding_object, original_shape_id);
- }
-
struct heap_page *orig_page = GET_HEAP_PAGE(object);
orig_page->free_slots++;
+ RVALUE_AGE_SET_BITMAP(object, 0);
heap_page_add_freeobj(objspace, orig_page, object);
GC_ASSERT(RVALUE_MARKED(objspace, forwarding_object));
@@ -4065,7 +4225,7 @@ invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_
GC_ASSERT(BUILTIN_TYPE(forwarding_object) != T_NONE);
}
}
- p += BASE_SLOT_SIZE;
+ p += page->slot_size;
bitset >>= 1;
} while (bitset);
}
@@ -4077,25 +4237,21 @@ invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page)
int i;
bits_t *mark_bits, *pin_bits;
bits_t bitset;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
mark_bits = page->mark_bits;
pin_bits = page->pinned_bits;
uintptr_t p = page->start;
- // Skip out of range slots at the head of the page
- bitset = pin_bits[0] & ~mark_bits[0];
- bitset >>= NUM_IN_PAGE(p);
- invalidate_moved_plane(objspace, page, p, bitset);
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (i=1; i < HEAP_PAGE_BITMAP_LIMIT; i++) {
+ for (i=0; i < bitmap_plane_count; i++) {
/* Moved objects are pinned but never marked. We reuse the pin bits
* to indicate there is a moved object in this slot. */
bitset = pin_bits[i] & ~mark_bits[i];
-
invalidate_moved_plane(objspace, page, p, bitset);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ p += BITS_BITLENGTH * slot_size;
}
}
#endif
@@ -4367,15 +4523,11 @@ init_mark_stack(mark_stack_t *stack)
static void
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 (objspace->rgengc.parent_object_old_p) {
if (RVALUE_WB_UNPROTECTED(objspace, obj) || !RVALUE_OLD_P(objspace, obj)) {
- rgengc_remember(objspace, old_parent);
+ rgengc_remember(objspace, objspace->rgengc.parent_object);
}
}
-
- GC_ASSERT(old_parent == objspace->rgengc.parent_object);
}
static inline int
@@ -4406,8 +4558,16 @@ gc_aging(rb_objspace_t *objspace, VALUE obj)
if (!RVALUE_PAGE_WB_UNPROTECTED(page, obj)) {
if (!RVALUE_OLD_P(objspace, obj)) {
- gc_report(3, objspace, "gc_aging: YOUNG: %s\n", rb_obj_info(obj));
- RVALUE_AGE_INC(objspace, obj);
+ int t = BUILTIN_TYPE(obj);
+ if (t == T_CLASS || t == T_MODULE || t == T_ICLASS) {
+ gc_report(3, objspace, "gc_aging: YOUNG class: %s\n", rb_obj_info(obj));
+ RVALUE_AGE_SET(obj, RVALUE_OLD_AGE);
+ RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
+ }
+ else {
+ gc_report(3, objspace, "gc_aging: YOUNG: %s\n", rb_obj_info(obj));
+ RVALUE_AGE_INC(objspace, obj);
+ }
}
else if (is_full_marking(objspace)) {
GC_ASSERT(RVALUE_PAGE_UNCOLLECTIBLE(page, obj) == FALSE);
@@ -4431,32 +4591,44 @@ gc_grey(rb_objspace_t *objspace, VALUE obj)
MARK_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
}
+ if (RB_FL_TEST_RAW(obj, RUBY_FL_WEAK_REFERENCE)) {
+ rb_darray_append_without_gc(&objspace->weak_references, obj);
+ }
+
push_mark_stack(&objspace->mark_stack, obj);
}
+static inline void
+gc_mark_check_t_none(rb_objspace_t *objspace, VALUE obj)
+{
+ if (RB_UNLIKELY(BUILTIN_TYPE(obj) == T_NONE)) {
+ enum {info_size = 256};
+ char obj_info_buf[info_size];
+ rb_raw_obj_info(obj_info_buf, info_size, obj);
+
+ char parent_obj_info_buf[info_size];
+ rb_raw_obj_info(parent_obj_info_buf, info_size, objspace->rgengc.parent_object);
+
+ rb_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf);
+ }
+}
+
static void
gc_mark(rb_objspace_t *objspace, VALUE obj)
{
GC_ASSERT(during_gc);
+ GC_ASSERT(!objspace->flags.during_reference_updating);
rgengc_check_relation(objspace, obj);
if (!gc_mark_set(objspace, obj)) return; /* already marked */
if (0) { // for debug GC marking miss
- if (objspace->rgengc.parent_object) {
- RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)",
- (void *)obj, obj_type_name(obj),
- (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object));
- }
- else {
- RUBY_DEBUG_LOG("%p (%s)", (void *)obj, obj_type_name(obj));
- }
+ RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)",
+ (void *)obj, obj_type_name(obj),
+ (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object));
}
- if (RB_UNLIKELY(RB_TYPE_P(obj, T_NONE))) {
- rb_obj_info_dump(obj);
- rb_bug("try to mark T_NONE object"); /* check here will help debugging */
- }
+ gc_mark_check_t_none(objspace, obj);
gc_aging(objspace, obj);
gc_grey(objspace, obj);
@@ -4493,7 +4665,10 @@ rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
GC_ASSERT(objspace->flags.during_compacting);
GC_ASSERT(during_gc);
- *ptr = rb_gc_impl_location(objspace, *ptr);
+ VALUE destination = rb_gc_impl_location(objspace, *ptr);
+ if (destination != *ptr) {
+ *ptr = destination;
+ }
}
else {
gc_mark(objspace, *ptr);
@@ -4527,10 +4702,10 @@ rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
asan_unpoisoning_object(obj) {
/* Garbage can live on the stack, so do not mark or pin */
switch (BUILTIN_TYPE(obj)) {
- case T_ZOMBIE:
- case T_NONE:
+ case T_ZOMBIE:
+ case T_NONE:
break;
- default:
+ default:
gc_mark_and_pin(objspace, obj);
break;
}
@@ -4538,64 +4713,34 @@ rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
}
}
-void
-rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
+static int
+pin_value(st_data_t key, st_data_t value, st_data_t data)
{
- rb_objspace_t *objspace = objspace_ptr;
-
- GC_ASSERT(objspace->rgengc.parent_object == 0 || FL_TEST(objspace->rgengc.parent_object, FL_WB_PROTECTED));
-
- VALUE obj = *ptr;
-
- if (RB_UNLIKELY(RB_TYPE_P(obj, T_NONE))) {
- rb_obj_info_dump(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 references list. */
- if (!is_full_marking(objspace) && RVALUE_OLD_P(objspace, obj)) {
- GC_ASSERT(RVALUE_MARKED(objspace, obj));
- GC_ASSERT(!objspace->flags.during_compacting);
-
- return;
- }
-
- rgengc_check_relation(objspace, obj);
-
- rb_darray_append_without_gc(&objspace->weak_references, ptr);
+ rb_gc_impl_mark_and_pin((void *)data, (VALUE)value);
- objspace->profile.weak_references_count++;
+ return ST_CONTINUE;
}
-void
-rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr)
+static inline void
+gc_mark_set_parent_raw(rb_objspace_t *objspace, VALUE obj, bool old_p)
{
- rb_objspace_t *objspace = objspace_ptr;
-
- /* 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(objspace, parent_obj)) return;
-
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (*ptr_ptr == ptr) {
- *ptr_ptr = NULL;
- break;
- }
- }
+ asan_unpoison_memory_region(&objspace->rgengc.parent_object, sizeof(objspace->rgengc.parent_object), false);
+ asan_unpoison_memory_region(&objspace->rgengc.parent_object_old_p, sizeof(objspace->rgengc.parent_object_old_p), false);
+ objspace->rgengc.parent_object = obj;
+ objspace->rgengc.parent_object_old_p = old_p;
}
-static int
-pin_value(st_data_t key, st_data_t value, st_data_t data)
+static inline void
+gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
{
- rb_gc_impl_mark_and_pin((void *)data, (VALUE)value);
+ gc_mark_set_parent_raw(objspace, obj, RVALUE_OLD_P(objspace, obj));
+}
- return ST_CONTINUE;
+static inline void
+gc_mark_set_parent_invalid(rb_objspace_t *objspace)
+{
+ asan_poison_memory_region(&objspace->rgengc.parent_object, sizeof(objspace->rgengc.parent_object));
+ asan_poison_memory_region(&objspace->rgengc.parent_object_old_p, sizeof(objspace->rgengc.parent_object_old_p));
}
static void
@@ -4606,29 +4751,17 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp)
} while (0)
MARK_CHECKPOINT("objspace");
- objspace->rgengc.parent_object = Qfalse;
+ gc_mark_set_parent_raw(objspace, Qundef, false);
if (finalizer_table != NULL) {
st_foreach(finalizer_table, pin_value, (st_data_t)objspace);
}
- st_foreach(objspace->obj_to_id_tbl, gc_mark_tbl_no_pin_i, (st_data_t)objspace);
-
if (stress_to_class) rb_gc_mark(stress_to_class);
rb_gc_save_machine_context();
rb_gc_mark_roots(objspace, categoryp);
-}
-
-static inline void
-gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
-{
- if (RVALUE_OLD_P(objspace, obj)) {
- objspace->rgengc.parent_object = obj;
- }
- else {
- objspace->rgengc.parent_object = Qfalse;
- }
+ gc_mark_set_parent_invalid(objspace);
}
static void
@@ -4636,6 +4769,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
{
gc_mark_set_parent(objspace, obj);
rb_gc_mark_children(objspace, obj);
+ gc_mark_set_parent_invalid(objspace);
}
/**
@@ -4921,10 +5055,22 @@ gc_check_after_marks_i(st_data_t k, st_data_t v, st_data_t ptr)
static void
gc_marks_check(rb_objspace_t *objspace, st_foreach_callback_func *checker_func, const char *checker_name)
{
- size_t saved_malloc_increase = objspace->malloc_params.increase;
+ MALLOC_COUNTERS_LOCK(objspace);
+ struct gc_malloc_bytes saved_malloc = {
+ .malloc = gc_counter_load_relaxed(&objspace->malloc_counters.counters.malloc),
+ .free = gc_counter_load_relaxed(&objspace->malloc_counters.counters.free),
+ .malloc_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.counters.malloc_at_last_gc),
+ .free_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.counters.free_at_last_gc),
+ };
#if RGENGC_ESTIMATE_OLDMALLOC
- size_t saved_oldmalloc_increase = objspace->rgengc.oldmalloc_increase;
+ struct gc_malloc_bytes saved_oldmalloc = {
+ .malloc = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.malloc),
+ .free = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.free),
+ .malloc_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.malloc_at_last_gc),
+ .free_at_last_gc = gc_counter_load_relaxed(&objspace->malloc_counters.oldcounters.free_at_last_gc),
+ };
#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
VALUE already_disabled = rb_objspace_gc_disable(objspace);
objspace->rgengc.allrefs_table = objspace_allrefs(objspace);
@@ -4944,10 +5090,18 @@ gc_marks_check(rb_objspace_t *objspace, st_foreach_callback_func *checker_func,
objspace->rgengc.allrefs_table = 0;
if (already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
- objspace->malloc_params.increase = saved_malloc_increase;
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_store_release(&objspace->malloc_counters.counters.malloc, saved_malloc.malloc);
+ gc_counter_store_release(&objspace->malloc_counters.counters.free, saved_malloc.free);
+ gc_counter_store_release(&objspace->malloc_counters.counters.malloc_at_last_gc, saved_malloc.malloc_at_last_gc);
+ gc_counter_store_release(&objspace->malloc_counters.counters.free_at_last_gc, saved_malloc.free_at_last_gc);
#if RGENGC_ESTIMATE_OLDMALLOC
- objspace->rgengc.oldmalloc_increase = saved_oldmalloc_increase;
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.malloc, saved_oldmalloc.malloc);
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.free, saved_oldmalloc.free);
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.malloc_at_last_gc, saved_oldmalloc.malloc_at_last_gc);
+ gc_counter_store_release(&objspace->malloc_counters.oldcounters.free_at_last_gc, saved_oldmalloc.free_at_last_gc);
#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
}
#endif /* RGENGC_CHECK_MODE >= 4 */
@@ -5036,6 +5190,10 @@ verify_internal_consistency_i(void *page_start, void *page_end, size_t stride,
rb_objspace_reachable_objects_from(obj, check_generation_i, (void *)data);
}
+ if (!is_marking(objspace) && rb_gc_obj_shareable_p(obj)) {
+ rb_gc_verify_shareable(obj);
+ }
+
if (is_incremental_marking(objspace)) {
if (RVALUE_BLACK_P(objspace, obj)) {
/* reachable objects from black objects should be black or grey objects */
@@ -5201,6 +5359,8 @@ gc_verify_internal_consistency_(rb_objspace_t *objspace)
/* check counters */
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+
if (!is_lazy_sweeping(objspace) &&
!finalizing &&
!rb_gc_multi_ractor_p()) {
@@ -5255,7 +5415,7 @@ gc_verify_internal_consistency(void *objspace_ptr)
{
rb_objspace_t *objspace = objspace_ptr;
- unsigned int lev = rb_gc_vm_lock();
+ unsigned int lev = RB_GC_VM_LOCK();
{
rb_gc_vm_barrier(); // stop other ractors
@@ -5266,7 +5426,7 @@ gc_verify_internal_consistency(void *objspace_ptr)
}
during_gc = prev_during_gc;
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
}
static void
@@ -5313,7 +5473,7 @@ gc_remember_unprotected(rb_objspace_t *objspace, VALUE obj)
}
static inline void
-gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits)
+gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits, short slot_size)
{
if (bits) {
do {
@@ -5323,7 +5483,7 @@ gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits
GC_ASSERT(RVALUE_MARKED(objspace, (VALUE)p));
gc_mark_children(objspace, (VALUE)p);
}
- p += BASE_SLOT_SIZE;
+ p += slot_size;
bits >>= 1;
} while (bits);
}
@@ -5338,48 +5498,63 @@ gc_marks_wb_unprotected_objects(rb_objspace_t *objspace, rb_heap_t *heap)
bits_t *mark_bits = page->mark_bits;
bits_t *wbun_bits = page->wb_unprotected_bits;
uintptr_t p = page->start;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
size_t j;
- bits_t bits = mark_bits[0] & wbun_bits[0];
- bits >>= NUM_IN_PAGE(p);
- gc_marks_wb_unprotected_objects_plane(objspace, p, bits);
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (j=1; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
+ for (j=0; j<(size_t)bitmap_plane_count; j++) {
bits_t bits = mark_bits[j] & wbun_bits[j];
-
- gc_marks_wb_unprotected_objects_plane(objspace, p, bits);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ gc_marks_wb_unprotected_objects_plane(objspace, p, bits, slot_size);
+ p += BITS_BITLENGTH * slot_size;
}
}
gc_mark_stacked_objects_all(objspace);
}
-static void
-gc_update_weak_references(rb_objspace_t *objspace)
+void
+rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
{
- size_t retained_weak_references_count = 0;
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (!*ptr_ptr) continue;
+ FL_SET_RAW(obj, RUBY_FL_WEAK_REFERENCE);
+}
- VALUE obj = **ptr_ptr;
+bool
+rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
+{
+ rb_objspace_t *objspace = objspace_ptr;
- if (RB_SPECIAL_CONST_P(obj)) continue;
+ bool marked = RVALUE_MARKED(objspace, obj);
- if (!RVALUE_MARKED(objspace, obj)) {
- **ptr_ptr = Qundef;
- }
- else {
- retained_weak_references_count++;
- }
+ if (marked) {
+ rgengc_check_relation(objspace, obj);
+ }
+
+ return marked;
+}
+
+static void
+gc_update_weak_references(rb_objspace_t *objspace)
+{
+ VALUE *obj_ptr;
+ rb_darray_foreach(objspace->weak_references, i, obj_ptr) {
+ gc_mark_set_parent(objspace, *obj_ptr);
+ rb_gc_handle_weak_references(*obj_ptr);
+ gc_mark_set_parent_invalid(objspace);
}
- objspace->profile.retained_weak_references_count = retained_weak_references_count;
+ size_t capa = rb_darray_capa(objspace->weak_references);
+ size_t size = rb_darray_size(objspace->weak_references);
+
+ objspace->profile.weak_references_count = size;
rb_darray_clear(objspace->weak_references);
- rb_darray_resize_capa_without_gc(&objspace->weak_references, retained_weak_references_count);
+
+ /* If the darray has capacity for more than four times the amount used, we
+ * shrink it down to half of that capacity. */
+ if (capa > size * 4) {
+ rb_darray_resize_capa_without_gc(&objspace->weak_references, size * 2);
+ }
}
static void
@@ -5438,22 +5613,27 @@ gc_marks_finish(rb_objspace_t *objspace)
/* Setup freeable slots. */
size_t total_init_slots = 0;
for (int i = 0; i < HEAP_COUNT; i++) {
- total_init_slots += gc_params.heap_init_slots[i] * r_mul;
+ total_init_slots += (gc_params.heap_init_bytes / heaps[i].slot_size) * r_mul;
}
if (max_free_slots < total_init_slots) {
max_free_slots = total_init_slots;
}
+ /* Approximate freeable pages using the average slots-per-pages across all heaps */
if (sweep_slots > max_free_slots) {
- heap_pages_freeable_pages = (sweep_slots - max_free_slots) / HEAP_PAGE_OBJ_LIMIT;
+ size_t excess_slots = sweep_slots - max_free_slots;
+ size_t total_heap_pages = heap_eden_total_pages(objspace);
+ heap_pages_freeable_pages = total_heap_pages > 0
+ ? excess_slots * total_heap_pages / total_slots
+ : 0;
}
else {
heap_pages_freeable_pages = 0;
}
- if (objspace->heap_pages.allocatable_slots == 0 && sweep_slots < min_free_slots) {
- if (!full_marking) {
+ if (objspace->heap_pages.allocatable_bytes == 0 && sweep_slots < min_free_slots) {
+ if (!full_marking && sweep_slots < min_free_slots * 7 / 8) {
if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
full_marking = TRUE;
}
@@ -5462,6 +5642,10 @@ gc_marks_finish(rb_objspace_t *objspace)
gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
}
}
+
+ if (full_marking) {
+ heap_allocatable_bytes_expand(objspace, NULL, sweep_slots, total_slots, heaps[0].slot_size);
+ }
}
if (full_marking) {
@@ -5483,8 +5667,8 @@ gc_marks_finish(rb_objspace_t *objspace)
gc_report(1, objspace, "gc_marks_finish (marks %"PRIdSIZE" objects, "
"old %"PRIdSIZE" objects, total %"PRIdSIZE" slots, "
- "sweep %"PRIdSIZE" slots, allocatable %"PRIdSIZE" slots, next GC: %s)\n",
- objspace->marked_slots, objspace->rgengc.old_objects, objspace_available_slots(objspace), sweep_slots, objspace->heap_pages.allocatable_slots,
+ "sweep %"PRIdSIZE" slots, allocatable %"PRIdSIZE" bytes, next GC: %s)\n",
+ objspace->marked_slots, objspace->rgengc.old_objects, objspace_available_slots(objspace), sweep_slots, objspace->heap_pages.allocatable_bytes,
gc_needs_major_flags ? "major" : "minor");
}
@@ -5509,10 +5693,9 @@ gc_compact_destination_pool(rb_objspace_t *objspace, rb_heap_t *src_pool, VALUE
return src_pool;
}
- size_t idx = 0;
- if (rb_gc_impl_size_allocatable_p(obj_size)) {
- idx = heap_idx_for_size(obj_size);
- }
+ GC_ASSERT(rb_gc_impl_size_allocatable_p(obj_size));
+
+ size_t idx = heap_idx_for_size(obj_size);
return &heaps[idx];
}
@@ -5524,25 +5707,10 @@ gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, VALUE src)
GC_ASSERT(gc_is_moveable_obj(objspace, src));
rb_heap_t *dest_pool = gc_compact_destination_pool(objspace, heap, src);
- uint32_t orig_shape = 0;
- uint32_t new_shape = 0;
-
if (gc_compact_heap_cursors_met_p(dest_pool)) {
return dest_pool != heap;
}
- if (RB_TYPE_P(src, T_OBJECT)) {
- orig_shape = rb_gc_get_shape(src);
-
- if (dest_pool != heap) {
- new_shape = rb_gc_rebuild_shape(src, dest_pool - heaps);
-
- if (new_shape == 0) {
- dest_pool = heap;
- }
- }
- }
-
while (!try_move(objspace, dest_pool, dest_pool->free_pages, src)) {
struct gc_sweep_context ctx = {
.page = dest_pool->sweeping_page,
@@ -5568,14 +5736,6 @@ gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, VALUE src)
}
}
- if (orig_shape != 0) {
- if (new_shape != 0) {
- VALUE dest = rb_gc_impl_location(objspace, src);
- rb_gc_set_shape(dest, new_shape);
- }
- RMOVED(src)->original_shape_id = orig_shape;
- }
-
return true;
}
@@ -5583,12 +5743,10 @@ static bool
gc_compact_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct heap_page *page)
{
short slot_size = page->slot_size;
- short slot_bits = slot_size / BASE_SLOT_SIZE;
- GC_ASSERT(slot_bits > 0);
do {
VALUE vp = (VALUE)p;
- GC_ASSERT(vp % BASE_SLOT_SIZE == 0);
+ GC_ASSERT(vp % sizeof(VALUE) == 0);
if (bitset & 1) {
objspace->rcompactor.considered_count_table[BUILTIN_TYPE(vp)]++;
@@ -5601,7 +5759,7 @@ gc_compact_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t b
}
}
p += slot_size;
- bitset >>= slot_bits;
+ bitset >>= 1;
} while (bitset);
return true;
@@ -5616,26 +5774,21 @@ gc_compact_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page
bits_t *mark_bits, *pin_bits;
bits_t bitset;
uintptr_t p = page->start;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
mark_bits = page->mark_bits;
pin_bits = page->pinned_bits;
- // objects that can be moved are marked and not pinned
- bitset = (mark_bits[0] & ~pin_bits[0]);
- bitset >>= NUM_IN_PAGE(p);
- if (bitset) {
- if (!gc_compact_plane(objspace, heap, (uintptr_t)p, bitset, page))
- return false;
- }
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (int j = 1; j < HEAP_PAGE_BITMAP_LIMIT; j++) {
+ for (int j = 0; j < bitmap_plane_count; j++) {
+ // objects that can be moved are marked and not pinned
bitset = (mark_bits[j] & ~pin_bits[j]);
if (bitset) {
if (!gc_compact_plane(objspace, heap, (uintptr_t)p, bitset, page))
return false;
}
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ p += BITS_BITLENGTH * slot_size;
}
return true;
@@ -5812,7 +5965,6 @@ gc_marks_start(rb_objspace_t *objspace, int full_mark)
static bool
gc_marks(rb_objspace_t *objspace, int full_mark)
{
- gc_prof_mark_timer_start(objspace);
gc_marking_enter(objspace);
bool marking_finished = false;
@@ -5833,7 +5985,6 @@ gc_marks(rb_objspace_t *objspace, int full_mark)
#endif
gc_marking_exit(objspace);
- gc_prof_mark_timer_stop(objspace);
return marking_finished;
}
@@ -5922,7 +6073,7 @@ rgengc_remember(rb_objspace_t *objspace, VALUE obj)
#endif
static inline void
-rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitset)
+rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitset, short slot_size)
{
if (bitset) {
do {
@@ -5933,8 +6084,12 @@ rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitse
GC_ASSERT(RVALUE_OLD_P(objspace, obj) || RVALUE_WB_UNPROTECTED(objspace, obj));
gc_mark_children(objspace, obj);
+
+ if (RB_FL_TEST_RAW(obj, RUBY_FL_WEAK_REFERENCE)) {
+ rb_darray_append_without_gc(&objspace->weak_references, obj);
+ }
}
- p += BASE_SLOT_SIZE;
+ p += slot_size;
bitset >>= 1;
} while (bitset);
}
@@ -5953,6 +6108,9 @@ rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
ccan_list_for_each(&heap->pages, page, page_node) {
if (page->flags.has_remembered_objects | page->flags.has_uncollectible_wb_unprotected_objects) {
uintptr_t p = page->start;
+ short slot_size = page->slot_size;
+ int total_slots = page->total_slots;
+ int bitmap_plane_count = CEILDIV(total_slots, BITS_BITLENGTH);
bits_t bitset, bits[HEAP_PAGE_BITMAP_LIMIT];
bits_t *remembered_bits = page->remembered_bits;
bits_t *uncollectible_bits = page->uncollectible_bits;
@@ -5962,21 +6120,16 @@ rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
else if (page->flags.has_remembered_objects) has_old++;
else if (page->flags.has_uncollectible_wb_unprotected_objects) has_shady++;
#endif
- for (j=0; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
+ for (j=0; j < (size_t)bitmap_plane_count; j++) {
bits[j] = remembered_bits[j] | (uncollectible_bits[j] & wb_unprotected_bits[j]);
remembered_bits[j] = 0;
}
page->flags.has_remembered_objects = FALSE;
- bitset = bits[0];
- bitset >>= NUM_IN_PAGE(p);
- rgengc_rememberset_mark_plane(objspace, p, bitset);
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (j=1; j < HEAP_PAGE_BITMAP_LIMIT; j++) {
+ for (j=0; j < (size_t)bitmap_plane_count; j++) {
bitset = bits[j];
- rgengc_rememberset_mark_plane(objspace, p, bitset);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ rgengc_rememberset_mark_plane(objspace, p, bitset, slot_size);
+ p += BITS_BITLENGTH * slot_size;
}
}
#if PROFILE_REMEMBERSET_MARK
@@ -6023,11 +6176,11 @@ gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace)
/* mark `a' and remember (default behavior) */
if (!RVALUE_REMEMBERED(objspace, a)) {
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
rgengc_remember(objspace, a);
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
gc_report(1, objspace, "gc_writebarrier_generational: %s (remembered) -> %s\n", rb_obj_info(a), rb_obj_info(b));
}
@@ -6041,9 +6194,11 @@ gc_mark_from(rb_objspace_t *objspace, VALUE obj, VALUE parent)
{
gc_mark_set_parent(objspace, parent);
rgengc_check_relation(objspace, obj);
- if (gc_mark_set(objspace, obj) == FALSE) return;
- gc_aging(objspace, obj);
- gc_grey(objspace, obj);
+ if (gc_mark_set(objspace, obj) != FALSE) {
+ gc_aging(objspace, obj);
+ gc_grey(objspace, obj);
+ }
+ gc_mark_set_parent_invalid(objspace);
}
NOINLINE(static void gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace));
@@ -6075,11 +6230,15 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
{
rb_objspace_t *objspace = objspace_ptr;
- if (RGENGC_CHECK_MODE) {
- if (SPECIAL_CONST_P(a)) rb_bug("rb_gc_writebarrier: a is special const: %"PRIxVALUE, a);
- if (SPECIAL_CONST_P(b)) rb_bug("rb_gc_writebarrier: b is special const: %"PRIxVALUE, b);
- }
+#if RGENGC_CHECK_MODE
+ if (SPECIAL_CONST_P(a)) rb_bug("rb_gc_writebarrier: a is special const: %"PRIxVALUE, a);
+ if (SPECIAL_CONST_P(b)) rb_bug("rb_gc_writebarrier: b is special const: %"PRIxVALUE, b);
+#else
+ RBIMPL_ASSERT_OR_ASSUME(!SPECIAL_CONST_P(a));
+ RBIMPL_ASSERT_OR_ASSUME(!SPECIAL_CONST_P(b));
+#endif
+ GC_ASSERT(!during_gc);
GC_ASSERT(RB_BUILTIN_TYPE(a) != T_NONE);
GC_ASSERT(RB_BUILTIN_TYPE(a) != T_MOVED);
GC_ASSERT(RB_BUILTIN_TYPE(a) != T_ZOMBIE);
@@ -6099,7 +6258,7 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
else {
bool retry = false;
/* slow path */
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
if (is_incremental_marking(objspace)) {
gc_writebarrier_incremental(a, b, objspace);
@@ -6108,7 +6267,7 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
retry = true;
}
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
if (retry) goto retry;
}
@@ -6127,7 +6286,7 @@ rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
gc_report(2, objspace, "rb_gc_writebarrier_unprotect: %s %s\n", rb_obj_info(obj),
RVALUE_REMEMBERED(objspace, obj) ? " (already remembered)" : "");
- unsigned int lev = rb_gc_vm_lock_no_barrier();
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
if (RVALUE_OLD_P(objspace, obj)) {
gc_report(1, objspace, "rb_gc_writebarrier_unprotect: %s\n", rb_obj_info(obj));
@@ -6149,7 +6308,7 @@ rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_wb_unprotect);
MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
}
}
@@ -6177,19 +6336,29 @@ rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
gc_report(1, objspace, "rb_gc_writebarrier_remember: %s\n", rb_obj_info(obj));
- if (is_incremental_marking(objspace)) {
- if (RVALUE_BLACK_P(objspace, obj)) {
- gc_grey(objspace, obj);
- }
- }
- else {
- if (RVALUE_OLD_P(objspace, obj)) {
- rgengc_remember(objspace, obj);
+ if (is_incremental_marking(objspace) || RVALUE_OLD_P(objspace, obj)) {
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
+ {
+ if (is_incremental_marking(objspace)) {
+ if (RVALUE_BLACK_P(objspace, obj)) {
+ gc_grey(objspace, obj);
+ }
+ }
+ else if (RVALUE_OLD_P(objspace, obj)) {
+ rgengc_remember(objspace, obj);
+ }
}
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
}
}
-#define RB_GC_OBJECT_METADATA_ENTRY_COUNT 7
+struct rb_gc_object_metadata_names {
+ // Must be ID only
+ ID ID_wb_protected, ID_age, ID_old, ID_uncollectible, ID_marking,
+ ID_marked, ID_pinned, ID_remembered, ID_object_id, ID_shareable;
+};
+
+#define RB_GC_OBJECT_METADATA_ENTRY_COUNT (sizeof(struct rb_gc_object_metadata_names) / sizeof(ID))
static struct rb_gc_object_metadata_entry object_metadata_entries[RB_GC_OBJECT_METADATA_ENTRY_COUNT + 1];
struct rb_gc_object_metadata_entry *
@@ -6197,10 +6366,10 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
{
rb_objspace_t *objspace = objspace_ptr;
size_t n = 0;
- static ID ID_wb_protected, ID_age, ID_old, ID_uncollectible, ID_marking, ID_marked, ID_pinned, ID_object_id;
+ static struct rb_gc_object_metadata_names names;
- if (!ID_marked) {
-#define I(s) ID_##s = rb_intern(#s);
+ if (!names.ID_marked) {
+#define I(s) names.ID_##s = rb_intern(#s)
I(wb_protected);
I(age);
I(old);
@@ -6208,13 +6377,15 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
I(marking);
I(marked);
I(pinned);
+ I(remembered);
I(object_id);
+ I(shareable);
#undef I
}
#define SET_ENTRY(na, v) do { \
GC_ASSERT(n <= RB_GC_OBJECT_METADATA_ENTRY_COUNT); \
- object_metadata_entries[n].name = ID_##na; \
+ object_metadata_entries[n].name = names.ID_##na; \
object_metadata_entries[n].val = v; \
n++; \
} while (0)
@@ -6226,7 +6397,9 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
if (RVALUE_MARKING(objspace, obj)) SET_ENTRY(marking, Qtrue);
if (RVALUE_MARKED(objspace, obj)) SET_ENTRY(marked, Qtrue);
if (RVALUE_PINNED(objspace, obj)) SET_ENTRY(pinned, Qtrue);
- if (FL_TEST(obj, FL_SEEN_OBJ_ID)) SET_ENTRY(object_id, rb_obj_id(obj));
+ if (RVALUE_REMEMBERED(objspace, obj)) SET_ENTRY(remembered, Qtrue);
+ if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));
+ if (FL_TEST(obj, FL_SHAREABLE)) SET_ENTRY(shareable, Qtrue);
object_metadata_entries[n].name = 0;
object_metadata_entries[n].val = 0;
@@ -6251,7 +6424,6 @@ rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache)
rb_objspace_t *objspace = objspace_ptr;
objspace->live_ractor_cache_count--;
-
gc_ractor_newobj_cache_clear(cache, NULL);
free(cache);
}
@@ -6261,7 +6433,7 @@ heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap)
{
if (!heap->free_pages) {
if (!heap_page_allocate_and_initialize(objspace, heap)) {
- objspace->heap_pages.allocatable_slots = 1;
+ objspace->heap_pages.allocatable_bytes = HEAP_PAGE_SIZE;
heap_page_allocate_and_initialize(objspace, heap);
}
}
@@ -6287,11 +6459,14 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
{
gc_prof_set_malloc_info(objspace);
{
- size_t inc = RUBY_ATOMIC_SIZE_EXCHANGE(malloc_increase, 0);
+ int64_t inc = gc_malloc_counters_increase(objspace, &objspace->malloc_counters.counters);
size_t old_limit = malloc_limit;
- if (inc > malloc_limit) {
- malloc_limit = (size_t)(inc * gc_params.malloc_limit_growth_factor);
+ /* A net-negative `inc` (more freed than malloc'd since last GC) is
+ * treated the same as "allocated less than malloc_limit".
+ * This matches what we were doing pre-monotonic counters, but is it right? */
+ if (inc > 0 && (size_t)inc > malloc_limit) {
+ malloc_limit = (size_t)((size_t)inc * gc_params.malloc_limit_growth_factor);
if (malloc_limit > gc_params.malloc_limit_max) {
malloc_limit = gc_params.malloc_limit_max;
}
@@ -6318,7 +6493,11 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
/* reset oldmalloc info */
#if RGENGC_ESTIMATE_OLDMALLOC
if (!full_mark) {
- if (objspace->rgengc.oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
+ /* Don't snapshot on minor GC: oldmalloc_increase is meant to
+ * accumulate across minor GCs and only reset at major GC. */
+ int64_t oldmalloc_increase = gc_malloc_counters_increase(objspace, &objspace->malloc_counters.oldcounters);
+ if (oldmalloc_increase > 0 &&
+ (uint64_t)oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_OLDMALLOC;
objspace->rgengc.oldmalloc_increase_limit =
(size_t)(objspace->rgengc.oldmalloc_increase_limit * gc_params.oldmalloc_limit_growth_factor);
@@ -6328,17 +6507,14 @@ gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
}
}
- if (0) fprintf(stderr, "%"PRIdSIZE"\t%d\t%"PRIuSIZE"\t%"PRIuSIZE"\t%"PRIdSIZE"\n",
+ if (0) fprintf(stderr, "%"PRIdSIZE"\t%d\t%"PRId64"\t%"PRIuSIZE"\t%"PRIdSIZE"\n",
rb_gc_count(),
gc_needs_major_flags,
- objspace->rgengc.oldmalloc_increase,
+ oldmalloc_increase,
objspace->rgengc.oldmalloc_increase_limit,
gc_params.oldmalloc_limit_max);
}
else {
- /* major GC */
- objspace->rgengc.oldmalloc_increase = 0;
-
if ((objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_BY_OLDMALLOC) == 0) {
objspace->rgengc.oldmalloc_increase_limit =
(size_t)(objspace->rgengc.oldmalloc_increase_limit / ((gc_params.oldmalloc_limit_growth_factor - 1)/10 + 1));
@@ -6355,7 +6531,7 @@ garbage_collect(rb_objspace_t *objspace, unsigned int reason)
{
int ret;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
{
#if GC_PROFILE_MORE_DETAIL
objspace->profile.prepare_time = getrusage_time();
@@ -6369,7 +6545,7 @@ garbage_collect(rb_objspace_t *objspace, unsigned int reason)
ret = gc_start(objspace, reason);
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
return ret;
}
@@ -6379,19 +6555,21 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
{
unsigned int do_full_mark = !!(reason & GPR_FLAG_FULL_MARK);
- /* reason may be clobbered, later, so keep set immediate_sweep here */
- objspace->flags.immediate_sweep = !!(reason & GPR_FLAG_IMMEDIATE_SWEEP);
-
if (!rb_darray_size(objspace->heap_pages.sorted)) return TRUE; /* heap is not ready */
if (!(reason & GPR_FLAG_METHOD) && !ready_to_gc(objspace)) return TRUE; /* GC is not allowed */
- GC_ASSERT(gc_mode(objspace) == gc_mode_none);
+ rb_gc_initialize_vm_context(&objspace->vm_context);
+
+ GC_ASSERT(gc_mode(objspace) == gc_mode_none, "gc_mode is %s\n", gc_mode_name(gc_mode(objspace)));
GC_ASSERT(!is_lazy_sweeping(objspace));
GC_ASSERT(!is_incremental_marking(objspace));
unsigned int lock_lev;
gc_enter(objspace, gc_enter_event_start, &lock_lev);
+ /* reason may be clobbered, later, so keep set immediate_sweep here */
+ objspace->flags.immediate_sweep = !!(reason & GPR_FLAG_IMMEDIATE_SWEEP);
+
#if RGENGC_CHECK_MODE >= 2
gc_verify_internal_consistency(objspace);
#endif
@@ -6451,7 +6629,6 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
reason,
do_full_mark, !is_incremental_marking(objspace), objspace->flags.immediate_sweep);
-#if USE_DEBUG_COUNTER
RB_DEBUG_COUNTER_INC(gc_count);
if (reason & GPR_FLAG_MAJOR_MASK) {
@@ -6470,14 +6647,13 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
(void)RB_DEBUG_COUNTER_INC_IF(gc_minor_capi, reason & GPR_FLAG_CAPI);
(void)RB_DEBUG_COUNTER_INC_IF(gc_minor_stress, reason & GPR_FLAG_STRESS);
}
-#endif
objspace->profile.count++;
objspace->profile.latest_gc_info = reason;
objspace->profile.total_allocated_objects_at_gc_start = total_allocated_objects(objspace);
objspace->profile.heap_used_at_gc_start = rb_darray_size(objspace->heap_pages.sorted);
+ objspace->profile.heap_total_slots_at_gc_start = objspace_available_slots(objspace);
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);
@@ -6655,12 +6831,10 @@ gc_clock_end(struct timespec *ts)
static inline void
gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev)
{
- *lock_lev = rb_gc_vm_lock();
+ *lock_lev = RB_GC_VM_LOCK();
switch (event) {
case gc_enter_event_rest:
- if (!is_marking(objspace)) break;
- // fall through
case gc_enter_event_start:
case gc_enter_event_continue:
// stop other ractors
@@ -6694,7 +6868,7 @@ gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_l
gc_report(1, objspace, "gc_exit: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
during_gc = FALSE;
- rb_gc_vm_unlock(*lock_lev);
+ RB_GC_VM_UNLOCK(*lock_lev);
}
#ifndef MEASURE_GC
@@ -6706,9 +6880,13 @@ gc_marking_enter(rb_objspace_t *objspace)
{
GC_ASSERT(during_gc != 0);
+ gc_prof_mark_timer_start(objspace);
+
if (MEASURE_GC) {
gc_clock_start(&objspace->profile.marking_start_time);
}
+
+ rb_gc_initialize_vm_context(&objspace->vm_context);
}
static void
@@ -6719,6 +6897,8 @@ gc_marking_exit(rb_objspace_t *objspace)
if (MEASURE_GC) {
objspace->profile.marking_time_ns += gc_clock_end(&objspace->profile.marking_start_time);
}
+
+ gc_prof_mark_timer_stop(objspace);
}
static void
@@ -6833,7 +7013,7 @@ rb_gc_impl_prepare_heap(void *objspace_ptr)
rb_objspace_t *objspace = objspace_ptr;
size_t orig_total_slots = objspace_available_slots(objspace);
- size_t orig_allocatable_slots = objspace->heap_pages.allocatable_slots;
+ size_t orig_allocatable_bytes = objspace->heap_pages.allocatable_bytes;
rb_gc_impl_each_objects(objspace, gc_set_candidate_object_i, objspace_ptr);
@@ -6843,14 +7023,16 @@ rb_gc_impl_prepare_heap(void *objspace_ptr)
rb_gc_impl_start(objspace, true, true, true, true);
gc_params.heap_free_slots_max_ratio = orig_max_free_slots;
- objspace->heap_pages.allocatable_slots = 0;
+ objspace->heap_pages.allocatable_bytes = 0;
+ heap_pages_freeable_pages = objspace->empty_pages_count;
heap_pages_free_unused_pages(objspace_ptr);
+ GC_ASSERT(heap_pages_freeable_pages == 0);
GC_ASSERT(objspace->empty_pages_count == 0);
- objspace->heap_pages.allocatable_slots = orig_allocatable_slots;
+ objspace->heap_pages.allocatable_bytes = orig_allocatable_bytes;
size_t total_slots = objspace_available_slots(objspace);
if (orig_total_slots > total_slots) {
- objspace->heap_pages.allocatable_slots += orig_total_slots - total_slots;
+ objspace->heap_pages.allocatable_bytes += (orig_total_slots - total_slots) * heaps[0].slot_size;
}
#if defined(HAVE_MALLOC_TRIM) && !defined(RUBY_ALTERNATIVE_MALLOC_HEADER)
@@ -6869,12 +7051,6 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
case T_ZOMBIE:
return FALSE;
case T_SYMBOL:
- // TODO: restore original behavior
- // if (RSYMBOL(obj)->id & ~ID_SCOPE_MASK) {
- // return FALSE;
- // }
- return false;
- /* fall through */
case T_STRING:
case T_OBJECT:
case T_FLOAT:
@@ -6919,8 +7095,11 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
void rb_mv_generic_ivar(VALUE src, VALUE dst);
static VALUE
-gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, size_t src_slot_size, size_t slot_size)
+gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, struct heap_page *src_page, struct heap_page *dest_page)
{
+ size_t src_slot_size = src_page->slot_size;
+ size_t slot_size = dest_page->slot_size;
+
int marked;
int wb_unprotected;
int uncollectible;
@@ -6946,30 +7125,13 @@ gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, size_t src_slot_size, si
CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(src), src);
CLEAR_IN_BITMAP(GET_HEAP_PAGE(src)->remembered_bits, src);
- if (FL_TEST_RAW(src, FL_SEEN_OBJ_ID)) {
- /* If the source object's object_id has been seen, we need to update
- * the object to object id mapping. */
- st_data_t srcid = (st_data_t)src, 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();
- {
- if (!st_delete(objspace->obj_to_id_tbl, &srcid, &id)) {
- rb_bug("gc_move: object ID seen, but not in mapping table: %s", rb_obj_info((VALUE)src));
- }
-
- st_insert(objspace->obj_to_id_tbl, (st_data_t)dest, id);
- }
- DURING_GC_COULD_MALLOC_REGION_END();
- }
- else {
- GC_ASSERT(!st_lookup(objspace->obj_to_id_tbl, (st_data_t)src, NULL));
- }
-
/* Move the object */
memcpy((void *)dest, (void *)src, MIN(src_slot_size, slot_size));
+ if (src_slot_size != slot_size && RB_TYPE_P(src, T_OBJECT)) {
+ rb_gc_obj_changed_pool(dest, dest_page->heap - heaps);
+ }
+
if (RVALUE_OVERHEAD > 0) {
void *dest_overhead = (void *)(((uintptr_t)dest) + slot_size - RVALUE_OVERHEAD);
void *src_overhead = (void *)(((uintptr_t)src) + src_slot_size - RVALUE_OVERHEAD);
@@ -6978,7 +7140,7 @@ gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, size_t src_slot_size, si
}
memset((void *)src, 0, src_slot_size);
- RVALUE_AGE_RESET(src);
+ RVALUE_AGE_SET_BITMAP(src, 0);
/* Set bits for object in new location */
if (remembered) {
@@ -7085,6 +7247,12 @@ gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func co
}
#endif
+void
+rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
+{
+ /* no-op */
+}
+
bool
rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
{
@@ -7152,6 +7320,8 @@ gc_update_references(rb_objspace_t *objspace)
{
objspace->flags.during_reference_updating = true;
+ rb_gc_before_updating_jit_code();
+
struct heap_page *page = NULL;
for (int i = 0; i < HEAP_COUNT; i++) {
@@ -7171,8 +7341,7 @@ gc_update_references(rb_objspace_t *objspace)
}
}
}
- gc_ref_update_table_values_only(objspace->obj_to_id_tbl);
- gc_update_table_refs(objspace->id_to_obj_tbl);
+
gc_update_table_refs(finalizer_table);
rb_gc_update_vm_references((void *)objspace);
@@ -7187,6 +7356,8 @@ gc_update_references(rb_objspace_t *objspace)
);
}
+ rb_gc_after_updating_jit_code();
+
objspace->flags.during_reference_updating = false;
}
@@ -7315,7 +7486,7 @@ 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;
+ static VALUE sym_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;
@@ -7357,7 +7528,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
S(sweeping);
S(weak_references_count);
- S(retained_weak_references_count);
#undef S
}
@@ -7410,7 +7580,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
}
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)) {
@@ -7437,7 +7606,7 @@ enum gc_stat_sym {
gc_stat_sym_sweeping_time,
gc_stat_sym_heap_allocated_pages,
gc_stat_sym_heap_empty_pages,
- gc_stat_sym_heap_allocatable_slots,
+ gc_stat_sym_heap_allocatable_bytes,
gc_stat_sym_heap_available_slots,
gc_stat_sym_heap_live_slots,
gc_stat_sym_heap_free_slots,
@@ -7448,6 +7617,8 @@ enum gc_stat_sym {
gc_stat_sym_total_freed_pages,
gc_stat_sym_total_allocated_objects,
gc_stat_sym_total_freed_objects,
+ gc_stat_sym_total_malloc_bytes,
+ gc_stat_sym_total_free_bytes,
gc_stat_sym_malloc_increase_bytes,
gc_stat_sym_malloc_increase_bytes_limit,
gc_stat_sym_minor_gc_count,
@@ -7463,7 +7634,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,
@@ -7488,7 +7658,7 @@ setup_gc_stat_symbols(void)
S(sweeping_time),
S(heap_allocated_pages);
S(heap_empty_pages);
- S(heap_allocatable_slots);
+ S(heap_allocatable_bytes);
S(heap_available_slots);
S(heap_live_slots);
S(heap_free_slots);
@@ -7499,6 +7669,8 @@ setup_gc_stat_symbols(void)
S(total_freed_pages);
S(total_allocated_objects);
S(total_freed_objects);
+ S(total_malloc_bytes);
+ S(total_free_bytes);
S(malloc_increase_bytes);
S(malloc_increase_bytes_limit);
S(minor_gc_count);
@@ -7514,7 +7686,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);
@@ -7533,6 +7704,8 @@ ns_to_ms(uint64_t ns)
return ns / (1000 * 1000);
}
+static void malloc_increase_local_flush(rb_objspace_t *objspace);
+
VALUE
rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
{
@@ -7541,6 +7714,9 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
setup_gc_stat_symbols();
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+ malloc_increase_local_flush(objspace);
+
if (RB_TYPE_P(hash_or_sym, T_HASH)) {
hash = hash_or_sym;
}
@@ -7556,27 +7732,32 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
return SIZET2NUM(attr); \
else if (hash != Qnil) \
rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
+#define SET64(name, attr) \
+ if (key == gc_stat_symbols[gc_stat_sym_##name]) \
+ return ULL2NUM(attr); \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], ULL2NUM(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));
- /* implementation dependent counters */
+ {
+ uint64_t total_malloc = (uint64_t)gc_counter_load_relaxed(&objspace->malloc_counters.counters.malloc);
+ uint64_t total_free = (uint64_t)gc_counter_load_relaxed(&objspace->malloc_counters.counters.free);
+ SET64(total_malloc_bytes, total_malloc);
+ SET64(total_free_bytes, total_free);
+ }
+
+ /* implementation dependent counters (small / fixnum-safe) */
SET(heap_allocated_pages, rb_darray_size(objspace->heap_pages.sorted));
SET(heap_empty_pages, objspace->empty_pages_count)
- SET(heap_allocatable_slots, objspace->heap_pages.allocatable_slots);
- SET(heap_available_slots, objspace_available_slots(objspace));
- SET(heap_live_slots, objspace_live_slots(objspace));
- SET(heap_free_slots, objspace_free_slots(objspace));
- SET(heap_final_slots, total_final_slots_count(objspace));
- SET(heap_marked_slots, objspace->marked_slots);
+ SET(heap_allocatable_bytes, objspace->heap_pages.allocatable_bytes);
SET(heap_eden_pages, heap_eden_total_pages(objspace));
SET(total_allocated_pages, objspace->heap_pages.allocated_pages);
SET(total_freed_pages, objspace->heap_pages.freed_pages);
- SET(total_allocated_objects, total_allocated_objects(objspace));
- SET(total_freed_objects, total_freed_objects(objspace));
- SET(malloc_increase_bytes, malloc_increase);
+ SET(malloc_increase_bytes, gc_malloc_counters_increase_unsigned(objspace, &objspace->malloc_counters.counters));
SET(malloc_increase_bytes_limit, malloc_limit);
SET(minor_gc_count, objspace->profile.minor_gc_count);
SET(major_gc_count, objspace->profile.major_gc_count);
@@ -7588,10 +7769,19 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
SET(old_objects, objspace->rgengc.old_objects);
SET(old_objects_limit, objspace->rgengc.old_objects_limit);
#if RGENGC_ESTIMATE_OLDMALLOC
- SET(oldmalloc_increase_bytes, objspace->rgengc.oldmalloc_increase);
+ SET(oldmalloc_increase_bytes, gc_malloc_counters_increase_unsigned(objspace, &objspace->malloc_counters.oldcounters));
SET(oldmalloc_increase_bytes_limit, objspace->rgengc.oldmalloc_increase_limit);
#endif
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+ SET(total_allocated_objects, total_allocated_objects(objspace));
+ SET(total_freed_objects, total_freed_objects(objspace));
+ SET(heap_available_slots, objspace_available_slots(objspace));
+ SET(heap_live_slots, objspace_live_slots(objspace));
+ SET(heap_free_slots, objspace_free_slots(objspace));
+ SET(heap_final_slots, total_final_slots_count(objspace));
+ SET(heap_marked_slots, objspace->marked_slots);
+
#if RGENGC_PROFILE
SET(total_generated_normal_object_count, objspace->profile.total_generated_normal_object_count);
SET(total_generated_shady_object_count, objspace->profile.total_generated_shady_object_count);
@@ -7601,6 +7791,7 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
SET(total_remembered_shady_object_count, objspace->profile.total_remembered_shady_object_count);
#endif /* RGENGC_PROFILE */
#undef SET
+#undef SET64
if (!NIL_P(key)) {
// Matched key should return above
@@ -7623,11 +7814,15 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
enum gc_stat_heap_sym {
gc_stat_heap_sym_slot_size,
+ gc_stat_heap_sym_heap_live_slots,
+ gc_stat_heap_sym_heap_free_slots,
+ gc_stat_heap_sym_heap_final_slots,
gc_stat_heap_sym_heap_eden_pages,
gc_stat_heap_sym_heap_eden_slots,
gc_stat_heap_sym_total_allocated_pages,
gc_stat_heap_sym_force_major_gc_count,
gc_stat_heap_sym_force_incremental_marking_finish_count,
+ gc_stat_heap_sym_heap_allocatable_slots,
gc_stat_heap_sym_total_allocated_objects,
gc_stat_heap_sym_total_freed_objects,
gc_stat_heap_sym_last
@@ -7641,8 +7836,12 @@ setup_gc_stat_heap_symbols(void)
if (gc_stat_heap_symbols[0] == 0) {
#define S(s) gc_stat_heap_symbols[gc_stat_heap_sym_##s] = ID2SYM(rb_intern_const(#s))
S(slot_size);
+ S(heap_live_slots);
+ S(heap_free_slots);
+ S(heap_final_slots);
S(heap_eden_pages);
S(heap_eden_slots);
+ S(heap_allocatable_slots);
S(total_allocated_pages);
S(force_major_gc_count);
S(force_incremental_marking_finish_count);
@@ -7653,7 +7852,7 @@ setup_gc_stat_heap_symbols(void)
}
static VALUE
-stat_one_heap(rb_heap_t *heap, VALUE hash, VALUE key)
+stat_one_heap(rb_objspace_t *objspace, rb_heap_t *heap, VALUE hash, VALUE key)
{
#define SET(name, attr) \
if (key == gc_stat_heap_symbols[gc_stat_heap_sym_##name]) \
@@ -7662,8 +7861,12 @@ stat_one_heap(rb_heap_t *heap, VALUE hash, VALUE key)
rb_hash_aset(hash, gc_stat_heap_symbols[gc_stat_heap_sym_##name], SIZET2NUM(attr));
SET(slot_size, heap->slot_size);
+ SET(heap_live_slots, heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count);
+ SET(heap_free_slots, heap->total_slots - (heap->total_allocated_objects - heap->total_freed_objects));
+ SET(heap_final_slots, heap->final_slots_count);
SET(heap_eden_pages, heap->total_pages);
SET(heap_eden_slots, heap->total_slots);
+ SET(heap_allocatable_slots, objspace->heap_pages.allocatable_bytes / heap->slot_size);
SET(total_allocated_pages, heap->total_allocated_pages);
SET(force_major_gc_count, heap->force_major_gc_count);
SET(force_incremental_marking_finish_count, heap->force_incremental_marking_finish_count);
@@ -7684,6 +7887,8 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
{
rb_objspace_t *objspace = objspace_ptr;
+ ractor_cache_flush_count(objspace, rb_gc_get_ractor_newobj_cache());
+
setup_gc_stat_heap_symbols();
if (NIL_P(heap_name)) {
@@ -7698,7 +7903,7 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
rb_hash_aset(hash_or_sym, INT2FIX(i), hash);
}
- stat_one_heap(&heaps[i], hash, Qnil);
+ stat_one_heap(objspace, &heaps[i], hash, Qnil);
}
}
else if (FIXNUM_P(heap_name)) {
@@ -7709,10 +7914,10 @@ rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
}
if (SYMBOL_P(hash_or_sym)) {
- return stat_one_heap(&heaps[heap_idx], Qnil, hash_or_sym);
+ return stat_one_heap(objspace, &heaps[heap_idx], Qnil, hash_or_sym);
}
else if (RB_TYPE_P(hash_or_sym, T_HASH)) {
- return stat_one_heap(&heaps[heap_idx], hash_or_sym, Qnil);
+ return stat_one_heap(objspace, &heaps[heap_idx], hash_or_sym, Qnil);
}
else {
rb_bug("non-hash or symbol given");
@@ -7747,7 +7952,7 @@ rb_gc_impl_config_get(void *objspace_ptr)
}
static int
-gc_config_set_key(st_data_t key, st_data_t value, st_data_t data)
+gc_config_set_key(VALUE key, VALUE value, VALUE data)
{
rb_objspace_t *objspace = (rb_objspace_t *)data;
if (rb_sym2id(key) == rb_intern("rgengc_allow_full_mark")) {
@@ -7766,7 +7971,7 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
rb_raise(rb_eArgError, "expected keyword arguments");
}
- rb_hash_stlike_foreach(hash, gc_config_set_key, (st_data_t)objspace);
+ rb_hash_foreach(hash, gc_config_set_key, (st_data_t)objspace);
}
VALUE
@@ -7894,8 +8099,8 @@ get_envparam_double(const char *name, double *default_value, double lower_bound,
* * RUBY_GC_HEAP_GROWTH_FACTOR (new from 2.1)
* - Allocate slots by this factor.
* - (next slots number) = (current slots number) * (this factor)
- * * RUBY_GC_HEAP_GROWTH_MAX_SLOTS (new from 2.1)
- * - Allocation rate is limited to this number of slots.
+ * * RUBY_GC_HEAP_GROWTH_MAX_BYTES (was RUBY_GC_HEAP_GROWTH_MAX_SLOTS)
+ * - Allocation rate is limited to this number of bytes.
* * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO (new from 2.4)
* - Allocate additional pages when the number of free slots is
* lower than the value (total_slots * (this ratio)).
@@ -7914,7 +8119,7 @@ get_envparam_double(const char *name, double *default_value, double lower_bound,
*
* * obsolete
* * RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS (from 2.1)
- * * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1)
+ * * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1) -> RUBY_GC_HEAP_INIT_BYTES
*
* * RUBY_GC_MALLOC_LIMIT
* * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
@@ -7934,15 +8139,10 @@ rb_gc_impl_set_params(void *objspace_ptr)
/* ok */
}
- for (int i = 0; i < HEAP_COUNT; 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);
-
- get_envparam_size(env_key, &gc_params.heap_init_slots[i], 0);
- }
+ get_envparam_size("RUBY_GC_HEAP_INIT_BYTES", &gc_params.heap_init_bytes, 0);
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);
+ get_envparam_size ("RUBY_GC_HEAP_GROWTH_MAX_BYTES", &gc_params.growth_max_bytes, 0);
get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO", &gc_params.heap_free_slots_min_ratio,
0.0, 1.0, FALSE);
get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO", &gc_params.heap_free_slots_max_ratio,
@@ -8016,8 +8216,53 @@ objspace_malloc_gc_stress(rb_objspace_t *objspace)
}
}
+static void
+malloc_increase_commit(rb_objspace_t *objspace, size_t new_size, size_t old_size)
+{
+ if (new_size > old_size) {
+ size_t delta = new_size - old_size;
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_add(&objspace->malloc_counters.counters.malloc, delta);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ gc_counter_add(&objspace->malloc_counters.oldcounters.malloc, delta);
+#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
+ }
+ else if (old_size > new_size) {
+ size_t delta = old_size - new_size;
+ MALLOC_COUNTERS_LOCK(objspace);
+ gc_counter_add(&objspace->malloc_counters.counters.free, delta);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ gc_counter_add(&objspace->malloc_counters.oldcounters.free, delta);
+#endif
+ MALLOC_COUNTERS_UNLOCK(objspace);
+ }
+}
+
+#if USE_MALLOC_INCREASE_LOCAL
+static void
+malloc_increase_local_flush(rb_objspace_t *objspace)
+{
+ int delta = malloc_increase_local;
+ if (delta == 0) return;
+
+ malloc_increase_local = 0;
+ if (delta > 0) {
+ malloc_increase_commit(objspace, (size_t)delta, 0);
+ }
+ else {
+ malloc_increase_commit(objspace, 0, (size_t)(-delta));
+ }
+}
+#else
+static void
+malloc_increase_local_flush(rb_objspace_t *objspace)
+{
+}
+#endif
+
static inline bool
-objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
+objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type, bool gc_allowed)
{
if (0) fprintf(stderr, "increase - ptr: %p, type: %s, new_size: %"PRIdSIZE", old_size: %"PRIdSIZE"\n",
mem,
@@ -8029,22 +8274,27 @@ objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_s
}
static bool
-objspace_malloc_increase_body(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
+objspace_malloc_increase_body(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type, bool gc_allowed)
{
- if (new_size > old_size) {
- RUBY_ATOMIC_SIZE_ADD(malloc_increase, new_size - old_size);
-#if RGENGC_ESTIMATE_OLDMALLOC
- RUBY_ATOMIC_SIZE_ADD(objspace->rgengc.oldmalloc_increase, new_size - old_size);
-#endif
+#if USE_MALLOC_INCREASE_LOCAL
+ if (new_size < GC_MALLOC_INCREASE_LOCAL_THRESHOLD &&
+ old_size < GC_MALLOC_INCREASE_LOCAL_THRESHOLD) {
+ malloc_increase_local += (int)new_size - (int)old_size;
+
+ if (malloc_increase_local >= GC_MALLOC_INCREASE_LOCAL_THRESHOLD ||
+ malloc_increase_local <= -GC_MALLOC_INCREASE_LOCAL_THRESHOLD) {
+ malloc_increase_local_flush(objspace);
+ }
}
else {
- atomic_sub_nounderflow(&malloc_increase, old_size - new_size);
-#if RGENGC_ESTIMATE_OLDMALLOC
- atomic_sub_nounderflow(&objspace->rgengc.oldmalloc_increase, old_size - new_size);
-#endif
+ malloc_increase_local_flush(objspace);
+ malloc_increase_commit(objspace, new_size, old_size);
}
+#else
+ malloc_increase_commit(objspace, new_size, old_size);
+#endif
- if (type == MEMOP_TYPE_MALLOC) {
+ if (type == MEMOP_TYPE_MALLOC && gc_allowed) {
retry:
if (malloc_increase > malloc_limit && ruby_native_thread_p() && !dont_gc_val()) {
if (ruby_thread_has_gvl_p() && is_lazy_sweeping(objspace)) {
@@ -8126,10 +8376,10 @@ malloc_during_gc_p(rb_objspace_t *objspace)
}
static inline void *
-objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
+objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size, bool gc_allowed)
{
size = objspace_malloc_size(objspace, mem, size);
- objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC) {}
+ objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC, gc_allowed) {}
#if CALC_EXACT_MALLOC_SIZE
{
@@ -8161,10 +8411,10 @@ objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
GPR_FLAG_MALLOC; \
objspace_malloc_gc_stress(objspace); \
\
- if (RB_LIKELY((expr))) { \
+ if (RB_LIKELY((expr))) { \
/* Success on 1st try */ \
} \
- else if (!garbage_collect_with_gvl(objspace, gpr)) { \
+ else if (gc_allowed && !garbage_collect_with_gvl(objspace, gpr)) { \
/* @shyouhei thinks this doesn't happen */ \
GC_MEMERROR("TRY_WITH_GC: could not GC"); \
} \
@@ -8202,12 +8452,21 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
}
#if CALC_EXACT_MALLOC_SIZE
struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+#if VERIFY_FREE_SIZE
+ if (!info->size) {
+ rb_bug("buffer %p has no recorded size. Was it allocated with ruby_mimalloc? If so it should be freed with ruby_mimfree", ptr);
+ }
+
+ if (old_size && (old_size + sizeof(struct malloc_obj_info)) != info->size) {
+ rb_bug("buffer %p freed with old_size=%zu, but was allocated with size=%zu", ptr, old_size, info->size - sizeof(struct malloc_obj_info));
+ }
+#endif
ptr = info;
old_size = info->size;
#endif
old_size = objspace_malloc_size(objspace, ptr, old_size);
- objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE) {
+ objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE, true) {
free(ptr);
ptr = NULL;
RB_DEBUG_COUNTER_INC(heap_xfree);
@@ -8215,7 +8474,7 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
}
void *
-rb_gc_impl_malloc(void *objspace_ptr, size_t size)
+rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
rb_objspace_t *objspace = objspace_ptr;
check_malloc_not_in_gc(objspace, "malloc");
@@ -8226,11 +8485,11 @@ rb_gc_impl_malloc(void *objspace_ptr, size_t size)
TRY_WITH_GC(size, mem = malloc(size));
RB_DEBUG_COUNTER_INC(heap_xmalloc);
if (!mem) return mem;
- return objspace_malloc_fixup(objspace, mem, size);
+ return objspace_malloc_fixup(objspace, mem, size, gc_allowed);
}
void *
-rb_gc_impl_calloc(void *objspace_ptr, size_t size)
+rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
rb_objspace_t *objspace = objspace_ptr;
@@ -8246,11 +8505,11 @@ rb_gc_impl_calloc(void *objspace_ptr, size_t size)
size = objspace_malloc_prepare(objspace, size);
TRY_WITH_GC(size, mem = calloc1(size));
if (!mem) return mem;
- return objspace_malloc_fixup(objspace, mem, size);
+ return objspace_malloc_fixup(objspace, mem, size, gc_allowed);
}
void *
-rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size)
+rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed)
{
rb_objspace_t *objspace = objspace_ptr;
@@ -8258,7 +8517,7 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
void *mem;
- if (!ptr) return rb_gc_impl_malloc(objspace, new_size);
+ if (!ptr) return rb_gc_impl_malloc(objspace, new_size, gc_allowed);
/*
* The behavior of realloc(ptr, 0) is implementation defined.
@@ -8266,7 +8525,7 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
* see http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm
*/
if (new_size == 0) {
- if ((mem = rb_gc_impl_malloc(objspace, 0)) != NULL) {
+ if ((mem = rb_gc_impl_malloc(objspace, 0, gc_allowed)) != NULL) {
/*
* - OpenBSD's malloc(3) man page says that when 0 is passed, it
* returns a non-NULL pointer to an access-protected memory page.
@@ -8308,6 +8567,11 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
new_size += sizeof(struct malloc_obj_info);
ptr = info;
+#if VERIFY_FREE_SIZE
+ if (old_size && (old_size + sizeof(struct malloc_obj_info)) != info->size) {
+ rb_bug("buffer %p realloced with old_size=%zu, but was allocated with size=%zu", ptr, old_size, info->size - sizeof(struct malloc_obj_info));
+ }
+#endif
old_size = info->size;
}
#endif
@@ -8325,7 +8589,7 @@ rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_si
}
#endif
- objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
+ objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC, gc_allowed);
RB_DEBUG_COUNTER_INC(heap_xrealloc);
return mem;
@@ -8337,10 +8601,10 @@ rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff)
rb_objspace_t *objspace = objspace_ptr;
if (diff > 0) {
- objspace_malloc_increase(objspace, 0, diff, 0, MEMOP_TYPE_REALLOC);
+ objspace_malloc_increase(objspace, 0, diff, 0, MEMOP_TYPE_REALLOC, true);
}
else if (diff < 0) {
- objspace_malloc_increase(objspace, 0, 0, -diff, MEMOP_TYPE_REALLOC);
+ objspace_malloc_increase(objspace, 0, 0, -diff, MEMOP_TYPE_REALLOC, true);
}
}
@@ -8579,18 +8843,29 @@ 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 total = objspace->profile.heap_used_at_gc_start * HEAP_PAGE_OBJ_LIMIT;
+
+ /* Sum across all size pools since each has a different slot size. */
+ size_t total = 0;
+ size_t use_size = 0;
+ size_t total_size = 0;
+ for (int i = 0; i < HEAP_COUNT; i++) {
+ rb_heap_t *heap = &heaps[i];
+ size_t heap_live = heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count;
+ total += heap->total_slots;
+ use_size += heap_live * heap->slot_size;
+ total_size += heap->total_slots * heap->slot_size;
+ }
#if GC_PROFILE_MORE_DETAIL
+ size_t live = objspace->profile.total_allocated_objects_at_gc_start - total_freed_objects(objspace);
record->heap_use_pages = objspace->profile.heap_used_at_gc_start;
record->heap_live_objects = live;
record->heap_free_objects = total - live;
#endif
record->heap_total_objects = total;
- record->heap_use_size = live * BASE_SLOT_SIZE;
- record->heap_total_size = total * BASE_SLOT_SIZE;
+ record->heap_use_size = use_size;
+ record->heap_total_size = total_size;
}
}
@@ -8957,6 +9232,12 @@ gc_profile_disable(VALUE _)
return Qnil;
}
+void
+rb_gc_verify_internal_consistency(void)
+{
+ gc_verify_internal_consistency(rb_gc_get_objspace());
+}
+
/*
* call-seq:
* GC.verify_internal_consistency -> nil
@@ -8970,7 +9251,7 @@ gc_profile_disable(VALUE _)
static VALUE
gc_verify_internal_consistency_m(VALUE dummy)
{
- gc_verify_internal_consistency(rb_gc_get_objspace());
+ rb_gc_verify_internal_consistency();
return Qnil;
}
@@ -9191,7 +9472,7 @@ gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
/* Clear the heap. */
rb_gc_impl_start(objspace, true, true, true, false);
- unsigned int lev = rb_gc_vm_lock();
+ unsigned int lev = RB_GC_VM_LOCK();
{
gc_rest(objspace);
@@ -9227,8 +9508,8 @@ gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
* 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
*/
- objspace->heap_pages.allocatable_slots = desired_compaction.required_slots[i];
- while (objspace->heap_pages.allocatable_slots > 0) {
+ objspace->heap_pages.allocatable_bytes = desired_compaction.required_slots[i] * heap->slot_size;
+ while (objspace->heap_pages.allocatable_bytes > 0) {
heap_page_allocate_and_initialize(objspace, heap);
}
/*
@@ -9247,7 +9528,7 @@ gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
objspace->rcompactor.compare_func = compare_free_slots;
}
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
rb_gc_impl_start(rb_gc_get_objspace(), true, true, true, true);
@@ -9286,14 +9567,15 @@ rb_gc_impl_objspace_free(void *objspace_ptr)
heap->total_slots = 0;
}
- st_free_table(objspace->id_to_obj_tbl);
- st_free_table(objspace->obj_to_id_tbl);
-
free_stack_chunks(&objspace->mark_stack);
mark_stack_free_cache(&objspace->mark_stack);
rb_darray_free_without_gc(objspace->weak_references);
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ rb_native_mutex_destroy(&objspace->malloc_counters.lock);
+#endif
+
free(objspace);
}
@@ -9331,9 +9613,31 @@ gc_malloc_allocations(VALUE self)
}
#endif
-void rb_gc_impl_before_fork(void *objspace_ptr) { /* no-op */ }
-void rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid) { /* no-op */ }
+void
+rb_gc_impl_before_fork(void *objspace_ptr)
+{
+ rb_objspace_t *objspace = objspace_ptr;
+
+ objspace->fork_vm_lock_lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+}
+
+void
+rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
+{
+ rb_objspace_t *objspace = objspace_ptr;
+
+ RB_GC_VM_UNLOCK(objspace->fork_vm_lock_lev);
+ objspace->fork_vm_lock_lev = 0;
+ if (pid == 0) { /* child process */
+ rb_gc_ractor_newobj_cache_foreach(gc_ractor_newobj_cache_clear, NULL);
+ }
+}
+
+VALUE rb_ident_hash_new_with_size(st_index_t size);
+
+#if GC_DEBUG_STRESS_TO_CLASS
/*
* call-seq:
* GC.add_stress_to_class(class[, ...])
@@ -9383,6 +9687,7 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
return Qnil;
}
+#endif
void *
rb_gc_impl_objspace_alloc(void)
@@ -9401,42 +9706,40 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
objspace->flags.measure_gc = true;
malloc_limit = gc_params.malloc_limit_min;
+#ifdef MALLOC_COUNTERS_NEED_LOCK
+ rb_native_mutex_initialize(&objspace->malloc_counters.lock);
+#endif
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");
}
+ /* A standard RVALUE (RBasic + embedded VALUEs + debug overhead) must fit
+ * in at least one pool. In debug builds RVALUE_OVERHEAD can push this
+ * beyond the 48-byte pool into the 64-byte pool, which is fine. */
+ GC_ASSERT(rb_gc_impl_size_allocatable_p(sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])));
+
for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
- heap->slot_size = (1 << i) * BASE_SLOT_SIZE;
+ heap->slot_size = pool_slot_sizes[i];
ccan_list_head_init(&heap->pages);
}
+ init_size_to_heap_idx();
+
rb_darray_make_without_gc(&objspace->heap_pages.sorted, 0);
rb_darray_make_without_gc(&objspace->weak_references, 0);
- // TODO: debug why on Windows Ruby crashes on boot when GC is on.
-#ifdef _WIN32
- dont_gc_on();
-#endif
-
#if defined(INIT_HEAP_PAGE_ALLOC_USE_MMAP)
/* Need to determine if we can use mmap at runtime. */
heap_page_alloc_use_mmap = INIT_HEAP_PAGE_ALLOC_USE_MMAP;
#endif
- objspace->next_object_id = OBJ_ID_INITIAL;
- objspace->id_to_obj_tbl = st_init_table(&object_id_hash_type);
- objspace->obj_to_id_tbl = st_init_numtable();
#if RGENGC_ESTIMATE_OLDMALLOC
objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
#endif
- /* Set size pools allocatable pages. */
- for (int i = 0; i < HEAP_COUNT; i++) {
- /* Set the default value of heap_init_slots. */
- gc_params.heap_init_slots[i] = GC_HEAP_INIT_SLOTS;
- }
+ gc_params.heap_init_bytes = GC_HEAP_INIT_BYTES;
init_mark_stack(&objspace->mark_stack);
@@ -9449,9 +9752,14 @@ rb_gc_impl_init(void)
{
VALUE gc_constants = rb_hash_new();
rb_hash_aset(gc_constants, ID2SYM(rb_intern("DEBUG")), GC_DEBUG ? Qtrue : Qfalse);
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(BASE_SLOT_SIZE - RVALUE_OVERHEAD));
+ /* Minimum slot size that fits a standard RVALUE */
+ size_t rvalue_pool = 0;
+ for (size_t i = 0; i < HEAP_COUNT; i++) {
+ if (pool_slot_sizes[i] >= RVALUE_SLOT_SIZE) { rvalue_pool = pool_slot_sizes[i]; break; }
+ }
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(rvalue_pool - RVALUE_OVERHEAD));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), SIZET2NUM(RVALUE_OVERHEAD));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_OBJ_LIMIT")), SIZET2NUM(HEAP_PAGE_OBJ_LIMIT));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_BITMAP_SIZE")), SIZET2NUM(HEAP_PAGE_BITMAP_SIZE));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_SIZE")), SIZET2NUM(HEAP_PAGE_SIZE));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_COUNT")), LONG2FIX(HEAP_COUNT));
@@ -9479,10 +9787,10 @@ rb_gc_impl_init(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
/* internal methods */
rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0);
diff --git a/gc/gc.h b/gc/gc.h
index c2e985252f..d147a3122a 100644
--- a/gc/gc.h
+++ b/gc/gc.h
@@ -10,16 +10,38 @@
* first introduced for [Feature #20470].
*/
#include "ruby/ruby.h"
+#include "ruby/assert.h"
-#if USE_MODULAR_GC
#include "ruby/thread_native.h"
+#ifndef VM_CHECK_MODE
+# define VM_CHECK_MODE RUBY_DEBUG
+#endif
+
+// From ractor_core.h
+#ifndef RACTOR_CHECK_MODE
+# define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
+#endif
+
+#if RACTOR_CHECK_MODE
+void rb_ractor_setup_belonging(VALUE obj);
+
+struct rb_gc_obj_suffix {
+ uint32_t _ractor_belonging_id;
+};
+
+# define RB_GC_OBJ_HAS_SUFFIX 1
+# define RB_GC_OBJ_SUFFIX_SIZE (sizeof(struct rb_gc_obj_suffix))
+#else
+# define RB_GC_OBJ_HAS_SUFFIX 0
+# define RB_GC_OBJ_SUFFIX_SIZE 0
+#endif
+
struct rb_gc_vm_context {
rb_nativethread_lock_t lock;
struct rb_execution_context_struct *ec;
};
-#endif
typedef int (*vm_table_foreach_callback_func)(VALUE value, void *data);
typedef int (*vm_table_update_callback_func)(VALUE *value, void *data);
@@ -28,57 +50,88 @@ enum rb_gc_vm_weak_tables {
RB_GC_VM_CI_TABLE,
RB_GC_VM_OVERLOADED_CME_TABLE,
RB_GC_VM_GLOBAL_SYMBOLS_TABLE,
- RB_GC_VM_GENERIC_IV_TABLE,
+ RB_GC_VM_ID2REF_TABLE,
+ RB_GC_VM_GENERIC_FIELDS_TABLE,
RB_GC_VM_FROZEN_STRINGS_TABLE,
RB_GC_VM_WEAK_TABLE_COUNT
};
+#define RB_GC_VM_LOCK() rb_gc_vm_lock(__FILE__, __LINE__)
+#define RB_GC_VM_UNLOCK(lev) rb_gc_vm_unlock(lev, __FILE__, __LINE__)
+#define RB_GC_CR_LOCK() rb_gc_cr_lock(__FILE__, __LINE__)
+#define RB_GC_CR_UNLOCK(lev) rb_gc_cr_unlock(lev, __FILE__, __LINE__)
+#define RB_GC_VM_LOCK_NO_BARRIER() rb_gc_vm_lock_no_barrier(__FILE__, __LINE__)
+#define RB_GC_VM_UNLOCK_NO_BARRIER(lev) rb_gc_vm_unlock_no_barrier(lev, __FILE__, __LINE__)
+
+#if USE_MODULAR_GC
+# define MODULAR_GC_FN
+#else
+// This takes advantage of internal linkage winning when appearing first.
+// See C99 6.2.2p4.
+# define MODULAR_GC_FN static
+#endif
+
+#if USE_MODULAR_GC
RUBY_SYMBOL_EXPORT_BEGIN
-unsigned int rb_gc_vm_lock(void);
-void rb_gc_vm_unlock(unsigned int lev);
-unsigned int rb_gc_cr_lock(void);
-void rb_gc_cr_unlock(unsigned int lev);
-unsigned int rb_gc_vm_lock_no_barrier(void);
-void rb_gc_vm_unlock_no_barrier(unsigned int lev);
-void rb_gc_vm_barrier(void);
-size_t rb_gc_obj_optimal_size(VALUE obj);
-void rb_gc_mark_children(void *objspace, VALUE obj);
-void rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, vm_table_update_callback_func update_callback, void *data, bool weak_only, enum rb_gc_vm_weak_tables table);
-void rb_gc_update_object_references(void *objspace, VALUE obj);
-void rb_gc_update_vm_references(void *objspace);
-void rb_gc_event_hook(VALUE obj, rb_event_flag_t event);
-void *rb_gc_get_objspace(void);
+#endif
+
+// These functions cannot be defined as static because they are used by other
+// files in Ruby.
size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc);
-void rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void *data), void *data);
-void rb_gc_set_pending_interrupt(void);
-void rb_gc_unset_pending_interrupt(void);
-void rb_gc_obj_free_vm_weak_references(VALUE obj);
-bool rb_gc_obj_free(void *objspace, VALUE obj);
-void rb_gc_save_machine_context(void);
-void rb_gc_mark_roots(void *objspace, const char **categoryp);
-void rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data);
-bool rb_gc_multi_ractor_p(void);
-void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data);
void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
-void rb_obj_info_dump(VALUE obj);
+const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
const char *rb_obj_info(VALUE obj);
-bool rb_gc_shutdown_call_finalizer_p(VALUE obj);
-uint32_t rb_gc_get_shape(VALUE obj);
-void rb_gc_set_shape(VALUE obj, uint32_t shape_id);
-uint32_t rb_gc_rebuild_shape(VALUE obj, size_t heap_id);
size_t rb_obj_memsize_of(VALUE obj);
-void rb_gc_prepare_heap_process_object(VALUE obj);
bool ruby_free_at_exit_p(void);
-bool rb_memerror_reentered(void);
+void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data);
+void rb_gc_verify_shareable(VALUE);
+
+MODULAR_GC_FN unsigned int rb_gc_vm_lock(const char *file, int line);
+MODULAR_GC_FN void rb_gc_vm_unlock(unsigned int lev, const char *file, int line);
+MODULAR_GC_FN unsigned int rb_gc_cr_lock(const char *file, int line);
+MODULAR_GC_FN void rb_gc_cr_unlock(unsigned int lev, const char *file, int line);
+MODULAR_GC_FN unsigned int rb_gc_vm_lock_no_barrier(const char *file, int line);
+MODULAR_GC_FN void rb_gc_vm_unlock_no_barrier(unsigned int lev, const char *file, int line);
+MODULAR_GC_FN void rb_gc_vm_barrier(void);
+MODULAR_GC_FN size_t rb_gc_obj_optimal_size(VALUE obj);
+MODULAR_GC_FN void rb_gc_mark_children(void *objspace, VALUE obj);
+MODULAR_GC_FN void rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, vm_table_update_callback_func update_callback, void *data, bool weak_only, enum rb_gc_vm_weak_tables table);
+MODULAR_GC_FN void rb_gc_update_object_references(void *objspace, VALUE obj);
+MODULAR_GC_FN void rb_gc_update_vm_references(void *objspace);
+MODULAR_GC_FN void rb_gc_event_hook(VALUE obj, rb_event_flag_t event);
+MODULAR_GC_FN void *rb_gc_get_objspace(void);
+MODULAR_GC_FN void rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void *data), void *data);
+MODULAR_GC_FN void rb_gc_set_pending_interrupt(void);
+MODULAR_GC_FN void rb_gc_unset_pending_interrupt(void);
+MODULAR_GC_FN void rb_gc_obj_free_vm_weak_references(VALUE obj);
+MODULAR_GC_FN bool rb_gc_obj_free(void *objspace, VALUE obj);
+MODULAR_GC_FN void rb_gc_save_machine_context(void);
+MODULAR_GC_FN void rb_gc_mark_roots(void *objspace, const char **categoryp);
+MODULAR_GC_FN void rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data);
+MODULAR_GC_FN bool rb_gc_multi_ractor_p(void);
+MODULAR_GC_FN bool rb_gc_shutdown_call_finalizer_p(VALUE obj);
+MODULAR_GC_FN void rb_gc_obj_changed_pool(VALUE obj, size_t heap_id);
+MODULAR_GC_FN void rb_gc_prepare_heap_process_object(VALUE obj);
+MODULAR_GC_FN bool rb_memerror_reentered(void);
+MODULAR_GC_FN bool rb_obj_id_p(VALUE);
+MODULAR_GC_FN void rb_gc_before_updating_jit_code(void);
+MODULAR_GC_FN void rb_gc_after_updating_jit_code(void);
+MODULAR_GC_FN bool rb_gc_obj_shareable_p(VALUE);
+MODULAR_GC_FN void rb_gc_rp(VALUE);
+MODULAR_GC_FN void rb_gc_handle_weak_references(VALUE obj);
+MODULAR_GC_FN bool rb_gc_obj_needs_cleanup_p(VALUE obj);
#if USE_MODULAR_GC
-bool rb_gc_event_hook_required_p(rb_event_flag_t event);
-void *rb_gc_get_ractor_newobj_cache(void);
-void rb_gc_initialize_vm_context(struct rb_gc_vm_context *context);
-void rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context);
-void rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context);
+MODULAR_GC_FN bool rb_gc_event_hook_required_p(rb_event_flag_t event);
+MODULAR_GC_FN void *rb_gc_get_ractor_newobj_cache(void);
+MODULAR_GC_FN void rb_gc_initialize_vm_context(struct rb_gc_vm_context *context);
+MODULAR_GC_FN void rb_gc_move_obj_during_marking(VALUE from, VALUE to);
+MODULAR_GC_FN void rb_gc_print_backtrace();
#endif
+
+#if USE_MODULAR_GC
RUBY_SYMBOL_EXPORT_END
+#endif
void rb_ractor_finish_marking(void);
@@ -103,7 +156,7 @@ RBIMPL_WARNING_IGNORED(-Wunused-function)
#endif
#ifndef GC_ASSERT
-# define GC_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr)
+# define GC_ASSERT(expr, ...) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
#endif
static int
@@ -142,6 +195,14 @@ gc_mark_tbl_no_pin_i(st_data_t key, st_data_t value, st_data_t data)
}
static int
+gc_mark_set_no_pin_i(st_data_t key, st_data_t value, st_data_t data)
+{
+ rb_gc_mark_movable((VALUE)key);
+
+ return ST_CONTINUE;
+}
+
+static int
hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error)
{
if (rb_gc_location((VALUE)key) != (VALUE)key) {
@@ -158,12 +219,14 @@ hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error)
static int
hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
{
- if (rb_gc_location((VALUE)*key) != (VALUE)*key) {
- *key = rb_gc_location((VALUE)*key);
+ VALUE new_key = rb_gc_location((VALUE)*key);
+ if (new_key != (VALUE)*key) {
+ *key = new_key;
}
- if (rb_gc_location((VALUE)*value) != (VALUE)*value) {
- *value = rb_gc_location((VALUE)*value);
+ VALUE new_value = rb_gc_location((VALUE)*value);
+ if (new_value != (VALUE)*value) {
+ *value = new_value;
}
return ST_CONTINUE;
diff --git a/gc/gc_impl.h b/gc/gc_impl.h
index bf2b34f8d9..d9e44cc66d 100644
--- a/gc/gc_impl.h
+++ b/gc/gc_impl.h
@@ -54,8 +54,9 @@ GC_IMPL_FN void rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag);
GC_IMPL_FN VALUE rb_gc_impl_stress_get(void *objspace_ptr);
GC_IMPL_FN VALUE rb_gc_impl_config_get(void *objspace_ptr);
GC_IMPL_FN void rb_gc_impl_config_set(void *objspace_ptr, VALUE hash);
+GC_IMPL_FN struct rb_gc_vm_context *rb_gc_impl_get_vm_context(void *objspace_ptr);
// Object allocation
-GC_IMPL_FN VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size);
+GC_IMPL_FN VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size);
GC_IMPL_FN size_t rb_gc_impl_obj_slot_size(VALUE obj);
GC_IMPL_FN size_t rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size);
GC_IMPL_FN bool rb_gc_impl_size_allocatable_p(size_t size);
@@ -72,9 +73,9 @@ GC_IMPL_FN bool rb_gc_impl_size_allocatable_p(size_t size);
* memory just return NULL (with appropriate errno set).
* The caller side takes care of that situation.
*/
-GC_IMPL_FN void *rb_gc_impl_malloc(void *objspace_ptr, size_t size);
-GC_IMPL_FN void *rb_gc_impl_calloc(void *objspace_ptr, size_t size);
-GC_IMPL_FN void *rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size);
+GC_IMPL_FN void *rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed);
+GC_IMPL_FN void *rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed);
+GC_IMPL_FN void *rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed);
GC_IMPL_FN void rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size);
GC_IMPL_FN void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff);
// Marking
@@ -82,9 +83,11 @@ GC_IMPL_FN void rb_gc_impl_mark(void *objspace_ptr, VALUE obj);
GC_IMPL_FN void rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr);
GC_IMPL_FN void rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj);
GC_IMPL_FN void rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr);
-GC_IMPL_FN void rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr);
+// Weak references
+GC_IMPL_FN void rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj);
+GC_IMPL_FN bool rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj);
// Compaction
+GC_IMPL_FN void rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj);
GC_IMPL_FN bool rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj);
GC_IMPL_FN VALUE rb_gc_impl_location(void *objspace_ptr, VALUE value);
// Write barriers
@@ -100,9 +103,6 @@ GC_IMPL_FN VALUE rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALU
GC_IMPL_FN void rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj);
GC_IMPL_FN void rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj);
GC_IMPL_FN void rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr);
-// Object ID
-GC_IMPL_FN VALUE rb_gc_impl_object_id(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN VALUE rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id);
// Forking
GC_IMPL_FN void rb_gc_impl_before_fork(void *objspace_ptr);
GC_IMPL_FN void rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid);
diff --git a/gc/mmtk/Cargo.lock b/gc/mmtk/Cargo.lock
index f909c3ae33..910048fa80 100644
--- a/gc/mmtk/Cargo.lock
+++ b/gc/mmtk/Cargo.lock
@@ -13,9 +13,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.14"
+version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -28,35 +28,36 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.7"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
-version = "0.2.4"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
-version = "1.1.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.3"
+version = "3.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
+checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
dependencies = [
"anstyle",
+ "once_cell_polyfill",
"windows-sys",
]
@@ -87,54 +88,54 @@ checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
[[package]]
name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
-version = "2.6.0"
+version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "built"
-version = "0.7.3"
+version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17"
+checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
dependencies = [
"git2",
]
[[package]]
name = "bytemuck"
-version = "1.16.1"
+version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
+checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
-version = "1.7.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b"
+checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
name = "cc"
-version = "1.0.100"
+version = "1.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b"
+checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
dependencies = [
"jobserver",
"libc",
- "once_cell",
+ "shlex",
]
[[package]]
@@ -145,15 +146,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "colorchoice"
-version = "1.0.1"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "core-foundation-sys"
-version = "0.8.6"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossbeam"
@@ -170,18 +171,18 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
-version = "0.5.13"
+version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
@@ -198,41 +199,41 @@ dependencies = [
[[package]]
name = "crossbeam-queue"
-version = "0.3.11"
+version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
-version = "0.8.20"
+version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "delegate"
-version = "0.12.0"
+version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b"
+checksum = "b9b6483c2bbed26f97861cf57651d4f2b731964a28cd2257f934a4b452480d21"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
name = "downcast-rs"
-version = "1.2.1"
+version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf"
[[package]]
name = "either"
-version = "1.12.0"
+version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "enum-map"
@@ -251,14 +252,14 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
name = "env_filter"
-version = "0.1.0"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
@@ -266,14 +267,14 @@ dependencies = [
[[package]]
name = "env_logger"
-version = "0.11.3"
+version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
- "humantime",
+ "jiff",
"log",
]
@@ -287,10 +288,22 @@ dependencies = [
]
[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi",
+]
+
+[[package]]
name = "git2"
-version = "0.18.3"
+version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70"
+checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b"
dependencies = [
"bitflags",
"libc",
@@ -312,53 +325,99 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
-name = "humantime"
-version = "2.1.0"
+name = "hermit-abi"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
[[package]]
name = "idna"
-version = "0.5.0"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "279259b0ac81c89d11c290495fdcfa96ea3643b7df311c138b6fe8ca5237f0f8"
+dependencies = [
+ "idna_mapping",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
+name = "idna_mapping"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11c13906586a4b339310541a274dd927aff6fcbb5b8e3af90634c4b31681c792"
+dependencies = [
+ "unicode-joining-type",
+]
+
+[[package]]
name = "is-terminal"
-version = "0.4.12"
+version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
+checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.5.1",
"libc",
"windows-sys",
]
[[package]]
name = "is_terminal_polyfill"
-version = "1.70.0"
+version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
-version = "0.12.1"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
+name = "jiff"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
name = "jobserver"
-version = "0.1.31"
+version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
+checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
dependencies = [
+ "getrandom",
"libc",
]
@@ -370,15 +429,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.155"
+version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libgit2-sys"
-version = "0.16.2+1.7.2"
+version = "0.18.3+1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8"
+checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487"
dependencies = [
"cc",
"libc",
@@ -388,9 +447,9 @@ dependencies = [
[[package]]
name = "libz-sys"
-version = "1.1.18"
+version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e"
+checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d"
dependencies = [
"cc",
"libc",
@@ -410,9 +469,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.21"
+version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
@@ -431,20 +490,22 @@ dependencies = [
[[package]]
name = "mmtk"
-version = "0.30.0"
-source = "git+https://github.com/mmtk/mmtk-core.git?rev=051bc7470feef915c445305301e6113f86d3957b#051bc7470feef915c445305301e6113f86d3957b"
+version = "0.31.0"
+source = "git+https://github.com/mmtk/mmtk-core.git?rev=c6317a3f1c262e33fc2e427e4cc999c17bcc4791#c6317a3f1c262e33fc2e427e4cc999c17bcc4791"
dependencies = [
"atomic",
"atomic-traits",
"atomic_refcell",
"built",
"bytemuck",
+ "bytemuck_derive",
"cfg-if",
"crossbeam",
"delegate",
"downcast-rs",
"enum-map",
"env_logger",
+ "idna_adapter",
"is-terminal",
"itertools",
"lazy_static",
@@ -456,24 +517,25 @@ dependencies = [
"num_cpus",
"portable-atomic",
"probe",
+ "rayon-core",
"regex",
"rustversion",
"spin",
"static_assertions",
"strum",
"strum_macros",
- "sysinfo 0.30.12",
+ "sysinfo 0.33.1",
]
[[package]]
name = "mmtk-macros"
-version = "0.30.0"
-source = "git+https://github.com/mmtk/mmtk-core.git?rev=051bc7470feef915c445305301e6113f86d3957b#051bc7470feef915c445305301e6113f86d3957b"
+version = "0.31.0"
+source = "git+https://github.com/mmtk/mmtk-core.git?rev=c6317a3f1c262e33fc2e427e4cc999c17bcc4791#c6317a3f1c262e33fc2e427e4cc999c17bcc4791"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
@@ -487,7 +549,7 @@ dependencies = [
"mmtk",
"once_cell",
"probe",
- "sysinfo 0.32.0",
+ "sysinfo 0.32.1",
]
[[package]]
@@ -514,15 +576,21 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.3.9",
"libc",
]
[[package]]
name = "once_cell"
-version = "1.19.0"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "percent-encoding"
@@ -532,15 +600,24 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pkg-config"
-version = "0.3.30"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "portable-atomic"
-version = "1.6.0"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
[[package]]
name = "probe"
@@ -574,23 +651,29 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.36"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -612,9 +695,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.10.5"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -624,9 +707,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -635,24 +718,24 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc_version"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
-version = "1.0.17"
+version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "scopeguard"
@@ -662,9 +745,41 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
-version = "1.0.23"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "smallvec"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
[[package]]
name = "spin"
@@ -683,21 +798,21 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strum"
-version = "0.26.3"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
[[package]]
name = "strum_macros"
-version = "0.26.4"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
@@ -712,9 +827,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.68"
+version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
@@ -723,38 +838,37 @@ dependencies = [
[[package]]
name = "sysinfo"
-version = "0.30.12"
+version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae"
+checksum = "4c33cd241af0f2e9e3b5c32163b873b29956890b5342e6745b917ce9d490f4af"
dependencies = [
- "cfg-if",
"core-foundation-sys",
"libc",
+ "memchr",
"ntapi",
- "once_cell",
"rayon",
- "windows 0.52.0",
+ "windows",
]
[[package]]
name = "sysinfo"
-version = "0.32.0"
+version = "0.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
+checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
dependencies = [
"core-foundation-sys",
"libc",
"memchr",
"ntapi",
"rayon",
- "windows 0.57.0",
+ "windows",
]
[[package]]
name = "tinyvec"
-version = "1.6.0"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
dependencies = [
"tinyvec_macros",
]
@@ -767,30 +881,36 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "unicode-bidi"
-version = "0.3.15"
+version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-joining-type"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "d8d00a78170970967fdb83f9d49b92f959ab2bb829186b113e4f4604ad98e180"
[[package]]
name = "unicode-normalization"
-version = "0.1.23"
+version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
dependencies = [
"tinyvec",
]
[[package]]
name = "url"
-version = "2.5.2"
+version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
@@ -798,6 +918,12 @@ dependencies = [
]
[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -811,9 +937,18 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
[[package]]
name = "winapi"
@@ -839,30 +974,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
-dependencies = [
- "windows-core 0.52.0",
- "windows-targets",
-]
-
-[[package]]
-name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
- "windows-core 0.57.0",
- "windows-targets",
-]
-
-[[package]]
-name = "windows-core"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-dependencies = [
+ "windows-core",
"windows-targets",
]
@@ -886,7 +1002,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
@@ -897,7 +1013,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.68",
+ "syn 2.0.101",
]
[[package]]
@@ -911,18 +1027,18 @@ dependencies = [
[[package]]
name = "windows-sys"
-version = "0.52.0"
+version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
@@ -936,48 +1052,57 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
diff --git a/gc/mmtk/Cargo.toml b/gc/mmtk/Cargo.toml
index 66af77fe61..d856122900 100644
--- a/gc/mmtk/Cargo.toml
+++ b/gc/mmtk/Cargo.toml
@@ -21,11 +21,11 @@ probe = "0.5"
sysinfo = "0.32.0"
[dependencies.mmtk]
-features = ["is_mmtk_object", "object_pinning", "sticky_immix_non_moving_nursery", "immix_non_moving"]
+features = ["is_mmtk_object", "object_pinning", "sticky_immix_non_moving_nursery"]
# Uncomment the following lines to use mmtk-core from the official repository.
git = "https://github.com/mmtk/mmtk-core.git"
-rev = "051bc7470feef915c445305301e6113f86d3957b"
+rev = "c6317a3f1c262e33fc2e427e4cc999c17bcc4791"
# Uncomment the following line to use mmtk-core from a local repository.
# path = "../../../mmtk-core"
@@ -35,3 +35,8 @@ default = []
# When moving an object, clear its original copy.
clear_old_copy = []
+
+# Enable extra assertions in release build. For debugging.
+extra_assert = []
+
+[workspace]
diff --git a/gc/mmtk/cbindgen.toml b/gc/mmtk/cbindgen.toml
index c66f829b3d..b99c30efc8 100644
--- a/gc/mmtk/cbindgen.toml
+++ b/gc/mmtk/cbindgen.toml
@@ -20,6 +20,11 @@ typedef void *MMTk_Address;
typedef void *MMTk_ObjectReference;
typedef void *MMTk_NullableObjectReference;
typedef uint32_t MMTk_AllocationSemantics;
+
+typedef struct MMTk_BumpPointer {
+ uintptr_t cursor;
+ uintptr_t limit;
+} MMTk_BumpPointer;
"""
[export]
diff --git a/gc/mmtk/extconf.rb b/gc/mmtk/extconf.rb
index 5f4228972b..c0e788037e 100644
--- a/gc/mmtk/extconf.rb
+++ b/gc/mmtk/extconf.rb
@@ -15,6 +15,10 @@ create_gc_makefile("mmtk") do |makefile|
MMTK_BUILD = debug
LIBMMTK_RUBY = libmmtk_ruby.#$LIBEXT
RUSTSRCS = #{rustsrcs.join(" \\\n\t ")}
+
+ ifeq ($(MMTK_BUILD), debug)
+ CPPFLAGS += -DMMTK_DEBUG
+ endif
MAKEFILE
]
end
diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c
index 93d50fe729..95176b692b 100644
--- a/gc/mmtk/mmtk.c
+++ b/gc/mmtk/mmtk.c
@@ -21,13 +21,10 @@ struct objspace {
bool gc_stress;
size_t gc_count;
+ size_t moving_gc_count;
size_t total_gc_time;
size_t total_allocated_objects;
- st_table *id_to_obj_tbl;
- st_table *obj_to_id_tbl;
- unsigned long long next_object_id;
-
st_table *finalizer_table;
struct MMTk_final_job *finalizer_jobs;
rb_postponed_job_handle_t finalizer_postponed_job;
@@ -36,19 +33,38 @@ struct objspace {
unsigned long live_ractor_cache_count;
pthread_mutex_t mutex;
+ rb_atomic_t mutator_blocking_count;
bool world_stopped;
pthread_cond_t cond_world_stopped;
pthread_cond_t cond_world_started;
size_t start_the_world_count;
+ pthread_mutex_t event_hook_mutex;
+
+ struct {
+ bool gc_thread_crashed;
+ char crash_msg[256];
+ } crash_context;
+
struct rb_gc_vm_context vm_context;
+
+ unsigned int fork_hook_vm_lock_lev;
};
+#define OBJ_FREE_BUF_CAPACITY 128
+
struct MMTk_ractor_cache {
struct ccan_list_node list_node;
MMTk_Mutator *mutator;
bool gc_mutator_p;
+
+ MMTk_BumpPointer *bump_pointer;
+
+ MMTk_ObjectReference obj_free_parallel_buf[OBJ_FREE_BUF_CAPACITY];
+ size_t obj_free_parallel_count;
+ MMTk_ObjectReference obj_free_non_parallel_buf[OBJ_FREE_BUF_CAPACITY];
+ size_t obj_free_non_parallel_count;
};
struct MMTk_final_job {
@@ -63,7 +79,7 @@ struct MMTk_final_job {
void *data;
} dfree;
struct {
- VALUE object_id;
+ /* HACK: we store the object ID on the 0th element of this array. */
VALUE finalizer_array;
} finalize;
} as;
@@ -71,12 +87,22 @@ struct MMTk_final_job {
#ifdef RB_THREAD_LOCAL_SPECIFIER
RB_THREAD_LOCAL_SPECIFIER struct MMTk_GCThreadTLS *rb_mmtk_gc_thread_tls;
+
+RB_THREAD_LOCAL_SPECIFIER VALUE marking_parent_object;
#else
# error We currently need language-supported TLS
#endif
+#ifdef MMTK_DEBUG
+# define MMTK_ASSERT(expr, ...) RUBY_ASSERT_ALWAYS(expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+#else
+# define MMTK_ASSERT(expr, ...) ((void)0)
+#endif
+
#include <pthread.h>
+static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);
+
static void
rb_mmtk_init_gc_worker_thread(MMTk_VMWorkerThread gc_thread_tls)
{
@@ -109,7 +135,7 @@ rb_mmtk_stop_the_world(void)
}
static void
-rb_mmtk_resume_mutators(void)
+rb_mmtk_resume_mutators(bool current_gc_may_move)
{
struct objspace *objspace = rb_gc_get_objspace();
@@ -120,6 +146,7 @@ rb_mmtk_resume_mutators(void)
objspace->world_stopped = false;
objspace->gc_count++;
+ if (current_gc_may_move) objspace->moving_gc_count++;
pthread_cond_broadcast(&objspace->cond_world_started);
if ((err = pthread_mutex_unlock(&objspace->mutex)) != 0) {
@@ -127,13 +154,17 @@ rb_mmtk_resume_mutators(void)
}
}
+static void mmtk_flush_obj_free_buffer(struct MMTk_ractor_cache *cache);
+
static void
rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
{
struct objspace *objspace = rb_gc_get_objspace();
size_t starting_gc_count = objspace->gc_count;
- int lock_lev = rb_gc_vm_lock();
+ RUBY_ATOMIC_INC(objspace->mutator_blocking_count);
+ int lock_lev = RB_GC_VM_LOCK();
+ RUBY_ATOMIC_DEC(objspace->mutator_blocking_count);
int err;
if ((err = pthread_mutex_lock(&objspace->mutex)) != 0) {
rb_bug("ERROR: cannot lock objspace->mutex: %s", strerror(err));
@@ -155,6 +186,11 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
rb_gc_vm_barrier();
+ struct MMTk_ractor_cache *rc;
+ ccan_list_for_each(&objspace->ractor_caches, rc, list_node) {
+ mmtk_flush_obj_free_buffer(rc);
+ }
+
objspace->world_stopped = true;
pthread_cond_broadcast(&objspace->cond_world_stopped);
@@ -164,6 +200,10 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
pthread_cond_wait(&objspace->cond_world_started, &objspace->mutex);
}
+ if (RB_UNLIKELY(objspace->crash_context.gc_thread_crashed)) {
+ rb_bug("%s", objspace->crash_context.crash_msg);
+ }
+
if (objspace->measure_gc_time) {
struct timespec gc_end_time;
clock_gettime(CLOCK_MONOTONIC, &gc_end_time);
@@ -177,7 +217,19 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
if ((err = pthread_mutex_unlock(&objspace->mutex)) != 0) {
rb_bug("ERROR: cannot release objspace->mutex: %s", strerror(err));
}
- rb_gc_vm_unlock(lock_lev);
+ RB_GC_VM_UNLOCK(lock_lev);
+}
+
+static void
+rb_mmtk_before_updating_jit_code(void)
+{
+ rb_gc_before_updating_jit_code();
+}
+
+static void
+rb_mmtk_after_updating_jit_code(void)
+{
+ rb_gc_after_updating_jit_code();
}
static size_t
@@ -191,9 +243,7 @@ static void
rb_mmtk_get_mutators(void (*visit_mutator)(MMTk_Mutator *mutator, void *data), void *data)
{
struct objspace *objspace = rb_gc_get_objspace();
-
struct MMTk_ractor_cache *ractor_cache;
- RUBY_ASSERT(ractor_cache != NULL);
ccan_list_for_each(&objspace->ractor_caches, ractor_cache, list_node) {
visit_mutator(ractor_cache->mutator, data);
@@ -203,7 +253,9 @@ rb_mmtk_get_mutators(void (*visit_mutator)(MMTk_Mutator *mutator, void *data), v
static void
rb_mmtk_scan_gc_roots(void)
{
- // rb_gc_mark_roots(rb_gc_get_objspace(), NULL);
+ struct objspace *objspace = rb_gc_get_objspace();
+
+ rb_gc_mark_roots(objspace, NULL);
}
static int
@@ -223,15 +275,12 @@ rb_mmtk_scan_objspace(void)
st_foreach(objspace->finalizer_table, pin_value, (st_data_t)objspace);
}
- st_foreach(objspace->obj_to_id_tbl, gc_mark_tbl_no_pin_i, (st_data_t)objspace);
-
struct MMTk_final_job *job = objspace->finalizer_jobs;
while (job != NULL) {
switch (job->kind) {
case MMTK_FINAL_JOB_DFREE:
break;
case MMTK_FINAL_JOB_FINALIZE:
- rb_gc_impl_mark(objspace, job->as.finalize.object_id);
rb_gc_impl_mark(objspace, job->as.finalize.finalizer_array);
break;
default:
@@ -243,27 +292,45 @@ rb_mmtk_scan_objspace(void)
}
static void
-rb_mmtk_scan_roots_in_mutator_thread(MMTk_VMMutatorThread mutator, MMTk_VMWorkerThread worker)
+rb_mmtk_move_obj_during_marking(MMTk_ObjectReference from, MMTk_ObjectReference to)
{
- if (mutator->gc_mutator_p) {
- struct objspace *objspace = rb_gc_get_objspace();
+ rb_gc_move_obj_during_marking((VALUE)from, (VALUE)to);
+}
+
+static void
+rb_mmtk_update_object_references(MMTk_ObjectReference mmtk_object)
+{
+ VALUE object = (VALUE)mmtk_object;
- rb_gc_worker_thread_set_vm_context(&objspace->vm_context);
- rb_gc_mark_roots(objspace, NULL);
- rb_gc_worker_thread_unset_vm_context(&objspace->vm_context);
+ if (!RB_FL_TEST(object, RUBY_FL_WEAK_REFERENCE)) {
+ marking_parent_object = object;
+ rb_gc_update_object_references(rb_gc_get_objspace(), object);
+ marking_parent_object = 0;
}
}
static void
-rb_mmtk_scan_object_ruby_style(MMTk_ObjectReference object)
+rb_mmtk_call_gc_mark_children(MMTk_ObjectReference object)
{
+ marking_parent_object = (VALUE)object;
rb_gc_mark_children(rb_gc_get_objspace(), (VALUE)object);
+ marking_parent_object = 0;
}
static void
-rb_mmtk_call_gc_mark_children(MMTk_ObjectReference object)
+rb_mmtk_handle_weak_references(MMTk_ObjectReference mmtk_object, bool moving)
{
- rb_gc_mark_children(rb_gc_get_objspace(), (VALUE)object);
+ VALUE object = (VALUE)mmtk_object;
+
+ marking_parent_object = object;
+
+ rb_gc_handle_weak_references(object);
+
+ if (moving) {
+ rb_gc_update_object_references(rb_gc_get_objspace(), object);
+ }
+
+ marking_parent_object = 0;
}
static void
@@ -273,12 +340,16 @@ rb_mmtk_call_obj_free(MMTk_ObjectReference object)
struct objspace *objspace = rb_gc_get_objspace();
if (RB_UNLIKELY(rb_gc_event_hook_required_p(RUBY_INTERNAL_EVENT_FREEOBJ))) {
- rb_gc_worker_thread_set_vm_context(&objspace->vm_context);
+ pthread_mutex_lock(&objspace->event_hook_mutex);
rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_FREEOBJ);
- rb_gc_worker_thread_unset_vm_context(&objspace->vm_context);
+ pthread_mutex_unlock(&objspace->event_hook_mutex);
}
rb_gc_obj_free(objspace, obj);
+
+#ifdef MMTK_DEBUG
+ memset((void *)obj, 0, rb_gc_impl_obj_slot_size(obj));
+#endif
}
static size_t
@@ -290,31 +361,34 @@ rb_mmtk_vm_live_bytes(void)
static void
make_final_job(struct objspace *objspace, VALUE obj, VALUE table)
{
- RUBY_ASSERT(RB_FL_TEST(obj, RUBY_FL_FINALIZE));
- RUBY_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)table));
- RUBY_ASSERT(RB_BUILTIN_TYPE(table) == T_ARRAY);
-
- RB_FL_UNSET(obj, RUBY_FL_FINALIZE);
+ MMTK_ASSERT(RB_BUILTIN_TYPE(table) == T_ARRAY);
struct MMTk_final_job *job = xmalloc(sizeof(struct MMTk_final_job));
job->next = objspace->finalizer_jobs;
job->kind = MMTK_FINAL_JOB_FINALIZE;
- job->as.finalize.object_id = rb_obj_id((VALUE)obj);
job->as.finalize.finalizer_array = table;
objspace->finalizer_jobs = job;
}
static int
-rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data)
+rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data, int error)
{
- RUBY_ASSERT(RB_FL_TEST(key, RUBY_FL_FINALIZE));
- RUBY_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)value));
- RUBY_ASSERT(RB_BUILTIN_TYPE(value) == T_ARRAY);
+ MMTK_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)value));
+ MMTK_ASSERT(RB_BUILTIN_TYPE(value) == T_ARRAY);
struct objspace *objspace = (struct objspace *)data;
- if (!mmtk_is_reachable((MMTk_ObjectReference)key)) {
+ if (mmtk_is_reachable((MMTk_ObjectReference)key)) {
+ VALUE new_key_location = rb_mmtk_call_object_closure((VALUE)key, false);
+
+ MMTK_ASSERT(RB_FL_TEST(new_key_location, RUBY_FL_FINALIZE));
+
+ if (new_key_location != key) {
+ return ST_REPLACE;
+ }
+ }
+ else {
make_final_job(objspace, (VALUE)key, (VALUE)value);
rb_postponed_job_trigger(objspace->finalizer_postponed_job);
@@ -325,70 +399,119 @@ rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data)
return ST_CONTINUE;
}
+static int
+rb_mmtk_update_finalizer_table_replace_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
+{
+ *key = rb_mmtk_call_object_closure((VALUE)*key, false);
+
+ return ST_CONTINUE;
+}
+
static void
rb_mmtk_update_finalizer_table(void)
{
struct objspace *objspace = rb_gc_get_objspace();
- // TODO: replace with st_foreach_with_replace when GC is moving
- st_foreach(objspace->finalizer_table, rb_mmtk_update_finalizer_table_i, (st_data_t)objspace);
+ st_foreach_with_replace(
+ objspace->finalizer_table,
+ rb_mmtk_update_finalizer_table_i,
+ rb_mmtk_update_finalizer_table_replace_i,
+ (st_data_t)objspace
+ );
+}
+
+static int
+rb_mmtk_global_tables_count(void)
+{
+ return RB_GC_VM_WEAK_TABLE_COUNT;
}
+static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);
+
static int
-rb_mmtk_update_table_i(VALUE val, void *data)
+rb_mmtk_update_global_tables_i(VALUE val, void *data)
{
if (!mmtk_is_reachable((MMTk_ObjectReference)val)) {
return ST_DELETE;
}
+ // TODO: check only if in moving GC
+ if (rb_mmtk_call_object_closure(val, false) != val) {
+ return ST_REPLACE;
+ }
+
return ST_CONTINUE;
}
static int
-rb_mmtk_update_obj_id_tables_obj_to_id_i(st_data_t key, st_data_t val, st_data_t data)
+rb_mmtk_update_global_tables_replace_i(VALUE *ptr, void *data)
{
- RUBY_ASSERT(RB_FL_TEST(key, FL_SEEN_OBJ_ID));
-
- if (!mmtk_is_reachable((MMTk_ObjectReference)key)) {
- return ST_DELETE;
- }
+ // TODO: cache the new location so we don't call rb_mmtk_call_object_closure twice
+ *ptr = rb_mmtk_call_object_closure(*ptr, false);
return ST_CONTINUE;
}
-static int
-rb_mmtk_update_obj_id_tables_id_to_obj_i(st_data_t key, st_data_t val, st_data_t data)
+static void
+rb_mmtk_update_global_tables(int table, bool moving)
{
- RUBY_ASSERT(RB_FL_TEST(val, FL_SEEN_OBJ_ID));
+ MMTK_ASSERT(table < RB_GC_VM_WEAK_TABLE_COUNT);
- if (!mmtk_is_reachable((MMTk_ObjectReference)val)) {
- return ST_DELETE;
- }
+ rb_gc_vm_weak_table_foreach(
+ rb_mmtk_update_global_tables_i,
+ rb_mmtk_update_global_tables_replace_i,
+ NULL,
+ !moving,
+ (enum rb_gc_vm_weak_tables)table
+ );
+}
- return ST_CONTINUE;
+static bool
+rb_mmtk_special_const_p(MMTk_ObjectReference object)
+{
+ VALUE obj = (VALUE)object;
+
+ return RB_SPECIAL_CONST_P(obj);
}
+RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
+RBIMPL_ATTR_NORETURN()
static void
-rb_mmtk_update_obj_id_tables(void)
+rb_mmtk_gc_thread_bug(const char *msg, ...)
{
struct objspace *objspace = rb_gc_get_objspace();
- st_foreach(objspace->obj_to_id_tbl, rb_mmtk_update_obj_id_tables_obj_to_id_i, 0);
- st_foreach(objspace->id_to_obj_tbl, rb_mmtk_update_obj_id_tables_id_to_obj_i, 0);
+ objspace->crash_context.gc_thread_crashed = true;
+
+ va_list args;
+ va_start(args, msg);
+ vsnprintf(objspace->crash_context.crash_msg, sizeof(objspace->crash_context.crash_msg), msg, args);
+ va_end(args);
+
+ fprintf(stderr, "-- GC thread backtrace "
+ "-------------------------------------------\n");
+ rb_gc_print_backtrace();
+ fprintf(stderr, "\n");
+
+ rb_mmtk_resume_mutators(false);
+
+ sleep(5);
+
+ rb_bug("rb_mmtk_gc_thread_bug");
}
-static int
-rb_mmtk_global_tables_count(void)
+RBIMPL_ATTR_NORETURN()
+static void
+rb_mmtk_gc_thread_panic_handler(void)
{
- return RB_GC_VM_WEAK_TABLE_COUNT;
+ rb_mmtk_gc_thread_bug("MMTk GC thread panicked");
}
+RBIMPL_ATTR_NORETURN()
static void
-rb_mmtk_update_global_tables(int table)
+rb_mmtk_mutator_thread_panic_handler(void)
{
- RUBY_ASSERT(table < RB_GC_VM_WEAK_TABLE_COUNT);
-
- rb_gc_vm_weak_table_foreach(rb_mmtk_update_table_i, NULL, NULL, true, (enum rb_gc_vm_weak_tables)table);
+ rb_bug("Ruby mutator thread panicked");
}
// Bootup
@@ -398,19 +521,24 @@ MMTk_RubyUpcalls ruby_upcalls = {
rb_mmtk_stop_the_world,
rb_mmtk_resume_mutators,
rb_mmtk_block_for_gc,
+ rb_mmtk_before_updating_jit_code,
+ rb_mmtk_after_updating_jit_code,
rb_mmtk_number_of_mutators,
rb_mmtk_get_mutators,
rb_mmtk_scan_gc_roots,
rb_mmtk_scan_objspace,
- rb_mmtk_scan_roots_in_mutator_thread,
- rb_mmtk_scan_object_ruby_style,
+ rb_mmtk_move_obj_during_marking,
+ rb_mmtk_update_object_references,
rb_mmtk_call_gc_mark_children,
+ rb_mmtk_handle_weak_references,
rb_mmtk_call_obj_free,
rb_mmtk_vm_live_bytes,
rb_mmtk_update_global_tables,
rb_mmtk_global_tables_count,
rb_mmtk_update_finalizer_table,
- rb_mmtk_update_obj_id_tables,
+ rb_mmtk_special_const_p,
+ rb_mmtk_mutator_thread_panic_handler,
+ rb_mmtk_gc_thread_panic_handler,
};
// Use max 80% of the available memory by default for MMTk
@@ -434,12 +562,14 @@ void *
rb_gc_impl_objspace_alloc(void)
{
MMTk_Builder *builder = rb_mmtk_builder_init();
- mmtk_init_binding(builder, NULL, &ruby_upcalls, (MMTk_ObjectReference)Qundef);
+ MMTk_RubyBindingOptions binding_options = {
+ .suffix_size = RB_GC_OBJ_SUFFIX_SIZE,
+ };
+ mmtk_init_binding(builder, &binding_options, &ruby_upcalls);
return calloc(1, sizeof(struct objspace));
}
-static void objspace_obj_id_init(struct objspace *objspace);
static void gc_run_finalizers(void *data);
void
@@ -449,8 +579,6 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
objspace->measure_gc_time = true;
- objspace_obj_id_init(objspace);
-
objspace->finalizer_table = st_init_numtable();
objspace->finalizer_postponed_job = rb_postponed_job_preregister(0, gc_run_finalizers, objspace);
@@ -459,6 +587,8 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
objspace->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
objspace->cond_world_stopped = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
objspace->cond_world_started = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
+
+ objspace->event_hook_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
}
void
@@ -476,10 +606,11 @@ rb_gc_impl_ractor_cache_alloc(void *objspace_ptr, void *ractor)
}
objspace->live_ractor_cache_count++;
- struct MMTk_ractor_cache *cache = malloc(sizeof(struct MMTk_ractor_cache));
+ struct MMTk_ractor_cache *cache = calloc(1, sizeof(struct MMTk_ractor_cache));
ccan_list_add(&objspace->ractor_caches, &cache->list_node);
cache->mutator = mmtk_bind_mutator(cache);
+ cache->bump_pointer = mmtk_get_bump_pointer_allocator(cache->mutator);
return cache;
}
@@ -492,7 +623,15 @@ rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache_ptr)
ccan_list_del(&cache->list_node);
- RUBY_ASSERT(objspace->live_ractor_cache_count > 1);
+ mmtk_flush_obj_free_buffer(cache);
+
+ if (ruby_free_at_exit_p()) {
+ MMTK_ASSERT(objspace->live_ractor_cache_count > 0);
+ }
+ else {
+ MMTK_ASSERT(objspace->live_ractor_cache_count > 1);
+ }
+
objspace->live_ractor_cache_count--;
mmtk_destroy_mutator(cache->mutator);
@@ -502,15 +641,31 @@ void rb_gc_impl_set_params(void *objspace_ptr) { }
static VALUE gc_verify_internal_consistency(VALUE self) { return Qnil; }
+#if SIZEOF_VALUE >= 8
+#define MMTK_HEAP_COUNT 12
+#define MMTK_MAX_OBJ_SIZE 1024
+static size_t heap_sizes[MMTK_HEAP_COUNT + 1] = {
+ 32, 40, 64, 80, 96, 128, 160, 256, 512, 640, 768, MMTK_MAX_OBJ_SIZE, 0
+};
+#else
+#define MMTK_HEAP_COUNT 5
+#define MMTK_MAX_OBJ_SIZE 512
+static size_t heap_sizes[MMTK_HEAP_COUNT + 1] = {
+ 32, 64, 128, 256, MMTK_MAX_OBJ_SIZE, 0
+};
+#endif
+
void
rb_gc_impl_init(void)
{
VALUE gc_constants = rb_hash_new();
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(sizeof(VALUE) * 5));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(SIZEOF_VALUE >= 8 ? 64 : 32));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(640));
- // Pretend we have 5 size pools
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(5));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MMTK_MAX_OBJ_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_COUNT")), LONG2FIX(MMTK_HEAP_COUNT));
+ // TODO: correctly set RVALUE_OLD_AGE when we have generational GC support
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(0));
OBJ_FREEZE(gc_constants);
rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
@@ -524,10 +679,6 @@ rb_gc_impl_init(void)
rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
}
-static size_t heap_sizes[6] = {
- 40, 80, 160, 320, 640, 0
-};
-
size_t *
rb_gc_impl_heap_sizes(void *objspace_ptr)
{
@@ -568,8 +719,8 @@ rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool i
bool
rb_gc_impl_during_gc_p(void *objspace_ptr)
{
- // TODO
- return false;
+ struct objspace *objspace = objspace_ptr;
+ return objspace->world_stopped;
}
static void
@@ -639,17 +790,106 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
// TODO
}
+struct rb_gc_vm_context *
+rb_gc_impl_get_vm_context(void *objspace_ptr)
+{
+ struct objspace *objspace = objspace_ptr;
+
+ return &objspace->vm_context;
+}
+
// Object allocation
+static VALUE
+rb_mmtk_alloc_fast_path(struct objspace *objspace, struct MMTk_ractor_cache *ractor_cache, size_t size, size_t align)
+{
+ MMTk_BumpPointer *bump_pointer = ractor_cache->bump_pointer;
+ if (bump_pointer == NULL) return 0;
+
+ uintptr_t cursor = bump_pointer->cursor;
+
+ // Ensure cursor is aligned
+ size_t mask = align - 1;
+ cursor = (cursor + mask) & ~mask;
+
+ cursor += size;
+
+ if (cursor > bump_pointer->limit) {
+ return 0;
+ }
+ else {
+ VALUE obj = cursor - size;
+ bump_pointer->cursor = cursor;
+ return obj;
+ }
+}
+
+static bool
+obj_can_parallel_free_p(VALUE obj)
+{
+ switch (RB_BUILTIN_TYPE(obj)) {
+ case T_ARRAY:
+ case T_BIGNUM:
+ case T_COMPLEX:
+ case T_FLOAT:
+ case T_HASH:
+ case T_OBJECT:
+ case T_RATIONAL:
+ case T_REGEXP:
+ case T_STRING:
+ case T_STRUCT:
+ case T_SYMBOL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void
+mmtk_flush_obj_free_buffer(struct MMTk_ractor_cache *cache)
+{
+ if (cache->obj_free_parallel_count > 0) {
+ mmtk_add_obj_free_candidates(cache->obj_free_parallel_buf,
+ cache->obj_free_parallel_count, true);
+ cache->obj_free_parallel_count = 0;
+ }
+ if (cache->obj_free_non_parallel_count > 0) {
+ mmtk_add_obj_free_candidates(cache->obj_free_non_parallel_buf,
+ cache->obj_free_non_parallel_count, false);
+ cache->obj_free_non_parallel_count = 0;
+ }
+}
+
+static inline void
+mmtk_buffer_obj_free_candidate(struct MMTk_ractor_cache *cache, VALUE obj)
+{
+ if (obj_can_parallel_free_p(obj)) {
+ cache->obj_free_parallel_buf[cache->obj_free_parallel_count++] = (MMTk_ObjectReference)obj;
+ if (cache->obj_free_parallel_count >= OBJ_FREE_BUF_CAPACITY) {
+ mmtk_add_obj_free_candidates(cache->obj_free_parallel_buf,
+ cache->obj_free_parallel_count, true);
+ cache->obj_free_parallel_count = 0;
+ }
+ }
+ else {
+ cache->obj_free_non_parallel_buf[cache->obj_free_non_parallel_count++] = (MMTk_ObjectReference)obj;
+ if (cache->obj_free_non_parallel_count >= OBJ_FREE_BUF_CAPACITY) {
+ mmtk_add_obj_free_candidates(cache->obj_free_non_parallel_buf,
+ cache->obj_free_non_parallel_count, false);
+ cache->obj_free_non_parallel_count = 0;
+ }
+ }
+}
+
VALUE
-rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size)
+rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
{
#define MMTK_ALLOCATION_SEMANTICS_DEFAULT 0
struct objspace *objspace = objspace_ptr;
struct MMTk_ractor_cache *ractor_cache = cache_ptr;
- if (alloc_size > 640) rb_bug("too big");
- for (int i = 0; i < 5; i++) {
+ if (alloc_size > MMTK_MAX_OBJ_SIZE) rb_bug("too big");
+ for (int i = 0; i < MMTK_HEAP_COUNT; i++) {
if (alloc_size == heap_sizes[i]) break;
if (alloc_size < heap_sizes[i]) {
alloc_size = heap_sizes[i];
@@ -661,19 +901,24 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
mmtk_handle_user_collection_request(ractor_cache, false, false);
}
- VALUE *alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size + 8, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
+ // Layout: [hidden size header (sizeof(VALUE))][payload (alloc_size)][suffix (RB_GC_OBJ_SUFFIX_SIZE)]
+ alloc_size += sizeof(VALUE) + RB_GC_OBJ_SUFFIX_SIZE;
+
+ VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, alloc_size, MMTk_MIN_OBJ_ALIGN);
+ if (!alloc_obj) {
+ alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
+ }
+
alloc_obj++;
- alloc_obj[-1] = alloc_size;
+ alloc_obj[-1] = alloc_size - sizeof(VALUE) - RB_GC_OBJ_SUFFIX_SIZE;
alloc_obj[0] = flags;
alloc_obj[1] = klass;
- if (alloc_size > 16) alloc_obj[2] = v1;
- if (alloc_size > 24) alloc_obj[3] = v2;
- if (alloc_size > 32) alloc_obj[4] = v3;
- mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size + 8, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
+ // TODO: implement fast path for mmtk_post_alloc
+ mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
// TODO: only add when object needs obj_free to be called
- mmtk_add_obj_free_candidate(alloc_obj);
+ mmtk_buffer_obj_free_candidate(ractor_cache, (VALUE)alloc_obj);
objspace->total_allocated_objects++;
@@ -689,7 +934,7 @@ rb_gc_impl_obj_slot_size(VALUE obj)
size_t
rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
{
- for (int i = 0; i < 5; i++) {
+ for (int i = 0; i < MMTK_HEAP_COUNT; i++) {
if (size == heap_sizes[i]) return i;
if (size < heap_sizes[i]) return i;
}
@@ -700,26 +945,26 @@ rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
bool
rb_gc_impl_size_allocatable_p(size_t size)
{
- return size <= 640;
+ return size <= MMTK_MAX_OBJ_SIZE;
}
// Malloc
void *
-rb_gc_impl_malloc(void *objspace_ptr, size_t size)
+rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
// TODO: don't use system malloc
return malloc(size);
}
void *
-rb_gc_impl_calloc(void *objspace_ptr, size_t size)
+rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed)
{
// TODO: don't use system calloc
return calloc(1, size);
}
void *
-rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size)
+rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed)
{
// TODO: don't use system realloc
return realloc(ptr, new_size);
@@ -735,15 +980,34 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff) { }
// Marking
+static inline VALUE
+rb_mmtk_call_object_closure(VALUE obj, bool pin)
+{
+ if (RB_UNLIKELY(RB_BUILTIN_TYPE(obj) == T_NONE)) {
+ enum { info_size = 256 };
+ char obj_info_buf[info_size];
+ rb_raw_obj_info(obj_info_buf, info_size, obj);
+
+ char parent_obj_info_buf[info_size];
+ rb_raw_obj_info(parent_obj_info_buf, info_size, marking_parent_object);
+
+ rb_mmtk_gc_thread_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf);
+ }
+
+ return (VALUE)rb_mmtk_gc_thread_tls->object_closure.c_function(
+ rb_mmtk_gc_thread_tls->object_closure.rust_closure,
+ rb_mmtk_gc_thread_tls->gc_context,
+ (MMTk_ObjectReference)obj,
+ pin
+ );
+}
+
void
rb_gc_impl_mark(void *objspace_ptr, VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) return;
- rb_mmtk_gc_thread_tls->object_closure.c_function(rb_mmtk_gc_thread_tls->object_closure.rust_closure,
- rb_mmtk_gc_thread_tls->gc_context,
- (MMTk_ObjectReference)obj,
- false);
+ rb_mmtk_call_object_closure(obj, false);
}
void
@@ -751,8 +1015,10 @@ rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
{
if (RB_SPECIAL_CONST_P(*ptr)) return;
- // TODO: make it movable
- rb_gc_impl_mark(objspace_ptr, *ptr);
+ VALUE new_obj = rb_mmtk_call_object_closure(*ptr, false);
+ if (new_obj != *ptr) {
+ *ptr = new_obj;
+ }
}
void
@@ -760,8 +1026,7 @@ rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) return;
- // TODO: also pin
- rb_gc_impl_mark(objspace_ptr, obj);
+ rb_mmtk_call_object_closure(obj, true);
}
void
@@ -773,28 +1038,35 @@ rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
}
void
-rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
+rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
{
- mmtk_mark_weak((MMTk_ObjectReference *)ptr);
+ RB_FL_SET(obj, RUBY_FL_WEAK_REFERENCE);
+ mmtk_declare_weak_references((MMTk_ObjectReference)obj);
}
-void
-rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr)
+bool
+rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
{
- mmtk_remove_weak((MMTk_ObjectReference *)ptr);
+ return mmtk_weak_references_alive_p((MMTk_ObjectReference)obj);
}
// Compaction
+void
+rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
+{
+ mmtk_register_pinning_obj((MMTk_ObjectReference)obj);
+}
+
bool
rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
{
- rb_bug("unimplemented");
+ return rb_mmtk_call_object_closure(obj, false) != obj;
}
VALUE
-rb_gc_impl_location(void *objspace_ptr, VALUE value)
+rb_gc_impl_location(void *objspace_ptr, VALUE obj)
{
- rb_bug("unimplemented");
+ return rb_mmtk_call_object_closure(obj, false);
}
// Write barriers
@@ -803,6 +1075,23 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
{
struct MMTk_ractor_cache *cache = rb_gc_get_ractor_newobj_cache();
+ if (SPECIAL_CONST_P(b)) return;
+
+#ifdef MMTK_DEBUG
+ if (!rb_gc_impl_pointer_to_heap_p(objspace_ptr, (void *)a)) {
+ char buff[256];
+ rb_bug("a: %s is not an object", rb_raw_obj_info(buff, 256, a));
+ }
+
+ if (!rb_gc_impl_pointer_to_heap_p(objspace_ptr, (void *)b)) {
+ char buff[256];
+ rb_bug("b: %s is not an object", rb_raw_obj_info(buff, 256, b));
+ }
+#endif
+
+ MMTK_ASSERT(BUILTIN_TYPE(a) != T_NONE);
+ MMTK_ASSERT(BUILTIN_TYPE(b) != T_NONE);
+
mmtk_object_reference_write_post(cache->mutator, (MMTk_ObjectReference)a);
}
@@ -907,7 +1196,7 @@ gc_run_finalizers_get_final(long i, void *data)
{
VALUE table = (VALUE)data;
- return RARRAY_AREF(table, i);
+ return RARRAY_AREF(table, i + 1);
}
static void
@@ -926,17 +1215,15 @@ gc_run_finalizers(void *data)
job->as.dfree.func(job->as.dfree.data);
break;
case MMTK_FINAL_JOB_FINALIZE: {
- VALUE object_id = job->as.finalize.object_id;
VALUE finalizer_array = job->as.finalize.finalizer_array;
rb_gc_run_obj_finalizer(
- job->as.finalize.object_id,
- RARRAY_LEN(finalizer_array),
+ RARRAY_AREF(finalizer_array, 0),
+ RARRAY_LEN(finalizer_array) - 1,
gc_run_finalizers_get_final,
(void *)finalizer_array
);
- RB_GC_GUARD(object_id);
RB_GC_GUARD(finalizer_array);
break;
}
@@ -980,6 +1267,8 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
RBASIC(obj)->flags |= FL_FINALIZE;
+ int lev = RB_GC_VM_LOCK();
+
if (st_lookup(objspace->finalizer_table, obj, &data)) {
table = (VALUE)data;
@@ -991,6 +1280,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
for (i = 0; i < len; i++) {
VALUE recv = RARRAY_AREF(table, i);
if (rb_equal(recv, block)) {
+ RB_GC_VM_UNLOCK(lev);
return recv;
}
}
@@ -999,11 +1289,13 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
rb_ary_push(table, block);
}
else {
- table = rb_ary_new3(1, block);
+ table = rb_ary_new3(2, rb_obj_id(obj), block);
rb_obj_hide(table);
st_add_direct(objspace->finalizer_table, obj, table);
}
+ RB_GC_VM_UNLOCK(lev);
+
return block;
}
@@ -1013,7 +1305,11 @@ rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
struct objspace *objspace = objspace_ptr;
st_data_t data = obj;
+
+ int lev = RB_GC_VM_LOCK();
st_delete(objspace->finalizer_table, &data, 0);
+ RB_GC_VM_UNLOCK(lev);
+
FL_UNSET(obj, FL_FINALIZE);
}
@@ -1026,14 +1322,17 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
if (!FL_TEST(obj, FL_FINALIZE)) return;
+ int lev = RB_GC_VM_LOCK();
if (RB_LIKELY(st_lookup(objspace->finalizer_table, obj, &data))) {
- table = (VALUE)data;
+ table = rb_ary_dup((VALUE)data);
+ RARRAY_ASET(table, 0, rb_obj_id(dest));
st_insert(objspace->finalizer_table, dest, table);
FL_SET(dest, FL_FINALIZE);
}
else {
rb_bug("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s", rb_obj_info(obj));
}
+ RB_GC_VM_UNLOCK(lev);
}
static int
@@ -1057,102 +1356,27 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
gc_run_finalizers(objspace);
}
- struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
- for (size_t i = 0; i < registered_candidates.len; i++) {
- VALUE obj = (VALUE)registered_candidates.ptr[i];
-
- if (rb_gc_shutdown_call_finalizer_p(obj)) {
- rb_gc_obj_free(objspace_ptr, obj);
- RBASIC(obj)->flags = 0;
+ unsigned int lev = RB_GC_VM_LOCK();
+ {
+ struct MMTk_ractor_cache *rc;
+ ccan_list_for_each(&objspace->ractor_caches, rc, list_node) {
+ mmtk_flush_obj_free_buffer(rc);
}
- }
- mmtk_free_raw_vec_of_obj_ref(registered_candidates);
-
- gc_run_finalizers(objspace);
-}
-// Object ID
-static int
-object_id_cmp(st_data_t x, st_data_t y)
-{
- if (RB_TYPE_P(x, T_BIGNUM)) {
- return !rb_big_eql(x, y);
- }
- else {
- return x != y;
- }
-}
+ struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates();
+ for (size_t i = 0; i < registered_candidates.len; i++) {
+ VALUE obj = (VALUE)registered_candidates.ptr[i];
-static st_index_t
-object_id_hash(st_data_t n)
-{
- return FIX2LONG(rb_hash((VALUE)n));
-}
-
-#define OBJ_ID_INCREMENT (RUBY_IMMEDIATE_MASK + 1)
-#define OBJ_ID_INITIAL (OBJ_ID_INCREMENT)
-
-static const struct st_hash_type object_id_hash_type = {
- object_id_cmp,
- object_id_hash,
-};
-
-static void
-objspace_obj_id_init(struct objspace *objspace)
-{
- objspace->id_to_obj_tbl = st_init_table(&object_id_hash_type);
- objspace->obj_to_id_tbl = st_init_numtable();
- objspace->next_object_id = OBJ_ID_INITIAL;
-}
-
-VALUE
-rb_gc_impl_object_id(void *objspace_ptr, VALUE obj)
-{
- VALUE id;
- struct objspace *objspace = objspace_ptr;
-
- unsigned int lev = rb_gc_vm_lock();
- if (FL_TEST(obj, FL_SEEN_OBJ_ID)) {
- st_data_t val;
- if (st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, &val)) {
- id = (VALUE)val;
- }
- else {
- rb_bug("rb_gc_impl_object_id: FL_SEEN_OBJ_ID flag set but not found in table");
+ if (rb_gc_shutdown_call_finalizer_p(obj)) {
+ rb_gc_obj_free(objspace_ptr, obj);
+ RBASIC(obj)->flags = 0;
+ }
}
+ mmtk_free_raw_vec_of_obj_ref(registered_candidates);
}
- else {
- RUBY_ASSERT(!st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, NULL));
-
- id = ULL2NUM(objspace->next_object_id);
- objspace->next_object_id += OBJ_ID_INCREMENT;
-
- st_insert(objspace->obj_to_id_tbl, (st_data_t)obj, (st_data_t)id);
- st_insert(objspace->id_to_obj_tbl, (st_data_t)id, (st_data_t)obj);
- FL_SET(obj, FL_SEEN_OBJ_ID);
- }
- rb_gc_vm_unlock(lev);
-
- return id;
-}
-
-VALUE
-rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id)
-{
- struct objspace *objspace = objspace_ptr;
-
- VALUE obj;
- if (st_lookup(objspace->id_to_obj_tbl, object_id, &obj) &&
- !rb_gc_impl_garbage_object_p(objspace, obj)) {
- return obj;
- }
+ RB_GC_VM_UNLOCK(lev);
- if (rb_funcall(object_id, rb_intern(">="), 1, ULL2NUM(objspace->next_object_id))) {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not id value", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
- }
- else {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is recycled object", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
- }
+ gc_run_finalizers(objspace);
}
// Forking
@@ -1160,13 +1384,39 @@ rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id)
void
rb_gc_impl_before_fork(void *objspace_ptr)
{
+ struct objspace *objspace = objspace_ptr;
+
+ retry:
+ objspace->fork_hook_vm_lock_lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+
+ /* At this point, we know that all the Ractors are paused because of the
+ * rb_gc_vm_barrier above. Since rb_mmtk_block_for_gc is a barrier point,
+ * one or more Ractors could be paused there. However, mmtk_before_fork is
+ * not compatible with that because it assumes that the MMTk workers are idle,
+ * but the workers are not idle because they are busy working on a GC.
+ *
+ * This essentially implements a trylock. It will optimistically lock but will
+ * release the lock if it detects that any other Ractors are waiting in
+ * rb_mmtk_block_for_gc.
+ */
+ rb_atomic_t mutator_blocking_count = RUBY_ATOMIC_LOAD(objspace->mutator_blocking_count);
+ if (mutator_blocking_count != 0) {
+ RB_GC_VM_UNLOCK(objspace->fork_hook_vm_lock_lev);
+ goto retry;
+ }
+
mmtk_before_fork();
}
void
rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
{
+ struct objspace *objspace = objspace_ptr;
+
mmtk_after_fork(rb_gc_get_ractor_newobj_cache());
+
+ RB_GC_VM_UNLOCK(objspace->fork_hook_vm_lock_lev);
}
// Statistics
@@ -1239,6 +1489,7 @@ rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE hash_or_key)
enum gc_stat_sym {
gc_stat_sym_count,
+ gc_stat_sym_moving_gc_count,
gc_stat_sym_time,
gc_stat_sym_total_allocated_objects,
gc_stat_sym_total_bytes,
@@ -1246,6 +1497,7 @@ enum gc_stat_sym {
gc_stat_sym_free_bytes,
gc_stat_sym_starting_heap_address,
gc_stat_sym_last_heap_address,
+ gc_stat_sym_weak_references_count,
gc_stat_sym_last
};
@@ -1257,6 +1509,7 @@ setup_gc_stat_symbols(void)
if (gc_stat_symbols[0] == 0) {
#define S(s) gc_stat_symbols[gc_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
S(count);
+ S(moving_gc_count);
S(time);
S(total_allocated_objects);
S(total_bytes);
@@ -1264,6 +1517,7 @@ setup_gc_stat_symbols(void)
S(free_bytes);
S(starting_heap_address);
S(last_heap_address);
+ S(weak_references_count);
}
}
@@ -1292,6 +1546,7 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
SET(count, objspace->gc_count);
+ SET(moving_gc_count, objspace->moving_gc_count);
SET(time, objspace->total_gc_time / (1000 * 1000));
SET(total_allocated_objects, objspace->total_allocated_objects);
SET(total_bytes, mmtk_total_bytes());
@@ -1299,6 +1554,7 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
SET(free_bytes, mmtk_free_bytes());
SET(starting_heap_address, (size_t)mmtk_starting_heap_address());
SET(last_heap_address, (size_t)mmtk_last_heap_address());
+ SET(weak_references_count, mmtk_weak_references_count());
#undef SET
if (!NIL_P(key)) {
@@ -1312,12 +1568,24 @@ rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
VALUE
rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
{
+ if (FIXNUM_P(heap_name) && SYMBOL_P(hash_or_sym)) {
+ int heap_idx = FIX2INT(heap_name);
+ if (heap_idx < 0 || heap_idx >= MMTK_HEAP_COUNT) {
+ rb_raise(rb_eArgError, "size pool index out of range");
+ }
+
+ if (hash_or_sym == ID2SYM(rb_intern("slot_size"))) {
+ return SIZET2NUM(heap_sizes[heap_idx]);
+ }
+
+ return Qundef;
+ }
+
if (RB_TYPE_P(hash_or_sym, T_HASH)) {
return hash_or_sym;
}
- else {
- return Qundef;
- }
+
+ return Qundef;
}
// Miscellaneous
@@ -1339,13 +1607,13 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
size_t n = 0;
#define SET_ENTRY(na, v) do { \
- RUBY_ASSERT(n <= RB_GC_OBJECT_METADATA_ENTRY_COUNT); \
+ MMTK_ASSERT(n <= RB_GC_OBJECT_METADATA_ENTRY_COUNT); \
object_metadata_entries[n].name = ID_##na; \
object_metadata_entries[n].val = v; \
n++; \
} while (0)
- if (FL_TEST(obj, FL_SEEN_OBJ_ID)) SET_ENTRY(object_id, rb_obj_id(obj));
+ if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));
object_metadata_entries[n].name = 0;
object_metadata_entries[n].val = 0;
diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h
index 614b832af5..b11e2873e3 100644
--- a/gc/mmtk/mmtk.h
+++ b/gc/mmtk/mmtk.h
@@ -20,6 +20,11 @@ typedef void *MMTk_ObjectReference;
typedef void *MMTk_NullableObjectReference;
typedef uint32_t MMTk_AllocationSemantics;
+typedef struct MMTk_BumpPointer {
+ uintptr_t cursor;
+ uintptr_t limit;
+} MMTk_BumpPointer;
+
#define MMTk_OBJREF_OFFSET 8
@@ -28,7 +33,6 @@ typedef uint32_t MMTk_AllocationSemantics;
#define MMTk_GC_THREAD_KIND_WORKER 1
typedef struct MMTk_RubyBindingOptions {
- bool ractor_check_mode;
size_t suffix_size;
} MMTk_RubyBindingOptions;
@@ -55,22 +59,26 @@ typedef struct MMTk_RubyUpcalls {
void (*init_gc_worker_thread)(struct MMTk_GCThreadTLS *gc_worker_tls);
bool (*is_mutator)(void);
void (*stop_the_world)(void);
- void (*resume_mutators)(void);
+ void (*resume_mutators)(bool gc_may_move);
void (*block_for_gc)(MMTk_VMMutatorThread tls);
+ void (*before_updating_jit_code)(void);
+ void (*after_updating_jit_code)(void);
size_t (*number_of_mutators)(void);
void (*get_mutators)(void (*visit_mutator)(MMTk_Mutator*, void*), void *data);
void (*scan_gc_roots)(void);
void (*scan_objspace)(void);
- void (*scan_roots_in_mutator_thread)(MMTk_VMMutatorThread mutator_tls,
- MMTk_VMWorkerThread worker_tls);
- void (*scan_object_ruby_style)(MMTk_ObjectReference object);
+ void (*move_obj_during_marking)(MMTk_ObjectReference from, MMTk_ObjectReference to);
+ void (*update_object_references)(MMTk_ObjectReference object);
void (*call_gc_mark_children)(MMTk_ObjectReference object);
+ void (*handle_weak_references)(MMTk_ObjectReference object, bool moving);
void (*call_obj_free)(MMTk_ObjectReference object);
size_t (*vm_live_bytes)(void);
- void (*update_global_tables)(int tbl_idx);
+ void (*update_global_tables)(int tbl_idx, bool moving);
int (*global_tables_count)(void);
void (*update_finalizer_table)(void);
- void (*update_obj_id_tables)(void);
+ bool (*special_const_p)(MMTk_ObjectReference object);
+ void (*mutator_thread_panic_handler)(void);
+ void (*gc_thread_panic_handler)(void);
} MMTk_RubyUpcalls;
typedef struct MMTk_RawVecOfObjRef {
@@ -86,14 +94,15 @@ bool mmtk_is_reachable(MMTk_ObjectReference object);
MMTk_Builder *mmtk_builder_default(void);
void mmtk_init_binding(MMTk_Builder *builder,
- const struct MMTk_RubyBindingOptions *_binding_options,
- const struct MMTk_RubyUpcalls *upcalls,
- MMTk_ObjectReference weak_reference_dead_value);
+ const struct MMTk_RubyBindingOptions *binding_options,
+ const struct MMTk_RubyUpcalls *upcalls);
void mmtk_initialize_collection(MMTk_VMThread tls);
MMTk_Mutator *mmtk_bind_mutator(MMTk_VMMutatorThread tls);
+MMTk_BumpPointer *mmtk_get_bump_pointer_allocator(MMTk_Mutator *m);
+
void mmtk_destroy_mutator(MMTk_Mutator *mutator);
void mmtk_handle_user_collection_request(MMTk_VMMutatorThread tls, bool force, bool exhaustive);
@@ -113,11 +122,17 @@ void mmtk_post_alloc(MMTk_Mutator *mutator,
size_t bytes,
MMTk_AllocationSemantics semantics);
-void mmtk_add_obj_free_candidate(MMTk_ObjectReference object);
+void mmtk_add_obj_free_candidates(const MMTk_ObjectReference *objects,
+ size_t count,
+ bool can_parallel_free);
+
+void mmtk_declare_weak_references(MMTk_ObjectReference object);
+
+bool mmtk_weak_references_alive_p(MMTk_ObjectReference object);
-void mmtk_mark_weak(MMTk_ObjectReference *ptr);
+size_t mmtk_weak_references_count(void);
-void mmtk_remove_weak(const MMTk_ObjectReference *ptr);
+void mmtk_register_pinning_obj(MMTk_ObjectReference obj);
void mmtk_object_reference_write_post(MMTk_Mutator *mutator, MMTk_ObjectReference object);
diff --git a/gc/mmtk/src/abi.rs b/gc/mmtk/src/abi.rs
index fc9c899743..30890e0853 100644
--- a/gc/mmtk/src/abi.rs
+++ b/gc/mmtk/src/abi.rs
@@ -1,8 +1,12 @@
use crate::api::RubyMutator;
+use crate::extra_assert;
use crate::Ruby;
use libc::c_int;
use mmtk::scheduler::GCWorker;
-use mmtk::util::{Address, ObjectReference, VMMutatorThread, VMWorkerThread};
+use mmtk::util::Address;
+use mmtk::util::ObjectReference;
+use mmtk::util::VMMutatorThread;
+use mmtk::util::VMWorkerThread;
// For the C binding
pub const OBJREF_OFFSET: usize = 8;
@@ -10,16 +14,38 @@ pub const MIN_OBJ_ALIGN: usize = 8; // Even on 32-bit machine. A Ruby object is
pub const GC_THREAD_KIND_WORKER: libc::c_int = 1;
-const HAS_MOVED_GIVTBL: usize = 1 << 63;
const HIDDEN_SIZE_MASK: usize = 0x0000FFFFFFFFFFFF;
-// Should keep in sync with C code.
-const RUBY_FL_EXIVAR: usize = 1 << 10;
-
// An opaque type for the C counterpart.
#[allow(non_camel_case_types)]
pub struct st_table;
+#[repr(C)]
+pub struct HiddenHeader {
+ pub prefix: usize,
+}
+
+impl HiddenHeader {
+ #[inline(always)]
+ pub fn is_sane(&self) -> bool {
+ self.prefix & !HIDDEN_SIZE_MASK == 0
+ }
+
+ #[inline(always)]
+ fn assert_sane(&self) {
+ extra_assert!(
+ self.is_sane(),
+ "Hidden header is corrupted: {:x}",
+ self.prefix
+ );
+ }
+
+ pub fn payload_size(&self) -> usize {
+ self.assert_sane();
+ self.prefix & HIDDEN_SIZE_MASK
+ }
+}
+
/// Provide convenient methods for accessing Ruby objects.
/// TODO: Wrap C functions in `RubyUpcalls` as Rust-friendly methods.
pub struct RubyObjectAccess {
@@ -47,32 +73,17 @@ impl RubyObjectAccess {
self.suffix_addr() + Self::suffix_size()
}
- fn hidden_field(&self) -> Address {
- self.obj_start()
- }
-
- fn load_hidden_field(&self) -> usize {
- unsafe { self.hidden_field().load::<usize>() }
+ fn hidden_header(&self) -> &'static HiddenHeader {
+ unsafe { self.obj_start().as_ref() }
}
- fn update_hidden_field<F>(&self, f: F)
- where
- F: FnOnce(usize) -> usize,
- {
- let old_value = self.load_hidden_field();
- let new_value = f(old_value);
- unsafe {
- self.hidden_field().store(new_value);
- }
+ #[allow(unused)] // Maybe we need to mutate the hidden header in the future.
+ fn hidden_header_mut(&self) -> &'static mut HiddenHeader {
+ unsafe { self.obj_start().as_mut_ref() }
}
pub fn payload_size(&self) -> usize {
- self.load_hidden_field() & HIDDEN_SIZE_MASK
- }
-
- pub fn set_payload_size(&self, size: usize) {
- debug_assert!((size & HIDDEN_SIZE_MASK) == size);
- self.update_hidden_field(|old| old & !HIDDEN_SIZE_MASK | size & HIDDEN_SIZE_MASK);
+ self.hidden_header().payload_size()
}
fn flags_field(&self) -> Address {
@@ -83,22 +94,6 @@ impl RubyObjectAccess {
unsafe { self.flags_field().load::<usize>() }
}
- pub fn has_exivar_flag(&self) -> bool {
- (self.load_flags() & RUBY_FL_EXIVAR) != 0
- }
-
- pub fn has_moved_givtbl(&self) -> bool {
- (self.load_hidden_field() & HAS_MOVED_GIVTBL) != 0
- }
-
- pub fn set_has_moved_givtbl(&self) {
- self.update_hidden_field(|old| old | HAS_MOVED_GIVTBL)
- }
-
- pub fn clear_has_moved_givtbl(&self) {
- self.update_hidden_field(|old| old & !HAS_MOVED_GIVTBL)
- }
-
pub fn prefix_size() -> usize {
// Currently, a hidden size field of word size is placed before each object.
OBJREF_OFFSET
@@ -232,7 +227,7 @@ impl GCThreadTLS {
/// Has undefined behavior if `ptr` is invalid.
pub unsafe fn check_cast(ptr: *mut GCThreadTLS) -> &'static mut GCThreadTLS {
assert!(!ptr.is_null());
- let result = &mut *ptr;
+ let result = unsafe { &mut *ptr };
debug_assert!({
let kind = result.kind;
kind == GC_THREAD_KIND_WORKER
@@ -247,7 +242,7 @@ impl GCThreadTLS {
/// Has undefined behavior if `ptr` is invalid.
pub unsafe fn from_vwt_check(vwt: VMWorkerThread) -> &'static mut GCThreadTLS {
let ptr = Self::from_vwt(vwt);
- Self::check_cast(ptr)
+ unsafe { Self::check_cast(ptr) }
}
#[allow(clippy::not_unsafe_ptr_arg_deref)] // `transmute` does not dereference pointer
@@ -283,7 +278,7 @@ impl RawVecOfObjRef {
///
/// This function turns raw pointer into a Vec without check.
pub unsafe fn into_vec(self) -> Vec<ObjectReference> {
- Vec::from_raw_parts(self.ptr, self.len, self.capa)
+ unsafe { Vec::from_raw_parts(self.ptr, self.len, self.capa) }
}
}
@@ -296,7 +291,6 @@ impl From<Vec<ObjectReference>> for RawVecOfObjRef {
#[repr(C)]
#[derive(Clone)]
pub struct RubyBindingOptions {
- pub ractor_check_mode: bool,
pub suffix_size: usize,
}
@@ -306,8 +300,10 @@ pub struct RubyUpcalls {
pub init_gc_worker_thread: extern "C" fn(gc_worker_tls: *mut GCThreadTLS),
pub is_mutator: extern "C" fn() -> bool,
pub stop_the_world: extern "C" fn(),
- pub resume_mutators: extern "C" fn(),
+ pub resume_mutators: extern "C" fn(gc_may_move: bool),
pub block_for_gc: extern "C" fn(tls: VMMutatorThread),
+ pub before_updating_jit_code: extern "C" fn(),
+ pub after_updating_jit_code: extern "C" fn(),
pub number_of_mutators: extern "C" fn() -> usize,
pub get_mutators: extern "C" fn(
visit_mutator: extern "C" fn(*mut RubyMutator, *mut libc::c_void),
@@ -315,16 +311,18 @@ pub struct RubyUpcalls {
),
pub scan_gc_roots: extern "C" fn(),
pub scan_objspace: extern "C" fn(),
- pub scan_roots_in_mutator_thread:
- extern "C" fn(mutator_tls: VMMutatorThread, worker_tls: VMWorkerThread),
- pub scan_object_ruby_style: extern "C" fn(object: ObjectReference),
+ pub move_obj_during_marking: extern "C" fn(from: ObjectReference, to: ObjectReference),
+ pub update_object_references: extern "C" fn(object: ObjectReference),
pub call_gc_mark_children: extern "C" fn(object: ObjectReference),
+ pub handle_weak_references: extern "C" fn(object: ObjectReference, moving: bool),
pub call_obj_free: extern "C" fn(object: ObjectReference),
pub vm_live_bytes: extern "C" fn() -> usize,
- pub update_global_tables: extern "C" fn(tbl_idx: c_int),
+ pub update_global_tables: extern "C" fn(tbl_idx: c_int, moving: bool),
pub global_tables_count: extern "C" fn() -> c_int,
pub update_finalizer_table: extern "C" fn(),
- pub update_obj_id_tables: extern "C" fn(),
+ pub special_const_p: extern "C" fn(object: ObjectReference) -> bool,
+ pub mutator_thread_panic_handler: extern "C" fn(),
+ pub gc_thread_panic_handler: extern "C" fn(),
}
unsafe impl Sync for RubyUpcalls {}
diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs
index c15996727e..c0540fe0c8 100644
--- a/gc/mmtk/src/api.rs
+++ b/gc/mmtk/src/api.rs
@@ -1,16 +1,28 @@
-use std::sync::atomic::Ordering;
+// Functions in this module are unsafe for one reason:
+// They are called by C functions and they need to pass raw pointers to Rust.
+#![allow(clippy::missing_safety_doc)]
+
+use mmtk::util::alloc::BumpPointer;
+use mmtk::util::alloc::ImmixAllocator;
+use mmtk::util::conversions;
use mmtk::util::options::PlanSelector;
+use std::str::FromStr;
+use std::sync::atomic::Ordering;
use crate::abi::RawVecOfObjRef;
use crate::abi::RubyBindingOptions;
use crate::abi::RubyUpcalls;
use crate::binding;
use crate::binding::RubyBinding;
+use crate::heap::CpuHeapTriggerConfig;
+use crate::heap::RubyHeapTriggerConfig;
+use crate::heap::CPU_HEAP_TRIGGER_CONFIG;
+use crate::heap::RUBY_HEAP_TRIGGER_CONFIG;
use crate::mmtk;
-use crate::Ruby;
-use crate::RubySlot;
use crate::utils::default_heap_max;
use crate::utils::parse_capacity;
+use crate::Ruby;
+use crate::RubySlot;
use mmtk::memory_manager;
use mmtk::memory_manager::mmtk_init;
use mmtk::util::constants::MIN_OBJECT_SIZE;
@@ -37,73 +49,139 @@ pub extern "C" fn mmtk_is_reachable(object: ObjectReference) -> bool {
// =============== Bootup ===============
-fn mmtk_builder_default_parse_threads() -> usize {
- let threads_str = std::env::var("MMTK_THREADS")
- .unwrap_or("0".to_string());
-
- threads_str
- .parse::<usize>()
- .unwrap_or_else(|_err| {
- eprintln!("[FATAL] Invalid MMTK_THREADS {}", threads_str);
+fn parse_env_var_with<T, F: FnOnce(&str) -> Option<T>>(key: &str, parse: F) -> Option<T> {
+ let val = match std::env::var(key) {
+ Ok(val) => val,
+ Err(std::env::VarError::NotPresent) => return None,
+ Err(std::env::VarError::NotUnicode(os_string)) => {
+ eprintln!("[FATAL] Invalid {key} {os_string:?}");
std::process::exit(1);
- })
-}
+ }
+ };
-fn mmtk_builder_default_parse_heap_min() -> usize {
- const DEFAULT_HEAP_MIN: usize = 1 << 20;
+ let parsed = parse(&val).unwrap_or_else(|| {
+ eprintln!("[FATAL] Invalid {key} {val}");
+ std::process::exit(1);
+ });
- let heap_min_str = std::env::var("MMTK_HEAP_MIN")
- .unwrap_or(DEFAULT_HEAP_MIN.to_string());
+ Some(parsed)
+}
- let size = parse_capacity(&heap_min_str, 0);
- if size == 0 {
- eprintln!("[FATAL] Invalid MMTK_HEAP_MIN {}", heap_min_str);
- std::process::exit(1);
- }
+fn parse_env_var<T: FromStr>(key: &str) -> Option<T> {
+ parse_env_var_with(key, |s| s.parse().ok())
+}
- size
+fn mmtk_builder_default_parse_threads() -> Option<usize> {
+ parse_env_var("MMTK_THREADS")
+}
+
+fn mmtk_builder_default_parse_heap_min() -> usize {
+ const DEFAULT_HEAP_MIN: usize = 1 << 20;
+ parse_env_var_with("MMTK_HEAP_MIN", parse_capacity).unwrap_or(DEFAULT_HEAP_MIN)
}
fn mmtk_builder_default_parse_heap_max() -> usize {
- let heap_max_str = std::env::var("MMTK_HEAP_MAX")
- .unwrap_or(default_heap_max().to_string());
+ parse_env_var_with("MMTK_HEAP_MAX", parse_capacity).unwrap_or_else(default_heap_max)
+}
- let size = parse_capacity(&heap_max_str, 0);
- if size == 0 {
- eprintln!("[FATAL] Invalid MMTK_HEAP_MAX {}", heap_max_str);
- std::process::exit(1);
- }
+fn parse_float_env_var(key: &str, default: f64, min: f64, max: f64) -> f64 {
+ parse_env_var_with(key, |s| {
+ let mut float = f64::from_str(s).unwrap_or(default);
+
+ if float <= min {
+ eprintln!(
+ "{key} has value {float} which must be greater than {min}, using default instead"
+ );
+ float = default;
+ }
- size
+ if float >= max {
+ eprintln!(
+ "{key} has value {float} which must be less than {max}, using default instead"
+ );
+ float = default;
+ }
+
+ Some(float)
+ })
+ .unwrap_or(default)
}
fn mmtk_builder_default_parse_heap_mode(heap_min: usize, heap_max: usize) -> GCTriggerSelector {
- let heap_mode_str = std::env::var("MMTK_HEAP_MODE")
- .unwrap_or("dynamic".to_string());
-
- match heap_mode_str.as_str() {
- "fixed" => GCTriggerSelector::FixedHeapSize(heap_max),
- "dynamic" => GCTriggerSelector::DynamicHeapSize(heap_min, heap_max),
- _ => {
- eprintln!("[FATAL] Invalid MMTK_HEAP_MODE {}", heap_mode_str);
- std::process::exit(1);
+ let make_fixed = || GCTriggerSelector::FixedHeapSize(heap_max);
+ let make_dynamic = || GCTriggerSelector::DynamicHeapSize(heap_min, heap_max);
+
+ parse_env_var_with("MMTK_HEAP_MODE", |s| match s {
+ "fixed" => Some(make_fixed()),
+ "dynamic" => Some(make_dynamic()),
+ "ruby" => {
+ let min_ratio = parse_float_env_var("RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO", 0.2, 0.0, 1.0);
+ let goal_ratio =
+ parse_float_env_var("RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO", 0.4, min_ratio, 1.0);
+ let max_ratio =
+ parse_float_env_var("RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO", 0.65, goal_ratio, 1.0);
+
+ crate::heap::RUBY_HEAP_TRIGGER_CONFIG
+ .set(RubyHeapTriggerConfig {
+ min_heap_pages: conversions::bytes_to_pages_up(heap_min),
+ max_heap_pages: conversions::bytes_to_pages_up(heap_max),
+ heap_pages_min_ratio: min_ratio,
+ heap_pages_goal_ratio: goal_ratio,
+ heap_pages_max_ratio: max_ratio,
+ })
+ .unwrap_or_else(|_| panic!("RUBY_HEAP_TRIGGER_CONFIG is already set"));
+
+ Some(GCTriggerSelector::Delegated)
}
- }
+ "cpu" => {
+ // CPU-overhead-driven heap sizing based on Tavakolisomeh et al.,
+ // "Heap Size Adjustment with CPU Control", MPLR '23.
+ //
+ // Target is expressed as a percentage (0, 100) via
+ // `MMTK_GC_CPU_TARGET`. The paper recommends 15 for ZGC (a
+ // concurrent collector); we default to 5 for MMTk-Ruby. With
+ // MMTk's stop-the-world Immix, every percent of GC CPU is also
+ // a percent of wall-clock the mutator is blocked on, so a much
+ // smaller budget is appropriate. An empirical sweep across
+ // ruby-bench (railsbench, lobsters, psych-load, liquid-render,
+ // lee) found target=5 to be Pareto-optimal: ~6% geomean speedup
+ // vs. the `ruby` heap mode with effectively identical geomean
+ // peak RSS.
+ let target_percent = parse_float_env_var("MMTK_GC_CPU_TARGET", 5.0, 0.0, 100.0);
+ let window_size = parse_env_var::<usize>("MMTK_GC_CPU_WINDOW").unwrap_or(3);
+ let window_size = window_size.max(1);
+
+ let min_heap_pages = conversions::bytes_to_pages_up(heap_min);
+ let max_heap_pages = conversions::bytes_to_pages_up(heap_max);
+ // Start at the min heap size, as the other delegated triggers do.
+ // The control loop will adjust from here after the first GC cycle.
+ let initial_heap_pages = min_heap_pages;
+
+ CPU_HEAP_TRIGGER_CONFIG
+ .set(CpuHeapTriggerConfig {
+ min_heap_pages,
+ max_heap_pages,
+ initial_heap_pages,
+ target_gc_cpu: target_percent / 100.0,
+ window_size,
+ })
+ .unwrap_or_else(|_| panic!("CPU_HEAP_TRIGGER_CONFIG is already set"));
+
+ Some(GCTriggerSelector::Delegated)
+ }
+ _ => None,
+ })
+ .unwrap_or_else(make_dynamic)
}
fn mmtk_builder_default_parse_plan() -> PlanSelector {
- let plan_str = std::env::var("MMTK_PLAN")
- .unwrap_or("Immix".to_string());
-
- match plan_str.as_str() {
- "NoGC" => PlanSelector::NoGC,
- "MarkSweep" => PlanSelector::MarkSweep,
- "Immix" => PlanSelector::Immix,
- _ => {
- eprintln!("[FATAL] Invalid MMTK_PLAN {}", plan_str);
- std::process::exit(1);
- }
- }
+ parse_env_var_with("MMTK_PLAN", |s| match s {
+ "NoGC" => Some(PlanSelector::NoGC),
+ "MarkSweep" => Some(PlanSelector::MarkSweep),
+ "Immix" => Some(PlanSelector::Immix),
+ _ => None,
+ })
+ .unwrap_or(PlanSelector::Immix)
}
#[no_mangle]
@@ -111,9 +189,12 @@ pub extern "C" fn mmtk_builder_default() -> *mut MMTKBuilder {
let mut builder = MMTKBuilder::new_no_env_vars();
builder.options.no_finalizer.set(true);
- let threads = mmtk_builder_default_parse_threads();
- if threads > 0 {
- builder.options.threads.set(threads);
+ if let Some(threads) = mmtk_builder_default_parse_threads() {
+ if !builder.options.threads.set(threads) {
+ // MMTk will validate it and reject 0.
+ eprintln!("[FATAL] Failed to set the number of MMTk threads to {threads}");
+ std::process::exit(1);
+ }
}
let heap_min = mmtk_builder_default_parse_heap_min();
@@ -121,11 +202,14 @@ pub extern "C" fn mmtk_builder_default() -> *mut MMTKBuilder {
let heap_max = mmtk_builder_default_parse_heap_max();
if heap_min >= heap_max {
- eprintln!("[FATAL] MMTK_HEAP_MIN({}) >= MMTK_HEAP_MAX({})", heap_min, heap_max);
+ eprintln!("[FATAL] MMTK_HEAP_MIN({heap_min}) >= MMTK_HEAP_MAX({heap_max})");
std::process::exit(1);
}
- builder.options.gc_trigger.set(mmtk_builder_default_parse_heap_mode(heap_min, heap_max));
+ builder
+ .options
+ .gc_trigger
+ .set(mmtk_builder_default_parse_heap_mode(heap_min, heap_max));
builder.options.plan.set(mmtk_builder_default_parse_plan());
@@ -133,20 +217,26 @@ pub extern "C" fn mmtk_builder_default() -> *mut MMTKBuilder {
}
#[no_mangle]
-pub extern "C" fn mmtk_init_binding(
+pub unsafe extern "C" fn mmtk_init_binding(
builder: *mut MMTKBuilder,
- _binding_options: *const RubyBindingOptions,
+ binding_options: *const RubyBindingOptions,
upcalls: *const RubyUpcalls,
- weak_reference_dead_value: ObjectReference,
) {
+ crate::MUTATOR_THREAD_PANIC_HANDLER
+ .set((unsafe { (*upcalls).clone() }).mutator_thread_panic_handler)
+ .unwrap_or_else(|_| panic!("MUTATOR_THREAD_PANIC_HANDLER is already initialized"));
+
crate::set_panic_hook();
- let builder = unsafe { Box::from_raw(builder) };
- let binding_options = RubyBindingOptions {ractor_check_mode: false, suffix_size: 0};
+ let builder: Box<MMTKBuilder> = unsafe { Box::from_raw(builder) };
+ let binding_options = unsafe { (*binding_options).clone() };
let mmtk_boxed = mmtk_init(&builder);
let mmtk_static = Box::leak(Box::new(mmtk_boxed));
- let binding = RubyBinding::new(mmtk_static, &binding_options, upcalls, weak_reference_dead_value);
+ let mut binding = RubyBinding::new(mmtk_static, &binding_options, upcalls);
+ binding
+ .weak_proc
+ .init_parallel_obj_free_candidates(memory_manager::num_of_workers(binding.mmtk));
crate::BINDING
.set(binding)
@@ -164,7 +254,25 @@ pub extern "C" fn mmtk_bind_mutator(tls: VMMutatorThread) -> *mut RubyMutator {
}
#[no_mangle]
-pub extern "C" fn mmtk_destroy_mutator(mutator: *mut RubyMutator) {
+pub unsafe extern "C" fn mmtk_get_bump_pointer_allocator(m: *mut RubyMutator) -> *mut BumpPointer {
+ match *crate::BINDING.get().unwrap().mmtk.get_options().plan {
+ PlanSelector::Immix => {
+ let mutator: &mut Mutator<Ruby> = unsafe { &mut *m };
+ let allocator =
+ unsafe { mutator.allocator_mut(mmtk::util::alloc::AllocatorSelector::Immix(0)) };
+
+ if let Some(immix_allocator) = allocator.downcast_mut::<ImmixAllocator<Ruby>>() {
+ &mut immix_allocator.bump_pointer as *mut BumpPointer
+ } else {
+ panic!("Failed to get bump pointer allocator");
+ }
+ }
+ _ => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn mmtk_destroy_mutator(mutator: *mut RubyMutator) {
// notify mmtk-core about destroyed mutator
memory_manager::destroy_mutator(unsafe { &mut *mutator });
// turn the ptr back to a box, and let Rust properly reclaim it
@@ -184,7 +292,9 @@ pub extern "C" fn mmtk_handle_user_collection_request(
#[no_mangle]
pub extern "C" fn mmtk_set_gc_enabled(enable: bool) {
- crate::CONFIGURATION.gc_enabled.store(enable, Ordering::Relaxed);
+ crate::CONFIGURATION
+ .gc_enabled
+ .store(enable, Ordering::Relaxed);
}
#[no_mangle]
@@ -195,7 +305,7 @@ pub extern "C" fn mmtk_gc_enabled_p() -> bool {
// =============== Object allocation ===============
#[no_mangle]
-pub extern "C" fn mmtk_alloc(
+pub unsafe extern "C" fn mmtk_alloc(
mutator: *mut RubyMutator,
size: usize,
align: usize,
@@ -213,7 +323,7 @@ pub extern "C" fn mmtk_alloc(
}
#[no_mangle]
-pub extern "C" fn mmtk_post_alloc(
+pub unsafe extern "C" fn mmtk_post_alloc(
mutator: *mut RubyMutator,
refer: ObjectReference,
bytes: usize,
@@ -222,28 +332,46 @@ pub extern "C" fn mmtk_post_alloc(
memory_manager::post_alloc::<Ruby>(unsafe { &mut *mutator }, refer, bytes, semantics)
}
-// TODO: Replace with buffered mmtk_add_obj_free_candidates
#[no_mangle]
-pub extern "C" fn mmtk_add_obj_free_candidate(object: ObjectReference) {
- binding().weak_proc.add_obj_free_candidate(object)
+pub unsafe extern "C" fn mmtk_add_obj_free_candidates(
+ objects: *const ObjectReference,
+ count: usize,
+ can_parallel_free: bool,
+) {
+ let objects = unsafe { std::slice::from_raw_parts(objects, count) };
+ binding()
+ .weak_proc
+ .add_obj_free_candidates_batch(objects, can_parallel_free)
+}
+
+// =============== Weak references ===============
+
+#[no_mangle]
+pub extern "C" fn mmtk_declare_weak_references(object: ObjectReference) {
+ binding().weak_proc.add_weak_reference(object);
}
-// =============== Marking ===============
+#[no_mangle]
+pub extern "C" fn mmtk_weak_references_alive_p(object: ObjectReference) -> bool {
+ object.is_reachable()
+}
#[no_mangle]
-pub extern "C" fn mmtk_mark_weak(ptr: &'static mut ObjectReference) {
- binding().weak_proc.add_weak_reference(ptr);
+pub extern "C" fn mmtk_weak_references_count() -> usize {
+ binding().weak_proc.weak_references_count()
}
+// =============== Compaction ===============
+
#[no_mangle]
-pub extern "C" fn mmtk_remove_weak(ptr: &ObjectReference) {
- binding().weak_proc.remove_weak_reference(ptr);
+pub extern "C" fn mmtk_register_pinning_obj(obj: ObjectReference) {
+ crate::binding().pinning_registry.register(obj);
}
// =============== Write barriers ===============
#[no_mangle]
-pub extern "C" fn mmtk_object_reference_write_post(
+pub unsafe extern "C" fn mmtk_object_reference_write_post(
mutator: *mut RubyMutator,
object: ObjectReference,
) {
@@ -347,7 +475,7 @@ pub extern "C" fn mmtk_plan() -> *const u8 {
PlanSelector::NoGC => NO_GC.as_ptr(),
PlanSelector::MarkSweep => MARK_SWEEP.as_ptr(),
PlanSelector::Immix => IMMIX.as_ptr(),
- _ => panic!("Unknown plan")
+ _ => panic!("Unknown plan"),
}
}
@@ -355,11 +483,21 @@ pub extern "C" fn mmtk_plan() -> *const u8 {
pub extern "C" fn mmtk_heap_mode() -> *const u8 {
static FIXED_HEAP: &[u8] = b"fixed\0";
static DYNAMIC_HEAP: &[u8] = b"dynamic\0";
+ static RUBY_HEAP: &[u8] = b"ruby\0";
+ static CPU_HEAP: &[u8] = b"cpu\0";
match *crate::BINDING.get().unwrap().mmtk.get_options().gc_trigger {
GCTriggerSelector::FixedHeapSize(_) => FIXED_HEAP.as_ptr(),
GCTriggerSelector::DynamicHeapSize(_, _) => DYNAMIC_HEAP.as_ptr(),
- _ => panic!("Unknown heap mode")
+ GCTriggerSelector::Delegated => {
+ // Two delegated triggers exist; disambiguate via the populated
+ // config singleton.
+ if CPU_HEAP_TRIGGER_CONFIG.get().is_some() {
+ CPU_HEAP.as_ptr()
+ } else {
+ RUBY_HEAP.as_ptr()
+ }
+ }
}
}
@@ -368,7 +506,18 @@ pub extern "C" fn mmtk_heap_min() -> usize {
match *crate::BINDING.get().unwrap().mmtk.get_options().gc_trigger {
GCTriggerSelector::FixedHeapSize(_) => 0,
GCTriggerSelector::DynamicHeapSize(min_size, _) => min_size,
- _ => panic!("Unknown heap mode")
+ GCTriggerSelector::Delegated => {
+ if let Some(cfg) = CPU_HEAP_TRIGGER_CONFIG.get() {
+ conversions::pages_to_bytes(cfg.min_heap_pages)
+ } else {
+ conversions::pages_to_bytes(
+ RUBY_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("RUBY_HEAP_TRIGGER_CONFIG not set")
+ .min_heap_pages,
+ )
+ }
+ }
}
}
@@ -377,7 +526,18 @@ pub extern "C" fn mmtk_heap_max() -> usize {
match *crate::BINDING.get().unwrap().mmtk.get_options().gc_trigger {
GCTriggerSelector::FixedHeapSize(max_size) => max_size,
GCTriggerSelector::DynamicHeapSize(_, max_size) => max_size,
- _ => panic!("Unknown heap mode")
+ GCTriggerSelector::Delegated => {
+ if let Some(cfg) = CPU_HEAP_TRIGGER_CONFIG.get() {
+ conversions::pages_to_bytes(cfg.max_heap_pages)
+ } else {
+ conversions::pages_to_bytes(
+ RUBY_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("RUBY_HEAP_TRIGGER_CONFIG not set")
+ .max_heap_pages,
+ )
+ }
+ }
}
}
diff --git a/gc/mmtk/src/binding.rs b/gc/mmtk/src/binding.rs
index e0f8640e1c..36d4a992fd 100644
--- a/gc/mmtk/src/binding.rs
+++ b/gc/mmtk/src/binding.rs
@@ -9,6 +9,7 @@ use mmtk::MMTK;
use crate::abi;
use crate::abi::RubyBindingOptions;
+use crate::pinning_registry::PinningRegistry;
use crate::weak_proc::WeakProcessor;
use crate::Ruby;
@@ -54,10 +55,9 @@ pub struct RubyBinding {
pub upcalls: *const abi::RubyUpcalls,
pub plan_name: Mutex<Option<CString>>,
pub weak_proc: WeakProcessor,
+ pub pinning_registry: PinningRegistry,
pub gc_thread_join_handles: Mutex<Vec<JoinHandle<()>>>,
pub wb_unprotected_objects: Mutex<HashSet<ObjectReference>>,
-
- pub weak_reference_dead_value: ObjectReference,
}
unsafe impl Sync for RubyBinding {}
@@ -68,7 +68,6 @@ impl RubyBinding {
mmtk: &'static MMTK<Ruby>,
binding_options: &RubyBindingOptions,
upcalls: *const abi::RubyUpcalls,
- weak_reference_dead_value: ObjectReference,
) -> Self {
unsafe {
crate::BINDING_FAST.suffix_size = binding_options.suffix_size;
@@ -80,10 +79,9 @@ impl RubyBinding {
upcalls,
plan_name: Mutex::new(None),
weak_proc: WeakProcessor::new(),
+ pinning_registry: PinningRegistry::new(),
gc_thread_join_handles: Default::default(),
wb_unprotected_objects: Default::default(),
-
- weak_reference_dead_value
}
}
@@ -119,7 +117,7 @@ impl RubyBinding {
}
pub fn register_wb_unprotected_object(&self, object: ObjectReference) {
- debug!("Registering WB-unprotected object: {}", object);
+ debug!("Registering WB-unprotected object: {object}");
let mut objects = self.wb_unprotected_objects.lock().unwrap();
objects.insert(object);
}
diff --git a/gc/mmtk/src/collection.rs b/gc/mmtk/src/collection.rs
index 0570b64e3a..648efa4e27 100644
--- a/gc/mmtk/src/collection.rs
+++ b/gc/mmtk/src/collection.rs
@@ -1,14 +1,26 @@
use crate::abi::GCThreadTLS;
use crate::api::RubyMutator;
-use crate::{mmtk, upcalls, Ruby};
+use crate::heap::CpuHeapTrigger;
+use crate::heap::RubyHeapTrigger;
+use crate::heap::CPU_HEAP_TRIGGER_CONFIG;
+use crate::mmtk;
+use crate::upcalls;
+use crate::Ruby;
use mmtk::memory_manager;
use mmtk::scheduler::*;
-use mmtk::util::{VMMutatorThread, VMThread, VMWorkerThread};
-use mmtk::vm::{Collection, GCThreadContext};
+use mmtk::util::heap::GCTriggerPolicy;
+use mmtk::util::VMMutatorThread;
+use mmtk::util::VMThread;
+use mmtk::util::VMWorkerThread;
+use mmtk::vm::Collection;
+use mmtk::vm::GCThreadContext;
+use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::thread;
+static CURRENT_GC_MAY_MOVE: AtomicBool = AtomicBool::new(false);
+
pub struct VMCollection {}
impl Collection<Ruby> for VMCollection {
@@ -16,11 +28,21 @@ impl Collection<Ruby> for VMCollection {
crate::CONFIGURATION.gc_enabled.load(Ordering::Relaxed)
}
- fn stop_all_mutators<F>(_tls: VMWorkerThread, mut mutator_visitor: F)
+ fn stop_all_mutators<F>(tls: VMWorkerThread, mut mutator_visitor: F)
where
F: FnMut(&'static mut mmtk::Mutator<Ruby>),
{
(upcalls().stop_the_world)();
+
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ CURRENT_GC_MAY_MOVE.store(true, Ordering::Relaxed);
+ (upcalls().before_updating_jit_code)();
+ } else {
+ CURRENT_GC_MAY_MOVE.store(false, Ordering::Relaxed);
+ }
+
+ crate::binding().pinning_registry.pin_children(tls);
+
(upcalls().get_mutators)(
Self::notify_mutator_ready::<F>,
&mut mutator_visitor as *mut F as *mut _,
@@ -28,7 +50,13 @@ impl Collection<Ruby> for VMCollection {
}
fn resume_mutators(_tls: VMWorkerThread) {
- (upcalls().resume_mutators)();
+ let current_gc_may_move = CURRENT_GC_MAY_MOVE.load(Ordering::Relaxed);
+
+ if current_gc_may_move {
+ (upcalls().after_updating_jit_code)();
+ }
+
+ (upcalls().resume_mutators)(current_gc_may_move);
}
fn block_for_gc(tls: VMMutatorThread) {
@@ -41,10 +69,7 @@ impl Collection<Ruby> for VMCollection {
.name("MMTk Worker Thread".to_string())
.spawn(move || {
let ordinal = worker.ordinal;
- debug!(
- "Hello! This is MMTk Worker Thread running! ordinal: {}",
- ordinal
- );
+ debug!("Hello! This is MMTk Worker Thread running! ordinal: {ordinal}");
crate::register_gc_thread(thread::current().id());
let ptr_worker = &mut *worker as *mut GCWorker<Ruby>;
let gc_thread_tls =
@@ -55,10 +80,7 @@ impl Collection<Ruby> for VMCollection {
GCThreadTLS::to_vwt(gc_thread_tls),
worker,
);
- debug!(
- "An MMTk Worker Thread is quitting. Good bye! ordinal: {}",
- ordinal
- );
+ debug!("An MMTk Worker Thread is quitting. Good bye! ordinal: {ordinal}");
crate::unregister_gc_thread(thread::current().id());
})
.unwrap(),
@@ -73,6 +95,19 @@ impl Collection<Ruby> for VMCollection {
fn vm_live_bytes() -> usize {
(upcalls().vm_live_bytes)()
}
+
+ fn create_gc_trigger() -> Box<dyn GCTriggerPolicy<Ruby>> {
+ // `GCTriggerSelector::Delegated` is currently used by two different
+ // heap modes: `ruby` (the Ruby-like free-slot ratio trigger) and `cpu`
+ // (the CPU-overhead trigger from Tavakolisomeh et al., MPLR '23).
+ // Which one is active is determined by which `OnceCell` config the
+ // `MMTK_HEAP_MODE` parser populated.
+ if CPU_HEAP_TRIGGER_CONFIG.get().is_some() {
+ Box::new(CpuHeapTrigger::default())
+ } else {
+ Box::new(RubyHeapTrigger::default())
+ }
+ }
}
impl VMCollection {
diff --git a/gc/mmtk/src/heap/cpu_heap_trigger.rs b/gc/mmtk/src/heap/cpu_heap_trigger.rs
new file mode 100644
index 0000000000..ef5a79fe9a
--- /dev/null
+++ b/gc/mmtk/src/heap/cpu_heap_trigger.rs
@@ -0,0 +1,370 @@
+//! A GC trigger that adjusts the heap size based on the CPU overhead of GC.
+//!
+//! This is an implementation of the heap sizing policy described in
+//! Tavakolisomeh, Shimchenko, Österlund, Bruno, Ferreira, Wrigstad,
+//! "Heap Size Adjustment with CPU Control", MPLR '23.
+//! <https://doi.org/10.1145/3617651.3622988>
+//!
+//! The idea: rather than letting heap size control GC frequency, let a
+//! user-supplied *target GC CPU overhead* control the heap size. After each GC
+//! cycle, we measure the GC CPU overhead (fraction of process CPU time spent
+//! in GC) and compare it to the target. If GC is over budget we grow the heap
+//! (reducing GC frequency); if it is under budget we shrink the heap (trading
+//! memory for more frequent collections).
+//!
+//! ## Algorithm
+//!
+//! After each GC cycle we compute, using an average of the last `n` cycles:
+//!
+//! ```text
+//! GC_CPU = T_GC / T_APP (Eq. 1)
+//! overhead_error = GC_CPU - target (Eq. 2)
+//! sigmoid_error = 1 / (1 + e^(-overhead_error)) (Eq. 3)
+//! adjustment_factor = sigmoid_error + 0.5 (in (0.5, 1.5)) (Eq. 4)
+//! new_size = current_size * adjustment_factor (Eq. 5)
+//! ```
+//!
+//! where:
+//! - `T_GC` is the wall-clock duration of each GC cycle.
+//! - `T_APP` is process CPU time elapsed between consecutive GC cycles (sum of
+//! CPU time over all threads — mutators, GC workers, compilers, etc.), read
+//! via `clock_gettime(CLOCK_PROCESS_CPUTIME_ID)`.
+//!
+//! The final heap size is then clamped to the range
+//! `[max(1.1 * used, min_heap_pages), max_heap_pages]`, providing 10% headroom
+//! above current live memory to avoid triggering GC on an effectively-empty
+//! heap.
+//!
+//! ## Differences from the paper
+//!
+//! The paper targets ZGC, a concurrent generational collector. MMTk's Ruby
+//! binding currently ships stop-the-world collectors (Immix, MarkSweep). The
+//! paper's formula still applies: with a STW collector the process CPU time
+//! during GC closely tracks the wall-clock GC time, and mutator CPU time
+//! during the mutator phase is correctly attributed. For generational plans
+//! we skip nursery-only GCs, consistent with MemBalancer.
+
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+use std::sync::Mutex;
+
+use mmtk::util::heap::GCTriggerPolicy;
+use mmtk::util::heap::SpaceStats;
+use mmtk::Plan;
+use mmtk::MMTK;
+use once_cell::sync::OnceCell;
+
+use crate::Ruby;
+
+pub static CPU_HEAP_TRIGGER_CONFIG: OnceCell<CpuHeapTriggerConfig> = OnceCell::new();
+
+/// Configuration for the [`CpuHeapTrigger`].
+pub struct CpuHeapTriggerConfig {
+ /// Lower bound on heap size (in pages). The trigger will never shrink below
+ /// this value.
+ pub min_heap_pages: usize,
+ /// Upper bound on heap size (in pages). The trigger will never grow above
+ /// this value.
+ pub max_heap_pages: usize,
+ /// Initial heap size (in pages).
+ pub initial_heap_pages: usize,
+ /// Target GC CPU overhead as a fraction of total process CPU time. For
+ /// example, `0.15` means the policy will try to keep GC CPU usage near 15%.
+ /// Valid range: `(0.0, 1.0)`.
+ pub target_gc_cpu: f64,
+ /// Number of recent GC cycles averaged together when computing the CPU
+ /// overhead signal. Smoothes out short-term fluctuations. The paper uses 3.
+ pub window_size: usize,
+}
+
+/// A single GC cycle's timing measurements.
+#[derive(Clone, Copy, Debug, Default)]
+struct GcSample {
+ /// Wall-clock seconds spent inside this GC cycle.
+ gc_seconds: f64,
+ /// Seconds of process CPU time elapsed since the previous GC cycle ended.
+ /// This covers both mutator time and (on multi-threaded mutators) any
+ /// mutator CPU time consumed in parallel with the previous GC.
+ app_cpu_seconds: f64,
+}
+
+struct CpuHeapTriggerState {
+ /// Ring buffer of the last `window_size` samples. Oldest-first.
+ samples: Vec<GcSample>,
+ /// Wall-clock time when the current GC cycle started. `None` when no GC is
+ /// in progress.
+ gc_start_wall: Option<std::time::Instant>,
+ /// Process CPU time (seconds) recorded at the end of the previous GC
+ /// cycle. `None` until the first cycle completes.
+ last_gc_end_cpu: Option<f64>,
+}
+
+impl CpuHeapTriggerState {
+ fn new() -> Self {
+ Self {
+ samples: Vec::new(),
+ gc_start_wall: None,
+ last_gc_end_cpu: None,
+ }
+ }
+
+ /// Pushes a new sample, dropping the oldest when the window is full.
+ fn push_sample(&mut self, sample: GcSample, window_size: usize) {
+ if self.samples.len() >= window_size {
+ self.samples.remove(0);
+ }
+ self.samples.push(sample);
+ }
+
+ /// Returns the arithmetic mean GC CPU overhead across the window, or
+ /// `None` if we don't yet have a full sample (which happens on the first
+ /// GC cycle — we have no baseline for `app_cpu_seconds`).
+ fn mean_gc_cpu(&self) -> Option<f64> {
+ if self.samples.is_empty() {
+ return None;
+ }
+ let total_gc: f64 = self.samples.iter().map(|s| s.gc_seconds).sum();
+ let total_app: f64 = self.samples.iter().map(|s| s.app_cpu_seconds).sum();
+ if total_app <= 0.0 {
+ return None;
+ }
+ Some(total_gc / total_app)
+ }
+}
+
+pub struct CpuHeapTrigger {
+ /// Target heap size in pages. Updated at the end of each GC cycle.
+ target_heap_pages: AtomicUsize,
+ /// Mutable timing state. Wrapped in a `Mutex` because `on_gc_start` and
+ /// `on_gc_end` are the only mutation sites and they are not on an
+ /// allocation hot path; avoiding the complexity of lock-free state is
+ /// worth the trivial contention.
+ state: Mutex<CpuHeapTriggerState>,
+}
+
+impl Default for CpuHeapTrigger {
+ fn default() -> Self {
+ let cfg = Self::get_config();
+ Self {
+ target_heap_pages: AtomicUsize::new(cfg.initial_heap_pages),
+ state: Mutex::new(CpuHeapTriggerState::new()),
+ }
+ }
+}
+
+impl GCTriggerPolicy<Ruby> for CpuHeapTrigger {
+ fn is_gc_required(
+ &self,
+ space_full: bool,
+ space: Option<SpaceStats<Ruby>>,
+ plan: &dyn Plan<VM = Ruby>,
+ ) -> bool {
+ // Let the plan decide, matching the other triggers.
+ plan.collection_required(space_full, space)
+ }
+
+ fn on_gc_start(&self, _mmtk: &'static MMTK<Ruby>) {
+ let mut state = self.state.lock().unwrap();
+ state.gc_start_wall = Some(std::time::Instant::now());
+ }
+
+ fn on_gc_end(&self, mmtk: &'static MMTK<Ruby>) {
+ // Skip nursery-only GCs for generational plans. The heap resizing
+ // decision is driven by the (much more expensive) full collections
+ // where the signal-to-noise ratio is high enough to be useful.
+ if let Some(gen_plan) = mmtk.get_plan().generational() {
+ if gen_plan.is_current_gc_nursery() {
+ return;
+ }
+ }
+
+ let cfg = Self::get_config();
+ let gc_end_cpu = process_cpu_time_seconds();
+
+ let mut state = self.state.lock().unwrap();
+
+ // Duration of this GC cycle (wall clock).
+ let gc_seconds = state
+ .gc_start_wall
+ .take()
+ .map(|start| start.elapsed().as_secs_f64())
+ .unwrap_or(0.0);
+
+ // Process CPU time elapsed since the previous GC cycle ended. We
+ // require at least one previous end timestamp to produce a valid
+ // sample — without it we cannot compute `T_APP`.
+ if let (Some(last_end), Some(now)) = (state.last_gc_end_cpu, gc_end_cpu) {
+ let app_cpu_seconds = (now - last_end).max(0.0);
+ // Only record non-degenerate samples to avoid poisoning the window
+ // with zero-time entries from back-to-back GCs.
+ if app_cpu_seconds > 0.0 {
+ state.push_sample(
+ GcSample {
+ gc_seconds,
+ app_cpu_seconds,
+ },
+ cfg.window_size,
+ );
+ }
+ }
+ state.last_gc_end_cpu = gc_end_cpu;
+
+ // Compute the new heap size only when we have samples to average over.
+ if let Some(gc_cpu) = state.mean_gc_cpu() {
+ // Drop the lock before doing the (relatively cheap) math and
+ // atomic update; nothing below needs the state.
+ drop(state);
+
+ let overhead_error = gc_cpu - cfg.target_gc_cpu; // Eq. (2)
+ let sigmoid_error = sigmoid(overhead_error); // Eq. (3)
+ let adjustment_factor = sigmoid_error + 0.5; // Eq. (4), range (0.5, 1.5)
+
+ let current = self.target_heap_pages.load(Ordering::Relaxed);
+ let suggested = ((current as f64) * adjustment_factor) as usize; // Eq. (5)
+
+ // Clamp:
+ // - upper bound: configured max
+ // - lower bound: max(1.1 * used, min) — 10% headroom above current
+ // live memory, so we never request a heap so small that GC is
+ // triggered immediately on return from this one.
+ let used = mmtk.get_plan().get_used_pages();
+ let floor = ((used as f64) * 1.1).ceil() as usize;
+ let lower = floor.max(cfg.min_heap_pages).min(cfg.max_heap_pages);
+ let upper = cfg.max_heap_pages;
+ let new_target = suggested.clamp(lower, upper);
+
+ self.target_heap_pages.store(new_target, Ordering::Relaxed);
+
+ info!(
+ "CpuHeapTrigger: gc_cpu={:.4} target={:.4} factor={:.4} \
+ pages {} -> {} (used={}, clamp=[{}, {}])",
+ gc_cpu,
+ cfg.target_gc_cpu,
+ adjustment_factor,
+ current,
+ new_target,
+ used,
+ lower,
+ upper
+ );
+ }
+ }
+
+ fn is_heap_full(&self, plan: &dyn Plan<VM = Ruby>) -> bool {
+ plan.get_reserved_pages() > self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_current_heap_size_in_pages(&self) -> usize {
+ self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_max_heap_size_in_pages(&self) -> usize {
+ Self::get_config().max_heap_pages
+ }
+
+ fn can_heap_size_grow(&self) -> bool {
+ self.target_heap_pages.load(Ordering::Relaxed) < Self::get_config().max_heap_pages
+ }
+}
+
+impl CpuHeapTrigger {
+ fn get_config<'b>() -> &'b CpuHeapTriggerConfig {
+ CPU_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("Attempt to use CPU_HEAP_TRIGGER_CONFIG before it is initialized")
+ }
+}
+
+/// Standard logistic sigmoid. Returns 0.5 when x == 0, asymptotes to 0 and 1.
+fn sigmoid(x: f64) -> f64 {
+ 1.0 / (1.0 + (-x).exp())
+}
+
+/// Reads the process-wide CPU time as a floating-point number of seconds,
+/// summed across all threads of this process. Returns `None` if the clock
+/// query fails (which should be essentially impossible on supported
+/// platforms).
+fn process_cpu_time_seconds() -> Option<f64> {
+ let mut ts = libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ };
+ // SAFETY: `clock_gettime` writes exactly `sizeof(timespec)` bytes to the
+ // pointer we pass, which is a valid local stack allocation.
+ let rc = unsafe { libc::clock_gettime(libc::CLOCK_PROCESS_CPUTIME_ID, &mut ts) };
+ if rc != 0 {
+ return None;
+ }
+ Some((ts.tv_sec as f64) + (ts.tv_nsec as f64) / 1_000_000_000.0)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn sigmoid_is_well_behaved() {
+ assert!((sigmoid(0.0) - 0.5).abs() < 1e-12);
+ assert!(sigmoid(-100.0) < 1e-9);
+ assert!(sigmoid(100.0) > 1.0 - 1e-9);
+ // Monotonic.
+ assert!(sigmoid(-1.0) < sigmoid(0.0));
+ assert!(sigmoid(0.0) < sigmoid(1.0));
+ }
+
+ #[test]
+ fn adjustment_factor_is_within_paper_bounds() {
+ // Eq. (4): adjustment_factor = sigmoid(e) + 0.5 must lie in (0.5, 1.5).
+ for e in [-10.0_f64, -1.0, 0.0, 1.0, 10.0] {
+ let f = sigmoid(e) + 0.5;
+ assert!(f > 0.5 && f < 1.5, "factor {f} out of range for e={e}");
+ }
+ }
+
+ #[test]
+ fn mean_gc_cpu_is_total_weighted() {
+ let mut state = CpuHeapTriggerState::new();
+ state.push_sample(
+ GcSample {
+ gc_seconds: 1.0,
+ app_cpu_seconds: 10.0,
+ },
+ 3,
+ );
+ state.push_sample(
+ GcSample {
+ gc_seconds: 3.0,
+ app_cpu_seconds: 10.0,
+ },
+ 3,
+ );
+ // (1 + 3) / (10 + 10) = 0.2
+ assert!((state.mean_gc_cpu().unwrap() - 0.2).abs() < 1e-12);
+ }
+
+ #[test]
+ fn window_drops_oldest() {
+ let mut state = CpuHeapTriggerState::new();
+ for i in 0..5 {
+ state.push_sample(
+ GcSample {
+ gc_seconds: i as f64,
+ app_cpu_seconds: 1.0,
+ },
+ 3,
+ );
+ }
+ assert_eq!(state.samples.len(), 3);
+ // After pushing 0,1,2,3,4 with window 3, we should have [2,3,4].
+ assert_eq!(state.samples[0].gc_seconds, 2.0);
+ assert_eq!(state.samples[2].gc_seconds, 4.0);
+ }
+
+ #[test]
+ fn no_sample_without_prior_gc() {
+ // First GC cycle cannot produce a sample (no previous end time). The
+ // push happens only when last_gc_end_cpu is Some.
+ let state = CpuHeapTriggerState::new();
+ assert!(state.mean_gc_cpu().is_none());
+ }
+}
diff --git a/gc/mmtk/src/heap/mod.rs b/gc/mmtk/src/heap/mod.rs
new file mode 100644
index 0000000000..05a35efb23
--- /dev/null
+++ b/gc/mmtk/src/heap/mod.rs
@@ -0,0 +1,9 @@
+mod cpu_heap_trigger;
+mod ruby_heap_trigger;
+
+pub use cpu_heap_trigger::CpuHeapTrigger;
+pub use cpu_heap_trigger::CpuHeapTriggerConfig;
+pub use cpu_heap_trigger::CPU_HEAP_TRIGGER_CONFIG;
+pub use ruby_heap_trigger::RubyHeapTrigger;
+pub use ruby_heap_trigger::RubyHeapTriggerConfig;
+pub use ruby_heap_trigger::RUBY_HEAP_TRIGGER_CONFIG;
diff --git a/gc/mmtk/src/heap/ruby_heap_trigger.rs b/gc/mmtk/src/heap/ruby_heap_trigger.rs
new file mode 100644
index 0000000000..fe1130043d
--- /dev/null
+++ b/gc/mmtk/src/heap/ruby_heap_trigger.rs
@@ -0,0 +1,105 @@
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+
+use mmtk::util::heap::GCTriggerPolicy;
+use mmtk::util::heap::SpaceStats;
+use mmtk::Plan;
+use mmtk::MMTK;
+use once_cell::sync::OnceCell;
+
+use crate::Ruby;
+
+pub static RUBY_HEAP_TRIGGER_CONFIG: OnceCell<RubyHeapTriggerConfig> = OnceCell::new();
+
+pub struct RubyHeapTriggerConfig {
+ /// Min heap size
+ pub min_heap_pages: usize,
+ /// Max heap size
+ pub max_heap_pages: usize,
+ /// Minimum ratio of empty space after a GC before the heap will grow
+ pub heap_pages_min_ratio: f64,
+ /// Ratio the heap will grow by
+ pub heap_pages_goal_ratio: f64,
+ /// Maximum ratio of empty space after a GC before the heap will shrink
+ pub heap_pages_max_ratio: f64,
+}
+
+pub struct RubyHeapTrigger {
+ /// Target number of heap pages
+ target_heap_pages: AtomicUsize,
+}
+
+impl GCTriggerPolicy<Ruby> for RubyHeapTrigger {
+ fn is_gc_required(
+ &self,
+ space_full: bool,
+ space: Option<SpaceStats<Ruby>>,
+ plan: &dyn Plan<VM = Ruby>,
+ ) -> bool {
+ // Let the plan decide
+ plan.collection_required(space_full, space)
+ }
+
+ fn on_gc_end(&self, mmtk: &'static MMTK<Ruby>) {
+ if let Some(plan) = mmtk.get_plan().generational() {
+ if plan.is_current_gc_nursery() {
+ // Nursery GC
+ } else {
+ // Full GC
+ }
+
+ panic!("TODO: support for generational GC not implemented")
+ } else {
+ let used_pages = mmtk.get_plan().get_used_pages();
+
+ let target_min =
+ (used_pages as f64 * (1.0 + Self::get_config().heap_pages_min_ratio)) as usize;
+ let target_max =
+ (used_pages as f64 * (1.0 + Self::get_config().heap_pages_max_ratio)) as usize;
+ let new_target =
+ (((used_pages as f64) * (1.0 + Self::get_config().heap_pages_goal_ratio)) as usize)
+ .clamp(
+ Self::get_config().min_heap_pages,
+ Self::get_config().max_heap_pages,
+ );
+
+ if used_pages < target_min || used_pages > target_max {
+ self.target_heap_pages.store(new_target, Ordering::Relaxed);
+ }
+ }
+ }
+
+ fn is_heap_full(&self, plan: &dyn Plan<VM = Ruby>) -> bool {
+ plan.get_reserved_pages() > self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_current_heap_size_in_pages(&self) -> usize {
+ self.target_heap_pages.load(Ordering::Relaxed)
+ }
+
+ fn get_max_heap_size_in_pages(&self) -> usize {
+ Self::get_config().max_heap_pages
+ }
+
+ fn can_heap_size_grow(&self) -> bool {
+ self.target_heap_pages.load(Ordering::Relaxed) < Self::get_config().max_heap_pages
+ }
+}
+
+impl Default for RubyHeapTrigger {
+ fn default() -> Self {
+ let min_heap_pages = Self::get_config().min_heap_pages;
+
+ Self {
+ target_heap_pages: AtomicUsize::new(min_heap_pages),
+ }
+ }
+}
+
+impl RubyHeapTrigger {
+ fn get_config<'b>() -> &'b RubyHeapTriggerConfig {
+ RUBY_HEAP_TRIGGER_CONFIG
+ .get()
+ .expect("Attempt to use RUBY_HEAP_TRIGGER_CONFIG before it is initialized")
+ }
+}
diff --git a/gc/mmtk/src/lib.rs b/gc/mmtk/src/lib.rs
index 01497e9c42..52dc782051 100644
--- a/gc/mmtk/src/lib.rs
+++ b/gc/mmtk/src/lib.rs
@@ -1,3 +1,7 @@
+// Warn about unsafe operations in functions that are already marked as unsafe.
+// This will become default in Rust 2024 edition.
+#![warn(unsafe_op_in_unsafe_fn)]
+
extern crate libc;
extern crate mmtk;
#[macro_use]
@@ -10,8 +14,11 @@ use std::sync::Mutex;
use std::thread::ThreadId;
use abi::RubyUpcalls;
-use binding::{RubyBinding, RubyBindingFast, RubyConfiguration};
-use mmtk::vm::slot::{SimpleSlot, UnimplementedMemorySlice};
+use binding::RubyBinding;
+use binding::RubyBindingFast;
+use binding::RubyConfiguration;
+use mmtk::vm::slot::SimpleSlot;
+use mmtk::vm::slot::UnimplementedMemorySlice;
use mmtk::vm::VMBinding;
use mmtk::MMTK;
use once_cell::sync::OnceCell;
@@ -21,7 +28,9 @@ pub mod active_plan;
pub mod api;
pub mod binding;
pub mod collection;
+pub mod heap;
pub mod object_model;
+pub mod pinning_registry;
pub mod reference_glue;
pub mod scanning;
pub mod utils;
@@ -51,6 +60,11 @@ impl VMBinding for Ruby {
type VMMemorySlice = RubyMemorySlice;
}
+/// The callback for mutator thread panic handler (which calls rb_bug to output
+/// debugging information such as the Ruby backtrace and memory maps).
+/// This is set before BINDING is set because mmtk_init could panic.
+pub static MUTATOR_THREAD_PANIC_HANDLER: OnceCell<extern "C" fn()> = OnceCell::new();
+
/// The singleton object for the Ruby binding itself.
pub static BINDING: OnceCell<RubyBinding> = OnceCell::new();
@@ -112,8 +126,6 @@ fn handle_gc_thread_panic(panic_info: &PanicHookInfo) {
eprintln!("Unknown backtrace status: {s:?}");
}
}
-
- std::process::abort();
}
pub(crate) fn set_panic_hook() {
@@ -126,8 +138,24 @@ pub(crate) fn set_panic_hook() {
std::panic::set_hook(Box::new(move |panic_info| {
if is_gc_thread(std::thread::current().id()) {
handle_gc_thread_panic(panic_info);
+
+ (crate::binding().upcalls().gc_thread_panic_handler)();
} else {
old_hook(panic_info);
+ (crate::MUTATOR_THREAD_PANIC_HANDLER
+ .get()
+ .expect("MUTATOR_THREAD_PANIC_HANDLER is not set"))();
}
}));
}
+
+/// This kind of assertion is enabled if either building in debug mode or the
+/// "extra_assert" feature is enabled.
+#[macro_export]
+macro_rules! extra_assert {
+ ($($arg:tt)*) => {
+ if std::cfg!(any(debug_assertions, feature = "extra_assert")) {
+ std::assert!($($arg)*);
+ }
+ };
+}
diff --git a/gc/mmtk/src/object_model.rs b/gc/mmtk/src/object_model.rs
index abeef1f2b9..d673ca11a0 100644
--- a/gc/mmtk/src/object_model.rs
+++ b/gc/mmtk/src/object_model.rs
@@ -1,8 +1,15 @@
-use crate::abi::{RubyObjectAccess, OBJREF_OFFSET};
-use crate::{abi, Ruby};
+use std::ptr::copy_nonoverlapping;
+
+use crate::abi;
+use crate::abi::RubyObjectAccess;
+use crate::abi::MIN_OBJ_ALIGN;
+use crate::abi::OBJREF_OFFSET;
+use crate::Ruby;
use mmtk::util::constants::BITS_IN_BYTE;
-use mmtk::util::copy::{CopySemantics, GCWorkerCopyContext};
-use mmtk::util::{Address, ObjectReference};
+use mmtk::util::copy::CopySemantics;
+use mmtk::util::copy::GCWorkerCopyContext;
+use mmtk::util::Address;
+use mmtk::util::ObjectReference;
use mmtk::vm::*;
pub struct VMObjectModel {}
@@ -36,13 +43,39 @@ impl ObjectModel<Ruby> for VMObjectModel {
const NEED_VO_BITS_DURING_TRACING: bool = true;
fn copy(
- _from: ObjectReference,
- _semantics: CopySemantics,
- _copy_context: &mut GCWorkerCopyContext<Ruby>,
+ from: ObjectReference,
+ semantics: CopySemantics,
+ copy_context: &mut GCWorkerCopyContext<Ruby>,
) -> ObjectReference {
- unimplemented!(
- "Copying GC not currently supported"
- )
+ let from_acc = RubyObjectAccess::from_objref(from);
+ let from_start = from_acc.obj_start();
+ let object_size = from_acc.object_size();
+ let to_start = copy_context.alloc_copy(from, object_size, MIN_OBJ_ALIGN, 0, semantics);
+ debug_assert!(!to_start.is_zero());
+ let to_payload = to_start.add(OBJREF_OFFSET);
+ unsafe {
+ copy_nonoverlapping::<u8>(from_start.to_ptr(), to_start.to_mut_ptr(), object_size);
+ }
+ let to_obj = unsafe { ObjectReference::from_raw_address_unchecked(to_payload) };
+ copy_context.post_copy(to_obj, object_size, semantics);
+ trace!("Copied object from {} to {}", from, to_obj);
+
+ (crate::binding().upcalls().move_obj_during_marking)(from, to_obj);
+
+ #[cfg(feature = "clear_old_copy")]
+ {
+ trace!(
+ "Clearing old copy {} ({}-{})",
+ from,
+ from_start,
+ from_start + object_size
+ );
+ // For debug purpose, we clear the old copy so that if the Ruby VM reads from the old
+ // copy again, it will likely result in an error.
+ unsafe { std::ptr::write_bytes::<u8>(from_start.to_mut_ptr(), 0, object_size) }
+ }
+
+ to_obj
}
fn copy_to(_from: ObjectReference, _to: ObjectReference, _region: Address) -> Address {
diff --git a/gc/mmtk/src/pinning_registry.rs b/gc/mmtk/src/pinning_registry.rs
new file mode 100644
index 0000000000..b498b508f1
--- /dev/null
+++ b/gc/mmtk/src/pinning_registry.rs
@@ -0,0 +1,187 @@
+use std::sync::Mutex;
+
+use mmtk::memory_manager;
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
+use mmtk::util::ObjectReference;
+use mmtk::util::VMWorkerThread;
+use mmtk::MMTK;
+
+use crate::abi::GCThreadTLS;
+use crate::upcalls;
+use crate::Ruby;
+
+pub struct PinningRegistry {
+ pinning_objs: Mutex<Vec<ObjectReference>>,
+ pinned_objs: Mutex<Vec<ObjectReference>>,
+}
+
+impl PinningRegistry {
+ pub fn new() -> Self {
+ Self {
+ pinning_objs: Default::default(),
+ pinned_objs: Default::default(),
+ }
+ }
+
+ pub fn register(&self, object: ObjectReference) {
+ let mut pinning_objs = self.pinning_objs.lock().unwrap();
+ pinning_objs.push(object);
+ }
+
+ pub fn pin_children(&self, tls: VMWorkerThread) {
+ if !crate::mmtk().get_plan().current_gc_may_move_object() {
+ log::debug!("The current GC is non-moving, skipping pinning children.");
+ return;
+ }
+
+ let gc_tls = unsafe { GCThreadTLS::from_vwt_check(tls) };
+ let worker = gc_tls.worker();
+
+ let pinning_objs = self
+ .pinning_objs
+ .try_lock()
+ .expect("PinningRegistry should not have races during GC.");
+
+ let packet_size = 512;
+ let work_packets = pinning_objs
+ .chunks(packet_size)
+ .map(|chunk| {
+ Box::new(PinPinningChildren {
+ pinning_objs: chunk.to_vec(),
+ }) as _
+ })
+ .collect();
+
+ worker.scheduler().work_buckets[WorkBucketStage::Prepare].bulk_add(work_packets);
+ }
+
+ pub fn cleanup(&self, worker: &mut GCWorker<Ruby>) {
+ worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].add(RemoveDeadPinnings);
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ let packet = {
+ let mut pinned_objs = self
+ .pinned_objs
+ .try_lock()
+ .expect("Unexpected contention on pinned_objs");
+ UnpinPinnedObjects {
+ objs: std::mem::take(&mut pinned_objs),
+ }
+ };
+
+ worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].add(packet);
+ } else {
+ debug!("The current GC is non-moving, skipping unpinning objects.");
+ debug_assert_eq!(
+ {
+ let pinned_objs = self
+ .pinned_objs
+ .try_lock()
+ .expect("Unexpected contention on pinned_objs");
+ pinned_objs.len()
+ },
+ 0
+ );
+ }
+ }
+}
+
+impl Default for PinningRegistry {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+struct PinPinningChildren {
+ pinning_objs: Vec<ObjectReference>,
+}
+
+impl GCWork<Ruby> for PinPinningChildren {
+ fn do_work(&mut self, worker: &mut GCWorker<Ruby>, _mmtk: &'static MMTK<Ruby>) {
+ let gc_tls = unsafe { GCThreadTLS::from_vwt_check(worker.tls) };
+ let mut pinned_objs = vec![];
+ let mut newly_pinned_objs = vec![];
+
+ let visit_object = |_worker, target_object: ObjectReference, pin| {
+ log::trace!(
+ " -> {} {}",
+ if pin { "(pin)" } else { " " },
+ target_object
+ );
+ if pin {
+ debug_assert!(
+ target_object.get_forwarded_object().is_none(),
+ "Trying to pin {target_object} but has been moved"
+ );
+
+ pinned_objs.push(target_object);
+ }
+ target_object
+ };
+
+ gc_tls
+ .object_closure
+ .set_temporarily_and_run_code(visit_object, || {
+ for obj in self.pinning_objs.iter().cloned() {
+ log::trace!(" Pinning: {}", obj);
+ (upcalls().call_gc_mark_children)(obj);
+ }
+ });
+
+ for target_object in pinned_objs {
+ if memory_manager::pin_object(target_object) {
+ newly_pinned_objs.push(target_object);
+ }
+ }
+
+ let mut pinned_objs = crate::binding()
+ .pinning_registry
+ .pinned_objs
+ .lock()
+ .unwrap();
+ pinned_objs.append(&mut newly_pinned_objs);
+ }
+}
+
+struct RemoveDeadPinnings;
+
+impl GCWork<Ruby> for RemoveDeadPinnings {
+ fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static MMTK<Ruby>) {
+ log::debug!("Removing dead Pinnings...");
+
+ let registry = &crate::binding().pinning_registry;
+ {
+ let mut pinning_objs = registry
+ .pinning_objs
+ .try_lock()
+ .expect("PinningRegistry should not have races during GC.");
+
+ pinning_objs.retain_mut(|obj| {
+ if obj.is_live() {
+ let new_obj = obj.get_forwarded_object().unwrap_or(*obj);
+ *obj = new_obj;
+ true
+ } else {
+ log::trace!(" Dead Pinning removed: {}", *obj);
+ false
+ }
+ });
+ }
+ }
+}
+
+struct UnpinPinnedObjects {
+ objs: Vec<ObjectReference>,
+}
+
+impl GCWork<Ruby> for UnpinPinnedObjects {
+ fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static MMTK<Ruby>) {
+ log::debug!("Unpinning pinned objects...");
+
+ for obj in self.objs.iter() {
+ let unpinned = memory_manager::unpin_object(*obj);
+ debug_assert!(unpinned);
+ }
+ }
+}
diff --git a/gc/mmtk/src/scanning.rs b/gc/mmtk/src/scanning.rs
index 33466b9db6..355a2e7759 100644
--- a/gc/mmtk/src/scanning.rs
+++ b/gc/mmtk/src/scanning.rs
@@ -1,11 +1,20 @@
use crate::abi::GCThreadTLS;
+use crate::upcalls;
use crate::utils::ChunkedVecCollector;
-use crate::{upcalls, Ruby, RubySlot};
-use mmtk::scheduler::{GCWork, GCWorker, WorkBucketStage};
-use mmtk::util::{ObjectReference, VMWorkerThread};
-use mmtk::vm::{ObjectTracer, RootsWorkFactory, Scanning, SlotVisitor};
-use mmtk::{Mutator, MutatorContext};
+use crate::Ruby;
+use crate::RubySlot;
+use mmtk::memory_manager;
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
+use mmtk::util::ObjectReference;
+use mmtk::util::VMWorkerThread;
+use mmtk::vm::ObjectTracer;
+use mmtk::vm::RootsWorkFactory;
+use mmtk::vm::Scanning;
+use mmtk::vm::SlotVisitor;
+use mmtk::Mutator;
pub struct VMScanning {}
@@ -45,20 +54,33 @@ impl Scanning<Ruby> for VMScanning {
mmtk::memory_manager::is_mmtk_object(target_object.to_raw_address()).is_some(),
"Destination is not an MMTk object. Src: {object} dst: {target_object}"
);
+
+ debug_assert!(
+ // If we are in a moving GC, all objects should be pinned by PinningRegistry.
+ // If it is requested that target_object be pinned but it is not pinned, then
+ // it is a bug because it could be moved.
+ if crate::mmtk().get_plan().current_gc_may_move_object() && pin {
+ memory_manager::is_pinned(target_object)
+ } else {
+ true
+ },
+ "Object {object} is trying to pin {target_object}"
+ );
+
let forwarded_target = object_tracer.trace_object(target_object);
if forwarded_target != target_object {
- trace!(
- " Forwarded target {} -> {}",
- target_object,
- forwarded_target
- );
+ trace!(" Forwarded target {target_object} -> {forwarded_target}");
}
forwarded_target
};
gc_tls
.object_closure
.set_temporarily_and_run_code(visit_object, || {
- (upcalls().scan_object_ruby_style)(object);
+ (upcalls().call_gc_mark_children)(object);
+
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ (upcalls().update_object_references)(object);
+ }
});
}
@@ -67,14 +89,13 @@ impl Scanning<Ruby> for VMScanning {
}
fn scan_roots_in_mutator_thread(
- tls: VMWorkerThread,
- mutator: &'static mut Mutator<Ruby>,
- mut factory: impl RootsWorkFactory<RubySlot>,
+ _tls: VMWorkerThread,
+ _mutator: &'static mut Mutator<Ruby>,
+ mut _factory: impl RootsWorkFactory<RubySlot>,
) {
- let gc_tls = unsafe { GCThreadTLS::from_vwt_check(tls) };
- Self::collect_object_roots_in("scan_thread_root", gc_tls, &mut factory, || {
- (upcalls().scan_roots_in_mutator_thread)(mutator.get_tls(), tls);
- });
+ // Do nothing. All stacks (including Ruby stacks and machine stacks) are reachable from
+ // `rb_vm_t` -> ractor -> thread -> fiber -> stacks. It is part of `ScanGCRoots` which
+ // calls `rb_gc_mark_roots` -> `rb_vm_mark`.
}
fn scan_vm_specific_roots(tls: VMWorkerThread, factory: impl RootsWorkFactory<RubySlot>) {
@@ -136,6 +157,7 @@ impl Scanning<Ruby> for VMScanning {
crate::binding()
.weak_proc
.process_weak_stuff(worker, tracer_context);
+ crate::binding().pinning_registry.cleanup(worker);
false
}
@@ -252,15 +274,15 @@ impl<F: RootsWorkFactory<RubySlot>> GCWork<Ruby> for ScanWbUnprotectedRoots<F> {
VMScanning::collect_object_roots_in("wb_unprot_roots", gc_tls, &mut self.factory, || {
for object in self.objects.iter().copied() {
if object.is_reachable() {
- debug!(
- "[wb_unprot_roots] Visiting WB-unprotected object (parent): {}",
- object
- );
- (upcalls().scan_object_ruby_style)(object);
+ debug!("[wb_unprot_roots] Visiting WB-unprotected object (parent): {object}");
+ (upcalls().call_gc_mark_children)(object);
+
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ (upcalls().update_object_references)(object);
+ }
} else {
debug!(
- "[wb_unprot_roots] Skipping young WB-unprotected object (parent): {}",
- object
+ "[wb_unprot_roots] Skipping young WB-unprotected object (parent): {object}"
);
}
}
diff --git a/gc/mmtk/src/utils.rs b/gc/mmtk/src/utils.rs
index de929c3952..d1979eaf58 100644
--- a/gc/mmtk/src/utils.rs
+++ b/gc/mmtk/src/utils.rs
@@ -1,10 +1,13 @@
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
use atomic_refcell::AtomicRefCell;
-use mmtk::scheduler::{GCWork, GCWorker, WorkBucketStage};
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
-use sysinfo::System;
use crate::Ruby;
+use sysinfo::System;
pub struct ChunkedVecCollector<T> {
vecs: Vec<Vec<T>>,
@@ -97,32 +100,29 @@ pub fn default_heap_max() -> usize {
.expect("Invalid Memory size") as usize
}
-pub fn parse_capacity(input: &String, default: usize) -> usize {
+pub fn parse_capacity(input: &str) -> Option<usize> {
let trimmed = input.trim();
const KIBIBYTE: usize = 1024;
const MEBIBYTE: usize = 1024 * KIBIBYTE;
const GIBIBYTE: usize = 1024 * MEBIBYTE;
- let (val, suffix) = if let Some(pos) = trimmed.find(|c: char| !c.is_numeric()) {
- (&trimmed[..pos], &trimmed[pos..])
+ let (number, suffix) = if let Some(pos) = trimmed.find(|c: char| !c.is_numeric()) {
+ trimmed.split_at(pos)
} else {
(trimmed, "")
};
- // 1MiB is the default heap size
- match (val, suffix) {
- (number, "GiB") => number.parse::<usize>()
- .and_then(|v| Ok(v * GIBIBYTE))
- .unwrap_or(default),
- (number, "MiB") => number.parse::<usize>()
- .and_then(|v| Ok(v * MEBIBYTE))
- .unwrap_or(default),
- (number, "KiB") => number.parse::<usize>()
- .and_then(|v| Ok(v * KIBIBYTE))
- .unwrap_or(default),
- (number, suffix) if suffix.is_empty() => number.parse::<usize>().unwrap_or(default),
- (_, _) => default
+ let Ok(v) = number.parse::<usize>() else {
+ return None;
+ };
+
+ match suffix {
+ "GiB" => Some(v * GIBIBYTE),
+ "MiB" => Some(v * MEBIBYTE),
+ "KiB" => Some(v * KIBIBYTE),
+ "" => Some(v),
+ _ => None,
}
}
@@ -132,32 +132,30 @@ mod tests {
#[test]
fn test_parse_capacity_parses_bare_bytes() {
- assert_eq!(1234, parse_capacity(&String::from("1234"), 0));
+ assert_eq!(Some(1234), parse_capacity("1234"));
}
#[test]
fn test_parse_capacity_parses_kibibytes() {
- assert_eq!(10240, parse_capacity(&String::from("10KiB"), 0))
+ assert_eq!(Some(10240), parse_capacity("10KiB"));
}
#[test]
fn test_parse_capacity_parses_mebibytes() {
- assert_eq!(10485760, parse_capacity(&String::from("10MiB"), 0))
+ assert_eq!(Some(10485760), parse_capacity("10MiB"))
}
#[test]
fn test_parse_capacity_parses_gibibytes() {
- assert_eq!(10737418240, parse_capacity(&String::from("10GiB"), 0))
+ assert_eq!(Some(10737418240), parse_capacity("10GiB"))
}
#[test]
- fn test_parses_nonsense_value_as_default_max() {
- let default = 100;
-
- assert_eq!(default, parse_capacity(&String::from("notanumber"), default));
- assert_eq!(default, parse_capacity(&String::from("5tartswithanumber"), default));
- assert_eq!(default, parse_capacity(&String::from("number1nthemiddle"), default));
- assert_eq!(default, parse_capacity(&String::from("numberattheend111"), default));
- assert_eq!(default, parse_capacity(&String::from("mult1pl3numb3r5"), default));
+ fn test_parse_capacity_parses_nonsense_values() {
+ assert_eq!(None, parse_capacity("notanumber"));
+ assert_eq!(None, parse_capacity("5tartswithanumber"));
+ assert_eq!(None, parse_capacity("number1nthemiddle"));
+ assert_eq!(None, parse_capacity("numberattheend111"));
+ assert_eq!(None, parse_capacity("mult1pl3numb3r5"));
}
}
diff --git a/gc/mmtk/src/weak_proc.rs b/gc/mmtk/src/weak_proc.rs
index 11f7f5abbf..d38dbe04a4 100644
--- a/gc/mmtk/src/weak_proc.rs
+++ b/gc/mmtk/src/weak_proc.rs
@@ -1,23 +1,23 @@
use std::sync::Mutex;
-use mmtk::{
- scheduler::{GCWork, GCWorker, WorkBucketStage},
- util::ObjectReference,
- vm::ObjectTracerContext,
-};
-
-use crate::{
- abi::GCThreadTLS,
- upcalls,
- Ruby,
-};
+use mmtk::scheduler::GCWork;
+use mmtk::scheduler::GCWorker;
+use mmtk::scheduler::WorkBucketStage;
+use mmtk::util::ObjectReference;
+use mmtk::vm::ObjectTracerContext;
+
+use crate::abi::GCThreadTLS;
+use crate::upcalls;
+use crate::Ruby;
pub struct WeakProcessor {
+ non_parallel_obj_free_candidates: Mutex<Vec<ObjectReference>>,
+ parallel_obj_free_candidates: Vec<Mutex<Vec<ObjectReference>>>,
+
/// Objects that needs `obj_free` called when dying.
/// If it is a bottleneck, replace it with a lock-free data structure,
/// or add candidates in batch.
- obj_free_candidates: Mutex<Vec<ObjectReference>>,
- weak_references: Mutex<Vec<&'static mut ObjectReference>>,
+ weak_references: Mutex<Vec<ObjectReference>>,
}
impl Default for WeakProcessor {
@@ -29,47 +29,74 @@ impl Default for WeakProcessor {
impl WeakProcessor {
pub fn new() -> Self {
Self {
- obj_free_candidates: Mutex::new(Vec::new()),
+ non_parallel_obj_free_candidates: Mutex::new(Vec::new()),
+ parallel_obj_free_candidates: vec![Mutex::new(Vec::new())],
weak_references: Mutex::new(Vec::new()),
}
}
- /// Add an object as a candidate for `obj_free`.
- ///
- /// Multiple mutators can call it concurrently, so it has `&self`.
- pub fn add_obj_free_candidate(&self, object: ObjectReference) {
- let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
- obj_free_candidates.push(object);
+ pub fn init_parallel_obj_free_candidates(&mut self, num_workers: usize) {
+ debug_assert_eq!(self.parallel_obj_free_candidates.len(), 1);
+
+ for _ in 1..num_workers {
+ self.parallel_obj_free_candidates
+ .push(Mutex::new(Vec::new()));
+ }
}
- /// Add many objects as candidates for `obj_free`.
+ /// Add a batch of objects as candidates for `obj_free`.
///
- /// Multiple mutators can call it concurrently, so it has `&self`.
- pub fn add_obj_free_candidates(&self, objects: &[ObjectReference]) {
- let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
- for object in objects.iter().copied() {
- obj_free_candidates.push(object);
+ /// Amortizes mutex acquisition over the entire batch. Called when a
+ /// mutator's local buffer is flushed (buffer full or stop-the-world).
+ pub fn add_obj_free_candidates_batch(
+ &self,
+ objects: &[ObjectReference],
+ can_parallel_free: bool,
+ ) {
+ if objects.is_empty() {
+ return;
+ }
+
+ if can_parallel_free {
+ let num_buckets = self.parallel_obj_free_candidates.len();
+ for idx in 0..num_buckets {
+ let mut bucket = self.parallel_obj_free_candidates[idx].lock().unwrap();
+ for (i, &obj) in objects.iter().enumerate() {
+ if i % num_buckets == idx {
+ bucket.push(obj);
+ }
+ }
+ }
+ } else {
+ self.non_parallel_obj_free_candidates
+ .lock()
+ .unwrap()
+ .extend_from_slice(objects);
}
}
pub fn get_all_obj_free_candidates(&self) -> Vec<ObjectReference> {
- let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
- std::mem::take(obj_free_candidates.as_mut())
+ // let mut obj_free_candidates = self.obj_free_candidates.lock().unwrap();
+ let mut all_obj_free_candidates = self
+ .non_parallel_obj_free_candidates
+ .lock()
+ .unwrap()
+ .to_vec();
+
+ for candidates_mutex in &self.parallel_obj_free_candidates {
+ all_obj_free_candidates.extend(candidates_mutex.lock().unwrap().to_vec());
+ }
+
+ std::mem::take(all_obj_free_candidates.as_mut())
}
- pub fn add_weak_reference(&self, ptr: &'static mut ObjectReference) {
+ pub fn add_weak_reference(&self, object: ObjectReference) {
let mut weak_references = self.weak_references.lock().unwrap();
- weak_references.push(ptr);
+ weak_references.push(object);
}
- pub fn remove_weak_reference(&self, ptr: &ObjectReference) {
- let mut weak_references = self.weak_references.lock().unwrap();
- for (i, curr_ptr) in weak_references.iter().enumerate() {
- if *curr_ptr == ptr {
- weak_references.swap_remove(i);
- break;
- }
- }
+ pub fn weak_references_count(&self) -> usize {
+ self.weak_references.lock().unwrap().len()
}
pub fn process_weak_stuff(
@@ -77,80 +104,133 @@ impl WeakProcessor {
worker: &mut GCWorker<Ruby>,
_tracer_context: impl ObjectTracerContext<Ruby>,
) {
- worker.add_work(WorkBucketStage::VMRefClosure, ProcessObjFreeCandidates);
+ worker.add_work(
+ WorkBucketStage::VMRefClosure,
+ ProcessNonParallelObjFreeCanadidates {},
+ );
+
+ for index in 0..self.parallel_obj_free_candidates.len() {
+ worker.add_work(
+ WorkBucketStage::VMRefClosure,
+ ProcessParallelObjFreeCandidates { index },
+ );
+ }
+
worker.add_work(WorkBucketStage::VMRefClosure, ProcessWeakReferences);
worker.add_work(WorkBucketStage::Prepare, UpdateFinalizerObjIdTables);
let global_tables_count = (crate::upcalls().global_tables_count)();
let work_packets = (0..global_tables_count)
- .map(|i| {
- Box::new(UpdateGlobalTables { idx: i }) as _
- })
- .collect();
+ .map(|i| Box::new(UpdateGlobalTables { idx: i }) as _)
+ .collect();
worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].bulk_add(work_packets);
- worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].bulk_add(vec![
- Box::new(UpdateWbUnprotectedObjectsList) as _,
- ]);
+ worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure]
+ .bulk_add(vec![Box::new(UpdateWbUnprotectedObjectsList) as _]);
+ }
+}
+
+fn process_obj_free_candidates(obj_free_candidates: &mut Vec<ObjectReference>) {
+ // Process obj_free
+ let mut new_candidates = Vec::new();
+
+ for object in obj_free_candidates.iter().copied() {
+ if object.is_reachable() {
+ // Forward and add back to the candidate list.
+ let new_object = object.forward();
+ trace!("Forwarding obj_free candidate: {object} -> {new_object}");
+ new_candidates.push(new_object);
+ } else {
+ (upcalls().call_obj_free)(object);
+ }
+ }
+
+ *obj_free_candidates = new_candidates;
+}
+
+struct ProcessParallelObjFreeCandidates {
+ index: usize,
+}
+
+impl GCWork<Ruby> for ProcessParallelObjFreeCandidates {
+ fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
+ let mut obj_free_candidates = crate::binding().weak_proc.parallel_obj_free_candidates
+ [self.index]
+ .try_lock()
+ .expect("Lock for parallel_obj_free_candidates should not be held");
+
+ process_obj_free_candidates(&mut obj_free_candidates);
}
}
-struct ProcessObjFreeCandidates;
+struct ProcessNonParallelObjFreeCanadidates;
-impl GCWork<Ruby> for ProcessObjFreeCandidates {
+impl GCWork<Ruby> for ProcessNonParallelObjFreeCanadidates {
fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
- // If it blocks, it is a bug.
let mut obj_free_candidates = crate::binding()
.weak_proc
- .obj_free_candidates
+ .non_parallel_obj_free_candidates
.try_lock()
- .expect("It's GC time. No mutators should hold this lock at this time.");
+ .expect("Lock for non_parallel_obj_free_candidates should not be held");
- let n_cands = obj_free_candidates.len();
+ process_obj_free_candidates(&mut obj_free_candidates);
+ }
+}
- debug!("Total: {} candidates", n_cands);
+struct ProcessWeakReferences;
- // Process obj_free
- let mut new_candidates = Vec::new();
+impl GCWork<Ruby> for ProcessWeakReferences {
+ fn do_work(&mut self, worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
+ if crate::mmtk().get_plan().current_gc_may_move_object() {
+ let gc_tls: &mut GCThreadTLS = unsafe { GCThreadTLS::from_vwt_check(worker.tls) };
- for object in obj_free_candidates.iter().copied() {
- if object.is_reachable() {
- // Forward and add back to the candidate list.
- let new_object = object.forward();
- trace!(
- "Forwarding obj_free candidate: {} -> {}",
- object,
- new_object
+ let visit_object = |_worker, target_object: ObjectReference, _pin| {
+ debug_assert!(
+ mmtk::memory_manager::is_mmtk_object(target_object.to_raw_address()).is_some(),
+ "Destination is not an MMTk object"
);
- new_candidates.push(new_object);
- } else {
- (upcalls().call_obj_free)(object);
- }
- }
- *obj_free_candidates = new_candidates;
+ target_object
+ .get_forwarded_object()
+ .unwrap_or(target_object)
+ };
+
+ gc_tls
+ .object_closure
+ .set_temporarily_and_run_code(visit_object, || {
+ self.process_weak_references(true);
+ })
+ } else {
+ self.process_weak_references(false);
+ }
}
}
-struct ProcessWeakReferences;
-
-impl GCWork<Ruby> for ProcessWeakReferences {
- fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
+impl ProcessWeakReferences {
+ fn process_weak_references(&mut self, moving_gc: bool) {
let mut weak_references = crate::binding()
.weak_proc
.weak_references
.try_lock()
.expect("Mutators should not be holding the lock.");
- for ptr_ptr in weak_references.iter_mut() {
- if !(**ptr_ptr).is_reachable() {
- **ptr_ptr = crate::binding().weak_reference_dead_value;
- }
+ weak_references.retain_mut(|object_ptr| {
+ let object = object_ptr.get_forwarded_object().unwrap_or(*object_ptr);
+
+ if object != *object_ptr {
+ *object_ptr = object;
}
- weak_references.clear();
+ if object.is_reachable() {
+ (upcalls().handle_weak_references)(object, moving_gc);
+
+ true
+ } else {
+ false
+ }
+ });
}
}
@@ -165,11 +245,10 @@ trait GlobalTableProcessingWork {
let forward_object = |_worker, object: ObjectReference, _pin| {
debug_assert!(
mmtk::memory_manager::is_mmtk_object(object.to_raw_address()).is_some(),
- "{} is not an MMTk object",
- object
+ "{object} is not an MMTk object"
);
let result = object.forward();
- trace!("Forwarding reference: {} -> {}", object, result);
+ trace!("Forwarding reference: {object} -> {result}");
result
};
@@ -185,7 +264,6 @@ struct UpdateFinalizerObjIdTables;
impl GlobalTableProcessingWork for UpdateFinalizerObjIdTables {
fn process_table(&mut self) {
(crate::upcalls().update_finalizer_table)();
- (crate::upcalls().update_obj_id_tables)();
}
}
impl GCWork<Ruby> for UpdateFinalizerObjIdTables {
@@ -195,11 +273,14 @@ impl GCWork<Ruby> for UpdateFinalizerObjIdTables {
}
struct UpdateGlobalTables {
- idx: i32
+ idx: i32,
}
impl GlobalTableProcessingWork for UpdateGlobalTables {
fn process_table(&mut self) {
- (crate::upcalls().update_global_tables)(self.idx)
+ (crate::upcalls().update_global_tables)(
+ self.idx,
+ crate::mmtk().get_plan().current_gc_may_move_object(),
+ )
}
}
impl GCWork<Ruby> for UpdateGlobalTables {
@@ -224,14 +305,10 @@ impl GCWork<Ruby> for UpdateWbUnprotectedObjectsList {
if object.is_reachable() {
// Forward and add back to the candidate list.
let new_object = object.forward();
- trace!(
- "Forwarding WB-unprotected object: {} -> {}",
- object,
- new_object
- );
+ trace!("Forwarding WB-unprotected object: {object} -> {new_object}");
objects.insert(new_object);
} else {
- trace!("Removing WB-unprotected object from list: {}", object);
+ trace!("Removing WB-unprotected object from list: {object}");
}
}
diff --git a/gc/wbcheck/extconf.rb b/gc/wbcheck/extconf.rb
new file mode 100644
index 0000000000..18b32d820d
--- /dev/null
+++ b/gc/wbcheck/extconf.rb
@@ -0,0 +1,3 @@
+require_relative '../extconf_base'
+
+create_gc_makefile("wbcheck")
diff --git a/gc/wbcheck/wbcheck.c b/gc/wbcheck/wbcheck.c
new file mode 100644
index 0000000000..a7d4cd6ccf
--- /dev/null
+++ b/gc/wbcheck/wbcheck.c
@@ -0,0 +1,1936 @@
+#include "internal.h"
+#include "ruby/ruby.h"
+#include "ruby/assert.h"
+#include "ruby/atomic.h"
+#include "ruby/debug.h"
+#include "ruby/internal/core/rbasic.h"
+#include "ruby/st.h"
+#include "internal/object.h"
+#include "internal/array.h"
+#include "internal/class.h"
+
+#include "ruby/thread.h"
+#include "gc/gc.h"
+#include "gc/gc_impl.h"
+
+#include <stdbool.h>
+#include <stdarg.h>
+
+// Debug output control
+static bool wbcheck_debug_enabled = false;
+
+// Verification after write barrier control
+static bool wbcheck_verify_after_wb_enabled = false;
+
+// Useless write barrier warning control
+static bool wbcheck_warn_useless_wb_enabled = false;
+
+static void
+wbcheck_debug(const char *format, ...)
+{
+ if (!wbcheck_debug_enabled) return;
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+#define WBCHECK_DEBUG(...) do { \
+ if (wbcheck_debug_enabled) { \
+ wbcheck_debug(__VA_ARGS__); \
+ } \
+} while (0)
+
+static void
+wbcheck_debug_obj_info_dump(VALUE obj)
+{
+ if (!wbcheck_debug_enabled) return;
+ char buff[0x100];
+ fprintf(stderr, "%s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+}
+
+// Forward declaration
+static void lock_and_maybe_gc(void *objspace_ptr);
+static void force_gc(void *objspace_ptr);
+
+// Configure wbcheck from environment variables
+static void
+wbcheck_configure_from_env(void)
+{
+ // Configure debug output based on environment variable
+ const char *debug_env = getenv("WBCHECK_DEBUG");
+ if (debug_env && (strcmp(debug_env, "1") == 0 || strcmp(debug_env, "true") == 0)) {
+ wbcheck_debug_enabled = true;
+ }
+
+ // Configure verification after write barrier based on environment variable
+ const char *verify_after_wb_env = getenv("WBCHECK_VERIFY_AFTER_WB");
+ if (verify_after_wb_env && (strcmp(verify_after_wb_env, "1") == 0 || strcmp(verify_after_wb_env, "true") == 0)) {
+ wbcheck_verify_after_wb_enabled = true;
+ }
+
+ // Configure useless write barrier warnings based on environment variable
+ const char *warn_useless_wb_env = getenv("WBCHECK_WARN_USELESS_WB");
+ if (warn_useless_wb_env && (strcmp(warn_useless_wb_env, "1") == 0 || strcmp(warn_useless_wb_env, "true") == 0)) {
+ wbcheck_warn_useless_wb_enabled = true;
+ }
+}
+
+// Define same heap sizes as the default GC
+static size_t heap_sizes[] = {
+ 32,
+ 40,
+ 48,
+ 56,
+ 64,
+ 72,
+ 80,
+ 96,
+ 128,
+ 160,
+ 256,
+ 512,
+ 640,
+ 768,
+ 1024,
+ 0
+};
+
+#define HEAP_COUNT ((int)(sizeof(heap_sizes) / sizeof(heap_sizes[0])) - 1)
+#define MAX_HEAP_SIZE (heap_sizes[(HEAP_COUNT) - 1])
+
+// Object states for verification tracking
+typedef enum {
+ WBCHECK_STATE_CLEAR, // Just allocated or writebarrier_remember, needs reference capture
+ WBCHECK_STATE_MARKED, // Has valid snapshot, ready for normal operation
+ WBCHECK_STATE_DIRTY // Has seen writebarrier since last snapshot, queued for verification
+} wbcheck_object_state_t;
+
+// Tri-color marking colors
+typedef enum {
+ WBCHECK_COLOR_WHITE, // Unmarked - will be swept
+ WBCHECK_COLOR_GRAY, // Marked but children not processed
+ WBCHECK_COLOR_BLACK // Marked and children processed
+} wbcheck_color_t;
+
+// GC phases
+typedef enum {
+ WBCHECK_PHASE_MUTATOR, // Normal execution
+ WBCHECK_PHASE_SNAPSHOT, // Collecting references for verification
+ WBCHECK_PHASE_FULL_GC // Marking objects during full GC
+} wbcheck_phase_t;
+
+// List of objects
+typedef struct {
+ VALUE *items;
+ size_t count;
+ size_t capacity;
+} wbcheck_object_list_t;
+
+// Helper functions for object list
+static wbcheck_object_list_t *
+wbcheck_object_list_init_with_capacity(size_t capacity)
+{
+ wbcheck_object_list_t *list = calloc(1, sizeof(wbcheck_object_list_t));
+ if (!list) rb_bug("wbcheck: failed to allocate object list structure");
+
+ if (capacity < 4) capacity = 4;
+ list->items = malloc(capacity * sizeof(VALUE));
+ if (!list->items) rb_bug("wbcheck: failed to allocate object list array");
+ list->capacity = capacity;
+ list->count = 0;
+ return list;
+}
+
+static wbcheck_object_list_t *
+wbcheck_object_list_init(void)
+{
+ return wbcheck_object_list_init_with_capacity(4);
+}
+
+static void
+wbcheck_object_list_append(wbcheck_object_list_t *list, VALUE obj)
+{
+ if (list->count >= list->capacity) {
+ size_t new_capacity = list->capacity == 0 ? 4 : list->capacity * 2;
+ VALUE *new_items = realloc(list->items, new_capacity * sizeof(VALUE));
+ if (!new_items) rb_bug("wbcheck: failed to reallocate object list array");
+ list->items = new_items;
+ list->capacity = new_capacity;
+ }
+ list->items[list->count++] = obj;
+}
+
+static void
+wbcheck_object_list_free(wbcheck_object_list_t *list)
+{
+ if (!list) return;
+ if (list->items) {
+ free(list->items);
+ }
+ free(list);
+}
+
+static void
+wbcheck_object_list_debug_print(wbcheck_object_list_t *list)
+{
+ if (!wbcheck_debug_enabled) return;
+ for (size_t i = 0; i < list->count; i++) {
+ char buff[0x100];
+ fprintf(stderr, "-> %s\n", rb_raw_obj_info(buff, sizeof(buff), list->items[i]));
+ }
+}
+
+static bool
+wbcheck_object_list_contains(wbcheck_object_list_t *list, VALUE obj)
+{
+ for (size_t i = 0; i < list->count; i++) {
+ if (list->items[i] == obj) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Information tracked for each object
+typedef struct {
+ size_t alloc_size; // Allocated size (static)
+ bool wb_protected; // Write barrier protection status (static)
+ VALUE finalizers; // Ruby Array of finalizers like [finalizer1, finalizer2, ...]
+ wbcheck_object_list_t *gc_mark_snapshot; // Snapshot of references from last GC mark
+ wbcheck_object_list_t *mark_maybe_snapshot; // Conservative refs reported via mark_maybe; needed for liveness, not verifiable
+ wbcheck_object_list_t *writebarrier_children; // References added via write barriers since last snapshot
+ wbcheck_object_state_t state; // Current state in verification lifecycle
+ wbcheck_color_t color; // Tri-color marking color
+} rb_wbcheck_object_info_t;
+
+// Finalizer job types
+struct wbcheck_final_job {
+ struct wbcheck_final_job *next;
+ enum {
+ WBCHECK_FINAL_JOB_DFREE,
+ WBCHECK_FINAL_JOB_FINALIZE,
+ } kind;
+ union {
+ struct {
+ void (*func)(void *);
+ void *data;
+ } dfree;
+ struct {
+ VALUE finalizer_array;
+ } finalize;
+ } as;
+};
+
+// wbcheck objspace structure to track all objects
+typedef struct {
+ st_table *object_table; // Hash table to track all allocated objects (VALUE -> rb_wbcheck_object_info_t*)
+ wbcheck_object_list_t *objects_to_capture; // Objects that need initial reference capture
+ wbcheck_object_list_t *objects_to_verify; // Objects that need verification after write barriers
+ wbcheck_object_list_t *current_refs; // Current list for collecting references during marking
+ wbcheck_object_list_t *current_maybe_refs; // Current list for collecting mark_maybe references during marking
+ wbcheck_object_list_t *mark_queue; // Queue of gray objects for tri-color marking
+ wbcheck_object_list_t *weak_references; // Objects holding weak references, found during marking
+ wbcheck_phase_t phase; // Current GC phase
+ bool gc_enabled; // Whether GC is allowed to run
+ bool gc_stress; // GC stress mode (run GC on every allocation)
+ size_t gc_threshold; // Trigger GC when object count reaches this
+ size_t missed_write_barrier_parents; // Number of parent objects with missed write barriers
+ size_t missed_write_barrier_children; // Total number of missed write barriers detected
+ size_t simulated_gc_count; // Simulated GC count incremented on each GC.start
+ bool measure_total_time; // Whether to accumulate :time in stats
+ struct wbcheck_final_job *finalizer_jobs; // Linked list of finalizer jobs
+ rb_nativethread_lock_t finalizer_lock; // Protects finalizer_jobs list
+ rb_postponed_job_handle_t finalizer_postponed_job; // Postponed job handle for finalizers
+} rb_wbcheck_objspace_t;
+
+// Global objspace pointer for accessing from obj_slot_size function
+static rb_wbcheck_objspace_t *wbcheck_global_objspace = NULL;
+
+// Forward declarations
+static void wbcheck_foreach_object(rb_wbcheck_objspace_t *objspace, int (*callback)(VALUE obj, rb_wbcheck_object_info_t *info, void *data), void *data);
+static int wbcheck_verify_all_references_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data);
+static int wbcheck_update_all_snapshots_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data);
+static void wbcheck_run_finalizers_for_object(VALUE obj, rb_wbcheck_object_info_t *info);
+static void gc_run_finalizers(void *data);
+static void make_final_job(rb_wbcheck_objspace_t *objspace, VALUE obj, VALUE finalizer_array);
+
+// Helper functions for object tracking
+static rb_wbcheck_object_info_t *
+wbcheck_get_object_info(VALUE obj)
+{
+ // Objspace must be initialized by this point
+ GC_ASSERT(wbcheck_global_objspace);
+
+ st_data_t value;
+ if (st_lookup(wbcheck_global_objspace->object_table, (st_data_t)obj, &value)) {
+ return (rb_wbcheck_object_info_t *)value;
+ }
+
+ fprintf(stderr, "wbcheck: object not found in tracking table\n");
+ char buff[0x100];
+ fprintf(stderr, "%s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+
+ // Force ASAN crash?
+ ((volatile VALUE *)obj)[0];
+
+ // Object not found in tracking table - this should never happen
+ rb_bug("wbcheck: object not found in tracking table");
+}
+
+static void
+wbcheck_report_error(void *objspace_ptr, VALUE parent_obj, wbcheck_object_list_t *current_refs, wbcheck_object_list_t *gc_mark_snapshot, wbcheck_object_list_t *writebarrier_children, wbcheck_object_list_t *missed_refs)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ rb_wbcheck_object_info_t *parent_info = wbcheck_get_object_info(parent_obj);
+
+ size_t snapshot_count = gc_mark_snapshot ? gc_mark_snapshot->count : 0;
+ size_t wb_count = writebarrier_children ? writebarrier_children->count : 0;
+
+ fprintf(stderr, "WBCHECK ERROR: Missed write barrier detected!\n");
+ fprintf(stderr, " Parent object: %p (wb_protected: %s)\n",
+ (void *)parent_obj, parent_info->wb_protected ? "true" : "false");
+ char buff[0x100];
+ fprintf(stderr, " %s\n", rb_raw_obj_info(buff, sizeof(buff), parent_obj));
+ fprintf(stderr, " Reference counts - snapshot: %zu, writebarrier: %zu, current: %zu, missed: %zu\n",
+ snapshot_count, wb_count, current_refs->count, missed_refs->count);
+
+ for (size_t i = 0; i < missed_refs->count; i++) {
+ VALUE missed_ref = missed_refs->items[i];
+ char buff[0x100];
+ fprintf(stderr, " Missing reference to: %p\n %s\n", (void *)missed_ref, rb_raw_obj_info(buff, sizeof(buff), missed_ref));
+ }
+
+ fprintf(stderr, "\n");
+ objspace->missed_write_barrier_parents++;
+ objspace->missed_write_barrier_children += missed_refs->count;
+}
+
+static void
+wbcheck_compare_references(void *objspace_ptr, VALUE parent_obj, wbcheck_object_list_t *current_refs, wbcheck_object_list_t *gc_mark_snapshot, wbcheck_object_list_t *writebarrier_children)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ (void)objspace;
+
+ size_t snapshot_count = gc_mark_snapshot ? gc_mark_snapshot->count : 0;
+ size_t wb_count = writebarrier_children ? writebarrier_children->count : 0;
+
+ WBCHECK_DEBUG("wbcheck: comparing references for object %p\n", (void *)parent_obj);
+ WBCHECK_DEBUG("wbcheck: current refs: %zu, snapshot refs: %zu, wb refs: %zu\n",
+ current_refs->count, snapshot_count, wb_count);
+
+ // Collect missed references (lazily allocated)
+ wbcheck_object_list_t *missed_refs = NULL;
+
+ // Use circular comparison for better performance when lists are mostly similar
+ size_t snapshot_idx = 0;
+
+ // Check each object in current_refs to see if it's in either stored list
+ for (size_t i = 0; i < current_refs->count; i++) {
+ VALUE current_ref = current_refs->items[i];
+
+ // Usually the lists are nearly identical. We take advantage of this by
+ // attempting to loop over both lists in sequence. When the next element
+ // of the snapshot doesn't match the next element of our current_refs,
+ // we'll loop around the list to try to find it and continue from that
+ // match, so any runs of identical items can be matched efficiently.
+ //
+ // Pathologically this is O(N**2), but is O(N * num_changes)
+ bool found_in_snapshot = false;
+ if (gc_mark_snapshot && snapshot_count > 0) {
+ size_t start_idx = snapshot_idx;
+ do {
+ if (gc_mark_snapshot->items[snapshot_idx] == current_ref) {
+ found_in_snapshot = true;
+ snapshot_idx++;
+ if (snapshot_idx >= snapshot_count) snapshot_idx = 0;
+ break;
+ }
+ snapshot_idx++;
+ if (snapshot_idx >= snapshot_count) snapshot_idx = 0;
+ } while (snapshot_idx != start_idx);
+ }
+
+ if (found_in_snapshot) {
+ continue;
+ }
+
+ // Built-in immortal classes can be assigned via RBASIC_SET_CLASS_RAW,
+ // which bypasses the write barrier. They're pinned as VM roots and
+ // can never be collected, so a missing WB to them is harmless.
+ if (RB_TYPE_P(current_ref, T_CLASS) && FL_TEST_RAW(current_ref, RCLASS_IS_ROOT)) {
+ continue;
+ }
+
+ // Self reference... Weird but okay I guess
+ if (current_ref == parent_obj) {
+ continue;
+ }
+
+
+ // Check if reference exists in writebarrier_children
+ if (writebarrier_children && wbcheck_object_list_contains(writebarrier_children, current_ref)) {
+ continue;
+ }
+
+ // If we get here, the reference wasn't found in either list
+ // Lazily allocate missed_refs list on first miss
+ if (!missed_refs) {
+ missed_refs = wbcheck_object_list_init();
+ }
+ wbcheck_object_list_append(missed_refs, current_ref);
+ }
+
+ // Report any errors found
+ if (missed_refs) {
+ wbcheck_report_error(objspace_ptr, parent_obj, current_refs, gc_mark_snapshot, writebarrier_children, missed_refs);
+ wbcheck_object_list_free(missed_refs);
+ }
+}
+
+static void
+wbcheck_register_object(void *objspace_ptr, VALUE obj, size_t alloc_size, bool wb_protected)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ // Allocate and initialize object info structure
+ rb_wbcheck_object_info_t *info = calloc(1, sizeof(rb_wbcheck_object_info_t));
+ if (!info) rb_bug("wbcheck_register_object: failed to allocate object info");
+
+ info->alloc_size = alloc_size;
+ info->wb_protected = wb_protected;
+ info->finalizers = 0; /* No finalizers initially */
+ info->gc_mark_snapshot = NULL; /* No snapshot initially */
+ info->mark_maybe_snapshot = NULL; /* No mark_maybe snapshot initially */
+ info->writebarrier_children = NULL; /* No write barrier children initially */
+ info->state = WBCHECK_STATE_CLEAR; /* Start in clear state */
+ info->color = WBCHECK_COLOR_BLACK; /* Start as black to survive current GC */
+
+ // Store object info in hash table (VALUE -> rb_wbcheck_object_info_t*)
+ st_insert(objspace->object_table, (st_data_t)obj, (st_data_t)info);
+}
+
+static void
+wbcheck_unregister_object(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ rb_wbcheck_object_info_t *info;
+
+ if (st_delete(objspace->object_table, (st_data_t *)&obj, (st_data_t *)&info)) {
+ // Free object lists if they were allocated
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ free(info);
+ } else {
+ rb_bug("wbcheck_unregister_object: object not found in table");
+ }
+}
+
+// Bootup
+void *
+rb_gc_impl_objspace_alloc(void)
+{
+ wbcheck_configure_from_env();
+
+ rb_wbcheck_objspace_t *objspace = calloc(1, sizeof(rb_wbcheck_objspace_t));
+ if (!objspace) rb_bug("wbcheck: failed to allocate objspace");
+
+ objspace->object_table = st_init_numtable();
+ if (!objspace->object_table) {
+ free(objspace);
+ rb_bug("wbcheck: failed to create object table");
+ }
+
+ objspace->objects_to_capture = wbcheck_object_list_init(); // Initialize empty list
+ objspace->objects_to_verify = wbcheck_object_list_init(); // Initialize empty list
+ objspace->current_refs = NULL; // No current refs initially
+ objspace->current_maybe_refs = NULL; // No current maybe refs initially
+ objspace->mark_queue = wbcheck_object_list_init(); // Initialize mark queue
+ objspace->weak_references = wbcheck_object_list_init(); // Initialize weak references array
+ objspace->phase = WBCHECK_PHASE_MUTATOR; // Start in mutator phase
+ objspace->gc_enabled = true; // GC enabled by default (like default GC)
+ objspace->gc_stress = false; // GC stress disabled by default
+ objspace->gc_threshold = 1000; // Start with 1000 objects, will adjust after first GC
+ objspace->missed_write_barrier_parents = 0; // No errors found yet
+ objspace->missed_write_barrier_children = 0; // No errors found yet
+ objspace->simulated_gc_count = 0; // Start with GC count of 0
+ objspace->measure_total_time = true; // On by default
+
+ return objspace;
+}
+
+void
+rb_gc_impl_objspace_init(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ // Object table is already initialized in objspace_alloc
+ // Set up global objspace pointer for obj_slot_size function
+ wbcheck_global_objspace = objspace;
+
+ // Initialize postponed job for finalizers
+ rb_native_mutex_initialize(&objspace->finalizer_lock);
+ objspace->finalizer_postponed_job = rb_postponed_job_preregister(0, gc_run_finalizers, objspace);
+}
+
+void *
+rb_gc_impl_ractor_cache_alloc(void *objspace_ptr, void *ractor)
+{
+ // Stub implementation
+ return NULL;
+}
+
+void
+rb_gc_impl_set_params(void *objspace_ptr)
+{
+ // Stub implementation
+}
+
+static VALUE
+gc_verify_internal_consistency(VALUE self)
+{
+ return Qnil;
+}
+
+void
+rb_gc_impl_init(void)
+{
+ VALUE gc_constants = rb_hash_new();
+ //rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(BASE_SLOT_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RBASIC_SIZE")), SIZET2NUM(sizeof(struct RBasic)));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), INT2NUM(0));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(MAX_HEAP_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_COUNT")), LONG2FIX(HEAP_COUNT));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(HEAP_COUNT));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), INT2FIX(3));
+ OBJ_FREEZE(gc_constants);
+ rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
+
+ // no-ops for compatibility
+ rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency, 0);
+
+ rb_define_singleton_method(rb_mGC, "compact", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact=", rb_f_notimplement, 1);
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
+ // Stub implementation
+}
+
+size_t *
+rb_gc_impl_heap_sizes(void *objspace_ptr)
+{
+ return heap_sizes;
+}
+
+// Shutdown
+void
+rb_gc_impl_shutdown_free_objects(void *objspace_ptr)
+{
+ // Stub implementation
+}
+
+void
+rb_gc_impl_objspace_free(void *objspace_ptr)
+{
+ // This should free everything, but we'll just let it leak
+}
+
+void
+rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache)
+{
+ // Stub implementation
+}
+
+// GC
+void
+rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ if (objspace) {
+ objspace->simulated_gc_count++;
+ }
+
+ if (!ruby_native_thread_p()) return;
+
+ unsigned int lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+ force_gc(objspace_ptr);
+ RB_GC_VM_UNLOCK(lev);
+}
+
+bool
+rb_gc_impl_during_gc_p(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->phase != WBCHECK_PHASE_MUTATOR;
+}
+
+static void
+wbcheck_prepare_heap_i(VALUE obj, void *data)
+{
+ rb_gc_prepare_heap_process_object(obj);
+}
+
+void
+rb_gc_impl_prepare_heap(void *objspace_ptr)
+{
+ rb_gc_impl_each_object(objspace_ptr, wbcheck_prepare_heap_i, NULL);
+}
+
+void
+rb_gc_impl_gc_enable(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->gc_enabled = true;
+}
+
+void
+rb_gc_impl_gc_disable(void *objspace_ptr, bool finish_current_gc)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->gc_enabled = false;
+}
+
+bool
+rb_gc_impl_gc_enabled_p(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->gc_enabled;
+}
+
+void
+rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->gc_stress = RTEST(flag);
+}
+
+VALUE
+rb_gc_impl_stress_get(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->gc_stress ? Qtrue : Qfalse;
+}
+
+VALUE
+rb_gc_impl_config_get(void *objspace_ptr)
+{
+ return rb_hash_new();
+}
+
+void
+rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
+{
+}
+
+static wbcheck_object_list_t *
+wbcheck_collect_references_from_object(VALUE obj, rb_wbcheck_object_info_t *info)
+{
+ rb_wbcheck_objspace_t *objspace = wbcheck_global_objspace;
+
+ // Use combination of writebarrier children and last snapshot as capacity hint
+ size_t snapshot_count = (info->gc_mark_snapshot) ? info->gc_mark_snapshot->count : 0;
+ size_t wb_children_count = (info->writebarrier_children) ? info->writebarrier_children->count : 0;
+ size_t capacity_hint = snapshot_count + wb_children_count;
+ wbcheck_object_list_t *new_list = wbcheck_object_list_init_with_capacity(capacity_hint);
+
+ // Set up objspace state for marking. current_maybe_refs is allocated lazily
+ // by rb_gc_impl_mark_maybe, since most objects have no conservative refs.
+ objspace->current_refs = new_list;
+ objspace->current_maybe_refs = NULL;
+ objspace->phase = WBCHECK_PHASE_SNAPSHOT;
+
+ // Use the marking infrastructure to collect references
+ rb_gc_mark_children(objspace, obj);
+
+ // Clean up objspace state
+ objspace->phase = WBCHECK_PHASE_MUTATOR;
+ objspace->current_refs = NULL;
+
+ // Update the mark_maybe snapshot in place. These references don't participate
+ // in verification, but we need to keep them so full GC can mark them gray.
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ info->mark_maybe_snapshot = objspace->current_maybe_refs;
+ objspace->current_maybe_refs = NULL;
+
+ if (wbcheck_debug_enabled) {
+ WBCHECK_DEBUG("wbcheck: collected %zu references from %p\n", new_list->count, (void *)obj);
+ char buff[0x100];
+ fprintf(stderr, "%s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+ wbcheck_object_list_debug_print(new_list);
+ }
+
+ return new_list;
+}
+
+static void
+wbcheck_collect_initial_references(void *objspace_ptr, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: collecting initial references from %p:\n", obj);
+ wbcheck_debug_obj_info_dump(obj);
+
+ // Get the object info and set the initial GC mark snapshot
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+ wbcheck_object_list_t *new_list = wbcheck_collect_references_from_object(obj, info);
+ RUBY_ASSERT(!info->gc_mark_snapshot);
+ RUBY_ASSERT(info->state == WBCHECK_STATE_CLEAR);
+ info->gc_mark_snapshot = new_list; // Set the initial snapshot
+ info->state = WBCHECK_STATE_MARKED; // Transition to marked state
+}
+
+static void
+wbcheck_verify_object_references(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ // Ignore objects which are not write barrier protected
+ if (!info->wb_protected) {
+ return;
+ }
+
+ // We hadn't captured initial references
+ if (info->state == WBCHECK_STATE_CLEAR) {
+ RUBY_ASSERT(!info->gc_mark_snapshot);
+ return;
+ }
+
+ WBCHECK_DEBUG("wbcheck: verifying references for object:\n");
+ wbcheck_debug_obj_info_dump(obj);
+
+ // Get the current references from the object
+ wbcheck_object_list_t *current_refs = wbcheck_collect_references_from_object(obj, info);
+
+ // Check for useless write barriers before clearing them
+ if (wbcheck_warn_useless_wb_enabled && info->writebarrier_children) {
+ for (size_t i = 0; i < info->writebarrier_children->count; i++) {
+ VALUE wb_ref = info->writebarrier_children->items[i];
+ if (!wbcheck_object_list_contains(current_refs, wb_ref)) {
+ fprintf(stderr, "WBCHECK WARNING: Potentially useless write barrier detected for object %p\n", (void *)obj);
+ fprintf(stderr, " Write barrier was recorded for reference to %p, but object no longer references it\n", (void *)wb_ref);
+ char buff[0x100];
+ fprintf(stderr, " Parent: %s\n", rb_raw_obj_info(buff, sizeof(buff), obj));
+ fprintf(stderr, " Stale reference: %s\n", rb_raw_obj_info(buff, sizeof(buff), wb_ref));
+ }
+ }
+ }
+
+ // Compare current_refs against both stored lists to detect missed write barriers
+ wbcheck_compare_references(objspace_ptr, obj, current_refs, info->gc_mark_snapshot, info->writebarrier_children);
+
+ // Update the snapshot with current references and clear write barrier children
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ info->gc_mark_snapshot = current_refs;
+ info->writebarrier_children = NULL;
+ info->state = WBCHECK_STATE_MARKED; // Back to marked state after verification
+}
+
+// Mark object as gray (add to mark queue)
+static void
+wbcheck_mark_gray(rb_wbcheck_objspace_t *objspace, VALUE obj)
+{
+ if (RB_SPECIAL_CONST_P(obj)) return;
+
+ st_data_t value;
+ if (!st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_bug("wbcheck: asked to mark object %p not in our object table", (void *)obj);
+ }
+
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ if (info->color != WBCHECK_COLOR_WHITE) {
+ return; // Already marked
+ }
+
+ info->color = WBCHECK_COLOR_GRAY;
+ wbcheck_object_list_append(objspace->mark_queue, obj);
+
+ if (RB_FL_TEST_RAW(obj, RUBY_FL_WEAK_REFERENCE)) {
+ wbcheck_object_list_append(objspace->weak_references, obj);
+ }
+
+ WBCHECK_DEBUG("wbcheck: marked gray: %p\n", (void *)obj);
+}
+
+// Reset all objects to white
+static int
+st_foreach_reset_white(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ info->color = WBCHECK_COLOR_WHITE;
+ return ST_CONTINUE;
+}
+
+// Mark all finalizer arrays to keep them alive during GC
+static int
+st_foreach_mark_finalizers(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)arg;
+
+ if (info->finalizers) {
+ wbcheck_mark_gray(objspace, info->finalizers);
+ }
+
+ return ST_CONTINUE;
+}
+
+// Full mark phase using tri-color marking with snapshots
+static void
+wbcheck_mark_phase(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: starting GC mark phase\n");
+
+ objspace->phase = WBCHECK_PHASE_FULL_GC;
+
+ // Clear mark queue and reset all objects to white
+ objspace->mark_queue->count = 0;
+ st_foreach(objspace->object_table, st_foreach_reset_white, 0);
+
+ // Mark all finalizer arrays first to keep them alive
+ st_foreach(objspace->object_table, st_foreach_mark_finalizers, (st_data_t)objspace);
+
+ // Mark finalizer arrays in pending jobs to keep them alive.
+ // No lock needed: all other threads are stopped during GC.
+ struct wbcheck_final_job *job = objspace->finalizer_jobs;
+ while (job != NULL) {
+ switch (job->kind) {
+ case WBCHECK_FINAL_JOB_DFREE:
+ break;
+ case WBCHECK_FINAL_JOB_FINALIZE:
+ wbcheck_mark_gray(objspace, job->as.finalize.finalizer_array);
+ break;
+ default:
+ rb_bug("wbcheck_mark_phase: unknown final job type %d", job->kind);
+ }
+ job = job->next;
+ }
+
+ // Mark roots gray
+ rb_gc_save_machine_context();
+ rb_gc_mark_roots(objspace, NULL);
+
+ // Process gray queue until empty
+ while (objspace->mark_queue->count > 0) {
+ // Get last object from queue (LIFO)
+ VALUE obj = objspace->mark_queue->items[--objspace->mark_queue->count];
+
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ if (info->color == WBCHECK_COLOR_GRAY) {
+ // Mark all children from snapshot gray
+ if (info->gc_mark_snapshot) {
+ for (size_t i = 0; i < info->gc_mark_snapshot->count; i++) {
+ wbcheck_mark_gray(objspace, info->gc_mark_snapshot->items[i]);
+ }
+ }
+
+ // Conservatively-scanned children must also be kept alive
+ if (info->mark_maybe_snapshot) {
+ for (size_t i = 0; i < info->mark_maybe_snapshot->count; i++) {
+ wbcheck_mark_gray(objspace, info->mark_maybe_snapshot->items[i]);
+ }
+ }
+
+ // Mark this object black
+ info->color = WBCHECK_COLOR_BLACK;
+ WBCHECK_DEBUG("wbcheck: marked black: %p\n", (void *)obj);
+ }
+ }
+ }
+
+ objspace->phase = WBCHECK_PHASE_MUTATOR;
+
+ WBCHECK_DEBUG("wbcheck: tri-color mark phase complete\n");
+}
+
+// Sweep phase callback - free white objects
+static int
+wbcheck_sweep_callback(st_data_t key, st_data_t val, st_data_t arg, int error)
+{
+ VALUE obj = (VALUE)key;
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)arg;
+
+ if (info->color == WBCHECK_COLOR_WHITE) {
+ WBCHECK_DEBUG("wbcheck: sweeping unmarked object %p\n", (void *)obj);
+
+ rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_FREEOBJ);
+
+ // Clear weak references first
+ rb_gc_obj_free_vm_weak_references(obj);
+
+ // Queue finalizers for postponed job if they exist
+ if (info->finalizers) {
+ make_final_job(objspace, obj, info->finalizers);
+ rb_postponed_job_trigger(objspace->finalizer_postponed_job);
+ }
+
+ // Call rb_gc_obj_free which handles finalizers/zombies
+ if (rb_gc_obj_free(objspace, obj)) {
+ // Object was actually freed, clean up our tracking
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ free(info);
+
+ // Free the actual object memory
+ free((void *)obj);
+
+ return ST_DELETE; // Remove from hash table
+ } else {
+ // Object became a zombie - it will be freed by postponed job
+ // Remove from tracking since we can't safely access it anymore
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ wbcheck_object_list_free(info->writebarrier_children);
+ free(info);
+
+ // Free the actual object memory
+ free((void *)obj);
+
+ return ST_DELETE; // Remove from hash table
+ }
+ }
+
+ return ST_CONTINUE; // Keep marked objects
+}
+
+static void
+wbcheck_sweep_phase(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: starting sweep phase\n");
+
+ size_t objects_before = st_table_size(objspace->object_table);
+
+ // Sweep unmarked objects
+ st_foreach_check(objspace->object_table, wbcheck_sweep_callback, (st_data_t)objspace, 0);
+
+ size_t objects_after = st_table_size(objspace->object_table);
+ size_t freed_objects = objects_before - objects_after;
+
+ // Update GC threshold: 2x the live set after GC
+ objspace->gc_threshold = objects_after * 2;
+
+ WBCHECK_DEBUG("wbcheck: sweep phase complete - freed %zu objects (%zu -> %zu), new threshold: %zu\n",
+ freed_objects, objects_before, objects_after, objspace->gc_threshold);
+}
+
+// Process weak references after marking - call rb_gc_handle_weak_references
+// on each object that was flagged with RUBY_FL_WEAK_REFERENCE and collected
+// during the mark phase.
+static void
+wbcheck_process_weak_references(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: processing %zu weak reference objects\n", objspace->weak_references->count);
+
+ for (size_t i = 0; i < objspace->weak_references->count; i++) {
+ VALUE obj = objspace->weak_references->items[i];
+ rb_gc_handle_weak_references(obj);
+ }
+
+ objspace->weak_references->count = 0;
+}
+
+// Full GC: verify all objects then mark from roots
+static void
+wbcheck_full_gc(rb_wbcheck_objspace_t *objspace)
+{
+ WBCHECK_DEBUG("wbcheck: starting full GC\n");
+
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_ENTER);
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_START);
+
+ // First, update snapshots for all objects (verify wb_protected ones)
+ WBCHECK_DEBUG("wbcheck: updating snapshots for all objects\n");
+ wbcheck_foreach_object(objspace, wbcheck_update_all_snapshots_callback, objspace);
+
+ // Now start tri-color marking
+ wbcheck_mark_phase(objspace);
+
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_MARK);
+
+ // Process weak references after marking, before sweeping
+ wbcheck_process_weak_references(objspace);
+
+ // Sweep unmarked objects
+ wbcheck_sweep_phase(objspace);
+
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
+ rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_EXIT);
+
+ WBCHECK_DEBUG("wbcheck: full GC complete\n");
+}
+
+static void
+gc_step(void *objspace_ptr, bool force)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ // Not initialized yet
+ if (!objspace) return;
+
+ if (!objspace->gc_enabled && !force) return;
+
+ // Process all objects that need verification after write barriers (if enabled)
+ if (wbcheck_verify_after_wb_enabled) {
+ for (size_t i = 0; i < objspace->objects_to_verify->count; i++) {
+ VALUE obj = objspace->objects_to_verify->items[i];
+ wbcheck_verify_object_references(objspace_ptr, obj);
+ }
+
+ // Clear the list after processing
+ objspace->objects_to_verify->count = 0;
+
+ // If any new errors were detected during verification, exit immediately
+ if (objspace->missed_write_barrier_parents > 0) {
+ rb_bug("wbcheck: missed write barrier detected during immediate verification (WBCHECK_VERIFY_AFTER_WB=1)");
+ }
+ }
+
+ // Process all objects that need initial reference capture
+ for (size_t i = 0; i < objspace->objects_to_capture->count; i++) {
+ VALUE obj = objspace->objects_to_capture->items[i];
+ wbcheck_collect_initial_references(objspace_ptr, obj);
+ }
+
+ // Clear the list after processing
+ objspace->objects_to_capture->count = 0;
+
+ // Run full GC if forced, if we exceed the threshold, or if gc_stress is enabled
+ if (ruby_native_thread_p() &&
+ (force ||
+ (objspace->gc_enabled &&
+ (objspace->gc_stress || st_table_size(objspace->object_table) >= objspace->gc_threshold)))) {
+ wbcheck_full_gc(objspace);
+ }
+
+}
+
+static void
+maybe_gc(void *objspace_ptr)
+{
+ gc_step(objspace_ptr, false);
+}
+
+static void
+force_gc(void *objspace_ptr)
+{
+ gc_step(objspace_ptr, true);
+}
+
+int ruby_thread_has_gvl_p(void);
+
+static void *
+lock_and_maybe_gc_gvl(void *objspace_ptr)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+
+ maybe_gc(objspace_ptr);
+
+ RB_GC_VM_UNLOCK(lev);
+ return NULL;
+}
+
+static void
+lock_and_maybe_gc(void *objspace_ptr)
+{
+ if (!ruby_native_thread_p()) return;
+
+ if (!ruby_thread_has_gvl_p()) {
+ rb_thread_call_with_gvl(lock_and_maybe_gc_gvl, objspace_ptr);
+ }
+ else {
+ lock_and_maybe_gc_gvl(objspace_ptr);
+ }
+}
+
+VALUE
+rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+ rb_gc_vm_barrier();
+
+ // Check if we should trigger GC before allocating
+ maybe_gc(objspace_ptr);
+
+ // Ensure minimum allocation size of BASE_SLOT_SIZE
+ alloc_size = heap_sizes[rb_gc_impl_heap_id_for_size(objspace_ptr, alloc_size)];
+
+ // Allocate memory for the object
+ VALUE *mem = malloc(alloc_size);
+ if (!mem) rb_bug("FIXME: malloc failed");
+
+ // Initialize the object
+ VALUE obj = (VALUE)mem;
+ RBASIC(obj)->flags = flags;
+ *((VALUE *)&RBASIC(obj)->klass) = klass;
+
+ // Register the new object in our tracking table
+ wbcheck_register_object(objspace_ptr, obj, alloc_size, wb_protected);
+
+ // Add this object to the list of objects that need initial reference capture
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ wbcheck_object_list_append(objspace->objects_to_capture, obj);
+
+ RB_GC_VM_UNLOCK(lev);
+ return obj;
+}
+
+size_t
+rb_gc_impl_obj_slot_size(VALUE obj)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+ size_t result = info->alloc_size;
+
+ RB_GC_VM_UNLOCK(lev);
+ return result;
+}
+
+size_t
+rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
+{
+ for (int i = 0; i < HEAP_COUNT; i++) {
+ if (size <= heap_sizes[i]) return i;
+ }
+ rb_bug("size too big");
+}
+
+bool
+rb_gc_impl_size_allocatable_p(size_t size)
+{
+ // Only allow sizes up to the largest heap size
+ return size <= MAX_HEAP_SIZE;
+}
+
+// Malloc
+void *
+rb_gc_impl_malloc(void *objspace_ptr, size_t size, bool gc_allowed)
+{
+ if (gc_allowed) {
+ lock_and_maybe_gc(objspace_ptr);
+ }
+ return malloc(size);
+}
+
+void *
+rb_gc_impl_calloc(void *objspace_ptr, size_t size, bool gc_allowed)
+{
+ if (gc_allowed) {
+ lock_and_maybe_gc(objspace_ptr);
+ }
+ return calloc(1, size);
+}
+
+void *
+rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size, bool gc_allowed)
+{
+ if (gc_allowed) {
+ lock_and_maybe_gc(objspace_ptr);
+ }
+ return realloc(ptr, new_size);
+}
+
+void
+rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
+{
+ free(ptr);
+}
+
+void
+rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff)
+{
+ // For wbcheck, we don't track memory usage
+}
+
+// Marking
+static void
+gc_mark(rb_wbcheck_objspace_t *objspace, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: gc_mark called\n");
+ wbcheck_debug_obj_info_dump(obj);
+
+ if (RB_SPECIAL_CONST_P(obj)) return;
+
+ switch (objspace->phase) {
+ case WBCHECK_PHASE_SNAPSHOT:
+ // Collecting references during verification
+ GC_ASSERT(objspace->current_refs);
+ wbcheck_object_list_append(objspace->current_refs, obj);
+ break;
+ case WBCHECK_PHASE_FULL_GC:
+ // Marking during full GC
+ wbcheck_mark_gray(objspace, obj);
+ break;
+ case WBCHECK_PHASE_MUTATOR:
+ // Should not be called during mutator phase
+ rb_bug("wbcheck: gc_mark called during mutator phase");
+ break;
+ }
+}
+
+void
+rb_gc_impl_mark(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+ gc_mark(objspace, obj);
+}
+
+void
+rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+ gc_mark(objspace, *ptr);
+}
+
+void
+rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+ gc_mark(objspace, obj);
+}
+
+void
+rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ if (!rb_gc_impl_pointer_to_heap_p(objspace_ptr, (void *)obj)) return;
+
+ switch (objspace->phase) {
+ case WBCHECK_PHASE_SNAPSHOT:
+ // We don't know if this is actually a reference or just a value
+ // that looks like one, so we can't expect a write barrier for it.
+ // Keep it separate from the verifiable refs, but retain it so full
+ // GC can mark the target gray if it does turn out to be live.
+ if (!objspace->current_maybe_refs) {
+ objspace->current_maybe_refs = wbcheck_object_list_init();
+ }
+ wbcheck_object_list_append(objspace->current_maybe_refs, obj);
+ break;
+ case WBCHECK_PHASE_FULL_GC:
+ wbcheck_mark_gray(objspace, obj);
+ break;
+ case WBCHECK_PHASE_MUTATOR:
+ rb_bug("wbcheck: rb_gc_impl_mark_maybe called during mutator phase");
+ break;
+ }
+}
+
+// Weak references
+void
+rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
+{
+ FL_SET_RAW(obj, RUBY_FL_WEAK_REFERENCE);
+}
+
+bool
+rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ return info->color != WBCHECK_COLOR_WHITE;
+ }
+
+ return false;
+}
+
+// Compaction
+void
+rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
+{
+ /* no-op */
+}
+
+bool
+rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
+{
+ // Stub implementation
+ return false;
+}
+
+VALUE
+rb_gc_impl_location(void *objspace_ptr, VALUE value)
+{
+ // Stub implementation
+ return Qnil;
+}
+
+// Write barriers
+void
+rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
+{
+ if (RB_SPECIAL_CONST_P(b)) return;
+
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
+
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ // Get the object info for the parent object (a)
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(a);
+
+ // Only record the write barrier if we have a valid snapshot
+ if (info->state != WBCHECK_STATE_CLEAR) {
+ RUBY_ASSERT(info->gc_mark_snapshot);
+
+ // Initialize writebarrier_children list if it doesn't exist
+ if (!info->writebarrier_children) {
+ info->writebarrier_children = wbcheck_object_list_init();
+ }
+
+ // Add the new reference to the write barrier children list
+ wbcheck_object_list_append(info->writebarrier_children, b);
+
+ WBCHECK_DEBUG("wbcheck: write barrier recorded reference from %p to %p\n", (void *)a, (void *)b);
+
+ // If verification after write barrier is enabled, queue the object for verification
+ if (wbcheck_verify_after_wb_enabled && info->state != WBCHECK_STATE_DIRTY) {
+ WBCHECK_DEBUG("wbcheck: queueing object for verification after write barrier\n");
+ info->state = WBCHECK_STATE_DIRTY; // Mark as dirty
+ wbcheck_object_list_append(objspace->objects_to_verify, a);
+ }
+ } else {
+ WBCHECK_DEBUG("wbcheck: write barrier skipped (snapshot not initialized) from %p to %p\n", (void *)a, (void *)b);
+ }
+
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+void
+rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: writebarrier_unprotect called on object %p\n", (void *)obj);
+
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
+
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+ info->wb_protected = false;
+
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+void
+rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
+{
+ WBCHECK_DEBUG("wbcheck: writebarrier_remember called on object %p\n", (void *)obj);
+
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
+
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ // Clear existing references since they may be stale
+ if (info->state != WBCHECK_STATE_CLEAR) {
+ RUBY_ASSERT(info->gc_mark_snapshot);
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ info->gc_mark_snapshot = NULL;
+
+ wbcheck_object_list_free(info->mark_maybe_snapshot);
+ info->mark_maybe_snapshot = NULL;
+
+ // Only re-add to objects_to_capture if it had previous snapshot
+ // (new objects don't need to be re-added since they'll be captured at allocation)
+ wbcheck_object_list_append(objspace->objects_to_capture, obj);
+
+ // Also clear write barrier children
+ if (info->writebarrier_children) {
+ wbcheck_object_list_free(info->writebarrier_children);
+ info->writebarrier_children = NULL;
+ }
+
+ // Reset to clear state
+ info->state = WBCHECK_STATE_CLEAR;
+ }
+ RUBY_ASSERT(!info->gc_mark_snapshot);
+ RUBY_ASSERT(!info->mark_maybe_snapshot);
+ RUBY_ASSERT(!info->writebarrier_children);
+
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
+}
+
+// Heap walking
+struct wbcheck_foreach_data {
+ int (*callback)(VALUE obj, rb_wbcheck_object_info_t *info, void *data);
+ void *data;
+};
+
+static int
+wbcheck_foreach_object_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE obj = (VALUE)key;
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)val;
+ struct wbcheck_foreach_data *foreach_data = (struct wbcheck_foreach_data *)arg;
+
+ return foreach_data->callback(obj, info, foreach_data->data);
+}
+
+static void
+wbcheck_foreach_object(rb_wbcheck_objspace_t *objspace, int (*callback)(VALUE obj, rb_wbcheck_object_info_t *info, void *data), void *data)
+{
+ struct wbcheck_foreach_data foreach_data = {
+ .callback = callback,
+ .data = data
+ };
+
+ st_foreach(objspace->object_table, wbcheck_foreach_object_i, (st_data_t)&foreach_data);
+}
+
+// Helper to collect all objects into a snapshot list
+static int
+wbcheck_snapshot_collector(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE obj = (VALUE)key;
+ wbcheck_object_list_t *snapshot = (wbcheck_object_list_t *)arg;
+ wbcheck_object_list_append(snapshot, obj);
+ return ST_CONTINUE;
+}
+
+// Take a snapshot of all objects for safe iteration
+static wbcheck_object_list_t *
+wbcheck_take_object_snapshot(rb_wbcheck_objspace_t *objspace)
+{
+ size_t object_count = st_table_size(objspace->object_table);
+ wbcheck_object_list_t *snapshot = wbcheck_object_list_init_with_capacity(object_count);
+ st_foreach(objspace->object_table, wbcheck_snapshot_collector, (st_data_t)snapshot);
+ return snapshot;
+}
+
+
+void
+rb_gc_impl_each_objects(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ wbcheck_object_list_t *snapshot = wbcheck_take_object_snapshot(objspace);
+
+ for (size_t i = 0; i < snapshot->count; i++) {
+ VALUE obj = snapshot->items[i];
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ rb_wbcheck_object_info_t *info = (rb_wbcheck_object_info_t *)value;
+ int result = callback(
+ (void *)obj,
+ (void *)((char *)obj + info->alloc_size),
+ info->alloc_size,
+ data
+ );
+ if (result != 0) break;
+ }
+ }
+
+ wbcheck_object_list_free(snapshot);
+}
+
+void
+rb_gc_impl_each_object(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ wbcheck_object_list_t *snapshot = wbcheck_take_object_snapshot(objspace);
+
+ for (size_t i = 0; i < snapshot->count; i++) {
+ VALUE obj = snapshot->items[i];
+ st_data_t value;
+ if (st_lookup(objspace->object_table, (st_data_t)obj, &value)) {
+ func(obj, data);
+ }
+ }
+
+ wbcheck_object_list_free(snapshot);
+}
+
+static void
+finalizer_jobs_push(rb_wbcheck_objspace_t *objspace, struct wbcheck_final_job *job)
+{
+ rb_native_mutex_lock(&objspace->finalizer_lock);
+ job->next = objspace->finalizer_jobs;
+ objspace->finalizer_jobs = job;
+ rb_native_mutex_unlock(&objspace->finalizer_lock);
+}
+
+static struct wbcheck_final_job *
+finalizer_jobs_pop(rb_wbcheck_objspace_t *objspace)
+{
+ rb_native_mutex_lock(&objspace->finalizer_lock);
+ struct wbcheck_final_job *job = objspace->finalizer_jobs;
+ if (job) {
+ objspace->finalizer_jobs = job->next;
+ }
+ rb_native_mutex_unlock(&objspace->finalizer_lock);
+ return job;
+}
+
+// Finalizers
+void
+rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data)
+{
+ if (dfree == NULL) return;
+
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+
+ struct wbcheck_final_job *job = malloc(sizeof(struct wbcheck_final_job));
+ job->kind = WBCHECK_FINAL_JOB_DFREE;
+ job->as.dfree.func = dfree;
+ job->as.dfree.data = data;
+
+ finalizer_jobs_push(objspace, job);
+
+ if (!ruby_free_at_exit_p()) {
+ rb_postponed_job_trigger(objspace->finalizer_postponed_job);
+ }
+
+ WBCHECK_DEBUG("wbcheck: made zombie for object %p with dfree function\n", (void *)obj);
+}
+
+VALUE
+rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ (void)objspace_ptr;
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ GC_ASSERT(!OBJ_FROZEN(obj));
+
+ RBASIC(obj)->flags |= FL_FINALIZE;
+
+ VALUE table = info->finalizers;
+ VALUE result = block;
+
+ if (!table) {
+ /* First finalizer for this object - store object ID as first element */
+ table = rb_ary_new3(2, rb_obj_id(obj), block);
+ rb_obj_hide(table);
+ info->finalizers = table;
+ } else {
+ /* Check for duplicate finalizers (skip index 0 which is object ID) */
+ long len = RARRAY_LEN(table);
+ long i;
+
+ for (i = 1; i < len; i++) {
+ VALUE recv = RARRAY_AREF(table, i);
+ if (rb_equal(recv, block)) {
+ result = recv; /* Duplicate found, return existing */
+ goto unlock_and_return;
+ }
+ }
+
+ rb_ary_push(table, block);
+ }
+
+unlock_and_return:
+ RB_GC_VM_UNLOCK(lev);
+ return result;
+}
+
+void
+rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ (void)objspace_ptr;
+ rb_wbcheck_object_info_t *info = wbcheck_get_object_info(obj);
+
+ GC_ASSERT(!OBJ_FROZEN(obj));
+
+ info->finalizers = 0;
+ FL_UNSET(obj, FL_FINALIZE);
+
+ RB_GC_VM_UNLOCK(lev);
+}
+
+void
+rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
+{
+ (void)objspace_ptr;
+
+ if (!FL_TEST(obj, FL_FINALIZE)) return;
+
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ rb_wbcheck_object_info_t *src_info = wbcheck_get_object_info(obj);
+ rb_wbcheck_object_info_t *dest_info = wbcheck_get_object_info(dest);
+
+ if (src_info->finalizers) {
+ VALUE table = rb_ary_dup(src_info->finalizers);
+ RARRAY_ASET(table, 0, rb_obj_id(dest));
+ rb_obj_hide(table);
+ dest_info->finalizers = table;
+ FL_SET(dest, FL_FINALIZE);
+ }
+
+ RB_GC_VM_UNLOCK(lev);
+}
+
+static VALUE
+wbcheck_get_final(long i, void *data)
+{
+ VALUE table = (VALUE)data;
+
+ return RARRAY_AREF(table, i + 1);
+}
+
+static void
+make_final_job(rb_wbcheck_objspace_t *objspace, VALUE obj, VALUE finalizer_array)
+{
+ RUBY_ASSERT(RB_FL_TEST(obj, FL_FINALIZE));
+ RUBY_ASSERT(RB_BUILTIN_TYPE(finalizer_array) == T_ARRAY);
+
+ RB_FL_UNSET(obj, FL_FINALIZE);
+
+ struct wbcheck_final_job *job = malloc(sizeof(struct wbcheck_final_job));
+ job->kind = WBCHECK_FINAL_JOB_FINALIZE;
+ job->as.finalize.finalizer_array = finalizer_array;
+
+ finalizer_jobs_push(objspace, job);
+}
+
+static void
+gc_run_finalizers(void *data)
+{
+ rb_wbcheck_objspace_t *objspace = data;
+
+ rb_gc_set_pending_interrupt();
+
+ struct wbcheck_final_job *job;
+ while ((job = finalizer_jobs_pop(objspace)) != NULL) {
+ switch (job->kind) {
+ case WBCHECK_FINAL_JOB_DFREE:
+ job->as.dfree.func(job->as.dfree.data);
+ break;
+ case WBCHECK_FINAL_JOB_FINALIZE: {
+ VALUE finalizer_array = job->as.finalize.finalizer_array;
+
+ rb_gc_run_obj_finalizer(
+ RARRAY_AREF(finalizer_array, 0),
+ RARRAY_LEN(finalizer_array) - 1,
+ wbcheck_get_final,
+ (void *)finalizer_array
+ );
+
+ RB_GC_GUARD(finalizer_array);
+ break;
+ }
+ }
+
+ free(job);
+ }
+
+ rb_gc_unset_pending_interrupt();
+}
+
+static void
+wbcheck_run_finalizers_for_object(VALUE obj, rb_wbcheck_object_info_t *info)
+{
+ if (info->finalizers) {
+ VALUE table = info->finalizers;
+ long count = RARRAY_LEN(table) - 1;
+ rb_gc_run_obj_finalizer(RARRAY_AREF(table, 0), count, wbcheck_get_final, (void *)table);
+ FL_UNSET(obj, FL_FINALIZE);
+ }
+ info->finalizers = 0;
+}
+
+static int
+wbcheck_shutdown_call_finalizer_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ wbcheck_run_finalizers_for_object(obj, info);
+ return ST_CONTINUE; /* Keep iterating through all objects */
+}
+
+static int
+wbcheck_verify_all_references_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ void *objspace_ptr = data;
+ wbcheck_verify_object_references(objspace_ptr, obj);
+ return ST_CONTINUE;
+}
+
+static int
+wbcheck_update_all_snapshots_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ void *objspace_ptr = data;
+
+ // For wb_protected objects, do full verification if they have a snapshot
+ if (info->wb_protected && info->state != WBCHECK_STATE_CLEAR) {
+ wbcheck_verify_object_references(objspace_ptr, obj);
+ } else {
+ // For CLEAR objects (wb_protected or not) and non-wb_protected objects, just take a new snapshot
+ wbcheck_object_list_t *current_refs = wbcheck_collect_references_from_object(obj, info);
+ wbcheck_object_list_free(info->gc_mark_snapshot);
+ info->gc_mark_snapshot = current_refs;
+ info->state = WBCHECK_STATE_MARKED;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+wbcheck_shutdown_finalizer_callback(VALUE obj, rb_wbcheck_object_info_t *info, void *data)
+{
+ void *objspace_ptr = data;
+
+ if (rb_gc_shutdown_call_finalizer_p(obj)) {
+ WBCHECK_DEBUG("wbcheck: finalizing object during shutdown: %p\n", (void *)obj);
+ rb_gc_obj_free_vm_weak_references(obj);
+ if (rb_gc_obj_free(objspace_ptr, obj)) {
+ RBASIC(obj)->flags = 0;
+ }
+ }
+
+ return ST_CONTINUE;
+}
+
+
+void
+rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = objspace_ptr;
+
+ // Call all finalizers for all objects using our shared iteration helper
+ wbcheck_foreach_object(objspace, wbcheck_shutdown_call_finalizer_callback, NULL);
+
+ // After all finalizers have been called, verify all object references
+ unsigned int verify_lev = RB_GC_VM_LOCK();
+ WBCHECK_DEBUG("wbcheck: verifying references for all objects after finalizers\n");
+ wbcheck_foreach_object(objspace, wbcheck_verify_all_references_callback, objspace_ptr);
+ WBCHECK_DEBUG("wbcheck: finished verifying all object references\n");
+ RB_GC_VM_UNLOCK(verify_lev);
+
+ // Print summary and exit with error code if violations were found
+ if (objspace->missed_write_barrier_parents > 0 || objspace->missed_write_barrier_children > 0) {
+ fprintf(stderr, "WBCHECK SUMMARY: Found %zu objects with missed write barriers (%zu total violations)\n",
+ objspace->missed_write_barrier_parents, objspace->missed_write_barrier_children);
+
+
+ exit(1); // Exit with error code to indicate violations were found
+ } else {
+ WBCHECK_DEBUG("wbcheck: no write barrier violations detected\n");
+ }
+
+ // Call rb_gc_obj_free on objects that need shutdown finalization (File, Data with dfree, etc.)
+ unsigned int lev = RB_GC_VM_LOCK();
+ WBCHECK_DEBUG("wbcheck: calling rb_gc_obj_free on objects that need shutdown finalization\n");
+ wbcheck_foreach_object(objspace, wbcheck_shutdown_finalizer_callback, objspace_ptr);
+ WBCHECK_DEBUG("wbcheck: finished calling rb_gc_obj_free\n");
+
+ // Run any pending finalizer jobs (dfree functions)
+ WBCHECK_DEBUG("wbcheck: running pending finalizer jobs\n");
+ gc_run_finalizers(objspace);
+ WBCHECK_DEBUG("wbcheck: finished running finalizer jobs\n");
+ RB_GC_VM_UNLOCK(lev);
+}
+
+// Forking
+void
+rb_gc_impl_before_fork(void *objspace_ptr)
+{
+ // Stub implementation
+}
+
+void
+rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
+{
+ // Stub implementation
+}
+
+// Statistics
+void
+rb_gc_impl_set_measure_total_time(void *objspace_ptr, VALUE flag)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ objspace->measure_total_time = RTEST(flag);
+}
+
+bool
+rb_gc_impl_get_measure_total_time(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->measure_total_time;
+}
+
+unsigned long long
+rb_gc_impl_get_total_time(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ return objspace->measure_total_time ? objspace->simulated_gc_count : 0;
+}
+
+size_t
+rb_gc_impl_gc_count(void *objspace_ptr)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ if (objspace) {
+ return objspace->simulated_gc_count;
+ }
+ return 0;
+}
+
+VALUE
+rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE key)
+{
+ // Stub implementation
+ return Qnil;
+}
+
+VALUE
+rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
+{
+ rb_wbcheck_objspace_t *objspace = (rb_wbcheck_objspace_t *)objspace_ptr;
+ GC_ASSERT(objspace);
+
+ VALUE hash = Qnil, key = Qnil;
+
+ if (RB_TYPE_P(hash_or_sym, T_HASH)) {
+ hash = hash_or_sym;
+ }
+ else if (SYMBOL_P(hash_or_sym)) {
+ key = hash_or_sym;
+ }
+ else {
+ rb_bug("non-hash or symbol given");
+ }
+
+#define SET(name, attr) \
+ if (key == ID2SYM(rb_intern(#name))) \
+ return SIZET2NUM(attr); \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, ID2SYM(rb_intern(#name)), SIZET2NUM(attr));
+
+ /* Pretend each GC takes 1ms; :time is reported in milliseconds. */
+ SET(count, objspace->simulated_gc_count);
+ SET(time, objspace->measure_total_time ? objspace->simulated_gc_count : 0);
+ SET(tracked_objects, st_table_size(objspace->object_table));
+#undef SET
+
+ if (!NIL_P(key)) {
+ rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
+ }
+
+ rb_hash_aset(hash, ID2SYM(rb_intern("gc_implementation")), rb_str_new_cstr("wbcheck"));
+
+ return hash;
+}
+
+VALUE
+rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
+{
+ if (FIXNUM_P(heap_name) && SYMBOL_P(hash_or_sym)) {
+ int heap_idx = FIX2INT(heap_name);
+ if (heap_idx < 0 || heap_idx >= HEAP_COUNT) {
+ rb_raise(rb_eArgError, "size pool index out of range");
+ }
+
+ if (hash_or_sym == ID2SYM(rb_intern("slot_size"))) {
+ return SIZET2NUM(heap_sizes[heap_idx]);
+ }
+
+ return Qundef;
+ }
+
+ if (RB_TYPE_P(hash_or_sym, T_HASH)) {
+ return hash_or_sym;
+ }
+
+ return Qundef;
+}
+
+const char *
+rb_gc_impl_active_gc_name(void)
+{
+ // Stub implementation
+ return "wbcheck";
+}
+
+// Miscellaneous
+#define WBCHECK_OBJECT_METADATA_ENTRY_COUNT 2
+static struct rb_gc_object_metadata_entry object_metadata_entries[WBCHECK_OBJECT_METADATA_ENTRY_COUNT + 1];
+
+struct rb_gc_object_metadata_entry *
+rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
+{
+ static ID ID_object_id, ID_shareable;
+
+ if (!ID_object_id) {
+ ID_object_id = rb_intern("object_id");
+ ID_shareable = rb_intern("shareable");
+ }
+
+ size_t n = 0;
+
+#define SET_ENTRY(na, v) do { \
+ GC_ASSERT(n < WBCHECK_OBJECT_METADATA_ENTRY_COUNT); \
+ object_metadata_entries[n].name = ID_##na; \
+ object_metadata_entries[n].val = v; \
+ n++; \
+} while (0)
+
+ if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));
+ if (FL_TEST(obj, FL_SHAREABLE)) SET_ENTRY(shareable, Qtrue);
+#undef SET_ENTRY
+
+ object_metadata_entries[n].name = 0;
+ object_metadata_entries[n].val = 0;
+
+ return object_metadata_entries;
+}
+
+bool
+rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr)
+{
+ GC_ASSERT(wbcheck_global_objspace);
+
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ // Check if this pointer exists in our object tracking table
+ st_data_t value;
+ bool result = st_lookup(wbcheck_global_objspace->object_table, (st_data_t)ptr, &value);
+
+ RB_GC_VM_UNLOCK(lev);
+ return result;
+}
+
+bool
+rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE obj)
+{
+ unsigned int lev = RB_GC_VM_LOCK();
+
+ // Check if this pointer exists in our object tracking table
+ st_data_t value;
+ bool result = st_lookup(wbcheck_global_objspace->object_table, (st_data_t)obj, &value);
+
+ RB_GC_VM_UNLOCK(lev);
+ return !result;
+}
+
+void
+rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event)
+{
+ // Stub implementation
+}
+
+void
+rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj)
+{
+ rb_wbcheck_object_info_t *src_info = wbcheck_get_object_info(obj);
+
+ if (!src_info->wb_protected) {
+ rb_gc_impl_writebarrier_unprotect(objspace_ptr, dest);
+ }
+ rb_gc_impl_copy_finalizer(objspace_ptr, dest, obj);
+}
+
diff --git a/gem_prelude.rb b/gem_prelude.rb
index bcd2560fab..1b78d80c72 100644
--- a/gem_prelude.rb
+++ b/gem_prelude.rb
@@ -25,4 +25,3 @@ begin
rescue LoadError
warn "`syntax_suggest' was not loaded."
end if defined?(SyntaxSuggest)
-
diff --git a/gems/bundled_gems b/gems/bundled_gems
index f70bdd6c5b..8e244af598 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -6,42 +6,42 @@
# - revision: revision in repository-url to test
# if `revision` is not given, "v"+`version` or `version` will be used.
-minitest 5.25.5 https://github.com/minitest/minitest
-power_assert 2.0.5 https://github.com/ruby/power_assert
-rake 13.2.1 https://github.com/ruby/rake
-test-unit 3.6.7 https://github.com/test-unit/test-unit
-rexml 3.4.1 https://github.com/ruby/rexml
-rss 0.3.1 https://github.com/ruby/rss
-net-ftp 0.3.8 https://github.com/ruby/net-ftp
-net-imap 0.5.6 https://github.com/ruby/net-imap
-net-pop 0.1.2 https://github.com/ruby/net-pop
+minitest 6.0.6 https://github.com/minitest/minitest
+power_assert 3.0.1 https://github.com/ruby/power_assert
+rake 13.4.2 https://github.com/ruby/rake
+test-unit 3.7.7 https://github.com/test-unit/test-unit
+rexml 3.4.4 https://github.com/ruby/rexml
+rss 0.3.2 https://github.com/ruby/rss
+net-imap 0.6.4 https://github.com/ruby/net-imap
net-smtp 0.5.1 https://github.com/ruby/net-smtp
-matrix 0.4.2 https://github.com/ruby/matrix
-prime 0.1.3 https://github.com/ruby/prime
-rbs 3.9.2 https://github.com/ruby/rbs
-typeprof 0.30.1 https://github.com/ruby/typeprof
-debug 1.10.0 https://github.com/ruby/debug
+matrix 0.4.3 https://github.com/ruby/matrix
+prime 0.1.4 https://github.com/ruby/prime
+rbs 4.0.2 https://github.com/ruby/rbs 1582ce76429810b057a2816e5000cf5de4b1363d
+typeprof 0.32.0 https://github.com/ruby/typeprof
+debug 1.11.1 https://github.com/ruby/debug 9dc2024a5a05116b3d38afbc5579d9503d8913f3
racc 1.8.1 https://github.com/ruby/racc
mutex_m 0.3.0 https://github.com/ruby/mutex_m
getoptlong 0.2.1 https://github.com/ruby/getoptlong
-base64 0.2.0 https://github.com/ruby/base64
-bigdecimal 3.1.9 https://github.com/ruby/bigdecimal
+base64 0.3.0 https://github.com/ruby/base64
+bigdecimal 4.1.2 https://github.com/ruby/bigdecimal
observer 0.1.2 https://github.com/ruby/observer
abbrev 0.1.2 https://github.com/ruby/abbrev
-resolv-replace 0.1.1 https://github.com/ruby/resolv-replace
+resolv-replace 0.2.0 https://github.com/ruby/resolv-replace
rinda 0.2.0 https://github.com/ruby/rinda
-drb 2.2.1 https://github.com/ruby/drb
+drb 2.2.3 https://github.com/ruby/drb
nkf 0.2.0 https://github.com/ruby/nkf
-syslog 0.3.0 https://github.com/ruby/syslog
-csv 3.3.3 https://github.com/ruby/csv e0874e47e2730dacccdb0c534a2cdc073d3bdaea
-repl_type_completor 0.1.10 https://github.com/ruby/repl_type_completor
-ostruct 0.6.1 https://github.com/ruby/ostruct
-pstore 0.2.0 https://github.com/ruby/pstore
-benchmark 0.4.0 https://github.com/ruby/benchmark
+syslog 0.4.0 https://github.com/ruby/syslog
+csv 3.3.5 https://github.com/ruby/csv
+repl_type_completor 0.1.15 https://github.com/ruby/repl_type_completor
+ostruct 0.6.3 https://github.com/ruby/ostruct
+pstore 0.2.1 https://github.com/ruby/pstore
+benchmark 0.5.0 https://github.com/ruby/benchmark
logger 1.7.0 https://github.com/ruby/logger
-rdoc 6.13.1 https://github.com/ruby/rdoc
-win32ole 1.9.1 https://github.com/ruby/win32ole
-irb 1.15.1 https://github.com/ruby/irb 6bb53630c3398b2042fb99d5232c68399491d338
-reline 0.6.0 https://github.com/ruby/reline defcd36c0b6e6648333d4b9ab5923eb4e543615e
+rdoc 7.2.0 https://github.com/ruby/rdoc 1f93543615928b6d45357432f16ec6006e2d8b1e
+win32ole 1.9.3 https://github.com/ruby/win32ole
+irb 1.18.0 https://github.com/ruby/irb
+reline 0.6.3 https://github.com/ruby/reline
readline 0.0.4 https://github.com/ruby/readline
-fiddle 1.1.6 https://github.com/ruby/fiddle
+fiddle 1.1.8 https://github.com/ruby/fiddle
+tsort 0.2.0 https://github.com/ruby/tsort
+win32-registry 0.1.2 https://github.com/ruby/win32-registry
diff --git a/hash.c b/hash.c
index 0b211df3b3..9ba8c3d4fe 100644
--- a/hash.c
+++ b/hash.c
@@ -71,10 +71,6 @@
#define HASH_DEBUG 0
#endif
-#if HASH_DEBUG
-#include "internal/gc.h"
-#endif
-
#define SET_DEFAULT(hash, ifnone) ( \
FL_UNSET_RAW(hash, RHASH_PROC_DEFAULT), \
RHASH_SET_IFNONE(hash, ifnone))
@@ -184,7 +180,7 @@ any_hash(VALUE a, st_index_t (*other_func)(VALUE))
hnum = rb_hash_start(hnum);
}
else {
- hnum = RSYMBOL(a)->hashval;
+ hnum = RSHIFT(RSYMBOL(a)->hashval, 1);
}
break;
case T_FIXNUM:
@@ -325,40 +321,35 @@ objid_hash(VALUE obj)
#endif
}
-/**
+/*
* call-seq:
- * obj.hash -> integer
- *
- * Generates an Integer hash value for this object. This function must have the
- * property that <code>a.eql?(b)</code> implies <code>a.hash == b.hash</code>.
- *
- * The hash value is used along with #eql? by the Hash class to determine if
- * two objects reference the same hash key. Any hash value that exceeds the
- * capacity of an Integer will be truncated before being used.
+ * hash -> integer
*
- * The hash value for an object may not be identical across invocations or
- * implementations of Ruby. If you need a stable identifier across Ruby
- * invocations and implementations you will need to generate one with a custom
- * method.
+ * Returns the integer hash value for +self+;
+ * has the property that if <tt>foo.eql?(bar)</tt>
+ * then <tt>foo.hash == bar.hash</tt>.
*
- * Certain core classes such as Integer use built-in hash calculations and
- * do not call the #hash method when used as a hash key.
+ * \Class Hash uses both #hash and #eql? to determine whether two objects
+ * used as hash keys are to be treated as the same key.
+ * A hash value that exceeds the capacity of an Integer is truncated before being used.
*
- * When implementing your own #hash based on multiple values, the best
- * practice is to combine the class and any values using the hash code of an
- * array:
+ * Many core classes override method Object#hash;
+ * other core classes (e.g., Integer) calculate the hash internally,
+ * and do not call the #hash method when used as a hash key.
*
- * For example:
+ * When implementing #hash for a user-defined class,
+ * best practice is to use Array#hash with the class name and the values
+ * that are important in the instance;
+ * this takes advantage of that method's logic for safely and efficiently
+ * generating a hash value:
*
* def hash
* [self.class, a, b, c].hash
* end
*
- * The reason for this is that the Array#hash method already has logic for
- * safely and efficiently combining multiple hash values.
- *--
- * \private
- *++
+ * The hash value may differ among invocations or implementations of Ruby.
+ * If you need stable hash-like identifiers across Ruby invocations and implementations,
+ * use a custom method to generate them.
*/
VALUE
rb_obj_hash(VALUE obj)
@@ -480,58 +471,11 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha
#define RHASH_AR_TABLE_SIZE(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \
RHASH_AR_TABLE_SIZE_RAW(h))
-#define RHASH_AR_TABLE_BOUND_RAW(h) \
- ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
- (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
-
-#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__)
-void
-rb_hash_dump(VALUE hash)
-{
- rb_obj_info_dump(hash);
-
- if (RHASH_AR_TABLE_P(hash)) {
- unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
-
- fprintf(stderr, " size:%u bound:%u\n",
- RHASH_AR_TABLE_SIZE(hash), bound);
-
- for (i=0; i<bound; i++) {
- st_data_t k, v;
-
- if (!ar_cleared_entry(hash, i)) {
- char b1[0x100], b2[0x100];
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- k = pair->key;
- v = pair->val;
- fprintf(stderr, " %d key:%s val:%s hint:%02x\n", i,
- rb_raw_obj_info(b1, 0x100, k),
- rb_raw_obj_info(b2, 0x100, v),
- ar_hint(hash, i));
- }
- else {
- fprintf(stderr, " %d empty\n", i);
- }
- }
- }
-}
-
static VALUE
hash_verify_(VALUE hash, const char *file, int line)
{
@@ -584,7 +528,7 @@ hash_st_table_init(VALUE hash, const struct st_hash_type *type, st_index_t size)
RHASH_SET_ST_FLAG(hash);
}
-void
+static void
rb_hash_st_table_set(VALUE hash, st_table *st)
{
HASH_ASSERT(st != NULL);
@@ -644,6 +588,7 @@ RHASH_AR_TABLE_SIZE_DEC(VALUE h)
static inline void
RHASH_AR_TABLE_CLEAR(VALUE h)
{
+ RUBY_ASSERT(rb_gc_obj_slot_size(h) >= sizeof(struct RHash) + sizeof(ar_table));
RBASIC(h)->flags &= ~RHASH_AR_TABLE_SIZE_MASK;
RBASIC(h)->flags &= ~RHASH_AR_TABLE_BOUND_MASK;
@@ -759,6 +704,8 @@ ar_force_convert_table(VALUE hash, const char *file, int line)
st_hash_t hashes[RHASH_AR_TABLE_MAX_SIZE];
unsigned int bound, size;
+ RUBY_ASSERT(rb_gc_obj_slot_size(hash) >= sizeof(struct RHash) + sizeof(ar_table));
+
// prepare hash values
do {
st_data_t keys[RHASH_AR_TABLE_MAX_SIZE];
@@ -783,7 +730,7 @@ ar_force_convert_table(VALUE hash, const char *file, int line)
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);
+ rb_hash_st_table_set(hash, new_tab);
return RHASH_ST_TABLE(hash);
}
}
@@ -880,10 +827,11 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
return 0;
case ST_REPLACE:
if (replace) {
- retval = (*replace)(&key, &val, arg, TRUE);
+ (*replace)(&key, &val, arg, TRUE);
+
+ // Pair should not have moved
+ HASH_ASSERT(pair == RHASH_AR_TABLE_REF(hash, i));
- // TODO: pair should be same as pair before.
- pair = RHASH_AR_TABLE_REF(hash, i);
pair->key = (VALUE)key;
pair->val = (VALUE)val;
}
@@ -951,7 +899,7 @@ ar_foreach_check(VALUE hash, st_foreach_check_callback_func *func, st_data_t arg
if (pair->key == never) break;
ret = ar_find_entry_hint(hash, hint, key);
if (ret == RHASH_AR_TABLE_MAX_BOUND) {
- retval = (*func)(0, 0, arg, 1);
+ (*func)(0, 0, arg, 1);
return 2;
}
}
@@ -1181,12 +1129,15 @@ ar_values(VALUE hash, st_data_t *values, st_index_t size)
static ar_table*
ar_copy(VALUE hash1, VALUE hash2)
{
+ RUBY_ASSERT(rb_gc_obj_slot_size(hash1) >= sizeof(struct RHash) + sizeof(ar_table));
ar_table *old_tab = RHASH_AR_TABLE(hash2);
ar_table *new_tab = RHASH_AR_TABLE(hash1);
- *new_tab = *old_tab;
+ unsigned int bound = RHASH_AR_TABLE_BOUND(hash2);
+ new_tab->ar_hint.word = old_tab->ar_hint.word;
+ MEMCPY(&new_tab->pairs, &old_tab->pairs, ar_table_pair, bound);
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_BOUND_SET(hash1, bound);
RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
rb_gc_writebarrier_remember(hash1);
@@ -1212,17 +1163,13 @@ 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);
+ rb_st_free_embedded_table(RHASH_ST_TABLE(hash));
}
static void
hash_st_free_and_clear_table(VALUE hash)
{
hash_st_free(hash);
-
RHASH_ST_CLEAR(hash);
}
@@ -1300,7 +1247,6 @@ hash_ar_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
if (error) return ST_STOP;
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
- /* TODO: rehash check? rb_raise(rb_eRuntimeError, "rehash occurred during iteration"); */
return hash_iter_status_check(status);
}
@@ -1312,13 +1258,8 @@ hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
if (error) return ST_STOP;
- st_table *tbl = RHASH_ST_TABLE(arg->hash);
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
- if (RHASH_ST_TABLE(arg->hash) != tbl) {
- rb_raise(rb_eRuntimeError, "rehash occurred during iteration");
- }
-
return hash_iter_status_check(status);
}
@@ -1404,6 +1345,7 @@ hash_foreach_ensure(VALUE hash)
return 0;
}
+/* This does not manage iteration level */
int
rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg)
{
@@ -1415,6 +1357,7 @@ rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg
}
}
+/* This does not manage iteration level */
int
rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
{
@@ -1478,14 +1421,9 @@ compact_after_delete(VALUE hash)
static VALUE
hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st)
{
- 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);
-
- RHASH_SET_IFNONE((VALUE)hash, ifnone);
-
- return (VALUE)hash;
+ VALUE hash = rb_newobj_of(klass, T_HASH | flags, size);
+ return rb_hash_set_ifnone(hash, ifnone);
}
static VALUE
@@ -1537,9 +1475,30 @@ rb_hash_new_capa(long capa)
return rb_hash_new_with_size((st_index_t)capa);
}
+VALUE
+rb_hash_alloc_fixed_size(VALUE klass, st_index_t size)
+{
+ VALUE ret;
+ if (size > RHASH_AR_TABLE_MAX_SIZE) {
+ ret = hash_alloc_flags(klass, 0, Qnil, true);
+ hash_st_table_init(ret, &objhash, size);
+ }
+ else {
+ size_t slot_size = sizeof(struct RHash) + offsetof(ar_table, pairs) + size * sizeof(ar_table_pair);
+ ret = rb_newobj_of(klass, T_HASH, slot_size);
+ }
+
+ RHASH_SET_IFNONE(ret, Qnil);
+ return ret;
+}
+
static VALUE
hash_copy(VALUE ret, VALUE hash)
{
+ if (rb_hash_compare_by_id_p(hash)) {
+ rb_gc_register_pinning_obj(ret);
+ }
+
if (RHASH_AR_TABLE_P(hash)) {
if (RHASH_AR_TABLE_P(ret)) {
ar_copy(ret, hash);
@@ -1595,10 +1554,10 @@ VALUE
rb_hash_dup(VALUE hash)
{
const VALUE flags = RBASIC(hash)->flags;
- VALUE ret = hash_dup(hash, rb_obj_class(hash),
- flags & (FL_EXIVAR|RHASH_PROC_DEFAULT));
- if (flags & FL_EXIVAR)
- rb_copy_generic_ivar(ret, hash);
+ VALUE ret = hash_dup(hash, rb_obj_class(hash), flags & RHASH_PROC_DEFAULT);
+
+ rb_copy_generic_ivar(ret, hash);
+
return ret;
}
@@ -1721,14 +1680,14 @@ tbl_update(VALUE hash, VALUE key, tbl_update_func func, st_data_t optional_arg)
.func = func,
.hash = hash,
.key = key,
- .value = (VALUE)optional_arg,
+ .value = 0
};
int ret = rb_hash_stlike_update(hash, key, tbl_update_modify, (st_data_t)&arg);
/* write barrier */
RB_OBJ_WRITTEN(hash, Qundef, arg.key);
- RB_OBJ_WRITTEN(hash, Qundef, arg.value);
+ if (arg.value) RB_OBJ_WRITTEN(hash, Qundef, arg.value);
return ret;
}
@@ -1981,6 +1940,9 @@ rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
else {
st_insert(RHASH_ST_TABLE(arg), (st_data_t)key, (st_data_t)value);
}
+
+ RB_OBJ_WRITTEN(arg, Qundef, key);
+ RB_OBJ_WRITTEN(arg, Qundef, value);
return ST_CONTINUE;
}
@@ -2024,7 +1986,7 @@ rb_hash_rehash(VALUE hash)
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
hash_st_free(hash);
- RHASH_ST_TABLE_SET(hash, tbl);
+ rb_hash_st_table_set(hash, tbl);
RHASH_ST_CLEAR(tmp);
}
hash_verify(hash);
@@ -2253,7 +2215,7 @@ rb_hash_default(int argc, VALUE *argv, VALUE hash)
* See {Hash Default}[rdoc-ref:Hash@Hash+Default].
*/
-static VALUE
+VALUE
rb_hash_set_default(VALUE hash, VALUE ifnone)
{
rb_hash_modify_check(hash);
@@ -2683,9 +2645,9 @@ rb_hash_slice(int argc, VALUE *argv, VALUE hash)
* Returns a copy of +self+ that excludes entries for the given +keys+;
* any +keys+ that are not found are ignored:
*
- * h = {foo:0, bar: 1, baz: 2} # => {:foo=>0, :bar=>1, :baz=>2}
- * h.except(:baz, :foo) # => {:bar=>1}
- * h.except(:bar, :nosuch) # => {:foo=>0, :baz=>2}
+ * h = {foo:0, bar: 1, baz: 2} # => {foo: 0, bar: 1, baz: 2}
+ * h.except(:baz, :foo) # => {bar: 1}
+ * h.except(:bar, :nosuch) # => {foo: 0, baz: 2}
*
* Related: see {Methods for Deleting}[rdoc-ref:Hash@Methods+for+Deleting].
*/
@@ -2918,7 +2880,7 @@ hash_aset(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
VALUE
rb_hash_key_str(VALUE key)
{
- if (!RB_FL_ANY_RAW(key, FL_EXIVAR) && RBASIC_CLASS(key) == rb_cString) {
+ if (!rb_obj_gen_fields_p(key) && RBASIC_CLASS(key) == rb_cString) {
return rb_fstring(key);
}
else {
@@ -2962,7 +2924,7 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
* h = {foo: 0, bar: 1}
* h[:baz] = 2 # => 2
* h[:baz] # => 2
- * h # => {:foo=>0, :bar=>1, :baz=>2}
+ * h # => {foo: 0, bar: 1, baz: 2}
*
* Related: #[]; see also {Methods for Assigning}[rdoc-ref:Hash@Methods+for+Assigning].
*/
@@ -2993,6 +2955,14 @@ rb_hash_aset(VALUE hash, VALUE key, VALUE val)
* h = {foo: 0, bar: 1, baz: 2}
* h.replace({bat: 3, bam: 4}) # => {bat: 3, bam: 4}
*
+ * Also replaces the default value or proc of +self+ with the default value
+ * or proc of +other_hash+.
+ *
+ * h = {}
+ * other = Hash.new(:ok)
+ * h.replace(other)
+ * h.default # => :ok
+ *
* Related: see {Methods for Assigning}[rdoc-ref:Hash@Methods+for+Assigning].
*/
@@ -3486,6 +3456,20 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
return ST_CONTINUE;
}
+static VALUE
+transform_values_call(VALUE hash)
+{
+ rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
+ return hash;
+}
+
+static void
+transform_values(VALUE hash)
+{
+ hash_iter_lev_inc(hash);
+ rb_ensure(transform_values_call, hash, hash_foreach_ensure, hash);
+}
+
/*
* call-seq:
* transform_values {|value| ... } -> new_hash
@@ -3514,7 +3498,7 @@ rb_hash_transform_values(VALUE hash)
SET_DEFAULT(result, Qnil);
if (!RHASH_EMPTY_P(hash)) {
- rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result);
+ transform_values(result);
compact_after_delete(result);
}
@@ -3549,7 +3533,7 @@ rb_hash_transform_values_bang(VALUE hash)
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
- rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
+ transform_values(hash);
}
return hash;
@@ -3596,24 +3580,24 @@ symbol_key_needs_quote(VALUE str)
if (first == '@' || first == '$' || first == '!') return true;
if (!at_char_boundary(s, s + len - 1, RSTRING_END(str), rb_enc_get(str))) return false;
switch (s[len - 1]) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '`':
- case '%':
- case '^':
- case '&':
- case '|':
- case ']':
- case '<':
- case '=':
- case '>':
- case '~':
- case '@':
- return true;
- default:
- return false;
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '`':
+ case '%':
+ case '^':
+ case '&':
+ case '|':
+ case ']':
+ case '<':
+ case '=':
+ case '>':
+ case '~':
+ case '@':
+ return true;
+ default:
+ return false;
}
}
@@ -3855,7 +3839,6 @@ rb_hash_values(VALUE hash)
}
rb_ary_set_len(values, size);
}
-
else {
rb_hash_foreach(hash, values_i, values);
}
@@ -3997,17 +3980,13 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
/*
* call-seq:
- * self == object -> true or false
- *
- * Returns whether +self+ and +object+ are equal.
- *
- * Returns +true+ if all of the following are true:
+ * self == other -> true or false
*
- * - +object+ is a +Hash+ object (or can be converted to one).
- * - +self+ and +object+ have the same keys (regardless of order).
- * - For each key +key+, <tt>self[key] == object[key]</tt>.
+ * Returns whether all of the following are true:
*
- * Otherwise, returns +false+.
+ * - +other+ is a +Hash+ object (or can be converted to one).
+ * - +self+ and +other+ have the same keys (regardless of order).
+ * - For each key +key+, <tt>self[key] == other[key]</tt>.
*
* Examples:
*
@@ -4016,8 +3995,8 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
* h == {bar: 1, foo: 0} # => true # Equal entries (different order).
* h == 1 # => false # Object not a hash.
* h == {} # => false # Different number of entries.
- * h == {foo: 0, bar: 1} # => false # Different key.
- * h == {foo: 0, bar: 1} # => false # Different value.
+ * h == {foo: 0, bat: 1} # => false # Different key.
+ * h == {foo: 0, bar: 2} # => false # Different value.
*
* Related: see {Methods for Comparing}[rdoc-ref:Hash@Methods+for+Comparing].
*/
@@ -4139,30 +4118,70 @@ rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
return ST_CONTINUE;
}
+struct update_call_args {
+ VALUE hash, newvalue, *argv;
+ int argc;
+ bool block_given;
+ bool iterating;
+};
+
static int
rb_hash_update_block_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing)
{
- st_data_t newvalue = arg->arg;
+ VALUE k = (VALUE)*key, v = (VALUE)*value;
+ struct update_call_args *ua = (void *)arg->arg;
+ VALUE newvalue = ua->newvalue, hash = arg->hash;
if (existing) {
- newvalue = (st_data_t)rb_yield_values(3, (VALUE)*key, (VALUE)*value, (VALUE)newvalue);
+ hash_iter_lev_inc(hash);
+ ua->iterating = true;
+ newvalue = rb_yield_values(3, k, v, newvalue);
+ hash_iter_lev_dec(hash);
+ ua->iterating = false;
}
- else if (RHASH_STRING_KEY_P(arg->hash, *key) && !RB_OBJ_FROZEN(*key)) {
- *key = rb_hash_key_str(*key);
+ else if (RHASH_STRING_KEY_P(hash, k) && !RB_OBJ_FROZEN(k)) {
+ *key = (st_data_t)rb_hash_key_str(k);
}
- *value = newvalue;
+ *value = (st_data_t)newvalue;
return ST_CONTINUE;
}
NOINSERT_UPDATE_CALLBACK(rb_hash_update_block_callback)
static int
-rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
+rb_hash_update_block_i(VALUE key, VALUE value, VALUE args)
{
- RHASH_UPDATE(hash, key, rb_hash_update_block_callback, value);
+ struct update_call_args *ua = (void *)args;
+ ua->newvalue = value;
+ RHASH_UPDATE(ua->hash, key, rb_hash_update_block_callback, args);
return ST_CONTINUE;
}
+static VALUE
+rb_hash_update_call(VALUE args)
+{
+ struct update_call_args *arg = (void *)args;
+
+ for (int i = 0; i < arg->argc; i++){
+ VALUE hash = to_hash(arg->argv[i]);
+ if (arg->block_given) {
+ rb_hash_foreach(hash, rb_hash_update_block_i, args);
+ }
+ else {
+ rb_hash_foreach(hash, rb_hash_update_i, arg->hash);
+ }
+ }
+ return arg->hash;
+}
+
+static VALUE
+rb_hash_update_ensure(VALUE args)
+{
+ struct update_call_args *ua = (void *)args;
+ if (ua->iterating) hash_iter_lev_dec(ua->hash);
+ return Qnil;
+}
+
/*
* call-seq:
* update(*other_hashes) -> self
@@ -4209,20 +4228,17 @@ rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
static VALUE
rb_hash_update(int argc, VALUE *argv, VALUE self)
{
- int i;
- bool block_given = rb_block_given_p();
+ struct update_call_args args = {
+ .hash = self,
+ .argv = argv,
+ .argc = argc,
+ .block_given = rb_block_given_p(),
+ .iterating = false,
+ };
+ VALUE arg = (VALUE)&args;
rb_hash_modify(self);
- for (i = 0; i < argc; i++){
- VALUE hash = to_hash(argv[i]);
- if (block_given) {
- rb_hash_foreach(hash, rb_hash_update_block_i, self);
- }
- else {
- rb_hash_foreach(hash, rb_hash_update_i, self);
- }
- }
- return self;
+ return rb_ensure(rb_hash_update_call, arg, rb_hash_update_ensure, arg);
}
struct update_func_arg {
@@ -4477,21 +4493,21 @@ flatten_i(VALUE key, VALUE val, VALUE ary)
* Examples; note that entry <tt>foo: {bar: 1, baz: 2}</tt> is never flattened.
*
* h = {foo: {bar: 1, baz: 2}, bat: [:bam, [:bap, [:bah]]]}
- * h.flatten(1) # => [:foo, {:bar=>1, :baz=>2}, :bat, [:bam, [:bap, [:bah]]]]
- * h.flatten(2) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, [:bap, [:bah]]]
- * h.flatten(3) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, [:bah]]
- * h.flatten(4) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
- * h.flatten(5) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
+ * h.flatten(1) # => [:foo, {bar: 1, baz: 2}, :bat, [:bam, [:bap, [:bah]]]]
+ * h.flatten(2) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, [:bap, [:bah]]]
+ * h.flatten(3) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, [:bah]]
+ * h.flatten(4) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, :bah]
+ * h.flatten(5) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, :bah]
*
* With negative integer +depth+,
* flattens all levels:
*
- * h.flatten(-1) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
+ * h.flatten(-1) # => [:foo, {bar: 1, baz: 2}, :bat, :bam, :bap, :bah]
*
* With +depth+ zero,
* returns the equivalent of #to_a:
*
- * h.flatten(0) # => [[:foo, {:bar=>1, :baz=>2}], [:bat, [:bam, [:bap, [:bah]]]]]
+ * h.flatten(0) # => [[:foo, {bar: 1, baz: 2}], [:bat, [:bam, [:bap, [:bah]]]]]
*
* Related: see {Methods for Converting}[rdoc-ref:Hash@Methods+for+Converting].
*/
@@ -4602,7 +4618,7 @@ rb_hash_compact_bang(VALUE hash)
* returns +self+:
*
* By default, two keys are considered to be the same key
- * if and only if they are _equal_ objects (per method #==):
+ * if and only if they are _equal_ objects (per method #eql?):
*
* h = {}
* h['x'] = 0
@@ -4653,10 +4669,12 @@ rb_hash_compare_by_id(VALUE 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);
+ rb_hash_st_table_set(hash, identtable);
RHASH_ST_CLEAR(tmp);
}
+ rb_gc_register_pinning_obj(hash);
+
return hash;
}
@@ -4686,6 +4704,7 @@ rb_ident_hash_new(void)
{
VALUE hash = rb_hash_new();
hash_st_table_init(hash, &identhash, 0);
+ rb_gc_register_pinning_obj(hash);
return hash;
}
@@ -4694,6 +4713,7 @@ rb_ident_hash_new_with_size(st_index_t size)
{
VALUE hash = rb_hash_new();
hash_st_table_init(hash, &identhash, size);
+ rb_gc_register_pinning_obj(hash);
return hash;
}
@@ -4835,7 +4855,7 @@ rb_hash_any_p(int argc, VALUE *argv, VALUE hash)
* h.dig(:hello) # => nil
* h.default_proc = -> (hash, _key) { hash }
* h.dig(:hello, :world)
- * # => {:foo=>{:bar=>[:a, :b, :c]}}
+ * # => {foo: {bar: [:a, :b, :c]}}
*
* Related: {Methods for Fetching}[rdoc-ref:Hash@Methods+for+Fetching].
*/
@@ -4872,10 +4892,9 @@ hash_le(VALUE hash1, VALUE hash2)
/*
* call-seq:
- * self <= other_hash -> true or false
+ * self <= other -> true or false
*
- * Returns +true+ if the entries of +self+ are a subset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a subset of the entries of +other+:
*
* h0 = {foo: 0, bar: 1}
* h1 = {foo: 0, bar: 1, baz: 2}
@@ -4883,7 +4902,7 @@ hash_le(VALUE hash1, VALUE hash2)
* h0 <= h1 # => true
* h1 <= h0 # => false
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4899,20 +4918,19 @@ rb_hash_le(VALUE hash, VALUE other)
/*
* call-seq:
- * self < other_hash -> true or false
+ * self < other -> true or false
*
- * Returns +true+ if the entries of +self+ are a proper subset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a proper subset of the entries of +other+:
*
* h = {foo: 0, bar: 1}
* h < {foo: 0, bar: 1, baz: 2} # => true # Proper subset.
* h < {baz: 2, bar: 1, foo: 0} # => true # Order may differ.
* h < h # => false # Not a proper subset.
* h < {bar: 1, foo: 0} # => false # Not a proper subset.
- * h < {foo: 0, bar: 1, baz: 2} # => false # Different key.
- * h < {foo: 0, bar: 1, baz: 2} # => false # Different value.
+ * h < {foo: 0, bat: 1, baz: 2} # => false # Different key.
+ * h < {foo: 0, bar: 3, baz: 2} # => false # Different value.
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4928,10 +4946,9 @@ rb_hash_lt(VALUE hash, VALUE other)
/*
* call-seq:
- * self >= other_hash -> true or false
+ * self >= other -> true or false
*
- * Returns +true+ if the entries of +self+ are a superset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a superset of the entries of +other+:
*
* h0 = {foo: 0, bar: 1, baz: 2}
* h1 = {foo: 0, bar: 1}
@@ -4939,7 +4956,7 @@ rb_hash_lt(VALUE hash, VALUE other)
* h0 >= h0 # => true
* h1 >= h0 # => false
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4955,20 +4972,19 @@ rb_hash_ge(VALUE hash, VALUE other)
/*
* call-seq:
- * self > other_hash -> true or false
+ * self > other -> true or false
*
- * Returns +true+ if the entries of +self+ are a proper superset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a proper superset of the entries of +other+:
*
* h = {foo: 0, bar: 1, baz: 2}
* h > {foo: 0, bar: 1} # => true # Proper superset.
* h > {bar: 1, foo: 0} # => true # Order may differ.
* h > h # => false # Not a proper superset.
* h > {baz: 2, bar: 1, foo: 0} # => false # Not a proper superset.
- * h > {foo: 0, bar: 1} # => false # Different key.
- * h > {foo: 0, bar: 1} # => false # Different value.
+ * h > {foo: 0, bat: 1} # => false # Different key.
+ * h > {foo: 0, bar: 3} # => false # Different value.
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -5001,6 +5017,8 @@ hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, hash))
* proc.call(:foo) # => 0
* proc.call(:bar) # => 1
* proc.call(:nosuch) # => nil
+ * h.default_proc = proc { |hash, key| "Missing key: #{key}" } # This affect the existing proc object
+ * proc.call(:nosuch) # => "Missing key: #{nosuch}"
*
* Related: see {Methods for Converting}[rdoc-ref:Hash@Methods+for+Converting].
*/
@@ -5020,10 +5038,8 @@ rb_hash_deconstruct_keys(VALUE hash, VALUE keys)
static int
add_new_i(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
{
- VALUE *args = (VALUE *)arg;
if (existing) return ST_STOP;
- RB_OBJ_WRITTEN(args[0], Qundef, (VALUE)*key);
- RB_OBJ_WRITE(args[0], (VALUE *)val, args[1]);
+ *val = arg;
return ST_CONTINUE;
}
@@ -5035,22 +5051,25 @@ int
rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val)
{
st_table *tbl;
- int ret = 0;
- VALUE args[2];
- args[0] = hash;
- args[1] = val;
+ int ret = -1;
if (RHASH_AR_TABLE_P(hash)) {
- ret = ar_update(hash, (st_data_t)key, add_new_i, (st_data_t)args);
- if (ret != -1) {
- return ret;
+ ret = ar_update(hash, (st_data_t)key, add_new_i, (st_data_t)val);
+ if (ret == -1) {
+ ar_force_convert_table(hash, __FILE__, __LINE__);
}
- ar_force_convert_table(hash, __FILE__, __LINE__);
}
- tbl = RHASH_TBL_RAW(hash);
- return st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)args);
-
+ if (ret == -1) {
+ tbl = RHASH_TBL_RAW(hash);
+ ret = st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)val);
+ }
+ if (!ret) {
+ // Newly inserted
+ RB_OBJ_WRITTEN(hash, Qundef, key);
+ RB_OBJ_WRITTEN(hash, Qundef, val);
+ }
+ return ret;
}
static st_data_t
@@ -5090,6 +5109,14 @@ rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
}
}
+VALUE
+rb_hash_new_with_bulk_insert(long argc, const VALUE *argv)
+{
+ VALUE val = rb_hash_new_with_size(argc / 2);
+ rb_hash_bulk_insert(argc, argv, val);
+ return val;
+}
+
static char **origenviron;
#ifdef _WIN32
#define GET_ENVIRON(e) ((e) = rb_w32_get_environ())
@@ -5117,8 +5144,7 @@ extern char **environ;
#define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0)
#endif
-#define ENV_LOCK() RB_VM_LOCK_ENTER()
-#define ENV_UNLOCK() RB_VM_LOCK_LEAVE()
+#define ENV_LOCKING() RB_VM_LOCKING()
static inline rb_encoding *
env_encoding(void)
@@ -5140,28 +5166,27 @@ env_enc_str_new(const char *ptr, long len, rb_encoding *enc)
}
static VALUE
-env_str_new(const char *ptr, long len)
+env_str_new(const char *ptr, long len, rb_encoding *enc)
{
- return env_enc_str_new(ptr, len, env_encoding());
+ return env_enc_str_new(ptr, len, enc);
}
static VALUE
-env_str_new2(const char *ptr)
+env_str_new2(const char *ptr, rb_encoding *enc)
{
if (!ptr) return Qnil;
- return env_str_new(ptr, strlen(ptr));
+ return env_str_new(ptr, strlen(ptr), enc);
}
static VALUE
getenv_with_lock(const char *name)
{
VALUE ret;
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
const char *val = getenv(name);
- ret = env_str_new2(val);
+ ret = env_str_new2(val, enc);
}
- ENV_UNLOCK();
return ret;
}
@@ -5170,11 +5195,9 @@ has_env_with_lock(const char *name)
{
const char *val;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
val = getenv(name);
}
- ENV_UNLOCK();
return val ? true : false;
}
@@ -5324,7 +5347,7 @@ static VALUE
env_fetch(int argc, VALUE *argv, VALUE _)
{
VALUE key;
- long block_given;
+ int block_given;
const char *nam;
VALUE env;
@@ -5347,6 +5370,42 @@ env_fetch(int argc, VALUE *argv, VALUE _)
return env;
}
+/*
+ * call-seq:
+ * ENV.fetch_values(*names) -> array of values
+ * ENV.fetch_values(*names) {|name| ... } -> array of values
+ *
+ * Returns an Array containing the environment variable values associated with
+ * the given names:
+ * ENV.replace('foo' => '0', 'bar' => '1', 'baz' => '2')
+ * ENV.fetch_values('foo', 'baz') # => ["0", "2"]
+ *
+ * Otherwise if a block is given yields +name+ to
+ * the block and returns the block's return value:
+ * ENV.fetch_values('foo', 'bam') {|key| key.to_s} # => ["0", "bam"]
+ *
+ * Raises KeyError if +name+ is valid, but not found and block is not given:
+ * ENV.fetch_values('foo', 'bam') # Raises KeyError (key not found: "bam")
+ *
+ * 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].
+ */
+
+static VALUE
+env_fetch_values(int argc, VALUE *argv, VALUE ehash)
+{
+ VALUE result = rb_ary_new2(argc);
+ long i;
+
+ for (i=0; i<argc; i++) {
+ rb_ary_push(result, env_fetch(1, &argv[i], ehash));
+ }
+
+ return result;
+}
+
#if defined(_WIN32) || (defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
#elif defined __sun
static int
@@ -5424,13 +5483,11 @@ ruby_setenv(const char *name, const char *value)
*wvalue = L'\0';
}
- ENV_LOCK();
- {
+ ENV_LOCKING() {
/* Use _wputenv_s() instead of SetEnvironmentVariableW() to make sure
* special variables like "TZ" are interpret by libc. */
failed = _wputenv_s(wname, wvalue);
}
- ENV_UNLOCK();
ALLOCV_END(buf);
/* even if putenv() failed, clean up and try to delete the
@@ -5447,28 +5504,22 @@ ruby_setenv(const char *name, const char *value)
#elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
if (value) {
int ret;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
ret = setenv(name, value, 1);
}
- ENV_UNLOCK();
if (ret) rb_sys_fail_sprintf("setenv(%s)", name);
}
else {
#ifdef VOID_UNSETENV
- ENV_LOCK();
- {
+ ENV_LOCKING() {
unsetenv(name);
}
- ENV_UNLOCK();
#else
int ret;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
ret = unsetenv(name);
}
- ENV_UNLOCK();
if (ret) rb_sys_fail_sprintf("unsetenv(%s)", name);
#endif
@@ -5491,8 +5542,7 @@ ruby_setenv(const char *name, const char *value)
snprintf(mem_ptr, mem_size, "%s=%s", name, value);
}
- ENV_LOCK();
- {
+ ENV_LOCKING() {
for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) {
if (!strncmp(str, name, len) && str[len] == '=') {
if (!in_origenv(str)) free(str);
@@ -5501,15 +5551,12 @@ ruby_setenv(const char *name, const char *value)
}
}
}
- ENV_UNLOCK();
if (value) {
int ret;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
ret = putenv(mem_ptr);
}
- ENV_UNLOCK();
if (ret) {
free(mem_ptr);
@@ -5520,8 +5567,7 @@ ruby_setenv(const char *name, const char *value)
size_t len;
int i;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
i = envix(name); /* where does it go? */
if (environ == origenviron) { /* need we copy environment? */
@@ -5562,7 +5608,6 @@ ruby_setenv(const char *name, const char *value)
finish:;
}
- ENV_UNLOCK();
#endif /* WIN32 */
}
@@ -5647,8 +5692,7 @@ env_keys(int raw)
rb_encoding *enc = raw ? 0 : rb_locale_encoding();
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -5662,7 +5706,6 @@ env_keys(int raw)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ary;
}
@@ -5692,8 +5735,7 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj)
char **env;
long cnt = 0;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
env = GET_ENVIRON(environ);
for (; *env ; ++env) {
if (strchr(*env, '=')) {
@@ -5702,7 +5744,6 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return LONG2FIX(cnt);
}
@@ -5743,20 +5784,19 @@ env_values(void)
{
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_ary_push(ary, env_str_new2(s+1));
+ rb_ary_push(ary, env_str_new2(s+1, enc));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ary;
}
@@ -5837,21 +5877,20 @@ env_each_pair(VALUE ehash)
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_ary_push(ary, env_str_new(*env, s-*env));
- rb_ary_push(ary, env_str_new2(s+1));
+ rb_ary_push(ary, env_str_new(*env, s-*env, enc));
+ rb_ary_push(ary, env_str_new2(s+1, enc));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
if (rb_block_pair_yield_optimizable()) {
for (i=0; i<RARRAY_LEN(ary); i+=2) {
@@ -6191,8 +6230,7 @@ env_inspect(VALUE _)
VALUE str = rb_str_buf_new2("{");
rb_encoding *enc = env_encoding();
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
const char *s = strchr(*env, '=');
@@ -6210,7 +6248,6 @@ env_inspect(VALUE _)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
rb_str_buf_cat2(str, "}");
@@ -6231,20 +6268,19 @@ env_to_a(VALUE _)
{
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
- env_str_new2(s+1)));
+ rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env, enc),
+ env_str_new2(s+1, enc)));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ary;
}
@@ -6268,13 +6304,11 @@ env_size_with_lock(void)
{
int i = 0;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (env[i]) i++;
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return i;
}
@@ -6310,15 +6344,13 @@ env_empty_p(VALUE _)
{
bool empty = true;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
if (env[0] != 0) {
empty = false;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return RBOOL(empty);
}
@@ -6407,8 +6439,7 @@ env_has_value(VALUE dmy, VALUE obj)
VALUE ret = Qfalse;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -6423,7 +6454,6 @@ env_has_value(VALUE dmy, VALUE obj)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ret;
}
@@ -6450,13 +6480,12 @@ env_rassoc(VALUE dmy, VALUE obj)
VALUE result = Qnil;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
const char *p = *env;
- char *s = strchr(p, '=');
+ const char *s = strchr(p, '=');
if (s++) {
long len = strlen(s);
if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
@@ -6468,7 +6497,6 @@ env_rassoc(VALUE dmy, VALUE obj)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return result;
}
@@ -6495,15 +6523,15 @@ env_key(VALUE dmy, VALUE value)
StringValue(value);
VALUE str = Qnil;
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s++) {
long len = strlen(s);
if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
- str = env_str_new(*env, s-*env-1);
+ str = env_str_new(*env, s-*env-1, enc);
break;
}
}
@@ -6511,7 +6539,6 @@ env_key(VALUE dmy, VALUE value)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return str;
}
@@ -6521,20 +6548,19 @@ env_to_hash(void)
{
VALUE hash = rb_hash_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_hash_aset(hash, env_str_new(*env, s-*env),
- env_str_new2(s+1));
+ rb_hash_aset(hash, env_str_new(*env, s-*env, enc),
+ env_str_new2(s+1, enc));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return hash;
}
@@ -6674,21 +6700,20 @@ env_shift(VALUE _)
VALUE result = Qnil;
VALUE key = Qnil;
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
if (*env) {
const char *p = *env;
- char *s = strchr(p, '=');
+ const char *s = strchr(p, '=');
if (s) {
- key = env_str_new(p, s-p);
- VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
+ key = env_str_new(p, s-p, enc);
+ VALUE val = env_str_new2(getenv(RSTRING_PTR(key)), enc);
result = rb_assoc_new(key, val);
}
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
if (!NIL_P(key)) {
env_delete(key);
@@ -6902,7 +6927,7 @@ static const rb_data_type_t env_data_type = {
* A \Hash object 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 key can be (almost) any object.
*
@@ -6946,24 +6971,24 @@ static const rb_data_type_t env_data_type = {
*
* === Common Uses
*
- * You can use a +Hash+ to give names to objects:
+ * You can use a hash to give names to objects:
*
* person = {name: 'Matz', language: 'Ruby'}
* person # => {name: "Matz", language: "Ruby"}
*
- * You can use a +Hash+ to give names to method arguments:
+ * You can use a hash to give names to method arguments:
*
* def some_method(hash)
* p hash
* end
* some_method({foo: 0, bar: 1, baz: 2}) # => {foo: 0, bar: 1, baz: 2}
*
- * Note: when the last argument in a method call is a +Hash+,
+ * Note: when the last argument in a method call is a hash,
* the curly braces may be omitted:
*
* some_method(foo: 0, bar: 1, baz: 2) # => {foo: 0, bar: 1, baz: 2}
*
- * You can use a +Hash+ to initialize an object:
+ * You can use a hash to initialize an object:
*
* class Dev
* attr_accessor :name, :language
@@ -6975,57 +7000,49 @@ static const rb_data_type_t env_data_type = {
* matz = Dev.new(name: 'Matz', language: 'Ruby')
* matz # => #<Dev: @name="Matz", @language="Ruby">
*
- * === Creating a +Hash+
+ * === Creating a \Hash
*
- * You can create a +Hash+ object explicitly with:
+ * You can create a \Hash object explicitly with:
*
* - A {hash literal}[rdoc-ref:syntax/literals.rdoc@Hash+Literals].
*
- * You can convert certain objects to Hashes with:
- *
- * - Method #Hash.
+ * You can convert certain objects to hashes with:
*
- * You can create a +Hash+ by calling method Hash.new.
+ * - Method Kernel#Hash.
*
- * Create an empty +Hash+:
+ * You can create a hash by calling method Hash.new:
*
+ * # Create an empty hash.
* h = Hash.new
* h # => {}
* h.class # => Hash
*
- * You can create a +Hash+ by calling method Hash.[].
- *
- * Create an empty +Hash+:
+ * You can create a hash by calling method Hash.[]:
*
+ * # Create an empty hash.
* h = Hash[]
* h # => {}
- *
- * Create a +Hash+ with initial entries:
- *
+ * # Create a hash with initial entries.
* h = Hash[foo: 0, bar: 1, baz: 2]
* h # => {foo: 0, bar: 1, baz: 2}
*
- * You can create a +Hash+ by using its literal form (curly braces).
- *
- * Create an empty +Hash+:
+ * You can create a hash by using its literal form (curly braces):
*
+ * # Create an empty hash.
* h = {}
* h # => {}
- *
- * Create a +Hash+ with initial entries:
- *
+ * # Create a +Hash+ with initial entries.
* h = {foo: 0, bar: 1, baz: 2}
* h # => {foo: 0, bar: 1, baz: 2}
*
+ * === \Hash Value Basics
*
- * === +Hash+ Value Basics
- *
- * The simplest way to retrieve a +Hash+ value (instance method #[]):
+ * The simplest way to retrieve a hash value (instance method #[]):
*
* h = {foo: 0, bar: 1, baz: 2}
* h[:foo] # => 0
*
- * The simplest way to create or update a +Hash+ value (instance method #[]=):
+ * The simplest way to create or update a hash value (instance method #[]=):
*
* h = {foo: 0, bar: 1, baz: 2}
* h[:bat] = 3 # => 3
@@ -7033,7 +7050,7 @@ static const rb_data_type_t env_data_type = {
* h[:foo] = 4 # => 4
* h # => {foo: 4, bar: 1, baz: 2, bat: 3}
*
- * The simplest way to delete a +Hash+ entry (instance method #delete):
+ * The simplest way to delete a hash entry (instance method #delete):
*
* h = {foo: 0, bar: 1, baz: 2}
* h.delete(:bar) # => 1
@@ -7041,13 +7058,13 @@ static const rb_data_type_t env_data_type = {
*
* === Entry Order
*
- * A +Hash+ object presents its entries in the order of their creation. This is seen in:
+ * A \Hash object presents its entries in the order of their creation. This is seen in:
*
* - 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:
+ * A new hash has its initial ordering per the given entries:
*
* h = Hash[foo: 0, bar: 1]
* h # => {foo: 0, bar: 1}
@@ -7246,8 +7263,8 @@ static const rb_data_type_t env_data_type = {
*
* First, what's elsewhere. Class +Hash+:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class +Hash+ provides methods that are useful for:
@@ -7311,7 +7328,7 @@ static const rb_data_type_t env_data_type = {
* - #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.
- * - #values: Returns an array containing all values in +self+/
+ * - #values: Returns an array containing all values in +self+.
* - #values_at: Returns an array containing values for given keys.
*
* ==== Methods for Assigning
@@ -7360,7 +7377,6 @@ static const rb_data_type_t env_data_type = {
*
* ==== Methods for Transforming Keys and Values
*
- * - #flatten!: Returns +self+, flattened.
* - #invert: Returns a hash with the each key-value pair inverted.
* - #transform_keys: Returns a copy of +self+ with modified keys.
* - #transform_keys!: Modifies keys in +self+
@@ -7472,7 +7488,8 @@ Init_Hash(void)
rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash?", rb_hash_s_ruby2_keywords_hash_p, 1);
rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash", rb_hash_s_ruby2_keywords_hash, 1);
- rb_cHash_empty_frozen = rb_hash_freeze(rb_hash_new());
+ rb_cHash_empty_frozen = rb_hash_freeze(rb_hash_alloc_fixed_size(rb_cHash, 0));
+ RB_OBJ_SET_SHAREABLE(rb_cHash_empty_frozen);
rb_vm_register_global_object(rb_cHash_empty_frozen);
/* Document-class: ENV
@@ -7558,8 +7575,8 @@ Init_Hash(void)
*
* First, what's elsewhere. Class +ENV+:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Extends {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Extends {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
*
* Here, class +ENV+ provides methods that are useful for:
*
@@ -7608,9 +7625,10 @@ Init_Hash(void)
*
* - ::assoc: Returns a 2-element array containing the name and value
* of the named environment variable if it exists:
- * - ::clone: Returns +ENV+ (and issues a warning).
+ * - ::clone: Raises an exception.
* - ::except: Returns a hash of all name/value pairs except those given.
* - ::fetch: Returns the value for the given name.
+ * - ::fetch_values: Returns array containing the values associated with given names.
* - ::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.
@@ -7642,11 +7660,11 @@ Init_Hash(void)
origenviron = environ;
envtbl = TypedData_Wrap_Struct(rb_cObject, &env_data_type, NULL);
rb_extend_object(envtbl, rb_mEnumerable);
- FL_SET_RAW(envtbl, RUBY_FL_SHAREABLE);
-
+ RB_OBJ_SET_SHAREABLE(envtbl);
rb_define_singleton_method(envtbl, "[]", rb_f_getenv, 1);
rb_define_singleton_method(envtbl, "fetch", env_fetch, -1);
+ rb_define_singleton_method(envtbl, "fetch_values", env_fetch_values, -1);
rb_define_singleton_method(envtbl, "[]=", env_aset_m, 2);
rb_define_singleton_method(envtbl, "store", env_aset_m, 2);
rb_define_singleton_method(envtbl, "each", env_each_pair, 0);
diff --git a/hash.rb b/hash.rb
index 99b34a9bda..40f823783e 100644
--- a/hash.rb
+++ b/hash.rb
@@ -7,7 +7,7 @@ class Hash
#
# Initializes the values of Hash#default and Hash#default_proc,
# which determine the behavior when a given key is not found;
- # see {Key Not Found?}[rdoc-ref:Hash@Key+Not+Found-3F].
+ # see {Key Not Found?}[rdoc-ref:Hash@Key+Not+Found].
#
# By default, a hash has +nil+ values for both +default+ and +default_proc+:
#
diff --git a/id_table.c b/id_table.c
index 6bb067d09a..299b7d3ae5 100644
--- a/id_table.c
+++ b/id_table.c
@@ -38,16 +38,9 @@ typedef struct rb_id_item {
VALUE val;
} item_t;
-struct rb_id_table {
- int capa;
- int num;
- int used;
- item_t *items;
-};
-
#if SIZEOF_VALUE == 8
#define ITEM_GET_KEY(tbl, i) ((tbl)->items[i].key)
-#define ITEM_KEY_ISSET(tbl, i) ((tbl)->items[i].key)
+#define ITEM_KEY_ISSET(tbl, i) ((tbl)->items && (tbl)->items[i].key)
#define ITEM_COLLIDED(tbl, i) ((tbl)->items[i].collision)
#define ITEM_SET_COLLIDED(tbl, i) ((tbl)->items[i].collision = 1)
static inline void
@@ -80,9 +73,10 @@ round_capa(int capa)
return (capa + 1) << 2;
}
-static struct rb_id_table *
-rb_id_table_init(struct rb_id_table *tbl, int capa)
+struct rb_id_table *
+rb_id_table_init(struct rb_id_table *tbl, size_t s_capa)
{
+ int capa = (int)s_capa;
MEMZERO(tbl, struct rb_id_table, 1);
if (capa > 0) {
capa = round_capa(capa);
@@ -96,7 +90,13 @@ struct rb_id_table *
rb_id_table_create(size_t capa)
{
struct rb_id_table *tbl = ALLOC(struct rb_id_table);
- return rb_id_table_init(tbl, (int)capa);
+ return rb_id_table_init(tbl, capa);
+}
+
+void
+rb_id_table_free_items(struct rb_id_table *tbl)
+{
+ xfree(tbl->items);
}
void
@@ -291,6 +291,10 @@ rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_f
{
int i, capa = tbl->capa;
+ if (!tbl->items) {
+ return;
+ }
+
for (i=0; i<capa; i++) {
if (ITEM_KEY_ISSET(tbl, i)) {
enum rb_id_table_iterator_result ret = (*func)(tbl->items[i].val, data);
@@ -324,3 +328,185 @@ rb_id_table_foreach_values_with_replace(struct rb_id_table *tbl, rb_id_table_for
}
}
+static void
+managed_id_table_free(void *data)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)data;
+ rb_id_table_free_items(tbl);
+}
+
+static size_t
+managed_id_table_memsize(const void *data)
+{
+ const struct rb_id_table *tbl = (const struct rb_id_table *)data;
+ return rb_id_table_memsize(tbl) - sizeof(struct rb_id_table);
+}
+
+const rb_data_type_t rb_managed_id_table_type = {
+ .wrap_struct_name = "VM/managed_id_table",
+ .function = {
+ .dmark = NULL, // Nothing to mark
+ .dfree = managed_id_table_free,
+ .dsize = managed_id_table_memsize,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+};
+
+static inline struct rb_id_table *
+managed_id_table_ptr(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, T_DATA));
+ RUBY_ASSERT(rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), &rb_managed_id_table_type));
+
+ return RTYPEDDATA_GET_DATA(obj);
+}
+
+VALUE
+rb_managed_id_table_create(const rb_data_type_t *type, size_t capa)
+{
+ struct rb_id_table *tbl;
+ VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, type, tbl);
+ RB_OBJ_SET_SHAREABLE(obj);
+ rb_id_table_init(tbl, capa); // NOTE: this can cause GC, so dmark and dsize need to check tbl->items
+ return obj;
+}
+
+VALUE
+rb_managed_id_table_new(size_t capa)
+{
+ return rb_managed_id_table_create(&rb_managed_id_table_type, capa);
+}
+
+static enum rb_id_table_iterator_result
+managed_id_table_dup_i(ID id, VALUE val, void *data)
+{
+ struct rb_id_table *new_tbl = (struct rb_id_table *)data;
+ rb_id_table_insert(new_tbl, id, val);
+ return ID_TABLE_CONTINUE;
+}
+
+VALUE
+rb_managed_id_table_dup(VALUE old_table)
+{
+ struct rb_id_table *new_tbl;
+ VALUE obj = TypedData_Make_Struct(0, struct rb_id_table, RTYPEDDATA_TYPE(old_table), new_tbl);
+ struct rb_id_table *old_tbl = managed_id_table_ptr(old_table);
+ rb_id_table_init(new_tbl, old_tbl->num + 1);
+ rb_id_table_foreach(old_tbl, managed_id_table_dup_i, new_tbl);
+ return obj;
+}
+
+int
+rb_managed_id_table_lookup(VALUE table, ID id, VALUE *valp)
+{
+ return rb_id_table_lookup(managed_id_table_ptr(table), id, valp);
+}
+
+int
+rb_managed_id_table_insert(VALUE table, ID id, VALUE val)
+{
+ return rb_id_table_insert(managed_id_table_ptr(table), id, val);
+}
+
+size_t
+rb_managed_id_table_size(VALUE table)
+{
+ return rb_id_table_size(managed_id_table_ptr(table));
+}
+
+void
+rb_managed_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void *data)
+{
+ rb_id_table_foreach(managed_id_table_ptr(table), func, data);
+}
+
+void
+rb_managed_id_table_foreach_values(VALUE table, rb_id_table_foreach_values_func_t *func, void *data)
+{
+ rb_id_table_foreach_values(managed_id_table_ptr(table), func, data);
+}
+
+int
+rb_managed_id_table_delete(VALUE table, ID id)
+{
+ return rb_id_table_delete(managed_id_table_ptr(table), id);
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_mark_i(VALUE val, void *data)
+{
+ rb_gc_mark_movable(val);
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+marked_id_table_mark(void *ptr)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)ptr;
+ rb_id_table_foreach_values(tbl, marked_id_table_mark_i, NULL);
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_compact_check_i(VALUE value, void *data)
+{
+ if (rb_gc_location(value) != value) {
+ return ID_TABLE_REPLACE;
+ }
+ return ID_TABLE_CONTINUE;
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_compact_replace_i(VALUE *value, void *data, int existing)
+{
+ *value = rb_gc_location(*value);
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+marked_id_table_compact(void *ptr)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)ptr;
+ rb_id_table_foreach_values_with_replace(tbl, marked_id_table_compact_check_i, marked_id_table_compact_replace_i, NULL);
+}
+
+const rb_data_type_t rb_marked_id_table_type = {
+ .wrap_struct_name = "VM/marked_id_table",
+ .function = {
+ .dmark = marked_id_table_mark,
+ .dfree = managed_id_table_free,
+ .dsize = managed_id_table_memsize,
+ .dcompact = marked_id_table_compact,
+ },
+ .parent = &rb_managed_id_table_type,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+};
+
+VALUE
+rb_marked_id_table_new(size_t capa)
+{
+ return rb_managed_id_table_create(&rb_marked_id_table_type, capa);
+}
+
+int
+rb_marked_id_table_insert(VALUE table, ID id, VALUE val)
+{
+ int result = rb_managed_id_table_insert(table, id, val);
+ RB_OBJ_WRITTEN(table, Qundef, val);
+ return result;
+}
+
+static enum rb_id_table_iterator_result
+marked_id_table_dup_i(VALUE val, void *data)
+{
+ VALUE new_table = (VALUE)data;
+ RB_OBJ_WRITTEN(new_table, Qundef, val);
+ return ID_TABLE_CONTINUE;
+}
+
+VALUE
+rb_marked_id_table_dup(VALUE old_table)
+{
+ VALUE new_table = rb_managed_id_table_dup(old_table);
+ rb_managed_id_table_foreach_values(new_table, marked_id_table_dup_i, (void *)new_table);
+ return new_table;
+}
diff --git a/id_table.h b/id_table.h
index f72e2d1d92..c4333bea98 100644
--- a/id_table.h
+++ b/id_table.h
@@ -4,7 +4,14 @@
#include <stddef.h>
#include "ruby/ruby.h"
-struct rb_id_table;
+struct rb_id_item;
+
+struct rb_id_table {
+ int capa;
+ int num;
+ int used;
+ struct rb_id_item *items;
+};
/* compatible with ST_* */
enum rb_id_table_iterator_result {
@@ -16,7 +23,10 @@ enum rb_id_table_iterator_result {
};
struct rb_id_table *rb_id_table_create(size_t size);
+struct rb_id_table *rb_id_table_init(struct rb_id_table *tbl, size_t capa);
+
void rb_id_table_free(struct rb_id_table *tbl);
+void rb_id_table_free_items(struct rb_id_table *tbl);
void rb_id_table_clear(struct rb_id_table *tbl);
size_t rb_id_table_memsize(const struct rb_id_table *tbl);
@@ -32,6 +42,28 @@ void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *fu
void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data);
void rb_id_table_foreach_values_with_replace(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, rb_id_table_update_value_callback_func_t *replace, void *data);
+VALUE rb_managed_id_table_create(const rb_data_type_t *type, size_t capa);
+VALUE rb_managed_id_table_new(size_t capa);
+VALUE rb_managed_id_table_dup(VALUE table);
+int rb_managed_id_table_insert(VALUE table, ID id, VALUE val);
+int rb_managed_id_table_lookup(VALUE table, ID id, VALUE *valp);
+size_t rb_managed_id_table_size(VALUE table);
+void rb_managed_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void *data);
+void rb_managed_id_table_foreach_values(VALUE table, rb_id_table_foreach_values_func_t *func, void *data);
+int rb_managed_id_table_delete(VALUE table, ID id);
+
+extern const rb_data_type_t rb_managed_id_table_type;
+
+VALUE rb_marked_id_table_new(size_t capa);
+int rb_marked_id_table_insert(VALUE table, ID id, VALUE val);
+VALUE rb_marked_id_table_dup(VALUE table);
+
+// alisases
+#define rb_marked_id_table_size rb_managed_id_table_size
+#define rb_marked_id_table_lookup rb_managed_id_table_lookup
+#define rb_marked_id_table_foreach rb_managed_id_table_foreach
+#define rb_marked_id_table_foreach_values rb_managed_id_table_foreach_values
+
RUBY_SYMBOL_EXPORT_BEGIN
size_t rb_id_table_size(const struct rb_id_table *tbl);
RUBY_SYMBOL_EXPORT_END
diff --git a/imemo.c b/imemo.c
index a0ed567719..796e078c89 100644
--- a/imemo.c
+++ b/imemo.c
@@ -3,6 +3,8 @@
#include "id_table.h"
#include "internal.h"
#include "internal/imemo.h"
+#include "internal/object.h"
+#include "internal/st.h"
#include "vm_callinfo.h"
size_t rb_iseq_memsize(const rb_iseq_t *iseq);
@@ -15,7 +17,6 @@ rb_imemo_name(enum imemo_type type)
// put no default case to get a warning if an imemo type is missing
switch (type) {
#define IMEMO_NAME(x) case imemo_##x: return #x;
- IMEMO_NAME(ast);
IMEMO_NAME(callcache);
IMEMO_NAME(callinfo);
IMEMO_NAME(constcache);
@@ -25,14 +26,16 @@ rb_imemo_name(enum imemo_type type)
IMEMO_NAME(iseq);
IMEMO_NAME(memo);
IMEMO_NAME(ment);
- IMEMO_NAME(parser_strterm);
IMEMO_NAME(svar);
IMEMO_NAME(throw_data);
IMEMO_NAME(tmpbuf);
+ IMEMO_NAME(cvar_entry);
+ IMEMO_NAME(fields);
+ IMEMO_NAME(subclasses);
+ IMEMO_NAME(cdhash);
#undef IMEMO_NAME
- default:
- rb_bug("unreachable");
}
+ rb_bug("unreachable");
}
/* =========================================================================
@@ -40,73 +43,225 @@ rb_imemo_name(enum imemo_type type)
* ========================================================================= */
VALUE
-rb_imemo_new(enum imemo_type type, VALUE v0, size_t size)
+rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable)
{
- VALUE flags = T_IMEMO | FL_WB_PROTECTED | (type << FL_USHIFT);
- NEWOBJ_OF(obj, void, v0, flags, size, 0);
-
- return (VALUE)obj;
+ VALUE flags = T_IMEMO | (type << FL_USHIFT) | (is_shareable ? FL_SHAREABLE : 0);
+ return rb_newobj_of(v0, flags, size);
}
-static rb_imemo_tmpbuf_t *
+VALUE
rb_imemo_tmpbuf_new(void)
{
- size_t size = sizeof(struct rb_imemo_tmpbuf_struct);
VALUE flags = T_IMEMO | (imemo_tmpbuf << FL_USHIFT);
- NEWOBJ_OF(obj, struct rb_imemo_tmpbuf_struct, 0, flags, size, 0);
+ UNPROTECTED_NEWOBJ_OF(obj, rb_imemo_tmpbuf_t, 0, flags, sizeof(rb_imemo_tmpbuf_t));
+
+ rb_gc_register_pinning_obj((VALUE)obj);
- return obj;
+ obj->ptr = NULL;
+ obj->size = 0;
+
+ return (VALUE)obj;
}
void *
-rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
+rb_alloc_tmp_buffer(volatile VALUE *store, long len)
{
- void *ptr;
- rb_imemo_tmpbuf_t *tmpbuf;
+ if (len < 0) {
+ rb_raise(rb_eArgError, "negative buffer size (or size too big)");
+ }
/* Keep the order; allocate an empty imemo first then xmalloc, to
* get rid of potential memory leak */
- tmpbuf = rb_imemo_tmpbuf_new();
+ rb_imemo_tmpbuf_t *tmpbuf = (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new();
*store = (VALUE)tmpbuf;
- ptr = ruby_xmalloc(size);
+ void *ptr = ruby_xmalloc(len);
tmpbuf->ptr = ptr;
- tmpbuf->cnt = cnt;
+ tmpbuf->size = len;
return ptr;
}
void *
-rb_alloc_tmp_buffer(volatile VALUE *store, long len)
+rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
{
- long cnt;
-
- if (len < 0 || (cnt = (long)roomof(len, sizeof(VALUE))) < 0) {
- rb_raise(rb_eArgError, "negative buffer size (or size too big)");
- }
-
- return rb_alloc_tmp_buffer_with_count(store, len, cnt);
+ return rb_alloc_tmp_buffer(store, (long)size);
}
void
rb_free_tmp_buffer(volatile VALUE *store)
{
+ if (!*store) return;
rb_imemo_tmpbuf_t *s = (rb_imemo_tmpbuf_t*)ATOMIC_VALUE_EXCHANGE(*store, 0);
if (s) {
void *ptr = ATOMIC_PTR_EXCHANGE(s->ptr, 0);
- s->cnt = 0;
- ruby_xfree(ptr);
+ long size = s->size;
+ s->size = 0;
+ ruby_xfree_sized(ptr, size);
}
}
-rb_imemo_tmpbuf_t *
-rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
+struct MEMO *
+rb_imemo_memo_new(VALUE a, VALUE b, long c)
{
- rb_imemo_tmpbuf_t *tmpbuf = rb_imemo_tmpbuf_new();
- tmpbuf->ptr = buf;
- tmpbuf->next = old_heap;
- tmpbuf->cnt = cnt;
+ struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
+
+ *((VALUE *)&memo->v1) = a;
+ *((VALUE *)&memo->v2) = b;
+ memo->u3.cnt = c;
+
+ return memo;
+}
+
+struct MEMO *
+rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c)
+{
+ struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
+
+ *((VALUE *)&memo->v1) = a;
+ *((VALUE *)&memo->v2) = b;
+ *((VALUE *)&memo->u3.value) = c;
+ memo->flags |= MEMO_U3_IS_VALUE;
- return tmpbuf;
+ return memo;
+}
+
+VALUE
+rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type)
+{
+ struct rb_imemo_cdhash *memo = IMEMO_NEW(struct rb_imemo_cdhash, imemo_cdhash, 0);
+ memo->tbl.num_entries = 0;
+ st_init_existing_table_with_size(&memo->tbl, type, size);
+ return (VALUE)memo;
+}
+
+VALUE
+rb_imemo_fields_new(VALUE owner, shape_id_t shape_id, bool shareable)
+{
+ size_t capa = RSHAPE_CAPACITY(shape_id);
+ size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
+ RUBY_ASSERT(rb_gc_size_allocatable_p(embedded_size));
+ VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
+ return fields;
+}
+
+VALUE
+rb_imemo_fields_new_complex(VALUE owner, shape_id_t shape_id, size_t capa, bool shareable)
+{
+ VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
+ IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
+ FL_SET_RAW(fields, OBJ_FIELD_HEAP);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ return fields;
+}
+
+static int
+imemo_fields_trigger_wb_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ VALUE field_obj = (VALUE)arg;
+ RB_OBJ_WRITTEN(field_obj, Qundef, (VALUE)value);
+ return ST_CONTINUE;
+}
+
+static int
+imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ RB_OBJ_WRITTEN((VALUE)arg, Qundef, (VALUE)value);
+ return ST_CONTINUE;
+}
+
+VALUE
+rb_imemo_fields_new_complex_tbl(VALUE owner, shape_id_t shape_id, st_table *tbl, bool shareable)
+{
+ VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
+ IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
+ FL_SET_RAW(fields, OBJ_FIELD_HEAP);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
+ return fields;
+}
+
+VALUE
+rb_imemo_fields_clone(VALUE fields_obj)
+{
+ shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
+ VALUE clone;
+
+ if (rb_shape_complex_p(shape_id)) {
+ st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
+
+ st_table *dest_table = xcalloc(1, sizeof(st_table));
+ clone = rb_imemo_fields_new_complex_tbl(rb_imemo_fields_owner(fields_obj), shape_id, dest_table, false /* TODO: check */);
+
+ st_replace(dest_table, src_table);
+
+ st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
+ }
+ else {
+ clone = rb_imemo_fields_new(rb_imemo_fields_owner(fields_obj), shape_id, false /* TODO: check */);
+ VALUE *fields = rb_imemo_fields_ptr(clone);
+ attr_index_t fields_count = RSHAPE_LEN(shape_id);
+ MEMCPY(fields, rb_imemo_fields_ptr(fields_obj), VALUE, fields_count);
+ for (attr_index_t i = 0; i < fields_count; i++) {
+ RB_OBJ_WRITTEN(clone, Qundef, fields[i]);
+ }
+ }
+
+ return clone;
+}
+
+void
+rb_imemo_fields_clear(VALUE fields_obj)
+{
+ // When replacing an imemo/fields by another one, we must clear
+ // its shape so that gc.c:obj_free_object_id won't be called.
+ if (rb_obj_shape_complex_p(fields_obj)) {
+ RBASIC_SET_SHAPE_ID(fields_obj, ROOT_COMPLEX_SHAPE_ID);
+ }
+ else {
+ RBASIC_SET_SHAPE_ID(fields_obj, ROOT_SHAPE_ID);
+ }
+ // Invalidate the ec->gen_fields_cache.
+ RBASIC_CLEAR_CLASS(fields_obj);
+}
+
+VALUE
+rb_imemo_subclasses_new(uint32_t capacity)
+{
+ size_t embed_size = offsetof(struct rb_subclasses, as) + capacity * sizeof(VALUE);
+ struct rb_subclasses *subs;
+
+ if (rb_gc_size_allocatable_p(embed_size)) {
+ subs = (struct rb_subclasses *)rb_imemo_new(imemo_subclasses, 0, embed_size, true);
+ subs->count = 0;
+ subs->capacity = capacity;
+ memset(subs->as.embed, 0, capacity * sizeof(VALUE));
+ rb_gc_declare_weak_references((VALUE)subs);
+ }
+ else {
+ subs = (struct rb_subclasses *)rb_imemo_new(imemo_subclasses, 0, sizeof(struct rb_subclasses), true);
+ subs->as.external = NULL;
+ subs->count = 0;
+ subs->capacity = 0;
+ FL_SET_RAW((VALUE)subs, IMEMO_SUBCLASSES_HEAP);
+ rb_gc_declare_weak_references((VALUE)subs);
+ subs->as.external = ZALLOC_N(VALUE, capacity);
+ subs->capacity = capacity;
+ }
+ return (VALUE)subs;
}
/* =========================================================================
@@ -118,10 +273,6 @@ rb_imemo_memsize(VALUE obj)
{
size_t size = 0;
switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
case imemo_callcache:
break;
case imemo_callinfo:
@@ -146,14 +297,32 @@ rb_imemo_memsize(VALUE obj)
size += sizeof(((rb_method_entry_t *)obj)->def);
break;
- case imemo_parser_strterm:
- break;
case imemo_svar:
break;
case imemo_throw_data:
break;
case imemo_tmpbuf:
- size += ((rb_imemo_tmpbuf_t *)obj)->cnt * sizeof(VALUE);
+ size += ((rb_imemo_tmpbuf_t *)obj)->size;
+
+ break;
+ case imemo_cvar_entry:
+ break;
+ case imemo_fields:
+ if (rb_obj_shape_complex_p(obj)) {
+ size += st_memsize(IMEMO_OBJ_FIELDS(obj)->as.complex.table);
+ }
+
+ break;
+ case imemo_subclasses: {
+ if (FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP)) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ size += subs->capacity * sizeof(VALUE);
+ }
+
+ break;
+ }
+ case imemo_cdhash:
+ size += st_memsize(rb_imemo_cdhash_tbl(obj)) - sizeof(st_table);
break;
default:
@@ -167,49 +336,10 @@ rb_imemo_memsize(VALUE obj)
* mark
* ========================================================================= */
-static enum rb_id_table_iterator_result
-cc_table_mark_i(VALUE ccs_ptr, void *data)
-{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VM_ASSERT(vm_ccs_p(ccs));
-#if VM_CHECK_MODE > 0
- VALUE klass = (VALUE)data;
-
- VALUE lookup_val;
- VM_ASSERT(rb_id_table_lookup(RCLASS_CC_TBL(klass), ccs->cme->called_id, &lookup_val));
- VM_ASSERT(lookup_val == ccs_ptr);
-#endif
-
- if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
- rb_vm_ccs_free(ccs);
- return ID_TABLE_DELETE;
- }
- else {
- rb_gc_mark_movable((VALUE)ccs->cme);
-
- for (int i=0; i<ccs->len; i++) {
- VM_ASSERT(klass == ccs->entries[i].cc->klass);
- VM_ASSERT(vm_cc_check_cme(ccs->entries[i].cc, ccs->cme));
-
- rb_gc_mark_movable((VALUE)ccs->entries[i].cc);
- }
- return ID_TABLE_CONTINUE;
- }
-}
-
-void
-rb_cc_table_mark(VALUE klass)
-{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- if (cc_tbl) {
- rb_id_table_foreach_values(cc_tbl, cc_table_mark_i, (void *)klass);
- }
-}
-
static bool
moved_or_living_object_strictly_p(VALUE obj)
{
- return obj && (!rb_objspace_garbage_object_p(obj) || BUILTIN_TYPE(obj) == T_MOVED);
+ return !SPECIAL_CONST_P(obj) && (!rb_objspace_garbage_object_p(obj) || BUILTIN_TYPE(obj) == T_MOVED);
}
static void
@@ -241,9 +371,8 @@ mark_and_move_method_entry(rb_method_entry_t *ment, bool reference_updating)
rb_gc_mark_and_move(&def->body.attr.location);
break;
case VM_METHOD_TYPE_BMETHOD:
- rb_gc_mark_and_move(&def->body.bmethod.proc);
- if (!reference_updating) {
- if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&def->body.bmethod.proc);
}
break;
case VM_METHOD_TYPE_ALIAS:
@@ -267,51 +396,52 @@ void
rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
{
switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
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.
+ * For "normal" CCs cc->cme (cme) should not be marked because the cc is
+ * invalidated through the klass when the cme is free'd.
* - 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
+ * - caller class's ccs->cme marks cc->cme.
+ * - if cc is invalidated (klass doesn't refer the cc), cc is
+ * invalidated by `vm_cc_invalidate()` after which cc->cme must not
+ * be accessed.
+ * - With 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.
+ *
+ * However cc_type_super and cc_type_refinement are not chained
+ * from ccs so cc->cme should be marked as long as the cc is valid;
+ * the cme might be reachable only through cc in these cases.
*/
struct rb_callcache *cc = (struct rb_callcache *)obj;
- if (reference_updating) {
- if (!cc->klass) {
- // already invalidated
+ if (UNDEF_P(cc->klass)) {
+ /* If it's invalidated, we must not mark anything.
+ * All fields should are considered invalid
+ */
+ }
+ else if (reference_updating) {
+ if (moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
+ *((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
+ *((struct rb_callable_method_entry_struct **)&cc->cme_) =
+ (struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cc->cme_);
+
+ RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
+ RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
}
else {
- if (moved_or_living_object_strictly_p(cc->klass) &&
- moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
- *((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
- *((struct rb_callable_method_entry_struct **)&cc->cme_) =
- (struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cc->cme_);
- }
- else {
- vm_cc_invalidate(cc);
- }
+ vm_cc_invalidate(cc);
}
}
else {
- if (cc->klass && (vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
+ RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
+ RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
+
+ if ((vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
rb_gc_mark_movable((VALUE)cc->cme_);
- rb_gc_mark_movable((VALUE)cc->klass);
}
}
@@ -322,16 +452,27 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
case imemo_constcache: {
struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
- rb_gc_mark_and_move(&ice->value);
+ if ((ice->flags & IMEMO_CONST_CACHE_SHAREABLE) ||
+ !rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&ice->value);
+ }
break;
}
case imemo_cref: {
rb_cref_t *cref = (rb_cref_t *)obj;
- rb_gc_mark_and_move(&cref->klass_or_self);
+ if (!rb_gc_checking_shareable()) {
+ // cref->klass_or_self can be unshareable, but no way to access it from other ractors
+ rb_gc_mark_and_move(&cref->klass_or_self);
+ }
+
rb_gc_mark_and_move_ptr(&cref->next);
- rb_gc_mark_and_move(&cref->refinements);
+
+ // TODO: Ractor and refeinements are not resolved yet
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&cref->refinements);
+ }
break;
}
@@ -349,6 +490,13 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
rb_gc_mark_and_move_ptr(&env->iseq);
+ if (VM_ENV_LOCAL_P(env->ep) && VM_ENV_BOXED_P(env->ep)) {
+ const rb_box_t *box = VM_ENV_BOX(env->ep);
+ if (BOX_USER_P(box)) {
+ rb_gc_mark_and_move((VALUE *)&box->box_object);
+ }
+ }
+
if (reference_updating) {
((VALUE *)env->ep)[VM_ENV_DATA_INDEX_ENV] = rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]);
}
@@ -379,8 +527,8 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
rb_gc_mark_and_move((VALUE *)&memo->v1);
rb_gc_mark_and_move((VALUE *)&memo->v2);
- if (!reference_updating) {
- rb_gc_mark_maybe(memo->u3.value);
+ if (FL_TEST_RAW(obj, MEMO_U3_IS_VALUE)) {
+ rb_gc_mark_and_move((VALUE *)&memo->u3.value);
}
break;
@@ -388,8 +536,6 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
case imemo_ment:
mark_and_move_method_entry((rb_method_entry_t *)obj, reference_updating);
break;
- case imemo_parser_strterm:
- break;
case imemo_svar: {
struct vm_svar *svar = (struct vm_svar *)obj;
@@ -411,13 +557,65 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
const rb_imemo_tmpbuf_t *m = (const rb_imemo_tmpbuf_t *)obj;
if (!reference_updating) {
- do {
- rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
- } while ((m = m->next) != NULL);
+ rb_gc_mark_locations(m->ptr, m->ptr + (m->size / sizeof(VALUE)));
}
break;
}
+ case imemo_cvar_entry: {
+ struct rb_cvar_class_tbl_entry *ent = (struct rb_cvar_class_tbl_entry *)obj;
+ rb_gc_mark_and_move(&ent->class_value);
+ rb_gc_mark_and_move((VALUE *)&ent->cref);
+ break;
+ }
+ case imemo_subclasses: {
+ if (reference_updating) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ VALUE *entries = rb_imemo_subclasses_entries(obj);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ if (entries[i]) {
+ entries[i] = rb_gc_location(entries[i]);
+ }
+ }
+ }
+ break;
+ }
+ case imemo_fields: {
+ rb_gc_mark_and_move((VALUE *)&RBASIC(obj)->klass);
+
+ if (!rb_gc_checking_shareable()) {
+ // imemo_fields can refer unshareable objects
+ // even if the imemo_fields is shareable.
+
+ if (rb_obj_shape_complex_p(obj)) {
+ st_table *tbl = rb_imemo_fields_complex_tbl(obj);
+ if (reference_updating) {
+ rb_gc_ref_update_table_values_only(tbl);
+ }
+ else {
+ rb_mark_tbl_no_pin(tbl);
+ }
+ }
+ else {
+ VALUE *fields = rb_imemo_fields_ptr(obj);
+ attr_index_t len = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (attr_index_t i = 0; i < len; i++) {
+ rb_gc_mark_and_move(&fields[i]);
+ }
+ }
+ }
+ break;
+ }
+ case imemo_cdhash: {
+ st_table *tbl = rb_imemo_cdhash_tbl(obj);
+ if (reference_updating) {
+ rb_gc_update_set_refs(tbl);
+ }
+ else {
+ rb_gc_mark_set_no_pin(tbl);
+ }
+ break;
+ }
default:
rb_bug("unreachable");
}
@@ -431,7 +629,7 @@ static enum rb_id_table_iterator_result
free_const_entry_i(VALUE value, void *data)
{
rb_const_entry_t *ce = (rb_const_entry_t *)value;
- xfree(ce);
+ SIZED_FREE(ce);
return ID_TABLE_CONTINUE;
}
@@ -442,61 +640,12 @@ rb_free_const_table(struct rb_id_table *tbl)
rb_id_table_free(tbl);
}
-// alive: if false, target pointers can be freed already.
-static void
-vm_ccs_free(struct rb_class_cc_entries *ccs, int alive, VALUE klass)
-{
- if (ccs->entries) {
- for (int i=0; i<ccs->len; i++) {
- const struct rb_callcache *cc = ccs->entries[i].cc;
- if (!alive) {
- // ccs can be free'ed.
- if (rb_gc_pointer_to_heap_p((VALUE)cc) &&
- !rb_objspace_garbage_object_p((VALUE)cc) &&
- IMEMO_TYPE_P(cc, imemo_callcache) &&
- cc->klass == klass) {
- // OK. maybe target cc.
- }
- else {
- continue;
- }
- }
-
- VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
- vm_cc_invalidate(cc);
- }
- ruby_xfree(ccs->entries);
- }
- ruby_xfree(ccs);
-}
-
-void
-rb_vm_ccs_free(struct rb_class_cc_entries *ccs)
-{
- RB_DEBUG_COUNTER_INC(ccs_free);
- vm_ccs_free(ccs, true, Qundef);
-}
-
-static enum rb_id_table_iterator_result
-cc_table_free_i(VALUE ccs_ptr, void *data)
-{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VALUE klass = (VALUE)data;
- VM_ASSERT(vm_ccs_p(ccs));
-
- vm_ccs_free(ccs, false, klass);
-
- return ID_TABLE_CONTINUE;
-}
-
-void
-rb_cc_table_free(VALUE klass)
+static inline void
+imemo_fields_free(struct rb_fields *fields)
{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
-
- if (cc_tbl) {
- rb_id_table_foreach_values(cc_tbl, cc_table_free_i, (void *)klass);
- rb_id_table_free(cc_tbl);
+ if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_HEAP)) {
+ RUBY_ASSERT(rb_shape_complex_p(RBASIC_SHAPE_ID((VALUE)fields)));
+ st_free_table(fields->as.complex.table);
}
}
@@ -504,10 +653,6 @@ void
rb_imemo_free(VALUE obj)
{
switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
case imemo_callcache:
RB_DEBUG_COUNTER_INC(obj_imemo_callcache);
@@ -516,8 +661,9 @@ rb_imemo_free(VALUE obj)
const struct rb_callinfo *ci = ((const struct rb_callinfo *)obj);
if (ci->kwarg) {
- ((struct rb_callinfo_kwarg *)ci->kwarg)->references--;
- if (ci->kwarg->references == 0) xfree((void *)ci->kwarg);
+ if (RUBY_ATOMIC_FETCH_SUB(((struct rb_callinfo_kwarg *)ci->kwarg)->references, 1) == 1) {
+ ruby_xfree_sized((void *)ci->kwarg, rb_callinfo_kwarg_bytes(ci->kwarg->keyword_len));
+ }
}
RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
@@ -535,7 +681,7 @@ rb_imemo_free(VALUE obj)
rb_env_t *env = (rb_env_t *)obj;
RUBY_ASSERT(VM_ENV_ESCAPED_P(env->ep));
- xfree((VALUE *)env->env);
+ SIZED_FREE_N(env->env, env->env_size);
RB_DEBUG_COUNTER_INC(obj_imemo_env);
break;
@@ -557,22 +703,41 @@ rb_imemo_free(VALUE obj)
RB_DEBUG_COUNTER_INC(obj_imemo_ment);
break;
- case imemo_parser_strterm:
- RB_DEBUG_COUNTER_INC(obj_imemo_parser_strterm);
-
- break;
case imemo_svar:
RB_DEBUG_COUNTER_INC(obj_imemo_svar);
+
break;
case imemo_throw_data:
RB_DEBUG_COUNTER_INC(obj_imemo_throw_data);
break;
case imemo_tmpbuf:
- xfree(((rb_imemo_tmpbuf_t *)obj)->ptr);
+ ruby_xfree_sized(((rb_imemo_tmpbuf_t *)obj)->ptr, ((rb_imemo_tmpbuf_t *)obj)->size);
RB_DEBUG_COUNTER_INC(obj_imemo_tmpbuf);
break;
+ case imemo_cvar_entry:
+ RB_DEBUG_COUNTER_INC(obj_imemo_cvar_entry);
+
+ break;
+ case imemo_fields:
+ imemo_fields_free(IMEMO_OBJ_FIELDS(obj));
+ RB_DEBUG_COUNTER_INC(obj_imemo_fields);
+
+ break;
+ case imemo_subclasses: {
+ if (FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP)) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ SIZED_FREE_N(subs->as.external, subs->capacity);
+ }
+ RB_DEBUG_COUNTER_INC(obj_imemo_subclasses);
+ break;
+ }
+ case imemo_cdhash:
+ st_free_embedded_table(rb_imemo_cdhash_tbl(obj));
+ RB_DEBUG_COUNTER_INC(obj_imemo_cdhash);
+
+ break;
default:
rb_bug("unreachable");
}
diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h
index 18072f4810..fcc48f532c 100644
--- a/include/ruby/atomic.h
+++ b/include/ruby/atomic.h
@@ -34,7 +34,7 @@
# include <sys/types.h> /* ssize_t */
#endif
-#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# pragma intrinsic(_InterlockedOr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
# include <atomic.h>
@@ -77,10 +77,35 @@ typedef unsigned int rb_atomic_t;
typedef LONG rb_atomic_t;
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
typedef unsigned int rb_atomic_t;
+#elif defined(HAVE_STDATOMIC_H)
+# include <stdatomic.h>
+typedef unsigned int rb_atomic_t;
#else
# error No atomic operation found
#endif
+/* Memory ordering constants */
+#if defined(HAVE_GCC_ATOMIC_BUILTINS)
+# define RBIMPL_ATOMIC_RELAXED __ATOMIC_RELAXED
+# define RBIMPL_ATOMIC_ACQUIRE __ATOMIC_ACQUIRE
+# define RBIMPL_ATOMIC_RELEASE __ATOMIC_RELEASE
+# define RBIMPL_ATOMIC_ACQ_REL __ATOMIC_ACQ_REL
+# define RBIMPL_ATOMIC_SEQ_CST __ATOMIC_SEQ_CST
+#elif defined(HAVE_STDATOMIC_H)
+# define RBIMPL_ATOMIC_RELAXED memory_order_relaxed
+# define RBIMPL_ATOMIC_ACQUIRE memory_order_acquire
+# define RBIMPL_ATOMIC_RELEASE memory_order_release
+# define RBIMPL_ATOMIC_ACQ_REL memory_order_acq_rel
+# define RBIMPL_ATOMIC_SEQ_CST memory_order_seq_cst
+#else
+/* Dummy values for unsupported platforms */
+# define RBIMPL_ATOMIC_RELAXED 0
+# define RBIMPL_ATOMIC_ACQUIRE 1
+# define RBIMPL_ATOMIC_RELEASE 2
+# define RBIMPL_ATOMIC_ACQ_REL 3
+# define RBIMPL_ATOMIC_SEQ_CST 4
+#endif
+
/**
* Atomically replaces the value pointed by `var` with the result of addition
* of `val` to the old value of `var`.
@@ -90,7 +115,7 @@ typedef unsigned int rb_atomic_t;
* @return What was stored in `var` before the addition.
* @post `var` holds `var + val`.
*/
-#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val))
+#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically replaces the value pointed by `var` with the result of
@@ -101,7 +126,7 @@ typedef unsigned int rb_atomic_t;
* @return What was stored in `var` before the subtraction.
* @post `var` holds `var - val`.
*/
-#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val))
+#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically replaces the value pointed by `var` with the result of
@@ -113,7 +138,7 @@ typedef unsigned int rb_atomic_t;
* @post `var` holds `var | val`.
* @note For portability, this macro can return void.
*/
-#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val))
+#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically replaces the value pointed by `var` with `val`. This is just an
@@ -124,7 +149,7 @@ typedef unsigned int rb_atomic_t;
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
-#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val))
+#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomic compare-and-swap. This stores `val` to `var` if and only if the
@@ -138,7 +163,7 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_CAS(var, oldval, newval) \
- rbimpl_atomic_cas(&(var), (oldval), (newval))
+ rbimpl_atomic_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomic load. This loads `var` with an atomic intrinsic and returns
@@ -147,7 +172,7 @@ typedef unsigned int rb_atomic_t;
* @param var A variable of ::rb_atomic_t
* @return What was stored in `var`j
*/
-#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var))
+#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
@@ -157,7 +182,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `val`.
*/
-#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_set(&(var), (val))
+#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type.
@@ -167,7 +192,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + val`.
*/
-#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val))
+#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_FETCH_SUB, except for the return type.
@@ -177,7 +202,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - val`.
*/
-#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val))
+#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically increments the value pointed by `var`.
@@ -186,7 +211,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + 1`.
*/
-#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var))
+#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically decrements the value pointed by `var`.
@@ -195,7 +220,19 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - 1`.
*/
-#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var))
+#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var), RBIMPL_ATOMIC_SEQ_CST)
+
+/**
+ * Identical to #RUBY_ATOMIC_FETCH_ADD, except it expects its arguments to be `size_t`.
+ * There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
+ * should be used for size related operations to support such platforms.
+ *
+ * @param var A variable of `size_t`.
+ * @param val Value to add.
+ * @return What was stored in `var` before the addition.
+ * @post `var` holds `var + val`.
+ */
+#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val) rbimpl_atomic_size_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_INC, except it expects its argument is `size_t`.
@@ -206,7 +243,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + 1`.
*/
-#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var))
+#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_DEC, except it expects its argument is `size_t`.
@@ -217,7 +254,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - 1`.
*/
-#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var))
+#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -231,7 +268,7 @@ typedef unsigned int rb_atomic_t;
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) \
- rbimpl_atomic_size_exchange(&(var), (val))
+ rbimpl_atomic_size_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `size_t`.
@@ -245,7 +282,7 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) \
- rbimpl_atomic_size_cas(&(var), (oldval), (newval))
+ rbimpl_atomic_size_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_ADD, except it expects its arguments are `size_t`.
@@ -257,7 +294,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + val`.
*/
-#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val))
+#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_SUB, except it expects its arguments are `size_t`.
@@ -269,7 +306,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - val`.
*/
-#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val))
+#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -288,7 +325,7 @@ typedef unsigned int rb_atomic_t;
* some pointers, most notably function pointers.
*/
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) \
- RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
+ RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val, RBIMPL_ATOMIC_SEQ_CST))
/**
* Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`.
@@ -299,7 +336,20 @@ typedef unsigned int rb_atomic_t;
* @return The value of `var` (without tearing)
*/
#define RUBY_ATOMIC_PTR_LOAD(var) \
- RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var))
+ RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var, RBIMPL_ATOMIC_SEQ_CST))
+
+/**
+* Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
+* `void*`. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
+* 64bit. This should be used for pointer related operations to support such
+* platforms.
+*
+* @param var A variable of `void*`.
+* @param val Value to set.
+* @post `var` holds `val`.
+*/
+#define RUBY_ATOMIC_PTR_SET(var, val) \
+ rbimpl_atomic_ptr_store((volatile void **)&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
@@ -313,7 +363,20 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \
- RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval)))
+ RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST))
+
+/**
+ * Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
+ * ::VALUE. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
+ * 64bit. This should be used for pointer related operations to support such
+ * platforms.
+ *
+ * @param var A variable of ::VALUE.
+ * @param val Value to set.
+ * @post `var` holds `val`.
+ */
+#define RUBY_ATOMIC_VALUE_SET(var, val) \
+ rbimpl_atomic_value_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -327,7 +390,7 @@ typedef unsigned int rb_atomic_t;
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) \
- rbimpl_atomic_value_exchange(&(var), (val))
+ rbimpl_atomic_value_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are ::VALUE.
@@ -341,19 +404,20 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_VALUE_CAS(var, oldval, newval) \
- rbimpl_atomic_value_cas(&(var), (oldval), (newval))
+ rbimpl_atomic_value_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
/** @cond INTERNAL_MACRO */
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_fetch_add(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_fetch_and_add(ptr, val);
@@ -370,6 +434,47 @@ rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
return atomic_add_int_nv(ptr, val) - val;
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
+#else
+# error Unsupported platform.
+#endif
+}
+
+/** @cond INTERNAL_MACRO */
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline size_t
+rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val, int memory_order)
+{
+ (void)memory_order;
+#if 0
+
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+ return __atomic_fetch_add(ptr, val, memory_order);
+
+#elif defined(HAVE_GCC_SYNC_BUILTINS)
+ return __sync_fetch_and_add(ptr, val);
+
+#elif defined(_WIN32)
+ return InterlockedExchangeAdd64(ptr, val);
+
+#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
+ /* Ditto for `atomic_add_int_nv`. */
+ RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
+ atomic_add_long(ptr, val);
+
+#elif defined(__sun) && defined(HAVE_ATOMIC_H)
+ RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
+
+ volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
+ rbimpl_atomic_fetch_add(tmp, val, memory_order);
+
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -379,8 +484,9 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
@@ -389,7 +495,7 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
* return value is not used, then compiles it into single `LOCK ADD`
* instruction.
*/
- __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_add_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
@@ -407,6 +513,9 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
atomic_add_int(ptr, val);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -416,12 +525,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
+rbimpl_atomic_size_add(volatile size_t *ptr, size_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_add_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
@@ -435,12 +545,17 @@ rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
atomic_add_long(ptr, val);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- rbimpl_atomic_add(tmp, val);
+ rbimpl_atomic_add(tmp, val, memory_order);
+
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -448,12 +563,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
+rbimpl_atomic_inc(volatile rb_atomic_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_add(ptr, 1);
+ rbimpl_atomic_add(ptr, 1, memory_order);
#elif defined(_WIN32)
InterlockedIncrement(ptr);
@@ -461,9 +577,11 @@ rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_inc_uint(ptr);
-#else
- rbimpl_atomic_add(ptr, 1);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_add(ptr, 1, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -471,12 +589,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_inc(volatile size_t *ptr)
+rbimpl_atomic_size_inc(volatile size_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_size_add(ptr, 1);
+ rbimpl_atomic_size_add(ptr, 1, memory_order);
#elif defined(_WIN64)
InterlockedIncrement64(ptr);
@@ -484,11 +603,16 @@ rbimpl_atomic_size_inc(volatile size_t *ptr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_inc_ulong(ptr);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
- rbimpl_atomic_size_add(ptr, 1);
+ rbimpl_atomic_size_add(ptr, 1, memory_order);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_size_add(ptr, 1, memory_order);
+
+#else
+# error Unsupported platform.
#endif
}
@@ -496,12 +620,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_fetch_sub(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_fetch_sub(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_fetch_and_sub(ptr, val);
@@ -516,6 +641,9 @@ rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
return atomic_add_int_nv(ptr, neg * val) + val;
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -525,12 +653,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_sub_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
@@ -543,6 +672,9 @@ rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
atomic_add_int(ptr, neg * val);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -552,12 +684,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
+rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_sub_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
@@ -571,12 +704,17 @@ rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
atomic_add_long(ptr, neg * val);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- rbimpl_atomic_sub(tmp, val);
+ rbimpl_atomic_sub(tmp, val, memory_order);
+
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_sub_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -584,12 +722,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
+rbimpl_atomic_dec(volatile rb_atomic_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_sub(ptr, 1);
+ rbimpl_atomic_sub(ptr, 1, memory_order);
#elif defined(_WIN32)
InterlockedDecrement(ptr);
@@ -597,9 +736,11 @@ rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_dec_uint(ptr);
-#else
- rbimpl_atomic_sub(ptr, 1);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_sub(ptr, 1, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -607,12 +748,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_dec(volatile size_t *ptr)
+rbimpl_atomic_size_dec(volatile size_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_size_sub(ptr, 1);
+ rbimpl_atomic_size_sub(ptr, 1, memory_order);
#elif defined(_WIN64)
InterlockedDecrement64(ptr);
@@ -620,11 +762,16 @@ rbimpl_atomic_size_dec(volatile size_t *ptr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_dec_ulong(ptr);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
- rbimpl_atomic_size_sub(ptr, 1);
+ rbimpl_atomic_size_sub(ptr, 1, memory_order);
+
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_size_sub(ptr, 1, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -632,59 +779,42 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_or_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_or_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_or_and_fetch(ptr, val);
-#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
_InterlockedOr(ptr, val);
-#elif defined(_WIN32) && defined(__GNUC__)
- /* This was for old MinGW. Maybe not needed any longer? */
- __asm__(
- "lock\n\t"
- "orl\t%1, %0"
- : "=m"(ptr)
- : "Ir"(val));
-
-#elif defined(_WIN32) && defined(_M_IX86)
- __asm mov eax, ptr;
- __asm mov ecx, val;
- __asm lock or [eax], ecx;
-
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_or_uint(ptr, val);
+#elif !defined(_WIN32) && defined(HAVE_STDATOMIC_H)
+ atomic_fetch_or_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
}
-/* Nobody uses this but for theoretical backwards compatibility... */
-#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
-{
- return rbimpl_atomic_or(var, val);
-}
-#endif
-
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_exchange_n(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
@@ -695,6 +825,9 @@ rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_swap_uint(ptr, val);
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_exchange_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -704,12 +837,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline size_t
-rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
+rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_exchange_n(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
@@ -720,13 +854,36 @@ rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_swap_ulong(ptr, val);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val);
+ const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val, memory_order);
return RBIMPL_CAST((size_t)ret);
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_exchange_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+
+#else
+# error Unsupported platform.
+#endif
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline void
+rbimpl_atomic_size_store(volatile size_t *ptr, size_t val, int memory_order)
+{
+ (void)memory_order;
+#if 0
+
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+ __atomic_store_n(ptr, val, memory_order);
+
+#else
+ rbimpl_atomic_size_exchange(ptr, val, memory_order);
+
#endif
}
@@ -734,8 +891,9 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
-rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
+rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(InterlockedExchangePointer)
@@ -752,7 +910,7 @@ rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
+ const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order);
return RBIMPL_CAST((void *)sret);
#endif
@@ -761,29 +919,56 @@ rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
+static inline void
+rbimpl_atomic_ptr_store(volatile void **ptr, void *val, int memory_order)
+{
+ RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
+
+ const size_t sval = RBIMPL_CAST((size_t)val);
+ volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
+ rbimpl_atomic_size_store(sptr, sval, memory_order);
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
static inline VALUE
-rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
+rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val, int memory_order)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
+ const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order);
return RBIMPL_CAST((VALUE)sret);
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
+static inline void
+rbimpl_atomic_value_store(volatile VALUE *ptr, VALUE val, int memory_order)
+{
+ RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
+
+ const size_t sval = RBIMPL_CAST((size_t)val);
+ volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
+ rbimpl_atomic_size_store(sptr, sval, memory_order);
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_load(volatile rb_atomic_t *ptr)
+rbimpl_atomic_load(volatile rb_atomic_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+ return __atomic_load_n(ptr, memory_order);
#else
- return rbimpl_atomic_fetch_add(ptr, 0);
+ return rbimpl_atomic_fetch_add(ptr, 0, memory_order);
#endif
}
@@ -791,16 +976,17 @@ 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)
+rbimpl_atomic_store(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_store_n(ptr, val, memory_order);
#else
/* Maybe std::atomic<rb_atomic_t>::store can be faster? */
- rbimpl_atomic_exchange(ptr, val);
+ rbimpl_atomic_exchange(ptr, val, memory_order);
#endif
}
@@ -809,56 +995,49 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval)
+rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval, int success_memorder, int failure_memorder)
{
+ (void)success_memorder;
+ (void)failure_memorder;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_compare_exchange_n(
- ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ ptr, &oldval, newval, 0, success_memorder, failure_memorder);
return oldval;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
-#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
return InterlockedCompareExchange(ptr, newval, oldval);
-#elif defined(_WIN32)
- PVOID *pptr = RBIMPL_CAST((PVOID *)ptr);
- PVOID pold = RBIMPL_CAST((PVOID)oldval);
- PVOID pnew = RBIMPL_CAST((PVOID)newval);
- PVOID pret = InterlockedCompareExchange(pptr, pnew, pold);
- return RBIMPL_CAST((rb_atomic_t)pret);
-
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_cas_uint(ptr, oldval, newval);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_compare_exchange_strong_explicit(
+ (_Atomic volatile rb_atomic_t *)ptr, &oldval, newval, success_memorder, failure_memorder);
+ return oldval;
+
#else
# error Unsupported platform.
#endif
}
-/* Nobody uses this but for theoretical backwards compatibility... */
-#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval)
-{
- return rbimpl_atomic_cas(var, oldval, newval);
-}
-#endif
-
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline size_t
-rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
+rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval, int success_memorder, int failure_memorder)
{
+ (void)success_memorder;
+ (void)failure_memorder;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_compare_exchange_n(
- ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ ptr, &oldval, newval, 0, success_memorder, failure_memorder);
return oldval;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
@@ -870,12 +1049,19 @@ rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_cas_ulong(ptr, oldval, newval);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- return rbimpl_atomic_cas(tmp, oldval, newval);
+ return rbimpl_atomic_cas(tmp, oldval, newval, success_memorder, failure_memorder);
+
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_compare_exchange_strong_explicit(
+ (_Atomic volatile size_t *)ptr, &oldval, newval, success_memorder, failure_memorder);
+ return oldval;
+#else
+# error Unsupported platform.
#endif
}
@@ -883,8 +1069,10 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
-rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
+rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval, int success_memorder, int failure_memorder)
{
+ (void)success_memorder;
+ (void)failure_memorder;
#if 0
#elif defined(InterlockedExchangePointer)
@@ -907,7 +1095,7 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
const size_t snew = RBIMPL_CAST((size_t)newval);
const size_t sold = RBIMPL_CAST((size_t)oldval);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
+ const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder);
return RBIMPL_CAST((void *)sret);
#endif
@@ -917,15 +1105,16 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
-rbimpl_atomic_ptr_load(void **ptr)
+rbimpl_atomic_ptr_load(void **ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+ return __atomic_load_n(ptr, memory_order);
#else
void *val = *ptr;
- return rbimpl_atomic_ptr_cas(ptr, val, val);
+ return rbimpl_atomic_ptr_cas(ptr, val, val, memory_order, memory_order);
#endif
}
@@ -933,14 +1122,23 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline VALUE
-rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval)
+rbimpl_atomic_value_load(volatile VALUE *ptr, int memory_order)
+{
+ return RBIMPL_CAST((VALUE)rbimpl_atomic_ptr_load((void **)ptr, memory_order));
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline VALUE
+rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval, int success_memorder, int failure_memorder)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
const size_t snew = RBIMPL_CAST((size_t)newval);
const size_t sold = RBIMPL_CAST((size_t)oldval);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
+ const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder);
return RBIMPL_CAST((VALUE)sret);
}
/** @endcond */
diff --git a/include/ruby/backward.h b/include/ruby/backward.h
index f804c2c36e..6726102158 100644
--- a/include/ruby/backward.h
+++ b/include/ruby/backward.h
@@ -11,12 +11,6 @@
#include "ruby/internal/interpreter.h"
#include "ruby/backward/2/attributes.h"
-#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) RBIMPL_ATTR_DEPRECATED(("since " #ver))
-#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
-#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() RBIMPL_ATTR_DEPRECATED(("only for internal use"))
-
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() void rb_clear_constant_cache(void);
-
/* from version.c */
#if defined(RUBY_SHOW_COPYRIGHT_TO_DIE) && !!(RUBY_SHOW_COPYRIGHT_TO_DIE+0)
# error RUBY_SHOW_COPYRIGHT_TO_DIE is deprecated
diff --git a/include/ruby/backward/2/rmodule.h b/include/ruby/backward/2/rmodule.h
index 53b37831c0..76c0936462 100644
--- a/include/ruby/backward/2/rmodule.h
+++ b/include/ruby/backward/2/rmodule.h
@@ -23,7 +23,7 @@
* who is implementing the internals) could have used those macros for a while.
* Kept public as-is here to keep some theoretical backwards compatibility.
*/
-#define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
+#define RMODULE_IV_TBL(m) RCLASS_FIELDS(m)
#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
#define RMODULE_SUPER(m) RCLASS_SUPER(m)
diff --git a/include/ruby/backward/cxxanyargs.hpp b/include/ruby/backward/cxxanyargs.hpp
index 2414b7ae6d..0ca2745c20 100644
--- a/include/ruby/backward/cxxanyargs.hpp
+++ b/include/ruby/backward/cxxanyargs.hpp
@@ -190,33 +190,6 @@ rb_define_hooked_variable(const char *q, VALUE *w, std::nullptr_t e, void_type *
/// @name Exceptions and tag jumps
/// @{
-// RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
-RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
-/// @brief Old way to implement iterators.
-/// @param[in] q A function that can yield.
-/// @param[in] w Passed to `q`.
-/// @param[in] e What is to be yielded.
-/// @param[in] r Passed to `e`.
-/// @return The return value of `q`.
-/// @note `e` can be nullptr.
-/// @deprecated This function is obsoleted since long before 2.x era. Do not
-/// use it any longer. rb_block_call() is provided instead.
-inline VALUE
-rb_iterate(onearg_type *q, VALUE w, type *e, VALUE r)
-{
- rb_block_call_func_t t = reinterpret_cast<rb_block_call_func_t>(e);
- return backward::rb_iterate_deprecated(q, w, t, r);
-}
-
-#ifdef HAVE_NULLPTR
-RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
-inline VALUE
-rb_iterate(onearg_type *q, VALUE w, std::nullptr_t e, VALUE r)
-{
- return backward::rb_iterate_deprecated(q, w, e, r);
-}
-#endif
-
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Call a method with a block.
/// @param[in] q The self.
@@ -537,9 +510,7 @@ struct driver {
* this writing the version is 2.8. Let's warn this later, some time
* during 3.x. Hopefully codes in old (ANYARGS-ed) format should be
* less than now. */
-#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) >= 301
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
-#endif
/// @copydoc define(VALUE klass, T mid, U func)
/// @deprecated Pass correctly typed function instead.
static inline void
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index 0a9f693951..27a7a5f2c1 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -297,7 +297,7 @@ VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
#define RB_DEBUG_INSPECTOR_FRAME_DEPTH(dc, index) rb_debug_inspector_frame_depth(dc, index)
/**
- * Return current frmae depth.
+ * Return current frame depth.
*
* @retval The depth of the current frame in Integer.
*/
@@ -754,59 +754,6 @@ rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_po
*/
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] 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.
- */
- 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`
- *
- * @param[in] flags Unused and ignored.
- * @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.
- */
- 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 b678bd0d1a..4d764f68ae 100644
--- a/include/ruby/fiber/scheduler.h
+++ b/include/ruby/fiber/scheduler.h
@@ -23,9 +23,11 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
-#define RUBY_FIBER_SCHEDULER_VERSION 2
+// Version 3: Adds support for `fiber_interrupt`.
+#define RUBY_FIBER_SCHEDULER_VERSION 3
struct timeval;
+struct rb_thread_struct;
/**
* Wrap a `ssize_t` and `int errno` into a single `VALUE`. This interface should
@@ -117,7 +119,7 @@ VALUE rb_fiber_scheduler_current(void);
/**
* Identical to rb_fiber_scheduler_current(), except it queries for that of the
- * passed thread instead of the implicit current one.
+ * passed thread value instead of the implicit current one.
*
* @param[in] thread Target thread.
* @exception rb_eTypeError `thread` is not a thread.
@@ -127,6 +129,17 @@ VALUE rb_fiber_scheduler_current(void);
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread);
/**
+ * Identical to rb_fiber_scheduler_current_for_thread(), except it expects
+ * a threadptr instead of a thread value.
+ *
+ * @param[in] thread Target thread.
+ * @exception rb_eTypeError `thread` is not a thread.
+ * @retval RUBY_Qnil No scheduler is in effect in `thread`.
+ * @retval otherwise The scheduler that is in effect in `thread`.
+ */
+VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread);
+
+/**
* Converts the passed timeout to an expression that rb_fiber_scheduler_block()
* etc. expects.
*
@@ -166,6 +179,14 @@ VALUE rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE duration);
*/
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv);
+/**
+ * Yield to the scheduler, to be resumed on the next scheduling cycle.
+ *
+ * @param[in] scheduler Target scheduler.
+ * @return What `scheduler.yield` returns.
+ */
+VALUE rb_fiber_scheduler_yield(VALUE scheduler);
+
/* Description TBW */
#if 0
VALUE rb_fiber_scheduler_timeout_after(VALUE scheduler, VALUE timeout, VALUE exception, VALUE message);
@@ -199,6 +220,8 @@ VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout);
/**
* Wakes up a fiber previously blocked using rb_fiber_scheduler_block().
*
+ * This function may be called from a different thread.
+ *
* @param[in] scheduler Target scheduler.
* @param[in] blocker What was awaited for.
* @param[in] fiber What to unblock.
@@ -391,11 +414,54 @@ VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io);
*/
VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname);
+// The state of the blocking operation execution.
struct rb_fiber_scheduler_blocking_operation_state {
void *result;
int saved_errno;
};
+// The opaque handle for the blocking operation.
+typedef struct rb_fiber_scheduler_blocking_operation rb_fiber_scheduler_blocking_operation_t;
+
+/**
+ * Extract the blocking operation handle from a BlockingOperationRuby object.
+ *
+ * This function safely extracts the opaque handle from a BlockingOperation VALUE
+ * while holding the GVL. The returned pointer can be passed to worker threads
+ * and used with rb_fiber_scheduler_blocking_operation_execute.
+ *
+ * @param[in] self The BlockingOperation VALUE to extract from
+ * @return The opaque struct pointer on success, NULL on error
+ * @note Experimental.
+ */
+rb_fiber_scheduler_blocking_operation_t *rb_fiber_scheduler_blocking_operation_extract(VALUE self);
+
+/**
+ * Execute blocking operation from handle (GVL not required).
+ *
+ * This function executes a blocking operation using the opaque handle
+ * obtained from rb_fiber_scheduler_blocking_operation_extract.
+ * It can be called from native threads without holding the GVL.
+ *
+ * @param[in] blocking_operation The opaque handle.
+ * @return 0 on success, -1 on error.
+ * @note Experimental. Can be called from any thread without holding the GVL
+ */
+int rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
+
+/**
+ * Cancel a blocking operation.
+ *
+ * This function cancels a blocking operation. If the operation is queued,
+ * it just marks it as cancelled. If it's executing, it marks it as cancelled
+ * and calls the unblock function to interrupt the operation.
+ *
+ * @param blocking_operation The opaque struct pointer
+ * @return 1 if unblock function was called, 0 if just marked cancelled, -1 on error
+ * @note Experimental.
+ */
+int rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
+
/**
* Defer the execution of the passed function to the scheduler.
*
@@ -412,8 +478,25 @@ struct rb_fiber_scheduler_blocking_operation_state {
VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*function)(void *), void *data, rb_unblock_function_t *unblock_function, void *data2, int flags, struct rb_fiber_scheduler_blocking_operation_state *state);
/**
+ * Interrupt a fiber by raising an exception. You can construct an exception using `rb_make_exception`.
+ *
+ * This hook may be invoked by a different thread.
+ *
+ * @param[in] scheduler Target scheduler.
+ * @param[in] fiber The fiber to interrupt.
+ * @param[in] exception The exception to raise in the fiber.
+ * @return What `scheduler.fiber_interrupt` returns.
+ */
+VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exception);
+
+/**
* Create and schedule a non-blocking fiber.
*
+ * @param[in] scheduler Target scheduler.
+ * @param[in] argc Number of arguments in argv.
+ * @param[in] argv Array of arguments to pass to the fiber.
+ * @param[in] kw_splat Whether to expand last argument as keywords.
+ * @return The created and scheduled fiber.
*/
VALUE rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat);
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 48e4cd546e..8718169ce2 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -51,6 +51,7 @@
#include "ruby/internal/intern/re.h"
#include "ruby/internal/intern/ruby.h"
#include "ruby/internal/intern/select.h"
+#include "ruby/internal/intern/set.h"
#include "ruby/internal/intern/signal.h"
#include "ruby/internal/intern/sprintf.h"
#include "ruby/internal/intern/string.h"
diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h
index e735a67564..7ceb8c40b7 100644
--- a/include/ruby/internal/abi.h
+++ b/include/ruby/internal/abi.h
@@ -24,7 +24,7 @@
* In released versions of Ruby, this number is not defined since teeny
* versions of Ruby should guarantee ABI compatibility.
*/
-#define RUBY_ABI_VERSION 0
+#define RUBY_ABI_VERSION 3
/* Windows does not support weak symbols so ruby_abi_version will not exist
* in the shared library. */
diff --git a/include/ruby/internal/anyargs.h b/include/ruby/internal/anyargs.h
index e3e1b6166d..e4c6d155cc 100644
--- a/include/ruby/internal/anyargs.h
+++ b/include/ruby/internal/anyargs.h
@@ -84,12 +84,15 @@
#elif defined(_WIN32) || defined(__CYGWIN__)
# /* Skip due to [Bug #16134] */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! RBIMPL_HAS_ATTRIBUTE(transparent_union)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! defined(HAVE_VA_ARGS_MACRO)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#else
# /** @cond INTERNAL_MACRO */
@@ -348,6 +351,25 @@ RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *)
#endif /* __cplusplus */
+#if defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus)
+/* In C23, K&R style prototypes are gone and so `void foo(ANYARGS)` became
+ * equivalent to `void foo(void)` unlike in earlier versions. This is a problem
+ * for rb_define_* functions since that makes all valid functions one can pass
+ * trip -Wincompatible-pointer-types, which we treat as errors. This is mostly
+ * not a problem for the __builtin_choose_expr path, but outside of that we
+ * need to add a cast for compatibility.
+ */
+#define rb_define_method(klass, mid, func, arity) rb_define_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_method_id(klass, mid, func, arity) rb_define_method_id((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_singleton_method(obj, mid, func, arity) rb_define_singleton_method((obj), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_protected_method(klass, mid, func, arity) rb_define_protected_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_private_method(klass, mid, func, arity) rb_define_private_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_module_function(mod, mid, func, arity) rb_define_module_function((mod), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_global_function(mid, func, arity) rb_define_global_function((mid), (VALUE (*)(ANYARGS))(func), (arity))
+
+#undef RBIMPL_CAST_FN_PTR
+#endif /* defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus) */
+
/**
* This macro is to properly cast a function parameter of *_define_method
* family. It has been around since 1.x era so you can maximise backwards
diff --git a/include/ruby/internal/arithmetic/intptr_t.h b/include/ruby/internal/arithmetic/intptr_t.h
index a354f4469c..70090f88e6 100644
--- a/include/ruby/internal/arithmetic/intptr_t.h
+++ b/include/ruby/internal/arithmetic/intptr_t.h
@@ -32,6 +32,18 @@
#define rb_int_new rb_int2inum /**< @alias{rb_int2inum} */
#define rb_uint_new rb_uint2inum /**< @alias{rb_uint2inum} */
+// These definitions are same as fiddle/conversions.h
+#if SIZEOF_VOIDP <= SIZEOF_LONG
+# define PTR2NUM(x) (LONG2NUM((long)(x)))
+# define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
+#elif SIZEOF_VOIDP <= SIZEOF_LONG_LONG
+# define PTR2NUM(x) (LL2NUM((LONG_LONG)(x)))
+# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
+#else
+// should have been an error in ruby/internal/value.h
+# error Need integer for VALUE
+#endif
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
diff --git a/include/ruby/internal/attr/deprecated.h b/include/ruby/internal/attr/deprecated.h
index e1bbdbd15a..a374ace868 100644
--- a/include/ruby/internal/attr/deprecated.h
+++ b/include/ruby/internal/attr/deprecated.h
@@ -48,7 +48,7 @@
#elif RBIMPL_HAS_ATTRIBUTE(deprecated) /* but not with message. */
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_DEPRECATED(msg) __declspec(deprecated msg)
#elif RBIMPL_HAS_DECLSPEC_ATTRIBUTE(deprecated)
@@ -72,4 +72,11 @@
# define RBIMPL_ATTR_DEPRECATED_EXT(msg) RBIMPL_ATTR_DEPRECATED(msg)
#endif
+#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) \
+ RBIMPL_ATTR_DEPRECATED(("since " #ver))
+#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) \
+ RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
+#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() \
+ RBIMPL_ATTR_DEPRECATED(("only for internal use"))
+
#endif /* RBIMPL_ATTR_DEPRECATED_H */
diff --git a/include/ruby/internal/attr/forceinline.h b/include/ruby/internal/attr/forceinline.h
index b7daafede7..5b9ae794af 100644
--- a/include/ruby/internal/attr/forceinline.h
+++ b/include/ruby/internal/attr/forceinline.h
@@ -29,7 +29,7 @@
* `__forceinline` are mutually exclusive. We have to mimic that behaviour for
* non-MSVC compilers.
*/
-#if RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_FORCEINLINE() __forceinline
#elif RBIMPL_HAS_ATTRIBUTE(always_inline)
# define RBIMPL_ATTR_FORCEINLINE() __attribute__((__always_inline__)) inline
diff --git a/include/ruby/internal/attr/format.h b/include/ruby/internal/attr/format.h
index b3488ee00a..7feff1c846 100644
--- a/include/ruby/internal/attr/format.h
+++ b/include/ruby/internal/attr/format.h
@@ -22,6 +22,10 @@
*/
#include "ruby/internal/has/attribute.h"
+#if defined(__MINGW32__)
+#include <stdio.h> /* for __MINGW_PRINTF_FORMAT */
+#endif
+
/** Wraps (or simulates) `__attribute__((format))` */
#if RBIMPL_HAS_ATTRIBUTE(format)
# define RBIMPL_ATTR_FORMAT(x, y, z) __attribute__((__format__(x, y, z)))
diff --git a/include/ruby/internal/attr/noexcept.h b/include/ruby/internal/attr/noexcept.h
index 7c3f92f1e7..dd4c667407 100644
--- a/include/ruby/internal/attr/noexcept.h
+++ b/include/ruby/internal/attr/noexcept.h
@@ -78,7 +78,7 @@
#elif defined(__INTEL_CXX11_MODE__)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 19, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif __cplusplus >= 201103L
diff --git a/include/ruby/internal/attr/nonstring.h b/include/ruby/internal/attr/nonstring.h
new file mode 100644
index 0000000000..da2501f7bf
--- /dev/null
+++ b/include/ruby/internal/attr/nonstring.h
@@ -0,0 +1,40 @@
+#ifndef RBIMPL_ATTR_NONSTRING_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_ATTR_NONSTRING_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Defines #RBIMPL_ATTR_NONSTRING.
+ */
+#include "ruby/internal/has/attribute.h"
+
+/** Wraps (or simulates) `__attribute__((nonstring))` */
+#if RBIMPL_HAS_ATTRIBUTE(nonstring)
+# define RBIMPL_ATTR_NONSTRING() __attribute__((nonstring))
+# if RBIMPL_COMPILER_SINCE(GCC, 15, 0, 0)
+# define RBIMPL_ATTR_NONSTRING_ARRAY() RBIMPL_ATTR_NONSTRING()
+# elif defined(__clang_major__) && __clang_major__ >= 21
+# define RBIMPL_ATTR_NONSTRING_ARRAY() RBIMPL_ATTR_NONSTRING()
+# else
+# define RBIMPL_ATTR_NONSTRING_ARRAY() /* void */
+# endif
+#else
+# define RBIMPL_ATTR_NONSTRING() /* void */
+# define RBIMPL_ATTR_NONSTRING_ARRAY() /* void */
+#endif
+
+#endif /* RBIMPL_ATTR_NONSTRING_H */
diff --git a/include/ruby/internal/attr/restrict.h b/include/ruby/internal/attr/restrict.h
index e39104138c..b12fdc9dbc 100644
--- a/include/ruby/internal/attr/restrict.h
+++ b/include/ruby/internal/attr/restrict.h
@@ -28,7 +28,7 @@
* `__has_declspec_attribute()` which involves macro substitution. */
/** Wraps (or simulates) `__declspec(restrict)` */
-#if RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_RESTRICT() __declspec(re ## strict)
#elif RBIMPL_HAS_ATTRIBUTE(malloc)
diff --git a/include/ruby/internal/compiler_is/msvc.h b/include/ruby/internal/compiler_is/msvc.h
index 8a864ea558..824f0ecc21 100644
--- a/include/ruby/internal/compiler_is/msvc.h
+++ b/include/ruby/internal/compiler_is/msvc.h
@@ -38,19 +38,8 @@
# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 10000000 / 100000)
# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 100000)
-#elif defined(_MSC_FULL_VER)
-# define RBIMPL_COMPILER_IS_MSVC 1
-# /* _MSC_FULL_VER = XXYYZZZZ */
-# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_FULL_VER / 1000000)
-# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 1000000 / 10000)
-# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 10000)
-
#else
-# define RBIMPL_COMPILER_IS_MSVC 1
-# /* _MSC_VER = XXYY */
-# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_VER / 100)
-# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_VER % 100)
-# define RBIMPL_COMPILER_VERSION_PATCH 0
+# error Unsupported MSVC version
#endif
#endif /* RBIMPL_COMPILER_IS_MSVC_H */
diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h
index da070f0979..34862ded6e 100644
--- a/include/ruby/internal/config.h
+++ b/include/ruby/internal/config.h
@@ -50,7 +50,7 @@
# define HAVE_VA_ARGS_MACRO
# elif defined(__INTEL_CXX11_MODE__)
# define HAVE_VA_ARGS_MACRO
-# elif RBIMPL_COMPILER_SINCE(MSVC, 16, 0, 0)
+# elif RBIMPL_COMPILER_IS(MSVC)
# define HAVE_VA_ARGS_MACRO
# else
# /* NG, not known. */
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h
index 73cc0f5dd9..b47b63d51b 100644
--- a/include/ruby/internal/core/rarray.h
+++ b/include/ruby/internal/core/rarray.h
@@ -367,7 +367,7 @@ RARRAY_PTR(VALUE ary)
{
RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
- VALUE tmp = RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary);
+ VALUE tmp = RB_OBJ_WB_UNPROTECT(ary);
return RBIMPL_CAST((VALUE *)RARRAY_CONST_PTR(tmp));
}
diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h
index a1477e2600..63cdff8e09 100644
--- a/include/ruby/internal/core/rbasic.h
+++ b/include/ruby/internal/core/rbasic.h
@@ -55,6 +55,12 @@ enum ruby_rvalue_flags {
RVALUE_EMBED_LEN_MAX = RBIMPL_RVALUE_EMBED_LEN_MAX
};
+#if (SIZEOF_VALUE < SIZEOF_UINT64_T)
+#define RBASIC_SHAPE_ID_FIELD 1
+#else
+#define RBASIC_SHAPE_ID_FIELD 0
+#endif
+
/**
* Ruby object's base components. All Ruby objects have them in common.
*/
@@ -85,6 +91,10 @@ RBasic {
*/
const VALUE klass;
+#if RBASIC_SHAPE_ID_FIELD
+ VALUE shape_id;
+#endif
+
#ifdef __cplusplus
public:
RBIMPL_ATTR_CONSTEXPR(CXX11)
@@ -100,8 +110,14 @@ RBasic {
RBasic() :
flags(RBIMPL_VALUE_NULL),
klass(RBIMPL_VALUE_NULL)
+#if RBASIC_SHAPE_ID_FIELD
+ , shape_id(RBIMPL_VALUE_NULL)
+#endif
{
}
+# define RBASIC_INIT RBasic()
+#else
+# define RBASIC_INIT {RBIMPL_VALUE_NULL}
#endif
};
diff --git a/include/ruby/internal/core/rclass.h b/include/ruby/internal/core/rclass.h
index b0b6bfc80c..6f78cc569b 100644
--- a/include/ruby/internal/core/rclass.h
+++ b/include/ruby/internal/core/rclass.h
@@ -58,7 +58,7 @@ enum ruby_rmodule_flags {
* rb_mod_refine() has this flag set. This is the bit which controls
* difference between normal inclusion versus refinements.
*/
- RMODULE_IS_REFINEMENT = RUBY_FL_USER3
+ RMODULE_IS_REFINEMENT = RUBY_FL_USER1
};
struct RClass; /* Opaque, declared here for RCLASS() macro. */
diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h
index e4c146a716..d0a4dc7c83 100644
--- a/include/ruby/internal/core/rdata.h
+++ b/include/ruby/internal/core/rdata.h
@@ -42,31 +42,9 @@
#endif
#define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f))
-#define RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() \
- RBIMPL_ATTR_WARNING(("untyped Data is unsafe; use TypedData instead")) \
- RBIMPL_ATTR_DEPRECATED(("by TypedData"))
-
-#define RBIMPL_MACRO_SELECT(x, y) x ## y
-#define RUBY_MACRO_SELECT(x, y) RBIMPL_MACRO_SELECT(x, y)
/** @endcond */
/**
- * Convenient casting macro.
- *
- * @param obj An object, which is in fact an ::RData.
- * @return The passed object casted to ::RData.
- */
-#define RDATA(obj) RBIMPL_CAST((struct RData *)(obj))
-
-/**
- * Convenient getter macro.
- *
- * @param obj An object, which is in fact an ::RData.
- * @return The passed object's ::RData::data field.
- */
-#define DATA_PTR(obj) RDATA(obj)->data
-
-/**
* This is a value you can set to ::RData::dfree. Setting this means the data
* was allocated using ::ruby_xmalloc() (or variants), and shall be freed using
* ::ruby_xfree().
@@ -85,19 +63,6 @@
#define RUBY_NEVER_FREE RBIMPL_DATA_FUNC(0)
/**
- * @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 RUBY_UNTYPED_DATA_FUNC(f) f RBIMPL_ATTRSET_UNTYPED_DATA_FUNC()
-
-/*
-#define RUBY_DATA_FUNC(func) ((void (*)(void*))(func))
-*/
-
-/**
* This is the type of callbacks registered to ::RData. The argument is the
* `data` field.
*/
@@ -106,268 +71,16 @@ typedef void (*RUBY_DATA_FUNC)(void*);
/**
* @deprecated
*
- * Old "untyped" user data. It has roughly the same usage as struct
- * ::RTypedData, but lacked several features such as support for compaction GC.
- * Use of this struct is not recommended any longer. If it is dead necessary,
- * please inform the core devs about your usage.
- *
- * @internal
- *
- * @shyouhei tried to add RBIMPL_ATTR_DEPRECATED for this type but that yielded
- * too many warnings in the core. Maybe we want to retry later... Just add
- * deprecated document for now.
+ * DO NOT USE: Obsolete "untyped" user data, that is remained only for
+ * the backward compatibility for some wrapper generator gems.
*/
struct RData {
-
- /** Basic part, including flags and class. */
struct RBasic basic;
-
- /**
- * This function is called when the object is experiencing GC marks. If it
- * contains references to other Ruby objects, you need to mark them also.
- * Otherwise GC will smash your data.
- *
- * @see rb_gc_mark()
- * @warning This is called during GC runs. Object allocations are
- * impossible at that moment (that is why GC runs).
- */
+ VALUE fields_obj;
+ VALUE _reserved;
+ void *data;
RUBY_DATA_FUNC dmark;
-
- /**
- * This function is called when the object is no longer used. You need to
- * do whatever necessary to avoid memory leaks.
- *
- * @warning This is called during GC runs. Object allocations are
- * impossible at that moment (that is why GC runs).
- */
RUBY_DATA_FUNC dfree;
-
- /** Pointer to the actual C level struct that you want to wrap. */
- void *data;
};
-RBIMPL_SYMBOL_EXPORT_BEGIN()
-
-/**
- * This is the primitive way to wrap an existing C struct into ::RData.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] datap Pointer to the target C struct.
- * @param[in] dmark Mark function.
- * @param[in] dfree Free function.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return An allocated object that wraps `datap`.
- */
-VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree);
-
-/**
- * Identical to rb_data_object_wrap(), except it allocates a new data region
- * internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense to pass anything other than
- * ::RUBY_DEFAULT_FREE to the last argument.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] size Requested size of memory to allocate.
- * @param[in] dmark Mark function.
- * @param[in] dfree Free function.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return An allocated object that wraps a new `size` byte region.
- */
-VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree);
-
-/**
- * @private
- * Documented in include/ruby/internal/globals.h
- */
-RUBY_EXTERN VALUE rb_cObject;
-RBIMPL_SYMBOL_EXPORT_END()
-
-/**
- * Converts sval, a pointer to your struct, into a Ruby object.
- *
- * @param klass A ruby level class.
- * @param mark Mark function.
- * @param free Free function.
- * @param sval A pointer to your struct.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return A created Ruby object.
- */
-#define Data_Wrap_Struct(klass, mark, free, sval) \
- rb_data_object_wrap( \
- (klass), \
- (sval), \
- RBIMPL_DATA_FUNC(mark), \
- RBIMPL_DATA_FUNC(free))
-
-/**
- * @private
- *
- * This is an implementation detail of #Data_Make_Struct. People don't use it
- * directly.
- *
- * @param result Variable name of created Ruby object.
- * @param klass Ruby level class of the object.
- * @param type Type name of the C struct.
- * @param size Size of the C struct.
- * @param mark Mark function.
- * @param free Free function.
- * @param sval Variable name of created C struct.
- */
-#define Data_Make_Struct0(result, klass, type, size, mark, free, sval) \
- VALUE result = rb_data_object_zalloc( \
- (klass), \
- (size), \
- RBIMPL_DATA_FUNC(mark), \
- RBIMPL_DATA_FUNC(free)); \
- (sval) = RBIMPL_CAST((type *)DATA_PTR(result)); \
- RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
-
-/**
- * Identical to #Data_Wrap_Struct, except it allocates a new data region
- * internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense to pass anything other than
- * ::RUBY_DEFAULT_FREE to the `free` argument.
- *
- * @param klass Ruby level class of the returning object.
- * @param type Type name of the C struct.
- * @param mark Mark function.
- * @param free Free function.
- * @param sval Variable name of created C struct.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return A created Ruby object.
- */
-#ifdef HAVE_STMT_AND_DECL_IN_EXPR
-#define Data_Make_Struct(klass, type, mark, free, sval) \
- RB_GNUC_EXTENSION({ \
- Data_Make_Struct0( \
- data_struct_obj, \
- klass, \
- type, \
- sizeof(type), \
- mark, \
- free, \
- sval); \
- data_struct_obj; \
- })
-#else
-#define Data_Make_Struct(klass, type, mark, free, sval) \
- rb_data_object_make( \
- (klass), \
- RBIMPL_DATA_FUNC(mark), \
- RBIMPL_DATA_FUNC(free), \
- RBIMPL_CAST((void **)&(sval)), \
- sizeof(type))
-#endif
-
-/**
- * Obtains a C struct from inside of a wrapper Ruby object.
- *
- * @param obj An instance of ::RData.
- * @param type Type name of the C struct.
- * @param sval Variable name of obtained C struct.
- * @return Unwrapped C struct that `obj` holds.
- */
-#define Data_Get_Struct(obj, type, sval) \
- ((sval) = RBIMPL_CAST((type*)rb_data_object_get(obj)))
-
-RBIMPL_ATTRSET_UNTYPED_DATA_FUNC()
-/**
- * @private
- *
- * This is an implementation detail of rb_data_object_wrap(). People don't use
- * it directly.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] ptr Pointer to the target C struct.
- * @param[in] mark Mark function.
- * @param[in] free Free function.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return An allocated object that wraps `datap`.
- */
-static inline VALUE
-rb_data_object_wrap_warning(VALUE klass, void *ptr, RUBY_DATA_FUNC mark, RUBY_DATA_FUNC free)
-{
- return rb_data_object_wrap(klass, ptr, mark, free);
-}
-
-/**
- * @private
- *
- * This is an implementation detail of #Data_Get_Struct. People don't use it
- * directly.
- *
- * @param[in] obj An instance of ::RData.
- * @return Unwrapped C struct that `obj` holds.
- */
-static inline void *
-rb_data_object_get(VALUE obj)
-{
- Check_Type(obj, RUBY_T_DATA);
- return DATA_PTR(obj);
-}
-
-RBIMPL_ATTRSET_UNTYPED_DATA_FUNC()
-/**
- * @private
- *
- * This is an implementation detail of #Data_Get_Struct. People don't use it
- * directly.
- *
- * @param[in] obj An instance of ::RData.
- * @return Unwrapped C struct that `obj` holds.
- */
-static inline void *
-rb_data_object_get_warning(VALUE obj)
-{
- return rb_data_object_get(obj);
-}
-
-/**
- * This is an implementation detail of #Data_Make_Struct. People don't use it
- * directly.
- *
- * @param[in] klass Ruby level class of the returning object.
- * @param[in] mark_func Mark function.
- * @param[in] free_func Free function.
- * @param[in] datap Variable of created C struct.
- * @param[in] size Requested size of allocation.
- * @exception rb_eTypeError `klass` is not a class.
- * @exception rb_eNoMemError Out of memory.
- * @return A created Ruby object.
- * @post `*datap` holds the created C struct.
- */
-static inline VALUE
-rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_func, void **datap, size_t size)
-{
- Data_Make_Struct0(result, klass, void, size, mark_func, free_func, *datap);
- return result;
-}
-
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_object_wrap"))
-/** @deprecated This function was renamed to rb_data_object_wrap(). */
-static inline VALUE
-rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- return rb_data_object_wrap(klass, data, dmark, dfree);
-}
-
-/** @cond INTERNAL_MACRO */
-#define rb_data_object_wrap_0 rb_data_object_wrap
-#define rb_data_object_wrap_1 rb_data_object_wrap_warning
-#define rb_data_object_wrap_2 rb_data_object_wrap_ /* Used here vvvv */
-#define rb_data_object_wrap RUBY_MACRO_SELECT(rb_data_object_wrap_2, RUBY_UNTYPED_DATA_WARNING)
-#define rb_data_object_get_0 rb_data_object_get
-#define rb_data_object_get_1 rb_data_object_get_warning
-#define rb_data_object_get_2 rb_data_object_get_ /* Used here vvvv */
-#define rb_data_object_get RUBY_MACRO_SELECT(rb_data_object_get_2, RUBY_UNTYPED_DATA_WARNING)
-#define rb_data_object_make_0 rb_data_object_make
-#define rb_data_object_make_1 rb_data_object_make_warning
-#define rb_data_object_make_2 rb_data_object_make_ /* Used here vvvv */
-#define rb_data_object_make RUBY_MACRO_SELECT(rb_data_object_make_2, RUBY_UNTYPED_DATA_WARNING)
-/** @endcond */
#endif /* RBIMPL_RDATA_H */
diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h
index a528c2999e..ae93755531 100644
--- a/include/ruby/internal/core/rmatch.h
+++ b/include/ruby/internal/core/rmatch.h
@@ -67,23 +67,6 @@ struct rmatch_offset {
long end; /**< End of a group. */
};
-/** Represents a match. */
-struct rb_matchext_struct {
- /**
- * "Registers" of a match. This is a quasi-opaque struct that holds
- * execution result of a match. Roughly resembles `&~`.
- */
- struct re_registers regs;
-
- /** Capture group offsets, in C array. */
- struct rmatch_offset *char_offset;
-
- /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */
- 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.
@@ -107,12 +90,41 @@ struct RMatch {
* The expression of this match.
*/
VALUE regexp; /* RRegexp */
+
+ /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */
+ int char_offset_num_allocated;
+
+ /** Capture group offsets, in C array. */
+ struct rmatch_offset *char_offset;
+
+ /** Number of capture-group registers. */
+ int num_regs;
+
+ /** Capacity of `as.embed`, in OnigPosition slots. */
+ int capa;
+
+ /**
+ * "Registers" of a match. This is a quasi-opaque struct that holds
+ * execution result of a match. Roughly resembles `$~`.
+ */
+ union {
+ OnigPosition embed[1];
+ struct re_registers onig;
+ } as;
};
-#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch)))
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+/**
+ * @private
+ *
+ * Converts an embedded match to onig form. This is an implementation
+ * detail of #RMATCH_REGS. People don't use it directly.
+ *
+ * @param[out] match A match object, possibly in embedded form.
+ */
+void rb_match_ensure_onig(VALUE match);
+RBIMPL_SYMBOL_EXPORT_END()
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the raw ::re_registers.
*
@@ -138,7 +150,8 @@ static inline struct re_registers *
RMATCH_REGS(VALUE match)
{
RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH);
- return &RMATCH_EXT(match)->regs;
+ rb_match_ensure_onig(match);
+ return &RMATCH(match)->as.onig;
}
#endif /* RBIMPL_RMATCH_H */
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index 1f2b7168b8..df1901eb1e 100644
--- a/include/ruby/internal/core/robject.h
+++ b/include/ruby/internal/core/robject.h
@@ -42,10 +42,10 @@
*/
#define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj))
/** @cond INTERNAL_MACRO */
-#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
-#define ROBJECT_EMBED ROBJECT_EMBED
-#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY
-#define ROBJECT_IVPTR ROBJECT_IVPTR
+#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
+#define ROBJECT_HEAP ROBJECT_HEAP
+#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY
+#define ROBJECT_FIELDS ROBJECT_FIELDS
/** @endcond */
/**
@@ -55,10 +55,12 @@
*/
enum ruby_robject_flags {
/**
- * This flag has something to do with memory footprint. If the object is
- * "small" enough, ruby tries to be creative to abuse padding bits of
- * struct ::RObject for storing instance variables. This flag denotes that
- * situation.
+ * This flag marks that the object's instance variables are stored in an
+ * external heap buffer.
+ * Normally, instance variable references are stored inside the object slot,
+ * but if it overflow, Ruby may have to allocate a separate buffer and spills
+ * the instance variables there.
+ * This flag denotes that situation.
*
* @warning This bit has to be considered read-only. Setting/clearing
* this bit without corresponding fix up must cause immediate
@@ -71,7 +73,7 @@ enum ruby_robject_flags {
* 3rd parties must not be aware that there even is more than one way to
* store instance variables. Might better be hidden.
*/
- ROBJECT_EMBED = RUBY_FL_USER1
+ ROBJECT_HEAP = RUBY_FL_USER4
};
struct st_table;
@@ -94,9 +96,14 @@ struct RObject {
*/
struct {
/** Pointer to a C array that holds instance variables. */
- VALUE *ivptr;
+ VALUE *fields;
} heap;
+ /* When an object is too complex, it uses a st_table to store instance
+ * variable name to value mappings.
+ */
+ st_table *hash;
+
/* Embedded instance variables. When an object is small enough, it
* uses this area to store the instance variables.
*
@@ -123,17 +130,17 @@ RBIMPL_ATTR_ARTIFICIAL()
* @shyouhei finds no reason for this to be visible from extension libraries.
*/
static inline VALUE *
-ROBJECT_IVPTR(VALUE obj)
+ROBJECT_FIELDS(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
struct RObject *const ptr = ROBJECT(obj);
- if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) {
- return ptr->as.ary;
+ if (RB_UNLIKELY(RB_FL_ANY_RAW(obj, ROBJECT_HEAP))) {
+ return ptr->as.heap.fields;
}
else {
- return ptr->as.heap.ivptr;
+ return ptr->as.ary;
}
}
diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h
index 0bca74e688..35175ea94a 100644
--- a/include/ruby/internal/core/rstring.h
+++ b/include/ruby/internal/core/rstring.h
@@ -369,41 +369,6 @@ RSTRING_LEN(VALUE str)
return RSTRING(str)->len;
}
-RBIMPL_WARNING_PUSH()
-#if RBIMPL_COMPILER_IS(Intel)
-RBIMPL_WARNING_IGNORED(413)
-#endif
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * @private
- *
- * "Expands" an embedded string into an ordinal one. This is a function that
- * returns aggregated type. The returned struct always has its `as.heap.len`
- * an `as.heap.ptr` fields set appropriately.
- *
- * This is an implementation detail that 3rd parties should never bother.
- */
-static inline struct RString
-rbimpl_rstring_getmem(VALUE str)
-{
- RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING);
-
- if (RB_FL_ANY_RAW(str, RSTRING_NOEMBED)) {
- return *RSTRING(str);
- }
- else {
- /* Expecting compilers to optimize this on-stack struct away. */
- struct RString retval;
- retval.len = RSTRING_LEN(str);
- retval.as.heap.ptr = RSTRING(str)->as.embed.ary;
- return retval;
- }
-}
-
-RBIMPL_WARNING_POP()
-
RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the contents pointer of the string.
@@ -415,7 +380,9 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_PTR(VALUE str)
{
- char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr;
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) {
/* :BEWARE: @shyouhei thinks that currently, there are rooms for this
@@ -441,14 +408,17 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_END(VALUE str)
{
- struct RString buf = rbimpl_rstring_getmem(str);
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
+ long len = RSTRING_LEN(str);
- if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) {
+ if (RUBY_DEBUG && RB_UNLIKELY(!ptr)) {
/* Ditto. */
rb_debug_rstring_null_ptr("RSTRING_END");
}
- return &buf.as.heap.ptr[buf.len];
+ return &ptr[len];
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -477,16 +447,7 @@ RSTRING_LENINT(VALUE str)
* @param ptrvar Variable where its contents is stored.
* @param lenvar Variable where its length is stored.
*/
-#ifdef HAVE_STMT_AND_DECL_IN_EXPR
-# define RSTRING_GETMEM(str, ptrvar, lenvar) \
- __extension__ ({ \
- struct RString rbimpl_str = rbimpl_rstring_getmem(str); \
- (ptrvar) = rbimpl_str.as.heap.ptr; \
- (lenvar) = rbimpl_str.len; \
- })
-#else
# define RSTRING_GETMEM(str, ptrvar, lenvar) \
((ptrvar) = RSTRING_PTR(str), \
(lenvar) = RSTRING_LEN(str))
-#endif /* HAVE_STMT_AND_DECL_IN_EXPR */
#endif /* RBIMPL_RSTRING_H */
diff --git a/include/ruby/internal/core/rstruct.h b/include/ruby/internal/core/rstruct.h
index 69be487b59..0028a1bdcd 100644
--- a/include/ruby/internal/core/rstruct.h
+++ b/include/ruby/internal/core/rstruct.h
@@ -31,18 +31,6 @@
# include "ruby/backward.h"
#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
- *
- * Declaration of rb_struct_ptr() is at include/ruby/backward.h.
- */
-#define RSTRUCT_PTR(st) rb_struct_ptr(st)
/** @cond INTERNAL_MACRO */
#define RSTRUCT_LEN RSTRUCT_LEN
#define RSTRUCT_SET RSTRUCT_SET
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index 6c19576c20..eb8313f180 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -26,6 +26,7 @@
# include <stddef.h>
#endif
+#include "ruby/assert.h"
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/flag_enum.h"
@@ -37,6 +38,7 @@
#include "ruby/internal/dllexport.h"
#include "ruby/internal/error.h"
#include "ruby/internal/fl_type.h"
+#include "ruby/internal/static_assert.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value_type.h"
@@ -93,13 +95,15 @@
*/
#define RTYPEDDATA(obj) RBIMPL_CAST((struct RTypedData *)(obj))
+static inline VALUE rbimpl_check_external_typeddata(VALUE obj);
+
/**
* Convenient getter macro.
*
* @param v An object, which is in fact an ::RTypedData.
* @return The passed object's ::RTypedData::data field.
*/
-#define RTYPEDDATA_DATA(v) (RTYPEDDATA(v)->data)
+#define RTYPEDDATA_DATA(v) (RTYPEDDATA(rbimpl_check_external_typeddata(v))->data)
/** @old{rb_check_typeddata} */
#define Check_TypedStruct(v, t) \
@@ -108,13 +112,18 @@
/** @cond INTERNAL_MACRO */
#define RTYPEDDATA_P RTYPEDDATA_P
#define RTYPEDDATA_TYPE RTYPEDDATA_TYPE
+#define TYPED_DATA_EMBEDDED ((VALUE)1)
+#define TYPED_DATA_PTR_MASK (~(TYPED_DATA_EMBEDDED))
+/** @endcond */
+
+/**
+ * Macros to see if each corresponding flag is defined.
+ */
#define RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
#define RUBY_TYPED_WB_PROTECTED RUBY_TYPED_WB_PROTECTED
+#define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
-/** @endcond */
-
-#define TYPED_DATA_EMBEDDED 2
/**
* @private
@@ -139,6 +148,20 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
+ /**
+ * This flag indicate to Ruby that the associated C struct may be embedded
+ * inside the object slot, instead of being externally allocated
+ * with +malloc+.
+ *
+ * Embeddable types MUST NOT be accessed using the +DATA_PTR+ macro, only
+ * with +TypedData_Get_Struct+ or +RTYPEDDATA_GET_DATA+.
+ *
+ * Embeddable types MUST NOT free the associated C struct.
+ *
+ * Pointers into the associated C struct MUST NOT be used after the ruby
+ * object is not longer on the stack, as they become invalid when GC
+ * compaction occurs
+ */
RUBY_TYPED_EMBEDDABLE = 2,
/**
@@ -155,6 +178,12 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE,
+ // experimental flag
+ // Similar to RUBY_TYPED_FROZEN_SHAREABLE, but doesn't make shareable
+ // reachable objects from this T_DATA object on the Ractor.make_shareable.
+ // If it refers to unshareable objects, simply raise an error.
+ // RUBY_TYPED_FROZEN_SHAREABLE_NO_REC = RUBY_FL_FINALIZE,
+
/**
* This flag has something to do with our garbage collector. These days
* ruby objects are "generational". There are those who are young and
@@ -177,11 +206,6 @@ rbimpl_typeddata_flags {
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
- * This flag no longer in use
- */
- 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
@@ -251,10 +275,15 @@ struct rb_data_type_struct {
RUBY_DATA_FUNC dcompact;
/**
- * This field is reserved for future extension. For now, it must be
- * filled with zeros.
+ * @internal
*/
- void *reserved[1]; /* For future extension.
+ void (*handle_weak_references)(void *);
+
+ /**
+ * This field is reserved for future extension. For now, it must be
+ * filled with zeros.
+ */
+ void *reserved[7]; /* For future extension.
This array *must* be filled with ZERO. */
} function;
@@ -352,24 +381,45 @@ struct RTypedData {
/** The part that all ruby objects have in common. */
struct RBasic basic;
+ /** Direct reference to the slots that holds instance variables, if any **/
+ VALUE fields_obj;
+
/**
+ * This is a `const rb_data_type_t *const` value, with the low bits set:
+ *
+ * 1: Set if object is embedded.
+ *
* This field stores various information about how Ruby should handle a
* data. This roughly resembles a Ruby level class (apart from method
* definition etc.)
*/
- const rb_data_type_t *const type;
-
- /**
- * This has to be always 1.
- *
- * @internal
- */
- const VALUE typed_flag;
+ const VALUE type;
/** Pointer to the actual C level struct that you want to wrap. */
void *data;
};
+#if !defined(__cplusplus) || __cplusplus >= 201103L
+RBIMPL_STATIC_ASSERT(fields_obj_in_rdata, offsetof(struct RData, fields_obj) == offsetof(struct RTypedData, fields_obj));
+RBIMPL_STATIC_ASSERT(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data));
+#endif
+
+/**
+ * Convenient casting macro for backward compatibility.
+ *
+ * @param obj An object, which is in fact an ::RData.
+ * @return The passed object casted to ::RData.
+ */
+#define RDATA(obj) RTYPEDDATA(obj)
+
+/**
+ * Convenient casting macro for backward compatibility.
+ *
+ * @param obj An object, which is in fact an ::RData.
+ * @return The passed object's ::RTypedData::data field.
+ */
+#define DATA_PTR(obj) RTYPEDDATA_DATA(obj)
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NONNULL((3))
/**
@@ -384,11 +434,11 @@ RBIMPL_ATTR_NONNULL((3))
*/
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL((3))
/**
* Identical to rb_data_typed_object_wrap(), except it allocates a new data
* region internally instead of taking an existing one. The allocation is done
- * using ruby_calloc(). Hence it makes no sense for `type->function.dfree` to
- * be anything other than ::RUBY_TYPED_DEFAULT_FREE.
+ * using ruby_calloc().
*
* @param[in] klass Ruby level class of the returning object.
* @param[in] size Requested size of memory to allocate.
@@ -399,6 +449,7 @@ VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *
*/
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL(())
/**
* Checks for the domestic relationship between the two.
*
@@ -413,6 +464,7 @@ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t
*/
int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent);
+RBIMPL_ATTR_NONNULL((2))
/**
* Checks if the given object is of given kind.
*
@@ -423,6 +475,7 @@ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *
*/
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
+RBIMPL_ATTR_NONNULL((2))
/**
* Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead
* of returning false.
@@ -434,8 +487,49 @@ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
* @post Upon successful return `obj`'s type is guaranteed `data_type`.
*/
void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
+ *
+ * @param[in] obj The object in question.
+ * @param[in] expected Name of expected data type of `obj`.
+ */
+void rb_unexpected_object_type(VALUE obj, const char *expected);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL(())
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of #TypedData_Make_Struct. People don't
+ * use it directly.
+ *
+ * @param[in] actual Actual data type.
+ * @param[in] expected Expected data type.
+ */
+void rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected);
RBIMPL_SYMBOL_EXPORT_END()
+#if RUBY_DEBUG
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ while (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { \
+ rb_unexpected_object_type(obj, "Data"); \
+ unreachable; \
+ }
+#else
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ RBIMPL_ASSERT_NOTHING
+#endif
+
/**
* Converts sval, a pointer to your struct, into a Ruby object.
*
@@ -464,14 +558,13 @@ 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 *)rbimpl_typeddata_get_data(result)); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
* Identical to #TypedData_Wrap_Struct, except it allocates a new data region
* internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense for `data_type->function.dfree` to
- * be anything other than ::RUBY_TYPED_DEFAULT_FREE.
+ * ruby_calloc().
*
* @param klass Ruby level class of the object.
* @param type Type name of the C struct.
@@ -502,47 +595,36 @@ RBIMPL_SYMBOL_EXPORT_END()
sizeof(type))
#endif
-/**
- * Obtains a C struct from inside of a wrapper Ruby object.
- *
- * @param obj An instance of ::RTypedData.
- * @param type Type name of the C struct.
- * @param data_type The data type describing `type`.
- * @param sval Variable name of obtained C struct.
- * @exception rb_eTypeError `obj` is not a kind of `data_type`.
- * @return Unwrapped C struct that `obj` holds.
- */
-#define TypedData_Get_Struct(obj,type,data_type,sval) \
- ((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
+static inline bool
+rbimpl_typeddata_embedded_p(VALUE obj)
+{
+ return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED;
+}
+RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
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
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
- return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED;
+ return rbimpl_typeddata_embedded_p(obj);
}
static inline void *
-RTYPEDDATA_GET_DATA(VALUE obj)
+rbimpl_typeddata_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. */
+ return rbimpl_typeddata_embedded_p(obj) ?
+ RBIMPL_CAST((void *)&RTYPEDDATA(obj)->data) :
+ RTYPEDDATA_DATA(obj);
+}
- /* 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 *);
+static inline void *
+RTYPEDDATA_GET_DATA(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
- return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data;
+ return rbimpl_typeddata_get_data(obj);
}
RBIMPL_ATTR_PURE()
@@ -550,47 +632,41 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of Check_Type(). People don't use it
- * directly.
+ * Checks whether the passed object is ::RTypedData.
+ *
+ * This is an implementation detail of inline functions defined in this file.
+ * People don't use it directly.
*
* @param[in] obj Object in question
* @retval true `obj` is an instance of ::RTypedData.
- * @retval false `obj` is an instance of ::RData.
- * @pre `obj` must be a Ruby object of ::RUBY_T_DATA.
+ * @retval false `obj` is not an instance of ::RTypedData
*/
static inline bool
-rbimpl_rtypeddata_p(VALUE obj)
+rbimpl_obj_typeddata_p(VALUE obj)
{
- VALUE typed_flag = RTYPEDDATA(obj)->typed_flag;
- return typed_flag != 0 && typed_flag <= 3;
+ return RB_TYPE_P(obj, RUBY_T_DATA);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * Checks whether the passed object is ::RTypedData or ::RData.
+ * Checks whether the passed object is ::RTypedData.
*
* @param[in] obj Object in question
- * @retval true `obj` is an instance of ::RTypedData.
- * @retval false `obj` is an instance of ::RData.
+ * @retval true
* @pre `obj` must be a Ruby object of ::RUBY_T_DATA.
*/
static inline bool
RTYPEDDATA_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
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
- return rbimpl_rtypeddata_p(obj);
+ return true;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
+RBIMPL_ATTR_RETURNS_NONNULL()
/**
* Queries for the type of given object.
*
@@ -598,20 +674,93 @@ RBIMPL_ATTR_ARTIFICIAL()
* @return Data type struct that corresponds to `obj`.
* @pre `obj` must be an instance of ::RTypedData.
*/
-static inline const struct rb_data_type_struct *
+static inline const rb_data_type_t *
RTYPEDDATA_TYPE(VALUE obj)
{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(! RTYPEDDATA_P(obj))) {
- rb_unexpected_type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(NULL);
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
+
+ VALUE type = RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK;
+ const rb_data_type_t *ptr = RBIMPL_CAST((const rb_data_type_t *)type);
+ RBIMPL_ASSERT_OR_ASSUME(ptr);
+ return ptr;
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL(())
+static inline bool
+rbimpl_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent)
+{
+ do {
+ if (RB_LIKELY(child == parent)) return true;
+ } while ((child = child->parent) != NULL);
+ return false;
+}
+#define rb_typeddata_inherited_p rbimpl_typeddata_inherited_p_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+static inline bool
+rbimpl_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false;
+ return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type);
+}
+#define rb_typeddata_is_kind_of rbimpl_typeddata_is_kind_of_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * This is an implementation detail of TypedData_Get_Struct(). Don't use it
+ * directly.
+ */
+static inline void *
+rbimpl_check_typeddata(VALUE obj, const rb_data_type_t *expected_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) {
+ rb_unexpected_object_type(obj, expected_type->wrap_struct_name);
+ }
+
+ const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj);
+ if (RB_UNLIKELY(!rb_typeddata_inherited_p(actual_type, expected_type))){
+ rb_unexpected_typeddata(actual_type, expected_type);
}
-#endif
- return RTYPEDDATA(obj)->type;
+ return RTYPEDDATA_GET_DATA(obj);
+}
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * @private
+ *
+ * This is an implementation detail of RTYPEDDATA_DATA(). Don't use it
+ * directly.
+ */
+static inline VALUE
+rbimpl_check_external_typeddata(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
+ RUBY_ASSERT(!rbimpl_typeddata_embedded_p(obj));
+ return obj;
}
/**
+ * Obtains a C struct from inside of a wrapper Ruby object.
+ *
+ * @param obj An instance of ::RTypedData.
+ * @param type Type name of the C struct.
+ * @param data_type The data type describing `type`.
+ * @param sval Variable name of obtained C struct.
+ * @exception rb_eTypeError `obj` is not a kind of `data_type`.
+ * @return Unwrapped C struct that `obj` holds.
+ */
+#define TypedData_Get_Struct(obj,type,data_type,sval) \
+ ((sval) = RBIMPL_CAST((type *)rbimpl_check_typeddata((obj), (data_type))))
+
+RBIMPL_ATTR_NONNULL((2))
+/**
* While we don't stop you from using this function, it seems to be an
* implementation detail of #TypedData_Make_Struct, which is preferred over
* this one.
@@ -632,12 +781,4 @@ rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap,
return result;
}
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap"))
-/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */
-static inline VALUE
-rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
-{
- return rb_data_typed_object_wrap(klass, datap, type);
-}
-
#endif /* RBIMPL_RTYPEDDATA_H */
diff --git a/include/ruby/internal/ctype.h b/include/ruby/internal/ctype.h
index 0f7ca6c516..8b24026311 100644
--- a/include/ruby/internal/ctype.h
+++ b/include/ruby/internal/ctype.h
@@ -498,8 +498,8 @@ RBIMPL_ATTR_ARTIFICIAL()
* Our own locale-insensitive version of `tolower(3)`.
*
* @param[in] c Byte in question to convert.
- * @retval c The byte is not listed in in IEEE 1003.1 section
- * 7.3.1.1 "upper".
+ * @retval c The byte is not listed in IEEE 1003.1 section 7.3.1.1
+ * "upper".
* @retval otherwise Byte converted using the map defined in IEEE 1003.1
* section 7.3.1 "tolower".
* @note Not only does this function works under the POSIX Locale, but
diff --git a/include/ruby/internal/encoding/string.h b/include/ruby/internal/encoding/string.h
index 2cfa91c01e..ea78cf23f3 100644
--- a/include/ruby/internal/encoding/string.h
+++ b/include/ruby/internal/encoding/string.h
@@ -264,6 +264,14 @@ VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to);
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts);
/**
+ * @private
+ *
+ * This is an implementation detail of rb_enc_str_coderange(). Don't use this
+ * directly.
+ **/
+int rbimpl_enc_str_coderange_scan(VALUE str);
+
+/**
* Scans the passed string to collect its code range. Because a Ruby's string
* is mutable, its contents change from time to time; so does its code range.
* A long-lived string tends to fall back to ::RUBY_ENC_CODERANGE_UNKNOWN.
@@ -275,6 +283,27 @@ VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ec
int rb_enc_str_coderange(VALUE str);
/**
+ * Scans the passed string to collect its code range. Because a Ruby's string
+ * is mutable, its contents change from time to time; so does its code range.
+ * A long-lived string tends to fall back to ::RUBY_ENC_CODERANGE_UNKNOWN.
+ * This API scans it and re-assigns a fine-grained code range constant.
+ *
+ * @param[out] str A string.
+ * @return An enum ::ruby_coderange_type.
+ */
+static inline int
+rb_enc_str_coderange_inline(VALUE str)
+{
+ int cr = ENC_CODERANGE(str);
+ if (cr == ENC_CODERANGE_UNKNOWN) {
+ cr = rbimpl_enc_str_coderange_scan(str);
+ }
+ return cr;
+}
+
+#define rb_enc_str_coderange rb_enc_str_coderange_inline
+
+/**
* Scans the passed string until it finds something odd. Returns the number of
* bytes scanned. As the name implies this is suitable for repeated call. One
* of its application is `IO#readlines`. The method reads from its receiver's
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index 3ff885b2b1..5bf82bfe7d 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -421,11 +421,12 @@ void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int err, const
RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NORETURN()
/**
+ * @private
+ *
* Fails with the given object's type incompatibility to the type.
*
- * It seems this function is visible from extension libraries only because
- * RTYPEDDATA_TYPE() uses it on RUBY_DEBUG. So you can basically ignore it;
- * use some other fine-grained method instead.
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
*
* @param[in] self The object in question.
* @param[in] t Expected type of the object.
diff --git a/include/ruby/internal/eval.h b/include/ruby/internal/eval.h
index 5bcbb97746..23aa1d9580 100644
--- a/include/ruby/internal/eval.h
+++ b/include/ruby/internal/eval.h
@@ -155,7 +155,8 @@ VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method evaluates to.
@@ -189,7 +190,8 @@ VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -261,7 +263,8 @@ VALUE rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -307,7 +310,8 @@ VALUE rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VAL
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -335,7 +339,8 @@ VALUE rb_call_super(int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No super method are there.
* @exception rb_eException Any exceptions happen inside.
* @return What the super method evaluates to.
diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h
index f80f65ef8f..f7ec742422 100644
--- a/include/ruby/internal/fl_type.h
+++ b/include/ruby/internal/fl_type.h
@@ -59,10 +59,8 @@
#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_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} */
#define FL_UNTRUSTED RBIMPL_CAST((VALUE)RUBY_FL_UNTRUSTED) /**< @old{RUBY_FL_UNTRUSTED} */
-#define FL_SEEN_OBJ_ID RBIMPL_CAST((VALUE)RUBY_FL_SEEN_OBJ_ID) /**< @old{RUBY_FL_SEEN_OBJ_ID} */
#define FL_EXIVAR RBIMPL_CAST((VALUE)RUBY_FL_EXIVAR) /**< @old{RUBY_FL_EXIVAR} */
#define FL_FREEZE RBIMPL_CAST((VALUE)RUBY_FL_FREEZE) /**< @old{RUBY_FL_FREEZE} */
@@ -110,8 +108,6 @@
#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_UNTRUST RB_OBJ_TAINT
-#define RB_OBJ_UNTRUSTED RB_OBJ_TAINTED
/** @endcond */
/**
@@ -136,15 +132,6 @@
#define OBJ_FREEZE_RAW RB_OBJ_FREEZE_RAW /**< @old{RB_OBJ_FREEZE_RAW} */
#define OBJ_FROZEN RB_OBJ_FROZEN /**< @old{RB_OBJ_FROZEN} */
#define OBJ_FROZEN_RAW RB_OBJ_FROZEN_RAW /**< @old{RB_OBJ_FROZEN_RAW} */
-#define OBJ_INFECT RB_OBJ_INFECT /**< @old{RB_OBJ_INFECT} */
-#define OBJ_INFECT_RAW RB_OBJ_INFECT_RAW /**< @old{RB_OBJ_INFECT_RAW} */
-#define OBJ_TAINT RB_OBJ_TAINT /**< @old{RB_OBJ_TAINT} */
-#define OBJ_TAINTABLE RB_OBJ_TAINTABLE /**< @old{RB_OBJ_TAINT_RAW} */
-#define OBJ_TAINTED RB_OBJ_TAINTED /**< @old{RB_OBJ_TAINTED} */
-#define OBJ_TAINTED_RAW RB_OBJ_TAINTED_RAW /**< @old{RB_OBJ_TAINTED_RAW} */
-#define OBJ_TAINT_RAW RB_OBJ_TAINT_RAW /**< @old{RB_OBJ_TAINT_RAW} */
-#define OBJ_UNTRUST RB_OBJ_UNTRUST /**< @old{RB_OBJ_TAINT} */
-#define OBJ_UNTRUSTED RB_OBJ_UNTRUSTED /**< @old{RB_OBJ_TAINTED} */
/** @} */
/**
@@ -222,7 +209,7 @@ ruby_fl_type {
*
* @internal
*/
- RUBY_FL_UNUSED6 = (1<<6),
+ RUBY_FL_UNUSED6 = (1<<6),
/**
* This flag has something to do with finalisers. A ruby object can have
@@ -239,16 +226,16 @@ ruby_fl_type {
RUBY_FL_FINALIZE = (1<<7),
/**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
+ * @deprecated This flag was an implementation detail that should never have
+ * no been exposed. Exists here for backwards
* compatibility only. You can safely forget about it.
*/
- RUBY_FL_TAINT
+ RUBY_FL_EXIVAR
#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
+ RBIMPL_ATTR_DEPRECATED(("FL_EXIVAR is an outdated implementation detail, it should not be used."))
#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_TAINT)
+# pragma deprecated(RUBY_FL_EXIVAR)
#endif
= 0,
@@ -265,52 +252,19 @@ ruby_fl_type {
*/
RUBY_FL_SHAREABLE = (1<<8),
- /**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_UNTRUSTED
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("trustedness turned out to be a wrong idea."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_UNTRUSTED)
-#endif
-
- = 0,
+ /**
+ * This object weakly refers to other objects.
+ *
+ * @internal
+ */
+ RUBY_FL_WEAK_REFERENCE = (1<<9),
- /**
- * This flag has something to do with object IDs. Unlike in the old days,
- * an object's object ID (that a user can query using `Object#object_id`)
- * is no longer its physical address represented using Ruby level integers.
- * It is now a monotonic-increasing integer unrelated to the underlying
- * memory arrangement. Object IDs are assigned when necessary; objects are
- * born without one, and will eventually have such property when queried.
- * The interpreter has to manage which one is which. This is the flag that
- * helps the management. Objects with this flag set are the ones with
- * object IDs assigned.
- *
- * @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_SEEN_OBJ_ID = (1<<9),
-
- /**
- * This flag has something to do with instance variables. 3rd parties need
- * not know, but there are several ways to store an object's instance
- * variables. Objects with this flag use so-called "generic" backend
- * storage. This distinction is purely an implementation detail. People
- * need not be aware of this working behind-the-scene.
- *
- * @internal
- *
- * As of writing everything except ::RObject and RModule use this scheme.
- */
- RUBY_FL_EXIVAR = (1<<10),
+ /**
+ * This flag is no longer in use
+ *
+ * @internal
+ */
+ RUBY_FL_UNUSED10 = (1<<10),
/**
* This flag has something to do with data immutability. When this flag is
@@ -398,23 +352,6 @@ ruby_fl_type {
RUBY_FL_SINGLETON = RUBY_FL_USER1,
};
-enum {
- /**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_DUPPED
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("It seems there is no actual usage of this enum."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_DUPPED)
-#endif
-
- = (int)RUBY_T_MASK | (int)RUBY_FL_EXIVAR
-};
-
#undef RBIMPL_HAVE_ENUM_ATTRIBUTE
RBIMPL_SYMBOL_EXPORT_BEGIN()
@@ -446,10 +383,8 @@ RB_FL_ABLE(VALUE obj)
if (RB_SPECIAL_CONST_P(obj)) {
return false;
}
- else if (RB_TYPE_P(obj, RUBY_T_NODE)) {
- return false;
- }
else {
+ RBIMPL_ASSERT_OR_ASSUME(!RB_TYPE_P(obj, RUBY_T_NODE));
return true;
}
}
@@ -743,128 +678,6 @@ RB_FL_REVERSE(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline bool
-RB_OBJ_TAINTABLE(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline VALUE
-RB_OBJ_TAINTED_RAW(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline bool
-RB_OBJ_TAINTED(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- */
-static inline void
-RB_OBJ_TAINT_RAW(VALUE obj)
-{
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] obj Object in question.
- */
-static inline void
-RB_OBJ_TAINT(VALUE obj)
-{
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] dst Victim object.
- * @param[in] src Infectant object.
- */
-static inline void
-RB_OBJ_INFECT_RAW(VALUE dst, VALUE src)
-{
- (void)dst;
- (void)src;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function 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.
- *
- * @param[in] dst Victim object.
- * @param[in] src Infectant object.
- */
-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
* use this. Just always use RB_OBJ_FROZEN().
diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h
index 5ab3bb266e..1900b48a75 100644
--- a/include/ruby/internal/gc.h
+++ b/include/ruby/internal/gc.h
@@ -436,153 +436,6 @@ RBIMPL_SYMBOL_EXPORT_END()
#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
@@ -621,11 +474,11 @@ RBIMPL_SYMBOL_EXPORT_END()
#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.
+ * Marks the object as not protected by write barriers. These objects do not
+ * participate in generational GCs which means that, as long as the object is
+ * alive, they will be scanned on every GC cycle.
*
- * @param[out] x An object that would not be protected by the barrier.
+ * @param[out] x An object that is not protected by the write barrier.
*/
#define RB_OBJ_WB_UNPROTECT(x) rb_obj_wb_unprotect(x, __FILE__, __LINE__)
@@ -640,8 +493,7 @@ RBIMPL_SYMBOL_EXPORT_END()
*
* @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)
+#define RB_OBJ_WB_UNPROTECT_FOR(type, obj) OBJ_WB_UNPROTECT(obj)
/**
* @private
@@ -823,7 +675,4 @@ rb_obj_write(
return a;
}
-RBIMPL_ATTR_DEPRECATED(("Will be removed soon"))
-static inline void rb_gc_force_recycle(VALUE obj){}
-
#endif /* RBIMPL_GC_H */
diff --git a/include/ruby/internal/globals.h b/include/ruby/internal/globals.h
index 60d8e5309a..9beb215c0c 100644
--- a/include/ruby/internal/globals.h
+++ b/include/ruby/internal/globals.h
@@ -68,6 +68,7 @@ RUBY_EXTERN VALUE rb_cBasicObject; /**< `BasicObject` class. */
RUBY_EXTERN VALUE rb_cObject; /**< `Object` class. */
RUBY_EXTERN VALUE rb_cArray; /**< `Array` class. */
RUBY_EXTERN VALUE rb_cBinding; /**< `Binding` class. */
+RUBY_EXTERN VALUE rb_cBox; /**< `Ruby::Box` class. */
RUBY_EXTERN VALUE rb_cClass; /**< `Class` class. */
RUBY_EXTERN VALUE rb_cDir; /**< `Dir` class. */
RUBY_EXTERN VALUE rb_cEncoding; /**< `Encoding` class. */
@@ -91,6 +92,7 @@ RUBY_EXTERN VALUE rb_cRandom; /**< `Random` class. */
RUBY_EXTERN VALUE rb_cRange; /**< `Range` class. */
RUBY_EXTERN VALUE rb_cRational; /**< `Rational` class. */
RUBY_EXTERN VALUE rb_cRegexp; /**< `Regexp` class. */
+RUBY_EXTERN VALUE rb_cSet; /**< `Set` class. */
RUBY_EXTERN VALUE rb_cStat; /**< `File::Stat` class. */
RUBY_EXTERN VALUE rb_cString; /**< `String` class. */
RUBY_EXTERN VALUE rb_cStruct; /**< `Struct` class. */
diff --git a/include/ruby/internal/intern/bignum.h b/include/ruby/internal/intern/bignum.h
index c27f77a1fb..6ab26fef71 100644
--- a/include/ruby/internal/intern/bignum.h
+++ b/include/ruby/internal/intern/bignum.h
@@ -26,6 +26,10 @@
# include <stddef.h>
#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* for ssize_t (note: on Windows ssize_t is */
+#endif /* `#define`d in ruby/config.h) */
+
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
@@ -841,6 +845,47 @@ size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret);
*/
int rb_absint_singlebit_p(VALUE val);
+/**
+ * @name Flags for rb_int_parse_cstr()
+ * @{
+ */
+
+/** Allows a leading sign (`+` or `-`). */
+#define RB_INT_PARSE_SIGN 0x01
+
+/** Allows underscores between digits. */
+#define RB_INT_PARSE_UNDERSCORE 0x02
+
+/** Allows a base prefix (`0x`, `0b`, `0o`, `0d`). */
+#define RB_INT_PARSE_PREFIX 0x04
+
+/** Shorthand for all of the above flags combined. */
+#define RB_INT_PARSE_ALL 0x07
+
+/** Default flags (all features enabled). */
+#define RB_INT_PARSE_DEFAULT 0x07
+
+/** @} */
+
+/**
+ * Parses a C string to convert into a Ruby integer, with detailed control over
+ * parsing behaviour. Unlike rb_cstr_to_inum(), this function can report the
+ * end position of the parsed integer and the number of parsed digits.
+ *
+ * @param[in] str Pointer to the string to parse.
+ * @param[in] len Length of `str` in bytes, or `-1` to use `strlen(str)`.
+ * @param[out] endp If not `NULL`, the pointer to the first unparsed
+ * character is stored here on return.
+ * @param[out] ndigits If not `NULL`, the number of parsed digits (excluding
+ * prefix, sign, and underscores) is stored here.
+ * @param[in] base Base of conversion. `0` means auto-detect from
+ * prefix. `2..36` for explicit base.
+ * @param[in] flags Bitwise or of `RB_INT_PARSE_*` macros.
+ * @return A Ruby Integer (Fixnum or Bignum), or `Qnil` on parse failure
+ * (when no digits are found).
+ */
+VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_BIGNUM_H */
diff --git a/include/ruby/internal/intern/complex.h b/include/ruby/internal/intern/complex.h
index e111bd8ced..1efc093631 100644
--- a/include/ruby/internal/intern/complex.h
+++ b/include/ruby/internal/intern/complex.h
@@ -87,10 +87,6 @@ VALUE rb_complex_new(VALUE real, VALUE imag);
*/
VALUE rb_complex_new_polar(VALUE abs, VALUE arg);
-RBIMPL_ATTR_DEPRECATED(("by: rb_complex_new_polar"))
-/** @old{rb_complex_new_polar} */
-VALUE rb_complex_polar(VALUE abs, VALUE arg);
-
RBIMPL_ATTR_PURE()
/**
* Queries the real part of the passed Complex.
diff --git a/include/ruby/internal/intern/cont.h b/include/ruby/internal/intern/cont.h
index 32647f48aa..2d813ceb9d 100644
--- a/include/ruby/internal/intern/cont.h
+++ b/include/ruby/internal/intern/cont.h
@@ -148,7 +148,8 @@ VALUE rb_fiber_resume(VALUE fiber, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eFiberError `fiber` is terminated etc.
* @exception rb_eException Any exceptions happen in `fiber`.
* @return Either what was yielded or the last value of the fiber body.
@@ -192,7 +193,8 @@ VALUE rb_fiber_yield(int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException What was raised using `Fiber#raise`.
* @return (See rb_fiber_resume() for details)
*/
@@ -247,7 +249,8 @@ VALUE rb_fiber_transfer(VALUE fiber, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eFiberError (See above)
* @exception rb_eException What was raised using `Fiber#raise`.
* @return (See rb_fiber_resume() for details)
@@ -275,7 +278,7 @@ VALUE rb_fiber_transfer_kw(VALUE fiber, int argc, const VALUE *argv, int kw_spla
* @exception rb_eFiberError `fiber` is terminated etc.
* @return (See rb_fiber_resume() for details)
*/
-VALUE rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv);
+VALUE rb_fiber_raise(VALUE fiber, int argc, VALUE *argv);
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/internal/intern/enumerator.h b/include/ruby/internal/intern/enumerator.h
index 20e5d7c6fc..00804d786a 100644
--- a/include/ruby/internal/intern/enumerator.h
+++ b/include/ruby/internal/intern/enumerator.h
@@ -100,7 +100,8 @@ VALUE rb_enumeratorize_with_size(VALUE recv, VALUE meth, int argc, const VALUE *
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `meth` is not an instance of ::rb_cSymbol.
* @return A new instance of ::rb_cEnumerator which, when yielded,
* enumerates by calling `meth` on `recv` with `argv`.
@@ -186,7 +187,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return A new instance of ::rb_cEnumerator which, when yielded,
* enumerates by calling the current method on `recv` with `argv`.
*/
@@ -220,7 +222,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @note This macro may return inside.
*/
#define RETURN_SIZED_ENUMERATOR_KW(obj, argc, argv, size_fn, kw_splat) do { \
@@ -250,7 +253,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @note This macro may return inside.
*/
#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat) \
diff --git a/include/ruby/internal/intern/file.h b/include/ruby/internal/intern/file.h
index b669758d21..8508b7ab9e 100644
--- a/include/ruby/internal/intern/file.h
+++ b/include/ruby/internal/intern/file.h
@@ -211,22 +211,6 @@ int rb_is_absolute_path(const char *path);
*/
rb_off_t rb_file_size(VALUE file);
-#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
-#endif
-/**
- * If the PATH_SEPARATOR-separated list of directory names contains the name of
- * a world-writable directory, issue a warning for it. This may do nothing on
- * some platforms.
- *
- * @param[in] path A local path.
- * @retval 0 The "check" succeeded.
- * @retval otherwise The "check" failed.
- * @note This feature may be disabled by setting `ENABLE_PATH_CHECK`
- * macro to zero at compilation time.
- */
-int rb_path_check(const char *path);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_FILE_H */
diff --git a/include/ruby/internal/intern/object.h b/include/ruby/internal/intern/object.h
index 9daad7d046..3897639a0a 100644
--- a/include/ruby/internal/intern/object.h
+++ b/include/ruby/internal/intern/object.h
@@ -80,7 +80,8 @@ VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `klass`'s allocator is undefined.
* @exception rb_eException Any exceptions can happen inside.
* @return An allocated new instance of `klass`.
diff --git a/include/ruby/internal/intern/proc.h b/include/ruby/internal/intern/proc.h
index b8c3c5e146..2635d672eb 100644
--- a/include/ruby/internal/intern/proc.h
+++ b/include/ruby/internal/intern/proc.h
@@ -101,7 +101,8 @@ VALUE rb_proc_call(VALUE recv, VALUE args);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException Any exceptions happen inside.
* @return What the proc evaluates to.
*/
@@ -141,7 +142,8 @@ VALUE rb_proc_call_with_block(VALUE recv, int argc, const VALUE *argv, VALUE pro
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException Any exceptions happen inside.
* @return What the proc evaluates to.
*/
@@ -245,7 +247,8 @@ VALUE rb_method_call(int argc, const VALUE *argv, VALUE recv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `recv` is not a method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method returns.
@@ -279,7 +282,8 @@ VALUE rb_method_call_with_block(int argc, const VALUE *argv, VALUE recv, VALUE p
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `recv` is not a method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method returns.
diff --git a/include/ruby/internal/intern/select.h b/include/ruby/internal/intern/select.h
index 6ba84c6e63..ba75213618 100644
--- a/include/ruby/internal/intern/select.h
+++ b/include/ruby/internal/intern/select.h
@@ -72,6 +72,8 @@ struct timeval;
* someone else, vastly varies among operating systems. You would better avoid
* touching an fd from more than one threads.
*
+ * NOTE: this function is used in native extensions, so change its API with care.
+ *
* @internal
*
* Although any file descriptors are possible here, it makes completely no
diff --git a/include/ruby/internal/intern/set.h b/include/ruby/internal/intern/set.h
new file mode 100644
index 0000000000..f4ff8665e2
--- /dev/null
+++ b/include/ruby/internal/intern/set.h
@@ -0,0 +1,111 @@
+#ifndef RBIMPL_INTERN_SET_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_INTERN_SET_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_cSet.
+ */
+#include "ruby/internal/attr/nonnull.h"
+#include "ruby/internal/dllexport.h"
+#include "ruby/internal/value.h"
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+
+/* set.c */
+
+RBIMPL_ATTR_NONNULL(())
+/**
+ * Iterates over a set. Calls func with each element of the set and the
+ * argument given. func should return ST_CONTINUE, ST_STOP, or ST_DELETE.
+ *
+ * @param[in] set An instance of ::rb_cSet to iterate over.
+ * @param[in] func Callback function to yield.
+ * @param[in] arg Passed as-is to `func`.
+ * @exception rb_eRuntimeError `set` was tampered during iterating.
+ */
+void rb_set_foreach(VALUE set, int (*func)(VALUE element, VALUE arg), VALUE arg);
+
+/**
+ * Creates a new, empty set object.
+ *
+ * @return An allocated new instance of ::rb_cSet.
+ */
+VALUE rb_set_new(void);
+
+/**
+ * Identical to rb_set_new(), except it additionally specifies how many elements
+ * it is expected to contain. This way you can create a set that is large enough
+ * for your need. For large sets, it means it won't need to be reallocated
+ * much, improving performance.
+ *
+ * @param[in] capa Designed capacity of the set.
+ * @return An empty Set, whose capacity is `capa`.
+ */
+VALUE rb_set_new_capa(size_t capa);
+
+/**
+ * Whether the set contains the given element.
+ *
+ * @param[in] set Set to look into.
+ * @param[in] element Set element to look for.
+ * @return true if element is in the set, falst otherwise.
+ */
+bool rb_set_lookup(VALUE set, VALUE element);
+
+/**
+ * Adds element to set.
+ *
+ * @param[in] set Target set table to modify.
+ * @param[in] element Arbitrary Ruby object.
+ * @exception rb_eFrozenError `set` is frozen.
+ * @return true if element was not already in set, false otherwise
+ * @post `element` is in `set`.
+ */
+bool rb_set_add(VALUE set, VALUE element);
+
+/**
+ * Removes all entries from set.
+ *
+ * @param[out] set Target to clear.
+ * @exception rb_eFrozenError `set`is frozen.
+ * @return The passed `set`
+ * @post `set` has no elements.
+ */
+VALUE rb_set_clear(VALUE set);
+
+/**
+ * Removes the element from from set.
+ *
+ * @param[in] set Target set to modify.
+ * @param[in] element Key to delete.
+ * @retval true if element was already in set, false otherwise
+ * @post `set` does not have `element` as an element.
+ */
+bool rb_set_delete(VALUE set, VALUE element);
+
+/**
+ * Returns the number of elements in the set.
+ *
+ * @param[in] set A set object.
+ * @return The size of the set.
+ */
+size_t rb_set_size(VALUE set);
+
+RBIMPL_SYMBOL_EXPORT_END()
+
+#endif /* RBIMPL_INTERN_SET_H */
diff --git a/include/ruby/internal/intern/string.h b/include/ruby/internal/intern/string.h
index 4573ec1262..8bd1ffcfb4 100644
--- a/include/ruby/internal/intern/string.h
+++ b/include/ruby/internal/intern/string.h
@@ -412,8 +412,8 @@ VALUE rb_utf8_str_new_static(const char *ptr, long len);
/**
* Identical to rb_interned_str(), except it takes a Ruby's string instead of
- * C's. It can also be seen as a routine identical to rb_str_new_shared(),
- * except it returns an infamous "f"string.
+ * C's and preserves its encoding. It can also be seen as a routine identical
+ * to rb_str_new_shared(), except it returns an infamous "f"string.
*
* @param[in] str An object of ::RString.
* @return An instance of ::rb_cString, either cached or allocated, which
@@ -444,8 +444,9 @@ VALUE rb_str_to_interned_str(VALUE str);
* terminating NUL character.
* @exception rb_eArgError `len` is negative.
* @return A found or created instance of ::rb_cString, of `len` bytes
- * length, of "binary" encoding, whose contents are identical to
- * that of `ptr`.
+ * length, whose contents are identical to that of `ptr`. Its
+ * encoding will be US-ASCII if all bytes are lower ASCII, BINARY
+ * otherwise.
* @pre At least `len` bytes of continuous memory region shall be
* accessible via `ptr`.
*/
@@ -461,8 +462,9 @@ RBIMPL_ATTR_NONNULL(())
*
* @param[in] ptr A C string.
* @exception rb_eNoMemError Failed to allocate memory.
- * @return An instance of ::rb_cString, of "binary" encoding, whose
- * contents are verbatim copy of `ptr`.
+ * @return An instance of ::rb_cString, whose contents are verbatim copy
+ * of `ptr`. Its encoding will be US-ASCII if all bytes are lower
+ * ASCII, BINARY otherwise.
* @pre `ptr` must not be a null pointer.
*/
VALUE rb_interned_str_cstr(const char *ptr);
@@ -591,10 +593,9 @@ void rb_must_asciicompat(VALUE obj);
VALUE rb_str_dup(VALUE str);
/**
- * I guess there is no use case of this function in extension libraries, but
- * this is a routine identical to rb_str_dup(), except it always creates an
- * instance of ::rb_cString regardless of the given object's class. This makes
- * the most sense when the passed string is formerly hidden by rb_obj_hide().
+ * Like rb_str_dup(), but always create an instance of ::rb_cString
+ * regardless of the given object's class. This makes the most sense
+ * when the passed string is formerly hidden by rb_obj_hide().
*
* @param[in] str A string, possibly hidden.
* @return A duplicated new instance of ::rb_cString.
@@ -970,8 +971,8 @@ st_index_t rb_str_hash(VALUE str);
*
* @param[in] str1 A string.
* @param[in] str2 Another string.
- * @retval 1 They have identical contents, length, and encodings.
- * @retval 0 Otherwise.
+ * @retval 0 They have identical contents, length, and encodings.
+ * @retval 1 Otherwise.
* @pre Both objects must not be any arbitrary objects except
* ::RString.
*
diff --git a/include/ruby/internal/intern/thread.h b/include/ruby/internal/intern/thread.h
index 716375acd7..4d87452745 100644
--- a/include/ruby/internal/intern/thread.h
+++ b/include/ruby/internal/intern/thread.h
@@ -61,10 +61,10 @@ int rb_thread_wait_fd(int fd);
int rb_thread_fd_writable(int fd);
/**
- * Notifies a closing of a file descriptor to other threads. Multiple threads
- * can wait for the given file descriptor at once. If such file descriptor is
- * closed, threads need to start propagating their exceptions. This is the API
- * to kick that process.
+ * This funciton is now a no-op. It was previously used to interrupt threads
+ * that were using the given file descriptor and wait for them to finish.
+ *
+ * @deprecated Use IO with RUBY_IO_MODE_EXTERNAL and `rb_io_close` instead.
*
* @param[in] fd A file descriptor.
* @note This function blocks until all the threads waiting for such fd
diff --git a/include/ruby/internal/intern/variable.h b/include/ruby/internal/intern/variable.h
index 479c3950c1..315584790c 100644
--- a/include/ruby/internal/intern/variable.h
+++ b/include/ruby/internal/intern/variable.h
@@ -48,6 +48,7 @@ VALUE rb_mod_name(VALUE mod);
*/
VALUE rb_class_path(VALUE mod);
+RBIMPL_ATTR_DEPRECATED(("rb_mod_name"))
/**
* @alias{rb_mod_name}
*
diff --git a/include/ruby/internal/intern/vm.h b/include/ruby/internal/intern/vm.h
index 29e0c7f534..f0b54c702c 100644
--- a/include/ruby/internal/intern/vm.h
+++ b/include/ruby/internal/intern/vm.h
@@ -89,7 +89,8 @@ VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @retval RUBY_Qundef `recv` doesn't respond to `mid`.
* @retval otherwise What the method evaluates to.
*/
@@ -106,9 +107,11 @@ VALUE rb_check_funcall_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int k
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `arg`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `arg`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return What the command evaluates to.
*/
+RBIMPL_ATTR_DEPRECATED_INTERNAL(4.0)
VALUE rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat);
/**
diff --git a/include/ruby/internal/iterator.h b/include/ruby/internal/iterator.h
index 5f706460f8..891045363e 100644
--- a/include/ruby/internal/iterator.h
+++ b/include/ruby/internal/iterator.h
@@ -265,48 +265,6 @@ int rb_block_given_p(void);
*/
void rb_need_block(void);
-#ifndef __cplusplus
-RBIMPL_ATTR_DEPRECATED(("by: rb_block_call since 1.9"))
-#endif
-/**
- * Old way to iterate a block.
- *
- * @deprecated This is an old API. Use rb_block_call() instead.
- * @warning The passed function must at least once call a ruby method
- * (to handle interrupts etc.)
- * @param[in] func1 A function that could yield a value.
- * @param[in,out] data1 Passed to `func1`
- * @param[in] proc A function acts as a block.
- * @param[in,out] data2 Passed to `proc` as the data2 parameter.
- * @return What `func1` returns.
- */
-VALUE rb_iterate(VALUE (*func1)(VALUE), VALUE data1, rb_block_call_func_t proc, VALUE data2);
-
-#ifdef __cplusplus
-namespace ruby {
-namespace backward {
-/**
- * Old way to iterate a block.
- *
- * @deprecated This is an old API. Use rb_block_call() instead.
- * @warning The passed function must at least once call a ruby method
- * (to handle interrupts etc.)
- * @param[in] iter A function that could yield a value.
- * @param[in,out] data1 Passed to `func1`
- * @param[in] bl A function acts as a block.
- * @param[in,out] data2 Passed to `proc` as the data2 parameter.
- * @return What `func1` returns.
- */
-static inline VALUE
-rb_iterate_deprecated(VALUE (*iter)(VALUE), VALUE data1, rb_block_call_func_t bl, VALUE data2)
-{
- return ::rb_iterate(iter, data1, bl, data2);
-}}}
-
-RBIMPL_ATTR_DEPRECATED(("by: rb_block_call since 1.9"))
-VALUE rb_iterate(VALUE (*func1)(VALUE), VALUE data1, rb_block_call_func_t proc, VALUE data2);
-#endif
-
/**
* Identical to rb_funcallv(), except it additionally passes a function as a
* block. When the method yields, `proc` is called with the yielded value as
@@ -337,7 +295,8 @@ VALUE rb_block_call(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_cal
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return What `obj.mid` returns.
*/
VALUE rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t proc, VALUE data2, int kw_splat);
diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h
index 9fc6c39efc..eb9c1d2525 100644
--- a/include/ruby/internal/memory.h
+++ b/include/ruby/internal/memory.h
@@ -408,7 +408,8 @@ typedef uint128_t DSIZE_T;
/**
* @private
*
- * This is an implementation detail of rbimpl_size_mul_overflow().
+ * This is an implementation detail of rbimpl_size_mul_overflow() and
+ * rbimpl_size_add_overflow().
*
* @internal
*
@@ -416,9 +417,9 @@ typedef uint128_t DSIZE_T;
* nothing more than std::variant<std::size_t> if we could use recent C++, but
* reality is we cannot.
*/
-struct rbimpl_size_mul_overflow_tag {
- bool left; /**< Whether overflow happened or not. */
- size_t right; /**< Multiplication result. */
+struct rbimpl_size_overflow_tag {
+ bool overflowed; /**< Whether overflow happened or not. */
+ size_t result; /**< Calculation result. */
};
RBIMPL_SYMBOL_EXPORT_BEGIN()
@@ -572,46 +573,46 @@ RBIMPL_ATTR_CONST()
*
* @param[in] x Arbitrary value.
* @param[in] y Arbitrary value.
- * @return `{ left, right }`, where `left` is whether there is an integer
- * overflow or not, and `right` is a (possibly overflowed) result
- * of `x` * `y`.
+ * @return `{ overflowed, result }`, where `overflowed` is whether there is
+ * an integer overflow or not, and `result` is a (possibly
+ * overflowed) result of `x` * `y`.
*
* @internal
*
* This is in fact also an implementation detail of ruby_xmalloc2() etc.
*/
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
rbimpl_size_mul_overflow(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
+ struct rbimpl_size_overflow_tag ret = { false, 0, };
#if defined(ckd_mul)
- ret.left = ckd_mul(&ret.right, x, y);
+ ret.overflowed = ckd_mul(&ret.result, x, y);
#elif RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
- ret.left = __builtin_mul_overflow(x, y, &ret.right);
+ ret.overflowed = __builtin_mul_overflow(x, y, &ret.result);
#elif defined(DSIZE_T)
RB_GNUC_EXTENSION DSIZE_T dx = x;
RB_GNUC_EXTENSION DSIZE_T dy = y;
RB_GNUC_EXTENSION DSIZE_T dz = dx * dy;
- ret.left = dz > SIZE_MAX;
- ret.right = RBIMPL_CAST((size_t)dz);
+ ret.overflowed = dz > SIZE_MAX;
+ ret.result = RBIMPL_CAST((size_t)dz);
#elif defined(_MSC_VER) && defined(_M_AMD64)
unsigned __int64 dp = 0;
unsigned __int64 dz = _umul128(x, y, &dp);
- ret.left = RBIMPL_CAST((bool)dp);
- ret.right = RBIMPL_CAST((size_t)dz);
+ ret.overflowed = RBIMPL_CAST((bool)dp);
+ ret.result = RBIMPL_CAST((size_t)dz);
#elif defined(_MSC_VER) && defined(_M_ARM64)
- ret.left = __umulh(x, y) != 0;
- ret.right = x * y;
+ ret.overflowed = __umulh(x, y) != 0;
+ ret.result = x * y;
#else
/* https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap */
- ret.left = (y != 0) && (x > SIZE_MAX / y);
- ret.right = x * y;
+ ret.overflowed = (y != 0) && (x > SIZE_MAX / y);
+ ret.result = x * y;
#endif
return ret;
@@ -635,11 +636,11 @@ rbimpl_size_mul_overflow(size_t x, size_t y)
static inline size_t
rbimpl_size_mul_or_raise(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag size =
+ struct rbimpl_size_overflow_tag size =
rbimpl_size_mul_overflow(x, y);
- if (RB_LIKELY(! size.left)) {
- return size.right;
+ if (RB_LIKELY(! size.overflowed)) {
+ return size.result;
}
else {
ruby_malloc_size_overflow(x, y);
@@ -662,33 +663,33 @@ RBIMPL_ATTR_CONST()
*
* @param[in] x Arbitrary value.
* @param[in] y Arbitrary value.
- * @return `{ left, right }`, where `left` is whether there is an integer
- * overflow or not, and `right` is a (possibly overflowed) result
- * of `x` + `y`.
+ * @return `{ overflowed, result }`, where `overflowed` is whether there is
+ * an integer overflow or not, and `result` is a (possibly
+ * overflowed) result of `x` + `y`.
*
* @internal
*/
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
rbimpl_size_add_overflow(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
+ struct rbimpl_size_overflow_tag ret = { false, 0, };
#if defined(ckd_add)
- ret.left = ckd_add(&ret.right, x, y);
+ ret.overflowed = ckd_add(&ret.result, x, y);
#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow)
- ret.left = __builtin_add_overflow(x, y, &ret.right);
+ ret.overflowed = __builtin_add_overflow(x, y, &ret.result);
#elif defined(DSIZE_T)
RB_GNUC_EXTENSION DSIZE_T dx = x;
RB_GNUC_EXTENSION DSIZE_T dy = y;
RB_GNUC_EXTENSION DSIZE_T dz = dx + dy;
- ret.left = dz > SIZE_MAX;
- ret.right = (size_t)dz;
+ ret.overflowed = dz > SIZE_MAX;
+ ret.result = (size_t)dz;
#else
- ret.right = x + y;
- ret.left = ret.right < y;
+ ret.result = x + y;
+ ret.overflowed = ret.result < y;
#endif
@@ -710,11 +711,11 @@ rbimpl_size_add_overflow(size_t x, size_t y)
static inline size_t
rbimpl_size_add_or_raise(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag size =
+ struct rbimpl_size_overflow_tag size =
rbimpl_size_add_overflow(x, y);
- if (RB_LIKELY(!size.left)) {
- return size.right;
+ if (RB_LIKELY(!size.overflowed)) {
+ return size.result;
}
else {
ruby_malloc_add_size_overflow(x, y);
@@ -740,8 +741,7 @@ static inline void *
rb_alloc_tmp_buffer2(volatile VALUE *store, long count, size_t elsize)
{
const size_t total_size = rbimpl_size_mul_or_raise(RBIMPL_CAST((size_t)count), elsize);
- const size_t cnt = (total_size + sizeof(VALUE) - 1) / sizeof(VALUE);
- return rb_alloc_tmp_buffer_with_count(store, total_size, cnt);
+ return rb_alloc_tmp_buffer(store, (long)total_size);
}
RBIMPL_SYMBOL_EXPORT_BEGIN()
diff --git a/include/ruby/internal/newobj.h b/include/ruby/internal/newobj.h
index 6eee2fa5fa..13030ae279 100644
--- a/include/ruby/internal/newobj.h
+++ b/include/ruby/internal/newobj.h
@@ -109,42 +109,4 @@ void rb_singleton_class_attached(VALUE klass, VALUE obj);
void rb_copy_generic_ivar(VALUE clone, VALUE obj);
RBIMPL_SYMBOL_EXPORT_END()
-RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#clone works."))
-/**
- * @deprecated Not sure exactly when but at some time, the implementation of
- * `Object#clone` stopped using this function. It remained
- * untouched for a while, and then @shyouhei realised that they
- * are no longer doing the same thing. It seems nobody seriously
- * uses this function any longer. Let's just abandon it.
- *
- * @param[out] clone The destination object.
- * @param[in] obj The source object.
- */
-static inline void
-rb_clone_setup(VALUE clone, VALUE obj)
-{
- (void)clone;
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#dup works."))
-/**
- * @deprecated Not sure exactly when but at some time, the implementation of
- * `Object#dup` stopped using this function. It remained
- * untouched for a while, and then @shyouhei realised that they
- * are no longer the same thing. It seems nobody seriously uses
- * this function any longer. Let's just abandon it.
- *
- * @param[out] dup The destination object.
- * @param[in] obj The source object.
- */
-static inline void
-rb_dup_setup(VALUE dup, VALUE obj)
-{
- (void)dup;
- (void)obj;
- return;
-}
-
#endif /* RBIMPL_NEWOBJ_H */
diff --git a/include/ruby/internal/scan_args.h b/include/ruby/internal/scan_args.h
index 2dbc1ee7bc..da64678db5 100644
--- a/include/ruby/internal/scan_args.h
+++ b/include/ruby/internal/scan_args.h
@@ -49,11 +49,11 @@
/** Same behaviour as rb_scan_args(). */
#define RB_SCAN_ARGS_PASS_CALLED_KEYWORDS 0
-/** The final argument should be a hash treated as keywords.*/
+/** The final argument must be a hash, which will be treated as keywords. */
#define RB_SCAN_ARGS_KEYWORDS 1
/**
- * Treat a final argument as keywords if it is a hash, and not as keywords
+ * Treat a final argument as keywords if it is a hash, and not as keywords
* otherwise.
*/
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS 3
@@ -68,7 +68,7 @@
/** Do not pass keywords. */
#define RB_NO_KEYWORDS 0
-/** Pass keywords, final argument should be a hash of keywords. */
+/** Pass keywords, final argument must be a hash of keywords. */
#define RB_PASS_KEYWORDS 1
/**
diff --git a/include/ruby/internal/static_assert.h b/include/ruby/internal/static_assert.h
index 7f00bc21eb..30bfd3bb79 100644
--- a/include/ruby/internal/static_assert.h
+++ b/include/ruby/internal/static_assert.h
@@ -30,7 +30,7 @@
# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
# define RBIMPL_STATIC_ASSERT0 static_assert
-#elif defined(__cplusplus) && RBIMPL_COMPILER_SINCE(MSVC, 16, 0, 0)
+#elif defined(__cplusplus) && RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_STATIC_ASSERT0 static_assert
#elif defined(__INTEL_CXX11_MODE__)
diff --git a/include/ruby/internal/stdbool.h b/include/ruby/internal/stdbool.h
index 7f3e6dcf97..5d9026434b 100644
--- a/include/ruby/internal/stdbool.h
+++ b/include/ruby/internal/stdbool.h
@@ -31,17 +31,9 @@
# define __bool_true_false_are_defined
# endif
-#elif defined(HAVE_STDBOOL_H)
-# /* Take stdbool.h definition. */
+#else
+# /* Take stdbool.h definition. It exists since GCC 3.0 and VS 2015. */
# include <stdbool.h>
-
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# /* See also http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2229.htm */
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
#endif
#endif /* RBIMPL_STDBOOL_H */
diff --git a/include/ruby/internal/symbol.h b/include/ruby/internal/symbol.h
index 569bf215a2..8bfd686fbe 100644
--- a/include/ruby/internal/symbol.h
+++ b/include/ruby/internal/symbol.h
@@ -101,12 +101,11 @@ ID rb_intern(const char *name);
ID rb_intern2(const char *name, long len);
/**
- * Identical to rb_intern(), except it takes an instance of ::rb_cString.
+ * Identical to rb_intern(), except it takes a `T_STRING` object.
*
* @param[in] str The name of the id.
- * @pre `str` must either be an instance of ::rb_cSymbol, or an instance
- * of ::rb_cString, or responds to `#to_str` method.
- * @exception rb_eTypeError Can't convert `str` into ::rb_cString.
+ * @pre `rb_type(str)` must be `T_STRING`.
+ * @exception rb_eEncodingError `str` contains invalid character(s).
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given str.
* @note These days Ruby internally has two kinds of symbols
@@ -166,29 +165,34 @@ RBIMPL_ATTR_NONNULL(())
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
- * @exception rb_eEncodingError Given string is non-ASCII.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
* @retval 0 No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
+ * @see rb_str_to_str
* @see https://bugs.ruby-lang.org/issues/5072
- *
- * @internal
- *
- * @shyouhei doesn't know why this has to raise rb_eEncodingError.
*/
ID rb_check_id(volatile VALUE *namep);
/**
- * @copydoc rb_intern_str()
+ * Identical to rb_intern_str(), except it tries to convert the parameter object
+ * to an instance of ::rb_cString or its subclasses.
*
- * @internal
- *
- * :FIXME: Can anyone tell us what is the difference between this one and
- * rb_intern_str()? As far as @shyouhei reads the implementation it seems what
- * rb_to_id() does is is just waste some CPU time, then call rb_intern_str().
- * He hopes he is wrong.
+ * @param[in] str The name of the id.
+ * @pre `str` must either be an instance of ::rb_cSymbol, or an instance
+ * of ::rb_cString, or responds to `#to_str` method.
+ * @exception rb_eTypeError Can't convert `str` into ::rb_cString.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
+ * @exception rb_eRuntimeError Too many symbols.
+ * @return A (possibly new) id whose value is the given str.
+ * @note These days Ruby internally has two kinds of symbols
+ * (static/dynamic). Symbols created using this function would
+ * become static ones; i.e. would never be garbage collected. It
+ * is up to you to avoid memory leaks. Think twice before using
+ * it.
+ * @see rb_str_to_str
*/
ID rb_to_id(VALUE str);
@@ -245,17 +249,14 @@ RBIMPL_ATTR_NONNULL(())
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
- * @exception rb_eEncodingError Given string is non-ASCII.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
* @retval RUBY_Qnil No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
* @see https://bugs.ruby-lang.org/issues/5072
- *
- * @internal
- *
- * @shyouhei doesn't know why this has to raise rb_eEncodingError.
+ * @see rb_str_to_str
*/
VALUE rb_check_symbol(volatile VALUE *namep);
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/internal/value_type.h b/include/ruby/internal/value_type.h
index aedd0abe4b..77cb38bc7d 100644
--- a/include/ruby/internal/value_type.h
+++ b/include/ruby/internal/value_type.h
@@ -130,8 +130,8 @@ ruby_value_type {
RUBY_T_RATIONAL = 0x0f, /**< @see struct ::RRational */
RUBY_T_NIL = 0x11, /**< @see ::RUBY_Qnil */
- RUBY_T_TRUE = 0x12, /**< @see ::RUBY_Qfalse */
- RUBY_T_FALSE = 0x13, /**< @see ::RUBY_Qtrue */
+ RUBY_T_TRUE = 0x12, /**< @see ::RUBY_Qtrue */
+ RUBY_T_FALSE = 0x13, /**< @see ::RUBY_Qfalse */
RUBY_T_SYMBOL = 0x14, /**< @see struct ::RSymbol */
RUBY_T_FIXNUM = 0x15, /**< Integers formerly known as Fixnums. */
RUBY_T_UNDEF = 0x16, /**< @see ::RUBY_Qundef */
@@ -410,14 +410,6 @@ RB_TYPE_P(VALUE obj, enum ruby_value_type t)
#endif
/** @endcond */
-RBIMPL_ATTR_PURE()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * @private
- * Defined in ruby/internal/core/rtypeddata.h
- */
-static inline bool rbimpl_rtypeddata_p(VALUE obj);
-
RBIMPL_ATTR_ARTIFICIAL()
/**
* Identical to RB_TYPE_P(), except it raises exceptions on predication
@@ -432,19 +424,11 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline void
Check_Type(VALUE v, enum ruby_value_type t)
{
+ /* Typed data is not simple `T_DATA`, see `rb_check_type` */
+ RUBY_ASSERT_ALWAYS(t != RUBY_T_DATA);
if (RB_UNLIKELY(! RB_TYPE_P(v, t))) {
- goto unexpected_type;
+ rb_unexpected_type(v, RBIMPL_CAST((int)t));
}
- else if (t == RUBY_T_DATA && rbimpl_rtypeddata_p(v)) {
- /* Typed data is not simple `T_DATA`, see `rb_check_type` */
- goto unexpected_type;
- }
- else {
- return;
- }
-
- unexpected_type:
- rb_unexpected_type(v, RBIMPL_CAST((int)t));
}
#endif /* RBIMPL_VALUE_TYPE_H */
diff --git a/include/ruby/internal/warning_push.h b/include/ruby/internal/warning_push.h
index f5981633f8..91d62cb00d 100644
--- a/include/ruby/internal/warning_push.h
+++ b/include/ruby/internal/warning_push.h
@@ -79,7 +79,7 @@
*/
#define RBIMPL_WARNING_IGNORED(flag) __pragma(warning(disable: flag))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# /* Not sure exactly when but it seems VC++ 6.0 is a version with it.*/
# define RBIMPL_WARNING_PUSH() __pragma(warning(push))
# define RBIMPL_WARNING_POP() __pragma(warning(pop))
diff --git a/include/ruby/internal/xmalloc.h b/include/ruby/internal/xmalloc.h
index 132bc478ce..2551609123 100644
--- a/include/ruby/internal/xmalloc.h
+++ b/include/ruby/internal/xmalloc.h
@@ -57,6 +57,10 @@
#define xrealloc2 ruby_xrealloc2 /**< @old{ruby_xrealloc2} */
#define xfree ruby_xfree /**< @old{ruby_xfree} */
+#define xfree_sized ruby_xfree_sized
+#define xrealloc_sized ruby_xrealloc_sized
+#define xrealloc2_sized ruby_xrealloc2_sized
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NODISCARD()
@@ -196,6 +200,58 @@ RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
RBIMPL_ATTR_NODISCARD()
RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((2))
+/**
+ * Identical to ruby_xrealloc(), except that it takes the old storage size
+ * as third argument.
+ *
+ * @param[in] ptr A valid pointer to a storage instance that was
+ * previously returned from either:
+ * - ruby_xmalloc(),
+ * - ruby_xmalloc2(),
+ * - ruby_xcalloc(),
+ * - ruby_xrealloc(), or
+ * - ruby_xrealloc2().
+ * @param[in] newsiz Requested new amount of memory.
+ * @param[in] oldsiz Existing amount of memory.
+ * @exception rb_eNoMemError No space left for `newsiz` bytes allocation.
+ * @return A valid pointer to a (possibly newly allocated) storage
+ * instance; which has at least `newsiz` bytes width, with
+ * appropriate alignment detected by the underlying realloc()
+ * routine.
+ * @pre The passed pointer must point to a valid live storage instance.
+ * It is a failure to pass an already freed pointer.
+ * @pre The passed oldsiz must be exactly equal to the size the pointer
+ * was allocated with.
+ * Passing an incorrect oldsiz is undefined behavior, which may
+ * cause memory leaks or crashes.
+ * @post In case the function returns the passed pointer as-is, the
+ * storage instance that the pointer holds is either grown or
+ * shrunken to have at least `newsiz` bytes. Otherwise a valid
+ * pointer to a newly allocated storage instance is returned. In
+ * this case `ptr` is invalidated as if it was passed to
+ * ruby_xfree().
+ * @note It doesn't return NULL.
+ * @warning Unlike some realloc() implementations, passing zero to `newsiz`
+ * is not the same as calling ruby_xfree(), because this function
+ * never returns NULL. Something meaningful still returns then.
+ * @warning It is a failure not to check the return value. Do not assume
+ * anything on it. It could be either identical to, or distinct
+ * form the passed argument.
+ * @warning Do not assume anything on the alignment of the return value.
+ * There is no guarantee that it inherits the passed argument's
+ * one.
+ * @warning The return value shall be invalidated exactly once by either
+ * ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
+ * failure to pass it to system free(), because the system and Ruby
+ * might or might not share the same malloc() implementation.
+ */
+void *ruby_xrealloc_sized(void *ptr, size_t newsiz, size_t oldsiz)
+RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
+;
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RETURNS_NONNULL()
RBIMPL_ATTR_ALLOC_SIZE((2,3))
/**
* Identical to ruby_xrealloc(), except it resizes the given storage instance
@@ -251,6 +307,64 @@ void *ruby_xrealloc2(void *ptr, size_t newelems, size_t newsiz)
RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
;
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((2,3))
+/**
+ * Identical to ruby_xrealloc2(), except it takes the old elements count.
+ *
+ * This is roughly the same as reallocarray() function that OpenBSD
+ * etc. provides, but also interacts with our GC.
+ *
+ * @param[in] ptr A valid pointer to a storage instance that was
+ * previously returned from either:
+ * - ruby_xmalloc(),
+ * - ruby_xmalloc2(),
+ * - ruby_xcalloc(),
+ * - ruby_xrealloc(), or
+ * - ruby_xrealloc2().
+ * @param[in] newelems Requested new number of elements.
+ * @param[in] newsiz Requested new size of each element.
+ * @param[in] oldelems The number of elements the pointer was
+ * previously allocated with.
+ * @exception rb_eNoMemError No space left for allocation.
+ * @exception rb_eArgError `newelems` * `newsiz` would overflow.
+ * @return A valid pointer to a (possibly newly allocated) storage
+ * instance; which has at least `newelems` * `newsiz` bytes width,
+ * with appropriate alignment detected by the underlying realloc()
+ * routine.
+ * @pre The passed pointer must point to a valid live storage instance.
+ * It is a failure to pass an already freed pointer.
+ * @pre The passed oldelems must be exactly equal to the number of
+ * elements the pointer was allocated with.
+ * Passing an incorrect oldelems is undefined behavior, which may
+ * cause memory leaks or crashes.
+ * @post In case the function returns the passed pointer as-is, the
+ * storage instance that the pointer holds is either grown or
+ * shrunken to have at least `newelems` * `newsiz` bytes.
+ * Otherwise a valid pointer to a newly allocated storage instance
+ * is returned. In this case `ptr` is invalidated as if it was
+ * passed to ruby_xfree().
+ * @note It doesn't return NULL.
+ * @warning Unlike some realloc() implementations, passing zero to either
+ * `newelems` or `elemsiz` are not the same as calling
+ * ruby_xfree(), because this function never returns NULL.
+ * Something meaningful still returns then.
+ * @warning It is a failure not to check the return value. Do not assume
+ * anything on it. It could be either identical to, or distinct
+ * form the passed argument.
+ * @warning Do not assume anything on the alignment of the return value.
+ * There is no guarantee that it inherits the passed argument's
+ * one.
+ * @warning The return value shall be invalidated exactly once by either
+ * ruby_xfree(), ruby_xrealloc(), or ruby_xrealloc2(). It is a
+ * failure to pass it to system free(), because the system and Ruby
+ * might or might not share the same malloc() implementation.
+ */
+void *ruby_xrealloc2_sized(void *ptr, size_t newelems, size_t newsiz, size_t oldelems)
+RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
+;
+
/**
* Deallocates a storage instance.
*
@@ -283,6 +397,43 @@ void ruby_xfree(void *ptr)
RBIMPL_ATTR_NOEXCEPT(free(ptr))
;
+/**
+ * Deallocates a storage instance of a specific ssize.
+ *
+ * @param[out] ptr Either
+ * - NULL, or
+ * - a valid pointer previously returned from one of:
+ * - ruby_xmalloc(),
+ * - ruby_xmalloc2(),
+ * - ruby_xcalloc(),
+ * - ruby_xrealloc(), or
+ * - ruby_xrealloc2().
+ * @pre The passed pointer must point to a valid live storage instance.
+ * It is a failure to pass an already freed pointer.
+ * @pre The passed size must be exactly equal to the size the pointer
+ * was allocated with.
+ * Passing an incorrect size is undefined behavior, which may
+ * cause memory leaks or crashes.
+ * @post The storage instance pointed by the passed pointer gets
+ * invalidated; it is no longer addressable.
+ * @warning Every single storage instance that was previously allocated by
+ * either ruby_xmalloc(), ruby_xmalloc2(), ruby_xcalloc(),
+ * ruby_xrealloc(), or ruby_xrealloc2() shall be invalidated
+ * exactly once by either passing it to ruby_xfree(), or passing
+ * it to either ruby_xrealloc(), ruby_xrealloc2() then check the
+ * return value for invalidation.
+ * @warning Do not pass anything other than pointers described above. For
+ * instance pointers returned from malloc() or mmap() shall not be
+ * passed to this function, because the underlying memory
+ * management mechanism could differ.
+ * @warning Do not pass any invalid pointers to this function e.g. by
+ * calling it twice with a same argument.
+ */
+void ruby_xfree_sized(void *ptr, size_t size)
+RBIMPL_ATTR_NOEXCEPT(free(ptr))
+;
+
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_XMALLOC_H */
diff --git a/include/ruby/io.h b/include/ruby/io.h
index d2fd3ed317..ed0967abad 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -66,6 +66,21 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
struct stat;
struct timeval;
+#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
+# define RUBY_USE_STATX 0
+#elif defined(HAVE_STRUCT_STATX_STX_BTIME)
+# define RUBY_USE_STATX 1
+struct statx;
+#else
+# define RUBY_USE_STATX 0
+#endif
+
+#if RUBY_USE_STATX
+typedef struct statx rb_io_stat_data;
+#else
+typedef struct stat rb_io_stat_data;
+#endif
+
/**
* Indicates that a timeout has occurred while performing an IO operation.
*/
@@ -137,6 +152,143 @@ struct rb_io_encoding {
VALUE ecopts;
};
+/**
+ * @name Possible flags for ::rb_io_t::mode
+ *
+ * @{
+ */
+
+/** The IO is opened for reading. */
+#define FMODE_READABLE 0x00000001
+
+/** The IO is opened for writing. */
+#define FMODE_WRITABLE 0x00000002
+
+/** The IO is opened for both read/write. */
+#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE)
+
+/**
+ * The IO is in "binary mode". This is not what everything rb_io_binmode()
+ * concerns. This low-level flag is to stop CR <-> CRLF conversions that would
+ * happen in the underlying operating system.
+ *
+ * Setting this one and #FMODE_TEXTMODE at the same time is a contradiction.
+ * Setting this one and #ECONV_NEWLINE_DECORATOR_MASK at the same time is also
+ * a contradiction.
+ */
+#define FMODE_BINMODE 0x00000004
+
+/**
+ * The IO is in "sync mode". All output is immediately flushed to the
+ * underlying operating system then. Can be set via rb_io_synchronized(), but
+ * there is no way except calling `IO#sync=` to reset.
+ */
+#define FMODE_SYNC 0x00000008
+
+/**
+ * The IO is a TTY. What is a TTY and what isn't depends on the underlying
+ * operating system's `isatty(3)` output. You cannot change this.
+ */
+#define FMODE_TTY 0x00000010
+
+/**
+ * Ruby eventually detects that the IO is bidirectional. For instance a TTY
+ * has such property. There are several other things known to be duplexed.
+ * Additionally you (extension library authors) can also implement your own
+ * bidirectional IO subclasses. One of such example is `Socket`.
+ */
+#define FMODE_DUPLEX 0x00000020
+
+/**
+ * The IO is opened for appending. This mode always writes at the end of the
+ * IO. Ruby manages this flag for record but basically the logic behind this
+ * mode is at the underlying operating system. We almost do nothing.
+ */
+#define FMODE_APPEND 0x00000040
+
+/**
+ * The IO is opened for creating. This makes sense only when the destination
+ * file does not exist at the time the IO object was created. This is the
+ * default mode for writing, but you can pass `"r+"` to `IO.open` etc., to
+ * reroute this creation.
+ */
+#define FMODE_CREATE 0x00000080
+/* #define FMODE_NOREVLOOKUP 0x00000100 */
+
+/**
+ * This flag amends the effect of #FMODE_CREATE, so that if there already is a
+ * file at the given path the operation fails. Using this you can be sure that
+ * the file you get is a fresh new one.
+ */
+#define FMODE_EXCL 0x00000400
+
+/**
+ * This flag amends the effect of #FMODE_CREATE, so that if there already is a
+ * file at the given path it gets truncated.
+ */
+#define FMODE_TRUNC 0x00000800
+
+/**
+ * The IO is in "text mode". On systems where such mode make sense, this flag
+ * changes the way the IO handles the contents. On POSIX systems it is
+ * basically a no-op, but with this flag set you can optionally let Ruby
+ * manually convert newlines, unlike when in binary mode:
+ *
+ * ```ruby
+ * IO.open("/p/a/t/h", "wt", crlf_newline: true) # "wb" is NG.
+ * ```
+ *
+ * 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_SIGNAL_ON_EPIPE 0x00020000 */
+
+/**
+ * This flag amends the encoding of the IO so that the BOM of the contents of
+ * the IO takes effect.
+ */
+#define FMODE_SETENC_BY_BOM 0x00100000
+/* #define FMODE_UNIX 0x00200000 */
+/* #define FMODE_INET 0x00400000 */
+/* #define FMODE_INET6 0x00800000 */
+
+/** @} */
+
+enum rb_io_mode {
+ RUBY_IO_MODE_EXTERNAL = FMODE_EXTERNAL,
+
+ RUBY_IO_MODE_READABLE = FMODE_READABLE,
+ RUBY_IO_MODE_WRITABLE = FMODE_WRITABLE,
+ RUBY_IO_MODE_READABLE_WRITABLE = (RUBY_IO_MODE_READABLE|RUBY_IO_MODE_WRITABLE),
+
+ RUBY_IO_MODE_BINARY = FMODE_BINMODE,
+ RUBY_IO_MODE_TEXT = FMODE_TEXTMODE,
+ RUBY_IO_MODE_TEXT_SET_ENCODING_FROM_BOM = FMODE_SETENC_BY_BOM,
+
+ RUBY_IO_MODE_SYNCHRONISED = FMODE_SYNC,
+
+ RUBY_IO_MODE_TTY = FMODE_TTY,
+
+ RUBY_IO_MODE_DUPLEX = FMODE_DUPLEX,
+
+ RUBY_IO_MODE_APPEND = FMODE_APPEND,
+ RUBY_IO_MODE_CREATE = FMODE_CREATE,
+ RUBY_IO_MODE_EXCLUSIVE = FMODE_EXCL,
+ RUBY_IO_MODE_TRUNCATE = FMODE_TRUNC,
+};
+
+typedef enum rb_io_mode rb_io_mode_t;
+
#ifndef HAVE_RB_IO_T
#define HAVE_RB_IO_T 1
/** Ruby's IO, metadata and buffers. */
@@ -155,7 +307,7 @@ struct rb_io {
/** mode flags: FMODE_XXXs */
RBIMPL_ATTR_DEPRECATED(("rb_io_mode"))
- int mode;
+ enum rb_io_mode mode;
/** child's pid (for pipes) */
RBIMPL_ATTR_DEPRECATED(("with no replacement"))
@@ -261,118 +413,6 @@ typedef struct rb_io rb_io_t;
typedef struct rb_io_encoding rb_io_enc_t;
/**
- * @name Possible flags for ::rb_io_t::mode
- *
- * @{
- */
-
-/** The IO is opened for reading. */
-#define FMODE_READABLE 0x00000001
-
-/** The IO is opened for writing. */
-#define FMODE_WRITABLE 0x00000002
-
-/** The IO is opened for both read/write. */
-#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE)
-
-/**
- * The IO is in "binary mode". This is not what everything rb_io_binmode()
- * concerns. This low-level flag is to stop CR <-> CRLF conversions that would
- * happen in the underlying operating system.
- *
- * Setting this one and #FMODE_TEXTMODE at the same time is a contradiction.
- * Setting this one and #ECONV_NEWLINE_DECORATOR_MASK at the same time is also
- * a contradiction.
- */
-#define FMODE_BINMODE 0x00000004
-
-/**
- * The IO is in "sync mode". All output is immediately flushed to the
- * underlying operating system then. Can be set via rb_io_synchronized(), but
- * there is no way except calling `IO#sync=` to reset.
- */
-#define FMODE_SYNC 0x00000008
-
-/**
- * The IO is a TTY. What is a TTY and what isn't depends on the underlying
- * operating system's `isatty(3)` output. You cannot change this.
- */
-#define FMODE_TTY 0x00000010
-
-/**
- * Ruby eventually detects that the IO is bidirectional. For instance a TTY
- * has such property. There are several other things known to be duplexed.
- * Additionally you (extension library authors) can also implement your own
- * bidirectional IO subclasses. One of such example is `Socket`.
- */
-#define FMODE_DUPLEX 0x00000020
-
-/**
- * The IO is opened for appending. This mode always writes at the end of the
- * IO. Ruby manages this flag for record but basically the logic behind this
- * mode is at the underlying operating system. We almost do nothing.
- */
-#define FMODE_APPEND 0x00000040
-
-/**
- * The IO is opened for creating. This makes sense only when the destination
- * file does not exist at the time the IO object was created. This is the
- * default mode for writing, but you can pass `"r+"` to `IO.open` etc., to
- * reroute this creation.
- */
-#define FMODE_CREATE 0x00000080
-/* #define FMODE_NOREVLOOKUP 0x00000100 */
-
-/**
- * This flag amends the effect of #FMODE_CREATE, so that if there already is a
- * file at the given path the operation fails. Using this you can be sure that
- * the file you get is a fresh new one.
- */
-#define FMODE_EXCL 0x00000400
-
-/**
- * This flag amends the effect of #FMODE_CREATE, so that if there already is a
- * file at the given path it gets truncated.
- */
-#define FMODE_TRUNC 0x00000800
-
-/**
- * The IO is in "text mode". On systems where such mode make sense, this flag
- * changes the way the IO handles the contents. On POSIX systems it is
- * basically a no-op, but with this flag set you can optionally let Ruby
- * manually convert newlines, unlike when in binary mode:
- *
- * ```ruby
- * IO.open("/p/a/t/h", "wt", crlf_newline: true) # "wb" is NG.
- * ```
- *
- * 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_SIGNAL_ON_EPIPE 0x00020000 */
-
-/**
- * This flag amends the encoding of the IO so that the BOM of the contents of
- * the IO takes effect.
- */
-#define FMODE_SETENC_BY_BOM 0x00100000
-/* #define FMODE_UNIX 0x00200000 */
-/* #define FMODE_INET 0x00400000 */
-/* #define FMODE_INET6 0x00800000 */
-
-/** @} */
-
-/**
* 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);
@@ -525,7 +565,7 @@ FILE *rb_fdopen(int fd, const char *modestr);
*
* rb_io_modestr_fmode() is not a pure function because it raises.
*/
-int rb_io_modestr_fmode(const char *modestr);
+enum rb_io_mode rb_io_modestr_fmode(const char *modestr);
/**
* Identical to rb_io_modestr_fmode(), except it returns a mixture of `O_`
@@ -780,7 +820,7 @@ int rb_io_mode(VALUE io);
* @post `enc2_p` is the specified external encoding.
* @post `fmode_p` is the specified set of `FMODE_` modes.
*/
-int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p);
+int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p);
/**
* This function can be seen as an extended version of
@@ -849,7 +889,7 @@ int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **
* ) -> void
* ```
*/
-void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p);
+void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p);
/* :TODO: can this function be __attribute__((warn_unused_result)) or not? */
/**
@@ -1073,6 +1113,18 @@ int rb_io_read_pending(rb_io_t *fptr);
*/
VALUE rb_stat_new(const struct stat *st);
+#if RUBY_USE_STATX
+/**
+ * Constructs an instance of ::rb_cStat from the passed information.
+ *
+ * @param[in] st A stat.
+ * @return Allocated new instance of ::rb_cStat.
+ */
+VALUE rb_statx_new(const rb_io_stat_data *st);
+#else
+# define rb_statx_new rb_stat_new
+#endif
+
/* gc.c */
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/onigmo.h b/include/ruby/onigmo.h
index db290cd47a..5c2ebe55fe 100644
--- a/include/ruby/onigmo.h
+++ b/include/ruby/onigmo.h
@@ -4,8 +4,8 @@
onigmo.h - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2009 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2017 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2016 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,8 @@ extern "C" {
#endif
#define ONIGMO_VERSION_MAJOR 6
-#define ONIGMO_VERSION_MINOR 1
-#define ONIGMO_VERSION_TEENY 3
+#define ONIGMO_VERSION_MINOR 2
+#define ONIGMO_VERSION_TEENY 0
#ifndef ONIG_EXTERN
# ifdef RUBY_EXTERN
@@ -687,6 +687,8 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax;
#define ONIGERR_NEVER_ENDING_RECURSION -221
#define ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY -222
#define ONIGERR_INVALID_CHAR_PROPERTY_NAME -223
+#define ONIGERR_TOO_MANY_RANGE_REPEAT -224
+#define ONIGERR_TOO_MANY_NULL_CHECK -225
#define ONIGERR_INVALID_CODE_POINT_VALUE -400
#define ONIGERR_INVALID_WIDE_CHAR_VALUE -400
#define ONIGERR_TOO_BIG_WIDE_CHAR_VALUE -401
@@ -789,8 +791,8 @@ typedef struct re_pattern_buffer {
unsigned char *exact;
unsigned char *exact_end;
unsigned char map[ONIG_CHAR_TABLE_SIZE]; /* used as BM skip or char-map */
- int *int_map; /* BM skip for exact_len > 255 */
- int *int_map_backward; /* BM skip for backward search */
+ int *reserved1;
+ int *reserved2;
OnigDistance dmin; /* min-distance of exact or map */
OnigDistance dmax; /* max-distance of exact or map */
diff --git a/include/ruby/ractor.h b/include/ruby/ractor.h
index 7811616f6d..8cfca21621 100644
--- a/include/ruby/ractor.h
+++ b/include/ruby/ractor.h
@@ -217,7 +217,7 @@ VALUE rb_ractor_make_shareable(VALUE obj);
*
* @param[in] obj Arbitrary ruby object to duplicate.
* @exception rb_eRactorError Ractors cannot share `obj` by nature.
- * @return A deep copy of `obj` which is sharable among Ractors.
+ * @return A deep copy of `obj` which is shareable among Ractors.
*/
VALUE rb_ractor_make_shareable_copy(VALUE obj);
@@ -261,4 +261,18 @@ rb_ractor_shareable_p(VALUE obj)
}
}
+// TODO: optimize on interpreter core
+#ifndef RB_OBJ_SET_SHAREABLE
+VALUE rb_obj_set_shareable(VALUE obj); // ractor.c
+#define RB_OBJ_SET_SHAREABLE(obj) rb_obj_set_shareable(obj)
+#endif
+
+static inline VALUE
+RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
+{
+ RB_OBJ_FREEZE(obj);
+ RB_OBJ_SET_SHAREABLE(obj);
+ return obj;
+}
+
#endif /* RUBY_RACTOR_H */
diff --git a/include/ruby/random.h b/include/ruby/random.h
index f3df0d96fb..3b63a23334 100644
--- a/include/ruby/random.h
+++ b/include/ruby/random.h
@@ -332,7 +332,8 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG()
static inline const rb_random_interface_t *
rb_rand_if(VALUE obj)
{
- RBIMPL_ASSERT_OR_ASSUME(RTYPEDDATA_P(obj));
+ RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(obj, T_DATA));
+ RUBY_ASSERT(rb_typeddata_is_kind_of(obj, &rb_random_data_type));
const struct rb_data_type_struct *t = RTYPEDDATA_TYPE(obj);
const void *ret = t->data;
return RBIMPL_CAST((const rb_random_interface_t *)ret);
diff --git a/include/ruby/st.h b/include/ruby/st.h
index f35ab43603..b510989b6b 100644
--- a/include/ruby/st.h
+++ b/include/ruby/st.h
@@ -84,13 +84,12 @@ struct st_table {
const struct st_hash_type *type;
/* Number of entries currently in the table. */
st_index_t num_entries;
- /* Array of bins used for access by keys. */
- st_index_t *bins;
/* Start and bound index of entries in array entries.
entries_starts and entries_bound are in interval
[0,allocated_entries]. */
st_index_t entries_start, entries_bound;
- /* Array of size 2^entry_power. */
+ /* Array of size 2^entry_power.
+ Optionnally followed by an array of bins used for access by keys. */
st_table_entry *entries;
};
diff --git a/include/ruby/thread.h b/include/ruby/thread.h
index 7cbefc9777..2fa01229e2 100644
--- a/include/ruby/thread.h
+++ b/include/ruby/thread.h
@@ -333,6 +333,13 @@ void *rb_internal_thread_specific_get(VALUE thread_val, rb_internal_thread_speci
*/
void rb_internal_thread_specific_set(VALUE thread_val, rb_internal_thread_specific_key_t key, void *data);
+/**
+ * Whether the current thread is holding the GVL.
+ *
+ * @return true if the current thread is holding the GVL, false otherwise.
+ */
+int ruby_thread_has_gvl_p(void);
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_THREAD_H */
diff --git a/include/ruby/version.h b/include/ruby/version.h
index a521d925ed..5bb381cea2 100644
--- a/include/ruby/version.h
+++ b/include/ruby/version.h
@@ -61,13 +61,13 @@
* doesn't mean a total rewrite. Practically when it comes to API versioning,
* major and minor version changes are equally catastrophic.
*/
-#define RUBY_API_VERSION_MAJOR 3
+#define RUBY_API_VERSION_MAJOR 4
/**
* 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 5
+#define RUBY_API_VERSION_MINOR 1
/**
* 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 27a3467606..ae11a61481 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -30,15 +30,10 @@ extern "C++" { /* template without extern "C++" */
#if !defined(_WIN64) && !defined(WIN32)
#define WIN32
#endif
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
-#if !defined(_MSC_VER) || _MSC_VER >= 1400
#include <iphlpapi.h>
-#endif
#if defined(__cplusplus) && defined(_MSC_VER)
}
#endif
@@ -59,13 +54,7 @@ extern "C++" { /* template without extern "C++" */
#include <direct.h>
#include <process.h>
#include <time.h>
-#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200
-extern "C++" { /* template without extern "C++" */
-#endif
#include <math.h>
-#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200
-}
-#endif
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -126,8 +115,30 @@ typedef unsigned int uintptr_t;
#define O_SHARE_DELETE 0x20000000 /* for rb_w32_open(), rb_w32_wopen() */
typedef int clockid_t;
-#define CLOCK_REALTIME 0
-#define CLOCK_MONOTONIC 1
+
+/*
+ * Since we use our versions in win32/win32.c, not to depend on yet
+ * another DLL, prefix our versions not to conflict with inline
+ * versions provided in time.h.
+ */
+#define clock_gettime rb_w32_clock_gettime
+#define clock_getres rb_w32_clock_getres
+
+#ifndef CLOCK_REALTIME
+# define CLOCK_REALTIME 0
+#endif
+#ifndef CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC 1
+#endif
+#ifndef CLOCK_PROCESS_CPUTIME_ID
+# define CLOCK_PROCESS_CPUTIME_ID 2
+#endif
+#ifndef CLOCK_THREAD_CPUTIME_ID
+# define CLOCK_THREAD_CPUTIME_ID 3
+#endif
+#ifndef CLOCK_REALTIME_COARSE
+# define CLOCK_REALTIME_COARSE 4
+#endif
#undef utime
#undef lseek
@@ -251,7 +262,6 @@ struct ifaddrs {
#endif
extern void rb_w32_sysinit(int *, char ***);
-extern DWORD rb_w32_osid(void);
extern int flock(int fd, int oper);
extern int rb_w32_io_cancelable_p(int);
extern int rb_w32_is_socket(int);
@@ -295,7 +305,11 @@ extern void rb_w32_free_environ(char **);
extern int rb_w32_map_errno(DWORD);
extern const char *WSAAPI rb_w32_inet_ntop(int,const void *,char *,size_t);
extern int WSAAPI rb_w32_inet_pton(int,const char *,void *);
-extern DWORD rb_w32_osver(void);
+
+RBIMPL_ATTR_DEPRECATED(("as Windows 9x is not supported already"))
+static inline DWORD rb_w32_osid(void) {return VER_PLATFORM_WIN32_NT;}
+RBIMPL_ATTR_DEPRECATED(("by Windows Version Helper APIs"))
+extern DWORD rb_w32_osver(void);
extern int rb_w32_uchown(const char *, int, int);
extern int rb_w32_ulink(const char *, const char *);
@@ -331,7 +345,7 @@ extern int rb_w32_dup2(int, int);
#include <float.h>
-#if defined _MSC_VER && _MSC_VER >= 1800 && defined INFINITY
+#if defined _MSC_VER && defined INFINITY
#pragma warning(push)
#pragma warning(disable:4756)
static inline float
@@ -414,11 +428,6 @@ extern int rb_w32_utruncate(const char *path, rb_off_t length);
#define HAVE_TRUNCATE 1
#define truncate rb_w32_utruncate
-#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1800
-#define strtoll _strtoi64
-#define strtoull _strtoui64
-#endif
-
/*
* stubs
*/
diff --git a/inits.c b/inits.c
index 947029f232..4988fa09d0 100644
--- a/inits.c
+++ b/inits.c
@@ -52,6 +52,8 @@ rb_call_inits(void)
CALL(Time);
CALL(Random);
CALL(load);
+ CALL(Ruby_module);
+ CALL(Box);
CALL(Proc);
CALL(Binding);
CALL(Math);
@@ -63,18 +65,21 @@ rb_call_inits(void)
CALL(ISeq);
CALL(Thread);
CALL(signal);
+ CALL(Cont);
CALL(Fiber_Scheduler);
CALL(process);
- CALL(Cont);
CALL(Rational);
CALL(Complex);
CALL(MemoryView);
+ CALL(pathname);
CALL(version);
CALL(vm_trace);
CALL(vm_stack_canary);
CALL(ast);
CALL(shape);
CALL(Prism);
+ CALL(unicode_version);
+ CALL(Set);
// enable builtin loading
CALL(builtin);
@@ -84,9 +89,10 @@ void
rb_call_builtin_inits(void)
{
#define BUILTIN(n) CALL(builtin_##n)
- BUILTIN(kernel);
+ BUILTIN(jit_hook);
BUILTIN(yjit);
- // BUILTIN(yjit_hook) is called after rb_yjit_init()
+ BUILTIN(zjit);
+ BUILTIN(kernel);
BUILTIN(gc);
BUILTIN(ractor);
BUILTIN(numeric);
@@ -95,6 +101,7 @@ rb_call_builtin_inits(void)
BUILTIN(ast);
BUILTIN(trace_point);
BUILTIN(pack);
+ BUILTIN(pathname_builtin);
BUILTIN(warning);
BUILTIN(array);
BUILTIN(hash);
@@ -103,6 +110,7 @@ rb_call_builtin_inits(void)
BUILTIN(thread_sync);
BUILTIN(nilclass);
BUILTIN(marshal);
+ BUILTIN(jit_undef);
Init_builtin_prelude();
}
#undef CALL
diff --git a/insns.def b/insns.def
index 0f2c225b66..3ad378081a 100644
--- a/insns.def
+++ b/insns.def
@@ -145,6 +145,7 @@ getblockparamproxy
(lindex_t idx, rb_num_t level)
()
(VALUE val)
+// attr bool zjit_profile = true;
{
const VALUE *ep = vm_get_ep(GET_EP(), level);
VM_ASSERT(VM_ENV_LOCAL_P(ep));
@@ -212,6 +213,7 @@ getinstancevariable
(VALUE val)
/* Ractor crashes when it accesses class/module-level instances variables. */
// attr bool leaf = false; /* has IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() */
+// attr bool zjit_profile = true;
{
val = vm_getinstancevariable(GET_ISEQ(), GET_SELF(), id, ic);
}
@@ -223,6 +225,7 @@ setinstancevariable
(VALUE val)
()
// attr bool leaf = false; /* has rb_check_frozen() */
+// attr bool zjit_profile = true;
{
vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id, val, ic);
}
@@ -370,7 +373,7 @@ putspecialobject
/* put string val. string will be copied. */
DEFINE_INSN
-putstring
+dupstring
(VALUE str)
()
(VALUE val)
@@ -380,7 +383,7 @@ putstring
/* put chilled string val. string will be copied but frozen in the future. */
DEFINE_INSN
-putchilledstring
+dupchilledstring
(VALUE str)
()
(VALUE val)
@@ -426,9 +429,7 @@ toregexp
// attr bool leaf = false;
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)cnt;
{
- const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, STACK_ADDR_FROM_TOP(cnt));
- val = rb_reg_new_ary(ary, (int)opt);
- rb_ary_clear(ary);
+ val = rb_reg_new_from_values(cnt, STACK_ADDR_FROM_TOP(cnt), (int)opt);
}
/* intern str to Symbol and push it. */
@@ -566,6 +567,7 @@ splatkw
(VALUE hash, VALUE block)
(VALUE obj, VALUE block)
// attr bool leaf = false; /* has rb_to_hash_type() */
+// attr bool zjit_profile = true;
{
if (NIL_P(hash)) {
obj = Qnil;
@@ -587,8 +589,7 @@ newhash
RUBY_DTRACE_CREATE_HOOK(HASH, num);
if (num) {
- val = rb_hash_new_with_size(num / 2);
- rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
+ val = rb_hash_new_with_bulk_insert(num, STACK_ADDR_FROM_TOP(num));
}
else {
val = rb_hash_new();
@@ -744,6 +745,7 @@ definedivar
()
(VALUE val)
// attr bool leaf = false;
+// attr bool zjit_profile = true;
{
val = Qnil;
if (!UNDEF_P(vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef))) {
@@ -802,13 +804,20 @@ defineclass
(VALUE val)
{
VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super);
+ const rb_box_t *box = rb_current_box();
rb_iseq_check(class_iseq);
+ rb_cref_t *cref = vm_cref_push(ec, klass, NULL, FALSE, FALSE);
+
+ if (VM_DEFINECLASS_DYNAMIC_CREF_P(flags)) {
+ CREF_DYNAMIC_SET(cref);
+ }
+
/* enter scope */
vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass,
- GET_BLOCK_HANDLER(),
- (VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE),
+ GC_GUARDED_PTR(box),
+ (VALUE)cref,
ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(),
ISEQ_BODY(class_iseq)->local_table_size,
ISEQ_BODY(class_iseq)->stack_max);
@@ -844,6 +853,7 @@ send
(CALL_DATA cd, ISEQ blockiseq)
(...)
(VALUE val)
+// attr bool zjit_profile = true;
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
{
@@ -890,6 +900,7 @@ opt_send_without_block
(CALL_DATA cd)
(...)
(VALUE val)
+// attr bool zjit_profile = true;
// attr bool handles_sp = true;
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
@@ -904,6 +915,32 @@ opt_send_without_block
}
}
+/* Jump if "new" method has been defined by user */
+DEFINE_INSN
+opt_new
+(CALL_DATA cd, OFFSET dst)
+()
+()
+// attr bool leaf = false;
+{
+ VALUE argc = vm_ci_argc(cd->ci);
+ VALUE val = TOPN(argc);
+
+ // The bookkeeping slot should be empty.
+ RUBY_ASSERT(TOPN(argc + 1) == Qnil);
+
+ if (vm_method_cfunc_is(GET_CFP(), cd, val, rb_class_new_instance_pass_kw)) {
+ RB_DEBUG_COUNTER_INC(opt_new_hit);
+ val = rb_obj_alloc(val);
+ TOPN(argc) = val;
+ TOPN(argc + 1) = val;
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(opt_new_miss);
+ JUMP(dst);
+ }
+}
+
/* Convert object to string using to_s or equivalent. */
DEFINE_INSN
objtostring
@@ -911,8 +948,9 @@ objtostring
(VALUE recv)
(VALUE val)
// attr bool leaf = false;
+// attr bool zjit_profile = true;
{
- val = vm_objtostring(GET_ISEQ(), recv, cd);
+ val = vm_objtostring(GET_CFP(), recv, cd);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -969,8 +1007,9 @@ opt_nil_p
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
- val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
+ val = vm_opt_nil_p(GET_CFP(), cd, recv);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1058,11 +1097,27 @@ invokesuper
(VALUE val)
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
-{
- 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);
+// attr bool zjit_profile = true;
+{
+ struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci),
+ vm_ci_flag(cd->ci),
+ vm_ci_argc(cd->ci),
+ vm_ci_kwarg(cd->ci));
+ const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE);
+ struct rb_call_data adjusted_cd = {
+ .ci = &adjusted_ci,
+ .cc = original_cc,
+ };
+
+ VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true);
+ val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super);
JIT_EXEC(ec, val);
+ if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) {
+ rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE);
+ RB_OBJ_WRITTEN(GET_ISEQ(), Qundef, adjusted_cd.cc);
+ }
+
if (UNDEF_P(val)) {
RESTORE_REGS();
NEXT_INSN();
@@ -1105,6 +1160,7 @@ invokeblock
// attr bool handles_sp = true;
// attr rb_snum_t sp_inc = sp_inc_of_invokeblock(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_invokeblock(ci);
+// attr bool zjit_profile = true;
{
VALUE bh = VM_BLOCK_HANDLER_NONE;
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
@@ -1177,7 +1233,7 @@ jump
()
()
/* Same discussion as leave. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
RUBY_VM_CHECK_INTS(ec);
JUMP(dst);
@@ -1190,7 +1246,7 @@ branchif
(VALUE val)
()
/* Same discussion as jump. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
if (RTEST(val)) {
RUBY_VM_CHECK_INTS(ec);
@@ -1205,7 +1261,7 @@ branchunless
(VALUE val)
()
/* Same discussion as jump. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
if (!RTEST(val)) {
RUBY_VM_CHECK_INTS(ec);
@@ -1220,7 +1276,7 @@ branchnil
(VALUE val)
()
/* Same discussion as jump. */
-// attr bool leaf = leafness_of_check_ints; /* has rb_threadptr_execute_interrupts() */
+// attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
{
if (NIL_P(val)) {
RUBY_VM_CHECK_INTS(ec);
@@ -1228,6 +1284,56 @@ branchnil
}
}
+/* same as jump, but without interrupt check */
+DEFINE_INSN
+jump_without_ints
+(OFFSET dst)
+()
+()
+// attr bool leaf = true;
+{
+ JUMP(dst);
+}
+
+/* same as branchif, but without interrupt check */
+DEFINE_INSN
+branchif_without_ints
+(OFFSET dst)
+(VALUE val)
+()
+// attr bool leaf = true;
+{
+ if (RTEST(val)) {
+ JUMP(dst);
+ }
+}
+
+/* same as branchunless, but without interrupt check */
+DEFINE_INSN
+branchunless_without_ints
+(OFFSET dst)
+(VALUE val)
+()
+// attr bool leaf = true;
+{
+ if (!RTEST(val)) {
+ JUMP(dst);
+ }
+}
+
+/* same as branchnil, but without interrupt check */
+DEFINE_INSN
+branchnil_without_ints
+(OFFSET dst)
+(VALUE val)
+()
+// attr bool leaf = true;
+{
+ if (NIL_P(val)) {
+ JUMP(dst);
+ }
+}
+
/**********************************************************/
/* for optimize */
/**********************************************************/
@@ -1265,6 +1371,7 @@ opt_plus
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_plus(recv, obj);
@@ -1279,6 +1386,7 @@ opt_minus
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_minus(recv, obj);
@@ -1293,6 +1401,7 @@ opt_mult
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_mult(recv, obj);
@@ -1310,6 +1419,7 @@ opt_div
/* In case of division by zero, it raises. Thus
* ZeroDivisionError#initialize is called. */
// attr bool leaf = false;
+// attr bool zjit_profile = true;
{
val = vm_opt_div(recv, obj);
@@ -1326,6 +1436,7 @@ opt_mod
(VALUE val)
/* Same discussion as opt_div. */
// attr bool leaf = false;
+// attr bool zjit_profile = true;
{
val = vm_opt_mod(recv, obj);
@@ -1340,8 +1451,9 @@ opt_eq
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
- val = opt_equality(GET_ISEQ(), recv, obj, cd);
+ val = opt_equality(GET_CFP(), recv, obj, cd);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1354,8 +1466,9 @@ opt_neq
(CALL_DATA cd_eq, CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
- val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
+ val = vm_opt_neq(GET_CFP(), cd, cd_eq, recv, obj);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1368,6 +1481,7 @@ opt_lt
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_lt(recv, obj);
@@ -1382,6 +1496,7 @@ opt_le
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_le(recv, obj);
@@ -1396,6 +1511,7 @@ opt_gt
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_gt(recv, obj);
@@ -1410,6 +1526,7 @@ opt_ge
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_ge(recv, obj);
@@ -1428,6 +1545,7 @@ opt_ltlt
* string. Then what happens if that codepoint does not exist in the
* string's encoding? Of course an exception. That's not a leaf. */
// attr bool leaf = false; /* has "invalid codepoint" exception */
+// attr bool zjit_profile = true;
{
val = vm_opt_ltlt(recv, obj);
@@ -1442,6 +1560,7 @@ opt_and
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_and(recv, obj);
@@ -1456,6 +1575,7 @@ opt_or
(CALL_DATA cd)
(VALUE recv, VALUE obj)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_or(recv, obj);
@@ -1475,6 +1595,7 @@ opt_aref
* default_proc. This is a method call. So opt_aref is
* (surprisingly) not leaf. */
// attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
+// attr bool zjit_profile = true;
{
val = vm_opt_aref(recv, obj);
@@ -1492,6 +1613,7 @@ opt_aset
/* This is another story than opt_aref. When vm_opt_aset() resorts
* to rb_hash_aset(), which should call #hash for `obj`. */
// attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
+// attr bool zjit_profile = true;
{
val = vm_opt_aset(recv, obj, set);
@@ -1500,50 +1622,13 @@ opt_aset
}
}
-/* recv[str] = set */
-DEFINE_INSN
-opt_aset_with
-(VALUE key, CALL_DATA cd)
-(VALUE recv, VALUE val)
-(VALUE val)
-/* Same discussion as opt_aset. */
-// attr bool leaf = false; /* has rb_funcall() */ /* calls #hash */
-{
- VALUE tmp = vm_opt_aset_with(recv, key, val);
-
- if (!UNDEF_P(tmp)) {
- val = tmp;
- }
- else {
- TOPN(0) = rb_str_resurrect(key);
- PUSH(val);
- CALL_SIMPLE_METHOD();
- }
-}
-
-/* recv[str] */
-DEFINE_INSN
-opt_aref_with
-(VALUE key, CALL_DATA cd)
-(VALUE recv)
-(VALUE val)
-/* Same discussion as opt_aref. */
-// attr bool leaf = false; /* has rb_funcall() */ /* calls #yield */
-{
- val = vm_opt_aref_with(recv, key);
-
- if (UNDEF_P(val)) {
- PUSH(rb_str_resurrect(key));
- CALL_SIMPLE_METHOD();
- }
-}
-
/* optimized length */
DEFINE_INSN
opt_length
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_length(recv, BOP_LENGTH);
@@ -1558,6 +1643,7 @@ opt_size
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_length(recv, BOP_SIZE);
@@ -1572,6 +1658,7 @@ opt_empty_p
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_empty_p(recv);
@@ -1586,6 +1673,7 @@ opt_succ
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
val = vm_opt_succ(recv);
@@ -1600,8 +1688,9 @@ opt_not
(CALL_DATA cd)
(VALUE recv)
(VALUE val)
+// attr bool zjit_profile = true;
{
- val = vm_opt_not(GET_ISEQ(), cd, recv);
+ val = vm_opt_not(GET_CFP(), cd, recv);
if (UNDEF_P(val)) {
CALL_SIMPLE_METHOD();
@@ -1615,6 +1704,7 @@ opt_regexpmatch2
(VALUE obj2, VALUE obj1)
(VALUE val)
// attr bool leaf = false; /* match_at() has rb_thread_check_ints() */
+// attr bool zjit_profile = true;
{
val = vm_opt_regexpmatch2(obj2, obj1);
diff --git a/internal.h b/internal.h
index 4fb99d1c08..002044cfa1 100644
--- a/internal.h
+++ b/internal.h
@@ -58,9 +58,6 @@
/* internal/array.h */
#define rb_ary_new_from_args(...) rb_nonexistent_symbol(__VA_ARGS__)
-/* internal/io.h */
-#define rb_io_fptr_finalize(...) rb_nonexistent_symbol(__VA_ARGS__)
-
/* internal/string.h */
#define rb_fstring_cstr(...) rb_nonexistent_symbol(__VA_ARGS__)
diff --git a/internal/array.h b/internal/array.h
index 398676df4a..a2cd06f2e3 100644
--- a/internal/array.h
+++ b/internal/array.h
@@ -37,6 +37,7 @@ size_t rb_ary_size_as_embedded(VALUE ary);
void rb_ary_make_embedded(VALUE ary);
bool rb_ary_embeddable_p(VALUE ary);
VALUE rb_ary_diff(VALUE ary1, VALUE ary2);
+VALUE rb_ary_compact_bang(VALUE ary);
RUBY_EXTERN VALUE rb_cArray_empty_frozen;
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
@@ -140,6 +141,8 @@ RARRAY_AREF(VALUE ary, long i)
VALUE val;
RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
+ RUBY_ASSERT(i < RARRAY_LEN(ary));
+
RBIMPL_WARNING_PUSH();
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 13
RBIMPL_WARNING_IGNORED(-Warray-bounds);
diff --git a/internal/basic_operators.h b/internal/basic_operators.h
index 5dc8d7fe8d..493d2fa7f7 100644
--- a/internal/basic_operators.h
+++ b/internal/basic_operators.h
@@ -24,6 +24,7 @@ enum ruby_basic_operators {
BOP_SUCC,
BOP_GT,
BOP_GE,
+ BOP_GTGT,
BOP_NOT,
BOP_NEQ,
BOP_MATCH,
diff --git a/internal/bignum.h b/internal/bignum.h
index db8d3aee83..7389a17c74 100644
--- a/internal/bignum.h
+++ b/internal/bignum.h
@@ -9,6 +9,7 @@
* @brief Internal header for Bignums.
*/
#include "ruby/internal/config.h" /* for HAVE_LIBGMP */
+#include "internal/compilers.h" /* for FLEX_ARY_LEN */
#include <stddef.h> /* for size_t */
#ifdef HAVE_SYS_TYPES_H
@@ -76,26 +77,17 @@
#define RBIGNUM(obj) ((struct RBignum *)(obj))
#define BIGNUM_SIGN_BIT FL_USER1
#define BIGNUM_EMBED_FLAG ((VALUE)FL_USER2)
-#define BIGNUM_EMBED_LEN_NUMBITS 3
+
+/* This is likely more bits than we need today and will also need adjustment if
+ * we change GC slot sizes.
+ */
+#define BIGNUM_EMBED_LEN_NUMBITS 9
#define BIGNUM_EMBED_LEN_MASK \
- (~(~(VALUE)0U << BIGNUM_EMBED_LEN_NUMBITS) << BIGNUM_EMBED_LEN_SHIFT)
+ (RUBY_FL_USER11 | RUBY_FL_USER10 | RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | \
+ RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3)
#define BIGNUM_EMBED_LEN_SHIFT \
(FL_USHIFT+3) /* bit offset of BIGNUM_EMBED_LEN_MASK */
-#ifndef BIGNUM_EMBED_LEN_MAX
-# if (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT) < (1 << BIGNUM_EMBED_LEN_NUMBITS)-1
-# define BIGNUM_EMBED_LEN_MAX (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT)
-# else
-# define BIGNUM_EMBED_LEN_MAX ((1 << BIGNUM_EMBED_LEN_NUMBITS)-1)
-# endif
-#endif
-
-enum rb_int_parse_flags {
- RB_INT_PARSE_SIGN = 0x01,
- RB_INT_PARSE_UNDERSCORE = 0x02,
- RB_INT_PARSE_PREFIX = 0x04,
- RB_INT_PARSE_ALL = 0x07,
- RB_INT_PARSE_DEFAULT = 0x07,
-};
+#define BIGNUM_EMBED_LEN_MAX (BIGNUM_EMBED_LEN_MASK >> BIGNUM_EMBED_LEN_SHIFT)
struct RBignum {
struct RBasic basic;
@@ -104,12 +96,18 @@ struct RBignum {
size_t len;
BDIGIT *digits;
} heap;
- BDIGIT ary[BIGNUM_EMBED_LEN_MAX];
+ /* 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
+ */
+ BDIGIT ary[1];
} as;
};
/* bignum.c */
extern const char ruby_digitmap[];
+extern const char ruby_decimal_digit_pairs[];
double rb_big_fdiv_double(VALUE x, VALUE y);
VALUE rb_big_uminus(VALUE x);
VALUE rb_big_hash(VALUE);
@@ -121,6 +119,7 @@ VALUE rb_integer_float_eq(VALUE x, VALUE y);
VALUE rb_str_convert_to_inum(VALUE str, int base, int badcheck, int raise_exception);
VALUE rb_big_comp(VALUE x);
VALUE rb_big_aref(VALUE x, VALUE y);
+VALUE rb_big_aref2(VALUE num, VALUE beg, VALUE len);
VALUE rb_big_abs(VALUE x);
VALUE rb_big_size_m(VALUE big);
VALUE rb_big_bit_length(VALUE big);
@@ -160,10 +159,15 @@ VALUE rb_big_divrem_gmp(VALUE x, VALUE y);
VALUE rb_big2str_gmp(VALUE x, int base);
VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck);
#endif
-VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
RUBY_SYMBOL_EXPORT_END
+#if HAVE_LONG_LONG
+VALUE rb_ull2big(unsigned LONG_LONG n);
+VALUE rb_ll2big(LONG_LONG n);
+#endif
+
#if defined(HAVE_INT128_T)
+VALUE rb_uint128t2big(uint128_t n);
VALUE rb_int128t2big(int128_t n);
#endif
diff --git a/internal/bits.h b/internal/bits.h
index 2b5aecf112..698ab3e219 100644
--- a/internal/bits.h
+++ b/internal/bits.h
@@ -30,13 +30,13 @@
#include <stdint.h> /* for uintptr_t */
#include "internal/compilers.h" /* for MSC_VERSION_SINCE */
-#if MSC_VERSION_SINCE(1310)
+#ifdef _MSC_VER
# include <stdlib.h> /* for _byteswap_uint64 */
#endif
#if defined(HAVE_X86INTRIN_H)
# include <x86intrin.h> /* for _lzcnt_u64 */
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
# include <intrin.h> /* for the following intrinsics */
#endif
@@ -50,16 +50,13 @@
# pragma intrinsic(__lzcnt64)
#endif
-#if MSC_VERSION_SINCE(1310)
+#if defined(_MSC_VER)
# 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
@@ -266,7 +263,7 @@ ruby_swap16(uint16_t x)
#if __has_builtin(__builtin_bswap16)
return __builtin_bswap16(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ushort(x);
#else
@@ -281,7 +278,7 @@ ruby_swap32(uint32_t x)
#if __has_builtin(__builtin_bswap32)
return __builtin_bswap32(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ulong(x);
#else
@@ -298,7 +295,7 @@ ruby_swap64(uint64_t x)
#if __has_builtin(__builtin_bswap64)
return __builtin_bswap64(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_uint64(x);
#else
@@ -323,7 +320,7 @@ nlz_int32(uint32_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
@@ -352,7 +349,7 @@ nlz_int64(uint64_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
@@ -538,7 +535,7 @@ ntz_int32(uint32_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400)
+#elif defined(_MSC_VER)
/* :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;
@@ -560,7 +557,7 @@ ntz_int64(uint64_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
+#elif defined(_WIN64) && defined(_MSC_VER)
unsigned long r;
return _BitScanForward64(&r, x) ? (int)r : 64;
@@ -608,10 +605,10 @@ RUBY_BIT_ROTL(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotl(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotl64(v, n);
#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG)
@@ -632,10 +629,10 @@ RUBY_BIT_ROTR(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotr(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotr64(v, n);
#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG)
diff --git a/internal/box.h b/internal/box.h
new file mode 100644
index 0000000000..c717dc4e24
--- /dev/null
+++ b/internal/box.h
@@ -0,0 +1,96 @@
+#ifndef INTERNAL_BOX_H /*-*-C-*-vi:se ft=c:*/
+#define INTERNAL_BOX_H
+
+#include "ruby/ruby.h" /* for VALUE */
+
+/**
+ * @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 Ruby Box.
+ */
+struct rb_box_struct {
+ /*
+ * To retrieve Ruby::Box object that provides #require and so on.
+ * That is used from load.c, etc., that uses rb_box_t internally.
+ */
+ VALUE box_object;
+ long box_id; // box_id to generate ext filenames
+
+ VALUE top_self;
+
+ VALUE load_path;
+ VALUE load_path_snapshot;
+ VALUE load_path_check_cache;
+ VALUE expanded_load_path;
+ VALUE loaded_features;
+ VALUE loaded_features_snapshot;
+ VALUE loaded_features_realpaths;
+ VALUE loaded_features_realpath_map;
+ struct st_table *loaded_features_index;
+ struct st_table *loading_table;
+ VALUE ruby_dln_libmap;
+
+ VALUE gvar_tbl;
+ struct st_table *classext_cow_classes;
+
+ bool is_root;
+ bool is_user;
+ bool is_optional;
+};
+typedef struct rb_box_struct rb_box_t;
+
+struct rb_box_gem_flags {
+ bool gem;
+ bool error_highlight;
+ bool did_you_mean;
+ bool syntax_suggest;
+};
+typedef struct rb_box_gem_flags rb_box_gem_flags_t;
+
+#define BOX_OBJ_P(obj) (rb_obj_class(obj) == rb_cBox)
+
+#define BOX_MASTER_P(box) (box && !box->is_root && !box->is_user)
+#define BOX_MUTABLE_P(box) (box && (box->is_root || box->is_user))
+#define BOX_ROOT_P(box) (box && box->is_root)
+#define BOX_USER_P(box) (box && box->is_user)
+#define BOX_OPTIONAL_P(box) (box && box->is_optional)
+#define BOX_MAIN_P(box) (box && box->is_user && !box->is_optional)
+
+#define BOX_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL)
+#define BOX_METHOD_ENTRY(me) (me ? BOX_METHOD_DEFINITION(me->def) : NULL)
+#define BOX_CC(cc) (cc ? BOX_METHOD_ENTRY(cc->cme_) : NULL)
+#define BOX_CC_ENTRIES(ccs) (ccs ? BOX_METHOD_ENTRY(ccs->cme) : NULL)
+
+RUBY_EXTERN bool ruby_box_enabled;
+RUBY_EXTERN bool ruby_box_init_done;
+RUBY_EXTERN bool ruby_box_crashed;
+
+static inline bool
+rb_box_available(void)
+{
+ return ruby_box_enabled;
+}
+
+const rb_box_t * rb_master_box(void);
+const rb_box_t * rb_root_box(void);
+const rb_box_t * rb_main_box(void);
+const rb_box_t * rb_current_box(void);
+const rb_box_t * rb_loading_box(void);
+const rb_box_t * rb_current_box_in_crash_report(void);
+
+void rb_box_entry_mark(void *);
+void rb_box_gc_update_references(void *ptr);
+
+rb_box_t * rb_get_box_t(VALUE ns);
+VALUE rb_get_box_object(rb_box_t *ns);
+
+VALUE rb_box_local_extension(VALUE box, VALUE fname, VALUE path, VALUE *cleanup);
+void rb_box_cleanup_local_extension(VALUE cleanup);
+
+void rb_initialize_mandatory_boxes(void);
+void rb_box_init_done(void);
+void rb_box_set_gem_flags(rb_box_gem_flags_t *);
+#endif /* INTERNAL_BOX_H */
diff --git a/internal/class.h b/internal/class.h
index f94434b938..0773dbad95 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -10,6 +10,7 @@
*/
#include "id.h"
#include "id_table.h" /* for struct rb_id_table */
+#include "internal/box.h"
#include "internal/serial.h" /* for rb_serial_t */
#include "internal/static_assert.h"
#include "internal/variable.h" /* for rb_class_ivar_set */
@@ -26,36 +27,31 @@
# undef RCLASS_SUPER
#endif
-struct rb_subclass_entry {
- VALUE klass;
- 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 {
+ VALUE imemo_flags;
uint32_t index;
rb_serial_t global_cvar_state;
- const rb_cref_t * cref;
+ const rb_cref_t *cref;
VALUE class_value;
};
struct rb_classext_struct {
- VALUE *iv_ptr;
+ const rb_box_t *box;
+ VALUE super;
+ VALUE fields_obj; // Fields are either ivar or other internal properties stored inline
+ VALUE classpath;
+ struct rb_id_table *m_tbl;
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 *cvc_tbl;
- size_t superclass_depth;
+ VALUE cc_tbl; /* { ID => { cme, [cc1, cc2, ...] }, ... } */
+ VALUE cvc_tbl;
VALUE *superclasses;
- struct rb_subclass_entry *subclasses;
- struct rb_subclass_entry *subclass_entry;
/**
- * In the case that this is an `ICLASS`, `module_subclasses` points to the link
- * in the module's `subclasses` list that indicates that the klass has been
- * included. Hopefully that makes sense.
+ * imemo_subclasses VALUE tracking this class's subclasses.
+ * Only used in prime classext. Lazily allocated on first subclass addition.
*/
- struct rb_subclass_entry *module_subclass_entry;
+ VALUE subclasses;
+
const VALUE origin_;
const VALUE refined_class;
union {
@@ -65,13 +61,19 @@ struct rb_classext_struct {
struct {
VALUE attached_object;
} singleton_class;
+ struct {
+ const VALUE includer;
+ } iclass;
} as;
- const VALUE includer;
+ uint16_t superclass_depth;
attr_index_t max_iv_count;
- unsigned char variation_count;
+ uint8_t variation_count;
bool permanent_classpath : 1;
- bool cloned : 1;
- VALUE classpath;
+ bool shared_const_tbl : 1;
+ bool iclass_is_origin : 1;
+ bool iclass_origin_shared_mtbl : 1;
+ bool superclasses_with_self : 1;
+ bool expect_no_ivar : 1;
};
typedef struct rb_classext_struct rb_classext_t;
@@ -79,103 +81,365 @@ STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_cl
struct RClass {
struct RBasic basic;
- VALUE super;
- struct rb_id_table *m_tbl;
+ VALUE object_id;
+ /*
+ * If box_classext_tbl is NULL, then the prime classext is readable (because no other classext exists).
+ * For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE
+ */
};
-// Assert that classes can be embedded in heaps[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;
};
-#define RCLASS_EXT(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
-#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)
-#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
-#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl)
-#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl)
-#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_)
-#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class)
-#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_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)
+#if SIZEOF_VALUE >= SIZEOF_LONG_LONG
+// Assert that classes can be embedded in heaps[3] (256B slot size on 64-bit).
+// On 32bit platforms there is no variable width allocation so it doesn't matter.
+STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass_and_rb_classext_t) <= 256);
+#endif
+
+struct RClass_boxable {
+ struct RClass_and_rb_classext_t base;
+ st_table *box_classext_tbl; // box_object -> (rb_classext_t *)
+};
+
+static const uint16_t RCLASS_MAX_SUPERCLASS_DEPTH = ((uint16_t)-1);
+
+static inline bool RCLASS_SINGLETON_P(VALUE klass);
+
+static inline bool RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE obj);
+static inline bool RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE obj);
+static inline void RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE obj, bool writable);
+
+#define RCLASS_EXT_PRIME(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
+#define RCLASS_EXT_PRIME_P(ext, c) (&((struct RClass_and_rb_classext_t*)(c))->classext == ext)
+
+static inline rb_classext_t * RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box);
+static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj);
+static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box);
+static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
+
+// Raw accessor
+#define RCLASSEXT_BOX(ext) (ext->box)
+#define RCLASSEXT_SUPER(ext) (ext->super)
+#define RCLASSEXT_FIELDS(ext) (ext->fields_obj ? ROBJECT_FIELDS(ext->fields_obj) : NULL)
+#define RCLASSEXT_FIELDS_OBJ(ext) (ext->fields_obj)
+#define RCLASSEXT_M_TBL(ext) (ext->m_tbl)
+#define RCLASSEXT_CONST_TBL(ext) (ext->const_tbl)
+#define RCLASSEXT_CALLABLE_M_TBL(ext) (ext->callable_m_tbl)
+#define RCLASSEXT_CC_TBL(ext) (ext->cc_tbl)
+#define RCLASSEXT_CVC_TBL(ext) (ext->cvc_tbl)
+#define RCLASSEXT_SUPERCLASS_DEPTH(ext) (ext->superclass_depth)
+#define RCLASSEXT_SUPERCLASSES(ext) (ext->superclasses)
+#define RCLASSEXT_SUBCLASSES(ext) (ext->subclasses)
+#define RCLASSEXT_ORIGIN(ext) (ext->origin_)
+#define RCLASSEXT_REFINED_CLASS(ext) (ext->refined_class)
+// class.allocator/singleton_class.attached_object are not accessed directly via RCLASSEXT_*
+#define RCLASSEXT_INCLUDER(ext) (ext->as.iclass.includer)
+#define RCLASSEXT_PERMANENT_CLASSPATH(ext) (ext->permanent_classpath)
+#define RCLASSEXT_SHARED_CONST_TBL(ext) (ext->shared_const_tbl)
+#define RCLASSEXT_ICLASS_IS_ORIGIN(ext) (ext->iclass_is_origin)
+#define RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) (ext->iclass_origin_shared_mtbl)
+#define RCLASSEXT_SUPERCLASSES_WITH_SELF(ext) (ext->superclasses_with_self)
+#define RCLASSEXT_CLASSPATH(ext) (ext->classpath)
+
+static inline void RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE origin);
+static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer);
+
+/* Prime classext entry accessor for very specific reason */
+#define RCLASS_PRIME_BOX(c) (RCLASS_EXT_PRIME(c)->box)
+// To invalidate CC by inserting&invalidating method entry into tables containing the target cme
+// See clear_method_cache_by_id_in_class()
+#define RCLASS_PRIME_FIELDS_OBJ(c) (RCLASS_EXT_PRIME(c)->fields_obj)
+#define RCLASS_PRIME_M_TBL(c) (RCLASS_EXT_PRIME(c)->m_tbl)
+#define RCLASS_PRIME_CONST_TBL(c) (RCLASS_EXT_PRIME(c)->const_tbl)
+#define RCLASS_PRIME_CALLABLE_M_TBL(c) (RCLASS_EXT_PRIME(c)->callable_m_tbl)
+#define RCLASS_PRIME_CC_TBL(c) (RCLASS_EXT_PRIME(c)->cc_tbl)
+#define RCLASS_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->m_tbl != tbl)
+#define RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->callable_m_tbl != tbl)
+#define RCLASS_CC_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->cc_tbl != tbl)
+
+// Read accessor, regarding box
+#define RCLASS_SUPER(c) (RCLASS_EXT_READABLE(c)->super)
+#define RCLASS_M_TBL(c) (RCLASS_EXT_READABLE(c)->m_tbl)
+#define RCLASS_CONST_TBL(c) (RCLASS_EXT_READABLE(c)->const_tbl)
+/*
+ * Both cc_tbl/callable_m_tbl are cache-like and always be changed when referreed,
+ * so always those should be writable.
+ */
+#define RCLASS_CVC_TBL(c) (RCLASS_EXT_READABLE(c)->cvc_tbl)
+#define RCLASS_SUBCLASSES(c) (RCLASS_EXT_PRIME(c)->subclasses)
+#define RCLASS_ORIGIN(c) (RCLASS_EXT_READABLE(c)->origin_)
+#define RICLASS_IS_ORIGIN_P(c) (RCLASS_EXT_READABLE(c)->iclass_is_origin)
+#define RCLASS_PERMANENT_CLASSPATH_P(c) (RCLASS_EXT_READABLE(c)->permanent_classpath)
+#define RCLASS_CLASSPATH(c) (RCLASS_EXT_READABLE(c)->classpath)
+
+// Superclasses can't be changed after initialization
+#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT_PRIME(c)->superclass_depth)
+#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT_PRIME(c)->superclasses)
+#define RCLASS_SUPERCLASSES_WITH_SELF_P(c) (RCLASS_EXT_PRIME(c)->superclasses_with_self)
+
+// Ruby Box doesn't make changes on these refined_class/attached_object/includer
+#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT_PRIME(c)->refined_class)
+#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT_PRIME(c)->as.singleton_class.attached_object)
+#define RCLASS_INCLUDER(c) (RCLASS_EXT_PRIME(c)->as.iclass.includer)
+
+// max IV count and variation count are just hints, so they don't need to be per-box
+#define RCLASS_MAX_IV_COUNT(ext) (RCLASS_EXT_PRIME(ext)->max_iv_count)
+#define RCLASS_VARIATION_COUNT(ext) (RCLASS_EXT_PRIME(ext)->variation_count)
+
+// Writable classext entries (instead of RCLASS_SET_*) because member data will be operated directly
+#define RCLASS_WRITABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->m_tbl)
+#define RCLASS_WRITABLE_CONST_TBL(c) (RCLASS_EXT_WRITABLE(c)->const_tbl)
+#define RCLASS_WRITABLE_CALLABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->callable_m_tbl)
+#define RCLASS_WRITABLE_CC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cc_tbl)
+#define RCLASS_WRITABLE_CVC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cvc_tbl)
+// Subclasses are only in the prime classext (box-invariant)
+#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_PRIME(c)->subclasses)
+
+static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super);
+static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super);
+static inline void RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared);
+static inline void RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared);
+static inline void RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table);
+static inline void RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table);
+static inline void RCLASS_SET_CVC_TBL(VALUE klass, VALUE table);
+static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, VALUE table);
+
+static inline void RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool with_self);
+static inline void RCLASS_SET_SUBCLASSES(VALUE klass, VALUE subclasses);
+
+static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
+static inline void RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin);
+static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass);
+static inline void RICLASS_WRITE_ORIGIN_SHARED_MTBL(VALUE iclass);
+static inline bool RICLASS_OWNS_M_TBL_P(VALUE iclass);
+
+static inline void RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined);
+static inline rb_alloc_func_t RCLASS_ALLOCATOR(VALUE klass);
+static inline void RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator);
+static inline VALUE RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object);
+
+static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
+static inline void RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count);
+static inline void RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent);
+static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent);
#define RCLASS_IS_ROOT FL_USER0
-#define RICLASS_IS_ORIGIN FL_USER0
-#define RCLASS_SUPERCLASSES_INCLUDE_SELF FL_USER2
-#define RICLASS_ORIGIN_SHARED_MTBL FL_USER3
+// 1 is for RUBY_FL_SINGLETON or RMODULE_IS_REFINEMENT
+#define RCLASS_PRIME_CLASSEXT_WRITABLE FL_USER2
+#define RCLASS_IS_INITIALIZED FL_USER3
+// 3 is RMODULE_IS_REFINEMENT for RMODULE
+#define RCLASS_BOXABLE FL_USER4
+#define RCLASS_ALLOCATOR_DEFINED FL_USER5
+#define RCLASS_HAS_SUBCLASSES FL_USER6
static inline st_table *
-RCLASS_IV_HASH(VALUE obj)
+RCLASS_CLASSEXT_TBL(VALUE klass)
{
- 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);
+ if (FL_TEST_RAW(klass, RCLASS_BOXABLE)) {
+ struct RClass_boxable *box_klass = (struct RClass_boxable *)klass;
+ return box_klass->box_classext_tbl;
+ }
+ return NULL;
}
static inline void
-RCLASS_SET_IV_HASH(VALUE obj, const st_table *tbl)
+RCLASS_SET_CLASSEXT_TBL(VALUE klass, 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;
+ RUBY_ASSERT(FL_TEST_RAW(klass, RCLASS_BOXABLE));
+ struct RClass_boxable *box_klass = (struct RClass_boxable *)klass;
+ box_klass->box_classext_tbl = tbl;
}
-static inline uint32_t
-RCLASS_IV_COUNT(VALUE obj)
+/* class.c */
+rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_box_t *box);
+void rb_class_ensure_writable(VALUE obj);
+
+void rb_class_set_box_classext(VALUE obj, const rb_box_t *box, rb_classext_t *ext);
+
+static inline int
+RCLASS_SET_BOX_CLASSEXT(VALUE obj, const rb_box_t *box, rb_classext_t *ext)
{
- 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();
+ int first_set = 0;
+ st_table *tbl = RCLASS_CLASSEXT_TBL(obj);
+ VM_ASSERT(BOX_MUTABLE_P(box)); // Setting non-prime classext never happens on the master box
+ VM_ASSERT(box->box_object);
+ VM_ASSERT(RCLASSEXT_BOX(ext) == box);
+ if (!tbl) {
+ tbl = st_init_numtable_with_size(1);
+ RCLASS_SET_CLASSEXT_TBL(obj, tbl);
+ }
+ if (rb_st_table_size(tbl) == 0) {
+ first_set = 1;
+ }
+
+ rb_class_set_box_classext(obj, box, ext);
+
+ return first_set;
+}
+
+#define VM_ASSERT_BOXABLE_TYPE(klass) \
+ VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS), "%s is not boxable type", rb_type_str(BUILTIN_TYPE(klass)))
+
+static inline bool
+RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE klass)
+{
+ VM_ASSERT(klass != 0, "klass should be a valid object");
+ VM_ASSERT_BOXABLE_TYPE(klass);
+ // if the lookup table exists, then it means the prime classext is NOT directly readable.
+ return !FL_TEST_RAW(klass, RCLASS_BOXABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL;
+}
- return count;
+static inline bool
+RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE klass)
+{
+ VM_ASSERT(klass != 0, "klass should be a valid object");
+ VM_ASSERT_BOXABLE_TYPE(klass);
+ RBIMPL_ASSUME(klass != 0);
+ return FL_TEST_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
+}
+
+static inline void
+RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE klass, bool writable)
+{
+ VM_ASSERT(klass != 0, "klass should be a valid object");
+ VM_ASSERT_BOXABLE_TYPE(klass);
+ if (writable) {
+ FL_SET_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}
else {
- return rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
+ FL_UNSET_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}
}
+static inline rb_classext_t *
+RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_box_t *box)
+{
+ st_data_t classext_ptr;
+ st_table *classext_tbl = RCLASS_CLASSEXT_TBL(obj);
+ if (classext_tbl) {
+ if (rb_st_lookup(classext_tbl, (st_data_t)box->box_object, &classext_ptr)) {
+ return (rb_classext_t *)classext_ptr;
+ }
+ }
+ return NULL;
+}
+
+static inline rb_classext_t *
+RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_box_t *box)
+{
+ rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box);
+ if (ext)
+ return ext;
+ // Classext for the ns not found. Refer the prime one instead.
+ return RCLASS_EXT_PRIME(obj);
+}
+
+static inline rb_classext_t *
+RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box)
+{
+ if (BOX_MASTER_P(box)
+ || RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) {
+ return RCLASS_EXT_PRIME(obj);
+ }
+ return RCLASS_EXT_READABLE_LOOKUP(obj, box);
+}
+
+static inline rb_classext_t *
+RCLASS_EXT_READABLE(VALUE obj)
+{
+ const rb_box_t *box;
+ if (RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) {
+ return RCLASS_EXT_PRIME(obj);
+ }
+ // delay determining the current box to optimize for unmodified classes
+ box = rb_current_box();
+ if (BOX_MASTER_P(box)) {
+ return RCLASS_EXT_PRIME(obj);
+ }
+ return RCLASS_EXT_READABLE_LOOKUP(obj, box);
+}
+
+static inline rb_classext_t *
+RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_box_t *box)
+{
+ rb_classext_t *ext;
+ int first_set = 0;
+
+ ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box);
+ if (ext)
+ return ext;
+
+ RB_VM_LOCKING() {
+ // re-check the classext is not created to avoid the multi-thread race
+ ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box);
+ if (!ext) {
+ ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, box);
+ first_set = RCLASS_SET_BOX_CLASSEXT(obj, box, ext);
+ if (first_set) {
+ // TODO: are there any case that a class/module become non-writable after its birthtime?
+ RCLASS_SET_PRIME_CLASSEXT_WRITABLE(obj, false);
+ }
+ }
+ }
+ return ext;
+}
+
+static inline rb_classext_t *
+RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box)
+{
+ if (BOX_MASTER_P(box)
+ || RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj)) {
+ return RCLASS_EXT_PRIME(obj);
+ }
+ return RCLASS_EXT_WRITABLE_LOOKUP(obj, box);
+}
+
+static inline rb_classext_t *
+RCLASS_EXT_WRITABLE(VALUE obj)
+{
+ const rb_box_t *box;
+ if (LIKELY(RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj))) {
+ return RCLASS_EXT_PRIME(obj);
+ }
+ // delay determining the current box to optimize for unmodified classes
+ box = rb_current_box();
+ if (BOX_MASTER_P(box)) {
+ return RCLASS_EXT_PRIME(obj);
+ }
+ return RCLASS_EXT_WRITABLE_LOOKUP(obj, box);
+}
+
static inline void
-RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table)
+RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE origin)
+{
+ RB_OBJ_WRITE(klass, &(RCLASSEXT_ORIGIN(ext)), origin);
+}
+
+static inline void
+RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer)
{
- RUBY_ASSERT(!RB_OBJ_PROMOTED(klass));
- RCLASS_M_TBL(klass) = table;
+ RUBY_ASSERT(RB_TYPE_P(klass, T_ICLASS));
+ RB_OBJ_WRITE(klass, &(RCLASSEXT_INCLUDER(ext)), includer);
}
/* class.c */
+typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE box_value, void *arg);
+void rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg);
void rb_class_subclass_add(VALUE super, VALUE klass);
-void rb_class_remove_from_super_subclasses(VALUE);
+void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
void rb_class_update_superclasses(VALUE);
-size_t rb_class_superclasses_memsize(VALUE);
-void rb_class_remove_subclass_head(VALUE);
int rb_singleton_class_internal_p(VALUE sklass);
+VALUE rb_class_set_super(VALUE klass, VALUE super);
VALUE rb_class_boot(VALUE);
VALUE rb_class_s_alloc(VALUE klass);
VALUE rb_module_s_alloc(VALUE klass);
-void rb_module_set_initialized(VALUE module);
+void rb_class_set_initialized(VALUE klass);
void rb_module_check_initializable(VALUE module);
VALUE rb_make_metaclass(VALUE, VALUE);
VALUE rb_include_class_new(VALUE, VALUE);
-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);
@@ -186,89 +450,258 @@ VALUE rb_special_singleton_class(VALUE);
VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach);
VALUE rb_singleton_class_get(VALUE obj);
void rb_undef_methods_from(VALUE klass, VALUE super);
-
-static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
-static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass);
-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);
-
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
+rb_classext_t *rb_class_unlink_classext(VALUE klass, const rb_box_t *box);
+void rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime);
+void rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+
+/* for objspace */
+VALUE rb_class_super_of(VALUE klass);
+VALUE rb_class_singleton_p(VALUE klass);
+unsigned char rb_class_variation_count(VALUE klass);
+
+RUBY_SYMBOL_EXPORT_END
+
static inline bool
RCLASS_SINGLETON_P(VALUE klass)
{
- return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+ return RB_BUILTIN_TYPE(klass) == T_CLASS && FL_TEST_RAW(klass, FL_SINGLETON);
+}
+
+static inline void
+RCLASS_SET_SUPER(VALUE klass, VALUE super)
+{
+ RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_PRIME(klass)), super);
+}
+
+static inline void
+RCLASS_WRITE_SUPER(VALUE klass, VALUE super)
+{
+ RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_WRITABLE(klass)), super);
+}
+
+static inline VALUE
+RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+ rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
+ if (!ext->fields_obj) {
+ RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, ROOT_SHAPE_ID, true));
+ }
+ return ext->fields_obj;
+}
+
+static inline VALUE
+RCLASS_WRITABLE_FIELDS_OBJ(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+ return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_WRITABLE(obj));
+}
+
+static inline void
+RCLASSEXT_SET_FIELDS_OBJ(VALUE obj, rb_classext_t *ext, VALUE fields_obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+
+ RB_OBJ_ATOMIC_WRITE(obj, &ext->fields_obj, fields_obj);
+}
+
+static inline void
+RCLASS_WRITABLE_SET_FIELDS_OBJ(VALUE obj, VALUE fields_obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+
+ RCLASSEXT_SET_FIELDS_OBJ(obj, RCLASS_EXT_WRITABLE(obj), fields_obj);
+}
+
+static inline uint32_t
+RCLASS_FIELDS_COUNT(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (fields_obj) {
+ if (rb_obj_shape_complex_p(fields_obj)) {
+ return (uint32_t)rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
+ }
+ else {
+ return RSHAPE_LEN(RBASIC_SHAPE_ID(fields_obj));
+ }
+ }
+ return 0;
+}
+
+static inline void
+RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table)
+{
+ RCLASSEXT_M_TBL(RCLASS_EXT_PRIME(klass)) = table;
+}
+
+static inline void
+RCLASS_WRITE_M_TBL(VALUE klass, struct rb_id_table *table)
+{
+ RCLASSEXT_M_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
+}
+
+static inline void
+RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared)
+{
+ rb_classext_t *ext = RCLASS_EXT_PRIME(klass);
+ RCLASSEXT_CONST_TBL(ext) = table;
+ if (shared)
+ RCLASSEXT_SHARED_CONST_TBL(ext) = true;
+}
+
+static inline void
+RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared)
+{
+ rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
+ RCLASSEXT_CONST_TBL(ext) = table;
+ if (shared)
+ RCLASSEXT_SHARED_CONST_TBL(ext) = true;
+}
+
+static inline void
+RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table)
+{
+ RCLASSEXT_CALLABLE_M_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
+}
+
+static inline void
+RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table)
+{
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)), table);
+}
+
+static inline void
+RCLASS_SET_CVC_TBL(VALUE klass, VALUE table)
+{
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CVC_TBL(RCLASS_EXT_PRIME(klass)), table);
+}
+
+static inline void
+RCLASS_WRITE_CVC_TBL(VALUE klass, VALUE table)
+{
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)), table);
+}
+
+static inline void
+RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined)
+{
+ RB_OBJ_WRITE(klass, &RCLASSEXT_REFINED_CLASS(RCLASS_EXT_PRIME(klass)), refined);
}
static inline rb_alloc_func_t
RCLASS_ALLOCATOR(VALUE klass)
{
- if (RCLASS_SINGLETON_P(klass)) {
- return 0;
- }
- return RCLASS_EXT(klass)->as.class.allocator;
+ RBIMPL_ASSERT_TYPE(klass, T_CLASS);
+ RUBY_ASSERT(!RCLASS_SINGLETON_P(klass));
+ return RCLASS_EXT_PRIME(klass)->as.class.allocator;
}
static inline void
RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
{
- assert(!RCLASS_SINGLETON_P(klass));
- RCLASS_EXT(klass)->as.class.allocator = allocator;
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
+ RUBY_ASSERT(!RCLASS_SINGLETON_P(klass));
+ RCLASS_EXT_PRIME(klass)->as.class.allocator = allocator; // Allocator is set only on the initial definition
}
static inline void
RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
{
- RB_OBJ_WRITE(klass, &RCLASS_ORIGIN(klass), origin);
- if (klass != origin) FL_SET(origin, RICLASS_IS_ORIGIN);
+ rb_classext_t *ext = RCLASS_EXT_PRIME(klass);
+ RB_OBJ_WRITE(klass, &RCLASSEXT_ORIGIN(ext), origin);
+ if (klass != origin) RCLASSEXT_ICLASS_IS_ORIGIN(RCLASS_EXT_WRITABLE(origin)) = true;
+}
+
+static inline void
+RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin)
+{
+ rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
+ RB_OBJ_WRITE(klass, &RCLASSEXT_ORIGIN(ext), origin);
+ if (klass != origin) RCLASSEXT_ICLASS_IS_ORIGIN(RCLASS_EXT_WRITABLE(origin)) = true;
}
static inline void
RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass)
{
- FL_SET(iclass, RICLASS_ORIGIN_SHARED_MTBL);
+ RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(RCLASS_EXT_PRIME(iclass)) = true;
+}
+
+static inline void
+RICLASS_WRITE_ORIGIN_SHARED_MTBL(VALUE iclass)
+{
+ RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(RCLASS_EXT_WRITABLE(iclass)) = true;
}
static inline bool
RICLASS_OWNS_M_TBL_P(VALUE iclass)
{
- return FL_TEST_RAW(iclass, RICLASS_IS_ORIGIN | RICLASS_ORIGIN_SHARED_MTBL) == RICLASS_IS_ORIGIN;
+ rb_classext_t *ext = RCLASS_EXT_READABLE(iclass);
+ return RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext);
+}
+
+static inline bool
+RICLASS_FOR_REFINEMENT_P(VALUE iclass)
+{
+ return BUILTIN_TYPE(iclass) == T_ICLASS &&
+ RB_TYPE_P(RBASIC(iclass)->klass, T_MODULE) &&
+ FL_TEST_RAW(RBASIC(iclass)->klass, RMODULE_IS_REFINEMENT);
}
static inline void
RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass)
{
+ RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass);
}
-static inline VALUE
-RCLASS_SUPER(VALUE klass)
+static inline void
+RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool with_self)
{
- return RCLASS(klass)->super;
+ RUBY_ASSERT(depth <= RCLASS_MAX_SUPERCLASS_DEPTH);
+
+ rb_classext_t *ext = RCLASS_EXT_PRIME(klass);
+ RCLASSEXT_SUPERCLASS_DEPTH(ext) = depth;
+ RCLASSEXT_SUPERCLASSES(ext) = superclasses;
+ RCLASSEXT_SUPERCLASSES_WITH_SELF(ext) = with_self;
}
-static inline VALUE
-RCLASS_SET_SUPER(VALUE klass, VALUE super)
+static inline void
+RCLASS_SET_SUBCLASSES(VALUE klass, VALUE subclasses)
{
- if (super) {
- rb_class_remove_from_super_subclasses(klass);
- rb_class_subclass_add(super, klass);
- }
- RB_OBJ_WRITE(klass, &RCLASS(klass)->super, super);
- rb_class_update_superclasses(klass);
- return super;
+ rb_classext_t *ext = RCLASS_EXT_PRIME(klass);
+ RB_OBJ_WRITE(klass, &RCLASSEXT_SUBCLASSES(ext), subclasses);
}
static inline void
RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
{
+ rb_classext_t *ext = RCLASS_EXT_READABLE(klass);
+ assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
+ assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
+ assert(FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE));
+
+ RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
+ RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent;
+}
+
+static inline void
+RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
+{
+ rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
+ assert(!RB_FL_ABLE(classpath) || FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE));
- RB_OBJ_WRITE(klass, &(RCLASS_EXT(klass)->classpath), classpath);
- RCLASS_EXT(klass)->permanent_classpath = permanent;
+ RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
+ RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent;
}
static inline VALUE
@@ -276,8 +709,36 @@ RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
{
assert(RCLASS_SINGLETON_P(klass));
- RB_OBJ_WRITE(klass, &RCLASS_EXT(klass)->as.singleton_class.attached_object, attached_object);
+ RB_OBJ_WRITE(klass, &RCLASS_EXT_PRIME(klass)->as.singleton_class.attached_object, attached_object);
return attached_object;
}
+static inline void
+RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count)
+{
+ RUBY_ASSERT(klass != rb_cObject);
+ RUBY_ASSERT(klass != rb_cBasicObject);
+
+ RCLASS_MAX_IV_COUNT(klass) = count;
+}
+
+static inline void
+RCLASS_SET_EXPECT_NO_IVAR(VALUE klass)
+{
+ RCLASS_EXT_PRIME(klass)->expect_no_ivar = true;
+}
+
+static inline bool
+RCLASS_EXPECT_NO_IVAR(VALUE klass)
+{
+ return RCLASS_EXT_PRIME(klass)->expect_no_ivar;
+}
+
+static inline bool
+RCLASS_INITIALIZED_P(VALUE klass)
+{
+ VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE));
+ return FL_TEST_RAW(klass, RCLASS_IS_INITIALIZED);
+}
+
#endif /* INTERNAL_CLASS_H */
diff --git a/internal/cmdlineopt.h b/internal/cmdlineopt.h
index c12994733e..aed209e2a2 100644
--- a/internal/cmdlineopt.h
+++ b/internal/cmdlineopt.h
@@ -39,6 +39,9 @@ typedef struct ruby_cmdline_options {
#if USE_YJIT
unsigned int yjit: 1;
#endif
+#if USE_ZJIT
+ unsigned int zjit: 1;
+#endif
} ruby_cmdline_options_t;
struct ruby_opt_message {
diff --git a/internal/compar.h b/internal/compar.h
index 9115e4bd63..5eb5e8714e 100644
--- a/internal/compar.h
+++ b/internal/compar.h
@@ -25,5 +25,6 @@
/* compar.c */
VALUE rb_invcmp(VALUE, VALUE);
+NORETURN(void rb_cmperr_reason(VALUE, VALUE, const char*));
#endif /* INTERNAL_COMPAR_H */
diff --git a/internal/concurrent_set.h b/internal/concurrent_set.h
new file mode 100644
index 0000000000..76cbefab04
--- /dev/null
+++ b/internal/concurrent_set.h
@@ -0,0 +1,21 @@
+#ifndef RUBY_RACTOR_SAFE_TABLE_H
+#define RUBY_RACTOR_SAFE_TABLE_H
+
+#include "ruby/atomic.h"
+#include "ruby/ruby.h"
+
+struct rb_concurrent_set_funcs {
+ VALUE (*hash)(VALUE key);
+ bool (*cmp)(VALUE a, VALUE b);
+ VALUE (*create)(VALUE key, void *data);
+ void (*free)(VALUE key);
+};
+
+VALUE rb_concurrent_set_new(const struct rb_concurrent_set_funcs *funcs, int capacity);
+rb_atomic_t rb_concurrent_set_size(VALUE set_obj);
+VALUE rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key);
+VALUE rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data);
+VALUE rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key);
+void rb_concurrent_set_foreach_with_replace(VALUE set_obj, int (*callback)(VALUE *key, void *data), void *data);
+
+#endif
diff --git a/internal/cont.h b/internal/cont.h
index 3c2528a02a..dcf6f820a3 100644
--- a/internal/cont.h
+++ b/internal/cont.h
@@ -31,5 +31,4 @@ VALUE rb_fiber_inherit_storage(struct rb_execution_context_struct *ec, struct rb
VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber);
unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber);
struct rb_execution_context_struct * rb_fiberptr_get_ec(struct rb_fiber_struct *fiber);
-
#endif /* INTERNAL_CONT_H */
diff --git a/internal/encoding.h b/internal/encoding.h
index 29d7dc5c2d..38bf8fc9da 100644
--- a/internal/encoding.h
+++ b/internal/encoding.h
@@ -11,7 +11,6 @@
#include "ruby/ruby.h" /* for ID */
#include "ruby/encoding.h" /* for rb_encoding */
-#define rb_enc_autoload_p(enc) (!rb_enc_mbmaxlen(enc))
#define rb_is_usascii_enc(enc) ((enc) == rb_usascii_encoding())
#define rb_is_ascii8bit_enc(enc) ((enc) == rb_ascii8bit_encoding())
#define rb_is_locale_enc(enc) ((enc) == rb_locale_encoding())
@@ -24,11 +23,13 @@ rb_encoding *rb_enc_check_str(VALUE str1, VALUE str2);
int rb_encdb_replicate(const char *alias, const char *orig);
int rb_encdb_alias(const char *alias, const char *orig);
int rb_enc_autoload(rb_encoding *enc);
+bool rb_enc_autoload_p(rb_encoding *enc);
int rb_encdb_dummy(const char *name);
void rb_encdb_declare(const char *name);
void rb_enc_set_base(const char *name, const char *orig);
int rb_enc_set_dummy(int index);
void rb_enc_raw_set(VALUE obj, rb_encoding *enc);
+int rb_enc_registered(const char *name);
PUREFUNC(int rb_data_is_encoding(VALUE obj));
diff --git a/internal/error.h b/internal/error.h
index 5d53f96b8e..fead2aee95 100644
--- a/internal/error.h
+++ b/internal/error.h
@@ -75,11 +75,11 @@ PRINTF_ARGS(void rb_warn_deprecated_to_remove(const char *removal, const char *f
PRINTF_ARGS(void rb_warn_reserved_name(const char *removal, const char *fmt, ...), 2, 3);
#if RUBY_DEBUG
# include "ruby/version.h"
-# define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major * 10000) + (minor) * 100)
-# define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major * 10000) + (minor) * 100)
+# define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major) * 10000 + (minor) * 100)
+# define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major) * 10000 + (minor) * 100)
# if defined(RBIMPL_WARNING_PRAGMA0)
# define RBIMPL_TODO0(x) RBIMPL_WARNING_PRAGMA0(message(x))
-# elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+# elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_TODO0(x) __pragma(message(x))
# endif
@@ -186,6 +186,9 @@ static inline void Check_Type(VALUE v, enum ruby_value_type t);
static inline bool rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type);
#define rb_typeddata_is_instance_of rb_typeddata_is_instance_of_inline
void rb_bug_without_die(const char *fmt, ...);
+NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname));
+NORETURN(void rb_cant_convert(VALUE val, const char *tname));
+NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret));
RUBY_SYMBOL_EXPORT_BEGIN
/* error.c (export) */
@@ -235,10 +238,18 @@ rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name)
rb_exc_raise(exc);
}
+RBIMPL_ATTR_NONNULL((2))
static inline bool
rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type)
{
- return RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj) && (RTYPEDDATA_TYPE(obj) == data_type);
+ return rbimpl_obj_typeddata_p(obj) && (RTYPEDDATA_TYPE(obj) == data_type);
}
+typedef enum {
+ rb_stack_overflow_prevention = 0, // VM stack overflow or about to machine stack overflow
+ rb_stack_overflow_signal = 1, // machine stack overflow but may be recoverable
+ rb_stack_overflow_fatal = 2, // fatal machine stack overflow
+} ruby_stack_overflow_critical_level;
+NORETURN(void rb_ec_stack_overflow(struct rb_execution_context_struct *ec, ruby_stack_overflow_critical_level crit));
+
#endif /* INTERNAL_ERROR_H */
diff --git a/internal/eval.h b/internal/eval.h
index e594d8516d..17ade0a7f1 100644
--- a/internal/eval.h
+++ b/internal/eval.h
@@ -11,17 +11,27 @@
* header (related to this file, but not the same role).
*/
#include "ruby/ruby.h" /* for ID */
+#include "vm_core.h" /* for ID */
#define id_signo ruby_static_id_signo
#define id_status ruby_static_id_status
/* eval.c */
+struct rb_refinements_data {
+ VALUE refinement;
+ VALUE refinements;
+};
+
extern ID ruby_static_id_signo;
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_exception_setup(int argc, VALUE *argv);
+void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass);
+void rb_vm_using_module(VALUE module);
VALUE rb_top_main_class(const char *method);
+VALUE rb_ec_ensure(rb_execution_context_t *ec, VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2);
/* eval_error.c */
VALUE rb_get_backtrace(VALUE info);
diff --git a/internal/file.h b/internal/file.h
index 9c192ff4d1..1aa4c67043 100644
--- a/internal/file.h
+++ b/internal/file.h
@@ -23,7 +23,9 @@ VALUE rb_file_expand_path_fast(VALUE, VALUE);
VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE);
VALUE rb_get_path_check_to_string(VALUE);
VALUE rb_get_path_check_convert(VALUE);
+VALUE rb_get_path_check_no_convert(VALUE);
int ruby_is_fd_loadable(int fd);
+char *rb_enc_path_skip_prefix_root(const char *path, const char *end, rb_encoding *enc);
RUBY_SYMBOL_EXPORT_BEGIN
/* file.c (export) */
diff --git a/internal/gc.h b/internal/gc.h
index 454f8ec685..8b136e6572 100644
--- a/internal/gc.h
+++ b/internal/gc.h
@@ -83,8 +83,6 @@ rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
#define RUBY_GC_INFO if(0)printf
#endif
-#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
@@ -122,10 +120,11 @@ const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
struct rb_execution_context_struct; /* in vm_core.h */
struct rb_objspace; /* in vm_core.h */
-#define NEWOBJ_OF(var, T, c, f, s, ec) \
- T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
- rb_wb_protected_newobj_of((ec ? ec : GET_EC()), (c), (f) & ~FL_WB_PROTECTED, s) : \
- rb_wb_unprotected_newobj_of((c), (f), s))
+#define EC_NEWOBJ_OF(var, T, c, f, s, ec) \
+ T *(var) = (T *)rb_ec_newobj_of((ec), (c), (f), s)
+#define NEWOBJ_OF(var, T, c, f, s) EC_NEWOBJ_OF(var, T, c, f, s, GET_EC())
+#define UNPROTECTED_NEWOBJ_OF(var, T, c, f, s) \
+ T *(var) = (T *)rb_newobj((GET_EC()), (c), (f), ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, false, s)
#ifndef RB_GC_OBJECT_METADATA_ENTRY_DEFINED
# define RB_GC_OBJECT_METADATA_ENTRY_DEFINED
@@ -183,7 +182,6 @@ struct rb_gc_object_metadata_entry {
/* gc.c */
RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size);
RUBY_ATTR_MALLOC void *ruby_mimcalloc(size_t num, size_t size);
-void rb_gc_ractor_moved(VALUE dest, VALUE src);
void ruby_mimfree(void *ptr);
void rb_gc_prepare_heap(void);
void rb_objspace_set_event_hook(const rb_event_flag_t event);
@@ -199,9 +197,9 @@ 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);
RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add_mul(size_t, size_t, size_t, size_t);
RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t);
-static inline void *ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2));
-static inline void *ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3));
-static inline void ruby_sized_xfree_inlined(void *ptr, size_t size);
+void rb_gc_obj_id_moved(VALUE obj);
+void rb_gc_register_pinning_obj(VALUE obj);
+rb_execution_context_t *rb_gc_get_ec(void);
void *rb_gc_ractor_cache_alloc(rb_ractor_t *ractor);
void rb_gc_ractor_cache_free(void *cache);
@@ -212,8 +210,8 @@ size_t rb_gc_heap_id_for_size(size_t size);
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_declare_weak_references(VALUE obj);
+bool rb_gc_handle_weak_references_alive_p(VALUE obj);
void rb_gc_ref_update_table_values_only(st_table *tbl);
@@ -248,87 +246,62 @@ 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_unprotected_newobj_of(VALUE, VALUE, size_t);
+VALUE rb_newobj(struct rb_execution_context_struct *, VALUE, VALUE, uint32_t /* shape_id_t */, bool, size_t);
+VALUE rb_newobj_of(VALUE, VALUE, size_t);
+VALUE rb_ec_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t);
size_t rb_obj_memsize_of(VALUE);
struct rb_gc_object_metadata_entry *rb_gc_object_metadata(VALUE obj);
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);
+void rb_gc_mark_set_no_pin(st_table *);
+void rb_gc_update_set_refs(st_table *);
+#if USE_MODULAR_GC
const char *rb_gc_active_gc_name(void);
int rb_gc_modular_gc_loaded_p(void);
+#endif
RUBY_SYMBOL_EXPORT_END
-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);
-void ruby_annotate_mmap(const void *addr, unsigned long size, const char *name);
-
-#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32)
-
-static inline void *
-ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size)
-{
- return ruby_xrealloc(ptr, new_size);
-}
-
-static inline void *
-ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count)
-{
- return ruby_xrealloc2(ptr, new_count, elemsiz);
-}
-
-static inline void
-ruby_sized_xfree_inlined(void *ptr, size_t size)
-{
- ruby_xfree(ptr);
-}
-
-# 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)
+static inline VALUE
+rb_obj_atomic_write(
+ VALUE a, VALUE *slot, VALUE b,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
{
- return ruby_xrealloc2(ptr, new_count, element_size);
-}
-
-#else
+#ifdef RGENGC_LOGGING_WRITE
+ RGENGC_LOGGING_WRITE(a, slot, b, filename, line);
+#endif
-static inline void *
-ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size)
-{
- return ruby_sized_xrealloc(ptr, new_size, old_size);
-}
+ RUBY_ATOMIC_VALUE_SET(*slot, b);
-static inline void *
-ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count)
-{
- return ruby_sized_xrealloc2(ptr, new_count, elemsiz, old_count);
+ rb_obj_written(a, RUBY_Qundef /* ignore `oldv' now */, b, filename, line);
+ return a;
}
+#define RB_OBJ_ATOMIC_WRITE(old, slot, young) \
+ RBIMPL_CAST(rb_obj_atomic_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young), __FILE__, __LINE__))
-static inline void
-ruby_sized_xfree_inlined(void *ptr, size_t size)
-{
- ruby_sized_xfree(ptr, size);
-}
+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);
+void ruby_annotate_mmap(const void *addr, unsigned long size, const char *name);
# define SIZED_REALLOC_N(v, T, m, n) \
- ((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n)))
+ ((v) = (T *)ruby_xrealloc2_sized((void *)(v), (m), sizeof(T), (n)))
+
+# define SIZED_FREE(v) ruby_xfree_sized((void *)(v), sizeof(*(v)))
+# define SIZED_FREE_N(v, n) ruby_xfree_sized((void *)(v), sizeof(*(v)) * (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);
+ return ruby_xrealloc2_sized(ptr, new_count, element_size, old_count);
}
-#endif /* HAVE_MALLOC_USABLE_SIZE */
+void rb_gc_verify_shareable(VALUE);
+bool rb_gc_checking_shareable(void);
-#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined
-#define ruby_sized_xrealloc2 ruby_sized_xrealloc2_inlined
-#define ruby_sized_xfree ruby_sized_xfree_inlined
#endif /* INTERNAL_GC_H */
diff --git a/internal/hash.h b/internal/hash.h
index 676f140496..0386a5009c 100644
--- a/internal/hash.h
+++ b/internal/hash.h
@@ -70,8 +70,8 @@ struct RHash {
#endif
/* hash.c */
-void rb_hash_st_table_set(VALUE hash, st_table *st);
VALUE rb_hash_default_value(VALUE hash, VALUE key);
+VALUE rb_hash_set_default(VALUE hash, VALUE ifnone);
VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
long rb_dbl_long_hash(double d);
st_table *rb_init_identtable(void);
@@ -87,6 +87,7 @@ 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);
bool rb_hash_default_unredefined(VALUE hash);
+VALUE rb_hash_alloc_fixed_size(VALUE klass, st_index_t size);
VALUE rb_ident_hash_new_with_size(st_index_t size);
void rb_hash_free(VALUE hash);
RUBY_EXTERN VALUE rb_cHash_empty_frozen;
@@ -110,6 +111,7 @@ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t
RUBY_SYMBOL_EXPORT_END
VALUE rb_hash_new_with_size(st_index_t size);
+VALUE rb_hash_new_with_bulk_insert(long argc, const VALUE *argv);
VALUE rb_hash_resurrect(VALUE hash);
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
VALUE rb_hash_keys(VALUE hash);
@@ -190,4 +192,19 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
return (unsigned)ret;
}
+#define RHASH_AR_TABLE_BOUND_RAW(h) \
+ ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
+ (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
+
+#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
+
+static inline unsigned int
+RHASH_AR_TABLE_BOUND(VALUE h)
+{
+ RUBY_ASSERT(RHASH_AR_TABLE_P(h));
+ const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
+ RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
+ return bound;
+}
+
#endif /* INTERNAL_HASH_H */
diff --git a/internal/imemo.h b/internal/imemo.h
index a28ad92f7b..e8a5f0fc8e 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -10,6 +10,7 @@
*/
#include "ruby/internal/config.h"
#include <stddef.h> /* for size_t */
+#include "id_table.h"
#include "internal/array.h" /* for rb_ary_hidden_new_fill */
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for rb_block_call_func_t */
@@ -24,6 +25,7 @@
#define IMEMO_FL_USER3 FL_USER7
#define IMEMO_FL_USER4 FL_USER8
#define IMEMO_FL_USER5 FL_USER9
+#define IMEMO_FL_USER6 FL_USER10
enum imemo_type {
imemo_env = 0,
@@ -35,11 +37,13 @@ enum imemo_type {
imemo_ment = 6,
imemo_iseq = 7,
imemo_tmpbuf = 8,
- imemo_ast = 9, // Obsolete due to the universal parser
- imemo_parser_strterm = 10,
- imemo_callinfo = 11,
- imemo_callcache = 12,
- imemo_constcache = 13,
+ imemo_cvar_entry = 9,
+ imemo_callinfo = 10,
+ imemo_callcache = 11,
+ imemo_constcache = 12,
+ imemo_fields = 13,
+ imemo_subclasses = 14,
+ imemo_cdhash = 15,
};
/* CREF (Class REFerence) is defined in method.h */
@@ -56,7 +60,6 @@ struct vm_svar {
/*! THROW_DATA */
struct vm_throw_data {
VALUE flags;
- VALUE reserved;
const VALUE throw_obj;
const struct rb_control_frame_struct *catch_frame;
int throw_state;
@@ -92,30 +95,36 @@ struct vm_ifunc {
struct rb_imemo_tmpbuf_struct {
VALUE flags;
- VALUE reserved;
VALUE *ptr; /* malloc'ed buffer */
- struct rb_imemo_tmpbuf_struct *next; /* next imemo */
- size_t cnt; /* buffer size in VALUE */
+ size_t size; /* buffer size in bytes */
};
+struct rb_imemo_cdhash {
+ VALUE flags;
+ st_table tbl;
+};
+
+/* Set on imemo_memo when u3 holds a VALUE that GC must mark.
+ * When unset, u3 is a non-VALUE (cnt/state). */
+#define MEMO_U3_IS_VALUE IMEMO_FL_USER0
+
/*! MEMO
*
* @see imemo_type
* */
struct MEMO {
VALUE flags;
- VALUE reserved;
const VALUE v1;
const VALUE v2;
union {
long cnt;
long state;
const VALUE value;
- void (*func)(void);
} u3;
};
-#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T)))
+#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), false))
+#define SHAREABLE_IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), true))
/* ment is in method.h */
@@ -132,41 +141,27 @@ struct MEMO {
#ifndef RUBY_RUBYPARSER_H
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
#endif
-rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt);
+VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable);
+VALUE rb_imemo_tmpbuf_new(void);
+struct MEMO *rb_imemo_memo_new(VALUE a, VALUE b, long c);
+struct MEMO *rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
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);
static inline struct vm_ifunc *rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data);
-static inline VALUE rb_imemo_tmpbuf_auto_free_pointer(void);
static inline void *RB_IMEMO_TMPBUF_PTR(VALUE v);
-static inline void *rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr);
-static inline VALUE rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str);
static inline void MEMO_V1_SET(struct MEMO *m, VALUE v);
static inline void MEMO_V2_SET(struct MEMO *m, VALUE v);
size_t rb_imemo_memsize(VALUE obj);
-void rb_cc_table_mark(VALUE klass);
void rb_imemo_mark_and_move(VALUE obj, bool reference_updating);
-void rb_cc_table_free(VALUE klass);
void rb_imemo_free(VALUE obj);
RUBY_SYMBOL_EXPORT_BEGIN
-VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size);
const char *rb_imemo_name(enum imemo_type type);
RUBY_SYMBOL_EXPORT_END
-static inline struct MEMO *
-MEMO_NEW(VALUE a, VALUE b, VALUE c)
-{
- struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
- *((VALUE *)&memo->v1) = a;
- *((VALUE *)&memo->v2) = b;
- *((VALUE *)&memo->u3.value) = c;
-
- return memo;
-}
-
static inline enum imemo_type
imemo_type(VALUE imemo)
{
@@ -202,12 +197,6 @@ rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data)
return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
}
-static inline VALUE
-rb_imemo_tmpbuf_auto_free_pointer(void)
-{
- return rb_imemo_new(imemo_tmpbuf, 0, sizeof(rb_imemo_tmpbuf_t));
-}
-
static inline void *
RB_IMEMO_TMPBUF_PTR(VALUE v)
{
@@ -215,30 +204,16 @@ RB_IMEMO_TMPBUF_PTR(VALUE v)
return p->ptr;
}
-static inline void *
-rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr)
-{
- return ((rb_imemo_tmpbuf_t *)v)->ptr = ptr;
-}
-
static inline VALUE
-rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str)
+rb_imemo_tmpbuf_new_from_an_RString(VALUE str)
{
- const void *src;
VALUE imemo;
- rb_imemo_tmpbuf_t *tmpbuf;
- void *dst;
size_t len;
StringValue(str);
- /* create tmpbuf to keep the pointer before xmalloc */
- imemo = rb_imemo_tmpbuf_auto_free_pointer();
- tmpbuf = (rb_imemo_tmpbuf_t *)imemo;
len = RSTRING_LEN(str);
- src = RSTRING_PTR(str);
- dst = ruby_xmalloc(len);
- memcpy(dst, src, len);
- tmpbuf->ptr = dst;
+ rb_alloc_tmp_buffer(&imemo, len);
+ memcpy(RB_IMEMO_TMPBUF_PTR(imemo), RSTRING_PTR(str), len);
return imemo;
}
@@ -254,4 +229,108 @@ MEMO_V2_SET(struct MEMO *m, VALUE v)
RB_OBJ_WRITE(m, &m->v2, v);
}
+VALUE rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type);
+
+static inline st_table *
+rb_imemo_cdhash_tbl(VALUE obj)
+{
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_cdhash));
+ return &((struct rb_imemo_cdhash *)obj)->tbl;
+}
+
+struct rb_fields {
+ struct RBasic basic;
+ union {
+ struct {
+ VALUE fields[1];
+ } embed;
+ struct {
+ VALUE *ptr;
+ } external;
+ struct {
+ // Note: the st_table could be embedded, but complex T_CLASS should be rare to
+ // non-existent, so not really worth the trouble.
+ st_table *table;
+ } complex;
+ } as;
+};
+
+// IMEMO/fields and T_OBJECT have exactly the same layout.
+// This is useful for JIT and common codepaths.
+#define OBJ_FIELD_HEAP ROBJECT_HEAP
+STATIC_ASSERT(imemo_fields_flags, OBJ_FIELD_HEAP == IMEMO_FL_USER0);
+STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.ary) == offsetof(struct rb_fields, as.embed.fields));
+STATIC_ASSERT(imemo_fields_external_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.external.ptr));
+STATIC_ASSERT(imemo_fields_complex_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.complex.table));
+
+#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)
+
+#define IMEMO_SUBCLASSES_HEAP IMEMO_FL_USER0
+
+struct rb_subclasses {
+ VALUE flags;
+ uint32_t count;
+ uint32_t capacity;
+ union {
+ VALUE *external;
+ VALUE embed[1];
+ } as;
+};
+
+static inline VALUE *
+rb_imemo_subclasses_entries(VALUE v)
+{
+ struct rb_subclasses *s = (struct rb_subclasses *)v;
+ return FL_TEST_RAW(v, IMEMO_SUBCLASSES_HEAP) ? s->as.external : s->as.embed;
+}
+
+VALUE rb_imemo_fields_new(VALUE owner, /* shape_id_t */ uint32_t shape_id, bool shareable);
+VALUE rb_imemo_subclasses_new(uint32_t capacity);
+VALUE rb_imemo_fields_new_complex(VALUE owner, /* shape_id_t */ uint32_t shape_id, size_t capa, bool shareable);
+VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, /* shape_id_t */ uint32_t shape_id, st_table *tbl, bool shareable);
+VALUE rb_imemo_fields_clone(VALUE fields_obj);
+void rb_imemo_fields_clear(VALUE fields_obj);
+
+static inline VALUE
+rb_imemo_fields_owner(VALUE fields_obj)
+{
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields));
+
+ return CLASS_OF(fields_obj);
+}
+
+static inline VALUE *
+rb_imemo_fields_ptr(VALUE fields_obj)
+{
+ if (!fields_obj) {
+ return NULL;
+ }
+
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT));
+
+ if (UNLIKELY(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP))) {
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.external.ptr;
+ }
+ else {
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.embed.fields;
+ }
+}
+
+static inline st_table *
+rb_imemo_fields_complex_tbl(VALUE fields_obj)
+{
+ if (!fields_obj) {
+ return NULL;
+ }
+
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT));
+ RUBY_ASSERT(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP));
+
+ // Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the
+ // shape is complex.
+ RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table);
+
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table;
+}
+
#endif /* INTERNAL_IMEMO_H */
diff --git a/internal/inits.h b/internal/inits.h
index 03de289dd4..be73dac1dc 100644
--- a/internal/inits.h
+++ b/internal/inits.h
@@ -9,6 +9,10 @@
* @brief Internal header aggregating init functions.
*/
+/* box.c */
+void Init_enable_box(void);
+void Init_master_box(void);
+
/* class.c */
void Init_class_hierarchy(void);
diff --git a/internal/io.h b/internal/io.h
index b4efa174a1..2110f0b087 100644
--- a/internal/io.h
+++ b/internal/io.h
@@ -14,10 +14,21 @@
struct rb_io;
#include "ruby/io.h" /* for rb_io_t */
+#include "ccan/list/list.h"
+#include "serial.h"
#define IO_WITHOUT_GVL(func, arg) rb_nogvl(func, arg, RUBY_UBF_IO, 0, RB_NOGVL_OFFLOAD_SAFE)
#define IO_WITHOUT_GVL_INT(func, arg) (int)(VALUE)IO_WITHOUT_GVL(func, arg)
+// Represents an in-flight blocking operation:
+struct rb_io_blocking_operation {
+ // The linked list data structure.
+ struct ccan_list_node list;
+
+ // The execution context of the blocking operation.
+ struct rb_execution_context_struct *ec;
+};
+
/** Ruby's IO, metadata and buffers. */
struct rb_io {
@@ -31,7 +42,7 @@ struct rb_io {
int fd;
/** mode flags: FMODE_XXXs */
- int mode;
+ enum rb_io_mode mode;
/** child's pid (for pipes) */
rb_pid_t pid;
@@ -111,6 +122,18 @@ struct rb_io {
* The timeout associated with this IO when performing blocking operations.
*/
VALUE timeout;
+
+ /**
+ * Threads that are performing a blocking operation without the GVL using
+ * this IO. On calling IO#close, these threads will be interrupted so that
+ * the operation can be cancelled.
+ */
+ struct ccan_list_head blocking_operations;
+ struct rb_execution_context_struct *closing_ec;
+ VALUE wakeup_mutex;
+
+ // The fork generation of the blocking operations list.
+ rb_serial_t fork_generation;
};
/* io.c */
@@ -119,17 +142,15 @@ void rb_stdio_set_default_encoding(void);
VALUE rb_io_flush_raw(VALUE, int);
size_t rb_io_memsize(const rb_io_t *);
int rb_stderr_tty_p(void);
-void rb_io_fptr_finalize_internal(void *ptr);
-#ifdef rb_io_fptr_finalize
-# undef rb_io_fptr_finalize
-#endif
-#define rb_io_fptr_finalize rb_io_fptr_finalize_internal
VALUE rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt);
VALUE rb_io_prep_stdin(void);
VALUE rb_io_prep_stdout(void);
VALUE rb_io_prep_stderr(void);
+int rb_io_notify_close(struct rb_io *fptr);
+bool rb_io_fptr_finalize_closed(struct rb_io *fptr);
+
RUBY_SYMBOL_EXPORT_BEGIN
/* io.c (export) */
void rb_maygvl_fd_fix_cloexec(int fd);
diff --git a/internal/load.h b/internal/load.h
index d4c0bb91ba..6cffe0ce64 100644
--- a/internal/load.h
+++ b/internal/load.h
@@ -12,6 +12,8 @@
/* load.c */
VALUE rb_get_expanded_load_path(void);
+VALUE rb_load_entrypoint(VALUE fname, VALUE wrap);
+VALUE rb_require_relative_entrypoint(VALUE fname);
int rb_require_internal(VALUE fname);
NORETURN(void rb_load_fail(VALUE, const char*));
diff --git a/internal/numeric.h b/internal/numeric.h
index 6406cfc2fa..a24432df1e 100644
--- a/internal/numeric.h
+++ b/internal/numeric.h
@@ -10,9 +10,9 @@
*/
#include "internal/bignum.h" /* for BIGNUM_POSITIVE_P */
#include "internal/bits.h" /* for RUBY_BIT_ROTL */
+#include "internal/compar.h" /* for rb_cmperr_reason */
#include "internal/fixnum.h" /* for FIXNUM_POSITIVE_P */
#include "internal/vm.h" /* for rb_method_basic_definition_p */
-#include "ruby/intern.h" /* for rb_cmperr */
#include "ruby/ruby.h" /* for USE_FLONUM */
#define ROUND_TO(mode, even, up, down) \
@@ -70,6 +70,7 @@ VALUE rb_float_minus(VALUE x, VALUE y);
VALUE rb_int_mul(VALUE x, VALUE y);
VALUE rb_float_mul(VALUE x, VALUE y);
VALUE rb_float_div(VALUE x, VALUE y);
+VALUE rb_flo_to_i(VALUE num);
VALUE rb_int_idiv(VALUE x, VALUE y);
VALUE rb_int_modulo(VALUE x, VALUE y);
VALUE rb_int2str(VALUE num, int base);
@@ -78,6 +79,7 @@ VALUE rb_int_gt(VALUE x, VALUE y);
VALUE rb_float_gt(VALUE x, VALUE y);
VALUE rb_int_ge(VALUE x, VALUE y);
enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts);
+VALUE rb_int_fdiv(VALUE x, VALUE y);
double rb_int_fdiv_double(VALUE x, VALUE y);
VALUE rb_int_pow(VALUE x, VALUE y);
VALUE rb_float_pow(VALUE x, VALUE y);
@@ -85,6 +87,7 @@ VALUE rb_int_cmp(VALUE x, VALUE y);
VALUE rb_int_equal(VALUE x, VALUE y);
VALUE rb_int_divmod(VALUE x, VALUE y);
VALUE rb_int_and(VALUE x, VALUE y);
+VALUE rb_int_xor(VALUE x, VALUE y);
VALUE rb_int_lshift(VALUE x, VALUE y);
VALUE rb_int_rshift(VALUE x, VALUE y);
VALUE rb_int_div(VALUE x, VALUE y);
@@ -126,6 +129,54 @@ VALUE rb_int_bit_length(VALUE num);
VALUE rb_int_uminus(VALUE num);
VALUE rb_int_comp(VALUE num);
+// Unified 128-bit integer structures that work with or without native support:
+union rb_uint128 {
+#ifdef WORDS_BIGENDIAN
+ struct {
+ uint64_t high;
+ uint64_t low;
+ } parts;
+#else
+ struct {
+ uint64_t low;
+ uint64_t high;
+ } parts;
+#endif
+#ifdef HAVE_UINT128_T
+ uint128_t value;
+#endif
+};
+typedef union rb_uint128 rb_uint128_t;
+
+union rb_int128 {
+#ifdef WORDS_BIGENDIAN
+ struct {
+ uint64_t high;
+ uint64_t low;
+ } parts;
+#else
+ struct {
+ uint64_t low;
+ uint64_t high;
+ } parts;
+#endif
+#ifdef HAVE_UINT128_T
+ int128_t value;
+#endif
+};
+typedef union rb_int128 rb_int128_t;
+
+union uint128_int128_conversion {
+ rb_uint128_t uint128;
+ rb_int128_t int128;
+};
+
+// Conversion functions for 128-bit integers:
+rb_uint128_t rb_numeric_to_uint128(VALUE x);
+rb_int128_t rb_numeric_to_int128(VALUE x);
+VALUE rb_uint128_to_numeric(rb_uint128_t n);
+VALUE rb_int128_to_numeric(rb_int128_t n);
+
static inline bool
INT_POSITIVE_P(VALUE num)
{
@@ -160,7 +211,7 @@ rb_num_compare_with_zero(VALUE num, ID mid)
VALUE zero = INT2FIX(0);
VALUE r = rb_check_funcall(num, mid, 1, &zero);
if (RB_UNDEF_P(r)) {
- rb_cmperr(num, zero);
+ rb_cmperr_reason(num, zero, "unable to compare with zero");
}
return r;
}
diff --git a/internal/object.h b/internal/object.h
index 92ad37fdc8..99aa1f524b 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -11,7 +11,7 @@
#include "ruby/ruby.h" /* for VALUE */
/* object.c */
-size_t rb_obj_embedded_size(uint32_t numiv);
+
VALUE rb_class_allocate_instance(VALUE klass);
VALUE rb_class_search_ancestor(VALUE klass, VALUE super);
NORETURN(void rb_undefined_alloc(VALUE klass));
@@ -60,4 +60,13 @@ RBASIC_SET_CLASS(VALUE obj, VALUE klass)
RBASIC_SET_CLASS_RAW(obj, klass);
RB_OBJ_WRITTEN(obj, oldv, klass);
}
+
+static inline size_t
+rb_obj_embedded_size(uint32_t fields_count)
+{
+ size_t size = offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count);
+ // Ensure enough room for the heap pointer if this expands
+ if (size < sizeof(struct RObject)) size = sizeof(struct RObject);
+ return size;
+}
#endif /* INTERNAL_OBJECT_H */
diff --git a/internal/range.h b/internal/range.h
index 2394937bf8..80493ce13e 100644
--- a/internal/range.h
+++ b/internal/range.h
@@ -18,19 +18,19 @@ static inline VALUE RANGE_EXCL(VALUE r);
static inline VALUE
RANGE_BEG(VALUE r)
{
- return RSTRUCT(r)->as.ary[0];
+ return RSTRUCT_GET_RAW(r, 0);
}
static inline VALUE
RANGE_END(VALUE r)
{
- return RSTRUCT_GET(r, 1);
+ return RSTRUCT_GET_RAW(r, 1);
}
static inline VALUE
RANGE_EXCL(VALUE r)
{
- return RSTRUCT_GET(r, 2);
+ return RSTRUCT_GET_RAW(r, 2);
}
VALUE
diff --git a/internal/rational.h b/internal/rational.h
index f11fab4583..6861a90130 100644
--- a/internal/rational.h
+++ b/internal/rational.h
@@ -28,6 +28,7 @@ VALUE rb_rational_plus(VALUE self, VALUE other);
VALUE rb_rational_minus(VALUE self, VALUE other);
VALUE rb_rational_mul(VALUE self, VALUE other);
VALUE rb_rational_div(VALUE self, VALUE other);
+VALUE rb_rational_fdiv(VALUE self, VALUE other);
VALUE rb_lcm(VALUE x, VALUE y);
VALUE rb_rational_reciprocal(VALUE x);
VALUE rb_cstr_to_rat(const char *, int);
@@ -37,7 +38,9 @@ VALUE rb_rational_cmp(VALUE self, VALUE other);
VALUE rb_rational_pow(VALUE self, VALUE other);
VALUE rb_rational_floor(VALUE self, int ndigits);
VALUE rb_numeric_quo(VALUE x, VALUE y);
-VALUE rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num);
+VALUE rb_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode);
+VALUE rb_flo_ceil_by_rational(VALUE num, int ndigits);
+VALUE rb_flo_floor_by_rational(VALUE num, int ndigits);
VALUE rb_float_numerator(VALUE x);
VALUE rb_float_denominator(VALUE x);
@@ -68,4 +71,22 @@ RATIONAL_SET_DEN(VALUE r, VALUE d)
RB_OBJ_WRITE(r, &RRATIONAL(r)->den, d);
}
+inline static bool
+f_zero_p(VALUE x)
+{
+ if (RB_INTEGER_TYPE_P(x)) {
+ return FIXNUM_ZERO_P(x);
+ }
+ else if (RB_FLOAT_TYPE_P(x)) {
+ return FLOAT_ZERO_P(x);
+ }
+ else if (RB_TYPE_P(x, T_RATIONAL)) {
+ const VALUE num = RRATIONAL(x)->num;
+ return FIXNUM_ZERO_P(num);
+ }
+ return rb_equal(x, INT2FIX(0)) != 0;
+}
+
+#define f_nonzero_p(x) (!f_zero_p(x))
+
#endif /* INTERNAL_RATIONAL_H */
diff --git a/internal/re.h b/internal/re.h
index 2788f8b42a..6c0aee6d06 100644
--- a/internal/re.h
+++ b/internal/re.h
@@ -10,19 +10,70 @@
*/
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for VALUE */
+#include "ruby/re.h" /* for struct RMatch and struct re_registers */
+
+#define RMATCH_ONIG FL_USER1
+#define RMATCH_OFFSETS_EXTERNAL FL_USER2
+
+static inline OnigPosition *
+RMATCH_BEG_PTR(VALUE match)
+{
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) {
+ return RMATCH(match)->as.onig.beg;
+ }
+ else {
+ return &RMATCH(match)->as.embed[0];
+ }
+}
+
+static inline OnigPosition *
+RMATCH_END_PTR(VALUE match)
+{
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) {
+ return RMATCH(match)->as.onig.end;
+ }
+ else {
+ return &RMATCH(match)->as.embed[RMATCH(match)->num_regs];
+ }
+}
+
+static inline long
+RMATCH_BEG(VALUE match, int i)
+{
+ return RMATCH_BEG_PTR(match)[i];
+}
+
+static inline long
+RMATCH_END(VALUE match, int i)
+{
+ return RMATCH_END_PTR(match)[i];
+}
+
+static inline int
+RMATCH_NREGS(VALUE match)
+{
+ return RMATCH(match)->num_regs;
+}
/* re.c */
+VALUE rb_reg_s_alloc(VALUE klass);
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline);
VALUE rb_reg_check_preprocess(VALUE);
long rb_reg_search0(VALUE, VALUE, long, int, int, VALUE *);
VALUE rb_reg_match_p(VALUE re, VALUE str, long pos);
+VALUE rb_reg_regsub_match(VALUE str, VALUE src, VALUE match);
bool rb_reg_start_with_p(VALUE re, VALUE str);
VALUE rb_reg_hash(VALUE re);
VALUE rb_reg_equal(VALUE re1, VALUE re2);
VALUE rb_backref_set_string(VALUE string, long pos, long len);
void rb_match_unbusy(VALUE);
int rb_match_count(VALUE match);
-VALUE rb_reg_new_ary(VALUE ary, int options);
+VALUE rb_reg_new_from_values(long cnt, const VALUE *elements, int opt);
VALUE rb_reg_last_defined(VALUE match);
+#define ARG_REG_OPTION_MASK \
+ (ONIG_OPTION_IGNORECASE|ONIG_OPTION_MULTILINE|ONIG_OPTION_EXTEND)
+#define ARG_ENCODING_FIXED 16
+#define ARG_ENCODING_NONE 32
+
#endif /* INTERNAL_RE_H */
diff --git a/internal/sanitizers.h b/internal/sanitizers.h
index 279cbbe069..feafb4e616 100644
--- a/internal/sanitizers.h
+++ b/internal/sanitizers.h
@@ -29,6 +29,13 @@
# endif
#endif
+#ifdef HAVE_SANITIZER_TSAN_INTERFACE_H
+# if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
+# define RUBY_TSAN_ENABLED
+# include <sanitizer/tsan_interface.h>
+# endif
+#endif
+
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for VALUE */
@@ -42,6 +49,9 @@
#elif defined(RUBY_MSAN_ENABLED)
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
__attribute__((__no_sanitize__("memory"), __noinline__)) x
+#elif defined(RUBY_TSAN_ENABLED)
+# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
+ __attribute__((__no_sanitize__("thread"), __noinline__)) x
#elif defined(NO_SANITIZE_ADDRESS)
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
NO_SANITIZE_ADDRESS(NOINLINE(x))
@@ -127,6 +137,7 @@ asan_poison_memory_region(const volatile void *ptr, size_t size)
#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
#endif
+#ifdef RUBY_ASAN_ENABLED
RUBY_SYMBOL_EXPORT_BEGIN
/**
* This is a variant of asan_poison_memory_region that takes a VALUE.
@@ -153,6 +164,11 @@ void *rb_asan_poisoned_object_p(VALUE obj);
void rb_asan_unpoison_object(VALUE obj, bool newobj_p);
RUBY_SYMBOL_EXPORT_END
+#else
+# define rb_asan_poison_object(obj) ((void)obj)
+# define rb_asan_poisoned_object_p(obj) ((void)obj, NULL)
+# define rb_asan_unpoison_object(obj, newobj_p) ((void)obj, (void)newobj_p)
+#endif
/**
* This function asserts that a (formally poisoned) memory region from ptr to
diff --git a/internal/set_table.h b/internal/set_table.h
new file mode 100644
index 0000000000..3876a8935e
--- /dev/null
+++ b/internal/set_table.h
@@ -0,0 +1,74 @@
+#ifndef INTERNAL_SET_TABLE_H
+#define INTERNAL_SET_TABLE_H
+
+#include "ruby/st.h"
+
+struct set_table_entry;
+
+typedef struct set_table_entry set_table_entry;
+
+struct set_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 st_hash_type *type;
+ /* Number of entries currently in the table. */
+ st_index_t num_entries;
+
+ /* Start and bound index of entries in array entries.
+ entries_starts and entries_bound are in interval
+ [0,allocated_entries]. */
+ st_index_t entries_start, entries_bound;
+
+ /**
+ * Array of size 2^entry_power.
+ * Followed by st_index_t *bins, Array of bins used for access by keys.
+ */
+ set_table_entry *entries;
+};
+
+typedef struct set_table set_table;
+
+typedef int set_foreach_callback_func(st_data_t, st_data_t);
+typedef int set_foreach_check_callback_func(st_data_t, st_data_t, int);
+typedef int set_update_callback_func(st_data_t *key, st_data_t arg, int existing);
+
+#define set_table_size rb_set_table_size
+size_t rb_set_table_size(const struct set_table *tbl);
+#define set_init_table_with_size rb_set_init_table_with_size
+set_table *rb_set_init_table_with_size(set_table *tab, const struct st_hash_type *, st_index_t);
+#define set_init_numtable rb_set_init_numtable
+set_table *rb_set_init_numtable(void);
+#define set_init_numtable_with_size rb_set_init_numtable_with_size
+set_table *rb_set_init_numtable_with_size(st_index_t size);
+#define set_init_embedded_numtable_with_size rb_set_init_embedded_numtable_with_size
+set_table *rb_set_init_embedded_numtable_with_size(struct set_table *tbl, st_index_t size);
+#define set_table_delete rb_set_table_delete
+int rb_set_table_delete(set_table *, st_data_t *); /* returns 0:notfound 1:deleted */
+#define set_insert rb_set_insert
+int rb_set_insert(set_table *, st_data_t);
+#define set_table_lookup rb_set_table_lookup
+int rb_set_table_lookup(set_table *, st_data_t);
+#define set_foreach_with_replace rb_set_foreach_with_replace
+int rb_set_foreach_with_replace(set_table *tab, set_foreach_check_callback_func *func, set_update_callback_func *replace, st_data_t arg);
+#define set_table_foreach rb_set_table_foreach
+int rb_set_table_foreach(set_table *, set_foreach_callback_func *, st_data_t);
+#define set_foreach_check rb_set_foreach_check
+int rb_set_foreach_check(set_table *, set_foreach_check_callback_func *, st_data_t, st_data_t);
+#define set_keys rb_set_keys
+st_index_t rb_set_keys(set_table *table, st_data_t *keys, st_index_t size);
+#define set_free_table rb_set_free_table
+void rb_set_free_table(set_table *);
+#define set_free_embedded_table rb_set_free_embedded_table
+void set_free_embedded_table(set_table *tab);
+#define set_table_clear rb_set_table_clear
+void rb_set_table_clear(set_table *);
+#define set_copy rb_set_copy
+set_table *rb_set_copy(set_table *new_table, set_table *old_table);
+#define set_memsize rb_set_memsize
+PUREFUNC(size_t rb_set_memsize(const set_table *));
+#define set_compact_table rb_set_compact_table
+void set_compact_table(set_table *tab);
+
+#endif
diff --git a/internal/signal.h b/internal/signal.h
index 2363bf412c..904747e226 100644
--- a/internal/signal.h
+++ b/internal/signal.h
@@ -19,6 +19,7 @@ void (*ruby_posix_signal(int, void (*)(int)))(int);
RUBY_SYMBOL_EXPORT_BEGIN
/* signal.c (export) */
+void rb_signal_atfork(void);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_SIGNAL_H */
diff --git a/internal/st.h b/internal/st.h
index a26b224505..14dcb25511 100644
--- a/internal/st.h
+++ b/internal/st.h
@@ -1,11 +1,20 @@
#ifndef INTERNAL_ST_H
#define INTERNAL_ST_H
-#include "include/ruby/st.h"
+#include "ruby/st.h"
st_table *rb_st_replace(st_table *new_tab, st_table *old_tab);
#define st_replace rb_st_replace
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_existing_numtable_with_size(st_table *tab, st_index_t size);
+#define st_init_existing_numtable_with_size rb_st_init_existing_numtable_with_size
+
+st_table *rb_st_init_existing_strtable_with_size(st_table *tab, st_index_t size);
+#define st_init_existing_strtable_with_size rb_st_init_existing_strtable_with_size
+
+void rb_st_free_embedded_table(st_table *tab);
+#define st_free_embedded_table rb_st_free_embedded_table
+
#endif
diff --git a/internal/string.h b/internal/string.h
index 0ff92c3b84..94a46a9657 100644
--- a/internal/string.h
+++ b/internal/string.h
@@ -14,6 +14,7 @@
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/encoding.h" /* for rb_encoding */
#include "ruby/ruby.h" /* for VALUE */
+#include "encindex.h"
#define STR_SHARED FL_USER0 /* = ELTS_SHARED */
#define STR_NOEMBED FL_USER1
@@ -29,7 +30,41 @@ enum ruby_rstring_private_flags {
# undef rb_fstring_cstr
#endif
+static inline bool
+rb_str_encindex_fastpath(int encindex)
+{
+ // The overwhelming majority of strings are in one of these 3 encodings,
+ // which are all either ASCII or perfect ASCII supersets.
+ // Hence you can use fast, single byte algorithms on them, such as `memchr` etc,
+ // without all the overhead of fetching the rb_encoding and using functions such as
+ // rb_enc_mbminlen etc.
+ // Many other encodings could qualify, but they are expected to be rare occurrences,
+ // so it's better to keep that list small.
+ switch (encindex) {
+ case ENCINDEX_ASCII_8BIT:
+ case ENCINDEX_UTF_8:
+ case ENCINDEX_US_ASCII:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool
+rb_str_enc_fastpath(VALUE str)
+{
+ return rb_str_encindex_fastpath(ENCODING_GET_INLINED(str));
+}
+
+static inline rb_encoding *
+rb_str_enc_get(VALUE str)
+{
+ RUBY_ASSERT(RB_TYPE_P(str, T_STRING));
+ return rb_enc_from_index(ENCODING_GET(str));
+}
+
/* string.c */
+VALUE rb_str_dup_m(VALUE str);
VALUE rb_fstring(VALUE);
VALUE rb_fstring_cstr(const char *str);
VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc);
@@ -62,6 +97,8 @@ bool rb_str_reembeddable_p(VALUE);
VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
VALUE rb_str_with_debug_created_info(VALUE, VALUE, int);
VALUE rb_str_frozen_bare_string(VALUE);
+const char *rb_str_null_check(VALUE);
+VALUE rb_str_casecmp(VALUE str1, VALUE str2);
/* error.c */
void rb_warn_unchilled_literal(VALUE str);
@@ -83,6 +120,9 @@ VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb
RUBY_SYMBOL_EXPORT_END
VALUE rb_fstring_new(const char *ptr, long len);
+void rb_gc_free_fstring(VALUE obj);
+bool rb_obj_is_fstring_table(VALUE obj);
+void Init_fstring_table();
VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
VALUE rb_str_opt_plus(VALUE x, VALUE y);
VALUE rb_str_concat_literals(size_t num, const VALUE *strary);
diff --git a/internal/struct.h b/internal/struct.h
index a8c773b730..d3c8157393 100644
--- a/internal/struct.h
+++ b/internal/struct.h
@@ -11,10 +11,23 @@
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for struct RBasic */
+/* Flags of RStruct
+ *
+ * 1-7: RSTRUCT_EMBED_LEN
+ * If non-zero, the struct is embedded (its contents follow the
+ * header, rather than being on a separately allocated buffer) and
+ * these bits are the length of the Struct.
+ * 8: RSTRUCT_GEN_FIELDS
+ * The struct is embedded and has no space left to store the
+ * IMEMO/fields reference. Any ivar this struct may have will be in
+ * the generic_fields_tbl. This flag doesn't imply the struct has
+ * ivars.
+ */
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_SHIFT = (RUBY_FL_USHIFT+1),
+ RSTRUCT_GEN_FIELDS = RUBY_FL_USER8,
};
struct RStruct {
@@ -23,6 +36,7 @@ struct RStruct {
struct {
long len;
const VALUE *ptr;
+ VALUE fields_obj;
} heap;
/* This is a length 1 array because:
* 1. GCC has a bug that does not optimize C flexible array members
@@ -35,36 +49,16 @@ struct RStruct {
#define RSTRUCT(obj) ((struct RStruct *)(obj))
-#ifdef RSTRUCT_LEN
-# undef RSTRUCT_LEN
-#endif
-
-#ifdef RSTRUCT_PTR
-# undef RSTRUCT_PTR
-#endif
-
-#ifdef RSTRUCT_SET
-# undef RSTRUCT_SET
-#endif
-
-#ifdef RSTRUCT_GET
-# undef RSTRUCT_GET
-#endif
-
-#define RSTRUCT_LEN internal_RSTRUCT_LEN
-#define RSTRUCT_SET internal_RSTRUCT_SET
-#define RSTRUCT_GET internal_RSTRUCT_GET
-
/* struct.c */
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 long RSTRUCT_EMBED_LEN(VALUE st);
-static inline long RSTRUCT_LEN(VALUE st);
+static inline long RSTRUCT_LEN_RAW(VALUE st);
static inline int RSTRUCT_LENINT(VALUE st);
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 void RSTRUCT_SET_RAW(VALUE st, long k, VALUE v);
+static inline VALUE RSTRUCT_GET_RAW(VALUE st, long k);
static inline long
RSTRUCT_EMBED_LEN(VALUE st)
@@ -75,7 +69,7 @@ RSTRUCT_EMBED_LEN(VALUE st)
}
static inline long
-RSTRUCT_LEN(VALUE st)
+RSTRUCT_LEN_RAW(VALUE st)
{
if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
return RSTRUCT_EMBED_LEN(st);
@@ -88,7 +82,7 @@ RSTRUCT_LEN(VALUE st)
static inline int
RSTRUCT_LENINT(VALUE st)
{
- return rb_long2int(RSTRUCT_LEN(st));
+ return rb_long2int(RSTRUCT_LEN_RAW(st));
}
static inline const VALUE *
@@ -105,15 +99,42 @@ RSTRUCT_CONST_PTR(VALUE st)
}
static inline void
-RSTRUCT_SET(VALUE st, long k, VALUE v)
+RSTRUCT_SET_RAW(VALUE st, long k, VALUE v)
{
RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v);
}
static inline VALUE
-RSTRUCT_GET(VALUE st, long k)
+RSTRUCT_GET_RAW(VALUE st, long k)
{
return RSTRUCT_CONST_PTR(st)[k];
}
+static inline VALUE
+RSTRUCT_FIELDS_OBJ(VALUE st)
+{
+ const long embed_len = RSTRUCT_EMBED_LEN(st);
+ VALUE fields_obj;
+ if (embed_len) {
+ RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
+ fields_obj = RSTRUCT_GET_RAW(st, embed_len);
+ }
+ else {
+ fields_obj = RSTRUCT(st)->as.heap.fields_obj;
+ }
+ return fields_obj;
+}
+
+static inline void
+RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj)
+{
+ const long embed_len = RSTRUCT_EMBED_LEN(st);
+ if (embed_len) {
+ RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
+ RSTRUCT_SET_RAW(st, embed_len, fields_obj);
+ }
+ else {
+ RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj);
+ }
+}
#endif /* INTERNAL_STRUCT_H */
diff --git a/internal/symbol.h b/internal/symbol.h
index 1a066af0e7..b9109b1347 100644
--- a/internal/symbol.h
+++ b/internal/symbol.h
@@ -17,8 +17,7 @@
#endif
/* symbol.c */
-void rb_sym_global_symbols_mark(void);
-void rb_sym_global_symbols_update_references(void);
+void rb_sym_global_symbols_mark_and_move(void);
VALUE rb_to_symbol_type(VALUE obj);
VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc);
VALUE rb_sym_intern_ascii(const char *ptr, long len);
@@ -31,11 +30,11 @@ PUREFUNC(int rb_is_const_sym(VALUE sym));
PUREFUNC(int rb_is_attrset_sym(VALUE sym));
ID rb_make_internal_id(void);
ID rb_make_temporary_id(size_t n);
+bool rb_obj_is_symbol_table(VALUE obj);
+void rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data);
void rb_gc_free_dsymbol(VALUE);
int rb_static_id_valid_p(ID id);
-
-/* vm.c */
-void rb_free_static_symid_str(void);
+void rb_free_global_symbol_table(void);
#if __has_builtin(__builtin_constant_p)
#define rb_sym_intern_ascii_cstr(ptr) \
diff --git a/internal/thread.h b/internal/thread.h
index 61c516984d..ea891b4372 100644
--- a/internal/thread.h
+++ b/internal/thread.h
@@ -13,6 +13,7 @@
#include "ccan/list/list.h" /* for list in rb_io_close_wait_list */
struct rb_thread_struct; /* in vm_core.h */
+struct rb_io;
#define RB_VM_SAVE_MACHINE_CONTEXT(th) \
do { \
@@ -55,26 +56,26 @@ 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);
+int rb_thread_io_wait(struct rb_thread_struct *th, struct rb_io *io, int events, struct timeval * timeout);
+int rb_thread_wait_for_single_fd(struct rb_thread_struct *th, 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);
+size_t rb_thread_io_close_interrupt(struct rb_io *);
+void rb_thread_io_close_wait(struct rb_io *);
void rb_ec_check_ints(struct rb_execution_context_struct *ec);
+void rb_thread_free_native_thread(void *th_ptr);
+
RUBY_SYMBOL_EXPORT_BEGIN
void *rb_thread_prevent_fork(void *(*func)(void *), void *data); /* for ext/socket/raddrinfo.c */
/* 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);
+VALUE rb_thread_io_blocking_region(struct rb_io *io, rb_blocking_function_t *func, void *data1);
+VALUE rb_thread_io_blocking_call(struct rb_io *io, rb_blocking_function_t *func, void *data1, int events);
+
+// Invoke the given function, with the specified argument, in a way that `IO#close` from another execution context can interrupt it.
+VALUE rb_thread_io_blocking_operation(VALUE self, VALUE(*function)(VALUE), VALUE argument);
/* thread.c (export) */
int ruby_thread_has_gvl_p(void); /* for ext/fiddle/closure.c */
@@ -84,6 +85,8 @@ RUBY_SYMBOL_EXPORT_END
int rb_threadptr_execute_interrupts(struct rb_thread_struct *th, int blocking_timing);
bool rb_thread_mn_schedulable(VALUE thread);
+bool rb_thread_resolve_unblock_function(rb_unblock_function_t **unblock_function, void **data2, struct rb_thread_struct *thread);
+
// interrupt exec
typedef VALUE (rb_interrupt_exec_func_t)(void *data);
@@ -91,6 +94,7 @@ typedef VALUE (rb_interrupt_exec_func_t)(void *data);
enum rb_interrupt_exec_flag {
rb_interrupt_exec_flag_none = 0x00,
rb_interrupt_exec_flag_value_data = 0x01,
+ rb_interrupt_exec_flag_new_thread = 0x02,
};
// interrupt the target_th and run func.
diff --git a/internal/time.h b/internal/time.h
index e21b3574f6..1f3505f5bc 100644
--- a/internal/time.h
+++ b/internal/time.h
@@ -27,11 +27,8 @@ 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 *);
RUBY_SYMBOL_EXPORT_END
+void ruby_reset_timezone(const char *);
+
#endif /* INTERNAL_TIME_H */
diff --git a/internal/variable.h b/internal/variable.h
index 007ea23aa8..58364941c1 100644
--- a/internal/variable.h
+++ b/internal/variable.h
@@ -13,23 +13,23 @@
#include "constant.h" /* for rb_const_entry_t */
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for VALUE */
-#include "shape.h" /* for rb_shape_t */
+#include "shape.h" /* for shape_id_t */
/* variable.c */
-void rb_const_added(VALUE klass, ID const_name);
-void rb_const_set_raw(VALUE klass, ID id, VALUE val);
void rb_gc_mark_global_tbl(void);
void rb_gc_update_global_tbl(void);
-size_t rb_generic_ivar_memsize(VALUE);
VALUE rb_search_class_path(VALUE);
VALUE rb_attr_delete(VALUE, ID);
void rb_autoload_str(VALUE mod, ID id, VALUE file);
VALUE rb_autoload_at_p(VALUE, ID, int);
+void rb_autoload_copy_table_for_box(st_table *, const rb_box_t *);
NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE));
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);
+void rb_gvar_box_ready(const char *name);
+void rb_gvar_box_dynamic(const char *name);
/**
* Sets the name of a module.
@@ -47,18 +47,23 @@ void rb_gvar_ractor_local(const char *name);
*/
VALUE rb_mod_set_temporary_name(VALUE, VALUE);
-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_obj_init_complex(VALUE obj, st_table *table);
void rb_evict_ivars_to_hash(VALUE obj);
+VALUE rb_obj_field_get(VALUE obj, shape_id_t target_shape_id);
+void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
+void rb_ivar_foreach_buffered(VALUE obj, int (*func)(ID name, VALUE val, st_data_t arg), st_data_t arg);
+attr_index_t rb_ivar_set_index(VALUE obj, ID id, VALUE val);
+attr_index_t rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val);
+VALUE rb_ivar_get_at(VALUE obj, attr_index_t index, ID id);
+VALUE rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index);
RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */
void rb_mark_generic_ivar(VALUE obj);
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);
+bool rb_class_ivar_set(VALUE klass, ID vid, VALUE value);
+void rb_fields_tbl_copy(VALUE dst, VALUE src);
RUBY_SYMBOL_EXPORT_END
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
@@ -66,7 +71,6 @@ 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);
-void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize);
-attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val);
+void rb_ensure_iv_list_size(VALUE obj, uint32_t current_len, uint32_t newsize);
#endif /* INTERNAL_VARIABLE_H */
diff --git a/internal/vm.h b/internal/vm.h
index c30e26a8b4..4e50ec2710 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -56,7 +56,6 @@ 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);
-PUREFUNC(st_table *rb_vm_fstring_table(void));
void rb_lastline_set_up(VALUE val, unsigned int up);
@@ -70,6 +69,7 @@ const char *rb_type_str(enum ruby_value_type type);
VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE);
VALUE rb_check_funcall_basic_kw(VALUE, ID, VALUE, int, const VALUE*, int);
VALUE rb_yield_1(VALUE val);
+VALUE rb_ec_yield(struct rb_execution_context_struct *ec, VALUE val);
VALUE rb_yield_force_blockarg(VALUE values);
VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
rb_block_call_func_t bl_proc, int min_argc, int max_argc,
@@ -78,10 +78,12 @@ void rb_check_stack_overflow(void);
#define RB_BLOCK_NO_USE_PACKED_ARGS 2
VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags);
struct vm_ifunc *rb_current_ifunc(void);
+VALUE rb_gccct_clear_table(void);
+VALUE rb_eval_cmd_call_kw(VALUE cmd, int argc, const VALUE *argv, int kw_splat);
-#if USE_YJIT
+#if USE_YJIT || USE_ZJIT
/* vm_exec.c */
-extern uint64_t rb_vm_insns_count;
+extern uint64_t rb_vm_insn_count;
#endif
extern bool rb_free_at_exit;
@@ -99,8 +101,6 @@ const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo
/* vm_method.c */
int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv);
-void rb_clear_constant_cache(void);
-
/* vm_dump.c */
void rb_print_backtrace(FILE *);
@@ -121,7 +121,6 @@ int rb_get_node_id_from_frame_info(VALUE obj);
const struct rb_iseq_struct *rb_get_iseq_from_frame_info(VALUE obj);
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
-void rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self);
#define RUBY_DTRACE_CREATE_HOOK(name, arg) \
RUBY_DTRACE_HOOK(name##_CREATE, arg)
diff --git a/io.c b/io.c
index f055746991..effcb349c3 100644
--- a/io.c
+++ b/io.c
@@ -220,12 +220,12 @@ static VALUE sym_DATA;
static VALUE sym_HOLE;
#endif
-static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
+static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
VALUE
rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
{
- return rb_thread_io_blocking_call(function, argument, io->fd, events);
+ return rb_thread_io_blocking_call(io, function, argument, events);
}
VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
@@ -500,6 +500,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
#define ARGF argf_of(argf)
+#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
#define GetWriteIO(io) rb_io_get_write_io(io)
@@ -1110,7 +1111,7 @@ ruby_dup(int orig)
static VALUE
io_alloc(VALUE klass)
{
- NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
+ UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
io->fptr = 0;
@@ -1185,7 +1186,8 @@ io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct time
if (error) {
errno = error;
return -1;
- } else {
+ }
+ else {
// Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
return ready;
}
@@ -1290,7 +1292,8 @@ internal_writev_func(void *ptr)
static ssize_t
rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
@@ -1300,7 +1303,7 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
}
struct io_internal_read_struct iis = {
- .th = rb_thread_current(),
+ .th = th->self,
.fptr = fptr,
.nonblock = 0,
.fd = fptr->fd,
@@ -1323,7 +1326,8 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
static ssize_t
rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
@@ -1333,7 +1337,7 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
}
struct io_internal_write_struct iis = {
- .th = rb_thread_current(),
+ .th = th->self,
.fptr = fptr,
.nonblock = 0,
.fd = fptr->fd,
@@ -1359,7 +1363,9 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
{
if (!iovcnt) return 0;
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
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);
@@ -1370,7 +1376,7 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
}
struct io_internal_writev_struct iis = {
- .th = rb_thread_current(),
+ .th = th->self,
.fptr = fptr,
.nonblock = 0,
.fd = fptr->fd,
@@ -1413,10 +1419,34 @@ io_flush_buffer_sync(void *arg)
return (VALUE)-1;
}
+static inline VALUE
+io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
+{
+ VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len, 0);
+ if (!UNDEF_P(ret)) {
+ ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
+ if (result > 0) {
+ fptr->wbuf.off += result;
+ fptr->wbuf.len -= result;
+ }
+ return result >= 0 ? (VALUE)0 : (VALUE)-1;
+ }
+ return ret;
+}
+
static VALUE
io_flush_buffer_async(VALUE arg)
{
rb_io_t *fptr = (rb_io_t *)arg;
+
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (scheduler != Qnil) {
+ VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
+ if (!UNDEF_P(result)) {
+ return result;
+ }
+ }
+
return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
}
@@ -1452,7 +1482,8 @@ io_fflush(rb_io_t *fptr)
VALUE
rb_io_wait(VALUE io, VALUE events, VALUE timeout)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
@@ -1473,7 +1504,7 @@ rb_io_wait(VALUE io, VALUE events, VALUE timeout)
tv = &tv_storage;
}
- int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
+ int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
if (ready < 0) {
rb_sys_fail(0);
@@ -1497,17 +1528,15 @@ io_from_fd(int fd)
}
static int
-io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
+io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
{
- VALUE scheduler = rb_fiber_scheduler_current();
-
if (scheduler != Qnil) {
return RTEST(
rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
);
}
- return rb_thread_wait_for_single_fd(fd, events, timeout);
+ return rb_thread_wait_for_single_fd(th, fd, events, timeout);
}
int
@@ -1515,7 +1544,8 @@ rb_io_wait_readable(int f)
{
io_fd_check_closed(f);
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
switch (errno) {
case EINTR:
@@ -1535,7 +1565,7 @@ rb_io_wait_readable(int f)
);
}
else {
- io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
+ io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
}
return TRUE;
@@ -1549,7 +1579,8 @@ rb_io_wait_writable(int f)
{
io_fd_check_closed(f);
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
switch (errno) {
case EINTR:
@@ -1578,7 +1609,7 @@ rb_io_wait_writable(int f)
);
}
else {
- io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
+ io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
}
return TRUE;
@@ -1590,7 +1621,9 @@ rb_io_wait_writable(int f)
int
rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
{
- return io_wait_for_single_fd(fd, events, timeout);
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
+ return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
}
int
@@ -2503,7 +2536,7 @@ interpret_seek_whence(VALUE vwhence)
* f.tell # => 12
* f.close
*
- * - +:SET+ or <tt>IO:SEEK_SET</tt>:
+ * - +:SET+ or <tt>IO::SEEK_SET</tt>:
* Repositions the stream to the given +offset+:
*
* f = File.open('t.txt')
@@ -2627,9 +2660,6 @@ io_fillbuf(rb_io_t *fptr)
fptr->rbuf.len = 0;
fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
-#ifdef _WIN32
- fptr->rbuf.capa--;
-#endif
}
if (fptr->rbuf.len == 0) {
retry:
@@ -3155,8 +3185,6 @@ io_enc_str(VALUE str, rb_io_t *fptr)
return str;
}
-static rb_encoding *io_read_encoding(rb_io_t *fptr);
-
static void
make_readconv(rb_io_t *fptr, int size)
{
@@ -3299,10 +3327,6 @@ io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
static int
io_setstrbuf(VALUE *str, long len)
{
-#ifdef _WIN32
- if (len > 0)
- len = (len + 1) & ~1L; /* round up for wide char */
-#endif
if (NIL_P(*str)) {
*str = rb_str_new(0, len);
return TRUE;
@@ -4306,11 +4330,17 @@ rb_io_gets(VALUE io)
}
VALUE
-rb_io_gets_internal(VALUE io)
+rb_io_gets_limit_internal(VALUE io, long limit)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
- return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
+ return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
+}
+
+VALUE
+rb_io_gets_internal(VALUE io)
+{
+ return rb_io_gets_limit_internal(io, -1);
}
/*
@@ -4691,10 +4721,11 @@ rb_io_each_line(int argc, VALUE *argv, VALUE io)
* Calls the given block with each byte (0..255) in the stream; returns +self+.
* See {Byte IO}[rdoc-ref:IO@Byte+IO].
*
- * f = File.new('t.rus')
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.new('t.ja')
* a = []
* f.each_byte {|b| a << b }
- * a # => [209, 130, 208, 181, 209, 129, 209, 130]
+ * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
* f.close
*
* Returns an Enumerator if no block is given.
@@ -4839,10 +4870,11 @@ io_getc(rb_io_t *fptr, rb_encoding *enc)
* Calls the given block with each character in the stream; returns +self+.
* See {Character IO}[rdoc-ref:IO@Character+IO].
*
- * f = File.new('t.rus')
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.new('t.ja')
* a = []
* f.each_char {|c| a << c.ord }
- * a # => [1090, 1077, 1089, 1090]
+ * a # => [12371, 12435, 12395, 12385, 12399]
* f.close
*
* Returns an Enumerator if no block is given.
@@ -4877,10 +4909,11 @@ rb_io_each_char(VALUE io)
*
* Calls the given block with each codepoint in the stream; returns +self+:
*
- * f = File.new('t.rus')
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.new('t.ja')
* a = []
* f.each_codepoint {|c| a << c }
- * a # => [1090, 1077, 1089, 1090]
+ * a # => [12371, 12435, 12395, 12385, 12399]
* f.close
*
* Returns an Enumerator if no block is given.
@@ -4902,6 +4935,7 @@ rb_io_each_codepoint(VALUE io)
rb_io_check_char_readable(fptr);
READ_CHECK(fptr);
+ enc = io_read_encoding(fptr);
if (NEED_READCONV(fptr)) {
SET_BINARY_MODE(fptr);
r = 1; /* no invalid char yet */
@@ -4909,12 +4943,9 @@ rb_io_each_codepoint(VALUE io)
make_readconv(fptr, 0);
for (;;) {
if (fptr->cbuf.len) {
- if (fptr->encs.enc)
- r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
- fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
- fptr->encs.enc);
- else
- r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
+ r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
+ fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
+ enc);
if (!MBCLEN_NEEDMORE_P(r))
break;
if (fptr->cbuf.len == fptr->cbuf.capa) {
@@ -4924,33 +4955,25 @@ rb_io_each_codepoint(VALUE io)
if (more_char(fptr) == MORE_CHAR_FINISHED) {
clear_readconv(fptr);
if (!MBCLEN_CHARFOUND_P(r)) {
- enc = fptr->encs.enc;
goto invalid;
}
return io;
}
}
if (MBCLEN_INVALID_P(r)) {
- enc = fptr->encs.enc;
goto invalid;
}
n = MBCLEN_CHARFOUND_LEN(r);
- if (fptr->encs.enc) {
- c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
- fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
- fptr->encs.enc);
- }
- else {
- c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
- }
+ c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
+ fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
+ enc);
fptr->cbuf.off += n;
fptr->cbuf.len -= n;
rb_yield(UINT2NUM(c));
- rb_io_check_byte_readable(fptr);
+ rb_io_check_char_readable(fptr);
}
}
NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
- enc = io_input_encoding(fptr);
while (io_fillbuf(fptr) >= 0) {
r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
@@ -5004,8 +5027,9 @@ rb_io_each_codepoint(VALUE io)
* f = File.open('t.txt')
* f.getc # => "F"
* f.close
- * f = File.open('t.rus')
- * f.getc.ord # => 1090
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.open('t.ja')
+ * f.getc.ord # => 12371
* f.close
*
* Related: IO#readchar (may raise EOFError).
@@ -5037,8 +5061,9 @@ rb_io_getc(VALUE io)
* f = File.open('t.txt')
* f.readchar # => "F"
* f.close
- * f = File.open('t.rus')
- * f.readchar.ord # => 1090
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.open('t.ja')
+ * f.readchar.ord # => 12371
* f.close
*
* Related: IO#getc (will not raise EOFError).
@@ -5067,8 +5092,9 @@ rb_io_readchar(VALUE io)
* f = File.open('t.txt')
* f.getbyte # => 70
* f.close
- * f = File.open('t.rus')
- * f.getbyte # => 209
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.open('t.ja')
+ * f.getbyte # => 227
* f.close
*
* Related: IO#readbyte (may raise EOFError).
@@ -5111,8 +5137,9 @@ rb_io_getbyte(VALUE io)
* f = File.open('t.txt')
* f.readbyte # => 70
* f.close
- * f = File.open('t.rus')
- * f.readbyte # => 209
+ * File.read('t.ja') # => "こんにちは"
+ * f = File.open('t.ja')
+ * f.readbyte # => 227
* f.close
*
* Related: IO#getbyte (will not raise EOFError).
@@ -5516,8 +5543,7 @@ maygvl_fclose(FILE *file, int keepgvl)
static void free_io_buffer(rb_io_buffer_t *buf);
static void
-fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
- struct rb_io_close_wait_list *busy)
+fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
{
VALUE error = Qnil;
int fd = fptr->fd;
@@ -5557,20 +5583,8 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
fptr->stdio_file = 0;
fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
- // 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);
- }
-
- // Disable for now.
- // if (!done && fd >= 0) {
- // VALUE scheduler = rb_fiber_scheduler_current();
- // if (scheduler != Qnil) {
- // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
- // if (!UNDEF_P(result)) done = 1;
- // }
- // }
+ // Wait for blocking operations to ensure they do not hit EBADF:
+ rb_thread_io_close_wait(fptr);
if (!done && stdio_file) {
// stdio_file is deallocated anyway even if fclose failed.
@@ -5583,6 +5597,15 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
done = 1;
}
+ VALUE scheduler = rb_fiber_scheduler_current();
+ if (!done && fd >= 0 && scheduler != Qnil) {
+ VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
+
+ if (!UNDEF_P(result)) {
+ done = RTEST(result);
+ }
+ }
+
if (!done && fd >= 0) {
// fptr->fd may be closed even if close fails. POSIX doesn't specify it.
// We assumes it is closed.
@@ -5609,7 +5632,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
static void
fptr_finalize(rb_io_t *fptr, int noraise)
{
- fptr_finalize_flush(fptr, noraise, FALSE, 0);
+ fptr_finalize_flush(fptr, noraise, FALSE);
free_io_buffer(&fptr->rbuf);
free_io_buffer(&fptr->wbuf);
clear_codeconv(fptr);
@@ -5630,7 +5653,7 @@ static void
free_io_buffer(rb_io_buffer_t *buf)
{
if (buf->ptr) {
- ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
+ ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
buf->ptr = NULL;
}
}
@@ -5674,37 +5697,45 @@ rb_io_fptr_cleanup_all(rb_io_t *fptr)
clear_codeconv(fptr);
}
-void
-rb_io_fptr_finalize_internal(void *ptr)
+int
+rb_io_fptr_finalize(struct rb_io *io)
{
- if (!ptr) return;
- rb_io_fptr_cleanup_all(ptr);
- free(ptr);
+ if (!io) return 0;
+ rb_io_fptr_cleanup_all(io);
+ free(io);
+
+ return 1;
}
-#undef rb_io_fptr_finalize
-int
-rb_io_fptr_finalize(rb_io_t *fptr)
+bool
+rb_io_fptr_finalize_closed(struct rb_io *io)
{
- if (!fptr) {
- return 0;
- }
- else {
- rb_io_fptr_finalize_internal(fptr);
- return 1;
- }
+ if (!io) return true;
+ if (io->fd >= 0) return false;
+ rb_io_fptr_finalize(io);
+ return true;
}
-#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
size_t
-rb_io_memsize(const rb_io_t *fptr)
+rb_io_memsize(const rb_io_t *io)
{
size_t size = sizeof(rb_io_t);
- size += fptr->rbuf.capa;
- size += fptr->wbuf.capa;
- size += fptr->cbuf.capa;
- if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
- if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
+ size += io->rbuf.capa;
+ size += io->wbuf.capa;
+ size += io->cbuf.capa;
+ if (io->readconv) size += rb_econv_memsize(io->readconv);
+ if (io->writeconv) size += rb_econv_memsize(io->writeconv);
+
+ struct rb_io_blocking_operation *blocking_operation = 0;
+
+ // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
+ rb_serial_t fork_generation = GET_VM()->fork_gen;
+ if (io->fork_generation == fork_generation) {
+ ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
+ size += sizeof(struct rb_io_blocking_operation);
+ }
+ }
+
return size;
}
@@ -5721,7 +5752,6 @@ io_close_fptr(VALUE io)
rb_io_t *fptr;
VALUE write_io;
rb_io_t *write_fptr;
- struct rb_io_close_wait_list busy;
write_io = GetWriteIO(io);
if (io != write_io) {
@@ -5735,10 +5765,12 @@ io_close_fptr(VALUE io)
if (!fptr) return 0;
if (fptr->fd < 0) return 0;
- if (rb_notify_fd_close(fptr->fd, &busy)) {
+ // This guards against multiple threads closing the same IO object:
+ if (rb_thread_io_close_interrupt(fptr)) {
/* calls close(fptr->fd): */
- fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
+ fptr_finalize_flush(fptr, FALSE, KEEPGVL);
}
+
rb_io_fptr_cleanup(fptr, FALSE);
return fptr;
}
@@ -6265,6 +6297,14 @@ internal_pwrite_func(void *_arg)
{
struct prdwr_internal_arg *arg = _arg;
+ return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
+}
+
+static VALUE
+pwrite_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_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
@@ -6274,8 +6314,7 @@ internal_pwrite_func(void *_arg)
}
}
-
- return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
+ return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
}
/*
@@ -6327,7 +6366,7 @@ 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_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
+ n = (ssize_t)pwrite_internal_call((VALUE)&arg);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
@@ -6432,7 +6471,7 @@ rb_io_binmode_p(VALUE io)
}
static const char*
-rb_io_fmode_modestr(int fmode)
+rb_io_fmode_modestr(enum rb_io_mode fmode)
{
if (fmode & FMODE_APPEND) {
if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
@@ -6466,10 +6505,10 @@ io_encname_bom_p(const char *name, long len)
return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
}
-int
+enum rb_io_mode
rb_io_modestr_fmode(const char *modestr)
{
- int fmode = 0;
+ enum rb_io_mode fmode = 0;
const char *m = modestr, *p = NULL;
switch (*m++) {
@@ -6526,7 +6565,7 @@ rb_io_modestr_fmode(const char *modestr)
int
rb_io_oflags_fmode(int oflags)
{
- int fmode = 0;
+ enum rb_io_mode fmode = 0;
switch (oflags & O_ACCMODE) {
case O_RDONLY:
@@ -6562,7 +6601,7 @@ rb_io_oflags_fmode(int oflags)
}
static int
-rb_io_fmode_oflags(int fmode)
+rb_io_fmode_oflags(enum rb_io_mode fmode)
{
int oflags = 0;
@@ -6647,7 +6686,7 @@ rb_io_oflags_modestr(int oflags)
* Qnil => no encoding specified (internal only)
*/
static void
-rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
+rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
{
int default_ext = 0;
@@ -6682,12 +6721,12 @@ unsupported_encoding(const char *name, rb_encoding *enc)
static void
parse_mode_enc(const char *estr, rb_encoding *estr_enc,
- rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
+ rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
{
const char *p;
char encname[ENCODING_MAXNAMELEN+1];
int idx, idx2;
- int fmode = fmode_p ? *fmode_p : 0;
+ enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
rb_encoding *ext_enc, *int_enc;
long len;
@@ -6749,7 +6788,7 @@ parse_mode_enc(const char *estr, rb_encoding *estr_enc,
}
int
-rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
+rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
{
VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
int extracted = 0;
@@ -6818,9 +6857,9 @@ rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2
}
static void
-validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
+validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
{
- int fmode = *fmode_p;
+ enum rb_io_mode fmode = *fmode_p;
if ((fmode & FMODE_READABLE) &&
!enc2 &&
@@ -6845,7 +6884,7 @@ validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *e
}
static void
-extract_binmode(VALUE opthash, int *fmode)
+extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
{
if (!NIL_P(opthash)) {
VALUE v;
@@ -6875,10 +6914,11 @@ 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, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
{
VALUE vmode;
- int oflags, fmode;
+ int oflags;
+ enum rb_io_mode fmode;
rb_encoding *enc, *enc2;
int ecflags;
VALUE ecopts;
@@ -7193,7 +7233,7 @@ io_set_encoding_by_bom(VALUE io)
}
static VALUE
-rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
+rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
const struct rb_io_encoding *convconfig, mode_t perm)
{
VALUE pathv;
@@ -7230,7 +7270,7 @@ rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
static VALUE
rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
{
- int fmode = rb_io_modestr_fmode(modestr);
+ enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
const char *p = strchr(modestr, ':');
struct rb_io_encoding convconfig;
@@ -7546,7 +7586,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,
+pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
const struct rb_io_encoding *convconfig)
{
struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
@@ -7775,7 +7815,7 @@ pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
}
#else
static VALUE
-pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
+pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
const struct rb_io_encoding *convconfig)
{
rb_raise(rb_eNotImpError, "popen() is not available");
@@ -7797,7 +7837,7 @@ is_popen_fork(VALUE prog)
}
static VALUE
-pipe_open_s(VALUE prog, const char *modestr, int fmode,
+pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
const struct rb_io_encoding *convconfig)
{
int argc = 1;
@@ -7830,7 +7870,7 @@ static VALUE popen_finish(VALUE port, VALUE klass);
* whose $stdin and $stdout are connected to a new stream +io+.
*
* This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* If no block is given, returns the new stream,
* which depending on given +mode+ may be open for reading, writing, or both.
@@ -7839,7 +7879,8 @@ static VALUE popen_finish(VALUE port, VALUE klass);
* If a block is given, the stream is passed to the block
* (again, open for reading, writing, or both);
* when the block exits, the stream is closed,
- * and the block's value is assigned to global variable <tt>$?</tt> and returned.
+ * the block's value is returned,
+ * and the global variable <tt>$?</tt> is set to the child's exit status.
*
* Optional argument +mode+ may be any valid \IO mode.
* See {Access Modes}[rdoc-ref:File@Access+Modes].
@@ -8006,7 +8047,8 @@ rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
{
const char *modestr;
VALUE tmp, execarg_obj = Qnil;
- int oflags, fmode;
+ int oflags;
+ enum rb_io_mode fmode;
struct rb_io_encoding convconfig;
tmp = rb_check_array_type(pname);
@@ -8047,7 +8089,7 @@ popen_finish(VALUE port, VALUE klass)
rb_protect(rb_yield, Qnil, NULL);
rb_io_flush(rb_ractor_stdout());
rb_io_flush(rb_ractor_stderr());
- _exit(0);
+ _exit(EXIT_SUCCESS);
}
return Qnil;
}
@@ -8087,7 +8129,12 @@ ruby_popen_writer(char *const *argv, rb_pid_t *pid)
int write_pair[2];
# endif
- int result = rb_cloexec_pipe(write_pair);
+#ifdef HAVE_PIPE2
+ int result = pipe2(write_pair, O_CLOEXEC);
+#else
+ int result = pipe(write_pair);
+#endif
+
*pid = -1;
if (result == 0) {
# ifdef HAVE_WORKING_FORK
@@ -8115,8 +8162,9 @@ ruby_popen_writer(char *const *argv, rb_pid_t *pid)
static VALUE
rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
{
+ int oflags;
+ enum rb_io_mode fmode;
struct rb_io_encoding convconfig;
- int oflags, fmode;
mode_t perm;
FilePathValue(fname);
@@ -8218,21 +8266,6 @@ rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
return INT2NUM(fd);
}
-static VALUE
-check_pipe_command(VALUE filename_or_command)
-{
- char *s = RSTRING_PTR(filename_or_command);
- long l = RSTRING_LEN(filename_or_command);
- char *e = s + l;
- int chlen;
-
- if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
- VALUE cmd = rb_str_new(s+chlen, l-chlen);
- return cmd;
- }
- return Qnil;
-}
-
/*
* call-seq:
* open(path, mode = 'r', perm = 0666, **opts) -> io or nil
@@ -8240,9 +8273,6 @@ check_pipe_command(VALUE filename_or_command)
*
* Creates an IO object connected to the given file.
*
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
* With no block given, file stream is returned:
*
* open('t.txt') # => #<File:t.txt>
@@ -8278,13 +8308,7 @@ rb_f_open(int argc, VALUE *argv, VALUE _)
redirect = TRUE;
}
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);
- }
+ argv[0] = tmp;
}
}
}
@@ -8299,12 +8323,19 @@ 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 klass, VALUE filename, int oflags, enum rb_io_mode fmode,
+ const struct rb_io_encoding *convconfig, mode_t perm)
+{
+ return rb_file_open_generic(io_alloc(klass), filename,
+ oflags, fmode, convconfig, perm);
+}
static VALUE
rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
{
- int oflags, fmode;
+ int oflags;
+ enum rb_io_mode fmode;
struct rb_io_encoding convconfig;
mode_t perm;
@@ -8314,22 +8345,6 @@ 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)
-{
- 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 {
- return rb_file_open_generic(io_alloc(klass), filename,
- oflags, fmode, convconfig, perm);
- }
-}
-
-static VALUE
io_reopen(VALUE io, VALUE nfile)
{
rb_io_t *fptr, *orig;
@@ -8378,6 +8393,10 @@ io_reopen(VALUE io, VALUE nfile)
fd = fptr->fd;
fd2 = orig->fd;
if (fd != fd2) {
+ // Interrupt all usage of the old file descriptor:
+ rb_thread_io_close_interrupt(fptr);
+ rb_thread_io_close_wait(fptr);
+
if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
/* need to keep FILE objects of stdin, stdout and stderr */
if (rb_cloexec_dup2(fd2, fd) < 0)
@@ -8393,7 +8412,7 @@ io_reopen(VALUE io, VALUE nfile)
rb_update_max_fd(fd);
fptr->fd = fd;
}
- rb_thread_fd_close(fd);
+
if ((orig->mode & FMODE_READABLE) && pos >= 0) {
if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
rb_sys_fail_path(fptr->pathv);
@@ -8482,7 +8501,7 @@ rb_io_reopen(int argc, VALUE *argv, VALUE file)
}
if (!NIL_P(nmode) || !NIL_P(opt)) {
- int fmode;
+ enum rb_io_mode fmode;
struct rb_io_encoding convconfig;
rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
@@ -8570,6 +8589,12 @@ rb_io_init_copy(VALUE dest, VALUE io)
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
fptr->timeout = orig->timeout;
+
+ ccan_list_head_init(&fptr->blocking_operations);
+ fptr->closing_ec = NULL;
+ fptr->wakeup_mutex = Qnil;
+ fptr->fork_generation = GET_VM()->fork_gen;
+
if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
fptr_copy_finalizer(fptr, orig);
@@ -8599,7 +8624,7 @@ rb_io_init_copy(VALUE dest, VALUE io)
* Formats and writes +objects+ to the stream.
*
* For details on +format_string+, see
- * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
*
*/
@@ -8620,7 +8645,7 @@ rb_io_printf(int argc, const VALUE *argv, VALUE out)
* io.write(sprintf(format_string, *objects))
*
* For details on +format_string+, see
- * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
*
* With the single argument +format_string+, formats +objects+ into the string,
* then writes the formatted string to $stdout:
@@ -8663,31 +8688,19 @@ rb_f_printf(int argc, VALUE *argv, VALUE _)
return Qnil;
}
-static void
-deprecated_str_setter(VALUE val, ID id, VALUE *var)
-{
- rb_str_setter(val, id, &val);
- if (!NIL_P(val)) {
- rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
- }
- *var = val;
-}
+extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
static void
deprecated_rs_setter(VALUE val, ID id, VALUE *var)
{
+ rb_deprecated_str_setter(val, id, &val);
if (!NIL_P(val)) {
- if (!RB_TYPE_P(val, T_STRING)) {
- rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
- }
if (rb_str_equal(val, rb_default_rs)) {
val = rb_default_rs;
}
else {
val = rb_str_frozen_bare_string(val);
}
- rb_enc_str_coderange(val);
- rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
}
*var = val;
}
@@ -9307,6 +9320,11 @@ rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE t
io->timeout = timeout;
+ ccan_list_head_init(&io->blocking_operations);
+ io->closing_ec = NULL;
+ io->wakeup_mutex = Qnil;
+ io->fork_generation = GET_VM()->fork_gen;
+
if (encoding) {
io->encs = *encoding;
}
@@ -9317,7 +9335,7 @@ rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE t
}
static VALUE
-prep_io(int fd, int fmode, VALUE klass, const char *path)
+prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
{
VALUE path_value = Qnil;
rb_encoding *e;
@@ -9363,7 +9381,7 @@ rb_io_fdopen(int fd, int oflags, const char *path)
}
static VALUE
-prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
+prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
{
rb_io_t *fptr;
VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
@@ -9446,6 +9464,10 @@ rb_io_fptr_new(void)
fp->encs.ecopts = Qnil;
fp->write_lock = Qnil;
fp->timeout = Qnil;
+ ccan_list_head_init(&fp->blocking_operations);
+ fp->closing_ec = NULL;
+ fp->wakeup_mutex = Qnil;
+ fp->fork_generation = GET_VM()->fork_gen;
return fp;
}
@@ -9487,7 +9509,8 @@ static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
* The new \IO object does not inherit encoding
* (because the integer file descriptor does not have an encoding):
*
- * fd = IO.sysopen('t.rus', 'rb')
+ * File.read('t.ja') # => "こんにちは"
+ * fd = IO.sysopen('t.ja', 'rb')
* io = IO.new(fd)
* io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
*
@@ -9523,7 +9546,8 @@ static VALUE
io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
{
rb_io_t *fp;
- int fd, fmode, oflags = O_RDONLY;
+ int fd, oflags = O_RDONLY;
+ enum rb_io_mode fmode;
struct rb_io_encoding convconfig;
#if defined(HAVE_FCNTL) && defined(F_GETFL)
int ofmode;
@@ -9575,6 +9599,10 @@ io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
fp->encs = convconfig;
fp->pathv = path;
fp->timeout = Qnil;
+ ccan_list_head_init(&fp->blocking_operations);
+ fp->closing_ec = NULL;
+ fp->wakeup_mutex = Qnil;
+ fp->fork_generation = GET_VM()->fork_gen;
clear_codeconv(fp);
io_check_tty(fp);
if (fileno(stdin) == fd)
@@ -9804,7 +9832,7 @@ io_wait_readable(int argc, VALUE *argv, VALUE io)
rb_io_t *fptr;
RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
+ rb_io_check_char_readable(fptr);
if (rb_io_read_pending(fptr)) return Qtrue;
@@ -9851,7 +9879,7 @@ io_wait_priority(int argc, VALUE *argv, VALUE io)
rb_io_t *fptr = NULL;
RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
+ rb_io_check_char_readable(fptr);
if (rb_io_read_pending(fptr)) return Qtrue;
@@ -9908,7 +9936,7 @@ io_event_from_value(VALUE value)
/*
* call-seq:
* io.wait(events, timeout) -> event mask, false or nil
- * io.wait(timeout = nil, mode = :read) -> self, true, or false
+ * io.wait(*event_symbols[, timeout]) -> self, true, or false
*
* Waits until the IO becomes ready for the specified events and returns the
* subset of events that become ready, or a falsy value when times out.
@@ -9916,10 +9944,14 @@ io_event_from_value(VALUE value)
* The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
* +IO::PRIORITY+.
*
- * Returns an event mask (truthy value) immediately when buffered data is available.
+ * Returns an event mask (truthy value) immediately when buffered data is
+ * available.
*
- * Optional parameter +mode+ is one of +:read+, +:write+, or
- * +:read_write+.
+ * The second form: if one or more event symbols (+:read+, +:write+, or
+ * +:read_write+) are passed, the event mask is the bit OR of the bitmask
+ * corresponding to those symbols. In this form, +timeout+ is optional, the
+ * order of the arguments is arbitrary, and returns +io+ if any of the
+ * events is ready.
*/
static VALUE
@@ -9929,10 +9961,6 @@ io_wait(int argc, VALUE *argv, VALUE io)
enum rb_io_event events = 0;
int return_io = 0;
- // The documented signature for this method is actually incorrect.
- // A single timeout is allowed in any position, and multiple symbols can be given.
- // Whether this is intentional or not, I don't know, and as such I consider this to
- // be a legacy/slow path.
if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
// We'd prefer to return the actual mask, but this form would return the io itself:
return_io = 1;
@@ -9978,14 +10006,14 @@ io_wait(int argc, VALUE *argv, VALUE io)
}
static void
-argf_mark(void *ptr)
+argf_mark_and_move(void *ptr)
{
struct argf *p = ptr;
- rb_gc_mark(p->filename);
- rb_gc_mark(p->current_file);
- rb_gc_mark(p->argv);
- rb_gc_mark(p->inplace);
- rb_gc_mark(p->encs.ecopts);
+ rb_gc_mark_and_move(&p->filename);
+ rb_gc_mark_and_move(&p->current_file);
+ rb_gc_mark_and_move(&p->argv);
+ rb_gc_mark_and_move(&p->inplace);
+ rb_gc_mark_and_move(&p->encs.ecopts);
}
static size_t
@@ -9996,30 +10024,19 @@ argf_memsize(const void *ptr)
return size;
}
-static void
-argf_compact(void *ptr)
-{
- struct argf *p = ptr;
- p->filename = rb_gc_location(p->filename);
- p->current_file = rb_gc_location(p->current_file);
- p->argv = rb_gc_location(p->argv);
- p->inplace = rb_gc_location(p->inplace);
- p->encs.ecopts = rb_gc_location(p->encs.ecopts);
-}
-
static const rb_data_type_t argf_type = {
"ARGF",
- {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_compact},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static inline void
-argf_init(struct argf *p, VALUE v)
+argf_init(VALUE argf, struct argf *p, VALUE v)
{
p->filename = Qnil;
p->current_file = Qnil;
p->lineno = 0;
- p->argv = v;
+ RB_OBJ_WRITE(argf, &p->argv, v);
}
static VALUE
@@ -10028,7 +10045,7 @@ argf_alloc(VALUE klass)
struct argf *p;
VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
- argf_init(p, Qnil);
+ argf_init(argf, p, Qnil);
return argf;
}
@@ -10039,7 +10056,7 @@ static VALUE
argf_initialize(VALUE argf, VALUE argv)
{
memset(&ARGF, 0, sizeof(ARGF));
- argf_init(&ARGF, argv);
+ argf_init(argf, &ARGF, argv);
return argf;
}
@@ -10050,7 +10067,8 @@ argf_initialize_copy(VALUE argf, VALUE orig)
{
if (!OBJ_INIT_COPY(argf, orig)) return argf;
ARGF = argf_of(orig);
- ARGF.argv = rb_obj_dup(ARGF.argv);
+ rb_gc_writebarrier_remember(argf);
+ ARGF_SET(argv, rb_obj_dup(ARGF.argv));
return argf;
}
@@ -10135,7 +10153,7 @@ argf_next_argv(VALUE argf)
char *fn;
rb_io_t *fptr;
int stdout_binmode = 0;
- int fmode;
+ enum rb_io_mode fmode;
VALUE r_stdout = rb_ractor_stdout();
@@ -10169,11 +10187,11 @@ argf_next_argv(VALUE argf)
if (RARRAY_LEN(ARGF.argv) > 0) {
VALUE filename = rb_ary_shift(ARGF.argv);
FilePathValue(filename);
- ARGF.filename = filename;
+ ARGF_SET(filename, filename);
filename = rb_str_encode_ospath(filename);
fn = StringValueCStr(filename);
if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
- ARGF.current_file = rb_stdin;
+ ARGF_SET(current_file, rb_stdin);
if (ARGF.inplace) {
rb_warn("Can't do inplace edit for stdio; skipping");
goto retry;
@@ -10268,7 +10286,7 @@ argf_next_argv(VALUE argf)
if (!ARGF.binmode) {
fmode |= DEFAULT_TEXTMODE;
}
- ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
+ ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
if (!NIL_P(write_io)) {
rb_io_set_write_io(ARGF.current_file, write_io);
}
@@ -10297,8 +10315,8 @@ argf_next_argv(VALUE argf)
}
}
else if (ARGF.next_p == -1) {
- ARGF.current_file = rb_stdin;
- ARGF.filename = rb_str_new2("-");
+ ARGF_SET(current_file, rb_stdin);
+ ARGF_SET(filename, rb_str_new2("-"));
if (ARGF.inplace) {
rb_warn("Can't do inplace edit for stdio");
rb_ractor_stdout_set(orig_stdout);
@@ -10640,14 +10658,14 @@ argf_readlines(int argc, VALUE *argv, VALUE argf)
* sets global variable <tt>$?</tt> to the process status.
*
* This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* Examples:
*
* $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
* $ `echo oops && exit 99` # => "oops\n"
* $ $? # => #<Process::Status: pid 17088 exit 99>
- * $ $?.status # => 99>
+ * $ $?.exitstatus # => 99
*
* The built-in syntax <tt>%x{...}</tt> uses this method.
*
@@ -10751,9 +10769,9 @@ select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fd
if (!pending && n == 0) return Qnil; /* returns nil on timeout */
res = rb_ary_new2(3);
- rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
- rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
- rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
+ rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
+ rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
+ rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
if (rp) {
list = RARRAY_AREF(res, 0);
@@ -10941,7 +10959,7 @@ advice_arg_check(VALUE advice)
* advise(advice, offset = 0, len = 0) -> nil
*
* Invokes Posix system call
- * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
+ * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
* which announces an intention to access data from the current file
* in a particular manner.
*
@@ -10993,11 +11011,21 @@ rb_io_advise(int argc, VALUE *argv, VALUE io)
#endif
}
+static int
+is_pos_inf(VALUE x)
+{
+ double f;
+ if (!RB_FLOAT_TYPE_P(x))
+ return 0;
+ f = RFLOAT_VALUE(x);
+ return isinf(f) && 0 < f;
+}
+
/*
* call-seq:
* IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
*
- * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
+ * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
* which monitors multiple file descriptors,
* waiting until one or more of the file descriptors
* becomes ready for some class of I/O operation.
@@ -11009,6 +11037,8 @@ rb_io_advise(int argc, VALUE *argv, VALUE io)
*
* Argument +timeout+ is a numeric value (such as integer or float) timeout
* interval in seconds.
+ * +timeout+ can also be +nil+ or +Float::INFINITY+.
+ * +nil+ and +Float::INFINITY+ means no timeout.
*
* The method monitors the \IO objects given in all three arrays,
* waiting for some to be ready;
@@ -11082,7 +11112,7 @@ rb_io_advise(int argc, VALUE *argv, VALUE io)
* Finally, Linux kernel developers don't guarantee that
* readability of select(2) means readability of following read(2) even
* for a single process;
- * see {select(2)}[https://linux.die.net/man/2/select]
+ * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
*
* Invoking \IO.select before IO#readpartial works well as usual.
* However it is not the best way to use \IO.select.
@@ -11159,7 +11189,7 @@ rb_f_select(int argc, VALUE *argv, VALUE obj)
int i;
rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
- if (NIL_P(timeout)) {
+ if (NIL_P(timeout) || is_pos_inf(timeout)) {
args.timeout = 0;
}
else {
@@ -11476,7 +11506,7 @@ rb_ioctl(VALUE io, VALUE req, VALUE arg)
* call-seq:
* ioctl(integer_cmd, argument) -> integer
*
- * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
+ * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
* which issues a low-level command to an I/O device.
*
* Issues a low-level command to an I/O device.
@@ -11565,7 +11595,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg)
* call-seq:
* fcntl(integer_cmd, argument) -> integer
*
- * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
+ * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
* which provides a mechanism for issuing low-level commands to control or query
* a file-oriented I/O stream. Arguments and results are platform
* dependent.
@@ -11595,7 +11625,7 @@ rb_io_fcntl(int argc, VALUE *argv, VALUE io)
* call-seq:
* syscall(integer_callno, *arguments) -> integer
*
- * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
+ * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
* which calls a specified function.
*
* Calls the operating system function identified by +integer_callno+;
@@ -11905,7 +11935,7 @@ rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
VALUE opt;
rb_io_t *fptr, *fptr2;
struct io_encoding_set_args ies_args;
- int fmode = 0;
+ enum rb_io_mode fmode = 0;
VALUE ret;
argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
@@ -12040,10 +12070,6 @@ io_s_foreach(VALUE v)
*
* Calls the block with each successive line read from the stream.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
* With only argument +path+ given, parses lines from the file at the given +path+,
@@ -12143,10 +12169,6 @@ io_s_readlines(VALUE v)
*
* Returns an array of all lines read from the stream.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
* With only argument +path+ given, parses lines from the file at the given +path+,
@@ -12232,17 +12254,17 @@ seek_before_access(VALUE argp)
* Opens the stream, reads and returns some or all of its content,
* and closes the stream; returns +nil+ if no bytes were read.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
* With only argument +path+ given, reads in text mode and returns the entire content
* of the file at the given path:
*
- * IO.read('t.txt')
- * # => "First line\nSecond line\n\nThird line\nFourth line\n"
+ * File.read('t.txt')
+ * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+ * File.read('t.ja')
+ * # => "こんにちは"
+ * File.read('t.dat')
+ * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
*
* On Windows, text mode can terminate reading and leave bytes in the file
* unread when encountering certain special bytes. Consider using
@@ -12250,15 +12272,36 @@ seek_before_access(VALUE argp)
*
* With argument +length+, returns +length+ bytes if available:
*
- * IO.read('t.txt', 7) # => "First l"
- * IO.read('t.txt', 700)
+ * File.read('t.txt', 7)
+ * # => "First l"
+ * File.read('t.ja', 7)
+ * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
+ * File.read('t.dat', 7)
+ * # => "\xFE\xFF\x99\x90\x99\x91\x99"
+ *
+ * Returns all bytes if +length+ is larger than the files size:
+ *
+ * File.read('t.txt', 700)
* # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
+ * File.read('t.ja', 700)
+ * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ * File.read('t.dat', 700)
+ * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
*
* With arguments +length+ and +offset+, returns +length+ bytes
* if available, beginning at the given +offset+:
*
- * IO.read('t.txt', 10, 2) # => "rst line\nS"
- * IO.read('t.txt', 10, 200) # => nil
+ * File.read('t.txt', 10, 2)
+ * # => "rst line\r\n"
+ * File.read('t.ja', 10, 2)
+ * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
+ * File.read('t.dat', 10, 2)
+ * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ *
+ * Returns +nil+ if +offset+ is past the end of the stream:
+ *
+ * File.read('t.txt', 10, 200)
+ * # => nil
*
* Optional keyword arguments +opts+ specify:
*
@@ -12303,10 +12346,6 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
* Behaves like IO.read, except that the stream is opened in binary mode
* with ASCII-8BIT encoding.
*
- * When called from class \IO (but not subclasses of \IO),
- * this method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
*/
static VALUE
@@ -12314,8 +12353,8 @@ rb_io_s_binread(int argc, VALUE *argv, VALUE io)
{
VALUE offset;
struct foreach_arg arg;
+ enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
enum {
- fmode = FMODE_READABLE|FMODE_BINMODE,
oflags = O_RDONLY
#ifdef O_BINARY
|O_BINARY
@@ -12402,40 +12441,50 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
/*
* call-seq:
- * IO.write(path, data, offset = 0, **opts) -> integer
+ * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
*
* Opens the stream, writes the given +data+ to it,
* and closes the stream; returns the number of bytes written.
*
- * When called from class \IO (but not subclasses of \IO),
- * 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.
*
- * With only argument +path+ given, writes the given +data+ to the file at that path:
+ * With only arguments +path+ and +data+ given,
+ * writes the given data to the file at that path:
*
- * IO.write('t.tmp', 'abc') # => 3
- * File.read('t.tmp') # => "abc"
+ * path = 't.tmp'
+ * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
+ * File.write(path, 'こんにちは') # => 15
+ * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
+ *
+ * When +offset+ is zero (the default), the entire file content is overwritten:
*
- * If +offset+ is zero (the default), the file is overwritten:
+ * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ * File.write(path, 'foo')
+ * File.read(path) # => "foo"
*
- * IO.write('t.tmp', 'A') # => 1
- * File.read('t.tmp') # => "A"
+ * When +offset+ in within the file content, the file content is partly overwritten,
+ * beginning at byte +offset+:
*
- * If +offset+ in within the file content, the file is partly overwritten:
+ * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
+ * File.write(path, 'LINE', 6)
+ * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
*
- * IO.write('t.tmp', 'abcdef') # => 3
- * File.read('t.tmp') # => "abcdef"
- * # Offset within content.
- * IO.write('t.tmp', '012', 2) # => 3
- * File.read('t.tmp') # => "ab012f"
+ * When the file contains multi-byte characters,
+ * the effect of writing may disturb some characters:
+ *
+ * File.write(path, "こんにちは")
+ * File.write(path, 'FOO', 3) # Replace one 3-byte character.
+ * File.read(path) # => "こFOOにちは"
+ * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
+ * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
*
* If +offset+ is outside the file content,
* the file is padded with null characters <tt>"\u0000"</tt>:
*
- * IO.write('t.tmp', 'xyz', 10) # => 3
- * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
+ * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
+ * File.write(path, 'FOO', 55)
+ * File.read(path)
+ * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
*
* Optional keyword arguments +opts+ specify:
*
@@ -12452,15 +12501,11 @@ rb_io_s_write(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
- * IO.binwrite(path, string, offset = 0) -> integer
+ * IO.binwrite(path, string, offset = 0, **opts) -> integer
*
* Behaves like IO.write, except that the stream is opened in binary mode
* with ASCII-8BIT encoding.
*
- * When called from class \IO (but not subclasses of \IO),
- * this method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
*/
static VALUE
@@ -13679,6 +13724,7 @@ argf_set_encoding(int argc, VALUE *argv, VALUE argf)
rb_io_set_encoding(argc, argv, ARGF.current_file);
GetOpenFile(ARGF.current_file, fptr);
ARGF.encs = fptr->encs;
+ RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
return argf;
}
@@ -14611,7 +14657,7 @@ argf_inplace_mode_set(VALUE argf, VALUE val)
ARGF.inplace = Qnil;
}
else {
- ARGF.inplace = rb_str_new_frozen(val);
+ ARGF_SET(inplace, rb_str_new_frozen(val));
}
return argf;
}
@@ -14625,7 +14671,7 @@ opt_i_set(VALUE val, ID id, VALUE *var)
void
ruby_set_inplace_mode(const char *suffix)
{
- ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
+ ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
}
/*
@@ -14885,7 +14931,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* - \File +t.rb+:
*
* p "ARGV: #{ARGV}"
- * p "Line: #{ARGF.read}" # Read everything from all specified streams.
+ * p "Read: #{ARGF.read}" # Read everything from all specified streams.
*
* - Command and output:
*
@@ -14959,9 +15005,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* ["ARGV", ["-"]]
* ["ARGF.read", "Open the pod bay doors, Hal.\n"]
*
- * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
- * (exception:
- * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
+ * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
*
* - Command and output:
*
@@ -15076,7 +15120,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* 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].
+ * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
* - A data mode, which may be text-only or binary;
* see {Data Mode}[rdoc-ref:File@Data+Mode].
* - Internal and external encodings;
@@ -15120,7 +15164,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
* - +:autoclose+: If a truthy value, specifies that the +fd+ will close
* when the stream closes; otherwise it remains open.
- * - +:path:+ If a string value is provided, it is used in #inspect and is available as
+ * - +:path+: If a string value is provided, it is used in #inspect and is available as
* #path method.
*
* Also available are the options offered in String#encode,
@@ -15317,11 +15361,13 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
* File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
*
- * # Text with 2-byte characters, which will not be split.
- * File.open('t.rus') {|f| f.gets(1).size } # => 1
- * File.open('t.rus') {|f| f.gets(2).size } # => 1
- * File.open('t.rus') {|f| f.gets(3).size } # => 2
- * File.open('t.rus') {|f| f.gets(4).size } # => 2
+ * # Text with 3-byte characters, which will not be split.
+ * File.read('t.ja') # => "こんにちは"
+ * File.open('t.ja') {|f| f.gets(1).size } # => 1
+ * File.open('t.ja') {|f| f.gets(2).size } # => 1
+ * File.open('t.ja') {|f| f.gets(3).size } # => 1
+ * File.open('t.ja') {|f| f.gets(4).size } # => 2
+ * File.open('t.ja') {|f| f.gets(5).size } # => 2
*
* ===== Line Separator and Line Limit
*
@@ -15472,8 +15518,8 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
*
* First, what's elsewhere. Class \IO:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class \IO provides methods that are useful for:
@@ -15737,7 +15783,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
rb_output_fs = Qnil;
- rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
+ rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
rb_vm_register_global_object(rb_default_rs);
@@ -15747,10 +15793,11 @@ Init_IO(void)
rb_gvar_ractor_local("$/"); // not local but ractor safe
rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
rb_gvar_ractor_local("$-0"); // not local but ractor safe
- rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
+ rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
rb_gvar_ractor_local("$_");
+ rb_gvar_box_dynamic("$_");
rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
@@ -15972,7 +16019,7 @@ Init_IO(void)
rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
- ARGF.filename = rb_str_new2("-");
+ ARGF_SET(filename, rb_str_new2("-"));
rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
rb_gvar_ractor_local("$-i");
diff --git a/io_buffer.c b/io_buffer.c
index 140571bdbc..faa5304248 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -39,6 +39,7 @@ size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
enum {
RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
+ RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH = 1024,
RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
@@ -272,7 +273,36 @@ io_buffer_free(struct rb_io_buffer *buffer)
#endif
}
-void
+static void
+rb_io_buffer_type_mark(void *_buffer)
+{
+ struct rb_io_buffer *buffer = _buffer;
+ if (buffer->source != Qnil) {
+ if (RB_TYPE_P(buffer->source, T_STRING)) {
+ // The `source` String has to be pinned, because the `base` may point to the embedded String content,
+ // which can be otherwise moved by GC compaction.
+ rb_gc_mark(buffer->source);
+ } else {
+ rb_gc_mark_movable(buffer->source);
+ }
+ }
+}
+
+static void
+rb_io_buffer_type_compact(void *_buffer)
+{
+ struct rb_io_buffer *buffer = _buffer;
+ if (buffer->source != Qnil) {
+ if (RB_TYPE_P(buffer->source, T_STRING)) {
+ // The `source` String has to be pinned, because the `base` may point to the embedded String content,
+ // which can be otherwise moved by GC compaction.
+ } else {
+ buffer->source = rb_gc_location(buffer->source);
+ }
+ }
+}
+
+static void
rb_io_buffer_type_free(void *_buffer)
{
struct rb_io_buffer *buffer = _buffer;
@@ -280,7 +310,7 @@ rb_io_buffer_type_free(void *_buffer)
io_buffer_free(buffer);
}
-size_t
+static size_t
rb_io_buffer_type_size(const void *_buffer)
{
const struct rb_io_buffer *buffer = _buffer;
@@ -293,20 +323,16 @@ rb_io_buffer_type_size(const void *_buffer)
return total;
}
-RUBY_REFERENCES(io_buffer_refs) = {
- RUBY_REF_EDGE(struct rb_io_buffer, source),
- RUBY_REF_END
-};
-
static const rb_data_type_t rb_io_buffer_type = {
.wrap_struct_name = "IO::Buffer",
.function = {
- .dmark = RUBY_REFS_LIST_PTR(io_buffer_refs),
+ .dmark = rb_io_buffer_type_mark,
.dfree = rb_io_buffer_type_free,
.dsize = rb_io_buffer_type_size,
+ .dcompact = rb_io_buffer_type_compact,
},
.data = NULL,
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE | RUBY_TYPED_DECL_MARKING,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
};
static inline enum rb_io_buffer_flags
@@ -359,7 +385,7 @@ io_buffer_extract_size(VALUE argument)
}
// Extract a width argument, which must be a non-negative integer, and must be
-// at least the given minimum.
+// at least the given minimum and at most RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH.
static inline size_t
io_buffer_extract_width(VALUE argument, size_t minimum)
{
@@ -373,6 +399,10 @@ io_buffer_extract_width(VALUE argument, size_t minimum)
rb_raise(rb_eArgError, "Width must be at least %" PRIuSIZE "!", minimum);
}
+ if (width > RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH) {
+ rb_raise(rb_eArgError, "Width must be at most %" PRIuSIZE "!", (size_t)RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH);
+ }
+
return width;
}
@@ -454,6 +484,8 @@ io_buffer_extract_offset_length(VALUE self, int argc, VALUE argv[], size_t *offs
VALUE
rb_io_buffer_type_allocate(VALUE self)
{
+ io_buffer_experimental();
+
struct rb_io_buffer *buffer = NULL;
VALUE instance = TypedData_Make_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
@@ -496,7 +528,9 @@ io_buffer_for_yield_instance(VALUE _arguments)
arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
- rb_str_locktmp(arguments->string);
+ if (!RB_OBJ_FROZEN(arguments->string)) {
+ rb_str_locktmp(arguments->string);
+ }
return rb_yield(arguments->instance);
}
@@ -510,7 +544,9 @@ io_buffer_for_yield_instance_ensure(VALUE _arguments)
rb_io_buffer_free(arguments->instance);
}
- rb_str_unlocktmp(arguments->string);
+ if (!RB_OBJ_FROZEN(arguments->string)) {
+ rb_str_unlocktmp(arguments->string);
+ }
return Qnil;
}
@@ -540,7 +576,7 @@ io_buffer_for_yield_instance_ensure(VALUE _arguments)
* buffer.get_string(0, 1)
* # => "t"
* string
- * # => "best"
+ * # => "test"
*
* buffer.resize(100)
* # in `resize': Cannot resize external buffer! (IO::Buffer::AccessError)
@@ -620,8 +656,6 @@ rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags)
VALUE
rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags flags)
{
- io_buffer_experimental();
-
VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
struct rb_io_buffer *buffer = NULL;
@@ -638,18 +672,25 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
* call-seq: IO::Buffer.map(file, [size, [offset, [flags]]]) -> io_buffer
*
* Create an IO::Buffer for reading from +file+ by memory-mapping the file.
- * +file_io+ should be a +File+ instance, opened for reading.
+ * +file+ should be a +File+ instance, opened for reading or reading and writing.
*
* Optional +size+ and +offset+ of mapping can be specified.
+ * Trying to map an empty file or specify +size+ of 0 will raise an error.
+ * Valid values for +offset+ are system-dependent.
*
- * By default, the buffer would be immutable (read only); to create a writable
- * mapping, you need to open a file in read-write mode, and explicitly pass
- * +flags+ argument without IO::Buffer::IMMUTABLE.
+ * By default, the buffer is writable and expects the file to be writable.
+ * It is also shared, so several processes can use the same mapping.
+ *
+ * You can pass IO::Buffer::READONLY in +flags+ argument to make a read-only buffer;
+ * this allows to work with files opened only for reading.
+ * Specifying IO::Buffer::PRIVATE in +flags+ creates a private mapping,
+ * which will not impact other processes or the underlying file.
+ * It also allows updating a buffer created from a read-only file.
*
* File.write('test.txt', 'test')
*
* buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
- * # => #<IO::Buffer 0x00000001014a0000+4 MAPPED READONLY>
+ * # => #<IO::Buffer 0x00000001014a0000+4 EXTERNAL MAPPED FILE SHARED READONLY>
*
* buffer.readonly? # => true
*
@@ -657,7 +698,7 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
* # => "test"
*
* buffer.set_string('b', 0)
- * # `set_string': Buffer is not writable! (IO::Buffer::AccessError)
+ * # 'IO::Buffer#set_string': Buffer is not writable! (IO::Buffer::AccessError)
*
* # create read/write mapping: length 4 bytes, offset 0, flags 0
* buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 4, 0)
@@ -679,31 +720,48 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass)
// We might like to handle a string path?
VALUE io = argv[0];
+ rb_off_t file_size = rb_file_size(io);
+ // Compiler can confirm that we handled file_size <= 0 case:
+ if (UNLIKELY(file_size <= 0)) {
+ rb_raise(rb_eArgError, "Invalid negative or zero file size!");
+ }
+ // Here, we assume that file_size is positive:
+ else if (UNLIKELY((uintmax_t)file_size > SIZE_MAX)) {
+ rb_raise(rb_eArgError, "File larger than address space!");
+ }
+
size_t size;
if (argc >= 2 && !RB_NIL_P(argv[1])) {
size = io_buffer_extract_size(argv[1]);
- }
- else {
- rb_off_t file_size = rb_file_size(io);
-
- // Compiler can confirm that we handled file_size < 0 case:
- if (file_size < 0) {
- rb_raise(rb_eArgError, "Invalid negative file size!");
- }
- // Here, we assume that file_size is positive:
- else if ((uintmax_t)file_size > SIZE_MAX) {
- rb_raise(rb_eArgError, "File larger than address space!");
+ if (UNLIKELY(size == 0)) {
+ rb_raise(rb_eArgError, "Size can't be zero!");
}
- else {
- // This conversion should be safe:
- size = (size_t)file_size;
+ if (UNLIKELY(size > (size_t)file_size)) {
+ rb_raise(rb_eArgError, "Size can't be larger than file size!");
}
}
+ else {
+ // This conversion should be safe:
+ size = (size_t)file_size;
+ }
// This is the file offset, not the buffer offset:
rb_off_t offset = 0;
if (argc >= 3) {
offset = NUM2OFFT(argv[2]);
+ if (UNLIKELY(offset < 0)) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+ if (UNLIKELY(offset >= file_size)) {
+ rb_raise(rb_eArgError, "Offset too large!");
+ }
+ if (RB_NIL_P(argv[1])) {
+ // Decrease size if it's set from the actual file size:
+ size = (size_t)(file_size - offset);
+ }
+ else if (UNLIKELY((size_t)(file_size - offset) < size)) {
+ rb_raise(rb_eArgError, "Offset too large!");
+ }
}
enum rb_io_buffer_flags flags = 0;
@@ -752,8 +810,6 @@ io_flags_for_size(size_t size)
VALUE
rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
{
- io_buffer_experimental();
-
rb_check_arity(argc, 0, 2);
struct rb_io_buffer *buffer = NULL;
@@ -1373,6 +1429,17 @@ rb_io_buffer_try_unlock(VALUE self)
return 0;
}
+static VALUE
+rb_io_buffer_locked_ensure(VALUE self)
+{
+ struct rb_io_buffer *buffer = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+
+ buffer->flags &= ~RB_IO_BUFFER_LOCKED;
+
+ return Qnil;
+}
+
/*
* call-seq: locked { ... }
*
@@ -1415,11 +1482,7 @@ rb_io_buffer_locked(VALUE self)
buffer->flags |= RB_IO_BUFFER_LOCKED;
- VALUE result = rb_yield(self);
-
- buffer->flags &= ~RB_IO_BUFFER_LOCKED;
-
- return result;
+ return rb_ensure(rb_yield, self, rb_io_buffer_locked_ensure, self);
}
/*
@@ -1430,7 +1493,7 @@ rb_io_buffer_locked(VALUE self)
* * for a buffer created from scratch: free memory.
* * for a buffer created from string: undo the association.
*
- * After the buffer is freed, no further operations can't be performed on it.
+ * After the buffer is freed, no further operations can be performed on it.
*
* You can resize a freed buffer to re-allocate it.
*
@@ -1473,13 +1536,19 @@ VALUE rb_io_buffer_free_locked(VALUE self)
return self;
}
+static bool
+size_sum_is_bigger_than(size_t a, size_t b, size_t x)
+{
+ struct rbimpl_size_overflow_tag size = rbimpl_size_add_overflow(a, b);
+ return size.overflowed || size.result > x;
+}
+
// 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)
{
- // We assume here that offset + length won't overflow:
- if (offset + length > buffer->size) {
+ if (size_sum_is_bigger_than(offset, length, buffer->size)) {
rb_raise(rb_eArgError, "Specified offset+length is bigger than the buffer size!");
}
}
@@ -1789,9 +1858,9 @@ rb_io_buffer_compare(VALUE self, VALUE other)
}
static void
-io_buffer_validate_type(size_t size, size_t offset)
+io_buffer_validate_type(size_t size, size_t offset, size_t extend)
{
- if (offset > size) {
+ if (size_sum_is_bigger_than(offset, extend, size)) {
rb_raise(rb_eArgError, "Type extends beyond end of buffer! (offset=%"PRIdSIZE" > size=%"PRIdSIZE")", offset, size);
}
}
@@ -1811,6 +1880,9 @@ io_buffer_validate_type(size_t size, size_t offset)
// :u64, :U64 | unsigned 64-bit integer.
// :s64, :S64 | signed 64-bit integer.
//
+// :u128, :U128 | unsigned 128-bit integer.
+// :s128, :S128 | signed 128-bit integer.
+//
// :f32, :F32 | 32-bit floating point number.
// :f64, :F64 | 64-bit floating point number.
@@ -1842,13 +1914,53 @@ ruby_swapf64(double value)
return swap.value;
}
+// Structures and conversion functions are now in numeric.h/numeric.c
+// Unified swap function for 128-bit integers (works with both signed and unsigned)
+// Since both rb_uint128_t and rb_int128_t have the same memory layout,
+// we can use a union to make the swap function work with both types
+static inline rb_uint128_t
+ruby_swap128_uint(rb_uint128_t x)
+{
+ rb_uint128_t result;
+#ifdef HAVE_UINT128_T
+#if __has_builtin(__builtin_bswap128)
+ result.value = __builtin_bswap128(x.value);
+#else
+ // Manual byte swap for 128-bit integers
+ uint64_t low = (uint64_t)x.value;
+ uint64_t high = (uint64_t)(x.value >> 64);
+ low = ruby_swap64(low);
+ high = ruby_swap64(high);
+ result.value = ((uint128_t)low << 64) | high;
+#endif
+#else
+ // Fallback swap function using two 64-bit integers
+ // For big-endian data on little-endian host (or vice versa):
+ // 1. Swap bytes within each 64-bit part
+ // 2. Swap the order of the parts (since big-endian stores high first, little-endian stores low first)
+ result.parts.low = ruby_swap64(x.parts.high);
+ result.parts.high = ruby_swap64(x.parts.low);
+#endif
+ return result;
+}
+
+static inline rb_int128_t
+ruby_swap128_int(rb_int128_t x)
+{
+ union uint128_int128_conversion conversion = {
+ .int128 = x
+ };
+ conversion.uint128 = ruby_swap128_uint(conversion.uint128);
+ return conversion.int128;
+}
+
#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
static ID RB_IO_BUFFER_DATA_TYPE_##name; \
\
static VALUE \
io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
{ \
- io_buffer_validate_type(size, *offset + sizeof(type)); \
+ io_buffer_validate_type(size, *offset, sizeof(type)); \
type value; \
memcpy(&value, (char*)base + *offset, sizeof(type)); \
if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
@@ -1859,7 +1971,7 @@ io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
static void \
io_buffer_write_##name(const void* base, size_t size, size_t *offset, VALUE _value) \
{ \
- io_buffer_validate_type(size, *offset + sizeof(type)); \
+ io_buffer_validate_type(size, *offset, sizeof(type)); \
type value = unwrap(_value); \
if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
memcpy((char*)base + *offset, &value, sizeof(type)); \
@@ -1888,6 +2000,11 @@ IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN, RB_ULL2NUM, RB_NU
IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN, RB_LL2NUM, RB_NUM2LL, ruby_swap64)
IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN, RB_LL2NUM, RB_NUM2LL, ruby_swap64)
+IO_BUFFER_DECLARE_TYPE(u128, rb_uint128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
+IO_BUFFER_DECLARE_TYPE(U128, rb_uint128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
+IO_BUFFER_DECLARE_TYPE(s128, rb_int128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
+IO_BUFFER_DECLARE_TYPE(S128, rb_int128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
+
IO_BUFFER_DECLARE_TYPE(f32, float, RB_IO_BUFFER_LITTLE_ENDIAN, DBL2NUM, NUM2DBL, ruby_swapf32)
IO_BUFFER_DECLARE_TYPE(F32, float, RB_IO_BUFFER_BIG_ENDIAN, DBL2NUM, NUM2DBL, ruby_swapf32)
IO_BUFFER_DECLARE_TYPE(f64, double, RB_IO_BUFFER_LITTLE_ENDIAN, DBL2NUM, NUM2DBL, ruby_swapf64)
@@ -1912,6 +2029,10 @@ io_buffer_buffer_type_size(ID buffer_type)
IO_BUFFER_DATA_TYPE_SIZE(U64)
IO_BUFFER_DATA_TYPE_SIZE(s64)
IO_BUFFER_DATA_TYPE_SIZE(S64)
+ IO_BUFFER_DATA_TYPE_SIZE(u128)
+ IO_BUFFER_DATA_TYPE_SIZE(U128)
+ IO_BUFFER_DATA_TYPE_SIZE(s128)
+ IO_BUFFER_DATA_TYPE_SIZE(S128)
IO_BUFFER_DATA_TYPE_SIZE(f32)
IO_BUFFER_DATA_TYPE_SIZE(F32)
IO_BUFFER_DATA_TYPE_SIZE(f64)
@@ -1968,6 +2089,11 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
IO_BUFFER_GET_VALUE(s64)
IO_BUFFER_GET_VALUE(S64)
+ IO_BUFFER_GET_VALUE(u128)
+ IO_BUFFER_GET_VALUE(U128)
+ IO_BUFFER_GET_VALUE(s128)
+ IO_BUFFER_GET_VALUE(S128)
+
IO_BUFFER_GET_VALUE(f32)
IO_BUFFER_GET_VALUE(F32)
IO_BUFFER_GET_VALUE(f64)
@@ -1997,6 +2123,10 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
* * +:U64+: unsigned integer, 8 bytes, big-endian
* * +:s64+: signed integer, 8 bytes, little-endian
* * +:S64+: signed integer, 8 bytes, big-endian
+ * * +:u128+: unsigned integer, 16 bytes, little-endian
+ * * +:U128+: unsigned integer, 16 bytes, big-endian
+ * * +:s128+: signed integer, 16 bytes, little-endian
+ * * +:S128+: signed integer, 16 bytes, big-endian
* * +:f32+: float, 4 bytes, little-endian
* * +:F32+: float, 4 bytes, big-endian
* * +:f64+: double, 8 bytes, little-endian
@@ -2178,7 +2308,7 @@ io_buffer_values(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * each_byte([offset, [count]]) {|offset, byte| ...} -> self
+ * each_byte([offset, [count]]) {|byte| ...} -> self
* each_byte([offset, [count]]) -> enumerator
*
* Iterates over the buffer, yielding each byte starting from +offset+.
@@ -2202,7 +2332,11 @@ 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);
+ io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc, argv, &offset, &count);
+
+ if (size_sum_is_bigger_than(offset, count, size)) {
+ rb_raise(rb_eArgError, "Specified offset+count is bigger than the buffer size!");
+ }
for (size_t i = 0; i < count; i++) {
unsigned char *value = (unsigned char *)base + i + offset;
@@ -2234,6 +2368,11 @@ rb_io_buffer_set_value(const void* base, size_t size, ID buffer_type, size_t *of
IO_BUFFER_SET_VALUE(s64);
IO_BUFFER_SET_VALUE(S64);
+ IO_BUFFER_SET_VALUE(u128);
+ IO_BUFFER_SET_VALUE(U128);
+ IO_BUFFER_SET_VALUE(s128);
+ IO_BUFFER_SET_VALUE(S128);
+
IO_BUFFER_SET_VALUE(f32);
IO_BUFFER_SET_VALUE(F32);
IO_BUFFER_SET_VALUE(f64);
@@ -2364,7 +2503,7 @@ io_buffer_memmove(struct rb_io_buffer *buffer, size_t offset, const void *source
io_buffer_validate_range(buffer, offset, length);
- if (source_offset + length > source_size) {
+ if (size_sum_is_bigger_than(source_offset, length, source_size)) {
rb_raise(rb_eArgError, "The computed source range exceeds the size of the source buffer!");
}
@@ -2450,7 +2589,9 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size), Qnil);
- return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
+ VALUE result = io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
+ RB_GC_GUARD(source);
+ return result;
}
/*
@@ -2535,7 +2676,9 @@ 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);
+ VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ RB_GC_GUARD(source);
+ return result;
}
/*
@@ -2613,7 +2756,9 @@ io_buffer_set_string(int argc, VALUE *argv, VALUE self)
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);
+ VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ RB_GC_GUARD(string);
+ return result;
}
void
@@ -2733,7 +2878,6 @@ io_buffer_blocking_region_ensure(VALUE _argument)
static VALUE
io_buffer_blocking_region(VALUE io, struct rb_io_buffer *buffer, rb_blocking_function_t *function, void *data)
{
- io = rb_io_get_io(io);
struct rb_io *ioptr;
RB_IO_POINTER(io, ioptr);
@@ -2798,6 +2942,8 @@ io_buffer_read_internal(void *_argument)
VALUE
rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset)
{
+ io = rb_io_get_io(io);
+
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_read(scheduler, io, self, length, offset);
@@ -2915,6 +3061,8 @@ io_buffer_pread_internal(void *_argument)
VALUE
rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset)
{
+ io = rb_io_get_io(io);
+
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, from, self, length, offset);
@@ -3035,6 +3183,8 @@ io_buffer_write_internal(void *_argument)
VALUE
rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset)
{
+ io = rb_io_get_write_io(rb_io_get_io(io));
+
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_write(scheduler, io, self, length, offset);
@@ -3099,6 +3249,7 @@ io_buffer_write(int argc, VALUE *argv, VALUE self)
return rb_io_buffer_write(self, io, length, offset);
}
+
struct io_buffer_pwrite_internal_argument {
// The file descriptor to write to:
int descriptor;
@@ -3144,6 +3295,8 @@ io_buffer_pwrite_internal(void *_argument)
VALUE
rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset)
{
+ io = rb_io_get_write_io(rb_io_get_io(io));
+
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, from, self, length, offset);
@@ -3225,14 +3378,14 @@ io_buffer_pwrite(int argc, VALUE *argv, VALUE self)
}
static inline void
-io_buffer_check_mask(const struct rb_io_buffer *buffer)
+io_buffer_check_mask_size(size_t size)
{
- if (buffer->size == 0)
+ if (size == 0)
rb_raise(rb_eIOBufferMaskError, "Zero-length mask given!");
}
static void
-memory_and(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size)
+memory_and(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = base[offset] & mask[offset % mask_size];
@@ -3260,19 +3413,27 @@ io_buffer_and(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ const void *mask_base;
+ size_t mask_size;
+ io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ io_buffer_check_mask_size(mask_size);
+
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_and(output_buffer->base, base, size, mask_base, mask_size);
return output;
}
static void
-memory_or(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size)
+memory_or(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = base[offset] | mask[offset % mask_size];
@@ -3300,19 +3461,27 @@ io_buffer_or(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ const void *mask_base;
+ size_t mask_size;
+ io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
+
+ io_buffer_check_mask_size(mask_size);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_or(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_or(output_buffer->base, base, size, mask_base, mask_size);
return output;
}
static void
-memory_xor(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size)
+memory_xor(unsigned char * restrict output, const unsigned char * restrict base, size_t size, const unsigned char * restrict mask, size_t mask_size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = base[offset] ^ mask[offset % mask_size];
@@ -3340,19 +3509,27 @@ io_buffer_xor(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ const void *mask_base;
+ size_t mask_size;
+ io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
+
+ io_buffer_check_mask_size(mask_size);
+
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_xor(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_xor(output_buffer->base, base, size, mask_base, mask_size);
return output;
}
static void
-memory_not(unsigned char * restrict output, unsigned char * restrict base, size_t size)
+memory_not(unsigned char * restrict output, const unsigned char * restrict base, size_t size)
{
for (size_t offset = 0; offset < size; offset += 1) {
output[offset] = ~base[offset];
@@ -3363,7 +3540,7 @@ memory_not(unsigned char * restrict output, unsigned char * restrict base, size_
* call-seq:
* ~source -> io_buffer
*
- * Generate a new buffer the same size as the source by applying the binary NOT
+ * Generate a new buffer the same size as the source by applying the unary NOT
* operation to the source.
*
* ~IO::Buffer.for("1234567890")
@@ -3377,11 +3554,15 @@ io_buffer_not(VALUE self)
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
- memory_not(output_buffer->base, buffer->base, buffer->size);
+ memory_not(output_buffer->base, base, size);
return output;
}
@@ -3437,7 +3618,7 @@ io_buffer_and_inplace(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask_size(mask_buffer->size);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
@@ -3483,7 +3664,7 @@ io_buffer_or_inplace(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask_size(mask_buffer->size);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
@@ -3529,7 +3710,7 @@ io_buffer_xor_inplace(VALUE self, VALUE mask)
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask_size(mask_buffer->size);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
@@ -3553,7 +3734,7 @@ memory_not_inplace(unsigned char * restrict base, size_t size)
* call-seq:
* source.not! -> io_buffer
*
- * Modify the source buffer in place by applying the binary NOT
+ * Modify the source buffer in place by applying the unary NOT
* operation to the source.
*
* source = IO::Buffer.for("1234567890").dup # Make a read/write copy.
@@ -3581,6 +3762,60 @@ io_buffer_not_inplace(VALUE self)
return self;
}
+static size_t
+memory_bit_count(const unsigned char *base, size_t size)
+{
+ size_t count = 0;
+
+ // Process 8 bytes at a time for efficiency:
+ const uint64_t *base64 = (const uint64_t *)base;
+ size_t count64 = size / 8;
+ for (size_t i = 0; i < count64; i += 1) {
+ count += rb_popcount64(base64[i]);
+ }
+
+ // Process any remaining bytes:
+ size_t remaining = size % 8;
+ const unsigned char *tail = base + (count64 * 8);
+ for (size_t i = 0; i < remaining; i += 1) {
+ count += rb_popcount32(tail[i]);
+ }
+
+ return count;
+}
+
+/*
+ * call-seq: bit_count([offset, [length]]) -> integer
+ *
+ * Returns the number of set bits (1s) in the buffer, also known as the
+ * Hamming weight or population count. An optional +offset+ and +length+
+ * can be provided to count bits in a subrange of the buffer.
+ *
+ * IO::Buffer.for("\xFF\x00\x0F").bit_count
+ * # => 12
+ *
+ * IO::Buffer.for("\xFF\x00\x0F").bit_count(1, 2)
+ * # => 4
+ */
+static VALUE
+io_buffer_bit_count(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);
+
+ io_buffer_validate_range(buffer, offset, length);
+
+ const void *base;
+ size_t size;
+ io_buffer_get_bytes_for_reading(buffer, &base, &size);
+
+ size_t count = memory_bit_count((const unsigned char *)base + offset, length);
+
+ return SIZET2NUM(count);
+}
+
/*
* Document-class: IO::Buffer
*
@@ -3647,9 +3882,9 @@ io_buffer_not_inplace(VALUE self)
*
* File.write('test.txt', 'test data')
* # => 9
- * buffer = IO::Buffer.map(File.open('test.txt'))
+ * buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
* # =>
- * # #<IO::Buffer 0x00007f3f0768c000+9 MAPPED IMMUTABLE>
+ * # #<IO::Buffer 0x00007f3f0768c000+9 EXTERNAL MAPPED FILE SHARED READONLY>
* # ...
* buffer.get_string(5, 2) # read 2 bytes, starting from offset 5
* # => "da"
@@ -3798,6 +4033,11 @@ Init_IO_Buffer(void)
IO_BUFFER_DEFINE_DATA_TYPE(s64);
IO_BUFFER_DEFINE_DATA_TYPE(S64);
+ IO_BUFFER_DEFINE_DATA_TYPE(u128);
+ IO_BUFFER_DEFINE_DATA_TYPE(U128);
+ IO_BUFFER_DEFINE_DATA_TYPE(s128);
+ IO_BUFFER_DEFINE_DATA_TYPE(S128);
+
IO_BUFFER_DEFINE_DATA_TYPE(f32);
IO_BUFFER_DEFINE_DATA_TYPE(F32);
IO_BUFFER_DEFINE_DATA_TYPE(f64);
@@ -3831,6 +4071,8 @@ Init_IO_Buffer(void)
rb_define_method(rb_cIOBuffer, "xor!", io_buffer_xor_inplace, 1);
rb_define_method(rb_cIOBuffer, "not!", io_buffer_not_inplace, 0);
+ rb_define_method(rb_cIOBuffer, "bit_count", io_buffer_bit_count, -1);
+
// IO operations:
rb_define_method(rb_cIOBuffer, "read", io_buffer_read, -1);
rb_define_method(rb_cIOBuffer, "pread", io_buffer_pread, -1);
diff --git a/iseq.c b/iseq.c
index 4583591b5d..b90fcb4334 100644
--- a/iseq.c
+++ b/iseq.c
@@ -19,6 +19,7 @@
#endif
#include "eval_intern.h"
+#include "id.h"
#include "id_table.h"
#include "internal.h"
#include "internal/bits.h"
@@ -31,18 +32,21 @@
#include "internal/io.h"
#include "internal/ruby_parser.h"
#include "internal/sanitizers.h"
+#include "internal/set_table.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
#include "ruby/util.h"
#include "vm_core.h"
+#include "ractor_core.h"
#include "vm_callinfo.h"
#include "yjit.h"
#include "ruby/ractor.h"
#include "builtin.h"
#include "insns.inc"
#include "insns_info.inc"
+#include "zjit.h"
VALUE rb_cISeq;
static VALUE iseqw_new(const rb_iseq_t *iseq);
@@ -84,7 +88,7 @@ free_arena(struct iseq_compile_data_storage *cur)
while (cur) {
next = cur->next;
- ruby_xfree(cur);
+ ruby_xfree_sized(cur, offsetof(struct iseq_compile_data_storage, buff) + cur->size * sizeof(char));
cur = next;
}
}
@@ -98,7 +102,7 @@ compile_data_free(struct iseq_compile_data *compile_data)
if (compile_data->ivar_cache_table) {
rb_id_table_free(compile_data->ivar_cache_table);
}
- ruby_xfree(compile_data);
+ SIZED_FREE(compile_data);
}
}
@@ -109,15 +113,15 @@ remove_from_constant_cache(ID id, IC ic)
VALUE lookup_result;
st_data_t ic_data = (st_data_t)ic;
- if (rb_id_table_lookup(vm->constant_cache, id, &lookup_result)) {
- st_table *ics = (st_table *)lookup_result;
- st_delete(ics, &ic_data, NULL);
+ if (rb_id_table_lookup(&vm->constant_cache, id, &lookup_result)) {
+ set_table *ics = (set_table *)lookup_result;
+ set_table_delete(ics, &ic_data);
if (ics->num_entries == 0 &&
// See comment in vm_track_constant_cache on why we need this check
id != vm->inserting_constant_cache_id) {
- rb_id_table_delete(vm->constant_cache, id);
- st_free_table(ics);
+ rb_id_table_delete(&vm->constant_cache, id);
+ set_free_table(ics);
}
}
}
@@ -148,14 +152,33 @@ iseq_clear_ic_references(const rb_iseq_t *iseq)
if (segments == NULL)
continue;
- for (int i = 0; segments[i]; i++) {
+ int i;
+ for (i = 0; segments[i]; i++) {
ID id = segments[i];
if (id == idNULL) continue;
remove_from_constant_cache(id, ic);
}
- ruby_xfree((void *)segments);
+ SIZED_FREE_N(segments, i + 1);
+ }
+}
+
+
+rb_hook_list_t *
+rb_iseq_local_hooks(const rb_iseq_t *iseq, rb_ractor_t *r, bool create)
+{
+ rb_hook_list_t *hook_list = NULL;
+ st_data_t val;
+ if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
+ hook_list = (rb_hook_list_t*)val;
+ RUBY_ASSERT(hook_list->type == hook_list_type_targeted_iseq);
+ }
+ else if (create) {
+ hook_list = RB_ZALLOC(rb_hook_list_t);
+ hook_list->type = hook_list_type_targeted_iseq;
+ st_insert(rb_ractor_targeted_hooks(r), (st_data_t)iseq, (st_data_t)hook_list);
}
+ return hook_list;
}
void
@@ -173,39 +196,44 @@ rb_iseq_free(const rb_iseq_t *iseq)
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 USE_ZJIT
+ rb_zjit_iseq_free(iseq);
+#endif
+ SIZED_FREE_N(body->iseq_encoded, body->iseq_size);
+ SIZED_FREE_N(body->insns_info.body, body->insns_info.size);
+ SIZED_FREE_N(body->insns_info.positions, body->insns_info.size);
#if VM_INSN_INFO_TABLE_IMPL == 2
ruby_xfree(body->insns_info.succ_index_table);
#endif
- ruby_xfree((void *)body->is_entries);
- ruby_xfree(body->call_data);
- ruby_xfree((void *)body->catch_table);
- ruby_xfree((void *)body->param.opt_table);
+ SIZED_FREE_N(body->is_entries, ISEQ_IS_SIZE(body));
+ SIZED_FREE_N(body->call_data, body->ci_size);
+ if (body->catch_table) {
+ ruby_xfree_sized(body->catch_table, iseq_catch_table_bytes(body->catch_table->size));
+ }
+ SIZED_FREE_N(body->param.opt_table, body->param.opt_num + 1);
if (ISEQ_MBITS_BUFLEN(body->iseq_size) > 1 && body->mark_bits.list) {
- ruby_xfree((void *)body->mark_bits.list);
+ SIZED_FREE_N(body->mark_bits.list, ISEQ_MBITS_BUFLEN(body->iseq_size));
}
- ruby_xfree(body->variable.original_iseq);
+ ISEQ_ORIGINAL_ISEQ_CLEAR(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);
- if (body->param.keyword->default_values) {
- ruby_xfree((void *)body->param.keyword->default_values);
+ struct rb_iseq_param_keyword *pkw = (struct rb_iseq_param_keyword *)body->param.keyword;
+ if (pkw != NULL) {
+ if (pkw->table != &body->local_table[pkw->bits_start - pkw->num])
+ SIZED_FREE_N(pkw->table, pkw->required_num);
+ if (pkw->default_values) {
+ SIZED_FREE_N(pkw->default_values, pkw->num - pkw->required_num);
}
- ruby_xfree((void *)body->param.keyword);
+ SIZED_FREE(pkw);
+ }
+ if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl)) {
+ SIZED_FREE_N(body->local_table, body->local_table_size);
}
- if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl))
- ruby_xfree((void *)body->local_table);
+ SIZED_FREE_N(body->lvar_states, body->local_table_size);
+
compile_data_free(ISEQ_COMPILE_DATA(iseq));
if (body->outer_variables) rb_id_table_free(body->outer_variables);
- ruby_xfree(body);
- }
-
- if (iseq && ISEQ_EXECUTABLE_P(iseq) && iseq->aux.exec.local_hooks) {
- rb_hook_list_free(iseq->aux.exec.local_hooks);
+ SIZED_FREE(body);
}
RUBY_FREE_LEAVE("iseq");
@@ -274,9 +302,7 @@ rb_iseq_mark_and_move_each_body_value(const rb_iseq_t *iseq, VALUE *original_ise
for (unsigned int i = 0; i < body->icvarc_size; i++, is_entries++) {
ICVARC icvarc = (ICVARC)is_entries;
if (icvarc->entry) {
- RUBY_ASSERT(!RB_TYPE_P(icvarc->entry->class_value, T_NONE));
-
- rb_gc_mark_and_move(&icvarc->entry->class_value);
+ rb_gc_mark_and_move((VALUE *)&icvarc->entry);
}
}
@@ -323,15 +349,13 @@ cc_is_active(const struct rb_callcache *cc, bool reference_updating)
cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
}
- 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 (!METHOD_ENTRY_INVALIDATED(cme)) {
- return true;
- }
+ if (vm_cc_markable(cc) && vm_cc_valid(cc)) {
+ 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 (!METHOD_ENTRY_INVALIDATED(cme)) {
+ return true;
}
}
}
@@ -350,8 +374,6 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
rb_iseq_mark_and_move_each_body_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : 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);
@@ -401,33 +423,48 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
#if USE_YJIT
rb_yjit_iseq_update_references(iseq);
#endif
+#if USE_ZJIT
+ rb_zjit_iseq_update_references(body->zjit_payload);
+#endif
}
else {
+ // TODO: check jit payload
+ if (!rb_gc_checking_shareable()) {
#if USE_YJIT
- rb_yjit_iseq_mark(body->yjit_payload);
+ rb_yjit_iseq_mark(body->yjit_payload);
+#endif
+#if USE_ZJIT
+ rb_zjit_iseq_mark(body->zjit_payload);
#endif
+ }
+ }
+
+ // TODO: ractor aware coverage
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&body->variable.coverage);
+ rb_gc_mark_and_move(&body->variable.pc2branchindex);
}
}
if (FL_TEST_RAW((VALUE)iseq, ISEQ_NOT_LOADED_YET)) {
- rb_gc_mark_and_move(&iseq->aux.loader.obj);
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&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 (!rb_gc_checking_shareable()) {
+ const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
- rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head);
- rb_iseq_mark_and_move_each_compile_data_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
+ rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head);
+ rb_iseq_mark_and_move_each_compile_data_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
- rb_gc_mark_and_move((VALUE *)&compile_data->err_info);
- rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary);
+ rb_gc_mark_and_move((VALUE *)&compile_data->err_info);
+ rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary);
+ }
}
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);
- }
}
RUBY_MARK_LEAVE("iseq");
@@ -532,9 +569,14 @@ rb_iseq_pathobj_new(VALUE path, VALUE realpath)
pathobj = rb_fstring(path);
}
else {
- if (!NIL_P(realpath)) realpath = rb_fstring(realpath);
- pathobj = rb_ary_new_from_args(2, rb_fstring(path), realpath);
+ if (!NIL_P(realpath)) {
+ realpath = rb_fstring(realpath);
+ }
+ VALUE fpath = rb_fstring(path);
+
+ pathobj = rb_ary_new_from_args(2, fpath, realpath);
rb_ary_freeze(pathobj);
+ RB_OBJ_SET_SHAREABLE(pathobj);
}
return pathobj;
}
@@ -553,6 +595,11 @@ rb_iseq_alloc_with_dummy_path(VALUE fname)
rb_iseq_t *dummy_iseq = iseq_alloc();
ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP;
+
+ if (!RB_OBJ_SHAREABLE_P(fname)) {
+ RB_OBJ_SET_FROZEN_SHAREABLE(fname);
+ }
+
RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname);
RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname);
@@ -601,11 +648,11 @@ set_relation(rb_iseq_t *iseq, const rb_iseq_t *piseq)
body->local_iseq = iseq;
}
else if (piseq) {
- body->local_iseq = ISEQ_BODY(piseq)->local_iseq;
+ RB_OBJ_WRITE(iseq, &body->local_iseq, ISEQ_BODY(piseq)->local_iseq);
}
if (piseq) {
- body->parent_iseq = piseq;
+ RB_OBJ_WRITE(iseq, &body->parent_iseq, piseq);
}
if (type == ISEQ_TYPE_MAIN) {
@@ -628,6 +675,18 @@ new_arena(void)
return new_arena;
}
+static int
+prepare_node_id(const NODE *node)
+{
+ if (!node) return -1;
+
+ if (nd_type(node) == NODE_SCOPE && RNODE_SCOPE(node)->nd_parent) {
+ return nd_node_id(RNODE_SCOPE(node)->nd_parent);
+ }
+
+ return nd_node_id(node);
+}
+
static VALUE
prepare_iseq_build(rb_iseq_t *iseq,
VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id,
@@ -701,7 +760,7 @@ rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
body->insns_info.succ_index_table = succ_index_table_create(max_pos, data, size);
#if VM_CHECK_MODE == 0
- ruby_xfree(body->insns_info.positions);
+ SIZED_FREE_N(body->insns_info.positions, body->insns_info.size);
body->insns_info.positions = NULL;
#endif
#endif
@@ -805,10 +864,6 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
static rb_compile_option_t *
set_compile_option_from_ast(rb_compile_option_t *option, const rb_ast_body_t *ast)
{
-#define SET_COMPILE_OPTION(o, a, mem) \
- ((a)->mem < 0 ? 0 : ((o)->mem = (a)->mem > 0))
- SET_COMPILE_OPTION(option, ast, coverage_enabled);
-#undef SET_COMPILE_OPTION
if (ast->frozen_string_literal >= 0) {
option->frozen_string_literal = ast->frozen_string_literal;
}
@@ -921,7 +976,7 @@ rb_iseq_new_top(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, c
rb_iseq_t *
pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, int *error_state)
{
- iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
+ iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1));
return pm_iseq_new_with_opt(node, name, path, realpath, 0, parent, 0,
ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT, error_state);
@@ -945,7 +1000,7 @@ rb_iseq_new_main(const VALUE ast_value, VALUE path, VALUE realpath, const rb_ise
rb_iseq_t *
pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state)
{
- iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
+ iseq_new_setup_coverage(path, (int) (pm_parser_line_offsets(node->parser)->size - 1));
return pm_iseq_new_with_opt(node, rb_fstring_lit("<main>"),
path, realpath, 0,
@@ -962,8 +1017,13 @@ rb_iseq_new_eval(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
}
}
+ rb_compile_option_t option = COMPILE_OPTION_DEFAULT;
+ rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
+ if (ast->body.coverage_enabled >= 0) {
+ option.coverage_enabled = ast->body.coverage_enabled;
+ }
return rb_iseq_new_with_opt(ast_value, name, path, realpath, first_lineno,
- parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT,
+ parent, isolated_depth, ISEQ_TYPE_EVAL, &option,
Qnil);
}
@@ -974,7 +1034,7 @@ pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) {
VALUE coverages = rb_get_coverages();
if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) {
- iseq_setup_coverage(coverages, path, ((int) (node->parser->newline_list.size - 1)) + first_lineno - 1);
+ iseq_setup_coverage(coverages, path, ((int) (pm_parser_line_offsets(node->parser)->size - 1)) + first_lineno - 1);
}
}
@@ -1025,7 +1085,7 @@ rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
script_lines = ISEQ_BODY(parent)->variable.script_lines;
}
- prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1,
+ prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, prepare_node_id(node),
parent, isolated_depth, type, script_lines, option);
rb_iseq_compile_node(iseq, node);
@@ -1035,41 +1095,15 @@ rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
return iseq_translate(iseq);
}
-struct pm_iseq_new_with_opt_data {
- rb_iseq_t *iseq;
- pm_scope_node_t *node;
-};
-
-VALUE
-pm_iseq_new_with_opt_try(VALUE d)
-{
- struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
-
- // This can compile child iseqs, which can raise syntax errors
- pm_iseq_compile_node(data->iseq, data->node);
-
- // This raises an exception if there is a syntax error
- finish_iseq_build(data->iseq);
-
- return Qundef;
-}
-
/**
- * This is a step in the prism compiler that is called once all of the various
- * options have been established. It is called from one of the pm_iseq_new_*
- * functions or from the RubyVM::InstructionSequence APIs. It is responsible for
- * allocating the instruction sequence, calling into the compiler, and returning
- * the built instruction sequence.
- *
- * Importantly, this is also the function where the compiler is re-entered to
- * compile child instruction sequences. A child instruction sequence is always
- * compiled using a scope node, which is why we cast it explicitly to that here
- * in the parameters (as opposed to accepting a generic pm_node_t *).
+ * Core implementation for building a prism iseq. This does not use rb_protect,
+ * so any exceptions (e.g. from finish_iseq_build) propagate normally up the
+ * call stack — matching the parse.y compiler's behavior.
*/
rb_iseq_t *
-pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
- int first_lineno, const rb_iseq_t *parent, int isolated_depth,
- enum rb_iseq_type type, const rb_compile_option_t *option, int *error_state)
+pm_iseq_build(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
+ int first_lineno, const rb_iseq_t *parent, int isolated_depth,
+ enum rb_iseq_type type, const rb_compile_option_t *option)
{
rb_iseq_t *iseq = iseq_alloc();
ISEQ_BODY(iseq)->prism = true;
@@ -1082,10 +1116,11 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa
option = &next_option;
pm_location_t *location = &node->base.location;
- int32_t start_line = node->parser->start_line;
+ int32_t start_line = pm_parser_start_line(node->parser);
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(node->parser);
- pm_line_column_t start = pm_newline_list_line_column(&node->parser->newline_list, location->start, start_line);
- pm_line_column_t end = pm_newline_list_line_column(&node->parser->newline_list, location->end, start_line);
+ pm_line_column_t start = pm_line_offset_list_line_column(line_offsets, location->start, start_line);
+ pm_line_column_t end = pm_line_offset_list_line_column(line_offsets, location->start + location->length, start_line);
rb_code_location_t code_location = (rb_code_location_t) {
.beg_pos = { .lineno = (int) start.line, .column = (int) start.column },
@@ -1095,15 +1130,59 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, node->ast_node->node_id,
parent, isolated_depth, type, node->script_lines == NULL ? Qnil : *node->script_lines, option);
+ pm_iseq_compile_node(iseq, node);
+ finish_iseq_build(iseq);
+
+ return iseq_translate(iseq);
+}
+
+struct pm_iseq_new_with_opt_data {
+ rb_iseq_t *iseq;
+ pm_scope_node_t *node;
+ VALUE name, path, realpath;
+ int first_lineno, isolated_depth;
+ const rb_iseq_t *parent;
+ enum rb_iseq_type type;
+ const rb_compile_option_t *option;
+};
+
+static VALUE
+pm_iseq_new_with_opt_try(VALUE d)
+{
+ struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
+ data->iseq = pm_iseq_build(data->node, data->name, data->path, data->realpath,
+ data->first_lineno, data->parent, data->isolated_depth,
+ data->type, data->option);
+ return Qundef;
+}
+
+/**
+ * This is a step in the prism compiler that is called once all of the various
+ * options have been established. It is called from one of the pm_iseq_new_*
+ * functions or from the RubyVM::InstructionSequence APIs.
+ *
+ * This function uses rb_protect to catch exceptions, storing the error state
+ * in the provided out parameter. This is only needed at top-level entry points
+ * where the caller wants to handle errors gracefully. Child iseqs compiled
+ * during the compilation process do NOT go through this function — they use
+ * pm_iseq_build directly, letting exceptions propagate naturally (matching
+ * the parse.y compiler's behavior).
+ */
+rb_iseq_t *
+pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
+ int first_lineno, const rb_iseq_t *parent, int isolated_depth,
+ enum rb_iseq_type type, const rb_compile_option_t *option, int *error_state)
+{
struct pm_iseq_new_with_opt_data data = {
- .iseq = iseq,
- .node = node
+ .node = node, .name = name, .path = path, .realpath = realpath,
+ .first_lineno = first_lineno, .parent = parent,
+ .isolated_depth = isolated_depth, .type = type, .option = option
};
rb_protect(pm_iseq_new_with_opt_try, (VALUE)&data, error_state);
if (*error_state) return NULL;
- return iseq_translate(iseq);
+ return data.iseq;
}
rb_iseq_t *
@@ -1131,7 +1210,22 @@ rb_iseq_load_iseq(VALUE fname)
VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("load_iseq"), 1, &fname);
if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
- return iseqw_check(iseqv);
+ return iseqw_check(iseqv);
+ }
+
+ return NULL;
+}
+
+const rb_iseq_t *
+rb_iseq_compile_iseq(VALUE str, VALUE fname)
+{
+ VALUE args[] = {
+ str, fname
+ };
+ VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("compile"), 2, args);
+
+ if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
+ return iseqw_check(iseqv);
}
return NULL;
@@ -1304,6 +1398,7 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
rb_exc_raise(GET_EC()->errinfo);
}
else {
+ iseq_new_setup_coverage(file, ast_line_count(ast_value));
iseq = rb_iseq_new_with_opt(ast_value, name, file, realpath, ln,
NULL, 0, ISEQ_TYPE_TOP, &option,
Qnil);
@@ -1326,19 +1421,29 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
ln = NUM2INT(line);
StringValueCStr(file);
- pm_parse_result_t result = { 0 };
- pm_options_line_set(&result.options, NUM2INT(line));
- pm_options_scopes_init(&result.options, 1);
+ bool parse_file = false;
+ if (RB_TYPE_P(src, T_FILE)) {
+ parse_file = true;
+ src = rb_io_path(src);
+ }
+ else {
+ src = StringValue(src);
+ }
+
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
+ pm_options_line_set(result.options, NUM2INT(line));
+ pm_options_scopes_init(result.options, 1);
result.node.coverage_enabled = 1;
switch (option.frozen_string_literal) {
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
- pm_options_frozen_string_literal_set(&result.options, false);
+ pm_options_frozen_string_literal_set(result.options, false);
break;
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
- pm_options_frozen_string_literal_set(&result.options, true);
+ pm_options_frozen_string_literal_set(result.options, true);
break;
default:
rb_bug("pm_iseq_compile_with_option: invalid frozen_string_literal=%d", option.frozen_string_literal);
@@ -1348,18 +1453,18 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
VALUE script_lines;
VALUE error;
- if (RB_TYPE_P(src, T_FILE)) {
- VALUE filepath = rb_io_path(src);
- error = pm_load_parse_file(&result, filepath, ruby_vm_keep_script_lines ? &script_lines : NULL);
- RB_GC_GUARD(filepath);
+ if (parse_file) {
+ error = pm_load_parse_file(&result, src, ruby_vm_keep_script_lines ? &script_lines : NULL);
}
else {
- src = StringValue(src);
error = pm_parse_string(&result, src, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
}
+ RB_GC_GUARD(src);
+
if (error == Qnil) {
int error_state;
+ iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
iseq = pm_iseq_new_with_opt(&result.node, name, file, realpath, ln, NULL, 0, ISEQ_TYPE_TOP, &option, &error_state);
pm_parse_result_free(&result);
@@ -1483,9 +1588,9 @@ rb_iseq_remove_coverage_all(void)
/* define wrapper class methods (RubyVM::InstructionSequence) */
static void
-iseqw_mark(void *ptr)
+iseqw_mark_and_move(void *ptr)
{
- rb_gc_mark_movable(*(VALUE *)ptr);
+ rb_gc_mark_and_move((VALUE *)ptr);
}
static size_t
@@ -1494,20 +1599,13 @@ iseqw_memsize(const void *ptr)
return rb_iseq_memsize(*(const rb_iseq_t **)ptr);
}
-static void
-iseqw_ref_update(void *ptr)
-{
- VALUE *vptr = ptr;
- *vptr = rb_gc_location(*vptr);
-}
-
static const rb_data_type_t iseqw_data_type = {
"T_IMEMO/iseq",
{
- iseqw_mark,
+ iseqw_mark_and_move,
RUBY_TYPED_DEFAULT_FREE,
iseqw_memsize,
- iseqw_ref_update,
+ iseqw_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};
@@ -1528,8 +1626,8 @@ iseqw_new(const rb_iseq_t *iseq)
RB_OBJ_WRITE(obj, ptr, iseq);
/* cache a wrapper object */
+ RB_OBJ_SET_FROZEN_SHAREABLE((VALUE)obj);
RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj);
- RB_OBJ_FREEZE((VALUE)iseq);
return obj;
}
@@ -1591,7 +1689,7 @@ iseqw_s_compile_parser(int argc, VALUE *argv, VALUE self, bool prism)
* real path and first line number of the ruby code in +source+ which are
* metadata attached to the returned +iseq+.
*
- * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
+ * +file+ is used for +__FILE__+ and exception backtrace. +path+ is used for
* +require_relative+ base. It is recommended these should be the same full
* path.
*
@@ -1633,7 +1731,7 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
* real path and first line number of the ruby code in +source+ which are
* metadata attached to the returned +iseq+.
*
- * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
+ * +file+ is used for +__FILE__+ and exception backtrace. +path+ is used for
* +require_relative+ base. It is recommended these should be the same full
* path.
*
@@ -1675,7 +1773,7 @@ iseqw_s_compile_parsey(int argc, VALUE *argv, VALUE self)
* real path and first line number of the ruby code in +source+ which are
* metadata attached to the returned +iseq+.
*
- * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
+ * +file+ is used for +__FILE__+ and exception backtrace. +path+ is used for
* +require_relative+ base. It is recommended these should be the same full
* path.
*
@@ -1706,6 +1804,8 @@ iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
return iseqw_s_compile_parser(argc, argv, self, true);
}
+static VALUE iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self);
+
/*
* call-seq:
* InstructionSequence.compile_file(file[, options]) -> iseq
@@ -1729,6 +1829,10 @@ iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
static VALUE
iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
{
+ if (rb_ruby_prism_p()) {
+ return iseqw_s_compile_file_prism(argc, argv, self);
+ }
+
VALUE file, opt = Qnil;
VALUE parser, f, exc = Qnil, ret;
rb_ast_t *ast;
@@ -1752,6 +1856,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
ast_value = rb_parser_load_file(parser, file);
+ iseq_new_setup_coverage(file, ast_line_count(ast_value));
ast = rb_ruby_ast_data_get(ast_value);
if (!ast->body.root) exc = GET_EC()->errinfo;
@@ -1815,17 +1920,32 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, file);
- pm_parse_result_t result = { 0 };
- result.options.line = 1;
+ make_compile_option(&option, opt);
+
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
result.node.coverage_enabled = 1;
+ switch (option.frozen_string_literal) {
+ case ISEQ_FROZEN_STRING_LITERAL_UNSET:
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
+ pm_options_frozen_string_literal_set(result.options, false);
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
+ pm_options_frozen_string_literal_set(result.options, true);
+ break;
+ default:
+ rb_bug("iseqw_s_compile_file_prism: invalid frozen_string_literal=%d", option.frozen_string_literal);
+ break;
+ }
+
VALUE script_lines;
VALUE error = pm_load_parse_file(&result, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
if (error == Qnil) {
- make_compile_option(&option, opt);
-
int error_state;
+ iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
rb_iseq_t *iseq = pm_iseq_new_with_opt(&result.node, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
@@ -1842,7 +1962,8 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
return ret;
- } else {
+ }
+ else {
pm_parse_result_free(&result);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
@@ -1941,7 +2062,7 @@ iseqw_eval(VALUE 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(iseq, rb_current_box());
}
/*
@@ -2375,15 +2496,22 @@ rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
}
}
+static void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
+
+// Clear tracing event flags and turn off tracing for a given instruction as needed.
+// This is currently used after updating a one-shot line coverage for the current instruction.
void
rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset)
{
- struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
- if (entry) {
- entry->events &= ~reset;
- if (!(entry->events & iseq->aux.exec.global_trace_events)) {
- void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
- rb_iseq_trace_flag_cleared(iseq, pos);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+
+ struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
+ if (entry) {
+ entry->events &= ~reset;
+ if (!(entry->events & iseq->aux.exec.global_trace_events)) {
+ rb_iseq_trace_flag_cleared(iseq, pos);
+ }
}
}
}
@@ -2902,24 +3030,31 @@ rb_iseq_disasm(const rb_iseq_t *iseq)
attr_index_t
rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
{
- struct rb_id_table * iv_names = rb_id_table_create(0);
+ set_table iv_names = { 0 };
+ set_init_embedded_numtable_with_size(&iv_names, 0);
for (unsigned int i = 0; i < ISEQ_BODY(initialize_iseq)->ivc_size; i++) {
IVC cache = (IVC)&ISEQ_BODY(initialize_iseq)->is_entries[i];
if (cache->iv_set_name) {
- rb_id_table_insert(iv_names, cache->iv_set_name, Qtrue);
+ set_insert(&iv_names, cache->iv_set_name);
}
}
- attr_index_t count = (attr_index_t)rb_id_table_size(iv_names);
+ size_t count = iv_names.num_entries;
VALUE superclass = rb_class_superclass(klass);
- count += RCLASS_EXT(superclass)->max_iv_count;
+ if (!NIL_P(superclass)) { // BasicObject doesn't have a superclass
+ count += RCLASS_MAX_IV_COUNT(superclass);
+ }
+
+ set_free_embedded_table(&iv_names);
- rb_id_table_free(iv_names);
+ if (count > (attr_index_t)-1) {
+ return (attr_index_t)-1;
+ }
- return count;
+ return (attr_index_t)count;
}
/*
@@ -3140,7 +3275,7 @@ iseqw_s_of(VALUE klass, VALUE body)
* 0000 trace 8 ( 1)
* 0002 trace 1 ( 2)
* 0004 putself
- * 0005 putstring "hello, world"
+ * 0005 dupstring "hello, world"
* 0007 send :puts, 1, nil, 8, <ic:0>
* 0013 trace 16 ( 3)
* 0015 leave ( 2)
@@ -3205,7 +3340,7 @@ static int
cdhash_each(VALUE key, VALUE value, VALUE ary)
{
rb_ary_push(ary, obj_resurrect(key));
- rb_ary_push(ary, value);
+ rb_ary_push(ary, INT2FIX(value));
return ST_CONTINUE;
}
@@ -3264,6 +3399,7 @@ iseq_type_id(enum rb_iseq_type type)
static VALUE
iseq_data_to_ary(const rb_iseq_t *iseq)
{
+ VALUE iseq_value = (VALUE)iseq;
unsigned int i;
long l;
const struct rb_iseq_constant_body *const iseq_body = ISEQ_BODY(iseq);
@@ -3281,7 +3417,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
VALUE exception = rb_ary_new(); /* [[....]] */
VALUE misc = rb_hash_new();
- static ID insn_syms[VM_INSTRUCTION_SIZE/2]; /* w/o-trace only */
+ static ID insn_syms[VM_BARE_INSTRUCTION_SIZE]; /* w/o-trace only */
struct st_table *labels_table = st_init_numtable();
VALUE labels_wrapper = TypedData_Wrap_Struct(0, &label_wrapper, labels_table);
@@ -3299,7 +3435,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
for (i=0; i<iseq_body->local_table_size; i++) {
ID lid = iseq_body->local_table[i];
if (lid) {
- if (rb_id2str(lid)) {
+ if (lid != idItImplicit && rb_id2str(lid)) {
rb_ary_push(locals, ID2SYM(lid));
}
else { /* hidden variable from id_internal() */
@@ -3445,11 +3581,11 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
break;
case TS_CDHASH:
{
- VALUE hash = *seq;
+ VALUE cdhash = *seq;
VALUE val = rb_ary_new();
int i;
- rb_hash_foreach(hash, cdhash_each, val);
+ st_foreach(rb_imemo_cdhash_tbl(cdhash), cdhash_each, val);
for (i=0; i<RARRAY_LEN(val); i+=2) {
VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
@@ -3596,6 +3732,9 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
rb_ary_push(val, params);
rb_ary_push(val, exception);
rb_ary_push(val, body);
+
+ RB_GC_GUARD(iseq_value);
+
return val;
}
@@ -3609,10 +3748,10 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
ID req, opt, rest, block, key, keyrest;
#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
#define PARAM_ID(i) body->local_table[(i)]
-#define PARAM(i, type) ( \
- PARAM_TYPE(type), \
- rb_id2str(PARAM_ID(i)) ? \
- rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
+#define PARAM(i, type) ( \
+ PARAM_TYPE(type), \
+ PARAM_ID(i) != idItImplicit && rb_id2str(PARAM_ID(i)) ? \
+ rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
a)
CONST_ID(req, "req");
@@ -3630,11 +3769,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
if (is_proc) {
for (i = 0; i < body->param.lead_num; i++) {
- PARAM_TYPE(opt);
- if (rb_id2str(PARAM_ID(i))) {
- rb_ary_push(a, ID2SYM(PARAM_ID(i)));
- }
- rb_ary_push(args, a);
+ rb_ary_push(args, PARAM(i, opt));
}
}
else {
@@ -3644,11 +3779,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
}
r = body->param.lead_num + body->param.opt_num;
for (; i < r; i++) {
- PARAM_TYPE(opt);
- if (rb_id2str(PARAM_ID(i))) {
- rb_ary_push(a, ID2SYM(PARAM_ID(i)));
- }
- rb_ary_push(args, a);
+ rb_ary_push(args, PARAM(i, opt));
}
if (body->param.flags.has_rest) {
CONST_ID(rest, "rest");
@@ -3657,11 +3788,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
r = body->param.post_start + body->param.post_num;
if (is_proc) {
for (i = body->param.post_start; i < r; i++) {
- PARAM_TYPE(opt);
- if (rb_id2str(PARAM_ID(i))) {
- rb_ary_push(a, ID2SYM(PARAM_ID(i)));
- }
- rb_ary_push(args, a);
+ rb_ary_push(args, PARAM(i, opt));
}
}
else {
@@ -3710,7 +3837,13 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
}
rb_ary_push(args, a);
}
- if (body->param.flags.has_block) {
+ if (body->param.flags.accepts_no_block) {
+ ID noblock;
+ CONST_ID(noblock, "noblock");
+ PARAM_TYPE(noblock);
+ rb_ary_push(args, a);
+ }
+ else if (body->param.flags.has_block) {
CONST_ID(block, "block");
rb_ary_push(args, PARAM(body->param.block_start, block));
}
@@ -3743,17 +3876,21 @@ rb_iseq_defined_string(enum defined_type type)
return rb_fstring_cstr(estr);
}
-/* A map from encoded_insn to insn_data: decoded insn number, its len,
- * non-trace version of encoded insn, and trace version. */
-
+// A map from encoded_insn to insn_data: decoded insn number, its len,
+// decoded ZJIT insn number, non-trace version of encoded insn,
+// trace version, and zjit version.
static st_table *encoded_insn_data;
typedef struct insn_data_struct {
int insn;
int insn_len;
void *notrace_encoded_insn;
void *trace_encoded_insn;
+#if USE_ZJIT
+ int zjit_insn;
+ void *zjit_encoded_insn;
+#endif
} insn_data_t;
-static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
+static insn_data_t insn_data[VM_BARE_INSTRUCTION_SIZE];
void
rb_free_encoded_insn_data(void)
@@ -3761,6 +3898,8 @@ rb_free_encoded_insn_data(void)
st_free_table(encoded_insn_data);
}
+// Initialize a table to decode bare, trace, and zjit instructions.
+// This function also determines which instructions are used when TracePoint is enabled.
void
rb_vm_encoded_insn_data_table_init(void)
{
@@ -3768,32 +3907,42 @@ rb_vm_encoded_insn_data_table_init(void)
const void * const *table = rb_vm_get_insns_address_table();
#define INSN_CODE(insn) ((VALUE)table[insn])
#else
-#define INSN_CODE(insn) (insn)
+#define INSN_CODE(insn) ((VALUE)(insn))
#endif
- st_data_t insn;
- encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
-
- for (insn = 0; insn < VM_INSTRUCTION_SIZE/2; insn++) {
- st_data_t key1 = (st_data_t)INSN_CODE(insn);
- st_data_t key2 = (st_data_t)INSN_CODE(insn + VM_INSTRUCTION_SIZE/2);
+ encoded_insn_data = st_init_numtable_with_size(VM_BARE_INSTRUCTION_SIZE);
- insn_data[insn].insn = (int)insn;
+ for (int insn = 0; insn < VM_BARE_INSTRUCTION_SIZE; insn++) {
+ insn_data[insn].insn = insn;
insn_data[insn].insn_len = insn_len(insn);
- if (insn != BIN(opt_invokebuiltin_delegate_leave)) {
- insn_data[insn].notrace_encoded_insn = (void *) key1;
- insn_data[insn].trace_encoded_insn = (void *) key2;
- }
- else {
- insn_data[insn].notrace_encoded_insn = (void *) INSN_CODE(BIN(opt_invokebuiltin_delegate));
- insn_data[insn].trace_encoded_insn = (void *) INSN_CODE(BIN(opt_invokebuiltin_delegate) + VM_INSTRUCTION_SIZE/2);
- }
+ // When tracing :return events, we convert opt_invokebuiltin_delegate_leave + leave into
+ // opt_invokebuiltin_delegate + trace_leave, presumably because we don't want to fire
+ // :return events before invokebuiltin. https://github.com/ruby/ruby/pull/3256
+ int notrace_insn = (insn != BIN(opt_invokebuiltin_delegate_leave)) ? insn : BIN(opt_invokebuiltin_delegate);
+ insn_data[insn].notrace_encoded_insn = (void *)INSN_CODE(notrace_insn);
+ insn_data[insn].trace_encoded_insn = (void *)INSN_CODE(notrace_insn + VM_BARE_INSTRUCTION_SIZE);
+ st_data_t key1 = (st_data_t)INSN_CODE(insn);
+ st_data_t key2 = (st_data_t)INSN_CODE(insn + VM_BARE_INSTRUCTION_SIZE);
st_add_direct(encoded_insn_data, key1, (st_data_t)&insn_data[insn]);
st_add_direct(encoded_insn_data, key2, (st_data_t)&insn_data[insn]);
+
+#if USE_ZJIT
+ int zjit_insn = vm_bare_insn_to_zjit_insn(insn);
+ insn_data[insn].zjit_insn = zjit_insn;
+ insn_data[insn].zjit_encoded_insn = (insn != zjit_insn) ? (void *)INSN_CODE(zjit_insn) : 0;
+
+ if (insn != zjit_insn) {
+ st_data_t key3 = (st_data_t)INSN_CODE(zjit_insn);
+ st_add_direct(encoded_insn_data, key3, (st_data_t)&insn_data[insn]);
+ }
+#endif
}
}
+// Decode an insn address to an insn. This returns bare instructions
+// even if they're trace/zjit instructions. Use rb_vm_insn_addr2opcode
+// to decode trace/zjit instructions as is.
int
rb_vm_insn_addr2insn(const void *addr)
{
@@ -3808,7 +3957,8 @@ rb_vm_insn_addr2insn(const void *addr)
rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr);
}
-// Unlike rb_vm_insn_addr2insn, this function can return trace opcode variants.
+// Decode an insn address to an insn. Unlike rb_vm_insn_addr2insn,
+// this function can return trace/zjit opcode variants.
int
rb_vm_insn_addr2opcode(const void *addr)
{
@@ -3819,15 +3969,22 @@ rb_vm_insn_addr2opcode(const void *addr)
insn_data_t *e = (insn_data_t *)val;
int opcode = e->insn;
if (addr == e->trace_encoded_insn) {
- opcode += VM_INSTRUCTION_SIZE/2;
+ opcode += VM_BARE_INSTRUCTION_SIZE;
}
+#if USE_ZJIT
+ else if (addr == e->zjit_encoded_insn) {
+ opcode = e->zjit_insn;
+ }
+#endif
return opcode;
}
rb_bug("rb_vm_insn_addr2opcode: invalid insn address: %p", addr);
}
-// Decode `ISEQ_BODY(iseq)->iseq_encoded[i]` to an insn.
+// Decode `ISEQ_BODY(iseq)->iseq_encoded[i]` to an insn. This returns
+// bare instructions even if they're trace/zjit instructions. Use
+// rb_vm_insn_addr2opcode to decode trace/zjit instructions as is.
int
rb_vm_insn_decode(const VALUE encoded)
{
@@ -3839,15 +3996,16 @@ rb_vm_insn_decode(const VALUE encoded)
return insn;
}
+// Turn on or off tracing for a given instruction address
static inline int
-encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_current_trace)
+encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon, bool remain_traced)
{
st_data_t key = (st_data_t)*iseq_encoded_insn;
st_data_t val;
if (st_lookup(encoded_insn_data, key, &val)) {
insn_data_t *e = (insn_data_t *)val;
- if (remain_current_trace && key == (st_data_t)e->trace_encoded_insn) {
+ if (remain_traced && key == (st_data_t)e->trace_encoded_insn) {
turnon = 1;
}
*iseq_encoded_insn = (VALUE) (turnon ? e->trace_encoded_insn : e->notrace_encoded_insn);
@@ -3857,7 +4015,8 @@ encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon,
rb_bug("trace_instrument: invalid insn address: %p", (void *)*iseq_encoded_insn);
}
-void
+// Turn off tracing for an instruction at pos after tracing event flags are cleared
+static void
rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
{
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
@@ -3883,14 +4042,16 @@ add_bmethod_events(rb_event_flag_t events)
// Note, to support call/return events for bmethods, turnon_event can have more events than tpval.
static int
-iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
+iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, rb_ractor_t *r)
{
unsigned int pc;
int n = 0;
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
+ rb_iseq_t *iseq_mut = (rb_iseq_t*)iseq;
VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
+ ASSERT_vm_locking_with_barrier();
for (pc=0; pc<body->iseq_size;) {
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc);
@@ -3912,11 +4073,9 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events,
}
if (n > 0) {
- if (iseq->aux.exec.local_hooks == NULL) {
- ((rb_iseq_t *)iseq)->aux.exec.local_hooks = RB_ZALLOC(rb_hook_list_t);
- iseq->aux.exec.local_hooks->is_local = true;
- }
- rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->aux.exec.local_hooks, tpval, target_line);
+ rb_hook_list_t *hook_list = rb_iseq_local_hooks(iseq, r, true);
+ rb_hook_list_connect_local_tracepoint(hook_list, tpval, target_line);
+ iseq_mut->aux.exec.local_hooks_cnt++;
}
return n;
@@ -3927,19 +4086,21 @@ struct trace_set_local_events_struct {
VALUE tpval;
unsigned int target_line;
int n;
+ rb_ractor_t *r;
};
static void
iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
{
struct trace_set_local_events_struct *data = (struct trace_set_local_events_struct *)p;
- data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line);
+ data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line, data->r);
iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
}
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)
{
+ ASSERT_vm_locking_with_barrier();
struct trace_set_local_events_struct data;
if (target_bmethod) {
turnon_events = add_bmethod_events(turnon_events);
@@ -3948,35 +4109,52 @@ rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t
data.tpval = tpval;
data.target_line = target_line;
data.n = 0;
+ data.r = GET_RACTOR();
iseq_add_local_tracepoint_i(iseq, (void *)&data);
- if (0) rb_funcall(Qnil, rb_intern("puts"), 1, rb_iseq_disasm(iseq)); /* for debug */
+ if (0) fprintf(stderr, "Iseq disasm:\n:%s", RSTRING_PTR(rb_iseq_disasm(iseq))); /* for debug */
return data.n;
}
static int
-iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
+iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r)
{
int n = 0;
+ unsigned int num_hooks_left;
+ unsigned int pc;
+ const struct rb_iseq_constant_body *body;
+ rb_iseq_t *iseq_mut = (rb_iseq_t*)iseq;
+ rb_hook_list_t *hook_list;
+ VALUE *iseq_encoded;
+ ASSERT_vm_locking_with_barrier();
- if (iseq->aux.exec.local_hooks) {
- unsigned int pc;
- const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
+ hook_list = rb_iseq_local_hooks(iseq, r, false);
+
+ if (hook_list) {
rb_event_flag_t local_events = 0;
- rb_hook_list_remove_tracepoint(iseq->aux.exec.local_hooks, tpval);
- local_events = iseq->aux.exec.local_hooks->events;
+ rb_event_flag_t prev_events = hook_list->events;
+ if (rb_hook_list_remove_local_tracepoint(hook_list, tpval)) {
+ RUBY_ASSERT(iseq->aux.exec.local_hooks_cnt > 0);
+ iseq_mut->aux.exec.local_hooks_cnt--;
+ local_events = hook_list->events; // remaining events for this ractor
+ num_hooks_left = rb_hook_list_count(hook_list);
+ if (local_events == 0 && prev_events != 0) {
+ st_delete(rb_ractor_targeted_hooks(r), (st_data_t*)&iseq, NULL);
+ rb_hook_list_free(hook_list);
+ }
- if (local_events == 0) {
- rb_hook_list_free(iseq->aux.exec.local_hooks);
- ((rb_iseq_t *)iseq)->aux.exec.local_hooks = NULL;
- }
+ if (iseq->aux.exec.local_hooks_cnt == num_hooks_left) {
+ body = ISEQ_BODY(iseq);
+ iseq_encoded = (VALUE *)body->iseq_encoded;
+ local_events = add_bmethod_events(local_events);
+ for (pc = 0; pc<body->iseq_size;) {
+ rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
+ pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events), false);
+ }
+ }
- local_events = add_bmethod_events(local_events);
- for (pc = 0; pc<body->iseq_size;) {
- rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
- pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events), false);
+ n++;
}
}
return n;
@@ -3985,22 +4163,25 @@ iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
struct trace_clear_local_events_struct {
VALUE tpval;
int n;
+ rb_ractor_t *r;
};
static void
iseq_remove_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
{
struct trace_clear_local_events_struct *data = (struct trace_clear_local_events_struct *)p;
- data->n += iseq_remove_local_tracepoint(iseq, data->tpval);
+ data->n += iseq_remove_local_tracepoint(iseq, data->tpval, data->r);
iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p);
}
int
-rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval)
+rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r)
{
struct trace_clear_local_events_struct data;
+ ASSERT_vm_locking_with_barrier();
data.tpval = tpval;
data.n = 0;
+ data.r = r;
iseq_remove_local_tracepoint_i(iseq, (void *)&data);
return data.n;
@@ -4018,11 +4199,14 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
return;
}
else {
+ // NOTE: this does not need VM barrier if it's a new ISEQ
unsigned int pc;
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
rb_event_flag_t enabled_events;
- rb_event_flag_t local_events = iseq->aux.exec.local_hooks ? iseq->aux.exec.local_hooks->events : 0;
+ rb_hook_list_t *local_hooks = rb_iseq_local_hooks(iseq, GET_RACTOR(), false);
+ rb_event_flag_t local_events = local_hooks ? local_hooks->events : 0;
((rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events;
enabled_events = add_bmethod_events(turnon_events | local_events);
@@ -4038,6 +4222,7 @@ void rb_vm_cc_general(const struct rb_callcache *cc);
static bool
clear_attr_cc(VALUE v)
{
+ ASSERT_vm_locking_with_barrier();
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;
@@ -4050,6 +4235,7 @@ clear_attr_cc(VALUE v)
static bool
clear_bf_cc(VALUE v)
{
+ ASSERT_vm_locking_with_barrier();
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;
@@ -4075,7 +4261,10 @@ clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
void
rb_clear_attr_ccs(void)
{
- rb_objspace_each_objects(clear_attr_ccs_i, NULL);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+ rb_objspace_each_objects(clear_attr_ccs_i, NULL);
+ }
}
static int
@@ -4094,6 +4283,7 @@ clear_bf_ccs_i(void *vstart, void *vend, size_t stride, void *data)
void
rb_clear_bf_ccs(void)
{
+ ASSERT_vm_locking_with_barrier();
rb_objspace_each_objects(clear_bf_ccs_i, NULL);
}
@@ -4123,7 +4313,10 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data)
void
rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
{
- rb_objspace_each_objects(trace_set_i, &turnon_events);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+ rb_objspace_each_objects(trace_set_i, &turnon_events);
+ }
}
VALUE
diff --git a/iseq.h b/iseq.h
index 1cecc6960d..b9bc03c23c 100644
--- a/iseq.h
+++ b/iseq.h
@@ -68,9 +68,11 @@ ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq)
static inline void
ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq)
{
- void *ptr = ISEQ_BODY(iseq)->variable.original_iseq;
- ISEQ_BODY(iseq)->variable.original_iseq = NULL;
- ruby_xfree(ptr);
+ VALUE *ptr = (VALUE *)ISEQ_BODY(iseq)->variable.original_iseq;
+ if (ptr) {
+ ISEQ_BODY(iseq)->variable.original_iseq = NULL;
+ SIZED_FREE_N(ptr, ISEQ_BODY(iseq)->iseq_size);
+ }
}
static inline VALUE *
@@ -129,7 +131,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;
@@ -175,7 +176,12 @@ ISEQ_COMPILE_DATA_CLEAR(rb_iseq_t *iseq)
static inline rb_iseq_t *
iseq_imemo_alloc(void)
{
- return IMEMO_NEW(rb_iseq_t, imemo_iseq, 0);
+ rb_iseq_t *iseq = SHAREABLE_IMEMO_NEW(rb_iseq_t, imemo_iseq, 0);
+
+ // Clear out the whole iseq except for the flags.
+ memset((char *)iseq + sizeof(VALUE), 0, sizeof(rb_iseq_t) - sizeof(VALUE));
+
+ return iseq;
}
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt);
@@ -185,9 +191,12 @@ const rb_iseq_t *rb_iseq_ibf_load_bytes(const char *cstr, size_t);
VALUE rb_iseq_ibf_load_extra_data(VALUE str);
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);
+int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval, rb_ractor_t *r);
const rb_iseq_t *rb_iseq_load_iseq(VALUE fname);
+const rb_iseq_t *rb_iseq_compile_iseq(VALUE str, VALUE fname);
int rb_iseq_opt_frozen_string_literal(void);
+rb_hook_list_t *rb_iseq_local_hooks(const rb_iseq_t *iseq, rb_ractor_t *r, bool create);
+
#if VM_INSN_INFO_TABLE_IMPL == 2
unsigned int *rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body);
diff --git a/jit.c b/jit.c
new file mode 100644
index 0000000000..9bd16eab84
--- /dev/null
+++ b/jit.c
@@ -0,0 +1,844 @@
+// Glue code shared between YJIT and ZJIT for use from Rust.
+// For FFI safety and bindgen compatibility reasons, certain types of C
+// functions require wrapping before they can be called from Rust. Those show
+// up here.
+//
+// Code specific to YJIT and ZJIT should go to yjit.c and zjit.c respectively.
+
+#include "internal.h"
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "builtin.h"
+#include "insns.inc"
+#include "insns_info.inc"
+#include "iseq.h"
+#include "internal/compile.h"
+#include "internal/gc.h"
+#include "vm_sync.h"
+#include "internal/fixnum.h"
+#include "internal/string.h"
+#include "internal/class.h"
+#include "internal/imemo.h"
+#include "ruby/internal/core/rtypeddata.h"
+#include "zjit.h"
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+
+enum jit_bindgen_constants {
+ // Field offsets for the RObject struct
+ ROBJECT_OFFSET_AS_HEAP_FIELDS = offsetof(struct RObject, as.heap.fields),
+ ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary),
+
+ // Field offset for prime classext's fields_obj from a class pointer
+ RCLASS_OFFSET_PRIME_FIELDS_OBJ = offsetof(struct RClass_and_rb_classext_t, classext.fields_obj),
+
+ // Field offset for fields_obj in T_DATA
+ TDATA_OFFSET_FIELDS_OBJ = offsetof(struct RTypedData, fields_obj),
+
+ // Field offsets for the RString struct
+ RUBY_OFFSET_RSTRING_LEN = offsetof(struct RString, len),
+
+ // Shape constant related to RBasic::flags. (See RBASIC_SET_SHAPE_ID())
+ RB_SHAPE_FLAG_SHIFT = SHAPE_FLAG_SHIFT,
+
+ // Field offsets for rb_execution_context_t
+ RUBY_OFFSET_EC_CFP = offsetof(rb_execution_context_t, cfp),
+ RUBY_OFFSET_EC_INTERRUPT_FLAG = offsetof(rb_execution_context_t, interrupt_flag),
+ RUBY_OFFSET_EC_INTERRUPT_MASK = offsetof(rb_execution_context_t, interrupt_mask),
+ RUBY_OFFSET_EC_THREAD_PTR = offsetof(rb_execution_context_t, thread_ptr),
+ RUBY_OFFSET_EC_RACTOR_ID = offsetof(rb_execution_context_t, ractor_id),
+};
+
+// Manually bound in rust since this is out-of-range of `int`,
+// so this can't be in a `enum`, and we avoid `static const`
+// to avoid allocating storage for the constant.
+const shape_id_t rb_invalid_shape_id = INVALID_SHAPE_ID;
+
+unsigned int
+rb_iseq_encoded_size(const rb_iseq_t *iseq)
+{
+ return iseq->body->iseq_size;
+}
+
+// Get the PC for a given index in an iseq
+VALUE *
+rb_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
+{
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
+ RUBY_ASSERT_ALWAYS(insn_idx < iseq->body->iseq_size);
+ VALUE *encoded = iseq->body->iseq_encoded;
+ VALUE *pc = &encoded[insn_idx];
+ return pc;
+}
+
+// Get the opcode given a program counter. Can return trace opcode variants.
+int
+rb_iseq_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
+{
+ // YJIT should only use iseqs after AST to bytecode compilation.
+ // (Certain non-default interpreter configurations never set ISEQ_TRANSLATED)
+ if (OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE) {
+ RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
+ }
+
+ const VALUE at_pc = *pc;
+ return rb_vm_insn_addr2opcode((const void *)at_pc);
+}
+
+// Get the bare opcode given a program counter. Always returns the base
+// instruction, stripping trace/zjit variants.
+int
+rb_iseq_bare_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
+{
+ if (OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE) {
+ RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
+ }
+
+ const VALUE at_pc = *pc;
+ return rb_vm_insn_addr2insn((const void *)at_pc);
+}
+
+unsigned long
+rb_RSTRING_LEN(VALUE str)
+{
+ return RSTRING_LEN(str);
+}
+
+char *
+rb_RSTRING_PTR(VALUE str)
+{
+ return RSTRING_PTR(str);
+}
+
+const char *
+rb_insn_name(VALUE insn)
+{
+ return insn_name(insn);
+}
+
+unsigned int
+rb_vm_ci_argc(const struct rb_callinfo *ci)
+{
+ return vm_ci_argc(ci);
+}
+
+ID
+rb_vm_ci_mid(const struct rb_callinfo *ci)
+{
+ return vm_ci_mid(ci);
+}
+
+unsigned int
+rb_vm_ci_flag(const struct rb_callinfo *ci)
+{
+ return vm_ci_flag(ci);
+}
+
+const struct rb_callinfo_kwarg *
+rb_vm_ci_kwarg(const struct rb_callinfo *ci)
+{
+ return vm_ci_kwarg(ci);
+}
+
+int
+rb_get_cikw_keyword_len(const struct rb_callinfo_kwarg *cikw)
+{
+ return cikw->keyword_len;
+}
+
+VALUE
+rb_get_cikw_keywords_idx(const struct rb_callinfo_kwarg *cikw, int idx)
+{
+ return cikw->keywords[idx];
+}
+
+rb_method_visibility_t
+rb_METHOD_ENTRY_VISI(const rb_callable_method_entry_t *me)
+{
+ return METHOD_ENTRY_VISI(me);
+}
+
+rb_method_type_t
+rb_get_cme_def_type(const rb_callable_method_entry_t *cme)
+{
+ if (UNDEFINED_METHOD_ENTRY_P(cme)) {
+ return VM_METHOD_TYPE_UNDEF;
+ }
+ else {
+ return cme->def->type;
+ }
+}
+
+ID
+rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.attr.id;
+}
+
+enum method_optimized_type
+rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.optimized.type;
+}
+
+unsigned int
+rb_get_cme_def_body_optimized_index(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.optimized.index;
+}
+
+rb_method_cfunc_t *
+rb_get_cme_def_body_cfunc(const rb_callable_method_entry_t *cme)
+{
+ return UNALIGNED_MEMBER_PTR(cme->def, body.cfunc);
+}
+
+uintptr_t
+rb_get_def_method_serial(const rb_method_definition_t *def)
+{
+ return def->method_serial;
+}
+
+ID
+rb_get_def_original_id(const rb_method_definition_t *def)
+{
+ return def->original_id;
+}
+
+VALUE
+rb_get_def_bmethod_proc(rb_method_definition_t *def)
+{
+ RUBY_ASSERT(def->type == VM_METHOD_TYPE_BMETHOD);
+ return def->body.bmethod.proc;
+}
+
+rb_proc_t *
+rb_jit_get_proc_ptr(VALUE procv)
+{
+ rb_proc_t *proc;
+ GetProcPtr(procv, proc);
+ return proc;
+}
+
+VALUE
+rb_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);
+}
+
+unsigned int
+rb_jit_iseq_builtin_attrs(const rb_iseq_t *iseq)
+{
+ return iseq->body->builtin_attrs;
+}
+
+int
+rb_get_mct_argc(const rb_method_cfunc_t *mct)
+{
+ return mct->argc;
+}
+
+void *
+rb_get_mct_func(const rb_method_cfunc_t *mct)
+{
+ return (void*)(uintptr_t)mct->func; // this field is defined as type VALUE (*func)(ANYARGS)
+}
+
+const rb_iseq_t *
+rb_get_def_iseq_ptr(rb_method_definition_t *def)
+{
+ return def_iseq_ptr(def);
+}
+
+const rb_iseq_t *
+rb_get_iseq_body_local_iseq(const rb_iseq_t *iseq)
+{
+ return iseq->body->local_iseq;
+}
+
+const rb_iseq_t *
+rb_get_iseq_body_parent_iseq(const rb_iseq_t *iseq)
+{
+ return iseq->body->parent_iseq;
+}
+
+unsigned int
+rb_get_iseq_body_local_table_size(const rb_iseq_t *iseq)
+{
+ return iseq->body->local_table_size;
+}
+
+VALUE *
+rb_get_iseq_body_iseq_encoded(const rb_iseq_t *iseq)
+{
+ return iseq->body->iseq_encoded;
+}
+
+unsigned
+rb_get_iseq_body_stack_max(const rb_iseq_t *iseq)
+{
+ return iseq->body->stack_max;
+}
+
+enum rb_iseq_type
+rb_get_iseq_body_type(const rb_iseq_t *iseq)
+{
+ return iseq->body->type;
+}
+
+bool
+rb_get_iseq_flags_has_lead(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_lead;
+}
+
+bool
+rb_get_iseq_flags_has_opt(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_opt;
+}
+
+bool
+rb_get_iseq_flags_has_kw(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_kw;
+}
+
+bool
+rb_get_iseq_flags_has_post(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_post;
+}
+
+bool
+rb_get_iseq_flags_has_kwrest(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_kwrest;
+}
+
+bool
+rb_get_iseq_flags_anon_kwrest(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.anon_kwrest;
+}
+
+bool
+rb_get_iseq_flags_has_rest(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_rest;
+}
+
+bool
+rb_get_iseq_flags_ruby2_keywords(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.ruby2_keywords;
+}
+
+bool
+rb_get_iseq_flags_has_block(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_block;
+}
+
+bool
+rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.ambiguous_param0;
+}
+
+bool
+rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.accepts_no_kwarg;
+}
+
+bool
+rb_get_iseq_flags_forwardable(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.forwardable;
+}
+
+// This is defined only as a named struct inside rb_iseq_constant_body.
+// By giving it a separate typedef, we make it nameable by rust-bindgen.
+// Bindgen's temp/anon name isn't guaranteed stable.
+typedef struct rb_iseq_param_keyword rb_iseq_param_keyword_struct;
+
+const rb_iseq_param_keyword_struct *
+rb_get_iseq_body_param_keyword(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.keyword;
+}
+
+unsigned
+rb_get_iseq_body_param_size(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.size;
+}
+
+int
+rb_get_iseq_body_param_lead_num(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.lead_num;
+}
+
+int
+rb_get_iseq_body_param_opt_num(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.opt_num;
+}
+
+const VALUE *
+rb_get_iseq_body_param_opt_table(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.opt_table;
+}
+
+struct rb_control_frame_struct *
+rb_get_ec_cfp(const rb_execution_context_t *ec)
+{
+ return ec->cfp;
+}
+
+const rb_iseq_t *
+rb_get_cfp_iseq(struct rb_control_frame_struct *cfp)
+{
+ return CFP_ISEQ(cfp);
+}
+
+VALUE *
+rb_get_cfp_pc(struct rb_control_frame_struct *cfp)
+{
+ return (VALUE*)cfp->pc;
+}
+
+VALUE *
+rb_get_cfp_sp(struct rb_control_frame_struct *cfp)
+{
+ return cfp->sp;
+}
+
+VALUE
+rb_get_cfp_self(struct rb_control_frame_struct *cfp)
+{
+ return cfp->self;
+}
+
+VALUE *
+rb_get_cfp_ep(struct rb_control_frame_struct *cfp)
+{
+ return (VALUE*)cfp->ep;
+}
+
+const VALUE *
+rb_get_cfp_ep_level(struct rb_control_frame_struct *cfp, uint32_t lv)
+{
+ uint32_t i;
+ const VALUE *ep = (VALUE*)cfp->ep;
+ for (i = 0; i < lv; i++) {
+ ep = VM_ENV_PREV_EP(ep);
+ }
+ return ep;
+}
+
+VALUE
+rb_yarv_class_of(VALUE obj)
+{
+ return rb_class_of(obj);
+}
+
+// The FL_TEST() macro
+VALUE
+rb_FL_TEST(VALUE obj, VALUE flags)
+{
+ return RB_FL_TEST(obj, flags);
+}
+
+// The FL_TEST_RAW() macro, normally an internal implementation detail
+VALUE
+rb_FL_TEST_RAW(VALUE obj, VALUE flags)
+{
+ return FL_TEST_RAW(obj, flags);
+}
+
+// The RB_TYPE_P macro
+bool
+rb_RB_TYPE_P(VALUE obj, enum ruby_value_type t)
+{
+ return RB_TYPE_P(obj, t);
+}
+
+long
+rb_RSTRUCT_LEN(VALUE st)
+{
+ return RSTRUCT_LEN(st);
+}
+
+const struct rb_callinfo *
+rb_get_call_data_ci(const struct rb_call_data *cd)
+{
+ return cd->ci;
+}
+
+bool
+rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop, uint32_t klass)
+{
+ return BASIC_OP_UNREDEFINED_P(bop, klass);
+}
+
+VALUE
+rb_RCLASS_ORIGIN(VALUE c)
+{
+ return RCLASS_ORIGIN(c);
+}
+
+// For debug builds
+void
+rb_assert_iseq_handle(VALUE handle)
+{
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
+}
+
+// Assert that we have the VM lock. Relevant mostly for multi ractor situations.
+// The GC takes the lock before calling us, and this asserts that it indeed happens.
+void
+rb_assert_holding_vm_lock(void)
+{
+ ASSERT_vm_locking();
+}
+
+int
+rb_IMEMO_TYPE_P(VALUE imemo, enum imemo_type imemo_type)
+{
+ return IMEMO_TYPE_P(imemo, imemo_type);
+}
+
+void
+rb_assert_cme_handle(VALUE handle)
+{
+ RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle));
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment));
+}
+
+// YJIT and ZJIT need this function to never allocate and never raise
+VALUE
+rb_yarv_ary_entry_internal(VALUE ary, long offset)
+{
+ return rb_ary_entry_internal(ary, offset);
+}
+
+long
+rb_jit_array_len(VALUE a)
+{
+ return rb_array_len(a);
+}
+
+void
+rb_set_cfp_pc(struct rb_control_frame_struct *cfp, const VALUE *pc)
+{
+ cfp->pc = pc;
+}
+
+void
+rb_set_cfp_sp(struct rb_control_frame_struct *cfp, VALUE *sp)
+{
+ cfp->sp = sp;
+}
+
+bool
+rb_jit_shape_complex_p(shape_id_t shape_id)
+{
+ return rb_shape_complex_p(shape_id);
+}
+
+bool
+rb_jit_multi_ractor_p(void)
+{
+ return rb_multi_ractor_p();
+}
+
+bool
+rb_jit_class_fields_embedded_p(VALUE klass)
+{
+ VALUE fields_obj = RCLASS_EXT_PRIME(klass)->fields_obj;
+ return !fields_obj || !FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP);
+}
+
+bool
+rb_jit_data_fields_embedded_p(VALUE obj)
+{
+ VALUE fields_obj = RTYPEDDATA(obj)->fields_obj;
+ return !fields_obj || !FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP);
+}
+
+// Acquire the VM lock and then signal all other Ruby threads (ractors) to
+// contend for the VM lock, putting them to sleep. ZJIT and YJIT use this to
+// evict threads running inside generated code so among other things, it can
+// safely change memory protection of regions housing generated code.
+void
+rb_jit_vm_lock_then_barrier(unsigned int *recursive_lock_level, const char *file, int line)
+{
+ rb_vm_lock_enter(recursive_lock_level, file, line);
+ rb_vm_barrier();
+}
+
+// Release the VM lock. The lock level must point to the same integer used to
+// acquire the lock.
+void
+rb_jit_vm_unlock(unsigned int *recursive_lock_level, const char *file, int line)
+{
+ rb_vm_lock_leave(recursive_lock_level, file, line);
+}
+
+void
+rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
+{
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
+ iseq->body->jit_entry = NULL;
+ iseq->body->jit_exception = NULL;
+ // Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
+ // we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
+ iseq->body->jit_entry_calls = 0;
+ iseq->body->jit_exception_calls = 0;
+}
+
+// Callback data for rb_jit_for_each_iseq
+struct iseq_callback_data {
+ rb_iseq_callback callback;
+ void *data;
+};
+
+// Heap-walking callback for rb_jit_for_each_iseq
+static int
+for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
+{
+ const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
+ VALUE v = (VALUE)vstart;
+ for (; v != (VALUE)vend; v += stride) {
+ void *ptr = rb_asan_poisoned_object_p(v);
+ rb_asan_unpoison_object(v, false);
+
+ if (rb_obj_is_iseq(v)) {
+ rb_iseq_t *iseq = (rb_iseq_t *)v;
+ callback_data->callback(iseq, callback_data->data);
+ }
+
+ if (ptr) {
+ rb_asan_poison_object(v);
+ }
+ }
+ return 0;
+}
+
+uint32_t
+rb_jit_get_page_size(void)
+{
+#if defined(_SC_PAGESIZE)
+ long page_size = sysconf(_SC_PAGESIZE);
+ if (page_size <= 0) rb_bug("jit: failed to get page size");
+
+ // 1 GiB limit. x86 CPUs with PDPE1GB can do this and anything larger is unexpected.
+ // Though our design sort of assume we have fine grained control over memory protection
+ // which require small page sizes.
+ if (page_size > 0x40000000l) rb_bug("jit page size too large");
+
+ return (uint32_t)page_size;
+#else
+#error "JIT supports POSIX only for now"
+#endif
+}
+
+#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.
+uint8_t *
+rb_jit_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 *)(uintptr_t)&rb_jit_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) {
+ ruby_annotate_mmap(mem_block, mem_size, "Ruby:rb_jit_reserve_addr_space");
+ break;
+ }
+
+ // -4MiB. Downwards to probe away from the heap. (On x86/A64 Linux
+ // main_code_addr < heap_addr, and in case we are in a shared
+ // library mapped higher than the heap, downwards is still better
+ // since it's towards the end of the heap rather than the stack.)
+ 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 *)rb_jit_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
+ );
+
+ if (mem_block != MAP_FAILED) {
+ ruby_annotate_mmap(mem_block, mem_size, "Ruby:rb_jit_reserve_addr_space:fallback");
+ }
+ }
+
+ // Check that the memory mapping was successful
+ if (mem_block == MAP_FAILED) {
+ perror("ruby: jit: 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
+}
+
+// Walk all ISEQs in the heap and invoke the callback - shared between YJIT and ZJIT
+void
+rb_jit_for_each_iseq(rb_iseq_callback callback, void *data)
+{
+ struct iseq_callback_data callback_data = { .callback = callback, .data = data };
+ rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
+}
+
+bool
+rb_jit_mark_writable(void *mem_block, uint32_t mem_size)
+{
+ return mprotect(mem_block, mem_size, PROT_READ | PROT_WRITE) == 0;
+}
+
+void
+rb_jit_mark_executable(void *mem_block, uint32_t mem_size)
+{
+ // Do not call mprotect when mem_size is zero. Some platforms may return
+ // an error for it. https://github.com/Shopify/ruby/issues/450
+ if (mem_size == 0) {
+ return;
+ }
+ 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));
+ }
+}
+
+// Free the specified memory block.
+bool
+rb_jit_mark_unused(void *mem_block, uint32_t mem_size)
+{
+ // On Linux, you need to use madvise MADV_DONTNEED to free memory.
+ // We might not need to call this on macOS, but it's not really documented.
+ // We generally prefer to do the same thing on both to ease testing too.
+ madvise(mem_block, mem_size, MADV_DONTNEED);
+
+ // On macOS, mprotect PROT_NONE seems to reduce RSS.
+ // We also call this on Linux to avoid executing unused pages.
+ return mprotect(mem_block, mem_size, PROT_NONE) == 0;
+}
+
+// Invalidate icache for arm64.
+// `start` is inclusive and `end` is exclusive.
+void
+rb_jit_icache_invalidate(void *start, void *end)
+{
+ // Clear/invalidate the instruction cache. Compiles to nothing on x86_64
+ // but required on ARM before running freshly written code.
+ // On Darwin it's the same as calling sys_icache_invalidate().
+#ifdef __GNUC__
+ __builtin___clear_cache(start, end);
+#elif defined(__aarch64__)
+#error No instruction cache clear available with this compiler on Aarch64!
+#endif
+}
+
+VALUE
+rb_jit_fix_mod_fix(VALUE recv, VALUE obj)
+{
+ return rb_fix_mod_fix(recv, obj);
+}
+
+VALUE
+rb_jit_fix_div_fix(VALUE recv, VALUE obj)
+{
+ return rb_fix_div_fix(recv, obj);
+}
+
+// YJIT/ZJIT need this function to never allocate and never raise
+VALUE
+rb_yarv_str_eql_internal(VALUE str1, VALUE str2)
+{
+ // We wrap this since it's static inline
+ return rb_str_eql_internal(str1, str2);
+}
+
+void rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint);
+
+attr_index_t
+rb_jit_shape_capacity(shape_id_t shape_id)
+{
+ return RSHAPE_CAPACITY(shape_id);
+}
diff --git a/jit/Cargo.toml b/jit/Cargo.toml
new file mode 100644
index 0000000000..530fe3674b
--- /dev/null
+++ b/jit/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "jit"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
diff --git a/jit/src/lib.rs b/jit/src/lib.rs
new file mode 100644
index 0000000000..c0f043131e
--- /dev/null
+++ b/jit/src/lib.rs
@@ -0,0 +1,38 @@
+//! Shared code between YJIT and ZJIT.
+#![warn(unsafe_op_in_unsafe_fn)] // Adopt 2024 edition default when targeting 2021 editions
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::alloc::{GlobalAlloc, Layout, System};
+
+#[global_allocator]
+pub static GLOBAL_ALLOCATOR: StatsAlloc = StatsAlloc { alloc_size: AtomicUsize::new(0) };
+
+pub struct StatsAlloc {
+ pub alloc_size: AtomicUsize,
+}
+
+unsafe impl GlobalAlloc for StatsAlloc {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ self.alloc_size.fetch_add(layout.size(), Ordering::SeqCst);
+ unsafe { System.alloc(layout) }
+ }
+
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ self.alloc_size.fetch_sub(layout.size(), Ordering::SeqCst);
+ unsafe { System.dealloc(ptr, layout) }
+ }
+
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ self.alloc_size.fetch_add(layout.size(), Ordering::SeqCst);
+ unsafe { System.alloc_zeroed(layout) }
+ }
+
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if new_size > layout.size() {
+ self.alloc_size.fetch_add(new_size - layout.size(), Ordering::SeqCst);
+ } else if new_size < layout.size() {
+ self.alloc_size.fetch_sub(layout.size() - new_size, Ordering::SeqCst);
+ }
+ unsafe { System.realloc(ptr, layout, new_size) }
+ }
+}
diff --git a/jit_hook.rb b/jit_hook.rb
new file mode 100644
index 0000000000..c605d6e26d
--- /dev/null
+++ b/jit_hook.rb
@@ -0,0 +1,12 @@
+class Module
+ # Internal helper for built-in initializations to define methods only when JIT is enabled.
+ # This method is removed in jit_undef.rb.
+ private def with_jit(&block) # :nodoc:
+ if defined?(RubyVM::ZJIT)
+ RubyVM::ZJIT.send(:add_jit_hook, block)
+ end
+ if defined?(RubyVM::YJIT)
+ RubyVM::YJIT.send(:add_jit_hook, block)
+ end
+ end
+end
diff --git a/jit_undef.rb b/jit_undef.rb
new file mode 100644
index 0000000000..0e855fe7a2
--- /dev/null
+++ b/jit_undef.rb
@@ -0,0 +1,4 @@
+# Remove the helper defined in jit_hook.rb
+class Module
+ undef :with_jit
+end
diff --git a/kernel.rb b/kernel.rb
index 554de49977..dc5cea1515 100644
--- a/kernel.rb
+++ b/kernel.rb
@@ -17,7 +17,7 @@ module Kernel
#
def class
Primitive.attr! :leaf
- Primitive.cexpr! 'rb_obj_class(self)'
+ Primitive.cexpr! 'rb_obj_class_must(self)'
end
#
@@ -141,6 +141,7 @@ module Kernel
# loop do
# print "Input: "
# line = gets
+ # # break if q, Q is entered or EOF signal (Ctrl-D on Unix, Ctrl-Z on windows) is sent
# break if !line or line =~ /^q/i
# # ...
# end
@@ -291,13 +292,3 @@ module Kernel
end
end
end
-
-class Module
- # Internal helper for built-in initializations to define methods only when YJIT is enabled.
- # This method is removed in yjit_hook.rb.
- private def with_yjit(&block) # :nodoc:
- if defined?(RubyVM::YJIT)
- RubyVM::YJIT.send(:add_yjit_hook, block)
- end
- end
-end
diff --git a/lib/English.gemspec b/lib/English.gemspec
index 5f4eb420c2..9c09555ca1 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.8.1"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -15,8 +15,13 @@ 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)/}) }
+ excludes = %W[
+ :^/test :^/spec :^/feature :^/bin
+ :^/Rakefile :^/Gemfile\* :^/.git*
+ :^/#{File.basename(__FILE__)}
+ ]
+ spec.files = IO.popen(%W[git ls-files -z --] + excludes, err: IO::NULL) do |f|
+ f.readlines("\x0", chomp: true)
end
spec.require_paths = ["lib"]
end
diff --git a/lib/English.rb b/lib/English.rb
index 03fe721991..bf7896dcd6 100644
--- a/lib/English.rb
+++ b/lib/English.rb
@@ -9,7 +9,7 @@
# "waterbuffalo" =~ /buff/
# print $', $$, "\n"
#
-# With English:
+# With 'English':
#
# require "English"
#
@@ -20,30 +20,30 @@
# Below is a full list of descriptive aliases and their associated global
# variable:
#
-# $ERROR_INFO:: $!
-# $ERROR_POSITION:: $@
-# $FS:: $;
-# $FIELD_SEPARATOR:: $;
-# $OFS:: $,
-# $OUTPUT_FIELD_SEPARATOR:: $,
-# $RS:: $/
-# $INPUT_RECORD_SEPARATOR:: $/
-# $ORS:: $\
-# $OUTPUT_RECORD_SEPARATOR:: $\
-# $INPUT_LINE_NUMBER:: $.
-# $NR:: $.
-# $LAST_READ_LINE:: $_
-# $DEFAULT_OUTPUT:: $>
-# $DEFAULT_INPUT:: $<
-# $PID:: $$
-# $PROCESS_ID:: $$
-# $CHILD_STATUS:: $?
-# $LAST_MATCH_INFO:: $~
-# $ARGV:: $*
-# $MATCH:: $&
-# $PREMATCH:: $`
-# $POSTMATCH:: $'
-# $LAST_PAREN_MATCH:: $+
+# <tt>$ERROR_INFO</tt>:: <tt>$!</tt>
+# <tt>$ERROR_POSITION</tt>:: <tt>$@</tt>
+# <tt>$FS</tt>:: <tt>$;</tt>
+# <tt>$FIELD_SEPARATOR</tt>:: <tt>$;</tt>
+# <tt>$OFS</tt>:: <tt>$,</tt>
+# <tt>$OUTPUT_FIELD_SEPARATOR</tt>:: <tt>$,</tt>
+# <tt>$RS</tt>:: <tt>$/</tt>
+# <tt>$INPUT_RECORD_SEPARATOR</tt>:: <tt>$/</tt>
+# <tt>$ORS</tt>:: <tt>$\</tt>
+# <tt>$OUTPUT_RECORD_SEPARATOR</tt>:: <tt>$\</tt>
+# <tt>$NR</tt>:: <tt>$.</tt>
+# <tt>$INPUT_LINE_NUMBER</tt>:: <tt>$.</tt>
+# <tt>$LAST_READ_LINE</tt>:: <tt>$_</tt>
+# <tt>$DEFAULT_OUTPUT</tt>:: <tt>$></tt>
+# <tt>$DEFAULT_INPUT</tt>:: <tt>$<</tt>
+# <tt>$PID</tt>:: <tt>$$</tt>
+# <tt>$PROCESS_ID</tt>:: <tt>$$</tt>
+# <tt>$CHILD_STATUS</tt>:: <tt>$?</tt>
+# <tt>$LAST_MATCH_INFO</tt>:: <tt>$~</tt>
+# <tt>$ARGV</tt>:: <tt>$*</tt>
+# <tt>$MATCH</tt>:: <tt>$&</tt>
+# <tt>$PREMATCH</tt>:: <tt>$`</tt>
+# <tt>$POSTMATCH</tt>:: <tt>$'</tt>
+# <tt>$LAST_PAREN_MATCH</tt>:: <tt>$+</tt>
#
module English end if false
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb
index 4e96c555d3..a287c49a34 100644
--- a/lib/bundled_gems.rb
+++ b/lib/bundled_gems.rb
@@ -1,13 +1,12 @@
# -*- frozen-string-literal: true -*-
+module Gem # :nodoc:
+ # TODO: the nodoc above is a workaround for RDoc's Prism parser handling stopdoc differently, we may want to use
+ # stopdoc/startdoc pair like before
+end
+
module Gem::BUNDLED_GEMS # :nodoc:
SINCE = {
- "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",
@@ -21,16 +20,17 @@ module Gem::BUNDLED_GEMS # :nodoc:
"resolv-replace" => "3.4.0",
"rinda" => "3.4.0",
"syslog" => "3.4.0",
- "ostruct" => "3.5.0",
- "pstore" => "3.5.0",
- "rdoc" => "3.5.0",
- "win32ole" => "3.5.0",
- "fiddle" => "3.5.0",
- "logger" => "3.5.0",
- "benchmark" => "3.5.0",
- "irb" => "3.5.0",
- "reline" => "3.5.0",
- # "readline" => "3.5.0", # This is wrapper for reline. We don't warn for this.
+ "ostruct" => "4.0.0",
+ "pstore" => "4.0.0",
+ "rdoc" => "4.0.0",
+ "win32ole" => "4.0.0",
+ "fiddle" => "4.0.0",
+ "logger" => "4.0.0",
+ "benchmark" => "4.0.0",
+ "irb" => "4.0.0",
+ "reline" => "4.0.0",
+ # "readline" => "4.0.0", # This is wrapper for reline. We don't warn for this.
+ "tsort" => "4.1.0",
}.freeze
EXACT = {
@@ -55,12 +55,7 @@ module Gem::BUNDLED_GEMS # :nodoc:
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)
- uplevel = ::Gem::BUNDLED_GEMS.uplevel
- if uplevel > 0
- Kernel.warn message, uplevel: uplevel
- else
- Kernel.warn message
- end
+ Kernel.warn message, uplevel: ::Gem::BUNDLED_GEMS.uplevel
end
kernel_class.send(:no_warning_require, name)
end
@@ -92,11 +87,10 @@ module Gem::BUNDLED_GEMS # :nodoc:
uplevel += 1
# Don't show script name when bundle exec and call ruby script directly.
if cl.path.end_with?("bundle")
- frame_count = 0
- break
+ return
end
end
- require_found ? 1 : frame_count - 1
+ require_found ? 1 : (frame_count - 1).nonzero?
end
def self.warning?(name, specs: nil)
@@ -111,11 +105,14 @@ module Gem::BUNDLED_GEMS # :nodoc:
# and `require "syslog"` to `require "#{ARCHDIR}/syslog.so"`.
feature.delete_prefix!(ARCHDIR)
feature.delete_prefix!(LIBDIR)
- segments = feature.split("/")
+ # 1. A segment for the EXACT mapping and SINCE check
+ # 2. A segment for the SINCE check for dashed names
+ # 3. A segment to check if there's a subfeature
+ segments = feature.split("/", 3)
name = segments.shift
name = EXACT[name] || name
if !SINCE[name]
- name = [name, segments.shift].join("-")
+ name = "#{name}-#{segments.shift}"
return unless SINCE[name]
end
segments.any?
@@ -125,29 +122,47 @@ module Gem::BUNDLED_GEMS # :nodoc:
false
end
+ if suppress_list = Thread.current[:__bundled_gems_warning_suppression]
+ return if suppress_list.include?(name) || suppress_list.include?(feature)
+ end
+
return if specs.include?(name)
+ # Don't warn if a hyphenated gem provides this feature
+ # (e.g., benchmark-ips provides benchmark/ips, benchmark/timing, etc.)
+ if subfeature
+ prefix = feature.split("/").first + "-"
+ return if specs.any? { |spec, _| spec.start_with?(prefix) }
+
+ # Don't warn if the feature is found outside the standard library
+ # (e.g., benchmark-ips's lib dir is on $LOAD_PATH but not in specs)
+ resolved = $LOAD_PATH.resolve_feature_path(feature) rescue nil
+ if resolved && !resolved[1].start_with?(LIBDIR, ARCHDIR)
+ return
+ end
+ end
+
return if WARNED[name]
WARNED[name] = true
- level = RUBY_VERSION < SINCE[name] ? "warning" : "error"
+ level = RUBY_VERSION < SINCE[name] ? :warning : :error
if subfeature
"#{feature} is found in #{name}, which"
else
- "#{feature} #{level == "warning" ? "was loaded" : "used to be loaded"} from the standard library, but"
+ "#{feature} #{level == :warning ? "was loaded" : "used to be loaded"} from the standard library, but"
end + build_message(name, level)
end
def self.build_message(name, level)
- msg = if level == "warning"
+ msg = if level == :warning
" will no longer be part of the default gems starting from Ruby #{SINCE[name]}"
else
" is not part of the default gems since Ruby #{SINCE[name]}."
end
if defined?(Bundler)
- motivation = level == "warning" ? "silence this warning" : "fix this error"
+ motivation = level == :warning ? "silence this warning" : "fix this error"
msg += "\nYou can add #{name} to your Gemfile or gemspec to #{motivation}."
# We detect the gem name from caller_locations. First we walk until we find `require`
@@ -197,17 +212,31 @@ module Gem::BUNDLED_GEMS # :nodoc:
end
def self.force_activate(gem)
+ require "bundler"
Bundler.reset!
+ # Build and activate a temporary definition containing the original gems + the requested gem
builder = Bundler::Dsl.new
- if Bundler.definition.gemfiles.empty? # bundler/inline
- Bundler.definition.locked_gems.specs.each{|spec| builder.gem spec.name, spec.version.to_s }
+
+ lockfile = nil
+ if Bundler::SharedHelpers.in_bundle? && Bundler.definition.gemfiles.size > 0
+ Bundler.definition.gemfiles.each {|gemfile| builder.eval_gemfile(gemfile) }
+ lockfile = begin
+ Bundler.default_lockfile
+ rescue Bundler::GemfileNotFound
+ nil
+ end
else
- Bundler.definition.gemfiles.each{|gemfile| builder.eval_gemfile(gemfile) }
+ # Fake BUNDLE_GEMFILE and BUNDLE_LOCKFILE to let checks pass
+ orig_gemfile = ENV["BUNDLE_GEMFILE"]
+ orig_lockfile = ENV["BUNDLE_LOCKFILE"]
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock"
end
+
builder.gem gem
- definition = builder.to_definition(nil, true)
+ definition = builder.to_definition(lockfile, nil)
definition.validate_runtime!
begin
@@ -223,6 +252,8 @@ module Gem::BUNDLED_GEMS # :nodoc:
rescue Bundler::GemNotFound
warn "Failed to activate #{gem}, please install it with 'gem install #{gem}'"
ensure
+ ENV['BUNDLE_GEMFILE'] = orig_gemfile if orig_gemfile
+ ENV['BUNDLE_LOCKFILE'] = orig_lockfile if orig_lockfile
Bundler.ui = orig_ui
Bundler::Definition.no_lock = orig_no_lock
end
@@ -237,7 +268,7 @@ class LoadError
name = path.tr("/", "-")
if !defined?(Bundler) && Gem::BUNDLED_GEMS::SINCE[name] && !Gem::BUNDLED_GEMS::WARNED[name]
- warn name + Gem::BUNDLED_GEMS.build_message(name, "error"), uplevel: Gem::BUNDLED_GEMS.uplevel
+ warn name + Gem::BUNDLED_GEMS.build_message(name, :error), uplevel: Gem::BUNDLED_GEMS.uplevel
end
super
end
diff --git a/lib/bundler.rb b/lib/bundler.rb
index eea3b0cf17..12dde90fc5 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
+require_relative "bundler/rubygems_ext"
require_relative "bundler/vendored_fileutils"
-require "pathname"
+autoload :Pathname, "pathname" unless defined?(Pathname)
require "rbconfig"
require_relative "bundler/errors"
require_relative "bundler/environment_preserver"
require_relative "bundler/plugin"
-require_relative "bundler/rubygems_ext"
require_relative "bundler/rubygems_integration"
require_relative "bundler/version"
require_relative "bundler/current_ruby"
@@ -53,9 +53,7 @@ module Bundler
autoload :FeatureFlag, File.expand_path("bundler/feature_flag", __dir__)
autoload :FREEBSD, File.expand_path("bundler/constants", __dir__)
autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__)
- autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__)
autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__)
- autoload :Graph, File.expand_path("bundler/graph", __dir__)
autoload :Index, File.expand_path("bundler/index", __dir__)
autoload :Injector, File.expand_path("bundler/injector", __dir__)
autoload :Installer, File.expand_path("bundler/installer", __dir__)
@@ -64,6 +62,7 @@ module Bundler
autoload :MatchRemoteMetadata, File.expand_path("bundler/match_remote_metadata", __dir__)
autoload :Materialization, File.expand_path("bundler/materialization", __dir__)
autoload :NULL, File.expand_path("bundler/constants", __dir__)
+ autoload :Override, File.expand_path("bundler/override", __dir__)
autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__)
autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__)
autoload :Resolver, File.expand_path("bundler/resolver", __dir__)
@@ -114,13 +113,13 @@ module Bundler
end
def configured_bundle_path
- @configured_bundle_path ||= settings.path.tap(&:validate!)
+ @configured_bundle_path ||= Bundler.settings.path.tap(&:validate!)
end
# Returns absolute location of where binstubs are installed to.
def bin_path
@bin_path ||= begin
- path = settings[:bin] || "bin"
+ path = Bundler.settings[:bin] || "bin"
path = Pathname.new(path).expand_path(root).expand_path
mkdir_p(path)
path
@@ -158,6 +157,7 @@ module Bundler
# Return if all groups are already loaded
return @setup if defined?(@setup) && @setup
+ configure_custom_gemfile
definition.validate_runtime!
SharedHelpers.print_major_deprecations!
@@ -174,14 +174,14 @@ module Bundler
self_manager.restart_with_locked_bundler_if_needed
end
- # Automatically install dependencies if Bundler.settings[:auto_install] exists.
+ # Automatically install dependencies if <tt>settings[:auto_install]</tt> 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]
+ return unless Bundler.settings[:auto_install]
begin
definition.specs
@@ -220,8 +220,7 @@ module Bundler
end
def environment
- SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", print_caller_location: true
- load
+ SharedHelpers.feature_removed! "Bundler.environment has been removed in favor of Bundler.load"
end
# Returns an instance of Bundler::Definition for given Gemfile and lockfile
@@ -239,10 +238,10 @@ module Bundler
end
def frozen_bundle?
- frozen = settings[:frozen]
+ frozen = Bundler.settings[:frozen]
return frozen unless frozen.nil?
- settings[:deployment]
+ Bundler.settings[:deployment]
end
def locked_gems
@@ -343,7 +342,7 @@ module Bundler
def app_cache(custom_path = nil)
path = custom_path || root
- Pathname.new(path).join(settings.app_cache_path)
+ Pathname.new(path).join(Bundler.settings.app_cache_path)
end
def tmp(name = Process.pid.to_s)
@@ -366,16 +365,11 @@ module Bundler
ORIGINAL_ENV.clone
end
- # @deprecated Use `unbundled_env` instead
def clean_env
- message =
- "`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)
- unbundled_env
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# @return [Hash] Environment with all bundler-related variables removed
@@ -393,16 +387,11 @@ module Bundler
with_env(original_env) { yield }
end
- # @deprecated Use `with_unbundled_env` instead
def with_clean_env
- message =
- "`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)
- with_env(unbundled_env) { yield }
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# Run block with all bundler-related variables removed
@@ -415,16 +404,11 @@ module Bundler
with_original_env { Kernel.system(*args) }
end
- # @deprecated Use `unbundled_system` instead
def clean_system(*args)
- message =
- "`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)
- with_env(unbundled_env) { Kernel.system(*args) }
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# Run subcommand in an environment with all bundler related variables removed
@@ -437,16 +421,11 @@ module Bundler
with_original_env { Kernel.exec(*args) }
end
- # @deprecated Use `unbundled_exec` instead
def clean_exec(*args)
- message =
- "`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)
- with_env(unbundled_env) { Kernel.exec(*args) }
+ Bundler::SharedHelpers.feature_removed!(removed_message)
end
# Run a `Kernel.exec` to a subcommand in an environment with all bundler related variables removed
@@ -455,10 +434,14 @@ module Bundler
end
def local_platform
- return Gem::Platform::RUBY if settings[:force_ruby_platform]
+ return Gem::Platform::RUBY if Bundler.settings[:force_ruby_platform]
Gem::Platform.local
end
+ def generic_local_platform
+ Gem::Platform.generic(local_platform)
+ end
+
def default_gemfile
SharedHelpers.default_gemfile
end
@@ -564,7 +547,7 @@ module Bundler
end
def feature_flag
- @feature_flag ||= FeatureFlag.new(VERSION)
+ @feature_flag ||= FeatureFlag.new(Bundler.settings[:simulate_version] || VERSION)
end
def reset!
@@ -580,7 +563,6 @@ module Bundler
def reset_paths!
@bin_path = nil
- @bundler_major_version = nil
@bundle_path = nil
@configure = nil
@configured_bundle_path = nil
@@ -606,6 +588,15 @@ module Bundler
Bundler.rubygems.clear_paths
end
+ def configure_custom_gemfile(custom_gemfile = nil)
+ custom_gemfile ||= Bundler.settings[:gemfile]
+
+ if custom_gemfile && !custom_gemfile.empty?
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile)
+ reset_settings_and_root!
+ end
+ end
+
def self_manager
@self_manager ||= begin
require_relative "bundler/self_manager"
diff --git a/lib/bundler/build_metadata.rb b/lib/bundler/build_metadata.rb
index 5d2a8b53bb..49d2518078 100644
--- a/lib/bundler/build_metadata.rb
+++ b/lib/bundler/build_metadata.rb
@@ -4,21 +4,26 @@ module Bundler
# Represents metadata from when the Bundler gem was built.
module BuildMetadata
# begin ivars
- @release = false
+ @built_at = nil
# end ivars
# A hash representation of the build metadata.
def self.to_h
{
- "Built At" => built_at,
+ "Timestamp" => timestamp,
"Git SHA" => git_commit_sha,
- "Released Version" => release?,
}
end
+ # A timestamp representing the date the bundler gem was built, or the
+ # current time if never built
+ def self.timestamp
+ @timestamp ||= @built_at || Time.now.utc.strftime("%Y-%m-%d").freeze
+ end
+
# A string representing the date the bundler gem was built.
def self.built_at
- @built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze
+ @built_at
end
# The SHA for the git commit the bundler gem was built from.
@@ -34,10 +39,5 @@ module Bundler
@git_commit_sha ||= "unknown"
end
-
- # Whether this is an official release build of Bundler.
- def self.release?
- @release
- end
end
end
diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec
index 88411f295d..49319e81b4 100644
--- a/lib/bundler/bundler.gemspec
+++ b/lib/bundler/bundler.gemspec
@@ -23,16 +23,16 @@ Gem::Specification.new do |s|
s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably"
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",
+ "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
+ "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/bundler/CHANGELOG.md",
"homepage_uri" => "https://bundler.io/",
- "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler",
+ "source_code_uri" => "https://github.com/ruby/rubygems/tree/master/bundler",
}
- s.required_ruby_version = ">= 3.1.0"
+ s.required_ruby_version = ">= 3.2.0"
# It should match the RubyGems version shipped with `required_ruby_version` above
- s.required_rubygems_version = ">= 3.3.3"
+ s.required_rubygems_version = ">= 3.4.1"
s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
diff --git a/lib/bundler/capistrano.rb b/lib/bundler/capistrano.rb
index 705840143f..6d2437d895 100644
--- a/lib/bundler/capistrano.rb
+++ b/lib/bundler/capistrano.rb
@@ -1,22 +1,4 @@
# frozen_string_literal: true
require_relative "shared_helpers"
-Bundler::SharedHelpers.major_deprecation 2,
- "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler"
-
-# Capistrano task for Bundler.
-#
-# Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and
-# Bundler will be activated after each new deployment.
-require_relative "deployment"
-require "capistrano/version"
-
-if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0")
- raise "For Capistrano 3.x integration, please use https://github.com/capistrano/bundler"
-end
-
-Capistrano::Configuration.instance(:must_exist).load do
- before "deploy:finalize_update", "bundle:install"
- Bundler::Deployment.define_task(self, :task, except: { no_release: true })
- set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" }
-end
+Bundler::SharedHelpers.feature_removed! "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler"
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb
index 356f4a48bc..ce05818bb0 100644
--- a/lib/bundler/checksum.rb
+++ b/lib/bundler/checksum.rb
@@ -205,6 +205,12 @@ module Bundler
@store[spec.lock_name].nil?
end
+ def empty?(spec)
+ return false unless spec.source.is_a?(Bundler::Source::Rubygems)
+
+ @store[spec.lock_name].empty?
+ end
+
def register(spec, checksum)
register_checksum(spec.lock_name, checksum)
end
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 91c31651da..9d8a68fff9 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -11,7 +11,7 @@ module Bundler
AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze
PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze
- EXTENSIONS = ["c", "rust"].freeze
+ EXTENSIONS = ["c", "rust", "go"].freeze
COMMAND_ALIASES = {
"check" => "c",
@@ -24,7 +24,7 @@ module Bundler
}.freeze
def self.start(*)
- check_deprecated_ext_option(ARGV) if ARGV.include?("--ext")
+ check_invalid_ext_option(ARGV) if ARGV.include?("--ext")
super
ensure
@@ -59,17 +59,29 @@ module Bundler
def initialize(*args)
super
- custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile]
- if custom_gemfile && !custom_gemfile.empty?
- Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile)
- Bundler.reset_settings_and_root!
+ current_cmd = args.last[:current_command].name
+
+ # `bundle config` manages stored settings, so avoid promoting settings
+ # like `gemfile` or `lockfile` to environment variables before it runs.
+ unless current_cmd == "config"
+ Bundler.configure_custom_gemfile(options[:gemfile])
+
+ # lock --lockfile works differently than install --lockfile
+ unless current_cmd == "lock"
+ custom_lockfile = options[:lockfile] || ENV["BUNDLE_LOCKFILE"] || Bundler.settings[:lockfile]
+ if custom_lockfile && !custom_lockfile.empty?
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", File.expand_path(custom_lockfile)
+ reset_settings = true
+ end
+ end
end
+ Bundler.reset_settings_and_root! if reset_settings
+
Bundler.auto_switch
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)
rescue UnknownArgumentError => e
raise InvalidOption, e.message
@@ -77,7 +89,7 @@ module Bundler
self.options ||= {}
unprinted_warnings = Bundler.ui.unprinted_warnings
Bundler.ui = UI::Shell.new(options)
- Bundler.ui.level = "debug" if options["verbose"]
+ Bundler.ui.level = "debug" if options[:verbose] || Bundler.settings[:verbose]
unprinted_warnings.each {|w| Bundler.ui.warn(w) }
end
@@ -92,7 +104,7 @@ module Bundler
primary_commands = ["install", "update", "cache", "exec", "config", "help"]
list = self.class.printable_commands(true)
- by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] }
+ by_name = list.group_by {|name, _message| name.match(/^bundler? (\w+)/)[1] }
utilities = by_name.keys.sort - primary_commands
primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first }
utilities.map! {|name| by_name[name].first }
@@ -107,7 +119,33 @@ module Bundler
shell.say
self.class.send(:class_options_help, shell)
end
- default_task(Bundler.feature_flag.default_cli_command)
+
+ desc "install_or_cli_help", "Deprecated alias of install", hide: true
+ def install_or_cli_help
+ Bundler.ui.warn <<~MSG
+ `bundle install_or_cli_help` is a deprecated alias of `bundle install`.
+ It might be called due to the 'default_cli_command' being set to 'install_or_cli_help',
+ if so fix that by running `bundle config set default_cli_command install --global`.
+ MSG
+ invoke_other_command("install")
+ end
+
+ def self.default_command(meth = nil)
+ return super if meth
+
+ unless Bundler.settings[:default_cli_command]
+ Bundler.ui.info <<~MSG
+ In a future version of Bundler, running `bundle` without argument will no longer run `bundle install`.
+ Instead, the `cli_help` command will be displayed. Please use `bundle install` explicitly for scripts like CI/CD.
+ You can use the future behavior now with `bundle config set default_cli_command cli_help --global`,
+ or you can continue to use the current behavior with `bundle config set default_cli_command install --global`.
+ This message will be removed after a default_cli_command value is set.
+
+ MSG
+ end
+
+ Bundler.settings[:default_cli_command] || "install"
+ end
class_option "no-color", type: :boolean, desc: "Disable colorization in output"
class_option "retry", type: :numeric, aliases: "-r", banner: "NUM",
@@ -117,6 +155,10 @@ module Bundler
def help(cli = nil)
cli = self.class.all_aliases[cli] if self.class.all_aliases[cli]
+ if Bundler.settings[:plugins] && Bundler::Plugin.command?(cli) && !self.class.all_commands.key?(cli)
+ return Bundler::Plugin.exec_command(cli, ["--help"])
+ end
+
case cli
when "gemfile" then command = "gemfile"
when nil then command = "bundle"
@@ -130,7 +172,7 @@ 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/.+})
+ if Bundler.which("man") && !man_path.match?(%r{^(?:file:/.+!|uri:classloader:)/META-INF/jruby.home/.+})
Kernel.exec("man", man_page)
else
puts File.read("#{man_path}/#{File.basename(man_page)}.ronn")
@@ -143,7 +185,7 @@ module Bundler
end
def self.handle_no_command_error(command, has_namespace = $thor_runner)
- if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command)
+ if Bundler.settings[:plugins] && Bundler::Plugin.command?(command)
return Bundler::Plugin.exec_command(command, ARGV[1..-1])
end
@@ -173,7 +215,7 @@ module Bundler
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 "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)"
def check
remembered_flag_deprecation("path")
@@ -187,12 +229,11 @@ 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 (removed)"
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)
+ raise InvalidOption, removed_message
end
require_relative "cli/remove"
@@ -210,42 +251,53 @@ 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 "binstubs", type: :string, lazy_default: "bin", banner: "Generate bin stubs for bundled gems to ./bin (removed)"
+ method_option "clean", type: :boolean, banner: "Run bundle clean automatically after install (removed)"
+ method_option "deployment", type: :boolean, banner: "Install using defaults tuned for deployment environments (removed)"
+ method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this install (removed)"
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 "lockfile", type: :string, banner: "Use the specified lockfile instead of the default."
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 "no-lock", type: :boolean, banner: "Don't create a lockfile."
+ method_option "force", type: :boolean, aliases: "--redownload", banner: "Force reinstalling every gem, even if already installed"
+ method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache (removed)."
+ method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)."
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 "shebang", type: :string, banner: "Specify a different shebang executable name than the default, usually 'ruby' (removed)"
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 "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 (removed)"
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 "target-rbconfig", type: :string, banner: "Path to rbconfig.rb for the deployment target platform"
- 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 "without", type: :array, banner: "Exclude gems that are part of the specified named group (removed)."
+ method_option "with", type: :array, banner: "Include gems that are part of the specified named group (removed)."
+ method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
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|
remembered_flag_deprecation(option)
end
print_remembered_flag_deprecation("--system", "path.system", "true") if ARGV.include?("--system")
- remembered_negative_flag_deprecation("no-deployment")
+ remembered_flag_deprecation("deployment", negative: true)
+
+ if ARGV.include?("--binstubs")
+ removed_message = "The --binstubs option has been removed in favor of `bundle binstubs --all`"
+ raise InvalidOption, removed_message
+ end
require_relative "cli/install"
+ options = self.options.dup
+ options["lockfile"] ||= ENV["BUNDLE_LOCKFILE"]
Bundler.settings.temporary(no_install: false) do
- Install.new(options.dup).run
+ Install.new(options).run
end
+ rescue GemfileNotFound => error
+ invoke_other_command("cli_help")
+ raise error # re-raise to show the error and get a failing exit status
end
map aliases_for("install")
@@ -263,7 +315,7 @@ module Bundler
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 "force", type: :boolean, aliases: "--redownload", banner: "Force reinstalling every gem, even if already installed"
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"
@@ -273,8 +325,8 @@ module Bundler
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 "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
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
Update.new(options, gems).run
@@ -287,12 +339,11 @@ module Bundler
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 "outdated", type: :boolean, banner: "Show verbose output including whether gems are outdated (removed)."
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)
+ removed_message = "the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`"
+ raise InvalidOption, removed_message
end
require_relative "cli/show"
Show.new(options, gem_name).run
@@ -302,6 +353,7 @@ module Bundler
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 "format", type: :string, banner: "format output ('json' is the only supported format)"
method_option "paths", type: :boolean, banner: "print the path to each gem in the bundle"
def list
require_relative "cli/list"
@@ -325,12 +377,14 @@ module Bundler
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 "path", type: :string, lazy_default: "bin", banner: "Binstub destination directory, `bin` by default (removed)"
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)
+ remembered_flag_deprecation("path", option_name: "bin")
+
require_relative "cli/binstubs"
Binstubs.new(options, gems).run
end
@@ -351,8 +405,10 @@ module Bundler
method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)"
method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
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 "optimistic", type: :boolean, banner: "Ignored (now default behavior)"
+ method_option "pessimistic", type: :boolean, banner: "Adds pessimistic declaration of version to gem"
method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem"
+ method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
def add(*gems)
require_relative "cli/add"
Add.new(options.dup, gems).run
@@ -383,6 +439,7 @@ module Bundler
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 "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
def outdated(*gems)
require_relative "cli/outdated"
Outdated.new(options, gems).run
@@ -396,15 +453,15 @@ module Bundler
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", type: :boolean, default: Bundler.settings[:cache_all], banner: "Include all sources (including path and git) (removed)."
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 "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache (removed)."
+ method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)."
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 "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install (removed)"
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
@@ -413,18 +470,19 @@ module Bundler
D
def cache
print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all")
+ print_remembered_flag_deprecation("--no-all", "cache_all", "false") if ARGV.include?("--no-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"
+ %w[frozen no-prune].each do |option|
+ remembered_flag_deprecation(option)
+ end
+
+ if flag_passed?("--path")
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
+ "and `bundle config path` to configure the path where your gems are installed, " \
+ "and stop using this flag"
+ raise InvalidOption, removed_message
end
require_relative "cli/cache"
@@ -434,7 +492,7 @@ 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, banner: "Passes all file descriptors to the new processes. Default is true, and setting it to false is deprecated"
+ method_option :keep_file_descriptors, type: :boolean, default: true, banner: "Passes all file descriptors to the new processes. Default is true, and setting it to false is not permitted (removed)."
method_option :gemfile, type: :string, required: false, banner: "Use the specified gemfile instead of Gemfile"
long_desc <<-D
Exec runs a command, providing it access to the gems in the bundle. While using
@@ -443,9 +501,8 @@ 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)
+ raise InvalidOption, removed_message
end
require_relative "cli/exec"
@@ -486,13 +543,13 @@ module Bundler
def version
cli_help = current_command.name == "cli_help"
if cli_help || ARGV.include?("version")
- build_info = " (#{BuildMetadata.built_at} commit #{BuildMetadata.git_commit_sha})"
+ build_info = " (#{BuildMetadata.timestamp} commit #{BuildMetadata.git_commit_sha})"
end
- if !cli_help && Bundler.feature_flag.print_only_version_number?
- Bundler.ui.info "#{Bundler::VERSION}#{build_info}"
+ if !cli_help
+ Bundler.ui.info "#{Bundler.verbose_version}#{build_info}"
else
- Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}"
+ Bundler.ui.info "Bundler version #{Bundler.verbose_version}#{build_info}"
end
end
@@ -512,41 +569,32 @@ module Bundler
end
end
- unless Bundler.feature_flag.bundler_3_mode?
- 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."
- 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"
- Viz.new(options.dup).run
- end
+ desc "viz [OPTIONS]", "Generates a visual dependency graph", hide: true
+ def viz
+ SharedHelpers.feature_removed! "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
end
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 :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], banner: "Generate a binary executable for your library."
+ method_option :coc, type: :boolean, banner: "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, lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, banner: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
+ method_option :ext, type: :string, banner: "Generate the boilerplate for C extension code.", enum: EXTENSIONS
+ method_option :git, type: :boolean, default: true, banner: "Initialize a git repo inside your library."
+ method_option :mit, type: :boolean, banner: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
+ method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true` (removed)."
+ method_option :changelog, type: :boolean, banner: "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 :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "", enum: %w[github gitlab circle], banner: "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], banner: "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 :bundle, type: :boolean, default: Bundler.settings["gem.bundle"], banner: "Automatically run `bundle install` after creation. Set a default with `bundle config set --global gem.bundle true`"
def gem(name)
require_relative "cli/gem"
+
+ raise InvalidOption, "--rubocop has been removed, use --linter=rubocop" if ARGV.include?("--rubocop")
+ raise InvalidOption, "--no-rubocop has been removed, use --no-linter" if ARGV.include?("--no-rubocop")
+
cmd_args = args + [self]
cmd_args.unshift(options)
@@ -557,7 +605,7 @@ module Bundler
File.expand_path("templates", __dir__)
end
- desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", hide: true
+ desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory"
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
@@ -573,12 +621,8 @@ module Bundler
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"
- def inject(name, version)
- SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command"
- require_relative "cli/inject"
- Inject.new(options.dup, name, version).run
+ def inject(*)
+ SharedHelpers.feature_removed! "The `inject` command has been replaced by the `add` command"
end
desc "lock", "Creates a lockfile without installing"
@@ -610,17 +654,8 @@ module Bundler
end
desc "doctor [OPTIONS]", "Checks the bundle for common problems"
- long_desc <<-D
- Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If
- 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."
- def doctor
- require_relative "cli/doctor"
- Doctor.new(options).run
- end
+ require_relative "cli/doctor"
+ subcommand("doctor", Doctor)
desc "issue", "Learn how to report an issue in Bundler"
def issue
@@ -641,7 +676,7 @@ module Bundler
end
end
- if Bundler.feature_flag.plugins?
+ if Bundler.settings[:plugins]
require_relative "cli/plugin"
desc "plugin", "Manage the bundler plugins"
subcommand "plugin", Plugin
@@ -675,18 +710,15 @@ module Bundler
end
end
- def self.check_deprecated_ext_option(arguments)
- # 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."
+ def self.check_invalid_ext_option(arguments)
+ # when invalid version of `--ext` is called
+ if invalid_ext_value?(arguments)
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
- arguments[arguments.index("--ext")] = "--ext=c"
+ raise InvalidOption, removed_message
end
end
- def self.deprecated_ext_value?(arguments)
+ def self.invalid_ext_value?(arguments)
index = arguments.index("--ext")
next_argument = arguments[index + 1]
@@ -694,15 +726,15 @@ module Bundler
# for example `bundle gem hello --ext c`
return false if EXTENSIONS.include?(next_argument)
- # deprecated call when --ext is called with no value in last position
+ # invalid call when --ext is called with no value in last position
# for example `bundle gem hello_gem --ext`
return true if next_argument.nil?
- # deprecated call when --ext is followed by other parameter
+ # invalid call when --ext is followed by other parameter
# for example `bundle gem --ext --no-ci hello_gem`
return true if next_argument.start_with?("-")
- # deprecated call when --ext is followed by gem name
+ # invalid call when --ext is followed by gem name
# for example `bundle gem --ext hello_gem`
return true if next_argument
@@ -716,6 +748,19 @@ module Bundler
config[:current_command]
end
+ def invoke_other_command(name)
+ _, _, config = @_initializer
+ original_command = config[:current_command]
+ command = self.class.all_commands[name]
+ config[:current_command] = command
+ send(name)
+ ensure
+ config[:current_command] = original_command
+ end
+
+ def current_command=(command)
+ end
+
def print_command
return unless Bundler.ui.debug?
cmd = current_command
@@ -729,7 +774,7 @@ module Bundler
end
command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip
command.reject!(&:empty?)
- Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}"
+ Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler.verbose_version}"
end
def warn_on_outdated_bundler
@@ -756,44 +801,30 @@ module Bundler
nil
end
- def remembered_negative_flag_deprecation(name)
- positive_name = name.gsub(/\Ano-/, "")
- option = current_command.options[positive_name]
- flag_name = "--no-" + option.switch_name.gsub(/\A--/, "")
-
- flag_deprecation(positive_name, flag_name, option)
- end
-
- def remembered_flag_deprecation(name)
+ def remembered_flag_deprecation(name, negative: false, option_name: nil)
option = current_command.options[name]
flag_name = option.switch_name
-
- flag_deprecation(name, flag_name, option)
- end
-
- def flag_deprecation(name, flag_name, option)
- name_index = ARGV.find {|arg| flag_name == arg.split("=")[0] }
- return unless name_index
+ flag_name = "--no-" + flag_name.gsub(/\A--/, "") if negative
+ return unless flag_passed?(flag_name)
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)
+ print_remembered_flag_deprecation(flag_name, option_name || name.tr("-", "_"), value)
end
def print_remembered_flag_deprecation(flag_name, option_name, option_value)
- message =
- "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
+ "remembered across bundler invocations, which bundler no longer does. " \
+ "Instead please use `bundle config set #{option_name} #{option_value}`, " \
+ "and stop using this flag"
+ raise InvalidOption, removed_message
+ end
+
+ def flag_passed?(name)
+ ARGV.any? {|arg| name == arg.split("=")[0] }
end
end
end
diff --git a/lib/bundler/cli/add.rb b/lib/bundler/cli/add.rb
index 12a681a816..20f76b59d1 100644
--- a/lib/bundler/cli/add.rb
+++ b/lib/bundler/cli/add.rb
@@ -14,6 +14,9 @@ module Bundler
def run
Bundler.ui.level = "warn" if options[:quiet]
+ Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
+ Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
+
validate_options!
inject_dependencies
perform_bundle_install unless options["skip-install"]
@@ -31,12 +34,22 @@ module Bundler
Injector.inject(dependencies,
conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified
- optimistic: options[:optimistic],
+ pessimistic: options[:pessimistic],
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 cannot specify `--git` and `--github` at the same time." if options["git"] && options["github"]
+
+ unless options["git"] || options["github"]
+ raise InvalidOption, "You cannot specify `--branch` unless `--git` or `--github` is specified." if options["branch"]
+
+ raise InvalidOption, "You cannot specify `--ref` unless `--git` or `--github` is specified." if options["ref"]
+ end
+
+ raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"]
+
+ raise InvalidOption, "You cannot specify `--strict` and `--pessimistic` at the same time." if options[:strict] && options[:pessimistic]
# raise error when no gems are specified
raise InvalidOption, "Please specify gems to add." if gems.empty?
diff --git a/lib/bundler/cli/cache.rb b/lib/bundler/cli/cache.rb
index 2e63a16ec3..59605df847 100644
--- a/lib/bundler/cli/cache.rb
+++ b/lib/bundler/cli/cache.rb
@@ -10,17 +10,12 @@ module Bundler
def run
Bundler.ui.level = "warn" if options[:quiet]
- Bundler.settings.set_command_option_if_given :path, options[:path]
Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"]
- setup_cache_all
install
- # 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.load.cache(custom_path)
+ Bundler.load.cache
end
end
@@ -33,11 +28,5 @@ module Bundler
options["no-cache"] = true
Bundler::CLI::Install.new(options).run
end
-
- def setup_cache_all
- all = options.fetch(:all, Bundler.feature_flag.cache_all? || nil)
-
- Bundler.settings.set_command_option_if_given :cache_all, all
- end
end
end
diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb
index 7ef6deb2cf..b44fbc3096 100644
--- a/lib/bundler/cli/common.rb
+++ b/lib/bundler/cli/common.rb
@@ -2,6 +2,12 @@
module Bundler
module CLI::Common
+ def self.validate_cooldown!(value)
+ return if value.nil?
+ return if value.is_a?(Integer) && value >= 0
+ raise InvalidOption, "Expected `--cooldown` to be a non-negative integer, got #{value.inspect}"
+ end
+
def self.output_post_install_messages(messages)
return if Bundler.settings["ignore_messages"]
messages.to_a.each do |name, msg|
@@ -94,11 +100,14 @@ module Bundler
end
def self.gem_not_found_message(missing_gem_name, alternatives)
- require_relative "../similarity_detector"
message = "Could not find gem '#{missing_gem_name}'."
alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a }
- suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name)
- message += "\nDid you mean #{suggestions}?" if suggestions
+ if alternate_names.include?(missing_gem_name.downcase)
+ message += "\nDid you mean '#{missing_gem_name.downcase}'?"
+ elsif defined?(DidYouMean::SpellChecker)
+ suggestions = DidYouMean::SpellChecker.new(dictionary: alternate_names).correct(missing_gem_name)
+ message += "\nDid you mean #{word_list(suggestions)}?" unless suggestions.empty?
+ end
message
end
@@ -130,9 +139,23 @@ module Bundler
def self.clean_after_install?
clean = Bundler.settings[:clean]
return clean unless clean.nil?
- clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil?
+ clean ||= Bundler.feature_flag.bundler_5_mode? && Bundler.settings[:path].nil?
clean &&= !Bundler.use_system_gems?
clean
end
+
+ def self.word_list(words)
+ if words.empty?
+ return ""
+ end
+
+ words = words.map {|word| "'#{word}'" }
+
+ if words.length == 1
+ return words[0]
+ end
+
+ [words[0..-2].join(", "), words[-1]].join(" or ")
+ end
end
end
diff --git a/lib/bundler/cli/config.rb b/lib/bundler/cli/config.rb
index 77b502fe60..976cda7484 100644
--- a/lib/bundler/cli/config.rb
+++ b/lib/bundler/cli/config.rb
@@ -26,8 +26,7 @@ module Bundler
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.feature_deprecated! message
Base.new(options, name, value, self).run
end
@@ -88,16 +87,21 @@ module Bundler
if value.nil?
warn_unused_scope "Ignoring --#{scope} since no value to set was given"
+ current_value = Bundler.settings[name]
if options[:parseable]
if value = Bundler.settings[name]
Bundler.ui.info("#{name}=#{value}")
end
- return
+ else
+ confirm(name)
end
- confirm(name)
- return
+ if current_value.nil?
+ exit 1
+ else
+ return
+ end
end
Bundler.ui.info(message) if message
diff --git a/lib/bundler/cli/console.rb b/lib/bundler/cli/console.rb
index f6389e8ea0..2d1a2ce458 100644
--- a/lib/bundler/cli/console.rb
+++ b/lib/bundler/cli/console.rb
@@ -21,6 +21,11 @@ module Bundler
get_constant(name)
rescue LoadError
if name == "irb"
+ if defined?(Gem::BUNDLED_GEMS) && Gem::BUNDLED_GEMS.respond_to?(:force_activate)
+ Gem::BUNDLED_GEMS.force_activate "irb"
+ require name
+ return get_constant(name)
+ end
Bundler.ui.error "#{name} is not available"
exit 1
else
diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb
index 1274630556..5fd6a73d91 100644
--- a/lib/bundler/cli/doctor.rb
+++ b/lib/bundler/cli/doctor.rb
@@ -1,161 +1,33 @@
# frozen_string_literal: true
-require "rbconfig"
-require "shellwords"
-
module Bundler
- class CLI::Doctor
- DARWIN_REGEX = /\s+(.+) \(compatibility /
- LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/
-
- attr_reader :options
-
- def initialize(options)
- @options = options
- end
-
- def otool_available?
- Bundler.which("otool")
- end
-
- def ldd_available?
- Bundler.which("ldd")
- end
-
- def dylibs_darwin(path)
- output = `/usr/bin/otool -L #{path.shellescape}`.chomp
- dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq
- # ignore @rpath and friends
- dylibs.reject {|dylib| dylib.start_with? "@" }
- end
-
- def dylibs_ldd(path)
- output = `/usr/bin/ldd #{path.shellescape}`.chomp
- output.split("\n").filter_map do |l|
- match = l.match(LDD_REGEX)
- next if match.nil?
- match.captures[0]
- end
- end
-
- def dylibs(path)
- case RbConfig::CONFIG["host_os"]
- when /darwin/
- return [] unless otool_available?
- dylibs_darwin(path)
- when /(linux|solaris|bsd)/
- return [] unless ldd_available?
- dylibs_ldd(path)
- else # Windows, etc.
- Bundler.ui.warn("Dynamic library check not supported on this platform.")
- []
- end
- end
-
- def bundles_for_gem(spec)
- Dir.glob("#{spec.full_gem_path}/**/*.bundle")
- end
-
- def lookup_with_fiddle(path)
- require "fiddle"
- Fiddle.dlopen(path)
- false
- rescue Fiddle::DLError
- true
- end
-
- def check!
- require_relative "check"
- Bundler::CLI::Check.new({}).run
- end
-
- def run
- Bundler.ui.level = "warn" if options[:quiet]
- Bundler.settings.validate!
- check!
-
- definition = Bundler.definition
- broken_links = {}
-
- definition.specs.each do |spec|
- bundles_for_gem(spec).each do |bundle|
- bad_paths = dylibs(bundle).select do |f|
- lookup_with_fiddle(f)
- end
- if bad_paths.any?
- broken_links[spec] ||= []
- broken_links[spec].concat(bad_paths)
- end
- end
- end
-
- permissions_valid = check_home_permissions
-
- if broken_links.any?
- message = "The following gems are missing OS dependencies:"
- broken_links.flat_map do |spec, paths|
- paths.uniq.map do |path|
- "\n * #{spec.name}: #{path}"
- end
- end.sort.each {|m| message += m }
- raise ProductionError, message
- elsif permissions_valid
- Bundler.ui.info "No issues found with the installed bundle"
- end
- end
-
- private
-
- def check_home_permissions
- require "find"
- files_not_readable = []
- files_not_readable_and_owned_by_different_user = []
- files_not_owned_by_current_user_but_still_readable = []
- broken_symlinks = []
- Find.find(Bundler.bundle_path.to_s).each do |f|
- if !File.exist?(f)
- broken_symlinks << f
- elsif !File.readable?(f)
- if File.stat(f).uid != Process.uid
- files_not_readable_and_owned_by_different_user << f
- else
- files_not_readable << f
- end
- elsif File.stat(f).uid != Process.uid
- files_not_owned_by_current_user_but_still_readable << f
- end
- end
-
- ok = true
-
- if broken_symlinks.any?
- Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}"
-
- ok = false
- end
-
- if files_not_owned_by_current_user_but_still_readable.any?
- Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \
- "user, but are still readable. These files are:\n - #{files_not_owned_by_current_user_but_still_readable.join("\n - ")}"
-
- ok = false
- end
-
- if files_not_readable_and_owned_by_different_user.any?
- Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \
- "user, and are not readable. These files are:\n - #{files_not_readable_and_owned_by_different_user.join("\n - ")}"
-
- ok = false
- end
-
- if files_not_readable.any?
- Bundler.ui.warn "Files exist in the Bundler home that are not " \
- "readable by the current user. These files are:\n - #{files_not_readable.join("\n - ")}"
-
- ok = false
- end
-
- ok
+ class CLI::Doctor < Thor
+ default_command(:diagnose)
+
+ desc "diagnose [OPTIONS]", "Checks the bundle for common problems"
+ long_desc <<-D
+ Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If
+ 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 "ssl", type: :boolean, default: false, banner: "Diagnose SSL problems."
+ def diagnose
+ require_relative "doctor/diagnose"
+ Diagnose.new(options).run
+ end
+
+ desc "ssl [OPTIONS]", "Diagnose SSL problems"
+ long_desc <<-D
+ Diagnose SSL problems, especially related to certificates or TLS version while connecting to https://rubygems.org.
+ D
+ method_option "host", type: :string, banner: "The host to diagnose."
+ method_option "tls-version", type: :string, banner: "Specify the SSL/TLS version when running the diagnostic. Accepts either <1.1> or <1.2>"
+ method_option "verify-mode", type: :string, banner: "Specify the mode used for certification verification. Accepts either <peer> or <none>"
+ def ssl
+ require_relative "doctor/ssl"
+ SSL.new(options).run
end
end
end
diff --git a/lib/bundler/cli/doctor/diagnose.rb b/lib/bundler/cli/doctor/diagnose.rb
new file mode 100644
index 0000000000..a878025dda
--- /dev/null
+++ b/lib/bundler/cli/doctor/diagnose.rb
@@ -0,0 +1,167 @@
+# frozen_string_literal: true
+
+require "rbconfig"
+require "shellwords"
+
+module Bundler
+ class CLI::Doctor::Diagnose
+ DARWIN_REGEX = /\s+(.+) \(compatibility /
+ LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/
+
+ attr_reader :options
+
+ def initialize(options)
+ @options = options
+ end
+
+ def otool_available?
+ Bundler.which("otool")
+ end
+
+ def ldd_available?
+ Bundler.which("ldd")
+ end
+
+ def dylibs_darwin(path)
+ output = `/usr/bin/otool -L #{path.shellescape}`.chomp
+ dylibs = output.split("\n")[1..-1].filter_map {|l| l.match(DARWIN_REGEX)&.match(1) }.uniq
+ # ignore @rpath and friends
+ dylibs.reject {|dylib| dylib.start_with? "@" }
+ end
+
+ def dylibs_ldd(path)
+ output = `/usr/bin/ldd #{path.shellescape}`.chomp
+ output.split("\n").filter_map do |l|
+ match = l.match(LDD_REGEX)
+ next if match.nil?
+ match.captures[0]
+ end
+ end
+
+ def dylibs(path)
+ case RbConfig::CONFIG["host_os"]
+ when /darwin/
+ return [] unless otool_available?
+ dylibs_darwin(path)
+ when /(linux|solaris|bsd)/
+ return [] unless ldd_available?
+ dylibs_ldd(path)
+ else # Windows, etc.
+ Bundler.ui.warn("Dynamic library check not supported on this platform.")
+ []
+ end
+ end
+
+ def bundles_for_gem(spec)
+ Dir.glob("#{spec.full_gem_path}/**/*.bundle")
+ end
+
+ def lookup_with_fiddle(path)
+ require "fiddle"
+ Fiddle.dlopen(path)
+ false
+ rescue Fiddle::DLError
+ true
+ end
+
+ def check!
+ require_relative "../check"
+ Bundler::CLI::Check.new({}).run
+ end
+
+ def diagnose_ssl
+ require_relative "ssl"
+ Bundler::CLI::Doctor::SSL.new({}).run
+ end
+
+ def run
+ Bundler.ui.level = "warn" if options[:quiet]
+ Bundler.settings.validate!
+ check!
+ diagnose_ssl if options[:ssl]
+
+ definition = Bundler.definition
+ broken_links = {}
+
+ definition.specs.each do |spec|
+ bundles_for_gem(spec).each do |bundle|
+ bad_paths = dylibs(bundle).select do |f|
+ lookup_with_fiddle(f)
+ end
+ if bad_paths.any?
+ broken_links[spec] ||= []
+ broken_links[spec].concat(bad_paths)
+ end
+ end
+ end
+
+ permissions_valid = check_home_permissions
+
+ if broken_links.any?
+ message = "The following gems are missing OS dependencies:"
+ broken_links.flat_map do |spec, paths|
+ paths.uniq.map do |path|
+ "\n * #{spec.name}: #{path}"
+ end
+ end.sort.each {|m| message += m }
+ raise ProductionError, message
+ elsif permissions_valid
+ Bundler.ui.info "No issues found with the installed bundle"
+ end
+ end
+
+ private
+
+ def check_home_permissions
+ require "find"
+ files_not_readable = []
+ files_not_readable_and_owned_by_different_user = []
+ files_not_owned_by_current_user_but_still_readable = []
+ broken_symlinks = []
+ Find.find(Bundler.bundle_path.to_s).each do |f|
+ if !File.exist?(f)
+ broken_symlinks << f
+ elsif !File.readable?(f)
+ if File.stat(f).uid != Process.uid
+ files_not_readable_and_owned_by_different_user << f
+ else
+ files_not_readable << f
+ end
+ elsif File.stat(f).uid != Process.uid
+ files_not_owned_by_current_user_but_still_readable << f
+ end
+ end
+
+ ok = true
+
+ if broken_symlinks.any?
+ Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}"
+
+ ok = false
+ end
+
+ if files_not_owned_by_current_user_but_still_readable.any?
+ Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \
+ "user, but are still readable. These files are:\n - #{files_not_owned_by_current_user_but_still_readable.join("\n - ")}"
+
+ ok = false
+ end
+
+ if files_not_readable_and_owned_by_different_user.any?
+ Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \
+ "user, and are not readable. These files are:\n - #{files_not_readable_and_owned_by_different_user.join("\n - ")}"
+
+ ok = false
+ end
+
+ if files_not_readable.any?
+ Bundler.ui.warn "Files exist in the Bundler home that are not " \
+ "readable by the current user. These files are:\n - #{files_not_readable.join("\n - ")}"
+
+ ok = false
+ end
+
+ ok
+ end
+ end
+end
diff --git a/lib/bundler/cli/doctor/ssl.rb b/lib/bundler/cli/doctor/ssl.rb
new file mode 100644
index 0000000000..21fc4edf2d
--- /dev/null
+++ b/lib/bundler/cli/doctor/ssl.rb
@@ -0,0 +1,249 @@
+# frozen_string_literal: true
+
+require "rubygems/remote_fetcher"
+require "uri"
+
+module Bundler
+ class CLI::Doctor::SSL
+ attr_reader :options
+
+ def initialize(options)
+ @options = options
+ end
+
+ def run
+ return unless openssl_installed?
+
+ output_ssl_environment
+ bundler_success = bundler_connection_successful?
+ rubygem_success = rubygem_connection_successful?
+
+ return unless net_http_connection_successful?
+
+ Explanation.summarize(bundler_success, rubygem_success, host)
+ end
+
+ private
+
+ def host
+ @options[:host] || "rubygems.org"
+ end
+
+ def tls_version
+ @options[:"tls-version"].then do |version|
+ "TLS#{version.sub(".", "_")}".to_sym if version
+ end
+ end
+
+ def verify_mode
+ mode = @options[:"verify-mode"] || :peer
+
+ @verify_mode ||= mode.then {|mod| OpenSSL::SSL.const_get("verify_#{mod}".upcase) }
+ end
+
+ def uri
+ @uri ||= URI("https://#{host}")
+ end
+
+ def openssl_installed?
+ require "openssl"
+
+ true
+ rescue LoadError
+ Bundler.ui.warn(<<~MSG)
+ Oh no! Your Ruby doesn't have OpenSSL, so it can't connect to #{host}.
+ You'll need to recompile or reinstall Ruby with OpenSSL support and try again.
+ MSG
+
+ false
+ end
+
+ def output_ssl_environment
+ Bundler.ui.info(<<~MESSAGE)
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+ MESSAGE
+ end
+
+ def bundler_connection_successful?
+ Bundler.ui.info("\nTrying connections to #{uri}:\n")
+
+ bundler_uri = Gem::URI(uri.to_s)
+ Bundler::Fetcher.new(
+ Bundler::Source::Rubygems::Remote.new(bundler_uri)
+ ).send(:connection).request(bundler_uri)
+
+ Bundler.ui.info("Bundler: success")
+
+ true
+ rescue StandardError => error
+ Bundler.ui.warn("Bundler: failed (#{Explanation.explain_bundler_or_rubygems_error(error)})")
+
+ false
+ end
+
+ def rubygem_connection_successful?
+ Gem::RemoteFetcher.fetcher.fetch_path(uri)
+ Bundler.ui.info("RubyGems: success")
+
+ true
+ rescue StandardError => error
+ Bundler.ui.warn("RubyGems: failed (#{Explanation.explain_bundler_or_rubygems_error(error)})")
+
+ false
+ end
+
+ def net_http_connection_successful?
+ ::Gem::Net::HTTP.new(uri.host, uri.port).tap do |http|
+ http.use_ssl = true
+ http.min_version = tls_version
+ http.max_version = tls_version
+ http.verify_mode = verify_mode
+ end.start
+
+ Bundler.ui.info("Ruby net/http: success")
+ warn_on_unsupported_tls12
+
+ true
+ rescue StandardError => error
+ Bundler.ui.warn(<<~MSG)
+ Ruby net/http: failed
+
+ Unfortunately, this Ruby can't connect to #{host}.
+
+ #{Explanation.explain_net_http_error(error, host, tls_version)}
+ MSG
+
+ false
+ end
+
+ def warn_on_unsupported_tls12
+ ctx = OpenSSL::SSL::SSLContext.new
+ supported = true
+
+ if ctx.respond_to?(:min_version=)
+ begin
+ ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
+ rescue OpenSSL::SSL::SSLError, NameError
+ supported = false
+ end
+ else
+ supported = OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) # rubocop:disable Naming/VariableNumber
+ end
+
+ Bundler.ui.warn(<<~EOM) unless supported
+
+ WARNING: Although your Ruby can connect to #{host} today, your OpenSSL is very old!
+ WARNING: You will need to upgrade OpenSSL to use #{host}.
+
+ EOM
+ end
+
+ module Explanation
+ extend self
+
+ def explain_bundler_or_rubygems_error(error)
+ case error.message
+ when /certificate verify failed/
+ "certificate verification"
+ when /read server hello A/
+ "SSL/TLS protocol version mismatch"
+ when /tlsv1 alert protocol version/
+ "requested TLS version is too old"
+ else
+ error.message
+ end
+ end
+
+ def explain_net_http_error(error, host, tls_version)
+ case error.message
+ # Check for certificate errors
+ when /certificate verify failed/
+ <<~MSG
+ #{show_ssl_certs}
+ Your Ruby can't connect to #{host} because you are missing the certificate files OpenSSL needs to verify you are connecting to the genuine #{host} servers.
+ MSG
+ # Check for TLS version errors
+ when /read server hello A/, /tlsv1 alert protocol version/
+ if tls_version.to_s == "TLS1_3"
+ "Your Ruby can't connect to #{host} because #{tls_version} isn't supported yet.\n"
+ else
+ <<~MSG
+ Your Ruby can't connect to #{host} because your version of OpenSSL is too old.
+ You'll need to upgrade your OpenSSL install and/or recompile Ruby to use a newer OpenSSL.
+ MSG
+ end
+ # OpenSSL doesn't support TLS version specified by argument
+ when /unknown SSL method/
+ "Your Ruby can't connect because #{tls_version} isn't supported by your version of OpenSSL."
+ else
+ <<~MSG
+ Even worse, we're not sure why.
+
+ Here's the full error information:
+ #{error.class}: #{error.message}
+ #{error.backtrace.join("\n ")}
+
+ You might have more luck using Mislav's SSL doctor.rb script. You can get it here:
+ https://github.com/mislav/ssl-tools/blob/8b3dec4/doctor.rb
+
+ Read more about the script and how to use it in this blog post:
+ https://mislav.net/2013/07/ruby-openssl/
+ MSG
+ end
+ end
+
+ def summarize(bundler_success, rubygems_success, host)
+ guide_url = "http://ruby.to/ssl-check-failed"
+
+ message = if bundler_success && rubygems_success
+ <<~MSG
+ Hooray! This Ruby can connect to #{host}.
+ You are all set to use Bundler and RubyGems.
+
+ MSG
+ elsif !bundler_success && !rubygems_success
+ <<~MSG
+ For some reason, your Ruby installation can connect to #{host}, but neither RubyGems nor Bundler can.
+ The most likely fix is to manually upgrade RubyGems by following the instructions at #{guide_url}.
+ After you've done that, run `gem install bundler` to upgrade Bundler, and then run this script again to make sure everything worked. ❣
+
+ MSG
+ elsif !bundler_success
+ <<~MSG
+ Although your Ruby installation and RubyGems can both connect to #{host}, Bundler is having trouble.
+ The most likely way to fix this is to upgrade Bundler by running `gem install bundler`.
+ Run this script again after doing that to make sure everything is all set.
+ If you're still having trouble, check out the troubleshooting guide at #{guide_url}.
+
+ MSG
+ else
+ <<~MSG
+ It looks like Ruby and Bundler can connect to #{host}, but RubyGems itself cannot.
+ You can likely solve this by manually downloading and installing a RubyGems update.
+ Visit #{guide_url} for instructions on how to manually upgrade RubyGems.
+
+ MSG
+ end
+
+ Bundler.ui.info("\n#{message}")
+ end
+
+ private
+
+ def show_ssl_certs
+ ssl_cert_file = ENV["SSL_CERT_FILE"] || OpenSSL::X509::DEFAULT_CERT_FILE
+ ssl_cert_dir = ENV["SSL_CERT_DIR"] || OpenSSL::X509::DEFAULT_CERT_DIR
+
+ <<~MSG
+ Below affect only Ruby net/http connections:
+ SSL_CERT_FILE: #{File.exist?(ssl_cert_file) ? "exists #{ssl_cert_file}" : "is missing #{ssl_cert_file}"}
+ SSL_CERT_DIR: #{Dir.exist?(ssl_cert_dir) ? "exists #{ssl_cert_dir}" : "is missing #{ssl_cert_dir}"}
+ MSG
+ end
+ end
+ end
+end
diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb
index 9428e9db3b..2fdc416286 100644
--- a/lib/bundler/cli/exec.rb
+++ b/lib/bundler/cli/exec.rb
@@ -19,11 +19,13 @@ module Bundler
validate_cmd!
SharedHelpers.set_bundle_environment
if bin_path = Bundler.which(cmd)
- if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path)
- return kernel_load(bin_path, *args)
+ if !Bundler.settings[:disable_exec_load] && directly_loadable?(bin_path)
+ bin_path.delete_suffix!(".bat") if Gem.win_platform?
+ kernel_load(bin_path, *args)
+ else
+ bin_path = "./" + bin_path unless File.absolute_path?(bin_path)
+ kernel_exec(bin_path, *args)
end
- bin_path = "./" + bin_path unless File.absolute_path?(bin_path)
- kernel_exec(bin_path, *args)
else
# exec using the given command
kernel_exec(cmd, *args)
@@ -69,6 +71,29 @@ module Bundler
"#{file} #{args.join(" ")}".strip
end
+ def directly_loadable?(file)
+ if Gem.win_platform?
+ script_wrapper?(file)
+ else
+ ruby_shebang?(file)
+ end
+ end
+
+ def script_wrapper?(file)
+ script_file = file.delete_suffix(".bat")
+ return false unless File.exist?(script_file)
+
+ if File.zero?(script_file)
+ Bundler.ui.warn "#{script_file} is empty"
+ return false
+ end
+
+ header = File.open(file, "r") {|f| f.read(32) }
+ ruby_exe = "#{RbConfig::CONFIG["RUBY_INSTALL_NAME"]}#{RbConfig::CONFIG["EXEEXT"]}"
+ ruby_exe = "ruby.exe" if ruby_exe.empty?
+ header.include?(ruby_exe)
+ end
+
def ruby_shebang?(file)
possibilities = [
"#!/usr/bin/env ruby\n",
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb
index 22bcf0e47a..c8c24c8e66 100644
--- a/lib/bundler/cli/gem.rb
+++ b/lib/bundler/cli/gem.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "pathname"
-
module Bundler
class CLI
Bundler.require_thor_actions
@@ -9,11 +7,7 @@ module Bundler
end
class CLI::Gem
- TEST_FRAMEWORK_VERSIONS = {
- "rspec" => "3.0",
- "minitest" => "5.16",
- "test-unit" => "3.0",
- }.freeze
+ DEFAULT_GITHUB_USERNAME = "[USERNAME]"
attr_reader :options, :gem_name, :thor, :name, :target, :extension
@@ -26,12 +20,11 @@ module Bundler
thor.destination_root = nil
@name = @gem_name
- @target = SharedHelpers.pwd.join(gem_name)
+ @target = Pathname.new(SharedHelpers.pwd).join(gem_name)
@extension = options[:ext]
validate_ext_name if @extension
- validate_rust_builder_rubygems_version if @extension == "rust"
end
def run
@@ -48,13 +41,16 @@ module Bundler
git_author_name = use_git ? `git config user.name`.chomp : ""
git_username = use_git ? `git config github.user`.chomp : ""
git_user_email = use_git ? `git config user.email`.chomp : ""
+ github_username = github_username(git_username)
- github_username = if options[:github_username].nil?
- git_username
- elsif options[:github_username] == false
- ""
+ if github_username.empty?
+ homepage_uri = "TODO: Put your gem's website or public repo URL here."
+ source_code_uri = "TODO: Put your gem's public repo URL here."
+ changelog_uri = "TODO: Put your gem's CHANGELOG.md URL here."
else
- options[:github_username]
+ homepage_uri = "https://github.com/#{github_username}/#{name}"
+ source_code_uri = "https://github.com/#{github_username}/#{name}"
+ changelog_uri = "https://github.com/#{github_username}/#{name}/blob/main/CHANGELOG.md"
end
config = {
@@ -69,12 +65,17 @@ module Bundler
test: options[:test],
ext: extension,
exe: options[:exe],
+ bundle: options[:bundle],
bundler_version: bundler_dependency_version,
git: use_git,
- github_username: github_username.empty? ? "[USERNAME]" : github_username,
+ github_username: github_username.empty? ? DEFAULT_GITHUB_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,
+ ignore_paths: %w[bin/],
+ homepage_uri: homepage_uri,
+ source_code_uri: source_code_uri,
+ changelog_uri: changelog_uri,
}
ensure_safe_gem_name(name, constant_array)
@@ -95,11 +96,21 @@ module Bundler
bin/setup
]
- templates.merge!("gitignore.tt" => ".gitignore") if use_git
+ case Bundler.preferred_gemfile_name
+ when "Gemfile"
+ config[:ignore_paths] << "Gemfile"
+ when "gems.rb"
+ config[:ignore_paths] << "gems.rb"
+ config[:ignore_paths] << "gems.locked"
+ end
+
+ if use_git
+ templates.merge!("gitignore.tt" => ".gitignore")
+ config[:ignore_paths] << ".gitignore"
+ end
if test_framework = ask_and_set_test_framework
config[:test] = test_framework
- config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework]
case test_framework
when "rspec"
@@ -109,6 +120,8 @@ module Bundler
"spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb"
)
config[:test_task] = :spec
+ config[:ignore_paths] << ".rspec"
+ config[:ignore_paths] << "spec/"
when "minitest"
# Generate path for minitest target file (FileList["test/**/test_*.rb"])
# foo => test/test_foo.rb
@@ -123,12 +136,14 @@ module Bundler
"test/minitest/test_newgem.rb.tt" => "test/#{minitest_namespaced_path}.rb"
)
config[:test_task] = :test
+ config[:ignore_paths] << "test/"
when "test-unit"
templates.merge!(
"test/test-unit/test_helper.rb.tt" => "test/test_helper.rb",
"test/test-unit/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb"
)
config[:test_task] = :test
+ config[:ignore_paths] << "test/"
end
end
@@ -136,19 +151,22 @@ module Bundler
case config[:ci]
when "github"
templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml")
- config[:ci_config_path] = ".github "
+ if extension == "rust"
+ templates.merge!("github/workflows/build-gems.yml.tt" => ".github/workflows/build-gems.yml")
+ end
+ config[:ignore_paths] << ".github/"
when "gitlab"
templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml")
- config[:ci_config_path] = ".gitlab-ci.yml "
+ config[:ignore_paths] << ".gitlab-ci.yml"
when "circle"
templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml")
- config[:ci_config_path] = ".circleci "
+ config[:ignore_paths] << ".circleci/"
end
if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?",
- "This means that any other developer or company will be legally allowed to use your code " \
- "for free as long as they admit you created it. You can read more about the MIT license " \
- "at https://choosealicense.com/licenses/mit.")
+ "Using a MIT license means that any other developer or company will be legally allowed " \
+ "to use your code for free as long as they admit you created it. You can read more about " \
+ "the MIT license at https://choosealicense.com/licenses/mit.")
config[:mit] = true
Bundler.ui.info "MIT License enabled in config"
templates.merge!("LICENSE.txt.tt" => "LICENSE.txt")
@@ -156,12 +174,8 @@ module Bundler
if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?",
"Codes of conduct can increase contributions to your project by contributors who " \
- "prefer collaborative, safe spaces. You can read more about the code of conduct at " \
- "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \
- "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \
- "address is specified as a contact in the generated code of conduct so that people know " \
- "who to contact in case of a violation. For suggestions about " \
- "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.")
+ "prefer safe, respectful, productive, and collaborative spaces. \n" \
+ "See https://github.com/ruby/rubygems/blob/master/CODE_OF_CONDUCT.md")
config[:coc] = true
Bundler.ui.info "Code of conduct enabled in config"
templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md")
@@ -182,13 +196,13 @@ module Bundler
config[:linter] = ask_and_set_linter
case config[:linter]
when "rubocop"
- config[:linter_version] = rubocop_version
Bundler.ui.info "RuboCop enabled in config"
templates.merge!("rubocop.yml.tt" => ".rubocop.yml")
+ config[:ignore_paths] << ".rubocop.yml"
when "standard"
- config[:linter_version] = standard_version
Bundler.ui.info "Standard enabled in config"
templates.merge!("standard.yml.tt" => ".standard.yml")
+ config[:ignore_paths] << ".standard.yml"
end
if config[:exe]
@@ -208,18 +222,31 @@ module Bundler
templates.merge!(
"Cargo.toml.tt" => "Cargo.toml",
"ext/newgem/Cargo.toml.tt" => "ext/#{name}/Cargo.toml",
+ "ext/newgem/build.rs.tt" => "ext/#{name}/build.rs",
"ext/newgem/extconf-rust.rb.tt" => "ext/#{name}/extconf.rb",
"ext/newgem/src/lib.rs.tt" => "ext/#{name}/src/lib.rs",
)
end
+ if extension == "go"
+ templates.merge!(
+ "ext/newgem/go.mod.tt" => "ext/#{name}/go.mod",
+ "ext/newgem/extconf-go.rb.tt" => "ext/#{name}/extconf.rb",
+ "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h",
+ "ext/newgem/newgem.go.tt" => "ext/#{name}/#{underscored_name}.go",
+ "ext/newgem/newgem-go.c.tt" => "ext/#{name}/#{underscored_name}.c",
+ )
+
+ config[:go_module_username] = config[:github_username] == DEFAULT_GITHUB_USERNAME ? "username" : config[:github_username]
+ end
+
if target.exist? && !target.directory?
Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`."
exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError]
end
if use_git
- Bundler.ui.info "Initializing git repo in #{target}"
+ Bundler.ui.info "\nInitializing git repo in #{target}"
require "shellwords"
`git init #{target.to_s.shellescape}`
@@ -241,26 +268,33 @@ module Bundler
IO.popen(%w[git add .], { chdir: target }, &:read)
end
+ if config[:bundle]
+ Bundler.ui.info "Running bundle install in the new gem directory."
+ Dir.chdir(target) do
+ system("bundle install")
+ end
+ end
+
# Open gemspec in editor
open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit]
- Bundler.ui.info "Gem '#{name}' was successfully created. " \
- "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html"
+ Bundler.ui.info "\nGem '#{name}' was successfully created. " \
+ "For more information on making a RubyGem visit https://guides.rubygems.org/make-your-own-gem/"
end
private
def resolve_name(name)
- SharedHelpers.pwd.join(name).basename.to_s
+ Pathname.new(SharedHelpers.pwd).join(name).basename.to_s
end
- def ask_and_set(key, header, message)
+ def ask_and_set(key, prompt, explanation)
choice = options[key]
choice = Bundler.settings["gem.#{key}"] if choice.nil?
if choice.nil?
- Bundler.ui.confirm header
- choice = Bundler.ui.yes? "#{message} y/(n):"
+ Bundler.ui.info "\n#{explanation}"
+ choice = Bundler.ui.yes? "#{prompt} y/(n):"
Bundler.settings.set_global("gem.#{key}", choice)
end
@@ -282,7 +316,7 @@ module Bundler
test_framework = options[:test] || Bundler.settings["gem.test"]
if test_framework.to_s.empty?
- Bundler.ui.confirm "Do you want to generate tests with your gem?"
+ Bundler.ui.info "\nDo you want to generate tests with your gem?"
Bundler.ui.info hint_text("test")
result = Bundler.ui.ask "Enter a test framework. rspec/minitest/test-unit/(none):"
@@ -322,12 +356,11 @@ module Bundler
ci_template = options[:ci] || Bundler.settings["gem.ci"]
if ci_template.to_s.empty?
- Bundler.ui.confirm "Do you want to set up continuous integration for your gem? " \
+ Bundler.ui.info "\nDo you want to set up continuous integration for your gem? " \
"Supported services:\n" \
"* CircleCI: https://circleci.com/\n" \
"* GitHub Actions: https://github.com/features/actions\n" \
- "* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \
- "\n"
+ "* GitLab CI: https://docs.gitlab.com/ee/ci/\n"
Bundler.ui.info hint_text("ci")
result = Bundler.ui.ask "Enter a CI service. github/gitlab/circle/(none):"
@@ -352,14 +385,12 @@ module Bundler
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?
if linter_template.to_s.empty?
- Bundler.ui.confirm "Do you want to add a code linter and formatter to your gem? " \
+ Bundler.ui.info "\nDo 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" \
- "\n"
+ "* Standard: https://github.com/standardrb/standard\n"
Bundler.ui.info hint_text("linter")
result = Bundler.ui.ask "Enter a linter. rubocop/standard/(none):"
@@ -386,27 +417,6 @@ module Bundler
linter_template
end
- 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"
- "rubocop"
- else
- Bundler::SharedHelpers.major_deprecation 2,
- "--no-rubocop is deprecated, use --linter",
- removed_message: "--no-rubocop has been removed, 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"
- Bundler.settings["gem.rubocop"] ? "rubocop" : false
- end
- end
-
def bundler_dependency_version
v = Gem::Version.new(Bundler::VERSION)
req = v.segments[0..1]
@@ -420,6 +430,10 @@ module Bundler
exit 1
end
+ if /[A-Z]/.match?(name)
+ Bundler.ui.warn "Gem names with capital letters are not recommended. Please use only lowercase letters, numbers, and hyphens."
+ end
+
constant_name = constant_array.join("::")
existing_constant = constant_array.inject(Object) do |c, s|
@@ -446,21 +460,16 @@ module Bundler
end
def required_ruby_version
- "3.1.0"
- end
-
- def rubocop_version
- "1.21"
- end
-
- def standard_version
- "1.3"
+ "3.2.0"
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."
- exit 1
+ def github_username(git_username)
+ if options[:github_username].nil?
+ git_username
+ elsif options[:github_username] == false
+ ""
+ else
+ options[:github_username]
end
end
end
diff --git a/lib/bundler/cli/inject.rb b/lib/bundler/cli/inject.rb
deleted file mode 100644
index a09d5c6bda..0000000000
--- a/lib/bundler/cli/inject.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CLI::Inject
- attr_reader :options, :name, :version, :group, :source, :gems
- def initialize(options, name, version)
- @options = options
- @name = name
- @version = version || last_version_number
- @group = options[:group].split(",") unless options[:group].nil?
- @source = options[:source]
- @gems = []
- end
-
- def run
- # The required arguments allow Thor to give useful feedback when the arguments
- # are incorrect. This adds those first two arguments onto the list as a whole.
- gems.unshift(source).unshift(group).unshift(version).unshift(name)
-
- # Build an array of Dependency objects out of the arguments
- deps = []
- # when `inject` support addition of more than one gem, then this loop will
- # help. Currently this loop is running once.
- gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source|
- ops = Gem::Requirement::OPS.map {|key, _val| key }
- has_op = ops.any? {|op| gem_version.start_with? op }
- gem_version = "~> #{gem_version}" unless has_op
- deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source)
- end
-
- added = Injector.inject(deps, options)
-
- if added.any?
- Bundler.ui.confirm "Added to Gemfile:"
- Bundler.ui.confirm(added.map do |d|
- name = "'#{d.name}'"
- requirement = ", '#{d.requirement}'"
- group = ", group: #{d.groups.inspect}" if d.groups != Array(:default)
- source = ", source: '#{d.source}'" unless d.source.nil?
- %(gem #{name}#{requirement}#{group}#{source})
- end.join("\n"))
- else
- Bundler.ui.confirm "All gems were already present in the Gemfile"
- end
- end
-
- private
-
- def last_version_number
- definition = Bundler.definition(true)
- definition.remotely!
- specs = definition.index[name].sort_by(&:version)
- unless options[:pre]
- specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
- end
- spec = specs.last
- spec.version.to_s
- end
- end
-end
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index b0b354cf10..69affd1a10 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -20,54 +20,32 @@ module Bundler
Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Gem.freebsd_platform?
- # Disable color in deployment mode
- Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment]
-
if target_rbconfig_path = options[:"target-rbconfig"]
Bundler.rubygems.set_target_rbconfig(target_rbconfig_path)
end
- check_for_options_conflicts
-
check_trust_policy
- 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 " \
- "before deploying."
- end
-
- options[:local] = true if Bundler.app_cache.exist?
-
- Bundler.settings.set_command_option :deployment, true if options[:deployment]
- Bundler.settings.set_command_option :frozen, true if options[:frozen]
- end
-
- # When install is called with --no-deployment, disable deployment mode
- if options[:deployment] == false
- Bundler.settings.set_command_option :frozen, nil
- options[:system] = true
+ if Bundler.frozen_bundle? && !Bundler.default_lockfile.exist?
+ 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 " \
+ "before deploying."
end
normalize_settings
Bundler::Fetcher.disable_endpoint = options["full-index"]
- 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`"
- end
-
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
- definition = Bundler.definition
+ # For install we want to enable strict validation
+ # (rather than some optimizations we perform at app runtime).
+ definition = Bundler.definition(strict: true)
definition.validate_runtime!
+ definition.lockfile = options["lockfile"] if options["lockfile"]
+ definition.lockfile = false if options["no-lock"]
installer = Installer.install(Bundler.root, definition, options)
@@ -87,8 +65,6 @@ module Bundler
Bundler::CLI::Common.output_post_install_messages installer.post_install_messages
- warn_ambiguous_gems
-
if CLI::Common.clean_after_install?
require_relative "clean"
Bundler::CLI::Clean.new(options).run
@@ -114,26 +90,10 @@ module Bundler
end
def gems_installed_for(definition)
- count = definition.specs.count
+ count = definition.specs.count {|spec| spec.name != "bundler" }
"#{count} #{count == 1 ? "gem" : "gems"} now installed"
end
- def check_for_group_conflicts_in_cli_options
- conflicting_groups = Array(options[:without]) & Array(options[:with])
- return if conflicting_groups.empty?
- raise InvalidOption, "You can't list a group in both with and without." \
- " The offending groups are: #{conflicting_groups.join(", ")}."
- end
-
- def check_for_options_conflicts
- if (options[:path] || options[:deployment]) && options[:system]
- error_message = String.new
- error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path]
- error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment]
- raise InvalidOption.new(error_message)
- end
- end
-
def check_trust_policy
trust_policy = options["trust-policy"]
unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy)
@@ -143,57 +103,25 @@ module Bundler
Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy
end
- def normalize_groups
- check_for_group_conflicts_in_cli_options
-
- # need to nil them out first to get around validation for backwards compatibility
- Bundler.settings.set_command_option :without, nil
- Bundler.settings.set_command_option :with, nil
- Bundler.settings.set_command_option :without, options[:without]
- Bundler.settings.set_command_option :with, options[:with]
- end
-
def normalize_settings
- Bundler.settings.set_command_option :path, nil if options[:system]
- 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.set_command_option :path, "bundle"
- end
+ Bundler.settings.set_command_option :path, "bundle"
end
- bin_option = options["binstubs"]
- bin_option = nil if bin_option&.empty?
- Bundler.settings.set_command_option :bin, bin_option if options["binstubs"]
-
Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
Bundler.settings.set_command_option_if_given :jobs, options["jobs"]
+ Bundler::CLI::Common.validate_cooldown!(options["cooldown"])
+ Bundler.settings.set_command_option_if_given :cooldown, options["cooldown"]
+
Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"]
Bundler.settings.set_command_option_if_given :no_install, options["no-install"]
Bundler.settings.set_command_option_if_given :clean, options["clean"]
- normalize_groups if options[:without] || options[:with]
-
- options[:force] = options[:redownload]
- end
-
- def warn_ambiguous_gems
- # TODO: remove this when we drop Bundler 1.x support
- Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris|
- Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources."
- Bundler.ui.warn "Installed from: #{installed_from_uri}"
- Bundler.ui.warn "Also found in:"
- also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" }
- Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source."
- Bundler.ui.warn "For example:"
- Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'"
- Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again."
- end
+ options[:force] = options[:redownload] if options[:redownload]
end
end
end
diff --git a/lib/bundler/cli/issue.rb b/lib/bundler/cli/issue.rb
index e16c9b0e39..cbfb7da2d8 100644
--- a/lib/bundler/cli/issue.rb
+++ b/lib/bundler/cli/issue.rb
@@ -10,7 +10,7 @@ module Bundler
be sure to check out these resources:
1. Check out our troubleshooting guide for quick fixes to common issues:
- https://github.com/rubygems/rubygems/blob/master/doc/bundler/TROUBLESHOOTING.md
+ https://github.com/ruby/rubygems/blob/master/doc/bundler/TROUBLESHOOTING.md
2. Instructions for common Bundler uses can be found on the documentation
site: https://bundler.io/
@@ -22,7 +22,7 @@ module Bundler
still aren't working the way you expect them to, please let us know so
that we can diagnose and help fix the problem you're having, by filling
in the new issue form located at
- https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md,
+ https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md,
and copy and pasting the information below.
EOS
@@ -34,8 +34,8 @@ module Bundler
end
def doctor
- require_relative "doctor"
- Bundler::CLI::Doctor.new({}).run
+ require_relative "doctor/diagnose"
+ Bundler::CLI::Doctor::Diagnose.new({}).run
end
end
end
diff --git a/lib/bundler/cli/list.rb b/lib/bundler/cli/list.rb
index f56bf5b86a..6a467f45a9 100644
--- a/lib/bundler/cli/list.rb
+++ b/lib/bundler/cli/list.rb
@@ -1,11 +1,14 @@
# frozen_string_literal: true
+require "json"
+
module Bundler
class CLI::List
def initialize(options)
@options = options
@without_group = options["without-group"].map(&:to_sym)
@only_group = options["only-group"].map(&:to_sym)
+ @format = options["format"]
end
def run
@@ -25,6 +28,36 @@ module Bundler
end
end.reject {|s| s.name == "bundler" }.sort_by(&:name)
+ case @format
+ when "json"
+ print_json(specs: specs)
+ when nil
+ print_human(specs: specs)
+ else
+ raise InvalidOption, "Unknown option`--format=#{@format}`. Supported formats: `json`"
+ end
+ end
+
+ private
+
+ def print_json(specs:)
+ gems = if @options["name-only"]
+ specs.map {|s| { name: s.name } }
+ else
+ specs.map do |s|
+ {
+ name: s.name,
+ version: s.version.to_s,
+ git_version: s.git_version&.strip,
+ }.tap do |h|
+ h[:path] = s.full_gem_path if @options["paths"]
+ end
+ end
+ end
+ Bundler.ui.info({ gems: gems }.to_json)
+ end
+
+ def print_human(specs:)
return Bundler.ui.info "No gems in the Gemfile" if specs.empty?
return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"]
@@ -37,8 +70,6 @@ module Bundler
Bundler.ui.info "Use `bundle info` to print more detailed information about a gem"
end
- private
-
def verify_group_exists(groups)
(@without_group + @only_group).each do |group|
raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group)
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb
index b60c82e3a1..2f78868936 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -35,11 +35,8 @@ module Bundler
update = { bundler: bundler }
end
- file = options[:lockfile]
- file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile
-
Bundler.settings.temporary(frozen: false) do
- definition = Bundler.definition(update, file)
+ definition = Bundler.definition(update, Bundler.default_lockfile)
definition.add_checksums if options["add-checksums"]
Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update]
@@ -71,8 +68,11 @@ module Bundler
if print
puts definition.to_lock
else
+ file = options[:lockfile]
+ file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile
+
puts "Writing lockfile to #{file}"
- definition.lock
+ definition.write_lock(file, false)
end
end
diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb
index 1be44ff4b4..465e56ada2 100644
--- a/lib/bundler/cli/outdated.rb
+++ b/lib/bundler/cli/outdated.rb
@@ -26,6 +26,9 @@ module Bundler
def run
check_for_deployment_mode!
+ Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
+ Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
+
Bundler.definition.validate_runtime!
current_specs = Bundler.ui.silence { Bundler.definition.resolve }
@@ -155,7 +158,7 @@ module Bundler
return active_spec if strict
- active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
+ active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.installable_on_platform?(current_spec.platform) }.sort_by(&:version)
if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1
active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
end
@@ -199,7 +202,15 @@ module Bundler
end
spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \
- "installed #{current_version}#{dependency_version})"
+ "installed #{current_version}#{dependency_version}"
+
+ release_date = release_date_for(active_spec)
+ spec_outdated_info += ", released #{release_date}" unless release_date.empty?
+
+ remaining = cooldown_days_remaining(active_spec)
+ spec_outdated_info += ", in cooldown for #{remaining} more day#{"s" if remaining > 1}" if remaining
+
+ spec_outdated_info += ")"
output_message = if options[:parseable]
spec_outdated_info.to_s
@@ -215,13 +226,25 @@ module Bundler
def gem_column_for(current_spec, active_spec, dependency, groups)
current_version = "#{current_spec.version}#{current_spec.git_version}"
spec_version = "#{active_spec.version}#{active_spec.git_version}"
+ remaining = cooldown_days_remaining(active_spec)
+ spec_version += " (cooldown #{remaining}d)" if remaining
dependency = dependency.requirement if dependency
ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s]
+ ret_val << release_date_for(active_spec)
ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug?
ret_val
end
+ def cooldown_days_remaining(spec, now = Time.now)
+ return nil unless spec.respond_to?(:created_at) && spec.created_at
+ return nil unless spec.respond_to?(:remote) && spec.remote
+ days = spec.remote.effective_cooldown
+ return nil if days.nil? || days <= 0
+ remaining = days - ((now - spec.created_at) / 86_400.0)
+ remaining > 0 ? remaining.ceil : nil
+ end
+
def check_for_deployment_mode!
return unless Bundler.frozen_bundle?
suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any?
@@ -283,11 +306,28 @@ module Bundler
end
def table_header
- header = ["Gem", "Current", "Latest", "Requested", "Groups"]
+ header = ["Gem", "Current", "Latest", "Requested", "Groups", "Release Date"]
header << "Path" if Bundler.ui.debug?
header
end
+ def release_date_for(spec)
+ return "" unless spec.respond_to?(:date)
+
+ date = spec.date
+ return "" unless date
+
+ return "" unless Gem.const_defined?(:DEFAULT_SOURCE_DATE_EPOCH)
+ default_date = Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc
+ default_date = Time.utc(default_date.year, default_date.month, default_date.day)
+
+ date = date.utc if date.respond_to?(:utc)
+
+ return "" if date == default_date
+
+ date.strftime("%Y-%m-%d")
+ end
+
def justify(row, sizes)
row.each_with_index.map do |element, index|
element.ljust(sizes[index])
diff --git a/lib/bundler/cli/plugin.rb b/lib/bundler/cli/plugin.rb
index fd61ef0d95..32fa660fe0 100644
--- a/lib/bundler/cli/plugin.rb
+++ b/lib/bundler/cli/plugin.rb
@@ -10,11 +10,15 @@ module Bundler
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 "local_git", type: :string, default: nil, banner: "Path of the local git repo to fetch from (removed)"
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"
def install(*plugins)
+ if options.key?(:local_git)
+ raise InvalidOption, "--local_git has been removed, use --git"
+ end
+
Bundler::Plugin.install(plugins, options)
end
diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb
index cfd4a995a3..f463f0bce8 100644
--- a/lib/bundler/cli/pristine.rb
+++ b/lib/bundler/cli/pristine.rb
@@ -11,6 +11,7 @@ module Bundler
definition = Bundler.definition
definition.validate_runtime!
installer = Bundler::Installer.new(Bundler.root, definition)
+ git_sources = []
ProcessLock.lock do
installed_specs = definition.specs.reject do |spec|
@@ -41,6 +42,9 @@ module Bundler
end
FileUtils.rm_rf spec.extension_dir
FileUtils.rm_rf spec.full_gem_path
+
+ next if git_sources.include?(source)
+ git_sources << source
else
Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
next
@@ -49,7 +53,7 @@ module Bundler
true
end.map(&:name)
- jobs = installer.send(:installation_parallelization)
+ jobs = Bundler.settings.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
diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb
index 13bb8b774b..67fdcc797e 100644
--- a/lib/bundler/cli/show.rb
+++ b/lib/bundler/cli/show.rb
@@ -6,7 +6,7 @@ module Bundler
def initialize(options, gem_name)
@options = options
@gem_name = gem_name
- @verbose = options[:verbose] || options[:outdated]
+ @verbose = options[:verbose]
@latest_specs = fetch_latest_specs if @verbose
end
@@ -57,12 +57,8 @@ module Bundler
def fetch_latest_specs
definition = Bundler.definition(true)
- if options[:outdated]
- Bundler.ui.info "Fetching remote specs for outdated check...\n\n"
- Bundler.ui.silence { definition.remotely! }
- else
- definition.with_cache!
- end
+ Bundler.ui.info "Fetching remote specs for outdated check...\n\n"
+ Bundler.ui.silence { definition.remotely! }
Bundler.reset!
definition.specs
end
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 985e8db051..d92ffd995f 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -15,7 +15,7 @@ module Bundler
Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler) if update_bundler
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
sources = Array(options[:source])
groups = Array(options[:group]).map(&:to_sym)
@@ -23,10 +23,10 @@ module Bundler
full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !update_bundler
if full_update && !options[:all]
- if Bundler.feature_flag.update_requires_all_flag?
+ if Bundler.settings[:update_requires_all_flag]
raise InvalidOption, "To update everything, pass the `--all` flag."
end
- SharedHelpers.major_deprecation 3, "Pass --all to `bundle update` to update everything"
+ SharedHelpers.feature_deprecated! "Pass --all to `bundle update` to update everything"
elsif !full_update && options[:all]
raise InvalidOption, "Cannot specify --all along with specific options."
end
@@ -63,9 +63,11 @@ module Bundler
opts = options.dup
opts["update"] = true
opts["local"] = options[:local]
- opts["force"] = options[:redownload]
+ opts["force"] = options[:redownload] if options[:redownload]
Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
+ Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
+ Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
Bundler.definition.validate_runtime!
@@ -92,7 +94,7 @@ module Bundler
locked_spec = locked_info[:spec]
new_spec = Bundler.definition.specs[name].first
unless new_spec
- unless locked_spec.match_platform(Bundler.local_platform)
+ unless locked_spec.installable_on_platform?(Bundler.local_platform)
Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one"
end
diff --git a/lib/bundler/cli/viz.rb b/lib/bundler/cli/viz.rb
deleted file mode 100644
index 5c09e00995..0000000000
--- a/lib/bundler/cli/viz.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CLI::Viz
- attr_reader :options, :gem_name
- def initialize(options)
- @options = options
- end
-
- def run
- # make sure we get the right `graphviz`. There is also a `graphviz`
- # gem we're not built to support
- gem "ruby-graphviz"
- require "graphviz"
-
- options[:without] = options[:without].join(":").tr(" ", ":").split(":")
- output_file = File.expand_path(options[:file])
-
- graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without])
- graph.viz
- rescue LoadError => e
- Bundler.ui.error e.inspect
- Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:"
- Bundler.ui.warn "`gem install ruby-graphviz`"
- rescue StandardError => e
- raise unless e.message.to_s.include?("GraphViz not installed or dot not in PATH")
- Bundler.ui.error e.message
- Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`."
- end
- end
-end
diff --git a/lib/bundler/compact_index_client.rb b/lib/bundler/compact_index_client.rb
index 37e2ccced8..6865e30dbc 100644
--- a/lib/bundler/compact_index_client.rb
+++ b/lib/bundler/compact_index_client.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "pathname"
require "set"
module Bundler
diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb
index bedd7f8028..3bae6c9efd 100644
--- a/lib/bundler/compact_index_client/cache.rb
+++ b/lib/bundler/compact_index_client/cache.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_relative "gem_parser"
+require "rubygems/resolver/api_set/gem_parser"
module Bundler
class CompactIndexClient
diff --git a/lib/bundler/compact_index_client/gem_parser.rb b/lib/bundler/compact_index_client/gem_parser.rb
deleted file mode 100644
index 60a1817607..0000000000
--- a/lib/bundler/compact_index_client/gem_parser.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CompactIndexClient
- if defined?(Gem::Resolver::APISet::GemParser)
- 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
- [version, platform, dependencies, requirements]
- end
-
- private
-
- def parse_dependency(string)
- dependency = string.split(":")
- dependency[-1] = dependency[-1].split("&") if dependency.size > 1
- dependency[0] = -dependency[0]
- dependency
- end
- end
- end
- end
-end
diff --git a/lib/bundler/compact_index_client/parser.rb b/lib/bundler/compact_index_client/parser.rb
index 3276abdd68..ad0d17ed4a 100644
--- a/lib/bundler/compact_index_client/parser.rb
+++ b/lib/bundler/compact_index_client/parser.rb
@@ -64,14 +64,17 @@ module Bundler
end
def gem_parser
- @gem_parser ||= GemParser.new
+ @gem_parser ||= Gem::Resolver::APISet::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_start = line.index(" ", name_end + 1)
+ return unless checksum_start
+ checksum_start += 1
+
checksum_end = line.size - checksum_start
line.freeze # allows slicing into the string to not allocate a copy of the line
diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb
index e7c872031f..17c7655adb 100644
--- a/lib/bundler/current_ruby.rb
+++ b/lib/bundler/current_ruby.rb
@@ -11,7 +11,7 @@ module Bundler
end
class CurrentRuby
- ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..35).to_a).freeze
+ ALL_RUBY_VERSIONS = [*18..27, *30..34, *40..41].freeze
KNOWN_MINOR_VERSIONS = ALL_RUBY_VERSIONS.map {|v| v.digits.reverse.join(".") }.freeze
KNOWN_MAJOR_VERSIONS = ALL_RUBY_VERSIONS.map {|v| v.digits.last.to_s }.uniq.freeze
PLATFORM_MAP = {
@@ -32,7 +32,7 @@ module Bundler
end.freeze
def ruby?
- return true if Bundler::GemHelpers.generic_local_platform_is_ruby?
+ return true if Bundler::MatchPlatform.generic_local_platform_is_ruby?
!windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
end
@@ -50,19 +50,10 @@ module Bundler
end
def maglev?
- message =
- "`CurrentRuby#maglev?` is deprecated with no replacement. Please use the " \
- "built-in Ruby `RUBY_ENGINE` constant to check the Ruby implementation you are running on."
removed_message =
"`CurrentRuby#maglev?` was removed with no replacement. Please use the " \
"built-in Ruby `RUBY_ENGINE` constant to check the Ruby implementation you are running on."
- internally_exempted = caller_locations(1, 1).first.path == __FILE__
-
- unless internally_exempted
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
- end
-
- RUBY_ENGINE == "maglev"
+ SharedHelpers.feature_removed!(removed_message)
end
def truffleruby?
@@ -90,14 +81,11 @@ module Bundler
end
define_method(:"maglev_#{trimmed_version}?") do
- message =
- "`CurrentRuby##{__method__}` is deprecated with no replacement. Please use the " \
- "built-in Ruby `RUBY_ENGINE` and `RUBY_VERSION` constants to perform a similar check."
removed_message =
"`CurrentRuby##{__method__}` was removed with no replacement. Please use the " \
"built-in Ruby `RUBY_ENGINE` and `RUBY_VERSION` constants to perform a similar check."
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ SharedHelpers.feature_removed!(removed_message)
send(:"maglev?") && send(:"on_#{trimmed_version}?")
end
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index f0d7cf8d2a..7a95671471 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -1,21 +1,23 @@
# frozen_string_literal: true
require_relative "lockfile_parser"
+require_relative "worker"
module Bundler
class Definition
- include GemHelpers
-
class << self
# Do not create or modify a lockfile (Makes #lock a noop)
attr_accessor :no_lock
end
+ attr_writer :lockfile, :overrides
+
attr_reader(
:dependencies,
:locked_checksums,
:locked_deps,
:locked_gems,
+ :overrides,
:platforms,
:ruby_version,
:lockfile,
@@ -36,7 +38,10 @@ module Bundler
raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?
- Dsl.evaluate(gemfile, lockfile, unlock)
+ Plugin.hook(Plugin::Events::GEM_BEFORE_EVAL, gemfile, lockfile)
+ Dsl.evaluate(gemfile, lockfile, unlock).tap do |definition|
+ Plugin.hook(Plugin::Events::GEM_AFTER_EVAL, definition)
+ end
end
#
@@ -57,11 +62,12 @@ module Bundler
# to be updated or true if all gems should be updated
# @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
# @param optional_groups [Array(String)] A list of optional groups
- def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
+ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [], overrides = [])
unlock ||= {}
if unlock == true
@unlocking_all = true
+ strict = false
@unlocking_bundler = false
@unlocking = unlock
@sources_to_unlock = []
@@ -70,6 +76,7 @@ module Bundler
conservative = false
else
@unlocking_all = false
+ strict = unlock.delete(:strict)
@unlocking_bundler = unlock.delete(:bundler)
@unlocking = unlock.any? {|_k, v| !Array(v).empty? }
@sources_to_unlock = unlock.delete(:sources) || []
@@ -85,6 +92,7 @@ module Bundler
@specs = nil
@ruby_version = ruby_version
@gemfiles = gemfiles
+ @overrides = overrides
@lockfile = lockfile
@lockfile_contents = String.new
@@ -99,14 +107,16 @@ module Bundler
if lockfile_exists?
@lockfile_contents = Bundler.read_file(lockfile)
- @locked_gems = LockfileParser.new(@lockfile_contents)
+ @locked_gems = LockfileParser.new(@lockfile_contents, strict: strict)
@locked_platforms = @locked_gems.platforms
@most_specific_locked_platform = @locked_gems.most_specific_locked_platform
@platforms = @locked_platforms.dup
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
@locked_deps = @locked_gems.dependencies
+ Override.attach(@locked_gems.specs, @overrides)
@originally_locked_specs = SpecSet.new(@locked_gems.specs)
+ @originally_locked_sources = @locked_gems.sources
@locked_checksums = @locked_gems.checksums
if @unlocking_all
@@ -114,7 +124,16 @@ module Bundler
@locked_sources = []
else
@locked_specs = @originally_locked_specs
- @locked_sources = @locked_gems.sources
+ @locked_sources = @originally_locked_sources
+ end
+
+ locked_gem_sources = @originally_locked_sources.select {|s| s.is_a?(Source::Rubygems) }
+ multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes?
+
+ if multisource_lockfile
+ msg = "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::SharedHelpers.feature_removed! msg
end
else
@locked_gems = nil
@@ -123,22 +142,10 @@ module Bundler
@platforms = []
@locked_deps = {}
@locked_specs = SpecSet.new([])
- @originally_locked_specs = @locked_specs
@locked_sources = []
- @locked_checksums = Bundler.feature_flag.lockfile_checksums?
- end
-
- locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
- @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle?
-
- if @multisource_allowed
- unless sources.aggregate_global_source?
- msg = "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::SharedHelpers.major_deprecation 2, msg
- end
-
- @sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
+ @originally_locked_specs = @locked_specs
+ @originally_locked_sources = @locked_sources
+ @locked_checksums = Bundler.settings[:lockfile_checksums]
end
@unlocking_ruby ||= if @ruby_version && locked_ruby_version_object
@@ -189,12 +196,14 @@ module Bundler
def setup_domain!(options = {})
prefer_local! if options[:"prefer-local"]
+ sources.cached!
+
if options[:add_checksums] || (!options[:local] && install_needed?)
- remotely!
+ sources.remote!
true
else
Bundler.settings.set_command_option(:jobs, 1) unless install_needed? # to avoid the overhead of Bundler::Worker
- with_cache!
+ sources.local!
false
end
end
@@ -246,6 +255,7 @@ module Bundler
end
def missing_specs
+ preload_git_sources
resolve.missing_specs_for(requested_dependencies)
end
@@ -257,7 +267,7 @@ module Bundler
rescue BundlerError => e
@resolve = nil
@resolver = nil
- @resolution_packages = nil
+ @resolution_base = nil
@source_requirements = nil
@specs = nil
@@ -282,12 +292,17 @@ module Bundler
end
def filter_relevant(dependencies)
- platforms_array = [generic_local_platform].freeze
dependencies.select do |d|
- d.should_include? && !d.gem_platforms(platforms_array).empty?
+ relevant_deps?(d)
end
end
+ def relevant_deps?(dep)
+ platforms_array = [Bundler.generic_local_platform].freeze
+
+ dep.should_include? && !dep.gem_platforms(platforms_array).empty?
+ end
+
def locked_dependencies
@locked_deps.values
end
@@ -337,11 +352,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 resolve_needed_reason
start_resolution
end
@@ -371,12 +382,50 @@ module Bundler
msg = "`Definition#lock` was passed a target file argument. #{suggestion}"
- Bundler::SharedHelpers.major_deprecation 2, msg
+ Bundler::SharedHelpers.feature_removed! msg
end
write_lock(target_lockfile, preserve_unknown_sections)
end
+ def write_lock(file, preserve_unknown_sections)
+ return if Definition.no_lock || !lockfile || 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
+
+ begin
+ SharedHelpers.filesystem_access(file) do |p|
+ File.open(p, "wb") {|f| f.puts(contents) }
+ end
+ rescue ReadOnlyFileSystemError
+ raise ProductionError, lockfile_changes_summary("file system is read-only")
+ end
+ end
+
def locked_ruby_version
return unless ruby_version
if @unlocking_ruby || !@locked_ruby_version
@@ -444,12 +493,6 @@ module Bundler
"Your Ruby version is #{actual}, but your Gemfile specified #{expected}"
when :engine_version
"Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
- when :patchlevel
- if !expected.is_a?(String)
- "The Ruby patchlevel in your Gemfile must be a string"
- else
- "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
- end
end
raise RubyVersionMismatch, msg
@@ -460,12 +503,12 @@ module Bundler
return if current_platform_locked? || @platforms.include?(Gem::Platform::RUBY)
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 normalize_platforms
- @platforms = resolve.normalize_platforms!(current_dependencies, platforms)
+ resolve.normalize_platforms!(current_dependencies, platforms)
@resolve = SpecSet.new(resolve.for(current_dependencies, @platforms))
end
@@ -496,14 +539,25 @@ module Bundler
@unlocking
end
- attr_writer :source_requirements
-
def add_checksums
+ require "rubygems/package"
+
@locked_checksums = true
setup_domain!(add_checksums: true)
- specs # force materialization to real specifications, so that checksums are fetched
+ # force materialization to real specifications, so that checksums are fetched
+ specs.each do |spec|
+ next unless spec.source.is_a?(Bundler::Source::Rubygems)
+ # Checksum was fetched from the compact index API.
+ next if !spec.source.checksum_store.missing?(spec) && !spec.source.checksum_store.empty?(spec)
+ # The gem isn't installed, can't compute the checksum.
+ next unless spec.loaded_from
+
+ package = Gem::Package.new(spec.source.cached_built_in_gem(spec))
+ checksum = Checksum.from_gem_package(package)
+ spec.source.checksum_store.register(spec, checksum)
+ end
end
private
@@ -537,9 +591,7 @@ module Bundler
return unless added.any? || deleted.any? || changed.any? || resolve_needed?
- reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile"
-
- msg = String.new("#{reason.capitalize.strip}, but ")
+ msg = String.new("#{change_reason[0].upcase}#{change_reason[1..-1].strip}, but ")
msg << "the lockfile " unless msg.start_with?("Your lockfile")
msg << "can't be updated because #{update_refused_reason}"
msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
@@ -565,6 +617,7 @@ module Bundler
@missing_lockfile_dep ||
@unlocking_bundler ||
@locked_spec_with_missing_checksums ||
+ @locked_spec_with_empty_checksums ||
@locked_spec_with_missing_deps ||
@locked_spec_with_invalid_deps
end
@@ -574,57 +627,32 @@ module Bundler
end
def should_add_extra_platforms?
- !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
+ !lockfile_exists? && Bundler::MatchPlatform.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
+ def resolver
+ @resolver ||= new_resolver(resolution_base)
+ end
- begin
- SharedHelpers.filesystem_access(file) do |p|
- File.open(p, "wb") {|f| f.puts(contents) }
- end
- rescue ReadOnlyFileSystemError
- raise ProductionError, lockfile_changes_summary("file system is read-only")
- end
+ def expanded_dependencies
+ apply_overrides_to(dependencies_with_bundler) + metadata_dependencies
end
- def resolver
- @resolver ||= Resolver.new(resolution_packages, gem_version_promoter, @most_specific_locked_platform)
+ def apply_overrides_to(deps)
+ return deps if @overrides.empty?
+ deps.map {|dep| apply_override_to(dep) }
end
- def expanded_dependencies
- dependencies_with_bundler + metadata_dependencies
+ def apply_override_to(dep)
+ override = Override.find_for(@overrides, dep.name, :version)
+ return dep unless override
+ new_dep = dep.dup
+ new_dep.instance_variable_set(:@requirement, override.apply_to(dep.requirement))
+ new_dep
end
def dependencies_with_bundler
@@ -634,15 +662,14 @@ module Bundler
[Dependency.new("bundler", @unlocking_bundler)] + dependencies
end
- def resolution_packages
- @resolution_packages ||= begin
+ def resolution_base
+ @resolution_base ||= begin
last_resolve = converge_locked_specs
remove_invalid_platforms!
- new_resolution_platforms = @current_platform_missing ? @new_platforms + [local_platform] : @new_platforms
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlocking_all || @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms)
- packages = additional_base_requirements_to_prevent_downgrades(packages)
- packages = additional_base_requirements_to_force_updates(packages)
- packages
+ base = new_resolution_base(last_resolve: last_resolve, unlock: @unlocking_all || @gems_to_unlock)
+ base = additional_base_requirements_to_prevent_downgrades(base)
+ base = additional_base_requirements_to_force_updates(base)
+ base
end
end
@@ -651,20 +678,12 @@ module Bundler
end
def materialize(dependencies)
- # Tracks potential endless loops trying to re-resolve.
- # TODO: Remove as dead code if not reports are received in a while
- incorrect_spec = nil
-
specs = begin
resolve.materialize(dependencies)
rescue IncorrectLockfileDependencies => e
raise if Bundler.frozen_bundle?
- spec = e.spec
- raise "Infinite loop while fixing lockfile dependencies" if incorrect_spec == spec
-
- incorrect_spec = spec
- reresolve_without([spec])
+ reresolve_without([e.spec])
retry
end
@@ -717,8 +736,7 @@ module Bundler
still_incomplete_specs = resolve.incomplete_specs
if still_incomplete_specs == incomplete_specs
- package = resolution_packages.get_package(incomplete_specs.first.name)
- resolver.raise_not_found! package
+ resolver.raise_incomplete! incomplete_specs
end
incomplete_specs = still_incomplete_specs
@@ -740,24 +758,31 @@ module Bundler
end
def reresolve_without(incomplete_specs)
- resolution_packages.delete(incomplete_specs)
+ resolution_base.delete(incomplete_specs)
@resolve = start_resolution
end
def start_resolution
- local_platform_needed_for_resolvability = @most_specific_non_local_locked_platform && !@platforms.include?(local_platform)
- @platforms << local_platform if local_platform_needed_for_resolvability
- add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
+ local_platform_needed_for_resolvability = @most_specific_non_local_locked_platform && !@platforms.include?(Bundler.local_platform)
+ @platforms << Bundler.local_platform if local_platform_needed_for_resolvability
result = SpecSet.new(resolver.start)
@resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
+ @new_platforms.each do |platform|
+ incomplete_specs = result.incomplete_specs_for_platform(current_dependencies, platform)
+
+ if incomplete_specs.any?
+ resolver.raise_incomplete! incomplete_specs
+ end
+ end
+
if @most_specific_non_local_locked_platform
- if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_platform)
+ if result.incomplete_for_platform?(current_dependencies, @most_specific_non_local_locked_platform)
@platforms.delete(@most_specific_non_local_locked_platform)
elsif local_platform_needed_for_resolvability
- @platforms.delete(local_platform)
+ @platforms.delete(Bundler.local_platform)
end
end
@@ -771,22 +796,40 @@ module Bundler
end
def precompute_source_requirements_for_indirect_dependencies?
- sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
+ if sources.non_global_rubygems_sources.all?(&:dependency_api_available?)
+ true
+ else
+ non_dependency_api_warning
+ false
+ end
+ end
+
+ def non_dependency_api_warning
+ non_api_sources = sources.non_global_rubygems_sources.reject(&:dependency_api_available?)
+ non_api_source_names = non_api_sources.map {|d| " * #{d}" }.join("\n")
+
+ msg = String.new
+ msg << "Your Gemfile contains scoped sources that don't implement a dependency API, namely:\n\n"
+ msg << non_api_source_names
+ msg << "\n\nUsing the above gem servers may result in installing unexpected gems. " \
+ "To resolve this warning, make sure you use gem servers that implement dependency APIs, " \
+ "such as gemstash or geminabox gem servers."
+ Bundler.ui.warn msg
end
def current_platform_locked?
@platforms.any? do |bundle_platform|
- generic_local_platform == bundle_platform || local_platform === bundle_platform
+ Bundler.generic_local_platform == bundle_platform || Bundler.local_platform === bundle_platform
end
end
def add_current_platform
- return if @platforms.include?(local_platform)
+ return if @platforms.include?(Bundler.local_platform)
@most_specific_non_local_locked_platform = find_most_specific_locked_platform
return if @most_specific_non_local_locked_platform
- @platforms << local_platform
+ @platforms << Bundler.local_platform
true
end
@@ -796,22 +839,47 @@ module Bundler
@most_specific_locked_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]
+ def resolve_needed_reason
+ if lockfile_exists?
+ if unlocking?
+ "Re-resolving dependencies because #{unlocking_reason}"
+ else
+ "Found changes from the lockfile, re-resolving dependencies because #{lockfile_changed_reason}"
end
+ else
+ "Resolving dependencies because there's no lockfile"
+ end
+ end
- unlock_reason = if unlock_targets
- "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
+ def change_reason
+ if resolve_needed?
+ if unlocking?
+ unlocking_reason
else
- @unlocking_ruby ? "ruby" : ""
+ lockfile_changed_reason
end
+ else
+ "some dependencies were deleted from your gemfile"
+ end
+ end
+
+ def unlocking_reason
+ unlock_targets = if @gems_to_unlock.any?
+ ["gems", @gems_to_unlock]
+ elsif @sources_to_unlock.any?
+ ["sources", @sources_to_unlock]
+ end
- return "bundler is unlocking #{unlock_reason}"
+ unlock_reason = if unlock_targets
+ "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
+ else
+ @unlocking_ruby ? "ruby" : ""
end
+
+ "bundler is unlocking #{unlock_reason}"
+ end
+
+ def lockfile_changed_reason
[
[@source_changes, "the list of sources changed"],
[@dependency_changes, "the dependencies in your gemfile changed"],
@@ -822,6 +890,7 @@ module Bundler
[@missing_lockfile_dep, "your lockfile is missing \"#{@missing_lockfile_dep}\""],
[@unlocking_bundler, "an update to the version of Bundler itself was requested"],
[@locked_spec_with_missing_checksums, "your lockfile is missing a CHECKSUMS entry for \"#{@locked_spec_with_missing_checksums}\""],
+ [@locked_spec_with_empty_checksums, "your lockfile has an empty CHECKSUMS entry for \"#{@locked_spec_with_empty_checksums}\""],
[@locked_spec_with_missing_deps, "your lockfile 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}\""],
].select(&:first).map(&:last).join(", ")
@@ -881,13 +950,23 @@ module Bundler
@locked_spec_with_invalid_deps = nil
@locked_spec_with_missing_deps = nil
@locked_spec_with_missing_checksums = nil
+ @locked_spec_with_empty_checksums = nil
missing_deps = []
missing_checksums = []
+ empty_checksums = []
invalid = []
@locked_specs.each do |s|
- missing_checksums << s if @locked_checksums && s.source.checksum_store.missing?(s)
+ if @locked_checksums
+ checksum_store = s.source.checksum_store
+
+ if checksum_store.missing?(s)
+ missing_checksums << s
+ elsif checksum_store.empty?(s)
+ empty_checksums << s
+ end
+ end
validation = @locked_specs.validate_deps(s)
@@ -896,6 +975,7 @@ module Bundler
end
@locked_spec_with_missing_checksums = missing_checksums.first.name if missing_checksums.any?
+ @locked_spec_with_empty_checksums = empty_checksums.first.name if empty_checksums.any?
if missing_deps.any?
@locked_specs.delete(missing_deps)
@@ -925,7 +1005,7 @@ module Bundler
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) }
+ if @locked_checksums && @locked_gems && locked_source = @originally_locked_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
@@ -939,6 +1019,8 @@ module Bundler
end
end
+ sources.metadata_source.checksum_store.merge!(@locked_gems.metadata_source.checksum_store) if @locked_gems
+
changes
end
@@ -946,10 +1028,11 @@ module Bundler
@missing_lockfile_dep = nil
@changed_dependencies = []
- current_dependencies.each do |dep|
+ @dependencies.each do |dep|
if dep.source
dep.source = sources.get(dep.source)
end
+ next unless relevant_deps?(dep)
name = dep.name
@@ -965,7 +1048,7 @@ module Bundler
@locked_specs.delete(locked_specs.select {|s| s.source != dep.source })
end
- unless dep.matches_spec?(locked_specs.first)
+ unless apply_override_to(dep).matches_spec?(locked_specs.first)
@gems_to_unlock << name
dep_changed = true
end
@@ -975,9 +1058,32 @@ module Bundler
@changed_dependencies << name if dep_changed
end
+ converge_overrides_outside_dependencies
+
@changed_dependencies.any?
end
+ def converge_overrides_outside_dependencies
+ @overrides.each do |override|
+ # :all overrides are intentionally not pre-unlocked. They take effect on
+ # fresh resolution (no lockfile) or when the user runs `bundle update`.
+ # Forcing a full re-resolve from a single :all directive would surprise
+ # users with unrelated dependency churn.
+ next unless override.target.is_a?(String)
+
+ name = override.target
+ next if @changed_dependencies.include?(name)
+ next if @originally_locked_specs[name].empty?
+ # version: overrides on direct deps are detected in the per-dep
+ # converge_dependencies loop via apply_override_to + matches_spec?.
+ # Other fields are not visible there, so they always reach here.
+ next if override.field == :version && @dependencies.any? {|d| d.name == name }
+
+ @gems_to_unlock << name
+ @changed_dependencies << name
+ end
+ end
+
# Remove elements from the locked specs that are expired. This will most
# commonly happen if the Gemfile has changed since the lockfile was last
# generated
@@ -1007,26 +1113,43 @@ module Bundler
specs.each do |s|
name = s.name
+ next if @gems_to_unlock.include?(name)
+
dep = @dependencies.find {|d| s.satisfies?(d) }
lockfile_source = s.source
if dep
- gemfile_source = dep.source || default_source
-
- deps << dep if !dep.source || lockfile_source.include?(dep.source) || new_deps.include?(dep)
+ replacement_source = dep.source
- # Replace the locked dependency's source with the equivalent source from the Gemfile
- s.source = gemfile_source
+ deps << dep if !replacement_source || lockfile_source.include?(replacement_source) || new_deps.include?(dep)
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)
+ parent_dep = @dependencies.find do |d|
+ next unless d.source && d.source != lockfile_source
+ next if d.source.is_a?(Source::Gemspec)
+
+ parent_locked_specs = @originally_locked_specs[d.name]
+
+ parent_locked_specs.any? do |parent_spec|
+ parent_spec.runtime_dependencies.any? {|rd| rd.name == s.name }
+ end
+ end
+
+ if parent_dep && parent_dep.source.is_a?(Source::Path) && parent_dep.source.specs[s]&.any?
+ replacement_source = parent_dep.source
+ else
+ replacement_source = sources.get(lockfile_source)
+ end
end
+ # Replace the locked dependency's source with the equivalent source from the Gemfile
+ s.source = replacement_source || default_source
+ next if s.source_changed?
+
source = s.source
next if @sources_to_unlock.include?(source.name)
# Path sources have special logic
- if source.instance_of?(Source::Path) || source.instance_of?(Source::Gemspec) || (source.instance_of?(Source::Git) && !@gems_to_unlock.include?(name) && deps.include?(dep))
+ if source.is_a?(Source::Path)
new_spec = source.specs[s].first
if new_spec
s.runtime_dependencies.replace(new_spec.runtime_dependencies)
@@ -1054,17 +1177,56 @@ module Bundler
@source_requirements ||= find_source_requirements
end
+ def preload_git_source_worker
+ workers = Bundler.settings.installation_parallelization
+
+ @preload_git_source_worker ||= Bundler::Worker.new(workers, "Git source preloading", ->(source, _) { source.specs })
+ end
+
+ def preload_git_sources
+ if Gem.ruby_version < Gem::Version.new("3.3")
+ # Ruby 3.2 has a bug that incorrectly triggers a circular dependency warning. This version will continue to
+ # fetch git repositories one by one.
+ return
+ end
+
+ begin
+ needed_git_sources.each {|source| preload_git_source_worker.enq(source) }
+ ensure
+ preload_git_source_worker.stop
+ end
+ end
+
+ # Git sources needed for the requested groups (excludes sources only used by --without groups)
+ def needed_git_sources
+ needed_deps = dependencies_for(requested_groups)
+ sources.git_sources.select do |source|
+ needed_deps.any? {|d| d.source == source }
+ end
+ end
+
+ # Git sources that should be excluded (only used by --without groups)
+ def excluded_git_sources
+ sources.git_sources - needed_git_sources
+ end
+
def find_source_requirements
+ preload_git_sources
+
+ # Only safe to exclude when locked_requirements (merged below) backfills the gap.
+ nothing_changed = nothing_changed?
+ excluded = nothing_changed ? excluded_git_sources : []
+
# 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
+ all_requirements = source_map.all_requirements(excluded)
{ default: 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, excluded) }.merge(source_map.direct_requirements)
end
- source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
+ source_requirements.merge!(source_map.locked_requirements) if nothing_changed
metadata_dependencies.each do |dep|
source_requirements[dep.name] = sources.metadata_source
end
@@ -1105,66 +1267,63 @@ module Bundler
current == proposed
end
- def additional_base_requirements_to_prevent_downgrades(resolution_packages)
- return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
+ def additional_base_requirements_to_prevent_downgrades(resolution_base)
+ return resolution_base unless @locked_gems
@originally_locked_specs.each do |locked_spec|
- next if locked_spec.source.is_a?(Source::Path)
+ next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed?
name = locked_spec.name
next if @changed_dependencies.include?(name)
- resolution_packages.base_requirements[name] = Gem::Requirement.new(">= #{locked_spec.version}")
+ resolution_base.base_requirements[name] = Gem::Requirement.new(">= #{locked_spec.version}")
end
- resolution_packages
+ resolution_base
end
- def additional_base_requirements_to_force_updates(resolution_packages)
- return resolution_packages if @explicit_unlocks.empty?
- full_update = dup_for_full_unlock.resolve
+ def additional_base_requirements_to_force_updates(resolution_base)
+ return resolution_base if @explicit_unlocks.empty?
+ full_update = SpecSet.new(new_resolver_for_full_update.start)
@explicit_unlocks.each do |name|
version = full_update.version_for(name)
- resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
+ resolution_base.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
+ resolution_base
end
def remove_invalid_platforms!
return if Bundler.frozen_bundle?
- @originally_invalid_platforms = platforms.select do |platform|
- next if local_platform == platform ||
- @new_platforms.include?(platform)
+ skips = (@new_platforms + [Bundler.local_platform]).uniq
- # We should probably avoid removing non-ruby platforms, since that means
- # lockfile will no longer install on those platforms, so a error to give
- # heads up to the user may be better. However, we have tests expecting
- # non ruby platform autoremoval to work, so leaving that in place for
- # now.
- next if @dependency_changes && platform != Gem::Platform::RUBY
+ # We should probably avoid removing non-ruby platforms, since that means
+ # lockfile will no longer install on those platforms, so a error to give
+ # heads up to the user may be better. However, we have tests expecting
+ # non ruby platform autoremoval to work, so leaving that in place for
+ # now.
+ skips |= platforms - [Gem::Platform::RUBY] if @dependency_changes
- spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
- end
+ @originally_invalid_platforms = @originally_locked_specs.remove_invalid_platforms!(current_dependencies, platforms, skips: skips)
+ end
- @platforms -= @originally_invalid_platforms
+ def source_map
+ @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
end
- def spec_set_incomplete_for_platform?(spec_set, platform)
- spec_set.incomplete_for_platform?(current_dependencies, platform)
+ def new_resolver_for_full_update
+ new_resolver(unlocked_resolution_base)
end
- def source_map
- @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
+ def unlocked_resolution_base
+ new_resolution_base(last_resolve: SpecSet.new([]), unlock: true)
+ end
+
+ def new_resolution_base(last_resolve:, unlock:)
+ new_resolution_platforms = @current_platform_missing ? @new_platforms + [Bundler.local_platform] : @new_platforms
+ Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms, overrides: @overrides)
+ end
+
+ def new_resolver(base)
+ Resolver.new(base, gem_version_promoter, @most_specific_locked_platform)
end
end
end
diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb
index e81696ff42..cb9c7a76ea 100644
--- a/lib/bundler/dependency.rb
+++ b/lib/bundler/dependency.rb
@@ -99,7 +99,7 @@ module Bundler
return RUBY_PLATFORM_ARRAY if force_ruby_platform
return valid_platforms if platforms.empty?
- valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) }
+ valid_platforms.select {|p| expanded_platforms.include?(Gem::Platform.generic(p)) }
end
def expanded_platforms
diff --git a/lib/bundler/deployment.rb b/lib/bundler/deployment.rb
index b432ae6ae1..3344449e82 100644
--- a/lib/bundler/deployment.rb
+++ b/lib/bundler/deployment.rb
@@ -1,69 +1,6 @@
# frozen_string_literal: true
require_relative "shared_helpers"
-Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \
+Bundler::SharedHelpers.feature_removed! "Bundler no longer integrates with " \
"Capistrano, but Capistrano provides its own integration with " \
"Bundler via the capistrano-bundler gem. Use it instead."
-
-module Bundler
- class Deployment
- def self.define_task(context, task_method = :task, opts = {})
- if defined?(Capistrano) && context.is_a?(Capistrano::Configuration)
- context_name = "capistrano"
- role_default = "{:except => {:no_release => true}}"
- error_type = ::Capistrano::CommandError
- else
- context_name = "vlad"
- role_default = "[:app]"
- error_type = ::Rake::CommandFailedError
- end
-
- roles = context.fetch(:bundle_roles, false)
- opts[:roles] = roles if roles
-
- context.send :namespace, :bundle do
- send :desc, <<-DESC
- Install the current Bundler environment. By default, gems will be \
- installed to the shared/bundle path. Gems in the development and \
- test group will not be installed. The install command is executed \
- with the --deployment and --quiet flags. If the bundle cmd cannot \
- be found then you can override the bundle_cmd variable to specify \
- which one it should use. The base path to the app is fetched from \
- the :latest_release variable. Set it for custom deploy layouts.
-
- You can override any of these defaults by setting the variables shown below.
-
- N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \
- in your deploy.rb file.
-
- set :bundle_gemfile, "Gemfile"
- set :bundle_dir, File.join(fetch(:shared_path), 'bundle')
- set :bundle_flags, "--deployment --quiet"
- set :bundle_without, [:development, :test]
- set :bundle_with, [:mysql]
- set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle"
- set :bundle_roles, #{role_default} # e.g. [:app, :batch]
- DESC
- send task_method, :install, opts do
- bundle_cmd = context.fetch(:bundle_cmd, "bundle")
- bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet")
- bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle"))
- bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile")
- bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact
- bundle_with = [*context.fetch(:bundle_with, [])].compact
- app_path = context.fetch(:latest_release)
- if app_path.to_s.empty?
- raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.")
- end
- args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"]
- args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty?
- args << bundle_flags.to_s
- args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty?
- args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty?
-
- run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}"
- end
- end
- end
- end
-end
diff --git a/lib/bundler/digest.rb b/lib/bundler/digest.rb
index 2c6d971f1b..158803033d 100644
--- a/lib/bundler/digest.rb
+++ b/lib/bundler/digest.rb
@@ -26,7 +26,7 @@ module Bundler
end
a, b, c, d, e = *words
(16..79).each do |i|
- w[i] = SHA1_MASK & rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1)
+ w[i] = SHA1_MASK & rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1)
end
0.upto(79) do |i|
case i
diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb
index 32f45d97ec..6e2638a8be 100644
--- a/lib/bundler/dsl.rb
+++ b/lib/bundler/dsl.rb
@@ -9,8 +9,9 @@ module Bundler
def self.evaluate(gemfile, lockfile, unlock)
builder = new
+ builder.lockfile(lockfile)
builder.eval_gemfile(gemfile)
- builder.to_definition(lockfile, unlock)
+ builder.to_definition(builder.lockfile_path, unlock)
end
VALID_PLATFORMS = Bundler::CurrentRuby::PLATFORM_MAP.keys.freeze
@@ -21,7 +22,7 @@ module Bundler
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}
- attr_reader :gemspecs, :gemfile
+ attr_reader :gemspecs, :gemfile, :overrides
attr_accessor :dependencies
def initialize
@@ -38,6 +39,8 @@ module Bundler
@gemspecs = []
@gemfile = nil
@gemfiles = []
+ @lockfile = nil
+ @overrides = []
add_git_sources
end
@@ -73,7 +76,7 @@ module Bundler
case specs_by_name_and_version.size
when 1
specs = specs_by_name_and_version.values.first
- spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first
+ spec = specs.find {|s| s.installable_on_platform?(Bundler.local_platform) } || specs.first
@gemspecs << spec
@@ -101,10 +104,23 @@ module Bundler
add_dependency(name, version, options)
end
+ # For usage in Dsl.evaluate, since lockfile is used as part of the Gemfile.
+ def lockfile_path
+ @lockfile
+ end
+
+ def lockfile(file)
+ @lockfile = file
+ end
+
def source(source, *args, &blk)
options = args.last.is_a?(Hash) ? args.pop.dup : {}
options = normalize_hash(options)
source = normalize_source(source)
+ cooldown = options["cooldown"]
+ if cooldown && !(cooldown.is_a?(Integer) && cooldown >= 0)
+ raise InvalidOption, "Expected `cooldown` to be a non-negative integer, got #{cooldown.inspect}"
+ end
if options.key?("type")
options["type"] = options["type"].to_s
@@ -119,9 +135,9 @@ module Bundler
source_opts = options.merge("uri" => source)
with_source(@sources.add_plugin_source(options["type"], source_opts), &blk)
elsif block_given?
- with_source(@sources.add_rubygems_source("remotes" => source), &blk)
+ with_source(@sources.add_rubygems_source("remotes" => source, "cooldown" => cooldown), &blk)
else
- @sources.add_global_rubygems_remote(source)
+ @sources.add_global_rubygems_remote(source, cooldown: cooldown)
end
end
@@ -173,9 +189,32 @@ module Bundler
with_source(git_source) { yield }
end
+ SUPPORTED_OVERRIDE_FIELDS = [:version, :required_ruby_version, :required_rubygems_version].freeze
+ SUPPORTED_OVERRIDE_SYMBOL_OPERATIONS = [:ignore_upper].freeze
+
+ def override(target, **operations)
+ validate_override_target!(target)
+
+ if target == :all && operations.key?(:version)
+ raise ArgumentError, "`override :all, version:` is not allowed; version requirements are per-gem"
+ end
+
+ operations.each do |field, operation|
+ validate_override_field!(field)
+ validate_override_operation!(operation)
+ validate_override_uniqueness!(target, field)
+ end
+
+ source_location = caller_locations(1, 1)&.first
+ operations.each do |field, operation|
+ @overrides << Override.new(target, field, operation, source_location: source_location)
+ end
+ end
+
def to_definition(lockfile, unlock)
check_primary_source_safety
- Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles)
+ lockfile = @lockfile unless @lockfile.nil?
+ Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles, @overrides)
end
def group(*args, &blk)
@@ -232,6 +271,39 @@ module Bundler
private
+ def validate_override_target!(target)
+ return if target == :all
+ return if target.is_a?(String)
+ raise ArgumentError, "override target must be :all or a gem name string, got #{target.inspect}"
+ end
+
+ def validate_override_field!(field)
+ return if SUPPORTED_OVERRIDE_FIELDS.include?(field)
+ supported = SUPPORTED_OVERRIDE_FIELDS.map {|f| "`#{f}:`" }.join(", ")
+ raise ArgumentError, "unsupported override field `#{field}:`; supported fields: #{supported}"
+ end
+
+ def validate_override_operation!(operation)
+ case operation
+ when String
+ Gem::Requirement.new(operation)
+ when nil
+ # ok
+ when Symbol
+ return if SUPPORTED_OVERRIDE_SYMBOL_OPERATIONS.include?(operation)
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
+ else
+ raise ArgumentError, "override operation must be a String, Symbol, or nil, got #{operation.inspect}"
+ end
+ rescue Gem::Requirement::BadRequirementError => e
+ raise ArgumentError, "invalid override version requirement #{operation.inspect}: #{e.message}"
+ end
+
+ def validate_override_uniqueness!(target, field)
+ return unless @overrides.any? {|o| o.target == target && o.field == field }
+ raise ArgumentError, "duplicate override for #{target.inspect} `#{field}:`"
+ end
+
def add_dependency(name, version = nil, options = {})
options["gemfile"] = @gemfile
options["source"] ||= @source
@@ -290,7 +362,7 @@ module Bundler
@dependencies.delete(current)
elsif dep.gemspec_dev_dep?
return
- elsif current.source != dep.source
+ elsif current.source.to_s != dep.source.to_s
raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
"You specified that #{name} (#{dep.requirement}) should come from " \
"#{current.source || "an unspecified source"} and #{dep.source}\n"
@@ -411,7 +483,13 @@ module Bundler
next if VALID_PLATFORMS.include?(p)
raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
end
- deprecate_legacy_windows_platforms(platforms)
+
+ windows_platforms = platforms.select {|pl| pl.to_s.match?(/mingw|mswin/) }
+ if windows_platforms.any?
+ windows_platforms = windows_platforms.map! {|pl| ":#{pl}" }.join(", ")
+ deprecated_message = "Platform #{windows_platforms} will be removed in the future. Please use platform :windows instead."
+ Bundler::SharedHelpers.feature_deprecated! deprecated_message
+ end
# Save sources passed in a key
if opts.key?("source")
@@ -477,14 +555,10 @@ 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
- "http://rubygems.org"
+ Bundler::SharedHelpers.feature_removed! removed_message
when String
source
else
@@ -492,16 +566,6 @@ module Bundler
end
end
- def deprecate_legacy_windows_platforms(platforms)
- windows_platforms = platforms.select {|pl| pl.to_s.match?(/mingw|mswin/) }
- return if windows_platforms.empty?
-
- windows_platforms = windows_platforms.map! {|pl| ":#{pl}" }.join(", ")
- message = "Platform #{windows_platforms} is deprecated. Please use platform :windows instead."
- removed_message = "Platform #{windows_platforms} has been removed. Please use platform :windows instead."
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
- end
-
def check_path_source_safety
return if @sources.global_path_source.nil?
@@ -513,7 +577,7 @@ module Bundler
" gem 'rails'\n" \
" end\n\n"
- SharedHelpers.major_deprecation(2, msg.strip)
+ SharedHelpers.feature_removed! msg.strip
end
def check_rubygems_source_safety
@@ -521,24 +585,10 @@ module Bundler
end
def multiple_global_source_warning
- if Bundler.feature_flag.bundler_3_mode?
- msg = "This Gemfile contains multiple global sources. " \
- "Each source after the first must include a block to indicate which gems " \
- "should come from that source"
- raise GemfileEvalError, msg
- else
- 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 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
+ msg = "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
+ raise GemfileEvalError, msg
end
class DSLError < GemfileError
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index c06684657d..7c7ce107e2 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -5,7 +5,7 @@ module Bundler
class EndpointSpecification < Gem::Specification
include MatchRemoteMetadata
- attr_reader :name, :version, :platform, :checksum
+ attr_reader :name, :version, :platform, :checksum, :created_at
attr_writer :dependencies
attr_accessor :remote, :locked_platform
@@ -145,6 +145,7 @@ module Bundler
unless data
@required_ruby_version = nil
@required_rubygems_version = nil
+ @created_at = nil
return
end
@@ -161,6 +162,15 @@ module Bundler
@required_rubygems_version = Gem::Requirement.new(v)
when "ruby"
@required_ruby_version = Gem::Requirement.new(v)
+ when "created_at"
+ value = v.is_a?(Array) ? v.last : v
+ if value.is_a?(String)
+ @created_at = begin
+ Time.new(value)
+ rescue ArgumentError
+ nil
+ end
+ end
end
end
rescue StandardError => e
diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb
index 444ab6fd37..bf9478a299 100644
--- a/lib/bundler/environment_preserver.rb
+++ b/lib/bundler/environment_preserver.rb
@@ -6,6 +6,7 @@ module Bundler
BUNDLER_KEYS = %w[
BUNDLE_BIN_PATH
BUNDLE_GEMFILE
+ BUNDLE_LOCKFILE
BUNDLER_VERSION
BUNDLER_SETUP
GEM_HOME
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index 4d1bface51..dff5d93128 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -25,6 +25,7 @@ module Bundler
class GemNotFound < BundlerError; status_code(7); end
class InstallHookError < BundlerError; status_code(8); end
+ class RemovedError < BundlerError; status_code(9); end
class GemfileNotFound < BundlerError; status_code(10); end
class GitError < BundlerError; status_code(11); end
class DeprecatedError < BundlerError; status_code(12); end
@@ -76,11 +77,6 @@ module Bundler
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
@@ -135,7 +131,8 @@ module Bundler
attr_reader :orig_exception
def initialize(orig_exception, msg)
- full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\
+ full_message = msg + "\nGem Load Error is:
+ #{orig_exception.full_message(highlight: false)}\n"\
"Backtrace for gem load error is:\n"\
"#{orig_exception.backtrace.join("\n")}\n"\
"Bundler Error Backtrace:\n"
@@ -225,7 +222,9 @@ module Bundler
class DirectoryRemovalError < BundlerError
def initialize(orig_exception, msg)
full_message = "#{msg}.\n" \
- "The underlying error was #{orig_exception.class}: #{orig_exception.message}, with backtrace:\n" \
+ "The underlying error was #{orig_exception.class}:
+ #{orig_exception.full_message(highlight: false)},
+ with backtrace:\n" \
" #{orig_exception.backtrace.join("\n ")}\n\n" \
"Bundler Error Backtrace:"
super(full_message)
@@ -266,14 +265,40 @@ module Bundler
class InvalidArgumentError < BundlerError; status_code(40); end
class IncorrectLockfileDependencies < BundlerError
- attr_reader :spec
+ attr_reader :spec, :actual_dependencies, :lockfile_dependencies
- def initialize(spec)
+ def initialize(spec, actual_dependencies = nil, lockfile_dependencies = nil)
@spec = spec
+ @actual_dependencies = actual_dependencies
+ @lockfile_dependencies = lockfile_dependencies
end
def message
- "Bundler found incorrect dependencies in the lockfile for #{spec.full_name}"
+ lines = ["Bundler found incorrect dependencies in the lockfile for #{spec.full_name}", ""]
+
+ if @actual_dependencies && @lockfile_dependencies
+ actual_by_name = @actual_dependencies.each_with_object({}) {|d, h| h[d.name] = d }
+ lockfile_by_name = @lockfile_dependencies.each_with_object({}) {|d, h| h[d.name] = d }
+
+ (actual_by_name.keys | lockfile_by_name.keys).sort.each do |name|
+ actual = actual_by_name[name]
+ lockfile = lockfile_by_name[name]
+ next if actual && lockfile && actual.requirement == lockfile.requirement
+
+ if actual && lockfile
+ lines << " #{name}: gemspec specifies #{actual.requirement}, lockfile has #{lockfile.requirement}"
+ elsif actual
+ lines << " #{name}: gemspec specifies #{actual.requirement}, not in lockfile"
+ else
+ lines << " #{name}: not in gemspec, lockfile has #{lockfile.requirement}"
+ end
+ end
+
+ lines << ""
+ end
+
+ lines << "Please run `bundle install` to regenerate the lockfile."
+ lines.join("\n")
end
status_code(41)
diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb
index b19cf42cc3..dea8abedba 100644
--- a/lib/bundler/feature_flag.rb
+++ b/lib/bundler/feature_flag.rb
@@ -2,45 +2,15 @@
module Bundler
class FeatureFlag
- def self.settings_flag(flag, &default)
- unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s)
- raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key"
- end
-
- settings_method("#{flag}?", flag, &default)
- end
- private_class_method :settings_flag
+ (1..10).each {|v| define_method("bundler_#{v}_mode?") { @major_version >= v } }
- def self.settings_option(key, &default)
- settings_method(key, key, &default)
+ def removed_major?(target_major_version)
+ @major_version > target_major_version
end
- private_class_method :settings_option
- def self.settings_method(name, key, &default)
- define_method(name) do
- value = Bundler.settings[key]
- value = instance_eval(&default) if value.nil?
- value
- end
+ def deprecated_major?(target_major_version)
+ @major_version >= target_major_version
end
- private_class_method :settings_method
-
- (1..10).each {|v| define_method("bundler_#{v}_mode?") { @major_version >= v } }
-
- settings_flag(:allow_offline_install) { bundler_3_mode? }
- settings_flag(:auto_clean_without_path) { bundler_3_mode? }
- settings_flag(:cache_all) { bundler_3_mode? }
- settings_flag(:default_install_uses_path) { bundler_3_mode? }
- settings_flag(:forget_cli_options) { bundler_3_mode? }
- settings_flag(:global_gem_cache) { bundler_3_mode? }
- settings_flag(:lockfile_checksums) { bundler_3_mode? }
- settings_flag(:path_relative_to_cwd) { bundler_3_mode? }
- 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(:update_requires_all_flag) { bundler_4_mode? }
-
- settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install }
def initialize(bundler_version)
@bundler_version = Gem::Version.create(bundler_version)
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index 9d7e8e1aca..0b6ced6f39 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -2,7 +2,6 @@
require_relative "vendored_persistent"
require_relative "vendored_timeout"
-require "cgi"
require_relative "vendored_securerandom"
require "zlib"
@@ -73,19 +72,57 @@ module Bundler
end
end
+ HTTP_ERRORS = (Downloader::HTTP_RETRYABLE_ERRORS + Downloader::HTTP_NON_RETRYABLE_ERRORS).freeze
+ deprecate_constant :HTTP_ERRORS
+
+ NET_ERRORS = [
+ :HTTPBadGateway,
+ :HTTPBadRequest,
+ :HTTPFailedDependency,
+ :HTTPForbidden,
+ :HTTPInsufficientStorage,
+ :HTTPMethodNotAllowed,
+ :HTTPMovedPermanently,
+ :HTTPNoContent,
+ :HTTPNotFound,
+ :HTTPNotImplemented,
+ :HTTPPreconditionFailed,
+ :HTTPRequestEntityTooLarge,
+ :HTTPRequestURITooLong,
+ :HTTPUnauthorized,
+ :HTTPUnprocessableEntity,
+ :HTTPUnsupportedMediaType,
+ :HTTPVersionNotSupported,
+ ].freeze
+ deprecate_constant :NET_ERRORS
+
# 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,
- :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed,
- :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound,
- :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge,
- :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
- :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
- FAIL_ERRORS = begin
- fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError]
- fail_errors << Gem::Requirement::BadRequirementError
- fail_errors.concat(NET_ERRORS.map {|e| Gem::Net.const_get(e) })
- end.freeze
+ FAIL_ERRORS = [
+ AuthenticationRequiredError,
+ BadAuthenticationError,
+ AuthenticationForbiddenError,
+ FallbackError,
+ SecurityError,
+ Gem::Requirement::BadRequirementError,
+ Gem::Net::HTTPBadGateway,
+ Gem::Net::HTTPBadRequest,
+ Gem::Net::HTTPFailedDependency,
+ Gem::Net::HTTPForbidden,
+ Gem::Net::HTTPInsufficientStorage,
+ Gem::Net::HTTPMethodNotAllowed,
+ Gem::Net::HTTPMovedPermanently,
+ Gem::Net::HTTPNoContent,
+ Gem::Net::HTTPNotFound,
+ Gem::Net::HTTPNotImplemented,
+ Gem::Net::HTTPPreconditionFailed,
+ Gem::Net::HTTPRequestEntityTooLarge,
+ Gem::Net::HTTPRequestURITooLong,
+ Gem::Net::HTTPUnauthorized,
+ Gem::Net::HTTPUnprocessableEntity,
+ Gem::Net::HTTPUnsupportedMediaType,
+ Gem::Net::HTTPVersionNotSupported,
+ ].freeze
class << self
attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries
@@ -294,13 +331,6 @@ module Bundler
paths.find {|path| File.file? path }
end
- HTTP_ERRORS = [
- Gem::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
- ].freeze
-
def bundler_cert_store
store = OpenSSL::X509::Store.new
ssl_ca_cert = Bundler.settings[:ssl_ca_cert] ||
diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb
index 6c82d57011..52168111fe 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -110,7 +110,7 @@ module Bundler
def call(path, headers)
fetcher.downloader.fetch(fetcher.fetch_uri + path, headers)
rescue NetworkDownError => e
- raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"]
+ raise unless 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)
end
diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb
index 0b807c9a4b..4f2414e33d 100644
--- a/lib/bundler/fetcher/dependency.rb
+++ b/lib/bundler/fetcher/dependency.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require_relative "base"
-require "cgi"
+require "cgi/escape"
+require "cgi/util" unless defined?(CGI::EscapeExt)
module Bundler
class Fetcher
@@ -49,7 +50,7 @@ module Bundler
def unmarshalled_dep_gems(gem_names)
gem_list = []
- gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names|
+ gem_names.each_slice(api_request_size) do |names|
marshalled_deps = downloader.fetch(dependency_api_uri(names)).body
gem_list.concat(Bundler.safe_load_marshal(marshalled_deps))
end
@@ -73,6 +74,12 @@ module Bundler
uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any?
uri
end
+
+ private
+
+ def api_request_size
+ Bundler.settings[:api_request_size]&.to_i || Source::Rubygems::API_REQUEST_SIZE
+ end
end
end
end
diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb
index 868b39b959..179eed8340 100644
--- a/lib/bundler/fetcher/downloader.rb
+++ b/lib/bundler/fetcher/downloader.rb
@@ -3,6 +3,28 @@
module Bundler
class Fetcher
class Downloader
+ HTTP_NON_RETRYABLE_ERRORS = [
+ SocketError,
+ Errno::EADDRNOTAVAIL,
+ Errno::ENETDOWN,
+ Errno::ENETUNREACH,
+ Gem::Net::HTTP::Persistent::Error,
+ Errno::EHOSTUNREACH,
+ ].freeze
+
+ HTTP_RETRYABLE_ERRORS = [
+ Gem::Timeout::Error,
+ EOFError,
+ Errno::EINVAL,
+ Errno::ECONNRESET,
+ Errno::ETIMEDOUT,
+ Errno::EAGAIN,
+ Gem::Net::HTTPBadResponse,
+ Gem::Net::HTTPHeaderSyntaxError,
+ Gem::Net::ProtocolError,
+ Zlib::BufError,
+ ].freeze
+
attr_reader :connection
attr_reader :redirect_limit
@@ -32,7 +54,6 @@ module Bundler
when Gem::Net::HTTPRequestedRangeNotSatisfiable
new_headers = headers.dup
new_headers.delete("Range")
- new_headers["Accept-Encoding"] = "gzip"
fetch(uri, new_headers)
when Gem::Net::HTTPRequestEntityTooLarge
raise FallbackError, response.body
@@ -67,15 +88,19 @@ module Bundler
connection.request(uri, req)
rescue OpenSSL::SSL::SSLError
raise CertificateFailureError.new(uri)
- rescue *HTTP_ERRORS => e
+ rescue *HTTP_NON_RETRYABLE_ERRORS => e
Bundler.ui.trace e
- if e.is_a?(SocketError) || e.message.to_s.include?("host down:")
- raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \
- "connection and try again."
- else
- raise HTTPError, "Network error while fetching #{filtered_uri}" \
+
+ host = uri.host
+ host_port = "#{host}:#{uri.port}"
+ host = host_port if filtered_uri.to_s.include?(host_port)
+ raise NetworkDownError, "Could not reach host #{host}. Check your network " \
+ "connection and try again."
+ rescue *HTTP_RETRYABLE_ERRORS => e
+ Bundler.ui.trace e
+
+ raise HTTPError, "Network error while fetching #{filtered_uri}" \
" (#{e})"
- end
end
private
diff --git a/lib/bundler/fetcher/gem_remote_fetcher.rb b/lib/bundler/fetcher/gem_remote_fetcher.rb
index 3fc7b68263..3159e05688 100644
--- a/lib/bundler/fetcher/gem_remote_fetcher.rb
+++ b/lib/bundler/fetcher/gem_remote_fetcher.rb
@@ -5,6 +5,12 @@ require "rubygems/remote_fetcher"
module Bundler
class Fetcher
class GemRemoteFetcher < Gem::RemoteFetcher
+ def initialize(*)
+ super
+
+ @pool_size = Bundler.settings.installation_parallelization
+ end
+
def request(*args)
super do |req|
req.delete("User-Agent") if headers["User-Agent"]
diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb
index e61ed64450..5e8eaee6bb 100644
--- a/lib/bundler/friendly_errors.rb
+++ b/lib/bundler/friendly_errors.rb
@@ -80,7 +80,7 @@ module Bundler
First, try this link to see if there are any existing issue reports for this error:
#{issues_url(e)}
- If there aren't any reports for this error yet, please fill in the new issue form located at #{new_issue_url}, and copy and paste the report template above in there.
+ If there aren't any reports for this error yet, please fill in the new issue form located at #{new_issue_url}. Make sure to copy and paste the full output of this command under the "What happened instead?" section.
EOS
end
@@ -102,13 +102,14 @@ module Bundler
def issues_url(exception)
message = exception.message.lines.first.tr(":", " ").chomp
message = message.split("-").first if exception.is_a?(Errno)
- require "cgi"
- "https://github.com/rubygems/rubygems/search?q=" \
+ require "cgi/escape"
+ require "cgi/util" unless defined?(CGI::EscapeExt)
+ "https://github.com/ruby/rubygems/search?q=" \
"#{CGI.escape(message)}&type=Issues"
end
def new_issue_url
- "https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md"
+ "https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md"
end
end
diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb
deleted file mode 100644
index ad12bf89a4..0000000000
--- a/lib/bundler/gem_helpers.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module GemHelpers
- GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant
- GENERICS = [
- Gem::Platform::JAVA,
- *Gem::Platform::WINDOWS,
- ].freeze
-
- def generic(p)
- GENERIC_CACHE[p] ||= begin
- found = GENERICS.find do |match|
- p === match
- end
- found || Gem::Platform::RUBY
- end
- end
- module_function :generic
-
- def generic_local_platform
- generic(local_platform)
- end
- module_function :generic_local_platform
-
- def local_platform
- Bundler.local_platform
- 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)
-
- PlatformMatch.specificity_score(spec_platform, user_platform)
- end
- module_function :platform_specificity_match
-
- def select_all_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
-
- matching
- end
- module_function :select_all_platform_match
-
- def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
- matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked)
-
- sort_and_filter_best_platform_match(matching, platform)
- end
- module_function :select_best_platform_match
-
- def select_best_local_platform_match(specs, force_ruby: false)
- matching = select_all_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
-
- sort_best_platform_match(matching, local_platform)
- end
- module_function :select_best_local_platform_match
-
- def sort_and_filter_best_platform_match(matching, platform)
- return matching if matching.one?
-
- exact = matching.select {|spec| spec.platform == platform }
- return exact if exact.any?
-
- sorted_matching = sort_best_platform_match(matching, platform)
- exemplary_spec = sorted_matching.first
-
- sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) }
- end
- module_function :sort_and_filter_best_platform_match
-
- def sort_best_platform_match(matching, platform)
- matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
- end
- module_function :sort_best_platform_match
-
- class PlatformMatch
- def self.specificity_score(spec_platform, user_platform)
- return -1 if spec_platform == user_platform
- return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
-
- os_match(spec_platform, user_platform) +
- cpu_match(spec_platform, user_platform) * 10 +
- platform_version_match(spec_platform, user_platform) * 100
- end
-
- def self.os_match(spec_platform, user_platform)
- if spec_platform.os == user_platform.os
- 0
- else
- 1
- end
- end
-
- def self.cpu_match(spec_platform, user_platform)
- if spec_platform.cpu == user_platform.cpu
- 0
- elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm")
- 0
- elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal"
- 1
- else
- 2
- end
- end
-
- def self.platform_version_match(spec_platform, user_platform)
- if spec_platform.version == user_platform.version
- 0
- elsif spec_platform.version.nil?
- 1
- else
- 2
- end
- end
- end
-
- def same_specificity(platform, spec, exemplary_spec)
- platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform)
- end
- module_function :same_specificity
-
- def same_deps(spec, exemplary_spec)
- same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort
- 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
- module_function :same_deps
- end
-end
diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb
deleted file mode 100644
index b22b17a453..0000000000
--- a/lib/bundler/graph.rb
+++ /dev/null
@@ -1,152 +0,0 @@
-# frozen_string_literal: true
-
-require "set"
-module Bundler
- class Graph
- GRAPH_NAME = :Gemfile
-
- def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = [])
- @env = env
- @output_file = output_file
- @show_version = show_version
- @show_requirements = show_requirements
- @output_format = output_format
- @without_groups = without.map(&:to_sym)
-
- @groups = []
- @relations = Hash.new {|h, k| h[k] = Set.new }
- @node_options = {}
- @edge_options = {}
-
- _populate_relations
- end
-
- attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format
-
- def viz
- GraphVizClient.new(self).run
- end
-
- private
-
- def _populate_relations
- parent_dependencies = _groups.values.to_set.flatten
- loop do
- break if parent_dependencies.empty?
-
- tmp = Set.new
- parent_dependencies.each do |dependency|
- child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set
- @relations[dependency.name] += child_dependencies.map(&:name).to_set
- tmp += child_dependencies
-
- @node_options[dependency.name] = _make_label(dependency, :node)
- child_dependencies.each do |c_dependency|
- @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
- end
- end
- parent_dependencies = tmp
- end
- end
-
- def _groups
- relations = Hash.new {|h, k| h[k] = Set.new }
- @env.current_dependencies.each do |dependency|
- dependency.groups.each do |group|
- next if @without_groups.include?(group)
-
- relations[group.to_s].add(dependency)
- @relations[group.to_s].add(dependency.name)
-
- @node_options[group.to_s] ||= _make_label(group, :node)
- @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge)
- end
- end
- @groups = relations.keys
- relations
- end
-
- def _make_label(symbol_or_string_or_dependency, element_type)
- case element_type.to_sym
- when :node
- if symbol_or_string_or_dependency.is_a?(Gem::Dependency)
- label = symbol_or_string_or_dependency.name.dup
- label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version
- else
- label = symbol_or_string_or_dependency.to_s
- end
- when :edge
- label = nil
- if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements
- tmp = symbol_or_string_or_dependency.requirements_list.join(", ")
- label = tmp if tmp != ">= 0"
- end
- else
- raise ArgumentError, "2nd argument is invalid"
- end
- label.nil? ? {} : { label: label }
- end
-
- def spec_for_dependency(dependency)
- @env.requested_specs.find {|s| s.name == dependency.name }
- end
-
- class GraphVizClient
- def initialize(graph_instance)
- @graph_name = graph_instance.class::GRAPH_NAME
- @groups = graph_instance.groups
- @relations = graph_instance.relations
- @node_options = graph_instance.node_options
- @edge_options = graph_instance.edge_options
- @output_file = graph_instance.output_file
- @output_format = graph_instance.output_format
- end
-
- def 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
- end
- end
-
- def run
- @groups.each do |group|
- g.add_nodes(
- group, {
- style: "filled",
- fillcolor: "#B9B9D5",
- shape: "box3d",
- fontsize: 16,
- }.merge(@node_options[group])
- )
- end
-
- @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}"]))
- else
- g.add_nodes(child, @node_options[child])
- g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
- end
- end
- end
-
- if @output_format.to_s == "debug"
- $stdout.puts g.output none: String
- Bundler.ui.info "debugging bundle viz..."
- else
- begin
- g.output @output_format.to_sym => "#{@output_file}.#{@output_format}"
- Bundler.ui.info "#{@output_file}.#{@output_format}"
- rescue ArgumentError => e
- warn "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb"
- raise e
- end
- end
- end
- end
- end
-end
diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb
index df46facc88..9aef2dfa12 100644
--- a/lib/bundler/index.rb
+++ b/lib/bundler/index.rb
@@ -46,13 +46,6 @@ 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) }
- end
-
# Search this index's specs, and any source indexes that this index knows
# about, returning all of the results.
def search(query)
@@ -131,6 +124,11 @@ module Bundler
return unless other
other.each do |spec|
if existing = find_by_spec(spec)
+ unless dependencies_eql?(existing, spec)
+ Bundler.ui.warn "Local specification for #{spec.full_name} has different dependencies than the remote gem, ignoring it"
+ next
+ end
+
add_duplicate(existing)
end
add spec
@@ -153,8 +151,8 @@ module Bundler
end
def dependencies_eql?(spec, other_spec)
- deps = spec.dependencies.select {|d| d.type != :development }
- other_deps = other_spec.dependencies.select {|d| d.type != :development }
+ deps = spec.runtime_dependencies
+ other_deps = other_spec.runtime_dependencies
deps.sort == other_deps.sort
end
diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb
index 21ff90ad13..6aa9179024 100644
--- a/lib/bundler/injector.rb
+++ b/lib/bundler/injector.rb
@@ -80,20 +80,19 @@ module Bundler
def conservative_version(spec)
version = spec.version
return ">= 0" if version.nil?
- 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?
- "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
+ "#{version_prefix}#{version.segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
end
def version_prefix
if @options[:strict]
"= "
- elsif @options[:optimistic]
- ">= "
- else
+ elsif @options[:pessimistic]
"~> "
+ else
+ ">= "
end
end
diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb
index f2f5b22cd3..a1b8e0475e 100644
--- a/lib/bundler/inline.rb
+++ b/lib/bundler/inline.rb
@@ -44,14 +44,16 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
old_gemfile = ENV["BUNDLE_GEMFILE"]
+ old_lockfile = ENV["BUNDLE_LOCKFILE"]
Bundler.unbundle_env!
begin
Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
+ Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock"
- Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
+ Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins]
builder = Bundler::Dsl.new
builder.instance_eval(&gemfile)
@@ -60,14 +62,53 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
definition.validate_runtime!
if force_latest_compatible || definition.missing_specs?
- 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}"
+ do_install = -> do
+ 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
+
+ # When possible we do the install in a subprocess because to install
+ # gems we need to require some default gems like `securerandom` etc
+ # which may later conflict with the Gemfile requirements.
+ installed_in_fork = false
+ if Process.respond_to?(:fork)
+ Gem.load_yaml # Avoid NameError on Ruby 3.2's safe_yaml.rb after Gem::Specification.reset
+ _, status = Process.waitpid2(Process.fork do
+ $VERBOSE = nil
+ do_install.call end)
+ exit(status.exitstatus || status.to_i) unless status.success?
+
+ installed_in_fork = true
+
+ Bundler.reset!
+ Gem::Specification.reset
+ Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
+
+ builder = Bundler::Dsl.new
+ builder.instance_eval(&gemfile)
+ builder.check_primary_source_safety
+
+ definition = builder.to_definition(nil, true)
+ definition.validate_runtime!
+ else
+ do_install.call
+ end
end
+ configure_forked_definition = ->(d) do
+ d.sources.rubygems_sources.each(&:remote!)
+ d.sources.git_sources.each do |source|
+ source.cached!
+ source.instance_variable_set(:@copied, true)
+ end
+ def d.lock(*); end
+ end
+ configure_forked_definition.call(definition) if installed_in_fork
+
begin
runtime = Bundler::Runtime.new(nil, definition).setup
rescue Gem::LoadError => e
@@ -82,6 +123,7 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
builder.dependencies.delete_if {|d| d.name == name }
builder.instance_eval { gem name, activated_version }
definition = builder.to_definition(nil, true)
+ configure_forked_definition.call(definition) if installed_in_fork
retry
end
@@ -94,5 +136,11 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
else
ENV["BUNDLE_GEMFILE"] = ""
end
+
+ if old_lockfile
+ ENV["BUNDLE_LOCKFILE"] = old_lockfile
+ else
+ ENV["BUNDLE_LOCKFILE"] = ""
+ end
end
end
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index 0e91327aab..87d9a75627 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -7,12 +7,6 @@ require_relative "installer/gem_installer"
module Bundler
class Installer
- class << self
- attr_accessor :ambiguous_gems
-
- Installer.ambiguous_gems = []
- end
-
attr_reader :post_install_messages, :definition
# Begins the installation process for Bundler.
@@ -69,6 +63,11 @@ module Bundler
Bundler.create_bundle_path
ProcessLock.lock do
+ # Invalidate any stale gem specification cache from before we acquired the lock.
+ # Another process may have installed gems while we were waiting.
+ Gem::Specification.reset
+ @definition.sources.clear_cache
+
@definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
if @definition.dependencies.empty?
@@ -195,25 +194,17 @@ module Bundler
standalone = options[:standalone]
force = options[:force]
local = options[:local] || options[:"prefer-local"]
- jobs = installation_parallelization
+ jobs = Bundler.settings.installation_parallelization
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
end
- def installation_parallelization
- if jobs = Bundler.settings[:jobs]
- return jobs
- end
-
- Bundler.settings.processor_count
- end
-
def load_plugins
Gem.load_plugins
- requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
+ requested_path_gems = @definition.specs.select {|s| s.source.is_a?(Source::Path) }
path_plugin_files = requested_path_gems.flat_map do |spec|
spec.matches_for_glob("rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
rescue TypeError
@@ -225,12 +216,13 @@ module Bundler
end
def ensure_specs_are_compatible!
+ overrides = @definition.overrides
@definition.specs.each do |spec|
- unless spec.matches_current_ruby?
+ unless spec.matches_current_ruby_with_overrides?(overrides)
raise InstallError, "#{spec.full_name} requires ruby version #{spec.required_ruby_version}, " \
"which is incompatible with the current version, #{Gem.ruby_version}"
end
- unless spec.matches_current_rubygems?
+ unless spec.matches_current_rubygems_with_overrides?(overrides)
raise InstallError, "#{spec.full_name} requires rubygems version #{spec.required_rubygems_version}, " \
"which is incompatible with the current version, #{Gem.rubygems_version}"
end
diff --git a/lib/bundler/installer/gem_installer.rb b/lib/bundler/installer/gem_installer.rb
index 1da91857bd..f3b43c31ee 100644
--- a/lib/bundler/installer/gem_installer.rb
+++ b/lib/bundler/installer/gem_installer.rb
@@ -16,7 +16,6 @@ module Bundler
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
raise
@@ -26,6 +25,20 @@ module Bundler
[false, specific_failure_message(e)]
end
+ def download
+ spec.source.download(
+ spec,
+ force: force,
+ local: local,
+ build_args: Array(spec_settings),
+ previous_spec: previous_spec,
+ )
+
+ [true, nil]
+ rescue Bundler::BundlerError => e
+ [false, specific_failure_message(e)]
+ end
+
private
def specific_failure_message(e)
@@ -71,15 +84,5 @@ module Bundler
def out_of_space_message
"#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle."
end
-
- def generate_executable_stubs
- return if Bundler.feature_flag.forget_cli_options?
- return if Bundler.settings[:inline]
- if Bundler.settings[:bin] && standalone
- installer.generate_standalone_bundler_executable_stubs(spec)
- elsif Bundler.settings[:bin]
- installer.generate_bundler_executable_stubs(spec, force: true)
- end
- end
end
end
diff --git a/lib/bundler/installer/parallel_installer.rb b/lib/bundler/installer/parallel_installer.rb
index d10e5ec924..fef326ed0a 100644
--- a/lib/bundler/installer/parallel_installer.rb
+++ b/lib/bundler/installer/parallel_installer.rb
@@ -6,7 +6,7 @@ require_relative "gem_installer"
module Bundler
class ParallelInstaller
class SpecInstallation
- attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error
+ attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error, :dependencies
def initialize(spec)
@spec = spec
@name = spec.name
@@ -24,6 +24,10 @@ module Bundler
state == :enqueued
end
+ def enqueue_with_priority?
+ state == :installable && spec.extensions.any?
+ end
+
def failed?
state == :failed
end
@@ -32,29 +36,21 @@ module Bundler
state == :none
end
- def has_post_install_message?
- !post_install_message.empty?
- end
-
- def ignorable_dependency?(dep)
- dep.type == :development || dep.name == @name
- end
+ def ready_to_install?(installed_specs)
+ return false unless state == :downloaded
- # Checks installed dependencies against spec's dependencies to make
- # sure needed dependencies have been installed.
- def dependencies_installed?(installed_specs)
- dependencies.all? {|d| installed_specs.include? d.name }
+ spec.extensions.none? || dependencies_installed?(installed_specs)
end
- # Represents only the non-development dependencies, the ones that are
- # itself and are in the total list.
- def dependencies
- @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep }
+ def has_post_install_message?
+ !post_install_message.empty?
end
- # Represents all dependencies
- def all_dependencies
- @spec.dependencies
+ # Recursively checks that all dependencies (direct and transitive) have been installed.
+ def dependencies_installed?(installed_specs)
+ dependencies.all? do |dep|
+ installed_specs.include?(dep.name) && dep.dependencies_installed?(installed_specs)
+ end
end
def to_s
@@ -75,6 +71,12 @@ module Bundler
@force = force
@local = local
@specs = all_specs.map {|s| SpecInstallation.new(s) }
+ specs_by_name = @specs.to_h {|s| [s.name, s] }
+ @specs.each do |spec_install|
+ spec_install.dependencies = spec_install.spec.dependencies.filter_map do |dep|
+ specs_by_name[dep.name] unless dep.type == :development || dep.name == spec_install.name
+ end
+ end
@specs.each do |spec_install|
spec_install.state = :installed if skip.include?(spec_install.name)
end if skip
@@ -84,6 +86,7 @@ module Bundler
def call
if @rake
+ do_download(@rake, 0)
do_install(@rake, 0)
Gem::Specification.reset
end
@@ -107,26 +110,54 @@ module Bundler
end
def install_with_worker
- enqueue_specs
- process_specs until finished_installing?
+ installed_specs = {}
+ enqueue_specs(installed_specs)
+
+ process_specs(installed_specs) until finished_installing?
end
def install_serially
until finished_installing?
raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?)
spec_install.state = :enqueued
+ do_download(spec_install, 0)
do_install(spec_install, 0)
end
end
def worker_pool
@worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num|
- do_install(spec_install, worker_num)
+ case spec_install.state
+ when :enqueued
+ do_download(spec_install, worker_num)
+ when :installable
+ do_install(spec_install, worker_num)
+ else
+ spec_install
+ end
}
end
- def do_install(spec_install, worker_num)
+ def do_download(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
+ )
+
+ success, message = gem_installer.download
+
+ if success
+ spec_install.state = :downloaded
+ else
+ spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
+ spec_install.state = :failed
+ end
+
+ spec_install
+ end
+
+ def do_install(spec_install, worker_num)
gem_installer = Bundler::GemInstaller.new(
spec_install.spec, @installer, @standalone, worker_num, @force, @local
)
@@ -147,9 +178,19 @@ module Bundler
# Some specs might've had to wait til this spec was installed to be
# processed so the call to `enqueue_specs` is important after every
# dequeue.
- def process_specs
- worker_pool.deq
- enqueue_specs
+ def process_specs(installed_specs)
+ spec = worker_pool.deq
+
+ if spec.installed?
+ installed_specs[spec.name] = true
+ return
+ elsif spec.failed?
+ return
+ elsif spec.ready_to_install?(installed_specs)
+ spec.state = :installable
+ end
+
+ worker_pool.enq(spec, priority: spec.enqueue_with_priority?)
end
def finished_installing?
@@ -185,18 +226,15 @@ module Bundler
# Later we call this lambda again to install specs that depended on
# previously installed specifications. We continue until all specs
# are installed.
- def enqueue_specs
- installed_specs = {}
+ 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)
- spec.state = :enqueued
- worker_pool.enq spec
+ if spec.installed?
+ installed_specs[spec.name] = true
+ next
end
+
+ spec.state = :enqueued
+ worker_pool.enq spec
end
end
end
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index e617d32410..0da621d21f 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -9,7 +9,7 @@ module Bundler
include ForcePlatform
attr_reader :name, :version, :platform, :materialization
- attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version
+ attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version, :overrides
#
# For backwards compatibility with existing lockfiles, if the most specific
@@ -30,10 +30,11 @@ module Bundler
lazy_spec.dependencies = s.runtime_dependencies
lazy_spec.required_ruby_version = s.required_ruby_version
lazy_spec.required_rubygems_version = s.required_rubygems_version
+ lazy_spec.overrides = s.overrides if s.is_a?(LazySpecification)
lazy_spec
end
- def initialize(name, version, platform, source = nil)
+ def initialize(name, version, platform, source = nil, **materialization_options)
@name = name
@version = version
@dependencies = []
@@ -43,6 +44,7 @@ module Bundler
@original_source = source
@source = source
+ @materialization_options = materialization_options
@force_ruby_platform = default_force_ruby_platform
@most_specific_locked_platform = nil
@@ -137,24 +139,16 @@ module Bundler
source.local!
if use_exact_resolved_specifications?
- materialize(self) do |matching_specs|
- choose_compatible(matching_specs)
- end
- else
- materialize([name, version]) do |matching_specs|
- target_platform = source.is_a?(Source::Path) ? platform : local_platform
-
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
-
- specification = choose_compatible(installable_candidates, fallback_to_non_installable: false)
- return specification unless specification.nil?
+ spec = materialize(self) {|specs| choose_compatible(specs, fallback_to_non_installable: false) }
+ return spec if spec
- if target_platform != platform
- installable_candidates = GemHelpers.select_best_platform_match(matching_specs, platform)
- end
-
- choose_compatible(installable_candidates)
+ # Exact spec is incompatible; in frozen mode, try to find a compatible platform variant
+ # In non-frozen mode, return nil to trigger re-resolution and lockfile update
+ if Bundler.frozen_bundle?
+ materialize([name, version]) {|specs| resolve_best_platform(specs) }
end
+ else
+ materialize([name, version]) {|specs| resolve_best_platform(specs) }
end
end
@@ -189,8 +183,41 @@ module Bundler
!source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
end
+ # Try platforms in order of preference until finding a compatible spec.
+ # Used for legacy lockfiles and as a fallback when the exact locked spec
+ # is incompatible. Falls back to frozen bundle behavior if none match.
+ def resolve_best_platform(specs)
+ find_compatible_platform_spec(specs) || frozen_bundle_fallback(specs)
+ end
+
+ def find_compatible_platform_spec(specs)
+ candidate_platforms.each do |plat|
+ candidates = MatchPlatform.select_best_platform_match(specs, plat)
+ spec = choose_compatible(candidates, fallback_to_non_installable: false)
+ return spec if spec
+ end
+ nil
+ end
+
+ # Platforms to try in order of preference. Ruby platform is last since it
+ # requires compilation, but works when precompiled gems are incompatible.
+ def candidate_platforms
+ target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
+ [target, platform, Gem::Platform::RUBY].uniq
+ end
+
+ # In frozen mode, accept any candidate. Will error at install time.
+ # When target differs from locked platform, prefer locked platform's candidates
+ # to preserve lockfile integrity.
+ def frozen_bundle_fallback(specs)
+ target = source.is_a?(Source::Path) ? platform : Bundler.local_platform
+ fallback_platform = target == platform ? target : platform
+ candidates = MatchPlatform.select_best_platform_match(specs, fallback_platform)
+ choose_compatible(candidates)
+ end
+
def ruby_platform_materializes_to_ruby_platform?
- generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
+ generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY
(most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform]
end
@@ -208,27 +235,38 @@ module Bundler
# about the mismatch higher up the stack, right before trying to install the
# bad gem.
def choose_compatible(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
+ override_list = overrides || []
search = candidates.reverse.find do |spec|
- spec.is_a?(StubSpecification) || spec.matches_current_metadata?
+ spec.is_a?(StubSpecification) || spec.matches_current_metadata_with_overrides?(override_list)
end
if search.nil? && fallback_to_non_installable
search = candidates.last
- elsif search && search.full_name == full_name
- # We don't validate locally installed dependencies but accept what's in
- # the lockfile instead for performance, since loading locally installed
- # dependencies would mean evaluating all gemspecs, which would affect
- # `bundler/setup` performance
- if search.is_a?(StubSpecification)
- search.dependencies = dependencies
- else
- if !source.is_a?(Source::Path) && search.runtime_dependencies.sort != dependencies.sort
- raise IncorrectLockfileDependencies.new(self)
- end
-
- search.locked_platform = platform if search.instance_of?(RemoteSpecification) || search.instance_of?(EndpointSpecification)
- end
+ end
+
+ if search
+ validate_dependencies(search) if search.platform == platform
+
+ search.locked_platform = platform if search.instance_of?(RemoteSpecification) || search.instance_of?(EndpointSpecification)
end
search
end
+
+ # Validate dependencies of this locked spec are consistent with dependencies
+ # of the actual spec that was materialized.
+ #
+ # Note that unless we are in strict mode (which we set during installation)
+ # we don't validate dependencies of locally installed gems but
+ # accept what's in the lockfile instead for performance, since loading
+ # dependencies of locally installed gems would mean evaluating all gemspecs,
+ # which would affect `bundler/setup` performance.
+ def validate_dependencies(spec)
+ if !@materialization_options[:strict] && spec.is_a?(StubSpecification)
+ spec.dependencies = dependencies
+ else
+ if !source.is_a?(Source::Path) && spec.runtime_dependencies.sort != dependencies.sort
+ raise IncorrectLockfileDependencies.new(self, spec.runtime_dependencies, dependencies)
+ end
+ end
+ end
end
end
diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb
index 904552fa0c..2a3ad22480 100644
--- a/lib/bundler/lockfile_generator.rb
+++ b/lib/bundler/lockfile_generator.rb
@@ -71,7 +71,8 @@ module Bundler
checksums = definition.resolve.map do |spec|
spec.source.checksum_store.to_lock(spec)
end
- add_section("CHECKSUMS", checksums)
+
+ add_section("CHECKSUMS", checksums + bundler_checksum)
end
def add_locked_ruby_version
@@ -95,10 +96,24 @@ module Bundler
out << " #{key}: #{val}\n"
end
when String
- out << " #{value}\n"
+ out << " #{value}\n"
else
raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile"
end
end
+
+ def bundler_checksum
+ return [] if Bundler.gem_version.to_s.end_with?(".dev") || ENV["SKIP_BUNDLER_CHECKSUM"]
+
+ bundler_spec = definition.sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
+ return [] unless File.exist?(bundler_spec.cache_file)
+
+ require "rubygems/package"
+
+ package = Gem::Package.new(bundler_spec.cache_file)
+ definition.sources.metadata_source.checksum_store.register(bundler_spec, Checksum.from_gem_package(package))
+
+ [definition.sources.metadata_source.checksum_store.to_lock(bundler_spec)]
+ end
end
end
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 7d57ec724d..852fc631f3 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
+require_relative "shared_helpers"
+
module Bundler
class LockfileParser
- include GemHelpers
-
class Position
attr_reader :line, :column
def initialize(line, column)
@@ -28,6 +28,7 @@ module Bundler
attr_reader(
:sources,
+ :metadata_source,
:dependencies,
:specs,
:platforms,
@@ -94,24 +95,37 @@ module Bundler
lockfile_contents.split(BUNDLED).last.strip
end
- def initialize(lockfile)
+ def initialize(lockfile, strict: false, lockfile_path: nil)
@platforms = []
@sources = []
+ @metadata_source = Source::Metadata.new
@dependencies = {}
@parse_method = nil
@specs = {}
- @lockfile_path = begin
+ @lockfile_path = lockfile_path || begin
SharedHelpers.relative_lockfile_path
rescue GemfileNotFound
"Gemfile.lock"
end
@pos = Position.new(1, 1)
+ @strict = strict
if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
"Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock."
end
+ @valid = lockfile.strip.empty? ||
+ lockfile.split(/(?:\r?\n)+/).any? {|l| KNOWN_SECTIONS.include?(l) }
+
+ unless @valid
+ SharedHelpers.feature_deprecated!(
+ "Your #{@lockfile_path} does not appear to be a valid lockfile. " \
+ "Run `rm #{@lockfile_path}` and then `bundle install` to generate a new lockfile. " \
+ "This will raise a LockfileError in a future version of Bundler."
+ )
+ end
+
lockfile.split(/((?:\r?\n)+)/) do |line|
# split alternates between the line and the following whitespace
next @pos.advance!(line) if line.match?(/^\s*$/)
@@ -139,8 +153,13 @@ module Bundler
end
@pos.advance!(line)
end
+
+ if @platforms.include?(Gem::Platform::X64_MINGW_LEGACY)
+ SharedHelpers.feature_deprecated!("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.")
+ end
+
@most_specific_locked_platform = @platforms.min_by do |bundle_platform|
- platform_specificity_match(bundle_platform, local_platform)
+ Gem::Platform.platform_specificity_match(bundle_platform, Bundler.local_platform)
end
@specs = @specs.values.sort_by!(&:full_name).each do |spec|
spec.most_specific_locked_platform = @most_specific_locked_platform
@@ -156,6 +175,10 @@ module Bundler
bundler_version.nil? || bundler_version < Gem::Version.new("1.16.2")
end
+ def valid?
+ @valid
+ end
+
private
TYPES = {
@@ -246,7 +269,12 @@ module Bundler
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]
+ spec = @specs[full_name]
+
+ if name == "bundler"
+ spec ||= LazySpecification.new(name, version, platform, @metadata_source)
+ end
+ return unless spec
if checksums
checksums.split(",") do |lock_checksum|
@@ -271,7 +299,7 @@ module Bundler
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_source, strict: @strict)
@current_source.add_dependency_names(name)
@specs[@current_spec.full_name] = @current_spec
diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1
index 176e8b117e..0956aa83f1 100644
--- a/lib/bundler/man/bundle-add.1
+++ b/lib/bundler/man/bundle-add.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-ADD" "1" "March 2025" ""
+.TH "BUNDLE\-ADD" "1" "May 2026" ""
.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] [\-\-quiet] [\-\-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] [\-\-cooldown=NUMBER] [\-\-quiet] [\-\-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\.
.SH "OPTIONS"
@@ -46,10 +46,16 @@ Do not print progress information to the standard output\.
Adds the gem to the Gemfile but does not install it\.
.TP
\fB\-\-optimistic\fR
-Adds optimistic declaration of version\.
+Ignored (now default behavior)
+.TP
+\fB\-\-pessimistic\fR
+Adds pessimistic declaration of version\.
.TP
\fB\-\-strict\fR
Adds strict declaration of version\.
+.TP
+\fB\-\-cooldown=<number>\fR
+Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run\. See \fBcooldown\fR in bundle\-config(1) for precedence rules\.
.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\.
@@ -62,7 +68,7 @@ You can add the \fBrails\fR gem with version greater than 1\.1 (not including 1\
.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
+\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
diff --git a/lib/bundler/man/bundle-add.1.ronn b/lib/bundler/man/bundle-add.1.ronn
index 48c0c66b09..8c65af0cc0 100644
--- a/lib/bundler/man/bundle-add.1.ronn
+++ b/lib/bundler/man/bundle-add.1.ronn
@@ -5,7 +5,7 @@ bundle-add(1) -- Add gem to the Gemfile and run bundle install
`bundle add` <GEM_NAME> [--group=GROUP] [--version=VERSION] [--source=SOURCE]
[--path=PATH] [--git=GIT|--github=GITHUB] [--branch=BRANCH] [--ref=REF]
- [--quiet] [--skip-install] [--strict|--optimistic]
+ [--cooldown=NUMBER] [--quiet] [--skip-install] [--strict|--optimistic]
## DESCRIPTION
@@ -51,11 +51,19 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
Adds the gem to the Gemfile but does not install it.
* `--optimistic`:
- Adds optimistic declaration of version.
+ Ignored (now default behavior)
+
+* `--pessimistic`:
+ Adds pessimistic declaration of version.
* `--strict`:
Adds strict declaration of version.
+* `--cooldown=<number>`:
+ Only consider gem versions published at least <number> days ago when
+ resolving. Pass `0` to disable cooldown for this run. See `cooldown`
+ in bundle-config(1) for precedence rules.
+
## EXAMPLES
1. You can add the `rails` gem to the Gemfile without any version restriction.
@@ -70,7 +78,7 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
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"`
+ `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`.
diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1
index 146c1c021e..246daeae53 100644
--- a/lib/bundler/man/bundle-binstubs.1
+++ b/lib/bundler/man/bundle-binstubs.1
@@ -1,24 +1,21 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-BINSTUBS" "1" "March 2025" ""
+.TH "BUNDLE\-BINSTUBS" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
.SH "SYNOPSIS"
-\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone] [\-\-all\-platforms]
+\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-standalone] [\-\-all\-platforms]
.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\.
+This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the directory specified by \fBbin\fR setting if it has been configured\. 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[=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
diff --git a/lib/bundler/man/bundle-binstubs.1.ronn b/lib/bundler/man/bundle-binstubs.1.ronn
index ec2cfd80db..cbe5983f4d 100644
--- a/lib/bundler/man/bundle-binstubs.1.ronn
+++ b/lib/bundler/man/bundle-binstubs.1.ronn
@@ -3,7 +3,7 @@ bundle-binstubs(1) -- Install the binstubs of the listed gems
## SYNOPSIS
-`bundle binstubs` <GEM_NAME> [--force] [--path PATH] [--standalone] [--all-platforms]
+`bundle binstubs` <GEM_NAME> [--force] [--standalone] [--all-platforms]
## DESCRIPTION
@@ -19,17 +19,15 @@ the file `bin/rspec`. That file will contain enough code to load Bundler,
tell it to load the bundled gems, and then run rspec.
This command generates binstubs for executables in `GEM_NAME`.
-Binstubs are put into `bin`, or the `--path` directory if one has been set.
-Calling binstubs with [GEM [GEM]] will create binstubs for all given gems.
+Binstubs are put into `bin`, or the directory specified by `bin` setting if it
+has been configured. Calling binstubs with [GEM [GEM]] will create binstubs for
+all given gems.
## OPTIONS
* `--force`:
Overwrite existing binstubs if they exist.
-* `--path[=PATH]`:
- The location to install the specified binstubs to. This defaults to `bin`.
-
* `--standalone`:
Makes binstubs that can work without depending on Rubygems or Bundler at
runtime.
diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1
index 64e806029b..38ea047961 100644
--- a/lib/bundler/man/bundle-cache.1
+++ b/lib/bundler/man/bundle-cache.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CACHE" "1" "March 2025" ""
+.TH "BUNDLE\-CACHE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
.SH "SYNOPSIS"
@@ -11,9 +11,6 @@ alias: \fBpackage\fR, \fBpack\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 \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR, use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\.
.SH "OPTIONS"
.TP
-\fB\-\-all\fR
-Include all sources (including path and git)\.
-.TP
\fB\-\-all\-platforms\fR
Include gems for all platforms present in the lockfile, not only the current one\.
.TP
@@ -26,19 +23,10 @@ Use the specified gemfile instead of Gemfile\.
\fB\-\-no\-install\fR
Don't install the gems, only update the cache\.
.TP
-\fB\-\-no\-prune\fR
-Don't remove stale gems from the cache\.
-.TP
-\fB\-\-path=PATH\fR
-Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME)\.
-.TP
\fB\-\-quiet\fR
Only output warnings and errors\.
-.TP
-\fB\-\-frozen\fR
-Do not allow the Gemfile\.lock to be updated after this bundle cache operation's install\.
.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\.
+The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This can be disabled setting \fBcache_all\fR to false\.
.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"
diff --git a/lib/bundler/man/bundle-cache.1.ronn b/lib/bundler/man/bundle-cache.1.ronn
index ffcc07c7b1..51846c96b4 100644
--- a/lib/bundler/man/bundle-cache.1.ronn
+++ b/lib/bundler/man/bundle-cache.1.ronn
@@ -15,9 +15,6 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
## OPTIONS
-* `--all`:
- Include all sources (including path and git).
-
* `--all-platforms`:
Include gems for all platforms present in the lockfile, not only the current one.
@@ -30,23 +27,13 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
* `--no-install`:
Don't install the gems, only update the cache.
-* `--no-prune`:
- Don't remove stale gems from the cache.
-
-* `--path=PATH`:
- Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).
-
* `--quiet`:
Only output warnings and errors.
-* `--frozen`:
- Do not allow the Gemfile.lock to be updated after this bundle cache operation's install.
-
## GIT AND PATH GEMS
The `bundle cache` command can also package `:git` and `:path` dependencies
-besides .gem files. This needs to be explicitly enabled via the `--all` option.
-Once used, the `--all` option will be remembered.
+besides .gem files. This can be disabled setting `cache_all` to false.
## SUPPORT FOR MULTIPLE PLATFORMS
diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1
index bf16a22461..6cd474d90a 100644
--- a/lib/bundler/man/bundle-check.1
+++ b/lib/bundler/man/bundle-check.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CHECK" "1" "March 2025" ""
+.TH "BUNDLE\-CHECK" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
.SH "SYNOPSIS"
-\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH]
+\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE]
.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
@@ -18,7 +18,4 @@ Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\.
.TP
\fB\-\-gemfile=GEMFILE\fR
Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\.
-.TP
-\fB\-\-path=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 23bb6f3eb8..92589159c9 100644
--- a/lib/bundler/man/bundle-check.1.ronn
+++ b/lib/bundler/man/bundle-check.1.ronn
@@ -5,7 +5,6 @@ bundle-check(1) -- Verifies if dependencies are satisfied by installed gems
`bundle check` [--dry-run]
[--gemfile=FILE]
- [--path=PATH]
## DESCRIPTION
@@ -25,7 +24,3 @@ installed on the local machine, if they satisfy the requirements.
* `--gemfile=GEMFILE`:
Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)].
-
-* `--path=PATH`:
- Specify a different path than the system default (`$BUNDLE_PATH` or `$GEM_HOME`).
- Bundler will remember this value for future installs on this machine.
diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1
index 83f7661482..eb90636c17 100644
--- a/lib/bundler/man/bundle-clean.1
+++ b/lib/bundler/man/bundle-clean.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CLEAN" "1" "March 2025" ""
+.TH "BUNDLE\-CLEAN" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1
index 190177eb37..c055c8a415 100644
--- a/lib/bundler/man/bundle-config.1
+++ b/lib/bundler/man/bundle-config.1
@@ -1,16 +1,16 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CONFIG" "1" "March 2025" ""
+.TH "BUNDLE\-CONFIG" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
.SH "SYNOPSIS"
-\fBbundle config\fR list
+\fBbundle config\fR [list]
.br
-\fBbundle config\fR [get] NAME
+\fBbundle config\fR [get [\-\-local|\-\-global]] NAME
.br
-\fBbundle config\fR [set] NAME VALUE
+\fBbundle config\fR [set [\-\-local|\-\-global]] NAME VALUE
.br
-\fBbundle config\fR unset NAME
+\fBbundle config\fR unset [\-\-local|\-\-global] NAME
.SH "DESCRIPTION"
This command allows you to interact with Bundler's configuration system\.
.P
@@ -25,65 +25,40 @@ Global config (\fB~/\.bundle/config\fR)
Bundler default config
.IP "" 0
.P
+Executing \fBbundle\fR with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\.
+.SH "SUB\-COMMANDS"
+.SS "list (default command)"
Executing \fBbundle config list\fR will print a list of all bundler configuration for the current bundle, and where that configuration was set\.
+.SS "get"
+Executing \fBbundle config get <name>\fR will print the value of that configuration setting, and all locations where it 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\.
+\fBOPTIONS\fR
+.TP
+\fB\-\-local\fR
+Get configuration from configuration file for the local application, namely, \fB<project_root>/\.bundle/config\fR, or \fB$BUNDLE_APP_CONFIG/config\fR if \fBBUNDLE_APP_CONFIG\fR is set\.
+.TP
+\fB\-\-global\fR
+Get configuration from configuration file global to all bundles executed as the current user, namely, from \fB~/\.bundle/config\fR\.
+.SS "set"
+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\.
.P
+\fBOPTIONS\fR
+.TP
+\fB\-\-local\fR
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
+.TP
+\fB\-\-global\fR
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
+.SS "unset"
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)\.
-.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)\.
-.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\.
-.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\.
+\fBOPTIONS\fR
.TP
-\fBonly\fR
-A space\-separated list of groups to install only gems of the specified groups\. Please check carefully if you want to install also gems without a group, cause they get put inside \fBdefault\fR group\. For example \fBonly test:default\fR will install all gems specified in test group and without one\.
-.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\.
-.TP
-\fBwithout\fR
-A space\-separated or \fB:\fR\-separated list of groups referencing gems to skip during installation\.
+\fB\-\-local\fR
+Executing \fBbundle config unset \-\-local <name>\fR will delete the configuration only from the local application\.
.TP
-\fBwith\fR
-A space\-separated or \fB:\fR\-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\.
+\fB\-\-global\fR
+Executing \fBbundle config unset \-\-global <name>\fR will delete the configuration only from the user configuration\.
.SH "CONFIGURATION KEYS"
Configuration keys in bundler have two forms: the canonical form and the environment variable form\.
.P
@@ -95,27 +70,40 @@ Any periods in the configuration keys must be replaced with two underscores when
.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_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\.
+\fBapi_request_size\fR (\fBBUNDLE_API_REQUEST_SIZE\fR): Configure how many dependencies to fetch when resolving the specifications\. This configuration is only used when fetching specifications from RubyGems servers that didn't implement the Compact Index API\. Defaults to 100\.
.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\.
+\fBbin\fR (\fBBUNDLE_BIN\fR): If configured, \fBbundle binstubs\fR will install executables from gems in the bundle to the specified directory\. Otherwise it will create them in a \fBbin\fR directory relative to the Gemfile directory\. 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, \fBbundle binstubs\fR will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
.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\.
+\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly before bundler 4, but will be the default on bundler 4\.
.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\.
+\fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\. Defaults to \fBtrue\fR in Bundler 4, as long as \fBpath\fR is not explicitly configured\.
.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\.
+\fBcooldown\fR (\fBBUNDLE_COOLDOWN\fR): Number of days a published gem version must age before bundler will resolve to it\. Defaults to unset (no cooldown)\. Pass \fB0\fR to disable cooldown for an individual run\.
+.IP
+The effective cooldown for any given gem is resolved from three layers, highest precedence first:
+.IP "1." 4
+CLI flag \fB\-\-cooldown N\fR on \fBinstall\fR, \fBupdate\fR, \fBadd\fR, and \fBoutdated\fR\.
+.IP "2." 4
+This setting (\fBbundle config set cooldown N\fR or \fBBUNDLE_COOLDOWN=N\fR)\.
+.IP "3." 4
+The per\-source \fBcooldown:\fR keyword in the Gemfile, such as \fBsource "https://rubygems\.org", cooldown: 7\fR\.
+.IP "" 0
+.IP
+The CLI flag and this setting apply uniformly to every source, including ones declared with their own \fBcooldown:\fR value\. To keep a private registry permanently exempt while still cooling down public gems, declare \fBsource "https://internal", cooldown: 0\fR in the Gemfile; remember that \fB\-\-cooldown N\fR on the command line will still override it for that single run\.
+.IP
+Cooldown filtering depends on the gem server providing a per\-version \fBcreated_at\fR timestamp in the v2 compact\-index format\. Versions without that metadata \- older gem servers, historical entries that predate the v2 cutover on \fBrubygems\.org\fR, or private registries that still emit the v1 format \- are treated as outside the cooldown window and remain resolvable\. If you rely on cooldown for supply\-chain protection, confirm that the gem server emits \fBcreated_at\fR in its \fB/info/<gem>\fR responses\.
+.IP "\(bu" 4
+\fBdefault_cli_command\fR (\fBBUNDLE_DEFAULT_CLI_COMMAND\fR): The command that running \fBbundle\fR without arguments should run\. Defaults to \fBcli_help\fR since Bundler 4, but can also be \fBinstall\fR which was the previous default\.
.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\.
+\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Equivalent to setting \fBfrozen\fR to \fBtrue\fR and \fBpath\fR to \fBvendor/bundle\fR\.
.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
@@ -131,15 +119,15 @@ The following is a list of all configuration keys and their purpose\. You can le
.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\.
.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\.
+\fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow any automatic changes to \fBGemfile\.lock\fR\. Bundler commands will be blocked unless the lockfile can be installed exactly as written\. Usually this will happen when changing the \fBGemfile\fR manually and forgetting to update the lockfile through \fBbundle lock\fR or \fBbundle install\fR\.
.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\.
+\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in the \fBREADME\fR and \fB\.gemspec\fR files 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\.
+\fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems and compiled extensions globally, rather than locally to the configured installation path\.
.IP "\(bu" 4
\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR): When set, no funding requests will be printed\.
.IP "\(bu" 4
@@ -147,40 +135,42 @@ The following is a list of all configuration keys and their purpose\. You can le
.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\.
+\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can download and install in parallel\. Defaults to the number of available processors\.
+.IP "\(bu" 4
+\fBlockfile\fR (\fBBUNDLE_LOCKFILE\fR): The path to the lockfile that bundler should use\. By default, Bundler adds \fB\.lock\fR to the end of the \fBgemfile\fR entry\. Can be set to \fBfalse\fR in the Gemfile to disable lockfile creation entirely (see gemfile(5))\.
+.IP "\(bu" 4
+\fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR): Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\.
.IP "\(bu" 4
-\fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR): Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\.
+\fBno_build_extension\fR (\fBBUNDLE_NO_BUILD_EXTENSION\fR): Whether Bundler should skip building native extensions during installation\. When set, gems are installed without compiling their C extensions\. To build extensions later, unset this setting and run \fBbundle pristine <gem>\fR\.
.IP "\(bu" 4
\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\.
.IP "\(bu" 4
+\fBno_install_plugin\fR (\fBBUNDLE_NO_INSTALL_PLUGIN\fR): Whether Bundler should skip installing RubyGems plugins during installation\. When set, plugin files are not written to the plugins directory\. To install plugins later, unset this setting and run \fBbundle pristine <gem>\fR\.
+.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\.
+\fBonly\fR (\fBBUNDLE_ONLY\fR): A space\-separated list of groups to install only gems of the specified groups\. Please check carefully if you want to install also gems without a group, because they get put inside \fBdefault\fR group\. For example \fBonly test:default\fR will install all gems specified in test group and without one\.
.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\.
+\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\. When not set, Bundler install by default to a \fB\.bundle\fR directory relative to repository root in Bundler 4, and to the default system path (\fBGem\.dir\fR) before Bundler 4\. That means that before Bundler 4, Bundler shares this location with Rubygems, and \fBgem install \|\.\|\.\|\.\fR will have gems installed in the same location and therefore, gems installed without \fBpath\fR set will show up by calling \fBgem list\fR\. This will not be the case in Bundler 4\.
.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\.
.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\.
+\fBprefer_patch\fR (\fBBUNDLE_PREFER_PATCH\fR): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\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
+\fBsimulate_version\fR (\fBBUNDLE_SIMULATE_VERSION\fR): The virtual version Bundler should use for activating feature flags\. Can be used to simulate all the new functionality that will be enabled in a future major version\.
+.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\.
@@ -195,12 +185,32 @@ The following is a list of all configuration keys and their purpose\. You can le
.IP "\(bu" 4
\fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\.
.IP "\(bu" 4
+\fBverbose\fR (\fBBUNDLE_VERBOSE\fR): Whether Bundler should print verbose output\. Defaults to \fBfalse\fR, unless the \fB\-\-verbose\fR CLI flag is used\.
+.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 space\-separated or \fB:\fR\-separated list of groups whose gems bundler should install\.
.IP "\(bu" 4
\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should not install\.
.IP "" 0
+.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 "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
@@ -209,7 +219,16 @@ 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:
+Important: This feature only works for gems that are specified with a git source in your Gemfile\. It does not work for gems installed from RubyGems or other sources\. The gem must be defined with \fBgit:\fR option pointing to a remote repository\.
+.P
+For example, if your Gemfile contains:
+.IP "" 4
+.nf
+gem "rack", git: "https://github\.com/rack/rack\.git", branch: "main"
+.fi
+.IP "" 0
+.P
+Then you can use a local Rack repository by running:
.IP "" 4
.nf
bundle config set \-\-local local\.rack ~/Work/git/rack
@@ -221,6 +240,13 @@ Now instead of checking out the remote git repository, the local override will b
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\.
+.P
+If you need to temporarily use a local version of a gem that is normally installed from RubyGems (not from git), use a path source instead:
+.IP "" 4
+.nf
+gem "rack", path: "~/Work/git/rack"
+.fi
+.IP "" 0
.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
@@ -276,7 +302,7 @@ export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit"
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
+bundle config set \-\-global https://github\.com/ruby/rubygems\.git username:password
.fi
.IP "" 0
.P
diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn
index 44c31cd10d..72f891b428 100644
--- a/lib/bundler/man/bundle-config.1.ronn
+++ b/lib/bundler/man/bundle-config.1.ronn
@@ -3,10 +3,10 @@ bundle-config(1) -- Set bundler configuration options
## SYNOPSIS
-`bundle config` list<br>
-`bundle config` [get] NAME<br>
-`bundle config` [set] NAME VALUE<br>
-`bundle config` unset NAME
+`bundle config` [list]<br>
+`bundle config` [get [--local|--global]] NAME<br>
+`bundle config` [set [--local|--global]] NAME VALUE<br>
+`bundle config` unset [--local|--global] NAME
## DESCRIPTION
@@ -19,103 +19,67 @@ Bundler loads configuration settings in this order:
3. Global config (`~/.bundle/config`)
4. Bundler default config
-Executing `bundle config list` will print a list of all bundler
-configuration for the current bundle, and where that configuration
-was set.
-
-Executing `bundle config get <name>` will print the value of that configuration
-setting, and where it was set.
-
-Executing `bundle config set <name> <value>` defaults to setting `local`
-configuration if executing from within a local application, otherwise it will
-set `global` configuration. See `--local` and `--global` options below.
-
-Executing `bundle config set --local <name> <value>` will set that configuration
-in the directory for the local application. The configuration will be stored in
-`<project_root>/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration
-will be stored in `$BUNDLE_APP_CONFIG/config`.
-
-Executing `bundle config set --global <name> <value>` will set that
-configuration to the value specified for all bundles executed as the current
-user. The configuration will be stored in `~/.bundle/config`. If <name> already
-is set, <name> will be overridden and user will be warned.
-
-Executing `bundle config unset <name>` will delete the configuration in both
-local and global sources.
-
-Executing `bundle config unset --global <name>` will delete the configuration
-only from the user configuration.
-
-Executing `bundle config unset --local <name>` will delete the configuration
-only from the local application.
-
-Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will
+Executing `bundle` with the `BUNDLE_IGNORE_CONFIG` environment variable set will
cause it to ignore all configuration.
-## REMEMBERING OPTIONS
+## SUB-COMMANDS
-Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or
-`--without production`, are remembered between commands and saved to your local
-application's configuration (normally, `./.bundle/config`).
+### list (default command)
-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
-`bundle config` (e.g., `bundle config set --local path foo`).
+Executing `bundle config list` will print a list of all bundler
+configuration for the current bundle, and where that configuration
+was set.
-The options that can be configured are:
+### get
-* `bin`:
- Creates a directory (defaults to `~/bin`) 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 `PATH` variable. For instance, if the
- `rails` gem comes with a `rails` executable, this flag will create a
- `bin/rails` executable that ensures that all referred dependencies will be
- resolved using the bundled gems.
+Executing `bundle config get <name>` will print the value of that configuration
+setting, and all locations where it was set.
-* `deployment`:
- In deployment mode, Bundler will 'roll-out' the bundle for
- `production` use. Please check carefully if you want to have this option
- enabled in `development` or `test` environments.
+**OPTIONS**
-* `only`:
- A space-separated list of groups to install only gems of the specified groups.
- Please check carefully if you want to install also gems without a group, cause
- they get put inside `default` group. For example `only test:default` will install
- all gems specified in test group and without one.
+* `--local`:
+ Get configuration from configuration file for the local application, namely,
+ `<project_root>/.bundle/config`, or `$BUNDLE_APP_CONFIG/config` if
+ `BUNDLE_APP_CONFIG` is set.
-* `path`:
- The location to install the specified gems to. This defaults to Rubygems'
- setting. Bundler shares this location with Rubygems, `gem install ...` will
- have gem installed there, too. Therefore, gems installed without a
- `--path ...` setting will show up by calling `gem list`. Accordingly, gems
- installed to other locations will not get listed.
+* `--global`:
+ Get configuration from configuration file global to all bundles executed as
+ the current user, namely, from `~/.bundle/config`.
-* `without`:
- A space-separated or `:`-separated list of groups referencing gems to skip during
- installation.
+### set
-* `with`:
- A space-separated or `:`-separated list of **optional** groups referencing gems to
- include during installation.
+Executing `bundle config set <name> <value>` defaults to setting `local`
+configuration if executing from within a local application, otherwise it will
+set `global` configuration.
-## BUILD OPTIONS
+**OPTIONS**
-You can use `bundle config` to give Bundler the flags to pass to the gem
-installer every time bundler tries to install a particular gem.
+* `--local`:
+ Executing `bundle config set --local <name> <value>` will set that configuration
+ in the directory for the local application. The configuration will be stored in
+ `<project_root>/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration
+ will be stored in `$BUNDLE_APP_CONFIG/config`.
-A very common example, the `mysql` gem, requires Snow Leopard users to
-pass configuration flags to `gem install` to specify where to find the
-`mysql_config` executable.
+* `--global`:
+ Executing `bundle config set --global <name> <value>` will set that
+ configuration to the value specified for all bundles executed as the current
+ user. The configuration will be stored in `~/.bundle/config`. If <name> already
+ is set, <name> will be overridden and user will be warned.
- gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
+### unset
-Since the specific location of that executable can change from machine
-to machine, you can specify these flags on a per-machine basis.
+Executing `bundle config unset <name>` will delete the configuration in both
+local and global sources.
- bundle config set --global build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config
+**OPTIONS**
-After running this command, every time bundler needs to install the
-`mysql` gem, it will pass along the flags you specified.
+* `--local`:
+ Executing `bundle config unset --local <name>` will delete the configuration
+ only from the local application.
+
+* `--global`:
+ Executing `bundle config unset --global <name>` will delete the configuration
+ only from the user configuration.
## CONFIGURATION KEYS
@@ -142,19 +106,25 @@ 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_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`):
- Automatically run `bundle clean` after installing when an explicit `path`
- has not been set and Bundler is not installing into the system gems.
+* `api_request_size` (`BUNDLE_API_REQUEST_SIZE`):
+ Configure how many dependencies to fetch when resolving the specifications.
+ This configuration is only used when fetching specifications from RubyGems
+ servers that didn't implement the Compact Index API.
+ Defaults to 100.
* `auto_install` (`BUNDLE_AUTO_INSTALL`):
Automatically run `bundle install` when gems are missing.
* `bin` (`BUNDLE_BIN`):
- Install executables from gems in the bundle to the specified directory.
- Defaults to `false`.
+ If configured, `bundle binstubs` will install executables from gems in the
+ bundle to the specified directory. Otherwise it will create them in a `bin`
+ directory relative to the Gemfile directory. These executables run in
+ Bundler's context. If used, you might add this directory to your
+ environment's `PATH` variable. For instance, if the `rails` gem comes with a
+ `rails` executable, `bundle binstubs` will create a `bin/rails` executable
+ that ensures that all referred dependencies will be resolved using the
+ bundled gems.
* `cache_all` (`BUNDLE_CACHE_ALL`):
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.
+ before bundler 4, but will be the default on bundler 4.
* `cache_all_platforms` (`BUNDLE_CACHE_ALL_PLATFORMS`):
Cache gems for all platforms.
* `cache_path` (`BUNDLE_CACHE_PATH`):
@@ -163,15 +133,46 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
Defaults to `vendor/cache`.
* `clean` (`BUNDLE_CLEAN`):
Whether Bundler should run `bundle clean` automatically after
- `bundle install`.
+ `bundle install`. Defaults to `true` in Bundler 4, as long as `path` is not
+ explicitly configured.
* `console` (`BUNDLE_CONSOLE`):
The console that `bundle console` starts. Defaults to `irb`.
-* `default_install_uses_path` (`BUNDLE_DEFAULT_INSTALL_USES_PATH`):
- Whether a `bundle install` without an explicit `--path` argument defaults
- to installing gems in `.bundle`.
+* `cooldown` (`BUNDLE_COOLDOWN`):
+ Number of days a published gem version must age before bundler will
+ resolve to it. Defaults to unset (no cooldown). Pass `0` to disable
+ cooldown for an individual run.
+
+ The effective cooldown for any given gem is resolved from three
+ layers, highest precedence first:
+
+ 1. CLI flag `--cooldown N` on `install`, `update`, `add`, and
+ `outdated`.
+ 2. This setting (`bundle config set cooldown N` or
+ `BUNDLE_COOLDOWN=N`).
+ 3. The per-source `cooldown:` keyword in the Gemfile, such as
+ `source "https://rubygems.org", cooldown: 7`.
+
+ The CLI flag and this setting apply uniformly to every source,
+ including ones declared with their own `cooldown:` value. To keep a
+ private registry permanently exempt while still cooling down public
+ gems, declare `source "https://internal", cooldown: 0` in the
+ Gemfile; remember that `--cooldown N` on the command line will
+ still override it for that single run.
+
+ Cooldown filtering depends on the gem server providing a per-version
+ `created_at` timestamp in the v2 compact-index format. Versions
+ without that metadata - older gem servers, historical entries that
+ predate the v2 cutover on `rubygems.org`, or private registries that
+ still emit the v1 format - are treated as outside the cooldown
+ window and remain resolvable. If you rely on cooldown for
+ supply-chain protection, confirm that the gem server emits
+ `created_at` in its `/info/<gem>` responses.
+* `default_cli_command` (`BUNDLE_DEFAULT_CLI_COMMAND`):
+ The command that running `bundle` without arguments should run. Defaults to
+ `cli_help` since Bundler 4, but can also be `install` which was the previous
+ default.
* `deployment` (`BUNDLE_DEPLOYMENT`):
- Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the
- lockfile has not been updated, running Bundler commands will be blocked.
+ Equivalent to setting `frozen` to `true` and `path` to `vendor/bundle`.
* `disable_checksum_validation` (`BUNDLE_DISABLE_CHECKSUM_VALIDATION`):
Allow installing gems even if they do not match the checksum provided by
RubyGems.
@@ -193,12 +194,13 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
Ignore the current machine's platform and install only `ruby` platform gems.
As a result, gems with native extensions will be compiled from source.
* `frozen` (`BUNDLE_FROZEN`):
- Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the
- lockfile has not been updated, running Bundler commands will be blocked.
- Defaults to `true` when `--deployment` is used.
+ Disallow any automatic changes to `Gemfile.lock`. Bundler commands will
+ be blocked unless the lockfile can be installed exactly as written.
+ Usually this will happen when changing the `Gemfile` manually and forgetting
+ to update the lockfile through `bundle lock` or `bundle install`.
* `gem.github_username` (`BUNDLE_GEM__GITHUB_USERNAME`):
- Sets a GitHub username or organization to be used in `README` file when you
- create a new gem via `bundle gem` command. It can be overridden by passing an
+ Sets a GitHub username or organization to be used in the `README` and `.gemspec` files
+ when you create a new gem via `bundle gem` command. It can be overridden by passing an
explicit `--github-username` flag to `bundle gem`.
* `gem.push_key` (`BUNDLE_GEM__PUSH_KEY`):
Sets the `--key` parameter for `gem push` when using the `rake release`
@@ -210,8 +212,8 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
will search up from the current working directory until it finds a
`Gemfile`.
* `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`):
- Whether Bundler should cache all gems globally, rather than locally to the
- installing Ruby installation.
+ Whether Bundler should cache all gems and compiled extensions globally,
+ rather than locally to the configured installation path.
* `ignore_funding_requests` (`BUNDLE_IGNORE_FUNDING_REQUESTS`):
When set, no funding requests will be printed.
* `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`):
@@ -220,38 +222,51 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`):
Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`.
* `jobs` (`BUNDLE_JOBS`):
- The number of gems Bundler can install in parallel. Defaults to the number of
- available processors.
+ The number of gems Bundler can download and install in parallel.
+ Defaults to the number of available processors.
+* `lockfile` (`BUNDLE_LOCKFILE`):
+ The path to the lockfile that bundler should use. By default, Bundler adds
+ `.lock` to the end of the `gemfile` entry. Can be set to `false` in the
+ Gemfile to disable lockfile creation entirely (see gemfile(5)).
* `lockfile_checksums` (`BUNDLE_LOCKFILE_CHECKSUMS`):
- Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources.
+ Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources. Defaults to true.
+* `no_build_extension` (`BUNDLE_NO_BUILD_EXTENSION`):
+ Whether Bundler should skip building native extensions during installation.
+ When set, gems are installed without compiling their C extensions.
+ To build extensions later, unset this setting and run `bundle pristine <gem>`.
* `no_install` (`BUNDLE_NO_INSTALL`):
Whether `bundle package` should skip installing gems.
+* `no_install_plugin` (`BUNDLE_NO_INSTALL_PLUGIN`):
+ Whether Bundler should skip installing RubyGems plugins during installation.
+ When set, plugin files are not written to the plugins directory.
+ To install plugins later, unset this setting and run `bundle pristine <gem>`.
* `no_prune` (`BUNDLE_NO_PRUNE`):
Whether Bundler should leave outdated gems unpruned when caching.
* `only` (`BUNDLE_ONLY`):
A space-separated list of groups to install only gems of the specified groups.
+ Please check carefully if you want to install also gems without a group, because
+ they get put inside `default` group. For example `only test:default` will install
+ all gems specified in test group and without one.
* `path` (`BUNDLE_PATH`):
The location on disk where all gems in your bundle will be located regardless
of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location
- will be installed by `bundle install`. Defaults to `Gem.dir`. When --deployment
- is used, defaults to vendor/bundle.
+ will be installed by `bundle install`. When not set, Bundler install by
+ default to a `.bundle` directory relative to repository root in Bundler 4,
+ and to the default system path (`Gem.dir`) before Bundler 4. That means that
+ before Bundler 4, Bundler shares this location with Rubygems, and `gem
+ install ...` will have gems installed in the same location and therefore,
+ gems installed without `path` set will show up by calling `gem list`. This
+ will not be the case in Bundler 4.
* `path.system` (`BUNDLE_PATH__SYSTEM`):
Whether Bundler will install gems into the default system path (`Gem.dir`).
-* `path_relative_to_cwd` (`BUNDLE_PATH_RELATIVE_TO_CWD`)
- Makes `--path` relative to the CWD instead of the `Gemfile`.
* `plugins` (`BUNDLE_PLUGINS`):
Enable Bundler's experimental plugin system.
-* `prefer_patch` (BUNDLE_PREFER_PATCH):
+* `prefer_patch` (`BUNDLE_PREFER_PATCH`):
Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`.
-* `print_only_version_number` (`BUNDLE_PRINT_ONLY_VERSION_NUMBER`):
- Print only version number from `bundler --version`.
* `redirect` (`BUNDLE_REDIRECT`):
The number of redirects allowed for network requests. Defaults to `5`.
* `retry` (`BUNDLE_RETRY`):
The number of times to retry failed network requests. Defaults to `3`.
-* `setup_makes_kernel_gem_public` (`BUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC`):
- Have `Bundler.setup` make the `Kernel#gem` method public, even though
- RubyGems declares it as private.
* `shebang` (`BUNDLE_SHEBANG`):
The program name that should be invoked for generated binstubs. Defaults to
the ruby install name used to generate the binstub.
@@ -260,6 +275,10 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
be changed in the next major version.
* `silence_root_warning` (`BUNDLE_SILENCE_ROOT_WARNING`):
Silence the warning Bundler prints when installing gems as root.
+* `simulate_version` (`BUNDLE_SIMULATE_VERSION`):
+ The virtual version Bundler should use for activating feature flags. Can be
+ used to simulate all the new functionality that will be enabled in a future
+ major version.
* `ssl_ca_cert` (`BUNDLE_SSL_CA_CERT`):
Path to a designated CA certificate file or folder containing multiple
certificates for trusted CAs in PEM format.
@@ -278,6 +297,9 @@ 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.
+* `verbose` (`BUNDLE_VERBOSE`):
+ Whether Bundler should print verbose output. Defaults to `false`, unless the
+ `--verbose` CLI flag is used.
* `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`.
@@ -289,6 +311,25 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `without` (`BUNDLE_WITHOUT`):
A space-separated or `:`-separated list of groups whose gems bundler should not install.
+## BUILD OPTIONS
+
+You can use `bundle config` to give Bundler the flags to pass to the gem
+installer every time bundler tries to install a particular gem.
+
+A very common example, the `mysql` gem, requires Snow Leopard users to
+pass configuration flags to `gem install` to specify where to find the
+`mysql_config` executable.
+
+ gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
+
+Since the specific location of that executable can change from machine
+to machine, you can specify these flags on a per-machine basis.
+
+ bundle config set --global build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config
+
+After running this command, every time bundler needs to install the
+`mysql` gem, it will pass along the flags you specified.
+
## LOCAL GIT REPOS
Bundler also allows you to work against a git repository locally
@@ -297,7 +338,16 @@ up a local override:
bundle config set --local local.GEM_NAME /path/to/local/git/repository
-For example, in order to use a local Rack repository, a developer could call:
+Important: This feature only works for gems that are specified with a git
+source in your Gemfile. It does not work for gems installed from RubyGems
+or other sources. The gem must be defined with `git:` option pointing to a
+remote repository.
+
+For example, if your Gemfile contains:
+
+ gem "rack", git: "https://github.com/rack/rack.git", branch: "main"
+
+Then you can use a local Rack repository by running:
bundle config set --local local.rack ~/Work/git/rack
@@ -323,6 +373,11 @@ Finally, Bundler also ensures that the current revision in the
`Gemfile.lock` exists in the local git repository. By doing this, Bundler
forces you to fetch the latest changes in the remotes.
+If you need to temporarily use a local version of a gem that is normally
+installed from RubyGems (not from git), use a path source instead:
+
+ gem "rack", path: "~/Work/git/rack"
+
## MIRRORS OF GEM SOURCES
Bundler supports overriding gem sources with mirrors. This allows you to
@@ -366,7 +421,7 @@ Or you can set the credentials as an environment variable like this:
For gems with a git source with HTTP(S) URL you can specify credentials like so:
- bundle config set --global https://github.com/rubygems/rubygems.git username:password
+ bundle config set --global https://github.com/ruby/rubygems.git username:password
Or you can set the credentials as an environment variable like so:
diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1
index de9eeac907..5d3f65365f 100644
--- a/lib/bundler/man/bundle-console.1
+++ b/lib/bundler/man/bundle-console.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-CONSOLE" "1" "March 2025" ""
+.TH "BUNDLE\-CONSOLE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-console\fR \- Open an IRB session with the bundle pre\-loaded
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1
index cd831f2fee..4c59871b66 100644
--- a/lib/bundler/man/bundle-doctor.1
+++ b/lib/bundler/man/bundle-doctor.1
@@ -1,14 +1,21 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-DOCTOR" "1" "March 2025" ""
+.TH "BUNDLE\-DOCTOR" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems
.SH "SYNOPSIS"
-\fBbundle doctor\fR [\-\-quiet] [\-\-gemfile=GEMFILE]
+\fBbundle doctor [diagnose]\fR [\-\-quiet] [\-\-gemfile=GEMFILE] [\-\-ssl]
+.br
+\fBbundle doctor ssl\fR [\-\-host=HOST] [\-\-tls\-version=TLS\-VERSION] [\-\-verify\-mode=VERIFY\-MODE]
+.br
+\fBbundle doctor\fR help [COMMAND]
.SH "DESCRIPTION"
+You can diagnose common Bundler problems with this command such as checking gem environment or SSL/TLS issue\.
+.SH "SUB\-COMMANDS"
+.SS "diagnose (default command)"
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:
+Examples of common problems caught include:
.IP "\(bu" 4
Invalid Bundler settings
.IP "\(bu" 4
@@ -20,11 +27,43 @@ Uninstalled gems
.IP "\(bu" 4
Missing dependencies
.IP "" 0
-.SH "OPTIONS"
+.P
+\fBOPTIONS\fR
.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\.
+.TP
+\fB\-\-ssl\fR
+Diagnose common SSL problems when connecting to https://rubygems\.org\.
+.IP
+This flag runs the \fBbundle doctor ssl\fR subcommand with default values underneath\.
+.SS "ssl"
+If you've experienced issues related to SSL certificates and/or TLS versions while connecting to https://rubygems\.org, this command can help troubleshoot common problems\. The diagnostic will perform a few checks such as:
+.IP "\(bu" 4
+Verify the Ruby OpenSSL version installed on your system\.
+.IP "\(bu" 4
+Check the OpenSSL library version used for compilation\.
+.IP "\(bu" 4
+Ensure CA certificates are correctly setup on your machine\.
+.IP "\(bu" 4
+Open a TLS connection and verify the outcome\.
+.IP "" 0
+.P
+\fBOPTIONS\fR
+.TP
+\fB\-\-host=HOST\fR
+Perform the diagnostic on HOST\. Defaults to \fBrubygems\.org\fR\.
+.TP
+\fB\-\-tls\-version=TLS\-VERSION\fR
+Specify the TLS version when opening the connection to HOST\.
+.IP
+Accepted values are: \fB1\.1\fR or \fB1\.2\fR\.
+.TP
+\fB\-\-verify\-mode=VERIFY\-MODE\fR
+Specify the TLS verify mode when opening the connection to HOST\. Defaults to \fBSSL_VERIFY_PEER\fR\.
+.IP
+Accepted values are: \fBCLIENT_ONCE\fR, \fBFAIL_IF_NO_PEER_CERT\fR, \fBNONE\fR, \fBPEER\fR\.
diff --git a/lib/bundler/man/bundle-doctor.1.ronn b/lib/bundler/man/bundle-doctor.1.ronn
index 5970f6188b..7495099ff5 100644
--- a/lib/bundler/man/bundle-doctor.1.ronn
+++ b/lib/bundler/man/bundle-doctor.1.ronn
@@ -3,16 +3,27 @@ bundle-doctor(1) -- Checks the bundle for common problems
## SYNOPSIS
-`bundle doctor` [--quiet]
- [--gemfile=GEMFILE]
+`bundle doctor [diagnose]` [--quiet]
+ [--gemfile=GEMFILE]
+ [--ssl]<br>
+`bundle doctor ssl` [--host=HOST]
+ [--tls-version=TLS-VERSION]
+ [--verify-mode=VERIFY-MODE]<br>
+`bundle doctor` help [COMMAND]
## DESCRIPTION
+You can diagnose common Bundler problems with this command such as checking gem environment or SSL/TLS issue.
+
+## SUB-COMMANDS
+
+### diagnose (default command)
+
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.
-Examples of common problems caught by bundle-doctor include:
+Examples of common problems caught include:
* Invalid Bundler settings
* Mismatched Ruby versions
@@ -20,7 +31,7 @@ Examples of common problems caught by bundle-doctor include:
* Uninstalled gems
* Missing dependencies
-## OPTIONS
+**OPTIONS**
* `--quiet`:
Only output warnings and errors.
@@ -31,3 +42,36 @@ Examples of common problems caught by bundle-doctor include:
will assume that the location of the Gemfile(5) is also the project's
root and will try to find `Gemfile.lock` and `vendor/cache` relative
to this location.
+
+* `--ssl`:
+ Diagnose common SSL problems when connecting to https://rubygems.org.
+
+ This flag runs the `bundle doctor ssl` subcommand with default values
+ underneath.
+
+### ssl
+
+If you've experienced issues related to SSL certificates and/or TLS versions while connecting
+to https://rubygems.org, this command can help troubleshoot common problems.
+The diagnostic will perform a few checks such as:
+
+* Verify the Ruby OpenSSL version installed on your system.
+* Check the OpenSSL library version used for compilation.
+* Ensure CA certificates are correctly setup on your machine.
+* Open a TLS connection and verify the outcome.
+
+**OPTIONS**
+
+* `--host=HOST`:
+ Perform the diagnostic on HOST. Defaults to `rubygems.org`.
+
+* `--tls-version=TLS-VERSION`:
+ Specify the TLS version when opening the connection to HOST.
+
+ Accepted values are: `1.1` or `1.2`.
+
+* `--verify-mode=VERIFY-MODE`:
+ Specify the TLS verify mode when opening the connection to HOST.
+ Defaults to `SSL_VERIFY_PEER`.
+
+ Accepted values are: `CLIENT_ONCE`, `FAIL_IF_NO_PEER_CERT`, `NONE`, `PEER`.
diff --git a/lib/bundler/man/bundle-env.1 b/lib/bundler/man/bundle-env.1
index c936294827..25fcb64891 100644
--- a/lib/bundler/man/bundle-env.1
+++ b/lib/bundler/man/bundle-env.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-ENV" "1" "March 2025" ""
+.TH "BUNDLE\-ENV" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-env\fR \- Print information about the environment Bundler is running under
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1
index 0ebbb4c198..c3a6a09d57 100644
--- a/lib/bundler/man/bundle-exec.1
+++ b/lib/bundler/man/bundle-exec.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-EXEC" "1" "March 2025" ""
+.TH "BUNDLE\-EXEC" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle
.SH "SYNOPSIS"
-\fBbundle exec\fR [\-\-keep\-file\-descriptors] [\-\-gemfile=GEMFILE] \fIcommand\fR
+\fBbundle exec\fR [\-\-gemfile=GEMFILE] \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
@@ -13,9 +13,6 @@ Essentially, if you would normally have run something like \fBrspec spec/my_spec
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\.
-.TP
\fB\-\-gemfile=GEMFILE\fR
Use the specified gemfile instead of [\fBGemfile(5)\fR][Gemfile(5)]\.
.SH "BUNDLE INSTALL \-\-BINSTUBS"
diff --git a/lib/bundler/man/bundle-exec.1.ronn b/lib/bundler/man/bundle-exec.1.ronn
index 3d3f0eed7b..e51a66a084 100644
--- a/lib/bundler/man/bundle-exec.1.ronn
+++ b/lib/bundler/man/bundle-exec.1.ronn
@@ -3,7 +3,7 @@ bundle-exec(1) -- Execute a command in the context of the bundle
## SYNOPSIS
-`bundle exec` [--keep-file-descriptors] [--gemfile=GEMFILE] <command>
+`bundle exec` [--gemfile=GEMFILE] <command>
## DESCRIPTION
@@ -20,10 +20,6 @@ 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.
-
* `--gemfile=GEMFILE`:
Use the specified gemfile instead of [`Gemfile(5)`][Gemfile(5)].
diff --git a/lib/bundler/man/bundle-fund.1 b/lib/bundler/man/bundle-fund.1
index 641d8cf864..caee1f81dd 100644
--- a/lib/bundler/man/bundle-fund.1
+++ b/lib/bundler/man/bundle-fund.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-FUND" "1" "March 2025" ""
+.TH "BUNDLE\-FUND" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-fund\fR \- Lists information about gems seeking funding assistance
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1
index 65882afa4f..87d7568246 100644
--- a/lib/bundler/man/bundle-gem.1
+++ b/lib/bundler/man/bundle-gem.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-GEM" "1" "March 2025" ""
+.TH "BUNDLE\-GEM" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
.SH "SYNOPSIS"
@@ -19,67 +19,87 @@ The generated project skeleton can be customized with OPTIONS, as explained belo
\fBgem\.test\fR
.IP "" 0
.SH "OPTIONS"
-.IP "\(bu" 4
-\fB\-\-exe\fR, \fB\-\-bin\fR, \fB\-b\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\.
-.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\-\-changelog\fR Add a \fBCHANGELOG\.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\-changelog\fR: Do not create a \fBCHANGELOG\.md\fR (overrides \fB\-\-changelog\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\-\-git\fR: Initialize a git repo inside your library\.
-.IP "\(bu" 4
-\fB\-\-github\-username=GITHUB_USERNAME\fR: Fill in GitHub username on README so that you don't have to do it manually\. Set a default with \fBbundle config set \-\-global gem\.github_username <your_username>\fR\.
-.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\.
-.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:
+.TP
+\fB\-\-exe\fR, \fB\-\-bin\fR, \fB\-b\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\.
+.TP
+\fB\-\-no\-exe\fR
+Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\.
+.TP
+\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\.
+.TP
+\fB\-\-no\-coc\fR
+Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\.
+.TP
+\fB\-\-changelog\fR
+Add a \fBCHANGELOG\.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\. Update the default with \fBbundle config set \-\-global gem\.changelog <true|false>\fR\.
+.TP
+\fB\-\-no\-changelog\fR
+Do not create a \fBCHANGELOG\.md\fR (overrides \fB\-\-changelog\fR specified in the global config)\.
+.TP
+\fB\-\-ext=c\fR, \fB\-\-ext=go\fR, \fB\-\-ext=rust\fR
+Add boilerplate for C, Go (currently go\-gem\-wrapper \fIhttps://github\.com/ruby\-go\-gem/go\-gem\-wrapper\fR based) or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\.
+.TP
+\fB\-\-no\-ext\fR
+Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\.
+.TP
+\fB\-\-git\fR
+Initialize a git repo inside your library\.
+.TP
+\fB\-\-github\-username=GITHUB_USERNAME\fR
+Fill in GitHub username on README so that you don't have to do it manually\. Set a default with \fBbundle config set \-\-global gem\.github_username <your_username>\fR\.
+.TP
+\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\.
+.TP
+\fB\-\-no\-mit\fR
+Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\.
+.TP
+\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\.
.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)\.
-.IP "\(bu" 4
-\fB\-\-changelog\fR: Generate changelog file\. Set a default with \fBbundle config set \-\-global gem\.changelog true\fR\.
-.IP "\(bu" 4
-\fB\-\-ci\fR, \fB\-\-ci=circle\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\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:
+.TP
+\fB\-\-no\-test\fR
+Do not use a test framework (overrides \fB\-\-test\fR specified in the global config)\.
+.TP
+\fB\-\-ci\fR, \fB\-\-ci=circle\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\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\.
.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)\.
-.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:
+.TP
+\fB\-\-no\-ci\fR
+Do not use a continuous integration service (overrides \fB\-\-ci\fR specified in the global config)\.
+.TP
+\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\.
.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)\.
-.IP "\(bu" 4
-\fB\-\-rubocop\fR: Add rubocop to the generated Rakefile and gemspec\. Set a default with \fBbundle config set \-\-global gem\.rubocop true\fR\.
-.IP "\(bu" 4
-\fB\-\-edit=EDIT\fR, \fB\-e=EDIT\fR: Open the resulting GEM_NAME\.gemspec in EDIT, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\.
-.IP "" 0
+.TP
+\fB\-\-no\-linter\fR
+Do not add a linter (overrides \fB\-\-linter\fR specified in the global config)\.
+.TP
+\fB\-\-edit=EDIT\fR, \fB\-e=EDIT\fR
+Open the resulting GEM_NAME\.gemspec in EDIT, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\.
+.TP
+\fB\-\-bundle\fR
+Run \fBbundle install\fR after creating the gem\.
+.TP
+\fB\-\-no\-bundle\fR
+Do not run \fBbundle install\fR after creating the gem\.
.SH "SEE ALSO"
.IP "\(bu" 4
bundle config(1) \fIbundle\-config\.1\.html\fR
diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn
index 13dc55c310..488c8113e4 100644
--- a/lib/bundler/man/bundle-gem.1.ronn
+++ b/lib/bundler/man/bundle-gem.1.ronn
@@ -41,17 +41,18 @@ configuration file using the following names:
Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the
global config).
-* `--changelog`
+* `--changelog`:
Add a `CHANGELOG.md` 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 `bundle gem` use.
+ Update the default with `bundle config set --global gem.changelog <true|false>`.
* `--no-changelog`:
Do not create a `CHANGELOG.md` (overrides `--changelog` specified in the
global config).
-* `--ext=c`, `--ext=rust`:
- Add boilerplate for C or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior
+* `--ext=c`, `--ext=go`, `--ext=rust`:
+ Add boilerplate for C, Go (currently [go-gem-wrapper](https://github.com/ruby-go-gem/go-gem-wrapper) based) or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior
is disabled by default.
* `--no-ext`:
@@ -95,9 +96,6 @@ configuration file using the following names:
Do not use a test framework (overrides `--test` specified in the global
config).
-* `--changelog`:
- Generate changelog file. Set a default with `bundle config set --global gem.changelog true`.
-
* `--ci`, `--ci=circle`, `--ci=github`, `--ci=gitlab`:
Specify the continuous integration service that Bundler should use when
generating the project. Acceptable values are `github`, `gitlab`
@@ -137,13 +135,16 @@ configuration file using the following names:
* `--no-linter`:
Do not add a linter (overrides `--linter` specified in the global config).
-* `--rubocop`:
- Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`.
-
* `--edit=EDIT`, `-e=EDIT`:
Open the resulting GEM_NAME.gemspec in EDIT, or the default editor if not
specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`.
+* `--bundle`:
+ Run `bundle install` after creating the gem.
+
+* `--no-bundle`:
+ Do not run `bundle install` after creating the gem.
+
## SEE ALSO
* [bundle config(1)](bundle-config.1.html)
diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1
index d8dd4660dc..3bcfd047e5 100644
--- a/lib/bundler/man/bundle-help.1
+++ b/lib/bundler/man/bundle-help.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-HELP" "1" "March 2025" ""
+.TH "BUNDLE\-HELP" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-help\fR \- Displays detailed help for each subcommand
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1
index 8124836519..49c2295f8c 100644
--- a/lib/bundler/man/bundle-info.1
+++ b/lib/bundler/man/bundle-info.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INFO" "1" "March 2025" ""
+.TH "BUNDLE\-INFO" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1
index 2e4b99b28a..63e2376c3f 100644
--- a/lib/bundler/man/bundle-init.1
+++ b/lib/bundler/man/bundle-init.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INIT" "1" "March 2025" ""
+.TH "BUNDLE\-INIT" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1
deleted file mode 100644
index 54cacaa56d..0000000000
--- a/lib/bundler/man/bundle-inject.1
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" generated with Ronn-NG/v0.10.1
-.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INJECT" "1" "March 2025" ""
-.SH "NAME"
-\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile
-.SH "SYNOPSIS"
-\fBbundle inject\fR [GEM] [VERSION] [\-\-source=SOURCE] [\-\-group=GROUP]
-.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\.
-.P
-Example:
-.IP "" 4
-.nf
-bundle install
-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\.
-.P
-The \fBbundle inject\fR command was deprecated in Bundler 2\.1 and will be removed in Bundler 3\.0\.
-.SH "OPTIONS"
-.TP
-\fB\-\-source=SOURCE\fR
-Install gem from the given source\.
-.TP
-\fB\-\-group=GROUP\fR
-Install gem into a bundler group\.
-
diff --git a/lib/bundler/man/bundle-inject.1.ronn b/lib/bundler/man/bundle-inject.1.ronn
deleted file mode 100644
index e2a911b6d8..0000000000
--- a/lib/bundler/man/bundle-inject.1.ronn
+++ /dev/null
@@ -1,32 +0,0 @@
-bundle-inject(1) -- Add named gem(s) with version requirements to Gemfile
-=========================================================================
-
-## SYNOPSIS
-
-`bundle inject` [GEM] [VERSION] [--source=SOURCE] [--group=GROUP]
-
-## DESCRIPTION
-
-Adds the named gem(s) with their version requirements to the resolved
-[`Gemfile(5)`][Gemfile(5)].
-
-This command will add the gem to both your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock if it
-isn't listed yet.
-
-Example:
-
- bundle install
- bundle inject 'rack' '> 0'
-
-This will inject the 'rack' gem with a version greater than 0 in your
-[`Gemfile(5)`][Gemfile(5)] and Gemfile.lock.
-
-The `bundle inject` command was deprecated in Bundler 2.1 and will be removed in Bundler 3.0.
-
-## OPTIONS
-
-* `--source=SOURCE`:
- Install gem from the given source.
-
-* `--group=GROUP`:
- Install gem into a bundler group.
diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1
index 272f4187ed..801768c7ec 100644
--- a/lib/bundler/man/bundle-install.1
+++ b/lib/bundler/man/bundle-install.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-INSTALL" "1" "March 2025" ""
+.TH "BUNDLE\-INSTALL" "1" "May 2026" ""
.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=SHEBANG] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-system] [\-\-trust\-policy=TRUST\-POLICY] [\-\-target\-rbconfig=TARGET\-RBCONFIG] [\-\-with=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-without=GROUP[ GROUP\|\.\|\.\|\.]]
+\fBbundle install\fR [\-\-cooldown=NUMBER] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-lockfile=LOCKFILE] [\-\-no\-cache] [\-\-no\-lock] [\-\-prefer\-local] [\-\-quiet] [\-\-retry=NUMBER] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-trust\-policy=TRUST\-POLICY] [\-\-target\-rbconfig=TARGET\-RBCONFIG]
.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
@@ -12,30 +12,12 @@ If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), B
.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[=BINSTUBS]\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 when the option is used without a value, or to the given \fB<BINSTUBS>\fR directory otherwise) 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\.
-.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\.
-.IP
-This option is deprecated in favor of the \fBdeployment\fR setting\.
+\fB\-\-cooldown=<number>\fR
+Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. See \fBcooldown\fR in bundle\-config(1) for details on the precedence between the CLI flag, Bundler config, and Gemfile per\-source settings\.
.TP
-\fB\-\-redownload\fR, \fB\-\-force\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\.
+\fB\-\-force\fR, \fB\-\-redownload\fR
+Force reinstalling every gem, even if already installed\.
.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\.
@@ -49,21 +31,19 @@ The maximum number of parallel download and install jobs\. The default is the nu
\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\.
.TP
+\fB\-\-lockfile=LOCKFILE\fR
+The location of the lockfile which Bundler should use\. This defaults to the Gemfile location with \fB\.lock\fR appended\.
+.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\.
.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\.
-.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\.
+\fB\-\-no\-lock\fR
+Do not create a lockfile\. Useful if you want to install dependencies but not lock versions of gems\. Recommended for library development, and other situations where the code is expected to work with a range of dependency versions\.
.IP
-This option is deprecated in favor of the \fBpath\fR setting\.
+This has the same effect as using \fBlockfile false\fR in the Gemfile\. See gemfile(5) for more information\.
.TP
\fB\-\-quiet\fR
Do not print progress information to the standard output\.
@@ -71,36 +51,16 @@ Do not print progress information to the standard output\.
\fB\-\-retry=[<number>]\fR
Retry failed network or git requests for \fInumber\fR times\.
.TP
-\fB\-\-shebang=SHEBANG\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 can 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\.
-.IP
-This option is deprecated in favor of the \fBsystem\fR setting\.
+Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install can 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\.
.TP
\fB\-\-trust\-policy=TRUST\-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\-\-target\-rbconfig=TARGET\-RBCONFIG\fR
Path to rbconfig\.rb for the deployment target platform\.
-.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 \fBdeployment\fR setting\. 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
@@ -120,14 +80,14 @@ In development, it's convenient to share the gems used in your application with
.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\.
+As a result, when \fBdeployment\fR is configured, \fBbundle install\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fBpath\fR setting\.
.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\.
+However, you can explicitly tell Bundler to skip installing certain groups with the \fBwithout\fR setting\. This setting 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)\.
+While the \fBwithout\fR setting will skip \fIinstalling\fR the gems in the specified groups, \fBbundle install\fR 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
@@ -148,7 +108,7 @@ end
.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\.
+When you configure \fBbundle config 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
diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn
index a3606826df..56fd8bdf42 100644
--- a/lib/bundler/man/bundle-install.1.ronn
+++ b/lib/bundler/man/bundle-install.1.ronn
@@ -3,28 +3,21 @@ bundle-install(1) -- Install the dependencies specified in your Gemfile
## SYNOPSIS
-`bundle install` [--binstubs[=DIRECTORY]]
- [--clean]
- [--deployment]
- [--frozen]
+`bundle install` [--cooldown=NUMBER]
+ [--force]
[--full-index]
[--gemfile=GEMFILE]
[--jobs=NUMBER]
[--local]
+ [--lockfile=LOCKFILE]
[--no-cache]
- [--no-prune]
- [--path PATH]
+ [--no-lock]
[--prefer-local]
[--quiet]
- [--redownload]
[--retry=NUMBER]
- [--shebang=SHEBANG]
[--standalone[=GROUP[ GROUP...]]]
- [--system]
[--trust-policy=TRUST-POLICY]
[--target-rbconfig=TARGET-RBCONFIG]
- [--with=GROUP[ GROUP...]]
- [--without=GROUP[ GROUP...]]
## DESCRIPTION
@@ -45,50 +38,15 @@ update process below under [CONSERVATIVE UPDATING][].
## OPTIONS
-The `--clean`, `--deployment`, `--frozen`, `--no-prune`, `--path`, `--shebang`,
-`--system`, `--without` and `--with` options are deprecated because they only
-make sense if they are applied to every subsequent `bundle install` run
-automatically and that requires `bundler` to silently remember them. Since
-`bundler` will no longer remember CLI flags in future versions, `bundle config`
-(see bundle-config(1)) should be used to apply them permanently.
+* `--cooldown=<number>`:
+ Only consider gem versions published at least <number> days ago when
+ resolving. Pass `0` to disable cooldown for this run, overriding any
+ per-source or global configuration. See `cooldown` in bundle-config(1)
+ for details on the precedence between the CLI flag, Bundler config,
+ and Gemfile per-source settings.
-* `--binstubs[=BINSTUBS]`:
- 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 `bin/`.
- This lets you link the binstub inside of an application to the exact gem
- version the application needs.
-
- Creates a directory (defaults to `~/bin` when the option is used without a
- value, or to the given `<BINSTUBS>` directory otherwise) 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 `PATH` variable. For
- instance, if the `rails` gem comes with a `rails` executable, this flag will
- create a `bin/rails` executable that ensures that all referred dependencies
- will be resolved using the bundled gems.
-
-* `--clean`:
- 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.
-
- This option is deprecated in favor of the `clean` setting.
-
-* `--deployment`:
- In [deployment mode][DEPLOYMENT MODE], 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.
-
- This option is deprecated in favor of the `deployment` setting.
-
-* `--redownload`, `--force`:
- Force download every gem, even if the required versions are already available
- locally.
-
-* `--frozen`:
- 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.
-
- This option is deprecated in favor of the `frozen` setting.
+* `--force`, `--redownload`:
+ Force reinstalling every gem, even if already installed.
* `--full-index`:
Bundler will not call Rubygems' API endpoint (default) but download and cache
@@ -112,6 +70,10 @@ automatically and that requires `bundler` to silently remember them. Since
appropriate platform-specific gem exists on `rubygems.org` it will not be
found.
+* `--lockfile=LOCKFILE`:
+ The location of the lockfile which Bundler should use. This defaults
+ to the Gemfile location with `.lock` appended.
+
* `--prefer-local`:
Force using locally installed gems, or gems already present in Rubygems' cache
or in `vendor/cache`, when resolving, even if newer versions are available
@@ -123,19 +85,14 @@ automatically and that requires `bundler` to silently remember them. Since
does not remove any gems in the cache but keeps the newly bundled gems from
being cached during the install.
-* `--no-prune`:
- Don't remove stale gems from the cache when the installation finishes.
-
- This option is deprecated in favor of the `no_prune` setting.
+* `--no-lock`:
+ Do not create a lockfile. Useful if you want to install dependencies but not
+ lock versions of gems. Recommended for library development, and other
+ situations where the code is expected to work with a range of dependency
+ versions.
-* `--path=PATH`:
- The location to install the specified gems to. This defaults to Rubygems'
- setting. Bundler shares this location with Rubygems, `gem install ...` will
- have gem installed there, too. Therefore, gems installed without a
- `--path ...` setting will show up by calling `gem list`. Accordingly, gems
- installed to other locations will not get listed.
-
- This option is deprecated in favor of the `path` setting.
+ This has the same effect as using `lockfile false` in the Gemfile.
+ See gemfile(5) for more information.
* `--quiet`:
Do not print progress information to the standard output.
@@ -143,27 +100,12 @@ automatically and that requires `bundler` to silently remember them. Since
* `--retry=[<number>]`:
Retry failed network or git requests for <number> times.
-* `--shebang=SHEBANG`:
- Uses the specified ruby executable (usually `ruby`) to execute the scripts
- created with `--binstubs`. In addition, if you use `--binstubs` together with
- `--shebang jruby` these executables will be changed to execute `jruby`
- instead.
-
- This option is deprecated in favor of the `shebang` setting.
-
* `--standalone[=<list>]`:
Makes a bundle that can work without depending on Rubygems or Bundler at
runtime. A space separated list of groups to install can be specified.
Bundler creates a directory named `bundle` and installs the bundle there. It
also generates a `bundle/bundler/setup.rb` file to replace Bundler's own setup
- in the manner required. Using this option implicitly sets `path`, which is a
- [remembered option][REMEMBERED OPTIONS].
-
-* `--system`:
- Installs the gems specified in the bundle to the system's Rubygems location.
- This overrides any previous configuration of `--path`.
-
- This option is deprecated in favor of the `system` setting.
+ in the manner required.
* `--trust-policy=TRUST-POLICY`:
Apply the Rubygems security policy <policy>, where policy is one of
@@ -174,26 +116,11 @@ automatically and that requires `bundler` to silently remember them. Since
* `--target-rbconfig=TARGET-RBCONFIG`:
Path to rbconfig.rb for the deployment target platform.
-* `--with=<list>`:
- 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.
-
- This option is deprecated in favor of the `with` setting.
-
-* `--without=<list>`:
- 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.
-
- This option is deprecated in favor of the `without` setting.
-
## DEPLOYMENT MODE
Bundler's defaults are optimized for development. To switch to
-defaults optimized for deployment and for CI, use the `--deployment`
-flag. Do not activate deployment mode on development machines, as it
+defaults optimized for deployment and for CI, use the `deployment`
+setting. Do not activate deployment mode on development machines, as it
will cause an error when the Gemfile(5) is modified.
1. A `Gemfile.lock` is required.
@@ -225,9 +152,9 @@ will cause an error when the Gemfile(5) is modified.
gems to the system, or the web server may not have permission to
read them.
- As a result, `bundle install --deployment` installs gems to
- the `vendor/bundle` directory in the application. This may be
- overridden using the `--path` option.
+ As a result, when `deployment` is configured, `bundle install` installs gems
+ to the `vendor/bundle` directory in the application. This may be
+ overridden using the `path` setting.
## INSTALLING GROUPS
@@ -235,12 +162,12 @@ By default, `bundle install` will install all gems in all groups
in your Gemfile(5), except those declared for a different platform.
However, you can explicitly tell Bundler to skip installing
-certain groups with the `--without` option. This option takes
+certain groups with the `without` setting. This setting takes
a space-separated list of groups.
-While the `--without` option will skip _installing_ the gems in the
-specified groups, it will still _download_ those gems and use them to
-resolve the dependencies of every gem in your Gemfile(5).
+While the `without` setting will skip _installing_ the gems in the
+specified groups, `bundle install` will still _download_ those gems and use them
+to resolve the dependencies of every gem in your Gemfile(5).
This is so that installing a different set of groups on another
machine (such as a production server) will not change the
@@ -266,7 +193,7 @@ For a simple illustration, consider the following Gemfile(5):
In this case, `sinatra` depends on any version of Rack (`>= 1.0`), while
`rack-perftools-profiler` depends on 1.x (`~> 1.0`).
-When you run `bundle install --without production` in development, we
+When you configure `bundle config without production` in development, we
look at the dependencies of `rack-perftools-profiler` 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
diff --git a/lib/bundler/man/bundle-issue.1 b/lib/bundler/man/bundle-issue.1
index 02d28c91ba..3af277ef86 100644
--- a/lib/bundler/man/bundle-issue.1
+++ b/lib/bundler/man/bundle-issue.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-ISSUE" "1" "March 2025" ""
+.TH "BUNDLE\-ISSUE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-issue\fR \- Get help reporting Bundler issues
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-licenses.1 b/lib/bundler/man/bundle-licenses.1
index d0dbf3913c..ab5996d2be 100644
--- a/lib/bundler/man/bundle-licenses.1
+++ b/lib/bundler/man/bundle-licenses.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-LICENSES" "1" "March 2025" ""
+.TH "BUNDLE\-LICENSES" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-licenses\fR \- Print the license of all gems in the bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1
index cd09ccab31..e759e0d449 100644
--- a/lib/bundler/man/bundle-list.1
+++ b/lib/bundler/man/bundle-list.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-LIST" "1" "March 2025" ""
+.TH "BUNDLE\-LIST" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle
.SH "SYNOPSIS"
@@ -19,6 +19,8 @@ bundle list \-\-without\-group test
bundle list \-\-only\-group dev
.P
bundle list \-\-only\-group dev test \-\-paths
+.P
+bundle list \-\-format json
.SH "OPTIONS"
.TP
\fB\-\-name\-only\fR
@@ -32,4 +34,7 @@ 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\.
+.TP
+\fB\-\-format=FORMAT\fR
+Format output ('json' is the only supported format)
diff --git a/lib/bundler/man/bundle-list.1.ronn b/lib/bundler/man/bundle-list.1.ronn
index 81bee0ac33..9ec2b13282 100644
--- a/lib/bundler/man/bundle-list.1.ronn
+++ b/lib/bundler/man/bundle-list.1.ronn
@@ -21,6 +21,8 @@ bundle list --only-group dev
bundle list --only-group dev test --paths
+bundle list --format json
+
## OPTIONS
* `--name-only`:
@@ -34,3 +36,6 @@ bundle list --only-group dev test --paths
* `--only-group=<list>`:
A space-separated list of groups of gems to print.
+
+* `--format=FORMAT`:
+ Format output ('json' is the only supported format)
diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1
index 8c9b94e8e2..396c8ff6ca 100644
--- a/lib/bundler/man/bundle-lock.1
+++ b/lib/bundler/man/bundle-lock.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-LOCK" "1" "March 2025" ""
+.TH "BUNDLE\-LOCK" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1
index eb4ac2e859..2aab59f14b 100644
--- a/lib/bundler/man/bundle-open.1
+++ b/lib/bundler/man/bundle-open.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-OPEN" "1" "March 2025" ""
+.TH "BUNDLE\-OPEN" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1
index 4f8a2cc56f..c2f8086e24 100644
--- a/lib/bundler/man/bundle-outdated.1
+++ b/lib/bundler/man/bundle-outdated.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-OUTDATED" "1" "March 2025" ""
+.TH "BUNDLE\-OUTDATED" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available
.SH "SYNOPSIS"
-\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-filter\-strict | \-\-strict] [\-\-update\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit]
+\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-filter\-strict | \-\-strict] [\-\-update\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit] [\-\-cooldown=NUMBER]
.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"
@@ -53,6 +53,9 @@ Only list patch newer versions\.
.TP
\fB\-\-only\-explicit\fR
Only list gems specified in your Gemfile, not their dependencies\.
+.TP
+\fB\-\-cooldown=<number>\fR
+Annotate (rather than hide) versions that are still inside the cooldown window of \fInumber\fR days\. The prose output appends "in cooldown for Nd more days" and the table form adds "(cooldown Nd)" to the Latest column\. See \fBcooldown\fR in bundle\-config(1)\.
.SH "PATCH LEVEL OPTIONS"
See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
.SH "FILTERING OUTPUT"
@@ -61,42 +64,42 @@ The 3 filtering options do not affect the resolution of versions, merely what ve
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
+* Gem Current Latest Requested Groups Release Date
+* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05
+* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default 2023\-11\-10
+* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test 2022\-08\-19
.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
+* Gem Current Latest Requested Groups Release Date
+* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default 2023\-11\-10
.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
+* Gem Current Latest Requested Groups Release Date
+* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test 2022\-08\-19
.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
+* Gem Current Latest Requested Groups Release Date
+* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05
.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
+* Gem Current Latest Requested Groups Release Date
+* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05
.fi
.IP "" 0
.P
diff --git a/lib/bundler/man/bundle-outdated.1.ronn b/lib/bundler/man/bundle-outdated.1.ronn
index 6f67a31977..e5badac2e9 100644
--- a/lib/bundler/man/bundle-outdated.1.ronn
+++ b/lib/bundler/man/bundle-outdated.1.ronn
@@ -16,6 +16,7 @@ bundle-outdated(1) -- List installed gems with newer versions available
[--filter-minor]
[--filter-patch]
[--only-explicit]
+ [--cooldown=NUMBER]
## DESCRIPTION
@@ -71,6 +72,12 @@ are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1.
* `--only-explicit`:
Only list gems specified in your Gemfile, not their dependencies.
+* `--cooldown=<number>`:
+ Annotate (rather than hide) versions that are still inside the
+ cooldown window of <number> days. The prose output appends "in
+ cooldown for Nd more days" and the table form adds "(cooldown Nd)" to
+ the Latest column. See `cooldown` in bundle-config(1).
+
## PATCH LEVEL OPTIONS
See [bundle update(1)](bundle-update.1.html) for details.
@@ -82,29 +89,29 @@ 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
+ * Gem Current Latest Requested Groups Release Date
+ * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05
+ * hashie 1.2.0 3.4.6 = 1.2.0 default 2023-11-10
+ * headless 2.2.3 2.3.1 = 2.2.3 test 2022-08-19
`--filter-major` would only show:
- * Gem Current Latest Requested Groups
- * hashie 1.2.0 3.4.6 = 1.2.0 default
+ * Gem Current Latest Requested Groups Release Date
+ * hashie 1.2.0 3.4.6 = 1.2.0 default 2023-11-10
`--filter-minor` would only show:
- * Gem Current Latest Requested Groups
- * headless 2.2.3 2.3.1 = 2.2.3 test
+ * Gem Current Latest Requested Groups Release Date
+ * headless 2.2.3 2.3.1 = 2.2.3 test 2022-08-19
`--filter-patch` would only show:
- * Gem Current Latest Requested Groups
- * faker 1.6.5 1.6.6 ~> 1.4 development, test
+ * Gem Current Latest Requested Groups Release Date
+ * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05
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
+ * Gem Current Latest Requested Groups Release Date
+ * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05
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 bdac52f937..39b7111263 100644
--- a/lib/bundler/man/bundle-platform.1
+++ b/lib/bundler/man/bundle-platform.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-PLATFORM" "1" "March 2025" ""
+.TH "BUNDLE\-PLATFORM" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1
index ded328dbd8..d182c7789b 100644
--- a/lib/bundler/man/bundle-plugin.1
+++ b/lib/bundler/man/bundle-plugin.1
@@ -1,12 +1,12 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-PLUGIN" "1" "March 2025" ""
+.TH "BUNDLE\-PLUGIN" "1" "May 2026" ""
.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=SOURCE] [\-\-version=VERSION] [\-\-git=GIT] [\-\-branch=BRANCH|\-\-ref=REF] [\-\-path=PATH]
.br
-\fBbundle plugin\fR uninstall PLUGINS
+\fBbundle plugin\fR uninstall PLUGINS [\-\-all]
.br
\fBbundle plugin\fR list
.br
@@ -16,18 +16,23 @@ You can install, uninstall, and list plugin(s) with this command to extend funct
.SH "SUB\-COMMANDS"
.SS "install"
Install the given plugin(s)\.
+.P
+For example, \fBbundle plugin install bundler\-graph\fR will install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. Note that the global source specified in Gemfile is ignored\.
+.P
+\fBOPTIONS\fR
.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\.
+\fB\-\-source=SOURCE\fR
+Install the plugin gem from a specific source, rather than from globally configured sources\.
+.IP
+Example: \fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR
.TP
-\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR
-You can specify the version of the gem via \fB\-\-version\fR\.
+\fB\-\-version=VERSION\fR
+Specify a version of the plugin gem to install via \fB\-\-version\fR\.
+.IP
+Example: \fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\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:
+\fB\-\-git=GIT\fR
+Install the plugin gem from a Git repository\. You can use standard Git URLs like:
.IP
\fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR
.br
@@ -37,12 +42,25 @@ Install bundler\-graph gem from Git repository\. You can use standard Git URLs l
.br
\fBfile:///path/to/repo\fR
.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\.
+Example: \fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR
.TP
-\fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR
-Install bundler\-graph gem from a local path\.
+\fB\-\-branch=BRANCH\fR
+When you specify \fB\-\-git\fR, you can use \fB\-\-branch\fR to use\.
+.TP
+\fB\-\-ref=REF\fR
+When you specify \fB\-\-git\fR, you can use \fB\-\-ref\fR to specify any tag, or commit hash (revision) to use\.
+.TP
+\fB\-\-path=PATH\fR
+Install the plugin gem from a local path\.
+.IP
+Example: \fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR
.SS "uninstall"
Uninstall the plugin(s) specified in PLUGINS\.
+.P
+\fBOPTIONS\fR
+.TP
+\fB\-\-all\fR
+Uninstall all the installed plugins\. If no plugin is installed, then it does nothing\.
.SS "list"
List the installed plugins and available commands\.
.P
diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn
index b0a34660ea..b54e0c08b4 100644
--- a/lib/bundler/man/bundle-plugin.1.ronn
+++ b/lib/bundler/man/bundle-plugin.1.ronn
@@ -3,10 +3,10 @@ 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>
-`bundle plugin` uninstall PLUGINS<br>
+`bundle plugin` install PLUGINS [--source=SOURCE] [--version=VERSION]
+ [--git=GIT] [--branch=BRANCH|--ref=REF]
+ [--path=PATH]<br>
+`bundle plugin` uninstall PLUGINS [--all]<br>
`bundle plugin` list<br>
`bundle plugin` help [COMMAND]
@@ -20,32 +20,53 @@ 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.
+For example, `bundle plugin install bundler-graph` will install bundler-graph
+gem from globally configured sources (defaults to RubyGems.org). Note that the
+global source specified 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.
+**OPTIONS**
-* `bundle plugin install bundler-graph --version 0.2.1`:
- You can specify the version of the gem via `--version`.
+* `--source=SOURCE`:
+ Install the plugin gem from a specific source, rather than from globally configured sources.
-* `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:
+ Example: `bundle plugin install bundler-graph --source https://example.com`
+
+* `--version=VERSION`:
+ Specify a version of the plugin gem to install via `--version`.
+
+ Example: `bundle plugin install bundler-graph --version 0.2.1`
+
+* `--git=GIT`:
+ Install the plugin gem from a Git repository. 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`
- When you specify `--git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use.
+ Example: `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`
+
+* `--branch=BRANCH`:
+ When you specify `--git`, you can use `--branch` to use.
-* `bundle plugin install bundler-graph --path ../bundler-graph`:
- Install bundler-graph gem from a local path.
+* `--ref=REF`:
+ When you specify `--git`, you can use `--ref` to specify any tag, or commit
+ hash (revision) to use.
+
+* `--path=PATH`:
+ Install the plugin gem from a local path.
+
+ Example: `bundle plugin install bundler-graph --path ../bundler-graph`
### uninstall
Uninstall the plugin(s) specified in PLUGINS.
+**OPTIONS**
+
+* `--all`:
+ Uninstall all the installed plugins. If no plugin is installed, then it does nothing.
+
### list
List the installed plugins and available commands.
diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1
index 294ef179a7..f6cc066571 100644
--- a/lib/bundler/man/bundle-pristine.1
+++ b/lib/bundler/man/bundle-pristine.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-PRISTINE" "1" "March 2025" ""
+.TH "BUNDLE\-PRISTINE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1
index 2e42a12de3..2ca40e74db 100644
--- a/lib/bundler/man/bundle-remove.1
+++ b/lib/bundler/man/bundle-remove.1
@@ -1,21 +1,15 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-REMOVE" "1" "March 2025" ""
+.TH "BUNDLE\-REMOVE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile
.SH "SYNOPSIS"
-\fBbundle remove [GEM [GEM \|\.\|\.\|\.]] [\-\-install]\fR
+`bundle remove [GEM [GEM \|\.\|\.\|\.]]
.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-remove.1.ronn b/lib/bundler/man/bundle-remove.1.ronn
index ceb1a980be..49cb4dc1fd 100644
--- a/lib/bundler/man/bundle-remove.1.ronn
+++ b/lib/bundler/man/bundle-remove.1.ronn
@@ -3,21 +3,14 @@ bundle-remove(1) -- Removes gems from the Gemfile
## SYNOPSIS
-`bundle remove [GEM [GEM ...]] [--install]`
+`bundle remove [GEM [GEM ...]]
## 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.
-## OPTIONS
-
-* `--install`:
- Runs `bundle install` 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).
-
Example:
bundle remove rails
bundle remove rails rack
-
-bundle remove rails rack --install
diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1
index d460e7a256..a2142694b8 100644
--- a/lib/bundler/man/bundle-show.1
+++ b/lib/bundler/man/bundle-show.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-SHOW" "1" "March 2025" ""
+.TH "BUNDLE\-SHOW" "1" "May 2026" ""
.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] [\-\-outdated]
+\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
@@ -13,7 +13,4 @@ Calling show with [GEM] will list the exact location of that gem on your machine
.TP
\fB\-\-paths\fR
List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\.
-.TP
-\fB\-\-outdated\fR
-Show verbose output including whether gems are outdated\.
diff --git a/lib/bundler/man/bundle-show.1.ronn b/lib/bundler/man/bundle-show.1.ronn
index 6e80b04696..a6a59a1445 100644
--- a/lib/bundler/man/bundle-show.1.ronn
+++ b/lib/bundler/man/bundle-show.1.ronn
@@ -5,7 +5,6 @@ bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem
`bundle show` [GEM]
[--paths]
- [--outdated]
## DESCRIPTION
@@ -20,6 +19,3 @@ machine.
* `--paths`:
List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)],
sorted by gem name.
-
-* `--outdated`:
- Show verbose output including whether gems are outdated.
diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1
index 855a5049aa..94161083fc 100644
--- a/lib/bundler/man/bundle-update.1
+++ b/lib/bundler/man/bundle-update.1
@@ -1,10 +1,10 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-UPDATE" "1" "March 2025" ""
+.TH "BUNDLE\-UPDATE" "1" "May 2026" ""
.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] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-pre] [\-\-redownload] [\-\-strict] [\-\-conservative]
+\fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-cooldown=NUMBER] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-pre] [\-\-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
@@ -29,6 +29,9 @@ Update the locked version of Ruby to the current version of Ruby\.
\fB\-\-bundler[=BUNDLER]\fR
Update the locked version of bundler to the invoked bundler version\.
.TP
+\fB\-\-force\fR, \fB\-\-redownload\fR
+Force reinstalling every gem, even if already installed\.
+.TP
\fB\-\-full\-index\fR
Fall back to using the single\-file index of all gems\.
.TP
@@ -44,9 +47,6 @@ Retry failed network or git requests for \fInumber\fR times\.
\fB\-\-quiet\fR
Only output warnings and errors\.
.TP
-\fB\-\-redownload\fR, \fB\-\-force\fR
-Force downloading every gem\.
-.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
.TP
@@ -64,6 +64,9 @@ Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR
.TP
\fB\-\-conservative\fR
Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\.
+.TP
+\fB\-\-cooldown=<number>\fR
+Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. Combine with \fB\-\-conservative\fR to minimize transitive churn when bypassing cooldown for an urgent update\. See \fBcooldown\fR in bundle\-config(1)\.
.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
diff --git a/lib/bundler/man/bundle-update.1.ronn b/lib/bundler/man/bundle-update.1.ronn
index 1b8b31951d..72fbf054d1 100644
--- a/lib/bundler/man/bundle-update.1.ronn
+++ b/lib/bundler/man/bundle-update.1.ronn
@@ -9,13 +9,14 @@ bundle-update(1) -- Update your gems to the latest available versions
[--local]
[--ruby]
[--bundler[=VERSION]]
+ [--cooldown=NUMBER]
+ [--force]
[--full-index]
[--gemfile=GEMFILE]
[--jobs=NUMBER]
[--quiet]
[--patch|--minor|--major]
[--pre]
- [--redownload]
[--strict]
[--conservative]
@@ -54,6 +55,9 @@ gem.
* `--bundler[=BUNDLER]`:
Update the locked version of bundler to the invoked bundler version.
+* `--force`, `--redownload`:
+ Force reinstalling every gem, even if already installed.
+
* `--full-index`:
Fall back to using the single-file index of all gems.
@@ -70,9 +74,6 @@ gem.
* `--quiet`:
Only output warnings and errors.
-* `--redownload`, `--force`:
- Force downloading every gem.
-
* `--patch`:
Prefer updating only to next patch version.
@@ -91,6 +92,13 @@ gem.
* `--conservative`:
Use bundle install conservative update behavior and do not allow indirect dependencies to be updated.
+* `--cooldown=<number>`:
+ Only consider gem versions published at least <number> days ago when
+ resolving. Pass `0` to disable cooldown for this run, overriding any
+ per-source or global configuration. Combine with `--conservative` to
+ minimize transitive churn when bypassing cooldown for an urgent
+ update. See `cooldown` in bundle-config(1).
+
## UPDATING ALL GEMS
If you run `bundle update --all`, bundler will ignore
diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1
index 17add566d8..751a408312 100644
--- a/lib/bundler/man/bundle-version.1
+++ b/lib/bundler/man/bundle-version.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-VERSION" "1" "March 2025" ""
+.TH "BUNDLE\-VERSION" "1" "May 2026" ""
.SH "NAME"
\fBbundle\-version\fR \- Prints Bundler version information
.SH "SYNOPSIS"
diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1
deleted file mode 100644
index 17e6f90cca..0000000000
--- a/lib/bundler/man/bundle-viz.1
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" generated with Ronn-NG/v0.10.1
-.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE\-VIZ" "1" "March 2025" ""
-.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=FILE\fR, \fB\-f=FILE\fR
-The name to use for the generated file\. See \fB\-\-format\fR option
-.TP
-\fB\-\-format=FORMAT\fR, \fB\-F=FORMAT\fR
-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=<list>\fR, \fB\-W=<list>\fR
-Exclude gems that are part of the specified named group\.
-
diff --git a/lib/bundler/man/bundle-viz.1.ronn b/lib/bundler/man/bundle-viz.1.ronn
deleted file mode 100644
index 730b0eed22..0000000000
--- a/lib/bundler/man/bundle-viz.1.ronn
+++ /dev/null
@@ -1,36 +0,0 @@
-bundle-viz(1) -- Generates a visual dependency graph for your Gemfile
-=====================================================================
-
-## SYNOPSIS
-
-`bundle viz` [--file=FILE]
- [--format=FORMAT]
- [--requirements]
- [--version]
- [--without=GROUP GROUP]
-
-## DESCRIPTION
-
-`viz` generates a PNG file of the current `Gemfile(5)` as a dependency graph.
-`viz` requires the ruby-graphviz gem (and its dependencies).
-
-The associated gems must also be installed via [`bundle install(1)`](bundle-install.1.html).
-
-`viz` command was deprecated in Bundler 2.2. Use [bundler-graph plugin](https://github.com/rubygems/bundler-graph) instead.
-
-## OPTIONS
-
-* `--file=FILE`, `-f=FILE`:
- The name to use for the generated file. See `--format` option
-
-* `--format=FORMAT`, `-F=FORMAT`:
- This is output format option. Supported format is png, jpg, svg, dot ...
-
-* `--requirements`, `-R`:
- Set to show the version of each required dependency.
-
-* `--version`, `-v`:
- Set to show each gem version.
-
-* `--without=<list>`, `-W=<list>`:
- 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 3b40f58210..167815631a 100644
--- a/lib/bundler/man/bundle.1
+++ b/lib/bundler/man/bundle.1
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "BUNDLE" "1" "March 2025" ""
+.TH "BUNDLE" "1" "May 2026" ""
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management
.SH "SYNOPSIS"
@@ -66,9 +66,6 @@ Open an installed gem in the editor
\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
@@ -94,9 +91,3 @@ Manage Bundler plugins
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\.
-.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/bundle.1.ronn b/lib/bundler/man/bundle.1.ronn
index 8245effabd..1c2b3df7af 100644
--- a/lib/bundler/man/bundle.1.ronn
+++ b/lib/bundler/man/bundle.1.ronn
@@ -76,9 +76,6 @@ We divide `bundle` subcommands into primary commands and utilities:
* [`bundle lock(1)`](bundle-lock.1.html):
Generate a lockfile for your dependencies
-* [`bundle viz(1)`](bundle-viz.1.html) (deprecated):
- Generate a visual representation of your dependencies
-
* [`bundle init(1)`](bundle-init.1.html):
Generate a simple `Gemfile`, placed in the current directory
@@ -108,9 +105,3 @@ We divide `bundle` subcommands into primary commands and utilities:
When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES,
Bundler will try to find an executable on your path named `bundler-<command>`
and execute it, passing down any extra arguments to it.
-
-## OBSOLETE
-
-These commands are obsolete and should no longer be used:
-
-* `bundle inject(1)`
diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5
index f52864a2bf..64e93c4b15 100644
--- a/lib/bundler/man/gemfile.5
+++ b/lib/bundler/man/gemfile.5
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1
-.TH "GEMFILE" "5" "March 2025" ""
+.TH "GEMFILE" "5" "May 2026" ""
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
.SH "SYNOPSIS"
@@ -460,6 +460,50 @@ The \fBgemspec\fR method adds any runtime dependencies as gem requirements in th
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\.
.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 "OVERRIDE"
+The \fBoverride\fR directive rewrites a constraint on another gem before resolution runs\. It targets the common case where an upstream gem's published metadata is too narrow on the current project's machine \-\- a stale upper bound, an unwanted floor, or a transitive pin that has to be lifted\.
+.IP "" 4
+.nf
+override <target>, <field>: <operation>
+.fi
+.IP "" 0
+.P
+\fB<target>\fR is a gem name string or \fB:all\fR\. \fB<field>\fR is one of \fBversion:\fR, \fBrequired_ruby_version:\fR, or \fBrequired_rubygems_version:\fR\. \fB<operation>\fR is one of:
+.IP "\(bu" 4
+a version requirement string (e\.g\. \fB">= 8\.0"\fR), which \fBreplaces\fR the target's requirement absolutely\. The original requirement, both direct and transitive, is discarded in favour of the override\.
+.IP "\(bu" 4
+\fB:ignore_upper\fR, which removes upper\-bound operators (\fB<\fR and \fB<=\fR) from the existing requirement and folds \fB~>\fR into its lower bound (\fB~> 1\.5\fR becomes \fB>= 1\.5\fR)\. Other operators, including \fB!=\fR, are preserved\.
+.IP "\(bu" 4
+\fBnil\fR, which collapses the requirement to \fB>= 0\fR (no constraint at all)\.
+.IP "" 0
+.P
+\fB:all\fR only applies to \fBrequired_ruby_version:\fR and \fBrequired_rubygems_version:\fR\. A per\-gem override on the same field takes precedence over an \fB:all\fR override\. \fB:all + version:\fR is rejected: version requirements only make sense per gem\.
+.P
+Multiple \fBoverride\fR calls for distinct targets are allowed; declaring the same \fBtarget\fR and \fBfield\fR twice is an error\.
+.IP "" 4
+.nf
+source "https://rubygems\.org"
+
+# Force every reference to "rails" \-\- direct or transitive \-\- to >= 8\.0\.
+override "rails", version: ">= 8\.0"
+
+# Strip the upper bound on nokogiri\.
+override "nokogiri", version: :ignore_upper
+
+# Drop the version pin on legacy entirely\.
+override "legacy", version: nil
+
+# Loosen every gem's required_ruby_version upper bound\.
+override :all, required_ruby_version: :ignore_upper
+
+# Override one specific gem's required_rubygems_version\.
+override "tricky", required_rubygems_version: nil
+
+gem "rails", "~> 7\.0"
+.fi
+.IP "" 0
+.P
+The override only affects resolution and the install\-time Ruby/RubyGems compatibility checks; \fBGemfile\.lock\fR continues to reflect the resolved versions, not the rewritten requirements\. When resolution still fails, Bundler appends the active overrides (with their Gemfile location) to the error message so it is clear which override shaped the constraint set\.
.SH "SOURCE PRIORITY"
When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
.IP "1." 4
@@ -469,4 +513,35 @@ For implicit gems (dependencies of explicit gems), any source, git, or path repo
.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
+.SH "LOCKFILE"
+By default, Bundler will create a lockfile by adding \fB\.lock\fR to the end of the Gemfile name\. To change this, use the \fBlockfile\fR method:
+.IP "" 4
+.nf
+lockfile "/path/to/lockfile\.lock"
+.fi
+.IP "" 0
+.P
+This is useful when you want to use different lockfiles per ruby version or platform\.
+.P
+To avoid writing a lock file, use \fBfalse\fR as the argument:
+.IP "" 4
+.nf
+lockfile false
+.fi
+.IP "" 0
+.P
+This is useful for library development and other situations where the code is expected to work with a range of dependency versions\.
+.SS "LOCKFILE PRECEDENCE"
+When determining path to the lockfile or whether to create a lockfile, the following precedence is used:
+.IP "1." 4
+The \fBbundle install\fR \fB\-\-no\-lock\fR option (which disables lockfile creation)\.
+.IP "2." 4
+The \fBbundle install\fR \fB\-\-lockfile\fR option\.
+.IP "3." 4
+The \fBBUNDLE_LOCKFILE\fR environment variable\.
+.IP "4." 4
+The \fBlockfile\fR method in the Gemfile\.
+.IP "5." 4
+The default behavior of adding \fB\.lock\fR to the end of the Gemfile name\.
+.IP "" 0
diff --git a/lib/bundler/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn
index 802549737e..69fef90654 100644
--- a/lib/bundler/man/gemfile.5.ronn
+++ b/lib/bundler/man/gemfile.5.ronn
@@ -541,6 +541,59 @@ When a `gemspec` 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 `gemspec` gem.
+## OVERRIDE
+
+The `override` directive rewrites a constraint on another gem before
+resolution runs. It targets the common case where an upstream gem's
+published metadata is too narrow on the current project's machine -- a stale
+upper bound, an unwanted floor, or a transitive pin that has to be lifted.
+
+ override <target>, <field>: <operation>
+
+`<target>` is a gem name string or `:all`. `<field>` is one of `version:`,
+`required_ruby_version:`, or `required_rubygems_version:`. `<operation>` is
+one of:
+
+ * a version requirement string (e.g. `">= 8.0"`), which **replaces** the
+ target's requirement absolutely. The original requirement, both direct
+ and transitive, is discarded in favour of the override.
+ * `:ignore_upper`, which removes upper-bound operators (`<` and `<=`) from
+ the existing requirement and folds `~>` into its lower bound (`~> 1.5`
+ becomes `>= 1.5`). Other operators, including `!=`, are preserved.
+ * `nil`, which collapses the requirement to `>= 0` (no constraint at all).
+
+`:all` only applies to `required_ruby_version:` and `required_rubygems_version:`.
+A per-gem override on the same field takes precedence over an `:all` override.
+`:all + version:` is rejected: version requirements only make sense per gem.
+
+Multiple `override` calls for distinct targets are allowed; declaring the
+same `target` and `field` twice is an error.
+
+ source "https://rubygems.org"
+
+ # Force every reference to "rails" -- direct or transitive -- to >= 8.0.
+ override "rails", version: ">= 8.0"
+
+ # Strip the upper bound on nokogiri.
+ override "nokogiri", version: :ignore_upper
+
+ # Drop the version pin on legacy entirely.
+ override "legacy", version: nil
+
+ # Loosen every gem's required_ruby_version upper bound.
+ override :all, required_ruby_version: :ignore_upper
+
+ # Override one specific gem's required_rubygems_version.
+ override "tricky", required_rubygems_version: nil
+
+ gem "rails", "~> 7.0"
+
+The override only affects resolution and the install-time Ruby/RubyGems
+compatibility checks; `Gemfile.lock` continues to reflect the resolved
+versions, not the rewritten requirements. When resolution still fails,
+Bundler appends the active overrides (with their Gemfile location) to the
+error message so it is clear which override shaped the constraint set.
+
## SOURCE PRIORITY
When attempting to locate a gem to satisfy a gem requirement,
@@ -556,3 +609,31 @@ bundler uses the following priority order:
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.
+
+## LOCKFILE
+
+By default, Bundler will create a lockfile by adding `.lock` to the end of the
+Gemfile name. To change this, use the `lockfile` method:
+
+ lockfile "/path/to/lockfile.lock"
+
+This is useful when you want to use different lockfiles per ruby version or
+platform.
+
+To avoid writing a lock file, use `false` as the argument:
+
+ lockfile false
+
+This is useful for library development and other situations where the code is
+expected to work with a range of dependency versions.
+
+### LOCKFILE PRECEDENCE
+
+When determining path to the lockfile or whether to create a lockfile, the
+following precedence is used:
+
+1. The `bundle install` `--no-lock` option (which disables lockfile creation).
+1. The `bundle install` `--lockfile` option.
+1. The `BUNDLE_LOCKFILE` environment variable.
+1. The `lockfile` method in the Gemfile.
+1. The default behavior of adding `.lock` to the end of the Gemfile name.
diff --git a/lib/bundler/man/index.txt b/lib/bundler/man/index.txt
index 3ea3495f1b..f610ba852a 100644
--- a/lib/bundler/man/index.txt
+++ b/lib/bundler/man/index.txt
@@ -15,7 +15,6 @@ bundle-gem(1) bundle-gem.1
bundle-help(1) bundle-help.1
bundle-info(1) bundle-info.1
bundle-init(1) bundle-init.1
-bundle-inject(1) bundle-inject.1
bundle-install(1) bundle-install.1
bundle-issue(1) bundle-issue.1
bundle-licenses(1) bundle-licenses.1
@@ -30,4 +29,3 @@ bundle-remove(1) bundle-remove.1
bundle-show(1) bundle-show.1
bundle-update(1) bundle-update.1
bundle-version(1) bundle-version.1
-bundle-viz(1) bundle-viz.1
diff --git a/lib/bundler/match_metadata.rb b/lib/bundler/match_metadata.rb
index 6fd2994a85..92aeb2e893 100644
--- a/lib/bundler/match_metadata.rb
+++ b/lib/bundler/match_metadata.rb
@@ -14,6 +14,18 @@ module Bundler
@required_rubygems_version.satisfied_by?(Gem.rubygems_version)
end
+ def matches_current_metadata_with_overrides?(overrides)
+ matches_current_ruby_with_overrides?(overrides) && matches_current_rubygems_with_overrides?(overrides)
+ end
+
+ def matches_current_ruby_with_overrides?(overrides)
+ effective_required_version(@required_ruby_version, :required_ruby_version, overrides).satisfied_by?(Gem.ruby_version)
+ end
+
+ def matches_current_rubygems_with_overrides?(overrides)
+ effective_required_version(@required_rubygems_version, :required_rubygems_version, overrides).satisfied_by?(Gem.rubygems_version)
+ end
+
def expanded_dependencies
runtime_dependencies + [
metadata_dependency("Ruby", @required_ruby_version),
@@ -26,5 +38,13 @@ module Bundler
Gem::Dependency.new("#{name}\0", requirement)
end
+
+ private
+
+ def effective_required_version(requirement, field, overrides)
+ return requirement if overrides.nil? || overrides.empty?
+ override = Override.find_for(overrides, name, field)
+ override ? override.apply_to(requirement) : requirement
+ end
end
end
diff --git a/lib/bundler/match_platform.rb b/lib/bundler/match_platform.rb
index ece9fb8679..479818e5ec 100644
--- a/lib/bundler/match_platform.rb
+++ b/lib/bundler/match_platform.rb
@@ -1,23 +1,42 @@
# frozen_string_literal: true
-require_relative "gem_helpers"
-
module Bundler
module MatchPlatform
- include GemHelpers
+ def installable_on_platform?(target_platform) # :nodoc:
+ return true if [Gem::Platform::RUBY, nil, target_platform].include?(platform)
+ return true if Gem::Platform.new(platform) === target_platform
- def match_platform(p)
- MatchPlatform.platforms_match?(platform, p)
+ false
end
- 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 local_platform == gemspec_platform
- gemspec_platform = Gem::Platform.new(gemspec_platform)
- return true if gemspec_platform === local_platform
+ def self.select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
+ matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked)
- false
+ Gem::Platform.sort_and_filter_best_platform_match(matching, platform)
+ end
+
+ def self.select_best_local_platform_match(specs, force_ruby: false)
+ local = Bundler.local_platform
+ matching = select_all_platform_match(specs, local, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
+
+ Gem::Platform.sort_best_platform_match(matching, local)
+ end
+
+ def self.select_all_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
+ matching = specs.select {|spec| spec.installable_on_platform?(force_ruby ? Gem::Platform::RUBY : platform) }
+
+ specs.each(&:force_ruby_platform!) if force_ruby
+
+ if prefer_locked
+ locked_originally = matching.select {|spec| spec.is_a?(::Bundler::LazySpecification) }
+ return locked_originally if locked_originally.any?
+ end
+
+ matching
+ end
+
+ def self.generic_local_platform_is_ruby?
+ Bundler.generic_local_platform == Gem::Platform::RUBY
end
end
end
diff --git a/lib/bundler/match_remote_metadata.rb b/lib/bundler/match_remote_metadata.rb
index 5e46d52441..601af7e55d 100644
--- a/lib/bundler/match_remote_metadata.rb
+++ b/lib/bundler/match_remote_metadata.rb
@@ -6,19 +6,34 @@ module Bundler
# API didn't include that field, so some marshalled specs in the index have it
# set to +nil+.
def matches_current_ruby?
- @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default
-
+ ensure_required_ruby_version_loaded
super
end
def matches_current_rubygems?
- # A fallback is included because the original version of the specification
- # API didn't include that field, so some marshalled specs in the index have it
- # set to +nil+.
- @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default
+ ensure_required_rubygems_version_loaded
+ super
+ end
+
+ def matches_current_ruby_with_overrides?(overrides)
+ ensure_required_ruby_version_loaded
+ super
+ end
+ def matches_current_rubygems_with_overrides?(overrides)
+ ensure_required_rubygems_version_loaded
super
end
+
+ private
+
+ def ensure_required_ruby_version_loaded
+ @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default # rubocop:disable Naming/MemoizedInstanceVariableName
+ end
+
+ def ensure_required_rubygems_version_loaded
+ @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default # rubocop:disable Naming/MemoizedInstanceVariableName
+ end
end
module MatchRemoteMetadata
diff --git a/lib/bundler/materialization.rb b/lib/bundler/materialization.rb
index 6542c07649..82e48464a7 100644
--- a/lib/bundler/materialization.rb
+++ b/lib/bundler/materialization.rb
@@ -22,14 +22,14 @@ module Bundler
@specs ||= if @candidates.nil?
[]
elsif platform
- GemHelpers.select_best_platform_match(@candidates, platform, force_ruby: dep.force_ruby_platform)
+ MatchPlatform.select_best_platform_match(@candidates, platform, force_ruby: dep.force_ruby_platform)
else
- GemHelpers.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
+ MatchPlatform.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
end
end
def dependencies
- specs.first.runtime_dependencies.map {|d| [d, platform] }
+ (materialized_spec || specs.first).runtime_dependencies.map {|d| [d, platform] }
end
def materialized_spec
diff --git a/lib/bundler/override.rb b/lib/bundler/override.rb
new file mode 100644
index 0000000000..0e0ec59fd7
--- /dev/null
+++ b/lib/bundler/override.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Bundler
+ class Override
+ UPPER_BOUND_OPERATORS = ["<", "<="].freeze
+
+ def self.find_for(overrides, name, field)
+ overrides.find {|o| o.target == name && o.field == field } ||
+ overrides.find {|o| o.target == :all && o.field == field }
+ end
+
+ # Attach the given overrides onto every LazySpecification in `specs` so
+ # downstream consumers (LazySpecification#choose_compatible, the install-
+ # time compatibility check, etc.) can read the override list off the spec
+ # itself. Non-LazySpec entries (StubSpecification, Gem::Specification, ...)
+ # are left untouched.
+ def self.attach(specs, overrides)
+ return if overrides.nil? || overrides.empty?
+ specs.each {|s| s.overrides = overrides if s.is_a?(LazySpecification) }
+ end
+
+ attr_reader :target, :field, :operation, :source_location
+
+ def initialize(target, field, operation, source_location: nil)
+ @target = target
+ @field = field
+ @operation = operation
+ @source_location = source_location
+ end
+
+ def source_location_label
+ return nil unless @source_location
+ "#{File.basename(@source_location.path)}:#{@source_location.lineno}"
+ end
+
+ def apply_to(requirement)
+ case operation
+ when nil
+ Gem::Requirement.default
+ when :ignore_upper
+ remove_upper_bounds(requirement)
+ when String
+ Gem::Requirement.new(operation)
+ else
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
+ end
+ end
+
+ private
+
+ def remove_upper_bounds(requirement)
+ return Gem::Requirement.default if requirement.nil? || requirement.none?
+
+ preserved = requirement.requirements.filter_map do |op, version|
+ if UPPER_BOUND_OPERATORS.include?(op)
+ nil
+ elsif op == "~>"
+ [">=", version]
+ else
+ [op, version]
+ end
+ end
+
+ return Gem::Requirement.default if preserved.empty?
+
+ Gem::Requirement.new(preserved.map {|op, v| "#{op} #{v}" })
+ end
+ end
+end
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index 44129cc0ff..faca6bea53 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -113,7 +113,7 @@ module Bundler
return if definition.dependencies.empty?
- plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p }
+ plugins = definition.dependencies.map(&:name)
installed_specs = Installer.new.install_definition(definition)
save_plugins plugins, installed_specs, builder.inferred_plugins
@@ -220,7 +220,7 @@ module Bundler
#
# @param [String] event
def hook(event, *args, &arg_blk)
- return unless Bundler.feature_flag.plugins?
+ return unless Bundler.settings[:plugins]
unless Events.defined_event?(event)
raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events"
end
@@ -253,10 +253,13 @@ module Bundler
# @param [Array<String>] names of inferred source plugins that can be ignored
def save_plugins(plugins, specs, optional_plugins = [])
plugins.each do |name|
- next if index.installed?(name)
-
spec = specs[name]
+ # It's possible that the `plugin` found in the Gemfile don't appear in the specs. For instance when
+ # calling `BUNDLE_WITHOUT=default bundle install`, the plugins will not get installed.
+ next if spec.nil?
+ next if index.up_to_date?(spec)
+
save_plugin(name, spec, optional_plugins.include?(name))
end
end
diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb
index 6c888d0373..798326673a 100644
--- a/lib/bundler/plugin/api/source.rb
+++ b/lib/bundler/plugin/api/source.rb
@@ -74,6 +74,14 @@ module Bundler
{}
end
+ # Download the gem specified by the spec at appropriate path.
+ #
+ # A source plugin can implement this method to split the download and the
+ # installation of a gem.
+ #
+ # @return [Boolean] Whether the download of the gem succeeded.
+ def download(spec, opts); end
+
# Install the gem specified by the spec at appropriate path.
# `install_path` provides a sufficient default, if the source can only
# satisfy one gem, but is not binding.
diff --git a/lib/bundler/plugin/events.rb b/lib/bundler/plugin/events.rb
index 29c05098ae..3fbf60307e 100644
--- a/lib/bundler/plugin/events.rb
+++ b/lib/bundler/plugin/events.rb
@@ -31,6 +31,54 @@ module Bundler
end
# @!parse
+ # A hook called before the Gemfile is evaluated
+ # Includes the Gemfile path and the Lockfile path
+ # GEM_BEFORE_EVAL = "before-eval"
+ define :GEM_BEFORE_EVAL, "before-eval"
+
+ # @!parse
+ # A hook called after the Gemfile is evaluated
+ # Includes a Bundler::Definition
+ # GEM_AFTER_EVAL = "after-eval"
+ define :GEM_AFTER_EVAL, "after-eval"
+
+ # @!parse
+ # A hook called before any gems install
+ # Includes an Array of Bundler::Dependency objects
+ # GEM_BEFORE_INSTALL_ALL = "before-install-all"
+ define :GEM_BEFORE_INSTALL_ALL, "before-install-all"
+
+ # @!parse
+ # A hook called before each individual gem is downloaded from a remote source.
+ # Includes a spec-like object responding to the Gem::Specification API
+ # (for example, a Bundler spec proxy such as Bundler::EndpointSpecification
+ # or Bundler::RemoteSpecification). Does not fire when the gem is already
+ # present at the initial download-cache check.
+ # GEM_BEFORE_FETCH = "before-fetch"
+ define :GEM_BEFORE_FETCH, "before-fetch"
+
+ # @!parse
+ # A hook called after each individual gem is downloaded from a remote source.
+ # Includes a spec-like object responding to the Gem::Specification API
+ # (for example, a Bundler spec proxy such as Bundler::EndpointSpecification
+ # or Bundler::RemoteSpecification). Does not fire when the gem is already
+ # present at the initial download-cache check.
+ # GEM_AFTER_FETCH = "after-fetch"
+ define :GEM_AFTER_FETCH, "after-fetch"
+
+ # @!parse
+ # A hook called before a git source is fetched or checked out.
+ # Includes a Bundler::Source::Git reference.
+ # GIT_BEFORE_FETCH = "before-git-fetch"
+ define :GIT_BEFORE_FETCH, "before-git-fetch"
+
+ # @!parse
+ # A hook called after a git source is fetched or checked out.
+ # Includes a Bundler::Source::Git reference.
+ # GIT_AFTER_FETCH = "after-git-fetch"
+ define :GIT_AFTER_FETCH, "after-git-fetch"
+
+ # @!parse
# A hook called before each individual gem is installed
# Includes a Bundler::ParallelInstaller::SpecInstallation.
# No state, error, post_install_message will be present as nothing has installed yet
@@ -46,18 +94,18 @@ module Bundler
define :GEM_AFTER_INSTALL, "after-install"
# @!parse
- # A hook called before any gems install
- # Includes an Array of Bundler::Dependency objects
- # GEM_BEFORE_INSTALL_ALL = "before-install-all"
- define :GEM_BEFORE_INSTALL_ALL, "before-install-all"
-
- # @!parse
# A hook called after any gems install
# Includes an Array of Bundler::Dependency objects
# GEM_AFTER_INSTALL_ALL = "after-install-all"
define :GEM_AFTER_INSTALL_ALL, "after-install-all"
# @!parse
+ # A hook called before any gems require
+ # Includes an Array of Bundler::Dependency objects.
+ # GEM_BEFORE_REQUIRE_ALL = "before-require-all"
+ define :GEM_BEFORE_REQUIRE_ALL, "before-require-all"
+
+ # @!parse
# A hook called before each individual gem is required
# Includes a Bundler::Dependency.
# GEM_BEFORE_REQUIRE = "before-require"
@@ -70,16 +118,10 @@ module Bundler
define :GEM_AFTER_REQUIRE, "after-require"
# @!parse
- # A hook called before any gems require
- # Includes an Array of Bundler::Dependency objects.
- # GEM_BEFORE_REQUIRE_ALL = "before-require-all"
- define :GEM_BEFORE_REQUIRE_ALL, "before-require-all"
-
- # @!parse
# A hook called after all gems required
# Includes an Array of Bundler::Dependency objects.
# GEM_AFTER_REQUIRE_ALL = "after-require-all"
- define :GEM_AFTER_REQUIRE_ALL, "after-require-all"
+ define :GEM_AFTER_REQUIRE_ALL, "after-require-all"
end
end
end
diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb
index 0682d37772..1dfb061304 100644
--- a/lib/bundler/plugin/index.rb
+++ b/lib/bundler/plugin/index.rb
@@ -119,6 +119,12 @@ module Bundler
@plugin_paths[name]
end
+ def up_to_date?(spec)
+ path = installed?(spec.name)
+
+ path == spec.full_gem_path
+ end
+
def installed_plugins
@plugin_paths.keys
end
@@ -157,6 +163,8 @@ module Bundler
# @param [Pathname] index file path
# @param [Boolean] is the index file global index
def load_index(index_file, global = false)
+ base = base_for_index(global)
+
SharedHelpers.filesystem_access(index_file, :read) do |index_f|
valid_file = index_f&.exist? && !index_f.size.zero?
break unless valid_file
@@ -168,8 +176,8 @@ module Bundler
@commands.merge!(index["commands"])
@hooks.merge!(index["hooks"])
- @load_paths.merge!(index["load_paths"])
- @plugin_paths.merge!(index["plugin_paths"])
+ @load_paths.merge!(transform_index_paths(index["load_paths"]) {|p| absolutize_path(p, base) })
+ @plugin_paths.merge!(transform_index_paths(index["plugin_paths"]) {|p| absolutize_path(p, base) })
@sources.merge!(index["sources"]) unless global
end
end
@@ -178,11 +186,13 @@ module Bundler
# instance variables in YAML format. (The instance variables are supposed
# to be only String key value pairs)
def save_index
+ base = base_for_index(false)
+
index = {
"commands" => @commands,
"hooks" => @hooks,
- "load_paths" => @load_paths,
- "plugin_paths" => @plugin_paths,
+ "load_paths" => transform_index_paths(@load_paths) {|p| relativize_path(p, base) },
+ "plugin_paths" => transform_index_paths(@plugin_paths) {|p| relativize_path(p, base) },
"sources" => @sources,
}
@@ -192,6 +202,40 @@ module Bundler
File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) }
end
end
+
+ def base_for_index(global)
+ global ? Plugin.global_root : Plugin.root
+ end
+
+ def transform_index_paths(paths)
+ return {} unless paths
+
+ paths.transform_values do |value|
+ if value.is_a?(Array)
+ value.map {|path| yield path }
+ else
+ yield value
+ end
+ end
+ end
+
+ def relativize_path(path, base)
+ pathname = Pathname.new(path)
+ return path unless pathname.absolute?
+
+ base_path = Pathname.new(base)
+ if pathname == base_path || pathname.to_s.start_with?(base_path.to_s + File::SEPARATOR)
+ pathname.relative_path_from(base_path).to_s
+ else
+ path
+ end
+ end
+
+ def absolutize_path(path, base)
+ pathname = Pathname.new(path)
+ pathname = Pathname.new(base).join(pathname) unless pathname.absolute?
+ pathname.to_s
+ end
end
end
end
diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb
index ac3c3ea7f3..9be8b36843 100644
--- a/lib/bundler/plugin/installer.rb
+++ b/lib/bundler/plugin/installer.rb
@@ -43,16 +43,6 @@ module Bundler
private
def check_sources_consistency!(options)
- 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
@@ -120,7 +110,8 @@ module Bundler
paths = {}
specs.each do |spec|
- spec.source.install spec
+ spec.source.download(spec)
+ spec.source.install(spec)
paths[spec.name] = spec
end
diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb
index 746996de55..d929ade29e 100644
--- a/lib/bundler/plugin/source_list.rb
+++ b/lib/bundler/plugin/source_list.rb
@@ -23,7 +23,7 @@ module Bundler
private
- def rubygems_aggregate_class
+ def source_class
Plugin::Installer::Rubygems
end
end
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index ab163e2b04..dcaaf6af2e 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -12,7 +12,7 @@ module Bundler
attr_reader :name, :version, :platform
attr_writer :dependencies
- attr_accessor :source, :remote, :locked_platform
+ attr_accessor :source, :remote, :locked_platform, :created_at
def initialize(name, version, platform, spec_fetcher)
@name = name
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index af53104b38..422b726980 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -14,8 +14,6 @@ module Bundler
require_relative "resolver/root"
require_relative "resolver/strategy"
- include GemHelpers
-
def initialize(base, gem_version_promoter, most_specific_locked_platform = nil)
@source_requirements = base.source_requirements
@base = base
@@ -66,7 +64,9 @@ module Bundler
@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)
+ deps = version.dependencies.reject {|d| d.name == package.name }
+ deps = apply_metadata_overrides(deps, package.name)
+ versions[version] = to_dependency_hash(deps, @packages)
end
end
@@ -82,6 +82,7 @@ module Bundler
solver = PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger)
result = solver.solve
resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
+ Override.attach(resolved_specs, @base.overrides)
SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs)
rescue PubGrub::SolveFailure => e
incompatibility = e.incompatibility
@@ -122,9 +123,25 @@ module Bundler
explanation << extended_explanation
end
+ override_summary = override_diagnostic_summary
+ explanation << override_summary if override_summary
+
raise SolveFailure.new(explanation)
end
+ def override_diagnostic_summary
+ return nil if @base.overrides.empty?
+
+ lines = ["Bundler applied the following overrides while resolving:"]
+ @base.overrides.each do |override|
+ target = override.target == :all ? ":all" : override.target.inspect
+ location = override.source_location_label
+ lines << " override #{target}, #{override.field}: #{override.operation.inspect}" \
+ "#{location ? " (declared at #{location})" : ""}"
+ end
+ "\n\n#{lines.join("\n")}"
+ end
+
def find_names_to_relax(incompatibility)
names_to_unlock = []
names_to_allow_prereleases_for = []
@@ -167,7 +184,7 @@ module Bundler
PubGrub::VersionConstraint.new(package, range: range)
end
- def versions_for(package, range=VersionRange.any)
+ def versions_for(package, range = VersionRange.any)
range.select_versions(@sorted_versions[package])
end
@@ -186,6 +203,9 @@ module Bundler
platforms_explanation = specs_matching_other_platforms.any? ? " for any resolution platforms (#{package.platforms.join(", ")})" : ""
custom_explanation = "#{constraint} could not be found in #{repository_for(package)}#{platforms_explanation}"
+ if hint = cooldown_hint(specs_matching_other_platforms)
+ custom_explanation += " (#{hint})"
+ end
label = "#{name} (#{constraint_string})"
extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any?
@@ -273,7 +293,7 @@ module Bundler
next groups if platform_specs.all?(&:empty?)
end
- ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY)
+ ruby_specs = MatchPlatform.select_best_platform_match(specs, Gem::Platform::RUBY)
ruby_group = Resolver::SpecGroup.new(ruby_specs)
unless ruby_group.empty?
@@ -312,6 +332,16 @@ module Bundler
"Gemfile"
end
+ def raise_incomplete!(incomplete_specs)
+ raise_not_found!(@base.get_package(incomplete_specs.first.name))
+ end
+
+ def sort_versions_by_preferred(package, versions)
+ @gem_version_promoter.sort_versions(package, versions)
+ end
+
+ private
+
def raise_not_found!(package)
name = package.name
source = source_for(name)
@@ -345,14 +375,30 @@ module Bundler
message << "\n#{other_specs_matching_message(specs, matching_part)}"
end
+ if hint = cooldown_hint(specs_matching_requirement)
+ message << "\n\n#{hint}."
+ end
+
+ if specs_matching_requirement.any? && (hint = platform_mismatch_hint)
+ message << "\n\n#{hint}"
+ end
+
raise GemNotFound, message
end
- def sort_versions_by_preferred(package, versions)
- @gem_version_promoter.sort_versions(package, versions)
- end
+ def platform_mismatch_hint
+ locked_platforms = Bundler.locked_gems&.platforms
+ return unless locked_platforms
- private
+ local_platform = Bundler.local_platform
+ return if locked_platforms.include?(local_platform)
+ return if locked_platforms.any? {|p| p == Gem::Platform::RUBY }
+
+ "Your current platform (#{local_platform}) is not included in the lockfile's platforms (#{locked_platforms.join(", ")}). " \
+ "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
+ rescue GemfileNotFound
+ nil
+ end
def filtered_versions_for(package)
@gem_version_promoter.filter_versions(package, @all_versions[package])
@@ -376,7 +422,7 @@ module Bundler
end
def filter_specs(specs, package)
- filter_remote_specs(filter_prereleases(specs, package), package)
+ filter_remote_specs(filter_cooldown(filter_prereleases(specs, package)), package)
end
def filter_prereleases(specs, package)
@@ -385,6 +431,40 @@ module Bundler
specs.reject {|s| s.version.prerelease? }
end
+ def filter_cooldown(specs)
+ return specs if specs.empty?
+ excluded_versions = cooldown_excluded_versions(specs)
+ return specs if excluded_versions.empty?
+ specs.reject {|s| excluded_versions.include?([s.name, s.version]) }
+ end
+
+ def cooldown_excluded_versions(specs)
+ excluded = {}
+ specs.each do |spec|
+ next unless cooldown_excluded?(spec)
+ excluded[[spec.name, spec.version]] = true
+ end
+ excluded
+ end
+
+ def cooldown_hint(specs)
+ excluded_versions = cooldown_excluded_versions(specs)
+ return nil if excluded_versions.empty?
+ "#{excluded_versions.size} version#{"s" if excluded_versions.size > 1} excluded by the cooldown setting; pass `--cooldown 0` to bypass"
+ end
+
+ def cooldown_excluded?(spec)
+ return false unless spec.respond_to?(:created_at) && spec.created_at
+ return false unless spec.respond_to?(:remote) && spec.remote
+ days = spec.remote.effective_cooldown
+ return false if days.nil? || days <= 0
+ (cooldown_now - spec.created_at) < (days * 86_400)
+ end
+
+ def cooldown_now
+ @cooldown_now ||= Time.now
+ end
+
def filter_remote_specs(specs, package)
if package.prefer_local?
local_specs = specs.select {|s| s.is_a?(StubSpecification) }
@@ -490,7 +570,7 @@ module Bundler
end
def to_dependency_hash(dependencies, packages)
- dependencies.inject({}) do |deps, dep|
+ apply_overrides(dependencies).inject({}) do |deps, dep|
package = packages[dep.name]
current_req = deps[package]
@@ -506,6 +586,33 @@ module Bundler
end
end
+ def apply_overrides(dependencies)
+ return dependencies if @base.overrides.empty?
+
+ dependencies.map do |dep|
+ override = Override.find_for(@base.overrides, dep.name, :version)
+ next dep unless override
+ Gem::Dependency.new(dep.name, override.apply_to(dep.requirement))
+ end
+ end
+
+ METADATA_DEP_FIELD = {
+ "Ruby\0" => :required_ruby_version,
+ "RubyGems\0" => :required_rubygems_version,
+ }.freeze
+
+ def apply_metadata_overrides(dependencies, name)
+ return dependencies if @base.overrides.empty?
+
+ dependencies.map do |dep|
+ field = METADATA_DEP_FIELD[dep.name]
+ next dep unless field
+ override = Override.find_for(@base.overrides, name, field)
+ next dep unless override
+ Gem::Dependency.new(dep.name, override.apply_to(dep.requirement))
+ end
+ end
+
def bundler_not_found_message(conflict_dependencies)
candidate_specs = filter_matching_specs(default_bundler_source.specs.search("bundler"), conflict_dependencies)
diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb
index 932a92ff41..00bdd08303 100644
--- a/lib/bundler/resolver/base.rb
+++ b/lib/bundler/resolver/base.rb
@@ -5,9 +5,10 @@ require_relative "package"
module Bundler
class Resolver
class Base
- attr_reader :packages, :requirements, :source_requirements, :locked_specs
+ attr_reader :packages, :requirements, :source_requirements, :locked_specs, :overrides
def initialize(source_requirements, dependencies, base, platforms, options)
+ @overrides = options.delete(:overrides) || []
@source_requirements = source_requirements
@locked_specs = options[:locked_specs]
diff --git a/lib/bundler/resolver/package.rb b/lib/bundler/resolver/package.rb
index 0e86a4f84d..3906be3f57 100644
--- a/lib/bundler/resolver/package.rb
+++ b/lib/bundler/resolver/package.rb
@@ -21,6 +21,7 @@ module Bundler
@locked_version = locked_specs.version_for(name)
@unlock = unlock
@dependency = dependency || Dependency.new(name, @locked_version)
+ @platforms |= [Gem::Platform::RUBY] if @dependency.default_force_ruby_platform
@top_level = !dependency.nil?
@prerelease = @dependency.prerelease? || @locked_version&.prerelease? || prerelease ? :consider_first : :ignore
@prefer_local = prefer_local
@@ -30,7 +31,7 @@ module Bundler
def platform_specs(specs)
platforms.map do |platform|
prefer_locked = @new_platforms.include?(platform) ? false : !unlock?
- GemHelpers.select_best_platform_match(specs, platform, prefer_locked: prefer_locked)
+ MatchPlatform.select_best_platform_match(specs, platform, prefer_locked: prefer_locked)
end
end
diff --git a/lib/bundler/resolver/strategy.rb b/lib/bundler/resolver/strategy.rb
index 4f343bf0ce..7519d38968 100644
--- a/lib/bundler/resolver/strategy.rb
+++ b/lib/bundler/resolver/strategy.rb
@@ -5,6 +5,7 @@ module Bundler
class Strategy
def initialize(source)
@source = source
+ @package_priority_cache = {}
end
def next_package_and_version(unsatisfied)
@@ -17,10 +18,12 @@ module Bundler
def next_term_to_try_from(unsatisfied)
unsatisfied.min_by do |package, range|
- matching_versions = @source.versions_for(package, range)
- higher_versions = @source.versions_for(package, range.upper_invert)
+ @package_priority_cache[[package, range]] ||= begin
+ matching_versions = @source.versions_for(package, range)
+ higher_versions = @source.versions_for(package, range.upper_invert)
- [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ end
end
end
diff --git a/lib/bundler/retry.rb b/lib/bundler/retry.rb
index 090cb7e2ca..49b0f63838 100644
--- a/lib/bundler/retry.rb
+++ b/lib/bundler/retry.rb
@@ -6,6 +6,8 @@ module Bundler
attr_accessor :name, :total_runs, :current_run
class << self
+ attr_accessor :default_base_delay
+
def default_attempts
default_retries + 1
end
@@ -16,11 +18,17 @@ module Bundler
end
end
- def initialize(name, exceptions = nil, retries = self.class.default_retries)
+ # Set default base delay for exponential backoff
+ self.default_base_delay = 1.0
+
+ def initialize(name, exceptions = nil, retries = self.class.default_retries, opts = {})
@name = name
@retries = retries
@exceptions = Array(exceptions) || []
@total_runs = @retries + 1 # will run once, then upto attempts.times
+ @base_delay = opts[:base_delay] || self.class.default_base_delay
+ @max_delay = opts[:max_delay] || 60.0
+ @jitter = opts[:jitter] || 0.5
end
def attempt(&block)
@@ -48,9 +56,27 @@ module Bundler
Bundler.ui.info "" unless Bundler.ui.debug?
raise e
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
+ if 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
+ end
+ backoff_sleep if @base_delay > 0
+ true
+ end
+
+ def backoff_sleep
+ # Exponential backoff: delay = base_delay * 2^(attempt - 1)
+ # Add jitter to prevent thundering herd: random value between 0 and jitter seconds
+ delay = @base_delay * (2**(@current_run - 1))
+ delay = [@max_delay, delay].min
+ jitter_amount = rand * @jitter
+ total_delay = delay + jitter_amount
+ Bundler.ui.debug "Sleeping for #{total_delay.round(2)} seconds before retry"
+ sleep(total_delay)
+ end
+
+ def sleep(duration)
+ Kernel.sleep(duration)
end
def keep_trying?
diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb
index cd88253f46..5e52f38c8f 100644
--- a/lib/bundler/ruby_dsl.rb
+++ b/lib/bundler/ruby_dsl.rb
@@ -42,21 +42,26 @@ module Bundler
# 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", ruby = "3.2.2" or "ruby 3.2.2" capturing version string up to the first space or comment
- if /^ # Start of line
- ruby # Literal "ruby"
- [\s-]* # Optional whitespace or hyphens (for "ruby-3.2.2" format)
- (?:=\s*)? # Optional equals sign with whitespace (for ruby = "3.2.2" format)
- "? # Optional opening quote
- ( # Start capturing group
- [^\s#"]+ # One or more chars that aren't spaces, #, or quotes
- ) # End capturing group
- "? # Optional closing quote
- /x.match(file_content)
- $1
+ # match "ruby-3.2.2", ruby = "3.2.2", ruby = '3.2.2' or "ruby 3.2.2" capturing version string up to the first space or comment
+ version_match = /^ # Start of line
+ ruby # Literal "ruby"
+ [\s-]* # Optional whitespace or hyphens (for "ruby-3.2.2" format)
+ (?:=\s*)? # Optional equals sign with whitespace (for ruby = "3.2.2" format)
+ (?:
+ "([^"]+)" # Double quoted version
+ |
+ '([^']+)' # Single quoted version
+ |
+ ([^\s#"']+) # Unquoted version
+ )
+ /x.match(file_content)
+ if version_match
+ version_match[1] || version_match[2] || version_match[3]
else
file_content.strip
end
+ rescue Errno::ENOENT
+ raise GemfileError, "Could not find version file #{filename}"
end
end
end
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index 0ed5cbc6ca..aeff07582e 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -43,7 +43,6 @@ module Bundler
def to_s(versions = self.versions)
output = String.new("ruby #{versions_string(versions)}")
- output << "p#{patchlevel}" if patchlevel && patchlevel != "-1"
output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby"
output
@@ -72,8 +71,7 @@ module Bundler
def ==(other)
versions == other.versions &&
engine == other.engine &&
- engine_versions == other.engine_versions &&
- patchlevel == other.patchlevel
+ engine_versions == other.engine_versions
end
def host
@@ -98,8 +96,6 @@ module Bundler
[:version, versions_string(versions), versions_string(other.versions)]
elsif @input_engine && !matches?(engine_versions, other.engine_gem_version)
[:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)]
- elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel))
- [:patchlevel, patchlevel, other.patchlevel]
end
end
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index c684c6023a..4ad2bdf46f 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -13,15 +13,6 @@ require "rubygems" unless defined?(Gem)
# `Gem::Source` from the redefined `Gem::Specification#source`.
require "rubygems/source"
-# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler
-# versions and ignore patchlevels
-# (https://github.com/rubygems/rubygems/pull/5472,
-# https://github.com/rubygems/rubygems/pull/5486). May be removed once RubyGems
-# 3.3.12 support is dropped.
-unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1
- Gem.instance_variable_set(:@ruby_version, Gem::Version.new(RUBY_VERSION))
-end
-
module Gem
# Can be removed once RubyGems 3.5.11 support is dropped
unless Gem.respond_to?(:freebsd_platform?)
@@ -61,81 +52,122 @@ module Gem
require "rubygems/platform"
class Platform
- JAVA = Gem::Platform.new("java")
- MSWIN = Gem::Platform.new("mswin32")
- MSWIN64 = Gem::Platform.new("mswin64")
- MINGW = Gem::Platform.new("x86-mingw32")
- X64_MINGW = [Gem::Platform.new("x64-mingw32"),
- Gem::Platform.new("x64-mingw-ucrt")].freeze
- UNIVERSAL_MINGW = Gem::Platform.new("universal-mingw")
- WINDOWS = [MSWIN, MSWIN64, UNIVERSAL_MINGW].flatten.freeze
- X64_LINUX = Gem::Platform.new("x86_64-linux")
- X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl")
-
- if X64_LINUX === X64_LINUX_MUSL
- remove_method :===
-
- def ===(other)
- return nil unless Gem::Platform === other
-
- # universal-mingw32 matches x64-mingw-ucrt
- return true if (@cpu == "universal" || other.cpu == "universal") &&
- @os.start_with?("mingw") && other.os.start_with?("mingw")
-
- # cpu
- ([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
- (@cpu == "arm" && other.cpu.start_with?("armv"))) &&
-
- # os
- @os == other.os &&
-
- # version
- (
- (@os != "linux" && (@version.nil? || other.version.nil?)) ||
- (@os == "linux" && (normalized_linux_version_ext == other.normalized_linux_version_ext || ["musl#{@version}", "musleabi#{@version}", "musleabihf#{@version}"].include?(other.version))) ||
- @version == other.version
- )
- end
+ # Can be removed once RubyGems 3.6.9 support is dropped
+ unless respond_to?(:generic)
+ JAVA = Gem::Platform.new("java") # :nodoc:
+ MSWIN = Gem::Platform.new("mswin32") # :nodoc:
+ MSWIN64 = Gem::Platform.new("mswin64") # :nodoc:
+ MINGW = Gem::Platform.new("x86-mingw32") # :nodoc:
+ X64_MINGW_LEGACY = Gem::Platform.new("x64-mingw32") # :nodoc:
+ X64_MINGW = Gem::Platform.new("x64-mingw-ucrt") # :nodoc:
+ UNIVERSAL_MINGW = Gem::Platform.new("universal-mingw") # :nodoc:
+ WINDOWS = [MSWIN, MSWIN64, UNIVERSAL_MINGW].freeze # :nodoc:
+ X64_LINUX = Gem::Platform.new("x86_64-linux") # :nodoc:
+ X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl") # :nodoc:
+
+ GENERICS = [JAVA, *WINDOWS].freeze # :nodoc:
+ private_constant :GENERICS
+
+ GENERIC_CACHE = GENERICS.each_with_object({}) {|g, h| h[g] = g } # :nodoc:
+ private_constant :GENERIC_CACHE
- # This is a copy of RubyGems 3.3.23 or higher `normalized_linux_method`.
- # Once only 3.3.23 is supported, we can use the method in RubyGems.
- def normalized_linux_version_ext
- return nil unless @version
+ class << self
+ ##
+ # Returns the generic platform for the given platform.
- without_gnu_nor_abi_modifiers = @version.sub(/\Agnu/, "").sub(/eabi(hf)?\Z/, "")
- return nil if without_gnu_nor_abi_modifiers.empty?
+ def generic(platform)
+ return Gem::Platform::RUBY if platform.nil? || platform == Gem::Platform::RUBY
- without_gnu_nor_abi_modifiers
- end
- end
- end
+ GENERIC_CACHE[platform] ||= begin
+ found = GENERICS.find do |match|
+ platform === match
+ end
+ found || Gem::Platform::RUBY
+ end
+ end
- Platform.singleton_class.module_eval do
- unless Platform.singleton_methods.include?(:match_spec?)
- def match_spec?(spec)
- match_gem?(spec.platform, spec.name)
- end
+ ##
+ # Returns the platform specificity match for the given spec platform and user platform.
- def match_gem?(platform, gem_name)
- match_platforms?(platform, Gem.platforms)
- end
- end
+ def platform_specificity_match(spec_platform, user_platform)
+ return -1 if spec_platform == user_platform
+ return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
+
+ os_match(spec_platform, user_platform) +
+ cpu_match(spec_platform, user_platform) * 10 +
+ version_match(spec_platform, user_platform) * 100
+ end
+
+ ##
+ # Sorts and filters the best platform match for the given matching specs and platform.
+
+ def sort_and_filter_best_platform_match(matching, platform)
+ return matching if matching.one?
+
+ exact = matching.select {|spec| spec.platform == platform }
+ return exact if exact.any?
+
+ sorted_matching = sort_best_platform_match(matching, platform)
+ exemplary_spec = sorted_matching.first
- match_platforms_defined = Gem::Platform.respond_to?(:match_platforms?, true)
+ sorted_matching.take_while {|spec| same_specificity?(platform, spec, exemplary_spec) && same_deps?(spec, exemplary_spec) }
+ end
+
+ ##
+ # Sorts the best platform match for the given matching specs and platform.
+
+ def sort_best_platform_match(matching, platform)
+ matching.sort_by.with_index do |spec, i|
+ [
+ platform_specificity_match(spec.platform, platform),
+ i, # for stable sort
+ ]
+ end
+ end
- if !match_platforms_defined || Gem::Platform.send(:match_platforms?, Gem::Platform::X64_LINUX_MUSL, [Gem::Platform::X64_LINUX])
+ private
+
+ def same_specificity?(platform, spec, exemplary_spec)
+ platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform)
+ end
+
+ def same_deps?(spec, exemplary_spec)
+ spec.required_ruby_version == exemplary_spec.required_ruby_version &&
+ spec.required_rubygems_version == exemplary_spec.required_rubygems_version &&
+ spec.dependencies.sort == exemplary_spec.dependencies.sort
+ end
- private
+ def os_match(spec_platform, user_platform)
+ if spec_platform.os == user_platform.os
+ 0
+ else
+ 1
+ end
+ end
- remove_method :match_platforms? if match_platforms_defined
+ def cpu_match(spec_platform, user_platform)
+ if spec_platform.cpu == user_platform.cpu
+ 0
+ elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm")
+ 0
+ elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal"
+ 1
+ else
+ 2
+ end
+ end
- def match_platforms?(platform, platforms)
- platforms.any? do |local_platform|
- platform.nil? ||
- local_platform == platform ||
- (local_platform != Gem::Platform::RUBY && platform =~ local_platform)
+ def version_match(spec_platform, user_platform)
+ if spec_platform.version == user_platform.version
+ 0
+ elsif spec_platform.version.nil?
+ 1
+ else
+ 2
+ end
end
end
+
end
end
@@ -144,9 +176,6 @@ module Gem
# 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
@@ -158,7 +187,6 @@ module Gem
require_relative "match_platform"
include ::Bundler::MatchMetadata
- include ::Bundler::MatchPlatform
attr_accessor :remote, :relative_loaded_from
@@ -214,23 +242,6 @@ module Gem
full_gem_path
end
- unless const_defined?(:LATEST_RUBY_WITHOUT_PATCH_VERSIONS)
- LATEST_RUBY_WITHOUT_PATCH_VERSIONS = Gem::Version.new("2.1")
-
- alias_method :rg_required_ruby_version=, :required_ruby_version=
- def required_ruby_version=(req)
- self.rg_required_ruby_version = req
-
- @required_ruby_version.requirements.map! do |op, v|
- if v >= LATEST_RUBY_WITHOUT_PATCH_VERSIONS && v.release.segments.size == 4
- [op == "~>" ? "=" : op, Gem::Version.new(v.segments.tap {|s| s.delete_at(3) }.join("."))]
- else
- [op, v]
- end
- end
- end
- end
-
def insecurely_materialized?
false
end
@@ -272,25 +283,16 @@ module Gem
end
end
- unless FLATTENS_REQUIRED_PATHS
- def flatten_require_paths
- return unless raw_require_paths.first.is_a?(Array)
-
- 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
+ if Gem.rubygems_version < Gem::Version.new("3.5.22")
+ module FixPathSourceMissingExtensions
+ def missing_extensions?
+ return false if %w[Bundler::Source::Path Bundler::Source::Gemspec].include?(source.class.name)
- class << self
- module RequirePathFlattener
- def from_yaml(input)
- spec = super(input)
- spec.flatten_require_paths
- spec
- end
+ super
end
-
- prepend RequirePathFlattener
end
+
+ prepend FixPathSourceMissingExtensions
end
private
@@ -401,6 +403,11 @@ module Gem
@ignored = missing_extensions?
end
end
+
+ # Can be removed once RubyGems 3.6.9 support is dropped
+ unless new.respond_to?(:installable_on_platform?)
+ include(::Bundler::MatchPlatform)
+ end
end
require "rubygems/name_tuple"
@@ -410,7 +417,7 @@ module Gem
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)
+ def initialize(name, version, platform = Gem::Platform::RUBY)
if Gem::Platform === platform
initialize_with_platform(name, version, platform.to_s)
else
@@ -447,6 +454,39 @@ module Gem
end
end
+ unless Gem.rubygems_version >= Gem::Version.new("3.6.7")
+ module UnfreezeCompactIndexParsedResponse
+ def parse(line)
+ version, platform, dependencies, requirements = super
+ [version, platform, dependencies.frozen? ? dependencies.dup : dependencies, requirements.frozen? ? requirements.dup : requirements]
+ end
+ end
+
+ Resolver::APISet::GemParser.prepend(UnfreezeCompactIndexParsedResponse)
+ end
+
+ # RubyGems before 4.0.13 split compact index dependency/requirement entries
+ # on every colon, which mangles metadata values that contain colons such as
+ # the `created_at` timestamps the cooldown feature relies on. Split only on
+ # the first colon so those values survive on older RubyGems.
+ #
+ # The module is defined unconditionally so it stays testable on any RubyGems,
+ # but only prepended when the host RubyGems still has the buggy behavior.
+ module SplitCompactIndexEntryOnFirstColon
+ private
+
+ def parse_dependency(string)
+ dependency = string.split(":", 2)
+ dependency[-1] = dependency[-1].split("&") if dependency.size > 1
+ dependency[0] = -dependency[0]
+ dependency
+ end
+ end
+
+ unless Gem.rubygems_version >= Gem::Version.new("4.0.13")
+ Resolver::APISet::GemParser.prepend(SplitCompactIndexEntryOnFirstColon)
+ end
+
if Gem.rubygems_version < Gem::Version.new("3.6.0")
class Package; end
require "rubygems/package/tar_reader"
@@ -460,15 +500,4 @@ module Gem
Package::TarReader::Entry.prepend(FixFullNameEncoding)
end
-
- require "rubygems/uri"
-
- # Can be removed once RubyGems 3.3.15 support is dropped
- unless Gem::Uri.respond_to?(:redact)
- class Uri
- def self.redact(uri)
- new(uri).redacted
- end
- end
- end
end
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index 1af1b85ff0..fc019f54d2 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -20,14 +20,18 @@ 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
end
SharedHelpers.filesystem_access(gem_dir, :write) do
extract_files
end
- build_extensions if spec.extensions.any?
+ if options[:build_extension] == false
+ warn_skipped_extensions
+ elsif spec.extensions.any?
+ build_extensions
+ end
write_build_info_file
run_post_build_hooks
@@ -35,7 +39,12 @@ module Bundler
generate_bin
end
- generate_plugins
+ if options[:install_plugin] == false
+ remove_stale_plugins
+ warn_skipped_plugins
+ else
+ generate_plugins
+ end
write_spec
@@ -69,10 +78,7 @@ module Bundler
end
def generate_plugins
- return unless Gem::Installer.instance_methods(false).include?(:generate_plugins)
-
- latest = Gem::Specification.stubs_for(spec.name).first
- return if latest && latest.version > spec.version
+ return unless Gem::Installer.method_defined?(:generate_plugins, false)
ensure_writable_dir @plugins_dir
@@ -83,6 +89,20 @@ module Bundler
end
end
+ def warn_skipped_extensions
+ return if spec.extensions.empty?
+
+ Bundler.ui.warn "#{spec.full_name} contains native extensions that were not built.\n" \
+ "To build extensions, unset no_build_extension and run `bundle pristine #{spec.name}`."
+ end
+
+ def warn_skipped_plugins
+ return if spec.plugins.empty?
+
+ Bundler.ui.warn "#{spec.full_name} contains plugins that were not installed.\n" \
+ "To install plugins, unset no_install_plugin and run `bundle pristine #{spec.name}`."
+ end
+
if Bundler.rubygems.provides?("< 3.5.19")
def generate_bin_script(filename, bindir)
bin_script_path = File.join bindir, formatted_program_filename(filename)
@@ -103,6 +123,10 @@ module Bundler
end
end
+ def build_jobs
+ Bundler.settings[:jobs] || super
+ end
+
def build_extensions
extension_cache_path = options[:bundler_extension_cache_path]
extension_dir = spec.extension_dir
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index eddf36278c..e04ef23259 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -214,16 +214,11 @@ module Bundler
e.requirement = dep.requirement
raise e
end
-
- # backwards compatibility shim, see https://github.com/rubygems/bundler/issues/5102
- kernel_class.send(:public, :gem) if Bundler.feature_flag.setup_makes_kernel_gem_public?
end
end
# Used to give better error messages when activating specs outside of the current bundle
def replace_bin_path(specs_by_name)
- gem_class = (class << Gem; self; end)
-
redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args|
exec_name = args.first
raise ArgumentError, "you must supply exec_name" unless exec_name
@@ -345,9 +340,13 @@ module Bundler
Gem::Specification.all = specs
end
- redefine_method((class << Gem; self; end), :finish_resolve) do |*|
+ redefine_method(gem_class, :finish_resolve) do |*|
[]
end
+
+ redefine_method(gem_class, :load_plugins) do |*|
+ load_plugin_files specs.flat_map(&:plugins)
+ end
end
def plain_specs
@@ -417,11 +416,7 @@ 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
+ SharedHelpers.feature_removed! "Bundler.rubygems.all_specs has been removed in favor of Bundler.rubygems.installed_specs"
end
def installed_specs
@@ -437,7 +432,7 @@ module Bundler
end
def find_bundler(version)
- find_name("bundler").find {|s| s.version.to_s == version }
+ find_name("bundler").find {|s| s.version.to_s == version.to_s }
end
def find_name(name)
@@ -447,6 +442,12 @@ module Bundler
def default_stubs
Gem::Specification.default_stubs("*.gemspec")
end
+
+ private
+
+ def gem_class
+ class << Gem; self; end
+ end
end
def self.rubygems
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index 444b085bed..5280e72aa2 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -71,7 +71,7 @@ module Bundler
raise Bundler::GemRequireError.new e,
"There was an error while trying to load the gem '#{file}'."
end
- rescue RuntimeError => e
+ rescue StandardError => e
raise Bundler::GemRequireError.new e,
"There was an error while trying to load the gem '#{file}'."
end
@@ -174,7 +174,14 @@ module Bundler
spec_cache_paths = []
spec_gemspec_paths = []
spec_extension_paths = []
- Bundler.rubygems.add_default_gems_to(specs).values.each do |spec|
+ specs_to_keep = Bundler.rubygems.add_default_gems_to(specs).values
+
+ current_bundler = Bundler.rubygems.find_bundler(Bundler.gem_version)
+ if current_bundler
+ specs_to_keep << current_bundler
+ end
+
+ specs_to_keep.each do |spec|
spec_gem_paths << spec.full_gem_path
# need to check here in case gems are nested like for the rails git repo
md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path)
@@ -240,7 +247,11 @@ module Bundler
cached.each do |path|
Bundler.ui.info " * #{File.basename(path)}"
- File.delete(path)
+
+ begin
+ File.delete(path)
+ rescue Errno::ENOENT
+ end
end
end
end
diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb
index 2aeac6be52..82efbf56a4 100644
--- a/lib/bundler/self_manager.rb
+++ b/lib/bundler/self_manager.rb
@@ -7,13 +7,15 @@ module Bundler
#
class SelfManager
def restart_with_locked_bundler_if_needed
- return unless needs_switching? && installed?
+ restart_version = find_restart_version
+ return unless restart_version && installed?(restart_version)
restart_with(restart_version)
end
def install_locked_bundler_and_restart_with_it_if_needed
- return unless needs_switching?
+ restart_version = find_restart_version
+ return unless restart_version
if restart_version == lockfile_version
Bundler.ui.info \
@@ -29,8 +31,6 @@ module Bundler
end
def update_bundler_and_restart_with_it_if_needed(target)
- return unless autoswitching_applies?
-
spec = resolve_update_version_from(target)
return unless spec
@@ -38,7 +38,7 @@ module Bundler
Bundler.ui.info "Updating bundler to #{version}."
- install(spec)
+ install(spec) unless installed?(version)
restart_with(version)
end
@@ -63,52 +63,43 @@ module Bundler
end
def install(spec)
+ spec.source.download(spec)
spec.source.install(spec)
end
def restart_with(version)
configured_gem_home = ENV["GEM_HOME"]
+ configured_orig_gem_home = ENV["BUNDLER_ORIG_GEM_HOME"]
configured_gem_path = ENV["GEM_PATH"]
+ configured_orig_gem_path = ENV["BUNDLER_ORIG_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
- argv0 = File.exist?($PROGRAM_NAME) ? $PROGRAM_NAME : Process.argv0
- cmd = [argv0, *ARGV]
- cmd.unshift(Gem.ruby) unless File.executable?(argv0)
- end
+ argv0 = File.exist?($PROGRAM_NAME) ? $PROGRAM_NAME : Process.argv0
+ cmd = [argv0, *ARGV]
+ cmd.unshift(Gem.ruby) unless File.executable?(argv0)
Bundler.with_original_env do
Kernel.exec(
- { "GEM_HOME" => configured_gem_home, "GEM_PATH" => configured_gem_path, "BUNDLER_VERSION" => version.to_s },
+ {
+ "GEM_HOME" => configured_gem_home,
+ "BUNDLER_ORIG_GEM_HOME" => configured_orig_gem_home,
+ "GEM_PATH" => configured_gem_path,
+ "BUNDLER_ORIG_GEM_PATH" => configured_orig_gem_path,
+ "BUNDLER_VERSION" => version.to_s,
+ },
*cmd
)
end
end
- def needs_switching?
+ def needs_switching?(restart_version)
autoswitching_applies? &&
- Bundler.settings[:version] != "system" &&
released?(restart_version) &&
- !running?(restart_version) &&
- !updating?
+ !running?(restart_version)
end
def autoswitching_applies?
- ENV["BUNDLER_VERSION"].nil? &&
+ (ENV["BUNDLER_VERSION"].nil? || ENV["BUNDLER_VERSION"].empty?) &&
ruby_can_restart_with_same_arguments? &&
- SharedHelpers.in_bundle? &&
lockfile_version
end
@@ -142,6 +133,7 @@ module Bundler
end
def find_latest_matching_spec(requirement)
+ Bundler.configure
local_result = find_latest_matching_spec_from_collection(local_specs, requirement)
return local_result if local_result && requirement.specific?
@@ -171,18 +163,14 @@ module Bundler
$PROGRAM_NAME != "-e"
end
- def updating?
- "update".start_with?(ARGV.first || " ") && ARGV[1..-1].any? {|a| a.start_with?("--bundler") }
- end
-
- def installed?
+ def installed?(restart_version)
Bundler.configure
Bundler.rubygems.find_bundler(restart_version.to_s)
end
def current_version
- @current_version ||= Gem::Version.new(Bundler::VERSION)
+ @current_version ||= Bundler.gem_version
end
def lockfile_version
@@ -194,13 +182,16 @@ module Bundler
@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
+ def find_restart_version
+ return unless SharedHelpers.in_bundle?
+
+ configured_version = Bundler.settings[:version]
+ return if configured_version == "system"
+
+ restart_version = configured_version == "lockfile" ? lockfile_version : Gem::Version.new(configured_version)
+ return unless needs_switching?(restart_version)
+
+ restart_version
end
end
end
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index cde01e0181..fd77c2f7fc 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -7,13 +7,10 @@ module Bundler
autoload :Validator, File.expand_path("settings/validator", __dir__)
BOOL_KEYS = %w[
- allow_offline_install
- auto_clean_without_path
auto_install
cache_all
cache_all_platforms
clean
- default_install_uses_path
deployment
disable_checksum_validation
disable_exec_load
@@ -22,45 +19,32 @@ module Bundler
disable_shared_gems
disable_version_check
force_ruby_platform
- forget_cli_options
frozen
gem.changelog
gem.coc
gem.mit
+ gem.bundle
git.allow_insecure
global_gem_cache
ignore_messages
init_gems_rb
inline
lockfile_checksums
+ no_build_extension
no_install
+ no_install_plugin
no_prune
- path_relative_to_cwd
path.system
plugins
prefer_patch
- print_only_version_number
- setup_makes_kernel_gem_public
silence_deprecations
silence_root_warning
update_requires_all_flag
- ].freeze
-
- REMEMBERED_KEYS = %w[
- bin
- cache_all
- clean
- deployment
- frozen
- no_prune
- path
- shebang
- path.system
- without
- with
+ verbose
].freeze
NUMBER_KEYS = %w[
+ cooldown
jobs
redirect
retry
@@ -78,14 +62,17 @@ module Bundler
bin
cache_path
console
+ default_cli_command
gem.ci
gem.github_username
gem.linter
gem.rubocop
gem.test
gemfile
+ lockfile
path
shebang
+ simulate_version
system_bindir
trust-policy
version
@@ -99,6 +86,11 @@ module Bundler
"BUNDLE_RETRY" => 3,
"BUNDLE_TIMEOUT" => 10,
"BUNDLE_VERSION" => "lockfile",
+ "BUNDLE_LOCKFILE_CHECKSUMS" => true,
+ "BUNDLE_CACHE_ALL" => true,
+ "BUNDLE_PLUGINS" => true,
+ "BUNDLE_GLOBAL_GEM_CACHE" => false,
+ "BUNDLE_UPDATE_REQUIRES_ALL_FLAG" => false,
}.freeze
def initialize(root = nil)
@@ -130,12 +122,8 @@ module Bundler
end
def set_command_option(key, value)
- if !is_remembered(key) || Bundler.feature_flag.forget_cli_options?
- temporary(key => value)
- value
- else
- set_local(key, value)
- end
+ temporary(key => value)
+ value
end
def set_command_option_if_given(key, value)
@@ -274,7 +262,7 @@ module Bundler
def use_system_gems?
return true if system_path
return false if explicit_path
- !Bundler.feature_flag.default_install_uses_path?
+ !Bundler.feature_flag.bundler_5_mode?
end
def base_path
@@ -319,6 +307,10 @@ module Bundler
@app_cache_path ||= self[:cache_path] || "vendor/cache"
end
+ def installation_parallelization
+ self[:jobs] || processor_count
+ end
+
def validate!
all.each do |raw_key|
[@local_config, @env_config, @global_config].each do |settings|
@@ -389,10 +381,6 @@ module Bundler
ARRAY_KEYS.include?(self.class.key_to_s(key))
end
- def is_remembered(key)
- REMEMBERED_KEYS.include?(self.class.key_to_s(key))
- end
-
def is_credential(key)
key == "gem.push_key"
end
@@ -496,7 +484,7 @@ 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)|
+ (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!(".", "__")
diff --git a/lib/bundler/settings/validator.rb b/lib/bundler/settings/validator.rb
index 0a57ea7f03..70a0ca36d4 100644
--- a/lib/bundler/settings/validator.rb
+++ b/lib/bundler/settings/validator.rb
@@ -75,27 +75,11 @@ module Bundler
end
end
- rule %w[path], "relative paths are expanded relative to the current working directory" do |key, value, settings|
- next if value.nil?
-
- path = Pathname.new(value)
- next if !path.relative? || !Bundler.feature_flag.path_relative_to_cwd?
-
- path = path.expand_path
-
- root = begin
- Bundler.root
- rescue GemfileNotFound
- Pathname.pwd.expand_path
- end
-
- path = begin
- path.relative_path_from(root)
- rescue ArgumentError
- path
- end
-
- set(settings, key, path.to_s)
+ rule %w[default_cli_command], "default_cli_command must be either 'install' or 'cli_help'" do |key, value, _settings|
+ valid_values = %w[install cli_help]
+ if !value.nil? && !valid_values.include?(value.to_s)
+ fail!(key, value, "must be one of: #{valid_values.join(", ")}")
+ end
end
end
end
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index 1ef9d61361..2aa8abe0a0 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -4,8 +4,6 @@ require_relative "version"
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__)
@@ -25,6 +23,9 @@ module Bundler
end
def default_lockfile
+ given = ENV["BUNDLE_LOCKFILE"]
+ return Pathname.new(given) if given && !given.empty?
+
gemfile = default_gemfile
case gemfile.basename.to_s
@@ -57,7 +58,7 @@ module Bundler
def pwd
Bundler.rubygems.ext_lock.synchronize do
- Pathname.pwd
+ Dir.pwd
end
end
@@ -104,7 +105,8 @@ module Bundler
def filesystem_access(path, action = :write, &block)
yield(path.dup)
rescue Errno::EACCES => e
- raise unless e.message.include?(path.to_s) || action == :create
+ path_basename = File.basename(path.to_s)
+ raise unless e.message.include?(path_basename) || action == :create
raise PermissionError.new(path, action)
rescue Errno::EAGAIN
@@ -125,24 +127,17 @@ module Bundler
raise GenericSystemCallError.new(e, "There was an error #{[:create, :write].include?(action) ? "creating" : "accessing"} `#{path}`.")
end
- def major_deprecation(major_version, message, removed_message: nil, 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
- end
+ def feature_deprecated!(message)
+ return unless prints_major_deprecations?
- bundler_major_version = Bundler.bundler_major_version
- if bundler_major_version > major_version
- require_relative "errors"
- raise DeprecatedError, "[REMOVED] #{removed_message || message}"
- end
-
- return unless bundler_major_version >= major_version && prints_major_deprecations?
Bundler.ui.warn("[DEPRECATED] #{message}")
end
+ def feature_removed!(message)
+ require_relative "errors"
+ raise RemovedError, "[REMOVED] #{message}"
+ end
+
def print_major_deprecations!
multiple_gemfiles = search_up(".") do |dir|
gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) }
@@ -306,6 +301,7 @@ module Bundler
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 "BUNDLE_LOCKFILE", default_lockfile.to_s
Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__)
end
@@ -386,7 +382,6 @@ module Bundler
end
def prints_major_deprecations?
- require_relative "../bundler"
return false if Bundler.settings[:silence_deprecations]
require_relative "deprecate"
return false if Bundler::Deprecate.skip
diff --git a/lib/bundler/similarity_detector.rb b/lib/bundler/similarity_detector.rb
deleted file mode 100644
index 50e66b9cab..0000000000
--- a/lib/bundler/similarity_detector.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class SimilarityDetector
- SimilarityScore = Struct.new(:string, :distance)
-
- # initialize with an array of words to be matched against
- def initialize(corpus)
- @corpus = corpus
- end
-
- # return an array of words similar to 'word' from the corpus
- def similar_words(word, limit = 3)
- words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) }
- words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string)
- end
-
- # return the result of 'similar_words', concatenated into a list
- # (eg "a, b, or c")
- def similar_word_list(word, limit = 3)
- words = similar_words(word, limit)
- if words.length == 1
- words[0]
- elsif words.length > 1
- [words[0..-2].join(", "), words[-1]].join(" or ")
- end
- end
-
- protected
-
- # https://www.informit.com/articles/article.aspx?p=683059&seqNum=36
- def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1)
- # ins, del, sub are weighted costs
- return nil if this.nil?
- return nil if that.nil?
- dm = [] # distance matrix
-
- # Initialize first row values
- dm[0] = (0..this.length).collect {|i| i * ins }
- fill = [0] * (this.length - 1)
-
- # Initialize first column values
- (1..that.length).each do |i|
- dm[i] = [i * del, fill.flatten]
- end
-
- # populate matrix
- (1..that.length).each do |i|
- (1..this.length).each do |j|
- # critical comparison
- dm[i][j] = [
- dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub),
- dm[i][j - 1] + ins,
- dm[i - 1][j] + del,
- ].min
- end
- end
-
- # The last value in matrix is the Levenshtein distance between the strings
- dm[that.length][this.length]
- end
- end
-end
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index 232873503b..cf71be8801 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -31,6 +31,8 @@ module Bundler
message
end
+ def download(*); end
+
def can_lock?(spec)
spec.source == self
end
@@ -79,7 +81,7 @@ module Bundler
end
def extension_cache_path(spec)
- return unless Bundler.feature_flag.global_gem_cache?
+ return unless Bundler.settings[:global_gem_cache]
return unless source_slug = extension_cache_slug(spec)
Bundler.user_cache.join(
"extensions", Gem::Platform.local.to_s, Bundler.ruby_scope,
diff --git a/lib/bundler/source/gemspec.rb b/lib/bundler/source/gemspec.rb
index b59dce1d09..ed766dbe74 100644
--- a/lib/bundler/source/gemspec.rb
+++ b/lib/bundler/source/gemspec.rb
@@ -10,6 +10,10 @@ module Bundler
super
@gemspec = options["gemspec"]
end
+
+ def to_s
+ "gemspec at `#{@path}`"
+ end
end
end
end
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index d57944ee12..a002a2570a 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -191,8 +191,13 @@ module Bundler
set_cache_path!(app_cache_path) if use_app_cache?
if requires_checkout? && !@copied
- fetch unless use_app_cache?
- checkout
+ Plugin.hook(Plugin::Events::GIT_BEFORE_FETCH, self)
+ begin
+ fetch unless use_app_cache?
+ checkout
+ ensure
+ Plugin.hook(Plugin::Events::GIT_AFTER_FETCH, self)
+ end
end
local_specs
@@ -238,7 +243,7 @@ module Bundler
# across different projects, this cache will be shared.
# When using local git repos, this is set to the local repo.
def cache_path
- @cache_path ||= if Bundler.feature_flag.global_gem_cache?
+ @cache_path ||= if Bundler.settings[:global_gem_cache]
Bundler.user_cache
else
Bundler.bundle_path.join("cache", "bundler")
@@ -268,7 +273,7 @@ module Bundler
private
def cache_to(custom_path, try_migrate: false)
- return unless Bundler.feature_flag.cache_all?
+ return unless Bundler.settings[:cache_all]
app_cache_path = app_cache_path(custom_path)
@@ -416,7 +421,6 @@ module Bundler
def fetch
git_proxy.checkout
rescue GitError => e
- raise unless Bundler.feature_flag.allow_offline_install?
Bundler.ui.warn "Using cached git data because of network errors:\n#{e}"
end
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index 8230584260..8094dcaa9d 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -16,7 +16,7 @@ module Bundler
def initialize(command)
msg = String.new
msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, "
- msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md "
+ msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md "
msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
super msg
end
@@ -57,6 +57,29 @@ module Bundler
attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref
attr_writer :revision
+ def self.version
+ @version ||= full_version[/((\.?\d+)+).*/, 1]
+ end
+
+ def self.full_version
+ @full_version ||= begin
+ raise GitNotInstalledError.new unless Bundler.git_present?
+
+ require "open3"
+ out, err, status = Open3.capture3("git", "--version")
+
+ raise GitCommandError.new("--version", SharedHelpers.pwd, err) unless status.success?
+ Bundler.ui.warn err unless err.empty?
+
+ out.sub(/git version\s*/, "").strip
+ end
+ end
+
+ def self.reset
+ @version = nil
+ @full_version = nil
+ end
+
def initialize(path, uri, options = {}, revision = nil, git = nil)
@path = path
@uri = uri
@@ -92,11 +115,11 @@ module Bundler
end
def version
- @version ||= full_version.match(/((\.?\d+)+).*/)[1]
+ self.class.version
end
def full_version
- @full_version ||= git_local("--version").sub(/git version\s*/, "").strip
+ self.class.full_version
end
def checkout
@@ -121,7 +144,7 @@ module Bundler
FileUtils.rm_rf(p)
end
git "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s
- File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination)
+ File.chmod((File.stat(destination).mode | 0o777) & ~File.umask, destination)
rescue Errno::EEXIST => e
file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1]
raise GitError, "Bundler could not install a gem because it needs to " \
@@ -137,7 +160,7 @@ module Bundler
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
@@ -156,7 +179,7 @@ module Bundler
private
def git_remote_fetch(args)
- command = ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
+ command = fetch_command(args)
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}` at #{path}", [MissingGitRevisionError]).attempts do
@@ -166,6 +189,11 @@ module Bundler
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)
else
+ if shallow?
+ args -= depth_args
+ command = fetch_command(args)
+ command_with_no_credentials = check_allowed(command)
+ end
raise GitCommandError.new(command_with_no_credentials, path, err)
end
end
@@ -178,7 +206,8 @@ module Bundler
FileUtils.mkdir_p(p)
end
- command = ["clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s]
+ clone_args = extra_clone_args
+ command = clone_command(clone_args)
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do
@@ -189,13 +218,10 @@ module Bundler
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)
+ if shallow?
+ clone_args -= depth_args
+ command = clone_command(clone_args)
command_with_no_credentials = check_allowed(command)
-
- err += "Retrying without --depth argument."
end
raise GitCommandError.new(command_with_no_credentials, path, err)
end
@@ -204,14 +230,14 @@ module Bundler
def clone_needs_unshallow?
return false unless path.join("shallow").exist?
- return true if full_clone?
+ return true unless shallow?
@revision && @revision != head_revision
end
def extra_ref
return false if not_pinned?
- return true unless full_clone?
+ return true if shallow?
ref.start_with?("refs/")
end
@@ -305,8 +331,8 @@ module Bundler
end
def has_revision_cached?
- return unless @revision && path.exist?
- git("cat-file", "-e", @revision, dir: path)
+ return unless commit && path.exist?
+ git("cat-file", "-e", commit, dir: path)
true
rescue GitError
false
@@ -406,13 +432,14 @@ module Bundler
end
def capture3_args_for(cmd, dir)
- return ["git", *cmd] unless dir
+ # Disable automatic maintenance so a background commit-graph write in
+ # the source repo can't race the hardlinking local clone and fail with
+ # "hardlink different from source".
+ opts = ["-c", "gc.auto=0", "-c", "maintenance.auto=false"]
- if Bundler.feature_flag.bundler_3_mode? || supports_minus_c?
- ["git", "-C", dir.to_s, *cmd]
- else
- ["git", *cmd, { chdir: dir.to_s }]
- end
+ return ["git", *opts, *cmd] unless dir
+
+ ["git", "-C", dir.to_s, *opts, *cmd]
end
def extra_clone_args
@@ -431,8 +458,16 @@ module Bundler
args
end
+ def fetch_command(args)
+ ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
+ end
+
+ def clone_command(args)
+ ["clone", "--bare", "--no-hardlinks", "--quiet", *args, "--", configured_uri, path.to_s]
+ end
+
def depth_args
- return [] if full_clone?
+ return [] unless shallow?
["--depth", depth.to_s]
end
@@ -447,12 +482,8 @@ module Bundler
branch || tag
end
- def full_clone?
- depth.nil?
- end
-
- def supports_minus_c?
- @supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5")
+ def shallow?
+ !depth.nil?
end
def needs_allow_any_sha1_in_want?
diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb
index fd959cd64e..ecf8895187 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -58,6 +58,10 @@ module Bundler
def version_message(spec)
"#{spec.name} #{spec.version}"
end
+
+ def checksum_store
+ @checksum_store ||= Checksum::Store.new
+ end
end
end
end
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index 885dd96d85..366a23aea7 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -24,7 +24,7 @@ module Bundler
@path = Pathname.new(options["path"])
expanded_path = expand(@path)
@path = if @path.relative?
- expanded_path.relative_path_from(root_path.expand_path)
+ expanded_path.relative_path_from(File.expand_path(root_path))
else
expanded_path
end
@@ -53,6 +53,8 @@ module Bundler
"source at `#{@path}`"
end
+ alias_method :identifier, :to_s
+
alias_method :to_gemfile, :path
def hash
@@ -81,7 +83,7 @@ module Bundler
def cache(spec, custom_path = nil)
app_cache_path = app_cache_path(custom_path)
- return unless Bundler.feature_flag.cache_all?
+ return unless Bundler.settings[:cache_all]
return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0
unless @original_path.exist?
@@ -124,11 +126,7 @@ module Bundler
end
def expand(somepath)
- if Bundler.current_ruby.jruby? # TODO: Unify when https://github.com/rubygems/bundler/issues/7598 fixed upstream and all supported jrubies include the fix
- somepath.expand_path(root_path).expand_path
- else
- somepath.expand_path(root_path)
- end
+ somepath.expand_path(root_path)
rescue ArgumentError => e
Bundler.ui.debug(e)
raise PathError, "There was an error while trying to use the path " \
@@ -167,6 +165,13 @@ module Bundler
next unless spec = load_gemspec(file)
spec.source = self
+ # The ignore attribute is for ignoring installed gems that don't
+ # have extensions correctly compiled for activation. In the case of
+ # path sources, there's a single version of each gem in the path
+ # source available to Bundler, so we always certainly want to
+ # consider that for activation and never makes sense to ignore it.
+ spec.ignored = false
+
# Validation causes extension_dir to be calculated, which depends
# on #source, so we validate here instead of load_gemspec
validate_spec(spec)
@@ -215,10 +220,11 @@ module Bundler
# Some gem authors put absolute paths in their gemspec
# and we have to save them from themselves
spec.files = spec.files.filter_map do |path|
- next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path)
+ pathname = Pathname.new(path)
+ next path unless pathname.absolute?
next if File.directory?(path)
begin
- Pathname.new(path).relative_path_from(gem_dir).to_s
+ pathname.relative_path_from(gem_dir).to_s
rescue ArgumentError
path
end
diff --git a/lib/bundler/source/path/installer.rb b/lib/bundler/source/path/installer.rb
index 0af28fe770..39765e5da2 100644
--- a/lib/bundler/source/path/installer.rb
+++ b/lib/bundler/source/path/installer.rb
@@ -24,7 +24,7 @@ module Bundler
def post_install
run_hooks(:pre_install)
- unless @disable_extensions
+ unless @disable_extensions || Bundler.settings[:no_build_extension]
build_extensions
run_hooks(:post_build)
end
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 19800e9c58..ed864604fe 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -8,21 +8,26 @@ module Bundler
autoload :Remote, File.expand_path("rubygems/remote", __dir__)
# Ask for X gems per API request
- API_REQUEST_SIZE = 50
+ API_REQUEST_SIZE = 100
+ REQUIRE_MUTEX = Mutex.new
attr_accessor :remotes
def initialize(options = {})
@options = options
@remotes = []
+ @remote_cooldowns = {}
@dependency_names = []
@allow_remote = false
@allow_cached = false
@allow_local = options["allow_local"] || false
@prefer_local = false
@checksum_store = Checksum::Store.new
+ @gem_installers = {}
+ @gem_installers_mutex = Mutex.new
- Array(options["remotes"]).reverse_each {|r| add_remote(r) }
+ cooldown = options["cooldown"]
+ Array(options["remotes"]).reverse_each {|r| add_remote(r, cooldown: cooldown) }
@lockfile_remotes = @remotes if options["from_lockfile"]
end
@@ -145,6 +150,13 @@ module Bundler
# sources, and large_idx.merge! small_idx is way faster than
# small_idx.merge! large_idx.
index = @allow_remote ? remote_specs.dup : Index.new
+
+ # Snapshot per-version `created_at` from the remote info before installed
+ # / cached specs overwrite the EndpointSpecification objects that carry
+ # it. The cooldown filter consults `created_at` on every candidate, so
+ # local stubs need the published date back-filled to participate.
+ remote_created_at = collect_remote_created_at(index)
+
index.merge!(cached_specs) if @allow_cached
index.merge!(installed_specs) if @allow_local
@@ -158,66 +170,57 @@ module Bundler
end
end
+ backfill_created_at(index, remote_created_at) unless remote_created_at.empty?
+
index
end
end
- def install(spec, options = {})
+ def download(spec, options = {})
if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
- print_using_message "Using #{version_message(spec, options[:previous_spec])}"
- return nil # no post-install message
+ return true
end
- if spec.remote
- # Check for this spec from other sources
- uris = [spec.remote, *remotes_for_spec(spec)].map(&:anonymized_uri).uniq
- Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1
- end
-
- path = fetch_gem_if_possible(spec, options[:previous_spec])
- raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path
-
- return if Bundler.settings[:no_install]
-
- install_path = rubygems_dir
- bin_path = Bundler.system_bindir
-
- require_relative "../rubygems_gem_installer"
-
- 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)
- )
+ installer = rubygems_gem_installer(spec, options)
if spec.remote
s = begin
installer.spec
rescue Gem::Package::FormatError
- Bundler.rm_rf(path)
+ Bundler.rm_rf(installer.gem)
raise
rescue Gem::Security::Exception => e
raise SecurityError,
- "The gem #{File.basename(path, ".gem")} can't be installed because " \
+ "The gem #{installer.gem} can't be installed because " \
"the security policy didn't allow it, with the message: #{e.message}"
end
spec.__swap__(s)
end
+ spec
+ end
+
+ def install(spec, options = {})
+ if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
+ print_using_message "Using #{version_message(spec, options[:previous_spec])}"
+ return nil # no post-install message
+ end
+
+ return if Bundler.settings[:no_install]
+
+ installer = rubygems_gem_installer(spec, options)
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
- installed_spec = installer.install
+ installed_spec = nil
+
+ Gem.time("Installed #{spec.name} in", 0, true) do
+ installed_spec = installer.install
+ end
spec.full_gem_path = installed_spec.full_gem_path
spec.loaded_from = installed_spec.loaded_from
@@ -251,9 +254,14 @@ module Bundler
cached_path
end
- def add_remote(source)
+ def add_remote(source, cooldown: nil)
uri = normalize_uri(source)
@remotes.unshift(uri) unless @remotes.include?(uri)
+ @remote_cooldowns[uri] = cooldown if cooldown
+ end
+
+ def cooldown_for(uri)
+ @remote_cooldowns[uri]
end
def spec_names
@@ -274,7 +282,7 @@ module Bundler
def remote_fetchers
@remote_fetchers ||= remotes.to_h do |uri|
- remote = Source::Rubygems::Remote.new(uri)
+ remote = Source::Rubygems::Remote.new(uri, cooldown: cooldown_for(uri))
[remote, Bundler::Fetcher.new(remote)]
end.freeze
end
@@ -322,6 +330,13 @@ module Bundler
@allow_remote && api_fetchers.any?
end
+ def clear_cache
+ @specs = nil
+ @installed_specs = nil
+ @default_specs = nil
+ @cached_specs = nil
+ end
+
protected
def remote_names
@@ -332,13 +347,6 @@ module Bundler
remotes.map(&method(:remove_auth))
end
- def remotes_for_spec(spec)
- specs.search_all(spec.name).inject([]) do |uris, s|
- uris << s.remote if s.remote
- uris
- end
- end
-
def cached_gem(spec)
global_cache_path = download_cache_path(spec)
caches << global_cache_path if global_cache_path
@@ -471,6 +479,31 @@ module Bundler
private
+ def collect_remote_created_at(index)
+ return {} unless @allow_remote
+
+ snapshot = {}
+ index.each do |spec|
+ next unless spec.respond_to?(:created_at) && spec.created_at
+ # Remember the remote that supplied the date too: when a source has
+ # several remotes with different per-URI cooldown settings we must
+ # restore the same one during backfill so `effective_cooldown` agrees.
+ snapshot[[spec.name, spec.version]] = [spec.created_at, spec.remote]
+ end
+ snapshot
+ end
+
+ def backfill_created_at(index, snapshot)
+ index.each do |spec|
+ next unless spec.respond_to?(:created_at=)
+ next if spec.created_at
+ remote_created_at, remote = snapshot[[spec.name, spec.version]]
+ next unless remote_created_at
+ spec.created_at = remote_created_at
+ spec.remote ||= remote if remote && spec.respond_to?(:remote=)
+ end
+ end
+
def lockfile_remotes
@lockfile_remotes || credless_remotes
end
@@ -491,7 +524,15 @@ module Bundler
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)
+
+ Plugin.hook(Plugin::Events::GEM_BEFORE_FETCH, spec)
+ begin
+ Gem.time("Downloaded #{spec.name} in", 0, true) do
+ Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
+ end
+ ensure
+ Plugin.hook(Plugin::Events::GEM_AFTER_FETCH, spec)
+ end
end
# Returns the global cache path of the calling Rubygems::Source object.
@@ -506,17 +547,52 @@ module Bundler
# @return [Pathname] The global cache path.
#
def download_cache_path(spec)
- return unless Bundler.feature_flag.global_gem_cache?
+ return unless Bundler.settings[:global_gem_cache]
return unless remote = spec.remote
return unless cache_slug = remote.cache_slug
- Bundler.user_cache.join("gems", cache_slug)
+ if Gem.respond_to?(:global_gem_cache_path)
+ Pathname.new(Gem.global_gem_cache_path).join(cache_slug)
+ else
+ # Fall back to old location for older RubyGems versions
+ Bundler.user_cache.join("gems", cache_slug)
+ end
end
def extension_cache_slug(spec)
return unless remote = spec.remote
remote.cache_slug
end
+
+ # We are using a mutex to read and write from/to the hash.
+ # The reason this double synchronization was added is for performance
+ # and to lock the mutex for the shortest possible amount of time. Otherwise,
+ # all threads are fighting over this mutex and when it gets acquired it gets locked
+ # until a thread finishes downloading a gem, leaving the other threads waiting
+ # doing nothing.
+ def rubygems_gem_installer(spec, options)
+ @gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin
+ path = fetch_gem_if_possible(spec, options[:previous_spec])
+ raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path
+
+ REQUIRE_MUTEX.synchronize { require_relative "../rubygems_gem_installer" }
+
+ installer = Bundler::RubyGemsGemInstaller.at(
+ path,
+ security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
+ install_dir: rubygems_dir.to_s,
+ bin_dir: Bundler.system_bindir.to_s,
+ ignore_dependencies: true,
+ wrappers: true,
+ env_shebang: true,
+ build_args: options[:build_args],
+ bundler_extension_cache_path: extension_cache_path(spec),
+ build_extension: Bundler.settings[:no_build_extension] ? false : nil,
+ install_plugin: Bundler.settings[:no_install_plugin] ? false : nil
+ )
+ @gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer }
+ end
+ end
end
end
end
diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb
index ed55912a99..3d847424b7 100644
--- a/lib/bundler/source/rubygems/remote.rb
+++ b/lib/bundler/source/rubygems/remote.rb
@@ -4,9 +4,9 @@ module Bundler
class Source
class Rubygems
class Remote
- attr_reader :uri, :anonymized_uri, :original_uri
+ attr_reader :uri, :anonymized_uri, :original_uri, :cooldown
- def initialize(uri)
+ def initialize(uri, cooldown: nil)
orig_uri = uri
uri = Bundler.settings.mirror_for(uri)
@original_uri = orig_uri if orig_uri != uri
@@ -14,6 +14,16 @@ module Bundler
@uri = apply_auth(uri, fallback_auth).freeze
@anonymized_uri = remove_auth(@uri).freeze
+ @cooldown = cooldown
+ end
+
+ # Returns the cooldown days that apply to this remote, resolving the
+ # precedence CLI > config > Gemfile per-source. Returns nil if no
+ # cooldown applies.
+ def effective_cooldown
+ override = Bundler.settings[:cooldown]
+ return override if override
+ @cooldown
end
MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length
diff --git a/lib/bundler/source/rubygems_aggregate.rb b/lib/bundler/source/rubygems_aggregate.rb
index 99ef81ad54..8aeaa375fa 100644
--- a/lib/bundler/source/rubygems_aggregate.rb
+++ b/lib/bundler/source/rubygems_aggregate.rb
@@ -5,9 +5,10 @@ module Bundler
class RubygemsAggregate
attr_reader :source_map, :sources
- def initialize(sources, source_map)
+ def initialize(sources, source_map, excluded_sources = [])
@sources = sources
@source_map = source_map
+ @excluded_sources = excluded_sources
@index = build_index
end
@@ -31,6 +32,8 @@ module Bundler
dependency_names = source_map.pinned_spec_names
sources.all_sources.each do |source|
+ next if @excluded_sources.include?(source)
+
source.dependency_names = dependency_names - source_map.pinned_spec_names(source)
idx.add_source source.specs
dependency_names.concat(source.unmet_deps).uniq!
diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb
index d1308b1dfb..ab7002d6e5 100644
--- a/lib/bundler/source_list.rb
+++ b/lib/bundler/source_list.rb
@@ -9,7 +9,7 @@ module Bundler
:metadata_source
def global_rubygems_source
- @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true)
+ @global_rubygems_source ||= source_class.new("allow_local" => true)
end
def initialize
@@ -21,19 +21,9 @@ module Bundler
@rubygems_sources = []
@metadata_source = Source::Metadata.new
- @merged_gem_lockfile_sections = false
@local_mode = true
end
- def merged_gem_lockfile_sections?
- @merged_gem_lockfile_sections
- end
-
- def merged_gem_lockfile_sections!(replacement_source)
- @merged_gem_lockfile_sections = true
- @global_rubygems_source = replacement_source
- end
-
def aggregate_global_source?
global_rubygems_source.multiple_remotes?
end
@@ -69,8 +59,8 @@ module Bundler
add_source_to_list Plugin.source(source).new(options), @plugin_sources
end
- def add_global_rubygems_remote(uri)
- global_rubygems_source.add_remote(uri)
+ def add_global_rubygems_remote(uri, cooldown: nil)
+ global_rubygems_source.add_remote(uri, cooldown: cooldown)
global_rubygems_source
end
@@ -90,10 +80,6 @@ module Bundler
@rubygems_sources
end
- def rubygems_remotes
- rubygems_sources.flat_map(&:remotes).uniq
- end
-
def all_sources
path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source]
end
@@ -103,7 +89,7 @@ module Bundler
end
def get(source)
- source_list_for(source).find {|s| equivalent_source?(source, s) }
+ source_list_for(source).find {|s| s.include?(source) }
end
def lock_sources
@@ -115,11 +101,7 @@ module Bundler
end
def lock_rubygems_sources
- if merged_gem_lockfile_sections?
- [combine_rubygems_sources]
- else
- rubygems_sources.sort_by(&:identifier)
- end
+ rubygems_sources.sort_by(&:identifier)
end
# Returns true if there are changes
@@ -129,16 +111,7 @@ module Bundler
@rubygems_sources, @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources)
@global_rubygems_source = global_replacement_source(replacement_sources)
- different_sources?(lock_sources, replacement_sources)
- end
-
- # Returns true if there are changes
- def expired_sources?(replacement_sources)
- return false if replacement_sources.empty?
-
- lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources
-
- different_sources?(lock_sources, replacement_sources)
+ !equivalent_sources?(lock_sources, replacement_sources)
end
def prefer_local!
@@ -163,14 +136,12 @@ module Bundler
all_sources.each(&:remote!)
end
- private
-
- def dup_with_replaced_sources(replacement_sources)
- new_source_list = dup
- new_source_list.replace_sources!(replacement_sources)
- new_source_list
+ def clear_cache
+ rubygems_sources.each(&:clear_cache)
end
+ private
+
def map_sources(replacement_sources)
rubygems = @rubygems_sources.map do |source|
replace_rubygems_source(replacement_sources, source)
@@ -224,11 +195,7 @@ module Bundler
end
end
- def different_sources?(lock_sources, replacement_sources)
- !equivalent_sources?(lock_sources, replacement_sources)
- end
-
- def rubygems_aggregate_class
+ def source_class
Source::Rubygems
end
@@ -247,10 +214,6 @@ module Bundler
end
end
- def combine_rubygems_sources
- Source::Rubygems.new("remotes" => rubygems_remotes)
- end
-
def warn_on_git_protocol(source)
return if Bundler.settings["git.allow_insecure"]
@@ -265,9 +228,5 @@ module Bundler
def equivalent_sources?(lock_sources, replacement_sources)
lock_sources.sort_by(&:identifier) == replacement_sources.sort_by(&:identifier)
end
-
- def equivalent_source?(source, other_source)
- source == other_source
- end
end
end
diff --git a/lib/bundler/source_map.rb b/lib/bundler/source_map.rb
index ca73e01f9d..513eb37f8b 100644
--- a/lib/bundler/source_map.rb
+++ b/lib/bundler/source_map.rb
@@ -14,24 +14,25 @@ module Bundler
direct_requirements.reject {|_, source| source == skip }.keys
end
- def all_requirements
+ def all_requirements(excluded_sources = [])
requirements = direct_requirements.dup
- unmet_deps = sources.non_default_explicit_sources.map do |source|
+ explicit_sources = sources.non_default_explicit_sources.reject do |source|
+ excluded_sources.include?(source)
+ end
+
+ unmet_deps = explicit_sources.map do |source|
(source.spec_names - pinned_spec_names).each do |indirect_dependency_name|
previous_source = requirements[indirect_dependency_name]
if previous_source.nil?
requirements[indirect_dependency_name] = source
else
- no_ambiguous_sources = Bundler.feature_flag.bundler_3_mode?
-
msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."]
msg.concat [previous_source, source].map {|s| " * #{s}" }.sort
- msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
+ msg << "You must add this gem to the source block for the source you wish it to be installed from."
msg = msg.join("\n")
- raise SecurityError, msg if no_ambiguous_sources
- Bundler.ui.warn "Warning: #{msg}"
+ raise SecurityError, msg
end
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index de361845fe..ae5e5cbaa9 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -11,16 +11,11 @@ module Bundler
@specs = specs
end
- def for(dependencies, platforms_or_legacy_check = [nil], legacy_platforms = [nil], skips: [])
- platforms = if [true, false].include?(platforms_or_legacy_check)
- Bundler::SharedHelpers.major_deprecation 2,
+ def for(dependencies, platforms = [nil], legacy_platforms = [nil], skips: [])
+ if [true, false].include?(platforms)
+ Bundler::SharedHelpers.feature_removed! \
"SpecSet#for received a `check` parameter, but that's no longer used and deprecated. " \
- "SpecSet#for always implicitly performs validation. Please remove this parameter",
- print_caller_location: true
-
- legacy_platforms
- else
- platforms_or_legacy_check
+ "SpecSet#for always implicitly performs validation. Please remove this parameter"
end
materialize_dependencies(dependencies, platforms, skips: skips)
@@ -29,9 +24,10 @@ module Bundler
end
def normalize_platforms!(deps, platforms)
- complete_platforms = add_extra_platforms!(platforms)
+ remove_invalid_platforms!(deps, platforms)
+ add_extra_platforms!(platforms)
- complete_platforms.map do |platform|
+ platforms.map! do |platform|
next platform if platform == Gem::Platform::RUBY
begin
@@ -44,7 +40,7 @@ module Bundler
next platform if incomplete_for_platform?(deps, less_specific_platform)
less_specific_platform
- end.uniq
+ end.uniq!
end
def add_originally_invalid_platforms!(platforms, originally_invalid_platforms)
@@ -53,6 +49,20 @@ module Bundler
end
end
+ def remove_invalid_platforms!(deps, platforms, skips: [])
+ invalid_platforms = []
+
+ platforms.reject! do |platform|
+ next false if skips.include?(platform)
+
+ invalid = incomplete_for_platform?(deps, platform)
+ invalid_platforms << platform if invalid
+ invalid
+ end
+
+ invalid_platforms
+ end
+
def add_extra_platforms!(platforms)
if @specs.empty?
platforms.concat([Gem::Platform::RUBY]).uniq
@@ -61,13 +71,14 @@ module Bundler
new_platforms = all_platforms.select do |platform|
next if platforms.include?(platform)
- next unless GemHelpers.generic(platform) == Gem::Platform::RUBY
+ next unless Gem::Platform.generic(platform) == Gem::Platform::RUBY
complete_platform(platform)
end
return if new_platforms.empty?
platforms.concat(new_platforms)
+ return if new_platforms.include?(Bundler.local_platform)
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
@@ -129,12 +140,15 @@ module Bundler
end
def incomplete_for_platform?(deps, platform)
- return false if @specs.empty?
+ incomplete_specs_for_platform(deps, platform).any?
+ end
+
+ def incomplete_specs_for_platform(deps, platform)
+ return [] if @specs.empty?
validation_set = self.class.new(@specs)
validation_set.for(deps, [platform])
-
- validation_set.incomplete_specs.any?
+ validation_set.incomplete_specs
end
def missing_specs_for(deps)
@@ -160,11 +174,11 @@ module Bundler
end
def -(other)
- SpecSet.new(to_a - other.to_a)
+ SharedHelpers.feature_removed! "SpecSet#- has been removed with no replacement"
end
def find_by_name_and_platform(name, platform)
- @specs.detect {|spec| spec.name == name && spec.match_platform(platform) }
+ lookup[name]&.detect {|spec| spec.installable_on_platform?(platform) }
end
def specs_with_additional_variants_from(other)
@@ -180,7 +194,7 @@ module Bundler
end
def version_for(name)
- self[name].first&.version
+ exemplary_spec(name)&.version
end
def what_required(spec)
@@ -191,7 +205,7 @@ module Bundler
end
def <<(spec)
- @specs << spec
+ SharedHelpers.feature_removed! "SpecSet#<< has been removed with no replacement"
end
def length
@@ -260,13 +274,25 @@ module Bundler
valid_platform = lookup.all? do |_, specs|
spec = specs.first
+ # The matching candidates returned by source.specs.search are remote
+ # specs that do not carry the override list themselves. Borrow it from
+ # the LazySpec we are validating so platform-variant validation honors
+ # the same overrides the install/resolve path already applies.
+ overrides = spec.is_a?(LazySpecification) ? Array(spec.overrides) : []
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)
+ platform_spec = MatchPlatform.select_best_platform_match(matching_specs, platform).find do |s|
+ s.matches_current_metadata_with_overrides?(overrides) && valid_dependencies?(s)
end
if platform_spec
- new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
+ unless specs.include?(platform_spec)
+ new_lazy = LazySpecification.from_spec(platform_spec)
+ # Carry the overrides forward so a follow-up complete_platform
+ # call that picks this synthesized variant as its exemplar still
+ # honors the user's override list.
+ new_lazy.overrides = overrides if overrides.any?
+ new_specs << new_lazy
+ end
true
else
false
@@ -285,8 +311,13 @@ module Bundler
end
def additional_variants_from(other)
- other.select do |spec|
- version_for(spec.name) == spec.version && valid_dependencies?(spec)
+ other.select do |other_spec|
+ spec = exemplary_spec(other_spec.name)
+ next unless spec
+
+ selected = spec.version == other_spec.version && valid_dependencies?(other_spec)
+ other_spec.source = spec.source if selected
+ selected
end
end
@@ -295,7 +326,7 @@ module Bundler
end
def sorted
- @sorted ||= ([@specs.find {|s| s.name == "rake" }] + tsort).compact.uniq
+ @sorted ||= ([lookup["rake"]&.first] + tsort).compact.uniq
rescue TSort::Cyclic => error
cgems = extract_circular_gems(error)
raise CyclicDependencyError, "Your bundle requires gems that depend" \
@@ -363,5 +394,9 @@ module Bundler
hash[key] ||= []
hash[key] << value
end
+
+ def exemplary_spec(name)
+ self[name].first
+ end
end
end
diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index 026f753d41..b353642b40 100644
--- a/lib/bundler/stub_specification.rb
+++ b/lib/bundler/stub_specification.rb
@@ -52,6 +52,7 @@ module Bundler
# This is defined directly to avoid having to loading the full spec
def missing_extensions?
+ return false if RUBY_ENGINE == "jruby"
return false if default_gem?
return false if extensions.empty?
return false if File.exist? gem_build_complete_path
diff --git a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
index 67fe8cee79..633baebdd5 100644
--- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
+++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
@@ -1,132 +1,10 @@
-# Contributor Covenant Code of Conduct
+# Code of Conduct
-## Our Pledge
+<%= config[:name].inspect %> follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
-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.
+* Participants will be tolerant of opposing views.
+* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
+* When interpreting the words and actions of others, participants should always assume good intentions.
+* Behaviour which can be reasonably considered harassment will not be tolerated.
-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:
-
-* 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
-
-Examples of unacceptable behavior include:
-
-* 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
-* 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 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.
-
-## 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.
-
-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:
-
-### 1. Correction
-
-**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.
-
-### 2. Warning
-
-**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.
-
-### 3. Temporary Ban
-
-**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.
-
-### 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.
-
-**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].
-
-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].
-
-[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
+If you have any concerns about behaviour within this project, please contact us at [<%= config[:email].inspect %>](mailto:<%= config[:email].inspect %>).
diff --git a/lib/bundler/templates/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/Cargo.toml.tt
index f5a460c9bb..cd00f97e5a 100644
--- a/lib/bundler/templates/newgem/Cargo.toml.tt
+++ b/lib/bundler/templates/newgem/Cargo.toml.tt
@@ -5,3 +5,9 @@
[workspace]
members = ["./ext/<%= config[:name] %>"]
resolver = "2"
+
+[profile.release]
+# By default, debug symbols are stripped from the final binary which makes it
+# harder to debug if something goes wrong. It's recommended to keep debug
+# symbols in the release build so that you can debug the final binary if needed.
+debug = true
diff --git a/lib/bundler/templates/newgem/Gemfile.tt b/lib/bundler/templates/newgem/Gemfile.tt
index ea7a33ee28..85dc593b8f 100644
--- a/lib/bundler/templates/newgem/Gemfile.tt
+++ b/lib/bundler/templates/newgem/Gemfile.tt
@@ -6,19 +6,19 @@ source "https://rubygems.org"
gemspec
gem "irb"
-gem "rake", "~> 13.0"
+gem "rake", ">= 13.0"
<%- if config[:ext] -%>
gem "rake-compiler"
<%- end -%>
<%- if config[:test] -%>
-gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>"
+gem "<%= config[:test] %>"
<%- end -%>
<%- if config[:linter] == "rubocop" -%>
-gem "rubocop", "~> <%= config[:linter_version] %>"
+gem "rubocop"
<%- elsif config[:linter] == "standard" -%>
-gem "standard", "~> <%= config[:linter_version] %>"
+gem "standard"
<%- end -%>
diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt
index 172183d4b4..83f10009c7 100644
--- a/lib/bundler/templates/newgem/Rakefile.tt
+++ b/lib/bundler/templates/newgem/Rakefile.tt
@@ -59,6 +59,11 @@ Rake::ExtensionTask.new("<%= config[:underscored_name] %>", GEMSPEC) do |ext|
end
<% end -%>
+<% if config[:ext] == "go" -%>
+require "go_gem/rake_task"
+
+GoGem::RakeTask.new("<%= config[:underscored_name] %>")
+<% end -%>
<% end -%>
<% if default_task_names.size == 1 -%>
task default: <%= default_task_names.first.inspect %>
diff --git a/lib/bundler/templates/newgem/circleci/config.yml.tt b/lib/bundler/templates/newgem/circleci/config.yml.tt
index f40f029bf1..c4dd9d0647 100644
--- a/lib/bundler/templates/newgem/circleci/config.yml.tt
+++ b/lib/bundler/templates/newgem/circleci/config.yml.tt
@@ -7,6 +7,10 @@ jobs:
environment:
RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ environment:
+ GO_VERSION: '1.23.0'
+<%- end -%>
steps:
- checkout
<%- if config[:ext] == 'rust' -%>
@@ -17,6 +21,14 @@ jobs:
name: Install a RubyGems version that can compile rust extensions
command: gem update --system '<%= ::Gem.rubygems_version %>'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ - run:
+ name: Install Go
+ command: |
+ wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ tar -C /usr/local -xzf /tmp/go.tar.gz
+ echo 'export PATH=/usr/local/go/bin:"$PATH"' >> "$BASH_ENV"
+<%- end -%>
- run:
name: Run the default task
command: |
diff --git a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
index 0ebce0e4a0..a06166aee7 100644
--- a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
@@ -12,4 +12,11 @@ publish = false
crate-type = ["cdylib"]
[dependencies]
-magnus = { version = "0.6.2" }
+magnus = { version = "0.8.2" }
+rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] }
+
+[build-dependencies]
+rb-sys-env = "0.2.2"
+
+[dev-dependencies]
+rb-sys-test-helpers = { version = "0.2.2" }
diff --git a/lib/bundler/templates/newgem/ext/newgem/build.rs.tt b/lib/bundler/templates/newgem/ext/newgem/build.rs.tt
new file mode 100644
index 0000000000..80a7842753
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/build.rs.tt
@@ -0,0 +1,5 @@
+pub fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let _ = rb_sys_env::activate()?;
+
+ Ok(())
+}
diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt
new file mode 100644
index 0000000000..a689e21ebe
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require "mkmf"
+require "go_gem/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_go_makefile(<%= config[:makefile_path].inspect %>)
diff --git a/lib/bundler/templates/newgem/ext/newgem/go.mod.tt b/lib/bundler/templates/newgem/ext/newgem/go.mod.tt
new file mode 100644
index 0000000000..3f4819d004
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/go.mod.tt
@@ -0,0 +1,5 @@
+module github.com/<%= config[:go_module_username] %>/<%= config[:underscored_name] %>
+
+go 1.23
+
+require github.com/ruby-go-gem/go-gem-wrapper latest
diff --git a/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt b/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt
new file mode 100644
index 0000000000..119c0c96ea
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt
@@ -0,0 +1,2 @@
+#include "<%= config[:underscored_name] %>.h"
+#include "_cgo_export.h"
diff --git a/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt b/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt
new file mode 100644
index 0000000000..f19b750e58
--- /dev/null
+++ b/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt
@@ -0,0 +1,31 @@
+package main
+
+/*
+#include "<%= config[:underscored_name] %>.h"
+
+VALUE rb_<%= config[:underscored_name] %>_sum(VALUE self, VALUE a, VALUE b);
+*/
+import "C"
+
+import (
+ "github.com/ruby-go-gem/go-gem-wrapper/ruby"
+)
+
+//export rb_<%= config[:underscored_name] %>_sum
+func rb_<%= config[:underscored_name] %>_sum(_ C.VALUE, a C.VALUE, b C.VALUE) C.VALUE {
+ longA := ruby.NUM2LONG(ruby.VALUE(a))
+ longB := ruby.NUM2LONG(ruby.VALUE(b))
+
+ sum := longA + longB
+
+ return C.VALUE(ruby.LONG2NUM(sum))
+}
+
+//export Init_<%= config[:underscored_name] %>
+func Init_<%= config[:underscored_name] %>() {
+ rb_m<%= config[:constant_array].join %> := ruby.RbDefineModule(<%= config[:constant_name].inspect %>)
+ ruby.RbDefineSingletonMethod(rb_m<%= config[:constant_array].join %>, "sum", C.rb_<%= config[:underscored_name] %>_sum, 2)
+}
+
+func main() {
+}
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..09ce97682d 100644
--- a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
@@ -1,7 +1,7 @@
use magnus::{function, prelude::*, Error, Ruby};
-fn hello(subject: String) -> String {
- format!("Hello from Rust, {subject}!")
+pub fn hello(subject: String) -> String {
+ format!("Hello {subject}, from Rust!")
}
#[magnus::init]
@@ -10,3 +10,14 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
module.define_singleton_method("hello", function!(hello, 1))?;
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use rb_sys_test_helpers::ruby_test;
+ use super::hello;
+
+ #[ruby_test]
+ fn test_hello() {
+ assert_eq!("Hello world, from Rust!", hello("world".to_string()));
+ }
+}
diff --git a/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt b/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt
new file mode 100644
index 0000000000..d49954d2cd
--- /dev/null
+++ b/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt
@@ -0,0 +1,69 @@
+---
+name: Build gems
+
+on:
+ push:
+ tags:
+ - "v*"
+ - "cross-gem/*"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ packages: write
+
+jobs:
+ ci-data:
+ runs-on: ubuntu-latest
+ outputs:
+ result: ${{ steps.fetch.outputs.result }}
+ steps:
+ - uses: oxidize-rb/actions/fetch-ci-data@v1
+ id: fetch
+ with:
+ supported-ruby-platforms: |
+ exclude: ["arm-linux", "x64-mingw32"]
+ stable-ruby-versions: |
+ exclude: ["head"]
+
+ source-gem:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Build gem
+ run: bundle exec rake build
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: source-gem
+ path: pkg/*.gem
+
+ cross-gem:
+ name: Compile native gem for ${{ matrix.platform }}
+ runs-on: ubuntu-latest
+ needs: ci-data
+ strategy:
+ matrix:
+ platform: ${{ fromJSON(needs.ci-data.outputs.result).supported-ruby-platforms }}
+ steps:
+ - uses: actions/checkout@v6
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - uses: oxidize-rb/actions/cross-gem@v1
+ id: cross-gem
+ with:
+ platform: ${{ matrix.platform }}
+ ruby-versions: ${{ join(fromJSON(needs.ci-data.outputs.result).stable-ruby-versions, ',') }}
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: cross-gem
+ path: ${{ steps.cross-gem.outputs.gem-path }}
diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
index d1b5ae0534..cc8f04dd33 100644
--- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt
+++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
@@ -7,6 +7,9 @@ on:
pull_request:
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
@@ -17,7 +20,9 @@ jobs:
- '<%= RUBY_VERSION %>'
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
<%- if config[:ext] == 'rust' -%>
- name: Set up Ruby & Rust
uses: oxidize-rb/actions/setup-ruby-and-rust@v1
@@ -33,5 +38,11 @@ jobs:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ - name: Setup Go
+ uses: actions/setup-go@v5
+ with:
+ go-version-file: ext/<%= config[:underscored_name] %>/go.mod
+<%- end -%>
- name: Run the default task
run: bundle exec rake
diff --git a/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/lib/bundler/templates/newgem/gitlab-ci.yml.tt
index d2e1f33736..adbd70cbc0 100644
--- a/lib/bundler/templates/newgem/gitlab-ci.yml.tt
+++ b/lib/bundler/templates/newgem/gitlab-ci.yml.tt
@@ -6,6 +6,11 @@ default:
- apt-get update && apt-get install -y clang
- gem update --system '<%= ::Gem.rubygems_version %>'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ - wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ - tar -C /usr/local -xzf /tmp/go.tar.gz
+ - export PATH=/usr/local/go/bin:$PATH
+<%- end -%>
- gem install bundler -v <%= Bundler::VERSION %>
- bundle install
@@ -14,5 +19,9 @@ example_job:
variables:
RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true'
<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ variables:
+ GO_VERSION: '1.23.0'
+<%- end -%>
script:
- bundle exec rake
diff --git a/lib/bundler/templates/newgem/lib/newgem.rb.tt b/lib/bundler/templates/newgem/lib/newgem.rb.tt
index caf6e32f4a..3aedee0d25 100644
--- a/lib/bundler/templates/newgem/lib/newgem.rb.tt
+++ b/lib/bundler/templates/newgem/lib/newgem.rb.tt
@@ -2,7 +2,7 @@
require_relative "<%= File.basename(config[:namespaced_path]) %>/version"
<%- if config[:ext] -%>
-require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>"
+require "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>"
<%- end -%>
<%- config[:constant_array].each_with_index do |c, i| -%>
diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt
index ced300f379..1ab1c28f46 100644
--- a/lib/bundler/templates/newgem/newgem.gemspec.tt
+++ b/lib/bundler/templates/newgem/newgem.gemspec.tt
@@ -10,20 +10,23 @@ Gem::Specification.new do |spec|
spec.summary = "TODO: Write a short summary, because RubyGems requires one."
spec.description = "TODO: Write a longer description or delete this line."
- spec.homepage = "TODO: Put your gem's website or public repo URL here."
+ spec.homepage = "<%= config[:homepage_uri] %>"
<%- if config[:mit] -%>
spec.license = "MIT"
<%- end -%>
spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>"
-<%- if config[:ext] == 'rust' -%>
- spec.required_rubygems_version = ">= <%= config[:rust_builder_required_rubygems_version] %>"
-<%- end -%>
-
spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
-
spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
- spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
+ spec.metadata["source_code_uri"] = "<%= config[:source_code_uri] %>"
+<%- if config[:changelog] -%>
+ spec.metadata["changelog_uri"] = "<%= config[:changelog_uri] %>"
+<%- end -%>
+
+ # Uncomment the line below to require MFA for gem pushes.
+ # This helps protect your gem from supply chain attacks by ensuring
+ # no one can publish a new version without multi-factor authentication.
+ # See: https://guides.rubygems.org/mfa-requirement-opt-in/
+ # spec.metadata["rubygems_mfa_required"] = "true"
# 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.
@@ -31,22 +34,25 @@ Gem::Specification.new do |spec|
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])
+ f.start_with?(*%w[<%= config[:ignore_paths].join(" ") %>])
end
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
-<%- if config[:ext] == 'c' || config[:ext] == 'rust' -%>
+<%- if %w(c rust go).include?(config[:ext]) -%>
spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"]
<%- end -%>
# Uncomment to register a new dependency of your gem
- # spec.add_dependency "example-gem", "~> 1.0"
+ # spec.add_dependency "example-gem", ">= 1.0"
<%- if config[:ext] == 'rust' -%>
- spec.add_dependency "rb_sys", "~> 0.9.91"
+ spec.add_dependency "rb_sys", ">= 0.9.128"
+<%- end -%>
+<%- if config[:ext] == 'go' -%>
+ spec.add_dependency "go_gem", ">= 0.2"
<%- end -%>
# For more information and examples about making a new gem, check out our
- # guide at: https://bundler.io/guides/creating_gem.html
+ # guide at: https://guides.rubygems.org/make-your-own-gem/
end
diff --git a/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt b/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
index 82cada988c..7c6cde170b 100644
--- a/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
+++ b/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
@@ -5,7 +5,15 @@ RSpec.describe <%= config[:constant_name] %> do
expect(<%= config[:constant_name] %>::VERSION).not_to be nil
end
+<%- if config[:ext] == 'rust' -%>
+ it "can call into Rust" do
+ result = <%= config[:constant_name] %>.hello("world")
+
+ expect(result).to eq("Hello world, from Rust!")
+ end
+<%- else -%>
it "does something useful" do
expect(false).to eq(true)
end
+<%- end -%>
end
diff --git a/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt b/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt
index 4b35a63071..844d3aff81 100644
--- a/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt
+++ b/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt
@@ -7,7 +7,13 @@ class <%= config[:minitest_constant_name] %> < Minitest::Test
refute_nil ::<%= config[:constant_name] %>::VERSION
end
+<%- if config[:ext] == 'rust' -%>
+ def test_hello_world
+ assert_equal "Hello world, from Rust!", <%= config[:constant_name] %>.hello("world")
+ end
+<%- else -%>
def test_it_does_something_useful
assert false
end
+<%- end -%>
end
diff --git a/lib/bundler/ui/shell.rb b/lib/bundler/ui/shell.rb
index 6df1512a5b..b836208da8 100644
--- a/lib/bundler/ui/shell.rb
+++ b/lib/bundler/ui/shell.rb
@@ -17,6 +17,7 @@ module Bundler
@level = ENV["DEBUG"] ? "debug" : "info"
@warning_history = []
@output_stream = :stdout
+ @thread_safe_logger_key = "logger_level_#{object_id}"
end
def add_color(string, *color)
@@ -80,11 +81,11 @@ module Bundler
end
def ask(msg)
- @shell.ask(msg)
+ @shell.ask(msg, :green)
end
def yes?(msg)
- @shell.yes?(msg)
+ @shell.yes?(msg, :green)
end
def no?(msg)
@@ -97,11 +98,13 @@ module Bundler
end
def level(name = nil)
- return @level unless name
+ current_level = Thread.current.thread_variable_get(@thread_safe_logger_key) || @level
+ return current_level unless name
+
unless index = LEVELS.index(name)
raise "#{name.inspect} is not a valid level"
end
- index <= LEVELS.index(@level)
+ index <= LEVELS.index(current_level)
end
def output_stream=(symbol)
@@ -167,12 +170,13 @@ module Bundler
end * "\n"
end
- def with_level(level)
- original = @level
- @level = level
+ def with_level(desired_level)
+ old_level = level
+ Thread.current.thread_variable_set(@thread_safe_logger_key, desired_level)
+
yield
ensure
- @level = original
+ Thread.current.thread_variable_set(@thread_safe_logger_key, old_level)
end
def with_output_stream(symbol)
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
index cb4485e463..e8aaf70016 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
@@ -39,7 +39,7 @@ end
# - :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, auto_reload_after_fork: true}.freeze
def self.wrap(options, &block)
Wrapper.new(options, &block)
@@ -99,10 +99,14 @@ class Bundler::ConnectionPool
@available = TimedStack.new(@size, &block)
@key = :"pool-#{@available.object_id}"
@key_count = :"pool-#{@available.object_id}-count"
- INSTANCES[self] = self if INSTANCES
+ @discard_key = :"pool-#{@available.object_id}-discard"
+ INSTANCES[self] = self if @auto_reload_after_fork && INSTANCES
end
def with(options = {})
+ # We need to manage exception handling manually here in order
+ # to work correctly with `Gem::Timeout.timeout` and `Thread#raise`.
+ # Otherwise an interrupted Thread can leak connections.
Thread.handle_interrupt(Exception => :never) do
conn = checkout(options)
begin
@@ -116,20 +120,65 @@ class Bundler::ConnectionPool
end
alias_method :then, :with
+ ##
+ # Marks the current thread's checked-out connection for discard.
+ #
+ # When a connection is marked for discard, it will not be returned to the pool
+ # when checked in. Instead, the connection will be discarded.
+ # This is useful when a connection has become invalid or corrupted
+ # and should not be reused.
+ #
+ # Takes an optional block that will be called with the connection to be discarded.
+ # The block should perform any necessary clean-up on the connection.
+ #
+ # @yield [conn]
+ # @yieldparam conn [Object] The connection to be discarded.
+ # @yieldreturn [void]
+ #
+ #
+ # Note: This only affects the connection currently checked out by the calling thread.
+ # The connection will be discarded when +checkin+ is called.
+ #
+ # @return [void]
+ #
+ # @example
+ # pool.with do |conn|
+ # begin
+ # conn.execute("SELECT 1")
+ # rescue SomeConnectionError
+ # pool.discard_current_connection # Mark connection as bad
+ # raise
+ # end
+ # end
+ def discard_current_connection(&block)
+ ::Thread.current[@discard_key] = block || proc { |conn| conn }
+ end
+
def checkout(options = {})
if ::Thread.current[@key]
::Thread.current[@key_count] += 1
::Thread.current[@key]
else
::Thread.current[@key_count] = 1
- ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout)
+ ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout, options)
end
end
def checkin(force: false)
if ::Thread.current[@key]
if ::Thread.current[@key_count] == 1 || force
- @available.push(::Thread.current[@key])
+ if ::Thread.current[@discard_key]
+ begin
+ @available.decrement_created
+ ::Thread.current[@discard_key].call(::Thread.current[@key])
+ rescue
+ nil
+ ensure
+ ::Thread.current[@discard_key] = nil
+ end
+ else
+ @available.push(::Thread.current[@key])
+ end
::Thread.current[@key] = nil
::Thread.current[@key_count] = nil
else
@@ -146,7 +195,6 @@ class Bundler::ConnectionPool
# Shuts down the Bundler::ConnectionPool by passing each connection to +block+ and
# then removing it from the pool. Attempting to checkout a connection after
# shutdown will raise +Bundler::ConnectionPool::PoolShuttingDownError+.
-
def shutdown(&block)
@available.shutdown(&block)
end
@@ -155,7 +203,6 @@ class Bundler::ConnectionPool
# Reloads the Bundler::ConnectionPool by passing each connection to +block+ and then
# removing it the pool. Subsequent checkouts will create new connections as
# needed.
-
def reload(&block)
@available.shutdown(reload: true, &block)
end
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
index 02e4485eb2..026d2c5be2 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
@@ -1,8 +1,8 @@
##
# The TimedStack manages a pool of homogeneous connections (or any resource
-# you wish to manage). Connections are created lazily up to a given maximum
+# you wish to manage). Connections are created lazily up to a given maximum
# number.
-
+#
# Examples:
#
# ts = TimedStack.new(1) { MyConnection.new }
@@ -16,14 +16,12 @@
# conn = ts.pop
# ts.pop timeout: 5
# #=> raises Bundler::ConnectionPool::TimeoutError after 5 seconds
-
class Bundler::ConnectionPool::TimedStack
attr_reader :max
##
# Creates a new pool with +size+ connections that are created from the given
# +block+.
-
def initialize(size = 0, &block)
@create_block = block
@created = 0
@@ -35,9 +33,8 @@ class Bundler::ConnectionPool::TimedStack
end
##
- # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
+ # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
# used by subclasses that extend TimedStack.
-
def push(obj, options = {})
@mutex.synchronize do
if @shutdown_block
@@ -53,14 +50,16 @@ class Bundler::ConnectionPool::TimedStack
alias_method :<<, :push
##
- # Retrieves a connection from the stack. If a connection is available it is
- # immediately returned. If no connection is available within the given
+ # Retrieves a connection from the stack. If a connection is available it is
+ # immediately returned. If no connection is available within the given
# timeout a Bundler::ConnectionPool::TimeoutError is raised.
#
- # +:timeout+ is the only checked entry in +options+ and is preferred over
- # the +timeout+ argument (which will be removed in a future release). Other
- # options may be used by subclasses that extend TimedStack.
-
+ # @option options [Float] :timeout (0.5) Wait this many seconds for an available entry
+ # @option options [Class] :exception (Bundler::ConnectionPool::TimeoutError) Exception class to raise
+ # if an entry was not available within the timeout period. Use `exception: false` to return nil.
+ #
+ # The +timeout+ argument will be removed in 3.0.
+ # Other options may be used by subclasses that extend TimedStack.
def pop(timeout = 0.5, options = {})
options, timeout = timeout, 0.5 if Hash === timeout
timeout = options.fetch :timeout, timeout
@@ -69,13 +68,22 @@ class Bundler::ConnectionPool::TimedStack
@mutex.synchronize do
loop do
raise Bundler::ConnectionPool::PoolShuttingDownError if @shutdown_block
- return fetch_connection(options) if connection_stored?(options)
+ if (conn = try_fetch_connection(options))
+ return conn
+ end
connection = try_create(options)
return connection if connection
to_wait = deadline - current_time
- raise Bundler::ConnectionPool::TimeoutError, "Waited #{timeout} sec, #{length}/#{@max} available" if to_wait <= 0
+ if to_wait <= 0
+ exc = options.fetch(:exception, Bundler::ConnectionPool::TimeoutError)
+ if exc
+ raise Bundler::ConnectionPool::TimeoutError, "Waited #{timeout} sec, #{length}/#{@max} available"
+ else
+ return nil
+ end
+ end
@resource.wait(@mutex, to_wait)
end
end
@@ -86,7 +94,6 @@ class Bundler::ConnectionPool::TimedStack
# removing it from the pool. Attempting to checkout a connection after
# shutdown will raise +Bundler::ConnectionPool::PoolShuttingDownError+ unless
# +:reload+ is +true+.
-
def shutdown(reload: false, &block)
raise ArgumentError, "shutdown must receive a block" unless block
@@ -121,14 +128,12 @@ class Bundler::ConnectionPool::TimedStack
##
# Returns +true+ if there are no available connections.
-
def empty?
(@created - @que.length) >= @max
end
##
# The number of connections available on the stack.
-
def length
@max - @created + @que.length
end
@@ -139,6 +144,12 @@ class Bundler::ConnectionPool::TimedStack
@que.length
end
+ ##
+ # Reduce the created count
+ def decrement_created
+ @created -= 1 unless @created == 0
+ end
+
private
def current_time
@@ -148,8 +159,17 @@ class Bundler::ConnectionPool::TimedStack
##
# This is an extension point for TimedStack and is called with a mutex.
#
- # This method must returns true if a connection is available on the stack.
+ # This method must returns a connection from the stack if one exists. Allows
+ # subclasses with expensive match/search algorithms to avoid double-handling
+ # their stack.
+ def try_fetch_connection(options = nil)
+ connection_stored?(options) && fetch_connection(options)
+ end
+ ##
+ # This is an extension point for TimedStack and is called with a mutex.
+ #
+ # This method must returns true if a connection is available on the stack.
def connection_stored?(options = nil)
!@que.empty?
end
@@ -158,7 +178,6 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# This method must return a connection from the stack.
-
def fetch_connection(options = nil)
@que.pop&.first
end
@@ -167,10 +186,8 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# This method must shut down all connections on the stack.
-
def shutdown_connections(options = nil)
- while connection_stored?(options)
- conn = fetch_connection(options)
+ while (conn = try_fetch_connection(options))
@created -= 1 unless @created == 0
@shutdown_block.call(conn)
end
@@ -181,7 +198,6 @@ class Bundler::ConnectionPool::TimedStack
#
# This method returns the oldest idle connection if it has been idle for more than idle_seconds.
# This requires that the stack is kept in order of checked in time (oldest first).
-
def reserve_idle_connection(idle_seconds)
return unless idle_connections?(idle_seconds)
@@ -194,7 +210,6 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# Returns true if the first connection in the stack has been idle for more than idle_seconds
-
def idle_connections?(idle_seconds)
connection_stored? && (current_time - @que.first.last > idle_seconds)
end
@@ -203,7 +218,6 @@ class Bundler::ConnectionPool::TimedStack
# This is an extension point for TimedStack and is called with a mutex.
#
# This method must return +obj+ to the stack.
-
def store_connection(obj, options = nil)
@que.push [obj, current_time]
end
@@ -213,7 +227,6 @@ class Bundler::ConnectionPool::TimedStack
#
# This method must create a connection if and only if the total number of
# connections allowed has not been met.
-
def try_create(options = nil)
unless @created == @max
object = @create_block.call
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 88a3714fb8..2e9eebdbb6 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.5.0"
+ VERSION = "2.5.5"
end
diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb
index 4d7619ddcf..a11fdc7176 100644
--- a/lib/bundler/vendor/fileutils/lib/fileutils.rb
+++ b/lib/bundler/vendor/fileutils/lib/fileutils.rb
@@ -181,7 +181,7 @@ end
#
module Bundler::FileUtils
# The version number.
- VERSION = "1.7.3"
+ VERSION = "1.8.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -706,11 +706,12 @@ module Bundler::FileUtils
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
if relative
- return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
+ return ln_sr(src, dest, force: force, target_directory: target_directory, noop: noop, verbose: verbose)
end
- fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ fu_output_message "ln -s#{force ? 'f' : ''}#{
+ target_directory ? '' : 'T'} #{[src,dest].flatten.join ' '}" if verbose
return if noop
- fu_each_src_dest0(src, dest) do |s,d|
+ fu_each_src_dest0(src, dest, target_directory) do |s,d|
remove_file d, true if force
File.symlink s, d
end
@@ -730,42 +731,37 @@ module Bundler::FileUtils
# Like Bundler::FileUtils.ln_s, but create links relative to +dest+.
#
def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
- options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
- dest = File.path(dest)
- srcs = Array(src)
- link = proc do |s, target_dir_p = true|
- s = File.path(s)
- if target_dir_p
- d = File.join(destdirs = dest, File.basename(s))
+ cmd = "ln -s#{force ? 'f' : ''}#{target_directory ? '' : 'T'}" if verbose
+ fu_each_src_dest0(src, dest, target_directory) do |s,d|
+ if target_directory
+ parent = File.dirname(d)
+ destdirs = fu_split_path(parent)
+ real_ddirs = fu_split_path(File.realpath(parent))
else
- destdirs = File.dirname(d = dest)
+ destdirs ||= fu_split_path(dest)
+ real_ddirs ||= fu_split_path(File.realdirpath(dest))
end
- destdirs = fu_split_path(File.realpath(destdirs))
- if fu_starting_path?(s)
- srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
- base = fu_relative_components_from(srcdirs, destdirs)
- s = File.join(*base)
+ srcdirs = fu_split_path(s)
+ i = fu_common_components(srcdirs, destdirs)
+ n = destdirs.size - i
+ n -= 1 unless target_directory
+ link1 = fu_clean_components(*Array.new([n, 0].max, '..'), *srcdirs[i..-1])
+ begin
+ real_sdirs = fu_split_path(File.realdirpath(s)) rescue nil
+ rescue
else
- srcdirs = fu_clean_components(*fu_split_path(s))
- base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
- while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
- srcdirs.shift
- base.pop
- end
- s = File.join(*base, *srcdirs)
+ i = fu_common_components(real_sdirs, real_ddirs)
+ n = real_ddirs.size - i
+ n -= 1 unless target_directory
+ link2 = fu_clean_components(*Array.new([n, 0].max, '..'), *real_sdirs[i..-1])
+ link1 = link2 if link1.size > link2.size
end
- fu_output_message "ln -s#{options} #{s} #{d}" if verbose
+ s = File.join(link1)
+ fu_output_message [cmd, s, d].flatten.join(' ') if verbose
next if noop
remove_file d, true if force
File.symlink s, d
end
- case srcs.size
- when 0
- when 1
- link[srcs[0], target_directory && File.directory?(dest)]
- else
- srcs.each(&link)
- end
end
module_function :ln_sr
@@ -800,13 +796,13 @@ module Bundler::FileUtils
# File.file?('dest1/dir1/t2.txt') # => true
# File.file?('dest1/dir1/t3.txt') # => true
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference_root: true</tt> - dereferences +src+ if it is a symbolic link.
- # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
+ # - +dereference_root+ - dereferences +src+ if it is a symbolic link (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before creating links (+false+ by default).
#
# Raises an exception if +dest+ is the path to an existing file or directory
- # and keyword argument <tt>remove_destination: true</tt> is not given.
+ # and optional argument +remove_destination+ is not given.
#
# Related: Bundler::FileUtils.ln (has different options).
#
@@ -1029,12 +1025,12 @@ module Bundler::FileUtils
# directories, and symbolic links;
# other file types (FIFO streams, device files, etc.) are not supported.
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference_root: true</tt> - if +src+ is a symbolic link,
- # follows the link.
- # - <tt>preserve: true</tt> - preserves file times.
- # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - +dereference_root+ - if +src+ is a symbolic link,
+ # follows the link (+false+ by default).
+ # - +preserve+ - preserves file times (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before copying files (+false+ by default).
#
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
@@ -1065,12 +1061,12 @@ module Bundler::FileUtils
# Bundler::FileUtils.copy_file('src0.txt', 'dest0.txt')
# File.file?('dest0.txt') # => true
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference: false</tt> - if +src+ is a symbolic link,
- # does not follow the link.
- # - <tt>preserve: true</tt> - preserves file times.
- # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - +dereference+ - if +src+ is a symbolic link,
+ # follows the link (+true+ by default).
+ # - +preserve+ - preserves file times (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before copying files (+false+ by default).
#
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
@@ -1491,7 +1487,8 @@ module Bundler::FileUtils
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def remove_dir(path, force = false)
- remove_entry path, force # FIXME?? check if it is a directory
+ raise Errno::ENOTDIR, path unless force or File.directory?(path)
+ remove_entry path, force
end
module_function :remove_dir
@@ -2475,6 +2472,10 @@ module Bundler::FileUtils
def fu_each_src_dest0(src, dest, target_directory = true) #:nodoc:
if tmp = Array.try_convert(src)
+ unless target_directory or tmp.size <= 1
+ tmp = tmp.map {|f| File.path(f)} # A workaround for RBS
+ raise ArgumentError, "extra target #{tmp}"
+ end
tmp.each do |s|
s = File.path(s)
yield s, (target_directory ? File.join(dest, File.basename(s)) : dest)
@@ -2509,7 +2510,11 @@ module Bundler::FileUtils
path = File.path(path)
list = []
until (parent, base = File.split(path); parent == path or parent == ".")
- list << base
+ if base != '..' and list.last == '..' and !(fu_have_symlink? && File.symlink?(path))
+ list.pop
+ else
+ list << base
+ end
path = parent
end
list << path
@@ -2517,14 +2522,14 @@ module Bundler::FileUtils
end
private_module_function :fu_split_path
- def fu_relative_components_from(target, base) #:nodoc:
+ def fu_common_components(target, base) #:nodoc:
i = 0
while target[i]&.== base[i]
i += 1
end
- Array.new(base.size-i, '..').concat(target[i..-1])
+ i
end
- private_module_function :fu_relative_components_from
+ private_module_function :fu_common_components
def fu_clean_components(*comp) #:nodoc:
comp.shift while comp.first == "."
@@ -2534,7 +2539,7 @@ module Bundler::FileUtils
while c = comp.shift
if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
clean.pop
- path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
+ path.sub!(%r((?<=\A|/)[^/]+/\z), "")
else
clean << c
path << c << "/"
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..93e403a5bb 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,6 +1,10 @@
require_relative '../../../../../vendored_net_http'
require_relative '../../../../../vendored_uri'
-require 'cgi' # for escaping
+begin
+ require 'cgi/escape'
+rescue LoadError
+ require 'cgi/util' # for escaping
+end
require_relative '../../../../connection_pool/lib/connection_pool'
autoload :OpenSSL, 'openssl'
@@ -42,9 +46,8 @@ autoload :OpenSSL, 'openssl'
# # perform the POST, the Gem::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
-# params which are sent in the body for other requests.
+# ⚠ Note that for GET, HEAD and other requests that do not have a body,
+# it uses Gem::URI#request_uri as default to send query params
#
# == TLS/SSL
#
@@ -60,6 +63,7 @@ autoload :OpenSSL, 'openssl'
# #ca_path :: Directory with certificate-authorities
# #cert_store :: An SSL certificate store
# #ciphers :: List of SSl ciphers allowed
+# #extra_chain_cert :: Extra certificates to be added to the certificate chain
# #private_key :: The client's SSL private key
# #reuse_ssl_sessions :: Reuse a previously opened SSL session for a new
# connection
@@ -176,7 +180,7 @@ class Gem::Net::HTTP::Persistent
##
# The version of Gem::Net::HTTP::Persistent you are using
- VERSION = '4.0.4'
+ VERSION = '4.0.6'
##
# Error class for errors raised by Gem::Net::HTTP::Persistent. Various
@@ -268,6 +272,11 @@ class Gem::Net::HTTP::Persistent
attr_reader :ciphers
##
+ # Extra certificates to be added to the certificate chain
+
+ attr_reader :extra_chain_cert
+
+ ##
# Sends debug_output to this IO via Gem::Net::HTTP#set_debug_output.
#
# Never use this method in production code, it causes a serious security
@@ -587,6 +596,21 @@ class Gem::Net::HTTP::Persistent
reconnect_ssl
end
+ if Gem::Net::HTTP.method_defined?(:extra_chain_cert=)
+ ##
+ # Extra certificates to be added to the certificate chain.
+ # It is only supported starting from Gem::Net::HTTP version 0.1.1
+ def extra_chain_cert= extra_chain_cert
+ @extra_chain_cert = extra_chain_cert
+
+ reconnect_ssl
+ end
+ else
+ def extra_chain_cert= _extra_chain_cert
+ raise "extra_chain_cert= is not supported by this version of Gem::Net::HTTP"
+ end
+ end
+
##
# Creates a new connection for +uri+
@@ -605,47 +629,49 @@ class Gem::Net::HTTP::Persistent
connection = @pool.checkout net_http_args
- http = connection.http
+ begin
+ http = connection.http
- connection.ressl @ssl_generation if
- connection.ssl_generation != @ssl_generation
+ connection.ressl @ssl_generation if
+ connection.ssl_generation != @ssl_generation
- if not http.started? then
- ssl http if use_ssl
- start http
- elsif expired? connection then
- reset connection
- end
+ if not http.started? then
+ ssl http if use_ssl
+ start http
+ elsif expired? connection then
+ reset connection
+ end
- http.keep_alive_timeout = @idle_timeout if @idle_timeout
- http.max_retries = @max_retries if http.respond_to?(:max_retries=)
- http.read_timeout = @read_timeout if @read_timeout
- http.write_timeout = @write_timeout if
- @write_timeout && http.respond_to?(:write_timeout=)
+ http.keep_alive_timeout = @idle_timeout if @idle_timeout
+ http.max_retries = @max_retries if http.respond_to?(:max_retries=)
+ http.read_timeout = @read_timeout if @read_timeout
+ http.write_timeout = @write_timeout if
+ @write_timeout && http.respond_to?(:write_timeout=)
+
+ 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
- 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
+ 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
- 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
+ raise Error, "host down: #{address}:#{port}"
+ ensure
+ @pool.checkin net_http_args
end
-
- raise Error, "host down: #{address}:#{port}"
- ensure
- @pool.checkin net_http_args
end
##
@@ -782,7 +808,7 @@ class Gem::Net::HTTP::Persistent
@proxy_connection_id = [nil, *@proxy_args].join ':'
if @proxy_uri.query then
- @no_proxy = CGI.parse(@proxy_uri.query)['no_proxy'].join(',').downcase.split(',').map { |x| x.strip }.reject { |x| x.empty? }
+ @no_proxy = Gem::URI.decode_www_form(@proxy_uri.query).filter_map { |k, v| v if k == 'no_proxy' }.join(',').downcase.split(',').map { |x| x.strip }.reject { |x| x.empty? }
end
end
@@ -953,7 +979,8 @@ class Gem::Net::HTTP::Persistent
end
##
- # Shuts down all connections
+ # Shuts down all connections. Attempting to checkout a connection after
+ # shutdown will raise an error.
#
# *NOTE*: Calling shutdown for can be dangerous!
#
@@ -965,6 +992,17 @@ class Gem::Net::HTTP::Persistent
end
##
+ # Discard all existing connections. Subsequent checkouts will create
+ # new connections as needed.
+ #
+ # If any thread is still using a connection it may cause an error! Call
+ # #reload when you are completely done making requests!
+
+ def reload
+ @pool.reload { |http| http.finish }
+ end
+
+ ##
# Enables SSL on +connection+
def ssl connection
@@ -1021,6 +1059,10 @@ application:
connection.key = @private_key
end
+ if defined?(@extra_chain_cert) and @extra_chain_cert
+ connection.extra_chain_cert = @extra_chain_cert
+ end
+
connection.cert_store = if @cert_store then
@cert_store
else
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..034fbe39b8 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
@@ -63,7 +63,8 @@ class Gem::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::Tim
if @created >= @max && @enqueued >= 1
oldest, = @lru.first
@lru.delete oldest
- @ques[oldest].pop
+ connection = @ques[oldest].pop
+ connection.close if connection.respond_to?(:close)
@created -= 1
end
diff --git a/lib/bundler/vendor/thor/lib/thor.rb b/lib/bundler/vendor/thor/lib/thor.rb
index bfd9f5c914..945bdbd551 100644
--- a/lib/bundler/vendor/thor/lib/thor.rb
+++ b/lib/bundler/vendor/thor/lib/thor.rb
@@ -625,7 +625,7 @@ class Bundler::Thor
# alias name.
def find_command_possibilities(meth)
len = meth.to_s.length
- possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
+ possibilities = all_commands.reject { |_k, c| c.hidden? }.merge(map).keys.select { |n| meth == n[0, len] }.sort
unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
if possibilities.include?(meth)
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 bccfbb6b85..d8c9863054 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
@@ -242,6 +242,35 @@ class Bundler::Thor
insert_into_file(path, *(args << config), &block)
end
+ # Run a regular expression replacement on a file, raising an error if the
+ # contents of the file are not changed.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # 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.
+ #
+ # ==== Example
+ #
+ # gsub_file! 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
+ #
+ # gsub_file! 'README', /rake/, :green do |match|
+ # match << " no more. Use thor!"
+ # end
+ #
+ def gsub_file!(path, flag, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+
+ return unless behavior == :invoke || config.fetch(:force, false)
+
+ path = File.expand_path(path, destination_root)
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+
+ actually_gsub_file(path, flag, args, true, &block) unless options[:pretend]
+ end
+
# Run a regular expression replacement on a file.
#
# ==== Parameters
@@ -267,11 +296,7 @@ class Bundler::Thor
path = File.expand_path(path, destination_root)
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
- unless options[:pretend]
- content = File.binread(path)
- content.gsub!(flag, *args, &block)
- File.open(path, "wb") { |file| file.write(content) }
- end
+ actually_gsub_file(path, flag, args, false, &block) unless options[:pretend]
end
# Uncomment all lines matching a given regex. Preserves indentation before
@@ -348,7 +373,7 @@ class Bundler::Thor
end
def with_output_buffer(buf = "".dup) #:nodoc:
- raise ArgumentError, "Buffer can not be a frozen object" if buf.frozen?
+ raise ArgumentError, "Buffer cannot be a frozen object" if buf.frozen?
old_buffer = output_buffer
self.output_buffer = buf
yield
@@ -357,6 +382,17 @@ class Bundler::Thor
self.output_buffer = old_buffer
end
+ def actually_gsub_file(path, flag, args, error_on_no_change, &block)
+ content = File.binread(path)
+ success = content.gsub!(flag, *args, &block)
+
+ if success.nil? && error_on_no_change
+ raise Bundler::Thor::Error, "The content of #{path} did not change"
+ end
+
+ File.open(path, "wb") { |file| file.write(content) }
+ end
+
# Bundler::Thor::Actions#capture depends on what kind of buffer is used in ERB.
# Thus CapturableERB fixes ERB to use String buffer.
class CapturableERB < ERB
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
index 734f5fe7e3..fe22d989e5 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/options.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
@@ -144,7 +144,7 @@ class Bundler::Thor
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.
+ # the difference 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}'"}
diff --git a/lib/bundler/vendor/thor/lib/thor/runner.rb b/lib/bundler/vendor/thor/lib/thor/runner.rb
index c7cc873131..f0ce6df96c 100644
--- a/lib/bundler/vendor/thor/lib/thor/runner.rb
+++ b/lib/bundler/vendor/thor/lib/thor/runner.rb
@@ -1,9 +1,8 @@
require_relative "../thor"
require_relative "group"
-require "yaml"
require "digest/sha2"
-require "pathname"
+require "pathname" unless defined?(Pathname)
class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
@@ -195,6 +194,7 @@ private
def thor_yaml
@thor_yaml ||= begin
yaml_file = File.join(thor_root, "thor.yml")
+ require "yaml"
yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file)
yaml || {}
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
index b3e85733cb..da02b94227 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
@@ -314,7 +314,7 @@ class Bundler::Thor
diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
require "tempfile"
- Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
+ Tempfile.open(File.basename(destination), File.dirname(destination), binmode: true) do |temp|
temp.write content
temp.rewind
system %(#{diff_cmd} "#{destination}" "#{temp.path}")
@@ -372,16 +372,12 @@ class Bundler::Thor
Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
temp.write content
temp.rewind
- system %(#{merge_tool} "#{temp.path}" "#{destination}")
+ system(merge_tool, temp.path, destination)
end
end
def merge_tool #:nodoc:
- @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
- end
-
- def git_merge_tool #:nodoc:
- `git config merge.tool`.rstrip rescue ""
+ @merge_tool ||= ENV["THOR_MERGE"] || "git difftool --no-index"
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb
index cd7b4f060e..5474a2f71b 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.2"
+ VERSION = "1.4.0"
end
diff --git a/lib/bundler/vendor/uri/lib/uri/common.rb b/lib/bundler/vendor/uri/lib/uri/common.rb
index 186da24fa8..38339119c5 100644
--- a/lib/bundler/vendor/uri/lib/uri/common.rb
+++ b/lib/bundler/vendor/uri/lib/uri/common.rb
@@ -30,6 +30,9 @@ module Bundler::URI
remove_const(:Parser) if defined?(::Bundler::URI::Parser)
const_set("Parser", parser.class)
+ remove_const(:PARSER) if defined?(::Bundler::URI::PARSER)
+ const_set("PARSER", parser)
+
remove_const(:REGEXP) if defined?(::Bundler::URI::REGEXP)
remove_const(:PATTERN) if defined?(::Bundler::URI::PATTERN)
if Parser == RFC2396_Parser
@@ -49,10 +52,10 @@ module Bundler::URI
warn "Bundler::URI::REGEXP is obsolete. Use Bundler::URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE
Bundler::URI::RFC2396_REGEXP
elsif value = RFC2396_PARSER.regexp[const]
- warn "Bundler::URI::#{const} is obsolete. Use RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
+ warn "Bundler::URI::#{const} is obsolete. Use Bundler::URI::RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
value
elsif value = RFC2396_Parser.const_get(const)
- warn "Bundler::URI::#{const} is obsolete. Use RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
+ warn "Bundler::URI::#{const} is obsolete. Use Bundler::URI::RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
value
else
super
@@ -92,6 +95,40 @@ module Bundler::URI
end
module Schemes # :nodoc:
+ class << self
+ ReservedChars = ".+-"
+ EscapedChars = "\u01C0\u01C1\u01C2"
+ # Use Lo category chars as escaped chars for TruffleRuby, which
+ # does not allow Symbol categories as identifiers.
+
+ def escape(name)
+ unless name and name.ascii_only?
+ return nil
+ end
+ name.upcase.tr(ReservedChars, EscapedChars)
+ end
+
+ def unescape(name)
+ name.tr(EscapedChars, ReservedChars).encode(Encoding::US_ASCII).upcase
+ end
+
+ def find(name)
+ const_get(name, false) if name and const_defined?(name, false)
+ end
+
+ def register(name, klass)
+ unless scheme = escape(name)
+ raise ArgumentError, "invalid character as scheme - #{name}"
+ end
+ const_set(scheme, klass)
+ end
+
+ def list
+ constants.map { |name|
+ [unescape(name.to_s), const_get(name)]
+ }.to_h
+ end
+ end
end
private_constant :Schemes
@@ -104,7 +141,7 @@ module Bundler::URI
# 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)
+ Schemes.register(scheme, klass)
end
# Returns a hash of the defined schemes:
@@ -122,14 +159,14 @@ module Bundler::URI
#
# Related: Bundler::URI.register_scheme.
def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
+ Schemes.list
end
+ # :stopdoc:
INITIAL_SCHEMES = scheme_list
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
+ # :startdoc:
# Returns a new object constructed from the given +scheme+, +arguments+,
# and +default+:
@@ -148,12 +185,10 @@ module Bundler::URI
# # => #<Bundler::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
+ const_name = Schemes.escape(scheme)
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 ||= Schemes.find(const_name)
uri_class ||= default
return uri_class.new(scheme, *arguments)
@@ -195,7 +230,7 @@ module Bundler::URI
# ["fragment", "top"]]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ PARSER.split(uri)
end
# Returns a new \Bundler::URI object constructed from the given string +uri+:
@@ -205,11 +240,11 @@ module Bundler::URI
# 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>
#
- # It's recommended to first ::escape string +uri+
+ # It's recommended to first Bundler::URI::RFC2396_PARSER.escape string +uri+
# if it may contain invalid Bundler::URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ PARSER.parse(uri)
end
# Merges the given Bundler::URI strings +str+
@@ -265,7 +300,7 @@ module Bundler::URI
#
def self.extract(str, schemes = nil, &block) # :nodoc:
warn "Bundler::URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
+ PARSER.extract(str, schemes, &block)
end
#
@@ -302,7 +337,7 @@ module Bundler::URI
#
def self.regexp(schemes = nil)# :nodoc:
warn "Bundler::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
+ PARSER.make_regexp(schemes)
end
TBLENCWWWCOMP_ = {} # :nodoc:
@@ -407,6 +442,8 @@ module Bundler::URI
_decode_uri_component(/%\h\h/, str, enc)
end
+ # Returns a string derived from the given string +str+ with
+ # Bundler::URI-encoded characters matching +regexp+ according to +table+.
def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
@@ -421,6 +458,8 @@ module Bundler::URI
end
private_class_method :_encode_uri_component
+ # Returns a string decoding characters matching +regexp+ from the
+ # given \URL-encoded string +str+.
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)
@@ -859,6 +898,7 @@ 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:
#
+ # require 'bundler/vendor/uri/lib/uri'
# # Returns a new Bundler::URI.
# uri = Bundler::URI('http://github.com/ruby/ruby')
# # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
@@ -866,6 +906,8 @@ module Bundler
# Bundler::URI(uri)
# # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
#
+ # You must require 'bundler/vendor/uri/lib/uri' to use this method.
+ #
def URI(uri)
if uri.is_a?(Bundler::URI::Generic)
uri
diff --git a/lib/bundler/vendor/uri/lib/uri/file.rb b/lib/bundler/vendor/uri/lib/uri/file.rb
index de347af6eb..21dd9ee535 100644
--- a/lib/bundler/vendor/uri/lib/uri/file.rb
+++ b/lib/bundler/vendor/uri/lib/uri/file.rb
@@ -47,7 +47,7 @@ module Bundler::URI
# :path => '/ruby/src'})
# uri2.to_s # => "file://host.example.com/ruby/src"
#
- # uri3 = Bundler::URI::File.build({:path => Bundler::URI::escape('/path/my file.txt')})
+ # uri3 = Bundler::URI::File.build({:path => Bundler::URI::RFC2396_PARSER.escape('/path/my file.txt')})
# uri3.to_s # => "file:///path/my%20file.txt"
#
def self.build(args)
diff --git a/lib/bundler/vendor/uri/lib/uri/generic.rb b/lib/bundler/vendor/uri/lib/uri/generic.rb
index 6abb171d14..30dab60903 100644
--- a/lib/bundler/vendor/uri/lib/uri/generic.rb
+++ b/lib/bundler/vendor/uri/lib/uri/generic.rb
@@ -73,7 +73,7 @@ module Bundler::URI
#
# At first, tries to create a new Bundler::URI::Generic instance using
# Bundler::URI::Generic::build. But, if exception Bundler::URI::InvalidComponentError is raised,
- # then it does Bundler::URI::Escape.escape all Bundler::URI components and tries again.
+ # then it does Bundler::URI::RFC2396_PARSER.escape all Bundler::URI components and tries again.
#
def self.build2(args)
begin
@@ -126,9 +126,9 @@ module Bundler::URI
end
end
else
- component = self.class.component rescue ::Bundler::URI::Generic::COMPONENT
+ component = self.component rescue ::Bundler::URI::Generic::COMPONENT
raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
+ "expected Array of or Hash of components of #{self} (#{component.join(', ')})"
end
tmp << nil
@@ -186,18 +186,18 @@ module Bundler::URI
if arg_check
self.scheme = scheme
- self.userinfo = userinfo
self.hostname = host
self.port = port
+ self.userinfo = userinfo
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_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
@@ -284,7 +284,7 @@ module Bundler::URI
# Returns the parser to be used.
#
- # Unless a Bundler::URI::Parser is defined, DEFAULT_PARSER is used.
+ # Unless the +parser+ is defined, DEFAULT_PARSER is used.
#
def parser
if !defined?(@parser) || !@parser
@@ -315,7 +315,7 @@ module Bundler::URI
end
#
- # Checks the scheme +v+ component against the Bundler::URI::Parser Regexp for :SCHEME.
+ # Checks the scheme +v+ component against the +parser+ Regexp for :SCHEME.
#
def check_scheme(v)
if v && parser.regexp[:SCHEME] !~ v
@@ -385,7 +385,7 @@ module Bundler::URI
#
# Checks the user +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -409,7 +409,7 @@ module Bundler::URI
#
# Checks the password +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -511,7 +511,7 @@ module Bundler::URI
user, password = split_userinfo(user)
end
@user = user
- @password = password if password
+ @password = password
[@user, @password]
end
@@ -522,7 +522,7 @@ module Bundler::URI
# See also Bundler::URI::Generic.user=.
#
def set_user(v)
- set_userinfo(v, @password)
+ set_userinfo(v, nil)
v
end
protected :set_user
@@ -574,6 +574,12 @@ module Bundler::URI
@password
end
+ # Returns the authority info (array of user, password, host and
+ # port), if any is set. Or returns +nil+.
+ def authority
+ return @user, @password, @host, @port if @user || @password || @host || @port
+ end
+
# Returns the user component after Bundler::URI decoding.
def decoded_user
Bundler::URI.decode_uri_component(@user) if @user
@@ -586,7 +592,7 @@ module Bundler::URI
#
# Checks the host +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :HOST.
+ # and against the +parser+ Regexp for :HOST.
#
# Can not have a registry or opaque component defined,
# with a host component defined.
@@ -615,6 +621,13 @@ module Bundler::URI
end
protected :set_host
+ # Protected setter for the authority info (+user+, +password+, +host+
+ # and +port+). If +port+ is +nil+, +default_port+ will be set.
+ #
+ protected def set_authority(user, password, host, port = nil)
+ @user, @password, @host, @port = user, password, host, port || self.default_port
+ end
+
#
# == Args
#
@@ -639,6 +652,7 @@ module Bundler::URI
def host=(v)
check_host(v)
set_host(v)
+ set_userinfo(nil)
v
end
@@ -675,7 +689,7 @@ module Bundler::URI
#
# Checks the port +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp for :PORT.
+ # and against the +parser+ Regexp for :PORT.
#
# Can not have a registry or opaque component defined,
# with a port component defined.
@@ -729,6 +743,7 @@ module Bundler::URI
def port=(v)
check_port(v)
set_port(v)
+ set_userinfo(nil)
port
end
@@ -748,7 +763,7 @@ module Bundler::URI
#
# Checks the path +v+ component for RFC2396 compliance
- # and against the Bundler::URI::Parser Regexp
+ # and against the +parser+ Regexp
# for :ABS_PATH and :REL_PATH.
#
# Can not have a opaque component defined,
@@ -853,7 +868,7 @@ module Bundler::URI
#
# Checks the opaque +v+ component for RFC2396 compliance and
- # against the Bundler::URI::Parser Regexp for :OPAQUE.
+ # against the +parser+ Regexp for :OPAQUE.
#
# Can not have a host, port, user, or path component defined,
# with an opaque component defined.
@@ -905,7 +920,7 @@ module Bundler::URI
end
#
- # Checks the fragment +v+ component against the Bundler::URI::Parser Regexp for :FRAGMENT.
+ # Checks the fragment +v+ component against the +parser+ Regexp for :FRAGMENT.
#
#
# == Args
@@ -1121,7 +1136,7 @@ module Bundler::URI
base = self.dup
- authority = rel.userinfo || rel.host || rel.port
+ authority = rel.authority
# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
@@ -1134,9 +1149,7 @@ module Bundler::URI
# 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_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
@@ -1527,7 +1540,7 @@ module Bundler::URI
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
+ warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1
end
end
end
diff --git a/lib/bundler/vendor/uri/lib/uri/http.rb b/lib/bundler/vendor/uri/lib/uri/http.rb
index 6c34a469b7..9b217ee266 100644
--- a/lib/bundler/vendor/uri/lib/uri/http.rb
+++ b/lib/bundler/vendor/uri/lib/uri/http.rb
@@ -61,6 +61,18 @@ module Bundler::URI
super(tmp)
end
+ # Do not allow empty host names, as they are not allowed by RFC 3986.
+ def check_host(v)
+ ret = super
+
+ if ret && v.empty?
+ raise InvalidComponentError,
+ "bad component(expected host component): #{v}"
+ end
+
+ ret
+ end
+
#
# == Description
#
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
index 229971f73c..522113fe67 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
@@ -67,7 +67,7 @@ module Bundler::URI
#
# == Synopsis
#
- # Bundler::URI::Parser.new([opts])
+ # Bundler::URI::RFC2396_Parser.new([opts])
#
# == Args
#
@@ -86,7 +86,7 @@ module Bundler::URI
#
# == Examples
#
- # p = Bundler::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
+ # p = Bundler::URI::RFC2396_Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
# u = p.parse("http://example.jp/%uABCD") #=> #<Bundler::URI::HTTP http://example.jp/%uABCD>
# Bundler::URI.parse(u.to_s) #=> raises Bundler::URI::InvalidURIError
#
@@ -108,12 +108,12 @@ module Bundler::URI
# The Hash of patterns.
#
- # See also Bundler::URI::Parser.initialize_pattern.
+ # See also #initialize_pattern.
attr_reader :pattern
# The Hash of Regexp.
#
- # See also Bundler::URI::Parser.initialize_regexp.
+ # See also #initialize_regexp.
attr_reader :regexp
# Returns a split Bundler::URI against +regexp[:ABS_URI]+.
@@ -202,8 +202,7 @@ module Bundler::URI
#
# == Usage
#
- # p = Bundler::URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
+ # Bundler::URI::RFC2396_PARSER.parse("ldap://ldap.example.com/dc=example?user=john")
# #=> #<Bundler::URI::LDAP ldap://ldap.example.com/dc=example?user=john>
#
def parse(uri)
@@ -244,7 +243,7 @@ module Bundler::URI
# If no +block+ given, then returns the result,
# else it calls +block+ for each element in result.
#
- # See also Bundler::URI::Parser.make_regexp.
+ # See also #make_regexp.
#
def extract(str, schemes = nil)
if block_given?
@@ -263,7 +262,7 @@ module Bundler::URI
unless schemes
@regexp[:ABS_URI_REF]
else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
+ /(?=(?i:#{Regexp.union(*schemes).source}):)#{@pattern[:X_ABS_URI]}/x
end
end
@@ -524,6 +523,8 @@ module Bundler::URI
ret
end
+ # Returns +uri+ as-is if it is Bundler::URI, or convert it to Bundler::URI if it is
+ # a String.
def convert_to_uri(uri)
if uri.is_a?(Bundler::URI::Generic)
uri
diff --git a/lib/bundler/vendor/uri/lib/uri/version.rb b/lib/bundler/vendor/uri/lib/uri/version.rb
index d4996a12e2..ad76308e81 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 = '010003'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
+ VERSION = '1.1.1'.freeze
+ VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze
# :startdoc:
end
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index fa24b4966e..ca7bb0719a 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -1,13 +1,21 @@
# frozen_string_literal: false
module Bundler
- VERSION = "2.7.0.dev".freeze
+ VERSION = "4.1.0.dev".freeze
def self.bundler_major_version
- @bundler_major_version ||= VERSION.split(".").first.to_i
+ @bundler_major_version ||= gem_version.segments.first
end
def self.gem_version
@gem_version ||= Gem::Version.create(VERSION)
end
+
+ def self.verbose_version
+ @verbose_version ||= "#{VERSION}#{simulated_version ? " (simulating Bundler #{simulated_version})" : ""}"
+ end
+
+ def self.simulated_version
+ @simulated_version ||= Bundler.settings[:simulate_version]
+ end
end
diff --git a/lib/bundler/vlad.rb b/lib/bundler/vlad.rb
index 6179d0e4eb..c3a3d949a6 100644
--- a/lib/bundler/vlad.rb
+++ b/lib/bundler/vlad.rb
@@ -1,17 +1,4 @@
# frozen_string_literal: true
require_relative "shared_helpers"
-Bundler::SharedHelpers.major_deprecation 2,
- "The Bundler task for Vlad"
-
-# Vlad task for Bundler.
-#
-# Add "require 'bundler/vlad'" in your Vlad deploy.rb, and
-# include the vlad:bundle:install task in your vlad:deploy task.
-require_relative "deployment"
-
-include Rake::DSL if defined? Rake::DSL
-
-namespace :vlad do
- Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, roles: :app)
-end
+Bundler::SharedHelpers.feature_removed! "The Bundler task for Vlad"
diff --git a/lib/bundler/worker.rb b/lib/bundler/worker.rb
index 7137484cc6..77f4f004aa 100644
--- a/lib/bundler/worker.rb
+++ b/lib/bundler/worker.rb
@@ -22,6 +22,7 @@ module Bundler
def initialize(size, name, func)
@name = name
@request_queue = Thread::Queue.new
+ @request_queue_with_priority = Thread::Queue.new
@response_queue = Thread::Queue.new
@func = func
@size = size
@@ -32,9 +33,10 @@ module Bundler
# Enqueue a request to be executed in the worker pool
#
# @param obj [String] mostly it is name of spec that should be downloaded
- def enq(obj)
+ def enq(obj, priority: false)
+ queue = priority ? @request_queue_with_priority : @request_queue
create_threads unless @threads
- @request_queue.enq obj
+ queue.enq obj
end
# Retrieves results of job function being executed in worker pool
@@ -52,7 +54,13 @@ module Bundler
def process_queue(i)
loop do
- obj = @request_queue.deq
+ obj = begin
+ @request_queue_with_priority.deq(true)
+ rescue ThreadError
+ @request_queue.deq(false, timeout: 0.05)
+ end
+
+ next if obj.nil?
break if obj.equal? POISON
@response_queue.enq apply_func(obj, i)
end
diff --git a/lib/cgi.rb b/lib/cgi.rb
index 69c3c4fd24..0c403bd19c 100644
--- a/lib/cgi.rb
+++ b/lib/cgi.rb
@@ -1,297 +1,9 @@
# frozen_string_literal: true
-#
-# cgi.rb - cgi support library
-#
-# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
-#
-# Copyright (C) 2000 Information-technology Promotion Agency, Japan
-#
-# Author: Wakou Aoyama <wakou@ruby-lang.org>
-#
-# Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber)
-#
-# == Overview
-#
-# The Common Gateway Interface (CGI) is a simple protocol for passing an HTTP
-# request from a web server to a standalone program, and returning the output
-# to the web browser. Basically, a CGI program is called with the parameters
-# of the request passed in either in the environment (GET) or via $stdin
-# (POST), and everything it prints to $stdout is returned to the client.
-#
-# This file holds the CGI class. This class provides functionality for
-# retrieving HTTP request parameters, managing cookies, and generating HTML
-# output.
-#
-# The file CGI::Session provides session management functionality; see that
-# class for more details.
-#
-# See http://www.w3.org/CGI/ for more information on the CGI protocol.
-#
-# == Introduction
-#
-# CGI is a large class, providing several categories of methods, many of which
-# are mixed in from other modules. Some of the documentation is in this class,
-# some in the modules CGI::QueryExtension and CGI::HtmlExtension. See
-# CGI::Cookie for specific information on handling cookies, and cgi/session.rb
-# (CGI::Session) for information on sessions.
-#
-# For queries, CGI provides methods to get at environmental variables,
-# parameters, cookies, and multipart request data. For responses, CGI provides
-# methods for writing output and generating HTML.
-#
-# Read on for more details. Examples are provided at the bottom.
-#
-# == Queries
-#
-# The CGI class dynamically mixes in parameter and cookie-parsing
-# functionality, environmental variable access, and support for
-# parsing multipart requests (including uploaded files) from the
-# CGI::QueryExtension module.
-#
-# === Environmental Variables
-#
-# The standard CGI environmental variables are available as read-only
-# attributes of a CGI object. The following is a list of these variables:
-#
-#
-# AUTH_TYPE HTTP_HOST REMOTE_IDENT
-# CONTENT_LENGTH HTTP_NEGOTIATE REMOTE_USER
-# CONTENT_TYPE HTTP_PRAGMA REQUEST_METHOD
-# GATEWAY_INTERFACE HTTP_REFERER SCRIPT_NAME
-# HTTP_ACCEPT HTTP_USER_AGENT SERVER_NAME
-# HTTP_ACCEPT_CHARSET PATH_INFO SERVER_PORT
-# HTTP_ACCEPT_ENCODING PATH_TRANSLATED SERVER_PROTOCOL
-# HTTP_ACCEPT_LANGUAGE QUERY_STRING SERVER_SOFTWARE
-# HTTP_CACHE_CONTROL REMOTE_ADDR
-# HTTP_FROM REMOTE_HOST
-#
-#
-# For each of these variables, there is a corresponding attribute with the
-# same name, except all lower case and without a preceding HTTP_.
-# +content_length+ and +server_port+ are integers; the rest are strings.
-#
-# === Parameters
-#
-# The method #params() returns a hash of all parameters in the request as
-# name/value-list pairs, where the value-list is an Array of one or more
-# values. The CGI object itself also behaves as a hash of parameter names
-# to values, but only returns a single value (as a String) for each
-# parameter name.
-#
-# For instance, suppose the request contains the parameter
-# "favourite_colours" with the multiple values "blue" and "green". The
-# following behavior would occur:
-#
-# cgi.params["favourite_colours"] # => ["blue", "green"]
-# cgi["favourite_colours"] # => "blue"
-#
-# If a parameter does not exist, the former method will return an empty
-# array, the latter an empty string. The simplest way to test for existence
-# of a parameter is by the #has_key? method.
-#
-# === Cookies
-#
-# HTTP Cookies are automatically parsed from the request. They are available
-# from the #cookies() accessor, which returns a hash from cookie name to
-# CGI::Cookie object.
-#
-# === Multipart requests
-#
-# If a request's method is POST and its content type is multipart/form-data,
-# then it may contain uploaded files. These are stored by the QueryExtension
-# module in the parameters of the request. The parameter name is the name
-# attribute of the file input field, as usual. However, the value is not
-# a string, but an IO object, either an IOString for small files, or a
-# Tempfile for larger ones. This object also has the additional singleton
-# methods:
-#
-# #local_path():: the path of the uploaded file on the local filesystem
-# #original_filename():: the name of the file on the client computer
-# #content_type():: the content type of the file
-#
-# == Responses
-#
-# The CGI class provides methods for sending header and content output to
-# the HTTP client, and mixes in methods for programmatic HTML generation
-# from CGI::HtmlExtension and CGI::TagMaker modules. The precise version of HTML
-# to use for HTML generation is specified at object creation time.
-#
-# === Writing output
-#
-# The simplest way to send output to the HTTP client is using the #out() method.
-# This takes the HTTP headers as a hash parameter, and the body content
-# via a block. The headers can be generated as a string using the #http_header()
-# method. The output stream can be written directly to using the #print()
-# method.
-#
-# === Generating HTML
-#
-# Each HTML element has a corresponding method for generating that
-# element as a String. The name of this method is the same as that
-# of the element, all lowercase. The attributes of the element are
-# passed in as a hash, and the body as a no-argument block that evaluates
-# to a String. The HTML generation module knows which elements are
-# always empty, and silently drops any passed-in body. It also knows
-# which elements require matching closing tags and which don't. However,
-# it does not know what attributes are legal for which elements.
-#
-# There are also some additional HTML generation methods mixed in from
-# the CGI::HtmlExtension module. These include individual methods for the
-# different types of form inputs, and methods for elements that commonly
-# take particular attributes where the attributes can be directly specified
-# as arguments, rather than via a hash.
-#
-# === Utility HTML escape and other methods like a function.
-#
-# There are some utility tool defined in cgi/util.rb .
-# And when include, you can use utility methods like a function.
-#
-# == Examples of use
-#
-# === Get form values
-#
-# require "cgi"
-# cgi = CGI.new
-# value = cgi['field_name'] # <== value string for 'field_name'
-# # if not 'field_name' included, then return "".
-# fields = cgi.keys # <== array of field names
-#
-# # returns true if form has 'field_name'
-# cgi.has_key?('field_name')
-# cgi.has_key?('field_name')
-# cgi.include?('field_name')
-#
-# CAUTION! <code>cgi['field_name']</code> returned an Array with the old
-# cgi.rb(included in Ruby 1.6)
-#
-# === Get form values as hash
-#
-# require "cgi"
-# cgi = CGI.new
-# params = cgi.params
-#
-# cgi.params is a hash.
-#
-# cgi.params['new_field_name'] = ["value"] # add new param
-# cgi.params['field_name'] = ["new_value"] # change value
-# cgi.params.delete('field_name') # delete param
-# cgi.params.clear # delete all params
-#
-#
-# === Save form values to file
-#
-# require "pstore"
-# db = PStore.new("query.db")
-# db.transaction do
-# db["params"] = cgi.params
-# end
-#
-#
-# === Restore form values from file
-#
-# require "pstore"
-# db = PStore.new("query.db")
-# db.transaction do
-# cgi.params = db["params"]
-# end
-#
-#
-# === Get multipart form values
-#
-# require "cgi"
-# cgi = CGI.new
-# value = cgi['field_name'] # <== value string for 'field_name'
-# value.read # <== body of value
-# value.local_path # <== path to local file of value
-# value.original_filename # <== original filename of value
-# value.content_type # <== content_type of value
-#
-# and value has StringIO or Tempfile class methods.
-#
-# === Get cookie values
-#
-# require "cgi"
-# cgi = CGI.new
-# values = cgi.cookies['name'] # <== array of 'name'
-# # if not 'name' included, then return [].
-# names = cgi.cookies.keys # <== array of cookie names
-#
-# and cgi.cookies is a hash.
-#
-# === Get cookie objects
-#
-# require "cgi"
-# cgi = CGI.new
-# for name, cookie in cgi.cookies
-# cookie.expires = Time.now + 30
-# end
-# cgi.out("cookie" => cgi.cookies) {"string"}
-#
-# cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
-#
-# require "cgi"
-# cgi = CGI.new
-# cgi.cookies['name'].expires = Time.now + 30
-# cgi.out("cookie" => cgi.cookies['name']) {"string"}
-#
-# === Print http header and html string to $DEFAULT_OUTPUT ($>)
-#
-# require "cgi"
-# cgi = CGI.new("html4") # add HTML generation methods
-# cgi.out do
-# cgi.html do
-# cgi.head do
-# cgi.title { "TITLE" }
-# end +
-# cgi.body do
-# cgi.form("ACTION" => "uri") do
-# cgi.p do
-# cgi.textarea("get_text") +
-# cgi.br +
-# cgi.submit
-# end
-# end +
-# cgi.pre do
-# CGI.escapeHTML(
-# "params: #{cgi.params.inspect}\n" +
-# "cookies: #{cgi.cookies.inspect}\n" +
-# ENV.collect do |key, value|
-# "#{key} --> #{value}\n"
-# end.join("")
-# )
-# end
-# end
-# end
-# end
-#
-# # add HTML generation methods
-# CGI.new("html3") # html3.2
-# CGI.new("html4") # html4.01 (Strict)
-# CGI.new("html4Tr") # html4.01 Transitional
-# CGI.new("html4Fr") # html4.01 Frameset
-# CGI.new("html5") # html5
-#
-# === Some utility methods
-#
-# require 'cgi/util'
-# CGI.escapeHTML('Usage: foo "bar" <baz>')
-#
-#
-# === Some utility methods like a function
-#
-# require 'cgi/util'
-# include CGI::Util
-# escapeHTML('Usage: foo "bar" <baz>')
-# h('Usage: foo "bar" <baz>') # alias
-#
-#
+require "cgi/escape"
+warn <<-WARNING, uplevel: Gem::BUNDLED_GEMS.uplevel if $VERBOSE
+CGI library is removed from Ruby 4.0. Please use cgi/escape instead for CGI.escape and CGI.unescape features.
-class CGI
- VERSION = "0.4.2"
-end
-
-require 'cgi/core'
-require 'cgi/cookie'
-require 'cgi/util'
-CGI.autoload(:HtmlExtension, 'cgi/html')
+If you need to use the full features of CGI library, please add 'gem "cgi"' to your script
+or use Bundler to ensure you are using the cgi gem instead of this file.
+WARNING
diff --git a/lib/cgi/cgi.gemspec b/lib/cgi/cgi.gemspec
deleted file mode 100644
index 5ef00d591d..0000000000
--- a/lib/cgi/cgi.gemspec
+++ /dev/null
@@ -1,43 +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{Support for the Common Gateway Interface protocol.}
- spec.description = %q{Support for the Common Gateway Interface protocol.}
- spec.homepage = "https://github.com/ruby/cgi"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = ">= 2.5.0"
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- spec.executables = []
-
- spec.files = [
- "COPYING",
- "BSDL",
- "README.md",
- *Dir["lib{.rb,/**/*.rb}", "bin/*"] ]
-
- spec.require_paths = ["lib"]
-
- if Gem::Platform === spec.platform and spec.platform =~ 'java' or RUBY_ENGINE == 'jruby'
- spec.platform = 'java'
- spec.require_paths << "ext/java/org/jruby/ext/cgi/escape/lib"
- spec.files += Dir["ext/java/**/*.{rb}", "lib/cgi/escape.jar"]
- else
- spec.files += Dir["ext/cgi/**/*.{rb,c,h,sh}", "ext/cgi/escape/depend", "lib/cgi/escape.so"]
- spec.extensions = ["ext/cgi/escape/extconf.rb"]
- end
-end
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
deleted file mode 100644
index 1c4ef6a600..0000000000
--- a/lib/cgi/cookie.rb
+++ /dev/null
@@ -1,210 +0,0 @@
-# frozen_string_literal: true
-require_relative 'util'
-class CGI
- # Class representing an HTTP cookie.
- #
- # In addition to its specific fields and methods, a Cookie instance
- # is a delegator to the array of its values.
- #
- # See RFC 2965.
- #
- # == Examples of use
- # cookie1 = CGI::Cookie.new("name", "value1", "value2", ...)
- # cookie1 = CGI::Cookie.new("name" => "name", "value" => "value")
- # cookie1 = CGI::Cookie.new('name' => 'name',
- # 'value' => ['value1', 'value2', ...],
- # 'path' => 'path', # optional
- # 'domain' => 'domain', # optional
- # 'expires' => Time.now, # optional
- # 'secure' => true, # optional
- # 'httponly' => true # optional
- # )
- #
- # cgi.out("cookie" => [cookie1, cookie2]) { "string" }
- #
- # name = cookie1.name
- # values = cookie1.value
- # path = cookie1.path
- # domain = cookie1.domain
- # expires = cookie1.expires
- # secure = cookie1.secure
- # httponly = cookie1.httponly
- #
- # cookie1.name = 'name'
- # cookie1.value = ['value1', 'value2', ...]
- # cookie1.path = 'path'
- # cookie1.domain = 'domain'
- # cookie1.expires = Time.now + 30
- # cookie1.secure = true
- # cookie1.httponly = true
- class Cookie < Array
- @@accept_charset="UTF-8" unless defined?(@@accept_charset)
-
- TOKEN_RE = %r"\A[[!-~]&&[^()<>@,;:\\\"/?=\[\]{}]]+\z"
- PATH_VALUE_RE = %r"\A[[ -~]&&[^;]]*\z"
- DOMAIN_VALUE_RE = %r"\A\.?(?<label>(?!-)[-A-Za-z0-9]+(?<!-))(?:\.\g<label>)*\z"
-
- # Create a new CGI::Cookie object.
- #
- # :call-seq:
- # Cookie.new(name_string,*value)
- # Cookie.new(options_hash)
- #
- # +name_string+::
- # The name of the cookie; in this form, there is no #domain or
- # #expiration. The #path is gleaned from the +SCRIPT_NAME+ environment
- # variable, and #secure is false.
- # <tt>*value</tt>::
- # value or list of values of the cookie
- # +options_hash+::
- # A Hash of options to initialize this Cookie. Possible options are:
- #
- # name:: the name of the cookie. Required.
- # value:: the cookie's value or list of values.
- # path:: the path for which this cookie applies. Defaults to
- # the value of the +SCRIPT_NAME+ environment variable.
- # domain:: the domain for which this cookie applies.
- # expires:: the time at which this cookie expires, as a +Time+ object.
- # secure:: whether this cookie is a secure cookie or not (default to
- # false). Secure cookies are only transmitted to HTTPS
- # servers.
- # httponly:: whether this cookie is a HttpOnly cookie or not (default to
- # false). HttpOnly cookies are not available to javascript.
- #
- # These keywords correspond to attributes of the cookie object.
- def initialize(name = "", *value)
- @domain = nil
- @expires = nil
- if name.kind_of?(String)
- self.name = name
- self.path = (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "")
- @secure = false
- @httponly = false
- return super(value)
- end
-
- options = name
- unless options.has_key?("name")
- raise ArgumentError, "`name' required"
- end
-
- self.name = options["name"]
- value = Array(options["value"])
- # simple support for IE
- self.path = options["path"] || (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "")
- self.domain = options["domain"]
- @expires = options["expires"]
- @secure = options["secure"] == true
- @httponly = options["httponly"] == true
-
- super(value)
- end
-
- # Name of this cookie, as a +String+
- attr_reader :name
- # Set name of this cookie
- def name=(str)
- if str and !TOKEN_RE.match?(str)
- raise ArgumentError, "invalid name: #{str.dump}"
- end
- @name = str
- end
-
- # Path for which this cookie applies, as a +String+
- attr_reader :path
- # Set path for which this cookie applies
- def path=(str)
- if str and !PATH_VALUE_RE.match?(str)
- raise ArgumentError, "invalid path: #{str.dump}"
- end
- @path = str
- end
-
- # Domain for which this cookie applies, as a +String+
- attr_reader :domain
- # Set domain for which this cookie applies
- def domain=(str)
- if str and ((str = str.b).bytesize > 255 or !DOMAIN_VALUE_RE.match?(str))
- raise ArgumentError, "invalid domain: #{str.dump}"
- end
- @domain = str
- end
-
- # Time at which this cookie expires, as a +Time+
- attr_accessor :expires
- # True if this cookie is secure; false otherwise
- attr_reader :secure
- # True if this cookie is httponly; false otherwise
- attr_reader :httponly
-
- # Returns the value or list of values for this cookie.
- def value
- self
- end
-
- # Replaces the value of this cookie with a new value or list of values.
- def value=(val)
- replace(Array(val))
- end
-
- # Set whether the Cookie is a secure cookie or not.
- #
- # +val+ must be a boolean.
- def secure=(val)
- @secure = val if val == true or val == false
- @secure
- end
-
- # Set whether the Cookie is a httponly cookie or not.
- #
- # +val+ must be a boolean.
- def httponly=(val)
- @httponly = !!val
- end
-
- # Convert the Cookie to its string representation.
- def to_s
- val = collect{|v| CGI.escape(v) }.join("&")
- buf = "#{@name}=#{val}".dup
- buf << "; domain=#{@domain}" if @domain
- buf << "; path=#{@path}" if @path
- buf << "; expires=#{CGI.rfc1123_date(@expires)}" if @expires
- buf << "; secure" if @secure
- buf << "; HttpOnly" if @httponly
- buf
- end
-
- # Parse a raw cookie string into a hash of cookie-name=>Cookie
- # pairs.
- #
- # cookies = CGI::Cookie.parse("raw_cookie_string")
- # # { "name1" => cookie1, "name2" => cookie2, ... }
- #
- def self.parse(raw_cookie)
- cookies = Hash.new([])
- return cookies unless raw_cookie
-
- raw_cookie.split(/;\s?/).each do |pairs|
- name, values = pairs.split('=',2)
- next unless name and values
- 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)
- end
- end
-
- cookies
- end
-
- # A summary of cookie string.
- def inspect
- "#<CGI::Cookie: #{self.to_s.inspect}>"
- end
-
- end # class Cookie
-end
-
-
diff --git a/lib/cgi/core.rb b/lib/cgi/core.rb
deleted file mode 100644
index 62e606837a..0000000000
--- a/lib/cgi/core.rb
+++ /dev/null
@@ -1,900 +0,0 @@
-# frozen_string_literal: true
-#--
-# Methods for generating HTML, parsing CGI-related parameters, and
-# generating HTTP responses.
-#++
-class CGI
- unless const_defined?(:Util)
- module Util
- @@accept_charset = "UTF-8" # :nodoc:
- end
- include Util
- extend Util
- end
-
- $CGI_ENV = ENV # for FCGI support
-
- # String for carriage return
- CR = "\015"
-
- # String for linefeed
- LF = "\012"
-
- # Standard internet newline sequence
- EOL = CR + LF
-
- REVISION = '$Id$' #:nodoc:
-
- # Whether processing will be required in binary vs text
- NEEDS_BINMODE = File::BINARY != 0
-
- # Path separators in different environments.
- PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
-
- # HTTP status codes.
- HTTP_STATUS = {
- "OK" => "200 OK",
- "PARTIAL_CONTENT" => "206 Partial Content",
- "MULTIPLE_CHOICES" => "300 Multiple Choices",
- "MOVED" => "301 Moved Permanently",
- "REDIRECT" => "302 Found",
- "NOT_MODIFIED" => "304 Not Modified",
- "BAD_REQUEST" => "400 Bad Request",
- "AUTH_REQUIRED" => "401 Authorization Required",
- "FORBIDDEN" => "403 Forbidden",
- "NOT_FOUND" => "404 Not Found",
- "METHOD_NOT_ALLOWED" => "405 Method Not Allowed",
- "NOT_ACCEPTABLE" => "406 Not Acceptable",
- "LENGTH_REQUIRED" => "411 Length Required",
- "PRECONDITION_FAILED" => "412 Precondition Failed",
- "SERVER_ERROR" => "500 Internal Server Error",
- "NOT_IMPLEMENTED" => "501 Method Not Implemented",
- "BAD_GATEWAY" => "502 Bad Gateway",
- "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
- }
-
- # :startdoc:
-
- # Synonym for ENV.
- def env_table
- ENV
- end
-
- # Synonym for $stdin.
- def stdinput
- $stdin
- end
-
- # Synonym for $stdout.
- def stdoutput
- $stdout
- end
-
- private :env_table, :stdinput, :stdoutput
-
- # Create an HTTP header block as a string.
- #
- # :call-seq:
- # http_header(content_type_string="text/html")
- # http_header(headers_hash)
- #
- # Includes the empty line that ends the header block.
- #
- # +content_type_string+::
- # If this form is used, this string is the <tt>Content-Type</tt>
- # +headers_hash+::
- # A Hash of header values. The following header keys are recognized:
- #
- # type:: The Content-Type header. Defaults to "text/html"
- # charset:: The charset of the body, appended to the Content-Type header.
- # nph:: A boolean value. If true, prepend protocol string and status
- # code, and date; and sets default values for "server" and
- # "connection" if not explicitly set.
- # status::
- # The HTTP status code as a String, returned as the Status header. The
- # values are:
- #
- # OK:: 200 OK
- # PARTIAL_CONTENT:: 206 Partial Content
- # MULTIPLE_CHOICES:: 300 Multiple Choices
- # MOVED:: 301 Moved Permanently
- # REDIRECT:: 302 Found
- # NOT_MODIFIED:: 304 Not Modified
- # BAD_REQUEST:: 400 Bad Request
- # AUTH_REQUIRED:: 401 Authorization Required
- # FORBIDDEN:: 403 Forbidden
- # NOT_FOUND:: 404 Not Found
- # METHOD_NOT_ALLOWED:: 405 Method Not Allowed
- # NOT_ACCEPTABLE:: 406 Not Acceptable
- # LENGTH_REQUIRED:: 411 Length Required
- # PRECONDITION_FAILED:: 412 Precondition Failed
- # SERVER_ERROR:: 500 Internal Server Error
- # NOT_IMPLEMENTED:: 501 Method Not Implemented
- # BAD_GATEWAY:: 502 Bad Gateway
- # VARIANT_ALSO_VARIES:: 506 Variant Also Negotiates
- #
- # server:: The server software, returned as the Server header.
- # connection:: The connection type, returned as the Connection header (for
- # instance, "close".
- # length:: The length of the content that will be sent, returned as the
- # Content-Length header.
- # language:: The language of the content, returned as the Content-Language
- # header.
- # expires:: The time on which the current content expires, as a +Time+
- # object, returned as the Expires header.
- # cookie::
- # A cookie or cookies, returned as one or more Set-Cookie headers. The
- # value can be the literal string of the cookie; a CGI::Cookie object;
- # an Array of literal cookie strings or Cookie objects; or a hash all of
- # whose values are literal cookie strings or Cookie objects.
- #
- # These cookies are in addition to the cookies held in the
- # @output_cookies field.
- #
- # Other headers can also be set; they are appended as key: value.
- #
- # Examples:
- #
- # http_header
- # # Content-Type: text/html
- #
- # http_header("text/plain")
- # # Content-Type: text/plain
- #
- # http_header("nph" => true,
- # "status" => "OK", # == "200 OK"
- # # "status" => "200 GOOD",
- # "server" => ENV['SERVER_SOFTWARE'],
- # "connection" => "close",
- # "type" => "text/html",
- # "charset" => "iso-2022-jp",
- # # Content-Type: text/html; charset=iso-2022-jp
- # "length" => 103,
- # "language" => "ja",
- # "expires" => Time.now + 30,
- # "cookie" => [cookie1, cookie2],
- # "my_header1" => "my_value",
- # "my_header2" => "my_value")
- #
- # This method does not perform charset conversion.
- def http_header(options='text/html')
- if options.is_a?(String)
- content_type = options
- buf = _header_for_string(content_type)
- elsif options.is_a?(Hash)
- if options.size == 1 && options.has_key?('type')
- content_type = options['type']
- buf = _header_for_string(content_type)
- else
- buf = _header_for_hash(options.dup)
- end
- else
- raise ArgumentError.new("expected String or Hash but got #{options.class}")
- end
- if defined?(MOD_RUBY)
- _header_for_modruby(buf)
- return ''
- else
- buf << EOL # empty line of separator
- return buf
- end
- end # http_header()
-
- # This method is an alias for #http_header, when HTML5 tag maker is inactive.
- #
- # NOTE: use #http_header to create HTTP header blocks, this alias is only
- # provided for backwards compatibility.
- #
- # Using #header with the HTML5 tag maker will create a <header> element.
- alias :header :http_header
-
- def _no_crlf_check(str)
- if str
- str = str.to_s
- raise "A HTTP status or header field must not include CR and LF" if str =~ /[\r\n]/
- str
- else
- nil
- end
- end
- private :_no_crlf_check
-
- def _header_for_string(content_type) #:nodoc:
- buf = ''.dup
- if nph?()
- buf << "#{_no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'} 200 OK#{EOL}"
- buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}"
- buf << "Server: #{_no_crlf_check($CGI_ENV['SERVER_SOFTWARE'])}#{EOL}"
- buf << "Connection: close#{EOL}"
- end
- buf << "Content-Type: #{_no_crlf_check(content_type)}#{EOL}"
- if @output_cookies
- @output_cookies.each {|cookie| buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" }
- end
- return buf
- end # _header_for_string
- private :_header_for_string
-
- def _header_for_hash(options) #:nodoc:
- buf = ''.dup
- ## add charset to option['type']
- options['type'] ||= 'text/html'
- charset = options.delete('charset')
- options['type'] += "; charset=#{charset}" if charset
- ## NPH
- options.delete('nph') if defined?(MOD_RUBY)
- if options.delete('nph') || nph?()
- protocol = _no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'
- status = options.delete('status')
- status = HTTP_STATUS[status] || _no_crlf_check(status) || '200 OK'
- buf << "#{protocol} #{status}#{EOL}"
- buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}"
- options['server'] ||= $CGI_ENV['SERVER_SOFTWARE'] || ''
- options['connection'] ||= 'close'
- end
- ## common headers
- status = options.delete('status')
- buf << "Status: #{HTTP_STATUS[status] || _no_crlf_check(status)}#{EOL}" if status
- server = options.delete('server')
- buf << "Server: #{_no_crlf_check(server)}#{EOL}" if server
- connection = options.delete('connection')
- buf << "Connection: #{_no_crlf_check(connection)}#{EOL}" if connection
- type = options.delete('type')
- buf << "Content-Type: #{_no_crlf_check(type)}#{EOL}" #if type
- length = options.delete('length')
- buf << "Content-Length: #{_no_crlf_check(length)}#{EOL}" if length
- language = options.delete('language')
- buf << "Content-Language: #{_no_crlf_check(language)}#{EOL}" if language
- expires = options.delete('expires')
- buf << "Expires: #{CGI.rfc1123_date(expires)}#{EOL}" if expires
- ## cookie
- if cookie = options.delete('cookie')
- case cookie
- when String, Cookie
- buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}"
- when Array
- arr = cookie
- arr.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" }
- when Hash
- hash = cookie
- hash.each_value {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" }
- end
- end
- if @output_cookies
- @output_cookies.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" }
- end
- ## other headers
- options.each do |key, value|
- buf << "#{_no_crlf_check(key)}: #{_no_crlf_check(value)}#{EOL}"
- end
- return buf
- end # _header_for_hash
- private :_header_for_hash
-
- def nph? #:nodoc:
- return /IIS\/(\d+)/ =~ $CGI_ENV['SERVER_SOFTWARE'] && $1.to_i < 5
- end
-
- def _header_for_modruby(buf) #:nodoc:
- request = Apache::request
- buf.scan(/([^:]+): (.+)#{EOL}/o) do |name, value|
- $stderr.printf("name:%s value:%s\n", name, value) if $DEBUG
- case name
- when 'Set-Cookie'
- request.headers_out.add(name, value)
- when /^status$/i
- request.status_line = value
- request.status = value.to_i
- when /^content-type$/i
- request.content_type = value
- when /^content-encoding$/i
- request.content_encoding = value
- when /^location$/i
- request.status = 302 if request.status == 200
- request.headers_out[name] = value
- else
- request.headers_out[name] = value
- end
- end
- request.send_http_header
- return ''
- end
- private :_header_for_modruby
-
- # Print an HTTP header and body to $DEFAULT_OUTPUT ($>)
- #
- # :call-seq:
- # cgi.out(content_type_string='text/html')
- # cgi.out(headers_hash)
- #
- # +content_type_string+::
- # If a string is passed, it is assumed to be the content type.
- # +headers_hash+::
- # This is a Hash of headers, similar to that used by #http_header.
- # +block+::
- # A block is required and should evaluate to the body of the response.
- #
- # <tt>Content-Length</tt> is automatically calculated from the size of
- # the String returned by the content block.
- #
- # If <tt>ENV['REQUEST_METHOD'] == "HEAD"</tt>, then only the header
- # is output (the content block is still required, but it is ignored).
- #
- # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then the
- # content is converted to this charset, and the language is set to "ja".
- #
- # Example:
- #
- # cgi = CGI.new
- # cgi.out{ "string" }
- # # Content-Type: text/html
- # # Content-Length: 6
- # #
- # # string
- #
- # cgi.out("text/plain") { "string" }
- # # Content-Type: text/plain
- # # Content-Length: 6
- # #
- # # string
- #
- # cgi.out("nph" => true,
- # "status" => "OK", # == "200 OK"
- # "server" => ENV['SERVER_SOFTWARE'],
- # "connection" => "close",
- # "type" => "text/html",
- # "charset" => "iso-2022-jp",
- # # Content-Type: text/html; charset=iso-2022-jp
- # "language" => "ja",
- # "expires" => Time.now + (3600 * 24 * 30),
- # "cookie" => [cookie1, cookie2],
- # "my_header1" => "my_value",
- # "my_header2" => "my_value") { "string" }
- # # HTTP/1.1 200 OK
- # # Date: Sun, 15 May 2011 17:35:54 GMT
- # # Server: Apache 2.2.0
- # # Connection: close
- # # Content-Type: text/html; charset=iso-2022-jp
- # # Content-Length: 6
- # # Content-Language: ja
- # # Expires: Tue, 14 Jun 2011 17:35:54 GMT
- # # Set-Cookie: foo
- # # Set-Cookie: bar
- # # my_header1: my_value
- # # my_header2: my_value
- # #
- # # string
- def out(options = "text/html") # :yield:
-
- options = { "type" => options } if options.kind_of?(String)
- content = yield
- options["length"] = content.bytesize.to_s
- output = stdoutput
- output.binmode if defined? output.binmode
- output.print http_header(options)
- output.print content unless "HEAD" == env_table['REQUEST_METHOD']
- end
-
-
- # Print an argument or list of arguments to the default output stream
- #
- # cgi = CGI.new
- # cgi.print # default: cgi.print == $DEFAULT_OUTPUT.print
- def print(*options)
- stdoutput.print(*options)
- end
-
- # Parse an HTTP query string into a hash of key=>value pairs.
- #
- # params = CGI.parse("query_string")
- # # {"name1" => ["value1", "value2", ...],
- # # "name2" => ["value1", "value2", ...], ... }
- #
- def self.parse(query)
- params = {}
- query.split(/[&;]/).each do |pairs|
- key, value = pairs.split('=',2).collect{|v| CGI.unescape(v) }
-
- next unless key
-
- params[key] ||= []
- params[key].push(value) if value
- end
-
- params.default=[].freeze
- params
- end
-
- # Maximum content length of post data
- ##MAX_CONTENT_LENGTH = 2 * 1024 * 1024
-
- # Maximum number of request parameters when multipart
- MAX_MULTIPART_COUNT = 128
-
- # Mixin module that provides the following:
- #
- # 1. Access to the CGI environment variables as methods. See
- # documentation to the CGI class for a list of these variables. The
- # methods are exposed by removing the leading +HTTP_+ (if it exists) and
- # downcasing the name. For example, +auth_type+ will return the
- # environment variable +AUTH_TYPE+, and +accept+ will return the value
- # for +HTTP_ACCEPT+.
- #
- # 2. Access to cookies, including the cookies attribute.
- #
- # 3. Access to parameters, including the params attribute, and overloading
- # #[] to perform parameter value lookup by key.
- #
- # 4. The initialize_query method, for initializing the above
- # mechanisms, handling multipart forms, and allowing the
- # class to be used in "offline" mode.
- #
- module QueryExtension
-
- %w[ CONTENT_LENGTH SERVER_PORT ].each do |env|
- define_method(env.delete_prefix('HTTP_').downcase) do
- (val = env_table[env]) && Integer(val)
- end
- end
-
- %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
- PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
- REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
- SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
-
- HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
- HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
- HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
- define_method(env.delete_prefix('HTTP_').downcase) do
- env_table[env]
- end
- end
-
- # Get the raw cookies as a string.
- def raw_cookie
- env_table["HTTP_COOKIE"]
- end
-
- # Get the raw RFC2965 cookies as a string.
- def raw_cookie2
- env_table["HTTP_COOKIE2"]
- end
-
- # Get the cookies as a hash of cookie-name=>Cookie pairs.
- attr_accessor :cookies
-
- # Get the parameters as a hash of name=>values pairs, where
- # values is an Array.
- attr_reader :params
-
- # Get the uploaded files as a hash of name=>values pairs
- attr_reader :files
-
- # Set all the parameters.
- def params=(hash)
- @params.clear
- @params.update(hash)
- end
-
- ##
- # Parses multipart form elements according to
- # http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
- #
- # Returns a hash of multipart form parameters with bodies of type StringIO or
- # Tempfile depending on whether the multipart form element exceeds 10 KB
- #
- # params[name => body]
- #
- def read_multipart(boundary, content_length)
- ## read first boundary
- stdin = stdinput
- first_line = "--#{boundary}#{EOL}"
- content_length -= first_line.bytesize
- status = stdin.read(first_line.bytesize)
- raise EOFError.new("no content body") unless status
- raise EOFError.new("bad content body") unless first_line == status
- ## parse and set params
- params = {}
- @files = {}
- boundary_rexp = /--#{Regexp.quote(boundary)}(#{EOL}|--)/
- boundary_size = "#{EOL}--#{boundary}#{EOL}".bytesize
- buf = ''.dup
- bufsize = 10 * 1024
- max_count = MAX_MULTIPART_COUNT
- n = 0
- tempfiles = []
- while true
- (n += 1) < max_count or raise StandardError.new("too many parameters.")
- ## create body (StringIO or Tempfile)
- body = create_body(bufsize < content_length)
- tempfiles << body if defined?(Tempfile) && body.kind_of?(Tempfile)
- class << body
- if method_defined?(:path)
- alias local_path path
- else
- def local_path
- nil
- end
- end
- attr_reader :original_filename, :content_type
- end
- ## find head and boundary
- head = nil
- separator = EOL * 2
- until head && matched = boundary_rexp.match(buf)
- if !head && pos = buf.index(separator)
- len = pos + EOL.bytesize
- head = buf[0, len]
- buf = buf[(pos+separator.bytesize)..-1]
- else
- if head && buf.size > boundary_size
- len = buf.size - boundary_size
- body.print(buf[0, len])
- buf[0, len] = ''
- end
- c = stdin.read(bufsize < content_length ? bufsize : content_length)
- raise EOFError.new("bad content body") if c.nil? || c.empty?
- buf << c
- content_length -= c.bytesize
- end
- end
- ## read to end of boundary
- m = matched
- len = m.begin(0)
- s = buf[0, len]
- if s =~ /(\r?\n)\z/
- s = buf[0, len - $1.bytesize]
- end
- body.print(s)
- buf = buf[m.end(0)..-1]
- boundary_end = m[1]
- content_length = -1 if boundary_end == '--'
- ## reset file cursor position
- body.rewind
- ## original filename
- /Content-Disposition:.* filename=(?:"(.*?)"|([^;\r\n]*))/i.match(head)
- filename = $1 || $2 || ''.dup
- filename = CGI.unescape(filename) if unescape_filename?()
- body.instance_variable_set(:@original_filename, filename)
- ## content type
- /Content-Type: (.*)/i.match(head)
- (content_type = $1 || ''.dup).chomp!
- body.instance_variable_set(:@content_type, content_type)
- ## query parameter name
- /Content-Disposition:.* name=(?:"(.*?)"|([^;\r\n]*))/i.match(head)
- name = $1 || $2 || ''
- if body.original_filename.empty?
- value=body.read.dup.force_encoding(@accept_charset)
- body.close! if defined?(Tempfile) && body.kind_of?(Tempfile)
- (params[name] ||= []) << value
- unless value.valid_encoding?
- if @accept_charset_error_block
- @accept_charset_error_block.call(name,value)
- else
- raise InvalidEncoding,"Accept-Charset encoding error"
- end
- end
- class << params[name].last;self;end.class_eval do
- define_method(:read){self}
- define_method(:original_filename){""}
- define_method(:content_type){""}
- end
- else
- (params[name] ||= []) << body
- @files[name]=body
- end
- ## break loop
- break if content_length == -1
- end
- raise EOFError, "bad boundary end of body part" unless boundary_end =~ /--/
- params.default = []
- params
- rescue Exception
- if tempfiles
- tempfiles.each {|t|
- if t.path
- t.close!
- end
- }
- end
- raise
- end # read_multipart
- private :read_multipart
- def create_body(is_large) #:nodoc:
- if is_large
- require 'tempfile'
- body = Tempfile.new('CGI', encoding: Encoding::ASCII_8BIT)
- else
- begin
- require 'stringio'
- body = StringIO.new("".b)
- rescue LoadError
- require 'tempfile'
- body = Tempfile.new('CGI', encoding: Encoding::ASCII_8BIT)
- end
- end
- body.binmode if defined? body.binmode
- return body
- end
- def unescape_filename? #:nodoc:
- user_agent = $CGI_ENV['HTTP_USER_AGENT']
- return false unless user_agent
- return /Mac/i.match(user_agent) && /Mozilla/i.match(user_agent) && !/MSIE/i.match(user_agent)
- end
-
- # offline mode. read name=value pairs on standard input.
- def read_from_cmdline
- require "shellwords"
-
- string = unless ARGV.empty?
- ARGV.join(' ')
- else
- if STDIN.tty?
- STDERR.print(
- %|(offline mode: enter name=value pairs on standard input)\n|
- )
- end
- array = readlines rescue nil
- if not array.nil?
- array.join(' ').gsub(/\n/n, '')
- else
- ""
- end
- end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
-
- words = Shellwords.shellwords(string)
-
- if words.find{|x| /=/n.match(x) }
- words.join('&')
- else
- words.join('+')
- end
- end
- private :read_from_cmdline
-
- # A wrapper class to use a StringIO object as the body and switch
- # to a TempFile when the passed threshold is passed.
- # Initialize the data from the query.
- #
- # Handles multipart forms (in particular, forms that involve file uploads).
- # Reads query parameters in the @params field, and cookies into @cookies.
- def initialize_query()
- if ("POST" == env_table['REQUEST_METHOD']) and
- %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?| =~ env_table['CONTENT_TYPE']
- current_max_multipart_length = @max_multipart_length.respond_to?(:call) ? @max_multipart_length.call : @max_multipart_length
- raise StandardError.new("too large multipart data.") if env_table['CONTENT_LENGTH'].to_i > current_max_multipart_length
- boundary = $1.dup
- @multipart = true
- @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
- else
- @multipart = false
- @params = CGI.parse(
- case env_table['REQUEST_METHOD']
- when "GET", "HEAD"
- if defined?(MOD_RUBY)
- Apache::request.args or ""
- else
- env_table['QUERY_STRING'] or ""
- end
- when "POST"
- stdinput.binmode if defined? stdinput.binmode
- stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
- else
- read_from_cmdline
- end.dup.force_encoding(@accept_charset)
- )
- unless Encoding.find(@accept_charset) == Encoding::ASCII_8BIT
- @params.each do |key,values|
- values.each do |value|
- unless value.valid_encoding?
- if @accept_charset_error_block
- @accept_charset_error_block.call(key,value)
- else
- raise InvalidEncoding,"Accept-Charset encoding error"
- end
- end
- end
- end
- end
- end
-
- @cookies = CGI::Cookie.parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
- end
- private :initialize_query
-
- # Returns whether the form contained multipart/form-data
- def multipart?
- @multipart
- end
-
- # Get the value for the parameter with a given key.
- #
- # If the parameter has multiple values, only the first will be
- # retrieved; use #params to get the array of values.
- def [](key)
- params = @params[key]
- return '' unless params
- value = params[0]
- if @multipart
- if value
- return value
- elsif defined? StringIO
- StringIO.new("".b)
- else
- Tempfile.new("CGI",encoding: Encoding::ASCII_8BIT)
- end
- else
- str = if value then value.dup else "" end
- str
- end
- end
-
- # Return all query parameter names as an array of String.
- def keys(*args)
- @params.keys(*args)
- end
-
- # Returns true if a given query string parameter exists.
- def has_key?(*args)
- @params.has_key?(*args)
- end
- alias key? has_key?
- alias include? has_key?
-
- end # QueryExtension
-
- # Exception raised when there is an invalid encoding detected
- class InvalidEncoding < Exception; end
-
- # @@accept_charset is default accept character set.
- # This default value default is "UTF-8"
- # If you want to change the default accept character set
- # when create a new CGI instance, set this:
- #
- # CGI.accept_charset = "EUC-JP"
- #
- @@accept_charset="UTF-8" if false # needed for rdoc?
-
- # Return the accept character set for all new CGI instances.
- def self.accept_charset
- @@accept_charset
- end
-
- # Set the accept character set for all new CGI instances.
- def self.accept_charset=(accept_charset)
- @@accept_charset=accept_charset
- end
-
- # Return the accept character set for this CGI instance.
- attr_reader :accept_charset
-
- # @@max_multipart_length is the maximum length of multipart data.
- # The default value is 128 * 1024 * 1024 bytes
- #
- # The default can be set to something else in the CGI constructor,
- # via the :max_multipart_length key in the option hash.
- #
- # See CGI.new documentation.
- #
- @@max_multipart_length= 128 * 1024 * 1024
-
- # Create a new CGI instance.
- #
- # :call-seq:
- # CGI.new(tag_maker) { block }
- # CGI.new(options_hash = {}) { block }
- #
- #
- # <tt>tag_maker</tt>::
- # This is the same as using the +options_hash+ form with the value <tt>{
- # :tag_maker => tag_maker }</tt> Note that it is recommended to use the
- # +options_hash+ form, since it also allows you specify the charset you
- # will accept.
- # <tt>options_hash</tt>::
- # A Hash that recognizes three options:
- #
- # <tt>:accept_charset</tt>::
- # specifies encoding of received query string. If omitted,
- # <tt>@@accept_charset</tt> is used. If the encoding is not valid, a
- # CGI::InvalidEncoding will be raised.
- #
- # Example. Suppose <tt>@@accept_charset</tt> is "UTF-8"
- #
- # when not specified:
- #
- # cgi=CGI.new # @accept_charset # => "UTF-8"
- #
- # when specified as "EUC-JP":
- #
- # cgi=CGI.new(:accept_charset => "EUC-JP") # => "EUC-JP"
- #
- # <tt>:tag_maker</tt>::
- # String that specifies which version of the HTML generation methods to
- # use. If not specified, no HTML generation methods will be loaded.
- #
- # The following values are supported:
- #
- # "html3":: HTML 3.x
- # "html4":: HTML 4.0
- # "html4Tr":: HTML 4.0 Transitional
- # "html4Fr":: HTML 4.0 with Framesets
- # "html5":: HTML 5
- #
- # <tt>:max_multipart_length</tt>::
- # Specifies maximum length of multipart data. Can be an Integer scalar or
- # a lambda, that will be evaluated when the request is parsed. This
- # allows more complex logic to be set when determining whether to accept
- # multipart data (e.g. consult a registered users upload allowance)
- #
- # Default is 128 * 1024 * 1024 bytes
- #
- # cgi=CGI.new(:max_multipart_length => 268435456) # simple scalar
- #
- # cgi=CGI.new(:max_multipart_length => -> {check_filesystem}) # lambda
- #
- # <tt>block</tt>::
- # If provided, the block is called when an invalid encoding is
- # encountered. For example:
- #
- # encoding_errors={}
- # cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value|
- # encoding_errors[name] = value
- # end
- #
- # Finally, if the CGI object is not created in a standard CGI call
- # environment (that is, it can't locate REQUEST_METHOD in its environment),
- # then it will run in "offline" mode. In this mode, it reads its parameters
- # from the command line or (failing that) from standard input. Otherwise,
- # cookies and other parameters are parsed automatically from the standard
- # CGI locations, which varies according to the REQUEST_METHOD.
- def initialize(options = {}, &block) # :yields: name, value
- @accept_charset_error_block = block_given? ? block : nil
- @options={
- :accept_charset=>@@accept_charset,
- :max_multipart_length=>@@max_multipart_length
- }
- case options
- when Hash
- @options.merge!(options)
- when String
- @options[:tag_maker]=options
- end
- @accept_charset=@options[:accept_charset]
- @max_multipart_length=@options[:max_multipart_length]
- if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
- Apache.request.setup_cgi_env
- end
-
- extend QueryExtension
- @multipart = false
-
- initialize_query() # set @params, @cookies
- @output_cookies = nil
- @output_hidden = nil
-
- case @options[:tag_maker]
- when "html3"
- require_relative 'html'
- extend Html3
- extend HtmlExtension
- when "html4"
- require_relative 'html'
- extend Html4
- extend HtmlExtension
- when "html4Tr"
- require_relative 'html'
- extend Html4Tr
- extend HtmlExtension
- when "html4Fr"
- require_relative 'html'
- extend Html4Tr
- extend Html4Fr
- extend HtmlExtension
- when "html5"
- require_relative 'html'
- extend Html5
- extend HtmlExtension
- end
- end
-
-end # class CGI
diff --git a/lib/cgi/escape.rb b/lib/cgi/escape.rb
new file mode 100644
index 0000000000..555d24a5da
--- /dev/null
+++ b/lib/cgi/escape.rb
@@ -0,0 +1,232 @@
+# frozen_string_literal: true
+
+# Since Ruby 4.0, \CGI is a small holder for various escaping methods, included from CGI::Escape
+#
+# require 'cgi/escape'
+#
+# CGI.escape("Ruby programming language")
+# #=> "Ruby+programming+language"
+# CGI.escapeURIComponent("Ruby programming language")
+# #=> "Ruby%20programming%20language"
+#
+# See CGI::Escape module for methods list and their description.
+class CGI
+ module Escape; end
+ include Escape
+ extend Escape
+ module EscapeExt; end # :nodoc:
+end
+
+# Web-related escape/unescape functionality.
+module CGI::Escape
+ @@accept_charset = Encoding::UTF_8 unless defined?(@@accept_charset)
+
+ # URL-encode a string into application/x-www-form-urlencoded.
+ # Space characters (<tt>" "</tt>) are encoded with plus signs (<tt>"+"</tt>)
+ # url_encoded_string = CGI.escape("'Stop!' said Fred")
+ # # => "%27Stop%21%27+said+Fred"
+ def escape(string)
+ encoding = string.encoding
+ buffer = string.b
+ buffer.gsub!(/([^ a-zA-Z0-9_.\-~]+)/) do |m|
+ '%' + m.unpack('H2' * m.bytesize).join('%').upcase
+ end
+ buffer.tr!(' ', '+')
+ buffer.force_encoding(encoding)
+ end
+
+ # URL-decode an application/x-www-form-urlencoded string with encoding(optional).
+ # string = CGI.unescape("%27Stop%21%27+said+Fred")
+ # # => "'Stop!' said Fred"
+ def unescape(string, encoding = @@accept_charset)
+ str = string.tr('+', ' ')
+ str = str.b
+ str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m|
+ [m.delete('%')].pack('H*')
+ end
+ str.force_encoding(encoding)
+ str.valid_encoding? ? str : str.force_encoding(string.encoding)
+ end
+
+ # URL-encode a string following RFC 3986
+ # Space characters (<tt>" "</tt>) are encoded with (<tt>"%20"</tt>)
+ # url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred")
+ # # => "%27Stop%21%27%20said%20Fred"
+ def escapeURIComponent(string)
+ encoding = string.encoding
+ buffer = string.b
+ buffer.gsub!(/([^a-zA-Z0-9_.\-~]+)/) do |m|
+ '%' + m.unpack('H2' * m.bytesize).join('%').upcase
+ 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")
+ # # => "'Stop!'+said Fred"
+ def unescapeURIComponent(string, encoding = @@accept_charset)
+ str = string.b
+ str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m|
+ [m.delete('%')].pack('H*')
+ end
+ str.force_encoding(encoding)
+ 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__ = { # :nodoc:
+ "'" => '&#39;',
+ '&' => '&amp;',
+ '"' => '&quot;',
+ '<' => '&lt;',
+ '>' => '&gt;',
+ }
+
+ # \Escape special characters in HTML, namely <tt>'&\"<></tt>
+ # CGI.escapeHTML('Usage: foo "bar" <baz>')
+ # # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
+ def escapeHTML(string)
+ enc = string.encoding
+ unless enc.ascii_compatible?
+ if enc.dummy?
+ origenc = enc
+ enc = Encoding::Converter.asciicompat_encoding(enc)
+ string = enc ? string.encode(enc) : string.b
+ end
+ table = Hash[TABLE_FOR_ESCAPE_HTML__.map {|pair|pair.map {|s|s.encode(enc)}}]
+ string = string.gsub(/#{"['&\"<>]".encode(enc)}/, table)
+ string.encode!(origenc) if origenc
+ string
+ else
+ string = string.b
+ string.gsub!(/['&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
+ string.force_encoding(enc)
+ end
+ end
+
+ # Unescape a string that has been HTML-escaped
+ # CGI.unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
+ # # => "Usage: foo \"bar\" <baz>"
+ def unescapeHTML(string)
+ enc = string.encoding
+ unless enc.ascii_compatible?
+ if enc.dummy?
+ origenc = enc
+ enc = Encoding::Converter.asciicompat_encoding(enc)
+ string = enc ? string.encode(enc) : string.b
+ end
+ string = string.gsub(Regexp.new('&(apos|amp|quot|gt|lt|#[0-9]+|#x[0-9A-Fa-f]+);'.encode(enc))) do
+ case $1.encode(Encoding::US_ASCII)
+ when 'apos' then "'".encode(enc)
+ when 'amp' then '&'.encode(enc)
+ when 'quot' then '"'.encode(enc)
+ when 'gt' then '>'.encode(enc)
+ when 'lt' then '<'.encode(enc)
+ when /\A#0*(\d+)\z/ then $1.to_i.chr(enc)
+ when /\A#x([0-9a-f]+)\z/i then $1.hex.chr(enc)
+ end
+ end
+ string.encode!(origenc) if origenc
+ return string
+ end
+ return string unless string.include? '&'
+ charlimit = case enc
+ when Encoding::UTF_8; 0x10ffff
+ when Encoding::ISO_8859_1; 256
+ else 128
+ end
+ string = string.b
+ string.gsub!(/&(apos|amp|quot|gt|lt|\#[0-9]+|\#[xX][0-9A-Fa-f]+);/) do
+ match = $1.dup
+ case match
+ when 'apos' then "'"
+ when 'amp' then '&'
+ when 'quot' then '"'
+ when 'gt' then '>'
+ when 'lt' then '<'
+ when /\A#0*(\d+)\z/
+ n = $1.to_i
+ if n < charlimit
+ n.chr(enc)
+ else
+ "&##{$1};"
+ end
+ when /\A#x([0-9a-f]+)\z/i
+ n = $1.hex
+ if n < charlimit
+ n.chr(enc)
+ else
+ "&#x#{$1};"
+ end
+ else
+ "&#{match};"
+ end
+ end
+ string.force_encoding enc
+ end
+
+ alias escape_html escapeHTML
+ alias h escapeHTML
+
+ alias unescape_html unescapeHTML
+
+ # TruffleRuby runs the pure-Ruby variant faster, do not use the C extension there
+ unless RUBY_ENGINE == 'truffleruby'
+ begin
+ require 'cgi/escape.so'
+ rescue LoadError
+ end
+ end
+
+ # \Escape only the tags of certain HTML elements in +string+.
+ #
+ # Takes an element or elements or array of elements. Each element
+ # is specified by the name of the element, without angle brackets.
+ # This matches both the start and the end tag of that element.
+ # The attribute list of the open tag will also be escaped (for
+ # instance, the double-quotes surrounding attribute values).
+ #
+ # print CGI.escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
+ # # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
+ #
+ # print CGI.escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
+ # # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
+ def escapeElement(string, *elements)
+ elements = elements[0] if elements[0].kind_of?(Array)
+ unless elements.empty?
+ string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
+ CGI.escapeHTML($&)
+ end
+ else
+ string
+ end
+ end
+
+ # Undo escaping such as that done by CGI.escapeElement
+ #
+ # print CGI.unescapeElement(
+ # CGI.escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
+ # # "&lt;BR&gt;<A HREF="url"></A>"
+ #
+ # print CGI.unescapeElement(
+ # CGI.escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
+ # # "&lt;BR&gt;<A HREF="url"></A>"
+ 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
+ unescapeHTML($&)
+ end
+ else
+ string
+ end
+ end
+
+ alias escape_element escapeElement
+
+ alias unescape_element unescapeElement
+
+end
diff --git a/lib/cgi/html.rb b/lib/cgi/html.rb
deleted file mode 100644
index 1543943320..0000000000
--- a/lib/cgi/html.rb
+++ /dev/null
@@ -1,1035 +0,0 @@
-# frozen_string_literal: true
-class CGI
- # Base module for HTML-generation mixins.
- #
- # Provides methods for code generation for tags following
- # the various DTD element types.
- module TagMaker # :nodoc:
-
- # Generate code for an element with required start and end tags.
- #
- # - -
- def nn_element(element, attributes = {})
- s = nOE_element(element, attributes)
- if block_given?
- s << yield.to_s
- end
- s << "</#{element.upcase}>"
- end
-
- def nn_element_def(attributes = {}, &block)
- nn_element(__callee__, attributes, &block)
- end
-
- # Generate code for an empty element.
- #
- # - O EMPTY
- def nOE_element(element, attributes = {})
- attributes={attributes=>nil} if attributes.kind_of?(String)
- s = "<#{element.upcase}".dup
- attributes.each do|name, value|
- next unless value
- s << " "
- s << CGI.escapeHTML(name.to_s)
- if value != true
- s << '="'
- s << CGI.escapeHTML(value.to_s)
- s << '"'
- end
- end
- s << ">"
- end
-
- def nOE_element_def(attributes = {}, &block)
- nOE_element(__callee__, attributes, &block)
- end
-
-
- # Generate code for an element for which the end (and possibly the
- # start) tag is optional.
- #
- # O O or - O
- def nO_element(element, attributes = {})
- s = nOE_element(element, attributes)
- if block_given?
- s << yield.to_s
- s << "</#{element.upcase}>"
- end
- s
- end
-
- def nO_element_def(attributes = {}, &block)
- nO_element(__callee__, attributes, &block)
- end
-
- end # TagMaker
-
-
- # Mixin module providing HTML generation methods.
- #
- # For example,
- # cgi.a("http://www.example.com") { "Example" }
- # # => "<A HREF=\"http://www.example.com\">Example</A>"
- #
- # Modules Html3, Html4, etc., contain more basic HTML-generation methods
- # (+#title+, +#h1+, etc.).
- #
- # See class CGI for a detailed example.
- #
- module HtmlExtension
-
-
- # Generate an Anchor element as a string.
- #
- # +href+ can either be a string, giving the URL
- # for the HREF attribute, or it can be a hash of
- # the element's attributes.
- #
- # The body of the element is the string returned by the no-argument
- # block passed in.
- #
- # a("http://www.example.com") { "Example" }
- # # => "<A HREF=\"http://www.example.com\">Example</A>"
- #
- # a("HREF" => "http://www.example.com", "TARGET" => "_top") { "Example" }
- # # => "<A HREF=\"http://www.example.com\" TARGET=\"_top\">Example</A>"
- #
- def a(href = "") # :yield:
- attributes = if href.kind_of?(String)
- { "HREF" => href }
- else
- href
- end
- super(attributes)
- end
-
- # Generate a Document Base URI element as a String.
- #
- # +href+ can either by a string, giving the base URL for the HREF
- # attribute, or it can be a has of the element's attributes.
- #
- # The passed-in no-argument block is ignored.
- #
- # base("http://www.example.com/cgi")
- # # => "<BASE HREF=\"http://www.example.com/cgi\">"
- def base(href = "") # :yield:
- attributes = if href.kind_of?(String)
- { "HREF" => href }
- else
- href
- end
- super(attributes)
- end
-
- # Generate a BlockQuote element as a string.
- #
- # +cite+ can either be a string, give the URI for the source of
- # the quoted text, or a hash, giving all attributes of the element,
- # or it can be omitted, in which case the element has no attributes.
- #
- # The body is provided by the passed-in no-argument block
- #
- # blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
- # #=> "<BLOCKQUOTE CITE=\"http://www.example.com/quotes/foo.html\">Foo!</BLOCKQUOTE>
- def blockquote(cite = {}) # :yield:
- attributes = if cite.kind_of?(String)
- { "CITE" => cite }
- else
- cite
- end
- super(attributes)
- end
-
-
- # Generate a Table Caption element as a string.
- #
- # +align+ can be a string, giving the alignment of the caption
- # (one of top, bottom, left, or right). It can be a hash of
- # all the attributes of the element. Or it can be omitted.
- #
- # The body of the element is provided by the passed-in no-argument block.
- #
- # caption("left") { "Capital Cities" }
- # # => <CAPTION ALIGN=\"left\">Capital Cities</CAPTION>
- def caption(align = {}) # :yield:
- attributes = if align.kind_of?(String)
- { "ALIGN" => align }
- else
- align
- end
- super(attributes)
- end
-
-
- # Generate a Checkbox Input element as a string.
- #
- # The attributes of the element can be specified as three arguments,
- # +name+, +value+, and +checked+. +checked+ is a boolean value;
- # if true, the CHECKED attribute will be included in the element.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # checkbox("name")
- # # = checkbox("NAME" => "name")
- #
- # checkbox("name", "value")
- # # = checkbox("NAME" => "name", "VALUE" => "value")
- #
- # checkbox("name", "value", true)
- # # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true)
- def checkbox(name = "", value = nil, checked = nil)
- attributes = if name.kind_of?(String)
- { "TYPE" => "checkbox", "NAME" => name,
- "VALUE" => value, "CHECKED" => checked }
- else
- name["TYPE"] = "checkbox"
- name
- end
- input(attributes)
- end
-
- # Generate a sequence of checkbox elements, as a String.
- #
- # The checkboxes will all have the same +name+ attribute.
- # Each checkbox is followed by a label.
- # There will be one checkbox for each value. Each value
- # can be specified as a String, which will be used both
- # as the value of the VALUE attribute and as the label
- # for that checkbox. A single-element array has the
- # same effect.
- #
- # Each value can also be specified as a three-element array.
- # The first element is the VALUE attribute; the second is the
- # label; and the third is a boolean specifying whether this
- # checkbox is CHECKED.
- #
- # Each value can also be specified as a two-element
- # array, by omitting either the value element (defaults
- # to the same as the label), or the boolean checked element
- # (defaults to false).
- #
- # checkbox_group("name", "foo", "bar", "baz")
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
- #
- # checkbox_group("name", ["foo"], ["bar", true], "baz")
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
- # # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
- #
- # checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
- # # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
- # # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
- #
- # checkbox_group("NAME" => "name",
- # "VALUES" => ["foo", "bar", "baz"])
- #
- # checkbox_group("NAME" => "name",
- # "VALUES" => [["foo"], ["bar", true], "baz"])
- #
- # checkbox_group("NAME" => "name",
- # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
- def checkbox_group(name = "", *values)
- if name.kind_of?(Hash)
- values = name["VALUES"]
- name = name["NAME"]
- end
- values.collect{|value|
- if value.kind_of?(String)
- checkbox(name, value) + value
- else
- if value[-1] == true || value[-1] == false
- checkbox(name, value[0], value[-1]) +
- value[-2]
- else
- checkbox(name, value[0]) +
- value[-1]
- end
- end
- }.join
- end
-
-
- # Generate an File Upload Input element as a string.
- #
- # The attributes of the element can be specified as three arguments,
- # +name+, +size+, and +maxlength+. +maxlength+ is the maximum length
- # of the file's _name_, not of the file's _contents_.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # See #multipart_form() for forms that include file uploads.
- #
- # file_field("name")
- # # <INPUT TYPE="file" NAME="name" SIZE="20">
- #
- # file_field("name", 40)
- # # <INPUT TYPE="file" NAME="name" SIZE="40">
- #
- # file_field("name", 40, 100)
- # # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
- #
- # file_field("NAME" => "name", "SIZE" => 40)
- # # <INPUT TYPE="file" NAME="name" SIZE="40">
- def file_field(name = "", size = 20, maxlength = nil)
- attributes = if name.kind_of?(String)
- { "TYPE" => "file", "NAME" => name,
- "SIZE" => size.to_s }
- else
- name["TYPE"] = "file"
- name
- end
- attributes["MAXLENGTH"] = maxlength.to_s if maxlength
- input(attributes)
- end
-
-
- # Generate a Form element as a string.
- #
- # +method+ should be either "get" or "post", and defaults to the latter.
- # +action+ defaults to the current CGI script name. +enctype+
- # defaults to "application/x-www-form-urlencoded".
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # See also #multipart_form() for forms that include file uploads.
- #
- # form{ "string" }
- # # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
- #
- # form("get") { "string" }
- # # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
- #
- # form("get", "url") { "string" }
- # # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
- #
- # form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" }
- # # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
- def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
- attributes = if method.kind_of?(String)
- { "METHOD" => method, "ACTION" => action,
- "ENCTYPE" => enctype }
- else
- unless method.has_key?("METHOD")
- method["METHOD"] = "post"
- end
- unless method.has_key?("ENCTYPE")
- method["ENCTYPE"] = enctype
- end
- method
- end
- if block_given?
- body = yield
- else
- body = ""
- end
- if @output_hidden
- body << @output_hidden.collect{|k,v|
- "<INPUT TYPE=\"HIDDEN\" NAME=\"#{k}\" VALUE=\"#{v}\">"
- }.join
- end
- super(attributes){body}
- end
-
- # Generate a Hidden Input element as a string.
- #
- # The attributes of the element can be specified as two arguments,
- # +name+ and +value+.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # hidden("name")
- # # <INPUT TYPE="hidden" NAME="name">
- #
- # hidden("name", "value")
- # # <INPUT TYPE="hidden" NAME="name" VALUE="value">
- #
- # hidden("NAME" => "name", "VALUE" => "reset", "ID" => "foo")
- # # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
- def hidden(name = "", value = nil)
- attributes = if name.kind_of?(String)
- { "TYPE" => "hidden", "NAME" => name, "VALUE" => value }
- else
- name["TYPE"] = "hidden"
- name
- end
- input(attributes)
- end
-
- # Generate a top-level HTML element as a string.
- #
- # The attributes of the element are specified as a hash. The
- # pseudo-attribute "PRETTY" can be used to specify that the generated
- # HTML string should be indented. "PRETTY" can also be specified as
- # a string as the sole argument to this method. The pseudo-attribute
- # "DOCTYPE", if given, is used as the leading DOCTYPE SGML tag; it
- # should include the entire text of this tag, including angle brackets.
- #
- # The body of the html element is supplied as a block.
- #
- # html{ "string" }
- # # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
- #
- # html("LANG" => "ja") { "string" }
- # # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
- #
- # html("DOCTYPE" => false) { "string" }
- # # <HTML>string</HTML>
- #
- # html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">') { "string" }
- # # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
- #
- # html("PRETTY" => " ") { "<BODY></BODY>" }
- # # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
- # # <HTML>
- # # <BODY>
- # # </BODY>
- # # </HTML>
- #
- # html("PRETTY" => "\t") { "<BODY></BODY>" }
- # # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
- # # <HTML>
- # # <BODY>
- # # </BODY>
- # # </HTML>
- #
- # html("PRETTY") { "<BODY></BODY>" }
- # # = html("PRETTY" => " ") { "<BODY></BODY>" }
- #
- # html(if $VERBOSE then "PRETTY" end) { "HTML string" }
- #
- def html(attributes = {}) # :yield:
- if nil == attributes
- attributes = {}
- elsif "PRETTY" == attributes
- attributes = { "PRETTY" => true }
- end
- pretty = attributes.delete("PRETTY")
- pretty = " " if true == pretty
- buf = "".dup
-
- if attributes.has_key?("DOCTYPE")
- if attributes["DOCTYPE"]
- buf << attributes.delete("DOCTYPE")
- else
- attributes.delete("DOCTYPE")
- end
- else
- buf << doctype
- end
-
- buf << super(attributes)
-
- if pretty
- CGI.pretty(buf, pretty)
- else
- buf
- end
-
- end
-
- # Generate an Image Button Input element as a string.
- #
- # +src+ is the URL of the image to use for the button. +name+
- # is the input name. +alt+ is the alternative text for the image.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # image_button("url")
- # # <INPUT TYPE="image" SRC="url">
- #
- # image_button("url", "name", "string")
- # # <INPUT TYPE="image" SRC="url" NAME="name" ALT="string">
- #
- # image_button("SRC" => "url", "ALT" => "string")
- # # <INPUT TYPE="image" SRC="url" ALT="string">
- def image_button(src = "", name = nil, alt = nil)
- attributes = if src.kind_of?(String)
- { "TYPE" => "image", "SRC" => src, "NAME" => name,
- "ALT" => alt }
- else
- src["TYPE"] = "image"
- src["SRC"] ||= ""
- src
- end
- input(attributes)
- end
-
-
- # Generate an Image element as a string.
- #
- # +src+ is the URL of the image. +alt+ is the alternative text for
- # the image. +width+ is the width of the image, and +height+ is
- # its height.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # img("src", "alt", 100, 50)
- # # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
- #
- # img("SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50)
- # # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
- def img(src = "", alt = "", width = nil, height = nil)
- attributes = if src.kind_of?(String)
- { "SRC" => src, "ALT" => alt }
- else
- src
- end
- attributes["WIDTH"] = width.to_s if width
- attributes["HEIGHT"] = height.to_s if height
- super(attributes)
- end
-
-
- # Generate a Form element with multipart encoding as a String.
- #
- # Multipart encoding is used for forms that include file uploads.
- #
- # +action+ is the action to perform. +enctype+ is the encoding
- # type, which defaults to "multipart/form-data".
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # multipart_form{ "string" }
- # # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
- #
- # multipart_form("url") { "string" }
- # # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
- def multipart_form(action = nil, enctype = "multipart/form-data")
- attributes = if action == nil
- { "METHOD" => "post", "ENCTYPE" => enctype }
- elsif action.kind_of?(String)
- { "METHOD" => "post", "ACTION" => action,
- "ENCTYPE" => enctype }
- else
- unless action.has_key?("METHOD")
- action["METHOD"] = "post"
- end
- unless action.has_key?("ENCTYPE")
- action["ENCTYPE"] = enctype
- end
- action
- end
- if block_given?
- form(attributes){ yield }
- else
- form(attributes)
- end
- end
-
-
- # Generate a Password Input element as a string.
- #
- # +name+ is the name of the input field. +value+ is its default
- # value. +size+ is the size of the input field display. +maxlength+
- # is the maximum length of the inputted password.
- #
- # Alternatively, attributes can be specified as a hash.
- #
- # password_field("name")
- # # <INPUT TYPE="password" NAME="name" SIZE="40">
- #
- # password_field("name", "value")
- # # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
- #
- # password_field("password", "value", 80, 200)
- # # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
- #
- # password_field("NAME" => "name", "VALUE" => "value")
- # # <INPUT TYPE="password" NAME="name" VALUE="value">
- def password_field(name = "", value = nil, size = 40, maxlength = nil)
- attributes = if name.kind_of?(String)
- { "TYPE" => "password", "NAME" => name,
- "VALUE" => value, "SIZE" => size.to_s }
- else
- name["TYPE"] = "password"
- name
- end
- attributes["MAXLENGTH"] = maxlength.to_s if maxlength
- input(attributes)
- end
-
- # Generate a Select element as a string.
- #
- # +name+ is the name of the element. The +values+ are the options that
- # can be selected from the Select menu. Each value can be a String or
- # a one, two, or three-element Array. If a String or a one-element
- # Array, this is both the value of that option and the text displayed for
- # it. If a three-element Array, the elements are the option value, displayed
- # text, and a boolean value specifying whether this option starts as selected.
- # The two-element version omits either the option value (defaults to the same
- # as the display text) or the boolean selected specifier (defaults to false).
- #
- # The attributes and options can also be specified as a hash. In this
- # case, options are specified as an array of values as described above,
- # with the hash key of "VALUES".
- #
- # popup_menu("name", "foo", "bar", "baz")
- # # <SELECT NAME="name">
- # # <OPTION VALUE="foo">foo</OPTION>
- # # <OPTION VALUE="bar">bar</OPTION>
- # # <OPTION VALUE="baz">baz</OPTION>
- # # </SELECT>
- #
- # popup_menu("name", ["foo"], ["bar", true], "baz")
- # # <SELECT NAME="name">
- # # <OPTION VALUE="foo">foo</OPTION>
- # # <OPTION VALUE="bar" SELECTED>bar</OPTION>
- # # <OPTION VALUE="baz">baz</OPTION>
- # # </SELECT>
- #
- # popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
- # # <SELECT NAME="name">
- # # <OPTION VALUE="1">Foo</OPTION>
- # # <OPTION SELECTED VALUE="2">Bar</OPTION>
- # # <OPTION VALUE="Baz">Baz</OPTION>
- # # </SELECT>
- #
- # popup_menu("NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
- # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
- # # <SELECT NAME="name" MULTIPLE SIZE="2">
- # # <OPTION VALUE="1">Foo</OPTION>
- # # <OPTION SELECTED VALUE="2">Bar</OPTION>
- # # <OPTION VALUE="Baz">Baz</OPTION>
- # # </SELECT>
- def popup_menu(name = "", *values)
-
- if name.kind_of?(Hash)
- values = name["VALUES"]
- size = name["SIZE"].to_s if name["SIZE"]
- multiple = name["MULTIPLE"]
- name = name["NAME"]
- else
- size = nil
- multiple = nil
- end
-
- select({ "NAME" => name, "SIZE" => size,
- "MULTIPLE" => multiple }){
- values.collect{|value|
- if value.kind_of?(String)
- option({ "VALUE" => value }){ value }
- else
- if value[value.size - 1] == true
- option({ "VALUE" => value[0], "SELECTED" => true }){
- value[value.size - 2]
- }
- else
- option({ "VALUE" => value[0] }){
- value[value.size - 1]
- }
- end
- end
- }.join
- }
-
- end
-
- # Generates a radio-button Input element.
- #
- # +name+ is the name of the input field. +value+ is the value of
- # the field if checked. +checked+ specifies whether the field
- # starts off checked.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # radio_button("name", "value")
- # # <INPUT TYPE="radio" NAME="name" VALUE="value">
- #
- # radio_button("name", "value", true)
- # # <INPUT TYPE="radio" NAME="name" VALUE="value" CHECKED>
- #
- # radio_button("NAME" => "name", "VALUE" => "value", "ID" => "foo")
- # # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
- def radio_button(name = "", value = nil, checked = nil)
- attributes = if name.kind_of?(String)
- { "TYPE" => "radio", "NAME" => name,
- "VALUE" => value, "CHECKED" => checked }
- else
- name["TYPE"] = "radio"
- name
- end
- input(attributes)
- end
-
- # Generate a sequence of radio button Input elements, as a String.
- #
- # This works the same as #checkbox_group(). However, it is not valid
- # to have more than one radiobutton in a group checked.
- #
- # radio_group("name", "foo", "bar", "baz")
- # # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
- # # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
- # # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
- #
- # radio_group("name", ["foo"], ["bar", true], "baz")
- # # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
- # # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="bar">bar
- # # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
- #
- # radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
- # # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
- # # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="2">Bar
- # # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
- #
- # radio_group("NAME" => "name",
- # "VALUES" => ["foo", "bar", "baz"])
- #
- # radio_group("NAME" => "name",
- # "VALUES" => [["foo"], ["bar", true], "baz"])
- #
- # radio_group("NAME" => "name",
- # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
- def radio_group(name = "", *values)
- if name.kind_of?(Hash)
- values = name["VALUES"]
- name = name["NAME"]
- end
- values.collect{|value|
- if value.kind_of?(String)
- radio_button(name, value) + value
- else
- if value[-1] == true || value[-1] == false
- radio_button(name, value[0], value[-1]) +
- value[-2]
- else
- radio_button(name, value[0]) +
- value[-1]
- end
- end
- }.join
- end
-
- # Generate a reset button Input element, as a String.
- #
- # This resets the values on a form to their initial values. +value+
- # is the text displayed on the button. +name+ is the name of this button.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # reset
- # # <INPUT TYPE="reset">
- #
- # reset("reset")
- # # <INPUT TYPE="reset" VALUE="reset">
- #
- # reset("VALUE" => "reset", "ID" => "foo")
- # # <INPUT TYPE="reset" VALUE="reset" ID="foo">
- def reset(value = nil, name = nil)
- attributes = if (not value) or value.kind_of?(String)
- { "TYPE" => "reset", "VALUE" => value, "NAME" => name }
- else
- value["TYPE"] = "reset"
- value
- end
- input(attributes)
- end
-
- alias scrolling_list popup_menu
-
- # Generate a submit button Input element, as a String.
- #
- # +value+ is the text to display on the button. +name+ is the name
- # of the input.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # submit
- # # <INPUT TYPE="submit">
- #
- # submit("ok")
- # # <INPUT TYPE="submit" VALUE="ok">
- #
- # submit("ok", "button1")
- # # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
- #
- # submit("VALUE" => "ok", "NAME" => "button1", "ID" => "foo")
- # # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
- def submit(value = nil, name = nil)
- attributes = if (not value) or value.kind_of?(String)
- { "TYPE" => "submit", "VALUE" => value, "NAME" => name }
- else
- value["TYPE"] = "submit"
- value
- end
- input(attributes)
- end
-
- # Generate a text field Input element, as a String.
- #
- # +name+ is the name of the input field. +value+ is its initial
- # value. +size+ is the size of the input area. +maxlength+
- # is the maximum length of input accepted.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # text_field("name")
- # # <INPUT TYPE="text" NAME="name" SIZE="40">
- #
- # text_field("name", "value")
- # # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
- #
- # text_field("name", "value", 80)
- # # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80">
- #
- # text_field("name", "value", 80, 200)
- # # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
- #
- # text_field("NAME" => "name", "VALUE" => "value")
- # # <INPUT TYPE="text" NAME="name" VALUE="value">
- def text_field(name = "", value = nil, size = 40, maxlength = nil)
- attributes = if name.kind_of?(String)
- { "TYPE" => "text", "NAME" => name, "VALUE" => value,
- "SIZE" => size.to_s }
- else
- name["TYPE"] = "text"
- name
- end
- attributes["MAXLENGTH"] = maxlength.to_s if maxlength
- input(attributes)
- end
-
- # Generate a TextArea element, as a String.
- #
- # +name+ is the name of the textarea. +cols+ is the number of
- # columns and +rows+ is the number of rows in the display.
- #
- # Alternatively, the attributes can be specified as a hash.
- #
- # The body is provided by the passed-in no-argument block
- #
- # textarea("name")
- # # = textarea("NAME" => "name", "COLS" => 70, "ROWS" => 10)
- #
- # textarea("name", 40, 5)
- # # = textarea("NAME" => "name", "COLS" => 40, "ROWS" => 5)
- def textarea(name = "", cols = 70, rows = 10) # :yield:
- attributes = if name.kind_of?(String)
- { "NAME" => name, "COLS" => cols.to_s,
- "ROWS" => rows.to_s }
- else
- name
- end
- super(attributes)
- end
-
- end # HtmlExtension
-
-
- # Mixin module for HTML version 3 generation methods.
- module Html3 # :nodoc:
- include TagMaker
-
- # The DOCTYPE declaration for this version of HTML
- def doctype
- %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">|
- end
-
- instance_method(:nn_element_def).tap do |m|
- # - -
- for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
- DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV CENTER MAP
- APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT TABLE TITLE
- STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
- CAPTION ]
- define_method(element.downcase, m)
- end
- end
-
- instance_method(:nOE_element_def).tap do |m|
- # - O EMPTY
- for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
- ISINDEX META ]
- define_method(element.downcase, m)
- end
- end
-
- instance_method(:nO_element_def).tap do |m|
- # O O or - O
- for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION TR
- TH TD ]
- define_method(element.downcase, m)
- end
- end
-
- end # Html3
-
-
- # Mixin module for HTML version 4 generation methods.
- module Html4 # :nodoc:
- include TagMaker
-
- # The DOCTYPE declaration for this version of HTML
- def doctype
- %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|
- end
-
- # Initialize the HTML generation methods for this version.
- # - -
- instance_method(:nn_element_def).tap do |m|
- for element in %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD
- VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
- H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP
- FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
- TEXTAREA FORM A BLOCKQUOTE CAPTION ]
- define_method(element.downcase, m)
- end
- end
-
- # - O EMPTY
- instance_method(:nOE_element_def).tap do |m|
- for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ]
- define_method(element.downcase, m)
- end
- end
-
- # O O or - O
- instance_method(:nO_element_def).tap do |m|
- for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
- COLGROUP TR TH TD HEAD ]
- define_method(element.downcase, m)
- end
- end
-
- end # Html4
-
-
- # Mixin module for HTML version 4 transitional generation methods.
- module Html4Tr # :nodoc:
- include TagMaker
-
- # The DOCTYPE declaration for this version of HTML
- def doctype
- %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|
- end
-
- # Initialise the HTML generation methods for this version.
- # - -
- instance_method(:nn_element_def).tap do |m|
- for element in %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN
- CODE SAMP KBD VAR CITE ABBR ACRONYM FONT SUB SUP SPAN BDO
- ADDRESS DIV CENTER MAP OBJECT APPLET H1 H2 H3 H4 H5 H6 PRE Q
- INS DEL DL OL UL DIR MENU LABEL SELECT OPTGROUP FIELDSET
- LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE SCRIPT
- NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ]
- define_method(element.downcase, m)
- end
- end
-
- # - O EMPTY
- instance_method(:nOE_element_def).tap do |m|
- for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
- COL ISINDEX META ]
- define_method(element.downcase, m)
- end
- end
-
- # O O or - O
- instance_method(:nO_element_def).tap do |m|
- for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
- COLGROUP TR TH TD HEAD ]
- define_method(element.downcase, m)
- end
- end
-
- end # Html4Tr
-
-
- # Mixin module for generating HTML version 4 with framesets.
- module Html4Fr # :nodoc:
- include TagMaker
-
- # The DOCTYPE declaration for this version of HTML
- def doctype
- %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|
- end
-
- # Initialise the HTML generation methods for this version.
- # - -
- instance_method(:nn_element_def).tap do |m|
- for element in %w[ FRAMESET ]
- define_method(element.downcase, m)
- end
- end
-
- # - O EMPTY
- instance_method(:nOE_element_def).tap do |m|
- for element in %w[ FRAME ]
- define_method(element.downcase, m)
- end
- end
-
- end # Html4Fr
-
-
- # Mixin module for HTML version 5 generation methods.
- module Html5 # :nodoc:
- include TagMaker
-
- # The DOCTYPE declaration for this version of HTML
- def doctype
- %|<!DOCTYPE HTML>|
- end
-
- # Initialise the HTML generation methods for this version.
- # - -
- instance_method(:nn_element_def).tap do |m|
- for element in %w[ SECTION NAV ARTICLE ASIDE HGROUP HEADER
- FOOTER FIGURE FIGCAPTION S TIME U MARK RUBY BDI IFRAME
- VIDEO AUDIO CANVAS DATALIST OUTPUT PROGRESS METER DETAILS
- SUMMARY MENU DIALOG I B SMALL EM STRONG DFN CODE SAMP KBD
- VAR CITE ABBR SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
- H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT
- FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
- TEXTAREA FORM A BLOCKQUOTE CAPTION ]
- define_method(element.downcase, m)
- end
- end
-
- # - O EMPTY
- instance_method(:nOE_element_def).tap do |m|
- for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META
- COMMAND EMBED KEYGEN SOURCE TRACK WBR ]
- define_method(element.downcase, m)
- end
- end
-
- # O O or - O
- instance_method(:nO_element_def).tap do |m|
- for element in %w[ HTML HEAD BODY P DT DD LI OPTION THEAD TFOOT TBODY
- OPTGROUP COLGROUP RT RP TR TH TD ]
- define_method(element.downcase, m)
- end
- end
-
- end # Html5
-
- class HTML3
- include Html3
- include HtmlExtension
- end
-
- class HTML4
- include Html4
- include HtmlExtension
- end
-
- class HTML4Tr
- include Html4Tr
- include HtmlExtension
- end
-
- class HTML4Fr
- include Html4Tr
- include Html4Fr
- include HtmlExtension
- end
-
- class HTML5
- include Html5
- include HtmlExtension
- end
-
-end
diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb
deleted file mode 100644
index aab60869bb..0000000000
--- a/lib/cgi/session.rb
+++ /dev/null
@@ -1,562 +0,0 @@
-# frozen_string_literal: true
-#
-# cgi/session.rb - session support for cgi scripts
-#
-# Copyright (C) 2001 Yukihiro "Matz" Matsumoto
-# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
-# Copyright (C) 2000 Information-technology Promotion Agency, Japan
-#
-# Author: Yukihiro "Matz" Matsumoto
-#
-# Documentation: William Webber (william@williamwebber.com)
-
-require 'cgi'
-require 'tmpdir'
-
-class CGI
-
- # == Overview
- #
- # This file provides the CGI::Session class, which provides session
- # support for CGI scripts. A session is a sequence of HTTP requests
- # and responses linked together and associated with a single client.
- # Information associated with the session is stored
- # on the server between requests. A session id is passed between client
- # and server with every request and response, transparently
- # to the user. This adds state information to the otherwise stateless
- # HTTP request/response protocol.
- #
- # == Lifecycle
- #
- # A CGI::Session instance is created from a CGI object. By default,
- # this CGI::Session instance will start a new session if none currently
- # exists, or continue the current session for this client if one does
- # exist. The +new_session+ option can be used to either always or
- # never create a new session. See #new() for more details.
- #
- # #delete() deletes a session from session storage. It
- # does not however remove the session id from the client. If the client
- # makes another request with the same id, the effect will be to start
- # a new session with the old session's id.
- #
- # == Setting and retrieving session data.
- #
- # The Session class associates data with a session as key-value pairs.
- # This data can be set and retrieved by indexing the Session instance
- # using '[]', much the same as hashes (although other hash methods
- # are not supported).
- #
- # When session processing has been completed for a request, the
- # session should be closed using the close() method. This will
- # store the session's state to persistent storage. If you want
- # to store the session's state to persistent storage without
- # finishing session processing for this request, call the update()
- # method.
- #
- # == Storing session state
- #
- # The caller can specify what form of storage to use for the session's
- # data with the +database_manager+ option to CGI::Session::new. The
- # following storage classes are provided as part of the standard library:
- #
- # CGI::Session::FileStore:: stores data as plain text in a flat file. Only
- # works with String data. This is the default
- # storage type.
- # CGI::Session::MemoryStore:: stores data in an in-memory hash. The data
- # only persists for as long as the current Ruby
- # interpreter instance does.
- # CGI::Session::PStore:: stores data in Marshalled format. Provided by
- # cgi/session/pstore.rb. Supports data of any type,
- # and provides file-locking and transaction support.
- #
- # Custom storage types can also be created by defining a class with
- # the following methods:
- #
- # new(session, options)
- # restore # returns hash of session data.
- # update
- # close
- # delete
- #
- # Changing storage type mid-session does not work. Note in particular
- # that by default the FileStore and PStore session data files have the
- # same name. If your application switches from one to the other without
- # making sure that filenames will be different
- # and clients still have old sessions lying around in cookies, then
- # things will break nastily!
- #
- # == Maintaining the session id.
- #
- # Most session state is maintained on the server. However, a session
- # id must be passed backwards and forwards between client and server
- # to maintain a reference to this session state.
- #
- # The simplest way to do this is via cookies. The CGI::Session class
- # provides transparent support for session id communication via cookies
- # if the client has cookies enabled.
- #
- # If the client has cookies disabled, the session id must be included
- # as a parameter of all requests sent by the client to the server. The
- # CGI::Session class in conjunction with the CGI class will transparently
- # add the session id as a hidden input field to all forms generated
- # using the CGI#form() HTML generation method. No built-in support is
- # provided for other mechanisms, such as URL re-writing. The caller is
- # responsible for extracting the session id from the session_id
- # attribute and manually encoding it in URLs and adding it as a hidden
- # input to HTML forms created by other mechanisms. Also, session expiry
- # is not automatically handled.
- #
- # == Examples of use
- #
- # === Setting the user's name
- #
- # require 'cgi'
- # require 'cgi/session'
- # require 'cgi/session/pstore' # provides CGI::Session::PStore
- #
- # cgi = CGI.new("html4")
- #
- # session = CGI::Session.new(cgi,
- # 'database_manager' => CGI::Session::PStore, # use PStore
- # 'session_key' => '_rb_sess_id', # custom session key
- # 'session_expires' => Time.now + 30 * 60, # 30 minute timeout
- # 'prefix' => 'pstore_sid_') # PStore option
- # if cgi.has_key?('user_name') and cgi['user_name'] != ''
- # # coerce to String: cgi[] returns the
- # # string-like CGI::QueryExtension::Value
- # session['user_name'] = cgi['user_name'].to_s
- # elsif !session['user_name']
- # session['user_name'] = "guest"
- # end
- # session.close
- #
- # === Creating a new session safely
- #
- # require 'cgi'
- # require 'cgi/session'
- #
- # cgi = CGI.new("html4")
- #
- # # We make sure to delete an old session if one exists,
- # # not just to free resources, but to prevent the session
- # # from being maliciously hijacked later on.
- # begin
- # session = CGI::Session.new(cgi, 'new_session' => false)
- # session.delete
- # rescue ArgumentError # if no old session
- # end
- # session = CGI::Session.new(cgi, 'new_session' => true)
- # session.close
- #
- class Session
-
- class NoSession < RuntimeError #:nodoc:
- end
-
- # The id of this session.
- attr_reader :session_id, :new_session
-
- def Session::callback(dbman) #:nodoc:
- Proc.new{
- dbman[0].close unless dbman.empty?
- }
- end
-
- # Create a new session id.
- #
- # The session id is a secure random number by SecureRandom
- # if possible, otherwise an SHA512 hash based upon the time,
- # a random number, and a constant string. This routine is
- # used internally for automatically generated session ids.
- def create_new_id
- require 'securerandom'
- begin
- # by OpenSSL, or system provided entropy pool
- session_id = SecureRandom.hex(16)
- rescue NotImplementedError
- # never happens on modern systems
- require 'digest'
- d = Digest('SHA512').new
- now = Time::now
- d.update(now.to_s)
- d.update(String(now.usec))
- d.update(String(rand(0)))
- d.update(String($$))
- d.update('foobar')
- session_id = d.hexdigest[0, 32]
- end
- session_id
- end
- private :create_new_id
-
-
- # Create a new file to store the session data.
- #
- # This file will be created if it does not exist, or opened if it
- # does.
- #
- # This path is generated under _tmpdir_ from _prefix_, the
- # digested session id, and _suffix_.
- #
- # +option+ is a hash of options for the initializer. The
- # following options are recognised:
- #
- # tmpdir:: the directory to use for storing the FileStore
- # file. Defaults to Dir::tmpdir (generally "/tmp"
- # on Unix systems).
- # prefix:: the prefix to add to the session id when generating
- # the filename for this session's FileStore file.
- # Defaults to "cgi_sid_".
- # suffix:: the prefix to add to the session id when generating
- # the filename for this session's FileStore file.
- # Defaults to the empty string.
- def new_store_file(option={}) # :nodoc:
- dir = option['tmpdir'] || Dir::tmpdir
- prefix = option['prefix']
- suffix = option['suffix']
- require 'digest/md5'
- md5 = Digest::MD5.hexdigest(session_id)[0,16]
- path = dir+"/"
- path << prefix if prefix
- path << md5
- path << suffix if suffix
- if File::exist? path
- hash = nil
- elsif new_session
- hash = {}
- else
- raise NoSession, "uninitialized session"
- end
- return path, hash
- end
-
- # Create a new CGI::Session object for +request+.
- #
- # +request+ is an instance of the +CGI+ class (see cgi.rb).
- # +option+ is a hash of options for initialising this
- # CGI::Session instance. The following options are
- # recognised:
- #
- # session_key:: the parameter name used for the session id.
- # Defaults to '_session_id'.
- # session_id:: the session id to use. If not provided, then
- # it is retrieved from the +session_key+ parameter
- # of the request, or automatically generated for
- # a new session.
- # new_session:: if true, force creation of a new session. If not set,
- # a new session is only created if none currently
- # exists. If false, a new session is never created,
- # and if none currently exists and the +session_id+
- # option is not set, an ArgumentError is raised.
- # database_manager:: the name of the class providing storage facilities
- # for session state persistence. Built-in support
- # is provided for +FileStore+ (the default),
- # +MemoryStore+, and +PStore+ (from
- # cgi/session/pstore.rb). See the documentation for
- # these classes for more details.
- #
- # The following options are also recognised, but only apply if the
- # session id is stored in a cookie.
- #
- # session_expires:: the time the current session expires, as a
- # +Time+ object. If not set, the session will terminate
- # when the user's browser is closed.
- # session_domain:: the hostname domain for which this session is valid.
- # If not set, defaults to the hostname of the server.
- # session_secure:: if +true+, this session will only work over HTTPS.
- # session_path:: the path for which this session applies. Defaults
- # to the directory of the CGI script.
- #
- # +option+ is also passed on to the session storage class initializer; see
- # the documentation for each session storage class for the options
- # they support.
- #
- # The retrieved or created session is automatically added to +request+
- # as a cookie, and also to its +output_hidden+ table, which is used
- # to add hidden input elements to forms.
- #
- # *WARNING* the +output_hidden+
- # 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)
- #
- # cgi = CGI.new("html4")
- # class << cgi
- # undef_method :fieldset
- # end
- #
- def initialize(request, option={})
- @new_session = false
- session_key = option['session_key'] || '_session_id'
- session_id = option['session_id']
- unless session_id
- if option['new_session']
- session_id = create_new_id
- @new_session = true
- end
- end
- unless session_id
- if request.key?(session_key)
- session_id = request[session_key]
- session_id = session_id.read if session_id.respond_to?(:read)
- end
- unless session_id
- session_id, = request.cookies[session_key]
- end
- unless session_id
- unless option.fetch('new_session', true)
- raise ArgumentError, "session_key `%s' should be supplied"%session_key
- end
- session_id = create_new_id
- @new_session = true
- end
- end
- @session_id = session_id
- dbman = option['database_manager'] || FileStore
- begin
- @dbman = dbman::new(self, option)
- rescue NoSession
- unless option.fetch('new_session', true)
- raise ArgumentError, "invalid session_id `%s'"%session_id
- end
- session_id = @session_id = create_new_id unless session_id
- @new_session=true
- retry
- end
- request.instance_eval do
- @output_hidden = {session_key => session_id} unless option['no_hidden']
- @output_cookies = [
- Cookie::new("name" => session_key,
- "value" => session_id,
- "expires" => option['session_expires'],
- "domain" => option['session_domain'],
- "secure" => option['session_secure'],
- "path" =>
- if option['session_path']
- option['session_path']
- elsif ENV["SCRIPT_NAME"]
- File::dirname(ENV["SCRIPT_NAME"])
- else
- ""
- end)
- ] unless option['no_cookies']
- end
- @dbprot = [@dbman]
- ObjectSpace::define_finalizer(self, Session::callback(@dbprot))
- end
-
- # Retrieve the session data for key +key+.
- def [](key)
- @data ||= @dbman.restore
- @data[key]
- end
-
- # Set the session data for key +key+.
- def []=(key, val)
- @write_lock ||= true
- @data ||= @dbman.restore
- @data[key] = val
- end
-
- # Store session data on the server. For some session storage types,
- # this is a no-op.
- def update
- @dbman.update
- end
-
- # Store session data on the server and close the session storage.
- # For some session storage types, this is a no-op.
- def close
- @dbman.close
- @dbprot.clear
- end
-
- # Delete the session from storage. Also closes the storage.
- #
- # Note that the session's data is _not_ automatically deleted
- # upon the session expiring.
- def delete
- @dbman.delete
- @dbprot.clear
- end
-
- # File-based session storage class.
- #
- # Implements session storage as a flat file of 'key=value' values.
- # This storage type only works directly with String values; the
- # user is responsible for converting other types to Strings when
- # storing and from Strings when retrieving.
- class FileStore
- # Create a new FileStore instance.
- #
- # This constructor is used internally by CGI::Session. The
- # user does not generally need to call it directly.
- #
- # +session+ is the session for which this instance is being
- # created. The session id must only contain alphanumeric
- # characters; automatically generated session ids observe
- # this requirement.
- #
- # +option+ is a hash of options for the initializer. The
- # following options are recognised:
- #
- # tmpdir:: the directory to use for storing the FileStore
- # file. Defaults to Dir::tmpdir (generally "/tmp"
- # on Unix systems).
- # prefix:: the prefix to add to the session id when generating
- # the filename for this session's FileStore file.
- # Defaults to "cgi_sid_".
- # suffix:: the prefix to add to the session id when generating
- # the filename for this session's FileStore file.
- # Defaults to the empty string.
- #
- # This session's FileStore file will be created if it does
- # not exist, or opened if it does.
- def initialize(session, option={})
- option = {'prefix' => 'cgi_sid_'}.update(option)
- @path, @hash = session.new_store_file(option)
- end
-
- # Restore session state from the session's FileStore file.
- #
- # Returns the session state as a hash.
- def restore
- unless @hash
- @hash = {}
- begin
- lockf = File.open(@path+".lock", "r")
- lockf.flock File::LOCK_SH
- f = File.open(@path, 'r')
- for line in f
- line.chomp!
- k, v = line.split('=',2)
- @hash[CGI.unescape(k)] = Marshal.restore(CGI.unescape(v))
- end
- ensure
- f&.close
- lockf&.close
- end
- end
- @hash
- end
-
- # Save session state to the session's FileStore file.
- def update
- return unless @hash
- begin
- lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600)
- lockf.flock File::LOCK_EX
- f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600)
- for k,v in @hash
- f.printf "%s=%s\n", CGI.escape(k), CGI.escape(String(Marshal.dump(v)))
- end
- f.close
- File.rename @path+".new", @path
- ensure
- f&.close
- lockf&.close
- end
- end
-
- # Update and close the session's FileStore file.
- def close
- update
- end
-
- # Close and delete the session's FileStore file.
- def delete
- File::unlink @path+".lock" rescue nil
- File::unlink @path+".new" rescue nil
- File::unlink @path rescue nil
- end
- end
-
- # In-memory session storage class.
- #
- # Implements session storage as a global in-memory hash. Session
- # data will only persist for as long as the Ruby interpreter
- # instance does.
- class MemoryStore
- GLOBAL_HASH_TABLE = {} #:nodoc:
-
- # Create a new MemoryStore instance.
- #
- # +session+ is the session this instance is associated with.
- # +option+ is a list of initialisation options. None are
- # currently recognized.
- def initialize(session, option=nil)
- @session_id = session.session_id
- unless GLOBAL_HASH_TABLE.key?(@session_id)
- unless session.new_session
- raise CGI::Session::NoSession, "uninitialized session"
- end
- GLOBAL_HASH_TABLE[@session_id] = {}
- end
- end
-
- # Restore session state.
- #
- # Returns session data as a hash.
- def restore
- GLOBAL_HASH_TABLE[@session_id]
- end
-
- # Update session state.
- #
- # A no-op.
- def update
- # don't need to update; hash is shared
- end
-
- # Close session storage.
- #
- # A no-op.
- def close
- # don't need to close
- end
-
- # Delete the session state.
- def delete
- GLOBAL_HASH_TABLE.delete(@session_id)
- end
- end
-
- # Dummy session storage class.
- #
- # Implements session storage place holder. No actual storage
- # will be done.
- class NullStore
- # Create a new NullStore instance.
- #
- # +session+ is the session this instance is associated with.
- # +option+ is a list of initialisation options. None are
- # currently recognised.
- def initialize(session, option=nil)
- end
-
- # Restore (empty) session state.
- def restore
- {}
- end
-
- # Update session state.
- #
- # A no-op.
- def update
- end
-
- # Close session storage.
- #
- # A no-op.
- def close
- end
-
- # Delete the session state.
- #
- # A no-op.
- def delete
- end
- end
- end
-end
diff --git a/lib/cgi/session/pstore.rb b/lib/cgi/session/pstore.rb
deleted file mode 100644
index 6e3d10f075..0000000000
--- a/lib/cgi/session/pstore.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-#
-# cgi/session/pstore.rb - persistent storage of marshalled session data
-#
-# Documentation: William Webber (william@williamwebber.com)
-#
-# == Overview
-#
-# This file provides the CGI::Session::PStore class, which builds
-# persistent of session data on top of the pstore library. See
-# cgi/session.rb for more details on session storage managers.
-
-require_relative '../session'
-begin
- require 'pstore'
-rescue LoadError
-end
-
-class CGI
- class Session
- # PStore-based session storage class.
- #
- # This builds upon the top-level PStore class provided by the
- # library file pstore.rb. Session data is marshalled and stored
- # in a file. File locking and transaction services are provided.
- class PStore
- # Create a new CGI::Session::PStore instance
- #
- # This constructor is used internally by CGI::Session. The
- # user does not generally need to call it directly.
- #
- # +session+ is the session for which this instance is being
- # created. The session id must only contain alphanumeric
- # characters; automatically generated session ids observe
- # this requirement.
- #
- # +option+ is a hash of options for the initializer. The
- # following options are recognised:
- #
- # tmpdir:: the directory to use for storing the PStore
- # file. Defaults to Dir::tmpdir (generally "/tmp"
- # on Unix systems).
- # prefix:: the prefix to add to the session id when generating
- # the filename for this session's PStore file.
- # Defaults to the empty string.
- #
- # This session's PStore file will be created if it does
- # not exist, or opened if it does.
- def initialize(session, option={})
- option = {'suffix'=>''}.update(option)
- path, @hash = session.new_store_file(option)
- @p = ::PStore.new(path)
- @p.transaction do |p|
- File.chmod(0600, p.path)
- end
- end
-
- # Restore session state from the session's PStore file.
- #
- # Returns the session state as a hash.
- def restore
- unless @hash
- @p.transaction do
- @hash = @p['hash'] || {}
- end
- end
- @hash
- end
-
- # Save session state to the session's PStore file.
- def update
- @p.transaction do
- @p['hash'] = @hash
- end
- end
-
- # Update and close the session's PStore file.
- def close
- update
- end
-
- # Close and delete the session's PStore file.
- def delete
- path = @p.path
- File::unlink path
- end
-
- end if defined?(::PStore)
- end
-end
-# :enddoc:
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
index 5f12eae130..50a2e91665 100644
--- a/lib/cgi/util.rb
+++ b/lib/cgi/util.rb
@@ -1,258 +1,7 @@
# frozen_string_literal: true
-class CGI
- module Util; end
- include Util
- extend Util
-end
-module CGI::Util
- @@accept_charset = Encoding::UTF_8 unless defined?(@@accept_charset)
- # URL-encode a string into application/x-www-form-urlencoded.
- # Space characters (+" "+) are encoded with plus signs (+"+"+)
- # url_encoded_string = CGI.escape("'Stop!' said Fred")
- # # => "%27Stop%21%27+said+Fred"
- def escape(string)
- encoding = string.encoding
- buffer = string.b
- buffer.gsub!(/([^ a-zA-Z0-9_.\-~]+)/) do |m|
- '%' + m.unpack('H2' * m.bytesize).join('%').upcase
- end
- buffer.tr!(' ', '+')
- buffer.force_encoding(encoding)
- end
-
- # URL-decode an application/x-www-form-urlencoded string with encoding(optional).
- # string = CGI.unescape("%27Stop%21%27+said+Fred")
- # # => "'Stop!' said Fred"
- def unescape(string, encoding = @@accept_charset)
- str = string.tr('+', ' ')
- str = str.b
- str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m|
- [m.delete('%')].pack('H*')
- end
- str.force_encoding(encoding)
- str.valid_encoding? ? str : str.force_encoding(string.encoding)
- end
-
- # URL-encode a string following RFC 3986
- # Space characters (+" "+) are encoded with (+"%20"+)
- # url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred")
- # # => "%27Stop%21%27%20said%20Fred"
- def escapeURIComponent(string)
- encoding = string.encoding
- buffer = string.b
- buffer.gsub!(/([^a-zA-Z0-9_.\-~]+)/) do |m|
- '%' + m.unpack('H2' * m.bytesize).join('%').upcase
- 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")
- # # => "'Stop!'+said Fred"
- def unescapeURIComponent(string, encoding = @@accept_charset)
- str = string.b
- str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m|
- [m.delete('%')].pack('H*')
- end
- str.force_encoding(encoding)
- 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;',
- '&' => '&amp;',
- '"' => '&quot;',
- '<' => '&lt;',
- '>' => '&gt;',
- }
-
- # Escape special characters in HTML, namely '&\"<>
- # CGI.escapeHTML('Usage: foo "bar" <baz>')
- # # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
- def escapeHTML(string)
- enc = string.encoding
- unless enc.ascii_compatible?
- if enc.dummy?
- origenc = enc
- enc = Encoding::Converter.asciicompat_encoding(enc)
- string = enc ? string.encode(enc) : string.b
- end
- table = Hash[TABLE_FOR_ESCAPE_HTML__.map {|pair|pair.map {|s|s.encode(enc)}}]
- string = string.gsub(/#{"['&\"<>]".encode(enc)}/, table)
- string.encode!(origenc) if origenc
- string
- else
- string = string.b
- string.gsub!(/['&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
- string.force_encoding(enc)
- 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
- end
-
- # Unescape a string that has been HTML-escaped
- # CGI.unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
- # # => "Usage: foo \"bar\" <baz>"
- def unescapeHTML(string)
- enc = string.encoding
- unless enc.ascii_compatible?
- if enc.dummy?
- origenc = enc
- enc = Encoding::Converter.asciicompat_encoding(enc)
- string = enc ? string.encode(enc) : string.b
- end
- string = string.gsub(Regexp.new('&(apos|amp|quot|gt|lt|#[0-9]+|#x[0-9A-Fa-f]+);'.encode(enc))) do
- case $1.encode(Encoding::US_ASCII)
- when 'apos' then "'".encode(enc)
- when 'amp' then '&'.encode(enc)
- when 'quot' then '"'.encode(enc)
- when 'gt' then '>'.encode(enc)
- when 'lt' then '<'.encode(enc)
- when /\A#0*(\d+)\z/ then $1.to_i.chr(enc)
- when /\A#x([0-9a-f]+)\z/i then $1.hex.chr(enc)
- end
- end
- string.encode!(origenc) if origenc
- return string
- end
- return string unless string.include? '&'
- charlimit = case enc
- when Encoding::UTF_8; 0x10ffff
- when Encoding::ISO_8859_1; 256
- else 128
- end
- string = string.b
- string.gsub!(/&(apos|amp|quot|gt|lt|\#[0-9]+|\#[xX][0-9A-Fa-f]+);/) do
- match = $1.dup
- case match
- when 'apos' then "'"
- when 'amp' then '&'
- when 'quot' then '"'
- when 'gt' then '>'
- when 'lt' then '<'
- when /\A#0*(\d+)\z/
- n = $1.to_i
- if n < charlimit
- n.chr(enc)
- else
- "&##{$1};"
- end
- when /\A#x([0-9a-f]+)\z/i
- n = $1.hex
- if n < charlimit
- n.chr(enc)
- else
- "&#x#{$1};"
- end
- else
- "&#{match};"
- end
- end
- string.force_encoding enc
- end
-
- # Synonym for CGI.escapeHTML(str)
- alias escape_html escapeHTML
-
- # Synonym for CGI.unescapeHTML(str)
- alias unescape_html unescapeHTML
-
- # Escape only the tags of certain HTML elements in +string+.
- #
- # Takes an element or elements or array of elements. Each element
- # is specified by the name of the element, without angle brackets.
- # This matches both the start and the end tag of that element.
- # The attribute list of the open tag will also be escaped (for
- # instance, the double-quotes surrounding attribute values).
- #
- # print CGI.escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
- # # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
- #
- # print CGI.escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
- # # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
- def escapeElement(string, *elements)
- elements = elements[0] if elements[0].kind_of?(Array)
- unless elements.empty?
- string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
- CGI.escapeHTML($&)
- end
- else
- string
- end
- end
-
- # Undo escaping such as that done by CGI.escapeElement()
- #
- # print CGI.unescapeElement(
- # CGI.escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
- # # "&lt;BR&gt;<A HREF="url"></A>"
- #
- # print CGI.unescapeElement(
- # CGI.escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
- # # "&lt;BR&gt;<A HREF="url"></A>"
- 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
- unescapeHTML($&)
- end
- else
- string
- end
- end
-
- # Synonym for CGI.escapeElement(str)
- alias escape_element escapeElement
-
- # Synonym for CGI.unescapeElement(str)
- alias unescape_element unescapeElement
-
- # Format a +Time+ object as a String using the format specified by RFC 1123.
- #
- # CGI.rfc1123_date(Time.now)
- # # Sat, 01 Jan 2000 00:00:00 GMT
- def rfc1123_date(time)
- time.getgm.strftime("%a, %d %b %Y %T GMT")
- end
-
- # Prettify (indent) an HTML string.
- #
- # +string+ is the HTML string to indent. +shift+ is the indentation
- # unit to use; it defaults to two spaces.
- #
- # print CGI.pretty("<HTML><BODY></BODY></HTML>")
- # # <HTML>
- # # <BODY>
- # # </BODY>
- # # </HTML>
- #
- # print CGI.pretty("<HTML><BODY></BODY></HTML>", "\t")
- # # <HTML>
- # # <BODY>
- # # </BODY>
- # # </HTML>
- #
- def pretty(string, shift = " ")
- lines = string.gsub(/(?!\A)<.*?>/m, "\n\\0").gsub(/<.*?>(?!\n)/m, "\\0\n")
- end_pos = 0
- while end_pos = lines.index(/^<\/(\w+)/, end_pos)
- element = $1.dup
- start_pos = lines.rindex(/^\s*<#{element}/i, end_pos)
- lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/, "\n" + shift) + "__"
- end
- lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/, '\1')
- end
-
- alias h escapeHTML
-end
+require "cgi/escape"
+warn <<-WARNING, uplevel: Gem::BUNDLED_GEMS.uplevel if $VERBOSE
+CGI::Util is removed from Ruby 4.0. Please use cgi/escape instead for CGI.escape and CGI.unescape features.
+If you are using CGI.parse, please install and use the cgi gem instead.
+WARNING
diff --git a/lib/delegate.rb b/lib/delegate.rb
index 824d02f28b..0ff9797bdb 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -39,7 +39,8 @@
# Be advised, RDoc will not detect delegated methods.
#
class Delegator < BasicObject
- VERSION = "0.4.0"
+ # The version string
+ VERSION = "0.6.1"
kernel = ::Kernel.dup
kernel.class_eval do
@@ -77,7 +78,7 @@ class Delegator < BasicObject
end
#
- # Handles the magic of delegation through \_\_getobj\_\_.
+ # Handles the magic of delegation through +__getobj__+.
#
ruby2_keywords def method_missing(m, *args, &block)
r = true
@@ -94,7 +95,7 @@ class Delegator < BasicObject
#
# Checks for a method provided by this the delegate object by forwarding the
- # call through \_\_getobj\_\_.
+ # call through +__getobj__+.
#
def respond_to_missing?(m, include_private)
r = true
@@ -107,7 +108,7 @@ class Delegator < BasicObject
r
end
- KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
+ KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?) # :nodoc:
private_constant :KERNEL_RESPOND_TO
# Handle BasicObject instances
@@ -126,7 +127,7 @@ class Delegator < BasicObject
#
# Returns the methods available to this delegate object as the union
- # of this object's and \_\_getobj\_\_ methods.
+ # of this object's and +__getobj__+ methods.
#
def methods(all=true)
__getobj__.methods(all) | super
@@ -134,7 +135,7 @@ class Delegator < BasicObject
#
# Returns the methods available to this delegate object as the union
- # of this object's and \_\_getobj\_\_ public methods.
+ # of this object's and +__getobj__+ public methods.
#
def public_methods(all=true)
__getobj__.public_methods(all) | super
@@ -142,7 +143,7 @@ class Delegator < BasicObject
#
# Returns the methods available to this delegate object as the union
- # of this object's and \_\_getobj\_\_ protected methods.
+ # of this object's and +__getobj__+ protected methods.
#
def protected_methods(all=true)
__getobj__.protected_methods(all) | super
@@ -175,7 +176,7 @@ class Delegator < BasicObject
end
#
- # Delegates ! to the \_\_getobj\_\_
+ # Delegates ! to the +__getobj__+
#
def !
!__getobj__
@@ -198,7 +199,7 @@ class Delegator < BasicObject
end
#
- # Serialization support for the object returned by \_\_getobj\_\_.
+ # Serialization support for the object returned by +__getobj__+.
#
def marshal_dump
ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var}
@@ -232,7 +233,7 @@ class Delegator < BasicObject
##
# :method: freeze
- # Freeze both the object returned by \_\_getobj\_\_ and self.
+ # Freeze both the object returned by +__getobj__+ and self.
#
def freeze
__getobj__.freeze
@@ -343,13 +344,6 @@ class SimpleDelegator < Delegator
end
end
-def Delegator.delegating_block(mid) # :nodoc:
- lambda do |*args, &block|
- target = self.__getobj__
- target.__send__(mid, *args, &block)
- end.ruby2_keywords
-end
-
#
# The primary interface to this library. Use to setup delegation when defining
# your class.
@@ -398,6 +392,32 @@ def DelegateClass(superclass, &block)
protected_instance_methods -= ignores
public_instance_methods = superclass.public_instance_methods
public_instance_methods -= ignores
+
+ methods_to_define =
+ public_instance_methods.map { |x| [x, false] } +
+ protected_instance_methods.map { |x| [x, true] }
+
+ source = []
+
+ methods_to_define.each do |target_name, is_protected|
+ unless target_name.match?(/\A[_a-zA-Z]\w*[!\?]?\z/)
+ placeholder_name = :__delegate
+ end
+
+ send_source =
+ if is_protected || placeholder_name
+ "__getobj__.__send__(#{target_name.inspect}, ...)"
+ else
+ "__getobj__.#{target_name}(...)"
+ end
+ source << "def #{placeholder_name || target_name}(...); #{send_source}; end"
+
+ if placeholder_name
+ source << "alias_method #{target_name.inspect}, :#{placeholder_name}"
+ source << "remove_method :#{placeholder_name}"
+ end
+ end
+
klass.module_eval do
def __getobj__ # :nodoc:
unless defined?(@delegate_dc_obj)
@@ -406,18 +426,17 @@ def DelegateClass(superclass, &block)
end
@delegate_dc_obj
end
+
def __setobj__(obj) # :nodoc:
__raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
@delegate_dc_obj = obj
end
- protected_instance_methods.each do |method|
- define_method(method, Delegator.delegating_block(method))
- protected method
- end
- public_instance_methods.each do |method|
- define_method(method, Delegator.delegating_block(method))
- end
+
+ class_eval(source.join(";"), __FILE__, __LINE__)
+
+ protected(*protected_instance_methods)
end
+
klass.define_singleton_method :public_instance_methods do |all=true|
super(all) | superclass.public_instance_methods
end
diff --git a/lib/did_you_mean.rb b/lib/did_you_mean.rb
index 74cd176042..640d910389 100644
--- a/lib/did_you_mean.rb
+++ b/lib/did_you_mean.rb
@@ -47,9 +47,9 @@ require_relative 'did_you_mean/tree_spell_checker'
# # Did you mean? :foo
#
#
-# == Disabling +did_you_mean+
+# == Disabling \DidYouMean
#
-# Occasionally, you may want to disable the +did_you_mean+ gem for e.g.
+# Occasionally, you may want to disable the \DidYouMean gem for e.g.
# debugging issues in the error object itself. You can disable it entirely by
# specifying +--disable-did_you_mean+ option to the +ruby+ command:
#
diff --git a/lib/erb.gemspec b/lib/erb.gemspec
deleted file mode 100644
index 94a8fd5c3e..0000000000
--- a/lib/erb.gemspec
+++ /dev/null
@@ -1,38 +0,0 @@
-begin
- require_relative 'lib/erb/version'
-rescue LoadError
- # for Ruby core repository
- require_relative 'erb/version'
-end
-
-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.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.}
- spec.homepage = 'https://github.com/ruby/erb'
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
- 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`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = 'libexec'
- spec.executables = ['erb']
- spec.require_paths = ['lib']
-
- if RUBY_ENGINE == 'jruby'
- spec.platform = 'java'
- else
- spec.required_ruby_version = '>= 2.7.0'
- spec.extensions = ['ext/erb/escape/extconf.rb']
- end
-
- spec.add_dependency 'cgi', '>= 0.3.3'
-end
diff --git a/lib/erb.rb b/lib/erb.rb
index bdff2deceb..bde90de841 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -12,395 +12,963 @@
#
# You can redistribute it and/or modify it under the same terms as Ruby.
-require 'cgi/util'
+# A NOTE ABOUT TERMS:
+#
+# Formerly: The documentation in this file used the term _template_ to refer to an ERB object.
+#
+# Now: The documentation in this file uses the term _template_
+# to refer to the string input to ERB.new.
+#
+# The reason for the change: When documenting the ERB executable erb,
+# we need a term that refers to its string input;
+# _source_ is not a good idea, because ERB#src means something entirely different;
+# the two different sorts of sources would bring confusion.
+#
+# Therefore we use the term _template_ to refer to:
+#
+# - The string input to ERB.new
+# - The string input to executable erb.
+#
+
require 'erb/version'
require 'erb/compiler'
require 'erb/def_method'
require 'erb/util'
+# :markup: markdown
#
-# = ERB -- Ruby Templating
+# Class **ERB** (the name stands for **Embedded Ruby**)
+# is an easy-to-use, but also very powerful, [template processor][template processor].
#
-# == Introduction
+# ## Usage
#
-# ERB provides an easy to use but powerful templating system for Ruby. Using
-# ERB, actual Ruby code can be added to any plain text document for the
-# purposes of generating document information details and/or flow control.
+# Before you can use \ERB, you must first require it
+# (examples on this page assume that this has been done):
#
-# A very simple example is this:
+# ```
+# require 'erb'
+# ```
#
-# require 'erb'
+# ## In Brief
#
-# x = 42
-# template = ERB.new <<-EOF
-# The value of x is: <%= x %>
-# EOF
-# puts template.result(binding)
+# Here's how \ERB works:
#
-# <em>Prints:</em> The value of x is: 42
+# - You can create a *template*: a plain-text string that includes specially formatted *tags*..
+# - You can create an \ERB object to store the template.
+# - You can call instance method ERB#result to get the *result*.
#
-# More complex examples are given below.
+# \ERB supports tags of three kinds:
#
+# - [Expression tags][expression tags]:
+# each begins with `'<%='`, ends with `'%>'`; contains a Ruby expression;
+# in the result, the value of the expression replaces the entire tag:
#
-# == Recognized Tags
+# template = 'The magic word is <%= magic_word %>.'
+# erb = ERB.new(template)
+# magic_word = 'xyzzy'
+# erb.result(binding) # => "The magic word is xyzzy."
#
-# ERB recognizes certain tags in the provided template and converts them based
-# on the rules below:
+# The above call to #result passes argument `binding`,
+# which contains the binding of variable `magic_word` to its string value `'xyzzy'`.
#
-# <% Ruby code -- inline with output %>
-# <%= Ruby expression -- replace with result %>
-# <%# comment -- ignored -- useful in testing %> (`<% #` doesn't work. Don't use Ruby comments.)
-# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
-# %% replaced with % if first thing on a line and % processing is used
-# <%% or %%> -- replace with <% or %> respectively
+# The below call to #result need not pass a binding,
+# because its expression `Date::DAYNAMES` is globally defined.
#
-# All other text is passed through ERB filtering unchanged.
+# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result # => "Today is Monday."
#
+# - [Execution tags][execution tags]:
+# each begins with `'<%'`, ends with `'%>'`; contains Ruby code to be executed:
#
-# == Options
+# template = '<% File.write("t.txt", "Some stuff.") %>'
+# ERB.new(template).result
+# File.read('t.txt') # => "Some stuff."
#
-# There are several settings you can change when you use ERB:
-# * the nature of the tags that are recognized;
-# * the binding used to resolve local variables in the template.
+# - [Comment tags][comment tags]:
+# each begins with `'<%#'`, ends with `'%>'`; contains comment text;
+# in the result, the entire tag is omitted.
#
-# See the ERB.new and ERB#result methods for more detail.
+# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.'
+# ERB.new(template).result # => "Some stuff; more stuff."
#
-# == Character encodings
+# ## Some Simple Examples
#
-# ERB (or Ruby code generated by ERB) returns a string in the same
-# character encoding as the input string. When the input string has
-# a magic comment, however, it returns a string in the encoding specified
-# by the magic comment.
+# Here's a simple example of \ERB in action:
#
-# # -*- coding: utf-8 -*-
-# require 'erb'
+# ```
+# template = 'The time is <%= Time.now %>.'
+# erb = ERB.new(template)
+# erb.result
+# # => "The time is 2025-09-09 10:49:26 -0500."
+# ```
#
-# template = ERB.new <<EOF
-# <%#-*- coding: Big5 -*-%>
-# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
-# EOF
-# puts template.result
+# Details:
#
-# <em>Prints:</em> \_\_ENCODING\_\_ is Big5.
+# 1. A plain-text string is assigned to variable `template`.
+# Its embedded [expression tag][expression tags] `'<%= Time.now %>'` includes a Ruby expression, `Time.now`.
+# 2. The string is put into a new \ERB object, and stored in variable `erb`.
+# 4. Method call `erb.result` generates a string that contains the run-time value of `Time.now`,
+# as computed at the time of the call.
#
+# The
+# \ERB object may be re-used:
#
-# == Examples
+# ```
+# erb.result
+# # => "The time is 2025-09-09 10:49:33 -0500."
+# ```
#
-# === Plain Text
+# Another example:
#
-# ERB is useful for any generic templating situation. Note that in this example, we use the
-# convenient "% at start of line" tag, and we quote the template literally with
-# <tt>%q{...}</tt> to avoid trouble with the backslash.
+# ```
+# template = 'The magic word is <%= magic_word %>.'
+# erb = ERB.new(template)
+# magic_word = 'abracadabra'
+# erb.result(binding)
+# # => "The magic word is abracadabra."
+# ```
#
-# require "erb"
+# Details:
#
-# # Create template.
-# template = %q{
-# From: James Edward Gray II <james@grayproductions.net>
-# To: <%= to %>
-# Subject: Addressing Needs
+# 1. As before, a plain-text string is assigned to variable `template`.
+# Its embedded [expression tag][expression tags] `'<%= magic_word %>'` has a variable *name*, `magic_word`.
+# 2. The string is put into a new \ERB object, and stored in variable `erb`;
+# note that `magic_word` need not be defined before the \ERB object is created.
+# 3. `magic_word = 'abracadabra'` assigns a value to variable `magic_word`.
+# 4. Method call `erb.result(binding)` generates a string
+# that contains the *value* of `magic_word`.
#
-# <%= to[/\w+/] %>:
+# As before, the \ERB object may be re-used:
#
-# Just wanted to send a quick note assuring that your needs are being
-# addressed.
+# ```
+# magic_word = 'xyzzy'
+# erb.result(binding)
+# # => "The magic word is xyzzy."
+# ```
#
-# I want you to know that my team will keep working on the issues,
-# especially:
+# ## Bindings
#
-# <%# ignore numerous minor requests -- focus on priorities %>
-# % priorities.each do |priority|
-# * <%= priority %>
-# % end
+# A call to method #result, which produces the formatted result string,
+# requires a [Binding object][binding object] as its argument.
+#
+# The binding object provides the bindings for expressions in [expression tags][expression tags].
+#
+# There are three ways to provide the required binding:
+#
+# - [Default binding][default binding].
+# - [Local binding][local binding].
+# - [Augmented binding][augmented binding]
+#
+# ### Default Binding
+#
+# When you pass no `binding` argument to method #result,
+# the method uses its default binding: the one returned by method #new_toplevel.
+# This binding has the bindings defined by Ruby itself,
+# which are those for Ruby's constants and variables.
+#
+# That binding is sufficient for an expression tag that refers only to Ruby's constants and variables;
+# these expression tags refer only to Ruby's global constant `RUBY_COPYRIGHT` and global variable `$0`:
#
-# Thanks for your patience.
+# ```
+# template = <<TEMPLATE
+# The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>.
+# The current process is <%= $0 %>.
+# TEMPLATE
+# puts ERB.new(template).result
+# The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto".
+# The current process is irb.
+# ```
+#
+# (The current process is `irb` because that's where we're doing these examples!)
+#
+# ### Local Binding
+#
+# The default binding is *not* sufficient for an expression
+# that refers to a a constant or variable that is not defined there:
+#
+# ```
+# Foo = 1 # Defines local constant Foo.
+# foo = 2 # Defines local variable foo.
+# template = <<TEMPLATE
+# The current value of constant Foo is <%= Foo %>.
+# The current value of variable foo is <%= foo %>.
+# The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>.
+# The current process is <%= $0 %>.
+# TEMPLATE
+# erb = ERB.new(template)
+# ```
+#
+# This call below raises `NameError` because although `Foo` and `foo` are defined locally,
+# they are not defined in the default binding:
+#
+# ```
+# erb.result # Raises NameError.
+# ```
+#
+# To make the locally-defined constants and variables available,
+# you can call #result with the local binding:
+#
+# ```
+# puts erb.result(binding)
+# The current value of constant Foo is 1.
+# The current value of variable foo is 2.
+# The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto".
+# The current process is irb.
+# ```
+#
+# ### Augmented Binding
+#
+# Another way to make variable bindings (but not constant bindings) available
+# is to use method #result_with_hash(hash);
+# the passed hash has name/value pairs that are to be used to define and assign variables
+# in a copy of the default binding:
+#
+# ```
+# template = <<TEMPLATE
+# The current value of variable bar is <%= bar %>.
+# The current value of variable baz is <%= baz %>.
+# The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>.
+# The current process is <%= $0 %>.
+# TEMPLATE
+# erb = ERB.new(template)
+# ```
+#
+# Both of these calls raise `NameError`, because `bar` and `baz`
+# are not defined in either the default binding or the local binding.
+#
+# ```
+# puts erb.result # Raises NameError.
+# puts erb.result(binding) # Raises NameError.
+# ```
+#
+# This call passes a hash that causes `bar` and `baz` to be defined
+# in a new binding (derived from #new_toplevel):
+#
+# ```
+# hash = {bar: 3, baz: 4}
+# puts erb.result_with_hash(hash)
+# The current value of variable bar is 3.
+# The current value of variable baz is 4.
+# The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto".
+# The current process is irb.
+# ```
+#
+# ## Tags
+#
+# The examples above use expression tags.
+# These are the tags available in \ERB:
+#
+# - [Expression tag][expression tags]: the tag contains a Ruby expression;
+# in the result, the entire tag is to be replaced with the run-time value of the expression.
+# - [Execution tag][execution tags]: the tag contains Ruby code;
+# in the result, the entire tag is to be replaced with the run-time value of the code.
+# - [Comment tag][comment tags]: the tag contains comment code;
+# in the result, the entire tag is to be omitted.
+#
+# ### Expression Tags
+#
+# You can embed a Ruby expression in a template using an *expression tag*.
+#
+# Its syntax is `<%= _expression_ %>`,
+# where *expression* is any valid Ruby expression.
+#
+# When you call method #result,
+# the method evaluates the expression and replaces the entire expression tag with the expression's value:
+#
+# ```
+# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result
+# # => "Today is Monday."
+# ERB.new('Tomorrow will be <%= Date::DAYNAMES[Date.today.wday + 1] %>.').result
+# # => "Tomorrow will be Tuesday."
+# ERB.new('Yesterday was <%= Date::DAYNAMES[Date.today.wday - 1] %>.').result
+# # => "Yesterday was Sunday."
+# ```
+#
+# Note that whitespace before and after the expression
+# is allowed but not required,
+# and that such whitespace is stripped from the result.
+#
+# ```
+# ERB.new('My appointment is on <%=Date::DAYNAMES[Date.today.wday + 2]%>.').result
+# # => "My appointment is on Wednesday."
+# ERB.new('My appointment is on <%= Date::DAYNAMES[Date.today.wday + 2] %>.').result
+# # => "My appointment is on Wednesday."
+# ```
+#
+# ### Execution Tags
+#
+# You can embed Ruby executable code in template using an *execution tag*.
+#
+# Its syntax is `<% _code_ %>`,
+# where *code* is any valid Ruby code.
+#
+# When you call method #result,
+# the method executes the code and removes the entire execution tag
+# (generating no text in the result):
+#
+# ```
+# ERB.new('foo <% Dir.chdir("C:/") %> bar').result # => "foo bar"
+# ```
+#
+# Whitespace before and after the embedded code is optional:
+#
+# ```
+# ERB.new('foo <%Dir.chdir("C:/")%> bar').result # => "foo bar"
+# ```
+#
+# You can interleave text with execution tags to form a control structure
+# such as a conditional, a loop, or a `case` statements.
+#
+# Conditional:
+#
+# ```
+# template = <<TEMPLATE
+# <% if verbosity %>
+# An error has occurred.
+# <% else %>
+# Oops!
+# <% end %>
+# TEMPLATE
+# erb = ERB.new(template)
+# verbosity = true
+# erb.result(binding)
+# # => "\nAn error has occurred.\n\n"
+# verbosity = false
+# erb.result(binding)
+# # => "\nOops!\n\n"
+# ```
+#
+# Note that the interleaved text may itself contain expression tags:
+#
+# Loop:
+#
+# ```
+# template = <<TEMPLATE
+# <% Date::ABBR_DAYNAMES.each do |dayname| %>
+# <%= dayname %>
+# <% end %>
+# TEMPLATE
+# ERB.new(template).result
+# # => "\nSun\n\nMon\n\nTue\n\nWed\n\nThu\n\nFri\n\nSat\n\n"
+# ```
+#
+# Other, non-control, lines of Ruby code may be interleaved with the text,
+# and the Ruby code may itself contain regular Ruby comments:
+#
+# ```
+# template = <<TEMPLATE
+# <% 3.times do %>
+# <%= Time.now %>
+# <% sleep(1) # Let's make the times different. %>
+# <% end %>
+# TEMPLATE
+# ERB.new(template).result
+# # => "\n2025-09-09 11:36:02 -0500\n\n\n2025-09-09 11:36:03 -0500\n\n\n2025-09-09 11:36:04 -0500\n\n\n"
+# ```
+#
+# The execution tag may also contain multiple lines of code:
+#
+# ```
+# template = <<TEMPLATE
+# <%
+# (0..2).each do |i|
+# (0..2).each do |j|
+# %>
+# * <%=i%>,<%=j%>
+# <%
+# end
+# end
+# %>
+# TEMPLATE
+# ERB.new(template).result
+# # => "\n* 0,0\n\n* 0,1\n\n* 0,2\n\n* 1,0\n\n* 1,1\n\n* 1,2\n\n* 2,0\n\n* 2,1\n\n* 2,2\n\n"
+# ```
+#
+# #### Shorthand Format for Execution Tags
+#
+# You can use keyword argument `trim_mode: '%'` to enable a shorthand format for execution tags;
+# this example uses the shorthand format `% _code_` instead of `<% _code_ %>`:
+#
+# ```
+# template = <<TEMPLATE
+# % priorities.each do |priority|
+# * <%= priority %>
+# % end
+# TEMPLATE
+# erb = ERB.new(template, trim_mode: '%')
+# priorities = [ 'Run Ruby Quiz',
+# 'Document Modules',
+# 'Answer Questions on Ruby Talk' ]
+# puts erb.result(binding)
+# * Run Ruby Quiz
+# * Document Modules
+# * Answer Questions on Ruby Talk
+# ```
+#
+# Note that in the shorthand format, the character `'%'` must be the first character in the code line
+# (no leading whitespace).
+#
+# #### Suppressing Unwanted Blank Lines
+#
+# With keyword argument `trim_mode` not given,
+# all blank lines go into the result:
+#
+# ```
+# template = <<TEMPLATE
+# <% if true %>
+# <%= RUBY_VERSION %>
+# <% end %>
+# TEMPLATE
+# ERB.new(template).result.lines.each {|line| puts line.inspect }
+# "\n"
+# "3.4.5\n"
+# "\n"
+# ```
+#
+# You can give `trim_mode: '-'`, you can suppress each blank line
+# whose source line ends with `-%>` (instead of `%>`):
+#
+# ```
+# template = <<TEMPLATE
+# <% if true -%>
+# <%= RUBY_VERSION %>
+# <% end -%>
+# TEMPLATE
+# ERB.new(template, trim_mode: '-').result.lines.each {|line| puts line.inspect }
+# "3.4.5\n"
+# ```
+#
+# It is an error to use the trailing `'-%>'` notation without `trim_mode: '-'`:
+#
+# ```
+# ERB.new(template).result.lines.each {|line| puts line.inspect } # Raises SyntaxError.
+# ```
+#
+# #### Suppressing Unwanted Newlines
+#
+# Consider this template:
+#
+# ```
+# template = <<TEMPLATE
+# <% RUBY_VERSION %>
+# <%= RUBY_VERSION %>
+# foo <% RUBY_VERSION %>
+# foo <%= RUBY_VERSION %>
+# TEMPLATE
+# ```
+#
+# With keyword argument `trim_mode` not given, all newlines go into the result:
+#
+# ```
+# ERB.new(template).result.lines.each {|line| puts line.inspect }
+# "\n"
+# "3.4.5\n"
+# "foo \n"
+# "foo 3.4.5\n"
+# ```
+#
+# You can give `trim_mode: '>'` to suppress the trailing newline
+# for each line that ends with `'%>'` (regardless of its beginning):
+#
+# ```
+# ERB.new(template, trim_mode: '>').result.lines.each {|line| puts line.inspect }
+# "3.4.5foo foo 3.4.5"
+# ```
+#
+# You can give `trim_mode: '<>'` to suppress the trailing newline
+# for each line that both begins with `'<%'` and ends with `'%>'`:
+#
+# ```
+# ERB.new(template, trim_mode: '<>').result.lines.each {|line| puts line.inspect }
+# "3.4.5foo \n"
+# "foo 3.4.5\n"
+# ```
+#
+# #### Combining Trim Modes
+#
+# You can combine certain trim modes:
+#
+# - `'%-'`: Enable shorthand and omit each blank line ending with `'-%>'`.
+# - `'%>'`: Enable shorthand and omit newline for each line ending with `'%>'`.
+# - `'%<>'`: Enable shorthand and omit newline for each line starting with `'<%'` and ending with `'%>'`.
+#
+# ### Comment Tags
+#
+# You can embed a comment in a template using a *comment tag*;
+# its syntax is `<%# _text_ %>`,
+# where *text* is the text of the comment.
+#
+# When you call method #result,
+# it removes the entire comment tag
+# (generating no text in the result).
+#
+# Example:
+#
+# ```
+# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.'
+# ERB.new(template).result # => "Some stuff; more stuff."
+# ```
+#
+# A comment tag may appear anywhere in the template.
+#
+# Note that the beginning of the tag must be `'<%#'`, not `'<% #'`.
+#
+# In this example, the tag begins with `'<% #'`, and so is an execution tag, not a comment tag;
+# the cited code consists entirely of a Ruby-style comment (which is of course ignored):
+#
+# ```
+# ERB.new('Some stuff;<% # Note to self: figure out what the stuff is. %> more stuff.').result
+# # => "Some stuff;"
+# ```
+#
+# ## Encodings
+#
+# An \ERB object has an [encoding][encoding],
+# which is by default the encoding of the template string;
+# the result string will also have that encoding.
#
-# James Edward Gray II
-# }.gsub(/^ /, '')
+# ```
+# template = <<TEMPLATE
+# <%# Comment. %>
+# TEMPLATE
+# erb = ERB.new(template)
+# template.encoding # => #<Encoding:UTF-8>
+# erb.encoding # => #<Encoding:UTF-8>
+# erb.result.encoding # => #<Encoding:UTF-8>
+# ```
#
-# message = ERB.new(template, trim_mode: "%<>")
+# You can specify a different encoding by adding a [magic comment][magic comments]
+# at the top of the given template:
#
-# # Set up template data.
-# to = "Community Spokesman <spokesman@ruby_community.org>"
-# priorities = [ "Run Ruby Quiz",
-# "Document Modules",
-# "Answer Questions on Ruby Talk" ]
+# ```
+# template = <<TEMPLATE
+# <%#-*- coding: Big5 -*-%>
+# <%# Comment. %>
+# TEMPLATE
+# erb = ERB.new(template)
+# template.encoding # => #<Encoding:UTF-8>
+# erb.encoding # => #<Encoding:Big5>
+# erb.result.encoding # => #<Encoding:Big5>
+# ```
#
-# # Produce result.
-# email = message.result
-# puts email
+# ## Error Reporting
#
-# <i>Generates:</i>
+# Consider this template (containing an error):
#
-# From: James Edward Gray II <james@grayproductions.net>
-# To: Community Spokesman <spokesman@ruby_community.org>
-# Subject: Addressing Needs
+# ```
+# template = '<%= nosuch %>'
+# erb = ERB.new(template)
+# ```
#
-# Community:
+# When \ERB reports an error,
+# it includes a file name (if available) and a line number;
+# the file name comes from method #filename, the line number from method #lineno.
#
-# Just wanted to send a quick note assuring that your needs are being addressed.
+# Initially, those values are `nil` and `0`, respectively;
+# these initial values are reported as `'(erb)'` and `1`, respectively:
#
-# I want you to know that my team will keep working on the issues, especially:
+# ```
+# erb.filename # => nil
+# erb.lineno # => 0
+# erb.result
+# (erb):1:in '<main>': undefined local variable or method 'nosuch' for main (NameError)
+# ```
#
-# * Run Ruby Quiz
-# * Document Modules
-# * Answer Questions on Ruby Talk
+# You can use methods #filename= and #lineno= to assign values
+# that are more meaningful in your context:
#
-# Thanks for your patience.
+# ```
+# erb.filename = 't.txt'
+# erb.lineno = 555
+# erb.result
+# t.txt:556:in '<main>': undefined local variable or method 'nosuch' for main (NameError)
+# ```
#
-# James Edward Gray II
+# You can use method #location= to set both values:
#
-# === Ruby in HTML
+# ```
+# erb.location = ['u.txt', 999]
+# erb.result
+# u.txt:1000:in '<main>': undefined local variable or method 'nosuch' for main (NameError)
+# ```
#
-# ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
-# this example to provide a special binding when the template is run, so that the instance
-# variables in the Product object can be resolved.
+# ## Plain Text with Embedded Ruby
#
-# require "erb"
+# Here's a plain-text template;
+# it uses the literal notation `'%q{ ... }'` to define the template
+# (see [%q literals][%q literals]);
+# this avoids problems with backslashes.
#
-# # Build template data class.
-# class Product
-# def initialize( code, name, desc, cost )
-# @code = code
-# @name = name
-# @desc = desc
-# @cost = cost
+# ```
+# template = %q{
+# From: James Edward Gray II <james@grayproductions.net>
+# To: <%= to %>
+# Subject: Addressing Needs
#
-# @features = [ ]
-# end
+# <%= to[/\w+/] %>:
#
-# def add_feature( feature )
-# @features << feature
-# end
+# Just wanted to send a quick note assuring that your needs are being
+# addressed.
#
-# # Support templating of member data.
-# def get_binding
-# binding
-# end
+# I want you to know that my team will keep working on the issues,
+# especially:
#
-# # ...
-# end
+# <%# ignore numerous minor requests -- focus on priorities %>
+# % priorities.each do |priority|
+# * <%= priority %>
+# % end
+#
+# Thanks for your patience.
#
-# # Create template.
-# template = %{
-# <html>
-# <head><title>Ruby Toys -- <%= @name %></title></head>
-# <body>
+# James Edward Gray II
+# }
+# ```
#
-# <h1><%= @name %> (<%= @code %>)</h1>
-# <p><%= @desc %></p>
+# The template will need these:
#
-# <ul>
-# <% @features.each do |f| %>
-# <li><b><%= f %></b></li>
-# <% end %>
-# </ul>
+# ```
+# to = 'Community Spokesman <spokesman@ruby_community.org>'
+# priorities = [ 'Run Ruby Quiz',
+# 'Document Modules',
+# 'Answer Questions on Ruby Talk' ]
+# ```
#
-# <p>
-# <% if @cost < 10 %>
-# <b>Only <%= @cost %>!!!</b>
-# <% else %>
-# Call for a price, today!
-# <% end %>
-# </p>
+# Finally, create the \ERB object and get the result
#
-# </body>
-# </html>
-# }.gsub(/^ /, '')
+# ```
+# erb = ERB.new(template, trim_mode: '%<>')
+# puts erb.result(binding)
#
-# rhtml = ERB.new(template)
+# From: James Edward Gray II <james@grayproductions.net>
+# To: Community Spokesman <spokesman@ruby_community.org>
+# Subject: Addressing Needs
#
-# # Set up template data.
-# toy = Product.new( "TZ-1002",
-# "Rubysapien",
-# "Geek's Best Friend! Responds to Ruby commands...",
-# 999.95 )
-# toy.add_feature("Listens for verbal commands in the Ruby language!")
-# toy.add_feature("Ignores Perl, Java, and all C variants.")
-# toy.add_feature("Karate-Chop Action!!!")
-# toy.add_feature("Matz signature on left leg.")
-# toy.add_feature("Gem studded eyes... Rubies, of course!")
+# Community:
#
-# # Produce result.
-# rhtml.run(toy.get_binding)
+# Just wanted to send a quick note assuring that your needs are being
+# addressed.
#
-# <i>Generates (some blank lines removed):</i>
+# I want you to know that my team will keep working on the issues,
+# especially:
#
-# <html>
-# <head><title>Ruby Toys -- Rubysapien</title></head>
-# <body>
+# * Run Ruby Quiz
+# * Document Modules
+# * Answer Questions on Ruby Talk
#
-# <h1>Rubysapien (TZ-1002)</h1>
-# <p>Geek's Best Friend! Responds to Ruby commands...</p>
+# Thanks for your patience.
#
-# <ul>
-# <li><b>Listens for verbal commands in the Ruby language!</b></li>
-# <li><b>Ignores Perl, Java, and all C variants.</b></li>
-# <li><b>Karate-Chop Action!!!</b></li>
-# <li><b>Matz signature on left leg.</b></li>
-# <li><b>Gem studded eyes... Rubies, of course!</b></li>
-# </ul>
+# James Edward Gray II
+# ```
#
-# <p>
-# Call for a price, today!
-# </p>
+# ## HTML with Embedded Ruby
#
-# </body>
-# </html>
+# This example shows an HTML template.
#
+# First, here's a custom class, `Product`:
#
-# == Notes
+# ```
+# class Product
+# def initialize(code, name, desc, cost)
+# @code = code
+# @name = name
+# @desc = desc
+# @cost = cost
+# @features = []
+# end
#
-# There are a variety of templating solutions available in various Ruby projects.
-# For example, RDoc, distributed with Ruby, uses its own template engine, which
-# can be reused elsewhere.
+# def add_feature(feature)
+# @features << feature
+# end
#
-# Other popular engines could be found in the corresponding
-# {Category}[https://www.ruby-toolbox.com/categories/template_engines] of
-# The Ruby Toolbox.
+# # Support templating of member data.
+# def get_binding
+# binding
+# end
+#
+# end
+# ```
+#
+# The template below will need these values:
+#
+# ```
+# toy = Product.new('TZ-1002',
+# 'Rubysapien',
+# "Geek's Best Friend! Responds to Ruby commands...",
+# 999.95
+# )
+# toy.add_feature('Listens for verbal commands in the Ruby language!')
+# toy.add_feature('Ignores Perl, Java, and all C variants.')
+# toy.add_feature('Karate-Chop Action!!!')
+# toy.add_feature('Matz signature on left leg.')
+# toy.add_feature('Gem studded eyes... Rubies, of course!')
+# ```
+#
+# Here's the HTML:
+#
+# ```
+# template = <<TEMPLATE
+# <html>
+# <head><title>Ruby Toys -- <%= @name %></title></head>
+# <body>
+# <h1><%= @name %> (<%= @code %>)</h1>
+# <p><%= @desc %></p>
+# <ul>
+# <% @features.each do |f| %>
+# <li><b><%= f %></b></li>
+# <% end %>
+# </ul>
+# <p>
+# <% if @cost < 10 %>
+# <b>Only <%= @cost %>!!!</b>
+# <% else %>
+# Call for a price, today!
+# <% end %>
+# </p>
+# </body>
+# </html>
+# TEMPLATE
+# ```
+#
+# Finally, create the \ERB object and get the result (omitting some blank lines):
+#
+# ```
+# erb = ERB.new(template)
+# puts erb.result(toy.get_binding)
+# <html>
+# <head><title>Ruby Toys -- Rubysapien</title></head>
+# <body>
+# <h1>Rubysapien (TZ-1002)</h1>
+# <p>Geek's Best Friend! Responds to Ruby commands...</p>
+# <ul>
+# <li><b>Listens for verbal commands in the Ruby language!</b></li>
+# <li><b>Ignores Perl, Java, and all C variants.</b></li>
+# <li><b>Karate-Chop Action!!!</b></li>
+# <li><b>Matz signature on left leg.</b></li>
+# <li><b>Gem studded eyes... Rubies, of course!</b></li>
+# </ul>
+# <p>
+# Call for a price, today!
+# </p>
+# </body>
+# </html>
+# ```
+#
+#
+# ## Other Template Processors
+#
+# Various Ruby projects have their own template processors.
+# The Ruby Processing System [RDoc][rdoc], for example, has one that can be used elsewhere.
+#
+# Other popular template processors may found in the [Template Engines][template engines] page
+# of the Ruby Toolbox.
+#
+# [%q literals]: https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-25q-3A+Non-Interpolable+String+Literals
+# [augmented binding]: rdoc-ref:ERB@Augmented+Binding
+# [binding object]: https://docs.ruby-lang.org/en/master/Binding.html
+# [comment tags]: rdoc-ref:ERB@Comment+Tags
+# [default binding]: rdoc-ref:ERB@Default+Binding
+# [encoding]: https://docs.ruby-lang.org/en/master/Encoding.html
+# [execution tags]: rdoc-ref:ERB@Execution+Tags
+# [expression tags]: rdoc-ref:ERB@Expression+Tags
+# [kernel#binding]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-binding
+# [local binding]: rdoc-ref:ERB@Local+Binding
+# [magic comments]: https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-Magic+Comments
+# [rdoc]: https://ruby.github.io/rdoc
+# [sprintf]: https://docs.ruby-lang.org/en/master/Kernel.html#method-i-sprintf
+# [template engines]: https://www.ruby-toolbox.com/categories/template_engines
+# [template processor]: https://en.wikipedia.org/wiki/Template_processor
#
class ERB
- Revision = '$Date:: $' # :nodoc: #'
- deprecate_constant :Revision
-
- # Returns revision information for the erb.rb module.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # self.version -> string
+ #
+ # Returns the string \ERB version.
def self.version
VERSION
end
+ # :markup: markdown
#
- # Constructs a new ERB object with the template specified in _str_.
- #
- # An ERB object works by building a chunk of Ruby code that will output
- # the completed template when run.
+ # :call-seq:
+ # ERB.new(template, trim_mode: nil, eoutvar: '_erbout')
#
- # If _trim_mode_ is passed a String containing one or more of the following
- # modifiers, ERB will adjust its code generation as listed:
+ # Returns a new \ERB object containing the given string +template+.
#
- # % enables Ruby code processing for lines beginning with %
- # <> omit newline for lines starting with <% and ending in %>
- # > omit newline for lines ending in %>
- # - omit blank lines ending in -%>
+ # For details about `template`, its embedded tags, and generated results, see ERB.
#
- # _eoutvar_ can be used to set the name of the variable ERB will build up
- # its output in. This is useful when you need to run multiple ERB
- # templates through the same binding and/or when you want to control where
- # output ends up. Pass the name of the variable to be used inside a String.
+ # **Keyword Argument `trim_mode`**
#
- # === Example
+ # You can use keyword argument `trim_mode: '%'`
+ # to enable the [shorthand format][shorthand format] for execution tags.
#
- # require "erb"
+ # This value allows [blank line control][blank line control]:
#
- # # build data class
- # class Listings
- # PRODUCT = { :name => "Chicken Fried Steak",
- # :desc => "A well messaged pattie, breaded and fried.",
- # :cost => 9.95 }
+ # - `'-'`: Omit each blank line ending with `'%>'`.
#
- # attr_reader :product, :price
+ # Other values allow [newline control][newline control]:
#
- # def initialize( product = "", price = "" )
- # @product = product
- # @price = price
- # end
+ # - `'>'`: Omit newline for each line ending with `'%>'`.
+ # - `'<>'`: Omit newline for each line starting with `'<%'` and ending with `'%>'`.
#
- # def build
- # b = binding
- # # create and run templates, filling member data variables
- # ERB.new(<<~'END_PRODUCT', trim_mode: "", eoutvar: "@product").result b
- # <%= PRODUCT[:name] %>
- # <%= PRODUCT[:desc] %>
- # END_PRODUCT
- # ERB.new(<<~'END_PRICE', trim_mode: "", eoutvar: "@price").result b
- # <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
- # <%= PRODUCT[:desc] %>
- # END_PRICE
- # end
- # end
+ # You can also [combine trim modes][combine trim modes].
#
- # # setup template data
- # listings = Listings.new
- # listings.build
+ # **Keyword Argument `eoutvar`**
#
- # puts listings.product + "\n" + listings.price
+ # The string value of keyword argument `eoutvar` specifies the name of the variable
+ # that method #result uses to construct its result string;
+ # see #src.
#
- # _Generates_
+ # This is useful when you need to run multiple \ERB templates through the same binding
+ # and/or when you want to control where output ends up.
#
- # Chicken Fried Steak
- # A well massaged pattie, breaded and fried.
+ # It's good practice to choose a variable name that begins with an underscore: `'_'`.
#
- # Chicken Fried Steak -- 9.95
- # A well massaged pattie, breaded and fried.
+ # [blank line control]: rdoc-ref:ERB@Suppressing+Unwanted+Blank+Lines
+ # [combine trim modes]: rdoc-ref:ERB@Combining+Trim+Modes
+ # [newline control]: rdoc-ref:ERB@Suppressing+Unwanted+Newlines
+ # [shorthand format]: rdoc-ref:ERB@Shorthand+Format+for+Execution+Tags
#
- def initialize(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout')
- # Complex initializer for $SAFE deprecation at [Feature #14256]. Use keyword arguments to pass trim_mode or eoutvar.
- if safe_level != NOT_GIVEN
- warn 'Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.', uplevel: 1
- end
- if legacy_trim_mode != NOT_GIVEN
- warn 'Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.', uplevel: 1
- trim_mode = legacy_trim_mode
- end
- if legacy_eoutvar != NOT_GIVEN
- warn 'Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.', uplevel: 1
- eoutvar = legacy_eoutvar
- end
-
+ def initialize(str, trim_mode: nil, eoutvar: '_erbout')
compiler = make_compiler(trim_mode)
set_eoutvar(compiler, eoutvar)
@src, @encoding, @frozen_string = *compiler.compile(str)
+ @src.freeze
@filename = nil
@lineno = 0
@_init = self.class.singleton_class
end
- NOT_GIVEN = defined?(Ractor) ? Ractor.make_shareable(Object.new) : Object.new
- private_constant :NOT_GIVEN
-
- ##
- # Creates a new compiler for ERB. See ERB::Compiler.new for details
+ # :markup: markdown
+ #
+ # :call-seq:
+ # make_compiler -> erb_compiler
+ #
+ # Returns a new ERB::Compiler with the given `trim_mode`;
+ # for `trim_mode` values, see ERB.new:
+ #
+ # ```
+ # ERB.new('').make_compiler(nil)
+ # # => #<ERB::Compiler:0x000001cff9467678 @insert_cmd="print", @percent=false, @post_cmd=[], @pre_cmd=[], @put_cmd="print", @trim_mode=nil>
+ # ```
+ #
def make_compiler(trim_mode)
ERB::Compiler.new(trim_mode)
end
- # The Ruby code generated by ERB
+ # :markup: markdown
+ #
+ # Returns the Ruby code that, when executed, generates the result;
+ # the code is executed by method #result,
+ # and by its wrapper methods #result_with_hash and #run:
+ #
+ # ```
+ # template = 'The time is <%= Time.now %>.'
+ # erb = ERB.new(template)
+ # erb.src
+ # # => "#coding:UTF-8\n_erbout = +''; _erbout.<< \"The time is \".freeze; _erbout.<<(( Time.now ).to_s); _erbout.<< \".\".freeze; _erbout"
+ # erb.result
+ # # => "The time is 2025-09-18 15:58:08 -0500."
+ # ```
+ #
+ # In a more readable format:
+ #
+ # ```
+ # # puts erb.src.split('; ')
+ # # #coding:UTF-8
+ # # _erbout = +''
+ # # _erbout.<< "The time is ".freeze
+ # # _erbout.<<(( Time.now ).to_s)
+ # # _erbout.<< ".".freeze
+ # # _erbout
+ # ```
+ #
+ # Variable `_erbout` is used to store the intermediate results in the code;
+ # the name `_erbout` is the default in ERB.new,
+ # and can be changed via keyword argument `eoutvar`:
+ #
+ # ```
+ # erb = ERB.new(template, eoutvar: '_foo')
+ # puts template.src.split('; ')
+ # #coding:UTF-8
+ # _foo = +''
+ # _foo.<< "The time is ".freeze
+ # _foo.<<(( Time.now ).to_s)
+ # _foo.<< ".".freeze
+ # _foo
+ # ```
+ #
attr_reader :src
- # The encoding to eval
+ # :markup: markdown
+ #
+ # Returns the encoding of `self`;
+ # see [Encodings][encodings]:
+ #
+ # [encodings]: rdoc-ref:ERB@Encodings
+ #
attr_reader :encoding
- # The optional _filename_ argument passed to Kernel#eval when the ERB code
- # is run
+ # :markup: markdown
+ #
+ # Sets or returns the file name to be used in reporting errors;
+ # see [Error Reporting][error reporting].
+ #
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
attr_accessor :filename
- # The optional _lineno_ argument passed to Kernel#eval when the ERB code
- # is run
+ # :markup: markdown
+ #
+ # Sets or returns the line number to be used in reporting errors;
+ # see [Error Reporting][error reporting].
+ #
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
attr_accessor :lineno
+ # :markup: markdown
#
- # Sets optional filename and line number that will be used in ERB code
- # evaluation and error reporting. See also #filename= and #lineno=
- #
- # erb = ERB.new('<%= some_x %>')
- # erb.render
- # # undefined local variable or method `some_x'
- # # from (erb):1
+ # :call-seq:
+ # location = [filename, lineno] => [filename, lineno]
+ # location = filename -> filename
#
- # erb.location = ['file.erb', 3]
- # # All subsequent error reporting would use new location
- # erb.render
- # # undefined local variable or method `some_x'
- # # from file.erb:4
+ # Sets the values of #filename and, if given, #lineno;
+ # see [Error Reporting][error reporting].
#
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
def location=((filename, lineno))
@filename = filename
@lineno = lineno if lineno
end
+ # :markup: markdown
+ #
+ # :call-seq:
+ # set_eoutvar(compiler, eoutvar = '_erbout') -> [eoutvar]
#
- # Can be used to set _eoutvar_ as described in ERB::new. It's probably
- # easier to just use the constructor though, since calling this method
- # requires the setup of an ERB _compiler_ object.
+ # Sets the `eoutvar` value in the ERB::Compiler object `compiler`;
+ # returns a 1-element array containing the value of `eoutvar`:
+ #
+ # ```
+ # template = ERB.new('')
+ # compiler = template.make_compiler(nil)
+ # pp compiler
+ # #<ERB::Compiler:0x000001cff8a9aa00
+ # @insert_cmd="print",
+ # @percent=false,
+ # @post_cmd=[],
+ # @pre_cmd=[],
+ # @put_cmd="print",
+ # @trim_mode=nil>
+ # template.set_eoutvar(compiler, '_foo') # => ["_foo"]
+ # pp compiler
+ # #<ERB::Compiler:0x000001cff8a9aa00
+ # @insert_cmd="_foo.<<",
+ # @percent=false,
+ # @post_cmd=["_foo"],
+ # @pre_cmd=["_foo = +''"],
+ # @put_cmd="_foo.<<",
+ # @trim_mode=nil>
+ # ```
#
def set_eoutvar(compiler, eoutvar = '_erbout')
compiler.put_cmd = "#{eoutvar}.<<"
@@ -409,17 +977,34 @@ class ERB
compiler.post_cmd = [eoutvar]
end
- # Generate results and print them. (see ERB#result)
+ # :markup: markdown
+ #
+ # :call-seq:
+ # run(binding = new_toplevel) -> nil
+ #
+ # Like #result, but prints the result string (instead of returning it);
+ # returns `nil`.
def run(b=new_toplevel)
print self.result(b)
end
+ # :markup: markdown
#
- # Executes the generated ERB code to produce a completed template, returning
- # the results of that code.
+ # :call-seq:
+ # result(binding = new_toplevel) -> new_string
#
- # _b_ accepts a Binding object which is used to set the context of
- # code evaluation.
+ # Returns the string result formed by processing \ERB tags found in the stored template in `self`.
+ #
+ # With no argument given, uses the default binding;
+ # see [Default Binding][default binding].
+ #
+ # With argument `binding` given, uses the local binding;
+ # see [Local Binding][local binding].
+ #
+ # See also #result_with_hash.
+ #
+ # [default binding]: rdoc-ref:ERB@Default+Binding
+ # [local binding]: rdoc-ref:ERB@Local+Binding
#
def result(b=new_toplevel)
unless @_init.equal?(self.class.singleton_class)
@@ -428,8 +1013,18 @@ class ERB
eval(@src, b, (@filename || '(erb)'), @lineno)
end
- # Render a template on a new toplevel binding with local variables specified
- # by a Hash object.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # result_with_hash(hash) -> new_string
+ #
+ # Returns the string result formed by processing \ERB tags found in the stored string in `self`;
+ # see [Augmented Binding][augmented binding].
+ #
+ # See also #result.
+ #
+ # [augmented binding]: rdoc-ref:ERB@Augmented+Binding
+ #
def result_with_hash(hash)
b = new_toplevel(hash.keys)
hash.each_pair do |key, value|
@@ -438,10 +1033,22 @@ class ERB
result(b)
end
- ##
- # Returns a new binding each time *near* TOPLEVEL_BINDING for runs that do
- # not specify a binding.
-
+ # :markup: markdown
+ #
+ # :call-seq:
+ # new_toplevel(symbols) -> new_binding
+ #
+ # Returns a new binding based on `TOPLEVEL_BINDING`;
+ # used to create a default binding for a call to #result.
+ #
+ # See [Default Binding][default binding].
+ #
+ # Argument `symbols` is an array of symbols;
+ # each symbol `symbol` is defined as a new variable to hide and
+ # prevent it from overwriting a variable of the same name already
+ # defined within the binding.
+ #
+ # [default binding]: rdoc-ref:ERB@Default+Binding
def new_toplevel(vars = nil)
b = TOPLEVEL_BINDING
if vars
@@ -454,49 +1061,116 @@ class ERB
end
private :new_toplevel
- # Define _methodname_ as instance method of _mod_ from compiled Ruby source.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # def_method(module, method_signature, filename = '(ERB)') -> method_name
+ #
+ # Creates and returns a new instance method in the given module `module`;
+ # returns the method name as a symbol.
+ #
+ # The method is created from the given `method_signature`,
+ # which consists of the method name and its argument names (if any).
+ #
+ # The `filename` sets the value of #filename;
+ # see [Error Reporting][error reporting].
+ #
+ # [error reporting]: rdoc-ref:ERB@Error+Reporting
+ #
+ # ```
+ # template = '<%= arg1 %> <%= arg2 %>'
+ # erb = ERB.new(template)
+ # MyModule = Module.new
+ # erb.def_method(MyModule, 'render(arg1, arg2)') # => :render
+ # class MyClass; include MyModule; end
+ # MyClass.new.render('foo', 123) # => "foo 123"
+ # ```
#
- # example:
- # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
- # erb = ERB.new(File.read(filename))
- # erb.def_method(MyClass, 'render(arg1, arg2)', filename)
- # print MyClass.new.render('foo', 123)
def def_method(mod, methodname, fname='(ERB)')
+ unless @_init.equal?(self.class.singleton_class)
+ raise ArgumentError, "not initialized"
+ end
src = self.src.sub(/^(?!#|$)/) {"def #{methodname}\n"} << "\nend\n"
mod.module_eval do
eval(src, binding, fname, -1)
end
end
- # Create unnamed module, define _methodname_ as instance method of it, and return it.
- #
- # example:
- # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
- # erb = ERB.new(File.read(filename))
- # erb.filename = filename
- # MyModule = erb.def_module('render(arg1, arg2)')
- # class MyClass
- # include MyModule
- # end
+ # :markup: markdown
+ #
+ # :call-seq:
+ # def_module(method_name = 'erb') -> new_module
+ #
+ # Returns a new nameless module that has instance method `method_name`.
+ #
+ # ```
+ # template = '<%= arg1 %> <%= arg2 %>'
+ # erb = ERB.new(template)
+ # MyModule = template.def_module('render(arg1, arg2)')
+ # class MyClass
+ # include MyModule
+ # end
+ # MyClass.new.render('foo', 123)
+ # # => "foo 123"
+ # ```
+ #
def def_module(methodname='erb')
mod = Module.new
def_method(mod, methodname, @filename || '(ERB)')
mod
end
- # Define unnamed class which has _methodname_ as instance method, and return it.
+ # :markup: markdown
+ #
+ # :call-seq:
+ # def_class(super_class = Object, method_name = 'result') -> new_class
+ #
+ # Returns a new nameless class whose superclass is `super_class`,
+ # and which has instance method `method_name`.
+ #
+ # Create a template from HTML that has embedded expression tags that use `@arg1` and `@arg2`:
+ #
+ # ```
+ # html = <<TEMPLATE
+ # <html>
+ # <body>
+ # <p><%= @arg1 %></p>
+ # <p><%= @arg2 %></p>
+ # </body>
+ # </html>
+ # TEMPLATE
+ # template = ERB.new(html)
+ # ```
+ #
+ # Create a base class that has `@arg1` and `@arg2`:
#
- # example:
- # class MyClass_
- # def initialize(arg1, arg2)
- # @arg1 = arg1; @arg2 = arg2
- # end
+ # ```
+ # class MyBaseClass
+ # def initialize(arg1, arg2)
+ # @arg1 = arg1
+ # @arg2 = arg2
# end
- # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
- # erb = ERB.new(File.read(filename))
- # erb.filename = filename
- # MyClass = erb.def_class(MyClass_, 'render()')
- # print MyClass.new('foo', 123).render()
+ # end
+ # ```
+ #
+ # Use method #def_class to create a subclass that has method `:render`:
+ #
+ # ```
+ # MySubClass = template.def_class(MyBaseClass, :render)
+ # ```
+ #
+ # Generate the result:
+ #
+ # ```
+ # puts MySubClass.new('foo', 123).render
+ # <html>
+ # <body>
+ # <p>foo</p>
+ # <p>123</p>
+ # </body>
+ # </html>
+ # ```
+ #
def def_class(superklass=Object, methodname='result')
cls = Class.new(superklass)
def_method(cls, methodname, @filename || '(ERB)')
diff --git a/lib/erb/compiler.rb b/lib/erb/compiler.rb
index 74947a9a5f..6d70288b4f 100644
--- a/lib/erb/compiler.rb
+++ b/lib/erb/compiler.rb
@@ -225,7 +225,7 @@ class ERB::Compiler # :nodoc:
end
end
- ERB_STAG = %w(<%= <%# <%)
+ ERB_STAG = %w(<%= <%# <%).freeze
def is_erb_stag?(s)
ERB_STAG.member?(s)
end
@@ -472,7 +472,16 @@ class ERB::Compiler # :nodoc:
return enc, frozen
end
+ # :stopdoc:
+ WARNING_UPLEVEL = Class.new {
+ attr_reader :c
+ def initialize from
+ @c = caller.length - from.length
+ end
+ }.new(caller(0)).c
+ private_constant :WARNING_UPLEVEL
+
def warn_invalid_trim_mode(mode, uplevel:)
- warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + 1
+ warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + WARNING_UPLEVEL
end
end
diff --git a/lib/erb/def_method.rb b/lib/erb/def_method.rb
index aee989a926..e503b37140 100644
--- a/lib/erb/def_method.rb
+++ b/lib/erb/def_method.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-#--
+
# ERB::DefMethod
#
# Utility module to define eRuby script as instance method.
diff --git a/lib/erb/erb.gemspec b/lib/erb/erb.gemspec
new file mode 100644
index 0000000000..70113a2a04
--- /dev/null
+++ b/lib/erb/erb.gemspec
@@ -0,0 +1,37 @@
+begin
+ require_relative 'lib/erb/version'
+rescue LoadError
+ # for Ruby core repository
+ require_relative 'version'
+end
+
+Gem::Specification.new do |spec|
+ spec.name = 'erb'
+ spec.version = ERB::VERSION
+ spec.authors = ['Masatoshi SEKI', 'Takashi Kokubun']
+ spec.email = ['seki@ruby-lang.org', 'k0kubun@ruby-lang.org']
+
+ 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.}
+ spec.homepage = 'https://github.com/ruby/erb'
+ spec.licenses = ['Ruby', 'BSD-2-Clause']
+
+ spec.metadata['homepage_uri'] = spec.homepage
+ spec.metadata['source_code_uri'] = spec.homepage
+ spec.metadata['changelog_uri'] = "https://github.com/ruby/erb/blob/v#{spec.version}/NEWS.md"
+
+ spec.files = Dir.chdir(__dir__) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|\.git|\.github)/}) }
+ end
+ spec.bindir = 'libexec'
+ spec.executables = ['erb']
+ spec.require_paths = ['lib']
+
+ spec.required_ruby_version = '>= 3.2.0'
+
+ if RUBY_ENGINE == 'jruby'
+ spec.platform = 'java'
+ else
+ spec.extensions = ['ext/erb/escape/extconf.rb']
+ end
+end
diff --git a/lib/erb/util.rb b/lib/erb/util.rb
index 1d2a36275d..d7d69eb4f1 100644
--- a/lib/erb/util.rb
+++ b/lib/erb/util.rb
@@ -1,18 +1,25 @@
# frozen_string_literal: true
-#--
-# ERB::Escape
-#
-# A subset of ERB::Util. Unlike ERB::Util#html_escape, we expect/hope
-# Rails will not monkey-patch ERB::Escape#html_escape.
+
+# Load CGI.escapeHTML and CGI.escapeURIComponent.
+# CRuby:
+# cgi.gem v0.1.0+ (Ruby 2.7-3.4) and Ruby 4.0+ stdlib have 'cgi/escape' and CGI.escapeHTML.
+# cgi.gem v0.3.3+ (Ruby 3.2-3.4) and Ruby 4.0+ stdlib have CGI.escapeURIComponent.
+# JRuby: cgi.gem has a Java extension 'cgi/escape'.
+# TruffleRuby: lib/truffle/cgi/escape.rb requires 'cgi/util'.
+require 'cgi/escape'
+
+# Load or define ERB::Escape#html_escape.
+# We don't build the C extension 'cgi/escape' for JRuby, TruffleRuby, and WASM.
+# miniruby (used by CRuby build scripts) also fails to load erb/escape.so.
begin
- # We don't build the C extension for JRuby, TruffleRuby, and WASM
- if $LOAD_PATH.resolve_feature_path('erb/escape')
- require 'erb/escape'
- end
-rescue LoadError # resolve_feature_path raises LoadError on TruffleRuby 22.3.0
-end
-unless defined?(ERB::Escape)
+ require 'erb/escape'
+rescue LoadError
+ # ERB::Escape
+ #
+ # A subset of ERB::Util. Unlike ERB::Util#html_escape, we expect/hope
+ # Rails will not monkey-patch ERB::Escape#html_escape.
module ERB::Escape
+ # :stopdoc:
def html_escape(s)
CGI.escapeHTML(s.to_s)
end
@@ -20,7 +27,6 @@ unless defined?(ERB::Escape)
end
end
-#--
# ERB::Util
#
# A utility module for conversion routines, often handy in HTML generation.
@@ -42,20 +48,28 @@ module ERB::Util
alias h html_escape
module_function :h
- #
- # A utility method for encoding the String _s_ as a URL.
- #
- # require "erb"
- # include ERB::Util
- #
- # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
- #
- # _Generates_
- #
- # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
- #
- def url_encode(s)
- CGI.escapeURIComponent(s.to_s)
+ if CGI.respond_to?(:escapeURIComponent)
+ #
+ # A utility method for encoding the String _s_ as a URL.
+ #
+ # require "erb"
+ # include ERB::Util
+ #
+ # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
+ #
+ # _Generates_
+ #
+ # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
+ #
+ def url_encode(s)
+ CGI.escapeURIComponent(s.to_s)
+ end
+ else # cgi.gem <= v0.3.2
+ def url_encode(s)
+ s.to_s.b.gsub(/[^a-zA-Z0-9_\-.~]/n) do |m|
+ sprintf("%%%02X", m.unpack1("C"))
+ end
+ end
end
alias u url_encode
module_function :u
diff --git a/lib/erb/version.rb b/lib/erb/version.rb
index b5fe39b330..fde4a2776a 100644
--- a/lib/erb/version.rb
+++ b/lib/erb/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
class ERB
- VERSION = '4.0.4'
- private_constant :VERSION
+ # The string \ERB version.
+ VERSION = '6.0.4'
end
diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb
index 14e0ce5785..5fffe5ec34 100644
--- a/lib/error_highlight/base.rb
+++ b/lib/error_highlight/base.rb
@@ -1,13 +1,13 @@
require_relative "version"
module ErrorHighlight
- # Identify the code fragment at that a given exception occurred.
+ # Identify the code fragment where a given exception occurred.
#
# Options:
#
# point_type: :name | :args
- # :name (default) points the method/variable name that the exception occurred.
- # :args points the arguments of the method call that the exception occurred.
+ # :name (default) points to the method/variable name where the exception occurred.
+ # :args points to the arguments of the method call where the exception occurred.
#
# backtrace_location: Thread::Backtrace::Location
# It locates the code fragment of the given backtrace_location.
@@ -28,7 +28,7 @@ module ErrorHighlight
# Currently, ErrorHighlight.spot only supports a single-line code fragment.
# Therefore, if the return value is not nil, first_lineno and last_lineno will have
# the same value. If the relevant code fragment spans multiple lines
- # (e.g., Array#[] of +ary[(newline)expr(newline)]+), the method will return nil.
+ # (e.g., Array#[] of <tt>ary[(newline)expr(newline)]</tt>), the method will return nil.
# This restriction may be removed in the future.
def self.spot(obj, **opts)
case obj
@@ -113,7 +113,7 @@ module ErrorHighlight
snippet = @node.script_lines[lineno - 1 .. last_lineno - 1].join("")
snippet += "\n" unless snippet.end_with?("\n")
- # It require some work to support Unicode (or multibyte) characters.
+ # It requires some work to support Unicode (or multibyte) characters.
# Tentatively, we stop highlighting if the code snippet has non-ascii characters.
# See https://github.com/ruby/error_highlight/issues/4
raise NonAscii unless snippet.ascii_only?
@@ -122,56 +122,51 @@ 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
- # 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`.
- case @node.type
- when :COLON2
- 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
- when :constant_path_node
- subnodes = []
- node = @node
-
- begin
- subnodes << node if node.name == @name
- end while (node = node.parent).is_a?(Prism::ConstantPathNode)
-
- if node.is_a?(Prism::ConstantReadNode) && node.name == @name
+ # 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`.
+ case @node.type
+ when :COLON2
+ 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
+ when :constant_path_node
+ subnodes = []
+ node = @node
+
+ begin
+ subnodes << node if node.name == @name
+ end while (node = node.parent).is_a?(Prism::ConstantPathNode)
+
+ if node.is_a?(Prism::ConstantReadNode) && node.name == @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
end
case @node.type
@@ -239,6 +234,20 @@ module ErrorHighlight
when :OP_CDECL
spot_op_cdecl
+ when :DEFN
+ raise NotImplementedError if @point_type != :name
+ spot_defn
+
+ when :DEFS
+ raise NotImplementedError if @point_type != :name
+ spot_defs
+
+ when :LAMBDA
+ spot_lambda
+
+ when :ITER
+ spot_iter
+
when :call_node
case @point_type
when :name
@@ -280,6 +289,30 @@ module ErrorHighlight
when :constant_path_operator_write_node
prism_spot_constant_path_operator_write
+ when :def_node
+ case @point_type
+ when :name
+ prism_spot_def_for_name
+ when :args
+ raise NotImplementedError
+ end
+
+ when :lambda_node
+ case @point_type
+ when :name
+ prism_spot_lambda_for_name
+ when :args
+ raise NotImplementedError
+ end
+
+ when :block_node
+ case @point_type
+ when :name
+ prism_spot_block_for_name
+ when :args
+ raise NotImplementedError
+ end
+
end
if @snippet && @beg_column && @end_column && @beg_column < @end_column
@@ -471,7 +504,6 @@ module ErrorHighlight
def spot_fcall_for_args
_mid, nd_args = @node.children
if nd_args && nd_args.first_lineno == nd_args.last_lineno
- # binary operator
fetch_line(nd_args.first_lineno)
@beg_column = nd_args.first_column
@end_column = nd_args.last_column
@@ -621,6 +653,55 @@ module ErrorHighlight
end
end
+ # Example:
+ # def bar; end
+ # ^^^
+ def spot_defn
+ mid, = @node.children
+ fetch_line(@node.first_lineno)
+ if @snippet.match(/\Gdef\s+(#{ Regexp.quote(mid) }\b)/, @node.first_column)
+ @beg_column = $~.begin(1)
+ @end_column = $~.end(1)
+ end
+ end
+
+ # Example:
+ # def Foo.bar; end
+ # ^^^^
+ def spot_defs
+ nd_recv, mid, = @node.children
+ fetch_line(nd_recv.last_lineno)
+ if @snippet.match(/\G\s*(\.\s*#{ Regexp.quote(mid) }\b)/, nd_recv.last_column)
+ @beg_column = $~.begin(1)
+ @end_column = $~.end(1)
+ end
+ end
+
+ # Example:
+ # -> { ... }
+ # ^^
+ def spot_lambda
+ fetch_line(@node.first_lineno)
+ if @snippet.match(/\G->/, @node.first_column)
+ @beg_column = $~.begin(0)
+ @end_column = $~.end(0)
+ end
+ end
+
+ # Example:
+ # lambda { ... }
+ # ^
+ # define_method :foo do
+ # ^^
+ def spot_iter
+ _nd_fcall, nd_scope = @node.children
+ fetch_line(nd_scope.first_lineno)
+ if @snippet.match(/\G(?:do\b|\{)/, nd_scope.first_column)
+ @beg_column = $~.begin(0)
+ @end_column = $~.end(0)
+ end
+ end
+
def fetch_line(lineno)
@beg_lineno = @end_lineno = lineno
@snippet = @fetch[lineno]
@@ -826,6 +907,31 @@ module ErrorHighlight
prism_location(@node.binary_operator_loc.chop)
end
end
+
+ # Example:
+ # def foo()
+ # ^^^
+ def prism_spot_def_for_name
+ location = @node.name_loc
+ location = @node.operator_loc.join(location) if @node.operator_loc
+ prism_location(location)
+ end
+
+ # Example:
+ # -> x, y { }
+ # ^^
+ def prism_spot_lambda_for_name
+ prism_location(@node.operator_loc)
+ end
+
+ # Example:
+ # lambda { }
+ # ^
+ # define_method :foo do |x, y|
+ # ^
+ def prism_spot_block_for_name
+ prism_location(@node.opening_loc)
+ end
end
private_constant :Spotter
diff --git a/lib/error_highlight/core_ext.rb b/lib/error_highlight/core_ext.rb
index b69093f74e..c3354f46cd 100644
--- a/lib/error_highlight/core_ext.rb
+++ b/lib/error_highlight/core_ext.rb
@@ -3,9 +3,38 @@ require_relative "formatter"
module ErrorHighlight
module CoreExt
private def generate_snippet
- spot = ErrorHighlight.spot(self)
- return "" unless spot
- return ErrorHighlight.formatter.message_for(spot)
+ if ArgumentError === self && message =~ /\A(?:wrong number of arguments|missing keyword[s]?|unknown keyword[s]?|no keywords accepted)\b/
+ locs = self.backtrace_locations
+ return "" if locs.size < 2
+ callee_loc, caller_loc = locs
+ callee_spot = ErrorHighlight.spot(self, backtrace_location: callee_loc, point_type: :name)
+ caller_spot = ErrorHighlight.spot(self, backtrace_location: caller_loc, point_type: :name)
+ if caller_spot && callee_spot &&
+ caller_loc.path == callee_loc.path &&
+ caller_loc.lineno == callee_loc.lineno &&
+ caller_spot == callee_spot
+ callee_loc = callee_spot = nil
+ end
+ ret = +"\n"
+ [["caller", caller_loc, caller_spot], ["callee", callee_loc, callee_spot]].each do |header, loc, spot|
+ out = nil
+ if loc
+ out = " #{ header }: #{ loc.path }:#{ loc.lineno }"
+ if spot
+ _, _, snippet, highlight = ErrorHighlight.formatter.message_for(spot).lines
+ out += "\n | #{ snippet } #{ highlight }"
+ else
+ # do nothing
+ end
+ end
+ ret << "\n" + out if out
+ end
+ ret
+ else
+ spot = ErrorHighlight.spot(self)
+ return "" unless spot
+ return ErrorHighlight.formatter.message_for(spot)
+ end
end
if Exception.method_defined?(:detailed_message)
diff --git a/lib/error_highlight/error_highlight.gemspec b/lib/error_highlight/error_highlight.gemspec
index b2da18df83..edfc4b776f 100644
--- a/lib/error_highlight/error_highlight.gemspec
+++ b/lib/error_highlight/error_highlight.gemspec
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/error_highlight"
spec.license = "MIT"
- spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0.dev")
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
spec.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
diff --git a/lib/error_highlight/formatter.rb b/lib/error_highlight/formatter.rb
index 5180576405..d2fad9e75c 100644
--- a/lib/error_highlight/formatter.rb
+++ b/lib/error_highlight/formatter.rb
@@ -56,11 +56,11 @@ module ErrorHighlight
end
def self.terminal_width
- # lazy load io/console, so it's not loaded when 'max_snippet_width' is set
+ # lazy load io/console to avoid loading it when 'max_snippet_width' is manually set
require "io/console"
$stderr.winsize[1] if $stderr.tty?
rescue LoadError, NoMethodError, SystemCallError
- # do not truncate when window size is not available
+ # skip truncation when terminal window size is unavailable
end
end
diff --git a/lib/error_highlight/version.rb b/lib/error_highlight/version.rb
index d7a29c7c1e..f0a5376b14 100644
--- a/lib/error_highlight/version.rb
+++ b/lib/error_highlight/version.rb
@@ -1,3 +1,3 @@
module ErrorHighlight
- VERSION = "0.7.0"
+ VERSION = "0.7.1"
end
diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index b9d683797a..0706e007ca 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -181,7 +181,7 @@ end
#
module FileUtils
# The version number.
- VERSION = "1.7.3"
+ VERSION = "1.8.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -706,11 +706,12 @@ module FileUtils
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
if relative
- return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
+ return ln_sr(src, dest, force: force, target_directory: target_directory, noop: noop, verbose: verbose)
end
- fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ fu_output_message "ln -s#{force ? 'f' : ''}#{
+ target_directory ? '' : 'T'} #{[src,dest].flatten.join ' '}" if verbose
return if noop
- fu_each_src_dest0(src, dest) do |s,d|
+ fu_each_src_dest0(src, dest, target_directory) do |s,d|
remove_file d, true if force
File.symlink s, d
end
@@ -730,42 +731,37 @@ module FileUtils
# Like FileUtils.ln_s, but create links relative to +dest+.
#
def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
- options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
- dest = File.path(dest)
- srcs = Array(src)
- link = proc do |s, target_dir_p = true|
- s = File.path(s)
- if target_dir_p
- d = File.join(destdirs = dest, File.basename(s))
+ cmd = "ln -s#{force ? 'f' : ''}#{target_directory ? '' : 'T'}" if verbose
+ fu_each_src_dest0(src, dest, target_directory) do |s,d|
+ if target_directory
+ parent = File.dirname(d)
+ destdirs = fu_split_path(parent)
+ real_ddirs = fu_split_path(File.realpath(parent))
else
- destdirs = File.dirname(d = dest)
+ destdirs ||= fu_split_path(dest)
+ real_ddirs ||= fu_split_path(File.realdirpath(dest))
end
- destdirs = fu_split_path(File.realpath(destdirs))
- if fu_starting_path?(s)
- srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
- base = fu_relative_components_from(srcdirs, destdirs)
- s = File.join(*base)
+ srcdirs = fu_split_path(s)
+ i = fu_common_components(srcdirs, destdirs)
+ n = destdirs.size - i
+ n -= 1 unless target_directory
+ link1 = fu_clean_components(*Array.new([n, 0].max, '..'), *srcdirs[i..-1])
+ begin
+ real_sdirs = fu_split_path(File.realdirpath(s)) rescue nil
+ rescue
else
- srcdirs = fu_clean_components(*fu_split_path(s))
- base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
- while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
- srcdirs.shift
- base.pop
- end
- s = File.join(*base, *srcdirs)
+ i = fu_common_components(real_sdirs, real_ddirs)
+ n = real_ddirs.size - i
+ n -= 1 unless target_directory
+ link2 = fu_clean_components(*Array.new([n, 0].max, '..'), *real_sdirs[i..-1])
+ link1 = link2 if link1.size > link2.size
end
- fu_output_message "ln -s#{options} #{s} #{d}" if verbose
+ s = File.join(link1)
+ fu_output_message [cmd, s, d].flatten.join(' ') if verbose
next if noop
remove_file d, true if force
File.symlink s, d
end
- case srcs.size
- when 0
- when 1
- link[srcs[0], target_directory && File.directory?(dest)]
- else
- srcs.each(&link)
- end
end
module_function :ln_sr
@@ -800,13 +796,13 @@ module FileUtils
# File.file?('dest1/dir1/t2.txt') # => true
# File.file?('dest1/dir1/t3.txt') # => true
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference_root: true</tt> - dereferences +src+ if it is a symbolic link.
- # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
+ # - +dereference_root+ - dereferences +src+ if it is a symbolic link (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before creating links (+false+ by default).
#
# Raises an exception if +dest+ is the path to an existing file or directory
- # and keyword argument <tt>remove_destination: true</tt> is not given.
+ # and optional argument +remove_destination+ is not given.
#
# Related: FileUtils.ln (has different options).
#
@@ -1029,12 +1025,12 @@ module FileUtils
# directories, and symbolic links;
# other file types (FIFO streams, device files, etc.) are not supported.
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference_root: true</tt> - if +src+ is a symbolic link,
- # follows the link.
- # - <tt>preserve: true</tt> - preserves file times.
- # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - +dereference_root+ - if +src+ is a symbolic link,
+ # follows the link (+false+ by default).
+ # - +preserve+ - preserves file times (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before copying files (+false+ by default).
#
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
@@ -1065,12 +1061,12 @@ module FileUtils
# FileUtils.copy_file('src0.txt', 'dest0.txt')
# File.file?('dest0.txt') # => true
#
- # Keyword arguments:
+ # Optional arguments:
#
- # - <tt>dereference: false</tt> - if +src+ is a symbolic link,
- # does not follow the link.
- # - <tt>preserve: true</tt> - preserves file times.
- # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - +dereference+ - if +src+ is a symbolic link,
+ # follows the link (+true+ by default).
+ # - +preserve+ - preserves file times (+false+ by default).
+ # - +remove_destination+ - removes +dest+ before copying files (+false+ by default).
#
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
@@ -1491,7 +1487,8 @@ module FileUtils
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def remove_dir(path, force = false)
- remove_entry path, force # FIXME?? check if it is a directory
+ raise Errno::ENOTDIR, path unless force or File.directory?(path)
+ remove_entry path, force
end
module_function :remove_dir
@@ -2475,6 +2472,10 @@ module FileUtils
def fu_each_src_dest0(src, dest, target_directory = true) #:nodoc:
if tmp = Array.try_convert(src)
+ unless target_directory or tmp.size <= 1
+ tmp = tmp.map {|f| File.path(f)} # A workaround for RBS
+ raise ArgumentError, "extra target #{tmp}"
+ end
tmp.each do |s|
s = File.path(s)
yield s, (target_directory ? File.join(dest, File.basename(s)) : dest)
@@ -2509,7 +2510,11 @@ module FileUtils
path = File.path(path)
list = []
until (parent, base = File.split(path); parent == path or parent == ".")
- list << base
+ if base != '..' and list.last == '..' and !(fu_have_symlink? && File.symlink?(path))
+ list.pop
+ else
+ list << base
+ end
path = parent
end
list << path
@@ -2517,14 +2522,14 @@ module FileUtils
end
private_module_function :fu_split_path
- def fu_relative_components_from(target, base) #:nodoc:
+ def fu_common_components(target, base) #:nodoc:
i = 0
while target[i]&.== base[i]
i += 1
end
- Array.new(base.size-i, '..').concat(target[i..-1])
+ i
end
- private_module_function :fu_relative_components_from
+ private_module_function :fu_common_components
def fu_clean_components(*comp) #:nodoc:
comp.shift while comp.first == "."
@@ -2534,7 +2539,7 @@ module FileUtils
while c = comp.shift
if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
clean.pop
- path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
+ path.sub!(%r((?<=\A|/)[^/]+/\z), "")
else
clean << c
path << c << "/"
diff --git a/lib/find.rb b/lib/find.rb
index 98a79cc76d..d9b81eb92d 100644
--- a/lib/find.rb
+++ b/lib/find.rb
@@ -3,40 +3,50 @@
# find.rb: the Find module for processing all files under a given directory.
#
+# :markup: markdown
#
-# The +Find+ module supports the top-down traversal of a set of file paths.
-#
-# For example, to total the size of all files under your home directory,
-# ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
-#
-# require 'find'
-#
-# total_size = 0
-#
-# Find.find(ENV["HOME"]) do |path|
-# if FileTest.directory?(path)
-# if File.basename(path).start_with?('.')
-# Find.prune # Don't look any further into this directory.
-# else
-# next
-# end
-# else
-# total_size += FileTest.size(path)
-# end
-# end
-#
+# \Module \Find supports the top-down traversal of entries in the file system.
module Find
+ # The version string
VERSION = "0.2.0"
+ # :markup: markdown
#
- # Calls the associated block with the name of every file and directory listed
- # as arguments, then recursively on their subdirectories, and so on.
+ # With a block given, performs a depth-first traversal of each given path in `paths`;
+ # calls the block with each found file or directory path:
#
- # Returns an enumerator if no block is given.
+ # ```ruby
+ # paths = []
+ # Find.find('bin', 'jit') {|path| paths << path }
+ # paths
+ # # =>
+ # # ["bin",
+ # # "bin/gem",
+ # # "jit",
+ # # "jit/Cargo.toml",
+ # # "jit/src",
+ # # "jit/src/lib.rs"]
+ # ```
#
- # See the +Find+ module documentation for an example.
+ # Raises an exception if a given path cannot be read.
#
+ # When keyword argument `ignore_error` is given as `true` (the default),
+ # certain exceptions during traversal are ignored (i.e., silently rescued):
+ # Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL;
+ # when given as `false`, no exceptions are rescued.
+ #
+ # Note that these exceptions may be ignored only in `Find` traversal code;
+ # an exception raised before traversal begins,
+ # or raised while in the block is not ignored.
+ # Each of the calls below raises an Errno::ENOENT exception that is not ignored:
+ #
+ # ```ruby
+ # Find.find('nosuch') { }
+ # Find.find('lib') {|entry| raise Errno::ENOENT }
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
def find(*paths, ignore_error: true) # :yield: path
block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error)
@@ -74,13 +84,26 @@ module Find
nil
end
+ # :markup: markdown
+ #
+ # call-seq:
+ # Find.prune
+ #
+ # This method is meaningful only within a block given with Find.find.
#
- # Skips the current file or directory, restarting the loop with the next
- # entry. If the current file is a directory, that directory will not be
- # recursively entered. Meaningful only within the block associated with
- # Find::find.
+ # Inside such a block,
+ # "prunes" the traversed file tree by not descending into the current directory:
#
- # See the +Find+ module documentation for an example.
+ # ```ruby
+ # files = []
+ # Find.find('.') do |path|
+ # Find.prune if File.basename(path) == 'test'
+ # next unless File.file?(path) && File.extname(path) == '.rb'
+ # files << path
+ # end
+ # files.size # => 6690
+ # files.take(3) # => ["./KNOWNBUGS.rb", "./array.rb", "./ast.rb"]
+ # ```
#
def prune
throw :prune
diff --git a/lib/forwardable.rb b/lib/forwardable.rb
index 71b4e6adad..175d6d9c6b 100644
--- a/lib/forwardable.rb
+++ b/lib/forwardable.rb
@@ -109,11 +109,11 @@
# +delegate.rb+.
#
module Forwardable
- require 'forwardable/impl'
-
# Version of +forwardable.rb+
- VERSION = "1.3.3"
+ VERSION = "1.4.0"
VERSION.freeze
+
+ # Version for backward compatibility
FORWARDABLE_VERSION = VERSION
FORWARDABLE_VERSION.freeze
@@ -190,9 +190,7 @@ module Forwardable
# If it's not a class or module, it's an instance
mod = Module === self ? self : singleton_class
- ret = mod.module_eval(&gen)
- mod.__send__(:ruby2_keywords, ali) if RUBY_VERSION >= '2.7'
- ret
+ mod.module_eval(&gen)
end
alias delegate instance_delegate
@@ -206,36 +204,33 @@ module Forwardable
if Module === obj ?
obj.method_defined?(accessor) || obj.private_method_defined?(accessor) :
obj.respond_to?(accessor, true)
- accessor = "#{accessor}()"
+ accessor = "(#{accessor}())"
end
- method_call = ".__send__(:#{method}, *args, &block)"
- if _valid_method?(method)
+ args = RUBY_VERSION >= '2.7' ? '...' : '*args, &block'
+ method_call = ".__send__(:#{method}, #{args})"
+ if method.match?(/\A[_a-zA-Z]\w*[?!]?\z/)
loc, = caller_locations(2,1)
pre = "_ ="
mesg = "#{Module === obj ? obj : obj.class}\##{ali} at #{loc.path}:#{loc.lineno} forwarding to private method "
- method_call = "#{<<-"begin;"}\n#{<<-"end;".chomp}"
- begin;
- unless defined? _.#{method}
- ::Kernel.warn #{mesg.dump}"\#{_.class}"'##{method}', uplevel: 1
- _#{method_call}
- else
- _.#{method}(*args, &block)
- end
- end;
+ method_call = <<~RUBY.chomp
+ if defined?(_.#{method})
+ _.#{method}(#{args})
+ else
+ ::Kernel.warn #{mesg.dump}"\#{_.class}"'##{method}', uplevel: 1
+ _#{method_call}
+ end
+ RUBY
end
- _compile_method("#{<<-"begin;"}\n#{<<-"end;"}", __FILE__, __LINE__+1)
- begin;
+ eval(<<~RUBY, nil, __FILE__, __LINE__ + 1)
proc do
- def #{ali}(*args, &block)
- #{pre}
- begin
- #{accessor}
- end#{method_call}
+ def #{ali}(#{args})
+ #{pre}#{accessor}
+ #{method_call}
end
end
- end;
+ RUBY
end
end
@@ -310,9 +305,7 @@ module SingleForwardable
def def_single_delegator(accessor, method, ali = method)
gen = Forwardable._delegator_method(self, accessor, method, ali)
- ret = instance_eval(&gen)
- singleton_class.__send__(:ruby2_keywords, ali) if RUBY_VERSION >= '2.7'
- ret
+ instance_eval(&gen)
end
alias delegate single_delegate
diff --git a/lib/forwardable/forwardable.gemspec b/lib/forwardable/forwardable.gemspec
index 9ad59c5f8a..1b539bcfcb 100644
--- a/lib/forwardable/forwardable.gemspec
+++ b/lib/forwardable/forwardable.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.required_ruby_version = '>= 2.4.0'
- spec.files = ["forwardable.gemspec", "lib/forwardable.rb", "lib/forwardable/impl.rb"]
+ spec.files = ["forwardable.gemspec", "lib/forwardable.rb"]
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
diff --git a/lib/forwardable/impl.rb b/lib/forwardable/impl.rb
deleted file mode 100644
index 0322c136db..0000000000
--- a/lib/forwardable/impl.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Forwardable
- # :stopdoc:
-
- def self._valid_method?(method)
- catch {|tag|
- eval("BEGIN{throw tag}; ().#{method}", binding, __FILE__, __LINE__)
- }
- rescue SyntaxError
- false
- else
- true
- end
-
- def self._compile_method(src, file, line)
- eval(src, nil, file, line)
- end
-end
diff --git a/lib/ipaddr.gemspec b/lib/ipaddr.gemspec
index 5719f83fc4..cabc9161ba 100644
--- a/lib/ipaddr.gemspec
+++ b/lib/ipaddr.gemspec
@@ -29,7 +29,7 @@ Both IPv4 and IPv6 are supported.
spec.homepage = "https://github.com/ruby/ipaddr"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.files = ["LICENSE.txt", "README.md", "ipaddr.gemspec", "lib/ipaddr.rb"]
+ spec.files = ["LICENSE.txt", "README.md", "lib/ipaddr.rb"]
spec.require_paths = ["lib"]
spec.required_ruby_version = ">= 2.4"
diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb
index a45055496c..70b804f642 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -40,7 +40,8 @@ require 'socket'
# p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
class IPAddr
- VERSION = "1.2.7"
+ # The version string
+ VERSION = "1.2.9"
# 32 bit mask for IPv4
IN4MASK = 0xffffffff
@@ -151,8 +152,22 @@ class IPAddr
return self.clone.set(addr_mask(~@addr))
end
+ # Returns a new ipaddr greater than the original address by offset
+ def +(offset)
+ self.clone.set(@addr + offset, @family)
+ end
+
+ # Returns a new ipaddr less than the original address by offset
+ def -(offset)
+ self.clone.set(@addr - offset, @family)
+ end
+
# Returns true if two ipaddrs are equal.
def ==(other)
+ if other.nil?
+ return false
+ end
+
other = coerce_other(other)
rescue
false
@@ -282,7 +297,7 @@ class IPAddr
@addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
when Socket::AF_INET6
@addr == 1 || # ::1
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
+ (@addr >> 32 == 0xffff && (
@addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
))
else
@@ -303,10 +318,10 @@ class IPAddr
@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 >> 32 == 0xffff && (
@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 & 0xfff00000 == 0xac100000 || # ::ffff:172.16.0.0/12
+ @addr & 0xffff0000 == 0xc0a80000 # ::ffff:192.168.0.0/16
))
else
raise AddressFamilyError, "unsupported address family"
@@ -324,7 +339,7 @@ class IPAddr
@addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
when Socket::AF_INET6
@addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
+ (@addr >> 32 == 0xffff && (
@addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
))
else
@@ -343,7 +358,7 @@ class IPAddr
_ipv4_compat?
end
- def _ipv4_compat?
+ def _ipv4_compat? # :nodoc:
if !ipv6? || (@addr >> 32) != 0
return false
end
@@ -357,7 +372,7 @@ class IPAddr
# into an IPv4-mapped IPv6 address.
def ipv4_mapped
if !ipv4?
- raise InvalidAddressError, "not an IPv4 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv4 address: #{to_s}"
end
clone = self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000)
@@ -369,9 +384,11 @@ class IPAddr
def ipv4_compat
warn "IPAddr\##{__callee__} is obsolete", uplevel: 1 if $VERBOSE
if !ipv4?
- raise InvalidAddressError, "not an IPv4 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv4 address: #{to_s}"
end
- return self.clone.set(@addr, Socket::AF_INET6)
+ clone = self.clone.set(@addr, Socket::AF_INET6)
+ clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000)
+ clone
end
# Returns a new ipaddr built by converting the IPv6 address into a
@@ -400,7 +417,7 @@ class IPAddr
# Returns a string for DNS reverse lookup compatible with RFC3172.
def ip6_arpa
if !ipv6?
- raise InvalidAddressError, "not an IPv6 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv6 address: #{to_s}"
end
return _reverse + ".ip6.arpa"
end
@@ -408,7 +425,7 @@ class IPAddr
# Returns a string for DNS reverse lookup compatible with RFC1886.
def ip6_int
if !ipv6?
- raise InvalidAddressError, "not an IPv6 address: #{@addr}"
+ raise InvalidAddressError, "not an IPv6 address: #{to_s}"
end
return _reverse + ".ip6.int"
end
@@ -533,6 +550,7 @@ class IPAddr
end
protected
+ # :stopdoc:
def begin_addr
@addr & @mask_addr
@@ -548,6 +566,7 @@ class IPAddr
raise AddressFamilyError, "unsupported address family"
end
end
+ #:startdoc:
# Set +@addr+, the internal stored ip address, to given +addr+. The
# parameter +addr+ is validated using the first +family+ member,
@@ -689,6 +708,7 @@ class IPAddr
end
end
+ # :stopdoc:
def coerce_other(other)
case other
when IPAddr
@@ -709,8 +729,8 @@ class IPAddr
octets = addr.split('.')
end
octets.inject(0) { |i, s|
- (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address: #{@addr}"
- (s != '0') && s.start_with?('0') and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{@addr}"
+ (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address: #{addr}"
+ (s != '0') && s.start_with?('0') and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{addr}"
i << 8 | n
}
end
@@ -727,19 +747,19 @@ class IPAddr
right = ''
when RE_IPV6ADDRLIKE_COMPRESSED
if $4
- left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{@addr}"
+ left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{left}"
addr = in_addr($~[4,4])
left = $1
right = $3 + '0:0'
else
left.count(':') <= ($1.empty? || $2.empty? ? 8 : 7) or
- raise InvalidAddressError, "invalid address: #{@addr}"
+ raise InvalidAddressError, "invalid address: #{left}"
left = $1
right = $2
addr = 0
end
else
- raise InvalidAddressError, "invalid address: #{@addr}"
+ raise InvalidAddressError, "invalid address: #{left}"
end
l = left.split(':')
r = right.split(':')
@@ -800,7 +820,7 @@ unless Socket.const_defined? :AF_INET6
class << IPSocket
private
- def valid_v6?(addr)
+ def valid_v6?(addr) # :nodoc:
case addr
when IPAddr::RE_IPV6ADDRLIKE_FULL
if $2
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index 25f3bcd750..37ee4a70d9 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -40,7 +40,7 @@ class Array # :nodoc:
end
##
-# mkmf.rb is used by Ruby C extensions to generate a Makefile which will
+# \Module \MakeMakefile is used by Ruby C extensions to generate a Makefile which will
# correctly compile and link the C extension to Ruby and a third-party
# library.
module MakeMakefile
@@ -419,7 +419,7 @@ MESSAGE
# disable ASAN leak reporting - conftest programs almost always don't bother
# to free their memory.
- envs['ASAN_OPTIONS'] = "detect_leaks=0" unless ENV.key?('ASAN_OPTIONS')
+ envs['LSAN_OPTIONS'] = "detect_leaks=0" unless ENV.key?('LSAN_OPTIONS')
return envs, expand[commands]
end
@@ -573,11 +573,16 @@ MSG
conf)
end
- def cpp_command(outfile, opt="")
+ def cpp_config(opt)
conf = cc_config(opt)
if $universal and (arch_flag = conf['ARCH_FLAG']) and !arch_flag.empty?
conf['ARCH_FLAG'] = arch_flag.gsub(/(?:\G|\s)-arch\s+\S+/, '')
end
+ conf
+ end
+
+ def cpp_command(outfile, opt="")
+ conf = cpp_config(opt)
RbConfig::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}",
conf)
end
@@ -860,7 +865,7 @@ int main() {printf("%"PRI_CONFTEST_PREFIX"#{neg ? 'd' : 'u'}\\n", conftest_const
v
}
unless strvars.empty?
- prepare << "char " << strvars.map {|v| "#{v}[1024]"}.join(", ") << "; "
+ prepare << "char " << strvars.map {|v| %[#{v}[1024] = ""]}.join(", ") << "; "
end
when nil
call = ""
@@ -926,20 +931,12 @@ SRC
xpopen(cpp_command('', opt)) do |f|
if Regexp === pat
puts(" ruby -ne 'print if #{pat.inspect}'")
- f.grep(pat) {|l|
+ !f.grep(pat) {|l|
puts "#{f.lineno}: #{l}"
- return true
- }
- false
+ }.empty?
else
puts(" egrep '#{pat}'")
- begin
- stdin = $stdin.dup
- $stdin.reopen(f)
- system("egrep", pat)
- ensure
- $stdin.reopen(stdin)
- end
+ system("egrep", pat, in: f)
end
end
ensure
@@ -2510,16 +2507,19 @@ TIMESTAMP_DIR = #{$extout && $extmk ? '$(extout)/.timestamp' : '.'}
sodir = $extout ? '$(TARGET_SO_DIR)' : '$(RUBYARCHDIR)'
n = '$(TARGET_SO_DIR)$(TARGET)'
cleanobjs = ["$(OBJS)"]
+ cleanlibs = []
if $extmk
%w[bc i s].each {|ex| cleanobjs << "$(OBJS:.#{$OBJEXT}=.#{ex})"}
end
if target
config_string('cleanobjs') {|t| cleanobjs << t.gsub(/\$\*/, "$(TARGET)#{deffile ? '-$(arch)': ''}")}
+ cleanlibs << '$(TARGET_SO)'
end
+ config_string('cleanlibs') {|t| cleanlibs << t.gsub(/\$\*/) {n}}
conf << "\
TARGET_SO_DIR =#{$extout ? " $(RUBYARCHDIR)/" : ''}
TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
-CLEANLIBS = #{'$(TARGET_SO) ' if target}#{config_string('cleanlibs') {|t| t.gsub(/\$\*/) {n}}}
+CLEANLIBS = #{cleanlibs.join(' ')}
CLEANOBJS = #{cleanobjs.join(' ')} *.bak
TARGET_SO_DIR_TIMESTAMP = #{timestamp_file(sodir, target_prefix)}
" #"
@@ -2591,7 +2591,7 @@ static: #{$extmk && !$static ? "all" : %[$(STATIC_LIB)#{$extout ? " install-rb"
dest = "#{dir}/#{File.basename(f)}"
mfile.print("do-install-rb#{sfx}: #{dest}\n")
mfile.print("#{dest}: #{f} #{timestamp_file(dir, target_prefix)}\n")
- mfile.print("\t$(Q) $(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $(@D)\n")
+ mfile.print("\t$(Q) $(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $@\n")
if defined?($installed_list) and !$extout
mfile.print("\t@echo #{dest}>>$(INSTALLED_LIST)\n")
end
@@ -3030,15 +3030,32 @@ realclean: distclean
def cc_command(opt="")
conf = cc_config(opt)
+ cxx_command(opt, conf)
RbConfig::expand("$(CXX) #$INCFLAGS #$CPPFLAGS #$CXXFLAGS #$ARCH_FLAG #{opt} -c #{CONFTEST_CXX}",
conf)
end
+ def cpp_command(outfile, opt="")
+ conf = cpp_config(opt)
+ cxx = cxx_command(opt, conf)
+ cpp = conf['CPP'].sub(/(\A|\s)#{Regexp.quote(conf['CC'])}(?=\z|\s)/) {
+ "#$1#{cxx}"
+ }
+ RbConfig::expand("#{cpp} #$INCFLAGS #$CPPFLAGS #$CXXFLAGS #{opt} #{CONFTEST_CXX} #{outfile}",
+ conf)
+ end
+
def link_command(ldflags, *opts)
conf = link_config(ldflags, *opts)
RbConfig::expand(TRY_LINK_CXX.dup, conf)
end
+ def cxx_command(opt="", conf = cc_config(opt))
+ cxx = conf['CXX']
+ raise Errno::ENOENT, "C++ compiler not found" if !cxx or cxx == 'false'
+ cxx
+ end
+
# :startdoc:
end
diff --git a/lib/monitor.rb b/lib/monitor.rb
new file mode 100644
index 0000000000..21329a5de7
--- /dev/null
+++ b/lib/monitor.rb
@@ -0,0 +1,216 @@
+# frozen_string_literal: false
+# = monitor.rb
+#
+# Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
+#
+# This library is distributed under the terms of the Ruby license.
+# You can freely distribute/modify this library.
+#
+#
+# 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
+# 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].
+#
+# == Examples
+#
+# === Simple object.extend
+#
+# require 'monitor.rb'
+#
+# buf = []
+# buf.extend(MonitorMixin)
+# empty_cond = buf.new_cond
+#
+# # consumer
+# Thread.start do
+# loop do
+# buf.synchronize do
+# empty_cond.wait_while { buf.empty? }
+# print buf.shift
+# end
+# end
+# end
+#
+# # producer
+# while line = ARGF.gets
+# buf.synchronize do
+# buf.push(line)
+# empty_cond.signal
+# end
+# 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
+# line from ARGF and pushes it into buf then calls <tt>empty_cond.signal</tt>
+# to notify the consumer thread of new data.
+#
+# === Simple Class include
+#
+# require 'monitor'
+#
+# class SynchronizedArray < Array
+#
+# include MonitorMixin
+#
+# def initialize(*args)
+# super(*args)
+# end
+#
+# alias :old_shift :shift
+# alias :old_unshift :unshift
+#
+# def shift(n=1)
+# self.synchronize do
+# self.old_shift(n)
+# end
+# end
+#
+# def unshift(item)
+# self.synchronize do
+# self.old_unshift(item)
+# end
+# end
+#
+# # other methods ...
+# end
+#
+# +SynchronizedArray+ implements an Array with synchronized access to items.
+# This Class is implemented as subclass of Array which includes the
+# MonitorMixin module.
+#
+module MonitorMixin
+ ConditionVariable = Monitor::ConditionVariable # :nodoc:
+
+ #
+ # FIXME: This isn't documented in Nutshell.
+ #
+ # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
+ # above calls while_wait and signal, this class should be documented.
+ #
+
+ def self.extend_object(obj) # :nodoc:
+ super(obj)
+ obj.__send__(:mon_initialize)
+ end
+
+ #
+ # Attempts to enter exclusive section. Returns +false+ if lock fails.
+ #
+ def mon_try_enter
+ @mon_data.try_enter
+ end
+ # For backward compatibility
+ alias try_mon_enter mon_try_enter
+
+ #
+ # Enters exclusive section.
+ #
+ def mon_enter
+ @mon_data.enter
+ end
+
+ #
+ # Leaves exclusive section.
+ #
+ def mon_exit
+ mon_check_owner
+ @mon_data.exit
+ end
+
+ #
+ # Returns true if this monitor is locked by any thread
+ #
+ def mon_locked?
+ @mon_data.mon_locked?
+ end
+
+ #
+ # Returns true if this monitor is locked by current thread.
+ #
+ def mon_owned?
+ @mon_data.mon_owned?
+ end
+
+ #
+ # Enters exclusive section and executes the block. Leaves the exclusive
+ # section automatically when the block exits. See example under
+ # +MonitorMixin+.
+ #
+ def mon_synchronize(&b)
+ @mon_data.synchronize(&b)
+ end
+ alias synchronize mon_synchronize
+
+ #
+ # Creates a new MonitorMixin::ConditionVariable associated with the
+ # Monitor object.
+ #
+ def new_cond
+ unless defined?(@mon_data)
+ mon_initialize
+ @mon_initialized_by_new_cond = true
+ end
+ return ConditionVariable.new(@mon_data)
+ end
+
+ private
+
+ # Use <tt>extend MonitorMixin</tt> or <tt>include MonitorMixin</tt> instead
+ # of this constructor. Have look at the examples above to understand how to
+ # use this module.
+ def initialize(...)
+ super
+ mon_initialize
+ end
+
+ # Initializes the MonitorMixin after being included in a class or when an
+ # object has been extended with the MonitorMixin
+ def mon_initialize
+ if defined?(@mon_data)
+ if defined?(@mon_initialized_by_new_cond)
+ return # already initialized.
+ elsif @mon_data_owner_object_id == self.object_id
+ raise ThreadError, "already initialized"
+ end
+ end
+ @mon_data = ::Monitor.new
+ @mon_data_owner_object_id = self.object_id
+ end
+
+ # Ensures that the MonitorMixin is owned by the current thread,
+ # otherwise raises an exception.
+ def mon_check_owner
+ @mon_data.mon_check_owner
+ end
+end
+
+class Monitor # :nodoc:
+ alias try_mon_enter try_enter
+ alias mon_try_enter try_enter
+ alias mon_enter enter
+ alias mon_exit exit
+ alias mon_synchronize synchronize
+end
+
+# Documentation comments:
+# - All documentation comes from Nutshell.
+# - MonitorMixin.new_cond appears in the example, but is not documented in
+# Nutshell.
+# - All the internals (internal modules Accessible and Initializable, class
+# ConditionVariable) appear in RDoc. It might be good to hide them, by
+# making them private, or marking them :nodoc:, etc.
+# - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
+# not synchronize.
+# - mon_owner is in Nutshell, but appears as an accessor in a separate module
+# here, so is hard/impossible to RDoc. Some other useful accessors
+# (mon_count and some queue stuff) are also in this module, and don't appear
+# directly in the RDoc output.
+# - in short, it may be worth changing the code layout in this file to make the
+# documentation easier
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 797de6aaf5..53295fe90c 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -37,7 +37,7 @@ module Net #:nodoc:
# 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].
+ # - {Technology}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technology].
#
# == About the Examples
#
@@ -72,7 +72,7 @@ module Net #:nodoc:
#
# - 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]
+ # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method]
# and {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
#
# Net::HTTP.start(hostname) do |http|
@@ -198,7 +198,7 @@ module Net #:nodoc:
# 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]:
+ # - {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Method]:
#
# - #get, #request_get: GET.
# - #head, #request_head: HEAD.
@@ -447,7 +447,7 @@ module Net #:nodoc:
# 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]:
+ # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Content-Encoding_2]:
#
# - <tt>'deflate'</tt>, <tt>'gzip'</tt>, or <tt>'x-gzip'</tt>:
# decompresses the body and deletes the header.
@@ -460,7 +460,7 @@ module Net #:nodoc:
#
# First, what's elsewhere. Class Net::HTTP:
#
- # - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
+ # - Inherits from {class Object}[rdoc-ref:Object#class-object-whats-here].
#
# This is a categorized summary of methods and attributes.
#
@@ -724,7 +724,7 @@ module Net #:nodoc:
class HTTP < Protocol
# :stopdoc:
- VERSION = "0.6.0"
+ VERSION = "0.9.1"
HTTPVersion = '1.1'
begin
require 'zlib'
@@ -1179,6 +1179,7 @@ module Net #:nodoc:
@debug_output = options[:debug_output]
@response_body_encoding = options[:response_body_encoding]
@ignore_eof = options[:ignore_eof]
+ @tcpsocket_supports_open_timeout = nil
@proxy_from_env = false
@proxy_uri = nil
@@ -1303,7 +1304,7 @@ module Net #:nodoc:
# 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].
+ # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Net::HTTP@Proxy+Using+ENVHTTPProxy].
attr_writer :proxy_from_env
# Sets the proxy address;
@@ -1321,6 +1322,9 @@ module Net #:nodoc:
# Sets the proxy password;
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_pass
+
+ # Sets whether the proxy uses SSL;
+ # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_use_ssl
# Returns the IP address for the connection.
@@ -1527,9 +1531,9 @@ module Net #:nodoc:
:verify_depth,
:verify_mode,
:verify_hostname,
- ] # :nodoc:
+ ].freeze # :nodoc:
- SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym } # :nodoc:
+ SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym }.freeze # :nodoc:
# Sets or returns the path to a CA certification file in PEM format.
attr_accessor :ca_file
@@ -1632,6 +1636,21 @@ module Net #:nodoc:
self
end
+ # 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.
+ def finish
+ raise IOError, 'HTTP session not yet started' unless started?
+ do_finish
+ end
+
+ # :stopdoc:
def do_start
connect
@started = true
@@ -1654,14 +1673,15 @@ module Net #:nodoc:
end
debug "opening connection to #{conn_addr}:#{conn_port}..."
- s = Timeout.timeout(@open_timeout, 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})"
+ begin
+ s = timeouted_connect(conn_addr, conn_port)
+ rescue => e
+ if (defined?(IO::TimeoutError) && e.is_a?(IO::TimeoutError)) || e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
+ e = Net::OpenTimeout.new(e)
end
- }
+ 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?
@@ -1754,23 +1774,30 @@ module Net #:nodoc:
end
private :connect
- def on_connect
+ tcp_socket_parameters = TCPSocket.instance_method(:initialize).parameters
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT = if tcp_socket_parameters != [[:rest]]
+ tcp_socket_parameters.include?([:key, :open_timeout])
+ else
+ # Use Socket.tcp to find out since there is no parameters information for TCPSocket#initialize
+ # See discussion in https://github.com/ruby/net-http/pull/224
+ Socket.method(:tcp).parameters.include?([:key, :open_timeout])
end
- private :on_connect
+ private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
- # 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.
- def finish
- raise IOError, 'HTTP session not yet started' unless started?
- do_finish
+ def timeouted_connect(conn_addr, conn_port)
+ if TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
+ else
+ Timeout.timeout(@open_timeout, Net::OpenTimeout) {
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
+ }
+ end
+ end
+ private :timeouted_connect
+
+ def on_connect
end
+ private :on_connect
def do_finish
@started = false
@@ -1821,6 +1848,8 @@ module Net #:nodoc:
}
end
+ # :startdoc:
+
class << HTTP
# Returns true if self is a class which was created by HTTP::Proxy.
def proxy_class?
@@ -1915,9 +1944,11 @@ module Net #:nodoc:
alias proxyport proxy_port #:nodoc: obsolete
private
+ # :stopdoc:
def unescape(value)
- require 'cgi/util'
+ require 'cgi/escape'
+ require 'cgi/util' unless defined?(CGI::EscapeExt)
CGI.unescape(value)
end
@@ -1942,6 +1973,7 @@ module Net #:nodoc:
path
end
end
+ # :startdoc:
#
# HTTP operations
@@ -2396,7 +2428,9 @@ module Net #:nodoc:
res
end
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
+ # :stopdoc:
+
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/.freeze # :nodoc:
def transport_request(req)
count = 0
@@ -2553,7 +2587,7 @@ module Net #:nodoc:
alias_method :D, :debug
end
- # for backward compatibility until Ruby 3.5
+ # for backward compatibility until Ruby 4.0
# https://bugs.ruby-lang.org/issues/20900
# https://github.com/bblimke/webmock/pull/1081
HTTPSession = HTTP
diff --git a/lib/net/http/exceptions.rb b/lib/net/http/exceptions.rb
index ceec8f7b0a..4342cfc0ef 100644
--- a/lib/net/http/exceptions.rb
+++ b/lib/net/http/exceptions.rb
@@ -3,7 +3,7 @@ module Net
# Net::HTTP exception class.
# You cannot use Net::HTTPExceptions directly; instead, you must use
# its subclasses.
- module HTTPExceptions
+ module HTTPExceptions # :nodoc:
def initialize(msg, res) #:nodoc:
super msg
@response = res
@@ -12,6 +12,7 @@ module Net
alias data response #:nodoc: obsolete
end
+ # :stopdoc:
class HTTPError < ProtocolError
include HTTPExceptions
end
diff --git a/lib/net/http/generic_request.rb b/lib/net/http/generic_request.rb
index 44e329a0c8..5b01ea4abd 100644
--- a/lib/net/http/generic_request.rb
+++ b/lib/net/http/generic_request.rb
@@ -19,16 +19,13 @@ class Net::HTTPGenericRequest
if URI === uri_or_path then
raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path
- hostname = uri_or_path.hostname
+ hostname = uri_or_path.host
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
@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
@@ -51,7 +48,7 @@ class Net::HTTPGenericRequest
initialize_http_header initheader
self['Accept'] ||= '*/*'
self['User-Agent'] ||= 'Ruby'
- self['Host'] ||= host if host
+ self['Host'] ||= @uri.authority if @uri
@body = nil
@body_stream = nil
@body_data = nil
@@ -102,6 +99,31 @@ class Net::HTTPGenericRequest
"\#<#{self.class} #{@method}>"
end
+ # Returns a string representation of the request with the details for pp:
+ #
+ # require 'pp'
+ # post = Net::HTTP::Post.new(uri)
+ # post.inspect # => "#<Net::HTTP::Post POST>"
+ # post.pretty_inspect
+ # # => #<Net::HTTP::Post
+ # POST
+ # path="/"
+ # headers={"accept-encoding" => ["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
+ # "accept" => ["*/*"],
+ # "user-agent" => ["Ruby"],
+ # "host" => ["www.ruby-lang.org"]}>
+ #
+ def pretty_print(q)
+ q.object_group(self) {
+ q.breakable
+ q.text @method
+ q.breakable
+ q.text "path="; q.pp @path
+ q.breakable
+ q.text "headers="; q.pp to_hash
+ }
+ end
+
##
# Don't automatically decode response content-encoding if the user indicates
# they want to handle it.
@@ -220,7 +242,7 @@ class Net::HTTPGenericRequest
end
if host = self['host']
- host.sub!(/:.*/m, '')
+ host = URI.parse("//#{host}").host # Remove a port component from the existing Host header
elsif host = @uri.host
else
host = addr
@@ -239,6 +261,8 @@ class Net::HTTPGenericRequest
private
+ # :stopdoc:
+
class Chunker #:nodoc:
def initialize(sock)
@sock = sock
@@ -260,7 +284,6 @@ class Net::HTTPGenericRequest
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
@@ -271,7 +294,6 @@ class Net::HTTPGenericRequest
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?
@@ -373,12 +395,6 @@ class Net::HTTPGenericRequest
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.
@@ -411,4 +427,3 @@ class Net::HTTPGenericRequest
end
end
-
diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index f6c36f1b5e..5dcdcc7d74 100644
--- a/lib/net/http/header.rb
+++ b/lib/net/http/header.rb
@@ -179,7 +179,9 @@
# - #each_value: Passes each string field value to the block.
#
module Net::HTTPHeader
+ # The maximum length of HTTP header keys.
MAX_KEY_LENGTH = 1024
+ # The maximum length of HTTP header values.
MAX_FIELD_LENGTH = 65536
def initialize_http_header(initheader) #:nodoc:
@@ -267,6 +269,7 @@ module Net::HTTPHeader
end
end
+ # :stopdoc:
private def set_field(key, val)
case val
when Enumerable
@@ -294,6 +297,7 @@ module Net::HTTPHeader
ary.push val
end
end
+ # :startdoc:
# Returns the array field value for the given +key+,
# or +nil+ if there is no such field;
@@ -490,7 +494,7 @@ module Net::HTTPHeader
alias canonical_each each_capitalized
- def capitalize(name)
+ def capitalize(name) # :nodoc:
name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
end
private :capitalize
@@ -957,12 +961,12 @@ module Net::HTTPHeader
@header['proxy-authorization'] = [basic_encode(account, password)]
end
- def basic_encode(account, password)
+ def basic_encode(account, password) # :nodoc:
'Basic ' + ["#{account}:#{password}"].pack('m0')
end
private :basic_encode
-# Returns whether the HTTP session is to be closed.
+ # 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 +974,7 @@ module Net::HTTPHeader
false
end
-# Returns whether the HTTP session is to be kept alive.
+ # 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 70528d58cb..d59d5c3b74 100644
--- a/lib/net/http/net-http.gemspec
+++ b/lib/net/http/net-http.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
spec.summary = %q{HTTP client api for Ruby.}
spec.description = %q{HTTP client api for Ruby.}
spec.homepage = "https://github.com/ruby/net-http"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["changelog_uri"] = spec.homepage + "/releases"
@@ -30,11 +30,10 @@ 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)}) }
- end
+ excludes = %W[/.git* /bin /test /test_sig /*file /#{File.basename(__FILE__)}]
+ spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.bindir = "exe"
spec.require_paths = ["lib"]
- spec.add_dependency "uri"
+ spec.add_dependency "uri", ">= 0.11.1"
end
diff --git a/lib/net/http/requests.rb b/lib/net/http/requests.rb
index e58057adf1..8dc79a9f66 100644
--- a/lib/net/http/requests.rb
+++ b/lib/net/http/requests.rb
@@ -19,9 +19,9 @@
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -29,6 +29,7 @@
# - Net::HTTP#get: sends +GET+ request, returns response object.
#
class Net::HTTP::Get < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'GET'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -51,15 +52,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
# - Net::HTTP#head: sends +HEAD+ request, returns response object.
#
class Net::HTTP::Head < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'HEAD'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = false
@@ -85,9 +87,9 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -95,6 +97,7 @@ end
# - Net::HTTP#post: sends +POST+ request, returns response object.
#
class Net::HTTP::Post < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'POST'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -120,9 +123,9 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
@@ -130,6 +133,7 @@ end
# - Net::HTTP#put: sends +PUT+ request, returns response object.
#
class Net::HTTP::Put < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PUT'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -153,15 +157,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#delete: sends +DELETE+ request, returns response object.
#
class Net::HTTP::Delete < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'DELETE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -184,15 +189,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#options: sends +OPTIONS+ request, returns response object.
#
class Net::HTTP::Options < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'OPTIONS'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -215,15 +221,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#trace: sends +TRACE+ request, returns response object.
#
class Net::HTTP::Trace < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'TRACE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -249,15 +256,16 @@ end
#
# - 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.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
# - Net::HTTP#patch: sends +PATCH+ request, returns response object.
#
class Net::HTTP::Patch < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -285,6 +293,7 @@ end
# - Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
#
class Net::HTTP::Propfind < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPFIND'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -308,6 +317,7 @@ end
# - Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
#
class Net::HTTP::Proppatch < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPPATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -331,6 +341,7 @@ end
# - Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
#
class Net::HTTP::Mkcol < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MKCOL'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -354,6 +365,7 @@ end
# - Net::HTTP#copy: sends +COPY+ request, returns response object.
#
class Net::HTTP::Copy < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'COPY'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -377,6 +389,7 @@ end
# - Net::HTTP#move: sends +MOVE+ request, returns response object.
#
class Net::HTTP::Move < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MOVE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -400,6 +413,7 @@ end
# - Net::HTTP#lock: sends +LOCK+ request, returns response object.
#
class Net::HTTP::Lock < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'LOCK'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -423,8 +437,8 @@ end
# - Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
#
class Net::HTTP::Unlock < Net::HTTPRequest
+ # :stopdoc:
METHOD = 'UNLOCK'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
end
-
diff --git a/lib/net/http/response.rb b/lib/net/http/response.rb
index 40de963868..8804a99c9e 100644
--- a/lib/net/http/response.rb
+++ b/lib/net/http/response.rb
@@ -153,6 +153,7 @@ class Net::HTTPResponse
end
private
+ # :stopdoc:
def read_status_line(sock)
str = sock.readline
@@ -259,7 +260,7 @@ class Net::HTTPResponse
# header.
attr_accessor :ignore_eof
- def inspect
+ def inspect # :nodoc:
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
end
diff --git a/lib/net/http/responses.rb b/lib/net/http/responses.rb
index 6f6fb8d055..941a6fed80 100644
--- a/lib/net/http/responses.rb
+++ b/lib/net/http/responses.rb
@@ -4,7 +4,9 @@
module Net
+ # Unknown HTTP response
class HTTPUnknownResponse < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -19,6 +21,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response].
#
class HTTPInformation < HTTPResponse
+ # :stopdoc:
HAS_BODY = false
EXCEPTION_TYPE = HTTPError #
end
@@ -34,6 +37,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success].
#
class HTTPSuccess < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -49,6 +53,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection].
#
class HTTPRedirection < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPRetriableError #
end
@@ -63,6 +68,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors].
#
class HTTPClientError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPClientException #
end
@@ -77,6 +83,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors].
#
class HTTPServerError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPFatalError #
end
@@ -94,6 +101,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#100].
#
class HTTPContinue < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -111,6 +119,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#101].
#
class HTTPSwitchProtocol < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -127,6 +136,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
#
class HTTPProcessing < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -145,6 +155,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
#
class HTTPEarlyHints < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -162,6 +173,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
#
class HTTPOK < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -179,6 +191,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
#
class HTTPCreated < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -196,6 +209,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
#
class HTTPAccepted < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -215,6 +229,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
#
class HTTPNonAuthoritativeInformation < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -232,6 +247,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
#
class HTTPNoContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -250,6 +266,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
#
class HTTPResetContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -268,6 +285,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
#
class HTTPPartialContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -285,6 +303,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
#
class HTTPMultiStatus < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -304,6 +323,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
#
class HTTPAlreadyReported < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -321,6 +341,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
#
class HTTPIMUsed < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -338,6 +359,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
#
class HTTPMultipleChoices < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMultipleChoice = HTTPMultipleChoices
@@ -356,6 +378,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
#
class HTTPMovedPermanently < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -373,6 +396,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
#
class HTTPFound < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMovedTemporarily = HTTPFound
@@ -390,6 +414,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
#
class HTTPSeeOther < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -407,6 +432,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
#
class HTTPNotModified < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -423,6 +449,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
#
class HTTPUseProxy < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -440,6 +467,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
#
class HTTPTemporaryRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -456,6 +484,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
#
class HTTPPermanentRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -472,6 +501,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
#
class HTTPBadRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -488,6 +518,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
#
class HTTPUnauthorized < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -504,6 +535,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
#
class HTTPPaymentRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -521,6 +553,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
#
class HTTPForbidden < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -537,6 +570,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
#
class HTTPNotFound < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -553,6 +587,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
#
class HTTPMethodNotAllowed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -570,6 +605,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
#
class HTTPNotAcceptable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -586,6 +622,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
#
class HTTPProxyAuthenticationRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -602,6 +639,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
#
class HTTPRequestTimeout < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestTimeOut = HTTPRequestTimeout
@@ -619,6 +657,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
#
class HTTPConflict < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -636,6 +675,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
#
class HTTPGone < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -653,6 +693,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
#
class HTTPLengthRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -670,6 +711,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
#
class HTTPPreconditionFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -686,6 +728,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
#
class HTTPPayloadTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
@@ -703,6 +746,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
#
class HTTPURITooLong < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestURITooLong = HTTPURITooLong
@@ -721,6 +765,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
#
class HTTPUnsupportedMediaType < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -737,6 +782,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
#
class HTTPRangeNotSatisfiable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
@@ -754,6 +800,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
#
class HTTPExpectationFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -774,6 +821,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
#
class HTTPMisdirectedRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -790,6 +838,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
#
class HTTPUnprocessableEntity < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -805,6 +854,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
#
class HTTPLocked < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -821,6 +871,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
#
class HTTPFailedDependency < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -840,6 +891,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
#
class HTTPUpgradeRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -856,6 +908,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
#
class HTTPPreconditionRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -872,6 +925,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
#
class HTTPTooManyRequests < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -889,6 +943,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
#
class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -906,6 +961,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
#
class HTTPUnavailableForLegalReasons < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
# 444 No Response - Nginx
@@ -926,6 +982,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
#
class HTTPInternalServerError < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -943,6 +1000,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
#
class HTTPNotImplemented < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -960,6 +1018,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
#
class HTTPBadGateway < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -977,6 +1036,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
#
class HTTPServiceUnavailable < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -994,6 +1054,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
#
class HTTPGatewayTimeout < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
HTTPGatewayTimeOut = HTTPGatewayTimeout
@@ -1011,6 +1072,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
#
class HTTPVersionNotSupported < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1027,6 +1089,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
#
class HTTPVariantAlsoNegotiates < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1043,6 +1106,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
#
class HTTPInsufficientStorage < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1059,6 +1123,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
#
class HTTPLoopDetected < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
# 509 Bandwidth Limit Exceeded - Apache bw/limited extension
@@ -1076,6 +1141,7 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
#
class HTTPNotExtended < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1092,19 +1158,21 @@ module Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
#
class HTTPNetworkAuthenticationRequired < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
end
class Net::HTTPResponse
+ # :stopdoc:
CODE_CLASS_TO_OBJ = {
'1' => Net::HTTPInformation,
'2' => Net::HTTPSuccess,
'3' => Net::HTTPRedirection,
'4' => Net::HTTPClientError,
'5' => Net::HTTPServerError
- }
+ }.freeze
CODE_TO_OBJ = {
'100' => Net::HTTPContinue,
'101' => Net::HTTPSwitchProtocol,
@@ -1170,5 +1238,5 @@ class Net::HTTPResponse
'508' => Net::HTTPLoopDetected,
'510' => Net::HTTPNotExtended,
'511' => Net::HTTPNetworkAuthenticationRequired,
- }
+ }.freeze
end
diff --git a/lib/net/net-protocol.gemspec b/lib/net/net-protocol.gemspec
index f9fd83f12b..2d911a966c 100644
--- a/lib/net/net-protocol.gemspec
+++ b/lib/net/net-protocol.gemspec
@@ -25,9 +25,8 @@ 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)/}) }
- end
+ excludes = %W[/.git* /bin /test /*file /#{File.basename(__FILE__)}]
+ spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.require_paths = ["lib"]
spec.add_dependency "timeout"
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 197ea09089..8c81298c0e 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -54,9 +54,20 @@ module Net # :nodoc:
s.connect
end
end
+
+ tcp_socket_parameters = TCPSocket.instance_method(:initialize).parameters
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT = if tcp_socket_parameters != [[:rest]]
+ tcp_socket_parameters.include?([:key, :open_timeout])
+ else
+ # Use Socket.tcp to find out since there is no parameters information for TCPSocket#initialize
+ # See discussion in https://github.com/ruby/net-http/pull/224
+ Socket.method(:tcp).parameters.include?([:key, :open_timeout])
+ end
+ private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
end
+ # :stopdoc:
class ProtocolError < StandardError; end
class ProtoSyntaxError < ProtocolError; end
class ProtoFatalError < ProtocolError; end
@@ -66,6 +77,7 @@ module Net # :nodoc:
class ProtoCommandError < ProtocolError; end
class ProtoRetriableError < ProtocolError; end
ProtocRetryError = ProtoRetriableError
+ # :startdoc:
##
# OpenTimeout, a subclass of Timeout::Error, is raised if a connection cannot
@@ -78,6 +90,7 @@ module Net # :nodoc:
# response cannot be read within the read_timeout.
class ReadTimeout < Timeout::Error
+ # :stopdoc:
def initialize(io = nil)
@io = io
end
@@ -97,6 +110,7 @@ module Net # :nodoc:
# response cannot be written within the write_timeout. Not raised on Windows.
class WriteTimeout < Timeout::Error
+ # :stopdoc:
def initialize(io = nil)
@io = io
end
@@ -484,6 +498,7 @@ module Net # :nodoc:
# The writer adapter class
#
class WriteAdapter
+ # :stopdoc:
def initialize(writer)
@writer = writer
end
diff --git a/lib/open-uri.rb b/lib/open-uri.rb
index de710af261..844865b13a 100644
--- a/lib/open-uri.rb
+++ b/lib/open-uri.rb
@@ -4,22 +4,25 @@ require 'stringio'
require 'time'
module URI
- # Allows the opening of various resources including URIs.
+ # Allows the opening of various resources including URIs. Example:
#
- # If the first argument responds to the 'open' method, 'open' is called on
+ # require "open-uri"
+ # URI.open("http://example.com") { |f| f.read }
+ #
+ # If the first argument responds to the +open+ method, +open+ is called on
# it with the rest of the arguments.
#
# If the first argument is a string that begins with <code>(protocol)://</code>, it is parsed by
- # URI.parse. If the parsed object responds to the 'open' method,
- # 'open' is called on it with the rest of the arguments.
+ # URI.parse. If the parsed object responds to the +open+ method,
+ # +open+ is called on it with the rest of the arguments.
#
# Otherwise, Kernel#open is called.
#
# OpenURI::OpenRead#open provides URI::HTTP#open, URI::HTTPS#open and
# URI::FTP#open, Kernel#open.
#
- # We can accept URIs and strings that begin with http://, https:// and
- # ftp://. In these cases, the opened file object is extended by OpenURI::Meta.
+ # We can accept URIs and strings that begin with <code>http://</code>, <code>https://</code> and
+ # <code>ftp://</code>. In these cases, the opened file object is extended by OpenURI::Meta.
def self.open(name, *rest, &block)
if name.respond_to?(:open)
name.open(*rest, &block)
@@ -91,8 +94,10 @@ end
module OpenURI
+ # The version string
VERSION = "0.5.0"
+ # The default options
Options = {
:proxy => true,
:proxy_http_basic_authentication => true,
@@ -394,24 +399,28 @@ module OpenURI
end
end
+ # Raised on HTTP session failure
class HTTPError < StandardError
- def initialize(message, io)
+ def initialize(message, io) # :nodoc:
super(message)
@io = io
end
+ # StringIO having the received data
attr_reader :io
end
# Raised on redirection,
# only occurs when +redirect+ option for HTTP is +false+.
class HTTPRedirect < HTTPError
- def initialize(message, io, uri)
+ def initialize(message, io, uri) # :nodoc:
super(message, io)
@uri = uri
end
+ # URI to redirect
attr_reader :uri
end
+ # Raised on too many redirection,
class TooManyRedirects < HTTPError
end
diff --git a/lib/open3/version.rb b/lib/open3/version.rb
index bfcec44ccc..322dd71e2a 100644
--- a/lib/open3/version.rb
+++ b/lib/open3/version.rb
@@ -1,3 +1,4 @@
module Open3
+ # The version string
VERSION = "0.2.1"
end
diff --git a/lib/optparse.rb b/lib/optparse.rb
index e1069b3505..97178e284b 100644
--- a/lib/optparse.rb
+++ b/lib/optparse.rb
@@ -7,6 +7,7 @@
#
# See OptionParser for documentation.
#
+require 'set' unless defined?(Set)
#--
# == Developer Documentation (not for RDoc output)
@@ -425,7 +426,9 @@
#
class OptionParser
# The version string
- OptionParser::Version = "0.7.0.dev.2"
+ VERSION = "0.8.1"
+ # An alias for compatibility
+ Version = VERSION
# :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
@@ -469,7 +472,6 @@ class OptionParser
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
@@ -559,7 +561,7 @@ class OptionParser
# 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:
+ private def parse_arg(arg) # :nodoc:
pattern or return nil, [arg]
unless m = pattern.match(arg)
yield(InvalidArgument, arg)
@@ -577,14 +579,13 @@ class OptionParser
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:
+ private def conv_arg(arg, val = []) # :nodoc:
v, = *val
if conv
val = conv.call(*val)
@@ -596,7 +597,6 @@ class OptionParser
end
return arg, block, val
end
- private :conv_arg
#
# Produces the summary text. Each line of the summary is yielded to the
@@ -880,14 +880,13 @@ class OptionParser
# +lopts+:: Long style option list.
# +nlopts+:: Negated long style options list.
#
- def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
+ private 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
@@ -1293,7 +1292,15 @@ XXX
# to $0.
#
def program_name
- @program_name || File.basename($0, '.*')
+ @program_name || strip_ext(File.basename($0))
+ end
+
+ private def strip_ext(name) # :nodoc:
+ exts = /#{
+ require "rbconfig"
+ Regexp.union(*RbConfig::CONFIG["EXECUTABLE_EXTS"]&.split(" "))
+ }\z/o
+ name.sub(exts, "")
end
# for experimental cascading :-)
@@ -1448,14 +1455,13 @@ XXX
# +prv+:: Previously specified argument.
# +msg+:: Exception message.
#
- def notwice(obj, prv, msg) # :nodoc:
+ private 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:
@@ -1500,7 +1506,7 @@ XXX
case o
when Proc, Method
block = notwice(o, block, 'block')
- when Array, Hash
+ when Array, Hash, Set
if Array === o
o, v = o.partition {|v,| Completion.completable?(v)}
values = notwice(v, values, 'values') unless v.empty?
@@ -1722,7 +1728,7 @@ XXX
parse_in_order(argv, setter, **keywords, &nonopt)
end
- def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
+ private def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
opt, arg, val, rest = nil
nonopt ||= proc {|a| throw :terminate, a}
argv.unshift(arg) if arg = catch(:terminate) {
@@ -1813,10 +1819,9 @@ XXX
argv
end
- private :parse_in_order
# Calls callback with _val_.
- def callback!(cb, max_arity, *args) # :nodoc:
+ private def callback!(cb, max_arity, *args) # :nodoc:
args.compact!
if (size = args.size) < max_arity and cb.to_proc.lambda?
@@ -1826,7 +1831,6 @@ XXX
end
cb.call(*args)
end
- private :callback!
#
# Parses command line arguments +argv+ in permutation mode and returns
@@ -1846,7 +1850,7 @@ XXX
#
def permute!(argv = default_argv, **keywords)
nonopts = []
- order!(argv, **keywords, &nonopts.method(:<<))
+ order!(argv, **keywords) {|nonopt| nonopts << nonopt}
argv[0, 0] = nonopts
argv
end
@@ -1899,13 +1903,16 @@ XXX
single_options, *long_options = *args
result = {}
+ setter = (symbolize_names ?
+ ->(name, val) {result[name.to_sym] = val}
+ : ->(name, val) {result[name] = val})
single_options.scan(/(.)(:)?/) do |opt, val|
if val
- result[opt] = nil
+ setter[opt, nil]
define("-#{opt} VAL")
else
- result[opt] = false
+ setter[opt, false]
define("-#{opt}")
end
end if single_options
@@ -1914,16 +1921,16 @@ XXX
arg, desc = arg.split(';', 2)
opt, val = arg.split(':', 2)
if val
- result[opt] = val.empty? ? nil : val
+ setter[opt, (val unless val.empty?)]
define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
else
- result[opt] = false
+ setter[opt, false]
define("--#{opt}", *[desc].compact)
end
end
- parse_in_order(argv, result.method(:[]=), **keywords)
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ parse_in_order(argv, setter, **keywords)
+ result
end
#
@@ -1937,24 +1944,22 @@ XXX
# Traverses @stack, sending each element method +id+ with +args+ and
# +block+.
#
- def visit(id, *args, &block) # :nodoc:
+ private 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:
+ private 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
@@ -1965,7 +1970,7 @@ XXX
# +icase+:: Search case insensitive if true.
# +pat+:: Optional pattern for completion.
#
- def complete(typ, opt, icase = false, *pat) # :nodoc:
+ private def complete(typ, opt, icase = false, *pat) # :nodoc:
if pat.empty?
search(typ, opt) {|sw| return [sw, opt]} # exact match or...
end
@@ -1973,9 +1978,8 @@ XXX
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])
+ raise exc.new(opt, additional: proc {|o| additional_message(typ, o)})
end
- private :complete
#
# Returns additional info.
@@ -2038,19 +2042,27 @@ XXX
def load(filename = nil, **keywords)
unless filename
basename = File.basename($0, '.*')
- return true if load(File.expand_path(basename, '~/.options'), **keywords) rescue nil
+ return true if load(File.expand_path("~/.options/#{basename}"), **keywords) rescue nil
basename << ".options"
+ if !(xdg = ENV['XDG_CONFIG_HOME']) or xdg.empty?
+ # https://specifications.freedesktop.org/basedir-spec/latest/#variables
+ #
+ # If $XDG_CONFIG_HOME is either not set or empty, a default
+ # equal to $HOME/.config should be used.
+ xdg = ['~/.config', true]
+ end
return [
- # XDG
- ENV['XDG_CONFIG_HOME'],
- '~/.config',
+ xdg,
+
*ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
# Haiku
- '~/config/settings',
- ].any? {|dir|
+ ['~/config/settings', true],
+ ].any? {|dir, expand|
next if !dir or dir.empty?
- load(File.expand_path(basename, dir), **keywords) rescue nil
+ filename = File.join(dir, basename)
+ filename = File.expand_path(filename) if expand
+ load(filename, **keywords) rescue nil
}
end
begin
@@ -2256,9 +2268,10 @@ XXX
argv
end
+ DIR = File.join(__dir__, '')
def self.filter_backtrace(array)
unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ array.delete_if {|bt| bt.start_with?(DIR)}
end
array
end
@@ -2301,42 +2314,42 @@ XXX
# Raises when ambiguously completable string is encountered.
#
class AmbiguousOption < ParseError
- const_set(:Reason, 'ambiguous option')
+ Reason = 'ambiguous option' # :nodoc:
end
#
# Raises when there is an argument for a switch which takes no argument.
#
class NeedlessArgument < ParseError
- const_set(:Reason, 'needless argument')
+ Reason = 'needless argument' # :nodoc:
end
#
# Raises when a switch with mandatory argument has no argument.
#
class MissingArgument < ParseError
- const_set(:Reason, 'missing argument')
+ Reason = 'missing argument' # :nodoc:
end
#
# Raises when switch is undefined.
#
class InvalidOption < ParseError
- const_set(:Reason, 'invalid option')
+ Reason = 'invalid option' # :nodoc:
end
#
# Raises when the given argument does not match required format.
#
class InvalidArgument < ParseError
- const_set(:Reason, 'invalid argument')
+ Reason = 'invalid argument' # :nodoc:
end
#
# Raises when the given argument word can't be completed uniquely.
#
class AmbiguousArgument < InvalidArgument
- const_set(:Reason, 'ambiguous argument')
+ Reason = 'ambiguous argument' # :nodoc:
end
#
@@ -2435,9 +2448,11 @@ XXX
# and DecimalNumeric. See Acceptable argument classes (in source code).
#
module Acceptables
- const_set(:DecimalInteger, OptionParser::DecimalInteger)
- const_set(:OctalInteger, OptionParser::OctalInteger)
- const_set(:DecimalNumeric, OptionParser::DecimalNumeric)
+ # :stopdoc:
+ DecimalInteger = OptionParser::DecimalInteger
+ OctalInteger = OptionParser::OctalInteger
+ DecimalNumeric = OptionParser::DecimalNumeric
+ # :startdoc:
end
end
diff --git a/lib/optparse/optparse.gemspec b/lib/optparse/optparse.gemspec
index 8589f1857c..885b0ec380 100644
--- a/lib/optparse/optparse.gemspec
+++ b/lib/optparse/optparse.gemspec
@@ -3,7 +3,7 @@
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*OptionParser::Version\s*=\s*"(.*)"/ =~ line and break $1
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
end rescue nil
end
@@ -25,8 +25,9 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- spec.files = Dir["{doc,lib,misc}/**/{*,.document}"] +
- %w[README.md ChangeLog COPYING .document .rdoc_options]
+ dir, gemspec = File.split(__FILE__)
+ excludes = %W[#{gemspec} rakelib test/ Gemfile Rakefile .git* .editor*].map {|n| ":^"+n}
+ spec.files = IO.popen(%w[git ls-files -z --] + excludes, chdir: dir, &:read).split("\x0")
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
diff --git a/lib/pathname.rb b/lib/pathname.rb
new file mode 100644
index 0000000000..0e51e1fdf6
--- /dev/null
+++ b/lib/pathname.rb
@@ -0,0 +1,151 @@
+# frozen_string_literal: true
+#
+# = pathname.rb
+#
+# Object-Oriented Pathname Class
+#
+# Author:: Tanaka Akira <akr@m17n.org>
+# Documentation:: Author and Gavin Sinclair
+#
+# For documentation, see class Pathname.
+#
+class Pathname
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # Pathname.find(ignore_error: true) -> nil
+ #
+ # With a block given, performs a depth-first traversal of the path in `self`;
+ # calls the block with each found path:
+ #
+ # ```ruby
+ # paths = []
+ # Pathname('lib').find {|path| paths << path }
+ # paths.size # => 909
+ # paths.take(3)
+ # # =>
+ # # [#<Pathname:lib>,
+ # # #<Pathname:lib/English.gemspec>,
+ # # #<Pathname:lib/English.rb>]
+ # ```
+ #
+ # When `self` contains `'.'`, the found paths omit the leading `'./'`:
+ #
+ # ```ruby
+ # paths = []
+ # Dir.chdir('lib') do
+ # Pathname('.').find {|path| paths << path }
+ # end
+ # paths.take(3)
+ # # # =>
+ # # [#<Pathname:.>,
+ # # #<Pathname:English.gemspec>,
+ # # #<Pathname:English.rb>]
+ # ```
+ #
+ # This method calls method Find.find;
+ # therefore method Find.prune may be used in the block:
+ #
+ # ```ruby
+ # files = []
+ # Pathname('.').find do |path|
+ # Find.prune if File.basename(path) == 'test'
+ # next unless File.file?(path) && File.extname(path) == '.rb'
+ # files << path
+ # end
+ # files.size # => 6690
+ # files.take(3)
+ # # # =>
+ # # [#<Pathname:KNOWNBUGS.rb>,
+ # # #<Pathname:array.rb>,
+ # # #<Pathname:ast.rb>]
+ # ```
+ #
+ # Raises an exception if the path in `self` cannot be read.
+ #
+ # When keyword argument `ignore_error` is given as `true` (the default),
+ # certain exceptions during traversal are ignored (i.e., silently rescued):
+ # Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL;
+ # when given as `false`, no exceptions are rescued.
+ #
+ # Note that these exceptions may be ignored only in `Pathname#find` traversal code;
+ # an exception raised before traversal begins,
+ # or raised while in the block is not ignored.
+ # Each of the calls below raises an Errno::ENOENT exception that is not ignored:
+ #
+ # ```ruby
+ # Pathname('nosuch').find { }
+ # Pathname('lib').find {|entry| raise Errno::ENOENT }
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
+ def find(ignore_error: true) # :yield: pathname
+ return to_enum(__method__, ignore_error: ignore_error) unless block_given?
+ require 'find'
+ if @path == '.'
+ Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) }
+ else
+ Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
+ end
+ end
+end
+
+
+class Pathname # * FileUtils *
+ # Recursively deletes a directory, including all directories beneath it.
+ #
+ # Note that you need to require 'pathname' to use this method.
+ #
+ # See FileUtils.rm_rf
+ def rmtree(noop: nil, verbose: nil, secure: nil)
+ # The name "rmtree" is borrowed from File::Path of Perl.
+ # File::Path provides "mkpath" and "rmtree".
+ require 'fileutils'
+ FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure)
+ self
+ end
+end
+
+class Pathname # * tmpdir *
+ # call-seq:
+ # Pathname.mktmpdir -> new_pathname
+ # Pathname.mktmpdir {|pathname| ... } -> object
+ #
+ # Creates:
+ #
+ # - A temporary directory via Dir.mktmpdir.
+ # - A \Pathname object that contains the path to that directory.
+ #
+ # With no block given, returns the created pathname;
+ # the caller should delete the created directory when it is no longer needed
+ # (FileUtils.rm_r is a convenient method for the deletion):
+ #
+ # pathname = Pathname.mktmpdir
+ # dirpath = pathname.to_s
+ # Dir.exist?(dirpath) # => true
+ # # Do something with the directory.
+ # require 'fileutils'
+ # FileUtils.rm_r(dirpath)
+ #
+ # With a block given, calls the block with the created pathname;
+ # on block exit, automatically deletes the created directory and all its contents;
+ # returns the block's exit value:
+ #
+ # pathname = Pathname.mktmpdir do |p|
+ # # Do something with the directory.
+ # p
+ # end
+ # Dir.exist?(pathname.to_s) # => false
+ def self.mktmpdir
+ require 'tmpdir' unless defined?(Dir.mktmpdir)
+ if block_given?
+ Dir.mktmpdir do |dir|
+ dir = self.new(dir)
+ yield dir
+ end
+ else
+ self.new(Dir.mktmpdir)
+ end
+ end
+end
diff --git a/lib/pp.rb b/lib/pp.rb
index 332062164d..5fd29a373a 100644
--- a/lib/pp.rb
+++ b/lib/pp.rb
@@ -64,7 +64,7 @@ require 'prettyprint'
class PP < PrettyPrint
# The version string
- VERSION = "0.6.2"
+ VERSION = "0.6.3"
# Returns the usable width for +out+.
# As the width of +out+:
@@ -145,21 +145,13 @@ class PP < PrettyPrint
# Yields to a block
# and preserves the previous set of objects being printed.
def guard_inspect_key
- if Thread.current[:__recursive_key__] == nil
- Thread.current[:__recursive_key__] = {}.compare_by_identity
- end
-
- if Thread.current[:__recursive_key__][:inspect] == nil
- Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity
- end
-
- save = Thread.current[:__recursive_key__][:inspect]
-
+ recursive_state = Thread.current[:__recursive_key__] ||= {}.compare_by_identity
+ save = recursive_state[:inspect] ||= {}.compare_by_identity
begin
- Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity
+ recursive_state[:inspect] = {}.compare_by_identity
yield
ensure
- Thread.current[:__recursive_key__][:inspect] = save
+ recursive_state[:inspect] = save
end
end
@@ -167,9 +159,8 @@ class PP < PrettyPrint
# to be pretty printed. Used to break cycles in chains of objects to be
# pretty printed.
def check_inspect_key(id)
- Thread.current[:__recursive_key__] &&
- Thread.current[:__recursive_key__][:inspect] &&
- Thread.current[:__recursive_key__][:inspect].include?(id)
+ recursive_state = Thread.current[:__recursive_key__] or return false
+ recursive_state[:inspect]&.include?(id)
end
# Adds the object_id +id+ to the set of objects being pretty printed, so
@@ -183,10 +174,10 @@ class PP < PrettyPrint
Thread.current[:__recursive_key__][:inspect].delete id
end
- private def guard_inspect(object)
+ private def guard_inspect(object) # :nodoc:
recursive_state = Thread.current[:__recursive_key__]
- if recursive_state && recursive_state.key?(:inspect)
+ if recursive_state&.key?(:inspect)
begin
push_inspect_key(object)
yield
@@ -276,15 +267,20 @@ class PP < PrettyPrint
def seplist(list, sep=nil, iter_method=:each) # :yield: element
sep ||= lambda { comma_breakable }
first = true
+ kwsplat = EMPTY_KWHASH
list.__send__(iter_method) {|*v|
if first
first = false
else
sep.call
end
- RUBY_VERSION >= "3.0" ? yield(*v, **{}) : yield(*v)
+ kwsplat ? yield(*v, **kwsplat) : yield(*v)
}
end
+ EMPTY_KWHASH = if RUBY_VERSION >= "3.0" # :nodoc:
+ {}.freeze
+ end
+ private_constant :EMPTY_KWHASH
# A present standard failsafe for pretty printing any given Object
def pp_object(obj)
@@ -317,12 +313,10 @@ class PP < PrettyPrint
# A pretty print for a pair of Hash
def pp_hash_pair(k, v)
if Symbol === k
- sym_s = k.inspect
- if sym_s[1].match?(/["$@!]/) || sym_s[-1].match?(/[%&*+\-\/<=>@\]^`|~]/)
- text "#{k.to_s.inspect}:"
- else
- text "#{k}:"
+ if k.inspect.match?(%r[\A:["$@!]|[%&*+\-\/<=>@\]^`|~]\z])
+ k = k.to_s.inspect
end
+ text "#{k}:"
else
pp k
text ' '
@@ -394,7 +388,8 @@ class PP < PrettyPrint
# This method should return an array of names of instance variables as symbols or strings as:
# +[:@a, :@b]+.
def pretty_print_instance_variables
- instance_variables.sort
+ ivars = respond_to?(:instance_variables_to_inspect, true) ? instance_variables_to_inspect || instance_variables : instance_variables
+ ivars.sort
end
# Is #inspect implementation using #pretty_print.
@@ -437,6 +432,28 @@ class Hash # :nodoc:
end
end
+if defined?(Set)
+ if set_pp = Set.instance_method(:initialize).source_location
+ set_pp = !set_pp.first.end_with?("/set.rb") # not defined in set.rb
+ else
+ set_pp = true # defined in C
+ end
+end
+class Set # :nodoc:
+ def pretty_print(pp) # :nodoc:
+ pp.group(1, "#{self.class.name}[", ']') {
+ pp.seplist(self) { |o|
+ pp.pp o
+ }
+ }
+ end
+
+ def pretty_print_cycle(pp) # :nodoc:
+ name = self.class.name
+ pp.text(empty? ? "#{name}[]" : "#{name}[...]")
+ end
+end if set_pp
+
class << ENV # :nodoc:
def pretty_print(q) # :nodoc:
h = {}
@@ -467,6 +484,13 @@ class Struct # :nodoc:
end
end
+verbose, $VERBOSE = $VERBOSE, nil
+begin
+ has_data_define = defined?(Data.define)
+ensure
+ $VERBOSE = verbose
+end
+
class Data # :nodoc:
def pretty_print(q) # :nodoc:
class_name = PP.mcall(self, Kernel, :class).name
@@ -499,7 +523,7 @@ class Data # :nodoc:
def pretty_print_cycle(q) # :nodoc:
q.text sprintf("#<data %s:...>", PP.mcall(self, Kernel, :class).name)
end
-end if defined?(Data.define)
+end if has_data_define
class Range # :nodoc:
def pretty_print(q) # :nodoc:
diff --git a/lib/prettyprint.rb b/lib/prettyprint.rb
index 6f50192f5d..44ca5e816f 100644
--- a/lib/prettyprint.rb
+++ b/lib/prettyprint.rb
@@ -33,6 +33,7 @@
#
class PrettyPrint
+ # The version string
VERSION = "0.2.0"
# This is a convenience method which is same as follows:
@@ -486,8 +487,10 @@ class PrettyPrint
# It is passed to be similar to a PrettyPrint object itself, by responding to:
# * #text
# * #breakable
+ # * #fill_breakable
# * #nest
# * #group
+ # * #group_sub
# * #flush
# * #first?
#
@@ -521,6 +524,13 @@ class PrettyPrint
@output << sep
end
+ # Appends +sep+ to the text to be output. By default +sep+ is ' '
+ #
+ # +width+ argument is here for compatibility. It is a noop argument.
+ def fill_breakable(sep=' ', width=nil)
+ @output << sep
+ end
+
# Takes +indent+ arg, but does nothing with it.
#
# Yields to a block.
@@ -544,6 +554,15 @@ class PrettyPrint
@first.pop
end
+ # Yields to a block for compatibility.
+ def group_sub # :nodoc:
+ yield
+ end
+
+ # Method present for compatibility, but is a noop
+ def break_outmost_groups # :nodoc:
+ end
+
# Method present for compatibility, but is a noop
def flush # :nodoc:
end
diff --git a/lib/prism.rb b/lib/prism.rb
index eaab5cbfed..8f0342724a 100644
--- a/lib/prism.rb
+++ b/lib/prism.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
# The Prism Ruby parser.
#
@@ -19,9 +22,8 @@ module Prism
autoload :DSL, "prism/dsl"
autoload :InspectVisitor, "prism/inspect_visitor"
autoload :LexCompat, "prism/lex_compat"
- autoload :LexRipper, "prism/lex_compat"
autoload :MutationCompiler, "prism/mutation_compiler"
- autoload :Pack, "prism/pack"
+ autoload :NodeFind, "prism/node_find"
autoload :Pattern, "prism/pattern"
autoload :Reflection, "prism/reflection"
autoload :Relocation, "prism/relocation"
@@ -33,38 +35,91 @@ module Prism
# Some of these constants are not meant to be exposed, so marking them as
# private here.
- private_constant :LexCompat
- private_constant :LexRipper
+ if RUBY_ENGINE != "jruby"
+ private_constant :LexCompat
+ private_constant :NodeFind
+ end
+
+ # Raised when requested to parse as the currently running Ruby version but Prism has no support for it.
+ class CurrentVersionError < ArgumentError
+ # Initialize a new exception for the given ruby version string.
+ #--
+ #: (String version) -> void
+ def initialize(version)
+ message = +"invalid version: Requested to parse as `version: 'current'`; "
+ major, minor, =
+ if version.match?(/\A\d+\.\d+.\d+\z/)
+ version.split(".").map(&:to_i)
+ end
+
+ if major && minor && ((major < 3) || (major == 3 && minor < 3))
+ message << " #{version} is below the minimum supported syntax."
+ else
+ message << " #{version} is unknown. Please update the `prism` gem."
+ end
+
+ super(message)
+ end
+ end
# :call-seq:
- # Prism::lex_compat(source, **options) -> LexCompat::Result
+ # lex_compat(source, **options) -> LexCompat::Result
#
# 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.
+ # resembles the return value of Ripper.lex.
#
- # For supported options, see Prism::parse.
+ # For supported options, see Prism.parse.
+ #--
+ #: (String source, **untyped options) -> LexCompat::Result
def self.lex_compat(source, **options)
LexCompat.new(source, **options).result # steep:ignore
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 # steep:ignore
- end
-
- # :call-seq:
- # Prism::load(source, serialized, freeze) -> ParseResult
+ # load(source, serialized, freeze) -> ParseResult
#
# Load the serialized AST using the source as a reference into a tree.
+ #--
+ #: (String source, String serialized, ?bool freeze) -> ParseResult
def self.load(source, serialized, freeze = false)
Serialize.load_parse(source, serialized, freeze)
end
+
+ # Given a Method, UnboundMethod, Proc, or Thread::Backtrace::Location,
+ # returns the Prism node representing it. On CRuby, this uses node_id for
+ # an exact match. On other implementations, it falls back to best-effort
+ # matching by source location line number.
+ #--
+ #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, ?rubyvm: bool) -> Node?
+ def self.find(callable, rubyvm: !!defined?(RubyVM))
+ NodeFind.find(callable, rubyvm)
+ end
+
+ # @rbs!
+ # VERSION: String
+ # BACKEND: :CEXT | :FFI
+ #
+ # interface _Stream
+ # def gets: (?Integer integer) -> (String | nil)
+ # end
+ #
+ # def self.parse: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
+ # def self.profile: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> void
+ # def self.lex: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult
+ # def self.parse_lex: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult
+ # def self.dump: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> String
+ # def self.parse_comments: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment]
+ # def self.parse_success?: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
+ # def self.parse_failure?: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
+ # def self.parse_stream: (_Stream stream, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
+ # def self.parse_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
+ # def self.profile_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> void
+ # def self.lex_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult
+ # def self.parse_lex_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult
+ # def self.dump_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> String
+ # def self.parse_file_comments: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment]
+ # def self.parse_file_success?: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
+ # def self.parse_file_failure?: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
end
require_relative "prism/polyfill/byteindex"
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
index e3b15fc3b0..c64d03f64a 100644
--- a/lib/prism/desugar_compiler.rb
+++ b/lib/prism/desugar_compiler.rb
@@ -1,11 +1,18 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
class DesugarAndWriteNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: ClassVariableAndWriteNode | ConstantAndWriteNode | GlobalVariableAndWriteNode | InstanceVariableAndWriteNode | LocalVariableAndWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((ClassVariableAndWriteNode | ConstantAndWriteNode | GlobalVariableAndWriteNode | InstanceVariableAndWriteNode | LocalVariableAndWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -15,6 +22,8 @@ module Prism
end
# Desugar `x &&= y` to `x && x = y`
+ #--
+ #: () -> node
def compile
and_node(
location: node.location,
@@ -35,8 +44,12 @@ module Prism
class DesugarOrWriteDefinedNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: ClassVariableOrWriteNode | ConstantOrWriteNode | GlobalVariableOrWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((ClassVariableOrWriteNode | ConstantOrWriteNode | GlobalVariableOrWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -46,6 +59,8 @@ module Prism
end
# Desugar `x ||= y` to `defined?(x) ? x : x = y`
+ #--
+ #: () -> node
def compile
if_node(
location: node.location,
@@ -86,8 +101,12 @@ module Prism
class DesugarOperatorWriteNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: ClassVariableOperatorWriteNode | ConstantOperatorWriteNode | GlobalVariableOperatorWriteNode | InstanceVariableOperatorWriteNode | LocalVariableOperatorWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((ClassVariableOperatorWriteNode | ConstantOperatorWriteNode | GlobalVariableOperatorWriteNode | InstanceVariableOperatorWriteNode | LocalVariableOperatorWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -97,6 +116,8 @@ module Prism
end
# Desugar `x += y` to `x = x + y`
+ #--
+ #: () -> node
def compile
binary_operator_loc = node.binary_operator_loc.chop
@@ -130,8 +151,12 @@ module Prism
class DesugarOrWriteNode # :nodoc:
include DSL
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
+ attr_reader :node #: InstanceVariableOrWriteNode | LocalVariableOrWriteNode
+ attr_reader :default_source #: Source
+ attr_reader :read_class, :write_class #: Symbol
+ attr_reader :arguments #: Hash[Symbol, untyped]
+ #: ((InstanceVariableOrWriteNode | LocalVariableOrWriteNode) node, Source default_source, Symbol read_class, Symbol write_class, **untyped arguments) -> void
def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
@default_source = default_source
@@ -141,6 +166,8 @@ module Prism
end
# Desugar `x ||= y` to `x || x = y`
+ #--
+ #: () -> node
def compile
or_node(
location: node.location,
@@ -161,90 +188,105 @@ module Prism
private_constant :DesugarAndWriteNode, :DesugarOrWriteNode, :DesugarOrWriteDefinedNode, :DesugarOperatorWriteNode
class ClassVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ClassVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteDefinedNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ClassVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ConstantAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class ConstantOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteDefinedNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class ConstantOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class GlobalVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class GlobalVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteDefinedNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class GlobalVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class InstanceVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class InstanceVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class InstanceVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class LocalVariableAndWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarAndWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
class LocalVariableOrWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOrWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
class LocalVariableOperatorWriteNode
+ #: () -> node
def desugar # :nodoc:
DesugarOperatorWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
@@ -253,137 +295,167 @@ 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
+ # `@@foo &&= bar`
#
# becomes
#
- # @@foo && @@foo = bar
+ # `@@foo && @@foo = bar`
+ #--
+ #: (ClassVariableAndWriteNode node) -> node
def visit_class_variable_and_write_node(node)
node.desugar
end
- # @@foo ||= bar
+ # `@@foo ||= bar`
#
# becomes
#
- # defined?(@@foo) ? @@foo : @@foo = bar
+ # `defined?(@@foo) ? @@foo : @@foo = bar`
+ #--
+ #: (ClassVariableOrWriteNode node) -> node
def visit_class_variable_or_write_node(node)
node.desugar
end
- # @@foo += bar
+ # `@@foo += bar`
#
# becomes
#
- # @@foo = @@foo + bar
+ # `@@foo = @@foo + bar`
+ #--
+ #: (ClassVariableOperatorWriteNode node) -> node
def visit_class_variable_operator_write_node(node)
node.desugar
end
- # Foo &&= bar
+ # `Foo &&= bar`
#
# becomes
#
- # Foo && Foo = bar
+ # `Foo && Foo = bar`
+ #--
+ #: (ConstantAndWriteNode node) -> node
def visit_constant_and_write_node(node)
node.desugar
end
- # Foo ||= bar
+ # `Foo ||= bar`
#
# becomes
#
- # defined?(Foo) ? Foo : Foo = bar
+ # `defined?(Foo) ? Foo : Foo = bar`
+ #--
+ #: (ConstantOrWriteNode node) -> node
def visit_constant_or_write_node(node)
node.desugar
end
- # Foo += bar
+ # `Foo += bar`
#
# becomes
#
- # Foo = Foo + bar
+ # `Foo = Foo + bar`
+ #--
+ #: (ConstantOperatorWriteNode node) -> node
def visit_constant_operator_write_node(node)
node.desugar
end
- # $foo &&= bar
+ # `$foo &&= bar`
#
# becomes
#
- # $foo && $foo = bar
+ # `$foo && $foo = bar`
+ #--
+ #: (GlobalVariableAndWriteNode node) -> node
def visit_global_variable_and_write_node(node)
node.desugar
end
- # $foo ||= bar
+ # `$foo ||= bar`
#
# becomes
#
- # defined?($foo) ? $foo : $foo = bar
+ # `defined?($foo) ? $foo : $foo = bar`
+ #--
+ #: (GlobalVariableOrWriteNode node) -> node
def visit_global_variable_or_write_node(node)
node.desugar
end
- # $foo += bar
+ # `$foo += bar`
#
# becomes
#
- # $foo = $foo + bar
+ # `$foo = $foo + bar`
+ #--
+ #: (GlobalVariableOperatorWriteNode node) -> node
def visit_global_variable_operator_write_node(node)
node.desugar
end
- # @foo &&= bar
+ # `@foo &&= bar`
#
# becomes
#
- # @foo && @foo = bar
+ # `@foo && @foo = bar`
+ #--
+ #: (InstanceVariableAndWriteNode node) -> node
def visit_instance_variable_and_write_node(node)
node.desugar
end
- # @foo ||= bar
+ # `@foo ||= bar`
#
# becomes
#
- # @foo || @foo = bar
+ # `@foo || @foo = bar`
+ #--
+ #: (InstanceVariableOrWriteNode node) -> node
def visit_instance_variable_or_write_node(node)
node.desugar
end
- # @foo += bar
+ # `@foo += bar`
#
# becomes
#
- # @foo = @foo + bar
+ # `@foo = @foo + bar`
+ #--
+ #: (InstanceVariableOperatorWriteNode node) -> node
def visit_instance_variable_operator_write_node(node)
node.desugar
end
- # foo &&= bar
+ # `foo &&= bar`
#
# becomes
#
- # foo && foo = bar
+ # `foo && foo = bar`
+ #--
+ #: (LocalVariableAndWriteNode node) -> node
def visit_local_variable_and_write_node(node)
node.desugar
end
- # foo ||= bar
+ # `foo ||= bar`
#
# becomes
#
- # foo || foo = bar
+ # `foo || foo = bar`
+ #--
+ #: (LocalVariableOrWriteNode node) -> node
def visit_local_variable_or_write_node(node)
node.desugar
end
- # foo += bar
+ # `foo += bar`
#
# becomes
#
- # foo = foo + bar
+ # `foo = foo + bar`
+ #--
+ #: (LocalVariableOperatorWriteNode node) -> node
def visit_local_variable_operator_write_node(node)
node.desugar
end
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
index a0da0b6195..6b9bde51ea 100644
--- a/lib/prism/ffi.rb
+++ b/lib/prism/ffi.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# :markup: markdown
# typed: ignore
# This file is responsible for mirroring the API provided by the C extension by
@@ -11,7 +12,7 @@ require "ffi"
# autoloaded from within a non-main Ractor.
require "prism/serialize" if defined?(Ractor)
-module Prism
+module Prism # :nodoc:
module LibRubyParser # :nodoc:
extend FFI::Library
@@ -58,6 +59,9 @@ module Prism
# We only want to load the functions that we are interested in.
next unless functions.any? { |function| line.include?(function) }
+ # Strip trailing attributes (PRISM_NODISCARD, PRISM_NONNULL(...), etc.)
+ line = line.sub(/\)(\s+PRISM_\w+(?:\([^)]*\))?)+\s*;/, ");")
+
# Parse the function declaration.
unless /^PRISM_EXPORTED_FUNCTION (?<return_type>.+) (?<name>\w+)\((?<arg_types>.+)\);$/ =~ line
raise "Could not parse #{line}"
@@ -84,29 +88,44 @@ module Prism
raise "Could not find functions #{functions.inspect}" unless functions.empty?
end
- callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
- enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
+ callback :pm_source_stream_fgets_t, [:pointer, :int, :pointer], :pointer
+ callback :pm_source_stream_feof_t, [:pointer], :int
+ pm_source_init_result_values = %i[PM_SOURCE_INIT_SUCCESS PM_SOURCE_INIT_ERROR_GENERIC PM_SOURCE_INIT_ERROR_DIRECTORY PM_SOURCE_INIT_ERROR_NON_REGULAR]
+ enum :pm_source_init_result_t, pm_source_init_result_values
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
+ # Ractor-safe lookup table for pm_source_init_result_t, since FFI's
+ # enum_type accesses module instance variables that are not shareable.
+ SOURCE_INIT_RESULT = pm_source_init_result_values.freeze
+
load_exported_functions_from(
- "prism.h",
+ "prism/version.h",
"pm_version",
+ []
+ )
+
+ load_exported_functions_from(
+ "prism/serialize.h",
"pm_serialize_parse",
"pm_serialize_parse_stream",
"pm_serialize_parse_comments",
"pm_serialize_lex",
"pm_serialize_parse_lex",
- "pm_parse_success_p",
+ "pm_serialize_parse_success_p",
+ []
+ )
+
+ load_exported_functions_from(
+ "prism/string_query.h",
"pm_string_query_local",
"pm_string_query_constant",
"pm_string_query_method_name",
- [:pm_parse_stream_fgets_t]
+ []
)
load_exported_functions_from(
- "prism/util/pm_buffer.h",
- "pm_buffer_sizeof",
- "pm_buffer_init",
+ "prism/buffer.h",
+ "pm_buffer_new",
"pm_buffer_value",
"pm_buffer_length",
"pm_buffer_free",
@@ -114,20 +133,19 @@ module Prism
)
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",
- []
+ "prism/source.h",
+ "pm_source_file_new",
+ "pm_source_mapped_new",
+ "pm_source_stream_new",
+ "pm_source_free",
+ "pm_source_source",
+ "pm_source_length",
+ [:pm_source_stream_fgets_t, :pm_source_stream_feof_t]
)
# 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)
@@ -149,20 +167,20 @@ module Prism
# Initialize a new buffer and yield it to the block. The buffer will be
# automatically freed when the block returns.
def self.with
- FFI::MemoryPointer.new(SIZEOF) do |pointer|
- raise unless LibRubyParser.pm_buffer_init(pointer)
- return yield new(pointer)
+ buffer = LibRubyParser.pm_buffer_new
+ raise unless buffer
+
+ begin
+ yield new(buffer)
ensure
- LibRubyParser.pm_buffer_free(pointer)
+ LibRubyParser.pm_buffer_free(buffer)
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
-
+ # This object represents source code to be parsed. For strings it wraps a
+ # pointer directly; for files it uses a pm_source_t under the hood.
+ class PrismSource # :nodoc:
PLATFORM_EXPECTS_UTF8 =
RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i)
@@ -179,7 +197,7 @@ module Prism
@pointer.read_string(@length)
end
- # Yields a pm_string_t pointer to the given block.
+ # Yields a PrismSource backed by the given string to the block.
def self.with_string(string)
raise TypeError unless string.is_a?(String)
@@ -193,32 +211,38 @@ module Prism
end
end
- # Yields a pm_string_t pointer to the given block.
+ # Yields a PrismSource to the given block, backed by a pm_source_t.
def self.with_file(filepath)
raise TypeError unless filepath.is_a?(String)
# On Windows and Mac, it's expected that filepaths will be encoded in
# UTF-8. If they are not, we need to convert them to UTF-8 before
- # passing them into pm_string_mapped_init.
+ # passing them into pm_source_mapped_new.
if PLATFORM_EXPECTS_UTF8 && (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
filepath = filepath.encode(Encoding::UTF_8)
end
- FFI::MemoryPointer.new(SIZEOF) do |pm_string|
- case (result = LibRubyParser.pm_string_mapped_init(pm_string, filepath))
- when :PM_STRING_INIT_SUCCESS
- pointer = LibRubyParser.pm_string_source(pm_string)
- length = LibRubyParser.pm_string_length(pm_string)
+ FFI::MemoryPointer.new(:int) do |result_ptr|
+ pm_source = LibRubyParser.pm_source_mapped_new(filepath, 0, result_ptr)
+
+ case SOURCE_INIT_RESULT[result_ptr.read_int]
+ when :PM_SOURCE_INIT_SUCCESS
+ pointer = LibRubyParser.pm_source_source(pm_source)
+ length = LibRubyParser.pm_source_length(pm_source)
return yield new(pointer, length, false)
- when :PM_STRING_INIT_ERROR_GENERIC
+ when :PM_SOURCE_INIT_ERROR_GENERIC
raise SystemCallError.new(filepath, FFI.errno)
- when :PM_STRING_INIT_ERROR_DIRECTORY
+ when :PM_SOURCE_INIT_ERROR_DIRECTORY
raise Errno::EISDIR.new(filepath)
+ when :PM_SOURCE_INIT_ERROR_NON_REGULAR
+ # Fall back to reading the file through Ruby IO for non-regular
+ # files (pipes, character devices, etc.)
+ return with_string(File.read(filepath)) { |string| yield string }
else
- raise "Unknown error initializing pm_string_t: #{result.inspect}"
+ raise "Unknown error initializing pm_source_t: #{result_ptr.read_int}"
end
ensure
- LibRubyParser.pm_string_free(pm_string)
+ LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
end
end
end
@@ -234,29 +258,29 @@ module Prism
class << self
# Mirror the Prism.dump API by using the serialization API.
def dump(source, **options)
- LibRubyParser::PrismString.with_string(source) { |string| dump_common(string, options) }
+ LibRubyParser::PrismSource.with_string(source) { |string| dump_common(string, options) }
end
# Mirror the Prism.dump_file API by using the serialization API.
def dump_file(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| dump_common(string, options) }
end
# Mirror the Prism.lex API by using the serialization API.
def lex(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| lex_common(string, code, options) }
+ LibRubyParser::PrismSource.with_string(code) { |string| lex_common(string, code, options) }
end
# Mirror the Prism.lex_file API by using the serialization API.
def lex_file(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| lex_common(string, string.read, options) }
end
# Mirror the Prism.parse API by using the serialization API.
def parse(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_common(string, code, options) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_common(string, code, options) }
end
# Mirror the Prism.parse_file API by using the serialization API. This uses
@@ -264,7 +288,7 @@ module Prism
# when it is available.
def parse_file(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| parse_common(string, string.read, options) }
end
# Mirror the Prism.parse_stream API by using the serialization API.
@@ -280,19 +304,21 @@ module Prism
end
}
- # In the pm_serialize_parse_stream function it accepts a pointer to the
- # IO object as a void* and then passes it through to the callback as the
- # third argument, but it never touches it itself. As such, since we have
- # access to the IO object already through the closure of the lambda, we
- # can pass a null pointer here and not worry.
- LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
- Prism.load(source, buffer.read, options.fetch(:freeze, false))
+ eof_callback = -> (_) { stream.eof? }
+
+ pm_source = LibRubyParser.pm_source_stream_new(nil, callback, eof_callback)
+ begin
+ LibRubyParser.pm_serialize_parse_stream(buffer.pointer, pm_source, dump_options(options))
+ Prism.load(source, buffer.read, options.fetch(:freeze, false))
+ ensure
+ LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
+ end
end
end
# Mirror the Prism.parse_comments API by using the serialization API.
def parse_comments(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_comments_common(string, code, options) }
end
# Mirror the Prism.parse_file_comments API by using the serialization
@@ -300,23 +326,23 @@ module Prism
# to use mmap when it is available.
def parse_file_comments(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
end
# Mirror the Prism.parse_lex API by using the serialization API.
def parse_lex(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_lex_common(string, code, options) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_lex_common(string, code, options) }
end
# Mirror the Prism.parse_lex_file API by using the serialization API.
def parse_lex_file(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
end
# Mirror the Prism.parse_success? API by using the serialization API.
def parse_success?(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_file_success_common(string, options) }
+ LibRubyParser::PrismSource.with_string(code) { |string| parse_file_success_common(string, options) }
end
# Mirror the Prism.parse_failure? API by using the serialization API.
@@ -327,7 +353,7 @@ module Prism
# Mirror the Prism.parse_file_success? API by using the serialization API.
def parse_file_success?(filepath, **options)
options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) }
+ LibRubyParser::PrismSource.with_file(filepath) { |string| parse_file_success_common(string, options) }
end
# Mirror the Prism.parse_file_failure? API by using the serialization API.
@@ -337,7 +363,7 @@ module Prism
# Mirror the Prism.profile API by using the serialization API.
def profile(source, **options)
- LibRubyParser::PrismString.with_string(source) do |string|
+ LibRubyParser::PrismSource.with_string(source) do |string|
LibRubyParser::PrismBuffer.with do |buffer|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
nil
@@ -347,7 +373,7 @@ module Prism
# Mirror the Prism.profile_file API by using the serialization API.
def profile_file(filepath, **options)
- LibRubyParser::PrismString.with_file(filepath) do |string|
+ LibRubyParser::PrismSource.with_file(filepath) do |string|
LibRubyParser::PrismBuffer.with do |buffer|
options[:filepath] = filepath
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
@@ -396,7 +422,7 @@ module Prism
end
def parse_file_success_common(string, options) # :nodoc:
- LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
+ LibRubyParser.pm_serialize_parse_success_p(string.pointer, string.length, dump_options(options))
end
# Return the value that should be dumped for the command_line option.
@@ -420,16 +446,35 @@ module Prism
# Return the value that should be dumped for the version option.
def dump_options_version(version)
case version
- when nil, "latest"
- 0
+ when "current"
+ version_string_to_number(RUBY_VERSION) || raise(CurrentVersionError, RUBY_VERSION)
+ when "latest", nil
+ 0 # Handled in pm_parser_init
+ when "nearest"
+ dump = version_string_to_number(RUBY_VERSION)
+ return dump if dump
+ if RUBY_VERSION < "3.3"
+ version_string_to_number("3.3")
+ else
+ 0 # Handled in pm_parser_init
+ end
+ else
+ version_string_to_number(version) || raise(ArgumentError, "invalid version: #{version}")
+ end
+ end
+
+ # Converts a version string like "4.0.0" or "4.0" into a number.
+ # Returns nil if the version is unknown.
+ def version_string_to_number(version)
+ case version
when /\A3\.3(\.\d+)?\z/
1
when /\A3\.4(\.\d+)?\z/
2
- when /\A3\.5(\.\d+)?\z/
- 0
- else
- raise ArgumentError, "invalid version: #{version}"
+ when /\A3\.5(\.\d+)?\z/, /\A4\.0(\.\d+)?\z/
+ 3
+ when /\A4\.1(\.\d+)?\z/
+ 4
end
end
@@ -531,7 +576,7 @@ module Prism
# Here we are going to patch StringQuery to put in the class-level methods so
# that it can maintain a consistent interface
- class StringQuery
+ class StringQuery # :nodoc:
class << self
# Mirrors the C extension's StringQuery::local? method.
def local?(string)
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
index a83c24cb41..7aacec037d 100644
--- a/lib/prism/lex_compat.rb
+++ b/lib/prism/lex_compat.rb
@@ -1,28 +1,64 @@
# frozen_string_literal: true
-
-require "delegate"
-require "ripper"
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
+ # @rbs!
+ # module Translation
+ # class Ripper
+ # EXPR_NONE: Integer
+ # EXPR_BEG: Integer
+ # EXPR_MID: Integer
+ # EXPR_END: Integer
+ # EXPR_CLASS: Integer
+ # EXPR_VALUE: Integer
+ # EXPR_ARG: Integer
+ # EXPR_CMDARG: Integer
+ # EXPR_ENDARG: Integer
+ # EXPR_ENDFN: Integer
+ #
+ # class Lexer < Ripper
+ # class State
+ # def self.[]: (Integer value) -> State
+ # end
+ # end
+ #
+ # class LineAndColumnCache
+ # def initialize: (Source source) -> void
+ #
+ # def line_and_column: (Integer byte_offset) -> [Integer, Integer]
+ # end
+ # end
+ # end
+
# 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:
+ # @rbs!
+ # # A token produced by the Ripper lexer that Prism is replicating.
+ # type lex_compat_token = [[Integer, Integer], Symbol, String, untyped]
+
# A result class specialized for holding tokens produced by the lexer.
class Result < Prism::Result
# The list of tokens that were produced by the lexer.
- attr_reader :value
+ attr_reader :value #: Array[lex_compat_token]
# Create a new lex compat result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (Array[lex_compat_token] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for Result.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
end
@@ -104,6 +140,7 @@ module Prism
KEYWORD_DEF: :on_kw,
KEYWORD_DEFINED: :on_kw,
KEYWORD_DO: :on_kw,
+ KEYWORD_DO_BLOCK: :on_kw,
KEYWORD_DO_LOOP: :on_kw,
KEYWORD_ELSE: :on_kw,
KEYWORD_ELSIF: :on_kw,
@@ -198,93 +235,6 @@ module Prism
"__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
- # @dynamic initialize, each, []
-
- # 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[3] == Ripper::EXPR_ARG | Ripper::EXPR_LABELED
- other[3] & Ripper::EXPR_ARG | Ripper::EXPR_LABELED != 0
- else
- self[3] == other[3]
- 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.
@@ -294,16 +244,19 @@ module Prism
# 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
+ attr_reader :tokens #: Array[lex_compat_token]
+ #: () -> void
def initialize
@tokens = []
end
+ #: (lex_compat_token token) -> void
def <<(token)
tokens << token
end
+ #: () -> Array[lex_compat_token]
def to_a
tokens
end
@@ -313,22 +266,26 @@ module Prism
# 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
+ attr_reader :split #: bool
+ attr_reader :tokens #: Array[lex_compat_token]
+ #: (bool split) -> void
def initialize(split)
@split = split
@tokens = []
end
+ #: (lex_compat_token token) -> void
def <<(token)
tokens << token
end
+ #: () -> Array[lex_compat_token]
def to_a
embexpr_balance = 0
- tokens.each_with_object([]) do |token, results| #$ Array[Token]
- case token.event
+ tokens.each_with_object([]) do |token, results| #$ Array[lex_compat_token]
+ case token[1]
when :on_embexpr_beg
embexpr_balance += 1
results << token
@@ -343,9 +300,9 @@ module Prism
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|
+ token[2].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])
+ results << [[lineno, column], :on_tstring_content, value, token[3]]
lineno += value.count("\n")
end
else
@@ -374,8 +331,13 @@ module Prism
class DedentingHeredoc # :nodoc:
TAB_WIDTH = 8
- attr_reader :tokens, :dedent_next, :dedent, :embexpr_balance
+ attr_reader :tokens #: Array[lex_compat_token]
+ attr_reader :dedent_next #: bool
+ attr_reader :dedent #: Integer?
+ attr_reader :embexpr_balance #: Integer
+ # @rbs @ended_on_newline: bool
+ #: () -> void
def initialize
@tokens = []
@dedent_next = true
@@ -387,8 +349,10 @@ module Prism
# 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.
+ #
+ #: (lex_compat_token token) -> void
def <<(token)
- case token.event
+ case token[1]
when :on_embexpr_beg, :on_heredoc_beg
@embexpr_balance += 1
@dedent = 0 if @dedent_next && @ended_on_newline
@@ -396,10 +360,10 @@ module Prism
@embexpr_balance -= 1
when :on_tstring_content
if embexpr_balance == 0
- line = token.value
+ line = token[2]
if dedent_next && !(line.strip.empty? && line.end_with?("\n"))
- leading = line[/\A(\s*)\n?/, 1]
+ leading = line[/\A(\s*)\n?/, 1] #: String
next_dedent = 0
leading.each_char do |char|
@@ -419,20 +383,21 @@ module Prism
end
end
- @dedent_next = token.event == :on_tstring_content && embexpr_balance == 0
+ @dedent_next = token[1] == :on_tstring_content && embexpr_balance == 0
@ended_on_newline = false
tokens << token
end
+ #: () -> Array[lex_compat_token]
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 = [] #: Array[Token]
+ results = [] #: Array[lex_compat_token]
embexpr_balance = 0
tokens.each do |token|
- case token.event
+ case token[1]
when :on_embexpr_beg, :on_heredoc_beg
embexpr_balance += 1
results << token
@@ -444,9 +409,9 @@ module Prism
lineno = token[0][0]
column = token[0][1]
- token.value.split(/(?<=\n)/).each_with_index do |value, index|
+ token[2].split(/(?<=\n)/).each_with_index do |value, index|
column = 0 if index > 0
- results << Token.new([[lineno, column], :on_tstring_content, value, token.state])
+ results << [[lineno, column], :on_tstring_content, value, token[3]]
lineno += 1
end
else
@@ -463,7 +428,7 @@ module Prism
# If the minimum common whitespace is 0, then we need to concatenate
# string nodes together that are immediately adjacent.
if dedent == 0
- results = [] #: Array[Token]
+ results = [] #: Array[lex_compat_token]
embexpr_balance = 0
index = 0
@@ -474,15 +439,15 @@ module Prism
results << token
index += 1
- case token.event
+ case token[1]
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.match?(/\\\r?\n\z/)
- token.value << tokens[index].value
+ while index < max_index && tokens[index][1] == :on_tstring_content && !token[2].match?(/\\\r?\n\z/)
+ token[2] << tokens[index][2]
index += 1
end
end
@@ -496,7 +461,7 @@ module Prism
# 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 = [] #: Array[Token]
+ results = [] #: Array[lex_compat_token]
dedent_next = true
embexpr_balance = 0
@@ -505,7 +470,7 @@ module Prism
# 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
+ case token[1]
when :on_embexpr_beg
embexpr_balance += 1
results << token
@@ -517,7 +482,7 @@ module Prism
# 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)/)
+ splits = token[2].split(/(?<=\n)/)
index = 0
while index < splits.length
@@ -535,7 +500,8 @@ module Prism
# 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
+ unjoined = splits[index..] #: Array[String]
+ line = unjoined.join
index = splits.length
end
@@ -574,12 +540,12 @@ module Prism
ignored = deleted_chars.join
line.delete_prefix!(ignored)
- results << Token.new([[lineno, 0], :on_ignored_sp, ignored, token[3]])
+ results << [[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?
+ results << [[lineno, column], token[1], line, token[3]] unless line.empty?
index += 1
end
else
@@ -590,7 +556,7 @@ module Prism
end
dedent_next =
- ((token.event == :on_tstring_content) || (token.event == :on_heredoc_end)) &&
+ ((token[1] == :on_tstring_content) || (token[1] == :on_heredoc_end)) &&
embexpr_balance == 0
end
@@ -600,12 +566,14 @@ module Prism
# Here we will split between the two types of heredocs and return the
# object that will store their tokens.
+ #--
+ #: (lex_compat_token opening) -> (PlainHeredoc | DashHeredoc | DedentingHeredoc)
def self.build(opening)
- case opening.value[2]
+ case opening[2][2]
when "~"
DedentingHeredoc.new
when "-"
- DashHeredoc.new(opening.value[3] != "'")
+ DashHeredoc.new(opening[2][3] != "'")
else
PlainHeredoc.new
end
@@ -614,33 +582,43 @@ module Prism
private_constant :Heredoc
- attr_reader :source, :options
+ # 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.
+ BOM_FLUSHED = RUBY_VERSION >= "3.3.0"
+ private_constant :BOM_FLUSHED
+ attr_reader :options #: Hash[Symbol, untyped]
+ # @rbs @source: String
+
+ #: (String source, **untyped options) -> void
def initialize(source, **options)
@source = source
@options = options
end
+ #: () -> Result
def result
- tokens = [] #: Array[LexCompat::Token]
+ tokens = [] #: Array[lex_compat_token]
state = :default
heredoc_stack = [[]] #: Array[Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]]
- result = Prism.lex(source, **options)
+ result = Prism.lex(@source, **options)
+ source = result.source
result_value = result.value
- previous_state = nil #: Ripper::Lexer::State?
+ previous_state = nil #: Translation::Ripper::Lexer::State?
last_heredoc_end = nil #: Integer?
+ eof_token = nil #: Token?
+
+ bom = source.slice(0, 3) == "\xEF\xBB\xBF"
- # 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 |(prism_token, prism_state), index|
+ lineno = prism_token.location.start_line
+ column = prism_token.location.start_column
- result_value.each_with_index do |(token, lex_state), index|
- lineno = token.location.start_line
- column = token.location.start_column
+ event = RIPPER.fetch(prism_token.type)
+ value = prism_token.value
+ lex_state = Translation::Ripper::Lexer::State[prism_state]
# 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
@@ -650,70 +628,53 @@ module Prism
if bom && lineno == 1
column -= 3
- if index == 0 && column == 0 && !bom_flushed
+ if index == 0 && column == 0 && !BOM_FLUSHED
flushed =
- case token.type
+ case prism_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?("%")
+ 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 =
+ lex_compat_token =
case event
when :on___end__
- EndContentToken.new([[lineno, column], event, value, lex_state])
+ # 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.
+ value = value[0..value.index("\n")] #: String
+ [[lineno, column], event, value, lex_state]
when :on_comment
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
+ [[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
+ last_heredoc_end = prism_token.location.end_offset
+ [[lineno, column], event, value, lex_state]
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])
+ [[lineno, column], event, value, lex_state]
+ when :on_words_sep
+ # Ripper emits one token each per line.
+ value.each_line.with_index do |line, index|
+ if index > 0
+ lineno += 1
+ column = 0
+ end
+ tokens << [[lineno, column], event, line, lex_state]
+ end
+ tokens.pop #: lex_compat_token
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
@@ -738,13 +699,14 @@ module Prism
counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0
end
- Ripper::Lexer::State.new(result_value[current_index][1])
+ Translation::Ripper::Lexer::State[result_value[current_index][1]]
else
previous_state
end
- Token.new([[lineno, column], event, value, lex_state])
+ [[lineno, column], event, value, lex_state]
when :on_eof
+ eof_token = prism_token
previous_token = result_value[index - 1][0]
# If we're at the end of the file and the previous token was a
@@ -759,7 +721,7 @@ module Prism
# 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
+ end_offset = prism_token.location.start_offset
if start_offset < end_offset
if bom
@@ -767,14 +729,14 @@ module Prism
end_offset += 3
end
- tokens << Token.new([[lineno, 0], :on_nl, source.byteslice(start_offset...end_offset), lex_state])
+ tokens << [[lineno, 0], :on_nl, source.slice(start_offset, end_offset - start_offset), lex_state]
end
end
- Token.new([[lineno, column], event, value, lex_state])
+ [[lineno, column], event, value, lex_state]
else
- Token.new([[lineno, column], event, value, lex_state])
- end
+ [[lineno, column], event, value, lex_state]
+ end #: lex_compat_token
previous_state = lex_state
@@ -791,19 +753,19 @@ module Prism
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
+ tokens << lex_compat_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)
+ heredoc_stack.last << Heredoc.build(lex_compat_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
+ heredoc_stack.last.last << lex_compat_token
case event
when :on_heredoc_beg
@@ -811,7 +773,7 @@ module Prism
# 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)]
+ heredoc_stack << [Heredoc.build(lex_compat_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
@@ -820,10 +782,10 @@ module Prism
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 %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 = heredoc_stack.pop #: Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]
+ heredoc_stack.last.last << lex_compat_token
flushing.each do |heredoc|
heredoc.to_a.each do |flushed_token|
@@ -835,12 +797,12 @@ module Prism
next
end
elsif event == :on_heredoc_beg
- tokens << token
+ tokens << lex_compat_token
state = :heredoc_opened
- heredoc_stack.last << Heredoc.build(token)
+ heredoc_stack.last << Heredoc.build(lex_compat_token)
next
elsif heredoc_stack.size > 1
- heredoc_stack[-2].last << token
+ heredoc_stack[-2].last << lex_compat_token
next
end
@@ -851,77 +813,94 @@ module Prism
heredoc_stack.last.clear
state = :default
- tokens << token
+ tokens << lex_compat_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)
-
- Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, Source.for(source))
- end
- end
+ # Drop the EOF token from the list. The EOF token may not be
+ # present if the source was syntax invalid
+ if tokens.dig(-1, 1) == :on_eof
+ tokens = tokens[0...-1] #: Array[lex_compat_token]
+ end
- private_constant :LexCompat
+ # We sort by location because Ripper.lex sorts.
+ tokens.sort_by! do |token|
+ line, column = token[0]
+ source.byte_offset(line, column)
+ end
- # This is a class that wraps the Ripper lexer to produce almost exactly the
- # same tokens.
- class LexRipper # :nodoc:
- attr_reader :source
+ tokens = post_process_tokens(tokens, source, result.data_loc, bom, eof_token)
- def initialize(source)
- @source = source
+ Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, result.continuable?, source)
end
- def result
- previous = [] #: [[Integer, Integer], Symbol, String, untyped] | []
- results = [] #: Array[[[Integer, Integer], Symbol, String, untyped]]
-
- lex(source).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]
+ private
+
+ #: (Array[lex_compat_token] tokens, Source source, Location? data_loc, bool bom, Token? eof_token) -> Array[lex_compat_token]
+ def post_process_tokens(tokens, source, data_loc, bom, eof_token)
+ new_tokens = [] #: Array[lex_compat_token]
+
+ prev_token_state = Translation::Ripper::Lexer::State[Translation::Ripper::EXPR_BEG]
+ prev_token_end = bom ? 3 : 0
+
+ cache = Translation::Ripper::LineAndColumnCache.new(source)
+
+ tokens.each do |token|
+ # Skip missing heredoc ends.
+ next if token[1] == :on_heredoc_end && token[2] == ""
+
+ # Add :on_sp tokens.
+ line, column = token[0]
+ start_offset = source.byte_offset(line, column)
+
+ # Ripper reports columns on line 1 without counting the BOM, so we
+ # adjust to get the real offset
+ start_offset += 3 if line == 1 && bom
+
+ if start_offset > prev_token_end
+ sp_value = source.slice(prev_token_end, start_offset - prev_token_end)
+ sp_line, sp_column = cache.line_and_column(prev_token_end)
+ # Ripper reports columns on line 1 without counting the BOM
+ sp_column -= 3 if sp_line == 1 && bom
+ continuation_index = sp_value.byteindex("\\")
+
+ # ripper emits up to three :on_sp tokens when line continuations are used
+ if continuation_index
+ next_whitespace_index = continuation_index + 1
+ next_whitespace_index += 1 if sp_value.byteslice(next_whitespace_index) == "\r"
+ next_whitespace_index += 1
+ first_whitespace = sp_value[0...continuation_index] #: String
+ continuation = sp_value[continuation_index...next_whitespace_index] #: String
+ second_whitespace = sp_value[next_whitespace_index..] || ""
+
+ new_tokens << [[sp_line, sp_column], :on_sp, first_whitespace, prev_token_state] unless first_whitespace.empty?
+ new_tokens << [[sp_line, sp_column + continuation_index], :on_sp, continuation, prev_token_state]
+ new_tokens << [[sp_line + 1, 0], :on_sp, second_whitespace, prev_token_state] unless second_whitespace.empty?
else
- results << token
- previous = token
+ new_tokens << [[sp_line, sp_column], :on_sp, sp_value, prev_token_state]
end
- else
- results << token
- previous = token
end
- end
-
- results
- end
-
- private
- if Ripper.method(:lex).parameters.assoc(:keyrest)
- def lex(source)
- Ripper.lex(source, raise_errors: true)
+ new_tokens << token
+ prev_token_state = token[3]
+ prev_token_end = start_offset + token[2].bytesize
end
- else
- def lex(source)
- ripper = Ripper::Lexer.new(source)
- ripper.lex.tap do |result|
- raise SyntaxError, ripper.errors.map(&:message).join(' ;') if ripper.errors.any?
+
+ if !data_loc && eof_token # no trailing :on_sp with __END__ as it is always preceded by :on_nl
+ end_offset = eof_token.location.end_offset
+ if prev_token_end < end_offset
+ new_tokens << [
+ [source.line(prev_token_end), source.column(prev_token_end)],
+ :on_sp,
+ source.slice(prev_token_end, end_offset - prev_token_end),
+ prev_token_state
+ ]
end
end
+
+ new_tokens
end
end
- private_constant :LexRipper
+ private_constant :LexCompat
end
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
index b007a051ea..8a6624e76d 100644
--- a/lib/prism/node_ext.rb
+++ b/lib/prism/node_ext.rb
@@ -1,12 +1,17 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
+#--
# Here we are reopening the prism module to provide methods on nodes that aren't
# templated and are meant as convenience methods.
+#++
module Prism
class Node
+ #: (*String replacements) -> void
def deprecated(*replacements) # :nodoc:
- location = caller_locations(1, 1)
- location = location[0].label if location
+ location = caller_locations(1, 1)&.[](0)&.label
suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
warn(<<~MSG, uplevel: 1, category: :deprecated)
@@ -20,7 +25,9 @@ module Prism
module RegularExpressionOptions # :nodoc:
# Returns a numeric value that represents the flags that were used to create
# the regular expression.
- def options
+ #--
+ #: (Integer flags) -> Integer
+ def self.options(flags)
o = 0
o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
@@ -32,43 +39,87 @@ module Prism
end
class InterpolatedMatchLastLineNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
class InterpolatedRegularExpressionNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
class MatchLastLineNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
class RegularExpressionNode < Node
- include RegularExpressionOptions
+ # Returns a numeric value that represents the flags that were used to create
+ # the regular expression.
+ #--
+ #: () -> Integer
+ def options
+ RegularExpressionOptions.options(flags)
+ end
end
private_constant :RegularExpressionOptions
module HeredocQuery # :nodoc:
# Returns true if this node was represented as a heredoc in the source code.
- def heredoc?
+ #--
+ #: (String? opening) -> bool?
+ def self.heredoc?(opening)
+ # @type self: InterpolatedStringNode | InterpolatedXStringNode | StringNode | XStringNode
opening&.start_with?("<<")
end
end
class InterpolatedStringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
end
class InterpolatedXStringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
end
class StringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
# Occasionally it's helpful to treat a string as if it were interpolated so
# that there's a consistent interface for working with strings.
+ #--
+ #: () -> InterpolatedStringNode
def to_interpolated
InterpolatedStringNode.new(
source,
@@ -83,10 +134,17 @@ module Prism
end
class XStringNode < Node
- include HeredocQuery
+ # Returns true if this node was represented as a heredoc in the source code.
+ #--
+ #: () -> bool?
+ def heredoc?
+ HeredocQuery.heredoc?(opening)
+ end
# Occasionally it's helpful to treat a string as if it were interpolated so
# that there's a consistent interface for working with strings.
+ #--
+ #: () -> InterpolatedXStringNode
def to_interpolated
InterpolatedXStringNode.new(
source,
@@ -104,6 +162,8 @@ module Prism
class ImaginaryNode < Node
# Returns the value of the node as a Ruby Complex.
+ #--
+ #: () -> Complex
def value
Complex(0, numeric.value)
end
@@ -111,31 +171,25 @@ module Prism
class RationalNode < Node
# Returns the value of the node as a Ruby Rational.
+ #--
+ #: () -> Rational
def value
Rational(numerator, denominator)
end
-
- # Returns the value of the node as an IntegerNode or a FloatNode. This
- # method is deprecated in favor of #value or #numerator/#denominator.
- def numeric
- deprecated("value", "numerator", "denominator")
-
- if denominator == 1
- IntegerNode.new(source, -1, location.chop, flags, numerator)
- else
- FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator)
- end
- end
end
class ConstantReadNode < Node
# Returns the list of parts for the full name of this constant.
# For example: [:Foo]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
[name]
end
# Returns the full name of this constant. For example: "Foo"
+ #--
+ #: () -> String
def full_name
name.to_s
end
@@ -144,11 +198,15 @@ module Prism
class ConstantWriteNode < Node
# Returns the list of parts for the full name of this constant.
# For example: [:Foo]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
[name]
end
# Returns the full name of this constant. For example: "Foo"
+ #--
+ #: () -> String
def full_name
name.to_s
end
@@ -163,13 +221,15 @@ module Prism
# local variable
class DynamicPartsInConstantPathError < StandardError; end
- # An error class raised when missing nodes are found while computing a
+ # An error class raised when error recovery nodes are found while computing a
# constant path's full name. For example:
# Foo:: -> raises because the constant path is missing the last part
- class MissingNodesInConstantPathError < StandardError; end
+ class ErrorRecoveryNodesInConstantPathError < StandardError; end
# Returns the list of parts for the full name of this constant path.
# For example: [:Foo, :Bar]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
parts = [] #: Array[Symbol]
current = self #: node?
@@ -177,7 +237,7 @@ module Prism
while current.is_a?(ConstantPathNode)
name = current.name
if name.nil?
- raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
+ raise ErrorRecoveryNodesInConstantPathError, "Constant path contains error recovery nodes. Cannot compute full name"
end
parts.unshift(name)
@@ -192,30 +252,21 @@ module Prism
end
# Returns the full name of this constant path. For example: "Foo::Bar"
+ #--
+ #: () -> String
def full_name
full_name_parts.join("::")
end
-
- # Previously, we had a child node on this class that contained either a
- # constant read or a missing node. To not cause a breaking change, we
- # continue to supply that API.
- def child
- deprecated("name", "name_loc")
-
- if name
- ConstantReadNode.new(source, -1, name_loc, 0, name)
- else
- MissingNode.new(source, -1, location, 0)
- end
- end
end
class ConstantPathTargetNode < Node
# Returns the list of parts for the full name of this constant path.
# For example: [:Foo, :Bar]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
parts =
- case parent
+ case (parent = self.parent)
when ConstantPathNode, ConstantReadNode
parent.full_name_parts
when nil
@@ -225,40 +276,33 @@ module Prism
raise ConstantPathNode::DynamicPartsInConstantPathError, "Constant target path contains dynamic parts. Cannot compute full name"
end
- if name.nil?
- raise ConstantPathNode::MissingNodesInConstantPathError, "Constant target path contains missing nodes. Cannot compute full name"
+ if (name = self.name).nil?
+ raise ConstantPathNode::ErrorRecoveryNodesInConstantPathError, "Constant target path contains error recovery nodes. Cannot compute full name"
end
parts.push(name)
end
# Returns the full name of this constant path. For example: "Foo::Bar"
+ #--
+ #: () -> String
def full_name
full_name_parts.join("::")
end
-
- # Previously, we had a child node on this class that contained either a
- # constant read or a missing node. To not cause a breaking change, we
- # continue to supply that API.
- def child
- deprecated("name", "name_loc")
-
- if name
- ConstantReadNode.new(source, -1, name_loc, 0, name)
- else
- MissingNode.new(source, -1, location, 0)
- end
- end
end
class ConstantTargetNode < Node
# Returns the list of parts for the full name of this constant.
# For example: [:Foo]
+ #--
+ #: () -> Array[Symbol]
def full_name_parts
[name]
end
# Returns the full name of this constant. For example: "Foo"
+ #--
+ #: () -> String
def full_name
name.to_s
end
@@ -266,6 +310,8 @@ module Prism
class ParametersNode < Node
# Mirrors the Method#parameters method.
+ #--
+ #: () -> Array[[Symbol, Symbol] | [Symbol]]
def signature
names = [] #: Array[[Symbol, Symbol] | [Symbol]]
@@ -275,7 +321,7 @@ module Prism
optionals.each { |param| names << [:opt, param.name] }
- if rest && rest.is_a?(RestParameterNode)
+ if (rest = self.rest).is_a?(RestParameterNode)
names << [:rest, rest.name || :*]
end
@@ -283,8 +329,7 @@ module Prism
case param
when MultiTargetNode
names << [:req]
- when NoKeywordsParameterNode, KeywordRestParameterNode, ForwardingParameterNode
- # Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts
+ when ErrorRecoveryNode
raise "Invalid syntax"
else
names << [:req, param.name]
@@ -304,7 +349,7 @@ module Prism
keyopt.each { |param| names << [:key, param.name] }
- case keyword_rest
+ case (keyword_rest = self.keyword_rest)
when ForwardingParameterNode
names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
when KeywordRestParameterNode
@@ -313,7 +358,13 @@ module Prism
names << [:nokey]
end
- names << [:block, block.name || :&] if block
+ case (block = self.block)
+ when BlockParameterNode
+ names << [:block, block.name || :&]
+ when NoBlockParameterNode
+ names << [:noblock]
+ end
+
names
end
end
@@ -328,181 +379,10 @@ module Prism
# can be any amount of space between the message and the = sign. However,
# sometimes you want the location of the full message including the inner
# space and the = sign. This method provides that.
+ #--
+ #: () -> Location?
def full_message_loc
attribute_write? ? message_loc&.adjoin("=") : message_loc
end
end
-
- class CallOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class ClassVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class ConstantOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class ConstantPathOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class GlobalVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class IndexOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class InstanceVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class LocalVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class CaseMatchNode < Node
- # Returns the else clause of the case match node. This method is deprecated
- # in favor of #else_clause.
- def consequent
- deprecated("else_clause")
- else_clause
- end
- end
-
- class CaseNode < Node
- # Returns the else clause of the case node. This method is deprecated in
- # favor of #else_clause.
- def consequent
- deprecated("else_clause")
- else_clause
- end
- end
-
- class IfNode < Node
- # Returns the subsequent if/elsif/else clause of the if node. This method is
- # deprecated in favor of #subsequent.
- def consequent
- deprecated("subsequent")
- subsequent
- end
- end
-
- class RescueNode < Node
- # Returns the subsequent rescue clause of the rescue node. This method is
- # deprecated in favor of #subsequent.
- def consequent
- deprecated("subsequent")
- subsequent
- end
- end
-
- class UnlessNode < Node
- # Returns the else clause of the unless node. This method is deprecated in
- # favor of #else_clause.
- def consequent
- deprecated("else_clause")
- else_clause
- end
- end
end
diff --git a/lib/prism/node_find.rb b/lib/prism/node_find.rb
new file mode 100644
index 0000000000..697ee430e8
--- /dev/null
+++ b/lib/prism/node_find.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
+
+module Prism
+ # Finds the Prism AST node corresponding to a given Method, UnboundMethod,
+ # Proc, or Thread::Backtrace::Location. On CRuby, uses node_id from the
+ # instruction sequence for an exact match. On other implementations, falls
+ # back to best-effort matching by source location line number.
+ #
+ # This module is autoloaded so that programs that don't use Prism.find don't
+ # pay for its definition.
+ module NodeFind # :nodoc:
+ # Find the node for the given callable or backtrace location.
+ #--
+ #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, bool rubyvm) -> Node?
+ def self.find(callable, rubyvm)
+ case callable
+ when Proc
+ if rubyvm
+ RubyVMCallableFind.new.find(callable)
+ elsif callable.lambda?
+ LineLambdaFind.new.find(callable)
+ else
+ LineProcFind.new.find(callable)
+ end
+ when Method, UnboundMethod
+ if rubyvm
+ RubyVMCallableFind.new.find(callable)
+ else
+ LineMethodFind.new.find(callable)
+ end
+ when Thread::Backtrace::Location
+ if rubyvm
+ RubyVMBacktraceLocationFind.new.find(callable)
+ else
+ LineBacktraceLocationFind.new.find(callable)
+ end
+ else
+ raise ArgumentError, "Expected a Method, UnboundMethod, Proc, or Thread::Backtrace::Location, got #{callable.class}"
+ end
+ end
+
+ # Base class that handles parsing a file.
+ class Find
+ private
+
+ # Parse the given file path, returning a ParseResult or nil.
+ #--
+ #: (String? file) -> ParseResult?
+ def parse_file(file)
+ return unless file && File.readable?(file)
+ result = Prism.parse_file(file)
+ result if result.success?
+ end
+ end
+
+ # Finds the AST node for a Method, UnboundMethod, or Proc using the node_id
+ # from the instruction sequence.
+ class RubyVMCallableFind < Find
+ # Find the node for the given callable using the ISeq node_id.
+ #--
+ #: (Method | UnboundMethod | Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+ return unless (iseq = RubyVM::InstructionSequence.of(callable))
+
+ header = iseq.to_a[4]
+ return unless header[:parser] == :prism
+
+ result.value.find { |node| node.node_id == header[:node_id] }
+ end
+ end
+
+ # Finds the AST node for a Thread::Backtrace::Location using the node_id
+ # from the backtrace location.
+ class RubyVMBacktraceLocationFind < Find
+ # Find the node for the given backtrace location using node_id.
+ #--
+ #: (Thread::Backtrace::Location location) -> Node?
+ def find(location)
+ file = location.absolute_path || location.path
+ return unless (result = parse_file(file))
+ return unless RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location)
+
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
+
+ result.value.find { |node| node.node_id == node_id }
+ end
+ end
+
+ # Finds the AST node for a Method or UnboundMethod using best-effort line
+ # matching. Used on non-CRuby implementations.
+ class LineMethodFind < Find
+ # Find the node for the given method by matching on name and line.
+ #--
+ #: (Method | UnboundMethod callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ name = callable.name
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when DefNode
+ node.name == name && node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a lambda using best-effort line matching. Used
+ # on non-CRuby implementations.
+ class LineLambdaFind < Find
+ # Find the node for the given lambda by matching on line.
+ #--
+ #: (Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when LambdaNode
+ node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a non-lambda Proc using best-effort line
+ # matching. Used on non-CRuby implementations.
+ class LineProcFind < Find
+ # Find the node for the given proc by matching on line.
+ #--
+ #: (Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when ForNode
+ node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a Thread::Backtrace::Location using best-effort
+ # line matching. Used on non-CRuby implementations.
+ class LineBacktraceLocationFind < Find
+ # Find the node for the given backtrace location by matching on line.
+ #--
+ #: (Thread::Backtrace::Location location) -> Node?
+ def find(location)
+ file = location.absolute_path || location.path
+ return unless (result = parse_file(file))
+
+ start_line = location.lineno
+ result.value.find { |node| node.location.start_line == start_line }
+ end
+ end
+ end
+end
diff --git a/lib/prism/pack.rb b/lib/prism/pack.rb
deleted file mode 100644
index c0de8ab8b7..0000000000
--- a/lib/prism/pack.rb
+++ /dev/null
@@ -1,228 +0,0 @@
-# frozen_string_literal: true
-# typed: ignore
-
-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"
- else
- raise
- 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
- # @type var source_width: Integer
- " #{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
index 9a3e7c5b79..93d3c006b7 100644
--- a/lib/prism/parse_result.rb
+++ b/lib/prism/parse_result.rb
@@ -1,6 +1,16 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
+ # @rbs!
+ # # An internal interface for a cache that can be used to compute code
+ # # units from byte offsets.
+ # interface _CodeUnitsCache
+ # def []: (Integer byte_offset) -> Integer
+ # end
+
# 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.
@@ -9,7 +19,18 @@ module Prism
# be used instead of `new` and it will return either a `Source` or a
# specialized and more performant `ASCIISource` if no multibyte characters
# are present in the source code.
- def self.for(source, start_line = 1, offsets = [])
+ #
+ # Note that if you are calling this method manually, you will need to supply
+ # the start_line and offsets parameters. start_line is the line number that
+ # the source starts on, which is typically 1 but can be different if this
+ # source is a subset of a larger source or if this is an eval. offsets is an
+ # array of byte offsets for the start of each line in the source code, which
+ # can be calculated by iterating through the source code and recording the
+ # byte offset whenever a newline character is encountered. The first
+ # element is always 0 to mark the first line.
+ #--
+ #: (String source, Integer start_line, Array[Integer] offsets) -> Source
+ def self.for(source, start_line, offsets)
if source.ascii_only?
ASCIISource.new(source, start_line, offsets)
elsif source.encoding == Encoding::BINARY
@@ -33,77 +54,122 @@ module Prism
end
# The source code that this source object represents.
- attr_reader :source
+ attr_reader :source #: String
# The line number where this source starts.
- attr_reader :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.
- def initialize(source, start_line = 1, offsets = [])
+ attr_reader :start_line #: Integer
+
+ # The list of newline byte offsets in the source code. When initialized from
+ # the C extension, this may be a packed binary string of uint32_t values
+ # that is lazily unpacked on first access.
+ #--
+ #: () -> Array[Integer]
+ def offsets
+ offsets = @offsets
+ return offsets if offsets.is_a?(Array)
+ @offsets = offsets.unpack("L*")
+ end
+
+ # Create a new source object with the given source code. The offsets
+ # parameter can be either an Array of Integer byte offsets or a packed
+ # binary string of uint32_t values (from the C extension).
+ #--
+ #: (String source, Integer start_line, Array[Integer] | String offsets) -> void
+ def initialize(source, start_line, offsets)
@source = source
- @start_line = start_line # set after parsing is done
- @offsets = offsets # set after parsing is done
+ @start_line = start_line
+ @offsets = offsets
end
# Replace the value of start_line with the given value.
+ #--
+ #: (Integer start_line) -> void
def replace_start_line(start_line)
@start_line = start_line
end
# Replace the value of offsets with the given value.
+ #--
+ #: (Array[Integer] offsets) -> void
def replace_offsets(offsets)
- @offsets.replace(offsets)
+ @offsets = offsets
end
# Returns the encoding of the source code, which is set by parameters to the
# parser or by the encoding magic comment.
+ #--
+ #: () -> Encoding
def encoding
source.encoding
end
# Returns the lines of the source code as an array of strings.
+ #--
+ #: () -> Array[String]
def lines
source.lines
end
# Perform a byteslice on the source code using the given byte offset and
# byte length.
+ #--
+ #: (Integer byte_offset, Integer length) -> String
def slice(byte_offset, length)
source.byteslice(byte_offset, length) or raise
end
+ # Converts the line number and column in bytes to a byte offset.
+ #--
+ #: (Integer line, Integer column) -> Integer
+ def byte_offset(line, column)
+ normal = line - @start_line
+ raise IndexError if normal < 0
+ offsets.fetch(normal) + column
+ rescue IndexError
+ raise ArgumentError, "line #{line} is out of range"
+ end
+
# Binary search through the offsets to find the line number for the given
# byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
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.
+ #--
+ #: (Integer byte_offset) -> Integer
def line_start(byte_offset)
offsets[find_line(byte_offset)]
end
# Returns the byte offset of the end of the line corresponding to the given
# byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def line_end(byte_offset)
offsets[find_line(byte_offset) + 1] || source.bytesize
end
- # Return the column number for the given byte offset.
+ # Return the column in bytes for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def column(byte_offset)
byte_offset - line_start(byte_offset)
end
# Return the character offset for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_offset(byte_offset)
(source.byteslice(0, byte_offset) or raise).length
end
- # Return the column number in characters for the given byte offset.
+ # Return the column in characters for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_column(byte_offset)
character_offset(byte_offset) - character_offset(line_start(byte_offset))
end
@@ -120,7 +186,11 @@ module Prism
# possible that the given byte offset will not occur on a character
# boundary. Second, it's possible that the source code will contain a
# character that has no equivalent in the given encoding.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_offset(byte_offset, encoding)
+ return byte_offset if encoding == Encoding::UTF_8
+
byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding, invalid: :replace, undef: :replace)
if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
@@ -132,43 +202,36 @@ module Prism
# Generate a cache that targets a specific encoding for calculating code
# unit offsets.
+ #--
+ #: (Encoding encoding) -> CodeUnitsCache
def code_units_cache(encoding)
CodeUnitsCache.new(source, encoding)
end
- # Returns the column number in code units for the given encoding for the
+ # Returns the column in code units for the given encoding for the
# given byte offset.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_column(byte_offset, encoding)
code_units_offset(byte_offset, encoding) - code_units_offset(line_start(byte_offset), encoding)
end
# Freeze this object and the objects it contains.
+ #--
+ #: () -> void
def deep_freeze
source.freeze
offsets.freeze
freeze
end
- private
-
- # Binary search through the offsets to find the line number for the given
+ # Binary search through the offsets to find the index 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 (offset = offsets[mid]) == byte_offset
-
- if offset < byte_offset
- left = mid + 1
- else
- right = mid - 1
- end
- end
-
- left - 1
+ #--
+ #: (Integer byte_offset) -> Integer
+ def find_line(byte_offset) # :nodoc:
+ index = offsets.bsearch_index { |offset| offset > byte_offset } || offsets.length
+ index - 1
end
end
@@ -187,38 +250,69 @@ module Prism
# has not yet been implemented.
#
class CodeUnitsCache
+ # Counter used for UTF-8, where one code unit equals one byte.
+ class UTF8Counter # :nodoc:
+ #: (Integer byte_offset, Integer byte_length) -> Integer
+ def count(byte_offset, byte_length)
+ byte_length
+ end
+ end
+
class UTF16Counter # :nodoc:
+ # @rbs @source: String
+ # @rbs @encoding: Encoding
+
+ #: (String source, Encoding encoding) -> void
def initialize(source, encoding)
@source = source
@encoding = encoding
end
+ #: (Integer byte_offset, Integer byte_length) -> Integer
def count(byte_offset, byte_length)
- @source.byteslice(byte_offset, byte_length).encode(@encoding, invalid: :replace, undef: :replace).bytesize / 2
+ (@source.byteslice(byte_offset, byte_length) or raise).encode(@encoding, invalid: :replace, undef: :replace).bytesize / 2
end
end
- class LengthCounter # :nodoc:
+ # Counter used for UTF-32, where one code unit equals one code point and
+ # matches String#length. Also used as a best-effort fallback for any other
+ # encoding that does not have a dedicated counter.
+ class UTF32Counter # :nodoc:
+ # @rbs @source: String
+ # @rbs @encoding: Encoding
+
+ #: (String source, Encoding encoding) -> void
def initialize(source, encoding)
@source = source
@encoding = encoding
end
+ #: (Integer byte_offset, Integer byte_length) -> Integer
def count(byte_offset, byte_length)
- @source.byteslice(byte_offset, byte_length).encode(@encoding, invalid: :replace, undef: :replace).length
+ (@source.byteslice(byte_offset, byte_length) or raise).encode(@encoding, invalid: :replace, undef: :replace).length
end
end
- private_constant :UTF16Counter, :LengthCounter
+ private_constant :UTF8Counter, :UTF16Counter, :UTF32Counter
+
+ # @rbs @source: String
+ # @rbs @counter: UTF8Counter | UTF16Counter | UTF32Counter
+ # @rbs @cache: Hash[Integer, Integer]
+ # @rbs @offsets: Array[Integer]
# Initialize a new cache with the given source and encoding.
+ #--
+ #: (String source, Encoding encoding) -> void
def initialize(source, encoding)
@source = source
@counter =
- if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
+ case encoding
+ when Encoding::UTF_8
+ UTF8Counter.new
+ when Encoding::UTF_16LE, Encoding::UTF_16BE
UTF16Counter.new(source, encoding)
else
- LengthCounter.new(source, encoding)
+ UTF32Counter.new(source, encoding)
end
@cache = {} #: Hash[Integer, Integer]
@@ -226,6 +320,8 @@ module Prism
end
# Retrieve the code units offset from the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def [](byte_offset)
@cache[byte_offset] ||=
if (index = @offsets.bsearch_index { |offset| offset > byte_offset }).nil?
@@ -252,11 +348,15 @@ module Prism
# at that point we will treat everything as single-byte characters.
class ASCIISource < Source
# Return the character offset for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_offset(byte_offset)
byte_offset
end
- # Return the column number in characters for the given byte offset.
+ # Return the column in characters for the given byte offset.
+ #--
+ #: (Integer byte_offset) -> Integer
def character_column(byte_offset)
byte_offset - line_start(byte_offset)
end
@@ -267,6 +367,8 @@ module Prism
# This method is tested with UTF-8, UTF-16, and UTF-32. If there is the
# concept of code units that differs from the number of characters in other
# encodings, it is not captured here.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_offset(byte_offset, encoding)
byte_offset
end
@@ -274,6 +376,8 @@ module Prism
# Returns a cache that is the identity function in order to maintain the
# same interface. We can do this because code units are always equivalent to
# byte offsets for ASCII-only sources.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
->(byte_offset) { byte_offset }
end
@@ -281,6 +385,8 @@ module Prism
# Specialized version of `code_units_column` that does not depend on
# `code_units_offset`, which is a more expensive operation. This is
# essentially the same as `Prism::Source#column`.
+ #--
+ #: (Integer byte_offset, Encoding encoding) -> Integer
def code_units_column(byte_offset, encoding)
byte_offset - line_start(byte_offset)
end
@@ -290,18 +396,23 @@ module Prism
class Location
# A Source object that is used to determine more information from the given
# offset and length.
- attr_reader :source
+ attr_reader :source #: Source
protected :source
# The byte offset from the beginning of the source where this location
# starts.
- attr_reader :start_offset
+ attr_reader :start_offset #: Integer
# The length of this location in bytes.
- attr_reader :length
+ attr_reader :length #: Integer
+
+ # @rbs @leading_comments: Array[Comment]?
+ # @rbs @trailing_comments: Array[Comment]?
# Create a new location object with the given source, start byte offset, and
# byte length.
+ #--
+ #: (Source source, Integer start_offset, Integer length) -> void
def initialize(source, start_offset, length)
@source = source
@start_offset = start_offset
@@ -316,53 +427,73 @@ module Prism
# These are the comments that are associated with this location that exist
# before the start of this location.
+ #--
+ #: () -> Array[Comment]
def leading_comments
@leading_comments ||= []
end
# Attach a comment to the leading comments of this location.
+ #--
+ #: (Comment comment) -> void
def leading_comment(comment)
leading_comments << comment
end
# These are the comments that are associated with this location that exist
# after the end of this location.
+ #--
+ #: () -> Array[Comment]
def trailing_comments
@trailing_comments ||= []
end
# Attach a comment to the trailing comments of this location.
+ #--
+ #: (Comment comment) -> void
def trailing_comment(comment)
trailing_comments << comment
end
# Returns all comments that are associated with this location (both leading
# and trailing comments).
+ #--
+ #: () -> Array[Comment]
def comments
- [*@leading_comments, *@trailing_comments]
+ [*@leading_comments, *@trailing_comments] #: Array[Comment]
end
# Create a new location object with the given options.
+ #--
+ #: (?source: Source, ?start_offset: Integer, ?length: Integer) -> Location
def copy(source: self.source, start_offset: self.start_offset, length: self.length)
Location.new(source, start_offset, length)
end
# Returns a new location that is the result of chopping off the last byte.
+ #--
+ #: () -> Location
def chop
copy(length: length == 0 ? length : length - 1)
end
# Returns a string representation of this location.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::Location @start_offset=#{@start_offset} @length=#{@length} start_line=#{start_line}>"
end
# Returns all of the lines of the source code associated with this location.
+ #--
+ #: () -> Array[String]
def source_lines
source.lines
end
# The source code that this location represents.
+ #--
+ #: () -> String
def slice
source.slice(start_offset, length)
end
@@ -370,6 +501,8 @@ module Prism
# The source code that this location represents starting from the beginning
# of the line that this location starts on to the end of the line that this
# location ends on.
+ #--
+ #: () -> String
def slice_lines
line_start = source.line_start(start_offset)
line_end = source.line_end(end_offset)
@@ -378,118 +511,160 @@ module Prism
# The character offset from the beginning of the source where this location
# starts.
+ #--
+ #: () -> Integer
def start_character_offset
source.character_offset(start_offset)
end
# The offset from the start of the file in code units of the given encoding.
+ #--
+ #: (Encoding encoding) -> Integer
def start_code_units_offset(encoding = Encoding::UTF_16LE)
source.code_units_offset(start_offset, encoding)
end
# The start offset from the start of the file in code units using the given
# cache to fetch or calculate the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_offset(cache)
cache[start_offset]
end
# The byte offset from the beginning of the source where this location ends.
+ #--
+ #: () -> Integer
def end_offset
start_offset + length
end
# The character offset from the beginning of the source where this location
# ends.
+ #--
+ #: () -> Integer
def end_character_offset
source.character_offset(end_offset)
end
# The offset from the start of the file in code units of the given encoding.
+ #--
+ #: (Encoding encoding) -> Integer
def end_code_units_offset(encoding = Encoding::UTF_16LE)
source.code_units_offset(end_offset, encoding)
end
# The end offset from the start of the file in code units using the given
# cache to fetch or calculate the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_offset(cache)
cache[end_offset]
end
# The line number where this location starts.
+ #--
+ #: () -> Integer
def start_line
source.line(start_offset)
end
# The content of the line where this location starts before this location.
+ #--
+ #: () -> String
def start_line_slice
offset = source.line_start(start_offset)
source.slice(offset, start_offset - offset)
end
# The line number where this location ends.
+ #--
+ #: () -> Integer
def end_line
source.line(end_offset)
end
- # The column number in bytes where this location starts from the start of
+ # The column in bytes where this location starts from the start of
# the line.
+ #--
+ #: () -> Integer
def start_column
source.column(start_offset)
end
- # The column number in characters where this location ends from the start of
+ # The column in characters where this location ends from the start of
# the line.
+ #--
+ #: () -> Integer
def start_character_column
source.character_column(start_offset)
end
- # The column number in code units of the given encoding where this location
+ # The column in code units of the given encoding where this location
# starts from the start of the line.
+ #--
+ #: (?Encoding encoding) -> Integer
def start_code_units_column(encoding = Encoding::UTF_16LE)
source.code_units_column(start_offset, encoding)
end
# The start column in code units using the given cache to fetch or calculate
# the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_column(cache)
cache[start_offset] - cache[source.line_start(start_offset)]
end
- # The column number in bytes where this location ends from the start of the
+ # The column in bytes where this location ends from the start of the
# line.
+ #--
+ #: () -> Integer
def end_column
source.column(end_offset)
end
- # The column number in characters where this location ends from the start of
+ # The column in characters where this location ends from the start of
# the line.
+ #--
+ #: () -> Integer
def end_character_column
source.character_column(end_offset)
end
- # The column number in code units of the given encoding where this location
+ # The column in code units of the given encoding where this location
# ends from the start of the line.
+ #--
+ #: (?Encoding encoding) -> Integer
def end_code_units_column(encoding = Encoding::UTF_16LE)
source.code_units_column(end_offset, encoding)
end
# The end column in code units using the given cache to fetch or calculate
# the value.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_column(cache)
cache[end_offset] - cache[source.line_start(end_offset)]
end
# Implement the hash pattern matching interface for Location.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ start_offset: start_offset, end_offset: end_offset }
end
# Implement the pretty print interface for Location.
- def pretty_print(q)
+ #--
+ #: (PP q) -> void
+ def pretty_print(q) # :nodoc:
q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})")
end
# Returns true if the given other location is equal to this location.
+ #--
+ #: (untyped other) -> bool
def ==(other)
Location === other &&
other.start_offset == start_offset &&
@@ -499,6 +674,8 @@ module Prism
# 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.
+ #--
+ #: (Location other) -> Location
def join(other)
raise "Incompatible sources" if source != other.source
raise "Incompatible locations" if start_offset > other.start_offset
@@ -509,6 +686,8 @@ module Prism
# Join this location with the first occurrence of the string in the source
# that occurs after this location on the same line, and return the new
# location. This will raise an error if the string does not exist.
+ #--
+ #: (String string) -> Location
def adjoin(string)
line_suffix = source.slice(end_offset, source.line_end(end_offset) - end_offset)
@@ -522,23 +701,38 @@ module Prism
# 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
+ # The Location of this comment in the source.
+ attr_reader :location #: Location
# Create a new comment object with the given location.
+ #--
+ #: (Location location) -> void
def initialize(location)
@location = location
end
# Implement the hash pattern matching interface for Comment.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ location: location }
end
# Returns the content of the comment by slicing it from the source code.
+ #--
+ #: () -> String
def slice
location.slice
end
+
+ # Returns true if this comment happens on the same line as other code and
+ # false if the comment is by itself. This can only be true for inline
+ # comments and should be false for block comments.
+ #--
+ #: () -> bool
+ def trailing?
+ raise NotImplementedError, "trailing? is not implemented for #{self.class}"
+ end
end
# InlineComment objects are the most common. They correspond to comments in
@@ -546,12 +740,16 @@ module Prism
class InlineComment < Comment
# Returns true if this comment happens on the same line as other code and
# false if the comment is by itself.
+ #--
+ #: () -> bool
def trailing?
!location.start_line_slice.strip.empty?
end
# Returns a string representation of this comment.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::InlineComment @location=#{location.inspect}>"
end
end
@@ -559,13 +757,17 @@ module Prism
# EmbDocComment objects correspond to comments that are surrounded by =begin
# and =end.
class EmbDocComment < Comment
- # This can only be true for inline comments.
+ # Returns false. This can only be true for inline comments.
+ #--
+ #: () -> bool
def trailing?
false
end
# Returns a string representation of this comment.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::EmbDocComment @location=#{location.inspect}>"
end
end
@@ -573,34 +775,44 @@ module Prism
# 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
+ attr_reader :key_loc #: Location
# A Location object representing the location of the value in the source.
- attr_reader :value_loc
+ attr_reader :value_loc #: Location
# Create a new magic comment object with the given key and value locations.
+ #--
+ #: (Location key_loc, Location value_loc) -> void
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.
+ #--
+ #: () -> String
def key
key_loc.slice
end
# Returns the value of the magic comment by slicing it from the source code.
+ #--
+ #: () -> String
def value
value_loc.slice
end
# Implement the hash pattern matching interface for MagicComment.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ key_loc: key_loc, value_loc: value_loc }
end
# Returns a string representation of this magic comment.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>"
end
end
@@ -609,18 +821,20 @@ module Prism
class ParseError
# The type of error. This is an _internal_ symbol that is used for
# communicating with translation layers. It is not meant to be public API.
- attr_reader :type
+ attr_reader :type #: Symbol
# The message associated with this error.
- attr_reader :message
+ attr_reader :message #: String
# A Location object representing the location of this error in the source.
- attr_reader :location
+ attr_reader :location #: Location
# The level of this error.
- attr_reader :level
+ attr_reader :level #: Symbol
# Create a new error object with the given message and location.
+ #--
+ #: (Symbol type, String message, Location location, Symbol level) -> void
def initialize(type, message, location, level)
@type = type
@message = message
@@ -629,12 +843,16 @@ module Prism
end
# Implement the hash pattern matching interface for ParseError.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ type: type, message: message, location: location, level: level }
end
# Returns a string representation of this error.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::ParseError @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
end
end
@@ -643,18 +861,20 @@ module Prism
class ParseWarning
# The type of warning. This is an _internal_ symbol that is used for
# communicating with translation layers. It is not meant to be public API.
- attr_reader :type
+ attr_reader :type #: Symbol
# The message associated with this warning.
- attr_reader :message
+ attr_reader :message #: String
# A Location object representing the location of this warning in the source.
- attr_reader :location
+ attr_reader :location #: Location
# The level of this warning.
- attr_reader :level
+ attr_reader :level #: Symbol
# Create a new warning object with the given message and location.
+ #--
+ #: (Symbol type, String message, Location location, Symbol level) -> void
def initialize(type, message, location, level)
@type = type
@message = message
@@ -663,73 +883,116 @@ module Prism
end
# Implement the hash pattern matching interface for ParseWarning.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ type: type, message: message, location: location, level: level }
end
# Returns a string representation of this warning.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
"#<Prism::ParseWarning @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
end
end
- # This represents the result of a call to ::parse or ::parse_file. It contains
- # the requested structure, any comments that were encounters, and any errors
- # that were encountered.
+ # This represents the result of a call to Prism.parse or Prism.parse_file.
+ # It contains the requested structure, any comments that were encounters,
+ # and any errors that were encountered.
class Result
# The list of comments that were encountered during parsing.
- attr_reader :comments
+ attr_reader :comments #: Array[Comment]
# The list of magic comments that were encountered during parsing.
- attr_reader :magic_comments
+ attr_reader :magic_comments #: Array[MagicComment]
# An optional location that represents the location of the __END__ marker
# and the rest of the content of the file. This content is loaded into the
# DATA constant when the file being parsed is the main file being executed.
- attr_reader :data_loc
+ attr_reader :data_loc #: Location?
# The list of errors that were generated during parsing.
- attr_reader :errors
+ attr_reader :errors #: Array[ParseError]
# The list of warnings that were generated during parsing.
- attr_reader :warnings
+ attr_reader :warnings #: Array[ParseWarning]
# A Source instance that represents the source code that was parsed.
- attr_reader :source
+ attr_reader :source #: Source
# Create a new result object with the given values.
- def initialize(comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(comments, magic_comments, data_loc, errors, warnings, continuable, source)
@comments = comments
@magic_comments = magic_comments
@data_loc = data_loc
@errors = errors
@warnings = warnings
+ @continuable = continuable
@source = source
end
# Implement the hash pattern matching interface for Result.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
end
# Returns the encoding of the source code that was parsed.
+ #--
+ #: () -> Encoding
def encoding
source.encoding
end
# Returns true if there were no errors during parsing and false if there
# were.
+ #--
+ #: () -> bool
def success?
errors.empty?
end
# Returns true if there were errors during parsing and false if there were
# not.
+ #--
+ #: () -> bool
def failure?
!success?
end
+ # Returns true if the parsed source is an incomplete expression that could
+ # become valid with additional input. This is useful for REPL contexts (such
+ # as IRB) where the user may be entering a multi-line expression one line at
+ # a time and the implementation needs to determine whether to wait for more
+ # input or to evaluate what has been entered so far.
+ #
+ # Concretely, this returns true when every error present is caused by the
+ # parser reaching the end of the input before a construct was closed (e.g.
+ # an unclosed string, array, block, or keyword), and returns false when any
+ # error is caused by a token that makes the input structurally invalid
+ # regardless of what might follow (e.g. a stray `end`, `]`, or `)` with no
+ # matching opener).
+ #
+ # Examples:
+ #
+ # Prism.parse("1 + [").continuable? #=> true (unclosed array)
+ # Prism.parse("1 + ]").continuable? #=> false (stray ])
+ # Prism.parse("tap do").continuable? #=> true (unclosed block)
+ # Prism.parse("end.tap do").continuable? #=> false (stray end)
+ #
+ #--
+ #: () -> bool
+ def continuable?
+ @continuable
+ end
+
# Create a code units cache for the given encoding.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
source.code_units_cache(encoding)
end
@@ -746,32 +1009,42 @@ module Prism
private_constant :Newlines
# The syntax tree that was parsed from the source code.
- attr_reader :value
+ attr_reader :value #: ProgramNode
# Create a new parse result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (ProgramNode value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for ParseResult.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
# Attach the list of comments to their respective locations in the tree.
+ #--
+ #: () -> void
def attach_comments!
Comments.new(self).attach! # steep:ignore
end
# Walk the tree and mark nodes that are on a new line, loosely emulating
# the behavior of CRuby's `:line` tracepoint event.
+ #--
+ #: () -> void
def mark_newlines!
value.accept(Newlines.new(source.offsets.size)) # steep:ignore
end
# Returns a string representation of the syntax tree with the errors
# displayed inline.
+ #--
+ #: () -> String
def errors_format
Errors.new(self).format
end
@@ -780,16 +1053,20 @@ module Prism
# This is a result specific to the `lex` and `lex_file` methods.
class LexResult < Result
# The list of tokens that were parsed from the source code.
- attr_reader :value
+ attr_reader :value #: Array[[Token, Integer]]
# Create a new lex result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: (Array[[Token, Integer]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for LexResult.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
end
@@ -798,16 +1075,20 @@ module Prism
class ParseLexResult < Result
# A tuple of the syntax tree and the list of tokens that were parsed from
# the source code.
- attr_reader :value
+ attr_reader :value #: [ProgramNode, Array[[Token, Integer]]]
# Create a new parse lex result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
+ #--
+ #: ([ProgramNode, Array[[Token, Integer]]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
@value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
+ super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
end
# Implement the hash pattern matching interface for ParseLexResult.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
super.merge!(value: value)
end
end
@@ -815,16 +1096,20 @@ module Prism
# This represents a token from the Ruby source.
class Token
# The Source object that represents the source this token came from.
- attr_reader :source
+ attr_reader :source #: Source
private :source
# The type of token that this token is.
- attr_reader :type
+ attr_reader :type #: Symbol
# A byteslice of the source that this token represents.
- attr_reader :value
+ attr_reader :value #: String
+
+ # @rbs @location: Location | Integer
# Create a new token object with the given type, value, and location.
+ #--
+ #: (Source source, Symbol type, String value, Location | Integer location) -> void
def initialize(source, type, value, location)
@source = source
@type = type
@@ -833,11 +1118,15 @@ module Prism
end
# Implement the hash pattern matching interface for Token.
- def deconstruct_keys(keys)
+ #--
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ type: type, value: value, location: location }
end
# A Location object representing the location of this token in the source.
+ #--
+ #: () -> Location
def location
location = @location
return location if location.is_a?(Location)
@@ -845,7 +1134,9 @@ module Prism
end
# Implement the pretty print interface for Token.
- def pretty_print(q)
+ #--
+ #: (PP q) -> void
+ def pretty_print(q) # :nodoc:
q.group do
q.text(type.to_s)
self.location.pretty_print(q)
@@ -860,6 +1151,8 @@ module Prism
end
# Returns true if the given other token is equal to this token.
+ #--
+ #: (untyped other) -> bool
def ==(other)
Token === other &&
other.type == type &&
@@ -867,12 +1160,16 @@ module Prism
end
# Returns a string representation of this token.
- def inspect
+ #--
+ #: () -> String
+ def inspect # :nodoc:
location
super
end
# Freeze this object and the objects it contains.
+ #--
+ #: () -> void
def deep_freeze
value.freeze
location.freeze
@@ -887,14 +1184,16 @@ module Prism
class Scope
# The list of local variables that are defined in this scope. This should be
# defined as an array of symbols.
- attr_reader :locals
+ attr_reader :locals #: Array[Symbol]
# The list of local variables that are forwarded to the next scope. This
# should by defined as an array of symbols containing the specific values of
# :*, :**, :&, or :"...".
- attr_reader :forwarding
+ attr_reader :forwarding #: Array[Symbol]
# Create a new scope object with the given locals and forwarding.
+ #--
+ #: (Array[Symbol] locals, Array[Symbol] forwarding) -> void
def initialize(locals, forwarding)
@locals = locals
@forwarding = forwarding
@@ -904,6 +1203,8 @@ module Prism
# Create a new scope with the given locals and forwarding options that is
# suitable for passing into one of the Prism.* methods that accepts the
# `scopes` option.
+ #--
+ #: (?locals: Array[Symbol], ?forwarding: Array[Symbol]) -> Scope
def self.scope(locals: [], forwarding: [])
Scope.new(locals, forwarding)
end
diff --git a/lib/prism/parse_result/comments.rb b/lib/prism/parse_result/comments.rb
index 22c4148b2c..df80792d39 100644
--- a/lib/prism/parse_result/comments.rb
+++ b/lib/prism/parse_result/comments.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
class ParseResult < Result
@@ -17,32 +20,49 @@ module Prism
# the comment. Otherwise it will favor attaching to the nearest location
# that is after the comment.
class Comments
+ # @rbs!
+ # # An internal interface for a target that comments can be attached
+ # # to. This is either going to be a NodeTarget or a CommentTarget.
+ # interface _CommentTarget
+ # def start_offset: () -> Integer
+ # def end_offset: () -> Integer
+ # def encloses?: (Comment) -> bool
+ # def leading_comment: (Comment) -> void
+ # def trailing_comment: (Comment) -> void
+ # end
+
# A target for attaching comments that is based on a specific node's
# location.
class NodeTarget # :nodoc:
- attr_reader :node
+ attr_reader :node #: node
+ #: (node node) -> void
def initialize(node)
@node = node
end
+ #: () -> Integer
def start_offset
node.start_offset
end
+ #: () -> Integer
def end_offset
node.end_offset
end
+ #: (Comment comment) -> bool
def encloses?(comment)
start_offset <= comment.location.start_offset &&
comment.location.end_offset <= end_offset
end
+ #: (Comment comment) -> void
def leading_comment(comment)
node.location.leading_comment(comment)
end
+ #: (Comment comment) -> void
def trailing_comment(comment)
node.location.trailing_comment(comment)
end
@@ -51,44 +71,54 @@ module Prism
# 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
+ attr_reader :location #: Location
+ #: (Location location) -> void
def initialize(location)
@location = location
end
+ #: () -> Integer
def start_offset
location.start_offset
end
+ #: () -> Integer
def end_offset
location.end_offset
end
+ #: (Comment comment) -> bool
def encloses?(comment)
false
end
+ #: (Comment comment) -> void
def leading_comment(comment)
location.leading_comment(comment)
end
+ #: (Comment comment) -> void
def trailing_comment(comment)
location.trailing_comment(comment)
end
end
# The parse result that we are attaching comments to.
- attr_reader :parse_result
+ attr_reader :parse_result #: ParseResult
# Create a new Comments object that will attach comments to the given
# parse result.
+ #--
+ #: (ParseResult parse_result) -> void
def initialize(parse_result)
@parse_result = parse_result
end
# Attach the comments to their respective locations in the tree by
# mutating the parse result.
+ #--
+ #: () -> void
def attach!
parse_result.comments.each do |comment|
preceding, enclosing, following = nearest_targets(parse_result.value, comment)
@@ -116,11 +146,13 @@ module Prism
# Responsible for finding the nearest targets to the given comment within
# the context of the given encapsulating node.
+ #--
+ #: (node node, Comment comment) -> [_CommentTarget?, _CommentTarget?, _CommentTarget?]
def nearest_targets(node, comment)
comment_start = comment.location.start_offset
comment_end = comment.location.end_offset
- targets = [] #: Array[_Target]
+ targets = [] #: Array[_CommentTarget]
node.comment_targets.map do |value|
case value
when StatementsNode
@@ -133,8 +165,8 @@ module Prism
end
targets.sort_by!(&:start_offset)
- preceding = nil #: _Target?
- following = nil #: _Target?
+ preceding = nil #: _CommentTarget?
+ following = nil #: _CommentTarget?
left = 0
right = targets.length
diff --git a/lib/prism/parse_result/errors.rb b/lib/prism/parse_result/errors.rb
index eb4f317248..388309d23d 100644
--- a/lib/prism/parse_result/errors.rb
+++ b/lib/prism/parse_result/errors.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
require "stringio"
@@ -8,14 +11,18 @@ module Prism
# can be used to format the errors in a human-readable way.
class Errors
# The parse result that contains the errors.
- attr_reader :parse_result
+ attr_reader :parse_result #: ParseResult
# Initialize a new set of errors from the given parse result.
+ #--
+ #: (ParseResult parse_result) -> void
def initialize(parse_result)
@parse_result = parse_result
end
# Formats the errors in a human-readable way and return them as a string.
+ #--
+ #: () -> String
def format
error_lines = {} #: Hash[Integer, Array[ParseError]]
parse_result.errors.each do |error|
diff --git a/lib/prism/parse_result/newlines.rb b/lib/prism/parse_result/newlines.rb
index 37f64f8ae2..450c790226 100644
--- a/lib/prism/parse_result/newlines.rb
+++ b/lib/prism/parse_result/newlines.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
class ParseResult < Result
@@ -23,13 +26,20 @@ module Prism
# that case. We do that to avoid storing the extra `@newline` instance
# variable on every node if we don't need it.
class Newlines < Visitor
+ # The map of lines indices to whether or not they have been marked as
+ # emitting a newline event.
+ # @rbs @lines: Array[bool]
+
# Create a new Newlines visitor with the given newline offsets.
+ #--
+ #: (Integer lines) -> void
def initialize(lines)
- # @type var lines: Integer
@lines = Array.new(1 + lines, false)
end
- # Permit block/lambda nodes to mark newlines within themselves.
+ # Permit block nodes to mark newlines within themselves.
+ #--
+ #: (BlockNode node) -> void
def visit_block_node(node)
old_lines = @lines
@lines = Array.new(old_lines.size, false)
@@ -41,17 +51,39 @@ module Prism
end
end
- alias_method :visit_lambda_node, :visit_block_node
+ # Permit lambda nodes to mark newlines within themselves.
+ #--
+ #: (LambdaNode node) -> void
+ def visit_lambda_node(node)
+ old_lines = @lines
+ @lines = Array.new(old_lines.size, false)
+
+ begin
+ super(node)
+ ensure
+ @lines = old_lines
+ end
+ end
- # Mark if/unless nodes as newlines.
+ # Mark if nodes as newlines.
+ #--
+ #: (IfNode node) -> void
def visit_if_node(node)
node.newline_flag!(@lines)
super(node)
end
- alias_method :visit_unless_node, :visit_if_node
+ # Mark unless nodes as newlines.
+ #--
+ #: (UnlessNode node) -> void
+ def visit_unless_node(node)
+ node.newline_flag!(@lines)
+ super(node)
+ end
# Permit statements lists to mark newlines within themselves.
+ #--
+ #: (StatementsNode node) -> void
def visit_statements_node(node)
node.body.each do |child|
child.newline_flag!(@lines)
@@ -62,10 +94,16 @@ module Prism
end
class Node
+ # Tracks whether or not this node should emit a newline event when the
+ # instructions that it represents are executed.
+ # @rbs @newline_flag: bool
+
+ #: () -> bool
def newline_flag? # :nodoc:
!!defined?(@newline_flag)
end
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
line = location.start_line
unless lines[line]
@@ -76,48 +114,56 @@ module Prism
end
class BeginNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
# Never mark BeginNode with a newline flag, mark children instead.
end
end
class ParenthesesNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
# Never mark ParenthesesNode with a newline flag, mark children instead.
end
end
class IfNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class UnlessNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class UntilNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class WhileNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
predicate.newline_flag!(lines)
end
end
class RescueModifierNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
expression.newline_flag!(lines)
end
end
class InterpolatedMatchLastLineNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -125,6 +171,7 @@ module Prism
end
class InterpolatedRegularExpressionNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -132,6 +179,7 @@ module Prism
end
class InterpolatedStringNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -139,6 +187,7 @@ module Prism
end
class InterpolatedSymbolNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
@@ -146,6 +195,7 @@ module Prism
end
class InterpolatedXStringNode < Node
+ #: (Array[bool] lines) -> void
def newline_flag!(lines) # :nodoc:
first = parts.first
first.newline_flag!(lines) if first
diff --git a/lib/prism/pattern.rb b/lib/prism/pattern.rb
index 03fec26789..be0493df05 100644
--- a/lib/prism/pattern.rb
+++ b/lib/prism/pattern.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# A pattern is an object that wraps a Ruby pattern matching expression. The
@@ -40,7 +43,9 @@ module Prism
class CompilationError < StandardError
# Create a new CompilationError with the given representation of the node
# that caused the error.
- def initialize(repr)
+ #--
+ #: (String repr) -> void
+ def initialize(repr) # :nodoc:
super(<<~ERROR)
prism was unable to compile the pattern you provided into a usable
expression. It failed on to understand the node represented by:
@@ -56,10 +61,13 @@ module Prism
end
# The query that this pattern was initialized with.
- attr_reader :query
+ attr_reader :query #: String
+ # @rbs @compiled: Proc?
# Create a new pattern with the given query. The query should be a string
# containing a Ruby pattern matching expression.
+ #--
+ #: (String query) -> void
def initialize(query)
@query = query
@compiled = nil
@@ -67,6 +75,8 @@ module Prism
# Compile the query into a callable object that can be used to match against
# nodes.
+ #--
+ #: () -> Proc
def compile
result = Prism.parse("case nil\nin #{query}\nend")
@@ -83,7 +93,10 @@ module Prism
# 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)
+ #--
+ #: (node root) -> Enumerator[node, void]
+ #: (node root) { (node) -> void } -> void
+ def scan(root, &blk)
return to_enum(:scan, root) unless block_given?
@compiled ||= compile
@@ -99,23 +112,33 @@ module Prism
# Shortcut for combining two procs into one that returns true if both return
# true.
- def combine_and(left, right)
+ #--
+ #: (Proc left, Proc right) -> Proc
+ def combine_and(left, right) # :nodoc:
->(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)
+ #--
+ #: (Proc left, Proc right) -> Proc
+ def combine_or(left, right) # :nodoc:
->(other) { left.call(other) || right.call(other) }
end
- # Raise an error because the given node is not supported.
- def compile_error(node)
+ # Raise an error because the given node is not supported. Note purposefully
+ # not typing this method since it is a no return method that Steep does not
+ # understand.
+ #--
+ #: (node node) -> bot
+ def compile_error(node) # :nodoc:
raise CompilationError, node.inspect
end
# in [foo, bar, baz]
- def compile_array_pattern_node(node)
+ #--
+ #: (ArrayPatternNode node) -> Proc
+ def compile_array_pattern_node(node) # :nodoc:
compile_error(node) if !node.rest.nil? || node.posts.any?
constant = node.constant
@@ -140,12 +163,16 @@ module Prism
end
# in foo | bar
- def compile_alternation_pattern_node(node)
+ #--
+ #: (AlternationPatternNode node) -> Proc
+ def compile_alternation_pattern_node(node) # :nodoc:
combine_or(compile_node(node.left), compile_node(node.right))
end
# in Prism::ConstantReadNode
- def compile_constant_path_node(node)
+ #--
+ #: (ConstantPathNode node) -> Proc
+ def compile_constant_path_node(node) # :nodoc:
parent = node.parent
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
@@ -160,12 +187,16 @@ module Prism
# in ConstantReadNode
# in String
- def compile_constant_read_node(node)
+ #--
+ #: (ConstantReadNode node) -> Proc
+ def compile_constant_read_node(node) # :nodoc:
compile_constant_name(node, node.name)
end
# Compile a name associated with a constant.
- def compile_constant_name(node, name)
+ #--
+ #: ((ConstantPathNode | ConstantReadNode) node, Symbol name) -> Proc
+ def compile_constant_name(node, name) # :nodoc:
if Prism.const_defined?(name, false)
clazz = Prism.const_get(name)
@@ -181,9 +212,14 @@ module Prism
# in InstanceVariableReadNode[name: Symbol]
# in { name: Symbol }
- def compile_hash_pattern_node(node)
+ #--
+ #: (HashPatternNode node) -> Proc
+ def compile_hash_pattern_node(node) # :nodoc:
compile_error(node) if node.rest
- compiled_constant = compile_node(node.constant) if node.constant
+
+ if (constant = node.constant)
+ compiled_constant = compile_node(constant)
+ end
preprocessed =
node.elements.to_h do |element|
@@ -211,12 +247,16 @@ module Prism
end
# in nil
- def compile_nil_node(node)
+ #--
+ #: (NilNode node) -> Proc
+ def compile_nil_node(node) # :nodoc:
->(attribute) { attribute.nil? }
end
# in /foo/
- def compile_regular_expression_node(node)
+ #--
+ #: (RegularExpressionNode node) -> Proc
+ def compile_regular_expression_node(node) # :nodoc:
regexp = Regexp.new(node.unescaped, node.closing[1..])
->(attribute) { regexp === attribute }
@@ -224,7 +264,9 @@ module Prism
# in ""
# in "foo"
- def compile_string_node(node)
+ #--
+ #: (StringNode node) -> Proc
+ def compile_string_node(node) # :nodoc:
string = node.unescaped
->(attribute) { string === attribute }
@@ -232,7 +274,9 @@ module Prism
# in :+
# in :foo
- def compile_symbol_node(node)
+ #--
+ #: (SymbolNode node) -> Proc
+ def compile_symbol_node(node) # :nodoc:
symbol = node.unescaped.to_sym
->(attribute) { symbol === attribute }
@@ -240,7 +284,9 @@ module Prism
# Compile any kind of node. Dispatch out to the individual compilation
# methods based on the type of node.
- def compile_node(node)
+ #--
+ #: (node node) -> Proc
+ def compile_node(node) # :nodoc:
case node
when AlternationPatternNode
compile_alternation_pattern_node(node)
diff --git a/lib/prism/polyfill/scan_byte.rb b/lib/prism/polyfill/scan_byte.rb
new file mode 100644
index 0000000000..9276e509fc
--- /dev/null
+++ b/lib/prism/polyfill/scan_byte.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require "strscan"
+
+# Polyfill for StringScanner#scan_byte, which didn't exist until Ruby 3.4.
+if !(StringScanner.method_defined?(:scan_byte))
+ StringScanner.include(
+ Module.new {
+ def scan_byte # :nodoc:
+ get_byte&.b&.ord
+ end
+ }
+ )
+end
diff --git a/lib/prism/polyfill/warn.rb b/lib/prism/polyfill/warn.rb
index 560380d308..76a4264623 100644
--- a/lib/prism/polyfill/warn.rb
+++ b/lib/prism/polyfill/warn.rb
@@ -7,17 +7,14 @@ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.pa
Kernel.prepend(
Module.new {
def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
- uplevel =
- case uplevel
- when nil
- 1
- when Integer
- uplevel + 1
- else
- uplevel.to_int + 1
- end
-
- super(*msgs, uplevel: uplevel)
+ case uplevel
+ when nil
+ super(*msgs)
+ when Integer
+ super(*msgs, uplevel: uplevel + 1)
+ else
+ super(*msgs, uplevel: uplevel.to_int + 1)
+ end
end
}
)
@@ -25,17 +22,14 @@ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.pa
Object.prepend(
Module.new {
def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
- uplevel =
- case uplevel
- when nil
- 1
- when Integer
- uplevel + 1
- else
- uplevel.to_int + 1
- end
-
- super(*msgs, uplevel: uplevel)
+ case uplevel
+ when nil
+ super(*msgs)
+ when Integer
+ super(*msgs, uplevel: uplevel + 1)
+ else
+ super(*msgs, uplevel: uplevel.to_int + 1)
+ end
end
}
)
diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec
index 5cb5a98057..aac056b3f8 100644
--- a/lib/prism/prism.gemspec
+++ b/lib/prism/prism.gemspec
@@ -2,7 +2,7 @@
Gem::Specification.new do |spec|
spec.name = "prism"
- spec.version = "1.4.0"
+ spec.version = "1.9.0"
spec.authors = ["Shopify"]
spec.email = ["ruby@shopify.com"]
@@ -42,31 +42,69 @@ Gem::Specification.new do |spec|
"docs/serialization.md",
"docs/testing.md",
"ext/prism/api_node.c",
- "ext/prism/api_pack.c",
+ "ext/prism/extconf.rb",
"ext/prism/extension.c",
"ext/prism/extension.h",
"include/prism.h",
+ "include/prism/compiler/accel.h",
+ "include/prism/compiler/align.h",
+ "include/prism/compiler/exported.h",
+ "include/prism/compiler/fallthrough.h",
+ "include/prism/compiler/filesystem.h",
+ "include/prism/compiler/flex_array.h",
+ "include/prism/compiler/force_inline.h",
+ "include/prism/compiler/format.h",
+ "include/prism/compiler/inline.h",
+ "include/prism/compiler/nodiscard.h",
+ "include/prism/compiler/nonnull.h",
+ "include/prism/compiler/unused.h",
+ "include/prism/internal/allocator.h",
+ "include/prism/internal/allocator_debug.h",
+ "include/prism/internal/arena.h",
+ "include/prism/internal/bit.h",
+ "include/prism/internal/buffer.h",
+ "include/prism/internal/char.h",
+ "include/prism/internal/comments.h",
+ "include/prism/internal/constant_pool.h",
+ "include/prism/internal/diagnostic.h",
+ "include/prism/internal/encoding.h",
+ "include/prism/internal/integer.h",
+ "include/prism/internal/isinf.h",
+ "include/prism/internal/line_offset_list.h",
+ "include/prism/internal/list.h",
+ "include/prism/internal/magic_comments.h",
+ "include/prism/internal/memchr.h",
+ "include/prism/internal/node.h",
+ "include/prism/internal/options.h",
+ "include/prism/internal/parser.h",
+ "include/prism/internal/regexp.h",
+ "include/prism/internal/serialize.h",
+ "include/prism/internal/source.h",
+ "include/prism/internal/static_literals.h",
+ "include/prism/internal/strncasecmp.h",
+ "include/prism/internal/stringy.h",
+ "include/prism/internal/strpbrk.h",
+ "include/prism/internal/tokens.h",
+ "include/prism/arena.h",
"include/prism/ast.h",
- "include/prism/defines.h",
+ "include/prism/buffer.h",
+ "include/prism/comments.h",
+ "include/prism/constant_pool.h",
"include/prism/diagnostic.h",
- "include/prism/encoding.h",
+ "include/prism/excludes.h",
+ "include/prism/integer.h",
+ "include/prism/json.h",
+ "include/prism/line_offset_list.h",
+ "include/prism/magic_comments.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/static_literals.h",
- "include/prism/util/pm_buffer.h",
- "include/prism/util/pm_char.h",
- "include/prism/util/pm_constant_pool.h",
- "include/prism/util/pm_integer.h",
- "include/prism/util/pm_list.h",
- "include/prism/util/pm_memchr.h",
- "include/prism/util/pm_newline_list.h",
- "include/prism/util/pm_strncasecmp.h",
- "include/prism/util/pm_string.h",
- "include/prism/util/pm_strpbrk.h",
+ "include/prism/serialize.h",
+ "include/prism/source.h",
+ "include/prism/stream.h",
+ "include/prism/string_query.h",
+ "include/prism/stringy.h",
"include/prism/version.h",
"lib/prism.rb",
"lib/prism/compiler.rb",
@@ -79,8 +117,8 @@ Gem::Specification.new do |spec|
"lib/prism/lex_compat.rb",
"lib/prism/mutation_compiler.rb",
"lib/prism/node_ext.rb",
+ "lib/prism/node_find.rb",
"lib/prism/node.rb",
- "lib/prism/pack.rb",
"lib/prism/parse_result.rb",
"lib/prism/parse_result/comments.rb",
"lib/prism/parse_result/errors.rb",
@@ -88,6 +126,7 @@ Gem::Specification.new do |spec|
"lib/prism/pattern.rb",
"lib/prism/polyfill/append_as_bytes.rb",
"lib/prism/polyfill/byteindex.rb",
+ "lib/prism/polyfill/scan_byte.rb",
"lib/prism/polyfill/unpack1.rb",
"lib/prism/polyfill/warn.rb",
"lib/prism/reflection.rb",
@@ -97,73 +136,93 @@ Gem::Specification.new do |spec|
"lib/prism/translation.rb",
"lib/prism/translation/parser.rb",
"lib/prism/translation/parser_current.rb",
- "lib/prism/translation/parser33.rb",
- "lib/prism/translation/parser34.rb",
- "lib/prism/translation/parser35.rb",
+ "lib/prism/translation/parser_versions.rb",
"lib/prism/translation/parser/builder.rb",
"lib/prism/translation/parser/compiler.rb",
"lib/prism/translation/parser/lexer.rb",
"lib/prism/translation/ripper.rb",
+ "lib/prism/translation/ripper/filter.rb",
+ "lib/prism/translation/ripper/lexer.rb",
"lib/prism/translation/ripper/sexp.rb",
"lib/prism/translation/ripper/shim.rb",
"lib/prism/translation/ruby_parser.rb",
"lib/prism/visitor.rb",
"prism.gemspec",
- "rbi/prism.rbi",
- "rbi/prism/compiler.rbi",
- "rbi/prism/dsl.rbi",
- "rbi/prism/inspect_visitor.rbi",
- "rbi/prism/node_ext.rbi",
- "rbi/prism/node.rbi",
- "rbi/prism/parse_result.rbi",
- "rbi/prism/reflection.rbi",
- "rbi/prism/string_query.rbi",
+ "rbi/generated/prism.rbi",
+ "rbi/generated/prism/compiler.rbi",
+ "rbi/generated/prism/desugar_compiler.rbi",
+ "rbi/generated/prism/dispatcher.rbi",
+ "rbi/generated/prism/dot_visitor.rbi",
+ "rbi/generated/prism/dsl.rbi",
+ "rbi/generated/prism/inspect_visitor.rbi",
+ "rbi/generated/prism/lex_compat.rbi",
+ "rbi/generated/prism/mutation_compiler.rbi",
+ "rbi/generated/prism/node.rbi",
+ "rbi/generated/prism/node_ext.rbi",
+ "rbi/generated/prism/node_find.rbi",
+ "rbi/generated/prism/parse_result.rbi",
+ "rbi/generated/prism/pattern.rbi",
+ "rbi/generated/prism/reflection.rbi",
+ "rbi/generated/prism/relocation.rbi",
+ "rbi/generated/prism/serialize.rbi",
+ "rbi/generated/prism/string_query.rbi",
+ "rbi/generated/prism/translation.rbi",
+ "rbi/generated/prism/visitor.rbi",
+ "rbi/generated/prism/parse_result/comments.rbi",
+ "rbi/generated/prism/parse_result/errors.rbi",
+ "rbi/generated/prism/parse_result/newlines.rbi",
"rbi/prism/translation/parser.rbi",
- "rbi/prism/translation/parser33.rbi",
- "rbi/prism/translation/parser34.rbi",
- "rbi/prism/translation/parser35.rbi",
+ "rbi/prism/translation/parser_versions.rbi",
"rbi/prism/translation/ripper.rbi",
- "rbi/prism/visitor.rbi",
- "sig/prism.rbs",
- "sig/prism/compiler.rbs",
- "sig/prism/dispatcher.rbs",
- "sig/prism/dot_visitor.rbs",
- "sig/prism/dsl.rbs",
- "sig/prism/inspect_visitor.rbs",
- "sig/prism/lex_compat.rbs",
- "sig/prism/mutation_compiler.rbs",
- "sig/prism/node_ext.rbs",
- "sig/prism/node.rbs",
- "sig/prism/pack.rbs",
- "sig/prism/parse_result.rbs",
- "sig/prism/parse_result/comments.rbs",
- "sig/prism/pattern.rbs",
- "sig/prism/reflection.rbs",
- "sig/prism/relocation.rbs",
- "sig/prism/serialize.rbs",
- "sig/prism/string_query.rbs",
- "sig/prism/visitor.rbs",
+ "rbi/rubyvm/node_find.rbi",
+ "sig/generated/prism.rbs",
+ "sig/generated/prism/compiler.rbs",
+ "sig/generated/prism/desugar_compiler.rbs",
+ "sig/generated/prism/dispatcher.rbs",
+ "sig/generated/prism/dot_visitor.rbs",
+ "sig/generated/prism/dsl.rbs",
+ "sig/generated/prism/inspect_visitor.rbs",
+ "sig/generated/prism/lex_compat.rbs",
+ "sig/generated/prism/mutation_compiler.rbs",
+ "sig/generated/prism/node.rbs",
+ "sig/generated/prism/node_ext.rbs",
+ "sig/generated/prism/node_find.rbs",
+ "sig/generated/prism/parse_result.rbs",
+ "sig/generated/prism/pattern.rbs",
+ "sig/generated/prism/reflection.rbs",
+ "sig/generated/prism/relocation.rbs",
+ "sig/generated/prism/serialize.rbs",
+ "sig/generated/prism/string_query.rbs",
+ "sig/generated/prism/translation.rbs",
+ "sig/generated/prism/visitor.rbs",
+ "sig/generated/prism/parse_result/comments.rbs",
+ "sig/generated/prism/parse_result/errors.rbs",
+ "sig/generated/prism/parse_result/newlines.rbs",
+ "src/arena.c",
+ "src/buffer.c",
+ "src/char.c",
+ "src/constant_pool.c",
"src/diagnostic.c",
"src/encoding.c",
+ "src/integer.c",
+ "src/json.c",
+ "src/line_offset_list.c",
+ "src/list.c",
+ "src/memchr.c",
"src/node.c",
"src/options.c",
- "src/pack.c",
+ "src/parser.c",
"src/prettyprint.c",
"src/prism.c",
"src/regexp.c",
"src/serialize.c",
+ "src/source.c",
"src/static_literals.c",
- "src/token_type.c",
- "src/util/pm_buffer.c",
- "src/util/pm_char.c",
- "src/util/pm_constant_pool.c",
- "src/util/pm_integer.c",
- "src/util/pm_list.c",
- "src/util/pm_memchr.c",
- "src/util/pm_newline_list.c",
- "src/util/pm_string.c",
- "src/util/pm_strncasecmp.c",
- "src/util/pm_strpbrk.c"
+ "src/string_query.c",
+ "src/stringy.c",
+ "src/strncasecmp.c",
+ "src/strpbrk.c",
+ "src/tokens.c"
]
spec.extensions = ["ext/prism/extconf.rb"]
diff --git a/lib/prism/relocation.rb b/lib/prism/relocation.rb
index 163d2012c5..af0f792827 100644
--- a/lib/prism/relocation.rb
+++ b/lib/prism/relocation.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# Prism parses deterministically for the same input. This provides a nice
@@ -11,6 +14,33 @@ module Prism
# "save" nodes and locations using a minimal amount of memory (just the
# node_id and a field identifier) and then reify them later.
module Relocation
+ # @rbs!
+ # type entry_value = untyped
+ # type entry_values = Hash[Symbol, entry_value]
+ #
+ # interface _Value
+ # def start_line: () -> Integer
+ # def end_line: () -> Integer
+ # def start_offset: () -> Integer
+ # def end_offset: () -> Integer
+ # def start_character_offset: () -> Integer
+ # def end_character_offset: () -> Integer
+ # def cached_start_code_units_offset: (_CodeUnitsCache cache) -> Integer
+ # def cached_end_code_units_offset: (_CodeUnitsCache cache) -> Integer
+ # def start_column: () -> Integer
+ # def end_column: () -> Integer
+ # def start_character_column: () -> Integer
+ # def end_character_column: () -> Integer
+ # def cached_start_code_units_column: (_CodeUnitsCache cache) -> Integer
+ # def cached_end_code_units_column: (_CodeUnitsCache cache) -> Integer
+ # def leading_comments: () -> Array[Comment]
+ # def trailing_comments: () -> Array[Comment]
+ # end
+ #
+ # interface _Field
+ # def fields: (_Value value) -> entry_values
+ # end
+
# An entry in a repository that will lazily reify its values when they are
# first accessed.
class Entry
@@ -20,109 +50,152 @@ module Prism
class MissingValueError < StandardError
end
+ # @rbs @repository: Repository?
+ # @rbs @values: Hash[Symbol, untyped]?
+
# Initialize a new entry with the given repository.
+ #--
+ #: (Repository repository) -> void
def initialize(repository)
@repository = repository
@values = nil
end
# Fetch the filepath of the value.
+ #--
+ #: () -> String
def filepath
fetch_value(:filepath)
end
# Fetch the start line of the value.
+ #--
+ #: () -> Integer
def start_line
fetch_value(:start_line)
end
# Fetch the end line of the value.
+ #--
+ #: () -> Integer
def end_line
fetch_value(:end_line)
end
# Fetch the start byte offset of the value.
+ #--
+ #: () -> Integer
def start_offset
fetch_value(:start_offset)
end
# Fetch the end byte offset of the value.
+ #--
+ #: () -> Integer
def end_offset
fetch_value(:end_offset)
end
# Fetch the start character offset of the value.
+ #--
+ #: () -> Integer
def start_character_offset
fetch_value(:start_character_offset)
end
# Fetch the end character offset of the value.
+ #--
+ #: () -> Integer
def end_character_offset
fetch_value(:end_character_offset)
end
# Fetch the start code units offset of the value, for the encoding that
# was configured on the repository.
+ #--
+ #: () -> Integer
def start_code_units_offset
fetch_value(:start_code_units_offset)
end
# Fetch the end code units offset of the value, for the encoding that was
# configured on the repository.
+ #--
+ #: () -> Integer
def end_code_units_offset
fetch_value(:end_code_units_offset)
end
# Fetch the start byte column of the value.
+ #--
+ #: () -> Integer
def start_column
fetch_value(:start_column)
end
# Fetch the end byte column of the value.
+ #--
+ #: () -> Integer
def end_column
fetch_value(:end_column)
end
# Fetch the start character column of the value.
+ #--
+ #: () -> Integer
def start_character_column
fetch_value(:start_character_column)
end
# Fetch the end character column of the value.
+ #--
+ #: () -> Integer
def end_character_column
fetch_value(:end_character_column)
end
# Fetch the start code units column of the value, for the encoding that
# was configured on the repository.
+ #--
+ #: () -> Integer
def start_code_units_column
fetch_value(:start_code_units_column)
end
# Fetch the end code units column of the value, for the encoding that was
# configured on the repository.
+ #--
+ #: () -> Integer
def end_code_units_column
fetch_value(:end_code_units_column)
end
# Fetch the leading comments of the value.
+ #--
+ #: () -> Array[CommentsField::Comment]
def leading_comments
fetch_value(:leading_comments)
end
# Fetch the trailing comments of the value.
+ #--
+ #: () -> Array[CommentsField::Comment]
def trailing_comments
fetch_value(:trailing_comments)
end
# Fetch the leading and trailing comments of the value.
+ #--
+ #: () -> Array[CommentsField::Comment]
def comments
- leading_comments.concat(trailing_comments)
+ [*leading_comments, *trailing_comments]
end
# Reify the values on this entry with the given values. This is an
# internal-only API that is called from the repository when it is time to
# reify the values.
+ #--
+ #: (entry_values values) -> void
def reify!(values) # :nodoc:
@repository = nil
@values = values
@@ -131,6 +204,8 @@ module Prism
private
# Fetch a value from the entry, raising an error if it is missing.
+ #--
+ #: (Symbol name) -> entry_value
def fetch_value(name)
values.fetch(name) do
raise MissingValueError, "No value for #{name}, make sure the " \
@@ -139,27 +214,35 @@ module Prism
end
# Return the values from the repository, reifying them if necessary.
+ #--
+ #: () -> entry_values
def values
- @values || (@repository.reify!; @values)
+ @values || (@repository&.reify!; @values) #: entry_values
end
end
# Represents the source of a repository that will be reparsed.
class Source
# The value that will need to be reparsed.
- attr_reader :value
+ attr_reader :value #: untyped
# Initialize the source with the given value.
+ #--
+ #: (untyped value) -> void
def initialize(value)
@value = value
end
# Reparse the value and return the parse result.
+ #--
+ #: () -> ParseResult
def result
raise NotImplementedError, "Subclasses must implement #result"
end
# Create a code units cache for the given encoding.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
result.code_units_cache(encoding)
end
@@ -168,6 +251,8 @@ module Prism
# A source that is represented by a file path.
class SourceFilepath < Source
# Reparse the file and return the parse result.
+ #--
+ #: () -> ParseResult
def result
Prism.parse_file(value)
end
@@ -176,6 +261,8 @@ module Prism
# A source that is represented by a string.
class SourceString < Source
# Reparse the string and return the parse result.
+ #--
+ #: () -> ParseResult
def result
Prism.parse(value)
end
@@ -184,14 +271,18 @@ module Prism
# A field that represents the file path.
class FilepathField
# The file path that this field represents.
- attr_reader :value
+ attr_reader :value #: String
# Initialize a new field with the given file path.
+ #--
+ #: (String value) -> void
def initialize(value)
@value = value
end
# Fetch the file path.
+ #--
+ #: (_Value _value) -> entry_values
def fields(_value)
{ filepath: value }
end
@@ -200,6 +291,8 @@ module Prism
# A field representing the start and end lines.
class LinesField
# Fetches the start and end line of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ start_line: value.start_line, end_line: value.end_line }
end
@@ -208,6 +301,8 @@ module Prism
# A field representing the start and end byte offsets.
class OffsetsField
# Fetches the start and end byte offset of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ start_offset: value.start_offset, end_offset: value.end_offset }
end
@@ -216,6 +311,8 @@ module Prism
# A field representing the start and end character offsets.
class CharacterOffsetsField
# Fetches the start and end character offset of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_character_offset: value.start_character_offset,
@@ -228,12 +325,16 @@ module Prism
class CodeUnitOffsetsField
# A pointer to the repository object that is used for lazily creating a
# code units cache.
- attr_reader :repository
+ attr_reader :repository #: Repository
# The associated encoding for the code units.
- attr_reader :encoding
+ attr_reader :encoding #: Encoding
+
+ # @rbs @cache: _CodeUnitsCache?
# Initialize a new field with the associated repository and encoding.
+ #--
+ #: (Repository repository, Encoding encoding) -> void
def initialize(repository, encoding)
@repository = repository
@encoding = encoding
@@ -242,6 +343,8 @@ module Prism
# Fetches the start and end code units offset of a value for a particular
# encoding.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_code_units_offset: value.cached_start_code_units_offset(cache),
@@ -252,6 +355,8 @@ module Prism
private
# Lazily create a code units cache for the associated encoding.
+ #--
+ #: () -> _CodeUnitsCache
def cache
@cache ||= repository.code_units_cache(encoding)
end
@@ -260,6 +365,8 @@ module Prism
# A field representing the start and end byte columns.
class ColumnsField
# Fetches the start and end byte column of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ start_column: value.start_column, end_column: value.end_column }
end
@@ -268,6 +375,8 @@ module Prism
# A field representing the start and end character columns.
class CharacterColumnsField
# Fetches the start and end character column of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_character_column: value.start_character_column,
@@ -281,12 +390,16 @@ module Prism
class CodeUnitColumnsField
# The repository object that is used for lazily creating a code units
# cache.
- attr_reader :repository
+ attr_reader :repository #: Repository
# The associated encoding for the code units.
- attr_reader :encoding
+ attr_reader :encoding #: Encoding
+
+ # @rbs @cache: _CodeUnitsCache?
# Initialize a new field with the associated repository and encoding.
+ #--
+ #: (Repository repository, Encoding encoding) -> void
def initialize(repository, encoding)
@repository = repository
@encoding = encoding
@@ -295,6 +408,8 @@ module Prism
# Fetches the start and end code units column of a value for a particular
# encoding.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{
start_code_units_column: value.cached_start_code_units_column(cache),
@@ -305,6 +420,8 @@ module Prism
private
# Lazily create a code units cache for the associated encoding.
+ #--
+ #: () -> _CodeUnitsCache
def cache
@cache ||= repository.code_units_cache(encoding)
end
@@ -315,9 +432,11 @@ module Prism
# An object that represents a slice of a comment.
class Comment
# The slice of the comment.
- attr_reader :slice
+ attr_reader :slice #: String
# Initialize a new comment with the given slice.
+ #
+ #: (String slice) -> void
def initialize(slice)
@slice = slice
end
@@ -326,6 +445,8 @@ module Prism
private
# Create comment objects from the given values.
+ #--
+ #: (entry_value values) -> Array[Comment]
def comments(values)
values.map { |value| Comment.new(value.slice) }
end
@@ -334,6 +455,8 @@ module Prism
# A field representing the leading comments.
class LeadingCommentsField < CommentsField
# Fetches the leading comments of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ leading_comments: comments(value.leading_comments) }
end
@@ -342,6 +465,8 @@ module Prism
# A field representing the trailing comments.
class TrailingCommentsField < CommentsField
# Fetches the trailing comments of a value.
+ #--
+ #: (_Value value) -> entry_values
def fields(value)
{ trailing_comments: comments(value.trailing_comments) }
end
@@ -357,15 +482,17 @@ module Prism
# The source associated with this repository. This will be either a
# SourceFilepath (the most common use case) or a SourceString.
- attr_reader :source
+ attr_reader :source #: Source
# The fields that have been configured on this repository.
- attr_reader :fields
+ attr_reader :fields #: Hash[Symbol, _Field]
# The entries that have been saved on this repository.
- attr_reader :entries
+ attr_reader :entries #: Hash[Integer, Hash[Symbol, Entry]]
# Initialize a new repository with the given source.
+ #--
+ #: (Source source) -> void
def initialize(source)
@source = source
@fields = {}
@@ -373,69 +500,93 @@ module Prism
end
# Create a code units cache for the given encoding from the source.
+ #--
+ #: (Encoding encoding) -> _CodeUnitsCache
def code_units_cache(encoding)
source.code_units_cache(encoding)
end
# Configure the filepath field for this repository and return self.
+ #--
+ #: () -> self
def filepath
raise ConfigurationError, "Can only specify filepath for a filepath source" unless source.is_a?(SourceFilepath)
field(:filepath, FilepathField.new(source.value))
end
# Configure the lines field for this repository and return self.
+ #--
+ #: () -> self
def lines
field(:lines, LinesField.new)
end
# Configure the offsets field for this repository and return self.
+ #--
+ #: () -> self
def offsets
field(:offsets, OffsetsField.new)
end
# Configure the character offsets field for this repository and return
# self.
+ #--
+ #: () -> self
def character_offsets
field(:character_offsets, CharacterOffsetsField.new)
end
# Configure the code unit offsets field for this repository for a specific
# encoding and return self.
+ #--
+ #: (Encoding encoding) -> self
def code_unit_offsets(encoding)
field(:code_unit_offsets, CodeUnitOffsetsField.new(self, encoding))
end
# Configure the columns field for this repository and return self.
+ #--
+ #: () -> self
def columns
field(:columns, ColumnsField.new)
end
# Configure the character columns field for this repository and return
# self.
+ #--
+ #: () -> self
def character_columns
field(:character_columns, CharacterColumnsField.new)
end
# Configure the code unit columns field for this repository for a specific
# encoding and return self.
+ #--
+ #: (Encoding encoding) -> self
def code_unit_columns(encoding)
field(:code_unit_columns, CodeUnitColumnsField.new(self, encoding))
end
# Configure the leading comments field for this repository and return
# self.
+ #--
+ #: () -> self
def leading_comments
field(:leading_comments, LeadingCommentsField.new)
end
# Configure the trailing comments field for this repository and return
# self.
+ #--
+ #: () -> self
def trailing_comments
field(:trailing_comments, TrailingCommentsField.new)
end
# Configure both the leading and trailing comment fields for this
# repository and return self.
+ #--
+ #: () -> self
def comments
leading_comments.trailing_comments
end
@@ -443,6 +594,8 @@ module Prism
# This method is called from nodes and locations when they want to enter
# themselves into the repository. It it internal-only and meant to be
# called from the #save* APIs.
+ #--
+ #: (Integer node_id, Symbol field_name) -> Entry
def enter(node_id, field_name) # :nodoc:
entry = Entry.new(self)
@entries[node_id][field_name] = entry
@@ -452,6 +605,8 @@ module Prism
# This method is called from the entries in the repository when they need
# to reify their values. It is internal-only and meant to be called from
# the various value APIs.
+ #--
+ #: () -> void
def reify! # :nodoc:
result = source.result
@@ -465,7 +620,7 @@ module Prism
while (node = queue.shift)
@entries[node.node_id].each do |field_name, entry|
value = node.public_send(field_name)
- values = {} #: Hash[Symbol, untyped]
+ values = {} #: entry_values
fields.each_value do |field|
values.merge!(field.fields(value))
@@ -484,6 +639,8 @@ module Prism
# Append the given field to the repository and return the repository so
# that these calls can be chained.
+ #--
+ #: (Symbol name, _Field) -> self
def field(name, value)
raise ConfigurationError, "Cannot specify multiple #{name} fields" if @fields.key?(name)
@fields[name] = value
@@ -492,11 +649,15 @@ module Prism
end
# Create a new repository for the given filepath.
+ #--
+ #: (String value) -> Repository
def self.filepath(value)
Repository.new(SourceFilepath.new(value))
end
# Create a new repository for the given string.
+ #--
+ #: (String value) -> Repository
def self.string(value)
Repository.new(SourceString.new(value))
end
diff --git a/lib/prism/string_query.rb b/lib/prism/string_query.rb
index 9011051d2b..99ce57e5fe 100644
--- a/lib/prism/string_query.rb
+++ b/lib/prism/string_query.rb
@@ -1,28 +1,44 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# Query methods that allow categorizing strings based on their context for
# where they could be valid in a Ruby syntax tree.
class StringQuery
+ # @rbs!
+ # def self.local?: (String string) -> bool
+ # def self.constant?: (String string) -> bool
+ # def self.method_name?: (String string) -> bool
+
# The string that this query is wrapping.
- attr_reader :string
+ attr_reader :string #: String
# Initialize a new query with the given string.
+ #--
+ #: (String string) -> void
def initialize(string)
@string = string
end
# Whether or not this string is a valid local variable name.
+ #--
+ #: () -> bool
def local?
StringQuery.local?(string)
end
# Whether or not this string is a valid constant name.
+ #--
+ #: () -> bool
def constant?
StringQuery.constant?(string)
end
# Whether or not this string is a valid method name.
+ #--
+ #: () -> bool
def method_name?
StringQuery.method_name?(string)
end
diff --git a/lib/prism/translation.rb b/lib/prism/translation.rb
index 511c80febc..5a086a7542 100644
--- a/lib/prism/translation.rb
+++ b/lib/prism/translation.rb
@@ -1,4 +1,7 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
module Prism
# This module is responsible for converting the prism syntax tree into other
@@ -6,9 +9,11 @@ module Prism
module Translation # steep:ignore
autoload :Parser, "prism/translation/parser"
autoload :ParserCurrent, "prism/translation/parser_current"
- autoload :Parser33, "prism/translation/parser33"
- autoload :Parser34, "prism/translation/parser34"
- autoload :Parser35, "prism/translation/parser35"
+ autoload :Parser33, "prism/translation/parser_versions"
+ autoload :Parser34, "prism/translation/parser_versions"
+ autoload :Parser35, "prism/translation/parser_versions"
+ autoload :Parser40, "prism/translation/parser_versions"
+ autoload :Parser41, "prism/translation/parser_versions"
autoload :Ripper, "prism/translation/ripper"
autoload :RubyParser, "prism/translation/ruby_parser"
end
diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb
index d43ad7c1e4..70031f133a 100644
--- a/lib/prism/translation/parser.rb
+++ b/lib/prism/translation/parser.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# :markup: markdown
begin
required_version = ">= 3.3.7.2"
@@ -18,6 +19,13 @@ module Prism
# whitequark/parser gem's syntax tree. It inherits from the base parser for
# the parser gem, and overrides the parse* methods to parse with prism and
# then translate.
+ #
+ # Note that this version of the parser always parses using the latest
+ # version of Ruby syntax supported by Prism. If you want specific version
+ # support, use one of the version-specific subclasses, such as
+ # `Prism::Translation::Parser34`. If you want to parse using the same
+ # version of Ruby syntax as the currently running version of Ruby, use
+ # `Prism::Translation::ParserCurrent`.
class Parser < ::Parser::Base
Diagnostic = ::Parser::Diagnostic # :nodoc:
private_constant :Diagnostic
@@ -25,7 +33,7 @@ module Prism
# The parser gem has a list of diagnostics with a hard-coded set of error
# messages. We create our own diagnostic class in order to set our own
# error messages.
- class PrismDiagnostic < Diagnostic
+ class PrismDiagnostic < Diagnostic # :nodoc:
# This is the cached message coming from prism.
attr_reader :message
@@ -76,7 +84,7 @@ module Prism
end
def version # :nodoc:
- 34
+ 41
end
# The default encoding for Ruby files is UTF-8.
@@ -348,8 +356,10 @@ module Prism
"3.3.1"
when 34
"3.4.0"
- when 35
- "3.5.0"
+ when 35, 40
+ "4.0.0"
+ when 41
+ "4.1.0"
else
"latest"
end
diff --git a/lib/prism/translation/parser/builder.rb b/lib/prism/translation/parser/builder.rb
index d3b51f4275..7fc3bba6b7 100644
--- a/lib/prism/translation/parser/builder.rb
+++ b/lib/prism/translation/parser/builder.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# :markup: markdown
module Prism
module Translation
@@ -6,12 +7,14 @@ module Prism
# A builder that knows how to convert more modern Ruby syntax
# into whitequark/parser gem's syntax tree.
class Builder < ::Parser::Builders::Default
- # It represents the `it` block argument, which is not yet implemented in the Parser gem.
+ # It represents the `it` block argument, which is not yet implemented in
+ # the Parser gem.
def itarg
n(:itarg, [:it], nil)
end
- # The following three lines have been added to support the `it` block parameter syntax in the source code below.
+ # The following three lines have been added to support the `it` block
+ # parameter syntax in the source code below.
#
# if args.type == :itarg
# block_type = :itblock
@@ -55,6 +58,12 @@ module Prism
method_call.loc.with_expression(join_exprs(method_call, block)))
end
end
+
+ # def foo(&nil); end
+ # ^^^^
+ def blocknilarg(amper_t, nil_t)
+ n0(:blocknilarg, arg_prefix_map(amper_t, nil_t))
+ end
end
end
end
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index acf4e77ee4..d11db12ae6 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -1,13 +1,14 @@
# frozen_string_literal: true
+# :markup: markdown
module Prism
module Translation
class Parser
# A visitor that knows how to convert a prism syntax tree into the
# whitequark/parser gem's syntax tree.
- class Compiler < ::Prism::Compiler
+ class Compiler < ::Prism::Compiler # :nodoc:
# Raised when the tree is malformed or there is a bug in the compiler.
- class CompilationError < StandardError
+ class CompilationError < StandardError # :nodoc:
end
# The Parser::Base instance that is being used to build the AST.
@@ -216,7 +217,7 @@ module Prism
rescue_clause.exceptions.any? ? builder.array(nil, visit_all(rescue_clause.exceptions), nil) : nil,
token(rescue_clause.operator_loc),
visit(rescue_clause.reference),
- srange_find(find_start_offset, find_end_offset, ";"),
+ srange_semicolon(find_start_offset, find_end_offset),
visit(rescue_clause.statements)
)
end until (rescue_clause = rescue_clause.subsequent).nil?
@@ -296,11 +297,6 @@ module Prism
if node.call_operator_loc.nil?
case name
- when :-@
- case (receiver = node.receiver).type
- when :integer_node, :float_node, :rational_node, :imaginary_node
- return visit(numeric_negate(node.message_loc, receiver))
- end
when :!
return visit_block(builder.not_op(token(node.message_loc), token(node.opening_loc), visit(node.receiver), token(node.closing_loc)), block)
when :=~
@@ -322,7 +318,7 @@ module Prism
visit_all(arguments),
token(node.closing_loc),
),
- srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, "="),
+ token(node.equal_loc),
visit(node.arguments.arguments.last)
),
block
@@ -339,7 +335,7 @@ module Prism
if name.end_with?("=") && !message_loc.slice.end_with?("=") && node.arguments && block.nil?
builder.assign(
builder.attr_asgn(visit(node.receiver), call_operator, token(message_loc)),
- srange_find(message_loc.end_offset, node.arguments.location.start_offset, "="),
+ token(node.equal_loc),
visit(node.arguments.arguments.last)
)
else
@@ -788,7 +784,7 @@ module Prism
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
- srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, ";")
+ srange_semicolon(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset)
end,
visit(node.statements),
token(node.end_keyword_loc)
@@ -920,7 +916,7 @@ module Prism
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset)
end,
visit(node.statements),
case node.subsequent
@@ -986,7 +982,7 @@ module Prism
if (then_loc = node.then_loc)
token(then_loc)
else
- srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, ";")
+ srange_semicolon(node.pattern.location.end_offset, node.statements&.location&.start_offset)
end,
visit(node.statements)
)
@@ -1052,7 +1048,7 @@ module Prism
builder.index_asgn(
visit(node.receiver),
token(node.opening_loc),
- visit_all(node.arguments.arguments),
+ visit_all(node.arguments&.arguments || []),
token(node.closing_loc),
)
end
@@ -1323,7 +1319,7 @@ module Prism
# A node that is missing from the syntax tree. This is only used in the
# case of a syntax error. The parser gem doesn't have such a concept, so
# we invent our own here.
- def visit_missing_node(node)
+ def visit_error_recovery_node(node)
::AST::Node.new(:missing, [], location: ::Parser::Source::Map.new(srange(node.location)))
end
@@ -1389,6 +1385,12 @@ module Prism
builder.nil(token(node.location))
end
+ # def foo(&nil); end
+ # ^^^^
+ def visit_no_block_parameter_node(node)
+ builder.blocknilarg(token(node.operator_loc), token(node.keyword_loc))
+ end
+
# def foo(**nil); end
# ^^^^^
def visit_no_keywords_parameter_node(node)
@@ -1481,7 +1483,8 @@ module Prism
# foo => ^(bar)
# ^^^^^^
def visit_pinned_expression_node(node)
- expression = builder.begin(token(node.lparen_loc), visit(node.expression), token(node.rparen_loc))
+ parts = node.expression.accept(copy_compiler(in_pattern: false)) # Don't treat * and similar as match_rest
+ expression = builder.begin(token(node.lparen_loc), parts, token(node.rparen_loc))
builder.pin(token(node.operator_loc), expression)
end
@@ -1765,7 +1768,7 @@ module Prism
end
else
parts =
- if node.value == ""
+ if node.value_loc.nil?
[]
elsif node.value.include?("\n")
string_nodes_from_line_continuations(node.unescaped, node.value, node.value_loc.start_offset, node.opening)
@@ -1806,7 +1809,7 @@ module Prism
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset)
end,
visit(node.else_clause),
token(node.else_clause&.else_keyword_loc),
@@ -1837,7 +1840,7 @@ module Prism
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
end,
visit(node.statements),
token(node.closing_loc)
@@ -1861,7 +1864,7 @@ module Prism
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
- srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, ";")
+ srange_semicolon(node.conditions.last.location.end_offset, node.statements&.location&.start_offset)
end,
visit(node.statements)
)
@@ -1881,7 +1884,7 @@ module Prism
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
end,
visit(node.statements),
token(node.closing_loc)
@@ -1965,22 +1968,6 @@ module Prism
elements
end
- # Negate the value of a numeric node. This is a special case where you
- # have a negative sign on one line and then a number on the next line.
- # In normal Ruby, this will always be a method call. The parser gem,
- # however, marks this as a numeric literal. We have to massage the tree
- # here to get it into the correct form.
- def numeric_negate(message_loc, receiver)
- case receiver.type
- when :integer_node, :float_node
- receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
- when :rational_node
- receiver.copy(numerator: -receiver.numerator, location: message_loc.join(receiver.location))
- when :imaginary_node
- receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
- end
- end
-
# Blocks can have a special set of parameters that automatically expand
# when given arrays if they have a single required parameter and no
# other parameters.
@@ -2010,16 +1997,16 @@ module Prism
Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])
end
- # Constructs a new source range by finding the given character between
- # the given start offset and end offset. If the needle is not found, it
- # returns nil. Importantly it does not search past newlines or comments.
+ # Constructs a new source range by finding a semicolon between the given
+ # start offset and end offset. If the semicolon is not found, it returns
+ # nil. Importantly it does not search past newlines or comments.
#
# Note that end_offset is allowed to be nil, in which case this will
# search until the end of the string.
- def srange_find(start_offset, end_offset, character)
- if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*#{character}/])
+ def srange_semicolon(start_offset, end_offset)
+ if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*;/])
final_offset = start_offset + match.bytesize
- [character, Range.new(source_buffer, offset_cache[final_offset - character.bytesize], offset_cache[final_offset])]
+ [";", Range.new(source_buffer, offset_cache[final_offset - 1], offset_cache[final_offset])]
end
end
@@ -2191,7 +2178,7 @@ module Prism
else
lines.sum do |line|
count = line.scan(/(\\*)n/).count { |(backslashes)| backslashes&.length&.odd? }
- count -= 1 if !line.end_with?("\n") && count > 0
+ count -= 1 if line.match?(/(?:\A|[^\\])(?:\\\\)*\\n\z/) && count > 0
count
end
end
diff --git a/lib/prism/translation/parser/lexer.rb b/lib/prism/translation/parser/lexer.rb
index 8f2d065b73..e82042867f 100644
--- a/lib/prism/translation/parser/lexer.rb
+++ b/lib/prism/translation/parser/lexer.rb
@@ -1,14 +1,16 @@
# frozen_string_literal: true
+# :markup: markdown
require "strscan"
require_relative "../../polyfill/append_as_bytes"
+require_relative "../../polyfill/scan_byte"
module Prism
module Translation
class Parser
# Accepts a list of prism tokens and converts them into the expected
# format for the parser gem.
- class Lexer
+ class Lexer # :nodoc:
# These tokens are always skipped
TYPES_ALWAYS_SKIP = Set.new(%i[IGNORED_NEWLINE __END__ EOF])
private_constant :TYPES_ALWAYS_SKIP
@@ -16,8 +18,6 @@ module Prism
# The direct translating of types between the two lexers.
TYPES = {
# These tokens should never appear in the output of the lexer.
- MISSING: nil,
- NOT_PROVIDED: nil,
EMBDOC_END: nil,
EMBDOC_LINE: nil,
@@ -87,6 +87,7 @@ module Prism
KEYWORD_DEF: :kDEF,
KEYWORD_DEFINED: :kDEFINED,
KEYWORD_DO: :kDO,
+ KEYWORD_DO_BLOCK: :kDO_BLOCK,
KEYWORD_DO_LOOP: :kDO_COND,
KEYWORD_END: :kEND,
KEYWORD_END_UPCASE: :klEND,
@@ -188,8 +189,8 @@ module Prism
# without them. We should find another way to do this, but in the
# meantime we'll hide them from the documentation and mark them as
# private constants.
- EXPR_BEG = 0x1 # :nodoc:
- EXPR_LABEL = 0x400 # :nodoc:
+ EXPR_BEG = 0x1
+ EXPR_LABEL = 0x400
# It is used to determine whether `do` is of the token type `kDO` or `kDO_LAMBDA`.
#
@@ -201,7 +202,7 @@ module Prism
# The following token types are listed as those classified as `tLPAREN`.
LPAREN_CONVERSION_TOKEN_TYPES = Set.new([
:kBREAK, :tCARET, :kCASE, :tDIVIDE, :kFOR, :kIF, :kNEXT, :kRETURN, :kUNTIL, :kWHILE, :tAMPER, :tANDOP, :tBANG, :tCOMMA, :tDOT2, :tDOT3,
- :tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS
+ :tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS, :tLCURLY
])
# Types of tokens that are allowed to continue a method call with comments in-between.
@@ -232,7 +233,7 @@ module Prism
@offset_cache = offset_cache
end
- Range = ::Parser::Source::Range # :nodoc:
+ Range = ::Parser::Source::Range
private_constant :Range
# Convert the prism tokens into the expected format for the parser gem.
@@ -275,20 +276,20 @@ module Prism
when :tCOMMENT
if token.type == :EMBDOC_BEGIN
- while !((next_token = lexed[index][0]) && next_token.type == :EMBDOC_END) && (index < length - 1)
+ while !((next_token = lexed[index]&.first) && next_token.type == :EMBDOC_END) && (index < length - 1)
value += next_token.value
index += 1
end
value += next_token.value
- location = range(token.location.start_offset, lexed[index][0].location.end_offset)
+ location = range(token.location.start_offset, next_token.location.end_offset)
index += 1
else
is_at_eol = value.chomp!.nil?
location = range(token.location.start_offset, token.location.end_offset + (is_at_eol ? 0 : -1))
- prev_token = lexed[index - 2][0] if index - 2 >= 0
- next_token = lexed[index][0]
+ prev_token, _ = lexed[index - 2] if index - 2 >= 0
+ next_token, _ = lexed[index]
is_inline_comment = prev_token&.location&.start_line == token.location.start_line
if is_inline_comment && !is_at_eol && !COMMENT_CONTINUATION_TYPES.include?(next_token&.type)
@@ -307,7 +308,7 @@ module Prism
end
end
when :tNL
- next_token = next_token = lexed[index][0]
+ next_token, _ = lexed[index]
# Newlines after comments are emitted out of order.
if next_token&.type == :COMMENT
comment_newline_location = location
@@ -344,8 +345,8 @@ module Prism
location = range(token.location.start_offset, token.location.start_offset + percent_array_leading_whitespace(value))
value = nil
when :tSTRING_BEG
- next_token = lexed[index][0]
- next_next_token = lexed[index + 1][0]
+ next_token, _ = lexed[index]
+ next_next_token, _ = lexed[index + 1]
basic_quotes = value == '"' || value == "'"
if basic_quotes && next_token&.type == :STRING_END
@@ -413,7 +414,8 @@ module Prism
while token.type == :STRING_CONTENT
current_length += token.value.bytesize
# Heredoc interpolation can have multiple STRING_CONTENT nodes on the same line.
- is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2][0].location&.start_line
+ prev_token, _ = lexed[index - 2] if index - 2 >= 0
+ is_first_token_on_line = prev_token && token.location.start_line != prev_token.location.start_line
# The parser gem only removes indentation when the heredoc is not nested
not_nested = heredoc_stack.size == 1
if is_percent_array
@@ -423,11 +425,16 @@ module Prism
end
current_string << unescape_string(value, quote_stack.last)
- if (backslash_count = token.value[/(\\{1,})\n/, 1]&.length).nil? || backslash_count.even? || !interpolation?(quote_stack.last)
+ relevant_backslash_count = if quote_stack.last.start_with?("%W", "%I")
+ 0 # the last backslash escapes the newline
+ else
+ token.value[/(\\{1,})\n/, 1]&.length || 0
+ end
+ if relevant_backslash_count.even? || !interpolation?(quote_stack.last)
tokens << [:tSTRING_CONTENT, [current_string, range(start_offset, start_offset + current_length)]]
break
end
- token = lexed[index][0]
+ token, _ = lexed[index]
index += 1
end
else
@@ -482,7 +489,7 @@ module Prism
end
if percent_array?(quote_stack.pop)
- prev_token = lexed[index - 2][0] if index - 2 >= 0
+ prev_token, _ = lexed[index - 2] if index - 2 >= 0
empty = %i[PERCENT_LOWER_I PERCENT_LOWER_W PERCENT_UPPER_I PERCENT_UPPER_W].include?(prev_token&.type)
ends_with_whitespace = prev_token&.type == :WORDS_SEP
# parser always emits a space token after content in a percent array, even if no actual whitespace is present.
@@ -491,7 +498,7 @@ module Prism
end
end
when :tSYMBEG
- if (next_token = lexed[index][0]) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
+ if (next_token = lexed[index]&.first) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
next_location = token.location.join(next_token.location)
type = :tSYMBOL
value = next_token.value
@@ -506,13 +513,13 @@ module Prism
type = :tIDENTIFIER
end
when :tXSTRING_BEG
- if (next_token = lexed[index][0]) && !%i[STRING_CONTENT STRING_END EMBEXPR_BEGIN].include?(next_token.type)
+ if (next_token = lexed[index]&.first) && !%i[STRING_CONTENT STRING_END EMBEXPR_BEGIN].include?(next_token.type)
# self.`()
type = :tBACK_REF2
end
quote_stack.push(value)
when :tSYMBOLS_BEG, :tQSYMBOLS_BEG, :tWORDS_BEG, :tQWORDS_BEG
- if (next_token = lexed[index][0]) && next_token.type == :WORDS_SEP
+ if (next_token = lexed[index]&.first) && next_token.type == :WORDS_SEP
index += 1
end
@@ -588,9 +595,9 @@ module Prism
previous_line = -1
result = Float::MAX
- while (lexed[next_token_index] && next_token = lexed[next_token_index][0])
+ while (next_token = lexed[next_token_index]&.first)
next_token_index += 1
- next_next_token = lexed[next_token_index] && lexed[next_token_index][0]
+ next_next_token, _ = lexed[next_token_index]
first_token_on_line = next_token.location.start_column == 0
# String content inside nested heredocs and interpolation is ignored
@@ -761,12 +768,12 @@ module Prism
elsif (value = scanner.scan(/M-\\?(?=[[:print:]])/))
# \M-x where x is an ASCII printable character
escape_read(result, scanner, control, true)
- elsif (byte = scanner.get_byte)
+ elsif (byte = scanner.scan_byte)
# Something else after an escape.
- if control && byte == "?"
+ if control && byte == 0x3f # ASCII '?'
result.append_as_bytes(escape_build(0x7f, false, meta))
else
- result.append_as_bytes(escape_build(byte.ord, control, meta))
+ result.append_as_bytes(escape_build(byte, control, meta))
end
end
end
diff --git a/lib/prism/translation/parser33.rb b/lib/prism/translation/parser33.rb
deleted file mode 100644
index b09266e06a..0000000000
--- a/lib/prism/translation/parser33.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- # This class is the entry-point for Ruby 3.3 of `Prism::Translation::Parser`.
- class Parser33 < Parser
- def version # :nodoc:
- 33
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser34.rb b/lib/prism/translation/parser34.rb
deleted file mode 100644
index 0ead70ad3c..0000000000
--- a/lib/prism/translation/parser34.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- # This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
- class Parser34 < Parser
- def version # :nodoc:
- 34
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser35.rb b/lib/prism/translation/parser35.rb
deleted file mode 100644
index a6abc12589..0000000000
--- a/lib/prism/translation/parser35.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- # This class is the entry-point for Ruby 3.5 of `Prism::Translation::Parser`.
- class Parser35 < Parser
- def version # :nodoc:
- 35
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser_current.rb b/lib/prism/translation/parser_current.rb
index b44769fde7..f7c1070e30 100644
--- a/lib/prism/translation/parser_current.rb
+++ b/lib/prism/translation/parser_current.rb
@@ -1,4 +1,6 @@
# frozen_string_literal: true
+# :markup: markdown
+#--
# typed: ignore
module Prism
@@ -8,11 +10,13 @@ module Prism
ParserCurrent = Parser33
when /^3\.4\./
ParserCurrent = Parser34
- when /^3\.5\./
- ParserCurrent = Parser35
+ when /^3\.5\./, /^4\.0\./
+ ParserCurrent = Parser40
+ when /^4\.1\./
+ ParserCurrent = Parser41
else
# Keep this in sync with released Ruby.
- parser = Parser34
+ parser = Parser40
major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments
warn "warning: `Prism::Translation::Current` is loading #{parser.name}, " \
"but you are running #{major}.#{minor}."
diff --git a/lib/prism/translation/parser_versions.rb b/lib/prism/translation/parser_versions.rb
new file mode 100644
index 0000000000..720c7d548c
--- /dev/null
+++ b/lib/prism/translation/parser_versions.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+# :markup: markdown
+
+module Prism
+ module Translation
+ # This class is the entry-point for Ruby 3.3 of `Prism::Translation::Parser`.
+ class Parser33 < Parser
+ def version # :nodoc:
+ 33
+ end
+ end
+
+ # This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
+ class Parser34 < Parser
+ def version # :nodoc:
+ 34
+ end
+ end
+
+ # This class is the entry-point for Ruby 4.0 of `Prism::Translation::Parser`.
+ class Parser40 < Parser
+ def version # :nodoc:
+ 40
+ end
+ end
+
+ Parser35 = Parser40 # :nodoc:
+
+ # This class is the entry-point for Ruby 4.1 of `Prism::Translation::Parser`.
+ class Parser41 < Parser
+ def version # :nodoc:
+ 41
+ end
+ end
+ end
+end
diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb
index 95f366ac91..f179a149a1 100644
--- a/lib/prism/translation/ripper.rb
+++ b/lib/prism/translation/ripper.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-
-require "ripper"
+# :markup: markdown
module Prism
module Translation
@@ -23,22 +22,10 @@ module Prism
# - on_comma
# - on_ignored_nl
# - on_ignored_sp
- # - on_kw
- # - on_label_end
- # - on_lbrace
- # - on_lbracket
- # - on_lparen
# - on_nl
- # - on_op
# - on_operator_ambiguous
- # - on_rbrace
- # - on_rbracket
- # - on_rparen
# - on_semicolon
# - on_sp
- # - on_symbeg
- # - on_tstring_beg
- # - on_tstring_end
#
class Ripper < Compiler
# Parses the given Ruby program read from +src+.
@@ -70,7 +57,8 @@ module Prism
# [[1, 13], :on_kw, "end", END ]]
#
def self.lex(src, filename = "-", lineno = 1, raise_errors: false)
- result = Prism.lex_compat(src, filepath: filename, line: lineno)
+ coerced = coerce_source(src)
+ result = Prism.lex_compat(coerced, filepath: filename, line: lineno, version: "current", encoding: coerced.encoding)
if result.failure? && raise_errors
raise SyntaxError, result.errors.first.message
@@ -79,6 +67,34 @@ module Prism
end
end
+ # Tokenizes the Ruby program and returns an array of strings.
+ # The +filename+ and +lineno+ arguments are mostly ignored, since the
+ # return value is just the tokenized input.
+ # By default, this method does not handle syntax errors in +src+,
+ # use the +raise_errors+ keyword to raise a SyntaxError for an error in +src+.
+ #
+ # p Ripper.tokenize("def m(a) nil end")
+ # # => ["def", " ", "m", "(", "a", ")", " ", "nil", " ", "end"]
+ #
+ def self.tokenize(...)
+ lex(...).map { |token| token[2] }
+ end
+
+ # Mirros the various lex_types that ripper supports
+ def self.coerce_source(source) # :nodoc:
+ if source.is_a?(IO)
+ source.read
+ elsif source.respond_to?(:gets)
+ src = +""
+ while line = source.gets
+ src << line
+ end
+ src
+ else
+ source.to_str
+ end
+ end
+
# This contains a table of all of the parser events and their
# corresponding arity.
PARSER_EVENT_TABLE = {
@@ -331,7 +347,7 @@ module Prism
"__ENCODING__",
"__FILE__",
"__LINE__"
- ]
+ ].to_set
# A list of all of the Ruby binary operators.
BINARY_OPERATORS = [
@@ -356,7 +372,7 @@ module Prism
:/,
:*,
:**
- ]
+ ].to_set
private_constant :KEYWORDS, :BINARY_OPERATORS
@@ -425,9 +441,93 @@ module Prism
end
end
+ autoload :Filter, "prism/translation/ripper/filter"
+ autoload :Lexer, "prism/translation/ripper/lexer"
autoload :SexpBuilder, "prism/translation/ripper/sexp"
autoload :SexpBuilderPP, "prism/translation/ripper/sexp"
+ # Provides optimized access to line and column information.
+ # Ripper bounds are mostly accessed in a linear fashion, so
+ # we can try a linear scan first and fall back to binary search.
+ class LineAndColumnCache # :nodoc:
+ # How many should it look ahead/behind before falling back to binary searching.
+ WINDOW = 8
+ private_constant :WINDOW
+
+ #: (Source source) -> void
+ def initialize(source)
+ @source = source
+ @offsets = source.offsets
+ @hint = 0
+ end
+
+ #: (Integer byte_offset) -> [Integer, Integer]
+ def line_and_column(byte_offset)
+ @hint = new_hint(byte_offset) || @source.find_line(byte_offset)
+ return [@hint + @source.start_line, byte_offset - @offsets[@hint]]
+ end
+
+ private
+
+ def new_hint(byte_offset)
+ if @offsets[@hint] <= byte_offset
+ # Same line?
+ if (@hint + 1 >= @offsets.size || @offsets[@hint + 1] > byte_offset)
+ return @hint
+ end
+
+ # Scan forwards
+ limit = [@hint + WINDOW + 1, @offsets.size].min
+ idx = @hint + 1
+ while idx < limit
+ if @offsets[idx] > byte_offset
+ return idx - 1
+ end
+ if @offsets[idx] == byte_offset
+ return idx
+ end
+ idx += 1
+ end
+ else
+ # Scan backwards
+ limit = @hint > WINDOW ? @hint - WINDOW : 0
+ idx = @hint
+ while idx >= limit + 1
+ if @offsets[idx - 1] <= byte_offset
+ return idx - 1
+ end
+ idx -= 1
+ end
+ end
+
+ nil
+ end
+ end
+
+ # :stopdoc:
+ # This is not part of the public API but used by some gems.
+
+ # Ripper-internal bitflags.
+ LEX_STATE_NAMES = %i[
+ BEG END ENDARG ENDFN ARG CMDARG MID FNAME DOT CLASS LABEL LABELED FITEM
+ ].map.with_index.to_h { |name, i| [2 ** i, name] }.freeze
+ private_constant :LEX_STATE_NAMES
+
+ LEX_STATE_NAMES.each do |value, key|
+ const_set("EXPR_#{key}", value)
+ end
+ EXPR_NONE = 0
+ 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
+
+ def self.lex_state_name(state)
+ LEX_STATE_NAMES.filter_map { |flag, name| name if state & flag != 0 }.join("|")
+ end
+
+ # :startdoc:
+
# The source that is being parsed.
attr_reader :source
@@ -437,16 +537,17 @@ module Prism
# The current line number of the parser.
attr_reader :lineno
- # The current column number of the parser.
+ # The current column in bytes of the parser.
attr_reader :column
# Create a new Translation::Ripper object with the given source.
def initialize(source, filename = "(ripper)", lineno = 1)
- @source = source
+ @source = Ripper.coerce_source(source)
@filename = filename
@lineno = lineno
@column = 0
@result = nil
+ @line_and_column_cache = nil
end
##########################################################################
@@ -465,7 +566,12 @@ module Prism
bounds(location)
if comment.is_a?(InlineComment)
- on_comment(comment.slice)
+ # Inline comments always contain a newline if the line itself contains it
+ if result.source.source.bytesize > comment.location.end_offset
+ on_comment("#{comment.slice}\n")
+ else
+ on_comment(comment.slice)
+ end
else
offset = location.start_offset
lines = comment.slice.lines
@@ -546,9 +652,14 @@ module Prism
# Visitor methods
##########################################################################
+ # :stopdoc:
+
# alias foo bar
# ^^^^^^^^^^^^^
def visit_alias_method_node(node)
+ bounds(node.keyword_loc)
+ on_kw("alias")
+
new_name = visit(node.new_name)
old_name = visit(node.old_name)
@@ -559,6 +670,9 @@ module Prism
# alias $foo $bar
# ^^^^^^^^^^^^^^^
def visit_alias_global_variable_node(node)
+ bounds(node.keyword_loc)
+ on_kw("alias")
+
new_name = visit_alias_global_variable_node_value(node.new_name)
old_name = visit_alias_global_variable_node_value(node.old_name)
@@ -584,6 +698,10 @@ module Prism
# ^^^^^^^^^
def visit_alternation_pattern_node(node)
left = visit_pattern_node(node.left)
+
+ bounds(node.operator_loc)
+ on_op("|")
+
right = visit_pattern_node(node.right)
bounds(node.location)
@@ -594,7 +712,13 @@ module Prism
# parenthesis node that can be used to wrap patterns.
private def visit_pattern_node(node)
if node.is_a?(ParenthesesNode)
- visit(node.body)
+ bounds(node.opening_loc)
+ on_lparen("(")
+ result = visit(node.body)
+ bounds(node.closing_loc)
+ on_rparen(")")
+
+ result
else
visit(node)
end
@@ -604,6 +728,14 @@ module Prism
# ^^^^^^^
def visit_and_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ if node.operator == "and"
+ on_kw("and")
+ else
+ on_op("&&")
+ end
+
right = visit(node.right)
bounds(node.location)
@@ -631,6 +763,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
when /^%i/
@@ -650,6 +784,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
when /^%W/
@@ -687,6 +823,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
when /^%I/
@@ -724,6 +862,8 @@ module Prism
previous = element
end
+ visit_words_sep(opening_loc, node.elements.last, node.closing_loc)
+
bounds(node.closing_loc)
on_tstring_end(node.closing)
else
@@ -740,15 +880,21 @@ module Prism
on_array(elements)
end
- # Dispatch a words_sep event that contains the space between the elements
+ # Dispatch words_sep events that contains the whitespace between the elements
# of list literals.
private def visit_words_sep(opening_loc, previous, current)
- end_offset = (previous.nil? ? opening_loc : previous.location).end_offset
- start_offset = current.location.start_offset
-
- if end_offset != start_offset
- bounds(current.location.copy(start_offset: end_offset))
- on_words_sep(source.byteslice(end_offset...start_offset))
+ start_offset = (previous.nil? ? opening_loc : previous.location).end_offset
+ end_offset = current.start_offset
+ length = end_offset - start_offset
+
+ if length > 0
+ whitespace = source.byteslice(start_offset, length)
+ current_offset = start_offset
+ whitespace.each_line do |part|
+ bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize))
+ on_words_sep(part)
+ current_offset += part.bytesize
+ end
end
end
@@ -774,9 +920,18 @@ module Prism
# ^^^^^
def visit_array_pattern_node(node)
constant = visit(node.constant)
+
+ if node.opening_loc
+ bounds(node.opening_loc)
+ node.opening == "[" ? on_lbracket("[") : on_lparen("(")
+ end
+
requireds = visit_all(node.requireds) if node.requireds.any?
rest =
if (rest_node = node.rest).is_a?(SplatNode)
+ bounds(rest_node.operator_loc)
+ on_op("*")
+
if rest_node.expression.nil?
bounds(rest_node.location)
on_var_field(nil)
@@ -787,6 +942,10 @@ module Prism
posts = visit_all(node.posts) if node.posts.any?
+ if node.closing_loc
+ bounds(node.closing_loc)
+ node.closing == "]" ? on_rbracket("]") : on_rparen(")")
+ end
bounds(node.location)
on_aryptn(constant, requireds, rest, posts)
end
@@ -802,6 +961,12 @@ module Prism
# ^^^^
def visit_assoc_node(node)
key = visit(node.key)
+
+ if node.operator_loc
+ bounds(node.operator_loc)
+ on_op("=>")
+ end
+
value = visit(node.value)
bounds(node.location)
@@ -814,6 +979,9 @@ module Prism
# { **foo }
# ^^^^^
def visit_assoc_splat_node(node)
+ bounds(node.operator_loc)
+ on_op("**")
+
value = visit(node.value)
bounds(node.location)
@@ -830,8 +998,18 @@ module Prism
# begin end
# ^^^^^^^^^
def visit_begin_node(node)
+ if node.begin_keyword_loc
+ bounds(node.begin_keyword_loc)
+ on_kw("begin")
+ end
+
clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false)
+ if node.end_keyword_loc
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
on_begin(clauses)
end
@@ -843,7 +1021,7 @@ module Prism
on_stmts_add(on_stmts_new, on_void_stmt)
else
body = node.statements.body
- body.unshift(nil) if void_stmt?(location, node.statements.body[0].location, allow_newline)
+ body = [nil, *body] if void_stmt?(location, node.statements.body[0].location, allow_newline)
bounds(node.statements.location)
visit_statements_node_body(body)
@@ -852,12 +1030,15 @@ module Prism
rescue_clause = visit(node.rescue_clause)
else_clause =
unless (else_clause_node = node.else_clause).nil?
+ bounds(else_clause_node.else_keyword_loc)
+ on_kw("else")
+
else_statements =
if else_clause_node.statements.nil?
[nil]
else
body = else_clause_node.statements.body
- body.unshift(nil) if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline)
+ body = [nil, *body] if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline)
body
end
@@ -879,7 +1060,7 @@ module Prism
on_bodystmt(visit_statements_node_body([nil]), nil, nil, nil)
when StatementsNode
body = [*node.body]
- body.unshift(nil) if void_stmt?(location, body[0].location, allow_newline)
+ body = [nil, *body] if void_stmt?(location, body[0].location, allow_newline)
stmts = visit_statements_node_body(body)
bounds(node.body.first.location)
@@ -894,6 +1075,8 @@ module Prism
# foo(&bar)
# ^^^^
def visit_block_argument_node(node)
+ bounds(node.operator_loc)
+ on_op("&")
visit(node.expression)
end
@@ -907,6 +1090,13 @@ module Prism
# Visit a BlockNode.
def visit_block_node(node)
braces = node.opening == "{"
+ bounds(node.opening_loc)
+ if braces
+ on_lbrace("{")
+ else
+ on_kw("do")
+ end
+
parameters = visit(node.parameters)
body =
@@ -919,7 +1109,7 @@ module Prism
braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
when StatementsNode
stmts = node.body.body
- stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
+ stmts = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
stmts = visit_statements_node_body(stmts)
bounds(node.body.location)
@@ -931,6 +1121,14 @@ module Prism
end
if braces
+ bounds(node.closing_loc)
+ on_rbrace("}")
+ else
+ bounds(node.closing_loc)
+ on_kw("end")
+ end
+
+ if braces
bounds(node.location)
on_brace_block(parameters, body)
else
@@ -942,12 +1140,15 @@ module Prism
# def foo(&bar); end
# ^^^^
def visit_block_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("&")
+
if node.name_loc.nil?
bounds(node.location)
on_blockarg(nil)
else
bounds(node.name_loc)
- name = visit_token(node.name.to_s)
+ name = on_ident(node.name.to_s)
bounds(node.location)
on_blockarg(name)
@@ -956,6 +1157,9 @@ module Prism
# A block's parameters.
def visit_block_parameters_node(node)
+ bounds(node.opening_loc)
+ on_op("|")
+
parameters =
if node.parameters.nil?
on_params(nil, nil, nil, nil, nil, nil, nil)
@@ -970,6 +1174,9 @@ module Prism
false
end
+ bounds(node.closing_loc)
+ on_op("|")
+
bounds(node.location)
on_block_var(parameters, locals)
end
@@ -980,6 +1187,9 @@ module Prism
# break foo
# ^^^^^^^^^
def visit_break_node(node)
+ bounds(node.keyword_loc)
+ on_kw("break")
+
if node.arguments.nil?
bounds(node.location)
on_break(on_args_new)
@@ -1004,20 +1214,32 @@ module Prism
case node.name
when :[]
receiver = visit(node.receiver)
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
+ block = visit(block_node)
bounds(node.location)
call = on_aref(receiver, arguments)
- if block.nil?
- call
- else
+ if block_node
bounds(node.location)
on_method_add_block(call, block)
+ else
+ call
end
when :[]=
receiver = visit(node.receiver)
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
*arguments, last_argument = node.arguments.arguments
arguments << node.block if !node.block.nil?
@@ -1033,6 +1255,11 @@ module Prism
end
end
+ bounds(node.closing_loc)
+ on_rbracket("]")
+ bounds(node.equal_loc)
+ on_op("=")
+
bounds(node.location)
call = on_aref_field(receiver, arguments)
value = visit_write_value(last_argument)
@@ -1040,27 +1267,54 @@ module Prism
bounds(last_argument.location)
on_assign(call, value)
when :-@, :+@, :~
- receiver = visit(node.receiver)
+ bounds(node.message_loc)
+ on_op(node.message)
+ receiver = visit(node.receiver)
bounds(node.location)
on_unary(node.name, receiver)
when :!
+ bounds(node.message_loc)
if node.message == "not"
+ on_kw("not")
+
+ if node.opening_loc
+ bounds(node.opening_loc)
+ on_lparen("(")
+ end
+
receiver =
- if !node.receiver.is_a?(ParenthesesNode) || !node.receiver.body.nil?
+ if node.receiver.is_a?(ParenthesesNode) && node.receiver.body.nil?
+ # The parens in `not()` just emit parens and nothing else.
+ bounds(node.receiver.opening_loc)
+ on_lparen("(")
+ bounds(node.receiver.closing_loc)
+ on_rparen(")")
+ nil
+ else
visit(node.receiver)
end
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_rparen(")")
+ end
bounds(node.location)
on_unary(:not, receiver)
else
+ on_op("!")
+
receiver = visit(node.receiver)
bounds(node.location)
on_unary(:!, receiver)
end
- when *BINARY_OPERATORS
+ when BINARY_OPERATORS
receiver = visit(node.receiver)
+
+ bounds(node.message_loc)
+ on_op(node.message)
+
value = visit(node.arguments.arguments.first)
bounds(node.location)
@@ -1072,9 +1326,21 @@ module Prism
if node.variable_call?
on_vcall(message)
else
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
+ if node.opening_loc
+ bounds(node.opening_loc)
+ on_lparen("(")
+ end
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
+
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_rparen(")")
+ end
+
+ block = visit(block_node)
call =
- if node.opening_loc.nil? && arguments&.any?
+ if node.opening_loc.nil? && get_arguments_and_block(node.arguments, node.block).first.any?
bounds(node.location)
on_command(message, arguments)
elsif !node.opening_loc.nil?
@@ -1085,11 +1351,11 @@ module Prism
on_method_add_arg(on_fcall(message), on_args_new)
end
- if block.nil?
- call
- else
+ if block_node
bounds(node.block.location)
on_method_add_block(call, block)
+ else
+ call
end
end
end
@@ -1097,7 +1363,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
message =
if node.message_loc.nil?
@@ -1107,13 +1373,30 @@ module Prism
visit_token(node.message, false)
end
+ if node.equal_loc
+ bounds(node.equal_loc)
+ on_op("=")
+ end
+
if node.name.end_with?("=") && !node.message.end_with?("=") && !node.arguments.nil? && node.block.nil?
value = visit_write_value(node.arguments.arguments.first)
bounds(node.location)
on_assign(on_field(receiver, call_operator, message), value)
else
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
+ if node.opening_loc
+ bounds(node.opening_loc)
+ on_lparen("(")
+ end
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
+
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_rparen(")")
+ end
+
+ block = visit(block_node)
call =
if node.opening_loc.nil?
bounds(node.location)
@@ -1131,27 +1414,35 @@ module Prism
on_method_add_arg(on_call(receiver, call_operator, message), arguments)
end
- if block.nil?
- call
- else
+ if block_node
bounds(node.block.location)
on_method_add_block(call, block)
+ else
+ call
end
end
end
end
- # Visit the arguments and block of a call node and return the arguments
- # and block as they should be used.
- private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
+ # Extract the arguments and block Ripper-style, which means if the block
+ # is like `&b` then it's moved to arguments.
+ private def get_arguments_and_block(arguments_node, block_node)
arguments = arguments_node&.arguments || []
block = block_node
if block.is_a?(BlockArgumentNode)
- arguments << block
+ arguments += [block]
block = nil
end
+ [arguments, block]
+ end
+
+ # Visit the arguments and block of a call node and return the arguments
+ # and block as they should be used.
+ private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
+ arguments, block = get_arguments_and_block(arguments_node, block_node)
+
[
if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
visit(arguments.first)
@@ -1165,7 +1456,7 @@ module Prism
on_args_add_block(args, false)
end
end,
- visit(block)
+ block,
]
end
@@ -1183,7 +1474,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1205,7 +1496,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1227,7 +1518,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1249,6 +1540,9 @@ module Prism
if node.call_operator == "::"
receiver = visit(node.receiver)
+ bounds(node.call_operator_loc)
+ on_op("::")
+
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1258,7 +1552,7 @@ module Prism
receiver = visit(node.receiver)
bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
+ call_operator = visit_call_operator(node.call_operator)
bounds(node.message_loc)
message = visit_token(node.message)
@@ -1272,6 +1566,10 @@ module Prism
# ^^^^^^^^^^
def visit_capture_pattern_node(node)
value = visit(node.value)
+
+ bounds(node.operator_loc)
+ on_op("=>")
+
target = visit(node.target)
bounds(node.location)
@@ -1281,10 +1579,21 @@ module Prism
# case foo; when bar; end
# ^^^^^^^^^^^^^^^^^^^^^^^
def visit_case_node(node)
+ bounds(node.case_keyword_loc)
+ on_kw("case")
+
predicate = visit(node.predicate)
+ visited_conditions = node.conditions.map { |condition| visit(condition) }
+ visited_else_clause = visit(node.else_clause)
+
+ if !node.else_clause
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
clauses =
- node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
- on_when(*visit(condition), current)
+ visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition|
+ on_when(*condition, current)
end
bounds(node.location)
@@ -1294,10 +1603,23 @@ module Prism
# case foo; in bar; end
# ^^^^^^^^^^^^^^^^^^^^^
def visit_case_match_node(node)
+ bounds(node.case_keyword_loc)
+ on_kw("case")
+
predicate = visit(node.predicate)
+ visited_conditions = node.conditions.map do | condition|
+ visit(condition)
+ end
+ visited_else_clause = visit(node.else_clause)
+
+ if !node.else_clause
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
clauses =
- node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
- on_in(*visit(condition), current)
+ visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition|
+ on_in(*condition, current)
end
bounds(node.location)
@@ -1307,6 +1629,9 @@ module Prism
# class Foo; end
# ^^^^^^^^^^^^^^
def visit_class_node(node)
+ bounds(node.class_keyword_loc)
+ on_kw("class")
+
constant_path =
if node.constant_path.is_a?(ConstantReadNode)
bounds(node.constant_path.location)
@@ -1315,9 +1640,17 @@ module Prism
visit(node.constant_path)
end
+ if node.inheritance_operator_loc
+ bounds(node.inheritance_operator_loc)
+ on_op("<")
+ end
+
superclass = visit(node.superclass)
bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?)
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_class(constant_path, superclass, bodystmt)
end
@@ -1331,12 +1664,13 @@ module Prism
# @@foo = 1
# ^^^^^^^^^
- #
- # @@foo, @@bar = 1
- # ^^^^^ ^^^^^
def visit_class_variable_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_cvar(node.name.to_s))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1401,12 +1735,13 @@ module Prism
# Foo = 1
# ^^^^^^^
- #
- # Foo, Bar = 1
- # ^^^ ^^^
def visit_constant_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_const(node.name.to_s))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1466,6 +1801,11 @@ module Prism
# ^^^^^^^^
def visit_constant_path_node(node)
if node.parent.nil?
+ if node.delimiter_loc
+ bounds(node.delimiter_loc)
+ on_op("::")
+ end
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1474,6 +1814,9 @@ module Prism
else
parent = visit(node.parent)
+ bounds(node.delimiter_loc)
+ on_op("::")
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1484,11 +1827,12 @@ module Prism
# Foo::Bar = 1
# ^^^^^^^^^^^^
- #
- # Foo::Foo, Bar::Bar = 1
- # ^^^^^^^^ ^^^^^^^^
def visit_constant_path_write_node(node)
target = visit_constant_path_write_node_target(node.target)
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1498,6 +1842,11 @@ module Prism
# Visit a constant path that is part of a write node.
private def visit_constant_path_write_node_target(node)
if node.parent.nil?
+ if node.delimiter_loc
+ bounds(node.delimiter_loc)
+ on_op("::")
+ end
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1506,6 +1855,9 @@ module Prism
else
parent = visit(node.parent)
+ bounds(node.delimiter_loc)
+ on_op("::")
+
bounds(node.name_loc)
child = on_const(node.name.to_s)
@@ -1518,7 +1870,6 @@ module Prism
# ^^^^^^^^^^^^^^^
def visit_constant_path_operator_write_node(node)
target = visit_constant_path_write_node_target(node.target)
- value = visit(node.value)
bounds(node.binary_operator_loc)
operator = on_op("#{node.binary_operator}=")
@@ -1532,7 +1883,6 @@ module Prism
# ^^^^^^^^^^^^^^^^
def visit_constant_path_and_write_node(node)
target = visit_constant_path_write_node_target(node.target)
- value = visit(node.value)
bounds(node.operator_loc)
operator = on_op("&&=")
@@ -1546,7 +1896,6 @@ module Prism
# ^^^^^^^^^^^^^^^^
def visit_constant_path_or_write_node(node)
target = visit_constant_path_write_node_target(node.target)
- value = visit(node.value)
bounds(node.operator_loc)
operator = on_op("||=")
@@ -1568,16 +1917,24 @@ module Prism
# def self.foo; end
# ^^^^^^^^^^^^^^^^^
def visit_def_node(node)
+ bounds(node.def_keyword_loc)
+ on_kw("def")
+
receiver = visit(node.receiver)
operator =
if !node.operator_loc.nil?
bounds(node.operator_loc)
- visit_token(node.operator)
+ node.operator == "." ? on_period(".") : on_op("::")
end
bounds(node.name_loc)
name = visit_token(node.name_loc.slice)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
parameters =
if node.parameters.nil?
bounds(node.location)
@@ -1587,10 +1944,17 @@ module Prism
end
if !node.lparen_loc.nil?
+ bounds(node.rparen_loc)
+ on_rparen(")")
bounds(node.lparen_loc)
parameters = on_paren(parameters)
end
+ if node.equal_loc
+ bounds(node.equal_loc)
+ on_op("=")
+ end
+
bodystmt =
if node.equal_loc.nil?
visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body)
@@ -1601,11 +1965,16 @@ module Prism
on_bodystmt(body, nil, nil, nil)
end
+ if node.end_keyword_loc
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
- if receiver.nil?
- on_def(name, parameters, bodystmt)
- else
+ if receiver
on_defs(receiver, operator, name, parameters, bodystmt)
+ else
+ on_def(name, parameters, bodystmt)
end
end
@@ -1615,8 +1984,21 @@ module Prism
# defined?(a)
# ^^^^^^^^^^^
def visit_defined_node(node)
+ bounds(node.keyword_loc)
+ on_kw("defined?")
+
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
expression = visit(node.value)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
# Very weird circumstances here where something like:
#
# defined?
@@ -1637,17 +2019,24 @@ module Prism
# if foo then bar else baz end
# ^^^^^^^^^^^^
def visit_else_node(node)
+ bounds(node.else_keyword_loc)
+ on_kw("else")
+
statements =
if node.statements.nil?
[nil]
else
body = node.statements.body
- body.unshift(nil) if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false)
+ body = [nil, *body] if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false)
body
end
+ else_statements = visit_statements_node_body(statements)
+
+ bounds(node.end_keyword_loc)
+ on_kw("end")
bounds(node.location)
- on_else(visit_statements_node_body(statements))
+ on_else(else_statements)
end
# "foo #{bar}"
@@ -1685,12 +2074,15 @@ module Prism
# Visit an EnsureNode node.
def visit_ensure_node(node)
+ bounds(node.ensure_keyword_loc)
+ on_kw("ensure")
+
statements =
if node.statements.nil?
[nil]
else
body = node.statements.body
- body.unshift(nil) if void_stmt?(node.ensure_keyword_loc, body[0].location, false)
+ body = [nil, *body] if void_stmt?(node.ensure_keyword_loc, body[0].location, false)
body
end
@@ -1711,6 +2103,14 @@ module Prism
# ^^^^^^^^^^^
def visit_find_pattern_node(node)
constant = visit(node.constant)
+
+ if node.opening_loc
+ bounds(node.opening_loc)
+ node.opening == "[" ? on_lbracket("[") : on_lparen("(")
+ end
+ bounds(node.left.operator_loc)
+ on_op("*")
+
left =
if node.left.expression.nil?
bounds(node.left.location)
@@ -1720,6 +2120,10 @@ module Prism
end
requireds = visit_all(node.requireds) if node.requireds.any?
+
+ bounds(node.right.operator_loc)
+ on_op("*")
+
right =
if node.right.expression.nil?
bounds(node.right.location)
@@ -1728,6 +2132,10 @@ module Prism
visit(node.right.expression)
end
+ if node.closing_loc
+ bounds(node.closing_loc)
+ node.closing == "]" ? on_rbracket("]") : on_rparen(")")
+ end
bounds(node.location)
on_fndptn(constant, left, requireds, right)
end
@@ -1736,6 +2144,10 @@ module Prism
# ^^^^^^^^^^
def visit_flip_flop_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ on_op(node.operator)
+
right = visit(node.right)
bounds(node.location)
@@ -1755,8 +2167,18 @@ module Prism
# for foo in bar do end
# ^^^^^^^^^^^^^^^^^^^^^
def visit_for_node(node)
+ bounds(node.for_keyword_loc)
+ on_kw("for")
+
index = visit(node.index)
+ bounds(node.in_keyword_loc)
+ on_kw("in")
+
collection = visit(node.collection)
+ if node.do_keyword_loc
+ bounds(node.do_keyword_loc)
+ on_kw("do")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -1765,6 +2187,9 @@ module Prism
visit(node.statements)
end
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_for(index, collection, statements)
end
@@ -1773,6 +2198,7 @@ module Prism
# ^^^
def visit_forwarding_arguments_node(node)
bounds(node.location)
+ on_op("...")
on_args_forward
end
@@ -1780,6 +2206,7 @@ module Prism
# ^^^
def visit_forwarding_parameter_node(node)
bounds(node.location)
+ on_op("...")
on_args_forward
end
@@ -1789,6 +2216,9 @@ module Prism
# super {}
# ^^^^^^^^
def visit_forwarding_super_node(node)
+ bounds(node.keyword_loc)
+ on_kw("super")
+
if node.block.nil?
bounds(node.location)
on_zsuper
@@ -1809,12 +2239,13 @@ module Prism
# $foo = 1
# ^^^^^^^^
- #
- # $foo, $bar = 1
- # ^^^^ ^^^^
def visit_global_variable_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_gvar(node.name.to_s))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -1873,6 +2304,9 @@ module Prism
# {}
# ^^
def visit_hash_node(node)
+ bounds(node.opening_loc)
+ on_lbrace("{")
+
elements =
if node.elements.any?
args = visit_all(node.elements)
@@ -1881,6 +2315,8 @@ module Prism
on_assoclist_from_args(args)
end
+ bounds(node.closing_loc)
+ on_rbrace("}")
bounds(node.location)
on_hash(elements)
end
@@ -1889,6 +2325,15 @@ module Prism
# ^^
def visit_hash_pattern_node(node)
constant = visit(node.constant)
+
+ if node.constant
+ bounds(node.opening_loc)
+ node.opening == "[" ? on_lbracket("[") : on_lparen("(")
+ elsif node.opening_loc
+ bounds(node.opening_loc)
+ on_lbrace("{")
+ end
+
elements =
if node.elements.any? || !node.rest.nil?
node.elements.map do |element|
@@ -1911,12 +2356,21 @@ module Prism
rest =
case node.rest
when AssocSplatNode
+ bounds(node.rest.operator_loc)
+ on_op("**")
visit(node.rest.value)
when NoKeywordsParameterNode
bounds(node.rest.location)
on_var_field(visit(node.rest))
end
+ if node.constant
+ bounds(node.closing_loc)
+ node.closing == "]" ? on_rbracket("]") : on_rparen(")")
+ elsif node.closing_loc
+ bounds(node.closing_loc)
+ on_rbrace("}")
+ end
bounds(node.location)
on_hshptn(constant, elements, rest)
end
@@ -1932,13 +2386,27 @@ module Prism
def visit_if_node(node)
if node.then_keyword == "?"
predicate = visit(node.predicate)
+
+ bounds(node.then_keyword_loc)
+ on_op("?")
+
truthy = visit(node.statements.body.first)
+
+ bounds(node.subsequent.else_keyword_loc)
+ on_op(":")
+
falsy = visit(node.subsequent.statements.body.first)
bounds(node.location)
on_ifop(predicate, truthy, falsy)
elsif node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ bounds(node.if_keyword_loc)
+ on_kw(node.if_keyword)
predicate = visit(node.predicate)
+ if node.then_keyword_loc && node.then_keyword != "?"
+ bounds(node.then_keyword_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -1948,6 +2416,11 @@ module Prism
end
subsequent = visit(node.subsequent)
+ if node.end_keyword_loc && !node.subsequent
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
if node.if_keyword == "if"
on_if(predicate, statements, subsequent)
@@ -1956,6 +2429,8 @@ module Prism
end
else
statements = visit(node.statements.body.first)
+ bounds(node.if_keyword_loc)
+ on_kw(node.if_keyword)
predicate = visit(node.predicate)
bounds(node.location)
@@ -1987,7 +2462,14 @@ module Prism
# This is a special case where we're not going to call on_in directly
# because we don't have access to the subsequent. Instead, we'll return
# the component parts and let the parent node handle it.
+ bounds(node.in_loc)
+ on_kw("in")
+
pattern = visit_pattern_node(node.pattern)
+ if node.then_loc
+ bounds(node.then_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -2003,8 +2485,15 @@ module Prism
# ^^^^^^^^^^^^^^^
def visit_index_operator_write_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
target = on_aref_field(receiver, arguments)
@@ -2020,8 +2509,15 @@ module Prism
# ^^^^^^^^^^^^^^^^
def visit_index_and_write_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
target = on_aref_field(receiver, arguments)
@@ -2037,8 +2533,15 @@ module Prism
# ^^^^^^^^^^^^^^^^
def visit_index_or_write_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
target = on_aref_field(receiver, arguments)
@@ -2054,8 +2557,15 @@ module Prism
# ^^^^^^^^
def visit_index_target_node(node)
receiver = visit(node.receiver)
+
+ bounds(node.opening_loc)
+ on_lbracket("[")
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
+ bounds(node.closing_loc)
+ on_rbracket("]")
+
bounds(node.location)
on_aref_field(receiver, arguments)
end
@@ -2072,6 +2582,10 @@ module Prism
def visit_instance_variable_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_ivar(node.name.to_s))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -2174,20 +2688,37 @@ module Prism
# "foo #{bar}"
# ^^^^^^^^^^^^
def visit_interpolated_string_node(node)
- if node.opening&.start_with?("<<~")
- heredoc = visit_heredoc_string_node(node)
+ with_string_bounds(node) do
+ if node.opening&.start_with?("<<~")
+ heredoc = visit_heredoc_string_node(node)
- bounds(node.location)
- on_string_literal(heredoc)
- elsif !node.heredoc? && node.parts.length > 1 && node.parts.any? { |part| (part.is_a?(StringNode) || part.is_a?(InterpolatedStringNode)) && !part.opening_loc.nil? }
- first, *rest = node.parts
- rest.inject(visit(first)) do |content, part|
- concat = visit(part)
+ bounds(node.location)
+ on_string_literal(heredoc)
+ elsif !node.heredoc? && node.parts.length > 1 && node.parts.any? { |part| (part.is_a?(StringNode) || part.is_a?(InterpolatedStringNode)) && !part.opening_loc.nil? }
+ first, *rest = node.parts
+ rest.inject(visit(first)) do |content, part|
+ concat = visit(part)
+
+ bounds(part.location)
+ on_string_concat(content, concat)
+ end
+ else
+ bounds(node.parts.first.location)
+ parts =
+ node.parts.inject(on_string_content) do |content, part|
+ on_string_add(content, visit_string_content(part))
+ end
- bounds(part.location)
- on_string_concat(content, concat)
+ bounds(node.location)
+ on_string_literal(parts)
end
- else
+ end
+ end
+
+ # :"foo #{bar}"
+ # ^^^^^^^^^^^^^
+ def visit_interpolated_symbol_node(node)
+ with_string_bounds(node) do
bounds(node.parts.first.location)
parts =
node.parts.inject(on_string_content) do |content, part|
@@ -2195,40 +2726,29 @@ module Prism
end
bounds(node.location)
- on_string_literal(parts)
+ on_dyna_symbol(parts)
end
end
- # :"foo #{bar}"
- # ^^^^^^^^^^^^^
- def visit_interpolated_symbol_node(node)
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_string_content) do |content, part|
- on_string_add(content, visit_string_content(part))
- end
-
- bounds(node.location)
- on_dyna_symbol(parts)
- end
-
# `foo #{bar}`
# ^^^^^^^^^^^^
def visit_interpolated_x_string_node(node)
- if node.opening.start_with?("<<~")
- heredoc = visit_heredoc_x_string_node(node)
+ with_string_bounds(node) do
+ if node.opening.start_with?("<<~")
+ heredoc = visit_heredoc_x_string_node(node)
- bounds(node.location)
- on_xstring_literal(heredoc)
- else
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_xstring_new) do |content, part|
- on_xstring_add(content, visit_string_content(part))
- end
+ bounds(node.location)
+ on_xstring_literal(heredoc)
+ else
+ bounds(node.parts.first.location)
+ parts =
+ node.parts.inject(on_xstring_new) do |content, part|
+ on_xstring_add(content, visit_string_content(part))
+ end
- bounds(node.location)
- on_xstring_literal(parts)
+ bounds(node.location)
+ on_xstring_literal(parts)
+ end
end
end
@@ -2269,6 +2789,9 @@ module Prism
# def foo(**); end
# ^^
def visit_keyword_rest_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("**")
+
if node.name_loc.nil?
bounds(node.location)
on_kwrest_param(nil)
@@ -2288,6 +2811,11 @@ module Prism
parameters =
if node.parameters.is_a?(BlockParametersNode)
+ if node.parameters.opening_loc
+ bounds(node.parameters.opening_loc)
+ on_lparen("(")
+ end
+
# Ripper does not track block-locals within lambdas, so we skip
# directly to the parameters here.
params =
@@ -2298,6 +2826,13 @@ module Prism
visit(node.parameters.parameters)
end
+ visit_all(node.parameters.locals)
+
+ if node.parameters.closing_loc
+ bounds(node.parameters.closing_loc)
+ on_rparen(")")
+ end
+
if node.parameters.opening_loc.nil?
params
else
@@ -2310,9 +2845,11 @@ module Prism
end
braces = node.opening == "{"
+ bounds(node.opening_loc)
if braces
- bounds(node.opening_loc)
on_tlambeg(node.opening)
+ else
+ on_kw("do")
end
body =
@@ -2325,7 +2862,7 @@ module Prism
braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
when StatementsNode
stmts = node.body.body
- stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
+ stmts = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
stmts = visit_statements_node_body(stmts)
bounds(node.body.location)
@@ -2336,6 +2873,13 @@ module Prism
raise
end
+ bounds(node.closing_loc)
+ if braces
+ on_rbrace("}")
+ else
+ on_kw("end")
+ end
+
bounds(node.location)
on_lambda(parameters, body)
end
@@ -2352,6 +2896,10 @@ module Prism
def visit_local_variable_write_node(node)
bounds(node.name_loc)
target = on_var_field(on_ident(node.name_loc.slice))
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit_write_value(node.value)
bounds(node.location)
@@ -2426,6 +2974,8 @@ module Prism
# ^^^^^^^^^^
def visit_match_predicate_node(node)
value = visit(node.value)
+ bounds(node.operator_loc)
+ on_kw("in")
pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
on_case(value, pattern)
@@ -2435,6 +2985,10 @@ module Prism
# ^^^^^^^^^^
def visit_match_required_node(node)
value = visit(node.value)
+
+ bounds(node.operator_loc)
+ on_op("=>")
+
pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
on_case(value, pattern)
@@ -2448,13 +3002,16 @@ module Prism
# A node that is missing from the syntax tree. This is only used in the
# case of a syntax error.
- def visit_missing_node(node)
- raise "Cannot visit missing nodes directly."
+ def visit_error_recovery_node(node)
+ raise "Cannot visit error recovery nodes directly."
end
# module Foo; end
# ^^^^^^^^^^^^^^^
def visit_module_node(node)
+ bounds(node.module_keyword_loc)
+ on_kw("module")
+
constant_path =
if node.constant_path.is_a?(ConstantReadNode)
bounds(node.constant_path.location)
@@ -2465,6 +3022,9 @@ module Prism
bodystmt = visit_body_node(node.constant_path.location, node.body, true)
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_module(constant_path, bodystmt)
end
@@ -2472,9 +3032,19 @@ module Prism
# (foo, bar), bar = qux
# ^^^^^^^^^^
def visit_multi_target_node(node)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
bounds(node.location)
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
if node.lparen_loc.nil?
targets
else
@@ -2526,9 +3096,22 @@ module Prism
# foo, bar = baz
# ^^^^^^^^^^^^^^
def visit_multi_write_node(node)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
bounds(node.location)
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
+ bounds(node.operator_loc)
+ on_op("=")
+
unless node.lparen_loc.nil?
bounds(node.lparen_loc)
targets = on_mlhs_paren(targets)
@@ -2546,6 +3129,9 @@ module Prism
# next foo
# ^^^^^^^^
def visit_next_node(node)
+ bounds(node.keyword_loc)
+ on_kw("next")
+
if node.arguments.nil?
bounds(node.location)
on_next(on_args_new)
@@ -2564,9 +3150,24 @@ module Prism
on_var_ref(on_kw("nil"))
end
+ # def foo(&nil); end
+ # ^^^^
+ def visit_no_block_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("&")
+ bounds(node.keyword_loc)
+ on_kw("nil")
+ bounds(node.location)
+ on_blockarg(:nil)
+ end
+
# def foo(**nil); end
# ^^^^^
def visit_no_keywords_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("**")
+ bounds(node.keyword_loc)
+ on_kw("nil")
bounds(node.location)
on_nokw_param(nil)
@@ -2599,7 +3200,11 @@ module Prism
# ^^^^^^^
def visit_optional_parameter_node(node)
bounds(node.name_loc)
- name = visit_token(node.name.to_s)
+ name = on_ident(node.name.to_s)
+
+ bounds(node.operator_loc)
+ on_op("=")
+
value = visit(node.value)
[name, value]
@@ -2609,6 +3214,14 @@ module Prism
# ^^^^^^
def visit_or_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ if node.operator == "or"
+ on_kw("or")
+ else
+ on_op("||")
+ end
+
right = visit(node.right)
bounds(node.location)
@@ -2632,9 +3245,19 @@ module Prism
# Visit a destructured positional parameter node.
private def visit_destructured_parameter_node(node)
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
bounds(node.location)
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, false)
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
bounds(node.lparen_loc)
on_mlhs_paren(targets)
end
@@ -2645,6 +3268,9 @@ module Prism
# (1)
# ^^^
def visit_parentheses_node(node)
+ bounds(node.opening_loc)
+ on_lparen("(")
+
body =
if node.body.nil?
on_stmts_add(on_stmts_new, on_void_stmt)
@@ -2652,6 +3278,8 @@ module Prism
visit(node.body)
end
+ bounds(node.closing_loc)
+ on_rparen(")")
bounds(node.location)
on_paren(body)
end
@@ -2659,8 +3287,15 @@ module Prism
# foo => ^(bar)
# ^^^^^^
def visit_pinned_expression_node(node)
+ bounds(node.operator_loc)
+ on_op("^")
+ bounds(node.lparen_loc)
+ on_lparen("(")
+
expression = visit(node.expression)
+ bounds(node.rparen_loc)
+ on_rparen(")")
bounds(node.location)
on_begin(expression)
end
@@ -2668,12 +3303,20 @@ module Prism
# foo = 1 and bar => ^foo
# ^^^^
def visit_pinned_variable_node(node)
+ bounds(node.operator_loc)
+ on_op("^")
+
visit(node.variable)
end
# END {}
# ^^^^^^
def visit_post_execution_node(node)
+ bounds(node.keyword_loc)
+ on_kw("END")
+ bounds(node.opening_loc)
+ on_lbrace("{")
+
statements =
if node.statements.nil?
bounds(node.location)
@@ -2682,6 +3325,8 @@ module Prism
visit(node.statements)
end
+ bounds(node.closing_loc)
+ on_rbrace("}")
bounds(node.location)
on_END(statements)
end
@@ -2689,6 +3334,11 @@ module Prism
# BEGIN {}
# ^^^^^^^^
def visit_pre_execution_node(node)
+ bounds(node.keyword_loc)
+ on_kw("BEGIN")
+ bounds(node.opening_loc)
+ on_lbrace("{")
+
statements =
if node.statements.nil?
bounds(node.location)
@@ -2697,6 +3347,8 @@ module Prism
visit(node.statements)
end
+ bounds(node.closing_loc)
+ on_rbrace("}")
bounds(node.location)
on_BEGIN(statements)
end
@@ -2704,7 +3356,7 @@ module Prism
# The top-level program node.
def visit_program_node(node)
body = node.statements.body
- body << nil if body.empty?
+ body = [nil] if body.empty?
statements = visit_statements_node_body(body)
bounds(node.location)
@@ -2715,6 +3367,10 @@ module Prism
# ^^^^
def visit_range_node(node)
left = visit(node.left)
+
+ bounds(node.operator_loc)
+ on_op(node.operator)
+
right = visit(node.right)
bounds(node.location)
@@ -2735,6 +3391,7 @@ module Prism
# ^^^^
def visit_redo_node(node)
bounds(node.location)
+ on_kw("redo")
on_redo
end
@@ -2777,6 +3434,9 @@ module Prism
# foo rescue bar
# ^^^^^^^^^^^^^^
def visit_rescue_modifier_node(node)
+ bounds(node.keyword_loc)
+ on_kw("rescue")
+
expression = visit_write_value(node.expression)
rescue_expression = visit(node.rescue_expression)
@@ -2787,6 +3447,9 @@ module Prism
# begin; rescue; end
# ^^^^^^^
def visit_rescue_node(node)
+ bounds(node.keyword_loc)
+ on_kw("rescue")
+
exceptions =
case node.exceptions.length
when 0
@@ -2824,6 +3487,11 @@ module Prism
end
end
+ if node.operator_loc
+ bounds(node.operator_loc)
+ on_op("=>")
+ end
+
reference = visit(node.reference)
statements =
if node.statements.nil?
@@ -2845,12 +3513,15 @@ module Prism
# def foo(*); end
# ^
def visit_rest_parameter_node(node)
+ bounds(node.operator_loc)
+ on_op("*")
+
if node.name_loc.nil?
bounds(node.location)
on_rest_param(nil)
else
bounds(node.name_loc)
- on_rest_param(visit_token(node.name.to_s))
+ on_rest_param(on_ident(node.name.to_s))
end
end
@@ -2858,6 +3529,7 @@ module Prism
# ^^^^^
def visit_retry_node(node)
bounds(node.location)
+ on_kw("retry")
on_retry
end
@@ -2867,6 +3539,9 @@ module Prism
# return 1
# ^^^^^^^^
def visit_return_node(node)
+ bounds(node.keyword_loc)
+ on_kw("return")
+
if node.arguments.nil?
bounds(node.location)
on_return0
@@ -2893,9 +3568,17 @@ module Prism
# class << self; end
# ^^^^^^^^^^^^^^^^^^
def visit_singleton_class_node(node)
+ bounds(node.class_keyword_loc)
+ on_kw("class")
+ bounds(node.operator_loc)
+ on_op("<<")
+
expression = visit(node.expression)
bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body)
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+
bounds(node.location)
on_sclass(expression, bodystmt)
end
@@ -2930,6 +3613,8 @@ module Prism
# def foo(*); bar(*); end
# ^
def visit_splat_node(node)
+ bounds(node.operator_loc)
+ on_op("*")
visit(node.expression)
end
@@ -2952,26 +3637,68 @@ module Prism
# "foo"
# ^^^^^
def visit_string_node(node)
- if (content = node.content).empty?
- bounds(node.location)
- on_string_literal(on_string_content)
- elsif (opening = node.opening) == "?"
- bounds(node.location)
- on_CHAR("?#{node.content}")
- elsif opening.start_with?("<<~")
- heredoc = visit_heredoc_string_node(node.to_interpolated)
+ with_string_bounds(node) do
+ if (content = node.content).empty?
+ bounds(node.location)
+ on_string_literal(on_string_content)
+ elsif (opening = node.opening) == "?"
+ bounds(node.location)
+ on_CHAR("?#{node.content}")
+ elsif opening.start_with?("<<~")
+ heredoc = visit_heredoc_string_node(node.to_interpolated)
- bounds(node.location)
- on_string_literal(heredoc)
- else
- bounds(node.content_loc)
- tstring_content = on_tstring_content(content)
+ bounds(node.location)
+ on_string_literal(heredoc)
+ else
+ bounds(node.content_loc)
+ tstring_content = on_tstring_content(content)
- bounds(node.location)
- on_string_literal(on_string_add(on_string_content, tstring_content))
+ bounds(node.location)
+ on_string_literal(on_string_add(on_string_content, tstring_content))
+ end
end
end
+ # Responsible for emitting the various string-like begin/end events
+ private def with_string_bounds(node)
+ # `foo "bar": baz` doesn't emit the closing location
+ assoc = !(opening = node.opening)&.include?(":") && node.closing&.end_with?(":")
+
+ is_heredoc = opening&.start_with?("<<")
+ if is_heredoc
+ bounds(node.opening_loc)
+ on_heredoc_beg(node.opening)
+ elsif opening&.start_with?(":", "%s")
+ bounds(node.opening_loc)
+ on_symbeg(node.opening)
+ elsif opening&.start_with?("`", "%x")
+ bounds(node.opening_loc)
+ on_backtick(node.opening)
+ elsif opening && !opening.start_with?("?")
+ bounds(node.opening_loc)
+ on_tstring_beg(opening)
+ end
+
+ result = yield
+ if assoc
+ if node.closing != ":"
+ bounds(node.closing_loc)
+ on_label_end(node.closing)
+ end
+ return result
+ end
+
+ if is_heredoc
+ bounds(node.closing_loc)
+ on_heredoc_end(node.closing)
+ elsif node.closing_loc
+ bounds(node.closing_loc)
+ on_tstring_end(node.closing)
+ end
+
+ result
+ end
+
# Ripper gives back the escaped string content but strips out the common
# leading whitespace. Prism gives back the unescaped string content and
# a location for the escaped string content. Unfortunately these don't
@@ -3049,42 +3776,39 @@ module Prism
# Visit a heredoc node that is representing a string.
private def visit_heredoc_string_node(node)
- bounds(node.opening_loc)
- on_heredoc_beg(node.opening)
-
bounds(node.location)
- result =
- visit_heredoc_node(node.parts, on_string_content) do |parts, part|
- on_string_add(parts, part)
- end
-
- bounds(node.closing_loc)
- on_heredoc_end(node.closing)
-
- result
+ visit_heredoc_node(node.parts, on_string_content) do |parts, part|
+ on_string_add(parts, part)
+ end
end
# Visit a heredoc node that is representing an xstring.
private def visit_heredoc_x_string_node(node)
- bounds(node.opening_loc)
- on_heredoc_beg(node.opening)
-
bounds(node.location)
- result =
- visit_heredoc_node(node.parts, on_xstring_new) do |parts, part|
- on_xstring_add(parts, part)
- end
-
- bounds(node.closing_loc)
- on_heredoc_end(node.closing)
-
- result
+ visit_heredoc_node(node.parts, on_xstring_new) do |parts, part|
+ on_xstring_add(parts, part)
+ end
end
# super(foo)
# ^^^^^^^^^^
def visit_super_node(node)
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location))
+ bounds(node.keyword_loc)
+ on_kw("super")
+
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
+ arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location))
+
+ if node.rparen_loc
+ bounds(node.rparen_loc)
+ on_rparen(")")
+ end
+
+ block = visit(block_node)
if !node.lparen_loc.nil?
bounds(node.lparen_loc)
@@ -3094,35 +3818,36 @@ module Prism
bounds(node.location)
call = on_super(arguments)
- if block.nil?
- call
- else
+ if block_node
bounds(node.block.location)
on_method_add_block(call, block)
+ else
+ call
end
end
# :foo
# ^^^^
def visit_symbol_node(node)
- if (opening = node.opening)&.match?(/^%s|['"]:?$/)
- bounds(node.value_loc)
- content = on_string_content
-
- if !(value = node.value).empty?
- content = on_string_add(content, on_tstring_content(value))
+ with_string_bounds(node) do
+ if node.value_loc.nil?
+ bounds(node.location)
+ on_dyna_symbol(on_string_content)
+ elsif (opening = node.opening)&.match?(/^%s|['"]:?$/)
+ bounds(node.value_loc)
+ content = on_string_add(on_string_content, on_tstring_content(node.value))
+ bounds(node.location)
+ on_dyna_symbol(content)
+ elsif (closing = node.closing) == ":"
+ bounds(node.location)
+ on_label("#{node.value}:")
+ elsif opening.nil? && node.closing_loc.nil?
+ bounds(node.value_loc)
+ on_symbol_literal(visit_token(node.value))
+ else
+ bounds(node.value_loc)
+ on_symbol_literal(on_symbol(visit_token(node.value)))
end
-
- on_dyna_symbol(content)
- elsif (closing = node.closing) == ":"
- bounds(node.location)
- on_label("#{node.value}:")
- elsif opening.nil? && node.closing_loc.nil?
- bounds(node.value_loc)
- on_symbol_literal(visit_token(node.value))
- else
- bounds(node.value_loc)
- on_symbol_literal(on_symbol(visit_token(node.value)))
end
end
@@ -3136,6 +3861,9 @@ module Prism
# undef foo
# ^^^^^^^^^
def visit_undef_node(node)
+ bounds(node.keyword_loc)
+ on_kw("undef")
+
names = visit_all(node.names)
bounds(node.location)
@@ -3149,7 +3877,13 @@ module Prism
# ^^^^^^^^^^^^^^
def visit_unless_node(node)
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ bounds(node.keyword_loc)
+ on_kw("unless")
predicate = visit(node.predicate)
+ if node.then_keyword_loc
+ bounds(node.then_keyword_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -3159,10 +3893,17 @@ module Prism
end
else_clause = visit(node.else_clause)
+ if node.end_keyword_loc && !node.else_clause
+ bounds(node.end_keyword_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
on_unless(predicate, statements, else_clause)
else
statements = visit(node.statements.body.first)
+ bounds(node.keyword_loc)
+ on_kw("unless")
predicate = visit(node.predicate)
bounds(node.location)
@@ -3176,7 +3917,14 @@ module Prism
# bar until foo
# ^^^^^^^^^^^^^
def visit_until_node(node)
+ bounds(node.keyword_loc)
+ on_kw("until")
+
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ if node.do_keyword_loc
+ bounds(node.do_keyword_loc)
+ on_kw("do")
+ end
predicate = visit(node.predicate)
statements =
if node.statements.nil?
@@ -3186,6 +3934,11 @@ module Prism
visit(node.statements)
end
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_kw("end")
+ end
+
bounds(node.location)
on_until(predicate, statements)
else
@@ -3203,7 +3956,14 @@ module Prism
# This is a special case where we're not going to call on_when directly
# because we don't have access to the subsequent. Instead, we'll return
# the component parts and let the parent node handle it.
+ bounds(node.keyword_loc)
+ on_kw("when")
+
conditions = visit_arguments(node.conditions)
+ if node.then_keyword_loc
+ bounds(node.then_keyword_loc)
+ on_kw("then")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -3222,7 +3982,17 @@ module Prism
# ^^^^^^^^^^^^^
def visit_while_node(node)
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
+ bounds(node.keyword_loc)
+ on_kw("while")
+ if node.do_keyword_loc
+ bounds(node.do_keyword_loc)
+ on_kw("do")
+ end
predicate = visit(node.predicate)
+ if node.closing_loc
+ bounds(node.closing_loc)
+ on_kw("end")
+ end
statements =
if node.statements.nil?
bounds(node.location)
@@ -3235,6 +4005,8 @@ module Prism
on_while(predicate, statements)
else
statements = visit(node.statements.body.first)
+ bounds(node.keyword_loc)
+ on_kw("while")
predicate = visit(node.predicate)
bounds(node.location)
@@ -3245,20 +4017,22 @@ module Prism
# `foo`
# ^^^^^
def visit_x_string_node(node)
- if node.unescaped.empty?
- bounds(node.location)
- on_xstring_literal(on_xstring_new)
- elsif node.opening.start_with?("<<~")
- heredoc = visit_heredoc_x_string_node(node.to_interpolated)
+ with_string_bounds(node) do
+ if node.unescaped.empty?
+ bounds(node.location)
+ on_xstring_literal(on_xstring_new)
+ elsif node.opening.start_with?("<<~")
+ heredoc = visit_heredoc_x_string_node(node.to_interpolated)
- bounds(node.location)
- on_xstring_literal(heredoc)
- else
- bounds(node.content_loc)
- content = on_tstring_content(node.content)
+ bounds(node.location)
+ on_xstring_literal(heredoc)
+ else
+ bounds(node.content_loc)
+ content = on_tstring_content(node.content)
- bounds(node.location)
- on_xstring_literal(on_xstring_add(on_xstring_new, content))
+ bounds(node.location)
+ on_xstring_literal(on_xstring_add(on_xstring_new, content))
+ end
end
end
@@ -3268,10 +4042,18 @@ module Prism
# yield 1
# ^^^^^^^
def visit_yield_node(node)
+ bounds(node.keyword_loc)
+ on_kw("yield")
+
if node.arguments.nil? && node.lparen_loc.nil?
bounds(node.location)
on_yield0
else
+ if node.lparen_loc
+ bounds(node.lparen_loc)
+ on_lparen("(")
+ end
+
arguments =
if node.arguments.nil?
bounds(node.location)
@@ -3281,6 +4063,8 @@ module Prism
end
unless node.lparen_loc.nil?
+ bounds(node.rparen_loc)
+ on_rparen(")")
bounds(node.lparen_loc)
arguments = on_paren(arguments)
end
@@ -3294,7 +4078,11 @@ module Prism
# Lazily initialize the parse result.
def result
- @result ||= Prism.parse(source, partial_script: true)
+ @result ||= Prism.parse(source, partial_script: true, version: "current", freeze: true, encoding: source.encoding)
+ end
+
+ def line_and_column_cache
+ @line_and_column_cache ||= LineAndColumnCache.new(result.source)
end
##########################################################################
@@ -3315,30 +4103,34 @@ module Prism
# Visit the string content of a particular node. This method is used to
# split into the various token types.
def visit_token(token, allow_keywords = true)
- case token
- when "."
+ if token == "."
on_period(token)
- when "`"
+ elsif token == "`"
on_backtick(token)
- when *(allow_keywords ? KEYWORDS : [])
+ elsif allow_keywords && KEYWORDS.include?(token)
on_kw(token)
- when /^_/
+ elsif token.start_with?("_")
on_ident(token)
- when /^[[:upper:]]\w*$/
+ elsif token.match?(/^[[:upper:]]\w*$/)
on_const(token)
- when /^@@/
+ elsif token.start_with?("@@")
on_cvar(token)
- when /^@/
+ elsif token.start_with?("@")
on_ivar(token)
- when /^\$/
+ elsif token.start_with?("$")
on_gvar(token)
- when /^[[:punct:]]/
+ elsif token.match?(/^[[:punct:]]/)
on_op(token)
else
on_ident(token)
end
end
+ # Visit either `.`, `&.`, or `::`.
+ def visit_call_operator(token)
+ token == "." ? on_period(token) : on_op(token)
+ end
+
# Visit a node that represents a number. We need to explicitly handle the
# unary - operator.
def visit_number_node(node)
@@ -3346,6 +4138,9 @@ module Prism
location = node.location
if slice[0] == "-"
+ bounds(location.copy(length: 1))
+ on_op("-")
+
bounds(location.copy(start_offset: location.start_offset + 1))
value = yield slice[1..-1]
@@ -3394,26 +4189,24 @@ module Prism
# 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
+ @lineno, @column = line_and_column_cache.line_and_column(location.start_offset)
end
+ # :startdoc:
+
##########################################################################
# Ripper interface
##########################################################################
# :stopdoc:
def _dispatch_0; end
- def _dispatch_1(_); end
- def _dispatch_2(_, _); end
- def _dispatch_3(_, _, _); end
- def _dispatch_4(_, _, _, _); end
- def _dispatch_5(_, _, _, _, _); end
- def _dispatch_7(_, _, _, _, _, _, _); end
+ def _dispatch_1(arg); arg end
+ def _dispatch_2(arg, _); arg end
+ def _dispatch_3(arg, _, _); arg end
+ def _dispatch_4(arg, _, _, _); arg end
+ def _dispatch_5(arg, _, _, _, _); arg end
+ def _dispatch_7(arg, _, _, _, _, _, _); arg end
# :startdoc:
#
diff --git a/lib/prism/translation/ripper/filter.rb b/lib/prism/translation/ripper/filter.rb
new file mode 100644
index 0000000000..19deef2d37
--- /dev/null
+++ b/lib/prism/translation/ripper/filter.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Prism
+ module Translation
+ class Ripper
+ class Filter # :nodoc:
+ # :stopdoc:
+ def initialize(src, filename = '-', lineno = 1)
+ @__lexer = Lexer.new(src, filename, lineno)
+ @__line = nil
+ @__col = nil
+ @__state = nil
+ end
+
+ def filename
+ @__lexer.filename
+ end
+
+ def lineno
+ @__line
+ end
+
+ def column
+ @__col
+ end
+
+ def state
+ @__state
+ end
+
+ def parse(init = nil)
+ data = init
+ @__lexer.lex.each do |pos, event, tok, state|
+ @__line, @__col = *pos
+ @__state = state
+ data = if respond_to?(event, true)
+ then __send__(event, tok, data)
+ else on_default(event, tok, data)
+ end
+ end
+ data
+ end
+
+ private
+
+ def on_default(event, token, data)
+ data
+ end
+ # :startdoc:
+ end
+ end
+ end
+end
diff --git a/lib/prism/translation/ripper/lexer.rb b/lib/prism/translation/ripper/lexer.rb
new file mode 100644
index 0000000000..c6aeae4bd7
--- /dev/null
+++ b/lib/prism/translation/ripper/lexer.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+# :markup: markdown
+
+require_relative "../ripper"
+
+module Prism
+ module Translation
+ class Ripper
+ class Lexer < Ripper # :nodoc:
+ class State # :nodoc:
+ attr_reader :to_int, :to_s
+
+ def initialize(i)
+ @to_int = i
+ @to_s = Ripper.lex_state_name(i)
+ freeze
+ end
+
+ def [](index)
+ case index
+ when 0, :to_int
+ @to_int
+ when 1, :to_s
+ @to_s
+ else
+ nil
+ end
+ end
+
+ alias to_i to_int
+ alias inspect to_s
+ def pretty_print(q) q.text(to_s) end
+ def ==(i) super or to_int == i end
+ def &(i) self.class.new(to_int & i) end
+ def |(i) self.class.new(to_int | i) end
+ def allbits?(i) to_int.allbits?(i) end
+ def anybits?(i) to_int.anybits?(i) end
+ def nobits?(i) to_int.nobits?(i) end
+
+ # Instances are frozen and there are only a handful of them so we
+ # cache them here.
+ STATES = Hash.new { |hash, key| hash[key] = State.new(key) }
+ private_constant :STATES
+
+ def self.[](i)
+ STATES[i]
+ end
+ end
+
+ class Elem # :nodoc:
+ attr_accessor :pos, :event, :tok, :state, :message
+
+ def initialize(pos, event, tok, state, message = nil)
+ @pos = pos
+ @event = event
+ @tok = tok
+ @state = State[state]
+ @message = message
+ end
+
+ def [](index)
+ case index
+ when 0, :pos
+ @pos
+ when 1, :event
+ @event
+ when 2, :tok
+ @tok
+ when 3, :state
+ @state
+ when 4, :message
+ @message
+ else
+ nil
+ end
+ end
+
+ def inspect
+ "#<#{self.class}: #{event}@#{pos[0]}:#{pos[1]}:#{state}: #{tok.inspect}#{": " if message}#{message}>"
+ end
+
+ alias to_s inspect
+
+ def pretty_print(q)
+ q.group(2, "#<#{self.class}:", ">") {
+ q.breakable
+ q.text("#{event}@#{pos[0]}:#{pos[1]}")
+ q.breakable
+ state.pretty_print(q)
+ q.breakable
+ q.text("token: ")
+ tok.pretty_print(q)
+ if message
+ q.breakable
+ q.text("message: ")
+ q.text(message)
+ end
+ }
+ end
+
+ def to_a
+ if @message
+ [@pos, @event, @tok, @state, @message]
+ else
+ [@pos, @event, @tok, @state]
+ end
+ end
+ end
+
+ # Pretty much just the same as Prism.lex_compat.
+ def lex(raise_errors: false)
+ Ripper.lex(@source, filename, lineno, raise_errors: raise_errors)
+ end
+
+ # Returns the lex_compat result wrapped in `Elem`. Errors are omitted.
+ # Since ripper is a streaming parser, tokens are expected to be emitted in the order
+ # that the parser encounters them. This is not implemented.
+ def parse(...)
+ lex(...).map do |position, event, token, state|
+ Elem.new(position, event, token, state.to_int)
+ end
+ end
+
+ # Similar to parse but ripper sorts the elements by position in the source. Also
+ # includes errors. Since prism does error recovery, in cases of syntax errors
+ # the result may differ greatly compared to ripper.
+ def scan(...)
+ parse(...)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/prism/translation/ripper/sexp.rb b/lib/prism/translation/ripper/sexp.rb
index dc26a639a3..46c0333544 100644
--- a/lib/prism/translation/ripper/sexp.rb
+++ b/lib/prism/translation/ripper/sexp.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# :markup: markdown
require_relative "../ripper"
@@ -7,9 +8,7 @@ module Prism
class Ripper
# This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
# returns the arrays of [type, *children].
- class SexpBuilder < Ripper
- # :stopdoc:
-
+ class SexpBuilder < Ripper # :nodoc:
attr_reader :error
private
@@ -64,16 +63,12 @@ module Prism
remove_method :on_parse_error
alias on_parse_error on_error
alias compile_error on_error
-
- # :startdoc:
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
- # :stopdoc:
-
+ class SexpBuilderPP < SexpBuilder # :nodoc:
private
def on_heredoc_dedent(val, width)
@@ -117,8 +112,6 @@ module Prism
alias_method "on_#{event}", :_dispatch_event_push
end
end
-
- # :startdoc:
end
end
end
diff --git a/lib/prism/translation/ripper/shim.rb b/lib/prism/translation/ripper/shim.rb
index 10e21cd16a..00ed625da3 100644
--- a/lib/prism/translation/ripper/shim.rb
+++ b/lib/prism/translation/ripper/shim.rb
@@ -2,4 +2,6 @@
# This writes the prism ripper translation into the Ripper constant so that
# users can transparently use Ripper without any changes.
+# :stopdoc:
Ripper = Prism::Translation::Ripper
+# :startdoc:
diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb
index 8784e22d10..42bc5ee658 100644
--- a/lib/prism/translation/ruby_parser.rb
+++ b/lib/prism/translation/ruby_parser.rb
@@ -1,21 +1,27 @@
# frozen_string_literal: true
+# :markup: markdown
begin
- require "ruby_parser"
+ require "sexp"
rescue LoadError
- warn(%q{Error: Unable to load ruby_parser. Add `gem "ruby_parser"` to your Gemfile.})
+ warn(%q{Error: Unable to load sexp. Add `gem "sexp_processor"` to your Gemfile.})
exit(1)
end
+class RubyParser # :nodoc:
+ class SyntaxError < RuntimeError # :nodoc:
+ end
+end
+
module Prism
module Translation
# This module is the entry-point for converting a prism syntax tree into the
# seattlerb/ruby_parser gem's syntax tree.
class RubyParser
# A prism visitor that builds Sexp objects.
- class Compiler < ::Prism::Compiler
+ class Compiler < ::Prism::Compiler # :nodoc:
# This is the name of the file that we are compiling. We set it on every
- # Sexp object that is generated, and also use it to compile __FILE__
+ # Sexp object that is generated, and also use it to compile `__FILE__`
# nodes.
attr_reader :file
@@ -131,7 +137,7 @@ module Prism
# $+
# ^^
def visit_back_reference_read_node(node)
- s(node, :back_ref, node.name.name.delete_prefix("$").to_sym)
+ s(node, :back_ref, node.name.to_s.delete_prefix("$").to_sym)
end
# begin end
@@ -366,14 +372,18 @@ module Prism
visit(node.constant_path)
end
- if node.body.nil?
- s(node, :class, name, visit(node.superclass))
- elsif node.body.is_a?(StatementsNode)
- compiler = copy_compiler(in_def: false)
- s(node, :class, name, visit(node.superclass)).concat(node.body.body.map { |child| child.accept(compiler) })
- else
- s(node, :class, name, visit(node.superclass), node.body.accept(copy_compiler(in_def: false)))
- end
+ result =
+ if node.body.nil?
+ s(node, :class, name, visit(node.superclass))
+ elsif node.body.is_a?(StatementsNode)
+ compiler = copy_compiler(in_def: false)
+ s(node, :class, name, visit(node.superclass)).concat(node.body.body.map { |child| child.accept(compiler) })
+ else
+ s(node, :class, name, visit(node.superclass), node.body.accept(copy_compiler(in_def: false)))
+ end
+
+ attach_comments(result, node)
+ result
end
# @@foo
@@ -384,9 +394,6 @@ module Prism
# @@foo = 1
# ^^^^^^^^^
- #
- # @@foo, @@bar = 1
- # ^^^^^ ^^^^^
def visit_class_variable_write_node(node)
s(node, class_variable_write_type, node.name, visit_write_value(node.value))
end
@@ -524,7 +531,9 @@ module Prism
s(node, :defs, visit(node.receiver), name)
end
+ attach_comments(result, node)
result.line(node.name_loc.start_line)
+
if node.parameters.nil?
result << s(node, :args).line(node.name_loc.start_line)
else
@@ -639,9 +648,6 @@ module Prism
# $foo = 1
# ^^^^^^^^
- #
- # $foo, $bar = 1
- # ^^^^ ^^^^
def visit_global_variable_write_node(node)
s(node, :gasgn, node.name, visit_write_value(node.value))
end
@@ -787,9 +793,6 @@ module Prism
# @foo = 1
# ^^^^^^^^
- #
- # @foo, @bar = 1
- # ^^^^ ^^^^
def visit_instance_variable_write_node(node)
s(node, :iasgn, node.name, visit_write_value(node.value))
end
@@ -976,8 +979,8 @@ module Prism
def visit_lambda_node(node)
parameters =
case node.parameters
- when nil, NumberedParametersNode
- s(node, :args)
+ when nil, ItParametersNode, NumberedParametersNode
+ 0
else
visit(node.parameters)
end
@@ -1001,9 +1004,6 @@ module Prism
# foo = 1
# ^^^^^^^
- #
- # foo, bar = 1
- # ^^^ ^^^
def visit_local_variable_write_node(node)
s(node, :lasgn, node.name, visit_write_value(node.value))
end
@@ -1059,8 +1059,8 @@ module Prism
# A node that is missing from the syntax tree. This is only used in the
# case of a syntax error. The parser gem doesn't have such a concept, so
# we invent our own here.
- def visit_missing_node(node)
- raise "Cannot visit missing node directly"
+ def visit_error_recovery_node(node)
+ raise "Cannot visit error recovery node directly"
end
# module Foo; end
@@ -1073,14 +1073,18 @@ module Prism
visit(node.constant_path)
end
- if node.body.nil?
- s(node, :module, name)
- elsif node.body.is_a?(StatementsNode)
- compiler = copy_compiler(in_def: false)
- s(node, :module, name).concat(node.body.body.map { |child| child.accept(compiler) })
- else
- s(node, :module, name, node.body.accept(copy_compiler(in_def: false)))
- end
+ result =
+ if node.body.nil?
+ s(node, :module, name)
+ elsif node.body.is_a?(StatementsNode)
+ compiler = copy_compiler(in_def: false)
+ s(node, :module, name).concat(node.body.body.map { |child| child.accept(compiler) })
+ else
+ s(node, :module, name, node.body.accept(copy_compiler(in_def: false)))
+ end
+
+ attach_comments(result, node)
+ result
end
# foo, bar = baz
@@ -1136,6 +1140,12 @@ module Prism
s(node, :nil)
end
+ # def foo(&nil); end
+ # ^^^^
+ def visit_no_block_parameter_node(node)
+ :"&nil"
+ end
+
# def foo(**nil); end
# ^^^^^
def visit_no_keywords_parameter_node(node)
@@ -1188,7 +1198,7 @@ module Prism
# ^^^^^^^^^
def visit_parameters_node(node)
children =
- node.compact_child_nodes.map do |element|
+ node.each_child_node.map do |element|
if element.is_a?(MultiTargetNode)
visit_destructured_parameter(element)
else
@@ -1537,6 +1547,17 @@ module Prism
private
+ # Attach prism comments to the given sexp.
+ def attach_comments(sexp, node)
+ return unless node.comments
+ return if node.comments.empty?
+
+ extra = node.location.start_line - node.comments.last.location.start_line
+ comments = node.comments.map(&:slice)
+ comments.concat([nil] * [0, extra].max)
+ sexp.comments = comments.join("\n")
+ end
+
# Create a new compiler with the given options.
def copy_compiler(in_def: self.in_def, in_pattern: self.in_pattern)
Compiler.new(file, in_def: in_def, in_pattern: in_pattern)
@@ -1615,6 +1636,14 @@ module Prism
translate(Prism.parse_file(filepath, partial_script: true), filepath)
end
+ # Parse the give file and translate it into the
+ # seattlerb/ruby_parser gem's Sexp format. This method is
+ # provided for API compatibility to RubyParser and takes an
+ # optional +timeout+ argument.
+ def process(ruby, file = "(string)", timeout = nil)
+ Timeout.timeout(timeout) { parse(ruby, file) }
+ end
+
class << self
# Parse the given source and translate it into the seattlerb/ruby_parser
# gem's Sexp format.
@@ -1639,6 +1668,7 @@ module Prism
raise ::RubyParser::SyntaxError, "#{filepath}:#{error.location.start_line} :: #{error.message}"
end
+ result.attach_comments!
result.value.accept(Compiler.new(filepath))
end
end
diff --git a/lib/resolv.gemspec b/lib/resolv.gemspec
index bfa2f9ff31..66aed34e01 100644
--- a/lib/resolv.gemspec
+++ b/lib/resolv.gemspec
@@ -21,9 +21,8 @@ Gem::Specification.new do |spec|
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`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
+ excludes = %W[/.git* /bin /test /*file /#{File.basename(__FILE__)}]
+ spec.files = IO.popen(%W[git -C #{__dir__} ls-files -z --] + excludes.map {|e| ":^#{e}"}, &:read).split("\x0")
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 42a41d2527..6b58f92813 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -4,6 +4,7 @@ require 'socket'
require 'timeout'
require 'io/wait'
require 'securerandom'
+require 'rbconfig'
# Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can
# handle multiple DNS requests concurrently without blocking the entire Ruby
@@ -33,7 +34,8 @@ require 'securerandom'
class Resolv
- VERSION = "0.6.0"
+ # The version string
+ VERSION = "0.7.1"
##
# Looks up the first IP address for +name+.
@@ -173,21 +175,19 @@ class Resolv
class ResolvTimeout < Timeout::Error; end
- WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
- private_constant :WINDOWS
-
##
# Resolv::Hosts is a hostname resolver that uses the system hosts file.
class Hosts
- if WINDOWS
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
begin
require 'win32/resolv' unless defined?(Win32::Resolv)
- DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
+ hosts = Win32::Resolv.get_hosts_path || IO::NULL
rescue LoadError
end
end
- DefaultFileName ||= '/etc/hosts'
+ # The default file name for host names
+ DefaultFileName = hosts || '/etc/hosts'
##
# Creates a new Resolv::Hosts, using +filename+ for its data source.
@@ -487,13 +487,18 @@ class Resolv
# * Resolv::DNS::Resource::IN::A
# * Resolv::DNS::Resource::IN::AAAA
# * Resolv::DNS::Resource::IN::ANY
+ # * Resolv::DNS::Resource::IN::CAA
# * Resolv::DNS::Resource::IN::CNAME
# * Resolv::DNS::Resource::IN::HINFO
+ # * Resolv::DNS::Resource::IN::HTTPS
+ # * Resolv::DNS::Resource::IN::LOC
# * Resolv::DNS::Resource::IN::MINFO
# * Resolv::DNS::Resource::IN::MX
# * Resolv::DNS::Resource::IN::NS
# * Resolv::DNS::Resource::IN::PTR
# * Resolv::DNS::Resource::IN::SOA
+ # * Resolv::DNS::Resource::IN::SRV
+ # * Resolv::DNS::Resource::IN::SVCB
# * Resolv::DNS::Resource::IN::TXT
# * Resolv::DNS::Resource::IN::WKS
#
@@ -525,6 +530,8 @@ class Resolv
}
end
+ # :stopdoc:
+
def fetch_resource(name, typeclass)
lazy_initialize
truncated = {}
@@ -719,7 +726,8 @@ class Resolv
begin
reply, from = recv_reply(select_result[0])
rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
- Errno::ECONNRESET # Windows
+ Errno::ECONNRESET, # Windows
+ EOFError
# No name server running on the server?
# Don't wait anymore.
raise ResolvTimeout
@@ -928,8 +936,11 @@ class Resolv
end
def recv_reply(readable_socks)
- len = readable_socks[0].read(2).unpack('n')[0]
+ len_data = readable_socks[0].read(2)
+ raise EOFError if len_data.nil? || len_data.bytesize != 2
+ len = len_data.unpack('n')[0]
reply = @socks[0].read(len)
+ raise EOFError if reply.nil? || reply.bytesize != len
return reply, nil
end
@@ -998,13 +1009,13 @@ class Resolv
next unless keyword
case keyword
when 'nameserver'
- nameserver.concat(args)
+ nameserver.concat(args.each(&:freeze))
when 'domain'
next if args.empty?
- search = [args[0]]
+ search = [args[0].freeze]
when 'search'
next if args.empty?
- search = args
+ search = args.each(&:freeze)
when 'options'
args.each {|arg|
case arg
@@ -1015,22 +1026,21 @@ class Resolv
end
}
}
- return { :nameserver => nameserver, :search => search, :ndots => ndots }
+ return { :nameserver => nameserver.freeze, :search => search.freeze, :ndots => ndots.freeze }.freeze
end
def Config.default_config_hash(filename="/etc/resolv.conf")
if File.exist? filename
- config_hash = Config.parse_resolv_conf(filename)
+ Config.parse_resolv_conf(filename)
+ elsif defined?(Win32::Resolv)
+ search, nameserver = Win32::Resolv.get_resolv_info
+ config_hash = {}
+ config_hash[:nameserver] = nameserver if nameserver
+ config_hash[:search] = [search].flatten if search
+ config_hash
else
- if WINDOWS
- require 'win32/resolv' unless defined?(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
@@ -1679,6 +1689,7 @@ class Resolv
prev_index = @index
save_index = nil
d = []
+ size = -1
while true
raise DecodeError.new("limit exceeded") if @limit <= @index
case @data.getbyte(@index)
@@ -1699,7 +1710,10 @@ class Resolv
end
@index = idx
else
- d << self.get_label
+ l = self.get_label
+ d << l
+ size += 1 + l.string.bytesize
+ raise DecodeError.new("name label data exceed 255 octets") if size > 255
end
end
end
@@ -2125,7 +2139,14 @@ class Resolv
attr_reader :ttl
- ClassHash = {} # :nodoc:
+ ClassHash = Module.new do
+ module_function
+
+ def []=(type_class_value, klass)
+ type_value, class_value = type_class_value
+ Resource.const_set(:"Type#{type_value}_Class#{class_value}", klass)
+ end
+ end
def encode_rdata(msg) # :nodoc:
raise NotImplementedError.new
@@ -2163,7 +2184,9 @@ class Resolv
end
def self.get_class(type_value, class_value) # :nodoc:
- return ClassHash[[type_value, class_value]] ||
+ cache = :"Type#{type_value}_Class#{class_value}"
+
+ return (const_defined?(cache) && const_get(cache)) ||
Generic.create(type_value, class_value)
end
@@ -2592,7 +2615,7 @@ class Resolv
end
##
- # Flags for this proprty:
+ # Flags for this property:
# - Bit 0 : 0 = not critical, 1 = critical
attr_reader :flags
@@ -2913,15 +2936,21 @@ class Resolv
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
+ |[3-9][0-9]?/x # :nodoc:
+
+ ##
+ # Regular expression IPv4 addresses must match.
Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
+ ##
+ # Creates a new IPv4 address from +arg+ which may be:
+ #
+ # IPv4:: returns +arg+.
+ # String:: +arg+ must match the IPv4::Regex constant
+
def self.create(arg)
case arg
when IPv4
@@ -3230,14 +3259,16 @@ class Resolv
end
- module LOC
+ module LOC # :nodoc:
##
# A Resolv::LOC::Size
class Size
- Regex = /^(\d+\.*\d*)[m]$/
+ # Regular expression LOC size must match.
+
+ Regex = /\A0*(\d{1,8}(?:\.\d+)?)m\z/
##
# Creates a new LOC::Size from +arg+ which may be:
@@ -3250,18 +3281,20 @@ class Resolv
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
+ unless Regex =~ arg
raise ArgumentError.new("not a properly formed Size string: " + arg)
end
- return Size.new(scalar)
+ unless (0.0...1e8) === (scalar = $1.to_f)
+ raise ArgumentError.new("out of range as Size: #{arg}")
+ end
+ str = (scalar * 100).to_i.to_s
+ return new([(str[0].to_i << 4) + (str.bytesize-1)].pack("C"))
else
raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
end
end
+ # Internal use; use self.create.
def initialize(scalar)
@scalar = scalar
end
@@ -3272,8 +3305,8 @@ class Resolv
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"
+ s, = @scalar.unpack("C")
+ return "#{(s >> 4) * (10.0 ** ((s & 0xf) - 2))}m"
end
def inspect # :nodoc:
@@ -3299,7 +3332,12 @@ class Resolv
class Coord
- Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
+ # Regular expression LOC Coord must match.
+
+ Regex = /\A0*(\d{1,3})\s([0-5]?\d)\s([0-5]?\d(?:\.\d+)?)\s([NESW])\z/
+
+ # Bias for the equator/prime meridian, in thousandths of a second of arc.
+ Bias = 1 << 31
##
# Creates a new LOC::Coord from +arg+ which may be:
@@ -3312,27 +3350,30 @@ class Resolv
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
+ unless m = Regex.match(arg)
raise ArgumentError.new("not a properly formed Coord string: " + arg)
end
- return Coord.new(coordinates,orientation)
+
+ arc = (m[1].to_i * 3_600_000) + (m[2].to_i * 60_000) + (m[3].to_f * 1_000).to_i
+ dir = m[4]
+ lat = dir[/[NS]/]
+ unless arc <= (lat ? 324_000_000 : 648_000_000) # (lat ? 90 : 180) * 3_600_000
+ raise ArgumentError.new("out of range as Coord: #{arg}")
+ end
+
+ hemi = dir[/[NE]/] ? 1 : -1
+ return new([arc * hemi + Bias].pack("N"), lat ? "lat" : "lon")
else
raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
end
end
+ # Internal use; use self.create.
def initialize(coordinates,orientation)
- unless coordinates.kind_of?(String)
+ unless coordinates.kind_of?(String) and coordinates.bytesize == 4
raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
end
- unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/]
+ unless orientation == "lon" || orientation == "lat"
raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
end
@coordinates = coordinates
@@ -3349,22 +3390,17 @@ class Resolv
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"
+ c, = @coordinates.unpack("N")
+ val = (c -= Bias).abs
+ val, fracsecs = val.divmod(1000)
+ val, secs = val.divmod(60)
+ degs, mins = val.divmod(60)
+ hemi = if c.negative?
+ @orientation == "lon" ? "W" : "S"
else
- hemi = @orientation[/^lon$/] ? "W" : "S"
+ @orientation == "lat" ? "N" : "E"
end
- return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi
+ format("%d %02d %02d.%03d %s", degs, mins, secs, fracsecs, hemi)
end
def inspect # :nodoc:
@@ -3390,7 +3426,12 @@ class Resolv
class Alt
- Regex = /^([+-]*\d+\.*\d*)[m]$/
+ # Regular expression LOC Alt must match.
+
+ Regex = /\A([+-]?0*\d{1,8}(?:\.\d+)?)m\z/
+
+ # Bias to a base of 100,000m below the WGS 84 reference spheroid.
+ Bias = 100_000_00
##
# Creates a new LOC::Alt from +arg+ which may be:
@@ -3403,18 +3444,20 @@ class Resolv
when Alt
return arg
when String
- altitude = ''
- if Regex =~ arg
- altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
- else
+ unless Regex =~ arg
raise ArgumentError.new("not a properly formed Alt string: " + arg)
end
- return Alt.new(altitude)
+ altitude = ($1.to_f * 100).to_i + Bias
+ unless (0...0x1_0000_0000) === altitude
+ raise ArgumentError.new("out of raise as Alt: #{arg}")
+ end
+ return new([altitude].pack("N"))
else
raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
end
end
+ # Internal use; use self.create.
def initialize(altitude)
@altitude = altitude
end
@@ -3425,8 +3468,8 @@ class Resolv
attr_reader :altitude
def to_s # :nodoc:
- a = @altitude.unpack("N").join.to_i
- return ((a.to_f/1e2)-1e5).to_s + "m"
+ a, = @altitude.unpack("N")
+ return "#{(a - Bias).fdiv(100)}m"
end
def inspect # :nodoc:
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 1225cbe5cb..d289cab0fd 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -9,16 +9,15 @@
require "rbconfig"
module Gem
- VERSION = "3.7.0.dev"
+ VERSION = "4.1.0.dev"
end
-# Must be first since it unloads the prelude from 1.9.2
-require_relative "rubygems/compatibility"
-
require_relative "rubygems/defaults"
require_relative "rubygems/deprecate"
require_relative "rubygems/errors"
require_relative "rubygems/target_rbconfig"
+require_relative "rubygems/win_platform"
+require_relative "rubygems/util/atomic_file_writer"
##
# RubyGems is the Ruby standard for publishing and managing third party
@@ -39,7 +38,7 @@ require_relative "rubygems/target_rbconfig"
# Further RubyGems documentation can be found at:
#
# * {RubyGems Guides}[https://guides.rubygems.org]
-# * {RubyGems API}[https://www.rubydoc.info/github/rubygems/rubygems] (also available from
+# * {RubyGems API}[https://guides.rubygems.org/rubygems-org-api/] (also available from
# <tt>gem server</tt>)
#
# == RubyGems Plugins
@@ -71,7 +70,7 @@ require_relative "rubygems/target_rbconfig"
# == Bugs
#
# You can submit bugs to the
-# {RubyGems bug tracker}[https://github.com/rubygems/rubygems/issues]
+# {RubyGems bug tracker}[https://github.com/ruby/rubygems/issues]
# on GitHub
#
# == Credits
@@ -107,7 +106,7 @@ require_relative "rubygems/target_rbconfig"
#
# == License
#
-# See {LICENSE.txt}[https://github.com/rubygems/rubygems/blob/master/LICENSE.txt] for permissions.
+# See {LICENSE.txt}[https://github.com/ruby/rubygems/blob/master/LICENSE.txt] for permissions.
#
# Thanks!
#
@@ -116,18 +115,6 @@ require_relative "rubygems/target_rbconfig"
module Gem
RUBYGEMS_DIR = __dir__
- ##
- # An Array of Regexps that match windows Ruby platforms.
-
- WIN_PATTERNS = [
- /bccwin/i,
- /cygwin/i,
- /djgpp/i,
- /mingw/i,
- /mswin/i,
- /wince/i,
- ].freeze
-
GEM_DEP_FILES = %w[
gem.deps.rb
gems.rb
@@ -163,8 +150,6 @@ module Gem
DEFAULT_SOURCE_DATE_EPOCH = 315_619_200
- @@win_platform = nil
-
@configuration = nil
@gemdeps = nil
@loaded_specs = {}
@@ -208,11 +193,13 @@ module Gem
begin
spec.activate
rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax
- spec_by_name = Gem::Specification.find_by_name(spec.name)
- if spec_by_name.nil?
+ name = spec.name
+ spec = Gem::Specification.find_unloaded_by_path(path)
+ spec ||= Gem::Specification.find_by_name(name)
+ if spec.nil?
raise e
else
- spec_by_name.activate
+ spec.activate
end
end
@@ -227,7 +214,7 @@ module Gem
finish_resolve rs
end
- def self.finish_resolve(request_set=Gem::RequestSet.new)
+ def self.finish_resolve(request_set = Gem::RequestSet.new)
request_set.import Gem::Specification.unresolved_deps.values
request_set.import Gem.loaded_specs.values.map {|s| Gem::Dependency.new(s.name, s.version) }
@@ -249,6 +236,16 @@ module Gem
find_spec_for_exe(name, exec_name, requirements).bin_file exec_name
end
+ def self.find_and_activate_spec_for_exe(name, exec_name, requirements)
+ spec = find_spec_for_exe name, exec_name, requirements
+ Gem::LOADED_SPECS_MUTEX.synchronize do
+ spec.activate
+ finish_resolve
+ end
+ spec
+ end
+ private_class_method :find_and_activate_spec_for_exe
+
def self.find_spec_for_exe(name, exec_name, requirements)
raise ArgumentError, "you must supply exec_name" unless exec_name
@@ -274,6 +271,42 @@ module Gem
private_class_method :find_spec_for_exe
##
+ # Find and load the full path to the executable for gem +name+. If the
+ # +exec_name+ is not given, an exception will be raised, otherwise the
+ # specified executable's path is returned. +requirements+ allows
+ # you to specify specific gem versions.
+ #
+ # A side effect of this method is that it will activate the gem that
+ # contains the executable.
+ #
+ # This method should *only* be used in bin stub files.
+
+ def self.activate_and_load_bin_path(name, exec_name = nil, *requirements)
+ spec = find_and_activate_spec_for_exe name, exec_name, requirements
+
+ if spec.name == "bundler"
+ # Old versions of Bundler need a workaround to support nested `bundle
+ # exec` invocations by overriding `Gem.activate_bin_path`. However,
+ # RubyGems now uses this new `Gem.activate_and_load_bin_path` helper in
+ # binstubs, which is of course not overridden in Bundler since it didn't
+ # exist at the time. So, include the override here to workaround that.
+ load ENV["BUNDLE_BIN_PATH"] if ENV["BUNDLE_BIN_PATH"] && spec.version <= Gem::Version.create("2.5.22")
+
+ # Make sure there's no version of Bundler in `$LOAD_PATH` that's different
+ # from the version we just activated. If that was the case (it happens
+ # when testing Bundler from ruby/ruby), we would load Bundler extensions
+ # to RubyGems from the copy in `$LOAD_PATH` but then load the binstub from
+ # an installed copy, causing those copies to be mixed and yet more
+ # redefinition warnings.
+ #
+ require_path = $LOAD_PATH.resolve_feature_path("bundler").last.delete_suffix("/bundler.rb")
+ Gem.load_bundler_extensions(spec.version) if spec.full_require_paths.include?(require_path)
+ end
+
+ load spec.bin_file(exec_name)
+ end
+
+ ##
# Find the full path to the executable for gem +name+. If the +exec_name+
# is not given, an exception will be raised, otherwise the
# specified executable's path is returned. +requirements+ allows
@@ -285,12 +318,7 @@ module Gem
# This method should *only* be used in bin stub files.
def self.activate_bin_path(name, exec_name = nil, *requirements) # :nodoc:
- spec = find_spec_for_exe name, exec_name, requirements
- Gem::LOADED_SPECS_MUTEX.synchronize do
- spec.activate
- finish_resolve
- end
- spec.bin_file exec_name
+ find_and_activate_spec_for_exe(name, exec_name, requirements).bin_file exec_name
end
##
@@ -303,7 +331,7 @@ module Gem
##
# The path where gem executables are to be installed.
- def self.bindir(install_dir=Gem.dir)
+ def self.bindir(install_dir = Gem.dir)
return File.join install_dir, "bin" unless
install_dir.to_s == Gem.default_dir.to_s
Gem.default_bindir
@@ -312,7 +340,7 @@ module Gem
##
# The path were rubygems plugins are to be installed.
- def self.plugindir(install_dir=Gem.dir)
+ def self.plugindir(install_dir = Gem.dir)
File.join install_dir, "plugins"
end
@@ -324,6 +352,8 @@ module Gem
def self.clear_paths
@paths = nil
@user_home = nil
+ @cache_home = nil
+ @data_home = nil
Gem::Specification.reset
Gem::Security.reset if defined?(Gem::Security)
end
@@ -496,7 +526,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Note that find_files will return all files even if they are from different
# versions of the same gem. See also find_latest_files
- def self.find_files(glob, check_load_path=true)
+ def self.find_files(glob, check_load_path = true)
files = []
files = find_files_from_load_path glob if check_load_path
@@ -533,7 +563,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Unlike find_files, find_latest_files will return only files from the
# latest version of a gem.
- def self.find_latest_files(glob, check_load_path=true)
+ def self.find_latest_files(glob, check_load_path = true)
files = []
files = find_files_from_load_path glob if check_load_path
@@ -611,6 +641,14 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
@yaml_loaded = false
+ @use_psych = nil
+
+ ##
+ # Returns true if the Psych YAML parser is enabled via configuration.
+
+ def self.use_psych?
+ @use_psych || false
+ end
##
# Loads YAML, preferring Psych
@@ -618,9 +656,15 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.load_yaml
return if @yaml_loaded
- require "psych"
- require_relative "rubygems/psych_tree"
+ @use_psych = ENV["RUBYGEMS_USE_PSYCH"] == "true" ||
+ (defined?(@configuration) && @configuration && !@configuration[:use_psych].nil?)
+
+ if @use_psych
+ require "psych"
+ require_relative "rubygems/psych_tree"
+ end
+ require_relative "rubygems/yaml_serializer"
require_relative "rubygems/safe_yaml"
@yaml_loaded = true
@@ -637,6 +681,30 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
+ # Load Bundler extensions to RubyGems, making sure to avoid redefinition
+ # warnings in platform constants
+
+ def self.load_bundler_extensions(version)
+ return unless version <= Gem::Version.create("2.6.9")
+
+ previous_platforms = {}
+
+ platform_const_list = ["JAVA", "MSWIN", "MSWIN64", "MINGW", "X64_MINGW_LEGACY", "X64_MINGW", "UNIVERSAL_MINGW", "WINDOWS", "X64_LINUX", "X64_LINUX_MUSL"]
+
+ platform_const_list.each do |platform|
+ previous_platforms[platform] = Gem::Platform.const_get(platform)
+ Gem::Platform.send(:remove_const, platform)
+ end
+
+ require "bundler/rubygems_ext"
+
+ platform_const_list.each do |platform|
+ Gem::Platform.send(:remove_const, platform) if Gem::Platform.const_defined?(platform)
+ Gem::Platform.const_set(platform, previous_platforms[platform])
+ end
+ end
+
+ ##
# The file name and line number of the caller of the caller of this method.
#
# +depth+ is how many layers up the call stack it should go.
@@ -784,14 +852,12 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Safely write a file in binary mode on all platforms.
+ # Atomically write a file in binary mode on all platforms.
def self.write_binary(path, data)
- File.binwrite(path, data)
- 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)
- raise
+ Gem::AtomicFileWriter.open(path) do |file|
+ file.write(data)
+ end
end
##
@@ -1030,18 +1096,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Is this a windows platform?
-
- def self.win_platform?
- if @@win_platform.nil?
- ruby_platform = RbConfig::CONFIG["host_os"]
- @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
- end
-
- @@win_platform
- end
-
- ##
# Is this a java platform?
def self.java_platform?
@@ -1246,10 +1300,17 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
prefix_pattern = /^(#{prefix_group})/
end
+ native_extension_suffixes = Gem.dynamic_library_suffixes.reject(&:empty?)
+
spec.files.each do |file|
if new_format
file = file.sub(prefix_pattern, "")
- next unless $~
+ unless $~
+ # Also register native extension files (e.g. date_core.bundle)
+ # that are listed without require path prefix in the gemspec
+ next if file.include?("/")
+ next unless file.end_with?(*native_extension_suffixes)
+ end
end
spec.activate if already_loaded?(file)
@@ -1373,9 +1434,7 @@ require_relative "rubygems/specification"
# REFACTOR: This should be pulled out into some kind of hacks file.
begin
- ##
# Defaults the operating system (or packager) wants to provide for RubyGems.
-
require "rubygems/defaults/operating_system"
rescue LoadError
# Ignored
@@ -1390,9 +1449,7 @@ rescue StandardError => e
end
begin
- ##
# Defaults the Ruby implementation wants to provide for RubyGems
-
require "rubygems/defaults/#{RUBY_ENGINE}"
rescue LoadError
end
diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb
index a09e8ed0e1..0ed7fc60bb 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -34,15 +34,6 @@ class Gem::BasicSpecification
internal_init
end
- def self.default_specifications_dir
- Gem.default_specifications_dir
- end
-
- class << self
- extend Gem::Deprecate
- rubygems_deprecate :default_specifications_dir, "Gem.default_specifications_dir"
- end
-
##
# The path to the gem.build_complete file within the extension install
# directory.
@@ -199,6 +190,9 @@ class Gem::BasicSpecification
File.expand_path(File.join(gems_dir, full_name, "data", name))
end
+ extend Gem::Deprecate
+ rubygems_deprecate :datadir, :none, "4.1"
+
##
# Full path of the target library file.
# If the file is not in this gem, return nil.
@@ -256,6 +250,13 @@ class Gem::BasicSpecification
raise NotImplementedError
end
+ def installable_on_platform?(target_platform) # :nodoc:
+ return true if [Gem::Platform::RUBY, nil, target_platform].include?(platform)
+ return true if Gem::Platform.new(platform) === target_platform
+
+ false
+ end
+
def raw_require_paths # :nodoc:
raise NotImplementedError
end
diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb
index 4ebbad1c0c..bbe7bf0ab5 100644
--- a/lib/rubygems/bundler_version_finder.rb
+++ b/lib/rubygems/bundler_version_finder.rb
@@ -2,11 +2,17 @@
module Gem::BundlerVersionFinder
def self.bundler_version
+ bcv = bundle_config_version
+ return if bcv == "system"
+
v = ENV["BUNDLER_VERSION"]
+ v = nil if v&.empty?
v ||= bundle_update_bundler_version
return if v == true
+ v ||= bcv unless bcv == "lockfile"
+
v ||= lockfile_version
return unless v
@@ -46,6 +52,67 @@ module Gem::BundlerVersionFinder
private_class_method :lockfile_version
def self.lockfile_contents
+ gemfile = gemfile_path
+
+ return unless gemfile
+
+ lockfile = ENV["BUNDLE_LOCKFILE"]
+ lockfile = nil if lockfile&.empty?
+
+ lockfile ||= case gemfile
+ when "gems.rb" then "gems.locked"
+ else "#{gemfile}.lock"
+ end
+
+ return unless File.file?(lockfile)
+
+ File.read(lockfile)
+ end
+ private_class_method :lockfile_contents
+
+ def self.bundle_config_version
+ env_version = ENV["BUNDLE_VERSION"]
+ return env_version if env_version && !env_version.empty?
+
+ version = nil
+
+ [bundler_local_config_file, bundler_global_config_file].each do |config_file|
+ next unless config_file && File.file?(config_file)
+
+ contents = File.read(config_file)
+ contents =~ /^BUNDLE_VERSION:\s*["']?([^"'\s]+)["']?\s*$/
+
+ version = $1
+ break if version
+ end
+
+ version
+ end
+ private_class_method :bundle_config_version
+
+ def self.bundler_global_config_file
+ # see Bundler::Settings#global_config_file
+ if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty?
+ ENV["BUNDLE_CONFIG"]
+ elsif ENV["BUNDLE_USER_CONFIG"] && !ENV["BUNDLE_USER_CONFIG"].empty?
+ ENV["BUNDLE_USER_CONFIG"]
+ elsif ENV["BUNDLE_USER_HOME"] && !ENV["BUNDLE_USER_HOME"].empty?
+ ENV["BUNDLE_USER_HOME"] + "config"
+ elsif Gem.user_home && !Gem.user_home.empty?
+ Gem.user_home + ".bundle/config"
+ end
+ end
+ private_class_method :bundler_global_config_file
+
+ def self.bundler_local_config_file
+ gemfile = gemfile_path
+ return unless gemfile
+
+ File.join(File.dirname(gemfile), ".bundle", "config")
+ end
+ private_class_method :bundler_local_config_file
+
+ def self.gemfile_path
gemfile = ENV["BUNDLE_GEMFILE"]
gemfile = nil if gemfile&.empty?
@@ -62,16 +129,7 @@ module Gem::BundlerVersionFinder
end
end
- return unless gemfile
-
- lockfile = case gemfile
- when "gems.rb" then "gems.locked"
- else "#{gemfile}.lock"
- end
-
- return unless File.file?(lockfile)
-
- File.read(lockfile)
+ gemfile
end
- private_class_method :lockfile_contents
+ private_class_method :gemfile_path
end
diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb
index 3a149ea38e..d38363f293 100644
--- a/lib/rubygems/command.rb
+++ b/lib/rubygems/command.rb
@@ -117,7 +117,7 @@ class Gem::Command
# Unhandled arguments (gem names, files, etc.) are left in
# <tt>options[:args]</tt>.
- def initialize(command, summary=nil, defaults={})
+ def initialize(command, summary = nil, defaults = {})
@command = command
@summary = summary
@program_name = "gem #{command}"
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index 15834ce4dd..76b2fba835 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -58,7 +58,6 @@ class Gem::CommandManager
:owner,
:pristine,
:push,
- :query,
:rdoc,
:rebuild,
:search,
@@ -118,7 +117,7 @@ class Gem::CommandManager
##
# Register the Symbol +command+ as a gem command.
- def register_command(command, obj=false)
+ def register_command(command, obj = false)
@commands[command] = obj
end
@@ -148,7 +147,7 @@ class Gem::CommandManager
##
# Run the command specified by +args+.
- def run(args, build_args=nil)
+ def run(args, build_args = nil)
process_args(args, build_args)
rescue StandardError, Gem::Timeout::Error => ex
if ex.respond_to?(:detailed_message)
@@ -165,7 +164,7 @@ class Gem::CommandManager
terminate_interaction(1)
end
- def process_args(args, build_args=nil)
+ def process_args(args, build_args = nil)
if args.empty?
say Gem::Command::HELP
terminate_interaction 1
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb
index 2ec8324141..cfe1f8ec3c 100644
--- a/lib/rubygems/commands/build_command.rb
+++ b/lib/rubygems/commands/build_command.rb
@@ -25,13 +25,6 @@ class Gem::Commands::BuildCommand < Gem::Command
add_option "-o", "--output FILE", "output gem with the given filename" do |value, options|
options[:output] = 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
- deprecate_option "-C",
- version: "4.0",
- extra_msg: "-C is a global flag now. Use `gem -C PATH build GEMSPEC_FILE [options]` instead"
end
def arguments # :nodoc:
diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb
index 72dcf1dd17..fe03841ddb 100644
--- a/lib/rubygems/commands/cert_command.rb
+++ b/lib/rubygems/commands/cert_command.rb
@@ -158,7 +158,7 @@ class Gem::Commands::CertCommand < Gem::Command
cert = Gem::Security.create_cert_email(
email,
key,
- (Gem::Security::ONE_DAY * expiration_length_days)
+ Gem::Security::ONE_DAY * expiration_length_days
)
Gem::Security.write cert, "gem-public_cert.pem"
diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb
index aea8c0d7de..a5eb521a53 100644
--- a/lib/rubygems/commands/environment_command.rb
+++ b/lib/rubygems/commands/environment_command.rb
@@ -38,6 +38,7 @@ keys:
:verbose: Verbosity of the gem command. false, true, and :really are the
levels
:update_sources: Enable/disable automatic updating of repository metadata
+ :concurrent_downloads: The number of gem downloads to perform concurrently
:backtrace: Print backtrace when RubyGems encounters an error
:gempath: The paths in which to look for gems
:disable_default_gem_server: Force specification of gem server host on push
diff --git a/lib/rubygems/commands/exec_command.rb b/lib/rubygems/commands/exec_command.rb
index c24ebbf711..1feafbdd35 100644
--- a/lib/rubygems/commands/exec_command.rb
+++ b/lib/rubygems/commands/exec_command.rb
@@ -173,6 +173,9 @@ to the same gem path as user-installed gems.
rescue Gem::InstallError => e
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
terminate_interaction 1
+ rescue Gem::DependencyResolutionError => e
+ alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+ terminate_interaction 2
rescue Gem::GemNotFoundException => e
show_lookup_failure e.name, e.version, e.errors, false
diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb
index c524cf7922..8e64a18cee 100644
--- a/lib/rubygems/commands/fetch_command.rb
+++ b/lib/rubygems/commands/fetch_command.rb
@@ -56,7 +56,7 @@ then repackaging it.
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem fetch 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem fetch 'my_gem:1.0.0' 'my_other_gem:>=2'`"
terminate_interaction 1
end
end
diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb
index 1619b152e7..664f400561 100644
--- a/lib/rubygems/commands/help_command.rb
+++ b/lib/rubygems/commands/help_command.rb
@@ -90,7 +90,9 @@ Use #gem to declare which gems you directly depend upon:
To depend on a specific set of versions:
- gem 'rake', '~> 10.3', '>= 10.3.2'
+ gem 'rake', '>= 10.3.2'
+ # or for multiple version restrictions
+ gem 'rake', '>= 10.3.2', "< 13"
RubyGems will require the gem name when activating the gem using
the RUBYGEMS_GEMDEPS environment variable or Gem::use_gemdeps. Use the
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 2888b6c55a..6d3beec0b4 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -140,7 +140,7 @@ You can use `i` command instead of `install`.
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:>=2'`"
terminate_interaction 1
end
end
@@ -224,6 +224,9 @@ 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::DependencyResolutionError => e
+ alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+ exit_code |= 2
rescue Gem::UnsatisfiableDependencyError => e
show_lookup_failure e.name, e.version, e.errors, suppress_suggestions,
"'#{gem_name}' (#{gem_version})"
@@ -239,11 +242,7 @@ You can use `i` command instead of `install`.
# Loads post-install hooks
def load_hooks # :nodoc:
- if options[:install_as_default]
- require_relative "../install_default_message"
- else
- require_relative "../install_message"
- end
+ require_relative "../install_message"
require_relative "../rdoc"
end
diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index 12bfe3a834..675e866734 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -75,11 +75,12 @@ permission to.
end
with_response response do |resp|
- owners = Gem::SafeYAML.load clean_text(resp.body)
+ owners = Gem::SafeYAML.safe_load clean_text(resp.body)
say "Owners for gem: #{name}"
owners.each do |owner|
- say "- #{owner["email"] || owner["handle"] || owner["id"]}"
+ identifier = owner["email"] || owner["handle"] || owner["id"]
+ say "- #{identifier} (#{owner["role"]})"
end
end
end
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 97f1646ba0..10978c2af7 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -88,6 +88,10 @@ If you have made modifications to an installed gem, the pristine command
will revert them. All extensions are rebuilt and all bin stubs for the gem
are regenerated after checking for modifications.
+Rebuilding extensions also refreshes C-extension gems against updated system
+libraries (for example after OS or package upgrades) to avoid mismatches like
+outdated library version warnings.
+
If the cached gem cannot be found it will be downloaded.
If --no-extensions is provided pristine will not attempt to restore a gem
@@ -128,6 +132,11 @@ extensions will be restored.
specs = specs.select {|spec| spec.platform == RUBY_ENGINE || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
if specs.to_a.empty?
+ if options[:only_missing_extensions]
+ say "No gems with missing extensions to restore"
+ return
+ end
+
raise Gem::Exception,
"Failed to find gems #{options[:args]} #{options[:version]}"
end
@@ -137,11 +146,14 @@ extensions will be restored.
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?
+ only_executables = options[:only_executables]
+ only_plugins = options[:only_plugins]
+
+ unless only_executables || only_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?
+ only_executables = true if spec.default_gem?
end
if options.key? :skip
@@ -151,14 +163,14 @@ extensions will be restored.
end
end
- unless spec.extensions.empty? || options[:extensions] || only_executables_or_plugins?
+ unless spec.extensions.empty? || options[:extensions] || only_executables || only_plugins
say "Skipped #{spec.full_name_with_location}, it needs to compile an extension"
next
end
gem = spec.cache_file
- unless File.exist?(gem) || only_executables_or_plugins?
+ unless File.exist?(gem) || only_executables || only_plugins
require_relative "../remote_fetcher"
say "Cached gem for #{spec.full_name_with_location} not found, attempting to fetch..."
@@ -194,10 +206,10 @@ extensions will be restored.
bin_dir: bin_dir,
}
- if options[:only_executables]
+ if only_executables
installer = Gem::Installer.for_spec(spec, installer_options)
installer.generate_bin
- elsif options[:only_plugins]
+ elsif only_plugins
installer = Gem::Installer.for_spec(spec, installer_options)
installer.generate_plugins
else
@@ -208,10 +220,4 @@ extensions will be restored.
say "Restored #{spec.full_name_with_location}"
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 726191377a..02931b3025 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -92,20 +92,77 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
private
def send_push_request(name, args)
- rubygems_api_request(*args, scope: get_push_scope) do |request|
+ # Always honor explicit --attestation option
+ # Auto-attestation is only supported on rubygems.org with GitHub Actions (not JRuby)
+ if options[:attestations].any? || (RUBY_ENGINE != "jruby" && attestation_supported_host? && ENV["GITHUB_ACTIONS"])
+ send_push_request_with_attestation(name, args)
+ else
+ send_push_request_without_attestation(name, args)
+ end
+ end
+
+ def send_push_request_without_attestation(name, args)
+ scope = get_push_scope
+ rubygems_api_request(*args, scope: scope) do |request|
body = Gem.read_binary name
- if options[:attestations].any?
- request.set_form([
- ["gem", body, { filename: name, content_type: "application/octet-stream" }],
- get_attestations_part,
- ], "multipart/form-data")
- else
- request.body = body
- request.add_field "Content-Type", "application/octet-stream"
- request.add_field "Content-Length", request.body.size
+ request.body = body
+ request.add_field "Content-Type", "application/octet-stream"
+ request.add_field "Content-Length", request.body.size
+ request.add_field "Authorization", api_key
+ end
+ end
+
+ def send_push_request_with_attestation(name, args)
+ attestations = if options[:attestations].any?
+ options[:attestations].map do |attestation|
+ Gem.read_binary(attestation)
end
+ else
+ bundle_path = attest!(name)
+ begin
+ [Gem.read_binary(bundle_path)]
+ ensure
+ File.unlink(bundle_path) if bundle_path && File.exist?(bundle_path)
+ end
+ end
+ bundles = "[" + attestations.join(",") + "]"
+
+ rubygems_api_request(*args, scope: get_push_scope) do |request|
+ request.set_form([
+ ["gem", Gem.read_binary(name), { filename: name, content_type: "application/octet-stream" }],
+ ["attestations", bundles, { content_type: "application/json" }],
+ ], "multipart/form-data")
request.add_field "Authorization", api_key
end
+ rescue StandardError => e
+ message = "Failed to push with attestation, retrying without attestation.\n"
+ message += if Gem.configuration.really_verbose
+ e.full_message
+ else
+ e.message
+ end
+ alert_warning message
+ send_push_request_without_attestation(name, args)
+ end
+
+ def attest!(name)
+ require "open3"
+ require "tempfile"
+
+ tempfile = Tempfile.new([File.basename(name, ".*"), ".sigstore.json"])
+ bundle = tempfile.path
+ tempfile.close(false)
+
+ env = defined?(Bundler.unbundled_env) ? Bundler.unbundled_env : ENV.to_h
+ out, st = Open3.capture2e(
+ env,
+ Gem.ruby, "-S", "gem", "exec", "--conservative",
+ "sigstore-cli", "sign", name, "--bundle", bundle,
+ unsetenv_others: true
+ )
+ raise Gem::Exception, "Failed to sign gem:\n\n#{out}" unless st.success?
+
+ bundle
end
def get_hosts_for(name)
@@ -121,14 +178,8 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
:push_rubygem
end
- def get_attestations_part
- bundles = "[" + options[:attestations].map do |attestation|
- Gem.read_binary(attestation)
- end.join(",") + "]"
- [
- "attestations",
- bundles,
- { content_type: "application/json" },
- ]
+ def attestation_supported_host?
+ host = (@host || Gem.host).to_s.chomp("/")
+ host == Gem::DEFAULT_HOST
end
end
diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb
deleted file mode 100644
index 3b527974a3..0000000000
--- a/lib/rubygems/commands/query_command.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../command"
-require_relative "../query_utils"
-require_relative "../deprecate"
-
-class Gem::Commands::QueryCommand < Gem::Command
- extend Gem::Deprecate
- rubygems_deprecate_command
-
- include Gem::QueryUtils
-
- alias_method :warning_without_suggested_alternatives, :deprecation_warning
- def deprecation_warning
- warning_without_suggested_alternatives
-
- message = "It is recommended that you use `gem search` or `gem list` instead.\n"
- alert_warning message unless Gem::Deprecate.skip
- end
-
- 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
-
- add_option("-n", "--name-matches REGEXP",
- "Name of gem(s) to query on matches the",
- "provided REGEXP") do |value, options|
- options[:name] = /#{value}/i
- end
-
- add_query_options
- end
-
- def description # :nodoc:
- <<-EOF
-The query command is the basis for the list and search commands.
-
-You should really use the list and search commands instead. This command
-is too hard to use.
- EOF
- end
-end
diff --git a/lib/rubygems/commands/rebuild_command.rb b/lib/rubygems/commands/rebuild_command.rb
index 77a474ef1d..23b9d7b3ba 100644
--- a/lib/rubygems/commands/rebuild_command.rb
+++ b/lib/rubygems/commands/rebuild_command.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "date"
require "digest"
require "fileutils"
require "tmpdir"
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index 301ce25314..175599967c 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -7,8 +7,8 @@ require_relative "../command"
# RubyGems checkout or tarball.
class Gem::Commands::SetupCommand < Gem::Command
- HISTORY_HEADER = %r{^#\s*[\d.a-zA-Z]+\s*/\s*\d{4}-\d{2}-\d{2}\s*$}
- VERSION_MATCHER = %r{^#\s*([\d.a-zA-Z]+)\s*/\s*\d{4}-\d{2}-\d{2}\s*$}
+ 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*$}
ENV_PATHS = %w[/usr/bin/env /bin/env].freeze
@@ -393,16 +393,20 @@ By default, this RubyGems will install gem as:
Dir.chdir("bundler") do
built_gem = Gem::Package.build(new_bundler_spec)
begin
- Gem::Installer.at(
+ installer = Gem::Installer.at(
built_gem,
env_shebang: options[:env_shebang],
format_executable: options[:format_executable],
force: options[:force],
- install_as_default: true,
bin_dir: bin_dir,
install_dir: default_dir,
wrappers: true
- ).install
+ )
+ # We need to install only executable and default spec files.
+ # lib/bundler.rb and lib/bundler/* are available under the site_ruby directory.
+ installer.extract_bin
+ installer.generate_bin
+ installer.write_default_spec
ensure
FileUtils.rm_f built_gem
end
diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb
index 976f4a4ea2..b399af2bd3 100644
--- a/lib/rubygems/commands/sources_command.rb
+++ b/lib/rubygems/commands/sources_command.rb
@@ -18,6 +18,14 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:add] = value
end
+ add_option "--append SOURCE_URI", "Append source (can be used multiple times)" do |value, options|
+ options[:append] = value
+ end
+
+ add_option "-p", "--prepend SOURCE_URI", "Prepend source (can be used multiple times)" do |value, options|
+ options[:prepend] = value
+ end
+
add_option "-l", "--list", "List sources" do |value, options|
options[:list] = value
end
@@ -26,8 +34,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:remove] = value
end
- add_option "-c", "--clear-all",
- "Remove all sources (clear the cache)" do |value, options|
+ add_option "-c", "--clear-all", "Remove all sources (clear the cache)" do |value, options|
options[:clear_all] = value
end
@@ -43,11 +50,8 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
def add_source(source_uri) # :nodoc:
- check_rubygems_https source_uri
-
- source = Gem::Source.new source_uri
-
- check_typo_squatting(source)
+ source = build_new_source(source_uri)
+ source_uri = source.uri.to_s
begin
if Gem.sources.include? source
@@ -68,6 +72,54 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
end
+ def append_source(source_uri) # :nodoc:
+ source = build_new_source(source_uri)
+ source_uri = source.uri.to_s
+
+ begin
+ source.load_specs :released
+ was_present = Gem.sources.include?(source)
+ Gem.sources.append source
+ Gem.configuration.write
+
+ if was_present
+ say "#{source_uri} moved to end of sources"
+ else
+ say "#{source_uri} added to sources"
+ end
+ rescue Gem::URI::Error, ArgumentError
+ say "#{source_uri} is not a URI"
+ terminate_interaction 1
+ rescue Gem::RemoteFetcher::FetchError => e
+ say "Error fetching #{Gem::Uri.redact(source.uri)}:\n\t#{e.message}"
+ terminate_interaction 1
+ end
+ end
+
+ def prepend_source(source_uri) # :nodoc:
+ source = build_new_source(source_uri)
+ source_uri = source.uri.to_s
+
+ begin
+ source.load_specs :released
+ was_present = Gem.sources.include?(source)
+ Gem.sources.prepend source
+ Gem.configuration.write
+
+ if was_present
+ say "#{source_uri} moved to top of sources"
+ else
+ say "#{source_uri} added to sources"
+ end
+ rescue Gem::URI::Error, ArgumentError
+ say "#{source_uri} is not a URI"
+ terminate_interaction 1
+ rescue Gem::RemoteFetcher::FetchError => e
+ say "Error fetching #{Gem::Uri.redact(source.uri)}:\n\t#{e.message}"
+ terminate_interaction 1
+ end
+ end
+
def check_typo_squatting(source)
if source.typo_squatting?("rubygems.org")
question = <<-QUESTION.chomp
@@ -80,6 +132,19 @@ Do you want to add this source?
end
end
+ def normalize_source_uri(source_uri) # :nodoc:
+ # Ensure the source URI has a trailing slash for proper RFC 2396 path merging
+ # Without a trailing slash, the last path segment is treated as a file and removed
+ # during relative path resolution (e.g., "/blish" + "gems/foo.gem" = "/gems/foo.gem")
+ # With a trailing slash, it's treated as a directory (e.g., "/blish/" + "gems/foo.gem" = "/blish/gems/foo.gem")
+ uri = Gem::URI.parse(source_uri)
+ uri.path = uri.path.gsub(%r{/+\z}, "") + "/" if uri.path && !uri.path.empty?
+ uri.to_s
+ rescue Gem::URI::Error
+ # If parsing fails, return the original URI and let later validation handle it
+ source_uri
+ end
+
def check_rubygems_https(source_uri) # :nodoc:
uri = Gem::URI source_uri
@@ -128,7 +193,7 @@ yourself to use your own gem server.
Without any arguments the sources lists your currently configured sources:
$ gem sources
- *** CURRENT SOURCES ***
+ *** NO CONFIGURED SOURCES, DEFAULT SOURCES LISTED BELOW ***
https://rubygems.org
@@ -147,33 +212,49 @@ Since all of these sources point to the same set of gems you only need one
of them in your list. https://rubygems.org is recommended as it brings the
protections of an SSL connection to gem downloads.
-To add a source use the --add argument:
+To add a private gem source use the --prepend argument to insert it before
+the default source. This is usually the best place for private gem sources:
- $ gem sources --add https://rubygems.org
- https://rubygems.org added to sources
+ $ gem sources --prepend https://my.private.source
+ https://my.private.source added to sources
RubyGems will check to see if gems can be installed from the source given
before it is added.
+To add or move a source after all other sources, use --append:
+
+ $ gem sources --append https://rubygems.org
+ https://rubygems.org moved to end of sources
+
To remove a source use the --remove argument:
- $ gem sources --remove https://rubygems.org/
- https://rubygems.org/ removed from sources
+ $ gem sources --remove https://my.private.source/
+ https://my.private.source/ removed from sources
EOF
end
def list # :nodoc:
- say "*** CURRENT SOURCES ***"
+ if configured_sources
+ header = "*** CURRENT SOURCES ***"
+ list = configured_sources
+ else
+ header = "*** NO CONFIGURED SOURCES, DEFAULT SOURCES LISTED BELOW ***"
+ list = Gem.sources
+ end
+
+ say header
say
- Gem.sources.each do |src|
+ list.each do |src|
say src
end
end
def list? # :nodoc:
!(options[:add] ||
+ options[:prepend] ||
+ options[:append] ||
options[:clear_all] ||
options[:remove] ||
options[:update])
@@ -182,11 +263,13 @@ To remove a source use the --remove argument:
def execute
clear_all if options[:clear_all]
- source_uri = options[:add]
- add_source source_uri if source_uri
+ add_source options[:add] if options[:add]
+
+ prepend_source options[:prepend] if options[:prepend]
+
+ append_source options[:append] if options[:append]
- source_uri = options[:remove]
- remove_source source_uri if source_uri
+ remove_source options[:remove] if options[:remove]
update if options[:update]
@@ -194,13 +277,22 @@ To remove a source use the --remove argument:
end
def remove_source(source_uri) # :nodoc:
- if Gem.sources.include? source_uri
- Gem.sources.delete source_uri
+ source = build_source(source_uri)
+ source_uri = source.uri.to_s
+
+ if configured_sources&.include? source
+ Gem.sources.delete source
Gem.configuration.write
- say "#{source_uri} removed from sources"
+ if default_sources.include?(source) && configured_sources.one?
+ alert_warning "Removing a default source when it is the only source has no effect. Add a different source to #{config_file_name} if you want to stop using it as a source."
+ else
+ say "#{source_uri} removed from sources"
+ end
+ elsif configured_sources
+ say "source #{source_uri} cannot be removed because it's not present in #{config_file_name}"
else
- say "source #{source_uri} not present in cache"
+ say "source #{source_uri} cannot be removed because there are no configured sources in #{config_file_name}"
end
end
@@ -224,4 +316,33 @@ To remove a source use the --remove argument:
say "*** Unable to remove #{desc} source cache ***"
end
end
+
+ private
+
+ def default_sources
+ Gem::SourceList.from(Gem.default_sources)
+ end
+
+ def configured_sources
+ return @configured_sources if defined?(@configured_sources)
+
+ configuration_sources = Gem.configuration.sources
+ @configured_sources = Gem::SourceList.from(configuration_sources) if configuration_sources
+ end
+
+ def config_file_name
+ Gem.configuration.config_file_name
+ end
+
+ def build_source(source_uri)
+ source_uri = normalize_source_uri(source_uri)
+ Gem::Source.new(source_uri)
+ end
+
+ def build_new_source(source_uri)
+ source = build_source(source_uri)
+ check_rubygems_https(source.uri.to_s)
+ check_typo_squatting(source)
+ source
+ end
end
diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb
index a21ed35be3..15e543f1a6 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -42,7 +42,7 @@ class Gem::Commands::SpecificationCommand < Gem::Command
def arguments # :nodoc:
<<-ARGS
-GEMFILE name of gem to show the gemspec for
+GEM_OR_FILE gem name or a .gem file to show the gemspec for
FIELD name of gemspec field to show
ARGS
end
@@ -68,7 +68,7 @@ Specific fields in the specification can be extracted in YAML format:
end
def usage # :nodoc:
- "#{program_name} [GEMFILE] [FIELD]"
+ "#{program_name} [GEM_OR_FILE] [FIELD]"
end
def execute
@@ -77,7 +77,7 @@ Specific fields in the specification can be extracted in YAML format:
unless gem
raise Gem::CommandLineError,
- "Please specify a gem name or file on the command line"
+ "Please specify a gem name or a .gem file on the command line"
end
case v = options[:version]
@@ -147,7 +147,7 @@ Specific fields in the specification can be extracted in YAML format:
say case options[:format]
when :ruby then s.to_ruby
when :marshal then Marshal.dump s
- else s.to_yaml
+ else Gem.use_psych? ? s.to_yaml : Gem::YAMLSerializer.dump(s)
end
say "\n"
diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb
index 3d6e41e49e..3c26074f93 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -117,7 +117,7 @@ that is a dependency of an existing gem. You can use the
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem uninstall 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem uninstall 'my_gem:1.0.0' 'my_other_gem:>=2'`"
terminate_interaction 1
end
end
diff --git a/lib/rubygems/compatibility.rb b/lib/rubygems/compatibility.rb
deleted file mode 100644
index 0d9df56f8a..0000000000
--- a/lib/rubygems/compatibility.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-#--
-# This file contains all sorts of little compatibility hacks that we've
-# had to introduce over the years. Quarantining them into one file helps
-# us know when we can get rid of them.
-#
-# Ruby 1.9.x has introduced some things that are awkward, and we need to
-# support them, so we define some constants to use later.
-#
-# TODO remove at RubyGems 4
-#++
-
-module Gem
- # :stopdoc:
-
- RubyGemsVersion = VERSION
- deprecate_constant(:RubyGemsVersion)
-
- RbConfigPriorities = %w[
- MAJOR
- MINOR
- TEENY
- EXEEXT RUBY_SO_NAME arch bindir datadir libdir ruby_install_name
- ruby_version rubylibprefix sitedir sitelibdir vendordir vendorlibdir
- rubylibdir
- ].freeze
-
- if defined?(ConfigMap)
- RbConfigPriorities.each do |key|
- ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
- end
- else
- ##
- # Configuration settings from ::RbConfig
- ConfigMap = Hash.new do |cm, key|
- cm[key] = RbConfig::CONFIG[key.to_s]
- end
- deprecate_constant(:ConfigMap)
- end
-end
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index a2bcb6dfbc..d5e9eb4e33 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -26,9 +26,22 @@ require "rbconfig"
# RubyGems options use symbol keys. Valid options are:
#
# +:backtrace+:: See #backtrace
-# +:sources+:: Sets Gem::sources
+# +:bulk_threshold+:: See #bulk_threshold
# +:verbose+:: See #verbose
+# +:update_sources+:: See #update_sources
# +:concurrent_downloads+:: See #concurrent_downloads
+# +:cert_expiration_length_days+:: See #cert_expiration_length_days
+# +:install_extension_in_lib+:: See #install_extension_in_lib
+# +:ipv4_fallback_enabled+:: See #ipv4_fallback_enabled
+# +:global_gem_cache+:: See #global_gem_cache
+# +:use_psych+:: See #use_psych
+# +:gemhome+:: See #home
+# +:gempath+:: See #path
+# +:sources+:: Sets Gem::sources
+# +:disable_default_gem_server+:: See #disable_default_gem_server
+# +:ssl_verify_mode+:: See #ssl_verify_mode
+# +:ssl_ca_cert+:: See #ssl_ca_cert
+# +:ssl_client_cert+:: See #ssl_client_cert
#
# gemrc files may exist in various locations and are read and merged in
# the following order:
@@ -47,8 +60,9 @@ class Gem::ConfigFile
DEFAULT_CONCURRENT_DOWNLOADS = 8
DEFAULT_CERT_EXPIRATION_LENGTH_DAYS = 365
DEFAULT_IPV4_FALLBACK_ENABLED = false
- # TODO: Use false as default value for this option in RubyGems 4.0
DEFAULT_INSTALL_EXTENSION_IN_LIB = true
+ DEFAULT_GLOBAL_GEM_CACHE = false
+ DEFAULT_USE_PSYCH = false
##
# For Ruby packagers to set configuration defaults. Set in
@@ -156,6 +170,17 @@ class Gem::ConfigFile
attr_accessor :ipv4_fallback_enabled
##
+ # Use a global cache for .gem files shared across all Ruby installations.
+ # When enabled, gems are cached to ~/.cache/gem/gems (or XDG_CACHE_HOME/gem/gems).
+
+ attr_accessor :global_gem_cache
+
+ ##
+ # Use Psych (C extension YAML parser) instead of the pure Ruby YAMLSerializer.
+
+ attr_accessor :use_psych
+
+ ##
# Path name of directory or file of openssl client certificate, used for remote https connection with client authentication
attr_reader :ssl_client_cert
@@ -192,6 +217,8 @@ class Gem::ConfigFile
@cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS
@install_extension_in_lib = DEFAULT_INSTALL_EXTENSION_IN_LIB
@ipv4_fallback_enabled = ENV["IPV4_FALLBACK_ENABLED"] == "true" || DEFAULT_IPV4_FALLBACK_ENABLED
+ @global_gem_cache = ENV["RUBYGEMS_GLOBAL_GEM_CACHE"] == "true" || DEFAULT_GLOBAL_GEM_CACHE
+ @use_psych = ENV["RUBYGEMS_USE_PSYCH"] == "true" || DEFAULT_USE_PSYCH
operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
@@ -213,8 +240,9 @@ class Gem::ConfigFile
@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)
+ concurrent_downloads install_extension_in_lib ipv4_fallback_enabled
+ global_gem_cache use_psych sources
+ disable_default_gem_server ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)
k.to_sym
else
k
@@ -226,10 +254,12 @@ class Gem::ConfigFile
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
@verbose = @hash[:verbose] if @hash.key? :verbose
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
- # TODO: We should handle concurrent_downloads same as other options
+ @concurrent_downloads = @hash[:concurrent_downloads] if @hash.key? :concurrent_downloads
@cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days
@install_extension_in_lib = @hash[:install_extension_in_lib] if @hash.key? :install_extension_in_lib
@ipv4_fallback_enabled = @hash[:ipv4_fallback_enabled] if @hash.key? :ipv4_fallback_enabled
+ @global_gem_cache = @hash[:global_gem_cache] if @hash.key? :global_gem_cache
+ @use_psych = @hash[:use_psych] if @hash.key? :use_psych
@home = @hash[:gemhome] if @hash.key? :gemhome
@path = @hash[:gempath] if @hash.key? :gempath
@@ -345,7 +375,7 @@ if you believe they were disclosed to a third party.
require "fileutils"
FileUtils.mkdir_p(dirname)
- permissions = 0o600 & (~File.umask)
+ permissions = 0o600 & ~File.umask
File.open(credentials_path, "w", permissions) do |f|
f.write self.class.dump_with_rubygems_yaml(config)
end
@@ -369,7 +399,9 @@ if you believe they were disclosed to a third party.
begin
config = self.class.load_with_rubygems_config_hash(File.read(filename))
- if config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
+ has_invalid_keys = config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
+ has_invalid_values = config.values.any? {|v| v.is_a?(String) && v.gsub(%r{https?:\/\/}, "").match?(/\A\S+: /) }
+ if has_invalid_keys || has_invalid_values
warn "Failed to load #{filename} because it doesn't contain valid YAML hash"
return {}
else
@@ -554,7 +586,9 @@ if you believe they were disclosed to a third party.
def self.load_with_rubygems_config_hash(yaml)
require_relative "yaml_serializer"
- content = Gem::YAMLSerializer.load(yaml)
+ content = Gem::YAMLSerializer.load(yaml, permitted_classes: [])
+ return {} unless content.is_a?(Hash)
+
deep_transform_config_keys!(content)
end
@@ -588,7 +622,7 @@ if you believe they were disclosed to a third party.
else
v
end
- elsif v.empty?
+ elsif v.respond_to?(:empty?) && v.empty?
nil
elsif v.is_a?(Hash)
deep_transform_config_keys!(v)
diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb
index 073966b696..3a9bdbdc9d 100644
--- a/lib/rubygems/core_ext/kernel_require.rb
+++ b/lib/rubygems/core_ext/kernel_require.rb
@@ -64,8 +64,11 @@ module Kernel
rp
end
- Kernel.send(:gem, name, Gem::Requirement.default_prerelease) unless
- resolved_path
+ next if resolved_path
+
+ Kernel.send(:gem, name, Gem::Requirement.default_prerelease)
+
+ Gem.load_bundler_extensions(Gem.loaded_specs[name].version) if name == "bundler"
next
end
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index db07681a17..2247c49c81 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -13,7 +13,7 @@ module Gem
# An Array of the default sources that come with RubyGems
def self.default_sources
- %w[https://rubygems.org/]
+ @default_sources ||= %w[https://rubygems.org/]
end
##
@@ -149,6 +149,15 @@ module Gem
end
##
+ # The path to the global gem cache directory.
+ # This is used when global_gem_cache is enabled to share .gem files
+ # across all Ruby installations.
+
+ def self.global_gem_cache_path
+ File.join(cache_home, "gem", "gems")
+ end
+
+ ##
# The path to standard location of the user's data directory.
def self.data_home
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index d1ec9222af..1e91f493a6 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -217,7 +217,7 @@ class Gem::Dependency
# NOTE: Unlike #matches_spec? this method does not return true when the
# version is a prerelease version unless this is a prerelease dependency.
- def match?(obj, version=nil, allow_prerelease=false)
+ def match?(obj, version = nil, allow_prerelease = false)
if !version
name = obj.name
version = obj.version
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index b119dca1cf..c842714d95 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -7,14 +7,12 @@ require_relative "installer"
require_relative "spec_fetcher"
require_relative "user_interaction"
require_relative "available_set"
-require_relative "deprecate"
##
# Installs a gem along with all its dependencies from local and remote gems.
class Gem::DependencyInstaller
include Gem::UserInteraction
- extend Gem::Deprecate
DEFAULT_OPTIONS = { # :nodoc:
env_shebang: false,
@@ -28,7 +26,6 @@ class Gem::DependencyInstaller
wrappers: true,
build_args: nil,
build_docs_in_background: false,
- install_as_default: false,
}.freeze
##
@@ -86,11 +83,13 @@ class Gem::DependencyInstaller
@user_install = options[:user_install]
@wrappers = options[:wrappers]
@build_args = options[:build_args]
+ @build_jobs = options[:build_jobs]
@build_docs_in_background = options[:build_docs_in_background]
- @install_as_default = options[:install_as_default]
@dir_mode = options[:dir_mode]
@data_mode = options[:data_mode]
@prog_mode = options[:prog_mode]
+ @build_extension = options[:build_extension]
+ @install_plugin = options[:install_plugin]
# Indicates that we should not try to update any deps unless
# we absolutely must.
@@ -121,78 +120,6 @@ class Gem::DependencyInstaller
@domain == :both || @domain == :remote
end
- ##
- # Returns a list of pairs of gemspecs and source_uris that match
- # Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources)
- # sources. Gems are sorted with newer gems preferred over older gems, and
- # local gems preferred over remote gems.
-
- def find_gems_with_sources(dep, best_only=false) # :nodoc:
- set = Gem::AvailableSet.new
-
- if consider_local?
- sl = Gem::Source::Local.new
-
- if spec = sl.find_gem(dep.name)
- if dep.matches_spec? spec
- set.add spec, sl
- end
- end
- end
-
- if consider_remote?
- begin
- # This is pulled from #spec_for_dependency to allow
- # us to filter tuples before fetching specs.
- tuples, errors = Gem::SpecFetcher.fetcher.search_for_dependency dep
-
- if best_only && !tuples.empty?
- tuples.sort! do |a,b|
- if b[0].version == a[0].version
- if b[0].platform != Gem::Platform::RUBY
- 1
- else
- -1
- end
- else
- b[0].version <=> a[0].version
- end
- end
- tuples = [tuples.first]
- end
-
- 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]
- end
-
- if @errors
- @errors += errors
- else
- @errors = errors
- 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
- # couldn't find their requested gem.
- verbose do
- "Error fetching remote data:\t\t#{e.message}\n" \
- "Falling back to local-only install"
- end
- @domain = :local
- end
- end
-
- set
- end
- rubygems_deprecate :find_gems_with_sources
-
def in_background(what) # :nodoc:
fork_happened = false
if @build_docs_in_background && Process.respond_to?(:fork)
@@ -230,6 +157,7 @@ class Gem::DependencyInstaller
options = {
bin_dir: @bin_dir,
build_args: @build_args,
+ build_jobs: @build_jobs,
document: @document,
env_shebang: @env_shebang,
force: @force,
@@ -240,10 +168,11 @@ class Gem::DependencyInstaller
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,
+ build_extension: @build_extension,
+ install_plugin: @install_plugin,
}
options[:install_dir] = @install_dir if @only_install_dir
diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb
index ad5e59e8c1..d50cfe2d54 100644
--- a/lib/rubygems/dependency_list.rb
+++ b/lib/rubygems/dependency_list.rb
@@ -7,7 +7,6 @@
#++
require_relative "vendored_tsort"
-require_relative "deprecate"
##
# Gem::DependencyList is used for installing and uninstalling gems in the
@@ -140,7 +139,7 @@ class Gem::DependencyList
# If removing the gemspec creates breaks a currently ok dependency, then it
# is NOT ok to remove the gemspec.
- def ok_to_remove?(full_name, check_dev=true)
+ def ok_to_remove?(full_name, check_dev = true)
gem_to_remove = find_name full_name
# If the state is inconsistent, at least don't crash
diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb
index 7d24f9cbfc..eb503bb269 100644
--- a/lib/rubygems/deprecate.rb
+++ b/lib/rubygems/deprecate.rb
@@ -1,75 +1,75 @@
# frozen_string_literal: true
-##
-# Provides 3 methods for declaring when something is going away.
-#
-# +deprecate(name, repl, year, month)+:
-# Indicate something may be removed on/after a certain date.
-#
-# +rubygems_deprecate(name, replacement=:none)+:
-# Indicate something will be removed in the next major RubyGems version,
-# and (optionally) a replacement for it.
-#
-# +rubygems_deprecate_command+:
-# Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be
-# removed in the next RubyGems version.
-#
-# Also provides +skip_during+ for temporarily turning off deprecation warnings.
-# This is intended to be used in the test suite, so deprecation warnings
-# don't cause test failures if you need to make sure stderr is otherwise empty.
-#
-#
-# Example usage of +deprecate+ and +rubygems_deprecate+:
-#
-# class Legacy
-# def self.some_class_method
-# # ...
-# end
-#
-# def some_instance_method
-# # ...
-# end
-#
-# def some_old_method
-# # ...
-# end
-#
-# extend Gem::Deprecate
-# deprecate :some_instance_method, "X.z", 2011, 4
-# rubygems_deprecate :some_old_method, "Modern#some_new_method"
-#
-# class << self
-# extend Gem::Deprecate
-# deprecate :some_class_method, :none, 2011, 4
-# end
-# end
-#
-#
-# Example usage of +rubygems_deprecate_command+:
-#
-# class Gem::Commands::QueryCommand < Gem::Command
-# extend Gem::Deprecate
-# rubygems_deprecate_command
-#
-# # ...
-# end
-#
-#
-# Example usage of +skip_during+:
-#
-# class TestSomething < Gem::Testcase
-# def test_some_thing_with_deprecations
-# Gem::Deprecate.skip_during do
-# actual_stdout, actual_stderr = capture_output do
-# Gem.something_deprecated
-# end
-# assert_empty actual_stdout
-# assert_equal(expected, actual_stderr)
-# end
-# end
-# end
-
module Gem
+ ##
+ # Provides 3 methods for declaring when something is going away.
+ #
+ # <tt>deprecate(name, repl, year, month)</tt>:
+ # Indicate something may be removed on/after a certain date.
+ #
+ # <tt>rubygems_deprecate(name, replacement=:none)</tt>:
+ # Indicate something will be removed in the next major RubyGems version,
+ # and (optionally) a replacement for it.
+ #
+ # +rubygems_deprecate_command+:
+ # Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be
+ # removed in the next RubyGems version.
+ #
+ # Also provides +skip_during+ for temporarily turning off deprecation warnings.
+ # This is intended to be used in the test suite, so deprecation warnings
+ # don't cause test failures if you need to make sure stderr is otherwise empty.
+ #
+ #
+ # Example usage of +deprecate+ and +rubygems_deprecate+:
+ #
+ # class Legacy
+ # def self.some_class_method
+ # # ...
+ # end
+ #
+ # def some_instance_method
+ # # ...
+ # end
+ #
+ # def some_old_method
+ # # ...
+ # end
+ #
+ # extend Gem::Deprecate
+ # deprecate :some_instance_method, "X.z", 2011, 4
+ # rubygems_deprecate :some_old_method, "Modern#some_new_method"
+ #
+ # class << self
+ # extend Gem::Deprecate
+ # deprecate :some_class_method, :none, 2011, 4
+ # end
+ # end
+ #
+ #
+ # Example usage of +rubygems_deprecate_command+:
+ #
+ # class Gem::Commands::QueryCommand < Gem::Command
+ # extend Gem::Deprecate
+ # rubygems_deprecate_command
+ #
+ # # ...
+ # end
+ #
+ #
+ # Example usage of +skip_during+:
+ #
+ # class TestSomething < Gem::Testcase
+ # def test_some_thing_with_deprecations
+ # Gem::Deprecate.skip_during do
+ # actual_stdout, actual_stderr = capture_output do
+ # Gem.something_deprecated
+ # end
+ # assert_empty actual_stdout
+ # assert_equal(expected, actual_stderr)
+ # end
+ # end
+ # end
+
module Deprecate
def self.skip # :nodoc:
@skip ||= false
@@ -126,17 +126,18 @@ module Gem
# 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)
+ def rubygems_deprecate(name, replacement = :none, version = nil)
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}#"
+ version ||= Gem::Deprecate.next_rubygems_major_version
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}",
+ ". It will be removed in Rubygems #{version}",
"\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
]
warn "#{msg.join}." unless Gem::Deprecate.skip
@@ -147,13 +148,14 @@ module Gem
end
# Deprecation method to deprecate Rubygems commands
- def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
+ def rubygems_deprecate_command(version = nil)
class_eval do
define_method "deprecated?" do
true
end
define_method "deprecation_warning" do
+ version ||= Gem::Deprecate.next_rubygems_major_version
msg = [
"#{command} command is deprecated",
". It will be removed in Rubygems #{version}.\n",
diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb
index 56b7c081eb..4f26260d83 100644
--- a/lib/rubygems/doctor.rb
+++ b/lib/rubygems/doctor.rb
@@ -113,7 +113,7 @@ class Gem::Doctor
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 sub_directory == "plugins" && 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..4bbc5217e0 100644
--- a/lib/rubygems/errors.rb
+++ b/lib/rubygems/errors.rb
@@ -26,7 +26,7 @@ module Gem
# system. Instead of rescuing from this class, make sure to rescue from the
# superclass Gem::LoadError to catch all types of load errors.
class MissingSpecError < Gem::LoadError
- def initialize(name, requirement, extra_message=nil)
+ def initialize(name, requirement, extra_message = nil)
@name = name
@requirement = requirement
@extra_message = extra_message
diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb
index 793324b875..e00a70c662 100644
--- a/lib/rubygems/exceptions.rb
+++ b/lib/rubygems/exceptions.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
require_relative "unknown_command_spell_checker"
##
@@ -21,20 +20,11 @@ class Gem::UnknownCommandError < Gem::Exception
end
def self.attach_correctable
- return if defined?(@attached)
+ return if method_defined?(:corrections)
- if defined?(DidYouMean::SPELL_CHECKERS) && defined?(DidYouMean::Correctable)
- if DidYouMean.respond_to?(:correct_error)
- DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
- else
- DidYouMean::SPELL_CHECKERS["Gem::UnknownCommandError"] =
- Gem::UnknownCommandSpellChecker
-
- prepend DidYouMean::Correctable
- end
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
+ DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
end
-
- @attached = true
end
end
@@ -43,22 +33,24 @@ class Gem::DependencyError < Gem::Exception; end
class Gem::DependencyRemovalException < Gem::Exception; end
##
-# Raised by Gem::Resolver when a Gem::Dependency::Conflict reaches the
-# toplevel. Indicates which dependencies were incompatible through #conflict
-# and #conflicting_dependencies
+# Raised by Gem::Resolver when dependency resolution fails.
class Gem::DependencyResolutionError < Gem::DependencyError
- attr_reader :conflict
-
def initialize(conflict)
- @conflict = conflict
- a, b = conflicting_dependencies
+ @explanation = conflict.explanation
+ super @explanation
+ end
- super "conflicting dependencies #{a} and #{b}\n#{@conflict.explanation}"
+ def explanation
+ @explanation
+ end
+
+ def conflict
+ nil
end
def conflicting_dependencies
- @conflict.conflicting_dependencies
+ []
end
end
@@ -110,7 +102,7 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
# and +version+. Any +errors+ encountered when attempting to find the gem
# are also stored.
- def initialize(name, version, errors=nil)
+ def initialize(name, version, errors = nil)
super "Could not find a valid gem '#{name}' (#{version}) locally or in a repository"
@name = name
@@ -136,40 +128,6 @@ 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.
-
-class Gem::ImpossibleDependenciesError < Gem::Exception
- attr_reader :conflicts
- attr_reader :request
-
- def initialize(request, conflicts)
- @request = request
- @conflicts = conflicts
-
- super build_message
- end
-
- def build_message # :nodoc:
- requester = @request.requester
- requester = requester ? requester.spec.full_name : "The user"
- dependency = @request.dependency
-
- message = "#{requester} requires #{dependency} but it conflicted:\n".dup
-
- @conflicts.each do |_, conflict|
- message << conflict.explanation
- end
-
- message
- end
-
- def dependency
- @request.dependency
- end
-end
-
class Gem::InstallError < Gem::Exception; end
class Gem::RuntimeRequirementNotMetError < Gem::InstallError
@@ -261,7 +219,7 @@ class Gem::UnsatisfiableDependencyError < Gem::DependencyError
# Creates a new UnsatisfiableDependencyError for the unsatisfiable
# Gem::Resolver::DependencyRequest +dep+
- def initialize(dep, platform_mismatch=nil)
+ 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(", ")}"
diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb
index 12eb62ef16..e00cf159da 100644
--- a/lib/rubygems/ext/builder.rb
+++ b/lib/rubygems/ext/builder.rb
@@ -7,11 +7,13 @@
#++
require_relative "../user_interaction"
-require_relative "../shellwords"
class Gem::Ext::Builder
include Gem::UserInteraction
+ class NoMakefileError < Gem::InstallError
+ end
+
attr_accessor :build_args # :nodoc:
def self.class_name
@@ -20,19 +22,30 @@ class Gem::Ext::Builder
end
def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil, targets = ["clean", "", "install"],
- target_rbconfig: Gem.target_rbconfig)
+ target_rbconfig: Gem.target_rbconfig, n_jobs: nil)
unless File.exist? File.join(make_dir, "Makefile")
- raise Gem::InstallError, "Makefile not found"
+ # No makefile exists, nothing to do.
+ raise NoMakefileError, "No Makefile found in #{make_dir}"
end
# try to find make program from Ruby configure arguments first
target_rbconfig["configure_args"] =~ /with-make-prog\=(\w+)/
make_program_name = ENV["MAKE"] || ENV["make"] || $1
make_program_name ||= RUBY_PLATFORM.include?("mswin") ? "nmake" : "make"
- make_program = Shellwords.split(make_program_name)
+ make_program = shellsplit(make_program_name)
+ is_nmake = /\bnmake/i.match?(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 = !is_nmake || ENV["DESTDIR"] && ENV["DESTDIR"] != "" ? format("DESTDIR=%s", ENV["DESTDIR"]) : ""
+
+ # nmake doesn't support parallel build
+ unless is_nmake
+ have_make_arguments = make_program.size > 1
+
+ if !have_make_arguments && !ENV["MAKEFLAGS"] && n_jobs
+ make_program << "-j#{n_jobs}"
+ end
+ end
env = [destdir]
@@ -58,7 +71,7 @@ class Gem::Ext::Builder
def self.ruby
# Gem.ruby is quoted if it contains whitespace
- cmd = Shellwords.split(Gem.ruby)
+ cmd = shellsplit(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.
@@ -83,13 +96,14 @@ class Gem::Ext::Builder
p(command)
end
results << "current directory: #{dir}"
- results << Shellwords.join(command)
+ results << shelljoin(command)
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|
+ Open3.popen2e(build_env, *command, chdir: dir) do |stdin, stdouterr, wait_thread|
+ stdin.close
output = String.new
while line = stdouterr.gets
output << line
@@ -127,18 +141,29 @@ class Gem::Ext::Builder
end
end
+ def self.shellsplit(command)
+ require "shellwords"
+
+ Shellwords.split(command)
+ end
+
+ def self.shelljoin(command)
+ require "shellwords"
+
+ Shellwords.join(command)
+ end
+
##
# Creates a new extension builder for +spec+. If the +spec+ does not yet
# have build arguments, saved, set +build_args+ which is an ARGV-style
# array.
- def initialize(spec, build_args = spec.build_args, target_rbconfig = Gem.target_rbconfig)
+ def initialize(spec, build_args = spec.build_args, target_rbconfig = Gem.target_rbconfig, build_jobs = nil)
@spec = spec
@build_args = build_args
@gem_dir = spec.full_gem_path
@target_rbconfig = target_rbconfig
-
- @ran_rake = false
+ @build_jobs = build_jobs
end
##
@@ -151,10 +176,9 @@ class Gem::Ext::Builder
when /configure/ then
Gem::Ext::ConfigureBuilder
when /rakefile/i, /mkrf_conf/i then
- @ran_rake = true
Gem::Ext::RakeBuilder
when /CMakeLists.txt/ then
- Gem::Ext::CmakeBuilder
+ Gem::Ext::CmakeBuilder.new
when /Cargo.toml/ then
Gem::Ext::CargoBuilder.new
else
@@ -193,7 +217,7 @@ EOF
FileUtils.mkdir_p dest_path
results = builder.build(extension, dest_path,
- results, @build_args, lib_dir, extension_dir, @target_rbconfig)
+ results, @build_args, lib_dir, extension_dir, @target_rbconfig, n_jobs: @build_jobs)
verbose { results.join("\n") }
@@ -224,8 +248,6 @@ EOF
FileUtils.rm_f @spec.gem_build_complete_path
@spec.extensions.each do |extension|
- break if @ran_rake
-
build_extension extension, dest_path
end
diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb
index 453f8d5bcb..516459dd60 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.
@@ -17,7 +15,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
end
def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
require "tempfile"
require "fileutils"
@@ -159,7 +157,11 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
# We want to use the same linker that Ruby uses, so that the linker flags from
# mkmf work properly.
def linker_args
- cc_flag = Shellwords.split(makefile_config("CC"))
+ cc_flag = self.class.shellsplit(makefile_config("CC"))
+ # Avoid to ccache like tool from Rust build
+ # see https://github.com/ruby/rubygems/pull/8521#issuecomment-2689854359
+ # ex. CC="ccache gcc" or CC="sccache clang --any --args"
+ cc_flag.shift if cc_flag.size >= 2 && !cc_flag[1].start_with?("-")
linker = cc_flag.shift
link_args = cc_flag.flat_map {|a| ["-C", "link-arg=#{a}"] }
@@ -178,7 +180,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
def libruby_args(dest_dir)
libs = makefile_config(ruby_static? ? "LIBRUBYARG_STATIC" : "LIBRUBYARG_SHARED")
- raw_libs = Shellwords.split(libs)
+ raw_libs = self.class.shellsplit(libs)
raw_libs.flat_map {|l| ldflag_to_link_modifier(l) }
end
@@ -225,10 +227,9 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
raise Gem::InstallError, "cargo metadata failed#{exit_reason}"
end
- # cargo metadata output is specified as json, but with the
- # --format-version 1 option the output is compatible with YAML, so we can
- # avoid the json dependency
- metadata = Gem::SafeYAML.safe_load(output)
+ # cargo metadata output is specified as json
+ require "json"
+ metadata = JSON.parse(output)
package = metadata["packages"].find {|pkg| normalize_path(pkg["manifest_path"]) == manifest_path }
unless package
found = metadata["packages"].map {|md| "#{md["name"]} at #{md["manifest_path"]}" }
@@ -261,7 +262,7 @@ EOF
end
def split_flags(var)
- Shellwords.split(RbConfig::CONFIG.fetch(var, ""))
+ self.class.shellsplit(RbConfig::CONFIG.fetch(var, ""))
end
def ldflag_to_link_modifier(arg)
diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb
index 34564f668d..e660ed558b 100644
--- a/lib/rubygems/ext/cmake_builder.rb
+++ b/lib/rubygems/ext/cmake_builder.rb
@@ -1,21 +1,110 @@
# frozen_string_literal: true
+# This builder creates extensions defined using CMake. Its is invoked if a Gem's spec file
+# sets the `extension` property to a string that contains `CMakeLists.txt`.
+#
+# In general, CMake projects are built in two steps:
+#
+# * configure
+# * build
+#
+# The builder follow this convention. First it runs a configuration step and then it runs a build step.
+#
+# CMake projects can be quite configurable - it is likely you will want to specify options when
+# installing a gem. To pass options to CMake specify them after `--` in the gem install command. For example:
+#
+# gem install <gem_name> -- --preset <preset_name>
+#
+# Note that options are ONLY sent to the configure step - it is not currently possible to specify
+# options for the build step. If this becomes and issue then the CMake builder can be updated to
+# support build options.
+#
+# Useful options to know are:
+#
+# -G to specify a generator (-G Ninja is recommended)
+# -D<CMAKE_VARIABLE> to set a CMake variable (for example -DCMAKE_BUILD_TYPE=Release)
+# --preset <preset_name> to use a preset
+#
+# If the Gem author provides presets, via CMakePresets.json file, you will likely want to use one of them.
+# If not, you may wish to specify a generator. Ninja is recommended because it can build projects in parallel
+# and thus much faster than building them serially like Make does.
+
class Gem::Ext::CmakeBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
+ attr_accessor :runner, :profile
+ def initialize
+ @runner = self.class.method(:run)
+ @profile = :release
+ end
+
+ def build(extension, dest_path, results, args = [], lib_dir = nil, cmake_dir = Dir.pwd,
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
if target_rbconfig.path
warn "--target-rbconfig is not yet supported for CMake extensions. Ignoring"
end
- unless File.exist?(File.join(cmake_dir, "Makefile"))
- require_relative "../command"
- cmd = ["cmake", ".", "-DCMAKE_INSTALL_PREFIX=#{dest_path}", *Gem::Command.build_args]
+ # Figure the build dir
+ build_dir = File.join(cmake_dir, "build")
- run cmd, results, class_name, cmake_dir
- end
+ # Check if the gem defined presets
+ check_presets(cmake_dir, args, results)
+
+ # Configure
+ configure(cmake_dir, build_dir, dest_path, args, results)
- make dest_path, results, cmake_dir, target_rbconfig: target_rbconfig
+ # Compile
+ compile(cmake_dir, build_dir, args, results)
results
end
+
+ def configure(cmake_dir, build_dir, install_dir, args, results)
+ cmd = ["cmake",
+ cmake_dir,
+ "-B",
+ build_dir,
+ "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=#{install_dir}", # Windows
+ "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=#{install_dir}", # Not Windows
+ *Gem::Command.build_args,
+ *args]
+
+ runner.call(cmd, results, "cmake_configure", cmake_dir)
+ end
+
+ def compile(cmake_dir, build_dir, args, results)
+ cmd = ["cmake",
+ "--build",
+ build_dir.to_s,
+ "--config",
+ @profile.to_s]
+
+ runner.call(cmd, results, "cmake_compile", cmake_dir)
+ end
+
+ private
+
+ def check_presets(cmake_dir, args, results)
+ # Return if the user specified a preset
+ return unless args.grep(/--preset/i).empty?
+
+ cmd = ["cmake",
+ "--list-presets"]
+
+ presets = Array.new
+ begin
+ runner.call(cmd, presets, "cmake_presets", cmake_dir)
+
+ # Remove the first two lines of the array which is the current_directory and the command
+ # that was run
+ presets = presets[2..].join
+ results << <<~EOS
+ The gem author provided a list of presets that can be used to build the gem. To use a preset specify it on the command line:
+
+ gem install <gem_name> -- --preset <preset_name>
+
+ #{presets}
+ EOS
+ rescue Gem::InstallError
+ # Do nothing, CMakePresets.json was not included in the Gem
+ end
+ end
end
diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb
index d91b1ec5e8..230b214b3c 100644
--- a/lib/rubygems/ext/configure_builder.rb
+++ b/lib/rubygems/ext/configure_builder.rb
@@ -7,8 +7,8 @@
#++
class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, configure_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
+ def self.build(extension, dest_path, results, args = [], lib_dir = nil, configure_dir = Dir.pwd,
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
if target_rbconfig.path
warn "--target-rbconfig is not yet supported for configure-based extensions. Ignoring"
end
@@ -19,7 +19,7 @@ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
run cmd, results, class_name, configure_dir
end
- make dest_path, results, configure_dir, target_rbconfig: target_rbconfig
+ make dest_path, results, configure_dir, target_rbconfig: target_rbconfig, n_jobs: n_jobs
results
end
diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb
index e652a221f8..822454355d 100644
--- a/lib/rubygems/ext/ext_conf_builder.rb
+++ b/lib/rubygems/ext/ext_conf_builder.rb
@@ -7,8 +7,8 @@
#++
class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
+ def self.build(extension, dest_path, results, args = [], lib_dir = nil, extension_dir = Dir.pwd,
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
require "fileutils"
require "tempfile"
@@ -41,7 +41,7 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
ENV["DESTDIR"] = nil
- make dest_path, results, extension_dir, tmp_dest_relative, target_rbconfig: target_rbconfig
+ make dest_path, results, extension_dir, tmp_dest_relative, target_rbconfig: target_rbconfig, n_jobs: n_jobs
full_tmp_dest = File.join(extension_dir, tmp_dest_relative)
@@ -66,6 +66,10 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
end
results
+ rescue Gem::Ext::Builder::NoMakefileError => error
+ results << error.message
+ results << "Skipping make for #{extension} as no Makefile was found."
+ # We are good, do not re-raise the error.
ensure
FileUtils.rm_rf tmp_dest if tmp_dest
end
diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb
index 42393a4a06..d702d7f339 100644
--- a/lib/rubygems/ext/rake_builder.rb
+++ b/lib/rubygems/ext/rake_builder.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "../shellwords"
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -9,8 +7,8 @@ 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,
- target_rbconfig=Gem.target_rbconfig)
+ def self.build(extension, dest_path, results, args = [], lib_dir = nil, extension_dir = Dir.pwd,
+ target_rbconfig = Gem.target_rbconfig, n_jobs: nil)
if target_rbconfig.path
warn "--target-rbconfig is not yet supported for Rake extensions. Ignoring"
end
@@ -22,7 +20,7 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder
rake = ENV["rake"]
if rake
- rake = Shellwords.split(rake)
+ rake = shellsplit(rake)
else
begin
rake = ruby << "-rrubygems" << Gem.bin_path("rake", "rake")
diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb
index 4cb924677f..e60cebd0cb 100644
--- a/lib/rubygems/gem_runner.rb
+++ b/lib/rubygems/gem_runner.rb
@@ -8,7 +8,6 @@
require_relative "../rubygems"
require_relative "command_manager"
-require_relative "deprecate"
##
# Run an instance of the gem program.
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index d3176d4564..9c22c14fad 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -154,10 +154,11 @@ module Gem::GemcutterUtilities
def sign_in(sign_in_host = nil, scope: nil)
sign_in_host ||= host
- return if api_key
-
pretty_host = pretty_host(sign_in_host)
-
+ if api_key
+ say "You are already signed in on #{pretty_host}."
+ return
+ end
say "Enter your #{pretty_host} credentials."
say "Don't have an account yet? " \
"Create one at #{sign_in_host}/sign_up"
@@ -263,7 +264,10 @@ module Gem::GemcutterUtilities
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."
+ say "You have enabled multi-factor authentication. Please visit the following URL 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."
+ say ""
+ say url_with_port
+ say ""
threads = [WebauthnListener.listener_thread(host, server), WebauthnPoller.poll_thread(options, host, webauthn_url, credentials)]
otp_thread = wait_for_otp_thread(*threads)
@@ -316,7 +320,7 @@ module Gem::GemcutterUtilities
end
def get_scope_params(scope)
- scope_params = { index_rubygems: true }
+ scope_params = { index_rubygems: true, push_rubygem: true }
if scope
scope_params = { scope => true }
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
index abf65efe37..3f56a077c9 100644
--- a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
+++ b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
@@ -85,10 +85,17 @@ module Gem::GemcutterUtilities
end
def parse_otp_from_uri(uri)
- require "cgi"
+ query = uri.query
+ return unless query && !query.empty?
- return if uri.query.nil?
- CGI.parse(uri.query).dig("code", 0)
+ query.split("&") do |param|
+ key, value = param.split("=", 2)
+ if value && Gem::URI.decode_www_form_component(key) == "code"
+ return Gem::URI.decode_www_form_component(value)
+ end
+ end
+
+ nil
end
class SocketResponder
diff --git a/lib/rubygems/install_default_message.rb b/lib/rubygems/install_default_message.rb
deleted file mode 100644
index 0640eaaf08..0000000000
--- a/lib/rubygems/install_default_message.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../rubygems"
-require_relative "user_interaction"
-
-##
-# A post-install hook that displays "Successfully installed
-# some_gem-1.0 as a default gem"
-
-Gem.post_install do |installer|
- ui = Gem::DefaultUserInteraction.ui
- ui.say "Successfully installed #{installer.spec.full_name} as a default gem"
-end
diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb
index 0d0f0dc211..e8859cadaf 100644
--- a/lib/rubygems/install_update_options.rb
+++ b/lib/rubygems/install_update_options.rb
@@ -31,6 +31,15 @@ module Gem::InstallUpdateOptions
options[:bin_dir] = File.expand_path(value)
end
+ add_option(:"Install/Update", "-j", "--build-jobs VALUE", Integer,
+ "Specify the number of jobs to pass to `make` when installing",
+ "gems with native extensions.",
+ "Defaults to the number of processors.",
+ "This option is ignored on the mswin platform or",
+ "if the MAKEFLAGS environment variable is set.") do |value, options|
+ options[:build_jobs] = value
+ end
+
add_option(:"Install/Update", "--document [TYPES]", Array,
"Generate documentation for installed gems",
"List the documentation types you wish to",
@@ -158,10 +167,9 @@ module Gem::InstallUpdateOptions
options[:without_groups].concat v.map(&:intern)
end
- add_option(:"Install/Update", "--default",
+ add_option(:Deprecated, "--default",
"Add the gem's full specification to",
"specifications/default and extract only its bin") do |v,_o|
- options[:install_as_default] = v
end
add_option(:"Install/Update", "--explain",
@@ -184,6 +192,18 @@ module Gem::InstallUpdateOptions
"rbconfig.rb for the deployment target platform") do |v, _o|
Gem.set_target_rbconfig(v)
end
+
+ add_option(:"Install/Update", "--[no-]build-extension",
+ "Build native extensions during installation.",
+ "Defaults to true") do |v, _o|
+ options[:build_extension] = v
+ end
+
+ add_option(:"Install/Update", "--[no-]install-plugin",
+ "Install plugins during installation.",
+ "Defaults to true") do |v, _o|
+ options[:install_plugin] = v
+ end
end
##
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 7f5d913ac4..15d6aac0fd 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -8,7 +8,6 @@
require_relative "installer_uninstaller_utils"
require_relative "exceptions"
-require_relative "deprecate"
require_relative "package"
require_relative "ext"
require_relative "user_interaction"
@@ -27,8 +26,6 @@ require_relative "user_interaction"
# file. See Gem.pre_install and Gem.post_install for details.
class Gem::Installer
- extend Gem::Deprecate
-
##
# Paths where env(1) might live. Some systems are broken and have it in
# /bin
@@ -67,23 +64,6 @@ class Gem::Installer
attr_reader :package
class << self
- #
- # Changes in rubygems to lazily loading `rubygems/command` (in order to
- # lazily load `optparse` as a side effect) affect bundler's custom installer
- # which uses `Gem::Command` without requiring it (up until bundler 2.2.29).
- # This hook is to compensate for that missing require.
- #
- # TODO: Remove when rubygems no longer supports running on bundler older
- # than 2.2.29.
-
- def inherited(klass)
- if klass.name == "Bundler::RubyGemsGemInstaller"
- require "rubygems/command"
- end
-
- super(klass)
- end
-
##
# Overrides the executable format.
#
@@ -170,7 +150,7 @@ class Gem::Installer
# process. If not set, then Gem::Command.build_args is used
# :post_install_message:: Print gem post install message if true
- def initialize(package, options={})
+ def initialize(package, options = {})
require "fileutils"
@options = options
@@ -228,8 +208,7 @@ class Gem::Installer
ruby_executable = true
existing = io.read.slice(/
^\s*(
- gem \s |
- load \s Gem\.bin_path\( |
+ Gem\.activate_and_load_bin_path\( |
load \s Gem\.activate_bin_path\(
)
(['"])(.*?)(\2),
@@ -292,11 +271,7 @@ class Gem::Installer
run_pre_install_hooks
# Set loaded_from to ensure extension_dir is correct
- if @options[:install_as_default]
- spec.loaded_from = default_spec_file
- else
- spec.loaded_from = spec_file
- end
+ spec.loaded_from = spec_file
# Completely remove any previous gem files
FileUtils.rm_rf gem_dir
@@ -305,32 +280,30 @@ class Gem::Installer
dir_mode = options[:dir_mode]
FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755
- if @options[:install_as_default]
- extract_bin
- write_default_spec
- else
- extract_files
+ extract_files
- build_extensions
- write_build_info_file
- run_post_build_hooks
- end
+ build_extensions
+ write_build_info_file
+ run_post_build_hooks
generate_bin
- generate_plugins
-
- unless @options[:install_as_default]
- write_spec
- write_cache_file
+ if options[:install_plugin] == false
+ remove_stale_plugins
+ warn_skipped_plugins
+ else
+ generate_plugins
end
+ write_spec
+ write_cache_file
+
File.chmod(dir_mode, gem_dir) if dir_mode
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
+ load_plugin unless options[:install_plugin] == false
run_post_install_hooks
@@ -411,15 +384,6 @@ class Gem::Installer
end
##
- # Unpacks the gem into the given directory.
-
- def unpack(directory)
- @gem_dir = directory
- extract_files
- end
- rubygems_deprecate :unpack
-
- ##
# The location of the spec file that is installed.
#
@@ -427,12 +391,18 @@ class Gem::Installer
File.join gem_home, "specifications", "#{spec.full_name}.gemspec"
end
+ def default_spec_dir
+ dir = File.join(gem_home, "specifications", "default")
+ FileUtils.mkdir_p dir
+ dir
+ end
+
##
# The location of the default spec file for default gems.
#
def default_spec_file
- File.join gem_home, "specifications", "default", "#{spec.full_name}.gemspec"
+ File.join default_spec_dir, "#{spec.full_name}.gemspec"
end
##
@@ -670,6 +640,7 @@ class Gem::Installer
@build_root = options[:build_root]
@build_args = options[:build_args]
+ @build_jobs = options[:build_jobs]
@gem_home = @install_dir || user_install_dir || Gem.dir
@@ -749,54 +720,53 @@ class Gem::Installer
def app_script_text(bin_file_name)
# NOTE: that the `load` lines cannot be indented, as old RG versions match
# against the beginning of the line
- <<-TEXT
-#{shebang bin_file_name}
-#
-# This file was generated by RubyGems.
-#
-# The application '#{spec.name}' is installed as part of a gem, and
-# this file is here to facilitate running it.
-#
-
-require 'rubygems'
-#{gemdeps_load(spec.name)}
-version = "#{Gem::Requirement.default_prerelease}"
-
-str = ARGV.first
-if str
- str = str.b[/\\A_(.*)_\\z/, 1]
- if str and Gem::Version.correct?(str)
- #{explicit_version_requirement(spec.name)}
- ARGV.shift
- end
-end
+ <<~TEXT
+ #{shebang bin_file_name}
+ #
+ # This file was generated by RubyGems.
+ #
+ # The application '#{spec.name}' is installed as part of a gem, and
+ # this file is here to facilitate running it.
+ #
+
+ require 'rubygems'
+ #{gemdeps_load(spec.name)}
+ version = "#{Gem::Requirement.default_prerelease}"
+
+ str = ARGV.first
+ if str
+ str = str.b[/\\A_(.*)_\\z/, 1]
+ if str and Gem::Version.correct?(str)
+ #{explicit_version_requirement(spec.name)}
+ ARGV.shift
+ end
+ end
-if Gem.respond_to?(:activate_bin_path)
-load Gem.activate_bin_path('#{spec.name}', '#{bin_file_name}', version)
-else
-gem #{spec.name.dump}, version
-load Gem.bin_path(#{spec.name.dump}, #{bin_file_name.dump}, version)
-end
-TEXT
+ if Gem.respond_to?(:activate_and_load_bin_path)
+ Gem.activate_and_load_bin_path('#{spec.name}', '#{bin_file_name}', version)
+ else
+ load Gem.activate_bin_path('#{spec.name}', '#{bin_file_name}', version)
+ end
+ TEXT
end
def gemdeps_load(name)
return "" if name == "bundler"
- <<-TEXT
+ <<~TEXT
-Gem.use_gemdeps
-TEXT
+ Gem.use_gemdeps
+ TEXT
end
def explicit_version_requirement(name)
code = "version = str"
return code unless name == "bundler"
- code += <<-TEXT
+ code += <<~TEXT
- ENV['BUNDLER_VERSION'] = str
-TEXT
+ ENV['BUNDLER_VERSION'] = str
+ TEXT
end
##
@@ -811,9 +781,9 @@ TEXT
if File.exist?(File.join(bindir, ruby_exe))
# stub & ruby.exe within same folder. Portable
- <<-TEXT
-@ECHO OFF
-@"%~dp0#{ruby_exe}" "%~dpn0" %*
+ <<~TEXT
+ @ECHO OFF
+ @"%~dp0#{ruby_exe}" "%~dpn0" %*
TEXT
elsif bindir.downcase.start_with? rb_topdir.downcase
# stub within ruby folder, but not standard bin. Portable
@@ -821,16 +791,16 @@ TEXT
from = Pathname.new bindir
to = Pathname.new "#{rb_topdir}/bin"
rel = to.relative_path_from from
- <<-TEXT
-@ECHO OFF
-@"%~dp0#{rel}/#{ruby_exe}" "%~dpn0" %*
+ <<~TEXT
+ @ECHO OFF
+ @"%~dp0#{rel}/#{ruby_exe}" "%~dpn0" %*
TEXT
else
# outside ruby folder, maybe -user-install or bundler. Portable, but ruby
# is dependent on PATH
- <<-TEXT
-@ECHO OFF
-@#{ruby_exe} "%~dpn0" %*
+ <<~TEXT
+ @ECHO OFF
+ @#{ruby_exe} "%~dpn0" %*
TEXT
end
end
@@ -839,11 +809,37 @@ TEXT
# configure scripts and rakefiles or mkrf_conf files.
def build_extensions
- builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig
+ if options[:build_extension] == false
+ warn_skipped_extensions
+ return
+ end
+
+ builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig, build_jobs
builder.build_extensions
end
+ def warn_skipped_extensions # :nodoc:
+ return if spec.extensions.empty?
+
+ alert_warning "#{spec.full_name} contains native extensions that were not built.\n" \
+ "To build extensions, run: gem pristine #{spec.name} --extensions"
+ end
+
+ def warn_skipped_plugins # :nodoc:
+ return if spec.plugins.empty?
+
+ alert_warning "#{spec.full_name} contains plugins that were not installed.\n" \
+ "To install plugins, run: gem pristine #{spec.name} --only-plugins"
+ end
+
+ def remove_stale_plugins # :nodoc:
+ return unless spec.plugins.empty?
+
+ ensure_writable_dir @plugins_dir
+ remove_plugins_for(spec, @plugins_dir)
+ end
+
##
# Reads the file index and extracts each file into the gem directory.
#
@@ -908,11 +904,7 @@ TEXT
ensure_loadable_spec
- if options[:install_as_default]
- Gem.ensure_default_gem_subdirectories gem_home
- else
- Gem.ensure_gem_subdirectories gem_home
- end
+ Gem.ensure_gem_subdirectories gem_home
return true if @force
@@ -953,11 +945,8 @@ TEXT
end
def ensure_writable_dir(dir) # :nodoc:
- begin
- Dir.mkdir dir, *[options[:dir_mode] && 0o755].compact
- rescue SystemCallError
- raise unless File.directory? dir
- end
+ require "fileutils"
+ FileUtils.mkdir_p dir, mode: options[:dir_mode] && 0o755
raise Gem::FilePermissionError.new(dir) unless File.writable? dir
end
@@ -984,6 +973,15 @@ TEXT
end
end
+ def build_jobs
+ @build_jobs ||= begin
+ require "etc"
+ Etc.nprocessors + 1
+ rescue LoadError
+ 1
+ end
+ end
+
def rb_config
Gem.target_rbconfig
end
@@ -1023,9 +1021,10 @@ TEXT
# 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)}")
+ plugin_files = spec.plugins.filter_map do |plugin|
+ path = File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}")
+ path if File.exist?(path)
end
- Gem.load_plugin_files(plugin_files)
+ Gem.load_plugin_files(plugin_files) unless plugin_files.empty?
end
end
diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb
index 3f4a6fcf3d..cbdf4d7ac5 100644
--- a/lib/rubygems/name_tuple.rb
+++ b/lib/rubygems/name_tuple.rb
@@ -6,7 +6,7 @@
# wrap the data returned from the indexes.
class Gem::NameTuple
- def initialize(name, version, platform=Gem::Platform::RUBY)
+ def initialize(name, version, platform = Gem::Platform::RUBY)
@name = name
@version = version
@@ -81,6 +81,12 @@ class Gem::NameTuple
[@name, @version, @platform]
end
+ alias_method :deconstruct, :to_a
+
+ def deconstruct_keys(keys)
+ { name: @name, version: @version, platform: @platform }
+ end
+
def inspect # :nodoc:
"#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>"
end
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index c855423ed7..7e41b18f66 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -7,6 +7,7 @@
# rubocop:enable Style/AsciiComments
+require_relative "win_platform"
require_relative "security"
require_relative "user_interaction"
@@ -231,7 +232,11 @@ class Gem::Package
tar.add_file_signed "checksums.yaml.gz", 0o444, @signer do |io|
gzip_to io do |gz_io|
- Psych.dump checksums_by_algorithm, gz_io
+ if Gem.use_psych?
+ Psych.dump checksums_by_algorithm, gz_io
+ else
+ gz_io.write Gem::YAMLSerializer.dump(checksums_by_algorithm)
+ end
end
end
end
@@ -267,7 +272,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)
+ copy_stream(src_io, dst_io, stat.size)
end
end
end
@@ -436,8 +441,6 @@ EOM
symlinks << [full_name, link_target, destination, real_destination]
end
- FileUtils.rm_rf destination
-
mkdir =
if entry.directory?
destination
@@ -450,9 +453,20 @@ EOM
directories << mkdir
end
+ real_mkdir = File.realpath(mkdir)
+ unless real_mkdir == destination_dir || normalize_path(real_mkdir).start_with?(normalize_path(destination_dir + "/"))
+ raise Gem::Package::PathError.new(real_mkdir, destination_dir)
+ 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") do |out|
+ copy_stream(tar.io, out, entry.size)
+ # Flush needs to happen before chmod because there could be data
+ # in the IO buffer that needs to be written, and that could be
+ # written after the chmod (on close) which would mess up the perms
+ out.flush
+ out.chmod file_mode(entry.header.mode) & ~File.umask
+ end
end
verbose destination
@@ -461,7 +475,7 @@ EOM
symlinks.each do |name, target, destination, real_destination|
if File.exist?(real_destination)
- File.symlink(target, destination)
+ create_symlink(target, destination)
else
alert_warning "#{@spec.full_name} ships with a dangling symlink named #{name} pointing to missing #{target} file. Ignoring"
end
@@ -514,10 +528,12 @@ EOM
destination
end
- def normalize_path(pathname)
- if Gem.win_platform?
+ if Gem.win_platform?
+ def normalize_path(pathname) # :nodoc:
pathname.downcase
- else
+ end
+ else
+ def normalize_path(pathname) # :nodoc:
pathname
end
end
@@ -525,7 +541,7 @@ EOM
##
# Loads a Gem::Specification from the TarEntry +entry+
- def load_spec(entry) # :nodoc:
+ def load_spec_from_metadata(entry) # :nodoc:
limit = 10 * 1024 * 1024
case entry.full_name
when "metadata" then
@@ -545,6 +561,15 @@ EOM
tar = Gem::Package::TarReader.new gzio
yield tar
+ ensure
+ # Consume remaining gzip data to prevent the
+ # "attempt to close unfinished zstream; reset forced" warning
+ # when the GzipReader is closed with unconsumed compressed data.
+ begin
+ IO.copy_stream(gzio, IO::NULL)
+ rescue Zlib::GzipFile::Error, IOError
+ nil
+ end
end
end
@@ -635,6 +660,8 @@ EOM
raise Gem::Package::FormatError.new e.message, @gem
end
+ private
+
##
# Verifies the +checksums+ against the +digests+. This check is not
# cryptographically secure. Missing checksums are ignored.
@@ -669,12 +696,7 @@ EOM
digest entry
end
- case file_name
- when "metadata", "metadata.gz" then
- load_spec entry
- when "data.tar.gz" then
- verify_gz entry
- end
+ load_spec_from_metadata entry
rescue StandardError
warn "Exception while verifying #{@gem.path}"
raise
@@ -702,25 +724,13 @@ EOM
end
end
- ##
- # Verifies that +entry+ is a valid gzipped file.
-
- 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
- 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
+ def copy_stream(src, dst, size) # :nodoc:
+ dst.write src.read(size)
end
else
- def copy_stream(src, dst) # :nodoc:
- IO.copy_stream(src, dst)
+ def copy_stream(src, dst, size) # :nodoc:
+ IO.copy_stream(src, dst, size)
end
end
@@ -729,6 +739,23 @@ EOM
raise Gem::Package::FormatError, "#{name} is too big (over #{limit} bytes)" if bytes.size > limit
bytes
end
+
+ if Gem.win_platform?
+ # Create a symlink and fallback to copy the file or directory on Windows,
+ # where symlink creation needs special privileges in form of the Developer Mode.
+ # JRuby on Windows raises TypeError from the wincode path-conversion helper
+ # when it cannot create the symlink, so fall back to copy in that case too.
+ def create_symlink(old_name, new_name)
+ File.symlink(old_name, new_name)
+ rescue Errno::EACCES, TypeError
+ from = File.expand_path(old_name, File.dirname(new_name))
+ FileUtils.cp_r(from, new_name)
+ end
+ else
+ def create_symlink(old_name, new_name)
+ File.symlink(old_name, new_name)
+ end
+ end
end
require_relative "package/digest_io"
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index 0ebcbd789d..dd20d65080 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -56,7 +56,7 @@ class Gem::Package::TarHeader
##
# Pack format for a tar header
- PACK_FORMAT = "a100" + # name
+ PACK_FORMAT = ("a100" + # name
"a8" + # mode
"a8" + # uid
"a8" + # gid
@@ -71,12 +71,12 @@ class Gem::Package::TarHeader
"a32" + # gname
"a8" + # devmajor
"a8" + # devminor
- "a155" # prefix
+ "a155").freeze # prefix
##
# Unpack format for a tar header
- UNPACK_FORMAT = "A100" + # name
+ UNPACK_FORMAT = ("A100" + # name
"A8" + # mode
"A8" + # uid
"A8" + # gid
@@ -91,7 +91,7 @@ class Gem::Package::TarHeader
"A32" + # gname
"A8" + # devmajor
"A8" + # devminor
- "A155" # prefix
+ "A155").freeze # prefix
attr_reader(*FIELDS)
diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb
index 25f9b2f945..b66a8a62bc 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -30,6 +30,8 @@ class Gem::Package::TarReader
nil
end
+ attr_reader :io # :nodoc:
+
##
# Creates a new tar file reader on +io+ which needs to respond to #pos,
# #eof?, #read, #getc and #pos=
diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb
index b24bdb63e7..39fed9e2af 100644
--- a/lib/rubygems/package/tar_writer.rb
+++ b/lib/rubygems/package/tar_writer.rb
@@ -95,10 +95,11 @@ class Gem::Package::TarWriter
end
##
- # Adds file +name+ with permissions +mode+, and yields an IO for writing the
- # file to
+ # Adds file +name+ with permissions +mode+ and mtime +mtime+ (sets
+ # Gem.source_date_epoch if not specified), and yields an IO for
+ # writing the file to
- def add_file(name, mode) # :yields: io
+ def add_file(name, mode, mtime = nil) # :yields: io
check_closed
name, prefix = split_name name
@@ -118,7 +119,7 @@ class Gem::Package::TarWriter
header = Gem::Package::TarHeader.new name: name, mode: mode,
size: size, prefix: prefix,
- mtime: Gem.source_date_epoch
+ mtime: mtime || Gem.source_date_epoch
@io.write header
@io.pos = final_pos
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 450c214167..367b00e7e1 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
-
##
# Available list of platforms for targeting Gem installations.
#
@@ -21,15 +19,6 @@ class Gem::Platform
end
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|
@@ -88,56 +77,45 @@ class Gem::Platform
when Array then
@cpu, @os, @version = arch
when String then
- arch = arch.split "-"
-
- if arch.length > 2 && !arch.last.match?(/\d+(\.\d+)?$/) # reassemble x86-linux-{libc}
- extra = arch.pop
- arch.last << "-#{extra}"
- end
+ cpu, os = arch.sub(/-+$/, "").split("-", 2)
- cpu = arch.shift
-
- @cpu = case cpu
- when /i\d86/ then "x86"
- else cpu
- end
-
- if arch.length == 2 && arch.last.match?(/^\d+(\.\d+)?$/) # for command-line
- @os, @version = arch
- return
+ @cpu = if cpu&.match?(/i\d86/)
+ "x86"
+ else
+ cpu
end
- os, = arch
if os.nil?
@cpu = nil
os = cpu
end # 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
+ when /aix-?(\d+)?/ then ["aix", $1]
+ when /cygwin/ then ["cygwin", nil]
+ when /darwin-?(\d+)?/ then ["darwin", $1]
+ when "macruby" then ["macruby", nil]
+ when /^macruby-?(\d+(?:\.\d+)*)?/ then ["macruby", $1]
+ when /freebsd-?(\d+)?/ then ["freebsd", $1]
+ when "java", "jruby" then ["java", nil]
+ when /^java-?(\d+(?:\.\d+)*)?/ then ["java", $1]
+ when /^dalvik-?(\d+)?$/ then ["dalvik", $1]
+ when /^dotnet$/ then ["dotnet", nil]
+ when /^dotnet-?(\d+(?:\.\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$/
+ version = $2
+ @cpu = "x86" if @cpu.nil? && os.end_with?("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]
+ 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]
+ when /^(\w+_platform)-?(\d+)?/ then [$1, $2]
else ["unknown", nil]
end
when Gem::Platform then
@@ -154,7 +132,38 @@ class Gem::Platform
end
def to_s
- to_a.compact.join "-"
+ to_a.compact.join(@cpu.nil? ? "" : "-")
+ end
+
+ ##
+ # Deconstructs the platform into an array for pattern matching.
+ # Returns [cpu, os, version].
+ #
+ # Gem::Platform.new("x86_64-linux").deconstruct #=> ["x86_64", "linux", nil]
+ #
+ # This enables array pattern matching:
+ #
+ # case Gem::Platform.new("arm64-darwin-21")
+ # in ["arm64", "darwin", version]
+ # # version => "21"
+ # end
+ alias_method :deconstruct, :to_a
+
+ ##
+ # Deconstructs the platform into a hash for pattern matching.
+ # Returns a hash with keys +:cpu+, +:os+, and +:version+.
+ #
+ # Gem::Platform.new("x86_64-darwin-20").deconstruct_keys(nil)
+ # #=> { cpu: "x86_64", os: "darwin", version: "20" }
+ #
+ # This enables hash pattern matching:
+ #
+ # case Gem::Platform.new("x86_64-linux")
+ # in cpu: "x86_64", os: "linux"
+ # # Matches Linux on x86_64
+ # end
+ def deconstruct_keys(keys)
+ { cpu: @cpu, os: @os, version: @version }
end
##
@@ -266,4 +275,118 @@ class Gem::Platform
# This will be replaced with Gem::Platform::local.
CURRENT = "current"
+
+ JAVA = Gem::Platform.new("java") # :nodoc:
+ MSWIN = Gem::Platform.new("mswin32") # :nodoc:
+ MSWIN64 = Gem::Platform.new("mswin64") # :nodoc:
+ MINGW = Gem::Platform.new("x86-mingw32") # :nodoc:
+ X64_MINGW_LEGACY = Gem::Platform.new("x64-mingw32") # :nodoc:
+ X64_MINGW = Gem::Platform.new("x64-mingw-ucrt") # :nodoc:
+ UNIVERSAL_MINGW = Gem::Platform.new("universal-mingw") # :nodoc:
+ WINDOWS = [MSWIN, MSWIN64, UNIVERSAL_MINGW].freeze # :nodoc:
+ X64_LINUX = Gem::Platform.new("x86_64-linux") # :nodoc:
+ X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl") # :nodoc:
+
+ GENERICS = [JAVA, *WINDOWS].freeze # :nodoc:
+ private_constant :GENERICS
+
+ GENERIC_CACHE = GENERICS.each_with_object({}) {|g, h| h[g] = g } # :nodoc:
+ private_constant :GENERIC_CACHE
+
+ class << self
+ ##
+ # Returns the generic platform for the given platform.
+
+ def generic(platform)
+ return Gem::Platform::RUBY if platform.nil? || platform == Gem::Platform::RUBY
+
+ GENERIC_CACHE[platform] ||= begin
+ found = GENERICS.find do |match|
+ platform === match
+ end
+ found || Gem::Platform::RUBY
+ end
+ end
+
+ ##
+ # Returns the platform specificity match for the given spec platform and user platform.
+
+ def platform_specificity_match(spec_platform, user_platform)
+ return -1 if spec_platform == user_platform
+ return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
+
+ os_match(spec_platform, user_platform) +
+ cpu_match(spec_platform, user_platform) * 10 +
+ version_match(spec_platform, user_platform) * 100
+ end
+
+ ##
+ # Sorts and filters the best platform match for the given matching specs and platform.
+
+ def sort_and_filter_best_platform_match(matching, platform)
+ return matching if matching.one?
+
+ exact = matching.select {|spec| spec.platform == platform }
+ return exact if exact.any?
+
+ sorted_matching = sort_best_platform_match(matching, platform)
+ exemplary_spec = sorted_matching.first
+
+ sorted_matching.take_while {|spec| same_specificity?(platform, spec, exemplary_spec) && same_deps?(spec, exemplary_spec) }
+ end
+
+ ##
+ # Sorts the best platform match for the given matching specs and platform.
+
+ def sort_best_platform_match(matching, platform)
+ matching.sort_by.with_index do |spec, i|
+ [
+ platform_specificity_match(spec.platform, platform),
+ i, # for stable sort
+ ]
+ end
+ end
+
+ private
+
+ def same_specificity?(platform, spec, exemplary_spec)
+ platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform)
+ end
+
+ def same_deps?(spec, exemplary_spec)
+ spec.required_ruby_version == exemplary_spec.required_ruby_version &&
+ spec.required_rubygems_version == exemplary_spec.required_rubygems_version &&
+ spec.dependencies.sort == exemplary_spec.dependencies.sort
+ end
+
+ def os_match(spec_platform, user_platform)
+ if spec_platform.os == user_platform.os
+ 0
+ else
+ 1
+ end
+ end
+
+ def cpu_match(spec_platform, user_platform)
+ if spec_platform.cpu == user_platform.cpu
+ 0
+ elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm")
+ 0
+ elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal"
+ 1
+ else
+ 2
+ end
+ end
+
+ def version_match(spec_platform, user_platform)
+ if spec_platform.version == user_platform.version
+ 0
+ elsif spec_platform.version.nil?
+ 1
+ else
+ 2
+ end
+ end
+ end
end
diff --git a/lib/rubygems/psych_tree.rb b/lib/rubygems/psych_tree.rb
index 24857adb9d..8b4c425a33 100644
--- a/lib/rubygems/psych_tree.rb
+++ b/lib/rubygems/psych_tree.rb
@@ -22,7 +22,7 @@ module Gem
def register(target, obj)
end
- # This is ported over from the yaml_tree in 1.9.3
+ # This is ported over from the YAMLTree implementation in Ruby 1.9.3
def format_time(time)
if time.utc?
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 4b5c74e0ea..5b83dc6f6f 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -72,7 +72,7 @@ class Gem::RemoteFetcher
# +headers+: A set of additional HTTP headers to be sent to the server when
# fetching the gem.
- def initialize(proxy=nil, dns=nil, headers={})
+ 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"
@@ -82,6 +82,7 @@ class Gem::RemoteFetcher
@proxy = proxy
@pools = {}
@pool_lock = Thread::Mutex.new
+ @pool_size = 1
@cert_files = Gem::Request.get_cert_files
@headers = headers
@@ -110,9 +111,13 @@ class Gem::RemoteFetcher
# always replaced.
def download(spec, source_uri, install_dir = Gem.dir)
+ gem_file_name = File.basename spec.cache_file
+
install_cache_dir = File.join install_dir, "cache"
cache_dir =
- if Dir.pwd == install_dir # see fetch_command
+ if Gem.configuration.global_gem_cache
+ Gem.global_gem_cache_path
+ elsif Dir.pwd == install_dir # see fetch_command
install_dir
elsif File.writable?(install_cache_dir) || (File.writable?(install_dir) && !File.exist?(install_cache_dir))
install_cache_dir
@@ -120,7 +125,6 @@ class Gem::RemoteFetcher
File.join Gem.user_dir, "cache"
end
- gem_file_name = File.basename spec.cache_file
local_gem_path = File.join cache_dir, gem_file_name
require "fileutils"
@@ -173,7 +177,7 @@ class Gem::RemoteFetcher
end
verbose "Using local gem #{local_gem_path}"
- when nil then # TODO: test for local overriding cache
+ when nil then
source_path = if Gem.win_platform? && source_uri.scheme &&
!source_uri.path.include?(":")
"#{source_uri.scheme}:#{source_uri.path}"
@@ -233,7 +237,9 @@ class Gem::RemoteFetcher
fetch_http(location, last_modified, head, depth + 1)
else
- raise FetchError.new("bad response #{response.message} #{response.code}", uri)
+ custom_error = response["X-Error-Message"]
+ error_detail = custom_error || response.message
+ raise FetchError.new("Bad response #{error_detail} #{response.code}", uri)
end
end
@@ -245,11 +251,14 @@ class Gem::RemoteFetcher
def fetch_path(uri, mtime = nil, head = false)
uri = Gem::Uri.new uri
- unless uri.scheme
- raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}"
- end
+ method = {
+ "http" => "fetch_http",
+ "https" => "fetch_http",
+ "s3" => "fetch_s3",
+ "file" => "fetch_file",
+ }.fetch(uri.scheme) { raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}" }
- data = send "fetch_#{uri.scheme}", uri, mtime, head
+ data = send method, uri, mtime, head
if data && !head && uri.to_s.end_with?(".gz")
begin
@@ -267,7 +276,7 @@ class Gem::RemoteFetcher
def fetch_s3(uri, mtime = nil, head = false)
begin
- public_uri = s3_uri_signer(uri).sign
+ public_uri = s3_uri_signer(uri, head ? "HEAD" : "GET").sign
rescue Gem::S3URISigner::ConfigurationError, Gem::S3URISigner::InstanceProfileError => e
raise FetchError.new(e.message, "s3://#{uri.host}")
end
@@ -275,8 +284,8 @@ class Gem::RemoteFetcher
end
# we have our own signing code here to avoid a dependency on the aws-sdk gem
- def s3_uri_signer(uri)
- Gem::S3URISigner.new(uri)
+ def s3_uri_signer(uri, method)
+ Gem::S3URISigner.new(uri, method)
end
##
@@ -335,7 +344,7 @@ class Gem::RemoteFetcher
def pools_for(proxy)
@pool_lock.synchronize do
- @pools[proxy] ||= Gem::Request::ConnectionPools.new proxy, @cert_files
+ @pools[proxy] ||= Gem::Request::ConnectionPools.new proxy, @cert_files, @pool_size
end
end
end
diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb
index 9116785231..e817ee5704 100644
--- a/lib/rubygems/request.rb
+++ b/lib/rubygems/request.rb
@@ -2,6 +2,7 @@
require_relative "vendored_net_http"
require_relative "user_interaction"
+require_relative "uri_formatter"
class Gem::Request
extend Gem::UserInteraction
diff --git a/lib/rubygems/request/connection_pools.rb b/lib/rubygems/request/connection_pools.rb
index 6c1b04ab65..01e7e0629a 100644
--- a/lib/rubygems/request/connection_pools.rb
+++ b/lib/rubygems/request/connection_pools.rb
@@ -7,11 +7,12 @@ class Gem::Request::ConnectionPools # :nodoc:
attr_accessor :client
end
- def initialize(proxy_uri, cert_files)
+ def initialize(proxy_uri, cert_files, pool_size = 1)
@proxy_uri = proxy_uri
@cert_files = cert_files
@pools = {}
@pool_mutex = Thread::Mutex.new
+ @pool_size = pool_size
end
def pool_for(uri)
@@ -20,9 +21,9 @@ class Gem::Request::ConnectionPools # :nodoc:
@pool_mutex.synchronize do
@pools[key] ||=
if https? uri
- Gem::Request::HTTPSPool.new(http_args, @cert_files, @proxy_uri)
+ Gem::Request::HTTPSPool.new(http_args, @cert_files, @proxy_uri, @pool_size)
else
- Gem::Request::HTTPPool.new(http_args, @cert_files, @proxy_uri)
+ Gem::Request::HTTPPool.new(http_args, @cert_files, @proxy_uri, @pool_size)
end
end
end
diff --git a/lib/rubygems/request/http_pool.rb b/lib/rubygems/request/http_pool.rb
index 52543de41f..468502ca6b 100644
--- a/lib/rubygems/request/http_pool.rb
+++ b/lib/rubygems/request/http_pool.rb
@@ -9,12 +9,14 @@
class Gem::Request::HTTPPool # :nodoc:
attr_reader :cert_files, :proxy_uri
- def initialize(http_args, cert_files, proxy_uri)
+ def initialize(http_args, cert_files, proxy_uri, pool_size)
@http_args = http_args
@cert_files = cert_files
@proxy_uri = proxy_uri
- @queue = Thread::SizedQueue.new 1
- @queue << nil
+ @pool_size = pool_size
+
+ @queue = Thread::SizedQueue.new @pool_size
+ setup_queue
end
def checkout
@@ -31,7 +33,8 @@ class Gem::Request::HTTPPool # :nodoc:
connection.finish
end
end
- @queue.push(nil)
+
+ setup_queue
end
private
@@ -44,4 +47,8 @@ class Gem::Request::HTTPPool # :nodoc:
connection.start
connection
end
+
+ def setup_queue
+ @pool_size.times { @queue.push(nil) }
+ end
end
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index 875df7e019..eb8b4658f3 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -181,13 +181,10 @@ class Gem::RequestSet
# Install requested gems after they have been downloaded
sorted_requests.each do |req|
- if req.installed?
- req.spec.spec.build_extensions
-
- if @always_install.none? {|spec| spec == req.spec.spec }
- yield req, nil if block_given?
- next
- end
+ if req.installed? && @always_install.none? {|spec| spec == req.spec.spec }
+ req.spec.spec.build_extensions unless options[:build_extension] == false
+ yield req, nil if block_given?
+ next
end
spec =
@@ -237,10 +234,6 @@ class Gem::RequestSet
sorted_requests.each do |spec|
puts " #{spec.full_name}"
end
-
- if Gem.configuration.really_verbose
- @resolver.stats.display
- end
else
installed = install options, &block
@@ -325,11 +318,8 @@ class Gem::RequestSet
@git_set.root_dir = @install_dir
lock_file = "#{File.expand_path(path)}.lock"
- begin
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file
- parser = tokenizer.make_parser self, []
- parser.parse
- rescue Errno::ENOENT
+ if File.exist?(lock_file)
+ load_lockfile lock_file
end
gf = Gem::RequestSet::GemDependencyAPI.new self, path
@@ -338,6 +328,63 @@ class Gem::RequestSet
gf.load
end
+ def load_lockfile(lock_file) # :nodoc:
+ require "bundler"
+ require "bundler/lockfile_parser"
+
+ # Bundler::Source::Path resolves relative `remote:` paths against
+ # Bundler.root, which raises when there is no Gemfile in the working
+ # directory. Anchor it to the lockfile's directory so PATH sections in a
+ # `gem install -g` lockfile can be parsed without a Bundler environment.
+ previous_root = Bundler.instance_variable_get(:@root)
+ Bundler.instance_variable_set(:@root, Pathname.new(File.expand_path(File.dirname(lock_file))))
+
+ parser = Bundler::LockfileParser.new(File.read(lock_file), lockfile_path: lock_file)
+
+ parser.specs.group_by(&:source).each do |source, specs|
+ case source
+ when Bundler::Source::Rubygems
+ remotes = source.remotes.map {|remote| Gem::Source.new(remote.to_s) }
+ remotes << Gem::Source.new(Gem::DEFAULT_HOST) if remotes.empty?
+ lock_set = Gem::Resolver::LockSet.new(remotes)
+ specs.each do |spec|
+ added = lock_set.add(spec.name, spec.version.to_s, spec.platform)
+ spec.dependencies.each do |dep|
+ added.each {|s| s.add_dependency dep }
+ end
+ end
+ @sets << lock_set
+ when Bundler::Source::Git
+ git_set = Gem::Resolver::GitSet.new
+ git_set.root_dir = @install_dir
+ specs.each do |spec|
+ git_spec = git_set.add_git_spec(
+ spec.name,
+ spec.version.to_s,
+ source.uri.to_s,
+ source.revision,
+ source.submodules || false
+ )
+ spec.dependencies.each {|dep| git_spec.add_dependency dep }
+ end
+ @sets << git_set
+ when Bundler::Source::Path
+ vendor_set = Gem::Resolver::VendorSet.new
+ specs.each do |spec|
+ loaded = vendor_set.add_vendor_gem(spec.name, source.path.to_s)
+ spec.dependencies.each {|dep| loaded.dependencies << dep }
+ end
+ @sets << vendor_set
+ end
+ end
+
+ parser.dependencies.each_value do |dep|
+ gem dep.name, *dep.requirement.as_list
+ end
+ ensure
+ Bundler.instance_variable_set(:@root, previous_root) if defined?(previous_root)
+ end
+
def pretty_print(q) # :nodoc:
q.group 2, "[RequestSet:", "]" do
q.breakable
@@ -465,4 +512,3 @@ end
require_relative "request_set/gem_dependency_api"
require_relative "request_set/lockfile"
-require_relative "request_set/lockfile/tokenizer"
diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb
index c446b3ae51..8b9c9690d6 100644
--- a/lib/rubygems/request_set/lockfile.rb
+++ b/lib/rubygems/request_set/lockfile.rb
@@ -38,7 +38,7 @@ class Gem::RequestSet::Lockfile
end
##
- # Creates a new Lockfile for the given +request_set+ and +gem_deps_file+
+ # Creates a new Lockfile for the given Gem::RequestSet and +gem_deps_file+
# location.
def self.build(request_set, gem_deps_file, dependencies = nil)
@@ -231,5 +231,3 @@ class Gem::RequestSet::Lockfile
@set.sorted_requests
end
end
-
-require_relative "lockfile/tokenizer"
diff --git a/lib/rubygems/request_set/lockfile/parser.rb b/lib/rubygems/request_set/lockfile/parser.rb
deleted file mode 100644
index e751a1445e..0000000000
--- a/lib/rubygems/request_set/lockfile/parser.rb
+++ /dev/null
@@ -1,344 +0,0 @@
-# frozen_string_literal: true
-
-class Gem::RequestSet::Lockfile::Parser
- ###
- # Parses lockfiles
-
- def initialize(tokenizer, set, platforms, filename = nil)
- @tokens = tokenizer
- @filename = filename
- @set = set
- @platforms = platforms
- end
-
- def parse
- until @tokens.empty? do
- token = get
-
- case token.type
- when :section then
- @tokens.skip :newline
-
- case token.value
- when "DEPENDENCIES" then
- parse_DEPENDENCIES
- when "GIT" then
- parse_GIT
- when "GEM" then
- parse_GEM
- when "PATH" then
- parse_PATH
- when "PLATFORMS" then
- parse_PLATFORMS
- else
- token = get until @tokens.empty? || peek.first == :section
- end
- else
- raise "BUG: unhandled token #{token.type} (#{token.value.inspect}) at line #{token.line} column #{token.column}"
- end
- end
- end
-
- ##
- # Gets the next token for a Lockfile
-
- def get(expected_types = nil, expected_value = nil) # :nodoc:
- token = @tokens.shift
-
- if expected_types && !Array(expected_types).include?(token.type)
- unget token
-
- 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
- end
-
- if expected_value && expected_value != token.value
- unget token
-
- 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
- end
-
- token
- end
-
- def parse_DEPENDENCIES # :nodoc:
- while !@tokens.empty? && peek.type == :text do
- token = get :text
-
- requirements = []
-
- case peek[0]
- when :bang then
- get :bang
-
- requirements << pinned_requirement(token.value)
- when :l_paren then
- get :l_paren
-
- loop do
- op = get(:requirement).value
- version = get(:text).value
-
- requirements << "#{op} #{version}"
-
- break unless peek.type == :comma
-
- get :comma
- end
-
- get :r_paren
-
- if peek[0] == :bang
- requirements.clear
- requirements << pinned_requirement(token.value)
-
- get :bang
- end
- end
-
- @set.gem token.value, *requirements
-
- skip :newline
- end
- end
-
- def parse_GEM # :nodoc:
- sources = []
-
- while peek.first(2) == [:entry, "remote"] do
- get :entry, "remote"
- data = get(:text).value
- skip :newline
-
- sources << Gem::Source.new(data)
- end
-
- sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty?
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::LockSet.new sources
- last_specs = nil
-
- while !@tokens.empty? && peek.type == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_specs.each do |spec|
- spec.add_dependency Gem::Dependency.new name if column == 6
- end
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- version, platform = data.split "-", 2
-
- platform =
- platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
-
- last_specs = set.add name, version, platform
- else
- dependency = parse_dependency name, data
-
- last_specs.each do |spec|
- spec.add_dependency dependency
- end
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_GIT # :nodoc:
- get :entry, "remote"
- repository = get(:text).value
-
- skip :newline
-
- get :entry, "revision"
- revision = get(:text).value
-
- skip :newline
-
- type = peek.type
- value = peek.value
- if type == :entry && %w[branch ref tag].include?(value)
- get
- get :text
-
- skip :newline
- end
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::GitSet.new
- set.root_dir = @set.install_dir
-
- last_spec = nil
-
- while !@tokens.empty? && peek.type == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_spec.add_dependency Gem::Dependency.new name if column == 6
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- last_spec = set.add_git_spec name, data, repository, revision, true
- else
- dependency = parse_dependency name, data
-
- last_spec.add_dependency dependency
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_PATH # :nodoc:
- get :entry, "remote"
- directory = get(:text).value
-
- skip :newline
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::VendorSet.new
- last_spec = nil
-
- while !@tokens.empty? && peek.first == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_spec.add_dependency Gem::Dependency.new name if column == 6
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- last_spec = set.add_vendor_gem name, directory
- else
- dependency = parse_dependency name, data
-
- last_spec.dependencies << dependency
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_PLATFORMS # :nodoc:
- while !@tokens.empty? && peek.first == :text do
- name = get(:text).value
-
- @platforms << name
-
- skip :newline
- end
- end
-
- ##
- # Parses the requirements following the dependency +name+ and the +op+ for
- # the first token of the requirements and returns a Gem::Dependency object.
-
- def parse_dependency(name, op) # :nodoc:
- return Gem::Dependency.new name, op unless peek[0] == :text
-
- version = get(:text).value
-
- requirements = ["#{op} #{version}"]
-
- while peek.type == :comma do
- get :comma
- op = get(:requirement).value
- version = get(:text).value
-
- requirements << "#{op} #{version}"
- end
-
- Gem::Dependency.new name, requirements
- end
-
- private
-
- def skip(type) # :nodoc:
- @tokens.skip type
- end
-
- ##
- # Peeks at the next token for Lockfile
-
- def peek # :nodoc:
- @tokens.peek
- end
-
- def pinned_requirement(name) # :nodoc:
- requirement = Gem::Dependency.new name
- specification = @set.sets.flat_map do |set|
- set.find_all(requirement)
- end.compact.first
-
- specification&.version
- end
-
- ##
- # Ungets the last token retrieved by #get
-
- def unget(token) # :nodoc:
- @tokens.unshift token
- end
-end
diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb
deleted file mode 100644
index 65cef3baa0..0000000000
--- a/lib/rubygems/request_set/lockfile/tokenizer.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-# frozen_string_literal: true
-
-# ) frozen_string_literal: true
-require_relative "parser"
-
-class Gem::RequestSet::Lockfile::Tokenizer
- Token = Struct.new :type, :value, :column, :line
- EOF = Token.new :EOF
-
- def self.from_file(file)
- new File.read(file), file
- end
-
- def initialize(input, filename = nil, line = 0, pos = 0)
- @line = line
- @line_pos = pos
- @tokens = []
- @filename = filename
- tokenize input
- end
-
- def make_parser(set, platforms)
- Gem::RequestSet::Lockfile::Parser.new self, set, platforms, @filename
- end
-
- def to_a
- @tokens.map {|token| [token.type, token.value, token.column, token.line] }
- end
-
- def skip(type)
- @tokens.shift while !@tokens.empty? && peek.type == type
- end
-
- ##
- # Calculates the column (by byte) and the line of the current token based on
- # +byte_offset+.
-
- def token_pos(byte_offset) # :nodoc:
- [byte_offset - @line_pos, @line]
- end
-
- def empty?
- @tokens.empty?
- end
-
- def unshift(token)
- @tokens.unshift token
- end
-
- def next_token
- @tokens.shift
- end
- alias_method :shift, :next_token
-
- def peek
- @tokens.first || EOF
- end
-
- private
-
- def tokenize(input)
- require "strscan"
- s = StringScanner.new input
-
- until s.eos? do
- pos = s.pos
-
- pos = s.pos if leading_whitespace = s.scan(/ +/)
-
- if s.scan(/[<|=>]{7}/)
- message = "your #{@filename} contains merge conflict markers"
- column, line = token_pos pos
-
- raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
- end
-
- @tokens <<
- if s.scan(/\r?\n/)
-
- token = Token.new(:newline, nil, *token_pos(pos))
- @line_pos = s.pos
- @line += 1
- token
- elsif s.scan(/[A-Z]+/)
-
- if leading_whitespace
- text = s.matched
- text += s.scan(/[^\s)]*/).to_s # in case of no match
- Token.new(:text, text, *token_pos(pos))
- else
- Token.new(:section, s.matched, *token_pos(pos))
- end
- elsif s.scan(/([a-z]+):\s/)
-
- s.pos -= 1 # rewind for possible newline
- Token.new(:entry, s[1], *token_pos(pos))
- elsif s.scan(/\(/)
-
- Token.new(:l_paren, nil, *token_pos(pos))
- elsif s.scan(/\)/)
-
- Token.new(:r_paren, nil, *token_pos(pos))
- elsif s.scan(/<=|>=|=|~>|<|>|!=/)
-
- Token.new(:requirement, s.matched, *token_pos(pos))
- elsif s.scan(/,/)
-
- Token.new(:comma, nil, *token_pos(pos))
- elsif s.scan(/!/)
-
- Token.new(:bang, nil, *token_pos(pos))
- elsif s.scan(/[^\s),!]*/)
-
- Token.new(:text, s.matched, *token_pos(pos))
- else
- raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
- end
- end
-
- @tokens
- end
-end
diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb
index 35d83abd2d..788206c056 100644
--- a/lib/rubygems/resolver.rb
+++ b/lib/rubygems/resolver.rb
@@ -2,7 +2,6 @@
require_relative "dependency"
require_relative "exceptions"
-require_relative "util/list"
##
# Given a set of Gem::Dependency objects as +needed+ and a way to query the
@@ -11,7 +10,7 @@ require_relative "util/list"
# all the requirements.
class Gem::Resolver
- require_relative "vendored_molinillo"
+ require_relative "vendored_pub_grub"
##
# If the DEBUG_RESOLVER environment variable is set then debugging mode is
@@ -36,11 +35,6 @@ class Gem::Resolver
attr_accessor :ignore_dependencies
##
- # List of dependencies that could not be found in the configured sources.
-
- attr_reader :stats
-
- ##
# Hash of gems to skip resolution. Keyed by gem name, with arrays of
# gem specifications as values.
@@ -105,219 +99,449 @@ class Gem::Resolver
@ignore_dependencies = false
@skip_gems = {}
@soft_missing = false
- @stats = Gem::Resolver::Stats.new
- end
- def explain(stage, *data) # :nodoc:
- return unless DEBUG_RESOLVER
+ @root_package = RootPackage.new
+ @root_version = Gem::PubGrub::Package.root_version
+
+ @packages = {}
- d = data.map(&:pretty_inspect).join(", ")
- $stderr.printf "%10s %s\n", stage.to_s.upcase, d
+ @unfiltered_specs = Hash.new {|h, name| h[name] = find_unfiltered_specs_for(name) }
+ @all_specs = Hash.new {|h, name| h[name] = filter_specs(@unfiltered_specs[name]) }
+ @all_versions = Hash.new {|h, pkg| h[pkg] = @all_specs[pkg.to_s].map(&:version).uniq.sort }
+ @sorted_versions = Hash.new do |h, pkg|
+ h[pkg] = Gem::PubGrub::Package.root?(pkg) ? [@root_version] : @all_versions[pkg]
+ end
+ @cached_dependencies = Hash.new do |h, pkg|
+ h[pkg] = if Gem::PubGrub::Package.root?(pkg)
+ { @root_version => root_dependencies }
+ else
+ Hash.new {|v, ver| v[ver] = compute_dependencies(pkg, ver) }
+ end
+ end
+ @version_to_index = Hash.new {|h, pkg| h[pkg] = @sorted_versions[pkg].each_with_index.to_h }
+ @versions_for_cache = Hash.new {|h, pkg| h[pkg] = {} }
+ @spec_for_cache = Hash.new {|h, name| h[name] = build_spec_for_cache(name) }
end
- def explain_list(stage) # :nodoc:
- return unless DEBUG_RESOLVER
+ ##
+ # Proceed with resolution! Returns an array of ActivationRequest objects.
+
+ def resolve
+ # Pre-check: raise UnsatisfiableDependencyError for root deps with no
+ # platform match. We filter by platform ONLY here (not required_ruby_version
+ # / required_rubygems_version): a foreign-platform gem is genuinely "not
+ # found", but a gem that exists yet is incompatible with the running Ruby
+ # should flow through the solver to a DependencyResolutionError that names
+ # the Ruby requirement. That matches Bundler (which models Ruby as a
+ # synthetic dependency, so this surfaces as a solve failure) and gives a
+ # clearer message than the platform-oriented UnsatisfiableDependencyError.
+ @needed.each do |dep|
+ next if @soft_missing
+ dep_request = DependencyRequest.new(dep, nil)
+ all = @set.find_all(dep_request)
+ matching = select_local_platforms(all)
+
+ next unless matching.empty?
+
+ exc = Gem::UnsatisfiableDependencyError.new(dep_request, all)
+ exc.errors = @set.errors
+ raise exc
+ end
- data = yield
- $stderr.printf "%10s (%d entries)\n", stage.to_s.upcase, data.size
- unless data.empty?
- require "pp"
- PP.pp data, $stderr
+ solver = Gem::PubGrub::VersionSolver.new(
+ source: self,
+ root: @root_package,
+ strategy: Gem::Resolver::Strategy.new(self),
+ logger: make_logger
+ )
+ result = solver.solve
+
+ # Convert to Array<ActivationRequest>
+ needed_by_name = @needed.group_by(&:name)
+ result.filter_map do |package, version|
+ next if Gem::PubGrub::Package.root?(package)
+ spec = spec_for(package.to_s, version)
+ dep = needed_by_name[package.to_s]&.first || Gem::Dependency.new(package.to_s)
+ dep_request = DependencyRequest.new(dep, nil)
+ ActivationRequest.new(spec, dep_request)
+ end
+ rescue Gem::PubGrub::SolveFailure => e
+ extended = extract_extended_explanation(e.incompatibility)
+ if extended
+ message = "#{e.explanation}\n\n#{extended}"
+ raise Gem::DependencyResolutionError, Struct.new(:explanation).new(message)
+ else
+ raise Gem::DependencyResolutionError, e
end
end
- ##
- # Creates an ActivationRequest for the given +dep+ and the last +possible+
- # specification.
- #
- # Returns the Specification and the ActivationRequest
+ # PubGrub source interface methods
+
+ def all_versions_for(package)
+ versions = @sorted_versions[package].reverse # highest first
+ name = package.to_s
+
+ if (skip_dep_gems = skip_gems[name]) && !skip_dep_gems.empty?
+ # Conservative mode: float the already-installed (skip) versions to the
+ # front so the solver prefers them. This sets *preference* only (it feeds
+ # the strategy's version-index map); it does not restrict availability, so
+ # every version stays selectable via versions_for. When an installed
+ # version is made impossible by a downstream conflict, the solver
+ # backtracks to a newer version instead of failing. Molinillo instead
+ # hard-restricted the candidate set to skip versions and raised.
+ #
+ # This reaches the same outcome as Bundler (upgrade-over-raise) for the
+ # common single-blocked-gem case, though the mechanism differs: Bundler
+ # hard-pins locked gems and selectively unlocks + re-solves on conflict,
+ # whereas we float as a preference and let PubGrub backtrack in one solve.
+ # The float can therefore over-upgrade when several installed gems are
+ # jointly involved in a conflict; that outcome-level divergence is
+ # accepted (see test_conservative_upgrades_when_installed_blocked).
+ skip_versions = skip_dep_gems.map(&:version)
+ preferred, rest = versions.partition {|v| skip_versions.include?(v) }
+ preferred + rest
+ else
+ # Prefer already-installed versions to avoid unnecessary upgrades
+ installed_versions = @all_specs[name].
+ select {|s| s.is_a?(Gem::Resolver::InstalledSpecification) }.
+ map(&:version)
+ if installed_versions.any?
+ preferred, rest = versions.partition {|v| installed_versions.include?(v) }
+ preferred + rest
+ else
+ versions
+ end
+ end
+ end
+
+ def versions_for(package, range = Gem::PubGrub::VersionRange.any)
+ @versions_for_cache[package][range] ||= begin
+ candidates = range.select_versions(@sorted_versions[package])
+
+ if Gem::PubGrub::Package.root?(package) ||
+ (@set.respond_to?(:prerelease) && @set.prerelease) ||
+ range_admits_prerelease?(range)
+ candidates
+ elsif @all_versions[package].any? {|v| !v.prerelease? }
+ candidates.reject(&:prerelease?)
+ else
+ # Only prereleases exist for this gem; fall back to them so
+ # dependencies like `>= 1.0` can still be satisfied.
+ candidates
+ end
+ end
+ end
- def activation_request(dep, possible) # :nodoc:
- spec = possible.pop
+ def no_versions_incompatibility_for(_package, unsatisfied_term)
+ cause = Gem::PubGrub::Incompatibility::NoVersions.new(unsatisfied_term)
- explain :activate, [spec.full_name, possible.size]
- explain :possible, possible
+ name = unsatisfied_term.package.to_s
+ constraint = unsatisfied_term.constraint
+ extended_explanation = build_extended_explanation(name, constraint)
- activation_request =
- Gem::Resolver::ActivationRequest.new spec, dep, possible
+ custom_explanation = if extended_explanation
+ "#{constraint} could not be found in any repository"
+ end
- [spec, activation_request]
+ Gem::Resolver::Incompatibility.new(
+ [unsatisfied_term],
+ cause: cause,
+ custom_explanation: custom_explanation,
+ extended_explanation: extended_explanation
+ )
end
- def requests(s, act, reqs=[]) # :nodoc:
- return reqs if @ignore_dependencies
+ def incompatibilities_for(package, version)
+ package_deps = @cached_dependencies[package]
+ sorted_versions = @sorted_versions[package]
+ package_deps[version].filter_map do |dep_package_name, dep_constraint|
+ dep_package = dep_constraint.package
- s.fetch_development_dependencies if @development
+ low = high = @version_to_index[package][version]
- s.dependencies.reverse_each do |d|
- next if d.type == :development && !@development
- next if d.type == :development && @development_shallow &&
- act.development?
- next if d.type == :development && @development_shallow &&
- act.parent
+ # find version low such that all >= low share the same dep
+ while low > 0 &&
+ package_deps[sorted_versions[low - 1]][dep_package_name] == dep_constraint
+ low -= 1
+ end
+ low =
+ if low == 0
+ nil
+ else
+ sorted_versions[low]
+ end
+
+ # find version high such that all < high share the same dep
+ while high < sorted_versions.length &&
+ package_deps[sorted_versions[high]][dep_package_name] == dep_constraint
+ high += 1
+ end
+ high =
+ if high == sorted_versions.length
+ nil
+ else
+ sorted_versions[high]
+ end
+
+ range = Gem::PubGrub::VersionRange.new(min: low, max: high, include_min: !low.nil?)
+ self_constraint = Gem::PubGrub::VersionConstraint.new(package, range: range)
+
+ # No specs anywhere means an unknown package. Check @unfiltered_specs, not
+ # the filtered set, so a dep filtered out by platform/Ruby/prerelease falls
+ # through to NoVersions for proper hints instead. The band-scoped
+ # self_constraint lets clean sibling versions still resolve via backtracking.
+ if @unfiltered_specs[dep_package_name].empty?
+ cause = Gem::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint)
+ self_term = Gem::PubGrub::Term.new(self_constraint, true)
+ # PubGrub's default InvalidDependency rendering drops the version
+ # requirement ("depends on unknown package bar"). Supply a custom
+ # explanation so the missing dependency's constraint is preserved
+ # ("depends on bar = 0.5 which could not be found in any repository"),
+ # matching Molinillo's diagnostics.
+ return [Gem::PubGrub::Incompatibility.new(
+ [self_term],
+ cause: cause,
+ custom_explanation: "#{self_term.to_s(allow_every: true)} depends on #{dep_constraint} which could not be found in any repository"
+ )]
+ end
- reqs << Gem::Resolver::DependencyRequest.new(d, act)
- @stats.requirement!
+ # An empty range means the requirement is self-contradictory (e.g. `> 2, < 1`).
+ if dep_constraint.range.empty?
+ return [Gem::Resolver::Incompatibility.new(
+ [Gem::PubGrub::Term.new(self_constraint, true)],
+ cause: Gem::PubGrub::Incompatibility::NoVersions.new(dep_constraint),
+ custom_explanation: "#{dep_package_name} cannot satisfy contradictory requirements #{dep_constraint.constraint_string}"
+ )]
+ end
+
+ Gem::PubGrub::Incompatibility.new(
+ [Gem::PubGrub::Term.new(self_constraint, true), Gem::PubGrub::Term.new(dep_constraint, false)],
+ cause: :dependency
+ )
end
+ end
+
+ ##
+ # Returns the gems in +specs+ that match the local platform.
- @set.prefetch reqs
+ def select_local_platforms(specs) # :nodoc:
+ specs.select do |spec|
+ Gem::Platform.installable? spec
+ end
+ end
- @stats.record_requirements reqs
+ private
- reqs
+ def package_for(name)
+ @packages[name] ||= Gem::PubGrub::Package.new(name)
end
- include Gem::Molinillo::UI
+ def root_dependencies
+ deps = {}
+ @needed.each do |dep|
+ constraint = Gem::PubGrub::RubyGems.requirement_to_constraint(package_for(dep.name), dep.requirement)
+ deps[dep.name] = deps.key?(dep.name) ? deps[dep.name].intersect(constraint) : constraint
+ end
+ deps
+ end
- def output
- @output ||= debug? ? $stdout : File.open(IO::NULL, "w")
+ # Only the min bound is inspected: `~>` synthesises a max like `X.A`
+ # whose suffix looks prerelease to Gem::Version but is not the user's
+ # intent, so checking max would mis-admit prereleases for every `~>`.
+ def range_admits_prerelease?(range)
+ range.ranges.any? do |r|
+ next false if r.empty?
+ r.min&.prerelease?
+ end
end
- def debug?
- DEBUG_RESOLVER
+ def find_unfiltered_specs_for(name)
+ dep = Gem::Dependency.new(name, ">= 0.a")
+ dep_request = DependencyRequest.new(dep, nil)
+ @set.find_all(dep_request)
end
- include Gem::Molinillo::SpecificationProvider
+ def filter_specs(specs)
+ filtered = select_local_platforms(specs)
- ##
- # Proceed with resolution! Returns an array of ActivationRequest objects.
+ unless @soft_missing
+ filtered = filtered.select do |s|
+ s.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
+ s.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
+ rescue StandardError
+ true
+ end
+ end
- def resolve
- Gem::Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }).tsort.filter_map(&:payload)
- rescue Gem::Molinillo::VersionConflict => e
- conflict = e.conflicts.values.first
- raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
- ensure
- @output.close if defined?(@output) && !debug?
+ filtered
end
- ##
- # Extracts the specifications that may be able to fulfill +dependency+ and
- # returns those that match the local platform and all those that match.
+ def spec_for(name, version)
+ @spec_for_cache[name][version]
+ end
- def find_possible(dependency) # :nodoc:
- all = @set.find_all dependency
+ def build_spec_for_cache(name)
+ # Rank sources by the order they were first supplied so that, when multiple
+ # sources offer the same version and platform, the earlier source wins.
+ source_rank = {}
+ @all_specs[name].each do |s|
+ source_rank[s.source] ||= source_rank.size
+ end
- if (skip_dep_gems = skip_gems[dependency.name]) && !skip_dep_gems.empty?
- matching = all.select do |api_spec|
- skip_dep_gems.any? {|s| api_spec.version == s.version }
- end
+ @all_specs[name].group_by(&:version).transform_values do |candidates|
+ next candidates.first if candidates.length == 1
+
+ # Prefer already-installed specs to avoid unnecessary downloads
+ installed = candidates.select {|s| s.is_a?(Gem::Resolver::InstalledSpecification) }
+ next installed.first if installed.length == 1
+ candidates = installed if installed.any?
- all = matching unless matching.empty?
+ # Among remaining candidates, prefer the most specific platform, then the
+ # earlier-supplied source.
+ candidates.min_by do |s|
+ [Gem::Platform.platform_specificity_match(s.platform, Gem::Platform.local),
+ source_rank[s.source]]
+ end
end
+ end
- matching_platform = select_local_platforms all
+ def compute_dependencies(package, version)
+ spec = spec_for(package.to_s, version)
+ return {} unless spec
+ return {} if @ignore_dependencies
- [matching_platform, all]
- end
+ spec.fetch_development_dependencies if @development && spec.respond_to?(:fetch_development_dependencies)
- ##
- # Returns the gems in +specs+ that match the local platform.
+ deps = {}
+ root_names = @needed.map(&:name)
- def select_local_platforms(specs) # :nodoc:
- specs.select do |spec|
- Gem::Platform.installable? spec
+ spec.dependencies.each do |d|
+ next if d.name == package.to_s
+ next if d.type == :development && !@development
+ next if d.type == :development && @development_shallow && !root_names.include?(package.to_s)
+
+ dep_package = package_for(d.name)
+
+ # In force mode, skip deps that can't be satisfied - either no
+ # specs at all, or no specs matching the version requirement.
+ if @soft_missing
+ dep_specs = @all_specs[d.name]
+ matching = dep_specs.select {|s| d.requirement.satisfied_by?(s.version) }
+ next if matching.empty?
+ end
+
+ deps[d.name] = Gem::PubGrub::RubyGems.requirement_to_constraint(dep_package, d.requirement)
end
+
+ deps
end
- def search_for(dependency)
- possibles, all = find_possible(dependency)
- if !@soft_missing && possibles.empty?
- exc = Gem::UnsatisfiableDependencyError.new dependency, all
- exc.errors = @set.errors
- raise exc
- end
+ def build_extended_explanation(name, constraint)
+ unfiltered = @unfiltered_specs[name]
+ return if unfiltered.empty?
+
+ filtered = @all_specs[name]
+ pkg = package_for(name)
- groups = Hash.new {|hash, key| hash[key] = [] }
+ # A prerelease hint applies when the source would strip prereleases for
+ # this constraint (global prerelease flag off and the constraint's range
+ # doesn't itself reach into prerelease territory) AND a prerelease of
+ # the gem exists somewhere.
+ prerelease_gated = !(@set.respond_to?(:prerelease) && @set.prerelease) &&
+ !range_admits_prerelease?(constraint.range)
+ has_prerelease_candidate = prerelease_gated &&
+ @all_versions[pkg].any?(&:prerelease?)
- # create groups & sources in the same loop
- sources = possibles.map do |spec|
- source = spec.source
- groups[source] << spec
- source
- end.uniq.reverse
+ return if filtered.length == unfiltered.length && !has_prerelease_candidate
- activation_requests = []
+ hints = []
- sources.each do |source|
- groups[source].
- sort_by {|spec| [spec.version, spec.platform =~ Gem::Platform.local ? 1 : 0] }. # rubocop:disable Performance/RegexpMatch
- map {|spec| ActivationRequest.new spec, dependency }.
- each {|activation_request| activation_requests << activation_request }
+ # Check for specs that exist for other platforms
+ platform_specs = unfiltered.select do |s|
+ !Gem::Platform.installable?(s) && constraint.range.include?(s.version)
+ end
+ if platform_specs.any?
+ label = "#{name} (#{constraint.constraint_string})"
+ hints << "The source contains the following gems matching '#{label}':"
+ platform_specs.each do |s|
+ actual = s.respond_to?(:spec) ? s.spec : s
+ hints << " * #{actual.full_name}"
+ end
end
- activation_requests
- end
+ # Check for specs filtered by Ruby version
+ installable = select_local_platforms(unfiltered)
+ ruby_specs = installable.select do |s|
+ actual = s.respond_to?(:spec) ? s.spec : s
+ constraint.range.include?(s.version) &&
+ !actual.required_ruby_version.satisfied_by?(Gem.ruby_version)
+ rescue StandardError
+ false
+ end
+ if ruby_specs.any?
+ versions = ruby_specs.map(&:version).uniq.sort.reverse.first(3)
+ sample = ruby_specs.find {|s| s.version == versions.first }
+ actual = sample.respond_to?(:spec) ? sample.spec : sample
+ ruby_req = actual.required_ruby_version
+ hints << "#{name} #{versions.join(", ")} requires Ruby #{ruby_req} (you have #{Gem.ruby_version})"
+ end
+
+ # Check for specs filtered by prerelease status
+ if prerelease_gated
+ prerelease_versions = @all_versions[pkg].select(&:prerelease?)
+ if prerelease_versions.any?
+ versions = prerelease_versions.sort.reverse.first(3) # limit to avoid cluttering error output
+ hints << "#{name} #{versions.join(", ")} are pre-release versions. Use --prerelease to allow pre-release gems."
+ end
+ end
- def dependencies_for(specification)
- return [] if @ignore_dependencies
- spec = specification.spec
- requests(spec, specification)
+ hints.empty? ? nil : hints.join("\n")
end
- def requirement_satisfied_by?(requirement, activated, spec)
- matches_spec = requirement.matches_spec? spec
- return matches_spec if @soft_missing
+ def extract_extended_explanation(incompatibility)
+ while incompatibility.cause.is_a?(Gem::PubGrub::Incompatibility::ConflictCause)
+ cause = incompatibility.cause
- matches_spec &&
- spec.spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
- spec.spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
- end
+ [cause.conflict, cause.other].each do |incompat|
+ if incompat.cause.is_a?(Gem::PubGrub::Incompatibility::NoVersions) &&
+ incompat.respond_to?(:extended_explanation) &&
+ incompat.extended_explanation
+ return incompat.extended_explanation
+ end
+ end
+
+ incompatibility = cause.conflict
+ end
- def name_for(dependency)
- dependency.name
+ nil
end
- def allow_missing?(dependency)
- @soft_missing
+ def make_logger
+ DEBUG_RESOLVER ? Gem::PubGrub::StderrLogger.new : Gem::PubGrub::NullLogger.new
end
- def sort_dependencies(dependencies, activated, conflicts)
- dependencies.sort_by.with_index do |dependency, i|
- name = name_for(dependency)
- [
- activated.vertex_named(name).payload ? 0 : 1,
- amount_constrained(dependency),
- conflicts[name] ? 0 : 1,
- activated.vertex_named(name).payload ? 0 : search_for(dependency).count,
- i, # for stable sort
- ]
+ # Custom root package so error messages say "your request depends on..."
+ # instead of PubGrub's default "root depends on...".
+ class RootPackage < Gem::PubGrub::Package
+ def initialize
+ super(:root)
end
- end
- SINGLE_POSSIBILITY_CONSTRAINT_PENALTY = 1_000_000
- private_constant :SINGLE_POSSIBILITY_CONSTRAINT_PENALTY if defined?(private_constant)
+ def root?
+ true
+ end
- # returns an integer \in (-\infty, 0]
- # a number closer to 0 means the dependency is less constraining
- #
- # dependencies w/ 0 or 1 possibilities (ignoring version requirements)
- # are given very negative values, so they _always_ sort first,
- # before dependencies that are unconstrained
- def amount_constrained(dependency)
- @amount_constrained ||= {}
- @amount_constrained[dependency.name] ||= begin
- name_dependency = Gem::Dependency.new(dependency.name)
- dependency_request_for_name = Gem::Resolver::DependencyRequest.new(name_dependency, dependency.requester)
- all = @set.find_all(dependency_request_for_name).size
-
- if all <= 1
- all - SINGLE_POSSIBILITY_CONSTRAINT_PENALTY
- else
- search = search_for(dependency).size
- search - all
- end
+ def to_s
+ "your request"
end
end
- private :amount_constrained
end
require_relative "resolver/activation_request"
-require_relative "resolver/conflict"
require_relative "resolver/dependency_request"
+require_relative "resolver/incompatibility"
+require_relative "resolver/strategy"
require_relative "resolver/requirement_list"
-require_relative "resolver/stats"
-
require_relative "resolver/set"
require_relative "resolver/api_set"
require_relative "resolver/composed_set"
diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb
index 9f6695a6a9..3f443519d8 100644
--- a/lib/rubygems/resolver/api_set.rb
+++ b/lib/rubygems/resolver/api_set.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
##
-# The global rubygems pool, available via the rubygems.org API.
+# The global rubygems pool, available via the Compact Index API.
# Returns instances of APISpecification.
class Gem::Resolver::APISet < Gem::Resolver::Set
autoload :GemParser, File.expand_path("api_set/gem_parser", __dir__)
##
- # The URI for the dependency API this APISet uses.
+ # The URI for the Compact Index API this APISet uses.
attr_reader :dep_uri # :nodoc:
@@ -23,9 +23,9 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
attr_reader :uri
##
- # Creates a new APISet that will retrieve gems from +uri+ using the RubyGems
- # API URL +dep_uri+ which is described at
- # https://guides.rubygems.org/rubygems-org-api
+ # Creates a new APISet that will retrieve gems from +uri+ using the Compact
+ # Index API URL +dep_uri+ which is described at
+ # https://guides.rubygems.org/rubygems-org-compact-index-api
def initialize(dep_uri = "https://index.rubygems.org/info/")
super()
diff --git a/lib/rubygems/resolver/api_set/gem_parser.rb b/lib/rubygems/resolver/api_set/gem_parser.rb
index 643b857107..4d827f4980 100644
--- a/lib/rubygems/resolver/api_set/gem_parser.rb
+++ b/lib/rubygems/resolver/api_set/gem_parser.rb
@@ -1,22 +1,19 @@
# 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 = dependencies ? dependencies.map! {|d| parse_dependency(d) } : []
+ requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : []
[version, platform, dependencies, requirements]
end
private
def parse_dependency(string)
- dependency = string.split(":")
+ dependency = string.split(":", 2)
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
dependency[0] = -dependency[0]
dependency
diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb
index a14bcbfeb1..ccfd6fe084 100644
--- a/lib/rubygems/resolver/api_specification.rb
+++ b/lib/rubygems/resolver/api_specification.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
##
-# Represents a specification retrieved via the rubygems.org API.
+# Represents a specification retrieved via the Compact Index API.
#
# This is used to avoid loading the full Specification object when all we need
# is the name, version, and dependencies.
@@ -19,10 +19,10 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
end
##
- # Creates an APISpecification for the given +set+ from the rubygems.org
+ # Creates an APISpecification for the given +set+ from the Compact Index API
# +api_data+.
#
- # See https://guides.rubygems.org/rubygems-org-api/#misc-methods for the
+ # See https://guides.rubygems.org/rubygems-org-compact-index-api 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..e647a2c11b 100644
--- a/lib/rubygems/resolver/best_set.rb
+++ b/lib/rubygems/resolver/best_set.rb
@@ -21,7 +21,7 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
def pick_sets # :nodoc:
@sources.each_source do |source|
- @sets << source.dependency_resolver_set
+ @sets << source.dependency_resolver_set(@prerelease)
end
end
diff --git a/lib/rubygems/resolver/conflict.rb b/lib/rubygems/resolver/conflict.rb
deleted file mode 100644
index 367a36b43d..0000000000
--- a/lib/rubygems/resolver/conflict.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-# frozen_string_literal: true
-
-##
-# Used internally to indicate that a dependency conflicted
-# with a spec that would be activated.
-
-class Gem::Resolver::Conflict
- ##
- # The specification that was activated prior to the conflict
-
- attr_reader :activated
-
- ##
- # The dependency that is in conflict with the activated gem.
-
- attr_reader :dependency
-
- attr_reader :failed_dep # :nodoc:
-
- ##
- # Creates a new resolver conflict when +dependency+ is in conflict with an
- # already +activated+ specification.
-
- def initialize(dependency, activated, failed_dep=dependency)
- @dependency = dependency
- @activated = activated
- @failed_dep = failed_dep
- end
-
- def ==(other) # :nodoc:
- self.class === other &&
- @dependency == other.dependency &&
- @activated == other.activated &&
- @failed_dep == other.failed_dep
- end
-
- ##
- # A string explanation of the conflict.
-
- def explain
- "<Conflict wanted: #{@failed_dep}, had: #{activated.spec.full_name}>"
- end
-
- ##
- # Return the 2 dependency objects that conflicted
-
- def conflicting_dependencies
- [@failed_dep.dependency, @activated.request.dependency]
- end
-
- ##
- # Explanation of the conflict used by exceptions to print useful messages
-
- def explanation
- activated = @activated.spec.full_name
- dependency = @failed_dep.dependency
- requirement = dependency.requirement
- alternates = dependency.matching_specs.map(&:full_name)
-
- unless alternates.empty?
- matching = <<-MATCHING.chomp
-
- Gems matching %s:
- %s
- MATCHING
-
- matching = format(matching, dependency, alternates.join(", "))
- end
-
- explanation = <<-EXPLANATION
- Activated %s
- which does not match conflicting dependency (%s)
-
- Conflicting dependency chains:
- %s
-
- versus:
- %s
-%s
- EXPLANATION
-
- format(explanation, activated, requirement, request_path(@activated).reverse.join(", depends on\n "), request_path(@failed_dep).reverse.join(", depends on\n "), matching)
- end
-
- ##
- # Returns true if the conflicting dependency's name matches +spec+.
-
- def for_spec?(spec)
- @dependency.name == spec.name
- end
-
- def pretty_print(q) # :nodoc:
- q.group 2, "[Dependency conflict: ", "]" do
- q.breakable
-
- q.text "activated "
- q.pp @activated
-
- q.breakable
- q.text " dependency "
- q.pp @dependency
-
- q.breakable
- if @dependency == @failed_dep
- q.text " failed"
- else
- q.text " failed dependency "
- q.pp @failed_dep
- end
- end
- end
-
- ##
- # Path of activations from the +current+ list.
-
- def request_path(current)
- path = []
-
- while current do
- case current
- when Gem::Resolver::ActivationRequest then
- path <<
- "#{current.request.dependency}, #{current.spec.version} activated"
-
- current = current.parent
- when Gem::Resolver::DependencyRequest then
- path << current.dependency.to_s
-
- current = current.requester
- else
- raise Gem::Exception, "[BUG] unknown request class #{current.class}"
- end
- end
-
- path = ["user request (gem command or Gemfile)"] if path.empty?
-
- path
- end
-
- ##
- # Return the Specification that listed the dependency
-
- def requester
- @failed_dep.requester
- end
-end
diff --git a/lib/rubygems/resolver/incompatibility.rb b/lib/rubygems/resolver/incompatibility.rb
new file mode 100644
index 0000000000..57a60affb4
--- /dev/null
+++ b/lib/rubygems/resolver/incompatibility.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class Gem::Resolver::Incompatibility < Gem::PubGrub::Incompatibility
+ attr_reader :extended_explanation
+
+ def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil)
+ @extended_explanation = extended_explanation
+ super(terms, cause: cause, custom_explanation: custom_explanation)
+ end
+end
diff --git a/lib/rubygems/resolver/installer_set.rb b/lib/rubygems/resolver/installer_set.rb
index d9fe36c589..42ce0890e2 100644
--- a/lib/rubygems/resolver/installer_set.rb
+++ b/lib/rubygems/resolver/installer_set.rb
@@ -160,7 +160,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
res.concat matching_local
begin
- if local_spec = @local_source.find_gem(name, dep.requirement)
+ @local_source.find_all_gems(name, dep.requirement).each do |local_spec|
res << Gem::Resolver::IndexSpecification.new(
self, local_spec.name, local_spec.version,
@local_source, local_spec.platform
diff --git a/lib/rubygems/resolver/source_set.rb b/lib/rubygems/resolver/source_set.rb
index 296cf41078..074b473edc 100644
--- a/lib/rubygems/resolver/source_set.rb
+++ b/lib/rubygems/resolver/source_set.rb
@@ -42,6 +42,6 @@ class Gem::Resolver::SourceSet < Gem::Resolver::Set
def get_set(name)
link = @links[name]
- @sets[link] ||= Gem::Source.new(link).dependency_resolver_set if link
+ @sets[link] ||= Gem::Source.new(link).dependency_resolver_set(@prerelease) if link
end
end
diff --git a/lib/rubygems/resolver/stats.rb b/lib/rubygems/resolver/stats.rb
deleted file mode 100644
index 9920976b2a..0000000000
--- a/lib/rubygems/resolver/stats.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-class Gem::Resolver::Stats
- def initialize
- @max_depth = 0
- @max_requirements = 0
- @requirements = 0
- @backtracking = 0
- @iterations = 0
- end
-
- def record_depth(stack)
- if stack.size > @max_depth
- @max_depth = stack.size
- end
- end
-
- def record_requirements(reqs)
- if reqs.size > @max_requirements
- @max_requirements = reqs.size
- end
- end
-
- def requirement!
- @requirements += 1
- end
-
- def backtracking!
- @backtracking += 1
- end
-
- def iteration!
- @iterations += 1
- end
-
- PATTERN = "%20s: %d\n"
-
- def display
- $stdout.puts "=== Resolver Statistics ==="
- $stdout.printf PATTERN, "Max Depth", @max_depth
- $stdout.printf PATTERN, "Total Requirements", @requirements
- $stdout.printf PATTERN, "Max Requirements", @max_requirements
- $stdout.printf PATTERN, "Backtracking #", @backtracking
- $stdout.printf PATTERN, "Iteration #", @iterations
- end
-end
diff --git a/lib/rubygems/resolver/strategy.rb b/lib/rubygems/resolver/strategy.rb
new file mode 100644
index 0000000000..bf0dbb6adc
--- /dev/null
+++ b/lib/rubygems/resolver/strategy.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+# Custom PubGrub strategy with caching for version selection.
+# Modeled after Bundler's strategy to avoid redundant versions_for
+# calls during the solver's package selection loop.
+
+class Gem::Resolver::Strategy
+ def initialize(source)
+ @source = source
+ @package_priority_cache = Hash.new {|h, pkg| h[pkg] = {} }
+
+ @version_indexes = Hash.new do |h, k|
+ if Gem::PubGrub::Package.root?(k)
+ h[k] = { Gem::PubGrub::Package.root_version => 0 }
+ else
+ h[k] = @source.all_versions_for(k).each.with_index.to_h
+ end
+ end
+ end
+
+ def next_package_and_version(unsatisfied)
+ package, range = next_term_to_try_from(unsatisfied)
+ [package, most_preferred_version_of(package, range)]
+ end
+
+ private
+
+ def most_preferred_version_of(package, range)
+ versions = @source.versions_for(package, range)
+ indexes = @version_indexes[package]
+ versions.min_by {|version| indexes[version] || Float::INFINITY }
+ end
+
+ def next_term_to_try_from(unsatisfied)
+ unsatisfied.min_by do |package, range|
+ @package_priority_cache[package][range] ||= begin
+ matching_versions = @source.versions_for(package, range)
+ higher_versions = @source.versions_for(package, range.upper_invert)
+
+ [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/s3_uri_signer.rb b/lib/rubygems/s3_uri_signer.rb
index 7c95a9d4f5..148cba38c4 100644
--- a/lib/rubygems/s3_uri_signer.rb
+++ b/lib/rubygems/s3_uri_signer.rb
@@ -1,11 +1,14 @@
# frozen_string_literal: true
require_relative "openssl"
+require_relative "user_interaction"
##
# S3URISigner implements AWS SigV4 for S3 Source to avoid a dependency on the aws-sdk-* gems
# More on AWS SigV4: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
class Gem::S3URISigner
+ include Gem::UserInteraction
+
class ConfigurationError < Gem::Exception
def initialize(message)
super message
@@ -27,9 +30,11 @@ class Gem::S3URISigner
end
attr_accessor :uri
+ attr_accessor :method
- def initialize(uri)
+ def initialize(uri, method)
@uri = uri
+ @method = method
end
##
@@ -38,7 +43,7 @@ class Gem::S3URISigner
s3_config = fetch_s3_config
current_time = Time.now.utc
- date_time = current_time.strftime("%Y%m%dT%H%m%SZ")
+ date_time = current_time.strftime("%Y%m%dT%H%M%SZ")
date = date_time[0,8]
credential_info = "#{date}/#{s3_config.region}/s3/aws4_request"
@@ -73,7 +78,7 @@ class Gem::S3URISigner
def generate_canonical_request(canonical_host, query_params)
[
- "GET",
+ method.upcase,
uri.path,
query_params,
"host:#{canonical_host}",
@@ -145,17 +150,40 @@ class Gem::S3URISigner
require_relative "request/connection_pools"
require "json"
- iam_info = ec2_metadata_request(EC2_IAM_INFO)
+ # First try V2 fallback to V1
+ res = nil
+ begin
+ res = ec2_metadata_credentials_imds_v2
+ rescue InstanceProfileError
+ alert_warning "Unable to access ec2 credentials via IMDSv2, falling back to IMDSv1"
+ res = ec2_metadata_credentials_imds_v1
+ end
+ res
+ end
+
+ def ec2_metadata_credentials_imds_v2
+ token = ec2_metadata_token
+ iam_info = ec2_metadata_request(EC2_IAM_INFO, token:)
# Expected format: arn:aws:iam::<id>:instance-profile/<role_name>
role_name = iam_info["InstanceProfileArn"].split("/").last
- ec2_metadata_request(EC2_IAM_SECURITY_CREDENTIALS + role_name)
+ ec2_metadata_request(EC2_IAM_SECURITY_CREDENTIALS + role_name, token:)
end
- def ec2_metadata_request(url)
- uri = Gem::URI(url)
- @request_pool ||= create_request_pool(uri)
- request = Gem::Request.new(uri, Gem::Net::HTTP::Get, nil, @request_pool)
- response = request.fetch
+ def ec2_metadata_credentials_imds_v1
+ iam_info = ec2_metadata_request(EC2_IAM_INFO, token: nil)
+ # Expected format: arn:aws:iam::<id>:instance-profile/<role_name>
+ role_name = iam_info["InstanceProfileArn"].split("/").last
+ ec2_metadata_request(EC2_IAM_SECURITY_CREDENTIALS + role_name, token: nil)
+ end
+
+ def ec2_metadata_request(url, token:)
+ request = ec2_iam_request(Gem::URI(url), Gem::Net::HTTP::Get)
+
+ response = request.fetch do |req|
+ if token
+ req.add_field "X-aws-ec2-metadata-token", token
+ end
+ end
case response
when Gem::Net::HTTPOK then
@@ -165,6 +193,26 @@ class Gem::S3URISigner
end
end
+ def ec2_metadata_token
+ request = ec2_iam_request(Gem::URI(EC2_IAM_TOKEN), Gem::Net::HTTP::Put)
+
+ response = request.fetch do |req|
+ req.add_field "X-aws-ec2-metadata-token-ttl-seconds", 60
+ end
+
+ case response
+ when Gem::Net::HTTPOK then
+ response.body
+ else
+ raise InstanceProfileError.new("Unable to fetch AWS metadata from #{uri}: #{response.message} #{response.code}")
+ end
+ end
+
+ def ec2_iam_request(uri, verb)
+ @request_pool ||= create_request_pool(uri)
+ Gem::Request.new(uri, verb, nil, @request_pool)
+ end
+
def create_request_pool(uri)
proxy_uri = Gem::Request.proxy_uri(Gem::Request.get_proxy_from_env(uri.scheme))
certs = Gem::Request.get_cert_files
@@ -172,6 +220,7 @@ class Gem::S3URISigner
end
BASE64_URI_TRANSLATE = { "+" => "%2B", "/" => "%2F", "=" => "%3D", "\n" => "" }.freeze
+ EC2_IAM_TOKEN = "http://169.254.169.254/latest/api/token"
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/"
end
diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb
index b81d1a0a47..871f24727d 100644
--- a/lib/rubygems/safe_marshal.rb
+++ b/lib/rubygems/safe_marshal.rb
@@ -54,6 +54,7 @@ module Gem
"Gem::NameTuple" => %w[@name @version @platform],
"Gem::Platform" => %w[@os @cpu @version],
"Psych::PrivateType" => %w[@value @type_id],
+ "YAML::PrivateType" => %w[@value @type_id],
}.freeze
private_constant :PERMITTED_IVARS
diff --git a/lib/rubygems/safe_yaml.rb b/lib/rubygems/safe_yaml.rb
index 6a02a48230..f4bba00136 100644
--- a/lib/rubygems/safe_yaml.rb
+++ b/lib/rubygems/safe_yaml.rb
@@ -35,11 +35,21 @@ module Gem
end
def self.safe_load(input)
- ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: @aliases_enabled)
+ if Gem.use_psych?
+ ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES,
+ permitted_symbols: PERMITTED_SYMBOLS, aliases: @aliases_enabled)
+ else
+ Gem::YAMLSerializer.load(
+ input,
+ permitted_classes: PERMITTED_CLASSES,
+ permitted_symbols: PERMITTED_SYMBOLS,
+ aliases: aliases_enabled?
+ )
+ end
end
- def self.load(input)
- ::Psych.safe_load(input, permitted_classes: [::Symbol])
+ class << self
+ alias_method :load, :safe_load
end
end
end
diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb
index 7b86ac5763..128958ab80 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -143,7 +143,7 @@ class Gem::Security::Policy
end
##
- # Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and
+ # Ensures the root of +chain+ has a trusted certificate in Gem::Security.trust_dir and
# the digests of the two certificates match according to +digester+
def check_trust(chain, digester, trust_dir)
diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb
index 5732fb57fd..eeeeb52906 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -52,7 +52,7 @@ class Gem::Security::Signer
re_signed_cert = Gem::Security.re_sign(
expired_cert,
private_key,
- (Gem::Security::ONE_DAY * Gem.configuration.cert_expiration_length_days)
+ Gem::Security::ONE_DAY * Gem.configuration.cert_expiration_length_days
)
Gem::Security.write(re_signed_cert, expired_cert_path)
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..86717e3e71 100644
--- a/lib/rubygems/source.rb
+++ b/lib/rubygems/source.rb
@@ -5,7 +5,7 @@ require_relative "text"
# A Source knows how to list and fetch gems from a RubyGems marshal index.
#
# There are other Source subclasses for installed gems, local gems, the
-# bundler dependency API and so-forth.
+# Compact Index API and so-forth.
class Gem::Source
include Comparable
@@ -67,28 +67,11 @@ 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"
-
- fetch_uri = if uri.host == "rubygems.org"
- index_uri = uri.dup
- index_uri.host = "index.rubygems.org"
- index_uri
- else
- uri
- end
-
- bundler_api_uri = enforce_trailing_slash(fetch_uri) + "versions"
-
- begin
- fetcher = Gem::RemoteFetcher.fetcher
- response = fetcher.fetch_path bundler_api_uri, nil, true
- rescue Gem::RemoteFetcher::FetchError
- Gem::Resolver::IndexSet.new self
- else
- Gem::Resolver::APISet.new response.uri + "./info/"
- end
+ #
+ # The set will optionally fetch prereleases if requested.
+ #
+ def dependency_resolver_set(prerelease = false)
+ new_dependency_resolver_set.tap {|set| set.prerelease = prerelease }
end
def hash # :nodoc:
@@ -119,7 +102,7 @@ class Gem::Source
end
##
- # Fetches a specification for the given +name_tuple+.
+ # Fetches a specification for the given Gem::NameTuple.
def fetch_spec(name_tuple)
fetcher = Gem::RemoteFetcher.fetcher
@@ -207,7 +190,7 @@ class Gem::Source
# Downloads +spec+ and writes it to +dir+. See also
# Gem::RemoteFetcher#download.
- def download(spec, dir=Dir.pwd)
+ def download(spec, dir = Dir.pwd)
fetcher = Gem::RemoteFetcher.fetcher
fetcher.download spec, uri.to_s, dir
end
@@ -227,13 +210,36 @@ class Gem::Source
end
end
- def typo_squatting?(host, distance_threshold=4)
+ def typo_squatting?(host, distance_threshold = 4)
return if @uri.host.nil?
levenshtein_distance(@uri.host, host).between? 1, distance_threshold
end
private
+ def new_dependency_resolver_set
+ return Gem::Resolver::IndexSet.new self if uri.scheme == "file"
+
+ fetch_uri = if uri.host == "rubygems.org"
+ index_uri = uri.dup
+ index_uri.host = "index.rubygems.org"
+ index_uri
+ else
+ uri
+ end
+
+ bundler_api_uri = enforce_trailing_slash(fetch_uri) + "versions"
+
+ begin
+ fetcher = Gem::RemoteFetcher.fetcher
+ response = fetcher.fetch_path bundler_api_uri, nil, true
+ rescue Gem::RemoteFetcher::FetchError
+ Gem::Resolver::IndexSet.new self
+ else
+ Gem::Resolver::APISet.new response.uri + "./info/"
+ end
+ end
+
def enforce_trailing_slash(uri)
uri.merge(uri.path.gsub(%r{/+$}, "") + "/")
end
diff --git a/lib/rubygems/source/local.rb b/lib/rubygems/source/local.rb
index ba6eea1f9a..4bef31a265 100644
--- a/lib/rubygems/source/local.rb
+++ b/lib/rubygems/source/local.rb
@@ -76,6 +76,10 @@ class Gem::Source::Local < Gem::Source
end
def find_gem(gem_name, version = Gem::Requirement.default, prerelease = false) # :nodoc:
+ find_all_gems(gem_name, version, prerelease).max_by(&:version)
+ end
+
+ def find_all_gems(gem_name, version = Gem::Requirement.default, prerelease = false) # :nodoc:
load_specs :complete
found = []
@@ -93,7 +97,7 @@ class Gem::Source::Local < Gem::Source
end
end
- found.max_by(&:version)
+ found
end
def fetch_spec(name) # :nodoc:
diff --git a/lib/rubygems/source_list.rb b/lib/rubygems/source_list.rb
index 33db64fbc1..19bf4595c4 100644
--- a/lib/rubygems/source_list.rb
+++ b/lib/rubygems/source_list.rb
@@ -60,6 +60,42 @@ class Gem::SourceList
end
##
+ # Prepends +obj+ to the beginning of the source list which may be a Gem::Source, Gem::URI or URI
+ # Moves +obj+ to the beginning of the list if already present.
+ # String.
+
+ def prepend(obj)
+ src = case obj
+ when Gem::Source
+ obj
+ else
+ Gem::Source.new(obj)
+ end
+
+ @sources.delete(src) if @sources.include?(src)
+ @sources.unshift(src)
+ src
+ end
+
+ ##
+ # Appends +obj+ to the end of the source list, moving it if already present.
+ # +obj+ may be a Gem::Source, Gem::URI or URI String.
+ # Moves +obj+ to the end of the list if already present.
+
+ def append(obj)
+ src = case obj
+ when Gem::Source
+ obj
+ else
+ Gem::Source.new(obj)
+ end
+
+ @sources.delete(src) if @sources.include?(src)
+ @sources << src
+ src
+ end
+
+ ##
# Replaces this SourceList with the sources in +other+ See #<< for
# acceptable items in +other+.
diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb
index 285f117b39..835dedf948 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -83,7 +83,7 @@ class Gem::SpecFetcher
#
# If +matching_platform+ is false, gems for all platforms are returned.
- def search_for_dependency(dependency, matching_platform=true)
+ def search_for_dependency(dependency, matching_platform = true)
found = {}
rejected_specs = {}
@@ -130,7 +130,7 @@ class Gem::SpecFetcher
##
# Return all gem name tuples who's names match +obj+
- def detect(type=:complete)
+ def detect(type = :complete)
tuples = []
list, _ = available_specs(type)
@@ -150,7 +150,7 @@ class Gem::SpecFetcher
#
# If +matching_platform+ is false, gems for all platforms are returned.
- def spec_for_dependency(dependency, matching_platform=true)
+ def spec_for_dependency(dependency, matching_platform = true)
tuples, errors = search_for_dependency(dependency, matching_platform)
specs = []
@@ -280,7 +280,7 @@ class Gem::SpecFetcher
# Retrieves NameTuples from +source+ of the given +type+ (:prerelease,
# etc.). If +gracefully_ignore+ is true, errors are ignored.
- def tuples_for(source, type, gracefully_ignore=false) # :nodoc:
+ def tuples_for(source, type, gracefully_ignore = false) # :nodoc:
@caches[type][source.uri] ||=
source.load_specs(type).sort_by(&:name)
rescue Gem::RemoteFetcher::FetchError
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 121b72f90a..51729d755b 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -7,12 +7,10 @@
# See LICENSE.txt for permissions.
#++
-require_relative "deprecate"
require_relative "basic_specification"
require_relative "stub_specification"
require_relative "platform"
require_relative "specification_record"
-require_relative "util/list"
require "rbconfig"
@@ -36,10 +34,17 @@ require "rbconfig"
# Starting in RubyGems 2.0, a Specification can hold arbitrary
# metadata. See #metadata for restrictions on the format and size of metadata
# items you may add to a specification.
+#
+# Specifications must be deterministic, as in the example above. For instance,
+# you cannot define attributes conditionally:
+#
+# # INVALID: do not do this.
+# unless RUBY_ENGINE == "jruby"
+# s.extensions << "ext/example/extconf.rb"
+# end
+#
class Gem::Specification < Gem::BasicSpecification
- extend Gem::Deprecate
-
# REFACTOR: Consider breaking out this version stuff into a separate
# module. There's enough special stuff around it that it may justify
# a separate class.
@@ -488,8 +493,6 @@ class Gem::Specification < Gem::BasicSpecification
end
@platform = @new_platform.to_s
-
- invalidate_memoized_attributes
end
##
@@ -738,14 +741,6 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :autorequire # :nodoc:
##
- # Sets the default executable for this gem.
- #
- # Deprecated: You must now specify the executable name to Gem.bin_path.
-
- attr_writer :default_executable
- rubygems_deprecate :default_executable=
-
- ##
# Allows deinstallation of gems with legacy platforms.
attr_writer :original_platform # :nodoc:
@@ -974,6 +969,15 @@ class Gem::Specification < Gem::BasicSpecification
##
# Return the best specification that contains the file matching +path+
+ # amongst the specs that are not loaded. This method is different than
+ # +find_inactive_by_path+ as it will filter out loaded specs by their name.
+
+ def self.find_unloaded_by_path(path)
+ specification_record.find_unloaded_by_path(path)
+ end
+
+ ##
+ # Return the best specification that contains the file matching +path+
# amongst the specs that are not activated.
def self.find_inactive_by_path(path)
@@ -1002,7 +1006,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|
- if to_spec.has_conflicts? || to_spec.conficts_when_loaded_with?(trail)
+ if to_spec.has_conflicts? || to_spec.conflicts_when_loaded_with?(trail)
:next
else
return trail.reverse if to_spec.contains_requirable_file? path
@@ -1271,7 +1275,7 @@ class Gem::Specification < Gem::BasicSpecification
raise unless message.include?("YAML::")
unless Object.const_defined?(:YAML)
- Object.const_set "YAML", Psych
+ Object.const_set "YAML", Module.new
yaml_set = true
end
@@ -1280,7 +1284,7 @@ class Gem::Specification < Gem::BasicSpecification
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.const_set "PrivateType", Class.new
+ YAML.const_set "PrivateType", Class.new { attr_accessor :type_id, :value }
end
retry_count += 1
@@ -1321,7 +1325,7 @@ class Gem::Specification < Gem::BasicSpecification
spec.instance_variable_set :@authors, array[12]
spec.instance_variable_set :@description, array[13]
spec.instance_variable_set :@homepage, array[14]
- spec.instance_variable_set :@has_rdoc, array[15]
+ # offset due to has_rdoc removal
spec.instance_variable_set :@licenses, array[17]
spec.instance_variable_set :@metadata, array[18]
spec.instance_variable_set :@loaded, false
@@ -1620,14 +1624,14 @@ class Gem::Specification < Gem::BasicSpecification
# spec's cached gem.
def cache_dir
- @cache_dir ||= File.join base_dir, "cache"
+ File.join base_dir, "cache"
end
##
# Returns the full path to the cached gem for this spec.
def cache_file
- @cache_file ||= File.join cache_dir, "#{full_name}.gem"
+ File.join cache_dir, "#{full_name}.gem"
end
##
@@ -1649,7 +1653,7 @@ class Gem::Specification < Gem::BasicSpecification
##
# return true if there will be conflict when spec if loaded together with the list of specs.
- def conficts_when_loaded_with?(list_of_specs) # :nodoc:
+ def conflicts_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) }
end
@@ -1717,24 +1721,6 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # The default executable for this gem.
- #
- # Deprecated: The name of the gem is assumed to be the name of the
- # executable now. See Gem.bin_path.
-
- def default_executable # :nodoc:
- if defined?(@default_executable) && @default_executable
- result = @default_executable
- elsif @executables && @executables.size == 1
- result = Array(@executables).first
- else
- result = nil
- end
- result
- end
- rubygems_deprecate :default_executable
-
- ##
# The default value for specification attribute +name+
def default_value(name)
@@ -1757,7 +1743,7 @@ class Gem::Specification < Gem::BasicSpecification
#
# [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
- def dependent_gems(check_dev=true)
+ def dependent_gems(check_dev = true)
out = []
Gem::Specification.each do |spec|
deps = check_dev ? spec.dependencies : spec.runtime_dependencies
@@ -1903,10 +1889,6 @@ class Gem::Specification < Gem::BasicSpecification
spec
end
- def full_name
- @full_name ||= super
- end
-
##
# Work around old bundler versions removing my methods
# Can be removed once RubyGems can no longer install Bundler 2.5
@@ -1920,29 +1902,6 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Deprecated and ignored, defaults to true.
- #
- # Formerly used to indicate this gem was RDoc-capable.
-
- def has_rdoc # :nodoc:
- true
- end
- rubygems_deprecate :has_rdoc
-
- ##
- # Deprecated and ignored.
- #
- # Formerly used to indicate this gem was RDoc-capable.
-
- def has_rdoc=(ignored) # :nodoc:
- @has_rdoc = true
- end
- rubygems_deprecate :has_rdoc=
-
- alias_method :has_rdoc?, :has_rdoc # :nodoc:
- rubygems_deprecate :has_rdoc?
-
- ##
# True if this gem has files in test_files
def has_unit_tests? # :nodoc:
@@ -2044,17 +2003,6 @@ class Gem::Specification < Gem::BasicSpecification
end
end
- ##
- # Expire memoized instance variables that can incorrectly generate, replace
- # or miss files due changes in certain attributes used to compute them.
-
- def invalidate_memoized_attributes
- @full_name = nil
- @cache_file = nil
- end
-
- private :invalidate_memoized_attributes
-
def inspect # :nodoc:
if $DEBUG
super
@@ -2093,8 +2041,6 @@ class Gem::Specification < Gem::BasicSpecification
def internal_init # :nodoc:
super
@bin_dir = nil
- @cache_dir = nil
- @cache_file = nil
@doc_dir = nil
@ri_dir = nil
@spec_dir = nil
@@ -2124,6 +2070,7 @@ class Gem::Specification < Gem::BasicSpecification
# probably want to build_extensions
def missing_extensions?
+ return false if RUBY_ENGINE == "jruby"
return false if extensions.empty?
return false if default_gem?
return false if File.exist? gem_build_complete_path
@@ -2144,11 +2091,11 @@ class Gem::Specification < Gem::BasicSpecification
@files.concat(@extra_rdoc_files)
end
- @files = @files.uniq if @files
- @extensions = @extensions.uniq if @extensions
- @test_files = @test_files.uniq if @test_files
- @executables = @executables.uniq if @executables
- @extra_rdoc_files = @extra_rdoc_files.uniq if @extra_rdoc_files
+ @files = @files.uniq.sort if @files
+ @extensions = @extensions.uniq.sort if @extensions
+ @test_files = @test_files.uniq.sort if @test_files
+ @executables = @executables.uniq.sort if @executables
+ @extra_rdoc_files = @extra_rdoc_files.uniq.sort if @extra_rdoc_files
end
##
@@ -2244,10 +2191,13 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Sets rdoc_options to +value+, ensuring it is an array.
+ # Sets rdoc_options to +value+, ensuring it is a flat array of strings.
+ # Handles malformed gemspecs where rdoc_options may be a Hash or contain Hashes.
def rdoc_options=(options)
- @rdoc_options = Array options
+ @rdoc_options = Array(options).flat_map do |opt|
+ opt.is_a?(Hash) ? opt.to_a.flatten.map(&:to_s) : opt
+ end
end
##
@@ -2447,8 +2397,6 @@ class Gem::Specification < Gem::BasicSpecification
:required_rubygems_version,
:specification_version,
:version,
- :has_rdoc,
- :default_executable,
:metadata,
:signing_key,
]
@@ -2511,24 +2459,28 @@ class Gem::Specification < Gem::BasicSpecification
def to_yaml(opts = {}) # :nodoc:
Gem.load_yaml
- # Because the user can switch the YAML engine behind our
- # back, we have to check again here to make sure that our
- # psych code was properly loaded, and load it if not.
- unless Gem.const_defined?(:NoAliasYAMLTree)
- require_relative "psych_tree"
- end
+ if Gem.use_psych?
+ # Because the user can switch the YAML engine behind our
+ # back, we have to check again here to make sure that our
+ # psych code was properly loaded, and load it if not.
+ unless Gem.const_defined?(:NoAliasYAMLTree)
+ require_relative "psych_tree"
+ end
- builder = Gem::NoAliasYAMLTree.create
- builder << self
- ast = builder.tree
+ builder = Gem::NoAliasYAMLTree.create
+ builder << self
+ ast = builder.tree
- require "stringio"
- io = StringIO.new
- io.set_encoding Encoding::UTF_8
+ require "stringio"
+ io = StringIO.new
+ io.set_encoding Encoding::UTF_8
- Psych::Visitors::Emitter.new(io).accept(ast)
+ Psych::Visitors::Emitter.new(io).accept(ast)
- io.string.gsub(/ !!null \n/, " \n")
+ io.string.gsub(/ !!null \n/, " \n")
+ else
+ Gem::YAMLSerializer.dump(self)
+ end
end
##
@@ -2586,29 +2538,11 @@ class Gem::Specification < Gem::BasicSpecification
Gem::SpecificationPolicy.new(self).validate_for_resolution
end
- def validate_metadata
- Gem::SpecificationPolicy.new(self).validate_metadata
- end
- rubygems_deprecate :validate_metadata
-
- def validate_dependencies
- Gem::SpecificationPolicy.new(self).validate_dependencies
- end
- rubygems_deprecate :validate_dependencies
-
- def validate_permissions
- Gem::SpecificationPolicy.new(self).validate_permissions
- end
- rubygems_deprecate :validate_permissions
-
##
# Set the version to +version+.
def version=(version)
- @version = Gem::Version.create(version)
- return if @version.nil?
-
- invalidate_memoized_attributes
+ @version = version.nil? ? version : Gem::Version.create(version)
end
def stubbed?
@@ -2623,6 +2557,10 @@ class Gem::Specification < Gem::BasicSpecification
self.date = val
when "platform"
self.platform = val
+ when "rdoc_options"
+ self.rdoc_options = val
+ when "requirements"
+ self.requirements = val
else
instance_variable_set "@#{ivar}", val
end
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb
index d79ee7df92..478e294e09 100644
--- a/lib/rubygems/specification_policy.rb
+++ b/lib/rubygems/specification_policy.rb
@@ -190,53 +190,16 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
##
# 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.
def validate_dependencies # :nodoc:
- warning_messages = []
+ error_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
-
- warning_messages << "prerelease dependency on #{dep} is not recommended" if
- prerelease_dep && !@specification.version.prerelease?
-
- open_ended = dep.requirement.requirements.all? do |op, version|
- !version.prerelease? && [">", ">="].include?(op)
+ if dep.name == @specification.name # error on self reference
+ error_messages << "Dependencies of this gem include a self-reference."
end
-
- next unless open_ended
- op, dep_version = dep.requirement.requirements.first
-
- segments = dep_version.segments
-
- 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}\""
- end
-
- " if #{dep.name} is semantically versioned, use:\n" \
- " add_#{dep.type}_dependency \"#{dep.name}\", \"~> #{base.join "."}\"#{bugfix}"
- 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
+
+ error error_messages.join if error_messages.any?
end
def validate_required_ruby_version
@@ -472,6 +435,7 @@ or set it to nil if you don't want to specify a license.
warning "deprecated autorequire specified" if @specification.autorequire
@specification.executables.each do |executable|
+ validate_executable(executable)
validate_shebang_line_in(executable)
end
@@ -485,6 +449,13 @@ or set it to nil if you don't want to specify a license.
warning("no #{attribute} specified") if value.nil? || value.empty?
end
+ def validate_executable(executable)
+ separators = [File::SEPARATOR, File::ALT_SEPARATOR, File::PATH_SEPARATOR].compact.map {|sep| Regexp.escape(sep) }.join
+ return unless executable.match?(/[\s#{separators}]/)
+
+ error "executable \"#{executable}\" contains invalid characters"
+ end
+
def validate_shebang_line_in(executable)
executable_path = File.join(@specification.bindir, executable)
return if File.read(executable_path, 2) == "#!"
@@ -504,6 +475,7 @@ or set it to nil if you don't want to specify a license.
validate_rake_extensions(builder)
validate_rust_extensions(builder)
+ validate_extension_require_relative
end
def validate_rust_extensions(builder) # :nodoc:
@@ -524,6 +496,33 @@ You have specified rake based extension, but rake is not added as runtime depend
WARNING
end
+ def validate_extension_require_relative # :nodoc:
+ return unless @specification.extensions.any?
+
+ require_paths = @specification.require_paths
+
+ @specification.files.each do |rb_file|
+ next unless rb_file.end_with?(".rb")
+ next unless require_paths.any? {|rp| rb_file.start_with?("#{rp}/") }
+ next unless File.file?(rb_file)
+
+ File.foreach(rb_file).with_index(1) do |line, lineno|
+ next unless line =~ /^\s*require_relative\s+["']([^"']+)["']/
+
+ required_path = Regexp.last_match(1)
+ resolved = File.join(File.dirname(rb_file), required_path)
+
+ next if @specification.files.any? {|f| f == "#{resolved}.rb" || f == resolved }
+
+ warning <<~WARNING
+ #{rb_file}:#{lineno} uses `require_relative "#{required_path}"` to load a compiled extension.
+ This will break in RubyGems 4.2, which will stop copying compiled extensions into the gem's lib directory.
+ Use `require` instead of `require_relative` to load compiled extensions.
+ WARNING
+ end
+ end
+ end
+
def validate_unique_links
links = @specification.metadata.slice(*METADATA_LINK_KEYS)
grouped = links.group_by {|_key, uri| uri }
diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb
index 195a355496..c7e5cbedb5 100644
--- a/lib/rubygems/specification_record.rb
+++ b/lib/rubygems/specification_record.rb
@@ -73,7 +73,7 @@ module Gem
end
##
- # Adds +spec+ to the the record, keeping the collection properly sorted.
+ # Adds +spec+ to the record, keeping the collection properly sorted.
def add_spec(spec)
return if all.include? spec
@@ -155,6 +155,19 @@ module Gem
end
##
+ # Return the best specification that contains the file matching +path+
+ # amongst the specs that are not loaded. This method is different than
+ # +find_inactive_by_path+ as it will filter out loaded specs by their name.
+
+ def find_unloaded_by_path(path)
+ stub = stubs.find do |s|
+ next if Gem.loaded_specs[s.name]
+ s.contains_requirable_file? path
+ end
+ stub&.to_spec
+ end
+
+ ##
# Return the best specification in the record that contains the file
# matching +path+ amongst the specs that are not activated.
diff --git a/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem b/lib/rubygems/ssl_certs/rubygems.org/GlobalSign.pem
index 8afb219058..8afb219058 100644
--- a/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem
+++ b/lib/rubygems/ssl_certs/rubygems.org/GlobalSign.pem
diff --git a/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem b/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem
deleted file mode 100644
index f4ce4ca43d..0000000000
--- a/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
-A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
-b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
-MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
-YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
-aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
-jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
-xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
-1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
-snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
-U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
-9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
-AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
-yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
-38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
-AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
-DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
-HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
------END CERTIFICATE-----
diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb
index 4f6a70ba4b..53b337ed85 100644
--- a/lib/rubygems/stub_specification.rb
+++ b/lib/rubygems/stub_specification.rb
@@ -140,6 +140,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
end
def missing_extensions?
+ return false if RUBY_ENGINE == "jruby"
return false if default_gem?
return false if extensions.empty?
return false if File.exist? gem_build_complete_path
diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb
index da0795b771..88d4ce59b4 100644
--- a/lib/rubygems/text.rb
+++ b/lib/rubygems/text.rb
@@ -21,7 +21,7 @@ module Gem::Text
# Wraps +text+ to +wrap+ characters and optionally indents by +indent+
# characters
- def format_text(text, wrap, indent=0)
+ def format_text(text, wrap, indent = 0)
result = []
work = clean_text(text)
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index 991bc6fb95..fe4c3a80cf 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -42,10 +42,25 @@ class Gem::Uninstaller
attr_reader :spec
##
- # Constructs an uninstaller that will uninstall +gem+
+ # Constructs an uninstaller that will uninstall gem named +gem+.
+ # +options+ is a Hash with the following keys:
+ #
+ # :version:: Version requirement for the gem to uninstall. If not specified,
+ # uses Gem::Requirement.default.
+ # :install_dir:: The directory where the gem is installed. If not specified,
+ # uses Gem.dir.
+ # :executables:: Whether executables should be removed without confirmation or not. If nil, asks the user explicitly.
+ # :all:: If more than one version matches the requirement, whether to forcefully remove all matching versions or ask the user to select specific matching versions that should be removed.
+ # :ignore:: Ignore broken dependency checks when uninstalling.
+ # :bin_dir:: Directory containing executables to remove. If not specified,
+ # uses Gem.bindir.
+ # :format_executable:: In order to find executables to be removed, format executable names using Gem::Installer.exec_format.
+ # :abort_on_dependent:: Directly abort uninstallation if dependencies would be broken, rather than asking the user for confirmation.
+ # :check_dev:: When checking if uninstalling gem would leave broken dependencies around, also consider development dependencies.
+ # :force:: Set both :all and :ignore to true for forced uninstallation.
+ # :user_install:: Uninstall from user gem directory instead of system directory.
def initialize(gem, options = {})
- # TODO: document the valid options
@gem = gem
@version = options[:version] || Gem::Requirement.default
@install_dir = options[:install_dir]
@@ -57,10 +72,6 @@ class Gem::Uninstaller
@bin_dir = options[:bin_dir]
@format_executable = options[:format_executable]
@abort_on_dependent = options[:abort_on_dependent]
-
- # Indicate if development dependencies should be checked when
- # uninstalling. (default: false)
- #
@check_dev = options[:check_dev]
if options[:force]
diff --git a/lib/rubygems/uri_formatter.rb b/lib/rubygems/uri_formatter.rb
index 517ce33637..8856fdadd2 100644
--- a/lib/rubygems/uri_formatter.rb
+++ b/lib/rubygems/uri_formatter.rb
@@ -17,7 +17,8 @@ class Gem::UriFormatter
# Creates a new URI formatter for +uri+.
def initialize(uri)
- require "cgi"
+ require "cgi/escape"
+ require "cgi/util" unless defined?(CGI::EscapeExt)
@uri = uri
end
diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb
index 0172c4ee89..9fe3e755c4 100644
--- a/lib/rubygems/user_interaction.rb
+++ b/lib/rubygems/user_interaction.rb
@@ -6,7 +6,6 @@
# See LICENSE.txt for permissions.
#++
-require_relative "deprecate"
require_relative "text"
##
@@ -170,8 +169,6 @@ end
# Gem::StreamUI implements a simple stream based user interface.
class Gem::StreamUI
- extend Gem::Deprecate
-
##
# The input stream
@@ -193,7 +190,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
@@ -246,7 +243,7 @@ class Gem::StreamUI
# to a tty, raises an exception if default is nil, otherwise returns
# default.
- def ask_yes_no(question, default=nil)
+ def ask_yes_no(question, default = nil)
unless tty?
if default.nil?
raise Gem::OperationNotSupportedError,
@@ -325,14 +322,14 @@ class Gem::StreamUI
##
# Display a statement.
- def say(statement="")
+ def say(statement = "")
@outs.puts statement
end
##
# Display an informational alert. Will ask +question+ if it is not nil.
- def alert(statement, question=nil)
+ def alert(statement, question = nil)
@outs.puts "INFO: #{statement}"
ask(question) if question
end
@@ -340,7 +337,7 @@ class Gem::StreamUI
##
# Display a warning on stderr. Will ask +question+ if it is not nil.
- def alert_warning(statement, question=nil)
+ def alert_warning(statement, question = nil)
@errs.puts "WARNING: #{statement}"
ask(question) if question
end
@@ -349,7 +346,7 @@ class Gem::StreamUI
# Display an error message in a location expected to get error messages.
# Will ask +question+ if it is not nil.
- def alert_error(statement, question=nil)
+ def alert_error(statement, question = nil)
@errs.puts "ERROR: #{statement}"
ask(question) if question
end
diff --git a/lib/rubygems/util.rb b/lib/rubygems/util.rb
index 51f9c2029f..ee4106c6ce 100644
--- a/lib/rubygems/util.rb
+++ b/lib/rubygems/util.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "deprecate"
-
##
# This module contains various utility methods as module methods.
@@ -57,26 +55,6 @@ module Gem::Util
end
##
- # Invokes system, but silences all output.
-
- def self.silent_system(*command)
- opt = { out: IO::NULL, err: [:child, :out] }
- if Hash === command.last
- opt.update(command.last)
- cmds = command[0...-1]
- else
- cmds = command.dup
- end
- system(*(cmds << opt))
- end
-
- class << self
- extend Gem::Deprecate
-
- rubygems_deprecate :silent_system
- end
-
- ##
# Enumerates the parents of +directory+.
def self.traverse_parents(directory, &block)
diff --git a/lib/rubygems/util/atomic_file_writer.rb b/lib/rubygems/util/atomic_file_writer.rb
new file mode 100644
index 0000000000..32767c6a79
--- /dev/null
+++ b/lib/rubygems/util/atomic_file_writer.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+# Based on ActiveSupport's AtomicFile implementation
+# Copyright (c) David Heinemeier Hansson
+# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/file/atomic.rb
+# Licensed under the MIT License
+
+module Gem
+ class AtomicFileWriter
+ ##
+ # Write to a file atomically. Useful for situations where you don't
+ # want other processes or threads to see half-written files.
+
+ def self.open(file_name)
+ require "securerandom" unless defined?(SecureRandom)
+
+ old_stat = begin
+ File.stat(file_name)
+ rescue SystemCallError
+ nil
+ end
+
+ # Names can't be longer than 255B
+ tmp_suffix = ".tmp.#{SecureRandom.hex}"
+ dirname = File.dirname(file_name)
+ basename = File.basename(file_name)
+ tmp_path = File.join(dirname, ".#{basename.byteslice(0, 254 - tmp_suffix.bytesize)}#{tmp_suffix}")
+
+ flags = File::RDWR | File::CREAT | File::EXCL | File::BINARY
+ flags |= File::SHARE_DELETE if defined?(File::SHARE_DELETE)
+
+ File.open(tmp_path, flags) do |temp_file|
+ temp_file.binmode
+ if old_stat
+ # Set correct permissions on new file
+ begin
+ File.chown(old_stat.uid, old_stat.gid, temp_file.path)
+ # This operation will affect filesystem ACL's
+ File.chmod(old_stat.mode, temp_file.path)
+ rescue Errno::EPERM, Errno::EACCES
+ # Changing file ownership failed, moving on.
+ end
+ end
+
+ return_val = yield temp_file
+ rescue StandardError => error
+ begin
+ temp_file.close
+ rescue StandardError
+ nil
+ end
+
+ begin
+ File.unlink(temp_file.path)
+ rescue StandardError
+ nil
+ end
+
+ raise error
+ else
+ begin
+ File.rename(temp_file.path, file_name)
+ rescue StandardError
+ begin
+ File.unlink(temp_file.path)
+ rescue StandardError
+ end
+
+ raise
+ end
+
+ return_val
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb
index 3d9df5ebcd..caf53d0b7e 100644
--- a/lib/rubygems/util/licenses.rb
+++ b/lib/rubygems/util/licenses.rb
@@ -27,6 +27,7 @@ class Gem::Licenses
AGPL-1.0-or-later
AGPL-3.0-only
AGPL-3.0-or-later
+ ALGLIB-Documentation
AMD-newlib
AMDPLPA
AML
@@ -48,6 +49,7 @@ class Gem::Licenses
Adobe-Display-PostScript
Adobe-Glyph
Adobe-Utopia
+ Advanced-Cryptics-Dictionary
Afmparse
Aladdin
Apache-1.0
@@ -59,12 +61,16 @@ class Gem::Licenses
Artistic-1.0-Perl
Artistic-1.0-cl8
Artistic-2.0
+ Artistic-dist
+ Aspell-RU
+ BOLA-1.1
BSD-1-Clause
BSD-2-Clause
BSD-2-Clause-Darwin
BSD-2-Clause-Patent
BSD-2-Clause-Views
BSD-2-Clause-first-lines
+ BSD-2-Clause-pkgconf-disclaimer
BSD-3-Clause
BSD-3-Clause-Attribution
BSD-3-Clause-Clear
@@ -77,6 +83,7 @@ class Gem::Licenses
BSD-3-Clause-No-Nuclear-Warranty
BSD-3-Clause-Open-MPI
BSD-3-Clause-Sun
+ BSD-3-Clause-Tso
BSD-3-Clause-acpica
BSD-3-Clause-flex
BSD-4-Clause
@@ -87,6 +94,7 @@ class Gem::Licenses
BSD-Advertising-Acknowledgement
BSD-Attribution-HPND-disclaimer
BSD-Inferno-Nettverk
+ BSD-Mark-Modifications
BSD-Protection
BSD-Source-Code
BSD-Source-beginning-file
@@ -108,9 +116,11 @@ class Gem::Licenses
Borceux
Brian-Gladman-2-Clause
Brian-Gladman-3-Clause
+ Buddy
C-UDA-1.0
CAL-1.0
CAL-1.0-Combined-Work-Exception
+ CAPEC-tou
CATOSL-1.1
CC-BY-1.0
CC-BY-2.0
@@ -205,6 +215,7 @@ class Gem::Licenses
Cornell-Lossless-JPEG
Cronyx
Crossword
+ CryptoSwift
CrystalStacker
Cube
D-FSL-1.0
@@ -215,6 +226,7 @@ class Gem::Licenses
DRL-1.0
DRL-1.1
DSDP
+ DocBook-DTD
DocBook-Schema
DocBook-Stylesheet
DocBook-XML
@@ -226,6 +238,9 @@ class Gem::Licenses
EPICS
EPL-1.0
EPL-2.0
+ ESA-PL-permissive-2.4
+ ESA-PL-strong-copyleft-2.4
+ ESA-PL-weak-copyleft-2.4
EUDatagrid
EUPL-1.0
EUPL-1.1
@@ -240,7 +255,10 @@ class Gem::Licenses
FSFAP-no-warranty-disclaimer
FSFUL
FSFULLR
+ FSFULLRSD
FSFULLRWD
+ FSL-1.1-ALv2
+ FSL-1.1-MIT
FTL
Fair
Ferguson-Twofish
@@ -276,11 +294,13 @@ class Gem::Licenses
GPL-2.0-or-later
GPL-3.0-only
GPL-3.0-or-later
+ Game-Programming-Gems
Giftware
Glide
Glulxe
Graphics-Gems
Gutmann
+ HDF5
HIDAPI
HP-1986
HP-1989
@@ -294,6 +314,7 @@ class Gem::Licenses
HPND-Markus-Kuhn
HPND-Netrek
HPND-Pbmplus
+ HPND-SMC
HPND-UC
HPND-UC-export-US
HPND-doc
@@ -308,6 +329,7 @@ class Gem::Licenses
HPND-sell-variant
HPND-sell-variant-MIT-disclaimer
HPND-sell-variant-MIT-disclaimer-rev
+ HPND-sell-variant-critical-systems
HTMLTIDY
HaskellReport
Hippocratic-2.1
@@ -320,6 +342,7 @@ class Gem::Licenses
IPL-1.0
ISC
ISC-Veillard
+ ISO-permission
ImageMagick
Imlib2
Info-ZIP
@@ -377,6 +400,7 @@ class Gem::Licenses
MIT-Festival
MIT-Khronos-old
MIT-Modern-Variant
+ MIT-STK
MIT-Wu
MIT-advertising
MIT-enna
@@ -385,6 +409,7 @@ class Gem::Licenses
MIT-testregex
MITNFA
MMIXware
+ MMPL-1.0.1
MPEG-SSG
MPL-1.0
MPL-1.1
@@ -416,6 +441,7 @@ class Gem::Licenses
NGPL
NICTA-1.0
NIST-PD
+ NIST-PD-TNT
NIST-PD-fallback
NIST-Software
NLOD-1.0
@@ -426,6 +452,7 @@ class Gem::Licenses
NPL-1.1
NPOSL-3.0
NRL
+ NTIA-PD
NTP
NTP-0
Naumen
@@ -474,12 +501,15 @@ class Gem::Licenses
OPL-1.0
OPL-UK-3.0
OPUBL-1.0
+ OSC-1.0
OSET-PL-2.1
OSL-1.0
OSL-1.1
OSL-2.0
OSL-2.1
OSL-3.0
+ OSSP
+ OpenMDW-1.0
OpenPBS-2.3
OpenSSL
OpenSSL-standalone
@@ -490,6 +520,7 @@ class Gem::Licenses
PHP-3.01
PPL
PSF-2.0
+ ParaType-Free-Font-1.3
Parity-6.0.0
Parity-7.0.0
Pixar
@@ -518,6 +549,7 @@ class Gem::Licenses
SGI-B-1.1
SGI-B-2.0
SGI-OpenGL
+ SGMLUG-PM
SGP4
SHL-0.5
SHL-0.51
@@ -528,11 +560,13 @@ class Gem::Licenses
SMLNJ
SMPPL
SNIA
+ SOFA
SPL-1.0
SSH-OpenSSH
SSH-short
SSLeay-standalone
SSPL-1.0
+ SUL-1.0
SWL
Saxpath
SchemeReport
@@ -563,6 +597,7 @@ class Gem::Licenses
TTYP0
TU-Berlin-1.0
TU-Berlin-2.0
+ TekHVC
TermReadKey
ThirdEye
TrustedQSL
@@ -572,24 +607,31 @@ class Gem::Licenses
UPL-1.0
URT-RLE
Ubuntu-font-1.0
+ UnRAR
Unicode-3.0
Unicode-DFS-2015
Unicode-DFS-2016
Unicode-TOU
UnixCrypt
Unlicense
+ Unlicense-libtelnet
+ Unlicense-libwhirlpool
VOSTROM
VSL-1.0
Vim
+ Vixie-Cron
W3C
W3C-19980720
W3C-20150513
+ WTFNMFPL
WTFPL
Watcom-1.0
Widget-Workshop
+ WordNet
Wsuipa
X11
X11-distribute-modifications-variant
+ X11-no-permit-persons
X11-swapped
XFree86-1.1
XSkat
@@ -630,7 +672,10 @@ class Gem::Licenses
gnuplot
gtkbook
hdparm
+ hyphen-bulgarian
iMatix
+ jove
+ libpng-1.6.35
libpng-2.0
libselinux-1.0
libtiff
@@ -638,10 +683,12 @@ class Gem::Licenses
lsof
magaz
mailprio
+ man2html
metamail
mpi-permissive
mpich2
mplus
+ ngrep
pkgconf
pnmstitch
psfrag
@@ -715,7 +762,9 @@ class Gem::Licenses
CGAL-linking-exception
CLISP-exception-2.0
Classpath-exception-2.0
+ Classpath-exception-2.0-short
DigiRule-FOSS-exception
+ Digia-Qt-LGPL-exception-1.1
FLTK-exception
Fawkes-Runtime-exception
Font-exception-2.0
@@ -755,6 +804,7 @@ class Gem::Licenses
SHL-2.0
SHL-2.1
SWI-exception
+ Simple-Library-Usage-exception
Swift-exception
Texinfo-exception
UBDL-exception
@@ -768,11 +818,15 @@ class Gem::Licenses
gnu-javamail-exception
harbour-exception
i2p-gpl-java-exception
+ kvirc-openssl-exception
libpri-OpenH323-exception
mif-exception
mxml-exception
openvpn-openssl-exception
+ polyparse-exception
romic-exception
+ rsync-linking-exception
+ sqlitestudio-OpenSSL-exception
stunnel-exception
u-boot-exception-2.0
vsftpd-openssl-exception
diff --git a/lib/rubygems/util/list.rb b/lib/rubygems/util/list.rb
deleted file mode 100644
index 2899e8a2b9..0000000000
--- a/lib/rubygems/util/list.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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:
- include Enumerable
- attr_accessor :value, :tail
-
- def initialize(value = nil, tail = nil)
- @value = value
- @tail = tail
- end
-
- def each
- n = self
- while n
- yield n.value
- n = n.tail
- end
- end
-
- def to_a
- super.reverse
- end
-
- def prepend(value)
- List.new value, self
- end
-
- def pretty_print(q) # :nodoc:
- q.pp to_a
- end
-
- def self.prepend(list, value)
- return List.new(value) unless list
- List.new value, list
- end
- end
- deprecate_constant :List
-end
diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb
index 57e0747eb4..eb5b513570 100644
--- a/lib/rubygems/validator.rb
+++ b/lib/rubygems/validator.rb
@@ -59,7 +59,7 @@ class Gem::Validator
#--
# TODO needs further cleanup
- def alien(gems=[])
+ def alien(gems = [])
errors = Hash.new {|h,k| h[k] = {} }
Gem::Specification.each do |spec|
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/lib/net/http.rb b/lib/rubygems/vendor/net-http/lib/net/http.rb
index ad3e646cca..4800cd25f1 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http.rb
@@ -46,7 +46,7 @@ module Gem::Net #:nodoc:
# == Strategies
#
# - If you will make only a few GET requests,
- # consider using {OpenURI}[rdoc-ref:OpenURI].
+ # consider using {OpenURI}[https://docs.ruby-lang.org/en/master/OpenURI.html].
# - 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
@@ -102,14 +102,14 @@ module Gem::Net #:nodoc:
#
# == URIs
#
- # On the internet, a URI
+ # On the internet, a Gem::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].
+ # see {Gem::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.
+ # A Ruby {Gem::URI::Generic}[https://docs.ruby-lang.org/en/master/Gem::URI/Generic.html] object
+ # represents an internet Gem::URI.
# It provides, among others, methods
# +scheme+, +hostname+, +path+, +query+, and +fragment+.
#
@@ -144,7 +144,7 @@ module Gem::Net #:nodoc:
#
# === Queries
#
- # A host-specific query adds name/value pairs to the URI:
+ # A host-specific query adds name/value pairs to the Gem::URI:
#
# _uri = uri.dup
# params = {userId: 1, completed: false}
@@ -154,7 +154,7 @@ module Gem::Net #:nodoc:
#
# === Fragments
#
- # A {URI fragment}[https://en.wikipedia.org/wiki/URI_fragment] has no effect
+ # A {Gem::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.
#
@@ -327,9 +327,9 @@ module Gem::Net #:nodoc:
# res = http.request(req)
# end
#
- # Or if you simply want to make a GET request, you may pass in a URI
+ # Or if you simply want to make a GET request, you may pass in a Gem::URI
# object that has an \HTTPS URL. \Gem::Net::HTTP automatically turns on TLS
- # verification if the URI object has a 'https' :URI scheme:
+ # verification if the Gem::URI object has a 'https' Gem::URI scheme:
#
# uri # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com/>
# Gem::Net::HTTP.get(uri)
@@ -374,7 +374,7 @@ module Gem::Net #:nodoc:
#
# 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;
+ # the returned +http+ will have the server at that Gem::URI as its proxy;
# note that the \Gem::URI string must have a protocol
# such as <tt>'http'</tt> or <tt>'https'</tt>:
#
@@ -460,7 +460,7 @@ module Gem::Net #:nodoc:
#
# First, what's elsewhere. Class Gem::Net::HTTP:
#
- # - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
+ # - Inherits from {class Object}[https://docs.ruby-lang.org/en/master/Object.html#class-Object-label-What-27s+Here].
#
# This is a categorized summary of methods and attributes.
#
@@ -475,8 +475,7 @@ module Gem::Net #:nodoc:
#
# - {::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?]):
+ # - {#started?}[rdoc-ref:Gem::Net::HTTP#started?]:
# Returns whether in a session.
# - {#finish}[rdoc-ref:Gem::Net::HTTP#finish]:
# Ends an active session.
@@ -556,18 +555,15 @@ module Gem::Net #:nodoc:
# 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]):
+ # - {#request_get}[rdoc-ref:Gem::Net::HTTP#request_get]:
# 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]):
+ # - {#request_head}[rdoc-ref:Gem::Net::HTTP#request_head]:
# 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]):
+ # - {#request_post}[rdoc-ref:Gem::Net::HTTP#request_post]:
# Sends a POST request and forms a response object;
# if a block given, calls the block with the object,
# otherwise returns the object.
@@ -605,8 +601,7 @@ module Gem::Net #:nodoc:
# 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]):
+ # - {#proxy_address}[rdoc-ref:Gem::Net::HTTP#proxy_address]:
# 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.
@@ -718,8 +713,7 @@ module Gem::Net #:nodoc:
# === \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]):
+ # (aliased as {::version_1_2}[rdoc-ref:Gem::Net::HTTP.version_1_2]):
# Returns true; retained for compatibility.
#
# === Debugging
@@ -730,7 +724,7 @@ module Gem::Net #:nodoc:
class HTTP < Protocol
# :stopdoc:
- VERSION = "0.6.0"
+ VERSION = "0.9.1"
HTTPVersion = '1.1'
begin
require 'zlib'
@@ -796,7 +790,7 @@ module Gem::Net #:nodoc:
# "completed": false
# }
#
- # With URI object +uri+ and optional hash argument +headers+:
+ # With Gem::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'}
@@ -869,7 +863,7 @@ module Gem::Net #:nodoc:
# Posts data to a host; returns a Gem::Net::HTTPResponse object.
#
- # Argument +url+ must be a URI;
+ # Argument +url+ must be a Gem::URI;
# argument +data+ must be a hash:
#
# _uri = uri.dup
@@ -1185,6 +1179,7 @@ module Gem::Net #:nodoc:
@debug_output = options[:debug_output]
@response_body_encoding = options[:response_body_encoding]
@ignore_eof = options[:ignore_eof]
+ @tcpsocket_supports_open_timeout = nil
@proxy_from_env = false
@proxy_uri = nil
@@ -1293,7 +1288,7 @@ module Gem::Net #:nodoc:
# - The name of an encoding.
# - An alias for an encoding name.
#
- # See {Encoding}[rdoc-ref:Encoding].
+ # See {Encoding}[https://docs.ruby-lang.org/en/master/Encoding.html].
#
# Examples:
#
@@ -1327,6 +1322,9 @@ module Gem::Net #:nodoc:
# Sets the proxy password;
# see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
attr_writer :proxy_pass
+
+ # Sets whether the proxy uses SSL;
+ # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
attr_writer :proxy_use_ssl
# Returns the IP address for the connection.
@@ -1533,9 +1531,9 @@ module Gem::Net #:nodoc:
:verify_depth,
:verify_mode,
:verify_hostname,
- ] # :nodoc:
+ ].freeze # :nodoc:
- SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym } # :nodoc:
+ SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym }.freeze # :nodoc:
# Sets or returns the path to a CA certification file in PEM format.
attr_accessor :ca_file
@@ -1552,11 +1550,11 @@ module Gem::Net #:nodoc:
attr_accessor :cert_store
# Sets or returns the available SSL ciphers.
- # See {OpenSSL::SSL::SSLContext#ciphers=}[rdoc-ref:OpenSSL::SSL::SSLContext#ciphers-3D].
+ # See {OpenSSL::SSL::SSLContext#ciphers=}[OpenSSL::SSL::SSL::Context#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].
+ # See {OpenSSL::SSL::SSLContext#add_certificate}[OpenSSL::SSL::SSL::Context#add_certificate].
attr_accessor :extra_chain_cert
# Sets or returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
@@ -1566,15 +1564,15 @@ module Gem::Net #:nodoc:
attr_accessor :ssl_timeout
# Sets or returns the SSL version.
- # See {OpenSSL::SSL::SSLContext#ssl_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#ssl_version-3D].
+ # See {OpenSSL::SSL::SSLContext#ssl_version=}[OpenSSL::SSL::SSL::Context#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].
+ # See {OpenSSL::SSL::SSLContext#min_version=}[OpenSSL::SSL::SSL::Context#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].
+ # See {OpenSSL::SSL::SSLContext#max_version=}[OpenSSL::SSL::SSL::Context#max_version=].
attr_accessor :max_version
# Sets or returns the callback for the server certification verification.
@@ -1590,7 +1588,7 @@ module Gem::Net #:nodoc:
# 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].
+ # See {OpenSSL::SSL::SSLContext#verify_hostname=}[OpenSSL::SSL::SSL::Context#verify_hostname=].
attr_accessor :verify_hostname
# Returns the X509 certificate chain (an array of strings)
@@ -1638,6 +1636,21 @@ module Gem::Net #:nodoc:
self
end
+ # 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
+
+ # :stopdoc:
def do_start
connect
@started = true
@@ -1660,14 +1673,15 @@ module Gem::Net #:nodoc:
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})"
+ begin
+ s = timeouted_connect(conn_addr, conn_port)
+ rescue => e
+ if (defined?(IO::TimeoutError) && e.is_a?(IO::TimeoutError)) || e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
+ e = Gem::Net::OpenTimeout.new(e)
end
- }
+ 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?
@@ -1760,23 +1774,30 @@ module Gem::Net #:nodoc:
end
private :connect
- def on_connect
+ tcp_socket_parameters = TCPSocket.instance_method(:initialize).parameters
+ TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT = if tcp_socket_parameters != [[:rest]]
+ tcp_socket_parameters.include?([:key, :open_timeout])
+ else
+ # Use Socket.tcp to find out since there is no parameters information for TCPSocket#initialize
+ # See discussion in https://github.com/ruby/net-http/pull/224
+ Socket.method(:tcp).parameters.include?([:key, :open_timeout])
end
- private :on_connect
+ private_constant :TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
- # 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
+ def timeouted_connect(conn_addr, conn_port)
+ if TCP_SOCKET_NEW_HAS_OPEN_TIMEOUT
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
+ else
+ Gem::Timeout.timeout(@open_timeout, Gem::Net::OpenTimeout) {
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
+ }
+ end
+ end
+ private :timeouted_connect
+
+ def on_connect
end
+ private :on_connect
def do_finish
@started = false
@@ -1827,6 +1848,8 @@ module Gem::Net #:nodoc:
}
end
+ # :startdoc:
+
class << HTTP
# Returns true if self is a class which was created by HTTP::Proxy.
def proxy_class?
@@ -1866,7 +1889,7 @@ module Gem::Net #:nodoc:
@proxy_from_env
end
- # The proxy URI determined from the environment for this connection.
+ # The proxy Gem::URI determined from the environment for this connection.
def proxy_uri # :nodoc:
return if @proxy_uri == false
@proxy_uri ||= Gem::URI::HTTP.new(
@@ -1921,9 +1944,11 @@ module Gem::Net #:nodoc:
alias proxyport proxy_port #:nodoc: obsolete
private
+ # :stopdoc:
def unescape(value)
- require 'cgi/util'
+ require 'cgi/escape'
+ require 'cgi/util' unless defined?(CGI::EscapeExt)
CGI.unescape(value)
end
@@ -1948,6 +1973,7 @@ module Gem::Net #:nodoc:
path
end
end
+ # :startdoc:
#
# HTTP operations
@@ -2402,7 +2428,9 @@ module Gem::Net #:nodoc:
res
end
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
+ # :stopdoc:
+
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/.freeze # :nodoc:
def transport_request(req)
count = 0
@@ -2559,7 +2587,7 @@ module Gem::Net #:nodoc:
alias_method :D, :debug
end
- # for backward compatibility until Ruby 3.5
+ # for backward compatibility until Ruby 4.0
# https://bugs.ruby-lang.org/issues/20900
# https://github.com/bblimke/webmock/pull/1081
HTTPSession = HTTP
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb b/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
index c629c0113b..218df9a8bd 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
@@ -3,7 +3,7 @@ module Gem::Net
# Gem::Net::HTTP exception class.
# You cannot use Gem::Net::HTTPExceptions directly; instead, you must use
# its subclasses.
- module HTTPExceptions
+ module HTTPExceptions # :nodoc:
def initialize(msg, res) #:nodoc:
super msg
@response = res
@@ -12,6 +12,7 @@ module Gem::Net
alias data response #:nodoc: obsolete
end
+ # :stopdoc:
class HTTPError < ProtocolError
include HTTPExceptions
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
index 5cfe75a7cd..d6496d4ac1 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
@@ -19,16 +19,13 @@ class Gem::Net::HTTPGenericRequest
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
+ hostname = uri_or_path.host
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
@@ -51,7 +48,7 @@ class Gem::Net::HTTPGenericRequest
initialize_http_header initheader
self['Accept'] ||= '*/*'
self['User-Agent'] ||= 'Ruby'
- self['Host'] ||= host if host
+ self['Host'] ||= @uri.authority if @uri
@body = nil
@body_stream = nil
@body_data = nil
@@ -102,6 +99,31 @@ class Gem::Net::HTTPGenericRequest
"\#<#{self.class} #{@method}>"
end
+ # Returns a string representation of the request with the details for pp:
+ #
+ # require 'pp'
+ # post = Gem::Net::HTTP::Post.new(uri)
+ # post.inspect # => "#<Gem::Net::HTTP::Post POST>"
+ # post.pretty_inspect
+ # # => #<Gem::Net::HTTP::Post
+ # POST
+ # path="/"
+ # headers={"accept-encoding" => ["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
+ # "accept" => ["*/*"],
+ # "user-agent" => ["Ruby"],
+ # "host" => ["www.ruby-lang.org"]}>
+ #
+ def pretty_print(q)
+ q.object_group(self) {
+ q.breakable
+ q.text @method
+ q.breakable
+ q.text "path="; q.pp @path
+ q.breakable
+ q.text "headers="; q.pp to_hash
+ }
+ end
+
##
# Don't automatically decode response content-encoding if the user indicates
# they want to handle it.
@@ -220,7 +242,7 @@ class Gem::Net::HTTPGenericRequest
end
if host = self['host']
- host.sub!(/:.*/m, '')
+ host = Gem::URI.parse("//#{host}").host # Remove a port component from the existing Host header
elsif host = @uri.host
else
host = addr
@@ -239,6 +261,8 @@ class Gem::Net::HTTPGenericRequest
private
+ # :stopdoc:
+
class Chunker #:nodoc:
def initialize(sock)
@sock = sock
@@ -260,7 +284,6 @@ class Gem::Net::HTTPGenericRequest
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
@@ -271,7 +294,6 @@ class Gem::Net::HTTPGenericRequest
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?
@@ -373,12 +395,6 @@ class Gem::Net::HTTPGenericRequest
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.
@@ -411,4 +427,3 @@ class Gem::Net::HTTPGenericRequest
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
index 5cb1da01ec..bc68cd2eef 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/header.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/header.rb
@@ -179,7 +179,9 @@
# - #each_value: Passes each string field value to the block.
#
module Gem::Net::HTTPHeader
+ # The maximum length of HTTP header keys.
MAX_KEY_LENGTH = 1024
+ # The maximum length of HTTP header values.
MAX_FIELD_LENGTH = 65536
def initialize_http_header(initheader) #:nodoc:
@@ -267,6 +269,7 @@ module Gem::Net::HTTPHeader
end
end
+ # :stopdoc:
private def set_field(key, val)
case val
when Enumerable
@@ -294,6 +297,7 @@ module Gem::Net::HTTPHeader
ary.push val
end
end
+ # :startdoc:
# Returns the array field value for the given +key+,
# or +nil+ if there is no such field;
@@ -490,7 +494,7 @@ module Gem::Net::HTTPHeader
alias canonical_each each_capitalized
- def capitalize(name)
+ def capitalize(name) # :nodoc:
name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
end
private :capitalize
@@ -957,12 +961,12 @@ module Gem::Net::HTTPHeader
@header['proxy-authorization'] = [basic_encode(account, password)]
end
- def basic_encode(account, password)
+ def basic_encode(account, password) # :nodoc:
'Basic ' + ["#{account}:#{password}"].pack('m0')
end
private :basic_encode
-# Returns whether the HTTP session is to be closed.
+ # 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 +974,7 @@ module Gem::Net::HTTPHeader
false
end
-# Returns whether the HTTP session is to be kept alive.
+ # 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/rubygems/vendor/net-http/lib/net/http/requests.rb b/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
index 45727e7f61..f990761042 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
@@ -29,6 +29,7 @@
# - Gem::Net::HTTP#get: sends +GET+ request, returns response object.
#
class Gem::Net::HTTP::Get < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'GET'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -60,6 +61,7 @@ end
# - Gem::Net::HTTP#head: sends +HEAD+ request, returns response object.
#
class Gem::Net::HTTP::Head < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'HEAD'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = false
@@ -95,6 +97,7 @@ end
# - Gem::Net::HTTP#post: sends +POST+ request, returns response object.
#
class Gem::Net::HTTP::Post < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'POST'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -130,6 +133,7 @@ end
# - Gem::Net::HTTP#put: sends +PUT+ request, returns response object.
#
class Gem::Net::HTTP::Put < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PUT'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -162,6 +166,7 @@ end
# - Gem::Net::HTTP#delete: sends +DELETE+ request, returns response object.
#
class Gem::Net::HTTP::Delete < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'DELETE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -193,6 +198,7 @@ end
# - Gem::Net::HTTP#options: sends +OPTIONS+ request, returns response object.
#
class Gem::Net::HTTP::Options < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'OPTIONS'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -224,6 +230,7 @@ end
# - Gem::Net::HTTP#trace: sends +TRACE+ request, returns response object.
#
class Gem::Net::HTTP::Trace < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'TRACE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -258,6 +265,7 @@ end
# - Gem::Net::HTTP#patch: sends +PATCH+ request, returns response object.
#
class Gem::Net::HTTP::Patch < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -285,6 +293,7 @@ end
# - Gem::Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
#
class Gem::Net::HTTP::Propfind < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPFIND'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -308,6 +317,7 @@ end
# - Gem::Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
#
class Gem::Net::HTTP::Proppatch < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'PROPPATCH'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -331,6 +341,7 @@ end
# - Gem::Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
#
class Gem::Net::HTTP::Mkcol < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MKCOL'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -354,6 +365,7 @@ end
# - Gem::Net::HTTP#copy: sends +COPY+ request, returns response object.
#
class Gem::Net::HTTP::Copy < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'COPY'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -377,6 +389,7 @@ end
# - Gem::Net::HTTP#move: sends +MOVE+ request, returns response object.
#
class Gem::Net::HTTP::Move < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'MOVE'
REQUEST_HAS_BODY = false
RESPONSE_HAS_BODY = true
@@ -400,6 +413,7 @@ end
# - Gem::Net::HTTP#lock: sends +LOCK+ request, returns response object.
#
class Gem::Net::HTTP::Lock < Gem::Net::HTTPRequest
+ # :stopdoc:
METHOD = 'LOCK'
REQUEST_HAS_BODY = true
RESPONSE_HAS_BODY = true
@@ -423,8 +437,8 @@ end
# - Gem::Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
#
class Gem::Net::HTTP::Unlock < Gem::Net::HTTPRequest
+ # :stopdoc:
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
index cbbd191d87..dc164f1504 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/response.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/response.rb
@@ -153,6 +153,7 @@ class Gem::Net::HTTPResponse
end
private
+ # :stopdoc:
def read_status_line(sock)
str = sock.readline
@@ -259,7 +260,7 @@ class Gem::Net::HTTPResponse
# header.
attr_accessor :ignore_eof
- def inspect
+ def inspect # :nodoc:
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
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
index 0f26ae6c26..62ce1cba1b 100644
--- a/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
+++ b/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
@@ -4,7 +4,9 @@
module Gem::Net
+ # Unknown HTTP response
class HTTPUnknownResponse < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -19,6 +21,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response].
#
class HTTPInformation < HTTPResponse
+ # :stopdoc:
HAS_BODY = false
EXCEPTION_TYPE = HTTPError #
end
@@ -34,6 +37,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success].
#
class HTTPSuccess < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPError #
end
@@ -49,6 +53,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection].
#
class HTTPRedirection < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPRetriableError #
end
@@ -63,6 +68,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors].
#
class HTTPClientError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPClientException #
end
@@ -77,6 +83,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors].
#
class HTTPServerError < HTTPResponse
+ # :stopdoc:
HAS_BODY = true
EXCEPTION_TYPE = HTTPFatalError #
end
@@ -94,6 +101,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#100].
#
class HTTPContinue < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -111,6 +119,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#101].
#
class HTTPSwitchProtocol < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -127,6 +136,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
#
class HTTPProcessing < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -145,6 +155,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
#
class HTTPEarlyHints < HTTPInformation
+ # :stopdoc:
HAS_BODY = false
end
@@ -162,6 +173,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
#
class HTTPOK < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -179,6 +191,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
#
class HTTPCreated < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -196,6 +209,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
#
class HTTPAccepted < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -215,6 +229,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
#
class HTTPNonAuthoritativeInformation < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -232,6 +247,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
#
class HTTPNoContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -250,6 +266,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
#
class HTTPResetContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = false
end
@@ -268,6 +285,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
#
class HTTPPartialContent < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -285,6 +303,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
#
class HTTPMultiStatus < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -304,6 +323,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
#
class HTTPAlreadyReported < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -321,6 +341,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
#
class HTTPIMUsed < HTTPSuccess
+ # :stopdoc:
HAS_BODY = true
end
@@ -338,6 +359,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
#
class HTTPMultipleChoices < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMultipleChoice = HTTPMultipleChoices
@@ -356,6 +378,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
#
class HTTPMovedPermanently < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -373,6 +396,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
#
class HTTPFound < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
HTTPMovedTemporarily = HTTPFound
@@ -390,6 +414,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
#
class HTTPSeeOther < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -407,6 +432,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
#
class HTTPNotModified < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -423,6 +449,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
#
class HTTPUseProxy < HTTPRedirection
+ # :stopdoc:
HAS_BODY = false
end
@@ -440,6 +467,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
#
class HTTPTemporaryRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -456,6 +484,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
#
class HTTPPermanentRedirect < HTTPRedirection
+ # :stopdoc:
HAS_BODY = true
end
@@ -472,6 +501,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
#
class HTTPBadRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -488,6 +518,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
#
class HTTPUnauthorized < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -504,6 +535,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
#
class HTTPPaymentRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -521,6 +553,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
#
class HTTPForbidden < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -537,6 +570,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
#
class HTTPNotFound < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -553,6 +587,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
#
class HTTPMethodNotAllowed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -570,6 +605,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
#
class HTTPNotAcceptable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -586,6 +622,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
#
class HTTPProxyAuthenticationRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -602,6 +639,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
#
class HTTPRequestTimeout < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestTimeOut = HTTPRequestTimeout
@@ -619,6 +657,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
#
class HTTPConflict < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -636,6 +675,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
#
class HTTPGone < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -653,6 +693,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
#
class HTTPLengthRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -670,6 +711,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
#
class HTTPPreconditionFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -686,6 +728,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
#
class HTTPPayloadTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
@@ -703,6 +746,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
#
class HTTPURITooLong < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestURITooLong = HTTPURITooLong
@@ -721,6 +765,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
#
class HTTPUnsupportedMediaType < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -737,6 +782,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
#
class HTTPRangeNotSatisfiable < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
@@ -754,6 +800,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
#
class HTTPExpectationFailed < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -774,6 +821,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
#
class HTTPMisdirectedRequest < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -790,6 +838,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
#
class HTTPUnprocessableEntity < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -805,6 +854,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
#
class HTTPLocked < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -821,6 +871,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
#
class HTTPFailedDependency < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -840,6 +891,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
#
class HTTPUpgradeRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -856,6 +908,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
#
class HTTPPreconditionRequired < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -872,6 +925,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
#
class HTTPTooManyRequests < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -889,6 +943,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
#
class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
@@ -906,6 +961,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
#
class HTTPUnavailableForLegalReasons < HTTPClientError
+ # :stopdoc:
HAS_BODY = true
end
# 444 No Response - Nginx
@@ -926,6 +982,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
#
class HTTPInternalServerError < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -943,6 +1000,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
#
class HTTPNotImplemented < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -960,6 +1018,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
#
class HTTPBadGateway < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -977,6 +1036,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
#
class HTTPServiceUnavailable < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -994,6 +1054,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
#
class HTTPGatewayTimeout < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
HTTPGatewayTimeOut = HTTPGatewayTimeout
@@ -1011,6 +1072,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
#
class HTTPVersionNotSupported < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1027,6 +1089,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
#
class HTTPVariantAlsoNegotiates < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1043,6 +1106,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
#
class HTTPInsufficientStorage < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1059,6 +1123,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
#
class HTTPLoopDetected < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
# 509 Bandwidth Limit Exceeded - Apache bw/limited extension
@@ -1076,6 +1141,7 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
#
class HTTPNotExtended < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
@@ -1092,19 +1158,21 @@ module Gem::Net
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
#
class HTTPNetworkAuthenticationRequired < HTTPServerError
+ # :stopdoc:
HAS_BODY = true
end
end
class Gem::Net::HTTPResponse
+ # :stopdoc:
CODE_CLASS_TO_OBJ = {
'1' => Gem::Net::HTTPInformation,
'2' => Gem::Net::HTTPSuccess,
'3' => Gem::Net::HTTPRedirection,
'4' => Gem::Net::HTTPClientError,
'5' => Gem::Net::HTTPServerError
- }
+ }.freeze
CODE_TO_OBJ = {
'100' => Gem::Net::HTTPContinue,
'101' => Gem::Net::HTTPSwitchProtocol,
@@ -1170,5 +1238,5 @@ class Gem::Net::HTTPResponse
'508' => Gem::Net::HTTPLoopDetected,
'510' => Gem::Net::HTTPNotExtended,
'511' => Gem::Net::HTTPNetworkAuthenticationRequired,
- }
+ }.freeze
end
diff --git a/lib/rubygems/vendor/optparse/lib/optparse.rb b/lib/rubygems/vendor/optparse/lib/optparse.rb
index 537d06f229..d39d9dd4e0 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse.rb
+++ b/lib/rubygems/vendor/optparse/lib/optparse.rb
@@ -7,6 +7,7 @@
#
# See Gem::OptionParser for documentation.
#
+require 'set' unless defined?(Set)
#--
# == Developer Documentation (not for RDoc output)
@@ -142,7 +143,7 @@
# Used:
#
# $ ruby optparse-test.rb -r
-# optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
+# optparse-test.rb:9:in '<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
# $ ruby optparse-test.rb -r my-library
# You required my-library!
#
@@ -235,7 +236,7 @@
# $ 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)
+# optparse-test.rb:15:in 'block in find_user': No User Found for id 3 (RuntimeError)
#
# === Store options to a Hash
#
@@ -425,7 +426,8 @@
#
class Gem::OptionParser
# The version string
- Gem::OptionParser::Version = "0.6.0"
+ VERSION = "0.8.0"
+ Version = VERSION # for compatibility
# :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
@@ -461,6 +463,10 @@ class Gem::OptionParser
candidates
end
+ def self.completable?(key)
+ String.try_convert(key) or defined?(key.id2name)
+ end
+
def candidate(key, icase = false, pat = nil, &_)
Completion.candidate(key, icase, pat, &method(:each))
end
@@ -496,7 +502,6 @@ class Gem::OptionParser
end
end
-
#
# Map from option/keyword string to object with completion.
#
@@ -504,7 +509,6 @@ class Gem::OptionParser
include Completion
end
-
#
# Individual switch class. Not important to the user.
#
@@ -546,11 +550,11 @@ class Gem::OptionParser
def initialize(pattern = nil, conv = nil,
short = nil, long = nil, arg = nil,
- desc = ([] if short or long), block = nil, &_block)
+ desc = ([] if short or long), block = nil, values = nil, &_block)
raise if Array === pattern
block ||= _block
- @pattern, @conv, @short, @long, @arg, @desc, @block =
- pattern, conv, short, long, arg, desc, block
+ @pattern, @conv, @short, @long, @arg, @desc, @block, @values =
+ pattern, conv, short, long, arg, desc, block, values
end
#
@@ -583,11 +587,15 @@ class Gem::OptionParser
# exception.
#
def conv_arg(arg, val = []) # :nodoc:
+ v, = *val
if conv
val = conv.call(*val)
else
val = proc {|v| v}.call(*val)
end
+ if @values
+ @values.include?(val) or raise InvalidArgument, v
+ end
return arg, block, val
end
private :conv_arg
@@ -668,7 +676,7 @@ class Gem::OptionParser
(sopts+lopts).each do |opt|
# "(-x -c -r)-l[left justify]"
- if /^--\[no-\](.+)$/ =~ opt
+ if /\A--\[no-\](.+)$/ =~ opt
o = $1
yield("--#{o}", desc.join(""))
yield("--no-#{o}", desc.join(""))
@@ -1032,7 +1040,6 @@ class Gem::OptionParser
DefaultList.short['-'] = Switch::NoArgument.new {}
DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
-
COMPSYS_HEADER = <<'XXX' # :nodoc:
typeset -A opt_args
@@ -1051,16 +1058,16 @@ XXX
end
def help_exit
- if STDOUT.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?})
+ if $stdout.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?})
less = ENV["LESS"]
- args = [{"LESS" => "#{!less || less.empty? ? '-' : less}Fe"}, pager, "w"]
+ args = [{"LESS" => "#{less} -Fe"}, pager, "w"]
print = proc do |f|
f.puts help
rescue Errno::EPIPE
# pager terminated
end
if Process.respond_to?(:fork) and false
- IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call(STDOUT)}
+ IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call($stdout)}
# unreachable
end
IO.popen(*args, &print)
@@ -1102,7 +1109,7 @@ XXX
#
Officious['*-completion-zsh'] = proc do |parser|
Switch::OptionalArgument.new do |arg|
- parser.compsys(STDOUT, arg)
+ parser.compsys($stdout, arg)
exit
end
end
@@ -1288,7 +1295,15 @@ XXX
# to $0.
#
def program_name
- @program_name || File.basename($0, '.*')
+ @program_name || strip_ext(File.basename($0))
+ end
+
+ private def strip_ext(name) # :nodoc:
+ exts = /#{
+ require "rbconfig"
+ Regexp.union(*RbConfig::CONFIG["EXECUTABLE_EXTS"]&.split(" "))
+ }\z/o
+ name.sub(exts, "")
end
# for experimental cascading :-)
@@ -1467,6 +1482,7 @@ XXX
klass = nil
q, a = nil
has_arg = false
+ values = nil
opts.each do |o|
# argument class
@@ -1480,7 +1496,7 @@ XXX
end
# directly specified pattern(any object possible to match)
- if (!(String === o || Symbol === o)) and o.respond_to?(:match)
+ if !Completion.completable?(o) and o.respond_to?(:match)
pattern = notwice(o, pattern, 'pattern')
if pattern.respond_to?(:convert)
conv = pattern.method(:convert).to_proc
@@ -1494,7 +1510,12 @@ XXX
case o
when Proc, Method
block = notwice(o, block, 'block')
- when Array, Hash
+ when Array, Hash, Set
+ if Array === o
+ o, v = o.partition {|v,| Completion.completable?(v)}
+ values = notwice(v, values, 'values') unless v.empty?
+ next if o.empty?
+ end
case pattern
when CompletingHash
when nil
@@ -1504,11 +1525,13 @@ XXX
raise ArgumentError, "argument pattern given twice"
end
o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
+ when Range
+ values = notwice(o, values, 'values')
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]*)(.+)?/
+ when /\A--no-([^\[\]=\s]*)(.+)?/
q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type')
not_pattern, not_conv = search(:atype, o) unless not_style
@@ -1519,7 +1542,7 @@ XXX
(q = q.downcase).tr!('_', '-')
long << "no-#{q}"
nolong << q
- when /^--\[no-\]([^\[\]=\s]*)(.+)?/
+ when /\A--\[no-\]([^\[\]=\s]*)(.+)?/
q, a = $1, $2
o = notwice(a ? Object : TrueClass, klass, 'type')
if a
@@ -1532,7 +1555,7 @@ XXX
not_pattern, not_conv = search(:atype, FalseClass) unless not_style
not_style = Switch::NoArgument
nolong << "no-#{o}"
- when /^--([^\[\]=\s]*)(.+)?/
+ when /\A--([^\[\]=\s]*)(.+)?/
q, a = $1, $2
if a
o = notwice(NilClass, klass, 'type')
@@ -1542,7 +1565,7 @@ XXX
ldesc << "--#{q}"
(o = q.downcase).tr!('_', '-')
long << o
- when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
+ when /\A-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
q, a = $1, $2
o = notwice(Object, klass, 'type')
if a
@@ -1553,7 +1576,7 @@ XXX
end
sdesc << "-#{q}"
short << Regexp.new(q)
- when /^-(.)(.+)?/
+ when /\A-(.)(.+)?/
q, a = $1, $2
if a
o = notwice(NilClass, klass, 'type')
@@ -1562,7 +1585,7 @@ XXX
end
sdesc << "-#{q}"
short << q
- when /^=/
+ when /\A=/
style = notwice(default_style.guess(arg = o), style, 'style')
default_pattern, conv = search(:atype, Object) unless default_pattern
else
@@ -1571,12 +1594,18 @@ XXX
end
default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
+ if Range === values and klass
+ unless (!values.begin or klass === values.begin) and
+ (!values.end or klass === values.end)
+ raise ArgumentError, "range does not match class"
+ end
+ end
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)
+ conv, sdesc, ldesc, arg, desc, block, values)
elsif !block
if style or pattern
raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
@@ -1585,7 +1614,7 @@ XXX
else
short << pattern
s = (style || default_style).new(pattern,
- conv, nil, nil, arg, desc, block)
+ conv, nil, nil, arg, desc, block, values)
end
return s, short, long,
(not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
@@ -1827,7 +1856,7 @@ XXX
#
def permute!(argv = default_argv, **keywords)
nonopts = []
- order!(argv, **keywords, &nonopts.method(:<<))
+ order!(argv, **keywords) {|nonopt| nonopts << nonopt}
argv[0, 0] = nonopts
argv
end
@@ -1880,13 +1909,16 @@ XXX
single_options, *long_options = *args
result = {}
+ setter = (symbolize_names ?
+ ->(name, val) {result[name.to_sym] = val}
+ : ->(name, val) {result[name] = val})
single_options.scan(/(.)(:)?/) do |opt, val|
if val
- result[opt] = nil
+ setter[opt, nil]
define("-#{opt} VAL")
else
- result[opt] = false
+ setter[opt, false]
define("-#{opt}")
end
end if single_options
@@ -1895,16 +1927,16 @@ XXX
arg, desc = arg.split(';', 2)
opt, val = arg.split(':', 2)
if val
- result[opt] = val.empty? ? nil : val
+ setter[opt, (val unless val.empty?)]
define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
else
- result[opt] = false
+ setter[opt, false]
define("--#{opt}", *[desc].compact)
end
end
- parse_in_order(argv, result.method(:[]=), **keywords)
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ parse_in_order(argv, setter, **keywords)
+ result
end
#
@@ -1954,7 +1986,7 @@ XXX
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])
+ raise exc.new(opt, additional: proc {|o| additional_message(typ, o)})
end
private :complete
@@ -2019,19 +2051,27 @@ XXX
def load(filename = nil, **keywords)
unless filename
basename = File.basename($0, '.*')
- return true if load(File.expand_path(basename, '~/.options'), **keywords) rescue nil
+ return true if load(File.expand_path("~/.options/#{basename}"), **keywords) rescue nil
basename << ".options"
+ if !(xdg = ENV['XDG_CONFIG_HOME']) or xdg.empty?
+ # https://specifications.freedesktop.org/basedir-spec/latest/#variables
+ #
+ # If $XDG_CONFIG_HOME is either not set or empty, a default
+ # equal to $HOME/.config should be used.
+ xdg = ['~/.config', true]
+ end
return [
- # XDG
- ENV['XDG_CONFIG_HOME'],
- '~/.config',
+ xdg,
+
*ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
# Haiku
- '~/config/settings',
- ].any? {|dir|
+ ['~/config/settings', true],
+ ].any? {|dir, expand|
next if !dir or dir.empty?
- load(File.expand_path(basename, dir), **keywords) rescue nil
+ filename = File.join(dir, basename)
+ filename = File.expand_path(filename) if expand
+ load(filename, **keywords) rescue nil
}
end
begin
@@ -2237,9 +2277,10 @@ XXX
argv
end
+ DIR = File.join(__dir__, '')
def self.filter_backtrace(array)
unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ array.delete_if {|bt| bt.start_with?(DIR)}
end
array
end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb
new file mode 100644
index 0000000000..818e947477
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb
@@ -0,0 +1,53 @@
+require_relative "pub_grub/package"
+require_relative "pub_grub/static_package_source"
+require_relative "pub_grub/term"
+require_relative "pub_grub/version_range"
+require_relative "pub_grub/version_constraint"
+require_relative "pub_grub/version_union"
+require_relative "pub_grub/version_solver"
+require_relative "pub_grub/incompatibility"
+require_relative 'pub_grub/solve_failure'
+require_relative 'pub_grub/failure_writer'
+require_relative 'pub_grub/version'
+
+module Gem::PubGrub
+ # Minimal logger that doesn't require the 'logger' gem
+ class NullLogger
+ def info(&block); end
+ def debug(&block); end
+ def warn(&block); end
+ def error(&block); end
+ end
+
+ class StderrLogger
+ def info(&block)
+ $stderr.puts "INFO: #{block.call}" if block
+ end
+
+ def debug(&block)
+ $stderr.puts "DEBUG: #{block.call}" if block
+ end
+
+ def warn(&block)
+ $stderr.puts "WARN: #{block.call}" if block
+ end
+
+ def error(&block)
+ $stderr.puts "ERROR: #{block.call}" if block
+ end
+ end
+
+ class << self
+ attr_writer :logger
+
+ def logger
+ @logger || default_logger
+ end
+
+ private
+
+ def default_logger
+ @logger = $DEBUG ? StderrLogger.new : NullLogger.new
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb
new file mode 100644
index 0000000000..7a11cf0933
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/assignment.rb
@@ -0,0 +1,20 @@
+module Gem::PubGrub
+ class Assignment
+ attr_reader :term, :cause, :decision_level, :index
+ def initialize(term, cause, decision_level, index)
+ @term = term
+ @cause = cause
+ @decision_level = decision_level
+ @index = index
+ end
+
+ def self.decision(package, version, decision_level, index)
+ term = Term.new(VersionConstraint.exact(package, version), true)
+ new(term, :decision, decision_level, index)
+ end
+
+ def decision?
+ cause == :decision
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb
new file mode 100644
index 0000000000..c8dbf2a5ab
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/basic_package_source.rb
@@ -0,0 +1,169 @@
+require_relative 'version_constraint'
+require_relative 'incompatibility'
+
+module Gem::PubGrub
+ # Types:
+ #
+ # Where possible, Gem::PubGrub will accept user-defined types, so long as they quack.
+ #
+ # ## "Package":
+ #
+ # This class will be used to represent the various packages being solved for.
+ # .to_s will be called when displaying errors and debugging info, it should
+ # probably return the package's name.
+ # It must also have a reasonable definition of #== and #hash
+ #
+ # Example classes: String ("rails")
+ #
+ #
+ # ## "Version":
+ #
+ # This class will be used to represent a single version number.
+ #
+ # Versions don't need to store their associated package, however they will
+ # only be compared against other versions of the same package.
+ #
+ # It must be Comparible (and implement <=> reasonably)
+ #
+ # Example classes: Gem::Version, Integer
+ #
+ #
+ # ## "Dependency"
+ #
+ # This class represents the requirement one package has on another. It is
+ # returned by dependencies_for(package, version) and will be passed to
+ # parse_dependency to convert it to a format Gem::PubGrub understands.
+ #
+ # It must also have a reasonable definition of #==
+ #
+ # Example classes: String ("~> 1.0"), Gem::Requirement
+ #
+ class BasicPackageSource
+ # Override me!
+ #
+ # This is called per package to find all possible versions of a package.
+ #
+ # It is called at most once per-package
+ #
+ # Returns: Array of versions for a package, in preferred order of selection
+ def all_versions_for(package)
+ raise NotImplementedError
+ end
+
+ # Override me!
+ #
+ # Returns: Hash in the form of { package => requirement, ... }
+ def dependencies_for(package, version)
+ raise NotImplementedError
+ end
+
+ # Override me!
+ #
+ # Convert a (user-defined) dependency into a format Gem::PubGrub understands.
+ #
+ # Package is passed to this method but for many implementations is not
+ # needed.
+ #
+ # Returns: either a Gem::PubGrub::VersionRange, Gem::PubGrub::VersionUnion, or a
+ # Gem::PubGrub::VersionConstraint
+ def parse_dependency(package, dependency)
+ raise NotImplementedError
+ end
+
+ # Override me!
+ #
+ # If not overridden, this will call dependencies_for with the root package.
+ #
+ # Returns: Hash in the form of { package => requirement, ... } (see dependencies_for)
+ def root_dependencies
+ dependencies_for(@root_package, @root_version)
+ end
+
+ def initialize
+ @root_package = Package.root
+ @root_version = Package.root_version
+
+ @sorted_versions = Hash.new do |h,k|
+ if k == @root_package
+ h[k] = [@root_version]
+ else
+ h[k] = all_versions_for(k).sort
+ end
+ end
+
+ @cached_dependencies = Hash.new do |packages, package|
+ if package == @root_package
+ packages[package] = {
+ @root_version => root_dependencies
+ }
+ else
+ packages[package] = Hash.new do |versions, version|
+ versions[version] = dependencies_for(package, version)
+ end
+ end
+ end
+ end
+
+ def versions_for(package, range=VersionRange.any)
+ range.select_versions(@sorted_versions[package])
+ end
+
+ def no_versions_incompatibility_for(_package, unsatisfied_term)
+ cause = Incompatibility::NoVersions.new(unsatisfied_term)
+
+ Incompatibility.new([unsatisfied_term], cause: cause)
+ end
+
+ def incompatibilities_for(package, version)
+ package_deps = @cached_dependencies[package]
+ sorted_versions = @sorted_versions[package]
+ package_deps[version].map do |dep_package, dep_constraint_name|
+ low = high = sorted_versions.index(version)
+
+ # find version low such that all >= low share the same dep
+ while low > 0 &&
+ package_deps[sorted_versions[low - 1]][dep_package] == dep_constraint_name
+ low -= 1
+ end
+ low =
+ if low == 0
+ nil
+ else
+ sorted_versions[low]
+ end
+
+ # find version high such that all < high share the same dep
+ while high < sorted_versions.length &&
+ package_deps[sorted_versions[high]][dep_package] == dep_constraint_name
+ high += 1
+ end
+ high =
+ if high == sorted_versions.length
+ nil
+ else
+ sorted_versions[high]
+ end
+
+ range = VersionRange.new(min: low, max: high, include_min: !low.nil?)
+
+ self_constraint = VersionConstraint.new(package, range: range)
+
+ if !@packages.include?(dep_package)
+ # no such package -> this version is invalid
+ end
+
+ dep_constraint = parse_dependency(dep_package, dep_constraint_name)
+ if !dep_constraint
+ # falsey indicates this dependency was invalid
+ cause = Gem::PubGrub::Incompatibility::InvalidDependency.new(dep_package, dep_constraint_name)
+ return [Incompatibility.new([Term.new(self_constraint, true)], cause: cause)]
+ elsif !dep_constraint.is_a?(VersionConstraint)
+ # Upgrade range/union to VersionConstraint
+ dep_constraint = VersionConstraint.new(dep_package, range: dep_constraint)
+ end
+
+ Incompatibility.new([Term.new(self_constraint, true), Term.new(dep_constraint, false)], cause: :dependency)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb
new file mode 100644
index 0000000000..d8bfde0286
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/failure_writer.rb
@@ -0,0 +1,182 @@
+module Gem::PubGrub
+ class FailureWriter
+ def initialize(root)
+ @root = root
+
+ # { Incompatibility => Integer }
+ @derivations = {}
+
+ # [ [ String, Integer or nil ] ]
+ @lines = []
+
+ # { Incompatibility => Integer }
+ @line_numbers = {}
+
+ count_derivations(root)
+ end
+
+ def write
+ return @root.to_s unless @root.conflict?
+
+ visit(@root)
+
+ padding = @line_numbers.empty? ? 0 : "(#{@line_numbers.values.last}) ".length
+
+ @lines.map do |message, number|
+ next "" if message.empty?
+
+ lead = number ? "(#{number}) " : ""
+ lead = lead.ljust(padding)
+ message = message.gsub("\n", "\n" + " " * (padding + 2))
+ "#{lead}#{message}"
+ end.join("\n")
+ end
+
+ private
+
+ def write_line(incompatibility, message, numbered:)
+ if numbered
+ number = @line_numbers.length + 1
+ @line_numbers[incompatibility] = number
+ end
+
+ @lines << [message, number]
+ end
+
+ def visit(incompatibility, conclusion: false)
+ raise unless incompatibility.conflict?
+
+ numbered = conclusion || @derivations[incompatibility] > 1;
+ conjunction = conclusion || incompatibility == @root ? "So," : "And"
+
+ cause = incompatibility.cause
+
+ if cause.conflict.conflict? && cause.other.conflict?
+ conflict_line = @line_numbers[cause.conflict]
+ other_line = @line_numbers[cause.other]
+
+ if conflict_line && other_line
+ write_line(
+ incompatibility,
+ "Because #{cause.conflict} (#{conflict_line})\nand #{cause.other} (#{other_line}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ elsif conflict_line || other_line
+ with_line = conflict_line ? cause.conflict : cause.other
+ without_line = conflict_line ? cause.other : cause.conflict
+ line = @line_numbers[with_line]
+
+ visit(without_line);
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{with_line} (#{line}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ else
+ single_line_conflict = single_line?(cause.conflict.cause)
+ single_line_other = single_line?(cause.other.cause)
+
+ if single_line_conflict || single_line_other
+ first = single_line_other ? cause.conflict : cause.other
+ second = single_line_other ? cause.other : cause.conflict
+ visit(first)
+ visit(second)
+ write_line(
+ incompatibility,
+ "Thus, #{incompatibility}.",
+ numbered: numbered
+ )
+ else
+ visit(cause.conflict, conclusion: true)
+ @lines << ["", nil]
+ visit(cause.other)
+
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{cause.conflict} (#{@line_numbers[cause.conflict]}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ end
+ end
+ elsif cause.conflict.conflict? || cause.other.conflict?
+ derived = cause.conflict.conflict? ? cause.conflict : cause.other
+ ext = cause.conflict.conflict? ? cause.other : cause.conflict
+
+ derived_line = @line_numbers[derived]
+ if derived_line
+ write_line(
+ incompatibility,
+ "Because #{ext}\nand #{derived} (#{derived_line}),\n#{incompatibility}.",
+ numbered: numbered
+ )
+ elsif collapsible?(derived)
+ derived_cause = derived.cause
+ if derived_cause.conflict.conflict?
+ collapsed_derived = derived_cause.conflict
+ collapsed_ext = derived_cause.other
+ else
+ collapsed_derived = derived_cause.other
+ collapsed_ext = derived_cause.conflict
+ end
+
+ visit(collapsed_derived)
+
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{collapsed_ext}\nand #{ext},\n#{incompatibility}.",
+ numbered: numbered
+ )
+ else
+ visit(derived)
+ write_line(
+ incompatibility,
+ "#{conjunction} because #{ext},\n#{incompatibility}.",
+ numbered: numbered
+ )
+ end
+ else
+ write_line(
+ incompatibility,
+ "Because #{cause.conflict}\nand #{cause.other},\n#{incompatibility}.",
+ numbered: numbered
+ )
+ end
+ end
+
+ def single_line?(cause)
+ !cause.conflict.conflict? && !cause.other.conflict?
+ end
+
+ def collapsible?(incompatibility)
+ return false if @derivations[incompatibility] > 1
+
+ cause = incompatibility.cause
+ # If incompatibility is derived from two derived incompatibilities,
+ # there are too many transitive causes to display concisely.
+ return false if cause.conflict.conflict? && cause.other.conflict?
+
+ # If incompatibility is derived from two external incompatibilities, it
+ # tends to be confusing to collapse it.
+ return false unless cause.conflict.conflict? || cause.other.conflict?
+
+ # If incompatibility's internal cause is numbered, collapsing it would
+ # get too noisy.
+ complex = cause.conflict.conflict? ? cause.conflict : cause.other
+
+ !@line_numbers.has_key?(complex)
+ end
+
+ def count_derivations(incompatibility)
+ if @derivations.has_key?(incompatibility)
+ @derivations[incompatibility] += 1
+ else
+ @derivations[incompatibility] = 1
+ if incompatibility.conflict?
+ cause = incompatibility.cause
+ count_derivations(cause.conflict)
+ count_derivations(cause.other)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb
new file mode 100644
index 0000000000..b5652b5e01
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/incompatibility.rb
@@ -0,0 +1,150 @@
+module Gem::PubGrub
+ class Incompatibility
+ ConflictCause = Struct.new(:incompatibility, :satisfier) do
+ alias_method :conflict, :incompatibility
+ alias_method :other, :satisfier
+ end
+
+ InvalidDependency = Struct.new(:package, :constraint) do
+ end
+
+ NoVersions = Struct.new(:constraint) do
+ end
+
+ attr_reader :terms, :cause
+
+ def initialize(terms, cause:, custom_explanation: nil)
+ @cause = cause
+ @terms = cleanup_terms(terms)
+ @custom_explanation = custom_explanation
+
+ if cause == :dependency && @terms.length != 2
+ raise ArgumentError, "a dependency Incompatibility must have exactly two terms. Got #{@terms.inspect}"
+ end
+ end
+
+ def hash
+ cause.hash ^ terms.hash
+ end
+
+ def eql?(other)
+ cause.eql?(other.cause) &&
+ terms.eql?(other.terms)
+ end
+
+ def failure?
+ terms.empty? || (terms.length == 1 && Package.root?(terms[0].package) && terms[0].positive?)
+ end
+
+ def conflict?
+ ConflictCause === cause
+ end
+
+ # Returns all external incompatibilities in this incompatibility's
+ # derivation graph
+ def external_incompatibilities
+ if conflict?
+ [
+ cause.conflict,
+ cause.other
+ ].flat_map(&:external_incompatibilities)
+ else
+ [this]
+ end
+ end
+
+ def to_s
+ return @custom_explanation if @custom_explanation
+
+ case cause
+ when :root
+ "(root dependency)"
+ when :dependency
+ "#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
+ when Gem::PubGrub::Incompatibility::InvalidDependency
+ "#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
+ when Gem::PubGrub::Incompatibility::NoVersions
+ "no versions satisfy #{cause.constraint}"
+ when Gem::PubGrub::Incompatibility::ConflictCause
+ if failure?
+ "version solving has failed"
+ 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
+ else
+ "#{term.invert} is required"
+ end
+ else
+ if terms.all?(&:positive?)
+ if terms.length == 2
+ "#{terms[0].to_s(allow_every: true)} is incompatible with #{terms[1]}"
+ else
+ "one of #{terms.map(&:to_s).join(" or ")} must be false"
+ end
+ elsif terms.all?(&:negative?)
+ if terms.length == 2
+ "either #{terms[0].invert} or #{terms[1].invert}"
+ else
+ "one of #{terms.map(&:invert).join(" or ")} must be true";
+ end
+ else
+ positive = terms.select(&:positive?)
+ negative = terms.select(&:negative?).map(&:invert)
+
+ if positive.length == 1
+ "#{positive[0].to_s(allow_every: true)} requires #{negative.join(" or ")}"
+ else
+ "if #{positive.join(" and ")} then #{negative.join(" or ")}"
+ end
+ end
+ end
+ else
+ raise "unhandled cause: #{cause.inspect}"
+ end
+ end
+
+ def inspect
+ "#<#{self.class} #{to_s}>"
+ end
+
+ def pretty_print(q)
+ q.group 2, "#<#{self.class}", ">" do
+ q.breakable
+ q.text to_s
+
+ q.breakable
+ q.text " caused by "
+ q.pp @cause
+ end
+ end
+
+ private
+
+ def cleanup_terms(terms)
+ terms.each do |term|
+ raise "#{term.inspect} must be a term" unless term.is_a?(Term)
+ end
+
+ if terms.length != 1 && ConflictCause === cause
+ terms = terms.reject do |term|
+ term.positive? && Package.root?(term.package)
+ end
+ end
+
+ # Optimized simple cases
+ return terms if terms.length <= 1
+ return terms if terms.length == 2 && terms[0].package != terms[1].package
+
+ terms.group_by(&:package).map do |package, common_terms|
+ common_terms.inject do |acc, term|
+ acc.intersect(term)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb
new file mode 100644
index 0000000000..6baa908f60
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/package.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gem::PubGrub
+ class Package
+
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def inspect
+ "#<#{self.class} #{name.inspect}>"
+ end
+
+ def <=>(other)
+ name <=> other.name
+ end
+
+ ROOT = Package.new(:root)
+ ROOT_VERSION = 0
+
+ def self.root
+ ROOT
+ end
+
+ def self.root_version
+ ROOT_VERSION
+ end
+
+ def self.root?(package)
+ if package.respond_to?(:root?)
+ package.root?
+ else
+ package == root
+ end
+ end
+
+ def to_s
+ name.to_s
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb
new file mode 100644
index 0000000000..f6a6ae6964
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/partial_solution.rb
@@ -0,0 +1,121 @@
+require_relative 'assignment'
+
+module Gem::PubGrub
+ class PartialSolution
+ attr_reader :assignments, :decisions
+ attr_reader :attempted_solutions
+
+ def initialize
+ reset!
+
+ @attempted_solutions = 1
+ @backtracking = false
+ end
+
+ def decision_level
+ @decisions.length
+ end
+
+ def relation(term)
+ package = term.package
+ return :overlap if !@terms.key?(package)
+
+ @relation_cache[package][term] ||=
+ @terms[package].relation(term)
+ end
+
+ def satisfies?(term)
+ relation(term) == :subset
+ end
+
+ def derive(term, cause)
+ add_assignment(Assignment.new(term, cause, decision_level, assignments.length))
+ end
+
+ def satisfier(term)
+ assignment =
+ @assignments_by[term.package].bsearch do |assignment_by|
+ @cumulative_assignments[assignment_by].satisfies?(term)
+ end
+
+ assignment || raise("#{term} unsatisfied")
+ end
+
+ # A list of unsatisfied terms
+ def unsatisfied
+ @required.keys.reject do |package|
+ @decisions.key?(package)
+ end.map do |package|
+ @terms[package]
+ end
+ end
+
+ def decide(package, version)
+ @attempted_solutions += 1 if @backtracking
+ @backtracking = false;
+
+ decisions[package] = version
+ assignment = Assignment.decision(package, version, decision_level, assignments.length)
+ add_assignment(assignment)
+ end
+
+ def backtrack(previous_level)
+ @backtracking = true
+
+ new_assignments = assignments.select do |assignment|
+ assignment.decision_level <= previous_level
+ end
+
+ new_decisions = Hash[decisions.first(previous_level)]
+
+ reset!
+
+ @decisions = new_decisions
+
+ new_assignments.each do |assignment|
+ add_assignment(assignment)
+ end
+ end
+
+ private
+
+ def reset!
+ # { Array<Assignment> }
+ @assignments = []
+
+ # { Package => Array<Assignment> }
+ @assignments_by = Hash.new { |h,k| h[k] = [] }
+ @cumulative_assignments = {}.compare_by_identity
+
+ # { Package => Package::Version }
+ @decisions = {}
+
+ # { Package => Term }
+ @terms = {}
+ @relation_cache = Hash.new { |h,k| h[k] = {} }
+
+ # { Package => Boolean }
+ @required = {}
+ end
+
+ def add_assignment(assignment)
+ term = assignment.term
+ package = term.package
+
+ @assignments << assignment
+ @assignments_by[package] << assignment
+
+ @required[package] = true if term.positive?
+
+ if @terms.key?(package)
+ old_term = @terms[package]
+ @terms[package] = old_term.intersect(term)
+ else
+ @terms[package] = term
+ end
+ @relation_cache[package].clear
+
+ @cumulative_assignments[assignment] = @terms[package]
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb
new file mode 100644
index 0000000000..60ca3ca2ea
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/rubygems.rb
@@ -0,0 +1,45 @@
+module Gem::PubGrub
+ module RubyGems
+ extend self
+
+ def requirement_to_range(requirement)
+ ranges = requirement.requirements.map do |(op, ver)|
+ case op
+ when "~>"
+ name = "~> #{ver}"
+ bump = ver.class.new(ver.bump.to_s + ".A")
+ VersionRange.new(name: name, min: ver, max: bump, include_min: true)
+ when ">"
+ VersionRange.new(min: ver)
+ when ">="
+ VersionRange.new(min: ver, include_min: true)
+ when "<"
+ VersionRange.new(max: ver)
+ when "<="
+ VersionRange.new(max: ver, include_max: true)
+ when "="
+ VersionRange.new(min: ver, max: ver, include_min: true, include_max: true)
+ when "!="
+ VersionRange.new(min: ver, max: ver, include_min: true, include_max: true).invert
+ else
+ raise "bad version specifier: #{op}"
+ end
+ end
+
+ ranges.inject(&:intersect)
+ end
+
+ def requirement_to_constraint(package, requirement)
+ Gem::PubGrub::VersionConstraint.new(package, range: requirement_to_range(requirement))
+ end
+
+ def parse_range(dep)
+ requirement_to_range(Gem::Requirement.new(dep))
+ end
+
+ def parse_constraint(package, dep)
+ range = parse_range(dep)
+ Gem::PubGrub::VersionConstraint.new(package, range: range)
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb
new file mode 100644
index 0000000000..c4181d2b25
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/solve_failure.rb
@@ -0,0 +1,19 @@
+require_relative 'failure_writer'
+
+module Gem::PubGrub
+ class SolveFailure < StandardError
+ attr_reader :incompatibility
+
+ def initialize(incompatibility)
+ @incompatibility = incompatibility
+ end
+
+ def to_s
+ "Could not find compatible versions\n\n#{explanation}"
+ end
+
+ def explanation
+ @explanation ||= FailureWriter.new(@incompatibility).write
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb
new file mode 100644
index 0000000000..9e1de7d7a1
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/static_package_source.rb
@@ -0,0 +1,61 @@
+require_relative 'package'
+require_relative 'rubygems'
+require_relative 'version_constraint'
+require_relative 'incompatibility'
+require_relative 'basic_package_source'
+
+module Gem::PubGrub
+ class StaticPackageSource < BasicPackageSource
+ class DSL
+ def initialize(packages, root_deps)
+ @packages = packages
+ @root_deps = root_deps
+ end
+
+ def root(deps:)
+ @root_deps.update(deps)
+ end
+
+ def add(name, version, deps: {})
+ 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 && Gem::PubGrub::RubyGems.parse_range(req).include?(version) }
+ end
+ end
+
+ def initialize
+ @root_deps = {}
+ @packages = {}
+
+ yield DSL.new(@packages, @root_deps)
+
+ super()
+ end
+
+ def all_versions_for(package)
+ @packages[package].keys
+ end
+
+ def root_dependencies
+ @root_deps
+ end
+
+ def dependencies_for(package, version)
+ @packages[package][version]
+ end
+
+ def parse_dependency(package, dependency)
+ return false unless @packages.key?(package)
+
+ Gem::PubGrub::RubyGems.parse_constraint(package, dependency)
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb
new file mode 100644
index 0000000000..b9874cdece
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/strategy.rb
@@ -0,0 +1,42 @@
+module Gem::PubGrub
+ class Strategy
+ def initialize(source)
+ @source = source
+
+ @root_package = Package.root
+ @root_version = Package.root_version
+
+ @version_indexes = Hash.new do |h,k|
+ if k == @root_package
+ h[k] = { @root_version => 0 }
+ else
+ h[k] = @source.all_versions_for(k).each.with_index.to_h
+ end
+ end
+ end
+
+ def next_package_and_version(unsatisfied)
+ package, range = next_term_to_try_from(unsatisfied)
+
+ [package, most_preferred_version_of(package, range)]
+ end
+
+ private
+
+ def most_preferred_version_of(package, range)
+ versions = @source.versions_for(package, range)
+
+ indexes = @version_indexes[package]
+ versions.min_by { |version| indexes[version] || Float::INFINITY }
+ end
+
+ def next_term_to_try_from(unsatisfied)
+ unsatisfied.min_by do |package, range|
+ matching_versions = @source.versions_for(package, range)
+ higher_versions = @source.versions_for(package, range.upper_invert)
+
+ [matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb
new file mode 100644
index 0000000000..bb26bdc911
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/term.rb
@@ -0,0 +1,105 @@
+module Gem::PubGrub
+ class Term
+ attr_reader :package, :constraint, :positive
+
+ def initialize(constraint, positive)
+ @constraint = constraint
+ @package = @constraint.package
+ @positive = positive
+ end
+
+ def to_s(allow_every: false)
+ if positive
+ @constraint.to_s(allow_every: allow_every)
+ else
+ "not #{@constraint}"
+ end
+ end
+
+ def hash
+ constraint.hash ^ positive.hash
+ end
+
+ def eql?(other)
+ positive == other.positive &&
+ constraint.eql?(other.constraint)
+ end
+
+ def invert
+ self.class.new(@constraint, !@positive)
+ end
+ alias_method :inverse, :invert
+
+ def intersect(other)
+ raise ArgumentError, "packages must match" if package != other.package
+
+ if positive? && other.positive?
+ self.class.new(constraint.intersect(other.constraint), true)
+ elsif negative? && other.negative?
+ self.class.new(constraint.union(other.constraint), false)
+ else
+ positive = positive? ? self : other
+ negative = negative? ? self : other
+ self.class.new(positive.constraint.intersect(negative.constraint.invert), true)
+ end
+ end
+
+ def difference(other)
+ intersect(other.invert)
+ end
+
+ def relation(other)
+ if positive? && other.positive?
+ constraint.relation(other.constraint)
+ elsif negative? && other.positive?
+ if constraint.allows_all?(other.constraint)
+ :disjoint
+ else
+ :overlap
+ end
+ elsif positive? && other.negative?
+ if !other.constraint.allows_any?(constraint)
+ :subset
+ elsif other.constraint.allows_all?(constraint)
+ :disjoint
+ else
+ :overlap
+ end
+ elsif negative? && other.negative?
+ if constraint.allows_all?(other.constraint)
+ :subset
+ else
+ :overlap
+ end
+ else
+ raise
+ end
+ end
+
+ def normalized_constraint
+ @normalized_constraint ||= positive ? constraint : constraint.invert
+ end
+
+ def satisfies?(other)
+ raise ArgumentError, "packages must match" unless package == other.package
+
+ relation(other) == :subset
+ end
+
+ def positive?
+ @positive
+ end
+
+ def negative?
+ !positive?
+ end
+
+ def empty?
+ @empty ||= normalized_constraint.empty?
+ end
+
+ def inspect
+ "#<#{self.class} #{self}>"
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb
new file mode 100644
index 0000000000..5701bf0656
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version.rb
@@ -0,0 +1,3 @@
+module Gem::PubGrub
+ VERSION = "0.5.0"
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb
new file mode 100644
index 0000000000..ee998b3271
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_constraint.rb
@@ -0,0 +1,129 @@
+require_relative 'version_range'
+
+module Gem::PubGrub
+ class VersionConstraint
+ attr_reader :package, :range
+
+ # @param package [Gem::PubGrub::Package]
+ # @param range [Gem::PubGrub::VersionRange]
+ def initialize(package, range: nil)
+ @package = package
+ @range = range
+ end
+
+ def hash
+ 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
+
+ class << self
+ def exact(package, version)
+ range = VersionRange.new(min: version, max: version, include_min: true, include_max: true)
+ new(package, range: range)
+ end
+
+ def any(package)
+ new(package, range: VersionRange.any)
+ end
+
+ def empty(package)
+ new(package, range: VersionRange.empty)
+ end
+ end
+
+ def intersect(other)
+ unless package == other.package
+ raise ArgumentError, "Can only intersect between VersionConstraint of the same package"
+ end
+
+ self.class.new(package, range: range.intersect(other.range))
+ end
+
+ def union(other)
+ unless package == other.package
+ raise ArgumentError, "Can only intersect between VersionConstraint of the same package"
+ end
+
+ self.class.new(package, range: range.union(other.range))
+ end
+
+ def invert
+ new_range = range.invert
+ self.class.new(package, range: new_range)
+ end
+
+ def difference(other)
+ intersect(other.invert)
+ end
+
+ def allows_all?(other)
+ range.allows_all?(other.range)
+ end
+
+ def allows_any?(other)
+ range.intersects?(other.range)
+ end
+
+ def subset?(other)
+ other.allows_all?(self)
+ end
+
+ def overlap?(other)
+ other.allows_any?(self)
+ end
+
+ def disjoint?(other)
+ !overlap?(other)
+ end
+
+ def relation(other)
+ if subset?(other)
+ :subset
+ elsif overlap?(other)
+ :overlap
+ else
+ :disjoint
+ end
+ end
+
+ def to_s(allow_every: false)
+ if Package.root?(package)
+ package.to_s
+ elsif allow_every && any?
+ "every version of #{package}"
+ else
+ "#{package} #{constraint_string}"
+ end
+ end
+
+ def constraint_string
+ if any?
+ ">= 0"
+ else
+ range.to_s
+ end
+ end
+
+ def empty?
+ range.empty?
+ end
+
+ # Does this match every version of the package
+ def any?
+ range.any?
+ end
+
+ def inspect
+ "#<#{self.class} #{self}>"
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb
new file mode 100644
index 0000000000..fa0e2d5742
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_range.rb
@@ -0,0 +1,423 @@
+# frozen_string_literal: true
+
+module Gem::PubGrub
+ class VersionRange
+ attr_reader :min, :max, :include_min, :include_max
+
+ alias_method :include_min?, :include_min
+ alias_method :include_max?, :include_max
+
+ class Empty < VersionRange
+ undef_method :min, :max
+ undef_method :include_min, :include_min?
+ undef_method :include_max, :include_max?
+
+ def initialize
+ end
+
+ def empty?
+ true
+ end
+
+ def eql?(other)
+ other.empty?
+ end
+
+ def hash
+ [].hash
+ end
+
+ def intersects?(_)
+ false
+ end
+
+ def intersect(other)
+ self
+ end
+
+ def allows_all?(other)
+ other.empty?
+ end
+
+ def include?(_)
+ false
+ end
+
+ def any?
+ false
+ end
+
+ def to_s
+ "(no versions)"
+ end
+
+ def ==(other)
+ other.class == self.class
+ end
+
+ def invert
+ VersionRange.any
+ end
+
+ def select_versions(_)
+ []
+ end
+ end
+
+ EMPTY = Empty.new
+ Empty.singleton_class.undef_method(:new)
+
+ def self.empty
+ EMPTY
+ end
+
+ def self.any
+ new
+ end
+
+ def initialize(min: nil, max: nil, include_min: false, include_max: false, name: nil)
+ raise ArgumentError, "Ranges without a lower bound cannot have include_min == true" if !min && include_min == true
+ raise ArgumentError, "Ranges without an upper bound cannot have include_max == true" if !max && include_max == true
+
+ @min = min
+ @max = max
+ @include_min = include_min
+ @include_max = include_max
+ @name = name
+ end
+
+ def hash
+ @hash ||= min.hash ^ max.hash ^ include_min.hash ^ include_max.hash
+ end
+
+ def eql?(other)
+ if other.is_a?(VersionRange)
+ !other.empty? &&
+ min.eql?(other.min) &&
+ max.eql?(other.max) &&
+ include_min.eql?(other.include_min) &&
+ include_max.eql?(other.include_max)
+ else
+ ranges.eql?(other.ranges)
+ end
+ end
+
+ def ranges
+ [self]
+ end
+
+ def include?(version)
+ compare_version(version) == 0
+ end
+
+ # Partitions passed versions into [lower, within, higher]
+ #
+ # versions must be sorted
+ def partition_versions(versions)
+ min_index =
+ if !min || versions.empty?
+ 0
+ elsif include_min?
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] >= min }
+ else
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] > min }
+ end
+
+ lower = versions.slice(0, min_index)
+ versions = versions.slice(min_index, versions.size)
+
+ max_index =
+ if !max || versions.empty?
+ versions.size
+ elsif include_max?
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] > max }
+ else
+ (0..versions.size).bsearch { |i| versions[i].nil? || versions[i] >= max }
+ end
+
+ [
+ lower,
+ versions.slice(0, max_index),
+ versions.slice(max_index, versions.size)
+ ]
+ end
+
+ # Returns versions which are included by this range.
+ #
+ # versions must be sorted
+ def select_versions(versions)
+ return versions if any?
+
+ partition_versions(versions)[1]
+ end
+
+ def compare_version(version)
+ if min
+ case version <=> min
+ when -1
+ return -1
+ when 0
+ return -1 if !include_min
+ when 1
+ end
+ end
+
+ if max
+ case version <=> max
+ when -1
+ when 0
+ return 1 if !include_max
+ when 1
+ return 1
+ end
+ end
+
+ 0
+ end
+
+ def strictly_lower?(other)
+ return false if !max || !other.min
+
+ case max <=> other.min
+ when 0
+ !include_max || !other.include_min
+ when -1
+ true
+ when 1
+ false
+ end
+ end
+
+ def strictly_higher?(other)
+ other.strictly_lower?(self)
+ end
+
+ def intersects?(other)
+ return false if other.empty?
+ return other.intersects?(self) if other.is_a?(VersionUnion)
+ !strictly_lower?(other) && !strictly_higher?(other)
+ end
+ alias_method :allows_any?, :intersects?
+
+ def intersect(other)
+ return other if other.empty?
+ return other.intersect(self) if other.is_a?(VersionUnion)
+
+ min_range =
+ if !min
+ other
+ elsif !other.min
+ self
+ else
+ case min <=> other.min
+ when 0
+ include_min ? other : self
+ when -1
+ other
+ when 1
+ self
+ end
+ end
+
+ max_range =
+ if !max
+ other
+ elsif !other.max
+ self
+ else
+ case max <=> other.max
+ when 0
+ include_max ? other : self
+ when -1
+ self
+ when 1
+ other
+ end
+ end
+
+ if !min_range.equal?(max_range) && min_range.min && max_range.max
+ case min_range.min <=> max_range.max
+ when -1
+ when 0
+ if !min_range.include_min || !max_range.include_max
+ return EMPTY
+ end
+ when 1
+ return EMPTY
+ end
+ end
+
+ VersionRange.new(
+ min: min_range.min,
+ include_min: min_range.include_min,
+ max: max_range.max,
+ include_max: max_range.include_max
+ )
+ end
+
+ # The span covered by two ranges
+ #
+ # If self and other are contiguous, this builds a union of the two ranges.
+ # (if they aren't you are probably calling the wrong method)
+ def span(other)
+ return self if other.empty?
+
+ min_range =
+ if !min
+ self
+ elsif !other.min
+ other
+ else
+ case min <=> other.min
+ when 0
+ include_min ? self : other
+ when -1
+ self
+ when 1
+ other
+ end
+ end
+
+ max_range =
+ if !max
+ self
+ elsif !other.max
+ other
+ else
+ case max <=> other.max
+ when 0
+ include_max ? self : other
+ when -1
+ other
+ when 1
+ self
+ end
+ end
+
+ VersionRange.new(
+ min: min_range.min,
+ include_min: min_range.include_min,
+ max: max_range.max,
+ include_max: max_range.include_max
+ )
+ end
+
+ def union(other)
+ return other.union(self) if other.is_a?(VersionUnion)
+
+ if contiguous_to?(other)
+ span(other)
+ else
+ VersionUnion.union([self, other])
+ end
+ end
+
+ def contiguous_to?(other)
+ return false if other.empty?
+ return true if any?
+
+ intersects?(other) || contiguous_below?(other) || contiguous_above?(other)
+ end
+
+ def contiguous_below?(other)
+ return false if !max || !other.min
+
+ max == other.min && (include_max || other.include_min)
+ end
+
+ def contiguous_above?(other)
+ other.contiguous_below?(self)
+ end
+
+ def allows_all?(other)
+ return true if other.empty?
+
+ if other.is_a?(VersionUnion)
+ return VersionUnion.new([self]).allows_all?(other)
+ end
+
+ return false if max && !other.max
+ return false if min && !other.min
+
+ if min
+ case min <=> other.min
+ when -1
+ when 0
+ return false if !include_min && other.include_min
+ when 1
+ return false
+ end
+ end
+
+ if max
+ case max <=> other.max
+ when -1
+ return false
+ when 0
+ return false if !include_max && other.include_max
+ when 1
+ end
+ end
+
+ true
+ end
+
+ def any?
+ !min && !max
+ end
+
+ def empty?
+ false
+ end
+
+ def to_s
+ @name ||= constraints.join(", ")
+ end
+
+ def inspect
+ "#<#{self.class} #{to_s}>"
+ end
+
+ def upper_invert
+ return self.class.empty unless max
+
+ VersionRange.new(min: max, include_min: !include_max)
+ end
+
+ def invert
+ return self.class.empty if any?
+
+ low = -> { VersionRange.new(max: min, include_max: !include_min) }
+ high = -> { VersionRange.new(min: max, include_min: !include_max) }
+
+ if !min
+ high.call
+ elsif !max
+ low.call
+ else
+ low.call.union(high.call)
+ end
+ end
+
+ def ==(other)
+ self.class == other.class &&
+ min == other.min &&
+ max == other.max &&
+ include_min == other.include_min &&
+ include_max == other.include_max
+ end
+
+ private
+
+ def constraints
+ return ["any"] if any?
+ return ["= #{min}"] if min.to_s == max.to_s
+
+ c = []
+ c << "#{include_min ? ">=" : ">"} #{min}" if min
+ c << "#{include_max ? "<=" : "<"} #{max}" if max
+ c
+ end
+
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb
new file mode 100644
index 0000000000..3341d8fe3b
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_solver.rb
@@ -0,0 +1,236 @@
+require_relative 'partial_solution'
+require_relative 'term'
+require_relative 'incompatibility'
+require_relative 'solve_failure'
+require_relative 'strategy'
+
+module Gem::PubGrub
+ class VersionSolver
+ attr_reader :logger
+ attr_reader :source
+ attr_reader :solution
+ attr_reader :strategy
+
+ def initialize(source:, root: Package.root, strategy: Strategy.new(source), logger: Gem::PubGrub.logger)
+ @logger = logger
+
+ @source = source
+ @strategy = strategy
+
+ # { package => [incompatibility, ...]}
+ @incompatibilities = Hash.new do |h, k|
+ h[k] = []
+ end
+
+ @seen_incompatibilities = {}
+
+ @solution = PartialSolution.new
+
+ add_incompatibility Incompatibility.new([
+ Term.new(VersionConstraint.any(root), false)
+ ], cause: :root)
+
+ propagate(root)
+ end
+
+ def solved?
+ solution.unsatisfied.empty?
+ end
+
+ # Returns true if there is more work to be done, false otherwise
+ def work
+ unsatisfied_terms = solution.unsatisfied
+ if unsatisfied_terms.empty?
+ logger.info { "Solution found after #{solution.attempted_solutions} attempts:" }
+ solution.decisions.each do |package, version|
+ next if Package.root?(package)
+ logger.info { "* #{package} #{version}" }
+ end
+
+ return false
+ end
+
+ next_package = choose_package_version_from(unsatisfied_terms)
+ propagate(next_package)
+
+ true
+ end
+
+ def solve
+ while work; end
+
+ solution.decisions
+ end
+
+ alias_method :result, :solve
+
+ private
+
+ def propagate(initial_package)
+ changed = [initial_package]
+ while package = changed.shift
+ @incompatibilities[package].reverse_each do |incompatibility|
+ result = propagate_incompatibility(incompatibility)
+ if result == :conflict
+ root_cause = resolve_conflict(incompatibility)
+ changed.clear
+ changed << propagate_incompatibility(root_cause)
+ elsif result # should be a Package
+ changed << result
+ end
+ end
+ changed.uniq!
+ end
+ end
+
+ def propagate_incompatibility(incompatibility)
+ unsatisfied = nil
+ incompatibility.terms.each do |term|
+ relation = solution.relation(term)
+ if relation == :disjoint
+ return nil
+ elsif relation == :overlap
+ # If more than one term is inconclusive, we can't deduce anything
+ return nil if unsatisfied
+ unsatisfied = term
+ end
+ end
+
+ if !unsatisfied
+ return :conflict
+ end
+
+ logger.debug { "derived: #{unsatisfied.invert}" }
+
+ solution.derive(unsatisfied.invert, incompatibility)
+
+ unsatisfied.package
+ end
+
+ def choose_package_version_from(unsatisfied_terms)
+ remaining = unsatisfied_terms.map { |t| [t.package, t.constraint.range] }.to_h
+
+ package, version = strategy.next_package_and_version(remaining)
+
+ logger.debug { "attempting #{package} #{version}" }
+
+ if version.nil?
+ unsatisfied_term = unsatisfied_terms.find { |t| t.package == package }
+ add_incompatibility source.no_versions_incompatibility_for(package, unsatisfied_term)
+ return package
+ end
+
+ conflict = false
+
+ source.incompatibilities_for(package, version).each do |incompatibility|
+ if @seen_incompatibilities.include?(incompatibility)
+ logger.debug { "knew: #{incompatibility}" }
+ next
+ end
+ @seen_incompatibilities[incompatibility] = true
+
+ add_incompatibility incompatibility
+
+ conflict ||= incompatibility.terms.all? do |term|
+ term.package == package || solution.satisfies?(term)
+ end
+ end
+
+ unless conflict
+ logger.info { "selected #{package} #{version}" }
+
+ solution.decide(package, version)
+ else
+ logger.info { "conflict: #{conflict.inspect}" }
+ end
+
+ package
+ end
+
+ def resolve_conflict(incompatibility)
+ logger.info { "conflict: #{incompatibility}" }
+
+ new_incompatibility = nil
+
+ while !incompatibility.failure?
+ most_recent_term = nil
+ most_recent_satisfier = nil
+ difference = nil
+
+ previous_level = 1
+
+ incompatibility.terms.each do |term|
+ satisfier = solution.satisfier(term)
+
+ if most_recent_satisfier.nil?
+ most_recent_term = term
+ most_recent_satisfier = satisfier
+ elsif most_recent_satisfier.index < satisfier.index
+ previous_level = [previous_level, most_recent_satisfier.decision_level].max
+ most_recent_term = term
+ most_recent_satisfier = satisfier
+ difference = nil
+ else
+ previous_level = [previous_level, satisfier.decision_level].max
+ end
+
+ if most_recent_term == term
+ difference = most_recent_satisfier.term.difference(most_recent_term)
+ if difference.empty?
+ difference = nil
+ else
+ difference_satisfier = solution.satisfier(difference.inverse)
+ previous_level = [previous_level, difference_satisfier.decision_level].max
+ end
+ end
+ end
+
+ if previous_level < most_recent_satisfier.decision_level ||
+ most_recent_satisfier.decision?
+
+ logger.info { "backtracking to #{previous_level}" }
+ solution.backtrack(previous_level)
+
+ if new_incompatibility
+ add_incompatibility(new_incompatibility)
+ end
+
+ return incompatibility
+ end
+
+ new_terms = []
+ new_terms += incompatibility.terms - [most_recent_term]
+ new_terms += most_recent_satisfier.cause.terms.reject { |term|
+ term.package == most_recent_satisfier.term.package
+ }
+ if difference
+ 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 = new_incompatibility
+
+ partially = difference ? " partially" : ""
+ logger.info { "! #{most_recent_term} is#{partially} satisfied by #{most_recent_satisfier.term}" }
+ logger.info { "! which is caused by #{most_recent_satisfier.cause}" }
+ logger.info { "! thus #{incompatibility}" }
+ end
+
+ raise SolveFailure.new(incompatibility)
+ end
+
+ def add_incompatibility(incompatibility)
+ logger.debug { "fact: #{incompatibility}" }
+ incompatibility.terms.each do |term|
+ package = term.package
+ @incompatibilities[package] << incompatibility
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb
new file mode 100644
index 0000000000..4166318a98
--- /dev/null
+++ b/lib/rubygems/vendor/pub_grub/lib/pub_grub/version_union.rb
@@ -0,0 +1,178 @@
+# frozen_string_literal: true
+
+module Gem::PubGrub
+ class VersionUnion
+ attr_reader :ranges
+
+ def self.normalize_ranges(ranges)
+ ranges = ranges.flat_map do |range|
+ range.ranges
+ end
+
+ ranges.reject!(&:empty?)
+
+ return [] if ranges.empty?
+
+ mins, ranges = ranges.partition { |r| !r.min }
+ original_ranges = mins + ranges.sort_by { |r| [r.min, r.include_min ? 0 : 1] }
+ ranges = [original_ranges.shift]
+ original_ranges.each do |range|
+ if ranges.last.contiguous_to?(range)
+ ranges << ranges.pop.span(range)
+ else
+ ranges << range
+ end
+ end
+
+ ranges
+ end
+
+ def self.union(ranges, normalize: true)
+ ranges = normalize_ranges(ranges) if normalize
+
+ if ranges.size == 0
+ VersionRange.empty
+ elsif ranges.size == 1
+ ranges[0]
+ else
+ new(ranges)
+ end
+ end
+
+ def initialize(ranges)
+ raise ArgumentError unless ranges.all? { |r| r.instance_of?(VersionRange) }
+ @ranges = ranges
+ end
+
+ def hash
+ ranges.hash
+ end
+
+ def eql?(other)
+ ranges.eql?(other.ranges)
+ end
+
+ def include?(version)
+ !!ranges.bsearch {|r| r.compare_version(version) }
+ end
+
+ def select_versions(all_versions)
+ versions = []
+ ranges.inject(all_versions) do |acc, range|
+ _, matching, higher = range.partition_versions(acc)
+ versions.concat matching
+ higher
+ end
+ versions
+ end
+
+ def intersects?(other)
+ my_ranges = ranges.dup
+ other_ranges = other.ranges.dup
+
+ my_range = my_ranges.shift
+ other_range = other_ranges.shift
+ while my_range && other_range
+ if my_range.intersects?(other_range)
+ return true
+ end
+
+ if !my_range.max || other_range.empty? || (other_range.max && other_range.max < my_range.max)
+ other_range = other_ranges.shift
+ else
+ my_range = my_ranges.shift
+ end
+ end
+ end
+ alias_method :allows_any?, :intersects?
+
+ def allows_all?(other)
+ my_ranges = ranges.dup
+
+ my_range = my_ranges.shift
+
+ other.ranges.all? do |other_range|
+ while my_range
+ break if my_range.allows_all?(other_range)
+ my_range = my_ranges.shift
+ end
+
+ !!my_range
+ end
+ end
+
+ def empty?
+ false
+ end
+
+ def any?
+ false
+ end
+
+ def intersect(other)
+ my_ranges = ranges.dup
+ other_ranges = other.ranges.dup
+ new_ranges = []
+
+ my_range = my_ranges.shift
+ other_range = other_ranges.shift
+ while my_range && other_range
+ new_ranges << my_range.intersect(other_range)
+
+ if !my_range.max || other_range.empty? || (other_range.max && other_range.max < my_range.max)
+ other_range = other_ranges.shift
+ else
+ my_range = my_ranges.shift
+ end
+ end
+ new_ranges.reject!(&:empty?)
+ VersionUnion.union(new_ranges, normalize: false)
+ end
+
+ def upper_invert
+ ranges.last.upper_invert
+ end
+
+ def invert
+ ranges.map(&:invert).inject(:intersect)
+ end
+
+ def union(other)
+ VersionUnion.union([self, other])
+ end
+
+ def to_s
+ output = []
+
+ ranges = self.ranges.dup
+ while !ranges.empty?
+ ne = []
+ range = ranges.shift
+ while !ranges.empty? && ranges[0].min.to_s == range.max.to_s
+ ne << range.max
+ range = range.span(ranges.shift)
+ end
+
+ ne.map! {|x| "!= #{x}" }
+ if ne.empty?
+ output << range.to_s
+ elsif range.any?
+ output << ne.join(', ')
+ else
+ output << "#{range}, #{ne.join(', ')}"
+ end
+ end
+
+ output.join(" OR ")
+ end
+
+ def inspect
+ "#<#{self.class} #{to_s}>"
+ end
+
+ def ==(other)
+ self.class == other.class &&
+ self.ranges == other.ranges
+ end
+ end
+end
diff --git a/lib/rubygems/vendor/resolv/lib/resolv.rb b/lib/rubygems/vendor/resolv/lib/resolv.rb
index 4d95e5fc7f..4f48e0642b 100644
--- a/lib/rubygems/vendor/resolv/lib/resolv.rb
+++ b/lib/rubygems/vendor/resolv/lib/resolv.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'socket'
-require_relative '../../timeout/lib/timeout'
+require_relative '../../../vendored_timeout'
require 'io/wait'
require_relative '../../../vendored_securerandom'
+require 'rbconfig'
# 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
@@ -33,7 +34,8 @@ require_relative '../../../vendored_securerandom'
class Gem::Resolv
- VERSION = "0.6.0"
+ # The version string
+ VERSION = "0.7.0"
##
# Looks up the first IP address for +name+.
@@ -177,14 +179,15 @@ class Gem::Resolv
# Gem::Resolv::Hosts is a hostname resolver that uses the system hosts file.
class Hosts
- if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
begin
- require 'win32/resolv'
- DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
+ require 'win32/resolv' unless defined?(Win32::Resolv)
+ hosts = Win32::Resolv.get_hosts_path || IO::NULL
rescue LoadError
end
end
- DefaultFileName ||= '/etc/hosts'
+ # The default file name for host names
+ DefaultFileName = hosts || '/etc/hosts'
##
# Creates a new Gem::Resolv::Hosts, using +filename+ for its data source.
@@ -522,6 +525,8 @@ class Gem::Resolv
}
end
+ # :stopdoc:
+
def fetch_resource(name, typeclass)
lazy_initialize
truncated = {}
@@ -659,8 +664,20 @@ class Gem::Resolv
}
end
- def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
- begin
+ case RUBY_PLATFORM
+ when *[
+ # https://www.rfc-editor.org/rfc/rfc6056.txt
+ # Appendix A. Survey of the Algorithms in Use by Some Popular Implementations
+ /freebsd/, /linux/, /netbsd/, /openbsd/, /solaris/,
+ /darwin/, # the same as FreeBSD
+ ] then
+ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
+ udpsock.bind(bind_host, 0)
+ end
+ else
+ # Sequential port assignment
+ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
+ # Ephemeral port number range recommended by RFC 6056
port = random(1024..65535)
udpsock.bind(bind_host, port)
rescue Errno::EADDRINUSE, # POSIX
@@ -983,13 +1000,13 @@ class Gem::Resolv
next unless keyword
case keyword
when 'nameserver'
- nameserver.concat(args)
+ nameserver.concat(args.each(&:freeze))
when 'domain'
next if args.empty?
- search = [args[0]]
+ search = [args[0].freeze]
when 'search'
next if args.empty?
- search = args
+ search = args.each(&:freeze)
when 'options'
args.each {|arg|
case arg
@@ -1000,22 +1017,21 @@ class Gem::Resolv
end
}
}
- return { :nameserver => nameserver, :search => search, :ndots => ndots }
+ return { :nameserver => nameserver.freeze, :search => search.freeze, :ndots => ndots.freeze }.freeze
end
def Config.default_config_hash(filename="/etc/resolv.conf")
if File.exist? filename
- config_hash = Config.parse_resolv_conf(filename)
+ Config.parse_resolv_conf(filename)
+ elsif defined?(Win32::Resolv)
+ search, nameserver = Win32::Resolv.get_resolv_info
+ config_hash = {}
+ config_hash[:nameserver] = nameserver if nameserver
+ config_hash[:search] = [search].flatten if search
+ config_hash
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
@@ -1664,6 +1680,7 @@ class Gem::Resolv
prev_index = @index
save_index = nil
d = []
+ size = -1
while true
raise DecodeError.new("limit exceeded") if @limit <= @index
case @data.getbyte(@index)
@@ -1684,7 +1701,10 @@ class Gem::Resolv
end
@index = idx
else
- d << self.get_label
+ l = self.get_label
+ d << l
+ size += 1 + l.string.bytesize
+ raise DecodeError.new("name label data exceed 255 octets") if size > 255
end
end
end
@@ -2110,7 +2130,14 @@ class Gem::Resolv
attr_reader :ttl
- ClassHash = {} # :nodoc:
+ ClassHash = Module.new do
+ module_function
+
+ def []=(type_class_value, klass)
+ type_value, class_value = type_class_value
+ Resource.const_set(:"Type#{type_value}_Class#{class_value}", klass)
+ end
+ end
def encode_rdata(msg) # :nodoc:
raise NotImplementedError.new
@@ -2148,7 +2175,9 @@ class Gem::Resolv
end
def self.get_class(type_value, class_value) # :nodoc:
- return ClassHash[[type_value, class_value]] ||
+ cache = :"Type#{type_value}_Class#{class_value}"
+
+ return (const_defined?(cache) && const_get(cache)) ||
Generic.create(type_value, class_value)
end
@@ -2577,7 +2606,7 @@ class Gem::Resolv
end
##
- # Flags for this proprty:
+ # Flags for this property:
# - Bit 0 : 0 = not critical, 1 = critical
attr_reader :flags
@@ -2898,15 +2927,21 @@ class Gem::Resolv
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
+ |[3-9][0-9]?/x # :nodoc:
+
+ ##
+ # Regular expression IPv4 addresses must match.
Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
+ ##
+ # Creates a new IPv4 address from +arg+ which may be:
+ #
+ # IPv4:: returns +arg+.
+ # String:: +arg+ must match the IPv4::Regex constant
+
def self.create(arg)
case arg
when IPv4
@@ -3215,13 +3250,15 @@ class Gem::Resolv
end
- module LOC
+ module LOC # :nodoc:
##
# A Gem::Resolv::LOC::Size
class Size
+ # Regular expression LOC size must match.
+
Regex = /^(\d+\.*\d*)[m]$/
##
@@ -3247,6 +3284,7 @@ class Gem::Resolv
end
end
+ # Internal use; use self.create.
def initialize(scalar)
@scalar = scalar
end
@@ -3284,6 +3322,8 @@ class Gem::Resolv
class Coord
+ # Regular expression LOC Coord must match.
+
Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
##
@@ -3313,6 +3353,7 @@ class Gem::Resolv
end
end
+ # Internal use; use self.create.
def initialize(coordinates,orientation)
unless coordinates.kind_of?(String)
raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
@@ -3375,6 +3416,8 @@ class Gem::Resolv
class Alt
+ # Regular expression LOC Alt must match.
+
Regex = /^([+-]*\d+\.*\d*)[m]$/
##
@@ -3400,6 +3443,7 @@ class Gem::Resolv
end
end
+ # Internal use; use self.create.
def initialize(altitude)
@altitude = altitude
end
diff --git a/lib/rubygems/vendor/timeout/lib/timeout.rb b/lib/rubygems/vendor/timeout/lib/timeout.rb
index 455c504f47..376b8c0e2b 100644
--- a/lib/rubygems/vendor/timeout/lib/timeout.rb
+++ b/lib/rubygems/vendor/timeout/lib/timeout.rb
@@ -20,7 +20,7 @@
module Gem::Timeout
# The version
- VERSION = "0.4.3"
+ VERSION = "0.4.4"
# Internal error raised to when a timeout is triggered.
class ExitException < Exception
@@ -123,6 +123,9 @@ module Gem::Timeout
def self.ensure_timeout_thread_created
unless @timeout_thread and @timeout_thread.alive?
+ # If the Mutex is already owned we are in a signal handler.
+ # In that case, just return and let the main thread create the @timeout_thread.
+ return if TIMEOUT_THREAD_MUTEX.owned?
TIMEOUT_THREAD_MUTEX.synchronize do
unless @timeout_thread and @timeout_thread.alive?
@timeout_thread = create_timeout_thread
diff --git a/lib/rubygems/vendor/uri/lib/uri/common.rb b/lib/rubygems/vendor/uri/lib/uri/common.rb
index f0755f5fdc..e9bdfa6a07 100644
--- a/lib/rubygems/vendor/uri/lib/uri/common.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/common.rb
@@ -30,6 +30,9 @@ module Gem::URI
remove_const(:Parser) if defined?(::Gem::URI::Parser)
const_set("Parser", parser.class)
+ remove_const(:PARSER) if defined?(::Gem::URI::PARSER)
+ const_set("PARSER", parser)
+
remove_const(:REGEXP) if defined?(::Gem::URI::REGEXP)
remove_const(:PATTERN) if defined?(::Gem::URI::PATTERN)
if Parser == RFC2396_Parser
@@ -49,10 +52,10 @@ module Gem::URI
warn "Gem::URI::REGEXP is obsolete. Use Gem::URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE
Gem::URI::RFC2396_REGEXP
elsif value = RFC2396_PARSER.regexp[const]
- warn "Gem::URI::#{const} is obsolete. Use RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
+ warn "Gem::URI::#{const} is obsolete. Use Gem::URI::RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
value
elsif value = RFC2396_Parser.const_get(const)
- warn "Gem::URI::#{const} is obsolete. Use RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
+ warn "Gem::URI::#{const} is obsolete. Use Gem::URI::RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
value
else
super
@@ -92,6 +95,40 @@ module Gem::URI
end
module Schemes # :nodoc:
+ class << self
+ ReservedChars = ".+-"
+ EscapedChars = "\u01C0\u01C1\u01C2"
+ # Use Lo category chars as escaped chars for TruffleRuby, which
+ # does not allow Symbol categories as identifiers.
+
+ def escape(name)
+ unless name and name.ascii_only?
+ return nil
+ end
+ name.upcase.tr(ReservedChars, EscapedChars)
+ end
+
+ def unescape(name)
+ name.tr(EscapedChars, ReservedChars).encode(Encoding::US_ASCII).upcase
+ end
+
+ def find(name)
+ const_get(name, false) if name and const_defined?(name, false)
+ end
+
+ def register(name, klass)
+ unless scheme = escape(name)
+ raise ArgumentError, "invalid character as scheme - #{name}"
+ end
+ const_set(scheme, klass)
+ end
+
+ def list
+ constants.map { |name|
+ [unescape(name.to_s), const_get(name)]
+ }.to_h
+ end
+ end
end
private_constant :Schemes
@@ -104,7 +141,7 @@ module Gem::URI
# 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)
+ Schemes.register(scheme, klass)
end
# Returns a hash of the defined schemes:
@@ -122,14 +159,14 @@ module Gem::URI
#
# Related: Gem::URI.register_scheme.
def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
+ Schemes.list
end
+ # :stopdoc:
INITIAL_SCHEMES = scheme_list
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
+ # :startdoc:
# Returns a new object constructed from the given +scheme+, +arguments+,
# and +default+:
@@ -148,12 +185,10 @@ module Gem::URI
# # => #<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
+ const_name = Schemes.escape(scheme)
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 ||= Schemes.find(const_name)
uri_class ||= default
return uri_class.new(scheme, *arguments)
@@ -195,7 +230,7 @@ module Gem::URI
# ["fragment", "top"]]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ PARSER.split(uri)
end
# Returns a new \Gem::URI object constructed from the given string +uri+:
@@ -205,11 +240,11 @@ module Gem::URI
# 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+
+ # It's recommended to first Gem::URI::RFC2396_PARSER.escape string +uri+
# if it may contain invalid Gem::URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ PARSER.parse(uri)
end
# Merges the given Gem::URI strings +str+
@@ -265,7 +300,7 @@ module Gem::URI
#
def self.extract(str, schemes = nil, &block) # :nodoc:
warn "Gem::URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
+ PARSER.extract(str, schemes, &block)
end
#
@@ -302,7 +337,7 @@ module Gem::URI
#
def self.regexp(schemes = nil)# :nodoc:
warn "Gem::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
+ PARSER.make_regexp(schemes)
end
TBLENCWWWCOMP_ = {} # :nodoc:
@@ -407,6 +442,8 @@ module Gem::URI
_decode_uri_component(/%\h\h/, str, enc)
end
+ # Returns a string derived from the given string +str+ with
+ # Gem::URI-encoded characters matching +regexp+ according to +table+.
def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
@@ -421,6 +458,8 @@ module Gem::URI
end
private_class_method :_encode_uri_component
+ # Returns a string decoding characters matching +regexp+ from the
+ # given \URL-encoded string +str+.
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)
@@ -859,6 +898,7 @@ 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:
#
+ # require 'rubygems/vendor/uri/lib/uri'
# # Returns a new Gem::URI.
# uri = Gem::URI('http://github.com/ruby/ruby')
# # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
@@ -866,6 +906,8 @@ module Gem
# Gem::URI(uri)
# # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
#
+ # You must require 'rubygems/vendor/uri/lib/uri' to use this method.
+ #
def URI(uri)
if uri.is_a?(Gem::URI::Generic)
uri
diff --git a/lib/rubygems/vendor/uri/lib/uri/file.rb b/lib/rubygems/vendor/uri/lib/uri/file.rb
index 768755fc2d..391c499716 100644
--- a/lib/rubygems/vendor/uri/lib/uri/file.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/file.rb
@@ -47,7 +47,7 @@ module Gem::URI
# :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 = Gem::URI::File.build({:path => Gem::URI::RFC2396_PARSER.escape('/path/my file.txt')})
# uri3.to_s # => "file:///path/my%20file.txt"
#
def self.build(args)
diff --git a/lib/rubygems/vendor/uri/lib/uri/generic.rb b/lib/rubygems/vendor/uri/lib/uri/generic.rb
index 2eabe2b4e3..d0bc77dfda 100644
--- a/lib/rubygems/vendor/uri/lib/uri/generic.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/generic.rb
@@ -73,7 +73,7 @@ module Gem::URI
#
# 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.
+ # then it does Gem::URI::RFC2396_PARSER.escape all Gem::URI components and tries again.
#
def self.build2(args)
begin
@@ -126,9 +126,9 @@ module Gem::URI
end
end
else
- component = self.class.component rescue ::Gem::URI::Generic::COMPONENT
+ component = self.component rescue ::Gem::URI::Generic::COMPONENT
raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
+ "expected Array of or Hash of components of #{self} (#{component.join(', ')})"
end
tmp << nil
@@ -186,18 +186,18 @@ module Gem::URI
if arg_check
self.scheme = scheme
- self.userinfo = userinfo
self.hostname = host
self.port = port
+ self.userinfo = userinfo
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_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
@@ -284,7 +284,7 @@ module Gem::URI
# Returns the parser to be used.
#
- # Unless a Gem::URI::Parser is defined, DEFAULT_PARSER is used.
+ # Unless the +parser+ is defined, DEFAULT_PARSER is used.
#
def parser
if !defined?(@parser) || !@parser
@@ -315,7 +315,7 @@ module Gem::URI
end
#
- # Checks the scheme +v+ component against the Gem::URI::Parser Regexp for :SCHEME.
+ # Checks the scheme +v+ component against the +parser+ Regexp for :SCHEME.
#
def check_scheme(v)
if v && parser.regexp[:SCHEME] !~ v
@@ -385,7 +385,7 @@ module Gem::URI
#
# Checks the user +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -409,7 +409,7 @@ module Gem::URI
#
# Checks the password +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -511,7 +511,7 @@ module Gem::URI
user, password = split_userinfo(user)
end
@user = user
- @password = password if password
+ @password = password
[@user, @password]
end
@@ -522,7 +522,7 @@ module Gem::URI
# See also Gem::URI::Generic.user=.
#
def set_user(v)
- set_userinfo(v, @password)
+ set_userinfo(v, nil)
v
end
protected :set_user
@@ -574,6 +574,12 @@ module Gem::URI
@password
end
+ # Returns the authority info (array of user, password, host and
+ # port), if any is set. Or returns +nil+.
+ def authority
+ return @user, @password, @host, @port if @user || @password || @host || @port
+ end
+
# Returns the user component after Gem::URI decoding.
def decoded_user
Gem::URI.decode_uri_component(@user) if @user
@@ -586,7 +592,7 @@ module Gem::URI
#
# Checks the host +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :HOST.
+ # and against the +parser+ Regexp for :HOST.
#
# Can not have a registry or opaque component defined,
# with a host component defined.
@@ -615,6 +621,13 @@ module Gem::URI
end
protected :set_host
+ # Protected setter for the authority info (+user+, +password+, +host+
+ # and +port+). If +port+ is +nil+, +default_port+ will be set.
+ #
+ protected def set_authority(user, password, host, port = nil)
+ @user, @password, @host, @port = user, password, host, port || self.default_port
+ end
+
#
# == Args
#
@@ -639,6 +652,7 @@ module Gem::URI
def host=(v)
check_host(v)
set_host(v)
+ set_userinfo(nil)
v
end
@@ -675,7 +689,7 @@ module Gem::URI
#
# Checks the port +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :PORT.
+ # and against the +parser+ Regexp for :PORT.
#
# Can not have a registry or opaque component defined,
# with a port component defined.
@@ -729,6 +743,7 @@ module Gem::URI
def port=(v)
check_port(v)
set_port(v)
+ set_userinfo(nil)
port
end
@@ -748,7 +763,7 @@ module Gem::URI
#
# Checks the path +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp
+ # and against the +parser+ Regexp
# for :ABS_PATH and :REL_PATH.
#
# Can not have a opaque component defined,
@@ -853,7 +868,7 @@ module Gem::URI
#
# Checks the opaque +v+ component for RFC2396 compliance and
- # against the Gem::URI::Parser Regexp for :OPAQUE.
+ # against the +parser+ Regexp for :OPAQUE.
#
# Can not have a host, port, user, or path component defined,
# with an opaque component defined.
@@ -905,7 +920,7 @@ module Gem::URI
end
#
- # Checks the fragment +v+ component against the Gem::URI::Parser Regexp for :FRAGMENT.
+ # Checks the fragment +v+ component against the +parser+ Regexp for :FRAGMENT.
#
#
# == Args
@@ -1121,7 +1136,7 @@ module Gem::URI
base = self.dup
- authority = rel.userinfo || rel.host || rel.port
+ authority = rel.authority
# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
@@ -1134,9 +1149,7 @@ module Gem::URI
# 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_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
@@ -1527,7 +1540,7 @@ module Gem::URI
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
+ warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1
end
end
end
diff --git a/lib/rubygems/vendor/uri/lib/uri/http.rb b/lib/rubygems/vendor/uri/lib/uri/http.rb
index 658e9941dd..99c78358ac 100644
--- a/lib/rubygems/vendor/uri/lib/uri/http.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/http.rb
@@ -61,6 +61,18 @@ module Gem::URI
super(tmp)
end
+ # Do not allow empty host names, as they are not allowed by RFC 3986.
+ def check_host(v)
+ ret = super
+
+ if ret && v.empty?
+ raise InvalidComponentError,
+ "bad component(expected host component): #{v}"
+ end
+
+ ret
+ end
+
#
# == Description
#
diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
index 04a1d0c869..2bb4181649 100644
--- a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
@@ -67,7 +67,7 @@ module Gem::URI
#
# == Synopsis
#
- # Gem::URI::Parser.new([opts])
+ # Gem::URI::RFC2396_Parser.new([opts])
#
# == Args
#
@@ -86,7 +86,7 @@ module Gem::URI
#
# == Examples
#
- # p = Gem::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
+ # p = Gem::URI::RFC2396_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
#
@@ -108,12 +108,12 @@ module Gem::URI
# The Hash of patterns.
#
- # See also Gem::URI::Parser.initialize_pattern.
+ # See also #initialize_pattern.
attr_reader :pattern
# The Hash of Regexp.
#
- # See also Gem::URI::Parser.initialize_regexp.
+ # See also #initialize_regexp.
attr_reader :regexp
# Returns a split Gem::URI against +regexp[:ABS_URI]+.
@@ -202,8 +202,7 @@ module Gem::URI
#
# == Usage
#
- # p = Gem::URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
+ # Gem::URI::RFC2396_PARSER.parse("ldap://ldap.example.com/dc=example?user=john")
# #=> #<Gem::URI::LDAP ldap://ldap.example.com/dc=example?user=john>
#
def parse(uri)
@@ -244,7 +243,7 @@ module Gem::URI
# If no +block+ given, then returns the result,
# else it calls +block+ for each element in result.
#
- # See also Gem::URI::Parser.make_regexp.
+ # See also #make_regexp.
#
def extract(str, schemes = nil)
if block_given?
@@ -263,7 +262,7 @@ module Gem::URI
unless schemes
@regexp[:ABS_URI_REF]
else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
+ /(?=(?i:#{Regexp.union(*schemes).source}):)#{@pattern[:X_ABS_URI]}/x
end
end
@@ -524,6 +523,8 @@ module Gem::URI
ret
end
+ # Returns +uri+ as-is if it is Gem::URI, or convert it to Gem::URI if it is
+ # a String.
def convert_to_uri(uri)
if uri.is_a?(Gem::URI::Generic)
uri
diff --git a/lib/rubygems/vendor/uri/lib/uri/version.rb b/lib/rubygems/vendor/uri/lib/uri/version.rb
index c2f617ce25..7ee577887b 100644
--- a/lib/rubygems/vendor/uri/lib/uri/version.rb
+++ b/lib/rubygems/vendor/uri/lib/uri/version.rb
@@ -1,6 +1,6 @@
module Gem::URI
# :stopdoc:
- VERSION_CODE = '010003'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
+ VERSION = '1.1.1'.freeze
+ VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze
# :startdoc:
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_pub_grub.rb b/lib/rubygems/vendored_pub_grub.rb
new file mode 100644
index 0000000000..844d243ab3
--- /dev/null
+++ b/lib/rubygems/vendored_pub_grub.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "vendor/pub_grub/lib/pub_grub"
diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb
index 25c412be4b..306733c1d7 100644
--- a/lib/rubygems/version.rb
+++ b/lib/rubygems/version.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
-require_relative "deprecate"
+#--
+# Workaround for directly loading Gem::Version in some cases
+module Gem; end
+#++
##
# The Version class processes string versions into comparable
@@ -27,136 +30,153 @@ require_relative "deprecate"
# 4. 0.9
#
# If you want to specify a version restriction that includes both prereleases
-# and regular releases of the 1.x series this is the best way:
+# and regular releases of 1.x or later versions:
#
-# s.add_dependency 'example', '>= 1.0.0.a', '< 2.0.0'
+# s.add_dependency 'example', '>= 1.0.0.a'
#
# == How Software Changes
#
-# Users expect to be able to specify a version constraint that gives them
-# some reasonable expectation that new versions of a library will work with
-# their software if the version constraint is true, and not work with their
-# software if the version constraint is false. In other words, the perfect
-# system will accept all compatible versions of the library and reject all
-# incompatible versions.
-#
-# Libraries change in 3 ways (well, more than 3, but stay focused here!).
-#
-# 1. The change may be an implementation detail only and have no effect on
-# the client software.
-# 2. The change may add new features, but do so in a way that client software
-# written to an earlier version is still compatible.
-# 3. The change may change the public interface of the library in such a way
-# that old software is no longer compatible.
-#
-# Some examples are appropriate at this point. Suppose I have a Stack class
-# that supports a <tt>push</tt> and a <tt>pop</tt> method.
+# Libraries generally change in 3 ways:
#
-# === Examples of Category 1 changes:
+# 1. The change is an implementation detail, bug fix, security fix, or
+# optimization, and has no behavioral effect on the software using it.
#
-# * Switch from an array based implementation to a linked-list based
-# implementation.
-# * Provide an automatic (and transparent) backing store for large stacks.
+# 2. The change adds new features, and software using those new features is
+# not compatible with previous versions of the library, but software using
+# previous versions of the library is compatible with the change.
#
-# === Examples of Category 2 changes might be:
+# 3. The change modifies the public interface of some part of the library in
+# such a way that software that uses that part of the library must be
+# modified to work.
#
-# * Add a <tt>depth</tt> method to return the current depth of the stack.
-# * Add a <tt>top</tt> method that returns the current top of stack (without
-# changing the stack).
-# * Change <tt>push</tt> so that it returns the item pushed (previously it
-# had no usable return value).
-#
-# === Examples of Category 3 changes might be:
-#
-# * Changes <tt>pop</tt> so that it no longer returns a value (you must use
-# <tt>top</tt> to get the top of the stack).
-# * Rename the methods to <tt>push_item</tt> and <tt>pop_item</tt>.
-#
-# == RubyGems Rational Versioning
+# == RubyGems Rational Versioning (the recommended approach)
#
# * Versions shall be represented by three non-negative integers, separated
-# by periods (e.g. 3.1.4). The first integers is the "major" version
+# by periods (e.g. 3.1.4). The first integer is the "major" version
# number, the second integer is the "minor" version number, and the third
-# integer is the "build" number.
+# integer is the "patch" version number.
#
-# * A category 1 change (implementation detail) will increment the build
-# number.
+# * A category 1 change (implementation detail, bug fix, or security fix)
+# will increment the patch number.
#
# * A category 2 change (backwards compatible) will increment the minor
-# version number and reset the build number.
-#
-# * A category 3 change (incompatible) will increment the major build number
-# and reset the minor and build numbers.
-#
-# * Any "public" release of a gem should have a different version. Normally
-# that means incrementing the build number. This means a developer can
-# generate builds all day long, but as soon as they make a public release,
-# the version must be updated.
-#
-# === Examples
+# version number and reset the patch number.
#
-# Let's work through a project lifecycle using our Stack example from above.
+# * A category 3 change (incompatible) will increment the major version number
+# and reset the minor and patch numbers.
#
-# Version 0.0.1:: The initial Stack class is release.
-# Version 0.0.2:: Switched to a linked=list implementation because it is
-# cooler.
-# Version 0.1.0:: Added a <tt>depth</tt> method.
-# Version 1.0.0:: Added <tt>top</tt> and made <tt>pop</tt> return nil
-# (<tt>pop</tt> used to return the old top item).
-# Version 1.1.0:: <tt>push</tt> now returns the value pushed (it used it
-# return nil).
-# Version 1.1.1:: Fixed a bug in the linked list implementation.
-# Version 1.1.2:: Fixed a bug introduced in the last fix.
+# * Any "public" release of a gem should have a different version.
#
-# Client A needs a stack with basic push/pop capability. They write to the
-# original interface (no <tt>top</tt>), so their version constraint looks like:
+# == Optimistic Vs. Pessimistic Dependency Versioning
#
-# gem 'stack', '>= 0.0'
-#
-# Essentially, any version is OK with Client A. An incompatible change to
-# the library will cause them grief, but they are willing to take the chance
-# (we call Client A optimistic).
-#
-# Client B is just like Client A except for two things: (1) They use the
-# <tt>depth</tt> method and (2) they are worried about future
-# incompatibilities, so they write their version constraint like this:
-#
-# gem 'stack', '~> 0.1'
-#
-# The <tt>depth</tt> method was introduced in version 0.1.0, so that version
-# or anything later is fine, as long as the version stays below version 1.0
-# where incompatibilities are introduced. We call Client B pessimistic
-# because they are worried about incompatible future changes (it is OK to be
-# pessimistic!).
-#
-# == Preventing Version Catastrophe:
-#
-# From: https://www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.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
-# happens if fnord 3.0 comes out and it isn't backwards compatible
-# with 2.y.z? Your stuff will break as a result of using ">=". The
-# better route is to specify your dependency with an "approximate" version
-# specifier ("~>"). They're a tad confusing, so here is how the dependency
-# specifiers work:
-#
-# Specification From ... To (exclusive)
-# ">= 3.0" 3.0 ... &infin;
-# "~> 3.0" 3.0 ... 4.0
-# "~> 3.0.0" 3.0.0 ... 3.1
-# "~> 3.5" 3.5 ... 4.0
-# "~> 3.5.0" 3.5.0 ... 3.6
-# "~> 3" 3.0 ... 4.0
-#
-# For the last example, single-digit versions are automatically extended with
-# a zero to give a sensible result.
+# Users expect to be able to specify a version constraint that gives them
+# a reasonable expectation that new versions of a library will work with
+# their software if the version constraint is true, and not work with their
+# software if the version constraint is false. In other words, the perfect
+# system will accept all compatible versions of the library and reject all
+# incompatible versions. Unfortunately, there is no perfect system, as you
+# cannot predict the future. You can never know whether a future version of
+# a library will contain which type of change.
+#
+# There are two common outlooks on dependency versioning:
+#
+# 1. Optimistic. This does not set an upper bound on a dependency. It is
+# possible that a future version of a dependency will break the software,
+# and in that case, the dependency version will need to be updated and
+# changes will need to be made.
+#
+# 2. Pessimistic. This assumes all major version changes of a dependency will
+# break the software, and that patch or minor changes of a dependency will
+# not break the software. If there is a major version of a dependency
+# released, the dependency version must be updated in order to use it, even
+# if no code changes are actually needed.
+#
+# In general, optimistic versioning is superior to pessimistic versioning.
+# Pessimistic versioning is often wrong in both directions. Dependencies can
+# release patch or minor versions that contain incompatibilities. One
+# common reason is that a security fix may require a backwards-incompatible API
+# change. In this case, even though pessimistic versioning was used, it
+# didn't even save effort, as you still need to make code changes and adjust
+# dependency versions. Similarly, for all but the smallest dependencies, just
+# because the dependency made a backwards incompatible change to one interface
+# doesn't mean the dependency made a backwards incompatible change to an
+# interface that the software is using. It is a common problem that a
+# dependency will release a new major version and the software does not require
+# any changes in order to use it. In this case, being pessimistic results in
+# additional work for no benefit.
+#
+# When a library uses pessimistic versioning of dependencies, it causes
+# significant problems if that library is not diligent about updating
+# dependency versions and any library is depending on that library.
+# For example:
+#
+# * Library A is currently on release 1.2.3.
+#
+# * Library B is at version 2.3.4 and has a pessimistic dependency on
+# library A, using ~> 1.0 (>= 1.0, < 2).
+#
+# * Library C is at version 3.4.5 and has an optimistic dependency on
+# library A, using >= 1.0.
+#
+# * Library D has optimistic dependencies on both libraries B and C.
+#
+# * Library A releases a new major version, 2.0.0, with new features, which
+# is mostly backwards compatible, but does contain some backwards
+# incompatible changes.
+#
+# * Library B would work with A 2.0.0, but cannot use it due to pessimistic
+# versioning.
+#
+# * Library C wants to use the new features in the major release of library
+# A to implement its own new features, so it does so, bumps the
+# dependency version of A to >= 2.0, and releases version 3.5.0.
+#
+# * Library D cannot upgrade to the new version of library C, because it
+# depends on library B, which has a pessimistic dependency on library A.
+#
+# * Library C releases a security fix patch version 3.5.1 to fix a
+# vulnerability present in all previous versions.
+#
+# * Library D is now in a terrible situation. It cannot upgrade to library
+# C 3.5.1, as that requires library A > 2.0, because it depends on library
+# B, which requires library A > 1.0, < 2, even though library B would work
+# fine with library A 2.0.0.
+#
+# This type of situation brought on by pessimistic versioning is unfortunately
+# both common and serious in practice.
+#
+# This is not to say that optimistic versioning never causes a problem.
+# However, with optimistic versioning, if there is a problem, it can be solved
+# with the addition of a single dependency. For example, continuing the
+# previous example:
+#
+# * Library A releases a new major version, 3.0.0, which makes backwards
+# incompatible changes that break library C.
+#
+# * Until library C releases an updated version with new changes, library
+# D only needs to set a specific dependency on library A for > 2.0, < 3,
+# until library C is updated to work with the new version of library A.
+#
+# Both optimistic versioning and pessimistic versioning have problems in
+# certain cases. However, it's significantly easier to fix optimistic
+# versioning problems than to fix pessimistic versioning problems.
+#
+# That is not to say that pessimistic versioning is never appropriate. If the
+# dependency is a library that adds a single method, where any change resulting
+# in a major version bump would probably break a library using it, then using
+# pessimistic versioning may be warranted. Additionally, if a dependency has
+# already announced or committed backwards incompatible changes that would
+# break a library's use of it, then having that library use a pessimistic
+# version constraint would likely be warranted. However, outside of
+# specific situations, you should avoid using pessimistic versioning, as the
+# costs typically exceed the benefits.
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:
+ RADIX_OPT = [9_500, 3_500, 260_000, 22_227, 24].freeze # :nodoc:
##
# A string representation of this Version.
@@ -171,9 +191,7 @@ class Gem::Version
# True if the +version+ string matches RubyGems' requirements.
def self.correct?(version)
- nil_versions_are_discouraged! if version.nil?
-
- ANCHORED_VERSION_PATTERN.match?(version.to_s)
+ version.nil? || ANCHORED_VERSION_PATTERN.match?(version.to_s)
end
##
@@ -182,15 +200,10 @@ class Gem::Version
#
# ver1 = Version.create('1.3.17') # -> (Version object)
# ver2 = Version.create(ver1) # -> (ver1)
- # ver3 = Version.create(nil) # -> nil
def self.create(input)
if self === input # check yourself before you wreck yourself
input
- elsif input.nil?
- nil_versions_are_discouraged!
-
- nil
else
new input
end
@@ -206,14 +219,6 @@ class Gem::Version
@@all[version] ||= super
end
- def self.nil_versions_are_discouraged!
- unless Gem::Deprecate.skip
- warn "nil versions are discouraged and will be deprecated in Rubygems 4"
- end
- end
-
- private_class_method :nil_versions_are_discouraged!
-
##
# Constructs a Version from the +version+ string. A version string is a
# series of digits or ASCII letters separated by dots.
@@ -224,7 +229,7 @@ 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 = 0 if version.nil? || (version.is_a?(String) && /\A\s*\Z/.match?(version))
@version = version.to_s
@@ -236,6 +241,7 @@ class Gem::Version
end
@version = -@version
@segments = nil
+ @sort_key = compute_sort_key
end
##
@@ -337,7 +343,7 @@ class Gem::Version
end
##
- # A recommended version for use with a ~> Requirement.
+ # A recommended version for use with a >= Requirement.
def approximate_recommendation
segments = self.segments
@@ -346,7 +352,7 @@ class Gem::Version
segments.pop while segments.size > 2
segments.push 0 while segments.size < 2
- recommendation = "~> #{segments.join(".")}"
+ recommendation = ">= #{segments.join(".")}"
recommendation += ".a" if prerelease?
recommendation
end
@@ -354,55 +360,62 @@ class Gem::Version
##
# Compares this version with +other+ returning -1, 0, or 1 if the
# other version is larger, the same, or smaller than this
- # one. Attempts to compare to something that's not a
- # <tt>Gem::Version</tt> or a valid version String return +nil+.
+ # one. +other+ must be an instance of Gem::Version, comparing with
+ # other types may raise an exception.
def <=>(other)
- 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
+ if Gem::Version === other
+ # Fast path for comparison when available.
+ if @sort_key && other.sort_key
+ return @sort_key <=> other.sort_key
+ end
- lhsegments = canonical_segments
- rhsegments = other.canonical_segments
+ return 0 if @version == other.version || canonical_segments == other.canonical_segments
- lhsize = lhsegments.size
- rhsize = rhsegments.size
- limit = (lhsize > rhsize ? rhsize : lhsize)
+ lhsegments = canonical_segments
+ rhsegments = other.canonical_segments
- i = 0
+ lhsize = lhsegments.size
+ rhsize = rhsegments.size
+ limit = (lhsize > rhsize ? rhsize : lhsize)
- while i < limit
- lhs = lhsegments[i]
- rhs = rhsegments[i]
- i += 1
+ i = 0
- next if lhs == rhs
- return -1 if String === lhs && Numeric === rhs
- return 1 if Numeric === lhs && String === rhs
+ while i < limit
+ lhs = lhsegments[i]
+ rhs = rhsegments[i]
+ i += 1
- return lhs <=> rhs
- end
+ next if lhs == rhs
+ return -1 if String === lhs && Numeric === rhs
+ return 1 if Numeric === lhs && String === rhs
- lhs = lhsegments[i]
+ return lhs <=> rhs
+ end
- if lhs.nil?
- rhs = rhsegments[i]
+ lhs = lhsegments[i]
- while i < rhsize
- return 1 if String === rhs
- return -1 unless rhs.zero?
- rhs = rhsegments[i += 1]
- end
- else
- while i < lhsize
- return -1 if String === lhs
- return 1 unless lhs.zero?
- lhs = lhsegments[i += 1]
+ if lhs.nil?
+ rhs = rhsegments[i]
+
+ while i < rhsize
+ return 1 if String === rhs
+ return -1 unless rhs.zero?
+ rhs = rhsegments[i += 1]
+ end
+ else
+ while i < lhsize
+ return -1 if String === lhs
+ return 1 unless lhs.zero?
+ lhs = lhsegments[i += 1]
+ end
end
- end
- 0
+ 0
+ elsif String === other
+ return unless self.class.correct?(other)
+ self <=> self.class.new(other)
+ end
end
# remove trailing zeros segments before first letter or at the end of the version
@@ -426,6 +439,24 @@ class Gem::Version
protected
+ attr_reader :sort_key # :nodoc:
+
+ def compute_sort_key
+ return if prerelease?
+
+ segments = canonical_segments
+ return if segments.size > 5
+
+ key = 0
+ RADIX_OPT.each_with_index do |radix, i|
+ seg = segments.fetch(i, 0)
+ return nil if seg >= radix
+ key = key * radix + seg
+ end
+
+ key
+ 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.
diff --git a/lib/rubygems/win_platform.rb b/lib/rubygems/win_platform.rb
new file mode 100644
index 0000000000..10556871b2
--- /dev/null
+++ b/lib/rubygems/win_platform.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require "rbconfig"
+
+module Gem
+ ##
+ # An Array of Regexps that match windows Ruby platforms.
+
+ WIN_PATTERNS = [
+ /bccwin/i,
+ /djgpp/i,
+ /mingw/i,
+ /mswin/i,
+ /wince/i,
+ ].freeze
+
+ @@win_platform = nil
+
+ ##
+ # Is this a windows platform?
+
+ def self.win_platform?
+ if @@win_platform.nil?
+ ruby_platform = RbConfig::CONFIG["host_os"]
+ @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
+ end
+
+ @@win_platform
+ end
+end
diff --git a/lib/rubygems/yaml_serializer.rb b/lib/rubygems/yaml_serializer.rb
index f89004f32a..b2547b136b 100644
--- a/lib/rubygems/yaml_serializer.rb
+++ b/lib/rubygems/yaml_serializer.rb
@@ -1,98 +1,845 @@
# frozen_string_literal: true
+unless defined?(Psych::VERSION)
+ module Psych
+ class Exception < ::RuntimeError; end
+ class SyntaxError < Exception; end
+ class DisallowedClass < Exception; end
+ class BadAlias < Exception; end
+ class AliasesNotEnabled < BadAlias; end
+ end
+end
+
module Gem
- # A stub yaml serializer that can handle only hashes and strings (as of now).
module YAMLSerializer
- module_function
+ Scalar = Struct.new(:value, :tag, :anchor, keyword_init: true)
- def dump(hash)
- yaml = String.new("---")
- yaml << dump_hash(hash)
+ Mapping = Struct.new(:pairs, :tag, :anchor, keyword_init: true) do
+ def initialize(pairs: [], tag: nil, anchor: nil)
+ super
+ end
+ end
+
+ Sequence = Struct.new(:items, :tag, :anchor, keyword_init: true) do
+ def initialize(items: [], tag: nil, anchor: nil)
+ super
+ end
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"
+ AliasRef = Struct.new(:name, keyword_init: true)
+
+ class Parser
+ MAPPING_KEY_RE = /^((?:[^#:]|:[^ ])+):(?:[ ]+(.*))?$/
+ MAX_NESTING_DEPTH = 1_000
+
+ def initialize(source)
+ @lines = source.split("\n")
+ @anchors = {}
+ @depth = 0
+ strip_document_prefix
+ end
+
+ def parse
+ return nil if @lines.empty?
+
+ root = nil
+ while @lines.any?
+ before = @lines.size
+ node = parse_node(-1)
+ @lines.shift if @lines.size == before && @lines.any?
+
+ if root.is_a?(Mapping) && node.is_a?(Mapping)
+ root.pairs.concat(node.pairs)
+ elsif root.nil?
+ root = node
+ end
+ end
+ root
+ end
+
+ private
+
+ def strip_document_prefix
+ return if @lines.empty?
+ return unless @lines[0]&.start_with?("---")
+
+ if @lines[0].strip == "---"
+ @lines.shift
+ else
+ @lines[0] = @lines[0].sub(/^---\s*/, "")
+ end
+ end
+
+ def parse_node(base_indent)
+ @depth += 1
+ raise_max_nesting! if @depth > MAX_NESTING_DEPTH
+
+ skip_blank_and_comments
+ return nil if @lines.empty?
+
+ line = @lines[0]
+ stripped = line.lstrip
+ indent = line.size - stripped.size
+ return nil if indent < base_indent
+
+ return parse_alias_ref if stripped.start_with?("*")
+
+ anchor = consume_anchor
+
+ if anchor
+ line = @lines[0]
+ stripped = line.lstrip
+ end
+
+ if stripped.start_with?("- ") || stripped == "-"
+ parse_sequence(indent, anchor)
+ elsif stripped.start_with?("\"") && stripped.end_with?("\"")
+ # We don't need to care about the following case here:
+ # 1. "value with comment" # ...
+ # 2. "key": "value"
+ #
+ # 1. must not happen because YAMLSerializer doesn't emit any
+ # comment. YAMLSerializer parses only YAML that is generated
+ # by YAMLSerializer.
+ #
+ # 2. must not happen because #parse_node isn't used non
+ # top-level mapping. Non top-level mapping always uses
+ # #parse_mapping. Top-level mapping never use the '"key":
+ # "value"' form because all top-level keys
+ # ("!ruby/object:Gem::Specification"'s keys) are known and
+ # #emit_specification doesn't quote anything.
+ parse_plain_scalar(indent, anchor)
+ elsif stripped.start_with?("'") && stripped.end_with?("'")
+ # See also the above note for double quotation.
+ parse_plain_scalar(indent, anchor)
+ elsif stripped =~ MAPPING_KEY_RE && !stripped.start_with?("!ruby/object:")
+ parse_mapping(indent, anchor)
+ elsif stripped.start_with?("!ruby/object:")
+ parse_tagged_node(indent, anchor)
+ elsif stripped.start_with?("|")
+ modifier = stripped[1..].to_s.strip
+ @lines.shift
+ register_anchor(anchor, Scalar.new(value: parse_block_scalar(indent, modifier)))
+ else
+ parse_plain_scalar(indent, anchor)
+ end
+ ensure
+ @depth -= 1
+ end
+
+ def parse_sequence(indent, anchor)
+ items = []
+ while @lines.any?
+ line = @lines[0]
+ stripped = line.lstrip
+ break unless line.size - stripped.size == indent &&
+ (stripped.start_with?("- ") || stripped == "-")
+ content = @lines.shift.lstrip[1..].strip
+ item_anchor, content = extract_item_anchor(content)
+ item = parse_sequence_item(content, indent)
+ items << register_anchor(item_anchor, item)
+ end
+ register_anchor(anchor, Sequence.new(items: items))
+ end
+
+ def parse_sequence_item(content, indent)
+ if content.start_with?("*")
+ parse_inline_alias(content)
+ elsif content.empty?
+ @lines.any? && current_indent > indent ? parse_node(indent) : nil
+ elsif content.start_with?("!ruby/object:")
+ parse_tagged_content(content.strip, indent)
+ elsif content.start_with?("!binary ")
+ parse_binary_value(content, indent)
+ elsif content.start_with?("-")
+ @lines.unshift("#{" " * (indent + 2)}#{content}")
+ parse_node(indent)
+ elsif content =~ MAPPING_KEY_RE && !content.start_with?("!ruby/object:")
+ @lines.unshift("#{" " * (indent + 2)}#{content}")
+ parse_node(indent)
+ elsif content.start_with?("|")
+ Scalar.new(value: parse_block_scalar(indent, content[1..].to_s.strip))
+ else
+ parse_inline_scalar(content, indent)
+ end
+ end
+
+ def parse_mapping(indent, anchor)
+ pairs = []
+ while @lines.any?
+ line = @lines[0]
+ stripped = line.lstrip
+ break unless line.size - stripped.size == indent &&
+ stripped =~ MAPPING_KEY_RE && !stripped.start_with?("!ruby/object:")
+ key = $1.strip
+ @lines.shift
+ val = strip_comment($2.to_s.strip)
+
+ key = decode_binary_tag(key) if key.start_with?("!binary ")
+
+ val_anchor, val = consume_value_anchor(val)
+ value = parse_mapping_value(val, indent)
+ value = register_anchor(val_anchor, value) if val_anchor
+
+ pairs << [Scalar.new(value: key), value]
+ end
+ register_anchor(anchor, Mapping.new(pairs: pairs))
+ end
+
+ def parse_mapping_value(val, indent)
+ if val.start_with?("*")
+ parse_inline_alias(val)
+ elsif val.start_with?("!ruby/object:")
+ parse_tagged_content(val.strip, indent)
+ elsif val.start_with?("!binary ")
+ parse_binary_value(val, indent)
+ elsif val.empty?
+ next_stripped = nil
+ next_indent = nil
+ if @lines.any?
+ next_stripped = @lines[0].lstrip
+ next_indent = @lines[0].size - next_stripped.size
+ end
+ if next_stripped &&
+ (next_stripped.start_with?("- ") || next_stripped == "-") &&
+ next_indent == indent
+ parse_node(indent)
else
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
+ parse_node(indent + 1)
end
+ elsif val == "[]"
+ Sequence.new
+ elsif val == "{}"
+ Mapping.new
+ elsif val.start_with?("|")
+ Scalar.new(value: parse_block_scalar(indent, val[1..].to_s.strip))
else
- yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
+ parse_inline_scalar(val, indent)
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]
+ def parse_tagged_node(indent, anchor)
+ tag = @lines.shift.strip
+ nested = parse_node(indent)
+ apply_tag(nested, tag, anchor)
+ end
+
+ def parse_tagged_content(tag, indent)
+ nested = parse_node(indent)
+ apply_tag(nested, tag, nil)
+ end
+
+ def apply_tag(node, tag, anchor)
+ if node.is_a?(Mapping)
+ node.tag = tag
+ node.anchor = anchor
+ node
+ else
+ Mapping.new(pairs: [[Scalar.new(value: "value"), node]], tag: tag, anchor: anchor)
+ end
+ end
+
+ def parse_block_scalar(base_indent, modifier)
+ parts = []
+ block_indent = nil
+
+ while @lines.any?
+ line = @lines[0]
+ if line.strip.empty?
+ parts << "\n"
+ @lines.shift
else
- val = [] if val == "[]" # empty array
- stack[depth][key] = val
+ line_indent = line.size - line.lstrip.size
+ break if line_indent <= base_indent
+ block_indent ||= line_indent
+ parts << @lines.shift[block_indent..].to_s << "\n"
+ end
+ end
+
+ res = parts.join
+ res.chomp! if modifier == "-" && res.end_with?("\n")
+ res
+ end
+
+ def parse_plain_scalar(indent, anchor)
+ result = coerce(@lines.shift.strip)
+ return register_anchor(anchor, result) if result.is_a?(Mapping) || result.is_a?(Sequence)
+
+ while result.is_a?(String) && @lines.any? &&
+ !@lines[0].strip.empty? && current_indent > indent
+ result << " " << @lines.shift.strip
+ end
+ register_anchor(anchor, Scalar.new(value: result))
+ end
+
+ def parse_inline_scalar(val, indent)
+ result = coerce(val)
+ return result if result.is_a?(Mapping) || result.is_a?(Sequence)
+
+ while result.is_a?(String) && @lines.any? &&
+ !@lines[0].strip.empty? && current_indent > indent
+ result << " " << @lines.shift.strip
+ end
+ Scalar.new(value: result)
+ end
+
+ def coerce(val, depth = 0)
+ raise_max_nesting! if depth > MAX_NESTING_DEPTH
+
+ val = val.sub(/^! /, "") if val.start_with?("! ")
+
+ if val =~ /^"(.*)"$/
+ $1.gsub(/\\["nrt\\]/) do |m|
+ case m
+ when '\\"' then '"'
+ when "\\n" then "\n"
+ when "\\r" then "\r"
+ when "\\t" then "\t"
+ when "\\\\" then "\\"
+ end
+ end
+ elsif val =~ /^'(.*)'$/
+ $1.gsub(/''/, "'")
+ elsif val == "true"
+ true
+ elsif val == "false"
+ false
+ elsif ["~", "null"].include?(val)
+ nil
+ elsif val == "{}"
+ Mapping.new
+ elsif val =~ /^\[(.*)\]$/
+ inner = $1.strip
+ return Sequence.new if inner.empty?
+ items = inner.split(/\s*,\s*/).reject(&:empty?).map {|e| Scalar.new(value: coerce(e, depth + 1)) }
+ Sequence.new(items: items)
+ elsif /\A\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}:\d{2})?/.match?(val)
+ begin
+ Time.new(val)
+ rescue ArgumentError
+ # date-only format like "2024-06-15" is not supported by Time.new
+ if /\A(\d{4})-(\d{2})-(\d{2})\z/.match(val)
+ Time.utc($1.to_i, $2.to_i, $3.to_i)
+ else
+ val
+ end
end
- elsif match = ARRAY_REGEX.match(line)
- _, val = match.captures
- val = strip_comment(val)
+ elsif /^-?\d+$/.match?(val)
+ val.to_i
+ else
+ val
+ end
+ end
- last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array)
+ def decode_binary_tag(str)
+ content = str.sub(/\A!binary\s+/, "")
+ content = $1 if content =~ /\A"(.*)"\z/ || content =~ /\A'(.*)'\z/
+ content.unpack1("m")
+ end
- last_hash[last_empty_key].push(val)
+ def parse_binary_value(val, indent)
+ rest = val.sub(/\A!binary\s+/, "")
+ if rest.start_with?("|")
+ content = parse_block_scalar(indent, rest[1..].to_s.strip)
+ Scalar.new(value: content.unpack1("m"))
+ else
+ Scalar.new(value: decode_binary_tag(val))
end
end
- res
- end
- def strip_comment(val)
- if val.include?("#") && !val.start_with?("#")
- val.split("#", 2).first.strip
- else
+ def parse_alias_ref
+ AliasRef.new(name: @lines.shift.lstrip[1..].strip)
+ end
+
+ def parse_inline_alias(content)
+ AliasRef.new(name: content[1..].strip)
+ end
+
+ def current_indent
+ line = @lines[0]
+ line.size - line.lstrip.size
+ end
+
+ def consume_anchor
+ line = @lines[0]
+ stripped = line.lstrip
+ return nil unless stripped.start_with?("&") && stripped =~ /^&(\S+)\s+/
+
+ anchor = $1
+ @lines[0] = line.sub(/&#{Regexp.escape(anchor)}\s+/, "")
+ anchor
+ end
+
+ def extract_item_anchor(content)
+ return [nil, content] unless content =~ /^&(\S+)/
+
+ anchor = $1
+ [anchor, content.sub(/^&#{Regexp.escape(anchor)}\s*/, "")]
+ end
+
+ def consume_value_anchor(val)
+ return [nil, val] unless val =~ /^&(\S+)\s+/
+
+ anchor = $1
+ [anchor, val.sub(/^&#{Regexp.escape(anchor)}\s+/, "")]
+ end
+
+ def register_anchor(name, node)
+ if name
+ @anchors[name] = node
+ node.anchor = name if node.respond_to?(:anchor=)
+ end
+ node
+ end
+
+ def raise_max_nesting!
+ message = "exceeded maximum nesting depth (#{MAX_NESTING_DEPTH})"
+ if defined?(Psych::VERSION)
+ raise Psych::SyntaxError.new(nil, 0, 0, 0, message, nil)
+ else
+ raise Psych::SyntaxError, message
+ end
+ end
+
+ def skip_blank_and_comments
+ while @lines.any?
+ line = @lines[0]
+ stripped = line.lstrip
+ break unless stripped.empty? || stripped.start_with?("#")
+ @lines.shift
+ end
+ end
+
+ def strip_comment(val)
+ return val unless val.include?("#")
+ return val if val.lstrip.start_with?("#")
+
+ in_single = false
+ in_double = false
+ escape = false
+
+ val.each_char.with_index do |ch, i|
+ if escape
+ escape = false
+ next
+ end
+
+ if in_single
+ in_single = false if ch == "'"
+ elsif in_double
+ if ch == "\\"
+ escape = true
+ elsif ch == '"'
+ in_double = false
+ end
+ else
+ case ch
+ when "'" then in_single = true
+ when '"' then in_double = true
+ when "#" then return val[0...i].rstrip
+ end
+ end
+ end
+
val
end
end
- class << self
- private :dump_hash
+ class Builder
+ VALID_OPS = %w[= != > < >= <= ~>].freeze
+ ARRAY_FIELDS = %w[files test_files executables extra_rdoc_files].freeze
+ MAX_ALIAS_RESOLUTIONS = 1_000
+
+ def initialize(permitted_classes: [], permitted_symbols: [], aliases: true)
+ @permitted_classes = permitted_classes.map {|c| "!ruby/object:#{c}" }
+ @permitted_symbols = permitted_symbols
+ @aliases = aliases
+ @anchor_values = {}
+ @alias_count = 0
+ end
+
+ def build(node)
+ return nil if node.nil?
+
+ result = build_node(node)
+
+ if result.is_a?(Hash) && result[:tag] == "!ruby/object:Gem::Specification"
+ build_specification(result)
+ else
+ result
+ end
+ end
+
+ private
+
+ def build_node(node)
+ case node
+ when nil then nil
+ when AliasRef then resolve_alias(node)
+ when Scalar then store_anchor(node.anchor, node.value)
+ when Mapping then build_mapping(node)
+ when Sequence then store_anchor(node.anchor, node.items.map {|item| build_node(item) })
+ else node # already a Ruby object
+ end
+ end
+
+ def resolve_alias(node)
+ raise Psych::AliasesNotEnabled unless @aliases
+ @alias_count += 1
+ if @alias_count > MAX_ALIAS_RESOLUTIONS
+ raise Psych::BadAlias, "exceeded maximum alias resolutions (#{MAX_ALIAS_RESOLUTIONS})"
+ end
+ unless @anchor_values.key?(node.name)
+ klass = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias
+ raise klass, "An alias referenced an unknown anchor: #{node.name}"
+ end
+ @anchor_values.fetch(node.name)
+ end
+
+ def store_anchor(name, value)
+ @anchor_values[name] = value if name
+ value
+ end
+
+ def build_mapping(node)
+ validate_tag!(node.tag) if node.tag
+
+ result = case node.tag
+ when "!ruby/object:Gem::Version"
+ build_version(node)
+ when "!ruby/object:Gem::Platform"
+ build_platform(node)
+ when "!ruby/object:Gem::Requirement", "!ruby/object:Gem::Version::Requirement"
+ build_requirement(node)
+ when "!ruby/object:Gem::Dependency"
+ build_dependency(node)
+ when nil
+ build_hash(node)
+ when "!ruby/object:Gem::Specification"
+ hash = build_hash(node)
+ hash[:tag] = node.tag
+ hash
+ else
+ raise ArgumentError, "undefined class/module #{node.tag.sub("!ruby/object:", "")}"
+ end
+
+ store_anchor(node.anchor, result)
+ end
+
+ def build_hash(node)
+ result = {}
+ node.pairs.each do |key_node, value_node|
+ key = key_node.is_a?(Scalar) ? key_node.value.to_s : build_node(key_node).to_s
+ value = build_node(value_node)
+
+ if ARRAY_FIELDS.include?(key)
+ value = normalize_array_field(value)
+ end
+
+ result[key] = value
+ end
+ result
+ end
+
+ def build_version(node)
+ hash = pairs_to_hash(node)
+ Gem::Version.new((hash["version"] || hash["value"]).to_s)
+ end
+
+ PLATFORM_FIELDS = %w[cpu os version].freeze
+ PLATFORM_ALLOWED_IVARS = %w[cpu os version value].freeze
+
+ def build_platform(node)
+ hash = pairs_to_hash(node)
+ if (hash.keys & PLATFORM_FIELDS).any?
+ Gem::Platform.new([hash["cpu"], hash["os"], hash["version"]])
+ elsif hash["value"].is_a?(Array)
+ # Malformed platform (e.g. sequence instead of mapping).
+ # Return the raw value so yaml_initialize handles it like Psych does.
+ hash["value"]
+ else
+ plat = Gem::Platform.allocate
+ hash.each do |k, v|
+ plat.instance_variable_set(:"@#{k}", v) if PLATFORM_ALLOWED_IVARS.include?(k)
+ end
+ plat
+ end
+ end
+
+ def build_requirement(node)
+ r = Gem::Requirement.allocate
+ hash = pairs_to_hash(node)
+ reqs = hash["requirements"] || hash["value"]
+
+ if reqs.is_a?(Array) && !reqs.empty?
+ safe_reqs = []
+ reqs.each do |item|
+ if item.is_a?(Array) && item.size == 2
+ op = item[0].to_s
+ ver = item[1]
+ if VALID_OPS.include?(op)
+ version_obj = ver.is_a?(Gem::Version) ? ver : Gem::Version.new(ver.to_s)
+ safe_reqs << [op, version_obj]
+ end
+ elsif item.is_a?(String)
+ parsed = Gem::Requirement.parse(item)
+ safe_reqs << parsed
+ end
+ rescue Gem::Requirement::BadRequirementError, Gem::Version::BadVersionError
+ # Skip malformed items silently
+ end
+ reqs = safe_reqs unless safe_reqs.empty?
+ end
+
+ r.instance_variable_set(:@requirements, reqs)
+ r
+ end
+
+ def build_dependency(node)
+ hash = pairs_to_hash(node)
+ d = Gem::Dependency.allocate
+ d.instance_variable_set(:@name, hash["name"])
+
+ d.instance_variable_set(:@requirement, hash["requirement"] || hash["version_requirements"])
+
+ raw_type = hash["type"]
+ if raw_type
+ name = raw_type.to_s.sub(/^:/, "")
+ validate_symbol!(name)
+ type = name.to_sym
+ else
+ type = :runtime
+ end
+ d.instance_variable_set(:@type, type)
+
+ d.instance_variable_set(:@prerelease, ["true", true].include?(hash["prerelease"]))
+ d.instance_variable_set(:@version_requirements, d.instance_variable_get(:@requirement))
+ d
+ end
+
+ def build_specification(hash)
+ spec = Gem::Specification.allocate
+
+ normalize_specification_version!(hash)
+ normalize_array_fields!(hash)
+
+ spec.yaml_initialize("!ruby/object:Gem::Specification", hash)
+ spec
+ end
+
+ def pairs_to_hash(node)
+ result = {}
+ node.pairs.each do |key_node, value_node|
+ key = key_node.is_a?(Scalar) ? key_node.value.to_s : build_node(key_node).to_s
+ result[key] = build_node(value_node)
+ end
+ result
+ end
+
+ def validate_tag!(tag)
+ return if @permitted_classes.include?(tag)
+ raise_disallowed_class!(tag)
+ end
+
+ def raise_disallowed_class!(tag)
+ if defined?(Psych::VERSION)
+ raise Psych::DisallowedClass.new("load", tag)
+ else
+ raise Psych::DisallowedClass, "Tried to load unspecified class: #{tag}"
+ end
+ end
+
+ def validate_symbol!(name)
+ return if @permitted_symbols.empty? || @permitted_symbols.include?(name)
+
+ label = ":#{name}"
+ if defined?(Psych::VERSION)
+ raise Psych::DisallowedClass.new("load", label)
+ else
+ raise Psych::DisallowedClass, "Tried to load unspecified class: #{label}"
+ end
+ end
+
+ def normalize_specification_version!(hash)
+ val = hash["specification_version"]
+ return unless val && !val.is_a?(Integer)
+ hash["specification_version"] = val.to_i if val.is_a?(String) && /\A\d+\z/.match?(val)
+ end
+
+ def normalize_array_fields!(hash)
+ ARRAY_FIELDS.each do |field|
+ hash[field] = normalize_array_field(hash[field]) if hash[field]
+ end
+ end
+
+ def normalize_array_field(value)
+ if value.is_a?(Hash)
+ value.values.flatten.compact
+ elsif !value.is_a?(Array) && value
+ [value].flatten.compact
+ else
+ value
+ end
+ end
+ end
+
+ class Emitter
+ def emit(obj)
+ "---#{emit_node(obj, 0)}"
+ end
+
+ private
+
+ def emit_node(obj, indent, quote: false)
+ case obj
+ when Gem::Specification then emit_specification(obj, indent)
+ when Gem::Version then emit_version(obj, indent)
+ when Gem::Platform then emit_platform(obj, indent)
+ when Gem::Requirement then emit_requirement(obj, indent)
+ when Gem::Dependency then emit_dependency(obj, indent)
+ when Hash then emit_hash(obj, indent)
+ when Array then emit_array(obj, indent)
+ when Time then emit_time(obj)
+ when String then emit_string(obj, indent, quote: quote)
+ when NilClass
+ "\n"
+ when Numeric, Symbol, TrueClass, FalseClass
+ " #{obj.inspect}\n"
+ else
+ " #{obj.to_s.inspect}\n"
+ end
+ end
+
+ def emit_specification(spec, indent)
+ parts = [" !ruby/object:Gem::Specification\n"]
+ parts << "#{pad(indent)}name:#{emit_node(spec.name, indent + 2)}"
+ parts << "#{pad(indent)}version:#{emit_node(spec.version, indent + 2)}"
+ parts << "#{pad(indent)}platform: #{spec.platform}\n"
+ if spec.platform.to_s != spec.original_platform.to_s
+ parts << "#{pad(indent)}original_platform: #{spec.original_platform}\n"
+ end
+
+ attributes = Gem::Specification.attribute_names.map(&:to_s).sort - %w[name version platform]
+ attributes.each do |name|
+ val = spec.instance_variable_get("@#{name}")
+ next if val.nil?
+ parts << "#{pad(indent)}#{name}:#{emit_node(val, indent + 2)}"
+ end
+
+ res = parts.join
+ res << "\n" unless res.end_with?("\n")
+ res
+ end
+
+ def emit_version(ver, indent)
+ " !ruby/object:Gem::Version\n" \
+ "#{pad(indent)}version: #{emit_node(ver.version.to_s, indent + 2).lstrip}"
+ end
+
+ def emit_platform(plat, indent)
+ " !ruby/object:Gem::Platform\n" \
+ "#{pad(indent)}cpu:#{emit_node(plat.cpu, indent + 2)}" \
+ "#{pad(indent)}os:#{emit_node(plat.os, indent + 2)}" \
+ "#{pad(indent)}version:#{emit_node(plat.version, indent + 2)}"
+ end
+
+ def emit_requirement(req, indent)
+ " !ruby/object:Gem::Requirement\n" \
+ "#{pad(indent)}requirements:#{emit_node(req.requirements, indent + 2)}"
+ end
+
+ def emit_dependency(dep, indent)
+ [
+ " !ruby/object:Gem::Dependency\n",
+ "#{pad(indent)}name: #{emit_node(dep.name, indent + 2).lstrip}",
+ "#{pad(indent)}requirement:#{emit_node(dep.requirement, indent + 2)}",
+ "#{pad(indent)}type: #{emit_node(dep.type, indent + 2).lstrip}",
+ "#{pad(indent)}prerelease: #{emit_node(dep.prerelease?, indent + 2).lstrip}",
+ "#{pad(indent)}version_requirements:#{emit_node(dep.requirement, indent + 2)}",
+ ].join
+ end
+
+ def emit_hash(hash, indent)
+ if hash.empty?
+ " {}\n"
+ else
+ parts = ["\n"]
+ hash.each do |k, v|
+ is_symbol = k.is_a?(Symbol) || (k.is_a?(String) && k.start_with?(":"))
+ key_str = k.is_a?(Symbol) ? k.inspect : k.to_s
+ parts << "#{pad(indent)}#{key_str}:#{emit_node(v, indent + 2, quote: is_symbol)}"
+ end
+ parts.join
+ end
+ end
+
+ def emit_array(arr, indent)
+ if arr.empty?
+ " []\n"
+ else
+ parts = ["\n"]
+ arr.each do |v|
+ parts << "#{pad(indent)}-#{emit_node(v, indent + 2)}"
+ end
+ parts.join
+ end
+ end
+
+ def emit_time(time)
+ " #{time.utc.strftime("%Y-%m-%d %H:%M:%S.%N Z")}\n"
+ end
+
+ def emit_string(str, indent, quote: false)
+ if str.include?("\n")
+ emit_block_scalar(str, indent)
+ elsif needs_quoting?(str, quote)
+ " #{str.to_s.inspect}\n"
+ else
+ " #{str}\n"
+ end
+ end
+
+ def emit_block_scalar(str, indent)
+ parts = [str.end_with?("\n") ? " |\n" : " |-\n"]
+ str.each_line do |line|
+ parts << "#{pad(indent + 2)}#{line}"
+ end
+ res = parts.join
+ res << "\n" unless res.end_with?("\n")
+ res
+ end
+
+ def needs_quoting?(str, quote)
+ quote || str.empty? ||
+ str =~ /^[!*&:@%$]/ || str =~ /^-?\d+(\.\d+)?$/ || str =~ /^[<>=-]/ ||
+ str == "true" || str == "false" || str == "nil" ||
+ str.include?(":") || str.include?("#") || str.include?("[") || str.include?("]") ||
+ str.include?("{") || str.include?("}") || str.include?(",")
+ end
+
+ def pad(indent)
+ " " * indent
+ end
+ end
+
+ module_function
+
+ def dump(obj)
+ Emitter.new.emit(obj)
+ end
+
+ def load(str, permitted_classes: [], permitted_symbols: [], aliases: true)
+ raise TypeError, "no implicit conversion of nil into String" if str.nil?
+ return nil if str.empty?
+
+ ast = Parser.new(str).parse
+ return nil if ast.nil?
+
+ Builder.new(
+ permitted_classes: permitted_classes,
+ permitted_symbols: permitted_symbols,
+ aliases: aliases
+ ).build(ast)
end
end
end
diff --git a/lib/set.rb b/lib/set.rb
deleted file mode 100644
index 26311af6cc..0000000000
--- a/lib/set.rb
+++ /dev/null
@@ -1,855 +0,0 @@
-# frozen_string_literal: true
-# :markup: markdown
-#
-# set.rb - defines the Set class
-#
-# Copyright (c) 2002-2024 Akinori MUSHA <knu@iDaemons.org>
-#
-# Documentation by Akinori MUSHA and Gavin Sinclair.
-#
-# All rights reserved. You can redistribute and/or modify it under the same
-# terms as Ruby.
-
-
-##
-# This library provides the Set class, which implements 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 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
-# can be converted to Set using the `to_set` method.
-#
-# Set uses Hash as storage, so you must note the following points:
-#
-# * Equality of elements is determined according to Object#eql? and
-# Object#hash. Use Set#compare_by_identity to make a set compare
-# its elements by their identity.
-# * Set assumes that the identity of each element does not change
-# while it is stored. Modifying an element of a set will render the
-# set to an unreliable state.
-# * When a string is to be stored, a frozen copy of the string is
-# stored instead unless the original string is already frozen.
-#
-# ## Comparison
-#
-# The comparison operators `<`, `>`, `<=`, and `>=` are implemented as
-# shorthand for the {proper_,}{subset?,superset?} methods. The `<=>`
-# operator reflects this order, or return `nil` for sets that both
-# have distinct elements (`{x, y}` vs. `{x, z}` for example).
-#
-# ## Example
-#
-# ```ruby
-# require 'set'
-# s1 = Set[1, 2] #=> #<Set: {1, 2}>
-# s2 = [1, 2].to_set #=> #<Set: {1, 2}>
-# s1 == s2 #=> true
-# s1.add("foo") #=> #<Set: {1, 2, "foo"}>
-# s1.merge([2, 6]) #=> #<Set: {1, 2, "foo", 6}>
-# s1.subset?(s2) #=> false
-# s2.subset?(s1) #=> true
-# ```
-#
-# ## Contact
-#
-# - Akinori MUSHA <<knu@iDaemons.org>> (current maintainer)
-#
-# ## What's Here
-#
-# First, what's elsewhere. \Class \Set:
-#
-# - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
-# - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
-# which provides dozens of additional methods.
-#
-# In particular, class \Set does not have many methods of its own
-# for fetching or for iterating.
-# Instead, it relies on those in \Enumerable.
-#
-# Here, class \Set provides methods that are useful for:
-#
-# - [Creating a Set](#class-Set-label-Methods+for+Creating+a+Set)
-# - [Set Operations](#class-Set-label-Methods+for+Set+Operations)
-# - [Comparing](#class-Set-label-Methods+for+Comparing)
-# - [Querying](#class-Set-label-Methods+for+Querying)
-# - [Assigning](#class-Set-label-Methods+for+Assigning)
-# - [Deleting](#class-Set-label-Methods+for+Deleting)
-# - [Converting](#class-Set-label-Methods+for+Converting)
-# - [Iterating](#class-Set-label-Methods+for+Iterating)
-# - [And more....](#class-Set-label-Other+Methods)
-#
-# ### Methods for Creating a \Set
-#
-# - ::[]:
-# Returns a new set containing the given objects.
-# - ::new:
-# Returns a new set containing either the given objects
-# (if no block given) or the return values from the called block
-# (if a block given).
-#
-# ### Methods for \Set Operations
-#
-# - [|](#method-i-7C) (aliased as #union and #+):
-# Returns a new set containing all elements from +self+
-# and all elements from a given enumerable (no duplicates).
-# - [&](#method-i-26) (aliased as #intersection):
-# Returns a new set containing all elements common to +self+
-# and a given enumerable.
-# - [-](#method-i-2D) (aliased as #difference):
-# Returns a copy of +self+ with all elements
-# in a given enumerable removed.
-# - [\^](#method-i-5E):
-# Returns a new set containing all elements from +self+
-# and a given enumerable except those common to both.
-#
-# ### Methods for Comparing
-#
-# - [<=>](#method-i-3C-3D-3E):
-# Returns -1, 0, or 1 as +self+ is less than, equal to,
-# or greater than a given object.
-# - [==](#method-i-3D-3D):
-# Returns whether +self+ and a given enumerable are equal,
-# as determined by Object#eql?.
-# - \#compare_by_identity?:
-# Returns whether the set considers only identity
-# when comparing elements.
-#
-# ### Methods for Querying
-#
-# - \#length (aliased as #size):
-# Returns the count of elements.
-# - \#empty?:
-# Returns whether the set has no elements.
-# - \#include? (aliased as #member? and #===):
-# Returns whether a given object is an element in the set.
-# - \#subset? (aliased as [<=](#method-i-3C-3D)):
-# Returns whether a given object is a subset of the set.
-# - \#proper_subset? (aliased as [<](#method-i-3C)):
-# Returns whether a given enumerable is a proper subset of the set.
-# - \#superset? (aliased as [>=](#method-i-3E-3D])):
-# Returns whether a given enumerable is a superset of the set.
-# - \#proper_superset? (aliased as [>](#method-i-3E)):
-# Returns whether a given enumerable is a proper superset of the set.
-# - \#disjoint?:
-# Returns +true+ if the set and a given enumerable
-# have no common elements, +false+ otherwise.
-# - \#intersect?:
-# Returns +true+ if the set and a given enumerable:
-# have any common elements, +false+ otherwise.
-# - \#compare_by_identity?:
-# Returns whether the set considers only identity
-# when comparing elements.
-#
-# ### Methods for Assigning
-#
-# - \#add (aliased as #<<):
-# Adds a given object to the set; returns +self+.
-# - \#add?:
-# 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+.
-# - \#replace:
-# Replaces the contents of the set with the contents
-# of a given enumerable.
-#
-# ### Methods for Deleting
-#
-# - \#clear:
-# Removes all elements in the set; returns +self+.
-# - \#delete:
-# Removes a given object from the set; returns +self+.
-# - \#delete?:
-# If the given object is an element in the set,
-# removes it and returns +self+; otherwise, returns +nil+.
-# - \#subtract:
-# Removes each given object from the set; returns +self+.
-# - \#delete_if - Removes elements specified by a given block.
-# - \#select! (aliased as #filter!):
-# Removes elements not specified by a given block.
-# - \#keep_if:
-# Removes elements not specified by a given block.
-# - \#reject!
-# Removes elements specified by a given block.
-#
-# ### Methods for Converting
-#
-# - \#classify:
-# Returns a hash that classifies the elements,
-# as determined by the given block.
-# - \#collect! (aliased as #map!):
-# Replaces each element with a block return-value.
-# - \#divide:
-# Returns a hash that classifies the elements,
-# as determined by the given block;
-# differs from #classify in that the block may accept
-# either one or two arguments.
-# - \#flatten:
-# Returns a new set that is a recursive flattening of +self+.
-# \#flatten!:
-# Replaces each nested set in +self+ with the elements from that set.
-# - \#inspect (aliased as #to_s):
-# Returns a string displaying the elements.
-# - \#join:
-# Returns a string containing all elements, converted to strings
-# as needed, and joined by the given record separator.
-# - \#to_a:
-# Returns an array containing all set elements.
-# - \#to_set:
-# Returns +self+ if given no arguments and no block;
-# with a block given, returns a new set consisting of block
-# return values.
-#
-# ### Methods for Iterating
-#
-# - \#each:
-# Calls the block with each successive element; returns +self+.
-#
-# ### Other Methods
-#
-# - \#reset:
-# Resets the internal state; useful if an object
-# has been modified while an element in the set.
-#
-class Set
- VERSION = "1.1.1"
-
- include Enumerable
-
- # Creates a new set containing the given objects.
- #
- # Set[1, 2] # => #<Set: {1, 2}>
- # Set[1, 2, 1] # => #<Set: {1, 2}>
- # Set[1, 'c', :s] # => #<Set: {1, "c", :s}>
- def self.[](*ary)
- new(ary)
- end
-
- # Creates a new set containing the elements of the given enumerable
- # object.
- #
- # If a block is given, the elements of enum are preprocessed by the
- # given block.
- #
- # Set.new([1, 2]) #=> #<Set: {1, 2}>
- # Set.new([1, 2, 1]) #=> #<Set: {1, 2}>
- # Set.new([1, 'c', :s]) #=> #<Set: {1, "c", :s}>
- # Set.new(1..5) #=> #<Set: {1, 2, 3, 4, 5}>
- # Set.new([1, 2, 3]) { |x| x * x } #=> #<Set: {1, 4, 9}>
- def initialize(enum = nil, &block) # :yields: o
- @hash ||= Hash.new(false)
-
- enum.nil? and return
-
- if block
- do_with_enum(enum) { |o| add(block[o]) }
- else
- merge(enum)
- end
- end
-
- # Makes the set compare its elements by their identity and returns
- # self. This method may not be supported by all subclasses of Set.
- def compare_by_identity
- if @hash.respond_to?(:compare_by_identity)
- @hash.compare_by_identity
- self
- else
- raise NotImplementedError, "#{self.class.name}\##{__method__} is not implemented"
- end
- end
-
- # Returns true if the set will compare its elements by their
- # identity. Also see Set#compare_by_identity.
- def compare_by_identity?
- @hash.respond_to?(:compare_by_identity?) && @hash.compare_by_identity?
- end
-
- def do_with_enum(enum, &block) # :nodoc:
- if enum.respond_to?(:each_entry)
- enum.each_entry(&block) if block
- elsif enum.respond_to?(:each)
- enum.each(&block) if block
- else
- raise ArgumentError, "value must be enumerable"
- end
- end
- private :do_with_enum
-
- # Dup internal hash.
- def initialize_dup(orig)
- super
- @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)
- end
-
- def freeze # :nodoc:
- @hash.freeze
- super
- end
-
- # Returns the number of elements.
- def size
- @hash.size
- end
- alias length size
-
- # Returns true if the set contains no elements.
- def empty?
- @hash.empty?
- end
-
- # Removes all elements and returns self.
- #
- # set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}>
- # set.clear #=> #<Set: {}>
- # set #=> #<Set: {}>
- def clear
- @hash.clear
- self
- end
-
- # Replaces the contents of the set with the contents of the given
- # enumerable object and returns self.
- #
- # set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}>
- # set.replace([1, 2]) #=> #<Set: {1, 2}>
- # set #=> #<Set: {1, 2}>
- def replace(enum)
- if enum.instance_of?(self.class)
- @hash.replace(enum.instance_variable_get(:@hash))
- self
- else
- do_with_enum(enum) # make sure enum is enumerable before calling clear
- clear
- merge(enum)
- end
- end
-
- # Returns an array containing all elements in the set.
- #
- # Set[1, 2].to_a #=> [1, 2]
- # Set[1, 'c', :s].to_a #=> [1, "c", :s]
- def to_a
- @hash.keys
- end
-
- # Returns self if no arguments are given. Otherwise, converts the
- # set to another with `klass.new(self, *args, &block)`.
- #
- # In subclasses, returns `klass.new(self, *args, &block)` unless
- # overridden.
- def to_set(klass = Set, *args, &block)
- return self if instance_of?(Set) && klass == Set && block.nil? && args.empty?
- klass.new(self, *args, &block)
- end
-
- def flatten_merge(set, seen = {}) # :nodoc:
- set.each { |e|
- if e.is_a?(Set)
- case seen[e_id = e.object_id]
- when true
- raise ArgumentError, "tried to flatten recursive Set"
- when false
- next
- end
-
- seen[e_id] = true
- flatten_merge(e, seen)
- seen[e_id] = false
- else
- add(e)
- end
- }
-
- self
- end
- protected :flatten_merge
-
- # Returns a new set that is a copy of the set, flattening each
- # containing set recursively.
- def flatten
- self.class.new.flatten_merge(self)
- end
-
- # 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)
- end
-
- # Returns true if the set contains the given object.
- #
- # Note that <code>include?</code> and <code>member?</code> do not test member
- # equality using <code>==</code> as do other Enumerables.
- #
- # See also Enumerable#include?
- def include?(o)
- @hash[o]
- end
- alias member? include?
-
- # Returns true if the set is a superset of the given set.
- def superset?(set)
- case
- 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)
- else
- raise ArgumentError, "value must be a set"
- end
- end
- alias >= superset?
-
- # Returns true if the set is a proper superset of the given set.
- def proper_superset?(set)
- case
- 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)
- else
- raise ArgumentError, "value must be a set"
- end
- end
- alias > proper_superset?
-
- # Returns true if the set is a subset of the given set.
- def subset?(set)
- case
- 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)
- else
- raise ArgumentError, "value must be a set"
- end
- end
- alias <= subset?
-
- # Returns true if the set is a proper subset of the given set.
- def proper_subset?(set)
- case
- 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)
- else
- raise ArgumentError, "value must be a set"
- end
- end
- alias < proper_subset?
-
- # Returns 0 if the set are equal,
- # -1 / +1 if the set is a proper subset / superset of the given set,
- # or nil if they both have unique elements.
- def <=>(set)
- return unless set.is_a?(Set)
-
- case size <=> set.size
- when -1 then -1 if proper_subset?(set)
- when +1 then +1 if proper_superset?(set)
- else 0 if self.==(set)
- end
- end
-
- # Returns true if the set and the given enumerable have at least one
- # element in common.
- #
- # Set[1, 2, 3].intersect? Set[4, 5] #=> false
- # Set[1, 2, 3].intersect? Set[3, 4] #=> true
- # Set[1, 2, 3].intersect? 4..5 #=> false
- # Set[1, 2, 3].intersect? [3, 4] #=> true
- def intersect?(set)
- case set
- when Set
- if size < set.size
- any?(set)
- else
- set.any?(self)
- end
- when Enumerable
- set.any?(self)
- else
- raise ArgumentError, "value must be enumerable"
- end
- end
-
- # Returns true if the set and the given enumerable have
- # no element in common. This method is the opposite of `intersect?`.
- #
- # Set[1, 2, 3].disjoint? Set[3, 4] #=> false
- # Set[1, 2, 3].disjoint? Set[4, 5] #=> true
- # Set[1, 2, 3].disjoint? [3, 4] #=> false
- # Set[1, 2, 3].disjoint? 4..5 #=> true
- def disjoint?(set)
- !intersect?(set)
- end
-
- # Calls the given block once for each element in the set, passing
- # the element as parameter. Returns an enumerator if no block is
- # given.
- def each(&block)
- block_given? or return enum_for(__method__) { size }
- @hash.each_key(&block)
- self
- end
-
- # Adds the given object to the set and returns self. Use `merge` to
- # add many elements at once.
- #
- # Set[1, 2].add(3) #=> #<Set: {1, 2, 3}>
- # Set[1, 2].add([3, 4]) #=> #<Set: {1, 2, [3, 4]}>
- # Set[1, 2].add(2) #=> #<Set: {1, 2}>
- def add(o)
- @hash[o] = true
- self
- end
- alias << add
-
- # Adds the given object to the set and returns self. If the
- # object is already in the set, returns nil.
- #
- # Set[1, 2].add?(3) #=> #<Set: {1, 2, 3}>
- # Set[1, 2].add?([3, 4]) #=> #<Set: {1, 2, [3, 4]}>
- # Set[1, 2].add?(2) #=> nil
- def add?(o)
- add(o) unless include?(o)
- end
-
- # Deletes the given object from the set and returns self. Use
- # `subtract` to delete many items at once.
- def delete(o)
- @hash.delete(o)
- self
- end
-
- # Deletes the given object from the set and returns self. If the
- # object is not in the set, returns nil.
- def delete?(o)
- delete(o) if include?(o)
- end
-
- # Deletes every element of the set for which block evaluates to
- # true, and returns self. Returns an enumerator if no block is
- # given.
- def delete_if(&block)
- block_given? or return enum_for(__method__) { size }
- # Instead of directly using @hash.delete_if, perform enumeration
- # using self.each that subclasses may override.
- select(&block).each { |o| @hash.delete(o) }
- self
- end
-
- # Deletes every element of the set for which block evaluates to
- # false, and returns self. Returns an enumerator if no block is
- # given.
- def keep_if(&block)
- block_given? or return enum_for(__method__) { size }
- # Instead of directly using @hash.keep_if, perform enumeration
- # using self.each that subclasses may override.
- reject(&block).each { |o| @hash.delete(o) }
- self
- end
-
- # Replaces the elements with ones returned by `collect()`.
- # Returns an enumerator if no block is given.
- def collect!
- block_given? or return enum_for(__method__) { size }
- set = self.class.new
- each { |o| set << yield(o) }
- replace(set)
- end
- alias map! collect!
-
- # 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 }
- n = size
- delete_if(&block)
- self if size != n
- end
-
- # 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 }
- n = size
- keep_if(&block)
- self if size != n
- end
-
- # Equivalent to Set#select!
- alias filter! select!
-
- # Merges the elements of the given enumerable objects 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
- end
-
- self
- end
-
- # Deletes every element that appears in the given enumerable object
- # and returns self.
- def subtract(enum)
- do_with_enum(enum) { |o| delete(o) }
- self
- end
-
- # Returns a new set built by merging the set and the elements of the
- # given enumerable object.
- #
- # Set[1, 2, 3] | Set[2, 4, 5] #=> #<Set: {1, 2, 3, 4, 5}>
- # Set[1, 5, 'z'] | (1..6) #=> #<Set: {1, 5, "z", 2, 3, 4, 6}>
- def |(enum)
- dup.merge(enum)
- end
- alias + |
- alias union |
-
- # Returns a new set built by duplicating the set, removing every
- # element that appears in the given enumerable object.
- #
- # Set[1, 3, 5] - Set[1, 5] #=> #<Set: {3}>
- # Set['a', 'b', 'z'] - ['a', 'c'] #=> #<Set: {"b", "z"}>
- def -(enum)
- dup.subtract(enum)
- end
- alias difference -
-
- # Returns a new set containing elements common to the set and the
- # given enumerable object.
- #
- # Set[1, 3, 5] & Set[3, 2, 1] #=> #<Set: {3, 1}>
- # Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> #<Set: {"a", "b"}>
- def &(enum)
- n = self.class.new
- if enum.is_a?(Set)
- if enum.size > size
- each { |o| n.add(o) if enum.include?(o) }
- else
- enum.each { |o| n.add(o) if include?(o) }
- end
- else
- do_with_enum(enum) { |o| n.add(o) if include?(o) }
- end
- n
- end
- alias intersection &
-
- # Returns a new set containing elements exclusive between the set
- # and the given enumerable object. `(set ^ enum)` is equivalent to
- # `((set | enum) - (set & enum))`.
- #
- # Set[1, 2] ^ Set[2, 3] #=> #<Set: {3, 1}>
- # Set[1, 'b', 'c'] ^ ['b', 'd'] #=> #<Set: {"d", 1, "c"}>
- def ^(enum)
- n = self.class.new(enum)
- each { |o| n.add(o) unless n.delete?(o) }
- n
- end
-
- # Returns true if two sets are equal. The equality of each couple
- # of elements is defined according to Object#eql?.
- #
- # Set[1, 2] == Set[2, 1] #=> true
- # Set[1, 3, 5] == Set[1, 5] #=> false
- # Set['a', 'b', 'c'] == Set['a', 'c', 'b'] #=> true
- # Set['a', 'b', 'c'] == ['a', 'c', 'b'] #=> false
- def ==(other)
- if self.equal?(other)
- true
- elsif other.instance_of?(self.class)
- @hash == other.instance_variable_get(:@hash)
- elsif other.is_a?(Set) && self.size == other.size
- other.all? { |o| @hash.include?(o) }
- else
- false
- end
- end
-
- def hash # :nodoc:
- @hash.hash
- end
-
- def eql?(o) # :nodoc:
- return false unless o.is_a?(Set)
- @hash.eql?(o.instance_variable_get(:@hash))
- end
-
- # Resets the internal state after modification to existing elements
- # and returns self.
- #
- # Elements will be reindexed and deduplicated.
- def reset
- if @hash.respond_to?(:rehash)
- @hash.rehash # This should perform frozenness check.
- else
- raise FrozenError, "can't modify frozen #{self.class.name}" if frozen?
- end
- self
- end
-
- # Returns true if the given object is a member of the set,
- # and false otherwise.
- #
- # Used in case statements:
- #
- # require 'set'
- #
- # case :apple
- # when Set[:potato, :carrot]
- # "vegetable"
- # when Set[:apple, :banana]
- # "fruit"
- # end
- # # => "fruit"
- #
- # Or by itself:
- #
- # Set[1, 2, 3] === 2 #=> true
- # Set[1, 2, 3] === 4 #=> false
- #
- alias === include?
-
- # Classifies the set by the return value of the given block and
- # returns a hash of {value => set of elements} pairs. The block is
- # called once for each element of the set, passing the element as
- # parameter.
- #
- # require 'set'
- # files = Set.new(Dir.glob("*.rb"))
- # hash = files.classify { |f| File.mtime(f).year }
- # hash #=> {2000=>#<Set: {"a.rb", "b.rb"}>,
- # # 2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>,
- # # 2002=>#<Set: {"f.rb"}>}
- #
- # Returns an enumerator if no block is given.
- def classify # :yields: o
- block_given? or return enum_for(__method__) { size }
-
- h = {}
-
- each { |i|
- (h[yield(i)] ||= self.class.new).add(i)
- }
-
- h
- end
-
- # Divides the set into a set of subsets according to the commonality
- # defined by the given block.
- #
- # If the arity of the block is 2, elements o1 and o2 are in common
- # if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are
- # in common if block.call(o1) == block.call(o2).
- #
- # require 'set'
- # numbers = Set[1, 3, 4, 6, 9, 10, 11]
- # set = numbers.divide { |i,j| (i - j).abs == 1 }
- # set #=> #<Set: {#<Set: {1}>,
- # # #<Set: {11, 9, 10}>,
- # # #<Set: {3, 4}>,
- # # #<Set: {6}>}>
- #
- # Returns an enumerator if no block is given.
- def divide(&func)
- func or return enum_for(__method__) { size }
-
- if func.arity == 2
- require 'tsort'
-
- class << dig = {} # :nodoc:
- include TSort
-
- alias tsort_each_node each_key
- def tsort_each_child(node, &block)
- fetch(node).each(&block)
- end
- end
-
- each { |u|
- dig[u] = a = []
- each{ |v| func.call(u, v) and a << v }
- }
-
- set = Set.new()
- dig.each_strongly_connected_component { |css|
- set.add(self.class.new(css))
- }
- set
- else
- Set.new(classify(&func).values)
- end
- end
-
- # Returns a string created by converting each element of the set to a string
- # See also: Array#join
- def join(separator=nil)
- to_a.join(separator)
- end
-
- InspectKey = :__inspect_key__ # :nodoc:
-
- # Returns a string containing a human-readable representation of the
- # set ("#<Set: {element1, element2, ...}>").
- def inspect
- ids = (Thread.current[InspectKey] ||= [])
-
- if ids.include?(object_id)
- return sprintf('#<%s: {...}>', self.class.name)
- end
-
- ids << object_id
- begin
- return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
- ensure
- ids.pop
- end
- end
-
- alias to_s inspect
-
- def pretty_print(pp) # :nodoc:
- pp.group(1, sprintf('#<%s:', self.class.name), '>') {
- pp.breakable
- pp.group(1, '{', '}') {
- pp.seplist(self) { |o|
- pp.pp o
- }
- }
- }
- end
-
- def pretty_print_cycle(pp) # :nodoc:
- pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
- end
-end
-
-module Enumerable
- # Makes a set from the enumerable object with given arguments.
- # Needs to `require "set"` to use this method.
- def to_set(klass = Set, *args, &block)
- klass.new(self, *args, &block)
- end unless method_defined?(:to_set)
-end
-
-autoload :SortedSet, "#{__dir__}/set/sorted_set"
diff --git a/lib/set/set.gemspec b/lib/set/set.gemspec
deleted file mode 100644
index 2ebef6985d..0000000000
--- a/lib/set/set.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 = ["Akinori MUSHA"]
- spec.email = ["knu@idaemons.org"]
-
- spec.summary = %q{Provides a class to deal with collections of unordered, unique values}
- 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.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
- spec.metadata["changelog_uri"] = "https://github.com/ruby/set/blob/v#{spec.version}/CHANGELOG.md"
-
- # 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`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.require_paths = ["lib"]
-end
diff --git a/lib/set/sorted_set.rb b/lib/set/sorted_set.rb
deleted file mode 100644
index bc07bc1fb0..0000000000
--- a/lib/set/sorted_set.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-begin
- require 'sorted_set'
-rescue ::LoadError
- raise "The `SortedSet` class has been extracted from the `set` library. " \
- "You must use the `sorted_set` gem or other alternatives."
-end
diff --git a/lib/set/subclass_compatible.rb b/lib/set/subclass_compatible.rb
new file mode 100644
index 0000000000..f43c34f6a2
--- /dev/null
+++ b/lib/set/subclass_compatible.rb
@@ -0,0 +1,347 @@
+# frozen_string_literal: true
+
+# :markup: markdown
+#
+# set/subclass_compatible.rb - Provides compatibility for set subclasses
+#
+# Copyright (c) 2002-2024 Akinori MUSHA <knu@iDaemons.org>
+#
+# Documentation by Akinori MUSHA and Gavin Sinclair.
+#
+# All rights reserved. You can redistribute and/or modify it under the same
+# terms as Ruby.
+
+
+class Set
+ # This module is automatically included in subclasses of Set, to
+ # make them backwards compatible with the pure-Ruby set implementation
+ # used before Ruby 4. Users who want to use Set subclasses without
+ # this compatibility layer should subclass from Set::CoreSet.
+ #
+ # Note that Set subclasses that access `@hash` are not compatible even
+ # with this support. Such subclasses must be updated to support Ruby 4.
+ module SubclassCompatible
+ module ClassMethods
+ def [](*ary)
+ new(ary)
+ end
+ end
+
+ # Creates a new set containing the elements of the given enumerable
+ # object.
+ #
+ # If a block is given, the elements of enum are preprocessed by the
+ # given block.
+ #
+ # Set.new([1, 2]) #=> #<Set: {1, 2}>
+ # Set.new([1, 2, 1]) #=> #<Set: {1, 2}>
+ # Set.new([1, 'c', :s]) #=> #<Set: {1, "c", :s}>
+ # Set.new(1..5) #=> #<Set: {1, 2, 3, 4, 5}>
+ # Set.new([1, 2, 3]) { |x| x * x } #=> #<Set: {1, 4, 9}>
+ def initialize(enum = nil, &block) # :yields: o
+ enum.nil? and return
+
+ if block
+ do_with_enum(enum) { |o| add(block[o]) }
+ else
+ merge(enum)
+ end
+ end
+
+ def do_with_enum(enum, &block) # :nodoc:
+ if enum.respond_to?(:each_entry)
+ enum.each_entry(&block) if block
+ elsif enum.respond_to?(:each)
+ enum.each(&block) if block
+ else
+ raise ArgumentError, "value must be enumerable"
+ end
+ end
+ private :do_with_enum
+
+ def replace(enum)
+ if enum.instance_of?(self.class)
+ super
+ else
+ do_with_enum(enum) # make sure enum is enumerable before calling clear
+ clear
+ merge(enum)
+ end
+ end
+
+ def to_set(&block)
+ return self if instance_of?(Set) && block.nil?
+ Set.new(self, &block)
+ end
+
+ def flatten_merge(set, seen = {}) # :nodoc:
+ set.each { |e|
+ if e.is_a?(Set)
+ case seen[e_id = e.object_id]
+ when true
+ raise ArgumentError, "tried to flatten recursive Set"
+ when false
+ next
+ end
+
+ seen[e_id] = true
+ flatten_merge(e, seen)
+ seen[e_id] = false
+ else
+ add(e)
+ end
+ }
+
+ self
+ end
+ protected :flatten_merge
+
+ def flatten
+ self.class.new.flatten_merge(self)
+ end
+
+ def flatten!
+ replace(flatten()) if any?(Set)
+ end
+
+ def superset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size >= set.size && set.all?(self)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias >= superset?
+
+ def proper_superset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size > set.size && set.all?(self)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias > proper_superset?
+
+ def subset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size <= set.size && all?(set)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias <= subset?
+
+ def proper_subset?(set)
+ case
+ when set.instance_of?(self.class)
+ super
+ when set.is_a?(Set)
+ size < set.size && all?(set)
+ else
+ raise ArgumentError, "value must be a set"
+ end
+ end
+ alias < proper_subset?
+
+ def <=>(set)
+ return unless set.is_a?(Set)
+
+ case size <=> set.size
+ when -1 then -1 if proper_subset?(set)
+ when +1 then +1 if proper_superset?(set)
+ else 0 if self.==(set)
+ end
+ end
+
+ def intersect?(set)
+ case set
+ when Set
+ if size < set.size
+ any?(set)
+ else
+ set.any?(self)
+ end
+ when Enumerable
+ set.any?(self)
+ else
+ raise ArgumentError, "value must be enumerable"
+ end
+ end
+
+ def disjoint?(set)
+ !intersect?(set)
+ end
+
+ def add?(o)
+ add(o) unless include?(o)
+ end
+
+ def delete?(o)
+ delete(o) if include?(o)
+ end
+
+ def delete_if(&block)
+ block_given? or return enum_for(__method__) { size }
+ select(&block).each { |o| delete(o) }
+ self
+ end
+
+ def keep_if(&block)
+ block_given? or return enum_for(__method__) { size }
+ reject(&block).each { |o| delete(o) }
+ self
+ end
+
+ def collect!
+ block_given? or return enum_for(__method__) { size }
+ set = self.class.new
+ each { |o| set << yield(o) }
+ replace(set)
+ end
+ alias map! collect!
+
+ def reject!(&block)
+ block_given? or return enum_for(__method__) { size }
+ n = size
+ delete_if(&block)
+ self if size != n
+ end
+
+ def select!(&block)
+ block_given? or return enum_for(__method__) { size }
+ n = size
+ keep_if(&block)
+ self if size != n
+ end
+
+ alias filter! select!
+
+ def merge(*enums, **nil)
+ enums.each do |enum|
+ if enum.instance_of?(self.class)
+ super(enum)
+ else
+ do_with_enum(enum) { |o| add(o) }
+ end
+ end
+
+ self
+ end
+
+ def subtract(enum)
+ do_with_enum(enum) { |o| delete(o) }
+ self
+ end
+
+ def |(enum)
+ dup.merge(enum)
+ end
+ alias + |
+ alias union |
+
+ def -(enum)
+ dup.subtract(enum)
+ end
+ alias difference -
+
+ def &(enum)
+ n = self.class.new
+ if enum.is_a?(Set)
+ if enum.size > size
+ each { |o| n.add(o) if enum.include?(o) }
+ else
+ enum.each { |o| n.add(o) if include?(o) }
+ end
+ else
+ do_with_enum(enum) { |o| n.add(o) if include?(o) }
+ end
+ n
+ end
+ alias intersection &
+
+ def ^(enum)
+ n = self.class.new(enum)
+ each { |o| n.add(o) unless n.delete?(o) }
+ n
+ end
+
+ def ==(other)
+ if self.equal?(other)
+ true
+ elsif other.instance_of?(self.class)
+ super
+ elsif other.is_a?(Set) && self.size == other.size
+ other.all? { |o| include?(o) }
+ else
+ false
+ end
+ end
+
+ def eql?(o) # :nodoc:
+ return false unless o.is_a?(Set)
+ super
+ end
+
+ def classify
+ block_given? or return enum_for(__method__) { size }
+
+ h = {}
+
+ each { |i|
+ (h[yield(i)] ||= self.class.new).add(i)
+ }
+
+ h
+ end
+
+ def join(separator=nil)
+ to_a.join(separator)
+ end
+
+ InspectKey = :__inspect_key__ # :nodoc:
+
+ # Returns a string containing a human-readable representation of the
+ # set ("#<Set: {element1, element2, ...}>").
+ def inspect
+ ids = (Thread.current[InspectKey] ||= [])
+
+ if ids.include?(object_id)
+ return sprintf('#<%s: {...}>', self.class.name)
+ end
+
+ ids << object_id
+ begin
+ return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
+ ensure
+ ids.pop
+ end
+ end
+
+ alias to_s inspect
+
+ def pretty_print(pp) # :nodoc:
+ pp.group(1, sprintf('#<%s:', self.class.name), '>') {
+ pp.breakable
+ pp.group(1, '{', '}') {
+ pp.seplist(self) { |o|
+ pp.pp o
+ }
+ }
+ }
+ end
+
+ def pretty_print_cycle(pp) # :nodoc:
+ pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
+ end
+ end
+ private_constant :SubclassCompatible
+end
diff --git a/lib/shellwords.gemspec b/lib/shellwords.gemspec
index 8d0c518ca5..b601508f94 100644
--- a/lib/shellwords.gemspec
+++ b/lib/shellwords.gemspec
@@ -25,7 +25,5 @@ Gem::Specification.new do |spec|
spec.files = Dir.chdir(srcdir) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:(?:test|spec|features)/|\.git|Rake)}) || f == gemspec_file}
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 b8e43a7794..74aec8903c 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -92,9 +92,10 @@
# p a.strip # => nil
#
module Singleton
+ # The version string
VERSION = "0.3.0"
- module SingletonInstanceMethods
+ module SingletonInstanceMethods # :nodoc:
# Raises a TypeError to prevent cloning.
def clone
raise TypeError, "can't clone instance of singleton #{self.class}"
@@ -143,11 +144,11 @@ module Singleton
end
end
- def self.module_with_class_methods
+ def self.module_with_class_methods # :nodoc:
SingletonClassMethods
end
- module SingletonClassProperties
+ module SingletonClassProperties # :nodoc:
def self.included(c)
# extending an object with Singleton is a bad idea
@@ -196,10 +197,10 @@ module Singleton
end
if defined?(Ractor)
- module RactorLocalSingleton
+ module RactorLocalSingleton # :nodoc:
include Singleton::SingletonInstanceMethods
- module RactorLocalSingletonClassMethods
+ module RactorLocalSingletonClassMethods # :nodoc:
include Singleton::SingletonClassMethods
def instance
set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil?
diff --git a/lib/syntax_suggest/api.rb b/lib/syntax_suggest/api.rb
index 46c9c8adac..5054efa888 100644
--- a/lib/syntax_suggest/api.rb
+++ b/lib/syntax_suggest/api.rb
@@ -7,25 +7,8 @@ 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 "prism"
module SyntaxSuggest
# Used to indicate a default value that cannot
@@ -35,14 +18,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
@@ -146,30 +121,17 @@ module SyntaxSuggest
def self.valid_without?(without_lines:, code_lines:)
lines = code_lines - Array(without_lines).flatten
- if lines.empty?
- true
- else
- valid?(lines)
- end
+ lines.empty? || valid?(lines)
end
# 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
+ Prism.parse(source).failure?
end
# SyntaxSuggest.valid? [Private]
@@ -223,7 +185,6 @@ require_relative "explain_syntax"
require_relative "clean_document"
# Helpers
-require_relative "lex_all"
require_relative "code_line"
require_relative "code_block"
require_relative "block_expand"
@@ -235,3 +196,5 @@ require_relative "priority_engulf_queue"
require_relative "pathname_from_message"
require_relative "display_invalid_blocks"
require_relative "parse_blocks_from_indent_line"
+require_relative "visitor"
+require_relative "token"
diff --git a/lib/syntax_suggest/clean_document.rb b/lib/syntax_suggest/clean_document.rb
index ba307af46e..94c68d8ad4 100644
--- a/lib/syntax_suggest/clean_document.rb
+++ b/lib/syntax_suggest/clean_document.rb
@@ -66,27 +66,9 @@ module SyntaxSuggest
#
# All of these problems are fixed by joining the whole heredoc into a single
# line.
- #
- # ## Comments and whitespace
- #
- # Comments can throw off the way the lexer tells us that the line
- # logically belongs with the next line. This is valid ruby but
- # results in a different lex output than before:
- #
- # 1 User.
- # 2 where(name: "schneems").
- # 3 # Comment here
- # 4 first
- #
- # To handle this we can replace comment lines with empty lines
- # and then re-lex the source. This removal and re-lexing preserves
- # line index and document size, but generates an easier to work with
- # document.
- #
class CleanDocument
def initialize(source:)
- lines = clean_sweep(source: source)
- @document = CodeLine.from_source(lines.join, lines: lines)
+ @document = CodeLine.from_source(source)
end
# Call all of the document "cleaners"
@@ -110,62 +92,6 @@ module SyntaxSuggest
@document.join
end
- # Remove comments
- #
- # replace with empty newlines
- #
- # source = <<~'EOM'
- # # Comment 1
- # puts "hello"
- # # Comment 2
- # puts "world"
- # EOM
- #
- # lines = CleanDocument.new(source: source).lines
- # expect(lines[0].to_s).to eq("\n")
- # expect(lines[1].to_s).to eq("puts "hello")
- # expect(lines[2].to_s).to eq("\n")
- # expect(lines[3].to_s).to eq("puts "world")
- #
- # Important: This must be done before lexing.
- #
- # After this change is made, we lex the document because
- # removing comments can change how the doc is parsed.
- #
- # For example:
- #
- # values = LexAll.new(source: <<~EOM))
- # User.
- # # comment
- # where(name: 'schneems')
- # EOM
- # expect(
- # values.count {|v| v.type == :on_ignored_nl}
- # ).to eq(1)
- #
- # After the comment is removed:
- #
- # values = LexAll.new(source: <<~EOM))
- # User.
- #
- # where(name: 'schneems')
- # EOM
- # expect(
- # values.count {|v| v.type == :on_ignored_nl}
- # ).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*#([^{].*|)$/)
- $/
- else
- line
- end
- end
- end
-
# Smushes all heredoc lines into one line
#
# source = <<~'EOM'
@@ -182,11 +108,11 @@ module SyntaxSuggest
start_index_stack = []
heredoc_beg_end_index = []
lines.each do |line|
- line.lex.each do |lex_value|
- case lex_value.type
- when :on_heredoc_beg
+ line.tokens.each do |token|
+ case token.type
+ when :HEREDOC_START
start_index_stack << line.index
- when :on_heredoc_end
+ when :HEREDOC_END
start_index = start_index_stack.pop
end_index = line.index
heredoc_beg_end_index << [start_index, end_index]
@@ -212,20 +138,10 @@ module SyntaxSuggest
# expect(lines[0].to_s).to eq(source)
# expect(lines[1].to_s).to eq("")
#
- # The one known case this doesn't handle is:
- #
- # Ripper.lex <<~EOM
- # a &&
- # b ||
- # c
- # EOM
- #
- # For some reason this introduces `on_ignore_newline` but with BEG type
- #
def join_consecutive!
- consecutive_groups = @document.select(&:ignore_newline_not_beg?).map do |code_line|
+ consecutive_groups = @document.select(&:consecutive?).map do |code_line|
take_while_including(code_line.index..) do |line|
- line.ignore_newline_not_beg?
+ line.consecutive?
end
end
@@ -273,16 +189,17 @@ module SyntaxSuggest
# Join group into the first line
@document[line.index] = CodeLine.new(
- lex: lines.map(&:lex).flatten,
+ tokens: lines.map(&:tokens).flatten,
line: lines.join,
- index: line.index
+ index: line.index,
+ consecutive: false
)
# Hide the rest of the lines
lines[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: [])
+ @document[line.index] = CodeLine.new(line: "", index: line.index, tokens: [], consecutive: false)
end
end
self
diff --git a/lib/syntax_suggest/code_line.rb b/lib/syntax_suggest/code_line.rb
index 58197e95d0..7fb1aae26a 100644
--- a/lib/syntax_suggest/code_line.rb
+++ b/lib/syntax_suggest/code_line.rb
@@ -26,23 +26,57 @@ module SyntaxSuggest
# Returns an array of CodeLine objects
# from the source string
- def self.from_source(source, lines: nil)
- lines ||= source.lines
- lex_array_for_line = LexAll.new(source: source, source_lines: lines).each_with_object(Hash.new { |h, k| h[k] = [] }) { |lex, hash| hash[lex.line] << lex }
- lines.map.with_index do |line, index|
+ def self.from_source(source)
+ source = +source
+ parse_result = Prism.parse_lex(source)
+ ast, tokens = parse_result.value
+
+ clean_comments!(source, parse_result.comments)
+
+ visitor = Visitor.new
+ visitor.visit(ast)
+ tokens.sort_by! { |token, _state| token.location.start_line }
+
+ prev_token = nil
+ tokens.map! do |token, _state|
+ prev_token = Token.new(token, prev_token, visitor)
+ end
+
+ tokens_for_line = tokens.each_with_object(Hash.new { |h, k| h[k] = [] }) { |token, hash| hash[token.line] << token }
+ source.lines.map.with_index do |line, index|
CodeLine.new(
line: line,
index: index,
- lex: lex_array_for_line[index + 1]
+ tokens: tokens_for_line[index + 1],
+ consecutive: visitor.consecutive_lines.include?(index + 1)
)
end
end
- attr_reader :line, :index, :lex, :line_number, :indent
- def initialize(line:, index:, lex:)
- @lex = lex
+ # Remove comments that apear on their own in source. They will never be the cause
+ # of syntax errors and are just visual noise. Example:
+ #
+ # source = +<<~RUBY
+ # # Comment-only line
+ # foo # Inline comment
+ # RUBY
+ # CodeLine.clean_comments!(source, Prism.parse(source).comments)
+ # source # => "\nfoo # Inline comment\n"
+ def self.clean_comments!(source, comments)
+ # Iterate backwards since we are modifying the source in place and must preserve
+ # the offsets. Prism comments are sorted by their location in the source.
+ comments.reverse_each do |comment|
+ next if comment.trailing?
+ source.bytesplice(comment.location.start_offset, comment.location.length, "")
+ end
+ end
+
+ attr_reader :line, :index, :tokens, :line_number, :indent
+ def initialize(line:, index:, tokens:, consecutive:)
+ @tokens = tokens
@line = line
@index = index
+ @consecutive = consecutive
@original = line
@line_number = @index + 1
strip_line = line.dup
@@ -151,92 +185,36 @@ module SyntaxSuggest
index <=> other.index
end
- # [Not stable API]
- #
- # Lines that have a `on_ignored_nl` type token and NOT
- # a `BEG` type seem to be a good proxy for the ability
- # to join multiple lines into one.
- #
- # This predicate method is used to determine when those
- # two criteria have been met.
- #
- # The one known case this doesn't handle is:
- #
- # Ripper.lex <<~EOM
- # a &&
- # b ||
- # c
- # EOM
- #
- # For some reason this introduces `on_ignore_newline` but with BEG type
- def ignore_newline_not_beg?
- @ignore_newline_not_beg
+ # Can this line be logically joined together
+ # with the following line? Determined by walking
+ # the AST
+ def consecutive?
+ @consecutive
end
- # Determines if the given line has a trailing slash
+ # Determines if the given line has a trailing slash.
+ # Simply check if the line contains a backslash after
+ # the content of the last token.
#
# lines = CodeLine.from_source(<<~EOM)
# it "foo" \
# 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
-
- last.token == TRAILING_SLASH
- end
+ def trailing_slash?
+ return unless (last = @tokens.last)
+ @line.byteindex(TRAILING_SLASH, last.location.end_column) != nil
end
- # Endless method detection
- #
- # From https://github.com/ruby/irb/commit/826ae909c9c93a2ddca6f9cfcd9c94dbf53d44ab
- # Detecting a "oneliner" seems to need a state machine.
- # This can be done by looking mostly at the "state" (last value):
- #
- # ENDFN -> BEG (token = '=' ) -> END
- #
private def set_kw_end
- oneliner_count = 0
- in_oneliner_def = nil
-
kw_count = 0
end_count = 0
- @ignore_newline_not_beg = false
- @lex.each do |lex|
- kw_count += 1 if lex.is_kw?
- end_count += 1 if lex.is_end?
-
- if lex.type == :on_ignored_nl
- @ignore_newline_not_beg = !lex.expr_beg?
- end
-
- if in_oneliner_def.nil?
- in_oneliner_def = :ENDFN if lex.state.allbits?(Ripper::EXPR_ENDFN)
- elsif lex.state.allbits?(Ripper::EXPR_ENDFN)
- # Continue
- elsif lex.state.allbits?(Ripper::EXPR_BEG)
- in_oneliner_def = :BODY if lex.token == "="
- elsif lex.state.allbits?(Ripper::EXPR_END)
- # We found an endless method, count it
- oneliner_count += 1 if in_oneliner_def == :BODY
-
- in_oneliner_def = nil
- else
- in_oneliner_def = nil
- end
+ @tokens.each do |token|
+ kw_count += 1 if token.is_kw?
+ end_count += 1 if token.is_end?
end
- kw_count -= oneliner_count
-
@is_kw = (kw_count - end_count) > 0
@is_end = (end_count - kw_count) > 0
end
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb
index 94f57ba605..ffbc922eed 100644
--- a/lib/syntax_suggest/core_ext.rb
+++ b/lib/syntax_suggest/core_ext.rb
@@ -1,96 +1,47 @@
# frozen_string_literal: true
-# Ruby 3.2+ has a cleaner way to hook into Ruby that doesn't use `require`
-if SyntaxError.method_defined?(:detailed_message)
- module SyntaxSuggest
- # SyntaxSuggest.module_for_detailed_message [Private]
- #
- # Used to monkeypatch SyntaxError via Module.prepend
- def self.module_for_detailed_message
- Module.new {
- def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
- return super unless syntax_suggest
-
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- message = super
-
- if path
- file = Pathname.new(path)
- io = SyntaxSuggest::MiniStringIO.new
-
- SyntaxSuggest.call(
- io: io,
- source: file.read,
- filename: file,
- terminal: highlight
- )
- annotation = io.string
-
- annotation += "\n" unless annotation.end_with?("\n")
-
- annotation + message
- else
- message
- end
- rescue => e
- if ENV["SYNTAX_SUGGEST_DEBUG"]
- $stderr.warn(e.message)
- $stderr.warn(e.backtrace)
- end
-
- # Ignore internal errors
+module SyntaxSuggest
+ # SyntaxSuggest.module_for_detailed_message [Private]
+ #
+ # Used to monkeypatch SyntaxError via Module.prepend
+ def self.module_for_detailed_message
+ Module.new {
+ def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
+ return super unless syntax_suggest
+
+ require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
+
+ message = super
+
+ if path
+ file = Pathname.new(path)
+ io = SyntaxSuggest::MiniStringIO.new
+
+ SyntaxSuggest.call(
+ io: io,
+ source: file.read,
+ filename: file,
+ terminal: highlight
+ )
+ annotation = io.string
+
+ annotation += "\n" unless annotation.end_with?("\n")
+
+ annotation + message
+ else
message
end
- }
- end
- end
-
- SyntaxError.prepend(SyntaxSuggest.module_for_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
- alias_method :syntax_suggest_original_require_relative, :require_relative
- alias_method :syntax_suggest_original_load, :load
-
- def load(file, wrap = false)
- syntax_suggest_original_load(file)
- rescue SyntaxError => e
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- SyntaxSuggest.handle_error(e)
- end
-
- def require(file)
- syntax_suggest_original_require(file)
- rescue SyntaxError => e
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- SyntaxSuggest.handle_error(e)
- end
+ rescue => e
+ if ENV["SYNTAX_SUGGEST_DEBUG"]
+ $stderr.warn(e.message)
+ $stderr.warn(e.backtrace)
+ end
- def require_relative(file)
- if Pathname.new(file).absolute?
- syntax_suggest_original_require file
- else
- relative_from = caller_locations(1..1).first
- relative_from_path = relative_from.absolute_path || relative_from.path
- syntax_suggest_original_require File.expand_path("../#{file}", relative_from_path)
+ # Ignore internal errors
+ message
end
- rescue SyntaxError => e
- require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
-
- SyntaxSuggest.handle_error(e)
- end
+ }
end
end
+
+SyntaxError.prepend(SyntaxSuggest.module_for_detailed_message)
diff --git a/lib/syntax_suggest/explain_syntax.rb b/lib/syntax_suggest/explain_syntax.rb
index 0d80c4d869..d7f5262ddb 100644
--- a/lib/syntax_suggest/explain_syntax.rb
+++ b/lib/syntax_suggest/explain_syntax.rb
@@ -1,19 +1,11 @@
# frozen_string_literal: true
-require_relative "left_right_lex_count"
-
-if !SyntaxSuggest.use_prism_parser?
- require_relative "ripper_errors"
-end
+require_relative "left_right_token_count"
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
+ Prism.parse(source).errors.map(&:message)
end
end
@@ -53,14 +45,14 @@ module SyntaxSuggest
def initialize(code_lines:)
@code_lines = code_lines
- @left_right = LeftRightLexCount.new
+ @left_right = LeftRightTokenCount.new
@missing = nil
end
def call
@code_lines.each do |line|
- line.lex.each do |lex|
- @left_right.count_lex(lex)
+ line.tokens.each do |token|
+ @left_right.count_token(token)
end
end
diff --git a/lib/syntax_suggest/left_right_lex_count.rb b/lib/syntax_suggest/left_right_lex_count.rb
deleted file mode 100644
index 6fcae7482b..0000000000
--- a/lib/syntax_suggest/left_right_lex_count.rb
+++ /dev/null
@@ -1,168 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- # Find mis-matched syntax based on lexical count
- #
- # Used for detecting missing pairs of elements
- # each keyword needs an end, each '{' needs a '}'
- # etc.
- #
- # Example:
- #
- # left_right = LeftRightLexCount.new
- # left_right.count_kw
- # left_right.missing.first
- # # => "end"
- #
- # left_right = LeftRightLexCount.new
- # source = "{ a: b, c: d" # Note missing '}'
- # LexAll.new(source: source).each do |lex|
- # left_right.count_lex(lex)
- # end
- # left_right.missing.first
- # # => "}"
- class LeftRightLexCount
- def initialize
- @kw_count = 0
- @end_count = 0
-
- @count_for_char = {
- "{" => 0,
- "}" => 0,
- "[" => 0,
- "]" => 0,
- "(" => 0,
- ")" => 0,
- "|" => 0
- }
- end
-
- def count_kw
- @kw_count += 1
- end
-
- def count_end
- @end_count += 1
- end
-
- # Count source code characters
- #
- # Example:
- #
- # left_right = LeftRightLexCount.new
- # left_right.count_lex(LexValue.new(1, :on_lbrace, "{", Ripper::EXPR_BEG))
- # left_right.count_for_char("{")
- # # => 1
- # left_right.count_for_char("}")
- # # => 0
- def count_lex(lex)
- case lex.type
- when :on_tstring_content
- # ^^^
- # Means it's a string or a symbol `"{"` rather than being
- # part of a data structure (like a hash) `{ a: b }`
- # ignore it.
- when :on_words_beg, :on_symbos_beg, :on_qwords_beg,
- :on_qsymbols_beg, :on_regexp_beg, :on_tstring_beg
- # ^^^
- # Handle shorthand syntaxes like `%Q{ i am a string }`
- #
- # The start token will be the full thing `%Q{` but we
- # need to count it as if it's a `{`. Any token
- # can be used
- char = lex.token[-1]
- @count_for_char[char] += 1 if @count_for_char.key?(char)
- when :on_embexpr_beg
- # ^^^
- # Embedded string expressions like `"#{foo} <-embed"`
- # are parsed with chars:
- #
- # `#{` as :on_embexpr_beg
- # `}` as :on_embexpr_end
- #
- # We cannot ignore both :on_emb_expr_beg and :on_embexpr_end
- # because sometimes the lexer thinks something is an embed
- # string end, when it is not like `lol = }` (no clue why).
- #
- # When we see `#{` count it as a `{` or we will
- # have a mis-match count.
- #
- case lex.token
- when "\#{"
- @count_for_char["{"] += 1
- end
- else
- @end_count += 1 if lex.is_end?
- @kw_count += 1 if lex.is_kw?
- @count_for_char[lex.token] += 1 if @count_for_char.key?(lex.token)
- end
- end
-
- def count_for_char(char)
- @count_for_char[char]
- end
-
- # Returns an array of missing syntax characters
- # or `"end"` or `"keyword"`
- #
- # left_right.missing
- # # => ["}"]
- def missing
- out = missing_pairs
- out << missing_pipe
- out << missing_keyword_end
- out.compact!
- out
- end
-
- PAIRS = {
- "{" => "}",
- "[" => "]",
- "(" => ")"
- }.freeze
-
- # Opening characters like `{` need closing characters # like `}`.
- #
- # When a mis-match count is detected, suggest the
- # missing member.
- #
- # For example if there are 3 `}` and only two `{`
- # return `"{"`
- private def missing_pairs
- PAIRS.map do |(left, right)|
- case @count_for_char[left] <=> @count_for_char[right]
- when 1
- right
- when 0
- nil
- when -1
- left
- end
- end
- end
-
- # Keywords need ends and ends need keywords
- #
- # If we have more keywords, there's a missing `end`
- # if we have more `end`-s, there's a missing keyword
- private def missing_keyword_end
- case @kw_count <=> @end_count
- when 1
- "end"
- when 0
- nil
- when -1
- "keyword"
- end
- end
-
- # Pipes come in pairs.
- # If there's an odd number of pipes then we
- # are missing one
- private def missing_pipe
- if @count_for_char["|"].odd?
- "|"
- end
- end
- end
-end
diff --git a/lib/syntax_suggest/left_right_token_count.rb b/lib/syntax_suggest/left_right_token_count.rb
new file mode 100644
index 0000000000..e0562ba9cd
--- /dev/null
+++ b/lib/syntax_suggest/left_right_token_count.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+module SyntaxSuggest
+ # Find mis-matched syntax based on lexical count
+ #
+ # Used for detecting missing pairs of elements
+ # each keyword needs an end, each '{' needs a '}'
+ # etc.
+ #
+ # Example:
+ #
+ # left_right = LeftRightTokenCount.new
+ # left_right.count_kw
+ # left_right.missing.first
+ # # => "end"
+ #
+ # left_right = LeftRightTokenCount.new
+ # source = "{ a: b, c: d" # Note missing '}'
+ # LexAll.new(source: source).each do |token|
+ # left_right.count_token(token)
+ # end
+ # left_right.missing.first
+ # # => "}"
+ class LeftRightTokenCount
+ def initialize
+ @kw_count = 0
+ @end_count = 0
+
+ @count_for_char = {
+ "{" => 0,
+ "}" => 0,
+ "[" => 0,
+ "]" => 0,
+ "(" => 0,
+ ")" => 0,
+ "|" => 0
+ }
+ end
+
+ def count_kw
+ @kw_count += 1
+ end
+
+ def count_end
+ @end_count += 1
+ end
+
+ # Count source code characters
+ #
+ # Example:
+ #
+ # token = CodeLine.from_source("{").first.tokens.first
+ # left_right = LeftRightTokenCount.new
+ # left_right.count_token(Token.new(token)
+ # left_right.count_for_char("{")
+ # # => 1
+ # left_right.count_for_char("}")
+ # # => 0
+ def count_token(token)
+ case token.type
+ when :STRING_CONTENT
+ # ^^^
+ # Means it's a string or a symbol `"{"` rather than being
+ # part of a data structure (like a hash) `{ a: b }`
+ # ignore it.
+ when :PERCENT_UPPER_W, :PERCENT_UPPER_I, :PERCENT_LOWER_W,
+ :PERCENT_LOWER_I, :REGEXP_BEGIN, :STRING_BEGIN
+ # ^^^
+ # Handle shorthand syntaxes like `%Q{ i am a string }`
+ #
+ # The start token will be the full thing `%Q{` but we
+ # need to count it as if it's a `{`. Any token
+ # can be used
+ char = token.value[-1]
+ @count_for_char[char] += 1 if @count_for_char.key?(char)
+ when :EMBEXPR_BEGIN
+ # ^^^
+ # Embedded string expressions like `"#{foo} <-embed"`
+ # are parsed with chars:
+ #
+ # `#{` as :EMBEXPR_BEGIN
+ # `}` as :EMBEXPR_END
+ #
+ # When we see `#{` count it as a `{` or we will
+ # have a mis-match count.
+ #
+ @count_for_char["{"] += 1
+ else
+ @end_count += 1 if token.is_end?
+ @kw_count += 1 if token.is_kw?
+ @count_for_char[token.value] += 1 if @count_for_char.key?(token.value)
+ end
+ end
+
+ def count_for_char(char)
+ @count_for_char[char]
+ end
+
+ # Returns an array of missing syntax characters
+ # or `"end"` or `"keyword"`
+ #
+ # left_right.missing
+ # # => ["}"]
+ def missing
+ out = missing_pairs
+ out << missing_pipe
+ out << missing_keyword_end
+ out.compact!
+ out
+ end
+
+ PAIRS = {
+ "{" => "}",
+ "[" => "]",
+ "(" => ")"
+ }.freeze
+
+ # Opening characters like `{` need closing characters # like `}`.
+ #
+ # When a mis-match count is detected, suggest the
+ # missing member.
+ #
+ # For example if there are 3 `}` and only two `{`
+ # return `"{"`
+ private def missing_pairs
+ PAIRS.map do |(left, right)|
+ case @count_for_char[left] <=> @count_for_char[right]
+ when 1
+ right
+ when 0
+ nil
+ when -1
+ left
+ end
+ end
+ end
+
+ # Keywords need ends and ends need keywords
+ #
+ # If we have more keywords, there's a missing `end`
+ # if we have more `end`-s, there's a missing keyword
+ private def missing_keyword_end
+ case @kw_count <=> @end_count
+ when 1
+ "end"
+ when 0
+ nil
+ when -1
+ "keyword"
+ end
+ end
+
+ # Pipes come in pairs.
+ # If there's an odd number of pipes then we
+ # are missing one
+ private def missing_pipe
+ if @count_for_char["|"].odd?
+ "|"
+ end
+ end
+ end
+end
diff --git a/lib/syntax_suggest/lex_all.rb b/lib/syntax_suggest/lex_all.rb
deleted file mode 100644
index c16fbb52d3..0000000000
--- a/lib/syntax_suggest/lex_all.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-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
- class LexAll
- include Enumerable
-
- def initialize(source:, source_lines: nil)
- @lex = self.class.lex(source, 1)
- lineno = @lex.last[0][0] + 1
- source_lines ||= source.lines
- last_lineno = source_lines.length
-
- until lineno >= last_lineno
- lines = source_lines[lineno..]
-
- @lex.concat(
- self.class.lex(lines.join, lineno + 1)
- )
-
- lineno = @lex.last[0].first + 1
- end
-
- last_lex = nil
- @lex.map! { |elem|
- last_lex = LexValue.new(elem[0].first, elem[1], elem[2], elem[3], 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
-
- def each
- return @lex.each unless block_given?
- @lex.each do |x|
- yield x
- end
- end
-
- def [](index)
- @lex[index]
- end
-
- def last
- @lex.last
- end
- end
-end
-
-require_relative "lex_value"
diff --git a/lib/syntax_suggest/lex_value.rb b/lib/syntax_suggest/lex_value.rb
deleted file mode 100644
index b46a332772..0000000000
--- a/lib/syntax_suggest/lex_value.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- # Value object for accessing lex values
- #
- # This lex:
- #
- # [1, 0], :on_ident, "describe", CMDARG
- #
- # Would translate into:
- #
- # lex.line # => 1
- # lex.type # => :on_indent
- # lex.token # => "describe"
- class LexValue
- attr_reader :line, :type, :token, :state
-
- def initialize(line, type, token, state, last_lex = nil)
- @line = line
- @type = type
- @token = token
- @state = state
-
- set_kw_end(last_lex)
- end
-
- private def set_kw_end(last_lex)
- @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
- when "if", "unless", "while", "until"
- # Only count if/unless when it's not a "trailing" if/unless
- # https://github.com/ruby/ruby/blob/06b44f819eb7b5ede1ff69cecb25682b56a1d60c/lib/irb/ruby-lex.rb#L374-L375
- @is_kw = true unless expr_label?
- when "def", "case", "for", "begin", "class", "module", "do"
- @is_kw = true
- when "end"
- @is_end = true
- end
- end
-
- def fname?
- state.allbits?(Ripper::EXPR_FNAME)
- end
-
- def ignore_newline?
- type == :on_ignored_nl
- end
-
- def is_end?
- @is_end
- end
-
- def is_kw?
- @is_kw
- end
-
- def expr_beg?
- state.anybits?(Ripper::EXPR_BEG)
- end
-
- def expr_label?
- state.allbits?(Ripper::EXPR_LABEL)
- end
- end
-end
diff --git a/lib/syntax_suggest/ripper_errors.rb b/lib/syntax_suggest/ripper_errors.rb
deleted file mode 100644
index 4e2bc90948..0000000000
--- a/lib/syntax_suggest/ripper_errors.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# 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.
- #
- # Example:
- #
- # puts RipperErrors.new(" def foo").call.errors
- # # => ["syntax error, unexpected end-of-input, expecting ';' or '\\n'"]
- class RipperErrors < Ripper
- attr_reader :errors
-
- # Comes from ripper, called
- # on every parse error, msg
- # is a string
- def on_parse_error(msg)
- @errors ||= []
- @errors << msg
- end
-
- alias_method :on_alias_error, :on_parse_error
- alias_method :on_assign_error, :on_parse_error
- alias_method :on_class_name_error, :on_parse_error
- alias_method :on_param_error, :on_parse_error
- alias_method :compile_error, :on_parse_error
-
- def call
- @run_once ||= begin
- @errors = []
- parse
- true
- end
- self
- end
- end
-end
diff --git a/lib/syntax_suggest/syntax_suggest.gemspec b/lib/syntax_suggest/syntax_suggest.gemspec
index 756a85bf63..44e458aaad 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(">= 3.3.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "https://github.com/ruby/syntax_suggest.git"
diff --git a/lib/syntax_suggest/token.rb b/lib/syntax_suggest/token.rb
new file mode 100644
index 0000000000..fc52639b1f
--- /dev/null
+++ b/lib/syntax_suggest/token.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module SyntaxSuggest
+ # Value object for accessing lex values
+ #
+ # This lex:
+ #
+ # [IDENTIFIER(1,0)-(1,8)("describe"), 32]
+ #
+ # Would translate into:
+ #
+ # lex.location # => (1,0)-(1,8)
+ # lex.type # => :IDENTIFIER
+ # lex.token # => "describe"
+ class Token
+ attr_reader :location, :type, :value
+
+ KW_TYPES = %i[
+ KEYWORD_IF KEYWORD_UNLESS KEYWORD_WHILE KEYWORD_UNTIL
+ KEYWORD_DEF KEYWORD_CASE KEYWORD_FOR KEYWORD_BEGIN KEYWORD_CLASS KEYWORD_MODULE KEYWORD_DO KEYWORD_DO_LOOP
+ ].to_set.freeze
+ private_constant :KW_TYPES
+
+ def initialize(prism_token, previous_prism_token, visitor)
+ @location = prism_token.location
+ @type = prism_token.type
+ @value = prism_token.value
+
+ # Prism lexes `:module` as SYMBOL_BEGIN, KEYWORD_MODULE
+ # https://github.com/ruby/prism/issues/3940
+ symbol_content = previous_prism_token&.type == :SYMBOL_BEGIN
+ @is_kw = KW_TYPES.include?(@type)
+ @is_kw = false if symbol_content || visitor.endless_def_keyword_offsets.include?(@location.start_offset)
+ @is_end = @type == :KEYWORD_END
+ end
+
+ def line
+ @location.start_line
+ end
+
+ def is_end?
+ @is_end
+ end
+
+ def is_kw?
+ @is_kw
+ end
+ end
+end
diff --git a/lib/syntax_suggest/version.rb b/lib/syntax_suggest/version.rb
index 1aa908f4e5..9114a079f6 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.2"
+ VERSION = "3.0.0"
end
diff --git a/lib/syntax_suggest/visitor.rb b/lib/syntax_suggest/visitor.rb
new file mode 100644
index 0000000000..6e25f7239c
--- /dev/null
+++ b/lib/syntax_suggest/visitor.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module SyntaxSuggest
+ # Walks the Prism AST to extract structural info that cannot be reliably determined from tokens
+ # alone.
+ #
+ # Such as the location of lines that must be logically joined so the search algorithm will
+ # treat them as one. Example:
+ #
+ # source = <<~RUBY
+ # User # 1
+ # .where(name: "Earlopain") # 2
+ # .first # 3
+ # RUBY
+ # ast, _tokens = Prism.parse_lex(source).value
+ # visitor = Visitor.new
+ # visitor.visit(ast)
+ # visitor.consecutive_lines # => Set[2, 1]
+ #
+ # This output means that line 1 and line 2 need to be joined with their next line.
+ #
+ # And determining the location of "endless" method definitions. For example:
+ #
+ # source = <<~RUBY
+ # def cube(x)
+ # x * x * x
+ # end
+ # def square(x) = x * x # 1
+ # RUBY
+ #
+ # ast, _tokens = Prism.parse_lex(source).value
+ # visitor = Visitor.new
+ # visitor.visit(ast)
+ # visitor.endless_def_keyword_offsets # => Set[28]
+ class Visitor < Prism::Visitor
+ attr_reader :endless_def_keyword_offsets, :consecutive_lines
+
+ def initialize
+ @endless_def_keyword_offsets = Set.new
+ @consecutive_lines = Set.new
+ end
+
+ # Called by Prism::Visitor for every method-call node in the AST
+ # (e.g. `foo.bar`, `foo.bar.baz`).
+ def visit_call_node(node)
+ receiver_loc = node.receiver&.location
+ call_operator_loc = node.call_operator_loc
+ message_loc = node.message_loc
+ if receiver_loc && call_operator_loc && message_loc
+ # dot-leading (dot on the next line)
+ # foo # line 1 - consecutive
+ # .bar # line 2
+ if receiver_loc.end_line != call_operator_loc.start_line && call_operator_loc.start_line == message_loc.start_line
+ (receiver_loc.end_line..call_operator_loc.start_line - 1).each do |line|
+ @consecutive_lines << line
+ end
+ end
+
+ # dot-trailing (dot on the same line as the receiver)
+ # foo. # line 1 - consecutive
+ # bar # line 2
+ if receiver_loc.end_line == call_operator_loc.start_line && call_operator_loc.start_line != message_loc.start_line
+ (call_operator_loc.start_line..message_loc.start_line - 1).each do |line|
+ @consecutive_lines << line
+ end
+ end
+ end
+ super
+ end
+
+ # Called by Prism::Visitor for every `def` node in the AST.
+ # Records the keyword start location for endless method definitions
+ # like `def foo = 123`. These are valid without a matching `end`,
+ # so Token must exclude them when deciding if a line is a keyword.
+ def visit_def_node(node)
+ @endless_def_keyword_offsets << node.def_keyword_loc.start_offset if node.equal_loc
+ super
+ end
+ end
+end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index f3213c5684..cd512bb1c5 100644
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -29,7 +29,7 @@ require 'tmpdir'
# require 'tempfile'
#
# # Tempfile.create with a block
-# # The filename are choosen automatically.
+# # The filename are chosen automatically.
# # (You can specify the prefix and suffix of the filename by an optional argument.)
# Tempfile.create {|f|
# f.puts "foo"
@@ -550,8 +550,8 @@ end
#
# Implementation note:
#
-# The keyword argument +anonymous=true+ is implemented using FILE_SHARE_DELETE on Windows.
-# O_TMPFILE is used on Linux.
+# The keyword argument <tt>anonymous=true</tt> is implemented using +FILE_SHARE_DELETE+ on Windows.
+# +O_TMPFILE+ is used on Linux.
#
# Related: Tempfile.new.
#
@@ -564,6 +564,8 @@ def Tempfile.create(basename="", tmpdir=nil, mode: 0, anonymous: false, **option
end
class << Tempfile
+# :stopdoc:
+
private def create_with_filename(basename="", tmpdir=nil, mode: 0, **options)
tmpfile = nil
Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
diff --git a/lib/time.gemspec b/lib/time.gemspec
index 4b9f9e1218..73650ab12e 100644
--- a/lib/time.gemspec
+++ b/lib/time.gemspec
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
+ spec.metadata["changelog_uri"] = "https://github.com/ruby/time/releases"
srcdir, gemspec = File.split(__FILE__)
spec.files = Dir.chdir(srcdir) do
diff --git a/lib/time.rb b/lib/time.rb
index a0fc7dfbf5..e6aab3fa5d 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -27,7 +27,7 @@ require 'date'
# #
class Time
- VERSION = "0.4.1" # :nodoc:
+ VERSION = "0.4.2" # :nodoc:
class << Time
@@ -80,7 +80,7 @@ class Time
#
# You must require 'time' to use this method.
#
- def zone_offset(zone, year=self.now.year)
+ def zone_offset(zone, year=nil)
off = nil
zone = zone.upcase
if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone
@@ -89,10 +89,13 @@ class Time
off = zone.to_i * 3600
elsif ZoneOffset.include?(zone)
off = ZoneOffset[zone] * 3600
- elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
- off = t.utc_offset
- elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
- off = t.utc_offset
+ else
+ year ||= self.now.year
+ if ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
+ off = t.utc_offset
+ elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
+ off = t.utc_offset
+ end
end
off
end
diff --git a/lib/timeout.rb b/lib/timeout.rb
index 4fd1fa46da..91b04a9562 100644
--- a/lib/timeout.rb
+++ b/lib/timeout.rb
@@ -20,9 +20,9 @@
module Timeout
# The version
- VERSION = "0.4.3"
+ VERSION = "0.6.1"
- # Internal error raised to when a timeout is triggered.
+ # Internal exception raised to when a timeout is triggered.
class ExitException < Exception
def exception(*) # :nodoc:
self
@@ -44,12 +44,101 @@ module Timeout
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
+
+ # We keep a private reference so that time mocking libraries won't break Timeout.
+ GET_TIME = Process.method(:clock_gettime)
+ if defined?(Ractor.make_shareable)
+ # Ractor.make_shareable(Method) only works on Ruby 4+
+ Ractor.make_shareable(GET_TIME) rescue nil
+ end
+ private_constant :GET_TIME
+
+ class State
+ def initialize
+ @condvar = ConditionVariable.new
+ @queue = Queue.new
+ @queue_mutex = Mutex.new
+
+ @timeout_thread = nil
+ @timeout_thread_mutex = Mutex.new
+ end
+
+ if defined?(Ractor.store_if_absent) && defined?(Ractor.shareable?) && Ractor.shareable?(GET_TIME)
+ # Ractor support if
+ # 1. Ractor.store_if_absent is available
+ # 2. Method object can be shareable (4.0~)
+ def self.instance
+ Ractor.store_if_absent :timeout_gem_state do
+ State.new
+ end
+ end
+ else
+ GLOBAL_STATE = State.new
+
+ def self.instance
+ GLOBAL_STATE
+ end
+ end
+
+ def create_timeout_thread
+ # Threads unexpectedly inherit the interrupt mask: https://github.com/ruby/timeout/issues/41
+ # So reset the interrupt mask to the default one for the timeout thread
+ Thread.handle_interrupt(Object => :immediate) do
+ 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
+
+ if !watcher.group.enclosed? && (!defined?(Ractor.main?) || Ractor.main?)
+ ThreadGroup::Default.add(watcher)
+ end
+
+ watcher.name = "Timeout stdlib thread"
+ watcher.thread_variable_set(:"\0__detached_thread__", true)
+ watcher
+ end
+ end
+
+ def ensure_timeout_thread_created
+ unless @timeout_thread&.alive?
+ # If the Mutex is already owned we are in a signal handler.
+ # In that case, just return and let the main thread create the Timeout thread.
+ return if @timeout_thread_mutex.owned?
+
+ Sync.synchronize @timeout_thread_mutex do
+ unless @timeout_thread&.alive?
+ @timeout_thread = create_timeout_thread
+ end
+ end
+ end
+ end
+
+ def add_request(request)
+ Sync.synchronize @queue_mutex do
+ @queue << request
+ @condvar.signal
+ end
+ end
+ end
+ private_constant :State
class Request
attr_reader :deadline
@@ -64,6 +153,7 @@ module Timeout
@done = false # protected by @mutex
end
+ # Only called by the timeout thread, so does not need Sync.synchronize
def done?
@mutex.synchronize do
@done
@@ -74,6 +164,7 @@ module Timeout
now >= @deadline
end
+ # Only called by the timeout thread, so does not need Sync.synchronize
def interrupt
@mutex.synchronize do
unless @done
@@ -84,61 +175,36 @@ module Timeout
end
def finished
- @mutex.synchronize do
+ Sync.synchronize @mutex 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 = "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
+ module Sync
+ # Calls mutex.synchronize(&block) but if that fails on CRuby due to being in a trap handler,
+ # run mutex.synchronize(&block) in a separate Thread instead.
+ def self.synchronize(mutex, &block)
+ begin
+ mutex.synchronize(&block)
+ rescue ThreadError => e
+ raise e unless e.message == "can't be called from trap context"
+ # Workaround CRuby issue https://bugs.ruby-lang.org/issues/19473
+ # which raises on Mutex#synchronize in trap handler.
+ # It's expensive to create a Thread just for this,
+ # but better than failing.
+ Thread.new {
+ mutex.synchronize(&block)
+ }.join
end
end
end
-
- # We keep a private reference so that time mocking libraries won't break
- # Timeout.
- GET_TIME = Process.method(:clock_gettime)
- private_constant :GET_TIME
+ private_constant :Sync
# :startdoc:
- # Perform an operation in a block, raising an error if it takes longer than
+ # Perform an operation in a block, raising an exception if it takes longer than
# +sec+ seconds to complete.
#
# +sec+:: Number of seconds to wait for the block to terminate. Any non-negative number
@@ -146,45 +212,91 @@ module Timeout
# value of 0 or +nil+ will execute the block without any timeout.
# Any negative number will raise an ArgumentError.
# +klass+:: Exception Class to raise if the block fails to terminate
- # in +sec+ seconds. Omitting will use the default, Timeout::Error
+ # in +sec+ seconds. Omitting will use the default, Timeout::Error.
# +message+:: Error message to raise with Exception Class.
- # Omitting will use the default, "execution expired"
+ # Omitting will use the default, <tt>"execution expired"</tt>.
#
# Returns the result of the block *if* the block completed before
- # +sec+ seconds, otherwise throws an exception, based on the value of +klass+.
+ # +sec+ seconds, otherwise raises an exception, based on the value of +klass+.
+ #
+ # The exception raised to terminate the given block is the given +klass+, or
+ # Timeout::ExitException if +klass+ is not given. The reason for that behavior
+ # is that Timeout::Error inherits from RuntimeError and might be caught unexpectedly by +rescue+.
+ # Timeout::ExitException inherits from Exception so it will only be rescued by <tt>rescue Exception</tt>.
+ # Note that the Timeout::ExitException is translated to a Timeout::Error once it reaches the Timeout.timeout call,
+ # so outside that call it will be a Timeout::Error.
#
- # 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.
+ # In general, be aware that the code block may rescue the exception, and in such a case not respect the timeout.
+ # Also, the block can use +ensure+ to prevent the handling of the exception.
+ # For those reasons, 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.
+ # Fiber::Scheduler#timeout_after.
#
# Note that this is both a method of module Timeout, so you can <tt>include
# Timeout</tt> into your classes so they have a #timeout method, as well as
# a module method, so you can call it directly as Timeout.timeout().
- def timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+
+ #
+ # ==== Ensuring the exception does not fire inside ensure blocks
+ #
+ # When using Timeout.timeout, it can be desirable to ensure the timeout exception does not fire inside an +ensure+ block.
+ # The simplest and best way to do so is to put the Timeout.timeout call inside the body of the +begin+/+ensure+/+end+:
+ #
+ # begin
+ # Timeout.timeout(sec) { some_long_operation }
+ # ensure
+ # cleanup # safe, cannot be interrupted by timeout
+ # end
+ #
+ # If that is not feasible, e.g. if there are +ensure+ blocks inside +some_long_operation+,
+ # they need to not be interrupted by timeout, and it's not possible to move these ensure blocks outside,
+ # one can use Thread.handle_interrupt to delay the timeout exception like so:
+ #
+ # Thread.handle_interrupt(Timeout::Error => :never) {
+ # Timeout.timeout(sec, Timeout::Error) do
+ # setup # timeout cannot happen here, no matter how long it takes
+ # Thread.handle_interrupt(Timeout::Error => :immediate) {
+ # some_long_operation # timeout can happen here
+ # }
+ # ensure
+ # cleanup # timeout cannot happen here, no matter how long it takes
+ # end
+ # }
+ #
+ # An important thing to note is the need to pass an exception +klass+ to Timeout.timeout,
+ # otherwise it does not work. Specifically, using <tt>Thread.handle_interrupt(Timeout::ExitException => ...)</tt>
+ # is unsupported and causes subtle errors like raising the wrong exception outside the block, do not use that.
+ #
+ # Note that Thread.handle_interrupt is somewhat dangerous because if setup or cleanup hangs
+ # then the current thread will hang too and the timeout will never fire.
+ # Also note the block might run for longer than +sec+ seconds:
+ # e.g. +some_long_operation+ executes for +sec+ seconds + whatever time cleanup takes.
+ #
+ # If you want the timeout to only happen on blocking operations, one can use +:on_blocking+
+ # instead of +:immediate+. However, that means if the block uses no blocking operations after +sec+ seconds,
+ # the block will not be interrupted.
+ def self.timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+
return yield(sec) if sec == nil or sec.zero?
raise ArgumentError, "Timeout sec must be a non-negative number" if 0 > sec
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
-
- 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
+ perform = Proc.new do |exc|
+ scheduler.timeout_after(sec, exc, message, &block)
end
- begin
- return yield(sec)
- ensure
- request.finished
+ else
+ state = State.instance
+ state.ensure_timeout_thread_created
+
+ perform = Proc.new do |exc|
+ request = Request.new(Thread.current, sec, exc, message)
+ state.add_request(request)
+ begin
+ return yield(sec)
+ ensure
+ request.finished
+ end
end
end
@@ -194,5 +306,9 @@ module Timeout
Error.handle_timeout(message, &perform)
end
end
- module_function :timeout
+
+ # See Timeout.timeout
+ private def timeout(*args, &block)
+ Timeout.timeout(*args, &block)
+ end
end
diff --git a/lib/tsort.gemspec b/lib/tsort.gemspec
deleted file mode 100644
index 0e2f110a53..0000000000
--- a/lib/tsort.gemspec
+++ /dev/null
@@ -1,29 +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 = ["Tanaka Akira"]
- spec.email = ["akr@fsij.org"]
-
- spec.summary = %q{Topological sorting using Tarjan's algorithm}
- spec.description = %q{Topological sorting using Tarjan's algorithm}
- spec.homepage = "https://github.com/ruby/tsort"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
- 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`.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/tsort.rb b/lib/tsort.rb
deleted file mode 100644
index dbaed45415..0000000000
--- a/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.
-#++
-#
-
-#
-# TSort implements topological sorting using Tarjan's algorithm for
-# strongly connected components.
-#
-# TSort is designed to be able to be used with any object which can be
-# interpreted as a directed graph.
-#
-# 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
-# TSort uses Hash internally.
-#
-# == A Simple Example
-#
-# The following example demonstrates how to mix the 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 'tsort'
-#
-# class Hash
-# include 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 '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 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 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 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, TSort::Cyclic is raised.
- #
- # class G
- # include 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 TSort::Cyclic
- #
- def tsort
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- 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, 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 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 TSort.tsort(each_node, each_child) # raises 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, TSort::Cyclic is raised.
- #
- # class G
- # include 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)
- TSort.tsort_each(each_node, each_child, &block)
- end
-
- # The iterator version of the 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) }
- # 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 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)
- 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 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 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 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)
- TSort.each_strongly_connected_component(each_node, each_child, &block)
- end
-
- # The iterator version of the 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) }
- # 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) }
- # 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 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
- 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.
- #
- # #TSort.each_strongly_connected_component_from is a class method and
- # it doesn't need a class to represent a graph which includes TSort.
- #
- # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_child = lambda {|n, &b| graph[n].each(&b) }
- # 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/unicode_normalize/normalize.rb b/lib/unicode_normalize/normalize.rb
index 1caf2cc8c8..0447df8de7 100644
--- a/lib/unicode_normalize/normalize.rb
+++ b/lib/unicode_normalize/normalize.rb
@@ -82,16 +82,22 @@ module UnicodeNormalize # :nodoc:
## Canonical Ordering
def self.canonical_ordering_one(string)
- sorting = string.each_char.collect { |c| [c, CLASS_TABLE[c]] }
- (sorting.length-2).downto(0) do |i| # almost, but not exactly bubble sort
- (0..i).each do |j|
- later_class = sorting[j+1].last
- if 0<later_class and later_class<sorting[j].last
- sorting[j], sorting[j+1] = sorting[j+1], sorting[j]
- end
+ result = ''
+ unordered = []
+ chars = string.chars
+ n = chars.size
+ chars.each_with_index do |char, i|
+ ccc = CLASS_TABLE[char]
+ if ccc == 0
+ unordered.sort!.each { result << chars[it % n] }
+ unordered.clear
+ result << char
+ else
+ unordered << ccc * n + i
end
end
- return sorting.collect(&:first).join('')
+ unordered.sort!.each { result << chars[it % n] }
+ result
end
## Normalization Forms for Patterns (not whole Strings)
@@ -105,16 +111,22 @@ module UnicodeNormalize # :nodoc:
start = nfd_string[0]
last_class = CLASS_TABLE[start]-1
accents = ''
+ result = ''
nfd_string[1..-1].each_char do |accent|
accent_class = CLASS_TABLE[accent]
if last_class<accent_class and composite = COMPOSITION_TABLE[start+accent]
start = composite
+ elsif accent_class == 0
+ result << start << accents
+ start = accent
+ accents = ''
+ last_class = -1
else
accents << accent
last_class = accent_class
end
end
- hangul_comp_one(start+accents)
+ hangul_comp_one(result+start+accents)
end
def self.normalize(string, form = :nfc)
diff --git a/lib/unicode_normalize/tables.rb b/lib/unicode_normalize/tables.rb
index 7448fad13f..dd5d3499b8 100644
--- a/lib/unicode_normalize/tables.rb
+++ b/lib/unicode_normalize/tables.rb
@@ -1,6 +1,9 @@
# coding: us-ascii
# frozen_string_literal: true
+Encoding::UNICODE_VERSION == "17.0.0" or
+ raise "Unicode version mismatch: 17.0.0 expected but #{Encoding::UNICODE_VERSION}"
+
# automatically generated by template/unicode_norm_gen.tmpl
module UnicodeNormalize # :nodoc:
@@ -29,7 +32,7 @@ module UnicodeNormalize # :nodoc:
"\u0825-\u0827" \
"\u0829-\u082D" \
"\u0859-\u085B" \
- "\u0898-\u089F" \
+ "\u0897-\u089F" \
"\u08CA-\u08E1" \
"\u08E3-\u08FF" \
"\u093C" \
@@ -96,7 +99,8 @@ module UnicodeNormalize # :nodoc:
"\u1A75-\u1A7C" \
"\u1A7F" \
"\u1AB0-\u1ABD" \
- "\u1ABF-\u1ACE" \
+ "\u1ABF-\u1ADD" \
+ "\u1AE0-\u1AEB" \
"\u1B34\u1B35" \
"\u1B44" \
"\u1B6B-\u1B73" \
@@ -149,7 +153,9 @@ module UnicodeNormalize # :nodoc:
"\u{10A3F}" \
"\u{10AE5}\u{10AE6}" \
"\u{10D24}-\u{10D27}" \
+ "\u{10D69}-\u{10D6D}" \
"\u{10EAB}\u{10EAC}" \
+ "\u{10EFA}\u{10EFB}" \
"\u{10EFD}-\u{10EFF}" \
"\u{10F46}-\u{10F50}" \
"\u{10F82}-\u{10F85}" \
@@ -171,6 +177,12 @@ module UnicodeNormalize # :nodoc:
"\u{11357}" \
"\u{11366}-\u{1136C}" \
"\u{11370}-\u{11374}" \
+ "\u{113B8}" \
+ "\u{113BB}" \
+ "\u{113C2}" \
+ "\u{113C5}" \
+ "\u{113C7}-\u{113C9}" \
+ "\u{113CE}-\u{113D0}" \
"\u{11442}" \
"\u{11446}" \
"\u{1145E}" \
@@ -196,8 +208,11 @@ module UnicodeNormalize # :nodoc:
"\u{11D44}\u{11D45}" \
"\u{11D97}" \
"\u{11F41}\u{11F42}" \
+ "\u{1611E}-\u{16129}" \
+ "\u{1612F}" \
"\u{16AF0}-\u{16AF4}" \
"\u{16B30}-\u{16B36}" \
+ "\u{16D67}\u{16D68}" \
"\u{16FF0}\u{16FF1}" \
"\u{1BC9E}" \
"\u{1D165}-\u{1D169}" \
@@ -216,6 +231,11 @@ module UnicodeNormalize # :nodoc:
"\u{1E2AE}" \
"\u{1E2EC}-\u{1E2EF}" \
"\u{1E4EC}-\u{1E4EF}" \
+ "\u{1E5EE}\u{1E5EF}" \
+ "\u{1E6E3}" \
+ "\u{1E6E6}" \
+ "\u{1E6EE}\u{1E6EF}" \
+ "\u{1E6F5}" \
"\u{1E8D0}-\u{1E8D6}" \
"\u{1E944}-\u{1E94A}" \
"]"
@@ -441,15 +461,25 @@ module UnicodeNormalize # :nodoc:
"\uFB40\uFB41" \
"\uFB43\uFB44" \
"\uFB46-\uFB4E" \
+ "\u{105C9}" \
+ "\u{105E4}" \
"\u{1109A}" \
"\u{1109C}" \
"\u{110AB}" \
"\u{1112E}\u{1112F}" \
"\u{1134B}\u{1134C}" \
+ "\u{11383}" \
+ "\u{11385}" \
+ "\u{1138E}" \
+ "\u{11391}" \
+ "\u{113C5}" \
+ "\u{113C7}\u{113C8}" \
"\u{114BB}\u{114BC}" \
"\u{114BE}" \
"\u{115BA}\u{115BB}" \
"\u{11938}" \
+ "\u{16121}-\u{16128}" \
+ "\u{16D68}-\u{16D6A}" \
"\u{1D15E}-\u{1D164}" \
"\u{1D1BB}-\u{1D1C0}" \
"\u{2F800}-\u{2FA1D}" \
@@ -613,14 +643,25 @@ module UnicodeNormalize # :nodoc:
"\u30DB" \
"\u30EF-\u30F2" \
"\u30FD" \
+ "\u{105D2}" \
+ "\u{105DA}" \
"\u{11099}" \
"\u{1109B}" \
"\u{110A5}" \
"\u{11131}\u{11132}" \
"\u{11347}" \
+ "\u{11382}" \
+ "\u{11384}" \
+ "\u{1138B}" \
+ "\u{11390}" \
+ "\u{113C2}" \
"\u{114B9}" \
"\u{115B8}\u{115B9}" \
"\u{11935}" \
+ "\u{1611E}" \
+ "\u{16129}" \
+ "\u{16D63}" \
+ "\u{16D67}" \
"]?#{accents}+" \
"|#{'' # precomposed Hangul syllables
}" \
@@ -891,6 +932,10 @@ module UnicodeNormalize # :nodoc:
"\u30F4" \
"\u30F7-\u30FA" \
"\u30FD\u30FE" \
+ "\u{105C9}" \
+ "\u{105D2}" \
+ "\u{105DA}" \
+ "\u{105E4}" \
"\u{11099}-\u{1109C}" \
"\u{110A5}" \
"\u{110AB}" \
@@ -898,12 +943,23 @@ module UnicodeNormalize # :nodoc:
"\u{11131}\u{11132}" \
"\u{11347}" \
"\u{1134B}\u{1134C}" \
+ "\u{11382}-\u{11385}" \
+ "\u{1138B}" \
+ "\u{1138E}" \
+ "\u{11390}\u{11391}" \
+ "\u{113C2}" \
+ "\u{113C5}" \
+ "\u{113C7}\u{113C8}" \
"\u{114B9}" \
"\u{114BB}\u{114BC}" \
"\u{114BE}" \
"\u{115B8}-\u{115BB}" \
"\u{11935}" \
"\u{11938}" \
+ "\u{1611E}" \
+ "\u{16121}-\u{16129}" \
+ "\u{16D63}" \
+ "\u{16D67}-\u{16D6A}" \
"]?#{accents}+" \
"|#{'' # Hangul syllables with separate trailer
}" \
@@ -1410,7 +1466,7 @@ module UnicodeNormalize # :nodoc:
"\u3280-\u33FF" \
"\uA69C\uA69D" \
"\uA770" \
- "\uA7F2-\uA7F4" \
+ "\uA7F1-\uA7F4" \
"\uA7F8\uA7F9" \
"\uAB5C-\uAB5F" \
"\uAB69" \
@@ -1440,6 +1496,7 @@ module UnicodeNormalize # :nodoc:
"\u{10781}-\u{10785}" \
"\u{10787}-\u{107B0}" \
"\u{107B2}-\u{107BA}" \
+ "\u{1CCD6}-\u{1CCF9}" \
"\u{1D400}-\u{1D454}" \
"\u{1D456}-\u{1D49C}" \
"\u{1D49E}\u{1D49F}" \
@@ -1789,6 +1846,7 @@ module UnicodeNormalize # :nodoc:
"\u0859"=>220,
"\u085A"=>220,
"\u085B"=>220,
+ "\u0897"=>230,
"\u0898"=>230,
"\u0899"=>220,
"\u089A"=>220,
@@ -1967,6 +2025,33 @@ module UnicodeNormalize # :nodoc:
"\u1ACC"=>230,
"\u1ACD"=>230,
"\u1ACE"=>230,
+ "\u1ACF"=>230,
+ "\u1AD0"=>230,
+ "\u1AD1"=>230,
+ "\u1AD2"=>230,
+ "\u1AD3"=>230,
+ "\u1AD4"=>230,
+ "\u1AD5"=>230,
+ "\u1AD6"=>230,
+ "\u1AD7"=>230,
+ "\u1AD8"=>230,
+ "\u1AD9"=>230,
+ "\u1ADA"=>230,
+ "\u1ADB"=>230,
+ "\u1ADC"=>230,
+ "\u1ADD"=>220,
+ "\u1AE0"=>230,
+ "\u1AE1"=>230,
+ "\u1AE2"=>230,
+ "\u1AE3"=>230,
+ "\u1AE4"=>230,
+ "\u1AE5"=>230,
+ "\u1AE6"=>220,
+ "\u1AE7"=>230,
+ "\u1AE8"=>230,
+ "\u1AE9"=>230,
+ "\u1AEA"=>230,
+ "\u1AEB"=>234,
"\u1B34"=>7,
"\u1B44"=>9,
"\u1B6B"=>230,
@@ -2234,8 +2319,15 @@ module UnicodeNormalize # :nodoc:
"\u{10D25}"=>230,
"\u{10D26}"=>230,
"\u{10D27}"=>230,
+ "\u{10D69}"=>230,
+ "\u{10D6A}"=>230,
+ "\u{10D6B}"=>230,
+ "\u{10D6C}"=>230,
+ "\u{10D6D}"=>230,
"\u{10EAB}"=>230,
"\u{10EAC}"=>230,
+ "\u{10EFA}"=>220,
+ "\u{10EFB}"=>220,
"\u{10EFD}"=>220,
"\u{10EFE}"=>220,
"\u{10EFF}"=>220,
@@ -2286,6 +2378,9 @@ module UnicodeNormalize # :nodoc:
"\u{11372}"=>230,
"\u{11373}"=>230,
"\u{11374}"=>230,
+ "\u{113CE}"=>9,
+ "\u{113CF}"=>9,
+ "\u{113D0}"=>9,
"\u{11442}"=>9,
"\u{11446}"=>7,
"\u{1145E}"=>230,
@@ -2313,6 +2408,7 @@ module UnicodeNormalize # :nodoc:
"\u{11D97}"=>9,
"\u{11F41}"=>9,
"\u{11F42}"=>9,
+ "\u{1612F}"=>9,
"\u{16AF0}"=>1,
"\u{16AF1}"=>1,
"\u{16AF2}"=>1,
@@ -2416,6 +2512,13 @@ module UnicodeNormalize # :nodoc:
"\u{1E4ED}"=>232,
"\u{1E4EE}"=>220,
"\u{1E4EF}"=>230,
+ "\u{1E5EE}"=>230,
+ "\u{1E5EF}"=>220,
+ "\u{1E6E3}"=>230,
+ "\u{1E6E6}"=>230,
+ "\u{1E6EE}"=>230,
+ "\u{1E6EF}"=>230,
+ "\u{1E6F5}"=>230,
"\u{1E8D0}"=>220,
"\u{1E8D1}"=>220,
"\u{1E8D2}"=>220,
@@ -3928,6 +4031,8 @@ module UnicodeNormalize # :nodoc:
"\uFB4C"=>"\u05D1\u05BF",
"\uFB4D"=>"\u05DB\u05BF",
"\uFB4E"=>"\u05E4\u05BF",
+ "\u{105C9}"=>"\u{105D2}\u0307",
+ "\u{105E4}"=>"\u{105DA}\u0307",
"\u{1109A}"=>"\u{11099}\u{110BA}",
"\u{1109C}"=>"\u{1109B}\u{110BA}",
"\u{110AB}"=>"\u{110A5}\u{110BA}",
@@ -3935,12 +4040,30 @@ module UnicodeNormalize # :nodoc:
"\u{1112F}"=>"\u{11132}\u{11127}",
"\u{1134B}"=>"\u{11347}\u{1133E}",
"\u{1134C}"=>"\u{11347}\u{11357}",
+ "\u{11383}"=>"\u{11382}\u{113C9}",
+ "\u{11385}"=>"\u{11384}\u{113BB}",
+ "\u{1138E}"=>"\u{1138B}\u{113C2}",
+ "\u{11391}"=>"\u{11390}\u{113C9}",
+ "\u{113C5}"=>"\u{113C2}\u{113C2}",
+ "\u{113C7}"=>"\u{113C2}\u{113B8}",
+ "\u{113C8}"=>"\u{113C2}\u{113C9}",
"\u{114BB}"=>"\u{114B9}\u{114BA}",
"\u{114BC}"=>"\u{114B9}\u{114B0}",
"\u{114BE}"=>"\u{114B9}\u{114BD}",
"\u{115BA}"=>"\u{115B8}\u{115AF}",
"\u{115BB}"=>"\u{115B9}\u{115AF}",
"\u{11938}"=>"\u{11935}\u{11930}",
+ "\u{16121}"=>"\u{1611E}\u{1611E}",
+ "\u{16122}"=>"\u{1611E}\u{16129}",
+ "\u{16123}"=>"\u{1611E}\u{1611F}",
+ "\u{16124}"=>"\u{16129}\u{1611F}",
+ "\u{16125}"=>"\u{1611E}\u{16120}",
+ "\u{16126}"=>"\u{1611E}\u{1611E}\u{1611F}",
+ "\u{16127}"=>"\u{1611E}\u{16129}\u{1611F}",
+ "\u{16128}"=>"\u{1611E}\u{1611E}\u{16120}",
+ "\u{16D68}"=>"\u{16D67}\u{16D67}",
+ "\u{16D69}"=>"\u{16D63}\u{16D67}",
+ "\u{16D6A}"=>"\u{16D63}\u{16D67}\u{16D67}",
"\u{1D15E}"=>"\u{1D157}\u{1D165}",
"\u{1D15F}"=>"\u{1D158}\u{1D165}",
"\u{1D160}"=>"\u{1D158}\u{1D165}\u{1D16E}",
@@ -5839,6 +5962,7 @@ module UnicodeNormalize # :nodoc:
"\uA69C"=>"\u044A",
"\uA69D"=>"\u044C",
"\uA770"=>"\uA76F",
+ "\uA7F1"=>"S",
"\uA7F2"=>"C",
"\uA7F3"=>"F",
"\uA7F4"=>"Q",
@@ -6950,6 +7074,42 @@ module UnicodeNormalize # :nodoc:
"\u{107B8}"=>"\u01C2",
"\u{107B9}"=>"\u{1DF0A}",
"\u{107BA}"=>"\u{1DF1E}",
+ "\u{1CCD6}"=>"A",
+ "\u{1CCD7}"=>"B",
+ "\u{1CCD8}"=>"C",
+ "\u{1CCD9}"=>"D",
+ "\u{1CCDA}"=>"E",
+ "\u{1CCDB}"=>"F",
+ "\u{1CCDC}"=>"G",
+ "\u{1CCDD}"=>"H",
+ "\u{1CCDE}"=>"I",
+ "\u{1CCDF}"=>"J",
+ "\u{1CCE0}"=>"K",
+ "\u{1CCE1}"=>"L",
+ "\u{1CCE2}"=>"M",
+ "\u{1CCE3}"=>"N",
+ "\u{1CCE4}"=>"O",
+ "\u{1CCE5}"=>"P",
+ "\u{1CCE6}"=>"Q",
+ "\u{1CCE7}"=>"R",
+ "\u{1CCE8}"=>"S",
+ "\u{1CCE9}"=>"T",
+ "\u{1CCEA}"=>"U",
+ "\u{1CCEB}"=>"V",
+ "\u{1CCEC}"=>"W",
+ "\u{1CCED}"=>"X",
+ "\u{1CCEE}"=>"Y",
+ "\u{1CCEF}"=>"Z",
+ "\u{1CCF0}"=>"0",
+ "\u{1CCF1}"=>"1",
+ "\u{1CCF2}"=>"2",
+ "\u{1CCF3}"=>"3",
+ "\u{1CCF4}"=>"4",
+ "\u{1CCF5}"=>"5",
+ "\u{1CCF6}"=>"6",
+ "\u{1CCF7}"=>"7",
+ "\u{1CCF8}"=>"8",
+ "\u{1CCF9}"=>"9",
"\u{1D400}"=>"A",
"\u{1D401}"=>"B",
"\u{1D402}"=>"C",
@@ -9242,6 +9402,8 @@ module UnicodeNormalize # :nodoc:
"\u30F1\u3099"=>"\u30F9",
"\u30F2\u3099"=>"\u30FA",
"\u30FD\u3099"=>"\u30FE",
+ "\u{105D2}\u0307"=>"\u{105C9}",
+ "\u{105DA}\u0307"=>"\u{105E4}",
"\u{11099}\u{110BA}"=>"\u{1109A}",
"\u{1109B}\u{110BA}"=>"\u{1109C}",
"\u{110A5}\u{110BA}"=>"\u{110AB}",
@@ -9249,11 +9411,29 @@ module UnicodeNormalize # :nodoc:
"\u{11132}\u{11127}"=>"\u{1112F}",
"\u{11347}\u{1133E}"=>"\u{1134B}",
"\u{11347}\u{11357}"=>"\u{1134C}",
+ "\u{11382}\u{113C9}"=>"\u{11383}",
+ "\u{11384}\u{113BB}"=>"\u{11385}",
+ "\u{1138B}\u{113C2}"=>"\u{1138E}",
+ "\u{11390}\u{113C9}"=>"\u{11391}",
+ "\u{113C2}\u{113C2}"=>"\u{113C5}",
+ "\u{113C2}\u{113B8}"=>"\u{113C7}",
+ "\u{113C2}\u{113C9}"=>"\u{113C8}",
"\u{114B9}\u{114BA}"=>"\u{114BB}",
"\u{114B9}\u{114B0}"=>"\u{114BC}",
"\u{114B9}\u{114BD}"=>"\u{114BE}",
"\u{115B8}\u{115AF}"=>"\u{115BA}",
"\u{115B9}\u{115AF}"=>"\u{115BB}",
"\u{11935}\u{11930}"=>"\u{11938}",
+ "\u{1611E}\u{1611E}"=>"\u{16121}",
+ "\u{1611E}\u{16129}"=>"\u{16122}",
+ "\u{1611E}\u{1611F}"=>"\u{16123}",
+ "\u{16129}\u{1611F}"=>"\u{16124}",
+ "\u{1611E}\u{16120}"=>"\u{16125}",
+ "\u{16121}\u{1611F}"=>"\u{16126}",
+ "\u{16122}\u{1611F}"=>"\u{16127}",
+ "\u{16121}\u{16120}"=>"\u{16128}",
+ "\u{16D67}\u{16D67}"=>"\u{16D68}",
+ "\u{16D63}\u{16D67}"=>"\u{16D69}",
+ "\u{16D69}\u{16D67}"=>"\u{16D6A}",
}.freeze
end
diff --git a/lib/uri/common.rb b/lib/uri/common.rb
index 1115736297..a2fb531631 100644
--- a/lib/uri/common.rb
+++ b/lib/uri/common.rb
@@ -30,6 +30,9 @@ module URI
remove_const(:Parser) if defined?(::URI::Parser)
const_set("Parser", parser.class)
+ remove_const(:PARSER) if defined?(::URI::PARSER)
+ const_set("PARSER", parser)
+
remove_const(:REGEXP) if defined?(::URI::REGEXP)
remove_const(:PATTERN) if defined?(::URI::PATTERN)
if Parser == RFC2396_Parser
@@ -92,6 +95,40 @@ module URI
end
module Schemes # :nodoc:
+ class << self
+ ReservedChars = ".+-"
+ EscapedChars = "\u01C0\u01C1\u01C2"
+ # Use Lo category chars as escaped chars for TruffleRuby, which
+ # does not allow Symbol categories as identifiers.
+
+ def escape(name)
+ unless name and name.ascii_only?
+ return nil
+ end
+ name.upcase.tr(ReservedChars, EscapedChars)
+ end
+
+ def unescape(name)
+ name.tr(EscapedChars, ReservedChars).encode(Encoding::US_ASCII).upcase
+ end
+
+ def find(name)
+ const_get(name, false) if name and const_defined?(name, false)
+ end
+
+ def register(name, klass)
+ unless scheme = escape(name)
+ raise ArgumentError, "invalid character as scheme - #{name}"
+ end
+ const_set(scheme, klass)
+ end
+
+ def list
+ constants.map { |name|
+ [unescape(name.to_s), const_get(name)]
+ }.to_h
+ end
+ end
end
private_constant :Schemes
@@ -104,7 +141,7 @@ module URI
# 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)
+ Schemes.register(scheme, klass)
end
# Returns a hash of the defined schemes:
@@ -122,14 +159,14 @@ module URI
#
# Related: URI.register_scheme.
def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
+ Schemes.list
end
+ # :stopdoc:
INITIAL_SCHEMES = scheme_list
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
+ # :startdoc:
# Returns a new object constructed from the given +scheme+, +arguments+,
# and +default+:
@@ -148,12 +185,10 @@ module URI
# # => #<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
+ const_name = Schemes.escape(scheme)
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 ||= Schemes.find(const_name)
uri_class ||= default
return uri_class.new(scheme, *arguments)
@@ -195,7 +230,7 @@ module URI
# ["fragment", "top"]]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ PARSER.split(uri)
end
# Returns a new \URI object constructed from the given string +uri+:
@@ -205,11 +240,11 @@ module URI
# 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>
#
- # It's recommended to first ::escape string +uri+
+ # It's recommended to first URI::RFC2396_PARSER.escape string +uri+
# if it may contain invalid URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ PARSER.parse(uri)
end
# Merges the given URI strings +str+
@@ -236,7 +271,7 @@ module URI
# # => #<URI::HTTP http://example.com/foo/bar>
#
def self.join(*str)
- DEFAULT_PARSER.join(*str)
+ PARSER.join(*str)
end
#
@@ -265,7 +300,7 @@ module URI
#
def self.extract(str, schemes = nil, &block) # :nodoc:
warn "URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
+ PARSER.extract(str, schemes, &block)
end
#
@@ -302,7 +337,7 @@ module URI
#
def self.regexp(schemes = nil)# :nodoc:
warn "URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
+ PARSER.make_regexp(schemes)
end
TBLENCWWWCOMP_ = {} # :nodoc:
@@ -407,6 +442,8 @@ module URI
_decode_uri_component(/%\h\h/, str, enc)
end
+ # Returns a string derived from the given string +str+ with
+ # URI-encoded characters matching +regexp+ according to +table+.
def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
@@ -421,6 +458,8 @@ module URI
end
private_class_method :_encode_uri_component
+ # Returns a string decoding characters matching +regexp+ from the
+ # given \URL-encoded string +str+.
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)
@@ -859,6 +898,7 @@ module Kernel
# Returns a \URI object derived from the given +uri+,
# which may be a \URI string or an existing \URI object:
#
+ # require 'uri'
# # Returns a new URI.
# uri = URI('http://github.com/ruby/ruby')
# # => #<URI::HTTP http://github.com/ruby/ruby>
@@ -866,6 +906,8 @@ module Kernel
# URI(uri)
# # => #<URI::HTTP http://github.com/ruby/ruby>
#
+ # You must require 'uri' to use this method.
+ #
def URI(uri)
if uri.is_a?(URI::Generic)
uri
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb
index 07f329e3d1..6a0f638d76 100644
--- a/lib/uri/generic.rb
+++ b/lib/uri/generic.rb
@@ -126,9 +126,9 @@ module URI
end
end
else
- component = self.class.component rescue ::URI::Generic::COMPONENT
+ component = self.component rescue ::URI::Generic::COMPONENT
raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
+ "expected Array of or Hash of components of #{self} (#{component.join(', ')})"
end
tmp << nil
@@ -186,18 +186,18 @@ module URI
if arg_check
self.scheme = scheme
- self.userinfo = userinfo
self.hostname = host
self.port = port
+ self.userinfo = userinfo
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_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
@@ -284,7 +284,7 @@ module URI
# Returns the parser to be used.
#
- # Unless a URI::Parser is defined, DEFAULT_PARSER is used.
+ # Unless the +parser+ is defined, DEFAULT_PARSER is used.
#
def parser
if !defined?(@parser) || !@parser
@@ -315,7 +315,7 @@ module URI
end
#
- # Checks the scheme +v+ component against the URI::Parser Regexp for :SCHEME.
+ # Checks the scheme +v+ component against the +parser+ Regexp for :SCHEME.
#
def check_scheme(v)
if v && parser.regexp[:SCHEME] !~ v
@@ -385,7 +385,7 @@ module URI
#
# Checks the user +v+ component for RFC2396 compliance
- # and against the URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -409,7 +409,7 @@ module URI
#
# Checks the password +v+ component for RFC2396 compliance
- # and against the URI::Parser Regexp for :USERINFO.
+ # and against the +parser+ Regexp for :USERINFO.
#
# Can not have a registry or opaque component defined,
# with a user component defined.
@@ -466,7 +466,7 @@ module URI
#
# uri = URI.parse("http://john:S3nsit1ve@my.example.com")
# uri.user = "sam"
- # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com"
+ # uri.to_s #=> "http://sam@my.example.com"
#
def user=(user)
check_user(user)
@@ -511,7 +511,7 @@ module URI
user, password = split_userinfo(user)
end
@user = user
- @password = password if password
+ @password = password
[@user, @password]
end
@@ -522,7 +522,7 @@ module URI
# See also URI::Generic.user=.
#
def set_user(v)
- set_userinfo(v, @password)
+ set_userinfo(v, nil)
v
end
protected :set_user
@@ -574,6 +574,12 @@ module URI
@password
end
+ # Returns the authority info (array of user, password, host and
+ # port), if any is set. Or returns +nil+.
+ def authority
+ return @user, @password, @host, @port if @user || @password || @host || @port
+ end
+
# Returns the user component after URI decoding.
def decoded_user
URI.decode_uri_component(@user) if @user
@@ -586,7 +592,7 @@ module URI
#
# Checks the host +v+ component for RFC2396 compliance
- # and against the URI::Parser Regexp for :HOST.
+ # and against the +parser+ Regexp for :HOST.
#
# Can not have a registry or opaque component defined,
# with a host component defined.
@@ -615,6 +621,13 @@ module URI
end
protected :set_host
+ # Protected setter for the authority info (+user+, +password+, +host+
+ # and +port+). If +port+ is +nil+, +default_port+ will be set.
+ #
+ protected def set_authority(user, password, host, port = nil)
+ @user, @password, @host, @port = user, password, host, port || self.default_port
+ end
+
#
# == Args
#
@@ -639,6 +652,7 @@ module URI
def host=(v)
check_host(v)
set_host(v)
+ set_userinfo(nil)
v
end
@@ -675,7 +689,7 @@ module URI
#
# Checks the port +v+ component for RFC2396 compliance
- # and against the URI::Parser Regexp for :PORT.
+ # and against the +parser+ Regexp for :PORT.
#
# Can not have a registry or opaque component defined,
# with a port component defined.
@@ -729,6 +743,7 @@ module URI
def port=(v)
check_port(v)
set_port(v)
+ set_userinfo(nil)
port
end
@@ -748,7 +763,7 @@ module URI
#
# Checks the path +v+ component for RFC2396 compliance
- # and against the URI::Parser Regexp
+ # and against the +parser+ Regexp
# for :ABS_PATH and :REL_PATH.
#
# Can not have a opaque component defined,
@@ -853,7 +868,7 @@ module URI
#
# Checks the opaque +v+ component for RFC2396 compliance and
- # against the URI::Parser Regexp for :OPAQUE.
+ # against the +parser+ Regexp for :OPAQUE.
#
# Can not have a host, port, user, or path component defined,
# with an opaque component defined.
@@ -905,7 +920,7 @@ module URI
end
#
- # Checks the fragment +v+ component against the URI::Parser Regexp for :FRAGMENT.
+ # Checks the fragment +v+ component against the +parser+ Regexp for :FRAGMENT.
#
#
# == Args
@@ -1121,7 +1136,7 @@ module URI
base = self.dup
- authority = rel.userinfo || rel.host || rel.port
+ authority = rel.authority
# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
@@ -1134,9 +1149,7 @@ module URI
# 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_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
@@ -1527,7 +1540,7 @@ module URI
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
+ warn 'The environment variable HTTP_PROXY is discouraged. Please use http_proxy instead.', uplevel: 1
end
end
end
diff --git a/lib/uri/http.rb b/lib/uri/http.rb
index 900b132c8c..3c41cd4e93 100644
--- a/lib/uri/http.rb
+++ b/lib/uri/http.rb
@@ -61,6 +61,18 @@ module URI
super(tmp)
end
+ # Do not allow empty host names, as they are not allowed by RFC 3986.
+ def check_host(v)
+ ret = super
+
+ if ret && v.empty?
+ raise InvalidComponentError,
+ "bad component(expected host component): #{v}"
+ end
+
+ ret
+ end
+
#
# == Description
#
diff --git a/lib/uri/rfc2396_parser.rb b/lib/uri/rfc2396_parser.rb
index 75a2d2dbde..cefd126cc6 100644
--- a/lib/uri/rfc2396_parser.rb
+++ b/lib/uri/rfc2396_parser.rb
@@ -67,7 +67,7 @@ module URI
#
# == Synopsis
#
- # URI::Parser.new([opts])
+ # URI::RFC2396_Parser.new([opts])
#
# == Args
#
@@ -86,7 +86,7 @@ module URI
#
# == Examples
#
- # p = URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
+ # p = URI::RFC2396_Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
# u = p.parse("http://example.jp/%uABCD") #=> #<URI::HTTP http://example.jp/%uABCD>
# URI.parse(u.to_s) #=> raises URI::InvalidURIError
#
@@ -108,12 +108,12 @@ module URI
# The Hash of patterns.
#
- # See also URI::Parser.initialize_pattern.
+ # See also #initialize_pattern.
attr_reader :pattern
# The Hash of Regexp.
#
- # See also URI::Parser.initialize_regexp.
+ # See also #initialize_regexp.
attr_reader :regexp
# Returns a split URI against +regexp[:ABS_URI]+.
@@ -202,8 +202,7 @@ module URI
#
# == Usage
#
- # p = URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
+ # URI::RFC2396_PARSER.parse("ldap://ldap.example.com/dc=example?user=john")
# #=> #<URI::LDAP ldap://ldap.example.com/dc=example?user=john>
#
def parse(uri)
@@ -244,7 +243,7 @@ module URI
# If no +block+ given, then returns the result,
# else it calls +block+ for each element in result.
#
- # See also URI::Parser.make_regexp.
+ # See also #make_regexp.
#
def extract(str, schemes = nil)
if block_given?
@@ -263,7 +262,7 @@ module URI
unless schemes
@regexp[:ABS_URI_REF]
else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
+ /(?=(?i:#{Regexp.union(*schemes).source}):)#{@pattern[:X_ABS_URI]}/x
end
end
@@ -524,6 +523,8 @@ module URI
ret
end
+ # Returns +uri+ as-is if it is URI, or convert it to URI if it is
+ # a String.
def convert_to_uri(uri)
if uri.is_a?(URI::Generic)
uri
diff --git a/lib/uri/version.rb b/lib/uri/version.rb
index b6a8ce1543..1f810602eb 100644
--- a/lib/uri/version.rb
+++ b/lib/uri/version.rb
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
- VERSION_CODE = '010003'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
+ VERSION = '1.1.1'.freeze
+ VERSION_CODE = VERSION.split('.').map{|s| s.rjust(2, '0')}.join.freeze
# :startdoc:
end
diff --git a/lib/weakref.rb b/lib/weakref.rb
index f0a7e7b318..c7274f9664 100644
--- a/lib/weakref.rb
+++ b/lib/weakref.rb
@@ -17,7 +17,8 @@ require "delegate"
#
class WeakRef < Delegator
- VERSION = "0.1.3"
+ # The version string
+ VERSION = "0.1.4"
##
# RefError is raised when a referenced object has been recycled by the
diff --git a/lib/yaml.rb b/lib/yaml.rb
index 2cf11fc3df..c6f0f89fd2 100644
--- a/lib/yaml.rb
+++ b/lib/yaml.rb
@@ -66,5 +66,6 @@ YAML = Psych # :nodoc:
#
# Syck can also be found on github: https://github.com/ruby/syck
module YAML
+ # The version of YAML wrapper
LOADER_VERSION = "0.4.0"
end
diff --git a/libexec/erb b/libexec/erb
index 4381671f25..de7d5888c3 100755
--- a/libexec/erb
+++ b/libexec/erb
@@ -90,29 +90,49 @@ class ERB
when '-P'
disable_percent = true
when '--help'
- raise "print this help"
+ raise ''
when /\A-/
- raise "unknown switch #{switch.dump}"
+ raise "Unknown switch: #{switch.dump}"
else
var, val = *switch.split('=', 2)
(variables ||= {})[var] = val
end
end
rescue # usage
- STDERR.puts $!.to_s
- STDERR.puts File.basename($0) +
- " [switches] [var=value...] [inputfile]"
+ message = $!.to_s
+ STDERR.puts message unless message.empty?
+ STDERR.puts 'Usage:'
+ STDERR.puts " #{File.basename($0)} [options] [filepaths]"
STDERR.puts <<EOU
- -x print ruby script
- -n print ruby script with line number
- -v enable verbose mode
- -d set $DEBUG to true
- -r library load a library
- -E ex[:in] set default external/internal encodings
- -U set default encoding to UTF-8
- -T trim_mode specify trim_mode (0..2, -)
- -P disable ruby code evaluation for lines beginning with %
- var=value set variable
+
+Options:
+ -d --debug Set $DEBUG to enable debugging.
+ -E ex[:in] --encoding ex[:in]
+ Set default external and internal encodings.
+ -h --help Print this text and exit.
+ -n Print generated Ruby source code with line numbers;
+ ignored if given without option -x.
+ -P Disable execution tag shorthand (for lines beginning with '%').
+ -r library Load the named library.
+ -T trim_mode Specify trim_mode:
+ '0' means '%'; '1' means '%>'; '2' means '<>'; '-' means '%-'.
+ -U Set default encoding to UTF-8.
+ -v Set $VERBOSE to enable debugging,
+ --version Print ERB version string and exit.
+ -x Print generated Ruby source code.
+ -- Treat all following words as filepaths (not options).
+ name=value Set the variable named name to the given string value.
+
+Filepaths:
+ The erb program reads the text from all files at the filepaths as a single ERB template:
+ plain text, possibly with embedded ERB tags;
+ filepaths may be repeated.
+
+ The pseudo-filepath '-' (hyphen character) specifies the standard input.
+
+ If no filepaths are given, the sole input is the standard input.
+
+See details and examples at https://docs.ruby-lang.org/en/master/erb_executable_md.html
EOU
exit 1
end
diff --git a/load.c b/load.c
index 4023ac03ba..1ee66e2bfc 100644
--- a/load.c
+++ b/load.c
@@ -5,8 +5,10 @@
#include "dln.h"
#include "eval_intern.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/dir.h"
#include "internal/error.h"
+#include "internal/eval.h"
#include "internal/file.h"
#include "internal/hash.h"
#include "internal/load.h"
@@ -19,23 +21,12 @@
#include "ruby/encoding.h"
#include "ruby/util.h"
#include "ractor_core.h"
-
-static VALUE ruby_dln_libmap;
+#include "vm_core.h"
#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() */
@@ -64,10 +55,11 @@ enum expand_type {
string objects in $LOAD_PATH are frozen.
*/
static void
-rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_relative, int *has_non_cache)
+rb_construct_expanded_load_path(rb_box_t *box, enum expand_type type, int *has_relative, int *has_non_cache)
{
- VALUE load_path = vm->load_path;
- VALUE expanded_load_path = vm->expanded_load_path;
+ VALUE load_path = box->load_path;
+ VALUE expanded_load_path = box->expanded_load_path;
+ VALUE snapshot;
VALUE ary;
long i;
@@ -106,108 +98,90 @@ rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_rel
rb_ary_push(ary, rb_fstring(expanded_path));
}
rb_ary_freeze(ary);
- vm->expanded_load_path = ary;
- rb_ary_replace(vm->load_path_snapshot, vm->load_path);
+ box->expanded_load_path = ary;
+ snapshot = box->load_path_snapshot;
+ load_path = box->load_path;
+ rb_ary_replace(snapshot, load_path);
}
static VALUE
-get_expanded_load_path(rb_vm_t *vm)
+get_expanded_load_path(rb_box_t *box)
{
+ VALUE check_cache;
const VALUE non_cache = Qtrue;
+ const VALUE load_path_snapshot = box->load_path_snapshot;
+ const VALUE load_path = box->load_path;
- if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
+ if (!rb_ary_shared_with_p(load_path_snapshot, load_path)) {
/* The load path was modified. Rebuild the expanded load path. */
int has_relative = 0, has_non_cache = 0;
- rb_construct_expanded_load_path(vm, EXPAND_ALL, &has_relative, &has_non_cache);
+ rb_construct_expanded_load_path(box, EXPAND_ALL, &has_relative, &has_non_cache);
if (has_relative) {
- vm->load_path_check_cache = rb_dir_getwd_ospath();
+ box->load_path_check_cache = rb_dir_getwd_ospath();
}
else if (has_non_cache) {
/* Non string object. */
- vm->load_path_check_cache = non_cache;
+ box->load_path_check_cache = non_cache;
}
else {
- vm->load_path_check_cache = 0;
+ box->load_path_check_cache = 0;
}
}
- else if (vm->load_path_check_cache == non_cache) {
+ else if ((check_cache = box->load_path_check_cache) == non_cache) {
int has_relative = 1, has_non_cache = 1;
/* Expand only non-cacheable objects. */
- rb_construct_expanded_load_path(vm, EXPAND_NON_CACHE,
+ rb_construct_expanded_load_path(box, EXPAND_NON_CACHE,
&has_relative, &has_non_cache);
}
- else if (vm->load_path_check_cache) {
+ else if (check_cache) {
int has_relative = 1, has_non_cache = 1;
VALUE cwd = rb_dir_getwd_ospath();
- if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
+ if (!rb_str_equal(check_cache, cwd)) {
/* Current working directory or filesystem encoding was changed.
Expand relative load path and non-cacheable objects again. */
- vm->load_path_check_cache = cwd;
- rb_construct_expanded_load_path(vm, EXPAND_RELATIVE,
+ box->load_path_check_cache = cwd;
+ rb_construct_expanded_load_path(box, EXPAND_RELATIVE,
&has_relative, &has_non_cache);
}
else {
/* Expand only tilde (User HOME) and non-cacheable objects. */
- rb_construct_expanded_load_path(vm, EXPAND_HOME,
+ rb_construct_expanded_load_path(box, EXPAND_HOME,
&has_relative, &has_non_cache);
}
}
- return vm->expanded_load_path;
+ return box->expanded_load_path;
}
VALUE
rb_get_expanded_load_path(void)
{
- return get_expanded_load_path(GET_VM());
-}
-
-static VALUE
-load_path_getter(ID id, VALUE * p)
-{
- rb_vm_t *vm = (void *)p;
- return vm->load_path;
+ return get_expanded_load_path((rb_box_t *)rb_loading_box());
}
static VALUE
-get_loaded_features(rb_vm_t *vm)
+load_path_getter(ID _x, VALUE * _y)
{
- return vm->loaded_features;
-}
-
-static VALUE
-get_loaded_features_realpaths(rb_vm_t *vm)
-{
- return vm->loaded_features_realpaths;
-}
-
-static VALUE
-get_loaded_features_realpath_map(rb_vm_t *vm)
-{
- return vm->loaded_features_realpath_map;
+ return rb_loading_box()->load_path;
}
static VALUE
get_LOADED_FEATURES(ID _x, VALUE *_y)
{
- return get_loaded_features(GET_VM());
+ return rb_loading_box()->loaded_features;
}
static void
-reset_loaded_features_snapshot(rb_vm_t *vm)
+reset_loaded_features_snapshot(const rb_box_t *box)
{
- rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
+ VALUE snapshot = box->loaded_features_snapshot;
+ VALUE loaded_features = box->loaded_features;
+ rb_ary_replace(snapshot, loaded_features);
}
static struct st_table *
-get_loaded_features_index_raw(rb_vm_t *vm)
-{
- return vm->loaded_features_index;
-}
-
-static st_table *
-get_loading_table(rb_vm_t *vm)
+get_loaded_features_index_raw(const rb_box_t *box)
{
- return vm->loading_table;
+ return box->loaded_features_index;
}
static st_data_t
@@ -228,7 +202,7 @@ is_rbext_path(VALUE feature_path)
typedef rb_darray(long) feature_indexes_t;
struct features_index_add_single_args {
- rb_vm_t *vm;
+ const rb_box_t *box;
VALUE offset;
bool rb;
};
@@ -237,7 +211,7 @@ static int
features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
{
struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
- rb_vm_t *vm = args->vm;
+ const rb_box_t *box = args->box;
VALUE offset = args->offset;
bool rb = args->rb;
@@ -245,7 +219,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
VALUE this_feature_index = *value;
if (FIXNUM_P(this_feature_index)) {
- VALUE loaded_features = get_loaded_features(vm);
+ VALUE loaded_features = box->loaded_features;
VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
feature_indexes_t feature_indexes;
@@ -265,7 +239,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
long pos = -1;
if (rb) {
- VALUE loaded_features = get_loaded_features(vm);
+ VALUE loaded_features = box->loaded_features;
for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
long idx = rb_darray_get(feature_indexes, i);
VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
@@ -284,7 +258,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
if (pos >= 0) {
long *ptr = rb_darray_data_ptr(feature_indexes);
long len = rb_darray_size(feature_indexes);
- MEMMOVE(ptr + pos, ptr + pos + 1, long, len - pos - 1);
+ MEMMOVE(ptr + pos + 1, ptr + pos, long, len - pos - 1);
ptr[pos] = FIX2LONG(offset);
}
}
@@ -297,7 +271,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
}
static void
-features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset, bool rb)
+features_index_add_single(const rb_box_t *box, const char* str, size_t len, VALUE offset, bool rb)
{
struct st_table *features_index;
st_data_t short_feature_key;
@@ -305,10 +279,10 @@ features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset
Check_Type(offset, T_FIXNUM);
short_feature_key = feature_key(str, len);
- features_index = get_loaded_features_index_raw(vm);
+ features_index = get_loaded_features_index_raw(box);
struct features_index_add_single_args args = {
- .vm = vm,
+ .box = box,
.offset = offset,
.rb = rb,
};
@@ -325,8 +299,10 @@ features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset
relies on for its fast lookup.
*/
static void
-features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
+features_index_add(const rb_box_t *box, VALUE feature, VALUE offset)
{
+ RUBY_ASSERT(rb_ractor_main_p());
+
const char *feature_str, *feature_end, *ext, *p;
bool rb = false;
@@ -351,14 +327,14 @@ features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
if (p < feature_str)
break;
/* Now *p == '/'. We reach this point for every '/' in `feature`. */
- features_index_add_single(vm, p + 1, feature_end - p - 1, offset, false);
+ features_index_add_single(box, p + 1, feature_end - p - 1, offset, false);
if (ext) {
- features_index_add_single(vm, p + 1, ext - p - 1, offset, rb);
+ features_index_add_single(box, p + 1, ext - p - 1, offset, rb);
}
}
- features_index_add_single(vm, feature_str, feature_end - feature_str, offset, false);
+ features_index_add_single(box, feature_str, feature_end - feature_str, offset, false);
if (ext) {
- features_index_add_single(vm, feature_str, ext - feature_str, offset, rb);
+ features_index_add_single(box, feature_str, ext - feature_str, offset, rb);
}
}
@@ -367,35 +343,33 @@ loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
{
VALUE obj = (VALUE)val;
if (!SPECIAL_CONST_P(obj)) {
- rb_darray_free((void *)obj);
+ rb_darray_free_sized((void *)obj, long);
}
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)
+get_loaded_features_index(const rb_box_t *box)
{
- VALUE features;
int i;
+ VALUE features = box->loaded_features;
+ const VALUE snapshot = box->loaded_features_snapshot;
- if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
+ if (!rb_ary_shared_with_p(snapshot, features)) {
/* The sharing was broken; something (other than us in rb_provide_feature())
modified loaded_features. Rebuild the index. */
- st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
+ st_foreach(box->loaded_features_index, loaded_features_index_clear_i, 0);
- VALUE realpaths = vm->loaded_features_realpaths;
- VALUE realpath_map = vm->loaded_features_realpath_map;
+ VALUE realpaths = box->loaded_features_realpaths;
+ VALUE realpath_map = box->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;
+
+ /* We have to make a copy of features here because the StringValue call
+ * below could call a Ruby method, which could modify $LOADED_FEATURES
+ * and cause it to be corrupt. */
+ features = rb_ary_resurrect(features);
for (i = 0; i < RARRAY_LEN(features); i++) {
VALUE entry, as_str;
as_str = entry = rb_ary_entry(features, i);
@@ -403,11 +377,15 @@ get_loaded_features_index(rb_vm_t *vm)
as_str = rb_fstring(as_str);
if (as_str != entry)
rb_ary_store(features, i, as_str);
- features_index_add(vm, as_str, INT2FIX(i));
+ features_index_add(box, as_str, INT2FIX(i));
+ }
+ /* The user modified $LOADED_FEATURES, so we should restore the changes. */
+ if (!rb_ary_shared_with_p(features, box->loaded_features)) {
+ rb_ary_replace(box->loaded_features, features);
}
- reset_loaded_features_snapshot(vm);
+ reset_loaded_features_snapshot(box);
- features = rb_ary_dup(vm->loaded_features_snapshot);
+ features = box->loaded_features_snapshot;
long j = RARRAY_LEN(features);
for (i = 0; i < j; i++) {
VALUE as_str = rb_ary_entry(features, i);
@@ -421,7 +399,7 @@ get_loaded_features_index(rb_vm_t *vm)
rb_hash_aset(realpath_map, as_str, realpath);
}
}
- return vm->loaded_features_index;
+ return box->loaded_features_index;
}
/* This searches `load_path` for a value such that
@@ -506,7 +484,7 @@ loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
* 'u': unsuffixed
*/
static int
-rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
+rb_feature_p(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
const char *f, *e;
@@ -527,8 +505,8 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
elen = 0;
type = 0;
}
- features = get_loaded_features(vm);
- features_index = get_loaded_features_index(vm);
+ features = box->loaded_features;
+ features_index = get_loaded_features_index(box);
key = feature_key(feature, strlen(feature));
/* We search `features` for an entry such that either
@@ -570,12 +548,13 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
index = rb_darray_get(feature_indexes, i);
}
+ if (index >= RARRAY_LEN(features)) continue;
v = RARRAY_AREF(features, index);
f = StringValuePtr(v);
if ((n = RSTRING_LEN(v)) < len) continue;
if (strncmp(f, feature, len) != 0) {
if (expanded) continue;
- if (!load_path) load_path = get_expanded_load_path(vm);
+ if (!load_path) load_path = get_expanded_load_path((rb_box_t *)box);
if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
continue;
expanded = 1;
@@ -595,14 +574,14 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
}
}
- loading_tbl = get_loading_table(vm);
+ loading_tbl = box->loading_table;
f = 0;
if (!expanded && !rb_is_absolute_path(feature)) {
struct loaded_feature_searching fs;
fs.name = feature;
fs.len = len;
fs.type = type;
- fs.load_path = load_path ? load_path : get_expanded_load_path(vm);
+ fs.load_path = load_path ? load_path : get_expanded_load_path((rb_box_t *)box);
fs.result = 0;
st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
if ((f = fs.result) != 0) {
@@ -657,7 +636,7 @@ rb_provided(const char *feature)
}
static int
-feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
+feature_provided(rb_box_t *box, const char *feature, const char **loading)
{
const char *ext = strrchr(feature, '.');
VALUE fullpath = 0;
@@ -669,15 +648,15 @@ feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
}
if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) {
- if (rb_feature_p(vm, feature, ext, TRUE, FALSE, loading)) return TRUE;
+ if (rb_feature_p(box, feature, ext, TRUE, FALSE, loading)) return TRUE;
return FALSE;
}
else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
- if (rb_feature_p(vm, feature, ext, FALSE, FALSE, loading)) return TRUE;
+ if (rb_feature_p(box, feature, ext, FALSE, FALSE, loading)) return TRUE;
return FALSE;
}
}
- if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading))
+ if (rb_feature_p(box, feature, 0, TRUE, FALSE, loading))
return TRUE;
RB_GC_GUARD(fullpath);
return FALSE;
@@ -686,35 +665,40 @@ feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
int
rb_feature_provided(const char *feature, const char **loading)
{
- return feature_provided(GET_VM(), feature, loading);
+ rb_box_t *box = (rb_box_t *)rb_current_box();
+ return feature_provided(box, feature, loading);
}
static void
-rb_provide_feature(rb_vm_t *vm, VALUE feature)
+rb_provide_feature(const rb_box_t *box, VALUE feature)
{
VALUE features;
- features = get_loaded_features(vm);
+ features = box->loaded_features;
if (OBJ_FROZEN(features)) {
rb_raise(rb_eRuntimeError,
"$LOADED_FEATURES is frozen; cannot append feature");
}
feature = rb_fstring(feature);
- get_loaded_features_index(vm);
+ get_loaded_features_index(box);
// 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_clear(box->loaded_features_snapshot);
rb_ary_push(features, feature);
- features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
- reset_loaded_features_snapshot(vm);
+ features_index_add(box, feature, INT2FIX(RARRAY_LEN(features)-1));
+ reset_loaded_features_snapshot(box);
}
void
rb_provide(const char *feature)
{
- rb_provide_feature(GET_VM(), rb_fstring_cstr(feature));
+ /*
+ * rb_provide() must use rb_current_box to store provided features
+ * in the current box's loaded_features, etc.
+ */
+ rb_provide_feature(rb_current_box(), rb_fstring_cstr(feature));
}
NORETURN(static void load_failed(VALUE));
@@ -735,18 +719,18 @@ realpath_internal_cached(VALUE hash, VALUE path)
static inline void
load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
{
+ const rb_box_t *box = rb_loading_box();
const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
if (!iseq) {
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, fname);
- rb_thread_t *th = rb_ec_thread_ptr(ec);
- VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
+ VALUE realpath_map = box->loaded_features_realpath_map;
if (rb_ruby_prism_p()) {
- pm_parse_result_t result = { 0 };
- result.options.line = 1;
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
result.node.coverage_enabled = 1;
VALUE error = pm_load_parse_file(&result, fname, NULL);
@@ -786,13 +770,15 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
RB_GC_GUARD(v);
}
rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
- rb_iseq_eval(iseq);
+
+ rb_iseq_eval(iseq, box);
}
static inline enum ruby_tag_type
load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
{
enum ruby_tag_type state;
+ rb_box_t *box;
rb_thread_t *th = rb_ec_thread_ptr(ec);
volatile VALUE wrapper = th->top_wrapper;
volatile VALUE self = th->top_self;
@@ -803,7 +789,16 @@ load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
ec->errinfo = Qnil; /* ensure */
/* load in module as toplevel */
- th->top_self = rb_obj_clone(rb_vm_top_self());
+ if (BOX_OBJ_P(load_wrapper)) {
+ box = rb_get_box_t(load_wrapper);
+ if (!box->top_self) {
+ box->top_self = rb_obj_clone(rb_vm_top_self());
+ }
+ th->top_self = box->top_self;
+ }
+ else {
+ th->top_self = rb_obj_clone(rb_vm_top_self());
+ }
th->top_wrapper = load_wrapper;
rb_extend_object(th->top_self, th->top_wrapper);
@@ -838,7 +833,9 @@ raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
static void
rb_load_internal(VALUE fname, VALUE wrap)
{
+ VALUE box_value;
rb_execution_context_t *ec = GET_EC();
+ const rb_box_t *box = rb_loading_box();
enum ruby_tag_type state = TAG_NONE;
if (RTEST(wrap)) {
if (!RB_TYPE_P(wrap, T_MODULE)) {
@@ -846,6 +843,10 @@ rb_load_internal(VALUE fname, VALUE wrap)
}
state = load_wrapping(ec, fname, wrap);
}
+ else if (BOX_OPTIONAL_P(box)) {
+ box_value = box->box_object;
+ state = load_wrapping(ec, fname, box_value);
+ }
else {
load_iseq_eval(ec, fname);
}
@@ -874,6 +875,28 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
if (state != TAG_NONE) *pstate = state;
}
+VALUE
+rb_load_entrypoint(VALUE fname, VALUE wrap)
+{
+ VALUE path, orig_fname;
+
+ orig_fname = rb_get_path_check_to_string(fname);
+ fname = rb_str_encode_ospath(orig_fname);
+ RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
+
+ path = rb_find_file(fname);
+ if (!path) {
+ if (!rb_file_load_ok(RSTRING_PTR(fname)))
+ load_failed(orig_fname);
+ path = fname;
+ }
+ rb_load_internal(path, wrap);
+
+ RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
+
+ return Qtrue;
+}
+
/*
* call-seq:
* load(filename, wrap=false) -> true
@@ -907,32 +930,16 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
static VALUE
rb_f_load(int argc, VALUE *argv, VALUE _)
{
- VALUE fname, wrap, path, orig_fname;
-
+ VALUE fname, wrap;
rb_scan_args(argc, argv, "11", &fname, &wrap);
-
- orig_fname = rb_get_path_check_to_string(fname);
- fname = rb_str_encode_ospath(orig_fname);
- RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
-
- path = rb_find_file(fname);
- if (!path) {
- if (!rb_file_load_ok(RSTRING_PTR(fname)))
- load_failed(orig_fname);
- path = fname;
- }
- rb_load_internal(path, wrap);
-
- RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
-
- return Qtrue;
+ return rb_load_entrypoint(fname, wrap);
}
static char *
-load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
+load_lock(const rb_box_t *box, const char *ftptr, bool warn)
{
st_data_t data;
- st_table *loading_tbl = get_loading_table(vm);
+ st_table *loading_tbl = box->loading_table;
if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
/* partial state */
@@ -974,11 +981,11 @@ release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int exis
}
static void
-load_unlock(rb_vm_t *vm, const char *ftptr, int done)
+load_unlock(const rb_box_t *box, const char *ftptr, int done)
{
if (ftptr) {
st_data_t key = (st_data_t)ftptr;
- st_table *loading_tbl = get_loading_table(vm);
+ st_table *loading_tbl = box->loading_table;
st_update(loading_tbl, key, release_thread_shield, done);
}
@@ -1029,6 +1036,17 @@ rb_f_require(VALUE obj, VALUE fname)
return rb_require_string(fname);
}
+VALUE
+rb_require_relative_entrypoint(VALUE fname)
+{
+ VALUE base = rb_current_realfilepath();
+ if (NIL_P(base)) {
+ rb_loaderror("cannot infer basepath");
+ }
+ base = rb_file_dirname(base);
+ return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
+}
+
/*
* call-seq:
* require_relative(string) -> true or false
@@ -1041,18 +1059,13 @@ rb_f_require(VALUE obj, VALUE fname)
VALUE
rb_f_require_relative(VALUE obj, VALUE fname)
{
- VALUE base = rb_current_realfilepath();
- if (NIL_P(base)) {
- 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_relative_entrypoint(fname);
}
-typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
+typedef int (*feature_func)(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn);
static int
-search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
+search_required(const rb_box_t *box, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
{
VALUE tmp;
char *ext, *ftptr;
@@ -1063,20 +1076,20 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) {
- if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
+ if (rb_feature_p(box, ftptr, ext, TRUE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r';
}
if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
+ if (!rb_feature_p(box, ftptr, ext, TRUE, TRUE, &loading) || loading)
*path = tmp;
return 'r';
}
return 0;
}
else if (IS_SOEXT(ext)) {
- if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
+ if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's';
}
@@ -1085,25 +1098,25 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
OBJ_FREEZE(tmp);
if ((tmp = rb_find_file(tmp)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
+ if (!rb_feature_p(box, ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
return 's';
}
}
else if (IS_DLEXT(ext)) {
- if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
+ if (rb_feature_p(box, ftptr, ext, FALSE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's';
}
if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
+ if (!rb_feature_p(box, ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
return 's';
}
}
}
- else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
+ else if ((ft = rb_feature_p(box, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r';
}
@@ -1112,20 +1125,23 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
// 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) {
- 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.
- // See encinit.c and extinit.c (generated at build-time).
- if (!ext) {
- lookup_name = rb_str_dup(lookup_name);
- rb_str_cat_cstr(lookup_name, ".so");
- }
- ftptr = RSTRING_PTR(lookup_name);
- if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
- *path = rb_filesystem_str_new_cstr(ftptr);
- RB_GC_GUARD(lookup_name);
- return 's';
+ if (!ft && type != loadable_ext_rb) {
+ rb_vm_t *vm = GET_VM();
+ if (vm->static_ext_inits.num_entries) {
+ 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.
+ // See encinit.c and extinit.c (generated at build-time).
+ if (!ext) {
+ lookup_name = rb_str_dup(lookup_name);
+ rb_str_cat_cstr(lookup_name, ".so");
+ }
+ ftptr = RSTRING_PTR(lookup_name);
+ if (st_lookup(&vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
+ *path = rb_filesystem_str_new_cstr(ftptr);
+ RB_GC_GUARD(lookup_name);
+ return 's';
+ }
}
}
@@ -1134,7 +1150,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
if (ft)
goto feature_present;
ftptr = RSTRING_PTR(tmp);
- return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
+ return rb_feature_p(box, ftptr, 0, FALSE, TRUE, 0);
default:
if (ft) {
@@ -1143,7 +1159,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
/* fall through */
case loadable_ext_rb:
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
+ if (rb_feature_p(box, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
break;
*path = tmp;
}
@@ -1161,42 +1177,57 @@ load_failed(VALUE fname)
}
static VALUE
-load_ext(VALUE path)
+load_ext(VALUE path, VALUE fname)
{
+ VALUE loaded = path;
+ const rb_box_t *box = rb_loading_box();
+ VALUE cleanup = 0;
+ if (BOX_USER_P(box)) {
+ loaded = rb_box_local_extension(box->box_object, fname, path, &cleanup);
+ }
rb_scope_visibility_set(METHOD_VISI_PUBLIC);
- return (VALUE)dln_load(RSTRING_PTR(path));
+ void *handle = dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
+ if (cleanup) {
+ rb_box_cleanup_local_extension(cleanup);
+ }
+ RB_GC_GUARD(loaded);
+ RB_GC_GUARD(fname);
+ return (VALUE)handle;
}
-static bool
-run_static_ext_init(rb_vm_t *vm, const char *feature)
+static VALUE
+run_static_ext_init(VALUE vm_ptr, VALUE feature_value)
{
+ rb_vm_t *vm = (rb_vm_t *)vm_ptr;
+ const char *feature = RSTRING_PTR(feature_value);
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 Qtrue;
}
- return false;
+ return Qfalse;
}
static int
-no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
+no_feature_p(const rb_box_t *box, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
return 0;
}
-// Documented in doc/globals.rdoc
+// Documented in doc/language/globals.md
VALUE
rb_resolve_feature_path(VALUE klass, VALUE fname)
{
VALUE path;
int found;
VALUE sym;
+ const rb_box_t *box = rb_loading_box();
fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname);
- found = search_required(GET_VM(), path, &path, no_feature_p);
+ found = search_required(box, path, &path, no_feature_p);
switch (found) {
case 'r':
@@ -1213,14 +1244,14 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
}
static void
-ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
+ext_config_push(rb_thread_t *th, volatile struct rb_ext_config *prev)
{
*prev = th->ext_config;
th->ext_config = (struct rb_ext_config){0};
}
static void
-ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
+ext_config_pop(rb_thread_t *th, volatile struct rb_ext_config *prev)
{
th->ext_config = *prev;
}
@@ -1243,22 +1274,24 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
{
volatile int result = -1;
rb_thread_t *th = rb_ec_thread_ptr(ec);
+ const rb_box_t *box = rb_loading_box();
volatile const struct {
VALUE wrapper, self, errinfo;
rb_execution_context_t *ec;
+ const rb_box_t *box;
} saved = {
th->top_wrapper, th->top_self, ec->errinfo,
- ec,
+ ec, box,
};
enum ruby_tag_type state;
char *volatile ftptr = 0;
VALUE path;
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);
+ VALUE realpaths = box->loaded_features_realpaths;
+ VALUE realpath_map = box->loaded_features_realpath_map;
volatile bool reset_ext_config = false;
- struct rb_ext_config prev_ext_config;
+ volatile struct rb_ext_config prev_ext_config;
path = rb_str_encode_ospath(fname);
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
@@ -1272,18 +1305,18 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
int found;
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
- found = search_required(th->vm, path, &saved_path, rb_feature_p);
+ found = search_required(box, path, &saved_path, rb_feature_p);
RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
path = saved_path;
if (found) {
- if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
+ if (!path || !(ftptr = load_lock(box, RSTRING_PTR(path), warn))) {
result = 0;
}
else if (!*ftptr) {
result = TAG_RETURN;
}
- else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
+ else if (found == 's' && RTEST(rb_vm_call_cfunc_in_box(Qnil, run_static_ext_init, (VALUE)th->vm, path, path, box))) {
result = TAG_RETURN;
}
else if (RTEST(rb_hash_aref(realpaths,
@@ -1299,9 +1332,8 @@ 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 = rb_vm_call_cfunc_in_box(box->top_self, load_ext, path, fname, path, box);
+ rb_hash_aset(box->ruby_dln_libmap, path, PTR2NUM(handle));
break;
}
result = TAG_RETURN;
@@ -1311,13 +1343,14 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
EC_POP_TAG();
ec = saved.ec;
+ box = saved.box;
rb_thread_t *th2 = rb_ec_thread_ptr(ec);
th2->top_self = saved.self;
th2->top_wrapper = saved.wrapper;
if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
path = saved_path;
- if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
+ if (ftptr) load_unlock(box, RSTRING_PTR(path), !state);
if (state) {
if (state == TAG_FATAL || state == TAG_THROW) {
@@ -1343,7 +1376,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
}
if (result == TAG_RETURN) {
- rb_provide_feature(th2->vm, path);
+ rb_provide_feature(box, path);
VALUE real = realpath;
if (real) {
real = rb_fstring(real);
@@ -1360,6 +1393,10 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
int
rb_require_internal_silent(VALUE fname)
{
+ if (!rb_ractor_main_p()) {
+ return NUM2INT(rb_ractor_require(fname, true));
+ }
+
rb_execution_context_t *ec = GET_EC();
return require_internal(ec, fname, 1, false);
}
@@ -1374,7 +1411,7 @@ rb_require_internal(VALUE fname)
int
ruby_require_internal(const char *fname, unsigned int len)
{
- struct RString fake;
+ struct RString fake = {RBASIC_INIT};
VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
rb_execution_context_t *ec = GET_EC();
int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
@@ -1396,7 +1433,7 @@ rb_require_string_internal(VALUE fname, bool resurrect)
// main ractor check
if (!rb_ractor_main_p()) {
if (resurrect) fname = rb_str_resurrect(fname);
- return rb_ractor_require(fname);
+ return rb_ractor_require(fname, false);
}
else {
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
@@ -1416,7 +1453,7 @@ rb_require_string_internal(VALUE fname, bool resurrect)
VALUE
rb_require(const char *fname)
{
- struct RString fake;
+ struct RString fake = {RBASIC_INIT};
VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
return rb_require_string_internal(str, true);
}
@@ -1441,18 +1478,13 @@ register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing
void
ruby_init_ext(const char *name, void (*init)(void))
{
- st_table *inits_table;
rb_vm_t *vm = GET_VM();
+ const rb_box_t *box = rb_loading_box();
- if (feature_provided(vm, name, 0))
+ if (feature_provided((rb_box_t *)box, 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);
+ st_update(&vm->static_ext_inits, (st_data_t)name, register_init_ext, (st_data_t)init);
}
/*
@@ -1488,6 +1520,49 @@ rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
/*
* call-seq:
+ * mod.autoload_relative(const, filename) -> nil
+ *
+ * Registers _filename_ to be loaded (using Kernel::require)
+ * the first time that _const_ (which may be a String or
+ * a symbol) is accessed in the namespace of _mod_. The _filename_
+ * is interpreted as relative to the directory of the file where
+ * autoload_relative is called.
+ *
+ * module A
+ * end
+ * A.autoload_relative(:B, "b.rb")
+ *
+ * If _const_ in _mod_ is defined as autoload, the file name to be
+ * loaded is replaced with _filename_. If _const_ is defined but not
+ * as autoload, does nothing.
+ *
+ * The relative path is converted to an absolute path, which is what
+ * will be returned by Module#autoload? for the constant.
+ *
+ * Raises LoadError if called without file context (e.g., from eval).
+ */
+
+static VALUE
+rb_mod_autoload_relative(VALUE mod, VALUE sym, VALUE file)
+{
+ ID id = rb_to_id(sym);
+ VALUE base, absolute_path;
+
+ FilePathValue(file);
+
+ base = rb_current_realfilepath();
+ if (NIL_P(base)) {
+ rb_loaderror("cannot infer basepath (autoload_relative called without file context)");
+ }
+ base = rb_file_dirname(base);
+ absolute_path = rb_file_absolute_path(file, base);
+
+ rb_autoload_str(mod, id, absolute_path);
+ return Qnil;
+}
+
+/*
+ * call-seq:
* mod.autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
@@ -1555,6 +1630,38 @@ rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
/*
* call-seq:
+ * autoload_relative(const, filename) -> nil
+ *
+ * Registers _filename_ to be loaded (using Kernel::require)
+ * the first time that _const_ (which may be a String or
+ * a symbol) is accessed. The _filename_ is interpreted as
+ * relative to the directory of the file where autoload_relative
+ * is called.
+ *
+ * autoload_relative(:MyModule, "my_module.rb")
+ *
+ * If _const_ is defined as autoload, the file name to be loaded is
+ * replaced with _filename_. If _const_ is defined but not as
+ * autoload, does nothing.
+ *
+ * The relative path is converted to an absolute path, which is what
+ * will be returned by Kernel#autoload? for the constant.
+ *
+ * Raises LoadError if called without file context (e.g., from eval).
+ */
+
+static VALUE
+rb_f_autoload_relative(VALUE obj, VALUE sym, VALUE file)
+{
+ VALUE klass = rb_class_real(rb_vm_cbase());
+ if (!klass) {
+ rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
+ }
+ return rb_mod_autoload_relative(klass, sym, file);
+}
+
+/*
+ * call-seq:
* autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
@@ -1593,8 +1700,9 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
VALUE handle;
VALUE resolved;
VALUE path;
- char *ext;
+ const char *ext;
VALUE fname_str = rb_str_new_cstr(fname);
+ const rb_box_t *box = rb_loading_box();
resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
if (NIL_P(resolved)) {
@@ -1602,7 +1710,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
if (!ext || !IS_SOEXT(ext)) {
rb_str_cat_cstr(fname_str, ".so");
}
- if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
+ if (rb_feature_p(box, fname, 0, FALSE, FALSE, 0)) {
return dln_symbol(NULL, symbol);
}
return NULL;
@@ -1611,47 +1719,36 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
return NULL;
}
path = rb_ary_entry(resolved, 1);
- handle = rb_hash_lookup(ruby_dln_libmap, path);
+ handle = rb_hash_lookup(box->ruby_dln_libmap, path);
if (NIL_P(handle)) {
return NULL;
}
- return dln_symbol((void *)NUM2SVALUE(handle), symbol);
+ return dln_symbol(NUM2PTR(handle), symbol);
}
void
Init_load(void)
{
- rb_vm_t *vm = GET_VM();
static const char var_load_path[] = "$:";
ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
- rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
+ rb_define_hooked_variable(var_load_path, 0, load_path_getter, rb_gvar_readonly_setter);
+ rb_gvar_box_ready(var_load_path);
rb_alias_variable(rb_intern_const("$-I"), id_load_path);
rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
- vm->load_path = rb_ary_new();
- vm->expanded_load_path = rb_ary_hidden_new(0);
- vm->load_path_snapshot = rb_ary_hidden_new(0);
- vm->load_path_check_cache = 0;
- rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
- rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
- vm->loaded_features = rb_ary_new();
- vm->loaded_features_snapshot = rb_ary_hidden_new(0);
- 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_gvar_box_ready("$\"");
+ rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); // TODO: rb_alias_variable ?
+ rb_gvar_box_ready("$LOADED_FEATURES");
rb_define_global_function("load", rb_f_load, -1);
rb_define_global_function("require", rb_f_require, 1);
rb_define_global_function("require_relative", rb_f_require_relative, 1);
rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
+ rb_define_method(rb_cModule, "autoload_relative", rb_mod_autoload_relative, 2);
rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
rb_define_global_function("autoload", rb_f_autoload, 2);
+ rb_define_global_function("autoload_relative", rb_f_autoload_relative, 2);
rb_define_global_function("autoload?", rb_f_autoload_p, -1);
-
- ruby_dln_libmap = rb_hash_new_with_size(0);
- rb_vm_register_global_object(ruby_dln_libmap);
}
diff --git a/man/erb.1 b/man/erb.1
index d8739a7639..38a4c14ea4 100644
--- a/man/erb.1
+++ b/man/erb.1
@@ -1,6 +1,6 @@
.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.jp>.
-.Dd December 16, 2018
-.Dt ERB \&1 "Ruby Programmer's Reference Guide"
+.Dd March 27, 2026
+.Dt ERB 1 "Ruby Programmer's Reference Guide"
.Os UNIX
.Sh NAME
.Nm erb
diff --git a/man/goruby.1 b/man/goruby.1
index a305a5afce..732ecaa663 100644
--- a/man/goruby.1
+++ b/man/goruby.1
@@ -1,6 +1,6 @@
.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.jp>.
-.Dd April 20, 2017
-.Dt GORUBY \&1 "Ruby Programmer's Reference Guide"
+.Dd March 27, 2026
+.Dt GORUBY 1 "Ruby Programmer's Reference Guide"
.Os UNIX
.Sh NAME
.Nm goruby
diff --git a/man/ruby.1 b/man/ruby.1
index 28d7ddadfa..bc776b8946 100644
--- a/man/ruby.1
+++ b/man/ruby.1
@@ -1,6 +1,6 @@
.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.jp>.
-.Dd April 14, 2018
-.Dt RUBY \&1 "Ruby Programmer's Reference Guide"
+.Dd March 27, 2026
+.Dt RUBY 1 "Ruby Programmer's Reference Guide"
.Os UNIX
.Sh NAME
.Nm ruby
@@ -287,6 +287,8 @@ to the standard output.
.It Fl -debug
Turns on debug mode.
.Li "$DEBUG"
+and
+.Li "$VERBOSE"
will be set to true.
.Pp
.It Fl e Ar command
@@ -521,6 +523,13 @@ variable is not defined, Ruby refers to
If set, Ruby tries to free all dynamically allocated memories.
Introduced in Ruby 3.3, default: unset.
.Pp
+.It Ev RUBY_BOX
+If set to
+.Li 1 ,
+Ruby Box is enabled and users will be able to execute
+.Li Ruby::Box.new .
+Ruby Box is an experimental feature introduced in Ruby 4.0.
+.Pp
.It Ev RUBY_IO_BUFFER_DEFAULT_SIZE
The custom default buffer size of
.Li IO::Buffer .
@@ -691,6 +700,16 @@ Frees stacks of pooled fibers, if set to 1.
Do not free the stacks if set to 0.
Introduced in Ruby 2.7, default: 1 (no growth)
.Pp
+.It Ev RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT
+If set to a non-negative integer, the shared fiber pool cannot allocate more
+than that many stacks; further fiber creation may fail with
+.Va FiberError .
+Unset or 0 means no explicit cap (subject to process limits).
+.Pp
+.It Ev RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT
+Initial and minimum growth chunk size for the shared fiber pool (stacks).
+Unset uses the implementation default.
+.Pp
.El
.Sh STACK SIZE ENVIRONMENT
Stack size environment variables are implementation-dependent and
diff --git a/marshal.c b/marshal.c
index c1b19a6e63..e6ee3b47b0 100644
--- a/marshal.c
+++ b/marshal.c
@@ -30,6 +30,7 @@
#include "internal/hash.h"
#include "internal/numeric.h"
#include "internal/object.h"
+#include "internal/re.h"
#include "internal/struct.h"
#include "internal/symbol.h"
#include "internal/util.h"
@@ -40,6 +41,7 @@
#include "ruby/util.h"
#include "builtin.h"
#include "shape.h"
+#include "ruby/internal/attr/nonstring.h"
#define BITSPERSHORT (2*CHAR_BIT)
#define SHORTMASK ((1<<BITSPERSHORT)-1)
@@ -144,12 +146,14 @@ rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE),
compat_allocator_table();
compat = ALLOC(marshal_compat_t);
- RB_OBJ_WRITE(compat_allocator_tbl_wrapper, &compat->newclass, newclass);
- RB_OBJ_WRITE(compat_allocator_tbl_wrapper, &compat->oldclass, oldclass);
+ compat->newclass = newclass;
+ compat->oldclass = oldclass;
compat->dumper = dumper;
compat->loader = loader;
st_insert(compat_allocator_table(), (st_data_t)allocator, (st_data_t)compat);
+ RB_OBJ_WRITTEN(compat_allocator_tbl_wrapper, Qundef, newclass);
+ RB_OBJ_WRITTEN(compat_allocator_tbl_wrapper, Qundef, oldclass);
}
struct dump_arg {
@@ -459,6 +463,31 @@ w_float(double d, struct dump_arg *arg)
}
}
+
+static VALUE
+w_encivar(VALUE str, struct dump_arg *arg)
+{
+ VALUE encname = encoding_name(str, arg);
+ if (NIL_P(encname) ||
+ is_ascii_string(str)) {
+ return Qnil;
+ }
+ w_byte(TYPE_IVAR, arg);
+ return encname;
+}
+
+static void
+w_encname(VALUE encname, struct dump_arg *arg)
+{
+ if (!NIL_P(encname)) {
+ struct dump_call_arg c_arg;
+ c_arg.limit = 1;
+ c_arg.arg = arg;
+ w_long(1L, arg);
+ w_encoding(encname, &c_arg);
+ }
+}
+
static void
w_symbol(VALUE sym, struct dump_arg *arg)
{
@@ -475,24 +504,11 @@ w_symbol(VALUE sym, struct dump_arg *arg)
if (!sym) {
rb_raise(rb_eTypeError, "can't dump anonymous ID %"PRIdVALUE, sym);
}
- encname = encoding_name(sym, arg);
- if (NIL_P(encname) ||
- is_ascii_string(sym)) {
- encname = Qnil;
- }
- else {
- w_byte(TYPE_IVAR, arg);
- }
+ encname = w_encivar(sym, arg);
w_byte(TYPE_SYMBOL, arg);
w_bytes(RSTRING_PTR(sym), RSTRING_LEN(sym), arg);
st_add_direct(arg->symbols, orig_sym, arg->symbols->num_entries);
- if (!NIL_P(encname)) {
- struct dump_call_arg c_arg;
- c_arg.limit = 1;
- c_arg.arg = arg;
- w_long(1L, arg);
- w_encoding(encname, &c_arg);
- }
+ w_encname(encname, arg);
}
}
@@ -530,7 +546,7 @@ w_extended(VALUE klass, struct dump_arg *arg, int check)
klass = RCLASS_SUPER(klass);
}
while (BUILTIN_TYPE(klass) == T_ICLASS) {
- if (!FL_TEST(klass, RICLASS_IS_ORIGIN) ||
+ if (!RICLASS_IS_ORIGIN_P(klass) ||
BUILTIN_TYPE(RBASIC(klass)->klass) != T_MODULE) {
VALUE path = rb_class_name(RBASIC(klass)->klass);
w_byte(TYPE_EXTENDED, arg);
@@ -712,28 +728,9 @@ has_ivars(VALUE obj, VALUE encname, VALUE *ivobj)
static void
w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg)
{
- shape_id_t shape_id = rb_shape_get_shape_id(arg->obj);
struct w_ivar_arg ivarg = {arg, num};
if (!num) return;
- rb_ivar_foreach(obj, w_obj_each, (st_data_t)&ivarg);
-
- if (shape_id != rb_shape_get_shape_id(arg->obj)) {
- rb_shape_t * expected_shape = rb_shape_get_shape_by_id(shape_id);
- rb_shape_t * actual_shape = rb_shape_get_shape(arg->obj);
-
- // If the shape tree got _shorter_ then we probably removed an IV
- // If the shape tree got longer, then we probably added an IV.
- // The exception message might not be accurate when someone adds and
- // removes the same number of IVs, but they will still get an exception
- if (rb_shape_depth(expected_shape) > rb_shape_depth(actual_shape)) {
- rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance",
- CLASS_OF(arg->obj));
- }
- else {
- rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance",
- CLASS_OF(arg->obj));
- }
- }
+ rb_ivar_foreach_buffered(obj, w_obj_each, (st_data_t)&ivarg);
}
static void
@@ -933,8 +930,9 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivobj);
{
st_data_t compat_data;
- rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass);
- if (st_lookup(compat_allocator_tbl,
+ VALUE klass = CLASS_OF(obj);
+ rb_alloc_func_t allocator = RCLASS_SINGLETON_P(klass) ? 0 : rb_get_alloc_func(klass);
+ if (allocator && st_lookup(compat_allocator_tbl,
(st_data_t)allocator,
&compat_data)) {
marshal_compat_t *compat = (marshal_compat_t*)compat_data;
@@ -954,19 +952,23 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
if (FL_TEST(obj, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "singleton class can't be dumped");
}
- w_byte(TYPE_CLASS, arg);
{
VALUE path = class2path(obj);
+ VALUE encname = w_encivar(path, arg);
+ w_byte(TYPE_CLASS, arg);
w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
+ w_encname(encname, arg);
RB_GC_GUARD(path);
}
break;
case T_MODULE:
- w_byte(TYPE_MODULE, arg);
{
VALUE path = class2path(obj);
+ VALUE encname = w_encivar(path, arg);
+ w_byte(TYPE_MODULE, arg);
w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
+ w_encname(encname, arg);
RB_GC_GUARD(path);
}
break;
@@ -1067,7 +1069,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
case T_STRUCT:
w_class(TYPE_STRUCT, obj, arg, TRUE);
{
- long len = RSTRUCT_LEN(obj);
+ long len = RSTRUCT_LEN_RAW(obj);
VALUE mem;
long i;
@@ -1075,7 +1077,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
mem = rb_struct_members(obj);
for (i=0; i<len; i++) {
w_symbol(RARRAY_AREF(mem, i), arg);
- w_object(RSTRUCT_GET(obj, i), arg, limit);
+ w_object(RSTRUCT_GET_RAW(obj, i), arg, limit);
}
}
break;
@@ -1172,7 +1174,7 @@ io_needed(void)
* * anonymous Class/Module.
* * objects which are related to system (ex: Dir, File::Stat, IO, File, Socket
* and so on)
- * * an instance of MatchData, Data, Method, UnboundMethod, Proc, Thread,
+ * * an instance of MatchData, Method, UnboundMethod, Proc, Thread,
* ThreadGroup, Continuation
* * objects which define singleton methods
*/
@@ -1240,6 +1242,7 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit)
struct load_arg {
VALUE src;
char *buf;
+ long bufsize;
long buflen;
long readable;
long offset;
@@ -1325,15 +1328,23 @@ static unsigned char
r_byte1_buffered(struct load_arg *arg)
{
if (arg->buflen == 0) {
- long readable = arg->readable < BUFSIZ ? arg->readable : BUFSIZ;
+ long readable = arg->readable < arg->bufsize ? arg->readable : arg->bufsize;
+ long read_len;
VALUE str, n = LONG2NUM(readable);
str = load_funcall(arg, arg->src, s_read, 1, &n);
if (NIL_P(str)) too_short();
StringValue(str);
- memcpy(arg->buf, RSTRING_PTR(str), RSTRING_LEN(str));
+ read_len = RSTRING_LEN(str);
+ if (UNLIKELY(read_len < readable)) too_short();
+ if (UNLIKELY(read_len > arg->bufsize)) {
+ arg->buf = ruby_sized_realloc_n(arg->buf, read_len, 1, arg->bufsize);
+ arg->bufsize = read_len;
+ }
+ memcpy(arg->buf, RSTRING_PTR(str), read_len);
arg->offset = 0;
- arg->buflen = RSTRING_LEN(str);
+ arg->buflen = read_len;
+ RB_GC_GUARD(str);
}
arg->buflen--;
return arg->buf[arg->offset++];
@@ -1411,7 +1422,7 @@ long
ruby_marshal_read_long(const char **buf, long len)
{
long x;
- struct RString src;
+ struct RString src = {RBASIC_INIT};
struct load_arg arg;
memset(&arg, 0, sizeof(arg));
arg.src = rb_setup_fake_str(&src, *buf, len, 0);
@@ -1420,6 +1431,18 @@ ruby_marshal_read_long(const char **buf, long len)
return x;
}
+static long
+r_keep_readable(struct load_arg *arg, long len, size_t size)
+{
+ if (UNLIKELY(len < 0)) {
+ rb_raise(rb_eArgError, "negative length");
+ }
+ if (UNLIKELY((unsigned long)len > SIZE_MAX / size || arg->readable >= LONG_MAX - len)) {
+ rb_raise(rb_eArgError, "marshaled data too big");
+ }
+ return len;
+}
+
static VALUE
r_bytes1(long len, struct load_arg *arg)
{
@@ -1449,7 +1472,7 @@ r_bytes1_buffered(long len, struct load_arg *arg)
long tmp_len, read_len, need_len = len - buflen;
VALUE tmp, n;
- readable = readable < BUFSIZ ? readable : BUFSIZ;
+ readable = readable < arg->bufsize ? readable : arg->bufsize;
read_len = need_len > readable ? need_len : readable;
n = LONG2NUM(read_len);
tmp = load_funcall(arg, arg->src, s_read, 1, &n);
@@ -1515,7 +1538,7 @@ name_equal(const char *name, size_t nlen, const char *p, long l)
static int
sym2encidx(VALUE sym, VALUE val)
{
- static const char name_encoding[8] = "encoding";
+ RBIMPL_ATTR_NONSTRING() static const char name_encoding[8] = "encoding";
const char *p;
long l;
if (rb_enc_get_index(sym) != ENCINDEX_US_ASCII) return -1;
@@ -1708,6 +1731,37 @@ r_copy_ivar(VALUE v, VALUE data)
"can't override instance variable of "type" '%"PRIsVALUE"'", \
(str))
+static int
+r_ivar_encoding(VALUE obj, struct load_arg *arg, VALUE sym, VALUE val)
+{
+ int idx = sym2encidx(sym, val);
+ if (idx >= 0) {
+ if (rb_enc_capable(obj)) {
+ // Check if needed to avoid rb_check_frozen() check for Regexps
+ if (rb_enc_get_index(obj) != idx) {
+ rb_enc_associate_index(obj, idx);
+ }
+ }
+ else {
+ rb_raise(rb_eArgError, "%"PRIsVALUE" is not enc_capable", obj);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static long
+r_encname(VALUE obj, struct load_arg *arg)
+{
+ long len = r_long(arg);
+ if (len > 0) {
+ VALUE sym = r_symbol(arg);
+ VALUE val = r_object(arg);
+ len -= r_ivar_encoding(obj, arg, sym, val);
+ }
+ return len;
+}
+
static void
r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
{
@@ -1724,14 +1778,7 @@ r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
do {
VALUE sym = r_symbol(arg);
VALUE val = r_object(arg);
- int idx = sym2encidx(sym, val);
- if (idx >= 0) {
- if (rb_enc_capable(obj)) {
- rb_enc_associate_index(obj, idx);
- }
- else {
- rb_raise(rb_eArgError, "%"PRIsVALUE" is not enc_capable", obj);
- }
+ if (r_ivar_encoding(obj, arg, sym, val)) {
if (has_encoding) *has_encoding = TRUE;
}
else if (symname_equal_lit(sym, name_s_ruby2_keywords_flag)) {
@@ -1816,17 +1863,17 @@ append_extmod(VALUE obj, VALUE extmod)
override_ivar_error(type, str); \
} while (0)
-static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type);
+static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE extmod, int type);
static VALUE
r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
{
int type = r_byte(arg);
- return r_object_for(arg, partial, ivp, extmod, type);
+ return r_object_for(arg, partial, ivp, 0, extmod, type);
}
static VALUE
-r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
+r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE extmod, int type)
{
VALUE (*hash_new_with_size)(st_index_t) = rb_hash_new_with_size;
VALUE v = Qnil;
@@ -1841,6 +1888,9 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
}
v = (VALUE)link;
if (!st_lookup(arg->partial_objects, (st_data_t)v, &link)) {
+ if (arg->freeze && RB_TYPE_P(v, T_STRING)) {
+ v = rb_str_to_interned_str(v);
+ }
v = r_post_proc(v, arg);
}
break;
@@ -1899,12 +1949,12 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
}
type = r_byte(arg);
if ((c == rb_cHash) &&
- /* Hack for compare_by_identify */
+ /* Hack for compare_by_identity */
(type == TYPE_HASH || type == TYPE_HASH_DEF)) {
hash_new_with_size = rb_ident_hash_new_with_size;
goto type_hash;
}
- v = r_object_for(arg, partial, 0, extmod, type);
+ v = r_object_for(arg, partial, 0, c, extmod, type);
if (RB_SPECIAL_CONST_P(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
goto format_error;
}
@@ -1976,7 +2026,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
int sign;
sign = r_byte(arg);
- len = r_long(arg);
+ if (sign != '+' && sign != '-') {
+ rb_raise(rb_eArgError, "invalid Bignum sign");
+ }
+ len = r_keep_readable(arg, r_long(arg), 2);
if (SIZEOF_VALUE >= 8 && len <= 4) {
// Representable within uintptr, likely FIXNUM
@@ -2041,7 +2094,10 @@ 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);
+ if (!klass) {
+ klass = rb_cRegexp;
+ }
+ VALUE regexp = rb_reg_init_str(rb_reg_s_alloc(klass), str, options);
r_copy_ivar(regexp, str);
v = r_entry0(regexp, idx, arg);
@@ -2051,7 +2107,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
case TYPE_ARRAY:
{
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 1);
v = rb_ary_new2(len);
v = r_entry(v, arg);
@@ -2069,7 +2125,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
case TYPE_HASH_DEF:
type_hash:
{
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 2);
v = hash_new_with_size(len);
v = r_entry(v, arg);
@@ -2095,7 +2151,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
VALUE slot;
st_index_t idx = r_prepare(arg);
VALUE klass = path2class(r_unique(arg));
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 2);
v = rb_obj_alloc(klass);
if (!RB_TYPE_P(v, T_STRUCT)) {
@@ -2255,6 +2311,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
{
VALUE str = r_bytes(arg);
+ if (ivp && *ivp > 0) *ivp = r_encname(str, arg) > 0;
v = path2class(str);
prohibit_ivar("class", str);
v = r_entry(v, arg);
@@ -2266,6 +2323,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
{
VALUE str = r_bytes(arg);
+ if (ivp && *ivp > 0) *ivp = r_encname(str, arg) > 0;
v = path2module(str);
prohibit_ivar("module", str);
v = r_entry(v, arg);
@@ -2310,8 +2368,9 @@ r_object(struct load_arg *arg)
static void
clear_load_arg(struct load_arg *arg)
{
- xfree(arg->buf);
+ ruby_xfree_sized(arg->buf, arg->bufsize);
arg->buf = NULL;
+ arg->bufsize = 0;
arg->buflen = 0;
arg->offset = 0;
arg->readable = 0;
@@ -2357,10 +2416,14 @@ rb_marshal_load_with_proc(VALUE port, VALUE proc, bool freeze)
arg->readable = 0;
arg->freeze = freeze;
- if (NIL_P(v))
+ if (NIL_P(v)) {
+ arg->bufsize = BUFSIZ;
arg->buf = xmalloc(BUFSIZ);
- else
+ }
+ else {
+ arg->bufsize = 0;
arg->buf = 0;
+ }
major = r_byte(arg);
minor = r_byte(arg);
@@ -2532,25 +2595,25 @@ Init_marshal(void)
}
static int
-marshal_compat_table_mark_i(st_data_t key, st_data_t value, st_data_t _)
+marshal_compat_table_mark_and_move_i(st_data_t key, st_data_t value, st_data_t _)
{
marshal_compat_t *p = (marshal_compat_t *)value;
- rb_gc_mark_movable(p->newclass);
- rb_gc_mark_movable(p->oldclass);
+ rb_gc_mark_and_move(&p->newclass);
+ rb_gc_mark_and_move(&p->oldclass);
return ST_CONTINUE;
}
static void
-marshal_compat_table_mark(void *tbl)
+marshal_compat_table_mark_and_move(void *tbl)
{
if (!tbl) return;
- st_foreach(tbl, marshal_compat_table_mark_i, 0);
+ st_foreach(tbl, marshal_compat_table_mark_and_move_i, 0);
}
static int
marshal_compat_table_free_i(st_data_t key, st_data_t value, st_data_t _)
{
- xfree((marshal_compat_t *)value);
+ SIZED_FREE((marshal_compat_t *)value);
return ST_CONTINUE;
}
@@ -2567,29 +2630,13 @@ marshal_compat_table_memsize(const void *data)
return st_memsize(data) + sizeof(marshal_compat_t) * st_table_size(data);
}
-static int
-marshal_compat_table_compact_i(st_data_t key, st_data_t value, st_data_t _)
-{
- marshal_compat_t *p = (marshal_compat_t *)value;
- p->newclass = rb_gc_location(p->newclass);
- p->oldclass = rb_gc_location(p->oldclass);
- return ST_CONTINUE;
-}
-
-static void
-marshal_compat_table_compact(void *tbl)
-{
- if (!tbl) return;
- st_foreach(tbl, marshal_compat_table_compact_i, 0);
-}
-
static const rb_data_type_t marshal_compat_type = {
.wrap_struct_name = "marshal_compat_table",
.function = {
- .dmark = marshal_compat_table_mark,
+ .dmark = marshal_compat_table_mark_and_move,
.dfree = marshal_compat_table_free,
.dsize = marshal_compat_table_memsize,
- .dcompact = marshal_compat_table_compact,
+ .dcompact = marshal_compat_table_mark_and_move,
},
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY,
};
diff --git a/math.c b/math.c
index 2394fe9f58..852620da20 100644
--- a/math.c
+++ b/math.c
@@ -15,7 +15,6 @@
# define _USE_MATH_DEFINES 1
#endif
-#include <errno.h>
#include <float.h>
#include <math.h>
@@ -458,6 +457,34 @@ math_exp(VALUE unused_obj, VALUE x)
return DBL2NUM(exp(Get_Double(x)));
}
+/*
+ * call-seq:
+ * Math.expm1(x) -> float
+ *
+ * Returns "exp(x) - 1", +e+ raised to the +x+ power, minus 1.
+ *
+ *
+ * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
+ * - Range: <tt>[-1.0, INFINITY]</tt>.
+ *
+ * Examples:
+ *
+ * expm1(-INFINITY) # => 0.0
+ * expm1(-1.0) # => -0.6321205588285577 # 1.0/E - 1
+ * expm1(0.0) # => 0.0
+ * expm1(0.5) # => 0.6487212707001282 # sqrt(E) - 1
+ * expm1(1.0) # => 1.718281828459045 # E - 1
+ * expm1(2.0) # => 6.38905609893065 # E**2 - 1
+ * expm1(INFINITY) # => Infinity
+ *
+ */
+
+static VALUE
+math_expm1(VALUE unused_obj, VALUE x)
+{
+ return DBL2NUM(expm1(Get_Double(x)));
+}
+
#if defined __CYGWIN__
# include <cygwin/version.h>
# if CYGWIN_VERSION_DLL_MAJOR < 1005
@@ -647,6 +674,47 @@ math_log10(VALUE unused_obj, VALUE x)
return DBL2NUM(log10(d) + numbits * log10(2)); /* log10(d * 2 ** numbits) */
}
+/*
+ * call-seq:
+ * Math.log1p(x) -> float
+ *
+ * Returns "log(x + 1)", the base E {logarithm}[https://en.wikipedia.org/wiki/Logarithm] of (+x+ + 1).
+ *
+ * - Domain: <tt>[-1, INFINITY]</tt>.
+ * - Range: <tt>[-INFINITY, INFINITY]</tt>.
+ *
+ * Examples:
+ *
+ * log1p(-1.0) # => -Infinity
+ * log1p(0.0) # => 0.0
+ * log1p(E - 1) # => 1.0
+ * log1p(INFINITY) # => Infinity
+ *
+ */
+
+static VALUE
+math_log1p(VALUE unused_obj, VALUE x)
+{
+ size_t numbits;
+ double d = get_double_rshift(x, &numbits);
+
+ if (numbits != 0) {
+ x = rb_big_plus(x, INT2FIX(1));
+ d = math_log_split(x, &numbits);
+ /* check for pole error */
+ if (d == 0.0) return DBL2NUM(-HUGE_VAL);
+ d = log(d);
+ d += numbits * M_LN2;
+ return DBL2NUM(d);
+ }
+
+ domain_check_min(d, -1.0, "log1p");
+ /* check for pole error */
+ if (d == -1.0) return DBL2NUM(-HUGE_VAL);
+
+ return DBL2NUM(log1p(d)); /* log10(d * 2 ** numbits) */
+}
+
static VALUE rb_math_sqrt(VALUE x);
/*
@@ -986,7 +1054,7 @@ math_gamma(VALUE unused_obj, VALUE x)
*
* [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
*
- * See {logarithmic gamma function}[https://en.wikipedia.org/wiki/Gamma_function#The_log-gamma_function].
+ * See {log gamma function}[https://en.wikipedia.org/wiki/Gamma_function#Log-gamma_function].
*
* - Domain: <tt>(-INFINITY, INFINITY]</tt>.
* - Range of first element: <tt>(-INFINITY, INFINITY]</tt>.
@@ -1121,9 +1189,11 @@ InitVM_Math(void)
rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
rb_define_module_function(rb_mMath, "exp", math_exp, 1);
+ rb_define_module_function(rb_mMath, "expm1", math_expm1, 1);
rb_define_module_function(rb_mMath, "log", math_log, -1);
rb_define_module_function(rb_mMath, "log2", math_log2, 1);
rb_define_module_function(rb_mMath, "log10", math_log10, 1);
+ rb_define_module_function(rb_mMath, "log1p", math_log1p, 1);
rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
rb_define_module_function(rb_mMath, "cbrt", math_cbrt, 1);
diff --git a/memory_view.c b/memory_view.c
index 519aad2ca1..2de756d681 100644
--- a/memory_view.c
+++ b/memory_view.c
@@ -51,11 +51,11 @@ exported_object_registry_mark(void *ptr)
static void
exported_object_registry_free(void *ptr)
{
- RB_VM_LOCK_ENTER();
- st_clear(exported_object_table);
- st_free_table(exported_object_table);
- exported_object_table = NULL;
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING() {
+ st_clear(exported_object_table);
+ st_free_table(exported_object_table);
+ exported_object_table = NULL;
+ }
}
const rb_data_type_t rb_memory_view_exported_object_registry_data_type = {
@@ -65,7 +65,7 @@ const rb_data_type_t rb_memory_view_exported_object_registry_data_type = {
exported_object_registry_free,
0,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static int
@@ -99,18 +99,19 @@ exported_object_dec_ref(st_data_t *key, st_data_t *val, st_data_t arg, int exist
static void
register_exported_object(VALUE obj)
{
- RB_VM_LOCK_ENTER();
- st_update(exported_object_table, (st_data_t)obj, exported_object_add_ref, 0);
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING() {
+ st_update(exported_object_table, (st_data_t)obj, exported_object_add_ref, 0);
+ RB_OBJ_WRITTEN(rb_memory_view_exported_object_registry, Qundef, obj);
+ }
}
static void
unregister_exported_object(VALUE obj)
{
- RB_VM_LOCK_ENTER();
- if (exported_object_table)
- st_update(exported_object_table, (st_data_t)obj, exported_object_dec_ref, 0);
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING() {
+ if (exported_object_table)
+ st_update(exported_object_table, (st_data_t)obj, exported_object_dec_ref, 0);
+ }
}
// MemoryView
@@ -845,7 +846,7 @@ rb_memory_view_release(rb_memory_view_t* view)
if (rv) {
unregister_exported_object(view->obj);
view->obj = Qnil;
- xfree((void *)view->item_desc.components);
+ SIZED_FREE_N((rb_memory_view_item_component_t *)view->item_desc.components, view->item_desc.length);
}
return rv;
}
diff --git a/method.h b/method.h
index 99ee922335..fdbab41cf7 100644
--- a/method.h
+++ b/method.h
@@ -73,11 +73,18 @@ typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_e
#define METHOD_ENTRY_COMPLEMENTED(me) ((me)->flags & IMEMO_FL_USER3)
#define METHOD_ENTRY_COMPLEMENTED_SET(me) ((me)->flags |= IMEMO_FL_USER3)
#define METHOD_ENTRY_CACHED(me) ((me)->flags & IMEMO_FL_USER4)
-#define METHOD_ENTRY_CACHED_SET(me) ((me)->flags |= IMEMO_FL_USER4)
#define METHOD_ENTRY_INVALIDATED(me) ((me)->flags & IMEMO_FL_USER5)
#define METHOD_ENTRY_INVALIDATED_SET(me) ((me)->flags |= IMEMO_FL_USER5)
static inline void
+METHOD_ENTRY_CACHED_SET(rb_callable_method_entry_t *me)
+{
+ if (!METHOD_ENTRY_CACHED(me)) {
+ me->flags |= IMEMO_FL_USER4;
+ }
+}
+
+static inline void
METHOD_ENTRY_VISI_SET(rb_method_entry_t *me, rb_method_visibility_t visi)
{
VM_ASSERT((int)visi >= 0 && visi <= 3);
@@ -159,8 +166,8 @@ typedef struct rb_method_refined_struct {
typedef struct rb_method_bmethod_struct {
VALUE proc; /* should be marked */
- struct rb_hook_list_struct *hooks;
- VALUE defined_ractor;
+ rb_serial_t defined_ractor_id;
+ unsigned int local_hooks_cnt;
} rb_method_bmethod_t;
enum method_optimized_type {
@@ -197,9 +204,12 @@ struct rb_method_definition_struct {
ID original_id;
uintptr_t method_serial;
+ const rb_box_t *box;
};
struct rb_id_table;
+struct rb_ractor_struct;
+struct rb_hook_list_struct;
typedef struct rb_method_definition_struct rb_method_definition_t;
STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body) <= 8);
@@ -247,12 +257,19 @@ const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
void rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me);
+void rb_method_table_insert0(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me, bool iclass_shared_mtbl);
void rb_scope_visibility_set(rb_method_visibility_t);
VALUE rb_unnamed_parameters(int arity);
+void rb_vm_insert_cc_refinement(const struct rb_callcache *cc);
+
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
void rb_clear_all_refinement_method_cache(void);
+void rb_invalidate_method_caches(struct rb_id_table *cm_tbl, VALUE cc_tbl);
+struct rb_hook_list_struct *rb_method_def_local_hooks(rb_method_definition_t *def, struct rb_ractor_struct *cr, bool create);
+void rb_method_definition_addref(rb_method_definition_t *def);
+void rb_method_definition_release(rb_method_definition_t *def);
#endif /* RUBY_METHOD_H */
diff --git a/mini_builtin.c b/mini_builtin.c
index adcb4f965f..75ea94d37d 100644
--- a/mini_builtin.c
+++ b/mini_builtin.c
@@ -1,5 +1,6 @@
#include "internal.h"
#include "internal/array.h"
+#include "internal/eval.h"
#include "iseq.h"
#include "vm_core.h"
#include "builtin.h"
@@ -22,7 +23,8 @@ prelude_ast_value(VALUE name, VALUE code, int line)
static void
pm_prelude_load(pm_parse_result_t *result, VALUE name, VALUE code, int line)
{
- pm_options_line_set(&result->options, line);
+ pm_parse_result_init(result);
+ pm_options_line_set(result->options, line);
VALUE error = pm_parse_string(result, code, name, NULL);
if (!NIL_P(error)) {
@@ -59,7 +61,7 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
};
if (rb_ruby_prism_p()) {
- pm_parse_result_t result = { 0 };
+ pm_parse_result_t result;
pm_prelude_load(&result, name_str, code, start_line);
vm->builtin_function_table = table;
@@ -99,5 +101,18 @@ void
rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
{
const rb_iseq_t *iseq = builtin_iseq_load(feature_name, table);
- rb_iseq_eval(iseq);
+ rb_iseq_eval(iseq, rb_root_box());
+}
+
+VALUE
+rb_define_gem_modules(VALUE _a, VALUE _b)
+{
+ // do nothing - moniruby doesn't load gem_prelude.rb.
+ return Qnil;
+}
+
+void
+rb_load_gem_prelude(VALUE _)
+{
+ // do nothing - miniruby doesn't support loading RubyGems.
}
diff --git a/misc/.vscode/settings.json b/misc/.vscode/settings.json
index c11838155e..a2e4e1ec69 100644
--- a/misc/.vscode/settings.json
+++ b/misc/.vscode/settings.json
@@ -3,4 +3,8 @@
"disasm",
],
"rust-analyzer.cfg.setTest": false,
+ // rust-analyzer bundled in the VSCode extension may only support Rust newer than 1.85.0.
+ // To avoid warnings, install rust-analyzer with `rustup component add rust-analyzer` and
+ // use `~/.cargo/bin/rust-analyzer` with the following config.
+ "rust-analyzer.server.path": "rust-analyzer",
}
diff --git a/misc/expand_tabs.rb b/misc/expand_tabs.rb
index a94eea5046..d26568eefc 100755
--- a/misc/expand_tabs.rb
+++ b/misc/expand_tabs.rb
@@ -59,53 +59,31 @@ class Git
end
DEFAULT_GEM_LIBS = %w[
- abbrev
- base64
- benchmark
bundler
- cmath
- csv
- debug
delegate
did_you_mean
- drb
english
erb
+ error_highlight
fileutils
find
forwardable
- getoptlong
ipaddr
- irb
- logger
- mutex_m
net-http
net-protocol
- observer
open3
open-uri
optparse
ostruct
pp
prettyprint
- prime
- pstore
- rdoc
- readline
- reline
+ prism
resolv
- resolv-replace
- rexml
- rinda
- rss
rubygems
- scanf
securerandom
- set
shellwords
singleton
tempfile
- thwait
time
timeout
tmpdir
@@ -117,27 +95,19 @@ DEFAULT_GEM_LIBS = %w[
]
DEFAULT_GEM_EXTS = %w[
- bigdecimal
- cgi
date
digest
etc
fcntl
- fiddle
io-console
io-nonblock
io-wait
json
- nkf
openssl
pathname
psych
- racc
- readline-ext
stringio
strscan
- syslog
- win32ole
zlib
]
diff --git a/misc/jit_perf.py b/misc/jit_perf.py
new file mode 100755
index 0000000000..bc0f961b20
--- /dev/null
+++ b/misc/jit_perf.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+import os
+import sys
+from collections import Counter, defaultdict
+import os.path
+
+# Aggregating cycles per symbol and dso
+total_cycles = 0
+category_cycles = Counter()
+detailed_category_cycles = defaultdict(Counter)
+categories = set()
+
+def truncate_symbol(symbol, max_length=50):
+ """ Truncate the symbol name to a maximum length """
+ return symbol if len(symbol) <= max_length else symbol[:max_length-3] + '...'
+
+def categorize_symbol(dso, symbol):
+ """ Categorize the symbol based on the defined criteria """
+ if dso == 'sqlite3_native.so':
+ return '[sqlite3]'
+ elif 'SHA256' in symbol:
+ return '[sha256]'
+ elif symbol.startswith('[JIT] gen_send'):
+ return '[JIT send]'
+ elif symbol.startswith('[JIT]') or symbol.startswith('ZJIT: ') or dso.startswith('perf-'):
+ return '[JIT code]'
+ elif '::' in symbol or symbol.startswith('_ZN4yjit') or symbol.startswith('_ZN4zjit'):
+ return '[JIT compile]'
+ elif symbol.startswith('rb_vm_') or symbol.startswith('vm_') or symbol in {
+ "rb_call0", "callable_method_entry_or_negative", "invoke_block_from_c_bh",
+ "rb_funcallv_scope", "setup_parameters_complex", "rb_yield"}:
+ return '[interpreter]'
+ elif symbol.startswith('rb_hash_') or symbol.startswith('hash_'):
+ return '[rb_hash_*]'
+ elif symbol.startswith('rb_ary_') or symbol.startswith('ary_'):
+ return '[rb_ary_*]'
+ elif symbol.startswith('rb_str_') or symbol.startswith('str_'):
+ return '[rb_str_*]'
+ elif symbol.startswith('rb_sym') or symbol.startswith('sym_'):
+ return '[rb_sym_*]'
+ elif symbol.startswith('rb_st_') or symbol.startswith('st_'):
+ return '[rb_st_*]'
+ elif symbol.startswith('rb_ivar_') or 'shape' in symbol:
+ return '[ivars]'
+ elif 'match' in symbol or symbol.startswith('rb_reg') or symbol.startswith('onig'):
+ return '[regexp]'
+ elif 'alloc' in symbol or 'free' in symbol or 'gc' in symbol:
+ return '[GC]'
+ elif 'pthread' in symbol and 'lock' in symbol:
+ return '[pthread lock]'
+ else:
+ return symbol # Return the symbol itself for uncategorized symbols
+
+def process_event(event):
+ global total_cycles, category_cycles, detailed_category_cycles, categories
+
+ full_dso = event.get("dso", "Unknown_dso")
+ dso = os.path.basename(full_dso)
+ symbol = event.get("symbol", "[unknown]")
+ cycles = event["sample"]["period"]
+ total_cycles += cycles
+
+ category = categorize_symbol(dso, symbol)
+ category_cycles[category] += cycles
+ detailed_category_cycles[category][(dso, symbol)] += cycles
+
+ if category.startswith('[') and category.endswith(']'):
+ categories.add(category)
+
+def trace_end():
+ if total_cycles == 0:
+ return
+
+ print("Aggregated Event Data:")
+ print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol or category]", "[top-most cycle ratio]", "[num cycles]"))
+
+ for category, cycles in category_cycles.most_common():
+ ratio = (cycles / total_cycles) * 100
+ dsos = {dso for dso, _ in detailed_category_cycles[category]}
+ dso_display = next(iter(dsos)) if len(dsos) == 1 else "Multiple DSOs"
+ print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso_display, truncate_symbol(category), ratio, cycles))
+
+ # Category breakdown
+ for category in categories:
+ symbols = detailed_category_cycles[category]
+ category_total = sum(symbols.values())
+ category_ratio = (category_total / total_cycles) * 100
+ print(f"\nCategory: {category} ({category_ratio:.2f}%)")
+ print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol]", "[top-most cycle ratio]", "[num cycles]"))
+ for (dso, symbol), cycles in symbols.most_common():
+ symbol_ratio = (cycles / category_total) * 100
+ print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso, truncate_symbol(symbol), symbol_ratio, cycles))
+
+# There are two ways to use this script:
+# 1) perf script -s misc/yjit_perf.py -- native interface
+# 2) perf script > perf.txt && misc/yjit_perf.py perf.txt -- hack, which doesn't require perf with Python support
+#
+# In both cases, __name__ is "__main__". The following code implements (2) when sys.argv is 2.
+if __name__ == "__main__" and len(sys.argv) == 2:
+ if len(sys.argv) != 2:
+ print("Usage: yjit_perf.py <filename>")
+ sys.exit(1)
+
+ with open(sys.argv[1], "r") as file:
+ for line in file:
+ # [Example]
+ # ruby 78207 3482.848465: 1212775 cpu_core/cycles:P/: 5c0333f682e1 [JIT] getlocal_WC_0+0x0 (/tmp/perf-78207.map)
+ row = line.split(maxsplit=6)
+
+ period = row[3] # "1212775"
+ symbol, dso = row[6].rsplit(" (", 1) # "[JIT] getlocal_WC_0+0x0", "/tmp/perf-78207.map)\n"
+ symbol = symbol.split("+")[0] # "[JIT] getlocal_WC_0"
+ dso = dso.split(")")[0] # "/tmp/perf-78207.map"
+
+ process_event({"dso": dso, "symbol": symbol, "sample": {"period": int(period)}})
+ trace_end()
diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py
index 0707bb42d3..b3d4fb509a 100755..100644
--- a/misc/lldb_cruby.py
+++ b/misc/lldb_cruby.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
#coding: utf-8
#
# Usage: run `command script import -r misc/lldb_cruby.py` on LLDB
@@ -14,6 +13,7 @@ import sys
import shlex
import platform
import glob
+import math
from lldb_rb.constants import *
@@ -67,7 +67,7 @@ class BackTrace:
return self.VM_FRAME_MAGIC_NAME.get(frame_type, "(none)")
def rb_iseq_path_str(self, iseq):
- tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
+ tRBasic = self.target.FindFirstType("::RBasic").GetPointerType()
pathobj = iseq.GetValueForExpressionPath("->body->location.pathobj")
pathobj = pathobj.Cast(tRBasic)
@@ -269,8 +269,7 @@ def lldb_inspect(debugger, target, result, val):
elif num & RUBY_IMMEDIATE_MASK:
print('immediate(%x)' % num, file=result)
else:
- tRBasic = target.FindFirstType("struct RBasic").GetPointerType()
- tRValue = target.FindFirstType("struct RVALUE")
+ tRBasic = target.FindFirstType("::RBasic").GetPointerType()
val = val.Cast(tRBasic)
flags = val.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
@@ -524,10 +523,11 @@ def rb_backtrace(debugger, command, result, internal_dict):
bt.print_bt(val)
def dump_bits(target, result, page, object_address, end = "\n"):
- tRValue = target.FindFirstType("struct RVALUE")
+ slot_size = page.GetChildMemberWithName("heap").GetChildMemberWithName("slot_size").unsigned
+ byte_size = 40 ** math.floor(math.log(slot_size, 40))
tUintPtr = target.FindFirstType("uintptr_t") # bits_t
- num_in_page = (object_address & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
+ num_in_page = (object_address & HEAP_PAGE_ALIGN_MASK) // byte_size;
bits_bitlength = tUintPtr.GetByteSize() * 8
bitmap_index = num_in_page // bits_bitlength
bitmap_offset = num_in_page & (bits_bitlength - 1)
@@ -549,8 +549,7 @@ class HeapPageIter:
self.num_slots = page.GetChildMemberWithName('total_slots').unsigned
self.slot_size = page.GetChildMemberWithName('heap').GetChildMemberWithName('slot_size').unsigned
self.counter = 0
- self.tRBasic = target.FindFirstType("struct RBasic")
- self.tRValue = target.FindFirstType("struct RVALUE")
+ self.tRBasic = target.FindFirstType("::RBasic")
def is_valid(self):
heap_page_header_size = self.target.FindFirstType("struct heap_page_header").GetByteSize()
@@ -582,14 +581,13 @@ def dump_page_internal(page, target, process, thread, frame, result, debugger, h
freelist = []
fl_start = page.GetChildMemberWithName('freelist').GetValueAsUnsigned()
- tRVALUE = target.FindFirstType("struct RVALUE")
+ free_slot = target.FindFirstType("struct free_slot")
while fl_start > 0:
freelist.append(fl_start)
obj_addr = lldb.SBAddress(fl_start, target)
- obj = target.CreateValueFromAddress("object", obj_addr, tRVALUE)
- fl_start = obj.GetChildMemberWithName("as").GetChildMemberWithName("free").GetChildMemberWithName("next").GetValueAsUnsigned()
-
+ obj = target.CreateValueFromAddress("object", obj_addr, free_slot)
+ fl_start = obj.GetChildMemberWithName("next").GetValueAsUnsigned()
page_iter = HeapPageIter(page, target)
if page_iter.is_valid():
diff --git a/misc/lldb_rb/commands/heap_page_command.py b/misc/lldb_rb/commands/heap_page_command.py
index b56a3eae4e..2eed3c3bee 100644
--- a/misc/lldb_rb/commands/heap_page_command.py
+++ b/misc/lldb_rb/commands/heap_page_command.py
@@ -8,14 +8,15 @@ class HeapPageCommand(RbBaseCommand):
help_string = "prints out 'struct heap_page' for a VALUE pointer in the page"
def call(self, debugger, command, exe_ctx, result):
+ self.result = result
self.t_heap_page_body = self.target.FindFirstType("struct heap_page_body")
self.t_heap_page_ptr = self.target.FindFirstType("struct heap_page").GetPointerType()
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_expression("(struct heap_page *) %0#x" % page.GetValueAsUnsigned())
+ self._append_expression("*(struct heap_page *) %0#x" % page.GetValueAsUnsigned())
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
index f28744faa6..bc494ae01a 100644
--- a/misc/lldb_rb/commands/print_flags_command.py
+++ b/misc/lldb_rb/commands/print_flags_command.py
@@ -11,13 +11,13 @@ class PrintFlagsCommand(RbBaseCommand):
# call is where our command logic will be implemented
def call(self, debugger, command, exe_ctx, result):
- rclass_t = self.target.FindFirstType("struct RBasic")
+ rclass_t = self.target.FindFirstType("::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_PROMOTED", "RUBY_FL_FINALIZE",
- "RUBY_FL_SHAREABLE", "RUBY_FL_EXIVAR", "RUBY_FL_FREEZE",
+ "RUBY_FL_SHAREABLE", "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",
diff --git a/misc/lldb_rb/lldb_interface.py b/misc/lldb_rb/lldb_interface.py
index 785a54b3e3..25930b2e16 100644
--- a/misc/lldb_rb/lldb_interface.py
+++ b/misc/lldb_rb/lldb_interface.py
@@ -5,3 +5,14 @@ class LLDBInterface:
self.process = self.target.GetProcess()
self.thread = self.process.GetSelectedThread()
self.frame = self.thread.GetSelectedFrame()
+
+ 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)
diff --git a/misc/lldb_rb/rb_heap_structs.py b/misc/lldb_rb/rb_heap_structs.py
index 86b38dbbbd..798b838080 100644
--- a/misc/lldb_rb/rb_heap_structs.py
+++ b/misc/lldb_rb/rb_heap_structs.py
@@ -1,4 +1,5 @@
import lldb
+import math
from lldb_rb.lldb_interface import LLDBInterface
from lldb_rb.constants import *
@@ -50,8 +51,7 @@ class RbObject(LLDBInterface):
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.tRBasic = self.target.FindFirstType("::RBasic").GetPointerType()
self.val = ptr.Cast(self.tRBasic)
self.page = HeapPage(self.debugger, self.val)
@@ -70,10 +70,12 @@ class RbObject(LLDBInterface):
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();
+ slot_size = self.page.to_heap_page_struct().GetChildMemberWithName("heap").GetChildMemberWithName("slot_size").unsigned
+ byte_size = 40 ** math.floor(math.log(slot_size, 40))
+
+ num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // byte_size;
bits_bitlength = tUintPtr.GetByteSize() * 8
bitmap_index = num_in_page // bits_bitlength
bitmap_offset = num_in_page & (bits_bitlength - 1)
@@ -109,7 +111,14 @@ class RbObject(LLDBInterface):
return False
def as_type(self, type_name):
- return self.val.Cast(self.tRValue.GetPointerType()).GetValueForExpressionPath("->as."+type_name)
+ if type_name == "array":
+ tRarray = self.target.FindFirstType("struct RArray")
+ return self.val.Cast(tRarray.GetPointerType())
+ elif type_name == "bignum":
+ tRbignum = self.target.FindFirstType("struct RBignum")
+ return self.val.Cast(tRbignum.GetPointerType())
+ else:
+ print("as_type is not implemented for:", type_name)
def ary_ptr(self):
rval = self.as_type("array")
diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
index a6bbd385cd..a2bcedc328 100644
--- a/misc/lldb_rb/utils.py
+++ b/misc/lldb_rb/utils.py
@@ -8,17 +8,6 @@ class RbInspector(LLDBInterface):
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():
@@ -247,16 +236,20 @@ class RbInspector(LLDBInterface):
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())
+ type = val.GetValueForExpressionPath("->type").GetValueAsUnsigned()
+ embed = (type & 1)
+ if embed:
+ flaginfo += "[EMBED] "
+ type = self.frame.EvaluateExpression("(rb_data_type_t *)%0#x" % (type & ~1))
+ print("T_DATA: %s%s" %
+ (flaginfo, type.GetValueForExpressionPath("->wrap_struct_name")),
+ file=self.result)
+ print("%s", type.Dereference(), file=self.result)
+ ptr = val.GetValueForExpressionPath("->data")
+ if embed:
+ ptr = ptr.AddressOf()
+ self._append_expression("(void *)%0#x" % ptr.GetValueAsUnsigned())
elif rval.is_type("RUBY_T_IMEMO"):
imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"])
@@ -290,7 +283,7 @@ class RbInspector(LLDBInterface):
# if val.GetType() != tRNode: does not work for unknown reason
- if val.GetType().GetPointeeType().name != "NODE":
+ if val.GetType().GetPointeeType().GetCanonicalType().name != "RNode":
return False
rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
diff --git a/misc/tsan_suppressions.txt b/misc/tsan_suppressions.txt
new file mode 100644
index 0000000000..5492500e7f
--- /dev/null
+++ b/misc/tsan_suppressions.txt
@@ -0,0 +1,109 @@
+# TSan: ThreadSanitizer
+# https://github.com/google/sanitizers/wiki/threadsanitizersuppressions
+#
+# This file describes a number of places where TSAN detects problems in CRuby.
+# Many of these indicate bugs. Others are benign (ex. data races that can be
+# replaced with relaxed atomic loads)
+#
+# Usage:
+# Configure with:
+# ./configure cflags='-fsanitize=thread' CC=clang
+# Build and run with:
+# TSAN_OPTIONS="suppressions=$(pwd)/misc/tsan_suppressions.txt:die_after_fork=0"
+#
+# Other useful TSAN_OPTIONS:
+# * halt_on_error=1
+# * strip_path_prefix=$(pwd)/
+
+# Namespaces
+race_top:push_subclass_entry_to_list
+
+# sub_nounderflow includes non-atomic read, possibly other issue
+race:objspace_malloc_increase_body
+
+# Signals and ubf
+race:unregister_ubf_list
+
+# It's already crashing. We're doing our best
+signal:rb_vm_bugreport
+race:check_reserved_signal_
+
+race_top:rb_check_deadlock
+
+# vm->ractor.sched.grq_cnt++
+race_top:ractor_sched_enq
+race_top:ractor_sched_deq
+
+# Race between vm_remove_ractor writing ractor count and
+# native_thread_check_and_create_shared reading it during thread creation.
+# The write happens when a ractor thread exits, the read happens when
+# checking if new shared threads need to be created.
+race:vm_remove_ractor
+
+# th->sched.finished at end of co_start
+race_top:rb_thread_sched_mark_zombies
+
+# Races against timer thread setting th->sched.waiting_reason.flags
+race_top:thread_sched_wait_events
+
+# At thread start
+race_top:rb_ractor_set_current_ec_
+
+# TSan reports a lock-order-inversion between thread_sched_lock_ and this lock.
+# It's unclear if that can cause a deadlock since the lock is on self
+deadlock:ractor_lock_self
+
+# TSan reports a deadlock when reacquiring the this lock after a barrier, but
+# we know the other threads have been stopped
+deadlock:rb_ractor_sched_barrier_start
+
+# RVALUE_AGE_SET manipulates flag bits on objects which may be accessed in Ractors
+race_top:RVALUE_AGE_SET
+
+# Inline caches and call cache updates
+# Multiple threads can race when updating shared call caches during method lookups
+# and argument forwarding. These races involve reading/writing cd->cc fields.
+race_top:vm_cc_call_set
+race_top:vm_cc_class_check
+race_top:vm_search_cc
+race_top:vm_search_method_slowpath0
+race_top:rb_vm_opt_getconstant_path
+race_top:vm_ic_attr_index_set
+race:vm_ic_update
+race:vm_caller_setup_fwd_args
+
+# Race in shape_get_next where multiple threads simultaneously access and modify
+# RCLASS_MAX_IV_COUNT and RCLASS_VARIATION_COUNT fields in class objects.
+# One thread reads the field while another thread calls RCLASS_SET_MAX_IV_COUNT.
+# This happens during instance variable shape transitions in multi-threaded code.
+race:shape_get_next
+
+# Non-atomic reads/writes
+race:gccct_method_search
+
+# Ignore exit for now
+race:rb_ec_finalize
+race:rb_ec_cleanup
+
+# TSan doesn't work well post-fork, this raises errors when creating the new
+# timer thread
+race:after_fork_ruby
+
+# Sets objspace->flags.dont_incremental while writebarrier may be running
+race_top:objspace_each_exec
+race_top:objspace_each_objects_ensure
+
+# Non-atomic lazy initialized static variable
+race_top:rbimpl_intern_const
+
+# Setting def->aliased bitfield non-atomically
+race_top:method_definition_addref
+
+# Switching to setting up tracing. Likely other ractors should be stopped for this.
+race_top:encoded_iseq_trace_instrument
+race:rb_iseq_trace_set_all
+race:rb_tracepoint_enable
+
+# GC enable/disable flag modifications race with object allocation flag reads
+race_top:rb_gc_impl_gc_disable
+race_top:rb_gc_impl_gc_enable
diff --git a/misc/yjit_perf.py b/misc/yjit_perf.py
deleted file mode 100755
index 61434e5eb4..0000000000
--- a/misc/yjit_perf.py
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env python3
-import os
-import sys
-from collections import Counter, defaultdict
-import os.path
-
-# Aggregating cycles per symbol and dso
-total_cycles = 0
-category_cycles = Counter()
-detailed_category_cycles = defaultdict(Counter)
-categories = set()
-
-def truncate_symbol(symbol, max_length=50):
- """ Truncate the symbol name to a maximum length """
- return symbol if len(symbol) <= max_length else symbol[:max_length-3] + '...'
-
-def categorize_symbol(dso, symbol):
- """ Categorize the symbol based on the defined criteria """
- if dso == 'sqlite3_native.so':
- return '[sqlite3]'
- elif 'SHA256' in symbol:
- return '[sha256]'
- elif symbol.startswith('[JIT] gen_send'):
- return '[JIT send]'
- elif symbol.startswith('[JIT]'):
- return '[JIT code]'
- elif '::' in symbol or symbol.startswith('yjit::') or symbol.startswith('_ZN4yjit'):
- return '[YJIT compile]'
- elif symbol.startswith('rb_vm_') or symbol.startswith('vm_') or symbol in {
- "rb_call0", "callable_method_entry_or_negative", "invoke_block_from_c_bh",
- "rb_funcallv_scope", "setup_parameters_complex", "rb_yield"}:
- return '[interpreter]'
- elif symbol.startswith('rb_hash_') or symbol.startswith('hash_'):
- return '[rb_hash_*]'
- elif symbol.startswith('rb_ary_') or symbol.startswith('ary_'):
- return '[rb_ary_*]'
- elif symbol.startswith('rb_str_') or symbol.startswith('str_'):
- return '[rb_str_*]'
- elif symbol.startswith('rb_sym') or symbol.startswith('sym_'):
- return '[rb_sym_*]'
- elif symbol.startswith('rb_st_') or symbol.startswith('st_'):
- return '[rb_st_*]'
- elif symbol.startswith('rb_ivar_') or 'shape' in symbol:
- return '[ivars]'
- elif 'match' in symbol or symbol.startswith('rb_reg') or symbol.startswith('onig'):
- return '[regexp]'
- elif 'alloc' in symbol or 'free' in symbol or 'gc' in symbol:
- return '[GC]'
- elif 'pthread' in symbol and 'lock' in symbol:
- return '[pthread lock]'
- else:
- return symbol # Return the symbol itself for uncategorized symbols
-
-def process_event(event):
- global total_cycles, category_cycles, detailed_category_cycles, categories
-
- full_dso = event.get("dso", "Unknown_dso")
- dso = os.path.basename(full_dso)
- symbol = event.get("symbol", "[unknown]")
- cycles = event["sample"]["period"]
- total_cycles += cycles
-
- category = categorize_symbol(dso, symbol)
- category_cycles[category] += cycles
- detailed_category_cycles[category][(dso, symbol)] += cycles
-
- if category.startswith('[') and category.endswith(']'):
- categories.add(category)
-
-def trace_end():
- if total_cycles == 0:
- return
-
- print("Aggregated Event Data:")
- print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol or category]", "[top-most cycle ratio]", "[num cycles]"))
-
- for category, cycles in category_cycles.most_common():
- ratio = (cycles / total_cycles) * 100
- dsos = {dso for dso, _ in detailed_category_cycles[category]}
- dso_display = next(iter(dsos)) if len(dsos) == 1 else "Multiple DSOs"
- print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso_display, truncate_symbol(category), ratio, cycles))
-
- # Category breakdown
- for category in categories:
- symbols = detailed_category_cycles[category]
- category_total = sum(symbols.values())
- category_ratio = (category_total / total_cycles) * 100
- print(f"\nCategory: {category} ({category_ratio:.2f}%)")
- print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol]", "[top-most cycle ratio]", "[num cycles]"))
- for (dso, symbol), cycles in symbols.most_common():
- symbol_ratio = (cycles / category_total) * 100
- print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso, truncate_symbol(symbol), symbol_ratio, cycles))
-
-# There are two ways to use this script:
-# 1) perf script -s misc/yjit_perf.py -- native interface
-# 2) perf script > perf.txt && misc/yjit_perf.py perf.txt -- hack, which doesn't require perf with Python support
-#
-# In both cases, __name__ is "__main__". The following code implements (2) when sys.argv is 2.
-if __name__ == "__main__" and len(sys.argv) == 2:
- if len(sys.argv) != 2:
- print("Usage: yjit_perf.py <filename>")
- sys.exit(1)
-
- with open(sys.argv[1], "r") as file:
- for line in file:
- # [Example]
- # ruby 78207 3482.848465: 1212775 cpu_core/cycles:P/: 5c0333f682e1 [JIT] getlocal_WC_0+0x0 (/tmp/perf-78207.map)
- row = line.split(maxsplit=6)
-
- period = row[3] # "1212775"
- symbol, dso = row[6].split(" (") # "[JIT] getlocal_WC_0+0x0", "/tmp/perf-78207.map)\n"
- symbol = symbol.split("+")[0] # "[JIT] getlocal_WC_0"
- dso = dso.split(")")[0] # "/tmp/perf-78207.map"
-
- process_event({"dso": dso, "symbol": symbol, "sample": {"period": int(period)}})
- trace_end()
diff --git a/missing/dtoa.c b/missing/dtoa.c
index 477b212a1b..ba8cd46ebd 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -98,17 +98,6 @@
* if memory is available and otherwise does something you deem
* appropriate. If MALLOC is undefined, malloc will be invoked
* directly -- and assumed always to succeed.
- * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
- * memory allocations from a private pool of memory when possible.
- * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
- * unless #defined to be a different length. This default length
- * suffices to get rid of MALLOC calls except for unusual cases,
- * such as decimal-to-binary conversion of a very long string of
- * digits. The longest string dtoa can return is about 751 bytes
- * long. For conversions by strtod of strings of 800 digits and
- * all dtoa conversions in single-threaded executions with 8-byte
- * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
- * pointers, PRIVATE_MEM >= 7112 appears adequate.
* #define INFNAN_CHECK on IEEE systems to cause strtod to check for
* Infinity and NaN (case insensitively). On some systems (e.g.,
* some HP systems), it may be necessary to #define NAN_WORD0
@@ -221,6 +210,29 @@
#include <locale.h>
#endif
+#if defined(HAVE_STDCKDINT_H) || !defined(__has_include)
+#elif __has_include(<stdckdint.h>)
+# define HAVE_STDCKDINT_H 1
+#endif
+#ifdef HAVE_STDCKDINT_H
+# include <stdckdint.h>
+#endif
+
+#if !defined(ckd_add)
+static inline int /* bool */
+ckd_add(int *result, int x, int y)
+{
+ if (x < 0) {
+ if (y < INT_MIN - x) return 1;
+ }
+ else if (x > 0) {
+ if (y > INT_MAX - x) return 1;
+ }
+ *result = x + y;
+ return 0;
+}
+#endif
+
#ifdef MALLOC
extern void *MALLOC(size_t);
#else
@@ -235,14 +247,6 @@ extern void FREE(void*);
#define NO_SANITIZE(x, y) y
#endif
-#ifndef Omit_Private_Memory
-#ifndef PRIVATE_MEM
-#define PRIVATE_MEM 2304
-#endif
-#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
-static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
-#endif
-
#undef IEEE_Arith
#undef Avoid_Underflow
#ifdef IEEE_BIG_ENDIAN
@@ -527,83 +531,29 @@ struct Bigint {
typedef struct Bigint Bigint;
-static Bigint *freelist[Kmax+1];
-
-#define BLOCKING_BIGINT ((Bigint *)(-1))
-
static Bigint *
Balloc(int k)
{
int x;
Bigint *rv;
-#ifndef Omit_Private_Memory
- size_t len;
-#endif
-
- rv = 0;
- ACQUIRE_DTOA_LOCK(0);
- if (k <= Kmax) {
- rv = freelist[k];
- while (rv) {
- Bigint *rvn = rv;
- rv = ATOMIC_PTR_CAS(freelist[k], rv, BLOCKING_BIGINT);
- if (LIKELY(rv != BLOCKING_BIGINT && rvn == rv)) {
- rvn = ATOMIC_PTR_CAS(freelist[k], BLOCKING_BIGINT, rv->next);
- assert(rvn == BLOCKING_BIGINT);
- ASSUME(rv);
- break;
- }
- }
- }
- if (!rv) {
- x = 1 << k;
-#ifdef Omit_Private_Memory
- rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
-#else
- len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
- /sizeof(double);
- if (k <= Kmax) {
- double *pnext = pmem_next;
- while (pnext - private_mem + len <= PRIVATE_mem) {
- double *p = pnext;
- pnext = ATOMIC_PTR_CAS(pmem_next, pnext, pnext + len);
- if (LIKELY(p == pnext)) {
- rv = (Bigint*)pnext;
- ASSUME(rv);
- break;
- }
- }
- }
- if (!rv)
- rv = (Bigint*)MALLOC(len*sizeof(double));
-#endif
- rv->k = k;
- rv->maxwds = x;
- }
- FREE_DTOA_LOCK(0);
+
+ x = 1 << k;
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+ if (!rv) return NULL;
+ rv->k = k;
+ rv->maxwds = x;
rv->sign = rv->wds = 0;
return rv;
}
static void
-Bfree(Bigint *v)
+Bclear(Bigint **vp)
{
- Bigint *vn;
- if (v) {
- if (v->k > Kmax) {
- FREE(v);
- return;
- }
- ACQUIRE_DTOA_LOCK(0);
- do {
- do {
- vn = ATOMIC_PTR_CAS(freelist[v->k], 0, 0);
- } while (UNLIKELY(vn == BLOCKING_BIGINT));
- v->next = vn;
- } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn));
- FREE_DTOA_LOCK(0);
- }
+ Bigint *v = *vp;
+ *vp = NULL;
+ if (v) FREE(v);
}
+#define Bfree(v) Bclear(&(v))
#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \
(y)->wds*sizeof(Long) + 2*sizeof(int))
@@ -649,6 +599,10 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */
if (carry) {
if (wds >= b->maxwds) {
b1 = Balloc(b->k+1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
Bcopy(b1, b);
Bfree(b);
b = b1;
@@ -670,10 +624,12 @@ s2b(const char *s, int nd0, int nd, ULong y9)
for (k = 0, y = 1; x > y; y <<= 1, k++) ;
#ifdef Pack_32
b = Balloc(k);
+ if (!b) return NULL;
b->x[0] = y9;
b->wds = 1;
#else
b = Balloc(k+1);
+ if (!b) return NULL;
b->x[0] = y9 & 0xffff;
b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
#endif
@@ -683,13 +639,16 @@ s2b(const char *s, int nd0, int nd, ULong y9)
s += 9;
do {
b = multadd(b, 10, *s++ - '0');
+ if (!b) return NULL;
} while (++i < nd0);
s++;
}
else
s += 10;
- for (; i < nd; i++)
+ for (; i < nd; i++) {
b = multadd(b, 10, *s++ - '0');
+ if (!b) return NULL;
+ }
return b;
}
@@ -771,11 +730,14 @@ i2b(int i)
Bigint *b;
b = Balloc(1);
+ if (!b) return NULL;
b->x[0] = i;
b->wds = 1;
return b;
}
+#define Bzero_p(b) (!(b)->x[0] && (b)->wds <= 1)
+
static Bigint *
mult(Bigint *a, Bigint *b)
{
@@ -792,6 +754,14 @@ mult(Bigint *a, Bigint *b)
#endif
#endif
+ if (Bzero_p(a) || Bzero_p(b)) {
+ c = Balloc(0);
+ if (!c) return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+
if (a->wds < b->wds) {
c = a;
a = b;
@@ -804,6 +774,7 @@ mult(Bigint *a, Bigint *b)
if (wc > a->maxwds)
k++;
c = Balloc(k);
+ if (!c) return NULL;
for (x = c->x, xa = x + wc; x < xa; x++)
*x = 0;
xa = a->x;
@@ -883,50 +854,47 @@ static Bigint *
pow5mult(Bigint *b, int k)
{
Bigint *b1, *p5, *p51;
- Bigint *p5tmp;
int i;
static const int p05[3] = { 5, 25, 125 };
- if ((i = k & 3) != 0)
+ if ((i = k & 3) != 0) {
b = multadd(b, p05[i-1], 0);
+ if (!b) return NULL;
+ }
+
+#define b_cache(var, addr, new_expr) \
+ if ((var = addr) != 0) {} else { \
+ Bigint *tmp = 0; \
+ ACQUIRE_DTOA_LOCK(1); \
+ if (!(var = addr) && (var = (new_expr)) != 0) { \
+ var->next = 0; \
+ tmp = ATOMIC_PTR_CAS(addr, NULL, var); \
+ } \
+ FREE_DTOA_LOCK(1); \
+ if (UNLIKELY(tmp)) { \
+ Bfree(var); \
+ var = tmp; \
+ } \
+ else if (!var) { \
+ Bfree(b); \
+ return NULL; \
+ } \
+ }
if (!(k >>= 2))
return b;
- if (!(p5 = p5s)) {
- /* first time */
- ACQUIRE_DTOA_LOCK(1);
- if (!(p5 = p5s)) {
- p5 = i2b(625);
- p5->next = 0;
- p5tmp = ATOMIC_PTR_CAS(p5s, NULL, p5);
- if (UNLIKELY(p5tmp)) {
- Bfree(p5);
- p5 = p5tmp;
- }
- }
- FREE_DTOA_LOCK(1);
- }
+ /* first time */
+ b_cache(p5, p5s, i2b(625));
for (;;) {
if (k & 1) {
b1 = mult(b, p5);
Bfree(b);
b = b1;
+ if (!b) return NULL;
}
if (!(k >>= 1))
break;
- if (!(p51 = p5->next)) {
- ACQUIRE_DTOA_LOCK(1);
- if (!(p51 = p5->next)) {
- p51 = mult(p5,p5);
- p51->next = 0;
- p5tmp = ATOMIC_PTR_CAS(p5->next, NULL, p51);
- if (UNLIKELY(p5tmp)) {
- Bfree(p51);
- p51 = p5tmp;
- }
- }
- FREE_DTOA_LOCK(1);
- }
+ b_cache(p51, p5->next, mult(p5, p5));
p5 = p51;
}
return b;
@@ -939,6 +907,8 @@ lshift(Bigint *b, int k)
Bigint *b1;
ULong *x, *x1, *xe, z;
+ if (!k || Bzero_p(b)) return b;
+
#ifdef Pack_32
n = k >> 5;
#else
@@ -949,6 +919,10 @@ lshift(Bigint *b, int k)
for (i = b->maxwds; n1 > i; i <<= 1)
k1++;
b1 = Balloc(k1);
+ if (!b1) {
+ Bfree(b);
+ return NULL;
+ }
x1 = b1->x;
for (i = 0; i < n; i++)
*x1++ = 0;
@@ -1034,6 +1008,7 @@ diff(Bigint *a, Bigint *b)
i = cmp(a,b);
if (!i) {
c = Balloc(0);
+ if (!c) return NULL;
c->wds = 1;
c->x[0] = 0;
return c;
@@ -1047,6 +1022,7 @@ diff(Bigint *a, Bigint *b)
else
i = 0;
c = Balloc(a->k);
+ if (!c) return NULL;
c->sign = i;
wa = a->wds;
xa = a->x;
@@ -1232,6 +1208,7 @@ d2b(double d_, int *e, int *bits)
#else
b = Balloc(2);
#endif
+ if (!b) return NULL;
x = b->x;
z = d0 & Frac_mask;
@@ -1982,12 +1959,16 @@ undfl:
/* Put digits into bd: true value = bd * 10^e */
bd0 = s2b(s0, nd0, nd, y);
+ if (!bd0) goto ret;
for (;;) {
bd = Balloc(bd0->k);
+ if (!bd) goto retfree;
Bcopy(bd, bd0);
bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
+ if (!bb) goto retfree;
bs = i2b(1);
+ if (!bs) goto retfree;
if (e >= 0) {
bb2 = bb5 = 0;
@@ -2044,19 +2025,30 @@ undfl:
}
if (bb5 > 0) {
bs = pow5mult(bs, bb5);
+ if (!bs) goto retfree;
bb1 = mult(bs, bb);
Bfree(bb);
bb = bb1;
+ if (!bb) goto retfree;
}
- if (bb2 > 0)
+ if (bb2 > 0) {
bb = lshift(bb, bb2);
- if (bd5 > 0)
+ if (!bb) goto retfree;
+ }
+ if (bd5 > 0) {
bd = pow5mult(bd, bd5);
- if (bd2 > 0)
+ if (!bd) goto retfree;
+ }
+ if (bd2 > 0) {
bd = lshift(bd, bd2);
- if (bs2 > 0)
+ if (!bd) goto retfree;
+ }
+ if (bs2 > 0) {
bs = lshift(bs, bs2);
+ if (!bs) goto retfree;
+ }
delta = diff(bb, bd);
+ if (!delta) goto retfree;
dsign = delta->sign;
delta->sign = 0;
i = cmp(delta, bs);
@@ -2089,6 +2081,7 @@ undfl:
#endif
{
delta = lshift(delta,Log2P);
+ if (!delta) goto nomem;
if (cmp(delta, bs) <= 0)
adj = -0.5;
}
@@ -2178,6 +2171,7 @@ apply_adj:
break;
}
delta = lshift(delta,Log2P);
+ if (!delta) goto retfree;
if (cmp(delta, bs) > 0)
goto drop_down;
break;
@@ -2580,6 +2574,7 @@ nrv_alloc(const char *s, char **rve, size_t n)
char *rv, *t;
t = rv = rv_alloc(n);
+ if (!rv) return NULL;
while ((*t = *s++) != 0) t++;
if (rve)
*rve = t;
@@ -2752,6 +2747,7 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
#endif
b = d2b(dval(d), &be, &bbits);
+ if (!b) return NULL;
#ifdef Sudden_Underflow
i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
@@ -2871,13 +2867,20 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
leftright = 0;
/* no break */
case 5:
- i = ndigits + k + 1;
+ if (ckd_add(&i, ndigits, k + 1)) { /* k + 1 should be safe */
+ Bfree(b);
+ return NULL;
+ }
ilim = i;
ilim1 = i - 1;
if (i <= 0)
i = 1;
}
s = s0 = rv_alloc(i+1);
+ if (!s) {
+ Bfree(b);
+ return NULL;
+ }
#ifdef Honor_FLT_ROUNDS
if (mode > 1 && rounding != 1)
@@ -3058,6 +3061,7 @@ bump_up:
b2 += i;
s2 += i;
mhi = i2b(1);
+ if (!mhi) goto nomem;
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
@@ -3069,19 +3073,28 @@ bump_up:
if (leftright) {
if (m5 > 0) {
mhi = pow5mult(mhi, m5);
+ if (!mhi) goto nomem;
b1 = mult(mhi, b);
Bfree(b);
b = b1;
+ if (!b) goto nomem;
}
- if ((j = b5 - m5) != 0)
+ if ((j = b5 - m5) != 0) {
b = pow5mult(b, j);
+ if (!b) goto nomem;
+ }
}
- else
+ else {
b = pow5mult(b, b5);
+ if (!b) goto nomem;
+ }
}
S = i2b(1);
- if (s5 > 0)
+ if (!S) goto nomem;
+ if (s5 > 0) {
S = pow5mult(S, s5);
+ if (!S) goto nomem;
+ }
/* Check for special case that d is a normalized power of 2. */
@@ -3129,16 +3142,23 @@ bump_up:
m2 += i;
s2 += i;
}
- if (b2 > 0)
+ if (b2 > 0) {
b = lshift(b, b2);
- if (s2 > 0)
+ if (!b) goto nomem;
+ }
+ if (s2 > 0) {
S = lshift(S, s2);
+ if (!S) goto nomem;
+ }
if (k_check) {
if (cmp(b,S) < 0) {
k--;
b = multadd(b, 10, 0); /* we botched the k estimate */
- if (leftright)
+ if (!b) goto nomem;
+ if (leftright) {
mhi = multadd(mhi, 10, 0);
+ if (!mhi) goto nomem;
+ }
ilim = ilim1;
}
}
@@ -3155,8 +3175,10 @@ one_digit:
goto ret;
}
if (leftright) {
- if (m2 > 0)
+ if (m2 > 0) {
mhi = lshift(mhi, m2);
+ if (!mhi) goto nomem;
+ }
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
@@ -3165,8 +3187,10 @@ one_digit:
mlo = mhi;
if (spec_case) {
mhi = Balloc(mhi->k);
+ if (!mhi) goto nomem;
Bcopy(mhi, mlo);
mhi = lshift(mhi, Log2P);
+ if (!mhi) goto nomem;
}
for (i = 1;;i++) {
@@ -3176,6 +3200,7 @@ one_digit:
*/
j = cmp(b, mlo);
delta = diff(S, mhi);
+ if (!delta) goto nomem;
j1 = delta->sign ? 1 : cmp(b, delta);
Bfree(delta);
#ifndef ROUND_BIASED
@@ -3216,6 +3241,7 @@ one_digit:
#endif /*Honor_FLT_ROUNDS*/
if (j1 > 0) {
b = lshift(b, 1);
+ if (!b) goto nomem;
j1 = cmp(b, S);
if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9')
goto round_9_up;
@@ -3244,11 +3270,16 @@ keep_dig:
if (i == ilim)
break;
b = multadd(b, 10, 0);
- if (mlo == mhi)
+ if (!b) goto nomem;
+ if (mlo == mhi) {
mlo = mhi = multadd(mhi, 10, 0);
+ if (!mlo) goto nomem;
+ }
else {
mlo = multadd(mlo, 10, 0);
+ if (!mlo) goto nomem;
mhi = multadd(mhi, 10, 0);
+ if (!mhi) goto nomem;
}
}
}
@@ -3264,6 +3295,7 @@ keep_dig:
if (i >= ilim)
break;
b = multadd(b, 10, 0);
+ if (!b) goto nomem;
}
/* Round off last digit */
@@ -3275,6 +3307,7 @@ keep_dig:
}
#endif
b = lshift(b, 1);
+ if (!b) goto nomem;
j = cmp(b, S);
if (j > 0 || (j == 0 && (dig & 1))) {
roundoff:
@@ -3316,6 +3349,16 @@ ret1:
if (rve)
*rve = s;
return s0;
+ nomem:
+ if (S) Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ if (b) Bfree(b);
+ FREE(s0);
+ return NULL;
}
/*-
@@ -3424,6 +3467,7 @@ hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rv
*/
bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
s0 = rv_alloc(bufsize+1);
+ if (!s0) return NULL;
/* Round to the desired number of digits. */
if (SIGFIGS > ndigits && ndigits > 0) {
diff --git a/nilclass.rb b/nilclass.rb
index 5a2e19680d..acd5666c71 100644
--- a/nilclass.rb
+++ b/nilclass.rb
@@ -1,6 +1,32 @@
class NilClass
#
# call-seq:
+ # rationalize(eps = nil) -> (0/1)
+ #
+ # Returns zero as a Rational:
+ #
+ # nil.rationalize # => (0/1)
+ #
+ # Argument +eps+ is ignored.
+ #
+ def rationalize(eps = nil)
+ 0r
+ end
+
+ #
+ # call-seq:
+ # to_c -> (0+0i)
+ #
+ # Returns zero as a Complex:
+ #
+ # nil.to_c # => (0+0i)
+ #
+ def to_c
+ 0i
+ end
+
+ #
+ # call-seq:
# nil.to_i -> 0
#
# Always returns zero.
@@ -22,4 +48,16 @@ class NilClass
def to_f
return 0.0
end
+
+ #
+ # call-seq:
+ # to_r -> (0/1)
+ #
+ # Returns zero as a Rational:
+ #
+ # nil.to_r # => (0/1)
+ #
+ def to_r
+ 0r
+ end
end
diff --git a/node_dump.c b/node_dump.c
index 24711f3d97..82a7d78c28 100644
--- a/node_dump.c
+++ b/node_dump.c
@@ -309,8 +309,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
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");
+ F_LOC(in_keyword_loc, RNODE_IN);
+ F_LOC(then_keyword_loc, RNODE_IN);
+ LAST_NODE;
+ F_LOC(operator_loc, RNODE_IN);
return;
case NODE_WHILE:
@@ -1009,8 +1012,10 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
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");
+ F_LOC(module_keyword_loc, RNODE_MODULE);
+ LAST_NODE;
+ F_LOC(end_keyword_loc, RNODE_MODULE);
return;
case NODE_SCLASS:
@@ -1018,8 +1023,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
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");
+ F_LOC(class_keyword_loc, RNODE_SCLASS);
+ F_LOC(operator_loc, RNODE_SCLASS);
+ LAST_NODE;
+ F_LOC(end_keyword_loc, RNODE_SCLASS);
return;
case NODE_COLON2:
@@ -1027,8 +1035,10 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
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");
+ F_LOC(delimiter_loc, RNODE_COLON2);
+ LAST_NODE;
+ F_LOC(name_loc, RNODE_COLON2);
return;
case NODE_COLON3:
@@ -1036,6 +1046,8 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("format: ::[nd_mid]");
ANN("example: ::Object");
F_ID(nd_mid, RNODE_COLON3, "constant name");
+ F_LOC(delimiter_loc, RNODE_COLON3);
+ F_LOC(name_loc, RNODE_COLON3);
return;
case NODE_DOT2:
@@ -1101,8 +1113,9 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("defined? expression");
ANN("format: defined?([nd_head])");
ANN("example: defined?(foo)");
- LAST_NODE;
F_NODE(nd_head, RNODE_DEFINED, "expr");
+ LAST_NODE;
+ F_LOC(keyword_loc, RNODE_DEFINED);
return;
case NODE_POSTEXE:
diff --git a/numeric.c b/numeric.c
index dcf4cf5c04..f4dc0f8927 100644
--- a/numeric.c
+++ b/numeric.c
@@ -30,6 +30,7 @@
#include "internal/compilers.h"
#include "internal/complex.h"
#include "internal/enumerator.h"
+#include "internal/error.h"
#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/numeric.h"
@@ -74,6 +75,8 @@
#define DBL_EPSILON 2.2204460492503131e-16
#endif
+#define ACCURATE_POW10(ndigits) ((ndigits) < DBL_DIG)
+
#ifndef USE_RB_INFINITY
#elif !defined(WORDS_BIGENDIAN) /* BYTE_ORDER == LITTLE_ENDIAN */
const union bytesequence4_or_float rb_infinity = {{0x00, 0x00, 0x80, 0x7f}};
@@ -491,7 +494,7 @@ rb_num_coerce_cmp(VALUE x, VALUE y, ID func)
static VALUE
ensure_cmp(VALUE c, VALUE x, VALUE y)
{
- if (NIL_P(c)) rb_cmperr(x, y);
+ if (NIL_P(c)) rb_cmperr_reason(x, y, "comparator returned nil");
return c;
}
@@ -501,7 +504,7 @@ rb_num_coerce_relop(VALUE x, VALUE y, ID func)
VALUE x0 = x, y0 = y;
if (!do_coerce(&x, &y, FALSE)) {
- rb_cmperr(x0, y0);
+ rb_cmperr_reason(x0, y0, "coercion was not possible");
UNREACHABLE_RETURN(Qnil);
}
return ensure_cmp(rb_funcall(x, func, 1, y), x0, y0);
@@ -576,7 +579,7 @@ num_imaginary(VALUE num)
* call-seq:
* -self -> numeric
*
- * Unary Minus---Returns the receiver, negated.
+ * Returns +self+, negated.
*/
static VALUE
@@ -595,8 +598,8 @@ num_uminus(VALUE num)
* fdiv(other) -> float
*
* Returns the quotient <tt>self/other</tt> as a float,
- * using method +/+ in the derived class of +self+.
- * (\Numeric itself does not define method +/+.)
+ * using method +/+ as defined in the subclass of \Numeric.
+ * (\Numeric itself does not define +/+.)
*
* Of the Core and Standard Library classes,
* only BigDecimal uses this implementation.
@@ -614,8 +617,8 @@ num_fdiv(VALUE x, VALUE y)
* div(other) -> integer
*
* Returns the quotient <tt>self/other</tt> as an integer (via +floor+),
- * using method +/+ in the derived class of +self+.
- * (\Numeric itself does not define method +/+.)
+ * using method +/+ as defined in the subclass of \Numeric.
+ * (\Numeric itself does not define +/+.)
*
* Of the Core and Standard Library classes,
* Only Float and Rational use this implementation.
@@ -633,7 +636,7 @@ num_div(VALUE x, VALUE y)
* call-seq:
* self % other -> real_numeric
*
- * Returns +self+ modulo +other+ as a real number.
+ * Returns +self+ modulo +other+ as a real numeric (\Integer, \Float, or \Rational).
*
* Of the Core and Standard Library classes,
* only Rational uses this implementation.
@@ -847,7 +850,8 @@ num_nonzero_p(VALUE num)
* to_int -> integer
*
* Returns +self+ as an integer;
- * converts using method +to_i+ in the derived class.
+ * converts using method +to_i+ in the subclass of \Numeric.
+ * (\Numeric itself does not define +to_i+.)
*
* Of the Core and Standard Library classes,
* only Rational and Complex use this implementation.
@@ -905,92 +909,10 @@ num_negative_p(VALUE num)
return RBOOL(rb_num_negative_int_p(num));
}
-
-/********************************************************************
- *
- * Document-class: Float
- *
- * A \Float object represents a sometimes-inexact real number using the native
- * architecture's double-precision floating point representation.
- *
- * Floating point has a different arithmetic and is an inexact number.
- * 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://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
- *
- * You can create a \Float object explicitly with:
- *
- * - A {floating-point literal}[rdoc-ref:syntax/literals.rdoc@Float+Literals].
- *
- * You can convert certain objects to Floats with:
- *
- * - Method #Float.
- *
- * == What's Here
- *
- * First, what's elsewhere. Class \Float:
- *
- * - Inherits from
- * {class Numeric}[rdoc-ref:Numeric@What-27s+Here]
- * and {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
- *
- * Here, class \Float provides methods for:
- *
- * - {Querying}[rdoc-ref:Float@Querying]
- * - {Comparing}[rdoc-ref:Float@Comparing]
- * - {Converting}[rdoc-ref:Float@Converting]
- *
- * === Querying
- *
- * - #finite?: Returns whether +self+ is finite.
- * - #hash: Returns the integer hash code for +self+.
- * - #infinite?: Returns whether +self+ is infinite.
- * - #nan?: Returns whether +self+ is a NaN (not-a-number).
- *
- * === Comparing
- *
- * - #<: Returns whether +self+ is less than the given value.
- * - #<=: Returns whether +self+ is less than or equal to the given value.
- * - #<=>: Returns a number indicating whether +self+ is less than, equal
- * to, or greater than the given value.
- * - #== (aliased as #=== and #eql?): Returns whether +self+ is equal to
- * the given value.
- * - #>: Returns whether +self+ is greater than the given value.
- * - #>=: Returns whether +self+ is greater than or equal to the given value.
- *
- * === Converting
- *
- * - #% (aliased as #modulo): Returns +self+ modulo the given value.
- * - #*: Returns the product of +self+ and the given value.
- * - #**: Returns the value of +self+ raised to the power of the given value.
- * - #+: Returns the sum of +self+ and the given value.
- * - #-: Returns the difference of +self+ and the given value.
- * - #/: 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+
- * - #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.
- * - #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.
- * - #quo: Returns the quotient from dividing +self+ by the given value.
- * - #round: Returns +self+ rounded to the nearest value, to a given precision.
- * - #to_i (aliased as #to_int): Returns +self+ truncated to an Integer.
- * - #to_s (aliased as #inspect): Returns a string containing the place-value
- * representation of +self+ in the given radix.
- * - #truncate: Returns +self+ truncated to a given precision.
- *
- */
-
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, sizeof(struct RFloat));
#if SIZEOF_DOUBLE <= SIZEOF_VALUE
flt->float_value = d;
@@ -1131,15 +1053,21 @@ rb_float_uminus(VALUE flt)
/*
* call-seq:
- * self + other -> numeric
+ * self + other -> float or complex
*
- * Returns a new \Float which is the sum of +self+ and +other+:
+ * Returns the sum of +self+ and +other+;
+ * the result may be inexact (see Float):
*
- * f = 3.14
- * f + 1 # => 4.140000000000001
- * f + 1.0 # => 4.140000000000001
- * f + Rational(1, 1) # => 4.140000000000001
- * f + Complex(1, 0) # => (4.140000000000001+0i)
+ * 3.14 + 0 # => 3.14
+ * 3.14 + 1 # => 4.140000000000001
+ * -3.14 + 0 # => -3.14
+ * -3.14 + 1 # => -2.14
+
+ * 3.14 + -3.14 # => 0.0
+ * -3.14 + -3.14 # => -6.28
+ *
+ * 3.14 + Complex(1, 0) # => (4.140000000000001+0i)
+ * 3.14 + Rational(1, 1) # => 4.140000000000001
*
*/
@@ -1164,7 +1092,7 @@ rb_float_plus(VALUE x, VALUE y)
* call-seq:
* self - other -> numeric
*
- * Returns a new \Float which is the difference of +self+ and +other+:
+ * Returns the difference of +self+ and +other+:
*
* f = 3.14
* f - 1 # => 2.14
@@ -1195,13 +1123,14 @@ rb_float_minus(VALUE x, VALUE y)
* call-seq:
* self * other -> numeric
*
- * Returns a new \Float which is the product of +self+ and +other+:
+ * Returns the numeric product of +self+ and +other+:
*
* f = 3.14
* f * 2 # => 6.28
* f * 2.0 # => 6.28
* f * Rational(1, 2) # => 1.57
* f * Complex(2, 0) # => (6.28+0.0i)
+ *
*/
VALUE
@@ -1249,7 +1178,7 @@ rb_flo_div_flo(VALUE x, VALUE y)
* call-seq:
* self / other -> numeric
*
- * Returns a new \Float which is the result of dividing +self+ by +other+:
+ * Returns the quotient of +self+ and +other+:
*
* f = 3.14
* f / 2 # => 1.57
@@ -1358,7 +1287,7 @@ ruby_float_mod(double x, double y)
* call-seq:
* self % other -> float
*
- * Returns +self+ modulo +other+ as a float.
+ * Returns +self+ modulo +other+ as a \Float.
*
* For float +f+ and real number +r+, these expressions are equivalent:
*
@@ -1464,9 +1393,9 @@ flo_divmod(VALUE x, VALUE y)
/*
* call-seq:
- * self ** other -> numeric
+ * self ** exponent -> numeric
*
- * Raises +self+ to the power of +other+:
+ * Returns +self+ raised to the power +exponent+:
*
* f = 3.14
* f ** 2 # => 9.8596
@@ -1542,10 +1471,17 @@ num_eql(VALUE x, VALUE y)
* call-seq:
* self <=> other -> zero or nil
*
- * Returns zero if +self+ is the same as +other+, +nil+ otherwise.
+ * Compares +self+ and +other+.
*
- * No subclass in the Ruby Core or Standard Library uses this implementation.
+ * Returns:
+ *
+ * - Zero, if +self+ is the same as +other+.
+ * - +nil+, otherwise.
*
+ * \Class \Numeric includes module Comparable,
+ * each of whose methods uses Numeric#<=> for comparison.
+ *
+ * No subclass in the Ruby Core or Standard Library uses this implementation.
*/
static VALUE
@@ -1568,7 +1504,7 @@ num_equal(VALUE x, VALUE y)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if +other+ has the same value as +self+, +false+ otherwise:
+ * Returns whether +other+ is numerically equal to +self+:
*
* 2.0 == 2 # => true
* 2.0 == 2.0 # => true
@@ -1591,17 +1527,11 @@ rb_float_equal(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return num_equal(x, y);
}
a = RFLOAT_VALUE(x);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a == b);
}
@@ -1641,30 +1571,32 @@ rb_dbl_cmp(double a, double b)
/*
* call-seq:
- * self <=> other -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
*
- * Returns a value that depends on the numeric relation
- * between +self+ and +other+:
+ * Compares +self+ and +other+.
*
- * - -1, if +self+ is less than +other+.
- * - 0, if +self+ is equal to +other+.
- * - 1, if +self+ is greater than +other+.
+ * Returns:
+ *
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if +self+ is equal to +other+.
+ * - +1+, if +self+ is greater than +other+.
* - +nil+, if the two values are incommensurate.
*
* Examples:
*
+ * 2.0 <=> 2.1 # => -1
* 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
*
- * This is the basis for the tests in the Comparable module.
- *
* <tt>Float::NAN <=> Float::NAN</tt> returns an implementation-dependent value.
*
+ * \Class \Float includes module Comparable,
+ * each of whose methods uses Float#<=> for comparison.
+ *
*/
static VALUE
@@ -1709,7 +1641,8 @@ rb_float_cmp(VALUE x, VALUE y)
* call-seq:
* self > other -> true or false
*
- * Returns +true+ if +self+ is numerically greater than +other+:
+ * Returns whether the value of +self+ is greater than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 > 1 # => true
* 2.0 > 1.0 # => true
@@ -1734,16 +1667,10 @@ rb_float_gt(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, '>');
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a > b);
}
@@ -1751,7 +1678,8 @@ rb_float_gt(VALUE x, VALUE y)
* call-seq:
* self >= other -> true or false
*
- * Returns +true+ if +self+ is numerically greater than or equal to +other+:
+ * Returns whether the value of +self+ is greater than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 >= 1 # => true
* 2.0 >= 1.0 # => true
@@ -1777,16 +1705,10 @@ flo_ge(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, idGE);
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a >= b);
}
@@ -1794,7 +1716,8 @@ flo_ge(VALUE x, VALUE y)
* call-seq:
* self < other -> true or false
*
- * Returns +true+ if +self+ is numerically less than +other+:
+ * Returns whether the value of +self+ is less than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 < 3 # => true
* 2.0 < 3.0 # => true
@@ -1802,7 +1725,6 @@ flo_ge(VALUE x, VALUE y)
* 2.0 < 2.0 # => false
*
* <tt>Float::NAN < Float::NAN</tt> returns an implementation-dependent value.
- *
*/
static VALUE
@@ -1819,16 +1741,10 @@ flo_lt(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, '<');
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a < b);
}
@@ -1836,7 +1752,8 @@ flo_lt(VALUE x, VALUE y)
* call-seq:
* self <= other -> true or false
*
- * Returns +true+ if +self+ is numerically less than or equal to +other+:
+ * Returns whether the value of +self+ is less than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 2.0 <= 3 # => true
* 2.0 <= 3.0 # => true
@@ -1862,16 +1779,10 @@ flo_le(VALUE x, VALUE y)
}
else if (RB_FLOAT_TYPE_P(y)) {
b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(b)) return Qfalse;
-#endif
}
else {
return rb_num_coerce_relop(x, y, idLE);
}
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) return Qfalse;
-#endif
return RBOOL(a <= b);
}
@@ -1899,10 +1810,7 @@ rb_float_eql(VALUE x, VALUE y)
if (RB_FLOAT_TYPE_P(y)) {
double a = RFLOAT_VALUE(x);
double b = RFLOAT_VALUE(y);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a) || isnan(b)) return Qfalse;
-#endif
- return RBOOL(a == b);
+ return RBOOL(a == b);
}
return Qfalse;
}
@@ -2112,6 +2020,9 @@ rb_float_floor(VALUE num, int ndigits)
if (float_round_overflow(ndigits, binexp)) return num;
if (number > 0.0 && float_round_underflow(ndigits, binexp))
return DBL2NUM(0.0);
+ if (!ACCURATE_POW10(ndigits)) {
+ return rb_flo_floor_by_rational(num, ndigits);
+ }
f = pow(10, ndigits);
mul = floor(number * f);
res = (mul + 1) / f;
@@ -2320,6 +2231,9 @@ rb_float_ceil(VALUE num, int ndigits)
if (float_round_overflow(ndigits, binexp)) return num;
if (number < 0.0 && float_round_underflow(ndigits, binexp))
return DBL2NUM(0.0);
+ if (!ACCURATE_POW10(ndigits)) {
+ return rb_flo_ceil_by_rational(num, ndigits);
+ }
f = pow(10, ndigits);
f = ceil(number * f) / f;
return DBL2NUM(f);
@@ -2584,9 +2498,8 @@ flo_round(int argc, VALUE *argv, VALUE num)
frexp(number, &binexp);
if (float_round_overflow(ndigits, binexp)) return num;
if (float_round_underflow(ndigits, binexp)) return DBL2NUM(0);
- if (ndigits > 14) {
- /* In this case, pow(10, ndigits) may not be accurate. */
- return rb_flo_round_by_rational(argc, argv, num);
+ if (!ACCURATE_POW10(ndigits)) {
+ return rb_flo_round_by_rational(num, ndigits, mode);
}
f = pow(10, ndigits);
x = ROUND_CALL(mode, round, (number, f));
@@ -2659,6 +2572,12 @@ flo_to_i(VALUE num)
return dbl2ival(f);
}
+VALUE
+rb_flo_to_i(VALUE num)
+{
+ return flo_to_i(num);
+}
+
/*
* call-seq:
* truncate(ndigits = 0) -> float or integer
@@ -2708,7 +2627,7 @@ flo_truncate(int argc, VALUE *argv, VALUE num)
* floor(ndigits = 0) -> float or integer
*
* Returns the largest float or integer that is less than or equal to +self+,
- * as specified by the given `ndigits`,
+ * as specified by the given +ndigits+,
* which must be an
* {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
*
@@ -2728,7 +2647,7 @@ num_floor(int argc, VALUE *argv, VALUE num)
* ceil(ndigits = 0) -> float or integer
*
* Returns the smallest float or integer that is greater than or equal to +self+,
- * as specified by the given `ndigits`,
+ * as specified by the given +ndigits+,
* which must be an
* {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
*
@@ -3197,7 +3116,7 @@ rb_num2long(VALUE val)
{
again:
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) return FIX2LONG(val);
@@ -3225,7 +3144,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_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) {
@@ -3468,7 +3387,7 @@ LONG_LONG
rb_num2ll(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion from nil");
+ rb_no_implicit_conversion(val, "Integer");
}
if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val);
@@ -3485,11 +3404,8 @@ rb_num2ll(VALUE val)
else if (RB_BIGNUM_TYPE_P(val)) {
return rb_big2ll(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");
+ else if (val == Qfalse || val == Qtrue || RB_TYPE_P(val, T_STRING)) {
+ rb_no_implicit_conversion(val, "Integer");
}
val = rb_to_int(val);
@@ -3500,7 +3416,7 @@ unsigned LONG_LONG
rb_num2ull(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_no_implicit_conversion(val, "Integer");
}
else if (FIXNUM_P(val)) {
return (LONG_LONG)FIX2LONG(val); /* this is FIX2LONG, intended */
@@ -3527,6 +3443,232 @@ rb_num2ull(VALUE val)
#endif /* HAVE_LONG_LONG */
+// Conversion functions for unified 128-bit integer structures,
+// These work with or without native 128-bit integer support.
+
+#ifndef HAVE_UINT128_T
+// Helper function to build 128-bit value from bignum digits (fallback path).
+static inline void
+rb_uint128_from_bignum_digits_fallback(rb_uint128_t *result, BDIGIT *digits, size_t length)
+{
+ // Build the 128-bit value from bignum digits:
+ for (long i = length - 1; i >= 0; i--) {
+ // Shift both low and high parts:
+ uint64_t carry = result->parts.low >> (64 - (SIZEOF_BDIGIT * CHAR_BIT));
+ result->parts.low = (result->parts.low << (SIZEOF_BDIGIT * CHAR_BIT)) | digits[i];
+ result->parts.high = (result->parts.high << (SIZEOF_BDIGIT * CHAR_BIT)) | carry;
+ }
+}
+
+// Helper function to convert absolute value of negative bignum to two's complement.
+// Ruby stores negative bignums as absolute values, so we need to convert to two's complement.
+static inline void
+rb_uint128_twos_complement_negate(rb_uint128_t *value)
+{
+ if (value->parts.low == 0) {
+ value->parts.high = ~value->parts.high + 1;
+ }
+ else {
+ value->parts.low = ~value->parts.low + 1;
+ value->parts.high = ~value->parts.high + (value->parts.low == 0 ? 1 : 0);
+ }
+}
+#endif
+
+rb_uint128_t
+rb_numeric_to_uint128(VALUE x)
+{
+ rb_uint128_t result = {0};
+ if (RB_FIXNUM_P(x)) {
+ long value = RB_FIX2LONG(x);
+ if (value < 0) {
+ rb_raise(rb_eRangeError, "negative integer cannot be converted to unsigned 128-bit integer");
+ }
+#ifdef HAVE_UINT128_T
+ result.value = (uint128_t)value;
+#else
+ result.parts.low = (uint64_t)value;
+ result.parts.high = 0;
+#endif
+ return result;
+ }
+ else if (RB_BIGNUM_TYPE_P(x)) {
+ if (BIGNUM_NEGATIVE_P(x)) {
+ rb_raise(rb_eRangeError, "negative integer cannot be converted to unsigned 128-bit integer");
+ }
+ size_t length = BIGNUM_LEN(x);
+#ifdef HAVE_UINT128_T
+ if (length > roomof(SIZEOF_INT128_T, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'unsigned 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ result.value = 0;
+ for (long i = length - 1; i >= 0; i--) {
+ result.value = (result.value << (SIZEOF_BDIGIT * CHAR_BIT)) | digits[i];
+ }
+#else
+ // Check if bignum fits in 128 bits (16 bytes)
+ if (length > roomof(16, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'unsigned 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ rb_uint128_from_bignum_digits_fallback(&result, digits, length);
+#endif
+ return result;
+ }
+ else {
+ rb_raise(rb_eTypeError, "not an integer");
+ }
+}
+
+rb_int128_t
+rb_numeric_to_int128(VALUE x)
+{
+ rb_int128_t result = {0};
+ if (RB_FIXNUM_P(x)) {
+ long value = RB_FIX2LONG(x);
+#ifdef HAVE_UINT128_T
+ result.value = (int128_t)value;
+#else
+ if (value < 0) {
+ // Two's complement representation: for negative values, sign extend
+ // Convert to unsigned: for -1, we want all bits set
+ result.parts.low = (uint64_t)value; // This will be the two's complement representation
+ result.parts.high = UINT64_MAX; // Sign extend: all bits set for negative
+ }
+ else {
+ result.parts.low = (uint64_t)value;
+ result.parts.high = 0;
+ }
+#endif
+ return result;
+ }
+ else if (RB_BIGNUM_TYPE_P(x)) {
+ size_t length = BIGNUM_LEN(x);
+#ifdef HAVE_UINT128_T
+ if (length > roomof(SIZEOF_INT128_T, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ uint128_t unsigned_result = 0;
+ for (long i = length - 1; i >= 0; i--) {
+ unsigned_result = (unsigned_result << (SIZEOF_BDIGIT * CHAR_BIT)) | digits[i];
+ }
+ if (BIGNUM_NEGATIVE_P(x)) {
+ // Convert from two's complement
+ // Maximum negative value is 2^127
+ if (unsigned_result > ((uint128_t)1 << 127)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ result.value = -(int128_t)(unsigned_result - 1) - 1;
+ }
+ else {
+ // Maximum positive value is 2^127 - 1
+ if (unsigned_result > (((uint128_t)1 << 127) - 1)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ result.value = (int128_t)unsigned_result;
+ }
+#else
+ if (length > roomof(16, SIZEOF_BDIGIT)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ BDIGIT *digits = BIGNUM_DIGITS(x);
+ rb_uint128_t unsigned_result = {0};
+ rb_uint128_from_bignum_digits_fallback(&unsigned_result, digits, length);
+ if (BIGNUM_NEGATIVE_P(x)) {
+ // Check if value fits in signed 128-bit (max negative is 2^127)
+ uint64_t max_neg_high = (uint64_t)1 << 63;
+ if (unsigned_result.parts.high > max_neg_high || (unsigned_result.parts.high == max_neg_high && unsigned_result.parts.low > 0)) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ // Convert from absolute value to two's complement (Ruby stores negative as absolute value)
+ rb_uint128_twos_complement_negate(&unsigned_result);
+ result.parts.low = unsigned_result.parts.low;
+ result.parts.high = (int64_t)unsigned_result.parts.high; // Sign extend
+ }
+ else {
+ // Check if value fits in signed 128-bit (max positive is 2^127 - 1)
+ // Max positive: high = 0x7FFFFFFFFFFFFFFF, low = 0xFFFFFFFFFFFFFFFF
+ uint64_t max_pos_high = ((uint64_t)1 << 63) - 1;
+ if (unsigned_result.parts.high > max_pos_high) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into 'signed 128-bit integer'");
+ }
+ result.parts.low = unsigned_result.parts.low;
+ result.parts.high = unsigned_result.parts.high;
+ }
+#endif
+ return result;
+ }
+ else {
+ rb_raise(rb_eTypeError, "not an integer");
+ }
+}
+
+VALUE
+rb_uint128_to_numeric(rb_uint128_t n)
+{
+#ifdef HAVE_UINT128_T
+ if (n.value <= (uint128_t)RUBY_FIXNUM_MAX) {
+ return LONG2FIX((long)n.value);
+ }
+ return rb_uint128t2big(n.value);
+#else
+ // If high part is zero and low part fits in fixnum
+ if (n.parts.high == 0 && n.parts.low <= (uint64_t)RUBY_FIXNUM_MAX) {
+ return LONG2FIX((long)n.parts.low);
+ }
+ // Convert to bignum by building it from the two 64-bit parts
+ VALUE bignum = rb_ull2big(n.parts.low);
+ if (n.parts.high > 0) {
+ VALUE high_bignum = rb_ull2big(n.parts.high);
+ // Multiply high part by 2^64 and add to low part
+ VALUE shifted_value = rb_int_lshift(high_bignum, INT2FIX(64));
+ bignum = rb_int_plus(bignum, shifted_value);
+ }
+ return bignum;
+#endif
+}
+
+VALUE
+rb_int128_to_numeric(rb_int128_t n)
+{
+#ifdef HAVE_UINT128_T
+ if (FIXABLE(n.value)) {
+ return LONG2FIX((long)n.value);
+ }
+ return rb_int128t2big(n.value);
+#else
+ int64_t high = (int64_t)n.parts.high;
+ // If it's a small positive value that fits in fixnum
+ if (high == 0 && n.parts.low <= (uint64_t)RUBY_FIXNUM_MAX) {
+ return LONG2FIX((long)n.parts.low);
+ }
+ // Check if it's negative (high bit of high part is set)
+ if (high < 0) {
+ // Negative value - convert from two's complement to absolute value
+ rb_uint128_t unsigned_value = {0};
+ if (n.parts.low == 0) {
+ unsigned_value.parts.low = 0;
+ unsigned_value.parts.high = ~n.parts.high + 1;
+ }
+ else {
+ unsigned_value.parts.low = ~n.parts.low + 1;
+ unsigned_value.parts.high = ~n.parts.high + (unsigned_value.parts.low == 0 ? 1 : 0);
+ }
+ VALUE bignum = rb_uint128_to_numeric(unsigned_value);
+ return rb_int_uminus(bignum);
+ }
+ else {
+ // Positive value
+ union uint128_int128_conversion conversion = {
+ .int128 = n
+ };
+ return rb_uint128_to_numeric(conversion.uint128);
+ }
+#endif
+}
+
/********************************************************************
*
* Document-class: Integer
@@ -3549,9 +3691,9 @@ rb_num2ull(VALUE val)
* First, what's elsewhere. Class \Integer:
*
* - Inherits from
- * {class Numeric}[rdoc-ref:Numeric@What-27s+Here]
- * and {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * {class Numeric}[rdoc-ref:Numeric@Whats+Here]
+ * and {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
*
* Here, class \Integer provides methods for:
*
@@ -3905,6 +4047,11 @@ rb_int_uminus(VALUE num)
}
}
+/* ruby_decimal_digit_pairs is defined in bignum.c and declared in
+ * internal/bignum.h. See there for the rationale of the 2-digit
+ * lookup-table itoa optimisation; both rb_fix2str here and big2str_2bdigits
+ * in bignum.c consume it. */
+
VALUE
rb_fix2str(VALUE x, int base)
{
@@ -3937,9 +4084,34 @@ rb_fix2str(VALUE x, int base)
else {
u = val;
}
- do {
- *--b = ruby_digitmap[(int)(u % base)];
- } while (u /= base);
+ if (base == 10) {
+ /* Emit two digits per iteration from a precomputed table. The
+ * compiler lowers `u % 100` and `u / 100` to a single multiply +
+ * shift, so each iteration costs roughly one multiply, one shift,
+ * and two stores. About 2x fewer iterations than the classic
+ * per-digit loop for multi-digit inputs. */
+ while (u >= 100) {
+ unsigned long idx = (u % 100) * 2;
+ u /= 100;
+ b -= 2;
+ b[0] = ruby_decimal_digit_pairs[idx];
+ b[1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ if (u >= 10) {
+ unsigned long idx = u * 2;
+ b -= 2;
+ b[0] = ruby_decimal_digit_pairs[idx];
+ b[1] = ruby_decimal_digit_pairs[idx + 1];
+ }
+ else {
+ *--b = (char)('0' + u);
+ }
+ }
+ else {
+ do {
+ *--b = ruby_digitmap[(int)(u % base)];
+ } while (u /= base);
+ }
if (neg) {
*--b = '-';
}
@@ -4030,17 +4202,20 @@ rb_fix_plus(VALUE x, VALUE y)
/*
* call-seq:
- * self + numeric -> numeric_result
+ * self + other -> numeric
+ *
+ * Returns the sum of +self+ and +other+:
*
- * Performs addition:
+ * 1 + 1 # => 2
+ * 1 + -1 # => 0
+ * 1 + 0 # => 1
+ * 1 + -2 # => -1
+ * 1 + Complex(1, 0) # => (2+0i)
+ * 1 + Rational(1, 1) # => (2/1)
*
- * 2 + 2 # => 4
- * -2 + 2 # => 0
- * -2 + -2 # => -4
- * 2 + 2.0 # => 4.0
- * 2 + Rational(2, 1) # => (4/1)
- * 2 + Complex(2, 0) # => (4+0i)
+ * For a computation involving Floats, the result may be inexact (see Float#+):
*
+ * 1 + 3.14 # => 4.140000000000001
*/
VALUE
@@ -4075,9 +4250,9 @@ fix_minus(VALUE x, VALUE y)
/*
* call-seq:
- * self - numeric -> numeric_result
+ * self - other -> numeric
*
- * Performs subtraction:
+ * Returns the difference of +self+ and +other+:
*
* 4 - 2 # => 2
* -4 - 2 # => -6
@@ -4131,16 +4306,17 @@ fix_mul(VALUE x, VALUE y)
/*
* call-seq:
- * self * numeric -> numeric_result
+ * self * other -> numeric
*
- * Performs multiplication:
+ * Returns the numeric product of +self+ and +other+:
*
* 4 * 2 # => 8
- * 4 * -2 # => -8
* -4 * 2 # => -8
+ * 4 * -2 # => -8
* 4 * 2.0 # => 8.0
* 4 * Rational(1, 3) # => (4/3)
* 4 * Complex(2, 0) # => (8+0i)
+ *
*/
VALUE
@@ -4155,16 +4331,24 @@ rb_int_mul(VALUE x, VALUE y)
return rb_num_coerce_bin(x, y, '*');
}
+static bool
+accurate_in_double(long i)
+{
+#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG
+ return ((i < 0 ? -i : i) < (1L << DBL_MANT_DIG));
+#else
+ return true;
+#endif
+}
+
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)) {
+ if (!accurate_in_double(iy)) {
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy));
}
-#endif
return double_div_double(FIX2LONG(x), iy);
}
else if (RB_BIGNUM_TYPE_P(y)) {
@@ -4178,10 +4362,29 @@ fix_fdiv_double(VALUE x, VALUE y)
}
}
+static bool
+int_accurate_in_double(VALUE n)
+{
+ if (FIXNUM_P(n)) {
+ return accurate_in_double(FIX2LONG(n));
+ }
+ RUBY_ASSERT(RB_TYPE_P(n, T_BIGNUM));
+#if SIZEOF_LONG * CHAR_BIT <= DBL_MANT_DIG
+ int nlz;
+ size_t size = rb_absint_size(n, &nlz);
+ const size_t mant_size = roomof(DBL_MANT_DIG, CHAR_BIT);
+ if (size < mant_size) return true;
+ if (size > mant_size) return false;
+ if ((size_t)nlz >= (CHAR_BIT * mant_size - DBL_MANT_DIG)) return true;
+#endif
+ return false;
+}
+
double
rb_int_fdiv_double(VALUE x, VALUE y)
{
- if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) {
+ if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y) &&
+ !(int_accurate_in_double(x) && int_accurate_in_double(y))) {
VALUE gcd = rb_gcd(x, y);
if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) {
x = rb_int_idiv(x, gcd);
@@ -4263,16 +4466,18 @@ fix_div(VALUE x, VALUE y)
/*
* call-seq:
- * self / numeric -> numeric_result
+ * self / other -> numeric
+ *
+ * Returns the quotient of +self+ and +other+.
*
- * Performs division; for integer +numeric+, truncates the result to an integer:
+ * For integer +other+, truncates the result to an integer:
*
* 4 / 3 # => 1
* 4 / -3 # => -2
* -4 / 3 # => -2
* -4 / -3 # => 1
*
- * For other +numeric+, returns non-integer result:
+ * For non-integer +other+, returns a non-integer result:
*
* 4 / 3.0 # => 1.3333333333333333
* 4 / Rational(3, 1) # => (4/3)
@@ -4349,9 +4554,9 @@ fix_mod(VALUE x, VALUE y)
/*
* call-seq:
- * self % other -> real_number
+ * self % other -> real_numeric
*
- * Returns +self+ modulo +other+ as a real number.
+ * Returns +self+ modulo +other+ as a real numeric (\Integer, \Float, or \Rational).
*
* For integer +n+ and real number +r+, these expressions are equivalent:
*
@@ -4500,9 +4705,9 @@ rb_int_divmod(VALUE x, VALUE y)
/*
* call-seq:
- * self ** numeric -> numeric_result
+ * self ** exponent -> numeric
*
- * Raises +self+ to the power of +numeric+:
+ * Returns +self+ raised to the power +exponent+:
*
* 2 ** 3 # => 8
* 2 ** -3 # => (1/8)
@@ -4623,17 +4828,47 @@ fix_pow(VALUE x, VALUE y)
/*
* call-seq:
- * self ** numeric -> numeric_result
- *
- * Raises +self+ to the power of +numeric+:
- *
- * 2 ** 3 # => 8
- * 2 ** -3 # => (1/8)
- * -2 ** 3 # => -8
- * -2 ** -3 # => (-1/8)
- * 2 ** 3.3 # => 9.849155306759329
- * 2 ** Rational(3, 1) # => (8/1)
- * 2 ** Complex(3, 0) # => (8+0i)
+ * self ** exponent -> numeric
+ *
+ * Returns +self+ raised to the power +exponent+:
+ *
+ * # Result for non-negative Integer exponent is Integer.
+ * 2 ** 0 # => 1
+ * 2 ** 1 # => 2
+ * 2 ** 2 # => 4
+ * 2 ** 3 # => 8
+ * -2 ** 3 # => -8
+ * # Result for negative Integer exponent is Rational, not Float.
+ * 2 ** -3 # => (1/8)
+ * -2 ** -3 # => (-1/8)
+ *
+ * # Result for Float exponent is Float.
+ * 2 ** 0.0 # => 1.0
+ * 2 ** 1.0 # => 2.0
+ * 2 ** 2.0 # => 4.0
+ * 2 ** 3.0 # => 8.0
+ * -2 ** 3.0 # => -8.0
+ * 2 ** -3.0 # => 0.125
+ * -2 ** -3.0 # => -0.125
+ *
+ * # Result for non-negative Complex exponent is Complex with Integer parts.
+ * 2 ** Complex(0, 0) # => (1+0i)
+ * 2 ** Complex(1, 0) # => (2+0i)
+ * 2 ** Complex(2, 0) # => (4+0i)
+ * 2 ** Complex(3, 0) # => (8+0i)
+ * -2 ** Complex(3, 0) # => (-8+0i)
+ * # Result for negative Complex exponent is Complex with Rational parts.
+ * 2 ** Complex(-3, 0) # => ((1/8)+(0/1)*i)
+ * -2 ** Complex(-3, 0) # => ((-1/8)+(0/1)*i)
+ *
+ * # Result for Rational exponent is Rational.
+ * 2 ** Rational(0, 1) # => (1/1)
+ * 2 ** Rational(1, 1) # => (2/1)
+ * 2 ** Rational(2, 1) # => (4/1)
+ * 2 ** Rational(3, 1) # => (8/1)
+ * -2 ** Rational(3, 1) # => (-8/1)
+ * 2 ** Rational(-3, 1) # => (1/8)
+ * -2 ** Rational(-3, 1) # => (-1/8)
*
*/
VALUE
@@ -4686,7 +4921,7 @@ fix_equal(VALUE x, VALUE y)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if +self+ is numerically equal to +other+; +false+ otherwise.
+ * Returns whether +self+ is numerically equal to +other+:
*
* 1 == 2 #=> false
* 1 == 1.0 #=> true
@@ -4732,28 +4967,29 @@ fix_cmp(VALUE x, VALUE y)
/*
* call-seq:
- * self <=> other -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
*
* Returns:
*
- * - -1, if +self+ is less than +other+.
- * - 0, if +self+ is equal to +other+.
- * - 1, if +self+ is greater then +other+.
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if +self+ is equal to +other+.
+ * - +1+, if +self+ is greater then +other+.
* - +nil+, if +self+ and +other+ are incomparable.
*
* Examples:
*
* 1 <=> 2 # => -1
* 1 <=> 1 # => 0
- * 1 <=> 0 # => 1
- * 1 <=> 'foo' # => nil
- *
* 1 <=> 1.0 # => 0
* 1 <=> Rational(1, 1) # => 0
* 1 <=> Complex(1, 0) # => 0
+ * 1 <=> 0 # => 1
+ * 1 <=> 'foo' # => nil
*
- * This method is the basis for comparisons in module Comparable.
- *
+ * \Class \Integer includes module Comparable,
+ * each of whose methods uses Integer#<=> for comparison.
*/
VALUE
@@ -4791,7 +5027,8 @@ fix_gt(VALUE x, VALUE y)
* call-seq:
* self > other -> true or false
*
- * Returns +true+ if the value of +self+ is greater than that of +other+:
+ * Returns whether the value of +self+ is greater than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 > 0 # => true
* 1 > 1 # => false
@@ -4835,10 +5072,10 @@ fix_ge(VALUE x, VALUE y)
/*
* call-seq:
- * self >= real -> true or false
+ * self >= other -> true or false
*
- * Returns +true+ if the value of +self+ is greater than or equal to
- * that of +other+:
+ * Returns whether the value of +self+ is greater than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 >= 0 # => true
* 1 >= 1 # => true
@@ -4883,7 +5120,8 @@ fix_lt(VALUE x, VALUE y)
* call-seq:
* self < other -> true or false
*
- * Returns +true+ if the value of +self+ is less than that of +other+:
+ * Returns whether the value of +self+ is less than the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 < 0 # => false
* 1 < 1 # => false
@@ -4891,8 +5129,6 @@ fix_lt(VALUE x, VALUE y)
* 1 < 0.5 # => false
* 1 < Rational(1, 2) # => false
*
- * Raises an exception if the comparison cannot be made.
- *
*/
static VALUE
@@ -4927,10 +5163,10 @@ fix_le(VALUE x, VALUE y)
/*
* call-seq:
- * self <= real -> true or false
+ * self <= other -> true or false
*
- * Returns +true+ if the value of +self+ is less than or equal to
- * that of +other+:
+ * Returns whether the value of +self+ is less than or equal to the value of +other+;
+ * +other+ must be numeric, but may not be Complex:
*
* 1 <= 0 # => false
* 1 <= 1 # => true
@@ -5115,8 +5351,8 @@ fix_xor(VALUE x, VALUE y)
*
*/
-static VALUE
-int_xor(VALUE x, VALUE y)
+VALUE
+rb_int_xor(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
return fix_xor(x, y);
@@ -5289,9 +5525,22 @@ generate_mask(VALUE len)
}
static VALUE
+int_aref2(VALUE num, VALUE beg, VALUE len)
+{
+ if (RB_TYPE_P(num, T_BIGNUM)) {
+ return rb_big_aref2(num, beg, len);
+ }
+ else {
+ num = rb_int_rshift(num, beg);
+ VALUE mask = generate_mask(len);
+ return rb_int_and(num, mask);
+ }
+}
+
+static VALUE
int_aref1(VALUE num, VALUE arg)
{
- VALUE orig_num = num, beg, end;
+ VALUE beg, end;
int excl;
if (rb_range_values(arg, &beg, &end, &excl)) {
@@ -5311,22 +5560,19 @@ int_aref1(VALUE num, VALUE arg)
return INT2FIX(0);
}
}
- num = rb_int_rshift(num, beg);
int cmp = compare_indexes(beg, end);
if (!NIL_P(end) && cmp < 0) {
VALUE len = rb_int_minus(end, beg);
if (!excl) len = rb_int_plus(len, INT2FIX(1));
- VALUE mask = generate_mask(len);
- num = rb_int_and(num, mask);
+ return int_aref2(num, beg, len);
}
else if (cmp == 0) {
if (excl) return INT2FIX(0);
- num = orig_num;
arg = beg;
goto one_bit;
}
- return num;
+ return rb_int_rshift(num, beg);
}
one_bit:
@@ -5339,15 +5585,6 @@ one_bit:
return Qnil;
}
-static VALUE
-int_aref2(VALUE num, VALUE beg, VALUE len)
-{
- num = rb_int_rshift(num, beg);
- VALUE mask = generate_mask(len);
- num = rb_int_and(num, mask);
- return num;
-}
-
/*
* call-seq:
* self[offset] -> 0 or 1
@@ -5552,7 +5789,7 @@ rb_int_digits_bigbase(VALUE num, VALUE base)
}
bases = rb_ary_new();
- for (VALUE b = base; int_lt(b, num) == Qtrue; b = rb_int_mul(b, b)) {
+ for (VALUE b = base; int_le(b, num) == Qtrue; b = rb_int_mul(b, b)) {
rb_ary_push(bases, b);
}
digits = rb_ary_new_from_args(1, num);
@@ -5717,7 +5954,7 @@ int_downto(VALUE from, VALUE to)
rb_yield(i);
i = rb_funcall(i, '-', 1, INT2FIX(1));
}
- if (NIL_P(c)) rb_cmperr(i, to);
+ ensure_cmp(c, i, to);
}
return from;
}
@@ -5978,7 +6215,11 @@ prefix##_isqrt(argtype n) \
while ((t = n/x) < (argtype)x) x = (rettype)((x + t) >> 1); \
return x; \
} \
- return (rettype)sqrt(argtype##_TO_DOUBLE(n)); \
+ 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; \
}
#if SIZEOF_LONG*CHAR_BIT > DBL_MANT_DIG
@@ -6192,8 +6433,8 @@ int_s_try_convert(VALUE self, VALUE num)
*
* First, what's elsewhere. Class \Numeric:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
*
* Here, class \Numeric provides methods for:
*
@@ -6362,7 +6603,7 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, "&", rb_int_and, 1);
rb_define_method(rb_cInteger, "|", int_or, 1);
- rb_define_method(rb_cInteger, "^", int_xor, 1);
+ rb_define_method(rb_cInteger, "^", rb_int_xor, 1);
rb_define_method(rb_cInteger, "[]", int_aref, -1);
rb_define_method(rb_cInteger, "<<", rb_int_lshift, 1);
@@ -6450,7 +6691,7 @@ Init_Numeric(void)
*
* If the platform supports denormalized numbers,
* there are numbers between zero and Float::MIN.
- * 0.0.next_float returns the smallest positive floating point number
+ * +0.0.next_float+ returns the smallest positive floating point number
* including denormalized numbers.
*/
rb_define_const(rb_cFloat, "MIN", DBL2NUM(DBL_MIN));
diff --git a/numeric.rb b/numeric.rb
index 27e9951fd3..306561943d 100644
--- a/numeric.rb
+++ b/numeric.rb
@@ -93,9 +93,14 @@ end
class Integer
# call-seq:
- # -int -> integer
+ # -self -> integer
+ #
+ # Returns +self+, negated:
+ #
+ # -1 # => -1
+ # -(-1) # => 1
+ # -0 # => 0
#
- # Returns +self+, negated.
def -@
Primitive.attr! :leaf
Primitive.cexpr! 'rb_int_uminus(self)'
@@ -322,7 +327,7 @@ class Integer
1
end
- with_yjit do
+ with_jit do
if Primitive.rb_builtin_basic_definition_p(:downto)
undef :downto
@@ -373,9 +378,13 @@ class Float
alias magnitude abs
# call-seq:
- # -float -> float
+ # -self -> float
+ #
+ # Returns +self+, negated:
#
- # Returns +self+, negated.
+ # -3.14 # => -3.14
+ # -(-3.14) # => 3.14
+ # -0.0 # => -0.0
#
def -@
Primitive.attr! :leaf
diff --git a/object.c b/object.c
index 74f58a15bd..2e962b1c3c 100644
--- a/object.c
+++ b/object.c
@@ -46,14 +46,9 @@
/* 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
+ * 4: ROBJECT_HEAP
+ * The object has its instance variables in a separately allocated buffer.
+ * This can be either a flat buffer of reference, or an st_table for complex objects.
*/
/*!
@@ -87,6 +82,7 @@ static VALUE rb_cFalseClass_to_s;
#define id_init_dup idInitialize_dup
#define id_const_missing idConst_missing
#define id_to_f idTo_f
+static ID id_instance_variables_to_inspect;
#define CLASS_OR_MODULE_P(obj) \
(!SPECIAL_CONST_P(obj) && \
@@ -94,11 +90,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)
@@ -118,40 +109,11 @@ rb_obj_reveal(VALUE obj, VALUE klass)
return obj;
}
-VALUE
-rb_class_allocate_instance(VALUE klass)
-{
- uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count;
-
- size_t size = rb_obj_embedded_size(index_tbl_num_entries);
- if (!rb_gc_size_allocatable_p(size)) {
- size = sizeof(struct RObject);
- }
-
- NEWOBJ_OF(o, struct RObject, klass,
- T_OBJECT | ROBJECT_EMBED | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 0), size, 0);
- VALUE obj = (VALUE)o;
-
- RUBY_ASSERT(rb_shape_get_shape(obj)->type == SHAPE_ROOT);
-
- // Set the shape to the specific T_OBJECT shape.
- ROBJECT_SET_SHAPE_ID(obj, (shape_id_t)(rb_gc_heap_id_for_size(size) + FIRST_T_OBJECT_SHAPE_ID));
-
-#if RUBY_DEBUG
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
- VALUE *ptr = ROBJECT_IVPTR(obj);
- for (size_t i = 0; i < ROBJECT_IV_CAPACITY(obj); i++) {
- ptr[i] = Qundef;
- }
-#endif
-
- return obj;
-}
VALUE
rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
{
- VALUE ignored_flags = RUBY_FL_PROMOTED | RUBY_FL_SEEN_OBJ_ID;
+ VALUE ignored_flags = RUBY_FL_PROMOTED;
RBASIC(obj)->flags = (type & ~ignored_flags) | (RBASIC(obj)->flags & ignored_flags);
RBASIC_SET_CLASS(obj, klass);
return obj;
@@ -165,7 +127,7 @@ rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
*
* Returns +true+ or +false+.
*
- * Like Object#==, if +object+ is an instance of Object
+ * Like Object#==, if +other+ is an instance of \Object
* (and not an instance of one of its many subclasses).
*
* This method is commonly overridden by those subclasses,
@@ -203,14 +165,18 @@ rb_eql(VALUE obj1, VALUE obj2)
/**
* call-seq:
- * obj == other -> true or false
- * obj.equal?(other) -> true or false
- * obj.eql?(other) -> true or false
+ * self == other -> true or false
+ * equal?(other) -> true or false
+ * eql?(other) -> true or false
*
- * Equality --- At the Object level, #== returns <code>true</code>
- * only if +obj+ and +other+ are the same object. Typically, this
- * method is overridden in descendant classes to provide
- * class-specific meaning.
+ * Returns whether +self+ and +other+ are the same object:
+ *
+ * object = Object.new
+ * object == object # => true
+ * object == Object.new # => false
+ *
+ * Here in class \Object, #==, #equal?, and #eql? are the same method.
+ * A subclass may override #== to provide class-specific meaning.
*
* Unlike #==, the #equal? method should never be overridden by
* subclasses as it is used to determine object identity (that is,
@@ -283,12 +249,38 @@ rb_obj_not_equal(VALUE obj1, VALUE obj2)
return rb_obj_not(result);
}
+static inline VALUE
+fake_class_p(VALUE klass)
+{
+ RUBY_ASSERT(klass);
+ RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
+ STATIC_ASSERT(t_iclass_overlap_t_class, !(T_CLASS & T_ICLASS));
+ STATIC_ASSERT(t_iclass_overlap_t_module, !(T_MODULE & T_ICLASS));
+
+ return FL_TEST_RAW(klass, T_ICLASS | FL_SINGLETON);
+}
+
+static inline VALUE
+class_real(VALUE cl)
+{
+ RUBY_ASSERT(cl);
+
+ // TODO: In the future we should only call this with T_CLASS
+ RUBY_ASSERT(RB_TYPE_P(cl, T_CLASS) || RB_TYPE_P(cl, T_ICLASS) || RB_TYPE_P(cl, T_MODULE));
+
+ while (RB_UNLIKELY(fake_class_p(cl))) {
+ // All paths through super in any box will eventually result in the
+ // same class.
+ cl = RCLASSEXT_SUPER(RCLASS_EXT_PRIME(cl));
+ }
+ return cl;
+}
+
VALUE
rb_class_real(VALUE cl)
{
- while (cl &&
- (RCLASS_SINGLETON_P(cl) || BUILTIN_TYPE(cl) == T_ICLASS)) {
- cl = RCLASS_SUPER(cl);
+ if (cl) {
+ cl = class_real(cl);
}
return cl;
}
@@ -296,7 +288,17 @@ rb_class_real(VALUE cl)
VALUE
rb_obj_class(VALUE obj)
{
- return rb_class_real(CLASS_OF(obj));
+ VALUE cl = CLASS_OF(obj);
+ if (cl) {
+ cl = class_real(cl);
+ }
+ return cl;
+}
+
+static inline VALUE
+rb_obj_class_must(VALUE obj)
+{
+ return class_real(CLASS_OF(obj));
}
/*
@@ -326,65 +328,47 @@ rb_obj_singleton_class(VALUE obj)
void
rb_obj_copy_ivar(VALUE dest, VALUE obj)
{
- RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
-
- 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);
+ RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT));
+ RUBY_ASSERT(RB_TYPE_P(dest, T_OBJECT));
+ unsigned long src_num_ivs = rb_ivar_count(obj);
+ if (!src_num_ivs) {
return;
}
- uint32_t src_num_ivs = RBASIC_IV_COUNT(obj);
- rb_shape_t * shape_to_set_on_dest = src_shape;
- VALUE * src_buf;
- VALUE * dest_buf;
+ shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj);
- if (!src_num_ivs) {
+ if (rb_shape_complex_p(src_shape_id)) {
+ rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj));
return;
}
- // The copy should be mutable, so we don't want the frozen shape
- if (rb_shape_frozen_shape_p(src_shape)) {
- shape_to_set_on_dest = rb_shape_get_parent(src_shape);
- }
-
- src_buf = ROBJECT_IVPTR(obj);
- dest_buf = ROBJECT_IVPTR(dest);
-
- rb_shape_t * initial_shape = rb_shape_get_shape(dest);
-
- if (initial_shape->heap_index != src_shape->heap_index) {
- RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
+ shape_id_t initial_shape_id = RBASIC_SHAPE_ID(dest);
+ RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));
- 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);
+ shape_id_t dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
+ if (UNLIKELY(rb_shape_complex_p(dest_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_init_complex(dest, table);
- return;
- }
+ 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);
- 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);
- }
+ VALUE *src_buf = ROBJECT_FIELDS(obj);
+ VALUE *dest_buf = ROBJECT_FIELDS(dest);
- MEMCPY(dest_buf, src_buf, VALUE, src_num_ivs);
+ attr_index_t initial_capa = RSHAPE_CAPACITY(initial_shape_id);
+ attr_index_t dest_capa = RSHAPE_CAPACITY(dest_shape_id);
- // Fire write barriers
- for (uint32_t i = 0; i < src_num_ivs; i++) {
- RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
+ RUBY_ASSERT(src_num_ivs <= dest_capa);
+ if (initial_capa < dest_capa) {
+ rb_ensure_iv_list_size(dest, 0, dest_capa);
+ dest_buf = ROBJECT_FIELDS(dest);
}
- rb_shape_set_shape(dest, shape_to_set_on_dest);
+ rb_shape_copy_fields(dest, dest_buf, dest_shape_id, src_buf, src_shape_id);
+ RBASIC_SET_SHAPE_ID(dest, dest_shape_id);
}
static void
@@ -393,14 +377,25 @@ init_copy(VALUE dest, VALUE obj)
if (OBJ_FROZEN(dest)) {
rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest));
}
- RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR);
+ RBASIC(dest)->flags &= ~T_MASK;
// Copies the shape id from obj to dest
- RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR);
- rb_gc_copy_attributes(dest, obj);
- rb_copy_generic_ivar(dest, obj);
- if (RB_TYPE_P(obj, T_OBJECT)) {
+ RBASIC(dest)->flags |= RBASIC(obj)->flags & T_MASK;
+ switch (BUILTIN_TYPE(obj)) {
+ case T_IMEMO:
+ rb_bug("Unreachable");
+ break;
+ case T_CLASS:
+ case T_MODULE:
+ rb_mod_init_copy(dest, obj);
+ break;
+ case T_OBJECT:
rb_obj_copy_ivar(dest, obj);
+ break;
+ default:
+ rb_copy_generic_ivar(dest, obj);
+ break;
}
+ rb_gc_copy_attributes(dest, obj);
}
static VALUE immutable_obj_clone(VALUE obj, VALUE kwfreeze);
@@ -506,13 +501,8 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
}
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);
- }
+ shape_id_t next_shape_id = rb_obj_shape_transition_frozen(clone);
+ RBASIC_SET_SHAPE_ID(clone, next_shape_id);
}
break;
case Qtrue: {
@@ -527,16 +517,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
argv[0] = obj;
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);
- }
+ OBJ_FREEZE(clone);
break;
}
case Qfalse: {
@@ -755,11 +736,17 @@ rb_inspect(VALUE obj)
static int
inspect_i(ID id, VALUE value, st_data_t a)
{
- VALUE str = (VALUE)a;
+ VALUE *args = (VALUE *)a, str = args[0], ivars = args[1];
/* need not to show internal data */
if (CLASS_OF(value) == 0) return ST_CONTINUE;
if (!rb_is_instance_id(id)) return ST_CONTINUE;
+ if (!NIL_P(ivars)) {
+ VALUE name = ID2SYM(id);
+ for (long i = 0; RARRAY_AREF(ivars, i) != name; ) {
+ if (++i >= RARRAY_LEN(ivars)) return ST_CONTINUE;
+ }
+ }
if (RSTRING_PTR(str)[0] == '-') { /* first element */
RSTRING_PTR(str)[0] = '#';
rb_str_cat2(str, " ");
@@ -774,13 +761,15 @@ inspect_i(ID id, VALUE value, st_data_t a)
}
static VALUE
-inspect_obj(VALUE obj, VALUE str, int recur)
+inspect_obj(VALUE obj, VALUE a, int recur)
{
+ VALUE *args = (VALUE *)a, str = args[0];
+
if (recur) {
rb_str_cat2(str, " ...");
}
else {
- rb_ivar_foreach(obj, inspect_i, str);
+ rb_ivar_foreach_buffered(obj, inspect_i, a);
}
rb_str_cat2(str, ">");
RSTRING_PTR(str)[0] = '#';
@@ -813,23 +802,67 @@ inspect_obj(VALUE obj, VALUE str, int recur)
* end
* end
* Bar.new.inspect #=> "#<Bar:0x0300c868 @bar=1>"
+ *
+ * If _obj_ responds to +instance_variables_to_inspect+, then only
+ * the instance variables listed in the returned array will be included
+ * in the inspect string.
+ *
+ *
+ * class DatabaseConfig
+ * def initialize(host, user, password)
+ * @host = host
+ * @user = user
+ * @password = password
+ * end
+ *
+ * private
+ * def instance_variables_to_inspect = [:@host, :@user]
+ * end
+ *
+ * conf = DatabaseConfig.new("localhost", "root", "hunter2")
+ * conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
*/
static VALUE
rb_obj_inspect(VALUE obj)
{
- if (rb_ivar_count(obj) > 0) {
- VALUE str;
- VALUE c = rb_class_name(CLASS_OF(obj));
+ VALUE ivars = rb_check_funcall(obj, id_instance_variables_to_inspect, 0, 0);
+ st_index_t n = 0;
+ if (UNDEF_P(ivars) || NIL_P(ivars)) {
+ n = rb_ivar_count(obj);
+ ivars = Qnil;
+ }
+ else if (RB_TYPE_P(ivars, T_ARRAY)) {
+ n = RARRAY_LEN(ivars);
+ }
+ else {
+ rb_raise(
+ rb_eTypeError,
+ "Expected #instance_variables_to_inspect to return an Array or nil, but it returned %"PRIsVALUE,
+ rb_obj_class(ivars)
+ );
+ }
- str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj);
- return rb_exec_recursive(inspect_obj, obj, str);
+ if (n > 0) {
+ VALUE c = rb_class_name(CLASS_OF(obj));
+ VALUE args[2] = {
+ rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj),
+ ivars
+ };
+ return rb_exec_recursive(inspect_obj, obj, (VALUE)args);
}
else {
return rb_any_to_s(obj);
}
}
+/* :nodoc: */
+static VALUE
+rb_obj_instance_variables_to_inspect(VALUE obj)
+{
+ return Qnil;
+}
+
static VALUE
class_or_module_required(VALUE c)
{
@@ -1193,6 +1226,30 @@ rb_class_search_ancestor(VALUE cl, VALUE c)
*
* Added :FOO
*
+ * If we define a class using the <tt>class</tt> keyword, <tt>const_added</tt>
+ * runs before <tt>inherited</tt>:
+ *
+ * module M
+ * def self.const_added(const_name)
+ * super
+ * p :const_added
+ * end
+ *
+ * parent = Class.new do
+ * def self.inherited(subclass)
+ * super
+ * p :inherited
+ * end
+ * end
+ *
+ * class Child < parent
+ * end
+ * end
+ *
+ * <em>produces:</em>
+ *
+ * :const_added
+ * :inherited
*/
#define rb_obj_mod_const_added rb_obj_dummy1
@@ -1498,10 +1555,10 @@ rb_true_to_s(VALUE obj)
/*
- * call-seq:
- * true & object -> true or false
+ * call-seq:
+ * true & object -> true or false
*
- * Returns +false+ if +object+ is +false+ or +nil+, +true+ otherwise:
+ * Returns +false+ if +object+ is +false+ or +nil+, +true+ otherwise:
*
* true & Object.new # => true
* true & false # => false
@@ -1684,21 +1741,33 @@ rb_obj_not_match(VALUE obj1, VALUE obj2)
/*
* call-seq:
- * obj <=> other -> 0 or nil
+ * self <=> other -> 0 or nil
+ *
+ * Compares +self+ and +other+.
*
- * Returns 0 if +obj+ and +other+ are the same object
- * or <code>obj == other</code>, otherwise nil.
+ * Returns:
*
- * The #<=> is used by various methods to compare objects, for example
- * Enumerable#sort, Enumerable#max etc.
+ * - +0+, if +self+ and +other+ are the same object,
+ * or if <tt>self == other</tt>.
+ * - +nil+, otherwise.
*
- * Your implementation of #<=> should return one of the following values: -1, 0,
- * 1 or nil. -1 means self is smaller than other. 0 means self is equal to other.
- * 1 means self is bigger than other. Nil means the two values could not be
- * compared.
+ * Examples:
+ *
+ * o = Object.new
+ * o <=> o # => 0
+ * o <=> o.dup # => nil
+ *
+ * A class that includes module Comparable
+ * should override this method by defining an instance method that:
+ *
+ * - Take one argument, +other+.
+ * - Returns:
+ *
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if +self+ is equal to +other+.
+ * - +1+, if +self+ is greater than +other+.
+ * - +nil+, if the two values are incommensurate.
*
- * When you define #<=>, you can include Comparable to gain the
- * methods #<=, #<, #==, #>=, #> and #between?.
*/
static VALUE
rb_obj_cmp(VALUE obj1, VALUE obj2)
@@ -1798,11 +1867,12 @@ rb_mod_freeze(VALUE mod)
/*
* call-seq:
- * mod === obj -> true or false
+ * self === other -> true or false
+ *
+ * Returns whether +other+ is an instance of +self+,
+ * or is an instance of a subclass of +self+.
*
- * Case Equality---Returns <code>true</code> if <i>obj</i> is an
- * instance of <i>mod</i> or an instance of one of <i>mod</i>'s descendants.
- * Of limited use for modules, but can be used in <code>case</code> statements
+ * Of limited use for modules, but can be used in +case+ statements
* to classify objects by class.
*/
@@ -1814,13 +1884,27 @@ rb_mod_eqq(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod <= other -> true, false, or nil
+ * self <= other -> true, false, or nil
+ *
+ * Compares +self+ and +other+ with respect to ancestry and inclusion.
+ *
+ * Returns +nil+ if there is no such relationship between the two:
+ *
+ * Array <= Hash # => nil
+ *
+ * Otherwise, returns +true+ if +other+ is an ancestor of +self+,
+ * or if +self+ includes +other+,
+ * or if the two are the same:
+ *
+ * File <= IO # => true # IO is an ancestor of File.
+ * Array <= Enumerable # => true # Array includes Enumerable.
+ * Array <= Array # => true
+ *
+ * Otherwise, returns +false+:
+ *
+ * IO <= File # => false
+ * Enumerable <= Array # => false
*
- * Returns true if <i>mod</i> is a subclass of <i>other</i> or
- * is the same as <i>other</i>. Returns
- * <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "A < B".)
*/
VALUE
@@ -1866,14 +1950,26 @@ rb_class_inherited_p(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod < other -> true, false, or nil
+ * self < other -> true, false, or nil
+ *
+ * Returns +true+ if +self+ is a descendant of +other+
+ * (+self+ is a subclass of +other+ or +self+ includes +other+):
+ *
+ * Float < Numeric # => true
+ * Array < Enumerable # => true
+ *
+ * Returns +false+ if +self+ is an ancestor of +other+
+ * (+self+ is a superclass of +other+ or +self+ is included in +other+) or
+ * if +self+ is the same as +other+:
+ *
+ * Numeric < Float # => false
+ * Enumerable < Array # => false
+ * Float < Float # => false
+ *
+ * Returns +nil+ if there is no relationship between the two:
*
- * Returns true if <i>mod</i> is a subclass of <i>other</i>. Returns
- * <code>false</code> if <i>mod</i> is the same as <i>other</i>
- * or <i>mod</i> is an ancestor of <i>other</i>.
- * Returns <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "A < B".)
+ * Float < Hash # => nil
+ * Enumerable < String # => nil
*
*/
@@ -1887,13 +1983,28 @@ rb_mod_lt(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod >= other -> true, false, or nil
+ * self >= other -> true, false, or nil
+ *
+ * Compares +self+ and +other+ with respect to ancestry and inclusion.
+ *
+ * Returns +true+ if +self+ is an ancestor of +other+
+ * (+self+ is a superclass of +other+ or +self+ is included in +other+) or
+ * if +self+ is the same as +other+:
+ *
+ * Numeric >= Float # => true
+ * Enumerable >= Array # => true
+ * Float >= Float # => true
+ *
+ * Returns +false+ if +self+ is a descendant of +other+
+ * (+self+ is a subclass of +other+ or +self+ includes +other+):
+ *
+ * Float >= Numeric # => false
+ * Array >= Enumerable # => false
+ *
+ * Returns +nil+ if there is no relationship between the two:
*
- * Returns true if <i>mod</i> is an ancestor of <i>other</i>, or the
- * two modules are the same. Returns
- * <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "B > A".)
+ * Float >= Hash # => nil
+ * Enumerable >= String # => nil
*
*/
@@ -1909,14 +2020,26 @@ rb_mod_ge(VALUE mod, VALUE arg)
/*
* call-seq:
- * mod > other -> true, false, or nil
+ * self > other -> true, false, or nil
*
- * Returns true if <i>mod</i> is an ancestor of <i>other</i>. Returns
- * <code>false</code> if <i>mod</i> is the same as <i>other</i>
- * or <i>mod</i> is a descendant of <i>other</i>.
- * Returns <code>nil</code> if there's no relationship between the two.
- * (Think of the relationship in terms of the class definition:
- * "class A < B" implies "B > A".)
+ * Returns +true+ if +self+ is an ancestor of +other+
+ * (+self+ is a superclass of +other+ or +self+ is included in +other+):
+ *
+ * Numeric > Float # => true
+ * Enumerable > Array # => true
+ *
+ * Returns +false+ if +self+ is a descendant of +other+
+ * (+self+ is a subclass of +other+ or +self+ includes +other+) or
+ * if +self+ is the same as +other+:
+ *
+ * Float > Numeric # => false
+ * Array > Enumerable # => false
+ * Float > Float # => false
+ *
+ * Returns +nil+ if there is no relationship between the two:
+ *
+ * Float > Hash # => nil
+ * Enumerable > String # => nil
*
*/
@@ -1929,14 +2052,30 @@ rb_mod_gt(VALUE mod, VALUE arg)
/*
* call-seq:
- * module <=> other_module -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
*
- * Comparison---Returns -1, 0, +1 or nil depending on whether +module+
- * includes +other_module+, they are the same, or if +module+ is included by
- * +other_module+.
+ * Returns:
+ *
+ * - +-1+, if +self+ includes +other+, if or +self+ is a subclass of +other+.
+ * - +0+, if +self+ and +other+ are the same.
+ * - +1+, if +other+ includes +self+, or if +other+ is a subclass of +self+.
+ * - +nil+, if none of the above is true.
+ *
+ * Examples:
+ *
+ * # Class Array includes module Enumerable.
+ * Array <=> Enumerable # => -1
+ * Enumerable <=> Enumerable # => 0
+ * Enumerable <=> Array # => 1
+ * # Class File is a subclass of class IO.
+ * File <=> IO # => -1
+ * File <=> File # => 0
+ * IO <=> File # => 1
+ * # Class File has no relationship to class String.
+ * File <=> String # => nil
*
- * Returns +nil+ if +module+ has no relationship with +other_module+, if
- * +other_module+ is not a module, or if the two values are incomparable.
*/
static VALUE
@@ -1961,28 +2100,52 @@ static VALUE rb_mod_initialize_exec(VALUE module);
/*
* call-seq:
- * Module.new -> mod
- * Module.new {|mod| block } -> mod
+ * Module.new -> new_module
+ * Module.new {|module| ... } -> new_module
*
- * Creates a new anonymous module. If a block is given, it is passed
- * the module object, and the block is evaluated in the context of this
- * module like #module_eval.
+ * Returns a new anonymous module.
*
- * fred = Module.new do
- * def meth1
- * "hello"
- * end
- * def meth2
- * "bye"
- * end
- * end
- * a = "my string"
- * a.extend(fred) #=> "my string"
- * a.meth1 #=> "hello"
- * a.meth2 #=> "bye"
+ * The module may be assigned to a name,
+ * which should be a constant name
+ * in capitalized {camel case}[https://en.wikipedia.org/wiki/Camel_case]
+ * (e.g., +MyModule+, not +MY_MODULE+).
+ *
+ * With no block given, returns the new module.
+ *
+ * MyModule = Module.new
+ * MyModule.class # => Module
+ * MyModule.name # => "MyModule"
+ *
+ * With a block given, calls the block with the new (not yet named) module:
+ *
+ * MyModule = Module.new {|m| p [m.class, m.name] }
+ * # => MyModule
+ * MyModule.class # => Module
+ MyModule.name # => "MyModule"
+ *
+ * Output (from the block):
+ *
+ * [Module, nil]
+ *
+ * The block may define methods and constants for the module:
+ *
+ * MyModule = Module.new do |m|
+ * MY_CONSTANT = "#{MyModule} constant value"
+ * def self.method1 = "#{MyModule} first method (singleton)"
+ * def method2 = "#{MyModule} Second method (instance)"
+ * end
+ * MyModule.method1 # => "MyModule first method (singleton)"
+ * class Foo
+ * include MyModule
+ * def speak
+ * MY_CONSTANT
+ * end
+ * end
+ * foo = Foo.new
+ * foo.method2 # => "MyModule Second method (instance)"
+ * foo.speak
+ * # => "MyModule constant value"
*
- * Assign the module to a constant (name starting uppercase) if you
- * want to treat it like a regular module.
*/
static VALUE
@@ -2056,11 +2219,13 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
else {
super = argv[0];
rb_check_inheritable(super);
- if (super != rb_cBasicObject && !RCLASS_SUPER(super)) {
+ if (!RCLASS_INITIALIZED_P(super)) {
rb_raise(rb_eTypeError, "can't inherit uninitialized class");
}
}
- RCLASS_SET_SUPER(klass, super);
+ rb_class_set_super(klass, super);
+ RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super));
+ RCLASS_SET_ALLOCATOR(klass, RCLASS_ALLOCATOR(super));
rb_make_metaclass(klass, RBASIC(super)->klass);
rb_class_inherited(super, klass);
rb_mod_initialize_exec(klass);
@@ -2102,19 +2267,9 @@ static VALUE class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass);
*/
static VALUE
-rb_class_alloc_m(VALUE klass)
-{
- rb_alloc_func_t allocator = class_get_alloc_func(klass);
- if (!rb_obj_respond_to(klass, rb_intern("allocate"), 1)) {
- rb_raise(rb_eTypeError, "calling %"PRIsVALUE".allocate is prohibited",
- klass);
- }
- return class_call_alloc_func(allocator, klass);
-}
-
-static VALUE
rb_class_alloc(VALUE klass)
{
+ RBIMPL_ASSERT_TYPE(klass, T_CLASS);
rb_alloc_func_t allocator = class_get_alloc_func(klass);
return class_call_alloc_func(allocator, klass);
}
@@ -2124,7 +2279,7 @@ class_get_alloc_func(VALUE klass)
{
rb_alloc_func_t allocator;
- if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) {
+ if (!RCLASS_INITIALIZED_P(klass)) {
rb_raise(rb_eTypeError, "can't instantiate uninitialized class");
}
if (RCLASS_SINGLETON_P(klass)) {
@@ -2137,6 +2292,15 @@ class_get_alloc_func(VALUE klass)
return allocator;
}
+// Might return NULL.
+rb_alloc_func_t
+rb_zjit_class_get_alloc_func(VALUE klass)
+{
+ assert(RCLASS_INITIALIZED_P(klass));
+ assert(!RCLASS_SINGLETON_P(klass));
+ return rb_get_alloc_func(klass);
+}
+
static VALUE
class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass)
{
@@ -2146,9 +2310,7 @@ class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass)
obj = (*allocator)(klass);
- if (rb_obj_class(obj) != rb_class_real(klass)) {
- rb_raise(rb_eTypeError, "wrong instance allocation");
- }
+ RUBY_ASSERT(rb_obj_class(obj) == rb_class_real(klass));
return obj;
}
@@ -2231,19 +2393,22 @@ rb_class_superclass(VALUE klass)
{
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
- VALUE super = RCLASS_SUPER(klass);
+ VALUE *superclasses = RCLASS_SUPERCLASSES(klass);
+ size_t superclasses_depth = RCLASS_SUPERCLASS_DEPTH(klass);
+
+ if (klass == rb_cBasicObject) return Qnil;
- if (!super) {
- if (klass == rb_cBasicObject) return Qnil;
+ if (!superclasses) {
+ RUBY_ASSERT(!RCLASS_SUPER(klass));
rb_raise(rb_eTypeError, "uninitialized class");
}
- if (!RCLASS_SUPERCLASS_DEPTH(klass)) {
+ if (!superclasses_depth) {
return Qnil;
}
else {
- super = RCLASS_SUPERCLASSES(klass)[RCLASS_SUPERCLASS_DEPTH(klass) - 1];
- RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
+ VALUE super = superclasses[superclasses_depth - 1];
+ RUBY_ASSERT(RB_TYPE_P(super, T_CLASS));
return super;
}
}
@@ -2251,7 +2416,7 @@ rb_class_superclass(VALUE klass)
VALUE
rb_class_get_superclass(VALUE klass)
{
- return RCLASS(klass)->super;
+ return RCLASS_SUPER(klass);
}
static const char bad_instance_name[] = "'%1$s' is not allowed as an instance variable name";
@@ -3137,19 +3302,12 @@ convert_type_with_id(VALUE val, const char *tname, ID method, int raise, int ind
VALUE r = rb_check_funcall(val, method, 0, 0);
if (UNDEF_P(r)) {
if (raise) {
- const char *msg =
- ((index < 0 ? conv_method_index(rb_id2name(method)) : index)
- < IMPLICIT_CONVERSIONS) ?
- "no implicit conversion of" : "can't convert";
- const char *cname = NIL_P(val) ? "nil" :
- val == Qtrue ? "true" :
- val == Qfalse ? "false" :
- NULL;
- if (cname)
- rb_raise(rb_eTypeError, "%s %s into %s", msg, cname, tname);
- rb_raise(rb_eTypeError, "%s %"PRIsVALUE" into %s", msg,
- rb_obj_class(val),
- tname);
+ if ((index < 0 ? conv_method_index(rb_id2name(method)) : index) < IMPLICIT_CONVERSIONS) {
+ rb_no_implicit_conversion(val, tname);
+ }
+ else {
+ rb_cant_convert(val, tname);
+ }
}
return Qnil;
}
@@ -3165,17 +3323,6 @@ convert_type(VALUE val, const char *tname, const char *method, int raise)
return convert_type_with_id(val, tname, m, raise, i);
}
-/*! \private */
-NORETURN(static void conversion_mismatch(VALUE, const char *, const char *, VALUE));
-static void
-conversion_mismatch(VALUE val, const char *tname, const char *method, VALUE result)
-{
- VALUE cname = rb_obj_class(val);
- rb_raise(rb_eTypeError,
- "can't convert %"PRIsVALUE" to %s (%"PRIsVALUE"#%s gives %"PRIsVALUE")",
- cname, tname, cname, method, rb_obj_class(result));
-}
-
VALUE
rb_convert_type(VALUE val, int type, const char *tname, const char *method)
{
@@ -3184,7 +3331,7 @@ rb_convert_type(VALUE val, int type, const char *tname, const char *method)
if (TYPE(val) == type) return val;
v = convert_type(val, tname, method, TRUE);
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, method, v);
+ rb_cant_convert_invalid_return(val, tname, method, v);
}
return v;
}
@@ -3198,7 +3345,7 @@ rb_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
if (TYPE(val) == type) return val;
v = convert_type_with_id(val, tname, method, TRUE, -1);
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, RSTRING_PTR(rb_id2str(method)), v);
+ rb_cant_convert_invalid_return(val, tname, rb_id2name(method), v);
}
return v;
}
@@ -3213,7 +3360,7 @@ rb_check_convert_type(VALUE val, int type, const char *tname, const char *method
v = convert_type(val, tname, method, FALSE);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, method, v);
+ rb_cant_convert_invalid_return(val, tname, method, v);
}
return v;
}
@@ -3229,7 +3376,7 @@ rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
v = convert_type_with_id(val, tname, method, FALSE, -1);
if (NIL_P(v)) return Qnil;
if (TYPE(v) != type) {
- conversion_mismatch(val, tname, RSTRING_PTR(rb_id2str(method)), v);
+ rb_cant_convert_invalid_return(val, tname, rb_id2name(method), v);
}
return v;
}
@@ -3255,7 +3402,7 @@ rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise
return Qnil;
}
if (!RB_INTEGER_TYPE_P(v)) {
- conversion_mismatch(val, "Integer", method, v);
+ rb_cant_convert_invalid_return(val, "Integer", method, v);
}
GET_EC()->cfp = current_cfp;
return v;
@@ -3332,7 +3479,7 @@ rb_convert_to_integer(VALUE val, int base, int raise_exception)
}
else if (NIL_P(val)) {
if (!raise_exception) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Integer");
+ rb_cant_convert(val, "Integer");
}
tmp = rb_protect(rb_check_to_int, val, NULL);
@@ -3626,18 +3773,6 @@ rat2dbl_without_to_f(VALUE x)
}
/*! \endcond */
-static inline void
-conversion_to_float(VALUE val)
-{
- special_const_to_float(val, "can't convert ", " into Float");
-}
-
-static inline void
-implicit_conversion_to_float(VALUE val)
-{
- special_const_to_float(val, "no implicit conversion to float from ", "");
-}
-
static int
to_float(VALUE *valp, int raise_exception)
{
@@ -3651,7 +3786,7 @@ to_float(VALUE *valp, int raise_exception)
return T_FLOAT;
}
else if (raise_exception) {
- conversion_to_float(val);
+ rb_cant_convert(val, "Float");
}
}
else {
@@ -3731,8 +3866,7 @@ static VALUE
numeric_to_float(VALUE val)
{
if (!rb_obj_is_kind_of(val, rb_cNumeric)) {
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into Float",
- rb_obj_class(val));
+ rb_cant_convert(val, "Float");
}
return rb_convert_type_with_id(val, T_FLOAT, "Float", id_to_f);
}
@@ -3776,7 +3910,7 @@ rb_num_to_dbl(VALUE val)
return rb_float_flonum_value(val);
}
else {
- conversion_to_float(val);
+ rb_cant_convert(val, "Float");
}
}
else {
@@ -3810,7 +3944,7 @@ rb_num2dbl(VALUE val)
return rb_float_flonum_value(val);
}
else {
- implicit_conversion_to_float(val);
+ rb_no_implicit_conversion(val, "Float");
}
}
else {
@@ -3822,7 +3956,7 @@ rb_num2dbl(VALUE val)
case T_RATIONAL:
return rat2dbl_without_to_f(val);
case T_STRING:
- rb_raise(rb_eTypeError, "no implicit conversion to float from string");
+ rb_no_implicit_conversion(val, "Float");
default:
break;
}
@@ -3916,7 +4050,7 @@ rb_Hash(VALUE val)
if (NIL_P(tmp)) {
if (RB_TYPE_P(val, T_ARRAY) && RARRAY_LEN(val) == 0)
return rb_hash_new();
- rb_raise(rb_eTypeError, "can't convert %s into Hash", rb_obj_classname(val));
+ rb_cant_convert(val, "Hash");
}
return tmp;
}
@@ -3937,7 +4071,7 @@ rb_Hash(VALUE val)
*
* Examples:
*
- * Hash({foo: 0, bar: 1}) # => {:foo=>0, :bar=>1}
+ * Hash({foo: 0, bar: 1}) # => {foo: 0, bar: 1}
* Hash(nil) # => {}
* Hash([]) # => {}
*
@@ -4024,7 +4158,7 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
* into +format_string+.
*
* For details on +format_string+, see
- * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
*/
static VALUE
@@ -4189,8 +4323,8 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
*
* First, what's elsewhere. Class \Object:
*
- * - Inherits from {class BasicObject}[rdoc-ref:BasicObject@What-27s+Here].
- * - Includes {module Kernel}[rdoc-ref:Kernel@What-27s+Here].
+ * - Inherits from {class BasicObject}[rdoc-ref:BasicObject@Whats+Here].
+ * - Includes {module Kernel}[rdoc-ref:Kernel@Whats+Here].
*
* Here, class \Object provides methods for:
*
@@ -4284,7 +4418,6 @@ InitVM_Object(void)
#endif
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_initialize, 0);
- rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);
rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1);
rb_define_method(rb_cBasicObject, "!", rb_obj_not, 0);
@@ -4465,6 +4598,7 @@ InitVM_Object(void)
rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0);
rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0);
+ rb_define_private_method(rb_mKernel, "instance_variables_to_inspect", rb_obj_instance_variables_to_inspect, 0);
rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); /* in class.c */
rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */
rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); /* in class.c */
@@ -4513,7 +4647,6 @@ InitVM_Object(void)
rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1);
rb_define_method(rb_cModule, ">", rb_mod_gt, 1);
rb_define_method(rb_cModule, ">=", rb_mod_ge, 1);
- rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */
rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0);
rb_define_alias(rb_cModule, "inspect", "to_s");
rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */
@@ -4562,8 +4695,8 @@ InitVM_Object(void)
rb_define_method(rb_cModule, "deprecate_constant", rb_mod_deprecate_constant, -1); /* in variable.c */
rb_define_method(rb_cModule, "singleton_class?", rb_mod_singleton_p, 0);
- rb_define_method(rb_singleton_class(rb_cClass), "allocate", rb_class_alloc_m, 0);
- rb_define_method(rb_cClass, "allocate", rb_class_alloc_m, 0);
+ rb_define_method(rb_singleton_class(rb_cClass), "allocate", rb_class_alloc, 0);
+ rb_define_method(rb_cClass, "allocate", rb_class_alloc, 0);
rb_define_method(rb_cClass, "new", rb_class_new_instance_pass_kw, -1);
rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1);
rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0);
@@ -4606,6 +4739,7 @@ void
Init_Object(void)
{
id_dig = rb_intern_const("dig");
+ id_instance_variables_to_inspect = rb_intern_const("instance_variables_to_inspect");
InitVM(Object);
}
diff --git a/pack.c b/pack.c
index 3a5c1bfb96..24221bc3d6 100644
--- a/pack.c
+++ b/pack.c
@@ -19,6 +19,7 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/bits.h"
+#include "internal/numeric.h"
#include "internal/string.h"
#include "internal/symbol.h"
#include "internal/variable.h"
@@ -61,7 +62,7 @@ is_bigendian(void)
{
static int init = 0;
static int endian_value;
- char *p;
+ const char *p;
if (init) return endian_value;
init = 1;
@@ -118,6 +119,7 @@ typedef union {
#define MAX_INTEGER_PACK_SIZE 8
static const char toofew[] = "too few arguments";
+static const char intoitself[] = "cannot pack buffer object into itself";
static void encodes(VALUE,const char*,long,int,int);
static void qpencode(VALUE,VALUE,long);
@@ -279,6 +281,8 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
#define MORE_ITEM (idx < RARRAY_LEN(ary))
#define THISFROM (MORE_ITEM ? RARRAY_AREF(ary, idx) : TOO_FEW)
#define NEXTFROM (MORE_ITEM ? RARRAY_AREF(ary, idx++) : TOO_FEW)
+#define NOT_BUFFER(val) (((val) == res) ? rb_raise(rb_eArgError, intoitself) : (void)0)
+#define STR_FROM(val) NOT_BUFFER(StringValue(val))
while (p < pend) {
int explicit_endian = 0;
@@ -302,7 +306,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
else if (ISDIGIT(*p)) {
errno = 0;
len = STRTOUL(p, (char**)&p, 10);
- if (errno) {
+ if (len < 0 || errno) {
rb_raise(rb_eRangeError, "pack length too big");
}
}
@@ -333,7 +337,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
plen = 0;
}
else {
- StringValue(from);
+ STR_FROM(from);
ptr = RSTRING_PTR(from);
plen = RSTRING_LEN(from);
}
@@ -667,10 +671,58 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
}
break;
+ case 'r': /* r for SLEB128 encoding (signed) */
+ case 'R': /* R for ULEB128 encoding (unsigned) */
+ {
+ int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
+
+ if (type == 'r') {
+ pack_flags |= INTEGER_PACK_2COMP;
+ }
+
+ while (len-- > 0) {
+ size_t numbytes, nlz_bits;
+ int sign, extra = 0;
+ char *cp;
+ const long start = RSTRING_LEN(res);
+
+ from = NEXTFROM;
+ from = rb_to_int(from);
+ if (type == 'R' && rb_int_negative_p(from)) {
+ rb_raise(rb_eArgError, "can't encode negative numbers in ULEB128");
+ }
+
+ numbytes = rb_absint_numwords(from, 7, &nlz_bits);
+ if (numbytes == 0) {
+ numbytes = 1;
+ }
+ else if (nlz_bits == 0 && type == 'r') {
+ /* No leading zero bits, we need an extra byte for sign extension */
+ extra = 1;
+ }
+ rb_str_modify_expand(res, numbytes + extra);
+
+ cp = RSTRING_PTR(res) + start;
+ sign = rb_integer_pack(from, cp, numbytes, 1, 1, pack_flags);
+
+ if (extra) {
+ /* Need an extra byte */
+ cp[numbytes++] = sign < 0 ? 0x7f : 0x00;
+ }
+ rb_str_set_len(res, start + numbytes);
+
+ while (1 < numbytes) {
+ *cp |= 0x80;
+ cp++;
+ numbytes--;
+ }
+ }
+ }
+ break;
case 'u': /* uuencoded string */
case 'm': /* base64 encoded string */
from = NEXTFROM;
- StringValue(from);
+ STR_FROM(from);
ptr = RSTRING_PTR(from);
plen = RSTRING_LEN(from);
@@ -700,6 +752,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'M': /* quoted-printable encoded string */
from = rb_obj_as_string(NEXTFROM);
+ NOT_BUFFER(from);
if (len <= 1)
len = 72;
qpencode(res, from, len);
@@ -708,7 +761,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'P': /* pointer to packed byte string */
from = THISFROM;
if (!NIL_P(from)) {
- StringValue(from);
+ STR_FROM(from);
if (RSTRING_LEN(from) < len) {
rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
RSTRING_LEN(from), len);
@@ -718,13 +771,11 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
/* FALL THROUGH */
case 'p': /* pointer to string */
while (len-- > 0) {
- char *t;
+ const char *t = 0;
from = NEXTFROM;
- if (NIL_P(from)) {
- t = 0;
- }
- else {
- t = StringValuePtr(from);
+ if (!NIL_P(from)) {
+ STR_FROM(from);
+ t = RSTRING_PTR(from);
}
if (!associates) {
associates = rb_ary_new();
@@ -736,7 +787,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'w': /* BER compressed integer */
while (len-- > 0) {
- VALUE buf = rb_str_new(0, 0);
+ VALUE buf;
size_t numbytes;
int sign;
char *cp;
@@ -950,8 +1001,8 @@ static VALUE
pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
{
#define hexdigits ruby_hexdigits
- char *s, *send;
- char *p, *pend;
+ const char *s, *send;
+ const char *p, *pend;
VALUE ary, associates = Qfalse;
long len;
AVOID_CC_BUG long tmp_len;
@@ -973,9 +1024,10 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
StringValue(fmt);
rb_must_asciicompat(fmt);
- if (offset < 0) rb_raise(rb_eArgError, "offset can't be negative");
len = RSTRING_LEN(str);
- if (offset > len) rb_raise(rb_eArgError, "offset outside of string");
+ if (offset < 0 ? (offset += len) < 0 : offset > len) {
+ rb_raise(rb_eArgError, "offset outside of string");
+ }
s = RSTRING_PTR(str);
send = s + len;
@@ -1025,7 +1077,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
if (len > send - s) len = send - s;
{
long end = len;
- char *t = s + len - 1;
+ const char *t = s + len - 1;
while (t >= s) {
if (*t != ' ' && *t != '\0') break;
@@ -1038,7 +1090,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
case 'Z':
{
- char *t = s;
+ const char *t = s;
if (len > send-s) len = send-s;
while (t < s+len && *t) t++;
@@ -1472,7 +1524,8 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
case 'M':
{
VALUE buf = rb_str_new(0, send - s);
- char *ptr = RSTRING_PTR(buf), *ss = s;
+ char *ptr = RSTRING_PTR(buf);
+ const char *ss = s;
int csum = 0;
int c1, c2;
@@ -1520,10 +1573,14 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
s += len;
break;
+ case '^':
+ UNPACK_PUSH(SSIZET2NUM(s - RSTRING_PTR(str)));
+ break;
+
case 'P':
if (sizeof(char *) <= (size_t)(send - s)) {
VALUE tmp = Qnil;
- char *t;
+ const char *t;
UNPACK_FETCH(&t, char *);
if (t) {
@@ -1546,7 +1603,7 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
break;
else {
VALUE tmp = Qnil;
- char *t;
+ const char *t;
UNPACK_FETCH(&t, char *);
if (t) {
@@ -1558,9 +1615,42 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
}
break;
+ case 'r':
+ case 'R':
+ {
+ int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
+
+ if (type == 'r') {
+ pack_flags |= INTEGER_PACK_2COMP;
+ }
+ const char *s0 = s;
+ while (len > 0 && s < send) {
+ if (*s & 0x80) {
+ s++;
+ }
+ else {
+ s++;
+ UNPACK_PUSH(rb_integer_unpack(s0, s-s0, 1, 1, pack_flags));
+ len--;
+ s0 = s;
+ }
+ }
+ /* Handle incomplete value and remaining expected values with nil (only if not using *) */
+ if (!star) {
+ if (s0 != s && len > 0) {
+ UNPACK_PUSH(Qnil);
+ len--;
+ }
+ while (len-- > 0) {
+ UNPACK_PUSH(Qnil);
+ }
+ }
+ }
+ break;
+
case 'w':
{
- char *s0 = s;
+ const char *s0 = s;
while (len > 0 && s < send) {
if (*s & 0x80) {
s++;
diff --git a/pack.rb b/pack.rb
index e70c6c7dc8..78ef6973d4 100644
--- a/pack.rb
+++ b/pack.rb
@@ -3,23 +3,25 @@ class Array
# pack(template, buffer: nil) -> string
#
# Formats each element in +self+ into a binary string; returns that string.
- # See {Packed Data}[rdoc-ref:packed_data.rdoc].
+ # See {Packed Data}[rdoc-ref:language/packed_data.md].
def pack(fmt, buffer: nil)
Primitive.pack_pack(fmt, buffer)
end
end
class String
- # call-seq:
- # unpack(template, offset: 0, &block) -> array
+ # call-seq:
+ # unpack(template, offset: 0) {|o| .... } -> object
+ # unpack(template, offset: 0) -> array
#
- # Extracts data from +self+.
+ # Extracts data from +self+ to form new objects;
+ # see {Packed Data}[rdoc-ref:language/packed_data.md].
#
- # If +block+ is not given, forming objects that become the elements
- # of a new array, and returns that array. Otherwise, yields each
- # object.
+ # With a block given, calls the block with each unpacked object.
#
- # See {Packed Data}[rdoc-ref:packed_data.rdoc].
+ # With no block given, returns an array containing the unpacked objects.
+ #
+ # Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
def unpack(fmt, offset: 0)
Primitive.attr! :use_block
Primitive.pack_unpack(fmt, offset)
@@ -28,8 +30,10 @@ class String
# call-seq:
# unpack1(template, offset: 0) -> object
#
- # Like String#unpack, but unpacks and returns only the first extracted object.
- # See {Packed Data}[rdoc-ref:packed_data.rdoc].
+ # Like String#unpack with no block, but unpacks and returns only the first extracted object.
+ # See {Packed Data}[rdoc-ref:language/packed_data.md].
+ #
+ # Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
def unpack1(fmt, offset: 0)
Primitive.pack_unpack1(fmt, offset)
end
diff --git a/parse.y b/parse.y
index a0ed61f80b..ecd26acbbb 100644
--- a/parse.y
+++ b/parse.y
@@ -314,9 +314,12 @@ struct lex_context {
unsigned int in_argdef: 1;
unsigned int in_def: 1;
unsigned int in_class: 1;
+ unsigned int has_trailing_semicolon: 1;
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
BITFIELD(enum rescue_context, in_rescue, 2);
unsigned int cant_return: 1;
+ unsigned int in_alt_pattern: 1;
+ unsigned int capture_in_pattern: 1;
};
typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
@@ -826,7 +829,7 @@ pop_end_expect_token_locations(struct parser_params *p)
if(!p->end_expect_token_locations) return;
end_expect_token_locations_t *locations = p->end_expect_token_locations->prev;
- ruby_sized_xfree(p->end_expect_token_locations, sizeof(end_expect_token_locations_t));
+ ruby_xfree_sized(p->end_expect_token_locations, sizeof(end_expect_token_locations_t));
p->end_expect_token_locations = locations;
debug_end_expect_token_locations(p, "pop_end_expect_token_locations");
@@ -1060,8 +1063,8 @@ rb_discard_node(struct parser_params *p, NODE *n)
rb_ast_delete_node(p->ast, n);
}
-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_scope_t *rb_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, NODE *nd_parent, 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, NODE *nd_parent, 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, const YYLTYPE* if_keyword_loc, const YYLTYPE* then_keyword_loc, const YYLTYPE* end_keyword_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, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc);
@@ -1069,7 +1072,7 @@ static rb_node_case_t *rb_node_case_new(struct parser_params *p, NODE *nd_head,
static rb_node_case2_t *rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc);
static rb_node_case3_t *rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_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, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_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_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *in_keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *operator_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, const YYLTYPE *keyword_loc, const YYLTYPE *closing_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, const YYLTYPE *keyword_loc, const YYLTYPE *closing_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);
@@ -1144,10 +1147,10 @@ static rb_node_alias_t *rb_node_alias_new(struct parser_params *p, NODE *nd_1st,
static rb_node_valias_t *rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc, const YYLTYPE *keyword_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, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_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_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *module_keyword_loc, const YYLTYPE *end_keyword_loc);
+static rb_node_sclass_t *rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *operator_loc, const YYLTYPE *end_keyword_loc);
+static rb_node_colon2_t *rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc);
+static rb_node_colon3_t *rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc);
static rb_node_dot2_t *rb_node_dot2_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc, const YYLTYPE *operator_loc);
static rb_node_dot3_t *rb_node_dot3_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc, const YYLTYPE *operator_loc);
static rb_node_self_t *rb_node_self_new(struct parser_params *p, const YYLTYPE *loc);
@@ -1155,7 +1158,7 @@ static rb_node_nil_t *rb_node_nil_new(struct parser_params *p, const YYLTYPE *lo
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_defined_t *rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
static rb_node_postexe_t *rb_node_postexe_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc);
static rb_node_sym_t *rb_node_sym_new(struct parser_params *p, VALUE str, const YYLTYPE *loc);
static rb_node_dsym_t *rb_node_dsym_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
@@ -1168,8 +1171,8 @@ static rb_node_line_t *rb_node_line_new(struct parser_params *p, const YYLTYPE *
static rb_node_file_t *rb_node_file_new(struct parser_params *p, VALUE str, 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_SCOPE(a,b,c,loc) (NODE *)rb_node_scope_new(p,a,b,c,loc)
+#define NEW_SCOPE2(t,a,b,c,loc) (NODE *)rb_node_scope_new2(p,t,a,b,c,loc)
#define NEW_BLOCK(a,loc) (NODE *)rb_node_block_new(p,a,loc)
#define NEW_IF(c,t,e,loc,ik_loc,tk_loc,ek_loc) (NODE *)rb_node_if_new(p,c,t,e,loc,ik_loc,tk_loc,ek_loc)
#define NEW_UNLESS(c,t,e,loc,k_loc,t_loc,e_loc) (NODE *)rb_node_unless_new(p,c,t,e,loc,k_loc,t_loc,e_loc)
@@ -1177,7 +1180,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_CASE2(b,loc,ck_loc,ek_loc) (NODE *)rb_node_case2_new(p,b,loc,ck_loc,ek_loc)
#define NEW_CASE3(h,b,loc,ck_loc,ek_loc) (NODE *)rb_node_case3_new(p,h,b,loc,ck_loc,ek_loc)
#define NEW_WHEN(c,t,e,loc,k_loc,t_loc) (NODE *)rb_node_when_new(p,c,t,e,loc,k_loc,t_loc)
-#define NEW_IN(c,t,e,loc) (NODE *)rb_node_in_new(p,c,t,e,loc)
+#define NEW_IN(c,t,e,loc,ik_loc,tk_loc,o_loc) (NODE *)rb_node_in_new(p,c,t,e,loc,ik_loc,tk_loc,o_loc)
#define NEW_WHILE(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_while_new(p,c,b,n,loc,k_loc,c_loc)
#define NEW_UNTIL(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_until_new(p,c,b,n,loc,k_loc,c_loc)
#define NEW_ITER(a,b,loc) (NODE *)rb_node_iter_new(p,a,b,loc)
@@ -1252,10 +1255,10 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_VALIAS(n,o,loc,k_loc) (NODE *)rb_node_valias_new(p,n,o,loc,k_loc)
#define NEW_UNDEF(i,loc) (NODE *)rb_node_undef_new(p,i,loc)
#define NEW_CLASS(n,b,s,loc,ck_loc,io_loc,ek_loc) (NODE *)rb_node_class_new(p,n,b,s,loc,ck_loc,io_loc,ek_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_MODULE(n,b,loc,mk_loc,ek_loc) (NODE *)rb_node_module_new(p,n,b,loc,mk_loc,ek_loc)
+#define NEW_SCLASS(r,b,loc,ck_loc,op_loc,ek_loc) (NODE *)rb_node_sclass_new(p,r,b,loc,ck_loc,op_loc,ek_loc)
+#define NEW_COLON2(c,i,loc,d_loc,n_loc) (NODE *)rb_node_colon2_new(p,c,i,loc,d_loc,n_loc)
+#define NEW_COLON3(i,loc,d_loc,n_loc) (NODE *)rb_node_colon3_new(p,i,loc,d_loc,n_loc)
#define NEW_DOT2(b,e,loc,op_loc) (NODE *)rb_node_dot2_new(p,b,e,loc,op_loc)
#define NEW_DOT3(b,e,loc,op_loc) (NODE *)rb_node_dot3_new(p,b,e,loc,op_loc)
#define NEW_SELF(loc) (NODE *)rb_node_self_new(p,loc)
@@ -1263,7 +1266,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#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_DEFINED(e,loc,k_loc) (NODE *)rb_node_defined_new(p,e,loc, k_loc)
#define NEW_POSTEXE(b,loc,k_loc,o_loc,c_loc) (NODE *)rb_node_postexe_new(p,b,loc,k_loc,o_loc,c_loc)
#define NEW_SYM(str,loc) (NODE *)rb_node_sym_new(p,str,loc)
#define NEW_DSYM(s,l,n,loc) (NODE *)rb_node_dsym_new(p,s,l,n,loc)
@@ -1390,7 +1393,6 @@ last_expr_node(NODE *expr)
static NODE* cond(struct parser_params *p, NODE *node, const YYLTYPE *loc);
static NODE* method_cond(struct parser_params *p, NODE *node, const YYLTYPE *loc);
-#define new_nil(loc) NEW_NIL(loc)
static NODE *new_nil_at(struct parser_params *p, const rb_code_position_t *pos);
static NODE *new_if(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*);
static NODE *new_unless(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*);
@@ -1399,10 +1401,9 @@ static NODE *logop(struct parser_params*,ID,NODE*,NODE*,const YYLTYPE*,const YYL
static NODE *newline_node(NODE*);
static void fixpos(NODE*,NODE*);
-static int value_expr_gen(struct parser_params*,NODE*);
+static int value_expr(struct parser_params*,NODE*);
static void void_expr(struct parser_params*,NODE*);
static NODE *remove_begin(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**);
static void block_dup_check(struct parser_params*,NODE*,NODE*);
@@ -1430,6 +1431,7 @@ static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YY
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*);
+#define new_empty_args_tail(p, loc) new_args_tail(p, 0, 0, 0, loc)
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_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc);
@@ -1440,7 +1442,7 @@ static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw
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,ID);
-static NODE* negate_lit(struct parser_params*, NODE*);
+static NODE* negate_lit(struct parser_params*, NODE*,const YYLTYPE*);
static void no_blockarg(struct parser_params*,NODE*);
static NODE *ret_args(struct parser_params*,NODE*);
static NODE *arg_blk_pass(NODE*,rb_node_block_pass_t*);
@@ -1469,7 +1471,7 @@ static rb_node_kw_arg_t *kwd_append(rb_node_kw_arg_t*, rb_node_kw_arg_t*);
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);
-static NODE *new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc);
+static NODE *new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
static NODE *new_regexp(struct parser_params *, NODE *, int, const YYLTYPE *, const YYLTYPE *, const YYLTYPE *, const YYLTYPE *);
@@ -1633,11 +1635,11 @@ aryptn_pre_args(struct parser_params *p, VALUE pre_arg, VALUE pre_args)
#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)
+new_scope_body(struct parser_params *p, rb_node_args_t *args, NODE *body, NODE *parent, const YYLTYPE *loc)
{
body = remove_begin(body);
reduce_nodes(p, &body);
- NODE *n = NEW_SCOPE(args, body, loc);
+ NODE *n = NEW_SCOPE(args, body, parent, loc);
nd_set_line(n, loc->end_pos.lineno);
set_line_body(body, loc->beg_pos.lineno);
return n;
@@ -1994,7 +1996,7 @@ parser_memhash(const void *ptr, long len)
#define STRING_TERM_LEN(str) (1)
#define STRING_TERM_FILL(str) (str->ptr[str->len] = '\0')
#define PARSER_STRING_RESIZE_CAPA_TERM(p,str,capacity,termlen) do {\
- SIZED_REALLOC_N(str->ptr, char, (size_t)total + termlen, STRING_SIZE(str)); \
+ REALLOC_N(str->ptr, char, (size_t)total + termlen); \
str->len = total; \
} while (0)
#define STRING_SET_LEN(str, n) do { \
@@ -2764,7 +2766,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <node_def_temp> defn_head defs_head k_def
%type <node_exits> block_open k_while k_until k_for allow_exits
%type <node> top_stmts top_stmt begin_block endless_arg endless_command
-%type <node> bodystmt stmts stmt_or_begin stmt expr arg primary
+%type <node> bodystmt stmts stmt_or_begin stmt expr arg ternary primary
%type <node> command command_call command_call_value method_call
%type <node> expr_value expr_value_do arg_value primary_value rel_expr
%type <node_fcall> fcall
@@ -2777,7 +2779,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <node> var_ref var_lhs
%type <node> command_rhs arg_rhs
%type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
-%type <node_args> f_arglist f_opt_paren_args f_paren_args f_args
+%type <node_args> f_arglist f_opt_paren_args f_paren_args f_args f_empty_arg
%type <node_args_aux> f_arg f_arg_item
%type <node> f_marg f_rest_marg
%type <node_masgn> f_margs
@@ -2786,17 +2788,17 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <id> do bv_decls opt_bv_decl bvar
%type <node> lambda brace_body do_body
%type <locations_lambda_body> lambda_body
-%type <node_args> f_larglist
+%type <node_args> f_larglist f_largs largs_tail
%type <node> brace_block cmd_brace_block do_block lhs none fitem
%type <node> mlhs_head mlhs_item mlhs_node
%type <node_masgn> mlhs mlhs_basic 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_value p_primitive p_primitive_value p_variable p_var_ref p_expr_ref p_const
+%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 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> cname fname op f_rest_arg f_block_arg opt_comma 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
@@ -2913,7 +2915,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
/*
* parameterizing rules
*/
-%rule asgn(lhs, rhs) <node>
+%rule asgn(rhs) <node>
: lhs '=' lex_ctxt rhs
{
$$ = node_assign(p, (NODE *)$lhs, $rhs, $lex_ctxt, &@$);
@@ -2921,18 +2923,18 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
}
;
-%rule args_tail_basic(value) <node_args>
- : f_kwarg(value) ',' f_kwrest opt_f_block_arg
+%rule args_tail_basic(value, trailing) <node_args>
+ : f_kwarg(value) ',' f_kwrest opt_f_block_arg(trailing)
{
$$ = new_args_tail(p, $1, $3, $4, &@3);
/*% ripper: [$:1, $:3, $:4] %*/
}
- | f_kwarg(value) opt_f_block_arg
+ | f_kwarg(value) opt_f_block_arg(trailing)
{
$$ = new_args_tail(p, $1, 0, $2, &@1);
/*% ripper: [$:1, Qnil, $:2] %*/
}
- | f_any_kwrest opt_f_block_arg
+ | f_any_kwrest opt_f_block_arg(trailing)
{
$$ = new_args_tail(p, 0, $1, $2, &@1);
/*% ripper: [Qnil, $:1, $:2] %*/
@@ -2942,14 +2944,24 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
$$ = new_args_tail(p, 0, 0, $1, &@1);
/*% ripper: [Qnil, Qnil, $:1] %*/
}
+ ;
+
+%rule opt_f_block_arg(trailing) <id>
+ : ',' f_block_arg
+ {
+ $$ = $2;
+ /*% ripper: $:2 %*/
+ }
+ | trailing
+ ;
%rule def_endless_method(bodystmt) <node>
: defn_head[head] f_opt_paren_args[args] '=' bodystmt
{
endless_method_name(p, $head->nd_mid, &@head);
restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
RNODE_DEFN($$)->nd_defn = $bodystmt;
/*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
/*% ripper: def!($:head, $:args, $:$) %*/
@@ -2959,8 +2971,8 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
{
endless_method_name(p, $head->nd_mid, &@head);
restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
RNODE_DEFS($$)->nd_defn = $bodystmt;
/*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
/*% ripper: defs!(*$:head[0..2], $:args, $:$) %*/
@@ -2984,15 +2996,15 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
}
;
-%rule f_optarg(value) <node_opt_arg>
+%rule f_opt_arg(value) <node_opt_arg>
: f_opt(value)
{
$$ = $f_opt;
/*% ripper: rb_ary_new3(1, $:1) %*/
}
- | f_optarg(value) ',' f_opt(value)
+ | f_opt_arg(value) ',' f_opt(value)
{
- $$ = opt_arg_append($f_optarg, $f_opt);
+ $$ = opt_arg_append($f_opt_arg, $f_opt);
/*% ripper: rb_ary_push($:1, $:3) %*/
}
;
@@ -3025,13 +3037,13 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
}
;
-%rule mlhs(item) <node>
+%rule mlhs_items(item) <node>
: item
{
$$ = NEW_LIST($1, &@$);
/*% ripper: mlhs_add!(mlhs_new!, $:1) %*/
}
- | mlhs(item) ',' item
+ | mlhs_items(item) ',' item
{
$$ = list_append(p, $1, $3);
/*% ripper: mlhs_add!($:1, $:3) %*/
@@ -3042,65 +3054,106 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
: var_lhs tOP_ASGN lex_ctxt rhs
{
$$ = new_op_assign(p, $var_lhs, $tOP_ASGN, $rhs, $lex_ctxt, &@$);
- /*% ripper: opassign!($:1, $:2, $:4) %*/
+ /*% ripper: opassign!($:var_lhs, $:tOP_ASGN, $:rhs) %*/
}
| primary_value '['[lbracket] opt_call_args rbracket tOP_ASGN lex_ctxt rhs
{
$$ = new_ary_op_assign(p, $primary_value, $opt_call_args, $tOP_ASGN, $rhs, &@opt_call_args, &@$, &NULL_LOC, &@lbracket, &@rbracket, &@tOP_ASGN);
- /*% ripper: opassign!(aref_field!($:1, $:3), $:5, $:7) %*/
+ /*% ripper: opassign!(aref_field!($:primary_value, $:opt_call_args), $:tOP_ASGN, $:rhs) %*/
}
| primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt rhs
{
$$ = new_attr_op_assign(p, $primary_value, $call_op, $tIDENTIFIER, $tOP_ASGN, $rhs, &@$, &@call_op, &@tIDENTIFIER, &@tOP_ASGN);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(field!($:primary_value, $:call_op, $:tIDENTIFIER), $:tOP_ASGN, $:rhs) %*/
}
| primary_value call_op tCONSTANT tOP_ASGN lex_ctxt rhs
{
$$ = new_attr_op_assign(p, $primary_value, $call_op, $tCONSTANT, $tOP_ASGN, $rhs, &@$, &@call_op, &@tCONSTANT, &@tOP_ASGN);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(field!($:primary_value, $:call_op, $:tCONSTANT), $:tOP_ASGN, $:rhs) %*/
}
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt rhs
{
$$ = new_attr_op_assign(p, $primary_value, idCOLON2, $tIDENTIFIER, $tOP_ASGN, $rhs, &@$, &@tCOLON2, &@tIDENTIFIER, &@tOP_ASGN);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
+ /*% ripper: opassign!(field!($:primary_value, $:tCOLON2, $:tIDENTIFIER), $:tOP_ASGN, $:rhs) %*/
}
| primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt rhs
{
YYLTYPE loc = code_loc_gen(&@primary_value, &@tCONSTANT);
- $$ = new_const_op_assign(p, NEW_COLON2($primary_value, $tCONSTANT, &loc), $tOP_ASGN, $rhs, $lex_ctxt, &@$);
- /*% ripper: opassign!(const_path_field!($:1, $:3), $:4, $:6) %*/
+ $$ = new_const_op_assign(p, NEW_COLON2($primary_value, $tCONSTANT, &loc, &@tCOLON2, &@tCONSTANT), $tOP_ASGN, $rhs, $lex_ctxt, &@$);
+ /*% ripper: opassign!(const_path_field!($:primary_value, $:tCONSTANT), $:tOP_ASGN, $:rhs) %*/
}
| tCOLON3 tCONSTANT tOP_ASGN lex_ctxt rhs
{
YYLTYPE loc = code_loc_gen(&@tCOLON3, &@tCONSTANT);
- $$ = new_const_op_assign(p, NEW_COLON3($tCONSTANT, &loc), $tOP_ASGN, $rhs, $lex_ctxt, &@$);
- /*% ripper: opassign!(top_const_field!($:2), $:3, $:5) %*/
+ $$ = new_const_op_assign(p, NEW_COLON3($tCONSTANT, &loc, &@tCOLON3, &@tCONSTANT), $tOP_ASGN, $rhs, $lex_ctxt, &@$);
+ /*% ripper: opassign!(top_const_field!($:tCONSTANT), $:tOP_ASGN, $:rhs) %*/
}
| backref tOP_ASGN lex_ctxt rhs
{
VALUE MAYBE_UNUSED(e) = rb_backref_error(p, $backref);
$$ = NEW_ERROR(&@$);
- /*% ripper[error]: assign_error!(?e, opassign!(var_field!($:1), $:2, $:4)) %*/
+ /*% ripper[error]: assign_error!(?e, opassign!(var_field!($:backref), $:tOP_ASGN, $:rhs)) %*/
}
;
-%rule opt_args_tail(tail) <node_args>
+%rule opt_args_tail(tail, trailing) <node_args>
: ',' tail
{
$$ = $tail;
- /*% ripper: $:2 %*/
+ /*% ripper: $:tail %*/
}
- | /* none */
+ | trailing
{
- $$ = new_args_tail(p, 0, 0, 0, &@0);
+ $$ = new_empty_args_tail(p, &@$);
/*% ripper: [Qnil, Qnil, Qnil] %*/
}
;
+%rule range_expr(range) <node>
+ : range tDOT2 range
+ {
+ value_expr(p, $1);
+ value_expr(p, $3);
+ $$ = NEW_DOT2($1, $3, &@$, &@2);
+ /*% ripper: dot2!($:1, $:3) %*/
+ }
+ | range tDOT3 range
+ {
+ value_expr(p, $1);
+ value_expr(p, $3);
+ $$ = NEW_DOT3($1, $3, &@$, &@2);
+ /*% ripper: dot3!($:1, $:3) %*/
+ }
+ | range tDOT2
+ {
+ value_expr(p, $1);
+ $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
+ /*% ripper: dot2!($:1, Qnil) %*/
+ }
+ | range tDOT3
+ {
+ value_expr(p, $1);
+ $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
+ /*% ripper: dot3!($:1, Qnil) %*/
+ }
+ | tBDOT2 range
+ {
+ value_expr(p, $2);
+ $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
+ /*% ripper: dot2!(Qnil, $:2) %*/
+ }
+ | tBDOT3 range
+ {
+ value_expr(p, $2);
+ $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
+ /*% ripper: dot3!(Qnil, $:2) %*/
+ }
+ ;
+
%rule value_expr(value) <node>
: value
{
- value_expr($1);
+ value_expr(p, $1);
$$ = $1;
}
;
@@ -3109,7 +3162,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
: begin ' '+ word_list tSTRING_END
{
$$ = make_list($word_list, &@$);
- /*% ripper: array!($:3) %*/
+ /*% ripper: array!($:word_list) %*/
}
;
@@ -3134,7 +3187,7 @@ program : {
node = remove_begin(node);
void_expr(p, node);
}
- p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), &@$);
+ p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), NULL, &@$);
/*% ripper[final]: program!($:2) %*/
local_pop(p);
}
@@ -3175,9 +3228,9 @@ begin_block : block_open compstmt(top_stmts) '}'
{
restore_block_exit(p, $block_open);
p->eval_tree_begin = block_append(p, p->eval_tree_begin,
- NEW_BEGIN($2, &@$));
+ NEW_BEGIN($compstmt, &@$));
$$ = NEW_BEGIN(0, &@$);
- /*% ripper: BEGIN!($:2) %*/
+ /*% ripper: BEGIN!($:compstmt) %*/
}
;
@@ -3243,123 +3296,125 @@ allow_exits : {$$ = allow_block_exit(p);};
k_END : keyword_END lex_ctxt
{
+ if (p->ctxt.in_def) {
+ rb_warn0("END in method; use at_exit");
+ }
$$ = $2;
p->ctxt.in_rescue = before_rescue;
/*% ripper: $:2 %*/
};
-stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
+stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem[old]
{
- $$ = NEW_ALIAS($2, $4, &@$, &@1);
- /*% ripper: alias!($:2, $:4) %*/
+ $$ = NEW_ALIAS($new, $old, &@$, &@kw);
+ /*% ripper: alias!($:new, $:old) %*/
}
- | keyword_alias tGVAR tGVAR
+ | keyword_alias[kw] tGVAR[new] tGVAR[old]
{
- $$ = NEW_VALIAS($2, $3, &@$, &@1);
- /*% ripper: var_alias!($:2, $:3) %*/
+ $$ = NEW_VALIAS($new, $old, &@$, &@kw);
+ /*% ripper: var_alias!($:new, $:old) %*/
}
- | keyword_alias tGVAR tBACK_REF
+ | keyword_alias[kw] tGVAR[new] tBACK_REF[old]
{
char buf[2];
buf[0] = '$';
- buf[1] = (char)RNODE_BACK_REF($3)->nd_nth;
- $$ = NEW_VALIAS($2, rb_intern2(buf, 2), &@$, &@1);
- /*% ripper: var_alias!($:2, $:3) %*/
+ buf[1] = (char)RNODE_BACK_REF($old)->nd_nth;
+ $$ = NEW_VALIAS($new, rb_intern2(buf, 2), &@$, &@kw);
+ /*% ripper: var_alias!($:new, $:old) %*/
}
- | keyword_alias tGVAR tNTH_REF
+ | keyword_alias tGVAR tNTH_REF[nth]
{
static const char mesg[] = "can't make alias for the number variables";
/*%%%*/
- yyerror1(&@3, mesg);
+ yyerror1(&@nth, mesg);
/*% %*/
$$ = NEW_ERROR(&@$);
- /*% ripper[error]: alias_error!(ERR_MESG(), $:3) %*/
+ /*% ripper[error]: alias_error!(ERR_MESG(), $:nth) %*/
}
- | keyword_undef undef_list
+ | keyword_undef[kw] undef_list[list]
{
- nd_set_first_loc($2, @1.beg_pos);
- RNODE_UNDEF($2)->keyword_loc = @1;
- $$ = $2;
- /*% ripper: undef!($:2) %*/
+ nd_set_first_loc($list, @kw.beg_pos);
+ RNODE_UNDEF($list)->keyword_loc = @kw;
+ $$ = $list;
+ /*% ripper: undef!($:list) %*/
}
- | stmt modifier_if expr_value
+ | stmt[body] modifier_if[mod] expr_value[cond]
{
- $$ = new_if(p, $3, remove_begin($1), 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
- fixpos($$, $3);
- /*% ripper: if_mod!($:3, $:1) %*/
+ $$ = new_if(p, $cond, remove_begin($body), 0, &@$, &@mod, &NULL_LOC, &NULL_LOC);
+ fixpos($$, $cond);
+ /*% ripper: if_mod!($:cond, $:body) %*/
}
- | stmt modifier_unless expr_value
+ | stmt[body] modifier_unless[mod] expr_value[cond]
{
- $$ = new_unless(p, $3, remove_begin($1), 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
- fixpos($$, $3);
- /*% ripper: unless_mod!($:3, $:1) %*/
+ $$ = new_unless(p, $cond, remove_begin($body), 0, &@$, &@mod, &NULL_LOC, &NULL_LOC);
+ fixpos($$, $cond);
+ /*% ripper: unless_mod!($:cond, $:body) %*/
}
- | stmt modifier_while expr_value
+ | stmt[body] modifier_while[mod] expr_value[cond_expr]
{
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, &@$, &@2, &NULL_LOC);
+ if ($body && nd_type_p($body, NODE_BEGIN)) {
+ $$ = NEW_WHILE(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
}
else {
- $$ = NEW_WHILE(cond(p, $3, &@3), $1, 1, &@$, &@2, &NULL_LOC);
+ $$ = NEW_WHILE(cond(p, $cond_expr, &@cond_expr), $body, 1, &@$, &@mod, &NULL_LOC);
}
- /*% ripper: while_mod!($:3, $:1) %*/
+ /*% ripper: while_mod!($:cond_expr, $:body) %*/
}
- | stmt modifier_until expr_value
+ | stmt[body] modifier_until[mod] expr_value[cond_expr]
{
- 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, &@$, &@2, &NULL_LOC);
+ clear_block_exit(p, 0);
+ if ($body && nd_type_p($body, NODE_BEGIN)) {
+ $$ = NEW_UNTIL(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
}
else {
- $$ = NEW_UNTIL(cond(p, $3, &@3), $1, 1, &@$, &@2, &NULL_LOC);
+ $$ = NEW_UNTIL(cond(p, $cond_expr, &@cond_expr), $body, 1, &@$, &@mod, &NULL_LOC);
}
- /*% ripper: until_mod!($:3, $:1) %*/
+ /*% ripper: until_mod!($:cond_expr, $:body) %*/
}
- | stmt modifier_rescue after_rescue stmt
+ | stmt[body] modifier_rescue[mod] after_rescue[ctxt] stmt[resbody]
{
- p->ctxt.in_rescue = $3.in_rescue;
+ p->ctxt.in_rescue = $ctxt.in_rescue;
NODE *resq;
- YYLTYPE loc = code_loc_gen(&@2, &@4);
- resq = NEW_RESBODY(0, 0, remove_begin($4), 0, &loc);
- $$ = NEW_RESCUE(remove_begin($1), resq, 0, &@$);
- /*% ripper: rescue_mod!($:1, $:4) %*/
+ YYLTYPE loc = code_loc_gen(&@mod, &@resbody);
+ resq = NEW_RESBODY(0, 0, remove_begin($resbody), 0, &loc);
+ $$ = NEW_RESCUE(remove_begin($body), resq, 0, &@$);
+ /*% ripper: rescue_mod!($:body, $:resbody) %*/
}
- | k_END allow_exits '{' compstmt(stmts) '}'
+ | k_END[k_end] block_open[lbrace] compstmt(stmts)[body] '}'[rbrace]
{
- if (p->ctxt.in_def) {
- rb_warn0("END in method; use at_exit");
- }
- restore_block_exit(p, $allow_exits);
- p->ctxt = $k_END;
+ clear_block_exit(p, true);
+ restore_block_exit(p, $block_open);
+ p->ctxt = $k_end;
{
- NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $compstmt /* body */, &@$);
- $$ = NEW_POSTEXE(scope, &@$, &@1, &@3, &@5);
+ NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $body /* body */, NULL /* parent */, &@$);
+ $$ = NEW_POSTEXE(scope, &@$, &@k_end, &@lbrace, &@rbrace);
+ RNODE_SCOPE(scope)->nd_parent = $$;
}
- /*% ripper: END!($:compstmt) %*/
+ /*% ripper: END!($:body) %*/
}
| command_asgn
- | mlhs '=' lex_ctxt command_call_value
+ | mlhs[lhs] '=' lex_ctxt[ctxt] command_call_value[rhs]
{
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% ripper: massign!($:1, $:4) %*/
+ $$ = node_assign(p, (NODE *)$lhs, $rhs, $ctxt, &@$);
+ /*% ripper: massign!($:lhs, $:rhs) %*/
}
- | asgn(lhs, mrhs)
- | mlhs '=' lex_ctxt mrhs_arg modifier_rescue
- after_rescue stmt[resbody]
+ | asgn(mrhs)
+ | mlhs[lhs] '=' lex_ctxt[lex_ctxt] mrhs_arg[mrhs_arg] modifier_rescue[modifier_rescue]
+ after_rescue[after_rescue] stmt[resbody]
{
- p->ctxt.in_rescue = $3.in_rescue;
+ p->ctxt.in_rescue = $after_rescue.in_rescue;
YYLTYPE loc = code_loc_gen(&@modifier_rescue, &@resbody);
$resbody = NEW_RESBODY(0, 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)) %*/
+ $$ = node_assign(p, (NODE *)$lhs, $mrhs_arg, $lex_ctxt, &@$);
+ /*% ripper: massign!($:lhs, rescue_mod!($:mrhs_arg, $:resbody)) %*/
}
- | mlhs '=' lex_ctxt mrhs_arg
+ | mlhs[lhs] '=' lex_ctxt[ctxt] mrhs_arg[rhs]
{
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% ripper: massign!($:1, $:4) %*/
+ $$ = node_assign(p, (NODE *)$lhs, $rhs, $ctxt, &@$);
+ /*% ripper: massign!($:lhs, $:rhs) %*/
}
| expr
| error
@@ -3369,7 +3424,7 @@ stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
}
;
-command_asgn : asgn(lhs, command_rhs)
+command_asgn : asgn(command_rhs)
| op_asgn(command_rhs)
| def_endless_method(endless_command)
;
@@ -3400,29 +3455,29 @@ command_rhs : command_call_value %prec tOP_ASGN
;
expr : command_call
- | expr keyword_and expr
+ | expr[left] keyword_and[op] expr[right]
{
- $$ = logop(p, idAND, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idAND), $:3) %*/
+ $$ = logop(p, idAND, $left, $right, &@op, &@$);
+ /*% ripper: binary!($:left, ID2VAL(idAND), $:right) %*/
}
- | expr keyword_or expr
+ | expr[left] keyword_or[op] expr[right]
{
- $$ = logop(p, idOR, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idOR), $:3) %*/
+ $$ = logop(p, idOR, $left, $right, &@op, &@$);
+ /*% ripper: binary!($:left, ID2VAL(idOR), $:right) %*/
}
- | keyword_not '\n'? expr
+ | keyword_not[not] '\n'? expr[arg]
{
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
+ $$ = call_uni_op(p, method_cond(p, $arg, &@arg), METHOD_NOT, &@not, &@$);
+ /*% ripper: unary!(ID2VAL(idNOT), $:arg) %*/
}
- | '!' command_call
+ | '!'[not] command_call[arg]
{
- $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
- /*% ripper: unary!(ID2VAL('\'!\''), $:2) %*/
+ $$ = call_uni_op(p, method_cond(p, $arg, &@arg), '!', &@not, &@$);
+ /*% ripper: unary!(ID2VAL('\'!\''), $:arg) %*/
}
- | arg tASSOC
+ | arg tASSOC[assoc]
{
- value_expr($arg);
+ value_expr(p, $arg);
}
p_in_kwarg[ctxt] p_pvtbl p_pktbl
p_top_expr_body[body]
@@ -3430,12 +3485,14 @@ expr : command_call
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), &@$, &NULL_LOC, &NULL_LOC);
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
+ $$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body, &NULL_LOC, &NULL_LOC, &@assoc), &@$, &NULL_LOC, &NULL_LOC);
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
}
| arg keyword_in
{
- value_expr($arg);
+ value_expr(p, $arg);
}
p_in_kwarg[ctxt] p_pvtbl p_pktbl
p_top_expr_body[body]
@@ -3443,7 +3500,9 @@ expr : command_call
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), &@$, &NULL_LOC, &NULL_LOC);
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
+ $$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body, &@keyword_in, &NULL_LOC, &NULL_LOC), &@$, &NULL_LOC, &NULL_LOC);
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
}
| arg %prec tLBRACE_ARG
@@ -3633,7 +3692,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN($1, $3, &@$);
/*% ripper: mlhs_add_star!($:1, $:3) %*/
}
- | mlhs_head tSTAR mlhs_node ',' mlhs(mlhs_item)
+ | mlhs_head tSTAR mlhs_node ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN($1, NEW_POSTARG($3,$5,&@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!($:1, $:3), $:5) %*/
@@ -3643,7 +3702,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN($1, NODE_SPECIAL_NO_NAME_REST, &@$);
/*% ripper: mlhs_add_star!($:1, Qnil) %*/
}
- | mlhs_head tSTAR ',' mlhs(mlhs_item)
+ | mlhs_head tSTAR ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN($1, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $4, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!($:1, Qnil), $:4) %*/
@@ -3653,7 +3712,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN(0, $2, &@$);
/*% ripper: mlhs_add_star!(mlhs_new!, $:2) %*/
}
- | tSTAR mlhs_node ',' mlhs(mlhs_item)
+ | tSTAR mlhs_node ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN(0, NEW_POSTARG($2,$4,&@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $:2), $:4) %*/
@@ -3663,7 +3722,7 @@ mlhs_basic : mlhs_head
$$ = NEW_MASGN(0, NODE_SPECIAL_NO_NAME_REST, &@$);
/*% ripper: mlhs_add_star!(mlhs_new!, Qnil) %*/
}
- | tSTAR ',' mlhs(mlhs_item)
+ | tSTAR ',' mlhs_items(mlhs_item)
{
$$ = NEW_MASGN(0, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $3, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, Qnil), $:3) %*/
@@ -3715,12 +3774,12 @@ mlhs_node : user_or_keyword_variable
| primary_value tCOLON2 tCONSTANT
{
/*% ripper: const_path_field!($:1, $:3) %*/
- $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
+ $$ = const_decl(p, NEW_COLON2($1, $3, &@$, &@2, &@3), &@$);
}
| tCOLON3 tCONSTANT
{
/*% ripper: top_const_field!($:2) %*/
- $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
+ $$ = const_decl(p, NEW_COLON3($2, &@$, &@1, &@2), &@$);
}
| backref
{
@@ -3753,12 +3812,12 @@ lhs : user_or_keyword_variable
| primary_value tCOLON2 tCONSTANT
{
/*% ripper: const_path_field!($:1, $:3) %*/
- $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
+ $$ = const_decl(p, NEW_COLON2($1, $3, &@$, &@2, &@3), &@$);
}
| tCOLON3 tCONSTANT
{
/*% ripper: top_const_field!($:2) %*/
- $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
+ $$ = const_decl(p, NEW_COLON3($2, &@$, &@1, &@2), &@$);
}
| backref
{
@@ -3781,17 +3840,17 @@ cname : tIDENTIFIER
cpath : tCOLON3 cname
{
- $$ = NEW_COLON3($2, &@$);
+ $$ = NEW_COLON3($2, &@$, &@1, &@2);
/*% ripper: top_const_ref!($:2) %*/
}
| cname
{
- $$ = NEW_COLON2(0, $1, &@$);
+ $$ = NEW_COLON2(0, $1, &@$, &NULL_LOC, &@1);
/*% ripper: const_ref!($:1) %*/
}
| primary_value tCOLON2 cname
{
- $$ = NEW_COLON2($1, $3, &@$);
+ $$ = NEW_COLON2($1, $3, &@$, &@2, &@3);
/*% ripper: const_path_ref!($:1, $:3) %*/
}
;
@@ -3872,46 +3931,9 @@ reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
| keyword_while | keyword_until
;
-arg : asgn(lhs, arg_rhs)
+arg : asgn(arg_rhs)
| op_asgn(arg_rhs)
- | arg tDOT2 arg
- {
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT2($1, $3, &@$, &@2);
- /*% ripper: dot2!($:1, $:3) %*/
- }
- | arg tDOT3 arg
- {
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT3($1, $3, &@$, &@2);
- /*% ripper: dot3!($:1, $:3) %*/
- }
- | arg tDOT2
- {
- value_expr($1);
- $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
- /*% ripper: dot2!($:1, Qnil) %*/
- }
- | arg tDOT3
- {
- value_expr($1);
- $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
- /*% ripper: dot3!($:1, Qnil) %*/
- }
- | tBDOT2 arg
- {
- value_expr($2);
- $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
- /*% ripper: dot2!(Qnil, $:2) %*/
- }
- | tBDOT3 arg
- {
- value_expr($2);
- $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
- /*% ripper: dot3!(Qnil, $:2) %*/
- }
+ | range_expr(arg)
| arg '+' arg
{
$$ = call_bin_op(p, $1, '+', $3, &@2, &@$);
@@ -4036,18 +4058,22 @@ arg : asgn(lhs, arg_rhs)
| keyword_defined '\n'? begin_defined arg
{
p->ctxt.in_defined = $3.in_defined;
- $$ = new_defined(p, $4, &@$);
+ $$ = new_defined(p, $4, &@$, &@1);
+ p->ctxt.has_trailing_semicolon = $3.has_trailing_semicolon;
/*% ripper: defined!($:4) %*/
}
- | arg '?' arg '\n'? ':' arg
+ | def_endless_method(endless_arg)
+ | ternary
+ | primary
+ ;
+
+ternary : arg '?' arg '\n'? ':' arg
{
- value_expr($1);
+ value_expr(p, $1);
$$ = new_if(p, $1, $3, $6, &@$, &NULL_LOC, &@5, &NULL_LOC);
fixpos($$, $1);
/*% ripper: ifop!($:1, $:3, $:6) %*/
}
- | def_endless_method(endless_arg)
- | primary
;
endless_arg : arg %prec modifier_rescue
@@ -4122,13 +4148,13 @@ aref_args : none
arg_rhs : arg %prec tOP_ASGN
{
- value_expr($1);
+ value_expr(p, $1);
$$ = $1;
}
| arg modifier_rescue after_rescue arg
{
p->ctxt.in_rescue = $3.in_rescue;
- value_expr($1);
+ value_expr(p, $1);
$$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
/*% ripper: rescue_mod!($:1, $:4) %*/
}
@@ -4188,6 +4214,11 @@ call_args : value_expr(command)
$$ = NEW_LIST($1, &@$);
/*% ripper: args_add!(args_new!, $:1) %*/
}
+ | def_endless_method(endless_command)
+ {
+ $$ = NEW_LIST($1, &@$);
+ /*% ripper: args_add!(args_new!, $:1) %*/
+ }
| args opt_block_arg
{
$$ = arg_blk_pass($1, $2);
@@ -4343,343 +4374,345 @@ mrhs : args ',' arg_value
| qsymbols
;
-primary : inline_primary
- | 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(stmts) {SET_LEX_STATE(EXPR_ENDARG);} ')'
- {
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = $2;
- /*% ripper: paren!($:2) %*/
- }
- | tLPAREN compstmt(stmts) ')'
- {
- 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, &@$, &@1);
- /*% ripper: return0! %*/
- }
- | k_yield '(' call_args rparen
- {
- $$ = NEW_YIELD($3, &@$, &@1, &@2, &@4);
- /*% ripper: yield!(paren!($:3)) %*/
- }
- | k_yield '(' rparen
- {
- $$ = NEW_YIELD(0, &@$, &@1, &@2, &@3);
- /*% ripper: yield!(paren!(args_new!)) %*/
- }
- | k_yield
- {
- $$ = NEW_YIELD(0, &@$, &@1, &NULL_LOC, &NULL_LOC);
- /*% ripper: yield0! %*/
- }
- | keyword_defined '\n'? '(' begin_defined expr rparen
- {
- p->ctxt.in_defined = $4.in_defined;
- $$ = new_defined(p, $5, &@$);
- /*% ripper: defined!($:5) %*/
- }
- | keyword_not '(' expr rparen
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
- }
- | keyword_not '(' rparen
- {
- $$ = call_uni_op(p, method_cond(p, new_nil(&@2), &@2), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), Qnil) %*/
- }
- | 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(stmts)
- if_tail
- k_end
- {
- if ($5 && nd_type_p($5, NODE_IF))
- RNODE_IF($5)->end_keyword_loc = @6;
-
- $$ = new_if(p, $2, $4, $5, &@$, &@1, &@3, &@6);
- fixpos($$, $2);
- /*% ripper: if!($:2, $:4, $:5) %*/
- }
- | k_unless expr_value then
- compstmt(stmts)
- opt_else
- k_end
- {
- $$ = new_unless(p, $2, $4, $5, &@$, &@1, &@3, &@6);
- fixpos($$, $2);
- /*% ripper: unless!($:2, $:4, $:5) %*/
- }
- | k_while expr_value_do
- compstmt(stmts)
- k_end
- {
- restore_block_exit(p, $1);
- $$ = NEW_WHILE(cond(p, $2, &@2), $3, 1, &@$, &@1, &@4);
- fixpos($$, $2);
- /*% ripper: while!($:2, $:3) %*/
- }
- | k_until expr_value_do
- compstmt(stmts)
- k_end
- {
- restore_block_exit(p, $1);
- $$ = NEW_UNTIL(cond(p, $2, &@2), $3, 1, &@$, &@1, &@4);
- fixpos($$, $2);
- /*% ripper: until!($:2, $:3) %*/
- }
- | k_case expr_value terms?
- {
- $$ = p->case_labels;
- p->case_labels = CHECK_LITERAL_WHEN;
- }<labels>
- case_body
- k_end
- {
- if (CASE_LABELS_ENABLED_P(p->case_labels)) st_free_table(p->case_labels);
- p->case_labels = $4;
- $$ = NEW_CASE($2, $5, &@$, &@1, &@6);
- fixpos($$, $2);
- /*% ripper: case!($:2, $:5) %*/
- }
- | k_case terms?
- {
- $$ = p->case_labels;
- p->case_labels = 0;
- }<labels>
- case_body
- k_end
- {
- if (p->case_labels) st_free_table(p->case_labels);
- p->case_labels = $3;
- $$ = NEW_CASE2($4, &@$, &@1, &@5);
- /*% ripper: case!(Qnil, $:4) %*/
- }
- | k_case expr_value terms?
- p_case_body
- k_end
- {
- $$ = NEW_CASE3($2, $4, &@$, &@1, &@5);
- /*% ripper: case!($:2, $:4) %*/
- }
- | k_for for_var keyword_in
- {COND_PUSH(1);} expr_value do {COND_POP();}
- compstmt(stmts)
- k_end
- {
- restore_block_exit(p, $k_for);
- /*
- * 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, &@for_var);
- rb_ast_id_table_t *tbl = rb_ast_new_local_table(p->ast, 1);
- tbl->ids[0] = id; /* internal id */
-
- switch (nd_type($for_var)) {
- case NODE_LASGN:
- case NODE_DASGN: /* e.each {|internal_var| a = internal_var; ... } */
- set_nd_value(p, $for_var, internal_var);
- id = 0;
- m->nd_plen = 1;
- m->nd_next = $for_var;
- 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, $for_var, NEW_FOR_MASGN(internal_var, &@for_var), NO_LEX_CTXT, &@for_var);
- 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($for_var, &@for_var), 0, &@for_var), internal_var, NO_LEX_CTXT, &@for_var);
- }
- /* {|*internal_id| <m> = internal_id; ... } */
- args = new_args(p, m, 0, id, 0, new_args_tail(p, 0, 0, 0, &@for_var), &@for_var);
- scope = NEW_SCOPE2(tbl, args, $compstmt, &@$);
- YYLTYPE do_keyword_loc = $do == keyword_do_cond ? @do : NULL_LOC;
- $$ = NEW_FOR($5, scope, &@$, &@k_for, &@keyword_in, &do_keyword_loc, &@k_end);
- fixpos($$, $for_var);
- /*% ripper: for!($:for_var, $:expr_value, $:compstmt) %*/
- }
- | k_class cpath superclass
- {
- begin_definition("class", &@k_class, &@cpath);
- }
- bodystmt
- k_end
- {
- YYLTYPE inheritance_operator_loc = NULL_LOC;
- if ($superclass) {
- inheritance_operator_loc = @superclass;
- inheritance_operator_loc.end_pos.column = inheritance_operator_loc.beg_pos.column + 1;
- }
- $$ = NEW_CLASS($cpath, $bodystmt, $superclass, &@$, &@k_class, &inheritance_operator_loc, &@k_end);
- 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.cant_return = $k_class.cant_return;
- 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.cant_return = $k_class.cant_return;
- 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.cant_return = $k_module.cant_return;
- 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, $: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[0..2], $:args, $:bodystmt) %*/
- local_pop(p);
- }
- | keyword_break
- {
- $$ = add_block_exit(p, NEW_BREAK(0, &@$, &@1));
- /*% ripper: break!(args_new!) %*/
- }
- | keyword_next
- {
- $$ = add_block_exit(p, NEW_NEXT(0, &@$, &@1));
- /*% ripper: next!(args_new!) %*/
- }
- | keyword_redo
- {
- $$ = add_block_exit(p, NEW_REDO(&@$, &@1));
- /*% 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;
- }
+primary : inline_primary
+ | var_ref
+ | backref
+ | tFID[fid]
+ {
+ $$ = (NODE *)NEW_FCALL($fid, 0, &@$);
+ /*% ripper: method_add_arg!(fcall!($:fid), args_new!) %*/
+ }
+ | k_begin[kw]
+ {
+ CMDARG_PUSH(0);
+ }
+ bodystmt[body]
+ k_end[k_end]
+ {
+ CMDARG_POP();
+ set_line_body($body, @kw.end_pos.lineno);
+ $$ = NEW_BEGIN($body, &@$);
+ nd_set_line($$, @kw.end_pos.lineno);
+ /*% ripper: begin!($:body) %*/
+ }
+ | tLPAREN_ARG compstmt(stmts)[body] {SET_LEX_STATE(EXPR_ENDARG);} ')'
+ {
+ if (nd_type_p($body, NODE_SELF)) RNODE_SELF($body)->nd_state = 0;
+ $$ = $body;
+ /*% ripper: paren!($:body) %*/
+ }
+ | tLPAREN compstmt(stmts)[body] ')'
+ {
+ if (nd_type_p($body, NODE_SELF)) RNODE_SELF($body)->nd_state = 0;
+ $$ = NEW_BLOCK($body, &@$);
+ /*% ripper: paren!($:body) %*/
+ }
+ | primary_value[recv] tCOLON2[op] tCONSTANT[name]
+ {
+ $$ = NEW_COLON2($recv, $name, &@$, &@op, &@name);
+ /*% ripper: const_path_ref!($:recv, $:name) %*/
+ }
+ | tCOLON3[top] tCONSTANT[name]
+ {
+ $$ = NEW_COLON3($name, &@$, &@top, &@name);
+ /*% ripper: top_const_ref!($:name) %*/
+ }
+ | tLBRACK aref_args[args] ']'
+ {
+ $$ = make_list($args, &@$);
+ /*% ripper: array!($:args) %*/
+ }
+ | tLBRACE assoc_list[list] '}'
+ {
+ $$ = new_hash(p, $list, &@$);
+ RNODE_HASH($$)->nd_brace = TRUE;
+ /*% ripper: hash!($:list) %*/
+ }
+ | k_return[kw]
+ {
+ $$ = NEW_RETURN(0, &@$, &@kw);
+ /*% ripper: return0! %*/
+ }
+ | k_yield[kw] '('[lpar] call_args[args] rparen[rpar]
+ {
+ $$ = NEW_YIELD($args, &@$, &@kw, &@lpar, &@rpar);
+ /*% ripper: yield!(paren!($:args)) %*/
+ }
+ | k_yield[kw] '('[lpar] rparen[rpar]
+ {
+ $$ = NEW_YIELD(0, &@$, &@kw, &@lpar, &@rpar);
+ /*% ripper: yield!(paren!(args_new!)) %*/
+ }
+ | k_yield[kw]
+ {
+ $$ = NEW_YIELD(0, &@$, &@kw, &NULL_LOC, &NULL_LOC);
+ /*% ripper: yield0! %*/
+ }
+ | keyword_defined[kw] '\n'? '(' begin_defined[ctxt] expr[arg] rparen
+ {
+ p->ctxt.in_defined = $ctxt.in_defined;
+ $$ = new_defined(p, $arg, &@$, &@kw);
+ p->ctxt.has_trailing_semicolon = $ctxt.has_trailing_semicolon;
+ /*% ripper: defined!($:arg) %*/
+ }
+ | keyword_not[kw] '(' expr[arg] rparen
+ {
+ $$ = call_uni_op(p, method_cond(p, $arg, &@arg), METHOD_NOT, &@kw, &@$);
+ /*% ripper: unary!(ID2VAL(idNOT), $:arg) %*/
+ }
+ | keyword_not[kw] '('[lpar] rparen
+ {
+ $$ = call_uni_op(p, method_cond(p, NEW_NIL(&@lpar), &@lpar), METHOD_NOT, &@kw, &@$);
+ /*% ripper: unary!(ID2VAL(idNOT), Qnil) %*/
+ }
+ | fcall[call] brace_block[block]
+ {
+ $$ = method_add_block(p, (NODE *)$call, $block, &@$);
+ /*% ripper: method_add_block!(method_add_arg!(fcall!($:call), args_new!), $:block) %*/
+ }
+ | method_call
+ | method_call[call] brace_block[block]
+ {
+ block_dup_check(p, get_nd_args(p, $call), $block);
+ $$ = method_add_block(p, $call, $block, &@$);
+ /*% ripper: method_add_block!($:call, $:block) %*/
+ }
+ | lambda
+ | k_if[kw] expr_value[cond] then[then]
+ compstmt(stmts)[body]
+ if_tail[tail]
+ k_end[k_end]
+ {
+ if ($tail && nd_type_p($tail, NODE_IF))
+ RNODE_IF($tail)->end_keyword_loc = @k_end;
+
+ $$ = new_if(p, $cond, $body, $tail, &@$, &@kw, &@then, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: if!($:cond, $:body, $:tail) %*/
+ }
+ | k_unless[kw] expr_value[cond] then[then]
+ compstmt(stmts)[body]
+ opt_else[tail]
+ k_end[k_end]
+ {
+ $$ = new_unless(p, $cond, $body, $tail, &@$, &@kw, &@then, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: unless!($:cond, $:body, $:tail) %*/
+ }
+ | k_while[kw] expr_value_do[cond]
+ compstmt(stmts)[body]
+ k_end[k_end]
+ {
+ restore_block_exit(p, $kw);
+ $$ = NEW_WHILE(cond(p, $cond, &@cond), $body, 1, &@$, &@kw, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: while!($:cond, $:body) %*/
+ }
+ | k_until[kw] expr_value_do[cond]
+ compstmt(stmts)[body]
+ k_end[k_end]
+ {
+ restore_block_exit(p, $kw);
+ $$ = NEW_UNTIL(cond(p, $cond, &@cond), $body, 1, &@$, &@kw, &@k_end);
+ fixpos($$, $cond);
+ /*% ripper: until!($:cond, $:body) %*/
+ }
+ | k_case[k_case] expr_value[expr] terms?
+ {
+ $$ = p->case_labels;
+ p->case_labels = CHECK_LITERAL_WHEN;
+ }[labels]<labels>
+ case_body[body]
+ k_end[k_end]
+ {
+ if (CASE_LABELS_ENABLED_P(p->case_labels)) st_free_table(p->case_labels);
+ p->case_labels = $labels;
+ $$ = NEW_CASE($expr, $body, &@$, &@k_case, &@k_end);
+ fixpos($$, $expr);
+ /*% ripper: case!($:expr, $:body) %*/
+ }
+ | k_case[k_case] terms?
+ {
+ $$ = p->case_labels;
+ p->case_labels = 0;
+ }[labels]<labels>
+ case_body[body]
+ k_end[k_end]
+ {
+ if (p->case_labels) st_free_table(p->case_labels);
+ p->case_labels = $labels;
+ $$ = NEW_CASE2($body, &@$, &@k_case, &@k_end);
+ /*% ripper: case!(Qnil, $:body) %*/
+ }
+ | k_case[k_case] expr_value[expr] terms?
+ p_case_body[body]
+ k_end[k_end]
+ {
+ $$ = NEW_CASE3($expr, $body, &@$, &@k_case, &@k_end);
+ /*% ripper: case!($:expr, $:body) %*/
+ }
+ | k_for[k_for] for_var[for_var] keyword_in[keyword_in]
+ {COND_PUSH(1);} expr_value[expr_value] do[do] {COND_POP();}
+ compstmt(stmts)[compstmt]
+ k_end[k_end]
+ {
+ restore_block_exit(p, $k_for);
+ /*
+ * 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, &@for_var);
+ rb_ast_id_table_t *tbl = rb_ast_new_local_table(p->ast, 1);
+ tbl->ids[0] = id; /* internal id */
+
+ switch (nd_type($for_var)) {
+ case NODE_LASGN:
+ case NODE_DASGN: /* e.each {|internal_var| a = internal_var; ... } */
+ set_nd_value(p, $for_var, internal_var);
+ id = 0;
+ m->nd_plen = 1;
+ m->nd_next = $for_var;
+ 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, $for_var, NEW_FOR_MASGN(internal_var, &@for_var), NO_LEX_CTXT, &@for_var);
+ 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($for_var, &@for_var), 0, &@for_var), internal_var, NO_LEX_CTXT, &@for_var);
+ }
+ /* {|*internal_id| <m> = internal_id; ... } */
+ args = new_args(p, m, 0, id, 0, new_empty_args_tail(p, &@for_var), &@for_var);
+ scope = NEW_SCOPE2(tbl, args, $compstmt, NULL, &@$);
+ YYLTYPE do_keyword_loc = $do == keyword_do_cond ? @do : NULL_LOC;
+ $$ = NEW_FOR($expr_value, scope, &@$, &@k_for, &@keyword_in, &do_keyword_loc, &@k_end);
+ RNODE_SCOPE(scope)->nd_parent = $$;
+ fixpos($$, $for_var);
+ /*% ripper: for!($:for_var, $:expr_value, $:compstmt) %*/
+ }
+ | k_class cpath superclass
+ {
+ begin_definition("class", &@k_class, &@cpath);
+ }
+ bodystmt
+ k_end
+ {
+ YYLTYPE inheritance_operator_loc = NULL_LOC;
+ if ($superclass) {
+ inheritance_operator_loc = @superclass;
+ inheritance_operator_loc.end_pos.column = inheritance_operator_loc.beg_pos.column + 1;
+ }
+ $$ = NEW_CLASS($cpath, $bodystmt, $superclass, &@$, &@k_class, &inheritance_operator_loc, &@k_end);
+ 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.cant_return = $k_class.cant_return;
+ 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, &@$, &@k_class, &@tLSHFT, &@k_end);
+ 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.cant_return = $k_class.cant_return;
+ 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, &@$, &@k_module, &@k_end);
+ 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.cant_return = $k_module.cant_return;
+ 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);
+ ($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
+ RNODE_DEFN($$)->nd_defn = $bodystmt;
+ /*% ripper: def!($:head, $: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);
+ ($$ = $head->nd_def)->nd_loc = @$;
+ $bodystmt = new_scope_body(p, $args, $bodystmt, $$, &@$);
+ RNODE_DEFS($$)->nd_defn = $bodystmt;
+ /*% ripper: defs!(*$:head[0..2], $:args, $:bodystmt) %*/
+ local_pop(p);
+ }
+ | keyword_break[kw]
+ {
+ $$ = add_block_exit(p, NEW_BREAK(0, &@$, &@kw));
+ /*% ripper: break!(args_new!) %*/
+ }
+ | keyword_next[kw]
+ {
+ $$ = add_block_exit(p, NEW_NEXT(0, &@$, &@kw));
+ /*% ripper: next!(args_new!) %*/
+ }
+ | keyword_redo[kw]
+ {
+ $$ = add_block_exit(p, NEW_REDO(&@$, &@kw));
+ /*% ripper: redo! %*/
+ }
+ | keyword_retry[kw]
+ {
+ if (!p->ctxt.in_defined) {
+ switch (p->ctxt.in_rescue) {
+ case before_rescue: yyerror1(&@kw, "Invalid retry without rescue"); break;
+ case after_rescue: /* ok */ break;
+ case after_else: yyerror1(&@kw, "Invalid retry after else"); break;
+ case after_ensure: yyerror1(&@kw, "Invalid retry after ensure"); break;
}
- $$ = NEW_RETRY(&@$);
- /*% ripper: retry! %*/
}
- ;
+ $$ = NEW_RETRY(&@$);
+ /*% ripper: retry! %*/
+ }
+ ;
primary_value : value_expr(primary)
;
@@ -4716,19 +4749,19 @@ k_unless : keyword_unless
}
;
-k_while : keyword_while allow_exits
+k_while : keyword_while[kw] allow_exits
{
$$ = $allow_exits;
token_info_push(p, "while", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
+ push_end_expect_token_locations(p, &@kw.beg_pos);
}
;
-k_until : keyword_until allow_exits
+k_until : keyword_until[kw] allow_exits
{
$$ = $allow_exits;
token_info_push(p, "until", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
+ push_end_expect_token_locations(p, &@kw.beg_pos);
}
;
@@ -4739,11 +4772,11 @@ k_case : keyword_case
}
;
-k_for : keyword_for allow_exits
+k_for : keyword_for[kw] allow_exits
{
$$ = $allow_exits;
token_info_push(p, "for", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
+ push_end_expect_token_locations(p, &@kw.beg_pos);
}
;
@@ -4900,17 +4933,17 @@ f_marg : f_norm_arg
;
-f_margs : mlhs(f_marg)
+f_margs : mlhs_items(f_marg)
{
$$ = NEW_MASGN($1, 0, &@$);
/*% ripper: $:1 %*/
}
- | mlhs(f_marg) ',' f_rest_marg
+ | mlhs_items(f_marg) ',' f_rest_marg
{
$$ = NEW_MASGN($1, $3, &@$);
/*% ripper: mlhs_add_star!($:1, $:3) %*/
}
- | mlhs(f_marg) ',' f_rest_marg ',' mlhs(f_marg)
+ | mlhs_items(f_marg) ',' f_rest_marg ',' mlhs_items(f_marg)
{
$$ = NEW_MASGN($1, NEW_POSTARG($3, $5, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!($:1, $:3), $:5) %*/
@@ -4920,7 +4953,7 @@ f_margs : mlhs(f_marg)
$$ = NEW_MASGN(0, $1, &@$);
/*% ripper: mlhs_add_star!(mlhs_new!, $:1) %*/
}
- | f_rest_marg ',' mlhs(f_marg)
+ | f_rest_marg ',' mlhs_items(f_marg)
{
$$ = NEW_MASGN(0, NEW_POSTARG($1, $3, &@$), &@$);
/*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $:1), $:3) %*/
@@ -4950,7 +4983,7 @@ f_any_kwrest : f_kwrest
f_eq : {p->ctxt.in_argdef = 0;} '=';
-block_args_tail : args_tail_basic(primary_value)
+block_args_tail : args_tail_basic(primary_value, none)
;
excessed_comma : ','
@@ -4961,82 +4994,19 @@ excessed_comma : ','
}
;
-block_param : f_arg ',' f_optarg(primary_value) ',' f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
- /*% ripper: params!($:1, $:3, $:5, Qnil, *$:6[0..2]) %*/
- }
- | f_arg ',' f_optarg(primary_value) ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- /*% ripper: params!($:1, $:3, $:5, $:7, *$:8[0..2]) %*/
- }
- | f_arg ',' f_optarg(primary_value) opt_args_tail(block_args_tail)
+block_param : args-list(primary_value, opt_args_tail(block_args_tail, none))
+ | f_arg[pre] excessed_comma
{
- $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
- /*% ripper: params!($:1, $:3, Qnil, Qnil, *$:4[0..2]) %*/
+ $$ = new_empty_args_tail(p, &@excessed_comma);
+ $$ = new_args(p, $pre, 0, $excessed_comma, 0, $$, &@$);
+ /*% ripper: params!($:pre, Qnil, $:excessed_comma, Qnil, Qnil, Qnil, Qnil) %*/
}
- | f_arg ',' f_optarg(primary_value) ',' f_arg opt_args_tail(block_args_tail)
+ | f_arg[pre] opt_args_tail(block_args_tail, none)[tail]
{
- $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
- /*% ripper: params!($:1, $:3, Qnil, $:5, *$:6[0..2]) %*/
- }
- | f_arg ',' f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
- /*% ripper: params!($:1, Qnil, $:3, Qnil, *$:4[0..2]) %*/
- }
- | f_arg excessed_comma
- {
- $$ = new_args_tail(p, 0, 0, 0, &@2);
- $$ = new_args(p, $1, 0, $2, 0, $$, &@$);
- /*% ripper: params!($:1, Qnil, $:2, Qnil, Qnil, Qnil, Qnil) %*/
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
- /*% ripper: params!($:1, Qnil, $:3, $:5, *$:6[0..2]) %*/
- }
- | f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
- /*% ripper: params!($:1, Qnil, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_optarg(primary_value) ',' f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, Qnil, *$:4[0..2]) %*/
- }
- | f_optarg(primary_value) ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, $:5, *$:6[0..2]) %*/
- }
- | f_optarg(primary_value) opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_optarg(primary_value) ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, $:3, *$:4[0..2]) %*/
- }
- | f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, Qnil, *$:2[0..2]) %*/
- }
- | f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, $:3, *$:4[0..2]) %*/
- }
- | block_args_tail
- {
- $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:1[0..2]) %*/
+ $$ = new_args(p, $pre, 0, 0, 0, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/
}
+ | tail-only-args(block_args_tail)
;
opt_block_param_def : none
@@ -5100,7 +5070,7 @@ numparam : {
}
;
-it_id : {
+it_id : {
$$ = p->it_id;
p->it_id = 0;
}
@@ -5108,7 +5078,7 @@ it_id : {
lambda : tLAMBDA[lpar]
{
- token_info_push(p, "->", &@1);
+ token_info_push(p, "->", &@lpar);
$$ = dyna_push(p);
}[dyna]<vars>
max_numparam numparam it_id allow_exits
@@ -5127,11 +5097,11 @@ lambda : tLAMBDA[lpar]
CMDARG_POP();
$args = args_with_numbered(p, $args, max_numparam, it_id);
{
- YYLTYPE loc = code_loc_gen(&@args, &@body);
+ YYLTYPE loc = code_loc_gen(&@lpar, &@body);
$$ = NEW_LAMBDA($args, $body->node, &loc, &@lpar, &$body->opening_loc, &$body->closing_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);
+ nd_set_first_loc($$, @lpar.beg_pos);
xfree($body);
}
/*% ripper: lambda!($:args, $:body) %*/
@@ -5140,19 +5110,19 @@ lambda : tLAMBDA[lpar]
}
;
-f_larglist : '(' f_args opt_bv_decl ')'
+f_larglist : '(' f_largs[args] opt_bv_decl ')'
{
p->ctxt.in_argdef = 0;
- $$ = $f_args;
+ $$ = $args;
p->max_numparam = ORDINAL_PARAM;
- /*% ripper: paren!($:2) %*/
+ /*% ripper: paren!($:args) %*/
}
- | f_args
+ | f_largs[args]
{
p->ctxt.in_argdef = 0;
- if (!args_info_empty_p(&$1->nd_ainfo))
+ if (!args_info_empty_p(&$args->nd_ainfo))
p->max_numparam = ORDINAL_PARAM;
- $$ = $f_args;
+ $$ = $args;
}
;
@@ -5207,16 +5177,19 @@ block_call : command do_block
{
if (NODE_EMPTY_ARGS_P($4)) $4 = 0;
$$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% ripper: command_call!($:1, $:2, $:3, $:4) %*/
- if ($5) {
- /*% ripper: method_add_block!($:$, $:5) %*/
- }
+ /*% ripper: 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) %*/
}
+ | block_call call_op2 paren_args
+ {
+ $$ = new_qcall(p, $2, $1, idCall, $3, &@2, &@$);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% ripper: method_add_arg!(call!($:1, $:2, ID2VAL(idCall)), $:3) %*/
+ }
;
method_call : fcall paren_args
@@ -5248,18 +5221,12 @@ method_call : fcall paren_args
$$ = new_qcall(p, idCOLON2, $1, $3, 0, &@3, &@$);
/*% ripper: call!($:1, $:2, $:3) %*/
}
- | primary_value call_op paren_args
+ | primary_value call_op2 paren_args
{
$$ = new_qcall(p, $2, $1, 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, idCOLON2, $1, idCall, $3, &@2, &@$);
- nd_set_line($$, @2.end_pos.lineno);
- /*% ripper: method_add_arg!(call!($:1, $:2, ID2VAL(idCall)), $:3) %*/
- }
| keyword_super paren_args
{
rb_code_location_t lparen_loc = @2;
@@ -5381,6 +5348,8 @@ p_in_kwarg : {
SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
p->command_start = FALSE;
p->ctxt.in_kwarg = 1;
+ p->ctxt.in_alt_pattern = 0;
+ p->ctxt.capture_in_pattern = 0;
}
;
@@ -5391,11 +5360,13 @@ p_case_body : keyword_in
pop_pktbl(p, $p_pktbl);
pop_pvtbl(p, $p_pvtbl);
p->ctxt.in_kwarg = $ctxt.in_kwarg;
+ p->ctxt.in_alt_pattern = $ctxt.in_alt_pattern;
+ p->ctxt.capture_in_pattern = $ctxt.capture_in_pattern;
}
compstmt(stmts)
p_cases[cases]
{
- $$ = NEW_IN($expr, $compstmt, $cases, &@$);
+ $$ = NEW_IN($expr, $compstmt, $cases, &@$, &@keyword_in, &@then, &NULL_LOC);
/*% ripper: in!($:expr, $:compstmt, $:cases) %*/
}
;
@@ -5462,10 +5433,18 @@ p_as : p_expr tASSOC p_variable
| p_alt
;
-p_alt : p_alt '|' p_expr_basic
+p_alt : p_alt[left] '|'[alt]
+ {
+ p->ctxt.in_alt_pattern = 1;
+ }
+ p_expr_basic[right]
{
- $$ = NEW_OR($1, $3, &@$, &@2);
- /*% ripper: binary!($:1, ID2VAL(idOr), $:3) %*/
+ if (p->ctxt.capture_in_pattern) {
+ yyerror1(&@alt, "alternative pattern after variable capture");
+ }
+ p->ctxt.in_alt_pattern = 0;
+ $$ = NEW_OR($left, $right, &@$, &@alt);
+ /*% ripper: binary!($:left, ID2VAL(idOr), $:right) %*/
}
| p_expr_basic
;
@@ -5537,8 +5516,8 @@ p_expr_basic : p_value
| p_const '[' rbracket
{
$$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
- $$ = new_array_pattern(p, $1, 0, $$, &@$);
- /*% ripper: aryptn!($:1, Qnil, Qnil, Qnil) %*/
+ $$ = new_array_pattern(p, $p_const, 0, $$, &@$);
+ /*% ripper: aryptn!($:p_const, Qnil, Qnil, Qnil) %*/
}
| tLBRACK p_args rbracket
{
@@ -5758,42 +5737,13 @@ p_any_kwrest : p_kwrest
;
p_value : p_primitive
- | p_primitive_value tDOT2 p_primitive_value
- {
- $$ = NEW_DOT2($1, $3, &@$, &@2);
- /*% ripper: dot2!($:1, $:3) %*/
- }
- | p_primitive_value tDOT3 p_primitive_value
- {
- $$ = NEW_DOT3($1, $3, &@$, &@2);
- /*% ripper: dot3!($:1, $:3) %*/
- }
- | p_primitive_value tDOT2
- {
- $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
- /*% ripper: dot2!($:1, Qnil) %*/
- }
- | p_primitive_value tDOT3
- {
- $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$, &@2);
- /*% ripper: dot3!($:1, Qnil) %*/
- }
+ | range_expr(p_primitive)
| p_var_ref
| p_expr_ref
| p_const
- | tBDOT2 p_primitive_value
- {
- $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
- /*% ripper: dot2!(Qnil, $:2) %*/
- }
- | tBDOT3 p_primitive_value
- {
- $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$, &@1);
- /*% ripper: dot3!(Qnil, $:2) %*/
- }
;
-p_primitive : inline_primary
+p_primitive : inline_primary
| keyword_variable
{
if (!($$ = gettable(p, $1, &@$))) $$ = NEW_ERROR(&@$);
@@ -5802,9 +5752,6 @@ p_primitive : inline_primary
| lambda
;
-p_primitive_value : value_expr(p_primitive)
- ;
-
p_variable : tIDENTIFIER
{
error_duplicate_pattern_variable(p, $1, &@1);
@@ -5841,12 +5788,12 @@ p_expr_ref : '^' tLPAREN expr_value rparen
p_const : tCOLON3 cname
{
- $$ = NEW_COLON3($2, &@$);
+ $$ = NEW_COLON3($2, &@$, &@1, &@2);
/*% ripper: top_const_ref!($:2) %*/
}
| p_const tCOLON2 cname
{
- $$ = NEW_COLON2($1, $3, &@$);
+ $$ = NEW_COLON2($1, $3, &@$, &@2, &@3);
/*% ripper: const_path_ref!($:1, $:3) %*/
}
| tCONSTANT
@@ -5918,7 +5865,8 @@ strings : string
{
if (!$1) {
$$ = NEW_STR(STRING_NEW0(), &@$);
- } else {
+ }
+ else {
$$ = evstr2dstr(p, $1);
}
/*% ripper: $:1 %*/
@@ -6035,7 +5983,7 @@ qsym_list : /* none */
}
;
-string_contents : /* none */
+string_contents : /* none */
{
$$ = 0;
/*% ripper: string_content! %*/
@@ -6059,7 +6007,7 @@ xstring_contents: /* none */
}
;
-regexp_contents: /* none */
+regexp_contents : /* none */
{
$$ = 0;
/*% ripper: regexp_new! %*/
@@ -6090,21 +6038,21 @@ regexp_contents: /* none */
}
;
-string_content : tSTRING_CONTENT
- /*% ripper[brace]: $:1 %*/
- | tSTRING_DVAR
+string_content : tSTRING_CONTENT[content]
+ /*% ripper[brace]: $:content %*/
+ | tSTRING_DVAR[state]
{
/* need to backup p->lex.strterm so that a string literal `%&foo,#$&,bar&` can be parsed */
$$ = p->lex.strterm;
p->lex.strterm = 0;
SET_LEX_STATE(EXPR_BEG);
- }<strterm>
- string_dvar
+ }[strterm]<strterm>
+ string_dvar[dvar]
{
- p->lex.strterm = $2;
- $$ = NEW_EVSTR($3, &@$, &@1, &NULL_LOC);
- nd_set_line($$, @3.end_pos.lineno);
- /*% ripper: string_dvar!($:3) %*/
+ p->lex.strterm = $strterm;
+ $$ = NEW_EVSTR($dvar, &@$, &@state, &NULL_LOC);
+ nd_set_line($$, @dvar.end_pos.lineno);
+ /*% ripper: string_dvar!($:dvar) %*/
}
| tSTRING_DBEG[state]
{
@@ -6186,7 +6134,7 @@ numeric : simple_numeric
| tUMINUS_NUM simple_numeric %prec tLOWEST
{
$$ = $2;
- negate_lit(p, $$);
+ negate_lit(p, $$, &@$);
/*% ripper: unary!(ID2VAL(idUMinus), $:2) %*/
}
;
@@ -6197,7 +6145,7 @@ simple_numeric : tINTEGER
| tIMAGINARY
;
-nonlocal_var : tIVAR
+nonlocal_var : tIVAR
| tGVAR
| tCVAR
;
@@ -6257,11 +6205,16 @@ superclass : '<'
;
f_opt_paren_args: f_paren_args
- | none
+ | f_empty_arg
{
p->ctxt.in_argdef = 0;
- $$ = new_args_tail(p, 0, 0, 0, &@0);
- $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
+ }
+ ;
+
+f_empty_arg : /* none */
+ {
+ $$ = new_empty_args_tail(p, &@$);
+ $$ = new_args(p, 0, 0, 0, 0, $$, &@$);
/*% ripper: params!(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil) %*/
}
;
@@ -6294,109 +6247,117 @@ f_arglist : f_paren_args
}
;
-args_tail : args_tail_basic(arg_value)
+args_tail : args_tail_basic(arg_value, opt_comma)
| args_forward
{
- ID fwd = $args_forward;
- if (lambda_beginning_p() ||
- (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest)) {
- yyerror0("unexpected ... in lambda argument");
- fwd = 0;
- }
- else {
- add_forwarding_args(p);
- }
- $$ = new_args_tail(p, 0, fwd, arg_FWD_BLOCK, &@1);
+ add_forwarding_args(p);
+ $$ = new_args_tail(p, 0, $args_forward, arg_FWD_BLOCK, &@args_forward);
$$->nd_ainfo.forwarding = 1;
- /*% ripper: [Qnil, $:1, Qnil] %*/
+ /*% ripper: [Qnil, $:args_forward, Qnil] %*/
}
;
-f_args : f_arg ',' f_optarg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
+largs_tail : args_tail_basic(arg_value, none)
+ | args_forward
{
- $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
- /*% ripper: params!($:1, $:3, $:5, Qnil, *$:6[0..2]) %*/
+ yyerror1(&@args_forward, "unexpected ... in lambda argument");
+ $$ = new_args_tail(p, 0, 0, 0, &@args_forward);
+ $$->nd_ainfo.forwarding = 1;
+ /*% ripper: [Qnil, $:args_forward, Qnil] %*/
}
- | f_arg ',' f_optarg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ ;
+
+%rule args-list(value, tail) <node_args>
+ : f_arg[pre] ',' f_opt_arg(value)[opt] ',' f_rest_arg[rest] tail
{
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- /*% ripper: params!($:1, $:3, $:5, $:7, *$:8[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, $rest, 0, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_arg ',' f_optarg(arg_value) opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_opt_arg(value)[opt] ',' f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
- /*% ripper: params!($:1, $:3, Qnil, Qnil, *$:4[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, $rest, $post, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, $:rest, $:post, *$:tail[0..2]) %*/
}
- | f_arg ',' f_optarg(arg_value) ',' f_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_opt_arg(value)[opt] tail
{
- $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
- /*% ripper: params!($:1, $:3, Qnil, $:5, *$:6[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, 0, 0, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, Qnil, Qnil, *$:tail[0..2]) %*/
}
- | f_arg ',' f_rest_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_opt_arg(value)[opt] ',' f_arg[post] tail
{
- $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
- /*% ripper: params!($:1, Qnil, $:3, Qnil, *$:4[0..2]) %*/
+ $$ = new_args(p, $pre, $opt, 0, $post, $tail, &@$);
+ /*% ripper: params!($:pre, $:opt, Qnil, $:post, *$:tail[0..2]) %*/
}
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_rest_arg[rest] tail
{
- $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
- /*% ripper: params!($:1, Qnil, $:3, $:5, *$:6[0..2]) %*/
+ $$ = new_args(p, $pre, 0, $rest, 0, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_arg opt_args_tail(args_tail)
+ | f_arg[pre] ',' f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
- /*% ripper: params!($:1, Qnil, Qnil, Qnil, *$:2[0..2]) %*/
+ $$ = new_args(p, $pre, 0, $rest, $post, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, $:rest, $:post, *$:tail[0..2]) %*/
}
- | f_optarg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] ',' f_rest_arg[rest] tail
{
- $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, Qnil, *$:4[0..2]) %*/
+ $$ = new_args(p, 0, $opt, $rest, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_optarg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] ',' f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, $:5, *$:6[0..2]) %*/
+ $$ = new_args(p, 0, $opt, $rest, $post, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, $:rest, $:post, *$:tail[0..2]) %*/
}
- | f_optarg(arg_value) opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] tail
{
- $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, Qnil, *$:2[0..2]) %*/
+ $$ = new_args(p, 0, $opt, 0, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, Qnil, Qnil, *$:tail[0..2]) %*/
}
- | f_optarg(arg_value) ',' f_arg opt_args_tail(args_tail)
+ | f_opt_arg(value)[opt] ',' f_arg[post] tail
{
- $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, $:3, *$:4[0..2]) %*/
+ $$ = new_args(p, 0, $opt, 0, $post, $tail, &@$);
+ /*% ripper: params!(Qnil, $:opt, Qnil, $:post, *$:tail[0..2]) %*/
}
- | f_rest_arg opt_args_tail(args_tail)
+ | f_rest_arg[rest] tail
{
- $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, Qnil, *$:2[0..2]) %*/
+ $$ = new_args(p, 0, 0, $rest, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, Qnil, $:rest, Qnil, *$:tail[0..2]) %*/
}
- | f_rest_arg ',' f_arg opt_args_tail(args_tail)
+ | f_rest_arg[rest] ',' f_arg[post] tail
{
- $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, $:3, *$:4[0..2]) %*/
+ $$ = new_args(p, 0, 0, $rest, $post, $tail, &@$);
+ /*% ripper: params!(Qnil, Qnil, $:rest, $:post, *$:tail[0..2]) %*/
}
- | args_tail
+ ;
+
+%rule tail-only-args(tail) <node_args>
+ : tail
{
- $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:1[0..2]) %*/
+ $$ = new_args(p, 0, 0, 0, 0, $tail, &@$);
+ /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/
}
- | /* none */
+ ;
+
+%rule f_args-list(tail, trailing) <node_args>
+ : args-list(arg_value, opt_args_tail(tail, trailing))
+ | f_arg[pre] opt_args_tail(tail, trailing)[tail]
{
- $$ = new_args_tail(p, 0, 0, 0, &@0);
- $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil) %*/
+ $$ = new_args(p, $pre, 0, 0, 0, $tail, &@$);
+ /*% ripper: params!($:pre, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/
}
+ | tail-only-args(tail)
+ | f_empty_arg
+ ;
+
+f_args : f_args-list(args_tail, opt_comma)
+ ;
+
+f_largs : f_args-list(largs_tail, none)
;
args_forward : tBDOT3
{
-#ifdef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- $$ = 0;
-#else
$$ = idFWD_KWREST;
-#endif
/*% ripper: args_forward! %*/
}
;
@@ -6566,6 +6527,11 @@ f_block_arg : blkarg_mark tIDENTIFIER
$$ = $2;
/*% ripper: blockarg!($:2) %*/
}
+ | blkarg_mark keyword_nil
+ {
+ $$ = idNil;
+ /*% ripper: blockarg!(ID2VAL(idNil)) %*/
+ }
| blkarg_mark
{
arg_var(p, idFWD_BLOCK);
@@ -6574,12 +6540,11 @@ f_block_arg : blkarg_mark tIDENTIFIER
}
;
-opt_f_block_arg : ',' f_block_arg
+opt_comma : ','?
{
- $$ = $2;
- /*% ripper: $:2 %*/
+ $$ = 0;
+ /*% ripper: Qnil %*/
}
- | none
;
@@ -6737,7 +6702,14 @@ trailer : '\n'?
| ','
;
-term : ';' {yyerrok;token_flush(p);}
+term : ';'
+ {
+ yyerrok;
+ token_flush(p);
+ if (p->ctxt.in_defined) {
+ p->ctxt.has_trailing_semicolon = 1;
+ }
+ }
| '\n'
{
@$.end_pos = @$.beg_pos;
@@ -6936,7 +6908,8 @@ parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int l
if (p->keep_tokens) {
/* p->delayed.token is freed by rb_parser_tokens_free */
parser_append_tokens(p, p->delayed.token, t, line);
- } else {
+ }
+ else {
rb_parser_string_free(p, p->delayed.token);
}
@@ -6999,6 +6972,19 @@ is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(
return rb_enc_isalnum((unsigned char)*ptr, enc) || *ptr == '_' || !ISASCII(*ptr);
}
+static inline bool
+peek_word_at(struct parser_params *p, const char *str, size_t len, int at)
+{
+ const char *ptr = p->lex.pcur + at;
+ if (lex_eol_ptr_n_p(p, ptr, len-1)) return false;
+ if (memcmp(ptr, str, len)) return false;
+ if (lex_eol_ptr_n_p(p, ptr, len)) return true;
+ switch (ptr[len]) {
+ case '!': case '?': return false;
+ }
+ return !is_identchar(p, ptr+len, p->lex.pend, p->enc);
+}
+
static inline int
parser_is_identchar(struct parser_params *p)
{
@@ -7055,7 +7041,7 @@ token_info_pop(struct parser_params *p, const char *token, const rb_code_locatio
token_info_warn(p, token, ptinfo_beg, 1, loc);
p->token_info = ptinfo_beg->next;
- ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
+ ruby_xfree_sized(ptinfo_beg, sizeof(*ptinfo_beg));
}
static void
@@ -7075,7 +7061,7 @@ token_info_drop(struct parser_params *p, const char *token, rb_code_position_t b
ptinfo_beg->token);
}
- ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
+ ruby_xfree_sized(ptinfo_beg, sizeof(*ptinfo_beg));
}
static void
@@ -7327,9 +7313,9 @@ vtable_free_gen(struct parser_params *p, int line, const char *name,
#endif
if (!DVARS_TERMINAL_P(tbl)) {
if (tbl->tbl) {
- ruby_sized_xfree(tbl->tbl, tbl->capa * sizeof(ID));
+ ruby_xfree_sized(tbl->tbl, tbl->capa * sizeof(ID));
}
- ruby_sized_xfree(tbl, sizeof(*tbl));
+ ruby_xfree_sized(tbl, sizeof(*tbl));
}
}
#define vtable_free(tbl) vtable_free_gen(p, __LINE__, #tbl, tbl)
@@ -8942,7 +8928,6 @@ number_literal_suffix(struct parser_params *p, int mask)
}
if (!ISASCII(c) || ISALPHA(c) || c == '_') {
p->lex.pcur = lastp;
- literal_flush(p, p->lex.pcur);
return 0;
}
pushback(p, c);
@@ -10570,7 +10555,24 @@ parser_yylex(struct parser_params *p)
token_flush(p);
}
goto retry;
+ case 'a':
+ if (peek_word_at(p, "nd", 2, 0)) goto leading_logical;
+ goto bol;
+ case 'o':
+ if (peek_word_at(p, "r", 1, 0)) goto leading_logical;
+ goto bol;
+ case '|':
+ if (peek(p, '|')) goto leading_logical;
+ goto bol;
case '&':
+ if (peek(p, '&')) {
+ leading_logical:
+ pushback(p, c);
+ dispatch_delayed_token(p, tIGNORED_NL);
+ cmd_state = FALSE;
+ goto retry;
+ }
+ /* fall through */
case '.': {
dispatch_delayed_token(p, tIGNORED_NL);
if (peek(p, '.') == (c == '&')) {
@@ -10579,6 +10581,7 @@ parser_yylex(struct parser_params *p)
goto retry;
}
}
+ bol:
default:
p->ruby_sourceline--;
p->lex.nextline = p->lex.lastline;
@@ -11229,24 +11232,26 @@ node_newnode(struct parser_params *p, enum node_type type, size_t size, size_t a
#define NODE_NEWNODE(node_type, type, loc) (type *)(node_newnode(p, node_type, sizeof(type), RUBY_ALIGNOF(type), loc))
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_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, NODE *nd_parent, 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_parent = nd_parent;
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_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, NODE *nd_parent, 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_parent = nd_parent;
n->nd_args = nd_args;
return n;
@@ -11434,8 +11439,9 @@ 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, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
+ NODE *scope = NEW_SCOPE(0, nd_body, NULL, loc);
rb_node_class_t *n = NODE_NEWNODE(NODE_CLASS, rb_node_class_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_cpath = nd_cpath;
n->nd_body = scope;
n->nd_super = nd_super;
@@ -11447,25 +11453,32 @@ rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *
}
static rb_node_sclass_t *
-rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc)
+rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *operator_loc, const YYLTYPE *end_keyword_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
+ NODE *scope = NEW_SCOPE(0, nd_body, NULL, loc);
rb_node_sclass_t *n = NODE_NEWNODE(NODE_SCLASS, rb_node_sclass_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_recv = nd_recv;
n->nd_body = scope;
+ n->class_keyword_loc = *class_keyword_loc;
+ n->operator_loc = *operator_loc;
+ n->end_keyword_loc = *end_keyword_loc;
return n;
}
static rb_node_module_t *
-rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc)
+rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *module_keyword_loc, const YYLTYPE *end_keyword_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
+ NODE *scope = NEW_SCOPE(0, nd_body, NULL, loc);
rb_node_module_t *n = NODE_NEWNODE(NODE_MODULE, rb_node_module_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_cpath = nd_cpath;
n->nd_body = scope;
+ n->module_keyword_loc = *module_keyword_loc;
+ n->end_keyword_loc = *end_keyword_loc;
return n;
}
@@ -11474,8 +11487,9 @@ 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);
+ NODE *scope = NEW_SCOPE(nd_args, nd_body, NULL, loc);
rb_node_iter_t *n = NODE_NEWNODE(NODE_ITER, rb_node_iter_t, loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_body = scope;
n->nd_iter = 0;
@@ -11486,9 +11500,10 @@ 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, const YYLTYPE *operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc)
{
/* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
+ NODE *scope = NEW_SCOPE(nd_args, nd_body, NULL, loc);
YYLTYPE lambda_loc = code_loc_gen(operator_loc, closing_loc);
rb_node_lambda_t *n = NODE_NEWNODE(NODE_LAMBDA, rb_node_lambda_t, &lambda_loc);
+ RNODE_SCOPE(scope)->nd_parent = &n->node;
n->nd_body = scope;
n->operator_loc = *operator_loc;
n->opening_loc = *opening_loc;
@@ -11547,12 +11562,15 @@ rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd
}
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_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *in_keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *operator_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;
+ n->in_keyword_loc = *in_keyword_loc;
+ n->then_keyword_loc = *then_keyword_loc;
+ n->operator_loc = *operator_loc;
return n;
}
@@ -11584,20 +11602,24 @@ rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd
}
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_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_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;
+ n->delimiter_loc = *delimiter_loc;
+ n->name_loc = *name_loc;
return n;
}
static rb_node_colon3_t *
-rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc)
+rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc)
{
rb_node_colon3_t *n = NODE_NEWNODE(NODE_COLON3, rb_node_colon3_t, loc);
n->nd_mid = nd_mid;
+ n->delimiter_loc = *delimiter_loc;
+ n->name_loc = *name_loc;
return n;
}
@@ -11699,16 +11721,10 @@ rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const
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;
+ return rb_node_list_new2(p, nd_head, 1, 0, loc);
}
static rb_node_list_t *
@@ -12257,10 +12273,11 @@ 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)
+rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
{
rb_node_defined_t *n = NODE_NEWNODE(NODE_DEFINED, rb_node_defined_t, loc);
n->nd_head = nd_head;
+ n->keyword_loc = *keyword_loc;
return n;
}
@@ -12769,8 +12786,8 @@ call_bin_op(struct parser_params *p, NODE *recv, ID id, NODE *arg1,
const YYLTYPE *op_loc, const YYLTYPE *loc)
{
NODE *expr;
- value_expr(recv);
- value_expr(arg1);
+ value_expr(p, recv);
+ value_expr(p, arg1);
expr = NEW_OPCALL(recv, id, NEW_LIST(arg1, &arg1->nd_loc), loc);
nd_set_line(expr, op_loc->beg_pos.lineno);
return expr;
@@ -12780,7 +12797,7 @@ static NODE *
call_uni_op(struct parser_params *p, NODE *recv, ID id, const YYLTYPE *op_loc, const YYLTYPE *loc)
{
NODE *opcall;
- value_expr(recv);
+ value_expr(p, recv);
opcall = NEW_OPCALL(recv, id, 0, loc);
nd_set_line(opcall, op_loc->beg_pos.lineno);
return opcall;
@@ -12830,8 +12847,8 @@ match_op(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *op_lo
NODE *n;
int line = op_loc->beg_pos.lineno;
- value_expr(node1);
- value_expr(node2);
+ value_expr(p, node1);
+ value_expr(p, node2);
if ((n = last_expr_once_body(node1)) != 0) {
switch (nd_type(n)) {
@@ -12891,10 +12908,10 @@ numparam_nested_p(struct parser_params *p)
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");
+ compile_error(p, "numbered parameter is already used in %s block\n"
+ "%s:%d: numbered parameter is already used here",
+ outer ? "outer" : "inner",
+ p->ruby_sourcefile, nd_line(used));
parser_show_error_line(p, &used->nd_loc);
return 1;
}
@@ -12906,8 +12923,8 @@ numparam_used_p(struct parser_params *p)
{
NODE *numparam = p->lvtbl->numparam.current;
if (numparam) {
- compile_error(p, "numbered parameter is already used in\n"
- "%s:%d: current block here",
+ compile_error(p, "'it' is not allowed when a numbered parameter is already used\n"
+ "%s:%d: numbered parameter is already used here",
p->ruby_sourcefile, nd_line(numparam));
parser_show_error_line(p, &numparam->nd_loc);
return 1;
@@ -12920,8 +12937,8 @@ it_used_p(struct parser_params *p)
{
NODE *it = p->lvtbl->it;
if (it) {
- compile_error(p, "'it' is already used in\n"
- "%s:%d: current block here",
+ compile_error(p, "numbered parameters are not allowed when 'it' is already used\n"
+ "%s:%d: 'it' is already used here",
p->ruby_sourcefile, nd_line(it));
parser_show_error_line(p, &it->nd_loc);
return 1;
@@ -12984,14 +13001,14 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
}
# 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))) {
+ if (dyna_in_block(p) && id == idIt && !(DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev))) {
if (numparam_used_p(p)) return 0;
if (p->max_numparam == ORDINAL_PARAM) {
compile_error(p, "ordinary parameter is defined");
return 0;
}
if (!p->it_id) {
- p->it_id = internal_id(p);
+ p->it_id = idItImplicit;
vtable_add(p->lvtbl->args, p->it_id);
}
NODE *node = NEW_DVAR(p->it_id, loc);
@@ -13038,8 +13055,11 @@ 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)
+new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
{
+ int had_trailing_semicolon = p->ctxt.has_trailing_semicolon;
+ p->ctxt.has_trailing_semicolon = 0;
+
NODE *n = expr;
while (n) {
if (nd_type_p(n, NODE_BEGIN)) {
@@ -13052,7 +13072,13 @@ new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc)
break;
}
}
- return NEW_DEFINED(n, loc);
+
+ if (had_trailing_semicolon && !nd_type_p(expr, NODE_BLOCK)) {
+ NODE *block = NEW_BLOCK(expr, loc);
+ return NEW_DEFINED(block, loc, keyword_loc);
+ }
+
+ return NEW_DEFINED(n, loc, keyword_loc);
}
static NODE*
@@ -13778,7 +13804,9 @@ value_expr_check(struct parser_params *p, NODE *node)
case NODE_RESCUE:
/* void only if all children are void */
vn = RNODE_RESCUE(node)->nd_head;
- if (!vn || !(vn = value_expr_check(p, vn))) return NULL;
+ if (!vn || !(vn = value_expr_check(p, vn))) {
+ if (!RNODE_RESCUE(node)->nd_else) return NULL;
+ }
if (!void_node) void_node = vn;
for (NODE *r = RNODE_RESCUE(node)->nd_resq; r; r = RNODE_RESBODY(r)->nd_next) {
if (!nd_type_p(r, NODE_RESBODY)) {
@@ -13786,8 +13814,7 @@ value_expr_check(struct parser_params *p, NODE *node)
return NULL;
}
if (!(vn = value_expr_check(p, RNODE_RESBODY(r)->nd_body))) {
- void_node = 0;
- break;
+ return NULL;
}
if (!void_node) void_node = vn;
}
@@ -13802,19 +13829,43 @@ value_expr_check(struct parser_params *p, NODE *node)
case NODE_RETRY:
goto found;
- 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;
+ case NODE_CASE:
+ case NODE_CASE2:
+ for (node = RNODE_CASE(node)->nd_body;
+ node && nd_type_p(node, NODE_WHEN);
+ node = RNODE_WHEN(node)->nd_next) {
+ if (!(vn = value_expr_check(p, RNODE_WHEN(node)->nd_body))) {
+ return NULL;
+ }
+ if (!void_node) void_node = vn;
}
- if (RNODE_IN(RNODE_CASE3(node)->nd_body)->nd_body) {
- return NULL;
+ break;
+
+ case NODE_CASE3:
+ {
+ NODE *in = RNODE_CASE3(node)->nd_body;
+ if (!in || !nd_type_p(in, NODE_IN)) {
+ compile_error(p, "unexpected node");
+ return NULL;
+ }
+ if (!RNODE_IN(in)->nd_body) {
+ /* single line pattern matching with "=>" operator */
+ goto found;
+ }
+ do {
+ vn = value_expr_check(p, RNODE_IN(in)->nd_body);
+ if (!vn) return NULL;
+ if (!void_node) void_node = vn;
+ in = RNODE_IN(in)->nd_next;
+ } while (in && nd_type_p(in, NODE_IN));
+ node = in; /* else */
}
- /* single line pattern matching with "=>" operator */
- goto found;
+ break;
case NODE_BLOCK:
while (RNODE_BLOCK(node)->nd_next) {
+ vn = value_expr_check(p, RNODE_BLOCK(node)->nd_head);
+ if (vn) return vn;
node = RNODE_BLOCK(node)->nd_next;
}
node = RNODE_BLOCK(node)->nd_head;
@@ -13862,7 +13913,7 @@ value_expr_check(struct parser_params *p, NODE *node)
}
static int
-value_expr_gen(struct parser_params *p, NODE *node)
+value_expr(struct parser_params *p, NODE *node)
{
NODE *void_node = value_expr_check(p, node);
if (void_node) {
@@ -14131,7 +14182,7 @@ range_op(struct parser_params *p, NODE *node, const YYLTYPE *loc)
if (node == 0) return 0;
type = nd_type(node);
- value_expr(node);
+ value_expr(p, node);
if (type == NODE_INTEGER) {
if (!e_option_supplied(p)) rb_warn0L(nd_line(node), "integer literal in flip-flop");
ID lineno = rb_intern("$.");
@@ -14268,7 +14319,7 @@ logop(struct parser_params *p, ID id, NODE *left, NODE *right,
{
enum node_type type = id == idAND || id == idANDOP ? NODE_AND : NODE_OR;
NODE *op;
- value_expr(left);
+ value_expr(p, 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)) {
@@ -14307,7 +14358,7 @@ ret_args(struct parser_params *p, NODE *node)
}
static NODE*
-negate_lit(struct parser_params *p, NODE* node)
+negate_lit(struct parser_params *p, NODE* node, const YYLTYPE *loc)
{
switch (nd_type(node)) {
case NODE_INTEGER:
@@ -14323,6 +14374,7 @@ negate_lit(struct parser_params *p, NODE* node)
RNODE_IMAGINARY(node)->minus = TRUE;
break;
}
+ node->nd_loc = *loc;
return node;
}
@@ -14376,12 +14428,6 @@ new_args(struct parser_params *p, rb_node_args_aux_t *pre_args, rb_node_opt_arg_
args->opt_args = opt_args;
-#ifdef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- args->ruby2_keywords = args->forwarding;
-#else
- args->ruby2_keywords = 0;
-#endif
-
nd_set_loc(RNODE(tail), loc);
return tail;
@@ -14394,6 +14440,10 @@ new_args_tail(struct parser_params *p, rb_node_kw_arg_t *kw_args, ID kw_rest_arg
struct rb_args_info *args = &node->nd_ainfo;
if (p->error_p) return node;
+ if (block == idNil) {
+ block = 0;
+ args->no_blockarg = TRUE;
+ }
args->block_arg = block;
args->kw_args = kw_args;
@@ -14450,7 +14500,7 @@ args_with_numbered(struct parser_params *p, rb_node_args_t *args, int max_numpar
if (max_numparam > NO_PARAM || it_id) {
if (!args) {
YYLTYPE loc = RUBY_INIT_YYLLOC();
- args = new_args_tail(p, 0, 0, 0, 0);
+ args = new_empty_args_tail(p, 0);
nd_set_loc(RNODE(args), &loc);
}
args->nd_ainfo.pre_args_num = it_id ? 1 : max_numparam;
@@ -14655,7 +14705,11 @@ error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *
if (st_is_member(p->pvtbl, id)) {
yyerror1(loc, "duplicated variable name");
}
+ else if (p->ctxt.in_alt_pattern && id) {
+ yyerror1(loc, "variable capture in alternative pattern");
+ }
else {
+ p->ctxt.capture_in_pattern = 1;
st_insert(p->pvtbl, (st_data_t)id, 0);
}
}
@@ -14864,7 +14918,7 @@ local_free(struct parser_params *p, struct local_vars *local)
vtable_chain_free(p, local->args);
vtable_chain_free(p, local->vars);
- ruby_sized_xfree(local, sizeof(struct local_vars));
+ ruby_xfree_sized(local, sizeof(struct local_vars));
}
static void
@@ -14987,9 +15041,7 @@ static void
add_forwarding_args(struct parser_params *p)
{
arg_var(p, idFWD_REST);
-#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
arg_var(p, idFWD_KWREST);
-#endif
arg_var(p, idFWD_BLOCK);
arg_var(p, idFWD_ALL);
}
@@ -15032,15 +15084,11 @@ static NODE *
new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc, const YYLTYPE *argsloc)
{
NODE *rest = NEW_LVAR(idFWD_REST, 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), argsloc, &NULL_LOC);
NODE *args = leading ? rest_arg_append(p, leading, rest, argsloc) : NEW_SPLAT(rest, loc, &NULL_LOC);
block->forwarding = TRUE;
-#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
args = arg_append(p, args, new_hash(p, kwrest, loc), argsloc);
-#endif
return arg_blk_pass(args, block);
}
@@ -15129,7 +15177,7 @@ dyna_pop(struct parser_params *p, const struct vtable *lvargs)
dyna_pop_1(p);
if (!p->lvtbl->args) {
struct local_vars *local = p->lvtbl->prev;
- ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
+ ruby_xfree_sized(p->lvtbl, sizeof(*p->lvtbl));
p->lvtbl = local;
}
}
@@ -15519,7 +15567,7 @@ rb_ruby_parser_free(void *ptr)
#endif
if (p->tokenbuf) {
- ruby_sized_xfree(p->tokenbuf, p->toksiz);
+ ruby_xfree_sized(p->tokenbuf, p->toksiz);
}
for (local = p->lvtbl; local; local = prev) {
diff --git a/parser_bits.h b/parser_bits.h
index ca7535280e..f894dde33e 100644
--- a/parser_bits.h
+++ b/parser_bits.h
@@ -30,13 +30,13 @@
#include <stdint.h> /* for uintptr_t */
#include "internal/compilers.h" /* for MSC_VERSION_SINCE */
-#if MSC_VERSION_SINCE(1310)
+#ifdef _MSC_VER
# include <stdlib.h> /* for _byteswap_uint64 */
#endif
#if defined(HAVE_X86INTRIN_H)
# include <x86intrin.h> /* for _lzcnt_u64 */
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
# include <intrin.h> /* for the following intrinsics */
#endif
@@ -50,16 +50,13 @@
# pragma intrinsic(__lzcnt64)
#endif
-#if MSC_VERSION_SINCE(1310)
+#if defined(_MSC_VER)
# 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
@@ -90,6 +87,7 @@
#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0)
+#ifndef MUL_OVERFLOW_SIGNED_INTEGER_P
#if __has_builtin(__builtin_mul_overflow_p)
# define MUL_OVERFLOW_P(a, b) \
__builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0)
@@ -118,15 +116,100 @@
MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
#endif
-#ifdef MUL_OVERFLOW_P
+#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_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
+#endif
+
+#ifndef ADD_OVERFLOW_SIGNED_INTEGER_P
+#if __has_builtin(__builtin_add_overflow_p)
+# define ADD_OVERFLOW_P(a, b) \
+ __builtin_add_overflow_p((a), (b), (__typeof__(a * b))0)
+#elif __has_builtin(__builtin_add_overflow)
+# define ADD_OVERFLOW_P(a, b) \
+ __extension__ ({ __typeof__(a) c; __builtin_add_overflow((a), (b), &c); })
+#endif
+
+#define ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ (a) > 0 ? (b) > (max) - (a) : (b) < (min) - (a))
+
+#if __has_builtin(__builtin_add_overflow_p)
+/* __builtin_add_overflow_p can take bitfield */
+/* and GCC permits bitfields for integers other than int */
+# define ADD_OVERFLOW_FIXNUM_P(a, b) \
+ __extension__ ({ \
+ struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
+ __builtin_add_overflow_p((a), (b), c.fixnum); \
+ })
+#else
+# define ADD_OVERFLOW_FIXNUM_P(a, b) \
+ ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
+#endif
+
+#if defined(ADD_OVERFLOW_P) && defined(USE___BUILTIN_ADD_OVERFLOW_LONG_LONG)
+# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_P(a, b)
+#else
+# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
+#endif
+
+#ifdef ADD_OVERFLOW_P
+# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_P(a, b)
+# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_P(a, b)
+#else
+# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
+# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
+#endif
+#endif
+
+#ifndef SUB_OVERFLOW_SIGNED_INTEGER_P
+#if __has_builtin(__builtin_sub_overflow_p)
+# define SUB_OVERFLOW_P(a, b) \
+ __builtin_sub_overflow_p((a), (b), (__typeof__(a * b))0)
+#elif __has_builtin(__builtin_sub_overflow)
+# define SUB_OVERFLOW_P(a, b) \
+ __extension__ ({ __typeof__(a) c; __builtin_sub_overflow((a), (b), &c); })
+#endif
+
+#define SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ (b) > 0 ? (a) < (min) + (b) : (a) > (max) + (b))
+
+#if __has_builtin(__builtin_sub_overflow_p)
+/* __builtin_sub_overflow_p can take bitfield */
+/* and GCC permits bitfields for integers other than int */
+# define SUB_OVERFLOW_FIXNUM_P(a, b) \
+ __extension__ ({ \
+ struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
+ __builtin_sub_overflow_p((a), (b), c.fixnum); \
+ })
+#else
+# define SUB_OVERFLOW_FIXNUM_P(a, b) \
+ SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
+#endif
+
+#if defined(SUB_OVERFLOW_P) && defined(USE___BUILTIN_SUB_OVERFLOW_LONG_LONG)
+# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_P(a, b)
+#else
+# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
+#endif
+
+#ifdef SUB_OVERFLOW_P
+# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_P(a, b)
+# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_P(a, b)
+#else
+# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
+# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
+#endif
+#endif
#ifdef HAVE_UINT128_T
# define bit_length(x) \
@@ -180,7 +263,7 @@ ruby_swap16(uint16_t x)
#if __has_builtin(__builtin_bswap16)
return __builtin_bswap16(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ushort(x);
#else
@@ -195,7 +278,7 @@ ruby_swap32(uint32_t x)
#if __has_builtin(__builtin_bswap32)
return __builtin_bswap32(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_ulong(x);
#else
@@ -212,7 +295,7 @@ ruby_swap64(uint64_t x)
#if __has_builtin(__builtin_bswap64)
return __builtin_bswap64(x);
-#elif MSC_VERSION_SINCE(1310)
+#elif defined(_MSC_VER)
return _byteswap_uint64(x);
#else
@@ -237,7 +320,7 @@ nlz_int32(uint32_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
@@ -266,7 +349,7 @@ nlz_int64(uint64_t x)
#elif defined(__x86_64__) && defined(__LZCNT__)
return (unsigned int)_lzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
+#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */
unsigned long r;
return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
@@ -394,9 +477,9 @@ rb_popcount32(uint32_t 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);
+ x = (x & 0x07070707) + (x >> 4 & 0x07070707);
+ x = (x & 0x000f000f) + (x >> 8 & 0x000f000f);
+ x = (x & 0x0000001f) + (x >>16 & 0x0000001f);
return (unsigned int)x;
#endif
@@ -424,9 +507,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 & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
- x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
- x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
+ x = (x & 0x000f000f000f000f) + (x >> 8 & 0x000f000f000f000f);
+ x = (x & 0x0000001f0000001f) + (x >>16 & 0x0000001f0000001f);
+ x = (x & 0x000000000000003f) + (x >>32 & 0x000000000000003f);
return (unsigned int)x;
#endif
@@ -452,7 +535,7 @@ ntz_int32(uint32_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u32(x);
-#elif MSC_VERSION_SINCE(1400)
+#elif defined(_MSC_VER)
/* :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;
@@ -474,7 +557,7 @@ ntz_int64(uint64_t x)
#if defined(__x86_64__) && defined(__BMI__)
return (unsigned)_tzcnt_u64(x);
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
+#elif defined(_WIN64) && defined(_MSC_VER)
unsigned long r;
return _BitScanForward64(&r, x) ? (int)r : 64;
@@ -522,10 +605,10 @@ RUBY_BIT_ROTL(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotl(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotl64(v, n);
#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG)
@@ -546,10 +629,10 @@ RUBY_BIT_ROTR(VALUE v, int 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)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32)
return _rotr(v, n);
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
+#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64)
return _rotr64(v, n);
#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG)
diff --git a/parser_st.c b/parser_st.c
index c234026122..77d9df702e 100644
--- a/parser_st.c
+++ b/parser_st.c
@@ -80,6 +80,12 @@ nonempty_memcpy(void *dest, const void *src, size_t n)
#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_init_existing_strtable_with_size
+#define st_init_existing_strtable_with_size rb_parser_st_init_existing_strtable_with_size
+#undef st_init_existing_numtable_with_size
+#define st_init_existing_numtable_with_size rb_parser_st_init_existing_numtable_with_size
+#undef st_free_embedded_table
+#define st_free_embedded_table rb_parser_st_free_embedded_table
#undef st_insert
#define st_insert rb_parser_st_insert
#undef st_lookup
diff --git a/parser_st.h b/parser_st.h
index 877b1e9051..007ebb1bd4 100644
--- a/parser_st.h
+++ b/parser_st.h
@@ -88,13 +88,12 @@ struct parser_st_table {
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. */
+ /* Array of size 2^entry_power.
+ Optionnally followed by an array of bins used for access by keys. */
parser_st_table_entry *entries;
};
diff --git a/pathname.c b/pathname.c
new file mode 100644
index 0000000000..b12f640373
--- /dev/null
+++ b/pathname.c
@@ -0,0 +1,372 @@
+#include "ruby.h"
+#include "internal.h"
+#include "internal/file.h"
+#include "internal/string.h"
+#include "internal/vm.h"
+
+#if defined __CYGWIN__ || defined DOSISH
+# define drive_letter 1
+# define alt_separator 1
+# define isdirsep(x) ((x) == '/' || (x) == '\\')
+#else
+# define drive_letter 0
+# define alt_separator 0
+# define isdirsep(x) ((x) == '/')
+#endif
+
+static VALUE rb_cPathname;
+static ID id_at_path;
+static ID id_sub;
+
+static VALUE
+check_strpath(VALUE path)
+{
+ Check_Type(path, T_STRING);
+ rb_get_path_check_no_convert(path);
+ return path;
+}
+
+static VALUE
+get_strpath(VALUE obj)
+{
+ VALUE strpath;
+ strpath = rb_ivar_get(obj, id_at_path);
+ if (!RB_TYPE_P(strpath, T_STRING))
+ rb_raise(rb_eTypeError, "unexpected @path");
+ rb_get_path_check_no_convert(strpath);
+ return strpath;
+}
+
+/*
+ * call-seq:
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares the contents of +self+ and +other+ as strings;
+ * see String#<=>.
+ *
+ * Returns:
+ *
+ * - <tt>-1</tt> if +self+'s string is smaller than +other+'s string.
+ * - <tt>0</tt> if the two are equal.
+ * - <tt>1</tt> if +self+'s string is larger than +other+'s string.
+ * - <tt>nil</tt> if +other+ is not a \Pathname.
+ *
+ * Examples:
+ *
+ * Pathname('a') <=> Pathname('b') # => -1
+ * Pathname('a') <=> Pathname('ab') # => -1
+ * Pathname('a') <=> Pathname('a') # => 0
+ * Pathname('b') <=> Pathname('a') # => 1
+ * Pathname('ab') <=> Pathname('a') # => 1
+ * Pathname('ab') <=> 'a' # => nil
+ *
+ * Two pathnames that are different may refer to the same entry in the filesystem:
+ *
+ * Pathname('lib') <=> Pathname('./lib') # => 1
+ *
+ */
+static VALUE
+path_cmp(VALUE self, VALUE other)
+{
+ VALUE s1, s2;
+ char *p1, *p2;
+ char *e1, *e2;
+ if (!rb_obj_is_kind_of(other, rb_cPathname))
+ return Qnil;
+ s1 = get_strpath(self);
+ s2 = get_strpath(other);
+ p1 = RSTRING_PTR(s1);
+ p2 = RSTRING_PTR(s2);
+ e1 = p1 + RSTRING_LEN(s1);
+ e2 = p2 + RSTRING_LEN(s2);
+ while (p1 < e1 && p2 < e2) {
+ int c1, c2;
+ c1 = (unsigned char)*p1++;
+ c2 = (unsigned char)*p2++;
+ if (c1 == '/') c1 = '\0';
+ if (c2 == '/') c2 = '\0';
+ if (c1 != c2) {
+ if (c1 < c2)
+ return INT2FIX(-1);
+ else
+ return INT2FIX(1);
+ }
+ }
+ if (p1 < e1)
+ return INT2FIX(1);
+ if (p2 < e2)
+ return INT2FIX(-1);
+ return INT2FIX(0);
+}
+
+/*
+ * Return a pathname which is substituted by String#sub.
+ *
+ * path1 = Pathname.new('/usr/bin/perl')
+ * path1.sub('perl', 'ruby')
+ * #=> #<Pathname:/usr/bin/ruby>
+ */
+static VALUE
+path_sub(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str = get_strpath(self);
+
+ if (rb_block_given_p()) {
+ str = rb_block_call(str, id_sub, argc, argv, 0, 0);
+ }
+ else {
+ str = rb_funcallv(str, id_sub, argc, argv);
+ }
+ return rb_class_new_instance(1, &str, rb_obj_class(self));
+}
+
+/* :nodoc: */
+static VALUE
+same_paths(VALUE self, VALUE a, VALUE b)
+{
+ check_strpath(a);
+ check_strpath(b);
+ if (CASEFOLD_FILESYSTEM)
+ return RBOOL(rb_str_casecmp(a, b) == INT2FIX(0));
+ else
+ return rb_str_equal(a, b);
+}
+
+/*
+ * Predicate method for root directories. Returns +true+ if the
+ * pathname consists of consecutive slashes.
+ *
+ * It doesn't access the filesystem. So it may return +false+ for some
+ * pathnames which points to roots such as <tt>/usr/..</tt>.
+ */
+static VALUE
+path_root_p(VALUE self)
+{
+ VALUE path = get_strpath(self);
+ if (RSTRING_LEN(path) == 0) return Qfalse;
+ const char *ptr = RSTRING_PTR(path), *end = RSTRING_END(path);
+ rb_encoding *enc = rb_enc_get(path);
+ const char *base = rb_enc_path_skip_prefix_root(ptr, end, enc);
+ return RBOOL(base == end);
+}
+
+/*
+ * call-seq:
+ * absolute? -> true or false
+ *
+ * Returns whether +self+ contains an absolute path:
+ *
+ * Pathname('/home').absolute? # => true
+ * Pathname('lib').absolute? # => false
+ *
+ * The result is OS-dependent for some paths:
+ *
+ * Pathname('C:/').absolute? # => true # On Windows.
+ * Pathname('C:/').absolute? # => false # Elsewhere.
+ *
+ */
+static VALUE
+path_absolute_p(VALUE self)
+{
+ VALUE path = get_strpath(self);
+ const char *ptr = RSTRING_PTR(path);
+ long len = RSTRING_LEN(path);
+ if (len < 1) return Qfalse;
+ if (drive_letter) {
+ if (len >= 2 && ISALPHA(ptr[0]) && (ptr[1] == ':')) return Qtrue;
+ }
+ return RBOOL(isdirsep(ptr[0]));
+}
+
+/* :nodoc: */
+static VALUE
+has_separator_p(VALUE self, VALUE path)
+{
+ const char *ptr = RSTRING_PTR(check_strpath(path));
+ const char *end = RSTRING_END(path);
+ if (alt_separator) {
+ rb_encoding *enc = rb_enc_get(path);
+ bool mb = !rb_str_enc_fastpath(path);
+ while (ptr < end) {
+ if (isdirsep(*ptr)) return Qtrue;
+ ptr += (mb ? rb_enc_mbclen(ptr, end, enc) : 1);
+ }
+ }
+ else {
+ /* assume '/' will never be trailing bytes */
+ if (memchr(ptr, '/', end - ptr)) return Qtrue;
+ }
+ return Qfalse;
+}
+
+/*
+ * Return a pathname with +repl+ added as a suffix to the basename.
+ *
+ * If self has no extension part, +repl+ is appended.
+ *
+ * Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
+ * #=> #<Pathname:/usr/bin/shutdown.rb>
+ */
+static VALUE
+path_sub_ext(VALUE self, VALUE repl)
+{
+ VALUE path = get_strpath(self);
+ long len = RSTRING_LEN(path);
+ const char *ptr = RSTRING_PTR(path);
+ const char *ext = ruby_enc_find_extname(ptr, &len, rb_enc_get(path));
+ if (len > 0) {
+ RUBY_ASSERT(ext, "should point the last dot");
+ path = rb_str_subseq(path, 0, ext - ptr);
+ }
+ else {
+ /* no dot or dotted file */
+ path = rb_str_dup(path);
+ }
+ path = rb_str_append(path, repl);
+ return rb_class_new_instance(1, &path, rb_obj_class(self));
+}
+
+/* :nodoc: */
+/* chop_basename(path) -> [pre-basename, basename] or nil */
+static VALUE
+chop_basename(VALUE self, VALUE path)
+{
+ long baselen, alllen = RSTRING_LEN(check_strpath(path));
+ if (alllen <= 0) return Qnil;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *base = ruby_enc_find_basename(name, &baselen, &alllen, enc);
+ if (baselen < 1) return Qnil;
+ if (baselen == 1 && isdirsep(*base)) return Qnil;
+ RUBY_ASSERT(base >= name);
+ RUBY_ASSERT(base <= RSTRING_END(path));
+ VALUE dir = rb_str_subseq(path, 0, base - name);
+ VALUE basename = rb_enc_str_new(base, alllen, enc);
+ RB_GC_GUARD(path);
+ return rb_assoc_new(dir, basename);
+}
+
+/* :nodoc: */
+/* split_names(path) -> prefix, [name, ...] */
+static VALUE
+split_names(VALUE self, VALUE path)
+{
+ rb_encoding *enc = rb_enc_get(check_strpath(path));
+ const char *beg = RSTRING_PTR(path), *ptr = beg;
+ const char *end = RSTRING_END(path);
+ const char *root = rb_enc_path_skip_prefix_root(ptr, end, enc);
+ VALUE pre = rb_str_subseq(path, 0, root - ptr);
+ VALUE names = rb_ary_new();
+ while (ptr < end) {
+ const char *next = rb_enc_path_next(ptr, end, enc);
+ if (next > ptr) rb_ary_push(names, rb_str_subseq(path, ptr - beg, next - ptr));
+ ptr = next;
+ while (ptr < end && isdirsep(*ptr)) ++ptr;
+ }
+ return rb_assoc_new(pre, names);
+}
+
+/* :nodoc: */
+/* has_trailing_separator?(path) -> bool */
+static VALUE
+has_trailing_separator(VALUE self, VALUE path)
+{
+ long baselen, alllen = RSTRING_LEN(check_strpath(path));
+ if (alllen <= 0) return Qfalse;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *base = ruby_enc_find_basename(name, &baselen, &alllen, enc);
+ if (baselen < 1) return Qfalse;
+ if (baselen == 1 && isdirsep(*base)) return Qfalse;
+ return RBOOL(base + alllen < RSTRING_END(path));
+}
+
+/* :nodoc: */
+/* add_trailing_separator(path) -> path */
+static VALUE
+add_trailing_separator(VALUE self, VALUE path)
+{
+ if (RSTRING_LEN(check_strpath(path)) <= 0) return path;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *end = RSTRING_END(path);
+ const char *top = rb_enc_path_skip_prefix(name, end, enc);
+ if (top < end && isdirsep(end[-1])) {
+ if (end[-1] == '/' || rb_enc_prev_char(top, end, end, enc) == end - 1)
+ return path;
+ }
+ return rb_str_cat_cstr(rb_str_dup(path), "/");
+}
+
+/* :nodoc: */
+static VALUE
+del_trailing_separator(VALUE self, VALUE path)
+{
+ long len = RSTRING_LEN(check_strpath(path));
+ if (len <= 0) return path;
+ rb_encoding *enc = rb_enc_get(path);
+ const char *name = RSTRING_PTR(path);
+ const char *end = name + len, *tail = end;
+ const char *top = rb_enc_path_skip_prefix(name, end, enc);
+ if (tail > top && isdirsep(tail[-1])) {
+ while (--tail > top && isdirsep(tail[-1]));
+ if (tail > top &&
+ tail[0] != '/' &&
+ !rb_str_enc_fastpath(path) &&
+ rb_enc_left_char_head(top, tail, end, enc) != tail) {
+ /* trailing byte, not a directory separator */
+ ++tail;
+ }
+ if (tail < end) {
+ if (tail == name || (drive_letter && tail == top && top[-1] == ':')) {
+ ++tail;
+ }
+ }
+ }
+ if (tail == end) return path;
+ return rb_str_subseq(path, 0, tail - name);
+}
+
+#include "pathname_builtin.rbinc"
+
+static void init_ids(void);
+
+void
+Init_pathname(void)
+{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
+ init_ids();
+ InitVM(pathname);
+}
+
+void
+InitVM_pathname(void)
+{
+ rb_cPathname = rb_define_class("Pathname", rb_cObject);
+ rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
+ rb_define_method(rb_cPathname, "sub", path_sub, -1);
+ rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
+ rb_define_method(rb_cPathname, "root?", path_root_p, 0);
+ rb_define_method(rb_cPathname, "absolute?", path_absolute_p, 0);
+
+ rb_define_private_method(rb_cPathname, "same_paths?", same_paths, 2);
+ rb_define_private_method(rb_cPathname, "has_separator?", has_separator_p, 1);
+ rb_define_private_method(rb_cPathname, "chop_basename", chop_basename, 1);
+ rb_define_private_method(rb_cPathname, "split_names", split_names, 1);
+ rb_define_private_method(rb_cPathname, "has_trailing_separator?", has_trailing_separator, 1);
+ rb_define_private_method(rb_cPathname, "add_trailing_separator", add_trailing_separator, 1);
+ rb_define_private_method(rb_cPathname, "del_trailing_separator", del_trailing_separator, 1);
+
+ rb_provide("pathname.so");
+}
+
+void
+init_ids(void)
+{
+#undef rb_intern
+ id_at_path = rb_intern("@path");
+ id_sub = rb_intern("sub");
+}
diff --git a/pathname_builtin.rb b/pathname_builtin.rb
new file mode 100644
index 0000000000..11ade220f0
--- /dev/null
+++ b/pathname_builtin.rb
@@ -0,0 +1,1895 @@
+# frozen_string_literal: true
+#
+# A \Pathname object contains a string directory path or filepath;
+# it does not represent a corresponding actual file or directory
+# -- which in fact may or may not exist.
+#
+# A \Pathname object is immutable (except for method #freeze).
+#
+# A pathname may be relative or absolute:
+#
+# Pathname.new('lib') # => #<Pathname:lib>
+# Pathname.new('/usr/local/bin') # => #<Pathname:/usr/local/bin>
+#
+# == About the Examples
+#
+# Many examples here use these variables:
+#
+# :include: doc/examples/files.rdoc
+#
+# == Convenience Methods
+#
+# The class provides *all* functionality from class File and module FileTest,
+# along with some functionality from class Dir and module FileUtils.
+#
+# Here's an example string path and corresponding \Pathname object:
+#
+# path = 'lib/fileutils.rb'
+# pn = Pathname.new(path) # => #<Pathname:lib/fileutils.rb>
+#
+# Each of these method pairs (\Pathname vs. \File) gives exactly the same result:
+#
+# pn.size # => 83777
+# File.size(path) # => 83777
+#
+# pn.directory? # => false
+# File.directory?(path) # => false
+#
+# pn.read.size # => 81074
+# File.read(path).size# # => 81074
+#
+# Each of these method pairs gives similar results,
+# but each \Pathname method returns a more versatile \Pathname object,
+# instead of a string:
+#
+# pn.dirname # => #<Pathname:lib>
+# File.dirname(path) # => "lib"
+#
+# pn.basename # => #<Pathname:fileutils.rb>
+# File.basename(path) # => "fileutils.rb"
+#
+# pn.split # => [#<Pathname:lib>, #<Pathname:fileutils.rb>]
+# File.split(path) # => ["lib", "fileutils.rb"]
+#
+# Each of these methods takes a block:
+#
+# pn.open do |file|
+# p file
+# end
+# File.open(path) do |file|
+# p file
+# end
+#
+# The outputs for each:
+#
+# #<File:lib/fileutils.rb (closed)>
+# #<File:lib/fileutils.rb (closed)>
+#
+# Each of these methods takes a block:
+#
+# pn.each_line do |line|
+# p line
+# break
+# end
+# File.foreach(path) do |line|
+# p line
+# break
+# end
+#
+# The outputs for each:
+#
+# "# frozen_string_literal: true\n"
+# "# frozen_string_literal: true\n"
+#
+# == More Methods
+#
+# Here is a sampling of other available methods:
+#
+# p1 = Pathname.new('/usr/lib') # => #<Pathname:/usr/lib>
+# p1.absolute? # => true
+# p2 = p1 + 'ruby/4.0' # => #<Pathname:/usr/lib/ruby/4.0>
+# p3 = p1.parent # => #<Pathname:/usr>
+# p4 = p2.relative_path_from(p3) # => #<Pathname:lib/ruby/4.0>
+# p4.absolute? # => false
+# p5 = Pathname.new('.') # => #<Pathname:.>
+# p6 = p5 + 'usr/../var' # => #<Pathname:usr/../var>
+# p6.cleanpath # => #<Pathname:var>
+# p6.realpath # => #<Pathname:/var>
+# p6.children.take(2)
+# # => [#<Pathname:usr/../var/local>, #<Pathname:usr/../var/spool>]
+#
+# == Breakdown of functionality
+#
+# === Core methods
+#
+# These methods are effectively manipulating a String, because that's
+# all a path is. None of these access the file system except for
+# #mountpoint?, #children, #each_child, #realdirpath and #realpath.
+#
+# - +
+# - #join
+# - #parent
+# - #root?
+# - #absolute?
+# - #relative?
+# - #relative_path_from
+# - #each_filename
+# - #cleanpath
+# - #realpath
+# - #realdirpath
+# - #children
+# - #each_child
+# - #mountpoint?
+#
+# === File status predicate methods
+#
+# These methods are a facade for FileTest:
+# - #blockdev?
+# - #chardev?
+# - #directory?
+# - #executable?
+# - #executable_real?
+# - #exist?
+# - #file?
+# - #grpowned?
+# - #owned?
+# - #pipe?
+# - #readable?
+# - #world_readable?
+# - #readable_real?
+# - #setgid?
+# - #setuid?
+# - #size
+# - #size?
+# - #socket?
+# - #sticky?
+# - #symlink?
+# - #writable?
+# - #world_writable?
+# - #writable_real?
+# - #zero?
+#
+# === File property and manipulation methods
+#
+# These methods are a facade for File:
+# - #each_line(*args, &block)
+# - #read(*args)
+# - #binread(*args)
+# - #readlines(*args)
+# - #sysopen(*args)
+# - #write(*args)
+# - #binwrite(*args)
+# - #atime
+# - #birthtime
+# - #ctime
+# - #mtime
+# - #chmod(mode)
+# - #lchmod(mode)
+# - #chown(owner, group)
+# - #lchown(owner, group)
+# - #fnmatch(pattern, *args)
+# - #fnmatch?(pattern, *args)
+# - #ftype
+# - #make_link(old)
+# - #open(*args, &block)
+# - #readlink
+# - #rename(to)
+# - #stat
+# - #lstat
+# - #make_symlink(old)
+# - #truncate(length)
+# - #utime(atime, mtime)
+# - #lutime(atime, mtime)
+# - #basename(*args)
+# - #dirname
+# - #extname
+# - #expand_path(*args)
+# - #split
+#
+# === Directory methods
+#
+# These methods are a facade for Dir:
+# - Pathname.glob(*args)
+# - Pathname.getwd / Pathname.pwd
+# - #rmdir
+# - #entries
+# - #each_entry(&block)
+# - #mkdir(*args)
+# - #opendir(*args)
+#
+# === Utilities
+#
+# These methods are a mixture of Find, FileUtils, and others:
+# - #find(&block)
+# - #mkpath
+# - #rmtree
+# - #unlink / #delete
+#
+#
+# == Method documentation
+#
+# As the above section shows, most of the methods in Pathname are facades. The
+# documentation for these methods generally just says, for instance, "See
+# FileTest.writable?", as you should be familiar with the original method
+# anyway, and its documentation (e.g. through +ri+) will contain more
+# information. In some cases, a brief description will follow.
+#
+class Pathname
+
+ # The version string.
+ VERSION = "0.4.0"
+
+ # :stopdoc:
+
+ attr_reader :path
+ protected :path
+
+ # :startdoc:
+
+ # call-seq:
+ # Pathname.new(path) -> new_pathname
+ #
+ # Returns a new \Pathname object based on the given +path+,
+ # via <tt>File.path(path).dup</tt>.
+ # the +path+ may be a String, a File, a Dir, or another \Pathname;
+ # see File.path:
+ #
+ # Pathname.new('.') # => #<Pathname:.>
+ # Pathname.new('/usr/bin') # => #<Pathname:/usr/bin>
+ # Pathname.new(File.new('LEGAL')) # => #<Pathname:LEGAL>
+ # Pathname.new(Dir.new('.')) # => #<Pathname:.>
+ # Pathname.new(Pathname.new('.')) # => #<Pathname:.>
+ #
+ def initialize(path)
+ @path = File.path(path).dup
+ rescue TypeError => e
+ raise e.class, "Pathname.new requires a String, #to_path or #to_str", cause: nil
+ end
+
+ #
+ # Freze self.
+ #
+ def freeze
+ super
+ @path.freeze
+ self
+ end
+
+ # call-seq:
+ # self == other -> true or false
+ #
+ # Returns whether the stored paths in +self+ and +other+ are equal:
+ #
+ # pn = Pathname('lib')
+ # pn == Pathname('lib') # => true
+ # pn == Pathname('./lib') # => false
+ #
+ # Returns +false+ if +other+ is not a pathname:
+ #
+ # pn == 'lib' # => false
+ #
+ def ==(other)
+ return false unless Pathname === other
+ other.path == @path
+ end
+ alias === ==
+ alias eql? ==
+
+ def hash # :nodoc:
+ @path.hash
+ end
+
+ # Return the path as a String.
+ def to_s
+ @path.dup
+ end
+
+ # to_path is implemented so Pathname objects are usable with File.open, etc.
+ alias to_path to_s
+
+ def inspect # :nodoc:
+ "#<#{self.class}:#{@path}>"
+ end
+
+ # Creates a full path, including any intermediate directories that don't yet
+ # exist.
+ #
+ # See FileUtils.mkpath and FileUtils.mkdir_p
+ def mkpath(mode: nil)
+ path = @path == '/' ? @path : @path.chomp('/')
+
+ stack = []
+ until File.directory?(path) || (parent = File.dirname(path)) == path
+ stack.push path
+ path = parent
+ end
+
+ stack.reverse_each do |dir|
+ dir = dir == '/' ? dir : dir.chomp('/')
+ if mode
+ Dir.mkdir dir, mode
+ File.chmod mode, dir
+ else
+ Dir.mkdir dir
+ end
+ rescue SystemCallError
+ raise unless File.directory?(dir)
+ end
+
+ self
+ end
+
+ def prepend_prefix(prefix, relpath) # :nodoc:
+ if relpath.empty?
+ File.dirname(prefix)
+ elsif has_separator?(prefix)
+ add_trailing_separator(File.dirname(prefix)) + relpath
+ else
+ prefix + relpath
+ end
+ end
+ private :prepend_prefix
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # cleanpath(symlinks = false) -> new_pathname
+ #
+ # Returns a new \Pathname object, "cleaned" of unnecessary separators,
+ # single-dot entries, and double-dot entries.
+ #
+ # When `self` is empty, returns a pathname with a single-dot entry:
+ #
+ # ```
+ # Pathname('').cleanpath # => #<Pathname:.>
+ # ```
+ #
+ # <b>Separators</b>
+ #
+ # A lone separator is preserved:
+ #
+ # ```
+ # Pathname('/').cleanpath # => #<Pathname:/>
+ # ```
+ #
+ # Multiple trailing separators are removed:
+ #
+ # ```
+ # Pathname('foo/////').cleanpath # => #<Pathname:foo>
+ # Pathname('foo/').cleanpath # => #<Pathname:foo>
+ # ```
+ #
+ # Multiple embedded separators are reduced to a single separator:
+ #
+ # ```
+ # Pathname('foo///bar').cleanpath # => #<Pathname:foo/bar>
+ # ```
+ #
+ # Multiple leading separators are reduced:
+ #
+ # ```
+ # # On Windows, where File.dirname('//') == '//'.
+ # Pathname('/////foo').cleanpath # => #<Pathname://foo>
+ # Pathname('/////').cleanpath # => #<Pathname://>
+ # # Otherwise, where File.dirname('//') == '/'.
+ # Pathname('/////foo').cleanpath # => #<Pathname:/foo>
+ # Pathname('/////').cleanpath # => #<Pathname:/>
+ # ```
+ #
+ # <b>Single-Dot Entries</b>
+ #
+ # A lone single-dot entry is preserved:
+ #
+ # ```
+ # Pathname('.').cleanpath # => #<Pathname:.>
+ # ```
+ #
+ # A non-lone single-dot entry, regardless of its location, is removed:
+ #
+ # ```
+ # Pathname('foo/././././bar').cleanpath # => #<Pathname:foo/bar>
+ # Pathname('./foo/./././bar').cleanpath # => #<Pathname:foo/bar>
+ # Pathname('foo/./././bar/./').cleanpath # => #<Pathname:foo/bar>
+ # ```
+ #
+ # <b>Double-Dot Entries</b>
+ #
+ # A lone double-dot entry is preserved:
+ #
+ # ```
+ # Pathname('..').cleanpath # => #<Pathname:..>
+ # ```
+ #
+ # When a non-lone double-dot entry is preceded by a named entry, both are removed:
+ #
+ # ```
+ # Pathname('foo/..').cleanpath # => #<Pathname:.>
+ # Pathname('foo/../bar').cleanpath # => #<Pathname:bar>
+ # Pathname('foo/../bar/..').cleanpath # => #<Pathname:.>
+ # Pathname('foo/bar/./../..').cleanpath # => #<Pathname:.>
+ # ```
+ #
+ # When a non-lone double-dot entry is _not_ preceded by a named entry,
+ # it is preserved:
+ #
+ # ```
+ # Pathname('../..').cleanpath # => #<Pathname:../..>
+ # ```
+ #
+ # A non-lone meaningless double-dot entry is removed:
+ #
+ # ```
+ # Pathname('/..').cleanpath # => #<Pathname:/>
+ # Pathname('/../..').cleanpath # => #<Pathname:/>
+ # ```
+ #
+ # <b> Symbolic Links</b>
+ #
+ # If the path may contain [symbolic links][symbolic link],
+ # consider give optional argument `symlinks` as `true`;
+ # the method then uses a more conservative algorithm
+ # that avoids breaking symbolic links.
+ # This may preserve more double-dot entries than are absolutely necessary,
+ # but without accessing the filesystem, this can't be avoided.
+ #
+ # Examples:
+ #
+ # ```
+ # Pathname('a/').cleanpath # => #<Pathname:a>
+ # Pathname('a/').cleanpath(true) # => #<Pathname:a/>
+ #
+ # Pathname('a/.').cleanpath # => #<Pathname:a>
+ # Pathname('a/.').cleanpath(true) # => #<Pathname:a/.>
+ #
+ # Pathname('a/./').cleanpath # => #<Pathname:a>
+ # Pathname('a/./').cleanpath(true) # => #<Pathname:a/.>
+ #
+ # Pathname('a/b/.').cleanpath # => #<Pathname:a/b>
+ # Pathname('a/b/.').cleanpath(true) # => #<Pathname:a/b/.>
+ #
+ # Pathname('a/../.').cleanpath # => #<Pathname:.>
+ # Pathname('a/../.').cleanpath(true) # => #<Pathname:a/..>
+ #
+ # Pathname('a/b/../../../../c/../d').cleanpath
+ # # => #<Pathname:../../d>
+ # Pathname('a/b/../../../../c/../d').cleanpath(true)
+ # # => #<Pathname:a/b/../../../../c/../d>
+ # ```
+ #
+ # [symbolic link]: https://en.wikipedia.org/wiki/Symbolic_link
+ #
+ def cleanpath(consider_symlink=false)
+ if consider_symlink
+ cleanpath_conservative
+ else
+ cleanpath_aggressive
+ end
+ end
+
+ #
+ # Clean the path simply by resolving and removing excess +.+ and +..+ entries.
+ # Nothing more, nothing less.
+ #
+ def cleanpath_aggressive # :nodoc:
+ path = @path
+ names = []
+ pre = path
+ while r = chop_basename(pre)
+ pre, base = r
+ case base
+ when '.'
+ when '..'
+ names.unshift base
+ else
+ if names[0] == '..'
+ names.shift
+ else
+ names.unshift base
+ end
+ end
+ end
+ pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
+ if has_separator?(File.basename(pre))
+ names.shift while names[0] == '..'
+ end
+ self.class.new(prepend_prefix(pre, File.join(*names)))
+ end
+ private :cleanpath_aggressive
+
+ def cleanpath_conservative # :nodoc:
+ path = @path
+ names = []
+ pre = path
+ while r = chop_basename(pre)
+ pre, base = r
+ names.unshift base if base != '.'
+ end
+ pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
+ if has_separator?(File.basename(pre))
+ names.shift while names[0] == '..'
+ end
+ if names.empty?
+ self.class.new(File.dirname(pre))
+ else
+ if names.last != '..' && File.basename(path) == '.'
+ names << '.'
+ end
+ result = prepend_prefix(pre, File.join(*names))
+ if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
+ self.class.new(add_trailing_separator(result))
+ else
+ self.class.new(result)
+ end
+ end
+ end
+ private :cleanpath_conservative
+
+ # Returns the parent directory.
+ #
+ # This is same as <code>self + '..'</code>.
+ def parent
+ self + '..'
+ end
+
+ # Returns +true+ if +self+ points to a mountpoint.
+ def mountpoint?
+ begin
+ stat1 = self.lstat
+ stat2 = self.parent.lstat
+ stat1.dev != stat2.dev || stat1.ino == stat2.ino
+ rescue Errno::ENOENT
+ false
+ end
+ end
+
+ # The opposite of Pathname#absolute?
+ #
+ # It returns +false+ if the pathname begins with a slash.
+ #
+ # p = Pathname.new('/im/sure')
+ # p.relative?
+ # #=> false
+ #
+ # p = Pathname.new('not/so/sure')
+ # p.relative?
+ # #=> true
+ def relative?
+ !absolute?
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_filename {|component| ... } -> nil
+ # each_filename -> new_enumerator
+ #
+ # With a block given, yields each component of the string path:
+ #
+ # ```ruby
+ # Pathname('/foo/bar/baz').each_filename {|filename| p filename }
+ # => nil
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # "foo"
+ # "bar"
+ # "baz"
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
+ def each_filename # :yield: filename
+ return to_enum(__method__) unless block_given?
+ _, names = split_names(@path)
+ names.each {|filename| yield filename }
+ nil
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # descend {|entry| ... } -> nil
+ # descend -> new_enumerator
+ #
+ # With a block given, yields a new pathname for each successive dirname
+ # in the stored path; see File.dirname:
+ #
+ # ```ruby
+ # # Absolute path.
+ # Pathname('/path/to/some/file.rb').descend {|pn| p pn }
+ # # #<Pathname:/>
+ # # #<Pathname:/path>
+ # # #<Pathname:/path/to>
+ # # #<Pathname:/path/to/some>
+ # # #<Pathname:/path/to/some/file.rb>
+ # # Relative path.
+ # Pathname('path/to/some/file.rb').descend {|pn| p pn }
+ # # #<Pathname:path>
+ # # #<Pathname:path/to>
+ # # #<Pathname:path/to/some>
+ # # #<Pathname:path/to/some/file.rb>
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
+ def descend
+ return to_enum(__method__) unless block_given?
+ vs = []
+ ascend {|v| vs << v }
+ vs.reverse_each {|v| yield v }
+ nil
+ end
+
+ # call-seq:
+ # ascend {|entry| ... } -> nil
+ # ascend -> new_enumerator
+ #
+ # With a block given,
+ # yields +self+, then a new pathname for each successive dirname in the stored path;
+ # see File.dirname:
+ #
+ # Pathname('/path/to/some/file.rb').ascend {|dirname| p dirname}
+ # #<Pathname:/path/to/some/file.rb>
+ # #<Pathname:/path/to/some>
+ # #<Pathname:/path/to>
+ # #<Pathname:/path>
+ # #<Pathname:/>
+ #
+ # With no block given, returns a new Enumerator.
+ def ascend
+ return to_enum(__method__) unless block_given?
+ path = @path
+ yield self
+ while r = chop_basename(path)
+ path, = r
+ break if path.empty?
+ yield self.class.new(del_trailing_separator(path))
+ end
+ end
+
+ # call-seq:
+ # self + other -> new_pathname
+ #
+ # Returns a new \Pathname object based on the content of +self+ and +other+;
+ # argument +other+ may be a String, a File, a Dir, or another \Pathname:
+ #
+ # pn = Pathname('foo') # => #<Pathname:foo>
+ # pn + 'bar' # => #<Pathname:foo/bar>
+ # pn + File.new('LEGAL') # => #<Pathname:foo/LEGAL>
+ # pn + Dir.new('lib') # => #<Pathname:foo/lib>
+ # pn + Pathname('bar') # => #<Pathname:foo/bar>
+ #
+ # When +other+ specifies a relative path (see #relative?),
+ # it is combined with +self+ to form a new pathname:
+ #
+ # Pathname('/a/b') + 'c' # => #<Pathname:/a/b/c>
+ #
+ # Extra component separators (<tt>'/'</tt>) are removed:
+ #
+ # Pathname('/a/b/') + 'c' # => #<Pathname:/a/b/c>
+ #
+ # Extra current-directory components (<tt>'.'</tt>) are removed:
+ #
+ # Pathname('a') + '.' # => #<Pathname:a>
+ # Pathname('.') + 'a' # => #<Pathname:a>
+ # Pathname('.') + '.' # => #<Pathname:.>
+ #
+ # Parent-directory components (<tt>'..'</tt>) are:
+ #
+ # - Resolved, when possible:
+ #
+ # Pathname('a') + '..' # => #<Pathname:.>
+ # Pathname('a/b') + '..' # => #<Pathname:a>
+ # Pathname('/') + '../a' # => #<Pathname:/a>
+ # Pathname('a') + '../b' # => #<Pathname:b>
+ # Pathname('a/b') + '../c' # => #<Pathname:a/c>
+ # Pathname('a//b/c') + '../d//e' # => #<Pathname:a//b/d//e>
+ #
+ # - Removed, when not needed:
+ #
+ # Pathname('/') + '..' # => #<Pathname:/>
+ #
+ # - Retained, when needed:
+ #
+ # Pathname('..') + '..' # => #<Pathname:../..>
+ # Pathname('..') + '../a' # => #<Pathname:../../a>
+ #
+ # When +other+ specifies an absolute path (see #absolute?),
+ # equivalent to <tt>Pathname(other.to_s)</tt>:
+ #
+ # Pathname('/a') + '/b/c' # => #<Pathname:/b/c>
+ #
+ # Occurrences of <tt>'/'</tt>, <tt>'.'</tt>, and <tt>'..'</tt> are preserved:
+ #
+ # Pathname('/a') + '//b//c/./../d' # => #<Pathname://b//c/./../d>
+ #
+ # This method does not access the file system, so +other+ need not represent
+ # an existing (or even a valid) file or directory path:
+ #
+ # Pathname('/var') + 'nosuch:ever' # => #<Pathname:/var/nosuch:ever>
+ #
+ def +(other)
+ other = Pathname.new(other) unless Pathname === other
+ Pathname.new(plus(@path, other.path))
+ end
+ alias / +
+
+ # (path1, path2) -> path
+ def plus(path1, path2) # :nodoc:
+ prefix2 = path2
+ index_list2 = []
+ basename_list2 = []
+ while r2 = chop_basename(prefix2)
+ prefix2, basename2 = r2
+ index_list2.unshift prefix2.length
+ basename_list2.unshift basename2
+ end
+ return path2 if prefix2 != ''
+ prefix1 = path1
+ while true
+ while !basename_list2.empty? && basename_list2.first == '.'
+ index_list2.shift
+ basename_list2.shift
+ end
+ break unless r1 = chop_basename(prefix1)
+ prefix1, basename1 = r1
+ next if basename1 == '.'
+ if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
+ prefix1 = prefix1 + basename1
+ break
+ end
+ index_list2.shift
+ basename_list2.shift
+ end
+ r1 = chop_basename(prefix1)
+ if !r1 && (r1 = has_separator?(File.basename(prefix1)))
+ while !basename_list2.empty? && basename_list2.first == '..'
+ index_list2.shift
+ basename_list2.shift
+ end
+ end
+ if !basename_list2.empty?
+ suffix2 = path2[index_list2.first..-1]
+ r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
+ else
+ r1 ? prefix1 : File.dirname(prefix1)
+ end
+ end
+ private :plus
+
+ #
+ # Joins the given pathnames onto +self+ to create a new Pathname object.
+ # This is effectively the same as using Pathname#+ to append +self+ and
+ # all arguments sequentially.
+ #
+ # path0 = Pathname.new("/usr") # Pathname:/usr
+ # path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby
+ # # is the same as
+ # path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby
+ # path0 == path1
+ # #=> true
+ #
+ def join(*args)
+ return self if args.empty?
+ result = args.pop
+ result = Pathname.new(result) unless Pathname === result
+ return result if result.absolute?
+ args.reverse_each {|arg|
+ arg = Pathname.new(arg) unless Pathname === arg
+ result = arg + result
+ return result if result.absolute?
+ }
+ self + result
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # children(with_dirnames = true) -> array_of_pathnames
+ #
+ # Returns an array of pathnames;
+ # each represents a child of the entry represented by `self`,
+ # which must be an existing directory in the underlying file system.
+ #
+ # With `with_dirnames` given as `true` (the default),
+ # each pathname contains the full entry:
+ #
+ # ```ruby
+ # Pathname('lib').children.size # => 72
+ # Pathname('lib').children.take(3)
+ # # => [#<Pathname:lib/bundled_gems.rb>, #<Pathname:lib/bundler>, #<Pathname:lib/bundler.rb>]
+ # ```
+ # With `with_dirnames` given as `false`,
+ # each pathname contains only the basename of the entry:
+ #
+ # ```ruby
+ # Pathname('lib').children(false).take(3)
+ # # => [#<Pathname:bundled_gems.rb>, #<Pathname:bundler>, #<Pathname:bundler.rb>]
+ # ```
+ #
+ # Note that entries `.` and `..` in directory are not actually children,
+ # and so are never included in the result.
+ def children(with_directory=true)
+ with_directory = false if @path == '.'
+ result = Dir.children(@path)
+ if with_directory
+ result.map! {|e| self.class.new(File.join(@path, e))}
+ else
+ result.map! {|e| self.class.new(e)}
+ end
+ result
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_child(with_dirnames = true) {|entry| ... } -> array_of_pathnames
+ # each_child(with_dirnames = true) -> new_enumerator
+ #
+ # With a block given and `with_dirnames` given as `true` (the default),
+ # yields a new pathname for each child
+ # of the entry represented by `self`;
+ # returns an array of those pathnames:
+ #
+ # ```ruby
+ # Pathname('include').each_child {|child| p child }
+ # # #<Pathname:include/ruby>
+ # # #<Pathname:include/ruby.h>
+ # # => [#<Pathname:include/ruby>, #<Pathname:include/ruby.h>]
+ # ```
+ #
+ # With a block given and `with_dirnames` given as `false`,
+ # yields a new pathname for each child
+ # of the entry represented by `self` with its dirname omitted;
+ # returns an array of those pathnames:
+ #
+ # ```ruby
+ # Pathname('include').each_child(false) {|child| p child }
+ # # #<Pathname:ruby>
+ # # #<Pathname:ruby.h>
+ # # => [#<Pathname:ruby>, #<Pathname:ruby.h>]
+ # ```
+ #
+ # Note that entries `'.'` and `'..'` are not children.
+ #
+ # With no block given, returns a new Enumerator.
+ def each_child(with_directory=true, &b)
+ children(with_directory).each(&b)
+ end
+
+ #
+ # Returns a relative path from the given +base_directory+ to the receiver.
+ #
+ # If +self+ is absolute, then +base_directory+ must be absolute too.
+ #
+ # If +self+ is relative, then +base_directory+ must be relative too.
+ #
+ # This method doesn't access the filesystem. It assumes no symlinks.
+ #
+ # ArgumentError is raised when it cannot find a relative path.
+ #
+ # Note that this method does not handle situations where the case sensitivity
+ # of the filesystem in use differs from the operating system default.
+ #
+ def relative_path_from(base_directory)
+ base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
+ dest_directory = self.cleanpath.path
+ base_directory = base_directory.cleanpath.path
+ dest_prefix = dest_directory
+ dest_names = []
+ while r = chop_basename(dest_prefix)
+ dest_prefix, basename = r
+ dest_names.unshift basename if basename != '.'
+ end
+ base_prefix = base_directory
+ base_names = []
+ while r = chop_basename(base_prefix)
+ base_prefix, basename = r
+ base_names.unshift basename if basename != '.'
+ end
+ unless same_paths?(dest_prefix, base_prefix)
+ raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
+ end
+ while !dest_names.empty? &&
+ !base_names.empty? &&
+ same_paths?(dest_names.first, base_names.first)
+ dest_names.shift
+ base_names.shift
+ end
+ if base_names.include? '..'
+ raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
+ end
+ base_names.fill('..')
+ relpath_names = base_names + dest_names
+ if relpath_names.empty?
+ Pathname.new('.')
+ else
+ Pathname.new(File.join(*relpath_names))
+ end
+ end
+end
+
+class Pathname # * File *
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_line(sep = $/, **opts) {|line| ... } → nil
+ # each_line(limit, **opts) {|line| ... } → nil
+ # each_line(sep, limit, **opts) {|line| ... } → nil
+ # each_line(...) → new_enumerator
+ #
+ # With a block given, calls the block with each line
+ # from the file represented by `self`;
+ # returns `nil`:
+ #
+ # ```ruby
+ # lines = []
+ # Pathname('COPYING').each_line {|line| lines << line }
+ # lines.take(3)
+ # # =>
+ # # ["{日本語}[rdoc-ref:COPYING.ja]\n",
+ # # "\n",
+ # # "Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.\n"]
+ # ```
+ #
+ # The lines are read using IO.foreach,
+ # all arguments and options are passed to that method;
+ # see details at IO.foreach.
+ #
+ # With no block given, returns a new Enumerator.
+ def each_line(...) # :yield: line
+ File.foreach(@path, ...)
+ end
+
+ # call-seq:
+ # read(length = nil, offset = 0, **opts) -> string or nil
+ #
+ # Reads and returns some or all of the content of the file
+ # whose path is <tt>self.to_s</tt>.
+ #
+ # With no arguments given,
+ # reads in text mode and returns the entire content of the file:
+ #
+ # Pathname.new('t.txt').read
+ # # => "First line\nSecond line\n\nFourth line\nFifth line\n"
+ # Pathname.new('t.ja').read
+ # # => "こんにちは"
+ # Pathname.new('t.dat').read
+ # # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ #
+ # On Windows, text mode can terminate reading and leave bytes in the file unread
+ # when encountering certain special bytes.
+ # Consider using #binread if all bytes in the file should be read.
+ #
+ # With argument +length+ given, returns +length+ bytes if available:
+ #
+ # Pathname.new('t.txt').read(7)
+ # # => "First l"
+ # Pathname.new('t.ja').read(7)
+ # # => "\xE3\x81\x93\xE3\x82\x93\xE3"
+ # Pathname.new('t.dat').read(7)
+ # # => "\xFE\xFF\x99\x90\x99\x91\x99"
+ #
+ # Returns all bytes if +length+ is larger than the files size:
+ #
+ # Pathname.new('t.txt').read(700)
+ # # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
+ # Pathname.new('t.ja').read(700)
+ # # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
+ # Pathname.new('t.dat').read(700)
+ # # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ #
+ # With arguments +length+ and +offset+ given,
+ # returns +length+ bytes if available, beginning at the given +offset+:
+ #
+ # Pathname.new('t.txt').read(10, 2)
+ # # => "rst line\r\n"
+ # Pathname.new('t.ja').read(10, 2)
+ # # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
+ # Pathname.new('t.dat').read(10, 2)
+ # # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
+ #
+ # Returns +nil+ if +offset+ is past the end of the file:
+ #
+ # Pathname.new('t.txt').read(10, 200) # => nil
+ #
+ # Optional keyword arguments +opts+ specify:
+ #
+ # - {Open Options}[rdoc-ref:IO@Open+Options].
+ # - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
+ #
+ def read(...) File.read(@path, ...) end
+
+ # call-seq:
+ # binread(length = nil, offset = 0) -> string or nil
+ #
+ # Behaves like #read, except that the file is opened in binary mode
+ # with ASCII-8BIT encoding.
+ #
+ def binread(...) File.binread(@path, ...) end
+
+ # See <tt>File.readlines</tt>. Returns all the lines from the file.
+ def readlines(...) File.readlines(@path, ...) end
+
+ # See <tt>File.sysopen</tt>.
+ def sysopen(...) File.sysopen(@path, ...) end
+
+ # call-seq:
+ # write(data, offset = 0, **opts) -> nonnegative_integer
+ #
+ # Opens the file at +self.to_s+, writes the given +data+ to it,
+ # and closes the file; returns the number of bytes written.
+ #
+ # With only argument +data+ given, writes the given data to the file:
+ #
+ # path = 't.tmp'
+ # pn = Pathname.new(path)
+ # pn.write('foo') # => 3
+ # File.read(path) # => "foo"
+ #
+ # If +offset+ is zero (the default), the file is overwritten:
+ #
+ # pn.write('bar')
+ # File.read(path) # => "bar"
+ #
+ # If +offset+ in within the file content, the file is partly overwritten:
+ #
+ # pn.write('foobarbaz')
+ # pn.write('BAR', 3)
+ # File.read(path) # => "fooBARbaz"
+ #
+ # If +offset+ is outside the file content,
+ # the file is padded with null characters <tt>"\u0000"</tt>:
+ #
+ # pn.write('bat', 12)
+ # File.read(path) # => "fooBARbaz\u0000\u0000\u0000bat"
+ #
+ # Optional keyword arguments +opts+ specify:
+ #
+ # - {Open Options}[rdoc-ref:IO@Open+Options].
+ # - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
+ #
+ def write(...) File.write(@path, ...) end
+
+ # call-seq:
+ # binwrite(string, offset = 0, **opts) -> nonnegative_integer
+ #
+ # Behaves like #write, except that the file is opened in binary mode
+ # with ASCII-8BIT encoding.
+ def binwrite(...) File.binwrite(@path, ...) end
+
+ # call-seq:
+ # atime -> new_time
+ #
+ # Returns a new Time object containing the time of the most recent
+ # access (read or write) to the entry represented by `self`;
+ # see {File System Timestamps}[rdoc-ref:file/timestamps.md]:
+ #
+ # # Work in a temporary directory.
+ # require 'tmpdir'
+ # Dir.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # Dir.mkdir(dirpath)
+ # dir_pn = Pathname(dirpath)
+ # puts "Create directory; establishes atime for directory."
+ # puts " Directory atime: #{dir_pn.atime}"
+ # sleep(1)
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # puts "Create file; establishes atime for file, updates atime for directory."
+ # File.write(filepath, 'foo')
+ # file_pn = Pathname(filepath)
+ # puts " File atime: #{file_pn.atime}"
+ # puts " Directory atime: #{dir_pn.atime}"
+ # sleep(1)
+ # puts "Write file; updates atimes for file and directory."
+ # File.write(filepath, 'bar')
+ # puts " File atime: #{file_pn.atime}"
+ # puts " Directory atime: #{dir_pn.atime}"
+ # end
+ #
+ # Output:
+ #
+ # Create directory; establishes atime for directory.
+ # Directory atime: 2026-05-14 14:36:43 +0100
+ # Create file; establishes atime for file, updates atime for directory.
+ # File atime: 2026-05-14 14:36:44 +0100
+ # Directory atime: 2026-05-14 14:36:44 +0100
+ # Write file; updates atimes for file and directory.
+ # File atime: 2026-05-14 14:36:45 +0100
+ # Directory atime: 2026-05-14 14:36:45 +0100
+ #
+ def atime() File.atime(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # birthtime -> new_time
+ #
+ # Returns a new Time object containing the create time of the entry
+ # represented by `self`;
+ # see [File System Timestamps](rdoc-ref:file/timestamps.md):
+ #
+ # ```ruby
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # puts "Create directory; directory birthtime established."
+ # dir_pn.mkdir
+ # puts " Directory birthtime: #{dir_pn.birthtime}"
+ # sleep(1)
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # puts "Create file; file birthtime established; directory birthtime not updated."
+ # file_pn.write('foo')
+ # puts " File birthtime: #{file_pn.birthtime}"
+ # puts " Directory birthtime: #{dir_pn.birthtime}"
+ # sleep(1)
+ # puts "Write file; neither birthtime updated."
+ # file_pn.write('bar')
+ # puts " File birthtime: #{file_pn.birthtime}"
+ # puts " Directory birthtime: #{dir_pn.birthtime}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Create directory; directory birthtime established.
+ # Directory birthtime: 2026-05-14 23:41:12 +0100
+ # Create file; file birthtime established; directory birthtime not updated.
+ # File birthtime: 2026-05-14 23:41:13 +0100
+ # Directory birthtime: 2026-05-14 23:41:12 +0100
+ # Write file; neither birthtime updated.
+ # File birthtime: 2026-05-14 23:41:13 +0100
+ # Directory birthtime: 2026-05-14 23:41:12 +0100
+ # ```
+ #
+ def birthtime() File.birthtime(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # ctime -> new_time
+ #
+ # On Windows, returns the #birthtime.
+ #
+ # On other systems,
+ # returns a new Time object containing the time of the most recent
+ # metadata change to the entry represented by `self`;
+ # see {File System Timestamps}[rdoc-ref:file/timestamps.md]:
+ #
+ # ```ruby
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # puts "Create directory; directory ctime established."
+ # dir_pn.mkdir
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # sleep(1)
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # puts "Create file; file ctime established; directory ctime updated."
+ # file_pn.write('foo')
+ # puts " File ctime: #{file_pn.ctime}"
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # sleep(1)
+ # puts "Write file; file ctime updated; directory ctime not updated."
+ # file_pn.write('bar')
+ # puts " File ctime: #{file_pn.ctime}"
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # sleep(1)
+ # puts "Read file; neither ctime not updated."
+ # file_pn.read
+ # puts " File ctime: #{file_pn.ctime}"
+ # puts " Directory ctime: #{dir_pn.ctime}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Create directory; directory ctime established.
+ # Directory ctime: 2026-05-20 14:05:05 -0500
+ # Create file; file ctime established; directory ctime updated.
+ # File ctime: 2026-05-20 14:05:06 -0500
+ # Directory ctime: 2026-05-20 14:05:06 -0500
+ # Write file; file ctime updated; directory ctime not updated.
+ # File ctime: 2026-05-20 14:05:07 -0500
+ # Directory ctime: 2026-05-20 14:05:06 -0500
+ # Read file; neither ctime not updated.
+ # File ctime: 2026-05-20 14:05:07 -0500
+ # Directory ctime: 2026-05-20 14:05:06 -0500
+ # ```
+ #
+ def ctime() File.ctime(@path) end
+
+ # See <tt>File.mtime</tt>. Returns last modification time.
+ def mtime() File.mtime(@path) end
+
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # chmod(mode) -> 1
+ #
+ # Changes the mode (i.e., permissions) of the entry represented by `self`;
+ # see {File Permissions}[rdoc-ref:File@File+Permissions];
+ # returns `1`:
+ #
+ # ```ruby
+ # # A helper method to make an integer mode display as octal.
+ # def pretty(mode); '0' + (mode & 0777).to_s(8); end
+ #
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # dir_pn.mkdir
+ # # The directory mode.
+ # puts "Original directory mode: #{pretty(dir_pn.stat.mode)}"
+ # # Change the directory mode.
+ # dir_pn.chmod(0777)
+ # puts "New directory mode: #{pretty(dir_pn.stat.mode)}"
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # # Create the file.
+ # file_pn.write('foo')
+ # # The file mode.
+ # puts "Original file mode: #{pretty(file_pn.stat.mode)}"
+ # # Change the file modes.
+ # file_pn.chmod(0777)
+ # puts "New file mode: #{pretty(file_pn.stat.mode)}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Original directory mode: 0775
+ # New directory mode: 0777
+ # Original file mode: 0664
+ # New file mode: 0777
+ # ```
+ #
+ def chmod(mode) File.chmod(mode, @path) end
+
+ # See <tt>File.lchmod</tt>.
+ def lchmod(mode) File.lchmod(mode, @path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # chown(owner_id, group_id) -> 0
+ #
+ # Changes the owner and group of an entry (directory or file):
+ #
+ # ```ruby
+ # # Work in a temporary directory.
+ # Pathname.mktmpdir do |tmpdirpath|
+ # # A subdirectory therein, and its Pathname.
+ # dirpath = File.join(tmpdirpath, 'subdir')
+ # dir_pn = Pathname(dirpath)
+ # dir_pn.mkdir
+ # dir_stat = File.stat(dirpath)
+ # puts "Original directory owner: #{dir_stat.uid}"
+ # puts "Original directory group: #{dir_stat.gid}"
+ # dir_pn.chown(1000, 1000)
+ # dir_stat = File.stat(dirpath)
+ # puts "New directory owner: #{dir_stat.uid}"
+ # puts "New directory group: #{dir_stat.gid}"
+ #
+ # # A file in the subdirectory, and its Pathname.
+ # filepath = File.join(dirpath, 't.txt')
+ # file_pn = Pathname(filepath)
+ # # Create the file.
+ # file_pn.write('foo')
+ # file_stat = File.stat(filepath)
+ # puts "Original file owner: #{file_stat.uid}"
+ # puts "Original file group: #{file_stat.gid}"
+ # file_pn = Pathname(dirpath)
+ # file_pn.chown(1000, 1000)
+ # file_stat = File.stat(dirpath)
+ # puts "New file owner: #{file_stat.uid}"
+ # puts "New file group: #{file_stat.gid}"
+ # end
+ # ```
+ #
+ # Output:
+ #
+ # ```text
+ # Original directory owner: 0
+ # Original directory group: 0
+ # New directory owner: 1000
+ # New directory group: 1000
+ # Original file owner: 0
+ # Original file group: 0
+ # New file owner: 1000
+ # New file group: 1000
+ # ```
+ #
+ # Notes:
+ #
+ # - On Windows, the owner and group are not changed.
+ # - Only a process with superuser privileges can change the owner of an entry.
+ # - The owner of an entry can change its group to any group
+ # to which the owner belongs.
+ # - A +nil+ or +-1+ owner or group id is ignored.
+ # - The method follows symbolic links to the target entry.
+ #
+ def chown(owner, group) File.chown(owner, group, @path) end
+
+ # See <tt>File.lchown</tt>.
+ def lchown(owner, group) File.lchown(owner, group, @path) end
+
+ # See <tt>File.fnmatch</tt>. Return +true+ if the receiver matches the given
+ # pattern.
+ def fnmatch(pattern, ...) File.fnmatch(pattern, @path, ...) end
+
+ # See <tt>File.fnmatch?</tt> (same as #fnmatch).
+ def fnmatch?(pattern, ...) File.fnmatch?(pattern, @path, ...) end
+
+ # See <tt>File.ftype</tt>. Returns "type" of file ("file", "directory",
+ # etc).
+ def ftype() File.ftype(@path) end
+
+ # See <tt>File.link</tt>. Creates a hard link.
+ def make_link(old) File.link(old, @path) end
+
+ # See <tt>File.open</tt>. Opens the file for reading or writing.
+ def open(...) # :yield: file
+ File.open(@path, ...)
+ end
+
+ # See <tt>File.readlink</tt>. Read symbolic link.
+ def readlink() self.class.new(File.readlink(@path)) end
+
+ # See <tt>File.rename</tt>. Rename the file.
+ def rename(to) File.rename(@path, to) end
+
+ # See <tt>File.stat</tt>. Returns a <tt>File::Stat</tt> object.
+ def stat() File.stat(@path) end
+
+ # See <tt>File.lstat</tt>.
+ def lstat() File.lstat(@path) end
+
+ # See <tt>File.symlink</tt>. Creates a symbolic link.
+ def make_symlink(old) File.symlink(old, @path) end
+
+ # See <tt>File.truncate</tt>. Truncate the file to +length+ bytes.
+ def truncate(length) File.truncate(@path, length) end
+
+ # See <tt>File.utime</tt>. Update the access and modification times.
+ def utime(atime, mtime) File.utime(atime, mtime, @path) end
+
+ # Update the access and modification times of the file.
+ #
+ # Same as Pathname#utime, but does not follow symbolic links.
+ #
+ # See File.lutime.
+ def lutime(atime, mtime) File.lutime(atime, mtime, @path) end
+
+ # call-seq:
+ # basename(path, suffix = '') -> new_pathname
+ #
+ # Returns a new \Pathname object containing all or part of the last entry
+ # of the path represented by +self+.
+ # Entries are delimited by the value of constant File::SEPARATOR
+ # and, if non-nil, the value of constant File::ALT_SEPARATOR.
+ #
+ # When +suffix+ is the empty string <tt>''</tt>, returns all of the last entry:
+ #
+ # Pathname.new('foo/bar/baz/bat.txt').basename # => #<Pathname:bat.txt>
+ # Pathname.new('foo/bar/baz').basename # => #<Pathname:baz>
+ #
+ # File::SEPARATOR # => "/"
+ # Pathname.new('foo/bar.txt////').basename # => #<Pathname:bar.txt>
+ # File::ALT_SEPARATOR # => "\\" # On Windows.
+ # Pathname.new('foo/bar.txt//\\\\//').basename # => #<Pathname:bar.txt>
+ #
+ # When +suffix+ is <tt>'.*'</tt>,
+ # the last {filename extension}[https://en.wikipedia.org/wiki/Filename_extension],
+ # if any, is removed:
+ #
+ # Pathname.new('foo/bar.txt').basename('.*') # => #<Pathname:bar>
+ # Pathname.new('foo/bar.txt.old').basename('.*') # => #<Pathname:bar.txt>
+ # Pathname.new('foo/bar').basename('.*') # => #<Pathname:bar>
+ #
+ # When +suffix+ is any string other than <tt>''</tt> or <tt>'.*'</tt>,
+ # the matching trailing substring, if any, is removed:
+ #
+ # Pathname.new('foo/bar.txt').basename('.txt') # => #<Pathname:bar>
+ # Pathname.new('foo/bar.txt').basename('txt') # => #<Pathname:bar.>
+ # Pathname.new('foo/bar.txt').basename('*') # => #<Pathname:bar.txt>
+ # Pathname.new('foo/bar.txt').basename('.') # => #<Pathname:bar.txt>
+ #
+ def basename(...) self.class.new(File.basename(@path, ...)) end
+
+ # See <tt>File.dirname</tt>. Returns all but the last component of the path.
+ def dirname() self.class.new(File.dirname(@path)) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # extname -> extension
+ #
+ # Returns the filename extension of `self` --
+ # usually the portion of the string path beginning from the last period:
+ #
+ # ```ruby
+ # Pathname('t.rb').extname # => ".rb"
+ # Pathname('foo.bar.t.rb').extname # => ".rb"
+ # Pathname('foo/bar/t.rb').extname # => ".rb"
+ # Pathname('nosuch.txt').extname # => ".txt" # Path need not exist.
+ # ```
+ #
+ # Returns the entire string when there is no period:
+ #
+ # ```ruby
+ # Pathname('foo').extname # => ""
+ # ```
+ #
+ # Returns an empty string when the only period is the first character:
+ #
+ # ```ruby
+ # Pathname('.irbrc').extname # => ""
+ # ```
+ #
+ # Returns an empty string or `'.'` when `path` ends with a period:
+ #
+ # ```ruby
+ # Pathname('foo.').extname # => "" # On Windows.
+ # Pathname('foo.').extname # => "." # Elsewhere.
+ # Pathname('foo....').extname # => "" # On Windows.
+ # Pathname('foo....').extname # => "." # Elsewhere.
+ # ```
+ #
+ def extname() File.extname(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # expand_path(dirpath = '.') -> new_pathname
+ #
+ # Returns a new pathname containing the absolute path for `self`.
+ #
+ # Evaluates a relative path with respect to the directory given by `dirpath`:
+ #
+ # ```ruby
+ # Dir.chdir('/snap')
+ # # Default dirpath.
+ # Pathname('README').expand_path # => #<Pathname:/snap/README>
+ # Pathname('bin').expand_path # => #<Pathname:/snap/bin>
+ # Pathname('bin/../var').expand_path # => #<Pathname:/snap/var> # Cleaned.
+ # # Other dirpath.
+ # Pathname('../zip').expand_path('/usr/bin/ruby') # => #<Pathname:/usr/bin/zip>
+ # Dir.chdir('/usr/bin')
+ # Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap>
+ # ```
+ #
+ # Evaluates an absolute path without respect to `dirpath`:
+ #
+ # ```ruby
+ # Pathname('/snap').expand_path # => #<Pathname:/snap>
+ # Pathname('/snap').expand_path.expand_path('nosuch') # => #<Pathname:/snap>
+ # Pathname('/snap/../snap').expand_path # => #<Pathname:/snap> # Cleaned.
+ # ```
+ #
+ # More examples:
+ #
+ # ```
+ # Dir.chdir('/usr/bin')
+ # Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap>
+ # Pathname('../../snap').expand_path # => #<Pathname:/snap>
+ # ```
+ #
+ def expand_path(...) self.class.new(File.expand_path(@path, ...)) end
+
+ # See <tt>File.split</tt>. Returns the #dirname and the #basename in an
+ # Array.
+ def split()
+ array = File.split(@path)
+ raise TypeError, 'wrong argument type nil (expected Array)' unless Array === array
+ array.map {|f| self.class.new(f) }
+ end
+
+ # Returns the real (absolute) pathname for +self+ in the actual filesystem.
+ #
+ # Does not contain symlinks or useless dots, +..+ and +.+.
+ #
+ # All components of the pathname must exist when this method is called.
+ def realpath(...) self.class.new(File.realpath(@path, ...)) end
+
+ # Returns the real (absolute) pathname of +self+ in the actual filesystem.
+ #
+ # Does not contain symlinks or useless dots, +..+ and +.+.
+ #
+ # The last component of the real pathname can be nonexistent.
+ def realdirpath(...) self.class.new(File.realdirpath(@path, ...)) end
+end
+
+
+class Pathname # * FileTest *
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # blockdev? => true or false
+ #
+ # Returns whether `self` represents a path to a block device
+ # (i.e., a direct-access device):
+ #
+ # ```ruby
+ # Pathname('/dev/nvme0n1').blockdev? # => true
+ # Pathname('/dev/loop0').blockdev? # => true
+ # Pathname('/dev/tty').blockdev? # => false
+ # Pathname('/dev/null').blockdev? # => false
+ # Pathname('nosuch').blockdev? # => false
+ # Pathname($stdin).blockdev? # => false
+ # ```
+ #
+ # The returned value is OS-dependent; on Windows, almost always `false`.
+ def blockdev?() FileTest.blockdev?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # chardev? => true or false
+ #
+ # Returns whether `self` represents a path to a character device
+ # (i.e., a sequential-access device):
+ #
+ # ```ruby
+ # Pathname('/dev/tty').chardev? # => true
+ # Pathname('/dev/null').chardev? # => true
+ # Pathname('/dev/nvme0n1').chardev? # => false
+ # Pathname('/dev/loop0').chardev? # => false
+ # Pathname($stdin).chardev? # => false
+ # Pathname('nosuch').chardev? # => false
+ # ```
+ #
+ # The returned value is OS-dependent; on Windows, almost always `false`.
+ def chardev?() FileTest.chardev?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # empty? -> true or false
+ #
+ # Returns whether the entry represented by `self` exists and is empty:
+ #
+ # ```ruby
+ # dir_pn = Pathname('example_dir')
+ # dir_pn.empty? # => false # Dir does not exist.
+ # dir_pn.mkdir
+ # dir_pn.empty? # => true # Dir exists and is empty.
+ #
+ # file_pn = Pathname('example_dir/example.txt')
+ # file_pn.empty? # => false # File does not exist.
+ # file_pn.write('')
+ # file_pn.empty? # => true # File exists and is empty.
+ # dir_pn.empty? # => false # Dir exists and is not empty.
+ # file_pn.write('foo')
+ # file_pn.empty? # => false # File exists and is not empty.
+ #
+ # file_pn.delete
+ # dir_pn.delete
+ # ```
+ #
+ def empty?
+ if FileTest.directory?(@path)
+ Dir.empty?(@path)
+ else
+ File.empty?(@path)
+ end
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # executable? -> true or false
+ #
+ # Returns whether the entry represented by `self` is executable;
+ # calls FileTest.executable? with argument `self.to_s`:
+ #
+ # ```ruby
+ # Pathname('bin/gem').executable? # => true
+ # Pathname('README.md').executable? # => false
+ # ```
+ #
+ def executable?() FileTest.executable?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # executable_real? -> true or false
+ #
+ # Returns whether the entry represented by `self` is executable
+ # by the real user and group id of the current process;
+ # calls FileTest.executable_real? with argument `self.to_s`:
+ #
+ # ```ruby
+ # pn = Pathname('example')
+ # pn.write('')
+ # pn.executable_real? # => false
+ # pn.chmod(0100)
+ # pn.executable_real? # => true
+ # ```
+ #
+ def executable_real?() FileTest.executable_real?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # exist? -> true or false
+ #
+ # Returns whether the entry represented by `self` exists:
+ #
+ # ```ruby
+ # Pathname('.').exist? # => true
+ # Pathname('README.md').exist? # => true
+ # Pathname('nosuch').exist? # => false
+ # ```
+ #
+ def exist?() FileTest.exist?(@path) end
+
+ # See <tt>FileTest.grpowned?</tt>.
+ def grpowned?() FileTest.grpowned?(@path) end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # directory? -> true or false
+ #
+ # Returns whether the entry represented by `self` is a directory:
+ #
+ # ```ruby
+ # Pathname('/etc').directory? # => true
+ # Pathname('lib').directory? # => true
+ # Pathname('README.md').directory? # => false
+ # Pathname('nosuch').directory? # => false
+ # ```
+ #
+ def directory?() FileTest.directory?(@path) end
+
+ # See <tt>FileTest.file?</tt>.
+ def file?() FileTest.file?(@path) end
+
+ # See <tt>FileTest.pipe?</tt>.
+ def pipe?() FileTest.pipe?(@path) end
+
+ # See <tt>FileTest.socket?</tt>.
+ def socket?() FileTest.socket?(@path) end
+
+ # See <tt>FileTest.owned?</tt>.
+ def owned?() FileTest.owned?(@path) end
+
+ # See <tt>FileTest.readable?</tt>.
+ def readable?() FileTest.readable?(@path) end
+
+ # See <tt>FileTest.world_readable?</tt>.
+ def world_readable?() File.world_readable?(@path) end
+
+ # See <tt>FileTest.readable_real?</tt>.
+ def readable_real?() FileTest.readable_real?(@path) end
+
+ # See <tt>FileTest.setuid?</tt>.
+ def setuid?() FileTest.setuid?(@path) end
+
+ # See <tt>FileTest.setgid?</tt>.
+ def setgid?() FileTest.setgid?(@path) end
+
+ # See <tt>FileTest.size</tt>.
+ def size() FileTest.size(@path) end
+
+ # See <tt>FileTest.size?</tt>.
+ def size?() FileTest.size?(@path) end
+
+ # See <tt>FileTest.sticky?</tt>.
+ def sticky?() FileTest.sticky?(@path) end
+
+ # See <tt>FileTest.symlink?</tt>.
+ def symlink?() FileTest.symlink?(@path) end
+
+ # See <tt>FileTest.writable?</tt>.
+ def writable?() FileTest.writable?(@path) end
+
+ # See <tt>FileTest.world_writable?</tt>.
+ def world_writable?() File.world_writable?(@path) end
+
+ # See <tt>FileTest.writable_real?</tt>.
+ def writable_real?() FileTest.writable_real?(@path) end
+
+ # See <tt>FileTest.zero?</tt>.
+ def zero?() FileTest.zero?(@path) end
+end
+
+
+class Pathname # * Dir *
+ # call-seq:
+ # glob(patterns, **kwargs) → array_of_pathnames
+ # glob(patterns, **kwargs) {|pathname| ... } → nil
+ #
+ # Calls <tt>Dir.glob(patterns, **kwargs)</tt>, which yields or returns entry names;
+ # see Dir.glob.
+ #
+ # Required argument +patterns+ is a string pattern or an array of string patterns;
+ # note that these patterns are not regexps.
+ #
+ # Keyword arguments <tt>**kwargs</tt> are passed through to Dir.glob;
+ # see the documentation there.
+ #
+ # With no block given, returns an array of \Pathname objects;
+ # each is <tt>Pathname.new(entry_name)</tt> for an entry name returned by Dir.glob.
+ #
+ # Pathname.glob('*').take(3)
+ # # => [#<Pathname:BSDL>, #<Pathname:CONTRIBUTING.md>, #<Pathname:COPYING>]
+ # Pathname.glob(['o*', 'a*']).take(3)
+ # # => [#<Pathname:object.c>, #<Pathname:aclocal.m4>, #<Pathname:addr2line.c>]
+ #
+ # With a block given, calls the block with each pathname
+ # <tt>Pathname.new(entry_name)</tt>,
+ # where each +entry_name+ is a \Pathname object created by the value yielded by Dir.glob.
+ #
+ # a = []
+ # Pathname.glob(['o*', 'a*']) {|pathname| a << pathname }
+ # a.take(3)
+ # # => [#<Pathname:object.c>, #<Pathname:aclocal.m4>, #<Pathname:addr2line.c>]
+ #
+ # Optional keyword argument +base+ is of particular interest.
+ # When it is given, its value specifies the base directory for the pathnames;
+ # each pattern string specifies entries relative to the base directory:
+ #
+ # Pathname.glob('*', base: 'lib').take(2)
+ # # => [#<Pathname:English.gemspec>, #<Pathname:English.rb>]
+ # Pathname.glob('*', base: 'lib/bundler').take(2)
+ # # => [#<Pathname:build_metadata.rb>, #<Pathname:bundler.gemspec>]
+ #
+ # Note that the base directory is not prepended to the entry names in the result.
+ def Pathname.glob(*args, **kwargs) # :yield: pathname
+ if block_given?
+ Dir.glob(*args, **kwargs) {|f| yield self.new(f) }
+ else
+ Dir.glob(*args, **kwargs).map {|f| self.new(f) }
+ end
+ end
+
+ # Returns or yields Pathname objects.
+ #
+ # Pathname("ruby-2.4.2").glob("R*.md")
+ # #=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
+ #
+ # See Dir.glob.
+ # This method uses the +base+ keyword argument of Dir.glob.
+ def glob(*args, **kwargs) # :yield: pathname
+ if block_given?
+ Dir.glob(*args, **kwargs, base: @path) {|f| yield self + f }
+ else
+ Dir.glob(*args, **kwargs, base: @path).map {|f| self + f }
+ end
+ end
+
+ # call-seq:
+ # Pathname.getwd -> new_pathname
+ #
+ # Returns a new \Pathname object containing the path to the current working directory
+ # (equivalent to <tt>Pathname.new(Dir.getwd)</tt>):
+ #
+ # Pathname.getwd # => #<Pathname:/home>
+ #
+ def Pathname.getwd() self.new(Dir.getwd) end
+ class << self
+ alias pwd getwd
+ end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # entries -> array_of_pathnames
+ #
+ # Returns an array of pathnames,
+ # one for each entry in the directory represented by `self`:
+ #
+ # ```ruby
+ # Pathname('.').entries.take(5)
+ # # =>
+ # # [#<Pathname:.>,
+ # # #<Pathname:..>,
+ # # #<Pathname:gc.rb>,
+ # # #<Pathname:yjit.rb>,
+ # # #<Pathname:iseq.h>]
+ # ```
+ #
+ def entries() Dir.entries(@path).map {|f| self.class.new(f) } end
+
+ # :markup: markdown
+ #
+ # call-seq:
+ # each_entry {|entry| ... } -> nil
+ # each_entry -> new_enumerator
+ #
+ # With a block given,
+ # yields a new pathname for each entry
+ # in the entry represented by `self`;
+ # returns `nil`:
+ #
+ # ```ruby
+ # Pathname('include').each_entry {|entry| p entry }
+ # # #<Pathname:ruby>
+ # # #<Pathname:..>
+ # # #<Pathname:ruby.h>
+ # # #<Pathname:.>
+ # # => nil
+ # ```
+ #
+ # With no block given, returns a new Enumerator.
+ def each_entry(&block) # :yield: pathname
+ return to_enum(__method__) unless block_given?
+ Dir.foreach(@path) {|f| yield self.class.new(f) }
+ end
+
+ # See <tt>Dir.mkdir</tt>. Create the referenced directory.
+ def mkdir(...) Dir.mkdir(@path, ...) end
+
+ # See <tt>Dir.rmdir</tt>. Remove the referenced directory.
+ def rmdir() Dir.rmdir(@path) end
+
+ # See <tt>Dir.open</tt>.
+ def opendir(&block) # :yield: dir
+ Dir.open(@path, &block)
+ end
+end
+
+class Pathname # * mixed *
+ #
+ # :markup: markdown
+ #
+ # call-seq:
+ # unlink -> 1 or 0
+ #
+ # Removes the file or directory represented by `self`, using:
+ #
+ # - File.unlink, if `self` represents a file; returns `1`.
+ # - Dir.unlink, if `self` represents a directory; returns `0`.
+ #
+ # Examples:
+ #
+ # ```ruby
+ # Pathname(Tempfile.create).unlink # => 1
+ # Pathname(Pathname.mktmpdir).unlink # => 0
+ # ```
+ #
+ def unlink()
+ Dir.unlink @path
+ rescue Errno::ENOTDIR
+ File.unlink @path
+ end
+ alias delete unlink
+end
+
+class Pathname
+ undef =~ if Kernel.method_defined?(:=~)
+end
+
+module Kernel
+ # Creates a Pathname object.
+ def Pathname(path) # :doc:
+ return path if Pathname === path
+ Pathname.new(path)
+ end
+ module_function :Pathname
+end
diff --git a/prelude.rb b/prelude.rb
index a9e2f155fb..b6c610dd58 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -1,13 +1,18 @@
class Binding
# :nodoc:
def irb(...)
+ suppress = Thread.current[:__bundled_gems_warning_suppression]
+ Thread.current[:__bundled_gems_warning_suppression] = ['reline', 'rdoc']
+
begin
require 'irb'
rescue LoadError, Gem::LoadError
Gem::BUNDLED_GEMS.force_activate 'irb'
- retry
+ require 'irb'
end
irb(...)
+ ensure
+ Thread.current[:__bundled_gems_warning_suppression] = suppress
end
# suppress redefinition warning
@@ -15,22 +20,22 @@ class Binding
end
module Kernel
+ # :stopdoc:
def pp(*objs)
require 'pp'
pp(*objs)
end
# suppress redefinition warning
- alias pp pp # :nodoc:
+ alias pp pp
private :pp
+ # :startdoc:
end
-autoload :Set, 'set'
-
module Enumerable
# Makes a set from the enumerable object with given arguments.
- def to_set(klass = Set, *args, &block)
- klass.new(self, *args, &block)
+ def to_set(&block)
+ Set.new(self, &block)
end
end
diff --git a/prism/api_pack.c b/prism/api_pack.c
deleted file mode 100644
index 98509ae65c..0000000000
--- a/prism/api_pack.c
+++ /dev/null
@@ -1,276 +0,0 @@
-#include "prism/extension.h"
-
-#ifdef PRISM_EXCLUDE_PACK
-
-void
-Init_prism_pack(void) {}
-
-#else
-
-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"));
-}
-
-#endif
diff --git a/prism/arena.c b/prism/arena.c
new file mode 100644
index 0000000000..64a731649d
--- /dev/null
+++ b/prism/arena.c
@@ -0,0 +1,117 @@
+#include "prism/internal/arena.h"
+
+#include "prism/internal/allocator.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Compute the block allocation size using offsetof so it is correct regardless
+ * of PM_FLEX_ARRAY_LENGTH.
+ */
+#define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size))
+
+/** Initial block data size: 8 KB. */
+#define PM_ARENA_INITIAL_SIZE 8192
+
+/** Double the block size every this many blocks. */
+#define PM_ARENA_GROWTH_INTERVAL 8
+
+/** Maximum block data size: 1 MB. */
+#define PM_ARENA_MAX_SIZE (1024 * 1024)
+
+/**
+ * Compute the data size for the next block.
+ */
+static size_t
+pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
+ size_t size = PM_ARENA_INITIAL_SIZE;
+
+ for (size_t exp = PM_ARENA_GROWTH_INTERVAL; exp <= arena->block_count; exp += PM_ARENA_GROWTH_INTERVAL) {
+ if (size < PM_ARENA_MAX_SIZE) size *= 2;
+ }
+
+ return size > min_size ? size : min_size;
+}
+
+/**
+ * Allocate a new block with the given data capacity and initial usage, link it
+ * into the arena, and return it. Aborts on allocation failure.
+ */
+static pm_arena_block_t *
+pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) {
+ assert(initial_used <= data_size);
+ pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size));
+
+ if (block == NULL) {
+ fprintf(stderr, "prism: out of memory; aborting\n");
+ abort();
+ }
+
+ block->capacity = data_size;
+ block->used = initial_used;
+ block->prev = arena->current;
+ arena->current = block;
+ arena->block_count++;
+
+ return block;
+}
+
+/**
+ * Ensure the arena has at least `capacity` bytes available in its current
+ * block, allocating a new block if necessary. This allows callers to
+ * pre-size the arena to avoid repeated small block allocations.
+ */
+void
+pm_arena_reserve(pm_arena_t *arena, size_t capacity) {
+ if (capacity <= PM_ARENA_INITIAL_SIZE) return;
+ if (arena->current != NULL && (arena->current->capacity - arena->current->used) >= capacity) return;
+ pm_arena_block_new(arena, capacity, 0);
+}
+
+/**
+ * Slow path for pm_arena_alloc: allocate a new block and return a pointer to
+ * the first `size` bytes. Called when the current block has insufficient space.
+ */
+void *
+pm_arena_alloc_slow(pm_arena_t *arena, size_t size) {
+ size_t block_data_size = pm_arena_next_block_size(arena, size);
+ pm_arena_block_t *block = pm_arena_block_new(arena, block_data_size, size);
+ return block->data;
+}
+
+/**
+ * Returns a newly allocated and initialized arena.
+ */
+pm_arena_t *
+pm_arena_new(void) {
+ pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t));
+ if (arena == NULL) abort();
+ return arena;
+}
+
+/**
+ * Free all blocks in the arena.
+ */
+void
+pm_arena_cleanup(pm_arena_t *arena) {
+ pm_arena_block_t *block = arena->current;
+
+ while (block != NULL) {
+ pm_arena_block_t *prev = block->prev;
+ xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity));
+ block = prev;
+ }
+
+ *arena = (pm_arena_t) { 0 };
+}
+
+/**
+ * Frees both the held memory and the arena itself.
+ */
+void
+pm_arena_free(pm_arena_t *arena) {
+ pm_arena_cleanup(arena);
+ xfree_sized(arena, sizeof(pm_arena_t));
+}
diff --git a/prism/arena.h b/prism/arena.h
new file mode 100644
index 0000000000..e1fa8fc6ad
--- /dev/null
+++ b/prism/arena.h
@@ -0,0 +1,37 @@
+/**
+ * @file arena.h
+ *
+ * A bump allocator for the prism parser.
+ */
+#ifndef PRISM_ARENA_H
+#define PRISM_ARENA_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+
+/**
+ * An opaque pointer to an arena that is used for allocations.
+ */
+typedef struct pm_arena_t pm_arena_t;
+
+/**
+ * Returns a newly allocated and initialized arena. If the arena cannot be
+ * allocated, this function aborts the process.
+ *
+ * @returns A pointer to the newly allocated arena. It is the responsibility of
+ * the caller to free the arena using pm_arena_free when it is no longer
+ * needed.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_arena_t * pm_arena_new(void);
+
+/**
+ * Frees both the held memory and the arena itself.
+ *
+ * @param arena The arena to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_arena_free(pm_arena_t *arena) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/buffer.c b/prism/buffer.c
new file mode 100644
index 0000000000..cb3b9a4fe8
--- /dev/null
+++ b/prism/buffer.c
@@ -0,0 +1,374 @@
+#include "prism/internal/buffer.h"
+
+#include "prism/compiler/inline.h"
+
+#include "prism/internal/char.h"
+#include "prism/internal/allocator.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Initialize a pm_buffer_t with the given capacity.
+ */
+void
+pm_buffer_init(pm_buffer_t *buffer, size_t capacity) {
+ buffer->length = 0;
+ buffer->capacity = capacity;
+
+ buffer->value = (char *) xmalloc(capacity);
+ if (buffer->value == NULL) abort();
+}
+
+/**
+ * Allocate and initialize a new buffer.
+ */
+pm_buffer_t *
+pm_buffer_new(void) {
+ pm_buffer_t *buffer = (pm_buffer_t *) xmalloc(sizeof(pm_buffer_t));
+ if (buffer == NULL) abort();
+
+ pm_buffer_init(buffer, 1024);
+ return buffer;
+}
+
+/**
+ * Return the value of the buffer.
+ */
+char *
+pm_buffer_value(const pm_buffer_t *buffer) {
+ return buffer->value;
+}
+
+/**
+ * Return the length of the buffer.
+ */
+size_t
+pm_buffer_length(const pm_buffer_t *buffer) {
+ return buffer->length;
+}
+
+/**
+ * Append the given amount of space to the buffer.
+ */
+static PRISM_INLINE bool
+pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
+ size_t next_length = buffer->length + length;
+ const size_t original_capacity = buffer->capacity;
+
+ if (next_length > buffer->capacity) {
+ if (buffer->capacity == 0) {
+ buffer->capacity = 1;
+ }
+
+ while (next_length > buffer->capacity) {
+ buffer->capacity *= 2;
+ }
+
+ buffer->value = xrealloc_sized(buffer->value, buffer->capacity, original_capacity);
+ if (buffer->value == NULL) return false;
+ }
+
+ buffer->length = next_length;
+ return true;
+}
+
+/**
+ * Append a generic pointer to memory to the buffer.
+ */
+static PRISM_INLINE void
+pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) {
+ size_t cursor = buffer->length;
+ if (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;
+ if (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;
+ if (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);
+}
+
+/**
+ * Append a double to the buffer.
+ */
+void
+pm_buffer_append_double(pm_buffer_t *buffer, double value) {
+ const void *source = &value;
+ pm_buffer_append(buffer, source, sizeof(double));
+}
+
+/**
+ * Append a unicode codepoint to the buffer.
+ */
+bool
+pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value) {
+ if (value <= 0x7F) {
+ pm_buffer_append_byte(buffer, (uint8_t) value); // 0xxxxxxx
+ return true;
+ } else if (value <= 0x7FF) {
+ uint8_t bytes[] = {
+ (uint8_t) (0xC0 | ((value >> 6) & 0x3F)), // 110xxxxx
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
+ };
+
+ pm_buffer_append_bytes(buffer, bytes, 2);
+ return true;
+ } else if (value <= 0xFFFF) {
+ uint8_t bytes[] = {
+ (uint8_t) (0xE0 | ((value >> 12) & 0x3F)), // 1110xxxx
+ (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
+ };
+
+ pm_buffer_append_bytes(buffer, bytes, 3);
+ return true;
+ } else if (value <= 0x10FFFF) {
+ uint8_t bytes[] = {
+ (uint8_t) (0xF0 | ((value >> 18) & 0x3F)), // 11110xxx
+ (uint8_t) (0x80 | ((value >> 12) & 0x3F)), // 10xxxxxx
+ (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
+ };
+
+ pm_buffer_append_bytes(buffer, bytes, 4);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Append a slice of source code to the buffer.
+ */
+void
+pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
+ for (size_t index = 0; index < length; index++) {
+ const uint8_t byte = source[index];
+
+ if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
+ if (escaping == PM_BUFFER_ESCAPING_RUBY) {
+ pm_buffer_append_format(buffer, "\\x%02X", byte);
+ } else {
+ pm_buffer_append_format(buffer, "\\u%04X", byte);
+ }
+ } else {
+ switch (byte) {
+ case '\a':
+ if (escaping == PM_BUFFER_ESCAPING_RUBY) {
+ pm_buffer_append_string(buffer, "\\a", 2);
+ } else {
+ pm_buffer_append_format(buffer, "\\u%04X", byte);
+ }
+ break;
+ case '\b':
+ pm_buffer_append_string(buffer, "\\b", 2);
+ break;
+ case '\t':
+ pm_buffer_append_string(buffer, "\\t", 2);
+ break;
+ case '\n':
+ pm_buffer_append_string(buffer, "\\n", 2);
+ break;
+ case '\v':
+ if (escaping == PM_BUFFER_ESCAPING_RUBY) {
+ pm_buffer_append_string(buffer, "\\v", 2);
+ } else {
+ pm_buffer_append_format(buffer, "\\u%04X", byte);
+ }
+ break;
+ case '\f':
+ pm_buffer_append_string(buffer, "\\f", 2);
+ break;
+ case '\r':
+ pm_buffer_append_string(buffer, "\\r", 2);
+ break;
+ case '"':
+ pm_buffer_append_string(buffer, "\\\"", 2);
+ break;
+ case '#': {
+ if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
+ const uint8_t next_byte = source[index + 1];
+ if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
+ pm_buffer_append_byte(buffer, '\\');
+ }
+ }
+
+ pm_buffer_append_byte(buffer, '#');
+ break;
+ }
+ case '\\':
+ pm_buffer_append_string(buffer, "\\\\", 2);
+ break;
+ default:
+ pm_buffer_append_byte(buffer, byte);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Prepend the given string to the buffer.
+ */
+void
+pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
+ size_t cursor = buffer->length;
+ if (pm_buffer_append_length(buffer, length)) {
+ memmove(buffer->value + length, buffer->value, cursor);
+ memcpy(buffer->value, value, length);
+ }
+}
+
+/**
+ * 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);
+ }
+}
+
+/**
+ * Clear the buffer by reducing its size to 0. This does not free the allocated
+ * memory, but it does allow the buffer to be reused.
+ */
+void
+pm_buffer_clear(pm_buffer_t *buffer) {
+ buffer->length = 0;
+}
+
+/**
+ * Strip the whitespace from the end of the buffer.
+ */
+void
+pm_buffer_rstrip(pm_buffer_t *buffer) {
+ while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
+ buffer->length--;
+ }
+}
+
+/**
+ * Checks if the buffer includes the given value.
+ */
+size_t
+pm_buffer_index(const pm_buffer_t *buffer, char value) {
+ const char *first = memchr(buffer->value, value, buffer->length);
+ return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
+}
+
+/**
+ * Insert the given string into the buffer at the given index.
+ */
+void
+pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
+ assert(index <= buffer->length);
+
+ if (index == buffer->length) {
+ pm_buffer_append_string(buffer, value, length);
+ } else {
+ pm_buffer_append_zeroes(buffer, length);
+ memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
+ memcpy(buffer->value + index, value, length);
+ }
+}
+
+/**
+ * Free the memory held by the buffer.
+ */
+void
+pm_buffer_cleanup(pm_buffer_t *buffer) {
+ xfree_sized(buffer->value, buffer->capacity);
+}
+
+/**
+ * Free both the memory held by the buffer and the buffer itself.
+ */
+void
+pm_buffer_free(pm_buffer_t *buffer) {
+ pm_buffer_cleanup(buffer);
+ xfree_sized(buffer, sizeof(pm_buffer_t));
+}
diff --git a/prism/buffer.h b/prism/buffer.h
new file mode 100644
index 0000000000..24b572d2c3
--- /dev/null
+++ b/prism/buffer.h
@@ -0,0 +1,52 @@
+/**
+ * @file buffer.h
+ *
+ * A wrapper around a contiguous block of allocated memory.
+ */
+#ifndef PRISM_BUFFER_H
+#define PRISM_BUFFER_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+
+/**
+ * A wrapper around a contiguous block of allocated memory.
+ */
+typedef struct pm_buffer_t pm_buffer_t;
+
+/**
+ * Allocate and initialize a new buffer. If the buffer cannot be allocated, this
+ * function will abort the process.
+ *
+ * @returns A pointer to the initialized buffer. The caller is responsible for
+ * freeing the buffer with pm_buffer_free.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_buffer_t * pm_buffer_new(void);
+
+/**
+ * Free both the memory held by the buffer and the buffer itself.
+ *
+ * @param buffer The buffer to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer) PRISM_NONNULL(1);
+
+/**
+ * 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(const pm_buffer_t *buffer) PRISM_NONNULL(1);
+
+/**
+ * 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(const pm_buffer_t *buffer) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/char.c b/prism/char.c
new file mode 100644
index 0000000000..08e457aa1f
--- /dev/null
+++ b/prism/char.c
@@ -0,0 +1,274 @@
+#include "prism/internal/char.h"
+
+#include "prism/compiler/inline.h"
+#include "prism/internal/line_offset_list.h"
+
+#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)
+
+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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 4x
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 5x
+ 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 6x
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 PRISM_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_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset) {
+ if (length <= 0) return 0;
+
+ uint32_t size = 0;
+ uint32_t maximum = (uint32_t) length;
+
+ while (size < maximum && (pm_byte_table[string[size]] & PRISM_CHAR_BIT_WHITESPACE)) {
+ if (string[size] == '\n') {
+ pm_line_offset_list_append(arena, line_offsets, start_offset + size + 1);
+ }
+
+ size++;
+ }
+
+ return size;
+}
+
+/**
+ * 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);
+}
+
+
+/**
+ * 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 PRISM_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 PRISM_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 (size > 0 && 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 PRISM_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);
+}
diff --git a/prism/comments.h b/prism/comments.h
new file mode 100644
index 0000000000..2270d53889
--- /dev/null
+++ b/prism/comments.h
@@ -0,0 +1,43 @@
+/**
+ * @file comments.h
+ *
+ * Types and functions related to comments found during parsing.
+ */
+#ifndef PRISM_COMMENTS_H
+#define PRISM_COMMENTS_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+
+#include <stddef.h>
+
+/** 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;
+
+/** An opaque pointer to a comment found while parsing. */
+typedef struct pm_comment_t pm_comment_t;
+
+/**
+ * Returns the location associated with the given comment.
+ *
+ * @param comment the comment whose location we want to get
+ * @returns the location associated with the given comment
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_comment_location(const pm_comment_t *comment) PRISM_NONNULL(1);
+
+/**
+ * Returns the type associated with the given comment.
+ *
+ * @param comment the comment whose type we want to get
+ * @returns the type associated with the given comment. This can either be
+ * PM_COMMENT_INLINE or PM_COMMENT_EMBDOC.
+ */
+PRISM_EXPORTED_FUNCTION pm_comment_type_t pm_comment_type(const pm_comment_t *comment) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/compiler/accel.h b/prism/compiler/accel.h
new file mode 100644
index 0000000000..be23236d1d
--- /dev/null
+++ b/prism/compiler/accel.h
@@ -0,0 +1,19 @@
+/**
+ * @file compiler/accel.h
+ */
+#ifndef PRISM_COMPILER_ACCEL_H
+#define PRISM_COMPILER_ACCEL_H
+
+/**
+ * Platform detection for SIMD/fast-path implementations. At most one of these
+ * macros is defined, selecting the best available vectorization strategy.
+ */
+#if (defined(__aarch64__) && defined(__ARM_NEON)) || (defined(_MSC_VER) && defined(_M_ARM64))
+# define PRISM_HAS_NEON
+#elif (defined(__x86_64__) && defined(__SSSE3__)) || (defined(_MSC_VER) && defined(_M_X64))
+# define PRISM_HAS_SSSE3
+#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define PRISM_HAS_SWAR
+#endif
+
+#endif
diff --git a/prism/compiler/align.h b/prism/compiler/align.h
new file mode 100644
index 0000000000..22cb49a48c
--- /dev/null
+++ b/prism/compiler/align.h
@@ -0,0 +1,36 @@
+/**
+ * @file compiler/align.h
+ */
+#ifndef PRISM_COMPILER_ALIGN_H
+#define PRISM_COMPILER_ALIGN_H
+
+/**
+ * Compiler-agnostic macros for specifying alignment of types and variables.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L /* C11 or later */
+ /** Specify alignment for a type or variable. */
+ #define PRISM_ALIGNAS _Alignas
+
+ /** Get the alignment requirement of a type. */
+ #define PRISM_ALIGNOF _Alignof
+#elif defined(__GNUC__) || defined(__clang__)
+ /** Specify alignment for a type or variable. */
+ #define PRISM_ALIGNAS(size) __attribute__((aligned(size)))
+
+ /** Get the alignment requirement of a type. */
+ #define PRISM_ALIGNOF(type) __alignof__(type)
+#elif defined(_MSC_VER)
+ /** Specify alignment for a type or variable. */
+ #define PRISM_ALIGNAS(size) __declspec(align(size))
+
+ /** Get the alignment requirement of a type. */
+ #define PRISM_ALIGNOF(type) __alignof(type)
+#else
+ /** Void because this platform does not support specifying alignment. */
+ #define PRISM_ALIGNAS(size)
+
+ /** Fallback to sizeof as alignment requirement of a type. */
+ #define PRISM_ALIGNOF(type) sizeof(type)
+#endif
+
+#endif
diff --git a/prism/compiler/exported.h b/prism/compiler/exported.h
new file mode 100644
index 0000000000..823773ecbb
--- /dev/null
+++ b/prism/compiler/exported.h
@@ -0,0 +1,24 @@
+/**
+ * @file compiler/exported.h
+ */
+#ifndef PRISM_COMPILER_EXPORTED_H
+#define PRISM_COMPILER_EXPORTED_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
+
+#endif
diff --git a/prism/compiler/fallthrough.h b/prism/compiler/fallthrough.h
new file mode 100644
index 0000000000..ce1b450e8a
--- /dev/null
+++ b/prism/compiler/fallthrough.h
@@ -0,0 +1,22 @@
+/**
+ * @file compiler/fallthrough.h
+ */
+#ifndef PRISM_COMPILER_FALLTHROUGH_H
+#define PRISM_COMPILER_FALLTHROUGH_H
+
+/**
+ * We use -Wimplicit-fallthrough to guard potentially unintended fall-through
+ * between cases of a switch. Use PRISM_FALLTHROUGH to explicitly annotate cases
+ * where the fallthrough is intentional.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L /* C23 or later */
+ #define PRISM_FALLTHROUGH [[fallthrough]];
+#elif defined(__GNUC__) || defined(__clang__)
+ #define PRISM_FALLTHROUGH __attribute__((fallthrough));
+#elif defined(_MSC_VER)
+ #define PRISM_FALLTHROUGH __fallthrough;
+#else
+ #define PRISM_FALLTHROUGH
+#endif
+
+#endif
diff --git a/prism/compiler/filesystem.h b/prism/compiler/filesystem.h
new file mode 100644
index 0000000000..f988909db8
--- /dev/null
+++ b/prism/compiler/filesystem.h
@@ -0,0 +1,32 @@
+/**
+ * @file compiler/filesystem.h
+ *
+ * Platform detection for mmap and filesystem support.
+ */
+#ifndef PRISM_COMPILER_FILESYSTEM_H
+#define PRISM_COMPILER_FILESYSTEM_H
+
+/**
+ * In general, libc for embedded systems does not support memory-mapped files.
+ * If the target platform is POSIX or Windows, we can map a file in memory and
+ * read it in a more efficient manner.
+ */
+#ifdef _WIN32
+# define PRISM_HAS_MMAP
+#else
+# include <unistd.h>
+# ifdef _POSIX_MAPPED_FILES
+# define PRISM_HAS_MMAP
+# endif
+#endif
+
+/**
+ * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem
+ * related code from the library. All filesystem related code should be guarded
+ * by PRISM_HAS_FILESYSTEM.
+ */
+#ifndef PRISM_HAS_NO_FILESYSTEM
+# define PRISM_HAS_FILESYSTEM
+#endif
+
+#endif
diff --git a/prism/compiler/flex_array.h b/prism/compiler/flex_array.h
new file mode 100644
index 0000000000..7504b5fdd3
--- /dev/null
+++ b/prism/compiler/flex_array.h
@@ -0,0 +1,19 @@
+/**
+ * @file compiler/flex_array.h
+ */
+#ifndef PRISM_COMPILER_FLEX_ARRAY_H
+#define PRISM_COMPILER_FLEX_ARRAY_H
+
+/**
+ * A macro for helper define a flexible array member. C99 supports `data[]`, GCC
+ * supports `data[0]` as an extension, and older compilers require `data[1]`.
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ #define PM_FLEX_ARRAY_LENGTH /* data[] */
+#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
+ #define PM_FLEX_ARRAY_LENGTH 0 /* data[0] */
+#else
+ #define PM_FLEX_ARRAY_LENGTH 1 /* data[1] */
+#endif
+
+#endif
diff --git a/prism/compiler/force_inline.h b/prism/compiler/force_inline.h
new file mode 100644
index 0000000000..e189d592d6
--- /dev/null
+++ b/prism/compiler/force_inline.h
@@ -0,0 +1,21 @@
+/**
+ * @file compiler/force_inline.h
+ */
+#ifndef PRISM_COMPILER_FORCE_INLINE_H
+#define PRISM_COMPILER_FORCE_INLINE_H
+
+#include "prism/compiler/inline.h"
+
+/**
+ * Force a function to be inlined at every call site. Use sparingly — only for
+ * small, hot functions where the compiler's heuristics fail to inline.
+ */
+#if defined(_MSC_VER)
+# define PRISM_FORCE_INLINE __forceinline
+#elif defined(__GNUC__) || defined(__clang__)
+# define PRISM_FORCE_INLINE PRISM_INLINE __attribute__((always_inline))
+#else
+# define PRISM_FORCE_INLINE PRISM_INLINE
+#endif
+
+#endif
diff --git a/prism/compiler/format.h b/prism/compiler/format.h
new file mode 100644
index 0000000000..32f4c3c6d7
--- /dev/null
+++ b/prism/compiler/format.h
@@ -0,0 +1,25 @@
+/**
+ * @file compiler/format.h
+ */
+#ifndef PRISM_COMPILER_FORMAT_H
+#define PRISM_COMPILER_FORMAT_H
+
+/**
+ * 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__)
+# if defined(__MINGW_PRINTF_FORMAT)
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((format(__MINGW_PRINTF_FORMAT, fmt_idx_, arg_idx_)))
+# else
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((format(printf, fmt_idx_, arg_idx_)))
+# endif
+#elif defined(__clang__)
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_) __attribute__((__format__(__printf__, fmt_idx_, arg_idx_)))
+#else
+# define PRISM_ATTRIBUTE_FORMAT(fmt_idx_, arg_idx_)
+#endif
+
+#endif
diff --git a/prism/compiler/inline.h b/prism/compiler/inline.h
new file mode 100644
index 0000000000..856a375691
--- /dev/null
+++ b/prism/compiler/inline.h
@@ -0,0 +1,17 @@
+/**
+ * @file compiler/inline.h
+ */
+#ifndef PRISM_COMPILER_INLINE_H
+#define PRISM_COMPILER_INLINE_H
+
+/**
+ * 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 PRISM_INLINE __inline
+#else
+# define PRISM_INLINE inline
+#endif
+
+#endif
diff --git a/prism/compiler/nodiscard.h b/prism/compiler/nodiscard.h
new file mode 100644
index 0000000000..ccd6c00719
--- /dev/null
+++ b/prism/compiler/nodiscard.h
@@ -0,0 +1,22 @@
+/**
+ * @file compiler/nodiscard.h
+ */
+#ifndef PRISM_COMPILER_NODISCARD_H
+#define PRISM_COMPILER_NODISCARD_H
+
+/**
+ * Mark the return value of a function as important so that the compiler warns
+ * if a caller ignores it. This is useful for functions that return error codes
+ * or allocated resources that must be freed.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+# define PRISM_NODISCARD [[nodiscard]]
+#elif defined(__GNUC__) || defined(__clang__)
+# define PRISM_NODISCARD __attribute__((__warn_unused_result__))
+#elif defined(_MSC_VER)
+# define PRISM_NODISCARD _Check_return_
+#else
+# define PRISM_NODISCARD
+#endif
+
+#endif
diff --git a/prism/compiler/nonnull.h b/prism/compiler/nonnull.h
new file mode 100644
index 0000000000..9d19355665
--- /dev/null
+++ b/prism/compiler/nonnull.h
@@ -0,0 +1,18 @@
+/**
+ * @file compiler/nonnull.h
+ */
+#ifndef PRISM_COMPILER_NONNULL_H
+#define PRISM_COMPILER_NONNULL_H
+
+/**
+ * Mark the parameters of a function as non-null. This allows the compiler to
+ * warn if a caller passes NULL for a parameter that should never be NULL. The
+ * arguments are the 1-based indices of the parameters.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define PRISM_NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+# define PRISM_NONNULL(...)
+#endif
+
+#endif
diff --git a/prism/compiler/unused.h b/prism/compiler/unused.h
new file mode 100644
index 0000000000..6a9e125dde
--- /dev/null
+++ b/prism/compiler/unused.h
@@ -0,0 +1,18 @@
+/**
+ * @file compiler/unused.h
+ */
+#ifndef PRISM_COMPILER_UNUSED_H
+#define PRISM_COMPILER_UNUSED_H
+
+/**
+ * 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_UNUSED __attribute__((unused))
+#else
+# define PRISM_UNUSED
+#endif
+
+#endif
diff --git a/prism/config.yml b/prism/config.yml
index 3d5eee190f..bbbc5f3d33 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -17,6 +17,8 @@ errors:
- ARGUMENT_FORWARDING_UNBOUND
- ARGUMENT_NO_FORWARDING_AMPERSAND
- ARGUMENT_NO_FORWARDING_ELLIPSES
+ - ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA
+ - ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK
- ARGUMENT_NO_FORWARDING_STAR
- ARGUMENT_NO_FORWARDING_STAR_STAR
- ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT
@@ -60,7 +62,9 @@ errors:
- CONDITIONAL_WHILE_PREDICATE
- CONSTANT_PATH_COLON_COLON_CONSTANT
- DEF_ENDLESS
+ - DEF_ENDLESS_PARAMETERS
- DEF_ENDLESS_SETTER
+ - DEF_ENDLESS_DO_BLOCK
- DEF_NAME
- DEF_PARAMS_TERM
- DEF_PARAMS_TERM_PAREN
@@ -101,6 +105,8 @@ errors:
- EXPECT_FOR_DELIMITER
- EXPECT_IDENT_REQ_PARAMETER
- EXPECT_IN_DELIMITER
+ - EXPECT_LPAREN_AFTER_NOT_LPAREN
+ - EXPECT_LPAREN_AFTER_NOT_OTHER
- EXPECT_LPAREN_REQ_PARAMETER
- EXPECT_MESSAGE
- EXPECT_RBRACKET
@@ -216,6 +222,7 @@ errors:
- PARAMETER_WILD_LOOSE_COMMA
- PATTERN_ARRAY_MULTIPLE_RESTS
- PATTERN_CAPTURE_DUPLICATE
+ - PATTERN_CAPTURE_IN_ALTERNATIVE
- PATTERN_EXPRESSION_AFTER_BRACKET
- PATTERN_EXPRESSION_AFTER_COMMA
- PATTERN_EXPRESSION_AFTER_HROCKET
@@ -241,7 +248,9 @@ errors:
- PATTERN_TERM_PAREN
- PIPEPIPEEQ_MULTI_ASSIGN
- REGEXP_ENCODING_OPTION_MISMATCH
+ - REGEXP_ESCAPED_NON_ASCII_IN_UTF8
- REGEXP_INCOMPAT_CHAR_ENCODING
+ - REGEXP_INVALID_CHAR_PROPERTY
- REGEXP_INVALID_UNICODE_RANGE
- REGEXP_NON_ESCAPED_MBC
- REGEXP_PARSE_ERROR
@@ -277,6 +286,7 @@ errors:
- UNEXPECTED_INDEX_KEYWORDS
- UNEXPECTED_LABEL
- UNEXPECTED_MULTI_WRITE
+ - UNEXPECTED_PARAMETER_DEFAULT_VALUE
- UNEXPECTED_RANGE_OPERATOR
- UNEXPECTED_SAFE_NAVIGATION
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
@@ -320,13 +330,44 @@ warnings:
- UNUSED_LOCAL_VARIABLE
- VOID_STATEMENT
tokens:
+ # The order of the tokens at the beginning is important, because we use them
+ # for a lookup table.
- 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: BRACE_RIGHT
+ comment: "}"
+ - name: COMMA
+ comment: ","
+ - name: EMBEXPR_END
+ comment: "}"
+ - name: KEYWORD_DO
+ comment: "do"
+ - name: KEYWORD_ELSE
+ comment: "else"
+ - name: KEYWORD_ELSIF
+ comment: "elsif"
+ - name: KEYWORD_END
+ comment: "end"
+ - name: KEYWORD_ENSURE
+ comment: "ensure"
+ - name: KEYWORD_IN
+ comment: "in"
+ - name: KEYWORD_RESCUE
+ comment: "rescue"
+ - name: KEYWORD_THEN
+ comment: "then"
+ - name: KEYWORD_WHEN
+ comment: "when"
+ - name: NEWLINE
+ comment: "a newline character outside of other tokens"
+ - name: PARENTHESIS_RIGHT
+ comment: ")"
+ - name: PIPE
+ comment: "|"
+ - name: SEMICOLON
+ comment: ";"
+ # Tokens from here on are not used for lookup, and can be in any order.
- name: AMPERSAND
comment: "&"
- name: AMPERSAND_AMPERSAND
@@ -349,8 +390,6 @@ tokens:
comment: "!~"
- name: BRACE_LEFT
comment: "{"
- - name: BRACE_RIGHT
- comment: "}"
- name: BRACKET_LEFT
comment: "["
- name: BRACKET_LEFT_ARRAY
@@ -373,8 +412,6 @@ tokens:
comment: ":"
- name: COLON_COLON
comment: "::"
- - name: COMMA
- comment: ","
- name: COMMENT
comment: "a comment"
- name: CONSTANT
@@ -393,8 +430,6 @@ tokens:
comment: "a line inside of embedded documentation"
- name: EMBEXPR_BEGIN
comment: "#{"
- - name: EMBEXPR_END
- comment: "}"
- name: EMBVAR
comment: "#"
- name: EQUAL
@@ -461,20 +496,12 @@ tokens:
comment: "def"
- name: KEYWORD_DEFINED
comment: "defined?"
- - name: KEYWORD_DO
- comment: "do"
+ - name: KEYWORD_DO_BLOCK
+ comment: "do keyword for a block attached to a command"
- 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
@@ -483,8 +510,6 @@ tokens:
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
@@ -497,8 +522,6 @@ tokens:
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
@@ -509,8 +532,6 @@ tokens:
comment: "self"
- name: KEYWORD_SUPER
comment: "super"
- - name: KEYWORD_THEN
- comment: "then"
- name: KEYWORD_TRUE
comment: "true"
- name: KEYWORD_UNDEF
@@ -523,8 +544,6 @@ tokens:
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
@@ -561,16 +580,12 @@ tokens:
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
@@ -585,8 +600,6 @@ tokens:
comment: "%I"
- name: PERCENT_UPPER_W
comment: "%W"
- - name: PIPE
- comment: "|"
- name: PIPE_EQUAL
comment: "|="
- name: PIPE_PIPE
@@ -603,8 +616,6 @@ tokens:
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
@@ -803,8 +814,6 @@ nodes:
- GlobalVariableReadNode
- BackReferenceReadNode
- NumberedReferenceReadNode
- - on error: SymbolNode # alias $a b
- - on error: MissingNode # alias $a 42
comment: |
Represents the old name of the global variable that can be used before aliasing.
@@ -813,7 +822,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- The location of the `alias` keyword.
+ The Location of the `alias` keyword.
alias $foo $bar
^^^^^
@@ -845,8 +854,6 @@ nodes:
kind:
- SymbolNode
- InterpolatedSymbolNode
- - on error: GlobalVariableReadNode # alias a $b
- - on error: MissingNode # alias a 42
comment: |
Represents the old name of the method that will be aliased.
@@ -861,7 +868,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- Represents the location of the `alias` keyword.
+ Represents the Location of the `alias` keyword.
alias foo bar
^^^^^
@@ -891,7 +898,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the alternation operator location.
+ Represents the alternation operator Location.
foo => bar | baz
^
@@ -927,7 +934,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `and` keyword or the `&&` operator.
+ The Location of the `and` keyword or the `&&` operator.
left and right
^^^
@@ -962,7 +969,7 @@ nodes:
- name: opening_loc
type: location?
comment: |
- Represents the optional source location for the opening token.
+ Represents the optional source Location for the opening token.
[1,2,3] # "["
%w[foo bar baz] # "%w["
@@ -971,7 +978,7 @@ nodes:
- name: closing_loc
type: location?
comment: |
- Represents the optional source location for the closing token.
+ Represents the optional source Location for the closing token.
[1,2,3] # "]"
%w[foo bar baz] # "]"
@@ -987,8 +994,19 @@ nodes:
- name: constant
type: node?
kind:
- - ConstantReadNode
- ConstantPathNode
+ - ConstantReadNode
+ comment: |
+ Represents the optional constant preceding the Array
+
+ foo in Bar[]
+ ^^^
+
+ foo in Bar[1, 2, 3]
+ ^^^
+
+ foo in Bar::Baz[1, 2, 3]
+ ^^^^^^^^
- name: requireds
type: node[]
kind: pattern expression
@@ -999,7 +1017,9 @@ nodes:
^ ^
- name: rest
type: node?
- kind: pattern expression
+ kind:
+ - ImplicitRestNode
+ - SplatNode
comment: |
Represents the rest element of the array pattern.
@@ -1016,14 +1036,14 @@ nodes:
- name: opening_loc
type: location?
comment: |
- Represents the opening location of the array pattern.
+ Represents the opening Location of the array pattern.
foo in [1, 2]
^
- name: closing_loc
type: location?
comment: |
- Represents the closing location of the array pattern.
+ Represents the closing Location of the array pattern.
foo in [1, 2]
^
@@ -1031,19 +1051,19 @@ nodes:
Represents an array pattern in pattern matching.
foo in 1, 2
- ^^^^^^^^^^^
+ ^^^^
foo in [1, 2]
- ^^^^^^^^^^^^^
+ ^^^^^^
foo in *bar
- ^^^^^^^^^^^
+ ^^^^
foo in Bar[]
- ^^^^^^^^^^^^
+ ^^^^^
foo in Bar[1, 2, 3]
- ^^^^^^^^^^^^^^^^^^^
+ ^^^^^^^^^^^^
- name: AssocNode
fields:
- name: key
@@ -1074,7 +1094,7 @@ nodes:
- name: operator_loc
type: location?
comment: |
- The location of the `=>` operator, if present.
+ The Location of the `=>` operator, if present.
{ foo => bar }
^^
@@ -1096,7 +1116,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `**` operator.
+ The Location of the `**` operator.
{ **x }
^^
@@ -1125,7 +1145,7 @@ nodes:
- name: begin_keyword_loc
type: location?
comment: |
- Represents the location of the `begin` keyword.
+ Represents the Location of the `begin` keyword.
begin x end
^^^^^
@@ -1152,7 +1172,7 @@ nodes:
Represents the else clause within the begin block.
begin x; rescue y; else z; end
- ^^^^^^
+ ^^^^^^^^^^^
- name: ensure_clause
type: node?
kind: EnsureNode
@@ -1164,7 +1184,7 @@ nodes:
- name: end_keyword_loc
type: location?
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
begin x end
^^^
@@ -1185,11 +1205,11 @@ nodes:
The expression that is being passed as a block argument. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
foo(&args)
- ^^^^^
+ ^^^^
- name: operator_loc
type: location
comment: |
- Represents the location of the `&` operator.
+ Represents the Location of the `&` operator.
foo(&args)
^
@@ -1197,7 +1217,7 @@ nodes:
Represents a block argument using `&`.
bar(&args)
- ^^^^^^^^^^
+ ^^^^^
- name: BlockLocalVariableNode
flags: ParameterFlags
fields:
@@ -1250,17 +1270,17 @@ nodes:
- name: opening_loc
type: location
comment: |
- Represents the location of the opening `|`.
+ Represents the Location of the opening `{` or `do`.
[1, 2, 3].each { |i| puts x }
- ^
+ ^
- name: closing_loc
type: location
comment: |
- Represents the location of the closing `|`.
+ Represents the Location of the closing `}` or `end`.
[1, 2, 3].each { |i| puts x }
- ^
+ ^
comment: |
Represents a block of ruby code.
@@ -1280,14 +1300,14 @@ nodes:
- name: name_loc
type: location?
comment: |
- Represents the location of the block parameter name.
+ Represents the Location of the block parameter name.
def a(&b)
^
- name: operator_loc
type: location
comment: |
- Represents the location of the `&` operator.
+ Represents the Location of the `&` operator.
def a(&b)
^
@@ -1327,7 +1347,7 @@ nodes:
- name: opening_loc
type: location?
comment: |
- Represents the opening location of the block parameters.
+ Represents the opening Location of the block parameters.
-> (a, b = 1; local) { }
^
@@ -1338,7 +1358,7 @@ nodes:
- name: closing_loc
type: location?
comment: |
- Represents the closing location of the block parameters.
+ Represents the closing Location of the block parameters.
-> (a, b = 1; local) { }
^
@@ -1368,7 +1388,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- The location of the `break` keyword.
+ The Location of the `break` keyword.
break foo
^^^^^
@@ -1391,14 +1411,14 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar &&= value
^
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar &&= value
^^^
@@ -1419,7 +1439,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the location of the operator.
+ Represents the Location of the operator.
foo.bar &&= value
^^^
@@ -1456,7 +1476,7 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar
^
@@ -1473,14 +1493,15 @@ nodes:
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar
^^^
- name: opening_loc
type: location?
comment: |
- Represents the location of the left parenthesis.
+ Represents the Location of the left parenthesis.
+
foo(bar)
^
- name: arguments
@@ -1494,10 +1515,20 @@ nodes:
- name: closing_loc
type: location?
comment: |
- Represents the location of the right parenthesis.
+ Represents the Location of the right parenthesis.
foo(bar)
^
+ - name: equal_loc
+ type: location?
+ comment: |
+ Represents the Location of the equal sign, in the case that this is an attribute write.
+
+ foo.bar = value
+ ^
+
+ foo[bar] = value
+ ^
- name: block
type: node?
kind:
@@ -1542,14 +1573,14 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar += value
^
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar += value
^^^
@@ -1577,7 +1608,7 @@ nodes:
- name: binary_operator_loc
type: location
comment: |
- Represents the location of the binary operator.
+ Represents the Location of the binary operator.
foo.bar += value
^^
@@ -1608,14 +1639,14 @@ nodes:
- name: call_operator_loc
type: location?
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar ||= value
^
- name: message_loc
type: location?
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar ||= value
^^^
@@ -1636,7 +1667,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the location of the operator.
+ Represents the Location of the operator.
foo.bar ||= value
^^^
@@ -1667,7 +1698,7 @@ nodes:
- name: call_operator_loc
type: location
comment: |
- Represents the location of the call operator.
+ Represents the Location of the call operator.
foo.bar = 1
^
@@ -1681,7 +1712,7 @@ nodes:
- name: message_loc
type: location
comment: |
- Represents the location of the message.
+ Represents the Location of the message.
foo.bar = 1
^^^
@@ -1719,7 +1750,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- Represents the location of the `=>` operator.
+ Represents the Location of the `=>` operator.
foo => bar
^^
@@ -1727,7 +1758,7 @@ nodes:
Represents assigning to a local variable in pattern matching.
foo => [bar => baz]
- ^^^^^^^^^^^^
+ ^^^^^^^^^^
- name: CaseMatchNode
fields:
- name: predicate
@@ -1737,7 +1768,7 @@ nodes:
Represents the predicate of the case match. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
case true; in false; end
- ^^^^
+ ^^^^
- name: conditions
type: node[]
kind: InNode
@@ -1753,18 +1784,18 @@ nodes:
Represents the else clause of the case match.
case true; in false; else; end
- ^^^^
+ ^^^^^^^^^
- name: case_keyword_loc
type: location
comment: |
- Represents the location of the `case` keyword.
+ Represents the Location of the `case` keyword.
case true; in false; end
^^^^
- name: end_keyword_loc
type: location
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
case true; in false; end
^^^
@@ -1784,7 +1815,7 @@ nodes:
Represents the predicate of the case statement. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
case true; when false; end
- ^^^^
+ ^^^^
- name: conditions
type: node[]
kind: WhenNode
@@ -1800,18 +1831,18 @@ nodes:
Represents the else clause of the case statement.
case true; when false; else; end
- ^^^^
+ ^^^^^^^^^
- name: case_keyword_loc
type: location
comment: |
- Represents the location of the `case` keyword.
+ Represents the Location of the `case` keyword.
case true; when false; end
^^^^
- name: end_keyword_loc
type: location
comment: |
- Represents the location of the `end` keyword.
+ Represents the Location of the `end` keyword.
case true; when false; end
^^^
@@ -1828,26 +1859,54 @@ nodes:
type: constant[]
- name: class_keyword_loc
type: location
+ comment: |
+ Represents the Location of the `class` keyword.
+
+ class Foo end
+ ^^^^^
- name: constant_path
type: node
kind:
- ConstantReadNode
- ConstantPathNode
- - on error: CallNode # class 0.X end
- name: inheritance_operator_loc
type: location?
+ comment: |
+ Represents the Location of the `<` operator.
+
+ class Foo < Bar
+ ^
- name: superclass
type: node?
kind: non-void expression
+ comment: |
+ Represents the superclass of the class.
+
+ class Foo < Bar
+ ^^^
- name: body
type: node?
kind:
- StatementsNode
- BeginNode
+ comment: |
+ Represents the body of the class.
+
+ class Foo; bar; end
+ ^^^
- name: end_keyword_loc
type: location
+ comment: |
+ Represents the Location of the `end` keyword.
+
+ class Foo end
+ ^^^
- name: name
type: constant
+ comment: |
+ The name of the class.
+
+ class Foo end # name `:Foo`
comment: |
Represents a class declaration involving the `class` keyword.
@@ -1865,14 +1924,14 @@ nodes:
- name: name_loc
type: location
comment: |
- Represents the location of the variable name.
+ Represents the Location of the variable name.
@@target &&= value
^^^^^^^^
- name: operator_loc
type: location
comment: |
- Represents the location of the `&&=` operator.
+ Represents the Location of the `&&=` operator.
@@target &&= value
^^^
@@ -1960,7 +2019,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the variable name.
+ The Location of the variable name.
@@foo = :bar
^^^^^
@@ -1978,7 +2037,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
@@foo = :bar
^
@@ -2074,7 +2133,7 @@ nodes:
- name: delimiter_loc
type: location
comment: |
- The location of the `::` delimiter.
+ The Location of the `::` delimiter.
::Foo
^^
@@ -2084,7 +2143,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the name of the constant.
+ The Location of the name of the constant.
::Foo
^^^
@@ -2160,7 +2219,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
::ABC = 123
^
@@ -2220,7 +2279,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the constant name.
+ The Location of the constant name.
FOO = 1
^^^
@@ -2238,7 +2297,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
FOO = :bar
^
@@ -2363,6 +2422,15 @@ nodes:
^^^^^^
bar
end
+ - name: ErrorRecoveryNode
+ fields:
+ - name: unexpected
+ type: node?
+ kind: Node
+ comment: |
+ The unexpected node that was found in the tree, if there was one.
+ comment: |
+ Represents a node that is either missing or unexpected and results in a syntax error.
- name: FalseNode
comment: |
Represents the use of the literal `false` keyword.
@@ -2374,23 +2442,66 @@ nodes:
- name: constant
type: node?
kind:
- - ConstantReadNode
- ConstantPathNode
+ - ConstantReadNode
+ comment: |
+ Represents the optional constant preceding the pattern
+
+ foo in Foo(*bar, baz, *qux)
+ ^^^
- name: left
type: node
kind: SplatNode
+ comment: |
+ Represents the first wildcard node in the pattern.
+
+ foo in *bar, baz, *qux
+ ^^^^
+
+ foo in Foo(*bar, baz, *qux)
+ ^^^^
- name: requireds
type: node[]
kind: pattern expression
+ comment: |
+ Represents the nodes in between the wildcards.
+
+ foo in *bar, baz, *qux
+ ^^^
+
+ foo in Foo(*bar, baz, 1, *qux)
+ ^^^^^^
- name: right
type: node
- kind:
- - SplatNode
- - on error: MissingNode
+ kind: SplatNode
+ comment: |
+ Represents the second wildcard node in the pattern.
+
+ foo in *bar, baz, *qux
+ ^^^^
+
+ foo in Foo(*bar, baz, *qux)
+ ^^^^
- name: opening_loc
type: location?
+ comment: |
+ The Location of the opening brace.
+
+ foo in [*bar, baz, *qux]
+ ^
+
+ foo in Foo(*bar, baz, *qux)
+ ^
- name: closing_loc
type: location?
+ comment: |
+ The Location of the closing brace.
+
+ foo in [*bar, baz, *qux]
+ ^
+
+ foo in Foo(*bar, baz, *qux)
+ ^
comment: |
Represents a find pattern in pattern matching.
@@ -2402,6 +2513,9 @@ nodes:
foo in Foo(*bar, baz, *qux)
^^^^^^^^^^^^^^^^^^^^
+
+ foo => *bar, baz, *qux
+ ^^^^^^^^^^^^^^^
- name: FlipFlopNode
flags: RangeFlags
fields:
@@ -2442,9 +2556,6 @@ nodes:
- CallTargetNode
- IndexTargetNode
- MultiTargetNode
- - on error: BackReferenceReadNode # for $& in a end
- - on error: NumberedReferenceReadNode # for $1 in a end
- - on error: MissingNode # for in 1..10; end
comment: |
The index expression for `for` loops.
@@ -2471,28 +2582,28 @@ nodes:
- name: for_keyword_loc
type: location
comment: |
- The location of the `for` keyword.
+ The Location of the `for` keyword.
for i in a end
^^^
- name: in_keyword_loc
type: location
comment: |
- The location of the `in` keyword.
+ The Location of the `in` keyword.
for i in a end
^^
- name: do_keyword_loc
type: location?
comment: |
- The location of the `do` keyword, if present.
+ The Location of the `do` keyword, if present.
for i in a do end
^^
- name: end_keyword_loc
type: location
comment: |
- The location of the `end` keyword.
+ The Location of the `end` keyword.
for i in a end
^^^
@@ -2518,14 +2629,29 @@ nodes:
end
- name: ForwardingSuperNode
fields:
+ - name: keyword_loc
+ type: location
+ comment: |
+ super
+ ^^^^^
+
+ super { 123 }
+ ^^^^^
- name: block
type: node?
kind: BlockNode
+ comment: |
+ All other arguments are forwarded as normal, except the original block is replaced with the new block.
comment: |
- Represents the use of the `super` keyword without parentheses or arguments.
+ Represents the use of the `super` keyword without parentheses or arguments, but which might have a block.
super
^^^^^
+
+ super { 123 }
+ ^^^^^^^^^^^^^
+
+ If it has any other arguments, it would be a `SuperNode` instead.
- name: GlobalVariableAndWriteNode
fields:
- name: name
@@ -2613,7 +2739,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the global variable's name.
+ The Location of the global variable's name.
$foo = :bar
^^^^
@@ -2631,7 +2757,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
$foo = :bar
^
@@ -2645,7 +2771,7 @@ nodes:
- name: opening_loc
type: location
comment: |
- The location of the opening brace.
+ The Location of the opening brace.
{ a => b }
^
@@ -2665,7 +2791,7 @@ nodes:
- name: closing_loc
type: location
comment: |
- The location of the closing brace.
+ The Location of the closing brace.
{ a => b }
^
@@ -2679,20 +2805,60 @@ nodes:
- name: constant
type: node?
kind:
- - ConstantReadNode
- ConstantPathNode
+ - ConstantReadNode
+ comment: |
+ Represents the optional constant preceding the Hash.
+
+ foo => Bar[a: 1, b: 2]
+ ^^^
+
+ foo => Bar::Baz[a: 1, b: 2]
+ ^^^^^^^^
- name: elements
type: node[]
kind: AssocNode
+ comment: |
+ Represents the explicit named hash keys and values.
+
+ foo => { a: 1, b:, ** }
+ ^^^^^^^^
- name: rest
type: node?
kind:
- AssocSplatNode
- NoKeywordsParameterNode
+ comment: |
+ Represents the rest of the Hash keys and values. This can be named, unnamed, or explicitly forbidden via `**nil`, this last one results in a `NoKeywordsParameterNode`.
+
+ foo => { a: 1, b:, **c }
+ ^^^
+
+ foo => { a: 1, b:, ** }
+ ^^
+
+ foo => { a: 1, b:, **nil }
+ ^^^^^
- name: opening_loc
type: location?
+ comment: |
+ The Location of the opening brace.
+
+ foo => { a: 1 }
+ ^
+
+ foo => Bar[a: 1]
+ ^
- name: closing_loc
type: location?
+ comment: |
+ The Location of the closing brace.
+
+ foo => { a: 1 }
+ ^
+
+ foo => Bar[a: 1]
+ ^
comment: |
Represents a hash pattern in pattern matching.
@@ -2701,12 +2867,18 @@ nodes:
foo => { a: 1, b: 2, **c }
^^^^^^^^^^^^^^^^^^^
+
+ foo => Bar[a: 1, b: 2]
+ ^^^^^^^^^^^^^^^
+
+ foo in { a: 1, b: 2 }
+ ^^^^^^^^^^^^^^
- name: IfNode
fields:
- name: if_keyword_loc
type: location?
comment: |
- The location of the `if` keyword if present.
+ The Location of the `if` keyword if present.
bar if foo
^^
@@ -2731,7 +2903,7 @@ nodes:
- name: then_keyword_loc
type: location?
comment: |
- The location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
+ The Location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
if foo then bar end
^^^^
@@ -2772,7 +2944,7 @@ nodes:
- name: end_keyword_loc
type: location?
comment: |
- The location of the `end` keyword if present, `nil` otherwise.
+ The Location of the `end` keyword if present, `nil` otherwise.
if foo
bar
@@ -3057,7 +3229,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the variable name.
+ The Location of the variable name.
@_x = 1
^^^
@@ -3075,7 +3247,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
@x = y
^
@@ -3145,7 +3317,6 @@ nodes:
- EmbeddedStatementsNode
- EmbeddedVariableNode
- InterpolatedStringNode # `"a" "#{b}"`
- - on error: XStringNode # `<<`FOO` "bar"
- name: closing_loc
type: location?
newline: parts
@@ -3353,6 +3524,9 @@ nodes:
foo, bar = baz
^^^ ^^^
+
+ foo => baz
+ ^^^
- name: LocalVariableWriteNode
fields:
- name: name
@@ -3376,7 +3550,7 @@ nodes:
- name: name_loc
type: location
comment: |
- The location of the variable name.
+ The Location of the variable name.
foo = :bar
^^^
@@ -3398,7 +3572,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `=` operator.
+ The Location of the `=` operator.
x = :y
^
@@ -3443,11 +3617,65 @@ nodes:
- name: value
type: node
kind: non-void expression
+ comment: |
+ Represents the left-hand side of the operator.
+
+ foo => bar
+ ^^^
- name: pattern
type: node
kind: pattern expression
+ comment: |
+ Represents the right-hand side of the operator. The type of the node depends on the expression.
+
+ Anything that looks like a local variable name (including `_`) will result in a `LocalVariableTargetNode`.
+
+ foo => a # This is equivalent to writing `a = foo`
+ ^
+
+ Using an explicit `Array` or combining expressions with `,` will result in a `ArrayPatternNode`. This can be preceded by a constant.
+
+ foo => [a]
+ ^^^
+
+ foo => a, b
+ ^^^^
+
+ foo => Bar[a, b]
+ ^^^^^^^^^
+
+ If the array pattern contains at least two wildcard matches, a `FindPatternNode` is created instead.
+
+ foo => *, 1, *a
+ ^^^^^
+
+ Using an explicit `Hash` or a constant with square brackets and hash keys in the square brackets will result in a `HashPatternNode`.
+
+ foo => { a: 1, b: }
+
+ foo => Bar[a: 1, b:]
+
+ foo => Bar[**]
+
+ To use any variable that needs run time evaluation, pinning is required. This results in a `PinnedVariableNode`
+
+ foo => ^a
+ ^^
+
+ Similar, any expression can be used with pinning. This results in a `PinnedExpressionNode`.
+
+ foo => ^(a + 1)
+
+ Anything else will result in the regular node for that expression, for example a `ConstantReadNode`.
+
+ foo => CONST
- name: operator_loc
type: location
+ comment: |
+ The Location of the operator.
+
+ foo => bar
+ ^^
comment: |
Represents the use of the `=>` operator.
@@ -3466,9 +3694,6 @@ nodes:
/(?<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
@@ -3480,7 +3705,6 @@ nodes:
kind:
- ConstantReadNode
- ConstantPathNode
- - on error: MissingNode # module Parent module end
- name: body
type: node?
kind:
@@ -3510,8 +3734,6 @@ nodes:
- IndexTargetNode
- MultiTargetNode
- RequiredParameterNode # def m((a,b)); end
- - on error: BackReferenceReadNode # a, (b, $&) = z
- - on error: NumberedReferenceReadNode # a, (b, $1) = z
comment: |
Represents the targets expressions before a splat node.
@@ -3555,8 +3777,6 @@ nodes:
- IndexTargetNode
- MultiTargetNode
- RequiredParameterNode # def m((*,b)); end
- - on error: BackReferenceReadNode # a, (*, $&) = z
- - on error: NumberedReferenceReadNode # a, (*, $1) = z
comment: |
Represents the targets expressions after a splat node.
@@ -3565,14 +3785,14 @@ nodes:
- name: lparen_loc
type: location?
comment: |
- The location of the opening parenthesis.
+ The Location of the opening parenthesis.
a, (b, c) = 1, 2, 3
^
- name: rparen_loc
type: location?
comment: |
- The location of the closing parenthesis.
+ The Location of the closing parenthesis.
a, (b, c) = 1, 2, 3
^
@@ -3600,8 +3820,6 @@ nodes:
- CallTargetNode
- IndexTargetNode
- MultiTargetNode
- - on error: BackReferenceReadNode # $&, = z
- - on error: NumberedReferenceReadNode # $1, = z
comment: |
Represents the targets expressions before a splat node.
@@ -3644,8 +3862,6 @@ nodes:
- CallTargetNode
- IndexTargetNode
- MultiTargetNode
- - on error: BackReferenceReadNode # *, $& = z
- - on error: NumberedReferenceReadNode # *, $1 = z
comment: |
Represents the targets expressions after a splat node.
@@ -3654,21 +3870,21 @@ nodes:
- name: lparen_loc
type: location?
comment: |
- The location of the opening parenthesis.
+ The Location of the opening parenthesis.
(a, b, c) = 1, 2, 3
^
- name: rparen_loc
type: location?
comment: |
- The location of the closing parenthesis.
+ The Location of the closing parenthesis.
(a, b, c) = 1, 2, 3
^
- name: operator_loc
type: location
comment: |
- The location of the operator.
+ The Location of the operator.
a, b, c = 1, 2, 3
^
@@ -3703,6 +3919,18 @@ nodes:
nil
^^^
+ - name: NoBlockParameterNode
+ 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: NoKeywordsParameterNode
fields:
- name: operator_loc
@@ -3802,7 +4030,7 @@ nodes:
- name: operator_loc
type: location
comment: |
- The location of the `or` keyword or the `||` operator.
+ The Location of the `or` keyword or the `||` operator.
left or right
^^
@@ -3831,11 +4059,6 @@ nodes:
kind:
- RequiredParameterNode
- MultiTargetNode
- # On parsing error of `f(**kwargs, ...)` or `f(**nil, ...)`, the keyword_rest value is moved here:
- - on error: KeywordRestParameterNode
- - on error: NoKeywordsParameterNode
- # On parsing error of `f(..., ...)`, the first forwarding parameter is moved here:
- - on error: ForwardingParameterNode
- name: keywords
type: node[]
kind:
@@ -3849,7 +4072,9 @@ nodes:
- NoKeywordsParameterNode
- name: block
type: node?
- kind: BlockParameterNode
+ kind:
+ - BlockParameterNode
+ - NoBlockParameterNode
comment: |
Represents the list of parameters on a method, block, or lambda definition.
@@ -3877,12 +4102,32 @@ nodes:
- name: expression
type: node
kind: non-void expression
+ comment: |
+ The expression used in the pinned expression
+
+ foo in ^(bar)
+ ^^^
- name: operator_loc
type: location
+ comment: |
+ The Location of the `^` operator
+
+ foo in ^(bar)
+ ^
- name: lparen_loc
type: location
+ comment: |
+ The Location of the opening parenthesis.
+
+ foo in ^(bar)
+ ^
- name: rparen_loc
type: location
+ comment: |
+ The Location of the closing parenthesis.
+
+ foo in ^(bar)
+ ^
comment: |
Represents the use of the `^` operator for pinning an expression in a pattern matching expression.
@@ -3900,9 +4145,18 @@ nodes:
- BackReferenceReadNode # foo in ^$&
- NumberedReferenceReadNode # foo in ^$1
- ItLocalVariableReadNode # proc { 1 in ^it }
- - on error: MissingNode # foo in ^Bar
+ comment: |
+ The variable used in the pinned expression
+
+ foo in ^bar
+ ^^^
- name: operator_loc
type: location
+ comment: |
+ The Location of the `^` operator
+
+ foo in ^bar
+ ^
comment: |
Represents the use of the `^` operator for pinning a variable in a pattern matching expression.
@@ -3973,11 +4227,11 @@ nodes:
1...foo
^^^
- If neither right-hand or left-hand side was included, this will be a MissingNode.
+ If neither right-hand or left-hand side was included, this will be an ErrorRecoveryNode.
- name: operator_loc
type: location
comment: |
- The location of the `..` or `...` operator.
+ The Location of the `..` or `...` operator.
comment: |
Represents the use of the `..` or `...` operators.
@@ -4088,9 +4342,6 @@ nodes:
- ConstantPathTargetNode
- CallTargetNode
- IndexTargetNode
- - on error: BackReferenceReadNode # => begin; rescue => $&; end
- - on error: NumberedReferenceReadNode # => begin; rescue => $1; end
- - on error: MissingNode # begin; rescue =>; end
- name: then_keyword_loc
type: location?
- name: statements
@@ -4203,7 +4454,7 @@ nodes:
fields:
- name: filepath
type: string
- comment: Represents the file path being parsed. This corresponds directly to the `filepath` option given to the various `Prism::parse*` APIs.
+ comment: Represents the file path being parsed. This corresponds directly to the `filepath` option given to the various `Prism.parse*` APIs.
comment: |
Represents the use of the `__FILE__` keyword.
@@ -4268,6 +4519,7 @@ nodes:
- name: arguments
type: node?
kind: ArgumentsNode
+ comment: "Can be only `nil` when there are empty parentheses, like `super()`."
- name: rparen_loc
type: location?
- name: block
@@ -4283,6 +4535,8 @@ nodes:
super foo, bar
^^^^^^^^^^^^^^
+
+ If no arguments are provided (except for a block), it would be a `ForwardingSuperNode` instead.
- name: SymbolNode
flags: SymbolFlags
fields:
@@ -4327,7 +4581,7 @@ nodes:
- name: keyword_loc
type: location
comment: |
- The location of the `unless` keyword.
+ The Location of the `unless` keyword.
unless cond then bar end
^^^^^^
@@ -4348,7 +4602,7 @@ nodes:
- name: then_keyword_loc
type: location?
comment: |
- The location of the `then` keyword, if present.
+ The Location of the `then` keyword, if present.
unless cond then bar end
^^^^
@@ -4368,11 +4622,11 @@ nodes:
The else clause of the unless expression, if present.
unless cond then bar else baz end
- ^^^^^^^^
+ ^^^^^^^^^^^^
- name: end_keyword_loc
type: location?
comment: |
- The location of the `end` keyword, if present.
+ The Location of the `end` keyword, if present.
unless cond then bar end
^^^
diff --git a/prism/constant_pool.c b/prism/constant_pool.c
new file mode 100644
index 0000000000..90201ebb8e
--- /dev/null
+++ b/prism/constant_pool.c
@@ -0,0 +1,360 @@
+#include "prism/internal/constant_pool.h"
+
+#include "prism/compiler/align.h"
+#include "prism/compiler/inline.h"
+#include "prism/internal/arena.h"
+
+#include <assert.h>
+#include <stdbool.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;
+}
+
+/**
+ * Initialize a list of constant ids with a given capacity.
+ */
+void
+pm_constant_id_list_init_capacity(pm_arena_t *arena, pm_constant_id_list_t *list, size_t capacity) {
+ if (capacity) {
+ list->ids = (pm_constant_id_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_id_t), PRISM_ALIGNOF(pm_constant_id_t));
+ } else {
+ list->ids = NULL;
+ }
+
+ list->size = 0;
+ list->capacity = capacity;
+}
+
+/**
+ * Append a constant id to a list of constant ids.
+ */
+void
+pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id) {
+ if (list->size >= list->capacity) {
+ size_t new_capacity = list->capacity == 0 ? 8 : list->capacity * 2;
+ pm_constant_id_t *new_ids = (pm_constant_id_t *) pm_arena_alloc(arena, sizeof(pm_constant_id_t) * new_capacity, PRISM_ALIGNOF(pm_constant_id_t));
+
+ if (list->size > 0) {
+ memcpy(new_ids, list->ids, list->size * sizeof(pm_constant_id_t));
+ }
+
+ list->ids = new_ids;
+ list->capacity = new_capacity;
+ }
+
+ list->ids[list->size++] = id;
+}
+
+/**
+ * Insert a constant id into a list of constant ids at the specified index.
+ */
+void
+pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id) {
+ assert(index < list->capacity);
+ assert(list->ids[index] == PM_CONSTANT_ID_UNSET);
+
+ list->ids[index] = id;
+ list->size++;
+}
+
+/**
+ * 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;
+}
+
+/**
+ * A multiply-xorshift hash that processes input a word at a time. This is
+ * significantly faster than the byte-at-a-time djb2 hash for the short strings
+ * typical in Ruby source (~15 bytes average). Each word is mixed into the hash
+ * by XOR followed by multiplication by a large odd constant, which spreads
+ * entropy across all bits. A final xorshift fold produces the 32-bit result.
+ */
+static PRISM_INLINE uint32_t
+pm_constant_pool_hash(const uint8_t *start, size_t length) {
+ // This constant is borrowed from wyhash. It is a 64-bit odd integer with
+ // roughly equal 0/1 bits, chosen for good avalanche behavior when used in
+ // multiply-xorshift sequences.
+ static const uint64_t secret = 0x517cc1b727220a95ULL;
+ uint64_t hash = (uint64_t) length;
+
+ if (length <= 8) {
+ // Short strings: read first and last 4 bytes (overlapping for len < 8).
+ // This covers the majority of Ruby identifiers with a single multiply.
+ if (length >= 4) {
+ uint32_t a, b;
+ memcpy(&a, start, 4);
+ memcpy(&b, start + length - 4, 4);
+ hash ^= (uint64_t) a | ((uint64_t) b << 32);
+ } else if (length > 0) {
+ hash ^= (uint64_t) start[0] | ((uint64_t) start[length >> 1] << 8) | ((uint64_t) start[length - 1] << 16);
+ }
+ hash *= secret;
+ } else if (length <= 16) {
+ // Medium strings: read first and last 8 bytes (overlapping).
+ // Two multiplies instead of the three the loop-based approach needs.
+ uint64_t word;
+ memcpy(&word, start, 8);
+ hash ^= word;
+ hash *= secret;
+ memcpy(&word, start + length - 8, 8);
+ hash ^= word;
+ hash *= secret;
+ } else {
+ const uint8_t *ptr = start;
+ size_t remaining = length;
+
+ while (remaining >= 8) {
+ uint64_t word;
+ memcpy(&word, ptr, 8);
+ hash ^= word;
+ hash *= secret;
+ ptr += 8;
+ remaining -= 8;
+ }
+
+ if (remaining > 0) {
+ // Read the last 8 bytes (overlapping with already-processed data).
+ uint64_t word;
+ memcpy(&word, start + length - 8, 8);
+ hash ^= word;
+ hash *= secret;
+ }
+ }
+
+ hash ^= hash >> 32;
+ return (uint32_t) hash;
+}
+
+/**
+ * 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 PRISM_INLINE void
+pm_constant_pool_resize(pm_arena_t *arena, pm_constant_pool_t *pool) {
+ assert(is_power_of_two(pool->capacity));
+
+ uint32_t next_capacity = pool->capacity * 2;
+ const uint32_t mask = next_capacity - 1;
+
+ pm_constant_pool_bucket_t *next_buckets = (pm_constant_pool_bucket_t *) pm_arena_zalloc(arena, next_capacity * sizeof(pm_constant_pool_bucket_t), PRISM_ALIGNOF(pm_constant_pool_bucket_t));
+ pm_constant_t *next_constants = (pm_constant_t *) pm_arena_alloc(arena, next_capacity * sizeof(pm_constant_t), PRISM_ALIGNOF(pm_constant_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 != PM_CONSTANT_ID_UNSET) {
+ 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 != PM_CONSTANT_ID_UNSET) {
+ 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 = next_constants;
+ pool->buckets = next_buckets;
+ pool->capacity = next_capacity;
+}
+
+/**
+ * Initialize a new constant pool with a given capacity.
+ */
+void
+pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity) {
+ capacity = next_power_of_two(capacity);
+
+ pool->buckets = (pm_constant_pool_bucket_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_pool_bucket_t), PRISM_ALIGNOF(pm_constant_pool_bucket_t));
+ pool->constants = (pm_constant_t *) pm_arena_alloc(arena, capacity * sizeof(pm_constant_t), PRISM_ALIGNOF(pm_constant_t));
+ pool->size = 0;
+ pool->capacity = capacity;
+}
+
+/**
+ * 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 != PM_CONSTANT_ID_UNSET && constant_id <= pool->size);
+ return &pool->constants[constant_id - 1];
+}
+
+/**
+ * Find a constant in a constant pool. Returns the id of the constant, or 0 if
+ * the constant is not found.
+ */
+pm_constant_id_t
+pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
+ 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 != PM_CONSTANT_ID_UNSET) {
+ if ((bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
+ return bucket->id;
+ }
+
+ index = (index + 1) & mask;
+ }
+
+ return PM_CONSTANT_ID_UNSET;
+}
+
+/**
+ * Insert a constant into a constant pool and return its index in the pool.
+ */
+static PRISM_INLINE pm_constant_id_t
+pm_constant_pool_insert(pm_arena_t *arena, 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)) {
+ pm_constant_pool_resize(arena, pool);
+ }
+
+ 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 != PM_CONSTANT_ID_UNSET) {
+ // 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.
+ if ((bucket->length == length) && memcmp(bucket->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 && 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 replace it with the
+ // shared constant to prefer non-owned references.
+ bucket->start = start;
+ bucket->type = (unsigned int) (type & 0x3);
+ pool->constants[bucket->id - 1].start = start;
+ }
+
+ return bucket->id;
+ }
+
+ index = (index + 1) & mask;
+ }
+
+ // IDs are allocated starting at 1, since the value 0 denotes a non-existent
+ // 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,
+ .start = start,
+ .length = length
+ };
+
+ 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
+ * PM_CONSTANT_ID_UNSET if any potential calls to resize fail.
+ */
+pm_constant_id_t
+pm_constant_pool_insert_shared(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
+ return pm_constant_pool_insert(arena, 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 PM_CONSTANT_ID_UNSET if any
+ * potential calls to resize fail.
+ */
+pm_constant_id_t
+pm_constant_pool_insert_owned(pm_arena_t *arena, pm_constant_pool_t *pool, uint8_t *start, size_t length) {
+ return pm_constant_pool_insert(arena, 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 PM_CONSTANT_ID_UNSET if any potential calls to
+ * resize fail.
+ */
+pm_constant_id_t
+pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
+ return pm_constant_pool_insert(arena, pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT);
+}
+
+/**
+ * Return a raw pointer to the start of a constant.
+ */
+const uint8_t *
+pm_constant_start(const pm_constant_t *constant) {
+ return constant->start;
+}
+
+/**
+ * Return the length of a constant.
+ */
+size_t pm_constant_length(const pm_constant_t *constant) {
+ return constant->length;
+}
diff --git a/prism/constant_pool.h b/prism/constant_pool.h
new file mode 100644
index 0000000000..dc03235c70
--- /dev/null
+++ b/prism/constant_pool.h
@@ -0,0 +1,81 @@
+/**
+ * @file 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/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/arena.h"
+
+#include <stddef.h>
+#include <stdint.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;
+
+/** A constant in the pool which effectively stores a string. */
+typedef struct pm_constant_t pm_constant_t;
+
+/**
+ * The overall constant pool, which stores constants found while parsing.
+ */
+typedef struct pm_constant_pool_t pm_constant_pool_t;
+
+/**
+ * Return a raw pointer to the start of a constant.
+ *
+ * @param constant The constant to get the start of.
+ * @returns A raw pointer to the start of the constant.
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_constant_start(const pm_constant_t *constant) PRISM_NONNULL(1);
+
+/**
+ * Return the length of a constant.
+ *
+ * @param constant The constant to get the length of.
+ * @returns The length of the constant.
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_constant_length(const pm_constant_t *constant) PRISM_NONNULL(1);
+
+/**
+ * Initialize a list of constant ids.
+ *
+ * @param list The list to initialize.
+ */
+PRISM_EXPORTED_FUNCTION void pm_constant_id_list_init(pm_constant_id_list_t *list) PRISM_NONNULL(1);
+
+/**
+ * Append a constant id to a list of constant ids.
+ *
+ * @param arena The arena to use for allocations.
+ * @param list The list to append to.
+ * @param id The constant id to append.
+ */
+PRISM_EXPORTED_FUNCTION void pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id) PRISM_NONNULL(1, 2);
+
+#endif
diff --git a/prism/defines.h b/prism/defines.h
deleted file mode 100644
index e31429c789..0000000000
--- a/prism/defines.h
+++ /dev/null
@@ -1,260 +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 <limits.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-/**
- * We want to be able to use the PRI* macros for printing out integers, but on
- * some platforms they aren't included unless this is already defined.
- */
-#define __STDC_FORMAT_MACROS
-// Include sys/types.h before inttypes.h to work around issue with
-// certain versions of GCC and newlib which causes omission of PRIx64
-#include <sys/types.h>
-#include <inttypes.h>
-
-/**
- * When we are parsing using recursive descent, we want to protect against
- * malicious payloads that could attempt to crash our parser. We do this by
- * specifying a maximum depth to which we are allowed to recurse.
- */
-#ifndef PRISM_DEPTH_MAXIMUM
- #define PRISM_DEPTH_MAXIMUM 10000
-#endif
-
-/**
- * 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__)
-# if defined(__MINGW_PRINTF_FORMAT)
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(__MINGW_PRINTF_FORMAT, string_index, argument_index)))
-# else
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index)))
-# endif
-#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
-
-/**
- * In general, libc for embedded systems does not support memory-mapped files.
- * If the target platform is POSIX or Windows, we can map a file in memory and
- * read it in a more efficient manner.
- */
-#ifdef _WIN32
-# define PRISM_HAS_MMAP
-#else
-# include <unistd.h>
-# ifdef _POSIX_MAPPED_FILES
-# define PRISM_HAS_MMAP
-# endif
-#endif
-
-/**
- * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem
- * related code from the library. All filesystem related code should be guarded
- * by PRISM_HAS_FILESYSTEM.
- */
-#ifndef PRISM_HAS_NO_FILESYSTEM
-# define PRISM_HAS_FILESYSTEM
-#endif
-
-/**
- * isinf on POSIX systems it accepts a float, a double, or a long double.
- * But mingw didn't provide an isinf macro, only an isinf function that only
- * accepts floats, so we need to use _finite instead.
- */
-#ifdef __MINGW64__
- #include <float.h>
- #define PRISM_ISINF(x) (!_finite(x))
-#else
- #define PRISM_ISINF(x) isinf(x)
-#endif
-
-/**
- * If you build prism with a custom allocator, configure it with
- * "-D PRISM_XALLOCATOR" to use your own allocator that defines xmalloc,
- * xrealloc, xcalloc, and xfree.
- *
- * For example, your `prism_xallocator.h` file could look like this:
- *
- * ```
- * #ifndef PRISM_XALLOCATOR_H
- * #define PRISM_XALLOCATOR_H
- * #define xmalloc my_malloc
- * #define xrealloc my_realloc
- * #define xcalloc my_calloc
- * #define xfree my_free
- * #endif
- * ```
- */
-#ifdef PRISM_XALLOCATOR
- #include "prism_xallocator.h"
-#else
- #ifndef xmalloc
- /**
- * The malloc function that should be used. This can be overridden with
- * the PRISM_XALLOCATOR define.
- */
- #define xmalloc malloc
- #endif
-
- #ifndef xrealloc
- /**
- * The realloc function that should be used. This can be overridden with
- * the PRISM_XALLOCATOR define.
- */
- #define xrealloc realloc
- #endif
-
- #ifndef xcalloc
- /**
- * The calloc function that should be used. This can be overridden with
- * the PRISM_XALLOCATOR define.
- */
- #define xcalloc calloc
- #endif
-
- #ifndef xfree
- /**
- * The free function that should be used. This can be overridden with the
- * PRISM_XALLOCATOR define.
- */
- #define xfree free
- #endif
-#endif
-
-/**
- * If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible
- * switch that will turn off certain features of prism.
- */
-#ifdef PRISM_BUILD_MINIMAL
- /** Exclude the serialization API. */
- #define PRISM_EXCLUDE_SERIALIZATION
-
- /** Exclude the JSON serialization API. */
- #define PRISM_EXCLUDE_JSON
-
- /** Exclude the Array#pack parser API. */
- #define PRISM_EXCLUDE_PACK
-
- /** Exclude the prettyprint API. */
- #define PRISM_EXCLUDE_PRETTYPRINT
-
- /** Exclude the full set of encodings, using the minimal only. */
- #define PRISM_ENCODING_EXCLUDE_FULL
-#endif
-
-/**
- * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its
- * branch predication.
- */
-#if defined(__GNUC__) || defined(__clang__)
- /** The compiler should predicate that this branch will be taken. */
- #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
-
- /** The compiler should predicate that this branch will not be taken. */
- #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
-#else
- /** Void because this platform does not support branch prediction hints. */
- #define PRISM_LIKELY(x) (x)
-
- /** Void because this platform does not support branch prediction hints. */
- #define PRISM_UNLIKELY(x) (x)
-#endif
-
-/**
- * We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
- * Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
- */
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later
- #define PRISM_FALLTHROUGH [[fallthrough]];
-#elif defined(__GNUC__) || defined(__clang__)
- #define PRISM_FALLTHROUGH __attribute__((fallthrough));
-#elif defined(_MSC_VER)
- #define PRISM_FALLTHROUGH __fallthrough;
-#else
- #define PRISM_FALLTHROUGH
-#endif
-
-#endif
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
new file mode 100644
index 0000000000..370061ec56
--- /dev/null
+++ b/prism/diagnostic.h
@@ -0,0 +1,93 @@
+/**
+ * @file diagnostic.h
+ *
+ * A list of diagnostics generated during parsing.
+ */
+#ifndef PRISM_DIAGNOSTIC_H
+#define PRISM_DIAGNOSTIC_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+
+/**
+ * An opaque pointer to a diagnostic generated during parsing.
+ */
+typedef struct pm_diagnostic_t pm_diagnostic_t;
+
+/**
+ * The levels of errors generated during parsing.
+ */
+typedef enum {
+ /** For errors that should raise a syntax error. */
+ PM_ERROR_LEVEL_SYNTAX = 0,
+
+ /** For errors that should raise an argument error. */
+ PM_ERROR_LEVEL_ARGUMENT = 1,
+
+ /** For errors that should raise a load error. */
+ PM_ERROR_LEVEL_LOAD = 2
+} pm_error_level_t;
+
+/**
+ * The levels of warnings generated during parsing.
+ */
+typedef enum {
+ /** For warnings which should be emitted if $VERBOSE != nil. */
+ PM_WARNING_LEVEL_DEFAULT = 0,
+
+ /** For warnings which should be emitted if $VERBOSE == true. */
+ PM_WARNING_LEVEL_VERBOSE = 1
+} pm_warning_level_t;
+
+/**
+ * Get the type of the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the type of.
+ * @returns The type of the given diagnostic. Note that this is a string
+ * representation of an internal ID, and is not meant to be relied upon as a
+ * stable identifier for the diagnostic. We do not guarantee that these will
+ * not change in the future. This is meant to be used for debugging and
+ * error reporting purposes, and not for programmatic checks.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_diagnostic_type(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the location of the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the location of.
+ * @returns The location of the given diagnostic.
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_diagnostic_location(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the message of the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the message of.
+ * @returns The message of the given diagnostic.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_diagnostic_message(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the error level associated with the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the error level of.
+ * @returns The error level of the given diagnostic. If the diagnostic was a
+ * warning, or is in any way not an error, then the return value is
+ * undefined and should not be relied upon.
+ */
+PRISM_EXPORTED_FUNCTION pm_error_level_t pm_diagnostic_error_level(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+/**
+ * Get the warning level associated with the given diagnostic.
+ *
+ * @param diagnostic The diagnostic to get the warning level of.
+ * @returns The warning level of the given diagnostic. If the diagnostic was an
+ * error, or is in any way not a warning, then the return value is
+ * undefined and should not be relied upon.
+ */
+PRISM_EXPORTED_FUNCTION pm_warning_level_t pm_diagnostic_warning_level(const pm_diagnostic_t *diagnostic) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/encoding.c b/prism/encoding.c
index a4aeed104f..c9c2e13056 100644
--- a/prism/encoding.c
+++ b/prism/encoding.c
@@ -1,8 +1,13 @@
-#include "prism/encoding.h"
+#include "prism/internal/encoding.h"
+
+#include "prism/compiler/unused.h"
+#include "prism/internal/strncasecmp.h"
+
+#include <assert.h>
typedef uint32_t pm_unicode_codepoint_t;
-#define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450
+#define UNICODE_ALPHA_CODEPOINTS_LENGTH 1508
static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = {
0x100, 0x2C1,
0x2C6, 0x2D1,
@@ -10,7 +15,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x2EC, 0x2EC,
0x2EE, 0x2EE,
0x345, 0x345,
- 0x370, 0x374,
+ 0x363, 0x374,
0x376, 0x377,
0x37A, 0x37D,
0x37F, 0x37F,
@@ -50,7 +55,8 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x840, 0x858,
0x860, 0x86A,
0x870, 0x887,
- 0x889, 0x88E,
+ 0x889, 0x88F,
+ 0x897, 0x897,
0x8A0, 0x8C9,
0x8D4, 0x8DF,
0x8E3, 0x8E9,
@@ -140,7 +146,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0xC4A, 0xC4C,
0xC55, 0xC56,
0xC58, 0xC5A,
- 0xC5D, 0xC5D,
+ 0xC5C, 0xC5D,
0xC60, 0xC63,
0xC80, 0xC83,
0xC85, 0xC8C,
@@ -152,7 +158,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0xCC6, 0xCC8,
0xCCA, 0xCCC,
0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
+ 0xCDC, 0xCDE,
0xCE0, 0xCE3,
0xCF1, 0xCF3,
0xD00, 0xD0C,
@@ -264,7 +270,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1C00, 0x1C36,
0x1C4D, 0x1C4F,
0x1C5A, 0x1C7D,
- 0x1C80, 0x1C88,
+ 0x1C80, 0x1C8A,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
0x1CE9, 0x1CEC,
@@ -272,7 +278,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1CF5, 0x1CF6,
0x1CFA, 0x1CFA,
0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
+ 0x1DD3, 0x1DF4,
0x1E00, 0x1F15,
0x1F18, 0x1F1D,
0x1F20, 0x1F45,
@@ -352,11 +358,8 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0xA67F, 0xA6EF,
0xA717, 0xA71F,
0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
+ 0xA78B, 0xA7DC,
+ 0xA7F1, 0xA805,
0xA807, 0xA827,
0xA840, 0xA873,
0xA880, 0xA8C3,
@@ -446,6 +449,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x105A3, 0x105B1,
0x105B3, 0x105B9,
0x105BB, 0x105BC,
+ 0x105C0, 0x105F3,
0x10600, 0x10736,
0x10740, 0x10755,
0x10760, 0x10767,
@@ -464,6 +468,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x108F4, 0x108F5,
0x10900, 0x10915,
0x10920, 0x10939,
+ 0x10940, 0x10959,
0x10980, 0x109B7,
0x109BE, 0x109BF,
0x10A00, 0x10A03,
@@ -483,9 +488,14 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x10C80, 0x10CB2,
0x10CC0, 0x10CF2,
0x10D00, 0x10D27,
+ 0x10D4A, 0x10D65,
+ 0x10D69, 0x10D69,
+ 0x10D6F, 0x10D85,
0x10E80, 0x10EA9,
0x10EAB, 0x10EAC,
0x10EB0, 0x10EB1,
+ 0x10EC2, 0x10EC7,
+ 0x10EFA, 0x10EFC,
0x10F00, 0x10F1C,
0x10F27, 0x10F27,
0x10F30, 0x10F45,
@@ -529,6 +539,17 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x11350, 0x11350,
0x11357, 0x11357,
0x1135D, 0x11363,
+ 0x11380, 0x11389,
+ 0x1138B, 0x1138B,
+ 0x1138E, 0x1138E,
+ 0x11390, 0x113B5,
+ 0x113B7, 0x113C0,
+ 0x113C2, 0x113C2,
+ 0x113C5, 0x113C5,
+ 0x113C7, 0x113CA,
+ 0x113CC, 0x113CD,
+ 0x113D1, 0x113D1,
+ 0x113D3, 0x113D3,
0x11400, 0x11441,
0x11443, 0x11445,
0x11447, 0x1144A,
@@ -567,6 +588,8 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x11A50, 0x11A97,
0x11A9D, 0x11A9D,
0x11AB0, 0x11AF8,
+ 0x11B60, 0x11B67,
+ 0x11BC0, 0x11BE0,
0x11C00, 0x11C08,
0x11C0A, 0x11C36,
0x11C38, 0x11C3E,
@@ -588,6 +611,7 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x11D90, 0x11D91,
0x11D93, 0x11D96,
0x11D98, 0x11D98,
+ 0x11DB0, 0x11DDB,
0x11EE0, 0x11EF6,
0x11F00, 0x11F10,
0x11F12, 0x11F3A,
@@ -599,7 +623,9 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x12F90, 0x12FF0,
0x13000, 0x1342F,
0x13441, 0x13446,
+ 0x13460, 0x143FA,
0x14400, 0x14646,
+ 0x16100, 0x1612E,
0x16800, 0x16A38,
0x16A40, 0x16A5E,
0x16A70, 0x16ABE,
@@ -608,16 +634,19 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x16B40, 0x16B43,
0x16B63, 0x16B77,
0x16B7D, 0x16B8F,
+ 0x16D40, 0x16D6C,
0x16E40, 0x16E7F,
+ 0x16EA0, 0x16EB8,
+ 0x16EBB, 0x16ED3,
0x16F00, 0x16F4A,
0x16F4F, 0x16F87,
0x16F8F, 0x16F9F,
0x16FE0, 0x16FE1,
0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
+ 0x16FF0, 0x16FF6,
+ 0x17000, 0x18CD5,
+ 0x18CFF, 0x18D1E,
+ 0x18D80, 0x18DF2,
0x1AFF0, 0x1AFF3,
0x1AFF5, 0x1AFFB,
0x1AFFD, 0x1AFFE,
@@ -677,6 +706,11 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1E290, 0x1E2AD,
0x1E2C0, 0x1E2EB,
0x1E4D0, 0x1E4EB,
+ 0x1E5D0, 0x1E5ED,
+ 0x1E5F0, 0x1E5F0,
+ 0x1E6C0, 0x1E6DE,
+ 0x1E6E0, 0x1E6F5,
+ 0x1E6FE, 0x1E6FF,
0x1E7E0, 0x1E7E6,
0x1E7E8, 0x1E7EB,
0x1E7ED, 0x1E7EE,
@@ -722,16 +756,16 @@ static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEP
0x1F150, 0x1F169,
0x1F170, 0x1F189,
0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
+ 0x2A700, 0x2B81D,
+ 0x2B820, 0x2CEAD,
0x2CEB0, 0x2EBE0,
+ 0x2EBF0, 0x2EE5D,
0x2F800, 0x2FA1D,
0x30000, 0x3134A,
- 0x31350, 0x323AF,
+ 0x31350, 0x33479,
};
-#define UNICODE_ALNUM_CODEPOINTS_LENGTH 1528
+#define UNICODE_ALNUM_CODEPOINTS_LENGTH 1598
static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = {
0x100, 0x2C1,
0x2C6, 0x2D1,
@@ -739,7 +773,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x2EC, 0x2EC,
0x2EE, 0x2EE,
0x345, 0x345,
- 0x370, 0x374,
+ 0x363, 0x374,
0x376, 0x377,
0x37A, 0x37D,
0x37F, 0x37F,
@@ -778,7 +812,8 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x840, 0x858,
0x860, 0x86A,
0x870, 0x887,
- 0x889, 0x88E,
+ 0x889, 0x88F,
+ 0x897, 0x897,
0x8A0, 0x8C9,
0x8D4, 0x8DF,
0x8E3, 0x8E9,
@@ -872,7 +907,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0xC4A, 0xC4C,
0xC55, 0xC56,
0xC58, 0xC5A,
- 0xC5D, 0xC5D,
+ 0xC5C, 0xC5D,
0xC60, 0xC63,
0xC66, 0xC6F,
0xC80, 0xC83,
@@ -885,7 +920,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0xCC6, 0xCC8,
0xCCA, 0xCCC,
0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
+ 0xCDC, 0xCDE,
0xCE0, 0xCE3,
0xCE6, 0xCEF,
0xCF1, 0xCF3,
@@ -1007,7 +1042,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1C00, 0x1C36,
0x1C40, 0x1C49,
0x1C4D, 0x1C7D,
- 0x1C80, 0x1C88,
+ 0x1C80, 0x1C8A,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
0x1CE9, 0x1CEC,
@@ -1015,7 +1050,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1CF5, 0x1CF6,
0x1CFA, 0x1CFA,
0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
+ 0x1DD3, 0x1DF4,
0x1E00, 0x1F15,
0x1F18, 0x1F1D,
0x1F20, 0x1F45,
@@ -1094,11 +1129,8 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0xA67F, 0xA6EF,
0xA717, 0xA71F,
0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
+ 0xA78B, 0xA7DC,
+ 0xA7F1, 0xA805,
0xA807, 0xA827,
0xA840, 0xA873,
0xA880, 0xA8C3,
@@ -1191,6 +1223,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x105A3, 0x105B1,
0x105B3, 0x105B9,
0x105BB, 0x105BC,
+ 0x105C0, 0x105F3,
0x10600, 0x10736,
0x10740, 0x10755,
0x10760, 0x10767,
@@ -1209,6 +1242,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x108F4, 0x108F5,
0x10900, 0x10915,
0x10920, 0x10939,
+ 0x10940, 0x10959,
0x10980, 0x109B7,
0x109BE, 0x109BF,
0x10A00, 0x10A03,
@@ -1229,9 +1263,14 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x10CC0, 0x10CF2,
0x10D00, 0x10D27,
0x10D30, 0x10D39,
+ 0x10D40, 0x10D65,
+ 0x10D69, 0x10D69,
+ 0x10D6F, 0x10D85,
0x10E80, 0x10EA9,
0x10EAB, 0x10EAC,
0x10EB0, 0x10EB1,
+ 0x10EC2, 0x10EC7,
+ 0x10EFA, 0x10EFC,
0x10F00, 0x10F1C,
0x10F27, 0x10F27,
0x10F30, 0x10F45,
@@ -1278,6 +1317,17 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11350, 0x11350,
0x11357, 0x11357,
0x1135D, 0x11363,
+ 0x11380, 0x11389,
+ 0x1138B, 0x1138B,
+ 0x1138E, 0x1138E,
+ 0x11390, 0x113B5,
+ 0x113B7, 0x113C0,
+ 0x113C2, 0x113C2,
+ 0x113C5, 0x113C5,
+ 0x113C7, 0x113CA,
+ 0x113CC, 0x113CD,
+ 0x113D1, 0x113D1,
+ 0x113D3, 0x113D3,
0x11400, 0x11441,
0x11443, 0x11445,
0x11447, 0x1144A,
@@ -1297,6 +1347,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11680, 0x116B5,
0x116B8, 0x116B8,
0x116C0, 0x116C9,
+ 0x116D0, 0x116E3,
0x11700, 0x1171A,
0x1171D, 0x1172A,
0x11730, 0x11739,
@@ -1322,6 +1373,9 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11A50, 0x11A97,
0x11A9D, 0x11A9D,
0x11AB0, 0x11AF8,
+ 0x11B60, 0x11B67,
+ 0x11BC0, 0x11BE0,
+ 0x11BF0, 0x11BF9,
0x11C00, 0x11C08,
0x11C0A, 0x11C36,
0x11C38, 0x11C3E,
@@ -1346,6 +1400,8 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x11D93, 0x11D96,
0x11D98, 0x11D98,
0x11DA0, 0x11DA9,
+ 0x11DB0, 0x11DDB,
+ 0x11DE0, 0x11DE9,
0x11EE0, 0x11EF6,
0x11F00, 0x11F10,
0x11F12, 0x11F3A,
@@ -1358,7 +1414,10 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x12F90, 0x12FF0,
0x13000, 0x1342F,
0x13441, 0x13446,
+ 0x13460, 0x143FA,
0x14400, 0x14646,
+ 0x16100, 0x1612E,
+ 0x16130, 0x16139,
0x16800, 0x16A38,
0x16A40, 0x16A5E,
0x16A60, 0x16A69,
@@ -1370,16 +1429,20 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x16B50, 0x16B59,
0x16B63, 0x16B77,
0x16B7D, 0x16B8F,
+ 0x16D40, 0x16D6C,
+ 0x16D70, 0x16D79,
0x16E40, 0x16E7F,
+ 0x16EA0, 0x16EB8,
+ 0x16EBB, 0x16ED3,
0x16F00, 0x16F4A,
0x16F4F, 0x16F87,
0x16F8F, 0x16F9F,
0x16FE0, 0x16FE1,
0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
+ 0x16FF0, 0x16FF6,
+ 0x17000, 0x18CD5,
+ 0x18CFF, 0x18D1E,
+ 0x18D80, 0x18DF2,
0x1AFF0, 0x1AFF3,
0x1AFF5, 0x1AFFB,
0x1AFFD, 0x1AFFE,
@@ -1394,6 +1457,7 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1BC80, 0x1BC88,
0x1BC90, 0x1BC99,
0x1BC9E, 0x1BC9E,
+ 0x1CCF0, 0x1CCF9,
0x1D400, 0x1D454,
0x1D456, 0x1D49C,
0x1D49E, 0x1D49F,
@@ -1443,6 +1507,11 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1E2F0, 0x1E2F9,
0x1E4D0, 0x1E4EB,
0x1E4F0, 0x1E4F9,
+ 0x1E5D0, 0x1E5ED,
+ 0x1E5F0, 0x1E5FA,
+ 0x1E6C0, 0x1E6DE,
+ 0x1E6E0, 0x1E6F5,
+ 0x1E6FE, 0x1E6FF,
0x1E7E0, 0x1E7E6,
0x1E7E8, 0x1E7EB,
0x1E7ED, 0x1E7EE,
@@ -1490,16 +1559,16 @@ static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEP
0x1F170, 0x1F189,
0x1FBF0, 0x1FBF9,
0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
+ 0x2A700, 0x2B81D,
+ 0x2B820, 0x2CEAD,
0x2CEB0, 0x2EBE0,
+ 0x2EBF0, 0x2EE5D,
0x2F800, 0x2FA1D,
0x30000, 0x3134A,
- 0x31350, 0x323AF,
+ 0x31350, 0x33479,
};
-#define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1302
+#define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1320
static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = {
0x100, 0x100,
0x102, 0x102,
@@ -1774,6 +1843,7 @@ static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_C
0x10C7, 0x10C7,
0x10CD, 0x10CD,
0x13A0, 0x13F5,
+ 0x1C89, 0x1C89,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
0x1E00, 0x1E00,
@@ -2103,9 +2173,15 @@ static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_C
0xA7C2, 0xA7C2,
0xA7C4, 0xA7C7,
0xA7C9, 0xA7C9,
+ 0xA7CB, 0xA7CC,
+ 0xA7CE, 0xA7CE,
0xA7D0, 0xA7D0,
+ 0xA7D2, 0xA7D2,
+ 0xA7D4, 0xA7D4,
0xA7D6, 0xA7D6,
0xA7D8, 0xA7D8,
+ 0xA7DA, 0xA7DA,
+ 0xA7DC, 0xA7DC,
0xA7F5, 0xA7F5,
0xFF21, 0xFF3A,
0x10400, 0x10427,
@@ -2115,8 +2191,10 @@ static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_C
0x1058C, 0x10592,
0x10594, 0x10595,
0x10C80, 0x10CB2,
+ 0x10D50, 0x10D65,
0x118A0, 0x118BF,
0x16E40, 0x16E5F,
+ 0x16EA0, 0x16EB8,
0x1D400, 0x1D419,
0x1D434, 0x1D44D,
0x1D468, 0x1D481,
@@ -2304,6 +2382,10 @@ pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n) {
*/
size_t
pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
}
@@ -2324,6 +2406,10 @@ pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
*/
size_t
pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
}
@@ -2344,6 +2430,10 @@ pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
*/
bool
pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
}
@@ -2362,7 +2452,8 @@ pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
static pm_unicode_codepoint_t
pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
- if (b[0] < 0x80) {
+
+ if ((n > 0) && (b[0] < 0x80)) {
*width = 1;
return (pm_unicode_codepoint_t) b[0];
}
@@ -2401,6 +2492,10 @@ pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
static size_t
pm_encoding_cesu_8_char_width(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
size_t width;
pm_cesu_8_codepoint(b, n, &width);
return width;
@@ -2408,6 +2503,10 @@ pm_encoding_cesu_8_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_cesu_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
}
@@ -2424,6 +2523,10 @@ pm_encoding_cesu_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_cesu_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
}
@@ -2440,6 +2543,10 @@ pm_encoding_cesu_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
static bool
pm_encoding_cesu_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
+
if (*b < 0x80) {
return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
}
@@ -3855,14 +3962,14 @@ static const uint8_t pm_encoding_windows_874_table[256] = {
};
#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 ## _alpha_char(const uint8_t *b, ptrdiff_t n) { \
+ return ((n > 0) && (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 size_t pm_encoding_ ##name ## _alnum_char(const uint8_t *b, ptrdiff_t n) { \
+ return ((n > 0) && (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); \
+ static bool pm_encoding_ ##name ## _isupper_char(const uint8_t *b, ptrdiff_t n) { \
+ return ((n > 0) && (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_UPPERCASE_BIT)); \
}
PRISM_ENCODING_TABLE(cp850)
@@ -3931,8 +4038,8 @@ PRISM_ENCODING_TABLE(windows_874)
* 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;
+pm_encoding_ascii_char_width(const uint8_t *b, ptrdiff_t n) {
+ return ((n > 0) && (*b < 0x80)) ? 1 : 0;
}
/**
@@ -3940,8 +4047,8 @@ pm_encoding_ascii_char_width(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t
* 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);
+pm_encoding_ascii_alpha_char(const uint8_t *b, ptrdiff_t n) {
+ return (n > 0) ? (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) : 0;
}
/**
@@ -3951,7 +4058,7 @@ pm_encoding_ascii_alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t
*/
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 ((n > 0) && (*b < 0x80)) ? pm_encoding_ascii_alpha_char(b, n) : 0;
}
/**
@@ -3959,8 +4066,8 @@ pm_encoding_ascii_alpha_char_7bit(const uint8_t *b, ptrdiff_t n) {
* 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;
+pm_encoding_ascii_alnum_char(const uint8_t *b, ptrdiff_t n) {
+ return ((n > 0) && (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
}
/**
@@ -3970,7 +4077,7 @@ pm_encoding_ascii_alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t
*/
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 ((n > 0) && (*b < 0x80)) ? pm_encoding_ascii_alnum_char(b, n) : 0;
}
/**
@@ -3978,8 +4085,8 @@ pm_encoding_ascii_alnum_char_7bit(const uint8_t *b, ptrdiff_t n) {
* 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);
+pm_encoding_ascii_isupper_char(const uint8_t *b, ptrdiff_t n) {
+ return (n > 0) && (pm_encoding_ascii_table[*b] & PRISM_ENCODING_UPPERCASE_BIT);
}
/**
@@ -3987,7 +4094,7 @@ pm_encoding_ascii_isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_
* 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) {
+pm_encoding_single_char_width(PRISM_UNUSED const uint8_t *b, PRISM_UNUSED ptrdiff_t n) {
return 1;
}
@@ -3998,7 +4105,7 @@ pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATT
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4042,6 +4149,9 @@ pm_encoding_euc_jp_isupper_char(const uint8_t *b, ptrdiff_t n) {
*/
static size_t
pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) {
+ if (n == 0) {
+ return 0;
+ }
// These are the single byte characters.
if (b[0] < 0x80 || (b[0] >= 0xA1 && b[0] <= 0xDF)) {
return 1;
@@ -4105,7 +4215,7 @@ pm_encoding_shift_jis_isupper_char(const uint8_t *b, ptrdiff_t n) {
*/
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);
+ return (n > 0) && (*b < 0x80) && pm_encoding_ascii_isupper_char(b, n);
}
/**
@@ -4115,7 +4225,7 @@ pm_encoding_ascii_isupper_char_7bit(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_big5_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the single byte characters.
- if (*b < 0x80) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4134,7 +4244,7 @@ pm_encoding_big5_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_cp949_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the single byte characters
- if (*b <= 0x80) {
+ if ((n > 0) && (*b <= 0x80)) {
return 1;
}
@@ -4153,7 +4263,7 @@ pm_encoding_cp949_char_width(const uint8_t *b, ptrdiff_t n) {
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4196,7 +4306,7 @@ pm_encoding_emacs_mule_char_width(const uint8_t *b, ptrdiff_t n) {
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4215,7 +4325,7 @@ pm_encoding_euc_kr_char_width(const uint8_t *b, ptrdiff_t n) {
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) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4239,7 +4349,7 @@ pm_encoding_euc_tw_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_gb18030_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the 1 byte characters.
- if (*b < 0x80) {
+ if ((n > 0) && (*b < 0x80)) {
return 1;
}
@@ -4263,7 +4373,7 @@ pm_encoding_gb18030_char_width(const uint8_t *b, ptrdiff_t n) {
static size_t
pm_encoding_gbk_char_width(const uint8_t *b, ptrdiff_t n) {
// These are the single byte characters.
- if (*b <= 0x80) {
+ if ((n > 0) && (*b <= 0x80)) {
return 1;
}
diff --git a/prism/encoding.h b/prism/encoding.h
deleted file mode 100644
index 5f7724821f..0000000000
--- a/prism/encoding.h
+++ /dev/null
@@ -1,283 +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.
- *
- * @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_char_width(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphabetical character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphanumeric character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return true if the next character in the UTF-8 encoding if it is an uppercase
- * character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns True if the next character is valid in the encoding and is an
- * uppercase character, or false if it is not.
- */
-bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * This lookup table is referenced in both the UTF-8 encoding file and the
- * parser directly in order to speed up the default encoding processing. It is
- * used to indicate whether a character is alphabetical, alphanumeric, or
- * uppercase in unicode mappings.
- */
-extern const uint8_t pm_encoding_unicode_table[256];
-
-/**
- * These are all of the encodings that prism supports.
- */
-typedef enum {
- PM_ENCODING_UTF_8 = 0,
- PM_ENCODING_US_ASCII,
- PM_ENCODING_ASCII_8BIT,
- PM_ENCODING_EUC_JP,
- PM_ENCODING_WINDOWS_31J,
-
-// We optionally support excluding the full set of encodings to only support the
-// minimum necessary to process Ruby code without encoding comments.
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- 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_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_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_874,
-#endif
-
- 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])
-
-/**
- * This is the ASCII-8BIT encoding. We need a reference to it so that pm_strpbrk
- * can compare against it because invalid multibyte characters are not a thing
- * in this encoding. It is also needed for handling Regexp encoding flags.
- */
-#define PM_ENCODING_ASCII_8BIT_ENTRY (&pm_encodings[PM_ENCODING_ASCII_8BIT])
-
-/**
- * This is the EUC-JP encoding. We need a reference to it to quickly process
- * regular expression modifiers.
- */
-#define PM_ENCODING_EUC_JP_ENTRY (&pm_encodings[PM_ENCODING_EUC_JP])
-
-/**
- * This is the Windows-31J encoding. We need a reference to it to quickly
- * process regular expression modifiers.
- */
-#define PM_ENCODING_WINDOWS_31J_ENTRY (&pm_encodings[PM_ENCODING_WINDOWS_31J])
-
-/**
- * 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/excludes.h b/prism/excludes.h
new file mode 100644
index 0000000000..8600622f63
--- /dev/null
+++ b/prism/excludes.h
@@ -0,0 +1,29 @@
+/**
+ * @file excludes.h
+ *
+ * A header file that defines macros to exclude certain features of the prism
+ * library. This is useful for reducing the size of the library when certain
+ * features are not needed.
+ */
+#ifndef PRISM_EXCLUDES_H
+#define PRISM_EXCLUDES_H
+
+/**
+ * If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible
+ * switch that will turn off certain features of prism.
+ */
+#ifdef PRISM_BUILD_MINIMAL
+ /** Exclude the serialization API. */
+ #define PRISM_EXCLUDE_SERIALIZATION
+
+ /** Exclude the JSON serialization API. */
+ #define PRISM_EXCLUDE_JSON
+
+ /** Exclude the prettyprint API. */
+ #define PRISM_EXCLUDE_PRETTYPRINT
+
+ /** Exclude the full set of encodings, using the minimal only. */
+ #define PRISM_ENCODING_EXCLUDE_FULL
+#endif
+
+#endif
diff --git a/prism/extension.c b/prism/extension.c
index 1533ca7bb3..27df8dac50 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -4,6 +4,8 @@
#include <ruby/win32.h>
#endif
+#include <errno.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.
@@ -25,6 +27,7 @@ VALUE rb_cPrismLexResult;
VALUE rb_cPrismParseLexResult;
VALUE rb_cPrismStringQuery;
VALUE rb_cPrismScope;
+VALUE rb_cPrismCurrentVersionError;
VALUE rb_cPrismDebugEncoding;
@@ -63,18 +66,6 @@ check_string(VALUE value) {
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 */
@@ -147,10 +138,8 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
// Initialize the scope array.
size_t locals_count = RARRAY_LEN(locals);
- pm_options_scope_t *options_scope = &options->scopes[scope_index];
- if (!pm_options_scope_init(options_scope, locals_count)) {
- rb_raise(rb_eNoMemError, "failed to allocate memory");
- }
+ pm_options_scope_t *options_scope = pm_options_scope_mut(options, 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++) {
@@ -163,7 +152,7 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
}
// Add the local to the scope.
- pm_string_t *scope_local = &options_scope->locals[local_index];
+ pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index);
const char *name = rb_id2name(SYM2ID(local));
pm_string_constant_init(scope_local, name, strlen(name));
}
@@ -199,7 +188,21 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
if (!NIL_P(value)) {
const char *version = check_string(value);
- if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
+ if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
+ if (!pm_options_version_set(options, ruby_version, 3)) {
+ rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, ruby_version));
+ }
+ } else if (RSTRING_LEN(value) == 7 && strncmp(version, "nearest", 7) == 0) {
+ if (!pm_options_version_set(options, ruby_version, 3)) {
+ // Prism doesn't know this specific version. Is it lower?
+ if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
+ pm_options_version_set_lowest(options);
+ } else {
+ // Must be higher.
+ pm_options_version_set_highest(options);
+ }
+ }
+ } else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
}
}
@@ -263,7 +266,7 @@ build_options(VALUE argument) {
*/
static void
extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
- options->line = 1; // default
+ pm_options_line_set(options, 1); /* default */
if (!NIL_P(keywords)) {
struct build_options_data data = { .options = options, .keywords = keywords };
@@ -291,36 +294,46 @@ extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
/**
* 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) {
+static VALUE
+string_options(int argc, VALUE *argv, pm_options_t *options) {
VALUE string;
VALUE keywords;
rb_scan_args(argc, argv, "1:", &string, &keywords);
+ if (!RB_TYPE_P(string, T_STRING)) {
+ pm_options_free(options);
+ rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(string));
+ }
+
extract_options(options, Qnil, keywords);
- input_load_string(input, string);
+ return string;
}
/**
* Read options for methods that look like (filepath, **options).
*/
-static void
-file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, VALUE *encoded_filepath) {
+static pm_source_t *
+file_options(int argc, VALUE *argv, pm_options_t *options, VALUE *encoded_filepath) {
VALUE filepath;
VALUE keywords;
rb_scan_args(argc, argv, "1:", &filepath, &keywords);
- Check_Type(filepath, T_STRING);
+ 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));
+ }
+
*encoded_filepath = rb_str_encode_ospath(filepath);
extract_options(options, *encoded_filepath, keywords);
- const char *source = (const char *) pm_string_source(&options->filepath);
- pm_string_init_result_t result;
+ const char *source = (const char *) pm_string_source(pm_options_filepath(options));
+ pm_source_init_result_t result;
+ pm_source_t *pm_src = pm_source_file_new(source, &result);
- switch (result = pm_string_file_init(input, source)) {
- case PM_STRING_INIT_SUCCESS:
+ switch (result) {
+ case PM_SOURCE_INIT_SUCCESS:
break;
- case PM_STRING_INIT_ERROR_GENERIC: {
+ case PM_SOURCE_INIT_ERROR_GENERIC: {
pm_options_free(options);
#ifdef _WIN32
@@ -332,7 +345,7 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
rb_syserr_fail(e, source);
break;
}
- case PM_STRING_INIT_ERROR_DIRECTORY:
+ case PM_SOURCE_INIT_ERROR_DIRECTORY:
pm_options_free(options);
rb_syserr_fail(EISDIR, source);
break;
@@ -341,6 +354,8 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
rb_raise(rb_eRuntimeError, "Unknown error (%d) initializing file: %s", result, source);
break;
}
+
+ return pm_src;
}
#ifndef PRISM_EXCLUDE_SERIALIZATION
@@ -353,77 +368,82 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
* 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)) {
+dump_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_buffer_t *buffer = pm_buffer_new();
+ if (!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_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- pm_serialize(&parser, node, &buffer);
+ 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);
+ VALUE result = rb_str_new(pm_buffer_value(buffer), pm_buffer_length(buffer));
+ pm_buffer_free(buffer);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::dump(source, **options) -> String
+ * dump(source, **options) -> String
*
* Dump the AST corresponding to the given string to a string. For supported
- * options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
+
+ const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
+ size_t length = RSTRING_LEN(string);
#ifdef PRISM_BUILD_DEBUG
- size_t length = pm_string_length(&input);
char* dup = xmalloc(length);
- memcpy(dup, pm_string_source(&input), length);
- pm_string_constant_init(&input, dup, length);
+ memcpy(dup, source, length);
+ source = (const uint8_t *) dup;
#endif
- VALUE value = dump_input(&input, &options);
- if (options.freeze) rb_obj_freeze(value);
+ VALUE value = dump_input(source, length, options);
+ if (pm_options_freeze(options)) rb_obj_freeze(value);
#ifdef PRISM_BUILD_DEBUG
+#ifdef xfree_sized
+ xfree_sized(dup, length);
+#else
xfree(dup);
#endif
+#endif
- pm_string_free(&input);
- pm_options_free(&options);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::dump_file(filepath, **options) -> String
+ * dump_file(filepath, **options) -> String
*
* Dump the AST corresponding to the given file to a string. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
dump_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = dump_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = dump_input(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -449,42 +469,49 @@ rb_class_new_instance_freeze(int argc, const VALUE *argv, VALUE klass, bool free
* Create a new Location instance from the given parser and bounds.
*/
static inline VALUE
-parser_location(const pm_parser_t *parser, VALUE source, bool freeze, const uint8_t *start, size_t length) {
- VALUE argv[] = { source, LONG2FIX(start - parser->start), LONG2FIX(length) };
+parser_location(VALUE source, bool freeze, uint32_t start, uint32_t length) {
+ VALUE argv[] = { source, LONG2FIX(start), LONG2FIX(length) };
return rb_class_new_instance_freeze(3, argv, rb_cPrismLocation, freeze);
}
/**
* Create a new Location instance from the given parser and location.
*/
-#define PARSER_LOCATION_LOC(parser, source, freeze, loc) \
- parser_location(parser, source, freeze, loc.start, (size_t) (loc.end - loc.start))
+#define PARSER_LOCATION(source, freeze, location) \
+ parser_location(source, freeze, location.start, location.length)
/**
* Build a new Comment instance from the given parser and comment.
*/
static inline VALUE
-parser_comment(const pm_parser_t *parser, VALUE source, bool freeze, const pm_comment_t *comment) {
- VALUE argv[] = { PARSER_LOCATION_LOC(parser, source, freeze, comment->location) };
- VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
+parser_comment(VALUE source, bool freeze, const pm_comment_t *comment) {
+ VALUE argv[] = { PARSER_LOCATION(source, freeze, pm_comment_location(comment)) };
+ VALUE type = (pm_comment_type(comment) == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
return rb_class_new_instance_freeze(1, argv, type, freeze);
}
+typedef struct {
+ VALUE comments;
+ VALUE source;
+ bool freeze;
+} parser_comments_each_data_t;
+
+static void
+parser_comments_each(const pm_comment_t *comment, void *data) {
+ parser_comments_each_data_t *each_data = (parser_comments_each_data_t *) data;
+ VALUE value = parser_comment(each_data->source, each_data->freeze, comment);
+ rb_ary_push(each_data->comments, value);
+}
+
/**
* Extract the comments out of the parser into an array.
*/
static VALUE
parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
- VALUE comments = rb_ary_new_capa(parser->comment_list.size);
-
- for (
- const pm_comment_t *comment = (const pm_comment_t *) parser->comment_list.head;
- comment != NULL;
- comment = (const pm_comment_t *) comment->node.next
- ) {
- VALUE value = parser_comment(parser, source, freeze, comment);
- rb_ary_push(comments, value);
- }
+ VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser));
+
+ parser_comments_each_data_t each_data = { comments, source, freeze };
+ pm_parser_comments_each(parser, parser_comments_each, &each_data);
if (freeze) rb_obj_freeze(comments);
return comments;
@@ -494,28 +521,39 @@ parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
* Build a new MagicComment instance from the given parser and magic comment.
*/
static inline VALUE
-parser_magic_comment(const pm_parser_t *parser, VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
- VALUE key_loc = parser_location(parser, source, freeze, magic_comment->key_start, magic_comment->key_length);
- VALUE value_loc = parser_location(parser, source, freeze, magic_comment->value_start, magic_comment->value_length);
+parser_magic_comment(VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
+ pm_location_t key = pm_magic_comment_key(magic_comment);
+ pm_location_t value = pm_magic_comment_value(magic_comment);
+
+ VALUE key_loc = parser_location(source, freeze, key.start, key.length);
+ VALUE value_loc = parser_location(source, freeze, value.start, value.length);
+
VALUE argv[] = { key_loc, value_loc };
return rb_class_new_instance_freeze(2, argv, rb_cPrismMagicComment, freeze);
}
+typedef struct {
+ VALUE magic_comments;
+ VALUE source;
+ bool freeze;
+} parser_magic_comments_each_data_t;
+
+static void
+parser_magic_comments_each(const pm_magic_comment_t *magic_comment, void *data) {
+ parser_magic_comments_each_data_t *each_data = (parser_magic_comments_each_data_t *) data;
+ VALUE value = parser_magic_comment(each_data->source, each_data->freeze, magic_comment);
+ rb_ary_push(each_data->magic_comments, value);
+}
+
/**
* Extract the magic comments out of the parser into an array.
*/
static VALUE
parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
- VALUE magic_comments = rb_ary_new_capa(parser->magic_comment_list.size);
-
- for (
- const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) parser->magic_comment_list.head;
- magic_comment != NULL;
- magic_comment = (const pm_magic_comment_t *) magic_comment->node.next
- ) {
- VALUE value = parser_magic_comment(parser, source, freeze, magic_comment);
- rb_ary_push(magic_comments, value);
- }
+ VALUE magic_comments = rb_ary_new_capa(pm_parser_magic_comments_size(parser));
+
+ parser_magic_comments_each_data_t each_data = { magic_comments, source, freeze };
+ pm_parser_magic_comments_each(parser, parser_magic_comments_each, &each_data);
if (freeze) rb_obj_freeze(magic_comments);
return magic_comments;
@@ -527,85 +565,109 @@ parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
*/
static VALUE
parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
- if (parser->data_loc.end == NULL) {
+ const pm_location_t *data_loc = pm_parser_data_loc(parser);
+
+ if (data_loc->length == 0) {
return Qnil;
} else {
- return PARSER_LOCATION_LOC(parser, source, freeze, parser->data_loc);
+ return parser_location(source, freeze, data_loc->start, data_loc->length);
}
}
+typedef struct {
+ VALUE errors;
+ rb_encoding *encoding;
+ VALUE source;
+ bool freeze;
+} parser_errors_each_data_t;
+
+static void
+parser_errors_each(const pm_diagnostic_t *diagnostic, void *data) {
+ parser_errors_each_data_t *each_data = (parser_errors_each_data_t *) data;
+
+ VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
+ VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
+ VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
+
+ pm_error_level_t error_level = pm_diagnostic_error_level(diagnostic);
+ VALUE level = Qnil;
+
+ switch (error_level) {
+ case PM_ERROR_LEVEL_SYNTAX:
+ level = ID2SYM(rb_intern("syntax"));
+ break;
+ case PM_ERROR_LEVEL_ARGUMENT:
+ level = ID2SYM(rb_intern("argument"));
+ break;
+ case PM_ERROR_LEVEL_LOAD:
+ level = ID2SYM(rb_intern("load"));
+ break;
+ default:
+ rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error_level);
+ }
+
+ VALUE argv[] = { type, message, location, level };
+ VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, each_data->freeze);
+ rb_ary_push(each_data->errors, value);
+}
+
/**
* Extract the errors out of the parser into an array.
*/
static VALUE
parser_errors(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
- VALUE errors = rb_ary_new_capa(parser->error_list.size);
-
- for (
- const pm_diagnostic_t *error = (const pm_diagnostic_t *) parser->error_list.head;
- error != NULL;
- error = (const pm_diagnostic_t *) error->node.next
- ) {
- VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(error->diag_id)));
- VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(error->message, encoding));
- VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, error->location);
-
- VALUE level = Qnil;
- switch (error->level) {
- case PM_ERROR_LEVEL_SYNTAX:
- level = ID2SYM(rb_intern("syntax"));
- break;
- case PM_ERROR_LEVEL_ARGUMENT:
- level = ID2SYM(rb_intern("argument"));
- break;
- case PM_ERROR_LEVEL_LOAD:
- level = ID2SYM(rb_intern("load"));
- break;
- default:
- rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error->level);
- }
+ VALUE errors = rb_ary_new_capa(pm_parser_errors_size(parser));
- VALUE argv[] = { type, message, location, level };
- VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, freeze);
- rb_ary_push(errors, value);
- }
+ parser_errors_each_data_t each_data = { errors, encoding, source, freeze };
+ pm_parser_errors_each(parser, parser_errors_each, &each_data);
if (freeze) rb_obj_freeze(errors);
return errors;
}
+typedef struct {
+ VALUE warnings;
+ rb_encoding *encoding;
+ VALUE source;
+ bool freeze;
+} parser_warnings_each_data_t;
+
+static void
+parser_warnings_each(const pm_diagnostic_t *diagnostic, void *data) {
+ parser_warnings_each_data_t *each_data = (parser_warnings_each_data_t *) data;
+
+ VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
+ VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
+ VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
+
+ pm_warning_level_t warning_level = pm_diagnostic_warning_level(diagnostic);
+ VALUE level = Qnil;
+
+ switch (warning_level) {
+ case PM_WARNING_LEVEL_DEFAULT:
+ level = ID2SYM(rb_intern("default"));
+ break;
+ case PM_WARNING_LEVEL_VERBOSE:
+ level = ID2SYM(rb_intern("verbose"));
+ break;
+ default:
+ rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning_level);
+ }
+
+ VALUE argv[] = { type, message, location, level };
+ VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, each_data->freeze);
+ rb_ary_push(each_data->warnings, value);
+}
+
/**
* Extract the warnings out of the parser into an array.
*/
static VALUE
parser_warnings(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
- VALUE warnings = rb_ary_new_capa(parser->warning_list.size);
-
- for (
- const pm_diagnostic_t *warning = (const pm_diagnostic_t *) parser->warning_list.head;
- warning != NULL;
- warning = (const pm_diagnostic_t *) warning->node.next
- ) {
- VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(warning->diag_id)));
- VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(warning->message, encoding));
- VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, warning->location);
-
- VALUE level = Qnil;
- switch (warning->level) {
- case PM_WARNING_LEVEL_DEFAULT:
- level = ID2SYM(rb_intern("default"));
- break;
- case PM_WARNING_LEVEL_VERBOSE:
- level = ID2SYM(rb_intern("verbose"));
- break;
- default:
- rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning->level);
- }
+ VALUE warnings = rb_ary_new_capa(pm_parser_warnings_size(parser));
- VALUE argv[] = { type, message, location, level };
- VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, freeze);
- rb_ary_push(warnings, value);
- }
+ parser_warnings_each_data_t each_data = { warnings, encoding, source, freeze };
+ pm_parser_warnings_each(parser, parser_warnings_each, &each_data);
if (freeze) rb_obj_freeze(warnings);
return warnings;
@@ -623,10 +685,11 @@ parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_enco
parser_data_loc(parser, source, freeze),
parser_errors(parser, encoding, source, freeze),
parser_warnings(parser, encoding, source, freeze),
+ pm_parser_continuable(parser) ? Qtrue : Qfalse,
source
};
- return rb_class_new_instance_freeze(7, result_argv, class, freeze);
+ return rb_class_new_instance_freeze(8, result_argv, class, freeze);
}
/******************************************************************************/
@@ -651,11 +714,11 @@ typedef struct {
* 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;
+parse_lex_token(pm_parser_t *parser, pm_token_t *token, void *data) {
+ parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) data;
VALUE value = pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source, parse_lex_data->freeze);
- VALUE yields = rb_assoc_new(value, INT2FIX(parser->lex_state));
+ VALUE yields = rb_assoc_new(value, INT2FIX(pm_parser_lex_state(parser)));
if (parse_lex_data->freeze) {
rb_obj_freeze(value);
@@ -672,8 +735,8 @@ parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
*/
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);
+ parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) pm_parser_lex_callback_data(parser);
+ parse_lex_data->encoding = rb_enc_find(pm_parser_encoding_name(parser));
// 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
@@ -718,43 +781,38 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) {
* 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);
+parse_lex_input(const uint8_t *input, size_t input_length, const pm_options_t *options, bool return_nodes) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
+ pm_parser_encoding_changed_callback_set(parser, parse_lex_encoding_changed_callback);
- VALUE source_string = rb_str_new((const char *) pm_string_source(input), pm_string_length(input));
- VALUE offsets = rb_ary_new_capa(parser.newline_list.size);
- VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(parser.start_line), offsets);
+ VALUE source_string = rb_str_new((const char *) input, input_length);
+ VALUE offsets = rb_ary_new_capa(pm_parser_line_offsets(parser)->size);
+ VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets);
parse_lex_data_t parse_lex_data = {
.source = source,
.tokens = rb_ary_new(),
- .encoding = rb_utf8_encoding(),
- .freeze = options->freeze,
+ .encoding = rb_enc_find(pm_parser_encoding_name(parser)),
+ .freeze = pm_options_freeze(options),
};
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,
- };
+ pm_parser_lex_callback_set(parser, parse_lex_token, data);
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
+ pm_node_t *node = pm_parse(parser);
- // Here we need to update the Source object to have the correct
- // encoding for the source string and the correct newline offsets.
- // We do it here because we've already created the Source object and given
- // it over to all of the tokens, and both of these are only set after pm_parse().
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ /* Update the Source object with the correct encoding and line offsets,
+ * which are only available after pm_parse() completes. */
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
rb_enc_associate(source_string, encoding);
- for (size_t index = 0; index < parser.newline_list.size; index++) {
- rb_ary_push(offsets, ULONG2NUM(parser.newline_list.offsets[index]));
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ for (size_t index = 0; index < line_offsets->size; index++) {
+ rb_ary_store(offsets, (long) index, ULONG2NUM(line_offsets->offsets[index]));
}
- if (options->freeze) {
+ if (pm_options_freeze(options)) {
rb_obj_freeze(source_string);
rb_obj_freeze(offsets);
rb_obj_freeze(source);
@@ -764,58 +822,57 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
VALUE result;
if (return_nodes) {
VALUE value = rb_ary_new_capa(2);
- rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding, source, options->freeze));
+ rb_ary_push(value, pm_ast_new(parser, node, parse_lex_data.encoding, source, pm_options_freeze(options)));
rb_ary_push(value, parse_lex_data.tokens);
- if (options->freeze) rb_obj_freeze(value);
- result = parse_result_create(rb_cPrismParseLexResult, &parser, value, parse_lex_data.encoding, source, options->freeze);
+ if (pm_options_freeze(options)) rb_obj_freeze(value);
+ result = parse_result_create(rb_cPrismParseLexResult, parser, value, parse_lex_data.encoding, source, pm_options_freeze(options));
} else {
- result = parse_result_create(rb_cPrismLexResult, &parser, parse_lex_data.tokens, parse_lex_data.encoding, source, options->freeze);
+ result = parse_result_create(rb_cPrismLexResult, parser, parse_lex_data.tokens, parse_lex_data.encoding, source, pm_options_freeze(options));
}
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::lex(source, **options) -> LexResult
+ * lex(source, **options) -> LexResult
*
* Return a LexResult instance that contains an array of Token instances
- * corresponding to the given string. For supported options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE result = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, false);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::lex_file(filepath, **options) -> LexResult
+ * lex_file(filepath, **options) -> LexResult
*
* Return a LexResult instance that contains an array of Token instances
- * corresponding to the given file. For supported options, see Prism::parse.
+ * 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 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, false);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -828,30 +885,32 @@ lex_file(int argc, VALUE *argv, VALUE self) {
* 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);
+parse_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ pm_node_t *node = pm_parse(parser);
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
- VALUE source = pm_source_new(&parser, encoding, options->freeze);
- VALUE value = pm_ast_new(&parser, node, encoding, source, options->freeze);
- VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options->freeze);
+ bool freeze = pm_options_freeze(options);
+ VALUE source = pm_source_new(parser, encoding, freeze);
+ VALUE value = pm_ast_new(parser, node, encoding, source, freeze);
+ VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, freeze);
- if (options->freeze) {
+ if (freeze) {
rb_obj_freeze(source);
}
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse(source, **options) -> ParseResult
+ * parse(source, **options) -> ParseResult
*
* Parse the given string and return a ParseResult instance. The options that
* are supported are:
@@ -888,51 +947,57 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
* version of Ruby syntax (which you can trigger with `nil` or
* `"latest"`). You may also restrict the syntax to a specific version of
* Ruby, e.g., with `"3.3.0"`. To parse with the same syntax version that
- * the current Ruby is running use `version: RUBY_VERSION`. Raises
- * ArgumentError if the version is not currently supported by Prism.
+ * the current Ruby is running use `version: "current"`. To parse with the
+ * nearest version to the current Ruby that is running, use
+ * `version: "nearest"`. Raises ArgumentError if the version is not
+ * currently supported by Prism.
*/
static VALUE
parse(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
+
+ const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
+ size_t length = RSTRING_LEN(string);
#ifdef PRISM_BUILD_DEBUG
- size_t length = pm_string_length(&input);
char* dup = xmalloc(length);
- memcpy(dup, pm_string_source(&input), length);
- pm_string_constant_init(&input, dup, length);
+ memcpy(dup, source, length);
+ source = (const uint8_t *) dup;
#endif
- VALUE value = parse_input(&input, &options);
+ VALUE value = parse_input(source, length, options);
#ifdef PRISM_BUILD_DEBUG
+#ifdef xfree_sized
+ xfree_sized(dup, length);
+#else
xfree(dup);
#endif
+#endif
- pm_string_free(&input);
- pm_options_free(&options);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file(filepath, **options) -> ParseResult
+ * parse_file(filepath, **options) -> ParseResult
*
* Parse the given file and return a ParseResult instance. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
parse_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_input(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -941,59 +1006,66 @@ parse_file(int argc, VALUE *argv, VALUE self) {
* Parse the given input and return nothing.
*/
static void
-profile_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);
+profile_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parse(parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::profile(source, **options) -> nil
+ * profile(source, **options) -> nil
*
* Parse the given string and return nothing. This method is meant to allow
* profilers to avoid the overhead of reifying the AST to Ruby. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
profile(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- string_options(argc, argv, &input, &options);
- profile_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ profile_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
+ pm_options_free(options);
return Qnil;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::profile_file(filepath, **options) -> nil
+ * profile_file(filepath, **options) -> nil
*
* Parse the given file and return nothing. This method is meant to allow
* profilers to avoid the overhead of reifying the AST to Ruby. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
profile_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- profile_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ profile_input(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return Qnil;
}
+static int
+parse_stream_eof(void *stream) {
+ if (rb_funcall((VALUE) stream, rb_intern("eof?"), 0)) {
+ return 1;
+ }
+ return 0;
+}
+
/**
* An implementation of fgets that is suitable for use with Ruby IO objects.
*/
@@ -1016,11 +1088,12 @@ parse_stream_fgets(char *string, int size, void *stream) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_stream(stream, **options) -> ParseResult
+ * parse_stream(stream, **options) -> ParseResult
*
* Parse the given object that responds to `gets` and return a ParseResult
- * instance. The options that are supported are the same as Prism::parse.
+ * instance. The options that are supported are the same as Prism.parse.
*/
static VALUE
parse_stream(int argc, VALUE *argv, VALUE self) {
@@ -1028,22 +1101,24 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
VALUE keywords;
rb_scan_args(argc, argv, "1:", &stream, &keywords);
- pm_options_t options = { 0 };
- extract_options(&options, Qnil, keywords);
+ pm_options_t *options = pm_options_new();
+ extract_options(options, Qnil, keywords);
- pm_parser_t parser;
- pm_buffer_t buffer;
+ pm_source_t *src = pm_source_stream_new((void *) stream, parse_stream_fgets, parse_stream_eof);
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser;
- pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, &options);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ pm_node_t *node = pm_parse_stream(&parser, arena, src, options);
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
- VALUE source = pm_source_new(&parser, encoding, options.freeze);
- VALUE value = pm_ast_new(&parser, node, encoding, source, options.freeze);
- VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options.freeze);
+ VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options));
+ VALUE value = pm_ast_new(parser, node, encoding, source, pm_options_freeze(options));
+ VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, pm_options_freeze(options));
- pm_node_destroy(&parser, node);
- pm_buffer_free(&buffer);
- pm_parser_free(&parser);
+ pm_source_free(src);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
+ pm_options_free(options);
return result;
}
@@ -1052,116 +1127,114 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
* 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);
+parse_input_comments(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
+ pm_parse(parser);
+ rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
- VALUE source = pm_source_new(&parser, encoding, options->freeze);
- VALUE comments = parser_comments(&parser, source, options->freeze);
+ VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options));
+ VALUE comments = parser_comments(parser, source, pm_options_freeze(options));
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return comments;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_comments(source, **options) -> Array
+ * parse_comments(source, **options) -> Array
*
* Parse the given string and return an array of Comment objects. For supported
- * options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE result = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_input_comments((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file_comments(filepath, **options) -> Array
+ * parse_file_comments(filepath, **options) -> Array
*
* Parse the given file and return an array of Comment objects. For supported
- * options, see Prism::parse.
+ * options, see Prism.parse.
*/
static VALUE
parse_file_comments(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_input_comments(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_lex(source, **options) -> ParseLexResult
+ * parse_lex(source, **options) -> ParseLexResult
*
* Parse the given string and return a ParseLexResult 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.
+ * the tokens. If you only need one or the other, use either Prism.parse or
+ * Prism.lex.
*
- * For supported options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, true);
+ pm_options_free(options);
return value;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_lex_file(filepath, **options) -> ParseLexResult
+ * parse_lex_file(filepath, **options) -> ParseLexResult
*
* Parse the given file and return a ParseLexResult 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.
+ * 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.
+ * 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 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, true);
+ pm_source_free(src);
+ pm_options_free(options);
return value;
}
@@ -1170,45 +1243,45 @@ parse_lex_file(int argc, VALUE *argv, VALUE self) {
* 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);
+parse_input_success_p(const uint8_t *input, size_t input_length, const pm_options_t *options) {
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
+ pm_parse(parser);
- VALUE result = parser.error_list.size == 0 ? Qtrue : Qfalse;
- pm_parser_free(&parser);
+ VALUE result = pm_parser_errors_size(parser) == 0 ? Qtrue : Qfalse;
+ pm_parser_free(parser);
+ pm_arena_free(arena);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_success?(source, **options) -> bool
+ * parse_success?(source, **options) -> bool
*
* Parse the given string and return true if it parses without errors. For
- * supported options, see Prism::parse.
+ * 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);
+ pm_options_t *options = pm_options_new();
+ VALUE string = string_options(argc, argv, options);
- VALUE result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_input_success_p((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_failure?(source, **options) -> bool
+ * parse_failure?(source, **options) -> bool
*
* Parse the given string and return true if it parses with errors. For
- * supported options, see Prism::parse.
+ * supported options, see Prism.parse.
*/
static VALUE
parse_failure_p(int argc, VALUE *argv, VALUE self) {
@@ -1216,33 +1289,34 @@ parse_failure_p(int argc, VALUE *argv, VALUE self) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file_success?(filepath, **options) -> bool
+ * parse_file_success?(filepath, **options) -> bool
*
* Parse the given file and return true if it parses without errors. For
- * supported options, see Prism::parse.
+ * 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 };
+ pm_options_t *options = pm_options_new();
VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
+ pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
- VALUE result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
+ VALUE result = parse_input_success_p(pm_source_source(src), pm_source_length(src), options);
+ pm_source_free(src);
+ pm_options_free(options);
return result;
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::parse_file_failure?(filepath, **options) -> bool
+ * parse_file_failure?(filepath, **options) -> bool
*
* Parse the given file and return true if it parses with errors. For
- * supported options, see Prism::parse.
+ * supported options, see Prism.parse.
*/
static VALUE
parse_file_failure_p(int argc, VALUE *argv, VALUE self) {
@@ -1272,8 +1346,9 @@ string_query(pm_string_query_t result) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::StringQuery::local?(string) -> bool
+ * local?(string) -> bool
*
* Returns true if the string constitutes a valid local variable name. Note that
* this means the names that can be set through Binding#local_variable_set, not
@@ -1286,8 +1361,9 @@ string_query_local_p(VALUE self, VALUE string) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::StringQuery::constant?(string) -> bool
+ * constant?(string) -> bool
*
* Returns true if the string constitutes a valid constant name. Note that this
* means the names that can be set through Module#const_set, not necessarily the
@@ -1300,8 +1376,9 @@ string_query_constant_p(VALUE self, VALUE string) {
}
/**
+ * :markup: markdown
* call-seq:
- * Prism::StringQuery::method_name?(string) -> bool
+ * method_name?(string) -> bool
*
* Returns true if the string constitutes a valid method name.
*/
@@ -1356,6 +1433,8 @@ Init_prism(void) {
rb_cPrismStringQuery = rb_define_class_under(rb_cPrism, "StringQuery", rb_cObject);
rb_cPrismScope = rb_define_class_under(rb_cPrism, "Scope", rb_cObject);
+ rb_cPrismCurrentVersionError = rb_const_get(rb_cPrism, rb_intern("CurrentVersionError"));
+
// Intern all of the IDs eagerly that we support so that we don't have to do
// it every time we parse.
rb_id_option_command_line = rb_intern_const("command_line");
@@ -1407,5 +1486,4 @@ Init_prism(void) {
// Next, initialize the other APIs.
Init_prism_api_node();
- Init_prism_pack();
}
diff --git a/prism/extension.h b/prism/extension.h
index 506da2fd6f..d0cbc2ff53 100644
--- a/prism/extension.h
+++ b/prism/extension.h
@@ -1,10 +1,11 @@
#ifndef PRISM_EXT_NODE_H
#define PRISM_EXT_NODE_H
-#define EXPECTED_PRISM_VERSION "1.4.0"
+#define EXPECTED_PRISM_VERSION "1.9.0"
#include <ruby.h>
#include <ruby/encoding.h>
+#include <ruby/version.h>
#include "prism.h"
VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze);
@@ -13,7 +14,6 @@ VALUE pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *
VALUE pm_integer_new(const pm_integer_t *integer);
void Init_prism_api_node(void);
-void Init_prism_pack(void);
RUBY_FUNC_EXPORTED void Init_prism(void);
#endif
diff --git a/prism/integer.c b/prism/integer.c
new file mode 100644
index 0000000000..1b69dbdceb
--- /dev/null
+++ b/prism/integer.c
@@ -0,0 +1,681 @@
+#include "prism/internal/integer.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/buffer.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Free the internal memory of an integer. This memory will only be allocated if
+ * the integer exceeds the size of a single uint32_t.
+ */
+static void
+pm_integer_free(pm_integer_t *integer) {
+ if (integer->values) {
+ xfree(integer->values);
+ }
+}
+
+/**
+ * Pull out the length and values from the integer, regardless of the form in
+ * which the length/values are stored.
+ */
+#define INTEGER_EXTRACT(integer, length_variable, values_variable) \
+ if ((integer)->values == NULL) { \
+ length_variable = 1; \
+ values_variable = &(integer)->value; \
+ } else { \
+ length_variable = (integer)->length; \
+ values_variable = (integer)->values; \
+ }
+
+/**
+ * Adds two positive pm_integer_t with the given base.
+ * Return pm_integer_t with values allocated. Not normalized.
+ */
+static void
+big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) {
+ size_t left_length;
+ uint32_t *left_values;
+ INTEGER_EXTRACT(left, left_length, left_values)
+
+ size_t right_length;
+ uint32_t *right_values;
+ INTEGER_EXTRACT(right, right_length, right_values)
+
+ size_t length = left_length < right_length ? right_length : left_length;
+ uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * (length + 1));
+ if (values == NULL) return;
+
+ uint64_t carry = 0;
+ for (size_t index = 0; index < length; index++) {
+ uint64_t sum = carry + (index < left_length ? left_values[index] : 0) + (index < right_length ? right_values[index] : 0);
+ values[index] = (uint32_t) (sum % base);
+ carry = sum / base;
+ }
+
+ if (carry > 0) {
+ values[length] = (uint32_t) carry;
+ length++;
+ }
+
+ *destination = (pm_integer_t) { length, values, 0, false };
+}
+
+/**
+ * Internal use for karatsuba_multiply. Calculates `a - b - c` with the given
+ * base. Assume a, b, c, a - b - c all to be positive.
+ * Return pm_integer_t with values allocated. Not normalized.
+ */
+static void
+big_sub2(pm_integer_t *destination, pm_integer_t *a, pm_integer_t *b, pm_integer_t *c, uint64_t base) {
+ size_t a_length;
+ uint32_t *a_values;
+ INTEGER_EXTRACT(a, a_length, a_values)
+
+ size_t b_length;
+ uint32_t *b_values;
+ INTEGER_EXTRACT(b, b_length, b_values)
+
+ size_t c_length;
+ uint32_t *c_values;
+ INTEGER_EXTRACT(c, c_length, c_values)
+
+ uint32_t *values = (uint32_t*) xmalloc(sizeof(uint32_t) * a_length);
+ int64_t carry = 0;
+
+ for (size_t index = 0; index < a_length; index++) {
+ int64_t sub = (
+ carry +
+ a_values[index] -
+ (index < b_length ? b_values[index] : 0) -
+ (index < c_length ? c_values[index] : 0)
+ );
+
+ if (sub >= 0) {
+ values[index] = (uint32_t) sub;
+ carry = 0;
+ } else {
+ sub += 2 * (int64_t) base;
+ values[index] = (uint32_t) ((uint64_t) sub % base);
+ carry = sub / (int64_t) base - 2;
+ }
+ }
+
+ while (a_length > 1 && values[a_length - 1] == 0) a_length--;
+ *destination = (pm_integer_t) { a_length, values, 0, false };
+}
+
+/**
+ * Multiply two positive integers with the given base using karatsuba algorithm.
+ * Return pm_integer_t with values allocated. Not normalized.
+ */
+static void
+karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) {
+ size_t left_length;
+ uint32_t *left_values;
+ INTEGER_EXTRACT(left, left_length, left_values)
+
+ size_t right_length;
+ uint32_t *right_values;
+ INTEGER_EXTRACT(right, right_length, right_values)
+
+ if (left_length > right_length) {
+ size_t temporary_length = left_length;
+ left_length = right_length;
+ right_length = temporary_length;
+
+ uint32_t *temporary_values = left_values;
+ left_values = right_values;
+ right_values = temporary_values;
+ }
+
+ if (left_length <= 10) {
+ size_t length = left_length + right_length;
+ uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
+ if (values == NULL) return;
+
+ for (size_t left_index = 0; left_index < left_length; left_index++) {
+ uint32_t carry = 0;
+ for (size_t right_index = 0; right_index < right_length; right_index++) {
+ uint64_t product = (uint64_t) left_values[left_index] * right_values[right_index] + values[left_index + right_index] + carry;
+ values[left_index + right_index] = (uint32_t) (product % base);
+ carry = (uint32_t) (product / base);
+ }
+ values[left_index + right_length] = carry;
+ }
+
+ while (length > 1 && values[length - 1] == 0) length--;
+ *destination = (pm_integer_t) { length, values, 0, false };
+ return;
+ }
+
+ if (left_length * 2 <= right_length) {
+ uint32_t *values = (uint32_t *) xcalloc(left_length + right_length, sizeof(uint32_t));
+
+ for (size_t start_offset = 0; start_offset < right_length; start_offset += left_length) {
+ size_t end_offset = start_offset + left_length;
+ if (end_offset > right_length) end_offset = right_length;
+
+ pm_integer_t sliced_left = {
+ .length = left_length,
+ .values = left_values,
+ .value = 0,
+ .negative = false
+ };
+
+ pm_integer_t sliced_right = {
+ .length = end_offset - start_offset,
+ .values = right_values + start_offset,
+ .value = 0,
+ .negative = false
+ };
+
+ pm_integer_t product;
+ karatsuba_multiply(&product, &sliced_left, &sliced_right, base);
+
+ uint32_t carry = 0;
+ for (size_t index = 0; index < product.length; index++) {
+ uint64_t sum = (uint64_t) values[start_offset + index] + product.values[index] + carry;
+ values[start_offset + index] = (uint32_t) (sum % base);
+ carry = (uint32_t) (sum / base);
+ }
+
+ if (carry > 0) values[start_offset + product.length] += carry;
+ pm_integer_free(&product);
+ }
+
+ *destination = (pm_integer_t) { left_length + right_length, values, 0, false };
+ return;
+ }
+
+ size_t half = left_length / 2;
+ pm_integer_t x0 = { half, left_values, 0, false };
+ pm_integer_t x1 = { left_length - half, left_values + half, 0, false };
+ pm_integer_t y0 = { half, right_values, 0, false };
+ pm_integer_t y1 = { right_length - half, right_values + half, 0, false };
+
+ pm_integer_t z0 = { 0 };
+ karatsuba_multiply(&z0, &x0, &y0, base);
+
+ pm_integer_t z2 = { 0 };
+ karatsuba_multiply(&z2, &x1, &y1, base);
+
+ // For simplicity to avoid considering negative values,
+ // use `z1 = (x0 + x1) * (y0 + y1) - z0 - z2` instead of original karatsuba algorithm.
+ pm_integer_t x01 = { 0 };
+ big_add(&x01, &x0, &x1, base);
+
+ pm_integer_t y01 = { 0 };
+ big_add(&y01, &y0, &y1, base);
+
+ pm_integer_t xy = { 0 };
+ karatsuba_multiply(&xy, &x01, &y01, base);
+
+ pm_integer_t z1;
+ big_sub2(&z1, &xy, &z0, &z2, base);
+
+ size_t length = left_length + right_length;
+ uint32_t *values = (uint32_t*) xcalloc(length, sizeof(uint32_t));
+
+ assert(z0.values != NULL);
+ memcpy(values, z0.values, sizeof(uint32_t) * z0.length);
+
+ assert(z2.values != NULL);
+ memcpy(values + 2 * half, z2.values, sizeof(uint32_t) * z2.length);
+
+ uint32_t carry = 0;
+ for(size_t index = 0; index < z1.length; index++) {
+ uint64_t sum = (uint64_t) carry + values[index + half] + z1.values[index];
+ values[index + half] = (uint32_t) (sum % base);
+ carry = (uint32_t) (sum / base);
+ }
+
+ for(size_t index = half + z1.length; carry > 0; index++) {
+ uint64_t sum = (uint64_t) carry + values[index];
+ values[index] = (uint32_t) (sum % base);
+ carry = (uint32_t) (sum / base);
+ }
+
+ while (length > 1 && values[length - 1] == 0) length--;
+ pm_integer_free(&z0);
+ pm_integer_free(&z1);
+ pm_integer_free(&z2);
+ pm_integer_free(&x01);
+ pm_integer_free(&y01);
+ pm_integer_free(&xy);
+
+ *destination = (pm_integer_t) { length, values, 0, false };
+}
+
+/**
+ * The values of a hexadecimal digit, where the index is the ASCII character.
+ * Note that there's an odd exception here where _ is mapped to 0. This is
+ * because it's possible for us to end up trying to parse a number that has
+ * already had an error attached to it, and we want to provide _something_ to
+ * the user.
+ */
+static const int8_t pm_integer_parse_digit_values[256] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, // 5x
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Fx
+};
+
+/**
+ * Return the value of a hexadecimal digit in a uint8_t.
+ */
+static uint8_t
+pm_integer_parse_digit(const uint8_t character) {
+ int8_t value = pm_integer_parse_digit_values[character];
+ assert(value != -1 && "invalid digit");
+
+ return (uint8_t) value;
+}
+
+/**
+ * Create a pm_integer_t from uint64_t with the given base. It is assumed that
+ * the memory for the pm_integer_t pointer has been zeroed.
+ */
+static void
+pm_integer_from_uint64(pm_integer_t *integer, uint64_t value, uint64_t base) {
+ if (value < base) {
+ integer->value = (uint32_t) value;
+ return;
+ }
+
+ size_t length = 0;
+ uint64_t length_value = value;
+ while (length_value > 0) {
+ length++;
+ length_value /= base;
+ }
+
+ uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * length);
+ if (values == NULL) return;
+
+ for (size_t value_index = 0; value_index < length; value_index++) {
+ values[value_index] = (uint32_t) (value % base);
+ value /= base;
+ }
+
+ integer->length = length;
+ integer->values = values;
+}
+
+/**
+ * Normalize pm_integer_t.
+ * Heading zero values will be removed. If the integer fits into uint32_t,
+ * values is set to NULL, length is set to 0, and value field will be used.
+ */
+static void
+pm_integer_normalize(pm_integer_t *integer) {
+ if (integer->values == NULL) {
+ return;
+ }
+
+ while (integer->length > 1 && integer->values[integer->length - 1] == 0) {
+ integer->length--;
+ }
+
+ if (integer->length > 1) {
+ return;
+ }
+
+ uint32_t value = integer->values[0];
+ bool negative = integer->negative && value != 0;
+
+ pm_integer_free(integer);
+ *integer = (pm_integer_t) { .values = NULL, .value = value, .length = 0, .negative = negative };
+}
+
+/**
+ * Convert base of the integer.
+ * In practice, it converts 10**9 to 1<<32 or 1<<32 to 10**9.
+ */
+static void
+pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, uint64_t base_from, uint64_t base_to) {
+ size_t source_length;
+ const uint32_t *source_values;
+ INTEGER_EXTRACT(source, source_length, source_values)
+
+ size_t bigints_length = (source_length + 1) / 2;
+ assert(bigints_length > 0);
+
+ pm_integer_t *bigints = (pm_integer_t *) xcalloc(bigints_length, sizeof(pm_integer_t));
+ if (bigints == NULL) return;
+
+ for (size_t index = 0; index < source_length; index += 2) {
+ uint64_t value = source_values[index] + base_from * (index + 1 < source_length ? source_values[index + 1] : 0);
+ pm_integer_from_uint64(&bigints[index / 2], value, base_to);
+ }
+
+ pm_integer_t base = { 0 };
+ pm_integer_from_uint64(&base, base_from, base_to);
+
+ while (bigints_length > 1) {
+ pm_integer_t next_base;
+ karatsuba_multiply(&next_base, &base, &base, base_to);
+
+ pm_integer_free(&base);
+ base = next_base;
+
+ size_t next_length = (bigints_length + 1) / 2;
+ pm_integer_t *next_bigints = (pm_integer_t *) xcalloc(next_length, sizeof(pm_integer_t));
+
+ for (size_t bigints_index = 0; bigints_index < bigints_length; bigints_index += 2) {
+ if (bigints_index + 1 == bigints_length) {
+ next_bigints[bigints_index / 2] = bigints[bigints_index];
+ } else {
+ pm_integer_t multiplied = { 0 };
+ karatsuba_multiply(&multiplied, &base, &bigints[bigints_index + 1], base_to);
+
+ big_add(&next_bigints[bigints_index / 2], &bigints[bigints_index], &multiplied, base_to);
+ pm_integer_free(&bigints[bigints_index]);
+ pm_integer_free(&bigints[bigints_index + 1]);
+ pm_integer_free(&multiplied);
+ }
+ }
+
+ xfree_sized(bigints, bigints_length * sizeof(pm_integer_t));
+ bigints = next_bigints;
+ bigints_length = next_length;
+ }
+
+ *destination = bigints[0];
+ destination->negative = source->negative;
+ pm_integer_normalize(destination);
+
+ xfree_sized(bigints, bigints_length * sizeof(pm_integer_t));
+ pm_integer_free(&base);
+}
+
+#undef INTEGER_EXTRACT
+
+/**
+ * Convert digits to integer with the given power-of-two base.
+ */
+static void
+pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *digits, size_t digits_length) {
+ size_t bit = 1;
+ while (base > (uint32_t) (1 << bit)) bit++;
+
+ size_t length = (digits_length * bit + 31) / 32;
+ uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
+
+ for (size_t digit_index = 0; digit_index < digits_length; digit_index++) {
+ size_t bit_position = bit * (digits_length - digit_index - 1);
+ uint32_t value = digits[digit_index];
+
+ size_t index = bit_position / 32;
+ size_t shift = bit_position % 32;
+
+ values[index] |= value << shift;
+ if (32 - shift < bit) values[index + 1] |= value >> (32 - shift);
+ }
+
+ while (length > 1 && values[length - 1] == 0) length--;
+ *integer = (pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false };
+ pm_integer_normalize(integer);
+}
+
+/**
+ * Convert decimal digits to pm_integer_t.
+ */
+static void
+pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t digits_length) {
+ const size_t batch = 9;
+ const size_t length = (digits_length + batch - 1) / batch;
+
+ uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
+ uint32_t value = 0;
+
+ for (size_t digits_index = 0; digits_index < digits_length; digits_index++) {
+ value = value * 10 + digits[digits_index];
+
+ size_t reverse_index = digits_length - digits_index - 1;
+ if (reverse_index % batch == 0) {
+ values[reverse_index / batch] = value;
+ value = 0;
+ }
+ }
+
+ // Convert base from 10**9 to 1<<32.
+ pm_integer_convert_base(integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32));
+ xfree_sized(values, length * sizeof(uint32_t));
+}
+
+/**
+ * Parse a large integer from a string that does not fit into uint32_t.
+ */
+static void
+pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) {
+ // Allocate an array to store digits.
+ const size_t digits_capa = sizeof(uint8_t) * (size_t) (end - start);
+ uint8_t *digits = xmalloc(digits_capa);
+ size_t digits_length = 0;
+
+ for (; start < end; start++) {
+ if (*start == '_') continue;
+ digits[digits_length++] = pm_integer_parse_digit(*start);
+ }
+
+ // Construct pm_integer_t from the digits.
+ if (multiplier == 10) {
+ pm_integer_parse_decimal(integer, digits, digits_length);
+ } else {
+ pm_integer_parse_powof2(integer, multiplier, digits, digits_length);
+ }
+
+ xfree_sized(digits, digits_capa);
+}
+
+/**
+ * Parse an integer from a string. This assumes that the format of the integer
+ * has already been validated, as internal validation checks are not performed
+ * here.
+ */
+void
+pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) {
+ // Ignore unary +. Unary - is parsed differently and will not end up here.
+ // Instead, it will modify the parsed integer later.
+ if (*start == '+') start++;
+
+ // Determine the multiplier from the base, and skip past any prefixes.
+ uint32_t multiplier = 10;
+ switch (base) {
+ case PM_INTEGER_BASE_DEFAULT:
+ while (*start == '0') start++; // 01 -> 1
+ break;
+ case PM_INTEGER_BASE_BINARY:
+ start += 2; // 0b
+ multiplier = 2;
+ break;
+ case PM_INTEGER_BASE_OCTAL:
+ start++; // 0
+ if (*start == '_' || *start == 'o' || *start == 'O') start++; // o
+ multiplier = 8;
+ break;
+ case PM_INTEGER_BASE_DECIMAL:
+ if (*start == '0' && (end - start) > 1) start += 2; // 0d
+ break;
+ case PM_INTEGER_BASE_HEXADECIMAL:
+ start += 2; // 0x
+ multiplier = 16;
+ break;
+ case PM_INTEGER_BASE_UNKNOWN:
+ if (*start == '0' && (end - start) > 1) {
+ switch (start[1]) {
+ case '_': start += 2; multiplier = 8; break;
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': start++; multiplier = 8; break;
+ case 'b': case 'B': start += 2; multiplier = 2; break;
+ case 'o': case 'O': start += 2; multiplier = 8; break;
+ case 'd': case 'D': start += 2; break;
+ case 'x': case 'X': start += 2; multiplier = 16; break;
+ default: assert(false && "unreachable"); break;
+ }
+ }
+ break;
+ }
+
+ // It's possible that we've consumed everything at this point if there is an
+ // invalid integer. If this is the case, we'll just return 0.
+ if (start >= end) return;
+
+ const uint8_t *cursor = start;
+ uint64_t value = (uint64_t) pm_integer_parse_digit(*cursor++);
+
+ for (; cursor < end; cursor++) {
+ if (*cursor == '_') continue;
+ value = value * multiplier + (uint64_t) pm_integer_parse_digit(*cursor);
+
+ if (value > UINT32_MAX) {
+ // If the integer is too large to fit into a single uint32_t, then
+ // we'll parse it as a big integer.
+ pm_integer_parse_big(integer, multiplier, start, end);
+ return;
+ }
+ }
+
+ integer->value = (uint32_t) value;
+}
+
+/**
+ * Compare two integers. This function returns -1 if the left integer is less
+ * than the right integer, 0 if they are equal, and 1 if the left integer is
+ * greater than the right integer.
+ */
+int
+pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right) {
+ if (left->negative != right->negative) return left->negative ? -1 : 1;
+ int negative = left->negative ? -1 : 1;
+
+ if (left->values == NULL && right->values == NULL) {
+ if (left->value < right->value) return -1 * negative;
+ if (left->value > right->value) return 1 * negative;
+ return 0;
+ }
+
+ if (left->values == NULL || left->length < right->length) return -1 * negative;
+ if (right->values == NULL || left->length > right->length) return 1 * negative;
+
+ for (size_t index = 0; index < left->length; index++) {
+ size_t value_index = left->length - index - 1;
+ uint32_t left_value = left->values[value_index];
+ uint32_t right_value = right->values[value_index];
+
+ if (left_value < right_value) return -1 * negative;
+ if (left_value > right_value) return 1 * negative;
+ }
+
+ return 0;
+}
+
+/**
+ * Reduce a ratio of integers to its simplest form.
+ */
+void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) {
+ // If either the numerator or denominator do not fit into a 32-bit integer,
+ // then this function is a no-op. In the future, we may consider reducing
+ // even the larger numbers, but for now we're going to keep it simple.
+ if (
+ // If the numerator doesn't fit into a 32-bit integer, return early.
+ numerator->length != 0 ||
+ // If the denominator doesn't fit into a 32-bit integer, return early.
+ denominator->length != 0 ||
+ // If the numerator is 0, then return early.
+ numerator->value == 0 ||
+ // If the denominator is 1, then return early.
+ denominator->value == 1
+ ) return;
+
+ // Find the greatest common divisor of the numerator and denominator.
+ uint32_t divisor = numerator->value;
+ uint32_t remainder = denominator->value;
+
+ while (remainder != 0) {
+ uint32_t temporary = remainder;
+ remainder = divisor % remainder;
+ divisor = temporary;
+ }
+
+ // Divide the numerator and denominator by the greatest common divisor.
+ numerator->value /= divisor;
+ denominator->value /= divisor;
+}
+
+/**
+ * Convert an integer to a decimal string.
+ */
+void
+pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) {
+ if (integer->negative) {
+ pm_buffer_append_byte(buffer, '-');
+ }
+
+ // If the integer fits into a single uint32_t, then we can just append the
+ // value directly to the buffer.
+ if (integer->values == NULL) {
+ pm_buffer_append_format(buffer, "%" PRIu32, integer->value);
+ return;
+ }
+
+ // If the integer is two uint32_t values, then we can | them together and
+ // append the result to the buffer.
+ if (integer->length == 2) {
+ const uint64_t value = ((uint64_t) integer->values[0]) | ((uint64_t) integer->values[1] << 32);
+ pm_buffer_append_format(buffer, "%" PRIu64, value);
+ return;
+ }
+
+ // Otherwise, first we'll convert the base from 1<<32 to 10**9.
+ pm_integer_t converted = { 0 };
+ pm_integer_convert_base(&converted, integer, (uint64_t) 1 << 32, 1000000000);
+
+ if (converted.values == NULL) {
+ pm_buffer_append_format(buffer, "%" PRIu32, converted.value);
+ pm_integer_free(&converted);
+ return;
+ }
+
+ // Allocate a buffer that we'll copy the decimal digits into.
+ const size_t digits_length = converted.length * 9;
+ char *digits = xcalloc(digits_length, sizeof(char));
+ if (digits == NULL) return;
+
+ // Pack bigdecimal to digits.
+ for (size_t value_index = 0; value_index < converted.length; value_index++) {
+ uint32_t value = converted.values[value_index];
+
+ for (size_t digit_index = 0; digit_index < 9; digit_index++) {
+ digits[digits_length - 9 * value_index - digit_index - 1] = (char) ('0' + value % 10);
+ value /= 10;
+ }
+ }
+
+ size_t start_offset = 0;
+ while (start_offset < digits_length - 1 && digits[start_offset] == '0') start_offset++;
+
+ // Finally, append the string to the buffer and free the digits.
+ pm_buffer_append_string(buffer, digits + start_offset, digits_length - start_offset);
+ xfree_sized(digits, sizeof(char) * digits_length);
+ pm_integer_free(&converted);
+}
diff --git a/prism/integer.h b/prism/integer.h
new file mode 100644
index 0000000000..9285986885
--- /dev/null
+++ b/prism/integer.h
@@ -0,0 +1,41 @@
+/**
+ * @file integer.h
+ *
+ * This module provides functions for working with arbitrary-sized integers.
+ */
+#ifndef PRISM_INTEGER_H
+#define PRISM_INTEGER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * A structure represents an arbitrary-sized integer.
+ */
+typedef struct {
+ /**
+ * The number of allocated values. length is set to 0 if the integer fits
+ * into uint32_t.
+ */
+ size_t length;
+
+ /**
+ * List of 32-bit integers. Set to NULL if the integer fits into uint32_t.
+ */
+ uint32_t *values;
+
+ /**
+ * Embedded value for small integer. This value is set to 0 if the value
+ * does not fit into uint32_t.
+ */
+ uint32_t value;
+
+ /**
+ * Whether or not the integer is negative. It is stored this way so that a
+ * zeroed pm_integer_t is always positive zero.
+ */
+ bool negative;
+} pm_integer_t;
+
+#endif
diff --git a/prism/internal/allocator.h b/prism/internal/allocator.h
new file mode 100644
index 0000000000..6c54010dbf
--- /dev/null
+++ b/prism/internal/allocator.h
@@ -0,0 +1,68 @@
+#ifndef PRISM_INTERNAL_ALLOCATOR_H
+#define PRISM_INTERNAL_ALLOCATOR_H
+
+/* If you build Prism with a custom allocator, configure it with
+ * "-D PRISM_XALLOCATOR" to use your own allocator that defines xmalloc,
+ * xrealloc, xcalloc, and xfree.
+ *
+ * For example, your `prism_xallocator.h` file could look like this:
+ *
+ * ```
+ * #ifndef PRISM_XALLOCATOR_H
+ * #define PRISM_XALLOCATOR_H
+ * #define xmalloc my_malloc
+ * #define xrealloc my_realloc
+ * #define xcalloc my_calloc
+ * #define xfree my_free
+ * #define xrealloc_sized my_realloc_sized // (optional)
+ * #define xfree_sized my_free_sized // (optional)
+ * #endif
+ * ```
+ */
+#ifdef PRISM_XALLOCATOR
+ #include "prism_xallocator.h"
+#else
+ #ifndef xmalloc
+ /* The malloc function that should be used. This can be overridden with
+ * the PRISM_XALLOCATOR define. */
+ #define xmalloc malloc
+ #endif
+
+ #ifndef xrealloc
+ /* The realloc function that should be used. This can be overridden with
+ * the PRISM_XALLOCATOR define. */
+ #define xrealloc realloc
+ #endif
+
+ #ifndef xcalloc
+ /* The calloc function that should be used. This can be overridden with
+ * the PRISM_XALLOCATOR define. */
+ #define xcalloc calloc
+ #endif
+
+ #ifndef xfree
+ /* The free function that should be used. This can be overridden with
+ * the PRISM_XALLOCATOR define. */
+ #define xfree free
+ #endif
+#endif
+
+#ifndef xfree_sized
+ /* The free_sized function that should be used. This can be overridden with
+ * the PRISM_XALLOCATOR define. If not defined, defaults to calling xfree.
+ */
+ #define xfree_sized(p, s) xfree(((void)(s), (p)))
+#endif
+
+#ifndef xrealloc_sized
+ /* The xrealloc_sized function that should be used. This can be overridden
+ * with the PRISM_XALLOCATOR define. If not defined, defaults to calling
+ * xrealloc. */
+ #define xrealloc_sized(p, ns, os) xrealloc((p), ((void)(os), (ns)))
+#endif
+
+#ifdef PRISM_BUILD_DEBUG
+ #include "prism/internal/allocator_debug.h"
+#endif
+
+#endif
diff --git a/prism/internal/allocator_debug.h b/prism/internal/allocator_debug.h
new file mode 100644
index 0000000000..846e96ba2d
--- /dev/null
+++ b/prism/internal/allocator_debug.h
@@ -0,0 +1,88 @@
+#ifndef PRISM_INTERNAL_ALLOCATOR_DEBUG_H
+#define PRISM_INTERNAL_ALLOCATOR_DEBUG_H
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static inline void *
+pm_allocator_debug_malloc(size_t size) {
+ size_t *memory = xmalloc(size + sizeof(size_t));
+ memory[0] = size;
+ return memory + 1;
+}
+
+static inline void *
+pm_allocator_debug_calloc(size_t nmemb, size_t size) {
+ size_t total_size = nmemb * size;
+ void *ptr = pm_allocator_debug_malloc(total_size);
+ memset(ptr, 0, total_size);
+ return ptr;
+}
+
+static inline void *
+pm_allocator_debug_realloc(void *ptr, size_t size) {
+ if (ptr == NULL) {
+ return pm_allocator_debug_malloc(size);
+ }
+
+ size_t *memory = (size_t *)ptr;
+ void *raw_memory = memory - 1;
+ memory = (size_t *)xrealloc(raw_memory, size + sizeof(size_t));
+ memory[0] = size;
+ return memory + 1;
+}
+
+static inline void
+pm_allocator_debug_free(void *ptr) {
+ if (ptr != NULL) {
+ size_t *memory = (size_t *)ptr;
+ xfree(memory - 1);
+ }
+}
+
+static inline void
+pm_allocator_debug_free_sized(void *ptr, size_t old_size) {
+ if (ptr != NULL) {
+ size_t *memory = (size_t *)ptr;
+ if (old_size != memory[-1]) {
+ fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but freed with size %lu\n", ptr, memory[-1], old_size);
+ abort();
+ }
+ xfree_sized(memory - 1, old_size + sizeof(size_t));
+ }
+}
+
+static inline void *
+pm_allocator_debug_realloc_sized(void *ptr, size_t size, size_t old_size) {
+ if (ptr == NULL) {
+ if (old_size != 0) {
+ fprintf(stderr, "[BUG] realloc_sized called with NULL pointer and old size %lu\n", old_size);
+ abort();
+ }
+ return pm_allocator_debug_malloc(size);
+ }
+
+ size_t *memory = (size_t *)ptr;
+ if (old_size != memory[-1]) {
+ fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but realloced with size %lu\n", ptr, memory[-1], old_size);
+ abort();
+ }
+ return pm_allocator_debug_realloc(ptr, size);
+}
+
+#undef xmalloc
+#undef xrealloc
+#undef xcalloc
+#undef xfree
+#undef xrealloc_sized
+#undef xfree_sized
+
+#define xmalloc pm_allocator_debug_malloc
+#define xrealloc pm_allocator_debug_realloc
+#define xcalloc pm_allocator_debug_calloc
+#define xfree pm_allocator_debug_free
+#define xrealloc_sized pm_allocator_debug_realloc_sized
+#define xfree_sized pm_allocator_debug_free_sized
+
+#endif
diff --git a/prism/internal/arena.h b/prism/internal/arena.h
new file mode 100644
index 0000000000..2e413b42bf
--- /dev/null
+++ b/prism/internal/arena.h
@@ -0,0 +1,108 @@
+#ifndef PRISM_INTERNAL_ARENA_H
+#define PRISM_INTERNAL_ARENA_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/flex_array.h"
+#include "prism/compiler/force_inline.h"
+#include "prism/compiler/inline.h"
+
+#include "prism/arena.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/*
+ * A single block of memory in the arena. Blocks are linked via prev pointers so
+ * they can be freed by walking the chain.
+ */
+typedef struct pm_arena_block {
+ /* The previous block in the chain (for freeing). */
+ struct pm_arena_block *prev;
+
+ /* The total usable bytes in data[]. */
+ size_t capacity;
+
+ /* The number of bytes consumed so far. */
+ size_t used;
+
+ /* The block's data. */
+ char data[PM_FLEX_ARRAY_LENGTH];
+} pm_arena_block_t;
+
+/*
+ * A bump allocator. Allocations are made by bumping a pointer within the
+ * current block. When a block is full, a new block is allocated and linked to
+ * the previous one. All blocks are freed at once by walking the chain.
+ */
+struct pm_arena_t {
+ /* The active block (allocate from here). */
+ pm_arena_block_t *current;
+
+ /* The number of blocks allocated. */
+ size_t block_count;
+};
+
+/*
+ * Free all blocks in the arena. After this call, all pointers returned by
+ * pm_arena_alloc and pm_arena_zalloc are invalid.
+ */
+void pm_arena_cleanup(pm_arena_t *arena);
+
+/*
+ * Ensure the arena has at least `capacity` bytes available in its current
+ * block, allocating a new block if necessary. This allows callers to
+ * pre-size the arena to avoid repeated small block allocations.
+ */
+void pm_arena_reserve(pm_arena_t *arena, size_t capacity);
+
+/*
+ * Slow path for pm_arena_alloc: allocate a new block and return a pointer to
+ * the first `size` bytes. Do not call directly — use pm_arena_alloc instead.
+ */
+void * pm_arena_alloc_slow(pm_arena_t *arena, size_t size);
+
+/*
+ * Allocate memory from the arena. The returned memory is NOT zeroed. This
+ * function is infallible — it aborts on allocation failure.
+ *
+ * The fast path (bump pointer within the current block) is inlined at each
+ * call site. The slow path (new block allocation) is out-of-line.
+ */
+static PRISM_FORCE_INLINE void *
+pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) {
+ if (arena->current != NULL) {
+ size_t used_aligned = (arena->current->used + alignment - 1) & ~(alignment - 1);
+ size_t needed = used_aligned + size;
+
+ if (used_aligned >= arena->current->used && needed >= used_aligned && needed <= arena->current->capacity) {
+ arena->current->used = needed;
+ return arena->current->data + used_aligned;
+ }
+ }
+
+ return pm_arena_alloc_slow(arena, size);
+}
+
+/*
+ * Allocate zero-initialized memory from the arena. This function is infallible
+ * — it aborts on allocation failure.
+ */
+static PRISM_INLINE void *
+pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment) {
+ void *ptr = pm_arena_alloc(arena, size, alignment);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+/*
+ * Allocate memory from the arena and copy the given data into it. This is a
+ * convenience wrapper around pm_arena_alloc + memcpy.
+ */
+static PRISM_INLINE void *
+pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment) {
+ void *dst = pm_arena_alloc(arena, size, alignment);
+ memcpy(dst, src, size);
+ return dst;
+}
+
+#endif
diff --git a/prism/internal/bit.h b/prism/internal/bit.h
new file mode 100644
index 0000000000..b0111a4c2c
--- /dev/null
+++ b/prism/internal/bit.h
@@ -0,0 +1,42 @@
+#ifndef PRISM_INTERNAL_BIT_H
+#define PRISM_INTERNAL_BIT_H
+
+#include "prism/compiler/inline.h"
+
+/*
+ * Count trailing zero bits in a 64-bit value. Used by SWAR identifier scanning
+ * to find the first non-matching byte in a word.
+ *
+ * Precondition: v must be nonzero. The result is undefined when v == 0
+ * (matching the behavior of __builtin_ctzll and _BitScanForward64).
+ */
+#if defined(__GNUC__) || defined(__clang__)
+#define pm_ctzll(v) ((unsigned) __builtin_ctzll(v))
+#elif defined(_MSC_VER)
+#include <intrin.h>
+#include <stdint.h>
+
+static PRISM_INLINE unsigned
+pm_ctzll(uint64_t v) {
+ unsigned long index;
+ _BitScanForward64(&index, v);
+ return (unsigned) index;
+}
+#else
+#include <stdint.h>
+
+static PRISM_INLINE unsigned
+pm_ctzll(uint64_t v) {
+ unsigned c = 0;
+ v &= (uint64_t) (-(int64_t) v);
+ if (v & 0x00000000FFFFFFFFULL) c += 0; else c += 32;
+ if (v & 0x0000FFFF0000FFFFULL) c += 0; else c += 16;
+ if (v & 0x00FF00FF00FF00FFULL) c += 0; else c += 8;
+ if (v & 0x0F0F0F0F0F0F0F0FULL) c += 0; else c += 4;
+ if (v & 0x3333333333333333ULL) c += 0; else c += 2;
+ if (v & 0x5555555555555555ULL) c += 0; else c += 1;
+ return c;
+}
+#endif
+
+#endif
diff --git a/prism/internal/buffer.h b/prism/internal/buffer.h
new file mode 100644
index 0000000000..a849bbf8e6
--- /dev/null
+++ b/prism/internal/buffer.h
@@ -0,0 +1,91 @@
+#ifndef PRISM_INTERNAL_BUFFER_H
+#define PRISM_INTERNAL_BUFFER_H
+
+#include "prism/compiler/format.h"
+
+#include "prism/buffer.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * A simple memory buffer that stores data in a contiguous block of memory.
+ */
+struct pm_buffer_t {
+ /* 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;
+};
+
+/* Initialize a pm_buffer_t with the given capacity. */
+void pm_buffer_init(pm_buffer_t *buffer, size_t capacity);
+
+/* Free the memory held by the buffer. */
+void pm_buffer_cleanup(pm_buffer_t *buffer);
+
+/* Append the given amount of space as zeroes to the buffer. */
+void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length);
+
+/* Append a formatted string to the buffer. */
+void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3);
+
+/* Append a string to the buffer. */
+void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t 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);
+
+/* Append a single byte to the buffer. */
+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. */
+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. */
+void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value);
+
+/* Append a double to the buffer. */
+void pm_buffer_append_double(pm_buffer_t *buffer, double value);
+
+/* Append a unicode codepoint to the buffer. */
+bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value);
+
+/*
+ * The different types of escaping that can be performed by the buffer when
+ * appending a slice of Ruby source code.
+ */
+typedef enum {
+ PM_BUFFER_ESCAPING_RUBY,
+ PM_BUFFER_ESCAPING_JSON
+} pm_buffer_escaping_t;
+
+/* Append a slice of source code to the buffer. */
+void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping);
+
+/* Prepend the given string to the buffer. */
+void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length);
+
+/* Concatenate one buffer onto another. */
+void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source);
+
+/*
+ * Clear the buffer by reducing its size to 0. This does not free the allocated
+ * memory, but it does allow the buffer to be reused.
+ */
+void pm_buffer_clear(pm_buffer_t *buffer);
+
+/* Strip the whitespace from the end of the buffer. */
+void pm_buffer_rstrip(pm_buffer_t *buffer);
+
+/* Checks if the buffer includes the given value. */
+size_t pm_buffer_index(const pm_buffer_t *buffer, char value);
+
+/* Insert the given string into the buffer at the given index. */
+void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length);
+
+#endif
diff --git a/prism/internal/char.h b/prism/internal/char.h
new file mode 100644
index 0000000000..9a58fba8c5
--- /dev/null
+++ b/prism/internal/char.h
@@ -0,0 +1,139 @@
+#ifndef PRISM_INTERNAL_CHAR_H
+#define PRISM_INTERNAL_CHAR_H
+
+#include "prism/compiler/force_inline.h"
+
+#include "prism/arena.h"
+#include "prism/line_offset_list.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Bit flag for whitespace characters in pm_byte_table. */
+#define PRISM_CHAR_BIT_WHITESPACE (1 << 0)
+
+/* Bit flag for inline whitespace characters in pm_byte_table. */
+#define PRISM_CHAR_BIT_INLINE_WHITESPACE (1 << 1)
+
+/*
+ * A lookup table for classifying bytes. Each entry is a bitfield of
+ * PRISM_CHAR_BIT_* flags. Defined in char.c.
+ */
+extern const uint8_t pm_byte_table[256];
+
+/* Returns true if the given character is a whitespace character. */
+static PRISM_FORCE_INLINE bool
+pm_char_is_whitespace(const uint8_t b) {
+ return (pm_byte_table[b] & PRISM_CHAR_BIT_WHITESPACE) != 0;
+}
+
+/* Returns true if the given character is an inline whitespace character. */
+static PRISM_FORCE_INLINE bool
+pm_char_is_inline_whitespace(const uint8_t b) {
+ return (pm_byte_table[b] & PRISM_CHAR_BIT_INLINE_WHITESPACE) != 0;
+}
+
+/*
+ * Returns the number of characters at the start of the string that are inline
+ * whitespace (space/tab). Scans the byte table directly for use in hot paths.
+ */
+static PRISM_FORCE_INLINE size_t
+pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) {
+ 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_INLINE_WHITESPACE)) 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);
+
+/*
+ * 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_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+
+/* Returns 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. */
+bool pm_char_is_octal_digit(const uint8_t b);
+
+/* Returns 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. */
+bool pm_char_is_hexadecimal_digit(const uint8_t b);
+
+#endif
diff --git a/prism/internal/comments.h b/prism/internal/comments.h
new file mode 100644
index 0000000000..bb3039a658
--- /dev/null
+++ b/prism/internal/comments.h
@@ -0,0 +1,20 @@
+#ifndef PRISM_INTERNAL_COMMENTS_H
+#define PRISM_INTERNAL_COMMENTS_H
+
+#include "prism/comments.h"
+
+#include "prism/internal/list.h"
+
+/* A comment found while parsing. */
+struct pm_comment_t {
+ /* The embedded base node. */
+ pm_list_node_t node;
+
+ /* The location of the comment in the source. */
+ pm_location_t location;
+
+ /* The type of the comment. */
+ pm_comment_type_t type;
+};
+
+#endif
diff --git a/prism/internal/constant_pool.h b/prism/internal/constant_pool.h
new file mode 100644
index 0000000000..fa2be783f5
--- /dev/null
+++ b/prism/internal/constant_pool.h
@@ -0,0 +1,117 @@
+#ifndef PRISM_INTERNAL_CONSTANT_POOL_H
+#define PRISM_INTERNAL_CONSTANT_POOL_H
+
+#include "prism/constant_pool.h"
+
+#include "prism/arena.h"
+
+#include <stdbool.h>
+
+/* A constant in the pool which effectively stores a string. */
+struct pm_constant_t {
+ /* A pointer to the start of the string. */
+ const uint8_t *start;
+
+ /* The length of the string. */
+ size_t length;
+};
+
+/*
+ * 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;
+
+ /*
+ * A pointer to the start of the string, stored directly in the bucket to
+ * avoid a pointer chase to the constants array during probing.
+ */
+ const uint8_t *start;
+
+ /* The length of the string. */
+ size_t length;
+} pm_constant_pool_bucket_t;
+
+/* The overall constant pool, which stores constants found while parsing. */
+struct pm_constant_pool_t {
+ /* 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;
+};
+
+/*
+ * When we allocate constants into the pool, we reserve 0 to mean that the slot
+ * is not yet filled. This constant is reused in other places to indicate the
+ * lack of a constant id.
+ */
+#define PM_CONSTANT_ID_UNSET 0
+
+/* Initialize a list of constant ids with a given capacity. */
+void pm_constant_id_list_init_capacity(pm_arena_t *arena, pm_constant_id_list_t *list, size_t capacity);
+
+/* Insert a constant id into a list of constant ids at the specified index. */
+void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id);
+
+/* 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);
+
+/* Initialize a new constant pool with a given capacity. */
+void pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity);
+
+/* 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);
+
+/*
+ * Find a constant in a constant pool. Returns the id of the constant, or 0 if
+ * the constant is not found.
+ */
+pm_constant_id_t pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length);
+
+/*
+ * 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.
+ */
+pm_constant_id_t pm_constant_pool_insert_shared(pm_arena_t *arena, 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.
+ */
+pm_constant_id_t pm_constant_pool_insert_owned(pm_arena_t *arena, pm_constant_pool_t *pool, 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.
+ */
+pm_constant_id_t pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length);
+
+#endif
diff --git a/prism/internal/encoding.h b/prism/internal/encoding.h
new file mode 100644
index 0000000000..62392ef970
--- /dev/null
+++ b/prism/internal/encoding.h
@@ -0,0 +1,242 @@
+#ifndef PRISM_INTERNAL_ENCODING_H
+#define PRISM_INTERNAL_ENCODING_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. */
+size_t pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+/*
+ * 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_US_ASCII,
+ PM_ENCODING_ASCII_8BIT,
+ PM_ENCODING_EUC_JP,
+ PM_ENCODING_WINDOWS_31J,
+
+/* We optionally support excluding the full set of encodings to only support the
+ * minimum necessary to process Ruby code without encoding comments. */
+#ifndef PRISM_ENCODING_EXCLUDE_FULL
+ 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_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_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_874,
+#endif
+
+ 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])
+
+/*
+ * This is the ASCII-8BIT encoding. We need a reference to it so that pm_strpbrk
+ * can compare against it because invalid multibyte characters are not a thing
+ * in this encoding. It is also needed for handling Regexp encoding flags.
+ */
+#define PM_ENCODING_ASCII_8BIT_ENTRY (&pm_encodings[PM_ENCODING_ASCII_8BIT])
+
+/*
+ * This is the EUC-JP encoding. We need a reference to it to quickly process
+ * regular expression modifiers.
+ */
+#define PM_ENCODING_EUC_JP_ENTRY (&pm_encodings[PM_ENCODING_EUC_JP])
+
+/*
+ * This is the Windows-31J encoding. We need a reference to it to quickly
+ * process regular expression modifiers.
+ */
+#define PM_ENCODING_WINDOWS_31J_ENTRY (&pm_encodings[PM_ENCODING_WINDOWS_31J])
+
+/*
+ * 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);
+
+#endif
diff --git a/prism/internal/integer.h b/prism/internal/integer.h
new file mode 100644
index 0000000000..7c9767e323
--- /dev/null
+++ b/prism/internal/integer.h
@@ -0,0 +1,68 @@
+/*
+ * This module provides functions for working with arbitrary-sized integers.
+ */
+#ifndef PRISM_INTERNAL_INTEGER_H
+#define PRISM_INTERNAL_INTEGER_H
+
+#include "prism/buffer.h"
+#include "prism/integer.h"
+
+#include <stdint.h>
+
+/*
+ * An enum controlling the base of an integer. It is expected that the base is
+ * already known before parsing the integer, even though it could be derived
+ * from the string itself.
+ */
+typedef enum {
+ /* The default decimal base, with no prefix. Leading 0s will be ignored. */
+ PM_INTEGER_BASE_DEFAULT,
+
+ /* The binary base, indicated by a 0b or 0B prefix. */
+ PM_INTEGER_BASE_BINARY,
+
+ /* The octal base, indicated by a 0, 0o, or 0O prefix. */
+ PM_INTEGER_BASE_OCTAL,
+
+ /* The decimal base, indicated by a 0d, 0D, or empty prefix. */
+ PM_INTEGER_BASE_DECIMAL,
+
+ /* The hexadecimal base, indicated by a 0x or 0X prefix. */
+ PM_INTEGER_BASE_HEXADECIMAL,
+
+ /*
+ * An unknown base, in which case pm_integer_parse will derive it based on
+ * the content of the string. This is less efficient and does more
+ * comparisons, so if callers know the base ahead of time, they should use
+ * that instead.
+ */
+ PM_INTEGER_BASE_UNKNOWN
+} pm_integer_base_t;
+
+/*
+ * Parse an integer from a string. This assumes that the format of the integer
+ * has already been validated, as internal validation checks are not performed
+ * here.
+ */
+void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end);
+
+/*
+ * Compare two integers. This function returns -1 if the left integer is less
+ * than the right integer, 0 if they are equal, and 1 if the left integer is
+ * greater than the right integer.
+ */
+int pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right);
+
+/*
+ * Reduce a ratio of integers to its simplest form.
+ *
+ * If either the numerator or denominator do not fit into a 32-bit integer, then
+ * this function is a no-op. In the future, we may consider reducing even the
+ * larger numbers, but for now we're going to keep it simple.
+ */
+void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator);
+
+/* Convert an integer to a decimal string. */
+void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer);
+
+#endif
diff --git a/prism/internal/isinf.h b/prism/internal/isinf.h
new file mode 100644
index 0000000000..41c160f56d
--- /dev/null
+++ b/prism/internal/isinf.h
@@ -0,0 +1,16 @@
+#ifndef PRISM_INTERNAL_ISINF_H
+#define PRISM_INTERNAL_ISINF_H
+
+/*
+ * isinf on POSIX systems accepts a float, a double, or a long double. But mingw
+ * didn't provide an isinf macro, only an isinf function that only accepts
+ * floats, so we need to use _finite instead.
+ */
+#ifdef __MINGW64__
+ #include <float.h>
+ #define PRISM_ISINF(x) (!_finite(x))
+#else
+ #define PRISM_ISINF(x) isinf(x)
+#endif
+
+#endif
diff --git a/prism/internal/line_offset_list.h b/prism/internal/line_offset_list.h
new file mode 100644
index 0000000000..dac9f7052e
--- /dev/null
+++ b/prism/internal/line_offset_list.h
@@ -0,0 +1,34 @@
+#ifndef PRISM_INTERNAL_LINE_OFFSET_LIST_H
+#define PRISM_INTERNAL_LINE_OFFSET_LIST_H
+
+#include "prism/compiler/force_inline.h"
+
+#include "prism/arena.h"
+#include "prism/line_offset_list.h"
+
+/* Initialize a new line offset list with the given capacity. */
+void pm_line_offset_list_init(pm_arena_t *arena, pm_line_offset_list_t *list, size_t capacity);
+
+/* Clear out the offsets that have been appended to the list. */
+void pm_line_offset_list_clear(pm_line_offset_list_t *list);
+
+/* Append a new offset to the list (slow path with resize). */
+void pm_line_offset_list_append_slow(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor);
+
+/* Append a new offset to the list. */
+static PRISM_FORCE_INLINE void
+pm_line_offset_list_append(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor) {
+ if (list->size < list->capacity) {
+ list->offsets[list->size++] = cursor;
+ } else {
+ pm_line_offset_list_append_slow(arena, list, cursor);
+ }
+}
+
+/*
+ * Returns the line of the given offset. If the offset is not in the list, the
+ * line of the closest offset less than the given offset is returned.
+ */
+int32_t pm_line_offset_list_line(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line);
+
+#endif
diff --git a/prism/internal/list.h b/prism/internal/list.h
new file mode 100644
index 0000000000..0ab59ef32a
--- /dev/null
+++ b/prism/internal/list.h
@@ -0,0 +1,62 @@
+#ifndef PRISM_INTERNAL_LIST_H
+#define PRISM_INTERNAL_LIST_H
+
+#include <stddef.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 = xmalloc(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 the size of the list. */
+size_t pm_list_size(pm_list_t *list);
+
+/* Append a node to the given list. */
+void pm_list_append(pm_list_t *list, pm_list_node_t *node);
+
+#endif
diff --git a/prism/internal/magic_comments.h b/prism/internal/magic_comments.h
new file mode 100644
index 0000000000..72a581c5d7
--- /dev/null
+++ b/prism/internal/magic_comments.h
@@ -0,0 +1,23 @@
+#ifndef PRISM_INTERNAL_MAGIC_COMMENTS_H
+#define PRISM_INTERNAL_MAGIC_COMMENTS_H
+
+#include "prism/magic_comments.h"
+
+#include "prism/internal/list.h"
+
+/*
+ * This is a node in the linked list of magic comments that we've found while
+ * parsing.
+ */
+struct pm_magic_comment_t {
+ /* The embedded base node. */
+ pm_list_node_t node;
+
+ /* The key of the magic comment. */
+ pm_location_t key;
+
+ /* The value of the magic comment. */
+ pm_location_t value;
+};
+
+#endif
diff --git a/prism/internal/memchr.h b/prism/internal/memchr.h
new file mode 100644
index 0000000000..6f6b0bca30
--- /dev/null
+++ b/prism/internal/memchr.h
@@ -0,0 +1,15 @@
+#ifndef PRISM_INTERNAL_MEMCHR_H
+#define PRISM_INTERNAL_MEMCHR_H
+
+#include "prism/internal/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.
+ */
+const void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding);
+
+#endif
diff --git a/prism/internal/node.h b/prism/internal/node.h
new file mode 100644
index 0000000000..ca6d5616d7
--- /dev/null
+++ b/prism/internal/node.h
@@ -0,0 +1,32 @@
+#ifndef PRISM_INTERNAL_NODE_H
+#define PRISM_INTERNAL_NODE_H
+
+#include "prism/node.h"
+
+#include "prism/compiler/force_inline.h"
+
+#include "prism/arena.h"
+
+/*
+ * Slow path for pm_node_list_append: grow the list and append the node.
+ * Do not call directly — use pm_node_list_append instead.
+ */
+void pm_node_list_append_slow(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node);
+
+/* Append a new node onto the end of the node list. */
+static PRISM_FORCE_INLINE void
+pm_node_list_append(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) {
+ if (list->size < list->capacity) {
+ list->nodes[list->size++] = node;
+ } else {
+ pm_node_list_append_slow(arena, list, node);
+ }
+}
+
+/* Prepend a new node onto the beginning of the node list. */
+void pm_node_list_prepend(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node);
+
+/* Concatenate the given node list onto the end of the other node list. */
+void pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *other);
+
+#endif
diff --git a/prism/internal/options.h b/prism/internal/options.h
new file mode 100644
index 0000000000..7e37742a8b
--- /dev/null
+++ b/prism/internal/options.h
@@ -0,0 +1,212 @@
+#ifndef PRISM_INTERNAL_OPTIONS_H
+#define PRISM_INTERNAL_OPTIONS_H
+
+#include "prism/options.h"
+
+/* A scope of locals surrounding the code that is being parsed. */
+struct pm_options_scope_t {
+ /* The number of locals in the scope. */
+ size_t locals_count;
+
+ /* The names of the locals in the scope. */
+ pm_string_t *locals;
+
+ /* Flags for the set of forwarding parameters in this scope. */
+ uint8_t forwarding;
+};
+
+/*
+ * The version of Ruby syntax that we should be parsing with. This is used to
+ * allow consumers to specify which behavior they want in case they need to
+ * parse in the same way as a specific version of CRuby would have.
+ */
+typedef enum {
+ /*
+ * If an explicit version is not provided, the current version of prism will
+ * be used.
+ */
+ PM_OPTIONS_VERSION_UNSET = 0,
+
+ /* The vendored version of prism in CRuby 3.3.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_3 = 1,
+
+ /* The vendored version of prism in CRuby 3.4.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_4 = 2,
+
+ /* The vendored version of prism in CRuby 4.0.x. */
+ PM_OPTIONS_VERSION_CRUBY_3_5 = 3,
+
+ /* The vendored version of prism in CRuby 4.0.x. */
+ PM_OPTIONS_VERSION_CRUBY_4_0 = 3,
+
+ /* The vendored version of prism in CRuby 4.1.x. */
+ PM_OPTIONS_VERSION_CRUBY_4_1 = 4,
+
+ /* The current version of prism. */
+ PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_1
+} pm_options_version_t;
+
+/* The options that can be passed to the parser. */
+struct pm_options_t {
+ /*
+ * The callback to call when additional switches are found in a shebang
+ * comment.
+ */
+ pm_options_shebang_callback_t shebang_callback;
+
+ /*
+ * Any additional data that should be passed along to the shebang callback
+ * if one was set.
+ */
+ void *shebang_callback_data;
+
+ /* 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
+ * 1-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. Scopes are ordered from the outermost scope to the
+ * innermost one.
+ */
+ pm_options_scope_t *scopes;
+
+ /*
+ * The version of prism that we should be parsing with. This is used to
+ * allow consumers to specify which behavior they want in case they need to
+ * parse exactly as a specific version of CRuby.
+ */
+ pm_options_version_t version;
+
+ /* A bitset of the various options that were set on the command line. */
+ uint8_t command_line;
+
+ /*
+ * Whether or not the frozen string literal option has been set.
+ * May be:
+ * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
+ * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
+ * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
+ */
+ int8_t frozen_string_literal;
+
+ /*
+ * Whether or not the encoding magic comments should be respected. This is a
+ * niche use-case where you want to parse a file with a specific encoding
+ * but ignore any encoding magic comments at the top of the file.
+ */
+ bool encoding_locked;
+
+ /*
+ * When the file being parsed is the main script, the shebang will be
+ * considered for command-line flags (or for implicit -x). The caller needs
+ * to pass this information to the parser so that it can behave correctly.
+ */
+ bool main_script;
+
+ /*
+ * When the file being parsed is considered a "partial" script, jumps will
+ * not be marked as errors if they are not contained within loops/blocks.
+ * This is used in the case that you're parsing a script that you know will
+ * be embedded inside another script later, but you do not have that context
+ * yet. For example, when parsing an ERB template that will be evaluated
+ * inside another script.
+ */
+ bool partial_script;
+
+ /*
+ * Whether or not the parser should freeze the nodes that it creates. This
+ * makes it possible to have a deeply frozen AST that is safe to share
+ * between concurrency primitives.
+ */
+ bool freeze;
+};
+
+/* Free the internal memory associated with the options. */
+void pm_options_cleanup(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` | -p command line option |
+ * | `1` | -n command line option |
+ * | `1` | -l command line option |
+ * | `1` | -a command line option |
+ * | `1` | the version |
+ * | `1` | encoding locked |
+ * | `1` | main script |
+ * | `1` | partial script |
+ * | `1` | freeze |
+ * | `4` | the number of scopes |
+ * | ... | the scopes |
+ *
+ * The version field is an enum, so it should be one of the following values:
+ *
+ * | value | version |
+ * | ----- | ------------------------- |
+ * | `0` | use the latest version of prism |
+ * | `1` | use the version of prism that is vendored in CRuby 3.3.0 |
+ * | `2` | use the version of prism that is vendored in CRuby 3.4.0 |
+ * | `3` | use the version of prism that is vendored in CRuby 4.0.0 |
+ * | `4` | use the version of prism that is vendored in CRuby 4.1.0 |
+ *
+ * Each scope is laid out as follows:
+ *
+ * | # bytes | field |
+ * | ------- | -------------------------- |
+ * | `4` | the number of locals |
+ * | `1` | the forwarding flags |
+ * | ... | the locals |
+ *
+ * Each local is laid 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, encoding locked, main script, and partial script
+ * fields are booleans, so their values should be either 0 or 1.
+ * * The number of scopes can be 0.
+ */
+void pm_options_read(pm_options_t *options, const char *data);
+
+#endif
diff --git a/prism/internal/parser.h b/prism/internal/parser.h
new file mode 100644
index 0000000000..4320cf4029
--- /dev/null
+++ b/prism/internal/parser.h
@@ -0,0 +1,958 @@
+#ifndef PRISM_INTERNAL_PARSER_H
+#define PRISM_INTERNAL_PARSER_H
+
+#include "prism/compiler/accel.h"
+
+#include "prism/internal/arena.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/list.h"
+#include "prism/internal/options.h"
+#include "prism/internal/static_literals.h"
+#include "prism/internal/strpbrk.h"
+
+#include "prism/ast.h"
+#include "prism/line_offset_list.h"
+#include "prism/parser.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * This enum provides various bits that represent different kinds of states that
+ * the lexer can track. This is used to determine which kind of token to return
+ * based on the context of the parser.
+ */
+typedef enum {
+ PM_LEX_STATE_BIT_BEG,
+ PM_LEX_STATE_BIT_END,
+ PM_LEX_STATE_BIT_ENDARG,
+ PM_LEX_STATE_BIT_ENDFN,
+ PM_LEX_STATE_BIT_ARG,
+ PM_LEX_STATE_BIT_CMDARG,
+ PM_LEX_STATE_BIT_MID,
+ PM_LEX_STATE_BIT_FNAME,
+ PM_LEX_STATE_BIT_DOT,
+ PM_LEX_STATE_BIT_CLASS,
+ PM_LEX_STATE_BIT_LABEL,
+ PM_LEX_STATE_BIT_LABELED,
+ PM_LEX_STATE_BIT_FITEM
+} pm_lex_state_bit_t;
+
+/*
+ * This enum combines the various bits from the above enum into individual
+ * values that represent the various states of the lexer.
+ */
+typedef enum {
+ PM_LEX_STATE_NONE = 0,
+ PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG),
+ PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END),
+ PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG),
+ PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN),
+ PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG),
+ PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG),
+ PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID),
+ PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME),
+ PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT),
+ PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS),
+ PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL),
+ PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED),
+ PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM),
+ PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS,
+ PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG,
+ PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN
+} pm_lex_state_t;
+
+/*
+ * The type of quote that a heredoc uses.
+ */
+typedef enum {
+ PM_HEREDOC_QUOTE_NONE,
+ PM_HEREDOC_QUOTE_SINGLE = '\'',
+ PM_HEREDOC_QUOTE_DOUBLE = '"',
+ PM_HEREDOC_QUOTE_BACKTICK = '`',
+} pm_heredoc_quote_t;
+
+/*
+ * The type of indentation that a heredoc uses.
+ */
+typedef enum {
+ PM_HEREDOC_INDENT_NONE,
+ PM_HEREDOC_INDENT_DASH,
+ PM_HEREDOC_INDENT_TILDE,
+} pm_heredoc_indent_t;
+
+/*
+ * All of the information necessary to store to lexing a heredoc.
+ */
+typedef 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;
+} pm_heredoc_lex_mode_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[PM_STRPBRK_CACHE_SIZE];
+ } 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[PM_STRPBRK_CACHE_SIZE];
+ } 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[PM_STRPBRK_CACHE_SIZE];
+ } string;
+
+ struct {
+ /*
+ * All of the data necessary to lex a heredoc.
+ */
+ pm_heredoc_lex_mode_t base;
+
+ /*
+ * 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;
+
+ /* True if the previous token ended with a line continuation. */
+ bool line_continuation;
+ } 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
+
+/*
+ * 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 null context, used for returning a value from a function */
+ PM_CONTEXT_NONE = 0,
+
+ /* a begin statement */
+ PM_CONTEXT_BEGIN,
+
+ /* an ensure statement with an explicit begin */
+ PM_CONTEXT_BEGIN_ENSURE,
+
+ /* a rescue else statement with an explicit begin */
+ PM_CONTEXT_BEGIN_ELSE,
+
+ /* a rescue statement with an explicit begin */
+ PM_CONTEXT_BEGIN_RESCUE,
+
+ /* expressions in block arguments using braces */
+ PM_CONTEXT_BLOCK_BRACES,
+
+ /* expressions in block arguments using do..end */
+ PM_CONTEXT_BLOCK_KEYWORDS,
+
+ /* an ensure statement within a do..end block */
+ PM_CONTEXT_BLOCK_ENSURE,
+
+ /* a rescue else statement within a do..end block */
+ PM_CONTEXT_BLOCK_ELSE,
+
+ /* expressions in block parameters `foo do |...| end ` */
+ PM_CONTEXT_BLOCK_PARAMETERS,
+
+ /* a rescue statement within a do..end block */
+ PM_CONTEXT_BLOCK_RESCUE,
+
+ /* a case when statements */
+ PM_CONTEXT_CASE_WHEN,
+
+ /* a case in statements */
+ PM_CONTEXT_CASE_IN,
+
+ /* a class declaration */
+ PM_CONTEXT_CLASS,
+
+ /* an ensure statement within a class statement */
+ PM_CONTEXT_CLASS_ENSURE,
+
+ /* a rescue else statement within a class statement */
+ PM_CONTEXT_CLASS_ELSE,
+
+ /* a rescue statement within a class statement */
+ PM_CONTEXT_CLASS_RESCUE,
+
+ /* a method definition */
+ PM_CONTEXT_DEF,
+
+ /* an ensure statement within a method definition */
+ PM_CONTEXT_DEF_ENSURE,
+
+ /* a rescue else statement within a method definition */
+ PM_CONTEXT_DEF_ELSE,
+
+ /* a rescue statement within a method definition */
+ PM_CONTEXT_DEF_RESCUE,
+
+ /* a method definition's parameters */
+ PM_CONTEXT_DEF_PARAMS,
+
+ /* a defined? expression */
+ PM_CONTEXT_DEFINED,
+
+ /* 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,
+
+ /* 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,
+
+ /* an ensure statement within a lambda expression */
+ PM_CONTEXT_LAMBDA_ENSURE,
+
+ /* a rescue else statement within a lambda expression */
+ PM_CONTEXT_LAMBDA_ELSE,
+
+ /* a rescue statement within a lambda expression */
+ PM_CONTEXT_LAMBDA_RESCUE,
+
+ /* the predicate clause of a loop statement */
+ PM_CONTEXT_LOOP_PREDICATE,
+
+ /* the top level context */
+ PM_CONTEXT_MAIN,
+
+ /* a module declaration */
+ PM_CONTEXT_MODULE,
+
+ /* an ensure statement within a module statement */
+ PM_CONTEXT_MODULE_ENSURE,
+
+ /* a rescue else statement within a module statement */
+ PM_CONTEXT_MODULE_ELSE,
+
+ /* a rescue statement within a module statement */
+ PM_CONTEXT_MODULE_RESCUE,
+
+ /* a multiple target expression */
+ PM_CONTEXT_MULTI_TARGET,
+
+ /* 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 modifier rescue clause */
+ PM_CONTEXT_RESCUE_MODIFIER,
+
+ /* a singleton class definition */
+ PM_CONTEXT_SCLASS,
+
+ /* an ensure statement with a singleton class */
+ PM_CONTEXT_SCLASS_ENSURE,
+
+ /* a rescue else statement with a singleton class */
+ PM_CONTEXT_SCLASS_ELSE,
+
+ /* a rescue statement with a singleton class */
+ PM_CONTEXT_SCLASS_RESCUE,
+
+ /* a ternary expression */
+ PM_CONTEXT_TERNARY,
+
+ /* 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;
+
+/* The type of shareable constant value that can be set. */
+typedef uint8_t pm_shareable_constant_value_t;
+static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0;
+static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL;
+static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING;
+static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY;
+
+/*
+ * This tracks an individual local variable in a certain lexical context, as
+ * well as the number of times is it read.
+ */
+typedef struct {
+ /* The name of the local variable. */
+ pm_constant_id_t name;
+
+ /* The location of the local variable in the source. */
+ pm_location_t location;
+
+ /* The index of the local variable in the local table. */
+ uint32_t index;
+
+ /* The number of times the local variable is read. */
+ uint32_t reads;
+
+ /* The hash of the local variable. */
+ uint32_t hash;
+} pm_local_t;
+
+/*
+ * This is a set of local variables in a certain lexical context (method, class,
+ * module, etc.). We need to track how many times these variables are read in
+ * order to warn if they only get written.
+ */
+typedef struct pm_locals {
+ /* The number of local variables in the set. */
+ uint32_t size;
+
+ /* The capacity of the local variables set. */
+ uint32_t capacity;
+
+ /*
+ * A bloom filter over constant IDs stored in this set. Used to quickly
+ * reject lookups for names that are definitely not present, avoiding the
+ * cost of a linear scan or hash probe.
+ */
+ uint32_t bloom;
+
+ /* The nullable allocated memory for the local variables in the set. */
+ pm_local_t *locals;
+} pm_locals_t;
+
+/* The flags about scope parameters that can be set. */
+typedef uint8_t pm_scope_parameters_t;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NONE = 0x0;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x1;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x2;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x4;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x8;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED = 0x10;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_INNER = 0x20;
+static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_FOUND = 0x40;
+
+/*
+ * 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 {
+ /* A pointer to the previous scope in the linked list. */
+ struct pm_scope *previous;
+
+ /* The IDs of the locals in the given scope. */
+ pm_locals_t locals;
+
+ /*
+ * This is a list of the implicit parameters contained within the block.
+ * These will be processed after the block is parsed to determine the kind
+ * of parameters node that should be used and to check if any errors need to
+ * be added.
+ */
+ pm_node_list_t implicit_parameters;
+
+ /*
+ * This is a bitfield that indicates the parameters that are being used in
+ * this scope. It is a combination of the PM_SCOPE_PARAMETERS_* constants.
+ * There are three different kinds of parameters that can be used in a
+ * scope:
+ *
+ * - Ordinary parameters (e.g., def foo(bar); end)
+ * - Numbered parameters (e.g., def foo; _1; end)
+ * - The it parameter (e.g., def foo; it; end)
+ *
+ * If ordinary parameters are being used, then certain parameters can be
+ * forwarded to another method/structure. Those are indicated by four
+ * additional bits in the params field. For example, some combinations of:
+ *
+ * - def foo(*); end
+ * - def foo(**); end
+ * - def foo(&); end
+ * - def foo(...); end
+ */
+ pm_scope_parameters_t parameters;
+
+ /*
+ * The current state of constant shareability for this scope. This is
+ * changed by magic shareable_constant_value comments.
+ */
+ pm_shareable_constant_value_t shareable_constant;
+
+ /*
+ * 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;
+} pm_scope_t;
+
+/*
+ * A struct that represents a stack of boolean values.
+ */
+typedef uint32_t pm_state_stack_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_t {
+ /* The arena used for all AST-lifetime allocations. Caller-owned. */
+ pm_arena_t *arena;
+
+ /* The arena used for parser metadata (comments, diagnostics, etc.). */
+ pm_arena_t metadata_arena;
+
+ /*
+ * The next node identifier that will be assigned. This is a unique
+ * identifier used to track nodes such that the syntax tree can be dropped
+ * but the node can be found through another parse.
+ */
+ uint32_t node_id;
+
+ /*
+ * A single-entry cache for pm_parser_constant_id_raw. Avoids redundant
+ * constant pool lookups when the same token is resolved multiple times
+ * (e.g., once during lexing for local variable detection, and again
+ * during parsing for node creation).
+ */
+ struct {
+ const uint8_t *start;
+ const uint8_t *end;
+ pm_constant_id_t id;
+ } constant_cache;
+
+ /* 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;
+
+ /*
+ * An optional location that represents the location of the __END__ marker
+ * and the rest of the content of the file. This content is loaded into the
+ * DATA constant when the file being parsed is the main file being executed.
+ */
+ 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 hash keys for the hash that is currently being parsed. This is not
+ * usually necessary because it can pass it down the various call chains,
+ * but in the event that you're parsing a hash that is being directly
+ * pushed into another hash with **, we need to share the hash keys so that
+ * we can warn for the nested hash as well.
+ */
+ pm_static_literals_t *current_hash_keys;
+
+ /*
+ * 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;
+
+ /*
+ * 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.
+ */
+ struct {
+ /*
+ * 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.
+ */
+ pm_lex_callback_t callback;
+
+ /*
+ * 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;
+ } lex_callback;
+
+ /*
+ * This is the path of the file being parsed. We use the filepath when
+ * constructing SourceFileNodes.
+ */
+ pm_string_t filepath;
+
+ /*
+ * 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 line offsets in the source file. */
+ pm_line_offset_list_t line_offsets;
+
+ /*
+ * State communicated from the lexer to the parser for integer tokens.
+ */
+ struct {
+ /*
+ * A flag indicating the base of the integer (binary, octal, decimal,
+ * hexadecimal). Set during lexing and read during node creation.
+ */
+ pm_node_flags_t base;
+
+ /*
+ * When lexing a decimal integer that fits in a uint32_t, we compute
+ * the value during lexing to avoid re-scanning the digits during
+ * parsing. If lexed is true, this holds the result and
+ * pm_integer_parse can be skipped.
+ */
+ uint32_t value;
+
+ /* Whether value holds a valid pre-computed integer. */
+ bool lexed;
+ } integer;
+
+ /*
+ * 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;
+
+ /*
+ * When parsing block exits (e.g., break, next, redo), we need to validate
+ * that they are in correct contexts. For the most part we can do this by
+ * looking at our parent contexts. However, modifier while and until
+ * expressions can change that context to make block exits valid. In these
+ * cases, we need to keep track of the block exits and then validate them
+ * after the expression has been parsed.
+ *
+ * We use a pointer here because we don't want to keep a whole list attached
+ * since this will only be used in the context of begin/end expressions.
+ */
+ pm_node_list_t *current_block_exits;
+
+ /* The version of prism that we should use to parse. */
+ pm_options_version_t version;
+
+ /* The command line flags given from the options. */
+ uint8_t command_line;
+
+ /*
+ * Whether or not we have found a frozen_string_literal magic comment with
+ * a true or false value.
+ * May be:
+ * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
+ * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
+ * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
+ */
+ int8_t frozen_string_literal;
+
+ /*
+ * Whether or not we are parsing an eval string. This impacts whether or not
+ * we should evaluate if block exits/yields are valid.
+ */
+ bool parsing_eval;
+
+ /*
+ * Whether or not we are parsing a "partial" script, which is a script that
+ * will be evaluated in the context of another script, so we should not
+ * check jumps (next/break/etc.) for validity.
+ */
+ bool partial_script;
+
+ /* Whether or not we're at the beginning of a command. */
+ bool command_start;
+
+ /*
+ * Whether or not we're currently parsing the body of an endless method
+ * definition. In this context, PM_TOKEN_KEYWORD_DO_BLOCK should not be
+ * consumed by commands (it should bubble up to the outer context).
+ */
+ bool in_endless_def_body;
+
+ /* Whether or not we're currently recovering from a syntax error. */
+ bool recovering;
+
+ /*
+ * Whether or not the source being parsed could become valid if more input
+ * were appended. This is set to false when the parser encounters a token
+ * that is definitively wrong (e.g., a stray `end` or `]`) as opposed to
+ * merely incomplete.
+ */
+ bool continuable;
+
+ /*
+ * This is very specialized behavior for when you want to parse in a context
+ * that does not respect encoding comments. Its main use case is translating
+ * into the whitequark/parser AST which re-encodes source files in UTF-8
+ * before they are parsed and ignores encoding comments.
+ */
+ bool encoding_locked;
+
+ /*
+ * Whether or not the encoding has been changed by a magic comment. We use
+ * this to provide a fast path for the lexer instead of going through the
+ * function pointer.
+ */
+ bool encoding_changed;
+
+ /*
+ * This flag indicates that we are currently parsing a pattern matching
+ * expression and impacts that calculation of newlines.
+ */
+ bool pattern_matching_newlines;
+
+ /* This flag indicates that we are currently parsing a keyword argument. */
+ bool in_keyword_arg;
+
+ /*
+ * Whether or not the parser has seen a token that has semantic meaning
+ * (i.e., a token that is not a comment or whitespace).
+ */
+ bool semantic_token_seen;
+
+ /*
+ * By default, Ruby always warns about mismatched indentation. This can be
+ * toggled with a magic comment.
+ */
+ bool warn_mismatched_indentation;
+
+#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR)
+ /*
+ * Cached lookup tables for pm_strpbrk's SIMD fast path. Avoids rebuilding
+ * the nibble-based tables on every call when the charset hasn't changed
+ * (which is the common case during string/regex/list lexing).
+ */
+ struct {
+ /* The cached charset (null-terminated, max 11 chars + NUL). */
+ uint8_t charset[12];
+
+ /* Nibble-based low lookup table for SIMD matching. */
+ uint8_t low_lut[16];
+
+ /* Nibble-based high lookup table for SIMD matching. */
+ uint8_t high_lut[16];
+
+ /* Scalar fallback table (4 x 64-bit bitmasks covering all ASCII). */
+ uint64_t table[4];
+ } strpbrk_cache;
+#endif
+};
+
+/*
+ * Initialize a parser with the given start and end pointers.
+ */
+void pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options);
+
+/*
+ * Free the memory held by the given parser.
+ *
+ * This does not free the `pm_options_t` object that was used to initialize the
+ * parser.
+ */
+void pm_parser_cleanup(pm_parser_t *parser);
+
+#endif
diff --git a/prism/internal/regexp.h b/prism/internal/regexp.h
new file mode 100644
index 0000000000..3710c984fc
--- /dev/null
+++ b/prism/internal/regexp.h
@@ -0,0 +1,41 @@
+#ifndef PRISM_INTERNAL_REGEXP_H
+#define PRISM_INTERNAL_REGEXP_H
+
+#include "prism/ast.h"
+#include "prism/parser.h"
+
+/*
+ * Accumulation state for named capture groups found during regexp parsing.
+ * The caller initializes this with the call node and passes it to
+ * pm_regexp_parse. The regexp parser populates match and names as groups
+ * are found.
+ */
+typedef struct {
+ /* The call node wrapping the regular expression node (for =~). */
+ pm_call_node_t *call;
+
+ /* The match write node being built, or NULL if no captures found yet. */
+ pm_match_write_node_t *match;
+
+ /* The list of capture names found so far (for deduplication). */
+ pm_constant_id_list_t names;
+} pm_regexp_name_data_t;
+
+/*
+ * Callback invoked by pm_regexp_parse() for each named capture group found.
+ */
+typedef void (*pm_regexp_name_callback_t)(pm_parser_t *parser, const pm_string_t *name, bool shared, pm_regexp_name_data_t *data);
+
+/*
+ * Parse a regular expression, validate its encoding, and optionally extract
+ * named capture groups. Returns the encoding flags to set on the node.
+ */
+PRISM_EXPORTED_FUNCTION pm_node_flags_t pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data);
+
+/*
+ * Parse an interpolated regular expression for named capture groups only.
+ * No encoding validation is performed.
+ */
+void pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_t size, bool shared, bool extended_mode, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data);
+
+#endif
diff --git a/prism/internal/serialize.h b/prism/internal/serialize.h
new file mode 100644
index 0000000000..e611a0374b
--- /dev/null
+++ b/prism/internal/serialize.h
@@ -0,0 +1,34 @@
+#ifndef PRISM_INTERNAL_SERIALIZE_H
+#define PRISM_INTERNAL_SERIALIZE_H
+
+#include "prism/internal/encoding.h"
+#include "prism/internal/list.h"
+
+#include "prism/ast.h"
+#include "prism/buffer.h"
+#include "prism/excludes.h"
+#include "prism/parser.h"
+
+/* We optionally support serializing to a binary string. For systems that do not
+ * want or need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_SERIALIZATION define. */
+#ifndef PRISM_EXCLUDE_SERIALIZATION
+
+/*
+ * Serialize the given list of comments to the given buffer.
+ */
+void pm_serialize_comment_list(pm_list_t *list, pm_buffer_t *buffer);
+
+/*
+ * Serialize the name of the encoding to the buffer.
+ */
+void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer);
+
+/*
+ * Serialize the encoding, metadata, nodes, and constant pool.
+ */
+void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer);
+
+#endif
+
+#endif
diff --git a/prism/internal/source.h b/prism/internal/source.h
new file mode 100644
index 0000000000..b3c2b55be3
--- /dev/null
+++ b/prism/internal/source.h
@@ -0,0 +1,72 @@
+#ifndef PRISM_INTERNAL_SOURCE_H
+#define PRISM_INTERNAL_SOURCE_H
+
+#include "prism/source.h"
+#include "prism/buffer.h"
+
+#include <stdbool.h>
+
+/*
+ * The type of source, which determines cleanup behavior.
+ */
+typedef enum {
+ /* Wraps existing constant memory, no cleanup. */
+ PM_SOURCE_CONSTANT,
+
+ /* Wraps existing shared memory (non-owning slice), no cleanup. */
+ PM_SOURCE_SHARED,
+
+ /* Owns a heap-allocated buffer, freed on cleanup. */
+ PM_SOURCE_OWNED,
+
+ /* Memory-mapped file, unmapped on cleanup. */
+ PM_SOURCE_MAPPED,
+
+ /* Stream source backed by a pm_buffer_t. */
+ PM_SOURCE_STREAM
+} pm_source_type_t;
+
+/*
+ * The internal representation of a source.
+ */
+struct pm_source_t {
+ /* A pointer to the start of the source data. */
+ const uint8_t *source;
+
+ /* The length of the source data in bytes. */
+ size_t length;
+
+ /* The type of the source. */
+ pm_source_type_t type;
+
+ /* Stream-specific data, only used for PM_SOURCE_STREAM sources. */
+ struct {
+ /* The buffer that holds the accumulated stream data. */
+ pm_buffer_t *buffer;
+
+ /* The stream object to read from. */
+ void *stream;
+
+ /* The function to use to read from the stream. */
+ pm_source_stream_fgets_t *fgets;
+
+ /* The function to use to check if the stream is at EOF. */
+ pm_source_stream_feof_t *feof;
+
+ /* Whether the stream has reached EOF. */
+ bool eof;
+ } stream;
+};
+
+/*
+ * Read from a stream into the source's internal buffer. This is used by
+ * pm_parse_stream to incrementally read the source.
+ */
+bool pm_source_stream_read(pm_source_t *source);
+
+/*
+ * Returns whether the stream source has reached EOF.
+ */
+bool pm_source_stream_eof(const pm_source_t *source);
+
+#endif
diff --git a/prism/internal/static_literals.h b/prism/internal/static_literals.h
new file mode 100644
index 0000000000..d59002ac0a
--- /dev/null
+++ b/prism/internal/static_literals.h
@@ -0,0 +1,98 @@
+#ifndef PRISM_INTERNAL_STATIC_LITERALS_H
+#define PRISM_INTERNAL_STATIC_LITERALS_H
+
+#include "prism/ast.h"
+#include "prism/buffer.h"
+#include "prism/line_offset_list.h"
+
+/*
+ * An internal hash table for a set of nodes.
+ */
+typedef struct {
+ /* The array of nodes in the hash table. */
+ pm_node_t **nodes;
+
+ /* The size of the hash table. */
+ uint32_t size;
+
+ /* The space that has been allocated in the hash table. */
+ uint32_t capacity;
+} pm_node_hash_t;
+
+/*
+ * Certain sets of nodes (hash keys and when clauses) check for duplicate nodes
+ * to alert the user of potential issues. To do this, we keep a set of the nodes
+ * that have been seen so far, and compare whenever we find a new node.
+ *
+ * We bucket the nodes based on their type to minimize the number of comparisons
+ * that need to be performed.
+ */
+typedef struct {
+ /*
+ * This is the set of IntegerNode and SourceLineNode instances.
+ */
+ pm_node_hash_t integer_nodes;
+
+ /*
+ * This is the set of FloatNode instances.
+ */
+ pm_node_hash_t float_nodes;
+
+ /*
+ * This is the set of RationalNode and ImaginaryNode instances.
+ */
+ pm_node_hash_t number_nodes;
+
+ /*
+ * This is the set of StringNode and SourceFileNode instances.
+ */
+ pm_node_hash_t string_nodes;
+
+ /*
+ * This is the set of RegularExpressionNode instances.
+ */
+ pm_node_hash_t regexp_nodes;
+
+ /*
+ * This is the set of SymbolNode instances.
+ */
+ pm_node_hash_t symbol_nodes;
+
+ /*
+ * A pointer to the last TrueNode instance that was inserted, or NULL.
+ */
+ pm_node_t *true_node;
+
+ /*
+ * A pointer to the last FalseNode instance that was inserted, or NULL.
+ */
+ pm_node_t *false_node;
+
+ /*
+ * A pointer to the last NilNode instance that was inserted, or NULL.
+ */
+ pm_node_t *nil_node;
+
+ /*
+ * A pointer to the last SourceEncodingNode instance that was inserted, or
+ * NULL.
+ */
+ pm_node_t *source_encoding_node;
+} pm_static_literals_t;
+
+/*
+ * Add a node to the set of static literals.
+ */
+pm_node_t * pm_static_literals_add(const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace);
+
+/*
+ * Free the internal memory associated with the given static literals set.
+ */
+void pm_static_literals_free(pm_static_literals_t *literals);
+
+/*
+ * Create a string-based representation of the given static literal.
+ */
+void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, const char *encoding_name, const pm_node_t *node);
+
+#endif
diff --git a/prism/internal/stringy.h b/prism/internal/stringy.h
new file mode 100644
index 0000000000..1aaa23ea75
--- /dev/null
+++ b/prism/internal/stringy.h
@@ -0,0 +1,30 @@
+#ifndef PRISM_INTERNAL_STRINGY_H
+#define PRISM_INTERNAL_STRINGY_H
+
+#include "prism/stringy.h"
+
+/*
+ * 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.
+ */
+void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end);
+
+/*
+ * Compare the underlying lengths and bytes of two strings. Returns 0 if the
+ * strings are equal, a negative number if the left string is less than the
+ * right string, and a positive number if the left string is greater than the
+ * right string.
+ */
+int pm_string_compare(const pm_string_t *left, const pm_string_t *right);
+
+/*
+ * Free the associated memory of the given string.
+ */
+void pm_string_cleanup(pm_string_t *string);
+
+#endif
diff --git a/prism/internal/strncasecmp.h b/prism/internal/strncasecmp.h
new file mode 100644
index 0000000000..775f6a993e
--- /dev/null
+++ b/prism/internal/strncasecmp.h
@@ -0,0 +1,18 @@
+#ifndef PRISM_INTERNAL_STRNCASECMP_H
+#define PRISM_INTERNAL_STRNCASECMP_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.
+ */
+int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length);
+
+#endif
diff --git a/prism/internal/strpbrk.h b/prism/internal/strpbrk.h
new file mode 100644
index 0000000000..d64156c002
--- /dev/null
+++ b/prism/internal/strpbrk.h
@@ -0,0 +1,33 @@
+#ifndef PRISM_INTERNAL_STRPBRK_H
+#define PRISM_INTERNAL_STRPBRK_H
+
+#include "prism/parser.h"
+
+/* The maximum number of bytes in a strpbrk charset. */
+#define PM_STRPBRK_CACHE_SIZE 16
+
+#include <stddef.h>
+#include <stdint.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.
+ */
+const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate);
+
+#endif
diff --git a/prism/internal/tokens.h b/prism/internal/tokens.h
new file mode 100644
index 0000000000..3a983e54ae
--- /dev/null
+++ b/prism/internal/tokens.h
@@ -0,0 +1,11 @@
+#ifndef PRISM_INTERNAL_TOKENS_H
+#define PRISM_INTERNAL_TOKENS_H
+
+#include "prism/ast.h"
+
+/*
+ * Returns the human name of the given token type.
+ */
+const char * pm_token_str(pm_token_type_t token_type);
+
+#endif
diff --git a/prism/json.h b/prism/json.h
new file mode 100644
index 0000000000..11039e7796
--- /dev/null
+++ b/prism/json.h
@@ -0,0 +1,32 @@
+/**
+ * @file json.h
+ */
+#ifndef PRISM_JSON_H
+#define PRISM_JSON_H
+
+#include "prism/excludes.h"
+
+/* We optionally support dumping to JSON. For systems that don't want or need
+ * this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define.
+ */
+#ifndef PRISM_EXCLUDE_JSON
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+#include "prism/buffer.h"
+#include "prism/parser.h"
+
+/**
+ * Dump JSON to the given buffer.
+ *
+ * @param buffer The buffer to serialize to.
+ * @param parser The parser that parsed the node.
+ * @param node The node to serialize.
+ */
+PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) PRISM_NONNULL(1, 2, 3);
+
+#endif
+
+#endif
diff --git a/prism/line_offset_list.c b/prism/line_offset_list.c
new file mode 100644
index 0000000000..ce217ebd3f
--- /dev/null
+++ b/prism/line_offset_list.c
@@ -0,0 +1,100 @@
+#include "prism/compiler/align.h"
+#include "prism/internal/line_offset_list.h"
+#include "prism/internal/arena.h"
+
+#include <assert.h>
+#include <string.h>
+
+/**
+ * Initialize a new line offset list with the given capacity.
+ */
+void
+pm_line_offset_list_init(pm_arena_t *arena, pm_line_offset_list_t *list, size_t capacity) {
+ list->offsets = (uint32_t *) pm_arena_alloc(arena, capacity * sizeof(uint32_t), PRISM_ALIGNOF(uint32_t));
+
+ // The first line always has offset 0.
+ list->offsets[0] = 0;
+ list->size = 1;
+ list->capacity = capacity;
+}
+
+/**
+ * Clear out the newlines that have been appended to the list.
+ */
+void
+pm_line_offset_list_clear(pm_line_offset_list_t *list) {
+ list->size = 1;
+}
+
+/**
+ * Append a new offset to the newline list (slow path: resize and store).
+ */
+void
+pm_line_offset_list_append_slow(pm_arena_t *arena, pm_line_offset_list_t *list, uint32_t cursor) {
+ size_t new_capacity = (list->capacity * 3) / 2;
+ uint32_t *new_offsets = (uint32_t *) pm_arena_alloc(arena, new_capacity * sizeof(uint32_t), PRISM_ALIGNOF(uint32_t));
+
+ memcpy(new_offsets, list->offsets, list->size * sizeof(uint32_t));
+
+ list->offsets = new_offsets;
+ list->capacity = new_capacity;
+
+ assert(list->size == 0 || cursor > list->offsets[list->size - 1]);
+ list->offsets[list->size++] = cursor;
+}
+
+/**
+ * Returns the line of the given offset. If the offset is not in the list, the
+ * line of the closest offset less than the given offset is returned.
+ */
+int32_t
+pm_line_offset_list_line(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) {
+ size_t left = 0;
+ size_t right = list->size - 1;
+
+ while (left <= right) {
+ size_t mid = left + (right - left) / 2;
+
+ if (list->offsets[mid] == cursor) {
+ return ((int32_t) mid) + start_line;
+ }
+
+ if (list->offsets[mid] < cursor) {
+ left = mid + 1;
+ } else {
+ right = mid - 1;
+ }
+ }
+
+ return ((int32_t) left) + start_line - 1;
+}
+
+/**
+ * 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_line_offset_list_line_column(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) {
+ size_t left = 0;
+ size_t right = list->size - 1;
+
+ while (left <= right) {
+ size_t mid = left + (right - left) / 2;
+
+ if (list->offsets[mid] == cursor) {
+ return ((pm_line_column_t) { ((int32_t) mid) + start_line, 0 });
+ }
+
+ if (list->offsets[mid] < cursor) {
+ left = mid + 1;
+ } else {
+ right = mid - 1;
+ }
+ }
+
+ return ((pm_line_column_t) {
+ .line = ((int32_t) left) + start_line - 1,
+ .column = cursor - list->offsets[left - 1]
+ });
+}
diff --git a/prism/line_offset_list.h b/prism/line_offset_list.h
new file mode 100644
index 0000000000..848bc49139
--- /dev/null
+++ b/prism/line_offset_list.h
@@ -0,0 +1,61 @@
+/**
+ * @file line_offset_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_LINE_OFFSET_LIST_H
+#define PRISM_LINE_OFFSET_LIST_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * A list of offsets of the start of lines in a string. The offsets are assumed
+ * to be sorted/inserted in ascending order.
+ */
+typedef struct {
+ /** 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. */
+ uint32_t *offsets;
+} pm_line_offset_list_t;
+
+/**
+ * A line and column in a string.
+ */
+typedef struct {
+ /** The line number. */
+ int32_t line;
+
+ /** The column in bytes. */
+ uint32_t column;
+} pm_line_column_t;
+
+/**
+ * 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 The offset to search for.
+ * @param start_line The line to start counting from.
+ * @returns The line and column of the given offset.
+ */
+PRISM_EXPORTED_FUNCTION pm_line_column_t pm_line_offset_list_line_column(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/list.c b/prism/list.c
new file mode 100644
index 0000000000..8d4cd1be94
--- /dev/null
+++ b/prism/list.c
@@ -0,0 +1,24 @@
+#include "prism/internal/list.h"
+
+/**
+ * Returns the size of the list.
+ */
+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++;
+}
diff --git a/prism/magic_comments.h b/prism/magic_comments.h
new file mode 100644
index 0000000000..c9d6b600e8
--- /dev/null
+++ b/prism/magic_comments.h
@@ -0,0 +1,35 @@
+/**
+ * @file magic_comments.h
+ *
+ * Types and functions related to magic comments found during parsing.
+ */
+#ifndef PRISM_MAGIC_COMMENTS_H
+#define PRISM_MAGIC_COMMENTS_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
+
+#include <stddef.h>
+
+/** An opaque pointer to a magic comment found while parsing. */
+typedef struct pm_magic_comment_t pm_magic_comment_t;
+
+/**
+ * Returns the location of the key associated with the given magic comment.
+ *
+ * @param magic_comment the magic comment whose key location we want to get
+ * @returns the location of the key associated with the given magic comment
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_key(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1);
+
+/**
+ * Returns the location of the value associated with the given magic comment.
+ *
+ * @param magic_comment the magic comment whose value location we want to get
+ * @returns the location of the value associated with the given magic comment
+ */
+PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_value(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/memchr.c b/prism/memchr.c
new file mode 100644
index 0000000000..900e6245b7
--- /dev/null
+++ b/prism/memchr.c
@@ -0,0 +1,37 @@
+#include "prism/internal/memchr.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#define 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.
+ */
+const 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 >= 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);
+ }
+}
diff --git a/prism/node.h b/prism/node.h
index e8686a327c..75bc3c9b2d 100644
--- a/prism/node.h
+++ b/prism/node.h
@@ -6,9 +6,10 @@
#ifndef PRISM_NODE_H
#define PRISM_NODE_H
-#include "prism/defines.h"
-#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/ast.h"
/**
* Loop through each node in the node list, writing each node to the given
@@ -18,51 +19,12 @@
for (size_t index = 0; index < (list)->size && ((node) = (list)->nodes[index]); index++)
/**
- * 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);
-
-/**
- * Prepend a new node onto the beginning of the node list.
- *
- * @param list The list to prepend to.
- * @param node The node to prepend.
- */
-void pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node);
-
-/**
- * Concatenate the given node list onto the end of the other node list.
- *
- * @param list The list to concatenate onto.
- * @param other The list to concatenate.
- */
-void pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other);
-
-/**
- * Free the internal memory associated with the given node list.
- *
- * @param list The list to free.
- */
-void pm_node_list_free(pm_node_list_t *list);
-
-/**
- * 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);
-
-/**
* 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.
+ * @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);
+PRISM_EXPORTED_FUNCTION const char * pm_node_type(pm_node_type_t node_type);
/**
* Visit each of the nodes in this subtree using the given visitor callback. The
@@ -80,7 +42,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ
* bool visit(const pm_node_t *node, void *data) {
* size_t *indent = (size_t *) data;
* for (size_t i = 0; i < *indent * 2; i++) putc(' ', stdout);
- * printf("%s\n", pm_node_type_to_str(node->type));
+ * printf("%s\n", pm_node_type(node->type));
*
* size_t next_indent = *indent + 1;
* size_t *next_data = &next_indent;
@@ -93,18 +55,21 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ
* const char *source = "1 + 2; 3 + 4";
* size_t size = strlen(source);
*
- * pm_parser_t parser;
- * pm_options_t options = { 0 };
- * pm_parser_init(&parser, (const uint8_t *) source, size, &options);
+ * pm_arena_t *arena = pm_arena_new();
+ * pm_options_t *options = pm_options_new();
+ *
+ * pm_parser_t *parser = pm_parser_new(arena, (const uint8_t *) source, size, options);
*
* size_t indent = 0;
- * pm_node_t *node = pm_parse(&parser);
+ * pm_node_t *node = pm_parse(parser);
*
* size_t *data = &indent;
* pm_visit_node(node, visit, data);
*
- * pm_node_destroy(&parser, node);
- * pm_parser_free(&parser);
+ * pm_parser_free(parser);
+ * pm_options_free(options);
+ * pm_arena_free(arena);
+ *
* return EXIT_SUCCESS;
* }
* ```
@@ -113,7 +78,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_typ
* @param visitor The callback to call for each node in the subtree.
* @param data An opaque pointer that is passed to the visitor callback.
*/
-PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data);
+PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) PRISM_NONNULL(1);
/**
* Visit the children of the given node with the given callback. This is the
@@ -124,6 +89,6 @@ PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor
* @param visitor The callback to call for each child node.
* @param data An opaque pointer that is passed to the visitor callback.
*/
-PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data);
+PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) PRISM_NONNULL(1);
#endif
diff --git a/prism/options.c b/prism/options.c
index a457178ce8..b589865a2a 100644
--- a/prism/options.c
+++ b/prism/options.c
@@ -1,18 +1,78 @@
-#include "prism/options.h"
+#include "prism/internal/options.h"
+
+#include "prism/compiler/inline.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/char.h"
+#include "prism/internal/stringy.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Allocate a new options struct. If the options struct cannot be allocated,
+ * this function aborts the process.
+ */
+pm_options_t *
+pm_options_new(void) {
+ pm_options_t *options = xcalloc(1, sizeof(pm_options_t));
+ if (options == NULL) abort();
+ return options;
+}
+
+/**
+ * Free the internal memory associated with the options.
+ */
+void
+pm_options_cleanup(pm_options_t *options) {
+ pm_string_cleanup(&options->filepath);
+ pm_string_cleanup(&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_cleanup(&scope->locals[local_index]);
+ }
+
+ xfree_sized(scope->locals, scope->locals_count * sizeof(pm_string_t));
+ }
+
+ xfree_sized(options->scopes, options->scopes_count * sizeof(pm_options_scope_t));
+}
+
+/**
+ * Free both the held memory of the given options struct and the struct itself.
+ *
+ * @param options The options struct to free.
+ */
+void
+pm_options_free(pm_options_t *options) {
+ pm_options_cleanup(options);
+ xfree_sized(options, sizeof(pm_options_t));
+}
/**
* Set the shebang callback option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) {
options->shebang_callback = shebang_callback;
options->shebang_callback_data = shebang_callback_data;
}
/**
+ * Get the filepath option on the given options struct.
+ */
+const pm_string_t *
+pm_options_filepath(const pm_options_t *options) {
+ return &options->filepath;
+}
+
+/**
* Set the filepath option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_filepath_set(pm_options_t *options, const char *filepath) {
pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
}
@@ -20,7 +80,7 @@ pm_options_filepath_set(pm_options_t *options, const char *filepath) {
/**
* Set the encoding option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_encoding_set(pm_options_t *options, const char *encoding) {
pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
}
@@ -28,7 +88,7 @@ pm_options_encoding_set(pm_options_t *options, const char *encoding) {
/**
* Set the encoding_locked option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
options->encoding_locked = encoding_locked;
}
@@ -36,7 +96,7 @@ pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
/**
* Set the line option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_line_set(pm_options_t *options, int32_t line) {
options->line = line;
}
@@ -44,7 +104,7 @@ pm_options_line_set(pm_options_t *options, int32_t line) {
/**
* Set the frozen string literal option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) {
options->frozen_string_literal = frozen_string_literal ? PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED : PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
}
@@ -52,7 +112,7 @@ pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_l
/**
* Sets the command line option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
options->command_line = command_line;
}
@@ -60,7 +120,7 @@ pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
/**
* Checks if the given slice represents a number.
*/
-static inline bool
+static PRISM_INLINE bool
is_number(const char *string, size_t length) {
return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length;
}
@@ -70,7 +130,7 @@ is_number(const char *string, size_t length) {
* string. If the string contains an invalid option, this returns false.
* Otherwise, it returns true.
*/
-PRISM_EXPORTED_FUNCTION bool
+bool
pm_options_version_set(pm_options_t *options, const char *version, size_t length) {
if (version == NULL) {
options->version = PM_OPTIONS_VERSION_LATEST;
@@ -88,33 +148,43 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
return true;
}
- if (strncmp(version, "3.5", 3) == 0) {
- options->version = PM_OPTIONS_VERSION_LATEST;
+ if (strncmp(version, "3.5", 3) == 0 || strncmp(version, "4.0", 3) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_0;
+ return true;
+ }
+
+ if (strncmp(version, "4.1", 3) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_1;
return true;
}
return false;
}
- if (length >= 4) {
- if (strncmp(version, "3.3.", 4) == 0 && is_number(version + 4, length - 4)) {
+ if (length >= 4 && is_number(version + 4, length - 4)) {
+ if (strncmp(version, "3.3.", 4) == 0) {
options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
return true;
}
- if (strncmp(version, "3.4.", 4) == 0 && is_number(version + 4, length - 4)) {
+ if (strncmp(version, "3.4.", 4) == 0) {
options->version = PM_OPTIONS_VERSION_CRUBY_3_4;
return true;
}
- if (strncmp(version, "3.5.", 4) == 0 && is_number(version + 4, length - 4)) {
- options->version = PM_OPTIONS_VERSION_LATEST;
+ if (strncmp(version, "3.5.", 4) == 0 || strncmp(version, "4.0.", 4) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_0;
+ return true;
+ }
+
+ if (strncmp(version, "4.1.", 4) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_4_1;
return true;
}
}
- if (length >= 6) {
- if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well
+ if (length == 6) {
+ if (strncmp(version, "latest", 6) == 0) {
options->version = PM_OPTIONS_VERSION_LATEST;
return true;
}
@@ -124,9 +194,27 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
}
/**
+ * Set the version option on the given options struct to the lowest version of
+ * Ruby that prism supports.
+ */
+void
+pm_options_version_set_lowest(pm_options_t *options) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
+}
+
+/**
+ * Set the version option on the given options struct to the highest version of
+ * Ruby that prism supports.
+ */
+void
+pm_options_version_set_highest(pm_options_t *options) {
+ options->version = PM_OPTIONS_VERSION_LATEST;
+}
+
+/**
* Set the main script option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_main_script_set(pm_options_t *options, bool main_script) {
options->main_script = main_script;
}
@@ -134,15 +222,23 @@ pm_options_main_script_set(pm_options_t *options, bool main_script) {
/**
* Set the partial script option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
options->partial_script = partial_script;
}
/**
+ * Get the freeze option on the given options struct.
+ */
+bool
+pm_options_freeze(const pm_options_t *options) {
+ return options->freeze;
+}
+
+/**
* Set the freeze option on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_options_freeze_set(pm_options_t *options, bool freeze) {
options->freeze = freeze;
}
@@ -158,7 +254,7 @@ pm_options_freeze_set(pm_options_t *options, bool freeze) {
/**
* Allocate and zero out the scopes array on the given options struct.
*/
-PRISM_EXPORTED_FUNCTION bool
+bool
pm_options_scopes_init(pm_options_t *options, size_t scopes_count) {
options->scopes_count = scopes_count;
options->scopes = xcalloc(scopes_count, sizeof(pm_options_scope_t));
@@ -166,10 +262,20 @@ 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.
+ * Return a constant 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) {
+const pm_options_scope_t *
+pm_options_scope(const pm_options_t *options, size_t index) {
+ return &options->scopes[index];
+}
+
+/**
+ * Return a mutable pointer to the scope at the given index within the given
+ * options.
+ */
+pm_options_scope_t *
+pm_options_scope_mut(pm_options_t *options, size_t index) {
return &options->scopes[index];
}
@@ -177,49 +283,38 @@ 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.
*/
-PRISM_EXPORTED_FUNCTION bool
+void
pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
scope->locals_count = locals_count;
scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
- return scope->locals != NULL;
+ if (scope->locals == NULL) abort();
}
/**
- * Return a pointer to the local at the given index within the given scope.
+ * Return a constant 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) {
+const pm_string_t *
+pm_options_scope_local(const pm_options_scope_t *scope, size_t index) {
return &scope->locals[index];
}
/**
- * Set the forwarding option on the given scope struct.
+ * Return a mutable pointer to the local at the given index within the given
+ * scope.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
- scope->forwarding = forwarding;
+pm_string_t *
+pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) {
+ return &scope->locals[index];
}
/**
- * Free the internal memory associated with the options.
+ * Set the forwarding option on the given scope struct.
*/
-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]);
- }
-
- xfree(scope->locals);
- }
-
- xfree(options->scopes);
+void
+pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
+ scope->forwarding = forwarding;
}
/**
@@ -304,10 +399,7 @@ pm_options_read(pm_options_t *options, const char *data) {
data += 4;
pm_options_scope_t *scope = &options->scopes[scope_index];
- if (!pm_options_scope_init(scope, locals_count)) {
- pm_options_free(options);
- return;
- }
+ pm_options_scope_init(scope, locals_count);
uint8_t forwarding = (uint8_t) *data++;
pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding);
diff --git a/prism/options.h b/prism/options.h
index 2f64701b0c..0f5d7529b1 100644
--- a/prism/options.h
+++ b/prism/options.h
@@ -6,16 +6,27 @@
#ifndef PRISM_OPTIONS_H
#define PRISM_OPTIONS_H
-#include "prism/defines.h"
-#include "prism/util/pm_char.h"
-#include "prism/util/pm_string.h"
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/stringy.h"
#include <stdbool.h>
#include <stddef.h>
-#include <stdint.h>
/**
- * String literals should be made frozen.
+ * A scope of locals surrounding the code that is being parsed.
+ */
+typedef struct pm_options_scope_t pm_options_scope_t;
+
+/**
+ * The options that can be passed to the parser.
+ */
+typedef struct pm_options_t pm_options_t;
+
+/**
+ * String literals should not be frozen.
*/
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED ((int8_t) -1)
@@ -26,42 +37,25 @@
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET ((int8_t) 0)
/**
- * String literals should be made mutable.
+ * String literals should be made frozen.
*/
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED ((int8_t) 1)
-/**
- * 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;
-
- /** Flags for the set of forwarding parameters in this scope. */
- uint8_t forwarding;
-} pm_options_scope_t;
-
/** The default value for parameters. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE = 0x0;
-/** When the scope is fowarding with the * parameter. */
+/** When the scope is forwarding with the * parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS = 0x1;
-/** When the scope is fowarding with the ** parameter. */
+/** When the scope is forwarding with the ** parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS = 0x2;
-/** When the scope is fowarding with the & parameter. */
+/** When the scope is forwarding with the & parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK = 0x4;
-/** When the scope is fowarding with the ... parameter. */
+/** When the scope is forwarding with the ... parameter. */
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL = 0x8;
-// Forward declaration needed by the callback typedef.
-struct pm_options;
-
/**
* The callback called when additional switches are found in a shebang comment
* that need to be processed by the runtime.
@@ -74,118 +68,7 @@ struct pm_options;
* @param shebang_callback_data Any additional data that should be passed along
* to the callback.
*/
-typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const uint8_t *source, size_t length, void *shebang_callback_data);
-
-/**
- * The version of Ruby syntax that we should be parsing with. This is used to
- * allow consumers to specify which behavior they want in case they need to
- * parse in the same way as a specific version of CRuby would have.
- */
-typedef enum {
- /** The current version of prism. */
- PM_OPTIONS_VERSION_LATEST = 0,
-
- /** The vendored version of prism in CRuby 3.3.x. */
- PM_OPTIONS_VERSION_CRUBY_3_3 = 1,
-
- /** The vendored version of prism in CRuby 3.4.x. */
- PM_OPTIONS_VERSION_CRUBY_3_4 = 2
-} pm_options_version_t;
-
-/**
- * The options that can be passed to the parser.
- */
-typedef struct pm_options {
- /**
- * The callback to call when additional switches are found in a shebang
- * comment.
- */
- pm_options_shebang_callback_t shebang_callback;
-
- /**
- * Any additional data that should be passed along to the shebang callback
- * if one was set.
- */
- void *shebang_callback_data;
-
- /** 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
- * 1-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. Scopes are ordered from the outermost scope to the
- * innermost one.
- */
- pm_options_scope_t *scopes;
-
- /**
- * The version of prism that we should be parsing with. This is used to
- * allow consumers to specify which behavior they want in case they need to
- * parse exactly as a specific version of CRuby.
- */
- pm_options_version_t version;
-
- /** A bitset of the various options that were set on the command line. */
- uint8_t command_line;
-
- /**
- * Whether or not the frozen string literal option has been set.
- * May be:
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
- */
- int8_t frozen_string_literal;
-
- /**
- * Whether or not the encoding magic comments should be respected. This is a
- * niche use-case where you want to parse a file with a specific encoding
- * but ignore any encoding magic comments at the top of the file.
- */
- bool encoding_locked;
-
- /**
- * When the file being parsed is the main script, the shebang will be
- * considered for command-line flags (or for implicit -x). The caller needs
- * to pass this information to the parser so that it can behave correctly.
- */
- bool main_script;
-
- /**
- * When the file being parsed is considered a "partial" script, jumps will
- * not be marked as errors if they are not contained within loops/blocks.
- * This is used in the case that you're parsing a script that you know will
- * be embedded inside another script later, but you do not have that context
- * yet. For example, when parsing an ERB template that will be evaluated
- * inside another script.
- */
- bool partial_script;
-
- /**
- * Whether or not the parser should freeze the nodes that it creates. This
- * makes it possible to have a deeply frozen AST that is safe to share
- * between concurrency primitives.
- */
- bool freeze;
-} pm_options_t;
+typedef void (*pm_options_shebang_callback_t)(pm_options_t *options, const uint8_t *source, size_t length, void *shebang_callback_data);
/**
* A bit representing whether or not the command line -a option was set. -a
@@ -220,11 +103,27 @@ static const uint8_t PM_OPTIONS_COMMAND_LINE_P = 0x10;
/**
* A bit representing whether or not the command line -x option was set. -x
- * searches the input file for a shebang that matches the current Ruby engine.
+ * searches the input file for a shebang that includes "ruby".
*/
static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
/**
+ * Allocate a new options struct. If the options struct cannot be allocated,
+ * this function aborts the process.
+ *
+ * @returns A new options struct with default values. It is the responsibility
+ * of the caller to free this struct using pm_options_free().
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_options_t * pm_options_new(void);
+
+/**
+ * Free both the held memory of the given options struct and the struct itself.
+ *
+ * @param options The options struct to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options) PRISM_NONNULL(1);
+
+/**
* Set the shebang callback option on the given options struct.
*
* @param options The options struct to set the shebang callback on.
@@ -232,7 +131,15 @@ static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
* @param shebang_callback_data Any additional data that should be passed along
* to the callback.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data);
+PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) PRISM_NONNULL(1);
+
+/**
+ * Get the filepath option on the given options struct.
+ *
+ * @param options The options struct to get the filepath from.
+ * @returns The filepath.
+ */
+PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_filepath(const pm_options_t *options) PRISM_NONNULL(1);
/**
* Set the filepath option on the given options struct.
@@ -240,7 +147,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *optio
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath) PRISM_NONNULL(1);
/**
* Set the line option on the given options struct.
@@ -248,7 +155,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, cons
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line) PRISM_NONNULL(1);
/**
* Set the encoding option on the given options struct.
@@ -256,7 +163,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding) PRISM_NONNULL(1);
/**
* Set the encoding_locked option on the given options struct.
@@ -264,7 +171,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, cons
* @param options The options struct to set the encoding_locked value on.
* @param encoding_locked The encoding_locked value to set.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked);
+PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) PRISM_NONNULL(1);
/**
* Set the frozen string literal option on the given options struct.
@@ -272,7 +179,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *option
* @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);
+PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) PRISM_NONNULL(1);
/**
* Sets the command line option on the given options struct.
@@ -280,7 +187,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *
* @param options The options struct to set the command line option on.
* @param command_line The command_line value to set.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line);
+PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line) PRISM_NONNULL(1);
/**
* Set the version option on the given options struct by parsing the given
@@ -290,9 +197,25 @@ PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options,
* @param options The options struct to set the version on.
* @param version The version to set.
* @param length The length of the version string.
- * @return Whether or not the version was parsed successfully.
+ * @returns Whether or not the version was parsed successfully.
*/
-PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length);
+PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length) PRISM_NONNULL(1);
+
+/**
+ * Set the version option on the given options struct to the lowest version of
+ * Ruby that prism supports.
+ *
+ * @param options The options struct to set the version on.
+ */
+PRISM_EXPORTED_FUNCTION void pm_options_version_set_lowest(pm_options_t *options) PRISM_NONNULL(1);
+
+/**
+ * Set the version option on the given options struct to the highest version of
+ * Ruby that prism supports.
+ *
+ * @param options The options struct to set the version on.
+ */
+PRISM_EXPORTED_FUNCTION void pm_options_version_set_highest(pm_options_t *options) PRISM_NONNULL(1);
/**
* Set the main script option on the given options struct.
@@ -300,7 +223,7 @@ PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const
* @param options The options struct to set the main script value on.
* @param main_script The main script value to set.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script);
+PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script) PRISM_NONNULL(1);
/**
* Set the partial script option on the given options struct.
@@ -308,7 +231,15 @@ PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, b
* @param options The options struct to set the partial script value on.
* @param partial_script The partial script value to set.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script);
+PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script) PRISM_NONNULL(1);
+
+/**
+ * Get the freeze option on the given options struct.
+ *
+ * @param options The options struct to get the freeze value from.
+ * @returns The freeze value.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_options_freeze(const pm_options_t *options) PRISM_NONNULL(1);
/**
* Set the freeze option on the given options struct.
@@ -316,127 +247,73 @@ PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options
* @param options The options struct to set the freeze value on.
* @param freeze The freeze value to set.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze);
+PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze) PRISM_NONNULL(1);
/**
* 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.
- * @return Whether or not the scopes array was initialized successfully.
+ * @returns Whether or not the scopes array was initialized successfully.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count) PRISM_NONNULL(1);
+
+/**
+ * Return a constant 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.
+ * @returns A constant pointer to the scope at the given index.
*/
-PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count);
+PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope(const pm_options_t *options, size_t index) PRISM_NONNULL(1);
/**
- * Return a pointer to the scope at the given index within the given options.
+ * Return a mutable 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.
+ * @returns A mutable 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);
+PRISM_EXPORTED_FUNCTION pm_options_scope_t * pm_options_scope_mut(pm_options_t *options, size_t index) PRISM_NONNULL(1);
/**
* Create a new options scope struct. This will hold a set of locals that are in
- * scope surrounding the code that is being parsed.
+ * scope surrounding the code that is being parsed. If the scope was unable to
+ * allocate its locals, this function will abort the process.
*
* @param scope The scope struct to initialize.
* @param locals_count The number of locals to allocate.
- * @return Whether or not the scope was initialized successfully.
*/
-PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count);
+PRISM_EXPORTED_FUNCTION void pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) PRISM_NONNULL(1);
/**
- * Return a pointer to the local at the given index within the given scope.
+ * Return a constant 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);
-
-/**
- * Set the forwarding option on the given scope struct.
- *
- * @param scope The scope struct to set the forwarding on.
- * @param forwarding The forwarding value to set.
+ * @returns A constant pointer to the local at the given index.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding);
+PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local(const pm_options_scope_t *scope, size_t index) PRISM_NONNULL(1);
/**
- * Free the internal memory associated with the options.
+ * Return a mutable pointer to the local at the given index within the given
+ * scope.
*
- * @param options The options struct whose internal memory should be freed.
+ * @param scope The scope struct to get the local from.
+ * @param index The index of the local to get.
+ * @returns A mutable pointer to the local at the given index.
*/
-PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
+PRISM_EXPORTED_FUNCTION pm_string_t * pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) PRISM_NONNULL(1);
/**
- * 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` | -p command line option |
- * | `1` | -n command line option |
- * | `1` | -l command line option |
- * | `1` | -a command line option |
- * | `1` | the version |
- * | `1` | encoding locked |
- * | `1` | main script |
- * | `1` | partial script |
- * | `1` | freeze |
- * | `4` | the number of scopes |
- * | ... | the scopes |
- *
- * The version field is an enum, so it should be one of the following values:
- *
- * | value | version |
- * | ----- | ------------------------- |
- * | `0` | use the latest version of prism |
- * | `1` | use the version of prism that is vendored in CRuby 3.3.0 |
- *
- * Each scope is laid out as follows:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the number of locals |
- * | `1` | the forwarding flags |
- * | ... | the locals |
- *
- * Each local is laid 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, encoding locked, main script, and partial script
- * fields are booleans, so their values should be either 0 or 1.
- * * The number of scopes can be 0.
+ * Set the forwarding option on the given scope struct.
*
- * @param options The options struct to deserialize into.
- * @param data The binary string to deserialize from.
+ * @param scope The scope struct to set the forwarding on.
+ * @param forwarding The forwarding value to set.
*/
-void pm_options_read(pm_options_t *options, const char *data);
+PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) PRISM_NONNULL(1);
#endif
diff --git a/prism/pack.c b/prism/pack.c
deleted file mode 100644
index 1388ca8a3b..0000000000
--- a/prism/pack.c
+++ /dev/null
@@ -1,509 +0,0 @@
-#include "prism/pack.h"
-
-// We optionally support parsing String#pack templates. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_PACK define.
-#ifdef PRISM_EXCLUDE_PACK
-
-void pm_pack_parse(void) {}
-
-#else
-
-#include <stdbool.h>
-#include <errno.h>
-
-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;
-}
-
-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;
- }
-}
-
-#endif
diff --git a/prism/pack.h b/prism/pack.h
deleted file mode 100644
index 0b0b4b19cc..0000000000
--- a/prism/pack.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * @file pack.h
- *
- * A pack template string parser.
- */
-#ifndef PRISM_PACK_H
-#define PRISM_PACK_H
-
-#include "prism/defines.h"
-
-// We optionally support parsing String#pack templates. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_PACK define.
-#ifdef PRISM_EXCLUDE_PACK
-
-void pm_pack_parse(void);
-
-#else
-
-#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
-
-#endif
diff --git a/prism/parser.c b/prism/parser.c
new file mode 100644
index 0000000000..415cd31984
--- /dev/null
+++ b/prism/parser.c
@@ -0,0 +1,302 @@
+#include "prism/internal/parser.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/comments.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/magic_comments.h"
+
+#include <stdlib.h>
+
+/**
+ * Register a callback that will be called whenever prism changes the encoding
+ * it is using to parse based on the magic comment.
+ */
+void
+pm_parser_encoding_changed_callback_set(pm_parser_t *parser, pm_encoding_changed_callback_t callback) {
+ parser->encoding_changed_callback = callback;
+}
+
+/**
+ * Register a callback that will be called whenever a token is lexed.
+ */
+void
+pm_parser_lex_callback_set(pm_parser_t *parser, pm_lex_callback_t callback, void *data) {
+ parser->lex_callback.callback = callback;
+ parser->lex_callback.data = data;
+}
+
+/**
+ * Returns the opaque data that is passed to the lex callback when it is called.
+ */
+void *
+pm_parser_lex_callback_data(const pm_parser_t *parser) {
+ return parser->lex_callback.data;
+}
+
+/**
+ * Returns the raw pointer to the start of the source that is being parsed.
+ */
+const uint8_t *
+pm_parser_start(const pm_parser_t *parser) {
+ return parser->start;
+}
+
+/**
+ * Returns the raw pointer to the end of the source that is being parsed.
+ */
+const uint8_t *
+pm_parser_end(const pm_parser_t *parser) {
+ return parser->end;
+}
+
+/**
+ * Returns the line that the parser was considered to have started on.
+ *
+ * @param parser the parser whose start line we want to get
+ * @return the line that the parser was considered to have started on
+ */
+int32_t
+pm_parser_start_line(const pm_parser_t *parser) {
+ return parser->start_line;
+}
+
+/**
+ * Returns the name of the encoding that is being used to parse the source.
+ */
+const char *
+pm_parser_encoding_name(const pm_parser_t *parser) {
+ return parser->encoding->name;
+}
+
+/**
+ * Returns the width of the character at the given pointer in the encoding that
+ * is being used to parse the source.
+ */
+size_t
+pm_parser_encoding_char_width(const pm_parser_t *parser, const uint8_t *start, ptrdiff_t remaining) {
+ return parser->encoding->char_width(start, remaining);
+}
+
+/**
+ * Returns whether or not the parser is using the US-ASCII encoding.
+ */
+bool
+pm_parser_encoding_us_ascii(const pm_parser_t *parser) {
+ return parser->encoding == PM_ENCODING_US_ASCII_ENTRY;
+}
+
+/**
+ * Returns the filepath that is being used to parse the source.
+ */
+const pm_string_t *
+pm_parser_filepath(const pm_parser_t *parser) {
+ return &parser->filepath;
+}
+
+/**
+ * Find a constant in the parser's constant pool. Returns the id of the
+ * constant, or 0 if the constant is not found.
+ */
+pm_constant_id_t
+pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) {
+ return pm_constant_pool_find(&parser->constant_pool, start, length);
+}
+
+/**
+ * Returns the frozen string literal value of the parser.
+ */
+int8_t
+pm_parser_frozen_string_literal(const pm_parser_t *parser) {
+ return parser->frozen_string_literal;
+}
+
+/**
+ * Returns the line offsets that are associated with the given parser.
+ *
+ * @param parser the parser whose line offsets we want to get
+ * @return the line offsets that are associated with the given parser
+ */
+const pm_line_offset_list_t *
+pm_parser_line_offsets(const pm_parser_t *parser) {
+ return &parser->line_offsets;
+}
+
+/**
+ * Returns the location of the __DATA__ section that is associated with the
+ * given parser, if it exists.
+ */
+const pm_location_t *
+pm_parser_data_loc(const pm_parser_t *parser) {
+ return &parser->data_loc;
+}
+
+/**
+ * Returns whether the given parser is continuable, meaning that it could become
+ * valid if more input were appended, as opposed to being definitively invalid.
+ */
+bool
+pm_parser_continuable(const pm_parser_t *parser) {
+ return parser->continuable;
+}
+
+/**
+ * Returns the lex state of the parser. Note that this is an internal detail,
+ * and we are purposefully not returning an instance of the internal enum that
+ * we use to track this. This is only exposed because we need it for some very
+ * niche use cases. Most consumers should avoid this function.
+ */
+int
+pm_parser_lex_state(const pm_parser_t *parser) {
+ return (int) parser->lex_state;
+}
+
+/**
+ * Returns the location associated with the given comment.
+ */
+pm_location_t
+pm_comment_location(const pm_comment_t *comment) {
+ return comment->location;
+}
+
+/**
+ * Returns the type associated with the given comment.
+ */
+pm_comment_type_t
+pm_comment_type(const pm_comment_t *comment) {
+ return comment->type;
+}
+
+/**
+ * Returns the number of comments associated with the given parser.
+ */
+size_t
+pm_parser_comments_size(const pm_parser_t *parser) {
+ return parser->comment_list.size;
+}
+
+/**
+ * Iterates over the comments associated with the given parser and calls the
+ * given callback for each comment.
+ */
+void
+pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) {
+ const pm_list_node_t *current = parser->comment_list.head;
+ while (current != NULL) {
+ const pm_comment_t *comment = (const pm_comment_t *) current;
+ callback(comment, data);
+ current = current->next;
+ }
+}
+
+/**
+ * Returns the location associated with the given magic comment key.
+ */
+pm_location_t
+pm_magic_comment_key(const pm_magic_comment_t *magic_comment) {
+ return magic_comment->key;
+}
+
+/**
+ * Returns the location associated with the given magic comment value.
+ */
+pm_location_t
+pm_magic_comment_value(const pm_magic_comment_t *magic_comment) {
+ return magic_comment->value;
+}
+
+/**
+ * Returns the number of magic comments associated with the given parser.
+ */
+size_t
+pm_parser_magic_comments_size(const pm_parser_t *parser) {
+ return parser->magic_comment_list.size;
+}
+
+/**
+ * Iterates over the magic comments associated with the given parser and calls
+ * the given callback for each magic comment.
+ */
+void
+pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) {
+ const pm_list_node_t *current = parser->magic_comment_list.head;
+ while (current != NULL) {
+ const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) current;
+ callback(magic_comment, data);
+ current = current->next;
+ }
+}
+
+/**
+ * Returns the number of errors associated with the given parser.
+ */
+size_t
+pm_parser_errors_size(const pm_parser_t *parser) {
+ return parser->error_list.size;
+}
+
+/**
+ * Returns the number of warnings associated with the given parser.
+ */
+size_t
+pm_parser_warnings_size(const pm_parser_t *parser) {
+ return parser->warning_list.size;
+}
+
+static inline void
+pm_parser_diagnostics_each(const pm_list_t *list, pm_diagnostic_callback_t callback, void *data) {
+ const pm_list_node_t *current = list->head;
+ while (current != NULL) {
+ const pm_diagnostic_t *diagnostic = (const pm_diagnostic_t *) current;
+ callback(diagnostic, data);
+ current = current->next;
+ }
+}
+
+/**
+ * Iterates over the errors associated with the given parser and calls the
+ * given callback for each error.
+ */
+void
+pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) {
+ pm_parser_diagnostics_each(&parser->error_list, callback, data);
+}
+
+/**
+ * Iterates over the warnings associated with the given parser and calls the
+ * given callback for each warning.
+ */
+void
+pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) {
+ pm_parser_diagnostics_each(&parser->warning_list, callback, data);
+}
+
+/**
+ * Returns the number of constants in the constant pool associated with the
+ * given parser.
+ */
+size_t
+pm_parser_constants_size(const pm_parser_t *parser) {
+ return parser->constant_pool.size;
+}
+
+/**
+ * Iterates over the constants in the constant pool associated with the given
+ * parser and calls the given callback for each constant.
+ */
+void
+pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) {
+ for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
+ const pm_constant_t *constant = &parser->constant_pool.constants[index];
+ callback(constant, data);
+ }
+}
+
+/**
+ * Returns a pointer to the constant at the given id in the constant pool
+ * associated with the given parser.
+ */
+const pm_constant_t *
+pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) {
+ return pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
+}
diff --git a/prism/parser.h b/prism/parser.h
index 992729d655..2c8c4b3a7a 100644
--- a/prism/parser.h
+++ b/prism/parser.h
@@ -6,928 +6,343 @@
#ifndef PRISM_PARSER_H
#define PRISM_PARSER_H
-#include "prism/defines.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
#include "prism/ast.h"
-#include "prism/encoding.h"
+#include "prism/comments.h"
+#include "prism/diagnostic.h"
+#include "prism/line_offset_list.h"
+#include "prism/magic_comments.h"
#include "prism/options.h"
-#include "prism/static_literals.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_string.h"
-
-#include <stdbool.h>
-
-/**
- * This enum provides various bits that represent different kinds of states that
- * the lexer can track. This is used to determine which kind of token to return
- * based on the context of the parser.
- */
-typedef enum {
- PM_LEX_STATE_BIT_BEG,
- PM_LEX_STATE_BIT_END,
- PM_LEX_STATE_BIT_ENDARG,
- PM_LEX_STATE_BIT_ENDFN,
- PM_LEX_STATE_BIT_ARG,
- PM_LEX_STATE_BIT_CMDARG,
- PM_LEX_STATE_BIT_MID,
- PM_LEX_STATE_BIT_FNAME,
- PM_LEX_STATE_BIT_DOT,
- PM_LEX_STATE_BIT_CLASS,
- PM_LEX_STATE_BIT_LABEL,
- PM_LEX_STATE_BIT_LABELED,
- PM_LEX_STATE_BIT_FITEM
-} pm_lex_state_bit_t;
-
-/**
- * This enum combines the various bits from the above enum into individual
- * values that represent the various states of the lexer.
- */
-typedef enum {
- PM_LEX_STATE_NONE = 0,
- PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG),
- PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END),
- PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG),
- PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN),
- PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG),
- PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG),
- PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID),
- PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME),
- PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT),
- PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS),
- PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL),
- PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED),
- PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM),
- PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS,
- PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG,
- PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN
-} pm_lex_state_t;
-
-/**
- * The type of quote that a heredoc uses.
- */
-typedef enum {
- PM_HEREDOC_QUOTE_NONE,
- PM_HEREDOC_QUOTE_SINGLE = '\'',
- PM_HEREDOC_QUOTE_DOUBLE = '"',
- PM_HEREDOC_QUOTE_BACKTICK = '`',
-} pm_heredoc_quote_t;
-
-/**
- * The type of indentation that a heredoc uses.
- */
-typedef enum {
- PM_HEREDOC_INDENT_NONE,
- PM_HEREDOC_INDENT_DASH,
- PM_HEREDOC_INDENT_TILDE,
-} pm_heredoc_indent_t;
-
-/**
- * All of the information necessary to store to lexing a heredoc.
- */
-typedef 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;
-} pm_heredoc_lex_mode_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[7];
- } 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[7];
- } string;
-
- struct {
- /**
- * All of the data necessary to lex a heredoc.
- */
- pm_heredoc_lex_mode_t base;
-
- /**
- * 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;
-
- /** True if the previous token ended with a line continuation. */
- bool line_continuation;
- } 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;
+typedef struct pm_parser_t 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.
+ * Allocate and initialize a parser with the given start and end pointers.
+ *
+ * @param arena The arena to use for all AST-lifetime allocations. It is caller-
+ * owned and must outlive the parser.
+ * @param source The source to parse.
+ * @param size The size of the source.
+ * @param options The optional options to use when parsing. These options must
+ * live for the whole lifetime of this parser.
+ * @returns The initialized parser. It is the responsibility of the caller to
+ * free the parser with `pm_parser_free()`.
*/
-typedef enum {
- /** a null context, used for returning a value from a function */
- PM_CONTEXT_NONE = 0,
-
- /** a begin statement */
- PM_CONTEXT_BEGIN,
-
- /** an ensure statement with an explicit begin */
- PM_CONTEXT_BEGIN_ENSURE,
-
- /** a rescue else statement with an explicit begin */
- PM_CONTEXT_BEGIN_ELSE,
-
- /** a rescue statement with an explicit begin */
- PM_CONTEXT_BEGIN_RESCUE,
-
- /** expressions in block arguments using braces */
- PM_CONTEXT_BLOCK_BRACES,
-
- /** expressions in block arguments using do..end */
- PM_CONTEXT_BLOCK_KEYWORDS,
-
- /** an ensure statement within a do..end block */
- PM_CONTEXT_BLOCK_ENSURE,
-
- /** a rescue else statement within a do..end block */
- PM_CONTEXT_BLOCK_ELSE,
-
- /** a rescue statement within a do..end block */
- PM_CONTEXT_BLOCK_RESCUE,
-
- /** a case when statements */
- PM_CONTEXT_CASE_WHEN,
-
- /** a case in statements */
- PM_CONTEXT_CASE_IN,
-
- /** a class declaration */
- PM_CONTEXT_CLASS,
-
- /** an ensure statement within a class statement */
- PM_CONTEXT_CLASS_ENSURE,
-
- /** a rescue else statement within a class statement */
- PM_CONTEXT_CLASS_ELSE,
-
- /** a rescue statement within a class statement */
- PM_CONTEXT_CLASS_RESCUE,
-
- /** a method definition */
- PM_CONTEXT_DEF,
-
- /** an ensure statement within a method definition */
- PM_CONTEXT_DEF_ENSURE,
-
- /** a rescue else statement within a method definition */
- PM_CONTEXT_DEF_ELSE,
-
- /** a rescue statement within a method definition */
- PM_CONTEXT_DEF_RESCUE,
-
- /** a method definition's parameters */
- PM_CONTEXT_DEF_PARAMS,
-
- /** a defined? expression */
- PM_CONTEXT_DEFINED,
-
- /** 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,
-
- /** 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,
-
- /** an ensure statement within a lambda expression */
- PM_CONTEXT_LAMBDA_ENSURE,
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1);
- /** a rescue else statement within a lambda expression */
- PM_CONTEXT_LAMBDA_ELSE,
-
- /** a rescue statement within a lambda expression */
- PM_CONTEXT_LAMBDA_RESCUE,
+/**
+ * Free both the memory held by the given parser and the parser itself.
+ *
+ * @param parser The parser to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1);
- /** the predicate clause of a loop statement */
- PM_CONTEXT_LOOP_PREDICATE,
+/**
+ * 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);
- /** the top level context */
- PM_CONTEXT_MAIN,
+/**
+ * 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.
+ */
+typedef void (*pm_lex_callback_t)(pm_parser_t *parser, pm_token_t *token, void *data);
- /** a module declaration */
- PM_CONTEXT_MODULE,
+/**
+ * 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_encoding_changed_callback_set(pm_parser_t *parser, pm_encoding_changed_callback_t callback) PRISM_NONNULL(1);
- /** an ensure statement within a module statement */
- PM_CONTEXT_MODULE_ENSURE,
+/**
+ * Register a callback that will be called whenever a token is lexed.
+ *
+ * @param parser The parser to register the callback with.
+ * @param data The opaque data to pass to the callback when it is called.
+ * @param callback The callback to register.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_lex_callback_set(pm_parser_t *parser, pm_lex_callback_t callback, void *data) PRISM_NONNULL(1);
- /** a rescue else statement within a module statement */
- PM_CONTEXT_MODULE_ELSE,
+/**
+ * Returns the opaque data that is passed to the lex callback when it is called.
+ *
+ * @param parser The parser whose lex callback data we want to get.
+ * @returns The opaque data that is passed to the lex callback when it is called.
+ */
+PRISM_EXPORTED_FUNCTION void * pm_parser_lex_callback_data(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a rescue statement within a module statement */
- PM_CONTEXT_MODULE_RESCUE,
+/**
+ * Returns the raw pointer to the start of the source that is being parsed.
+ *
+ * @param parser the parser whose start pointer we want to get
+ * @returns the raw pointer to the start of the source that is being parsed
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_parser_start(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a multiple target expression */
- PM_CONTEXT_MULTI_TARGET,
+/**
+ * Returns the raw pointer to the end of the source that is being parsed.
+ *
+ * @param parser the parser whose end pointer we want to get
+ * @returns the raw pointer to the end of the source that is being parsed
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_parser_end(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a parenthesized expression */
- PM_CONTEXT_PARENS,
+/**
+ * Returns the line that the parser was considered to have started on.
+ *
+ * @param parser the parser whose start line we want to get
+ * @returns the line that the parser was considered to have started on
+ */
+PRISM_EXPORTED_FUNCTION int32_t pm_parser_start_line(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** an END block */
- PM_CONTEXT_POSTEXE,
+/**
+ * Returns the name of the encoding that is being used to parse the source.
+ *
+ * @param parser the parser whose encoding name we want to get
+ * @returns the name of the encoding that is being used to parse the source
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_parser_encoding_name(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a predicate inside an if/elsif/unless statement */
- PM_CONTEXT_PREDICATE,
+/**
+ * Returns the width of the character at the given pointer in the encoding that
+ * is being used to parse the source.
+ *
+ * @param parser the parser whose encoding we want to use
+ * @param start a pointer to the start of the character
+ * @param remaining the number of bytes remaining in the source
+ * @returns the width of the character in bytes
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_encoding_char_width(const pm_parser_t *parser, const uint8_t *start, ptrdiff_t remaining) PRISM_NONNULL(1, 2);
- /** a BEGIN block */
- PM_CONTEXT_PREEXE,
+/**
+ * Returns whether or not the parser is using the US-ASCII encoding.
+ *
+ * @param parser the parser to check
+ * @returns true if the parser is using US-ASCII encoding, false otherwise
+ */
+PRISM_EXPORTED_FUNCTION bool pm_parser_encoding_us_ascii(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a modifier rescue clause */
- PM_CONTEXT_RESCUE_MODIFIER,
+/**
+ * Returns the filepath that is being used to parse the source.
+ *
+ * @param parser the parser whose filepath we want to get
+ * @returns a pointer to the filepath string
+ */
+PRISM_EXPORTED_FUNCTION const pm_string_t * pm_parser_filepath(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a singleton class definition */
- PM_CONTEXT_SCLASS,
+/**
+ * Find a constant in the parser's constant pool. Returns the id of the
+ * constant, or 0 if the constant is not found.
+ *
+ * @param parser the parser whose constant pool we want to search
+ * @param start a pointer to the start of the string to search for
+ * @param length the length of the string to search for
+ * @returns the id of the constant, or 0 if the constant is not found
+ */
+PRISM_EXPORTED_FUNCTION pm_constant_id_t pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) PRISM_NONNULL(1, 2);
- /** an ensure statement with a singleton class */
- PM_CONTEXT_SCLASS_ENSURE,
+/**
+ * Returns the frozen string literal value of the parser, as determined by the
+ * frozen_string_literal magic comment or the option set on the parser.
+ *
+ * @param parser the parser whose frozen string literal value we want to get
+ * @returns -1 if disabled, 0 if unset, 1 if enabled
+ */
+PRISM_EXPORTED_FUNCTION int8_t pm_parser_frozen_string_literal(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a rescue else statement with a singleton class */
- PM_CONTEXT_SCLASS_ELSE,
+/**
+ * Returns the line offsets that are associated with the given parser.
+ *
+ * @param parser the parser whose line offsets we want to get
+ * @returns the line offsets that are associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION const pm_line_offset_list_t * pm_parser_line_offsets(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a rescue statement with a singleton class */
- PM_CONTEXT_SCLASS_RESCUE,
+/**
+ * Returns the location of the __DATA__ section that is associated with the
+ * given parser.
+ *
+ * @param parser the parser whose data location we want to get
+ * @returns the location of the __DATA__ section that is associated with the
+ * given parser. If it is unset, then the length will be set to 0.
+ */
+PRISM_EXPORTED_FUNCTION const pm_location_t * pm_parser_data_loc(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a ternary expression */
- PM_CONTEXT_TERNARY,
+/**
+ * Returns whether the given parser is continuable, meaning that it could become
+ * valid if more input were appended, as opposed to being definitively invalid.
+ *
+ * @param parser the parser whose continuable status we want to get
+ * @returns whether the given parser is continuable
+ */
+PRISM_EXPORTED_FUNCTION bool pm_parser_continuable(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** an unless statement */
- PM_CONTEXT_UNLESS,
+/**
+ * Returns the lex state of the parser. Note that this is an internal detail,
+ * and we are purposefully not returning an instance of the internal enum that
+ * we use to track this. This is only exposed because we need it for some very
+ * niche use cases. Most consumers should avoid this function.
+ *
+ * @param parser the parser whose lex state we want to get
+ * @returns the lex state of the parser
+ */
+PRISM_EXPORTED_FUNCTION int pm_parser_lex_state(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** an until statement */
- PM_CONTEXT_UNTIL,
+/**
+ * Returns the number of comments associated with the given parser.
+ *
+ * @param parser the parser whose comments we want to get the size of
+ * @returns the number of comments associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** a while statement */
- PM_CONTEXT_WHILE,
-} pm_context_t;
+/**
+ * A callback function that can be used to process comments found while parsing.
+ */
+typedef void (*pm_comment_callback_t)(const pm_comment_t *comment, void *data);
-/** 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;
+/**
+ * Iterates over the comments associated with the given parser and calls the
+ * given callback for each comment.
+ *
+ * @param parser the parser whose comments we want to iterate over
+ * @param callback the callback function to call for each comment. This function
+ * will be passed a pointer to the comment and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each comment. This
+ * can be NULL if no data needs to be passed to the callback function.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) PRISM_NONNULL(1);
- /** A pointer to the previous context in the linked list. */
- struct pm_context_node *prev;
-} pm_context_node_t;
+/**
+ * Returns the number of magic comments associated with the given parser.
+ *
+ * @param parser the parser whose magic comments we want to get the size of
+ * @returns the number of magic comments associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_magic_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1);
-/** 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;
+/**
+ * A callback function that can be used to process magic comments found while parsing.
+ */
+typedef void (*pm_magic_comment_callback_t)(const pm_magic_comment_t *magic_comment, void *data);
/**
- * This is a node in the linked list of comments that we've found while parsing.
+ * Iterates over the magic comments associated with the given parser and calls the
+ * given callback for each magic comment.
*
- * @extends pm_list_node_t
+ * @param parser the parser whose magic comments we want to iterate over
+ * @param callback the callback function to call for each magic comment. This
+ * function will be passed a pointer to the magic comment and the data
+ * parameter passed to this function.
+ * @param data the data to pass to the callback function for each magic comment.
+ * This can be NULL if no data needs to be passed to the callback function.
*/
-typedef struct pm_comment {
- /** The embedded base node. */
- pm_list_node_t node;
+PRISM_EXPORTED_FUNCTION void pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) PRISM_NONNULL(1);
- /** The location of the comment in the source. */
- pm_location_t location;
+/**
+ * Returns the number of errors associated with the given parser.
+ *
+ * @param parser the parser whose errors we want to get the size of
+ * @returns the number of errors associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_errors_size(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** The type of comment that we've found. */
- pm_comment_type_t type;
-} pm_comment_t;
+/**
+ * Returns the number of warnings associated with the given parser.
+ *
+ * @param parser the parser whose warnings we want to get the size of
+ * @returns the number of warnings associated with the given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_warnings_size(const pm_parser_t *parser) PRISM_NONNULL(1);
/**
- * This is a node in the linked list of magic comments that we've found while
+ * A callback function that can be used to process diagnostics found while
* parsing.
+ */
+typedef void (*pm_diagnostic_callback_t)(const pm_diagnostic_t *diagnostic, void *data);
+
+/**
+ * Iterates over the errors associated with the given parser and calls the
+ * given callback for each error.
*
- * @extends pm_list_node_t
+ * @param parser the parser whose errors we want to iterate over
+ * @param callback the callback function to call for each error. This function
+ * will be passed a pointer to the error and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each error. This
+ * can be NULL if no data needs to be passed to the callback function.
*/
-typedef struct {
- /** The embedded base node. */
- pm_list_node_t node;
+PRISM_EXPORTED_FUNCTION void pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1);
- /** A pointer to the start of the key in the source. */
- const uint8_t *key_start;
+/**
+ * Iterates over the warnings associated with the given parser and calls the
+ * given callback for each warning.
+ *
+ * @param parser the parser whose warnings we want to iterate over
+ * @param callback the callback function to call for each warning. This function
+ * will be passed a pointer to the warning and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each warning. This
+ * can be NULL if no data needs to be passed to the callback function.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1);
- /** A pointer to the start of the value in the source. */
- const uint8_t *value_start;
+/**
+ * Returns the number of constants in the constant pool associated with the
+ * given parser.
+ *
+ * @param parser the parser whose constant pool constants we want to get the
+ * size of
+ * @returns the number of constants in the constant pool associated with the
+ * given parser
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_parser_constants_size(const pm_parser_t *parser) PRISM_NONNULL(1);
- /** The length of the key in the source. */
- uint32_t key_length;
+/**
+ * A callback function that can be used to process constants found while
+ * parsing.
+ */
+typedef void (*pm_constant_callback_t)(const pm_constant_t *constant, void *data);
- /** The length of the value in the source. */
- uint32_t value_length;
-} pm_magic_comment_t;
+/**
+ * Iterates over the constants in the constant pool associated with the given
+ * parser and calls the given callback for each constant.
+ *
+ * @param parser the parser whose constants we want to iterate over
+ * @param callback the callback function to call for each constant. This function
+ * will be passed a pointer to the constant and the data parameter passed to
+ * this function.
+ * @param data the data to pass to the callback function for each constant. This
+ * can be NULL if no data needs to be passed to the callback function.
+ */
+PRISM_EXPORTED_FUNCTION void pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) PRISM_NONNULL(1);
/**
- * 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.
+ * Returns a pointer to the constant at the given id in the constant pool
+ * associated with the given parser.
+ *
+ * @param parser the parser whose constant pool we want to look up from
+ * @param constant_id the id of the constant to look up (1-based)
+ * @returns a pointer to the constant at the given id
*/
-typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser);
+PRISM_EXPORTED_FUNCTION const pm_constant_t * pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) PRISM_NONNULL(1);
/**
- * 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;
-
-/** The type of shareable constant value that can be set. */
-typedef uint8_t pm_shareable_constant_value_t;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY;
-
-/**
- * This tracks an individual local variable in a certain lexical context, as
- * well as the number of times is it read.
- */
-typedef struct {
- /** The name of the local variable. */
- pm_constant_id_t name;
-
- /** The location of the local variable in the source. */
- pm_location_t location;
-
- /** The index of the local variable in the local table. */
- uint32_t index;
-
- /** The number of times the local variable is read. */
- uint32_t reads;
-
- /** The hash of the local variable. */
- uint32_t hash;
-} pm_local_t;
-
-/**
- * This is a set of local variables in a certain lexical context (method, class,
- * module, etc.). We need to track how many times these variables are read in
- * order to warn if they only get written.
- */
-typedef struct pm_locals {
- /** The number of local variables in the set. */
- uint32_t size;
-
- /** The capacity of the local variables set. */
- uint32_t capacity;
-
- /** The nullable allocated memory for the local variables in the set. */
- pm_local_t *locals;
-} pm_locals_t;
-
-/** The flags about scope parameters that can be set. */
-typedef uint8_t pm_scope_parameters_t;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NONE = 0x0;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x1;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x2;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x4;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x8;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED = 0x10;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_INNER = 0x20;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_FOUND = 0x40;
-
-/**
- * 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 {
- /** A pointer to the previous scope in the linked list. */
- struct pm_scope *previous;
-
- /** The IDs of the locals in the given scope. */
- pm_locals_t locals;
-
- /**
- * This is a list of the implicit parameters contained within the block.
- * These will be processed after the block is parsed to determine the kind
- * of parameters node that should be used and to check if any errors need to
- * be added.
- */
- pm_node_list_t implicit_parameters;
-
- /**
- * This is a bitfield that indicates the parameters that are being used in
- * this scope. It is a combination of the PM_SCOPE_PARAMETERS_* constants.
- * There are three different kinds of parameters that can be used in a
- * scope:
- *
- * - Ordinary parameters (e.g., def foo(bar); end)
- * - Numbered parameters (e.g., def foo; _1; end)
- * - The it parameter (e.g., def foo; it; end)
- *
- * If ordinary parameters are being used, then certain parameters can be
- * forwarded to another method/structure. Those are indicated by four
- * additional bits in the params field. For example, some combinations of:
- *
- * - def foo(*); end
- * - def foo(**); end
- * - def foo(&); end
- * - def foo(...); end
- */
- pm_scope_parameters_t parameters;
-
- /**
- * The current state of constant shareability for this scope. This is
- * changed by magic shareable_constant_value comments.
- */
- pm_shareable_constant_value_t shareable_constant;
-
- /**
- * 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;
-} pm_scope_t;
-
-/**
- * A struct that represents a stack of boolean values.
- */
-typedef uint32_t pm_state_stack_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 next node identifier that will be assigned. This is a unique
- * identifier used to track nodes such that the syntax tree can be dropped
- * but the node can be found through another parse.
- */
- uint32_t node_id;
-
- /** 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;
-
- /**
- * An optional location that represents the location of the __END__ marker
- * and the rest of the content of the file. This content is loaded into the
- * DATA constant when the file being parsed is the main file being executed.
- */
- 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 hash keys for the hash that is currently being parsed. This is not
- * usually necessary because it can pass it down the various call chains,
- * but in the event that you're parsing a hash that is being directly
- * pushed into another hash with **, we need to share the hash keys so that
- * we can warn for the nested hash as well.
- */
- pm_static_literals_t *current_hash_keys;
-
- /**
- * 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;
-
- /**
- * 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;
-
- /**
- * When parsing block exits (e.g., break, next, redo), we need to validate
- * that they are in correct contexts. For the most part we can do this by
- * looking at our parent contexts. However, modifier while and until
- * expressions can change that context to make block exits valid. In these
- * cases, we need to keep track of the block exits and then validate them
- * after the expression has been parsed.
- *
- * We use a pointer here because we don't want to keep a whole list attached
- * since this will only be used in the context of begin/end expressions.
- */
- pm_node_list_t *current_block_exits;
-
- /** The version of prism that we should use to parse. */
- pm_options_version_t version;
-
- /** The command line flags given from the options. */
- uint8_t command_line;
-
- /**
- * Whether or not we have found a frozen_string_literal magic comment with
- * a true or false value.
- * May be:
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
- */
- int8_t frozen_string_literal;
-
- /**
- * Whether or not we are parsing an eval string. This impacts whether or not
- * we should evaluate if block exits/yields are valid.
- */
- bool parsing_eval;
-
- /**
- * Whether or not we are parsing a "partial" script, which is a script that
- * will be evaluated in the context of another script, so we should not
- * check jumps (next/break/etc.) for validity.
- */
- bool partial_script;
-
- /** 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;
-
- /**
- * This is very specialized behavior for when you want to parse in a context
- * that does not respect encoding comments. Its main use case is translating
- * into the whitequark/parser AST which re-encodes source files in UTF-8
- * before they are parsed and ignores encoding comments.
- */
- bool encoding_locked;
-
- /**
- * Whether or not the encoding has been changed by a magic comment. We use
- * this to provide a fast path for the lexer instead of going through the
- * function pointer.
- */
- bool encoding_changed;
-
- /**
- * This flag indicates that we are currently parsing a pattern matching
- * expression and impacts that calculation of newlines.
- */
- bool pattern_matching_newlines;
-
- /** This flag indicates that we are currently parsing a keyword argument. */
- bool in_keyword_arg;
-
- /**
- * Whether or not the parser has seen a token that has semantic meaning
- * (i.e., a token that is not a comment or whitespace).
- */
- bool semantic_token_seen;
-
- /**
- * True if the current regular expression being lexed contains only ASCII
- * characters.
- */
- bool current_regular_expression_ascii_only;
-
- /**
- * By default, Ruby always warns about mismatched indentation. This can be
- * toggled with a magic comment.
- */
- bool warn_mismatched_indentation;
-};
+ * Initiate the parser with the given parser.
+ *
+ * @param parser The parser to use.
+ * @returns The AST representing the source.
+ */
+PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1);
#endif
diff --git a/prism/prettyprint.h b/prism/prettyprint.h
index 5a52b2b6b8..0d8e416341 100644
--- a/prism/prettyprint.h
+++ b/prism/prettyprint.h
@@ -6,19 +6,16 @@
#ifndef PRISM_PRETTYPRINT_H
#define PRISM_PRETTYPRINT_H
-#include "prism/defines.h"
+#include "prism/excludes.h"
-#ifdef PRISM_EXCLUDE_PRETTYPRINT
+#ifndef PRISM_EXCLUDE_PRETTYPRINT
-void pm_prettyprint(void);
-
-#else
-
-#include <stdio.h>
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
#include "prism/ast.h"
+#include "prism/buffer.h"
#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
/**
* Pretty-prints the AST represented by the given node to the given buffer.
@@ -27,7 +24,7 @@ void pm_prettyprint(void);
* @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);
+PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) PRISM_NONNULL(1, 2, 3);
#endif
diff --git a/prism/prism.c b/prism/prism.c
index f52008fe1e..a2e04ed106 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -1,4 +1,90 @@
-#include "prism.h"
+#include "prism/compiler/accel.h"
+#include "prism/compiler/fallthrough.h"
+#include "prism/compiler/unused.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/arena.h"
+#include "prism/internal/bit.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/char.h"
+#include "prism/internal/comments.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/isinf.h"
+#include "prism/internal/line_offset_list.h"
+#include "prism/internal/list.h"
+#include "prism/internal/magic_comments.h"
+#include "prism/internal/memchr.h"
+#include "prism/internal/node.h"
+#include "prism/internal/options.h"
+#include "prism/internal/parser.h"
+#include "prism/internal/regexp.h"
+#include "prism/internal/serialize.h"
+#include "prism/internal/source.h"
+#include "prism/internal/static_literals.h"
+#include "prism/internal/stringy.h"
+#include "prism/internal/strncasecmp.h"
+#include "prism/internal/strpbrk.h"
+#include "prism/internal/tokens.h"
+
+#include "prism/excludes.h"
+#include "prism/serialize.h"
+#include "prism/stream.h"
+#include "prism/version.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * When we are parsing using recursive descent, we want to protect against
+ * malicious payloads that could attempt to crash our parser. We do this by
+ * specifying a maximum depth to which we are allowed to recurse.
+ */
+#ifndef PRISM_DEPTH_MAXIMUM
+ #define PRISM_DEPTH_MAXIMUM 10000
+#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
+
+/**
+ * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its
+ * branch predication.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+ /** The compiler should predicate that this branch will be taken. */
+ #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
+
+ /** The compiler should predicate that this branch will not be taken. */
+ #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+ /** Void because this platform does not support branch prediction hints. */
+ #define PRISM_LIKELY(x) (x)
+
+ /** Void because this platform does not support branch prediction hints. */
+ #define PRISM_UNLIKELY(x) (x)
+#endif
/**
* The prism version and the serialization format.
@@ -19,6 +105,51 @@ pm_version(void) {
#define MAX(a,b) (((a)>(b))?(a):(b))
/******************************************************************************/
+/* Helpful AST-related macros */
+/******************************************************************************/
+
+#define U32(value_) ((uint32_t) (value_))
+
+#define FL PM_NODE_FLAGS
+#define UP PM_NODE_UPCAST
+
+#define PM_LOCATION_START(location_) ((location_)->start)
+#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
+
+#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
+#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
+#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
+#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
+
+#define PM_NODE_START(node_) (UP(node_)->location.start)
+#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
+#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
+#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
+
+#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
+#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
+
+#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
+#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
+#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
+#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
+#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
+
+#define PM_LOCATION_INIT(start_, length_) ((pm_location_t) { .start = (start_), .length = (length_) })
+#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
+#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
+#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
+
+#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
+#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
+#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
+#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
+
+#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
+#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
+#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
+
+/******************************************************************************/
/* Lex mode manipulations */
/******************************************************************************/
@@ -26,7 +157,7 @@ pm_version(void) {
* Returns the incrementor character that should be used to increment the
* nesting count if one is possible.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
lex_mode_incrementor(const uint8_t start) {
switch (start) {
case '(':
@@ -43,7 +174,7 @@ lex_mode_incrementor(const uint8_t start) {
* Returns the matching character that should be used to terminate a list
* beginning with the given character.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
lex_mode_terminator(const uint8_t start) {
switch (start) {
case '(':
@@ -85,7 +216,7 @@ lex_mode_push(pm_parser_t *parser, pm_lex_mode_t lex_mode) {
/**
* Push on a new list lex mode.
*/
-static inline bool
+static PRISM_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);
@@ -103,7 +234,8 @@ lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) {
// 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));
+ memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
+ memcpy(breakpoints, "\\ \t\f\r\v\n", sizeof("\\ \t\f\r\v\n") - 1);
size_t index = 7;
// Now we'll add the terminator to the list of breakpoints. If the
@@ -132,7 +264,7 @@ lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) {
* 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
+static PRISM_INLINE bool
lex_mode_push_list_eof(pm_parser_t *parser) {
return lex_mode_push_list(parser, false, '\0');
}
@@ -140,7 +272,7 @@ lex_mode_push_list_eof(pm_parser_t *parser) {
/**
* Push on a new regexp lex mode.
*/
-static inline bool
+static PRISM_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,
@@ -155,7 +287,8 @@ lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminato
// regular expression. We'll use strpbrk to find the first of these
// characters.
uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
- memcpy(breakpoints, "\r\n\\#\0\0", sizeof(lex_mode.as.regexp.breakpoints));
+ memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
+ memcpy(breakpoints, "\r\n\\#", sizeof("\r\n\\#") - 1);
size_t index = 4;
// First we'll add the terminator.
@@ -175,7 +308,7 @@ lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminato
/**
* Push on a new string lex mode.
*/
-static inline bool
+static PRISM_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,
@@ -191,7 +324,8 @@ lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed
// 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, "\r\n\\\0\0\0", sizeof(lex_mode.as.string.breakpoints));
+ memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
+ memcpy(breakpoints, "\r\n\\", sizeof("\r\n\\") - 1);
size_t index = 3;
// Now add in the terminator. If the terminator is not already a NULL byte,
@@ -221,7 +355,7 @@ lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed
* 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
+static PRISM_INLINE bool
lex_mode_push_string_eof(pm_parser_t *parser) {
return lex_mode_push_string(parser, false, false, '\0', '\0');
}
@@ -241,7 +375,7 @@ lex_mode_pop(pm_parser_t *parser) {
} else {
parser->lex_modes.index--;
pm_lex_mode_t *prev = parser->lex_modes.current->prev;
- xfree(parser->lex_modes.current);
+ xfree_sized(parser->lex_modes.current, sizeof(pm_lex_mode_t));
parser->lex_modes.current = prev;
}
}
@@ -249,7 +383,7 @@ lex_mode_pop(pm_parser_t *parser) {
/**
* This is the equivalent of IS_lex_state is CRuby.
*/
-static inline bool
+static PRISM_INLINE bool
lex_state_p(const pm_parser_t *parser, pm_lex_state_t state) {
return parser->lex_state & state;
}
@@ -260,7 +394,7 @@ typedef enum {
PM_IGNORED_NEWLINE_PATTERN
} pm_ignored_newline_type_t;
-static inline pm_ignored_newline_type_t
+static PRISM_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);
@@ -273,17 +407,17 @@ lex_state_ignored_p(pm_parser_t *parser) {
}
}
-static inline bool
+static PRISM_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
+static PRISM_INLINE bool
lex_state_arg_p(pm_parser_t *parser) {
return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
}
-static inline bool
+static PRISM_INLINE bool
lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) {
if (parser->current.end >= parser->end) {
return false;
@@ -291,7 +425,7 @@ lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) {
return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
}
-static inline bool
+static PRISM_INLINE bool
lex_state_end_p(pm_parser_t *parser) {
return lex_state_p(parser, PM_LEX_STATE_END_ANY);
}
@@ -299,7 +433,7 @@ lex_state_end_p(pm_parser_t *parser) {
/**
* This is the equivalent of IS_AFTER_OPERATOR in CRuby.
*/
-static inline bool
+static PRISM_INLINE bool
lex_state_operator_p(pm_parser_t *parser) {
return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
}
@@ -308,7 +442,7 @@ lex_state_operator_p(pm_parser_t *parser) {
* Set the state of the lexer. This is defined as a function to be able to put a
* breakpoint in it.
*/
-static inline void
+static PRISM_INLINE void
lex_state_set(pm_parser_t *parser, pm_lex_state_t state) {
parser->lex_state = state;
}
@@ -322,7 +456,7 @@ lex_state_set(pm_parser_t *parser, pm_lex_state_t state) {
#endif
#if PM_DEBUG_LOGGING
-PRISM_ATTRIBUTE_UNUSED static void
+PRISM_UNUSED static void
debug_state(pm_parser_t *parser) {
fprintf(stderr, "STATE: ");
bool first = true;
@@ -403,140 +537,134 @@ debug_lex_state_set(pm_parser_t *parser, pm_lex_state_t state, char const * call
/**
* 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);
+static PRISM_INLINE void
+pm_parser_err(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
+ pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
}
/**
- * Append an error to the list of errors on the parser using a format string.
+ * Append an error to the list of errors on the parser using the location of the
+ * given token.
*/
-#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
- pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
+static PRISM_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, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
+}
/**
* Append an error to the list of errors on the parser using the location of the
* current token.
*/
-static inline void
+static PRISM_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);
+ pm_parser_err_token(parser, &parser->current, diag_id);
}
/**
- * Append an error to the list of errors on the parser using the given location
- * using a format string.
+ * Append an error to the list of errors on the parser using the location of the
+ * previous token.
*/
-#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
- PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
+static PRISM_INLINE void
+pm_parser_err_previous(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
+ pm_parser_err_token(parser, &parser->previous, diag_id);
+}
/**
* Append an error to the list of errors on the parser using the location of the
* given node.
*/
-static inline void
+static PRISM_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);
+ pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), 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_PARSER_ERR_FORMAT(parser, (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
- * given node and a format string, and add on the content of the node.
+ * Append an error to the list of errors on the parser using a format string.
*/
-#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
- PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
+#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
+ pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
/**
* Append an error to the list of errors on the parser using the location of the
- * previous token.
+ * given node and a format string.
*/
-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);
-}
+#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
+ PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
/**
* Append an error to the list of errors on the parser using the location of the
- * given token.
+ * given node and a format string, and add on the content of the node.
*/
-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);
-}
+#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
+ PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
/**
* 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_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
+#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
+ PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
/**
* Append an error to the list of errors on the parser using the location of the
* given token and a format string, and add on the content of the token.
*/
-#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
- PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
+#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
+ PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
/**
* 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) {
- pm_diagnostic_list_append(&parser->warning_list, start, end, diag_id);
+static PRISM_INLINE void
+pm_parser_warn(pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
+ pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
}
/**
* Append a warning to the list of warnings on the parser using the location of
* the given token.
*/
-static inline void
+static PRISM_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);
+ pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
}
/**
* Append a warning to the list of warnings on the parser using the location of
* the given node.
*/
-static inline void
+static PRISM_INLINE void
pm_parser_warn_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_t diag_id) {
- pm_parser_warn(parser, node->location.start, node->location.end, diag_id);
+ pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
}
/**
- * Append a warning to the list of warnings on the parser using a format string.
+ * Append a warning to the list of warnings on the parser using a format string
+ * and the given location.
*/
-#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
- pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
+#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
+ pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
/**
* Append a warning to the list of warnings on the parser using the location of
* the given token and a format string.
*/
-#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
- PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
+#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
+ PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
/**
* Append a warning to the list of warnings on the parser using the location of
* the given token and a format string, and add on the content of the token.
*/
-#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
- PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
+#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
+ PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
/**
* Append a warning to the list of warnings on the parser using the location of
* the given node and a format string.
*/
-#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
- PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
+#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
+ PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
/**
* Add an error for an expected heredoc terminator. This is a special function
@@ -547,8 +675,8 @@ static void
pm_parser_err_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ident_length) {
PM_PARSER_ERR_FORMAT(
parser,
- ident_start,
- ident_start + ident_length,
+ U32(ident_start - parser->start),
+ U32(ident_length),
PM_ERR_HEREDOC_TERM,
(int) ident_length,
(const char *) ident_start
@@ -708,7 +836,7 @@ pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t
/**
* Get the current state of constant shareability.
*/
-static inline pm_shareable_constant_value_t
+static PRISM_INLINE pm_shareable_constant_value_t
pm_parser_scope_shareable_constant_get(pm_parser_t *parser) {
return parser->current_scope->shareable_constant;
}
@@ -733,12 +861,12 @@ pm_parser_scope_shareable_constant_set(pm_parser_t *parser, pm_shareable_constan
/**
* The point at which the set of locals switches from being a list to a hash.
*/
-#define PM_LOCALS_HASH_THRESHOLD 9
+#define PM_LOCALS_HASH_THRESHOLD 5
static void
pm_locals_free(pm_locals_t *locals) {
if (locals->capacity > 0) {
- xfree(locals->locals);
+ xfree_sized(locals->locals, locals->capacity * sizeof(pm_local_t));
}
}
@@ -810,11 +938,13 @@ pm_locals_resize(pm_locals_t *locals) {
* @return True if the local was added, and false if the local already exists.
*/
static bool
-pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start, const uint8_t *end, uint32_t reads) {
+pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, uint32_t start, uint32_t length, uint32_t reads) {
if (locals->size >= (locals->capacity / 4 * 3)) {
pm_locals_resize(locals);
}
+ locals->bloom |= (1u << (name & 31));
+
if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
for (uint32_t index = 0; index < locals->capacity; index++) {
pm_local_t *local = &locals->locals[index];
@@ -822,7 +952,7 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
if (local->name == PM_CONSTANT_ID_UNSET) {
*local = (pm_local_t) {
.name = name,
- .location = { .start = start, .end = end },
+ .location = { .start = start, .length = length },
.index = locals->size++,
.reads = reads,
.hash = 0
@@ -843,7 +973,7 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
if (local->name == PM_CONSTANT_ID_UNSET) {
*local = (pm_local_t) {
.name = name,
- .location = { .start = start, .end = end },
+ .location = { .start = start, .length = length },
.index = locals->size++,
.reads = reads,
.hash = initial_hash
@@ -867,6 +997,8 @@ pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start
*/
static uint32_t
pm_locals_find(pm_locals_t *locals, pm_constant_id_t name) {
+ if (!(locals->bloom & (1u << (name & 31)))) return UINT32_MAX;
+
if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
for (uint32_t index = 0; index < locals->size; index++) {
pm_local_t *local = &locals->locals[index];
@@ -943,8 +1075,8 @@ pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) {
* written but not read in certain contexts.
*/
static void
-pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) {
- pm_constant_id_list_init_capacity(list, locals->size);
+pm_locals_order(pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) {
+ pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
// If we're still below the threshold for switching to a hash, then we only
// need to loop over the locals until we hit the size because the locals are
@@ -961,14 +1093,14 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals,
if (local->name != PM_CONSTANT_ID_UNSET) {
pm_constant_id_list_insert(list, (size_t) local->index, local->name);
- if (warn_unused && local->reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->location.start, parser->start_line) >= 0))) {
+ if (warn_unused && local->reads == 0 && ((parser->start_line >= 0) || (pm_line_offset_list_line(&parser->line_offsets, local->location.start, parser->start_line) >= 0))) {
pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
if (constant->length >= 1 && *constant->start != '_') {
PM_PARSER_WARN_FORMAT(
parser,
local->location.start,
- local->location.end,
+ local->location.length,
PM_WARN_UNUSED_LOCAL_VARIABLE,
(int) constant->length,
(const char *) constant->start
@@ -986,43 +1118,53 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals,
/**
* 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));
+static PRISM_INLINE pm_constant_id_t
+pm_parser_constant_id_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
+ /* Fast path: if this is the same token as the last lookup (same pointer
+ * range), return the cached result. */
+ if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
+ return parser->constant_cache.id;
+ }
+
+ pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (size_t) (end - start));
+
+ parser->constant_cache.start = start;
+ parser->constant_cache.end = end;
+ parser->constant_cache.id = id;
+
+ return id;
}
/**
* Retrieve the constant pool id for the given string.
*/
-static inline pm_constant_id_t
+static PRISM_INLINE pm_constant_id_t
pm_parser_constant_id_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
- return pm_constant_pool_insert_owned(&parser->constant_pool, start, length);
+ return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
}
/**
* Retrieve the constant pool id for the given static literal C string.
*/
-static inline pm_constant_id_t
+static PRISM_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);
+ return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (const uint8_t *) start, length);
}
/**
* Retrieve the constant pool id for the given token.
*/
-static inline pm_constant_id_t
+static PRISM_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);
+ return pm_parser_constant_id_raw(parser, token->start, token->end);
}
/**
- * Retrieve the constant pool id for the given token. If the token is not
- * provided, then return 0.
+ * This macro allows you to define a case statement for all of the nodes that
+ * may result in a void value.
*/
-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);
-}
+#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
+ case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
/**
* Check whether or not the given node is value expression.
@@ -1035,12 +1177,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
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:
+ case PM_CASE_VOID_VALUE:
return void_node != NULL ? void_node : node;
case PM_MATCH_PREDICATE_NODE:
return NULL;
@@ -1049,57 +1186,128 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
if (cast->ensure_clause != NULL) {
if (cast->rescue_clause != NULL) {
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->rescue_clause);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->rescue_clause));
if (vn != NULL) return vn;
}
if (cast->statements != NULL) {
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
if (vn != NULL) return vn;
}
- node = (pm_node_t *) cast->ensure_clause;
+ node = UP(cast->ensure_clause);
} else if (cast->rescue_clause != NULL) {
- if (cast->statements == NULL) return NULL;
+ // https://bugs.ruby-lang.org/issues/21669
+ if (cast->else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ if (cast->statements == NULL) return NULL;
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
- if (vn == NULL) return NULL;
- if (void_node == NULL) void_node = vn;
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
+ if (vn == NULL) return NULL;
+ if (void_node == NULL) void_node = vn;
+ }
for (pm_rescue_node_t *rescue_clause = cast->rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->subsequent) {
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) rescue_clause->statements);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
+
if (vn == NULL) {
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return NULL;
+ }
void_node = NULL;
break;
}
- if (void_node == NULL) {
- void_node = vn;
- }
}
if (cast->else_clause != NULL) {
- node = (pm_node_t *) cast->else_clause;
+ node = UP(cast->else_clause);
+
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
+ pm_node_t *vn = pm_check_value_expression(parser, node);
+ if (vn != NULL) return vn;
+ }
} else {
return void_node;
}
} else {
- node = (pm_node_t *) cast->statements;
+ node = UP(cast->statements);
}
break;
}
+ case PM_CASE_NODE: {
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return NULL;
+ }
+
+ pm_case_node_t *cast = (pm_case_node_t *) node;
+ if (cast->else_clause == NULL) return NULL;
+
+ pm_node_t *condition;
+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
+ assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
+
+ pm_when_node_t *cast = (pm_when_node_t *) condition;
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
+ if (vn == NULL) return NULL;
+ if (void_node == NULL) void_node = vn;
+ }
+
+ node = UP(cast->else_clause);
+ break;
+ }
+ case PM_CASE_MATCH_NODE: {
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return NULL;
+ }
+
+ pm_case_match_node_t *cast = (pm_case_match_node_t *) node;
+ if (cast->else_clause == NULL) return NULL;
+
+ pm_node_t *condition;
+ PM_NODE_LIST_FOREACH(&cast->conditions, index, condition) {
+ assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
+
+ pm_in_node_t *cast = (pm_in_node_t *) condition;
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
+ if (vn == NULL) return NULL;
+ if (void_node == NULL) void_node = vn;
+ }
+
+ node = UP(cast->else_clause);
+ break;
+ }
case PM_ENSURE_NODE: {
pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
- node = (pm_node_t *) cast->statements;
+ node = UP(cast->statements);
break;
}
case PM_PARENTHESES_NODE: {
pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
- node = (pm_node_t *) cast->body;
+ node = UP(cast->body);
break;
}
case PM_STATEMENTS_NODE: {
pm_statements_node_t *cast = (pm_statements_node_t *) node;
+
+ // https://bugs.ruby-lang.org/issues/21669
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
+ pm_node_t *body_part;
+ PM_NODE_LIST_FOREACH(&cast->body, index, body_part) {
+ switch (PM_NODE_TYPE(body_part)) {
+ case PM_CASE_VOID_VALUE:
+ if (void_node == NULL) {
+ void_node = body_part;
+ }
+ return void_node;
+ default: break;
+ }
+ }
+ }
+
node = cast->body.nodes[cast->body.size - 1];
break;
}
@@ -1108,7 +1316,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
if (cast->statements == NULL || cast->subsequent == NULL) {
return NULL;
}
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
if (vn == NULL) {
return NULL;
}
@@ -1123,19 +1331,19 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
if (cast->statements == NULL || cast->else_clause == NULL) {
return NULL;
}
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
+ pm_node_t *vn = pm_check_value_expression(parser, UP(cast->statements));
if (vn == NULL) {
return NULL;
}
if (void_node == NULL) {
void_node = vn;
}
- node = (pm_node_t *) cast->else_clause;
+ node = UP(cast->else_clause);
break;
}
case PM_ELSE_NODE: {
pm_else_node_t *cast = (pm_else_node_t *) node;
- node = (pm_node_t *) cast->statements;
+ node = UP(cast->statements);
break;
}
case PM_AND_NODE: {
@@ -1165,7 +1373,7 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
return NULL;
}
-static inline void
+static PRISM_INLINE void
pm_assert_value_expression(pm_parser_t *parser, pm_node_t *node) {
pm_node_t *void_node = pm_check_value_expression(parser, node);
if (void_node != NULL) {
@@ -1193,7 +1401,7 @@ pm_void_statement_check(pm_parser_t *parser, const pm_node_t *node) {
break;
case PM_CALL_NODE: {
const pm_call_node_t *cast = (const pm_call_node_t *) node;
- if (cast->call_operator_loc.start != NULL || cast->message_loc.start == NULL) break;
+ if (cast->call_operator_loc.length > 0 || cast->message_loc.length == 0) break;
const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->name);
switch (message->length) {
@@ -1406,10 +1614,10 @@ pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) {
* Add a warning to the parser if the value that is being written inside of a
* predicate to a conditional is a literal.
*/
-static inline void
+static PRISM_INLINE void
pm_conditional_predicate_warn_write_literal(pm_parser_t *parser, const pm_node_t *node) {
if (pm_conditional_predicate_warn_write_literal_p(node)) {
- pm_parser_warn_node(parser, node, parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
+ pm_parser_warn_node(parser, node, parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
}
}
@@ -1547,26 +1755,6 @@ pm_conditional_predicate(pm_parser_t *parser, pm_node_t *node, pm_conditional_pr
}
/**
- * 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, this happens 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
@@ -1592,22 +1780,29 @@ typedef struct {
/**
* Retrieve the end location of a `pm_arguments_t` object.
*/
-static inline const uint8_t *
+static PRISM_INLINE const pm_location_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;
+ uint32_t end = PM_NODE_END(arguments->block);
+
+ if (arguments->closing_loc.length > 0) {
+ uint32_t arguments_end = PM_LOCATION_END(&arguments->closing_loc);
+ if (arguments_end > end) {
+ return &arguments->closing_loc;
+ }
}
- return end;
+ return &arguments->block->location;
}
- if (arguments->closing_loc.start != NULL) {
- return arguments->closing_loc.end;
+ if (arguments->closing_loc.length > 0) {
+ return &arguments->closing_loc;
}
if (arguments->arguments != NULL) {
- return arguments->arguments->base.location.end;
+ return &arguments->arguments->base.location;
+ }
+ if (arguments->opening_loc.length > 0) {
+ return &arguments->opening_loc;
}
- return arguments->closing_loc.end;
+ return NULL;
}
/**
@@ -1618,7 +1813,7 @@ 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) {
+ if (arguments->arguments == NULL || arguments->closing_loc.length > 0) {
return;
}
@@ -1635,7 +1830,7 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b
// 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);
+ pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
}
/******************************************************************************/
@@ -1648,7 +1843,7 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b
* 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
+static PRISM_INLINE size_t
char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t n) {
if (n <= 0) return 0;
@@ -1675,7 +1870,7 @@ char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t
* Similar to char_is_identifier but this function assumes that the encoding
* has not been changed.
*/
-static inline size_t
+static PRISM_INLINE size_t
char_is_identifier_utf8(const uint8_t *b, ptrdiff_t n) {
if (n <= 0) {
return 0;
@@ -1687,11 +1882,189 @@ char_is_identifier_utf8(const uint8_t *b, ptrdiff_t n) {
}
/**
+ * Scan forward through ASCII identifier characters (a-z, A-Z, 0-9, _) using
+ * wide operations. Returns the number of leading ASCII identifier bytes.
+ * Callers must handle any remaining bytes (short tail or non-ASCII/UTF-8)
+ * with a byte-at-a-time loop.
+ *
+ * Up to three optimized implementations are selected at compile time, with a
+ * no-op fallback for unsupported platforms:
+ * 1. NEON — processes 16 bytes per iteration on aarch64.
+ * 2. SSSE3 — processes 16 bytes per iteration on x86-64.
+ * 3. SWAR — little-endian fallback, processes 8 bytes per iteration.
+ */
+
+#if defined(PRISM_HAS_NEON)
+#include <arm_neon.h>
+
+static PRISM_INLINE size_t
+scan_identifier_ascii(const uint8_t *start, const uint8_t *end) {
+ const uint8_t *cursor = start;
+
+ // Nibble-based lookup tables for classifying [a-zA-Z0-9_].
+ // Each high nibble is assigned a unique bit; the low nibble table
+ // contains the OR of bits for all high nibbles that have an
+ // identifier character at that low nibble position. A byte is an
+ // identifier character iff (low_lut[lo] & high_lut[hi]) != 0.
+ static const uint8_t low_lut_data[16] = {
+ 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
+ };
+ static const uint8_t high_lut_data[16] = {
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const uint8x16_t low_lut = vld1q_u8(low_lut_data);
+ const uint8x16_t high_lut = vld1q_u8(high_lut_data);
+ const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
+
+ while (cursor + 16 <= end) {
+ uint8x16_t v = vld1q_u8(cursor);
+
+ uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
+ uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
+ uint8x16_t ident = vandq_u8(lo_class, hi_class);
+
+ // Fast check: if the per-byte minimum is nonzero, every byte matched.
+ if (vminvq_u8(ident) != 0) {
+ cursor += 16;
+ continue;
+ }
+
+ // Find the first non-identifier byte (zero in ident).
+ uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
+ uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
+
+ if (lo != 0) {
+ cursor += pm_ctzll(lo) / 8;
+ } else {
+ uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
+ cursor += 8 + pm_ctzll(hi) / 8;
+ }
+
+ return (size_t) (cursor - start);
+ }
+
+ return (size_t) (cursor - start);
+}
+
+#elif defined(PRISM_HAS_SSSE3)
+#include <tmmintrin.h>
+
+static PRISM_INLINE size_t
+scan_identifier_ascii(const uint8_t *start, const uint8_t *end) {
+ const uint8_t *cursor = start;
+
+ while (cursor + 16 <= end) {
+ __m128i v = _mm_loadu_si128((const __m128i *) cursor);
+ __m128i zero = _mm_setzero_si128();
+
+ // Unsigned range check via saturating subtraction:
+ // byte >= lo ⟺ saturate(lo - byte) == 0
+ // byte <= hi ⟺ saturate(byte - hi) == 0
+
+ // Fold case: OR with 0x20 maps A-Z to a-z.
+ __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
+ __m128i letter = _mm_and_si128(
+ _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
+ _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
+
+ __m128i digit = _mm_and_si128(
+ _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
+ _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
+
+ __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
+
+ __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
+ int mask = _mm_movemask_epi8(ident);
+
+ if (mask == 0xFFFF) {
+ cursor += 16;
+ continue;
+ }
+
+ cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
+ return (size_t) (cursor - start);
+ }
+
+ return (size_t) (cursor - start);
+}
+
+// The SWAR path uses pm_ctzll to find the first non-matching byte within a
+// word, which only yields the correct byte index on little-endian targets.
+// We gate on a positive little-endian check so that unknown-endianness
+// platforms safely fall through to the no-op fallback.
+#elif defined(PRISM_HAS_SWAR)
+
+/**
+ * Portable SWAR fallback — processes 8 bytes per iteration.
+ *
+ * The byte-wise range checks avoid cross-byte borrows by pre-setting the high
+ * bit of each byte before subtraction: (byte | 0x80) - lo has a minimum value
+ * of 0x80 - 0x7F = 1, so underflow (and thus a borrow into the next byte) is
+ * impossible. The result has bit 7 set if and only if byte >= lo. The same
+ * reasoning applies to the upper-bound direction.
+ */
+static PRISM_INLINE size_t
+scan_identifier_ascii(const uint8_t *start, const uint8_t *end) {
+ static const uint64_t ones = 0x0101010101010101ULL;
+ static const uint64_t highs = 0x8080808080808080ULL;
+ const uint8_t *cursor = start;
+
+ while (cursor + 8 <= end) {
+ uint64_t word;
+ memcpy(&word, cursor, 8);
+
+ // Bail on any non-ASCII byte.
+ if (word & highs) break;
+
+ uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
+
+ // Fold upper- and lowercase together by forcing bit 5 (OR 0x20),
+ // then check the lowercase range once. A-Z maps to a-z; the
+ // only non-letter byte that could alias into [0x61,0x7A] is one
+ // whose original value was in [0x41,0x5A] — which is exactly
+ // the uppercase letters we want to match.
+ uint64_t lowered = word | (ones * 0x20);
+ uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
+
+ // Standard SWAR "has zero byte" idiom on (word XOR 0x5F) to find
+ // bytes equal to underscore. Safe from cross-byte borrows because
+ // the ASCII guard above ensures all bytes are < 0x80.
+ uint64_t xor_us = word ^ (ones * 0x5F);
+ uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
+
+ uint64_t ident = digit | letter | underscore;
+
+ if (ident == highs) {
+ cursor += 8;
+ continue;
+ }
+
+ // Find the first non-identifier byte. On little-endian the first
+ // byte sits in the least-significant position.
+ uint64_t not_ident = ~ident & highs;
+ cursor += pm_ctzll(not_ident) / 8;
+ return (size_t) (cursor - start);
+ }
+
+ return (size_t) (cursor - start);
+}
+
+#else
+
+// No-op fallback for big-endian or other unsupported platforms.
+// The caller's byte-at-a-time loop handles everything.
+#define scan_identifier_ascii(start, end) ((size_t) 0)
+
+#endif
+
+/**
* 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
+static PRISM_INLINE size_t
char_is_identifier(const pm_parser_t *parser, const uint8_t *b, ptrdiff_t n) {
if (n <= 0) {
return 0;
@@ -1729,7 +2102,7 @@ const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = {
#undef BIT
#undef PUNCT
-static inline bool
+static PRISM_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;
@@ -1737,7 +2110,7 @@ char_is_global_name_punctuation(const uint8_t b) {
return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
}
-static inline bool
+static PRISM_INLINE bool
token_is_setter_name(pm_token_t *token) {
return (
(token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
@@ -1825,7 +2198,7 @@ pm_local_is_keyword(const char *source, size_t length) {
/**
* Set the given flag on the given node.
*/
-static inline void
+static PRISM_INLINE void
pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
node->flags |= flag;
}
@@ -1833,7 +2206,7 @@ pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
/**
* Remove the given flag from the given node.
*/
-static inline void
+static PRISM_INLINE void
pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
node->flags &= (pm_node_flags_t) ~flag;
}
@@ -1841,7 +2214,7 @@ pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
/**
* Set the repeated parameter flag on the given node.
*/
-static inline void
+static PRISM_INLINE void
pm_node_flag_set_repeated_parameter(pm_node_t *node) {
assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
@@ -1869,7 +2242,7 @@ pm_node_flag_set_repeated_parameter(pm_node_t *node) {
/**
* Parse out the options for a regular expression.
*/
-static inline pm_node_flags_t
+static PRISM_INLINE pm_node_flags_t
pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
pm_node_flags_t flags = 0;
@@ -1895,9 +2268,9 @@ pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closin
size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
if (unknown_flags_length != 0) {
const char *word = unknown_flags_length >= 2 ? "options" : "option";
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
}
- pm_buffer_free(&unknown_flags);
+ pm_buffer_cleanup(&unknown_flags);
}
return flags;
@@ -1915,36 +2288,45 @@ 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.
+ * Move an integer's values array into the arena. If the integer has heap-
+ * allocated values, copy them to the arena and free the original.
*/
-static inline void *
-pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
- void *memory = xcalloc(1, size);
- if (memory == NULL) {
- fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
- abort();
+static PRISM_INLINE void
+pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
+ if (integer->values != NULL) {
+ size_t byte_size = integer->length * sizeof(uint32_t);
+ uint32_t *old_values = integer->values;
+ integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
+ xfree(old_values);
}
- return memory;
}
-#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
-#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
-
/**
- * Allocate a new MissingNode node.
+ * Allocate a new ErrorRecoveryNode node with no unexpected child.
*/
-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_NODE_ALLOC(parser, pm_missing_node_t);
-
- *node = (pm_missing_node_t) {{
- .type = PM_MISSING_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = start, .end = end }
- }};
+static pm_error_recovery_node_t *
+pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ return pm_error_recovery_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = length }),
+ NULL
+ );
+}
- return node;
+/**
+ * Allocate a new ErrorRecoveryNode node wrapping an unexpected child node.
+ */
+static pm_error_recovery_node_t *
+pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
+ return pm_error_recovery_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ unexpected->location,
+ unexpected
+ );
}
/**
@@ -1953,23 +2335,16 @@ pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t
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_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
-
- *node = (pm_alias_global_variable_node_t) {
- {
- .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_alias_global_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
+ new_name,
+ old_name,
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -1978,23 +2353,16 @@ pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyw
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_NODE_ALLOC(parser, pm_alias_method_node_t);
- *node = (pm_alias_method_node_t) {
- {
- .type = PM_ALIAS_METHOD_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_alias_method_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
+ new_name,
+ old_name,
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -2002,23 +2370,15 @@ pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_n
*/
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_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
-
- *node = (pm_alternation_pattern_node_t) {
- {
- .type = PM_ALTERNATION_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end
- },
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ return pm_alternation_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2028,23 +2388,15 @@ 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_NODE_ALLOC(parser, pm_and_node_t);
-
- *node = (pm_and_node_t) {
- {
- .type = PM_AND_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end
- },
- },
- .left = left,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .right = right
- };
-
- return node;
+ return pm_and_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2052,18 +2404,13 @@ pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *opera
*/
static pm_arguments_node_t *
pm_arguments_node_create(pm_parser_t *parser) {
- pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
-
- *node = (pm_arguments_node_t) {
- {
- .type = PM_ARGUMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .arguments = { 0 }
- };
-
- return node;
+ return pm_arguments_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
@@ -2078,19 +2425,22 @@ pm_arguments_node_size(pm_arguments_node_t *node) {
* Append an argument to an arguments node.
*/
static void
-pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
+pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
if (pm_arguments_node_size(node) == 0) {
- node->base.location.start = argument->location.start;
+ PM_NODE_START_SET_NODE(node, argument);
}
- node->base.location.end = argument->location.end;
- pm_node_list_append(&node->arguments, argument);
+ if (PM_NODE_END(node) < PM_NODE_END(argument)) {
+ PM_NODE_LENGTH_SET_NODE(node, argument);
+ }
+
+ pm_node_list_append(arena, &node->arguments, argument);
if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
- pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
+ pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
} else {
- pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
+ pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
}
}
}
@@ -2100,43 +2450,49 @@ pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argumen
*/
static pm_array_node_t *
pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
-
- *node = (pm_array_node_t) {
- {
- .type = PM_ARRAY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ if (opening == NULL) {
+ return pm_array_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
+ } else {
+ return pm_array_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, opening)
+ );
+ }
}
/**
* 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;
+static PRISM_INLINE void
+pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
+ if (!node->elements.size && !node->opening_loc.length) {
+ PM_NODE_START_SET_NODE(node, element);
}
- pm_node_list_append(&node->elements, element);
- node->base.location.end = element->location.end;
+ pm_node_list_append(arena, &node->elements, element);
+ PM_NODE_LENGTH_SET_NODE(node, element);
// 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);
+ pm_node_flag_unset(UP(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);
+ pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
}
}
@@ -2144,10 +2500,10 @@ pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
* 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);
+pm_array_node_close_set(const pm_parser_t *parser, 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 == 0);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
+ node->closing_loc = TOK2LOC(parser, closing);
}
/**
@@ -2156,24 +2512,18 @@ pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
*/
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_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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
- };
+ pm_array_pattern_node_t *node = pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
// 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.
@@ -2185,9 +2535,9 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *node
node->rest = child;
found_rest = true;
} else if (found_rest) {
- pm_node_list_append(&node->posts, child);
+ pm_node_list_append(parser->arena, &node->posts, child);
} else {
- pm_node_list_append(&node->requireds, child);
+ pm_node_list_append(parser->arena, &node->requireds, child);
}
}
@@ -2199,23 +2549,18 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *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_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(rest),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ rest,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -2224,26 +2569,18 @@ pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
*/
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_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
+ constant,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -2252,31 +2589,23 @@ pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant,
*/
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_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_array_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
-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);
+static PRISM_INLINE void
+pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
+ pm_node_list_append(arena, &node->requireds, inner);
}
/**
@@ -2284,15 +2613,14 @@ pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t
*/
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_NODE_ALLOC(parser, pm_assoc_node_t);
- const uint8_t *end;
+ uint32_t end;
- if (value != NULL && value->location.end > key->location.end) {
- end = value->location.end;
- } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
- end = operator->end;
+ if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
+ end = PM_NODE_END(value);
+ } else if (operator != NULL) {
+ end = PM_TOKEN_END(parser, operator);
} else {
- end = key->location.end;
+ end = PM_NODE_END(key);
}
// Hash string keys will be frozen, so we can mark them as frozen here so
@@ -2312,22 +2640,15 @@ pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *oper
flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
}
- *node = (pm_assoc_node_t) {
- {
- .type = PM_ASSOC_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = key->location.start,
- .end = end
- },
- },
- .key = key,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
+ return pm_assoc_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
+ key,
+ value,
+ NTOK2LOC(parser, operator)
+ );
}
/**
@@ -2336,22 +2657,15 @@ pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *oper
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_NODE_ALLOC(parser, pm_assoc_splat_node_t);
-
- *node = (pm_assoc_splat_node_t) {
- {
- .type = PM_ASSOC_SPLAT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = value == NULL ? operator->end : value->location.end
- },
- },
- .value = value,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
- return node;
+ return pm_assoc_splat_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2360,18 +2674,14 @@ pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token
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_NODE_ALLOC(parser, pm_back_reference_read_node_t);
- *node = (pm_back_reference_read_node_t) {
- {
- .type = PM_BACK_REFERENCE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
+ return pm_back_reference_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -2379,23 +2689,21 @@ pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name)
*/
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_NODE_ALLOC(parser, pm_begin_node_t);
-
- *node = (pm_begin_node_t) {
- {
- .type = PM_BEGIN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
+ uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
+
+ return pm_begin_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, begin_keyword),
+ statements,
+ NULL,
+ NULL,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -2403,11 +2711,10 @@ pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_st
*/
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;
+ if (node->begin_keyword_loc.length == 0) {
+ PM_NODE_START_SET_NODE(node, rescue_clause);
}
- node->base.location.end = rescue_clause->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
node->rescue_clause = rescue_clause;
}
@@ -2416,7 +2723,10 @@ pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_
*/
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;
+ if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
+ PM_NODE_START_SET_NODE(node, else_clause);
+ }
+ PM_NODE_LENGTH_SET_NODE(node, else_clause);
node->else_clause = else_clause;
}
@@ -2425,7 +2735,10 @@ pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause
*/
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;
+ if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
+ PM_NODE_START_SET_NODE(node, ensure_clause);
+ }
+ PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
node->ensure_clause = ensure_clause;
}
@@ -2433,11 +2746,10 @@ pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_
* 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);
+pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
+ assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
+ node->end_keyword_loc = TOK2LOC(parser, end_keyword);
}
/**
@@ -2445,22 +2757,16 @@ pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keywo
*/
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_NODE_ALLOC(parser, pm_block_argument_node_t);
-
- *node = (pm_block_argument_node_t) {
- {
- .type = PM_BLOCK_ARGUMENT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = expression == NULL ? operator->end : expression->location.end
- },
- },
- .expression = expression,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ assert(operator->type == PM_TOKEN_UAMPERSAND);
+
+ return pm_block_argument_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
+ expression,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2468,22 +2774,17 @@ pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, p
*/
static pm_block_node_t *
pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
- pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
-
- *node = (pm_block_node_t) {
- {
- .type = PM_BLOCK_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = opening->start, .end = closing->end },
- },
- .locals = *locals,
- .parameters = parameters,
- .body = body,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
+ return pm_block_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ *locals,
+ parameters,
+ body,
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -2491,24 +2792,17 @@ pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const p
*/
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_NODE_ALLOC(parser, pm_block_parameter_node_t);
-
- *node = (pm_block_parameter_node_t) {
- {
- .type = PM_BLOCK_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
+
+ return pm_block_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
+ name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
+ NTOK2LOC(parser, name),
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -2516,53 +2810,44 @@ pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, cons
*/
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_NODE_ALLOC(parser, pm_block_parameters_node_t);
-
- const uint8_t *start;
- if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- start = opening->start;
+ uint32_t start;
+ if (opening != NULL) {
+ start = PM_TOKEN_START(parser, opening);
} else if (parameters != NULL) {
- start = parameters->base.location.start;
+ start = PM_NODE_START(parameters);
} else {
- start = NULL;
+ start = 0;
}
- const uint8_t *end;
+ uint32_t end;
if (parameters != NULL) {
- end = parameters->base.location.end;
- } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- end = opening->end;
+ end = PM_NODE_END(parameters);
+ } else if (opening != NULL) {
+ end = PM_TOKEN_END(parser, opening);
} else {
- end = NULL;
- }
-
- *node = (pm_block_parameters_node_t) {
- {
- .type = PM_BLOCK_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ end = 0;
+ }
+
+ return pm_block_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ parameters,
+ ((pm_node_list_t) { 0 }),
+ NTOK2LOC(parser, opening),
+ ((pm_location_t) { 0 })
+ );
}
/**
* 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);
+pm_block_parameters_node_closing_set(const pm_parser_t *parser, 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 == 0);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
+ node->closing_loc = TOK2LOC(parser, closing);
}
/**
@@ -2570,29 +2855,27 @@ pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_
*/
static pm_block_local_variable_node_t *
pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
-
- *node = (pm_block_local_variable_node_t) {
- {
- .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
+ return pm_block_local_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
* 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);
+pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
+ pm_node_list_append(arena, &node->locals, UP(local));
+
+ if (PM_NODE_LENGTH(node) == 0) {
+ PM_NODE_START_SET_NODE(node, local);
+ }
- if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
- node->base.location.end = local->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, local);
}
/**
@@ -2601,66 +2884,55 @@ pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm
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_NODE_ALLOC(parser, pm_break_node_t);
- *node = (pm_break_node_t) {
- {
- .type = PM_BREAK_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- },
- },
- .arguments = arguments,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
+ return pm_break_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
+ arguments,
+ TOK2LOC(parser, keyword)
+ );
}
// There are certain flags that we want to use internally but don't want to
// expose because they are not relevant beyond parsing. Therefore we'll define
// them here and not define them in config.yml/a header file.
-static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
-static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
-static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
-static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
+static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
+
+static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
+static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
+static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
/**
- * 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.
+ * Allocate and initialize a new CallNode node. This sets everything to NULL
+ * 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_node_flags_t flags) {
- pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
-
- *node = (pm_call_node_t) {
- {
- .type = PM_CALL_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_call_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_UNSET,
+ NULL,
+ ((pm_location_t) { 0 }),
+ 0,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL
+ );
}
/**
* Returns the value that the ignore visibility flag should be set to for the
* given receiver.
*/
-static inline pm_node_flags_t
+static PRISM_INLINE pm_node_flags_t
pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
}
@@ -2680,12 +2952,15 @@ pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_
pm_call_node_t *node = pm_call_node_create(parser, flags);
- node->base.location.start = receiver->location.start;
- node->base.location.end = pm_arguments_end(arguments);
+ PM_NODE_START_SET_NODE(node, receiver);
+
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+ PM_NODE_LENGTH_SET_LOCATION(node, end);
node->receiver = receiver;
node->message_loc.start = arguments->opening_loc.start;
- node->message_loc.end = arguments->closing_loc.end;
+ node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
node->opening_loc = arguments->opening_loc;
node->arguments = arguments->arguments;
@@ -2706,20 +2981,22 @@ pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t
pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
- node->base.location.start = MIN(receiver->location.start, argument->location.start);
- node->base.location.end = MAX(receiver->location.end, argument->location.end);
+ PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
+ PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
+ node->message_loc = TOK2LOC(parser, operator);
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(arguments, argument);
+ pm_arguments_node_arguments_append(parser->arena, arguments, argument);
node->arguments = arguments;
node->name = pm_parser_constant_id_token(parser, operator);
return node;
}
+static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
+
/**
* Allocate and initialize a new CallNode node from a call expression.
*/
@@ -2729,26 +3006,31 @@ pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *o
pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
- node->base.location.start = receiver->location.start;
- const uint8_t *end = pm_arguments_end(arguments);
+ PM_NODE_START_SET_NODE(node, receiver);
+ const pm_location_t *end = pm_arguments_end(arguments);
if (end == NULL) {
- end = message->end;
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
+ } else {
+ PM_NODE_LENGTH_SET_LOCATION(node, 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->call_operator_loc = TOK2LOC(parser, operator);
+ node->message_loc = TOK2LOC(parser, 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);
+ pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
}
- node->name = pm_parser_constant_id_token(parser, message);
+ /**
+ * If the final character is `@` as is the case for `foo.~@`,
+ * we should ignore the @ in the same way we do for symbols.
+ */
+ node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
return node;
}
@@ -2758,12 +3040,9 @@ pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *o
static pm_call_node_t *
pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
pm_call_node_t *node = pm_call_node_create(parser, 0);
- node->base.location.start = parser->start;
- node->base.location.end = parser->end;
+ node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
node->receiver = receiver;
- node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
- node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
node->arguments = arguments;
node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
@@ -2778,10 +3057,12 @@ 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, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
- node->base.location.start = message->start;
- node->base.location.end = pm_arguments_end(arguments);
+ PM_NODE_START_SET_TOKEN(parser, node, message);
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+ PM_NODE_LENGTH_SET_LOCATION(node, end);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
+ node->message_loc = TOK2LOC(parser, message);
node->opening_loc = arguments->opening_loc;
node->arguments = arguments->arguments;
node->closing_loc = arguments->closing_loc;
@@ -2799,7 +3080,7 @@ static pm_call_node_t *
pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
- node->base.location = PM_LOCATION_NULL_VALUE(parser);
+ node->base.location = (pm_location_t) { 0 };
node->arguments = arguments;
node->name = name;
@@ -2816,16 +3097,16 @@ pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *me
pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
- node->base.location.start = message->start;
- if (arguments->closing_loc.start != NULL) {
- node->base.location.end = arguments->closing_loc.end;
+ PM_NODE_START_SET_TOKEN(parser, node, message);
+ if (arguments->closing_loc.length > 0) {
+ PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
} else {
assert(receiver != NULL);
- node->base.location.end = receiver->location.end;
+ PM_NODE_LENGTH_SET_NODE(node, receiver);
}
node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
+ node->message_loc = TOK2LOC(parser, message);
node->opening_loc = arguments->opening_loc;
node->arguments = arguments->arguments;
node->closing_loc = arguments->closing_loc;
@@ -2843,18 +3124,20 @@ pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token
pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
- node->base.location.start = receiver->location.start;
- node->base.location.end = pm_arguments_end(arguments);
+ PM_NODE_START_SET_NODE(node, receiver);
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+ PM_NODE_LENGTH_SET_LOCATION(node, end);
node->receiver = receiver;
- node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
+ node->call_operator_loc = TOK2LOC(parser, 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);
+ pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
}
node->name = pm_parser_constant_id_constant(parser, "call", 4);
@@ -2870,11 +3153,11 @@ pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *
pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
- node->base.location.start = operator->start;
- node->base.location.end = receiver->location.end;
+ PM_NODE_START_SET_TOKEN(parser, node, operator);
+ PM_NODE_LENGTH_SET_NODE(node, receiver);
node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
+ node->message_loc = TOK2LOC(parser, operator);
node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
return node;
@@ -2888,8 +3171,8 @@ 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, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
- node->base.location = PM_LOCATION_TOKEN_VALUE(message);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
+ node->base.location = TOK2LOC(parser, message);
+ node->message_loc = TOK2LOC(parser, message);
node->name = pm_parser_constant_id_token(parser, message);
return node;
@@ -2899,14 +3182,14 @@ pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
* Returns whether or not this call can be used on the left-hand side of an
* operator assignment.
*/
-static inline bool
+static PRISM_INLINE bool
pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
return (
- (node->message_loc.start != NULL) &&
- (node->message_loc.end[-1] != '!') &&
- (node->message_loc.end[-1] != '?') &&
- char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
- (node->opening_loc.start == NULL) &&
+ (node->message_loc.length > 0) &&
+ (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
+ (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
+ char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
+ (node->opening_loc.length == 0) &&
(node->arguments == NULL) &&
(node->block == NULL)
);
@@ -2922,10 +3205,10 @@ pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, p
if (write_constant->length > 0) {
size_t length = write_constant->length - 1;
- void *memory = xmalloc(length);
+ uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
memcpy(memory, write_constant->start, length);
- *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
+ *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, 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);
@@ -2939,33 +3222,25 @@ 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_NODE_ALLOC(parser, pm_call_and_write_node_t);
- *node = (pm_call_and_write_node_t) {
- {
- .type = PM_CALL_AND_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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_and_write_node_t *node = pm_call_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->message_loc,
+ 0,
+ target->name,
+ TOK2LOC(parser, operator),
+ 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.
- xfree(target);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -2976,7 +3251,7 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
*/
static void
pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
- if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
pm_node_t *node;
PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
@@ -2999,35 +3274,28 @@ pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *argumen
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_NODE_ALLOC(parser, pm_index_and_write_node_t);
pm_index_arguments_check(parser, target->arguments, target->block);
assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_and_write_node_t) {
- {
- .type = PM_INDEX_AND_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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 = (pm_block_argument_node_t *) 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.
- xfree(target);
+ pm_index_and_write_node_t *node = pm_index_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block,
+ TOK2LOC(parser, operator),
+ value
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3038,34 +3306,26 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons
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_NODE_ALLOC(parser, pm_call_operator_write_node_t);
- *node = (pm_call_operator_write_node_t) {
- {
- .type = PM_CALL_OPERATOR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
+ pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->message_loc,
+ 0,
+ target->name,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
+ TOK2LOC(parser, operator),
+ 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.
- xfree(target);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3075,36 +3335,28 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
*/
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_NODE_ALLOC(parser, pm_index_operator_write_node_t);
-
pm_index_arguments_check(parser, target->arguments, target->block);
assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_operator_write_node_t) {
- {
- .type = PM_INDEX_OPERATOR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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 = (pm_block_argument_node_t *) target->block,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .binary_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.
- xfree(target);
+ pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
+ TOK2LOC(parser, operator),
+ value
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3116,33 +3368,25 @@ 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_NODE_ALLOC(parser, pm_call_or_write_node_t);
- *node = (pm_call_or_write_node_t) {
- {
- .type = PM_CALL_OR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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_or_write_node_t *node = pm_call_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->message_loc,
+ 0,
+ target->name,
+ TOK2LOC(parser, operator),
+ 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.
- xfree(target);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3153,35 +3397,28 @@ pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
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_NODE_ALLOC(parser, pm_index_or_write_node_t);
pm_index_arguments_check(parser, target->arguments, target->block);
assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_or_write_node_t) {
- {
- .type = PM_INDEX_OR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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 = (pm_block_argument_node_t *) 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.
- xfree(target);
+ pm_index_or_write_node_t *node = pm_index_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->receiver,
+ target->call_operator_loc,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block,
+ TOK2LOC(parser, operator),
+ value
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3192,25 +3429,27 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
*/
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_NODE_ALLOC(parser, pm_call_target_node_t);
+ pm_call_target_node_t *node = pm_call_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target),
+ PM_LOCATION_INIT_NODE(target),
+ target->receiver,
+ target->call_operator_loc,
+ target->name,
+ target->message_loc
+ );
- *node = (pm_call_target_node_t) {
- {
- .type = PM_CALL_TARGET_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = target->base.location
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .name = target->name,
- .message_loc = target->message_loc
- };
+ /* It is possible to get here where we have parsed an invalid syntax tree
+ * where the call operator was not present. In that case we will have a
+ * problem because it is a required location. In this case we need to fill
+ * it in with a fake location so that the syntax tree remains valid. */
+ if (node->call_operator_loc.length == 0) {
+ node->call_operator_loc = target->base.location;
+ }
- // 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.
- xfree(target);
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3221,30 +3460,23 @@ pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
*/
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_NODE_ALLOC(parser, pm_index_target_node_t);
- pm_node_flags_t flags = target->base.flags;
-
pm_index_arguments_check(parser, target->arguments, target->block);
-
assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_target_node_t) {
- {
- .type = PM_INDEX_TARGET_NODE,
- .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = target->base.location
- },
- .receiver = target->receiver,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = (pm_block_argument_node_t *) 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.
- xfree(target);
+ pm_index_target_node_t *node = pm_index_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
+ PM_LOCATION_INIT_NODE(target),
+ target->receiver,
+ target->opening_loc,
+ target->arguments,
+ target->closing_loc,
+ (pm_block_argument_node_t *) target->block
+ );
+
+ // The target is no longer necessary because we've reused its children.
+ // It is arena-allocated so no explicit free is needed.
return node;
}
@@ -3254,23 +3486,15 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
*/
static pm_capture_pattern_node_t *
pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
- pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
-
- *node = (pm_capture_pattern_node_t) {
- {
- .type = PM_CAPTURE_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = value->location.start,
- .end = target->base.location.end
- },
- },
- .value = value,
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ return pm_capture_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(value, target),
+ value,
+ target,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -3278,36 +3502,28 @@ pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_v
*/
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_NODE_ALLOC(parser, pm_case_node_t);
-
- *node = (pm_case_node_t) {
- {
- .type = PM_CASE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = case_keyword->start,
- .end = end_keyword->end
- },
- },
- .predicate = predicate,
- .else_clause = NULL,
- .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .conditions = { 0 }
- };
-
- return node;
+ return pm_case_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
+ predicate,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ TOK2LOC(parser, case_keyword),
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
* Append a new condition to a CaseNode node.
*/
static void
-pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
+pm_case_node_condition_append(pm_arena_t *arena, 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;
+ pm_node_list_append(arena, &node->conditions, condition);
+ PM_NODE_LENGTH_SET_NODE(node, condition);
}
/**
@@ -3316,53 +3532,45 @@ pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
static void
pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
node->else_clause = else_clause;
- node->base.location.end = else_clause->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, else_clause);
}
/**
* 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);
+pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
+ node->end_keyword_loc = TOK2LOC(parser, 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_NODE_ALLOC(parser, pm_case_match_node_t);
-
- *node = (pm_case_match_node_t) {
- {
- .type = PM_CASE_MATCH_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = case_keyword->start,
- .end = end_keyword->end
- },
- },
- .predicate = predicate,
- .else_clause = NULL,
- .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .conditions = { 0 }
- };
-
- return node;
+pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
+ return pm_case_match_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, case_keyword),
+ predicate,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ TOK2LOC(parser, case_keyword),
+ ((pm_location_t) { 0 })
+ );
}
/**
* 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) {
+pm_case_match_node_condition_append(pm_arena_t *arena, 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;
+ pm_node_list_append(arena, &node->conditions, condition);
+ PM_NODE_LENGTH_SET_NODE(node, condition);
}
/**
@@ -3371,16 +3579,16 @@ pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condi
static void
pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
node->else_clause = else_clause;
- node->base.location.end = else_clause->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, else_clause);
}
/**
* 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);
+pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
+ node->end_keyword_loc = TOK2LOC(parser, end_keyword);
}
/**
@@ -3388,25 +3596,20 @@ pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_toke
*/
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_NODE_ALLOC(parser, pm_class_node_t);
-
- *node = (pm_class_node_t) {
- {
- .type = PM_CLASS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_class_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
+ *locals,
+ TOK2LOC(parser, class_keyword),
+ constant_path,
+ NTOK2LOC(parser, inheritance_operator),
+ superclass,
+ body,
+ TOK2LOC(parser, end_keyword),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -3415,24 +3618,17 @@ pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const p
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_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
- *node = (pm_class_variable_and_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_class_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3440,25 +3636,17 @@ pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_r
*/
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_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
-
- *node = (pm_class_variable_operator_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
+ return pm_class_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -3467,24 +3655,17 @@ pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_varia
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_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
-
- *node = (pm_class_variable_or_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_class_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3493,18 +3674,14 @@ pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_re
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_NODE_ALLOC(parser, pm_class_variable_read_node_t);
-
- *node = (pm_class_variable_read_node_t) {
- {
- .type = PM_CLASS_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
- return node;
+ return pm_class_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_parser_constant_id_token(parser, token)
+ );
}
/**
@@ -3513,9 +3690,9 @@ pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token)
* a = *b
* a = 1, 2, 3
*/
-static inline pm_node_flags_t
+static PRISM_INLINE pm_node_flags_t
pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
- if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
+ if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
return flags;
}
return 0;
@@ -3526,25 +3703,16 @@ pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
*/
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_NODE_ALLOC(parser, pm_class_variable_write_node_t);
-
- *node = (pm_class_variable_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .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_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
+ return pm_class_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(read_node, value),
+ read_node->name,
+ read_node->base.location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -3553,23 +3721,16 @@ pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_
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_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
-
- *node = (pm_constant_path_and_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
- return node;
+ return pm_constant_path_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3577,24 +3738,16 @@ pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_nod
*/
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_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
-
- *node = (pm_constant_path_operator_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
+ return pm_constant_path_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -3603,23 +3756,16 @@ pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_pat
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_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
- *node = (pm_constant_path_or_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
+ return pm_constant_path_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3628,29 +3774,22 @@ pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_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, const pm_token_t *name_token) {
pm_assert_value_expression(parser, parent);
- pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
if (name_token->type == PM_TOKEN_CONSTANT) {
name = pm_parser_constant_id_token(parser, name_token);
}
- *node = (pm_constant_path_node_t) {
- {
- .type = PM_CONSTANT_PATH_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = parent == NULL ? delimiter->start : parent->location.start,
- .end = name_token->end
- },
- },
- .parent = parent,
- .name = name,
- .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
- };
-
- return node;
+ return pm_constant_path_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
+ parent,
+ name,
+ TOK2LOC(parser, delimiter),
+ TOK2LOC(parser, name_token)
+ );
}
/**
@@ -3658,24 +3797,15 @@ pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_to
*/
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_NODE_ALLOC(parser, pm_constant_path_write_node_t);
-
- *node = (pm_constant_path_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- },
- },
- .target = target,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
+ return pm_constant_path_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ target,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3684,24 +3814,17 @@ pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t
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_NODE_ALLOC(parser, pm_constant_and_write_node_t);
- *node = (pm_constant_and_write_node_t) {
- {
- .type = PM_CONSTANT_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_constant_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3709,25 +3832,17 @@ pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *
*/
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_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
-
- *node = (pm_constant_operator_write_node_t) {
- {
- .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
+ return pm_constant_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -3736,24 +3851,17 @@ pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_nod
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_NODE_ALLOC(parser, pm_constant_or_write_node_t);
-
- *node = (pm_constant_or_write_node_t) {
- {
- .type = PM_CONSTANT_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_constant_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -3761,19 +3869,15 @@ pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *t
*/
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_NODE_ALLOC(parser, pm_constant_read_node_t);
-
- *node = (pm_constant_read_node_t) {
- {
- .type = PM_CONSTANT_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
+ assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
+
+ return pm_constant_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -3781,25 +3885,16 @@ pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
*/
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_NODE_ALLOC(parser, pm_constant_write_node_t);
-
- *node = (pm_constant_write_node_t) {
- {
- .type = PM_CONSTANT_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_constant_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -3810,7 +3905,7 @@ pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_BEGIN_NODE: {
const pm_begin_node_t *cast = (pm_begin_node_t *) node;
- if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
+ if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
break;
}
case PM_PARENTHESES_NODE: {
@@ -3865,65 +3960,45 @@ pm_def_node_create(
const pm_token_t *equal,
const pm_token_t *end_keyword
) {
- pm_def_node_t *node = PM_NODE_ALLOC(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;
- }
-
if (receiver != NULL) {
pm_def_node_receiver_check(parser, receiver);
}
- *node = (pm_def_node_t) {
- {
- .type = PM_DEF_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = def_keyword->start, .end = end },
- },
- .name = name,
- .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
- .receiver = receiver,
- .parameters = parameters,
- .body = body,
- .locals = *locals,
- .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
- .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
- .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
+ return pm_def_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
+ name,
+ TOK2LOC(parser, name_loc),
+ receiver,
+ parameters,
+ body,
+ *locals,
+ TOK2LOC(parser, def_keyword),
+ NTOK2LOC(parser, operator),
+ NTOK2LOC(parser, lparen),
+ NTOK2LOC(parser, rparen),
+ NTOK2LOC(parser, equal),
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
* 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_NODE_ALLOC(parser, pm_defined_node_t);
-
- *node = (pm_defined_node_t) {
- {
- .type = PM_DEFINED_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_token_t *keyword) {
+ return pm_defined_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
+ NTOK2LOC(parser, lparen),
+ value,
+ NTOK2LOC(parser, rparen),
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -3931,29 +4006,15 @@ pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t
*/
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_NODE_ALLOC(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,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_else_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
+ TOK2LOC(parser, else_keyword),
+ statements,
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -3961,23 +4022,15 @@ pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_stat
*/
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_NODE_ALLOC(parser, pm_embedded_statements_node_t);
-
- *node = (pm_embedded_statements_node_t) {
- {
- .type = PM_EMBEDDED_STATEMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_embedded_statements_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ statements,
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -3985,22 +4038,14 @@ pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *openin
*/
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_NODE_ALLOC(parser, pm_embedded_variable_node_t);
-
- *node = (pm_embedded_variable_node_t) {
- {
- .type = PM_EMBEDDED_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = variable->location.end
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .variable = variable
- };
-
- return node;
+ return pm_embedded_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
+ TOK2LOC(parser, operator),
+ variable
+ );
}
/**
@@ -4008,23 +4053,15 @@ pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator
*/
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_NODE_ALLOC(parser, pm_ensure_node_t);
-
- *node = (pm_ensure_node_t) {
- {
- .type = PM_ENSURE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_ensure_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
+ TOK2LOC(parser, ensure_keyword),
+ statements,
+ TOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -4033,16 +4070,13 @@ pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_
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_NODE_ALLOC(parser, pm_false_node_t);
- *node = (pm_false_node_t) {{
- .type = PM_FALSE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
+ return pm_false_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4051,50 +4085,31 @@ pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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_NODE_ALLOC(parser, pm_find_pattern_node_t);
-
+ assert(nodes->size >= 2);
pm_node_t *left = nodes->nodes[0];
- assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
- pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
-
- pm_node_t *right;
+ pm_node_t *right = nodes->nodes[nodes->size - 1];
- 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];
- assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
- }
-
-#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
- // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
- // The resulting AST will anyway be ignored, but this file still needs to compile.
- pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
-#else
- pm_node_t *right_splat_node = right;
-#endif
- *node = (pm_find_pattern_node_t) {
- {
- .type = PM_FIND_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end,
- },
- },
- .constant = NULL,
- .left = left_splat_node,
- .right = right_splat_node,
- .requireds = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
+ assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
+ assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
+
+ pm_find_pattern_node_t *node = pm_find_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ NULL,
+ (pm_splat_node_t *) left,
+ ((pm_node_list_t) { 0 }),
+ (pm_splat_node_t *) right,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
// 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]);
+ pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
}
return node;
@@ -4111,7 +4126,8 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
// First, get a buffer of the content.
size_t length = (size_t) diff;
- char *buffer = xmalloc(sizeof(char) * (length + 1));
+ const size_t buffer_size = sizeof(char) * (length + 1);
+ char *buffer = xmalloc(buffer_size);
memcpy((void *) buffer, token->start, length);
// Next, determine if we need to replace the decimal point because of
@@ -4145,8 +4161,8 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
// This should never happen, because we've already checked that the token
// is in a valid format. However it's good to be safe.
if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
- xfree((void *) buffer);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
+ xfree_sized(buffer, buffer_size);
return 0.0;
}
@@ -4164,12 +4180,12 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
ellipsis = "";
}
- pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
+ pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->warning_list, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
}
// Finally we can free the buffer and return the value.
- xfree((void *) buffer);
+ xfree_sized(buffer, buffer_size);
return value;
}
@@ -4179,19 +4195,14 @@ pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
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_NODE_ALLOC(parser, pm_float_node_t);
- *node = (pm_float_node_t) {
- {
- .type = PM_FLOAT_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .value = pm_double_parse(parser, token)
- };
-
- return node;
+ return pm_float_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_double_parse(parser, token)
+ );
}
/**
@@ -4201,22 +4212,17 @@ 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_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_float_node_create(parser, &((pm_token_t) {
.type = PM_TOKEN_FLOAT,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4226,17 +4232,14 @@ 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_NODE_ALLOC(parser, pm_rational_node_t);
- *node = (pm_rational_node_t) {
- {
- .type = PM_RATIONAL_NODE,
- .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numerator = { 0 },
- .denominator = { 0 }
- };
+ pm_rational_node_t *node = pm_rational_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_integer_t) { 0 }),
+ ((pm_integer_t) { 0 })
+ );
const uint8_t *start = token->start;
const uint8_t *end = token->end - 1; // r
@@ -4253,7 +4256,7 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
const uint8_t *point = memchr(start, '.', length);
assert(point && "should have a decimal point");
- uint8_t *digits = malloc(length);
+ uint8_t *digits = xmalloc(length);
if (digits == NULL) {
fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
abort();
@@ -4263,12 +4266,18 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
+ size_t fract_length = 0;
+ for (const uint8_t *fract = point; fract < end; ++fract) {
+ if (*fract != '_') ++fract_length;
+ }
digits[0] = '1';
- if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
- pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
- free(digits);
+ if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
+ pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
+ xfree_sized(digits, length);
pm_integers_reduce(&node->numerator, &node->denominator);
+ pm_integer_arena_move(parser->arena, &node->numerator);
+ pm_integer_arena_move(parser->arena, &node->denominator);
return node;
}
@@ -4280,22 +4289,17 @@ 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_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_float_node_rational_create(parser, &((pm_token_t) {
.type = PM_TOKEN_FLOAT_RATIONAL,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4312,27 +4316,19 @@ pm_for_node_create(
const pm_token_t *do_keyword,
const pm_token_t *end_keyword
) {
- pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
-
- *node = (pm_for_node_t) {
- {
- .type = PM_FOR_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_for_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
+ index,
+ collection,
+ statements,
+ TOK2LOC(parser, for_keyword),
+ TOK2LOC(parser, in_keyword),
+ NTOK2LOC(parser, do_keyword),
+ TOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -4341,15 +4337,13 @@ pm_for_node_create(
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_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
-
- *node = (pm_forwarding_arguments_node_t) {{
- .type = PM_FORWARDING_ARGUMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
- return node;
+ return pm_forwarding_arguments_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4358,15 +4352,13 @@ pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token
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_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
-
- *node = (pm_forwarding_parameter_node_t) {{
- .type = PM_FORWARDING_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
- return node;
+ return pm_forwarding_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4376,26 +4368,20 @@ 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_NODE_ALLOC(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,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = token->start,
- .end = block != NULL ? block->base.location.end : token->end
- },
- },
- .block = block
- };
-
- return node;
+ return pm_forwarding_super_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ block
+ );
}
/**
@@ -4404,25 +4390,17 @@ pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm
*/
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_NODE_ALLOC(parser, pm_hash_pattern_node_t);
-
- *node = (pm_hash_pattern_node_t) {
- {
- .type = PM_HASH_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_hash_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -4430,46 +4408,36 @@ pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening
*/
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_NODE_ALLOC(parser, pm_hash_pattern_node_t);
-
- const uint8_t *start;
- const uint8_t *end;
+ uint32_t start;
+ uint32_t end;
if (elements->size > 0) {
if (rest) {
- start = elements->nodes[0]->location.start;
- end = rest->location.end;
+ start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
+ end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
} else {
- start = elements->nodes[0]->location.start;
- end = elements->nodes[elements->size - 1]->location.end;
+ start = PM_NODE_START(elements->nodes[0]);
+ end = PM_NODE_END(elements->nodes[elements->size - 1]);
}
} else {
assert(rest != NULL);
- start = rest->location.start;
- end = rest->location.end;
- }
-
- *node = (pm_hash_pattern_node_t) {
- {
- .type = PM_HASH_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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
- };
-
- pm_node_t *element;
- PM_NODE_LIST_FOREACH(elements, index, element) {
- pm_node_list_append(&node->elements, element);
- }
+ start = PM_NODE_START(rest);
+ end = PM_NODE_END(rest);
+ }
+
+ pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ rest,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
+ pm_node_list_concat(parser->arena, &node->elements, elements);
return node;
}
@@ -4486,7 +4454,7 @@ pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
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);
+ return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
default:
assert(false && "unreachable");
return (pm_constant_id_t) -1;
@@ -4499,24 +4467,17 @@ pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
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_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
-
- *node = (pm_global_variable_and_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_global_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -4524,25 +4485,17 @@ pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target,
*/
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_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
-
- *node = (pm_global_variable_operator_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
+ return pm_global_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -4551,24 +4504,17 @@ pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *ta
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_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
- *node = (pm_global_variable_or_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_global_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -4576,18 +4522,13 @@ pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target,
*/
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_NODE_ALLOC(parser, pm_global_variable_read_node_t);
-
- *node = (pm_global_variable_read_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
+ return pm_global_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -4595,18 +4536,13 @@ pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name)
*/
static pm_global_variable_read_node_t *
pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
- pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
-
- *node = (pm_global_variable_read_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .name = name
- };
-
- return node;
+ return pm_global_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ name
+ );
}
/**
@@ -4614,25 +4550,16 @@ pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant
*/
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_NODE_ALLOC(parser, pm_global_variable_write_node_t);
-
- *node = (pm_global_variable_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .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;
+ return pm_global_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ pm_global_variable_write_name(parser, target),
+ target->location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -4640,21 +4567,16 @@ pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, con
*/
static pm_global_variable_write_node_t *
pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
- pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
-
- *node = (pm_global_variable_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .name = name,
- .name_loc = PM_LOCATION_NULL_VALUE(parser),
- .operator_loc = PM_LOCATION_NULL_VALUE(parser),
- .value = value
- };
-
- return node;
+ return pm_global_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ name,
+ ((pm_location_t) { 0 }),
+ value,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -4663,29 +4585,24 @@ pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constan
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_NODE_ALLOC(parser, pm_hash_node_t);
-
- *node = (pm_hash_node_t) {
- {
- .type = PM_HASH_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(opening)
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_NULL_VALUE(parser),
- .elements = { 0 }
- };
- return node;
+ return pm_hash_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, opening),
+ TOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
}
/**
* 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);
+static PRISM_INLINE void
+pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
+ pm_node_list_append(arena, &hash->elements, element);
bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
if (static_literal) {
@@ -4696,14 +4613,14 @@ pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
}
if (!static_literal) {
- pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
+ pm_node_flag_unset(UP(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);
+static PRISM_INLINE void
+pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
+ hash->closing_loc = TOK2LOC(parser, token);
}
/**
@@ -4719,38 +4636,32 @@ pm_if_node_create(pm_parser_t *parser,
const pm_token_t *end_keyword
) {
pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
- const uint8_t *end;
- if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
- end = end_keyword->end;
+ uint32_t start = PM_TOKEN_START(parser, if_keyword);
+ uint32_t end;
+
+ if (end_keyword != NULL) {
+ end = PM_TOKEN_END(parser, end_keyword);
} else if (subsequent != NULL) {
- end = subsequent->location.end;
+ end = PM_NODE_END(subsequent);
} else if (pm_statements_node_body_length(statements) != 0) {
- end = statements->base.location.end;
+ end = PM_NODE_END(statements);
} else {
- end = predicate->location.end;
- }
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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,
- .subsequent = subsequent,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
+ end = PM_NODE_END(predicate);
+ }
+
+ return pm_if_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ TOK2LOC(parser, if_keyword),
+ predicate,
+ NTOK2LOC(parser, then_keyword),
+ statements,
+ subsequent,
+ NTOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -4759,30 +4670,22 @@ pm_if_node_create(pm_parser_t *parser,
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(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, statements, statement, true);
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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,
- .subsequent = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
+ return pm_if_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_NODES(statement, predicate),
+ TOK2LOC(parser, if_keyword),
+ predicate,
+ ((pm_location_t) { 0 }),
+ statements,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -4799,43 +4702,31 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_to
pm_statements_node_t *else_statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, else_statements, false_expression, true);
- 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_NODE_ALLOC(parser, pm_if_node_t);
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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,
- .subsequent = (pm_node_t *) else_node,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-
+ pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
+ return pm_if_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_NODES(predicate, false_expression),
+ ((pm_location_t) { 0 }),
+ predicate,
+ TOK2LOC(parser, qmark),
+ if_statements,
+ UP(else_node),
+ ((pm_location_t) { 0 })
+ );
}
-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 PRISM_INLINE void
+pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
+ node->end_keyword_loc = TOK2LOC(parser, 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);
+static PRISM_INLINE void
+pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
+ node->end_keyword_loc = TOK2LOC(parser, keyword);
}
/**
@@ -4843,18 +4734,13 @@ pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword
*/
static pm_implicit_node_t *
pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
- pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
-
- *node = (pm_implicit_node_t) {
- {
- .type = PM_IMPLICIT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = value->location
- },
- .value = value
- };
-
- return node;
+ return pm_implicit_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(value),
+ value
+ );
}
/**
@@ -4864,17 +4750,12 @@ 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_NODE_ALLOC(parser, pm_implicit_rest_node_t);
-
- *node = (pm_implicit_rest_node_t) {
- {
- .type = PM_IMPLICIT_REST_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }
- };
-
- return node;
+ return pm_implicit_rest_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -4883,28 +4764,33 @@ pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
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_NODE_ALLOC(parser, pm_integer_node_t);
- *node = (pm_integer_node_t) {
- {
- .type = PM_INTEGER_NODE,
- .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .value = { 0 }
- };
+ pm_integer_node_t *node = pm_integer_node_new(
+ parser->arena,
+ ++parser->node_id,
+ base | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_integer_t) { 0 })
+ );
- pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
- switch (base) {
- case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
- case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
- case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
- case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
- default: assert(false && "unreachable"); break;
+ if (parser->integer.lexed) {
+ // The value was already computed during lexing.
+ node->value.value = parser->integer.value;
+ parser->integer.lexed = false;
+ } else {
+ pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
+ switch (base) {
+ case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
+ case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
+ case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
+ case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
+ default: assert(false && "unreachable"); break;
+ }
+
+ pm_integer_parse(&node->value, integer_base, token->start, token->end);
+ pm_integer_arena_move(parser->arena, &node->value);
}
- pm_integer_parse(&node->value, integer_base, token->start, token->end);
return node;
}
@@ -4916,22 +4802,17 @@ 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_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_integer_node_create(parser, base, &((pm_token_t) {
.type = PM_TOKEN_INTEGER,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4942,17 +4823,14 @@ 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_NODE_ALLOC(parser, pm_rational_node_t);
- *node = (pm_rational_node_t) {
- {
- .type = PM_RATIONAL_NODE,
- .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numerator = { 0 },
- .denominator = { .value = 1, 0 }
- };
+ pm_rational_node_t *node = pm_rational_node_new(
+ parser->arena,
+ ++parser->node_id,
+ base | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_integer_t) { 0 }),
+ ((pm_integer_t) { .value = 1 })
+ );
pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
switch (base) {
@@ -4964,6 +4842,7 @@ pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const
}
pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
+ pm_integer_arena_move(parser->arena, &node->numerator);
return node;
}
@@ -4976,22 +4855,17 @@ 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_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
+ return pm_imaginary_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
.type = PM_TOKEN_INTEGER_RATIONAL,
.start = token->start,
.end = token->end - 1
- }))
- };
-
- return node;
+ })))
+ );
}
/**
@@ -4999,33 +4873,27 @@ pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t b
*/
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_NODE_ALLOC(parser, pm_in_node_t);
+ uint32_t start = PM_TOKEN_START(parser, in_keyword);
+ uint32_t end;
- 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;
+ end = PM_NODE_END(statements);
+ } else if (then_keyword != NULL) {
+ end = PM_TOKEN_END(parser, then_keyword);
} else {
- end = pattern->location.end;
- }
-
- *node = (pm_in_node_t) {
- {
- .type = PM_IN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ end = PM_NODE_END(pattern);
+ }
+
+ return pm_in_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ pattern,
+ statements,
+ TOK2LOC(parser, in_keyword),
+ NTOK2LOC(parser, then_keyword)
+ );
}
/**
@@ -5034,24 +4902,17 @@ pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t
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_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
- *node = (pm_instance_variable_and_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_instance_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -5059,25 +4920,17 @@ pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_vari
*/
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_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
-
- *node = (pm_instance_variable_operator_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
+ return pm_instance_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
+ );
}
/**
@@ -5086,24 +4939,17 @@ pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance
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_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
-
- *node = (pm_instance_variable_or_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_instance_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->name,
+ target->base.location,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -5112,18 +4958,14 @@ pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_varia
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_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
-
- *node = (pm_instance_variable_read_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
- return node;
+ return pm_instance_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_parser_constant_id_token(parser, token)
+ );
}
/**
@@ -5132,24 +4974,16 @@ pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *tok
*/
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_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
- *node = (pm_instance_variable_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_instance_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(read_node, value),
+ read_node->name,
+ read_node->base.location,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5158,7 +4992,7 @@ pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable
* literals.
*/
static void
-pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
+pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
switch (PM_NODE_TYPE(part)) {
case PM_STRING_NODE:
pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
@@ -5186,14 +5020,14 @@ pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *p
break;
}
case PM_EMBEDDED_VARIABLE_NODE:
- pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
+ pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
break;
default:
assert(false && "unexpected node type");
break;
}
- pm_node_list_append(parts, part);
+ pm_node_list_append(arena, parts, part);
}
/**
@@ -5201,43 +5035,34 @@ pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *p
*/
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_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
-
- *node = (pm_interpolated_regular_expression_node_t) {
- {
- .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = NULL,
- },
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .parts = { 0 }
- };
-
- return node;
+ return pm_interpolated_regular_expression_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, opening),
+ TOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, opening)
+ );
}
-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;
+static PRISM_INLINE void
+pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
+ if (PM_NODE_START(node) > PM_NODE_START(part)) {
+ PM_NODE_START_SET_NODE(node, part);
}
- if (node->base.location.end < part->location.end) {
- node->base.location.end = part->location.end;
+ if (PM_NODE_END(node) < PM_NODE_END(part)) {
+ PM_NODE_LENGTH_SET_NODE(node, part);
}
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
+ pm_interpolated_node_append(arena, UP(node), &node->parts, part);
}
-static inline void
+static PRISM_INLINE void
pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, 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(parser, closing));
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
+ pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
}
/**
@@ -5249,7 +5074,7 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte
* PM_NODE_FLAG_STATIC_LITERAL indicates that the node should be treated as a
* single static literal string that can be pushed onto the stack on its own.
* Note that this doesn't necessarily mean that the string will be frozen or
- * not; the instructions in CRuby will be either putobject or putstring,
+ * not; the instructions in CRuby will be either putobject, dupstring or dupchilledstring,
* depending on the combination of `--enable-frozen-string-literal`,
* `# frozen_string_literal: true`, and whether or not there is interpolation.
*
@@ -5263,22 +5088,31 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte
* is necessary to indicate that the string should be left up to the runtime,
* which could potentially use a chilled string otherwise.
*/
-static inline void
-pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
+static PRISM_INLINE void
+pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
+ pm_arena_t *arena = parser->arena;
#define CLEAR_FLAGS(node) \
- node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
+ node->base.flags = (pm_node_flags_t) (FL(node) & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
#define MUTABLE_FLAGS(node) \
- node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
+ node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
- if (node->parts.size == 0 && node->opening_loc.start == NULL) {
- node->base.location.start = part->location.start;
+ if (node->parts.size == 0 && node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(node, part);
}
- node->base.location.end = MAX(node->base.location.end, part->location.end);
+ if (PM_NODE_END(part) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, part);
+ }
switch (PM_NODE_TYPE(part)) {
case PM_STRING_NODE:
+ // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
+ // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
+ // as long as this interpolation only consists of other string literals.
+ if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
+ pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
+ }
part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
break;
case PM_INTERPOLATED_STRING_NODE:
@@ -5330,8 +5164,14 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
break;
case PM_X_STRING_NODE:
case PM_INTERPOLATED_X_STRING_NODE:
- // If this is an x string, then this is a syntax error. But we want
- // to handle it here so that we don't fail the assertion.
+ case PM_SYMBOL_NODE:
+ case PM_INTERPOLATED_SYMBOL_NODE:
+ // These will only happen in error cases. But we want to handle it
+ // here so that we don't fail the assertion.
+ CLEAR_FLAGS(node);
+ pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
+ return;
+ case PM_ERROR_RECOVERY_NODE:
CLEAR_FLAGS(node);
break;
default:
@@ -5339,7 +5179,7 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
break;
}
- pm_node_list_append(&node->parts, part);
+ pm_node_list_append(arena, &node->parts, part);
#undef CLEAR_FLAGS
#undef MUTABLE_FLAGS
@@ -5350,7 +5190,6 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_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_NODE_ALLOC(parser, pm_interpolated_string_node_t);
pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
switch (parser->frozen_string_literal) {
@@ -5362,25 +5201,23 @@ pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *openin
break;
}
- *node = (pm_interpolated_string_node_t) {
- {
- .type = PM_INTERPOLATED_STRING_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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 }
- };
+ uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
+ uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
+
+ pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ NTOK2LOC(parser, closing)
+ );
if (parts != NULL) {
pm_node_t *part;
PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_string_node_append(node, part);
+ pm_interpolated_string_node_append(parser, node, part);
}
}
@@ -5391,25 +5228,28 @@ pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *openin
* 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;
+pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
}
static 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_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
+ if (node->parts.size == 0 && node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(node, part);
}
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
- node->base.location.end = MAX(node->base.location.end, part->location.end);
+ pm_interpolated_node_append(arena, UP(node), &node->parts, part);
+
+ if (PM_NODE_END(part) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, part);
+ }
}
static void
-pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
+pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
}
/**
@@ -5417,27 +5257,23 @@ pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *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_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
-
- *node = (pm_interpolated_symbol_node_t) {
- {
- .type = PM_INTERPOLATED_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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 }
- };
+ uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
+ uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
+
+ pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ NTOK2LOC(parser, closing)
+ );
if (parts != NULL) {
pm_node_t *part;
PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_symbol_node_append(node, part);
+ pm_interpolated_symbol_node_append(parser->arena, node, part);
}
}
@@ -5449,35 +5285,27 @@ pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *openin
*/
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_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
-
- *node = (pm_interpolated_x_string_node_t) {
- {
- .type = PM_INTERPOLATED_X_STRING_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_interpolated_x_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, closing)
+ );
}
-static inline void
-pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
- node->base.location.end = part->location.end;
+static PRISM_INLINE void
+pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
+ pm_interpolated_node_append(arena, UP(node), &node->parts, part);
+ PM_NODE_LENGTH_SET_NODE(node, part);
}
-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;
+static PRISM_INLINE void
+pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
+ node->closing_loc = TOK2LOC(parser, closing);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
}
/**
@@ -5485,17 +5313,12 @@ pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node,
*/
static pm_it_local_variable_read_node_t *
pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
-
- *node = (pm_it_local_variable_read_node_t) {
- {
- .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name)
- }
- };
-
- return node;
+ return pm_it_local_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name)
+ );
}
/**
@@ -5503,20 +5326,12 @@ pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *nam
*/
static pm_it_parameters_node_t *
pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
-
- *node = (pm_it_parameters_node_t) {
- {
- .type = PM_IT_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- }
- };
-
- return node;
+ return pm_it_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing)
+ );
}
/**
@@ -5524,37 +5339,31 @@ pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, con
*/
static pm_keyword_hash_node_t *
pm_keyword_hash_node_create(pm_parser_t *parser) {
- pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
-
- *node = (pm_keyword_hash_node_t) {
- .base = {
- .type = PM_KEYWORD_HASH_NODE,
- .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- },
- .elements = { 0 }
- };
-
- return node;
+ return pm_keyword_hash_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
* Append an element to a KeywordHashNode node.
*/
static void
-pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
+pm_keyword_hash_node_elements_append(pm_arena_t *arena, 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 SYMBOL_KEYS flag off.
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_flag_unset(UP(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;
+ pm_node_list_append(arena, &hash->elements, element);
+ if (PM_NODE_LENGTH(hash) == 0) {
+ PM_NODE_START_SET_NODE(hash, element);
}
- hash->base.location.end = element->location.end;
+ PM_NODE_LENGTH_SET_NODE(hash, element);
}
/**
@@ -5562,22 +5371,14 @@ pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *el
*/
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_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
-
- *node = (pm_required_keyword_parameter_node_t) {
- {
- .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_required_keyword_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_parser_constant_id_raw(parser, name->start, name->end - 1),
+ TOK2LOC(parser, name)
+ );
}
/**
@@ -5585,23 +5386,15 @@ pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t
*/
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_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
-
- *node = (pm_optional_keyword_parameter_node_t) {
- {
- .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_optional_keyword_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
+ pm_parser_constant_id_raw(parser, name->start, name->end - 1),
+ TOK2LOC(parser, name),
+ value
+ );
}
/**
@@ -5609,23 +5402,15 @@ pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t
*/
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_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
-
- *node = (pm_keyword_rest_parameter_node_t) {
- {
- .type = PM_KEYWORD_REST_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_keyword_rest_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
+ name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
+ NTOK2LOC(parser, name),
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5641,26 +5426,18 @@ pm_lambda_node_create(
pm_node_t *parameters,
pm_node_t *body
) {
- pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
-
- *node = (pm_lambda_node_t) {
- {
- .type = PM_LAMBDA_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = closing->end
- },
- },
- .locals = *locals,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .parameters = parameters,
- .body = body
- };
-
- return node;
+ return pm_lambda_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, closing),
+ *locals,
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing),
+ parameters,
+ body
+ );
}
/**
@@ -5670,25 +5447,18 @@ 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_IT_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_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
-
- *node = (pm_local_variable_and_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_local_variable_and_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ name,
+ depth
+ );
}
/**
@@ -5696,26 +5466,18 @@ pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target,
*/
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_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
-
- *node = (pm_local_variable_operator_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .depth = depth
- };
-
- return node;
+ return pm_local_variable_operator_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ name,
+ pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
+ depth
+ );
}
/**
@@ -5725,25 +5487,18 @@ 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_IT_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_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
- *node = (pm_local_variable_or_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_local_variable_or_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(target, value),
+ target->location,
+ TOK2LOC(parser, operator),
+ value,
+ name,
+ depth
+ );
}
/**
@@ -5753,19 +5508,14 @@ static pm_local_variable_read_node_t *
pm_local_variable_read_node_create_constant_id(pm_parser_t *parser, const pm_token_t *name, pm_constant_id_t name_id, uint32_t depth, bool missing) {
if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
- pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
-
- *node = (pm_local_variable_read_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = name_id,
- .depth = depth
- };
-
- return node;
+ return pm_local_variable_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ name_id,
+ depth
+ );
}
/**
@@ -5792,32 +5542,23 @@ pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t
*/
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_NODE_ALLOC(parser, pm_local_variable_write_node_t);
-
- *node = (pm_local_variable_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_local_variable_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
+ name,
+ depth,
+ *name_loc,
+ value,
+ TOK2LOC(parser, operator)
+ );
}
/**
* Returns true if the given bounds comprise `it`.
*/
-static inline bool
+static PRISM_INLINE bool
pm_token_is_it(const uint8_t *start, const uint8_t *end) {
return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
}
@@ -5826,19 +5567,24 @@ pm_token_is_it(const uint8_t *start, const uint8_t *end) {
* 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]));
+static PRISM_INLINE bool
+pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
+ return (
+ (length == 2) &&
+ (parser->start[start] == '_') &&
+ (parser->start[start + 1] != '0') &&
+ pm_char_is_decimal_digit(parser->start[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);
+static PRISM_INLINE void
+pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ if (pm_token_is_numbered_parameter(parser, start, length)) {
+ PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
}
}
@@ -5848,20 +5594,16 @@ pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const ui
*/
static pm_local_variable_target_node_t *
pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
- pm_refute_numbered_parameter(parser, location->start, location->end);
- pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
-
- *node = (pm_local_variable_target_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_TARGET_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = *location
- },
- .name = name,
- .depth = depth
- };
-
- return node;
+ pm_refute_numbered_parameter(parser, location->start, location->length);
+
+ return pm_local_variable_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = location->start, .length = location->length }),
+ name,
+ depth
+ );
}
/**
@@ -5871,23 +5613,15 @@ 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_NODE_ALLOC(parser, pm_match_predicate_node_t);
-
- *node = (pm_match_predicate_node_t) {
- {
- .type = PM_MATCH_PREDICATE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = value->location.start,
- .end = pattern->location.end
- }
- },
- .value = value,
- .pattern = pattern,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ return pm_match_predicate_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(value, pattern),
+ value,
+ pattern,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5897,23 +5631,15 @@ 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_NODE_ALLOC(parser, pm_match_required_node_t);
-
- *node = (pm_match_required_node_t) {
- {
- .type = PM_MATCH_REQUIRED_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = value->location.start,
- .end = pattern->location.end
- }
- },
- .value = value,
- .pattern = pattern,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ return pm_match_required_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(value, pattern),
+ value,
+ pattern,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -5921,19 +5647,14 @@ pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *
*/
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_NODE_ALLOC(parser, pm_match_write_node_t);
-
- *node = (pm_match_write_node_t) {
- {
- .type = PM_MATCH_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = call->base.location
- },
- .call = call,
- .targets = { 0 }
- };
-
- return node;
+ return pm_match_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(call),
+ call,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
@@ -5941,26 +5662,18 @@ pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
*/
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_NODE_ALLOC(parser, pm_module_node_t);
-
- *node = (pm_module_node_t) {
- {
- .type = PM_MODULE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_module_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
+ (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
+ TOK2LOC(parser, module_keyword),
+ constant_path,
+ body,
+ TOK2LOC(parser, end_keyword),
+ pm_parser_constant_id_token(parser, name)
+ );
}
/**
@@ -5968,22 +5681,17 @@ pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const
*/
static pm_multi_target_node_t *
pm_multi_target_node_create(pm_parser_t *parser) {
- pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
-
- *node = (pm_multi_target_node_t) {
- {
- .type = PM_MULTI_TARGET_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_multi_target_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -5996,27 +5704,27 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t
node->rest = target;
} else {
pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
- pm_node_list_append(&node->rights, target);
+ pm_node_list_append(parser->arena, &node->rights, target);
}
} else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
if (node->rest == NULL) {
node->rest = target;
} else {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
- pm_node_list_append(&node->rights, target);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
+ pm_node_list_append(parser->arena, &node->rights, target);
}
} else if (node->rest == NULL) {
- pm_node_list_append(&node->lefts, target);
+ pm_node_list_append(parser->arena, &node->lefts, target);
} else {
- pm_node_list_append(&node->rights, target);
+ pm_node_list_append(parser->arena, &node->rights, target);
}
- if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
- node->base.location.start = target->location.start;
+ if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
+ PM_NODE_START_SET_NODE(node, target);
}
- if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
- node->base.location.end = target->location.end;
+ if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
+ PM_NODE_LENGTH_SET_NODE(node, target);
}
}
@@ -6024,18 +5732,19 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t
* 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);
+pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
+ PM_NODE_START_SET_TOKEN(parser, node, lparen);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
+ node->lparen_loc = TOK2LOC(parser, 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);
+pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
+ node->rparen_loc = TOK2LOC(parser, rparen);
}
/**
@@ -6043,32 +5752,21 @@ pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t
*/
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_NODE_ALLOC(parser, pm_multi_write_node_t);
-
- *node = (pm_multi_write_node_t) {
- {
- .type = PM_MULTI_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .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.
- xfree(target);
-
- return node;
+ /* The target is no longer necessary because we have reused its children. It
+ * is arena-allocated so no explicit free is needed. */
+ return pm_multi_write_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
+ PM_LOCATION_INIT_NODES(target, value),
+ target->lefts,
+ target->rest,
+ target->rights,
+ target->lparen_loc,
+ target->rparen_loc,
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -6077,22 +5775,15 @@ pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target,
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_NODE_ALLOC(parser, pm_next_node_t);
-
- *node = (pm_next_node_t) {
- {
- .type = PM_NEXT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .arguments = arguments
- };
- return node;
+ return pm_next_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
+ arguments,
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -6101,16 +5792,31 @@ pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments
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_NODE_ALLOC(parser, pm_nil_node_t);
- *node = (pm_nil_node_t) {{
- .type = PM_NIL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
+ return pm_nil_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
+}
- return node;
+/**
+ * Allocate and initialize a new NoKeywordsParameterNode node.
+ */
+static pm_no_block_parameter_node_t *
+pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
+ assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
+ assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
+
+ return pm_no_block_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, keyword)
+ );
}
/**
@@ -6120,41 +5826,29 @@ 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_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
-
- *node = (pm_no_keywords_parameter_node_t) {
- {
- .type = PM_NO_KEYWORDS_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = keyword->end
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
- return node;
+ return pm_no_keywords_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, keyword)
+ );
}
/**
* 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_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
-
- *node = (pm_numbered_parameters_node_t) {
- {
- .type = PM_NUMBERED_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = *location
- },
- .maximum = maximum
- };
-
- return node;
+pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
+ return pm_numbered_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ maximum
+ );
}
/**
@@ -6190,14 +5884,14 @@ pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *to
unsigned long value = strtoul(digits, &endptr, 10);
if ((digits == endptr) || (*endptr != '\0')) {
- pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
+ pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
value = 0;
}
- xfree(digits);
+ xfree_sized(digits, sizeof(char) * (length + 1));
if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
- PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
+ PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
value = 0;
}
@@ -6212,18 +5906,14 @@ pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *to
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_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
- *node = (pm_numbered_reference_read_node_t) {
- {
- .type = PM_NUMBERED_REFERENCE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .number = pm_numbered_reference_read_node_number(parser, name)
- };
-
- return node;
+ return pm_numbered_reference_read_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, name),
+ pm_numbered_reference_read_node_number(parser, name)
+ );
}
/**
@@ -6231,24 +5921,16 @@ pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *na
*/
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_NODE_ALLOC(parser, pm_optional_parameter_node_t);
-
- *node = (pm_optional_parameter_node_t) {
- {
- .type = PM_OPTIONAL_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_optional_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
+ pm_parser_constant_id_token(parser, name),
+ TOK2LOC(parser, name),
+ TOK2LOC(parser, operator),
+ value
+ );
}
/**
@@ -6258,23 +5940,15 @@ 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_NODE_ALLOC(parser, pm_or_node_t);
-
- *node = (pm_or_node_t) {
- {
- .type = PM_OR_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end
- }
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ return pm_or_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(left, right),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6282,24 +5956,19 @@ pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operat
*/
static pm_parameters_node_t *
pm_parameters_node_create(pm_parser_t *parser) {
- pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
-
- *node = (pm_parameters_node_t) {
- {
- .type = PM_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
- },
- .rest = NULL,
- .keyword_rest = NULL,
- .block = NULL,
- .requireds = { 0 },
- .optionals = { 0 },
- .posts = { 0 },
- .keywords = { 0 }
- };
-
- return node;
+ return pm_parameters_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 }),
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ ((pm_node_list_t) { 0 }),
+ ((pm_node_list_t) { 0 }),
+ NULL,
+ NULL
+ );
}
/**
@@ -6307,16 +5976,12 @@ pm_parameters_node_create(pm_parser_t *parser) {
*/
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.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
+ PM_NODE_START_SET_NODE(params, param);
}
- 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;
+ if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
+ PM_NODE_LENGTH_SET_NODE(params, param);
}
}
@@ -6324,27 +5989,27 @@ pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param)
* 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_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->requireds, param);
+ pm_node_list_append(arena, &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);
+pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
+ pm_parameters_node_location_set(params, UP(param));
+ pm_node_list_append(arena, &params->optionals, UP(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_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->posts, param);
+ pm_node_list_append(arena, &params->posts, param);
}
/**
@@ -6360,9 +6025,9 @@ pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *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_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->keywords, param);
+ pm_node_list_append(arena, &params->keywords, param);
}
/**
@@ -6379,9 +6044,9 @@ pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *par
* 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) {
+pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
assert(params->block == NULL);
- pm_parameters_node_location_set(params, (pm_node_t *) param);
+ pm_parameters_node_location_set(params, param);
params->block = param;
}
@@ -6390,22 +6055,14 @@ pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_no
*/
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_NODE_ALLOC(parser, pm_program_node_t);
-
- *node = (pm_program_node_t) {
- {
- .type = PM_PROGRAM_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_program_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODE(statements),
+ *locals,
+ statements
+ );
}
/**
@@ -6413,24 +6070,15 @@ pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_st
*/
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_node_flags_t flags) {
- pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
-
- *node = (pm_parentheses_node_t) {
- {
- .type = PM_PARENTHESES_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_parentheses_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ body,
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -6438,24 +6086,16 @@ pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_no
*/
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_NODE_ALLOC(parser, pm_pinned_expression_node_t);
-
- *node = (pm_pinned_expression_node_t) {
- {
- .type = PM_PINNED_EXPRESSION_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_pinned_expression_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
+ expression,
+ TOK2LOC(parser, operator),
+ TOK2LOC(parser, lparen),
+ TOK2LOC(parser, rparen)
+ );
}
/**
@@ -6463,22 +6103,14 @@ pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, con
*/
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_NODE_ALLOC(parser, pm_pinned_variable_node_t);
-
- *node = (pm_pinned_variable_node_t) {
- {
- .type = PM_PINNED_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = variable->location.end
- }
- },
- .variable = variable,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
+ return pm_pinned_variable_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
+ variable,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6486,24 +6118,16 @@ pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator,
*/
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_NODE_ALLOC(parser, pm_post_execution_node_t);
-
- *node = (pm_post_execution_node_t) {
- {
- .type = PM_POST_EXECUTION_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_post_execution_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ statements,
+ TOK2LOC(parser, keyword),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -6511,24 +6135,16 @@ pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, co
*/
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_NODE_ALLOC(parser, pm_pre_execution_node_t);
-
- *node = (pm_pre_execution_node_t) {
- {
- .type = PM_PRE_EXECUTION_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_pre_execution_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ statements,
+ TOK2LOC(parser, keyword),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, closing)
+ );
}
/**
@@ -6538,8 +6154,6 @@ 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_NODE_ALLOC(parser, pm_range_node_t);
pm_node_flags_t flags = 0;
// Indicate that this node is an exclusive range if the operator is `...`.
@@ -6557,22 +6171,18 @@ pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *ope
flags |= PM_NODE_FLAG_STATIC_LITERAL;
}
- *node = (pm_range_node_t) {
- {
- .type = PM_RANGE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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)
- };
+ uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
+ uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
- return node;
+ return pm_range_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ left,
+ right,
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6581,15 +6191,13 @@ pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *ope
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_NODE_ALLOC(parser, pm_redo_node_t);
- *node = (pm_redo_node_t) {{
- .type = PM_REDO_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
+ return pm_redo_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6598,31 +6206,22 @@ pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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_NODE_ALLOC(parser, pm_regular_expression_node_t);
-
- *node = (pm_regular_expression_node_t) {
- {
- .type = PM_REGULAR_EXPRESSION_NODE,
- .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_regular_expression_node_new(
+ parser->arena,
+ ++parser->node_id,
+ pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, content),
+ TOK2LOC(parser, closing),
+ *unescaped
+ );
}
/**
* Allocate a new initialize a new RegularExpressionNode node.
*/
-static inline pm_regular_expression_node_t *
+static PRISM_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);
}
@@ -6632,18 +6231,13 @@ pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening
*/
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_NODE_ALLOC(parser, pm_required_parameter_node_t);
-
- *node = (pm_required_parameter_node_t) {
- {
- .type = PM_REQUIRED_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
+ return pm_required_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ pm_parser_constant_id_token(parser, token)
+ );
}
/**
@@ -6651,23 +6245,15 @@ pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token)
*/
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_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
-
- *node = (pm_rescue_modifier_node_t) {
- {
- .type = PM_RESCUE_MODIFIER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_rescue_modifier_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_NODES(expression, rescue_expression),
+ expression,
+ TOK2LOC(parser, keyword),
+ rescue_expression
+ );
}
/**
@@ -6675,29 +6261,24 @@ pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const
*/
static pm_rescue_node_t *
pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
- pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
-
- *node = (pm_rescue_node_t) {
- {
- .type = PM_RESCUE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(keyword)
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .reference = NULL,
- .statements = NULL,
- .subsequent = NULL,
- .exceptions = { 0 }
- };
-
- return node;
+ return pm_rescue_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, keyword),
+ TOK2LOC(parser, keyword),
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL,
+ ((pm_location_t) { 0 }),
+ NULL,
+ NULL
+ );
}
-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);
+static PRISM_INLINE void
+pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
+ node->operator_loc = TOK2LOC(parser, operator);
}
/**
@@ -6706,7 +6287,7 @@ pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator)
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;
+ PM_NODE_LENGTH_SET_NODE(node, reference);
}
/**
@@ -6716,7 +6297,7 @@ 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;
+ PM_NODE_LENGTH_SET_NODE(node, statements);
}
}
@@ -6726,16 +6307,16 @@ pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *stat
static void
pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
node->subsequent = subsequent;
- node->base.location.end = subsequent->base.location.end;
+ PM_NODE_LENGTH_SET_NODE(node, subsequent);
}
/**
* 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;
+pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
+ pm_node_list_append(arena, &node->exceptions, exception);
+ PM_NODE_LENGTH_SET_NODE(node, exception);
}
/**
@@ -6743,23 +6324,15 @@ pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
*/
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_NODE_ALLOC(parser, pm_rest_parameter_node_t);
-
- *node = (pm_rest_parameter_node_t) {
- {
- .type = PM_REST_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_rest_parameter_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
+ name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
+ NTOK2LOC(parser, name),
+ TOK2LOC(parser, operator)
+ );
}
/**
@@ -6768,15 +6341,13 @@ pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, c
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_NODE_ALLOC(parser, pm_retry_node_t);
- *node = (pm_retry_node_t) {{
- .type = PM_RETRY_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
+ return pm_retry_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6784,22 +6355,14 @@ pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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_NODE_ALLOC(parser, pm_return_node_t);
-
- *node = (pm_return_node_t) {
- {
- .type = PM_RETURN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .arguments = arguments
- };
-
- return node;
+ return pm_return_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
+ TOK2LOC(parser, keyword),
+ arguments
+ );
}
/**
@@ -6808,15 +6371,13 @@ pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_argumen
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_NODE_ALLOC(parser, pm_self_node_t);
- *node = (pm_self_node_t) {{
- .type = PM_SELF_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
+ return pm_self_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6824,19 +6385,13 @@ pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
static pm_shareable_constant_node_t *
pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
- pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
-
- *node = (pm_shareable_constant_node_t) {
- {
- .type = PM_SHAREABLE_CONSTANT_NODE,
- .flags = (pm_node_flags_t) value,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NODE_VALUE(write)
- },
- .write = write
- };
-
- return node;
+ return pm_shareable_constant_node_new(
+ parser->arena,
+ ++parser->node_id,
+ (pm_node_flags_t) value,
+ PM_LOCATION_INIT_NODE(write),
+ write
+ );
}
/**
@@ -6844,26 +6399,18 @@ pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shar
*/
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_NODE_ALLOC(parser, pm_singleton_class_node_t);
-
- *node = (pm_singleton_class_node_t) {
- {
- .type = PM_SINGLETON_CLASS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_singleton_class_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
+ *locals,
+ TOK2LOC(parser, class_keyword),
+ TOK2LOC(parser, operator),
+ expression,
+ body,
+ TOK2LOC(parser, end_keyword)
+ );
}
/**
@@ -6872,16 +6419,13 @@ pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *local
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_NODE_ALLOC(parser, pm_source_encoding_node_t);
-
- *node = (pm_source_encoding_node_t) {{
- .type = PM_SOURCE_ENCODING_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
- return node;
+ return pm_source_encoding_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6889,7 +6433,6 @@ pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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_NODE_ALLOC(parser, pm_source_file_node_t);
assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
pm_node_flags_t flags = 0;
@@ -6903,17 +6446,13 @@ pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword)
break;
}
- *node = (pm_source_file_node_t) {
- {
- .type = PM_SOURCE_FILE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
- },
- .filepath = parser->filepath
- };
-
- return node;
+ return pm_source_file_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKEN(parser, file_keyword),
+ parser->filepath
+ );
}
/**
@@ -6922,16 +6461,13 @@ pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword)
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_NODE_ALLOC(parser, pm_source_line_node_t);
- *node = (pm_source_line_node_t) {{
- .type = PM_SOURCE_LINE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
+ return pm_source_line_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -6939,22 +6475,14 @@ pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
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_NODE_ALLOC(parser, pm_splat_node_t);
-
- *node = (pm_splat_node_t) {
- {
- .type = PM_SPLAT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = (expression == NULL ? operator->end : expression->location.end)
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .expression = expression
- };
-
- return node;
+ return pm_splat_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
+ TOK2LOC(parser, operator),
+ expression
+ );
}
/**
@@ -6962,18 +6490,13 @@ pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t
*/
static pm_statements_node_t *
pm_statements_node_create(pm_parser_t *parser) {
- pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
-
- *node = (pm_statements_node_t) {
- {
- .type = PM_STATEMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .body = { 0 }
- };
-
- return node;
+ return pm_statements_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_node_list_t) { 0 })
+ );
}
/**
@@ -6985,25 +6508,17 @@ pm_statements_node_body_length(pm_statements_node_t *node) {
}
/**
- * 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 };
-}
-
-/**
* Update the location of the statements node based on the statement that is
* being added to the list.
*/
-static inline void
+static PRISM_INLINE void
pm_statements_node_body_update(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 (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
+ PM_NODE_START_SET_NODE(node, statement);
}
- if (statement->location.end > node->base.location.end) {
- node->base.location.end = statement->location.end;
+ if (PM_NODE_END(statement) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, statement);
}
}
@@ -7030,7 +6545,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
}
}
- pm_node_list_append(&node->body, statement);
+ pm_node_list_append(parser->arena, &node->body, statement);
if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
}
@@ -7038,18 +6553,17 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
* Prepend a new node to the given StatementsNode node's body.
*/
static void
-pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
+pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
pm_statements_node_body_update(node, statement);
- pm_node_list_prepend(&node->body, statement);
+ pm_node_list_prepend(arena, &node->body, statement);
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 *
+static PRISM_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_NODE_ALLOC(parser, pm_string_node_t);
pm_node_flags_t flags = 0;
switch (parser->frozen_string_literal) {
@@ -7061,23 +6575,19 @@ pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening,
break;
}
- *node = (pm_string_node_t) {
- {
- .type = PM_STRING_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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
- };
+ uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
+ uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
- return node;
+ return pm_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ TOK2LOC(parser, content),
+ NTOK2LOC(parser, closing),
+ *string
+ );
}
/**
@@ -7105,30 +6615,21 @@ pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *open
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_NODE_ALLOC(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,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ const pm_location_t *end = pm_arguments_end(arguments);
+ assert(end != NULL && "unreachable");
+
+ return pm_super_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
+ TOK2LOC(parser, keyword),
+ arguments->opening_loc,
+ arguments->arguments,
+ arguments->closing_loc,
+ arguments->block
+ );
}
/**
@@ -7156,7 +6657,7 @@ parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *locat
size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
if (width == 0) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
+ pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
break;
}
@@ -7176,7 +6677,7 @@ parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *loca
size_t width = encoding->char_width(cursor, end - cursor);
if (width == 0) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
+ pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
break;
}
@@ -7193,7 +6694,7 @@ parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *loca
* If the validate flag is set, then it will check the contents of the symbol
* to ensure that all characters are valid in the encoding.
*/
-static inline pm_node_flags_t
+static PRISM_INLINE pm_node_flags_t
parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
if (parser->explicit_encoding != NULL) {
// A Symbol may optionally have its encoding explicitly set. This will
@@ -7218,160 +6719,31 @@ parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_
return 0;
}
-static pm_node_flags_t
-parse_and_validate_regular_expression_encoding_modifier(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding) {
- assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
- (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
- (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
- (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
-
- // There's special validation logic used if a string does not contain any character escape sequences.
- if (parser->explicit_encoding == NULL) {
- // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
- // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
- // the US-ASCII encoding.
- if (ascii_only) {
- return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
- }
-
- if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- if (!ascii_only) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
- }
- } else if (parser->encoding != modifier_encoding) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
-
- if (modifier == 'n' && !ascii_only) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) pm_string_length(source), (const char *) pm_string_source(source));
- }
- }
-
- return flags;
- }
-
- // TODO (nirvdrum 21-Feb-2024): To validate regexp sources with character escape sequences we need to know whether hex or Unicode escape sequences were used and Prism doesn't currently provide that data. We handle a subset of unambiguous cases in the meanwhile.
- bool mixed_encoding = false;
-
- if (mixed_encoding) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
- } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
- // TODO (nirvdrum 21-Feb-2024): Validate the content is valid in the modifier encoding. Do this on-demand so we don't pay the cost of computation unnecessarily.
- bool valid_string_in_modifier_encoding = true;
-
- if (!valid_string_in_modifier_encoding) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
- }
- } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- // TODO (nirvdrum 21-Feb-2024): There's currently no way to tell if the source used hex or Unicode character escapes from `explicit_encoding` alone. If the source encoding was already UTF-8, both character escape types would set `explicit_encoding` to UTF-8, but need to be processed differently. Skip for now.
- if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, (int) pm_string_length(source), (const char *) pm_string_source(source));
- }
- }
-
- // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
- return flags;
-}
-
-/**
- * Ruby "downgrades" the encoding of Regexps to US-ASCII if the associated encoding is ASCII-compatible and
- * the unescaped representation of a Regexp source consists only of US-ASCII code points. This is true even
- * when the Regexp is explicitly given an ASCII-8BIT encoding via the (/n) modifier. Otherwise, the encoding
- * may be explicitly set with an escape sequence.
- */
-static pm_node_flags_t
-parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
- // TODO (nirvdrum 22-Feb-2024): CRuby reports a special Regexp-specific error for invalid Unicode ranges. We either need to scan again or modify the "invalid Unicode escape sequence" message we already report.
- bool valid_unicode_range = true;
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, (int) pm_string_length(source), (const char *) pm_string_source(source));
- return flags;
- }
-
- // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
- // to multi-byte characters are allowed.
- if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
- // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
- // following error message appearing twice. We do the same for compatibility.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
- }
-
- /**
- * Start checking modifier flags. We need to process these before considering any explicit encodings that may have
- * been set by character literals. The order in which the encoding modifiers is checked does not matter. In the
- * event that both an encoding modifier and an explicit encoding would result in the same encoding we do not set
- * the corresponding "forced_<encoding>" flag. Instead, the caller should check the encoding modifier flag and
- * determine the encoding that way.
- */
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
- }
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
- }
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
- }
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
- }
-
- // At this point no encoding modifiers will be present on the regular expression as they would have already
- // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
- // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
- if (ascii_only) {
- return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
- }
-
- // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
- // or by specifying a modifier.
- //
- // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
- if (parser->explicit_encoding != NULL) {
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
- } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
- }
- }
-
- return 0;
-}
-
/**
* 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_node_flags_t flags) {
- pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
-
- *node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
+ uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
+
+ return pm_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL | flags,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ NTOK2LOC(parser, opening),
+ NTOK2LOC(parser, value),
+ NTOK2LOC(parser, closing),
+ *unescaped
+ );
}
/**
* Allocate and initialize a new SymbolNode node.
*/
-static inline pm_symbol_node_t *
+static PRISM_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, 0);
}
@@ -7391,35 +6763,15 @@ pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *open
*/
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 };
+ assert(token->type == PM_TOKEN_LABEL);
- pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
- node = pm_symbol_node_create(parser, &opening, &label, &closing);
+ 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 };
+ pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
- assert((label.end - label.start) >= 0);
- pm_string_shared_init(&node->unescaped, label.start, label.end);
- pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
-
- 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;
- }
+ assert((label.end - label.start) >= 0);
+ pm_string_shared_init(&node->unescaped, label.start, label.end);
+ pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
return node;
}
@@ -7429,18 +6781,16 @@ pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
*/
static pm_symbol_node_t *
pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
- pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
-
- *node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .value_loc = PM_LOCATION_NULL_VALUE(parser),
- .unescaped = { 0 }
- };
+ pm_symbol_node_t *node = pm_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_string_t) { 0 })
+ );
pm_string_constant_init(&node->unescaped, content, strlen(content));
return node;
@@ -7450,21 +6800,29 @@ pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
* 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;
+pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
+ const pm_location_t *location = NULL;
switch (PM_NODE_TYPE(node)) {
- case PM_SYMBOL_NODE:
- end = ((pm_symbol_node_t *) node)->closing_loc.end;
+ case PM_SYMBOL_NODE: {
+ const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
+ if (cast->closing_loc.length > 0) {
+ location = &cast->closing_loc;
+ }
break;
- case PM_INTERPOLATED_SYMBOL_NODE:
- end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
+ }
+ case PM_INTERPOLATED_SYMBOL_NODE: {
+ const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
+ if (cast->closing_loc.length > 0) {
+ location = &cast->closing_loc;
+ }
break;
+ }
default:
return false;
}
- return (end != NULL) && (end[-1] == ':');
+ return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
}
/**
@@ -7472,32 +6830,26 @@ pm_symbol_node_label_p(pm_node_t *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_NODE_ALLOC(parser, pm_symbol_node_t);
+ pm_symbol_node_t *new_node = pm_symbol_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ node->content_loc,
+ TOK2LOC(parser, closing),
+ node->unescaped
+ );
- *new_node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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
+ pm_token_t content = {
+ .type = PM_TOKEN_IDENTIFIER,
+ .start = parser->start + node->content_loc.start,
+ .end = parser->start + node->content_loc.start + node->content_loc.length
};
- pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
- pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
-
- // 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.
- xfree(node);
+ pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
+ /* The old node is arena-allocated so no explicit free is needed. */
return new_node;
}
@@ -7506,7 +6858,6 @@ pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const
*/
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_NODE_ALLOC(parser, pm_string_node_t);
pm_node_flags_t flags = 0;
switch (parser->frozen_string_literal) {
@@ -7518,24 +6869,18 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
break;
}
- *new_node = (pm_string_node_t) {
- {
- .type = PM_STRING_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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.
- xfree(node);
+ pm_string_node_t *new_node = pm_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_NODE(node),
+ node->opening_loc,
+ node->value_loc,
+ node->closing_loc,
+ node->unescaped
+ );
+ /* The old node is arena-allocated so no explicit free is needed. */
return new_node;
}
@@ -7545,16 +6890,13 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *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_NODE_ALLOC(parser, pm_true_node_t);
-
- *node = (pm_true_node_t) {{
- .type = PM_TRUE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
- return node;
+ return pm_true_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_TOKEN(parser, token)
+ );
}
/**
@@ -7562,16 +6904,12 @@ pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
*/
static pm_true_node_t *
pm_true_node_synthesized_create(pm_parser_t *parser) {
- pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
-
- *node = (pm_true_node_t) {{
- .type = PM_TRUE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = parser->start, .end = parser->end }
- }};
-
- return node;
+ return pm_true_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_STATIC_LITERAL,
+ PM_LOCATION_INIT_UNSET
+ );
}
/**
@@ -7580,28 +6918,24 @@ pm_true_node_synthesized_create(pm_parser_t *parser) {
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_NODE_ALLOC(parser, pm_undef_node_t);
-
- *node = (pm_undef_node_t) {
- {
- .type = PM_UNDEF_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token),
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
- .names = { 0 }
- };
- return node;
+ return pm_undef_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, token),
+ ((pm_node_list_t) { 0 }),
+ TOK2LOC(parser, token)
+ );
}
/**
* 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);
+pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
+ PM_NODE_LENGTH_SET_NODE(node, name);
+ pm_node_list_append(arena, &node->names, name);
}
/**
@@ -7610,34 +6944,20 @@ pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
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(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_unless_node_t *node = PM_NODE_ALLOC(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,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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,
- .else_clause = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
+ pm_node_t *end = statements == NULL ? predicate : UP(statements);
+
+ return pm_unless_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
+ TOK2LOC(parser, keyword),
+ predicate,
+ NTOK2LOC(parser, then_keyword),
+ statements,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
/**
@@ -7646,36 +6966,28 @@ pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t
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(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, statements, statement, true);
- *node = (pm_unless_node_t) {
- {
- .type = PM_UNLESS_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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,
- .else_clause = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
+ return pm_unless_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_NODE_FLAG_NEWLINE,
+ PM_LOCATION_INIT_NODES(statement, predicate),
+ TOK2LOC(parser, unless_keyword),
+ predicate,
+ ((pm_location_t) { 0 }),
+ statements,
+ NULL,
+ ((pm_location_t) { 0 })
+ );
}
-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;
+static PRISM_INLINE void
+pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
+ node->end_keyword_loc = TOK2LOC(parser, end_keyword);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
}
/**
@@ -7690,7 +7002,7 @@ pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statemen
// All of the block exits that we want to remove should be within the
// statements, and since we are modifying the statements, we shouldn't have
// to check the end location.
- const uint8_t *start = statements->base.location.start;
+ uint32_t start = statements->base.location.start;
for (size_t index = parser->current_block_exits->size; index > 0; index--) {
pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
@@ -7706,27 +7018,19 @@ pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statemen
*/
static pm_until_node_t *
pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_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_NODE_ALLOC(parser, pm_until_node_t);
pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- *node = (pm_until_node_t) {
- {
- .type = PM_UNTIL_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = closing->end,
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_until_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ TOK2LOC(parser, keyword),
+ NTOK2LOC(parser, do_keyword),
+ TOK2LOC(parser, closing),
+ predicate,
+ statements
+ );
}
/**
@@ -7734,28 +7038,20 @@ pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_to
*/
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_NODE_ALLOC(parser, pm_until_node_t);
pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
pm_loop_modifier_block_exits(parser, statements);
- *node = (pm_until_node_t) {
- {
- .type = PM_UNTIL_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statements->base.location.start,
- .end = predicate->location.end,
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_until_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_NODES(statements, predicate),
+ TOK2LOC(parser, keyword),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ predicate,
+ statements
+ );
}
/**
@@ -7763,42 +7059,34 @@ pm_until_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm
*/
static pm_when_node_t *
pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
- pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
-
- *node = (pm_when_node_t) {
- {
- .type = PM_WHEN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = NULL
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .statements = NULL,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .conditions = { 0 }
- };
-
- return node;
+ return pm_when_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_TOKEN(parser, keyword),
+ TOK2LOC(parser, keyword),
+ ((pm_node_list_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ NULL
+ );
}
/**
* 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);
+pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
+ PM_NODE_LENGTH_SET_NODE(node, condition);
+ pm_node_list_append(arena, &node->conditions, condition);
}
/**
* Set the location of the then keyword of a when node.
*/
-static inline void
-pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
- node->base.location.end = then_keyword->end;
- node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
+static PRISM_INLINE void
+pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
+ node->then_keyword_loc = TOK2LOC(parser, then_keyword);
}
/**
@@ -7806,8 +7094,8 @@ pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_k
*/
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;
+ if (PM_NODE_END(statements) > PM_NODE_END(node)) {
+ PM_NODE_LENGTH_SET_NODE(node, statements);
}
node->statements = statements;
@@ -7818,27 +7106,19 @@ pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statemen
*/
static pm_while_node_t *
pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_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_NODE_ALLOC(parser, pm_while_node_t);
pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = closing->end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_while_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
+ TOK2LOC(parser, keyword),
+ NTOK2LOC(parser, do_keyword),
+ TOK2LOC(parser, closing),
+ predicate,
+ statements
+ );
}
/**
@@ -7846,28 +7126,20 @@ pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_to
*/
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_NODE_ALLOC(parser, pm_while_node_t);
pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
pm_loop_modifier_block_exits(parser, statements);
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statements->base.location.start,
- .end = predicate->location.end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_while_node_new(
+ parser->arena,
+ ++parser->node_id,
+ flags,
+ PM_LOCATION_INIT_NODES(statements, predicate),
+ TOK2LOC(parser, keyword),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ predicate,
+ statements
+ );
}
/**
@@ -7875,22 +7147,17 @@ pm_while_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm
*/
static pm_while_node_t *
pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
- pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
-
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
- .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
- .closing_loc = PM_LOCATION_NULL_VALUE(parser),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
+ return pm_while_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ PM_LOCATION_INIT_UNSET,
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ ((pm_location_t) { 0 }),
+ predicate,
+ statements
+ );
}
/**
@@ -7899,31 +7166,22 @@ pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_s
*/
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_NODE_ALLOC(parser, pm_x_string_node_t);
-
- *node = (pm_x_string_node_t) {
- {
- .type = PM_X_STRING_NODE,
- .flags = PM_STRING_FLAGS_FROZEN,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ return pm_x_string_node_new(
+ parser->arena,
+ ++parser->node_id,
+ PM_STRING_FLAGS_FROZEN,
+ PM_LOCATION_INIT_TOKENS(parser, opening, closing),
+ TOK2LOC(parser, opening),
+ TOK2LOC(parser, content),
+ TOK2LOC(parser, closing),
+ *unescaped
+ );
}
/**
* Allocate and initialize a new XStringNode node.
*/
-static inline pm_x_string_node_t *
+static PRISM_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);
}
@@ -7933,40 +7191,31 @@ pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_
*/
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_NODE_ALLOC(parser, pm_yield_node_t);
+ uint32_t start = PM_TOKEN_START(parser, keyword);
+ uint32_t end;
- const uint8_t *end;
- if (rparen_loc->start != NULL) {
- end = rparen_loc->end;
+ if (rparen_loc->length > 0) {
+ end = PM_LOCATION_END(rparen_loc);
} else if (arguments != NULL) {
- end = arguments->base.location.end;
- } else if (lparen_loc->start != NULL) {
- end = lparen_loc->end;
+ end = PM_NODE_END(arguments);
+ } else if (lparen_loc->length > 0) {
+ end = PM_LOCATION_END(lparen_loc);
} else {
- end = keyword->end;
- }
-
- *node = (pm_yield_node_t) {
- {
- .type = PM_YIELD_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .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;
+ end = PM_TOKEN_END(parser, keyword);
+ }
+
+ return pm_yield_node_new(
+ parser->arena,
+ ++parser->node_id,
+ 0,
+ ((pm_location_t) { .start = start, .length = U32(end - start) }),
+ TOK2LOC(parser, keyword),
+ *lparen_loc,
+ arguments,
+ *rparen_loc
+ );
}
-#undef PM_NODE_ALLOC
-#undef PM_NODE_IDENTIFY
-
/**
* Check if any of the currently visible scopes contain a local variable
* described by the given constant id.
@@ -7992,7 +7241,7 @@ pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant
* described by the given token. This function implicitly inserts a constant
* into the constant pool.
*/
-static inline int
+static PRISM_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));
}
@@ -8000,27 +7249,35 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
/**
* Add a constant id to the local table of the current scope.
*/
-static inline void
+static PRISM_INLINE void
pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
- pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
+ pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
}
/**
* 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, uint32_t reads) {
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
+pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
+ pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
return constant_id;
}
/**
+ * Add a local variable from a location to the current scope.
+ */
+static PRISM_INLINE pm_constant_id_t
+pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
+ return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
+}
+
+/**
* Add a local variable from a token to the current scope.
*/
-static inline pm_constant_id_t
+static PRISM_INLINE pm_constant_id_t
pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
- return pm_parser_local_add_location(parser, token->start, token->end, reads);
+ return pm_parser_local_add_raw(parser, token->start, token->end, reads);
}
/**
@@ -8054,7 +7311,7 @@ static bool
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);
+ pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
// Otherwise we'll fetch the constant id for the parameter name and check
// whether it's already in the current scope.
@@ -8078,8 +7335,7 @@ pm_parser_scope_pop(pm_parser_t *parser) {
pm_scope_t *scope = parser->current_scope;
parser->current_scope = scope->previous;
pm_locals_free(&scope->locals);
- pm_node_list_free(&scope->implicit_parameters);
- xfree(scope);
+ xfree_sized(scope, sizeof(pm_scope_t));
}
/******************************************************************************/
@@ -8089,7 +7345,7 @@ pm_parser_scope_pop(pm_parser_t *parser) {
/**
* Pushes a value onto the stack.
*/
-static inline void
+static PRISM_INLINE void
pm_state_stack_push(pm_state_stack_t *stack, bool value) {
*stack = (*stack << 1) | (value & 1);
}
@@ -8097,7 +7353,7 @@ pm_state_stack_push(pm_state_stack_t *stack, bool value) {
/**
* Pops a value off the stack.
*/
-static inline void
+static PRISM_INLINE void
pm_state_stack_pop(pm_state_stack_t *stack) {
*stack >>= 1;
}
@@ -8105,38 +7361,38 @@ pm_state_stack_pop(pm_state_stack_t *stack) {
/**
* Returns the value at the top of the stack.
*/
-static inline bool
+static PRISM_INLINE bool
pm_state_stack_p(const pm_state_stack_t *stack) {
return *stack & 1;
}
-static inline void
+static PRISM_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
+static PRISM_INLINE void
pm_accepts_block_stack_pop(pm_parser_t *parser) {
pm_state_stack_pop(&parser->accepts_block_stack);
}
-static inline bool
+static PRISM_INLINE bool
pm_accepts_block_stack_p(pm_parser_t *parser) {
return !pm_state_stack_p(&parser->accepts_block_stack);
}
-static inline void
+static PRISM_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
+static PRISM_INLINE void
pm_do_loop_stack_pop(pm_parser_t *parser) {
pm_state_stack_pop(&parser->do_loop_stack);
}
-static inline bool
+static PRISM_INLINE bool
pm_do_loop_stack_p(pm_parser_t *parser) {
return pm_state_stack_p(&parser->do_loop_stack);
}
@@ -8149,7 +7405,7 @@ pm_do_loop_stack_p(pm_parser_t *parser) {
* 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
+static PRISM_INLINE uint8_t
peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
if (cursor < parser->end) {
return *cursor;
@@ -8163,7 +7419,7 @@ peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
* adding the given offset. If that position is beyond the end of the source
* then return '\0'.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
return peek_at(parser, parser->current.end + offset);
}
@@ -8172,7 +7428,7 @@ peek_offset(pm_parser_t *parser, ptrdiff_t 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
+static PRISM_INLINE uint8_t
peek(const pm_parser_t *parser) {
return peek_at(parser, parser->current.end);
}
@@ -8181,7 +7437,7 @@ peek(const pm_parser_t *parser) {
* If the character to be read matches the given value, then returns true and
* advances the current pointer.
*/
-static inline bool
+static PRISM_INLINE bool
match(pm_parser_t *parser, uint8_t value) {
if (peek(parser) == value) {
parser->current.end++;
@@ -8194,7 +7450,7 @@ match(pm_parser_t *parser, uint8_t value) {
* 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
+static PRISM_INLINE size_t
match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
if (peek_at(parser, cursor) == '\n') {
return 1;
@@ -8210,7 +7466,7 @@ match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
* `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
+static PRISM_INLINE size_t
match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
return match_eol_at(parser, parser->current.end + offset);
}
@@ -8220,7 +7476,7 @@ match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
* or 0 if it is not a line ending. This function is intended to be CRLF/LF
* agnostic.
*/
-static inline size_t
+static PRISM_INLINE size_t
match_eol(pm_parser_t *parser) {
return match_eol_at(parser, parser->current.end);
}
@@ -8228,7 +7484,7 @@ match_eol(pm_parser_t *parser) {
/**
* Skip to the next newline character or NUL byte.
*/
-static inline const uint8_t *
+static PRISM_INLINE const uint8_t *
next_newline(const uint8_t *cursor, ptrdiff_t length) {
assert(length >= 0);
@@ -8241,7 +7497,7 @@ next_newline(const uint8_t *cursor, ptrdiff_t length) {
/**
* This is equivalent to the predicate of warn_balanced in CRuby.
*/
-static inline bool
+static PRISM_INLINE bool
ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
return !lex_state_p(parser, PM_LEX_STATE_CLASS | PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME | PM_LEX_STATE_ENDFN) && space_seen && !pm_char_is_whitespace(peek(parser));
}
@@ -8319,7 +7575,7 @@ parser_lex_magic_comment_encoding(pm_parser_t *parser) {
// 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);
+ pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
}
}
@@ -8344,7 +7600,7 @@ parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t valu
}
}
-static inline bool
+static PRISM_INLINE bool
pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
return b == '\'' || b == '"' || b == ':' || b == ';';
}
@@ -8354,13 +7610,15 @@ pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
* found, it returns a pointer to the start of the marker. Otherwise it returns
* NULL.
*/
-static inline const uint8_t *
+static PRISM_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;
+ // Scan for '*' as the middle character, since it is rarer than '-' in
+ // typical comments and avoids repeated memchr calls for '-' that hit
+ // dashes in words like "foo-bar".
+ while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1, '*', (size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
+ if (cursor[-1] == '-' && cursor + 1 < end && cursor[1] == '-') {
+ return cursor - 1;
}
- cursor++;
}
return NULL;
}
@@ -8375,7 +7633,7 @@ parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor
* It returns true if it consumes the entire comment. Otherwise it returns
* false.
*/
-static inline bool
+static PRISM_INLINE bool
parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
bool result = true;
@@ -8397,11 +7655,24 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
// have a magic comment.
return false;
}
+ } else {
+ // Non-emacs magic comments must contain a colon for `key: value`.
+ // Reject early if there is no colon to avoid scanning the entire
+ // comment character-by-character.
+ if (pm_memchr(start, ':', (size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
+ return false;
+ }
+
+ // Advance start past leading whitespace so the main loop begins
+ // directly at the key, avoiding a redundant whitespace scan.
+ start += pm_strspn_whitespace(start, end - start);
}
cursor = start;
while (cursor < end) {
- while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
+ if (indicator) {
+ 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++;
@@ -8429,7 +7700,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
if (*cursor == '\\' && (cursor + 1 < end)) cursor++;
}
value_end = cursor;
- if (*cursor == '"') cursor++;
+ if (cursor < end && *cursor == '"') cursor++;
} else {
value_start = cursor;
while (cursor < end && *cursor != '"' && *cursor != ';' && !pm_char_is_whitespace(*cursor)) cursor++;
@@ -8487,7 +7758,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
(int) key_length,
(const char *) key_source,
@@ -8514,7 +7785,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
(int) key_length,
(const char *) key_source,
@@ -8549,7 +7820,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
} else {
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
(int) key_length,
(const char *) key_source,
@@ -8562,17 +7833,14 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
// When we're done, we want to free the string in case we had to
// allocate memory for it.
- pm_string_free(&key);
+ pm_string_cleanup(&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 *) xcalloc(1, sizeof(pm_magic_comment_t))) != 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 = value_length;
- pm_list_append(&parser->magic_comment_list, (pm_list_node_t *) magic_comment);
- }
+ pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_magic_comment_t), PRISM_ALIGNOF(pm_magic_comment_t));
+ magic_comment->node.next = NULL;
+ magic_comment->key = (pm_location_t) { .start = U32(key_start - parser->start), .length = U32(key_length) };
+ magic_comment->value = (pm_location_t) { .start = U32(value_start - parser->start), .length = value_length };
+ pm_list_append(&parser->magic_comment_list, (pm_list_node_t *) magic_comment);
}
return result;
@@ -8582,85 +7850,67 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
/* 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:
- case PM_CONTEXT_DEFINED:
- case PM_CONTEXT_MULTI_TARGET:
- case PM_CONTEXT_TERNARY:
- case PM_CONTEXT_RESCUE_MODIFIER:
- 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_BEGIN_ENSURE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_SCLASS_ENSURE:
- return token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_LOOP_PREDICATE:
- return token->type == PM_TOKEN_KEYWORD_DO || token->type == PM_TOKEN_KEYWORD_THEN;
- 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_BEGIN_RESCUE:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_SCLASS_RESCUE:
- return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_DEF_ELSE:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_SCLASS_ELSE:
- return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_LAMBDA_BRACES:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_PREDICATE:
- return token->type == PM_TOKEN_KEYWORD_THEN || token->type == PM_TOKEN_NEWLINE || token->type == PM_TOKEN_SEMICOLON;
- case PM_CONTEXT_NONE:
- return false;
- }
+static const uint32_t context_terminators[] = {
+ [PM_CONTEXT_NONE] = 0,
+ [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
+ [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
+ [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
+ [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
+ [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
+ [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
+ [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
+ [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
+ [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
+ [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
+ [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
+ [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
+ [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
+ [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
+};
- return false;
+static PRISM_INLINE bool
+context_terminator(pm_context_t context, pm_token_t *token) {
+ return token->type < 32 && (context_terminators[context] & (1U << token->type));
}
/**
@@ -8699,7 +7949,7 @@ context_push(pm_parser_t *parser, pm_context_t context) {
static void
context_pop(pm_parser_t *parser) {
pm_context_node_t *prev = parser->current_context->prev;
- xfree(parser->current_context);
+ xfree_sized(parser->current_context, sizeof(pm_context_node_t));
parser->current_context = prev;
}
@@ -8761,6 +8011,7 @@ context_human(pm_context_t context) {
case PM_CONTEXT_BEGIN: return "begin statement";
case PM_CONTEXT_BLOCK_BRACES: return "'{'..'}' block";
case PM_CONTEXT_BLOCK_KEYWORDS: return "'do'..'end' block";
+ case PM_CONTEXT_BLOCK_PARAMETERS: return "'|'..'|' block parameter";
case PM_CONTEXT_CASE_WHEN: return "'when' clause";
case PM_CONTEXT_CASE_IN: return "'in' clause";
case PM_CONTEXT_CLASS: return "class definition";
@@ -8821,11 +8072,11 @@ context_human(pm_context_t context) {
/* Specific token lexers */
/******************************************************************************/
-static inline void
+static PRISM_INLINE void
pm_strspn_number_validate(pm_parser_t *parser, const uint8_t *string, size_t length, const uint8_t *invalid) {
if (invalid != NULL) {
pm_diagnostic_id_t diag_id = (invalid == (string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
- pm_parser_err(parser, invalid, invalid + 1, diag_id);
+ pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
}
}
@@ -8936,7 +8187,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
}
- parser->integer_base = PM_INTEGER_BASE_FLAGS_BINARY;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
break;
// 0o1111 is an octal number
@@ -8950,7 +8201,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
}
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
break;
// 01111 is an octal number
@@ -8964,7 +8215,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
case '6':
case '7':
parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
break;
// 0x1111 is a hexadecimal number
@@ -8978,7 +8229,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
}
- parser->integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
break;
// 0.xxx is a float
@@ -8996,11 +8247,62 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
}
} 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);
+ // decimal number. We compute the integer value inline to avoid
+ // re-scanning the digits later in pm_integer_parse.
+ {
+ const uint8_t *cursor = parser->current.end;
+ const uint8_t *end = parser->end;
+ uint64_t value = (uint64_t) (cursor[-1] - '0');
+
+ bool has_underscore = false;
+ bool prev_underscore = false;
+ const uint8_t *invalid = NULL;
+
+ while (cursor < end) {
+ uint8_t c = *cursor;
+ if (c >= '0' && c <= '9') {
+ if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c - '0');
+ prev_underscore = false;
+ cursor++;
+ } else if (c == '_') {
+ has_underscore = true;
+ if (prev_underscore && invalid == NULL) invalid = cursor;
+ prev_underscore = true;
+ cursor++;
+ } else {
+ break;
+ }
+ }
+
+ if (has_underscore) {
+ if (prev_underscore && invalid == NULL) invalid = cursor - 1;
+ pm_strspn_number_validate(parser, parser->current.end, (size_t) (cursor - parser->current.end), invalid);
+ }
+
+ if (value <= UINT32_MAX) {
+ parser->integer.value = (uint32_t) value;
+ parser->integer.lexed = true;
+ }
+
+ parser->current.end = cursor;
+ }
// Afterward, we'll lex as far as we can into an optional float suffix.
- type = lex_optional_float_suffix(parser, seen_e);
+ // Guard the function call: the vast majority of decimal numbers are
+ // plain integers, so avoid the call when the next byte cannot start a
+ // float suffix.
+ {
+ uint8_t next = peek(parser);
+ if (next == '.' || next == 'e' || next == 'E') {
+ type = lex_optional_float_suffix(parser, seen_e);
+
+ // If it turned out to be a float, the cached integer value is
+ // invalid.
+ if (type != PM_TOKEN_INTEGER) {
+ parser->integer.lexed = false;
+ }
+ }
+ }
}
// At this point we have a completed number, but we want to provide the user
@@ -9010,7 +8312,7 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
const uint8_t *fraction_start = parser->current.end;
const uint8_t *fraction_end = parser->current.end + 2;
fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
- pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
+ pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
}
return type;
@@ -9019,7 +8321,8 @@ lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
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;
+ parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
+ parser->integer.lexed = false;
if (parser->current.end < parser->end) {
bool seen_e = false;
@@ -9109,8 +8412,8 @@ lex_global_variable(pm_parser_t *parser) {
} while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
// $0 isn't allowed to be followed by anything.
- pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, diag_id);
+ pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
}
return PM_TOKEN_GLOBAL_VARIABLE;
@@ -9146,9 +8449,9 @@ lex_global_variable(pm_parser_t *parser) {
} else {
// If we get here, then we have a $ followed by something that
// isn't recognized as a global variable.
- pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
- const uint8_t *end = parser->current.end + parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- PM_PARSER_ERR_FORMAT(parser, parser->current.start, end, diag_id, (int) (end - parser->current.start), (const char *) parser->current.start);
+ pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
+ size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
+ PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), diag_id, (int) (PM_TOKEN_LENGTH(&parser->current) + U32(width)), (const char *) parser->current.start);
}
return PM_TOKEN_GLOBAL_VARIABLE;
@@ -9168,7 +8471,7 @@ lex_global_variable(pm_parser_t *parser) {
* * `type` - the expected token type
* * `modifier_type` - the expected modifier token type
*/
-static inline pm_token_type_t
+static PRISM_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;
@@ -9207,6 +8510,10 @@ lex_identifier(pm_parser_t *parser, bool previous_command_start) {
current_end += width;
}
} else {
+ // Fast path: scan ASCII identifier bytes using wide operations.
+ current_end += scan_identifier_ascii(current_end, end);
+
+ // Byte-at-a-time fallback for the tail and any UTF-8 sequences.
while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
current_end += width;
}
@@ -9266,9 +8573,15 @@ lex_identifier(pm_parser_t *parser, bool previous_command_start) {
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 (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
+ return PM_TOKEN_KEYWORD_DO;
+ }
if (pm_do_loop_stack_p(parser)) {
return PM_TOKEN_KEYWORD_DO_LOOP;
}
+ if (!pm_accepts_block_stack_p(parser)) {
+ return PM_TOKEN_KEYWORD_DO_BLOCK;
+ }
return PM_TOKEN_KEYWORD_DO;
}
@@ -9347,8 +8660,8 @@ current_token_starts_line(pm_parser_t *parser) {
* 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.
+ * * 0 - 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
@@ -9365,9 +8678,9 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
return PM_TOKEN_STRING_CONTENT;
}
- // Now we'll check against the character that follows the #. If it constitutes
- // valid interplation, we'll handle that, otherwise we'll return
- // PM_TOKEN_NOT_PROVIDED.
+ // Now we'll check against the character that follows the #. If it
+ // constitutes valid interplation, we'll handle that, otherwise we'll return
+ // 0.
switch (pound[1]) {
case '@': {
// In this case we may have hit an embedded instance or class variable.
@@ -9401,7 +8714,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
// 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;
+ return 0;
}
case '$':
// In this case we may have hit an embedded global variable. If there's
@@ -9451,7 +8764,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
// 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;
+ return 0;
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
@@ -9475,7 +8788,7 @@ lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
// 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;
+ return 0;
}
}
@@ -9499,7 +8812,7 @@ static const bool ascii_printable_chars[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
};
-static inline bool
+static PRISM_INLINE bool
char_is_ascii_printable(const uint8_t b) {
return (b < 0x80) && ascii_printable_chars[b];
}
@@ -9508,7 +8821,7 @@ char_is_ascii_printable(const uint8_t b) {
* Return the value that a hexadecimal digit character represents. For example,
* transform 'a' into 10, 'b' into 11, etc.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
escape_hexadecimal_digit(const uint8_t value) {
return (uint8_t) ((value <= '9') ? (value - '0') : (value & 0x7) + 9);
}
@@ -9518,8 +8831,8 @@ escape_hexadecimal_digit(const uint8_t value) {
* digits scanned. This function assumes that the characters have already been
* validated.
*/
-static inline uint32_t
-escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
+static PRISM_INLINE uint32_t
+escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length, const pm_location_t *error_location, const uint8_t flags) {
uint32_t value = 0;
for (size_t index = 0; index < length; index++) {
if (index != 0) value <<= 4;
@@ -9529,7 +8842,14 @@ escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
// Here we're going to verify that the value is actually a valid Unicode
// codepoint and not a surrogate pair.
if (value >= 0xD800 && value <= 0xDFFF) {
- pm_parser_err(parser, string, string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, defer the error to regexp encoding
+ // validation where we can produce a regexp-specific message.
+ } else if (error_location != NULL) {
+ pm_parser_err(parser, error_location->start, error_location->length, PM_ERR_ESCAPE_INVALID_UNICODE);
+ } else {
+ pm_parser_err(parser, U32(string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
+ }
return 0xFFFD;
}
@@ -9539,7 +8859,7 @@ escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
/**
* Escape a single character value based on the given flags.
*/
-static inline uint8_t
+static PRISM_INLINE uint8_t
escape_byte(uint8_t value, const uint8_t flags) {
if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
@@ -9549,21 +8869,32 @@ escape_byte(uint8_t value, const uint8_t flags) {
/**
* Write a unicode codepoint to the given buffer.
*/
-static inline void
+static PRISM_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);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, suppress this error — the regexp encoding
+ // validation will produce a more specific error message.
+ } else {
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
+ }
}
parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
}
if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
- pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, defer the error to the regexp encoding
+ // validation which produces a regexp-specific message.
+ } else {
+ pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
+ }
+
pm_buffer_append_byte(buffer, 0xEF);
pm_buffer_append_byte(buffer, 0xBF);
pm_buffer_append_byte(buffer, 0xBD);
@@ -9574,11 +8905,16 @@ escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t fla
* 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) {
+static PRISM_INLINE void
+escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t flags, 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);
+ if (flags & PM_ESCAPE_FLAG_REGEXP) {
+ // In regexp context, suppress this error — the regexp encoding
+ // validation will produce a more specific error message.
+ } else {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
+ }
}
parser->explicit_encoding = parser->encoding;
@@ -9602,19 +8938,19 @@ escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t byte
* 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
+static PRISM_INLINE void
escape_write_byte(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags, uint8_t byte) {
if (flags & PM_ESCAPE_FLAG_REGEXP) {
pm_buffer_append_format(regular_expression_buffer, "\\x%02X", byte);
}
- escape_write_byte_encoded(parser, buffer, byte);
+ escape_write_byte_encoded(parser, buffer, flags, byte);
}
/**
* Write each byte of the given escaped character into the buffer.
*/
-static inline void
+static PRISM_INLINE void
escape_write_escape_encoded(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags) {
size_t width;
if (parser->encoding_changed) {
@@ -9624,6 +8960,7 @@ escape_write_escape_encoded(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_
}
if (width == 1) {
+ if (*parser->current.end == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
} else if (width > 1) {
// Valid multibyte character. Just ignore escape.
@@ -9649,7 +8986,7 @@ escape_read_warn(pm_parser_t *parser, uint8_t flags, uint8_t flag, const char *t
PM_PARSER_WARN_TOKEN_FORMAT(
parser,
- parser->current,
+ &parser->current,
PM_WARN_INVALID_CHARACTER,
FLAG(flags),
FLAG(flag),
@@ -9764,7 +9101,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
}
}
- escape_write_byte_encoded(parser, buffer, value);
+ escape_write_byte_encoded(parser, buffer, flags, value);
} else {
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
}
@@ -9777,7 +9114,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
if (parser->current.end == parser->end) {
const uint8_t *start = parser->current.end - 2;
- PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
} else if (peek(parser) == '{') {
const uint8_t *unicode_codepoints_start = parser->current.end - 2;
parser->current.end++;
@@ -9806,18 +9143,19 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
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);
+ pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
} else if (hexadecimal_length == 0) {
// there are not hexadecimal characters
if (flags & PM_ESCAPE_FLAG_REGEXP) {
// If this is a regular expression, we are going to
// let the regular expression engine handle this
- // error instead of us.
+ // error instead of us because we don't know at this
+ // point if we're inside a comment in /x mode.
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
} else {
- pm_parser_err(parser, parser->current.end, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
- pm_parser_err(parser, parser->current.end, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
+ pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
+ pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
}
return;
@@ -9829,7 +9167,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
extra_codepoints_start = unicode_start;
}
- uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
+ uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
@@ -9838,21 +9176,22 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
// ?\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);
+ pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
}
if (parser->current.end == parser->end) {
- PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (parser->current.end - start), start);
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (parser->current.end - start), start);
} else if (peek(parser) == '}') {
parser->current.end++;
} else {
if (flags & PM_ESCAPE_FLAG_REGEXP) {
// If this is a regular expression, we are going to let
// the regular expression engine handle this error
- // instead of us.
+ // instead of us because we don't know at this point if
+ // we're inside a comment in /x mode.
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
} else {
- pm_parser_err(parser, unicode_codepoints_start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
+ pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
}
}
@@ -9867,10 +9206,10 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
} else {
const uint8_t *start = parser->current.end - 2;
- PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
+ PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
}
} else if (length == 4) {
- uint32_t value = escape_unicode(parser, parser->current.end, 4);
+ uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
if (flags & PM_ESCAPE_FLAG_REGEXP) {
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
@@ -9916,7 +9255,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
parser->current.end++;
if (match(parser, 'u') || match(parser, 'U')) {
- pm_parser_err(parser, parser->current.start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
return;
}
@@ -9938,6 +9277,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
return;
}
+ if (peeked == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
parser->current.end++;
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
return;
@@ -9952,7 +9292,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
if (peek(parser) != '-') {
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
return;
}
@@ -9973,7 +9313,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
parser->current.end++;
if (match(parser, 'u') || match(parser, 'U')) {
- pm_parser_err(parser, parser->current.start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
return;
}
@@ -9992,10 +9332,11 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
default: {
if (!char_is_ascii_printable(peeked)) {
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
return;
}
+ if (peeked == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
parser->current.end++;
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
return;
@@ -10010,7 +9351,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
if (peek(parser) != '-') {
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
return;
}
@@ -10026,7 +9367,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
parser->current.end++;
if (match(parser, 'u') || match(parser, 'U')) {
- pm_parser_err(parser, parser->current.start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
return;
}
@@ -10045,10 +9386,11 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
default:
if (!char_is_ascii_printable(peeked)) {
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
return;
}
+ if (peeked == '\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
parser->current.end++;
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
return;
@@ -10056,8 +9398,9 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
}
case '\r': {
if (peek_offset(parser, 1) == '\n') {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
parser->current.end += 2;
- escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
+ escape_write_byte_encoded(parser, buffer, flags, escape_byte('\n', flags));
return;
}
PRISM_FALLTHROUGH
@@ -10065,7 +9408,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
default: {
if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
return;
}
if (parser->current.end < parser->end) {
@@ -10127,10 +9470,14 @@ lex_question_mark(pm_parser_t *parser) {
lex_state_set(parser, PM_LEX_STATE_END);
pm_buffer_t buffer;
- pm_buffer_init_capacity(&buffer, 3);
+ pm_buffer_init(&buffer, 3);
escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
- pm_string_owned_init(&parser->current_string, (uint8_t *) buffer.value, buffer.length);
+
+ // Copy buffer data into the arena and free the heap buffer.
+ void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length, PRISM_ALIGNOF(uint8_t));
+ pm_string_constant_init(&parser->current_string, (const char *) arena_data, buffer.length);
+ pm_buffer_cleanup(&buffer);
return PM_TOKEN_CHARACTER_LITERAL;
} else {
@@ -10173,12 +9520,12 @@ lex_at_variable(pm_parser_t *parser) {
}
} else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
- if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3) {
+ if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
}
size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, (int) ((parser->current.end + width) - parser->current.start), (const char *) parser->current.start);
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (int) ((parser->current.end + width) - parser->current.start), (const char *) parser->current.start);
} else {
pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
pm_parser_err_token(parser, &parser->current, diag_id);
@@ -10196,24 +9543,23 @@ lex_at_variable(pm_parser_t *parser) {
/**
* Optionally call out to the lex callback if one is provided.
*/
-static inline void
+static PRISM_INLINE void
parser_lex_callback(pm_parser_t *parser) {
- if (parser->lex_callback) {
- parser->lex_callback->callback(parser->lex_callback->data, parser, &parser->current);
+ if (parser->lex_callback.callback) {
+ parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
}
}
/**
* Return a new comment node of the specified type.
*/
-static inline pm_comment_t *
+static PRISM_INLINE pm_comment_t *
parser_comment(pm_parser_t *parser, pm_comment_type_t type) {
- pm_comment_t *comment = (pm_comment_t *) xcalloc(1, sizeof(pm_comment_t));
- if (comment == NULL) return NULL;
+ pm_comment_t *comment = (pm_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_comment_t), PRISM_ALIGNOF(pm_comment_t));
*comment = (pm_comment_t) {
.type = type,
- .location = { parser->current.start, parser->current.end }
+ .location = TOK2LOC(parser, &parser->current)
};
return comment;
@@ -10232,7 +9578,7 @@ lex_embdoc(pm_parser_t *parser) {
if (newline == NULL) {
parser->current.end = parser->end;
} else {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
parser->current.end = newline + 1;
}
@@ -10240,8 +9586,8 @@ lex_embdoc(pm_parser_t *parser) {
parser_lex_callback(parser);
// Now, create a comment that is going to be attached to the parser.
+ const uint8_t *comment_start = parser->current.start;
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.
@@ -10265,14 +9611,14 @@ lex_embdoc(pm_parser_t *parser) {
if (newline == NULL) {
parser->current.end = parser->end;
} else {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
parser->current.end = newline + 1;
}
parser->current.type = PM_TOKEN_EMBDOC_END;
parser_lex_callback(parser);
- comment->location.end = parser->current.end;
+ comment->location.length = (uint32_t) (parser->current.end - comment_start);
pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
return PM_TOKEN_EMBDOC_END;
@@ -10285,7 +9631,7 @@ lex_embdoc(pm_parser_t *parser) {
if (newline == NULL) {
parser->current.end = parser->end;
} else {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
parser->current.end = newline + 1;
}
@@ -10295,7 +9641,7 @@ lex_embdoc(pm_parser_t *parser) {
pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
- comment->location.end = parser->current.end;
+ comment->location.length = (uint32_t) (parser->current.end - comment_start);
pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
return PM_TOKEN_EOF;
@@ -10306,7 +9652,7 @@ lex_embdoc(pm_parser_t *parser) {
* This happens in a couple places depending on whether or not we have already
* lexed a comment.
*/
-static inline void
+static PRISM_INLINE void
parser_lex_ignored_newline(pm_parser_t *parser) {
parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
parser_lex_callback(parser);
@@ -10321,7 +9667,7 @@ parser_lex_ignored_newline(pm_parser_t *parser) {
* If it is set, then we need to skip past the heredoc body and then clear the
* heredoc_end field.
*/
-static inline void
+static PRISM_INLINE void
parser_flush_heredoc_end(pm_parser_t *parser) {
assert(parser->heredoc_end <= parser->end);
parser->next_start = parser->heredoc_end;
@@ -10397,12 +9743,12 @@ typedef struct {
/**
* Push the given byte into the token buffer.
*/
-static inline void
+static PRISM_INLINE void
pm_token_buffer_push_byte(pm_token_buffer_t *token_buffer, uint8_t byte) {
pm_buffer_append_byte(&token_buffer->buffer, byte);
}
-static inline void
+static PRISM_INLINE void
pm_regexp_token_buffer_push_byte(pm_regexp_token_buffer_t *token_buffer, uint8_t byte) {
pm_buffer_append_byte(&token_buffer->regexp_buffer, byte);
}
@@ -10410,7 +9756,7 @@ pm_regexp_token_buffer_push_byte(pm_regexp_token_buffer_t *token_buffer, uint8_t
/**
* Return the width of the character at the end of the current token.
*/
-static inline size_t
+static PRISM_INLINE size_t
parser_char_width(const pm_parser_t *parser) {
size_t width;
if (parser->encoding_changed) {
@@ -10437,36 +9783,31 @@ pm_token_buffer_push_escaped(pm_token_buffer_t *token_buffer, pm_parser_t *parse
static void
pm_regexp_token_buffer_push_escaped(pm_regexp_token_buffer_t *token_buffer, pm_parser_t *parser) {
size_t width = parser_char_width(parser);
- pm_buffer_append_bytes(&token_buffer->base.buffer, parser->current.end, width);
- pm_buffer_append_bytes(&token_buffer->regexp_buffer, parser->current.end, width);
+ const uint8_t *start = parser->current.end;
+ pm_buffer_append_bytes(&token_buffer->base.buffer, start, width);
+ pm_buffer_append_bytes(&token_buffer->regexp_buffer, start, width);
parser->current.end += width;
}
-static bool
-pm_slice_ascii_only_p(const uint8_t *value, size_t length) {
- for (size_t index = 0; index < length; index++) {
- if (value[index] & 0x80) return false;
- }
-
- return true;
-}
-
/**
* 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
+static PRISM_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 *) pm_buffer_value(&token_buffer->buffer), pm_buffer_length(&token_buffer->buffer));
+ // Copy buffer data into the arena and free the heap buffer.
+ size_t len = pm_buffer_length(&token_buffer->buffer);
+ void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->buffer), len, PRISM_ALIGNOF(uint8_t));
+ pm_string_constant_init(&parser->current_string, (const char *) arena_data, len);
+ pm_buffer_cleanup(&token_buffer->buffer);
}
-static inline void
+static PRISM_INLINE void
pm_regexp_token_buffer_copy(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) {
- pm_string_owned_init(&parser->current_string, (uint8_t *) pm_buffer_value(&token_buffer->base.buffer), pm_buffer_length(&token_buffer->base.buffer));
- parser->current_regular_expression_ascii_only = pm_slice_ascii_only_p((const uint8_t *) pm_buffer_value(&token_buffer->regexp_buffer), pm_buffer_length(&token_buffer->regexp_buffer));
- pm_buffer_free(&token_buffer->regexp_buffer);
+ pm_token_buffer_copy(parser, &token_buffer->base);
+ pm_buffer_cleanup(&token_buffer->regexp_buffer);
}
/**
@@ -10492,10 +9833,11 @@ static void
pm_regexp_token_buffer_flush(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) {
if (token_buffer->base.cursor == NULL) {
pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
- parser->current_regular_expression_ascii_only = pm_slice_ascii_only_p(parser->current.start, (size_t) (parser->current.end - parser->current.start));
} else {
- pm_buffer_append_bytes(&token_buffer->base.buffer, token_buffer->base.cursor, (size_t) (parser->current.end - token_buffer->base.cursor));
- pm_buffer_append_bytes(&token_buffer->regexp_buffer, token_buffer->base.cursor, (size_t) (parser->current.end - token_buffer->base.cursor));
+ const uint8_t *cursor = token_buffer->base.cursor;
+ size_t length = (size_t) (parser->current.end - cursor);
+ pm_buffer_append_bytes(&token_buffer->base.buffer, cursor, length);
+ pm_buffer_append_bytes(&token_buffer->regexp_buffer, cursor, length);
pm_regexp_token_buffer_copy(parser, token_buffer);
}
}
@@ -10514,7 +9856,7 @@ 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, PM_TOKEN_BUFFER_DEFAULT_SIZE);
+ pm_buffer_init(&token_buffer->buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
start = parser->current.start;
} else {
start = token_buffer->cursor;
@@ -10531,8 +9873,8 @@ static void
pm_regexp_token_buffer_escape(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) {
const uint8_t *start;
if (token_buffer->base.cursor == NULL) {
- pm_buffer_init_capacity(&token_buffer->base.buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
- pm_buffer_init_capacity(&token_buffer->regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
+ pm_buffer_init(&token_buffer->base.buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
+ pm_buffer_init(&token_buffer->regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
start = parser->current.start;
} else {
start = token_buffer->base.cursor;
@@ -10551,7 +9893,7 @@ pm_regexp_token_buffer_escape(pm_parser_t *parser, pm_regexp_token_buffer_t *tok
* 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
+static PRISM_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;
@@ -10599,7 +9941,7 @@ pm_lex_percent_delimiter(pm_parser_t *parser) {
parser_flush_heredoc_end(parser);
} else {
// Otherwise, we'll add the newline to the list of newlines.
- pm_newline_list_append(&parser->newline_list, parser->current.end + eol_length - 1);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
}
uint8_t delimiter = *parser->current.end;
@@ -10647,6 +9989,12 @@ parser_lex(pm_parser_t *parser) {
unsigned int semantic_token_seen = parser->semantic_token_seen;
parser->semantic_token_seen = true;
+ // We'll jump to this label when we are about to encounter an EOF.
+ // If we still have lex_modes on the stack, we pop them so that cleanup
+ // can happen. For example, we should still continue parsing after a heredoc
+ // identifier, even if the heredoc body was syntax invalid.
+ switch_lex_modes:
+
switch (parser->lex_modes.current->mode) {
case PM_LEX_DEFAULT:
case PM_LEX_EMBEXPR:
@@ -10669,22 +10017,29 @@ parser_lex(pm_parser_t *parser) {
bool space_seen = false;
// First, we're going to skip past any whitespace at the front of the next
- // token.
+ // token. Skip runs of inline whitespace in bulk to avoid per-character
+ // stores back to parser->current.end.
bool chomping = true;
while (parser->current.end < parser->end && chomping) {
- switch (*parser->current.end) {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- parser->current.end++;
+ {
+ static const uint8_t inline_whitespace[256] = {
+ [' '] = 1, ['\t'] = 1, ['\f'] = 1, ['\v'] = 1
+ };
+ const uint8_t *scan = parser->current.end;
+ while (scan < parser->end && inline_whitespace[*scan]) scan++;
+ if (scan > parser->current.end) {
+ parser->current.end = scan;
space_seen = true;
- break;
+ continue;
+ }
+ }
+
+ switch (*parser->current.end) {
case '\r':
if (match_eol_offset(parser, 1)) {
chomping = false;
} else {
- pm_parser_warn(parser, parser->current.end, parser->current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
+ pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
parser->current.end++;
space_seen = true;
}
@@ -10697,7 +10052,7 @@ parser_lex(pm_parser_t *parser) {
parser->heredoc_end = NULL;
} else {
parser->current.end += eol_length + 1;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
space_seen = true;
}
} else if (pm_char_is_inline_whitespace(*parser->current.end)) {
@@ -10720,6 +10075,14 @@ parser_lex(pm_parser_t *parser) {
// 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) {
+ // We may be missing closing tokens. We should pop modes one by one
+ // to do the appropriate cleanup like moving next_start for heredocs.
+ // Only when no mode is remaining will we actually emit the EOF token.
+ if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
+ lex_mode_pop(parser);
+ goto switch_lex_modes;
+ }
+
// If we hit EOF, but the EOF came immediately after a newline,
// set the start of the token to the newline. This way any EOF
// errors will be reported as happening on that line rather than
@@ -10791,7 +10154,7 @@ parser_lex(pm_parser_t *parser) {
}
if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
}
}
@@ -10849,14 +10212,50 @@ parser_lex(pm_parser_t *parser) {
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 the lex state was ignored, we will lex the
+ // ignored newline.
+ if (lex_state_ignored_p(parser)) {
+ if (!lexed_comment) parser_lex_ignored_newline(parser);
+ lexed_comment = false;
+ goto lex_next_token;
+ }
+
+ // If we hit a '.' or a '&.' we will lex the ignored
+ // newline.
+ if (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 are parsing as CRuby 4.0 or later and we
+ // hit a '&&' or a '||' then 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) == '.')
- ))
+ (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
+ following && (
+ (peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '&') ||
+ (peek_at(parser, following) == '|' && peek_at(parser, following + 1) == '|') ||
+ (
+ peek_at(parser, following) == 'a' &&
+ peek_at(parser, following + 1) == 'n' &&
+ peek_at(parser, following + 2) == 'd' &&
+ peek_at(parser, next_content + 3) != '!' &&
+ peek_at(parser, next_content + 3) != '?' &&
+ !char_is_identifier(parser, following + 3, parser->end - (following + 3))
+ ) ||
+ (
+ peek_at(parser, following) == 'o' &&
+ peek_at(parser, following + 1) == 'r' &&
+ peek_at(parser, next_content + 2) != '!' &&
+ peek_at(parser, next_content + 2) != '?' &&
+ !char_is_identifier(parser, following + 2, parser->end - (following + 2))
+ )
+ )
) {
if (!lexed_comment) parser_lex_ignored_newline(parser);
lexed_comment = false;
@@ -10896,6 +10295,67 @@ parser_lex(pm_parser_t *parser) {
parser->next_start = NULL;
LEX(PM_TOKEN_AMPERSAND_DOT);
}
+
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
+ // If we hit an && then we are in a logical chain
+ // and we need to return the logical 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_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 2;
+ parser->next_start = NULL;
+ LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
+ }
+
+ // If we hit a || then we are in a logical chain and
+ // we need to return the logical 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_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 2;
+ parser->next_start = NULL;
+ LEX(PM_TOKEN_PIPE_PIPE);
+ }
+
+ // If we hit an 'and' then we are in a logical chain
+ // and we need to return the logical operator.
+ if (
+ peek_at(parser, next_content) == 'a' &&
+ peek_at(parser, next_content + 1) == 'n' &&
+ peek_at(parser, next_content + 2) == 'd' &&
+ peek_at(parser, next_content + 3) != '!' &&
+ peek_at(parser, next_content + 3) != '?' &&
+ !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
+ ) {
+ if (!lexed_comment) parser_lex_ignored_newline(parser);
+ lex_state_set(parser, PM_LEX_STATE_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 3;
+ parser->next_start = NULL;
+ parser->command_start = true;
+ LEX(PM_TOKEN_KEYWORD_AND);
+ }
+
+ // If we hit a 'or' then we are in a logical chain
+ // and we need to return the logical operator.
+ if (
+ peek_at(parser, next_content) == 'o' &&
+ peek_at(parser, next_content + 1) == 'r' &&
+ peek_at(parser, next_content + 2) != '!' &&
+ peek_at(parser, next_content + 2) != '?' &&
+ !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
+ ) {
+ if (!lexed_comment) parser_lex_ignored_newline(parser);
+ lex_state_set(parser, PM_LEX_STATE_BEG);
+ parser->current.start = next_content;
+ parser->current.end = next_content + 2;
+ parser->next_start = NULL;
+ parser->command_start = true;
+ LEX(PM_TOKEN_KEYWORD_OR);
+ }
+ }
}
// At this point we know this is a regular newline, and we can set the
@@ -10910,7 +10370,7 @@ parser_lex(pm_parser_t *parser) {
// ,
case ',':
if ((parser->previous.type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
}
lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
@@ -11036,7 +10496,7 @@ parser_lex(pm_parser_t *parser) {
} else if (lex_state_beg_p(parser)) {
type = PM_TOKEN_USTAR_STAR;
} else if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "**", "argument prefix");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "**", "argument prefix");
}
if (lex_state_operator_p(parser)) {
@@ -11061,7 +10521,7 @@ parser_lex(pm_parser_t *parser) {
} else if (lex_state_beg_p(parser)) {
type = PM_TOKEN_USTAR;
} else if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "*", "argument prefix");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "*", "argument prefix");
}
if (lex_state_operator_p(parser)) {
@@ -11187,7 +10647,7 @@ parser_lex(pm_parser_t *parser) {
bool ident_error = false;
if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
- pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
+ pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
ident_error = true;
}
@@ -11220,7 +10680,7 @@ parser_lex(pm_parser_t *parser) {
} 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);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
body_start++;
}
@@ -11239,7 +10699,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "<<", "here document");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "<<", "here document");
}
if (lex_state_operator_p(parser)) {
@@ -11365,7 +10825,7 @@ parser_lex(pm_parser_t *parser) {
} else if (lex_state_beg_p(parser)) {
type = PM_TOKEN_UAMPERSAND;
} else if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "&", "argument prefix");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "&", "argument prefix");
}
if (lex_state_operator_p(parser)) {
@@ -11441,7 +10901,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "+", "unary operator");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "+", "unary operator");
}
lex_state_set(parser, PM_LEX_STATE_BEG);
@@ -11482,7 +10942,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "-", "unary operator");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "-", "unary operator");
}
lex_state_set(parser, PM_LEX_STATE_BEG);
@@ -11581,7 +11041,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "/", "regexp literal");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "/", "regexp literal");
}
if (lex_state_operator_p(parser)) {
@@ -11766,7 +11226,7 @@ parser_lex(pm_parser_t *parser) {
}
if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "%", "string literal");
+ PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "%", "string literal");
}
lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
@@ -11802,40 +11262,40 @@ parser_lex(pm_parser_t *parser) {
// token after adding an appropriate error message.
if (!width) {
if (*parser->current.start >= 0x80) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
} else if (*parser->current.start == '\\') {
switch (peek_at(parser, parser->current.start + 1)) {
case ' ':
parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped space");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped space");
break;
case '\f':
parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped form feed");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped form feed");
break;
case '\t':
parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped horizontal tab");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped horizontal tab");
break;
case '\v':
parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped vertical tab");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped vertical tab");
break;
case '\r':
if (peek_at(parser, parser->current.start + 2) != '\n') {
parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped carriage return");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped carriage return");
break;
}
PRISM_FALLTHROUGH
default:
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "backslash");
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "backslash");
break;
}
} else if (char_is_ascii_printable(*parser->current.start)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
} else {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
}
goto lex_next_token;
@@ -11861,15 +11321,15 @@ parser_lex(pm_parser_t *parser) {
// 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++);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
}
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;
+ parser->data_loc.start = PM_TOKEN_START(parser, &parser->current);
+ parser->data_loc.length = PM_TOKEN_LENGTH(&parser->current);
LEX(PM_TOKEN_EOF);
}
@@ -11894,7 +11354,7 @@ parser_lex(pm_parser_t *parser) {
!(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))
+ pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
) {
lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
}
@@ -11922,7 +11382,7 @@ parser_lex(pm_parser_t *parser) {
whitespace += 1;
}
} else {
- whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list);
+ whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
}
if (whitespace > 0) {
@@ -12037,7 +11497,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
} else {
// ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
}
parser->current.end++;
@@ -12065,7 +11525,7 @@ parser_lex(pm_parser_t *parser) {
if (*breakpoint == '#') {
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -12170,7 +11630,13 @@ parser_lex(pm_parser_t *parser) {
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);
+
+ // Track the newline if we're not in a heredoc that
+ // would have already have added the newline to the
+ // list.
+ if (parser->heredoc_end == NULL) {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
+ }
} else {
parser->current.end = breakpoint + 1;
}
@@ -12216,7 +11682,7 @@ parser_lex(pm_parser_t *parser) {
// If we've hit a newline, then we need to track that in
// the list of newlines.
if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
parser->current.end = breakpoint + 1;
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
break;
@@ -12264,7 +11730,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
} else {
// ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
}
parser->current.end++;
@@ -12311,7 +11777,7 @@ parser_lex(pm_parser_t *parser) {
// interpolation.
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -12424,7 +11890,13 @@ parser_lex(pm_parser_t *parser) {
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);
+
+ // Track the newline if we're not in a heredoc that
+ // would have already have added the newline to the
+ // list.
+ if (parser->heredoc_end == NULL) {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
+ }
} else {
parser->current.end = breakpoint + 1;
}
@@ -12436,6 +11908,13 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_LABEL_END);
}
+ // When the delimiter itself is a newline, we won't
+ // get a chance to flush heredocs in the usual places since
+ // the newline is already consumed.
+ if (term == '\n' && parser->heredoc_end) {
+ parser_flush_heredoc_end(parser);
+ }
+
lex_state_set(parser, PM_LEX_STATE_END);
lex_mode_pop(parser);
LEX(PM_TOKEN_STRING_END);
@@ -12468,7 +11947,7 @@ parser_lex(pm_parser_t *parser) {
// for the terminator in case the terminator is a
// newline character.
if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
parser->current.end = breakpoint + 1;
breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
break;
@@ -12522,7 +12001,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
} else {
// ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
}
parser->current.end++;
@@ -12551,7 +12030,7 @@ parser_lex(pm_parser_t *parser) {
case '#': {
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -12651,7 +12130,7 @@ parser_lex(pm_parser_t *parser) {
(memcmp(terminator_start, ident_start, ident_length) == 0)
) {
if (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
}
parser->current.end = terminator_end;
@@ -12682,7 +12161,7 @@ parser_lex(pm_parser_t *parser) {
// 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[] = "\r\n\\#";
+ uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] = "\r\n\\#";
pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
if (quote == PM_HEREDOC_QUOTE_SINGLE) {
@@ -12723,7 +12202,7 @@ parser_lex(pm_parser_t *parser) {
LEX(PM_TOKEN_STRING_CONTENT);
}
- pm_newline_list_append(&parser->newline_list, breakpoint);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
// If we have a - or ~ heredoc, then we can match after
// some leading whitespace.
@@ -12841,7 +12320,10 @@ parser_lex(pm_parser_t *parser) {
// string content.
if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
const uint8_t *end = parser->current.end;
- pm_newline_list_append(&parser->newline_list, end);
+
+ if (parser->heredoc_end == NULL) {
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
+ }
// Here we want the buffer to only
// include up to the backslash.
@@ -12872,7 +12354,7 @@ parser_lex(pm_parser_t *parser) {
case '#': {
pm_token_type_t type = lex_interpolation(parser, breakpoint);
- if (type == PM_TOKEN_NOT_PROVIDED) {
+ if (!type) {
// 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
@@ -13097,7 +12579,7 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
/**
* Returns true if the current token is of the given type.
*/
-static inline bool
+static PRISM_INLINE bool
match1(const pm_parser_t *parser, pm_token_type_t type) {
return parser->current.type == type;
}
@@ -13105,7 +12587,7 @@ match1(const pm_parser_t *parser, pm_token_type_t type) {
/**
* Returns true if the current token is of either of the given types.
*/
-static inline bool
+static PRISM_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);
}
@@ -13113,7 +12595,7 @@ match2(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2)
/**
* Returns true if the current token is any of the three given types.
*/
-static inline bool
+static PRISM_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);
}
@@ -13121,15 +12603,23 @@ match3(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2,
/**
* Returns true if the current token is any of the four given types.
*/
-static inline bool
+static PRISM_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 six given types.
+ */
+static PRISM_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
+static PRISM_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);
}
@@ -13137,20 +12627,12 @@ match7(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2,
/**
* Returns true if the current token is any of the eight given types.
*/
-static inline bool
+static PRISM_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);
}
/**
- * Returns true if the current token is any of the nine given types.
- */
-static inline bool
-match9(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, pm_token_type_t type9) {
- 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) || match1(parser, type9);
-}
-
-/**
* If the current token is of the specified type, lex forward by one token and
* return true. Otherwise, return false. For example:
*
@@ -13169,7 +12651,7 @@ accept1(pm_parser_t *parser, pm_token_type_t type) {
* 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
+static PRISM_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);
@@ -13194,10 +12676,10 @@ 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);
+ pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
/**
@@ -13209,10 +12691,10 @@ expect2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_di
if (accept2(parser, type1, type2)) return;
const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
+ pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
/**
@@ -13226,20 +12708,43 @@ expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ide
} else {
pm_parser_err_heredoc_term(parser, ident_start, ident_length);
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
}
+/**
+ * A special expect1 that attaches the error to the opening token location
+ * rather than the current position. This is useful for errors about missing
+ * closing tokens, where we want to point to the line with the opening token
+ * (e.g., `def`, `class`, `if`, `{`) rather than the end of the file.
+ */
+static void
+expect1_opening(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id, const pm_token_t *opening) {
+ if (accept1(parser, type)) return;
+
+ const uint8_t *start = opening->start;
+ pm_parser_err(parser, U32(start - parser->start), U32(opening->end - start), diag_id);
+
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = 0;
+}
+
+/** Flags for controlling expression parsing behavior. */
+#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
+#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
+#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
+#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
+
static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth);
+parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
/**
* This is a wrapper of parse_expression, which also checks whether the
* resulting node is a value expression.
*/
static pm_node_t *
-parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) {
- pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
+parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
+ pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
pm_assert_value_expression(parser, node);
return node;
}
@@ -13262,7 +12767,7 @@ parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bo
* work in all cases, it may need to be refactored later. But it appears to work
* for now.
*/
-static inline bool
+static PRISM_INLINE bool
token_begins_expression_p(pm_token_type_t type) {
switch (type) {
case PM_TOKEN_EQUAL_GREATER:
@@ -13278,6 +12783,7 @@ token_begins_expression_p(pm_token_type_t type) {
case PM_TOKEN_EOF:
case PM_TOKEN_LAMBDA_BEGIN:
case PM_TOKEN_KEYWORD_DO:
+ case PM_TOKEN_KEYWORD_DO_BLOCK:
case PM_TOKEN_KEYWORD_DO_LOOP:
case PM_TOKEN_KEYWORD_END:
case PM_TOKEN_KEYWORD_ELSE:
@@ -13323,14 +12829,89 @@ token_begins_expression_p(pm_token_type_t type) {
* 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, uint16_t depth) {
+parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
if (accept1(parser, PM_TOKEN_USTAR)) {
pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
+ pm_node_t *expression = parse_value_expression(parser, binding_power, (uint8_t) (flags & PM_PARSE_ACCEPTS_DO_BLOCK), PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+ return UP(pm_splat_node_create(parser, &operator, expression));
}
- return parse_value_expression(parser, binding_power, accepts_command_call, false, diag_id, depth);
+ return parse_value_expression(parser, binding_power, flags, diag_id, depth);
+}
+
+static bool
+pm_node_unreference_each(const pm_node_t *node, void *data) {
+ switch (PM_NODE_TYPE(node)) {
+ /* When we are about to destroy a set of nodes that could potentially
+ * contain block exits for the current scope, we need to check if they
+ * are contained in the list of block exits and remove them if they are.
+ */
+ case PM_BREAK_NODE:
+ case PM_NEXT_NODE:
+ case PM_REDO_NODE: {
+ pm_parser_t *parser = (pm_parser_t *) data;
+ size_t index = 0;
+
+ while (index < parser->current_block_exits->size) {
+ pm_node_t *block_exit = parser->current_block_exits->nodes[index];
+
+ if (block_exit == node) {
+ if (index + 1 < parser->current_block_exits->size) {
+ memmove(
+ &parser->current_block_exits->nodes[index],
+ &parser->current_block_exits->nodes[index + 1],
+ (parser->current_block_exits->size - index - 1) * sizeof(pm_node_t *)
+ );
+ }
+ parser->current_block_exits->size--;
+
+ /* Note returning true here because these nodes could have
+ * arguments that are themselves block exits. */
+ return true;
+ }
+
+ index++;
+ }
+
+ return true;
+ }
+ /* When an implicit local variable is written to or targeted, it becomes
+ * a regular, named local variable. This branch removes it from the list
+ * of implicit parameters when that happens. */
+ case PM_LOCAL_VARIABLE_READ_NODE:
+ case PM_IT_LOCAL_VARIABLE_READ_NODE: {
+ pm_parser_t *parser = (pm_parser_t *) data;
+ pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
+
+ for (size_t index = 0; index < implicit_parameters->size; index++) {
+ if (implicit_parameters->nodes[index] == node) {
+ /* If the node is not the last one in the list, we need to
+ * shift the remaining nodes down to fill the gap. This is
+ * extremely unlikely to happen. */
+ if (index != implicit_parameters->size - 1) {
+ memmove(&implicit_parameters->nodes[index], &implicit_parameters->nodes[index + 1], (implicit_parameters->size - index - 1) * sizeof(pm_node_t *));
+ }
+
+ implicit_parameters->size--;
+ break;
+ }
+ }
+
+ return false;
+ }
+ default:
+ return true;
+ }
+}
+
+/**
+ * When we are about to destroy a set of nodes that could potentially be
+ * referenced by one or more lists on the parser, then remove them from those
+ * lists so we don't get a use-after-free.
+ */
+static void
+pm_node_unreference(pm_parser_t *parser, const pm_node_t *node) {
+ pm_visit_node(node, pm_node_unreference_each, parser);
}
/**
@@ -13345,16 +12926,12 @@ parse_write_name(pm_parser_t *parser, pm_constant_id_t *name_field) {
// 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 = xcalloc(length + 1, sizeof(uint8_t));
- if (name == NULL) return;
+ uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
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);
+ *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
}
/**
@@ -13376,35 +12953,10 @@ parse_unwriteable_target(pm_parser_t *parser, pm_node_t *target) {
default: break;
}
- pm_constant_id_t name = pm_parser_constant_id_location(parser, target->location.start, target->location.end);
+ pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
pm_local_variable_target_node_t *result = pm_local_variable_target_node_create(parser, &target->location, name, 0);
- pm_node_destroy(parser, target);
- return (pm_node_t *) result;
-}
-
-/**
- * When an implicit local variable is written to or targeted, it becomes a
- * regular, named local variable. This function removes it from the list of
- * implicit parameters when that happens.
- */
-static void
-parse_target_implicit_parameter(pm_parser_t *parser, pm_node_t *node) {
- pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
-
- for (size_t index = 0; index < implicit_parameters->size; index++) {
- if (implicit_parameters->nodes[index] == node) {
- // If the node is not the last one in the list, we need to shift the
- // remaining nodes down to fill the gap. This is extremely unlikely
- // to happen.
- if (index != implicit_parameters->size - 1) {
- memcpy(&implicit_parameters->nodes[index], &implicit_parameters->nodes[index + 1], (implicit_parameters->size - index - 1) * sizeof(pm_node_t *));
- }
-
- implicit_parameters->size--;
- break;
- }
- }
+ return UP(result);
}
/**
@@ -13418,7 +12970,7 @@ parse_target_implicit_parameter(pm_parser_t *parser, pm_node_t *node) {
static pm_node_t *
parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_parent) {
switch (PM_NODE_TYPE(target)) {
- case PM_MISSING_NODE:
+ case PM_ERROR_RECOVERY_NODE:
return target;
case PM_SOURCE_ENCODING_NODE:
case PM_FALSE_NODE:
@@ -13456,15 +13008,15 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
case PM_BACK_REFERENCE_READ_NODE:
case PM_NUMBERED_REFERENCE_READ_NODE:
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
- return target;
+ return UP(pm_error_recovery_node_create_unexpected(parser, 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_FORMAT(parser, target->location.start, target->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, target->location.start);
- parse_target_implicit_parameter(parser, target);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
+ pm_node_unreference(parser, target);
}
const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) target;
@@ -13479,10 +13031,9 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
}
case PM_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
- pm_node_t *node = (pm_node_t *) pm_local_variable_target_node_create(parser, &target->location, name, 0);
+ pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->location, name, 0));
- parse_target_implicit_parameter(parser, target);
- pm_node_destroy(parser, target);
+ pm_node_unreference(parser, target);
return node;
}
@@ -13505,7 +13056,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
splat->expression = parse_target(parser, splat->expression, multiple, true);
}
- return (pm_node_t *) splat;
+ return UP(splat);
}
case PM_CALL_NODE: {
pm_call_node_t *call = (pm_call_node_t *) target;
@@ -13514,10 +13065,10 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
// 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->message_loc.length > 0) &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '!') &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '?') &&
+ (call->opening_loc.length == 0) &&
(call->arguments == NULL) &&
(call->block == NULL)
) {
@@ -13531,21 +13082,19 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
// 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_loc = call->message_loc;
-
- pm_constant_id_t name = pm_parser_local_add_location(parser, message_loc.start, message_loc.end, 0);
- pm_node_destroy(parser, target);
+ pm_location_t message_loc = call->message_loc;
+ pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
- return (pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
+ return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
}
- if (*call->message_loc.start == '_' || parser->encoding->alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) {
+ if (peek_at(parser, parser->start + call->message_loc.start) == '_' || parser->encoding->alnum_char(parser->start + call->message_loc.start, (ptrdiff_t) call->message_loc.length)) {
if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
pm_parser_err_node(parser, (const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
}
parse_write_name(parser, &call->name);
- return (pm_node_t *) pm_call_target_node_create(parser, call);
+ return UP(pm_call_target_node_create(parser, call));
}
}
@@ -13553,7 +13102,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
// an aref expression, and we can transform it into an aset
// expression.
if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
- return (pm_node_t *) pm_index_target_node_create(parser, call);
+ return UP(pm_index_target_node_create(parser, call));
}
}
PRISM_FALLTHROUGH
@@ -13596,7 +13145,7 @@ parse_shareable_constant_write(pm_parser_t *parser, pm_node_t *write) {
pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
- return (pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
+ return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
}
return write;
@@ -13608,16 +13157,14 @@ parse_shareable_constant_write(pm_parser_t *parser, pm_node_t *write) {
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);
+ case PM_ERROR_RECOVERY_NODE:
return target;
case PM_CLASS_VARIABLE_READ_NODE: {
pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target, operator, value);
- pm_node_destroy(parser, target);
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_CONSTANT_PATH_NODE: {
- pm_node_t *node = (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value);
+ pm_node_t *node = UP(pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value));
if (context_def_p(parser)) {
pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
@@ -13626,13 +13173,12 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
return parse_shareable_constant_write(parser, node);
}
case PM_CONSTANT_READ_NODE: {
- pm_node_t *node = (pm_node_t *) pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value);
+ pm_node_t *node = UP(pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value));
if (context_def_p(parser)) {
pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
}
- pm_node_destroy(parser, target);
return parse_shareable_constant_write(parser, node);
}
case PM_BACK_REFERENCE_READ_NODE:
@@ -13641,45 +13187,40 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
PRISM_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;
+ return UP(node);
}
case PM_LOCAL_VARIABLE_READ_NODE: {
pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
+ pm_location_t location = target->location;
pm_constant_id_t name = local_read->name;
- pm_location_t name_loc = target->location;
-
uint32_t depth = local_read->depth;
pm_scope_t *scope = pm_parser_scope_find(parser, depth);
- if (pm_token_is_numbered_parameter(target->location.start, target->location.end)) {
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
- PM_PARSER_ERR_FORMAT(parser, target->location.start, target->location.end, diag_id, target->location.start);
- parse_target_implicit_parameter(parser, target);
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
+ pm_node_unreference(parser, target);
}
pm_locals_unread(&scope->locals, name);
- pm_node_destroy(parser, target);
- return (pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc, operator);
+ return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location, operator));
}
case PM_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
- pm_node_t *node = (pm_node_t *) pm_local_variable_write_node_create(parser, name, 0, value, &target->location, operator);
+ pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->location, operator));
- parse_target_implicit_parameter(parser, target);
- pm_node_destroy(parser, target);
+ pm_node_unreference(parser, target);
return node;
}
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);
+ pm_node_t *write_node = UP(pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target, operator, value));
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);
+ return UP(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;
@@ -13688,9 +13229,9 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
}
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);
+ pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
- return (pm_node_t *) pm_multi_write_node_create(parser, multi_target, operator, value);
+ return UP(pm_multi_write_node_create(parser, multi_target, operator, value));
}
case PM_CALL_NODE: {
pm_call_node_t *call = (pm_call_node_t *) target;
@@ -13699,10 +13240,10 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
// 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->message_loc.length > 0) &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '!') &&
+ (parser->start[call->message_loc.start + call->message_loc.length - 1] != '?') &&
+ (call->opening_loc.length == 0) &&
(call->arguments == NULL) &&
(call->block == NULL)
) {
@@ -13716,19 +13257,18 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
// 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_location_t message_loc = call->message_loc;
- pm_parser_local_add_location(parser, message.start, message.end, 0);
- pm_node_destroy(parser, target);
+ pm_refute_numbered_parameter(parser, message_loc.start, message_loc.length);
+ pm_parser_local_add_location(parser, &message_loc, 0);
- 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_constant_id_t constant_id = pm_parser_constant_id_raw(parser, parser->start + PM_LOCATION_START(&message_loc), parser->start + PM_LOCATION_END(&message_loc));
+ target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc, operator));
- pm_refute_numbered_parameter(parser, message.start, message.end);
return target;
}
- if (char_is_identifier_start(parser, call->message_loc.start, parser->end - call->message_loc.start)) {
+ if (char_is_identifier_start(parser, parser->start + call->message_loc.start, (ptrdiff_t) call->message_loc.length)) {
// 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:
@@ -13742,13 +13282,14 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
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;
+ pm_arguments_node_arguments_append(parser->arena, arguments, value);
+ PM_NODE_LENGTH_SET_NODE(call, arguments);
+ call->equal_loc = TOK2LOC(parser, operator);
parse_write_name(parser, &call->name);
- pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
+ pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
- return (pm_node_t *) call;
+ return UP(call);
}
}
@@ -13760,25 +13301,31 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
call->arguments = pm_arguments_node_create(parser);
}
- pm_arguments_node_arguments_append(call->arguments, value);
- target->location.end = value->location.end;
+ pm_arguments_node_arguments_append(parser->arena, call->arguments, value);
+ PM_NODE_LENGTH_SET_NODE(target, value);
// Replace the name with "[]=".
call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
+ call->equal_loc = TOK2LOC(parser, operator);
// Ensure that the arguments for []= don't contain keywords
pm_index_arguments_check(parser, call->arguments, call->block);
- pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
+ pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
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
+ // 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);
+ //
+ // Since it is possible for the value to contain an implicit
+ // parameter somewhere in its subtree, we need to walk it and remove
+ // any implicit parameters from the list of implicit parameters for
+ // the current scope.
+ pm_node_unreference(parser, value);
}
PRISM_FALLTHROUGH
default:
@@ -13809,11 +13356,10 @@ parse_unwriteable_write(pm_parser_t *parser, pm_node_t *target, const pm_token_t
default: break;
}
- pm_constant_id_t name = pm_parser_local_add_location(parser, target->location.start, target->location.end, 1);
+ pm_constant_id_t name = pm_parser_local_add_location(parser, &target->location, 1);
pm_local_variable_write_node_t *result = pm_local_variable_write_node_create(parser, name, 0, value, &target->location, equals);
- pm_node_destroy(parser, target);
- return (pm_node_t *) result;
+ return UP(result);
}
/**
@@ -13846,35 +13392,35 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
pm_node_t *name = NULL;
if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+ name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
name = parse_target(parser, name, true, true);
}
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
+ pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
pm_multi_target_node_targets_append(parser, result, splat);
has_rest = true;
} else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
context_push(parser, PM_CONTEXT_MULTI_TARGET);
- pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
+ pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
target = parse_target(parser, target, true, false);
pm_multi_target_node_targets_append(parser, result, target);
context_pop(parser);
} else if (token_begins_expression_p(parser->current.type)) {
- pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
+ pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
target = parse_target(parser, target, true, false);
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 add an implicit rest node to represent this.
- pm_node_t *rest = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
+ pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
pm_multi_target_node_targets_append(parser, result, rest);
break;
}
}
- return (pm_node_t *) result;
+ return UP(result);
}
/**
@@ -13884,7 +13430,13 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
static pm_node_t *
parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
- accept1(parser, PM_TOKEN_NEWLINE);
+
+ // If we're inside parentheses, then we allow a newline before the
+ // closing parenthesis or equals sign. Outside of parentheses, a newline
+ // is not allowed (e.g., `a, b\n= 1, 2` is not valid).
+ if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
+ accept1(parser, PM_TOKEN_NEWLINE);
+ }
// Ensure that we have either an = or a ) after the targets.
if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
@@ -13913,7 +13465,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
context_push(parser, context);
while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
pm_statements_node_body_append(parser, statements, node, true);
// If we're recovering from a syntax error, then we need to stop parsing
@@ -13953,7 +13505,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
// 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)) {
+ if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
parser_lex(parser);
// If we are at the end of the file, then we need to stop parsing
@@ -13971,13 +13523,14 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
// This is an inlined version of accept1 because the error that we
// want to add has varargs. If this happens again, we should
// probably extract a helper function.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
}
context_pop(parser);
+
bool last_value = true;
switch (context) {
case PM_CONTEXT_BEGIN_ENSURE:
@@ -13998,23 +13551,24 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
*/
static void
pm_hash_key_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
- const pm_node_t *duplicated = pm_static_literals_add(&parser->newline_list, parser->start_line, literals, node, true);
+ const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, literals, node, true);
if (duplicated != NULL) {
pm_buffer_t buffer = { 0 };
- pm_static_literal_inspect(&buffer, &parser->newline_list, parser->start_line, parser->encoding->name, duplicated);
+ pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding->name, duplicated);
pm_diagnostic_list_append_format(
+ &parser->metadata_arena,
&parser->warning_list,
duplicated->location.start,
- duplicated->location.end,
+ duplicated->location.length,
PM_WARN_DUPLICATED_HASH_KEY,
(int) pm_buffer_length(&buffer),
pm_buffer_value(&buffer),
- pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line
+ pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).line
);
- pm_buffer_free(&buffer);
+ pm_buffer_cleanup(&buffer);
}
}
@@ -14026,14 +13580,15 @@ static void
pm_when_clause_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
pm_node_t *previous;
- if ((previous = pm_static_literals_add(&parser->newline_list, parser->start_line, literals, node, false)) != NULL) {
+ if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, literals, node, false)) != NULL) {
pm_diagnostic_list_append_format(
+ &parser->metadata_arena,
&parser->warning_list,
- node->location.start,
- node->location.end,
+ PM_NODE_START(node),
+ PM_NODE_LENGTH(node),
PM_WARN_DUPLICATED_WHEN_CLAUSE,
- pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line,
- pm_newline_list_line_column(&parser->newline_list, previous->location.start, parser->start_line).line
+ pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).line,
+ pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).line
);
}
}
@@ -14061,14 +13616,14 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
// inner hash to share the static literals with the outer
// hash.
parser->current_hash_keys = literals;
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
} else if (token_begins_expression_p(parser->current.type)) {
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
} else {
pm_parser_scope_forwarding_keywords_check(parser, &operator);
}
- element = (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
+ element = UP(pm_assoc_splat_node_create(parser, value, &operator));
contains_keyword_splat = true;
break;
}
@@ -14076,44 +13631,43 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
pm_token_t label = parser->current;
parser_lex(parser);
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &label);
+ pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
pm_hash_key_static_literals_add(parser, literals, key);
- 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, false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
+ value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
} 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);
+ value = UP(pm_constant_read_node_create(parser, &constant));
} else {
int depth = -1;
pm_token_t identifier = { .type = PM_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 };
if (identifier.end[-1] == '!' || identifier.end[-1] == '?') {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
} else {
depth = pm_parser_local_depth(parser, &identifier);
}
if (depth == -1) {
- value = (pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
+ value = UP(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 = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
}
}
- value->location.end++;
- value = (pm_node_t *) pm_implicit_node_create(parser, value);
+ value->location.length++;
+ value = UP(pm_implicit_node_create(parser, value));
}
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
+ element = UP(pm_assoc_node_create(parser, key, NULL, value));
break;
}
default: {
- pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
+ pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
// Hash keys that are strings are automatically frozen. We will
// mark that here.
@@ -14123,24 +13677,22 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
pm_hash_key_static_literals_add(parser, literals, key);
- pm_token_t operator;
- if (pm_symbol_node_label_p(key)) {
- operator = not_provided(parser);
- } else {
+ pm_token_t operator = { 0 };
+ if (!pm_symbol_node_label_p(parser, key)) {
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, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
+ element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(operator), value));
break;
}
}
if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
- pm_hash_node_elements_append((pm_hash_node_t *) node, element);
+ pm_hash_node_elements_append(parser->arena, (pm_hash_node_t *) node, element);
} else {
- pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
+ pm_keyword_hash_node_elements_append(parser->arena, (pm_keyword_hash_node_t *) node, element);
}
// If there's no comma after the element, then we're done.
@@ -14161,23 +13713,47 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod
return contains_keyword_splat;
}
+static PRISM_INLINE bool
+argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) {
+ if (pm_symbol_node_label_p(parser, argument)) {
+ return true;
+ }
+
+ switch (PM_NODE_TYPE(argument)) {
+ case PM_CALL_NODE: {
+ pm_call_node_t *cast = (pm_call_node_t *) argument;
+ if (cast->opening_loc.length == 0 && cast->arguments != NULL) {
+ if (PM_NODE_FLAG_P(cast->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
+ return false;
+ }
+ if (cast->block != NULL) {
+ return false;
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+ return accept1(parser, PM_TOKEN_EQUAL_GREATER);
+}
+
/**
* Append an argument to a list of arguments.
*/
-static inline void
+static PRISM_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);
+ pm_arguments_node_arguments_append(parser->arena, 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, uint16_t depth) {
+parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
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
@@ -14210,16 +13786,16 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
}
pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- argument = (pm_node_t *) hash;
+ argument = UP(hash);
pm_static_literals_t hash_keys = { 0 };
- bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash, (uint16_t) (depth + 1));
+ bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
parse_arguments_append(parser, arguments, argument);
- pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
- if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
- pm_node_flag_set((pm_node_t *) arguments->arguments, flags);
+ pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
+ if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
+ pm_node_flag_set(UP(arguments->arguments), node_flags);
pm_static_literals_free(&hash_keys);
parsed_bare_hash = true;
@@ -14232,12 +13808,12 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
pm_node_t *expression = NULL;
if (token_begins_expression_p(parser->current.type)) {
- expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
+ expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
} else {
pm_parser_scope_forwarding_block_check(parser, &operator);
}
- argument = (pm_node_t *) pm_block_argument_node_create(parser, &operator, expression);
+ argument = UP(pm_block_argument_node_create(parser, &operator, expression));
if (parsed_block_argument) {
parse_arguments_append(parser, arguments, argument);
} else {
@@ -14257,18 +13833,18 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
pm_parser_scope_forwarding_positionals_check(parser, &operator);
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, NULL);
+ argument = UP(pm_splat_node_create(parser, &operator, NULL));
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
}
} else {
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
if (parsed_bare_hash) {
- pm_parser_err(parser, operator.start, expression->location.end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &operator), PM_NODE_END(expression) - PM_TOKEN_START(parser, &operator), PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
}
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
+ argument = UP(pm_splat_node_create(parser, &operator, expression));
}
parse_arguments_append(parser, arguments, argument);
@@ -14283,26 +13859,26 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
// 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, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
// If we parse a range, we need to validate that we
// didn't accidentally violate the nonassoc rules of the
// ... operator.
if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
pm_range_node_t *range = (pm_range_node_t *) right;
- pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
+ pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
}
- argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
+ argument = UP(pm_range_node_create(parser, NULL, &operator, right));
} else {
pm_parser_scope_forwarding_all_check(parser, &parser->previous);
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);
+ argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
parse_arguments_append(parser, arguments, argument);
- pm_node_flag_set((pm_node_t *) arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
+ pm_node_flag_set(UP(arguments->arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
arguments->has_forwarding = true;
parsed_forwarding_arguments = true;
break;
@@ -14312,22 +13888,20 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
PRISM_FALLTHROUGH
default: {
if (argument == NULL) {
- argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
+ argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (!parsed_first_argument ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0u) | PM_PARSE_ACCEPTS_LABEL), PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
}
bool contains_keywords = false;
bool contains_keyword_splat = false;
- if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
+ if (argument_allowed_for_bare_hash(parser, argument)) {
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
}
- pm_token_t operator;
+ pm_token_t operator = { 0 };
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);
@@ -14338,18 +13912,18 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
pm_hash_key_static_literals_add(parser, &hash_keys, argument);
// Finish parsing the one we are part way through.
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
- argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
+ argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(operator), value));
- pm_keyword_hash_node_elements_append(bare_hash, argument);
- argument = (pm_node_t *) bare_hash;
+ pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
+ argument = UP(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, &hash_keys, (pm_node_t *) bare_hash, (uint16_t) (depth + 1));
+ contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
}
pm_static_literals_free(&hash_keys);
@@ -14358,10 +13932,10 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
parse_arguments_append(parser, arguments, argument);
- pm_node_flags_t flags = 0;
- if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
- if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
- pm_node_flag_set((pm_node_t *) arguments->arguments, flags);
+ pm_node_flags_t node_flags = 0;
+ if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
+ if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
+ pm_node_flag_set(UP(arguments->arguments), node_flags);
break;
}
@@ -14370,7 +13944,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
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 (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_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
@@ -14390,6 +13964,17 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
if (accepted_newline) {
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
}
+
+ // If this is a command call and an argument takes a block,
+ // there can be no further arguments. For example,
+ // `foo(bar 1 do end, 2)` should be rejected.
+ if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
+ pm_call_node_t *call = (pm_call_node_t *) argument;
+ if (call->opening_loc.length == 0 && call->arguments != NULL && call->block != NULL) {
+ pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
+ break;
+ }
+ }
} 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.
@@ -14417,7 +14002,7 @@ 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);
+ pm_multi_target_node_opening_set(parser, node, &parser->previous);
do {
pm_node_t *param;
@@ -14427,33 +14012,33 @@ parse_required_destructured_parameter(pm_parser_t *parser) {
// 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);
+ param = UP(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);
+ param = UP(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);
+ value = UP(pm_required_parameter_node_create(parser, &name));
if (pm_parser_parameter_name_check(parser, &name)) {
pm_node_flag_set_repeated_parameter(value);
}
pm_parser_local_add_token(parser, &name, 1);
}
- param = (pm_node_t *) pm_splat_node_create(parser, &star, value);
+ param = UP(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);
+ param = UP(pm_required_parameter_node_create(parser, &name));
if (pm_parser_parameter_name_check(parser, &name)) {
pm_node_flag_set_repeated_parameter(param);
}
@@ -14465,7 +14050,7 @@ parse_required_destructured_parameter(pm_parser_t *parser) {
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
- pm_multi_target_node_closing_set(node, &parser->previous);
+ pm_multi_target_node_closing_set(parser, node, &parser->previous);
return node;
}
@@ -14541,6 +14126,43 @@ update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_ord
return true;
}
+static PRISM_INLINE void
+parse_parameters_handle_trailing_comma(
+ pm_parser_t *parser,
+ pm_parameters_node_t *params,
+ pm_parameters_order_t order,
+ bool in_block,
+ bool allows_trailing_comma
+) {
+ if (!allows_trailing_comma) {
+ pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
+ return;
+ }
+
+ if (in_block) {
+ if (order >= PM_PARAMETERS_ORDER_NAMED) {
+ // foo do |bar,|; end
+ pm_node_t *param = UP(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, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
+ pm_parameters_node_posts_append(parser->arena, params, UP(param));
+ }
+ } else {
+ // foo do |*bar,|; end
+ pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
+ }
+ } else {
+ // https://bugs.ruby-lang.org/issues/19107
+ // Allow `def foo(bar,); end`, `def foo(*bar,); end`, etc. but not `def foo(...,); end`
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
+ pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
+ }
+ }
+}
+
/**
* Parse a list of parameters on a method definition.
*/
@@ -14553,6 +14175,7 @@ parse_parameters(
bool allows_forwarding_parameters,
bool accepts_blocks_in_defaults,
bool in_block,
+ pm_diagnostic_id_t diag_id_forwarding,
uint16_t depth
) {
pm_do_loop_stack_push(parser, false);
@@ -14566,12 +14189,12 @@ parse_parameters(
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);
+ pm_node_t *param = UP(parse_required_destructured_parameter(parser));
if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_parameters_node_requireds_append(params, param);
+ pm_parameters_node_requireds_append(parser->arena, params, param);
} else {
- pm_parameters_node_posts_append(params, param);
+ pm_parameters_node_posts_append(parser->arena, params, param);
}
break;
}
@@ -14581,34 +14204,40 @@ parse_parameters(
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_token_t name;
+ pm_node_t *param;
- bool repeated = false;
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- repeated = pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name, 1);
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
+ param = (pm_node_t *) pm_no_block_parameter_node_create(parser, &operator, &parser->previous);
} else {
- name = not_provided(parser);
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
- }
+ pm_token_t name = {0};
- pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &operator);
- if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *)param);
+ bool repeated = false;
+ if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
+ name = parser->previous;
+ repeated = pm_parser_parameter_name_check(parser, &name);
+ pm_parser_local_add_token(parser, &name, 1);
+ } else {
+ parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
+ }
+
+ param = (pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
+ if (repeated) {
+ pm_node_flag_set_repeated_parameter(param);
+ }
}
+
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);
+ pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
+ pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
}
break;
}
case PM_TOKEN_UDOT_DOT_DOT: {
if (!allows_forwarding_parameters) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
+ pm_parser_err_current(parser, diag_id_forwarding);
}
bool succeeded = update_parameter_state(parser, &parser->current, &order);
@@ -14621,12 +14250,12 @@ parse_parameters(
// 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_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
if (succeeded) 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);
+ pm_parameters_node_keyword_rest_set(params, UP(param));
break;
}
case PM_TOKEN_CLASS_VARIABLE:
@@ -14671,24 +14300,24 @@ parse_parameters(
parser_lex(parser);
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name);
- uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
+ uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
- pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
+ pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value);
if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *) param);
+ pm_node_flag_set_repeated_parameter(UP(param));
}
- pm_parameters_node_optionals_append(params, param);
+ pm_parameters_node_optionals_append(parser->arena, params, param);
// If the value of the parameter increased the number of
// reads of that parameter, then we need to warn that we
// have a circular definition.
- if ((parser->version == PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
+ if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
}
context_pop(parser);
@@ -14703,15 +14332,15 @@ parse_parameters(
} else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *)param);
+ pm_node_flag_set_repeated_parameter(UP(param));
}
- pm_parameters_node_requireds_append(params, (pm_node_t *) param);
+ pm_parameters_node_requireds_append(parser->arena, params, UP(param));
} else {
pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *)param);
+ pm_node_flag_set_repeated_parameter(UP(param));
}
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
+ pm_parameters_node_posts_append(parser->arena, params, UP(param));
}
break;
@@ -14728,9 +14357,9 @@ parse_parameters(
local.end -= 1;
if (parser->encoding_changed ? parser->encoding->isupper_char(local.start, local.end - local.start) : pm_encoding_utf_8_isupper_char(local.start, local.end - local.start)) {
- pm_parser_err(parser, local.start, local.end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
+ pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
} else if (local.end[-1] == '!' || local.end[-1] == '?') {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
}
bool repeated = pm_parser_parameter_name_check(parser, &local);
@@ -14742,12 +14371,12 @@ parse_parameters(
case PM_TOKEN_PIPE: {
context_pop(parser);
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
+ pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
- pm_parameters_node_keywords_append(params, param);
+ pm_parameters_node_keywords_append(parser->arena, params, param);
break;
}
case PM_TOKEN_SEMICOLON:
@@ -14759,12 +14388,12 @@ parse_parameters(
break;
}
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
+ pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
- pm_parameters_node_keywords_append(params, param);
+ pm_parameters_node_keywords_append(parser->arena, params, param);
break;
}
default: {
@@ -14772,20 +14401,20 @@ parse_parameters(
if (token_begins_expression_p(parser->current.type)) {
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local);
- uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
+ uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
- pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
+ pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
- if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
+ if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
}
- param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
+ param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
}
else {
- param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
+ param = UP(pm_required_keyword_parameter_node_create(parser, &name));
}
if (repeated) {
@@ -14793,7 +14422,7 @@ parse_parameters(
}
context_pop(parser);
- pm_parameters_node_keywords_append(params, param);
+ pm_parameters_node_keywords_append(parser->arena, 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
@@ -14814,7 +14443,7 @@ parse_parameters(
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_token_t name;
+ pm_token_t name = { 0 };
bool repeated = false;
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
@@ -14822,11 +14451,10 @@ parse_parameters(
repeated = pm_parser_parameter_name_check(parser, &name);
pm_parser_local_add_token(parser, &name, 1);
} else {
- name = not_provided(parser);
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
}
- pm_node_t *param = (pm_node_t *) pm_rest_parameter_node_create(parser, &operator, &name);
+ pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &operator, NTOK2PTR(name)));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
@@ -14835,7 +14463,7 @@ parse_parameters(
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);
+ pm_parameters_node_posts_append(parser->arena, params, param);
}
break;
@@ -14854,9 +14482,9 @@ parse_parameters(
pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
}
- param = (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous);
+ param = UP(pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous));
} else {
- pm_token_t name;
+ pm_token_t name = { 0 };
bool repeated = false;
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
@@ -14864,11 +14492,10 @@ parse_parameters(
repeated = pm_parser_parameter_name_check(parser, &name);
pm_parser_local_add_token(parser, &name, 1);
} else {
- name = not_provided(parser);
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
}
- param = (pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &operator, &name);
+ param = UP(pm_keyword_rest_parameter_node_create(parser, &operator, NTOK2PTR(name)));
if (repeated) {
pm_node_flag_set_repeated_parameter(param);
}
@@ -14878,27 +14505,14 @@ parse_parameters(
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);
+ pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
}
break;
}
default:
if (parser->previous.type == PM_TOKEN_COMMA) {
- if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
- // 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);
- }
+ parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
}
parsing = false;
@@ -14930,8 +14544,7 @@ parse_parameters(
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);
+ if (PM_NODE_START(params) == PM_NODE_END(params)) {
return NULL;
}
@@ -14948,13 +14561,13 @@ token_newline_index(const pm_parser_t *parser) {
// This is the common case. In this case we can look at the previously
// recorded newline in the newline list and subtract from the current
// offset.
- return parser->newline_list.size - 1;
+ return parser->line_offsets.size - 1;
} else {
// This is unlikely. This is the case that we have already parsed the
// start of a heredoc, so we cannot rely on looking at the previous
// offset of the newline list, and instead must go through the whole
// process of a binary search for the line number.
- return (size_t) pm_newline_list_line(&parser->newline_list, parser->current.start, 0);
+ return (size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
}
}
@@ -14964,7 +14577,7 @@ token_newline_index(const pm_parser_t *parser) {
*/
static int64_t
token_column(const pm_parser_t *parser, size_t newline_index, const pm_token_t *token, bool break_on_non_space) {
- const uint8_t *cursor = parser->start + parser->newline_list.offsets[newline_index];
+ const uint8_t *cursor = parser->start + parser->line_offsets.offsets[newline_index];
const uint8_t *end = token->start;
// Skip over the BOM if it is present.
@@ -15028,8 +14641,8 @@ parser_warn_indentation_mismatch(pm_parser_t *parser, size_t opening_newline_ind
// Otherwise, add a warning.
PM_PARSER_WARN_FORMAT(
parser,
- closing_token->start,
- closing_token->end,
+ PM_TOKEN_START(parser, closing_token),
+ PM_TOKEN_LENGTH(closing_token),
PM_WARN_INDENTATION_MISMATCH,
(int) (closing_token->end - closing_token->start),
(const char *) closing_token->start,
@@ -15053,7 +14666,7 @@ typedef enum {
* 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
+static PRISM_INLINE void
parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t type, uint16_t depth) {
pm_rescue_node_t *current = NULL;
@@ -15069,9 +14682,9 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// 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_rescue_node_operator_set(parser, rescue, &parser->previous);
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
+ pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
reference = parse_target(parser, reference, false, false);
pm_rescue_node_reference_set(rescue, reference);
@@ -15090,7 +14703,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
do {
pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
- pm_rescue_node_exceptions_append(rescue, expression);
+ pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
// If we hit a newline, then this is the end of the rescue expression. We
// can continue on to parse the statements.
@@ -15099,9 +14712,9 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// 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_rescue_node_operator_set(parser, rescue, &parser->previous);
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
+ pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
reference = parse_target(parser, reference, false, false);
pm_rescue_node_reference_set(rescue, reference);
@@ -15114,11 +14727,11 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- rescue->then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(&parser->previous);
+ rescue->then_keyword_loc = TOK2LOC(parser, &parser->previous);
}
} else {
expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
- rescue->then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(&parser->previous);
+ rescue->then_keyword_loc = TOK2LOC(parser, &parser->previous);
}
if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
@@ -15156,11 +14769,10 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// since we won't know the end until we've found all subsequent
// clauses. This sets the end location on all rescues once we know it.
if (current != NULL) {
- const uint8_t *end_to_set = current->base.location.end;
pm_rescue_node_t *clause = parent_node->rescue_clause;
while (clause != NULL) {
- clause->base.location.end = end_to_set;
+ PM_NODE_LENGTH_SET_NODE(clause, current);
clause = clause->subsequent;
}
}
@@ -15203,7 +14815,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
// If we don't have a `current` rescue node, then this is a dangling
// else, and it's an error.
- if (current == NULL) pm_parser_err_node(parser, (pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
+ if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
}
if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
@@ -15241,10 +14853,10 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
if (match1(parser, PM_TOKEN_KEYWORD_END)) {
if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false);
- pm_begin_node_end_keyword_set(parent_node, &parser->current);
+ pm_begin_node_end_keyword_set(parser, 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);
+ pm_token_t end_keyword = (pm_token_t) { .type = PM_TOKEN_KEYWORD_END, .start = parser->previous.end, .end = parser->previous.end };
+ pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
}
}
@@ -15254,11 +14866,11 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_
*/
static pm_begin_node_t *
parse_rescues_implicit_begin(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, const uint8_t *start, pm_statements_node_t *statements, pm_rescues_type_t type, uint16_t depth) {
- pm_token_t begin_keyword = not_provided(parser);
- pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
-
+ pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
parse_rescues(parser, opening_newline_index, opening, node, type, (uint16_t) (depth + 1));
- node->base.location.start = start;
+
+ node->base.location.start = U32(start - parser->start);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
return node;
}
@@ -15277,6 +14889,9 @@ parse_block_parameters(
) {
pm_parameters_node_t *parameters = NULL;
if (!match1(parser, PM_TOKEN_SEMICOLON)) {
+ if (!is_lambda_literal) {
+ context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
+ }
parameters = parse_parameters(
parser,
is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
@@ -15285,12 +14900,16 @@ parse_block_parameters(
false,
accepts_blocks_in_defaults,
true,
+ is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
(uint16_t) (depth + 1)
);
+ if (!is_lambda_literal) {
+ context_pop(parser);
+ }
}
pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
- if ((opening->type != PM_TOKEN_NOT_PROVIDED)) {
+ if (opening != NULL) {
accept1(parser, PM_TOKEN_NEWLINE);
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
@@ -15321,9 +14940,9 @@ parse_block_parameters(
pm_parser_local_add_token(parser, &parser->previous, 1);
pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous);
- if (repeated) pm_node_flag_set_repeated_parameter((pm_node_t *) local);
+ if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
- pm_block_parameters_node_append_local(block_parameters, local);
+ pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
} while (accept1(parser, PM_TOKEN_COMMA));
}
}
@@ -15403,8 +15022,8 @@ parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_
pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
} else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
- } else if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->location.start[1] - '0'));
+ } else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->location.start + 1] - '0'));
} else {
assert(false && "unreachable");
}
@@ -15423,13 +15042,11 @@ parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_
for (pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
}
-
- const pm_location_t location = { .start = opening->start, .end = closing->end };
- return (pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
+ return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
}
if (it_parameter) {
- return (pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
+ return UP(pm_it_parameters_node_create(parser, opening, closing));
}
return NULL;
@@ -15461,7 +15078,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
}
- pm_block_parameters_node_closing_set(block_parameters, &parser->previous);
+ pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
}
accept1(parser, PM_TOKEN_NEWLINE);
@@ -15469,30 +15086,30 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
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, (uint16_t) (depth + 1));
+ statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
}
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
} 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, (uint16_t) (depth + 1));
+ statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
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_implicit_begin(parser, 0, NULL, opening.start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1));
+ statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
}
}
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
}
pm_constant_id_list_t locals;
pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
- pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &opening, &parser->previous);
+ pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
pm_parser_scope_pop(parser);
pm_accepts_block_stack_pop(parser);
@@ -15506,42 +15123,54 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
* arguments, or blocks).
*/
static bool
-parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, bool accepts_command_call, uint16_t depth) {
+parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, uint8_t flags, uint16_t depth) {
+ /* Fast path: if the current token can't begin an expression and isn't
+ * a parenthesis, block opener, or splat/block-pass operator, there are
+ * no arguments to parse. */
+ if (
+ !token_begins_expression_p(parser->current.type) &&
+ !match6(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)
+ ) {
+ return false;
+ }
+
bool found = false;
+ bool parsed_command_args = false;
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
found |= true;
- arguments->opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
+ arguments->opening_loc = TOK2LOC(parser, &parser->previous);
if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
+ arguments->closing_loc = TOK2LOC(parser, &parser->previous);
} else {
pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
+ parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
pm_accepts_block_stack_pop(parser);
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
+ arguments->closing_loc = TOK2LOC(parser, &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)) {
+ } else if ((flags & PM_PARSE_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;
+ parsed_command_args = 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, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
+ parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
// 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_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
}
pm_accepts_block_stack_pop(parser);
@@ -15560,21 +15189,24 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
} else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
found |= true;
block = parse_block(parser, (uint16_t) (depth + 1));
+ } else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
+ found |= true;
+ block = parse_block(parser, (uint16_t) (depth + 1));
}
if (block != NULL) {
if (arguments->block == NULL && !arguments->has_forwarding) {
- arguments->block = (pm_node_t *) block;
+ arguments->block = UP(block);
} else {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
+ pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
if (arguments->block != NULL) {
if (arguments->arguments == NULL) {
arguments->arguments = pm_arguments_node_create(parser);
}
- pm_arguments_node_arguments_append(arguments->arguments, arguments->block);
+ pm_arguments_node_arguments_append(parser->arena, arguments->arguments, arguments->block);
}
- arguments->block = (pm_node_t *) block;
+ arguments->block = UP(block);
}
}
}
@@ -15642,6 +15274,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_BLOCK_ENSURE:
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_RESCUE:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_DEF_ELSE:
case PM_CONTEXT_DEF_ENSURE:
case PM_CONTEXT_DEF_PARAMS:
@@ -15661,7 +15294,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
break;
}
}
- if (in_sclass) {
+ if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
}
}
@@ -15678,6 +15311,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_ELSE:
case PM_CONTEXT_BLOCK_ENSURE:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_DEFINED:
case PM_CONTEXT_FOR:
@@ -15687,12 +15321,19 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
case PM_CONTEXT_LAMBDA_ENSURE:
case PM_CONTEXT_LAMBDA_RESCUE:
case PM_CONTEXT_LOOP_PREDICATE:
- case PM_CONTEXT_POSTEXE:
case PM_CONTEXT_UNTIL:
case PM_CONTEXT_WHILE:
// These are the good cases. We're allowed to have a block exit
// in these contexts.
return;
+ case PM_CONTEXT_POSTEXE:
+ // https://bugs.ruby-lang.org/issues/20409
+ if (context_node->context == PM_CONTEXT_POSTEXE) {
+ if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
+ return;
+ }
+ }
+ PRISM_FALLTHROUGH
case PM_CONTEXT_DEF:
case PM_CONTEXT_DEF_PARAMS:
case PM_CONTEXT_DEF_ELSE:
@@ -15714,7 +15355,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
// block exit to the list of exits for the expression, and
// the node parsing will handle validating it instead.
assert(parser->current_block_exits != NULL);
- pm_node_list_append(parser->current_block_exits, node);
+ pm_node_list_append(parser->arena, parser->current_block_exits, node);
return;
case PM_CONTEXT_BEGIN_ELSE:
case PM_CONTEXT_BEGIN_ENSURE:
@@ -15805,7 +15446,7 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
// However, they could still become valid in a higher level context if
// there is another list above this one. In this case we'll push all of
// the block exits up to the previous list.
- pm_node_list_concat(previous_block_exits, parser->current_block_exits);
+ pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
parser->current_block_exits = previous_block_exits;
} else {
// If we did not match a trailing while/until and this was the last
@@ -15815,11 +15456,11 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
}
}
-static inline pm_node_t *
+static PRISM_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, uint16_t depth) {
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, false, error_id, (uint16_t) (depth + 1));
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, error_id, (uint16_t) (depth + 1));
// 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);
@@ -15837,15 +15478,15 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex
return predicate;
}
-static inline pm_node_t *
+static PRISM_INLINE pm_node_t *
parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else, uint16_t depth) {
pm_node_list_t current_block_exits = { 0 };
pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
pm_token_t keyword = parser->previous;
- pm_token_t then_keyword = not_provided(parser);
+ pm_token_t then_keyword = { 0 };
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
+ pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
pm_statements_node_t *statements = NULL;
if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
@@ -15855,15 +15496,14 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
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);
+ parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
break;
case PM_CONTEXT_UNLESS:
- parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
+ parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
break;
default:
assert(false && "unreachable");
@@ -15877,21 +15517,21 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
if (context == PM_CONTEXT_IF) {
while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
if (parser_end_of_line_p(parser)) {
- PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_KEYWORD_EOL);
+ PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
pm_token_t elsif_keyword = parser->current;
parser_lex(parser);
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
+ pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
pm_accepts_block_stack_push(parser, true);
pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
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_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
((pm_if_node_t *) current)->subsequent = elsif;
current = elsif;
}
@@ -15910,13 +15550,13 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
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)->subsequent = (pm_node_t *) else_node;
+ ((pm_if_node_t *) current)->subsequent = UP(else_node);
break;
case PM_CONTEXT_UNLESS:
((pm_unless_node_t *) parent)->else_clause = else_node;
@@ -15927,7 +15567,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
}
} else {
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
}
// Set the appropriate end location for all of the nodes in the subtree.
@@ -15939,12 +15579,12 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
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);
+ pm_if_node_end_keyword_loc_set(parser, (pm_if_node_t *) current, &parser->previous);
current = ((pm_if_node_t *) current)->subsequent;
recursing = current != NULL;
break;
case PM_ELSE_NODE:
- pm_else_node_end_keyword_loc_set((pm_else_node_t *) current, &parser->previous);
+ pm_else_node_end_keyword_loc_set(parser, (pm_else_node_t *) current, &parser->previous);
recursing = false;
break;
default: {
@@ -15956,7 +15596,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
break;
}
case PM_CONTEXT_UNLESS:
- pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->previous);
+ pm_unless_node_end_keyword_loc_set(parser, (pm_unless_node_t *) parent, &parser->previous);
break;
default:
assert(false && "unreachable");
@@ -15964,8 +15604,6 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
}
pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
return parent;
}
@@ -15976,7 +15614,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
#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_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_BLOCK: 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: \
@@ -16039,7 +15677,7 @@ PM_STATIC_ASSERT(__LINE__, ((int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((int
* 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
+static PRISM_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) {
@@ -16071,10 +15709,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
// "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_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
pm_node_flag_set(node, parse_unescaped_encoding(parser));
parser_lex(parser);
@@ -16101,7 +15736,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
pm_token_t opening = parser->previous;
pm_statements_node_t *statements = NULL;
- if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
+ if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
pm_accepts_block_stack_push(parser, true);
statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
pm_accepts_block_stack_pop(parser);
@@ -16109,9 +15744,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
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;
// If this set of embedded statements only contains a single
// statement, then Ruby does not consider it as a possible statement
@@ -16120,7 +15753,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
pm_node_flag_unset(statements->body.nodes[0], PM_NODE_FLAG_NEWLINE);
}
- return (pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
+ return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
}
// Here the lexer has returned the beginning of an embedded variable.
@@ -16145,42 +15778,42 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
// 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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(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);
+ variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
break;
}
- return (pm_node_t *) pm_embedded_variable_node_create(parser, &operator, variable);
+ return UP(pm_embedded_variable_node_create(parser, &operator, variable));
}
default:
parser_lex(parser);
@@ -16208,18 +15841,16 @@ parse_operator_symbol_name(const pm_token_t *name) {
static pm_node_t *
parse_operator_symbol(pm_parser_t *parser, const pm_token_t *opening, pm_lex_state_t next_state) {
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, &closing);
-
+ pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
const uint8_t *end = parse_operator_symbol_name(&parser->current);
if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
parser_lex(parser);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, end);
- pm_node_flag_set((pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
+ pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
/**
@@ -16253,13 +15884,11 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
break;
}
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
+ pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
+ pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
if (lex_mode->as.string.interpolation) {
@@ -16267,10 +15896,13 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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 = {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->previous.start,
+ .end = parser->previous.start
+ };
- 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);
+ return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
}
// Now we can parse the first part of the symbol.
@@ -16282,15 +15914,15 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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);
+ return UP(pm_string_node_to_symbol_node(parser, (pm_string_node_t *) part, &opening, &parser->previous));
}
pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
- if (part) pm_interpolated_symbol_node_append(symbol, part);
+ if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_interpolated_symbol_node_append(symbol, part);
+ pm_interpolated_symbol_node_append(parser->arena, symbol, part);
}
}
@@ -16301,8 +15933,8 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
}
- pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->previous);
- return (pm_node_t *) symbol;
+ pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
+ return UP(symbol);
}
pm_token_t content;
@@ -16324,13 +15956,11 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
// interpolated string node, so that's what we'll do here.
if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
- pm_token_t bounds = not_provided(parser);
+ pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
+ pm_interpolated_symbol_node_append(parser->arena, symbol, part);
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
- pm_interpolated_symbol_node_append(symbol, part);
-
- part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &parser->current, &bounds, &parser->current_string);
- pm_interpolated_symbol_node_append(symbol, part);
+ part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
+ pm_interpolated_symbol_node_append(parser->arena, symbol, part);
if (next_state != PM_LEX_STATE_NONE) {
lex_state_set(parser, next_state);
@@ -16339,8 +15969,8 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
parser_lex(parser);
expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
- pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->previous);
- return (pm_node_t *) symbol;
+ pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
+ return UP(symbol);
}
} else {
content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end };
@@ -16357,34 +15987,29 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s
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_symbol_encoding(parser, &content, &unescaped, false));
+ return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, false)));
}
/**
* 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 *
+static PRISM_INLINE pm_node_t *
parse_undef_argument(pm_parser_t *parser, uint16_t depth) {
switch (parser->current.type) {
- case PM_CASE_OPERATOR: {
- const pm_token_t opening = not_provided(parser);
- return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
- }
+ case PM_CASE_OPERATOR:
+ return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
case PM_CASE_KEYWORD:
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_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
+ pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
@@ -16394,7 +16019,7 @@ parse_undef_argument(pm_parser_t *parser, uint16_t depth) {
}
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);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
}
@@ -16404,13 +16029,11 @@ parse_undef_argument(pm_parser_t *parser, uint16_t depth) {
* 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 *
+static PRISM_INLINE pm_node_t *
parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) {
switch (parser->current.type) {
- case PM_CASE_OPERATOR: {
- const pm_token_t opening = not_provided(parser);
- return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
- }
+ case PM_CASE_OPERATOR:
+ return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
case PM_CASE_KEYWORD:
case PM_TOKEN_CONSTANT:
case PM_TOKEN_IDENTIFIER:
@@ -16418,14 +16041,11 @@ parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) {
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_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
+ pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
- return (pm_node_t *) symbol;
+ return UP(symbol);
}
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
@@ -16435,16 +16055,16 @@ parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) {
}
case PM_TOKEN_BACK_REFERENCE:
parser_lex(parser);
- return (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
+ return UP(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);
+ return UP(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);
+ return UP(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 UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
}
@@ -16456,10 +16076,10 @@ static pm_node_t *
parse_variable(pm_parser_t *parser) {
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
int depth;
- bool is_numbered_param = pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end);
+ bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
- return (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth, false);
+ return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth, false));
}
pm_scope_t *current_scope = parser->current_scope;
@@ -16478,13 +16098,13 @@ parse_variable(pm_parser_t *parser) {
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
}
- pm_node_t *node = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false);
- pm_node_list_append(&current_scope->implicit_parameters, node);
+ pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false));
+ pm_node_list_append(parser->arena, &current_scope->implicit_parameters, node);
return node;
- } else if ((parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
- pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous);
- pm_node_list_append(&current_scope->implicit_parameters, node);
+ } else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
+ pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
+ pm_node_list_append(parser->arena, &current_scope->implicit_parameters, node);
return node;
}
@@ -16507,9 +16127,9 @@ parse_variable_call(pm_parser_t *parser) {
}
pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
- pm_node_flag_set((pm_node_t *)node, flags);
+ pm_node_flag_set(UP(node), flags);
- return (pm_node_t *) node;
+ return UP(node);
}
/**
@@ -16517,7 +16137,7 @@ parse_variable_call(pm_parser_t *parser) {
* parser. If it does not match a valid method definition name, then a missing
* token is returned.
*/
-static inline pm_token_t
+static PRISM_INLINE pm_token_t
parse_method_definition_name(pm_parser_t *parser) {
switch (parser->current.type) {
case PM_CASE_KEYWORD:
@@ -16526,7 +16146,7 @@ parse_method_definition_name(pm_parser_t *parser) {
parser_lex(parser);
return parser->previous;
case PM_TOKEN_IDENTIFIER:
- pm_refute_numbered_parameter(parser, parser->current.start, parser->current.end);
+ pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
parser_lex(parser);
return parser->previous;
case PM_CASE_OPERATOR:
@@ -16534,22 +16154,31 @@ parse_method_definition_name(pm_parser_t *parser) {
parser_lex(parser);
return parser->previous;
default:
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_NAME, pm_token_type_human(parser->current.type));
- return (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->current.start, .end = parser->current.end };
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
+ return (pm_token_t) { .type = 0, .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);
+parse_heredoc_dedent_string(pm_arena_t *arena, pm_string_t *string, size_t common_whitespace) {
+ // Make a writable copy in the arena if the string isn't already writable.
+ // We keep a mutable pointer to the arena memory so we can memmove into it
+ // below without casting away const from the string's source field.
+ uint8_t *writable;
+
+ if (string->type != PM_STRING_OWNED) {
+ size_t length = pm_string_length(string);
+ writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(string), length, PRISM_ALIGNOF(uint8_t));
+ pm_string_constant_init(string, (const char *) writable, length);
+ } else {
+ writable = (uint8_t *) string->source;
+ }
// 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_cursor = writable;
const uint8_t *source_end = source_cursor + dest_length;
// We're going to move bytes backward in the string when we get leading
@@ -16573,11 +16202,24 @@ parse_heredoc_dedent_string(pm_string_t *string, size_t common_whitespace) {
dest_length--;
}
- memmove((uint8_t *) string->source, source_cursor, (size_t) (source_end - source_cursor));
+ memmove(writable, source_cursor, (size_t) (source_end - source_cursor));
string->length = dest_length;
}
/**
+ * If we end up trimming all of the whitespace from a node and it isn't
+ * part of a line continuation, then we'll drop it from the list entirely.
+ */
+static PRISM_INLINE bool
+heredoc_dedent_discard_string_node(pm_parser_t *parser, pm_string_node_t *string_node) {
+ if (string_node->unescaped.length == 0) {
+ const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->content_loc);
+ return pm_memchr(cursor, '\\', string_node->content_loc.length, parser->encoding_changed, parser->encoding) == NULL;
+ }
+ return false;
+}
+
+/**
* Take a heredoc node that is indented by a ~ and trim the leading whitespace.
*/
static void
@@ -16587,8 +16229,7 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
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.
+ // keep around two indices: a read and a write.
size_t write_index = 0;
pm_node_t *node;
@@ -16604,11 +16245,10 @@ parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_w
pm_string_node_t *string_node = ((pm_string_node_t *) node);
if (dedent_next) {
- parse_heredoc_dedent_string(&string_node->unescaped, common_whitespace);
+ parse_heredoc_dedent_string(parser->arena, &string_node->unescaped, common_whitespace);
}
- if (string_node->unescaped.length == 0) {
- pm_node_destroy(parser, node);
+ if (heredoc_dedent_discard_string_node(parser, string_node)) {
} else {
nodes->nodes[write_index++] = node;
}
@@ -16631,7 +16271,7 @@ parse_strings_empty_content(const uint8_t *location) {
/**
* Parse a set of strings that could be concatenated together.
*/
-static inline pm_node_t *
+static PRISM_INLINE pm_node_t *
parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint16_t depth) {
assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
bool concating = false;
@@ -16658,16 +16298,14 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
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;
+ node = UP(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 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;
+ pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
+ pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.start);
+ node = UP(symbol);
if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
} else if (!lex_interpolation) {
@@ -16678,7 +16316,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
if (match1(parser, PM_TOKEN_EOF)) {
unescaped = PM_STRING_EMPTY;
- content = not_provided(parser);
+ content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
} else {
unescaped = parser->current_string;
expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
@@ -16698,34 +16336,30 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
// 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);
+ pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
+ pm_node_list_append(parser->arena, &parts, part);
do {
- part = (pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->current, &delimiters);
- pm_node_list_append(&parts, part);
+ part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ pm_node_list_append(parser->arena, &parts, part);
parser_lex(parser);
} while (match1(parser, PM_TOKEN_STRING_CONTENT));
expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
-
- pm_node_list_free(&parts);
+ node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
} else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true));
+ node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true)));
if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
} else if (match1(parser, PM_TOKEN_EOF)) {
pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
+ node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
} else if (accept1(parser, PM_TOKEN_STRING_END)) {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
+ node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
} else {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_type_human(parser->previous.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
+ parser->previous.type = 0;
+ node = UP(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
@@ -16737,7 +16371,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
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);
+ node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
pm_node_flag_set(node, parse_unescaped_encoding(parser));
// Kind of odd behavior, but basically if we have an
@@ -16747,43 +16381,38 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
if (!accept1(parser, PM_TOKEN_STRING_END)) {
const uint8_t *location = parser->previous.end;
if (location > parser->start && location[-1] == '\n') location--;
- pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
+ pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
} else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true));
+ node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true)));
if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
} 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_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
pm_node_flag_set(part, parse_unescaped_encoding(parser));
- pm_node_list_append(&parts, part);
+ pm_node_list_append(parser->arena, &parts, part);
while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_node_list_append(&parts, part);
+ pm_node_list_append(parser->arena, &parts, part);
}
}
if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
+ node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
} 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);
+ node = UP(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);
+ node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
}
-
- pm_node_list_free(&parts);
}
} else {
// If we get here, then the first part of the string is not plain
@@ -16794,22 +16423,20 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_node_list_append(&parts, part);
+ pm_node_list_append(parser->arena, &parts, part);
}
}
if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
+ node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
} 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);
+ node = UP(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);
+ node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
}
-
- pm_node_list_free(&parts);
}
if (current == NULL) {
@@ -16839,14 +16466,12 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
}
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_t *container = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, container, current);
+ current = UP(container);
}
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
+ pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, node);
}
}
@@ -16868,12 +16493,12 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
static void
parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location) {
// Skip this capture if it starts with an underscore.
- if (*location->start == '_') return;
+ if (peek_at(parser, parser->start + location->start) == '_') return;
if (pm_constant_id_list_includes(captures, capture)) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
+ pm_parser_err(parser, location->start, location->length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
} else {
- pm_constant_id_list_append(captures, capture);
+ pm_constant_id_list_append(parser->arena, captures, capture);
}
}
@@ -16887,7 +16512,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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);
- node = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
+ node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
}
// If there is a [ or ( that follows, then this is part of a larger pattern
@@ -16908,7 +16533,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
+ expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
}
closing = parser->previous;
@@ -16920,7 +16545,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
}
closing = parser->previous;
@@ -16929,7 +16554,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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);
+ return UP(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,
@@ -16940,15 +16565,15 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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;
+ if (pattern_node->constant == NULL && pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(pattern_node, node);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -16956,15 +16581,15 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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;
+ if (pattern_node->constant == NULL && pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(pattern_node, node);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -16972,15 +16597,15 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
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;
+ if (pattern_node->constant == NULL && pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_NODE(pattern_node, node);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -16993,8 +16618,8 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
// 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;
+ pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
+ return UP(pattern_node);
}
/**
@@ -17010,21 +16635,20 @@ parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
// 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_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
+ pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
int depth;
if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
- pm_parser_local_add(parser, constant_id, identifier.start, identifier.end, 0);
+ pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
- name = (pm_node_t *) pm_local_variable_target_node_create(
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
+ name = UP(pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&identifier),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
- );
+ ));
}
// Finally we can return the created node.
@@ -17043,7 +16667,7 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
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);
+ return UP(pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous));
}
if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
@@ -17054,16 +16678,16 @@ parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures)
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
- value = (pm_node_t *) pm_local_variable_target_node_create(
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
+ value = UP(pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
- );
+ ));
}
- return (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
+ return UP(pm_assoc_splat_node_create(parser, value, &operator));
}
/**
@@ -17100,22 +16724,24 @@ pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const u
static pm_node_t *
parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key) {
const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
+ const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
+ const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
+ pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
int depth = -1;
- if (pm_slice_is_valid_local(parser, value_loc->start, value_loc->end)) {
+ if (pm_slice_is_valid_local(parser, start, end)) {
depth = pm_parser_local_depth_constant_id(parser, constant_id);
} else {
- pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
+ pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
- if ((value_loc->end > value_loc->start) && ((value_loc->end[-1] == '!') || (value_loc->end[-1] == '?'))) {
- PM_PARSER_ERR_LOCATION_FORMAT(parser, value_loc, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (int) (value_loc->end - value_loc->start), (const char *) value_loc->start);
+ if ((end > start) && ((end[-1] == '!') || (end[-1] == '?'))) {
+ PM_PARSER_ERR_FORMAT(parser, value_loc->start, value_loc->length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (int) (end - start), (const char *) start);
}
}
if (depth == -1) {
- pm_parser_local_add(parser, constant_id, value_loc->start, value_loc->end, 0);
+ pm_parser_local_add(parser, constant_id, start, end, 0);
}
parse_pattern_capture(parser, captures, constant_id, value_loc);
@@ -17126,7 +16752,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca
(uint32_t) (depth == -1 ? 0 : depth)
);
- return (pm_node_t *) pm_implicit_node_create(parser, (pm_node_t *) target);
+ return UP(pm_implicit_node_create(parser, UP(target)));
}
/**
@@ -17135,7 +16761,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca
*/
static void
parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_t *node) {
- if (pm_static_literals_add(&parser->newline_list, parser->start_line, keys, node, true) != NULL) {
+ if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, keys, node, true) != NULL) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
}
}
@@ -17154,25 +16780,31 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
case PM_NO_KEYWORDS_PARAMETER_NODE:
rest = first_node;
break;
+ case PM_INTERPOLATED_SYMBOL_NODE:
case PM_SYMBOL_NODE: {
- if (pm_symbol_node_label_p(first_node)) {
- parse_pattern_hash_key(parser, &keys, first_node);
+ if (pm_symbol_node_label_p(parser, first_node)) {
+ if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
+ pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
+ } else {
+ parse_pattern_hash_key(parser, &keys, first_node);
+ }
+
pm_node_t *value;
if (match8(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, PM_TOKEN_EOF)) {
- // Otherwise, we will create an implicit local variable
- // target for the value.
- value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
+ if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
+ value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
+ } else {
+ value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
+ }
} else {
// Here we have a value for the first assoc in the list, so
// we will parse it now.
value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
}
- pm_token_t operator = not_provided(parser);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &operator, value);
-
- pm_node_list_append(&assocs, assoc);
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
+ pm_node_list_append(parser->arena, &assocs, assoc);
break;
}
}
@@ -17184,11 +16816,10 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
pm_diagnostic_id_t diag_id = PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE) ? PM_ERR_PATTERN_HASH_KEY_INTERPOLATED : PM_ERR_PATTERN_HASH_KEY_LABEL;
pm_parser_err_node(parser, first_node, diag_id);
- pm_token_t operator = not_provided(parser);
- pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, first_node->location.start, first_node->location.end);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &operator, value);
+ pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
- pm_node_list_append(&assocs, assoc);
+ pm_node_list_append(parser->arena, &assocs, assoc);
break;
}
}
@@ -17212,7 +16843,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
rest = assoc;
} else {
pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- pm_node_list_append(&assocs, assoc);
+ pm_node_list_append(parser->arena, &assocs, assoc);
}
} else {
pm_node_t *key;
@@ -17222,36 +16853,43 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
- } else if (!pm_symbol_node_label_p(key)) {
+ } else if (!pm_symbol_node_label_p(parser, key)) {
pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
}
+ } else if (accept1(parser, PM_TOKEN_LABEL)) {
+ key = UP(pm_symbol_node_label_create(parser, &parser->previous));
} else {
expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
- key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
+
+ pm_token_t label = { .type = PM_TOKEN_LABEL, .start = parser->previous.end, .end = parser->previous.end };
+ key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
}
parse_pattern_hash_key(parser, &keys, key);
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_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
+ if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
+ value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
+ } else {
+ value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
+ }
} else {
value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
}
- pm_token_t operator = not_provided(parser);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
if (rest != NULL) {
pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
}
- pm_node_list_append(&assocs, assoc);
+ pm_node_list_append(parser->arena, &assocs, assoc);
}
}
pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
- xfree(assocs.nodes);
+ // assocs.nodes is arena-allocated; no explicit free needed.
pm_static_literals_free(&keys);
return node;
@@ -17273,13 +16911,13 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
- return (pm_node_t *) pm_local_variable_target_node_create(
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
+ return UP(pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
- );
+ ));
}
case PM_TOKEN_BRACKET_LEFT_ARRAY: {
pm_token_t opening = parser->current;
@@ -17288,7 +16926,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
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);
+ return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
}
// Otherwise, we'll parse the inner pattern, then deal with it depending
@@ -17296,34 +16934,34 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
+ expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
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;
+ if (pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(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;
+ if (pattern_node->opening_loc.length == 0) {
+ PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ pattern_node->opening_loc = TOK2LOC(parser, &opening);
+ pattern_node->closing_loc = TOK2LOC(parser, &closing);
- return (pm_node_t *) pattern_node;
+ return UP(pattern_node);
}
break;
@@ -17333,8 +16971,8 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
}
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;
+ pm_array_pattern_node_requireds_append(parser->arena, node, inner);
+ return UP(node);
}
case PM_TOKEN_BRACE_LEFT: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -17354,19 +16992,19 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
switch (parser->current.type) {
case PM_TOKEN_LABEL:
parser_lex(parser);
- first_node = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
+ first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
break;
case PM_TOKEN_USTAR_STAR:
first_node = parse_pattern_keyword_rest(parser, captures);
break;
case PM_TOKEN_STRING_BEGIN:
- first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
+ first_node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
break;
default: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
parser_lex(parser);
- first_node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
+ first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
break;
}
}
@@ -17374,18 +17012,18 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
pm_token_t closing = parser->previous;
- node->base.location.start = opening.start;
- node->base.location.end = closing.end;
+ PM_NODE_START_SET_TOKEN(parser, node, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
- node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
+ node->opening_loc = TOK2LOC(parser, &opening);
+ node->closing_loc = TOK2LOC(parser, &closing);
}
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_UDOT_DOT:
case PM_TOKEN_UDOT_DOT_DOT: {
@@ -17396,21 +17034,27 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
// 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, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
+ return UP(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);
+ pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &operator), PM_TOKEN_LENGTH(&operator)));
+ return UP(pm_range_node_create(parser, NULL, &operator, right));
}
}
}
case PM_CASE_PRIMITIVE: {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, diag_id, (uint16_t) (depth + 1));
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_LABEL | PM_PARSE_ACCEPTS_DO_BLOCK, diag_id, (uint16_t) (depth + 1));
// If we found a label, we need to immediately return to the caller.
- if (pm_symbol_node_label_p(node)) return node;
+ if (pm_symbol_node_label_p(parser, node)) return node;
+
+ // Call nodes (arithmetic operations) are not allowed in patterns
+ if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
+ pm_parser_err_node(parser, node, diag_id);
+ return UP(pm_error_recovery_node_create_unexpected(parser, node));
+ }
// 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)) {
@@ -17421,11 +17065,11 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
// 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, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, right);
+ pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
+ return UP(pm_range_node_create(parser, node, &operator, right));
}
default:
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, NULL);
+ return UP(pm_range_node_create(parser, node, &operator, NULL));
}
}
@@ -17440,44 +17084,44 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER: {
parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) parse_variable(parser);
+ pm_node_t *variable = UP(parse_variable(parser));
if (variable == NULL) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
- variable = (pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->previous, 0);
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
+ variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
}
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(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);
+ pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
+ return UP(pm_pinned_variable_node_create(parser, &operator, variable));
}
case PM_TOKEN_PARENTHESIS_LEFT: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -17486,19 +17130,19 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
pm_token_t lparen = parser->current;
parser_lex(parser);
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
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);
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
+ return UP(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);
+ pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &operator), PM_TOKEN_LENGTH(&operator)));
+ return UP(pm_pinned_variable_node_create(parser, &operator, variable));
}
}
}
@@ -17509,31 +17153,56 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous);
- return parse_pattern_constant_path(parser, captures, (pm_node_t *) node, (uint16_t) (depth + 1));
+ return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
}
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);
+ pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
}
default:
pm_parser_err_current(parser, diag_id);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
+ }
+}
+
+static bool
+parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
+ switch (PM_NODE_TYPE(node)) {
+ case PM_LOCAL_VARIABLE_TARGET_NODE: {
+ pm_parser_t *parser = (pm_parser_t *) data;
+ pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
+ return false;
+ }
+ default:
+ return true;
}
}
/**
+ * When we get here, we know that we already have a syntax error, because we
+ * know we have captured a variable and that we are in an alternation.
+ */
+static void
+parse_pattern_alternation_error(pm_parser_t *parser, const pm_node_t *node) {
+ pm_visit_node(node, parse_pattern_alternation_error_each, parser);
+}
+
+/**
* 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_constant_id_list_t *captures, pm_node_t *first_node, pm_diagnostic_id_t diag_id, uint16_t depth) {
pm_node_t *node = first_node;
+ bool alternation = false;
- while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
- pm_token_t operator = parser->previous;
+ while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
+ if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->size) {
+ parse_pattern_alternation_error(parser, node);
+ }
switch (parser->current.type) {
case PM_TOKEN_IDENTIFIER:
@@ -17545,41 +17214,47 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
case PM_TOKEN_UDOT_DOT:
case PM_TOKEN_UDOT_DOT_DOT:
case PM_CASE_PRIMITIVE: {
- if (node == NULL) {
+ if (!alternation) {
node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
} else {
+ pm_token_t operator = parser->previous;
pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
+
+ if (captures->size) parse_pattern_alternation_error(parser, right);
+ node = UP(pm_alternation_pattern_node_create(parser, node, right, &operator));
}
break;
}
case PM_TOKEN_PARENTHESIS_LEFT:
case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
+ pm_token_t operator = parser->previous;
pm_token_t opening = parser->current;
parser_lex(parser);
pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0);
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
+ pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
- if (node == NULL) {
+ if (!alternation) {
node = right;
} else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
+ if (captures->size) parse_pattern_alternation_error(parser, right);
+ node = UP(pm_alternation_pattern_node_create(parser, node, right, &operator));
}
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);
+ pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
- if (node == NULL) {
+ if (!alternation) {
node = right;
} else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
+ if (captures->size) parse_pattern_alternation_error(parser, right);
+ node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
}
break;
@@ -17600,15 +17275,15 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
}
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
+ parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
+ &TOK2LOC(parser, &parser->previous),
constant_id,
(uint32_t) (depth == -1 ? 0 : depth)
);
- node = (pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &operator);
+ node = UP(pm_capture_pattern_node_create(parser, node, target, &operator));
}
return node;
@@ -17627,8 +17302,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
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);
- node = (pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
+ pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
+ node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
if (!(flags & PM_PARSE_PATTERN_TOP)) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17638,7 +17313,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
}
case PM_TOKEN_USTAR_STAR: {
node = parse_pattern_keyword_rest(parser, captures);
- node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
+ node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
if (!(flags & PM_PARSE_PATTERN_TOP)) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17651,8 +17326,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// be dynamic symbols leading to hash patterns.
node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
- if (pm_symbol_node_label_p(node)) {
- node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
+ if (pm_symbol_node_label_p(parser, node)) {
+ node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
if (!(flags & PM_PARSE_PATTERN_TOP)) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
@@ -17667,7 +17342,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
case PM_TOKEN_USTAR: {
if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
parser_lex(parser);
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
+ node = UP(parse_pattern_rest(parser, captures));
leading_rest = true;
break;
}
@@ -17680,8 +17355,8 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// 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)) {
- return (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
+ if (pm_symbol_node_label_p(parser, node)) {
+ return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
}
if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
@@ -17689,20 +17364,20 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// 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);
+ pm_node_list_append(parser->arena, &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 (match9(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE, PM_TOKEN_EOF,PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
- node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_node_list_append(&nodes, node);
+ if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
+ node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
+ pm_node_list_append(parser->arena, &nodes, node);
trailing_rest = true;
break;
}
if (accept1(parser, PM_TOKEN_USTAR)) {
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
+ node = UP(parse_pattern_rest(parser, captures));
// If we have already parsed a splat pattern, then this is an
// error. We will continue to parse the rest of the patterns,
@@ -17716,7 +17391,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
}
- pm_node_list_append(&nodes, node);
+ pm_node_list_append(parser->arena, &nodes, node);
}
// If the first pattern and the last pattern are rest patterns, then we
@@ -17724,24 +17399,24 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
// are in between because we know we already added the appropriate
// errors. Otherwise we will create an array pattern.
if (leading_rest && PM_NODE_TYPE_P(nodes.nodes[nodes.size - 1], PM_SPLAT_NODE)) {
- node = (pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
+ node = UP(pm_find_pattern_node_create(parser, &nodes));
if (nodes.size == 2) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
}
} else {
- node = (pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
+ node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
if (leading_rest && trailing_rest) {
pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
}
}
- xfree(nodes.nodes);
+ // nodes.nodes is arena-allocated; no explicit free needed.
} 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);
+ node = UP(pm_array_pattern_node_rest_create(parser, node));
}
return node;
@@ -17752,29 +17427,33 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
* from its start bounds. If it's a compound node, then we will recursively
* apply this function to its value.
*/
-static inline void
+static PRISM_INLINE void
parse_negative_numeric(pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE: {
pm_integer_node_t *cast = (pm_integer_node_t *) node;
cast->base.location.start--;
+ cast->base.location.length++;
cast->value.negative = true;
break;
}
case PM_FLOAT_NODE: {
pm_float_node_t *cast = (pm_float_node_t *) node;
cast->base.location.start--;
+ cast->base.location.length++;
cast->value = -cast->value;
break;
}
case PM_RATIONAL_NODE: {
pm_rational_node_t *cast = (pm_rational_node_t *) node;
cast->base.location.start--;
+ cast->base.location.length++;
cast->numerator.negative = true;
break;
}
case PM_IMAGINARY_NODE:
node->location.start--;
+ node->location.length++;
parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
break;
default:
@@ -17792,22 +17471,22 @@ static void
pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
switch (diag_id) {
case PM_ERR_HASH_KEY: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, pm_token_type_human(parser->previous.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.type));
break;
}
case PM_ERR_HASH_VALUE:
case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
break;
}
case PM_ERR_UNARY_RECEIVER: {
- const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_type_human(parser->current.type));
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, human, parser->previous.start[0]);
+ const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_str(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.start[0]);
break;
}
case PM_ERR_UNARY_DISALLOWED:
case PM_ERR_EXPECT_ARGUMENT: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
break;
}
default:
@@ -17887,6 +17566,7 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) {
case PM_CONTEXT_BEGIN:
case PM_CONTEXT_BLOCK_BRACES:
case PM_CONTEXT_BLOCK_KEYWORDS:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_CASE_IN:
case PM_CONTEXT_CASE_WHEN:
case PM_CONTEXT_DEFAULT_PARAMS:
@@ -17967,6 +17647,7 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
case PM_CONTEXT_BLOCK_KEYWORDS:
case PM_CONTEXT_BLOCK_ELSE:
case PM_CONTEXT_BLOCK_ENSURE:
+ case PM_CONTEXT_BLOCK_PARAMETERS:
case PM_CONTEXT_BLOCK_RESCUE:
case PM_CONTEXT_CASE_IN:
case PM_CONTEXT_CASE_WHEN:
@@ -18003,67 +17684,1383 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
}
/**
- * This struct is used to pass information between the regular expression parser
- * and the error callback.
+ * Determine if a given call node looks like a "command", which means it has
+ * arguments but does not have parentheses.
*/
-typedef struct {
- /** The parser that we are parsing the regular expression for. */
- pm_parser_t *parser;
+static PRISM_INLINE bool
+pm_call_node_command_p(const pm_call_node_t *node) {
+ return (
+ (node->opening_loc.length == 0) &&
+ (node->block == NULL || PM_NODE_TYPE_P(node->block, PM_BLOCK_ARGUMENT_NODE)) &&
+ (node->arguments != NULL || node->block != NULL)
+ );
+}
- /** The start of the regular expression. */
- const uint8_t *start;
+/**
+ * Returns true if the given node is a command-style call (a method call without
+ * parentheses that has arguments), excluding operator calls (e.g., a + b) which
+ * satisfy the same structural criteria but are not commands.
+ */
+static bool
+pm_command_call_value_p(const pm_node_t *node) {
+ switch (PM_NODE_TYPE(node)) {
+ case PM_CALL_NODE: {
+ const pm_call_node_t *call = (const pm_call_node_t *) node;
- /** The end of the regular expression. */
- const uint8_t *end;
+ // Command-style calls (e.g., foo bar, obj.foo bar).
+ // Attribute writes (e.g., a.b = 1) are not commands.
+ if (pm_call_node_command_p(call) && !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && (call->receiver == NULL || call->call_operator_loc.length > 0)) {
+ return true;
+ }
- /**
- * Whether or not the source of the regular expression is shared. This
- * impacts the location of error messages, because if it is shared then we
- * can use the location directly and if it is not, then we use the bounds of
- * the regular expression itself.
- */
- bool shared;
-} parse_regular_expression_error_data_t;
+ // A `!` or `not` prefix wrapping a command call (e.g.,
+ // `!foo bar`, `not foo bar`) is also a command-call value.
+ if (call->receiver != NULL && call->arguments == NULL && call->opening_loc.length == 0 && call->call_operator_loc.length == 0) {
+ return pm_command_call_value_p(call->receiver);
+ }
+
+ return false;
+ }
+ case PM_SUPER_NODE: {
+ const pm_super_node_t *cast = (const pm_super_node_t *) node;
+ return cast->lparen_loc.length == 0 && (cast->arguments != NULL || cast->block != NULL);
+ }
+ case PM_YIELD_NODE: {
+ const pm_yield_node_t *cast = (const pm_yield_node_t *) node;
+ return cast->lparen_loc.length == 0 && cast->arguments != NULL;
+ }
+ case PM_RESCUE_MODIFIER_NODE:
+ return pm_command_call_value_p(((const pm_rescue_modifier_node_t *) node)->expression);
+ case PM_DEF_NODE: {
+ const pm_def_node_t *cast = (const pm_def_node_t *) node;
+ if (cast->equal_loc.length > 0 && cast->body != NULL) {
+ const pm_node_t *body = cast->body;
+ if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
+ body = ((const pm_statements_node_t *) body)->body.nodes[((const pm_statements_node_t *) body)->body.size - 1];
+ }
+ return pm_command_call_value_p(body);
+ }
+ return false;
+ }
+ default:
+ return false;
+ }
+}
/**
- * This callback is called when the regular expression parser encounters a
- * syntax error.
+ * Returns true if the given node is a block call: a command
+ * with a do-block, or any call chained (via `.`, `::`, `&.`) from such a node.
+ * Block calls can only be followed by call chaining, composition (and/or), and
+ * modifier operators.
*/
-static void
-parse_regular_expression_error(const uint8_t *start, const uint8_t *end, const char *message, void *data) {
- parse_regular_expression_error_data_t *callback_data = (parse_regular_expression_error_data_t *) data;
- pm_location_t location;
+static bool
+pm_block_call_p(const pm_node_t *node) {
+ while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
+ const pm_call_node_t *call = (const pm_call_node_t *) node;
+ if (call->opening_loc.length > 0) return false;
+
+ // Root: command with do-block (e.g., `foo bar do end`).
+ if (call->arguments != NULL && call->block != NULL && PM_NODE_TYPE_P(call->block, PM_BLOCK_NODE)) {
+ return true;
+ }
- if (callback_data->shared) {
- location = (pm_location_t) { .start = start, .end = end };
+ // Walk up the receiver chain (e.g., `foo bar do end.baz`).
+ if (call->call_operator_loc.length > 0 && call->receiver != NULL) {
+ node = call->receiver;
+ continue;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+/**
+ * Parse a case expression (the `case` keyword). This handles both case-when and
+ * case-in (pattern matching) forms.
+ */
+static pm_node_t *
+parse_case(pm_parser_t *parser, uint8_t flags, uint16_t depth) {
+ size_t opening_newline_index = token_newline_index(parser);
+ parser_lex(parser);
+
+ pm_token_t case_keyword = parser->previous;
+ pm_node_t *predicate = NULL;
+
+ pm_node_list_t current_block_exits = { 0 };
+ pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
+
+ 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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
+ while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
+ }
+
+ if (match1(parser, PM_TOKEN_KEYWORD_END)) {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
+ parser_lex(parser);
+ pop_block_exits(parser, previous_block_exits);
+ pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
+ return UP(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_node_t *node;
+
+ if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
+ pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
+ pm_static_literals_t literals = { 0 };
+
+ /* 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 (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true);
+ parser_lex(parser);
+
+ 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, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+
+ pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression);
+ pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
+
+ if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE)) break;
+ } else {
+ pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
+ pm_when_node_conditions_append(parser->arena, when_node, condition);
+
+ /* If we found a missing node, then this is a syntax error
+ * and we should stop looping. */
+ if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE)) break;
+
+ /* If this is a string node, then we need to mark it as
+ * frozen because when clause strings are frozen. */
+ if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
+ pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
+ } else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
+ pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
+ }
+
+ pm_when_clause_static_literals_add(parser, &literals, condition);
+ }
+ } while (accept1(parser, PM_TOKEN_COMMA));
+
+ if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
+ if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
+ pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
+ }
+ } else {
+ expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
+ pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
+ }
+
+ 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, (uint16_t) (depth + 1));
+ if (statements != NULL) {
+ pm_when_node_statements_set(when_node, statements);
+ }
+ }
+
+ pm_case_node_condition_append(parser->arena, case_node, UP(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);
+ }
+
+ pm_static_literals_free(&literals);
+ node = UP(case_node);
+ } else {
+ pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
+
+ /* 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)) {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true);
+
+ 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_constant_id_list_t captures = { 0 };
+ pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
+
+ 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_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
+ pattern = UP(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_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
+ pattern = UP(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 = { 0 };
+ if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
+ if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
+ then_keyword = parser->previous;
+ }
+ } else {
+ expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_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, (uint16_t) (depth + 1));
+ }
+
+ /* 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 = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
+ pm_case_match_node_condition_append(parser->arena, 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 = UP(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, (uint16_t) (depth + 1)), &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_else_clause_set((pm_case_node_t *) node, else_node);
+ } else {
+ pm_case_match_node_else_clause_set((pm_case_match_node_t *) node, else_node);
+ }
+ }
+
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
+
+ if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
+ pm_case_node_end_keyword_loc_set(parser, (pm_case_node_t *) node, &parser->previous);
} else {
- location = (pm_location_t) { .start = callback_data->start, .end = callback_data->end };
+ pm_case_match_node_end_keyword_loc_set(parser, (pm_case_match_node_t *) node, &parser->previous);
}
- PM_PARSER_ERR_FORMAT(callback_data->parser, location.start, location.end, PM_ERR_REGEXP_PARSE_ERROR, message);
+ pop_block_exits(parser, previous_block_exits);
+ return node;
}
/**
- * Parse the errors for the regular expression and add them to the parser.
+ * Parse a class definition expression (the `class` keyword). This handles both
+ * regular class definitions and singleton class definitions (`class << expr`).
*/
-static void
-parse_regular_expression_errors(pm_parser_t *parser, pm_regular_expression_node_t *node) {
- const pm_string_t *unescaped = &node->unescaped;
- parse_regular_expression_error_data_t error_data = {
- .parser = parser,
- .start = node->base.location.start,
- .end = node->base.location.end,
- .shared = unescaped->type == PM_STRING_SHARED
- };
+static pm_node_t *
+parse_class(pm_parser_t *parser, uint8_t flags, uint16_t depth) {
+ size_t opening_newline_index = token_newline_index(parser);
+ parser_lex(parser);
+
+ pm_token_t class_keyword = parser->previous;
+ pm_do_loop_stack_push(parser, false);
+
+ pm_node_list_t current_block_exits = { 0 };
+ pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
+
+ if (accept1(parser, PM_TOKEN_LESS_LESS)) {
+ pm_token_t operator = parser->previous;
+ pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
+
+ pm_parser_scope_push(parser, true);
+ if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
+ }
+
+ pm_node_t *statements = NULL;
+ if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
+ pm_accepts_block_stack_push(parser, true);
+ statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
+ 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 = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1)));
+ } else {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
+ }
+
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
+
+ pm_constant_id_list_t locals;
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
+
+ pm_parser_scope_pop(parser);
+ pm_do_loop_stack_pop(parser);
+
+ flush_block_exits(parser, previous_block_exits);
+ return UP(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, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
+ 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 = { 0 };
+ 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, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
+ } else {
+ superclass = NULL;
+ }
+
+ pm_parser_scope_push(parser, true);
+
+ if (inheritance_operator.start != NULL) {
+ 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 (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
+ pm_accepts_block_stack_push(parser, true);
+ statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
+ 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 = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1)));
+ } else {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
+ }
+
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
+
+ if (context_def_p(parser)) {
+ pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
+ }
- pm_regexp_parse(parser, pm_string_source(unescaped), pm_string_length(unescaped), PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED), NULL, NULL, parse_regular_expression_error, &error_data);
+ pm_constant_id_list_t locals;
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
+
+ pm_parser_scope_pop(parser);
+ pm_do_loop_stack_pop(parser);
+
+ if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
+ pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
+ if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
+ constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
+ }
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+ return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
+}
+
+/**
+ * Parse a method definition expression (the `def` keyword).
+ */
+static pm_node_t *
+parse_def(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
+ pm_node_list_t current_block_exits = { 0 };
+ pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
+
+ pm_token_t def_keyword = parser->current;
+ size_t opening_newline_index = token_newline_index(parser);
+
+ pm_node_t *receiver = NULL;
+ pm_token_t operator = { 0 };
+ pm_token_t name;
+
+ /* 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);
+
+ /* This will be false if the method name is not a valid identifier but could
+ * be followed by an operator. */
+ bool valid_name = true;
+
+ switch (parser->current.type) {
+ case PM_CASE_OPERATOR:
+ pm_parser_scope_push(parser, true);
+ lex_state_set(parser, PM_LEX_STATE_ENDFN);
+ parser_lex(parser);
+
+ name = parser->previous;
+ break;
+ case PM_TOKEN_IDENTIFIER: {
+ parser_lex(parser);
+
+ if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
+ receiver = parse_variable_call(parser);
+
+ pm_parser_scope_push(parser, true);
+ lex_state_set(parser, PM_LEX_STATE_FNAME);
+ parser_lex(parser);
+
+ operator = parser->previous;
+ name = parse_method_definition_name(parser);
+ } else {
+ pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
+ pm_parser_scope_push(parser, true);
+
+ name = parser->previous;
+ }
+
+ break;
+ }
+ case PM_TOKEN_INSTANCE_VARIABLE:
+ case PM_TOKEN_CLASS_VARIABLE:
+ case PM_TOKEN_GLOBAL_VARIABLE:
+ valid_name = false;
+ PRISM_FALLTHROUGH
+ case PM_TOKEN_CONSTANT:
+ case PM_TOKEN_KEYWORD_NIL:
+ case PM_TOKEN_KEYWORD_SELF:
+ case PM_TOKEN_KEYWORD_TRUE:
+ case PM_TOKEN_KEYWORD_FALSE:
+ case PM_TOKEN_KEYWORD___FILE__:
+ case PM_TOKEN_KEYWORD___LINE__:
+ case PM_TOKEN_KEYWORD___ENCODING__: {
+ pm_parser_scope_push(parser, true);
+ parser_lex(parser);
+
+ pm_token_t identifier = parser->previous;
+
+ if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
+ lex_state_set(parser, PM_LEX_STATE_FNAME);
+ parser_lex(parser);
+ operator = parser->previous;
+
+ switch (identifier.type) {
+ case PM_TOKEN_CONSTANT:
+ receiver = UP(pm_constant_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_INSTANCE_VARIABLE:
+ receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_CLASS_VARIABLE:
+ receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_GLOBAL_VARIABLE:
+ receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_NIL:
+ receiver = UP(pm_nil_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_SELF:
+ receiver = UP(pm_self_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_TRUE:
+ receiver = UP(pm_true_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD_FALSE:
+ receiver = UP(pm_false_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD___FILE__:
+ receiver = UP(pm_source_file_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD___LINE__:
+ receiver = UP(pm_source_line_node_create(parser, &identifier));
+ break;
+ case PM_TOKEN_KEYWORD___ENCODING__:
+ receiver = UP(pm_source_encoding_node_create(parser, &identifier));
+ break;
+ default:
+ break;
+ }
+
+ name = parse_method_definition_name(parser);
+ } else {
+ if (!valid_name) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.type));
+ }
+
+ 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_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
+
+ accept1(parser, PM_TOKEN_NEWLINE);
+ 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 = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
+
+ /* To push `PM_CONTEXT_DEF_PARAMS` again is for the same reason as
+ * described the above. */
+ pm_parser_scope_push(parser, true);
+ context_push(parser, PM_CONTEXT_DEF_PARAMS);
+ name = parse_method_definition_name(parser);
+ break;
+ }
+ default:
+ pm_parser_scope_push(parser, true);
+ name = parse_method_definition_name(parser);
+ break;
+ }
+
+ pm_token_t lparen = { 0 };
+ pm_token_t rparen = { 0 };
+ pm_parameters_node_t *params;
+
+ bool accept_endless_def = true;
+ 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 {
+ /* https://bugs.ruby-lang.org/issues/19107 */
+ bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
+ params = parse_parameters(
+ parser,
+ PM_BINDING_POWER_DEFINED,
+ true,
+ allow_trailing_comma,
+ true,
+ true,
+ false,
+ PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
+ (uint16_t) (depth + 1)
+ );
+ }
+
+ lex_state_set(parser, PM_LEX_STATE_BEG);
+ parser->command_start = true;
+
+ context_pop(parser);
+ if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = 0;
+ }
+
+ 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);
+ }
+
+ params = parse_parameters(
+ parser,
+ PM_BINDING_POWER_DEFINED,
+ false,
+ false,
+ true,
+ true,
+ false,
+ PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
+ (uint16_t) (depth + 1)
+ );
+
+ /* Reject `def * = 1` and similar. We have to specifically check for
+ * them because they create ambiguity with optional arguments. */
+ accept_endless_def = false;
+
+ context_pop(parser);
+ break;
+ }
+ default: {
+ params = NULL;
+ context_pop(parser);
+ break;
+ }
+ }
+
+ pm_node_t *statements = NULL;
+ pm_token_t equal = { 0 };
+ pm_token_t end_keyword = { 0 };
+
+ if (accept1(parser, PM_TOKEN_EQUAL)) {
+ if (token_is_setter_name(&name)) {
+ pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
+ }
+ if (!accept_endless_def) {
+ pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
+ }
+ if (
+ parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
+ parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
+ ) {
+ PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &def_keyword), PM_TOKENS_LENGTH(&def_keyword, &parser->previous), PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE, "endless method definition");
+ }
+ equal = parser->previous;
+
+ context_push(parser, PM_CONTEXT_DEF);
+ pm_do_loop_stack_push(parser, false);
+ statements = UP(pm_statements_node_create(parser));
+
+ uint8_t allow_flags;
+ if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
+ allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
+ } else {
+ /* Allow `def foo = puts "Hello"` but not
+ * `private def foo = puts "Hello"` */
+ allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
+ }
+
+ /* Inside a def body, we push true onto the accepts_block_stack so that
+ * `do` is lexed as PM_TOKEN_KEYWORD_DO (which can only start a block
+ * for primary-level constructs, not commands). During command argument
+ * parsing, the stack is pushed to false, causing `do` to be lexed as
+ * PM_TOKEN_KEYWORD_DO_BLOCK, which is not consumed inside the endless
+ * def body and instead left for the outer context. */
+ pm_accepts_block_stack_push(parser, true);
+ pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_flags | PM_PARSE_IN_ENDLESS_DEF, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
+ pm_accepts_block_stack_pop(parser);
+
+ /* If an unconsumed PM_TOKEN_KEYWORD_DO follows the body, it is an error
+ * (e.g., `def f = 1 do end`). PM_TOKEN_KEYWORD_DO_BLOCK is
+ * intentionally not caught here — it should bubble up to the outer
+ * context (e.g., `private def f = puts "Hello" do end` where the block
+ * attaches to `private`). */
+ if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
+ pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
+ pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
+ }
+
+ if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
+ context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
+
+ pm_token_t rescue_keyword = parser->previous;
+
+ /* In the Ruby grammar, the rescue value of an endless method
+ * command excludes and/or and in/=>. */
+ pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_MATCH + 1, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ context_pop(parser);
+
+ statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
+ }
+
+ /* A nested endless def whose body is a command call (e.g.,
+ * `def f = def g = foo bar`) is a command assignment and cannot appear
+ * as a def body. */
+ if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(statement)) {
+ PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ }
+
+ pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement, false);
+ pm_do_loop_stack_pop(parser);
+ context_pop(parser);
+ } else {
+ if (lparen.start == NULL) {
+ 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 (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
+ pm_accepts_block_stack_push(parser, true);
+ statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
+ pm_accepts_block_stack_pop(parser);
+ }
+
+ if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
+ assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
+ statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1)));
+ } else {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword, false, false);
+ }
+
+ pm_accepts_block_stack_pop(parser);
+ pm_do_loop_stack_pop(parser);
+
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
+ end_keyword = parser->previous;
+ }
+
+ pm_constant_id_list_t locals;
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
+ pm_parser_scope_pop(parser);
+
+ /* If the final character is `@` as is the case when defining methods to
+ * override the unary operators, we should ignore the @ in the same way we
+ * do for symbols. */
+ pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.start, parse_operator_symbol_name(&name));
+
+ flush_block_exits(parser, previous_block_exits);
+
+ return UP(pm_def_node_create(
+ parser,
+ name_id,
+ &name,
+ receiver,
+ params,
+ statements,
+ &locals,
+ &def_keyword,
+ NTOK2PTR(operator),
+ NTOK2PTR(lparen),
+ NTOK2PTR(rparen),
+ NTOK2PTR(equal),
+ NTOK2PTR(end_keyword)
+ ));
+}
+
+/**
+ * Parse a module definition expression (the `module` keyword).
+ */
+static pm_node_t *
+parse_module(pm_parser_t *parser, uint8_t flags, uint16_t depth) {
+ pm_node_list_t current_block_exits = { 0 };
+ pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
+
+ size_t opening_newline_index = token_newline_index(parser);
+ parser_lex(parser);
+ pm_token_t module_keyword = parser->previous;
+
+ pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
+ 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_ERROR_RECOVERY_NODE)) {
+ pop_block_exits(parser, previous_block_exits);
+
+ pm_token_t missing = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
+ return UP(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);
+ constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
+ }
+
+ /* 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);
+ }
+
+ if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE) && !PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
+ constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
+ }
+
+ pm_parser_scope_push(parser, true);
+ accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
+ pm_node_t *statements = NULL;
+
+ if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
+ pm_accepts_block_stack_push(parser, true);
+ statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
+ pm_accepts_block_stack_pop(parser);
+ }
+
+ if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
+ assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
+ statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1)));
+ } else {
+ parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword, false, false);
+ }
+
+ pm_constant_id_list_t locals;
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
+
+ pm_parser_scope_pop(parser);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
+
+ if (context_def_p(parser)) {
+ pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+
+ return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
+}
+
+/**
+ * Parse an interpolated word array literal (`%W[...]`).
+ */
+static pm_node_t *
+parse_string_array(pm_parser_t *parser, uint16_t depth) {
+ 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(parser->arena, array, current);
+ current = NULL;
+ }
+
+ parser_lex(parser);
+ break;
+ }
+ case PM_TOKEN_STRING_CONTENT: {
+ pm_node_t *string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ 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(parser, (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, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ pm_interpolated_string_node_append(parser, interpolated, string);
+ current = UP(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. */
+ current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ current = UP(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, (uint16_t) (depth + 1));
+ pm_interpolated_string_node_append(parser, (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. */
+ current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ current = UP(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, (uint16_t) (depth + 1));
+ pm_interpolated_string_node_append(parser, (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(parser->arena, 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 = 0, .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(parser, array, &closing);
+ return UP(array);
+}
+
+/**
+ * Parse an interpolated symbol array literal (`%I[...]`).
+ */
+static pm_node_t *
+parse_symbol_array(pm_parser_t *parser, uint16_t depth) {
+ 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(parser->arena, array, current);
+ current = NULL;
+ }
+
+ parser_lex(parser);
+ break;
+ }
+ case PM_TOKEN_STRING_CONTENT: {
+ 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 = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
+ 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 = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ parser_lex(parser);
+
+ pm_interpolated_symbol_node_append(parser->arena, (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 symbol
+ * 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_symbol_node_t *cast = (pm_symbol_node_t *) current;
+ pm_token_t content = {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->start + cast->value_loc.start,
+ .end = parser->start + cast->value_loc.start + cast->value_loc.length
+ };
+
+ pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->unescaped));
+ pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
+ parser_lex(parser);
+
+ pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
+
+ current = UP(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. */
+ current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+
+ current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
+ PM_NODE_START_SET_NODE(interpolated, current);
+ start_location_set = true;
+ current = UP(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, (uint16_t) (depth + 1));
+ pm_interpolated_symbol_node_append(parser->arena, (pm_interpolated_symbol_node_t *) current, part);
+ if (!start_location_set) {
+ PM_NODE_START_SET_NODE(current, part);
+ }
+ 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. */
+ current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
+ } 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_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+
+ current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
+ PM_NODE_START_SET_NODE(interpolated, current);
+ start_location_set = true;
+ current = UP(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, (uint16_t) (depth + 1));
+ pm_interpolated_symbol_node_append(parser->arena, (pm_interpolated_symbol_node_t *) current, part);
+ if (!start_location_set) {
+ PM_NODE_START_SET_NODE(current, part);
+ }
+ 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(parser->arena, 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 = 0, .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(parser, array, &closing);
+
+ return UP(array);
+}
+
+/**
+ * Parse a parenthesized expression, which could be a grouping, a multi-target
+ * assignment, or a set of statements.
+ */
+static pm_node_t *
+parse_parentheses(pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
+ pm_token_t opening = parser->current;
+ pm_node_flags_t paren_flags = 0;
+
+ pm_node_list_t current_block_exits = { 0 };
+ pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
+
+ parser_lex(parser);
+ while (true) {
+ if (accept1(parser, PM_TOKEN_SEMICOLON)) {
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+ } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
+ break;
+ }
+ }
+
+ /* 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);
+ pop_block_exits(parser, previous_block_exits);
+ return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
+ }
+
+ /* 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, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
+ 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 = false;
+
+ if (accept1(parser, PM_TOKEN_SEMICOLON)) {
+ terminator_found = true;
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+ } else if (accept1(parser, PM_TOKEN_NEWLINE)) {
+ terminator_found = true;
+ }
+
+ if (terminator_found) {
+ while (true) {
+ if (accept1(parser, PM_TOKEN_SEMICOLON)) {
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+ } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
+ break;
+ }
+ }
+ }
+
+ /* 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);
+ pop_block_exits(parser, previous_block_exits);
+
+ 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.length == 0) {
+ 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);
+ }
+
+ multi_target->lparen_loc = TOK2LOC(parser, &opening);
+ multi_target->rparen_loc = TOK2LOC(parser, &parser->previous);
+ PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
+ PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
+
+ pm_node_t *result;
+ if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
+ result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
+ accept1(parser, PM_TOKEN_NEWLINE);
+ } else {
+ result = UP(multi_target);
+ }
+
+ if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
+ /* All set, this is explicitly allowed by the parent context. */
+ } else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) {
+ /* All set, we're inside a for loop and we're parsing multiple
+ * targets. */
+ } else if (binding_power != PM_BINDING_POWER_STATEMENT) {
+ /* Multi targets are not allowed when it's not a statement
+ * level. */
+ pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
+ } else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
+ /* Multi targets must be followed by an equal sign in order to
+ * be valid (or a right parenthesis if they are nested). */
+ pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
+ }
+
+ return result;
+ }
+
+ /* 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(parser, statements, statement, true);
+
+ return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
+ }
+
+ /* 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);
+ paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
+
+ pm_statements_node_t *statements = pm_statements_node_create(parser);
+ pm_statements_node_body_append(parser, statements, statement, true);
+
+ /* If we didn't find a terminator and we didn't find a right parenthesis,
+ * then this is a syntax error. */
+ if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ }
+
+ /* Parse each statement within the parentheses. */
+ while (true) {
+ pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
+ pm_statements_node_body_append(parser, statements, node, true);
+
+ /* 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_ERROR_RECOVERY_NODE)) break;
+
+ /* If we successfully parsed a statement, then we are going to need a
+ * 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 if (!match1(parser, PM_TOKEN_EOF)) {
+ /* If we're at the end of the file, then we're going to add an error
+ * after this for the ) anyway. */
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ }
+ }
+
+ context_pop(parser);
+ pm_accepts_block_stack_pop(parser);
+ expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
+
+ /* When we're parsing multi targets, we allow them to be followed by a right
+ * parenthesis if they are at the statement level. This is only possible if
+ * they are the final statement in a parentheses. We need to explicitly
+ * reject that here. */
+ {
+ pm_node_t *statement = statements->body.nodes[statements->body.size - 1];
+
+ if (PM_NODE_TYPE_P(statement, 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, statement);
+
+ statement = UP(multi_target);
+ statements->body.nodes[statements->body.size - 1] = statement;
+ }
+
+ if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
+ const uint8_t *offset = parser->start + PM_NODE_END(statement);
+ pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
+ pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
+
+ statement = UP(pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &operator, value));
+ statements->body.nodes[statements->body.size - 1] = statement;
+
+ pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
+ }
+ }
+
+ pop_block_exits(parser, previous_block_exits);
+ pm_void_statements_check(parser, statements, true);
+ return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
}
/**
* 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, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) {
+static PRISM_INLINE pm_node_t *
+parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
switch (parser->current.type) {
case PM_TOKEN_BRACKET_LEFT_ARRAY: {
parser_lex(parser);
@@ -18092,11 +19089,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
} else {
// If there was no comma, then we need to add a syntax
// error.
- const uint8_t *location = parser->previous.end;
- PM_PARSER_ERR_FORMAT(parser, location, location, PM_ERR_ARRAY_SEPARATOR, pm_token_type_human(parser->current.type));
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
+ PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
+ parser->previous.start = parser->previous.end;
+ parser->previous.type = 0;
}
}
@@ -18114,28 +19109,28 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
pm_parser_scope_forwarding_positionals_check(parser, &operator);
} else {
- expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+ expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
}
- element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
+ element = UP(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);
}
- element = (pm_node_t *) pm_keyword_hash_node_create(parser);
+ element = UP(pm_keyword_hash_node_create(parser));
pm_static_literals_t hash_keys = { 0 };
- 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)) {
+ if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
}
pm_static_literals_free(&hash_keys);
parsed_bare_hash = true;
} else {
- element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
+ element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_LABEL), PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
- if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
+ if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
if (parsed_bare_hash) {
pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
}
@@ -18144,18 +19139,16 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_static_literals_t hash_keys = { 0 };
pm_hash_key_static_literals_add(parser, &hash_keys, element);
- pm_token_t operator;
+ pm_token_t operator = { 0 };
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, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value);
- pm_keyword_hash_node_elements_append(hash, assoc);
+ pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(operator), value));
+ pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
- element = (pm_node_t *) hash;
+ element = UP(hash);
if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
}
@@ -18165,236 +19158,26 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
}
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
+ pm_array_node_elements_append(parser->arena, array, element);
+ if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE)) break;
}
accept1(parser, PM_TOKEN_NEWLINE);
if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
+ parser->previous.type = 0;
}
- pm_array_node_close_set(array, &parser->previous);
+ pm_array_node_close_set(parser, array, &parser->previous);
pm_accepts_block_stack_pop(parser);
- return (pm_node_t *) array;
+ return UP(array);
}
case PM_TOKEN_PARENTHESIS_LEFT:
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
- pm_token_t opening = parser->current;
- pm_node_flags_t flags = 0;
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- parser_lex(parser);
- while (true) {
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
- } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
- break;
- }
- }
-
- // 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);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, flags);
- }
-
- // 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, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
- 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 = false;
-
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- terminator_found = true;
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
- } else if (accept1(parser, PM_TOKEN_NEWLINE)) {
- terminator_found = true;
- }
-
- if (terminator_found) {
- while (true) {
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
- } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
- break;
- }
- }
- }
-
- // 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);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- 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;
-
- pm_node_t *result;
- if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
- result = parse_targets(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- accept1(parser, PM_TOKEN_NEWLINE);
- } else {
- result = (pm_node_t *) multi_target;
- }
-
- if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
- // All set, this is explicitly allowed by the parent
- // context.
- } else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) {
- // All set, we're inside a for loop and we're parsing
- // multiple targets.
- } else if (binding_power != PM_BINDING_POWER_STATEMENT) {
- // Multi targets are not allowed when it's not a
- // statement level.
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- } else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
- // Multi targets must be followed by an equal sign in
- // order to be valid (or a right parenthesis if they are
- // nested).
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return result;
- }
-
- // 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(parser, statements, statement, true);
-
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous, flags);
- }
-
- // 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);
- flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, statement, true);
-
- // If we didn't find a terminator and we didn't find a right
- // parenthesis, then this is a syntax error.
- if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
- }
-
- // Parse each statement within the parentheses.
- while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
- pm_statements_node_body_append(parser, statements, node, true);
-
- // 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 if (!match1(parser, PM_TOKEN_EOF)) {
- // If we're at the end of the file, then we're going to add
- // an error after this for the ) anyway.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
- }
- }
-
- context_pop(parser);
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- // When we're parsing multi targets, we allow them to be followed by
- // a right parenthesis if they are at the statement level. This is
- // only possible if they are the final statement in a parentheses.
- // We need to explicitly reject that here.
- {
- pm_node_t *statement = statements->body.nodes[statements->body.size - 1];
-
- if (PM_NODE_TYPE_P(statement, 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, statement);
-
- statement = (pm_node_t *) multi_target;
- statements->body.nodes[statements->body.size - 1] = statement;
- }
-
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
- const uint8_t *offset = statement->location.end;
- pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
- pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, offset, offset);
-
- statement = (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &operator, value);
- statements->body.nodes[statements->body.size - 1] = statement;
-
- pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- pm_void_statements_check(parser, statements, true);
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous, flags);
- }
+ case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
+ return parse_parentheses(parser, binding_power, depth);
case PM_TOKEN_BRACE_LEFT: {
// If we were passed a current_hash_keys via the parser, then that
// means we're already parsing a hash and we want to share the set
@@ -18409,14 +19192,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_accepts_block_stack_push(parser, true);
parser_lex(parser);
- pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
+ pm_token_t opening = parser->previous;
+ pm_hash_node_t *node = pm_hash_node_create(parser, &opening);
if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
if (current_hash_keys != NULL) {
- parse_assocs(parser, current_hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1));
+ parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
} else {
pm_static_literals_t hash_keys = { 0 };
- parse_assocs(parser, &hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1));
+ parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
pm_static_literals_free(&hash_keys);
}
@@ -18424,26 +19208,33 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
+ pm_hash_node_closing_loc_set(parser, node, &parser->previous);
- return (pm_node_t *) node;
+ return UP(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_node_t *node = UP(pm_string_node_create_current_string(
+ parser,
+ &(pm_token_t) {
+ .type = PM_TOKEN_STRING_BEGIN,
+ .start = parser->current.start,
+ .end = parser->current.start + 1
+ },
+ &(pm_token_t) {
+ .type = PM_TOKEN_STRING_CONTENT,
+ .start = parser->current.start + 1,
+ .end = parser->current.end
+ },
+ NULL
+ ));
- 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));
+ // Skip past the character literal here, since now we have handled
+ // parser->explicit_encoding correctly.
+ parser_lex(parser);
+
// Characters can be followed by strings in which case they are
// automatically concatenated.
if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
@@ -18454,7 +19245,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_CLASS_VARIABLE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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, (uint16_t) (depth + 1));
@@ -18470,16 +19261,16 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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))) ||
+ ((flags & PM_PARSE_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) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
match1(parser, PM_TOKEN_BRACE_LEFT)
) {
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
+ return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
}
- pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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
@@ -18494,7 +19285,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t delimiter = parser->previous;
expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *node = (pm_node_t *) pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous);
+ pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous));
if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
@@ -18507,7 +19298,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t operator = parser->current;
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
// Unary .. and ... are special because these are non-associative
// operators that can also be unary operators. In this case we need
@@ -18517,23 +19308,23 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
}
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ pm_node_t *node = UP(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, (uint16_t) (depth + 1));
@@ -18543,7 +19334,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_GLOBAL_VARIABLE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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, (uint16_t) (depth + 1));
@@ -18553,7 +19344,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_BACK_REFERENCE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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, (uint16_t) (depth + 1));
@@ -18575,26 +19366,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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, (uint16_t) (depth + 1))) {
+ if (parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1))) {
// 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);
+ pm_node_flag_unset(UP(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;
- }
+ const pm_location_t *end = pm_arguments_end(&arguments);
+ if (end == NULL) {
+ PM_NODE_LENGTH_SET_LOCATION(call, &call->message_loc);
} else {
- call->base.location.end = arguments.closing_loc.end;
+ PM_NODE_LENGTH_SET_LOCATION(call, end);
}
}
} else {
@@ -18602,19 +19388,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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))) ||
+ ((flags & PM_PARSE_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) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
match1(parser, PM_TOKEN_BRACE_LEFT)
) {
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
// If we're about to convert an 'it' implicit local
// variable read into a method call, we need to remove
// it from the list of implicit local variables.
- parse_target_implicit_parameter(parser, node);
+ pm_node_unreference(parser, node);
} else {
// Otherwise, we're about to convert a regular local
// variable read into a method call, in which case we
@@ -18622,16 +19408,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// purposes of warnings.
assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
- if (pm_token_is_numbered_parameter(identifier.start, identifier.end)) {
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
+ pm_node_unreference(parser, node);
} else {
pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
pm_locals_unread(&pm_parser_scope_find(parser, cast->depth)->locals, cast->name);
}
}
- pm_node_destroy(parser, node);
- return (pm_node_t *) fcall;
+ return UP(fcall);
}
}
@@ -18663,12 +19448,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t content = parse_strings_empty_content(parser->previous.start);
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
- node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
+ node = UP(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 = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
}
- node->location.end = opening.end;
+ PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
} else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
// If we get here, then we tried to find something in the
// heredoc but couldn't actually parse anything, so we'll just
@@ -18676,7 +19461,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
//
// parse_string_part handles its own errors, so there is no need
// for us to add one here.
- node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
+ node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
} 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
@@ -18685,8 +19470,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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->opening_loc = TOK2LOC(parser, &opening);
+ cast->closing_loc = TOK2LOC(parser, &parser->current);
cast->base.location = cast->opening_loc;
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
@@ -18695,21 +19480,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
- parse_heredoc_dedent_string(&cast->unescaped, common_whitespace);
+ parse_heredoc_dedent_string(parser->arena, &cast->unescaped, common_whitespace);
}
- node = (pm_node_t *) cast;
+ node = UP(cast);
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
} 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);
+ pm_node_list_append(parser->arena, &parts, part);
while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_node_list_append(&parts, part);
+ pm_node_list_append(parser->arena, &parts, part);
}
}
@@ -18720,19 +19505,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
cast->parts = parts;
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- pm_interpolated_xstring_node_closing_set(cast, &parser->previous);
+ pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
+ node = UP(cast);
} else {
pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
- pm_node_list_free(&parts);
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- pm_interpolated_string_node_closing_set(cast, &parser->previous);
+ pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
+ node = UP(cast);
}
// If this is a heredoc that is indented with a ~, then we need
@@ -18757,7 +19541,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
case PM_TOKEN_INSTANCE_VARIABLE: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(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, (uint16_t) (depth + 1));
@@ -18766,34 +19550,34 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return node;
}
case PM_TOKEN_INTEGER: {
- pm_node_flags_t base = parser->integer_base;
+ pm_node_flags_t base = parser->integer.base;
parser_lex(parser);
- return (pm_node_t *) pm_integer_node_create(parser, base, &parser->previous);
+ return UP(pm_integer_node_create(parser, base, &parser->previous));
}
case PM_TOKEN_INTEGER_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
+ pm_node_flags_t base = parser->integer.base;
parser_lex(parser);
- return (pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->previous);
+ return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
}
case PM_TOKEN_INTEGER_RATIONAL: {
- pm_node_flags_t base = parser->integer_base;
+ pm_node_flags_t base = parser->integer.base;
parser_lex(parser);
- return (pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->previous);
+ return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
}
case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
+ 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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
+ return UP(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);
@@ -18813,245 +19597,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
}
- } else {
+ } else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
+ old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
}
- return (pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
+ return UP(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)) {
+ if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
+ old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
}
}
PRISM_FALLTHROUGH
default:
- return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
- }
- }
- case PM_TOKEN_KEYWORD_CASE: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- pm_token_t case_keyword = parser->previous;
- pm_node_t *predicate = NULL;
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- 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, false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- }
-
- if (match1(parser, PM_TOKEN_KEYWORD_END)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
- parser_lex(parser);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- 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);
- pm_static_literals_t literals = { 0 };
-
- // 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 (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true);
- parser_lex(parser);
-
- 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, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
-
- 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, false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
- pm_when_node_conditions_append(when_node, condition);
-
- // If we found a missing node, then this is a syntax
- // error and we should stop looping.
- if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE)) break;
-
- // If this is a string node, then we need to mark it
- // as frozen because when clause strings are frozen.
- if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
- pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
- } else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
- pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- pm_when_clause_static_literals_add(parser, &literals, condition);
- }
- } while (accept1(parser, PM_TOKEN_COMMA));
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- pm_when_node_then_keyword_loc_set(when_node, &parser->previous);
- }
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
- pm_when_node_then_keyword_loc_set(when_node, &parser->previous);
- }
-
- 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, (uint16_t) (depth + 1));
- 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);
- }
-
- pm_static_literals_free(&literals);
- 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)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true);
-
- 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_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
-
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- pm_constant_id_list_free(&captures);
-
- // 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_COMPOSITION, true, false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
- 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_COMPOSITION, true, false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
- 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_IN_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, (uint16_t) (depth + 1));
- }
-
- // 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, (uint16_t) (depth + 1)), &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_else_clause_set((pm_case_node_t *) node, else_node);
- } else {
- pm_case_match_node_else_clause_set((pm_case_match_node_t *) node, else_node);
- }
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
- 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 UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
}
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return node;
}
+ case PM_TOKEN_KEYWORD_CASE:
+ return parse_case(parser, flags, depth);
case PM_TOKEN_KEYWORD_BEGIN: {
size_t opening_newline_index = token_newline_index(parser);
parser_lex(parser);
@@ -19072,15 +19638,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
- 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);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
+ PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
+ pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) begin_node;
+ return UP(begin_node);
}
case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
pm_node_list_t current_block_exits = { 0 };
@@ -19097,16 +19660,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t opening = parser->previous;
pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
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);
}
flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
+ return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
}
case PM_TOKEN_KEYWORD_BREAK:
case PM_TOKEN_KEYWORD_NEXT:
@@ -19123,29 +19684,44 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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, (uint16_t) (depth + 1));
+ pm_token_t next = parser->current;
+ parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
+
+ // Reject `foo && return bar`.
+ if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.arguments != NULL) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.type));
+ }
+ }
+
+ // It's possible that we've parsed a block argument through our
+ // call to parse_arguments. If we found one, we should mark it
+ // as invalid and destroy it, as we don't have a place for it.
+ if (arguments.block != NULL) {
+ pm_parser_err_node(parser, arguments.block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
+ pm_node_unreference(parser, arguments.block);
+ arguments.block = NULL;
}
}
switch (keyword.type) {
case PM_TOKEN_KEYWORD_BREAK: {
- pm_node_t *node = (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.arguments);
+ pm_node_t *node = UP(pm_break_node_create(parser, &keyword, arguments.arguments));
if (!parser->partial_script) parse_block_exit(parser, node);
return node;
}
case PM_TOKEN_KEYWORD_NEXT: {
- pm_node_t *node = (pm_node_t *) pm_next_node_create(parser, &keyword, arguments.arguments);
+ pm_node_t *node = UP(pm_next_node_create(parser, &keyword, arguments.arguments));
if (!parser->partial_script) parse_block_exit(parser, node);
return node;
}
case PM_TOKEN_KEYWORD_RETURN: {
- pm_node_t *node = (pm_node_t *) pm_return_node_create(parser, &keyword, arguments.arguments);
+ pm_node_t *node = UP(pm_return_node_create(parser, &keyword, arguments.arguments));
parse_return(parser, node);
return node;
}
default:
assert(false && "unreachable");
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
}
}
case PM_TOKEN_KEYWORD_SUPER: {
@@ -19153,24 +19729,24 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t keyword = parser->previous;
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
if (
- arguments.opening_loc.start == NULL &&
+ arguments.opening_loc.length == 0 &&
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 UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
}
- return (pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
+ return UP(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, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, false, flags, (uint16_t) (depth + 1));
// It's possible that we've parsed a block argument through our
// call to parse_arguments_list. If we found one, we should mark it
@@ -19178,434 +19754,25 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// yield node.
if (arguments.block != NULL) {
pm_parser_err_node(parser, arguments.block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
- pm_node_destroy(parser, arguments.block);
+ pm_node_unreference(parser, arguments.block);
arguments.block = NULL;
}
- pm_node_t *node = (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc);
+ pm_node_t *node = UP(pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc));
if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
return node;
}
- case PM_TOKEN_KEYWORD_CLASS: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- pm_token_t class_keyword = parser->previous;
- pm_do_loop_stack_push(parser, false);
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- if (accept1(parser, PM_TOKEN_LESS_LESS)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
-
- pm_parser_scope_push(parser, true);
- if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_type_human(parser->current.type));
- }
-
- pm_node_t *statements = NULL;
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1));
- 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_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
-
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_pop(parser);
-
- flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- 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, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
- 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, false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
- } else {
- inheritance_operator = not_provided(parser);
- superclass = NULL;
- }
-
- pm_parser_scope_push(parser, true);
-
- if (inheritance_operator.type != PM_TOKEN_NOT_PROVIDED) {
- expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
- } else {
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
- pm_node_t *statements = NULL;
-
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1));
- 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_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, 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;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
-
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_pop(parser);
-
- if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
- pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- 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_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- pm_token_t def_keyword = parser->current;
- size_t opening_newline_index = token_newline_index(parser);
-
- pm_node_t *receiver = NULL;
- pm_token_t operator = not_provided(parser);
- pm_token_t name;
-
- // 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);
-
- // This will be false if the method name is not a valid identifier
- // but could be followed by an operator.
- bool valid_name = true;
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- pm_parser_scope_push(parser, true);
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- parser_lex(parser);
-
- name = parser->previous;
- break;
- case PM_TOKEN_IDENTIFIER: {
- parser_lex(parser);
-
- if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
- receiver = parse_variable_call(parser);
-
- pm_parser_scope_push(parser, true);
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
-
- operator = parser->previous;
- name = parse_method_definition_name(parser);
- } else {
- pm_refute_numbered_parameter(parser, parser->previous.start, parser->previous.end);
- pm_parser_scope_push(parser, true);
-
- name = parser->previous;
- }
-
- break;
- }
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- valid_name = false;
- PRISM_FALLTHROUGH
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_KEYWORD_NIL:
- case PM_TOKEN_KEYWORD_SELF:
- case PM_TOKEN_KEYWORD_TRUE:
- case PM_TOKEN_KEYWORD_FALSE:
- case PM_TOKEN_KEYWORD___FILE__:
- case PM_TOKEN_KEYWORD___LINE__:
- case PM_TOKEN_KEYWORD___ENCODING__: {
- pm_parser_scope_push(parser, true);
- parser_lex(parser);
-
- pm_token_t identifier = parser->previous;
-
- if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
- operator = parser->previous;
-
- switch (identifier.type) {
- case PM_TOKEN_CONSTANT:
- receiver = (pm_node_t *) pm_constant_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_INSTANCE_VARIABLE:
- receiver = (pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_CLASS_VARIABLE:
- receiver = (pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_GLOBAL_VARIABLE:
- receiver = (pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_NIL:
- receiver = (pm_node_t *) pm_nil_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_SELF:
- receiver = (pm_node_t *) pm_self_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_TRUE:
- receiver = (pm_node_t *) pm_true_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_FALSE:
- receiver = (pm_node_t *) pm_false_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___FILE__:
- receiver = (pm_node_t *) pm_source_file_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___LINE__:
- receiver = (pm_node_t *) pm_source_line_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___ENCODING__:
- receiver = (pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
- break;
- default:
- break;
- }
-
- name = parse_method_definition_name(parser);
- } else {
- if (!valid_name) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, identifier, PM_ERR_DEF_NAME, pm_token_type_human(identifier.type));
- }
-
- 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_COMPOSITION, true, false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
-
- accept1(parser, PM_TOKEN_NEWLINE);
- 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, 0);
-
- // To push `PM_CONTEXT_DEF_PARAMS` again is for the same
- // reason as described the above.
- pm_parser_scope_push(parser, true);
- context_push(parser, PM_CONTEXT_DEF_PARAMS);
- name = parse_method_definition_name(parser);
- break;
- }
- default:
- pm_parser_scope_push(parser, true);
- name = parse_method_definition_name(parser);
- break;
- }
-
- 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, true, false, (uint16_t) (depth + 1));
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
-
- context_pop(parser);
- if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_type_human(parser->current.type));
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
-
- 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, true, false, (uint16_t) (depth + 1));
-
- context_pop(parser);
- break;
- }
- default: {
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- params = NULL;
-
- context_pop(parser);
- break;
- }
- }
-
- 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, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
-
- if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
-
- pm_token_t rescue_keyword = parser->previous;
- pm_node_t *value = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
- context_pop(parser);
-
- statement = (pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
- }
-
- pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement, false);
- 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 (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword, false, false);
- }
-
- 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;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
- pm_parser_scope_pop(parser);
-
- /**
- * If the final character is @. As is the case when defining
- * methods to override the unary operators, we should ignore
- * the @ in the same way we do for symbols.
- */
- pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
-
- flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_def_node_create(
- parser,
- name_id,
- &name,
- receiver,
- params,
- statements,
- &locals,
- &def_keyword,
- &operator,
- &lparen,
- &rparen,
- &equal,
- &end_keyword
- );
- }
+ case PM_TOKEN_KEYWORD_CLASS:
+ return parse_class(parser, flags, depth);
+ case PM_TOKEN_KEYWORD_DEF:
+ return parse_def(parser, binding_power, flags, depth);
case PM_TOKEN_KEYWORD_DEFINED: {
parser_lex(parser);
- pm_token_t keyword = parser->previous;
- pm_token_t lparen;
- pm_token_t rparen;
+ pm_token_t keyword = parser->previous;
+ pm_token_t lparen = { 0 };
+ pm_token_t rparen = { 0 };
pm_node_t *expression;
context_push(parser, PM_CONTEXT_DEFINED);
@@ -19615,34 +19782,29 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
lparen = parser->previous;
if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- expression = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
- lparen = not_provided(parser);
- rparen = not_provided(parser);
+ expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
+ lparen = (pm_token_t) { 0 };
} else {
- expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
+ expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
- if (parser->recovering) {
- rparen = not_provided(parser);
- } else {
+ if (!parser->recovering) {
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, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
+ expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
}
context_pop(parser);
- return (pm_node_t *) pm_defined_node_create(
+ return UP(pm_defined_node_create(
parser,
- &lparen,
+ NTOK2PTR(lparen),
expression,
- &rparen,
- &PM_LOCATION_TOKEN_VALUE(&keyword)
- );
+ NTOK2PTR(rparen),
+ &keyword
+ ));
}
case PM_TOKEN_KEYWORD_END_UPCASE: {
if (binding_power != PM_BINDING_POWER_STATEMENT) {
@@ -19660,12 +19822,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t opening = parser->previous;
pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
- 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);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
+ return UP(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);
+ return UP(pm_false_node_create(parser, &parser->previous));
case PM_TOKEN_KEYWORD_FOR: {
size_t opening_newline_index = token_newline_index(parser);
parser_lex(parser);
@@ -19681,15 +19843,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_t *name = NULL;
if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+ name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
}
- index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
+ index = UP(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, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
+ index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
} 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);
+ index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
}
// Now, if there are multiple index expressions, parse them out.
@@ -19705,16 +19867,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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, false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
+ pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
pm_do_loop_stack_pop(parser);
- pm_token_t do_keyword;
+ pm_token_t do_keyword = { 0 };
if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
do_keyword = parser->previous;
} else {
- do_keyword = not_provided(parser);
if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
}
}
@@ -19724,13 +19885,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
- return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous);
+ return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous));
}
case PM_TOKEN_KEYWORD_IF:
if (parser_end_of_line_p(parser)) {
- PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_KEYWORD_EOL);
+ PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
}
size_t opening_newline_index = token_newline_index(parser);
@@ -19747,26 +19908,24 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
- if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
- pm_node_destroy(parser, name);
+ if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
} else {
- pm_undef_node_append(undef, name);
+ pm_undef_node_append(parser->arena, 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, (uint16_t) (depth + 1));
- if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
- pm_node_destroy(parser, name);
+ if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
break;
}
- pm_undef_node_append(undef, name);
+ pm_undef_node_append(parser->arena, undef, name);
}
}
- return (pm_node_t *) undef;
+ return UP(undef);
}
case PM_TOKEN_KEYWORD_NOT: {
parser_lex(parser);
@@ -19775,28 +19934,46 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_arguments_t arguments = { 0 };
pm_node_t *receiver = NULL;
+ // The `not` keyword without parentheses is only valid in contexts
+ // where it would be parsed as an expression (i.e., at or below
+ // the `not` binding power level). In other contexts (e.g., method
+ // arguments, array elements, assignment right-hand sides),
+ // parentheses are required: `not(x)`. An exception is made for
+ // endless def bodies, where `not` is valid as both `arg` and
+ // `command` (e.g., `def f = not 1`, `def f = not foo bar`).
+ if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
+ if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
+ pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
+ } else {
+ accept1(parser, PM_TOKEN_NEWLINE);
+ pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
+ }
+
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
+ }
+
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, 0);
+ receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
} else {
- arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
- receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
+ arguments.opening_loc = TOK2LOC(parser, &lparen);
+ receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
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);
+ arguments.closing_loc = TOK2LOC(parser, &parser->previous);
}
}
} else {
- receiver = parse_expression(parser, PM_BINDING_POWER_NOT, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
+ receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
}
- return (pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
+ return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
}
case PM_TOKEN_KEYWORD_UNLESS: {
size_t opening_newline_index = token_newline_index(parser);
@@ -19804,81 +19981,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index, false, (uint16_t) (depth + 1));
}
- case PM_TOKEN_KEYWORD_MODULE: {
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
- pm_token_t module_keyword = parser->previous;
-
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
- 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)) {
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- 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);
- constant_path = (pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous);
- }
-
- // Here we retrieve the name of the module. If it wasn't a constant,
- // then it's possible that `module foo` was passed, which is a
- // syntax error. We handle that here as well.
- name = parser->previous;
- if (name.type != PM_TOKEN_CONSTANT) {
- pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
- }
-
- pm_parser_scope_push(parser, true);
- accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
- pm_node_t *statements = NULL;
-
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword, false, false);
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
-
- pm_parser_scope_pop(parser);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
-
- if (context_def_p(parser)) {
- pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous);
- }
+ case PM_TOKEN_KEYWORD_MODULE:
+ return parse_module(parser, flags, depth);
case PM_TOKEN_KEYWORD_NIL:
parser_lex(parser);
- return (pm_node_t *) pm_nil_node_create(parser, &parser->previous);
+ return UP(pm_nil_node_create(parser, &parser->previous));
case PM_TOKEN_KEYWORD_REDO: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_redo_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
if (!parser->partial_script) parse_block_exit(parser, node);
return node;
@@ -19886,17 +19997,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
case PM_TOKEN_KEYWORD_RETRY: {
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_retry_node_create(parser, &parser->previous);
+ pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
parse_retry(parser, node);
return node;
}
case PM_TOKEN_KEYWORD_SELF:
parser_lex(parser);
- return (pm_node_t *) pm_self_node_create(parser, &parser->previous);
+ return UP(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);
+ return UP(pm_true_node_create(parser, &parser->previous));
case PM_TOKEN_KEYWORD_UNTIL: {
size_t opening_newline_index = token_newline_index(parser);
@@ -19905,16 +20016,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
+ pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
pm_do_loop_stack_pop(parser);
context_pop(parser);
- pm_token_t do_keyword;
+ pm_token_t do_keyword = { 0 };
if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
do_keyword = parser->previous;
} else {
- do_keyword = not_provided(parser);
expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
}
@@ -19927,9 +20037,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
- return (pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0);
+ return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
}
case PM_TOKEN_KEYWORD_WHILE: {
size_t opening_newline_index = token_newline_index(parser);
@@ -19939,16 +20049,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
+ pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
pm_do_loop_stack_pop(parser);
context_pop(parser);
- pm_token_t do_keyword;
+ pm_token_t do_keyword = { 0 };
if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
do_keyword = parser->previous;
} else {
- do_keyword = not_provided(parser);
expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
}
@@ -19961,381 +20070,122 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
- return (pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0);
+ return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_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);
+ pm_node_t *current = NULL;
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;
- }
-
+ // Interpolation is not possible but nested heredocs can still lead to
+ // consecutive (disjoint) string tokens when the final newline is escaped.
+ while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
+ // Record the string node, moving to interpolation if needed.
+ if (current == NULL) {
+ current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
+ parser_lex(parser);
+ } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
+ pm_node_t *string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+ parser_lex(parser);
+ pm_interpolated_symbol_node_append(parser->arena, (pm_interpolated_symbol_node_t *) current, string);
+ } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
+ pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
+ pm_token_t content = { .type = PM_TOKEN_STRING_CONTENT, .start = parser->start + cast->value_loc.start, .end = parser->start + cast->value_loc.start + cast->value_loc.length };
+ pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->unescaped));
+ pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, 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 symbol 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_symbol_node_t *cast = (pm_symbol_node_t *) current;
- pm_token_t bounds = not_provided(parser);
-
- pm_token_t content = { .type = PM_TOKEN_STRING_CONTENT, .start = cast->value_loc.start, .end = cast->value_loc.end };
- pm_node_t *first_string = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->unescaped);
- pm_node_t *second_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, first_string);
- pm_interpolated_symbol_node_append(interpolated, second_string);
-
- xfree(current);
- 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, (uint16_t) (depth + 1));
- 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_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
+ pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
- pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
- if (!start_location_set) {
- current->location.start = part->location.start;
- }
- break;
+ // current is arena-allocated so no explicit free is needed.
+ current = UP(interpolated);
+ } else {
+ assert(false && "unreachable");
}
- 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);
+ if (current) {
+ pm_array_node_elements_append(parser->arena, array, current);
+ current = NULL;
+ } else {
+ 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_UPPER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
+ pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
+ closing = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
} else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
+ expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
}
- pm_array_node_close_set(array, &closing);
+ pm_array_node_close_set(parser, array, &closing);
- return (pm_node_t *) array;
+ return UP(array);
}
+ case PM_TOKEN_PERCENT_UPPER_I:
+ return parse_symbol_array(parser, depth);
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);
+ pm_node_t *current = NULL;
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);
+ // Interpolation is not possible but nested heredocs can still lead to
+ // consecutive (disjoint) string tokens when the final newline is escaped.
+ while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
+ pm_node_t *string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
+
+ // Record the string node, moving to interpolation if needed.
+ if (current == NULL) {
+ current = string;
+ } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
+ pm_interpolated_string_node_append(parser, (pm_interpolated_string_node_t *) current, string);
+ } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
+ pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, NULL, NULL, NULL);
+ pm_interpolated_string_node_append(parser, interpolated, current);
+ pm_interpolated_string_node_append(parser, interpolated, string);
+ current = UP(interpolated);
+ } else {
+ assert(false && "unreachable");
+ }
+ parser_lex(parser);
}
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
+ if (current) {
+ pm_array_node_elements_append(parser->arena, array, current);
+ current = NULL;
+ } else {
+ 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 };
+ closing = (pm_token_t) { .type = 0, .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, (uint16_t) (depth + 1));
- 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, (uint16_t) (depth + 1));
- 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;
+ pm_array_node_close_set(parser, array, &closing);
+ return UP(array);
}
+ case PM_TOKEN_PERCENT_UPPER_W:
+ return parse_string_array(parser, depth);
case PM_TOKEN_REGEXP_BEGIN: {
pm_token_t opening = parser->current;
parser_lex(parser);
@@ -20352,10 +20202,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_regular_expression_node_create(parser, &opening, &content, &parser->previous);
- pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
-
- return node;
+ pm_regular_expression_node_t *node = pm_regular_expression_node_create(parser, &opening, &content, &parser->previous);
+ pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
+ return UP(node);
}
pm_interpolated_regular_expression_node_t *interpolated;
@@ -20367,7 +20216,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// regular expression) or if it's not then it has interpolation.
pm_string_t unescaped = parser->current_string;
pm_token_t content = parser->current;
- bool ascii_only = parser->current_regular_expression_ascii_only;
parser_lex(parser);
// If we hit an end, then we can create a regular expression
@@ -20376,26 +20224,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (accept1(parser, PM_TOKEN_REGEXP_END)) {
pm_regular_expression_node_t *node = (pm_regular_expression_node_t *) pm_regular_expression_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- // If we're not immediately followed by a =~, then we want
- // to parse all of the errors at this point. If it is
- // followed by a =~, then it will get parsed higher up while
- // parsing the named captures as well.
+ // If we're not immediately followed by a =~, then we
+ // parse and validate now. If it is followed by a =~,
+ // then it will get parsed in the =~ handler where
+ // named captures can also be extracted.
if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
- parse_regular_expression_errors(parser, node);
+ pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
}
- pm_node_flag_set((pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.flags));
- return (pm_node_t *) node;
+ return UP(node);
}
// If we get here, then we have interpolation so we'll need to create
// a regular expression node with interpolation.
interpolated = 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_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
// This is extremely strange, but the first string part of a
// regular expression will always be tagged as binary if we
@@ -20403,7 +20247,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
}
- pm_interpolated_regular_expression_node_append(interpolated, part);
+ pm_interpolated_regular_expression_node_append(parser->arena, interpolated, 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
@@ -20416,20 +20260,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_t *part;
while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_interpolated_regular_expression_node_append(interpolated, part);
+ pm_interpolated_regular_expression_node_append(parser->arena, interpolated, 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 };
+ closing = (pm_token_t) { .type = 0, .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(parser, interpolated, &closing);
- return (pm_node_t *) interpolated;
+ return UP(interpolated);
}
case PM_TOKEN_BACKTICK:
case PM_TOKEN_PERCENT_LOWER_X: {
@@ -20451,7 +20295,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
};
parser_lex(parser);
- return (pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->previous);
+ return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
}
pm_interpolated_x_string_node_t *node;
@@ -20466,7 +20310,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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_t *node = UP(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;
@@ -20476,13 +20320,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// 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_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
pm_node_flag_set(part, parse_unescaped_encoding(parser));
- pm_interpolated_xstring_node_append(node, part);
+ pm_interpolated_xstring_node_append(parser->arena, 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
@@ -20493,20 +20334,20 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_t *part;
while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_interpolated_xstring_node_append(node, part);
+ pm_interpolated_xstring_node_append(parser->arena, 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 };
+ closing = (pm_token_t) { .type = 0, .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);
+ pm_interpolated_xstring_node_closing_set(parser, node, &closing);
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_USTAR: {
parser_lex(parser);
@@ -20516,17 +20357,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// still lex past it though and create a missing node place.
if (binding_power != PM_BINDING_POWER_STATEMENT) {
pm_parser_err_prefix(parser, diag_id);
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
}
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, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
+ name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
}
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name);
+ pm_node_t *splat = UP(pm_splat_node_create(parser, &operator, name));
if (match1(parser, PM_TOKEN_COMMA)) {
return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
@@ -20542,11 +20383,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!");
pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_TILDE: {
if (binding_power > PM_BINDING_POWER_UNARY) {
@@ -20555,10 +20396,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~");
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_UMINUS: {
if (binding_power > PM_BINDING_POWER_UNARY) {
@@ -20567,22 +20408,22 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@");
- return (pm_node_t *) node;
+ return UP(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, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
+ pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
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, false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
- node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
+ pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
+ node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
+ node = UP(pm_call_node_unary_create(parser, &operator, node, "-@"));
} else {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE:
@@ -20592,7 +20433,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parse_negative_numeric(node);
break;
default:
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
+ node = UP(pm_call_node_unary_create(parser, &operator, node, "-@"));
break;
}
}
@@ -20626,13 +20467,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
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);
+ pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
break;
}
case PM_CASE_PARAMETER: {
pm_accepts_block_stack_push(parser, false);
- pm_token_t opening = not_provided(parser);
- block_parameters = parse_block_parameters(parser, false, &opening, true, false, (uint16_t) (depth + 1));
+ block_parameters = parse_block_parameters(parser, false, NULL, true, false, (uint16_t) (depth + 1));
pm_accepts_block_stack_pop(parser);
break;
}
@@ -20650,39 +20490,37 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
opening = parser->previous;
if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
- body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1));
+ body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
}
parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
} 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, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
+ body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
}
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_implicit_begin(parser, opening_newline_index, &operator, opening.start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1));
+ body = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &operator, opening.start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1)));
} else {
parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
}
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &operator);
}
pm_constant_id_list_t locals;
pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
- pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &operator, &parser->previous);
+ pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &operator, &parser->previous);
pm_parser_scope_pop(parser);
pm_accepts_block_stack_pop(parser);
- return (pm_node_t *) pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, parameters, body);
+ return UP(pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, parameters, body));
}
case PM_TOKEN_UPLUS: {
if (binding_power > PM_BINDING_POWER_UNARY) {
@@ -20691,13 +20529,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@");
- return (pm_node_t *) node;
+ return UP(node);
}
case PM_TOKEN_STRING_BEGIN:
- return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
+ return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
parser_lex(parser);
@@ -20720,17 +20558,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// If we get here, then we are assuming this token is closing a
// parent context, so we'll indicate that to the user so that
// they know how we behaved.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_type_human(parser->current.type), context_human(recoverable));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
} else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
// We're going to make a special case here, because "cannot
// parse expression" is pretty generic, and we know here that we
// have an unexpected token.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
} else {
pm_parser_err_prefix(parser, diag_id);
}
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
}
}
}
@@ -20745,8 +20583,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
* or any of the binary operators that can be written to a variable.
*/
static 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, uint16_t depth) {
- 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, false, diag_id, (uint16_t) (depth + 1));
+parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
+ pm_node_t *value = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), diag_id, (uint16_t) (depth + 1));
+
+ // Assignments whose value is a command call (e.g., a = b c) can only
+ // be followed by modifiers (if/unless/while/until/rescue) and not by
+ // operators with higher binding power. If we find one, emit an error
+ // and skip the operator and its right-hand side.
+ if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ parser_lex(parser);
+ parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ }
// Contradicting binding powers, the right-hand-side value of the assignment
// allows the `rescue` modifier.
@@ -20756,10 +20604,10 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_
pm_token_t rescue = parser->current;
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
context_pop(parser);
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
+ return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
}
return value;
@@ -20814,35 +20662,46 @@ parse_assignment_value_local(pm_parser_t *parser, const pm_node_t *node) {
* operator that allows multiple values after it.
*/
static 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, uint16_t depth) {
+parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
bool permitted = true;
if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted = false;
- 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, (uint16_t) (depth + 1));
+ pm_node_t *value = parse_starred_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MODIFIER ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), diag_id, (uint16_t) (depth + 1));
if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
parse_assignment_value_local(parser, value);
bool single_value = true;
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
+ // Block calls (command call + do block, e.g., `foo bar do end`) cannot
+ // be followed by a comma to form a multi-value RHS because each element
+ // of a multi-value assignment must be an `arg`, not a `block_call`.
+ if (previous_binding_power == PM_BINDING_POWER_STATEMENT && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
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;
+ pm_array_node_t *array = pm_array_node_create(parser, NULL);
+ pm_array_node_elements_append(parser->arena, array, value);
+ value = UP(array);
while (accept1(parser, PM_TOKEN_COMMA)) {
pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
+ pm_array_node_elements_append(parser->arena, array, element);
+ if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE)) break;
parse_assignment_value_local(parser, element);
}
}
+ // Assignments whose value is a command call (e.g., a = b c) can only
+ // be followed by modifiers (if/unless/while/until/rescue) and not by
+ // operators with higher binding power. If we find one, emit an error
+ // and skip the operator and its right-hand side.
+ if (single_value && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
+ parser_lex(parser);
+ parse_expression(parser, pm_binding_powers[parser->previous.type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ }
+
// Contradicting binding powers, the right-hand-side value of the assignment
// allows the `rescue` modifier.
if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
@@ -20857,15 +20716,15 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
// but without parenthesis.
if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
pm_call_node_t *call_node = (pm_call_node_t *) value;
- if ((call_node->arguments != NULL) && (call_node->opening_loc.start == NULL)) {
+ if ((call_node->arguments != NULL) && (call_node->opening_loc.length == 0)) {
accepts_command_call_inner = true;
}
}
- pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, accepts_command_call_inner, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (accepts_command_call_inner ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
context_pop(parser);
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
+ return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
}
return value;
@@ -20882,43 +20741,18 @@ 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);
+ pm_node_unreference(parser, UP(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);
+ pm_node_unreference(parser, UP(call_node->block));
call_node->block = NULL;
}
}
-/**
- * This struct is used to pass information between the regular expression parser
- * and the named capture callback.
- */
-typedef struct {
- /** The parser that is parsing the regular expression. */
- pm_parser_t *parser;
-
- /** The call node wrapping the regular expression node. */
- pm_call_node_t *call;
-
- /** The match write node that is being created. */
- pm_match_write_node_t *match;
-
- /** The list of names that have been parsed. */
- pm_constant_id_list_t names;
-
- /**
- * Whether the content of the regular expression is shared. This impacts
- * whether or not we used owned constants or shared constants in the
- * constant pool for the names of the captures.
- */
- bool shared;
-} parse_regular_expression_named_capture_data_t;
-
-static inline const uint8_t *
+static PRISM_INLINE const uint8_t *
pm_named_capture_escape_hex(pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
cursor++;
@@ -20939,7 +20773,7 @@ pm_named_capture_escape_hex(pm_buffer_t *unescaped, const uint8_t *cursor, const
return cursor;
}
-static inline const uint8_t *
+static PRISM_INLINE const uint8_t *
pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
uint8_t value = (uint8_t) (*cursor - '0');
cursor++;
@@ -20958,8 +20792,8 @@ pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, con
return cursor;
}
-static inline const uint8_t *
-pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
+static PRISM_INLINE const uint8_t *
+pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end, const pm_location_t *error_location) {
const uint8_t *start = cursor - 1;
cursor++;
@@ -20970,7 +20804,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
if (*cursor != '{') {
size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
- uint32_t value = escape_unicode(parser, cursor, length);
+ uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
pm_buffer_append_string(unescaped, (const char *) start, (size_t) ((cursor + length) - start));
@@ -20990,7 +20824,10 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
}
size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
- uint32_t value = escape_unicode(parser, cursor, length);
+ if (length == 0) {
+ break;
+ }
+ uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
(void) pm_buffer_append_unicode_codepoint(unescaped, value);
cursor += length;
@@ -21000,7 +20837,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
}
static void
-pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *source, const size_t length, const uint8_t *cursor) {
+pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *source, const size_t length, const uint8_t *cursor, const pm_location_t *error_location) {
const uint8_t *end = source + length;
pm_buffer_append_string(unescaped, (const char *) source, (size_t) (cursor - source));
@@ -21018,7 +20855,7 @@ pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8
cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
break;
case 'u':
- cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
+ cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
break;
default:
pm_buffer_append_byte(unescaped, '\\');
@@ -21040,10 +20877,7 @@ pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8
* capture group.
*/
static void
-parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
- parse_regular_expression_named_capture_data_t *callback_data = (parse_regular_expression_named_capture_data_t *) data;
-
- pm_parser_t *parser = callback_data->parser;
+parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *capture, bool shared, pm_regexp_name_data_t *callback_data) {
pm_call_node_t *call = callback_data->call;
pm_constant_id_list_t *names = &callback_data->names;
@@ -21061,55 +20895,56 @@ parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
// unescaped, which is what we need.
const uint8_t *cursor = pm_memchr(source, '\\', length, parser->encoding_changed, parser->encoding);
if (PRISM_UNLIKELY(cursor != NULL)) {
- pm_named_capture_escape(parser, &unescaped, source, length, cursor);
+ pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
source = (const uint8_t *) pm_buffer_value(&unescaped);
length = pm_buffer_length(&unescaped);
}
- pm_location_t location;
+ const uint8_t *start;
+ const uint8_t *end;
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 (!pm_slice_is_valid_local(parser, source, source + length)) {
- pm_buffer_free(&unescaped);
+ pm_buffer_cleanup(&unescaped);
return;
}
- if (callback_data->shared) {
+ if (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);
+ start = source;
+ end = source + length;
+ name = pm_parser_constant_id_raw(parser, start, end);
} 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 = (pm_location_t) { .start = call->receiver->location.start, .end = call->receiver->location.end };
-
- void *memory = xmalloc(length);
- if (memory == NULL) abort();
+ start = parser->start + PM_NODE_START(call->receiver);
+ end = parser->start + PM_NODE_END(call->receiver);
+ uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
memcpy(memory, source, length);
- name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
+ name = pm_parser_constant_id_owned(parser, memory, length);
}
// Add this name to the list of constants if it is valid, not duplicated,
// and not a keyword.
if (name != 0 && !pm_constant_id_list_includes(names, name)) {
- pm_constant_id_list_append(names, name);
+ pm_constant_id_list_append(parser->arena, names, name);
int depth;
if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
// If the local is not already a local but it is a keyword, then we
// do not want to add a capture for this.
if (pm_local_is_keyword((const char *) source, length)) {
- pm_buffer_free(&unescaped);
+ pm_buffer_cleanup(&unescaped);
return;
}
// If the identifier is not already a local, then we will add it to
// the local table.
- pm_parser_local_add(parser, name, location.start, location.end, 0);
+ pm_parser_local_add(parser, name, start, end, 0);
}
// Here we lazily create the MatchWriteNode since we know we're
@@ -21120,45 +20955,37 @@ parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
// 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(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
- pm_node_list_append(&callback_data->match->targets, target);
+ pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &TOK2LOC(parser, &((pm_token_t) { .type = 0, .start = start, .end = end })), name, depth == -1 ? 0 : (uint32_t) depth));
+ pm_node_list_append(parser->arena, &callback_data->match->targets, target);
}
- pm_buffer_free(&unescaped);
+ pm_buffer_cleanup(&unescaped);
}
/**
- * Potentially change a =~ with a regular expression with named captures into a
- * match write node.
+ * Potentially change a =~ with an interpolated regular expression with named
+ * captures into a match write node. This is for the interpolated case where
+ * we have concatenated content rather than a regular expression node.
*/
static pm_node_t *
-parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *content, pm_call_node_t *call, bool extended_mode) {
- parse_regular_expression_named_capture_data_t callback_data = {
- .parser = parser,
+parse_interpolated_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *content, pm_call_node_t *call, bool extended_mode) {
+ pm_regexp_name_data_t callback_data = {
.call = call,
+ .match = NULL,
.names = { 0 },
- .shared = content->type == PM_STRING_SHARED
};
- parse_regular_expression_error_data_t error_data = {
- .parser = parser,
- .start = call->receiver->location.start,
- .end = call->receiver->location.end,
- .shared = content->type == PM_STRING_SHARED
- };
-
- pm_regexp_parse(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &callback_data, parse_regular_expression_error, &error_data);
- pm_constant_id_list_free(&callback_data.names);
+ pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content), false, extended_mode, parse_regular_expression_named_capture, &callback_data);
if (callback_data.match != NULL) {
- return (pm_node_t *) callback_data.match;
+ return UP(callback_data.match);
} else {
- return (pm_node_t *) call;
+ return UP(call);
}
}
-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, uint16_t depth) {
+static PRISM_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, uint8_t flags, uint16_t depth) {
pm_token_t token = parser->current;
switch (token.type) {
@@ -21171,13 +20998,20 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// is parsed because it could be referenced in the value.
pm_call_node_t *call_node = (pm_call_node_t *) node;
if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- pm_parser_local_add_location(parser, call_node->message_loc.start, call_node->message_loc.end, 0);
+ pm_parser_local_add_location(parser, &call_node->message_loc, 0);
}
}
PRISM_FALLTHROUGH
case PM_CASE_WRITABLE: {
+ // When we have `it = value`, we need to add `it` as a local
+ // variable before parsing the value, in case the value
+ // references the variable.
+ if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
+ pm_parser_local_add_location(parser, &node->location, 0);
+ }
+
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, (uint16_t) (depth + 1));
+ 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, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
@@ -21190,8 +21024,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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, (uint16_t) (depth + 1));
- return parse_write(parser, (pm_node_t *) multi_target, &token, value);
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
+ return parse_write(parser, UP(multi_target), &token, value);
}
case PM_SOURCE_ENCODING_NODE:
case PM_FALSE_NODE:
@@ -21203,7 +21037,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// In these special cases, we have specific error messages
// and we will replace them with local variable writes.
parser_lex(parser);
- pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
+ pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
return parse_unwriteable_write(parser, node, &token, value);
}
default:
@@ -21224,71 +21058,65 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
return parse_shareable_constant_write(parser, write);
}
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, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
- pm_node_destroy(parser, node);
return parse_shareable_constant_write(parser, write);
}
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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
- parse_target_implicit_parameter(parser, node);
- pm_node_destroy(parser, node);
+ pm_node_unreference(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + node->location.start);
+ pm_node_unreference(parser, 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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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: {
@@ -21298,16 +21126,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// receiver that could have been a local variable) then we
// will transform it into a local variable write.
if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- 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, 1);
+ pm_refute_numbered_parameter(parser, cast->message_loc.start, cast->message_loc.length);
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, &cast->message_loc, 1);
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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
- pm_node_destroy(parser, (pm_node_t *) cast);
return result;
}
@@ -21319,8 +21144,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// this is an aref expression, and we can transform it into
// an aset expression.
if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ return UP(pm_index_and_write_node_create(parser, cast, &token, value));
}
// If this node cannot be writable, then we have an error.
@@ -21331,8 +21156,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
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, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
+ return UP(pm_call_and_write_node_create(parser, cast, &token, value));
}
case PM_MULTI_WRITE_NODE: {
parser_lex(parser);
@@ -21358,71 +21183,65 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
return parse_shareable_constant_write(parser, write);
}
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, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
- pm_node_destroy(parser, node);
return parse_shareable_constant_write(parser, write);
}
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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
- parse_target_implicit_parameter(parser, node);
- pm_node_destroy(parser, node);
+ pm_node_unreference(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
+ pm_node_unreference(parser, 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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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: {
@@ -21432,16 +21251,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// receiver that could have been a local variable) then we
// will transform it into a local variable write.
if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- 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, 1);
+ pm_refute_numbered_parameter(parser, cast->message_loc.start, cast->message_loc.length);
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, &cast->message_loc, 1);
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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
- pm_node_destroy(parser, (pm_node_t *) cast);
return result;
}
@@ -21453,8 +21269,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// this is an aref expression, and we can transform it into
// an aset expression.
if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ return UP(pm_index_or_write_node_create(parser, cast, &token, value));
}
// If this node cannot be writable, then we have an error.
@@ -21465,8 +21281,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
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, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
+ return UP(pm_call_or_write_node_create(parser, cast, &token, value));
}
case PM_MULTI_WRITE_NODE: {
parser_lex(parser);
@@ -21502,71 +21318,65 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
return parse_shareable_constant_write(parser, write);
}
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, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *write = UP(pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
- pm_node_destroy(parser, node);
return parse_shareable_constant_write(parser, write);
}
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, (uint16_t) (depth + 1));
- 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_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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_IT_LOCAL_VARIABLE_READ_NODE: {
pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
- parse_target_implicit_parameter(parser, node);
- pm_node_destroy(parser, node);
+ pm_node_unreference(parser, node);
return result;
}
case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, node->location.start, node->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, node->location.start);
- parse_target_implicit_parameter(parser, node);
+ if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
+ PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
+ pm_node_unreference(parser, 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, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(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: {
@@ -21577,14 +21387,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// receiver that could have been a local variable) then we
// will transform it into a local variable write.
if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- pm_location_t *message_loc = &cast->message_loc;
- pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
+ pm_refute_numbered_parameter(parser, cast->message_loc.start, cast->message_loc.length);
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, &cast->message_loc, 1);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- 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;
}
@@ -21592,8 +21399,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// this is an aref expression, and we can transform it into
// an aset expression.
if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
}
// If this node cannot be writable, then we have an error.
@@ -21604,8 +21411,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
}
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, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
+ pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
}
case PM_MULTI_WRITE_NODE: {
parser_lex(parser);
@@ -21618,7 +21425,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_type_human(parser->current.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
return node;
}
}
@@ -21626,15 +21433,15 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_TOKEN_KEYWORD_AND: {
parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_AND, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_and_node_create(parser, node, &token, right);
+ pm_node_t *right = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->previous.type == PM_TOKEN_KEYWORD_AND ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(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, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_or_node_create(parser, node, &token, right);
+ pm_node_t *right = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->previous.type == PM_TOKEN_KEYWORD_OR ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_or_node_create(parser, node, &token, right));
}
case PM_TOKEN_EQUAL_TILDE: {
// Note that we _must_ parse the value before adding the local
@@ -21645,11 +21452,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
//
// 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, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
// 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, 0);
- pm_node_t *result = (pm_node_t *) call;
+ pm_node_t *result = UP(call);
// If the receiver of this =~ is a regular expression node, then we
// need to introduce local variables for it based on its named
@@ -21690,14 +21497,25 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_string_t owned;
pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
- result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
- pm_string_free(&owned);
+ result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
+ pm_string_cleanup(&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, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
+ // If we have a regular expression node, then we can parse
+ // the named captures and validate encoding in one pass.
+ pm_regular_expression_node_t *regexp = (pm_regular_expression_node_t *) node;
+
+ pm_regexp_name_data_t name_data = {
+ .call = call,
+ .match = NULL,
+ .names = { 0 },
+ };
+
+ pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
+
+ if (name_data.match != NULL) {
+ result = UP(name_data.match);
+ }
}
return result;
@@ -21729,21 +21547,21 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_RESCUE_MODIFIER_NODE: {
pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
if (PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_AND_NODE: {
pm_and_node_t *cast = (pm_and_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_OR_NODE: {
pm_or_node_t *cast = (pm_or_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
@@ -21751,20 +21569,20 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
break;
}
- pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
+ pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
}
case PM_TOKEN_GREATER:
case PM_TOKEN_GREATER_EQUAL:
case PM_TOKEN_LESS:
case PM_TOKEN_LESS_EQUAL: {
if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
- PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
+ PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
}
parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
+ pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
}
case PM_TOKEN_AMPERSAND_DOT:
case PM_TOKEN_DOT: {
@@ -21775,28 +21593,28 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// This if statement handles the foo.() syntax.
if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
parse_arguments_list(parser, &arguments, true, false, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &operator, &arguments);
+ return UP(pm_call_node_shorthand_create(parser, node, &operator, &arguments));
}
switch (PM_NODE_TYPE(node)) {
case PM_RESCUE_MODIFIER_NODE: {
pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
if (PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_AND_NODE: {
pm_and_node_t *cast = (pm_and_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
case PM_OR_NODE: {
pm_or_node_t *cast = (pm_or_node_t *) node;
if (PM_NODE_TYPE_P(cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->right, PM_MATCH_REQUIRED_NODE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(operator.type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(operator.type));
}
break;
}
@@ -21817,23 +21635,23 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
break;
}
default: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_type_human(parser->current.type));
- message = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
+ message = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
}
}
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
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 &&
+ arguments.opening_loc.length == 0 &&
match1(parser, PM_TOKEN_COMMA)
) {
- return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
+ return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
} else {
- return (pm_node_t *) call;
+ return UP(call);
}
}
case PM_TOKEN_DOT_DOT:
@@ -21842,40 +21660,40 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_t *right = NULL;
if (token_begins_expression_p(parser->current.type)) {
- right = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
+ right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
}
- return (pm_node_t *) pm_range_node_create(parser, node, &token, right);
+ return UP(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, false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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, false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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(parser, statements, node, true);
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
- 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);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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(parser, statements, node, true);
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
- 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);
+ pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
+ return UP(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: {
context_push(parser, PM_CONTEXT_TERNARY);
@@ -21885,7 +21703,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_token_t qmark = parser->current;
parser_lex(parser);
- pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
+ pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
if (parser->recovering) {
// If parsing the true expression of this ternary resulted in a syntax
@@ -21894,27 +21712,23 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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);
+ pm_token_t colon = (pm_token_t) { .type = 0, .start = parser->previous.end, .end = parser->previous.end };
+ pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
context_pop(parser);
pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
+ return UP(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, false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
+ pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
context_pop(parser);
pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
+ return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
}
case PM_TOKEN_COLON_COLON: {
parser_lex(parser);
@@ -21927,7 +21741,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
if (
(parser->current.type == 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)))
+ ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (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
@@ -21938,11 +21752,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_token_t message = parser->previous;
pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
+ path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
} else {
// Otherwise, this is a constant path. That would look like Foo::Bar.
- path = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
+ path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
}
// If this is followed by a comma then it is a multiple assignment.
@@ -21962,15 +21776,15 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
// 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, (uint16_t) (depth + 1));
+ parse_arguments_list(parser, &arguments, true, flags, (uint16_t) (depth + 1));
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, (uint16_t) (depth + 1));
+ return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
}
- return (pm_node_t *) call;
+ return UP(call);
}
case PM_TOKEN_PARENTHESIS_LEFT: {
// If we have a parenthesis following a '::' operator, then it is the
@@ -21978,11 +21792,11 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_arguments_t arguments = { 0 };
parse_arguments_list(parser, &arguments, true, false, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
+ return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
}
default: {
expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- return (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
+ return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
}
}
}
@@ -21991,31 +21805,31 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
parser_lex(parser);
accept1(parser, PM_TOKEN_NEWLINE);
- pm_node_t *value = parse_expression(parser, binding_power, true, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
+ pm_node_t *value = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
context_pop(parser);
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
+ return UP(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);
+ arguments.opening_loc = TOK2LOC(parser, &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, (uint16_t) (depth + 1));
+ parse_arguments(parser, &arguments, false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
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);
+ arguments.closing_loc = TOK2LOC(parser, &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, (uint16_t) (depth + 1));
+ return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
}
// If we're at the end of the arguments, we can now check if there is a
@@ -22031,17 +21845,17 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
if (block != NULL) {
if (arguments.block != NULL) {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
+ pm_parser_err_node(parser, UP(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);
+ pm_arguments_node_arguments_append(parser->arena, arguments.arguments, arguments.block);
}
- arguments.block = (pm_node_t *) block;
+ arguments.block = UP(block);
}
- return (pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
+ return UP(pm_call_node_aref_create(parser, node, &arguments));
}
case PM_TOKEN_KEYWORD_IN: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -22056,9 +21870,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- pm_constant_id_list_free(&captures);
- return (pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &operator);
+ return UP(pm_match_predicate_node_create(parser, node, pattern, &operator));
}
case PM_TOKEN_EQUAL_GREATER: {
bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
@@ -22073,9 +21886,8 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, (uint16_t) (depth + 1));
parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- pm_constant_id_list_free(&captures);
- return (pm_node_t *) pm_match_required_node_create(parser, node, pattern, &operator);
+ return UP(pm_match_required_node_create(parser, node, pattern, &operator));
}
default:
assert(false && "unreachable");
@@ -22088,16 +21900,83 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
#undef PM_PARSE_PATTERN_MULTI
/**
- * Determine if a given call node looks like a "command", which means it has
- * arguments but does not have parentheses.
+ * Some nodes act as statements and limit which operators can follow. This
+ * function inspects the node and the upcoming token to determine whether the
+ * expression loop should stop. It is called both after prefix parsing and after
+ * each infix operator.
+ *
+ * As a side effect, this function also attaches do-blocks to command-style call
+ * nodes when appropriate.
+ *
+ * Returns true if the expression loop should stop (i.e., the next operator
+ * should not be consumed).
*/
-static inline bool
-pm_call_node_command_p(const pm_call_node_t *node) {
- return (
- (node->opening_loc.start == NULL) &&
- (node->block == NULL || PM_NODE_TYPE_P(node->block, PM_BLOCK_ARGUMENT_NODE)) &&
- (node->arguments != NULL || node->block != NULL)
- );
+static bool
+parse_expression_terminator(pm_parser_t *parser, pm_node_t *node) {
+ pm_binding_power_t left = pm_binding_powers[parser->current.type].left;
+
+ switch (PM_NODE_TYPE(node)) {
+ case PM_MULTI_WRITE_NODE:
+ case PM_RETURN_NODE:
+ case PM_BREAK_NODE:
+ case PM_NEXT_NODE:
+ return left > PM_BINDING_POWER_MODIFIER;
+ case PM_CLASS_VARIABLE_WRITE_NODE:
+ case PM_CONSTANT_PATH_WRITE_NODE:
+ case PM_CONSTANT_WRITE_NODE:
+ case PM_GLOBAL_VARIABLE_WRITE_NODE:
+ case PM_INSTANCE_VARIABLE_WRITE_NODE:
+ case PM_LOCAL_VARIABLE_WRITE_NODE:
+ return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
+ case PM_CALL_NODE: {
+ // Calls with an implicit array on the right-hand side are
+ // statements and can only be followed by modifiers.
+ if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
+ return left > PM_BINDING_POWER_MODIFIER;
+ }
+
+ // Command-style calls (including block commands like
+ // `foo bar do end`) can only be followed by composition
+ // (and/or) and modifier (if/unless/etc.) operators.
+ if (pm_command_call_value_p(node)) {
+ return left > PM_BINDING_POWER_COMPOSITION;
+ }
+
+ // A block call (command with do-block, or any call chained
+ // from one) can only be followed by call chaining (., ::,
+ // &.), composition (and/or), and modifier operators.
+ if (pm_block_call_p(node)) {
+ return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL;
+ }
+
+ return false;
+ }
+ case PM_SUPER_NODE:
+ case PM_YIELD_NODE:
+ // Command-style super/yield (without parens) can only be followed
+ // by composition and modifier operators.
+ if (pm_command_call_value_p(node)) {
+ return left > PM_BINDING_POWER_COMPOSITION;
+ }
+ return false;
+ case PM_DEF_NODE:
+ // An endless method whose body is a command-style call (e.g.,
+ // `def f = foo bar`) is a command assignment and can only be
+ // followed by modifiers.
+ return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(node);
+ case PM_RESCUE_MODIFIER_NODE:
+ // A rescue modifier whose handler is a pattern match (=> or in)
+ // produces a statement and cannot be followed by operators above
+ // the modifier level.
+ if (left > PM_BINDING_POWER_MODIFIER) {
+ pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
+ pm_node_t *rescue_expression = cast->rescue_expression;
+ return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
+ }
+ return false;
+ default:
+ return false;
+ }
}
/**
@@ -22109,46 +21988,40 @@ pm_call_node_command_p(const pm_call_node_t *node) {
* 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, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) {
+parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
+ return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
}
- pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
+ pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
+ // Some prefix nodes are statements and can only be followed by modifiers
+ // (if/unless/while/until/rescue) or nothing at all. We check these cheaply
+ // here before entering the infix loop.
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.
+ case PM_ERROR_RECOVERY_NODE:
return node;
case PM_PRE_EXECUTION_NODE:
+ return node;
case PM_POST_EXECUTION_NODE:
case PM_ALIAS_GLOBAL_VARIABLE_NODE:
case PM_ALIAS_METHOD_NODE:
- case PM_MULTI_WRITE_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) {
return node;
}
break;
case PM_CALL_NODE:
- // If we have a call node, then we need to check if it looks like a
- // method call without parentheses that contains arguments. If it
- // does, then it has different rules for parsing infix operators,
- // namely that it only accepts composition (and/or) and modifiers
- // (if/unless/etc.).
- if ((pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((pm_call_node_t *) node)) {
+ case PM_SUPER_NODE:
+ case PM_YIELD_NODE:
+ case PM_DEF_NODE:
+ if (parse_expression_terminator(parser, node)) {
return node;
}
break;
case PM_SYMBOL_NODE:
- // If we have a symbol node that is being parsed as a label, then we
- // need to immediately return, because there should never be an
- // infix operator following this node.
- if (pm_symbol_node_label_p(node)) {
+ if (pm_symbol_node_label_p(parser, node)) {
return node;
}
break;
@@ -22156,8 +22029,8 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
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.
+ // 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;
pm_token_type_t current_token_type;
@@ -22167,39 +22040,8 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
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, (uint16_t) (depth + 1));
-
- switch (PM_NODE_TYPE(node)) {
- case PM_MULTI_WRITE_NODE:
- // Multi-write nodes are statements, and cannot be followed by
- // operators except modifiers.
- if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- case PM_CLASS_VARIABLE_WRITE_NODE:
- case PM_CONSTANT_PATH_WRITE_NODE:
- case PM_CONSTANT_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_WRITE_NODE:
- case PM_LOCAL_VARIABLE_WRITE_NODE:
- // These expressions are statements, by virtue of the right-hand
- // side of their write being an implicit array.
- if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- case PM_CALL_NODE:
- // These expressions are also statements, by virtue of the
- // right-hand side of the expression (i.e., the last argument to
- // the call node) being an implicit array.
- if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- default:
- break;
- }
+ node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, flags, (uint16_t) (depth + 1));
+ if (parse_expression_terminator(parser, node)) return node;
// If the operator is nonassoc and we should not be able to parse the
// upcoming infix operator, break.
@@ -22207,7 +22049,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
// If this is a non-assoc operator and we are about to parse the
// exact same operator, then we need to add an error.
if (match1(parser, current_token_type)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type));
break;
}
@@ -22220,7 +22062,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
//
if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type));
break;
}
@@ -22232,7 +22074,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
}
}
- if (accepts_command_call) {
+ if (flags & PM_PARSE_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:
@@ -22247,29 +22089,29 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
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] == ']'
+ cast->call_operator_loc.length == 0 &&
+ cast->message_loc.length > 0 &&
+ parser->start[cast->message_loc.start] == '[' &&
+ parser->start[cast->message_loc.start + cast->message_loc.length - 1] == ']'
) &&
// (2) foo.bar
!(
- cast->call_operator_loc.start != NULL &&
+ cast->call_operator_loc.length > 0 &&
cast->arguments == NULL &&
cast->block == NULL &&
- cast->opening_loc.start == NULL
+ cast->opening_loc.length == 0
) &&
// (3) foo.bar(1)
!(
- cast->call_operator_loc.start != NULL &&
- cast->opening_loc.start != NULL
+ cast->call_operator_loc.length > 0 &&
+ cast->opening_loc.length > 0
) &&
// (4) foo.bar do end
!(
cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)
)
) {
- accepts_command_call = false;
+ flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
}
break;
}
@@ -22277,10 +22119,21 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
case PM_CONSTANT_PATH_NODE:
break;
default:
- accepts_command_call = false;
+ flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
break;
}
}
+
+ if (context_terminator(parser->current_context->context, &parser->current)) {
+ pm_binding_powers_t next_binding_powers = pm_binding_powers[parser->current.type];
+ if (
+ !next_binding_powers.binary ||
+ binding_power > next_binding_powers.left ||
+ (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((pm_call_node_t *) node))
+ ) {
+ return node;
+ }
+ }
}
return node;
@@ -22299,15 +22152,16 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
pm_arguments_node_arguments_append(
+ parser->arena,
arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2))
+ UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2)))
);
- pm_statements_node_body_append(parser, statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
+ pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
parser,
arguments,
pm_parser_constant_id_constant(parser, "print", 5)
- ), true);
+ )), true);
}
if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
@@ -22318,47 +22172,49 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
pm_arguments_node_arguments_append(
+ parser->arena,
arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$;", 2))
+ UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$;", 2)))
);
pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2));
- pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (pm_node_t *) receiver, "split", arguments);
+ pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver), "split", arguments);
pm_global_variable_write_node_t *write = pm_global_variable_write_node_synthesized_create(
parser,
pm_parser_constant_id_constant(parser, "$F", 2),
- (pm_node_t *) call
+ UP(call)
);
- pm_statements_node_body_prepend(statements, (pm_node_t *) write);
+ pm_statements_node_body_prepend(parser->arena, statements, UP(write));
}
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
pm_arguments_node_arguments_append(
+ parser->arena,
arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$/", 2))
+ UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$/", 2)))
);
if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser);
- pm_keyword_hash_node_elements_append(keywords, (pm_node_t *) pm_assoc_node_create(
+ pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
parser,
- (pm_node_t *) pm_symbol_node_synthesized_create(parser, "chomp"),
- &(pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->start, .end = parser->start },
- (pm_node_t *) pm_true_node_synthesized_create(parser)
- ));
+ UP(pm_symbol_node_synthesized_create(parser, "chomp")),
+ NULL,
+ UP(pm_true_node_synthesized_create(parser))
+ )));
- pm_arguments_node_arguments_append(arguments, (pm_node_t *) keywords);
- pm_node_flag_set((pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
+ pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
+ pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
}
pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
+ pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
parser,
- (pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser, "gets", 4)),
+ UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser, "gets", 4))),
statements
- ), true);
+ )), true);
statements = wrapped_statements;
}
@@ -22402,7 +22258,6 @@ parse_program(pm_parser_t *parser) {
statements = wrap_statements(parser, statements);
} else {
flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
}
// If this is an empty file, then we're still going to parse all of the
@@ -22410,10 +22265,10 @@ parse_program(pm_parser_t *parser) {
// correct the location information.
if (statements == NULL) {
statements = pm_statements_node_create(parser);
- pm_statements_node_location_set(statements, parser->start, parser->start);
+ statements->base.location = (pm_location_t) { 0 };
}
- return (pm_node_t *) pm_program_node_create(parser, &locals, statements);
+ return UP(pm_program_node_create(parser, &locals, statements));
}
/******************************************************************************/
@@ -22422,8 +22277,8 @@ parse_program(pm_parser_t *parser) {
/**
* A vendored version of strnstr that is used to find a substring within a
- * string with a given length. This function is used to search for the Ruby
- * engine name within a shebang when the -x option is passed to Ruby.
+ * string with a given length. This function is used to search for "ruby"
+ * within a shebang when the -x option is passed to Ruby.
*
* The only modification that we made here is that we don't do NULL byte checks
* because we know the little parameter will not have a NULL byte and we allow
@@ -22433,7 +22288,7 @@ static const char *
pm_strnstr(const char *big, const char *little, size_t big_length) {
size_t little_length = strlen(little);
- for (const char *big_end = big + big_length; big < big_end; big++) {
+ for (const char *max = big + big_length - little_length; big <= max; big++) {
if (*big == *little && memcmp(big, little, little_length) == 0) return big;
}
@@ -22451,7 +22306,7 @@ pm_strnstr(const char *big, const char *little, size_t big_length) {
static void
pm_parser_warn_shebang_carriage_return(pm_parser_t *parser, const uint8_t *start, size_t length) {
if (length > 2 && start[length - 2] == '\r' && start[length - 1] == '\n') {
- pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
+ pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
}
}
#endif
@@ -22486,11 +22341,14 @@ pm_parser_init_shebang(pm_parser_t *parser, const pm_options_t *options, const c
/**
* 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) {
+void
+pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options) {
+ assert(arena != NULL);
assert(source != NULL);
*parser = (pm_parser_t) {
+ .arena = arena,
+ .metadata_arena = { 0 },
.node_id = 0,
.lex_state = PM_LEX_STATE_BEG,
.enclosure_nesting = 0,
@@ -22509,7 +22367,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
.next_start = NULL,
.heredoc_end = NULL,
- .data_loc = { .start = NULL, .end = NULL },
+ .data_loc = { 0 },
.comment_list = { 0 },
.magic_comment_list = { 0 },
.warning_list = { 0 },
@@ -22519,11 +22377,11 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.encoding = PM_ENCODING_UTF_8_ENTRY,
.encoding_changed_callback = NULL,
.encoding_comment_start = source,
- .lex_callback = NULL,
+ .lex_callback = { 0 },
.filepath = { 0 },
.constant_pool = { 0 },
- .newline_list = { 0 },
- .integer_base = 0,
+ .line_offsets = { 0 },
+ .integer = { 0 },
.current_string = PM_STRING_EMPTY,
.start_line = 1,
.explicit_encoding = NULL,
@@ -22532,6 +22390,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.partial_script = false,
.command_start = true,
.recovering = false,
+ .continuable = true,
.encoding_locked = false,
.encoding_changed = false,
.pattern_matching_newlines = false,
@@ -22539,32 +22398,30 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.current_block_exits = NULL,
.semantic_token_seen = false,
.frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET,
- .current_regular_expression_ascii_only = false,
.warn_mismatched_indentation = true
};
- // 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.
+ /* Pre-size the arenas based on input size to reduce the number of block
+ * allocations (and the kernel page zeroing they trigger). The ratios were
+ * measured empirically: AST arena ~3.3x input, metadata arena ~1.1x input.
+ * The reserve call is a no-op when the capacity is at or below the default
+ * arena block size, so small inputs don't waste an extra allocation. */
+ if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
+ if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
+
+ /* Initialize the constant pool. Measured across 1532 Ruby stdlib files, the
+ * bytes/constant ratio has a median of ~56 and a 90th percentile of ~135.
+ * We use 120 as a balance between over-allocation waste and resize
+ * frequency. Resizes are cheap with arena allocation, so we lean toward
+ * under-estimating. */
+ uint32_t constant_size = ((uint32_t) size) / 120;
+ pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
+
+ /* Initialize the line offset list. Similar to the constant pool, we are
+ * going to estimate the number of newlines that we will 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);
+ pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
// If options were provided to this parse, establish them here.
if (options != NULL) {
@@ -22601,7 +22458,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
if (parser->parsing_eval) parser->warn_mismatched_indentation = false;
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);
+ const pm_options_scope_t *scope = pm_options_scope(options, scope_index);
pm_parser_scope_push(parser, scope_index == 0);
// Scopes given from the outside are not allowed to have numbered
@@ -22609,20 +22466,24 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
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 pm_string_t *local = pm_options_scope_local(scope, local_index);
const uint8_t *source = pm_string_source(local);
size_t length = pm_string_length(local);
- void *allocated = xmalloc(length);
- if (allocated == NULL) continue;
-
+ uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
memcpy(allocated, source, length);
- pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
+ pm_parser_local_add_owned(parser, allocated, length);
}
}
}
+ // Now that we have established the user-provided options, check if
+ // a version was given and parse as the latest version otherwise.
+ if (parser->version == PM_OPTIONS_VERSION_UNSET) {
+ parser->version = PM_OPTIONS_VERSION_LATEST;
+ }
+
pm_accepts_block_stack_push(parser, true);
// Skip past the UTF-8 BOM if it exists.
@@ -22656,8 +22517,8 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
// If the shebang does not include "ruby" and this is the main script being
// parsed, then we will start searching the file for a shebang that does
// contain "ruby" as if -x were passed on the command line.
- const uint8_t *newline = next_newline(parser->start, parser->end - parser->start);
- size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->start);
+ const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
+ size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
if (length > 2 && parser->current.end[0] == '#' && parser->current.end[1] == '!') {
const char *engine;
@@ -22676,7 +22537,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
}
search_shebang = false;
- } else if (options->main_script && !parser->parsing_eval) {
+ } else if (options != NULL && options->main_script && !parser->parsing_eval) {
search_shebang = true;
}
}
@@ -22697,7 +22558,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
const uint8_t *newline = next_newline(cursor, parser->end - cursor);
while (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
+ pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
cursor = newline + 1;
newline = next_newline(cursor, parser->end - cursor);
@@ -22726,8 +22587,8 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
parser->previous = (pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
parser->current = (pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
} else {
- pm_parser_err(parser, parser->start, parser->start, PM_ERR_SCRIPT_NOT_FOUND);
- pm_newline_list_clear(&parser->newline_list);
+ pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
+ pm_line_offset_list_clear(&parser->line_offsets);
}
}
@@ -22738,56 +22599,28 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
}
/**
- * 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;
- xfree(comment);
- }
-}
-
-/**
- * Free all of the memory associated with the magic comment list.
+ * Allocate and initialize a parser with the given start and end pointers.
+ *
+ * The resulting parser must eventually be freed with `pm_parser_free()`. The
+ * arena is caller-owned and must outlive the parser — `pm_parser_cleanup()`
+ * does not free the arena.
*/
-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_parser_t *
+pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) {
+ pm_parser_t *parser = (pm_parser_t *) xmalloc(sizeof(pm_parser_t));
+ if (parser == NULL) abort();
- pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) node;
- xfree(magic_comment);
- }
+ pm_parser_init(arena, parser, source, size, options);
+ return parser;
}
/**
* Free any memory associated with the given parser.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_parser_free(pm_parser_t *parser) {
- pm_string_free(&parser->filepath);
- 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);
+void
+pm_parser_cleanup(pm_parser_t *parser) {
+ pm_string_cleanup(&parser->filepath);
+ pm_arena_cleanup(&parser->metadata_arena);
while (parser->current_scope != NULL) {
// Normally, popping the scope doesn't free the locals since it is
@@ -22803,145 +22636,224 @@ pm_parser_free(pm_parser_t *parser) {
}
/**
- * Parse the Ruby source associated with the given parser and return the tree.
+ * Free both the memory held by the given parser and the parser itself.
*/
-PRISM_EXPORTED_FUNCTION pm_node_t *
-pm_parse(pm_parser_t *parser) {
- return parse_program(parser);
+void
+pm_parser_free(pm_parser_t *parser) {
+ pm_parser_cleanup(parser);
+ xfree_sized(parser, sizeof(pm_parser_t));
}
/**
- * Read into the stream until the gets callback returns false. If the last read
- * line from the stream matches an __END__ marker, then halt and return false,
- * otherwise return true.
+ * Returns true if the given diagnostic ID represents an error that cannot be
+ * fixed by appending more input. These are errors where the existing source
+ * contains definitively invalid syntax (as opposed to merely incomplete input).
*/
static bool
-pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets) {
-#define LINE_SIZE 4096
- char line[LINE_SIZE];
-
- while (memset(line, '\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
- size_t length = LINE_SIZE;
- while (length > 0 && line[length - 1] == '\n') length--;
-
- if (length == LINE_SIZE) {
- // If we read a line that is the maximum size and it doesn't end
- // with a newline, then we'll just append it to the buffer and
- // continue reading.
- length--;
- pm_buffer_append_string(buffer, line, length);
- continue;
- }
-
- // Append the line to the buffer.
- length--;
- pm_buffer_append_string(buffer, line, length);
-
- // Check if the line matches the __END__ marker. If it does, then stop
- // reading and return false. In most circumstances, this means we should
- // stop reading from the stream so that the DATA constant can pick it
- // up.
- switch (length) {
- case 7:
- if (strncmp(line, "__END__", 7) == 0) return false;
- break;
- case 8:
- if (strncmp(line, "__END__\n", 8) == 0) return false;
- break;
- case 9:
- if (strncmp(line, "__END__\r\n", 9) == 0) return false;
- break;
- }
+pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
+ switch (diag_id) {
+ case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
+ case PM_ERR_BEGIN_UPCASE_BRACE:
+ case PM_ERR_CLASS_VARIABLE_BARE:
+ case PM_ERR_END_UPCASE_BRACE:
+ case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
+ case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
+ case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
+ case PM_ERR_EXPRESSION_NOT_WRITABLE:
+ case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
+ case PM_ERR_FLOAT_PARSE:
+ case PM_ERR_GLOBAL_VARIABLE_BARE:
+ case PM_ERR_HASH_KEY:
+ case PM_ERR_HEREDOC_IDENTIFIER:
+ case PM_ERR_INSTANCE_VARIABLE_BARE:
+ case PM_ERR_INVALID_BLOCK_EXIT:
+ case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
+ case PM_ERR_INVALID_FLOAT_EXPONENT:
+ case PM_ERR_INVALID_NUMBER_BINARY:
+ case PM_ERR_INVALID_NUMBER_DECIMAL:
+ case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
+ case PM_ERR_INVALID_NUMBER_OCTAL:
+ case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
+ case PM_ERR_NO_LOCAL_VARIABLE:
+ case PM_ERR_PARAMETER_ORDER:
+ case PM_ERR_STATEMENT_UNDEF:
+ case PM_ERR_VOID_EXPRESSION:
+ return true;
+ default:
+ return false;
}
-
- return true;
-#undef LINE_SIZE
}
/**
- * Determine if there was an unterminated heredoc at the end of the input, which
- * would mean the stream isn't finished and we should keep reading.
+ * Determine whether the source parsed by the given parser could become valid if
+ * more input were appended. This is used by tools like IRB to decide whether to
+ * prompt for continuation or to display an error.
+ *
+ * The parser starts with continuable=true. This function scans all errors to
+ * detect two categories of non-continuable errors:
+ *
+ * 1. Fatal errors: errors like invalid number literals or bare global variables
+ * that indicate definitively invalid syntax. These are only considered fatal
+ * if they occur before EOF (at EOF they could be from truncated input, e.g.
+ * `"\x` is an incomplete hex escape).
*
- * For the other lex modes we can check if the lex mode has been closed, but for
- * heredocs when we hit EOF we close the lex mode and then go back to parse the
- * rest of the line after the heredoc declaration so that we get more of the
- * syntax tree.
+ * 2. Stray tokens: unexpected_token_ignore and unexpected_token_close_context
+ * errors indicate tokens that don't belong. A stray token is a cascade
+ * effect (and does not prevent continuability) if:
+ *
+ * a. A non-stray, non-fatal error appeared earlier in the error list at a
+ * strictly earlier source position (the stray was caused by a preceding
+ * parse failure, e.g. a truncated heredoc), OR
+ * b. The stray token is at EOF, starts after position 0 (there is valid
+ * code before it), and either is a single byte (likely a truncated
+ * token like `\`) or there are non-stray errors elsewhere.
+ *
+ * Closing delimiters (`)`, `]`, `}`) at EOF are always genuinely stray —
+ * they are complete tokens and cannot become part of a longer valid
+ * construct by appending more input.
+ *
+ * c. The stray token is `=` at the start of a line, which could be the
+ * beginning of `=begin` (an embedded document). The remaining bytes
+ * after `=` may parse as an identifier, so the error is not at EOF,
+ * but the construct is genuinely incomplete.
*/
-static bool
-pm_parse_stream_unterminated_heredoc_p(pm_parser_t *parser) {
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) parser->error_list.head;
+static void
+pm_parse_continuable(pm_parser_t *parser) {
+ // If there are no errors then there is nothing to continue.
+ if (parser->error_list.size == 0) {
+ parser->continuable = false;
+ return;
+ }
- for (; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
- if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
- return true;
+ if (!parser->continuable) return;
+
+ size_t source_length = (size_t) (parser->end - parser->start);
+
+ // First pass: check if there are any non-stray, non-fatal errors.
+ bool has_non_stray_error = false;
+ for (pm_diagnostic_t *error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
+ if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE && error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT && !pm_parse_err_is_fatal(error->diag_id)) {
+ has_non_stray_error = true;
+ break;
}
}
- return false;
-}
+ // Second pass: check each error. We track the minimum source position
+ // among non-stray, non-fatal errors seen so far in list order, which
+ // lets us detect cascade stray tokens.
+ size_t non_stray_min_start = SIZE_MAX;
-/**
- * Parse a stream of Ruby source and return the tree.
- *
- * Prism is designed around having the entire source in memory at once, but you
- * can stream stdin in to Ruby so we need to support a streaming API.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t *
-pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const pm_options_t *options) {
- pm_buffer_init(buffer);
+ for (pm_diagnostic_t *error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
+ size_t error_start = (size_t) error->location.start;
+ size_t error_end = error_start + (size_t) error->location.length;
+ bool at_eof = error_end >= source_length;
- bool eof = pm_parse_stream_read(buffer, stream, stream_fgets);
- pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
- pm_node_t *node = pm_parse(parser);
+ // Fatal errors are non-continuable unless they occur at EOF.
+ if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
+ parser->continuable = false;
+ return;
+ }
- while (!eof && parser->error_list.size > 0 && (parser->lex_modes.index > 0 || pm_parse_stream_unterminated_heredoc_p(parser))) {
- pm_node_destroy(parser, node);
- eof = pm_parse_stream_read(buffer, stream, stream_fgets);
+ // Track non-stray, non-fatal error positions in list order.
+ if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
+ error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
+ if (error_start < non_stray_min_start) non_stray_min_start = error_start;
+ continue;
+ }
- pm_parser_free(parser);
- pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
- node = pm_parse(parser);
+ // This is a stray token. Determine if it is a cascade effect
+ // of a preceding error or genuinely stray.
+
+ // Rule (a): a non-stray error was seen earlier in the list at a
+ // strictly earlier position — this stray is a cascade effect.
+ if (non_stray_min_start < error_start) continue;
+
+ // Rule (b): this stray is at EOF with valid code before it.
+ // Single-byte stray tokens at EOF (like `\` for line continuation)
+ // are likely truncated tokens. Multi-byte stray tokens (like the
+ // keyword `end`) need additional evidence that they are cascade
+ // effects (i.e. non-stray errors exist elsewhere).
+ if (at_eof && error_start > 0) {
+ // Exception: closing delimiters at EOF are genuinely stray.
+ if (error->location.length == 1) {
+ const uint8_t *byte = parser->start + error_start;
+ if (*byte == ')' || *byte == ']' || *byte == '}') {
+ parser->continuable = false;
+ return;
+ }
+
+ // Single-byte non-delimiter stray at EOF: cascade.
+ continue;
+ }
+
+ // Multi-byte stray at EOF: cascade only if there are
+ // non-stray errors (evidence of a preceding parse failure).
+ if (has_non_stray_error) continue;
+ }
+
+ // Rule (c): a stray `=` at the start of a line could be the
+ // beginning of an embedded document (`=begin`). The remaining
+ // bytes after `=` parse as an identifier, so the error is not
+ // at EOF, but the construct is genuinely incomplete.
+ if (error->location.length == 1) {
+ const uint8_t *byte = parser->start + error_start;
+ if (*byte == '=' && (error_start == 0 || *(byte - 1) == '\n')) continue;
+ }
+
+ // This stray token is genuinely non-continuable.
+ parser->continuable = false;
+ return;
}
+}
+/**
+ * Parse the Ruby source associated with the given parser and return the tree.
+ */
+pm_node_t *
+pm_parse(pm_parser_t *parser) {
+ pm_node_t *node = parse_program(parser);
+ pm_parse_continuable(parser);
return node;
}
/**
- * Parse the source and return true if it parses without errors or warnings.
+ * Parse a stream of Ruby source and return the tree.
+ *
+ * Prism is designed around having the entire source in memory at once, but you
+ * can stream stdin in to Ruby so we need to support a streaming API.
*/
-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_node_t *
+pm_parse_stream(pm_parser_t **parser, pm_arena_t *arena, pm_source_t *source, const pm_options_t *options) {
+ bool eof = pm_source_stream_read(source);
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_t *tmp = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
+ pm_node_t *node = pm_parse(tmp);
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
+ while (!eof && tmp->error_list.size > 0) {
+ eof = pm_source_stream_read(source);
- bool result = parser.error_list.size == 0;
- pm_parser_free(&parser);
- pm_options_free(&options);
+ pm_parser_free(tmp);
+ pm_arena_cleanup(arena);
- return result;
+ tmp = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
+ node = pm_parse(tmp);
+ }
+
+ *parser = tmp;
+ return node;
}
#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
// We optionally support serializing to a binary string. For systems that don't
// want or need this functionality, it can be turned off with the
// PRISM_EXCLUDE_SERIALIZATION define.
#ifndef PRISM_EXCLUDE_SERIALIZATION
-static inline void
+static PRISM_INLINE void
pm_serialize_header(pm_buffer_t *buffer) {
pm_buffer_append_string(buffer, "PRISM", 5);
pm_buffer_append_byte(buffer, PRISM_VERSION_MAJOR);
@@ -22953,7 +22865,7 @@ pm_serialize_header(pm_buffer_t *buffer) {
/**
* Serialize the AST represented by the given node to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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);
@@ -22964,13 +22876,14 @@ pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
* Parse and serialize the AST represented by the given source to the given
* buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_init(&arena, &parser, source, size, &options);
pm_node_t *node = pm_parse(&parser);
@@ -22978,216 +22891,53 @@ pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, cons
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);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
/**
* Parse and serialize the AST represented by the source that is read out of the
* given stream into to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const char *data) {
- pm_parser_t parser;
+void
+pm_serialize_parse_stream(pm_buffer_t *buffer, pm_source_t *source, const char *data) {
+ pm_arena_t arena = { 0 };
+ pm_parser_t *parser;
pm_options_t options = { 0 };
pm_options_read(&options, data);
- pm_buffer_t parser_buffer;
- pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, &options);
+ pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
pm_serialize_header(buffer);
- pm_serialize_content(&parser, node, buffer);
+ pm_serialize_content(parser, node, buffer);
pm_buffer_append_byte(buffer, '\0');
- pm_node_destroy(&parser, node);
- pm_buffer_free(&parser_buffer);
- pm_parser_free(&parser);
- pm_options_free(&options);
+ pm_parser_free(parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
/**
* Parse and serialize the comments in the given source to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_init(&arena, &parser, source, size, &options);
- pm_node_t *node = pm_parse(&parser);
+ 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_serialize_comment_list(&parser.comment_list, buffer);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
#endif
-
-/******************************************************************************/
-/* Slice queries for the Ruby API */
-/******************************************************************************/
-
-/** The category of slice returned from pm_slice_type. */
-typedef enum {
- /** Returned when the given encoding name is invalid. */
- PM_SLICE_TYPE_ERROR = -1,
-
- /** Returned when no other types apply to the slice. */
- PM_SLICE_TYPE_NONE,
-
- /** Returned when the slice is a valid local variable name. */
- PM_SLICE_TYPE_LOCAL,
-
- /** Returned when the slice is a valid constant name. */
- PM_SLICE_TYPE_CONSTANT,
-
- /** Returned when the slice is a valid method name. */
- PM_SLICE_TYPE_METHOD_NAME
-} pm_slice_type_t;
-
-/**
- * Check that the slice is a valid local variable name or constant.
- */
-pm_slice_type_t
-pm_slice_type(const uint8_t *source, size_t length, const char *encoding_name) {
- // first, get the right encoding object
- const pm_encoding_t *encoding = pm_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name)));
- if (encoding == NULL) return PM_SLICE_TYPE_ERROR;
-
- // check that there is at least one character
- if (length == 0) return PM_SLICE_TYPE_NONE;
-
- size_t width;
- if ((width = encoding->alpha_char(source, (ptrdiff_t) length)) != 0) {
- // valid because alphabetical
- } else if (*source == '_') {
- // valid because underscore
- width = 1;
- } else if ((*source >= 0x80) && ((width = encoding->char_width(source, (ptrdiff_t) length)) > 0)) {
- // valid because multibyte
- } else {
- // invalid because no match
- return PM_SLICE_TYPE_NONE;
- }
-
- // determine the type of the slice based on the first character
- const uint8_t *end = source + length;
- pm_slice_type_t result = encoding->isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
-
- // next, iterate through all of the bytes of the string to ensure that they
- // are all valid identifier characters
- source += width;
-
- while (source < end) {
- if ((width = encoding->alnum_char(source, end - source)) != 0) {
- // valid because alphanumeric
- source += width;
- } else if (*source == '_') {
- // valid because underscore
- source++;
- } else if ((*source >= 0x80) && ((width = encoding->char_width(source, end - source)) > 0)) {
- // valid because multibyte
- source += width;
- } else {
- // invalid because no match
- break;
- }
- }
-
- // accept a ! or ? at the end of the slice as a method name
- if (*source == '!' || *source == '?' || *source == '=') {
- source++;
- result = PM_SLICE_TYPE_METHOD_NAME;
- }
-
- // valid if we are at the end of the slice
- return source == end ? result : PM_SLICE_TYPE_NONE;
-}
-
-/**
- * Check that the slice is a valid local variable name.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t
-pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) {
- switch (pm_slice_type(source, length, encoding_name)) {
- case PM_SLICE_TYPE_ERROR:
- return PM_STRING_QUERY_ERROR;
- case PM_SLICE_TYPE_NONE:
- case PM_SLICE_TYPE_CONSTANT:
- case PM_SLICE_TYPE_METHOD_NAME:
- return PM_STRING_QUERY_FALSE;
- case PM_SLICE_TYPE_LOCAL:
- return PM_STRING_QUERY_TRUE;
- }
-
- assert(false && "unreachable");
- return PM_STRING_QUERY_FALSE;
-}
-
-/**
- * Check that the slice is a valid constant name.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t
-pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) {
- switch (pm_slice_type(source, length, encoding_name)) {
- case PM_SLICE_TYPE_ERROR:
- return PM_STRING_QUERY_ERROR;
- case PM_SLICE_TYPE_NONE:
- case PM_SLICE_TYPE_LOCAL:
- case PM_SLICE_TYPE_METHOD_NAME:
- return PM_STRING_QUERY_FALSE;
- case PM_SLICE_TYPE_CONSTANT:
- return PM_STRING_QUERY_TRUE;
- }
-
- assert(false && "unreachable");
- return PM_STRING_QUERY_FALSE;
-}
-
-/**
- * Check that the slice is a valid method name.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t
-pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) {
-#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
-#define C1(c) (*source == c)
-#define C2(s) (memcmp(source, s, 2) == 0)
-#define C3(s) (memcmp(source, s, 3) == 0)
-
- switch (pm_slice_type(source, length, encoding_name)) {
- case PM_SLICE_TYPE_ERROR:
- return PM_STRING_QUERY_ERROR;
- case PM_SLICE_TYPE_NONE:
- break;
- case PM_SLICE_TYPE_LOCAL:
- // numbered parameters are not valid method names
- return B((length != 2) || (source[0] != '_') || (source[1] == '0') || !pm_char_is_decimal_digit(source[1]));
- case PM_SLICE_TYPE_CONSTANT:
- // all constants are valid method names
- case PM_SLICE_TYPE_METHOD_NAME:
- // all method names are valid method names
- return PM_STRING_QUERY_TRUE;
- }
-
- switch (length) {
- case 1:
- return B(C1('&') || C1('`') || C1('!') || C1('^') || C1('>') || C1('<') || C1('-') || C1('%') || C1('|') || C1('+') || C1('/') || C1('*') || C1('~'));
- case 2:
- return B(C2("!=") || C2("!~") || C2("[]") || C2("==") || C2("=~") || C2(">=") || C2(">>") || C2("<=") || C2("<<") || C2("**"));
- case 3:
- return B(C3("===") || C3("<=>") || C3("[]="));
- default:
- return PM_STRING_QUERY_FALSE;
- }
-
-#undef B
-#undef C1
-#undef C2
-#undef C3
-}
diff --git a/prism/prism.h b/prism/prism.h
index 317568aa0c..b342bb32c6 100644
--- a/prism/prism.h
+++ b/prism/prism.h
@@ -6,281 +6,25 @@
#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_integer.h"
-#include "prism/util/pm_memchr.h"
-#include "prism/util/pm_strncasecmp.h"
-#include "prism/util/pm_strpbrk.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "prism/arena.h"
#include "prism/ast.h"
+#include "prism/buffer.h"
#include "prism/diagnostic.h"
+#include "prism/json.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/static_literals.h"
+#include "prism/serialize.h"
+#include "prism/source.h"
+#include "prism/stream.h"
+#include "prism/string_query.h"
#include "prism/version.h"
-#include <assert.h>
-#include <errno.h>
-#include <locale.h>
-#include <math.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);
-
-/**
- * This function is used in pm_parse_stream to retrieve a line of input from a
- * stream. It closely mirrors that of fgets so that fgets can be used as the
- * default implementation.
- */
-typedef char * (pm_parse_stream_fgets_t)(char *string, int size, void *stream);
-
-/**
- * Parse a stream of Ruby source and return the tree.
- *
- * @param parser The parser to use.
- * @param buffer The buffer to use.
- * @param stream The stream to parse.
- * @param stream_fgets The function to use to read from the stream.
- * @param options The optional options to use when parsing.
- * @return The AST representing the source.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const pm_options_t *options);
-
-// We optionally support serializing to a binary string. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_SERIALIZATION define.
-#ifndef PRISM_EXCLUDE_SERIALIZATION
-
-/**
- * Parse and serialize the AST represented by the source that is read out of the
- * given stream into to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param stream The stream to parse.
- * @param stream_fgets The function to use to read from the stream.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const char *data);
-
-/**
- * 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);
-
-#endif
-
-/**
- * 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_name(pm_token_type_t token_type);
-
-/**
- * Returns the human name of the given token type.
- *
- * @param token_type The token type to convert to a human name.
- * @return The human name of the given token type.
- */
-const char * pm_token_type_human(pm_token_type_t token_type);
-
-// We optionally support dumping to JSON. For systems that don't want or need
-// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define.
-#ifndef PRISM_EXCLUDE_JSON
-
-/**
- * Dump JSON to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param parser The parser that parsed the node.
- * @param node The node to serialize.
- */
-PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node);
-
-#endif
-
-/**
- * Represents the results of a slice query.
- */
-typedef enum {
- /** Returned if the encoding given to a slice query was invalid. */
- PM_STRING_QUERY_ERROR = -1,
-
- /** Returned if the result of the slice query is false. */
- PM_STRING_QUERY_FALSE,
-
- /** Returned if the result of the slice query is true. */
- PM_STRING_QUERY_TRUE
-} pm_string_query_t;
-
-/**
- * Check that the slice is a valid local variable name.
- *
- * @param source The source to check.
- * @param length The length of the source.
- * @param encoding_name The name of the encoding of the source.
- * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
- * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name);
-
-/**
- * Check that the slice is a valid constant name.
- *
- * @param source The source to check.
- * @param length The length of the source.
- * @param encoding_name The name of the encoding of the source.
- * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
- * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name);
-
-/**
- * Check that the slice is a valid method name.
- *
- * @param source The source to check.
- * @param length The length of the source.
- * @param encoding_name The name of the encoding of the source.
- * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
- * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
- */
-PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name);
-
/**
* @mainpage
*
@@ -289,7 +33,7 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint
* 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),
+ * [TruffleRuby](https://github.com/truffleruby/truffleruby),
* [Sorbet](https://github.com/sorbet/sorbet), and
* [Syntax Tree](https://github.com/ruby-syntax-tree/syntax_tree).
*
@@ -303,32 +47,32 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint
*
* @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:
+ * In order to parse Ruby code, the functions that you are 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
+ * * `pm_arena_new()` - create a new arena to hold all AST-lifetime allocations
+ * * `pm_parser_new()` - allocate and initialize a new parser
+ * * `pm_parse()` - parse and return the root node
+ * * `pm_parser_free()` - free the parser and its internal memory
+ * * `pm_arena_free()` - free all AST-lifetime memory
*
* 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_arena_t *arena = pm_arena_new();
+ * pm_parser_t *parser = pm_parser_new(arena, source, length, NULL);
*
- * pm_node_t *root = pm_parse(&parser);
+ * pm_node_t *root = pm_parse(parser);
* printf("PARSED!\n");
*
- * pm_node_destroy(&parser, root);
- * pm_parser_free(&parser);
+ * pm_parser_free(parser);
+ * pm_arena_free(arena);
* }
* ```
*
- * 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
+ * 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
@@ -336,48 +80,51 @@ PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint
* 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:
+ * parse Ruby code. The functions that you are 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
+ * * `pm_buffer_new()` - create a new buffer
+ * * `pm_buffer_free()` - free the buffer and its internal memory
+ * * `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_buffer_t *buffer = pm_buffer_new();
*
- * pm_serialize_parse(&buffer, source, length, NULL);
+ * pm_serialize_parse(buffer, source, length, NULL);
* printf("SERIALIZED!\n");
*
- * pm_buffer_free(&buffer);
+ * 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:
+ * 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_arena_t *arena = pm_arena_new();
+ * pm_parser_t *parser = pm_parser_new(arena, source, length, NULL);
*
- * pm_node_t *root = pm_parse(&parser);
- * pm_buffer_t buffer = { 0 };
+ * pm_node_t *root = pm_parse(parser);
+ * pm_buffer_t *buffer = pm_buffer_new();
*
- * pm_prettyprint(&buffer, &parser, root);
- * printf("%*.s\n", (int) buffer.length, buffer.value);
+ * pm_prettyprint(buffer, parser, root);
+ * printf("%*.s\n", (int) pm_buffer_length(buffer), pm_buffer_value(buffer));
*
- * pm_buffer_free(&buffer);
- * pm_node_destroy(&parser, root);
- * pm_parser_free(&parser);
+ * pm_buffer_free(buffer);
+ * pm_parser_free(parser);
+ * pm_arena_free(arena);
* }
* ```
*/
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/prism/regexp.c b/prism/regexp.c
index dcc7476244..cc17aa4d09 100644
--- a/prism/regexp.c
+++ b/prism/regexp.c
@@ -1,5 +1,20 @@
-#include "prism/regexp.h"
-
+#include "prism/internal/regexp.h"
+
+#include "prism/compiler/inline.h"
+#include "prism/compiler/fallthrough.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/char.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/memchr.h"
+#include "prism/internal/parser.h"
+#include "prism/internal/stringy.h"
+#include "prism/internal/strncasecmp.h"
+
+#include <assert.h>
+#include <string.h>
+
+/** The maximum depth of nested groups allowed in a regular expression. */
#define PM_REGEXP_PARSE_DEPTH_MAX 4096
/**
@@ -18,6 +33,54 @@ typedef struct {
/** A pointer to the end of the source that we are parsing. */
const uint8_t *end;
+ /** The encoding of the source. */
+ const pm_encoding_t *encoding;
+
+ /** The callback to call when a named capture group is found. */
+ pm_regexp_name_callback_t name_callback;
+
+ /** The data to pass to the name callback. */
+ pm_regexp_name_data_t *name_data;
+
+ /** The start of the regexp node (for error locations). */
+ const uint8_t *node_start;
+
+ /** The end of the regexp node (for error locations). */
+ const uint8_t *node_end;
+
+ /**
+ * The explicit encoding determined by escape sequences. NULL if no
+ * encoding-setting escape has been seen, UTF-8 for `\u` escapes, or the
+ * source encoding for `\x` escapes.
+ */
+ const pm_encoding_t *explicit_encoding;
+
+ /**
+ * Pointer to the first non-POSIX property name (for /n error messages).
+ * POSIX properties (Alnum, Alpha, etc.) work in all encodings.
+ * Script properties (Hiragana, Katakana, etc.) work in /e, /s, /u.
+ * Unicode-only properties (L, Ll, etc.) work only in /u.
+ */
+ const uint8_t *property_name;
+
+ /** Length of the first non-POSIX property name found. */
+ size_t property_name_length;
+
+ /**
+ * Pointer to the first Unicode-only property name (for /e, /s error
+ * messages). NULL if only POSIX or script properties have been seen.
+ */
+ const uint8_t *unicode_property_name;
+
+ /** Length of the first Unicode-only property name found. */
+ size_t unicode_property_name_length;
+
+ /** Buffer of hex escape byte values >= 0x80, separated by 0x00 sentinels. */
+ pm_buffer_t hex_escape_buffer;
+
+ /** Count of non-ASCII literal bytes (not from escapes). */
+ uint32_t non_ascii_literal_count;
+
/**
* Whether or not the regular expression currently being parsed is in
* extended mode, wherein whitespace is ignored and comments are allowed.
@@ -27,31 +90,77 @@ typedef struct {
/** Whether the encoding has changed from the default. */
bool encoding_changed;
- /** The encoding of the source. */
- const pm_encoding_t *encoding;
+ /** Whether the source content is shared (for named capture callback). */
+ bool shared;
- /** The callback to call when a named capture group is found. */
- pm_regexp_name_callback_t name_callback;
+ /** Whether a `\u{...}` escape with value >= 0x80 was seen. */
+ bool has_unicode_escape;
- /** The data to pass to the name callback. */
- void *name_data;
+ /** Whether a `\xNN` escape (or `\M-x`, etc.) with value >= 0x80 was seen. */
+ bool has_hex_escape;
+
+ /**
+ * Tracks whether the last encoding-setting escape was `\u` (true) or `\x`
+ * (false). This matters for error messages when both types are mixed.
+ */
+ bool last_escape_was_unicode;
+
+ /** Whether any `\p{...}` or `\P{...}` property escape was found. */
+ bool has_property_escape;
+
+ /** Whether a Unicode-only property escape was found (not POSIX or script). */
+ bool has_unicode_property_escape;
- /** The callback to call when a parse error is found. */
- pm_regexp_error_callback_t error_callback;
+ /** Whether a `\u` escape with invalid range (surrogate or > 0x10FFFF) was seen. */
+ bool invalid_unicode_range;
- /** The data to pass to the error callback. */
- void *error_data;
+ /** Whether we are accumulating consecutive hex escape bytes. */
+ bool hex_group_active;
+
+ /** Whether an invalid multibyte character was found during parsing. */
+ bool has_invalid_multibyte;
} pm_regexp_parser_t;
/**
- * Append an error to the parser.
+ * Append a syntax error to the parser's error list. If the source is shared
+ * (points into the original source), we can point to the exact error location.
+ * Otherwise, we point to the whole regexp node.
*/
-static inline void
+static PRISM_INLINE void
pm_regexp_parse_error(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end, const char *message) {
- parser->error_callback(start, end, message, parser->error_data);
+ pm_parser_t *pm = parser->parser;
+ uint32_t loc_start, loc_length;
+
+ if (parser->shared) {
+ loc_start = (uint32_t) (start - pm->start);
+ loc_length = (uint32_t) (end - start);
+ } else {
+ loc_start = (uint32_t) (parser->node_start - pm->start);
+ loc_length = (uint32_t) (parser->node_end - parser->node_start);
+ }
+
+ pm_diagnostic_list_append_format(&pm->metadata_arena, &pm->error_list, loc_start, loc_length, PM_ERR_REGEXP_PARSE_ERROR, message);
}
/**
+ * Append a formatted diagnostic error with proper shared/non-shared location
+ * handling. This is a macro because we need variadic args for the format string.
+ */
+#define pm_regexp_parse_error_format(parser_, err_start_, err_end_, diag_id, ...) \
+ do { \
+ pm_parser_t *pm__ = (parser_)->parser; \
+ uint32_t loc_start__, loc_length__; \
+ if ((parser_)->shared) { \
+ loc_start__ = (uint32_t) ((err_start_) - pm__->start); \
+ loc_length__ = (uint32_t) ((err_end_) - (err_start_)); \
+ } else { \
+ loc_start__ = (uint32_t) ((parser_)->node_start - pm__->start); \
+ loc_length__ = (uint32_t) ((parser_)->node_end - (parser_)->node_start); \
+ } \
+ pm_diagnostic_list_append_format(&pm__->metadata_arena, &pm__->error_list, loc_start__, loc_length__, diag_id, __VA_ARGS__); \
+ } while (0)
+
+/**
* This appends a new string to the list of named captures. This function
* assumes the caller has already checked the validity of the name callback.
*/
@@ -59,14 +168,14 @@ 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);
- parser->name_callback(&string, parser->name_data);
- pm_string_free(&string);
+ parser->name_callback(parser->parser, &string, parser->shared, parser->name_data);
+ pm_string_cleanup(&string);
}
/**
* Returns true if the next character is the end of the source.
*/
-static inline bool
+static PRISM_INLINE bool
pm_regexp_char_is_eof(pm_regexp_parser_t *parser) {
return parser->cursor >= parser->end;
}
@@ -74,7 +183,7 @@ pm_regexp_char_is_eof(pm_regexp_parser_t *parser) {
/**
* Optionally accept a char and consume it if it exists.
*/
-static inline bool
+static PRISM_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++;
@@ -86,7 +195,7 @@ pm_regexp_char_accept(pm_regexp_parser_t *parser, uint8_t value) {
/**
* Expect a character to be present and consume it.
*/
-static inline bool
+static PRISM_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++;
@@ -114,6 +223,47 @@ pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) {
}
/**
+ * Mark a group boundary in the hex escape byte buffer. When consecutive hex
+ * escape bytes >= 0x80 are followed by a non-hex-escape, this appends a 0x00
+ * sentinel to separate the groups for later multibyte validation.
+ */
+static PRISM_INLINE void
+pm_regexp_hex_group_boundary(pm_regexp_parser_t *parser) {
+ if (parser->hex_group_active) {
+ pm_buffer_append_byte(&parser->hex_escape_buffer, 0x00);
+ parser->hex_group_active = false;
+ }
+}
+
+/**
+ * Track a hex escape byte value >= 0x80 for multibyte validation.
+ */
+static PRISM_INLINE void
+pm_regexp_track_hex_escape(pm_regexp_parser_t *parser, uint8_t byte) {
+ if (byte >= 0x80) {
+ pm_buffer_append_byte(&parser->hex_escape_buffer, byte);
+ parser->hex_group_active = true;
+ parser->has_hex_escape = true;
+
+ parser->explicit_encoding = parser->encoding;
+ parser->last_escape_was_unicode = false;
+ } else {
+ pm_regexp_hex_group_boundary(parser);
+ }
+}
+
+/**
+ * Parse a hex digit character and return its value, or -1 if not a hex digit.
+ */
+static PRISM_INLINE int
+pm_regexp_hex_digit_value(uint8_t byte) {
+ if (byte >= '0' && byte <= '9') return byte - '0';
+ if (byte >= 'a' && byte <= 'f') return byte - 'a' + 10;
+ if (byte >= 'A' && byte <= 'F') return byte - 'A' + 10;
+ return -1;
+}
+
+/**
* Range quantifiers are a special class of quantifiers that look like
*
* * {digit}
@@ -121,13 +271,12 @@ pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) {
* * {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.
+ * 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.
+ * To properly track everything, we're going to build a little state machine.
* It looks something like the following:
*
* +-------+ +---------+ ------------+
@@ -275,11 +424,393 @@ pm_regexp_parse_posix_class(pm_regexp_parser_t *parser) {
);
}
+/**
+ * Property escape classification. Onigmo supports three tiers of property
+ * names depending on the encoding:
+ *
+ * - POSIX properties (Alnum, Alpha, ASCII, Blank, Cntrl, Digit, Graph, Lower,
+ * Print, Punct, Space, Upper, XDigit, Word): valid in all encodings.
+ * - Script properties (Hiragana, Katakana, Han, Latin, Greek, Cyrillic): valid
+ * in EUC-JP (/e), Windows-31J (/s), and UTF-8 (/u), but not ASCII-8BIT (/n).
+ * - Unicode-only properties (general categories like L, Ll, Lu, etc., plus
+ * Any, Assigned): valid only in UTF-8 (/u).
+ */
+typedef enum {
+ PM_REGEXP_PROPERTY_POSIX,
+ PM_REGEXP_PROPERTY_SCRIPT,
+ PM_REGEXP_PROPERTY_UNICODE
+} pm_regexp_property_type_t;
+
+/**
+ * Classify a property name. The name may start with '^' for negation, which
+ * is skipped before matching.
+ */
+static pm_regexp_property_type_t
+pm_regexp_classify_property(const uint8_t *name, size_t length) {
+ // Skip leading '^' for negated properties like \p{^Hiragana}.
+ if (length > 0 && name[0] == '^') {
+ name++;
+ length--;
+ }
+
+#define PM_REGEXP_CASECMP(str_) (pm_strncasecmp(name, (const uint8_t *) (str_), length) == 0)
+
+ switch (length) {
+ case 3:
+ if (PM_REGEXP_CASECMP("Han")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ case 4:
+ if (PM_REGEXP_CASECMP("Word")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 5:
+ /* Most properties are length 5, so dispatch on first character. */
+ switch (name[0] | 0x20) {
+ case 'a':
+ if (PM_REGEXP_CASECMP("Alnum")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Alpha")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("ASCII")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'b':
+ if (PM_REGEXP_CASECMP("Blank")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'c':
+ if (PM_REGEXP_CASECMP("Cntrl")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'd':
+ if (PM_REGEXP_CASECMP("Digit")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'g':
+ if (PM_REGEXP_CASECMP("Graph")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Greek")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ case 'l':
+ if (PM_REGEXP_CASECMP("Lower")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Latin")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ case 'p':
+ if (PM_REGEXP_CASECMP("Print")) return PM_REGEXP_PROPERTY_POSIX;
+ if (PM_REGEXP_CASECMP("Punct")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 's':
+ if (PM_REGEXP_CASECMP("Space")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 'u':
+ if (PM_REGEXP_CASECMP("Upper")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ }
+ break;
+ case 6:
+ if (PM_REGEXP_CASECMP("XDigit")) return PM_REGEXP_PROPERTY_POSIX;
+ break;
+ case 8:
+ if (PM_REGEXP_CASECMP("Hiragana")) return PM_REGEXP_PROPERTY_SCRIPT;
+ if (PM_REGEXP_CASECMP("Katakana")) return PM_REGEXP_PROPERTY_SCRIPT;
+ if (PM_REGEXP_CASECMP("Cyrillic")) return PM_REGEXP_PROPERTY_SCRIPT;
+ break;
+ }
+
+#undef PM_REGEXP_CASECMP
+
+ // Everything else is Unicode-only (general categories, other scripts, etc.).
+ return PM_REGEXP_PROPERTY_UNICODE;
+}
+
+/**
+ * Check for and skip a `\p{...}` or `\P{...}` Unicode property escape. The
+ * cursor should be pointing at 'p' or 'P' when this is called. If a property
+ * escape is found, record it on the regexp parser and advance past the closing
+ * '}'.
+ *
+ * Properties are classified into three tiers (POSIX, script, Unicode-only) to
+ * determine which encoding modifiers they are valid with.
+ */
+static bool
+pm_regexp_parse_property_escape(pm_regexp_parser_t *parser) {
+ assert(*parser->cursor == 'p' || *parser->cursor == 'P');
+
+ if (parser->cursor + 1 < parser->end && parser->cursor[1] == '{') {
+ const uint8_t *name_start = parser->cursor + 2;
+ const uint8_t *search = name_start;
+
+ while (search < parser->end && *search != '}') search++;
+
+ if (search < parser->end) {
+ size_t name_length = (size_t) (search - name_start);
+ parser->has_property_escape = true;
+
+ pm_regexp_property_type_t type = pm_regexp_classify_property(name_start, name_length);
+
+ // Track the first non-POSIX property name (for /n error messages).
+ if (type >= PM_REGEXP_PROPERTY_SCRIPT && parser->property_name == NULL) {
+ parser->property_name = name_start;
+ parser->property_name_length = name_length;
+ }
+
+ // Track the first Unicode-only property name (for /e, /s error messages).
+ if (type == PM_REGEXP_PROPERTY_UNICODE) {
+ parser->has_unicode_property_escape = true;
+ if (parser->unicode_property_name == NULL) {
+ parser->unicode_property_name = name_start;
+ parser->unicode_property_name_length = name_length;
+ }
+ }
+
+ parser->cursor = search + 1; // skip past '}'
+ return true;
+ }
+ }
+
+ // Not a property escape, just skip the single character after '\'.
+ parser->cursor++;
+ return false;
+}
+
+/**
+ * Validate and skip a \u escape sequence in a regular expression. The cursor
+ * should be pointing at the character after 'u' when this is called. This
+ * handles both the \u{NNNN MMMM} and \uNNNN forms. Also tracks encoding
+ * state for validation.
+ */
+static void
+pm_regexp_parse_unicode_escape(pm_regexp_parser_t *parser) {
+ const uint8_t *escape_start = parser->cursor - 2; // points to '\'
+
+ if (pm_regexp_char_is_eof(parser)) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "invalid Unicode escape");
+ return;
+ }
+
+ if (*parser->cursor == '{') {
+ parser->cursor++; // skip '{'
+
+ // Skip leading whitespace.
+ while (!pm_regexp_char_is_eof(parser) && pm_char_is_whitespace(*parser->cursor)) {
+ parser->cursor++;
+ }
+
+ bool has_codepoint = false;
+
+ while (!pm_regexp_char_is_eof(parser) && *parser->cursor != '}') {
+ // Parse the hex digits to compute the codepoint value.
+ uint32_t value = 0;
+ size_t hex_count = 0;
+
+ int digit;
+ while (!pm_regexp_char_is_eof(parser) && (digit = pm_regexp_hex_digit_value(*parser->cursor)) >= 0) {
+ value = (value << 4) | (uint32_t) digit;
+ hex_count++;
+ parser->cursor++;
+ }
+
+ if (hex_count == 0) {
+ // Skip to '}' or end of regexp to find the full extent.
+ while (!pm_regexp_char_is_eof(parser) && *parser->cursor != '}') {
+ parser->cursor++;
+ }
+
+ const uint8_t *escape_end = parser->cursor;
+ if (!pm_regexp_char_is_eof(parser)) {
+ escape_end++;
+ parser->cursor++; // skip '}'
+ }
+
+ pm_regexp_parse_error_format(parser, escape_start, escape_end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (escape_end - escape_start), (const char *) escape_start);
+ return;
+ }
+
+ if (hex_count > 6) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "invalid Unicode range");
+ }
+
+ // Track encoding state for this codepoint.
+ if (value >= 0x80) {
+ parser->has_unicode_escape = true;
+ parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
+ parser->last_escape_was_unicode = true;
+ pm_regexp_hex_group_boundary(parser);
+ }
+
+ // Check for invalid Unicode range (surrogates or > 0x10FFFF).
+ if (value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF)) {
+ parser->invalid_unicode_range = true;
+ }
+
+ has_codepoint = true;
+
+ // Skip whitespace between codepoints.
+ while (!pm_regexp_char_is_eof(parser) && pm_char_is_whitespace(*parser->cursor)) {
+ parser->cursor++;
+ }
+ }
+
+ if (pm_regexp_char_is_eof(parser)) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "unterminated Unicode escape");
+ } else {
+ if (!has_codepoint) {
+ pm_regexp_parse_error_format(parser, escape_start, parser->cursor + 1, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (parser->cursor + 1 - escape_start), (const char *) escape_start);
+ }
+ parser->cursor++; // skip '}'
+ }
+ } else {
+ // \uNNNN form — need exactly 4 hex digits.
+ uint32_t value = 0;
+ size_t hex_count = 0;
+
+ int digit;
+ while (hex_count < 4 && !pm_regexp_char_is_eof(parser) && (digit = pm_regexp_hex_digit_value(*parser->cursor)) >= 0) {
+ value = (value << 4) | (uint32_t) digit;
+ hex_count++;
+ parser->cursor++;
+ }
+
+ if (hex_count < 4) {
+ pm_regexp_parse_error(parser, escape_start, parser->cursor, "invalid Unicode escape");
+ } else if (value >= 0x80) {
+ parser->has_unicode_escape = true;
+ parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
+ parser->last_escape_was_unicode = true;
+ pm_regexp_hex_group_boundary(parser);
+ }
+
+ // Check for invalid Unicode range.
+ if (hex_count == 4 && (value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF))) {
+ parser->invalid_unicode_range = true;
+ }
+ }
+}
+
// Forward declaration because character sets can be nested.
static bool
pm_regexp_parse_lbracket(pm_regexp_parser_t *parser, uint16_t depth);
/**
+ * Parse a \x escape and return the byte value. The cursor should be pointing
+ * at the character after 'x'. Returns -1 if no hex digits follow.
+ */
+static int
+pm_regexp_parse_hex_escape(pm_regexp_parser_t *parser) {
+ int value = -1;
+
+ if (!pm_regexp_char_is_eof(parser)) {
+ int digit = pm_regexp_hex_digit_value(*parser->cursor);
+ if (digit >= 0) {
+ value = digit;
+ parser->cursor++;
+
+ if (!pm_regexp_char_is_eof(parser)) {
+ digit = pm_regexp_hex_digit_value(*parser->cursor);
+ if (digit >= 0) {
+ value = (value << 4) | digit;
+ parser->cursor++;
+ }
+ }
+ }
+ }
+
+ if (value >= 0) {
+ pm_regexp_track_hex_escape(parser, (uint8_t) value);
+ }
+
+ return value;
+}
+
+/**
+ * Parse a backslash escape sequence in a regexp, handling \u (unicode),
+ * \p/\P (property), \x (hex), and other single-character escapes. Also
+ * tracks encoding state for \M-x and \C-\M-x escapes.
+ */
+static void
+pm_regexp_parse_backslash_escape(pm_regexp_parser_t *parser) {
+ if (pm_regexp_char_is_eof(parser)) return;
+
+ switch (*parser->cursor) {
+ case 'u':
+ parser->cursor++; // skip 'u'
+ pm_regexp_parse_unicode_escape(parser);
+ break;
+ case 'p':
+ case 'P':
+ pm_regexp_parse_property_escape(parser);
+ break;
+ case 'x':
+ parser->cursor++; // skip 'x'
+ pm_regexp_parse_hex_escape(parser);
+ break;
+ case 'M':
+ // \M-x produces (x | 0x80), always >= 0x80
+ if (parser->cursor + 2 < parser->end && parser->cursor[1] == '-') {
+ parser->cursor += 2; // skip 'M-'
+ if (!pm_regexp_char_is_eof(parser)) {
+ if (*parser->cursor == '\\') {
+ parser->cursor++;
+ // \M-\C-x or \M-\cx — the resulting byte is always >= 0x80
+ // We just need to track it as a hex escape >= 0x80.
+ pm_regexp_parse_backslash_escape(parser);
+ } else {
+ parser->cursor++;
+ }
+ // \M-x always produces a byte >= 0x80
+ pm_regexp_track_hex_escape(parser, 0x80);
+ }
+ } else {
+ parser->cursor++;
+ }
+ break;
+ case 'C':
+ // \C-x produces (x & 0x1F)
+ if (parser->cursor + 2 < parser->end && parser->cursor[1] == '-') {
+ parser->cursor += 2; // skip 'C-'
+ if (!pm_regexp_char_is_eof(parser)) {
+ if (*parser->cursor == '\\') {
+ parser->cursor++;
+ pm_regexp_parse_backslash_escape(parser);
+ } else {
+ parser->cursor++;
+ }
+ }
+ } else {
+ parser->cursor++;
+ }
+ break;
+ case 'c':
+ // \cx produces (x & 0x1F)
+ parser->cursor++; // skip 'c'
+ if (!pm_regexp_char_is_eof(parser)) {
+ if (*parser->cursor == '\\') {
+ parser->cursor++;
+ pm_regexp_parse_backslash_escape(parser);
+ } else {
+ parser->cursor++;
+ }
+ }
+ break;
+ default:
+ pm_regexp_hex_group_boundary(parser);
+ parser->cursor++;
+ break;
+ }
+}
+
+/**
+ * Check if a byte at the current position is a non-ASCII byte in a multibyte
+ * encoding that produces an invalid character. If so, emit an error at the
+ * byte location immediately.
+ */
+static void
+pm_regexp_parse_invalid_multibyte(pm_regexp_parser_t *parser, const uint8_t *cursor) {
+ uint8_t byte = *cursor;
+ if (byte >= 0x80 && parser->encoding_changed && parser->encoding->multibyte) {
+ size_t width = parser->encoding->char_width(cursor, (ptrdiff_t) (parser->end - cursor));
+ if (width > 1) {
+ parser->cursor += width - 1;
+ } else if (width == 0) {
+ parser->has_invalid_multibyte = true;
+ pm_regexp_parse_error_format(parser, cursor, cursor + 1, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ }
+ }
+}
+
+/**
* match-char-set : '[' '^'? (match-range | match-char)* ']'
* ;
*/
@@ -293,12 +824,16 @@ pm_regexp_parse_character_set(pm_regexp_parser_t *parser, uint16_t depth) {
pm_regexp_parse_lbracket(parser, (uint16_t) (depth + 1));
break;
case '\\':
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
+ pm_regexp_parse_backslash_escape(parser);
break;
default:
- // do nothing, we've already advanced the cursor
+ // We've already advanced the cursor by one byte. If the byte
+ // was >= 0x80 in a multibyte encoding, we may need to consume
+ // additional continuation bytes and validate the character.
+ if (*(parser->cursor - 1) >= 0x80) {
+ parser->non_ascii_literal_count++;
+ }
+ pm_regexp_parse_invalid_multibyte(parser, parser->cursor - 1);
break;
}
}
@@ -354,8 +889,13 @@ typedef enum {
// These are the options that are configurable on the regular expression (or
// from within a group).
+/** The minimum character value for a regexp option slot. */
#define PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM 'a'
+
+/** The maximum character value for a regexp option slot. */
#define PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM 'x'
+
+/** The number of regexp option slots. */
#define PRISM_REGEXP_OPTION_STATE_SLOTS (PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM + 1)
/**
@@ -498,7 +1038,15 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) {
}
size_t width = parser->encoding->char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
- if (width == 0) return false;
+ if (width == 0) {
+ if (*parser->cursor >= 0x80) {
+ parser->has_invalid_multibyte = true;
+ pm_regexp_parse_error_format(parser, parser->cursor, parser->cursor + 1, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ parser->cursor++;
+ continue;
+ }
+ return false;
+ }
escaped = (width == 1) && (*parser->cursor == '\\');
parser->cursor += width;
@@ -686,9 +1234,7 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
return pm_regexp_parse_quantifier(parser);
case '\\':
parser->cursor++;
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
+ pm_regexp_parse_backslash_escape(parser);
return pm_regexp_parse_quantifier(parser);
case '(':
parser->cursor++;
@@ -720,9 +1266,30 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
width = parser->encoding->char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
}
- if (width == 0) return false; // TODO: add appropriate error
- parser->cursor += width;
+ if (width == 0) {
+ if (*parser->cursor >= 0x80 && parser->encoding_changed) {
+ if (parser->encoding->multibyte) {
+ // Invalid multibyte character in a multibyte encoding.
+ // Emit the error at the byte location immediately.
+ parser->has_invalid_multibyte = true;
+ pm_regexp_parse_error_format(parser, parser->cursor, parser->cursor + 1, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ } else {
+ // Non-ASCII byte in a single-byte encoding (e.g.,
+ // US-ASCII). Count it for later error reporting.
+ parser->non_ascii_literal_count++;
+ }
+ parser->cursor++;
+ return pm_regexp_parse_quantifier(parser);
+ }
+ return false;
+ }
+
+ // Count non-ASCII literal bytes.
+ for (size_t i = 0; i < width; i++) {
+ if (parser->cursor[i] >= 0x80) parser->non_ascii_literal_count++;
+ }
+ parser->cursor += width;
return pm_regexp_parse_quantifier(parser);
}
}
@@ -768,13 +1335,354 @@ pm_regexp_parse_pattern(pm_regexp_parser_t *parser) {
return pm_regexp_char_is_eof(parser);
}
+// ---------------------------------------------------------------------------
+// Encoding validation
+// ---------------------------------------------------------------------------
+
/**
- * Parse a regular expression and extract the names of all of the named capture
- * groups.
+ * Validate that groups of hex escape bytes in the buffer form valid multibyte
+ * characters in the given encoding. Groups are separated by 0x00 sentinels.
+ */
+static bool
+pm_regexp_validate_hex_escapes(const pm_encoding_t *encoding, const pm_buffer_t *buffer) {
+ const uint8_t *data = (const uint8_t *) pm_buffer_value(buffer);
+ size_t len = pm_buffer_length(buffer);
+ size_t i = 0;
+
+ while (i < len) {
+ size_t group_start = i;
+ while (i < len && data[i] != 0x00) i++;
+
+ for (size_t j = group_start; j < i; ) {
+ size_t width = encoding->char_width(data + j, (ptrdiff_t) (i - j));
+ if (width == 0) return false;
+ j += width;
+ }
+
+ if (i < len) i++; // skip sentinel
+ }
+
+ return true;
+}
+
+/**
+ * Format regexp source content for use in error messages, hex-escaping
+ * non-ASCII bytes.
+ */
+static void
+pm_regexp_format_for_error(pm_buffer_t *buffer, const pm_encoding_t *encoding, const uint8_t *source, size_t length) {
+ size_t index = 0;
+
+ if (encoding == PM_ENCODING_UTF_8_ENTRY) {
+ pm_buffer_append_string(buffer, (const char *) source, length);
+ return;
+ }
+
+ while (index < length) {
+ if (source[index] < 0x80) {
+ pm_buffer_append_byte(buffer, source[index]);
+ index++;
+ } else if (encoding->multibyte) {
+ size_t width = encoding->char_width(source + index, (ptrdiff_t) (length - index));
+
+ if (width > 1) {
+ pm_buffer_append_string(buffer, "\\x{", 3);
+ for (size_t i = 0; i < width; i++) {
+ pm_buffer_append_format(buffer, "%02X", source[index + i]);
+ }
+ pm_buffer_append_byte(buffer, '}');
+ index += width;
+ } else {
+ pm_buffer_append_format(buffer, "\\x%02X", source[index]);
+ index++;
+ }
+ } else {
+ pm_buffer_append_format(buffer, "\\x%02X", source[index]);
+ index++;
+ }
+ }
+}
+
+/**
+ * Emit an encoding validation error on the regexp node.
+ */
+#define PM_REGEXP_ENCODING_ERROR(parser, diag_id, ...) \
+ pm_diagnostic_list_append_format( \
+ &(parser)->parser->metadata_arena, \
+ &(parser)->parser->error_list, \
+ (uint32_t) ((parser)->node_start - (parser)->parser->start), \
+ (uint32_t) ((parser)->node_end - (parser)->node_start), \
+ diag_id, __VA_ARGS__)
+
+/**
+ * Validate encoding for a regexp with an encoding modifier (/e, /s, /u, /n).
+ *
+ * The decision tree is:
+ *
+ * 1. No escape-set encoding (explicit_encoding == NULL):
+ * a. ASCII-only content: validate property escapes, return forced US-ASCII
+ * for /n or the modifier flags for others.
+ * b. US-ASCII source with non-ASCII literals: emit per-byte errors.
+ * c. Source encoding differs from modifier encoding: emit mismatch error.
+ *
+ * 2. Mixed \u and \x escapes: emit the appropriate conflict error depending
+ * on the modifier and which escape type was last.
+ *
+ * 3. \u escape with non-/u modifier: incompatible encoding error.
+ *
+ * 4. Validate that hex escape byte sequences form valid multibyte characters
+ * in the modifier's encoding.
+ */
+static pm_node_flags_t
+pm_regexp_validate_encoding_modifier(pm_regexp_parser_t *parser, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding, const char *source_start, int source_length) {
+
+ if (parser->explicit_encoding == NULL) {
+ if (ascii_only) {
+ // Check property escapes against the modifier's encoding tier.
+ // /n (ASCII-8BIT): only POSIX properties are valid.
+ // /e, /s: POSIX and script properties are valid.
+ // /u: all properties are valid.
+ if (modifier == 'n' && parser->property_name != NULL) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INVALID_CHAR_PROPERTY,
+ (int) parser->property_name_length, (const char *) parser->property_name,
+ source_length, source_start);
+ } else if (modifier != 'u' && parser->has_unicode_property_escape) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INVALID_CHAR_PROPERTY,
+ (int) parser->unicode_property_name_length, (const char *) parser->unicode_property_name,
+ source_length, source_start);
+ }
+ return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
+ }
+
+ if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
+ for (uint32_t i = 0; i < parser->non_ascii_literal_count; i++) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ }
+ } else if (parser->encoding != modifier_encoding) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
+
+ if (modifier == 'n' && !ascii_only) {
+ pm_buffer_t formatted = { 0 };
+ pm_regexp_format_for_error(&formatted, parser->encoding, (const uint8_t *) source_start, (size_t) source_length);
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) formatted.length, (const char *) formatted.value);
+ pm_buffer_cleanup(&formatted);
+ }
+ }
+
+ return flags;
+ }
+
+ // Mixed unicode + hex escapes.
+ if (parser->has_unicode_escape && parser->has_hex_escape) {
+ if (modifier == 'n') {
+ if (parser->last_escape_was_unicode) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP, source_length, source_start);
+ } else {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_ESCAPED_NON_ASCII_IN_UTF8, source_length, source_start);
+ }
+ } else {
+ if (!pm_regexp_validate_hex_escapes(modifier_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+ }
+
+ return flags;
+ }
+
+ if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
+ if (parser->last_escape_was_unicode) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, source_length, source_start);
+ } else if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, source_length, source_start);
+ }
+ }
+
+ if (modifier != 'n' && !pm_regexp_validate_hex_escapes(modifier_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+
+ return flags;
+}
+
+/**
+ * Validate encoding for a regexp without a modifier and compute the encoding
+ * flags to set on the node.
+ *
+ * The decision tree is:
+ *
+ * 1. If a modifier (/n, /u, /e, /s) is present, delegate to
+ * pm_regexp_validate_encoding_modifier.
+ * 2. Invalid multibyte chars or unicode ranges: suppress further checks (errors
+ * were already emitted during parsing).
+ * 3. US-ASCII source with non-ASCII literals: emit per-byte errors.
+ * 4. ASCII-only content: return forced US-ASCII (or forced UTF-8 if \p{...}).
+ * 5. Escape-set encoding present: validate hex escapes against the target
+ * encoding, handle mixed \u + \x conflicts, and return the appropriate
+ * forced encoding flag.
+ */
+static pm_node_flags_t
+pm_regexp_validate_encoding(pm_regexp_parser_t *parser, bool ascii_only, pm_node_flags_t flags, const char *source_start, int source_length) {
+
+ // Invalid multibyte characters suppress further validation.
+ // Errors were already emitted at the byte locations during parsing.
+ if (parser->has_invalid_multibyte) {
+ return flags;
+ }
+
+ if (parser->invalid_unicode_range) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, source_length, source_start);
+ return flags;
+ }
+
+ // Check modifier flags first.
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY, source_start, source_length);
+ }
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY, source_start, source_length);
+ }
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY, source_start, source_length);
+ }
+ if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
+ return pm_regexp_validate_encoding_modifier(parser, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY, source_start, source_length);
+ }
+
+ // No modifier — check for non-ASCII literals in US-ASCII encoding.
+ if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
+ for (uint32_t i = 0; i < parser->non_ascii_literal_count; i++) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
+ }
+ }
+
+ // ASCII-only regexps get downgraded to US-ASCII, unless property escapes
+ // force UTF-8.
+ if (ascii_only) {
+ if (parser->has_property_escape) {
+ return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
+ }
+ return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
+ }
+
+ // Check explicit encoding from escape sequences.
+ if (parser->explicit_encoding != NULL) {
+ // Mixed unicode + hex escapes without modifier.
+ if (parser->has_unicode_escape && parser->has_hex_escape && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
+ if (parser->encoding != PM_ENCODING_US_ASCII_ENTRY &&
+ parser->encoding != PM_ENCODING_ASCII_8BIT_ENTRY &&
+ !pm_regexp_validate_hex_escapes(parser->encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ } else if (parser->last_escape_was_unicode) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP, source_length, source_start);
+ } else {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_REGEXP_ESCAPED_NON_ASCII_IN_UTF8, source_length, source_start);
+ }
+
+ return 0;
+ }
+
+ if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
+ if (!pm_regexp_validate_hex_escapes(parser->explicit_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+
+ return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
+ } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
+ return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
+ } else {
+ if (!pm_regexp_validate_hex_escapes(parser->explicit_encoding, &parser->hex_escape_buffer)) {
+ PM_REGEXP_ENCODING_ERROR(parser, PM_ERR_INVALID_MULTIBYTE_ESCAPE, source_length, source_start);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Parse a regular expression, validate its encoding, and optionally extract
+ * named capture groups. Encoding validation walks the raw source (content_loc)
+ * to distinguish escape-produced bytes from literal bytes. Named capture
+ * extraction walks the unescaped content since escape sequences in group names
+ * (e.g., line continuations) have already been processed by the lexer.
+ */
+pm_node_flags_t
+pm_regexp_parse(pm_parser_t *parser, pm_regular_expression_node_t *node, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data) {
+ const uint8_t *source = parser->start + node->content_loc.start;
+ size_t size = node->content_loc.length;
+ bool extended_mode = PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED);
+ pm_node_flags_t flags = PM_NODE_FLAGS(node);
+
+ const uint8_t *node_start = parser->start + node->base.location.start;
+ const uint8_t *node_end = parser->start + node->base.location.start + node->base.location.length;
+
+ // First pass: walk raw source for encoding validation (no name extraction).
+ pm_regexp_parser_t regexp_parser = {
+ .parser = parser,
+ .start = source,
+ .cursor = source,
+ .end = source + size,
+ .extended_mode = extended_mode,
+ .encoding_changed = parser->encoding_changed,
+ .encoding = parser->encoding,
+ .name_callback = NULL,
+ .name_data = NULL,
+ .shared = true,
+ .node_start = node_start,
+ .node_end = node_end,
+ .has_unicode_escape = false,
+ .has_hex_escape = false,
+ .last_escape_was_unicode = false,
+ .explicit_encoding = NULL,
+ .has_property_escape = false,
+ .has_unicode_property_escape = false,
+ .property_name = NULL,
+ .property_name_length = 0,
+ .unicode_property_name = NULL,
+ .unicode_property_name_length = 0,
+ .non_ascii_literal_count = 0,
+ .invalid_unicode_range = false,
+ .hex_escape_buffer = { 0 },
+ .hex_group_active = false,
+ .has_invalid_multibyte = false,
+ };
+
+ pm_regexp_parse_pattern(&regexp_parser);
+
+ // Compute ascii_only from the regexp parser's tracked state. We cannot
+ // use node->unescaped for this because regexp unescaped content preserves
+ // escape text (e.g., \x80 is 4 ASCII chars), not the binary values.
+ bool ascii_only = !regexp_parser.has_hex_escape && !regexp_parser.has_unicode_escape && regexp_parser.non_ascii_literal_count == 0;
+ // Use the unescaped content for error messages to match CRuby's format,
+ // where Ruby escapes like \M-\C-? are resolved to bytes but regexp escapes
+ // like \u{80} are preserved as text.
+ const char *error_source = (const char *) pm_string_source(&node->unescaped);
+ int error_source_length = (int) pm_string_length(&node->unescaped);
+ pm_node_flags_t encoding_flags = pm_regexp_validate_encoding(&regexp_parser, ascii_only, flags, error_source, error_source_length);
+ pm_buffer_cleanup(&regexp_parser.hex_escape_buffer);
+
+ // Second pass: walk unescaped content for named capture extraction.
+ if (name_callback != NULL) {
+ bool shared = node->unescaped.type == PM_STRING_SHARED;
+ pm_regexp_parse_named_captures(parser, pm_string_source(&node->unescaped), pm_string_length(&node->unescaped), shared, extended_mode, name_callback, name_data);
+ }
+
+ return encoding_flags;
+}
+
+/**
+ * Parse an interpolated regular expression for named capture groups only.
+ * This is used for the =~ operator with interpolated regexps where we don't
+ * have a pm_regular_expression_node_t. No encoding validation is performed.
+ *
+ * Note: The encoding-tracking fields (has_unicode_escape, has_hex_escape, etc.)
+ * are initialized but not used for the result. They exist because the parsing
+ * functions (pm_regexp_parse_backslash_escape, etc.) unconditionally update
+ * them as they walk through the content.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data) {
- pm_regexp_parse_pattern(&(pm_regexp_parser_t) {
+void
+pm_regexp_parse_named_captures(pm_parser_t *parser, const uint8_t *source, size_t size, bool shared, bool extended_mode, pm_regexp_name_callback_t name_callback, pm_regexp_name_data_t *name_data) {
+ pm_regexp_parser_t regexp_parser = {
.parser = parser,
.start = source,
.cursor = source,
@@ -784,7 +1692,26 @@ pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool ex
.encoding = parser->encoding,
.name_callback = name_callback,
.name_data = name_data,
- .error_callback = error_callback,
- .error_data = error_data
- });
+ .shared = shared,
+ .node_start = source,
+ .node_end = source + size,
+ .has_unicode_escape = false,
+ .has_hex_escape = false,
+ .last_escape_was_unicode = false,
+ .explicit_encoding = NULL,
+ .has_property_escape = false,
+ .has_unicode_property_escape = false,
+ .property_name = NULL,
+ .property_name_length = 0,
+ .unicode_property_name = NULL,
+ .unicode_property_name_length = 0,
+ .non_ascii_literal_count = 0,
+ .invalid_unicode_range = false,
+ .hex_escape_buffer = { 0 },
+ .hex_group_active = false,
+ .has_invalid_multibyte = false,
+ };
+
+ pm_regexp_parse_pattern(&regexp_parser);
+ pm_buffer_cleanup(&regexp_parser.hex_escape_buffer);
}
diff --git a/prism/regexp.h b/prism/regexp.h
deleted file mode 100644
index c0b3163e93..0000000000
--- a/prism/regexp.h
+++ /dev/null
@@ -1,43 +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.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-/**
- * This callback is called when a named capture group is found.
- */
-typedef void (*pm_regexp_name_callback_t)(const pm_string_t *name, void *data);
-
-/**
- * This callback is called when a parse error is found.
- */
-typedef void (*pm_regexp_error_callback_t)(const uint8_t *start, const uint8_t *end, const char *message, void *data);
-
-/**
- * Parse a regular expression.
- *
- * @param parser The parser that is currently being used.
- * @param source The source code to parse.
- * @param size The size of the source code.
- * @param extended_mode Whether to parse the regular expression in extended mode.
- * @param name_callback The optional callback to call when a named capture group is found.
- * @param name_data The optional data to pass to the name callback.
- * @param error_callback The callback to call when a parse error is found.
- * @param error_data The data to pass to the error callback.
- */
-PRISM_EXPORTED_FUNCTION void pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data);
-
-#endif
diff --git a/prism/serialize.h b/prism/serialize.h
new file mode 100644
index 0000000000..786a1514bc
--- /dev/null
+++ b/prism/serialize.h
@@ -0,0 +1,96 @@
+/**
+ * @file serialize.h
+ *
+ * The functions related to serializing the AST to a binary format.
+ */
+#ifndef PRISM_SERIALIZE_H
+#define PRISM_SERIALIZE_H
+
+#include "prism/excludes.h"
+
+/* We optionally support serializing to a binary string. For systems that do not
+ * want or need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_SERIALIZATION define. */
+#ifndef PRISM_EXCLUDE_SERIALIZATION
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/buffer.h"
+#include "prism/parser.h"
+#include "prism/source.h"
+#include "prism/stream.h"
+
+/**
+ * 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) PRISM_NONNULL(1, 2, 3);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * Parse and serialize the AST represented by the given source into the given
+ * buffer.
+ *
+ * @param buffer The buffer to serialize to.
+ * @param source The source to parse.
+ * @param data The optional data to pass to the parser.
+ */
+PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, pm_source_t *source, const char *data) PRISM_NONNULL(1, 2);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * 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) PRISM_NONNULL(1, 2);
+
+/**
+ * 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.
+ * @returns True if the source parses without errors or warnings.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) PRISM_NONNULL(1);
+
+#endif
+
+#endif
diff --git a/prism/source.c b/prism/source.c
new file mode 100644
index 0000000000..f61cb19c1b
--- /dev/null
+++ b/prism/source.c
@@ -0,0 +1,491 @@
+#include "prism/internal/source.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/buffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* The following headers are necessary to read files using demand paging. */
+#ifdef _WIN32
+#include <windows.h>
+#elif defined(_POSIX_MAPPED_FILES)
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#elif defined(PRISM_HAS_FILESYSTEM)
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
+static const uint8_t empty_source[] = "";
+
+/**
+ * Allocate and initialize a pm_source_t with the given fields.
+ */
+static pm_source_t *
+pm_source_alloc(const uint8_t *source, size_t length, pm_source_type_t type) {
+ pm_source_t *result = xmalloc(sizeof(pm_source_t));
+ if (result == NULL) abort();
+
+ *result = (struct pm_source_t) {
+ .source = source,
+ .length = length,
+ .type = type
+ };
+
+ return result;
+}
+
+/**
+ * Create a new source that wraps existing constant memory.
+ */
+pm_source_t *
+pm_source_constant_new(const uint8_t *data, size_t length) {
+ return pm_source_alloc(data, length, PM_SOURCE_CONSTANT);
+}
+
+/**
+ * Create a new source that wraps existing shared memory.
+ */
+pm_source_t *
+pm_source_shared_new(const uint8_t *data, size_t length) {
+ return pm_source_alloc(data, length, PM_SOURCE_SHARED);
+}
+
+/**
+ * Create a new source that owns its memory.
+ */
+pm_source_t *
+pm_source_owned_new(uint8_t *data, size_t length) {
+ return pm_source_alloc(data, length, PM_SOURCE_OWNED);
+}
+
+#ifdef _WIN32
+/**
+ * Represents a file handle on Windows, where the path will need to be freed
+ * when the file is closed.
+ */
+typedef struct {
+ /** The path to the file, which will become allocated memory. */
+ WCHAR *path;
+
+ /** The size of the allocated path in bytes. */
+ size_t path_size;
+
+ /** The handle to the file, which will start as uninitialized memory. */
+ HANDLE file;
+} pm_source_file_handle_t;
+
+/**
+ * Open the file indicated by the filepath parameter for reading on Windows.
+ */
+static pm_source_init_result_t
+pm_source_file_handle_open(pm_source_file_handle_t *handle, const char *filepath) {
+ int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
+ if (length == 0) return PM_SOURCE_INIT_ERROR_GENERIC;
+
+ handle->path_size = sizeof(WCHAR) * ((size_t) length);
+ handle->path = xmalloc(handle->path_size);
+ if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
+ xfree_sized(handle->path, handle->path_size);
+ return PM_SOURCE_INIT_ERROR_GENERIC;
+ }
+
+ handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+ if (handle->file == INVALID_HANDLE_VALUE) {
+ pm_source_init_result_t result = PM_SOURCE_INIT_ERROR_GENERIC;
+
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ DWORD attributes = GetFileAttributesW(handle->path);
+ if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = PM_SOURCE_INIT_ERROR_DIRECTORY;
+ }
+ }
+
+ xfree_sized(handle->path, handle->path_size);
+ return result;
+ }
+
+ return PM_SOURCE_INIT_SUCCESS;
+}
+
+/**
+ * Close the file handle and free the path.
+ */
+static void
+pm_source_file_handle_close(pm_source_file_handle_t *handle) {
+ xfree_sized(handle->path, handle->path_size);
+ CloseHandle(handle->file);
+}
+#endif
+
+/**
+ * Create a new source by memory-mapping a file.
+ */
+pm_source_t *
+pm_source_mapped_new(const char *filepath, int open_flags, pm_source_init_result_t *result) {
+#ifdef _WIN32
+ (void) open_flags;
+
+ /* Open the file for reading. */
+ pm_source_file_handle_t handle;
+ *result = pm_source_file_handle_open(&handle, filepath);
+ if (*result != PM_SOURCE_INIT_SUCCESS) return NULL;
+
+ /* Get the file size. */
+ DWORD file_size = GetFileSize(handle.file, NULL);
+ if (file_size == INVALID_FILE_SIZE) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* If the file is empty, then return a constant source. */
+ if (file_size == 0) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ /* Create a mapping of the file. */
+ HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (mapping == NULL) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Map the file into memory. */
+ uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle(mapping);
+ pm_source_file_handle_close(&handle);
+
+ if (source == NULL) {
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, (size_t) file_size, PM_SOURCE_MAPPED);
+#elif defined(_POSIX_MAPPED_FILES)
+ /* Open the file for reading. */
+ int fd = open(filepath, O_RDONLY | open_flags);
+ if (fd == -1) {
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Stat the file to get the file size. */
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Ensure it is a file and not a directory. */
+ if (S_ISDIR(sb.st_mode)) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_DIRECTORY;
+ return NULL;
+ }
+
+ /*
+ * For non-regular files (pipes, character devices), return a specific
+ * error so the caller can handle reading through their own I/O layer.
+ */
+ if (!S_ISREG(sb.st_mode)) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_NON_REGULAR;
+ return NULL;
+ }
+
+ /* mmap the file descriptor to virtually get the contents. */
+ size_t size = (size_t) sb.st_size;
+
+ if (size == 0) {
+ close(fd);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ uint8_t *source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (source == MAP_FAILED) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ close(fd);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, size, PM_SOURCE_MAPPED);
+#else
+ (void) open_flags;
+ return pm_source_file_new(filepath, result);
+#endif
+}
+
+/**
+ * Create a new source by reading a file into a heap-allocated buffer.
+ */
+pm_source_t *
+pm_source_file_new(const char *filepath, pm_source_init_result_t *result) {
+#ifdef _WIN32
+ /* Open the file for reading. */
+ pm_source_file_handle_t handle;
+ *result = pm_source_file_handle_open(&handle, filepath);
+ if (*result != PM_SOURCE_INIT_SUCCESS) return NULL;
+
+ /* Get the file size. */
+ const DWORD file_size = GetFileSize(handle.file, NULL);
+ if (file_size == INVALID_FILE_SIZE) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* If the file is empty, return a constant source. */
+ if (file_size == 0) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ /* Create a buffer to read the file into. */
+ uint8_t *source = xmalloc(file_size);
+ if (source == NULL) {
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Read the contents of the file. */
+ DWORD bytes_read;
+ if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
+ xfree_sized(source, file_size);
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Check the number of bytes read. */
+ if (bytes_read != file_size) {
+ xfree_sized(source, file_size);
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ pm_source_file_handle_close(&handle);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, (size_t) file_size, PM_SOURCE_OWNED);
+#elif defined(PRISM_HAS_FILESYSTEM)
+ /* Open the file for reading. */
+ int fd = open(filepath, O_RDONLY);
+ if (fd == -1) {
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Stat the file to get the file size. */
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ /* Ensure it is a file and not a directory. */
+ if (S_ISDIR(sb.st_mode)) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_DIRECTORY;
+ return NULL;
+ }
+
+ /* Check the size to see if it's empty. */
+ size_t size = (size_t) sb.st_size;
+ if (size == 0) {
+ close(fd);
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
+ }
+
+ const size_t length = (size_t) size;
+ uint8_t *source = xmalloc(length);
+ if (source == NULL) {
+ close(fd);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ ssize_t bytes_read = read(fd, source, length);
+ close(fd);
+
+ if (bytes_read == -1 || (size_t) bytes_read != length) {
+ xfree_sized(source, length);
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ return NULL;
+ }
+
+ *result = PM_SOURCE_INIT_SUCCESS;
+ return pm_source_alloc(source, length, PM_SOURCE_OWNED);
+#else
+ (void) filepath;
+ *result = PM_SOURCE_INIT_ERROR_GENERIC;
+ perror("pm_source_file_new is not implemented for this platform");
+ return NULL;
+#endif
+}
+
+/**
+ * Create a new source by reading from a stream. This allocates the source
+ * but does not read from the stream yet. Use pm_source_stream_read to read
+ * data.
+ */
+pm_source_t *
+pm_source_stream_new(void *stream, pm_source_stream_fgets_t *fgets, pm_source_stream_feof_t *feof) {
+ pm_source_t *source = pm_source_alloc(NULL, 0, PM_SOURCE_STREAM);
+ source->stream.buffer = pm_buffer_new();
+ source->stream.stream = stream;
+ source->stream.fgets = fgets;
+ source->stream.feof = feof;
+ source->stream.eof = false;
+
+ return source;
+}
+
+/**
+ * Read from the stream into the source's internal buffer until __END__ is
+ * encountered or EOF is reached. Updates the source pointer and length.
+ *
+ * Returns true if EOF was reached, false if __END__ was encountered.
+ */
+bool
+pm_source_stream_read(pm_source_t *source) {
+ pm_buffer_t *buffer = source->stream.buffer;
+
+#define LINE_SIZE 4096
+ char line[LINE_SIZE];
+
+ while (memset(line, '\n', LINE_SIZE), source->stream.fgets(line, LINE_SIZE, source->stream.stream) != NULL) {
+ size_t length = LINE_SIZE;
+ while (length > 0 && line[length - 1] == '\n') length--;
+
+ if (length == LINE_SIZE) {
+ /*
+ * If we read a line that is the maximum size and it doesn't end
+ * with a newline, then we'll just append it to the buffer and
+ * continue reading.
+ */
+ length--;
+ pm_buffer_append_string(buffer, line, length);
+ continue;
+ }
+
+ /* Append the line to the buffer. */
+ length--;
+ pm_buffer_append_string(buffer, line, length);
+
+ /*
+ * Check if the line matches the __END__ marker. If it does, then stop
+ * reading and return false. In most circumstances, this means we should
+ * stop reading from the stream so that the DATA constant can pick it
+ * up.
+ */
+ switch (length) {
+ case 7:
+ if (strncmp(line, "__END__", 7) == 0) {
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return false;
+ }
+ break;
+ case 8:
+ if (strncmp(line, "__END__\n", 8) == 0) {
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return false;
+ }
+ break;
+ case 9:
+ if (strncmp(line, "__END__\r\n", 9) == 0) {
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return false;
+ }
+ break;
+ }
+
+ /*
+ * All data should be read via gets. If the string returned by gets
+ * _doesn't_ end with a newline, then we assume we hit EOF condition.
+ */
+ if (source->stream.feof(source->stream.stream)) {
+ break;
+ }
+ }
+
+#undef LINE_SIZE
+
+ source->stream.eof = true;
+ source->source = (const uint8_t *) pm_buffer_value(buffer);
+ source->length = pm_buffer_length(buffer);
+ return true;
+}
+
+/**
+ * Returns whether the stream source has reached EOF.
+ */
+bool
+pm_source_stream_eof(const pm_source_t *source) {
+ return source->stream.eof;
+}
+
+/**
+ * Free the given source and any memory it owns.
+ */
+void
+pm_source_free(pm_source_t *source) {
+ switch (source->type) {
+ case PM_SOURCE_CONSTANT:
+ case PM_SOURCE_SHARED:
+ /* No cleanup needed for the data. */
+ break;
+ case PM_SOURCE_OWNED:
+ xfree_sized((void *) source->source, source->length);
+ break;
+ case PM_SOURCE_MAPPED:
+#if defined(_WIN32)
+ if (source->length > 0) {
+ UnmapViewOfFile((void *) source->source);
+ }
+#elif defined(_POSIX_MAPPED_FILES)
+ if (source->length > 0) {
+ munmap((void *) source->source, source->length);
+ }
+#endif
+ break;
+ case PM_SOURCE_STREAM:
+ pm_buffer_free(source->stream.buffer);
+ break;
+ }
+
+ xfree_sized(source, sizeof(pm_source_t));
+}
+
+/**
+ * Returns the length of the source data in bytes.
+ */
+size_t
+pm_source_length(const pm_source_t *source) {
+ return source->length;
+}
+
+/**
+ * Returns a pointer to the source data.
+ */
+const uint8_t *
+pm_source_source(const pm_source_t *source) {
+ return source->source;
+}
diff --git a/prism/source.h b/prism/source.h
new file mode 100644
index 0000000000..c79987d3fb
--- /dev/null
+++ b/prism/source.h
@@ -0,0 +1,148 @@
+/**
+ * @file source.h
+ *
+ * An opaque type representing the source code being parsed, regardless of
+ * origin (constant memory, file, memory-mapped file, or stream).
+ */
+#ifndef PRISM_SOURCE_H
+#define PRISM_SOURCE_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/filesystem.h"
+#include "prism/compiler/nodiscard.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * An opaque type representing source code being parsed.
+ */
+typedef struct pm_source_t pm_source_t;
+
+/**
+ * This function is used to retrieve a line of input from a stream. It closely
+ * mirrors that of fgets so that fgets can be used as the default
+ * implementation.
+ */
+typedef char * (pm_source_stream_fgets_t)(char *string, int size, void *stream);
+
+/**
+ * This function is used to check whether a stream is at EOF. It closely mirrors
+ * that of feof so that feof can be used as the default implementation.
+ */
+typedef int (pm_source_stream_feof_t)(void *stream);
+
+/**
+ * Represents the result of initializing a source from a file.
+ */
+typedef enum {
+ /** Indicates that the source was successfully initialized. */
+ PM_SOURCE_INIT_SUCCESS = 0,
+
+ /**
+ * Indicates a generic error from a source init function, where the type
+ * of error should be read from `errno` or `GetLastError()`.
+ */
+ PM_SOURCE_INIT_ERROR_GENERIC = 1,
+
+ /**
+ * Indicates that the file that was attempted to be opened was a directory.
+ */
+ PM_SOURCE_INIT_ERROR_DIRECTORY = 2,
+
+ /**
+ * Indicates that the file is not a regular file (e.g. a pipe or character
+ * device) and the caller should handle reading it.
+ */
+ PM_SOURCE_INIT_ERROR_NON_REGULAR = 3
+} pm_source_init_result_t;
+
+/**
+ * Create a new source that wraps existing constant memory. The memory is not
+ * owned and will not be freed.
+ *
+ * @param data The pointer to the source data.
+ * @param length The length of the source data in bytes.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_constant_new(const uint8_t *data, size_t length);
+
+/**
+ * Create a new source that wraps existing shared memory. The memory is not
+ * owned and will not be freed. Semantically a "slice" of another source.
+ *
+ * @param data The pointer to the source data.
+ * @param length The length of the source data in bytes.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_shared_new(const uint8_t *data, size_t length);
+
+/**
+ * Create a new source that owns its memory. The memory will be freed with
+ * xfree when the source is freed.
+ *
+ * @param data The pointer to the heap-allocated source data.
+ * @param length The length of the source data in bytes.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_owned_new(uint8_t *data, size_t length);
+
+/**
+ * Create a new source by reading a file into a heap-allocated buffer.
+ *
+ * @param filepath The path to the file to read.
+ * @param result Out parameter for the result of the initialization.
+ * @returns A new source, or NULL on error (with result written to out param).
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_file_new(const char *filepath, pm_source_init_result_t *result) PRISM_NONNULL(1, 2);
+
+/**
+ * Create a new source by memory-mapping a file. Falls back to file reading on
+ * platforms without mmap support.
+ *
+ * If the file is a non-regular file (e.g. a pipe or character device),
+ * PM_SOURCE_INIT_ERROR_NON_REGULAR is returned, allowing the caller to handle
+ * it appropriately (e.g. by reading it through their own I/O layer).
+ *
+ * @param filepath The path to the file to read.
+ * @param open_flags Additional flags to pass to open(2) (e.g. O_NONBLOCK).
+ * @param result Out parameter for the result of the initialization.
+ * @returns A new source, or NULL on error (with result written to out param).
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_mapped_new(const char *filepath, int open_flags, pm_source_init_result_t *result) PRISM_NONNULL(1, 3);
+
+/**
+ * Create a new source by reading from a stream using the provided callbacks.
+ *
+ * @param stream The stream to read from.
+ * @param fgets The function to use to read from the stream.
+ * @param feof The function to use to check if the stream is at EOF.
+ * @returns A new source. Aborts on allocation failure.
+ */
+PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_source_t * pm_source_stream_new(void *stream, pm_source_stream_fgets_t *fgets, pm_source_stream_feof_t *feof);
+
+/**
+ * Free the given source and any memory it owns.
+ *
+ * @param source The source to free.
+ */
+PRISM_EXPORTED_FUNCTION void pm_source_free(pm_source_t *source) PRISM_NONNULL(1);
+
+/**
+ * Returns the length of the source data in bytes.
+ *
+ * @param source The source to get the length of.
+ * @returns The length of the source data.
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_source_length(const pm_source_t *source) PRISM_NONNULL(1);
+
+/**
+ * Returns a pointer to the source data.
+ *
+ * @param source The source to get the data of.
+ * @returns A pointer to the source data.
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_source_source(const pm_source_t *source) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/srcs.mk b/prism/srcs.mk
new file mode 100644
index 0000000000..93ad8f579f
--- /dev/null
+++ b/prism/srcs.mk
@@ -0,0 +1,160 @@
+PRISM_TEMPLATES_DIR = $(PRISM_SRCDIR)/templates
+PRISM_TEMPLATE = $(PRISM_TEMPLATES_DIR)/template.rb
+PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml
+
+srcs uncommon.mk: prism/.srcs.mk.time
+
+prism/.srcs.mk.time: $(order_only) $(PRISM_BUILD_DIR)/.time
+prism/$(HAVE_BASERUBY:no=.srcs.mk.time):
+ touch $@
+prism/$(HAVE_BASERUBY:yes=.srcs.mk.time): \
+ $(PRISM_SRCDIR)/templates/template.rb \
+ $(PRISM_SRCDIR)/srcs.mk.in
+ $(BASERUBY) $(tooldir)/generic_erb.rb -c -t$@ -o $(PRISM_SRCDIR)/srcs.mk $(PRISM_SRCDIR)/srcs.mk.in
+
+distclean-prism-srcs::
+ $(RM) prism/.srcs.mk.time
+ $(RMDIRS) prism || $(NULLCMD)
+
+distclean-srcs-local:: distclean-prism-srcs
+
+realclean-prism-srcs:: distclean-prism-srcs
+ $(RM) $(PRISM_SRCDIR)/srcs.mk
+
+realclean-srcs-local:: realclean-prism-srcs
+
+main srcs: prism-srcs
+main incs: prism-incs
+
+prism-srcs: $(srcdir)/prism/api_node.c
+$(srcdir)/prism/api_node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/ext/prism/api_node.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) ext/prism/api_node.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/api_node.c
+
+prism-incs: $(srcdir)/prism/ast.h
+$(srcdir)/prism/ast.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/ast.h.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/ast.h $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/ast.h
+
+prism-incs: $(srcdir)/prism/internal/diagnostic.h
+$(srcdir)/prism/internal/diagnostic.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/internal/diagnostic.h.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/internal/diagnostic.h $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/internal/diagnostic.h
+
+prism-srcs: $(srcdir)/lib/prism/compiler.rb
+$(srcdir)/lib/prism/compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/compiler.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/compiler.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/compiler.rb
+
+prism-srcs: $(srcdir)/lib/prism/dispatcher.rb
+$(srcdir)/lib/prism/dispatcher.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dispatcher.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dispatcher.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/dispatcher.rb
+
+prism-srcs: $(srcdir)/lib/prism/dot_visitor.rb
+$(srcdir)/lib/prism/dot_visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dot_visitor.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dot_visitor.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/dot_visitor.rb
+
+prism-srcs: $(srcdir)/lib/prism/dsl.rb
+$(srcdir)/lib/prism/dsl.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dsl.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dsl.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/dsl.rb
+
+prism-srcs: $(srcdir)/lib/prism/inspect_visitor.rb
+$(srcdir)/lib/prism/inspect_visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/inspect_visitor.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/inspect_visitor.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/inspect_visitor.rb
+
+prism-srcs: $(srcdir)/lib/prism/mutation_compiler.rb
+$(srcdir)/lib/prism/mutation_compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/mutation_compiler.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/mutation_compiler.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/mutation_compiler.rb
+
+prism-srcs: $(srcdir)/lib/prism/node.rb
+$(srcdir)/lib/prism/node.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/node.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/node.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/node.rb
+
+prism-srcs: $(srcdir)/lib/prism/reflection.rb
+$(srcdir)/lib/prism/reflection.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/reflection.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/reflection.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/reflection.rb
+
+prism-srcs: $(srcdir)/lib/prism/serialize.rb
+$(srcdir)/lib/prism/serialize.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/serialize.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/serialize.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/serialize.rb
+
+prism-srcs: $(srcdir)/lib/prism/visitor.rb
+$(srcdir)/lib/prism/visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/visitor.rb.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/visitor.rb $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/lib/prism/visitor.rb
+
+prism-srcs: $(srcdir)/prism/diagnostic.c
+$(srcdir)/prism/diagnostic.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/diagnostic.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/diagnostic.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/diagnostic.c
+
+prism-srcs: $(srcdir)/prism/json.c
+$(srcdir)/prism/json.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/json.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/json.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/json.c
+
+prism-srcs: $(srcdir)/prism/node.c
+$(srcdir)/prism/node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/node.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/node.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/node.c
+
+prism-srcs: $(srcdir)/prism/prettyprint.c
+$(srcdir)/prism/prettyprint.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/prettyprint.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/prettyprint.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/prettyprint.c
+
+prism-srcs: $(srcdir)/prism/serialize.c
+$(srcdir)/prism/serialize.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/serialize.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/serialize.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/serialize.c
+
+prism-srcs: $(srcdir)/prism/tokens.c
+$(srcdir)/prism/tokens.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/tokens.c.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/tokens.c $@
+
+realclean-prism-srcs::
+ $(RM) $(srcdir)/prism/tokens.c
diff --git a/prism/srcs.mk.in b/prism/srcs.mk.in
new file mode 100644
index 0000000000..6149e4ae9d
--- /dev/null
+++ b/prism/srcs.mk.in
@@ -0,0 +1,52 @@
+<% # -*- ruby -*-
+# :stopdoc:
+require_relative 'templates/template'
+
+script = File.basename(__FILE__)
+srcs = output ? File.basename(output) : script.chomp('.in')
+mk = 'uncommon.mk'
+
+# %>
+PRISM_TEMPLATES_DIR = $(PRISM_SRCDIR)/templates
+PRISM_TEMPLATE = $(PRISM_TEMPLATES_DIR)/template.rb
+PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml
+
+srcs <%=%><%=mk%>: prism/.srcs.mk.time
+
+prism/.srcs.mk.time: $(order_only) $(PRISM_BUILD_DIR)/.time
+prism/$(HAVE_BASERUBY:no=.srcs.mk.time):
+ touch $@
+prism/$(HAVE_BASERUBY:yes=.srcs.mk.time): \
+ $(PRISM_SRCDIR)/templates/template.rb \
+ $(PRISM_SRCDIR)/<%=%><%=script%>
+ $(BASERUBY) $(tooldir)/generic_erb.rb -c -t$@ -o $(PRISM_SRCDIR)/<%=%><%=srcs%> $(PRISM_SRCDIR)/<%=%><%=script%>
+
+distclean-prism-srcs::
+ $(RM) prism/.srcs.mk.time
+ $(RMDIRS) prism || $(NULLCMD)
+
+distclean-srcs-local:: distclean-prism-srcs
+
+realclean-prism-srcs:: distclean-prism-srcs
+ $(RM) $(PRISM_SRCDIR)/<%=%><%=srcs%>
+
+realclean-srcs-local:: realclean-prism-srcs
+
+main srcs: prism-srcs
+main incs: prism-incs
+<% Prism::Template::TEMPLATES.map do |t|
+ /\.(?:[ch]|rb)\z/ =~ t or next
+ s = '$(srcdir)/' + t.sub(%r[\A(?:(src)|ext|include)/]) {$1 && 'prism/'}
+ s.sub!(%r[\A\$(srcdir)/prism/], '$(PRISM_SRCDIR)/')
+ target = s.end_with?('.h') ? 'incs' : 'srcs'
+# %>
+
+prism-<%=%><%=target%>: <%=%><%=s%>
+<%=%><%=s%>: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/<%=%><%=t%>.erb
+ $(Q) $(BASERUBY) $(PRISM_TEMPLATE) <%=%><%=t%> $@
+
+realclean-prism-srcs::
+ $(RM) <%=%><%=s%>
+<%
+end
+# %>
diff --git a/prism/static_literals.c b/prism/static_literals.c
index 9fa37b999a..9af1eadf5d 100644
--- a/prism/static_literals.c
+++ b/prism/static_literals.c
@@ -1,4 +1,18 @@
-#include "prism/static_literals.h"
+#include "prism/internal/static_literals.h"
+
+#include "prism/compiler/inline.h"
+#include "prism/compiler/unused.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/isinf.h"
+#include "prism/internal/stringy.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
/**
* A small struct used for passing around a subset of the information that is
@@ -7,7 +21,10 @@
*/
typedef struct {
/** The list of newline offsets to use to calculate line numbers. */
- const pm_newline_list_t *newline_list;
+ const pm_line_offset_list_t *line_offsets;
+
+ /** The start of the source being parsed. */
+ const uint8_t *start;
/** The line number that the parser starts on. */
int32_t start_line;
@@ -16,7 +33,7 @@ typedef struct {
const char *encoding_name;
} pm_static_literals_metadata_t;
-static inline uint32_t
+static PRISM_INLINE uint32_t
murmur_scramble(uint32_t value) {
value *= 0xcc9e2d51;
value = (value << 15) | (value >> 17);
@@ -92,7 +109,7 @@ node_hash(const pm_static_literals_metadata_t *metadata, const pm_node_t *node)
}
case PM_SOURCE_LINE_NODE: {
// Source lines hash their line number.
- const pm_line_column_t line_column = pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line);
+ const pm_line_column_t line_column = pm_line_offset_list_line_column(metadata->line_offsets, node->location.start, metadata->start_line);
const int32_t *value = &line_column.line;
return murmur_hash((const uint8_t *) value, sizeof(int32_t));
}
@@ -180,7 +197,7 @@ pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *m
}
// Finally, free the old node list and update the hash.
- xfree(hash->nodes);
+ xfree_sized(hash->nodes, hash->capacity * sizeof(pm_node_t *));
hash->nodes = new_nodes;
hash->capacity = new_capacity;
}
@@ -218,7 +235,7 @@ pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *m
*/
static void
pm_node_hash_free(pm_node_hash_t *hash) {
- if (hash->capacity > 0) xfree(hash->nodes);
+ if (hash->capacity > 0) xfree_sized(hash->nodes, hash->capacity * sizeof(pm_node_t *));
}
/**
@@ -240,7 +257,7 @@ pm_int64_value(const pm_static_literals_metadata_t *metadata, const pm_node_t *n
return integer->negative ? -value : value;
}
case PM_SOURCE_LINE_NODE:
- return (int64_t) pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line;
+ return (int64_t) pm_line_offset_list_line_column(metadata->line_offsets, node->location.start, metadata->start_line).line;
default:
assert(false && "unreachable");
return 0;
@@ -268,7 +285,7 @@ pm_compare_integer_nodes(const pm_static_literals_metadata_t *metadata, const pm
* A comparison function for comparing two FloatNode instances.
*/
static int
-pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_float_nodes(PRISM_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
const double left_value = ((const pm_float_node_t *) left)->value;
const double right_value = ((const pm_float_node_t *) right)->value;
return PM_NUMERIC_COMPARISON(left_value, right_value);
@@ -327,7 +344,7 @@ pm_string_value(const pm_node_t *node) {
* A comparison function for comparing two nodes that have attached strings.
*/
static int
-pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_string_nodes(PRISM_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
const pm_string_t *left_string = pm_string_value(left);
const pm_string_t *right_string = pm_string_value(right);
return pm_string_compare(left_string, right_string);
@@ -337,7 +354,7 @@ pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata
* A comparison function for comparing two RegularExpressionNode instances.
*/
static int
-pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
+pm_compare_regular_expression_nodes(PRISM_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
const pm_regular_expression_node_t *left_regexp = (const pm_regular_expression_node_t *) left;
const pm_regular_expression_node_t *right_regexp = (const pm_regular_expression_node_t *) right;
@@ -353,14 +370,15 @@ pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_liter
* Add a node to the set of static literals.
*/
pm_node_t *
-pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace) {
+pm_static_literals_add(const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace) {
switch (PM_NODE_TYPE(node)) {
case PM_INTEGER_NODE:
case PM_SOURCE_LINE_NODE:
return pm_node_hash_insert(
&literals->integer_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -372,7 +390,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->float_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -385,7 +404,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->number_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -398,7 +418,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->string_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -410,7 +431,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->regexp_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -422,7 +444,8 @@ pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line
return pm_node_hash_insert(
&literals->symbol_nodes,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = NULL
},
@@ -492,7 +515,7 @@ pm_static_literal_positive_p(const pm_node_t *node) {
/**
* Create a string-based representation of the given static literal.
*/
-static inline void
+static PRISM_INLINE void
pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
switch (PM_NODE_TYPE(node)) {
case PM_FALSE_NODE:
@@ -502,12 +525,12 @@ pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_met
const double value = ((const pm_float_node_t *) node)->value;
if (PRISM_ISINF(value)) {
- if (*node->location.start == '-') {
+ if (metadata->start[node->location.start] == '-') {
pm_buffer_append_byte(buffer, '-');
}
pm_buffer_append_string(buffer, "Infinity", 8);
} else if (value == 0.0) {
- if (*node->location.start == '-') {
+ if (metadata->start[node->location.start] == '-') {
pm_buffer_append_byte(buffer, '-');
}
pm_buffer_append_string(buffer, "0.0", 3);
@@ -576,7 +599,7 @@ pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_met
break;
}
case PM_SOURCE_LINE_NODE:
- pm_buffer_append_format(buffer, "%d", pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line);
+ pm_buffer_append_format(buffer, "%d", pm_line_offset_list_line_column(metadata->line_offsets, node->location.start, metadata->start_line).line);
break;
case PM_STRING_NODE: {
const pm_string_t *unescaped = &((const pm_string_node_t *) node)->unescaped;
@@ -604,11 +627,12 @@ pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_met
* Create a string-based representation of the given static literal.
*/
void
-pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node) {
+pm_static_literal_inspect(pm_buffer_t *buffer, const pm_line_offset_list_t *line_offsets, const uint8_t *start, int32_t start_line, const char *encoding_name, const pm_node_t *node) {
pm_static_literal_inspect_node(
buffer,
&(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
+ .line_offsets = line_offsets,
+ .start = start,
.start_line = start_line,
.encoding_name = encoding_name
},
diff --git a/prism/static_literals.h b/prism/static_literals.h
deleted file mode 100644
index bd29761899..0000000000
--- a/prism/static_literals.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * @file static_literals.h
- *
- * A set of static literal nodes that can be checked for duplicates.
- */
-#ifndef PRISM_STATIC_LITERALS_H
-#define PRISM_STATIC_LITERALS_H
-
-#include "prism/defines.h"
-#include "prism/ast.h"
-#include "prism/util/pm_newline_list.h"
-
-#include <assert.h>
-#include <stdbool.h>
-
-/**
- * An internal hash table for a set of nodes.
- */
-typedef struct {
- /** The array of nodes in the hash table. */
- pm_node_t **nodes;
-
- /** The size of the hash table. */
- uint32_t size;
-
- /** The space that has been allocated in the hash table. */
- uint32_t capacity;
-} pm_node_hash_t;
-
-/**
- * Certain sets of nodes (hash keys and when clauses) check for duplicate nodes
- * to alert the user of potential issues. To do this, we keep a set of the nodes
- * that have been seen so far, and compare whenever we find a new node.
- *
- * We bucket the nodes based on their type to minimize the number of comparisons
- * that need to be performed.
- */
-typedef struct {
- /**
- * This is the set of IntegerNode and SourceLineNode instances.
- */
- pm_node_hash_t integer_nodes;
-
- /**
- * This is the set of FloatNode instances.
- */
- pm_node_hash_t float_nodes;
-
- /**
- * This is the set of RationalNode and ImaginaryNode instances.
- */
- pm_node_hash_t number_nodes;
-
- /**
- * This is the set of StringNode and SourceFileNode instances.
- */
- pm_node_hash_t string_nodes;
-
- /**
- * This is the set of RegularExpressionNode instances.
- */
- pm_node_hash_t regexp_nodes;
-
- /**
- * This is the set of SymbolNode instances.
- */
- pm_node_hash_t symbol_nodes;
-
- /**
- * A pointer to the last TrueNode instance that was inserted, or NULL.
- */
- pm_node_t *true_node;
-
- /**
- * A pointer to the last FalseNode instance that was inserted, or NULL.
- */
- pm_node_t *false_node;
-
- /**
- * A pointer to the last NilNode instance that was inserted, or NULL.
- */
- pm_node_t *nil_node;
-
- /**
- * A pointer to the last SourceEncodingNode instance that was inserted, or
- * NULL.
- */
- pm_node_t *source_encoding_node;
-} pm_static_literals_t;
-
-/**
- * Add a node to the set of static literals.
- *
- * @param newline_list The list of newline offsets to use to calculate lines.
- * @param start_line The line number that the parser starts on.
- * @param literals The set of static literals to add the node to.
- * @param node The node to add to the set.
- * @param replace Whether to replace the previous node if one already exists.
- * @return A pointer to the node that is being overwritten, if there is one.
- */
-pm_node_t * pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace);
-
-/**
- * Free the internal memory associated with the given static literals set.
- *
- * @param literals The set of static literals to free.
- */
-void pm_static_literals_free(pm_static_literals_t *literals);
-
-/**
- * Create a string-based representation of the given static literal.
- *
- * @param buffer The buffer to write the string to.
- * @param newline_list The list of newline offsets to use to calculate lines.
- * @param start_line The line number that the parser starts on.
- * @param encoding_name The name of the encoding of the source being parsed.
- * @param node The node to create a string representation of.
- */
-void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node);
-
-#endif
diff --git a/prism/stream.h b/prism/stream.h
new file mode 100644
index 0000000000..678322b442
--- /dev/null
+++ b/prism/stream.h
@@ -0,0 +1,28 @@
+/**
+ * @file stream.h
+ *
+ * Functions for parsing streams.
+ */
+#ifndef PRISM_STREAM_H
+#define PRISM_STREAM_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include "prism/arena.h"
+#include "prism/options.h"
+#include "prism/parser.h"
+#include "prism/source.h"
+
+/**
+ * Parse a stream of Ruby source and return the tree.
+ *
+ * @param parser The out parameter to write the parser to.
+ * @param arena The arena to use for all AST-lifetime allocations.
+ * @param source The source to use, created via pm_source_stream_new.
+ * @param options The optional options to use when parsing.
+ * @returns The AST representing the source.
+ */
+PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t **parser, pm_arena_t *arena, pm_source_t *source, const pm_options_t *options) PRISM_NONNULL(1, 2, 3);
+
+#endif
diff --git a/prism/string_query.c b/prism/string_query.c
new file mode 100644
index 0000000000..ccedaf9c00
--- /dev/null
+++ b/prism/string_query.c
@@ -0,0 +1,166 @@
+#include "prism/string_query.h"
+
+#include "prism/internal/char.h"
+#include "prism/internal/encoding.h"
+
+#include <assert.h>
+#include <string.h>
+
+/** The category of slice returned from pm_slice_type. */
+typedef enum {
+ /** Returned when the given encoding name is invalid. */
+ PM_SLICE_TYPE_ERROR = -1,
+
+ /** Returned when no other types apply to the slice. */
+ PM_SLICE_TYPE_NONE,
+
+ /** Returned when the slice is a valid local variable name. */
+ PM_SLICE_TYPE_LOCAL,
+
+ /** Returned when the slice is a valid constant name. */
+ PM_SLICE_TYPE_CONSTANT,
+
+ /** Returned when the slice is a valid method name. */
+ PM_SLICE_TYPE_METHOD_NAME
+} pm_slice_type_t;
+
+/**
+ * Check that the slice is a valid local variable name or constant.
+ */
+static pm_slice_type_t
+pm_slice_type(const uint8_t *source, size_t length, const char *encoding_name) {
+ // first, get the right encoding object
+ const pm_encoding_t *encoding = pm_encoding_find((const uint8_t *) encoding_name, (const uint8_t *) (encoding_name + strlen(encoding_name)));
+ if (encoding == NULL) return PM_SLICE_TYPE_ERROR;
+
+ // check that there is at least one character
+ if (length == 0) return PM_SLICE_TYPE_NONE;
+
+ size_t width;
+ if ((width = encoding->alpha_char(source, (ptrdiff_t) length)) != 0) {
+ // valid because alphabetical
+ } else if (*source == '_') {
+ // valid because underscore
+ width = 1;
+ } else if ((*source >= 0x80) && ((width = encoding->char_width(source, (ptrdiff_t) length)) > 0)) {
+ // valid because multibyte
+ } else {
+ // invalid because no match
+ return PM_SLICE_TYPE_NONE;
+ }
+
+ // determine the type of the slice based on the first character
+ const uint8_t *end = source + length;
+ pm_slice_type_t result = encoding->isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
+
+ // next, iterate through all of the bytes of the string to ensure that they
+ // are all valid identifier characters
+ source += width;
+
+ while (source < end) {
+ if ((width = encoding->alnum_char(source, end - source)) != 0) {
+ // valid because alphanumeric
+ source += width;
+ } else if (*source == '_') {
+ // valid because underscore
+ source++;
+ } else if ((*source >= 0x80) && ((width = encoding->char_width(source, end - source)) > 0)) {
+ // valid because multibyte
+ source += width;
+ } else {
+ // invalid because no match
+ break;
+ }
+ }
+
+ // accept a ! or ? at the end of the slice as a method name
+ if (*source == '!' || *source == '?' || *source == '=') {
+ source++;
+ result = PM_SLICE_TYPE_METHOD_NAME;
+ }
+
+ // valid if we are at the end of the slice
+ return source == end ? result : PM_SLICE_TYPE_NONE;
+}
+
+/**
+ * Check that the slice is a valid local variable name.
+ */
+pm_string_query_t
+pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) {
+ switch (pm_slice_type(source, length, encoding_name)) {
+ case PM_SLICE_TYPE_ERROR:
+ return PM_STRING_QUERY_ERROR;
+ case PM_SLICE_TYPE_NONE:
+ case PM_SLICE_TYPE_CONSTANT:
+ case PM_SLICE_TYPE_METHOD_NAME:
+ return PM_STRING_QUERY_FALSE;
+ case PM_SLICE_TYPE_LOCAL:
+ return PM_STRING_QUERY_TRUE;
+ }
+
+ assert(false && "unreachable");
+ return PM_STRING_QUERY_FALSE;
+}
+
+/**
+ * Check that the slice is a valid constant name.
+ */
+pm_string_query_t
+pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) {
+ switch (pm_slice_type(source, length, encoding_name)) {
+ case PM_SLICE_TYPE_ERROR:
+ return PM_STRING_QUERY_ERROR;
+ case PM_SLICE_TYPE_NONE:
+ case PM_SLICE_TYPE_LOCAL:
+ case PM_SLICE_TYPE_METHOD_NAME:
+ return PM_STRING_QUERY_FALSE;
+ case PM_SLICE_TYPE_CONSTANT:
+ return PM_STRING_QUERY_TRUE;
+ }
+
+ assert(false && "unreachable");
+ return PM_STRING_QUERY_FALSE;
+}
+
+/**
+ * Check that the slice is a valid method name.
+ */
+pm_string_query_t
+pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) {
+#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
+#define C1(c) (*source == c)
+#define C2(s) (memcmp(source, s, 2) == 0)
+#define C3(s) (memcmp(source, s, 3) == 0)
+
+ switch (pm_slice_type(source, length, encoding_name)) {
+ case PM_SLICE_TYPE_ERROR:
+ return PM_STRING_QUERY_ERROR;
+ case PM_SLICE_TYPE_NONE:
+ break;
+ case PM_SLICE_TYPE_LOCAL:
+ // numbered parameters are not valid method names
+ return B((length != 2) || (source[0] != '_') || (source[1] == '0') || !pm_char_is_decimal_digit(source[1]));
+ case PM_SLICE_TYPE_CONSTANT:
+ // all constants are valid method names
+ case PM_SLICE_TYPE_METHOD_NAME:
+ // all method names are valid method names
+ return PM_STRING_QUERY_TRUE;
+ }
+
+ switch (length) {
+ case 1:
+ return B(C1('&') || C1('`') || C1('!') || C1('^') || C1('>') || C1('<') || C1('-') || C1('%') || C1('|') || C1('+') || C1('/') || C1('*') || C1('~'));
+ case 2:
+ return B(C2("!=") || C2("!~") || C2("[]") || C2("==") || C2("=~") || C2(">=") || C2(">>") || C2("<=") || C2("<<") || C2("**"));
+ case 3:
+ return B(C3("===") || C3("<=>") || C3("[]="));
+ default:
+ return PM_STRING_QUERY_FALSE;
+ }
+
+#undef B
+#undef C1
+#undef C2
+#undef C3
+}
diff --git a/prism/string_query.h b/prism/string_query.h
new file mode 100644
index 0000000000..6ee1a9d9b6
--- /dev/null
+++ b/prism/string_query.h
@@ -0,0 +1,63 @@
+/**
+ * @file string_query.h
+ *
+ * Functions for querying properties of strings, such as whether they are valid
+ * local variable names, constant names, or method names.
+ */
+#ifndef PRISM_STRING_QUERY_H
+#define PRISM_STRING_QUERY_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * Represents the results of a slice query.
+ */
+typedef enum {
+ /** Returned if the encoding given to a slice query was invalid. */
+ PM_STRING_QUERY_ERROR = -1,
+
+ /** Returned if the result of the slice query is false. */
+ PM_STRING_QUERY_FALSE,
+
+ /** Returned if the result of the slice query is true. */
+ PM_STRING_QUERY_TRUE
+} pm_string_query_t;
+
+/**
+ * Check that the slice is a valid local variable name.
+ *
+ * @param source The source to check.
+ * @param length The length of the source.
+ * @param encoding_name The name of the encoding of the source.
+ * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
+ * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
+ */
+PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3);
+
+/**
+ * Check that the slice is a valid constant name.
+ *
+ * @param source The source to check.
+ * @param length The length of the source.
+ * @param encoding_name The name of the encoding of the source.
+ * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
+ * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
+ */
+PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3);
+
+/**
+ * Check that the slice is a valid method name.
+ *
+ * @param source The source to check.
+ * @param length The length of the source.
+ * @param encoding_name The name of the encoding of the source.
+ * @returns PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
+ * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
+ */
+PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name) PRISM_NONNULL(1, 3);
+
+#endif
diff --git a/prism/stringy.c b/prism/stringy.c
new file mode 100644
index 0000000000..d6f4c4a777
--- /dev/null
+++ b/prism/stringy.c
@@ -0,0 +1,91 @@
+#include "prism/internal/stringy.h"
+
+#include "prism/internal/allocator.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * 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
+ };
+}
+
+/**
+ * Compare the underlying lengths and bytes of two strings. Returns 0 if the
+ * strings are equal, a negative number if the left string is less than the
+ * right string, and a positive number if the left string is greater than the
+ * right string.
+ */
+int
+pm_string_compare(const pm_string_t *left, const pm_string_t *right) {
+ size_t left_length = pm_string_length(left);
+ size_t right_length = pm_string_length(right);
+
+ if (left_length < right_length) {
+ return -1;
+ } else if (left_length > right_length) {
+ return 1;
+ }
+
+ return memcmp(pm_string_source(left), pm_string_source(right), left_length);
+}
+
+/**
+ * Returns the length associated with the string.
+ */
+size_t
+pm_string_length(const pm_string_t *string) {
+ return string->length;
+}
+
+/**
+ * Returns the start pointer associated with the string.
+ */
+const uint8_t *
+pm_string_source(const pm_string_t *string) {
+ return string->source;
+}
+
+/**
+ * Free the associated memory of the given string.
+ */
+void
+pm_string_cleanup(pm_string_t *string) {
+ if (string->type == PM_STRING_OWNED) {
+ xfree_sized((void *) string->source, string->length);
+ }
+}
diff --git a/prism/stringy.h b/prism/stringy.h
new file mode 100644
index 0000000000..0d64387ac3
--- /dev/null
+++ b/prism/stringy.h
@@ -0,0 +1,72 @@
+/**
+ * @file stringy.h
+ *
+ * A generic string type that can have various ownership semantics.
+ */
+#ifndef PRISM_STRINGY_H
+#define PRISM_STRINGY_H
+
+#include "prism/compiler/exported.h"
+#include "prism/compiler/nonnull.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * 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 internally. */
+ PM_STRING_OWNED
+ } type;
+} pm_string_t;
+
+/**
+ * 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.
+ */
+PRISM_EXPORTED_FUNCTION void pm_string_constant_init(pm_string_t *string, const char *source, size_t length) PRISM_NONNULL(1);
+
+/**
+ * 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.
+ */
+PRISM_EXPORTED_FUNCTION void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) PRISM_NONNULL(1, 2);
+
+/**
+ * Returns the length associated with the string.
+ *
+ * @param string The string to get the length of.
+ * @returns The length of the string.
+ */
+PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string) PRISM_NONNULL(1);
+
+/**
+ * Returns the start pointer associated with the string.
+ *
+ * @param string The string to get the start pointer of.
+ * @returns The start pointer of the string.
+ */
+PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string) PRISM_NONNULL(1);
+
+#endif
diff --git a/prism/strncasecmp.c b/prism/strncasecmp.c
new file mode 100644
index 0000000000..a373cad6d7
--- /dev/null
+++ b/prism/strncasecmp.c
@@ -0,0 +1,37 @@
+#include "prism/internal/strncasecmp.h"
+
+#include "prism/compiler/inline.h"
+
+/**
+ * A locale-insensitive version of `tolower(3)`
+ */
+static PRISM_INLINE int
+pm_tolower(int c) {
+ if ('A' <= c && c <= 'Z') {
+ return c | 0x20;
+ }
+ return c;
+}
+
+/**
+ * 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 = pm_tolower(string1[offset]) - pm_tolower(string2[offset])) != 0) return difference;
+ offset++;
+ }
+
+ return difference;
+}
diff --git a/prism/strpbrk.c b/prism/strpbrk.c
new file mode 100644
index 0000000000..383707eb72
--- /dev/null
+++ b/prism/strpbrk.c
@@ -0,0 +1,439 @@
+#include "prism/internal/strpbrk.h"
+
+#include "prism/compiler/accel.h"
+#include "prism/compiler/inline.h"
+#include "prism/compiler/unused.h"
+
+#include "prism/internal/bit.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/parser.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+/**
+ * Add an invalid multibyte character error to the parser.
+ */
+static PRISM_INLINE void
+pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->error_list, start, length, PM_ERR_INVALID_MULTIBYTE_CHARACTER, parser->start[start]);
+}
+
+/**
+ * Set the explicit encoding for the parser to the current encoding.
+ */
+static PRISM_INLINE void
+pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, uint32_t start, uint32_t length) {
+ if (parser->explicit_encoding != NULL) {
+ if (parser->explicit_encoding == parser->encoding) {
+ // Okay, we already locked to this encoding.
+ } else if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
+ // Not okay, we already found a Unicode escape sequence and this
+ // conflicts.
+ pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->error_list, start, length, PM_ERR_MIXED_ENCODING, parser->encoding->name);
+ } else {
+ // Should not be anything else.
+ assert(false && "unreachable");
+ }
+ }
+
+ parser->explicit_encoding = parser->encoding;
+}
+
+/**
+ * Scan forward through ASCII bytes looking for a byte that is in the given
+ * charset. Returns true if a match was found, storing its offset in *index.
+ * Returns false if no match was found, storing the number of ASCII bytes
+ * consumed in *index (so the caller can skip past them).
+ *
+ * All charset characters must be ASCII (< 0x80). The scanner stops at non-ASCII
+ * bytes, returning control to the caller's encoding-aware loop.
+ *
+ * Up to three optimized implementations are selected at compile time, with a
+ * no-op fallback for unsupported platforms:
+ * 1. NEON — processes 16 bytes per iteration on aarch64.
+ * 2. SSSE3 — processes 16 bytes per iteration on x86-64.
+ * 3. SWAR — little-endian fallback, processes 8 bytes per iteration.
+ */
+
+#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR)
+
+/**
+ * Update the cached strpbrk lookup tables if the charset has changed. The
+ * parser caches the last charset's precomputed tables so that repeated calls
+ * with the same breakpoints (the common case during string/regex/list lexing)
+ * skip table construction entirely.
+ *
+ * Builds three structures:
+ * - low_lut/high_lut: nibble-based lookup tables for SIMD matching (NEON/SSSE3)
+ * - table: 256-bit bitmap for scalar fallback matching (all platforms)
+ */
+static PRISM_INLINE void
+pm_strpbrk_cache_update(pm_parser_t *parser, const uint8_t *charset) {
+ // The cache key is the full charset buffer (PM_STRPBRK_CACHE_SIZE bytes).
+ // Since it is always NUL-padded, a fixed-size comparison covers both
+ // content and length.
+ if (memcmp(parser->strpbrk_cache.charset, charset, sizeof(parser->strpbrk_cache.charset)) == 0) return;
+
+ memset(parser->strpbrk_cache.low_lut, 0, sizeof(parser->strpbrk_cache.low_lut));
+ memset(parser->strpbrk_cache.high_lut, 0, sizeof(parser->strpbrk_cache.high_lut));
+ memset(parser->strpbrk_cache.table, 0, sizeof(parser->strpbrk_cache.table));
+
+ // Always include NUL in the tables. The slow path uses strchr, which
+ // always matches NUL (it finds the C string terminator), so NUL is
+ // effectively always a breakpoint. Replicating that here lets the fast
+ // scanner handle NUL at full speed instead of bailing to the slow path.
+ parser->strpbrk_cache.low_lut[0x00] |= (uint8_t) (1 << 0);
+ parser->strpbrk_cache.high_lut[0x00] = (uint8_t) (1 << 0);
+ parser->strpbrk_cache.table[0] |= (uint64_t) 1;
+
+ size_t charset_len = 0;
+ for (const uint8_t *c = charset; *c != '\0'; c++) {
+ parser->strpbrk_cache.low_lut[*c & 0x0F] |= (uint8_t) (1 << (*c >> 4));
+ parser->strpbrk_cache.high_lut[*c >> 4] = (uint8_t) (1 << (*c >> 4));
+ parser->strpbrk_cache.table[*c >> 6] |= (uint64_t) 1 << (*c & 0x3F);
+ charset_len++;
+ }
+
+ // Store the new charset key, NUL-padded to the full buffer size.
+ memcpy(parser->strpbrk_cache.charset, charset, charset_len + 1);
+ memset(parser->strpbrk_cache.charset + charset_len + 1, 0, sizeof(parser->strpbrk_cache.charset) - charset_len - 1);
+}
+
+#endif
+
+#if defined(PRISM_HAS_NEON)
+#include <arm_neon.h>
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) {
+ pm_strpbrk_cache_update(parser, charset);
+
+ uint8x16_t low_lut = vld1q_u8(parser->strpbrk_cache.low_lut);
+ uint8x16_t high_lut = vld1q_u8(parser->strpbrk_cache.high_lut);
+ uint8x16_t mask_0f = vdupq_n_u8(0x0F);
+ uint8x16_t mask_80 = vdupq_n_u8(0x80);
+
+ size_t idx = 0;
+
+ while (idx + 16 <= maximum) {
+ uint8x16_t v = vld1q_u8(source + idx);
+
+ // If any byte has the high bit set, we have non-ASCII data.
+ // Return to let the caller's encoding-aware loop handle it.
+ if (vmaxvq_u8(vandq_u8(v, mask_80)) != 0) break;
+
+ uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
+ uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
+ uint8x16_t matched = vtstq_u8(lo_class, hi_class);
+
+ if (vmaxvq_u8(matched) == 0) {
+ idx += 16;
+ continue;
+ }
+
+ // Find the position of the first matching byte.
+ uint64_t lo64 = vgetq_lane_u64(vreinterpretq_u64_u8(matched), 0);
+ if (lo64 != 0) {
+ *index = idx + pm_ctzll(lo64) / 8;
+ return true;
+ }
+ uint64_t hi64 = vgetq_lane_u64(vreinterpretq_u64_u8(matched), 1);
+ *index = idx + 8 + pm_ctzll(hi64) / 8;
+ return true;
+ }
+
+ // Scalar tail for remaining < 16 ASCII bytes.
+ while (idx < maximum && source[idx] < 0x80) {
+ uint8_t byte = source[idx];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx;
+ return true;
+ }
+ idx++;
+ }
+
+ *index = idx;
+ return false;
+}
+
+#elif defined(PRISM_HAS_SSSE3)
+#include <tmmintrin.h>
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) {
+ pm_strpbrk_cache_update(parser, charset);
+
+ __m128i low_lut = _mm_loadu_si128((const __m128i *) parser->strpbrk_cache.low_lut);
+ __m128i high_lut = _mm_loadu_si128((const __m128i *) parser->strpbrk_cache.high_lut);
+ __m128i mask_0f = _mm_set1_epi8(0x0F);
+
+ size_t idx = 0;
+
+ while (idx + 16 <= maximum) {
+ __m128i v = _mm_loadu_si128((const __m128i *) (source + idx));
+
+ // If any byte has the high bit set, stop.
+ if (_mm_movemask_epi8(v) != 0) break;
+
+ // Nibble-based classification using pshufb (SSSE3), same as NEON
+ // vqtbl1q_u8. A byte matches iff (low_lut[lo_nib] & high_lut[hi_nib]) != 0.
+ __m128i lo_class = _mm_shuffle_epi8(low_lut, _mm_and_si128(v, mask_0f));
+ __m128i hi_class = _mm_shuffle_epi8(high_lut, _mm_and_si128(_mm_srli_epi16(v, 4), mask_0f));
+ __m128i matched = _mm_and_si128(lo_class, hi_class);
+
+ // Check if any byte matched.
+ int mask = _mm_movemask_epi8(_mm_cmpeq_epi8(matched, _mm_setzero_si128()));
+
+ if (mask == 0xFFFF) {
+ // All bytes were zero — no match in this chunk.
+ idx += 16;
+ continue;
+ }
+
+ // Find the first matching byte (first non-zero in matched).
+ *index = idx + pm_ctzll((uint64_t) (~mask & 0xFFFF));
+ return true;
+ }
+
+ // Scalar tail.
+ while (idx < maximum && source[idx] < 0x80) {
+ uint8_t byte = source[idx];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx;
+ return true;
+ }
+ idx++;
+ }
+
+ *index = idx;
+ return false;
+}
+
+#elif defined(PRISM_HAS_SWAR)
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(pm_parser_t *parser, const uint8_t *source, size_t maximum, const uint8_t *charset, size_t *index) {
+ pm_strpbrk_cache_update(parser, charset);
+
+ static const uint64_t highs = 0x8080808080808080ULL;
+ size_t idx = 0;
+
+ while (idx + 8 <= maximum) {
+ uint64_t word;
+ memcpy(&word, source + idx, 8);
+
+ // Bail on any non-ASCII byte.
+ if (word & highs) break;
+
+ // Check each byte against the charset table.
+ for (size_t j = 0; j < 8; j++) {
+ uint8_t byte = source[idx + j];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx + j;
+ return true;
+ }
+ }
+
+ idx += 8;
+ }
+
+ // Scalar tail.
+ while (idx < maximum && source[idx] < 0x80) {
+ uint8_t byte = source[idx];
+ if (parser->strpbrk_cache.table[byte >> 6] & ((uint64_t) 1 << (byte & 0x3F))) {
+ *index = idx;
+ return true;
+ }
+ idx++;
+ }
+
+ *index = idx;
+ return false;
+}
+
+#else
+
+static PRISM_INLINE bool
+scan_strpbrk_ascii(PRISM_UNUSED pm_parser_t *parser, PRISM_UNUSED const uint8_t *source, PRISM_UNUSED size_t maximum, PRISM_UNUSED const uint8_t *charset, size_t *index) {
+ *index = 0;
+ return false;
+}
+
+#endif
+
+/**
+ * This is the default path.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ while (index < maximum) {
+ if (strchr((const char *) charset, source[index]) != NULL) {
+ return source + index;
+ }
+
+ if (source[index] < 0x80) {
+ index++;
+ } else {
+ size_t width = pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index));
+
+ if (width > 0) {
+ index += width;
+ } else if (!validate) {
+ index++;
+ } else {
+ // At this point we know we have an invalid multibyte character.
+ // We'll walk forward as far as we can until we find the next
+ // valid character so that we don't spam the user with a ton of
+ // the same kind of error.
+ const size_t start = index;
+
+ do {
+ index++;
+ } while (index < maximum && pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
+
+ pm_strpbrk_invalid_multibyte_character(parser, (uint32_t) ((source + start) - parser->start), (uint32_t) (index - start));
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * This is the path when the encoding is ASCII-8BIT.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ while (index < maximum) {
+ if (strchr((const char *) charset, source[index]) != NULL) {
+ return source + index;
+ }
+
+ if (validate && source[index] >= 0x80) pm_strpbrk_explicit_encoding_set(parser, (uint32_t) (source - parser->start), 1);
+ index++;
+ }
+
+ return NULL;
+}
+
+/**
+ * This is the slow path that does care about the encoding.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ const pm_encoding_t *encoding = parser->encoding;
+
+ while (index < maximum) {
+ if (strchr((const char *) charset, source[index]) != NULL) {
+ return source + index;
+ }
+
+ if (source[index] < 0x80) {
+ index++;
+ } else {
+ size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
+ if (validate) pm_strpbrk_explicit_encoding_set(parser, (uint32_t) (source - parser->start), (uint32_t) width);
+
+ if (width > 0) {
+ index += width;
+ } else if (!validate) {
+ index++;
+ } else {
+ // At this point we know we have an invalid multibyte character.
+ // We'll walk forward as far as we can until we find the next
+ // valid character so that we don't spam the user with a ton of
+ // the same kind of error.
+ const size_t start = index;
+
+ do {
+ index++;
+ } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
+
+ pm_strpbrk_invalid_multibyte_character(parser, (uint32_t) ((source + start) - parser->start), (uint32_t) (index - start));
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * This is the fast path that does not care about the encoding because we know
+ * the encoding only supports single-byte characters.
+ */
+static PRISM_INLINE const uint8_t *
+pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t index, size_t maximum, bool validate) {
+ const pm_encoding_t *encoding = parser->encoding;
+
+ while (index < maximum) {
+ if (strchr((const char *) charset, source[index]) != NULL) {
+ return source + index;
+ }
+
+ if (source[index] < 0x80 || !validate) {
+ index++;
+ } else {
+ size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
+ pm_strpbrk_explicit_encoding_set(parser, (uint32_t) (source - parser->start), (uint32_t) width);
+
+ if (width > 0) {
+ index += width;
+ } else {
+ // At this point we know we have an invalid multibyte character.
+ // We'll walk forward as far as we can until we find the next
+ // valid character so that we don't spam the user with a ton of
+ // the same kind of error.
+ const size_t start = index;
+
+ do {
+ index++;
+ } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
+
+ pm_strpbrk_invalid_multibyte_character(parser, (uint32_t) ((source + start) - parser->start), (uint32_t) (index - start));
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Here we have rolled our own version of strpbrk. The standard library strpbrk
+ * has undefined behavior when the source string is not null-terminated. We want
+ * to support strings that are not null-terminated because pm_parse does not
+ * have the contract that the string is null-terminated. (This is desirable
+ * because it means the extension can call pm_parse with the result of a call to
+ * mmap).
+ *
+ * The standard library strpbrk also does not support passing a maximum length
+ * to search. We want to support this for the reason mentioned above, but we
+ * also don't want it to stop on null bytes. Ruby actually allows null bytes
+ * within strings, comments, regular expressions, etc. So we need to be able to
+ * skip past them.
+ *
+ * Finally, we want to support encodings wherein the charset could contain
+ * characters that are trailing bytes of multi-byte characters. For example, in
+ * Shift_JIS, the backslash character can be a trailing byte. In that case we
+ * need to take a slower path and iterate one multi-byte character at a time.
+ */
+const uint8_t *
+pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate) {
+ if (length <= 0) return NULL;
+
+ size_t maximum = (size_t) length;
+ size_t index = 0;
+ if (scan_strpbrk_ascii(parser, source, maximum, charset, &index)) return source + index;
+
+ if (!parser->encoding_changed) {
+ return pm_strpbrk_utf8(parser, source, charset, index, maximum, validate);
+ } else if (parser->encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
+ return pm_strpbrk_ascii_8bit(parser, source, charset, index, maximum, validate);
+ } else if (parser->encoding->multibyte) {
+ return pm_strpbrk_multi_byte(parser, source, charset, index, maximum, validate);
+ } else {
+ return pm_strpbrk_single_byte(parser, source, charset, index, maximum, validate);
+ }
+}
diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb
index 23af8886a7..41d7165930 100644
--- a/prism/templates/ext/prism/api_node.c.erb
+++ b/prism/templates/ext/prism/api_node.c.erb
@@ -1,5 +1,9 @@
#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
#include "prism/extension.h"
+#include "prism/internal/allocator.h"
+#include "prism/internal/arena.h"
+
+#include <assert.h>
extern VALUE rb_cPrism;
extern VALUE rb_cPrismNode;
@@ -12,25 +16,20 @@ static VALUE rb_cPrism<%= node.name %>;
<%- end -%>
static VALUE
-pm_location_new(const pm_parser_t *parser, const uint8_t *start, const uint8_t *end, VALUE source, bool freeze) {
+pm_location_new(const uint32_t start, const uint32_t length, VALUE source, bool freeze) {
if (freeze) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(start - parser->start),
- LONG2FIX(end - start)
- };
-
+ VALUE location_argv[] = { source, LONG2FIX(start), LONG2FIX(length) };
return rb_obj_freeze(rb_class_new_instance(3, location_argv, rb_cPrismLocation));
} else {
- uint64_t value = ((((uint64_t) (start - parser->start)) << 32) | ((uint32_t) (end - start)));
+ uint64_t value = ((((uint64_t) start) << 32) | ((uint64_t) length));
return ULL2NUM(value);
}
}
VALUE
pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source, bool freeze) {
- ID type = rb_intern(pm_token_type_name(token->type));
- VALUE location = pm_location_new(parser, token->start, token->end, source, freeze);
+ ID type = rb_intern(pm_token_type(token->type));
+ VALUE location = pm_location_new((uint32_t) (token->start - pm_parser_start(parser)), (uint32_t) (token->end - token->start), source, freeze);
VALUE slice = rb_enc_str_new((const char *) token->start, token->end - token->start, encoding);
if (freeze) rb_obj_freeze(slice);
@@ -79,19 +78,25 @@ pm_integer_new(const pm_integer_t *integer) {
// Create a Prism::Source object from the given parser, after pm_parse() was called.
VALUE
pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze) {
- VALUE source_string = rb_enc_str_new((const char *) parser->start, parser->end - parser->start, encoding);
+ const uint8_t *start = pm_parser_start(parser);
+ VALUE source_string = rb_enc_str_new((const char *) start, pm_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, ULONG2NUM(parser->newline_list.offsets[index]));
- }
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ VALUE offsets;
if (freeze) {
+ offsets = rb_ary_new_capa(line_offsets->size);
+ for (size_t index = 0; index < line_offsets->size; index++) {
+ rb_ary_push(offsets, ULONG2NUM(line_offsets->offsets[index]));
+ }
+
rb_obj_freeze(source_string);
rb_obj_freeze(offsets);
+ } else {
+ offsets = rb_str_new((const char *) line_offsets->offsets, line_offsets->size * sizeof(uint32_t));
}
- VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(parser->start_line), offsets);
+ VALUE source = rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets);
if (freeze) rb_obj_freeze(source);
return source;
@@ -104,8 +109,8 @@ typedef struct pm_node_stack_node {
} pm_node_stack_node_t;
static void
-pm_node_stack_push(pm_node_stack_node_t **stack, const pm_node_t *visit) {
- pm_node_stack_node_t *node = xmalloc(sizeof(pm_node_stack_node_t));
+pm_node_stack_push(pm_arena_t *arena, pm_node_stack_node_t **stack, const pm_node_t *visit) {
+ pm_node_stack_node_t *node = (pm_node_stack_node_t *) pm_arena_alloc(arena, sizeof(pm_node_stack_node_t), PRISM_ALIGNOF(pm_node_stack_node_t));
node->prev = *stack;
node->visit = visit;
node->visited = false;
@@ -118,32 +123,40 @@ pm_node_stack_pop(pm_node_stack_node_t **stack) {
const pm_node_t *visit = current->visit;
*stack = current->prev;
- xfree(current);
return visit;
}
-VALUE
-pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze) {
- VALUE constants = rb_ary_new_capa(parser->constant_pool.size);
-
- for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
- pm_constant_t *constant = &parser->constant_pool.constants[index];
- int state = 0;
+typedef struct {
+ VALUE constants;
+ rb_encoding *encoding;
+} pm_ast_constants_each_data_t;
- VALUE string = rb_enc_str_new((const char *) constant->start, constant->length, encoding);
- VALUE value = rb_protect(rb_str_intern, string, &state);
+static void
+pm_ast_constants_each(const pm_constant_t *constant, void *data) {
+ pm_ast_constants_each_data_t *constants_data = (pm_ast_constants_each_data_t *) data;
+ int state = 0;
- if (state != 0) {
- value = ID2SYM(rb_intern_const("?"));
- rb_set_errinfo(Qnil);
- }
+ VALUE string = rb_enc_str_new((const char *) pm_constant_start(constant), pm_constant_length(constant), constants_data->encoding);
+ VALUE value = rb_protect(rb_str_intern, string, &state);
- rb_ary_push(constants, value);
+ if (state != 0) {
+ value = ID2SYM(rb_intern_const("?"));
+ rb_set_errinfo(Qnil);
}
+ rb_ary_push(constants_data->constants, value);
+}
+
+VALUE
+pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze) {
+ VALUE constants = rb_ary_new_capa(pm_parser_constants_size(parser));
+ pm_ast_constants_each_data_t constants_data = { .constants = constants, .encoding = encoding };
+ pm_parser_constants_each(parser, pm_ast_constants_each, &constants_data);
+
+ pm_arena_t *node_arena = pm_arena_new();
pm_node_stack_node_t *node_stack = NULL;
- pm_node_stack_push(&node_stack, node);
+ pm_node_stack_push(node_arena, &node_stack, node);
VALUE value_stack = rb_ary_new();
while (node_stack != NULL) {
@@ -166,10 +179,10 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
<%- node.fields.each do |field| -%>
<%- case field -%>
<%- when Prism::Template::NodeField, Prism::Template::OptionalNodeField -%>
- pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>);
+ pm_node_stack_push(node_arena, &node_stack, (pm_node_t *) cast-><%= field.name %>);
<%- when Prism::Template::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]);
+ pm_node_stack_push(node_arena, &node_stack, (pm_node_t *) cast-><%= field.name %>.nodes[index]);
}
<%- end -%>
<%- end -%>
@@ -200,7 +213,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
argv[1] = ULONG2NUM(node->node_id);
// location
- argv[2] = pm_location_new(parser, node->location.start, node->location.end, source, freeze);
+ argv[2] = pm_location_new(node->location.start, node->location.length, source, freeze);
// flags
argv[3] = ULONG2NUM(node->flags);
@@ -237,10 +250,10 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
if (freeze) rb_obj_freeze(argv[<%= index %>]);
<%- when Prism::Template::LocationField -%>
#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = pm_location_new(parser, cast-><%= field.name %>.start, cast-><%= field.name %>.end, source, freeze);
+ argv[<%= index %>] = pm_location_new(cast-><%= field.name %>.start, cast-><%= field.name %>.length, source, freeze);
<%- when Prism::Template::OptionalLocationField -%>
#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = cast-><%= field.name %>.start == NULL ? Qnil : pm_location_new(parser, cast-><%= field.name %>.start, cast-><%= field.name %>.end, source, freeze);
+ argv[<%= index %>] = cast-><%= field.name %>.length == 0 ? Qnil : pm_location_new(cast-><%= field.name %>.start, cast-><%= field.name %>.length, source, freeze);
<%- when Prism::Template::UInt8Field -%>
#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
argv[<%= index %>] = UINT2NUM(cast-><%= field.name %>);
@@ -271,6 +284,7 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
}
}
+ pm_arena_free(node_arena);
return rb_ary_pop(value_stack);
}
diff --git a/prism/templates/include/prism/ast.h.erb b/prism/templates/include/prism/ast.h.erb
index 751c0b43c2..3b3be25e76 100644
--- a/prism/templates/include/prism/ast.h.erb
+++ b/prism/templates/include/prism/ast.h.erb
@@ -2,16 +2,20 @@
* @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_integer.h"
-#include "prism/util/pm_string.h"
+#include "prism/compiler/align.h"
+#include "prism/compiler/exported.h"
+
+#include "prism/arena.h"
+#include "prism/constant_pool.h"
+#include "prism/integer.h"
+#include "prism/stringy.h"
-#include <assert.h>
#include <stddef.h>
#include <stdint.h>
@@ -20,7 +24,7 @@
*/
typedef enum pm_token_type {
<%- tokens.each do |token| -%>
- /** <%= token.comment %> */
+ /** <%= Prism::Template::Doxygen.verbatim(token.comment) %> */
PM_TOKEN_<%= token.name %><%= " = #{token.value}" if token.value %>,
<%- end -%>
@@ -44,15 +48,28 @@ typedef struct {
} pm_token_t;
/**
- * This represents a range of bytes in the source string to which a node or
- * token corresponds.
+ * Returns a string representation of the given token type.
+ *
+ * @param token_type The type of the token to get the string representation of.
+ * @returns A string representation of the given token type. This is meant for
+ * debugging purposes and is not guaranteed to be stable across versions.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_token_type(pm_token_type_t token_type);
+
+/**
+ * This struct represents a slice in the source code, defined by an offset and
+ * a length. Note that we have confirmation that we can represent all locations
+ * within Ruby source files using 32-bit integers per:
+ *
+ * https://bugs.ruby-lang.org/issues/20488#note-1
+ *
*/
typedef struct {
- /** A pointer to the start location of the range in the source. */
- const uint8_t *start;
+ /** The offset of the location from the start of the source. */
+ uint32_t start;
- /** A pointer to the end location of the range in the source. */
- const uint8_t *end;
+ /** The length of the location. */
+ uint32_t length;
} pm_location_t;
struct pm_node;
@@ -104,29 +121,13 @@ static const pm_node_flags_t PM_NODE_FLAG_NEWLINE = 0x1;
static const pm_node_flags_t PM_NODE_FLAG_STATIC_LITERAL = 0x2;
/**
- * 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.
+ * existed in the original grammar and ripper, but it is not a 1:1 mapping.
*/
pm_node_type_t type;
@@ -143,11 +144,46 @@ typedef struct pm_node {
uint32_t node_id;
/**
- * This is the location of the node in the source. It's a range of bytes
+ * This is the location of the node in the source. It is a range of bytes
* containing a start and an end.
*/
pm_location_t location;
} pm_node_t;
+
+/**
+ * Cast the given node to the base pm_node_t type.
+ */
+#define PM_NODE_UPCAST(node_) ((pm_node_t *) (node_))
+
+/**
+ * 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 the flags associated with the given node.
+ */
+#define PM_NODE_FLAGS(node_) (PM_NODE_UPCAST(node_)->flags)
+
+/**
+ * Return true if the given flag is set on the given node.
+ */
+#define PM_NODE_FLAG_P(node_, flag_) ((PM_NODE_FLAGS(node_) & (flag_)) != 0)
+
+/**
+ * The alignment required for a child node within a parent node.
+ */
+#ifdef _MSC_VER
+#define PM_NODE_ALIGNAS __declspec(align(8))
+#else
+#define PM_NODE_ALIGNAS PRISM_ALIGNAS(PRISM_ALIGNOF(void *))
+#endif
<%- nodes.each do |node| -%>
/**
@@ -170,7 +206,6 @@ typedef struct pm_node {
typedef struct pm_<%= node.human %> {
/** The embedded base node. */
pm_node_t base;
-
<%- node.fields.each do |field| -%>
/**
@@ -183,7 +218,7 @@ typedef struct pm_<%= node.human %> {
<%- end -%>
*/
<%= case field
- when Prism::Template::NodeField, Prism::Template::OptionalNodeField then "struct #{field.c_type} *#{field.name}"
+ when Prism::Template::NodeField, Prism::Template::OptionalNodeField then "PM_NODE_ALIGNAS struct #{field.c_type} *#{field.name}"
when Prism::Template::NodeListField then "struct pm_node_list #{field.name}"
when Prism::Template::ConstantField, Prism::Template::OptionalConstantField then "pm_constant_id_t #{field.name}"
when Prism::Template::ConstantListField then "pm_constant_id_list_t #{field.name}"
@@ -210,8 +245,27 @@ typedef enum pm_<%= flag.human %> {
/** <%= value.comment %> */
PM_<%= flag.human.upcase %>_<%= value.name %> = <%= 1 << (index + Prism::Template::COMMON_FLAGS_COUNT) %>,
<%- end -%>
+
+ PM_<%= flag.human.upcase %>_LAST,
} pm_<%= flag.human %>_t;
<%- end -%>
+<%- nodes.each do |node| -%>
+
+<%- params = node.fields.map(&:c_param) -%>
+/**
+ * Allocate and initialize a new <%= node.name %> node.
+ *
+ * @param arena The arena to allocate from.
+ * @param node_id The unique identifier for this node.
+ * @param flags The flags for this node.
+ * @param location The location of this node in the source.
+<%- node.fields.each do |field| -%>
+ * @param <%= field.name %> <%= field.comment ? Prism::Template::Doxygen.verbatim(field.comment.lines.first.strip) : "The #{field.name} field." %>
+<%- end -%>
+ * @returns The newly allocated and initialized node.
+ */
+PRISM_EXPORTED_FUNCTION pm_<%= node.human %>_t * pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>);
+<%- end -%>
/**
* When we're serializing to Java, we want to skip serializing the location
diff --git a/prism/templates/include/prism/diagnostic.h.erb b/prism/templates/include/prism/diagnostic.h.erb
deleted file mode 100644
index 07bbc8fae7..0000000000
--- a/prism/templates/include/prism/diagnostic.h.erb
+++ /dev/null
@@ -1,130 +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>
-
-/**
- * The diagnostic IDs of all of the diagnostics, used to communicate the types
- * of errors between the parser and the user.
- */
-typedef enum {
- // These are the error diagnostics.
- <%- errors.each do |error| -%>
- PM_ERR_<%= error.name %>,
- <%- end -%>
-
- // These are the warning diagnostics.
- <%- warnings.each do |warning| -%>
- PM_WARN_<%= warning.name %>,
- <%- end -%>
-} pm_diagnostic_id_t;
-
-/**
- * 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 ID of the diagnostic. */
- pm_diagnostic_id_t diag_id;
-
- /** 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;
-
- /**
- * The level of the diagnostic, see `pm_error_level_t` and
- * `pm_warning_level_t` for possible values.
- */
- uint8_t level;
-} pm_diagnostic_t;
-
-/**
- * The levels of errors generated during parsing.
- */
-typedef enum {
- /** For errors that should raise a syntax error. */
- PM_ERROR_LEVEL_SYNTAX = 0,
-
- /** For errors that should raise an argument error. */
- PM_ERROR_LEVEL_ARGUMENT = 1,
-
- /** For errors that should raise a load error. */
- PM_ERROR_LEVEL_LOAD = 2
-} pm_error_level_t;
-
-/**
- * The levels of warnings generated during parsing.
- */
-typedef enum {
- /** For warnings which should be emitted if $VERBOSE != nil. */
- PM_WARNING_LEVEL_DEFAULT = 0,
-
- /** For warnings which should be emitted if $VERBOSE == true. */
- PM_WARNING_LEVEL_VERBOSE = 1
-} pm_warning_level_t;
-
-/**
- * Get the human-readable name of the given diagnostic ID.
- *
- * @param diag_id The diagnostic ID.
- * @return The human-readable name of the diagnostic ID.
- */
-const char * pm_diagnostic_id_human(pm_diagnostic_id_t diag_id);
-
-/**
- * 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/templates/include/prism/internal/diagnostic.h.erb b/prism/templates/include/prism/internal/diagnostic.h.erb
new file mode 100644
index 0000000000..ee44ff5382
--- /dev/null
+++ b/prism/templates/include/prism/internal/diagnostic.h.erb
@@ -0,0 +1,60 @@
+#ifndef PRISM_INTERNAL_DIAGNOSTIC_H
+#define PRISM_INTERNAL_DIAGNOSTIC_H
+
+#include "prism/internal/list.h"
+
+#include "prism/arena.h"
+#include "prism/diagnostic.h"
+
+/*
+ * The diagnostic IDs of all of the diagnostics, used to communicate the types
+ * of errors between the parser and the user.
+ */
+typedef enum {
+ /* These are the error diagnostics. */
+ <%- errors.each do |error| -%>
+ PM_ERR_<%= error.name %>,
+ <%- end -%>
+
+ /* These are the warning diagnostics. */
+ <%- warnings.each do |warning| -%>
+ PM_WARN_<%= warning.name %>,
+ <%- end -%>
+} pm_diagnostic_id_t;
+
+/*
+ * This struct represents a diagnostic generated during parsing.
+ */
+struct pm_diagnostic_t {
+ /* The embedded base node. */
+ pm_list_node_t node;
+
+ /* The location of the diagnostic in the source. */
+ pm_location_t location;
+
+ /* The ID of the diagnostic. */
+ pm_diagnostic_id_t diag_id;
+
+ /* The message associated with the diagnostic. */
+ const char *message;
+
+ /*
+ * The level of the diagnostic, see `pm_error_level_t` and
+ * `pm_warning_level_t` for possible values.
+ */
+ uint8_t level;
+};
+
+/*
+ * Append a diagnostic to the given list of diagnostics that is using shared
+ * memory for its message.
+ */
+void pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id);
+
+/*
+ * Append a diagnostic to the given list of diagnostics that is using a format
+ * string for its message.
+ */
+void pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id, ...);
+
+#endif
diff --git a/prism/templates/lib/prism/compiler.rb.erb b/prism/templates/lib/prism/compiler.rb.erb
index 45ed88d8de..13317cac04 100644
--- a/prism/templates/lib/prism/compiler.rb.erb
+++ b/prism/templates/lib/prism/compiler.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -18,24 +21,32 @@ module Prism
#
class Compiler < Visitor
# Visit an individual node.
- def visit(node)
+ #--
+ #: (node?) -> untyped
+ def visit(node) # :nodoc:
node&.accept(self)
end
# Visit a list of nodes.
- def visit_all(nodes)
+ #--
+ #: (Array[node?]) -> untyped
+ def visit_all(nodes) # :nodoc:
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) }
+ #--
+ #: (node) -> Array[untyped]
+ def visit_child_nodes(node) # :nodoc:
+ node.each_child_node.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
+ #: (<%= node.name %>) -> Array[untyped]
+ def visit_<%= node.human %>(node) # :nodoc:
+ node.each_child_node.map { |node| node.accept(self) }
+ end
<%- end -%>
end
end
diff --git a/prism/templates/lib/prism/dispatcher.rb.erb b/prism/templates/lib/prism/dispatcher.rb.erb
index 52478451c9..5991b0c904 100644
--- a/prism/templates/lib/prism/dispatcher.rb.erb
+++ b/prism/templates/lib/prism/dispatcher.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -32,50 +35,52 @@ module Prism
# dispatcher.dispatch_once(integer)
#
class Dispatcher < Visitor
- # attr_reader listeners: Hash[Symbol, Array[Listener]]
- attr_reader :listeners
+ # A hash mapping event names to arrays of listeners that should be notified
+ # when that event is fired.
+ attr_reader :listeners #: Hash[Symbol, Array[untyped]]
# Initialize a new dispatcher.
+ #--
+ #: () -> void
def initialize
@listeners = {}
end
# Register a listener for one or more events.
- #
- # def register: (Listener, *Symbol) -> void
+ #--
+ #: (untyped, *Symbol) -> void
def register(listener, *events)
register_events(listener, events)
end
# Register all public methods of a listener that match the pattern
# `on_<node_name>_(enter|leave)`.
- #
- # def register_public_methods: (Listener) -> void
+ #--
+ #: (untyped) -> void
def register_public_methods(listener)
register_events(listener, listener.public_methods(false).grep(/\Aon_.+_(?:enter|leave)\z/))
end
# Register a listener for the given events.
- private def register_events(listener, events)
+ #--
+ #: (untyped, Array[Symbol]) -> void
+ private def register_events(listener, events) # :nodoc:
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
+ #--
+ #: (node 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)
+ #: (<%= node.name %> node) -> void
+ def visit_<%= node.human %>(node) # :nodoc:
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) }
@@ -83,14 +88,17 @@ module Prism
<%- end -%>
class DispatchOnce < Visitor # :nodoc:
- attr_reader :listeners
+ attr_reader :listeners #: Hash[Symbol, Array[untyped]]
+ #: (Hash[Symbol, Array[untyped]] listeners) -> void
def initialize(listeners)
@listeners = listeners
end
<%- nodes.each do |node| -%>
# Dispatch enter and leave events for <%= node.name %> nodes.
+ #--
+ #: (<%= node.name %> node) -> void
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) }
diff --git a/prism/templates/lib/prism/dot_visitor.rb.erb b/prism/templates/lib/prism/dot_visitor.rb.erb
index e9c81e4545..88ef1e1f36 100644
--- a/prism/templates/lib/prism/dot_visitor.rb.erb
+++ b/prism/templates/lib/prism/dot_visitor.rb.erb
@@ -1,18 +1,26 @@
-require "cgi"
+#--
+# rbs_inline: enabled
+
+require "cgi/escape"
+require "cgi/util" unless defined?(CGI::EscapeExt)
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
+ attr_reader :name #: String
+ attr_reader :value #: String?
+ attr_reader :port #: bool
+ #: (String name, String? value, bool port) -> void
def initialize(name, value, port)
@name = name
@value = value
@port = port
end
+ #: () -> String
def to_dot
if port
"<tr><td align=\"left\" colspan=\"2\" port=\"#{name}\">#{name}</td></tr>"
@@ -23,17 +31,21 @@ module Prism
end
class Table # :nodoc:
- attr_reader :name, :fields
+ attr_reader :name #: String
+ attr_reader :fields #: Array[Field]
+ #: (String name) -> void
def initialize(name)
@name = name
@fields = []
end
+ #: (String name, ?String? value, ?port: bool) -> void
def field(name, value = nil, port: false)
fields << Field.new(name, value, port)
end
+ #: () -> String
def to_dot
dot = <<~DOT
<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
@@ -49,26 +61,31 @@ module Prism
end
class Digraph # :nodoc:
- attr_reader :nodes, :waypoints, :edges
+ attr_reader :nodes, :waypoints, :edges #: Array[String]
+ #: () -> void
def initialize
@nodes = []
@waypoints = []
@edges = []
end
+ #: (String value) -> void
def node(value)
nodes << value
end
+ #: (String value) -> void
def waypoint(value)
waypoints << value
end
+ #: (String value) -> void
def edge(value)
edges << value
end
+ #: () -> String
def to_dot
<<~DOT
digraph "Prism" {
@@ -92,21 +109,25 @@ module Prism
private_constant :Field, :Table, :Digraph
# The digraph that is being built.
- attr_reader :digraph
+ attr_reader :digraph #: Digraph
# Initialize a new dot visitor.
+ #--
+ #: () -> void
def initialize
@digraph = Digraph.new
end
# Convert this visitor into a graphviz dot graph string.
+ #--
+ #: () -> String
def to_dot
digraph.to_dot
end
<%- nodes.each do |node| -%>
- # Visit a <%= node.name %> node.
- def visit_<%= node.human %>(node)
+ #: (<%= node.name %>) -> void
+ def visit_<%= node.human %>(node) # :nodoc:
table = Table.new("<%= node.name %>")
id = node_id(node)
<%- if (node_flags = node.flags) -%>
@@ -151,7 +172,7 @@ module Prism
<%- end -%>
<%- end -%>
- digraph.nodes << <<~DOT
+ digraph.node(<<~DOT)
#{id} [
label=<#{table.to_dot.gsub(/\n/, "\n ")}>
];
@@ -164,19 +185,25 @@ module Prism
private
# Generate a unique node ID for a node throughout the digraph.
- def node_id(node)
+ #--
+ #: (node) -> String
+ def node_id(node) # :nodoc:
"Node_#{node.object_id}"
end
- # Inspect a location to display the start and end line and column numbers.
- def location_inspect(location)
+ # Inspect a location to display the start and end line and columns in bytes.
+ #--
+ #: (Location) -> String
+ def location_inspect(location) # :nodoc:
"(#{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)
+ #--
+ #: (<%= nodes.filter_map { |node| node.name if node.flags == flag }.join(" | ") %> node) -> String
+ def <%= flag.human %>_inspect(node) # :nodoc:
flags = [] #: Array[String]
<%- flag.values.each do |value| -%>
flags << "<%= value.name.downcase %>" if node.<%= value.name.downcase %>?
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
index e16ebb7110..be7dc6d9c1 100644
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ b/prism/templates/lib/prism/dsl.rb.erb
@@ -1,8 +1,11 @@
+#--
+# rbs_inline: enabled
+
module Prism
# The DSL module provides a set of methods that can be used to create prism
# nodes in a more concise manner. For example, instead of writing:
#
- # source = Prism::Source.for("[1]")
+ # source = Prism::Source.for("[1]", 1, [0])
#
# Prism::ArrayNode.new(
# source,
@@ -56,17 +59,31 @@ module Prism
extend self
# Create a new Source object.
+ #--
+ #: (String string) -> Source
def source(string)
- Source.for(string)
+ Source.for(string, 1, build_offsets(string))
end
# Create a new Location object.
+ #--
+ #: (?source: Source, ?start_offset: Integer, ?length: Integer) -> Location
def location(source: default_source, start_offset: 0, length: 0)
Location.new(source, start_offset, length)
end
<%- nodes.each do |node| -%>
+ <%-
+ params = [
+ ["source", "Source"],
+ ["node_id", "Integer"],
+ ["location", "Location"],
+ ["flags", "Integer"]
+ ].concat(node.fields.map { |field| [field.name, field.rbs_class] })
+ -%>
# Create a new <%= node.name %> node.
+ #--
+ #: (<%= params.map { |(name, type)| "?#{name}: #{type}" }.join(", ") %>) -> <%= node.name %>
def <%= node.human %>(<%= ["source: default_source", "node_id: 0", "location: default_location", "flags: 0", *node.fields.map { |field|
case field
when Prism::Template::NodeField
@@ -100,6 +117,8 @@ module Prism
<%- flags.each do |flag| -%>
# Retrieve the value of one of the <%= flag.name %> flags.
+ #--
+ #: (Symbol name) -> Integer
def <%= flag.human.chomp("s") %>(name)
case name
<%- flag.values.each do |value| -%>
@@ -114,20 +133,40 @@ module Prism
# The default source object that gets attached to nodes and locations if no
# source is specified.
+ #--
+ #: () -> Source
def default_source
- Source.for("")
+ Source.for("", 1, [0])
end
# The default location object that gets attached to nodes if no location is
# specified, which uses the given source.
+ #--
+ #: () -> Location
def default_location
Location.new(default_source, 0, 0)
end
# The default node that gets attached to nodes if no node is specified for a
# required node field.
+ #--
+ #: (Source source, Location location) -> node
def default_node(source, location)
- MissingNode.new(source, -1, location, 0)
+ ErrorRecoveryNode.new(source, -1, location, 0, nil)
+ end
+
+ private
+
+ # Build the newline byte offset array for the given source string.
+ #--
+ #: (String source) -> Array[Integer]
+ def build_offsets(source)
+ offsets = [0]
+ start = 0
+ while (index = source.byteindex("\n", start))
+ offsets << (start = index + 1)
+ end
+ offsets
end
end
end
diff --git a/prism/templates/lib/prism/inspect_visitor.rb.erb b/prism/templates/lib/prism/inspect_visitor.rb.erb
index 3cfe615d85..820f5ae75f 100644
--- a/prism/templates/lib/prism/inspect_visitor.rb.erb
+++ b/prism/templates/lib/prism/inspect_visitor.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
module Prism
# This visitor is responsible for composing the strings that get returned by
# the various #inspect methods defined on each of the nodes.
@@ -7,8 +10,9 @@ module Prism
# when we hit an element in that list. In this case, we have a special
# command that replaces the subsequent indent with the given value.
class Replace # :nodoc:
- attr_reader :value
+ attr_reader :value #: String
+ #: (String value) -> void
def initialize(value)
@value = value
end
@@ -17,19 +21,25 @@ module Prism
private_constant :Replace
# The current prefix string.
- attr_reader :indent
+ # :stopdoc:
+ attr_reader :indent #: String
+ # :startdoc:
# The list of commands that we need to execute in order to compose the
# final string.
- attr_reader :commands
+ #: stopdoc:
+ attr_reader :commands #: Array[[String | node | Replace, String]]
+ # :startdoc:
- # Initializes a new instance of the InspectVisitor.
- def initialize(indent = +"")
+ #: (?String indent) -> void
+ def initialize(indent = +"") # :nodoc:
@indent = indent
@commands = []
end
# Compose an inspect string for the given node.
+ #--
+ #: (node node) -> String
def self.compose(node)
visitor = new
node.accept(visitor)
@@ -37,7 +47,9 @@ module Prism
end
# Compose the final string.
- def compose
+ #--
+ #: () -> String
+ def compose # :nodoc:
buffer = +""
replace = nil
@@ -66,8 +78,8 @@ module Prism
end
<%- nodes.each do |node| -%>
- # Inspect a <%= node.name %> node.
- def visit_<%= node.human %>(node)
+ #: (<%= node.name %> node) -> void
+ def visit_<%= node.human %>(node) # :nodoc:
commands << [inspect_node(<%= node.name.inspect %>, node), indent]
<%- (fields = [node.flags || Prism::Template::Flags.empty, *node.fields]).each_with_index do |field, index| -%>
<%- pointer = index == fields.length - 1 ? "└── " : "├── " -%>
@@ -114,13 +126,17 @@ module Prism
private
# Compose a header for the given node.
- def inspect_node(name, node)
+ #--
+ #: (String name, node node) -> String
+ def inspect_node(name, node) # :nodoc:
location = node.location
"@ #{name} (location: (#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column}))\n"
end
# Compose a string representing the given inner location field.
- def inspect_location(location)
+ #--
+ #: (Location? location) -> String
+ def inspect_location(location) # :nodoc:
if location
"(#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column}) = #{location.slice.inspect}"
else
diff --git a/prism/templates/lib/prism/mutation_compiler.rb.erb b/prism/templates/lib/prism/mutation_compiler.rb.erb
index 565ee4e315..2d555048d2 100644
--- a/prism/templates/lib/prism/mutation_compiler.rb.erb
+++ b/prism/templates/lib/prism/mutation_compiler.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
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
@@ -5,8 +8,8 @@ module Prism
class MutationCompiler < Compiler
<%- nodes.each_with_index do |node, index| -%>
<%= "\n" if index != 0 -%>
- # Copy a <%= node.name %> node
- def visit_<%= node.human %>(node)
+ #: (<%= node.name %>) -> node?
+ def visit_<%= node.human %>(node) # :nodoc:
<%- fields = node.fields.select { |field| [Prism::Template::NodeField, Prism::Template::OptionalNodeField, Prism::Template::NodeListField].include?(field.class) } -%>
<%- if fields.any? -%>
node.copy(<%= fields.map { |field| "#{field.name}: #{field.is_a?(Prism::Template::NodeListField) ? "visit_all" : "visit"}(node.#{field.name})" }.join(", ") %>)
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
index ceee2b0ffe..fb13051aba 100644
--- a/prism/templates/lib/prism/node.rb.erb
+++ b/prism/templates/lib/prism/node.rb.erb
@@ -1,24 +1,49 @@
+#--
+# rbs_inline: enabled
+
module Prism
+ # @rbs!
+ # interface _Repository
+ # def enter: (Integer node_id, Symbol field_name) -> Relocation::Entry
+ # end
+ #
+ # interface _Node
+ # def deconstruct: () -> Array[Prism::node?]
+ # def inspect: () -> String
+ # end
+ #
+ # type node = Node & _Node
+
# This represents a node in the tree. It is the parent class of all of the
# various node types.
class Node
# A pointer to the source that this node was created from.
- attr_reader :source
+ # :stopdoc:
+ attr_reader :source #: Source
private :source
+ # :startdoc:
# A unique identifier for this node. This is used in a very specific
# use case where you want to keep around a reference to a node without
# having to keep around the syntax tree in memory. This unique identifier
# will be consistent across multiple parses of the same source code.
- attr_reader :node_id
+ attr_reader :node_id #: Integer
+
+ # The location associated with this node. For lazily loading Location
+ # objects, we keep it as a packed integer until it is accessed.
+ # @rbs @location: Location | Integer
# Save this node using a saved source so that it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry
def save(repository)
repository.enter(node_id, :itself)
end
# A Location instance that represents the location of this node in the
# source.
+ #--
+ #: () -> Location
def location
location = @location
return location if location.is_a?(Location)
@@ -26,104 +51,151 @@ module Prism
end
# Save the location using a saved source so that it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry
def save_location(repository)
repository.enter(node_id, :location)
end
- # Delegates to the start_line of the associated location object.
+ # --------------------------------------------------------------------------
+ # :section: Location Delegators
+ # These methods provide convenient access to the underlying Location object.
+ # --------------------------------------------------------------------------
+
+ # Delegates to [`start_line`](rdoc-ref:Location#start_line) of the associated location object.
+ #--
+ #: () -> Integer
def start_line
location.start_line
end
- # Delegates to the end_line of the associated location object.
+ # Delegates to [`end_line`](rdoc-ref:Location#end_line) of the associated location object.
+ #--
+ #: () -> Integer
def end_line
location.end_line
end
- # The start offset of the node in the source. This method is effectively a
- # delegate method to the location object.
+ # Delegates to [`start_offset`](rdoc-ref:Location#start_offset) of the associated location object.
+ #--
+ #: () -> Integer
def start_offset
location = @location
location.is_a?(Location) ? location.start_offset : location >> 32
end
- # The end offset of the node in the source. This method is effectively a
- # delegate method to the location object.
+ # Delegates to [`end_offset`](rdoc-ref:Location#end_offset) of the associated location object.
+ #--
+ #: () -> Integer
def end_offset
location = @location
location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
end
- # Delegates to the start_character_offset of the associated location object.
+ # Delegates to [`start_character_offset`](rdoc-ref:Location#start_character_offset)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def start_character_offset
location.start_character_offset
end
- # Delegates to the end_character_offset of the associated location object.
+ # Delegates to [`end_character_offset`](rdoc-ref:Location#end_character_offset)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def end_character_offset
location.end_character_offset
end
- # Delegates to the cached_start_code_units_offset of the associated location
- # object.
+ # Delegates to [`cached_start_code_units_offset`](rdoc-ref:Location#cached_start_code_units_offset)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_offset(cache)
location.cached_start_code_units_offset(cache)
end
- # Delegates to the cached_end_code_units_offset of the associated location
- # object.
+ # Delegates to [`cached_end_code_units_offset`](rdoc-ref:Location#cached_end_code_units_offset)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_offset(cache)
location.cached_end_code_units_offset(cache)
end
- # Delegates to the start_column of the associated location object.
+ # Delegates to [`start_column`](rdoc-ref:Location#start_column) of the associated location object.
+ #--
+ #: () -> Integer
def start_column
location.start_column
end
- # Delegates to the end_column of the associated location object.
+ # Delegates to [`end_column`](rdoc-ref:Location#end_column) of the associated location object.
+ #--
+ #: () -> Integer
def end_column
location.end_column
end
- # Delegates to the start_character_column of the associated location object.
+ # Delegates to [`start_character_column`](rdoc-ref:Location#start_character_column)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def start_character_column
location.start_character_column
end
- # Delegates to the end_character_column of the associated location object.
+ # Delegates to [`end_character_column`](rdoc-ref:Location#end_character_column)
+ # of the associated location object.
+ #--
+ #: () -> Integer
def end_character_column
location.end_character_column
end
- # Delegates to the cached_start_code_units_column of the associated location
- # object.
+ # Delegates to [`cached_start_code_units_column`](rdoc-ref:Location#cached_start_code_units_column)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_start_code_units_column(cache)
location.cached_start_code_units_column(cache)
end
- # Delegates to the cached_end_code_units_column of the associated location
- # object.
+ # Delegates to [`cached_end_code_units_column`](rdoc-ref:Location#cached_end_code_units_column)
+ # of the associated location object.
+ #--
+ #: (_CodeUnitsCache cache) -> Integer
def cached_end_code_units_column(cache)
location.cached_end_code_units_column(cache)
end
- # Delegates to the leading_comments of the associated location object.
+ # Delegates to [`leading_comments`](rdoc-ref:Location#leading_comments) of the associated location object.
+ #--
+ #: () -> Array[Comment]
def leading_comments
location.leading_comments
end
- # Delegates to the trailing_comments of the associated location object.
+ # Delegates to [`trailing_comments`](rdoc-ref:Location#trailing_comments) of the associated location object.
+ #--
+ #: () -> Array[Comment]
def trailing_comments
location.trailing_comments
end
- # Delegates to the comments of the associated location object.
+ # Delegates to [`comments`](rdoc-ref:Location#comments) of the associated location object.
+ #--
+ #: () -> Array[Comment]
def comments
location.comments
end
+ # :section:
+
# Returns all of the lines of the source code associated with this node.
+ #--
+ #: () -> Array[String]
def source_lines
location.source_lines
end
@@ -133,6 +205,8 @@ module Prism
alias script_lines source_lines
# Slice the location of the node from the source.
+ #--
+ #: () -> String
def slice
location.slice
end
@@ -140,28 +214,38 @@ module Prism
# Slice the location of the node from the source, starting at the beginning
# of the line that the location starts on, ending at the end of the line
# that the location ends on.
+ #--
+ #: () -> String
def slice_lines
location.slice_lines
end
# An bitset of flags for this node. There are certain flags that are common
# for all nodes, and then some nodes have specific flags.
- attr_reader :flags
+ # :stopdoc:
+ attr_reader :flags #: Integer
protected :flags
+ # :startdoc:
# Returns true if the node has the newline flag set.
+ #--
+ #: () -> bool
def newline?
flags.anybits?(NodeFlags::NEWLINE)
end
# Returns true if the node has the static literal flag set.
+ #--
+ #: () -> bool
def static_literal?
flags.anybits?(NodeFlags::STATIC_LITERAL)
end
# Similar to inspect, but respects the current level of indentation given by
# the pretty print object.
- def pretty_print(q)
+ #--
+ #: (PP q) -> void
+ def pretty_print(q) # :nodoc:
q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
q.text(line.chomp)
end
@@ -169,6 +253,8 @@ module Prism
end
# Convert this node into a graphviz dot graph string.
+ #--
+ #: () -> String
def to_dot
# @type self: node
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
@@ -180,28 +266,18 @@ module Prism
#
# Important to note is that the column given to this method should be in
# bytes, as opposed to characters or code units.
+ #--
+ #: (Integer line, Integer column) -> Array[node]
def tunnel(line, column)
- queue = [self] #: Array[Prism::node]
- result = [] #: Array[Prism::node]
+ queue = [self] #: Array[node]
+ result = [] #: Array[node]
+ offset = source.byte_offset(line, column)
while (node = queue.shift)
result << node
- node.compact_child_nodes.each do |child_node|
- child_location = child_node.location
-
- start_line = child_location.start_line
- end_line = child_location.end_line
-
- if start_line == end_line
- if line == start_line && column >= child_location.start_column && column < child_location.end_column
- queue << child_node
- break
- end
- elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column)
- queue << child_node
- break
- elsif line > start_line && line < end_line
+ node.each_child_node do |child_node|
+ if child_node.start_offset <= offset && offset < child_node.end_offset
queue << child_node
break
end
@@ -212,13 +288,14 @@ module Prism
end
# Returns the first node that matches the given block when visited in a
- # depth-first search. This is useful for finding a node that matches a
+ # breadth-first search. This is useful for finding a node that matches a
# particular condition.
#
# node.breadth_first_search { |node| node.node_id == node_id }
- #
- def breadth_first_search(&block)
- queue = [self] #: Array[Prism::node]
+ #--
+ #: () { (node) -> bool } -> node?
+ def breadth_first_search(&blk)
+ queue = [self] #: Array[node]
while (node = queue.shift)
return node if yield node
@@ -227,10 +304,33 @@ module Prism
nil
end
+ alias find breadth_first_search
+
+ # Returns all of the nodes that match the given block when visited in a
+ # breadth-first search. This is useful for finding all nodes that match a
+ # particular condition.
+ #
+ # node.breadth_first_search_all { |node| node.is_a?(Prism::CallNode) }
+ #--
+ #: () { (node) -> bool } -> Array[node]
+ def breadth_first_search_all(&blk)
+ queue = [self] #: Array[Prism::node]
+ results = [] #: Array[Prism::node]
+
+ while (node = queue.shift)
+ results << node if yield node
+ queue.concat(node.compact_child_nodes)
+ end
+
+ results
+ end
+ alias find_all breadth_first_search_all
# Returns a list of the fields that exist for this node class. Fields
# describe the structure of the node. This kind of reflection is useful for
# things like recursively visiting each node _and_ field in the tree.
+ #--
+ #: () -> Array[Reflection::Field]
def self.fields
# This method should only be called on subclasses of Node, not Node
# itself.
@@ -240,38 +340,57 @@ module Prism
end
# --------------------------------------------------------------------------
- # :section: Node interface
- # These methods are effectively abstract methods that must be implemented by
- # the various subclasses of Node. They are here to make it easier to work
- # with typecheckers.
+ # :section: Node Interface
+ # These methods are effectively abstract methods that are implemented by
+ # the various subclasses of Node.
# --------------------------------------------------------------------------
# Accepts a visitor and calls back into the specialized visit function.
+ #--
+ #: (_Visitor visitor) -> untyped
def accept(visitor)
raise NoMethodError, "undefined method `accept' for #{inspect}"
end
# Returns an array of child nodes, including `nil`s in the place of optional
# nodes that were not present.
+ #--
+ #: () -> Array[node?]
def child_nodes
raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
end
alias deconstruct child_nodes
+ # With a block given, yields each child node. Without a block, returns
+ # an enumerator that contains each child node. Excludes any `nil`s in
+ # the place of optional nodes that were not present.
+ #--
+ #: () -> Enumerator[node, void]
+ #: () { (node) -> void } -> void
+ def each_child_node(&blk)
+ raise NoMethodError, "undefined method `each_child_node' for #{inspect}"
+ end
+
# Returns an array of child nodes, excluding any `nil`s in the place of
# optional nodes that were not present.
+ #--
+ #: () -> Array[node]
def compact_child_nodes
raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
end
# Returns an array of child nodes and locations that could potentially have
# comments attached to them.
+ #--
+ #: () -> Array[node | Location]
def comment_targets
raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
end
# Returns a string representation of the node.
+ #--
+ #: () -> String
def inspect
raise NoMethodError, "undefined method `inspect' for #{inspect}"
end
@@ -288,6 +407,8 @@ module Prism
# 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.
+ #--
+ #: () -> Symbol
def type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
@@ -296,6 +417,8 @@ module Prism
# 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.
+ #--
+ #: () -> Symbol
def self.type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
@@ -306,7 +429,13 @@ module Prism
#<%= line %>
<%- end -%>
class <%= node.name -%> < Node
+ <%- node.fields.each do |field| -%>
+ # @rbs @<%= field.name %>: <%= field.rbs_class %>
+ <%- end -%>
+
# Initialize a new <%= node.name %> node.
+ #--
+ #: (Source source, Integer node_id, Location location, Integer flags, <%= node.fields.map { |field| "#{field.rbs_class} #{field.name}" }.join(", ") %>) -> void
def initialize(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
@source = source
@node_id = node_id
@@ -320,12 +449,27 @@ module Prism
<%- end -%>
end
- # def accept: (Visitor visitor) -> void
+ # ---------
+ # :section: Repository
+ # Methods related to Relocation.
+ # ---------
+
+ # ----------------------------------------------------------------------------------
+ # :section: Node Interface
+ # These methods are present on all subclasses of Node.
+ # Read the [node interface docs](Node.html#node-interface) for more information.
+ # ----------------------------------------------------------------------------------
+
+ # See Node.accept.
+ #--
+ #: (_Visitor visitor) -> untyped
def accept(visitor)
visitor.visit_<%= node.human %>(self)
end
- # def child_nodes: () -> Array[Node?]
+ # See Node.child_nodes.
+ #--
+ #: () -> Array[node?]
def child_nodes
[<%= node.fields.map { |field|
case field
@@ -335,7 +479,28 @@ module Prism
}.compact.join(", ") %>]
end
- # def compact_child_nodes: () -> Array[Node]
+ # See Node.each_child_node.
+ #--
+ #: () -> Enumerator[node, void]
+ #: () { (node) -> void } -> void
+ def each_child_node(&blk)
+ return to_enum(:each_child_node) unless block_given?
+
+ <%- node.fields.each do |field| -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ yield <%= field.name %>
+ <%- when Prism::Template::OptionalNodeField -%>
+ if (<%= field.name %> = self.<%= field.name %>); yield <%= field.name %>; end
+ <%- when Prism::Template::NodeListField -%>
+ <%= field.name %>.each { |node| yield node }
+ <%- end -%>
+ <%- end -%>
+ end
+
+ # See Node.compact_child_nodes.
+ #--
+ #: () -> Array[node]
def compact_child_nodes
<%- if node.fields.any? { |field| field.is_a?(Prism::Template::OptionalNodeField) } -%>
compact = [] #: Array[Prism::node]
@@ -344,7 +509,7 @@ module Prism
<%- when Prism::Template::NodeField -%>
compact << <%= field.name %>
<%- when Prism::Template::OptionalNodeField -%>
- compact << <%= field.name %> if <%= field.name %>
+ if (<%= field.name %> = self.<%= field.name %>); compact << <%= field.name %>; end
<%- when Prism::Template::NodeListField -%>
compact.concat(<%= field.name %>)
<%- end -%>
@@ -360,7 +525,9 @@ module Prism
<%- end -%>
end
- # def comment_targets: () -> Array[Node | Location]
+ # See Node.comment_targets.
+ #--
+ #: () -> Array[node | Location]
def comment_targets
[<%= node.fields.map { |field|
case field
@@ -370,50 +537,101 @@ module Prism
}.compact.join(", ") %>] #: Array[Prism::node | Location]
end
- # def copy: (<%= (["?node_id: Integer", "?location: Location", "?flags: Integer"] + node.fields.map { |field| "?#{field.name}: #{field.rbs_class}" }).join(", ") %>) -> <%= node.name %>
+ # :call-seq:
+ # copy(**fields) -> <%= node.name %>
+ #
+ # Creates a copy of self with the given fields, using self as the template.
+ #--
+ #: (?node_id: Integer, ?location: Location, ?flags: Integer, <%= node.fields.map { |field| "?#{field.name}: #{field.rbs_class}" }.join(", ") %>) -> <%= node.name %>
def copy(<%= (["node_id", "location", "flags"] + node.fields.map(&:name)).map { |field| "#{field}: self.#{field}" }.join(", ") %>)
<%= node.name %>.new(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
end
- # def deconstruct: () -> Array[Node?]
alias deconstruct child_nodes
- # def deconstruct_keys: (Array[Symbol] keys) -> { <%= (["node_id: Integer", "location: Location"] + node.fields.map { |field| "#{field.name}: #{field.rbs_class}" }).join(", ") %> }
- def deconstruct_keys(keys)
+ #: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
+ def deconstruct_keys(keys) # :nodoc:
{ <%= (["node_id: node_id", "location: location"] + node.fields.map { |field| "#{field.name}: #{field.name}" }).join(", ") %> }
end
+
+ # See `Node#type`.
+ #--
+ #: () -> :<%= node.human %>
+ def type
+ :<%= node.human %>
+ end
+
+ # See `Node.type`.
+ #--
+ #: () -> :<%= node.human %>
+ def self.type
+ :<%= node.human %>
+ end
+
+ #: () -> String
+ def inspect # :nodoc:
+ InspectVisitor.compose(self)
+ end
+
+ # :section:
+
<%- if (node_flags = node.flags) -%>
<%- node_flags.values.each do |value| -%>
-
- # def <%= value.name.downcase %>?: () -> bool
+ # :category: Flags
+ # <%= value.comment %>
+ #--
+ #: () -> bool
def <%= value.name.downcase %>?
flags.anybits?(<%= node_flags.name %>::<%= value.name %>)
end
+
<%- end -%>
<%- end -%>
<%- node.fields.each do |field| -%>
-
+ <%- case field -%>
+ <%- when Prism::Template::LocationField -%>
+ # :category: Locations
+ # :call-seq:
+ # <%= field.name %> -> <%= field.call_seq_type %>
+ #
<%- if field.comment.nil? -%>
- # attr_reader <%= field.name %>: <%= field.rbs_class %>
+ # Returns the Location represented by `<%= field.name %>`.
<%- else -%>
<%- field.each_comment_line do |line| -%>
#<%= line %>
<%- end -%>
<%- end -%>
- <%- case field -%>
- <%- when Prism::Template::LocationField -%>
+ #--
+ #: () -> Location
def <%= field.name %>
location = @<%= field.name %>
return location if location.is_a?(Location)
@<%= field.name %> = Location.new(source, location >> 32, location & 0xFFFFFFFF)
end
+ # :category: Repository
# Save the <%= field.name %> location using the given saved source so that
# it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry
def save_<%= field.name %>(repository)
repository.enter(node_id, :<%= field.name %>)
end
+
<%- when Prism::Template::OptionalLocationField -%>
+ # :category: Locations
+ # :call-seq:
+ # <%= field.name %> -> <%= field.call_seq_type %>
+ #
+ <%- if field.comment.nil? -%>
+ # Returns the Location represented by `<%= field.name %>`.
+ <%- else -%>
+ <%- field.each_comment_line do |line| -%>
+ #<%= line %>
+ <%- end -%>
+ <%- end -%>
+ #--
+ #: () -> Location?
def <%= field.name %>
location = @<%= field.name %>
case location
@@ -426,54 +644,69 @@ module Prism
end
end
+ # :category: Repository
# Save the <%= field.name %> location using the given saved source so that
# it can be retrieved later.
+ #--
+ #: (_Repository repository) -> Relocation::Entry?
def save_<%= field.name %>(repository)
repository.enter(node_id, :<%= field.name %>) unless @<%= field.name %>.nil?
end
<%- else -%>
- attr_reader :<%= field.name %>
+ # :call-seq:
+ # <%= field.name %> -> <%= field.call_seq_type %>
+ #
+ <%- if field.comment.nil? -%>
+ # Returns the `<%= field.name %>` attribute.
+ <%- else -%>
+ <%- field.each_comment_line do |line| -%>
+ #<%= line %>
<%- end -%>
<%- end -%>
+ #--
+ #: () -> <%= field.rbs_class %>
+ def <%= field.name %>
+ @<%= field.name %>
+ end
+
+ <%- end -%>
+ <%- end -%>
+ # :section: Slicing
+
<%- node.fields.each do |field| -%>
<%- case field -%>
<%- when Prism::Template::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
+ # :call-seq:
+ # <%= field.name.delete_suffix("_loc") %> -> String
+ #
+ # Slice the location of <%= field.name %> from the source.
+ #--
+ #: () -> String
def <%= field.name.delete_suffix("_loc") %>
<%= field.name %>.slice
end
+
<%- when Prism::Template::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?
+ # :call-seq:
+ # <%= field.name.delete_suffix("_loc") %> -> String | nil
+ #
+ # Slice the location of <%= field.name %> from the source.
+ #--
+ #: () -> String?
def <%= field.name.delete_suffix("_loc") %>
<%= field.name %>&.slice
end
+
<%- end -%>
<%- end -%>
+ # :section:
- # def inspect -> String
- def inspect
- InspectVisitor.compose(self)
- end
-
- # Return a symbol representation of this node type. See `Node#type`.
- def type
- :<%= node.human %>
- end
-
- # Return a symbol representation of this node type. See `Node::type`.
- def self.type
- :<%= node.human %>
- end
-
- # Implements case-equality for the node. This is effectively == but without
- # comparing the value of locations. Locations are checked only for presence.
- def ===(other)
+ #: (untyped other) -> boolish
+ def ===(other) # :nodoc:
other.is_a?(<%= node.name %>)<%= " &&" if (fields = [*node.flags, *node.fields]).any? %>
<%- fields.each_with_index do |field, index| -%>
<%- if field.is_a?(Prism::Template::LocationField) || field.is_a?(Prism::Template::OptionalLocationField) -%>
diff --git a/prism/templates/lib/prism/reflection.rb.erb b/prism/templates/lib/prism/reflection.rb.erb
index 6c8b2f4d25..0012f120b2 100644
--- a/prism/templates/lib/prism/reflection.rb.erb
+++ b/prism/templates/lib/prism/reflection.rb.erb
@@ -1,3 +1,6 @@
+#--
+# rbs_inline: enabled
+
module Prism
# The Reflection module provides the ability to reflect on the structure of
# the syntax tree itself, as opposed to looking at a single syntax tree. This
@@ -7,9 +10,11 @@ module Prism
# for all other field types.
class Field
# The name of the field.
- attr_reader :name
+ attr_reader :name #: Symbol
# Initializes the field with the given name.
+ #--
+ #: (Symbol name) -> void
def initialize(name)
@name = name
end
@@ -83,9 +88,11 @@ module Prism
# the bitset should be accessed through their query methods.
class FlagsField < Field
# The names of the flags in the bitset.
- attr_reader :flags
+ attr_reader :flags #: Array[Symbol]
# Initializes the flags field with the given name and flags.
+ #--
+ #: (Symbol name, Array[Symbol] flags) -> void
def initialize(name, flags)
super(name)
@flags = flags
@@ -93,6 +100,8 @@ module Prism
end
# Returns the fields for the given node.
+ #--
+ #: (singleton(Node) node) -> Array[Field]
def self.fields_for(node)
case node.type
<%- nodes.each do |node| -%>
diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb
index 104b60f484..a676f957af 100644
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ b/prism/templates/lib/prism/serialize.rb.erb
@@ -1,16 +1,19 @@
+#--
+# rbs_inline: enabled
+
require "stringio"
require_relative "polyfill/unpack1"
module Prism
# A module responsible for deserializing parse results.
- module Serialize
+ module Serialize # :nodoc:
# The major version of prism that we are expecting to find in the serialized
# strings.
MAJOR_VERSION = 1
# The minor version of prism that we are expecting to find in the serialized
# strings.
- MINOR_VERSION = 4
+ MINOR_VERSION = 9
# The patch version of prism that we are expecting to find in the serialized
# strings.
@@ -20,9 +23,11 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> ParseResult
def self.load_parse(input, serialized, freeze)
input = input.dup
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
loader.load_header
@@ -38,16 +43,17 @@ module Prism
data_loc = loader.load_optional_location_object(freeze)
errors = loader.load_errors(encoding, freeze)
warnings = loader.load_warnings(encoding, freeze)
+ continuable = loader.load_bool
cpool_base = loader.load_uint32
cpool_size = loader.load_varuint
- constant_pool = ConstantPool.new(input, serialized, cpool_base, cpool_size)
+ constant_pool = ConstantPool.new(serialized, cpool_base, cpool_size)
- node = loader.load_node(constant_pool, encoding, freeze)
+ node = loader.load_node(constant_pool, encoding, freeze) #: ProgramNode
loader.load_constant_pool(constant_pool)
raise unless loader.eof?
- result = ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, source)
+ result = ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, continuable, source)
result.freeze if freeze
input.force_encoding(encoding)
@@ -73,8 +79,10 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> LexResult
def self.load_lex(input, serialized, freeze)
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
tokens = loader.load_tokens
@@ -90,9 +98,10 @@ module Prism
data_loc = loader.load_optional_location_object(freeze)
errors = loader.load_errors(encoding, freeze)
warnings = loader.load_warnings(encoding, freeze)
+ continuable = loader.load_bool
raise unless loader.eof?
- result = LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, source)
+ result = LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, continuable, source)
tokens.each do |token|
token[0].value.force_encoding(encoding)
@@ -117,8 +126,10 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> Array[Comment]
def self.load_parse_comments(input, serialized, freeze)
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
loader.load_header
@@ -139,8 +150,10 @@ module Prism
#
# The formatting of the source of this method is purposeful to illustrate
# the structure of the serialized data.
+ #--
+ #: (String input, String serialized, bool freeze) -> ParseLexResult
def self.load_parse_lex(input, serialized, freeze)
- source = Source.for(input)
+ source = Source.for(input, 1, [])
loader = Loader.new(source, serialized)
tokens = loader.load_tokens
@@ -157,17 +170,18 @@ module Prism
data_loc = loader.load_optional_location_object(freeze)
errors = loader.load_errors(encoding, freeze)
warnings = loader.load_warnings(encoding, freeze)
+ continuable = loader.load_bool
cpool_base = loader.load_uint32
cpool_size = loader.load_varuint
- constant_pool = ConstantPool.new(input, serialized, cpool_base, cpool_size)
+ constant_pool = ConstantPool.new(serialized, cpool_base, cpool_size)
- node = loader.load_node(constant_pool, encoding, freeze)
+ node = loader.load_node(constant_pool, encoding, freeze) #: ProgramNode
loader.load_constant_pool(constant_pool)
raise unless loader.eof?
- value = [node, tokens]
- result = ParseLexResult.new(value, comments, magic_comments, data_loc, errors, warnings, source)
+ value = [node, tokens] #: [ProgramNode, Array[[Token, Integer]]]
+ result = ParseLexResult.new(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
tokens.each do |token|
token[0].value.force_encoding(encoding)
@@ -189,34 +203,36 @@ module Prism
end
class ConstantPool # :nodoc:
- attr_reader :size
+ attr_reader :size #: Integer
+
+ # @rbs @serialized: String
+ # @rbs @base: Integer
+ # @rbs @pool: Array[Symbol?]
- def initialize(input, serialized, base, size)
- @input = input
+ #: (String serialized, Integer base, Integer size) -> void
+ def initialize(serialized, base, size)
@serialized = serialized
@base = base
@size = size
@pool = Array.new(size, nil)
end
+ #: (Integer index, Encoding encoding) -> Symbol
def get(index, encoding)
@pool[index] ||=
begin
offset = @base + index * 8
- start = @serialized.unpack1("L", offset: offset)
- length = @serialized.unpack1("L", offset: offset + 4)
+ start = @serialized.unpack1("L", offset: offset) #: Integer
+ length = @serialized.unpack1("L", offset: offset + 4) #: Integer
- if start.nobits?(1 << 31)
- @input.byteslice(start, length).force_encoding(encoding).to_sym
- else
- @serialized.byteslice(start & ((1 << 31) - 1), length).force_encoding(encoding).to_sym
- end
+ (@serialized.byteslice(start, length) or raise).force_encoding(encoding).to_sym
end
end
end
if RUBY_ENGINE == "truffleruby"
# StringIO is synchronized and that adds a high overhead on TruffleRuby.
+ # @rbs skip
class FastStringIO # :nodoc:
attr_accessor :pos
@@ -246,8 +262,11 @@ module Prism
end
class Loader # :nodoc:
- attr_reader :input, :io, :source
+ attr_reader :input #: String
+ attr_reader :io #: StringIO
+ attr_reader :source #: Source
+ #: (Source source, String serialized) -> void
def initialize(source, serialized)
@input = source.source.dup
raise unless serialized.encoding == Encoding::BINARY
@@ -256,40 +275,46 @@ module Prism
define_load_node_lambdas if RUBY_ENGINE != "ruby"
end
+ #: () -> bool
def eof?
io.getbyte
io.eof?
end
+ #: (ConstantPool constant_pool) -> void
def load_constant_pool(constant_pool)
trailer = 0
constant_pool.size.times do |index|
- start, length = io.read(8).unpack("L2")
- trailer += length if start.anybits?(1 << 31)
+ length = (io.read(8) or raise).unpack1("L", offset: 4) #: Integer
+ trailer += length
end
io.read(trailer)
end
+ #: () -> void
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]
+ raise "Invalid serialization" if (io.read(3) or raise).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
raise "Invalid serialization (location fields must be included but are not)" if io.getbyte != 0
end
+ #: () -> Encoding
def load_encoding
- encoding = Encoding.find(io.read(load_varuint))
+ encoding = Encoding.find((io.read(load_varuint) or raise)) or raise
@input = input.force_encoding(encoding).freeze
encoding
end
+ #: (bool freeze) -> Array[Integer]
def load_line_offsets(freeze)
offsets = Array.new(load_varuint) { load_varuint }
offsets.freeze if freeze
offsets
end
+ #: (bool freeze) -> Array[Comment]
def load_comments(freeze)
comments =
Array.new(load_varuint) do
@@ -297,6 +322,7 @@ module Prism
case load_varuint
when 0 then InlineComment.new(load_location_object(freeze))
when 1 then EmbDocComment.new(load_location_object(freeze))
+ else raise
end
comment.freeze if freeze
@@ -307,6 +333,7 @@ module Prism
comments
end
+ #: (bool freeze) -> Array[MagicComment]
def load_magic_comments(freeze)
magic_comments =
Array.new(load_varuint) do
@@ -331,10 +358,11 @@ module Prism
<%- warnings.each do |warning| -%>
<%= warning.name.downcase.to_sym.inspect %>,
<%- end -%>
- ].freeze
+ ].freeze #: Array[Symbol]
private_constant :DIAGNOSTIC_TYPES
+ #: () -> Symbol
def load_error_level
level = io.getbyte
@@ -350,13 +378,14 @@ module Prism
end
end
+ #: (Encoding encoding, bool freeze) -> Array[ParseError]
def load_errors(encoding, freeze)
errors =
Array.new(load_varuint) do
error =
ParseError.new(
DIAGNOSTIC_TYPES.fetch(load_varuint),
- load_embedded_string(encoding),
+ load_string(encoding),
load_location_object(freeze),
load_error_level
)
@@ -369,6 +398,7 @@ module Prism
errors
end
+ #: () -> Symbol
def load_warning_level
level = io.getbyte
@@ -382,13 +412,14 @@ module Prism
end
end
+ #: (Encoding encoding, bool freeze) -> Array[ParseWarning]
def load_warnings(encoding, freeze)
warnings =
Array.new(load_varuint) do
warning =
ParseWarning.new(
DIAGNOSTIC_TYPES.fetch(load_varuint),
- load_embedded_string(encoding),
+ load_string(encoding),
load_location_object(freeze),
load_warning_level
)
@@ -401,15 +432,15 @@ module Prism
warnings
end
+ #: () -> Array[[Token, Integer]]
def load_tokens
- tokens = []
+ tokens = [] #: Array[[Token, Integer]]
while (type = TOKEN_TYPES.fetch(load_varuint))
- start = load_varuint
- length = load_varuint
+ location = load_location_object(false)
+
lex_state = load_varuint
- location = Location.new(@source, start, length)
token = Token.new(@source, type, location.slice, location)
tokens << [token, lex_state]
@@ -420,25 +451,29 @@ module Prism
# variable-length integer using https://en.wikipedia.org/wiki/LEB128
# This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
+ #--
+ #: () -> Integer
def load_varuint
- n = io.getbyte
+ n = (io.getbyte or raise)
if n < 128
n
else
n -= 128
shift = 0
- while (b = io.getbyte) >= 128
+ while (b = (io.getbyte or raise)) >= 128
n += (b - 128) << (shift += 7)
end
n + (b << (shift + 7))
end
end
+ #: () -> Integer
def load_varsint
n = load_varuint
(n >> 1) ^ (-(n & 1))
end
+ #: () -> Integer
def load_integer
negative = io.getbyte != 0
length = load_varuint
@@ -450,14 +485,22 @@ module Prism
value
end
+ #: () -> Float
def load_double
- io.read(8).unpack1("D")
+ (io.read(8) or raise).unpack1("D") #: Float
end
+ #: () -> bool
+ def load_bool
+ (io.getbyte or raise) != 0
+ end
+
+ #: () -> Integer
def load_uint32
- io.read(4).unpack1("L")
+ (io.read(4) or raise).unpack1("L") #: Integer
end
+ #: (ConstantPool constant_pool, Encoding encoding, bool freeze) -> node?
def load_optional_node(constant_pool, encoding, freeze)
if io.getbyte != 0
io.pos -= 1
@@ -465,90 +508,121 @@ module Prism
end
end
- def load_embedded_string(encoding)
- io.read(load_varuint).force_encoding(encoding).freeze
- end
-
+ #: (Encoding encoding) -> String
def load_string(encoding)
- case (type = io.getbyte)
- when 1
- input.byteslice(load_varuint, load_varuint).force_encoding(encoding).freeze
- when 2
- load_embedded_string(encoding)
- else
- raise "Unknown serialized string type: #{type}"
- end
+ (io.read(load_varuint) or raise).force_encoding(encoding).freeze
end
+ #: (bool freeze) -> Location
def load_location_object(freeze)
location = Location.new(source, load_varuint, load_varuint)
location.freeze if freeze
location
end
+ # Load a location object from the serialized data. Note that we are lying
+ # about the signature a bit here, because we sometimes load it as a packed
+ # integer instead of an object.
+ #--
+ #: (bool freeze) -> Location
def load_location(freeze)
return load_location_object(freeze) if freeze
- (load_varuint << 32) | load_varuint
+ (load_varuint << 32) | load_varuint #: Location
end
+ # Load an optional location object from the serialized data if it is
+ # present. Note that we are lying about the signature a bit here, because
+ # we sometimes load it as a packed integer instead of an object.
+ #--
+ #: (bool freeze) -> Location?
def load_optional_location(freeze)
load_location(freeze) if io.getbyte != 0
end
+ #: (bool freeze) -> Location?
def load_optional_location_object(freeze)
load_location_object(freeze) if io.getbyte != 0
end
+ #: (ConstantPool constant_pool, Encoding encoding) -> Symbol
def load_constant(constant_pool, encoding)
index = load_varuint
constant_pool.get(index - 1, encoding)
end
+ #: (ConstantPool constant_pool, Encoding encoding) -> Symbol?
def load_optional_constant(constant_pool, encoding)
index = load_varuint
constant_pool.get(index - 1, encoding) if index != 0
end
if RUBY_ENGINE == "ruby"
+ #: (ConstantPool constant_pool, Encoding encoding, bool freeze) -> node
def load_node(constant_pool, encoding, freeze)
type = io.getbyte
node_id = load_varuint
- location = load_location(freeze)
- value = case type
- <%- nodes.each_with_index do |node, index| -%>
- when <%= index + 1 %> then
- <%- if node.needs_serialized_length? -%>
- load_uint32
- <%- end -%>
- <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
- case field
- when Prism::Template::NodeField then "load_node(constant_pool, encoding, freeze)"
- when Prism::Template::OptionalNodeField then "load_optional_node(constant_pool, encoding, freeze)"
- when Prism::Template::StringField then "load_string(encoding)"
- when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node(constant_pool, encoding, freeze) }.tap { |nodes| nodes.freeze if freeze }"
- when Prism::Template::ConstantField then "load_constant(constant_pool, encoding)"
- when Prism::Template::OptionalConstantField then "load_optional_constant(constant_pool, encoding)"
- when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_constant(constant_pool, encoding) }.tap { |constants| constants.freeze if freeze }"
- when Prism::Template::LocationField then "load_location(freeze)"
- when Prism::Template::OptionalLocationField then "load_optional_location(freeze)"
- when Prism::Template::UInt8Field then "io.getbyte"
- when Prism::Template::UInt32Field then "load_varuint"
- when Prism::Template::IntegerField then "load_integer"
- when Prism::Template::DoubleField then "load_double"
- else raise
- end
- }].join(", ") -%>)
+ location = load_location(freeze) #: Location
+ value =
+ case type
+ <%- nodes.each_with_index do |node, index| -%>
+ when <%= index + 1 %>
+ <%- if node.needs_serialized_length? -%>
+ load_uint32
+ <%- end -%>
+ <%= node.name %>.new(
+ source,
+ node_id,
+ location,
+ load_varuint,
+ <%- node.fields.each do |field| -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ load_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::OptionalNodeField -%>
+ load_optional_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::StringField -%>
+ load_string(encoding),
+ <%- when Prism::Template::NodeListField -%>
+ Array.new(load_varuint) do
+ load_node(constant_pool, encoding, freeze) #: <%= field.element_rbs_class %>
+ end.tap { |nodes| nodes.freeze if freeze },
+ <%- when Prism::Template::ConstantField -%>
+ load_constant(constant_pool, encoding),
+ <%- when Prism::Template::OptionalConstantField -%>
+ load_optional_constant(constant_pool, encoding),
+ <%- when Prism::Template::ConstantListField -%>
+ Array.new(load_varuint) { load_constant(constant_pool, encoding) }.tap { |constants| constants.freeze if freeze },
+ <%- when Prism::Template::LocationField -%>
+ load_location(freeze),
+ <%- when Prism::Template::OptionalLocationField -%>
+ load_optional_location(freeze),
+ <%- when Prism::Template::UInt8Field -%>
+ (io.getbyte or raise),
+ <%- when Prism::Template::UInt32Field -%>
+ load_varuint,
+ <%- when Prism::Template::IntegerField -%>
+ load_integer,
+ <%- when Prism::Template::DoubleField -%>
+ load_double,
+ <%- else raise -%>
+ <%- end -%>
+ <%- end -%>
+ )
<%- end -%>
- end
+ else
+ raise "Unknown node type: #{type}"
+ end
value.freeze if freeze
value
end
else
+ # @rbs skip
def load_node(constant_pool, encoding, freeze)
- @load_node_lambdas[io.getbyte].call(constant_pool, encoding, freeze)
+ @load_node_lambdas[(io.getbyte or raise)].call(constant_pool, encoding, freeze)
end
+ # @rbs skip
def define_load_node_lambdas
@load_node_lambdas = [
nil,
@@ -559,24 +633,46 @@ module Prism
<%- if node.needs_serialized_length? -%>
load_uint32
<%- end -%>
- value = <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
- case field
- when Prism::Template::NodeField then "load_node(constant_pool, encoding, freeze)"
- when Prism::Template::OptionalNodeField then "load_optional_node(constant_pool, encoding, freeze)"
- when Prism::Template::StringField then "load_string(encoding)"
- when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node(constant_pool, encoding, freeze) }"
- when Prism::Template::ConstantField then "load_constant(constant_pool, encoding)"
- when Prism::Template::OptionalConstantField then "load_optional_constant(constant_pool, encoding)"
- when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_constant(constant_pool, encoding) }"
- when Prism::Template::LocationField then "load_location(freeze)"
- when Prism::Template::OptionalLocationField then "load_optional_location(freeze)"
- when Prism::Template::UInt8Field then "io.getbyte"
- when Prism::Template::UInt32Field then "load_varuint"
- when Prism::Template::IntegerField then "load_integer"
- when Prism::Template::DoubleField then "load_double"
- else raise
- end
- }].join(", ") -%>)
+ value =
+ <%= node.name %>.new(
+ source,
+ node_id,
+ location,
+ load_varuint,
+ <%- node.fields.map do |field| -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ load_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::OptionalNodeField -%>
+ load_optional_node(constant_pool, encoding, freeze), #: <%= field.rbs_class %>
+ <%- when Prism::Template::StringField -%>
+ load_string(encoding),
+ <%- when Prism::Template::NodeListField -%>
+ Array.new(load_varuint) do
+ load_node(constant_pool, encoding, freeze) #: <%= field.element_rbs_class %>
+ end,
+ <%- when Prism::Template::ConstantField -%>
+ load_constant(constant_pool, encoding),
+ <%- when Prism::Template::OptionalConstantField -%>
+ load_optional_constant(constant_pool, encoding),
+ <%- when Prism::Template::ConstantListField -%>
+ Array.new(load_varuint) { load_constant(constant_pool, encoding) },
+ <%- when Prism::Template::LocationField -%>
+ load_location(freeze),
+ <%- when Prism::Template::OptionalLocationField -%>
+ load_optional_location(freeze),
+ <%- when Prism::Template::UInt8Field -%>
+ (io.getbyte or raise),
+ <%- when Prism::Template::UInt32Field -%>
+ load_varuint,
+ <%- when Prism::Template::IntegerField -%>
+ load_integer,
+ <%- when Prism::Template::DoubleField -%>
+ load_double,
+ <%- else raise -%>
+ <%- end -%>
+ <%- end -%>
+ )
value.freeze if freeze
value
},
@@ -584,6 +680,10 @@ module Prism
]
end
end
+
+ # @rbs!
+ # @load_node_lambdas: Array[Proc]
+ # def define_load_node_lambdas: () -> void
end
# The token types that can be indexed by their enum values.
@@ -592,7 +692,7 @@ module Prism
<%- tokens.each do |token| -%>
<%= token.name.to_sym.inspect %>,
<%- end -%>
- ].freeze
+ ].freeze #: Array[Symbol?]
private_constant :MAJOR_VERSION, :MINOR_VERSION, :PATCH_VERSION
private_constant :ConstantPool, :FastStringIO, :Loader, :TOKEN_TYPES
diff --git a/prism/templates/lib/prism/visitor.rb.erb b/prism/templates/lib/prism/visitor.rb.erb
index 4b30a1815b..f23e87d99e 100644
--- a/prism/templates/lib/prism/visitor.rb.erb
+++ b/prism/templates/lib/prism/visitor.rb.erb
@@ -1,4 +1,14 @@
+#--
+# rbs_inline: enabled
+
module Prism
+ # @rbs!
+ # interface _Visitor
+ # <% nodes.each do |node| %>
+ # def visit_<%= node.human %>: (<%= node.name %>) -> void
+ # <% end %>
+ # end
+
# 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
@@ -6,21 +16,27 @@ module Prism
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.
+ #--
+ #: (node? node) -> void
def visit(node)
# @type self: _Visitor
node&.accept(self)
end
# Visits each node in `nodes` by calling `accept` on each one.
+ #--
+ #: (Array[node?] nodes) -> void
def visit_all(nodes)
# @type self: _Visitor
nodes.each { |node| node&.accept(self) }
end
# Visits the child nodes of `node` by calling `accept` on each one.
+ #--
+ #: (node node) -> void
def visit_child_nodes(node)
# @type self: _Visitor
- node.compact_child_nodes.each { |node| node.accept(self) }
+ node.each_child_node { |node| node.accept(self) }
end
end
@@ -34,7 +50,7 @@ module Prism
#
# class FooCalls < Prism::Visitor
# def visit_call_node(node)
- # if node.name == "foo"
+ # if node.name == :foo
# # Do something with the node
# end
#
@@ -47,7 +63,11 @@ module Prism
<%- nodes.each_with_index do |node, index| -%>
<%= "\n" if index != 0 -%>
# Visit a <%= node.name %> node
- alias visit_<%= node.human %> visit_child_nodes
+ #--
+ #: (<%= node.name %> node) -> void
+ def visit_<%= node.human %>(node)
+ node.each_child_node { |node| node.accept(self) }
+ end
<%- end -%>
end
end
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index ce98dc5acd..0dea732869 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -1,4 +1,16 @@
-#include "prism/diagnostic.h"
+#include "prism/internal/diagnostic.h"
+
+#include "prism/compiler/inline.h"
+
+#include "prism/internal/allocator.h"
+#include "prism/internal/arena.h"
+#include "prism/internal/list.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
#define PM_DIAGNOSTIC_ID_MAX <%= errors.length + warnings.length %>
@@ -75,16 +87,16 @@ typedef struct {
* * `PM_WARNING_LEVEL_VERBOSE` - Warnings that appear with `-w`, as in `ruby -w -c -e 'code'`.
*/
static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
- // Special error that can be replaced
+ /* Special error that can be replaced */
[PM_ERR_CANNOT_PARSE_EXPRESSION] = { "cannot parse the expression", PM_ERROR_LEVEL_SYNTAX },
- // Errors that should raise argument errors
+ /* Errors that should raise argument errors */
[PM_ERR_INVALID_ENCODING_MAGIC_COMMENT] = { "unknown or invalid encoding in the magic comment", PM_ERROR_LEVEL_ARGUMENT },
- // Errors that should raise load errors
+ /* Errors that should raise load errors */
[PM_ERR_SCRIPT_NOT_FOUND] = { "no Ruby script found in input", PM_ERROR_LEVEL_LOAD },
- // Errors that should raise syntax errors
+ /* Errors that should raise syntax errors */
[PM_ERR_ALIAS_ARGUMENT] = { "invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE] = { "invalid argument being passed to `alias`; can't make alias for the number variables", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_AMPAMPEQ_MULTI_ASSIGN] = { "unexpected `&&=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
@@ -102,6 +114,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA] = { "unexpected ... in lambda argument", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK] = { "unexpected ... in block argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR] = { "unexpected `**`; no anonymous keyword rest parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = { "unexpected `*` splat argument after a `**` keyword splat argument", PM_ERROR_LEVEL_SYNTAX },
@@ -144,7 +158,9 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_CONDITIONAL_WHILE_PREDICATE] = { "expected a predicate expression for the `while` statement", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = { "expected a constant after the `::` operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_ENDLESS] = { "could not parse the endless method body", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_DEF_ENDLESS_PARAMETERS] = { "could not parse the endless method parameters", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_ENDLESS_SETTER] = { "invalid method name; a setter method cannot be defined in an endless method definition", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_DEF_ENDLESS_DO_BLOCK] = { "unexpected `do` for block in an endless method definition", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_NAME] = { "unexpected %s; expected a method name", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_PARAMS_TERM] = { "expected a delimiter to close the parameters", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_DEF_PARAMS_TERM_PAREN] = { "unexpected %s; expected a `)` to close the parameters", PM_ERROR_LEVEL_SYNTAX },
@@ -184,6 +200,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_EXPECT_FOR_DELIMITER] = { "unexpected %s; expected a 'do', newline, or ';' after the 'for' loop collection", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_IDENT_REQ_PARAMETER] = { "expected an identifier for the required parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_IN_DELIMITER] = { "expected a delimiter after the patterns of an `in` clause", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN] = { "expected a `(` immediately after `not`", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER] = { "expected a `(` after `not`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_LPAREN_REQ_PARAMETER] = { "expected a `(` to start a required parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_MESSAGE] = { "unexpected %s; expecting a message to send to the receiver", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_EXPECT_RBRACKET] = { "expected a matching `]`", PM_ERROR_LEVEL_SYNTAX },
@@ -298,6 +316,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_PARAMETER_UNEXPECTED_NO_KW] = { "unexpected **nil; no keywords marker disallowed after keywords", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS] = { "unexpected multiple '*' rest patterns in an array pattern", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_CAPTURE_DUPLICATE] = { "duplicated variable name", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE] = { "variable capture in alternative pattern", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = { "expected a pattern expression after the `[` operator", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = { "expected a pattern expression after `,`", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = { "expected a pattern expression after `=>`", PM_ERROR_LEVEL_SYNTAX },
@@ -323,13 +342,15 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_PATTERN_TERM_PAREN] = { "expected a `)` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN] = { "unexpected `||=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH] = { "regexp encoding option '%c' differs from source encoding '%s'", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_REGEXP_ESCAPED_NON_ASCII_IN_UTF8] = { "escaped non ASCII character in UTF-8 regexp: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING] = { "incompatible character encoding: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_NON_ESCAPED_MBC] = { "/.../n has a non escaped non ASCII character in non ASCII-8BIT script: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_REGEXP_INVALID_CHAR_PROPERTY] = { "invalid character property name {%.*s}: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_INVALID_UNICODE_RANGE] = { "invalid Unicode range: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_REGEXP_NON_ESCAPED_MBC] = { "/.../n has a non escaped non ASCII character in non ASCII-8BIT script: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_PARSE_ERROR] = { "%s", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_UNKNOWN_OPTIONS] = { "unknown regexp %s - %.*s", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_REGEXP_TERM] = { "unterminated regexp meets end of file; expected a closing delimiter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP] = { "UTF-8 character in non UTF-8 regexp: /%s/", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP] = { "UTF-8 character in non UTF-8 regexp: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_RESCUE_EXPRESSION] = { "expected a rescued expression", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_RESCUE_MODIFIER_VALUE] = { "expected a value after the `rescue` modifier", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_RESCUE_TERM] = { "expected a closing delimiter for the `rescue` clause", PM_ERROR_LEVEL_SYNTAX },
@@ -344,7 +365,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_STRING_INTERPOLATED_TERM] = { "unterminated string; expected a closing delimiter for the interpolated string", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_STRING_LITERAL_EOF] = { "unterminated string meets end of file", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_STRING_LITERAL_TERM] = { "unexpected %s, expected a string literal terminator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_SYMBOL_INVALID] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX }, // TODO expected symbol? prism.c ~9719
+ [PM_ERR_SYMBOL_INVALID] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX }, /* TODO expected symbol? prism.c ~9719 */
[PM_ERR_SYMBOL_TERM_DYNAMIC] = { "unterminated quoted string; expected a closing delimiter for the dynamic symbol", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_SYMBOL_TERM_INTERPOLATED] = { "unterminated symbol; expected a closing delimiter for the interpolated symbol", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_TERNARY_COLON] = { "expected a `:` after the true expression of a ternary operator", PM_ERROR_LEVEL_SYNTAX },
@@ -358,6 +379,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_LABEL] = { "unexpected label", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_MULTI_WRITE] = { "unexpected multiple assignment; multiple assignment is not allowed in this context", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE] = { "unexpected %s; expected a default value for a parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_RANGE_OPERATOR] = { "unexpected range operator; .. and ... are non-associative and cannot be chained", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
@@ -370,7 +392,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_WRITE_TARGET_UNEXPECTED] = { "unexpected write target", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_XSTRING_TERM] = { "expected a closing delimiter for the `%x` or backtick string", PM_ERROR_LEVEL_SYNTAX },
- // Warnings
+ /* Warnings */
[PM_WARN_AMBIGUOUS_BINARY_OPERATOR] = { "'%s' after local variable or literal is interpreted as binary operator even though it seems like %s", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = { "ambiguous first argument; put parentheses or a space even after `-` operator", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = { "ambiguous first argument; put parentheses or a space even after `+` operator", PM_WARNING_LEVEL_VERBOSE },
@@ -406,8 +428,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
/**
* Get the human-readable name of the given diagnostic ID.
*/
-const char *
-pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) {
+static const char *
+pm_diagnostic_id_name(pm_diagnostic_id_t diag_id) {
switch (diag_id) {
<%- errors.each do |error| -%>
case PM_ERR_<%= error.name %>: return "<%= error.name.downcase %>";
@@ -421,8 +443,8 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) {
return "";
}
-static inline const char *
-pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
+static PRISM_INLINE const char *
+pm_diagnostic_id_message(pm_diagnostic_id_t diag_id) {
assert(diag_id < PM_DIAGNOSTIC_ID_MAX);
const char *message = diagnostic_messages[diag_id].message;
@@ -431,91 +453,102 @@ pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
return message;
}
-static inline uint8_t
-pm_diagnostic_level(pm_diagnostic_id_t diag_id) {
+static PRISM_INLINE uint8_t
+pm_diagnostic_id_level(pm_diagnostic_id_t diag_id) {
assert(diag_id < PM_DIAGNOSTIC_ID_MAX);
return (uint8_t) diagnostic_messages[diag_id].level;
}
/**
+ * Get the type of the given diagnostic.
+ */
+const char *
+pm_diagnostic_type(const pm_diagnostic_t *diagnostic) {
+ return pm_diagnostic_id_name(diagnostic->diag_id);
+}
+
+/**
+ * Get the location of the given diagnostic.
+ */
+pm_location_t
+pm_diagnostic_location(const pm_diagnostic_t *diagnostic) {
+ return diagnostic->location;
+}
+
+/**
+ * Get the message of the given diagnostic.
+ */
+const char *
+pm_diagnostic_message(const pm_diagnostic_t *diagnostic) {
+ return diagnostic->message;
+}
+
+/**
+ * Get the error level associated with the given diagnostic.
+ */
+pm_error_level_t
+pm_diagnostic_error_level(const pm_diagnostic_t *diagnostic) {
+ return (pm_error_level_t) pm_diagnostic_id_level(diagnostic->diag_id);
+}
+
+/**
+ * Get the warning level associated with the given diagnostic.
+ */
+pm_warning_level_t
+pm_diagnostic_warning_level(const pm_diagnostic_t *diagnostic) {
+ return (pm_warning_level_t) pm_diagnostic_id_level(diagnostic->diag_id);
+}
+
+/**
* 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 *) xcalloc(1, sizeof(pm_diagnostic_t));
- if (diagnostic == NULL) return false;
+void
+pm_diagnostic_list_append(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
+ pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) pm_arena_zalloc(arena, sizeof(pm_diagnostic_t), PRISM_ALIGNOF(pm_diagnostic_t));
*diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
+ .location = { .start = start, .length = length },
.diag_id = diag_id,
- .message = pm_diagnostic_message(diag_id),
- .owned = false,
- .level = pm_diagnostic_level(diag_id)
+ .message = pm_diagnostic_id_message(diag_id),
+ .level = pm_diagnostic_id_level(diag_id)
};
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, ...) {
+void
+pm_diagnostic_list_append_format(pm_arena_t *arena, pm_list_t *list, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id, ...) {
va_list arguments;
va_start(arguments, diag_id);
- const char *format = pm_diagnostic_message(diag_id);
+ const char *format = pm_diagnostic_id_message(diag_id);
int result = vsnprintf(NULL, 0, format, arguments);
va_end(arguments);
if (result < 0) {
- return false;
+ return;
}
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) xcalloc(1, sizeof(pm_diagnostic_t));
- if (diagnostic == NULL) {
- return false;
- }
+ pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) pm_arena_zalloc(arena, sizeof(pm_diagnostic_t), PRISM_ALIGNOF(pm_diagnostic_t));
- size_t length = (size_t) (result + 1);
- char *message = (char *) xmalloc(length);
- if (message == NULL) {
- xfree(diagnostic);
- return false;
- }
+ size_t message_length = (size_t) (result + 1);
+ char *message = (char *) pm_arena_alloc(arena, message_length, 1);
va_start(arguments, diag_id);
- vsnprintf(message, length, format, arguments);
+ vsnprintf(message, message_length, format, arguments);
va_end(arguments);
*diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
+ .location = { .start = start, .length = length },
.diag_id = diag_id,
.message = message,
- .owned = true,
- .level = pm_diagnostic_level(diag_id)
+ .level = pm_diagnostic_id_level(diag_id)
};
pm_list_append(list, (pm_list_node_t *) diagnostic);
- return true;
-}
-
-/**
- * Deallocate the internal state of the given diagnostic list.
- */
-void
-pm_diagnostic_list_free(pm_list_t *list) {
- pm_diagnostic_t *node = (pm_diagnostic_t *) list->head;
-
- while (node != NULL) {
- pm_diagnostic_t *next = (pm_diagnostic_t *) node->node.next;
-
- if (node->owned) xfree((void *) node->message);
- xfree(node);
-
- node = next;
- }
}
diff --git a/prism/templates/src/json.c.erb b/prism/templates/src/json.c.erb
new file mode 100644
index 0000000000..5c4ab8d92a
--- /dev/null
+++ b/prism/templates/src/json.c.erb
@@ -0,0 +1,130 @@
+#include "prism/json.h"
+
+// Ensure this translation unit is never empty, even when JSON is excluded.
+typedef int pm_json_unused_t;
+
+#ifndef PRISM_EXCLUDE_JSON
+
+#include "prism/internal/buffer.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/parser.h"
+
+#include <inttypes.h>
+
+static void
+pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) {
+ const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
+ pm_buffer_append_byte(buffer, '"');
+ pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON);
+ pm_buffer_append_byte(buffer, '"');
+}
+
+static void
+pm_dump_json_location(pm_buffer_t *buffer, const pm_location_t *location) {
+ pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length);
+}
+
+/**
+ * Dump JSON to the given buffer.
+ */
+void
+pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) {
+ switch (PM_NODE_TYPE(node)) {
+ <%- nodes.each do |node| -%>
+ case <%= node.type %>: {
+ pm_buffer_append_string(buffer, "{\"type\":\"<%= node.name %>\",\"location\":", <%= node.name.bytesize + 22 %>);
+
+ const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node;
+ pm_dump_json_location(buffer, &cast->base.location);
+ <%- [*node.flags, *node.fields].each_with_index do |field, index| -%>
+
+ // Dump the <%= field.name %> field
+ pm_buffer_append_byte(buffer, ',');
+ <%- if field.is_a?(Prism::Template::Flags) -%>
+ pm_buffer_append_string(buffer, "\"flags\":", 8);
+ <%- else -%>
+ pm_buffer_append_string(buffer, "\"<%= field.name %>\":", <%= field.name.bytesize + 3 %>);
+ <%- end -%>
+ <%- case field -%>
+ <%- when Prism::Template::NodeField -%>
+ pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>);
+ <%- when Prism::Template::OptionalNodeField -%>
+ if (cast-><%= field.name %> != NULL) {
+ pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>);
+ } else {
+ pm_buffer_append_string(buffer, "null", 4);
+ }
+ <%- when Prism::Template::NodeListField -%>
+ const pm_node_list_t *<%= field.name %> = &cast-><%= field.name %>;
+ pm_buffer_append_byte(buffer, '[');
+
+ for (size_t index = 0; index < <%= field.name %>->size; index++) {
+ if (index != 0) pm_buffer_append_byte(buffer, ',');
+ pm_dump_json(buffer, parser, <%= field.name %>->nodes[index]);
+ }
+ pm_buffer_append_byte(buffer, ']');
+ <%- when Prism::Template::StringField -%>
+ const pm_string_t *<%= field.name %> = &cast-><%= field.name %>;
+ pm_buffer_append_byte(buffer, '"');
+ pm_buffer_append_source(buffer, pm_string_source(<%= field.name %>), pm_string_length(<%= field.name %>), PM_BUFFER_ESCAPING_JSON);
+ pm_buffer_append_byte(buffer, '"');
+ <%- when Prism::Template::ConstantField -%>
+ pm_dump_json_constant(buffer, parser, cast-><%= field.name %>);
+ <%- when Prism::Template::OptionalConstantField -%>
+ if (cast-><%= field.name %> != PM_CONSTANT_ID_UNSET) {
+ pm_dump_json_constant(buffer, parser, cast-><%= field.name %>);
+ } else {
+ pm_buffer_append_string(buffer, "null", 4);
+ }
+ <%- when Prism::Template::ConstantListField -%>
+ const pm_constant_id_list_t *<%= field.name %> = &cast-><%= field.name %>;
+ pm_buffer_append_byte(buffer, '[');
+
+ for (size_t index = 0; index < <%= field.name %>->size; index++) {
+ if (index != 0) pm_buffer_append_byte(buffer, ',');
+ pm_dump_json_constant(buffer, parser, <%= field.name %>->ids[index]);
+ }
+ pm_buffer_append_byte(buffer, ']');
+ <%- when Prism::Template::LocationField -%>
+ pm_dump_json_location(buffer, &cast-><%= field.name %>);
+ <%- when Prism::Template::OptionalLocationField -%>
+ if (cast-><%= field.name %>.length != 0) {
+ pm_dump_json_location(buffer, &cast-><%= field.name %>);
+ } else {
+ pm_buffer_append_string(buffer, "null", 4);
+ }
+ <%- when Prism::Template::UInt8Field -%>
+ pm_buffer_append_format(buffer, "%" PRIu8, cast-><%= field.name %>);
+ <%- when Prism::Template::UInt32Field -%>
+ pm_buffer_append_format(buffer, "%" PRIu32, cast-><%= field.name %>);
+ <%- when Prism::Template::Flags -%>
+ size_t flags = 0;
+ pm_buffer_append_byte(buffer, '[');
+ <%- node.flags.values.each_with_index do |value, index| -%>
+ if (PM_NODE_FLAG_P(cast, PM_<%= node.flags.human.upcase %>_<%= value.name %>)) {
+ if (flags != 0) pm_buffer_append_byte(buffer, ',');
+ pm_buffer_append_string(buffer, "\"<%= value.name %>\"", <%= value.name.bytesize + 2 %>);
+ flags++;
+ }
+ <%- end -%>
+ pm_buffer_append_byte(buffer, ']');
+ <%- when Prism::Template::IntegerField -%>
+ pm_integer_string(buffer, &cast-><%= field.name %>);
+ <%- when Prism::Template::DoubleField -%>
+ pm_buffer_append_format(buffer, "%f", cast-><%= field.name %>);
+ <%- else -%>
+ <%- raise %>
+ <%- end -%>
+ <%- end -%>
+
+ pm_buffer_append_byte(buffer, '}');
+ break;
+ }
+ <%- end -%>
+ case PM_SCOPE_NODE:
+ break;
+ }
+}
+
+#endif
diff --git a/prism/templates/src/node.c.erb b/prism/templates/src/node.c.erb
index 2357e55200..f51aff6e53 100644
--- a/prism/templates/src/node.c.erb
+++ b/prism/templates/src/node.c.erb
@@ -1,153 +1,85 @@
#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
-#include "prism/node.h"
+#include "prism/internal/node.h"
+
+#include "prism/internal/arena.h"
+
+#include <stdlib.h>
/**
* Attempts to grow the node list to the next size. If there is already
- * capacity in the list, this function does nothing. Otherwise it reallocates
- * the list to be twice as large as it was before. If the reallocation fails,
- * this function returns false, otherwise it returns true.
+ * capacity in the list, this function does nothing. Otherwise it allocates a
+ * new array from the arena (abandon-and-copy strategy) and copies the existing
+ * data into it.
*/
-static bool
-pm_node_list_grow(pm_node_list_t *list, size_t size) {
+static void
+pm_node_list_grow(pm_arena_t *arena, pm_node_list_t *list, size_t size) {
size_t requested_size = list->size + size;
- // If the requested size caused overflow, return false.
- if (requested_size < list->size) return false;
+ // Guard against overflow on the addition.
+ if (requested_size < list->size) abort();
- // If the requested size is within the existing capacity, return true.
- if (requested_size < list->capacity) return true;
+ // If the requested size is within the existing capacity, return.
+ if (requested_size <= list->capacity) return;
- // Otherwise, reallocate the list to be twice as large as it was before.
+ // Otherwise, compute the next capacity by doubling.
size_t next_capacity = list->capacity == 0 ? 4 : list->capacity * 2;
- // If multiplying by 2 caused overflow, return false.
- if (next_capacity < list->capacity) return false;
-
- // If we didn't get enough by doubling, keep doubling until we do.
+ // Guard against overflow on the doubling.
while (requested_size > next_capacity) {
- size_t double_capacity = next_capacity * 2;
-
- // Ensure we didn't overflow by multiplying by 2.
- if (double_capacity < next_capacity) return false;
- next_capacity = double_capacity;
+ if (next_capacity == 0) abort();
+ next_capacity *= 2;
}
- pm_node_t **nodes = (pm_node_t **) xrealloc(list->nodes, sizeof(pm_node_t *) * next_capacity);
- if (nodes == NULL) return false;
+ // Allocate a new array from the arena (old array is abandoned).
+ pm_node_t **nodes = (pm_node_t **) pm_arena_alloc(arena, sizeof(pm_node_t *) * next_capacity, PRISM_ALIGNOF(pm_node_t *));
+
+ // Copy old data into the new array.
+ if (list->size > 0) {
+ memcpy(nodes, list->nodes, list->size * sizeof(pm_node_t *));
+ }
list->nodes = nodes;
list->capacity = next_capacity;
- return true;
}
/**
- * Append a new node onto the end of the node list.
+ * Slow path for pm_node_list_append: grow the list and append the node.
+ * Do not call directly - use pm_node_list_append instead.
*/
void
-pm_node_list_append(pm_node_list_t *list, pm_node_t *node) {
- if (pm_node_list_grow(list, 1)) {
- list->nodes[list->size++] = node;
- }
+pm_node_list_append_slow(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) {
+ pm_node_list_grow(arena, list, 1);
+ list->nodes[list->size++] = node;
}
/**
* Prepend a new node onto the beginning of the node list.
*/
void
-pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node) {
- if (pm_node_list_grow(list, 1)) {
- memmove(list->nodes + 1, list->nodes, list->size * sizeof(pm_node_t *));
- list->nodes[0] = node;
- list->size++;
- }
+pm_node_list_prepend(pm_arena_t *arena, pm_node_list_t *list, pm_node_t *node) {
+ pm_node_list_grow(arena, list, 1);
+ memmove(list->nodes + 1, list->nodes, list->size * sizeof(pm_node_t *));
+ list->nodes[0] = node;
+ list->size++;
}
/**
* Concatenate the given node list onto the end of the other node list.
*/
void
-pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other) {
- if (other->size > 0 && pm_node_list_grow(list, other->size)) {
+pm_node_list_concat(pm_arena_t *arena, pm_node_list_t *list, pm_node_list_t *other) {
+ if (other->size > 0) {
+ pm_node_list_grow(arena, list, other->size);
memcpy(list->nodes + list->size, other->nodes, other->size * sizeof(pm_node_t *));
list->size += other->size;
}
}
/**
- * Free the internal memory associated with the given node list.
- */
-void
-pm_node_list_free(pm_node_list_t *list) {
- if (list->capacity > 0) {
- xfree(list->nodes);
- *list = (pm_node_list_t) { 0 };
- }
-}
-
-PRISM_EXPORTED_FUNCTION void
-pm_node_destroy(pm_parser_t *parser, pm_node_t *node);
-
-/**
- * Destroy the nodes that are contained within the given node list.
- */
-static void
-pm_node_list_destroy(pm_parser_t *parser, pm_node_list_t *list) {
- pm_node_t *node;
- PM_NODE_LIST_FOREACH(list, index, node) pm_node_destroy(parser, node);
- pm_node_list_free(list);
-}
-
-/**
- * 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 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- <%- if node.fields.any? { |field| ![Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField].include?(field.class) } -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField -%>
- <%- when Prism::Template::NodeField -%>
- pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
- <%- when Prism::Template::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
- }
- <%- when Prism::Template::StringField -%>
- pm_string_free(&cast-><%= field.name %>);
- <%- when Prism::Template::NodeListField -%>
- pm_node_list_destroy(parser, &cast-><%= field.name %>);
- <%- when Prism::Template::ConstantListField -%>
- pm_constant_id_list_free(&cast-><%= field.name %>);
- <%- when Prism::Template::IntegerField -%>
- pm_integer_free(&cast-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- break;
- }
- <%- end -%>
-#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
- default:
- assert(false && "unreachable");
- break;
- }
- xfree(node);
-}
-
-/**
* 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)
+const char *
+pm_node_type(pm_node_type_t node_type)
{
switch (node_type) {
<%- nodes.each do |node| -%>
@@ -166,7 +98,7 @@ pm_node_type_to_str(pm_node_type_t node_type)
* pointer and is passed to the visitor callback for consumers to use as they
* see fit.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) {
if (visitor(node, data)) pm_visit_child_nodes(node, visitor, data);
}
@@ -176,7 +108,7 @@ pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void
* default behavior for walking the tree that is called from pm_visit_node if
* the callback returns true.
*/
-PRISM_EXPORTED_FUNCTION void
+void
pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) {
switch (PM_NODE_TYPE(node)) {
<%- nodes.each do |node| -%>
@@ -212,122 +144,23 @@ pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *nod
break;
}
}
+<%- nodes.each do |node| -%>
-// We optionally support dumping to JSON. For systems that don't want or need
-// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define.
-#ifndef PRISM_EXCLUDE_JSON
-
-static void
-pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) {
- const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-}
-
-static void
-pm_dump_json_location(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_location_t *location) {
- uint32_t start = (uint32_t) (location->start - parser->start);
- uint32_t end = (uint32_t) (location->end - parser->start);
- pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"end\":%" PRIu32 "}", start, end);
-}
-
+<%- params = node.fields.map(&:c_param) -%>
/**
- * Dump JSON to the given buffer.
+ * Allocate and initialize a new <%= node.name %> node.
*/
-PRISM_EXPORTED_FUNCTION void
-pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
- case <%= node.type %>: {
- pm_buffer_append_string(buffer, "{\"type\":\"<%= node.name %>\",\"location\":", <%= node.name.bytesize + 22 %>);
-
- const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node;
- pm_dump_json_location(buffer, parser, &cast->base.location);
- <%- [*node.flags, *node.fields].each_with_index do |field, index| -%>
-
- // Dump the <%= field.name %> field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"<%= field.name %>\":", <%= field.name.bytesize + 3 %>);
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>);
- <%- when Prism::Template::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
- <%- when Prism::Template::NodeListField -%>
- const pm_node_list_t *<%= field.name %> = &cast-><%= field.name %>;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < <%= field.name %>->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, <%= field.name %>->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
- <%- when Prism::Template::StringField -%>
- const pm_string_t *<%= field.name %> = &cast-><%= field.name %>;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(<%= field.name %>), pm_string_length(<%= field.name %>), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
- <%- when Prism::Template::ConstantField -%>
- pm_dump_json_constant(buffer, parser, cast-><%= field.name %>);
- <%- when Prism::Template::OptionalConstantField -%>
- if (cast-><%= field.name %> != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast-><%= field.name %>);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
- <%- when Prism::Template::ConstantListField -%>
- const pm_constant_id_list_t *<%= field.name %> = &cast-><%= field.name %>;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < <%= field.name %>->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, <%= field.name %>->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
- <%- when Prism::Template::LocationField -%>
- pm_dump_json_location(buffer, parser, &cast-><%= field.name %>);
- <%- when Prism::Template::OptionalLocationField -%>
- if (cast-><%= field.name %>.start != NULL) {
- pm_dump_json_location(buffer, parser, &cast-><%= field.name %>);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
- <%- when Prism::Template::UInt8Field -%>
- pm_buffer_append_format(buffer, "%" PRIu8, cast-><%= field.name %>);
- <%- when Prism::Template::UInt32Field -%>
- pm_buffer_append_format(buffer, "%" PRIu32, cast-><%= field.name %>);
- <%- when Prism::Template::Flags -%>
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- <%- node.flags.values.each_with_index do |value, index| -%>
- if (PM_NODE_FLAG_P(cast, PM_<%= node.flags.human.upcase %>_<%= value.name %>)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"<%= value.name %>\"", <%= value.name.bytesize + 2 %>);
- flags++;
- }
- <%- end -%>
- pm_buffer_append_byte(buffer, ']');
- <%- when Prism::Template::IntegerField -%>
- pm_integer_string(buffer, &cast-><%= field.name %>);
- <%- when Prism::Template::DoubleField -%>
- pm_buffer_append_format(buffer, "%f", cast-><%= field.name %>);
- <%- else -%>
- <%- raise %>
- <%- end -%>
- <%- end -%>
+pm_<%= node.human %>_t *
+pm_<%= node.human %>_new(pm_arena_t *arena, uint32_t node_id, pm_node_flags_t flags, pm_location_t location<%= params.empty? ? "" : ", #{params.join(", ")}" %>) {
+ pm_<%= node.human %>_t *node = (pm_<%= node.human %>_t *) pm_arena_alloc(arena, sizeof(pm_<%= node.human %>_t), PRISM_ALIGNOF(pm_<%= node.human %>_t));
+
+ *node = (pm_<%= node.human %>_t) {
+ .base = { .type = <%= node.type %>, .flags = flags, .node_id = node_id, .location = location }<%= node.fields.empty? ? "" : "," %>
+<%- node.fields.each_with_index do |field, index| -%>
+ .<%= field.name %> = <%= field.name %><%= index < node.fields.size - 1 ? "," : "" %>
+<%- end -%>
+ };
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- <%- end -%>
- case PM_SCOPE_NODE:
- break;
- }
+ return node;
}
-
-#endif
+<%- end -%>
diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb
index 639c2fecf3..f12531d934 100644
--- a/prism/templates/src/prettyprint.c.erb
+++ b/prism/templates/src/prettyprint.c.erb
@@ -1,23 +1,34 @@
<%# encoding: ASCII -%>
#include "prism/prettyprint.h"
-// We optionally support pretty printing nodes. For systems that don't want or
-// need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_PRETTYPRINT define.
+/* We optionally support pretty printing nodes. For systems that don't want or
+ * need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_PRETTYPRINT define. */
#ifdef PRISM_EXCLUDE_PRETTYPRINT
-void pm_prettyprint(void) {}
+/* Ensure this translation unit is never empty, even when prettyprint is
+ * excluded. */
+typedef int pm_prettyprint_unused_t;
#else
-static inline void
+#include "prism/compiler/inline.h"
+#include "prism/internal/buffer.h"
+#include "prism/internal/constant_pool.h"
+#include "prism/internal/integer.h"
+#include "prism/internal/parser.h"
+#include "prism/line_offset_list.h"
+
+#include <inttypes.h>
+
+static PRISM_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, parser->start_line);
- pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end, parser->start_line);
+ pm_line_column_t start = pm_line_offset_list_line_column(&parser->line_offsets, location->start, parser->start_line);
+ pm_line_column_t end = pm_line_offset_list_line_column(&parser->line_offsets, location->start + location->length, parser->start_line);
pm_buffer_append_format(output_buffer, "(%" PRIi32 ",%" PRIu32 ")-(%" PRIi32 ",%" PRIu32 ")", start.line, start.column, end.line, end.column);
}
-static inline void
+static PRISM_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);
@@ -106,17 +117,17 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
pm_buffer_append_byte(output_buffer, ' ');
prettyprint_location(output_buffer, parser, location);
pm_buffer_append_string(output_buffer, " = \"", 4);
- pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY);
+ pm_buffer_append_source(output_buffer, parser->start + location->start, (size_t) location->length, PM_BUFFER_ESCAPING_RUBY);
pm_buffer_append_string(output_buffer, "\"\n", 2);
<%- when Prism::Template::OptionalLocationField -%>
pm_location_t *location = &cast-><%= field.name %>;
- if (location->start == NULL) {
+ if (location->length == 0) {
pm_buffer_append_string(output_buffer, " nil\n", 5);
} else {
pm_buffer_append_byte(output_buffer, ' ');
prettyprint_location(output_buffer, parser, location);
pm_buffer_append_string(output_buffer, " = \"", 4);
- pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY);
+ pm_buffer_append_source(output_buffer, parser->start + location->start, (size_t) location->length, PM_BUFFER_ESCAPING_RUBY);
pm_buffer_append_string(output_buffer, "\"\n", 2);
}
<%- when Prism::Template::UInt8Field -%>
@@ -156,11 +167,11 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm
/**
* Pretty-prints the AST represented by the given node to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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);
+ pm_buffer_cleanup(&prefix_buffer);
}
#endif
diff --git a/prism/templates/src/serialize.c.erb b/prism/templates/src/serialize.c.erb
index 3e15a11039..3d9811e5db 100644
--- a/prism/templates/src/serialize.c.erb
+++ b/prism/templates/src/serialize.c.erb
@@ -1,57 +1,58 @@
-#include "prism.h"
+#include "prism/excludes.h"
+
+/* We optionally support serializing to a binary string. For systems that do not
+ * want or need this functionality, it can be turned off with the
+ * PRISM_EXCLUDE_SERIALIZATION define. */
+#ifdef PRISM_EXCLUDE_SERIALIZATION
+
+/* Ensure this translation unit is never empty, even when serialization is
+ * excluded. */
+typedef int pm_serialize_unused_t;
+
+#else
+
+#include "prism/compiler/inline.h"
-// We optionally support serializing to a binary string. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_SERIALIZATION define.
-#ifndef PRISM_EXCLUDE_SERIALIZATION
+#include "prism/internal/buffer.h"
+#include "prism/internal/comments.h"
+#include "prism/internal/diagnostic.h"
+#include "prism/internal/encoding.h"
+#include "prism/internal/list.h"
+#include "prism/internal/magic_comments.h"
+#include "prism/internal/options.h"
+#include "prism/internal/parser.h"
+#include "prism.h"
+#include "prism/ast.h"
+#include "prism/line_offset_list.h"
+
+#include <assert.h>
#include <stdio.h>
+#include <string.h>
-static inline uint32_t
+static PRISM_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
+static PRISM_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));
+pm_serialize_location(const pm_location_t *location, pm_buffer_t *buffer) {
+ pm_buffer_append_varuint(buffer, location->start);
+ pm_buffer_append_varuint(buffer, location->length);
}
static void
-pm_serialize_string(const pm_parser_t *parser, const 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;
- }
-#ifdef PRISM_HAS_MMAP
- case PM_STRING_MAPPED:
- assert(false && "Cannot serialize mapped strings.");
- break;
-#endif
- }
+pm_serialize_string(const pm_string_t *string, pm_buffer_t *buffer) {
+ uint32_t length = pm_sizet_to_u32(pm_string_length(string));
+ pm_buffer_append_varuint(buffer, length);
+ pm_buffer_append_bytes(buffer, pm_string_source(string), length);
}
static void
@@ -72,12 +73,10 @@ 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;
-
<%- if Prism::Template::INCLUDE_NODE_ID -%>
pm_buffer_append_varuint(buffer, node->node_id);
<%- end -%>
- pm_serialize_location(parser, &node->location, buffer);
+ pm_serialize_location(&node->location, buffer);
switch (PM_NODE_TYPE(node)) {
// We do not need to serialize a ScopeNode ever as
@@ -106,7 +105,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
}
<%- when Prism::Template::StringField -%>
- pm_serialize_string(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
+ pm_serialize_string(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
<%- when Prism::Template::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);
@@ -123,15 +122,15 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
}
<%- when Prism::Template::LocationField -%>
<%- if field.should_be_serialized? -%>
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
+ pm_serialize_location(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
<%- end -%>
<%- when Prism::Template::OptionalLocationField -%>
<%- if field.should_be_serialized? -%>
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %>.start == NULL) {
+ if (((pm_<%= node.human %>_t *)node)-><%= field.name %>.length == 0) {
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);
+ pm_serialize_location(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
}
<%- end -%>
<%- when Prism::Template::UInt8Field -%>
@@ -148,7 +147,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
<%- end -%>
<%- if node.needs_serialized_length? -%>
// serialize length
- uint32_t length = pm_sizet_to_u32(buffer->length - offset - sizeof(uint32_t));
+ uint32_t length = pm_sizet_to_u32(buffer->length - length_offset);
memcpy(buffer->value + length_offset, &length, sizeof(uint32_t));
<%- end -%>
break;
@@ -158,7 +157,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
}
static void
-pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
+pm_serialize_line_offset_list(pm_line_offset_list_t *list, pm_buffer_t *buffer) {
uint32_t size = pm_sizet_to_u32(list->size);
pm_buffer_append_varuint(buffer, size);
@@ -169,60 +168,60 @@ pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
}
static void
-pm_serialize_comment(pm_parser_t *parser, pm_comment_t *comment, pm_buffer_t *buffer) {
+pm_serialize_comment(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);
+ pm_serialize_location(&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_serialize_comment_list(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);
+ pm_serialize_comment(comment, buffer);
}
}
static void
-pm_serialize_magic_comment(pm_parser_t *parser, pm_magic_comment_t *magic_comment, pm_buffer_t *buffer) {
+pm_serialize_magic_comment(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));
+ pm_buffer_append_varuint(buffer, magic_comment->key.start);
+ pm_buffer_append_varuint(buffer, 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));
+ pm_buffer_append_varuint(buffer, magic_comment->value.start);
+ pm_buffer_append_varuint(buffer, magic_comment->value.length);
}
static void
-pm_serialize_magic_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
+pm_serialize_magic_comment_list(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);
+ pm_serialize_magic_comment(magic_comment, buffer);
}
}
static void
pm_serialize_data_loc(const pm_parser_t *parser, pm_buffer_t *buffer) {
- if (parser->data_loc.end == NULL) {
+ if (parser->data_loc.length == 0) {
pm_buffer_append_byte(buffer, 0);
} else {
pm_buffer_append_byte(buffer, 1);
- pm_serialize_location(parser, &parser->data_loc, buffer);
+ pm_serialize_location(&parser->data_loc, buffer);
}
}
static void
-pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
+pm_serialize_diagnostic(pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
// serialize the type
pm_buffer_append_varuint(buffer, (uint32_t) diagnostic->diag_id);
@@ -232,18 +231,18 @@ pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buf
pm_buffer_append_string(buffer, diagnostic->message, message_length);
// serialize location
- pm_serialize_location(parser, &diagnostic->location, buffer);
+ pm_serialize_location(&diagnostic->location, buffer);
pm_buffer_append_byte(buffer, diagnostic->level);
}
static void
-pm_serialize_diagnostic_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
+pm_serialize_diagnostic_list(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);
+ pm_serialize_diagnostic(diagnostic, buffer);
}
}
@@ -261,14 +260,15 @@ static void
pm_serialize_metadata(pm_parser_t *parser, pm_buffer_t *buffer) {
pm_serialize_encoding(parser->encoding, buffer);
pm_buffer_append_varsint(buffer, parser->start_line);
- pm_serialize_newline_list(&parser->newline_list, buffer);
+ pm_serialize_line_offset_list(&parser->line_offsets, buffer);
<%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
- pm_serialize_comment_list(parser, &parser->comment_list, buffer);
+ pm_serialize_comment_list(&parser->comment_list, buffer);
<%- end -%>
- pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer);
+ pm_serialize_magic_comment_list(&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_serialize_diagnostic_list(&parser->error_list, buffer);
+ pm_serialize_diagnostic_list(&parser->warning_list, buffer);
+ pm_buffer_append_byte(buffer, (uint8_t) parser->continuable);
}
#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
@@ -308,28 +308,12 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
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);
+ // Write the constant contents into the buffer after the constant
+ // pool. In place of the source offset, we store a buffer offset.
+ uint32_t content_offset = pm_sizet_to_u32(buffer->length);
+ memcpy(buffer->value + buffer_offset, &content_offset, 4);
+ pm_buffer_append_bytes(buffer, constant->start, constant->length);
- 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);
}
@@ -337,7 +321,7 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
}
static void
-serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
+serialize_token(pm_parser_t *parser, pm_token_t *token, void *data) {
pm_buffer_t *buffer = (pm_buffer_t *) data;
pm_buffer_append_varuint(buffer, token->type);
@@ -349,58 +333,72 @@ serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
/**
* Lex the given source and serialize to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
+ pm_parser_init(&arena, &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_parser_lex_callback_set(&parser, serialize_token, buffer);
+ pm_parse(&parser);
// Append 0 to mark end of tokens.
pm_buffer_append_byte(buffer, 0);
pm_serialize_metadata(&parser, buffer);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
}
/**
* Parse and serialize both the AST and the tokens represented by the given
* source to the given buffer.
*/
-PRISM_EXPORTED_FUNCTION void
+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_arena_t arena = { 0 };
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,
- };
+ pm_parser_init(&arena, &parser, source, size, &options);
- parser.lex_callback = &lex_callback;
+ pm_parser_lex_callback_set(&parser, serialize_token, buffer);
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);
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
+}
+
+/**
+ * Parse the source and return true if it parses without errors or warnings.
+ */
+bool
+pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) {
+ pm_options_t options = { 0 };
+ pm_options_read(&options, data);
+
+ pm_arena_t arena = { 0 };
+ pm_parser_t parser;
+ pm_parser_init(&arena, &parser, source, size, &options);
+
+ pm_parse(&parser);
+
+ bool result = parser.error_list.size == 0;
+ pm_parser_cleanup(&parser);
+ pm_arena_cleanup(&arena);
+ pm_options_cleanup(&options);
+
+ return result;
}
#endif
diff --git a/prism/templates/src/token_type.c.erb b/prism/templates/src/token_type.c.erb
deleted file mode 100644
index f196393ee1..0000000000
--- a/prism/templates/src/token_type.c.erb
+++ /dev/null
@@ -1,369 +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_name(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:
- assert(false && "unreachable");
- return "";
- }
-
- // Provide a default, because some compilers can't determine that the above
- // switch is exhaustive.
- assert(false && "unreachable");
- return "";
-}
-
-/**
- * Returns the human name of the given token type.
- */
-const char *
-pm_token_type_human(pm_token_type_t token_type) {
- switch (token_type) {
- case PM_TOKEN_EOF:
- return "end-of-input";
- case PM_TOKEN_MISSING:
- return "missing token";
- case PM_TOKEN_NOT_PROVIDED:
- return "not provided token";
- case PM_TOKEN_AMPERSAND:
- return "'&'";
- case PM_TOKEN_AMPERSAND_AMPERSAND:
- return "'&&'";
- case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL:
- return "'&&='";
- case PM_TOKEN_AMPERSAND_DOT:
- return "'&.'";
- case PM_TOKEN_AMPERSAND_EQUAL:
- return "'&='";
- case PM_TOKEN_BACKTICK:
- return "'`'";
- case PM_TOKEN_BACK_REFERENCE:
- return "back reference";
- case PM_TOKEN_BANG:
- return "'!'";
- case PM_TOKEN_BANG_EQUAL:
- return "'!='";
- case PM_TOKEN_BANG_TILDE:
- return "'!~'";
- case PM_TOKEN_BRACE_LEFT:
- return "'{'";
- case PM_TOKEN_BRACE_RIGHT:
- return "'}'";
- case PM_TOKEN_BRACKET_LEFT:
- return "'['";
- case PM_TOKEN_BRACKET_LEFT_ARRAY:
- return "'['";
- case PM_TOKEN_BRACKET_LEFT_RIGHT:
- return "'[]'";
- case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL:
- return "'[]='";
- case PM_TOKEN_BRACKET_RIGHT:
- return "']'";
- case PM_TOKEN_CARET:
- return "'^'";
- case PM_TOKEN_CARET_EQUAL:
- return "'^='";
- case PM_TOKEN_CHARACTER_LITERAL:
- return "character literal";
- case PM_TOKEN_CLASS_VARIABLE:
- return "class variable";
- case PM_TOKEN_COLON:
- return "':'";
- case PM_TOKEN_COLON_COLON:
- return "'::'";
- case PM_TOKEN_COMMA:
- return "','";
- case PM_TOKEN_COMMENT:
- return "comment";
- case PM_TOKEN_CONSTANT:
- return "constant";
- case PM_TOKEN_DOT:
- return "'.'";
- case PM_TOKEN_DOT_DOT:
- return "..";
- case PM_TOKEN_DOT_DOT_DOT:
- return "...";
- case PM_TOKEN_EMBDOC_BEGIN:
- return "'=begin'";
- case PM_TOKEN_EMBDOC_END:
- return "'=end'";
- case PM_TOKEN_EMBDOC_LINE:
- return "embedded documentation line";
- case PM_TOKEN_EMBEXPR_BEGIN:
- return "'#{'";
- case PM_TOKEN_EMBEXPR_END:
- return "'}'";
- case PM_TOKEN_EMBVAR:
- return "'#'";
- case PM_TOKEN_EQUAL:
- return "'='";
- case PM_TOKEN_EQUAL_EQUAL:
- return "'=='";
- case PM_TOKEN_EQUAL_EQUAL_EQUAL:
- return "'==='";
- case PM_TOKEN_EQUAL_GREATER:
- return "'=>'";
- case PM_TOKEN_EQUAL_TILDE:
- return "'=~'";
- case PM_TOKEN_FLOAT:
- return "float";
- case PM_TOKEN_FLOAT_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_FLOAT_RATIONAL:
- return "rational";
- case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_GLOBAL_VARIABLE:
- return "global variable";
- case PM_TOKEN_GREATER:
- return "'>'";
- case PM_TOKEN_GREATER_EQUAL:
- return "'>='";
- case PM_TOKEN_GREATER_GREATER:
- return ">>";
- case PM_TOKEN_GREATER_GREATER_EQUAL:
- return ">>=";
- case PM_TOKEN_HEREDOC_END:
- return "heredoc ending";
- case PM_TOKEN_HEREDOC_START:
- return "heredoc beginning";
- case PM_TOKEN_IDENTIFIER:
- return "local variable or method";
- case PM_TOKEN_IGNORED_NEWLINE:
- return "ignored newline";
- case PM_TOKEN_INSTANCE_VARIABLE:
- return "instance variable";
- case PM_TOKEN_INTEGER:
- return "integer";
- case PM_TOKEN_INTEGER_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_INTEGER_RATIONAL:
- return "rational";
- case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_KEYWORD_ALIAS:
- return "'alias'";
- case PM_TOKEN_KEYWORD_AND:
- return "'and'";
- case PM_TOKEN_KEYWORD_BEGIN:
- return "'begin'";
- case PM_TOKEN_KEYWORD_BEGIN_UPCASE:
- return "'BEGIN'";
- case PM_TOKEN_KEYWORD_BREAK:
- return "'break'";
- case PM_TOKEN_KEYWORD_CASE:
- return "'case'";
- case PM_TOKEN_KEYWORD_CLASS:
- return "'class'";
- case PM_TOKEN_KEYWORD_DEF:
- return "'def'";
- case PM_TOKEN_KEYWORD_DEFINED:
- return "'defined?'";
- case PM_TOKEN_KEYWORD_DO:
- return "'do'";
- case PM_TOKEN_KEYWORD_DO_LOOP:
- return "'do'";
- case PM_TOKEN_KEYWORD_ELSE:
- return "'else'";
- case PM_TOKEN_KEYWORD_ELSIF:
- return "'elsif'";
- case PM_TOKEN_KEYWORD_END:
- return "'end'";
- case PM_TOKEN_KEYWORD_END_UPCASE:
- return "'END'";
- case PM_TOKEN_KEYWORD_ENSURE:
- return "'ensure'";
- case PM_TOKEN_KEYWORD_FALSE:
- return "'false'";
- case PM_TOKEN_KEYWORD_FOR:
- return "'for'";
- case PM_TOKEN_KEYWORD_IF:
- return "'if'";
- case PM_TOKEN_KEYWORD_IF_MODIFIER:
- return "'if'";
- case PM_TOKEN_KEYWORD_IN:
- return "'in'";
- case PM_TOKEN_KEYWORD_MODULE:
- return "'module'";
- case PM_TOKEN_KEYWORD_NEXT:
- return "'next'";
- case PM_TOKEN_KEYWORD_NIL:
- return "'nil'";
- case PM_TOKEN_KEYWORD_NOT:
- return "'not'";
- case PM_TOKEN_KEYWORD_OR:
- return "'or'";
- case PM_TOKEN_KEYWORD_REDO:
- return "'redo'";
- case PM_TOKEN_KEYWORD_RESCUE:
- return "'rescue'";
- case PM_TOKEN_KEYWORD_RESCUE_MODIFIER:
- return "'rescue' modifier";
- case PM_TOKEN_KEYWORD_RETRY:
- return "'retry'";
- case PM_TOKEN_KEYWORD_RETURN:
- return "'return'";
- case PM_TOKEN_KEYWORD_SELF:
- return "'self'";
- case PM_TOKEN_KEYWORD_SUPER:
- return "'super'";
- case PM_TOKEN_KEYWORD_THEN:
- return "'then'";
- case PM_TOKEN_KEYWORD_TRUE:
- return "'true'";
- case PM_TOKEN_KEYWORD_UNDEF:
- return "'undef'";
- case PM_TOKEN_KEYWORD_UNLESS:
- return "'unless'";
- case PM_TOKEN_KEYWORD_UNLESS_MODIFIER:
- return "'unless'";
- case PM_TOKEN_KEYWORD_UNTIL:
- return "'until'";
- case PM_TOKEN_KEYWORD_UNTIL_MODIFIER:
- return "'until'";
- case PM_TOKEN_KEYWORD_WHEN:
- return "'when'";
- case PM_TOKEN_KEYWORD_WHILE:
- return "'while'";
- case PM_TOKEN_KEYWORD_WHILE_MODIFIER:
- return "'while'";
- case PM_TOKEN_KEYWORD_YIELD:
- return "'yield'";
- case PM_TOKEN_KEYWORD___ENCODING__:
- return "'__ENCODING__'";
- case PM_TOKEN_KEYWORD___FILE__:
- return "'__FILE__'";
- case PM_TOKEN_KEYWORD___LINE__:
- return "'__LINE__'";
- case PM_TOKEN_LABEL:
- return "label";
- case PM_TOKEN_LABEL_END:
- return "label terminator";
- case PM_TOKEN_LAMBDA_BEGIN:
- return "'{'";
- case PM_TOKEN_LESS:
- return "'<'";
- case PM_TOKEN_LESS_EQUAL:
- return "'<='";
- case PM_TOKEN_LESS_EQUAL_GREATER:
- return "'<=>'";
- case PM_TOKEN_LESS_LESS:
- return "<<";
- case PM_TOKEN_LESS_LESS_EQUAL:
- return "<<=";
- case PM_TOKEN_METHOD_NAME:
- return "method name";
- case PM_TOKEN_MINUS:
- return "'-'";
- case PM_TOKEN_MINUS_EQUAL:
- return "'-='";
- case PM_TOKEN_MINUS_GREATER:
- return "'->'";
- case PM_TOKEN_NEWLINE:
- return "newline";
- case PM_TOKEN_NUMBERED_REFERENCE:
- return "numbered reference";
- case PM_TOKEN_PARENTHESIS_LEFT:
- return "'('";
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
- return "'('";
- case PM_TOKEN_PARENTHESIS_RIGHT:
- return "')'";
- case PM_TOKEN_PERCENT:
- return "'%'";
- case PM_TOKEN_PERCENT_EQUAL:
- return "'%='";
- case PM_TOKEN_PERCENT_LOWER_I:
- return "'%i'";
- case PM_TOKEN_PERCENT_LOWER_W:
- return "'%w'";
- case PM_TOKEN_PERCENT_LOWER_X:
- return "'%x'";
- case PM_TOKEN_PERCENT_UPPER_I:
- return "'%I'";
- case PM_TOKEN_PERCENT_UPPER_W:
- return "'%W'";
- case PM_TOKEN_PIPE:
- return "'|'";
- case PM_TOKEN_PIPE_EQUAL:
- return "'|='";
- case PM_TOKEN_PIPE_PIPE:
- return "'||'";
- case PM_TOKEN_PIPE_PIPE_EQUAL:
- return "'||='";
- case PM_TOKEN_PLUS:
- return "'+'";
- case PM_TOKEN_PLUS_EQUAL:
- return "'+='";
- case PM_TOKEN_QUESTION_MARK:
- return "'?'";
- case PM_TOKEN_REGEXP_BEGIN:
- return "regular expression beginning";
- case PM_TOKEN_REGEXP_END:
- return "regular expression ending";
- case PM_TOKEN_SEMICOLON:
- return "';'";
- case PM_TOKEN_SLASH:
- return "'/'";
- case PM_TOKEN_SLASH_EQUAL:
- return "'/='";
- case PM_TOKEN_STAR:
- return "'*'";
- case PM_TOKEN_STAR_EQUAL:
- return "'*='";
- case PM_TOKEN_STAR_STAR:
- return "'**'";
- case PM_TOKEN_STAR_STAR_EQUAL:
- return "'**='";
- case PM_TOKEN_STRING_BEGIN:
- return "string literal";
- case PM_TOKEN_STRING_CONTENT:
- return "string content";
- case PM_TOKEN_STRING_END:
- return "string ending";
- case PM_TOKEN_SYMBOL_BEGIN:
- return "symbol literal";
- case PM_TOKEN_TILDE:
- return "'~'";
- case PM_TOKEN_UAMPERSAND:
- return "'&'";
- case PM_TOKEN_UCOLON_COLON:
- return "'::'";
- case PM_TOKEN_UDOT_DOT:
- return "'..'";
- case PM_TOKEN_UDOT_DOT_DOT:
- return "'...'";
- case PM_TOKEN_UMINUS:
- return "'-'";
- case PM_TOKEN_UMINUS_NUM:
- return "'-'";
- case PM_TOKEN_UPLUS:
- return "'+'";
- case PM_TOKEN_USTAR:
- return "*";
- case PM_TOKEN_USTAR_STAR:
- return "**";
- case PM_TOKEN_WORDS_SEP:
- return "string separator";
- case PM_TOKEN___END__:
- return "'__END__'";
- case PM_TOKEN_MAXIMUM:
- assert(false && "unreachable");
- return "";
- }
-
- // Provide a default, because some compilers can't determine that the above
- // switch is exhaustive.
- assert(false && "unreachable");
- return "";
-}
diff --git a/prism/templates/src/tokens.c.erb b/prism/templates/src/tokens.c.erb
new file mode 100644
index 0000000000..1e82954738
--- /dev/null
+++ b/prism/templates/src/tokens.c.erb
@@ -0,0 +1,367 @@
+#include "prism/ast.h"
+
+#include <assert.h>
+
+/**
+ * Returns a string representation of the given token type.
+ */
+const char *
+pm_token_type(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:
+ assert(false && "unreachable");
+ return "";
+ }
+
+ // Provide a default, because some compilers can't determine that the above
+ // switch is exhaustive.
+ assert(false && "unreachable");
+ return "";
+}
+
+/**
+ * Returns the human name of the given token type.
+ */
+const char *
+pm_token_str(pm_token_type_t token_type) {
+ switch (token_type) {
+ case PM_TOKEN_EOF:
+ return "end-of-input";
+ case PM_TOKEN_AMPERSAND:
+ return "'&'";
+ case PM_TOKEN_AMPERSAND_AMPERSAND:
+ return "'&&'";
+ case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL:
+ return "'&&='";
+ case PM_TOKEN_AMPERSAND_DOT:
+ return "'&.'";
+ case PM_TOKEN_AMPERSAND_EQUAL:
+ return "'&='";
+ case PM_TOKEN_BACKTICK:
+ return "'`'";
+ case PM_TOKEN_BACK_REFERENCE:
+ return "back reference";
+ case PM_TOKEN_BANG:
+ return "'!'";
+ case PM_TOKEN_BANG_EQUAL:
+ return "'!='";
+ case PM_TOKEN_BANG_TILDE:
+ return "'!~'";
+ case PM_TOKEN_BRACE_LEFT:
+ return "'{'";
+ case PM_TOKEN_BRACE_RIGHT:
+ return "'}'";
+ case PM_TOKEN_BRACKET_LEFT:
+ return "'['";
+ case PM_TOKEN_BRACKET_LEFT_ARRAY:
+ return "'['";
+ case PM_TOKEN_BRACKET_LEFT_RIGHT:
+ return "'[]'";
+ case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL:
+ return "'[]='";
+ case PM_TOKEN_BRACKET_RIGHT:
+ return "']'";
+ case PM_TOKEN_CARET:
+ return "'^'";
+ case PM_TOKEN_CARET_EQUAL:
+ return "'^='";
+ case PM_TOKEN_CHARACTER_LITERAL:
+ return "character literal";
+ case PM_TOKEN_CLASS_VARIABLE:
+ return "class variable";
+ case PM_TOKEN_COLON:
+ return "':'";
+ case PM_TOKEN_COLON_COLON:
+ return "'::'";
+ case PM_TOKEN_COMMA:
+ return "','";
+ case PM_TOKEN_COMMENT:
+ return "comment";
+ case PM_TOKEN_CONSTANT:
+ return "constant";
+ case PM_TOKEN_DOT:
+ return "'.'";
+ case PM_TOKEN_DOT_DOT:
+ return "..";
+ case PM_TOKEN_DOT_DOT_DOT:
+ return "...";
+ case PM_TOKEN_EMBDOC_BEGIN:
+ return "'=begin'";
+ case PM_TOKEN_EMBDOC_END:
+ return "'=end'";
+ case PM_TOKEN_EMBDOC_LINE:
+ return "embedded documentation line";
+ case PM_TOKEN_EMBEXPR_BEGIN:
+ return "'#{'";
+ case PM_TOKEN_EMBEXPR_END:
+ return "'}'";
+ case PM_TOKEN_EMBVAR:
+ return "'#'";
+ case PM_TOKEN_EQUAL:
+ return "'='";
+ case PM_TOKEN_EQUAL_EQUAL:
+ return "'=='";
+ case PM_TOKEN_EQUAL_EQUAL_EQUAL:
+ return "'==='";
+ case PM_TOKEN_EQUAL_GREATER:
+ return "'=>'";
+ case PM_TOKEN_EQUAL_TILDE:
+ return "'=~'";
+ case PM_TOKEN_FLOAT:
+ return "float";
+ case PM_TOKEN_FLOAT_IMAGINARY:
+ return "imaginary";
+ case PM_TOKEN_FLOAT_RATIONAL:
+ return "rational";
+ case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
+ return "imaginary";
+ case PM_TOKEN_GLOBAL_VARIABLE:
+ return "global variable";
+ case PM_TOKEN_GREATER:
+ return "'>'";
+ case PM_TOKEN_GREATER_EQUAL:
+ return "'>='";
+ case PM_TOKEN_GREATER_GREATER:
+ return ">>";
+ case PM_TOKEN_GREATER_GREATER_EQUAL:
+ return ">>=";
+ case PM_TOKEN_HEREDOC_END:
+ return "heredoc ending";
+ case PM_TOKEN_HEREDOC_START:
+ return "heredoc beginning";
+ case PM_TOKEN_IDENTIFIER:
+ return "local variable or method";
+ case PM_TOKEN_IGNORED_NEWLINE:
+ return "ignored newline";
+ case PM_TOKEN_INSTANCE_VARIABLE:
+ return "instance variable";
+ case PM_TOKEN_INTEGER:
+ return "integer";
+ case PM_TOKEN_INTEGER_IMAGINARY:
+ return "imaginary";
+ case PM_TOKEN_INTEGER_RATIONAL:
+ return "rational";
+ case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY:
+ return "imaginary";
+ case PM_TOKEN_KEYWORD_ALIAS:
+ return "'alias'";
+ case PM_TOKEN_KEYWORD_AND:
+ return "'and'";
+ case PM_TOKEN_KEYWORD_BEGIN:
+ return "'begin'";
+ case PM_TOKEN_KEYWORD_BEGIN_UPCASE:
+ return "'BEGIN'";
+ case PM_TOKEN_KEYWORD_BREAK:
+ return "'break'";
+ case PM_TOKEN_KEYWORD_CASE:
+ return "'case'";
+ case PM_TOKEN_KEYWORD_CLASS:
+ return "'class'";
+ case PM_TOKEN_KEYWORD_DEF:
+ return "'def'";
+ case PM_TOKEN_KEYWORD_DEFINED:
+ return "'defined?'";
+ case PM_TOKEN_KEYWORD_DO:
+ return "'do'";
+ case PM_TOKEN_KEYWORD_DO_BLOCK:
+ return "'do'";
+ case PM_TOKEN_KEYWORD_DO_LOOP:
+ return "'do'";
+ case PM_TOKEN_KEYWORD_ELSE:
+ return "'else'";
+ case PM_TOKEN_KEYWORD_ELSIF:
+ return "'elsif'";
+ case PM_TOKEN_KEYWORD_END:
+ return "'end'";
+ case PM_TOKEN_KEYWORD_END_UPCASE:
+ return "'END'";
+ case PM_TOKEN_KEYWORD_ENSURE:
+ return "'ensure'";
+ case PM_TOKEN_KEYWORD_FALSE:
+ return "'false'";
+ case PM_TOKEN_KEYWORD_FOR:
+ return "'for'";
+ case PM_TOKEN_KEYWORD_IF:
+ return "'if'";
+ case PM_TOKEN_KEYWORD_IF_MODIFIER:
+ return "'if'";
+ case PM_TOKEN_KEYWORD_IN:
+ return "'in'";
+ case PM_TOKEN_KEYWORD_MODULE:
+ return "'module'";
+ case PM_TOKEN_KEYWORD_NEXT:
+ return "'next'";
+ case PM_TOKEN_KEYWORD_NIL:
+ return "'nil'";
+ case PM_TOKEN_KEYWORD_NOT:
+ return "'not'";
+ case PM_TOKEN_KEYWORD_OR:
+ return "'or'";
+ case PM_TOKEN_KEYWORD_REDO:
+ return "'redo'";
+ case PM_TOKEN_KEYWORD_RESCUE:
+ return "'rescue'";
+ case PM_TOKEN_KEYWORD_RESCUE_MODIFIER:
+ return "'rescue' modifier";
+ case PM_TOKEN_KEYWORD_RETRY:
+ return "'retry'";
+ case PM_TOKEN_KEYWORD_RETURN:
+ return "'return'";
+ case PM_TOKEN_KEYWORD_SELF:
+ return "'self'";
+ case PM_TOKEN_KEYWORD_SUPER:
+ return "'super'";
+ case PM_TOKEN_KEYWORD_THEN:
+ return "'then'";
+ case PM_TOKEN_KEYWORD_TRUE:
+ return "'true'";
+ case PM_TOKEN_KEYWORD_UNDEF:
+ return "'undef'";
+ case PM_TOKEN_KEYWORD_UNLESS:
+ return "'unless'";
+ case PM_TOKEN_KEYWORD_UNLESS_MODIFIER:
+ return "'unless'";
+ case PM_TOKEN_KEYWORD_UNTIL:
+ return "'until'";
+ case PM_TOKEN_KEYWORD_UNTIL_MODIFIER:
+ return "'until'";
+ case PM_TOKEN_KEYWORD_WHEN:
+ return "'when'";
+ case PM_TOKEN_KEYWORD_WHILE:
+ return "'while'";
+ case PM_TOKEN_KEYWORD_WHILE_MODIFIER:
+ return "'while'";
+ case PM_TOKEN_KEYWORD_YIELD:
+ return "'yield'";
+ case PM_TOKEN_KEYWORD___ENCODING__:
+ return "'__ENCODING__'";
+ case PM_TOKEN_KEYWORD___FILE__:
+ return "'__FILE__'";
+ case PM_TOKEN_KEYWORD___LINE__:
+ return "'__LINE__'";
+ case PM_TOKEN_LABEL:
+ return "label";
+ case PM_TOKEN_LABEL_END:
+ return "label terminator";
+ case PM_TOKEN_LAMBDA_BEGIN:
+ return "'{'";
+ case PM_TOKEN_LESS:
+ return "'<'";
+ case PM_TOKEN_LESS_EQUAL:
+ return "'<='";
+ case PM_TOKEN_LESS_EQUAL_GREATER:
+ return "'<=>'";
+ case PM_TOKEN_LESS_LESS:
+ return "<<";
+ case PM_TOKEN_LESS_LESS_EQUAL:
+ return "<<=";
+ case PM_TOKEN_METHOD_NAME:
+ return "method name";
+ case PM_TOKEN_MINUS:
+ return "'-'";
+ case PM_TOKEN_MINUS_EQUAL:
+ return "'-='";
+ case PM_TOKEN_MINUS_GREATER:
+ return "'->'";
+ case PM_TOKEN_NEWLINE:
+ return "newline";
+ case PM_TOKEN_NUMBERED_REFERENCE:
+ return "numbered reference";
+ case PM_TOKEN_PARENTHESIS_LEFT:
+ return "'('";
+ case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
+ return "'('";
+ case PM_TOKEN_PARENTHESIS_RIGHT:
+ return "')'";
+ case PM_TOKEN_PERCENT:
+ return "'%'";
+ case PM_TOKEN_PERCENT_EQUAL:
+ return "'%='";
+ case PM_TOKEN_PERCENT_LOWER_I:
+ return "'%i'";
+ case PM_TOKEN_PERCENT_LOWER_W:
+ return "'%w'";
+ case PM_TOKEN_PERCENT_LOWER_X:
+ return "'%x'";
+ case PM_TOKEN_PERCENT_UPPER_I:
+ return "'%I'";
+ case PM_TOKEN_PERCENT_UPPER_W:
+ return "'%W'";
+ case PM_TOKEN_PIPE:
+ return "'|'";
+ case PM_TOKEN_PIPE_EQUAL:
+ return "'|='";
+ case PM_TOKEN_PIPE_PIPE:
+ return "'||'";
+ case PM_TOKEN_PIPE_PIPE_EQUAL:
+ return "'||='";
+ case PM_TOKEN_PLUS:
+ return "'+'";
+ case PM_TOKEN_PLUS_EQUAL:
+ return "'+='";
+ case PM_TOKEN_QUESTION_MARK:
+ return "'?'";
+ case PM_TOKEN_REGEXP_BEGIN:
+ return "regular expression beginning";
+ case PM_TOKEN_REGEXP_END:
+ return "regular expression ending";
+ case PM_TOKEN_SEMICOLON:
+ return "';'";
+ case PM_TOKEN_SLASH:
+ return "'/'";
+ case PM_TOKEN_SLASH_EQUAL:
+ return "'/='";
+ case PM_TOKEN_STAR:
+ return "'*'";
+ case PM_TOKEN_STAR_EQUAL:
+ return "'*='";
+ case PM_TOKEN_STAR_STAR:
+ return "'**'";
+ case PM_TOKEN_STAR_STAR_EQUAL:
+ return "'**='";
+ case PM_TOKEN_STRING_BEGIN:
+ return "string literal";
+ case PM_TOKEN_STRING_CONTENT:
+ return "string content";
+ case PM_TOKEN_STRING_END:
+ return "string ending";
+ case PM_TOKEN_SYMBOL_BEGIN:
+ return "symbol literal";
+ case PM_TOKEN_TILDE:
+ return "'~'";
+ case PM_TOKEN_UAMPERSAND:
+ return "'&'";
+ case PM_TOKEN_UCOLON_COLON:
+ return "'::'";
+ case PM_TOKEN_UDOT_DOT:
+ return "'..'";
+ case PM_TOKEN_UDOT_DOT_DOT:
+ return "'...'";
+ case PM_TOKEN_UMINUS:
+ return "'-'";
+ case PM_TOKEN_UMINUS_NUM:
+ return "'-'";
+ case PM_TOKEN_UPLUS:
+ return "'+'";
+ case PM_TOKEN_USTAR:
+ return "*";
+ case PM_TOKEN_USTAR_STAR:
+ return "**";
+ case PM_TOKEN_WORDS_SEP:
+ return "string separator";
+ case PM_TOKEN___END__:
+ return "'__END__'";
+ case PM_TOKEN_MAXIMUM:
+ assert(false && "unreachable");
+ return "";
+ }
+
+ /* Provide a default, because some compilers cannot determine that the above
+ * switch is exhaustive. */
+ assert(false && "unreachable");
+ return "";
+}
diff --git a/prism/templates/template.rb b/prism/templates/template.rb
index 30cb60cabd..0fdeda561f 100755
--- a/prism/templates/template.rb
+++ b/prism/templates/template.rb
@@ -6,13 +6,12 @@ require "fileutils"
require "yaml"
module Prism
- module Template
+ module Template # :nodoc: all
SERIALIZE_ONLY_SEMANTICS_FIELDS = ENV.fetch("PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS", false)
- REMOVE_ON_ERROR_TYPES = SERIALIZE_ONLY_SEMANTICS_FIELDS
CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false)
- JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby"
- JAVA_STRING_TYPE = JAVA_BACKEND == "jruby" ? "org.jruby.RubySymbol" : "String"
+ JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "default"
+ JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]"
INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby"
COMMON_FLAGS_COUNT = 2
@@ -49,6 +48,14 @@ module Prism
end
end
+ # This module contains methods for escaping characters in Doxygen comments.
+ module Doxygen
+ # Similar to /verbatim ... /endverbatim but doesn't wrap the result in a code block.
+ def self.verbatim(value)
+ value.gsub(/[*%!`#<>_+@-]/, '\\\\\0')
+ end
+ end
+
# A comment attached to a field or node.
class ConfigComment
attr_reader :value
@@ -97,6 +104,11 @@ module Prism
# Some node fields can be specialized if they point to a specific kind of
# node and not just a generic node.
class NodeKindField < Field
+ # The C type to use for this field as a function parameter.
+ def c_param
+ "struct #{c_type} *#{name}"
+ end
+
def initialize(kind:, **options)
@kind = kind
super(**options)
@@ -142,27 +154,27 @@ module Prism
if specific_kind
specific_kind
elsif union_kind
- union_kind.join(" | ")
+ "(#{union_kind.join(" | ")})"
else
"Prism::node"
end
end
- def rbi_class
+ def call_seq_type
if specific_kind
- "Prism::#{specific_kind}"
+ specific_kind
elsif union_kind
- "T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")})"
+ union_kind.join(" | ")
else
- "Prism::Node"
+ "Node"
end
end
def check_field_kind
if union_kind
- "[#{union_kind.join(', ')}].include?(#{name}.class)"
+ "[#{union_kind.join(', ')}, ErrorRecoveryNode].include?(#{name}.class)"
else
- "#{name}.is_a?(#{ruby_type})"
+ "#{name}.is_a?(#{ruby_type}) || #{name}.is_a?(ErrorRecoveryNode)"
end
end
end
@@ -174,27 +186,27 @@ module Prism
if specific_kind
"#{specific_kind}?"
elsif union_kind
- [*union_kind, "nil"].join(" | ")
+ "(#{union_kind.join(" | ")})?"
else
"Prism::node?"
end
end
- def rbi_class
+ def call_seq_type
if specific_kind
- "T.nilable(Prism::#{specific_kind})"
+ "#{specific_kind} | nil"
elsif union_kind
- "T.nilable(T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")}))"
+ [*union_kind, "nil"].join(" | ")
else
- "T.nilable(Prism::Node)"
+ "Node | nil"
end
end
def check_field_kind
if union_kind
- "[#{union_kind.join(', ')}, NilClass].include?(#{name}.class)"
+ "[#{union_kind.join(', ')}, ErrorRecoveryNode, NilClass].include?(#{name}.class)"
else
- "#{name}.nil? || #{name}.is_a?(#{ruby_type})"
+ "#{name}.nil? || #{name}.is_a?(#{ruby_type}) || #{name}.is_a?(ErrorRecoveryNode)"
end
end
end
@@ -202,23 +214,31 @@ module Prism
# 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 < NodeKindField
- def rbs_class
+ def c_param
+ "pm_node_list_t #{name}"
+ end
+
+ def element_rbs_class
if specific_kind
- "Array[#{specific_kind}]"
+ "#{specific_kind}"
elsif union_kind
- "Array[#{union_kind.join(" | ")}]"
+ "#{union_kind.join(" | ")}"
else
- "Array[Prism::node]"
+ "Prism::node"
end
end
- def rbi_class
+ def rbs_class
+ "Array[#{element_rbs_class}]"
+ end
+
+ def call_seq_type
if specific_kind
- "T::Array[Prism::#{specific_kind}]"
+ "Array[#{specific_kind}]"
elsif union_kind
- "T::Array[T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")})]"
+ "Array[#{union_kind.join(" | ")}]"
else
- "T::Array[Prism::Node]"
+ "Array[Node]"
end
end
@@ -228,9 +248,9 @@ module Prism
def check_field_kind
if union_kind
- "#{name}.all? { |n| [#{union_kind.join(', ')}].include?(n.class) }"
+ "#{name}.all? { |n| [#{union_kind.join(', ')}, ErrorRecoveryNode].include?(n.class) }"
else
- "#{name}.all? { |n| n.is_a?(#{ruby_type}) }"
+ "#{name}.all? { |n| n.is_a?(#{ruby_type}) || n.is_a?(ErrorRecoveryNode) }"
end
end
end
@@ -238,58 +258,74 @@ module Prism
# 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 c_param
+ "pm_constant_id_t #{name}"
+ end
+
def rbs_class
"Symbol"
end
- def rbi_class
+ def call_seq_type
"Symbol"
end
def java_type
- JAVA_STRING_TYPE
+ JAVA_IDENTIFIER_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 c_param
+ "pm_constant_id_t #{name}"
+ end
+
def rbs_class
"Symbol?"
end
- def rbi_class
- "T.nilable(Symbol)"
+ def call_seq_type
+ "Symbol | nil"
end
def java_type
- JAVA_STRING_TYPE
+ JAVA_IDENTIFIER_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 c_param
+ "pm_constant_id_list_t #{name}"
+ end
+
def rbs_class
"Array[Symbol]"
end
- def rbi_class
- "T::Array[Symbol]"
+ def call_seq_type
+ "Array[Symbol]"
end
def java_type
- "#{JAVA_STRING_TYPE}[]"
+ "#{JAVA_IDENTIFIER_TYPE}[]"
end
end
# This represents a field on a node that is a string.
class StringField < Field
+ def c_param
+ "pm_string_t #{name}"
+ end
+
def rbs_class
"String"
end
- def rbi_class
+ def call_seq_type
"String"
end
@@ -300,6 +336,10 @@ module Prism
# This represents a field on a node that is a location.
class LocationField < Field
+ def c_param
+ "pm_location_t #{name}"
+ end
+
def semantic_field?
false
end
@@ -308,8 +348,8 @@ module Prism
"Location"
end
- def rbi_class
- "Prism::Location"
+ def call_seq_type
+ "Location"
end
def java_type
@@ -319,6 +359,10 @@ module Prism
# This represents a field on a node that is a location that is optional.
class OptionalLocationField < Field
+ def c_param
+ "pm_location_t #{name}"
+ end
+
def semantic_field?
false
end
@@ -327,8 +371,8 @@ module Prism
"Location?"
end
- def rbi_class
- "T.nilable(Prism::Location)"
+ def call_seq_type
+ "Location | nil"
end
def java_type
@@ -338,11 +382,15 @@ module Prism
# This represents an integer field.
class UInt8Field < Field
+ def c_param
+ "uint8_t #{name}"
+ end
+
def rbs_class
"Integer"
end
- def rbi_class
+ def call_seq_type
"Integer"
end
@@ -353,11 +401,15 @@ module Prism
# This represents an integer field.
class UInt32Field < Field
+ def c_param
+ "uint32_t #{name}"
+ end
+
def rbs_class
"Integer"
end
- def rbi_class
+ def call_seq_type
"Integer"
end
@@ -369,11 +421,15 @@ module Prism
# This represents an arbitrarily-sized integer. When it gets to Ruby it will
# be an Integer.
class IntegerField < Field
+ def c_param
+ "pm_integer_t #{name}"
+ end
+
def rbs_class
"Integer"
end
- def rbi_class
+ def call_seq_type
"Integer"
end
@@ -385,11 +441,15 @@ module Prism
# This represents a double-precision floating point number. When it gets to
# Ruby it will be a Float.
class DoubleField < Field
+ def c_param
+ "double #{name}"
+ end
+
def rbs_class
"Float"
end
- def rbi_class
+ def call_seq_type
"Float"
end
@@ -432,9 +492,6 @@ module Prism
when "pattern expression"
# the list of all possible types is too long with 37+ different classes
"Node"
- when Hash
- kind = kind.fetch("on error")
- REMOVE_ON_ERROR_TYPES ? nil : kind
else
kind
end
@@ -547,33 +604,17 @@ module Prism
extension = File.extname(filepath.gsub(".erb", ""))
heading =
- case extension
- when ".rb"
+ if extension == ".rb"
<<~HEADING
# frozen_string_literal: true
+ # :markup: markdown
=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
- # typed: strict
-
- =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
@@ -582,7 +623,7 @@ module Prism
/*----------------------------------------------------------------------------*/
/* This file is generated by the templates/template.rb script and should not */
/* be modified manually. See */
- /* #{filepath + " " * (74 - filepath.size) } */
+ /* #{filepath.ljust(74)} */
/* if you are looking to modify the */
/* template */
/*----------------------------------------------------------------------------*/
@@ -602,8 +643,14 @@ module Prism
end
end
- FileUtils.mkdir_p(File.dirname(write_to))
- File.write(write_to, contents)
+ begin
+ FileUtils.mkdir_p(File.dirname(write_to))
+ File.write(write_to, contents)
+ rescue SystemCallError # EACCES, EPERM, EROFS, etc.
+ # Fall back to the current directory
+ FileUtils.mkdir_p(File.dirname(name))
+ File.write(name, contents)
+ end
end
private
@@ -639,13 +686,13 @@ module Prism
TEMPLATES = [
"ext/prism/api_node.c",
"include/prism/ast.h",
- "include/prism/diagnostic.h",
+ "include/prism/internal/diagnostic.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",
+ "java/api/src/main/java-templates/org/ruby_lang/prism/Loader.java",
+ "java/api/src/main/java-templates/org/ruby_lang/prism/Nodes.java",
+ "java/api/src/main/java-templates/org/ruby_lang/prism/AbstractNodeVisitor.java",
"lib/prism/compiler.rb",
"lib/prism/dispatcher.rb",
"lib/prism/dot_visitor.rb",
@@ -657,19 +704,11 @@ module Prism
"lib/prism/serialize.rb",
"lib/prism/visitor.rb",
"src/diagnostic.c",
+ "src/json.c",
"src/node.c",
"src/prettyprint.c",
"src/serialize.c",
- "src/token_type.c",
- "rbi/prism/dsl.rbi",
- "rbi/prism/node.rbi",
- "rbi/prism/visitor.rbi",
- "sig/prism.rbs",
- "sig/prism/dsl.rbs",
- "sig/prism/mutation_compiler.rbs",
- "sig/prism/node.rbs",
- "sig/prism/visitor.rbs",
- "sig/prism/_private/dot_visitor.rbs"
+ "src/tokens.c"
]
end
end
diff --git a/prism/util/pm_buffer.c b/prism/util/pm_buffer.c
deleted file mode 100644
index 2136a7c43e..0000000000
--- a/prism/util/pm_buffer.c
+++ /dev/null
@@ -1,357 +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 *) xmalloc(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(const pm_buffer_t *buffer) {
- return buffer->value;
-}
-
-/**
- * Return the length of the buffer.
- */
-size_t
-pm_buffer_length(const pm_buffer_t *buffer) {
- return buffer->length;
-}
-
-/**
- * Append the given amount of space to the buffer.
- */
-static inline bool
-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 = xrealloc(buffer->value, buffer->capacity);
- if (buffer->value == NULL) return false;
- }
-
- buffer->length = next_length;
- return true;
-}
-
-/**
- * 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;
- if (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;
- if (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;
- if (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);
-}
-
-/**
- * Append a double to the buffer.
- */
-void
-pm_buffer_append_double(pm_buffer_t *buffer, double value) {
- const void *source = &value;
- pm_buffer_append(buffer, source, sizeof(double));
-}
-
-/**
- * Append a unicode codepoint to the buffer.
- */
-bool
-pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value) {
- if (value <= 0x7F) {
- pm_buffer_append_byte(buffer, (uint8_t) value); // 0xxxxxxx
- return true;
- } else if (value <= 0x7FF) {
- uint8_t bytes[] = {
- (uint8_t) (0xC0 | ((value >> 6) & 0x3F)), // 110xxxxx
- (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
- };
-
- pm_buffer_append_bytes(buffer, bytes, 2);
- return true;
- } else if (value <= 0xFFFF) {
- uint8_t bytes[] = {
- (uint8_t) (0xE0 | ((value >> 12) & 0x3F)), // 1110xxxx
- (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
- (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
- };
-
- pm_buffer_append_bytes(buffer, bytes, 3);
- return true;
- } else if (value <= 0x10FFFF) {
- uint8_t bytes[] = {
- (uint8_t) (0xF0 | ((value >> 18) & 0x3F)), // 11110xxx
- (uint8_t) (0x80 | ((value >> 12) & 0x3F)), // 10xxxxxx
- (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
- (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
- };
-
- pm_buffer_append_bytes(buffer, bytes, 4);
- return true;
- } else {
- return false;
- }
-}
-
-/**
- * Append a slice of source code to the buffer.
- */
-void
-pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
- for (size_t index = 0; index < length; index++) {
- const uint8_t byte = source[index];
-
- if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
- if (escaping == PM_BUFFER_ESCAPING_RUBY) {
- pm_buffer_append_format(buffer, "\\x%02X", byte);
- } else {
- pm_buffer_append_format(buffer, "\\u%04X", byte);
- }
- } else {
- switch (byte) {
- case '\a':
- if (escaping == PM_BUFFER_ESCAPING_RUBY) {
- pm_buffer_append_string(buffer, "\\a", 2);
- } else {
- pm_buffer_append_format(buffer, "\\u%04X", byte);
- }
- break;
- case '\b':
- pm_buffer_append_string(buffer, "\\b", 2);
- break;
- case '\t':
- pm_buffer_append_string(buffer, "\\t", 2);
- break;
- case '\n':
- pm_buffer_append_string(buffer, "\\n", 2);
- break;
- case '\v':
- if (escaping == PM_BUFFER_ESCAPING_RUBY) {
- pm_buffer_append_string(buffer, "\\v", 2);
- } else {
- pm_buffer_append_format(buffer, "\\u%04X", byte);
- }
- break;
- case '\f':
- pm_buffer_append_string(buffer, "\\f", 2);
- break;
- case '\r':
- pm_buffer_append_string(buffer, "\\r", 2);
- break;
- case '"':
- pm_buffer_append_string(buffer, "\\\"", 2);
- break;
- case '#': {
- if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
- const uint8_t next_byte = source[index + 1];
- if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
- pm_buffer_append_byte(buffer, '\\');
- }
- }
-
- pm_buffer_append_byte(buffer, '#');
- break;
- }
- case '\\':
- pm_buffer_append_string(buffer, "\\\\", 2);
- break;
- default:
- pm_buffer_append_byte(buffer, byte);
- break;
- }
- }
- }
-}
-
-/**
- * Prepend the given string to the buffer.
- */
-void
-pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
- size_t cursor = buffer->length;
- if (pm_buffer_append_length(buffer, length)) {
- memmove(buffer->value + length, buffer->value, cursor);
- memcpy(buffer->value, value, length);
- }
-}
-
-/**
- * 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);
- }
-}
-
-/**
- * Clear the buffer by reducing its size to 0. This does not free the allocated
- * memory, but it does allow the buffer to be reused.
- */
-void
-pm_buffer_clear(pm_buffer_t *buffer) {
- buffer->length = 0;
-}
-
-/**
- * Strip the whitespace from the end of the buffer.
- */
-void
-pm_buffer_rstrip(pm_buffer_t *buffer) {
- while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
- buffer->length--;
- }
-}
-
-/**
- * Checks if the buffer includes the given value.
- */
-size_t
-pm_buffer_index(const pm_buffer_t *buffer, char value) {
- const char *first = memchr(buffer->value, value, buffer->length);
- return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
-}
-
-/**
- * Insert the given string into the buffer at the given index.
- */
-void
-pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
- assert(index <= buffer->length);
-
- if (index == buffer->length) {
- pm_buffer_append_string(buffer, value, length);
- } else {
- pm_buffer_append_zeroes(buffer, length);
- memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
- memcpy(buffer->value + index, value, length);
- }
-}
-
-/**
- * Free the memory associated with the buffer.
- */
-void
-pm_buffer_free(pm_buffer_t *buffer) {
- xfree(buffer->value);
-}
diff --git a/prism/util/pm_buffer.h b/prism/util/pm_buffer.h
deleted file mode 100644
index f3c20ab2a5..0000000000
--- a/prism/util/pm_buffer.h
+++ /dev/null
@@ -1,228 +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 "prism/util/pm_char.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(const 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(const 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);
-
-/**
- * Append a double to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The double to append.
- */
-void pm_buffer_append_double(pm_buffer_t *buffer, double value);
-
-/**
- * Append a unicode codepoint to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The character to append.
- * @returns True if the codepoint was valid and appended successfully, false
- * otherwise.
- */
-bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value);
-
-/**
- * The different types of escaping that can be performed by the buffer when
- * appending a slice of Ruby source code.
- */
-typedef enum {
- PM_BUFFER_ESCAPING_RUBY,
- PM_BUFFER_ESCAPING_JSON
-} pm_buffer_escaping_t;
-
-/**
- * Append a slice of source code to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param source The source code to append.
- * @param length The length of the source code to append.
- * @param escaping The type of escaping to perform.
- */
-void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping);
-
-/**
- * Prepend the given string to the buffer.
- *
- * @param buffer The buffer to prepend to.
- * @param value The string to prepend.
- * @param length The length of the string to prepend.
- */
-void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length);
-
-/**
- * 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);
-
-/**
- * Clear the buffer by reducing its size to 0. This does not free the allocated
- * memory, but it does allow the buffer to be reused.
- *
- * @param buffer The buffer to clear.
- */
-void pm_buffer_clear(pm_buffer_t *buffer);
-
-/**
- * Strip the whitespace from the end of the buffer.
- *
- * @param buffer The buffer to strip.
- */
-void pm_buffer_rstrip(pm_buffer_t *buffer);
-
-/**
- * Checks if the buffer includes the given value.
- *
- * @param buffer The buffer to check.
- * @param value The value to check for.
- * @returns The index of the first occurrence of the value in the buffer, or
- * SIZE_MAX if the value is not found.
- */
-size_t pm_buffer_index(const pm_buffer_t *buffer, char value);
-
-/**
- * Insert the given string into the buffer at the given index.
- *
- * @param buffer The buffer to insert into.
- * @param index The index to insert at.
- * @param value The string to insert.
- * @param length The length of the string to insert.
- */
-void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length);
-
-/**
- * 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 a51dc11645..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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 4x
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 5x
- 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 6x
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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 (size > 0 && 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 deeafd6321..0000000000
--- a/prism/util/pm_char.h
+++ /dev/null
@@ -1,204 +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 38ea01a228..0000000000
--- a/prism/util/pm_constant_pool.c
+++ /dev/null
@@ -1,342 +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;
-}
-
-/**
- * Initialize a list of constant ids with a given capacity.
- */
-void
-pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity) {
- if (capacity) {
- list->ids = xcalloc(capacity, sizeof(pm_constant_id_t));
- if (list->ids == NULL) abort();
- } else {
- list->ids = NULL;
- }
-
- list->size = 0;
- list->capacity = capacity;
-}
-
-/**
- * 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 *) xrealloc(list->ids, sizeof(pm_constant_id_t) * list->capacity);
- if (list->ids == NULL) return false;
- }
-
- list->ids[list->size++] = id;
- return true;
-}
-
-/**
- * Insert a constant id into a list of constant ids at the specified index.
- */
-void
-pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id) {
- assert(index < list->capacity);
- assert(list->ids[index] == PM_CONSTANT_ID_UNSET);
-
- list->ids[index] = id;
- list->size++;
-}
-
-/**
- * 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;
-}
-
-/**
- * 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) {
- xfree(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 = xcalloc(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 != PM_CONSTANT_ID_UNSET) {
- 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 != PM_CONSTANT_ID_UNSET) {
- 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.
- xfree(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 = xcalloc(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 != PM_CONSTANT_ID_UNSET && constant_id <= pool->size);
- return &pool->constants[constant_id - 1];
-}
-
-/**
- * Find a constant in a constant pool. Returns the id of the constant, or 0 if
- * the constant is not found.
- */
-pm_constant_id_t
-pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- 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 != PM_CONSTANT_ID_UNSET) {
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
- if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
- return bucket->id;
- }
-
- index = (index + 1) & mask;
- }
-
- return PM_CONSTANT_ID_UNSET;
-}
-
-/**
- * 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 PM_CONSTANT_ID_UNSET;
- }
-
- 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 != PM_CONSTANT_ID_UNSET) {
- // 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.
- xfree((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.
- xfree((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-existent
- // 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
- * PM_CONSTANT_ID_UNSET 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 PM_CONSTANT_ID_UNSET if any
- * potential calls to resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_owned(pm_constant_pool_t *pool, 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 PM_CONSTANT_ID_UNSET 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 != PM_CONSTANT_ID_UNSET && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
- xfree((void *) constant->start);
- }
- }
-
- xfree(pool->buckets);
-}
diff --git a/prism/util/pm_constant_pool.h b/prism/util/pm_constant_pool.h
deleted file mode 100644
index 6df23f8f50..0000000000
--- a/prism/util/pm_constant_pool.h
+++ /dev/null
@@ -1,218 +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>
-
-/**
- * When we allocate constants into the pool, we reserve 0 to mean that the slot
- * is not yet filled. This constant is reused in other places to indicate the
- * lack of a constant id.
- */
-#define PM_CONSTANT_ID_UNSET 0
-
-/**
- * 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);
-
-/**
- * Initialize a list of constant ids with a given capacity.
- *
- * @param list The list to initialize.
- * @param capacity The initial capacity of the list.
- */
-void pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity);
-
-/**
- * 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);
-
-/**
- * Insert a constant id into a list of constant ids at the specified index.
- *
- * @param list The list to insert into.
- * @param index The index at which to insert.
- * @param id The id to insert.
- */
-void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, 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);
-
-/**
- * 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);
-
-/**
- * Find a constant in a constant pool. Returns the id of the constant, or 0 if
- * the constant is not found.
- *
- * @param pool The pool to find the constant in.
- * @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_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * 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, 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_integer.c b/prism/util/pm_integer.c
deleted file mode 100644
index 4170ecc58d..0000000000
--- a/prism/util/pm_integer.c
+++ /dev/null
@@ -1,670 +0,0 @@
-#include "prism/util/pm_integer.h"
-
-/**
- * Pull out the length and values from the integer, regardless of the form in
- * which the length/values are stored.
- */
-#define INTEGER_EXTRACT(integer, length_variable, values_variable) \
- if ((integer)->values == NULL) { \
- length_variable = 1; \
- values_variable = &(integer)->value; \
- } else { \
- length_variable = (integer)->length; \
- values_variable = (integer)->values; \
- }
-
-/**
- * Adds two positive pm_integer_t with the given base.
- * Return pm_integer_t with values allocated. Not normalized.
- */
-static void
-big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) {
- size_t left_length;
- uint32_t *left_values;
- INTEGER_EXTRACT(left, left_length, left_values)
-
- size_t right_length;
- uint32_t *right_values;
- INTEGER_EXTRACT(right, right_length, right_values)
-
- size_t length = left_length < right_length ? right_length : left_length;
- uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * (length + 1));
- if (values == NULL) return;
-
- uint64_t carry = 0;
- for (size_t index = 0; index < length; index++) {
- uint64_t sum = carry + (index < left_length ? left_values[index] : 0) + (index < right_length ? right_values[index] : 0);
- values[index] = (uint32_t) (sum % base);
- carry = sum / base;
- }
-
- if (carry > 0) {
- values[length] = (uint32_t) carry;
- length++;
- }
-
- *destination = (pm_integer_t) { length, values, 0, false };
-}
-
-/**
- * Internal use for karatsuba_multiply. Calculates `a - b - c` with the given
- * base. Assume a, b, c, a - b - c all to be positive.
- * Return pm_integer_t with values allocated. Not normalized.
- */
-static void
-big_sub2(pm_integer_t *destination, pm_integer_t *a, pm_integer_t *b, pm_integer_t *c, uint64_t base) {
- size_t a_length;
- uint32_t *a_values;
- INTEGER_EXTRACT(a, a_length, a_values)
-
- size_t b_length;
- uint32_t *b_values;
- INTEGER_EXTRACT(b, b_length, b_values)
-
- size_t c_length;
- uint32_t *c_values;
- INTEGER_EXTRACT(c, c_length, c_values)
-
- uint32_t *values = (uint32_t*) xmalloc(sizeof(uint32_t) * a_length);
- int64_t carry = 0;
-
- for (size_t index = 0; index < a_length; index++) {
- int64_t sub = (
- carry +
- a_values[index] -
- (index < b_length ? b_values[index] : 0) -
- (index < c_length ? c_values[index] : 0)
- );
-
- if (sub >= 0) {
- values[index] = (uint32_t) sub;
- carry = 0;
- } else {
- sub += 2 * (int64_t) base;
- values[index] = (uint32_t) ((uint64_t) sub % base);
- carry = sub / (int64_t) base - 2;
- }
- }
-
- while (a_length > 1 && values[a_length - 1] == 0) a_length--;
- *destination = (pm_integer_t) { a_length, values, 0, false };
-}
-
-/**
- * Multiply two positive integers with the given base using karatsuba algorithm.
- * Return pm_integer_t with values allocated. Not normalized.
- */
-static void
-karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) {
- size_t left_length;
- uint32_t *left_values;
- INTEGER_EXTRACT(left, left_length, left_values)
-
- size_t right_length;
- uint32_t *right_values;
- INTEGER_EXTRACT(right, right_length, right_values)
-
- if (left_length > right_length) {
- size_t temporary_length = left_length;
- left_length = right_length;
- right_length = temporary_length;
-
- uint32_t *temporary_values = left_values;
- left_values = right_values;
- right_values = temporary_values;
- }
-
- if (left_length <= 10) {
- size_t length = left_length + right_length;
- uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
- if (values == NULL) return;
-
- for (size_t left_index = 0; left_index < left_length; left_index++) {
- uint32_t carry = 0;
- for (size_t right_index = 0; right_index < right_length; right_index++) {
- uint64_t product = (uint64_t) left_values[left_index] * right_values[right_index] + values[left_index + right_index] + carry;
- values[left_index + right_index] = (uint32_t) (product % base);
- carry = (uint32_t) (product / base);
- }
- values[left_index + right_length] = carry;
- }
-
- while (length > 1 && values[length - 1] == 0) length--;
- *destination = (pm_integer_t) { length, values, 0, false };
- return;
- }
-
- if (left_length * 2 <= right_length) {
- uint32_t *values = (uint32_t *) xcalloc(left_length + right_length, sizeof(uint32_t));
-
- for (size_t start_offset = 0; start_offset < right_length; start_offset += left_length) {
- size_t end_offset = start_offset + left_length;
- if (end_offset > right_length) end_offset = right_length;
-
- pm_integer_t sliced_left = {
- .length = left_length,
- .values = left_values,
- .value = 0,
- .negative = false
- };
-
- pm_integer_t sliced_right = {
- .length = end_offset - start_offset,
- .values = right_values + start_offset,
- .value = 0,
- .negative = false
- };
-
- pm_integer_t product;
- karatsuba_multiply(&product, &sliced_left, &sliced_right, base);
-
- uint32_t carry = 0;
- for (size_t index = 0; index < product.length; index++) {
- uint64_t sum = (uint64_t) values[start_offset + index] + product.values[index] + carry;
- values[start_offset + index] = (uint32_t) (sum % base);
- carry = (uint32_t) (sum / base);
- }
-
- if (carry > 0) values[start_offset + product.length] += carry;
- pm_integer_free(&product);
- }
-
- *destination = (pm_integer_t) { left_length + right_length, values, 0, false };
- return;
- }
-
- size_t half = left_length / 2;
- pm_integer_t x0 = { half, left_values, 0, false };
- pm_integer_t x1 = { left_length - half, left_values + half, 0, false };
- pm_integer_t y0 = { half, right_values, 0, false };
- pm_integer_t y1 = { right_length - half, right_values + half, 0, false };
-
- pm_integer_t z0 = { 0 };
- karatsuba_multiply(&z0, &x0, &y0, base);
-
- pm_integer_t z2 = { 0 };
- karatsuba_multiply(&z2, &x1, &y1, base);
-
- // For simplicity to avoid considering negative values,
- // use `z1 = (x0 + x1) * (y0 + y1) - z0 - z2` instead of original karatsuba algorithm.
- pm_integer_t x01 = { 0 };
- big_add(&x01, &x0, &x1, base);
-
- pm_integer_t y01 = { 0 };
- big_add(&y01, &y0, &y1, base);
-
- pm_integer_t xy = { 0 };
- karatsuba_multiply(&xy, &x01, &y01, base);
-
- pm_integer_t z1;
- big_sub2(&z1, &xy, &z0, &z2, base);
-
- size_t length = left_length + right_length;
- uint32_t *values = (uint32_t*) xcalloc(length, sizeof(uint32_t));
-
- assert(z0.values != NULL);
- memcpy(values, z0.values, sizeof(uint32_t) * z0.length);
-
- assert(z2.values != NULL);
- memcpy(values + 2 * half, z2.values, sizeof(uint32_t) * z2.length);
-
- uint32_t carry = 0;
- for(size_t index = 0; index < z1.length; index++) {
- uint64_t sum = (uint64_t) carry + values[index + half] + z1.values[index];
- values[index + half] = (uint32_t) (sum % base);
- carry = (uint32_t) (sum / base);
- }
-
- for(size_t index = half + z1.length; carry > 0; index++) {
- uint64_t sum = (uint64_t) carry + values[index];
- values[index] = (uint32_t) (sum % base);
- carry = (uint32_t) (sum / base);
- }
-
- while (length > 1 && values[length - 1] == 0) length--;
- pm_integer_free(&z0);
- pm_integer_free(&z1);
- pm_integer_free(&z2);
- pm_integer_free(&x01);
- pm_integer_free(&y01);
- pm_integer_free(&xy);
-
- *destination = (pm_integer_t) { length, values, 0, false };
-}
-
-/**
- * The values of a hexadecimal digit, where the index is the ASCII character.
- * Note that there's an odd exception here where _ is mapped to 0. This is
- * because it's possible for us to end up trying to parse a number that has
- * already had an error attached to it, and we want to provide _something_ to
- * the user.
- */
-static const int8_t pm_integer_parse_digit_values[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, // 5x
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Fx
-};
-
-/**
- * Return the value of a hexadecimal digit in a uint8_t.
- */
-static uint8_t
-pm_integer_parse_digit(const uint8_t character) {
- int8_t value = pm_integer_parse_digit_values[character];
- assert(value != -1 && "invalid digit");
-
- return (uint8_t) value;
-}
-
-/**
- * Create a pm_integer_t from uint64_t with the given base. It is assumed that
- * the memory for the pm_integer_t pointer has been zeroed.
- */
-static void
-pm_integer_from_uint64(pm_integer_t *integer, uint64_t value, uint64_t base) {
- if (value < base) {
- integer->value = (uint32_t) value;
- return;
- }
-
- size_t length = 0;
- uint64_t length_value = value;
- while (length_value > 0) {
- length++;
- length_value /= base;
- }
-
- uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * length);
- if (values == NULL) return;
-
- for (size_t value_index = 0; value_index < length; value_index++) {
- values[value_index] = (uint32_t) (value % base);
- value /= base;
- }
-
- integer->length = length;
- integer->values = values;
-}
-
-/**
- * Normalize pm_integer_t.
- * Heading zero values will be removed. If the integer fits into uint32_t,
- * values is set to NULL, length is set to 0, and value field will be used.
- */
-static void
-pm_integer_normalize(pm_integer_t *integer) {
- if (integer->values == NULL) {
- return;
- }
-
- while (integer->length > 1 && integer->values[integer->length - 1] == 0) {
- integer->length--;
- }
-
- if (integer->length > 1) {
- return;
- }
-
- uint32_t value = integer->values[0];
- bool negative = integer->negative && value != 0;
-
- pm_integer_free(integer);
- *integer = (pm_integer_t) { .values = NULL, .value = value, .length = 0, .negative = negative };
-}
-
-/**
- * Convert base of the integer.
- * In practice, it converts 10**9 to 1<<32 or 1<<32 to 10**9.
- */
-static void
-pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, uint64_t base_from, uint64_t base_to) {
- size_t source_length;
- const uint32_t *source_values;
- INTEGER_EXTRACT(source, source_length, source_values)
-
- size_t bigints_length = (source_length + 1) / 2;
- assert(bigints_length > 0);
-
- pm_integer_t *bigints = (pm_integer_t *) xcalloc(bigints_length, sizeof(pm_integer_t));
- if (bigints == NULL) return;
-
- for (size_t index = 0; index < source_length; index += 2) {
- uint64_t value = source_values[index] + base_from * (index + 1 < source_length ? source_values[index + 1] : 0);
- pm_integer_from_uint64(&bigints[index / 2], value, base_to);
- }
-
- pm_integer_t base = { 0 };
- pm_integer_from_uint64(&base, base_from, base_to);
-
- while (bigints_length > 1) {
- pm_integer_t next_base;
- karatsuba_multiply(&next_base, &base, &base, base_to);
-
- pm_integer_free(&base);
- base = next_base;
-
- size_t next_length = (bigints_length + 1) / 2;
- pm_integer_t *next_bigints = (pm_integer_t *) xcalloc(next_length, sizeof(pm_integer_t));
-
- for (size_t bigints_index = 0; bigints_index < bigints_length; bigints_index += 2) {
- if (bigints_index + 1 == bigints_length) {
- next_bigints[bigints_index / 2] = bigints[bigints_index];
- } else {
- pm_integer_t multiplied = { 0 };
- karatsuba_multiply(&multiplied, &base, &bigints[bigints_index + 1], base_to);
-
- big_add(&next_bigints[bigints_index / 2], &bigints[bigints_index], &multiplied, base_to);
- pm_integer_free(&bigints[bigints_index]);
- pm_integer_free(&bigints[bigints_index + 1]);
- pm_integer_free(&multiplied);
- }
- }
-
- xfree(bigints);
- bigints = next_bigints;
- bigints_length = next_length;
- }
-
- *destination = bigints[0];
- destination->negative = source->negative;
- pm_integer_normalize(destination);
-
- xfree(bigints);
- pm_integer_free(&base);
-}
-
-#undef INTEGER_EXTRACT
-
-/**
- * Convert digits to integer with the given power-of-two base.
- */
-static void
-pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *digits, size_t digits_length) {
- size_t bit = 1;
- while (base > (uint32_t) (1 << bit)) bit++;
-
- size_t length = (digits_length * bit + 31) / 32;
- uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
-
- for (size_t digit_index = 0; digit_index < digits_length; digit_index++) {
- size_t bit_position = bit * (digits_length - digit_index - 1);
- uint32_t value = digits[digit_index];
-
- size_t index = bit_position / 32;
- size_t shift = bit_position % 32;
-
- values[index] |= value << shift;
- if (32 - shift < bit) values[index + 1] |= value >> (32 - shift);
- }
-
- while (length > 1 && values[length - 1] == 0) length--;
- *integer = (pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false };
- pm_integer_normalize(integer);
-}
-
-/**
- * Convert decimal digits to pm_integer_t.
- */
-static void
-pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t digits_length) {
- const size_t batch = 9;
- size_t length = (digits_length + batch - 1) / batch;
-
- uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
- uint32_t value = 0;
-
- for (size_t digits_index = 0; digits_index < digits_length; digits_index++) {
- value = value * 10 + digits[digits_index];
-
- size_t reverse_index = digits_length - digits_index - 1;
- if (reverse_index % batch == 0) {
- values[reverse_index / batch] = value;
- value = 0;
- }
- }
-
- // Convert base from 10**9 to 1<<32.
- pm_integer_convert_base(integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32));
- xfree(values);
-}
-
-/**
- * Parse a large integer from a string that does not fit into uint32_t.
- */
-static void
-pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) {
- // Allocate an array to store digits.
- uint8_t *digits = xmalloc(sizeof(uint8_t) * (size_t) (end - start));
- size_t digits_length = 0;
-
- for (; start < end; start++) {
- if (*start == '_') continue;
- digits[digits_length++] = pm_integer_parse_digit(*start);
- }
-
- // Construct pm_integer_t from the digits.
- if (multiplier == 10) {
- pm_integer_parse_decimal(integer, digits, digits_length);
- } else {
- pm_integer_parse_powof2(integer, multiplier, digits, digits_length);
- }
-
- xfree(digits);
-}
-
-/**
- * Parse an integer from a string. This assumes that the format of the integer
- * has already been validated, as internal validation checks are not performed
- * here.
- */
-void
-pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) {
- // Ignore unary +. Unary - is parsed differently and will not end up here.
- // Instead, it will modify the parsed integer later.
- if (*start == '+') start++;
-
- // Determine the multiplier from the base, and skip past any prefixes.
- uint32_t multiplier = 10;
- switch (base) {
- case PM_INTEGER_BASE_DEFAULT:
- while (*start == '0') start++; // 01 -> 1
- break;
- case PM_INTEGER_BASE_BINARY:
- start += 2; // 0b
- multiplier = 2;
- break;
- case PM_INTEGER_BASE_OCTAL:
- start++; // 0
- if (*start == '_' || *start == 'o' || *start == 'O') start++; // o
- multiplier = 8;
- break;
- case PM_INTEGER_BASE_DECIMAL:
- if (*start == '0' && (end - start) > 1) start += 2; // 0d
- break;
- case PM_INTEGER_BASE_HEXADECIMAL:
- start += 2; // 0x
- multiplier = 16;
- break;
- case PM_INTEGER_BASE_UNKNOWN:
- if (*start == '0' && (end - start) > 1) {
- switch (start[1]) {
- case '_': start += 2; multiplier = 8; break;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': start++; multiplier = 8; break;
- case 'b': case 'B': start += 2; multiplier = 2; break;
- case 'o': case 'O': start += 2; multiplier = 8; break;
- case 'd': case 'D': start += 2; break;
- case 'x': case 'X': start += 2; multiplier = 16; break;
- default: assert(false && "unreachable"); break;
- }
- }
- break;
- }
-
- // It's possible that we've consumed everything at this point if there is an
- // invalid integer. If this is the case, we'll just return 0.
- if (start >= end) return;
-
- const uint8_t *cursor = start;
- uint64_t value = (uint64_t) pm_integer_parse_digit(*cursor++);
-
- for (; cursor < end; cursor++) {
- if (*cursor == '_') continue;
- value = value * multiplier + (uint64_t) pm_integer_parse_digit(*cursor);
-
- if (value > UINT32_MAX) {
- // If the integer is too large to fit into a single uint32_t, then
- // we'll parse it as a big integer.
- pm_integer_parse_big(integer, multiplier, start, end);
- return;
- }
- }
-
- integer->value = (uint32_t) value;
-}
-
-/**
- * Compare two integers. This function returns -1 if the left integer is less
- * than the right integer, 0 if they are equal, and 1 if the left integer is
- * greater than the right integer.
- */
-int
-pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right) {
- if (left->negative != right->negative) return left->negative ? -1 : 1;
- int negative = left->negative ? -1 : 1;
-
- if (left->values == NULL && right->values == NULL) {
- if (left->value < right->value) return -1 * negative;
- if (left->value > right->value) return 1 * negative;
- return 0;
- }
-
- if (left->values == NULL || left->length < right->length) return -1 * negative;
- if (right->values == NULL || left->length > right->length) return 1 * negative;
-
- for (size_t index = 0; index < left->length; index++) {
- size_t value_index = left->length - index - 1;
- uint32_t left_value = left->values[value_index];
- uint32_t right_value = right->values[value_index];
-
- if (left_value < right_value) return -1 * negative;
- if (left_value > right_value) return 1 * negative;
- }
-
- return 0;
-}
-
-/**
- * Reduce a ratio of integers to its simplest form.
- */
-void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) {
- // If either the numerator or denominator do not fit into a 32-bit integer,
- // then this function is a no-op. In the future, we may consider reducing
- // even the larger numbers, but for now we're going to keep it simple.
- if (
- // If the numerator doesn't fit into a 32-bit integer, return early.
- numerator->length != 0 ||
- // If the denominator doesn't fit into a 32-bit integer, return early.
- denominator->length != 0 ||
- // If the numerator is 0, then return early.
- numerator->value == 0 ||
- // If the denominator is 1, then return early.
- denominator->value == 1
- ) return;
-
- // Find the greatest common divisor of the numerator and denominator.
- uint32_t divisor = numerator->value;
- uint32_t remainder = denominator->value;
-
- while (remainder != 0) {
- uint32_t temporary = remainder;
- remainder = divisor % remainder;
- divisor = temporary;
- }
-
- // Divide the numerator and denominator by the greatest common divisor.
- numerator->value /= divisor;
- denominator->value /= divisor;
-}
-
-/**
- * Convert an integer to a decimal string.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) {
- if (integer->negative) {
- pm_buffer_append_byte(buffer, '-');
- }
-
- // If the integer fits into a single uint32_t, then we can just append the
- // value directly to the buffer.
- if (integer->values == NULL) {
- pm_buffer_append_format(buffer, "%" PRIu32, integer->value);
- return;
- }
-
- // If the integer is two uint32_t values, then we can | them together and
- // append the result to the buffer.
- if (integer->length == 2) {
- const uint64_t value = ((uint64_t) integer->values[0]) | ((uint64_t) integer->values[1] << 32);
- pm_buffer_append_format(buffer, "%" PRIu64, value);
- return;
- }
-
- // Otherwise, first we'll convert the base from 1<<32 to 10**9.
- pm_integer_t converted = { 0 };
- pm_integer_convert_base(&converted, integer, (uint64_t) 1 << 32, 1000000000);
-
- if (converted.values == NULL) {
- pm_buffer_append_format(buffer, "%" PRIu32, converted.value);
- pm_integer_free(&converted);
- return;
- }
-
- // Allocate a buffer that we'll copy the decimal digits into.
- size_t digits_length = converted.length * 9;
- char *digits = xcalloc(digits_length, sizeof(char));
- if (digits == NULL) return;
-
- // Pack bigdecimal to digits.
- for (size_t value_index = 0; value_index < converted.length; value_index++) {
- uint32_t value = converted.values[value_index];
-
- for (size_t digit_index = 0; digit_index < 9; digit_index++) {
- digits[digits_length - 9 * value_index - digit_index - 1] = (char) ('0' + value % 10);
- value /= 10;
- }
- }
-
- size_t start_offset = 0;
- while (start_offset < digits_length - 1 && digits[start_offset] == '0') start_offset++;
-
- // Finally, append the string to the buffer and free the digits.
- pm_buffer_append_string(buffer, digits + start_offset, digits_length - start_offset);
- xfree(digits);
- pm_integer_free(&converted);
-}
-
-/**
- * Free the internal memory of an integer. This memory will only be allocated if
- * the integer exceeds the size of a single uint32_t.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_integer_free(pm_integer_t *integer) {
- if (integer->values) {
- xfree(integer->values);
- }
-}
diff --git a/prism/util/pm_integer.h b/prism/util/pm_integer.h
deleted file mode 100644
index a9e2966703..0000000000
--- a/prism/util/pm_integer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @file pm_integer.h
- *
- * This module provides functions for working with arbitrary-sized integers.
- */
-#ifndef PRISM_NUMBER_H
-#define PRISM_NUMBER_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_buffer.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/**
- * A structure represents an arbitrary-sized integer.
- */
-typedef struct {
- /**
- * The number of allocated values. length is set to 0 if the integer fits
- * into uint32_t.
- */
- size_t length;
-
- /**
- * List of 32-bit integers. Set to NULL if the integer fits into uint32_t.
- */
- uint32_t *values;
-
- /**
- * Embedded value for small integer. This value is set to 0 if the value
- * does not fit into uint32_t.
- */
- uint32_t value;
-
- /**
- * Whether or not the integer is negative. It is stored this way so that a
- * zeroed pm_integer_t is always positive zero.
- */
- bool negative;
-} pm_integer_t;
-
-/**
- * An enum controlling the base of an integer. It is expected that the base is
- * already known before parsing the integer, even though it could be derived
- * from the string itself.
- */
-typedef enum {
- /** The default decimal base, with no prefix. Leading 0s will be ignored. */
- PM_INTEGER_BASE_DEFAULT,
-
- /** The binary base, indicated by a 0b or 0B prefix. */
- PM_INTEGER_BASE_BINARY,
-
- /** The octal base, indicated by a 0, 0o, or 0O prefix. */
- PM_INTEGER_BASE_OCTAL,
-
- /** The decimal base, indicated by a 0d, 0D, or empty prefix. */
- PM_INTEGER_BASE_DECIMAL,
-
- /** The hexadecimal base, indicated by a 0x or 0X prefix. */
- PM_INTEGER_BASE_HEXADECIMAL,
-
- /**
- * An unknown base, in which case pm_integer_parse will derive it based on
- * the content of the string. This is less efficient and does more
- * comparisons, so if callers know the base ahead of time, they should use
- * that instead.
- */
- PM_INTEGER_BASE_UNKNOWN
-} pm_integer_base_t;
-
-/**
- * Parse an integer from a string. This assumes that the format of the integer
- * has already been validated, as internal validation checks are not performed
- * here.
- *
- * @param integer The integer to parse into.
- * @param base The base of the integer.
- * @param start The start of the string.
- * @param end The end of the string.
- */
-void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end);
-
-/**
- * Compare two integers. This function returns -1 if the left integer is less
- * than the right integer, 0 if they are equal, and 1 if the left integer is
- * greater than the right integer.
- *
- * @param left The left integer to compare.
- * @param right The right integer to compare.
- * @return The result of the comparison.
- */
-int pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right);
-
-/**
- * Reduce a ratio of integers to its simplest form.
- *
- * If either the numerator or denominator do not fit into a 32-bit integer, then
- * this function is a no-op. In the future, we may consider reducing even the
- * larger numbers, but for now we're going to keep it simple.
- *
- * @param numerator The numerator of the ratio.
- * @param denominator The denominator of the ratio.
- */
-void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator);
-
-/**
- * Convert an integer to a decimal string.
- *
- * @param buffer The buffer to append the string to.
- * @param integer The integer to convert to a string.
- */
-PRISM_EXPORTED_FUNCTION void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer);
-
-/**
- * Free the internal memory of an integer. This memory will only be allocated if
- * the integer exceeds the size of a single node in the linked list.
- *
- * @param integer The integer to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_integer_free(pm_integer_t *integer);
-
-#endif
diff --git a/prism/util/pm_list.c b/prism/util/pm_list.c
deleted file mode 100644
index ad2294cd60..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;
- xfree(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 3512dee979..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 = xmalloc(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 8331618f54..0000000000
--- a/prism/util/pm_newline_list.c
+++ /dev/null
@@ -1,125 +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 *) xcalloc(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;
-}
-
-/**
- * Clear out the newlines that have been appended to the list.
- */
-void
-pm_newline_list_clear(pm_newline_list_t *list) {
- list->size = 1;
-}
-
-/**
- * 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 *) xcalloc(list->capacity, sizeof(size_t));
- if (list->offsets == NULL) return false;
-
- memcpy(list->offsets, original_offsets, list->size * sizeof(size_t));
- xfree(original_offsets);
- }
-
- 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;
-}
-
-/**
- * Returns the line of the given offset. If the offset is not in the list, the
- * line of the closest offset less than the given offset is returned.
- */
-int32_t
-pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
- 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 ((int32_t) mid) + start_line;
- }
-
- if (list->offsets[mid] < offset) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
-
- return ((int32_t) left) + start_line - 1;
-}
-
-/**
- * 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, int32_t start_line) {
- 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) { ((int32_t) mid) + start_line, 0 });
- }
-
- if (list->offsets[mid] < offset) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
-
- return ((pm_line_column_t) {
- .line = ((int32_t) left) + start_line - 1,
- .column = (uint32_t) (offset - list->offsets[left - 1])
- });
-}
-
-/**
- * Free the internal memory allocated for the newline list.
- */
-void
-pm_newline_list_free(pm_newline_list_t *list) {
- xfree(list->offsets);
-}
diff --git a/prism/util/pm_newline_list.h b/prism/util/pm_newline_list.h
deleted file mode 100644
index 406abe8ba5..0000000000
--- a/prism/util/pm_newline_list.h
+++ /dev/null
@@ -1,113 +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. */
- int32_t line;
-
- /** The column number. */
- uint32_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);
-
-/**
- * Clear out the newlines that have been appended to the list.
- *
- * @param list The list to clear.
- */
-void
-pm_newline_list_clear(pm_newline_list_t *list);
-
-/**
- * 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);
-
-/**
- * Returns the line of the given offset. If the offset is not in the list, the
- * line of the closest offset less than the given offset is returned.
- *
- * @param list The list to search.
- * @param cursor A pointer to the offset to search for.
- * @param start_line The line to start counting from.
- * @return The line of the given offset.
- */
-int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line);
-
-/**
- * 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.
- * @param start_line The line to start counting from.
- * @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, int32_t start_line);
-
-/**
- * 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_string.c b/prism/util/pm_string.c
deleted file mode 100644
index 75422fbdf2..0000000000
--- a/prism/util/pm_string.c
+++ /dev/null
@@ -1,383 +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
- };
-}
-
-#ifdef _WIN32
-/**
- * Represents a file handle on Windows, where the path will need to be freed
- * when the file is closed.
- */
-typedef struct {
- /** The path to the file, which will become allocated memory. */
- WCHAR *path;
-
- /** The handle to the file, which will start as uninitialized memory. */
- HANDLE file;
-} pm_string_file_handle_t;
-
-/**
- * Open the file indicated by the filepath parameter for reading on Windows.
- * Perform any kind of normalization that needs to happen on the filepath.
- */
-static pm_string_init_result_t
-pm_string_file_handle_open(pm_string_file_handle_t *handle, const char *filepath) {
- int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
- if (length == 0) return PM_STRING_INIT_ERROR_GENERIC;
-
- handle->path = xmalloc(sizeof(WCHAR) * ((size_t) length));
- if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
- xfree(handle->path);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
- if (handle->file == INVALID_HANDLE_VALUE) {
- pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC;
-
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- DWORD attributes = GetFileAttributesW(handle->path);
- if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
- result = PM_STRING_INIT_ERROR_DIRECTORY;
- }
- }
-
- xfree(handle->path);
- return result;
- }
-
- return PM_STRING_INIT_SUCCESS;
-}
-
-/**
- * Close the file handle and free the path.
- */
-static void
-pm_string_file_handle_close(pm_string_file_handle_t *handle) {
- xfree(handle->path);
- CloseHandle(handle->file);
-}
-#endif
-
-/**
- * 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`.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t
-pm_string_mapped_init(pm_string_t *string, const char *filepath) {
-#ifdef _WIN32
- // Open the file for reading.
- pm_string_file_handle_t handle;
- pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
- if (result != PM_STRING_INIT_SUCCESS) return result;
-
- // Get the file size.
- DWORD file_size = GetFileSize(handle.file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // 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) {
- pm_string_file_handle_close(&handle);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- // Create a mapping of the file.
- HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
- if (mapping == NULL) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Map the file into memory.
- uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
- CloseHandle(mapping);
- pm_string_file_handle_close(&handle);
-
- if (source == NULL) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
- return PM_STRING_INIT_SUCCESS;
-#elif defined(_POSIX_MAPPED_FILES)
- // Open the file for reading
- int fd = open(filepath, O_RDONLY);
- if (fd == -1) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Ensure it is a file and not a directory
- if (S_ISDIR(sb.st_mode)) {
- close(fd);
- return PM_STRING_INIT_ERROR_DIRECTORY;
- }
-
- // 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 PM_STRING_INIT_SUCCESS;
- }
-
- source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (source == MAP_FAILED) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- close(fd);
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
- return PM_STRING_INIT_SUCCESS;
-#else
- return pm_string_file_init(string, filepath);
-#endif
-}
-
-/**
- * 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.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t
-pm_string_file_init(pm_string_t *string, const char *filepath) {
-#ifdef _WIN32
- // Open the file for reading.
- pm_string_file_handle_t handle;
- pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
- if (result != PM_STRING_INIT_SUCCESS) return result;
-
- // Get the file size.
- DWORD file_size = GetFileSize(handle.file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // 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) {
- pm_string_file_handle_close(&handle);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- // Create a buffer to read the file into.
- uint8_t *source = xmalloc(file_size);
- if (source == NULL) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Read the contents of the file
- DWORD bytes_read;
- if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Check the number of bytes read
- if (bytes_read != file_size) {
- xfree(source);
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- pm_string_file_handle_close(&handle);
- *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size };
- return PM_STRING_INIT_SUCCESS;
-#elif defined(PRISM_HAS_FILESYSTEM)
- // Open the file for reading
- int fd = open(filepath, O_RDONLY);
- if (fd == -1) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Ensure it is a file and not a directory
- if (S_ISDIR(sb.st_mode)) {
- close(fd);
- return PM_STRING_INIT_ERROR_DIRECTORY;
- }
-
- // Check the size to see if it's empty
- size_t size = (size_t) sb.st_size;
- if (size == 0) {
- close(fd);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- size_t length = (size_t) size;
- uint8_t *source = xmalloc(length);
- if (source == NULL) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- long bytes_read = (long) read(fd, source, length);
- close(fd);
-
- if (bytes_read == -1) {
- xfree(source);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
- return PM_STRING_INIT_SUCCESS;
-#else
- (void) string;
- (void) filepath;
- perror("pm_string_file_init is not implemented for this platform");
- return PM_STRING_INIT_ERROR_GENERIC;
-#endif
-}
-
-/**
- * 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 = xmalloc(length);
- if (!memory) return;
-
- pm_string_owned_init(string, memory, length);
- memcpy((void *) string->source, source, length);
-}
-
-/**
- * Compare the underlying lengths and bytes of two strings. Returns 0 if the
- * strings are equal, a negative number if the left string is less than the
- * right string, and a positive number if the left string is greater than the
- * right string.
- */
-int
-pm_string_compare(const pm_string_t *left, const pm_string_t *right) {
- size_t left_length = pm_string_length(left);
- size_t right_length = pm_string_length(right);
-
- if (left_length < right_length) {
- return -1;
- } else if (left_length > right_length) {
- return 1;
- }
-
- return memcmp(pm_string_source(left), pm_string_source(right), left_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) {
- xfree(memory);
-#ifdef PRISM_HAS_MMAP
- } else if (string->type == PM_STRING_MAPPED && string->length) {
-#if defined(_WIN32)
- UnmapViewOfFile(memory);
-#elif defined(_POSIX_MAPPED_FILES)
- munmap(memory, string->length);
-#endif
-#endif /* PRISM_HAS_MMAP */
- }
-}
diff --git a/prism/util/pm_string.h b/prism/util/pm_string.h
deleted file mode 100644
index f99f1abdf3..0000000000
--- a/prism/util/pm_string.h
+++ /dev/null
@@ -1,190 +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 <errno.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>
-#elif defined(_POSIX_MAPPED_FILES)
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#elif defined(PRISM_HAS_FILESYSTEM)
-#include <fcntl.h>
-#include <sys/stat.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,
-
-#ifdef PRISM_HAS_MMAP
- /** This string is a memory-mapped file, and should be freed using `pm_string_free`. */
- PM_STRING_MAPPED
-#endif
- } 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);
-
-/**
- * Represents the result of calling pm_string_mapped_init or
- * pm_string_file_init. We need this additional information because there is
- * not a platform-agnostic way to indicate that the file that was attempted to
- * be opened was a directory.
- */
-typedef enum {
- /** Indicates that the string was successfully initialized. */
- PM_STRING_INIT_SUCCESS = 0,
- /**
- * Indicates a generic error from a string_*_init function, where the type
- * of error should be read from `errno` or `GetLastError()`.
- */
- PM_STRING_INIT_ERROR_GENERIC = 1,
- /**
- * Indicates that the file that was attempted to be opened was a directory.
- */
- PM_STRING_INIT_ERROR_DIRECTORY = 2
-} pm_string_init_result_t;
-
-/**
- * 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 The success of the read, indicated by the value of the enum.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_mapped_init(pm_string_t *string, const char *filepath);
-
-/**
- * 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.
- *
- * @param string The string to initialize.
- * @param filepath The filepath to read.
- * @return The success of the read, indicated by the value of the enum.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t *string, const char *filepath);
-
-/**
- * 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);
-
-/**
- * Compare the underlying lengths and bytes of two strings. Returns 0 if the
- * strings are equal, a negative number if the left string is less than the
- * right string, and a positive number if the left string is greater than the
- * right string.
- *
- * @param left The left string to compare.
- * @param right The right string to compare.
- * @return The comparison result.
- */
-int pm_string_compare(const pm_string_t *left, const pm_string_t *right);
-
-/**
- * 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_strncasecmp.c b/prism/util/pm_strncasecmp.c
deleted file mode 100644
index 3f58421554..0000000000
--- a/prism/util/pm_strncasecmp.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "prism/util/pm_strncasecmp.h"
-
-/**
- * A locale-insensitive version of `tolower(3)`
- */
-static inline int
-pm_tolower(int c)
-{
- if ('A' <= c && c <= 'Z') {
- return c | 0x20;
- }
- return c;
-}
-
-/**
- * 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 = pm_tolower(string1[offset]) - pm_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 916a4cc3fd..0000000000
--- a/prism/util/pm_strpbrk.c
+++ /dev/null
@@ -1,206 +0,0 @@
-#include "prism/util/pm_strpbrk.h"
-
-/**
- * Add an invalid multibyte character error to the parser.
- */
-static inline void
-pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_diagnostic_list_append_format(&parser->error_list, start, end, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *start);
-}
-
-/**
- * Set the explicit encoding for the parser to the current encoding.
- */
-static inline void
-pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, const uint8_t *source, size_t width) {
- if (parser->explicit_encoding != NULL) {
- if (parser->explicit_encoding == parser->encoding) {
- // Okay, we already locked to this encoding.
- } else if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- // Not okay, we already found a Unicode escape sequence and this
- // conflicts.
- pm_diagnostic_list_append_format(&parser->error_list, source, source + width, PM_ERR_MIXED_ENCODING, parser->encoding->name);
- } else {
- // Should not be anything else.
- assert(false && "unreachable");
- }
- }
-
- parser->explicit_encoding = parser->encoding;
-}
-
-/**
- * This is the default path.
- */
-static inline const uint8_t *
-pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (source[index] < 0x80) {
- index++;
- } else {
- size_t width = pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index));
-
- if (width > 0) {
- index += width;
- } else if (!validate) {
- index++;
- } else {
- // At this point we know we have an invalid multibyte character.
- // We'll walk forward as far as we can until we find the next
- // valid character so that we don't spam the user with a ton of
- // the same kind of error.
- const size_t start = index;
-
- do {
- index++;
- } while (index < maximum && pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
-
- pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * This is the path when the encoding is ASCII-8BIT.
- */
-static inline const uint8_t *
-pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (validate && source[index] >= 0x80) pm_strpbrk_explicit_encoding_set(parser, source, 1);
- index++;
- }
-
- return NULL;
-}
-
-/**
- * This is the slow path that does care about the encoding.
- */
-static inline const uint8_t *
-pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
- const pm_encoding_t *encoding = parser->encoding;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (source[index] < 0x80) {
- index++;
- } else {
- size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
- if (validate) pm_strpbrk_explicit_encoding_set(parser, source, width);
-
- if (width > 0) {
- index += width;
- } else if (!validate) {
- index++;
- } else {
- // At this point we know we have an invalid multibyte character.
- // We'll walk forward as far as we can until we find the next
- // valid character so that we don't spam the user with a ton of
- // the same kind of error.
- const size_t start = index;
-
- do {
- index++;
- } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
-
- pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * This is the fast path that does not care about the encoding because we know
- * the encoding only supports single-byte characters.
- */
-static inline const uint8_t *
-pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
- const pm_encoding_t *encoding = parser->encoding;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (source[index] < 0x80 || !validate) {
- index++;
- } else {
- size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
- pm_strpbrk_explicit_encoding_set(parser, source, width);
-
- if (width > 0) {
- index += width;
- } else {
- // At this point we know we have an invalid multibyte character.
- // We'll walk forward as far as we can until we find the next
- // valid character so that we don't spam the user with a ton of
- // the same kind of error.
- const size_t start = index;
-
- do {
- index++;
- } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
-
- pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * Here we have rolled our own version of strpbrk. The standard library strpbrk
- * has undefined behavior when the source string is not null-terminated. We want
- * to support strings that are not null-terminated because pm_parse does not
- * have the contract that the string is null-terminated. (This is desirable
- * because it means the extension can call pm_parse with the result of a call to
- * mmap).
- *
- * The standard library strpbrk also does not support passing a maximum length
- * to search. We want to support this for the reason mentioned above, but we
- * also don't want it to stop on null bytes. Ruby actually allows null bytes
- * within strings, comments, regular expressions, etc. So we need to be able to
- * skip past them.
- *
- * Finally, we want to support encodings wherein the charset could contain
- * characters that are trailing bytes of multi-byte characters. For example, in
- * Shift_JIS, the backslash character can be a trailing byte. In that case we
- * need to take a slower path and iterate one multi-byte character at a time.
- */
-const uint8_t *
-pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate) {
- if (length <= 0) {
- return NULL;
- } else if (!parser->encoding_changed) {
- return pm_strpbrk_utf8(parser, source, charset, (size_t) length, validate);
- } else if (parser->encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
- return pm_strpbrk_ascii_8bit(parser, source, charset, (size_t) length, validate);
- } else if (parser->encoding->multibyte) {
- return pm_strpbrk_multi_byte(parser, source, charset, (size_t) length, validate);
- } else {
- return pm_strpbrk_single_byte(parser, source, charset, (size_t) length, validate);
- }
-}
diff --git a/prism/util/pm_strpbrk.h b/prism/util/pm_strpbrk.h
deleted file mode 100644
index f387bd5782..0000000000
--- a/prism/util/pm_strpbrk.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @file pm_strpbrk.h
- *
- * A custom strpbrk implementation.
- */
-#ifndef PRISM_STRPBRK_H
-#define PRISM_STRPBRK_H
-
-#include "prism/defines.h"
-#include "prism/diagnostic.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.
- * @param validate Whether to validate that the source string is valid in the
- * current encoding of the parser.
- * @return A pointer to the first character in the source string that is in the
- * charset, or NULL if no such character exists.
- */
-const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate);
-
-#endif
diff --git a/prism/version.h b/prism/version.h
index 0a2a8c8fce..181b398462 100644
--- a/prism/version.h
+++ b/prism/version.h
@@ -6,6 +6,8 @@
#ifndef PRISM_VERSION_H
#define PRISM_VERSION_H
+#include "prism/compiler/exported.h"
+
/**
* The major version of the Prism library as an int.
*/
@@ -14,7 +16,7 @@
/**
* The minor version of the Prism library as an int.
*/
-#define PRISM_VERSION_MINOR 4
+#define PRISM_VERSION_MINOR 9
/**
* The patch version of the Prism library as an int.
@@ -24,6 +26,13 @@
/**
* The version of the Prism library as a constant string.
*/
-#define PRISM_VERSION "1.4.0"
+#define PRISM_VERSION "1.9.0"
+
+/**
+ * The prism version and the serialization format.
+ *
+ * @returns The prism version as a constant string.
+ */
+PRISM_EXPORTED_FUNCTION const char * pm_version(void);
#endif
diff --git a/prism_compile.c b/prism_compile.c
index 6de3f69c29..45e1de8a9c 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -1,4 +1,7 @@
#include "prism.h"
+#include "ruby/version.h"
+
+#include <fcntl.h>
/**
* This compiler defines its own concept of the location of a node. We do this
@@ -101,6 +104,7 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node
else {
ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(setlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
}
+ update_lvar_state(iseq, level, idx);
if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
}
@@ -138,33 +142,127 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node
#define PM_COMPILE_NOT_POPPED(node) \
pm_compile_node(iseq, (node), ret, false, scope_node)
-#define PM_NODE_START_LOCATION(parser, node) \
- ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id })
+// Direct-indexed lookup table. -1 means "not present".
+#define PM_INDEX_LOOKUP_TABLE_INIT { .values = NULL, .capacity = 0, .owned = false }
-#define PM_NODE_END_LOCATION(parser, node) \
- ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.end, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id })
+static inline void
+pm_index_lookup_table_init(pm_index_lookup_table_t *table, int constants_size, rb_iseq_t *iseq)
+{
+ int capacity = constants_size + PM_INDEX_LOOKUP_SPECIALS;
+ table->values = compile_data_alloc2_type(iseq, int, capacity);
+ memset(table->values, -1, capacity * sizeof(int));
+ table->capacity = capacity;
+ table->owned = false;
+}
-#define PM_LOCATION_START_LOCATION(parser, location, id) \
- ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, (location)->start, (parser)->start_line), .node_id = id })
+/**
+ * Cached line lookup that avoids repeated binary searches. Since the compiler
+ * walks the AST roughly in source order, consecutive lookups tend to be for
+ * nearby byte offsets. We cache the last result index in the scope node and
+ * try a short linear probe from there before falling back to binary search.
+ */
+static inline pm_line_column_t
+pm_line_offset_list_line_column_cached(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line, size_t *last_line)
+{
+ size_t hint = *last_line;
+ size_t size = list->size;
+ const uint32_t *offsets = list->offsets;
-#define PM_NODE_START_LINE_COLUMN(parser, node) \
- pm_newline_list_line_column(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line)
+ RUBY_ASSERT(hint < size);
-#define PM_NODE_END_LINE_COLUMN(parser, node) \
- pm_newline_list_line_column(&(parser)->newline_list, ((const pm_node_t *) (node))->location.end, (parser)->start_line)
+ /* Check if the cursor is on the same line as the hint. */
+ if (offsets[hint] <= cursor) {
+ if (hint + 1 >= size || offsets[hint + 1] > cursor) {
+ *last_line = hint;
+ return ((pm_line_column_t) {
+ .line = ((int32_t) hint) + start_line,
+ .column = cursor - offsets[hint]
+ });
+ }
-#define PM_LOCATION_START_LINE_COLUMN(parser, location) \
- pm_newline_list_line_column(&(parser)->newline_list, (location)->start, (parser)->start_line)
+ /* Linear scan forward (up to 8 lines before giving up). */
+ size_t limit = hint + 9;
+ if (limit > size) limit = size;
+ for (size_t idx = hint + 1; idx < limit; idx++) {
+ if (offsets[idx] > cursor) {
+ *last_line = idx - 1;
+ return ((pm_line_column_t) {
+ .line = ((int32_t) (idx - 1)) + start_line,
+ .column = cursor - offsets[idx - 1]
+ });
+ }
+ if (offsets[idx] == cursor) {
+ *last_line = idx;
+ return ((pm_line_column_t) { ((int32_t) idx) + start_line, 0 });
+ }
+ }
+ }
+ else {
+ /* Linear scan backward (up to 8 lines before giving up). */
+ size_t limit = hint > 8 ? hint - 8 : 0;
+ for (size_t idx = hint; idx > limit; idx--) {
+ if (offsets[idx - 1] <= cursor) {
+ *last_line = idx - 1;
+ return ((pm_line_column_t) {
+ .line = ((int32_t) (idx - 1)) + start_line,
+ .column = cursor - offsets[idx - 1]
+ });
+ }
+ }
+ }
-static int
-pm_node_line_number(const pm_parser_t *parser, const pm_node_t *node)
+ /* Fall back to binary search. */
+ pm_line_column_t result = pm_line_offset_list_line_column(list, cursor, start_line);
+ *last_line = (size_t) (result.line - start_line);
+ return result;
+}
+
+/**
+ * The same as pm_line_offset_list_line_column_cached, but returning only the
+ * line number.
+ */
+static inline int32_t
+pm_line_offset_list_line_cached(const pm_line_offset_list_t *list, uint32_t cursor, int32_t start_line, size_t *last_line)
{
- return (int) pm_newline_list_line(&parser->newline_list, node->location.start, parser->start_line);
+ return pm_line_offset_list_line_column_cached(list, cursor, start_line, last_line).line;
}
+#define PM_NODE_START_LOCATION(node) \
+ ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start, scope_node->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id })
+
+#define PM_NODE_END_LOCATION(node) \
+ ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, scope_node->start_line, &scope_node->last_line), .node_id = ((const pm_node_t *) (node))->node_id })
+
+#define PM_LOCATION_START_LOCATION(location, id) \
+ ((pm_node_location_t) { .line = pm_line_offset_list_line_cached(scope_node->line_offsets, (location)->start, scope_node->start_line, &scope_node->last_line), .node_id = id })
+
+#define PM_NODE_START_LINE_COLUMN(node) \
+ pm_line_offset_list_line_column_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start, scope_node->start_line, &scope_node->last_line)
+
+#define PM_NODE_END_LINE_COLUMN(node) \
+ pm_line_offset_list_line_column_cached(scope_node->line_offsets, ((const pm_node_t *) (node))->location.start + ((const pm_node_t *) (node))->location.length, scope_node->start_line, &scope_node->last_line)
+
+#define PM_LOCATION_START_LINE_COLUMN(location) \
+ pm_line_offset_list_line_column_cached(scope_node->line_offsets, (location)->start, scope_node->start_line, &scope_node->last_line)
+
static int
pm_location_line_number(const pm_parser_t *parser, const pm_location_t *location) {
- return (int) pm_newline_list_line(&parser->newline_list, location->start, parser->start_line);
+ return (int) pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location->start, pm_parser_start_line(parser)).line;
+}
+
+/**
+ * Cached variants that use the scope node's hint for fast lookups during
+ * compilation (where access patterns are roughly sequential).
+ */
+static inline int
+pm_node_line_number_cached(const pm_node_t *node, pm_scope_node_t *scope_node)
+{
+ return (int) pm_line_offset_list_line_cached(scope_node->line_offsets, node->location.start, scope_node->start_line, &scope_node->last_line);
+}
+
+static inline int
+pm_location_line_number_cached(const pm_location_t *location, pm_scope_node_t *scope_node) {
+ return (int) pm_line_offset_list_line_cached(scope_node->line_offsets, location->start, scope_node->start_line, &scope_node->last_line);
}
/**
@@ -179,24 +277,25 @@ parse_integer_value(const pm_integer_t *integer)
result = UINT2NUM(integer->value);
}
else {
- VALUE string = rb_str_new(NULL, integer->length * 8);
- unsigned char *bytes = (unsigned char *) RSTRING_PTR(string);
-
- size_t offset = integer->length * 8;
- for (size_t value_index = 0; value_index < integer->length; value_index++) {
- uint32_t value = integer->values[value_index];
-
- for (int index = 0; index < 8; index++) {
- int byte = (value >> (4 * index)) & 0xf;
- bytes[--offset] = byte < 10 ? byte + '0' : byte - 10 + 'a';
- }
- }
-
- result = rb_funcall(string, rb_intern("to_i"), 1, UINT2NUM(16));
+ // The pm_integer_t stores values as an array of uint32_t in
+ // least-significant-word-first order (base 2^32). We can convert
+ // directly to a Ruby Integer using rb_integer_unpack, avoiding the
+ // overhead of constructing a hex string and calling rb_funcall.
+ result = rb_integer_unpack(
+ integer->values,
+ integer->length,
+ sizeof(uint32_t),
+ 0,
+ INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER
+ );
}
if (integer->negative) {
- result = rb_funcall(result, rb_intern("-@"), 0);
+ result = rb_int_uminus(result);
+ }
+
+ if (!SPECIAL_CONST_P(result)) {
+ RB_OBJ_SET_SHAREABLE(result); // bignum
}
return result;
@@ -217,7 +316,11 @@ parse_integer(const pm_integer_node_t *node)
static VALUE
parse_float(const pm_float_node_t *node)
{
- return DBL2NUM(node->value);
+ VALUE val = DBL2NUM(node->value);
+ if (!FLONUM_P(val)) {
+ RB_OBJ_SET_SHAREABLE(val);
+ }
+ return val;
}
/**
@@ -231,7 +334,8 @@ parse_rational(const pm_rational_node_t *node)
{
VALUE numerator = parse_integer_value(&node->numerator);
VALUE denominator = parse_integer_value(&node->denominator);
- return rb_rational_new(numerator, denominator);
+
+ return rb_ractor_make_shareable(rb_rational_new(numerator, denominator));
}
/**
@@ -258,10 +362,10 @@ parse_imaginary(const pm_imaginary_node_t *node)
break;
}
default:
- rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type_to_str(PM_NODE_TYPE(node->numeric)));
+ rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type(PM_NODE_TYPE(node->numeric)));
}
- return rb_complex_raw(INT2FIX(0), imaginary_part);
+ return RB_OBJ_SET_SHAREABLE(rb_complex_raw(INT2FIX(0), imaginary_part));
}
static inline VALUE
@@ -294,7 +398,7 @@ parse_string_encoded(const pm_node_t *node, const pm_string_t *string, rb_encodi
}
static inline VALUE
-parse_static_literal_string(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *string)
+parse_static_literal_string(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *string)
{
rb_encoding *encoding;
@@ -312,8 +416,8 @@ parse_static_literal_string(rb_iseq_t *iseq, const pm_scope_node_t *scope_node,
rb_enc_str_coderange(value);
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
- int line_number = pm_node_line_number(scope_node->parser, node);
- value = rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number);
+ int line_number = pm_node_line_number_cached(node, scope_node);
+ value = rb_ractor_make_shareable(rb_str_with_debug_created_info(value, rb_iseq_path(iseq), line_number));
}
return value;
@@ -357,7 +461,7 @@ parse_regexp_error(rb_iseq_t *iseq, int32_t line_number, const char *fmt, ...)
}
static VALUE
-parse_regexp_string_part(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding)
+parse_regexp_string_part(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding)
{
// If we were passed an explicit regexp encoding, then we need to double
// check that it's okay here for this fragment of the string.
@@ -379,12 +483,12 @@ parse_regexp_string_part(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, con
VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), encoding);
VALUE error = rb_reg_check_preprocess(string);
- if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number(scope_node->parser, node), "%" PRIsVALUE, rb_obj_as_string(error));
+ if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(node, scope_node), "%" PRIsVALUE, rb_obj_as_string(error));
return string;
}
static VALUE
-pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, const pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool top)
+pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool top)
{
VALUE current = Qnil;
@@ -401,7 +505,7 @@ pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, const pm_
else {
string = parse_string_encoded(part, &((const pm_string_node_t *) part)->unescaped, scope_node->encoding);
VALUE error = rb_reg_check_preprocess(string);
- if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number(scope_node->parser, part), "%" PRIsVALUE, rb_obj_as_string(error));
+ if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number_cached(part, scope_node), "%" PRIsVALUE, rb_obj_as_string(error));
}
}
else {
@@ -514,12 +618,12 @@ parse_regexp_encoding(const pm_scope_node_t *scope_node, const pm_node_t *node)
}
static VALUE
-parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, VALUE string)
+parse_regexp(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, VALUE string)
{
VALUE errinfo = rb_errinfo();
- int32_t line_number = pm_node_line_number(scope_node->parser, node);
- VALUE regexp = rb_reg_compile(string, parse_regexp_flags(node), (const char *) pm_string_source(&scope_node->parser->filepath), line_number);
+ int32_t line_number = pm_node_line_number_cached(node, scope_node);
+ VALUE regexp = rb_reg_compile(string, parse_regexp_flags(node), (const char *) pm_string_source(pm_parser_filepath(scope_node->parser)), line_number);
if (NIL_P(regexp)) {
VALUE message = rb_attr_get(rb_errinfo(), idMesg);
@@ -529,22 +633,22 @@ parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t
return Qnil;
}
- rb_obj_freeze(regexp);
- return regexp;
+ return RB_OBJ_SET_SHAREABLE(rb_obj_freeze(regexp));
}
static inline VALUE
-parse_regexp_literal(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped)
+parse_regexp_literal(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped)
{
rb_encoding *regexp_encoding = parse_regexp_encoding(scope_node, node);
if (regexp_encoding == NULL) regexp_encoding = scope_node->encoding;
VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), regexp_encoding);
+ RB_OBJ_SET_SHAREABLE(string);
return parse_regexp(iseq, scope_node, node, string);
}
static inline VALUE
-parse_regexp_concat(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_node_list_t *parts)
+parse_regexp_concat(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, const pm_node_list_t *parts)
{
rb_encoding *explicit_regexp_encoding = parse_regexp_encoding(scope_node, node);
rb_encoding *implicit_regexp_encoding = explicit_regexp_encoding != NULL ? explicit_regexp_encoding : scope_node->encoding;
@@ -556,7 +660,7 @@ parse_regexp_concat(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm
static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node);
static int
-pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding)
+pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool mutable_result, bool frozen_result)
{
int stack_size = 0;
size_t parts_size = parts->size;
@@ -585,7 +689,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
}
else {
current_string = string_value;
- if (index != 0) current_location = PM_NODE_END_LOCATION(scope_node->parser, part);
+ if (index != 0) current_location = PM_NODE_END_LOCATION(part);
}
}
else {
@@ -612,7 +716,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
}
else {
current_string = string_value;
- current_location = PM_NODE_START_LOCATION(scope_node->parser, part);
+ current_location = PM_NODE_START_LOCATION(part);
}
}
else {
@@ -623,7 +727,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
if (explicit_regexp_encoding != NULL) {
encoding = explicit_regexp_encoding;
}
- else if (scope_node->parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
+ else if (pm_parser_encoding_us_ascii(scope_node->parser)) {
encoding = rb_ascii8bit_encoding();
}
else {
@@ -647,7 +751,7 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
PM_COMPILE_NOT_POPPED(part);
- const pm_node_location_t current_location = PM_NODE_START_LOCATION(scope_node->parser, part);
+ const pm_node_location_t current_location = PM_NODE_START_LOCATION(part);
PUSH_INSN(ret, current_location, dup);
{
@@ -666,10 +770,15 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
if (RTEST(current_string)) {
current_string = rb_fstring(current_string);
- if (stack_size == 0 && interpolated) {
- PUSH_INSN1(ret, current_location, putstring, current_string);
- }
- else {
+ if (stack_size == 0) {
+ if (frozen_result) {
+ PUSH_INSN1(ret, current_location, putobject, current_string);
+ } else if (mutable_result || interpolated) {
+ PUSH_INSN1(ret, current_location, dupstring, current_string);
+ } else {
+ PUSH_INSN1(ret, current_location, dupchilledstring, current_string);
+ }
+ } else {
PUSH_INSN1(ret, current_location, putobject, current_string);
}
@@ -690,7 +799,7 @@ pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_
rb_encoding *explicit_regexp_encoding = parse_regexp_encoding(scope_node, node);
rb_encoding *implicit_regexp_encoding = explicit_regexp_encoding != NULL ? explicit_regexp_encoding : scope_node->encoding;
- int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_node, implicit_regexp_encoding, explicit_regexp_encoding);
+ int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false, false);
PUSH_INSN2(ret, *node_location, toregexp, INT2FIX(parse_regexp_flags(node) & 0xFF), INT2FIX(length));
}
@@ -717,7 +826,9 @@ static VALUE
pm_static_literal_string(rb_iseq_t *iseq, VALUE string, int line_number)
{
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
- return rb_str_with_debug_created_info(string, rb_iseq_path(iseq), line_number);
+ VALUE str = rb_str_with_debug_created_info(string, rb_iseq_path(iseq), line_number);
+ RB_OBJ_SET_SHAREABLE(str);
+ return str;
}
else {
return rb_fstring(string);
@@ -730,7 +841,7 @@ pm_static_literal_string(rb_iseq_t *iseq, VALUE string, int line_number)
* literal values can be compiled into a literal array.
*/
static VALUE
-pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_node_t *scope_node)
+pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t *scope_node)
{
// Every node that comes into this function should already be marked as
// static literal. If it's not, then we have a bug somewhere.
@@ -746,7 +857,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
rb_ary_push(value, pm_static_literal_value(iseq, elements->nodes[index], scope_node));
}
- OBJ_FREEZE(value);
+ RB_OBJ_SET_FROZEN_SHAREABLE(value);
return value;
}
case PM_FALSE_NODE:
@@ -765,11 +876,11 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
rb_ary_cat(array, pair, 2);
}
- VALUE value = rb_hash_new_with_size(elements->size);
+ VALUE value = rb_hash_alloc_fixed_size(Qfalse, elements->size);
rb_hash_bulk_insert(RARRAY_LEN(array), RARRAY_CONST_PTR(array), value);
+ RB_GC_GUARD(array);
- value = rb_obj_hide(value);
- OBJ_FREEZE(value);
+ RB_OBJ_SET_FROZEN_SHAREABLE(value);
return value;
}
case PM_IMAGINARY_NODE:
@@ -786,7 +897,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
}
case PM_INTERPOLATED_STRING_NODE: {
VALUE string = pm_static_literal_concat(iseq, &((const pm_interpolated_string_node_t *) node)->parts, scope_node, NULL, NULL, false);
- int line_number = pm_node_line_number(scope_node->parser, node);
+ int line_number = pm_node_line_number_cached(node, scope_node);
return pm_static_literal_string(iseq, string, line_number);
}
case PM_INTERPOLATED_SYMBOL_NODE: {
@@ -814,7 +925,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
return pm_source_file_value(cast, scope_node);
}
case PM_SOURCE_LINE_NODE:
- return INT2FIX(pm_node_line_number(scope_node->parser, node));
+ return INT2FIX(pm_node_line_number_cached(node, scope_node));
case PM_STRING_NODE: {
const pm_string_node_t *cast = (const pm_string_node_t *) node;
return parse_static_literal_string(iseq, scope_node, node, &cast->unescaped);
@@ -824,7 +935,7 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
case PM_TRUE_NODE:
return Qtrue;
default:
- rb_bug("Don't have a literal value for node type %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Don't have a literal value for node type %s", pm_node_type(PM_NODE_TYPE(node)));
return Qfalse;
}
}
@@ -833,10 +944,10 @@ pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_n
* A helper for converting a pm_location_t into a rb_code_location_t.
*/
static rb_code_location_t
-pm_code_location(const pm_scope_node_t *scope_node, const pm_node_t *node)
+pm_code_location(pm_scope_node_t *scope_node, const pm_node_t *node)
{
- const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node);
- const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(scope_node->parser, node);
+ const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(node);
+ const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(node);
return (rb_code_location_t) {
.beg_pos = { .lineno = start_location.line, .column = start_location.column },
@@ -853,12 +964,12 @@ pm_code_location(const pm_scope_node_t *scope_node, const pm_node_t *node)
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, bool popped, pm_scope_node_t *scope_node);
+ LABEL *then_label, LABEL *else_label, 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, bool popped, pm_scope_node_t *scope_node)
+pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LABEL *then_label, LABEL *else_label, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(cond);
DECL_ANCHOR(seq);
@@ -866,17 +977,14 @@ pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LAB
if (!then_label) then_label = label;
else if (!else_label) else_label = label;
- pm_compile_branch_condition(iseq, seq, cond, then_label, else_label, popped, scope_node);
+ pm_compile_branch_condition(iseq, seq, cond, then_label, else_label, 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) {
- if (popped) PUSH_INSN(ret, location, putnil);
- }
- else {
+ if (label->refcnt) {
PUSH_LABEL(seq, label);
}
@@ -887,7 +995,7 @@ pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LAB
static void
pm_compile_flip_flop_bound(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .node_id = -1 };
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
if (PM_NODE_TYPE_P(node, PM_INTEGER_NODE)) {
PM_COMPILE_NOT_POPPED(node);
@@ -906,7 +1014,7 @@ pm_compile_flip_flop_bound(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *
static void
pm_compile_flip_flop(const 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, bool popped, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .node_id = -1 };
+ const pm_node_location_t location = { .line = lineno, .node_id = -1 };
LABEL *lend = NEW_LABEL(location.line);
int again = !(flip_flop_node->base.flags & PM_RANGE_FLAGS_EXCLUDE_END);
@@ -948,22 +1056,22 @@ pm_compile_flip_flop(const pm_flip_flop_node_t *flip_flop_node, LABEL *else_labe
static void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, 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, bool popped, pm_scope_node_t *scope_node)
+pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond, LABEL *then_label, LABEL *else_label, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(cond);
again:
switch (PM_NODE_TYPE(cond)) {
case PM_AND_NODE: {
const pm_and_node_t *cast = (const pm_and_node_t *) cond;
- pm_compile_logical(iseq, ret, cast->left, NULL, else_label, popped, scope_node);
+ pm_compile_logical(iseq, ret, cast->left, NULL, else_label, scope_node);
cond = cast->right;
goto again;
}
case PM_OR_NODE: {
const pm_or_node_t *cast = (const pm_or_node_t *) cond;
- pm_compile_logical(iseq, ret, cast->left, then_label, NULL, popped, scope_node);
+ pm_compile_logical(iseq, ret, cast->left, then_label, NULL, scope_node);
cond = cast->right;
goto again;
@@ -984,11 +1092,11 @@ again:
PUSH_INSNL(ret, location, jump, then_label);
return;
case PM_FLIP_FLOP_NODE:
- pm_compile_flip_flop((const pm_flip_flop_node_t *) cond, else_label, then_label, iseq, location.line, ret, popped, scope_node);
+ pm_compile_flip_flop((const pm_flip_flop_node_t *) cond, else_label, then_label, iseq, location.line, ret, false, scope_node);
return;
case PM_DEFINED_NODE: {
const pm_defined_node_t *cast = (const pm_defined_node_t *) cond;
- pm_compile_defined_expr(iseq, cast->value, &location, ret, popped, scope_node, true);
+ pm_compile_defined_expr(iseq, cast->value, &location, ret, false, scope_node, true);
break;
}
default: {
@@ -1032,7 +1140,7 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_location,
LABEL *end_label = NULL;
DECL_ANCHOR(cond_seq);
- pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, false, scope_node);
+ pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, scope_node);
PUSH_SEQ(ret, cond_seq);
rb_code_location_t conditional_location = { 0 };
@@ -1063,7 +1171,7 @@ pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_location,
if (statements != NULL) {
branch_location = pm_code_location(scope_node, (const pm_node_t *) statements);
} else if (type == PM_IF_NODE) {
- pm_line_column_t predicate_end = PM_NODE_END_LINE_COLUMN(scope_node->parser, predicate);
+ pm_line_column_t predicate_end = PM_NODE_END_LINE_COLUMN(predicate);
branch_location = (rb_code_location_t) {
.beg_pos = { .lineno = predicate_end.line, .column = predicate_end.column },
.end_pos = { .lineno = predicate_end.line, .column = predicate_end.column }
@@ -1180,10 +1288,10 @@ pm_compile_loop(rb_iseq_t *iseq, const pm_node_location_t *node_location, pm_nod
PUSH_LABEL(ret, next_label);
if (type == PM_WHILE_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, popped, scope_node);
+ pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, scope_node);
}
else if (type == PM_UNTIL_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, popped, scope_node);
+ pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, scope_node);
}
PUSH_LABEL(ret, end_label);
@@ -1212,14 +1320,15 @@ static pm_local_index_t
pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_constant_id_t constant_id, int start_depth)
{
pm_local_index_t lindex = { 0 };
- st_data_t local_index;
+ int local_index;
int level;
for (level = 0; level < start_depth; level++) {
scope_node = scope_node->previous;
}
- while (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
+ while (!pm_index_lookup_table_lookup(&scope_node->index_lookup_table, constant_id, &local_index))
+ {
level++;
if (scope_node->previous) {
@@ -1243,12 +1352,10 @@ pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_con
// We add a constants mapping on the scope_node which is a mapping from
// these constant_id indexes to the CRuby IDs that they represent.
// This helper method allows easy access to those IDs
-static ID
+static inline ID
pm_constant_id_lookup(const pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
{
- if (constant_id < 1 || constant_id > scope_node->parser->constant_pool.size) {
- rb_bug("constant_id out of range: %u", (unsigned int)constant_id);
- }
+ RUBY_ASSERT(constant_id >= 1 && constant_id <= pm_parser_constants_size(scope_node->parser));
return scope_node->constants[constant_id - 1];
}
@@ -1257,31 +1364,46 @@ pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_i
{
debugs("[new_child_iseq]> ---------------------------------------\n");
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- int error_state;
- rb_iseq_t *ret_iseq = pm_iseq_new_with_opt(node, name,
+ rb_iseq_t *ret_iseq = pm_iseq_build(node, name,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
line_no, parent,
isolated_depth ? isolated_depth + 1 : 0,
- type, ISEQ_COMPILE_DATA(iseq)->option, &error_state);
-
- if (error_state) {
- RUBY_ASSERT(ret_iseq == NULL);
- rb_jump_tag(error_state);
- }
+ type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
return ret_iseq;
}
static int
+pm_cpath_const_p(const pm_node_t *node)
+{
+ switch (PM_NODE_TYPE(node)) {
+ case PM_CONSTANT_READ_NODE:
+ return TRUE;
+ case PM_CONSTANT_PATH_NODE:
+ {
+ const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent;
+ if (!parent) return TRUE; /* ::Foo */
+ return pm_cpath_const_p(parent);
+ }
+ default:
+ return FALSE;
+ }
+}
+
+static int
pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
if (PM_NODE_TYPE_P(node, PM_CONSTANT_PATH_NODE)) {
const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent;
if (parent) {
- /* Bar::Foo */
+ /* Bar::Foo or expr::Foo */
PM_COMPILE(parent);
- return VM_DEFINECLASS_FLAG_SCOPED;
+ int flags = VM_DEFINECLASS_FLAG_SCOPED;
+ if (!pm_cpath_const_p(parent)) {
+ flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+ return flags;
}
else {
/* toplevel class ::Foo */
@@ -1361,7 +1483,7 @@ static void pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t
static void
pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, const pm_node_flags_t shareability, VALUE path, bool argument, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
// If this element is not popped, then we need to create the hash on the
// stack. Neighboring plain assoc nodes should be grouped together (either
@@ -1434,10 +1556,10 @@ pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
}
index --;
- VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
+ VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
- hash = rb_obj_hide(hash);
- OBJ_FREEZE(hash);
+ RB_GC_GUARD(ary);
+ RB_OBJ_SET_FROZEN_SHAREABLE(hash);
// Emit optimized code.
FLUSH_CHUNK;
@@ -1761,9 +1883,14 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
break;
}
- orig_argc += 2;
+ if (has_splat) {
+ // If we already have a splat, we're concatenating to existing array
+ orig_argc += 1;
+ } else {
+ orig_argc += 2;
+ }
- *flags |= VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_SPLAT_MUT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT;
+ *flags |= VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT;
// Forwarding arguments nodes are treated as foo(*, **, &)
// So foo(...) equals foo(*, **, &) and as such the local
@@ -1772,7 +1899,13 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// Push the *
pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_MULT, 0);
PUSH_GETLOCAL(ret, location, mult_local.index, mult_local.level);
- PUSH_INSN1(ret, location, splatarray, Qtrue);
+
+ if (has_splat) {
+ // If we already have a splat, we need to concatenate arrays
+ PUSH_INSN(ret, location, concattoarray);
+ } else {
+ PUSH_INSN1(ret, location, splatarray, Qfalse);
+ }
// Push the **
pm_local_index_t pow_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_POW, 0);
@@ -1781,7 +1914,6 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// Push the &
pm_local_index_t and_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_AND, 0);
PUSH_INSN2(ret, location, getblockparamproxy, INT2FIX(and_local.index + VM_ENV_DATA_SIZE - 1), INT2FIX(and_local.level));
- PUSH_INSN(ret, location, splatkw);
break;
}
@@ -1804,6 +1936,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// foo(*a, b, c: :d)
// foo(*a, b, **c)
//
+ // If the next node is a forwarding argument:
+ //
+ // foo(*a, b, ...)
+ //
// If the next node is NULL (we have hit the end):
//
// foo(*a, b)
@@ -1826,6 +1962,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
PUSH_INSN(ret, location, concatarray);
break;
}
+ case PM_FORWARDING_ARGUMENTS_NODE: {
+ PUSH_INSN1(ret, location, pushtoarray, INT2FIX(post_splat_counter));
+ break;
+ }
default:
break;
}
@@ -1854,7 +1994,6 @@ pm_setup_args_dup_rest_p(const pm_node_t *node)
switch (PM_NODE_TYPE(node)) {
case PM_BACK_REFERENCE_READ_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:
@@ -1873,8 +2012,24 @@ pm_setup_args_dup_rest_p(const pm_node_t *node)
case PM_SYMBOL_NODE:
case PM_TRUE_NODE:
return false;
+ case PM_CONSTANT_PATH_NODE: {
+ const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
+ if (cast->parent != NULL) {
+ return pm_setup_args_dup_rest_p(cast->parent);
+ }
+ return false;
+ }
case PM_IMPLICIT_NODE:
return pm_setup_args_dup_rest_p(((const pm_implicit_node_t *) node)->value);
+ case PM_ARRAY_NODE: {
+ const pm_array_node_t *cast = (const pm_array_node_t *) node;
+ for (size_t index = 0; index < cast->elements.size; index++) {
+ if (pm_setup_args_dup_rest_p(cast->elements.nodes[index])) {
+ return true;
+ }
+ }
+ return false;
+ }
default:
return true;
}
@@ -2244,7 +2399,7 @@ pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node,
// 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, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index);
+static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index);
/**
* This function generates the code to set up the error string and error_p
@@ -2253,7 +2408,7 @@ static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, cons
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)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *match_succeeded_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
@@ -2283,7 +2438,7 @@ pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, c
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)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *match_succeeded_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
@@ -2316,7 +2471,7 @@ pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, co
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)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *match_succeeded_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
@@ -2350,10 +2505,10 @@ pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const
* 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, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
+pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
{
- LABEL *matched_label = NEW_LABEL(pm_node_line_number(scope_node->parser, node));
- CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
+ LABEL *matched_label = NEW_LABEL(pm_node_line_number_cached(node, scope_node));
+ CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
PUSH_LABEL(ret, matched_label);
return COMPILE_OK;
}
@@ -2366,7 +2521,7 @@ pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_
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, 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)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
if (use_deconstructed_cache) {
PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
@@ -2420,7 +2575,7 @@ pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, con
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, LABEL *match_failed_label, bool in_single_pattern, unsigned int base_index)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
PUSH_INSN(ret, location, dup);
PM_COMPILE_NOT_POPPED(node);
@@ -2441,9 +2596,9 @@ pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const
* 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, LABEL *done_label, bool popped)
+pm_compile_pattern_error_handler(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *done_label, bool popped)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
LABEL *key_error_label = NEW_LABEL(location.line);
LABEL *cleanup_label = NEW_LABEL(location.line);
@@ -2500,9 +2655,9 @@ pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_n
* 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, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
+pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_ARRAY_PATTERN_NODE: {
@@ -2560,7 +2715,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN(ret, location, dup);
PUSH_INSN1(ret, location, putobject, INT2FIX(index));
PUSH_SEND(ret, location, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
if (cast->rest != NULL) {
@@ -2573,7 +2728,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_SEND(ret, location, idMINUS, INT2FIX(1));
PUSH_INSN1(ret, location, setn, INT2FIX(4));
PUSH_SEND(ret, location, idAREF, INT2FIX(2));
- CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
else if (posts_size > 0) {
PUSH_INSN(ret, location, dup);
@@ -2593,7 +2748,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN1(ret, location, topn, INT2FIX(3));
PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
PUSH_SEND(ret, location, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, false, base_index + 1));
}
PUSH_INSN(ret, location, pop);
@@ -2690,7 +2845,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
}
PUSH_SEND(ret, location, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, false, base_index + 4));
}
const pm_splat_node_t *left = cast->left;
@@ -2700,11 +2855,10 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN1(ret, location, putobject, INT2FIX(0));
PUSH_INSN1(ret, location, topn, INT2FIX(2));
PUSH_SEND(ret, location, idAREF, INT2FIX(2));
- CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4));
}
- RUBY_ASSERT(PM_NODE_TYPE_P(cast->right, PM_SPLAT_NODE));
- const pm_splat_node_t *right = (const pm_splat_node_t *) cast->right;
+ const pm_splat_node_t *right = cast->right;
if (right->expression != NULL) {
PUSH_INSN1(ret, location, topn, INT2FIX(3));
@@ -2713,7 +2867,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
PUSH_INSN1(ret, location, topn, INT2FIX(3));
PUSH_SEND(ret, location, idAREF, INT2FIX(2));
- pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4);
+ pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4);
}
PUSH_INSNL(ret, location, jump, find_succeeded_label);
@@ -2827,8 +2981,10 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
PUSH_INSN(ret, location, putnil);
}
else {
+ rb_obj_hide(keys);
+ RB_OBJ_SET_FROZEN_SHAREABLE(keys);
PUSH_INSN1(ret, location, duparray, keys);
- RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
+ RB_OBJ_WRITTEN(iseq, Qundef, keys);
}
PUSH_SEND(ret, location, rb_intern("deconstruct_keys"), INT2FIX(1));
@@ -2864,6 +3020,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
{
VALUE operand = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, symbol));
+ RB_OBJ_SET_SHAREABLE(operand);
PUSH_INSN1(ret, location, putobject, operand);
}
@@ -2889,7 +3046,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
value = ((const pm_implicit_node_t *) value)->value;
}
- CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, false, base_index + 1));
}
PUSH_SEQ(ret, match_values);
@@ -2917,7 +3074,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
case PM_ASSOC_SPLAT_NODE: {
const pm_assoc_splat_node_t *splat = (const pm_assoc_splat_node_t *) cast->rest;
PUSH_INSN(ret, location, dup);
- pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1);
+ pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, false, base_index + 1);
break;
}
default:
@@ -2962,8 +3119,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
LABEL *match_failed_label = NEW_LABEL(location.line);
PUSH_INSN(ret, location, dup);
- CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index + 1));
- CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, use_deconstructed_cache, base_index + 1));
+ CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, false, base_index));
PUSH_INSN(ret, location, putnil);
PUSH_LABEL(ret, match_failed_label);
@@ -2979,20 +3136,6 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node;
pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
- // 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(iseq, location.line, "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id));
- return COMPILE_NG;
- }
- }
-
PUSH_SETLOCAL(ret, location, index.index, index.level);
PUSH_INSNL(ret, location, jump, matched_label);
break;
@@ -3008,7 +3151,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// First, we're going to attempt to match against the left pattern. If
// that pattern matches, then we'll skip matching the right pattern.
PUSH_INSN(ret, location, dup);
- CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, true, use_deconstructed_cache, base_index + 1));
+ CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, use_deconstructed_cache, 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
@@ -3021,7 +3164,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// If we get here, then we didn't match on the left pattern. In this
// case we attempt to match against the right pattern.
PUSH_LABEL(ret, unmatched_left_label);
- CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, true, use_deconstructed_cache, base_index));
+ CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
break;
}
case PM_PARENTHESES_NODE:
@@ -3029,7 +3172,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// they do nothing since they can only wrap individual expressions and
// not groups. In this case we'll recurse back into this same function
// with the body of the parentheses.
- return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index);
+ return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index);
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:
@@ -3090,7 +3233,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// looks like: foo in ^@bar. To compile these, we compile the variable
// that they hold.
const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node;
- CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
+ CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, true, base_index));
break;
}
case PM_IF_NODE:
@@ -3124,7 +3267,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
statement = cast->statements->body.nodes[0];
}
- CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
+ CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index));
PM_COMPILE_NOT_POPPED(predicate);
if (in_single_pattern) {
@@ -3167,7 +3310,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
// 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)));
+ rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
@@ -3184,26 +3327,27 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
void
pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous)
{
- // This is very important, otherwise the scope node could be seen as having
- // certain flags set that _should not_ be set.
- memset(scope, 0, sizeof(pm_scope_node_t));
+ if (previous) {
+ // Copy inherited fields from the parent scope in one shot, then
+ // zero out the fields that are scope-specific.
+ *scope = *previous;
+ scope->locals = (pm_constant_id_list_t) { 0 };
+ scope->parameters = NULL;
+ scope->body = NULL;
+ scope->local_table_for_iseq_size = 0;
+ scope->index_lookup_table = (pm_index_lookup_table_t) PM_INDEX_LOOKUP_TABLE_INIT;
+ scope->pre_execution_anchor = NULL;
+ }
+ else {
+ memset(scope, 0, sizeof(pm_scope_node_t));
+ }
scope->base.type = PM_SCOPE_NODE;
scope->base.location.start = node->location.start;
- scope->base.location.end = node->location.end;
-
+ scope->base.location.length = node->location.length;
scope->previous = previous;
scope->ast_node = (pm_node_t *) node;
- if (previous) {
- scope->parser = previous->parser;
- scope->encoding = previous->encoding;
- scope->filepath_encoding = previous->filepath_encoding;
- scope->constants = previous->constants;
- scope->coverage_enabled = previous->coverage_enabled;
- scope->script_lines = previous->script_lines;
- }
-
switch (PM_NODE_TYPE(node)) {
case PM_BLOCK_NODE: {
const pm_block_node_t *cast = (const pm_block_node_t *) node;
@@ -3231,7 +3375,7 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
if (cast->statements != NULL) {
scope->base.location.start = cast->statements->base.location.start;
- scope->base.location.end = cast->statements->base.location.end;
+ scope->base.location.length = cast->statements->base.location.length;
}
break;
@@ -3251,13 +3395,6 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
scope->parameters = cast->parameters;
scope->body = cast->body;
scope->locals = cast->locals;
-
- if (cast->parameters != NULL) {
- scope->base.location.start = cast->parameters->location.start;
- }
- else {
- scope->base.location.start = cast->operator_loc.end;
- }
break;
}
case PM_MODULE_NODE: {
@@ -3307,8 +3444,8 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
void
pm_scope_node_destroy(pm_scope_node_t *scope_node)
{
- if (scope_node->index_lookup_table) {
- st_free_table(scope_node->index_lookup_table);
+ if (scope_node->index_lookup_table.owned) {
+ xfree(scope_node->index_lookup_table.values);
}
}
@@ -3377,7 +3514,7 @@ pm_iseq_builtin_function_name(const pm_scope_node_t *scope_node, const pm_node_t
// Compile Primitive.attr! :leaf, ...
static int
-pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_node_location_t *node_location)
+pm_compile_builtin_attr(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_node_location_t *node_location)
{
if (arguments == NULL) {
COMPILE_ERROR(iseq, node_location->line, "attr!: no argument");
@@ -3387,7 +3524,7 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, cons
const pm_node_t *argument;
PM_NODE_LIST_FOREACH(&arguments->arguments, index, argument) {
if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) {
- COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument)));
+ COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type(PM_NODE_TYPE(argument)));
return COMPILE_NG;
}
@@ -3407,6 +3544,9 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, cons
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
+ else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
+ ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
+ }
else {
COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %s", RSTRING_PTR(string));
return COMPILE_NG;
@@ -3431,7 +3571,7 @@ pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_n
const pm_node_t *argument = arguments->arguments.nodes[0];
if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) {
- COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument)));
+ COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type(PM_NODE_TYPE(argument)));
return COMPILE_NG;
}
@@ -3495,8 +3635,7 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope
pm_scope_node_t next_scope_node;
pm_scope_node_init(&def.base, &next_scope_node, scope_node);
- int error_state;
- ISEQ_BODY(iseq)->mandatory_only_iseq = pm_iseq_new_with_opt(
+ const rb_iseq_t *mandatory_only_iseq = pm_iseq_build(
&next_scope_node,
rb_iseq_base_label(iseq),
rb_iseq_path(iseq),
@@ -3505,14 +3644,9 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope
NULL,
0,
ISEQ_TYPE_METHOD,
- ISEQ_COMPILE_DATA(iseq)->option,
- &error_state
+ ISEQ_COMPILE_DATA(iseq)->option
);
-
- if (error_state) {
- RUBY_ASSERT(ISEQ_BODY(iseq)->mandatory_only_iseq == NULL);
- rb_jump_tag(error_state);
- }
+ RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
pm_scope_node_destroy(&next_scope_node);
return COMPILE_OK;
@@ -3617,9 +3751,10 @@ static void
pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, ID method_id, LABEL *start)
{
const pm_location_t *message_loc = &call_node->message_loc;
- if (message_loc->start == NULL) message_loc = &call_node->base.location;
+ if (message_loc->length == 0) message_loc = &call_node->base.location;
+
+ const pm_node_location_t location = PM_LOCATION_START_LOCATION(message_loc, call_node->base.node_id);
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, call_node->base.node_id);
LABEL *else_label = NEW_LABEL(location.line);
LABEL *end_label = NEW_LABEL(location.line);
LABEL *retry_end_l = NEW_LABEL(location.line);
@@ -3630,19 +3765,37 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
if (PM_BRANCH_COVERAGE_P(iseq)) {
- const uint8_t *cursors[3] = {
- call_node->closing_loc.end,
- call_node->arguments == NULL ? NULL : call_node->arguments->base.location.end,
- call_node->message_loc.end
- };
+ uint32_t end_cursor = 0;
+ bool end_found = false;
- const uint8_t *end_cursor = cursors[0];
- end_cursor = (end_cursor == NULL || cursors[1] == NULL) ? cursors[1] : (end_cursor > cursors[1] ? end_cursor : cursors[1]);
- end_cursor = (end_cursor == NULL || cursors[2] == NULL) ? cursors[2] : (end_cursor > cursors[2] ? end_cursor : cursors[2]);
- if (!end_cursor) end_cursor = call_node->closing_loc.end;
+ if (call_node->closing_loc.length > 0) {
+ uint32_t cursor = call_node->closing_loc.start + call_node->closing_loc.length;
+ end_cursor = cursor;
+ end_found = true;
+ }
- const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, call_node);
- const pm_line_column_t end_location = pm_newline_list_line_column(&scope_node->parser->newline_list, end_cursor, scope_node->parser->start_line);
+ if (call_node->arguments != NULL) {
+ uint32_t cursor = call_node->arguments->base.location.start + call_node->arguments->base.location.length;
+ if (!end_found || cursor > end_cursor) {
+ end_cursor = cursor;
+ end_found = true;
+ }
+ }
+
+ if (call_node->message_loc.length > 0) {
+ uint32_t cursor = call_node->message_loc.start + call_node->message_loc.length;
+ if (!end_found || cursor > end_cursor) {
+ end_cursor = cursor;
+ end_found = true;
+ }
+ }
+
+ if (!end_found) {
+ end_cursor = call_node->closing_loc.start + call_node->closing_loc.length;
+ }
+
+ const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(call_node);
+ const pm_line_column_t end_location = pm_line_offset_list_line_column_cached(scope_node->line_offsets, end_cursor, scope_node->start_line, &scope_node->last_line);
code_location = (rb_code_location_t) {
.beg_pos = { .lineno = start_location.line, .column = start_location.column },
@@ -3658,6 +3811,8 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
add_trace_branch_coverage(iseq, ret, &code_location, node_id, 0, "then", branches);
}
+ LINK_ELEMENT *opt_new_prelude = LAST_ELEMENT(ret);
+
int flags = 0;
struct rb_callinfo_kwarg *kw_arg = NULL;
@@ -3670,7 +3825,7 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
pm_scope_node_t next_scope_node;
pm_scope_node_init(call_node->block, &next_scope_node, scope_node);
- block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, pm_node_line_number(scope_node->parser, call_node->block));
+ block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, pm_node_line_number_cached(call_node->block, scope_node));
pm_scope_node_destroy(&next_scope_node);
ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
}
@@ -3714,7 +3869,50 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
PUSH_INSN(ret, location, splatkw);
}
- PUSH_SEND_R(ret, location, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
+ LABEL *not_basic_new = NEW_LABEL(location.line);
+ LABEL *not_basic_new_finish = NEW_LABEL(location.line);
+
+ bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
+ method_id == rb_intern("new") &&
+ call_node->block == NULL &&
+ (flags & VM_CALL_ARGS_BLOCKARG) == 0;
+
+ if (inline_new) {
+ if (LAST_ELEMENT(ret) == opt_new_prelude) {
+ PUSH_INSN(ret, location, putnil);
+ PUSH_INSN(ret, location, swap);
+ }
+ else {
+ ELEM_INSERT_NEXT(opt_new_prelude, &new_insn_body(iseq, location.line, location.node_id, BIN(swap), 0)->link);
+ ELEM_INSERT_NEXT(opt_new_prelude, &new_insn_body(iseq, location.line, location.node_id, BIN(putnil), 0)->link);
+ }
+
+ // Jump unless the receiver uses the "basic" implementation of "new"
+ VALUE ci;
+ if (flags & VM_CALL_FORWARDING) {
+ ci = (VALUE)new_callinfo(iseq, method_id, orig_argc + 1, flags, kw_arg, 0);
+ }
+ else {
+ ci = (VALUE)new_callinfo(iseq, method_id, orig_argc, flags, kw_arg, 0);
+ }
+
+ PUSH_INSN2(ret, location, opt_new, ci, not_basic_new);
+ LABEL_REF(not_basic_new);
+ // optimized path
+ PUSH_SEND_R(ret, location, rb_intern("initialize"), INT2FIX(orig_argc), block_iseq, INT2FIX(flags | VM_CALL_FCALL), kw_arg);
+ PUSH_INSNL(ret, location, jump, not_basic_new_finish);
+
+ PUSH_LABEL(ret, not_basic_new);
+ // Fall back to normal send
+ PUSH_SEND_R(ret, location, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
+ PUSH_INSN(ret, location, swap);
+
+ PUSH_LABEL(ret, not_basic_new_finish);
+ PUSH_INSN(ret, location, pop);
+ }
+ else {
+ PUSH_SEND_R(ret, location, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
+ }
if (block_iseq && ISEQ_BODY(block_iseq)->catch_table) {
pm_compile_retry_end_label(iseq, ret, retry_end_l);
@@ -3741,9 +3939,9 @@ pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *c
* node.
*/
static inline VALUE
-pm_compile_back_reference_ref(const pm_back_reference_read_node_t *node)
+pm_compile_back_reference_ref(const pm_scope_node_t *scope_node, const pm_back_reference_read_node_t *node)
{
- const char *type = (const char *) (node->base.location.start + 1);
+ const char *type = (const char *) (pm_parser_start(scope_node->parser) + node->base.location.start + 1);
// Since a back reference is `$<char>`, Ruby represents the ID as an
// rb_intern on the value after the `$`.
@@ -4134,7 +4332,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
// defined?($+)
// ^^
const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node;
- VALUE ref = pm_compile_back_reference_ref(cast);
+ VALUE ref = pm_compile_back_reference_ref(scope_node, cast);
PUSH_INSN(ret, location, putnil);
PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_REF), ref, PUSH_VAL(DEFINED_GVAR));
@@ -4422,6 +4620,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
case PM_PARAMETERS_NODE:
case PM_KEYWORD_REST_PARAMETER_NODE:
case PM_NO_KEYWORDS_PARAMETER_NODE:
+ case PM_NO_BLOCK_PARAMETER_NODE:
case PM_NUMBERED_PARAMETERS_NODE:
case PM_OPTIONAL_KEYWORD_PARAMETER_NODE:
case PM_OPTIONAL_PARAMETER_NODE:
@@ -4456,12 +4655,12 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
case PM_BLOCK_NODE:
case PM_EMBEDDED_STATEMENTS_NODE:
case PM_EMBEDDED_VARIABLE_NODE:
- case PM_MISSING_NODE:
+ case PM_ERROR_RECOVERY_NODE:
case PM_PRE_EXECUTION_NODE:
case PM_PROGRAM_NODE:
case PM_SCOPE_NODE:
case PM_STATEMENTS_NODE:
- rb_bug("Unreachable node in defined?: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unreachable node in defined?: %s", pm_node_type(PM_NODE_TYPE(node)));
}
RUBY_ASSERT(dtype != DEFINED_NOT_DEFINED);
@@ -4566,33 +4765,7 @@ pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, pm_sc
PUSH_SEQ(ret, ensure);
}
-struct pm_local_table_insert_ctx {
- pm_scope_node_t *scope_node;
- rb_ast_id_table_t *local_table_for_iseq;
- int local_index;
-};
-
-static int
-pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
-{
- if (!existing) {
- pm_constant_id_t constant_id = (pm_constant_id_t) *key;
- struct pm_local_table_insert_ctx * ctx = (struct pm_local_table_insert_ctx *) arg;
- pm_scope_node_t *scope_node = ctx->scope_node;
- rb_ast_id_table_t *local_table_for_iseq = ctx->local_table_for_iseq;
- int local_index = ctx->local_index;
-
- ID local = pm_constant_id_lookup(scope_node, constant_id);
- local_table_for_iseq->ids[local_index] = local;
-
- *value = (st_data_t)local_index;
-
- ctx->local_index++;
- }
-
- return ST_CONTINUE;
-}
/**
* Insert a local into the local table for the iseq. This is used to create the
@@ -4600,24 +4773,23 @@ pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int
* inserted are regular named locals, as opposed to special forwarding locals.
*/
static void
-pm_insert_local_index(pm_constant_id_t constant_id, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
+pm_insert_local_index(pm_constant_id_t constant_id, int local_index, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
{
RUBY_ASSERT((constant_id & PM_SPECIAL_CONSTANT_FLAG) == 0);
ID local = pm_constant_id_lookup(scope_node, constant_id);
local_table_for_iseq->ids[local_index] = local;
- st_insert(index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index);
+ pm_index_lookup_table_insert(index_lookup_table, constant_id, local_index);
}
/**
- * Insert a local into the local table for the iseq that is a special forwarding
- * local variable.
+ * Insert a special forwarding local (*, **, &, ...) into the local table.
*/
static void
-pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq)
+pm_insert_local_special(pm_constant_id_t special_id, ID local_name, int local_index, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq)
{
local_table_for_iseq->ids[local_index] = local_name;
- st_insert(index_lookup_table, (st_data_t) (local_name | PM_SPECIAL_CONSTANT_FLAG), (st_data_t) local_index);
+ pm_index_lookup_table_insert(index_lookup_table, special_id, local_index);
}
/**
@@ -4627,7 +4799,7 @@ pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_t
* local and index lookup tables and increments the local index as necessary.
*/
static int
-pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
+pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
{
for (size_t index = 0; index < node->lefts.size; index++) {
const pm_node_t *left = node->lefts.nodes[index];
@@ -4680,9 +4852,9 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl
* as a positional parameter in a method, block, or lambda definition.
*/
static inline void
-pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter_node_t *node, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
+pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, node->name, 0);
PUSH_SETLOCAL(ret, location, index.index, index.level);
}
@@ -4696,9 +4868,9 @@ pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter
* for this simplified case.
*/
static void
-pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node_t *node, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
+pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
bool has_rest = (node->rest && PM_NODE_TYPE_P(node->rest, PM_SPLAT_NODE) && (((const pm_splat_node_t *) node->rest)->expression) != NULL);
bool has_rights = node->rights.size > 0;
@@ -4857,7 +5029,7 @@ pm_multi_target_state_update(pm_multi_target_state_t *state)
previous = current;
current = current->next;
- xfree(previous);
+ SIZED_FREE(previous);
}
}
@@ -4895,7 +5067,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR
static void
pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_LOCAL_VARIABLE_TARGET_NODE: {
@@ -5117,8 +5289,22 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
break;
}
+ case PM_SPLAT_NODE: {
+ // Splat nodes capture all values into an array. They can be used
+ // as targets in assignments or for loops.
+ //
+ // for *x in []; end
+ //
+ const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
+
+ if (cast->expression != NULL) {
+ pm_compile_target_node(iseq, cast->expression, parents, writes, cleanup, scope_node, state);
+ }
+
+ break;
+ }
default:
- rb_bug("Unexpected node type: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unexpected node type: %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
}
@@ -5131,7 +5317,7 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
static void
pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
const pm_node_list_t *lefts;
const pm_node_t *rest;
const pm_node_list_t *rights;
@@ -5152,7 +5338,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR
break;
}
default:
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unsupported node %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
@@ -5214,7 +5400,7 @@ pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR
static void
pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_LOCAL_VARIABLE_TARGET_NODE: {
@@ -5250,6 +5436,7 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
pm_multi_target_state_update(&state);
break;
}
+ case PM_SPLAT_NODE:
case PM_MULTI_TARGET_NODE: {
DECL_ANCHOR(writes);
DECL_ANCHOR(cleanup);
@@ -5285,12 +5472,18 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
PUSH_INSN(ret, location, pop);
PUSH_LABEL(ret, not_single);
+
+ if (PM_NODE_TYPE_P(node, PM_SPLAT_NODE)) {
+ const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
+ PUSH_INSN2(ret, location, expandarray, INT2FIX(0), INT2FIX(cast->expression == NULL ? 0 : 1));
+ }
+
PUSH_SEQ(ret, writes);
PUSH_SEQ(ret, cleanup);
break;
}
default:
- rb_bug("Unexpected node type for index in for node: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_bug("Unexpected node type for index in for node: %s", pm_node_type(PM_NODE_TYPE(node)));
break;
}
}
@@ -5298,8 +5491,6 @@ pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *c
static void
pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
- const pm_parser_t *parser = scope_node->parser;
-
LABEL *lstart = NEW_LABEL(node_location->line);
LABEL *lend = NEW_LABEL(node_location->line);
LABEL *lcont = NEW_LABEL(node_location->line);
@@ -5311,7 +5502,7 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo
&rescue_scope_node,
rb_str_concat(rb_str_new2("rescue in "), ISEQ_BODY(iseq)->location.label),
ISEQ_TYPE_RESCUE,
- pm_node_line_number(parser, (const pm_node_t *) cast->rescue_clause)
+ pm_node_line_number_cached((const pm_node_t *) cast->rescue_clause, scope_node)
);
pm_scope_node_destroy(&rescue_scope_node);
@@ -5327,7 +5518,7 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo
PM_COMPILE_NOT_POPPED((const pm_node_t *) cast->statements);
}
else {
- const pm_node_location_t location = PM_NODE_START_LOCATION(parser, cast->rescue_clause);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(cast->rescue_clause);
PUSH_INSN(ret, location, putnil);
}
@@ -5350,12 +5541,11 @@ pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_lo
static void
pm_compile_ensure(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
- const pm_parser_t *parser = scope_node->parser;
const pm_statements_node_t *statements = cast->ensure_clause->statements;
pm_node_location_t location;
if (statements != NULL) {
- location = PM_NODE_START_LOCATION(parser, statements);
+ location = PM_NODE_START_LOCATION(statements);
}
else {
location = *node_location;
@@ -5439,55 +5629,18 @@ pm_opt_str_freeze_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
}
/**
- * Returns true if the given call node can use the opt_aref_with optimization
- * with the current iseq options.
- */
-static inline bool
-pm_opt_aref_with_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
-{
- return (
- !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) &&
- node->arguments != NULL &&
- PM_NODE_TYPE_P((const pm_node_t *) node->arguments, PM_ARGUMENTS_NODE) &&
- ((const pm_arguments_node_t *) node->arguments)->arguments.size == 1 &&
- PM_NODE_TYPE_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_NODE) &&
- node->block == NULL &&
- !PM_NODE_FLAG_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_FLAGS_FROZEN) &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction
- );
-}
-
-/**
- * Returns true if the given call node can use the opt_aset_with optimization
- * with the current iseq options.
- */
-static inline bool
-pm_opt_aset_with_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
-{
- return (
- !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) &&
- node->arguments != NULL &&
- PM_NODE_TYPE_P((const pm_node_t *) node->arguments, PM_ARGUMENTS_NODE) &&
- ((const pm_arguments_node_t *) node->arguments)->arguments.size == 2 &&
- PM_NODE_TYPE_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_NODE) &&
- node->block == NULL &&
- !PM_NODE_FLAG_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_FLAGS_FROZEN) &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction
- );
-}
-
-/**
* Compile the instructions necessary to read a constant, based on the options
* of the current iseq.
*/
static void
-pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, uint32_t node_id, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
+pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, uint32_t node_id, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, name_loc, node_id);
+ const pm_node_location_t location = PM_LOCATION_START_LOCATION(name_loc, node_id);
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
ISEQ_BODY(iseq)->ic_size++;
VALUE segments = rb_ary_new_from_args(1, name);
+ RB_OBJ_SET_SHAREABLE(segments);
PUSH_INSN1(ret, location, opt_getconstant_path, segments);
}
else {
@@ -5542,7 +5695,7 @@ pm_constant_path_parts(const pm_node_t *node, const pm_scope_node_t *scope_node)
static void
pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const prefix, LINK_ANCHOR *const body, bool popped, pm_scope_node_t *scope_node)
{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_CONSTANT_READ_NODE: {
@@ -5580,7 +5733,7 @@ pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *co
* Return the object that will be pushed onto the stack for the given node.
*/
static VALUE
-pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_node_t *scope_node)
+pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, pm_scope_node_t *scope_node)
{
switch (PM_NODE_TYPE(node)) {
case PM_TRUE_NODE:
@@ -5614,7 +5767,7 @@ pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, co
}
case PM_HASH_NODE: {
const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
- VALUE result = rb_hash_new_capa(cast->elements.size);
+ VALUE result = rb_hash_alloc_fixed_size(rb_cHash, cast->elements.size);
for (size_t index = 0; index < cast->elements.size; index++) {
const pm_node_t *element = cast->elements.nodes[index];
@@ -5647,12 +5800,12 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons
{
VALUE literal = pm_compile_shareable_constant_literal(iseq, node, scope_node);
if (literal != Qundef) {
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
PUSH_INSN1(ret, location, putobject, literal);
return;
}
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
switch (PM_NODE_TYPE(node)) {
case PM_ARRAY_NODE: {
const pm_array_node_t *cast = (const pm_array_node_t *) node;
@@ -5701,6 +5854,9 @@ pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, cons
if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL) {
PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
PUSH_SEQ(ret, value_seq);
+ if (!RB_OBJ_SHAREABLE_P(path)) {
+ RB_OBJ_SET_SHAREABLE(path);
+ }
PUSH_INSN1(ret, location, putobject, path);
PUSH_SEND_WITH_FLAG(ret, location, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
}
@@ -6114,7 +6270,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
body->param.flags.ambiguous_param0 = true;
break;
default:
- rb_bug("Unexpected node type for parameters: %s", pm_node_type_to_str(PM_NODE_TYPE(scope_node->parameters)));
+ rb_bug("Unexpected node type for parameters: %s", pm_node_type(PM_NODE_TYPE(scope_node->parameters)));
}
}
@@ -6139,8 +6295,9 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// hidden variables and multi target nodes
size_t locals_size = locals->size;
- // Index lookup table buffer size is only the number of the locals
- st_table *index_lookup_table = st_init_numtable();
+ // Index lookup table buffer size is only the number of the locals.
+ // We'll initialize it after computing table_size below.
+ pm_index_lookup_table_t index_lookup_table = PM_INDEX_LOOKUP_TABLE_INIT;
int table_size = (int) locals_size;
@@ -6251,7 +6408,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
}
- if (parameters_node && parameters_node->block) {
+ if (parameters_node && parameters_node->block && PM_NODE_TYPE_P(parameters_node->block, PM_BLOCK_PARAMETER_NODE)) {
const pm_block_parameter_node_t *block_node = (const pm_block_parameter_node_t *) parameters_node->block;
if (PM_NODE_FLAG_P(block_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER) || !block_node->name) {
@@ -6264,6 +6421,10 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
rb_ast_id_table_t *local_table_for_iseq = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
local_table_for_iseq->size = table_size;
+ // Init the direct-indexed lookup table. The capacity is based on the
+ // parser's constant pool size (for regular locals) plus special slots.
+ pm_index_lookup_table_init(&index_lookup_table, (int) pm_parser_constants_size(scope_node->parser), iseq);
+
//********END OF STEP 1**********
//********STEP 2**********
@@ -6316,13 +6477,13 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(param->name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
break;
}
default:
- rb_bug("Unsupported node in requireds in parameters %s", pm_node_type_to_str(PM_NODE_TYPE(required)));
+ rb_bug("Unsupported node in requireds in parameters %s", pm_node_type(PM_NODE_TYPE(required)));
}
}
@@ -6331,8 +6492,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
if (scope_node->parameters != NULL && PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
- ID local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index++] = local;
+ local_table_for_iseq->ids[local_index++] = idItImplicit;
}
// def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
@@ -6350,7 +6510,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
}
@@ -6376,14 +6536,14 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
else {
// def foo(a, (b, *c, d), e = 1, *, g, (h, *i, j), k:, l: 1, **m, &n)
// ^
body->param.flags.anon_rest = true;
- pm_insert_local_special(idMULT, local_index, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6423,12 +6583,12 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(param->name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
break;
}
default:
- rb_bug("Unsupported node in posts in parameters %s", pm_node_type_to_str(PM_NODE_TYPE(post_node)));
+ rb_bug("Unsupported node in posts in parameters %s", pm_node_type(PM_NODE_TYPE(post_node)));
}
}
}
@@ -6458,7 +6618,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
local_index++;
}
@@ -6488,7 +6648,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
local_index++;
}
@@ -6550,12 +6710,12 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
else {
body->param.flags.anon_kwrest = true;
- pm_insert_local_special(idPow, local_index, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6569,7 +6729,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
body->param.rest_start = local_index;
body->param.flags.has_rest = true;
body->param.flags.anon_rest = true;
- pm_insert_local_special(idMULT, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index++, &index_lookup_table, local_table_for_iseq);
// Add the anonymous **
RUBY_ASSERT(!body->param.flags.has_kw);
@@ -6578,46 +6738,58 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
body->param.flags.anon_kwrest = true;
body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
keyword->rest_start = local_index;
- pm_insert_local_special(idPow, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index++, &index_lookup_table, local_table_for_iseq);
// Add the anonymous &
body->param.block_start = local_index;
body->param.flags.has_block = true;
- pm_insert_local_special(idAnd, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index++, &index_lookup_table, local_table_for_iseq);
}
// Add the ...
- pm_insert_local_special(idDot3, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_DOT3, idDot3, local_index++, &index_lookup_table, local_table_for_iseq);
break;
}
default:
- rb_bug("node type %s not expected as keyword_rest", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->keyword_rest)));
+ rb_bug("node type %s not expected as keyword_rest", pm_node_type(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;
- iseq_set_use_block(iseq);
+ switch (PM_NODE_TYPE(parameters_node->block)) {
+ case PM_BLOCK_PARAMETER_NODE: {
+ body->param.block_start = local_index;
+ body->param.flags.has_block = true;
- pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
+ iseq_set_use_block(iseq);
- if (name) {
- if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, name);
- local_table_for_iseq->ids[local_index] = local;
+ pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
+
+ if (name) {
+ if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
+ ID local = pm_constant_id_lookup(scope_node, name);
+ local_table_for_iseq->ids[local_index] = local;
+ }
+ else {
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
+ }
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index, &index_lookup_table, local_table_for_iseq);
}
- }
- else {
- pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
- }
- local_index++;
+ local_index++;
+ break;
+ }
+ case PM_NO_BLOCK_PARAMETER_NODE: {
+ body->param.flags.accepts_no_block = true;
+ break;
+ }
+ default:
+ rb_bug("node type %s not expected as block parameter", pm_node_type(PM_NODE_TYPE(parameters_node->block)));
+ }
}
}
@@ -6641,7 +6813,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
const pm_node_t *required = requireds_list->nodes[i];
if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, index_lookup_table, local_table_for_iseq, scope_node, local_index);
+ local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, &index_lookup_table, local_table_for_iseq, scope_node, local_index);
}
}
}
@@ -6655,7 +6827,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
const pm_node_t *post = posts_list->nodes[i];
if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, index_lookup_table, local_table_for_iseq, scope_node, local_index);
+ local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, &index_lookup_table, local_table_for_iseq, scope_node, local_index);
}
}
}
@@ -6681,14 +6853,20 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
RUBY_ASSERT(0 < maximum && maximum <= 9);
for (int i = 0; i < maximum; i++, local_index++) {
const uint8_t param_name[] = { '_', '1' + i };
- pm_constant_id_t constant_id = pm_constant_pool_find(&scope_node->parser->constant_pool, param_name, 2);
+ pm_constant_id_t constant_id = pm_parser_constant_find(scope_node->parser, param_name, 2);
RUBY_ASSERT(constant_id && "parser should fill in any gaps in numbered parameters");
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
body->param.lead_num = maximum;
body->param.flags.has_lead = true;
}
+ // Fill in the anonymous `it` parameter, if it exists
+ if (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
+ body->param.lead_num = 1;
+ body->param.flags.has_lead = true;
+ }
+
//********END OF STEP 3**********
//********STEP 4**********
@@ -6700,7 +6878,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
if (block_locals && block_locals->size) {
for (size_t i = 0; i < block_locals->size; i++, local_index++) {
pm_constant_id_t constant_id = ((const pm_block_local_variable_node_t *) block_locals->nodes[i])->name;
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
@@ -6709,14 +6887,13 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
for (size_t i = 0; i < scope_node->locals.size; i++) {
pm_constant_id_t constant_id = locals->ids[i];
if (constant_id) {
- struct pm_local_table_insert_ctx ctx;
- ctx.scope_node = scope_node;
- ctx.local_table_for_iseq = local_table_for_iseq;
- ctx.local_index = local_index;
-
- st_update(index_lookup_table, (st_data_t)constant_id, pm_local_table_insert_func, (st_data_t)&ctx);
-
- local_index = ctx.local_index;
+ int existing;
+ if (!pm_index_lookup_table_lookup(&index_lookup_table, constant_id, &existing)) {
+ ID local = pm_constant_id_lookup(scope_node, constant_id);
+ local_table_for_iseq->ids[local_index] = local;
+ pm_index_lookup_table_insert(&index_lookup_table, constant_id, local_index);
+ local_index++;
+ }
}
}
}
@@ -6724,10 +6901,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
//********END OF STEP 4**********
// We set the index_lookup_table on the scope node so we can
- // refer to the parameters correctly
- if (scope_node->index_lookup_table) {
- st_free_table(scope_node->index_lookup_table);
- }
+ // refer to the parameters correctly.
scope_node->index_lookup_table = index_lookup_table;
iseq_calc_param_size(iseq);
@@ -6739,6 +6913,8 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// FIXME: args?
iseq_set_local_table(iseq, local_table_for_iseq, 0);
+ iseq_set_parameters_lvar_state(iseq);
+
scope_node->local_table_for_iseq_size = local_table_for_iseq->size;
if (keyword != NULL) {
@@ -6806,7 +6982,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// ^^
break;
default:
- rb_bug("Unexpected keyword parameter node type %s", pm_node_type_to_str(PM_NODE_TYPE(keyword_parameter_node)));
+ rb_bug("Unexpected keyword parameter node type %s", pm_node_type(PM_NODE_TYPE(keyword_parameter_node)));
}
}
}
@@ -6908,7 +7084,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
break;
}
case ISEQ_TYPE_ENSURE: {
- const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->parser, scope_node->body) : location);
+ const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->body) : location);
iseq_set_exception_local_table(iseq);
if (scope_node->body != NULL) {
@@ -6971,7 +7147,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
if (PM_NODE_TYPE_P(scope_node->ast_node, PM_CLASS_NODE) || PM_NODE_TYPE_P(scope_node->ast_node, PM_MODULE_NODE)) {
- const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->parser, scope_node->ast_node);
+ const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->ast_node);
PUSH_TRACE(ret, RUBY_EVENT_END);
ISEQ_COMPILE_DATA(iseq)->last_line = end_location.line;
}
@@ -6991,13 +7167,13 @@ pm_compile_alias_global_variable_node(rb_iseq_t *iseq, const pm_alias_global_var
{
const pm_location_t *name_loc = &node->new_name->location;
- VALUE operand = ID2SYM(rb_intern3((const char *) name_loc->start, name_loc->end - name_loc->start, scope_node->encoding));
+ VALUE operand = ID2SYM(rb_intern3((const char *) (pm_parser_start(scope_node->parser) + name_loc->start), name_loc->length, scope_node->encoding));
PUSH_INSN1(ret, *location, putobject, operand);
}
{
const pm_location_t *name_loc = &node->old_name->location;
- VALUE operand = ID2SYM(rb_intern3((const char *) name_loc->start, name_loc->end - name_loc->start, scope_node->encoding));
+ VALUE operand = ID2SYM(rb_intern3((const char *) (pm_parser_start(scope_node->parser) + name_loc->start), name_loc->length, scope_node->encoding));
PUSH_INSN1(ret, *location, putobject, operand);
}
@@ -7043,6 +7219,7 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list
if (!popped) {
if (elements->size) {
VALUE value = pm_static_literal_value(iseq, node, scope_node);
+ RB_OBJ_SET_FROZEN_SHAREABLE(value);
PUSH_INSN1(ret, *location, duparray, value);
}
else {
@@ -7173,7 +7350,7 @@ pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list
rb_ary_push(tmp_array, pm_static_literal_value(iseq, elements->nodes[index++], scope_node));
index--; // about to be incremented by for loop
- OBJ_FREEZE(tmp_array);
+ RB_OBJ_SET_FROZEN_SHAREABLE(tmp_array);
// Emit the optimized code.
FLUSH_CHUNK;
@@ -7275,9 +7452,9 @@ pm_compile_call_node(rb_iseq_t *iseq, const pm_call_node_t *node, LINK_ANCHOR *c
ID method_id = pm_constant_id_lookup(scope_node, node->name);
const pm_location_t *message_loc = &node->message_loc;
- if (message_loc->start == NULL) message_loc = &node->base.location;
+ if (message_loc->length == 0) message_loc = &node->base.location;
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, node->base.node_id);
+ const pm_node_location_t location = PM_LOCATION_START_LOCATION(message_loc, node->base.node_id);
const char *builtin_func;
if (UNLIKELY(iseq_has_builtin_function_table(iseq)) && (builtin_func = pm_iseq_builtin_function_name(scope_node, node->receiver, method_id)) != NULL) {
@@ -7309,44 +7486,6 @@ pm_compile_call_node(rb_iseq_t *iseq, const pm_call_node_t *node, LINK_ANCHOR *c
}
break;
}
- case idAREF: {
- if (pm_opt_aref_with_p(iseq, node)) {
- const pm_string_node_t *string = (const pm_string_node_t *) ((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0];
- VALUE value = parse_static_literal_string(iseq, scope_node, (const pm_node_t *) string, &string->unescaped);
-
- PM_COMPILE_NOT_POPPED(node->receiver);
-
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE);
- PUSH_INSN2(ret, location, opt_aref_with, value, callinfo);
-
- if (popped) {
- PUSH_INSN(ret, location, pop);
- }
-
- return;
- }
- break;
- }
- case idASET: {
- if (pm_opt_aset_with_p(iseq, node)) {
- const pm_string_node_t *string = (const pm_string_node_t *) ((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0];
- VALUE value = parse_static_literal_string(iseq, scope_node, (const pm_node_t *) string, &string->unescaped);
-
- PM_COMPILE_NOT_POPPED(node->receiver);
- PM_COMPILE_NOT_POPPED(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[1]);
-
- if (!popped) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
-
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idASET, 2, 0, NULL, FALSE);
- PUSH_INSN2(ret, location, opt_aset_with, value, callinfo);
- PUSH_INSN(ret, location, pop);
- return;
- }
- break;
- }
}
if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && !popped) {
@@ -7435,10 +7574,9 @@ pm_compile_call_operator_write_node(rb_iseq_t *iseq, const pm_call_operator_writ
* optimization entirely.
*/
static VALUE
-pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *node, LABEL *label, const pm_scope_node_t *scope_node)
+pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *node, LABEL *label, pm_scope_node_t *scope_node)
{
VALUE key = Qundef;
-
switch (PM_NODE_TYPE(node)) {
case PM_FLOAT_NODE: {
key = pm_static_literal_value(iseq, node, scope_node);
@@ -7468,10 +7606,7 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *
return Qundef;
}
- if (NIL_P(rb_hash_lookup(dispatch, key))) {
- rb_hash_aset(dispatch, key, ((VALUE) label) | 1);
- }
-
+ cdhash_aset_if_missing(dispatch, key, (VALUE)label);
return dispatch;
}
@@ -7481,7 +7616,6 @@ pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *
static inline void
pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
- const pm_parser_t *parser = scope_node->parser;
const pm_node_location_t location = *node_location;
const pm_node_list_t *conditions = &cast->conditions;
@@ -7520,7 +7654,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index];
const pm_node_list_t *conditions = &clause->conditions;
- int clause_lineno = pm_node_line_number(parser, (const pm_node_t *) clause);
+ int clause_lineno = pm_node_line_number_cached((const pm_node_t *) clause, scope_node);
LABEL *label = NEW_LABEL(clause_lineno);
PUSH_LABEL(body_seq, label);
@@ -7546,15 +7680,15 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
const pm_node_t *condition = conditions->nodes[condition_index];
if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) {
- pm_node_location_t cond_location = PM_NODE_START_LOCATION(parser, condition);
+ pm_node_location_t cond_location = PM_NODE_START_LOCATION(condition);
PUSH_INSN(cond_seq, cond_location, putnil);
pm_compile_node(iseq, condition, cond_seq, false, scope_node);
PUSH_INSN1(cond_seq, cond_location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
PUSH_INSNL(cond_seq, cond_location, branchif, label);
}
else {
- LABEL *next_label = NEW_LABEL(pm_node_line_number(parser, condition));
- pm_compile_branch_condition(iseq, cond_seq, condition, label, next_label, false, scope_node);
+ LABEL *next_label = NEW_LABEL(pm_node_line_number_cached(condition, scope_node));
+ pm_compile_branch_condition(iseq, cond_seq, condition, label, next_label, scope_node);
PUSH_LABEL(cond_seq, next_label);
}
}
@@ -7611,8 +7745,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// lookup to jump directly to the correct when clause body.
VALUE dispatch = Qundef;
if (ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- dispatch = rb_hash_new();
- RHASH_TBL_RAW(dispatch)->type = &cdhash_type;
+ dispatch = cdhash_new(0);
}
// We're going to loop through each of the conditions in the case
@@ -7625,7 +7758,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// node instructions later.
for (size_t clause_index = 0; clause_index < conditions->size; clause_index++) {
const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index];
- pm_node_location_t clause_location = PM_NODE_START_LOCATION(parser, (const pm_node_t *) clause);
+ pm_node_location_t clause_location = PM_NODE_START_LOCATION((const pm_node_t *) clause);
const pm_node_list_t *conditions = &clause->conditions;
LABEL *label = NEW_LABEL(clause_location.line);
@@ -7635,7 +7768,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// jumps into the body if it matches.
for (size_t condition_index = 0; condition_index < conditions->size; condition_index++) {
const pm_node_t *condition = conditions->nodes[condition_index];
- const pm_node_location_t condition_location = PM_NODE_START_LOCATION(parser, condition);
+ const pm_node_location_t condition_location = PM_NODE_START_LOCATION(condition);
// If we haven't already abandoned the optimization, then
// we're going to try to compile the condition into the
@@ -7699,6 +7832,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
// optimization.
if (dispatch != Qundef) {
PUSH_INSN(ret, location, dup);
+ RB_OBJ_SET_SHAREABLE(dispatch); // it is special that the hash is shareable but not frozen, because compile.c modify them. This Hahs instance is not accessible so it is safe to leave it.
PUSH_INSN2(ret, location, opt_case_dispatch, dispatch, else_label);
LABEL_REF(else_label);
}
@@ -7710,7 +7844,7 @@ pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_
PUSH_LABEL(ret, else_label);
if (cast->else_clause != NULL) {
- pm_node_location_t else_location = PM_NODE_START_LOCATION(parser, cast->else_clause->statements != NULL ? ((const pm_node_t *) cast->else_clause->statements) : ((const pm_node_t *) cast->else_clause));
+ pm_node_location_t else_location = PM_NODE_START_LOCATION(cast->else_clause->statements != NULL ? ((const pm_node_t *) cast->else_clause->statements) : ((const pm_node_t *) cast->else_clause));
PUSH_INSN(ret, else_location, pop);
// Establish branch coverage for the else clause.
@@ -7799,8 +7933,8 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co
RUBY_ASSERT(PM_NODE_TYPE_P(condition, PM_IN_NODE));
const pm_in_node_t *in_node = (const pm_in_node_t *) condition;
- const pm_node_location_t in_location = PM_NODE_START_LOCATION(scope_node->parser, in_node);
- const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(scope_node->parser, in_node->pattern);
+ const pm_node_location_t in_location = PM_NODE_START_LOCATION(in_node);
+ const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(in_node->pattern);
if (branch_id) {
PUSH_INSN(body_seq, in_location, putnil);
@@ -7827,7 +7961,7 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co
LABEL *next_pattern_label = NEW_LABEL(pattern_location.line);
PUSH_INSN(cond_seq, pattern_location, dup);
- pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, false, true, 2);
+ pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, true, 2);
PUSH_LABEL(cond_seq, next_pattern_label);
LABEL_UNREMOVABLE(next_pattern_label);
}
@@ -8075,7 +8209,7 @@ pm_compile_match_required_node(rb_iseq_t *iseq, const pm_match_required_node_t *
// 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, node->pattern, ret, matched_label, unmatched_label, true, false, true, 2);
+ pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, 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
@@ -8578,8 +8712,7 @@ pm_compile_yield_node(rb_iseq_t *iseq, const pm_yield_node_t *node, const pm_nod
static void
pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{
- const pm_parser_t *parser = scope_node->parser;
- const pm_node_location_t location = PM_NODE_START_LOCATION(parser, node);
+ const pm_node_location_t location = PM_NODE_START_LOCATION(node);
int lineno = (int) location.line;
if (PM_NODE_TYPE_P(node, PM_BEGIN_NODE) && (((const pm_begin_node_t *) node)->statements == NULL) && (((const pm_begin_node_t *) node)->rescue_clause != NULL)) {
@@ -8587,7 +8720,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// has a rescue clause, then the other parser considers it as
// starting on the same line as the rescue, as opposed to the
// location of the begin keyword. We replicate that behavior here.
- lineno = (int) PM_NODE_START_LINE_COLUMN(parser, ((const pm_begin_node_t *) node)->rescue_clause).line;
+ lineno = (int) PM_NODE_START_LINE_COLUMN(((const pm_begin_node_t *) node)->rescue_clause).line;
}
if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_NEWLINE) && ISEQ_COMPILE_DATA(iseq)->last_line != lineno) {
@@ -8597,7 +8730,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
int event = RUBY_EVENT_LINE;
ISEQ_COMPILE_DATA(iseq)->last_line = lineno;
- if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
+ if (lineno > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
event |= RUBY_EVENT_COVERAGE_LINE;
}
PUSH_TRACE(ret, event);
@@ -8682,7 +8815,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// ^^
if (!popped) {
const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node;
- VALUE backref = pm_compile_back_reference_ref(cast);
+ VALUE backref = pm_compile_back_reference_ref(scope_node, cast);
PUSH_INSN2(ret, location, getspecial, INT2FIX(1), backref);
}
@@ -8926,6 +9059,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache && ((parts = pm_constant_path_parts(node, scope_node)) != Qnil)) {
ISEQ_BODY(iseq)->ic_size++;
+ RB_OBJ_SET_SHAREABLE(parts);
PUSH_INSN1(ret, location, opt_getconstant_path, parts);
}
else {
@@ -9540,16 +9674,16 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, string);
}
else if (PM_NODE_FLAG_P(node, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, string);
+ PUSH_INSN1(ret, location, dupstring, string);
}
else {
- PUSH_INSN1(ret, location, putchilledstring, string);
+ PUSH_INSN1(ret, location, dupchilledstring, string);
}
}
}
else {
const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node;
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE), PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN));
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
if (popped) PUSH_INSN(ret, location, pop);
}
@@ -9560,7 +9694,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// :"foo #{bar}"
// ^^^^^^^^^^^^^
const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL, false, false);
if (length > 1) {
PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
@@ -9582,7 +9716,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN(ret, location, putself);
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL);
+ int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL, false, false);
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
PUSH_SEND_WITH_FLAG(ret, location, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
@@ -9594,7 +9728,19 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// -> { it }
// ^^
if (!popped) {
- PUSH_GETLOCAL(ret, location, scope_node->local_table_for_iseq_size, 0);
+ pm_scope_node_t *current_scope_node = scope_node;
+ int level = 0;
+
+ while (current_scope_node) {
+ if (current_scope_node->parameters && PM_NODE_TYPE_P(current_scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
+ PUSH_GETLOCAL(ret, location, current_scope_node->local_table_for_iseq_size, level);
+ return;
+ }
+
+ current_scope_node = current_scope_node->previous;
+ level++;
+ }
+ rb_bug("Local `it` does not exist");
}
return;
@@ -9621,7 +9767,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
pm_scope_node_t next_scope_node;
pm_scope_node_init(node, &next_scope_node, scope_node);
- int opening_lineno = pm_location_line_number(parser, &cast->opening_loc);
+ int opening_lineno = pm_location_line_number_cached(&cast->opening_loc, scope_node);
const rb_iseq_t *block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, opening_lineno);
pm_scope_node_destroy(&next_scope_node);
@@ -9751,7 +9897,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
LABEL *matched_label = NEW_LABEL(location.line);
LABEL *unmatched_label = NEW_LABEL(location.line);
LABEL *done_label = NEW_LABEL(location.line);
- pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, false, false, true, 2);
+ pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, 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.
@@ -9798,8 +9944,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// when the call is executed.
pm_compile_match_write_node(iseq, (const pm_match_write_node_t *) node, &location, ret, popped, scope_node);
return;
- case PM_MISSING_NODE:
- rb_bug("A pm_missing_node_t should not exist in prism's AST.");
+ case PM_ERROR_RECOVERY_NODE:
+ rb_bug("A pm_error_recovery_node_t should not exist in prism's AST.");
return;
case PM_MODULE_NODE: {
// module Foo; end
@@ -9884,6 +10030,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
return;
}
+ case PM_NO_BLOCK_PARAMETER_NODE: {
+ // def foo(&nil); end
+ // ^^^^
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block = TRUE;
+ return;
+ }
case PM_NO_KEYWORDS_PARAMETER_NODE: {
// def foo(**nil); end
// ^^^^^
@@ -10029,6 +10181,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
exclude_end
);
+ RB_OBJ_SET_SHAREABLE(val);
PUSH_INSN1(ret, location, putobject, val);
}
}
@@ -10092,7 +10245,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
&rescue_scope_node,
rb_str_concat(rb_str_new2("rescue in "), ISEQ_BODY(iseq)->location.label),
ISEQ_TYPE_RESCUE,
- pm_node_line_number(parser, cast->rescue_expression)
+ pm_node_line_number_cached(cast->rescue_expression, scope_node)
);
pm_scope_node_destroy(&rescue_scope_node);
@@ -10181,7 +10334,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
pm_compile_constant_path_operator_write_node(iseq, (const pm_constant_path_operator_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
break;
default:
- rb_bug("Unexpected node type for shareable constant write: %s", pm_node_type_to_str(PM_NODE_TYPE(cast->write)));
+ rb_bug("Unexpected node type for shareable constant write: %s", pm_node_type(PM_NODE_TYPE(cast->write)));
break;
}
@@ -10202,7 +10355,17 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ID singletonclass;
CONST_ID(singletonclass, "singletonclass");
- PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
+
+ /* `class << self` in a class body and `class << Foo` (constant
+ receiver) are stable. All other forms are potentially dynamic. */
+ int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
+ if (!(PM_NODE_TYPE_P(cast->expression, PM_SELF_NODE) &&
+ ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
+ !pm_cpath_const_p(cast->expression)) {
+ sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
+ }
+
+ PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(sclass_flags));
if (popped) PUSH_INSN(ret, location, pop);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) child_iseq);
@@ -10229,10 +10392,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, string);
}
else if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, string);
+ PUSH_INSN1(ret, location, dupstring, string);
}
else {
- PUSH_INSN1(ret, location, putchilledstring, string);
+ PUSH_INSN1(ret, location, dupchilledstring, string);
}
}
return;
@@ -10286,10 +10449,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, value);
}
else if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, value);
+ PUSH_INSN1(ret, location, dupstring, value);
}
else {
- PUSH_INSN1(ret, location, putchilledstring, value);
+ PUSH_INSN1(ret, location, dupchilledstring, value);
}
}
return;
@@ -10395,7 +10558,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
pm_compile_yield_node(iseq, (const pm_yield_node_t *) node, &location, ret, popped, scope_node);
return;
default:
- rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type_to_str(PM_NODE_TYPE(node)));
+ rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type(PM_NODE_TYPE(node)));
return;
}
}
@@ -10457,6 +10620,15 @@ pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node)
return iseq_setup(iseq, ret);
}
+void
+pm_parse_result_init(pm_parse_result_t *result)
+{
+ memset(result, 0, sizeof(pm_parse_result_t));
+ result->arena = pm_arena_new();
+ result->options = pm_options_new();
+ pm_options_line_set(result->options, 1);
+}
+
/**
* Free the internal memory associated with a pm_parse_result_t struct.
* Importantly this does not free the struct itself.
@@ -10464,24 +10636,21 @@ pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node)
void
pm_parse_result_free(pm_parse_result_t *result)
{
- if (result->node.ast_node != NULL) {
- pm_node_destroy(&result->parser, result->node.ast_node);
- }
-
if (result->parsed) {
- xfree(result->node.constants);
+ SIZED_FREE_N(result->node.constants, pm_parser_constants_size(result->node.parser));
pm_scope_node_destroy(&result->node);
}
- pm_parser_free(&result->parser);
- pm_string_free(&result->input);
- pm_options_free(&result->options);
+ if (result->parser) pm_parser_free(result->parser);
+ pm_arena_free(result->arena);
+ if (result->source) pm_source_free(result->source);
+ pm_options_free(result->options);
}
/** An error that is going to be formatted into the output. */
typedef struct {
/** A pointer to the diagnostic that was generated during parsing. */
- pm_diagnostic_t *error;
+ const pm_diagnostic_t *error;
/** The start line of the diagnostic message. */
int32_t line;
@@ -10517,123 +10686,151 @@ typedef struct {
#define PM_COLOR_RESET "\033[m"
#define PM_ERROR_TRUNCATE 30
-static inline pm_parse_error_t *
-pm_parse_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_list, const pm_newline_list_t *newline_list) {
- pm_parse_error_t *errors = xcalloc(error_list->size, sizeof(pm_parse_error_t));
- if (errors == NULL) return NULL;
+/** Context struct for collecting errors via callback. */
+typedef struct {
+ pm_parse_error_t *errors;
+ size_t count;
+ size_t capacity;
+ const pm_line_offset_list_t *line_offsets;
+ int32_t start_line;
+} pm_error_collect_t;
- int32_t start_line = parser->start_line;
- for (pm_diagnostic_t *error = (pm_diagnostic_t *) error_list->head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
- pm_line_column_t start = pm_newline_list_line_column(newline_list, error->location.start, start_line);
- pm_line_column_t end = pm_newline_list_line_column(newline_list, error->location.end, start_line);
-
- // We're going to insert this error into the array in sorted order. We
- // do this by finding the first error that has a line number greater
- // than the current error and then inserting the current error before
- // that one.
- size_t index = 0;
- while (
- (index < error_list->size) &&
- (errors[index].error != NULL) &&
- (
- (errors[index].line < start.line) ||
- ((errors[index].line == start.line) && (errors[index].column_start < start.column))
- )
- ) index++;
-
- // Now we're going to shift all of the errors after this one down one
- // index to make room for the new error.
- if (index + 1 < error_list->size) {
- memmove(&errors[index + 1], &errors[index], sizeof(pm_parse_error_t) * (error_list->size - index - 1));
- }
-
- // Finally, we'll insert the error into the array.
- uint32_t column_end;
- if (start.line == end.line) {
- column_end = end.column;
- } else {
- column_end = (uint32_t) (newline_list->offsets[start.line - start_line + 1] - newline_list->offsets[start.line - start_line] - 1);
- }
+static void
+pm_error_collect_callback(const pm_diagnostic_t *diagnostic, void *data)
+{
+ pm_error_collect_t *ctx = (pm_error_collect_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
- // Ensure we have at least one column of error.
- if (start.column == column_end) column_end++;
+ pm_line_column_t start = pm_line_offset_list_line_column(ctx->line_offsets, loc.start, ctx->start_line);
+ pm_line_column_t end = pm_line_offset_list_line_column(ctx->line_offsets, loc.start + loc.length, ctx->start_line);
- errors[index] = (pm_parse_error_t) {
- .error = error,
- .line = start.line,
- .column_start = start.column,
- .column_end = column_end
- };
+ uint32_t column_end;
+ if (start.line == end.line) {
+ column_end = end.column;
+ } else {
+ column_end = (uint32_t) (ctx->line_offsets->offsets[start.line - ctx->start_line + 1] - ctx->line_offsets->offsets[start.line - ctx->start_line] - 1);
}
- return errors;
+ // Ensure we have at least one column of error.
+ if (start.column == column_end) column_end++;
+
+ // Insert into sorted position (insertion sort).
+ size_t index = 0;
+ while (
+ (index < ctx->count) &&
+ (
+ (ctx->errors[index].line < start.line) ||
+ ((ctx->errors[index].line == start.line) && (ctx->errors[index].column_start < start.column))
+ )
+ ) index++;
+
+ if (index < ctx->count) {
+ memmove(&ctx->errors[index + 1], &ctx->errors[index], sizeof(pm_parse_error_t) * (ctx->count - index));
+ }
+
+ ctx->errors[index] = (pm_parse_error_t) {
+ .error = diagnostic,
+ .line = start.line,
+ .column_start = start.column,
+ .column_end = column_end
+ };
+ ctx->count++;
}
-/* Append a literal string to the buffer. */
-#define pm_buffer_append_literal(buffer, str) pm_buffer_append_string(buffer, str, rb_strlen_lit(str))
+static inline pm_parse_error_t *
+pm_parse_errors_format_sort(const pm_parser_t *parser, size_t error_count, const pm_line_offset_list_t *line_offsets) {
+ pm_parse_error_t *errors = xcalloc(error_count, sizeof(pm_parse_error_t));
+ if (errors == NULL) return NULL;
+
+ pm_error_collect_t ctx = {
+ .errors = errors,
+ .count = 0,
+ .capacity = error_count,
+ .line_offsets = line_offsets,
+ .start_line = pm_parser_start_line(parser)
+ };
+
+ pm_parser_errors_each(parser, pm_error_collect_callback, &ctx);
+
+ return errors;
+}
static inline void
-pm_parse_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, pm_buffer_t *buffer) {
- int32_t line_delta = line - parser->start_line;
+pm_parse_errors_format_line(const pm_parser_t *parser, const pm_line_offset_list_t *line_offsets, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, VALUE buffer) {
+ int32_t line_delta = line - pm_parser_start_line(parser);
assert(line_delta >= 0);
size_t index = (size_t) line_delta;
- assert(index < newline_list->size);
+ assert(index < line_offsets->size);
- const uint8_t *start = &parser->start[newline_list->offsets[index]];
+ const uint8_t *start = &pm_parser_start(parser)[line_offsets->offsets[index]];
const uint8_t *end;
- if (index >= newline_list->size - 1) {
- end = parser->end;
+ if (index >= line_offsets->size - 1) {
+ end = pm_parser_end(parser);
} else {
- end = &parser->start[newline_list->offsets[index + 1]];
+ end = &pm_parser_start(parser)[line_offsets->offsets[index + 1]];
}
- pm_buffer_append_format(buffer, number_prefix, line);
+ rb_str_catf(buffer, number_prefix, line);
// Here we determine if we should truncate the end of the line.
bool truncate_end = false;
if ((column_end != 0) && ((end - (start + column_end)) >= PM_ERROR_TRUNCATE)) {
- end = start + column_end + PM_ERROR_TRUNCATE;
+ const uint8_t *end_candidate = start + column_end + PM_ERROR_TRUNCATE;
+
+ for (const uint8_t *ptr = start; ptr < end_candidate;) {
+ size_t char_width = pm_parser_encoding_char_width(parser, ptr, pm_parser_end(parser) - ptr);
+
+ // If we failed to decode a character, then just bail out and
+ // truncate at the fixed width.
+ if (char_width == 0) break;
+
+ // If this next character would go past the end candidate,
+ // then we need to truncate before it.
+ if (ptr + char_width > end_candidate) {
+ end_candidate = ptr;
+ break;
+ }
+
+ ptr += char_width;
+ }
+
+ end = end_candidate;
truncate_end = true;
}
// Here we determine if we should truncate the start of the line.
if (column_start >= PM_ERROR_TRUNCATE) {
- pm_buffer_append_string(buffer, "... ", 4);
+ rb_str_cat(buffer, "... ", 4);
start += column_start;
}
- pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
+ rb_str_cat(buffer, (const char *) start, (size_t) (end - start));
if (truncate_end) {
- pm_buffer_append_string(buffer, " ...\n", 5);
- } else if (end == parser->end && end[-1] != '\n') {
- pm_buffer_append_string(buffer, "\n", 1);
+ rb_str_cat(buffer, " ...\n", 5);
+ } else if (end == pm_parser_end(parser) && end[-1] != '\n') {
+ rb_str_cat(buffer, "\n", 1);
}
}
/**
- * Format the errors on the parser into the given buffer.
+ * Format a pre-sorted array of errors into the given buffer.
*/
static void
-pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, pm_buffer_t *buffer, int highlight, bool inline_messages) {
- assert(error_list->size != 0);
-
- // First, we're going to sort all of the errors by line number using an
- // insertion sort into a newly allocated array.
- const int32_t start_line = parser->start_line;
- const pm_newline_list_t *newline_list = &parser->newline_list;
+pm_parse_errors_format_with(const pm_parser_t *parser, pm_parse_error_t *errors, size_t error_count, VALUE buffer, int highlight, bool inline_messages) {
+ assert(error_count != 0);
- pm_parse_error_t *errors = pm_parse_errors_format_sort(parser, error_list, newline_list);
- if (errors == NULL) return;
+ const int32_t start_line = pm_parser_start_line(parser);
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
// Now we're going to determine how we're going to format line numbers and
// blank lines based on the maximum number of digits in the line numbers
// that are going to be displaid.
pm_parse_error_format_t error_format;
int32_t first_line_number = errors[0].line;
- int32_t last_line_number = errors[error_list->size - 1].line;
+ int32_t last_line_number = errors[error_count - 1].line;
// If we have a maximum line number that is negative, then we're going to
// use the absolute value for comparison but multiple by 10 to additionally
@@ -10722,11 +10919,10 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
// the source before the error to give some context. We'll be careful not to
// display the same line twice in case the errors are close enough in the
// source.
- int32_t last_line = parser->start_line - 1;
+ int32_t last_line = pm_parser_start_line(parser) - 1;
uint32_t last_column_start = 0;
- const pm_encoding_t *encoding = parser->encoding;
- for (size_t index = 0; index < error_list->size; index++) {
+ for (size_t index = 0; index < error_count; index++) {
pm_parse_error_t *error = &errors[index];
// Here we determine how many lines of padding of the source to display,
@@ -10734,42 +10930,42 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
if (error->line - last_line > 1) {
if (error->line - last_line > 2) {
if ((index != 0) && (error->line - last_line > 3)) {
- pm_buffer_append_string(buffer, error_format.divider, error_format.divider_length);
+ rb_str_cat(buffer, error_format.divider, error_format.divider_length);
}
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 2, 0, 0, buffer);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, error->line - 2, 0, 0, buffer);
}
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 1, 0, 0, buffer);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, error->line - 1, 0, 0, buffer);
}
// If this is the first error or we're on a new line, then we'll display
// the line that has the error in it.
if ((index == 0) || (error->line != last_line)) {
if (highlight > 1) {
- pm_buffer_append_literal(buffer, PM_COLOR_RED "> " PM_COLOR_RESET);
+ rb_str_cat_cstr(buffer, PM_COLOR_RED "> " PM_COLOR_RESET);
} else if (highlight > 0) {
- pm_buffer_append_literal(buffer, PM_COLOR_BOLD "> " PM_COLOR_RESET);
+ rb_str_cat_cstr(buffer, PM_COLOR_BOLD "> " PM_COLOR_RESET);
} else {
- pm_buffer_append_literal(buffer, "> ");
+ rb_str_cat_cstr(buffer, "> ");
}
last_column_start = error->column_start;
// Find the maximum column end of all the errors on this line.
uint32_t column_end = error->column_end;
- for (size_t next_index = index + 1; next_index < error_list->size; next_index++) {
+ for (size_t next_index = index + 1; next_index < error_count; next_index++) {
if (errors[next_index].line != error->line) break;
if (errors[next_index].column_end > column_end) column_end = errors[next_index].column_end;
}
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, error->line, error->column_start, column_end, buffer);
+ pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, error->line, error->column_start, column_end, buffer);
}
- const uint8_t *start = &parser->start[newline_list->offsets[error->line - start_line]];
- if (start == parser->end) pm_buffer_append_byte(buffer, '\n');
+ const uint8_t *start = &pm_parser_start(parser)[line_offsets->offsets[error->line - start_line]];
+ if (start == pm_parser_end(parser)) rb_str_cat(buffer, "\n", 1);
// Now we'll display the actual error message. We'll do this by first
// putting the prefix to the line, then a bunch of blank spaces
@@ -10780,59 +10976,59 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
// character when displaid in the terminal. For some east-asian
// languages or emoji, this means it can be thrown off pretty badly. We
// will need to solve this eventually.
- pm_buffer_append_string(buffer, " ", 2);
- pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length);
+ rb_str_cat(buffer, " ", 2);
+ rb_str_cat(buffer, error_format.blank_prefix, error_format.blank_prefix_length);
size_t column = 0;
if (last_column_start >= PM_ERROR_TRUNCATE) {
- pm_buffer_append_string(buffer, " ", 4);
+ rb_str_cat(buffer, " ", 4);
column = last_column_start;
}
while (column < error->column_start) {
- pm_buffer_append_byte(buffer, ' ');
+ rb_str_cat(buffer, " ", 1);
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column));
column += (char_width == 0 ? 1 : char_width);
}
- if (highlight > 1) pm_buffer_append_literal(buffer, PM_COLOR_RED);
- else if (highlight > 0) pm_buffer_append_literal(buffer, PM_COLOR_BOLD);
- pm_buffer_append_byte(buffer, '^');
+ if (highlight > 1) rb_str_cat_cstr(buffer, PM_COLOR_RED);
+ else if (highlight > 0) rb_str_cat_cstr(buffer, PM_COLOR_BOLD);
+ rb_str_cat(buffer, "^", 1);
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column));
column += (char_width == 0 ? 1 : char_width);
while (column < error->column_end) {
- pm_buffer_append_byte(buffer, '~');
+ rb_str_cat(buffer, "~", 1);
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
+ size_t char_width = pm_parser_encoding_char_width(parser, start + column, pm_parser_end(parser) - (start + column));
column += (char_width == 0 ? 1 : char_width);
}
- if (highlight > 0) pm_buffer_append_literal(buffer, PM_COLOR_RESET);
+ if (highlight > 0) rb_str_cat_cstr(buffer, PM_COLOR_RESET);
if (inline_messages) {
- pm_buffer_append_byte(buffer, ' ');
+ rb_str_cat(buffer, " ", 1);
assert(error->error != NULL);
- const char *message = error->error->message;
- pm_buffer_append_string(buffer, message, strlen(message));
+ const char *message = pm_diagnostic_message(error->error);
+ rb_str_cat(buffer, message, strlen(message));
}
- pm_buffer_append_byte(buffer, '\n');
+ rb_str_cat(buffer, "\n", 1);
// Here we determine how many lines of padding to display after the
// error, depending on where the next error is in source.
last_line = error->line;
int32_t next_line;
- if (index == error_list->size - 1) {
- next_line = (((int32_t) newline_list->size) + parser->start_line);
+ if (index == error_count - 1) {
+ next_line = (((int32_t) line_offsets->size) + pm_parser_start_line(parser));
// If the file ends with a newline, subtract one from our "next_line"
// so that we don't output an extra line at the end of the file
- if ((parser->start + newline_list->offsets[newline_list->size - 1]) == parser->end) {
+ if ((pm_parser_start(parser) + line_offsets->offsets[line_offsets->size - 1]) == pm_parser_end(parser)) {
next_line--;
}
}
@@ -10841,18 +11037,30 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
}
if (next_line - last_line > 1) {
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
if (next_line - last_line > 1) {
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
+ rb_str_cat(buffer, " ", 2);
+ pm_parse_errors_format_line(parser, line_offsets, error_format.number_prefix, ++last_line, 0, 0, buffer);
}
}
- // Finally, we'll free the array of errors that we allocated.
- xfree(errors);
+}
+
+/**
+ * Format the errors on the parser into the given buffer.
+ */
+static void
+pm_parse_errors_format(const pm_parser_t *parser, size_t error_count, VALUE buffer, int highlight, bool inline_messages) {
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+
+ pm_parse_error_t *errors = pm_parse_errors_format_sort(parser, error_count, line_offsets);
+ if (errors == NULL) return;
+
+ pm_parse_errors_format_with(parser, errors, error_count, buffer, highlight, inline_messages);
+ SIZED_FREE_N(errors, error_count);
}
#undef PM_ERROR_TRUNCATE
@@ -10867,23 +11075,136 @@ pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, p
* as well.
*/
static bool
-pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *location)
+pm_parse_process_error_utf8_p(const pm_parser_t *parser, pm_location_t location)
{
- const size_t start_line = pm_newline_list_line_column(&parser->newline_list, location->start, 1).line;
- const size_t end_line = pm_newline_list_line_column(&parser->newline_list, location->end, 1).line;
+ const size_t start_line = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location.start, 1).line;
+ const size_t end_line = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), location.start + location.length, 1).line;
- const uint8_t *start = parser->start + parser->newline_list.offsets[start_line - 1];
- const uint8_t *end = ((end_line == parser->newline_list.size) ? parser->end : (parser->start + parser->newline_list.offsets[end_line]));
- size_t width;
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ const uint8_t *start = pm_parser_start(parser) + line_offsets->offsets[start_line - 1];
+ const uint8_t *end = ((end_line == line_offsets->size) ? pm_parser_end(parser) : (pm_parser_start(parser) + line_offsets->offsets[end_line]));
+ rb_encoding *utf8 = rb_utf8_encoding();
while (start < end) {
- if ((width = pm_encoding_utf_8_char_width(start, end - start)) == 0) return false;
- start += width;
+ int width = rb_enc_precise_mbclen((const char *) start, (const char *) end, utf8);
+ if (!MBCLEN_CHARFOUND_P(width)) return false;
+ start += MBCLEN_CHARFOUND_LEN(width);
}
return true;
}
+/** Context for the error processing callback used in pm_parse_process_error. */
+typedef struct {
+ const pm_parse_result_t *result;
+ const pm_parser_t *parser;
+ const pm_string_t *filepath;
+ VALUE buffer;
+ int highlight;
+ bool valid_utf8;
+ bool found_argument_error;
+ bool found_load_error;
+ VALUE early_return;
+ const pm_diagnostic_t *first_error;
+ size_t error_count;
+} pm_process_error_ctx_t;
+
+static void
+pm_process_error_check_callback(const pm_diagnostic_t *diagnostic, void *data)
+{
+ pm_process_error_ctx_t *ctx = (pm_process_error_ctx_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+
+ if (ctx->first_error == NULL) ctx->first_error = diagnostic;
+ ctx->error_count++;
+
+ switch (pm_diagnostic_error_level(diagnostic)) {
+ case PM_ERROR_LEVEL_SYNTAX:
+ if (ctx->valid_utf8 && !pm_parse_process_error_utf8_p(ctx->parser, loc)) {
+ ctx->valid_utf8 = false;
+ }
+ break;
+ case PM_ERROR_LEVEL_ARGUMENT: {
+ if (ctx->found_argument_error || ctx->found_load_error) break;
+ ctx->found_argument_error = true;
+
+ int32_t line_number = (int32_t) pm_location_line_number(ctx->parser, &loc);
+
+ rb_str_catf(
+ ctx->buffer,
+ "%.*s:%" PRIi32 ": %s",
+ (int) pm_string_length(ctx->filepath),
+ pm_string_source(ctx->filepath),
+ line_number,
+ pm_diagnostic_message(diagnostic)
+ );
+
+ if (pm_parse_process_error_utf8_p(ctx->parser, loc)) {
+ rb_str_cat(ctx->buffer, "\n", 1);
+ // Format just this one error. We construct a single-element sorted
+ // array manually and call the format function with count=1.
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(ctx->parser);
+ int32_t start_line = pm_parser_start_line(ctx->parser);
+ pm_line_column_t start_lc = pm_line_offset_list_line_column(line_offsets, loc.start, start_line);
+ pm_line_column_t end_lc = pm_line_offset_list_line_column(line_offsets, loc.start + loc.length, start_line);
+
+ uint32_t col_end;
+ if (start_lc.line == end_lc.line) {
+ col_end = end_lc.column;
+ } else {
+ col_end = (uint32_t) (line_offsets->offsets[start_lc.line - start_line + 1] - line_offsets->offsets[start_lc.line - start_line] - 1);
+ }
+ if (start_lc.column == col_end) col_end++;
+
+ pm_parse_error_t single_error = {
+ .error = diagnostic,
+ .line = start_lc.line,
+ .column_start = start_lc.column,
+ .column_end = col_end
+ };
+ pm_parse_errors_format_with(ctx->parser, &single_error, 1, ctx->buffer, ctx->highlight, false);
+ }
+
+ ctx->early_return = rb_exc_new_str(rb_eArgError, ctx->buffer);
+ break;
+ }
+ case PM_ERROR_LEVEL_LOAD: {
+ if (ctx->found_argument_error || ctx->found_load_error) break;
+ ctx->found_load_error = true;
+
+ VALUE message = rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), rb_locale_encoding());
+ VALUE value = rb_exc_new3(rb_eLoadError, message);
+ rb_ivar_set(value, rb_intern_const("@path"), Qnil);
+ ctx->early_return = value;
+ break;
+ }
+ }
+}
+
+/** Callback for formatting non-UTF8 errors. */
+typedef struct {
+ const pm_parser_t *parser;
+ const pm_string_t *filepath;
+ VALUE buffer;
+ bool first;
+} pm_error_simple_format_ctx_t;
+
+static void
+pm_error_simple_format_callback(const pm_diagnostic_t *diagnostic, void *data)
+{
+ pm_error_simple_format_ctx_t *ctx = (pm_error_simple_format_ctx_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+
+ if (!ctx->first) rb_str_cat(ctx->buffer, "\n", 1);
+ ctx->first = false;
+
+ rb_str_catf(ctx->buffer, "%.*s:%" PRIi32 ": %s",
+ (int) pm_string_length(ctx->filepath),
+ pm_string_source(ctx->filepath),
+ (int32_t) pm_location_line_number(ctx->parser, &loc),
+ pm_diagnostic_message(diagnostic));
+}
+
/**
* Generate an error object from the given parser that contains as much
* information as possible about the errors that were encountered.
@@ -10891,12 +11212,11 @@ pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *lo
static VALUE
pm_parse_process_error(const pm_parse_result_t *result)
{
- const pm_parser_t *parser = &result->parser;
- const pm_diagnostic_t *head = (const pm_diagnostic_t *) parser->error_list.head;
- bool valid_utf8 = true;
+ const pm_parser_t *parser = result->parser;
+ size_t error_count = pm_parser_errors_size(parser);
- pm_buffer_t buffer = { 0 };
- const pm_string_t *filepath = &parser->filepath;
+ VALUE buffer = rb_str_buf_new(0);
+ const pm_string_t *filepath = pm_parser_filepath(parser);
int highlight = rb_stderr_tty_p();
if (highlight) {
@@ -10904,90 +11224,98 @@ pm_parse_process_error(const pm_parse_result_t *result)
highlight = (no_color == NULL || no_color[0] == '\0') ? 2 : 1;
}
- for (const pm_diagnostic_t *error = head; error != NULL; error = (const pm_diagnostic_t *) error->node.next) {
- switch (error->level) {
- case PM_ERROR_LEVEL_SYNTAX:
- // It is implicitly assumed that the error messages will be
- // encodeable as UTF-8. Because of this, we can't include source
- // examples that contain invalid byte sequences. So if any source
- // examples include invalid UTF-8 byte sequences, we will skip
- // showing source examples entirely.
- if (valid_utf8 && !pm_parse_process_error_utf8_p(parser, &error->location)) {
- valid_utf8 = false;
- }
- break;
- case PM_ERROR_LEVEL_ARGUMENT: {
- // Any errors with the level PM_ERROR_LEVEL_ARGUMENT take over as
- // the only argument that gets raised. This is to allow priority
- // messages that should be handled before anything else.
- int32_t line_number = (int32_t) pm_location_line_number(parser, &error->location);
-
- pm_buffer_append_format(
- &buffer,
- "%.*s:%" PRIi32 ": %s",
- (int) pm_string_length(filepath),
- pm_string_source(filepath),
- line_number,
- error->message
- );
-
- if (pm_parse_process_error_utf8_p(parser, &error->location)) {
- pm_buffer_append_byte(&buffer, '\n');
-
- pm_list_node_t *list_node = (pm_list_node_t *) error;
- pm_list_t error_list = { .size = 1, .head = list_node, .tail = list_node };
-
- pm_parse_errors_format(parser, &error_list, &buffer, highlight, false);
- }
+ // First pass: check for argument/load errors and UTF-8 validity.
+ pm_process_error_ctx_t ctx = {
+ .result = result,
+ .parser = parser,
+ .filepath = filepath,
+ .buffer = buffer,
+ .highlight = highlight,
+ .valid_utf8 = true,
+ .found_argument_error = false,
+ .found_load_error = false,
+ .early_return = Qundef,
+ .first_error = NULL,
+ .error_count = 0
+ };
- VALUE value = rb_exc_new(rb_eArgError, pm_buffer_value(&buffer), pm_buffer_length(&buffer));
- pm_buffer_free(&buffer);
+ pm_parser_errors_each(parser, pm_process_error_check_callback, &ctx);
- return value;
- }
- case PM_ERROR_LEVEL_LOAD: {
- // Load errors are much simpler, because they don't include any of
- // the source in them. We create the error directly from the
- // message.
- VALUE message = rb_enc_str_new_cstr(error->message, rb_locale_encoding());
- VALUE value = rb_exc_new3(rb_eLoadError, message);
- rb_ivar_set(value, rb_intern_const("@path"), Qnil);
- return value;
- }
- }
+ // If we found an argument or load error, return it immediately.
+ if (ctx.early_return != Qundef) {
+ return ctx.early_return;
}
- pm_buffer_append_format(
- &buffer,
+ // Format the header line.
+ pm_location_t first_loc = pm_diagnostic_location(ctx.first_error);
+ rb_str_catf(
+ buffer,
"%.*s:%" PRIi32 ": syntax error%s found\n",
(int) pm_string_length(filepath),
pm_string_source(filepath),
- (int32_t) pm_location_line_number(parser, &head->location),
- (parser->error_list.size > 1) ? "s" : ""
+ (int32_t) pm_location_line_number(parser, &first_loc),
+ (error_count > 1) ? "s" : ""
);
- if (valid_utf8) {
- pm_parse_errors_format(parser, &parser->error_list, &buffer, highlight, true);
+ if (ctx.valid_utf8) {
+ pm_parse_errors_format(parser, error_count, buffer, highlight, true);
}
else {
- for (const pm_diagnostic_t *error = head; error != NULL; error = (const pm_diagnostic_t *) error->node.next) {
- if (error != head) pm_buffer_append_byte(&buffer, '\n');
- pm_buffer_append_format(&buffer, "%.*s:%" PRIi32 ": %s", (int) pm_string_length(filepath), pm_string_source(filepath), (int32_t) pm_location_line_number(parser, &error->location), error->message);
- }
+ pm_error_simple_format_ctx_t simple_ctx = {
+ .parser = parser,
+ .filepath = filepath,
+ .buffer = buffer,
+ .first = true
+ };
+ pm_parser_errors_each(parser, pm_error_simple_format_callback, &simple_ctx);
}
- VALUE message = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), result->node.encoding);
- VALUE error = rb_exc_new_str(rb_eSyntaxError, message);
+ rb_enc_associate(buffer, result->node.encoding);
+ VALUE error = rb_exc_new_str(rb_eSyntaxError, buffer);
rb_encoding *filepath_encoding = result->node.filepath_encoding != NULL ? result->node.filepath_encoding : rb_utf8_encoding();
VALUE path = rb_enc_str_new((const char *) pm_string_source(filepath), pm_string_length(filepath), filepath_encoding);
rb_ivar_set(error, rb_intern_const("@path"), path);
- pm_buffer_free(&buffer);
return error;
}
+/** Context for interning constants via callback. */
+typedef struct {
+ ID *constants;
+ rb_encoding *encoding;
+ size_t index;
+} pm_intern_constants_ctx_t;
+
+static void
+pm_intern_constants_callback(const pm_constant_t *constant, void *data)
+{
+ pm_intern_constants_ctx_t *ctx = (pm_intern_constants_ctx_t *) data;
+ ctx->constants[ctx->index++] = rb_intern3((const char *) pm_constant_start(constant), pm_constant_length(constant), ctx->encoding);
+}
+
+/** Context for emitting warnings via callback. */
+typedef struct {
+ const pm_parser_t *parser;
+ rb_encoding *encoding;
+ const char *filepath;
+} pm_warning_emit_ctx_t;
+
+static void
+pm_warning_emit_callback(const pm_diagnostic_t *diagnostic, void *data) {
+ pm_warning_emit_ctx_t *ctx = (pm_warning_emit_ctx_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+ int line = pm_location_line_number(ctx->parser, &loc);
+
+ if (pm_diagnostic_warning_level(diagnostic) == PM_WARNING_LEVEL_VERBOSE) {
+ rb_enc_compile_warning(ctx->encoding, ctx->filepath, line, "%s", pm_diagnostic_message(diagnostic));
+ }
+ else {
+ rb_enc_compile_warn(ctx->encoding, ctx->filepath, line, "%s", pm_diagnostic_message(diagnostic));
+ }
+}
+
/**
* Parse the parse result and raise a Ruby error if there are any syntax errors.
* It returns an error if one should be raised. It is assumed that the parse
@@ -10996,7 +11324,7 @@ pm_parse_process_error(const pm_parse_result_t *result)
static VALUE
pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines)
{
- pm_parser_t *parser = &result->parser;
+ pm_parser_t *parser = result->parser;
// First, set up the scope node so that the AST node is attached and can be
// freed regardless of whether or we return an error.
@@ -11007,42 +11335,37 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines
pm_scope_node_init(node, scope_node, NULL);
scope_node->filepath_encoding = filepath_encoding;
- scope_node->encoding = rb_enc_find(parser->encoding->name);
- if (!scope_node->encoding) rb_bug("Encoding not found %s!", parser->encoding->name);
+ const char *encoding_name = pm_parser_encoding_name(parser);
+ scope_node->encoding = rb_enc_find(encoding_name);
+ if (!scope_node->encoding) rb_bug("Encoding not found %s!", encoding_name);
scope_node->coverage_enabled = coverage_enabled;
// If RubyVM.keep_script_lines is set to true, then we need to create that
// array of script lines here.
if (script_lines != NULL) {
- *script_lines = rb_ary_new_capa(parser->newline_list.size);
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ *script_lines = rb_ary_new_capa(line_offsets->size);
- for (size_t index = 0; index < parser->newline_list.size; index++) {
- size_t offset = parser->newline_list.offsets[index];
- size_t length = index == parser->newline_list.size - 1 ? ((size_t) (parser->end - (parser->start + offset))) : (parser->newline_list.offsets[index + 1] - offset);
- rb_ary_push(*script_lines, rb_enc_str_new((const char *) parser->start + offset, length, scope_node->encoding));
+ for (size_t index = 0; index < line_offsets->size; index++) {
+ size_t offset = line_offsets->offsets[index];
+ size_t length = index == line_offsets->size - 1 ? ((size_t) (pm_parser_end(parser) - (pm_parser_start(parser) + offset))) : (line_offsets->offsets[index + 1] - offset);
+ rb_ary_push(*script_lines, rb_enc_str_new((const char *) pm_parser_start(parser) + offset, length, scope_node->encoding));
}
scope_node->script_lines = script_lines;
}
// Emit all of the various warnings from the parse.
- const pm_diagnostic_t *warning;
- const char *warning_filepath = (const char *) pm_string_source(&parser->filepath);
-
- for (warning = (const pm_diagnostic_t *) parser->warning_list.head; warning != NULL; warning = (const pm_diagnostic_t *) warning->node.next) {
- int line = pm_location_line_number(parser, &warning->location);
-
- if (warning->level == PM_WARNING_LEVEL_VERBOSE) {
- rb_enc_compile_warning(scope_node->encoding, warning_filepath, line, "%s", warning->message);
- }
- else {
- rb_enc_compile_warn(scope_node->encoding, warning_filepath, line, "%s", warning->message);
- }
- }
+ pm_warning_emit_ctx_t warning_ctx = {
+ .parser = parser,
+ .encoding = scope_node->encoding,
+ .filepath = (const char *) pm_string_source(pm_parser_filepath(parser))
+ };
+ pm_parser_warnings_each(parser, pm_warning_emit_callback, &warning_ctx);
// If there are errors, raise an appropriate error and free the result.
- if (parser->error_list.size > 0) {
+ if (pm_parser_errors_size(parser) > 0) {
VALUE error = pm_parse_process_error(result);
// TODO: We need to set the backtrace.
@@ -11053,18 +11376,14 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines
// Now set up the constant pool and intern all of the various constants into
// their corresponding IDs.
scope_node->parser = parser;
- scope_node->constants = xcalloc(parser->constant_pool.size, sizeof(ID));
+ scope_node->options = result->options;
+ scope_node->line_offsets = pm_parser_line_offsets(parser);
+ scope_node->start_line = pm_parser_start_line(parser);
+ size_t constants_size = pm_parser_constants_size(parser);
+ scope_node->constants = constants_size ? xmalloc(constants_size * sizeof(ID)) : NULL;
- for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
- pm_constant_t *constant = &parser->constant_pool.constants[index];
- scope_node->constants[index] = rb_intern3((const char *) constant->start, constant->length, scope_node->encoding);
- }
-
- scope_node->index_lookup_table = st_init_numtable();
- pm_constant_id_list_t *locals = &scope_node->locals;
- for (size_t index = 0; index < locals->size; index++) {
- st_insert(scope_node->index_lookup_table, locals->ids[index], index);
- }
+ pm_intern_constants_ctx_t intern_ctx = { .constants = scope_node->constants, .encoding = scope_node->encoding, .index = 0 };
+ pm_parser_constants_each(parser, pm_intern_constants_callback, &intern_ctx);
// If we got here, this is a success and we can return Qnil to indicate that
// no error should be raised.
@@ -11103,22 +11422,22 @@ pm_options_frozen_string_literal_init(pm_options_t *options)
static inline VALUE
pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t *parser)
{
- const pm_newline_list_t *newline_list = &parser->newline_list;
- const char *start = (const char *) parser->start;
- const char *end = (const char *) parser->end;
+ const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
+ const char *start = (const char *) pm_parser_start(parser);
+ const char *end = (const char *) pm_parser_end(parser);
// If we end exactly on a newline, then there's no need to push on a final
// segment. If we don't, then we need to push on the last offset up to the
// end of the string.
- size_t last_offset = newline_list->offsets[newline_list->size - 1];
+ size_t last_offset = line_offsets->offsets[line_offsets->size - 1];
bool last_push = start + last_offset != end;
// Create the ruby strings that represent the lines of the source.
- VALUE lines = rb_ary_new_capa(newline_list->size - (last_push ? 0 : 1));
+ VALUE lines = rb_ary_new_capa(line_offsets->size - (last_push ? 0 : 1));
- for (size_t index = 0; index < newline_list->size - 1; index++) {
- size_t offset = newline_list->offsets[index];
- size_t length = newline_list->offsets[index + 1] - offset;
+ for (size_t index = 0; index < line_offsets->size - 1; index++) {
+ size_t offset = line_offsets->offsets[index];
+ size_t length = line_offsets->offsets[index + 1] - offset;
rb_ary_push(lines, rb_enc_str_new(start + offset, length, scope_node->encoding));
}
@@ -11131,145 +11450,35 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t
return lines;
}
-// This is essentially pm_string_mapped_init(), preferring to memory map the
-// file, with additional handling for files that require blocking to properly
-// read (e.g. pipes).
-static pm_string_init_result_t
-pm_read_file(pm_string_t *string, const char *filepath)
-{
-#ifdef _WIN32
- // Open the file for reading.
- int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
- if (length == 0) return PM_STRING_INIT_ERROR_GENERIC;
-
- WCHAR *wfilepath = xmalloc(sizeof(WCHAR) * ((size_t) length));
- if ((wfilepath == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, wfilepath, length) == 0)) {
- xfree(wfilepath);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- HANDLE file = CreateFileW(wfilepath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
- if (file == INVALID_HANDLE_VALUE) {
- pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC;
-
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- DWORD attributes = GetFileAttributesW(wfilepath);
- if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
- result = PM_STRING_INIT_ERROR_DIRECTORY;
- }
- }
-
- xfree(wfilepath);
- return result;
- }
-
- // Get the file size.
- DWORD file_size = GetFileSize(file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- CloseHandle(file);
- xfree(wfilepath);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // 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);
- xfree(wfilepath);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- // Create a mapping of the file.
- HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
- if (mapping == NULL) {
- CloseHandle(file);
- xfree(wfilepath);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Map the file into memory.
- uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
- CloseHandle(mapping);
- CloseHandle(file);
- xfree(wfilepath);
-
- if (source == NULL) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
- return PM_STRING_INIT_SUCCESS;
-#elif defined(_POSIX_MAPPED_FILES)
- // Open the file for reading
- const int open_mode = O_RDONLY | O_NONBLOCK;
- int fd = open(filepath, open_mode);
- if (fd == -1) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Ensure it is a file and not a directory
- if (S_ISDIR(sb.st_mode)) {
- close(fd);
- return PM_STRING_INIT_ERROR_DIRECTORY;
- }
-
- // We need to wait for data first before reading from pipes and character
- // devices. To not block the entire VM, we need to release the GVL while
- // reading. Use IO#read to do this and let the GC handle closing the FD.
- if (S_ISFIFO(sb.st_mode) || S_ISCHR(sb.st_mode)) {
- VALUE io = rb_io_fdopen((int) fd, open_mode, filepath);
- rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
- VALUE contents = rb_funcall(io, rb_intern("read"), 0);
-
- if (!RB_TYPE_P(contents, T_STRING)) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- long len = RSTRING_LEN(contents);
- if (len < 0) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- size_t length = (size_t) len;
- uint8_t *source = malloc(length);
- memcpy(source, RSTRING_PTR(contents), length);
- *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
-
- return PM_STRING_INIT_SUCCESS;
- }
-
- // mmap the file descriptor to virtually get the contents
- size_t size = (size_t) sb.st_size;
- uint8_t *source = NULL;
+struct load_from_fd_args {
+ VALUE path;
+ VALUE io;
+ int open_mode;
+ int fd;
+};
- if (size == 0) {
- close(fd);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
+static VALUE
+close_file(VALUE args)
+{
+ struct load_from_fd_args *arg = (void *)args;
+ if (arg->fd != -1) {
+ close(arg->fd);
}
-
- source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (source == MAP_FAILED) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
+ else if (!NIL_P(arg->io)) {
+ rb_io_close(arg->io);
}
+ return Qnil;
+}
- close(fd);
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
- return PM_STRING_INIT_SUCCESS;
-#else
- return pm_string_file_init(string, filepath);
-#endif
+static VALUE
+load_content(VALUE args)
+{
+ struct load_from_fd_args *arg = (void *)args;
+ VALUE io = rb_io_fdopen(arg->fd, arg->open_mode, RSTRING_PTR(arg->path));
+ arg->io = io;
+ arg->fd = -1;
+ rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
+ return rb_funcall(io, rb_intern("read"), 0);
}
/**
@@ -11279,17 +11488,46 @@ pm_read_file(pm_string_t *string, const char *filepath)
VALUE
pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error)
{
- pm_string_init_result_t init_result = pm_read_file(&result->input, RSTRING_PTR(filepath));
+ pm_source_init_result_t init_result;
+ result->source = pm_source_mapped_new(RSTRING_PTR(filepath), O_RDONLY | O_NONBLOCK, &init_result);
- if (init_result == PM_STRING_INIT_SUCCESS) {
- pm_options_frozen_string_literal_init(&result->options);
+ if (init_result == PM_SOURCE_INIT_SUCCESS) {
+ pm_options_frozen_string_literal_init(result->options);
return Qnil;
}
int err;
- if (init_result == PM_STRING_INIT_ERROR_DIRECTORY) {
+
+ // For non-regular files (pipes, character devices), we need to read
+ // through Ruby IO to properly release the GVL while waiting for data.
+ if (init_result == PM_SOURCE_INIT_ERROR_NON_REGULAR) {
+ struct load_from_fd_args args = {
+ .path = filepath,
+ .open_mode = O_RDONLY | O_NONBLOCK,
+ .fd = rb_cloexec_open(RSTRING_PTR(filepath), args.open_mode, 0),
+ .io = Qnil,
+ };
+ if (args.fd == -1) goto error_generic;
+ VALUE contents = rb_ensure(load_content, (VALUE)&args, close_file, (VALUE)&args);
+
+ if (!RB_TYPE_P(contents, T_STRING)) goto error_generic;
+
+ long len = RSTRING_LEN(contents);
+ if (len < 0) goto error_generic;
+
+ size_t length = (size_t) len;
+ uint8_t *source_data = xmalloc(length);
+ memcpy(source_data, RSTRING_PTR(contents), length);
+ result->source = pm_source_owned_new(source_data, length);
+
+ pm_options_frozen_string_literal_init(result->options);
+ return Qnil;
+ }
+
+ if (init_result == PM_SOURCE_INIT_ERROR_DIRECTORY) {
err = EISDIR;
} else {
+error_generic:
#ifdef _WIN32
err = rb_w32_map_errno(GetLastError());
#else
@@ -11323,11 +11561,13 @@ VALUE
pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines)
{
result->node.filepath_encoding = rb_enc_get(filepath);
- pm_options_filepath_set(&result->options, RSTRING_PTR(filepath));
+ pm_options_filepath_set(result->options, RSTRING_PTR(filepath));
RB_GC_GUARD(filepath);
- pm_parser_init(&result->parser, pm_string_source(&result->input), pm_string_length(&result->input), &result->options);
- pm_node_t *node = pm_parse(&result->parser);
+ pm_options_version_for_current_ruby_set(result->options);
+
+ result->parser = pm_parser_new(result->arena, pm_source_source(result->source), pm_source_length(result->source), result->options);
+ pm_node_t *node = pm_parse(result->parser);
VALUE error = pm_parse_process(result, node, script_lines);
@@ -11340,7 +11580,7 @@ pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines)
VALUE constant_script_lines = rb_const_get_at(rb_cObject, id_script_lines);
if (RB_TYPE_P(constant_script_lines, T_HASH)) {
- rb_hash_aset(constant_script_lines, filepath, pm_parse_file_script_lines(&result->node, &result->parser));
+ rb_hash_aset(constant_script_lines, filepath, pm_parse_file_script_lines(&result->node, result->parser));
}
}
@@ -11376,20 +11616,36 @@ pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *
return rb_exc_new_cstr(rb_eArgError, "invalid source encoding");
}
- pm_options_frozen_string_literal_init(&result->options);
- pm_string_constant_init(&result->input, RSTRING_PTR(source), RSTRING_LEN(source));
- pm_options_encoding_set(&result->options, rb_enc_name(encoding));
+ pm_options_frozen_string_literal_init(result->options);
+ result->source = pm_source_constant_new((const uint8_t *) RSTRING_PTR(source), (size_t) RSTRING_LEN(source));
+ pm_options_encoding_set(result->options, rb_enc_name(encoding));
result->node.filepath_encoding = rb_enc_get(filepath);
- pm_options_filepath_set(&result->options, RSTRING_PTR(filepath));
+ pm_options_filepath_set(result->options, RSTRING_PTR(filepath));
RB_GC_GUARD(filepath);
- pm_parser_init(&result->parser, pm_string_source(&result->input), pm_string_length(&result->input), &result->options);
- pm_node_t *node = pm_parse(&result->parser);
+ pm_options_version_for_current_ruby_set(result->options);
+
+ result->parser = pm_parser_new(result->arena, pm_source_source(result->source), pm_source_length(result->source), result->options);
+ pm_node_t *node = pm_parse(result->parser);
return pm_parse_process(result, node, script_lines);
}
+struct rb_stdin_wrapper {
+ VALUE rb_stdin;
+ int eof_seen;
+};
+
+static int
+pm_parse_stdin_eof(void *stream)
+{
+ struct rb_stdin_wrapper * wrapped_stdin = (struct rb_stdin_wrapper *)stream;
+ return wrapped_stdin->eof_seen;
+}
+
+VALUE rb_io_gets_limit_internal(VALUE io, long limit);
+
/**
* An implementation of fgets that is suitable for use with Ruby IO objects.
*/
@@ -11398,7 +11654,9 @@ pm_parse_stdin_fgets(char *string, int size, void *stream)
{
RUBY_ASSERT(size > 0);
- VALUE line = rb_funcall((VALUE) stream, rb_intern("gets"), 1, INT2FIX(size - 1));
+ struct rb_stdin_wrapper * wrapped_stdin = (struct rb_stdin_wrapper *)stream;
+
+ VALUE line = rb_io_gets_limit_internal(wrapped_stdin->rb_stdin, size - 1);
if (NIL_P(line)) {
return NULL;
}
@@ -11409,6 +11667,13 @@ pm_parse_stdin_fgets(char *string, int size, void *stream)
memcpy(string, cstr, length);
string[length] = '\0';
+ // We're reading strings from stdin via gets. We'll assume that if the
+ // string is smaller than the requested length, and doesn't end with a
+ // newline, that we hit EOF.
+ if (length < (size - 1) && string[length - 1] != '\n') {
+ wrapped_stdin->eof_seen = 1;
+ }
+
return string;
}
@@ -11423,15 +11688,15 @@ void rb_reset_argf_lineno(long n);
VALUE
pm_parse_stdin(pm_parse_result_t *result)
{
- pm_options_frozen_string_literal_init(&result->options);
+ pm_options_frozen_string_literal_init(result->options);
- pm_buffer_t buffer;
- pm_node_t *node = pm_parse_stream(&result->parser, &buffer, (void *) rb_stdin, pm_parse_stdin_fgets, &result->options);
+ struct rb_stdin_wrapper wrapped_stdin = {
+ rb_stdin,
+ 0
+ };
- // Copy the allocated buffer contents into the input string so that it gets
- // freed. At this point we've handed over ownership, so we don't need to
- // free the buffer itself.
- pm_string_owned_init(&result->input, (uint8_t *) pm_buffer_value(&buffer), pm_buffer_length(&buffer));
+ result->source = pm_source_stream_new((void *) &wrapped_stdin, pm_parse_stdin_fgets, pm_parse_stdin_eof);
+ pm_node_t *node = pm_parse_stream(&result->parser, result->arena, result->source, result->options);
// When we're done parsing, we reset $. because we don't want the fact that
// we went through an IO object to be visible to the user.
@@ -11440,6 +11705,14 @@ pm_parse_stdin(pm_parse_result_t *result)
return pm_parse_process(result, node, NULL);
}
+#define PM_VERSION_FOR_RELEASE(major, minor) PM_VERSION_FOR_RELEASE_IMPL(major, minor)
+#define PM_VERSION_FOR_RELEASE_IMPL(major, minor) #major "." #minor
+
+void pm_options_version_for_current_ruby_set(pm_options_t *options) {
+ const char *version = PM_VERSION_FOR_RELEASE(RUBY_API_VERSION_MAJOR, RUBY_API_VERSION_MINOR);
+ pm_options_version_set(options, version, strlen(version));
+}
+
#undef NEW_ISEQ
#define NEW_ISEQ OLD_ISEQ
diff --git a/prism_compile.h b/prism_compile.h
index c032449bd6..4485793902 100644
--- a/prism_compile.h
+++ b/prism_compile.h
@@ -16,6 +16,82 @@ typedef struct pm_local_index_struct {
// A declaration for the struct that lives in compile.c.
struct iseq_link_anchor;
+/**
+ * A direct-indexed lookup table mapping constant IDs to local variable indices.
+ * Regular constant IDs (1..constants_size) index directly. Special forwarding
+ * parameter IDs (idMULT|FLAG, etc.) are mapped to 4 extra slots at the end.
+ *
+ * All lookups are O(1) — a single array dereference.
+ * The table is arena-allocated for child scopes (no explicit free needed).
+ */
+typedef struct {
+ /** Array of local indices, indexed by constant_id. -1 means not present. */
+ int *values;
+
+ /** Total number of slots (constants_size + PM_INDEX_LOOKUP_SPECIALS). */
+ int capacity;
+
+ /** Whether the values array is heap-allocated and needs explicit free. */
+ bool owned;
+} pm_index_lookup_table_t;
+
+/** Number of extra slots for special forwarding parameter IDs. */
+#define PM_INDEX_LOOKUP_SPECIALS 4
+
+/** Slot offsets for special forwarding parameters (relative to constants_size). */
+#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t) (1 << 31))
+#define PM_INDEX_LOOKUP_SPECIAL_MULT 0
+#define PM_INDEX_LOOKUP_SPECIAL_POW 1
+#define PM_INDEX_LOOKUP_SPECIAL_AND 2
+#define PM_INDEX_LOOKUP_SPECIAL_DOT3 3
+
+/**
+ * Special constant IDs for forwarding parameters. These use bit 31 to
+ * distinguish them from regular prism constant pool IDs. The lower bits
+ * encode which special slot (0-3) they map to in the lookup table.
+ */
+#define PM_CONSTANT_MULT ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_MULT))
+#define PM_CONSTANT_POW ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_POW))
+#define PM_CONSTANT_AND ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_AND))
+#define PM_CONSTANT_DOT3 ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_DOT3))
+
+static inline int
+pm_index_lookup_table_index(const pm_index_lookup_table_t *table, pm_constant_id_t key)
+{
+ if (LIKELY(!(key & PM_SPECIAL_CONSTANT_FLAG))) {
+ return (int) key - 1;
+ }
+ return table->capacity - PM_INDEX_LOOKUP_SPECIALS + (int)(key & ~PM_SPECIAL_CONSTANT_FLAG);
+}
+
+static inline void
+pm_index_lookup_table_insert(pm_index_lookup_table_t *table, pm_constant_id_t key, int value)
+{
+ int idx = pm_index_lookup_table_index(table, key);
+ RUBY_ASSERT(idx >= 0 && idx < table->capacity);
+ table->values[idx] = value;
+}
+
+static inline int
+pm_index_lookup_table_lookup(const pm_index_lookup_table_t *table, pm_constant_id_t key, int *value)
+{
+ int idx = pm_index_lookup_table_index(table, key);
+ RUBY_ASSERT(idx >= 0 && idx < table->capacity);
+ if (table->values[idx] == -1) return 0;
+ *value = table->values[idx];
+ return 1;
+}
+
+static inline void
+pm_index_lookup_table_init_heap(pm_index_lookup_table_t *table, int constants_size)
+{
+ int cap = constants_size + PM_INDEX_LOOKUP_SPECIALS;
+ table->values = (int *) ruby_xmalloc(cap * sizeof(int));
+ memset(table->values, -1, cap * sizeof(int));
+ table->capacity = cap;
+ table->owned = true;
+}
+
// ScopeNodes are helper nodes, and will never be part of the AST. We manually
// declare them here to avoid generating them.
typedef struct pm_scope_node {
@@ -27,6 +103,9 @@ typedef struct pm_scope_node {
pm_constant_id_list_t locals;
const pm_parser_t *parser;
+ const pm_options_t *options;
+ const pm_line_offset_list_t *line_offsets;
+ int32_t start_line;
rb_encoding *encoding;
/**
@@ -51,7 +130,14 @@ typedef struct pm_scope_node {
int local_table_for_iseq_size;
ID *constants;
- st_table *index_lookup_table;
+
+ /**
+ * A flat lookup table mapping constant IDs (or special IDs) to local
+ * variable indices. When allocated from the compile data arena (child
+ * scopes), no explicit free is needed. When heap-allocated (top-level
+ * scope in pm_parse_process), owned is set to true so destroy can free it.
+ */
+ pm_index_lookup_table_t index_lookup_table;
// The current coverage setting, passed down through the various scopes.
int coverage_enabled;
@@ -61,20 +147,30 @@ typedef struct pm_scope_node {
* the instructions pertaining to BEGIN{} nodes.
*/
struct iseq_link_anchor *pre_execution_anchor;
+
+ /**
+ * Cached line hint for line offset list lookups. Since the compiler walks
+ * the AST roughly in source order, consecutive lookups tend to be for
+ * nearby byte offsets. This avoids repeated binary searches.
+ */
+ size_t last_line;
} pm_scope_node_t;
void pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous);
void pm_scope_node_destroy(pm_scope_node_t *scope_node);
typedef struct {
+ /** The arena allocator for AST-lifetime memory. */
+ pm_arena_t *arena;
+
/** The parser that will do the actual parsing. */
- pm_parser_t parser;
+ pm_parser_t *parser;
/** The options that will be passed to the parser. */
- pm_options_t options;
+ pm_options_t *options;
- /** The input that represents the source to be parsed. */
- pm_string_t input;
+ /** The source backing the parse (file, string, or stream). */
+ pm_source_t *source;
/** The resulting scope node that will hold the generated AST. */
pm_scope_node_t node;
@@ -83,17 +179,13 @@ typedef struct {
bool parsed;
} pm_parse_result_t;
-#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t)(1 << 31))
-#define PM_CONSTANT_AND ((pm_constant_id_t)(idAnd | PM_SPECIAL_CONSTANT_FLAG))
-#define PM_CONSTANT_DOT3 ((pm_constant_id_t)(idDot3 | PM_SPECIAL_CONSTANT_FLAG))
-#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG))
-#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG))
-
+void pm_parse_result_init(pm_parse_result_t *result);
VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error);
VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
VALUE pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *script_lines);
VALUE pm_parse_stdin(pm_parse_result_t *result);
+void pm_options_version_for_current_ruby_set(pm_options_t *options);
void pm_parse_result_free(pm_parse_result_t *result);
rb_iseq_t *pm_iseq_new(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type, int *error_state);
@@ -101,5 +193,6 @@ rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE
rb_iseq_t *pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state);
rb_iseq_t *pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, int *error_state);
rb_iseq_t *pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option, int *error_state);
+rb_iseq_t *pm_iseq_build(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option);
VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node);
diff --git a/prism_xallocator.h b/prism_xallocator.h
new file mode 100644
index 0000000000..b1fcce48d8
--- /dev/null
+++ b/prism_xallocator.h
@@ -0,0 +1,6 @@
+#ifndef PRISM_XALLOCATOR_H
+#define PRISM_XALLOCATOR_H
+
+#include "ruby/internal/xmalloc.h"
+
+#endif /* PRISM_XALLOCATOR_H */
diff --git a/proc.c b/proc.c
index 9c50f5baa3..bfdc2cc25b 100644
--- a/proc.c
+++ b/proc.c
@@ -22,6 +22,7 @@
#include "method.h"
#include "iseq.h"
#include "vm_core.h"
+#include "ractor_core.h"
#include "yjit.h"
const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
@@ -97,7 +98,7 @@ proc_memsize(const void *ptr)
return sizeof(rb_proc_t);
}
-static const rb_data_type_t proc_data_type = {
+const rb_data_type_t ruby_proc_data_type = {
"proc",
{
proc_mark_and_move,
@@ -108,6 +109,8 @@ static const rb_data_type_t proc_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
+#define proc_data_type ruby_proc_data_type
+
VALUE
rb_proc_alloc(VALUE klass)
{
@@ -255,7 +258,7 @@ static void
binding_free(void *ptr)
{
RUBY_FREE_ENTER("binding");
- ruby_xfree(ptr);
+ SIZED_FREE((rb_binding_t *)ptr);
RUBY_FREE_LEAVE("binding");
}
@@ -297,10 +300,8 @@ rb_binding_alloc(VALUE klass)
return obj;
}
-
-/* :nodoc: */
static VALUE
-binding_dup(VALUE self)
+binding_copy(VALUE self)
{
VALUE bindval = rb_binding_alloc(rb_cBinding);
rb_binding_t *src, *dst;
@@ -309,15 +310,21 @@ 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: */
+static VALUE
+binding_dup(VALUE self)
+{
+ return rb_obj_dup_setup(self, binding_copy(self));
}
/* :nodoc: */
static VALUE
binding_clone(VALUE self)
{
- VALUE bindval = binding_dup(self);
- return rb_obj_clone_setup(self, bindval, Qnil);
+ return rb_obj_clone_setup(self, binding_copy(self), Qnil);
}
VALUE
@@ -352,7 +359,7 @@ rb_binding_new(void)
*
* # evaluate template in context of the object
* eval(template, user.get_binding)
- * #=> {:name=>"Joan", :position=>"manager"}
+ * #=> {name: "Joan", position: "manager"}
*
* Binding#local_variable_get can be used to access the variables
* whose names are reserved Ruby keywords:
@@ -378,19 +385,31 @@ rb_f_binding(VALUE self)
}
/*
- * call-seq:
- * binding.eval(string [, filename [,lineno]]) -> obj
+ * call-seq:
+ * binding.eval(string, filename = default_filename, lineno = 1) -> obj
*
- * Evaluates the Ruby expression(s) in <em>string</em>, in the
- * <em>binding</em>'s context. If the optional <em>filename</em> and
- * <em>lineno</em> parameters are present, they will be used when
- * reporting syntax errors.
+ * Evaluates the Ruby expression(s) in +string+ in the context of
+ * +self+. Returns the result of the last expression:
*
- * def get_binding(param)
- * binding
- * end
+ * def get_binding(param) = binding
* b = get_binding("hello")
* b.eval("param") #=> "hello"
+ *
+ * If the optional +filename+ is given, it will be used as the
+ * filename of the evaluation (for <tt>__FILE__</tt> and errors).
+ * Otherwise, it will default to <tt>(eval at __FILE__:__LINE__)</tt>
+ * where <tt>__FILE__</tt> and <tt>__LINE__</tt> are the filename and
+ * line number of the caller, respectively:
+ *
+ * b.eval("puts __FILE__") # => "(eval at test.rb:4)"
+ * b.eval("puts __FILE__", "foobar.rb") # => "foobar.rb"
+ *
+ * If the optional +lineno+ is given, it will be used as the
+ * line number of the evaluation (for <tt>__LINE__</tt> and errors).
+ * Otherwise, it will default to 1:
+ *
+ * b.eval("puts __LINE__") # => 1
+ * b.eval("puts __LINE__", "foobar.rb", 10) # => 10
*/
static VALUE
@@ -404,7 +423,7 @@ bind_eval(int argc, VALUE *argv, VALUE bindval)
}
static const VALUE *
-get_local_variable_ptr(const rb_env_t **envp, ID lid)
+get_local_variable_ptr(const rb_env_t **envp, ID lid, bool search_outer)
{
const rb_env_t *env = *envp;
do {
@@ -441,7 +460,7 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
*envp = NULL;
return NULL;
}
- } while ((env = rb_vm_env_prev_env(env)) != NULL);
+ } while (search_outer && (env = rb_vm_env_prev_env(env)) != NULL);
*envp = NULL;
return NULL;
@@ -506,7 +525,13 @@ bind_local_variables(VALUE bindval)
int
rb_numparam_id_p(ID id)
{
- return (tNUMPARAM_1 << ID_SCOPE_SHIFT) <= id && id < ((tNUMPARAM_1 + 10) << ID_SCOPE_SHIFT);
+ return (tNUMPARAM_1 << ID_SCOPE_SHIFT) <= id && id < ((tNUMPARAM_1 + 9) << ID_SCOPE_SHIFT);
+}
+
+int
+rb_implicit_param_p(ID id)
+{
+ return id == idItImplicit || rb_numparam_id_p(id);
}
/*
@@ -543,7 +568,7 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- if ((ptr = get_local_variable_ptr(&env, lid)) != NULL) {
+ if ((ptr = get_local_variable_ptr(&env, lid, TRUE)) != NULL) {
return *ptr;
}
@@ -595,7 +620,7 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
+ if ((ptr = get_local_variable_ptr(&env, lid, TRUE)) == NULL) {
/* not found. create new env */
ptr = rb_binding_add_dynavars(bindval, bind, 1, &lid);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
@@ -635,10 +660,140 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym)
const rb_env_t *env;
if (!lid) return Qfalse;
+ if (rb_numparam_id_p(lid)) {
+ rb_name_err_raise("numbered parameter '%1$s' is not a local variable",
+ bindval, ID2SYM(lid));
+ }
+
+ GetBindingPtr(bindval, bind);
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ return RBOOL(get_local_variable_ptr(&env, lid, TRUE));
+}
+
+/*
+ * call-seq:
+ * binding.implicit_parameters -> Array
+ *
+ * Returns the names of numbered parameters and "it" parameter
+ * that are defined in the binding.
+ *
+ * def foo
+ * [42].each do
+ * it
+ * binding.implicit_parameters #=> [:it]
+ * end
+ *
+ * { k: 42 }.each do
+ * _2
+ * binding.implicit_parameters #=> [:_1, :_2]
+ * end
+ * end
+ *
+ */
+static VALUE
+bind_implicit_parameters(VALUE bindval)
+{
+ const rb_binding_t *bind;
+ const rb_env_t *env;
GetBindingPtr(bindval, bind);
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
- return RBOOL(get_local_variable_ptr(&env, lid));
+
+ if (get_local_variable_ptr(&env, idItImplicit, FALSE)) {
+ return rb_ary_new_from_args(1, ID2SYM(idIt));
+ }
+
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ return rb_vm_env_numbered_parameters(env);
+}
+
+/*
+ * call-seq:
+ * binding.implicit_parameter_get(symbol) -> obj
+ *
+ * Returns the value of the numbered parameter or "it" parameter.
+ *
+ * def foo
+ * [42].each do
+ * it
+ * binding.implicit_parameter_get(:it) #=> 42
+ * end
+ *
+ * { k: 42 }.each do
+ * _2
+ * binding.implicit_parameter_get(:_1) #=> :k
+ * binding.implicit_parameter_get(:_2) #=> 42
+ * end
+ * end
+ *
+ */
+static VALUE
+bind_implicit_parameter_get(VALUE bindval, VALUE sym)
+{
+ ID lid = check_local_id(bindval, &sym);
+ const rb_binding_t *bind;
+ const VALUE *ptr;
+ const rb_env_t *env;
+
+ if (lid == idIt) lid = idItImplicit;
+
+ if (!lid || !rb_implicit_param_p(lid)) {
+ rb_name_err_raise("'%1$s' is not an implicit parameter",
+ bindval, sym);
+ }
+
+ GetBindingPtr(bindval, bind);
+
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ if ((ptr = get_local_variable_ptr(&env, lid, FALSE)) != NULL) {
+ return *ptr;
+ }
+
+ if (lid == idItImplicit) lid = idIt;
+ rb_name_err_raise("implicit parameter '%1$s' is not defined for %2$s", bindval, ID2SYM(lid));
+ UNREACHABLE_RETURN(Qundef);
+}
+
+/*
+ * call-seq:
+ * binding.implicit_parameter_defined?(symbol) -> obj
+ *
+ * Returns +true+ if the numbered parameter or "it" parameter exists.
+ *
+ * def foo
+ * [42].each do
+ * it
+ * binding.implicit_parameter_defined?(:it) #=> true
+ * binding.implicit_parameter_defined?(:_1) #=> false
+ * end
+ *
+ * { k: 42 }.each do
+ * _2
+ * binding.implicit_parameter_defined?(:_1) #=> true
+ * binding.implicit_parameter_defined?(:_2) #=> true
+ * binding.implicit_parameter_defined?(:_3) #=> false
+ * binding.implicit_parameter_defined?(:it) #=> false
+ * end
+ * end
+ *
+ */
+static VALUE
+bind_implicit_parameter_defined_p(VALUE bindval, VALUE sym)
+{
+ ID lid = check_local_id(bindval, &sym);
+ const rb_binding_t *bind;
+ const rb_env_t *env;
+
+ if (lid == idIt) lid = idItImplicit;
+
+ if (!lid || !rb_implicit_param_p(lid)) {
+ rb_name_err_raise("'%1$s' is not an implicit parameter",
+ bindval, sym);
+ }
+
+ GetBindingPtr(bindval, bind);
+ env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
+ return RBOOL(get_local_variable_ptr(&env, lid, FALSE));
}
/*
@@ -709,12 +864,15 @@ rb_func_proc_dup(VALUE src_obj)
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));
+ RB_OBJ_WRITTEN(proc_obj, Qundef, proc->basic.block.as.captured.self);
+ RB_OBJ_WRITTEN(proc_obj, Qundef, proc->basic.block.as.captured.code.val);
+ const VALUE *src_ep = src_proc->block.as.captured.ep;
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];
+ ep[VM_ENV_DATA_INDEX_FLAGS] = src_ep[VM_ENV_DATA_INDEX_FLAGS];
+ ep[VM_ENV_DATA_INDEX_ME_CREF] = src_ep[VM_ENV_DATA_INDEX_ME_CREF];
+ ep[VM_ENV_DATA_INDEX_SPECVAL] = src_ep[VM_ENV_DATA_INDEX_SPECVAL];
+ RB_OBJ_WRITE(proc_obj, &ep[VM_ENV_DATA_INDEX_ENV], src_ep[VM_ENV_DATA_INDEX_ENV]);
return proc_obj;
}
@@ -735,11 +893,6 @@ sym_proc_new(VALUE klass, VALUE sym)
struct vm_ifunc *
rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc)
{
- union {
- struct vm_ifunc_argc argc;
- VALUE packed;
- } arity;
-
if (min_argc < UNLIMITED_ARGUMENTS ||
#if SIZEOF_INT * 2 > SIZEOF_VALUE
min_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
@@ -756,14 +909,16 @@ rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int m
rb_raise(rb_eRangeError, "maximum argument number out of range: %d",
max_argc);
}
- arity.argc.min = min_argc;
- arity.argc.max = max_argc;
rb_execution_context_t *ec = GET_EC();
struct vm_ifunc *ifunc = IMEMO_NEW(struct vm_ifunc, imemo_ifunc, (VALUE)rb_vm_svar_lep(ec, ec->cfp));
+
+ rb_gc_register_pinning_obj((VALUE)ifunc);
+
ifunc->func = func;
ifunc->data = data;
- ifunc->argc = arity.argc;
+ ifunc->argc.min = min_argc;
+ ifunc->argc.max = max_argc;
return ifunc;
}
@@ -930,13 +1085,12 @@ f_lambda(VALUE _)
* Document-method: Proc#yield
*
* call-seq:
- * prc.call(params,...) -> obj
- * prc[params,...] -> obj
- * prc.(params,...) -> obj
- * prc.yield(params,...) -> obj
+ * call(...) -> obj
+ * self[...] -> obj
+ * yield(...) -> obj
*
- * Invokes the block, setting the block's parameters to the values in
- * <i>params</i> using something close to method calling semantics.
+ * Invokes the block, setting the block's parameters to the arguments
+ * using something close to method calling semantics.
* Returns the value of the last expression evaluated in the block.
*
* a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } }
@@ -990,7 +1144,12 @@ rb_proc_call_kw(VALUE self, VALUE args, int kw_splat)
VALUE vret;
rb_proc_t *proc;
int argc = check_argc(RARRAY_LEN(args));
- const VALUE *argv = RARRAY_CONST_PTR(args);
+
+ // rb_vm_invoke_proc may end up modifying argv as part of calling and so we
+ // must use RARRAY_PTR, which marks the array as WB_UNPROTECTED instead of
+ // RARRAY_CONST_PTR. Unfortunately this is worse for GC.
+ // See invoke_block_from_c_proc
+ VALUE *argv = RARRAY_PTR(args);
GetProcPtr(self, proc);
vret = rb_vm_invoke_proc(GET_EC(), proc, argc, argv,
kw_splat, VM_BLOCK_HANDLER_NONE);
@@ -1283,10 +1442,10 @@ rb_proc_get_iseq(VALUE self, int *is_proc)
}
/* call-seq:
- * prc == other -> true or false
- * prc.eql?(other) -> true or false
+ * self == other -> true or false
+ * eql?(other) -> true or false
*
- * Two procs are the same if, and only if, they were created from the same code block.
+ * Returns whether +self+ and +other+ were created from the same code block:
*
* def return_block(&block)
* block
@@ -1373,20 +1532,14 @@ proc_eq(VALUE self, VALUE other)
static VALUE
iseq_location(const rb_iseq_t *iseq)
{
- VALUE loc[5];
- int i = 0;
+ VALUE loc[2];
if (!iseq) return Qnil;
rb_iseq_check(iseq);
- loc[i++] = rb_iseq_path(iseq);
- const rb_code_location_t *cl = &ISEQ_BODY(iseq)->location.code_location;
- loc[i++] = RB_INT2NUM(cl->beg_pos.lineno);
- loc[i++] = RB_INT2NUM(cl->beg_pos.column);
- loc[i++] = RB_INT2NUM(cl->end_pos.lineno);
- loc[i++] = RB_INT2NUM(cl->end_pos.column);
- RUBY_ASSERT_ALWAYS(i == numberof(loc));
+ loc[0] = rb_iseq_path(iseq);
+ loc[1] = RB_INT2NUM(ISEQ_BODY(iseq)->location.first_lineno);
- return rb_ary_new_from_values(i, loc);
+ return rb_ary_new4(2, loc);
}
VALUE
@@ -1510,6 +1663,7 @@ rb_hash_proc(st_index_t hash, VALUE prc)
return hash;
}
+static VALUE sym_proc_cache = Qfalse;
/*
* call-seq:
@@ -1528,29 +1682,33 @@ rb_hash_proc(st_index_t hash, VALUE prc)
VALUE
rb_sym_to_proc(VALUE sym)
{
- static VALUE sym_proc_cache = Qfalse;
enum {SYM_PROC_CACHE_SIZE = 67};
- VALUE proc;
- long index;
- ID id;
- if (!sym_proc_cache) {
- sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2);
- rb_vm_register_global_object(sym_proc_cache);
- rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil);
- }
+ if (rb_ractor_main_p()) {
+ if (!sym_proc_cache) {
+ sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE);
+ rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE - 1, Qnil);
+ }
+
+ ID id = SYM2ID(sym);
+ long index = (id % SYM_PROC_CACHE_SIZE);
+ VALUE procval = RARRAY_AREF(sym_proc_cache, index);
+ if (RTEST(procval)) {
+ rb_proc_t *proc;
+ GetProcPtr(procval, proc);
- id = SYM2ID(sym);
- index = (id % SYM_PROC_CACHE_SIZE) << 1;
+ if (proc->block.as.symbol == sym) {
+ return procval;
+ }
+ }
- if (RARRAY_AREF(sym_proc_cache, index) == sym) {
- return RARRAY_AREF(sym_proc_cache, index + 1);
+ procval = sym_proc_new(rb_cProc, sym);
+ RARRAY_ASET(sym_proc_cache, index, procval);
+
+ return RB_GC_GUARD(procval);
}
else {
- proc = sym_proc_new(rb_cProc, ID2SYM(id));
- RARRAY_ASET(sym_proc_cache, index, sym);
- RARRAY_ASET(sym_proc_cache, index + 1, proc);
- return proc;
+ return sym_proc_new(rb_cProc, sym);
}
}
@@ -1654,7 +1812,7 @@ static const rb_data_type_t method_data_type = {
NULL, // No external memory to report,
bm_mark_and_move,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE | RUBY_TYPED_FROZEN_SHAREABLE_NO_REC
};
VALUE
@@ -1707,6 +1865,8 @@ mnew_missing_by_name(VALUE klass, VALUE obj, VALUE *name, int scope, VALUE mclas
return mnew_missing(klass, obj, SYM2ID(vid), mclass);
}
+VALUE rb_zsuper_to_super(int argc, VALUE *argv, VALUE self);
+
static VALUE
mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
VALUE obj, ID id, VALUE mclass, int scope, int error)
@@ -1732,8 +1892,9 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
rb_print_inaccessible(klass, id, visi);
}
}
- if (me->def->type == VM_METHOD_TYPE_ZSUPER) {
- if (me->defined_class) {
+ if (me->def->type == VM_METHOD_TYPE_ZSUPER ||
+ (me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == (rb_cfunc_t)rb_zsuper_to_super)) {
+ if (me->def->type == VM_METHOD_TYPE_ZSUPER && me->defined_class) {
VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class));
id = me->def->original_id;
me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass);
@@ -1828,10 +1989,9 @@ method_entry_defined_class(const rb_method_entry_t *me)
/*
* call-seq:
- * meth.eql?(other_meth) -> true or false
- * meth == other_meth -> true or false
+ * self == other -> true or false
*
- * Two method objects are equal if they are bound to the same
+ * Returns whether +self+ and +other+ are bound to the same
* object and refer to the same method definition and the classes
* defining the methods are the same class or module.
*/
@@ -1853,6 +2013,8 @@ method_eq(VALUE method, VALUE other)
klass1 = method_entry_defined_class(m1->me);
klass2 = method_entry_defined_class(m2->me);
+ if (RB_TYPE_P(klass1, T_ICLASS)) klass1 = RBASIC_CLASS(klass1);
+ if (RB_TYPE_P(klass2, T_ICLASS)) klass2 = RBASIC_CLASS(klass2);
if (!rb_method_entry_eq(m1->me, m2->me) ||
klass1 != klass2 ||
@@ -2012,6 +2174,26 @@ method_owner(VALUE obj)
return data->owner;
}
+/*
+ * call-seq:
+ * meth.box -> box or nil
+ *
+ * Returns the Ruby::Box where +meth+ is defined in.
+ */
+static VALUE
+method_box(VALUE obj)
+{
+ struct METHOD *data;
+ const rb_box_t *box;
+
+ TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
+ box = data->me->def->box;
+ if (!box) return Qnil;
+ if (box->box_object) return box->box_object;
+ rb_bug("Unexpected box on the method definition: %p", (void*) box);
+ UNREACHABLE_RETURN(Qnil);
+}
+
void
rb_method_name_error(VALUE klass, VALUE str)
{
@@ -2200,29 +2382,29 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
*
* Returns an +UnboundMethod+ representing the given
* instance method in _mod_.
+ * See +UnboundMethod+ about how to utilize it
*
- * class Interpreter
- * def do_a() print "there, "; end
- * def do_d() print "Hello "; end
- * def do_e() print "!\n"; end
- * def do_v() print "Dave"; end
- * Dispatcher = {
- * "a" => instance_method(:do_a),
- * "d" => instance_method(:do_d),
- * "e" => instance_method(:do_e),
- * "v" => instance_method(:do_v)
- * }
- * def interpret(string)
- * string.each_char {|b| Dispatcher[b].bind(self).call }
- * end
- * end
+ * class Person
+ * def initialize(name)
+ * @name = name
+ * end
+ *
+ * def hi
+ * puts "Hi, I'm #{@name}!"
+ * end
+ * end
*
- * interpreter = Interpreter.new
- * interpreter.interpret('dave')
+ * dave = Person.new('Dave')
+ * thomas = Person.new('Thomas')
+ *
+ * hi = Person.instance_method(:hi)
+ * hi.bind_call(dave)
+ * hi.bind_call(thomas)
*
* <em>produces:</em>
*
- * Hello there, Dave!
+ * Hi, I'm Dave!
+ * Hi, I'm Thomas!
*/
static VALUE
@@ -2451,7 +2633,7 @@ method_clone(VALUE self)
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);
+ clone = TypedData_Make_Struct(rb_obj_class(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);
@@ -2469,7 +2651,7 @@ method_dup(VALUE self)
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);
+ clone = TypedData_Make_Struct(rb_obj_class(self), struct METHOD, &method_data_type, data);
rb_obj_dup_setup(self, clone);
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
@@ -2479,13 +2661,20 @@ method_dup(VALUE self)
return clone;
}
-/* Document-method: Method#===
- *
+/*
* call-seq:
- * method === obj -> result_of_method
+ * call(...) -> obj
+ * self[...] -> obj
+ * self === obj -> result_of_method
*
- * Invokes the method with +obj+ as the parameter like #call.
- * This allows a method object to be the target of a +when+ clause
+ * Invokes +self+ with the specified arguments, returning the
+ * method's return value.
+ *
+ * m = 12.method("+")
+ * m.call(3) #=> 15
+ * m.call(20) #=> 32
+ *
+ * Using Method#=== allows a method object to be the target of a +when+ clause
* in a case statement.
*
* require 'prime'
@@ -2496,32 +2685,6 @@ method_dup(VALUE self)
* end
*/
-
-/* Document-method: Method#[]
- *
- * call-seq:
- * meth[args, ...] -> obj
- *
- * Invokes the <i>meth</i> with the specified arguments, returning the
- * method's return value, like #call.
- *
- * m = 12.method("+")
- * m[3] #=> 15
- * m[20] #=> 32
- */
-
-/*
- * call-seq:
- * meth.call(args, ...) -> obj
- *
- * Invokes the <i>meth</i> with the specified arguments, returning the
- * method's return value.
- *
- * m = 12.method("+")
- * m.call(3) #=> 15
- * m.call(20) #=> 32
- */
-
static VALUE
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
{
@@ -2923,7 +3086,11 @@ original_method_entry(VALUE mod, ID id)
while ((me = rb_method_entry(mod, id)) != 0) {
const rb_method_definition_t *def = me->def;
- if (def->type != VM_METHOD_TYPE_ZSUPER) break;
+
+ if (def->type != VM_METHOD_TYPE_ZSUPER &&
+ (def->type != VM_METHOD_TYPE_CFUNC ||
+ def->body.cfunc.func != (rb_cfunc_t)rb_zsuper_to_super)) break;
+
mod = RCLASS_SUPER(me->owner);
id = def->original_id;
}
@@ -3044,10 +3211,18 @@ rb_method_entry_location(const rb_method_entry_t *me)
/*
* call-seq:
- * meth.source_location -> [String, Integer]
+ * source_location -> location
+ *
+ * Returns a two-element array containing the Ruby source filename
+ * as a string and the line number integer where +self+ is defined:
*
- * Returns the Ruby source filename and line number containing this method
- * or nil if this method was not defined in Ruby (i.e. native).
+ * def greeting = "hello"
+ * method(:greeting).source_location # => ["test.rb", 1]
+ *
+ * Returns nil if +self+ is not a method defined in Ruby (i.e. defined
+ * using native code):
+ *
+ * Kernel.method(:puts).source_location # => nil
*/
VALUE
@@ -3144,6 +3319,18 @@ rb_method_parameters(VALUE method)
return method_def_parameters(rb_method_def(method));
}
+static inline VALUE
+append_param_name(VALUE str, VALUE name, const char *unnamed)
+{
+ if (!NIL_P(name)) {
+ rb_str_append(str, rb_sym2str(name));
+ }
+ else if (unnamed) {
+ rb_str_cat_cstr(str, unnamed);
+ }
+ return str;
+}
+
/*
* call-seq:
* meth.to_s -> string
@@ -3270,6 +3457,7 @@ method_inspect(VALUE method)
const VALUE keyrest = ID2SYM(rb_intern("keyrest"));
const VALUE block = ID2SYM(rb_intern("block"));
const VALUE nokey = ID2SYM(rb_intern("nokey"));
+ const VALUE noblock = ID2SYM(rb_intern("noblock"));
int forwarding = 0;
rb_str_buf_cat2(str, "(");
@@ -3287,47 +3475,34 @@ method_inspect(VALUE method)
for (int i = 0; i < RARRAY_LEN(params); i++) {
pair = RARRAY_AREF(params, i);
kind = RARRAY_AREF(pair, 0);
- name = RARRAY_AREF(pair, 1);
- // FIXME: in tests it turns out that kind, name = [:req] produces name to be false. Why?..
- if (NIL_P(name) || name == Qfalse) {
- // FIXME: can it be reduced to switch/case?
- if (kind == req || kind == opt) {
- name = rb_str_new2("_");
- }
- else if (kind == rest || kind == keyrest) {
- name = rb_str_new2("");
- }
- else if (kind == block) {
- name = rb_str_new2("block");
- }
- else if (kind == nokey) {
- name = rb_str_new2("nil");
- }
+ if (RARRAY_LEN(pair) > 1) {
+ name = RARRAY_AREF(pair, 1);
+ }
+ else {
+ name = Qnil;
}
if (kind == req) {
- rb_str_catf(str, "%"PRIsVALUE, name);
+ append_param_name(str, name, "_");
}
else if (kind == opt) {
- rb_str_catf(str, "%"PRIsVALUE"=...", name);
+ rb_str_cat_cstr(append_param_name(str, name, "_"), "=...");
}
else if (kind == keyreq) {
- rb_str_catf(str, "%"PRIsVALUE":", name);
+ rb_str_cat_cstr(append_param_name(str, name, NULL), ":");
}
else if (kind == key) {
- rb_str_catf(str, "%"PRIsVALUE": ...", name);
+ rb_str_cat_cstr(append_param_name(str, name, NULL), ": ...");
}
else if (kind == rest) {
- if (name == ID2SYM('*')) {
- rb_str_cat_cstr(str, forwarding ? "..." : "*");
- }
- else {
- rb_str_catf(str, "*%"PRIsVALUE, name);
+ rb_str_cat_cstr(str, forwarding ? "..." : "*");
+ if (name != ID2SYM('*')) {
+ append_param_name(str, name, NULL);
}
}
else if (kind == keyrest) {
if (name != ID2SYM(idPow)) {
- rb_str_catf(str, "**%"PRIsVALUE, name);
+ append_param_name(rb_str_cat_cstr(str, "**"), name, NULL);
}
else if (i > 0) {
rb_str_set_len(str, RSTRING_LEN(str) - 2);
@@ -3346,12 +3521,15 @@ method_inspect(VALUE method)
}
}
else {
- rb_str_catf(str, "&%"PRIsVALUE, name);
+ append_param_name(rb_str_cat_cstr(str, "&"), name, NULL);
}
}
else if (kind == nokey) {
rb_str_buf_cat2(str, "**nil");
}
+ else if (kind == noblock) {
+ rb_str_buf_cat2(str, "&nil");
+ }
if (i < RARRAY_LEN(params) - 1) {
rb_str_buf_cat2(str, ", ");
@@ -3417,6 +3595,8 @@ method_to_proc(VALUE method)
}
extern VALUE rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner);
+extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
+rb_cref_t * rb_vm_get_cref(const VALUE *ep);
/*
* call-seq:
@@ -3443,11 +3623,76 @@ method_super_method(VALUE method)
mid = data->me->def->body.alias.original_me->def->original_id;
}
else {
- super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass));
+ VALUE klass = iclass;
+ if (RICLASS_FOR_REFINEMENT_P(klass)) {
+ // Refined methods need this check before superclass determination
+ klass = RBASIC(klass)->klass;
+ }
+ super_class = RCLASS_SUPER(RCLASS_ORIGIN(klass));
mid = data->me->def->original_id;
}
if (!super_class) return Qnil;
- me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass);
+
+ // For refined methods, skip refinements for the same definition, but consider
+ // refinements for superclass methods
+ const rb_method_definition_t *skip_def = RICLASS_FOR_REFINEMENT_P(iclass) ? data->me->def : NULL;
+
+ // Use the CREF of the Method/UnboundMethod, not the CREF of the caller of super_method.
+ // We must avoid the use of rb_callable_method_entry_with_refinements, as that will
+ // implicitly use the refinements activated in of the caller of super_method.
+ const rb_cref_t *cref = NULL;
+ switch (data->me->def->type) {
+ case VM_METHOD_TYPE_ISEQ:
+ cref = data->me->def->body.iseq.cref;
+ break;
+ case VM_METHOD_TYPE_BMETHOD: {
+ const rb_proc_t *proc;
+ GetProcPtr(data->me->def->body.bmethod.proc, proc);
+ const struct rb_block *block = &proc->block;
+ if (vm_block_type(block) == block_type_iseq)
+ cref = rb_vm_get_cref(block->as.captured.ep);
+ break;
+ }
+ default:
+ break;
+ }
+ VALUE klass = super_class;
+ me = NULL;
+ while (klass) {
+ const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
+ if (!cme) break;
+ if (cme->def->type != VM_METHOD_TYPE_REFINED) {
+ me = (rb_method_entry_t *)cme;
+ iclass = cme->defined_class;
+ break;
+ }
+ // Look through all CREF scopes for a refinement for cme->owner, mirroring
+ // the loop in search_refined_method.
+ const rb_cref_t *c;
+ for (c = cref; c; c = CREF_NEXT(c)) {
+ VALUE refs = CREF_REFINEMENTS(c);
+ if (NIL_P(refs)) continue;
+ VALUE r = rb_hash_lookup(refs, cme->owner);
+ if (NIL_P(r)) continue;
+ const rb_callable_method_entry_t *ref_cme = rb_callable_method_entry(r, mid);
+ if (!ref_cme) break;
+ if (ref_cme->def->type == VM_METHOD_TYPE_REFINED) continue;
+ if (skip_def && rb_method_definition_eq(ref_cme->def, skip_def)) continue;
+ me = (rb_method_entry_t *)ref_cme;
+ iclass = ref_cme->defined_class;
+ break;
+ }
+ if (me) break;
+ // No refined method found. Use orig_me if available, or normal method lookup
+ // in superclass otherwise.
+ const rb_method_entry_t *orig_me = cme->def->body.refined.orig_me;
+ if (orig_me) {
+ me = (rb_method_entry_t *)orig_me;
+ iclass = orig_me->defined_class ? orig_me->defined_class : cme->defined_class;
+ break;
+ }
+ klass = RCLASS_SUPER(cme->defined_class);
+ }
if (!me) return Qnil;
return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE);
}
@@ -3873,19 +4118,18 @@ rb_proc_compose_to_right(VALUE self, VALUE g)
/*
* call-seq:
- * meth << g -> a_proc
+ * self << g -> a_proc
*
- * Returns a proc that is the composition of this method and the given <i>g</i>.
- * The returned proc takes a variable number of arguments, calls <i>g</i> with them
- * then calls this method with the result.
+ * Returns a proc that is the composition of the given +g+ and this method.
*
- * def f(x)
- * x * x
- * end
+ * The returned proc takes a variable number of arguments. It first calls +g+
+ * with the arguments, then calls +self+ with the return value of +g+.
+ *
+ * def f(ary) = ary << 'in f'
*
* f = self.method(:f)
- * g = proc {|x| x + x }
- * p (f << g).call(2) #=> 16
+ * g = proc { |ary| ary << 'in proc' }
+ * (f << g).call([]) # => ["in proc", "in f"]
*/
static VALUE
rb_method_compose_to_left(VALUE self, VALUE g)
@@ -3897,19 +4141,18 @@ rb_method_compose_to_left(VALUE self, VALUE g)
/*
* call-seq:
- * meth >> g -> a_proc
+ * self >> g -> a_proc
*
- * Returns a proc that is the composition of this method and the given <i>g</i>.
- * The returned proc takes a variable number of arguments, calls this method
- * with them then calls <i>g</i> with the result.
+ * Returns a proc that is the composition of this method and the given +g+.
*
- * def f(x)
- * x * x
- * end
+ * The returned proc takes a variable number of arguments. It first calls +self+
+ * with the arguments, then calls +g+ with the return value of +self+.
+ *
+ * def f(ary) = ary << 'in f'
*
* f = self.method(:f)
- * g = proc {|x| x + x }
- * p (f >> g).call(2) #=> 8
+ * g = proc { |ary| ary << 'in proc' }
+ * (f >> g).call([]) # => ["in f", "in proc"]
*/
static VALUE
rb_method_compose_to_right(VALUE self, VALUE g)
@@ -3967,12 +4210,13 @@ proc_ruby2_keywords(VALUE procval)
switch (proc->block.type) {
case block_type_iseq:
if (ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_rest &&
+ !ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_post &&
!ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_kw &&
!ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_kwrest) {
ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.ruby2_keywords = 1;
}
else {
- rb_warn("Skipping set of ruby2_keywords flag for proc (proc accepts keywords or proc does not accept argument splat)");
+ rb_warn("Skipping set of ruby2_keywords flag for proc (proc accepts keywords or post arguments or proc does not accept argument splat)");
}
break;
default:
@@ -4472,6 +4716,8 @@ Init_Proc(void)
rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
rb_define_method(rb_mKernel, "singleton_method", rb_obj_singleton_method, 1);
+ rb_define_method(rb_cMethod, "box", method_box, 0);
+
/* UnboundMethod */
rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject);
rb_undef_alloc_func(rb_cUnboundMethod);
@@ -4543,6 +4789,8 @@ Init_Proc(void)
void
Init_Binding(void)
{
+ rb_gc_register_address(&sym_proc_cache);
+
rb_cBinding = rb_define_class("Binding", rb_cObject);
rb_undef_alloc_func(rb_cBinding);
rb_undef_method(CLASS_OF(rb_cBinding), "new");
@@ -4553,6 +4801,9 @@ Init_Binding(void)
rb_define_method(rb_cBinding, "local_variable_get", bind_local_variable_get, 1);
rb_define_method(rb_cBinding, "local_variable_set", bind_local_variable_set, 2);
rb_define_method(rb_cBinding, "local_variable_defined?", bind_local_variable_defined_p, 1);
+ rb_define_method(rb_cBinding, "implicit_parameters", bind_implicit_parameters, 0);
+ rb_define_method(rb_cBinding, "implicit_parameter_get", bind_implicit_parameter_get, 1);
+ rb_define_method(rb_cBinding, "implicit_parameter_defined?", bind_implicit_parameter_defined_p, 1);
rb_define_method(rb_cBinding, "receiver", bind_receiver, 0);
rb_define_method(rb_cBinding, "source_location", bind_location, 0);
rb_define_global_function("binding", rb_f_binding, 0);
diff --git a/process.c b/process.c
index 3aea80495d..e443ccbe49 100644
--- a/process.c
+++ b/process.c
@@ -114,6 +114,7 @@ int initgroups(const char *, rb_gid_t);
#include "ruby/st.h"
#include "ruby/thread.h"
#include "ruby/util.h"
+#include "ractor_core.h"
#include "vm_core.h"
#include "vm_sync.h"
#include "ruby/ractor.h"
@@ -1574,8 +1575,8 @@ after_exec(void)
static void
before_fork_ruby(void)
{
- rb_gc_before_fork();
before_exec();
+ rb_gc_before_fork();
}
static void
@@ -2203,7 +2204,7 @@ check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
if (SYMBOL_P(key))
rb_raise(rb_eArgError, "wrong exec option symbol: % "PRIsVALUE,
key);
- rb_raise(rb_eArgError, "wrong exec option");
+ rb_raise(rb_eArgError, "wrong exec option: %"PRIsVALUE, rb_obj_class(key));
}
return ST_CONTINUE;
}
@@ -2634,7 +2635,7 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VAL
}
rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* terminator for execve. */
eargp->invoke.cmd.argv_str =
- rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
+ rb_imemo_tmpbuf_new_from_an_RString(argv_str);
}
RB_GC_GUARD(execarg_obj);
}
@@ -2725,9 +2726,7 @@ open_func(void *ptr)
static void
rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg *eargp, long len)
{
- VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
- rb_imemo_tmpbuf_set_ptr(tmpbuf, ruby_xmalloc(run_exec_dup2_tmpbuf_size(len)));
- eargp->dup2_tmpbuf = tmpbuf;
+ rb_alloc_tmp_buffer(&eargp->dup2_tmpbuf, run_exec_dup2_tmpbuf_size(len));
}
static VALUE
@@ -2829,7 +2828,7 @@ rb_execarg_parent_start1(VALUE execarg_obj)
p = NULL;
rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
eargp->envp_str =
- rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
+ rb_imemo_tmpbuf_new_from_an_RString(envp_str);
eargp->envp_buf = envp_buf;
/*
@@ -2889,7 +2888,6 @@ void
rb_execarg_parent_end(VALUE execarg_obj)
{
execarg_parent_end(execarg_obj);
- RB_GC_GUARD(execarg_obj);
}
static void
@@ -2956,7 +2954,7 @@ NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
* - 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].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* The new process is created using the
* {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
@@ -3182,8 +3180,7 @@ run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, s
long n, i;
int ret;
int extra_fd = -1;
- struct rb_imemo_tmpbuf_struct *buf = (void *)tmpbuf;
- struct run_exec_dup2_fd_pair *pairs = (void *)buf->ptr;
+ struct run_exec_dup2_fd_pair *pairs = RB_IMEMO_TMPBUF_PTR(tmpbuf);
n = RARRAY_LEN(ary);
@@ -4010,7 +4007,10 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
while (1) {
prefork();
disable_child_handler_before_fork(&old);
-#ifdef HAVE_WORKING_VFORK
+
+ // Older versions of ASAN does not work with vfork
+ // See https://github.com/google/sanitizers/issues/925
+#if defined(HAVE_WORKING_VFORK) && !defined(RUBY_ASAN_ENABLED)
if (!has_privilege())
pid = vfork();
else
@@ -4120,9 +4120,13 @@ rb_fork_async_signal_safe(int *status,
rb_pid_t
rb_fork_ruby(int *status)
{
+ if (UNLIKELY(!rb_ractor_main_p())) {
+ rb_raise(rb_eRactorIsolationError, "can not fork from non-main Ractors");
+ }
+
struct rb_process_status child = {.status = 0};
rb_pid_t pid;
- int try_gc = 1, err;
+ int try_gc = 1, err = 0;
struct child_handler_disabler_state old;
do {
@@ -4132,8 +4136,10 @@ rb_fork_ruby(int *status)
rb_thread_acquire_fork_lock();
disable_child_handler_before_fork(&old);
- child.pid = pid = rb_fork();
- child.error = err = errno;
+ RB_VM_LOCKING() {
+ child.pid = pid = rb_fork();
+ child.error = err = errno;
+ }
disable_child_handler_fork_parent(&old); /* yes, bad name */
if (
@@ -4223,7 +4229,7 @@ rb_proc__fork(VALUE _obj)
* puts "Before the fork: #{Process.pid}"
* fork do
* puts "In the child process: #{Process.pid}"
- * end # => 382141
+ * end # => 420520
* puts "After the fork: #{Process.pid}"
*
* Output:
@@ -4632,7 +4638,7 @@ rb_spawn(int argc, const VALUE *argv)
* - 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].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* Returns:
*
@@ -4812,7 +4818,7 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
* - 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].
+ * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
*
* Returns the process ID (pid) of the new process,
* without waiting for it to complete.
@@ -8220,7 +8226,7 @@ ruby_real_ms_time(void)
* - +: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.
+ * - +:second+: Number of seconds as an integer.
*
* Examples:
*
@@ -8752,9 +8758,9 @@ static VALUE rb_mProcID_Syscall;
static VALUE
proc_warmup(VALUE _)
{
- RB_VM_LOCK_ENTER();
- rb_gc_prepare_heap();
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING() {
+ rb_gc_prepare_heap();
+ }
return Qtrue;
}
diff --git a/ractor.c b/ractor.c
index 46390a1749..f94c06cc73 100644
--- a/ractor.c
+++ b/ractor.c
@@ -3,9 +3,9 @@
#include "ruby/ruby.h"
#include "ruby/thread.h"
#include "ruby/ractor.h"
+#include "ruby/re.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"
@@ -16,9 +16,11 @@
#include "internal/ractor.h"
#include "internal/rational.h"
#include "internal/struct.h"
+#include "internal/st.h"
#include "internal/thread.h"
#include "variable.h"
#include "yjit.h"
+#include "zjit.h"
VALUE rb_cRactor;
static VALUE rb_cRactorSelector;
@@ -33,13 +35,19 @@ static VALUE rb_cRactorMovedObject;
static void vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *r, const char *file, int line);
+
+#if RACTOR_CHECK_MODE > 0
+bool rb_ractor_ignore_belonging_flag = false;
+#endif
+
// Ractor locking
static void
ASSERT_ractor_unlocking(rb_ractor_t *r)
{
#if RACTOR_CHECK_MODE > 0
- if (rb_current_execution_context(false) != NULL && r->sync.locked_by == rb_ractor_self(GET_RACTOR())) {
+ const rb_execution_context_t *ec = rb_current_ec_noinline();
+ if (ec != NULL && r->sync.locked_by == rb_ractor_self(rb_ec_ractor_ptr(ec))) {
rb_bug("recursive ractor locking");
}
#endif
@@ -49,7 +57,8 @@ static void
ASSERT_ractor_locking(rb_ractor_t *r)
{
#if RACTOR_CHECK_MODE > 0
- if (rb_current_execution_context(false) != NULL && r->sync.locked_by != rb_ractor_self(GET_RACTOR())) {
+ const rb_execution_context_t *ec = rb_current_ec_noinline();
+ if (ec != NULL && r->sync.locked_by != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
rp(r->sync.locked_by);
rb_bug("ractor lock is not acquired.");
}
@@ -64,10 +73,17 @@ ractor_lock(rb_ractor_t *r, const char *file, int line)
ASSERT_ractor_unlocking(r);
rb_native_mutex_lock(&r->sync.lock);
+ const rb_execution_context_t *ec = rb_current_ec_noinline();
+ if (ec) {
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VM_ASSERT(!cr->malloc_gc_disabled);
+ cr->malloc_gc_disabled = true;
+ }
+
#if RACTOR_CHECK_MODE > 0
- if (rb_current_execution_context(false) != NULL) {
- rb_ractor_t *cr = rb_current_ractor_raw(false);
- r->sync.locked_by = cr ? rb_ractor_self(cr) : Qundef;
+ if (ec != NULL) {
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ r->sync.locked_by = rb_ractor_self(cr);
}
#endif
@@ -77,7 +93,7 @@ ractor_lock(rb_ractor_t *r, const char *file, int line)
static void
ractor_lock_self(rb_ractor_t *cr, const char *file, int line)
{
- VM_ASSERT(cr == GET_RACTOR());
+ VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
#if RACTOR_CHECK_MODE > 0
VM_ASSERT(cr->sync.locked_by != cr->pub.self);
#endif
@@ -91,6 +107,14 @@ ractor_unlock(rb_ractor_t *r, const char *file, int line)
#if RACTOR_CHECK_MODE > 0
r->sync.locked_by = Qnil;
#endif
+
+ const rb_execution_context_t *ec = rb_current_ec_noinline();
+ if (ec) {
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VM_ASSERT(cr->malloc_gc_disabled);
+ cr->malloc_gc_disabled = false;
+ }
+
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)" : "");
@@ -99,7 +123,7 @@ ractor_unlock(rb_ractor_t *r, const char *file, int line)
static void
ractor_unlock_self(rb_ractor_t *cr, const char *file, int line)
{
- VM_ASSERT(cr == GET_RACTOR());
+ VM_ASSERT(cr == rb_ec_ractor_ptr(rb_current_ec_noinline()));
#if RACTOR_CHECK_MODE > 0
VM_ASSERT(cr->sync.locked_by == cr->pub.self);
#endif
@@ -176,62 +200,81 @@ ractor_status_p(rb_ractor_t *r, enum ractor_status 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 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);
- 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_sync_mark(rb_ractor_t *r);
+static void ractor_sync_free(rb_ractor_t *r);
+static size_t ractor_sync_memsize(const rb_ractor_t *r);
+static void ractor_sync_init(rb_ractor_t *r);
+
+static int
+mark_targeted_hook_list(st_data_t key, st_data_t value, st_data_t _arg)
+{
+ rb_hook_list_t *hook_list = (rb_hook_list_t*)value;
+
+ if (hook_list->type == hook_list_type_targeted_iseq) {
+ rb_gc_mark((VALUE)key);
}
+ else {
+ rb_method_definition_t *def = (rb_method_definition_t*)key;
+ RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
+ rb_gc_mark(def->body.bmethod.proc);
+ }
+ rb_hook_list_mark(hook_list);
+
+ return ST_CONTINUE;
}
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);
-
- rb_gc_mark(r->receiving_mutex);
+ bool checking_shareable = rb_gc_checking_shareable();
rb_gc_mark(r->loc);
rb_gc_mark(r->name);
- rb_gc_mark(r->r_stdin);
- rb_gc_mark(r->r_stdout);
- rb_gc_mark(r->r_stderr);
- rb_hook_list_mark(&r->pub.hooks);
-
- if (r->threads.cnt > 0) {
- rb_thread_t *th = 0;
- ccan_list_for_each(&r->threads.set, th, lt_node) {
- VM_ASSERT(th != NULL);
- rb_gc_mark(th->self);
+
+ if (!checking_shareable) {
+ // may unshareable objects
+ rb_gc_mark(r->r_stdin);
+ rb_gc_mark(r->r_stdout);
+ rb_gc_mark(r->r_stderr);
+ rb_gc_mark(r->verbose);
+ rb_gc_mark(r->debug);
+
+ // mark received messages
+ ractor_sync_mark(r);
+
+ rb_hook_list_mark(&r->pub.hooks);
+ if (r->pub.targeted_hooks.num_entries) {
+ st_foreach(&r->pub.targeted_hooks, mark_targeted_hook_list, 0);
+ }
+
+ if (r->threads.cnt > 0) {
+ rb_thread_t *th = 0;
+ ccan_list_for_each(&r->threads.set, th, lt_node) {
+ VM_ASSERT(th != NULL);
+ rb_gc_mark(th->self);
+ }
}
+
+ ractor_local_storage_mark(r);
}
+}
- ractor_local_storage_mark(r);
+static int
+free_targeted_hook_lists(st_data_t key, st_data_t val, st_data_t _arg)
+{
+ rb_hook_list_t *hook_list = (rb_hook_list_t*)val;
+ rb_hook_list_free(hook_list);
+ return ST_DELETE;
}
static void
-ractor_queue_free(struct rb_ractor_queue *rq)
+free_targeted_hooks(st_table *hooks_tbl)
{
- free(rq->baskets);
+ st_foreach(hooks_tbl, free_targeted_hook_lists, 0);
}
static void
@@ -239,14 +282,14 @@ ractor_free(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
RUBY_DEBUG_LOG("free r:%d", rb_ractor_id(r));
+ free_targeted_hooks(&r->pub.targeted_hooks);
rb_native_mutex_destroy(&r->sync.lock);
#ifdef RUBY_THREAD_WIN32_H
- rb_native_cond_destroy(&r->sync.cond);
+ rb_native_cond_destroy(&r->sync.wakeup_cond);
#endif
- ractor_queue_free(&r->sync.recv_queue);
- ractor_queue_free(&r->sync.takers_queue);
ractor_local_storage_free(r);
rb_hook_list_free(&r->pub.hooks);
+ rb_st_free_embedded_table(&r->pub.targeted_hooks);
if (r->newobj_cache) {
RUBY_ASSERT(r == ruby_single_main_ractor);
@@ -255,13 +298,10 @@ ractor_free(void *ptr)
r->newobj_cache = NULL;
}
- ruby_xfree(r);
-}
-
-static size_t
-ractor_queue_memsize(const struct rb_ractor_queue *rq)
-{
- return sizeof(struct rb_ractor_basket) * rq->size;
+ ractor_sync_free(r);
+ if (!r->main_ractor) {
+ SIZED_FREE(r);
+ }
}
static size_t
@@ -270,9 +310,7 @@ ractor_memsize(const void *ptr)
rb_ractor_t *r = (rb_ractor_t *)ptr;
// TODO: more correct?
- return sizeof(rb_ractor_t) +
- ractor_queue_memsize(&r->sync.recv_queue) +
- ractor_queue_memsize(&r->sync.takers_queue);
+ return sizeof(rb_ractor_t) + ractor_sync_memsize(r);
}
static const rb_data_type_t ractor_data_type = {
@@ -305,7 +343,8 @@ RACTOR_PTR(VALUE self)
return r;
}
-static rb_atomic_t ractor_last_id;
+#define MAIN_RACTOR_ID 1
+static rb_atomic_t ractor_last_id = MAIN_RACTOR_ID;
#if RACTOR_CHECK_MODE > 0
uint32_t
@@ -320,1630 +359,7 @@ rb_ractor_current_id(void)
}
#endif
-// Ractor queue
-
-static void
-ractor_queue_setup(struct rb_ractor_queue *rq)
-{
- rq->size = 2;
- rq->cnt = 0;
- rq->start = 0;
- rq->baskets = malloc(sizeof(struct rb_ractor_basket) * rq->size);
-}
-
-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)
-{
- 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)
-{
- ASSERT_ractor_locking(r);
-
- if (rq->reserved_cnt == 0) {
- rq->cnt--;
- rq->start = (rq->start + 1) % rq->size;
- rq->serial++;
- }
- else {
- ractor_queue_at(r, rq, 0)->type.e = basket_type_deleted;
- }
-}
-
-static bool
-ractor_queue_skip_p(rb_ractor_t *r, 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);
-}
-
-static void
-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);
- }
-}
-
-static bool
-ractor_queue_empty_p(rb_ractor_t *r, struct rb_ractor_queue *rq)
-{
- ASSERT_ractor_locking(r);
-
- if (rq->cnt == 0) {
- return true;
- }
-
- ractor_queue_compact(r, rq);
-
- for (int i=0; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(r, rq, i)) {
- return false;
- }
- }
-
- return true;
-}
-
-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;
-
- // remove from queue
- b->type.e = basket_type_deleted;
- ractor_queue_compact(r, rq);
- return true;
- }
- }
-
- return false;
-}
-
-static void
-ractor_queue_enq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_basket *basket)
-{
- ASSERT_ractor_locking(r);
-
- if (rq->size <= rq->cnt) {
- rq->baskets = realloc(rq->baskets, sizeof(struct rb_ractor_basket) * rq->size * 2);
- for (int i=rq->size - rq->start; i<rq->cnt; i++) {
- rq->baskets[i + rq->start] = rq->baskets[i + rq->start - rq->size];
- }
- rq->size *= 2;
- }
- rq->baskets[(rq->start + rq->cnt++) % rq->size] = *basket;
- // fprintf(stderr, "%s %p->cnt:%d\n", RUBY_FUNCTION_NAME_STRING, (void *)rq, rq->cnt);
-}
-
-static void
-ractor_queue_delete(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_basket *basket)
-{
- basket->type.e = basket_type_deleted;
-}
-
-// 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) {
- 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);
- break;
- default:
- rb_bug("unreachable");
- }
-
- return b->p.send.v;
-}
-
-static VALUE
-ractor_basket_accept(struct rb_ractor_basket *b)
-{
- VALUE v = ractor_basket_value(b);
-
- if (b->p.send.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);
- rb_ec_setup_exception(NULL, err, cause);
- rb_exc_raise(err);
- }
-
- return v;
-}
-
-// Ractor synchronizations
-
-#if USE_RUBY_DEBUG_LOG
-static const char *
-wait_status_str(enum rb_ractor_wait_status 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");
-}
-
-static const char *
-wakeup_status_str(enum rb_ractor_wakeup_status wakeup_status)
-{
- 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";
- }
- 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;
-}
-#endif // USE_RUBY_DEBUG_LOG
-
-static bool
-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));
-
- if (ractor_sleeping_by(r, wait_status)) {
- r->sync.wait.wakeup_status = wakeup_status;
- rb_ractor_sched_wakeup(r);
- return true;
- }
- else {
- return false;
- }
-}
-
-static void
-ractor_sleep_interrupt(void *ptr)
-{
- rb_ractor_t *r = ptr;
-
- RACTOR_LOCK(r);
- {
- ractor_wakeup(r, wait_receiving | wait_taking | wait_yielding, wakeup_by_interrupt);
- }
- 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 (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) {
- enum ruby_tag_type state;
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- rb_ec_check_ints(ec);
- }
- EC_POP_TAG();
-
- if (state) {
- (*cf_func)(cr, cf_data);
- EC_JUMP_TAG(ec, state);
- }
- }
- else {
- rb_ec_check_ints(ec);
- }
- }
-
- // reachable?
- RACTOR_LOCK(cr);
- cr->sync.wait.status = prev_wait_status;
- }
-}
-
-#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)
-{
- 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
-rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf)
-{
- RACTOR_UNLOCK(cr);
- {
- rb_nogvl(ractor_sleep_wo_gvl, cr,
- ubf, 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));
-
- 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);
- }
-
- cr->sync.wait.status = wait_none;
-
- // TODO: multi-thread
- wakeup_status = cr->sync.wait.wakeup_status;
- cr->sync.wait.wakeup_status = wakeup_none;
-
- RUBY_DEBUG_LOG("wakeup %s", wakeup_status_str(wakeup_status));
-
- return wakeup_status;
-}
-
-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);
-}
-
-// Ractor.receive
-
-static void
-ractor_recursive_receive_if(rb_ractor_t *r)
-{
- if (r->receiving_mutex && rb_mutex_owned_p(r->receiving_mutex)) {
- rb_raise(rb_eRactorError, "can not call receive/receive_if recursively");
- }
-}
-
-static VALUE
-ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *rq)
-{
- 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);
-
- if (!received) {
- if (cr->sync.incoming_port_closed) {
- rb_raise(rb_eRactorClosedError, "The incoming port is already closed");
- }
- return Qundef;
- }
- else {
- return ractor_basket_accept(&basket);
- }
-}
-
-static void
-ractor_wait_receive(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *rq)
-{
- VM_ASSERT(cr == rb_ec_ractor_ptr(ec));
- ractor_recursive_receive_if(cr);
-
- RACTOR_LOCK(cr);
- {
- while (ractor_queue_empty_p(cr, rq) && !cr->sync.incoming_port_closed) {
- ractor_sleep(ec, cr, wait_receiving);
- }
- }
- RACTOR_UNLOCK(cr);
-}
-
-static VALUE
-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);
- }
-
- return v;
-}
-
-#if 0
-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);
- 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 (bug) rb_bug("!!");
-}
-#endif
-
-struct receive_block_data {
- rb_ractor_t *cr;
- struct rb_ractor_queue *rq;
- VALUE v;
- int index;
- bool success;
-};
-
-static void
-ractor_receive_if_lock(rb_ractor_t *cr)
-{
- VALUE m = cr->receiving_mutex;
- if (m == Qfalse) {
- m = cr->receiving_mutex = rb_mutex_new();
- }
- rb_mutex_lock(m);
-}
-
-static VALUE
-receive_if_body(VALUE ptr)
-{
- struct receive_block_data *data = (struct receive_block_data *)ptr;
-
- ractor_receive_if_lock(data->cr);
- VALUE block_result = rb_yield(data->v);
- rb_ractor_t *cr = data->cr;
-
- RACTOR_LOCK_SELF(cr);
- {
- struct rb_ractor_basket *b = ractor_queue_at(cr, data->rq, data->index);
- VM_ASSERT(basket_type_p(b, basket_type_reserved));
- data->rq->reserved_cnt--;
-
- if (RTEST(block_result)) {
- ractor_queue_delete(cr, data->rq, b);
- ractor_queue_compact(cr, data->rq);
- }
- else {
- b->type.e = basket_type_ref;
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- data->success = true;
-
- if (RTEST(block_result)) {
- return data->v;
- }
- else {
- return Qundef;
- }
-}
-
-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);
- {
- 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;
- data->rq->reserved_cnt--;
- }
- RACTOR_UNLOCK_SELF(cr);
- }
-
- rb_mutex_unlock(cr->receiving_mutex);
- return Qnil;
-}
-
-static VALUE
-ractor_receive_if(rb_execution_context_t *ec, VALUE crv, VALUE b)
-{
- if (!RTEST(b)) rb_raise(rb_eArgError, "no block given");
-
- 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;
-
- while (1) {
- VALUE v = Qundef;
-
- ractor_wait_receive(ec, cr, rq);
-
- RACTOR_LOCK_SELF(cr);
- {
- if (serial != rq->serial) {
- serial = rq->serial;
- index = 0;
- }
-
- // 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);
- v = ractor_basket_value(b);
- b->type.e = basket_type_reserved;
- rq->reserved_cnt++;
- index = i;
- break;
- }
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- if (!UNDEF_P(v)) {
- struct receive_block_data data = {
- .cr = cr,
- .rq = rq,
- .v = v,
- .index = index,
- .success = false,
- };
-
- VALUE result = rb_ensure(receive_if_body, (VALUE)&data,
- receive_if_ensure, (VALUE)&data);
-
- if (!UNDEF_P(result)) return result;
- index++;
- }
-
- RUBY_VM_CHECK_INTS(ec);
- }
-}
-
-static void
-ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_basket *b)
-{
- bool closed = false;
-
- RACTOR_LOCK(r);
- {
- if (r->sync.incoming_port_closed) {
- closed = true;
- }
- else {
- ractor_queue_enq(r, &r->sync.recv_queue, b);
- ractor_wakeup(r, wait_receiving, wakeup_by_send);
- }
- }
- RACTOR_UNLOCK(r);
-
- if (closed) {
- rb_raise(rb_eRactorClosedError, "The incoming-port is already closed");
- }
-}
-
-// 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)
-{
- VALUE v;
- enum rb_ractor_basket_type type;
-
- if (rb_ractor_shareable_p(obj)) {
- type = basket_type_ref;
- v = obj;
- }
- else if (!RTEST(move)) {
- v = ractor_copy(obj);
- type = basket_type_copy;
- }
- else {
- type = basket_type_move;
- v = ractor_move(obj);
- }
-
- *pobj = v;
- *ptype = type;
-}
-
-static void
-ractor_basket_fill_(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, bool exc)
-{
- VM_ASSERT(cr == GET_RACTOR());
-
- basket->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;
-}
-
-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_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)
-{
- 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,
- },
- },
- };
- 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;
- }
- 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
- }
- 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);
- }
- }
- }
- RACTOR_UNLOCK(r);
-
- return deleted;
-}
-
-static VALUE
-ractor_try_take(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket)
-{
- 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;
- }
-}
-
-
-#if VM_CHECK_MODE > 0
-static bool
-ractor_check_specific_take_basket_lock(rb_ractor_t *r, struct rb_ractor_basket *tb)
-{
- 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
-
-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));
- }
-}
-
-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);
- {
- 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;
- }
- }
-
- return false;
-}
-
-static bool
-ractor_deq_take_basket(rb_ractor_t *cr, struct rb_ractor_queue *rs, struct rb_ractor_basket *b)
-{
- ASSERT_ractor_unlocking(cr);
- struct rb_ractor_basket *first_tb = NULL;
- bool found = false;
-
- 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;
-
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_yielding) == basket_type_none) {
- found = true;
- break;
- }
- 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
- }
- }
- }
- else {
- VM_ASSERT(basket_none_p(b));
- }
- }
-
- 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;
- }
- else {
- enum ruby_tag_type 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);
- }
- RACTOR_UNLOCK(tr);
-
- return true;
- }
- else if (cr->sync.outgoing_port_closed) {
- rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- }
- 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) && !cr->sync.outgoing_port_closed) {
- 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
-
-static VALUE
-ractor_selector_create(VALUE klass)
-{
- 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)
-
-/*
- * call-seq:
- * add(ractor) -> ractor
- *
- * Adds _ractor_ to +self+. Raises an exception if _ractor_ is already added.
- * Returns _ractor_.
- */
-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);
- }
-
- return rv;
-}
-
-// Ractor::Selector#remove(r)
-
-/* call-seq:
- * remove(ractor) -> ractor
- *
- * Removes _ractor_ from +self+. Raises an exception if _ractor_ is not added.
- * Returns the removed _ractor_.
- */
-static VALUE
-ractor_selector_remove(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);
-
- RUBY_DEBUG_LOG("r:%u", rb_ractor_id(r));
-
- if (!st_lookup(s->take_ractors, (st_data_t)r, NULL)) {
- rb_raise(rb_eArgError, "not added yet");
- }
-
- 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;
-}
-
-/*
- * call-seq:
- * clear -> self
- *
- * Removes all ractors from +self+. Raises +self+.
- */
-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;
-}
-
-/*
- * call-seq:
- * empty? -> true or false
- *
- * Returns +true+ if no ractor is added.
- */
-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;
-}
-
-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;
-
- if (!basket_none_p(tb)) {
- RUBY_DEBUG_LOG("already taken:%s", basket_type_name(tb->type.e));
- return ST_STOP;
- }
-
- 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));
-
- 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;
- }
- }
- 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;
- }
- else {
- RUBY_DEBUG_LOG("closed, but already taken (%s)", basket_type_name(tb->type.e));
- ret = ST_CONTINUE;
- }
- }
- 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);
-}
-
-/* :nodoc: */
-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 && !UNDEF_P(ret_v = ractor_try_receive(ec, cr, rq))) {
- 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_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);
- 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");
- 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) {
-
- if (basket_type_p(tb, basket_type_yielding)) {
- RACTOR_UNLOCK_SELF(cr);
- {
- rb_thread_sleep(0);
- }
- RACTOR_LOCK_SELF(cr);
- }
- goto retry_waiting;
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- // check the taken result
- 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;
- }
-
- 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);
-}
-
-/*
- * call-seq:
- * wait(receive: false, yield_value: undef, move: false) -> [ractor, value]
- *
- * Waits until any ractor in _selector_ can be active.
- */
-static VALUE
-ractor_selector_wait(int argc, VALUE *argv, VALUE selector)
-{
- VALUE options;
- ID keywords[3];
- VALUE values[3];
-
- keywords[0] = rb_intern("receive");
- keywords[1] = rb_intern("yield_value");
- keywords[2] = rb_intern("move");
-
- 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]);
-}
-
-static VALUE
-ractor_selector_new(int argc, VALUE *ractors, VALUE klass)
-{
- VALUE selector = ractor_selector_create(klass);
-
- for (int i=0; i<argc; i++) {
- ractor_selector_add(selector, ractors[i]);
- }
-
- return selector;
-}
-
-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)
-{
- 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);
- }
- EC_POP_TAG();
- if (state != TAG_NONE) {
- // ensure
- ractor_selector_clear(selector);
-
- // jump
- EC_JUMP_TAG(ec, state);
- }
-
- RB_GC_GUARD(ractors);
- return result;
-}
-
-// Ractor#close_incoming
-
-static VALUE
-ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
-{
- VALUE prev;
-
- RACTOR_LOCK(r);
- {
- if (!r->sync.incoming_port_closed) {
- 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));
- RUBY_DEBUG_LOG("cancel receiving");
- }
- }
- else {
- prev = Qtrue;
- }
- }
- RACTOR_UNLOCK(r);
- return prev;
-}
-
-// Ractor#close_outgoing
-
-static VALUE
-ractor_close_outgoing(rb_execution_context_t *ec, rb_ractor_t *r)
-{
- VALUE prev;
-
- 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);
- }
- }
-
- // raising yielding Ractor
- ractor_wakeup(r, wait_yielding, wakeup_by_close);
-
- VM_ASSERT(ractor_queue_empty_p(r, ts));
- }
- RACTOR_UNLOCK(r);
- return prev;
-}
+#include "ractor_sync.c"
// creation/termination
@@ -1980,14 +396,6 @@ cancel_single_ractor_mode(void)
// enable multi-ractor mode
RUBY_DEBUG_LOG("enable multi-ractor mode");
- VALUE was_disabled = rb_gc_enable();
-
- rb_gc_start();
-
- if (was_disabled) {
- rb_gc_disable();
- }
-
ruby_single_main_ractor = NULL;
rb_funcall(rb_cRactor, rb_intern("_activated"), 0);
}
@@ -2055,22 +463,24 @@ ractor_alloc(VALUE klass)
VALUE rv = TypedData_Make_Struct(klass, rb_ractor_t, &ractor_data_type, r);
FL_SET_RAW(rv, RUBY_FL_SHAREABLE);
r->pub.self = rv;
+ r->next_ec_serial = 1;
VM_ASSERT(ractor_status_p(r, ractor_created));
return rv;
}
+static rb_ractor_t _main_ractor = {
+ .loc = Qnil,
+ .name = Qnil,
+ .pub.id = MAIN_RACTOR_ID,
+ .pub.self = Qnil,
+ .next_ec_serial = 1,
+ .main_ractor = true,
+};
+
rb_ractor_t *
rb_ractor_main_alloc(void)
{
- rb_ractor_t *r = ruby_mimcalloc(1, sizeof(rb_ractor_t));
- if (r == NULL) {
- fprintf(stderr, "[FATAL] failed to allocate memory for main ractor\n");
- exit(EXIT_FAILURE);
- }
- r->pub.id = ++ractor_last_id;
- r->loc = Qnil;
- r->name = Qnil;
- r->pub.self = Qnil;
+ rb_ractor_t *r = &_main_ractor;
r->newobj_cache = rb_gc_ractor_cache_alloc(r);
ruby_single_main_ractor = r;
@@ -2078,6 +488,8 @@ rb_ractor_main_alloc(void)
}
#if defined(HAVE_WORKING_FORK)
+// Set up the main Ractor for the VM after fork.
+// Puts us in "single Ractor mode"
void
rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th)
{
@@ -2093,6 +505,15 @@ rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th)
VM_ASSERT(vm->ractor.blocking_cnt == 0);
VM_ASSERT(vm->ractor.cnt == 1);
}
+
+void
+rb_ractor_terminate_atfork(rb_vm_t *vm, rb_ractor_t *r)
+{
+ rb_gc_ractor_cache_free(r->newobj_cache);
+ r->newobj_cache = NULL;
+ r->status_ = ractor_terminated;
+ ractor_sync_terminate_atfork(vm, r);
+}
#endif
void rb_thread_sched_init(struct rb_thread_sched *, bool atfork);
@@ -2108,15 +529,9 @@ 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);
- 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
+ ractor_sync_init(r);
+ st_init_existing_numtable_with_size(&r->pub.targeted_hooks, 0);
+ r->pub.hooks.type = hook_list_type_ractor_local;
// thread management
rb_thread_sched_init(&r->threads.sched, false);
@@ -2131,20 +546,24 @@ ractor_init(rb_ractor_t *r, VALUE name, VALUE loc)
rb_raise(rb_eArgError, "ASCII incompatible encoding (%s)",
rb_enc_name(enc));
}
- name = rb_str_new_frozen(name);
+ name = RB_OBJ_SET_SHAREABLE(rb_str_new_frozen(name));
}
- r->name = name;
+
+ if (!SPECIAL_CONST_P(loc)) RB_OBJ_SET_SHAREABLE(loc);
r->loc = loc;
+ r->name = name;
}
void
rb_ractor_main_setup(rb_vm_t *vm, rb_ractor_t *r, rb_thread_t *th)
{
- r->pub.self = TypedData_Wrap_Struct(rb_cRactor, &ractor_data_type, r);
+ VALUE rv = r->pub.self = TypedData_Wrap_Struct(rb_cRactor, &ractor_data_type, r);
FL_SET_RAW(r->pub.self, RUBY_FL_SHAREABLE);
ractor_init(r, Qnil, Qnil);
r->threads.main = th;
rb_ractor_living_threads_insert(r, th);
+
+ RB_GC_GUARD(rv);
}
static VALUE
@@ -2154,7 +573,6 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
rb_ractor_t *r = RACTOR_PTR(rv);
ractor_init(r, name, loc);
- // can block here
r->pub.id = ractor_next_id();
RUBY_DEBUG_LOG("r:%u", r->pub.id);
@@ -2163,89 +581,59 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
r->debug = cr->debug;
rb_yjit_before_ractor_spawn();
+ rb_zjit_before_ractor_spawn();
rb_thread_create_ractor(r, args, block);
RB_GC_GUARD(rv);
return rv;
}
+#if 0
static VALUE
ractor_create_func(VALUE klass, VALUE loc, VALUE name, VALUE args, rb_block_call_func_t func)
{
VALUE block = rb_proc_new(func, Qnil);
return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
}
+#endif
static void
-ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool exc)
+ractor_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE result, bool exc)
{
- if (cr->sync.outgoing_port_closed) {
- return;
- }
-
- ASSERT_ractor_unlocking(cr);
-
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
-
- retry:
- if (ractor_try_yield(ec, cr, ts, v, Qfalse, exc, true)) {
- // OK.
- }
- else {
- bool retry = false;
- RACTOR_LOCK(cr);
- {
- if (!ractor_check_take_basket(cr, ts)) {
- 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);
- }
- else {
- RUBY_DEBUG_LOG("rare timing!");
- retry = true; // another ractor is waiting for the yield.
- }
- }
- RACTOR_UNLOCK(cr);
-
- if (retry) goto retry;
- }
+ ractor_notify_exit(ec, cr, result, exc);
}
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);
+ ractor_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);
+ ractor_atexit(ec, cr, ec->errinfo, true);
}
void
rb_ractor_teardown(rb_execution_context_t *ec)
{
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- ractor_close_incoming(ec, cr);
- ractor_close_outgoing(ec, cr);
// sync with rb_ractor_terminate_interrupt_main_thread()
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
VM_ASSERT(cr->threads.main != NULL);
cr->threads.main = NULL;
}
- RB_VM_LOCK_LEAVE();
}
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++) {
- ptr[i] = ractor_receive(ec, r);
+ ptr[i] = ractor_receive(ec, ractor_default_port(r));
}
}
@@ -2254,7 +642,7 @@ rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *r, VALUE args
{
int len = RARRAY_LENINT(args);
for (int i=0; i<len; i++) {
- ractor_send(ec, r, RARRAY_AREF(args, i), false);
+ ractor_send(ec, ractor_default_port(r), RARRAY_AREF(args, i), false);
}
}
@@ -2266,14 +654,6 @@ rb_ractor_main_p_(void)
return rb_ec_ractor_ptr(ec) == rb_ec_vm_ptr(ec)->ractor.main_ractor;
}
-bool
-rb_obj_is_main_ractor(VALUE gv)
-{
- if (!rb_ractor_p(gv)) return false;
- rb_ractor_t *r = DATA_PTR(gv);
- return r == GET_VM()->ractor.main_ractor;
-}
-
int
rb_ractor_living_thread_num(const rb_ractor_t *r)
{
@@ -2371,11 +751,9 @@ ractor_check_blocking(rb_ractor_t *cr, unsigned int remained_thread_cnt, const c
// change ractor status: running -> blocking
rb_vm_t *vm = GET_VM();
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
rb_vm_ractor_blocking_cnt_inc(vm, cr, file, line);
}
- RB_VM_LOCK_LEAVE();
}
}
@@ -2427,11 +805,9 @@ rb_ractor_blocking_threads_dec(rb_ractor_t *cr, const char *file, int line)
if (cr->threads.cnt == cr->threads.blocking_cnt) {
rb_vm_t *vm = GET_VM();
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
}
- RB_VM_LOCK_LEAVE();
}
cr->threads.blocking_cnt--;
@@ -2505,13 +881,11 @@ rb_ractor_terminate_all(void)
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
- }
- RB_VM_UNLOCK();
+ RB_VM_LOCK();
+ {
+ 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
RB_VM_LOCK();
@@ -2524,6 +898,17 @@ rb_ractor_terminate_all(void)
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 */);
+#ifdef RUBY_THREAD_PTHREAD_H
+ while (vm->ractor.sched.barrier_waiting) {
+ // A barrier is waiting. Threads relinquish the VM lock before joining the barrier and
+ // since we just acquired the VM lock back, we're blocking other threads from joining it.
+ // We loop until the barrier is over. We can't join this barrier because our thread isn't added to
+ // running_threads until the call below to `rb_add_running_thread`.
+ RB_VM_UNLOCK();
+ unsigned int lev;
+ RB_VM_LOCK_ENTER_LEV_NB(&lev);
+ }
+#endif
rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
@@ -2561,83 +946,47 @@ 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
-
/*
- * Document-class: Ractor::Selector
- * :nodoc: currently
+ * Document-class: Ractor::Error
*
- * Selects multiple Ractors to be activated.
+ * The parent class of Ractor-related error classes.
*/
-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
*
* Raised when an attempt is made to send a message to a closed port,
* or to retrieve a message from a closed and empty port.
- * Ports may be closed explicitly with Ractor#close_outgoing/close_incoming
+ * Ports may be closed explicitly with Ractor::Port#close
* and are closed implicitly when a Ractor terminates.
*
- * r = Ractor.new { sleep(500) }
- * r.close_outgoing
- * r.take # Ractor::ClosedError
- *
- * ClosedError is a descendant of StopIteration, so the closing of the ractor will break
- * the loops without propagating the error:
- *
- * r = Ractor.new do
- * loop do
- * msg = receive # raises ClosedError and loop traps it
- * puts "Received: #{msg}"
- * end
- * puts "loop exited"
- * end
- *
- * 3.times{|i| r << i}
- * r.close_incoming
- * r.take
- * puts "Continue successfully"
+ * port = Ractor::Port.new
+ * port.close
+ * port << "test" # Ractor::ClosedError
+ * port.receive # Ractor::ClosedError
*
- * This will print:
+ * ClosedError is a descendant of StopIteration, so the closing of a port will break
+ * out of loops without propagating the error.
+ */
+
+/*
+ * Document-class: Ractor::IsolationError
*
- * Received: 0
- * Received: 1
- * Received: 2
- * loop exited
- * Continue successfully
+ * Raised on attempt to make a Ractor-unshareable object
+ * Ractor-shareable.
*/
/*
* Document-class: Ractor::RemoteError
*
- * Raised on attempt to Ractor#take if there was an uncaught exception in the Ractor.
+ * Raised on Ractor#join or Ractor#value if there was an uncaught exception in the Ractor.
* Its +cause+ will contain the original exception, and +ractor+ is the original ractor
* it was raised in.
*
* r = Ractor.new { raise "Something weird happened" }
*
* begin
- * r.take
+ * r.value
* rescue => e
* p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
* p e.ractor == r # => true
@@ -2649,7 +998,7 @@ rb_init_ractor_selector(void)
/*
* Document-class: Ractor::MovedError
*
- * Raised on an attempt to access an object which was moved in Ractor#send or Ractor.yield.
+ * Raised on an attempt to access an object which was moved in Ractor#send or Ractor::Port#send.
*
* r = Ractor.new { sleep }
*
@@ -2664,7 +1013,7 @@ rb_init_ractor_selector(void)
* Document-class: Ractor::MovedObject
*
* A special object which replaces any value that was moved to another ractor in Ractor#send
- * or Ractor.yield. Any attempt to access the object results in Ractor::MovedError.
+ * or Ractor::Port#send. Any attempt to access the object results in Ractor::MovedError.
*
* r = Ractor.new { receive }
*
@@ -2676,6 +1025,12 @@ rb_init_ractor_selector(void)
* # Ractor::MovedError (can not send any methods to a moved object)
*/
+/*
+ * Document-class: Ractor::UnsafeError
+ *
+ * Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor.
+ */
+
// Main docs are in ractor.rb, but without this clause there are weird artifacts
// in their rendering.
/*
@@ -2710,11 +1065,7 @@ Init_Ractor(void)
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
- // internal
-
-#if USE_RACTOR_SELECTOR
- rb_init_ractor_selector();
-#endif
+ Init_RactorPort();
}
void
@@ -2808,6 +1159,50 @@ rb_ractor_hooks(rb_ractor_t *cr)
return &cr->pub.hooks;
}
+st_table *
+rb_ractor_targeted_hooks(rb_ractor_t *cr)
+{
+ return &cr->pub.targeted_hooks;
+}
+
+static void
+rb_obj_set_shareable_no_assert(VALUE obj)
+{
+ FL_SET_RAW(obj, FL_SHAREABLE);
+
+ if (rb_obj_gen_fields_p(obj)) {
+ VALUE fields = rb_obj_fields_no_ractor_check(obj);
+ if (imemo_type_p(fields, imemo_fields)) {
+ // no recursive mark
+ FL_SET_RAW(fields, FL_SHAREABLE);
+ }
+ }
+}
+
+#ifndef STRICT_VERIFY_SHAREABLE
+#define STRICT_VERIFY_SHAREABLE 0
+#endif
+
+bool
+rb_ractor_verify_shareable(VALUE obj)
+{
+#if STRICT_VERIFY_SHAREABLE
+ rb_gc_verify_shareable(obj);
+#endif
+ return true;
+}
+
+VALUE
+rb_obj_set_shareable(VALUE obj)
+{
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
+
+ rb_obj_set_shareable_no_assert(obj);
+ RUBY_ASSERT(rb_ractor_verify_shareable(obj));
+
+ return obj;
+}
+
/// traverse function
// 2: stop search
@@ -2875,6 +1270,7 @@ obj_traverse_rec(struct obj_traverse_data *data)
{
if (UNLIKELY(!data->rec)) {
data->rec_hash = rb_ident_hash_new();
+ rb_obj_hide(data->rec_hash);
data->rec = RHASH_ST_TABLE(data->rec_hash);
}
return data->rec;
@@ -2908,6 +1304,7 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
// already traversed
return 0;
}
+ RB_OBJ_WRITTEN(data->rec_hash, Qundef, obj);
struct obj_traverse_callback_data d = {
.stop = false,
@@ -2924,7 +1321,6 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
case T_REGEXP:
case T_FILE:
case T_SYMBOL:
- case T_MATCH:
break;
case T_OBJECT:
@@ -2933,6 +1329,8 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
case T_ARRAY:
{
+ rb_ary_cancel_sharing(obj);
+
for (int i = 0; i < RARRAY_LENINT(obj); i++) {
VALUE e = rb_ary_entry(obj, i);
if (obj_traverse_i(e, data)) return 1;
@@ -2955,7 +1353,7 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
case T_STRUCT:
{
- long len = RSTRUCT_LEN(obj);
+ long len = RSTRUCT_LEN_RAW(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
for (long i=0; i<len; i++) {
@@ -2964,6 +1362,10 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
}
break;
+ case T_MATCH:
+ if (obj_traverse_i(RMATCH(obj)->str, data)) return 1;
+ break;
+
case T_RATIONAL:
if (obj_traverse_i(RRATIONAL(obj)->num, data)) return 1;
if (obj_traverse_i(RRATIONAL(obj)->den, data)) return 1;
@@ -2980,11 +1382,9 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
.stop = false,
.data = data,
};
- RB_VM_LOCK_ENTER_NO_BARRIER();
- {
+ RB_VM_LOCKING_NO_BARRIER() {
rb_objspace_reachable_objects_from(obj, obj_traverse_reachable_i, &d);
}
- RB_VM_LOCK_LEAVE_NO_BARRIER();
if (d.stop) return 1;
}
break;
@@ -3051,7 +1451,7 @@ allow_frozen_shareable_p(VALUE obj)
if (!RB_TYPE_P(obj, T_DATA)) {
return true;
}
- else if (RTYPEDDATA_P(obj)) {
+ else {
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE) {
return true;
@@ -3062,6 +1462,26 @@ allow_frozen_shareable_p(VALUE obj)
}
static enum obj_traverse_iterator_result
+make_shareable_check_shareable_freeze(VALUE obj, enum obj_traverse_iterator_result result)
+{
+ if (!RB_OBJ_FROZEN_RAW(obj)) {
+ rb_funcall(obj, idFreeze, 0);
+
+ if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
+ rb_raise(rb_eRactorError, "#freeze does not freeze object correctly");
+ }
+
+ if (RB_OBJ_SHAREABLE_P(obj)) {
+ return traverse_skip;
+ }
+ }
+
+ return result;
+}
+
+static int obj_refer_only_shareables_p(VALUE obj);
+
+static enum obj_traverse_iterator_result
make_shareable_check_shareable(VALUE obj)
{
VM_ASSERT(!SPECIAL_CONST_P(obj));
@@ -3070,38 +1490,61 @@ make_shareable_check_shareable(VALUE obj)
return traverse_skip;
}
else if (!allow_frozen_shareable_p(obj)) {
- if (rb_obj_is_proc(obj)) {
- rb_proc_ractor_make_shareable(obj);
+ VM_ASSERT(RB_TYPE_P(obj, T_DATA));
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
+
+ if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) {
+ if (obj_refer_only_shareables_p(obj)) {
+ make_shareable_check_shareable_freeze(obj, traverse_skip);
+ RB_OBJ_SET_SHAREABLE(obj);
+ return traverse_skip;
+ }
+ else {
+ rb_raise(rb_eRactorError,
+ "can not make shareable object for %+"PRIsVALUE" because it refers unshareable objects", obj);
+ }
+ }
+ else if (rb_obj_is_proc(obj)) {
+ rb_proc_ractor_make_shareable(obj, Qundef);
return traverse_cont;
}
else {
- rb_raise(rb_eRactorError, "can not make shareable object for %"PRIsVALUE, obj);
+ rb_raise(rb_eRactorError, "can not make shareable object for %+"PRIsVALUE, obj);
}
}
- if (RB_TYPE_P(obj, T_IMEMO)) {
+ switch (TYPE(obj)) {
+ case T_IMEMO:
return traverse_skip;
- }
-
- if (!RB_OBJ_FROZEN_RAW(obj)) {
- rb_funcall(obj, idFreeze, 0);
-
- if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
- rb_raise(rb_eRactorError, "#freeze does not freeze object correctly");
- }
-
- if (RB_OBJ_SHAREABLE_P(obj)) {
- return traverse_skip;
+ case T_OBJECT:
+ {
+ // If a T_OBJECT is shared and has no free capacity, we can't safely store the object_id inline,
+ // as it would require to move the object content into an external buffer.
+ // This is only a problem for T_OBJECT, given other types have external fields and can do RCU.
+ // To avoid this issue, we proactively create the object_id.
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
+ attr_index_t free_capacity = capacity - RSHAPE_LEN(shape_id);
+ if (!rb_shape_has_object_id(shape_id) && capacity && !free_capacity) {
+ rb_obj_id(obj);
+ }
}
+ break;
+ default:
+ break;
}
- return traverse_cont;
+ return make_shareable_check_shareable_freeze(obj, traverse_cont);
}
static enum obj_traverse_iterator_result
mark_shareable(VALUE obj)
{
- FL_SET_RAW(obj, RUBY_FL_SHAREABLE);
+ if (RB_TYPE_P(obj, T_STRING)) {
+ rb_str_make_independent(obj);
+ }
+
+ rb_obj_set_shareable_no_assert(obj);
return traverse_cont;
}
@@ -3319,11 +1762,9 @@ static int
obj_refer_only_shareables_p(VALUE obj)
{
int cnt = 0;
- RB_VM_LOCK_ENTER_NO_BARRIER();
- {
+ RB_VM_LOCKING_NO_BARRIER() {
rb_objspace_reachable_objects_from(obj, obj_refer_only_shareables_p_i, &cnt);
}
- RB_VM_LOCK_LEAVE_NO_BARRIER();
return cnt == 0;
}
@@ -3351,30 +1792,31 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
}
else {
st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, replacement);
+ RB_OBJ_WRITTEN(data->rec_hash, Qundef, obj);
+ RB_OBJ_WRITTEN(data->rec_hash, Qundef, replacement);
}
if (!data->move) {
obj = replacement;
}
-#define CHECK_AND_REPLACE(v) do { \
+#define CHECK_AND_REPLACE(parent_obj, v) do { \
VALUE _val = (v); \
if (obj_traverse_replace_i(_val, data)) { return 1; } \
- else if (data->replacement != _val) { RB_OBJ_WRITE(obj, &v, data->replacement); } \
+ else if (data->replacement != _val) { RB_OBJ_WRITE(parent_obj, &v, data->replacement); } \
} while (0)
- if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
- struct gen_ivtbl *ivtbl;
- rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
+ if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
+ VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
- if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
+ if (UNLIKELY(rb_obj_shape_complex_p(obj))) {
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
- .src = obj,
+ .src = fields_obj,
};
rb_st_foreach_with_replace(
- ivtbl->as.complex.table,
+ rb_imemo_fields_complex_tbl(fields_obj),
obj_iv_hash_traverse_replace_foreach_i,
obj_iv_hash_traverse_replace_i,
(st_data_t)&d
@@ -3382,10 +1824,10 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
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]);
- }
+ uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ VALUE *fields = rb_imemo_fields_ptr(fields_obj);
+ for (uint32_t i = 0; i < fields_count; i++) {
+ CHECK_AND_REPLACE(fields_obj, fields[i]);
}
}
}
@@ -3397,7 +1839,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_REGEXP:
case T_FILE:
case T_SYMBOL:
- case T_MATCH:
break;
case T_STRING:
rb_str_make_independent(obj);
@@ -3405,14 +1846,14 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_OBJECT:
{
- if (rb_shape_obj_too_complex(obj)) {
+ if (rb_obj_shape_complex_p(obj)) {
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
.src = obj,
};
rb_st_foreach_with_replace(
- ROBJECT_IV_HASH(obj),
+ ROBJECT_FIELDS_HASH(obj),
obj_iv_hash_traverse_replace_foreach_i,
obj_iv_hash_traverse_replace_i,
(st_data_t)&d
@@ -3420,11 +1861,11 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
if (d.stop) return 1;
}
else {
- uint32_t len = ROBJECT_IV_COUNT(obj);
- VALUE *ptr = ROBJECT_IVPTR(obj);
+ uint32_t len = ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
+ VALUE *ptr = ROBJECT_FIELDS(obj);
for (uint32_t i = 0; i < len; i++) {
- CHECK_AND_REPLACE(ptr[i]);
+ CHECK_AND_REPLACE(obj, ptr[i]);
}
}
}
@@ -3473,22 +1914,26 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_STRUCT:
{
- long len = RSTRUCT_LEN(obj);
+ long len = RSTRUCT_LEN_RAW(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
for (long i=0; i<len; i++) {
- CHECK_AND_REPLACE(ptr[i]);
+ CHECK_AND_REPLACE(obj, ptr[i]);
}
}
break;
+ case T_MATCH:
+ CHECK_AND_REPLACE(obj, RMATCH(obj)->str);
+ break;
+
case T_RATIONAL:
- CHECK_AND_REPLACE(RRATIONAL(obj)->num);
- CHECK_AND_REPLACE(RRATIONAL(obj)->den);
+ CHECK_AND_REPLACE(obj, RRATIONAL(obj)->num);
+ CHECK_AND_REPLACE(obj, RRATIONAL(obj)->den);
break;
case T_COMPLEX:
- CHECK_AND_REPLACE(RCOMPLEX(obj)->real);
- CHECK_AND_REPLACE(RCOMPLEX(obj)->imag);
+ CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->real);
+ CHECK_AND_REPLACE(obj, RCOMPLEX(obj)->imag);
break;
case T_DATA:
@@ -3547,6 +1992,19 @@ rb_obj_traverse_replace(VALUE obj,
}
}
+static const bool wb_protected_types[RUBY_T_MASK] = {
+ [T_OBJECT] = true,
+ [T_HASH] = true,
+ [T_ARRAY] = true,
+ [T_STRING] = true,
+ [T_STRUCT] = true,
+ [T_COMPLEX] = true,
+ [T_REGEXP] = true,
+ [T_MATCH] = true,
+ [T_FLOAT] = true,
+ [T_RATIONAL] = true,
+};
+
static enum obj_traverse_iterator_result
move_enter(VALUE obj, struct obj_traverse_replace_data *data)
{
@@ -3555,7 +2013,11 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
return traverse_skip;
}
else {
- data->replacement = rb_obj_clone(obj);
+ VALUE type = RB_BUILTIN_TYPE(obj);
+ size_t slot_size = rb_gc_obj_slot_size(obj);
+ VALUE moved = rb_newobj(GET_EC(), 0, type, RBASIC_SHAPE_ID(obj), wb_protected_types[type], slot_size);
+ MEMZERO(((struct RBasic *)moved) + 1, char, slot_size - sizeof(struct RBasic));
+ data->replacement = (VALUE)moved;
return traverse_cont;
}
}
@@ -3563,7 +2025,31 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
static enum obj_traverse_iterator_result
move_leave(VALUE obj, struct obj_traverse_replace_data *data)
{
- rb_gc_ractor_moved(data->replacement, obj);
+ // Copy flags
+ VALUE ignored_flags = RUBY_FL_PROMOTED;
+ RBASIC(data->replacement)->flags = (RBASIC(obj)->flags & ~ignored_flags) | (RBASIC(data->replacement)->flags & ignored_flags);
+ // Copy contents without the flags
+ memcpy(
+ (char *)data->replacement + sizeof(VALUE),
+ (char *)obj + sizeof(VALUE),
+ rb_gc_obj_slot_size(obj) - sizeof(VALUE)
+ );
+
+ // We've copied obj's references to the replacement
+ rb_gc_writebarrier_remember(data->replacement);
+
+ void rb_replace_generic_ivar(VALUE clone, VALUE obj); // variable.c
+ if (UNLIKELY(rb_obj_gen_fields_p(obj))) {
+ rb_replace_generic_ivar(data->replacement, obj);
+ }
+
+ rb_gc_obj_id_moved(data->replacement);
+
+ VALUE flags = T_OBJECT | FL_FREEZE | (RBASIC(obj)->flags & FL_PROMOTED);
+
+ // Avoid mutations using bind_call, etc.
+ MEMZERO((char *)obj, char, sizeof(struct RBasic));
+ RBASIC(obj)->flags = flags;
RBASIC_SET_CLASS_RAW(obj, rb_cRactorMovedObject);
return traverse_cont;
}
@@ -3580,6 +2066,31 @@ ractor_move(VALUE obj)
}
}
+static VALUE
+ractor_call_clone_try(VALUE obj)
+{
+ return rb_funcall(obj, idClone, 0);
+}
+
+static VALUE
+ractor_call_clone_rescue(VALUE obj, VALUE exc)
+{
+ rb_raise(rb_eRactorError, "can't clone unshareable instance of %"PRIsVALUE, rb_class_of(obj));
+ UNREACHABLE_RETURN(Qnil);
+}
+
+static VALUE
+ractor_obj_clone(VALUE obj)
+{
+ VALUE clone = rb_rescue(ractor_call_clone_try, obj, ractor_call_clone_rescue, obj);
+
+ if (obj == clone) {
+ rb_raise(rb_eRactorError, "#clone returned self");
+ }
+
+ return clone;
+}
+
static enum obj_traverse_iterator_result
copy_enter(VALUE obj, struct obj_traverse_replace_data *data)
{
@@ -3588,7 +2099,7 @@ copy_enter(VALUE obj, struct obj_traverse_replace_data *data)
return traverse_skip;
}
else {
- data->replacement = rb_obj_clone(obj);
+ data->replacement = ractor_obj_clone(obj);
return traverse_cont;
}
}
@@ -3722,15 +2233,13 @@ rb_ractor_local_storage_value_newkey(void)
void
rb_ractor_local_storage_delkey(rb_ractor_local_key_t key)
{
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) {
freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4;
- REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, freed_ractor_local_keys.capa);
+ SIZED_REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt);
}
freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key;
}
- RB_VM_LOCK_LEAVE();
}
static bool
@@ -3826,12 +2335,12 @@ void
rb_ractor_finish_marking(void)
{
for (int i=0; i<freed_ractor_local_keys.cnt; i++) {
- ruby_xfree(freed_ractor_local_keys.keys[i]);
+ SIZED_FREE(freed_ractor_local_keys.keys[i]);
}
freed_ractor_local_keys.cnt = 0;
if (freed_ractor_local_keys.capa > DEFAULT_KEYS_CAPA) {
freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA;
- REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, DEFAULT_KEYS_CAPA);
+ SIZED_REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa);
}
}
@@ -3915,241 +2424,226 @@ ractor_local_value_store_if_absent(rb_execution_context_t *ec, VALUE self, VALUE
return rb_mutex_synchronize(cr->local_storage_store_lock, ractor_local_value_store_i, (VALUE)&data);
}
-// Ractor::Channel (emulate with Ractor)
-
-typedef rb_ractor_t rb_ractor_channel_t;
+// shareable_proc
static VALUE
-ractor_channel_func(RB_BLOCK_CALL_FUNC_ARGLIST(y, c))
+ractor_shareable_proc(rb_execution_context_t *ec, VALUE replace_self, bool is_lambda)
{
- rb_execution_context_t *ec = GET_EC();
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
-
- while (1) {
- int state;
-
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- VALUE obj = ractor_receive(ec, cr);
- ractor_yield(ec, cr, obj, Qfalse);
- }
- EC_POP_TAG();
-
- if (state) {
- // ignore the error
- break;
- }
+ if (!rb_ractor_shareable_p(replace_self)) {
+ rb_raise(rb_eRactorIsolationError, "self should be shareable: %" PRIsVALUE, replace_self);
+ }
+ else {
+ VALUE proc = is_lambda ? rb_block_lambda() : rb_block_proc();
+ return rb_proc_ractor_make_shareable(rb_proc_dup(proc), replace_self);
}
-
- return Qnil;
-}
-
-static VALUE
-rb_ractor_channel_new(void)
-{
-#if 0
- return rb_funcall(rb_const_get(rb_cRactor, rb_intern("Channel")), rb_intern("new"), 0);
-#else
- // class Channel
- // def self.new
- // Ractor.new do # func body
- // while true
- // obj = Ractor.receive
- // Ractor.yield obj
- // end
- // rescue Ractor::ClosedError
- // nil
- // end
- // end
- // end
-
- return ractor_create_func(rb_cRactor, Qnil, rb_str_new2("Ractor/channel"), rb_ary_new(), ractor_channel_func);
-#endif
-}
-
-static VALUE
-rb_ractor_channel_yield(rb_execution_context_t *ec, VALUE vch, VALUE obj)
-{
- VM_ASSERT(ec == rb_current_ec_noinline());
- rb_ractor_channel_t *ch = RACTOR_PTR(vch);
-
- ractor_send(ec, (rb_ractor_t *)ch, obj, Qfalse);
- return Qnil;
}
-static VALUE
-rb_ractor_channel_take(rb_execution_context_t *ec, VALUE vch)
-{
- VM_ASSERT(ec == rb_current_ec_noinline());
- rb_ractor_channel_t *ch = RACTOR_PTR(vch);
-
- return ractor_take(ec, (rb_ractor_t *)ch);
-}
+// Ractor#require
-static VALUE
-rb_ractor_channel_close(rb_execution_context_t *ec, VALUE vch)
-{
- VM_ASSERT(ec == rb_current_ec_noinline());
- rb_ractor_channel_t *ch = RACTOR_PTR(vch);
+struct cross_ractor_require {
+ VALUE port;
+ bool raised;
- ractor_close_incoming(ec, (rb_ractor_t *)ch);
- return ractor_close_outgoing(ec, (rb_ractor_t *)ch);
-}
+ union {
+ struct {
+ VALUE feature;
+ } require;
-// Ractor#require
+ struct {
+ VALUE module;
+ ID name;
+ } autoload;
+ } as;
-struct cross_ractor_require {
- VALUE ch;
- VALUE result;
- VALUE exception;
+ bool silent;
+};
- // require
- VALUE feature;
+RUBY_REFERENCES(cross_ractor_require_refs) = {
+ RUBY_REF_EDGE(struct cross_ractor_require, port),
+ RUBY_REF_EDGE(struct cross_ractor_require, as.require.feature),
+ RUBY_REF_END
+};
- // autoload
- VALUE module;
- ID name;
+static const rb_data_type_t cross_ractor_require_data_type = {
+ "ractor/cross_ractor_require",
+ {
+ RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
+ RUBY_DEFAULT_FREE,
+ NULL, // memsize
+ NULL, // compact
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
};
static VALUE
-require_body(VALUE data)
+require_body(VALUE crr_obj)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
+ struct cross_ractor_require *crr;
+ TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ VALUE feature = crr->as.require.feature;
ID require;
CONST_ID(require, "require");
- crr->result = rb_funcallv(Qnil, require, 1, &crr->feature);
- return Qnil;
+ if (crr->silent) {
+ int rb_require_internal_silent(VALUE fname);
+ return INT2NUM(rb_require_internal_silent(feature));
+ }
+ else {
+ return rb_funcallv(Qnil, require, 1, &feature);
+ }
}
static VALUE
-require_rescue(VALUE data, VALUE errinfo)
+require_rescue(VALUE crr_obj, VALUE errinfo)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
- crr->exception = errinfo;
- return Qundef;
+ struct cross_ractor_require *crr;
+ TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ crr->raised = true;
+ return errinfo;
}
static VALUE
-require_result_copy_body(VALUE data)
+require_result_send_body(VALUE ary)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
+ VALUE port = RARRAY_AREF(ary, 0);
+ VALUE results = RARRAY_AREF(ary, 1);
- if (crr->exception != Qundef) {
- VM_ASSERT(crr->result == Qundef);
- crr->exception = ractor_copy(crr->exception);
- }
- else{
- VM_ASSERT(crr->result != Qundef);
- crr->result = ractor_copy(crr->result);
- }
+ rb_execution_context_t *ec = GET_EC();
+ ractor_port_send(ec, port, results, Qfalse);
return Qnil;
}
static VALUE
-require_result_copy_resuce(VALUE data, VALUE errinfo)
+require_result_send_resuce(VALUE port, VALUE errinfo)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
- crr->exception = errinfo; // ractor_move(crr->exception);
+ // TODO: need rescue?
+ ractor_port_send(GET_EC(), port, errinfo, Qfalse);
return Qnil;
}
static VALUE
-ractor_require_protect(struct cross_ractor_require *crr, VALUE (*func)(VALUE))
+ractor_require_protect(VALUE crr_obj, VALUE (*func)(VALUE))
{
- // catch any error
- rb_rescue2(func, (VALUE)crr,
- require_rescue, (VALUE)crr, rb_eException, 0);
+ struct cross_ractor_require *crr;
+ TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
- rb_rescue2(require_result_copy_body, (VALUE)crr,
- require_result_copy_resuce, (VALUE)crr, rb_eException, 0);
+ const bool silent = crr->silent;
- rb_ractor_channel_yield(GET_EC(), crr->ch, Qtrue);
- return Qnil;
+ VALUE debug, errinfo;
+ if (silent) {
+ debug = ruby_debug;
+ errinfo = rb_errinfo();
+ }
+
+ // get normal result or raised exception (with crr->raised == true)
+ VALUE result = rb_rescue2(func, crr_obj, require_rescue, crr_obj, rb_eException, 0);
+
+ if (silent) {
+ ruby_debug = debug;
+ rb_set_errinfo(errinfo);
+ }
+
+ rb_rescue2(require_result_send_body,
+ // [port, [result, raised]]
+ rb_ary_new_from_args(2, crr->port, rb_ary_new_from_args(2, result, crr->raised ? Qtrue : Qfalse)),
+ require_result_send_resuce, rb_eException, crr->port);
+ RB_GC_GUARD(crr_obj);
+ return Qnil;
}
static VALUE
-ractore_require_func(void *data)
+ractor_require_func(void *crr_obj)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
- return ractor_require_protect(crr, require_body);
+ return ractor_require_protect((VALUE)crr_obj, require_body);
}
VALUE
-rb_ractor_require(VALUE feature)
-{
- // TODO: make feature shareable
- struct cross_ractor_require crr = {
- .feature = feature, // TODO: ractor
- .ch = rb_ractor_channel_new(),
- .result = Qundef,
- .exception = Qundef,
- };
+rb_ractor_require(VALUE feature, bool silent)
+{
+ // We're about to block on the main ractor, so if we're holding the global lock we'll deadlock.
+ ASSERT_vm_unlocking();
+
+ struct cross_ractor_require *crr;
+ VALUE crr_obj = TypedData_Make_Struct(0, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ RB_OBJ_SET_SHAREABLE(crr_obj); // TODO: internal data?
+
+ // Convert feature to proper file path and make it shareable as fstring
+ RB_OBJ_WRITE(crr_obj, &crr->as.require.feature, rb_fstring(FilePathValue(feature)));
+ RB_OBJ_WRITE(crr_obj, &crr->port, rb_ractor_make_shareable(ractor_port_new(GET_RACTOR())));
+ crr->raised = false;
+ crr->silent = silent;
rb_execution_context_t *ec = GET_EC();
rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
- rb_ractor_interrupt_exec(main_r, ractore_require_func, &crr, 0);
+ rb_ractor_interrupt_exec(main_r, ractor_require_func, (void *)crr_obj, rb_interrupt_exec_flag_value_data);
// wait for require done
- rb_ractor_channel_take(ec, crr.ch);
- rb_ractor_channel_close(ec, crr.ch);
+ VALUE results = ractor_port_receive(ec, crr->port);
+ ractor_port_close(ec, crr->port);
+
+ VALUE exc = rb_ary_pop(results);
+ VALUE result = rb_ary_pop(results);
+ RB_GC_GUARD(crr_obj);
- if (crr.exception != Qundef) {
- rb_exc_raise(crr.exception);
+ if (RTEST(exc)) {
+ rb_exc_raise(result);
}
else {
- return crr.result;
+ return result;
}
}
static VALUE
ractor_require(rb_execution_context_t *ec, VALUE self, VALUE feature)
{
- return rb_ractor_require(feature);
+ return rb_ractor_require(feature, false);
}
static VALUE
-autoload_load_body(VALUE data)
+autoload_load_body(VALUE crr_obj)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
- crr->result = rb_autoload_load(crr->module, crr->name);
- return Qnil;
+ struct cross_ractor_require *crr;
+ TypedData_Get_Struct(crr_obj, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ return rb_autoload_load(crr->as.autoload.module, crr->as.autoload.name);
}
static VALUE
-ractor_autoload_load_func(void *data)
+ractor_autoload_load_func(void *crr_obj)
{
- struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
- return ractor_require_protect(crr, autoload_load_body);
+ return ractor_require_protect((VALUE)crr_obj, autoload_load_body);
}
VALUE
rb_ractor_autoload_load(VALUE module, ID name)
{
- struct cross_ractor_require crr = {
- .module = module,
- .name = name,
- .ch = rb_ractor_channel_new(),
- .result = Qundef,
- .exception = Qundef,
- };
+ struct cross_ractor_require *crr;
+ VALUE crr_obj = TypedData_Make_Struct(0, struct cross_ractor_require, &cross_ractor_require_data_type, crr);
+ RB_OBJ_SET_SHAREABLE(crr_obj); // TODO: internal data?
+
+ RB_OBJ_WRITE(crr_obj, &crr->as.autoload.module, module);
+ RB_OBJ_WRITE(crr_obj, &crr->as.autoload.name, name);
+ RB_OBJ_WRITE(crr_obj, &crr->port, rb_ractor_make_shareable(ractor_port_new(GET_RACTOR())));
rb_execution_context_t *ec = GET_EC();
rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
- rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, &crr, 0);
+ rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, (void *)crr_obj, rb_interrupt_exec_flag_value_data);
// wait for require done
- rb_ractor_channel_take(ec, crr.ch);
- rb_ractor_channel_close(ec, crr.ch);
+ VALUE results = ractor_port_receive(ec, crr->port);
+ ractor_port_close(ec, crr->port);
+
+ VALUE exc = rb_ary_pop(results);
+ VALUE result = rb_ary_pop(results);
+ RB_GC_GUARD(crr_obj);
- if (crr.exception != Qundef) {
- rb_exc_raise(crr.exception);
+ if (RTEST(exc)) {
+ rb_exc_raise(result);
}
else {
- return crr.result;
+ return result;
}
}
diff --git a/ractor.rb b/ractor.rb
index caeca88644..2dc60f5ff6 100644
--- a/ractor.rb
+++ b/ractor.rb
@@ -1,99 +1,54 @@
-# \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 creates a new \Ractor, which can run in parallel with other ractors.
#
# # The simplest ractor
# r = Ractor.new {puts "I am in Ractor!"}
-# r.take # wait for it to finish
+# r.join # wait for it to finish
# # Here, "I am in Ractor!" is 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.
#
# 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
+# Unlike in threads, ractors can't access all the objects available in other ractors. For example, objects normally
# available through variables in the outer scope are prohibited from being used across ractors.
#
# 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).)
+# # Ractor::IsolationError (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.
+# On CRuby (the default implementation), the Global Virtual Machine Lock (GVL) is held per ractor, so
+# ractors can run in parallel. This is unlike the situation with threads on CRuby.
#
# Instead of accessing shared state, objects should be passed to and from ractors by
# sending and receiving them 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 the Thread until our default port gets sent a message
# puts "I am in Ractor! a=#{a_in_ractor}"
# end
# r.send(a) # pass it
-# r.take
+# r.join
# # Here, "I am in Ractor! a=1" is 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
-# ractor as if sent by Ractor.yield.
-#
-# A little demonstration of a classic ping-pong:
-#
-# server = Ractor.new(name: "server") 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
-# received = Ractor.receive # The server doesn't know the sender and receives from whoever sent
-# puts "Server received: #{received}"
-# end
-#
-# client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv
-# puts "Client starts: #{self.inspect}"
-# received = srv.take # The client takes a message 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
-# end
-#
-# [client, server].each(&:take) # Wait until they both finish
-#
-# This will output something like:
-#
-# Server starts: #<Ractor:#2 server 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
-# Server received: pong
-#
-# Ractors receive their messages via the <em>incoming port</em>, and send 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
-# automatically.
+# as if received by Ractor.receive, and the last block value can be received with Ractor#value.
#
# == Shareable and unshareable objects
#
-# When an object is sent to and from a ractor, it's important to understand whether the
+# When an object is sent to 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.
#
-# Shareable objects are those which can be used by several threads without compromising
+# Shareable objects are those which can be used by several ractors at once 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
+# 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.
#
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
@@ -109,24 +64,24 @@
# 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
+# When a shareable object is sent via #send, no additional processing occurs
+# on it and it becomes usable by both ractors. When an unshareable object is sent, it can be
+# either _copied_ or _moved_. Copying is the default, and it copies the object fully by
# deep cloning (Object#clone) the non-shareable parts of its structure.
#
-# data = ['foo', 'bar'.freeze]
+# data = ['foo'.dup, 'bar'.freeze]
# r = Ractor.new do
# data2 = Ractor.receive
# puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
# end
# r.send(data)
-# r.take
+# r.join
# puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
#
# This will output something like:
#
-# In ractor: 340, 360, 320
-# Outside : 380, 400, 320
+# In ractor: 8, 16, 24
+# Outside : 32, 40, 24
#
# 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
@@ -142,7 +97,7 @@
# puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
# end
# r.send(data, move: true)
-# r.take
+# r.join
# puts "Outside: moved? #{Ractor::MovedObject === data}"
# puts "Outside: #{data.inspect}"
#
@@ -152,12 +107,12 @@
# Outside: moved? true
# test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
#
-# Notice that even +inspect+ (and more basic methods like <tt>__id__</tt>) is inaccessible
+# Notice that even +inspect+ and more basic methods like <tt>__id__</tt> are 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
-# will be kept. We can not define mutable shareable objects in Ruby, but C extensions can introduce them.
+# +Class+ and +Module+ objects are shareable and their class/module definitions are shared between ractors.
+# \Ractor objects are also shareable. All operations on shareable objects are thread-safe across ractors.
+# Defining mutable, shareable objects in Ruby is not possible, 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
@@ -177,7 +132,7 @@
# puts "I can't see #{cls.tricky}"
# cls.tricky = true # doesn't get here, but this would also raise an error
# end
-# r.take
+# r.join
# # I see C
# # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
#
@@ -191,7 +146,7 @@
# puts "GOOD=#{GOOD}"
# puts "BAD=#{BAD}"
# end
-# r.take
+# r.join
# # GOOD=good
# # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
#
@@ -201,7 +156,7 @@
# puts "I see #{C}"
# puts "I can't see #{C.tricky}"
# end
-# r.take
+# r.join
# # I see C
# # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
#
@@ -217,20 +172,21 @@
# a = 1
# Thread.new {puts "Thread in ractor: a=#{a}"}.join
# end
-# r.take
+# r.join
# # Here "Thread in ractor: a=1" will be printed
#
# == 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 the examples below, sometimes we use the following method to wait for ractors
+# to make progress or finish.
#
# 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.
+# This is **only for demonstration purposes** and shouldn't be used in a real code.
+# Most of the time, #join is used to wait for ractors to finish and Ractor.receive is used
+# to wait for messages.
#
# == Reference
#
@@ -241,13 +197,13 @@ class Ractor
# call-seq:
# Ractor.new(*args, name: nil) {|*args| block } -> ractor
#
- # Create a new \Ractor with args and a block.
+ # Creates a new \Ractor with args and a block.
#
- # The given block (Proc) will be isolated (can't access any outer variables). +self+
+ # The given block (Proc) is isolated (can't access any outer variables). +self+
# inside the block will refer to the current \Ractor.
#
# r = Ractor.new { puts "Hi, I am #{self.inspect}" }
- # r.take
+ # r.join
# # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
#
# Any +args+ passed are propagated to the block arguments by the same rules as
@@ -259,14 +215,14 @@ class Ractor
# r = Ractor.new(arg) {|received_arg|
# puts "Received: #{received_arg} (##{received_arg.object_id})"
# }
- # r.take
+ # r.join
# # Prints:
# # Passing: [1, 2, 3] (#280)
# # Received: [1, 2, 3] (#300)
#
# Ractor's +name+ can be set for debugging purposes:
#
- # r = Ractor.new(name: 'my ractor') {}; r.take
+ # r = Ractor.new(name: 'my ractor') {}; r.join
# p r
# #=> #<Ractor:#3 my ractor test.rb:1 terminated>
#
@@ -274,8 +230,8 @@ class Ractor
b = block # TODO: builtin bug
raise ArgumentError, "must be called with a block" unless block
if __builtin_cexpr!("RBOOL(ruby_single_main_ractor)")
- warn("Ractor is experimental, and the behavior may change in future versions of Ruby! " \
- "Also there are many implementation issues.", uplevel: 0, category: :experimental)
+ Kernel.warn("Ractor API is experimental and may change in future versions of Ruby.",
+ uplevel: 0, category: :experimental)
end
loc = caller_locations(1, 1).first
loc = "#{loc.path}:#{loc.lineno}"
@@ -291,13 +247,13 @@ class Ractor
}
end
- # Returns the number of Ractors currently running or blocking (waiting).
+ # Returns the number of ractors currently running or blocking (waiting).
#
# Ractor.count #=> 1
- # r = Ractor.new(name: 'example') { Ractor.yield(1) }
+ # r = Ractor.new(name: 'example') { Ractor.receive }
# Ractor.count #=> 2 (main + example ractor)
- # r.take # wait for Ractor.yield(1)
- # r.take # wait until r will finish
+ # r << 42 # r's Ractor.receive will resume
+ # r.join # wait for r's termination
# Ractor.count #=> 1
def self.count
__builtin_cexpr! %q{
@@ -307,130 +263,91 @@ 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.
- #
- # r1 = Ractor.new {Ractor.yield 'from 1'}
- # r2 = Ractor.new {Ractor.yield 'from 2'}
- #
- # r, obj = Ractor.select(r1, r2)
- #
- # 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.
- #
- # r1 = Ractor.new(Ractor.current) do |main|
- # main.send 'to main'
- # Ractor.yield 'from 1'
- # end
- # r2 = Ractor.new do
- # Ractor.yield 'from 2'
+ # Ractor.select(*ractors_or_ports) -> [ractor or port, obj]
+ #
+ # Blocks the current Thread until one of the given ports has received a message. Returns an
+ # array of two elements where the first element is the Port and the second is the received object.
+ # This method can also accept Ractor objects themselves, and in that case will wait until one
+ # has terminated and return a two-element array where the first element is the ractor and the
+ # second is its termination value.
+ #
+ # p1, p2 = Ractor::Port.new, Ractor::Port.new
+ # ps = [p1, p2]
+ # rs = 2.times.map do |i|
+ # Ractor.new(ps.shift, i) do |p, i|
+ # sleep rand(0.99)
+ # p.send("r#{i}")
+ # sleep rand(0.99)
+ # "r#{i} done"
+ # end
# end
#
- # r, obj = Ractor.select(r1, r2, Ractor.current)
- # puts "received #{obj.inspect} from #{r.inspect}"
- # # Could print: 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:
- #
- # r1 = Ractor.new(Ractor.current) do |main|
- # puts "Received from main: #{main.take}"
+ # waiting_on = [p1, p2, *rs]
+ # until waiting_on.empty?
+ # received_on, obj = Ractor.select(*waiting_on)
+ # waiting_on.delete(received_on)
+ # puts obj
# end
#
- # puts "Trying to select"
- # r, obj = Ractor.select(r1, Ractor.current, yield_value: 123)
- # wait
- # puts "Received #{obj.inspect} from #{r.inspect}"
+ # # r0
+ # # r1
+ # # r1 done
+ # # r0 done
#
- # This will print:
+ # The following example is almost equivalent to <code>ractors.map(&:value)</code> except the thread
+ # is unblocked when any of the ractors has terminated as opposed to waiting for their termination in
+ # the array element order.
#
- # Trying to select
- # Received from main: 123
- # Received nil from :yield
+ # values = []
+ # until ractors.empty?
+ # r, val = Ractor.select(*ractors)
+ # ractors.delete(r)
+ # values << val
+ # end
#
- # +move+ boolean flag defines whether yielded value will 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
+ def self.select(*ports)
+ raise ArgumentError, 'specify at least one Ractor::Port or Ractor' if ports.empty?
+
+ monitors = {} # Ractor::Port => Ractor
+
+ ports = ports.map do |arg|
+ case arg
+ when Ractor
+ port = Ractor::Port.new
+ monitors[port] = arg
+ arg.monitor port
+ port
+ when Ractor::Port
+ arg
+ else
+ raise ArgumentError, "should be Ractor::Port or Ractor"
+ end
end
- __builtin_ractor_select_internal ractors, do_receive, !yield_unspecified, yield_value, move
+ begin
+ result_port, obj = __builtin_ractor_select_internal(ports)
+
+ if r = monitors[result_port]
+ [r, r.value]
+ else
+ [result_port, obj]
+ end
+ ensure
+ # close all ports for join
+ monitors.each do |port, r|
+ r.unmonitor port
+ port.close
+ end
+ end
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).
- #
- # r = Ractor.new do
- # v1 = Ractor.receive
- # puts "Received: #{v1}"
- # end
- # r.send('message1')
- # r.take
- # # Here will be printed: "Received: message1"
- #
- # Alternatively, the private instance method +receive+ may be used:
- #
- # r = Ractor.new do
- # v1 = receive
- # puts "Received: #{v1}"
- # end
- # r.send('message1')
- # r.take
- # # This prints: "Received: message1"
- #
- # The method blocks if the queue is empty.
- #
- # r = Ractor.new do
- # puts "Before first receive"
- # v1 = Ractor.receive
- # puts "Received: #{v1}"
- # v2 = Ractor.receive
- # puts "Received: #{v2}"
- # end
- # wait
- # puts "Still not received"
- # r.send('message1')
- # wait
- # puts "Still received only one"
- # r.send('message2')
- # r.take
- #
- # Output:
- #
- # Before first receive
- # Still not received
- # Received: message1
- # Still received only one
- # 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:
- #
- # Ractor.new do
- # close_incoming
- # receive
- # end
- # wait
- # # in `receive': The incoming port is already closed => #<Ractor:#2 test.rb:1 running> (Ractor::ClosedError)
+ # Ractor.receive -> obj
#
+ # Receives a message from the current ractor's default port.
def self.receive
- __builtin_cexpr! %q{
- ractor_receive(ec, rb_ec_ractor_ptr(ec))
- }
+ Ractor.current.default_port.receive
end
class << self
@@ -439,280 +356,21 @@ class Ractor
# same as Ractor.receive
private def receive
- __builtin_cexpr! %q{
- ractor_receive(ec, rb_ec_ractor_ptr(ec))
- }
+ default_port.receive
end
alias recv receive
#
# call-seq:
- # Ractor.receive_if {|msg| block } -> msg
- #
- # 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.
- #
- # r = Ractor.new do
- # p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
- # p Ractor.receive_if{|msg| msg.match?(/bar/)} #=> "bar1"
- # p Ractor.receive_if{|msg| msg.match?(/baz/)} #=> "baz2"
- # end
- # r << "bar1"
- # r << "baz2"
- # r << "foo3"
- # r.take
- #
- # This will output:
- #
- # foo3
- # bar1
- # baz2
+ # ractor.send(msg, move: false) -> self
#
- # If the block returns a truthy value, the message is 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.
- #
- # If there are no messages left in the incoming queue, the method will
- # block until new messages arrive.
- #
- # If the block is escaped by break/return/exception/throw, the message is removed from
- # the incoming queue as if a truthy value had been returned.
- #
- # r = Ractor.new do
- # val = Ractor.receive_if{|msg| msg.is_a?(Array)}
- # puts "Received successfully: #{val}"
- # end
- #
- # r.send(1)
- # r.send('test')
- # wait
- # puts "2 non-matching sent, nothing received"
- # r.send([1, 2, 3])
- # wait
- #
- # Prints:
- #
- # 2 non-matching sent, nothing received
- # 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.
- #
- # Ractor.current << true
- # Ractor.receive_if{|msg| Ractor.receive}
- # #=> `receive': can not call receive/receive_if recursively (Ractor::Error)
- #
- def self.receive_if &b
- Primitive.ractor_receive_if b
- end
-
- # same as Ractor.receive_if
- private def receive_if &b
- Primitive.ractor_receive_if b
- end
-
- #
- # call-seq:
- # ractor.send(msg, move: false) -> self
- #
- # Send a message to a Ractor's incoming queue to be accepted by Ractor.receive.
- #
- # r = Ractor.new do
- # value = Ractor.receive
- # puts "Received #{value}"
- # end
- # r.send 'message'
- # # Prints: "Received: message"
- #
- # The method is non-blocking (will return immediately even if the ractor is not ready
- # to receive anything):
- #
- # r = Ractor.new {sleep(5)}
- # r.send('test')
- # puts "Sent successfully"
- # # Prints: "Sent successfully" immediately
- #
- # An attempt to send to a ractor which already finished its execution will raise Ractor::ClosedError.
- #
- # r = Ractor.new {}
- # r.take
- # p r
- # # "#<Ractor:#6 (irb):23 terminated>"
- # r.send('test')
- # # Ractor::ClosedError (The incoming-port is already closed)
- #
- # If close_incoming was called on the ractor, the method also raises Ractor::ClosedError.
- #
- # r = Ractor.new do
- # sleep(500)
- # receive
- # end
- # 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
- #
- # 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.
- #
- # r = Ractor.new {puts "Received: #{receive}"}
- # msg = 'message'
- # r.send(msg, move: true)
- # r.take
- # p msg
- #
- # This prints:
- #
- # 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.
- #
- # r = Ractor.new {puts "Received: #{receive}"}
- # s = 'message'
- # ary = [s]
- # copy = ary.dup
- # r.send(ary, move: true)
- #
- # s.inspect
- # # Ractor::MovedError (can not send any methods to a moved object)
- # ary.class
- # # Ractor::MovedError (can not send any methods to a moved object)
- # copy.class
- # # => Array, it is different object
- # copy[0].inspect
- # # 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:
- #
- # r = Ractor.new {puts "Received: #{receive}"}
- # s = 'message'.freeze
- # r.send(s, move: true)
- # s.inspect #=> "message", still available
- #
- def send(obj, move: false)
- __builtin_cexpr! %q{
- ractor_send(ec, RACTOR_PTR(self), obj, move)
- }
+ # This is equivalent to Port#send to the ractor's #default_port.
+ def send(...)
+ default_port.send(...)
+ self
end
alias << send
- #
- # call-seq:
- # Ractor.yield(msg, move: false) -> nil
- #
- # Send a message to the current ractor's outgoing port to be accepted 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
- # sent message.
- #
- # r = Ractor.new do
- # Ractor.yield 'Hello from ractor'
- # puts "Ractor: after yield"
- # end
- # wait
- # puts "Still not taken"
- # puts r.take
- #
- # This will print:
- #
- # Still not taken
- # Hello from ractor
- # Ractor: after yield
- #
- # If the outgoing port was closed with #close_outgoing, the method will raise:
- #
- # r = Ractor.new do
- # close_outgoing
- # Ractor.yield 'Hello from ractor'
- # end
- # wait
- # # `yield': The outgoing-port is already closed (Ractor::ClosedError)
- #
- # The meaning of the +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)
- }
- end
-
- #
- # 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.
- #
- # r = Ractor.new do
- # Ractor.yield 'explicit yield'
- # 'last value'
- # end
- # puts r.take #=> 'explicit yield'
- # 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.
- #
- # If the outgoing port was closed with #close_outgoing, the method will raise Ractor::ClosedError.
- #
- # r = Ractor.new do
- # sleep(500)
- # Ractor.yield 'Hello from ractor'
- # end
- # r.close_outgoing
- # r.take
- # # 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
- # Ractor::RemoteError.
- #
- # r = Ractor.new {raise "Something weird happened"}
- #
- # begin
- # r.take
- # rescue => e
- # p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
- # p e.ractor == r # => true
- # 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:
- #
- # r = Ractor.new do
- # 3.times {|i| Ractor.yield "message #{i}"}
- # "finishing"
- # end
- #
- # loop {puts "Received: " + r.take}
- # puts "Continue successfully"
- #
- # This will print:
- #
- # Received: message 0
- # Received: message 1
- # Received: message 2
- # Received: finishing
- # Continue successfully
- def take
- __builtin_cexpr! %q{
- ractor_take(ec, RACTOR_PTR(self))
- }
- end
-
def inspect
loc = __builtin_cexpr! %q{ RACTOR_PTR(self)->loc }
name = __builtin_cexpr! %q{ RACTOR_PTR(self)->name }
@@ -725,50 +383,25 @@ class Ractor
alias to_s inspect
- # The name set in Ractor.new, or +nil+.
+ # Returns the name set in Ractor.new, or +nil+.
def name
__builtin_cexpr! %q{RACTOR_PTR(self)->name}
end
class RemoteError
- # The Ractor an uncaught exception is raised in.
+ # The Ractor in which the uncaught exception was raised.
attr_reader :ractor
end
#
# call-seq:
- # ractor.close_incoming -> true | false
+ # ractor.close -> 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 default port. Closing a port is allowed only by the ractor which created the port.
+ # Therefore, the receiver must be the current ractor.
#
- # r = Ractor.new {sleep(500)}
- # r.close_incoming #=> false
- # r.close_incoming #=> true
- # r.send('test')
- # # Ractor::ClosedError (The incoming-port is already closed)
- def close_incoming
- __builtin_cexpr! %q{
- ractor_close_incoming(ec, RACTOR_PTR(self));
- }
- end
-
- #
- # 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.
- #
- # r = Ractor.new {sleep(500)}
- # r.close_outgoing #=> false
- # r.close_outgoing #=> true
- # r.take
- # # Ractor::ClosedError (The outgoing-port is already closed)
- def close_outgoing
- __builtin_cexpr! %q{
- ractor_close_outgoing(ec, RACTOR_PTR(self));
- }
+ def close
+ default_port.close
end
#
@@ -777,7 +410,7 @@ class Ractor
#
# Checks if the object is shareable by ractors.
#
- # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
+ # Ractor.shareable?(1) #=> true -- numbers are shareable
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
# Ractor.shareable?('foo'.freeze) #=> true
#
@@ -792,7 +425,7 @@ class Ractor
# call-seq:
# Ractor.make_shareable(obj, copy: false) -> shareable_obj
#
- # Make +obj+ shareable between ractors.
+ # Makes +obj+ shareable between ractors.
#
# +obj+ and all the objects it refers to will be frozen, unless they are
# already shareable.
@@ -835,24 +468,30 @@ class Ractor
end
end
- # get a value from ractor-local storage of current Ractor
- # Obsolete and use Ractor.[] instead.
+ # Gets a value from ractor-local storage for the current Ractor.
+ # Obsolete, use Ractor.[] instead.
def [](sym)
+ if (self != Ractor.current)
+ raise RuntimeError, "Cannot get ractor local storage for non-current ractor"
+ end
Primitive.ractor_local_value(sym)
end
- # set a value in ractor-local storage of current Ractor
- # Obsolete and use Ractor.[]= instead.
+ # Sets a value in ractor-local storage for the current Ractor.
+ # Obsolete, use Ractor.[]= instead.
def []=(sym, val)
+ if (self != Ractor.current)
+ raise RuntimeError, "Cannot set ractor local storage for non-current ractor"
+ end
Primitive.ractor_local_value_set(sym, val)
end
- # get a value from ractor-local storage of current Ractor
+ # Gets a value from ractor-local storage for the current Ractor.
def self.[](sym)
Primitive.ractor_local_value(sym)
end
- # set a value in ractor-local storage of current Ractor
+ # Sets a value in ractor-local storage for the current Ractor.
def self.[]=(sym, val)
Primitive.ractor_local_value_set(sym, val)
end
@@ -860,9 +499,9 @@ class Ractor
# call-seq:
# Ractor.store_if_absent(key){ init_block }
#
- # If the corresponding value is not set, yield a value with
- # init_block and store the value in thread-safe manner.
- # This method returns corresponding stored value.
+ # If the corresponding ractor-local value is not set, yields a value with
+ # init_block and stores the value in a thread-safe manner.
+ # This method returns the stored value.
#
# (1..10).map{
# Thread.new(it){|i|
@@ -872,17 +511,18 @@ class Ractor
# }.map(&:value).uniq.size #=> 1 and f() is called only once
#
def self.store_if_absent(sym)
+ Primitive.attr! :use_block
Primitive.ractor_local_value_store_if_absent(sym)
end
- # returns main ractor
+ # Returns the main ractor.
def self.main
__builtin_cexpr! %q{
rb_ractor_self(GET_VM()->ractor.main_ractor);
}
end
- # return true if the current ractor is main ractor
+ # Returns true if the current ractor is the main ractor.
def self.main?
__builtin_cexpr! %q{
RBOOL(GET_VM()->ractor.main_ractor == rb_ec_ractor_ptr(ec))
@@ -916,4 +556,279 @@ class Ractor
}
end
end
+
+ #
+ # call-seq:
+ # ractor.default_port -> port object
+ #
+ # Returns the default port of the Ractor.
+ #
+ def default_port
+ __builtin_cexpr! %q{
+ ractor_default_port_value(RACTOR_PTR(self))
+ }
+ end
+
+ #
+ # call-seq:
+ # ractor.join -> self
+ #
+ # Waits for the termination of the Ractor.
+ # If the Ractor was aborted (terminated by an unhandled exception),
+ # the exception is raised in the current ractor.
+ #
+ # Ractor.new{}.join #=> ractor
+ #
+ # Ractor.new{ raise "foo" }.join
+ # #=> raises the exception "foo (RuntimeError)"
+ #
+ def join
+ port = Port.new
+
+ self.monitor port
+ if port.receive == :aborted
+ __builtin_ractor_value
+ end
+
+ self
+ ensure
+ port.close
+ end
+
+ #
+ # call-seq:
+ # ractor.value -> obj
+ #
+ # Waits for +ractor+ to complete and returns its value or raises the exception
+ # which terminated the Ractor. The termination value will be moved to the calling
+ # Ractor. Therefore, at most 1 Ractor can receive another ractor's termination value.
+ #
+ # r = Ractor.new{ [1, 2] }
+ # r.value #=> [1, 2] (unshareable object)
+ #
+ # Ractor.new(r){|r| r.value} #=> Ractor::Error
+ #
+ def value
+ self.join
+ __builtin_ractor_value
+ end
+
+ #
+ # call-seq:
+ # ractor.monitor(port) -> self
+ #
+ # Registers the port as a monitoring port for this ractor. When the ractor terminates,
+ # the port receives a Symbol object.
+ #
+ # * +:exited+ is sent if the ractor terminates without an unhandled exception.
+ # * +:aborted+ is sent if the ractor terminates by an unhandled exception.
+ #
+ # r = Ractor.new{ some_task() }
+ # r.monitor(port = Ractor::Port.new)
+ # port.receive #=> :exited and r is terminated
+ #
+ # r = Ractor.new{ raise "foo" }
+ # r.monitor(port = Ractor::Port.new)
+ # port.receive #=> :aborted and r is terminated by the RuntimeError "foo"
+ #
+ def monitor port
+ __builtin_ractor_monitor(port)
+ end
+
+ #
+ # call-seq:
+ # ractor.unmonitor(port) -> self
+ #
+ # Unregisters the port from the monitoring ports for this ractor.
+ #
+ def unmonitor port
+ __builtin_ractor_unmonitor(port)
+ end
+
+ #
+ # call-seq:
+ # Ractor.shareable_proc(self: nil){} -> shareable proc
+ #
+ # Returns a shareable copy of the given block's Proc. The value of +self+
+ # in the Proc will be replaced with the value passed via the `self:` keyword,
+ # or +nil+ if not given.
+ #
+ # In a shareable Proc, access to any outer variables is prohibited.
+ #
+ # a = 42
+ # Ractor.shareable_proc{ p a }
+ # #=> can not isolate a Proc because it accesses outer variables (a). (Ractor::IsolationError)
+ #
+ # The value of `self` in the Proc must be a shareable object.
+ #
+ # Ractor.shareable_proc(self: self){}
+ # #=> self should be shareable: main (Ractor::IsolationError)
+ #
+ def self.shareable_proc self: nil
+ Primitive.attr! :use_block
+
+ __builtin_cexpr!(%Q{
+ ractor_shareable_proc(ec, *LOCAL_PTR(self), false)
+ })
+ end
+
+ #
+ # call-seq:
+ # Ractor.shareable_lambda(self: nil){} -> shareable lambda
+ #
+ # Same as Ractor.shareable_proc, but returns a lambda Proc.
+ #
+ def self.shareable_lambda self: nil
+ Primitive.attr! :use_block
+
+ __builtin_cexpr!(%Q{
+ ractor_shareable_proc(ec, *LOCAL_PTR(self), true)
+ })
+ end
+
+ # \Port objects transmit messages between Ractors.
+ class Port
+ #
+ # call-seq:
+ # port.receive -> msg
+ #
+ # Receives a message from the port (which was sent there by Port#send). Only the ractor
+ # that created the port can receive messages this way.
+ #
+ # port = Ractor::Port.new
+ # r = Ractor.new port do |port|
+ # port.send('message1')
+ # end
+ #
+ # v1 = port.receive
+ # puts "Received: #{v1}"
+ # r.join
+ # # This will print: "Received: message1"
+ #
+ # The method blocks the current Thread if the message queue is empty.
+ #
+ # port = Ractor::Port.new
+ # r = Ractor.new port do |port|
+ # wait
+ # puts "Still not received"
+ # port.send('message1')
+ # wait
+ # puts "Still received only one"
+ # port.send('message2')
+ # end
+ # puts "Before first receive"
+ # v1 = port.receive
+ # puts "Received: #{v1}"
+ # v2 = port.receive
+ # puts "Received: #{v2}"
+ # r.join
+ #
+ # Output:
+ #
+ # Before first receive
+ # Still not received
+ # Received: message1
+ # Still received only one
+ # Received: message2
+ #
+ # If the port is closed and there are no more messages in the message queue,
+ # the method raises Ractor::ClosedError.
+ #
+ # port = Ractor::Port.new
+ # port.close
+ # port.receive #=> raise Ractor::ClosedError
+ #
+ def receive
+ __builtin_cexpr! %q{
+ ractor_port_receive(ec, self)
+ }
+ end
+
+ #
+ # call-seq:
+ # port.send(msg, move: false) -> self
+ #
+ # Sends a message to the port to be accepted by port.receive.
+ #
+ # port = Ractor::Port.new
+ # r = Ractor.new(port) do |port|
+ # port.send 'message'
+ # end
+ # value = port.receive
+ # puts "Received #{value}"
+ # # Prints: "Received: message"
+ #
+ # The method is non-blocking (it will return immediately even if the ractor that created the port is not ready
+ # to receive anything):
+ #
+ # port = Ractor::Port.new
+ # r = Ractor.new(port) do |port|
+ # port.send 'test'
+ # puts "Sent successfully"
+ # # Prints: "Sent successfully" immediately
+ # end
+ #
+ # An attempt to send to a closed port will raise Ractor::ClosedError.
+ #
+ # r = Ractor.new {Ractor::Port.new}
+ # r.join
+ # p r
+ # # "#<Ractor:#6 (irb):23 terminated>"
+ # port = r.value
+ # port.send('test') # raise Ractor::ClosedError
+ #
+ # If the +obj+ is unshareable, by default it will be copied into the receiving ractor by deep cloning.
+ #
+ # If the object is shareable, a reference to the object will be sent to the receiving ractor.
+ #
+ def send obj, move: false
+ __builtin_cexpr! %q{
+ ractor_port_send(ec, self, obj, move)
+ }
+ end
+
+ alias << send
+
+ #
+ # call-seq:
+ # port.close
+ #
+ # Closes the port. Sending to a closed port is prohibited.
+ # Receiving is also prohibited if there are no messages in its message queue.
+ #
+ # Only the Ractor which created the port is allowed to close it.
+ #
+ # port = Ractor::Port.new
+ # Ractor.new port do |port|
+ # port.close #=> closing port by other ractors is not allowed (Ractor::Error)
+ # end.join
+ #
+ def close
+ __builtin_cexpr! %q{
+ ractor_port_close(ec, self)
+ }
+ end
+
+ #
+ # call-seq:
+ # port.closed? -> true/false
+ #
+ # Returns whether or not the port is closed.
+ def closed?
+ __builtin_cexpr! %q{
+ ractor_port_closed_p(ec, self);
+ }
+ end
+
+ #
+ # call-seq:
+ # port.inspect -> string
+ def inspect
+ "#<Ractor::Port to:\##{
+ __builtin_cexpr! "SIZET2NUM(rb_ractor_id((RACTOR_PORT_PTR(self)->r)))"
+ } id:#{
+ __builtin_cexpr! "SIZET2NUM(ractor_port_id(RACTOR_PORT_PTR(self)))"
+ }>"
+ end
+ end
end
diff --git a/ractor_core.h b/ractor_core.h
index 1e860edb4b..c692ebbbbf 100644
--- a/ractor_core.h
+++ b/ractor_core.h
@@ -9,122 +9,39 @@
#define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
#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;
- 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;
- int cnt;
- int size;
- unsigned int serial;
- unsigned int reserved_cnt;
-};
-
-enum rb_ractor_wait_status {
- wait_none = 0x00,
- wait_receiving = 0x01,
- wait_taking = 0x02,
- wait_yielding = 0x04,
- wait_moving = 0x08,
-};
-
-enum rb_ractor_wakeup_status {
- wakeup_none,
- wakeup_by_send,
- wakeup_by_yield,
- wakeup_by_take,
- wakeup_by_close,
- wakeup_by_interrupt,
- wakeup_by_retry,
-};
+// experimental flag because it is not sure it is the common pattern
+#define RUBY_TYPED_FROZEN_SHAREABLE_NO_REC RUBY_FL_FINALIZE
struct rb_ractor_sync {
// ractor lock
rb_nativethread_lock_t lock;
+
#if RACTOR_CHECK_MODE > 0
VALUE locked_by;
#endif
- bool incoming_port_closed;
- bool outgoing_port_closed;
+#ifndef RUBY_THREAD_PTHREAD_H
+ rb_nativethread_cond_t wakeup_cond;
+#endif
- // All sent messages will be pushed into recv_queue
- struct rb_ractor_queue recv_queue;
+ // incoming messages
+ struct ractor_queue *recv_queue;
- // The following ractors waiting for the yielding by this ractor
- struct rb_ractor_queue takers_queue;
+ // waiting threads for receiving
+ struct ccan_list_head waiters;
- // Enabled if the ractor already terminated and not taken yet.
- struct rb_ractor_basket will_basket;
+ // ports
+ VALUE default_port_value;
+ struct st_table *ports;
+ size_t next_port_id;
- struct ractor_wait {
- enum rb_ractor_wait_status status;
- enum rb_ractor_wakeup_status wakeup_status;
- rb_thread_t *waiting_thread;
- } wait;
+ // monitors
+ struct ccan_list_head monitors;
-#ifndef RUBY_THREAD_PTHREAD_H
- rb_nativethread_cond_t cond;
-#endif
+ // value
+ rb_ractor_t *successor;
+ VALUE legacy;
+ bool legacy_exc;
};
// created
@@ -150,12 +67,7 @@ enum ractor_status {
struct rb_ractor_struct {
struct rb_ractor_pub pub;
-
struct rb_ractor_sync sync;
- VALUE receiving_mutex;
-
- // vm wide barrier synchronization
- rb_nativethread_cond_t barrier_wait_cond;
// thread management
struct {
@@ -167,6 +79,7 @@ struct rb_ractor_struct {
rb_execution_context_t *running_ec;
rb_thread_t *main;
} threads;
+
VALUE thgroup_default;
VALUE name;
@@ -178,6 +91,8 @@ struct rb_ractor_struct {
// ractor local data
+ rb_serial_t next_ec_serial;
+
st_table *local_storage;
struct rb_id_table *idkey_local_storage;
VALUE local_storage_store_lock;
@@ -188,9 +103,24 @@ struct rb_ractor_struct {
VALUE verbose;
VALUE debug;
+ bool malloc_gc_disabled;
+ bool main_ractor;
void *newobj_cache;
}; // rb_ractor_t is defined in vm_core.h
+enum ractor_wakeup_status {
+ wakeup_none,
+ wakeup_by_send,
+ wakeup_by_interrupt,
+ // wakeup_by_close,
+};
+
+struct ractor_waiter {
+ enum ractor_wakeup_status wakeup_status;
+ rb_thread_t *th;
+ struct ccan_list_node node;
+ rb_atomic_t event_serial;
+};
static inline VALUE
rb_ractor_self(const rb_ractor_t *r)
@@ -223,10 +153,12 @@ void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
void rb_ractor_terminate_all(void);
bool rb_ractor_main_p_(void);
void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
-VALUE rb_ractor_require(VALUE feature);
+void rb_ractor_terminate_atfork(rb_vm_t *vm, rb_ractor_t *th);
+VALUE rb_ractor_require(VALUE feature, bool silent);
VALUE rb_ractor_autoload_load(VALUE space, ID id);
VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
+st_table *rb_ractor_targeted_hooks(rb_ractor_t *cr);
RUBY_SYMBOL_EXPORT_BEGIN
void rb_ractor_finish_marking(void);
@@ -281,12 +213,16 @@ rb_ractor_sleeper_thread_num(rb_ractor_t *r)
}
static inline void
-rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th)
+rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th, bool always_reset)
{
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 || always_reset) {
+ th->running_time_us = 0;
+ }
+
if (cr->threads.running_ec != th->ec) {
if (0) {
ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
@@ -297,10 +233,6 @@ rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th)
return;
}
- if (cr->threads.running_ec != th->ec) {
- th->running_time_us = 0;
- }
-
cr->threads.running_ec = th->ec;
VM_ASSERT(cr == GET_RACTOR());
@@ -333,6 +265,25 @@ rb_ractor_id(const rb_ractor_t *r)
return r->pub.id;
}
+static inline void
+rb_ractor_targeted_hooks_incr(rb_ractor_t *cr)
+{
+ cr->pub.targeted_hooks_cnt++;
+}
+
+static inline void
+rb_ractor_targeted_hooks_decr(rb_ractor_t *cr)
+{
+ RUBY_ASSERT(cr->pub.targeted_hooks_cnt > 0);
+ cr->pub.targeted_hooks_cnt--;
+}
+
+static inline unsigned int
+rb_ractor_targeted_hooks_cnt(rb_ractor_t *cr)
+{
+ return cr->pub.targeted_hooks_cnt;
+}
+
#if RACTOR_CHECK_MODE > 0
# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj)))
@@ -355,9 +306,13 @@ rb_ractor_belonging(VALUE obj)
}
}
+extern bool rb_ractor_ignore_belonging_flag;
+
static inline VALUE
rb_ractor_confirm_belonging(VALUE obj)
{
+ if (rb_ractor_ignore_belonging_flag) return obj;
+
uint32_t id = rb_ractor_belonging(obj);
if (id == 0) {
@@ -377,6 +332,14 @@ rb_ractor_confirm_belonging(VALUE obj)
}
return obj;
}
+
+static inline void
+rb_ractor_ignore_belonging(bool flag)
+{
+ rb_ractor_ignore_belonging_flag = flag;
+}
+
#else
#define rb_ractor_confirm_belonging(obj) obj
+#define rb_ractor_ignore_belonging(flag) (0)
#endif
diff --git a/ractor_sync.c b/ractor_sync.c
new file mode 100644
index 0000000000..44c84ded92
--- /dev/null
+++ b/ractor_sync.c
@@ -0,0 +1,1489 @@
+// this file is included by ractor.c
+
+struct ractor_port {
+ rb_ractor_t *r;
+ st_data_t id_;
+};
+
+static st_data_t
+ractor_port_id(const struct ractor_port *rp)
+{
+ return rp->id_;
+}
+
+static VALUE rb_cRactorPort;
+
+static VALUE ractor_receive(rb_execution_context_t *ec, const struct ractor_port *rp);
+static VALUE ractor_send(rb_execution_context_t *ec, const struct ractor_port *rp, VALUE obj, VALUE move);
+static VALUE ractor_try_send(rb_execution_context_t *ec, const struct ractor_port *rp, VALUE obj, VALUE move);
+static void ractor_add_port(rb_ractor_t *r, st_data_t id);
+
+static void
+ractor_port_mark(void *ptr)
+{
+ const struct ractor_port *rp = (struct ractor_port *)ptr;
+
+ if (rp->r) {
+ rb_gc_mark(rp->r->pub.self);
+ }
+}
+
+static const rb_data_type_t ractor_port_data_type = {
+ "ractor/port",
+ {
+ ractor_port_mark,
+ RUBY_TYPED_DEFAULT_FREE,
+ NULL, // memsize
+ NULL, // update
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
+};
+
+static st_data_t
+ractor_genid_for_port(rb_ractor_t *cr)
+{
+ // TODO: enough?
+ return cr->sync.next_port_id++;
+}
+
+static struct ractor_port *
+RACTOR_PORT_PTR(VALUE self)
+{
+ VM_ASSERT(rb_typeddata_is_kind_of(self, &ractor_port_data_type));
+ return RTYPEDDATA_GET_DATA(self);
+}
+
+static VALUE
+ractor_port_alloc(VALUE klass)
+{
+ struct ractor_port *rp;
+ VALUE rpv = TypedData_Make_Struct(klass, struct ractor_port, &ractor_port_data_type, rp);
+ rb_obj_freeze(rpv);
+ return rpv;
+}
+
+static VALUE
+ractor_port_init(VALUE rpv, rb_ractor_t *r)
+{
+ struct ractor_port *rp = RACTOR_PORT_PTR(rpv);
+
+ rp->r = r;
+ RB_OBJ_WRITTEN(rpv, Qundef, r->pub.self);
+ rp->id_ = ractor_genid_for_port(r);
+
+ ractor_add_port(r, ractor_port_id(rp));
+
+ rb_obj_freeze(rpv);
+
+ return rpv;
+}
+
+/*
+ * call-seq:
+ * Ractor::Port.new -> new_port
+ *
+ * Returns a new Ractor::Port object.
+ */
+static VALUE
+ractor_port_initialize(VALUE self)
+{
+ return ractor_port_init(self, GET_RACTOR());
+}
+
+/* :nodoc: */
+static VALUE
+ractor_port_initialize_copy(VALUE self, VALUE orig)
+{
+ struct ractor_port *dst = RACTOR_PORT_PTR(self);
+ struct ractor_port *src = RACTOR_PORT_PTR(orig);
+ dst->r = src->r;
+ RB_OBJ_WRITTEN(self, Qundef, dst->r->pub.self);
+ dst->id_ = ractor_port_id(src);
+
+ return self;
+}
+
+static VALUE
+ractor_port_new(rb_ractor_t *r)
+{
+ VALUE rpv = ractor_port_alloc(rb_cRactorPort);
+ ractor_port_init(rpv, r);
+ return rpv;
+}
+
+static bool
+ractor_port_p(VALUE self)
+{
+ return rb_typeddata_is_kind_of(self, &ractor_port_data_type);
+}
+
+static VALUE
+ractor_port_receive(rb_execution_context_t *ec, VALUE self)
+{
+ const struct ractor_port *rp = RACTOR_PORT_PTR(self);
+
+ if (rp->r != rb_ec_ractor_ptr(ec)) {
+ rb_raise(rb_eRactorError, "only allowed from the creator Ractor of this port");
+ }
+
+ return ractor_receive(ec, rp);
+}
+
+static VALUE
+ractor_port_send(rb_execution_context_t *ec, VALUE self, VALUE obj, VALUE move)
+{
+ const struct ractor_port *rp = RACTOR_PORT_PTR(self);
+ ractor_send(ec, rp, obj, RTEST(move));
+ return self;
+}
+
+static bool ractor_closed_port_p(rb_execution_context_t *ec, rb_ractor_t *r, const struct ractor_port *rp);
+static bool ractor_close_port(rb_execution_context_t *ec, rb_ractor_t *r, const struct ractor_port *rp);
+
+static VALUE
+ractor_port_closed_p(rb_execution_context_t *ec, VALUE self)
+{
+ const struct ractor_port *rp = RACTOR_PORT_PTR(self);
+
+ if (ractor_closed_port_p(ec, rp->r, rp)) {
+ return Qtrue;
+ }
+ else {
+ return Qfalse;
+ }
+}
+
+static VALUE
+ractor_port_close(rb_execution_context_t *ec, VALUE self)
+{
+ const struct ractor_port *rp = RACTOR_PORT_PTR(self);
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+
+ if (cr != rp->r) {
+ rb_raise(rb_eRactorError, "closing port by other ractors is not allowed");
+ }
+
+ ractor_close_port(ec, cr, rp);
+ return self;
+}
+
+// ractor-internal
+
+// ractor-internal - ractor_basket
+
+enum ractor_basket_type {
+ // basket is empty
+ basket_type_none,
+
+ // value is available
+ basket_type_ref,
+ basket_type_copy,
+ basket_type_move,
+};
+
+struct ractor_basket {
+ enum ractor_basket_type type;
+ VALUE sender;
+ st_data_t port_id;
+
+ struct {
+ VALUE v;
+ bool exception;
+ } p; // payload
+
+ struct ccan_list_node node;
+};
+
+#if 0
+static inline bool
+ractor_basket_type_p(const struct ractor_basket *b, enum ractor_basket_type type)
+{
+ return b->type == type;
+}
+
+static inline bool
+ractor_basket_none_p(const struct ractor_basket *b)
+{
+ return ractor_basket_type_p(b, basket_type_none);
+}
+#endif
+
+static void
+ractor_basket_mark(const struct ractor_basket *b)
+{
+ rb_gc_mark(b->p.v);
+}
+
+static void
+ractor_basket_free(struct ractor_basket *b)
+{
+ SIZED_FREE(b);
+}
+
+static struct ractor_basket *
+ractor_basket_alloc(void)
+{
+ struct ractor_basket *b = ALLOC(struct ractor_basket);
+ return b;
+}
+
+// ractor-internal - ractor_queue
+
+struct ractor_queue {
+ struct ccan_list_head set;
+ bool closed;
+};
+
+static void
+ractor_queue_init(struct ractor_queue *rq)
+{
+ ccan_list_head_init(&rq->set);
+ rq->closed = false;
+}
+
+static struct ractor_queue *
+ractor_queue_new(void)
+{
+ struct ractor_queue *rq = ALLOC(struct ractor_queue);
+ ractor_queue_init(rq);
+ return rq;
+}
+
+static void
+ractor_queue_mark(const struct ractor_queue *rq)
+{
+ const struct ractor_basket *b;
+
+ ccan_list_for_each(&rq->set, b, node) {
+ ractor_basket_mark(b);
+ }
+}
+
+static void
+ractor_queue_free(struct ractor_queue *rq)
+{
+ struct ractor_basket *b, *nxt;
+
+ ccan_list_for_each_safe(&rq->set, b, nxt, node) {
+ ccan_list_del_init(&b->node);
+ ractor_basket_free(b);
+ }
+
+ VM_ASSERT(ccan_list_empty(&rq->set));
+
+ SIZED_FREE(rq);
+}
+
+RBIMPL_ATTR_MAYBE_UNUSED()
+static size_t
+ractor_queue_size(const struct ractor_queue *rq)
+{
+ size_t size = 0;
+ const struct ractor_basket *b;
+
+ ccan_list_for_each(&rq->set, b, node) {
+ size++;
+ }
+ return size;
+}
+
+static void
+ractor_queue_close(struct ractor_queue *rq)
+{
+ rq->closed = true;
+}
+
+static void
+ractor_queue_move(struct ractor_queue *dst_rq, struct ractor_queue *src_rq)
+{
+ struct ccan_list_head *src = &src_rq->set;
+ struct ccan_list_head *dst = &dst_rq->set;
+
+ dst->n.next = src->n.next;
+ dst->n.prev = src->n.prev;
+ dst->n.next->prev = &dst->n;
+ dst->n.prev->next = &dst->n;
+ ccan_list_head_init(src);
+}
+
+#if 0
+static struct ractor_basket *
+ractor_queue_head(rb_ractor_t *r, struct ractor_queue *rq)
+{
+ return ccan_list_top(&rq->set, struct ractor_basket, node);
+}
+#endif
+
+static bool
+ractor_queue_empty_p(rb_ractor_t *r, const struct ractor_queue *rq)
+{
+ return ccan_list_empty(&rq->set);
+}
+
+static struct ractor_basket *
+ractor_queue_deq(rb_ractor_t *r, struct ractor_queue *rq)
+{
+ VM_ASSERT(GET_RACTOR() == r);
+
+ return ccan_list_pop(&rq->set, struct ractor_basket, node);
+}
+
+static void
+ractor_queue_enq(rb_ractor_t *r, struct ractor_queue *rq, struct ractor_basket *basket)
+{
+ ccan_list_add_tail(&rq->set, &basket->node);
+}
+
+#if 0
+static void
+rq_dump(const struct ractor_queue *rq)
+{
+ int i=0;
+ struct ractor_basket *b;
+ ccan_list_for_each(&rq->set, b, node) {
+ fprintf(stderr, "%d type:%s %p\n", i, basket_type_name(b->type), (void *)b);
+ i++;
+ }
+}
+#endif
+
+static void ractor_delete_port(rb_ractor_t *cr, st_data_t id, bool locked);
+
+static struct ractor_queue *
+ractor_get_queue(rb_ractor_t *cr, st_data_t id, bool locked)
+{
+ VM_ASSERT(cr == GET_RACTOR());
+
+ struct ractor_queue *rq;
+
+ if (cr->sync.ports && st_lookup(cr->sync.ports, id, (st_data_t *)&rq)) {
+ if (rq->closed && ractor_queue_empty_p(cr, rq)) {
+ ractor_delete_port(cr, id, locked);
+ return NULL;
+ }
+ else {
+ return rq;
+ }
+ }
+ else {
+ return NULL;
+ }
+}
+
+// ractor-internal - ports
+
+static void
+ractor_add_port(rb_ractor_t *r, st_data_t id)
+{
+ struct ractor_queue *rq = ractor_queue_new();
+ ASSERT_ractor_unlocking(r);
+
+ RUBY_DEBUG_LOG("id:%u", (unsigned int)id);
+
+ RACTOR_LOCK(r);
+ {
+ st_insert(r->sync.ports, id, (st_data_t)rq);
+ }
+ RACTOR_UNLOCK(r);
+}
+
+static void
+ractor_delete_port_locked(rb_ractor_t *cr, st_data_t id)
+{
+ ASSERT_ractor_locking(cr);
+
+ RUBY_DEBUG_LOG("id:%u", (unsigned int)id);
+
+ struct ractor_queue *rq;
+
+ if (st_delete(cr->sync.ports, &id, (st_data_t *)&rq)) {
+ ractor_queue_free(rq);
+ }
+ else {
+ VM_ASSERT(0);
+ }
+}
+
+static void
+ractor_delete_port(rb_ractor_t *cr, st_data_t id, bool locked)
+{
+ if (locked) {
+ ractor_delete_port_locked(cr, id);
+ }
+ else {
+ RACTOR_LOCK_SELF(cr);
+ {
+ ractor_delete_port_locked(cr, id);
+ }
+ RACTOR_UNLOCK_SELF(cr);
+ }
+}
+
+static const struct ractor_port *
+ractor_default_port(rb_ractor_t *r)
+{
+ return RACTOR_PORT_PTR(r->sync.default_port_value);
+}
+
+static VALUE
+ractor_default_port_value(rb_ractor_t *r)
+{
+ return r->sync.default_port_value;
+}
+
+static bool
+ractor_closed_port_p(rb_execution_context_t *ec, rb_ractor_t *r, const struct ractor_port *rp)
+{
+ VM_ASSERT(rb_ec_ractor_ptr(ec) == rp->r ? 1 : (ASSERT_ractor_locking(rp->r), 1));
+
+ const struct ractor_queue *rq;
+
+ if (rp->r->sync.ports && st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
+ return rq->closed;
+ }
+ else {
+ return true;
+ }
+}
+
+static void ractor_deliver_incoming_messages(rb_execution_context_t *ec, rb_ractor_t *cr);
+static bool ractor_queue_empty_p(rb_ractor_t *r, const struct ractor_queue *rq);
+
+static bool
+ractor_close_port(rb_execution_context_t *ec, rb_ractor_t *cr, const struct ractor_port *rp)
+{
+ VM_ASSERT(cr == rp->r);
+ struct ractor_queue *rq = NULL;
+
+ RACTOR_LOCK_SELF(cr);
+ {
+ ractor_deliver_incoming_messages(ec, cr); // check incoming messages
+
+ if (st_lookup(rp->r->sync.ports, ractor_port_id(rp), (st_data_t *)&rq)) {
+ ractor_queue_close(rq);
+
+ if (ractor_queue_empty_p(cr, rq)) {
+ // delete from the table
+ ractor_delete_port(cr, ractor_port_id(rp), true);
+ }
+
+ // TODO: free rq
+ }
+ }
+ RACTOR_UNLOCK_SELF(cr);
+
+ return rq != NULL;
+}
+
+static int
+ractor_free_all_ports_i(st_data_t port_id, st_data_t val, st_data_t dat)
+{
+ struct ractor_queue *rq = (struct ractor_queue *)val;
+ // rb_ractor_t *cr = (rb_ractor_t *)dat;
+
+ ractor_queue_free(rq);
+ return ST_CONTINUE;
+}
+
+static void
+ractor_free_all_ports(rb_ractor_t *cr)
+{
+ if (cr->sync.ports) {
+ st_foreach(cr->sync.ports, ractor_free_all_ports_i, (st_data_t)cr);
+ st_free_table(cr->sync.ports);
+ cr->sync.ports = NULL;
+ }
+
+ if (cr->sync.recv_queue) {
+ ractor_queue_free(cr->sync.recv_queue);
+ cr->sync.recv_queue = NULL;
+ }
+}
+
+#if defined(HAVE_WORKING_FORK)
+static void
+ractor_sync_terminate_atfork(rb_vm_t *vm, rb_ractor_t *r)
+{
+ ractor_free_all_ports(r);
+ r->sync.legacy = Qnil;
+}
+#endif
+
+// Ractor#monitor
+
+struct ractor_monitor {
+ struct ractor_port port;
+ struct ccan_list_node node;
+};
+
+static void
+ractor_mark_monitors(rb_ractor_t *r)
+{
+ const struct ractor_monitor *rm;
+ ccan_list_for_each(&r->sync.monitors, rm, node) {
+ rb_gc_mark(rm->port.r->pub.self);
+ }
+}
+
+static VALUE
+ractor_exit_token(bool exc)
+{
+ if (exc) {
+ RUBY_DEBUG_LOG("aborted");
+ return ID2SYM(idAborted);
+ }
+ else {
+ RUBY_DEBUG_LOG("exited");
+ return ID2SYM(idExited);
+ }
+}
+
+static VALUE
+ractor_monitor(rb_execution_context_t *ec, VALUE self, VALUE port)
+{
+ rb_ractor_t *r = RACTOR_PTR(self);
+ bool terminated = false;
+ const struct ractor_port *rp = RACTOR_PORT_PTR(port);
+ struct ractor_monitor *rm = ALLOC(struct ractor_monitor);
+ rm->port = *rp; // copy port information
+
+ RACTOR_LOCK(r);
+ {
+ if (UNDEF_P(r->sync.legacy)) { // not terminated
+ RUBY_DEBUG_LOG("OK/r:%u -> port:%u@r%u", (unsigned int)rb_ractor_id(r), (unsigned int)ractor_port_id(&rm->port), (unsigned int)rb_ractor_id(rm->port.r));
+ ccan_list_add_tail(&r->sync.monitors, &rm->node);
+ }
+ else {
+ RUBY_DEBUG_LOG("NG/r:%u -> port:%u@r%u", (unsigned int)rb_ractor_id(r), (unsigned int)ractor_port_id(&rm->port), (unsigned int)rb_ractor_id(rm->port.r));
+ terminated = true;
+ }
+ }
+ RACTOR_UNLOCK(r);
+
+ if (terminated) {
+ SIZED_FREE(rm);
+ ractor_port_send(ec, port, ractor_exit_token(r->sync.legacy_exc), Qfalse);
+
+ return Qfalse;
+ }
+ else {
+ return Qtrue;
+ }
+}
+
+static VALUE
+ractor_unmonitor(rb_execution_context_t *ec, VALUE self, VALUE port)
+{
+ rb_ractor_t *r = RACTOR_PTR(self);
+ const struct ractor_port *rp = RACTOR_PORT_PTR(port);
+
+ RACTOR_LOCK(r);
+ {
+ if (UNDEF_P(r->sync.legacy)) { // not terminated
+ struct ractor_monitor *rm, *nxt;
+
+ ccan_list_for_each_safe(&r->sync.monitors, rm, nxt, node) {
+ if (ractor_port_id(&rm->port) == ractor_port_id(rp)) {
+ RUBY_DEBUG_LOG("r:%u -> port:%u@r%u",
+ (unsigned int)rb_ractor_id(r),
+ (unsigned int)ractor_port_id(&rm->port),
+ (unsigned int)rb_ractor_id(rm->port.r));
+ ccan_list_del(&rm->node);
+ SIZED_FREE(rm);
+ }
+ }
+ }
+ }
+ RACTOR_UNLOCK(r);
+
+ return self;
+}
+
+static void
+ractor_notify_exit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE legacy, bool exc)
+{
+ RUBY_DEBUG_LOG("exc:%d", exc);
+ VM_ASSERT(!UNDEF_P(legacy));
+ VM_ASSERT(cr->sync.legacy == Qundef);
+
+ RACTOR_LOCK_SELF(cr);
+ {
+ ractor_free_all_ports(cr);
+
+ cr->sync.legacy = legacy;
+ cr->sync.legacy_exc = exc;
+ }
+ RACTOR_UNLOCK_SELF(cr);
+
+ // send token
+
+ VALUE token = ractor_exit_token(exc);
+ struct ractor_monitor *rm, *nxt;
+
+ ccan_list_for_each_safe(&cr->sync.monitors, rm, nxt, node)
+ {
+ RUBY_DEBUG_LOG("port:%u@r%u", (unsigned int)ractor_port_id(&rm->port), (unsigned int)rb_ractor_id(rm->port.r));
+
+ ractor_try_send(ec, &rm->port, token, false);
+
+ ccan_list_del(&rm->node);
+ SIZED_FREE(rm);
+ }
+
+ VM_ASSERT(ccan_list_empty(&cr->sync.monitors));
+}
+
+// ractor-internal - initialize, mark, free, memsize
+
+static int
+ractor_mark_ports_i(st_data_t key, st_data_t val, st_data_t data)
+{
+ // id -> ractor_queue
+ const struct ractor_queue *rq = (struct ractor_queue *)val;
+ ractor_queue_mark(rq);
+ return ST_CONTINUE;
+}
+
+static void
+ractor_sync_mark(rb_ractor_t *r)
+{
+ rb_gc_mark(r->sync.default_port_value);
+
+ if (r->sync.ports) {
+ ractor_queue_mark(r->sync.recv_queue);
+ st_foreach(r->sync.ports, ractor_mark_ports_i, 0);
+ }
+
+ ractor_mark_monitors(r);
+}
+
+static int
+ractor_sync_free_ports_i(st_data_t _key, st_data_t val, st_data_t _args)
+{
+ struct ractor_queue *queue = (struct ractor_queue *)val;
+
+ ractor_queue_free(queue);
+
+ return ST_CONTINUE;
+}
+
+static void
+ractor_sync_free(rb_ractor_t *r)
+{
+ if (r->sync.recv_queue) {
+ ractor_queue_free(r->sync.recv_queue);
+ }
+
+ // maybe NULL
+ if (r->sync.ports) {
+ st_foreach(r->sync.ports, ractor_sync_free_ports_i, 0);
+ st_free_table(r->sync.ports);
+ r->sync.ports = NULL;
+ }
+}
+
+static size_t
+ractor_sync_memsize(const rb_ractor_t *r)
+{
+ if (r->sync.ports) {
+ return st_table_size(r->sync.ports);
+ }
+ else {
+ return 0;
+ }
+}
+
+static void
+ractor_sync_init(rb_ractor_t *r)
+{
+ // lock
+ rb_native_mutex_initialize(&r->sync.lock);
+
+ // monitors
+ ccan_list_head_init(&r->sync.monitors);
+
+ // waiters
+ ccan_list_head_init(&r->sync.waiters);
+
+ // receiving queue
+ r->sync.recv_queue = ractor_queue_new();
+
+ // ports
+ r->sync.ports = st_init_numtable();
+ r->sync.default_port_value = ractor_port_new(r);
+ FL_SET_RAW(r->sync.default_port_value, RUBY_FL_SHAREABLE); // only default ports are shareable
+
+ // legacy
+ r->sync.legacy = Qundef;
+
+#ifndef RUBY_THREAD_PTHREAD_H
+ rb_native_cond_initialize(&r->sync.wakeup_cond);
+#endif
+}
+
+// Ractor#value
+
+static rb_ractor_t *
+ractor_set_successor_once(rb_ractor_t *r, rb_ractor_t *cr)
+{
+ if (r->sync.successor == NULL) {
+ rb_ractor_t *successor = ATOMIC_PTR_CAS(r->sync.successor, NULL, cr);
+ return successor == NULL ? cr : successor;
+ }
+
+ return r->sync.successor;
+}
+
+static VALUE ractor_reset_belonging(VALUE obj);
+
+static VALUE
+ractor_make_remote_exception(VALUE cause, VALUE sender)
+{
+ VALUE err = rb_exc_new_cstr(rb_eRactorRemoteError, "thrown by remote Ractor.");
+ rb_ivar_set(err, rb_intern("@ractor"), sender);
+ rb_ec_setup_exception(NULL, err, cause);
+ return err;
+}
+
+static VALUE
+ractor_value(rb_execution_context_t *ec, VALUE self)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ rb_ractor_t *r = RACTOR_PTR(self);
+ rb_ractor_t *sr = ractor_set_successor_once(r, cr);
+
+ if (sr == cr) {
+ ractor_reset_belonging(r->sync.legacy);
+
+ if (r->sync.legacy_exc) {
+ rb_exc_raise(ractor_make_remote_exception(r->sync.legacy, self));
+ }
+ return r->sync.legacy;
+ }
+ else {
+ rb_raise(rb_eRactorError, "Only the successor ractor can take a value");
+ }
+}
+
+static VALUE ractor_move(VALUE obj); // in this file
+static VALUE ractor_copy(VALUE obj); // in this file
+
+static VALUE
+ractor_prepare_payload(rb_execution_context_t *ec, VALUE obj, enum ractor_basket_type *ptype)
+{
+ switch (*ptype) {
+ case basket_type_ref:
+ return obj;
+ case basket_type_move:
+ return ractor_move(obj);
+ default:
+ if (rb_ractor_shareable_p(obj)) {
+ *ptype = basket_type_ref;
+ return obj;
+ }
+ else {
+ *ptype = basket_type_copy;
+ return ractor_copy(obj);
+ }
+ }
+}
+
+static struct ractor_basket *
+ractor_basket_new(rb_execution_context_t *ec, VALUE obj, enum ractor_basket_type type, bool exc)
+{
+ VALUE v = ractor_prepare_payload(ec, obj, &type);
+
+ struct ractor_basket *b = ractor_basket_alloc();
+ b->type = type;
+ b->p.v = v;
+ b->p.exception = exc;
+ return b;
+}
+
+static VALUE
+ractor_basket_value(struct ractor_basket *b)
+{
+ switch (b->type) {
+ case basket_type_ref:
+ break;
+ case basket_type_copy:
+ case basket_type_move:
+ ractor_reset_belonging(b->p.v);
+ break;
+ default:
+ VM_ASSERT(0); // unreachable
+ }
+
+ VM_ASSERT(!RB_TYPE_P(b->p.v, T_NONE));
+ return b->p.v;
+}
+
+static VALUE
+ractor_basket_accept(struct ractor_basket *b)
+{
+ VALUE v = ractor_basket_value(b);
+
+ if (b->p.exception) {
+ VALUE err = ractor_make_remote_exception(v, b->sender);
+ ractor_basket_free(b);
+ rb_exc_raise(err);
+ }
+
+ ractor_basket_free(b);
+ return v;
+}
+
+// Ractor blocking by receive
+
+#if VM_CHECK_MODE > 0
+static bool
+ractor_waiter_included(rb_ractor_t *cr, rb_thread_t *th)
+{
+ ASSERT_ractor_locking(cr);
+
+ struct ractor_waiter *w;
+
+ ccan_list_for_each(&cr->sync.waiters, w, node) {
+ if (w->th == th) {
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+#if USE_RUBY_DEBUG_LOG
+
+static const char *
+wakeup_status_str(enum ractor_wakeup_status wakeup_status)
+{
+ switch (wakeup_status) {
+ case wakeup_none: return "none";
+ case wakeup_by_send: return "by_send";
+ case wakeup_by_interrupt: return "by_interrupt";
+ // case wakeup_by_close: return "by_close";
+ }
+ rb_bug("unreachable");
+}
+
+static const char *
+basket_type_name(enum 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";
+ }
+ VM_ASSERT(0);
+ return NULL;
+}
+
+#endif // USE_RUBY_DEBUG_LOG
+
+#ifdef RUBY_THREAD_PTHREAD_H
+
+//
+
+#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.wakeup_cond, &r->sync.lock);
+
+#if RACTOR_CHECK_MODE > 0
+ r->sync.locked_by = locked_by;
+#endif
+}
+
+static void *
+ractor_wait_no_gvl(void *ptr)
+{
+ struct ractor_waiter *waiter = (struct ractor_waiter *)ptr;
+ rb_ractor_t *cr = waiter->th->ractor;
+
+ RACTOR_LOCK_SELF(cr);
+ {
+ if (waiter->wakeup_status == wakeup_none) {
+ ractor_cond_wait(cr);
+ }
+ }
+ RACTOR_UNLOCK_SELF(cr);
+ return NULL;
+}
+
+static void
+rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf, void *ptr)
+{
+ struct ractor_waiter *waiter = (struct ractor_waiter *)ptr;
+
+ RACTOR_UNLOCK(cr);
+ {
+ rb_nogvl(ractor_wait_no_gvl, waiter,
+ ubf, waiter,
+ RB_NOGVL_UBF_ASYNC_SAFE | RB_NOGVL_INTR_FAIL);
+ }
+ RACTOR_LOCK(cr);
+}
+
+static void
+rb_ractor_sched_wakeup(rb_ractor_t *r, rb_thread_t *th)
+{
+ // ractor lock is acquired
+ rb_native_cond_broadcast(&r->sync.wakeup_cond);
+}
+#endif
+
+static bool
+ractor_wakeup_all(rb_ractor_t *r, enum ractor_wakeup_status wakeup_status)
+{
+ ASSERT_ractor_unlocking(r);
+
+ RUBY_DEBUG_LOG("r:%u wakeup:%s", rb_ractor_id(r), wakeup_status_str(wakeup_status));
+
+ bool wakeup_p = false;
+
+ RACTOR_LOCK(r);
+ while (1) {
+ struct ractor_waiter *waiter = ccan_list_pop(&r->sync.waiters, struct ractor_waiter, node);
+
+ if (waiter) {
+ VM_ASSERT(waiter->wakeup_status == wakeup_none);
+
+ waiter->wakeup_status = wakeup_status;
+ rb_ractor_sched_wakeup(r, waiter->th);
+
+ wakeup_p = true;
+ }
+ else {
+ break;
+ }
+ }
+ RACTOR_UNLOCK(r);
+
+ return wakeup_p;
+}
+
+static void
+ubf_ractor_wait(void *ptr)
+{
+ struct ractor_waiter *waiter = (struct ractor_waiter *)ptr;
+
+ rb_thread_t *th = waiter->th;
+ rb_ractor_t *r = th->ractor;
+ rb_atomic_t event_serial = waiter->event_serial;
+
+ // clear ubf and nobody can kick UBF
+ th->unblock.func = NULL;
+ th->unblock.arg = NULL;
+
+ rb_native_mutex_unlock(&th->interrupt_lock);
+ {
+ RACTOR_LOCK(r);
+ {
+ if (RUBY_ATOMIC_LOAD(th->unblock.event_serial) == event_serial && waiter->wakeup_status == wakeup_none) {
+ RUBY_DEBUG_LOG("waiter:%p", (void *)waiter);
+
+ waiter->wakeup_status = wakeup_by_interrupt;
+ ccan_list_del(&waiter->node);
+
+ rb_ractor_sched_wakeup(r, waiter->th);
+ }
+ }
+ RACTOR_UNLOCK(r);
+ }
+ rb_native_mutex_lock(&th->interrupt_lock);
+}
+
+static enum ractor_wakeup_status
+ractor_wait(rb_execution_context_t *ec, rb_ractor_t *cr)
+{
+ rb_thread_t *th = rb_ec_thread_ptr(ec);
+
+ struct ractor_waiter waiter = {
+ .wakeup_status = wakeup_none,
+ .th = th,
+ };
+
+ RUBY_DEBUG_LOG("wait%s", "");
+
+ ASSERT_ractor_locking(cr);
+
+ VM_ASSERT(GET_RACTOR() == cr);
+ VM_ASSERT(!ractor_waiter_included(cr, th));
+
+ ccan_list_add_tail(&cr->sync.waiters, &waiter.node);
+
+ // resume another ready thread and wait for an event
+ rb_ractor_sched_wait(ec, cr, ubf_ractor_wait, &waiter);
+
+ if (waiter.wakeup_status == wakeup_none) {
+ ccan_list_del(&waiter.node);
+ }
+
+ RUBY_DEBUG_LOG("wakeup_status:%s", wakeup_status_str(waiter.wakeup_status));
+
+ RACTOR_UNLOCK_SELF(cr);
+ {
+ rb_ec_check_ints(ec);
+ }
+ RACTOR_LOCK_SELF(cr);
+
+ VM_ASSERT(!ractor_waiter_included(cr, th));
+ return waiter.wakeup_status;
+}
+
+static void
+ractor_deliver_incoming_messages(rb_execution_context_t *ec, rb_ractor_t *cr)
+{
+ ASSERT_ractor_locking(cr);
+ struct ractor_queue *recv_q = cr->sync.recv_queue;
+
+ struct ractor_basket *b;
+ while ((b = ractor_queue_deq(cr, recv_q)) != NULL) {
+ ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id, true), b);
+ }
+}
+
+static bool
+ractor_check_received(rb_ractor_t *cr, struct ractor_queue *messages)
+{
+ struct ractor_queue *received_queue = cr->sync.recv_queue;
+ bool received = false;
+
+ ASSERT_ractor_locking(cr);
+
+ if (ractor_queue_empty_p(cr, received_queue)) {
+ RUBY_DEBUG_LOG("empty");
+ }
+ else {
+ received = true;
+
+ // messages <- incoming
+ ractor_queue_init(messages);
+ ractor_queue_move(messages, received_queue);
+ }
+
+ VM_ASSERT(ractor_queue_empty_p(cr, received_queue));
+
+ RUBY_DEBUG_LOG("received:%d", received);
+ return received;
+}
+
+static void
+ractor_wait_receive(rb_execution_context_t *ec, rb_ractor_t *cr)
+{
+ struct ractor_queue messages;
+ bool deliverred = false;
+
+ RACTOR_LOCK_SELF(cr);
+ {
+ if (ractor_check_received(cr, &messages)) {
+ deliverred = true;
+ }
+ else {
+ ractor_wait(ec, cr);
+ }
+ }
+ RACTOR_UNLOCK_SELF(cr);
+
+ if (deliverred) {
+ VM_ASSERT(!ractor_queue_empty_p(cr, &messages));
+ struct ractor_basket *b;
+
+ while ((b = ractor_queue_deq(cr, &messages)) != NULL) {
+ ractor_queue_enq(cr, ractor_get_queue(cr, b->port_id, false), b);
+ }
+ }
+}
+
+static VALUE
+ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *cr, const struct ractor_port *rp)
+{
+ struct ractor_queue *rq = ractor_get_queue(cr, ractor_port_id(rp), false);
+
+ if (rq == NULL) {
+ rb_raise(rb_eRactorClosedError, "The port was already closed");
+ }
+
+ struct ractor_basket *b = ractor_queue_deq(cr, rq);
+
+ if (rq->closed && ractor_queue_empty_p(cr, rq)) {
+ ractor_delete_port(cr, ractor_port_id(rp), false);
+ }
+
+ if (b) {
+ return ractor_basket_accept(b);
+ }
+ else {
+ return Qundef;
+ }
+}
+
+static VALUE
+ractor_receive(rb_execution_context_t *ec, const struct ractor_port *rp)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VM_ASSERT(cr == rp->r);
+
+ RUBY_DEBUG_LOG("port:%u", (unsigned int)ractor_port_id(rp));
+
+ while (1) {
+ VALUE v = ractor_try_receive(ec, cr, rp);
+
+ if (v != Qundef) {
+ return v;
+ }
+ else {
+ ractor_wait_receive(ec, cr);
+ }
+ }
+}
+
+// Ractor#send
+
+static void
+ractor_send_basket(rb_execution_context_t *ec, const struct ractor_port *rp, struct ractor_basket *b, bool raise_on_error)
+{
+ bool closed = false;
+
+ RUBY_DEBUG_LOG("port:%u@r%u b:%s v:%p", (unsigned int)ractor_port_id(rp), rb_ractor_id(rp->r), basket_type_name(b->type), (void *)b->p.v);
+
+ RACTOR_LOCK(rp->r);
+ {
+ if (ractor_closed_port_p(ec, rp->r, rp)) {
+ closed = true;
+ }
+ else {
+ b->port_id = ractor_port_id(rp);
+ ractor_queue_enq(rp->r, rp->r->sync.recv_queue, b);
+ }
+ }
+ RACTOR_UNLOCK(rp->r);
+
+ // NOTE: ref r -> b->p.v is created, but Ractor is unprotected object, so no problem on that.
+
+ if (!closed) {
+ ractor_wakeup_all(rp->r, wakeup_by_send);
+ }
+ else {
+ RUBY_DEBUG_LOG("closed:%u@r%u", (unsigned int)ractor_port_id(rp), rb_ractor_id(rp->r));
+
+ if (raise_on_error) {
+ ractor_basket_free(b);
+ rb_raise(rb_eRactorClosedError, "The port was already closed");
+ }
+ }
+}
+
+static VALUE
+ractor_send0(rb_execution_context_t *ec, const struct ractor_port *rp, VALUE obj, VALUE move, bool raise_on_error)
+{
+ struct ractor_basket *b = ractor_basket_new(ec, obj, RTEST(move) ? basket_type_move : basket_type_none, false);
+ ractor_send_basket(ec, rp, b, raise_on_error);
+ RB_GC_GUARD(obj);
+ return rp->r->pub.self;
+}
+
+static VALUE
+ractor_send(rb_execution_context_t *ec, const struct ractor_port *rp, VALUE obj, VALUE move)
+{
+ return ractor_send0(ec, rp, obj, move, true);
+}
+
+static VALUE
+ractor_try_send(rb_execution_context_t *ec, const struct ractor_port *rp, VALUE obj, VALUE move)
+{
+ return ractor_send0(ec, rp, obj, move, false);
+}
+
+// Ractor::Selector
+
+struct ractor_selector {
+ struct st_table *ports; // rpv -> rp
+
+};
+
+static int
+ractor_selector_mark_i(st_data_t key, st_data_t val, st_data_t dmy)
+{
+ rb_gc_mark((VALUE)key); // rpv
+
+ return ST_CONTINUE;
+}
+
+static void
+ractor_selector_mark(void *ptr)
+{
+ struct ractor_selector *s = ptr;
+
+ if (s->ports) {
+ st_foreach(s->ports, ractor_selector_mark_i, 0);
+ }
+}
+
+static void
+ractor_selector_free(void *ptr)
+{
+ struct ractor_selector *s = ptr;
+ st_free_table(s->ports);
+ SIZED_FREE(s);
+}
+
+static size_t
+ractor_selector_memsize(const void *ptr)
+{
+ const struct ractor_selector *s = ptr;
+ size_t size = sizeof(struct ractor_selector);
+ if (s->ports) {
+ size += st_memsize(s->ports);
+ }
+ return size;
+}
+
+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 | RUBY_TYPED_WB_PROTECTED,
+};
+
+static struct ractor_selector *
+RACTOR_SELECTOR_PTR(VALUE selv)
+{
+ VM_ASSERT(rb_typeddata_is_kind_of(selv, &ractor_selector_data_type));
+ return (struct ractor_selector *)DATA_PTR(selv);
+}
+
+// Ractor::Selector.new
+
+static VALUE
+ractor_selector_create(VALUE klass)
+{
+ struct ractor_selector *s;
+ VALUE selv = TypedData_Make_Struct(klass, struct ractor_selector, &ractor_selector_data_type, s);
+ s->ports = st_init_numtable(); // TODO
+ return selv;
+}
+
+// Ractor::Selector#add(r)
+
+/*
+ * call-seq:
+ * add(ractor) -> ractor
+ *
+ * Adds _ractor_ to +self+. Raises an exception if _ractor_ is already added.
+ * Returns _ractor_.
+ */
+static VALUE
+ractor_selector_add(VALUE selv, VALUE rpv)
+{
+ if (!ractor_port_p(rpv)) {
+ rb_raise(rb_eArgError, "Not a Ractor::Port object");
+ }
+
+ struct ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
+ const struct ractor_port *rp = RACTOR_PORT_PTR(rpv);
+
+ if (st_lookup(s->ports, (st_data_t)rpv, NULL)) {
+ rb_raise(rb_eArgError, "already added");
+ }
+
+ st_insert(s->ports, (st_data_t)rpv, (st_data_t)rp);
+ RB_OBJ_WRITTEN(selv, Qundef, rpv);
+
+ return selv;
+}
+
+// Ractor::Selector#remove(r)
+
+/* call-seq:
+ * remove(ractor) -> ractor
+ *
+ * Removes _ractor_ from +self+. Raises an exception if _ractor_ is not added.
+ * Returns the removed _ractor_.
+ */
+static VALUE
+ractor_selector_remove(VALUE selv, VALUE rpv)
+{
+ if (!ractor_port_p(rpv)) {
+ rb_raise(rb_eArgError, "Not a Ractor::Port object");
+ }
+
+ struct ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
+
+ if (!st_lookup(s->ports, (st_data_t)rpv, NULL)) {
+ rb_raise(rb_eArgError, "not added yet");
+ }
+
+ st_delete(s->ports, (st_data_t *)&rpv, NULL);
+
+ return selv;
+}
+
+// Ractor::Selector#clear
+
+/*
+ * call-seq:
+ * clear -> self
+ *
+ * Removes all ractors from +self+. Raises +self+.
+ */
+static VALUE
+ractor_selector_clear(VALUE selv)
+{
+ struct ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
+ st_clear(s->ports);
+ return selv;
+}
+
+/*
+ * call-seq:
+ * empty? -> true or false
+ *
+ * Returns +true+ if no ractor is added.
+ */
+static VALUE
+ractor_selector_empty_p(VALUE selv)
+{
+ struct ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
+ return s->ports->num_entries == 0 ? Qtrue : Qfalse;
+}
+
+// Ractor::Selector#wait
+
+struct ractor_selector_wait_data {
+ rb_ractor_t *cr;
+ rb_execution_context_t *ec;
+ bool found;
+ VALUE v;
+ VALUE rpv;
+};
+
+static int
+ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t data)
+{
+ struct ractor_selector_wait_data *p = (struct ractor_selector_wait_data *)data;
+ const struct ractor_port *rp = (const struct ractor_port *)val;
+
+ VALUE v = ractor_try_receive(p->ec, p->cr, rp);
+
+ if (v != Qundef) {
+ p->found = true;
+ p->v = v;
+ p->rpv = (VALUE)key;
+ return ST_STOP;
+ }
+ else {
+ return ST_CONTINUE;
+ }
+}
+
+static VALUE
+ractor_selector__wait(rb_execution_context_t *ec, VALUE selector)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ struct ractor_selector *s = RACTOR_SELECTOR_PTR(selector);
+
+ struct ractor_selector_wait_data data = {
+ .ec = ec,
+ .cr = cr,
+ .found = false,
+ };
+
+ while (1) {
+ st_foreach(s->ports, ractor_selector_wait_i, (st_data_t)&data);
+
+ if (data.found) {
+ return rb_ary_new_from_args(2, data.rpv, data.v);
+ }
+
+ ractor_wait_receive(ec, cr);
+ }
+}
+
+/*
+ * call-seq:
+ * wait(receive: false, yield_value: undef, move: false) -> [ractor, value]
+ *
+ * Waits until any ractor in _selector_ can be active.
+ */
+static VALUE
+ractor_selector_wait(VALUE selector)
+{
+ return ractor_selector__wait(GET_EC(), selector);
+}
+
+static VALUE
+ractor_selector_new(int argc, VALUE *ractors, VALUE klass)
+{
+ VALUE selector = ractor_selector_create(klass);
+
+ for (int i=0; i<argc; i++) {
+ ractor_selector_add(selector, ractors[i]);
+ }
+
+ return selector;
+}
+
+static VALUE
+ractor_select_internal(rb_execution_context_t *ec, VALUE self, VALUE ports)
+{
+ VALUE selector = ractor_selector_new(RARRAY_LENINT(ports), (VALUE *)RARRAY_CONST_PTR(ports), rb_cRactorSelector);
+ VALUE result = ractor_selector__wait(ec, selector);
+
+ RB_GC_GUARD(selector);
+ RB_GC_GUARD(ports);
+ return result;
+}
+
+#ifndef USE_RACTOR_SELECTOR
+#define USE_RACTOR_SELECTOR 0
+#endif
+
+RUBY_SYMBOL_EXPORT_BEGIN
+void rb_init_ractor_selector(void);
+RUBY_SYMBOL_EXPORT_END
+
+/*
+ * Document-class: Ractor::Selector
+ * :nodoc: currently
+ *
+ * Selects multiple Ractors to be activated.
+ */
+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, 0);
+}
+
+static void
+Init_RactorPort(void)
+{
+ rb_cRactorPort = rb_define_class_under(rb_cRactor, "Port", rb_cObject);
+ rb_define_alloc_func(rb_cRactorPort, ractor_port_alloc);
+ rb_define_method(rb_cRactorPort, "initialize", ractor_port_initialize, 0);
+ rb_define_method(rb_cRactorPort, "initialize_copy", ractor_port_initialize_copy, 1);
+
+#if USE_RACTOR_SELECTOR
+ rb_init_ractor_selector();
+#endif
+}
diff --git a/random.c b/random.c
index f6f63e4cff..63f43a161a 100644
--- a/random.c
+++ b/random.c
@@ -142,18 +142,21 @@ static const rb_random_interface_t random_mt_if = {
};
static rb_random_mt_t *
-rand_mt_start(rb_random_mt_t *r)
+rand_mt_start(rb_random_mt_t *r, VALUE obj)
{
if (!genrand_initialized(&r->mt)) {
r->base.seed = rand_init(&random_mt_if, &r->base, random_seed(Qundef));
+ if (obj) {
+ RB_OBJ_WRITTEN(obj, Qundef, r->base.seed);
+ }
}
return r;
}
static rb_random_t *
-rand_start(rb_random_mt_t *r)
+rand_start(rb_random_mt_t *r, VALUE obj)
{
- return &rand_mt_start(r)->base;
+ return &rand_mt_start(r, obj)->base;
}
static rb_ractor_local_key_t default_rand_key;
@@ -192,7 +195,13 @@ default_rand(void)
static rb_random_mt_t *
default_mt(void)
{
- return rand_mt_start(default_rand());
+ return rand_mt_start(default_rand(), Qfalse);
+}
+
+static rb_random_t *
+default_rand_start(void)
+{
+ return &default_mt()->base;
}
unsigned int
@@ -221,7 +230,7 @@ int_pair_to_real_inclusive(uint32_t a, uint32_t b)
const uint128_t m = ((uint128_t)1 << dig) | 1;
uint128_t x = ((uint128_t)a << 32) | b;
r = (double)(uint64_t)((x * m) >> 64);
-#elif defined HAVE_UINT64_T && !MSC_VERSION_BEFORE(1300)
+#elif defined HAVE_UINT64_T
uint64_t x = ((uint64_t)a << dig_u) +
(((uint64_t)b + (a >> dig_u)) >> dig_r64);
r = (double)x;
@@ -263,7 +272,7 @@ const rb_data_type_t rb_random_data_type = {
random_free,
random_memsize,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
#define random_mt_mark rb_random_mark
@@ -284,7 +293,7 @@ static const rb_data_type_t random_mt_type = {
},
&rb_random_data_type,
(void *)&random_mt_if,
- RUBY_TYPED_FREE_IMMEDIATELY
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static rb_random_t *
@@ -293,7 +302,7 @@ get_rnd(VALUE obj)
rb_random_t *ptr;
TypedData_Get_Struct(obj, rb_random_t, &rb_random_data_type, ptr);
if (RTYPEDDATA_TYPE(obj) == &random_mt_type)
- return rand_start((rb_random_mt_t *)ptr);
+ return rand_start((rb_random_mt_t *)ptr, obj);
return ptr;
}
@@ -306,31 +315,24 @@ get_rnd_mt(VALUE obj)
}
static rb_random_t *
-try_get_rnd(VALUE obj)
+try_get_rnd(VALUE obj, const rb_random_interface_t **rng_p)
{
if (obj == rb_cRandom) {
- return rand_start(default_rand());
+ *rng_p = &random_mt_if;
+ return default_rand_start();
}
if (!rb_typeddata_is_kind_of(obj, &rb_random_data_type)) return NULL;
- if (RTYPEDDATA_TYPE(obj) == &random_mt_type)
- return rand_start(DATA_PTR(obj));
- rb_random_t *rnd = DATA_PTR(obj);
+ const struct rb_data_type_struct *type = RTYPEDDATA_TYPE(obj);
+ *rng_p = type->data;
+ void *rnd = DATA_PTR(obj);
if (!rnd) {
rb_raise(rb_eArgError, "uninitialized random: %s",
RTYPEDDATA_TYPE(obj)->wrap_struct_name);
}
+ if (type == &random_mt_type) rnd = rand_start(rnd, obj);
return rnd;
}
-static const rb_random_interface_t *
-try_rand_if(VALUE obj, rb_random_t *rnd)
-{
- if (rnd == &default_rand()->base) {
- return &random_mt_if;
- }
- return rb_rand_if(obj);
-}
-
/* :nodoc: */
void
rb_random_base_init(rb_random_t *rnd)
@@ -351,15 +353,23 @@ random_alloc(VALUE klass)
static VALUE
rand_init_default(const rb_random_interface_t *rng, rb_random_t *rnd)
{
- VALUE seed, buf0 = 0;
+ VALUE seed;
size_t len = roomof(rng->default_seed_bits, 32);
- uint32_t *buf = ALLOCV_N(uint32_t, buf0, len+1);
- fill_random_seed(buf, len, true);
- rng->init(rnd, buf, len);
- seed = make_seed_value(buf, len);
- explicit_bzero(buf, len * sizeof(*buf));
- ALLOCV_END(buf0);
+ if (LIKELY(len)) {
+ VALUE buf0 = 0;
+ uint32_t *buf = ALLOCV_N(uint32_t, buf0, len);
+ fill_random_seed(buf, len, true);
+ rng->init(rnd, buf, len);
+ seed = make_seed_value(buf, len);
+ explicit_bzero(buf, len * sizeof(*buf));
+ ALLOCV_END(buf0);
+ }
+ else {
+ uint32_t minimul[1] = {0};
+ rng->init(rnd, minimul, 0);
+ seed = INT2FIX(0);
+ }
return seed;
}
@@ -403,8 +413,8 @@ rand_init(const rb_random_interface_t *rng, rb_random_t *rnd, VALUE seed)
static VALUE
random_init(int argc, VALUE *argv, VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
- const rb_random_interface_t *rng = rb_rand_if(obj);
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rng) {
rb_raise(rb_eTypeError, "undefined random interface: %s",
@@ -422,10 +432,10 @@ random_init(int argc, VALUE *argv, VALUE obj)
argc = rb_check_arity(argc, 0, 1);
rb_check_frozen(obj);
if (argc == 0) {
- rnd->seed = rand_init_default(rng, rnd);
+ RB_OBJ_WRITE(obj, &rnd->seed, rand_init_default(rng, rnd));
}
else {
- rnd->seed = rand_init(rng, rnd, rb_to_int(argv[0]));
+ RB_OBJ_WRITE(obj, &rnd->seed, rand_init(rng, rnd, rb_to_int(argv[0])));
}
return obj;
}
@@ -438,23 +448,17 @@ random_init(int argc, VALUE *argv, VALUE obj)
# define USE_DEV_URANDOM 0
#endif
-#ifdef HAVE_GETENTROPY
-# define MAX_SEED_LEN_PER_READ 256
-static int
-fill_random_bytes_urandom(void *seed, size_t size)
-{
- unsigned char *p = (unsigned char *)seed;
- while (size) {
- size_t len = size < MAX_SEED_LEN_PER_READ ? size : MAX_SEED_LEN_PER_READ;
- if (getentropy(p, len) != 0) {
- return -1;
- }
- p += len;
- size -= len;
- }
- return 0;
-}
-#elif USE_DEV_URANDOM
+#if ! defined HAVE_GETRANDOM && defined __linux__ && defined __NR_getrandom
+# ifndef GRND_NONBLOCK
+# define GRND_NONBLOCK 0x0001 /* not defined in musl libc */
+# endif
+# define getrandom(ptr, size, flags) \
+ (ssize_t)syscall(__NR_getrandom, (ptr), (size), (flags))
+# define HAVE_GETRANDOM 1
+#endif
+
+/* fill random bytes by reading random device directly */
+#if USE_DEV_URANDOM
static int
fill_random_bytes_urandom(void *seed, size_t size)
{
@@ -494,15 +498,7 @@ fill_random_bytes_urandom(void *seed, size_t size)
# define fill_random_bytes_urandom(seed, size) -1
#endif
-#if ! defined HAVE_GETRANDOM && defined __linux__ && defined __NR_getrandom
-# ifndef GRND_NONBLOCK
-# define GRND_NONBLOCK 0x0001 /* not defined in musl libc */
-# endif
-# define getrandom(ptr, size, flags) \
- (ssize_t)syscall(__NR_getrandom, (ptr), (size), (flags))
-# define HAVE_GETRANDOM 1
-#endif
-
+/* fill random bytes by library */
#if 0
#elif defined MAC_OS_X_VERSION_10_7 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
@@ -520,7 +516,7 @@ fill_random_bytes_urandom(void *seed, size_t size)
# endif
static int
-fill_random_bytes_syscall(void *seed, size_t size, int unused)
+fill_random_bytes_lib(void *seed, size_t size)
{
#if USE_COMMON_RANDOM
CCRNGStatus status = CCRandomGenerateBytes(seed, size);
@@ -547,18 +543,16 @@ fill_random_bytes_syscall(void *seed, size_t size, int unused)
}
return 0;
}
-#elif defined(HAVE_ARC4RANDOM_BUF)
+#elif defined(HAVE_ARC4RANDOM_BUF) && \
+ ((defined(__OpenBSD__) && OpenBSD >= 201411) || \
+ (defined(__NetBSD__) && __NetBSD_Version__ >= 700000000) || \
+ (defined(__FreeBSD__) && __FreeBSD_version >= 1200079))
+// [Bug #15039] arc4random_buf(3) should used only if we know it is fork-safe
static int
-fill_random_bytes_syscall(void *buf, size_t size, int unused)
+fill_random_bytes_lib(void *buf, size_t size)
{
-#if (defined(__OpenBSD__) && OpenBSD >= 201411) || \
- (defined(__NetBSD__) && __NetBSD_Version__ >= 700000000) || \
- (defined(__FreeBSD__) && __FreeBSD_version >= 1200079)
arc4random_buf(buf, size);
return 0;
-#else
- return -1;
-#endif
}
#elif defined(_WIN32)
@@ -572,36 +566,29 @@ fill_random_bytes_syscall(void *buf, size_t size, int unused)
static const HCRYPTPROV INVALID_HCRYPTPROV = (HCRYPTPROV)INVALID_HANDLE_VALUE;
static void
-release_crypt(void *p)
+release_crypt(VALUE arg)
{
- HCRYPTPROV *ptr = p;
+ HCRYPTPROV *ptr = (void *)arg;
HCRYPTPROV prov = (HCRYPTPROV)ATOMIC_PTR_EXCHANGE(*ptr, INVALID_HCRYPTPROV);
if (prov && prov != INVALID_HCRYPTPROV) {
CryptReleaseContext(prov, 0);
}
}
-static const rb_data_type_t crypt_prov_type = {
- "HCRYPTPROV",
- {0, release_crypt,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
-};
-
static int
fill_random_bytes_crypt(void *seed, size_t size)
{
static HCRYPTPROV perm_prov;
HCRYPTPROV prov = perm_prov, old_prov;
if (!prov) {
- VALUE wrapper = TypedData_Wrap_Struct(0, &crypt_prov_type, 0);
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
prov = INVALID_HCRYPTPROV;
}
old_prov = (HCRYPTPROV)ATOMIC_PTR_CAS(perm_prov, 0, prov);
if (LIKELY(!old_prov)) { /* no other threads acquired */
if (prov != INVALID_HCRYPTPROV) {
- DATA_PTR(wrapper) = (void *)prov;
- rb_vm_register_global_object(wrapper);
+ /* register only once; perm_prov == 0 at the first call only */
+ rb_set_end_proc(release_crypt, (VALUE)&perm_prov);
}
}
else { /* another thread acquired */
@@ -613,7 +600,7 @@ fill_random_bytes_crypt(void *seed, size_t size)
}
if (prov == INVALID_HCRYPTPROV) return -1;
while (size > 0) {
- DWORD n = (size > (size_t)DWORD_MAX) ? DWORD_MAX : (DWORD)size;
+ DWORD n = (size > (size_t)DWORD_MAX) ? DWORD_MAX/2+1 : (DWORD)size;
if (!CryptGenRandom(prov, n, seed)) return -1;
seed = (char *)seed + n;
size -= n;
@@ -628,7 +615,7 @@ static int
fill_random_bytes_bcrypt(void *seed, size_t size)
{
while (size > 0) {
- ULONG n = (size > (size_t)ULONG_MAX) ? LONG_MAX : (ULONG)size;
+ ULONG n = (size > (size_t)ULONG_MAX) ? ULONG_MAX/2+1 : (ULONG)size;
if (BCryptGenRandom(NULL, seed, n, BCRYPT_USE_SYSTEM_PREFERRED_RNG))
return -1;
seed = (char *)seed + n;
@@ -638,11 +625,17 @@ fill_random_bytes_bcrypt(void *seed, size_t size)
}
static int
-fill_random_bytes_syscall(void *seed, size_t size, int unused)
+fill_random_bytes_lib(void *seed, size_t size)
{
if (fill_random_bytes_bcrypt(seed, size) == 0) return 0;
return fill_random_bytes_crypt(seed, size);
}
+#else
+# define fill_random_bytes_lib(seed, size) -1
+#endif
+
+/* fill random bytes by dedicated syscall */
+#if 0
#elif defined HAVE_GETRANDOM
static int
fill_random_bytes_syscall(void *seed, size_t size, int need_secure)
@@ -666,6 +659,31 @@ fill_random_bytes_syscall(void *seed, size_t size, int need_secure)
}
return -1;
}
+#elif defined(HAVE_GETENTROPY)
+/*
+ * The Open Group Base Specifications Issue 8 - IEEE Std 1003.1-2024
+ * https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html
+ *
+ * NOTE: `getentropy`(3) on Linux is implemented using `getrandom`(2),
+ * prefer the latter over this if both are defined.
+ */
+#ifndef GETENTROPY_MAX
+# define GETENTROPY_MAX 256
+#endif
+static int
+fill_random_bytes_syscall(void *seed, size_t size, int need_secure)
+{
+ unsigned char *p = (unsigned char *)seed;
+ while (size) {
+ size_t len = size < GETENTROPY_MAX ? size : GETENTROPY_MAX;
+ if (getentropy(p, len) != 0) {
+ return -1;
+ }
+ p += len;
+ size -= len;
+ }
+ return 0;
+}
#else
# define fill_random_bytes_syscall(seed, size, need_secure) -1
#endif
@@ -675,6 +693,7 @@ ruby_fill_random_bytes(void *seed, size_t size, int need_secure)
{
int ret = fill_random_bytes_syscall(seed, size, need_secure);
if (ret == 0) return ret;
+ if (fill_random_bytes_lib(seed, size) == 0) return 0;
return fill_random_bytes_urandom(seed, size);
}
@@ -813,6 +832,7 @@ rand_mt_copy(VALUE obj, VALUE orig)
mt = &rnd1->mt;
*rnd1 = *rnd2;
+ RB_OBJ_WRITTEN(obj, Qundef, rnd1->base.seed);
mt->next = mt->state + numberof(mt->state) - mt->left + 1;
return obj;
}
@@ -900,7 +920,7 @@ rand_mt_load(VALUE obj, VALUE dump)
}
mt->left = (unsigned int)x;
mt->next = mt->state + numberof(mt->state) - x + 1;
- rnd->base.seed = rb_to_int(seed);
+ RB_OBJ_WRITE(obj, &rnd->base.seed, rb_to_int(seed));
return obj;
}
@@ -959,7 +979,7 @@ static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
- rb_random_mt_t *r = rand_mt_start(default_rand());
+ rb_random_mt_t *r = default_mt();
if (rb_check_arity(argc, 0, 1) == 0) {
seed = random_seed(obj);
@@ -1104,17 +1124,18 @@ random_int32(const rb_random_interface_t *rng, rb_random_t *rnd)
unsigned int
rb_random_int32(VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
uint32_t x;
obj_random_bytes(obj, &x, sizeof(x));
return (unsigned int)x;
}
- return random_int32(try_rand_if(obj, rnd), rnd);
+ return random_int32(rng, rnd);
}
static double
-random_real(VALUE obj, rb_random_t *rnd, int excl)
+random_real(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, int excl)
{
uint32_t a, b;
@@ -1125,7 +1146,6 @@ random_real(VALUE obj, rb_random_t *rnd, int excl)
b = x[1];
}
else {
- const rb_random_interface_t *rng = try_rand_if(obj, rnd);
if (rng->get_real) return rng->get_real(rnd, excl);
a = random_int32(rng, rnd);
b = random_int32(rng, rnd);
@@ -1147,7 +1167,8 @@ rb_int_pair_to_real(uint32_t a, uint32_t b, int excl)
double
rb_random_real(VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
VALUE v = rb_funcallv(obj, id_rand, 0, 0);
double d = NUM2DBL(v);
@@ -1159,7 +1180,7 @@ rb_random_real(VALUE obj)
}
return d;
}
- return random_real(obj, rnd, TRUE);
+ return random_real(obj, rng, rnd, TRUE);
}
static inline VALUE
@@ -1176,7 +1197,7 @@ ulong_to_num_plus_1(unsigned long n)
}
static unsigned long
-random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit)
+random_ulong_limited(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, unsigned long limit)
{
if (!limit) return 0;
if (!rnd) {
@@ -1201,13 +1222,14 @@ random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit)
} while (limit < val);
return val;
}
- return limited_rand(try_rand_if(obj, rnd), rnd, limit);
+ return limited_rand(rng, rnd, limit);
}
unsigned long
rb_random_ulong_limited(VALUE obj, unsigned long limit)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
VALUE lim = ulong_to_num_plus_1(limit);
VALUE v = rb_to_int(rb_funcallv_public(obj, id_rand, 1, &lim));
@@ -1220,11 +1242,11 @@ rb_random_ulong_limited(VALUE obj, unsigned long limit)
}
return r;
}
- return limited_rand(try_rand_if(obj, rnd), rnd, limit);
+ return limited_rand(rng, rnd, limit);
}
static VALUE
-random_ulong_limited_big(VALUE obj, rb_random_t *rnd, VALUE vmax)
+random_ulong_limited_big(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, VALUE vmax)
{
if (!rnd) {
VALUE v, vtmp;
@@ -1249,7 +1271,7 @@ random_ulong_limited_big(VALUE obj, rb_random_t *rnd, VALUE vmax)
ALLOCV_END(vtmp);
return v;
}
- return limited_big_rand(try_rand_if(obj, rnd), rnd, vmax);
+ return limited_big_rand(rng, rnd, vmax);
}
static VALUE
@@ -1275,8 +1297,9 @@ rand_bytes(const rb_random_interface_t *rng, rb_random_t *rnd, long n)
static VALUE
random_bytes(VALUE obj, VALUE len)
{
- rb_random_t *rnd = try_get_rnd(obj);
- return rand_bytes(rb_rand_if(obj), rnd, NUM2LONG(rb_to_int(len)));
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
+ return rand_bytes(rng, rnd, NUM2LONG(rb_to_int(len)));
}
void
@@ -1305,11 +1328,12 @@ rb_rand_bytes_int32(rb_random_get_int32_func *get_int32,
VALUE
rb_random_bytes(VALUE obj, long n)
{
- rb_random_t *rnd = try_get_rnd(obj);
+ const rb_random_interface_t *rng;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
if (!rnd) {
return obj_random_bytes(obj, NULL, n);
}
- return rand_bytes(try_rand_if(obj, rnd), rnd, n);
+ return rand_bytes(rng, rnd, n);
}
/*
@@ -1321,7 +1345,7 @@ rb_random_bytes(VALUE obj, long n)
static VALUE
random_s_bytes(VALUE obj, VALUE len)
{
- rb_random_t *rnd = rand_start(default_rand());
+ rb_random_t *rnd = default_rand_start();
return rand_bytes(&random_mt_if, rnd, NUM2LONG(rb_to_int(len)));
}
@@ -1343,7 +1367,7 @@ random_s_bytes(VALUE obj, VALUE len)
static VALUE
random_s_seed(VALUE obj)
{
- rb_random_mt_t *rnd = rand_mt_start(default_rand());
+ rb_random_mt_t *rnd = default_mt();
return rnd->base.seed;
}
@@ -1361,7 +1385,7 @@ range_values(VALUE vmax, VALUE *begp, VALUE *endp, int *exclp)
}
static VALUE
-rand_int(VALUE obj, rb_random_t *rnd, VALUE vmax, int restrictive)
+rand_int(VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd, VALUE vmax, int restrictive)
{
/* mt must be initialized */
unsigned long r;
@@ -1373,7 +1397,7 @@ rand_int(VALUE obj, rb_random_t *rnd, VALUE vmax, int restrictive)
if (restrictive) return Qnil;
max = -max;
}
- r = random_ulong_limited(obj, rnd, (unsigned long)max - 1);
+ r = random_ulong_limited(obj, rng, rnd, (unsigned long)max - 1);
return ULONG2NUM(r);
}
else {
@@ -1387,10 +1411,10 @@ rand_int(VALUE obj, rb_random_t *rnd, VALUE vmax, int restrictive)
if (FIXNUM_P(vmax)) {
long max = FIX2LONG(vmax);
if (max == -1) return Qnil;
- r = random_ulong_limited(obj, rnd, max);
+ r = random_ulong_limited(obj, rng, rnd, max);
return LONG2NUM(r);
}
- ret = random_ulong_limited_big(obj, rnd, vmax);
+ ret = random_ulong_limited_big(obj, rng, rnd, vmax);
RB_GC_GUARD(vmax);
return ret;
}
@@ -1434,7 +1458,7 @@ float_value(VALUE v)
}
static inline VALUE
-rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
+rand_range(VALUE obj, const rb_random_interface_t *rng, rb_random_t* rnd, VALUE range)
{
VALUE beg = Qundef, end = Qundef, vmax, v;
int excl = 0;
@@ -1449,7 +1473,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
fixnum:
if (FIXNUM_P(vmax)) {
if ((max = FIX2LONG(vmax) - excl) >= 0) {
- unsigned long r = random_ulong_limited(obj, rnd, (unsigned long)max);
+ unsigned long r = random_ulong_limited(obj, rng, rnd, (unsigned long)max);
v = ULONG2NUM(r);
}
}
@@ -1459,7 +1483,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
excl = 0;
goto fixnum;
}
- v = random_ulong_limited_big(obj, rnd, vmax);
+ v = random_ulong_limited_big(obj, rng, rnd, vmax);
}
}
else if (v = rb_check_to_float(vmax), !NIL_P(v)) {
@@ -1477,7 +1501,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
}
v = Qnil;
if (max > 0.0) {
- r = random_real(obj, rnd, excl);
+ r = random_real(obj, rng, rnd, excl);
if (scale > 1) {
return rb_float_new(+(+(+(r - 0.5) * max) * scale) + mid);
}
@@ -1510,7 +1534,7 @@ rand_range(VALUE obj, rb_random_t* rnd, VALUE range)
return v;
}
-static VALUE rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd);
+static VALUE rand_random(int argc, VALUE *argv, VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd);
/*
* call-seq:
@@ -1526,9 +1550,11 @@ static VALUE rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd);
* prng.rand(100) # => 42
*
* When +max+ is a Float, +rand+ returns a random floating point number
- * between 0.0 and +max+, including 0.0 and excluding +max+.
+ * between 0.0 and +max+, including 0.0 and excluding +max+. Note that it
+ * behaves differently from Kernel.rand.
*
- * prng.rand(1.5) # => 1.4600282860034115
+ * prng.rand(1.5) # => 1.4600282860034115
+ * rand(1.5) # => 0
*
* When +range+ is a Range, +rand+ returns a random number where
* <code>range.member?(number) == true</code>.
@@ -1545,24 +1571,26 @@ static VALUE rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd);
static VALUE
random_rand(int argc, VALUE *argv, VALUE obj)
{
- VALUE v = rand_random(argc, argv, obj, try_get_rnd(obj));
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
+ VALUE v = rand_random(argc, argv, obj, rng, rnd);
check_random_number(v, argv);
return v;
}
static VALUE
-rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd)
+rand_random(int argc, VALUE *argv, VALUE obj, const rb_random_interface_t *rng, rb_random_t *rnd)
{
VALUE vmax, v;
if (rb_check_arity(argc, 0, 1) == 0) {
- return rb_float_new(random_real(obj, rnd, TRUE));
+ return rb_float_new(random_real(obj, rng, rnd, TRUE));
}
vmax = argv[0];
if (NIL_P(vmax)) return Qnil;
if (!RB_FLOAT_TYPE_P(vmax)) {
v = rb_check_to_int(vmax);
- if (!NIL_P(v)) return rand_int(obj, rnd, v, 1);
+ if (!NIL_P(v)) return rand_int(obj, rng, rnd, v, 1);
}
v = rb_check_to_float(vmax);
if (!NIL_P(v)) {
@@ -1571,12 +1599,12 @@ rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd)
return Qnil;
}
else {
- double r = random_real(obj, rnd, TRUE);
+ double r = random_real(obj, rng, rnd, TRUE);
if (max > 0.0) r *= max;
return rb_float_new(r);
}
}
- return rand_range(obj, rnd, vmax);
+ return rand_range(obj, rng, rnd, vmax);
}
/*
@@ -1594,9 +1622,10 @@ rand_random(int argc, VALUE *argv, VALUE obj, rb_random_t *rnd)
static VALUE
rand_random_number(int argc, VALUE *argv, VALUE obj)
{
- rb_random_t *rnd = try_get_rnd(obj);
- VALUE v = rand_random(argc, argv, obj, rnd);
- if (NIL_P(v)) v = rand_random(0, 0, obj, rnd);
+ const rb_random_interface_t *rng = NULL;
+ rb_random_t *rnd = try_get_rnd(obj, &rng);
+ VALUE v = rand_random(argc, argv, obj, rng, rnd);
+ if (NIL_P(v)) v = rand_random(0, 0, obj, rng, rnd);
else if (!v) invalid_argument(argv[0]);
return v;
}
@@ -1666,25 +1695,28 @@ rand_mt_equal(VALUE self, VALUE other)
* Kernel.srand may be used to ensure that sequences of random numbers are
* reproducible between different runs of a program.
*
- * See also Random.rand.
+ * Related: Random.rand.
+ * rand(100.0) # => 64 (Integer because max.to_i is 100)
+ * Random.rand(100.0) # => 30.315320967824523
*/
static VALUE
rb_f_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE vmax;
- rb_random_t *rnd = rand_start(default_rand());
+ const rb_random_interface_t *rng = &random_mt_if;
+ rb_random_t *rnd = default_rand_start();
if (rb_check_arity(argc, 0, 1) && !NIL_P(vmax = argv[0])) {
- VALUE v = rand_range(obj, rnd, vmax);
+ VALUE v = rand_range(obj, rng, rnd, vmax);
if (v != Qfalse) return v;
vmax = rb_to_int(vmax);
if (vmax != INT2FIX(0)) {
- v = rand_int(obj, rnd, vmax, 0);
+ v = rand_int(obj, rng, rnd, vmax, 0);
if (!NIL_P(v)) return v;
}
}
- return DBL2NUM(random_real(obj, rnd, TRUE));
+ return DBL2NUM(random_real(obj, rng, rnd, TRUE));
}
/*
@@ -1700,7 +1732,7 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj)
static VALUE
random_s_rand(int argc, VALUE *argv, VALUE obj)
{
- VALUE v = rand_random(argc, argv, Qnil, rand_start(default_rand()));
+ VALUE v = rand_random(argc, argv, Qnil, &random_mt_if, default_rand_start());
check_random_number(v, argv);
return v;
}
@@ -1752,8 +1784,10 @@ st_index_t
rb_memhash(const void *ptr, long len)
{
sip_uint64_t h = sip_hash13(hash_salt.key.sip, ptr, len);
-#ifdef HAVE_UINT64_T
+#if SIZEOF_ST_INDEX_T >= 8
return (st_index_t)h;
+#elif defined HAVE_UINT64_T
+ return (st_index_t)((h >> 32) ^ h);
#else
return (st_index_t)(h.u32[0] ^ h.u32[1]);
#endif
diff --git a/range.c b/range.c
index 12077a068e..041cd93f73 100644
--- a/range.c
+++ b/range.c
@@ -47,6 +47,7 @@ static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
static void
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
{
+ // Changing this condition has implications for JITs. If you do, please let maintainers know.
if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
VALUE v;
@@ -153,14 +154,14 @@ recursive_equal(VALUE range, VALUE obj, int recur)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if and only if:
+ * Returns whether all of the following are true:
*
* - +other+ is a range.
* - <tt>other.begin == self.begin</tt>.
* - <tt>other.end == self.end</tt>.
* - <tt>other.exclude_end? == self.exclude_end?</tt>.
*
- * Otherwise returns +false+.
+ * Examples:
*
* r = (1..5)
* r == (1..5) # => true
@@ -199,11 +200,10 @@ range_eq(VALUE range, VALUE obj)
static int
r_less(VALUE a, VALUE b)
{
- VALUE r = rb_funcall(a, id_cmp, 1, b);
-
- if (NIL_P(r))
- return INT_MAX;
- return rb_cmpint(r, a, b);
+ VALUE r;
+#define rb_cmpint(cmp, a, b) (NIL_P(r = (cmp)) ? INT_MAX : rb_cmpint(r, (a), (b)))
+ return OPTIMIZED_CMP(a, b);
+#undef rb_cmpint
}
static VALUE
@@ -783,7 +783,7 @@ bsearch_integer_range(VALUE beg, VALUE end, int excl)
*
* Returns an element from +self+ selected by a binary search.
*
- * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
*/
@@ -1017,6 +1017,29 @@ range_to_a(VALUE range)
return rb_call_super(0, 0);
}
+/*
+ * call-seq:
+ * to_set -> set
+ *
+ * Returns a set containing the elements in +self+, if a finite collection;
+ * raises an exception otherwise.
+ *
+ * (1..4).to_set # => Set[1, 2, 3, 4]
+ * (1...4).to_set # => Set[1, 2, 3]
+ *
+ * (1..).to_set
+ * # in 'Range#to_set': cannot convert endless range to a set (RangeError)
+ *
+ */
+static VALUE
+range_to_set(VALUE range)
+{
+ if (NIL_P(RANGE_END(range))) {
+ rb_raise(rb_eRangeError, "cannot convert endless range to a set");
+ }
+ return rb_call_super(0, NULL);
+}
+
static VALUE
range_enum_size(VALUE range, VALUE args, VALUE eobj)
{
@@ -2030,10 +2053,9 @@ VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
/*
* call-seq:
- * self === object -> true or false
+ * self === other -> true or false
*
- * Returns +true+ if +object+ is between <tt>self.begin</tt> and <tt>self.end</tt>.
- * +false+ otherwise:
+ * Returns whether +other+ is between <tt>self.begin</tt> and <tt>self.end</tt>:
*
* (1..4) === 2 # => true
* (1..4) === 5 # => false
@@ -2588,12 +2610,12 @@ range_overlap(VALUE range, VALUE other)
*
* - Method Range.new:
*
- * # Ranges that by default include the given end value.
- * Range.new(1, 4).to_a # => [1, 2, 3, 4]
- * Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
- * # Ranges that use third argument +exclude_end+ to exclude the given end value.
- * Range.new(1, 4, true).to_a # => [1, 2, 3]
- * Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
+ * # Ranges that by default include the given end value.
+ * Range.new(1, 4).to_a # => [1, 2, 3, 4]
+ * Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
+ * # Ranges that use third argument +exclude_end+ to exclude the given end value.
+ * Range.new(1, 4, true).to_a # => [1, 2, 3]
+ * Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
*
* == Beginless Ranges
*
@@ -2745,8 +2767,8 @@ range_overlap(VALUE range, VALUE other)
*
* First, what's elsewhere. Class \Range:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class \Range provides methods that are useful for:
@@ -2844,6 +2866,7 @@ Init_Range(void)
rb_define_method(rb_cRange, "minmax", range_minmax, 0);
rb_define_method(rb_cRange, "size", range_size, 0);
rb_define_method(rb_cRange, "to_a", range_to_a, 0);
+ rb_define_method(rb_cRange, "to_set", range_to_set, 0);
rb_define_method(rb_cRange, "entries", range_to_a, 0);
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
rb_define_method(rb_cRange, "inspect", range_inspect, 0);
diff --git a/rational.c b/rational.c
index f1547856b4..b031838d69 100644
--- a/rational.c
+++ b/rational.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/complex.h"
+#include "internal/error.h"
#include "internal/gc.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -175,22 +176,6 @@ f_idiv(VALUE x, VALUE y)
#define f_expt10(x) rb_int_pow(INT2FIX(10), x)
inline static int
-f_zero_p(VALUE x)
-{
- if (RB_INTEGER_TYPE_P(x)) {
- return FIXNUM_ZERO_P(x);
- }
- else if (RB_TYPE_P(x, T_RATIONAL)) {
- VALUE num = RRATIONAL(x)->num;
-
- return FIXNUM_ZERO_P(num);
- }
- return (int)rb_equal(x, ZERO);
-}
-
-#define f_nonzero_p(x) (!f_zero_p(x))
-
-inline static int
f_one_p(VALUE x)
{
if (RB_INTEGER_TYPE_P(x)) {
@@ -419,8 +404,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, sizeof(struct RRational));
RATIONAL_SET_NUM((VALUE)obj, num);
RATIONAL_SET_DEN((VALUE)obj, den);
@@ -609,9 +593,13 @@ nurat_denominator(VALUE self)
/*
* call-seq:
- * -rat -> rational
+ * -self -> rational
+ *
+ * Returns +self+, negated:
+ *
+ * -(1/3r) # => (-1/3)
+ * -(-1/3r) # => (1/3)
*
- * Negates +rat+.
*/
VALUE
rb_rational_uminus(VALUE self)
@@ -715,16 +703,27 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
static double nurat_to_double(VALUE self);
/*
- * call-seq:
- * rat + numeric -> numeric
+ * call-seq:
+ * self + other -> numeric
+ *
+ * Returns the sum of +self+ and +other+:
+ *
+ * Rational(2, 3) + 0 # => (2/3)
+ * Rational(2, 3) + 1 # => (5/3)
+ * Rational(2, 3) + -1 # => (-1/3)
+ *
+ * Rational(2, 3) + Complex(1, 0) # => ((5/3)+0i)
+ *
+ * Rational(2, 3) + Rational(1, 1) # => (5/3)
+ * Rational(2, 3) + Rational(3, 2) # => (13/6)
+ * Rational(2, 3) + Rational(3.0, 2.0) # => (13/6)
+ * Rational(2, 3) + Rational(3.1, 2.1) # => (30399297484750849/14186338826217063)
+ *
+ * For a computation involving Floats, the result may be inexact (see Float#+):
*
- * Performs addition.
+ * Rational(2, 3) + 1.0 # => 1.6666666666666665
+ * Rational(2, 3) + Complex(1.0, 0.0) # => (1.6666666666666665+0.0i)
*
- * Rational(2, 3) + Rational(2, 3) #=> (4/3)
- * Rational(900) + Rational(1) #=> (901/1)
- * Rational(-2, 9) + Rational(-9, 2) #=> (-85/18)
- * Rational(9, 8) + 4 #=> (41/8)
- * Rational(20, 9) + 9.8 #=> 12.022222222222222
*/
VALUE
rb_rational_plus(VALUE self, VALUE other)
@@ -757,9 +756,9 @@ rb_rational_plus(VALUE self, VALUE other)
/*
* call-seq:
- * rat - numeric -> numeric
+ * self - other -> numeric
*
- * Performs subtraction.
+ * Returns the difference of +self+ and +other+:
*
* Rational(2, 3) - Rational(2, 3) #=> (0/1)
* Rational(900) - Rational(1) #=> (899/1)
@@ -853,15 +852,17 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
/*
* call-seq:
- * rat * numeric -> numeric
+ * self * other -> numeric
*
- * Performs multiplication.
+ * Returns the numeric product of +self+ and +other+:
+ *
+ * Rational(9, 8) * 4 #=> (9/2)
+ * Rational(20, 9) * 9.8 #=> 21.77777777777778
+ * Rational(9, 8) * Complex(1, 2) # => ((9/8)+(9/4)*i)
+ * Rational(2, 3) * Rational(2, 3) #=> (4/9)
+ * Rational(900) * Rational(1) #=> (900/1)
+ * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
*
- * Rational(2, 3) * Rational(2, 3) #=> (4/9)
- * Rational(900) * Rational(1) #=> (900/1)
- * Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
- * Rational(9, 8) * 4 #=> (9/2)
- * Rational(20, 9) * 9.8 #=> 21.77777777777778
*/
VALUE
rb_rational_mul(VALUE self, VALUE other)
@@ -894,10 +895,9 @@ rb_rational_mul(VALUE self, VALUE other)
/*
* call-seq:
- * rat / numeric -> numeric
- * rat.quo(numeric) -> numeric
+ * self / other -> numeric
*
- * Performs division.
+ * Returns the quotient of +self+ and +other+:
*
* Rational(2, 3) / Rational(2, 3) #=> (1/1)
* Rational(900) / Rational(1) #=> (900/1)
@@ -953,8 +953,8 @@ rb_rational_div(VALUE self, VALUE other)
* Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333
* Rational(2).fdiv(3) #=> 0.6666666666666666
*/
-static VALUE
-nurat_fdiv(VALUE self, VALUE other)
+VALUE
+rb_rational_fdiv(VALUE self, VALUE other)
{
VALUE div;
if (f_zero_p(other))
@@ -971,9 +971,9 @@ nurat_fdiv(VALUE self, VALUE other)
/*
* call-seq:
- * rat ** numeric -> numeric
+ * self ** exponent -> numeric
*
- * Performs exponentiation.
+ * Returns +self+ raised to the power +exponent+:
*
* Rational(2) ** Rational(3) #=> (8/1)
* Rational(10) ** -2 #=> (1/100)
@@ -1061,20 +1061,30 @@ rb_rational_pow(VALUE self, VALUE other)
/*
* call-seq:
- * rational <=> numeric -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+.
+ *
+ * Returns:
*
- * Returns -1, 0, or +1 depending on whether +rational+ is
- * less than, equal to, or greater than +numeric+.
+ * - +-1+, if +self+ is less than +other+.
+ * - +0+, if the two values are the same.
+ * - +1+, if +self+ is greater than +other+.
+ * - +nil+, if the two values are incomparable.
*
- * +nil+ is returned if the two values are incomparable.
+ * Examples:
*
- * Rational(2, 3) <=> Rational(2, 3) #=> 0
- * Rational(5) <=> 5 #=> 0
- * Rational(2, 3) <=> Rational(1, 3) #=> 1
- * Rational(1, 3) <=> 1 #=> -1
- * Rational(1, 3) <=> 0.3 #=> 1
+ * Rational(2, 3) <=> Rational(4, 3) # => -1
+ * Rational(2, 1) <=> Rational(2, 1) # => 0
+ * Rational(2, 1) <=> 2 # => 0
+ * Rational(2, 1) <=> 2.0 # => 0
+ * Rational(2, 1) <=> Complex(2, 0) # => 0
+ * Rational(4, 3) <=> Rational(2, 3) # => 1
+ * Rational(4, 3) <=> :foo # => nil
+ *
+ * \Class \Rational includes module Comparable,
+ * each of whose methods uses Rational#<=> for comparison.
*
- * Rational(1, 3) <=> "0.3" #=> nil
*/
VALUE
rb_rational_cmp(VALUE self, VALUE other)
@@ -1119,9 +1129,9 @@ rb_rational_cmp(VALUE self, VALUE other)
/*
* call-seq:
- * rat == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +rat+ equals +object+ numerically.
+ * Returns whether +self+ and +other+ are numerically equal:
*
* Rational(2, 3) == Rational(2, 3) #=> true
* Rational(5) == 5 #=> true
@@ -1364,10 +1374,12 @@ nurat_round_half_even(VALUE self)
return num;
}
+static VALUE f_round_n(VALUE self, VALUE n, VALUE (*func)(VALUE)) ;
+
static VALUE
f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
{
- VALUE n, b, s;
+ VALUE n;
if (rb_check_arity(argc, 0, 1) == 0)
return (*func)(self);
@@ -1377,6 +1389,14 @@ f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
if (!k_integer_p(n))
rb_raise(rb_eTypeError, "not an integer");
+ return f_round_n(self, n, func);
+}
+
+static VALUE
+f_round_n(VALUE self, VALUE n, VALUE (*func)(VALUE))
+{
+ VALUE b, s;
+
b = f_expt10(n);
s = rb_rational_mul(self, b);
@@ -1407,8 +1427,7 @@ rb_rational_floor(VALUE self, int ndigits)
return nurat_floor(self);
}
else {
- VALUE n = INT2NUM(ndigits);
- return f_round_common(1, &n, self, nurat_floor);
+ return f_round_n(self, INT2NUM(ndigits), nurat_floor);
}
}
@@ -1551,9 +1570,22 @@ nurat_round_n(int argc, VALUE *argv, VALUE self)
}
VALUE
-rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num)
+rb_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
+{
+ VALUE (*round_func)(VALUE) = ROUND_FUNC(mode, nurat_round);
+ return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), round_func));
+}
+
+VALUE
+rb_flo_ceil_by_rational(VALUE num, int ndigits)
+{
+ return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), nurat_ceil));
+}
+
+VALUE
+rb_flo_floor_by_rational(VALUE num, int ndigits)
{
- return nurat_to_f(nurat_round_n(argc, argv, float_to_r(num)));
+ return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), nurat_floor));
}
static double
@@ -2109,39 +2141,6 @@ rb_float_denominator(VALUE self)
/*
* call-seq:
- * to_r -> (0/1)
- *
- * Returns zero as a Rational:
- *
- * nil.to_r # => (0/1)
- *
- */
-static VALUE
-nilclass_to_r(VALUE self)
-{
- return rb_rational_new1(INT2FIX(0));
-}
-
-/*
- * call-seq:
- * rationalize(eps = nil) -> (0/1)
- *
- * Returns zero as a Rational:
- *
- * nil.rationalize # => (0/1)
- *
- * Argument +eps+ is ignored.
- *
- */
-static VALUE
-nilclass_rationalize(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- return nilclass_to_r(self);
-}
-
-/*
- * call-seq:
* int.to_r -> rational
*
* Returns the value as a rational.
@@ -2327,6 +2326,12 @@ islettere(int c)
return (c == 'e' || c == 'E');
}
+inline static int
+isletterr(int c)
+{
+ return (c == 'r' || c == 'R');
+}
+
static VALUE
negate_num(VALUE num)
{
@@ -2376,7 +2381,13 @@ read_num(const char **s, const char *const end, VALUE *num, VALUE *nexp)
ok = 1;
}
- if (ok && *s + 1 < end && islettere(**s)) {
+ if (!ok || *s >= end) {
+ /* failed or finish */
+ }
+ else if (isletterr(**s)) {
+ (*s)++;
+ }
+ else if (*s + 1 < end && islettere(**s)) {
(*s)++;
expsign = read_sign(s, end);
exp = rb_int_parse_cstr(*s, end-*s, &e, NULL,
@@ -2500,31 +2511,32 @@ string_to_r_strict(VALUE self, int raise)
/*
* call-seq:
- * str.to_r -> rational
- *
- * Returns the result of interpreting leading characters in +str+
- * as a rational. Leading whitespace and extraneous characters
- * past the end of a valid number are ignored.
- * Digit sequences can be separated by an underscore.
- * If there is not a valid number at the start of +str+,
- * zero is returned. This method never raises an exception.
- *
- * ' 2 '.to_r #=> (2/1)
- * '300/2'.to_r #=> (150/1)
- * '-9.2'.to_r #=> (-46/5)
- * '-9.2e2'.to_r #=> (-920/1)
- * '1_234_567'.to_r #=> (1234567/1)
- * '21 June 09'.to_r #=> (21/1)
- * '21/06/09'.to_r #=> (7/2)
- * 'BWV 1079'.to_r #=> (0/1)
- *
- * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is
- * equivalent to "3/10".to_r, but the latter isn't so.
+ * str.to_r -> rational
*
- * "0.3".to_r == 3/10r #=> true
- * 0.3.to_r == 3/10r #=> false
+ * Returns the result of interpreting leading characters in +self+ as a rational value:
+ *
+ * '123'.to_r # => (123/1) # Integer literal.
+ * '300/2'.to_r # => (150/1) # Rational literal.
+ * '-9.2'.to_r # => (-46/5) # Float literal.
+ * '-9.2e2'.to_r # => (-920/1) # Float literal.
+ *
+ * Ignores leading and trailing whitespace, and trailing non-numeric characters:
+ *
+ * ' 2 '.to_r # => (2/1)
+ * '21-Jun-09'.to_r # => (21/1)
+ *
+ * Returns \Rational zero if there are no leading numeric characters.
+ *
+ * 'BWV 1079'.to_r # => (0/1)
+ *
+ * NOTE: <tt>'0.3'.to_r</tt> is equivalent to <tt>3/10r</tt>,
+ * but is different from <tt>0.3.to_r</tt>:
+ *
+ * '0.3'.to_r # => (3/10)
+ * 3/10r # => (3/10)
+ * 0.3.to_r # => (5404319552844595/18014398509481984)
*
- * See also Kernel#Rational.
+ * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
*/
static VALUE
string_to_r(VALUE self)
@@ -2568,7 +2580,7 @@ nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise)
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
- rb_raise(rb_eTypeError, "can't convert nil into Rational");
+ rb_cant_convert(Qnil, "Rational");
}
if (RB_TYPE_P(a1, T_COMPLEX)) {
@@ -2779,7 +2791,7 @@ Init_Rational(void)
rb_define_method(rb_cRational, "*", rb_rational_mul, 1);
rb_define_method(rb_cRational, "/", rb_rational_div, 1);
rb_define_method(rb_cRational, "quo", rb_rational_div, 1);
- rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
+ rb_define_method(rb_cRational, "fdiv", rb_rational_fdiv, 1);
rb_define_method(rb_cRational, "**", nurat_expt, 1);
rb_define_method(rb_cRational, "<=>", rb_rational_cmp, 1);
@@ -2823,8 +2835,6 @@ Init_Rational(void)
rb_define_method(rb_cFloat, "numerator", rb_float_numerator, 0);
rb_define_method(rb_cFloat, "denominator", rb_float_denominator, 0);
- rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
- rb_define_method(rb_cNilClass, "rationalize", nilclass_rationalize, -1);
rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
rb_define_method(rb_cInteger, "rationalize", integer_rationalize, -1);
rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
diff --git a/re.c b/re.c
index 96a3cbeaa9..63e2db81ac 100644
--- a/re.c
+++ b/re.c
@@ -16,7 +16,9 @@
#include "encindex.h"
#include "hrtime.h"
#include "internal.h"
+#include "internal/bignum.h"
#include "internal/encoding.h"
+#include "internal/error.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/re.h"
@@ -28,15 +30,13 @@
#include "ruby/encoding.h"
#include "ruby/re.h"
#include "ruby/util.h"
+#include "ractor_core.h"
VALUE rb_eRegexpError, rb_eRegexpTimeoutError;
typedef char onig_errmsg_buffer[ONIG_MAX_ERROR_MESSAGE_LEN];
#define errcpy(err, msg) strlcpy((err), (msg), ONIG_MAX_ERROR_MESSAGE_LEN)
-#define BEG(no) (regs->beg[(no)])
-#define END(no) (regs->end[(no)])
-
#if 'a' == 97 /* it's ascii */
static const char casetable[] = {
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
@@ -104,7 +104,7 @@ rb_memcicmp(const void *x, const void *y, long len)
return 0;
}
-#ifdef HAVE_MEMMEM
+#if defined(HAVE_MEMMEM) && !defined(__APPLE__)
static inline long
rb_memsearch_ss(const unsigned char *xs, long m, const unsigned char *ys, long n)
{
@@ -289,11 +289,6 @@ rb_memsearch(const void *x0, long m, const void *y0, long n, rb_encoding *enc)
#define KCODE_FIXED FL_USER4
-#define ARG_REG_OPTION_MASK \
- (ONIG_OPTION_IGNORECASE|ONIG_OPTION_MULTILINE|ONIG_OPTION_EXTEND)
-#define ARG_ENCODING_FIXED 16
-#define ARG_ENCODING_NONE 32
-
static int
char_to_option(int c)
{
@@ -967,19 +962,33 @@ make_regexp(const char *s, long len, rb_encoding *enc, int flags, onig_errmsg_bu
VALUE rb_cMatch;
static VALUE
-match_alloc(VALUE klass)
+match_alloc_n(VALUE klass, int num_regs)
{
- 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);
+ int capa = num_regs * 2;
+ size_t alloc_size = offsetof(struct RMatch, as) + sizeof(OnigPosition) * capa;
+ if (alloc_size < sizeof(struct RMatch)) {
+ alloc_size = sizeof(struct RMatch);
+ }
- match->str = Qfalse;
- match->regexp = Qfalse;
- memset(RMATCH_EXT(match), 0, sizeof(rb_matchext_t));
+ VALUE flags = T_MATCH;
+ if (!rb_gc_size_allocatable_p(alloc_size)) {
+ alloc_size = sizeof(struct RMatch);
+ flags |= RMATCH_ONIG;
+ capa = 0;
+ }
+ NEWOBJ_OF(match, struct RMatch, klass, flags, alloc_size);
+ memset(((char *)match) + sizeof(struct RBasic), 0, alloc_size - sizeof(struct RBasic));
+ match->capa = capa;
return (VALUE)match;
}
+static VALUE
+match_alloc(VALUE klass)
+{
+ return match_alloc_n(klass, 0);
+}
+
int
rb_reg_region_copy(struct re_registers *to, const struct re_registers *from)
{
@@ -991,6 +1000,54 @@ rb_reg_region_copy(struct re_registers *to, const struct re_registers *from)
return ONIGERR_MEMORY;
}
+static void
+match_to_onig(VALUE match, int num_regs, const OnigPosition *src_beg, const OnigPosition *src_end)
+{
+ struct RMatch *rm = RMATCH(match);
+ struct re_registers tmp = {0};
+ if (onig_region_resize(&tmp, num_regs)) {
+ rb_memerror();
+ }
+ memcpy(tmp.beg, src_beg, num_regs * sizeof(OnigPosition));
+ memcpy(tmp.end, src_end, num_regs * sizeof(OnigPosition));
+ rm->as.onig = tmp;
+ FL_SET_RAW(match, RMATCH_ONIG);
+}
+
+void
+rb_match_ensure_onig(VALUE match)
+{
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) return;
+ struct RMatch *rm = RMATCH(match);
+ int n = rm->num_regs;
+ match_to_onig(match, n, &rm->as.embed[0], &rm->as.embed[n]);
+}
+
+/* Replace `match`'s registers with a copy of (num_regs, beg, end). If the
+ * data does not fit in the embed form, the match is evicted to onig form.
+ * Raises on OOM. */
+static void
+match_set_regs(VALUE match, int num_regs, const OnigPosition *beg, const OnigPosition *end)
+{
+ struct RMatch *rm = RMATCH(match);
+
+ if (FL_TEST_RAW(match, RMATCH_ONIG)) {
+ if (onig_region_resize(&rm->as.onig, num_regs)) {
+ rb_memerror();
+ }
+ memcpy(rm->as.onig.beg, beg, num_regs * sizeof(OnigPosition));
+ memcpy(rm->as.onig.end, end, num_regs * sizeof(OnigPosition));
+ }
+ else if (num_regs * 2 <= rm->capa) {
+ memcpy(&rm->as.embed[0], beg, num_regs * sizeof(OnigPosition));
+ memcpy(&rm->as.embed[num_regs], end, num_regs * sizeof(OnigPosition));
+ }
+ else {
+ match_to_onig(match, num_regs, beg, end);
+ }
+ rm->num_regs = num_regs;
+}
+
typedef struct {
long byte_pos;
long char_pos;
@@ -1010,41 +1067,41 @@ pair_byte_cmp(const void *pair1, const void *pair2)
static void
update_char_offset(VALUE match)
{
- rb_matchext_t *rm = RMATCH_EXT(match);
- struct re_registers *regs;
+ struct RMatch *rm = RMATCH(match);
int i, num_regs, num_pos;
long c;
char *s, *p, *q;
rb_encoding *enc;
pair_t *pairs;
+ VALUE pairs_obj = Qnil;
if (rm->char_offset_num_allocated)
return;
- regs = &rm->regs;
- num_regs = rm->regs.num_regs;
+ num_regs = RMATCH_NREGS(match);
if (rm->char_offset_num_allocated < num_regs) {
- REALLOC_N(rm->char_offset, struct rmatch_offset, num_regs);
+ SIZED_REALLOC_N(rm->char_offset, struct rmatch_offset, num_regs, rm->char_offset_num_allocated);
rm->char_offset_num_allocated = num_regs;
+ FL_SET_RAW(match, RMATCH_OFFSETS_EXTERNAL);
}
enc = rb_enc_get(RMATCH(match)->str);
if (rb_enc_mbmaxlen(enc) == 1) {
for (i = 0; i < num_regs; i++) {
- rm->char_offset[i].beg = BEG(i);
- rm->char_offset[i].end = END(i);
+ rm->char_offset[i].beg = RMATCH_BEG(match, i);
+ rm->char_offset[i].end = RMATCH_END(match, i);
}
return;
}
- pairs = ALLOCA_N(pair_t, num_regs*2);
+ pairs = RB_ALLOCV_N(pair_t, pairs_obj, num_regs * 2);
num_pos = 0;
for (i = 0; i < num_regs; i++) {
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
continue;
- pairs[num_pos++].byte_pos = BEG(i);
- pairs[num_pos++].byte_pos = END(i);
+ pairs[num_pos++].byte_pos = RMATCH_BEG(match, i);
+ pairs[num_pos++].byte_pos = RMATCH_END(match, i);
}
qsort(pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
@@ -1059,20 +1116,22 @@ update_char_offset(VALUE match)
for (i = 0; i < num_regs; i++) {
pair_t key, *found;
- if (BEG(i) < 0) {
+ if (RMATCH_BEG(match, i) < 0) {
rm->char_offset[i].beg = -1;
rm->char_offset[i].end = -1;
continue;
}
- key.byte_pos = BEG(i);
+ key.byte_pos = RMATCH_BEG(match, i);
found = bsearch(&key, pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
rm->char_offset[i].beg = found->char_pos;
- key.byte_pos = END(i);
+ key.byte_pos = RMATCH_END(match, i);
found = bsearch(&key, pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
rm->char_offset[i].end = found->char_pos;
}
+
+ RB_ALLOCV_END(pairs_obj);
}
static VALUE
@@ -1088,24 +1147,23 @@ match_check(VALUE match)
static VALUE
match_init_copy(VALUE obj, VALUE orig)
{
- rb_matchext_t *rm;
+ struct RMatch *rm = RMATCH(obj);
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);
+ RB_OBJ_WRITE(obj, &rm->str, RMATCH(orig)->str);
+ RB_OBJ_WRITE(obj, &rm->regexp, RMATCH(orig)->regexp);
- rm = RMATCH_EXT(obj);
- if (rb_reg_region_copy(&rm->regs, RMATCH_REGS(orig)))
- rb_memerror();
+ match_set_regs(obj, RMATCH_NREGS(orig), RMATCH_BEG_PTR(orig), RMATCH_END_PTR(orig));
- if (RMATCH_EXT(orig)->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;
+ if (RMATCH(orig)->char_offset_num_allocated) {
+ if (rm->char_offset_num_allocated < rm->num_regs) {
+ SIZED_REALLOC_N(rm->char_offset, struct rmatch_offset, rm->num_regs, rm->char_offset_num_allocated);
+ rm->char_offset_num_allocated = rm->num_regs;
+ FL_SET_RAW(obj, RMATCH_OFFSETS_EXTERNAL);
}
- MEMCPY(rm->char_offset, RMATCH_EXT(orig)->char_offset,
- struct rmatch_offset, rm->regs.num_regs);
+ MEMCPY(rm->char_offset, RMATCH(orig)->char_offset,
+ struct rmatch_offset, rm->num_regs);
RB_GC_GUARD(orig);
}
@@ -1184,10 +1242,10 @@ static VALUE
match_size(VALUE match)
{
match_check(match);
- return INT2FIX(RMATCH_REGS(match)->num_regs);
+ return INT2FIX(RMATCH_NREGS(match));
}
-static int name_to_backref_number(struct re_registers *, VALUE, const char*, const char*);
+static int match_name_to_backref_number(VALUE match, VALUE name);
NORETURN(static void name_to_backref_error(VALUE name));
static void
@@ -1198,21 +1256,17 @@ name_to_backref_error(VALUE name)
}
static void
-backref_number_check(struct re_registers *regs, int i)
+backref_number_check(VALUE match, int i)
{
- if (i < 0 || regs->num_regs <= i)
+ if (i < 0 || RMATCH_NREGS(match) <= i)
rb_raise(rb_eIndexError, "index %d out of matches", i);
}
static int
match_backref_number(VALUE match, VALUE backref)
{
- const char *name;
int num;
- struct re_registers *regs = RMATCH_REGS(match);
- VALUE regexp = RMATCH(match)->regexp;
-
match_check(match);
if (SYMBOL_P(backref)) {
backref = rb_sym2str(backref);
@@ -1220,9 +1274,8 @@ match_backref_number(VALUE match, VALUE backref)
else if (!RB_TYPE_P(backref, T_STRING)) {
return NUM2INT(backref);
}
- name = StringValueCStr(backref);
- num = name_to_backref_number(regs, regexp, name, name + RSTRING_LEN(backref));
+ num = match_name_to_backref_number(match, backref);
if (num < 1) {
name_to_backref_error(backref);
@@ -1250,17 +1303,16 @@ static VALUE
match_offset(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
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)->char_offset[i].beg),
+ LONG2NUM(RMATCH(match)->char_offset[i].end));
}
/*
@@ -1285,14 +1337,13 @@ static VALUE
match_byteoffset(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return rb_assoc_new(Qnil, Qnil);
- return rb_assoc_new(LONG2NUM(BEG(i)), LONG2NUM(END(i)));
+ return rb_assoc_new(LONG2NUM(RMATCH_BEG(match, i)), LONG2NUM(RMATCH_END(match, i)));
}
@@ -1309,14 +1360,13 @@ static VALUE
match_bytebegin(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
- return LONG2NUM(BEG(i));
+ return LONG2NUM(RMATCH_BEG(match, i));
}
@@ -1333,14 +1383,13 @@ static VALUE
match_byteend(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
- return LONG2NUM(END(i));
+ return LONG2NUM(RMATCH_END(match, i));
}
@@ -1357,16 +1406,15 @@ static VALUE
match_begin(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].beg);
+ return LONG2NUM(RMATCH(match)->char_offset[i].beg);
}
@@ -1383,16 +1431,15 @@ static VALUE
match_end(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].end);
+ return LONG2NUM(RMATCH(match)->char_offset[i].end);
}
/*
@@ -1425,11 +1472,10 @@ static VALUE
match_nth(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- long start = BEG(i), end = END(i);
+ long start = RMATCH_BEG(match, i), end = RMATCH_END(match, i);
if (start < 0)
return Qnil;
@@ -1469,17 +1515,16 @@ static VALUE
match_nth_length(VALUE match, VALUE n)
{
int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
match_check(match);
- backref_number_check(regs, i);
+ backref_number_check(match, i);
- if (BEG(i) < 0)
+ if (RMATCH_BEG(match, i) < 0)
return Qnil;
update_char_offset(match);
const struct rmatch_offset *const ofs =
- &RMATCH_EXT(match)->char_offset[i];
+ &RMATCH(match)->char_offset[i];
return LONG2NUM(ofs->end - ofs->beg);
}
@@ -1500,34 +1545,36 @@ rb_match_unbusy(VALUE match)
int
rb_match_count(VALUE match)
{
- struct re_registers *regs;
if (NIL_P(match)) return -1;
- regs = RMATCH_REGS(match);
- if (!regs) return -1;
- return regs->num_regs;
+ return RMATCH_NREGS(match);
+}
+
+static VALUE
+match_alloc_or_reuse(VALUE existing, int num_regs)
+{
+ if (!NIL_P(existing) &&
+ !FL_TEST(existing, MATCH_BUSY) &&
+ RMATCH(existing)->capa >= num_regs * 2) {
+ return existing;
+ }
+ return match_alloc_n(rb_cMatch, num_regs);
}
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);
- RB_OBJ_WRITE(match, &RMATCH(match)->str, string);
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, Qnil);
- int err = onig_region_resize(&rmatch->regs, 1);
- if (err) rb_memerror();
- rmatch->regs.beg[0] = pos;
- rmatch->regs.end[0] = pos + len;
+ RB_OBJ_WRITE(match, &match->str, string);
+ RB_OBJ_WRITE(match, &match->regexp, Qnil);
+ OnigPosition beg = pos, end = pos + len;
+ match_set_regs(m, 1, &beg, &end);
}
VALUE
rb_backref_set_string(VALUE string, long pos, long len)
{
- VALUE match = rb_backref_get();
- if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
- match = match_alloc(rb_cMatch);
- }
+ VALUE match = match_alloc_or_reuse(rb_backref_get(), 1);
match_set_string(match, string, pos, len);
rb_backref_set(match);
return match;
@@ -1583,21 +1630,11 @@ reg_enc_error(VALUE re, VALUE str)
rb_enc_inspect_name(rb_enc_get(str)));
}
-static inline int
-str_coderange(VALUE str)
-{
- int cr = ENC_CODERANGE(str);
- if (cr == ENC_CODERANGE_UNKNOWN) {
- cr = rb_enc_str_coderange(str);
- }
- return cr;
-}
-
static rb_encoding*
rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
{
rb_encoding *enc = 0;
- int cr = str_coderange(str);
+ int cr = rb_enc_str_coderange(str);
if (cr == ENC_CODERANGE_BROKEN) {
rb_raise(rb_eArgError,
@@ -1666,7 +1703,7 @@ rb_reg_prepare_re(VALUE re, VALUE str)
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) {
+ if (ruby_single_main_ractor && RREGEXP(re)->usecnt == 0) {
regex_t tmp_reg;
r = onig_new_without_alloc(&tmp_reg, (UChar *)ptr, (UChar *)(ptr + len),
reg->options, enc,
@@ -1718,8 +1755,6 @@ rb_reg_onig_match(VALUE re, VALUE str,
}
if (result < 0) {
- onig_region_free(regs, 0);
-
switch (result) {
case ONIG_MISMATCH:
break;
@@ -1804,37 +1839,35 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
.pos = pos,
.range = reverse ? 0 : len,
};
- struct re_registers regs = {0};
+
+ rb_reg_check(re);
+
+ /* Stack-backed regs sized to max(num_mem+1, ONIG_NREGION) so
+ * onig_region_resize_clear takes its no-op branch. */
+ int n = RREGEXP_PTR(re)->num_mem + 1;
+ int cap = n < ONIG_NREGION ? ONIG_NREGION : n;
+ VALUE regs_buf;
+ OnigPosition *buf = ALLOCV_N(OnigPosition, regs_buf, (size_t)cap * 2);
+ struct re_registers regs = {
+ .allocated = cap,
+ .num_regs = 0,
+ .beg = buf,
+ .end = buf + cap,
+ };
OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
if (result == ONIG_MISMATCH) {
+ ALLOCV_END(regs_buf);
rb_backref_set(Qnil);
return ONIG_MISMATCH;
}
- VALUE match = Qnil;
- if (set_match) {
- match = *set_match;
- }
-
- if (NIL_P(match)) {
- match = rb_backref_get();
- }
-
- if (!NIL_P(match) && FL_TEST(match, MATCH_BUSY)) {
- match = Qnil;
- }
-
- if (NIL_P(match)) {
- match = match_alloc(rb_cMatch);
- }
- else {
- onig_region_free(&RMATCH_EXT(match)->regs, false);
- }
+ VALUE existing = (set_match && !NIL_P(*set_match)) ? *set_match : rb_backref_get();
+ VALUE match = match_alloc_or_reuse(existing, regs.num_regs);
- rb_matchext_t *rm = RMATCH_EXT(match);
- rm->regs = regs;
+ match_set_regs(match, regs.num_regs, regs.beg, regs.end);
+ ALLOCV_END(regs_buf);
if (set_backref_str) {
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
@@ -1886,18 +1919,29 @@ reg_onig_match(regex_t *reg, VALUE str, struct re_registers *regs, void *_)
bool
rb_reg_start_with_p(VALUE re, VALUE str)
{
- VALUE match = rb_backref_get();
- if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
- match = match_alloc(rb_cMatch);
- }
+ rb_reg_check(re);
- struct re_registers *regs = RMATCH_REGS(match);
+ int n = RREGEXP_PTR(re)->num_mem + 1;
+ int cap = n < ONIG_NREGION ? ONIG_NREGION : n;
+ VALUE regs_buf;
+ OnigPosition *buf = ALLOCV_N(OnigPosition, regs_buf, (size_t)cap * 2);
+ struct re_registers regs = {
+ .allocated = cap,
+ .num_regs = 0,
+ .beg = buf,
+ .end = buf + cap,
+ };
- if (rb_reg_onig_match(re, str, reg_onig_match, NULL, regs) == ONIG_MISMATCH) {
+ if (rb_reg_onig_match(re, str, reg_onig_match, NULL, &regs) == ONIG_MISMATCH) {
+ ALLOCV_END(regs_buf);
rb_backref_set(Qnil);
return false;
}
+ VALUE match = match_alloc_or_reuse(rb_backref_get(), regs.num_regs);
+ match_set_regs(match, regs.num_regs, regs.beg, regs.end);
+ ALLOCV_END(regs_buf);
+
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
rb_backref_set(match);
@@ -1908,18 +1952,17 @@ rb_reg_start_with_p(VALUE re, VALUE str)
VALUE
rb_reg_nth_defined(int nth, VALUE match)
{
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (nth >= regs->num_regs) {
+ int num_regs = RMATCH_NREGS(match);
+ if (nth >= num_regs) {
return Qnil;
}
if (nth < 0) {
- nth += regs->num_regs;
+ nth += num_regs;
if (nth <= 0) return Qnil;
}
- return RBOOL(BEG(nth) != -1);
+ return RBOOL(RMATCH_BEG(match, nth) != -1);
}
VALUE
@@ -1927,21 +1970,20 @@ rb_reg_nth_match(int nth, VALUE match)
{
VALUE str;
long start, end, len;
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (nth >= regs->num_regs) {
+ int num_regs = RMATCH_NREGS(match);
+ if (nth >= num_regs) {
return Qnil;
}
if (nth < 0) {
- nth += regs->num_regs;
+ nth += num_regs;
if (nth <= 0) return Qnil;
}
- start = BEG(nth);
+ start = RMATCH_BEG(match, nth);
if (start == -1) return Qnil;
- end = END(nth);
+ end = RMATCH_END(match, nth);
len = end - start;
str = rb_str_subseq(RMATCH(match)->str, start, len);
return str;
@@ -1975,13 +2017,11 @@ VALUE
rb_reg_match_pre(VALUE match)
{
VALUE str;
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return Qnil;
- str = rb_str_subseq(RMATCH(match)->str, 0, BEG(0));
+ if (RMATCH_BEG(match, 0) == -1) return Qnil;
+ str = rb_str_subseq(RMATCH(match)->str, 0, RMATCH_BEG(match, 0));
return str;
}
@@ -2009,14 +2049,12 @@ rb_reg_match_post(VALUE match)
{
VALUE str;
long pos;
- struct re_registers *regs;
if (NIL_P(match)) return Qnil;
match_check(match);
- regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return Qnil;
+ if (RMATCH_BEG(match, 0) == -1) return Qnil;
str = RMATCH(match)->str;
- pos = END(0);
+ pos = RMATCH_END(match, 0);
str = rb_str_subseq(str, pos, RSTRING_LEN(str) - pos);
return str;
}
@@ -2025,14 +2063,12 @@ static int
match_last_index(VALUE match)
{
int i;
- struct re_registers *regs;
if (NIL_P(match)) return -1;
match_check(match);
- regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return -1;
+ if (RMATCH_BEG(match, 0) == -1) return -1;
- for (i=regs->num_regs-1; BEG(i) == -1 && i > 0; i--)
+ for (i = RMATCH_NREGS(match) - 1; RMATCH_BEG(match, i) == -1 && i > 0; i--)
;
return i;
}
@@ -2042,8 +2078,8 @@ 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));
+ long start = RMATCH_BEG(match, i);
+ return rb_str_subseq(RMATCH(match)->str, start, RMATCH_END(match, i) - start);
}
VALUE
@@ -2081,22 +2117,22 @@ last_paren_match_getter(ID _x, VALUE *_y)
static VALUE
match_array(VALUE match, int start)
{
- struct re_registers *regs;
VALUE ary;
VALUE target;
int i;
match_check(match);
- regs = RMATCH_REGS(match);
- ary = rb_ary_new2(regs->num_regs);
+ int num_regs = RMATCH_NREGS(match);
+ ary = rb_ary_new2(num_regs);
target = RMATCH(match)->str;
- for (i=start; i<regs->num_regs; i++) {
- if (regs->beg[i] == -1) {
+ for (i = start; i < num_regs; i++) {
+ long beg = RMATCH_BEG(match, i);
+ if (beg == -1) {
rb_ary_push(ary, Qnil);
}
else {
- VALUE str = rb_str_subseq(target, regs->beg[i], regs->end[i]-regs->beg[i]);
+ VALUE str = rb_str_subseq(target, beg, RMATCH_END(match, i) - beg);
rb_ary_push(ary, str);
}
}
@@ -2147,7 +2183,7 @@ match_captures(VALUE match)
}
static int
-name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name, const char* name_end)
+name_to_backref_number(const struct re_registers *regs, VALUE regexp, const char* name, const char* name_end)
{
if (NIL_P(regexp)) return -1;
return onig_name_to_backref_number(RREGEXP_PTR(regexp),
@@ -2160,7 +2196,27 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
name_to_backref_number((regs), (re), (name_ptr), (name_end)))
static int
-namev_to_backref_number(struct re_registers *regs, VALUE re, VALUE name)
+match_name_to_backref_number(VALUE match, VALUE name)
+{
+ VALUE regexp = RMATCH(match)->regexp;
+ if (NIL_P(regexp)) return -1;
+
+ int *nums;
+ int n = onig_name_to_group_numbers(RREGEXP_PTR(regexp),
+ (const unsigned char *)RSTRING_PTR(name),
+ (const unsigned char *)RSTRING_END(name), &nums);
+ if (n < 0) return n;
+ if (n == 0) return ONIGERR_PARSER_BUG;
+ if (n == 1) return nums[0];
+ for (int i = n - 1; i >= 0; i--) {
+ if (RMATCH_BEG(match, nums[i]) != ONIG_REGION_NOTPOS)
+ return nums[i];
+ }
+ return nums[n - 1];
+}
+
+static int
+namev_to_backref_number(VALUE match, VALUE name)
{
int num;
@@ -2170,8 +2226,14 @@ namev_to_backref_number(struct re_registers *regs, VALUE re, VALUE name)
else if (!RB_TYPE_P(name, T_STRING)) {
return -1;
}
- num = NAME_TO_NUMBER(regs, re, name,
- RSTRING_PTR(name), RSTRING_END(name));
+
+ VALUE re = RMATCH(match)->regexp;
+ if (NIL_P(re) || !rb_enc_compatible(RREGEXP_SRC(re), name)) {
+ num = 0;
+ }
+ else {
+ num = match_name_to_backref_number(match, name);
+ }
if (num < 1) {
name_to_backref_error(name);
}
@@ -2181,7 +2243,7 @@ namev_to_backref_number(struct re_registers *regs, VALUE re, VALUE name)
static VALUE
match_ary_subseq(VALUE match, long beg, long len, VALUE result)
{
- long olen = RMATCH_REGS(match)->num_regs;
+ long olen = RMATCH_NREGS(match);
long j, end = olen < beg+len ? olen : beg+len;
if (NIL_P(result)) result = rb_ary_new_capa(len);
if (len == 0) return result;
@@ -2199,7 +2261,7 @@ static VALUE
match_ary_aref(VALUE match, VALUE idx, VALUE result)
{
long beg, len;
- int num_regs = RMATCH_REGS(match)->num_regs;
+ int num_regs = RMATCH_NREGS(match);
/* check if idx is Range */
switch (rb_range_beg_len(idx, &beg, &len, (long)num_regs, !NIL_P(result))) {
@@ -2216,12 +2278,12 @@ match_ary_aref(VALUE match, VALUE idx, VALUE result)
/*
* call-seq:
- * matchdata[index] -> string or nil
- * matchdata[start, length] -> array
- * matchdata[range] -> array
- * matchdata[name] -> string or nil
+ * self[offset] -> string or nil
+ * self[offset, size] -> array
+ * self[range] -> array
+ * self[name] -> string or nil
*
- * When arguments +index+, +start and +length+, or +range+ are given,
+ * When arguments +offset+, +offset+ and +size+, or +range+ are given,
* returns match and captures in the style of Array#[]:
*
* m = /(.)(.)(\d+)(\d)/.match("THX1138.")
@@ -2265,7 +2327,7 @@ match_aref(int argc, VALUE *argv, VALUE match)
return rb_reg_nth_match(FIX2INT(idx), match);
}
else {
- int num = namev_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, idx);
+ int num = namev_to_backref_number(match, idx);
if (num >= 0) {
return rb_reg_nth_match(num, match);
}
@@ -2277,7 +2339,7 @@ match_aref(int argc, VALUE *argv, VALUE match)
else {
long beg = NUM2LONG(idx);
long len = NUM2LONG(length);
- long num_regs = RMATCH_REGS(match)->num_regs;
+ long num_regs = RMATCH_NREGS(match);
if (len < 0) {
return Qnil;
}
@@ -2335,7 +2397,7 @@ match_values_at(int argc, VALUE *argv, VALUE match)
rb_ary_push(result, rb_reg_nth_match(FIX2INT(argv[i]), match));
}
else {
- int num = namev_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, argv[i]);
+ int num = namev_to_backref_number(match, argv[i]);
if (num >= 0) {
rb_ary_push(result, rb_reg_nth_match(num, match));
}
@@ -2375,18 +2437,23 @@ match_to_s(VALUE match)
return str;
}
+struct named_captures_data {
+ VALUE hash;
+ VALUE match;
+ int symbolize;
+};
+
static int
match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
int back_num, int *back_refs, OnigRegex regex, void *arg)
{
- struct MEMO *memo = MEMO_CAST(arg);
- VALUE hash = memo->v1;
- VALUE match = memo->v2;
- long symbolize = memo->u3.state;
+ struct named_captures_data *data = arg;
+ VALUE hash = data->hash;
+ VALUE match = data->match;
VALUE key = rb_enc_str_new((const char *)name, name_end-name, regex->enc);
- if (symbolize > 0) {
+ if (data->symbolize) {
key = rb_str_intern(key);
}
@@ -2446,14 +2513,13 @@ static VALUE
match_named_captures(int argc, VALUE *argv, VALUE match)
{
VALUE hash;
- struct MEMO *memo;
match_check(match);
if (NIL_P(RMATCH(match)->regexp))
return rb_hash_new();
VALUE opt;
- VALUE symbolize_names = 0;
+ int symbolize_names = 0;
rb_scan_args(argc, argv, "0:", &opt);
@@ -2472,9 +2538,9 @@ match_named_captures(int argc, VALUE *argv, VALUE match)
}
hash = rb_hash_new();
- memo = MEMO_NEW(hash, match, symbolize_names);
+ struct named_captures_data data = { hash, match, symbolize_names };
- onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo);
+ onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, &data);
return hash;
}
@@ -2510,10 +2576,9 @@ match_deconstruct_keys(VALUE match, VALUE keys)
if (NIL_P(keys)) {
h = rb_hash_new_with_size(onig_number_of_names(RREGEXP_PTR(RMATCH(match)->regexp)));
- struct MEMO *memo;
- memo = MEMO_NEW(h, match, 1);
+ struct named_captures_data data = { h, match, 1 };
- onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, (void*)memo);
+ onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, &data);
return h;
}
@@ -2534,8 +2599,7 @@ match_deconstruct_keys(VALUE match, VALUE keys)
name = rb_sym2str(key);
- int num = NAME_TO_NUMBER(RMATCH_REGS(match), RMATCH(match)->regexp, RMATCH(match)->regexp,
- RSTRING_PTR(name), RSTRING_END(name));
+ int num = match_name_to_backref_number(match, name);
if (num >= 0) {
rb_hash_aset(h, key, rb_reg_nth_match(num, match));
@@ -2614,9 +2678,9 @@ match_inspect(VALUE match)
VALUE cname = rb_class_path(rb_obj_class(match));
VALUE str;
int i;
- struct re_registers *regs = RMATCH_REGS(match);
- int num_regs = regs->num_regs;
+ int num_regs = RMATCH_NREGS(match);
struct backref_name_tag *names;
+ VALUE names_obj = Qnil;
VALUE regexp = RMATCH(match)->regexp;
if (regexp == 0) {
@@ -2627,7 +2691,7 @@ match_inspect(VALUE match)
cname, rb_reg_nth_match(0, match));
}
- names = ALLOCA_N(struct backref_name_tag, num_regs);
+ names = RB_ALLOCV_N(struct backref_name_tag, names_obj, num_regs);
MEMZERO(names, struct backref_name_tag, num_regs);
onig_foreach_name(RREGEXP_PTR(regexp),
@@ -2655,6 +2719,7 @@ match_inspect(VALUE match)
}
rb_str_buf_cat2(str, ">");
+ RB_ALLOCV_END(names_obj);
return str;
}
@@ -3273,7 +3338,7 @@ rb_reg_preprocess_dregexp(VALUE ary, int options)
src_enc = rb_enc_get(str);
if (options & ARG_ENCODING_NONE &&
src_enc != ascii8bit) {
- if (str_coderange(str) != ENC_CODERANGE_7BIT)
+ if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT)
rb_raise(rb_eRegexpError, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
else
src_enc = ascii8bit;
@@ -3365,6 +3430,9 @@ rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
options & ARG_REG_OPTION_MASK, err,
sourcefile, sourceline);
if (!re->ptr) return -1;
+ if (RBASIC_CLASS(obj) == rb_cRegexp) {
+ OBJ_FREEZE(obj);
+ }
RB_GC_GUARD(unescaped);
return 0;
}
@@ -3373,10 +3441,13 @@ static void
reg_set_source(VALUE reg, VALUE str, rb_encoding *enc)
{
rb_encoding *regenc = rb_enc_get(reg);
+
if (regenc != enc) {
- str = rb_enc_associate(rb_str_dup(str), enc = regenc);
+ VALUE dup = rb_str_dup(str);
+ str = rb_enc_associate(dup, enc = regenc);
}
- RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, rb_fstring(str));
+ str = rb_fstring(str);
+ RB_OBJ_WRITE(reg, &RREGEXP(reg)->src, str);
}
static int
@@ -3388,7 +3459,7 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
if (options & ARG_ENCODING_NONE) {
rb_encoding *ascii8bit = rb_ascii8bit_encoding();
if (enc != ascii8bit) {
- if (str_coderange(str) != ENC_CODERANGE_7BIT) {
+ if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
errcpy(err, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
return -1;
}
@@ -3401,10 +3472,10 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
return ret;
}
-static VALUE
+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, sizeof(struct RRegexp));
re->ptr = 0;
RB_OBJ_WRITE(re, &re->src, 0);
@@ -3452,11 +3523,12 @@ rb_reg_init_str_enc(VALUE re, VALUE s, rb_encoding *enc, int options)
}
VALUE
-rb_reg_new_ary(VALUE ary, int opt)
+rb_reg_new_from_values(long cnt, const VALUE *elements, int opt)
{
- VALUE re = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
- rb_obj_freeze(re);
- return re;
+ const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, elements);
+ VALUE val = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
+ rb_ary_clear(ary);
+ return val;
}
VALUE
@@ -3490,7 +3562,6 @@ rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
rb_set_errinfo(rb_reg_error_desc(str, options, err));
return Qnil;
}
- rb_obj_freeze(re);
return re;
}
@@ -3499,12 +3570,17 @@ static VALUE reg_cache;
VALUE
rb_reg_regcomp(VALUE str)
{
- if (reg_cache && RREGEXP_SRC_LEN(reg_cache) == RSTRING_LEN(str)
- && ENCODING_GET(reg_cache) == ENCODING_GET(str)
- && memcmp(RREGEXP_SRC_PTR(reg_cache), RSTRING_PTR(str), RSTRING_LEN(str)) == 0)
- return reg_cache;
+ if (rb_ractor_main_p()) {
+ if (reg_cache && RREGEXP_SRC_LEN(reg_cache) == RSTRING_LEN(str)
+ && ENCODING_GET(reg_cache) == ENCODING_GET(str)
+ && memcmp(RREGEXP_SRC_PTR(reg_cache), RSTRING_PTR(str), RSTRING_LEN(str)) == 0)
+ return reg_cache;
- return reg_cache = rb_reg_new_str(str, 0);
+ return reg_cache = rb_reg_new_str(str, 0);
+ }
+ else {
+ return rb_reg_new_str(str, 0);
+ }
}
static st_index_t reg_hash(VALUE re);
@@ -3539,10 +3615,10 @@ reg_hash(VALUE re)
/*
* call-seq:
- * regexp == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +object+ is another \Regexp whose pattern,
- * flags, and encoding are the same as +self+, +false+ otherwise:
+ * Returns whether +other+ is another \Regexp whose pattern,
+ * flags, and encoding are the same as +self+:
*
* /foo/ == Regexp.new('foo') # => true
* /foo/ == /foo/i # => false
@@ -3578,47 +3654,113 @@ rb_reg_equal(VALUE re1, VALUE re2)
static VALUE
match_hash(VALUE match)
{
- const struct re_registers *regs;
st_index_t hashval;
match_check(match);
hashval = rb_hash_start(rb_str_hash(RMATCH(match)->str));
hashval = rb_hash_uint(hashval, reg_hash(match_regexp(match)));
- regs = RMATCH_REGS(match);
- hashval = rb_hash_uint(hashval, regs->num_regs);
- hashval = rb_hash_uint(hashval, rb_memhash(regs->beg, regs->num_regs * sizeof(*regs->beg)));
- hashval = rb_hash_uint(hashval, rb_memhash(regs->end, regs->num_regs * sizeof(*regs->end)));
+ int num_regs = RMATCH_NREGS(match);
+ hashval = rb_hash_uint(hashval, num_regs);
+ hashval = rb_hash_uint(hashval, rb_memhash(RMATCH_BEG_PTR(match), num_regs * sizeof(OnigPosition)));
+ hashval = rb_hash_uint(hashval, rb_memhash(RMATCH_END_PTR(match), num_regs * sizeof(OnigPosition)));
hashval = rb_hash_end(hashval);
return ST2FIX(hashval);
}
/*
* call-seq:
- * matchdata == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +object+ is another \MatchData object
+ * Returns whether +other+ is another \MatchData object
* whose target string, regexp, match, and captures
- * are the same as +self+, +false+ otherwise.
+ * are the same as +self+.
*/
static VALUE
match_equal(VALUE match1, VALUE match2)
{
- const struct re_registers *regs1, *regs2;
-
if (match1 == match2) return Qtrue;
if (!RB_TYPE_P(match2, T_MATCH)) return Qfalse;
if (!RMATCH(match1)->regexp || !RMATCH(match2)->regexp) return Qfalse;
if (!rb_str_equal(RMATCH(match1)->str, RMATCH(match2)->str)) return Qfalse;
if (!rb_reg_equal(match_regexp(match1), match_regexp(match2))) return Qfalse;
- regs1 = RMATCH_REGS(match1);
- regs2 = RMATCH_REGS(match2);
- if (regs1->num_regs != regs2->num_regs) return Qfalse;
- if (memcmp(regs1->beg, regs2->beg, regs1->num_regs * sizeof(*regs1->beg))) return Qfalse;
- if (memcmp(regs1->end, regs2->end, regs1->num_regs * sizeof(*regs1->end))) return Qfalse;
+ int num_regs = RMATCH_NREGS(match1);
+ if (num_regs != RMATCH_NREGS(match2)) return Qfalse;
+ if (memcmp(RMATCH_BEG_PTR(match1), RMATCH_BEG_PTR(match2), num_regs * sizeof(OnigPosition))) return Qfalse;
+ if (memcmp(RMATCH_END_PTR(match1), RMATCH_END_PTR(match2), num_regs * sizeof(OnigPosition))) return Qfalse;
return Qtrue;
}
+/*
+ * call-seq:
+ * integer_at(index, base = 10) -> integer or nil
+ * integer_at(name, base = 10) -> integer or nil
+ *
+ * Converts the matched substring to integer and return the result.
+ * +$~.integer_at(N)+ is equivalent to +$N&.to_i+.
+ *
+ * m = /(\d+{4})(\d+{2})(\d+{2})/.match("20260308")
+ * # => #<MatchData "20260308" 1:"2026" 2:"03" 3:"08">
+ * m.integer_at(0) # => 20260308
+ * m.integer_at(1) # => 2026
+ * m.integer_at(2) # => 3
+ * m.integer_at(3) # => 8
+ *
+ * m = /(?<y>\d+{4})(?<m>\d+{2})(?<d>\d+{2})/.match("20260308")
+ * m.integer_at("y") # => 2026
+ * m.integer_at("m") # => 3
+ * m.integer_at("d") # => 8
+ *
+ * If the substring does not match, returns +nil+.
+ *
+ * re = /(\d+)?/
+ * re.match("123").integer_at(1) #=> 123
+ * re.match("abc").integer_at(1) #=> nil
+ *
+ * The string is converted in decimal by default.
+ *
+ * /\d+/.match("011").integer_at(0) #=> 10
+ * /\d+/.match("011").integer_at(0, 12) #=> 13
+ * /\d+/.match("011").integer_at(0, 0) #=> 9
+ *
+ * See also MatchData#[], String#to_i.
+ */
+static VALUE
+match_integer_at(int argc, VALUE *argv, VALUE match)
+{
+ match_check(match);
+
+ int base = 10;
+ VALUE idx;
+ int nth;
+
+ argc = rb_check_arity(argc, 1, 2);
+ if (FIXNUM_P(idx = argv[0])) {
+ nth = NUM2INT(idx);
+ }
+ else if ((nth = namev_to_backref_number(match, idx)) < 0) {
+ name_to_backref_error(idx);
+ }
+
+ if (argc > 1 && (base = NUM2INT(argv[1])) < 0) {
+ rb_raise(rb_eArgError, "invalid radix %d", base);
+ }
+
+ if (nth >= RMATCH_NREGS(match)) return Qnil;
+ if (nth < 0 && (nth += RMATCH_NREGS(match)) <= 0) return Qnil;
+
+ long start = RMATCH_BEG(match, nth), end = RMATCH_END(match, nth);
+ if (start < 0) return Qnil;
+ RUBY_ASSERT(start <= end, "%ld > %ld", start, end);
+
+ VALUE str = RMATCH(match)->str;
+ RUBY_ASSERT(end <= RSTRING_LEN(str), "%ld > %ld", end, RSTRING_LEN(str));
+
+ char *endp;
+ return rb_int_parse_cstr(RSTRING_PTR(str) + start, end - start, &endp, NULL,
+ base, RB_INT_PARSE_DEFAULT);
+}
+
static VALUE
reg_operand(VALUE s, int check)
{
@@ -3658,12 +3800,11 @@ reg_match_pos(VALUE re, VALUE *strp, long pos, VALUE* set_match)
/*
* call-seq:
- * regexp =~ string -> integer or nil
+ * self =~ other -> integer or nil
*
* 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]:
+ * for +self+ and +other+, or +nil+ if none;
+ * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
*
* /at/ =~ 'input data' # => 7
* $~ # => #<MatchData "at">
@@ -3723,9 +3864,9 @@ rb_reg_match(VALUE re, VALUE str)
/*
* call-seq:
- * regexp === string -> true or false
+ * self === other -> true or false
*
- * Returns +true+ if +self+ finds a match in +string+:
+ * Returns whether +self+ finds a match in +other+:
*
* /^[a-z]*$/ === 'HELLO' # => false
* /^[A-Z]*$/ === 'HELLO' # => true
@@ -3931,7 +4072,7 @@ static void
set_timeout(rb_hrtime_t *hrt, VALUE timeout)
{
double timeout_d = NIL_P(timeout) ? 0.0 : NUM2DBL(timeout);
- if (!NIL_P(timeout) && timeout_d <= 0) {
+ if (!NIL_P(timeout) && !(timeout_d > 0)) {
rb_raise(rb_eArgError, "invalid timeout: %"PRIsVALUE, timeout);
}
double2hrtime(hrt, timeout_d);
@@ -3953,6 +4094,9 @@ reg_copy(VALUE copy, VALUE orig)
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));
+ if (RBASIC_CLASS(copy) == rb_cRegexp) {
+ OBJ_FREEZE(copy);
+ }
return copy;
}
@@ -3966,7 +4110,6 @@ struct reg_init_args {
static VALUE reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args);
static VALUE reg_init_args(VALUE self, VALUE str, rb_encoding *enc, int flags);
-void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const char *suggest, ...);
/*
* call-seq:
@@ -4036,6 +4179,9 @@ rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
}
set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
+ if (RBASIC_CLASS(self) == rb_cRegexp) {
+ OBJ_FREEZE(self);
+ }
return self;
}
@@ -4459,8 +4605,8 @@ rb_reg_init_copy(VALUE copy, VALUE re)
return reg_copy(copy, re);
}
-VALUE
-rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
+static VALUE
+do_regsub(VALUE str, VALUE src, VALUE regexp, int num_regs, const OnigPosition *beg, const OnigPosition *end)
{
VALUE val = 0;
char *p, *s, *e;
@@ -4527,7 +4673,13 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
if (name_end < e) {
VALUE n = rb_str_subseq(str, (long)(name - RSTRING_PTR(str)),
(long)(name_end - name));
- if ((no = NAME_TO_NUMBER(regs, regexp, n, name, name_end)) < 1) {
+ struct re_registers tmp = {
+ .allocated = num_regs,
+ .num_regs = num_regs,
+ .beg = (OnigPosition *)beg,
+ .end = (OnigPosition *)end,
+ };
+ if ((no = NAME_TO_NUMBER(&tmp, regexp, n, name, name_end)) < 1) {
name_to_backref_error(n);
}
p = s = name_end + clen;
@@ -4547,16 +4699,16 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
break;
case '`':
- rb_enc_str_buf_cat(val, RSTRING_PTR(src), BEG(0), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_PTR(src), beg[0], src_enc);
continue;
case '\'':
- rb_enc_str_buf_cat(val, RSTRING_PTR(src)+END(0), RSTRING_LEN(src)-END(0), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_PTR(src)+end[0], RSTRING_LEN(src)-end[0], src_enc);
continue;
case '+':
- no = regs->num_regs-1;
- while (BEG(no) == -1 && no > 0) no--;
+ no = num_regs-1;
+ while (beg[no] == -1 && no > 0) no--;
if (no == 0) continue;
break;
@@ -4570,9 +4722,9 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
}
if (no >= 0) {
- if (no >= regs->num_regs) continue;
- if (BEG(no) == -1) continue;
- rb_enc_str_buf_cat(val, RSTRING_PTR(src)+BEG(no), END(no)-BEG(no), src_enc);
+ if (no >= num_regs) continue;
+ if (beg[no] == -1) continue;
+ rb_enc_str_buf_cat(val, RSTRING_PTR(src)+beg[no], end[no]-beg[no], src_enc);
}
}
@@ -4582,6 +4734,20 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
}
return val;
+#undef ASCGET
+}
+
+VALUE
+rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
+{
+ return do_regsub(str, src, regexp, regs->num_regs, regs->beg, regs->end);
+}
+
+VALUE
+rb_reg_regsub_match(VALUE str, VALUE src, VALUE match)
+{
+ return do_regsub(str, src, RMATCH(match)->regexp,
+ RMATCH_NREGS(match), RMATCH_BEG_PTR(match), RMATCH_END_PTR(match));
}
static VALUE
@@ -4815,6 +4981,11 @@ Init_Regexp(void)
rb_gvar_ractor_local("$`");
rb_gvar_ractor_local("$'");
rb_gvar_ractor_local("$+");
+ rb_gvar_box_dynamic("$~");
+ rb_gvar_box_ready("$&");
+ rb_gvar_box_ready("$`");
+ rb_gvar_box_ready("$'");
+ rb_gvar_box_ready("$+");
rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter);
@@ -4849,6 +5020,7 @@ Init_Regexp(void)
rb_define_method(rb_cRegexp, "named_captures", rb_reg_named_captures, 0);
rb_define_method(rb_cRegexp, "timeout", rb_reg_timeout_get, 0);
+ /* Raised when regexp matching timed out. */
rb_eRegexpTimeoutError = rb_define_class_under(rb_cRegexp, "TimeoutError", rb_eRegexpError);
rb_define_singleton_method(rb_cRegexp, "timeout", rb_reg_s_timeout_get, 0);
rb_define_singleton_method(rb_cRegexp, "timeout=", rb_reg_s_timeout_set, 1);
@@ -4899,4 +5071,5 @@ Init_Regexp(void)
rb_define_method(rb_cMatch, "hash", match_hash, 0);
rb_define_method(rb_cMatch, "eql?", match_equal, 1);
rb_define_method(rb_cMatch, "==", match_equal, 1);
+ rb_define_method(rb_cMatch, "integer_at", match_integer_at, -1);
}
diff --git a/regcomp.c b/regcomp.c
index 38bfed5631..1895ac24ed 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -2,8 +2,8 @@
regcomp.c - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2013 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2018 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -394,6 +394,7 @@ compile_tree_empty_check(Node* node, regex_t* reg, int empty_info)
r = add_mem_num(reg, reg->num_null_check); /* NULL CHECK ID */
if (r) return r;
reg->num_null_check++;
+ if ((MemNumType)reg->num_null_check <= 0) return ONIGERR_TOO_MANY_NULL_CHECK;
}
r = compile_tree(node, reg);
@@ -640,17 +641,17 @@ compile_cclass_node(CClassNode* cc, regex_t* reg)
else {
if (ONIGENC_MBC_MINLEN(reg->enc) > 1 || bitset_is_empty(cc->bs)) {
if (IS_NCCLASS_NOT(cc))
- add_opcode(reg, OP_CCLASS_MB_NOT);
+ add_opcode(reg, OP_CCLASS_MB_NOT);
else
- add_opcode(reg, OP_CCLASS_MB);
+ add_opcode(reg, OP_CCLASS_MB);
r = add_multi_byte_cclass(cc->mbuf, reg);
}
else {
if (IS_NCCLASS_NOT(cc))
- add_opcode(reg, OP_CCLASS_MIX_NOT);
+ add_opcode(reg, OP_CCLASS_MIX_NOT);
else
- add_opcode(reg, OP_CCLASS_MIX);
+ add_opcode(reg, OP_CCLASS_MIX);
r = add_bitset(reg, cc->bs);
if (r) return r;
@@ -703,6 +704,7 @@ compile_range_repeat_node(QtfrNode* qn, int target_len, int empty_info,
if (r) return r;
r = add_mem_num(reg, num_repeat); /* OP_REPEAT ID */
reg->num_repeat++;
+ if ((MemNumType)reg->num_repeat <= 0) return ONIGERR_TOO_MANY_RANGE_REPEAT;
if (r) return r;
r = add_rel_addr(reg, target_len + SIZE_OP_REPEAT_INC);
if (r) return r;
@@ -762,9 +764,9 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg)
if (NTYPE(qn->target) == NT_CANY) {
if (qn->greedy && infinite) {
if (IS_NOT_NULL(qn->next_head_exact) && !CKN_ON)
- return SIZE_OP_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower + cklen;
+ return SIZE_OP_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower + cklen;
else
- return SIZE_OP_ANYCHAR_STAR + tlen * qn->lower + cklen;
+ return SIZE_OP_ANYCHAR_STAR + tlen * qn->lower + cklen;
}
}
@@ -776,17 +778,17 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg)
if (infinite && qn->lower <= 1) {
if (qn->greedy) {
if (qn->lower == 1)
- len = SIZE_OP_JUMP;
+ len = SIZE_OP_JUMP;
else
- len = 0;
+ len = 0;
len += SIZE_OP_PUSH + cklen + mod_tlen + SIZE_OP_JUMP;
}
else {
if (qn->lower == 0)
- len = SIZE_OP_JUMP;
+ len = SIZE_OP_JUMP;
else
- len = 0;
+ len = 0;
len += mod_tlen + SIZE_OP_PUSH + cklen;
}
@@ -800,10 +802,10 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg)
else if (qn->upper == 1 && qn->greedy) {
if (qn->lower == 0) {
if (CKN_ON) {
- len = SIZE_OP_STATE_CHECK_PUSH + tlen;
+ len = SIZE_OP_STATE_CHECK_PUSH + tlen;
}
else {
- len = SIZE_OP_PUSH + tlen;
+ len = SIZE_OP_PUSH + tlen;
}
}
else {
@@ -841,31 +843,31 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
if (r) return r;
if (IS_NOT_NULL(qn->next_head_exact) && !CKN_ON) {
if (IS_MULTILINE(reg->options))
- r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT);
+ r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT);
else
- r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT);
+ r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT);
if (r) return r;
if (CKN_ON) {
- r = add_state_check_num(reg, ckn);
- if (r) return r;
+ r = add_state_check_num(reg, ckn);
+ if (r) return r;
}
return add_bytes(reg, NSTR(qn->next_head_exact)->s, 1);
}
else {
if (IS_MULTILINE(reg->options)) {
- r = add_opcode(reg, (CKN_ON ?
- OP_STATE_CHECK_ANYCHAR_ML_STAR
- : OP_ANYCHAR_ML_STAR));
+ r = add_opcode(reg, (CKN_ON ?
+ OP_STATE_CHECK_ANYCHAR_ML_STAR
+ : OP_ANYCHAR_ML_STAR));
}
else {
- r = add_opcode(reg, (CKN_ON ?
- OP_STATE_CHECK_ANYCHAR_STAR
- : OP_ANYCHAR_STAR));
+ r = add_opcode(reg, (CKN_ON ?
+ OP_STATE_CHECK_ANYCHAR_STAR
+ : OP_ANYCHAR_STAR));
}
if (r) return r;
if (CKN_ON)
- r = add_state_check_num(reg, ckn);
+ r = add_state_check_num(reg, ckn);
return r;
}
@@ -879,45 +881,45 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
if (infinite && qn->lower <= 1) {
if (qn->greedy) {
if (qn->lower == 1) {
- r = add_opcode_rel_addr(reg, OP_JUMP,
- (CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH));
- if (r) return r;
+ r = add_opcode_rel_addr(reg, OP_JUMP,
+ (CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH));
+ if (r) return r;
}
if (CKN_ON) {
- r = add_opcode(reg, OP_STATE_CHECK_PUSH);
- if (r) return r;
- r = add_state_check_num(reg, ckn);
- if (r) return r;
- r = add_rel_addr(reg, mod_tlen + SIZE_OP_JUMP);
+ r = add_opcode(reg, OP_STATE_CHECK_PUSH);
+ if (r) return r;
+ r = add_state_check_num(reg, ckn);
+ if (r) return r;
+ r = add_rel_addr(reg, mod_tlen + SIZE_OP_JUMP);
}
else {
- r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP);
+ r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP);
}
if (r) return r;
r = compile_tree_empty_check(qn->target, reg, empty_info);
if (r) return r;
r = add_opcode_rel_addr(reg, OP_JUMP,
- -(mod_tlen + (int )SIZE_OP_JUMP
- + (int )(CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH)));
+ -(mod_tlen + (int )SIZE_OP_JUMP
+ + (int )(CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH)));
}
else {
if (qn->lower == 0) {
- r = add_opcode_rel_addr(reg, OP_JUMP, mod_tlen);
- if (r) return r;
+ r = add_opcode_rel_addr(reg, OP_JUMP, mod_tlen);
+ if (r) return r;
}
r = compile_tree_empty_check(qn->target, reg, empty_info);
if (r) return r;
if (CKN_ON) {
- r = add_opcode(reg, OP_STATE_CHECK_PUSH_OR_JUMP);
- if (r) return r;
- r = add_state_check_num(reg, ckn);
- if (r) return r;
- r = add_rel_addr(reg,
- -(mod_tlen + (int )SIZE_OP_STATE_CHECK_PUSH_OR_JUMP));
+ r = add_opcode(reg, OP_STATE_CHECK_PUSH_OR_JUMP);
+ if (r) return r;
+ r = add_state_check_num(reg, ckn);
+ if (r) return r;
+ r = add_rel_addr(reg,
+ -(mod_tlen + (int )SIZE_OP_STATE_CHECK_PUSH_OR_JUMP));
}
else
- r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH));
+ r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH));
}
}
else if (qn->upper == 0) {
@@ -932,14 +934,14 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
else if (qn->upper == 1 && qn->greedy) {
if (qn->lower == 0) {
if (CKN_ON) {
- r = add_opcode(reg, OP_STATE_CHECK_PUSH);
- if (r) return r;
- r = add_state_check_num(reg, ckn);
- if (r) return r;
- r = add_rel_addr(reg, tlen);
+ r = add_opcode(reg, OP_STATE_CHECK_PUSH);
+ if (r) return r;
+ r = add_state_check_num(reg, ckn);
+ if (r) return r;
+ r = add_rel_addr(reg, tlen);
}
else {
- r = add_opcode_rel_addr(reg, OP_PUSH, tlen);
+ r = add_opcode_rel_addr(reg, OP_PUSH, tlen);
}
if (r) return r;
}
@@ -991,9 +993,9 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg)
if (NTYPE(qn->target) == NT_CANY) {
if (qn->greedy && infinite) {
if (IS_NOT_NULL(qn->next_head_exact))
- return SIZE_OP_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower;
+ return SIZE_OP_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower;
else
- return SIZE_OP_ANYCHAR_STAR + tlen * qn->lower;
+ return SIZE_OP_ANYCHAR_STAR + tlen * qn->lower;
}
}
@@ -1014,13 +1016,13 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg)
if (qn->greedy) {
#ifdef USE_OP_PUSH_OR_JUMP_EXACT
if (IS_NOT_NULL(qn->head_exact))
- len += SIZE_OP_PUSH_OR_JUMP_EXACT1 + mod_tlen + SIZE_OP_JUMP;
+ len += SIZE_OP_PUSH_OR_JUMP_EXACT1 + mod_tlen + SIZE_OP_JUMP;
else
#endif
if (IS_NOT_NULL(qn->next_head_exact))
- len += SIZE_OP_PUSH_IF_PEEK_NEXT + mod_tlen + SIZE_OP_JUMP;
+ len += SIZE_OP_PUSH_IF_PEEK_NEXT + mod_tlen + SIZE_OP_JUMP;
else
- len += SIZE_OP_PUSH + mod_tlen + SIZE_OP_JUMP;
+ len += SIZE_OP_PUSH + mod_tlen + SIZE_OP_JUMP;
}
else
len += SIZE_OP_JUMP + mod_tlen + SIZE_OP_PUSH;
@@ -1060,17 +1062,17 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
if (r) return r;
if (IS_NOT_NULL(qn->next_head_exact)) {
if (IS_MULTILINE(reg->options))
- r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT);
+ r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT);
else
- r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT);
+ r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT);
if (r) return r;
return add_bytes(reg, NSTR(qn->next_head_exact)->s, 1);
}
else {
if (IS_MULTILINE(reg->options))
- return add_opcode(reg, OP_ANYCHAR_ML_STAR);
+ return add_opcode(reg, OP_ANYCHAR_ML_STAR);
else
- return add_opcode(reg, OP_ANYCHAR_STAR);
+ return add_opcode(reg, OP_ANYCHAR_STAR);
}
}
@@ -1084,17 +1086,17 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
if (qn->lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
if (qn->greedy) {
#ifdef USE_OP_PUSH_OR_JUMP_EXACT
- if (IS_NOT_NULL(qn->head_exact))
- r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_OR_JUMP_EXACT1);
- else
+ if (IS_NOT_NULL(qn->head_exact))
+ r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_OR_JUMP_EXACT1);
+ else
#endif
- if (IS_NOT_NULL(qn->next_head_exact))
- r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_IF_PEEK_NEXT);
- else
- r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH);
+ if (IS_NOT_NULL(qn->next_head_exact))
+ r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_IF_PEEK_NEXT);
+ else
+ r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH);
}
else {
- r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_JUMP);
+ r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_JUMP);
}
if (r) return r;
}
@@ -1106,34 +1108,34 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
if (qn->greedy) {
#ifdef USE_OP_PUSH_OR_JUMP_EXACT
if (IS_NOT_NULL(qn->head_exact)) {
- r = add_opcode_rel_addr(reg, OP_PUSH_OR_JUMP_EXACT1,
- mod_tlen + SIZE_OP_JUMP);
- if (r) return r;
- add_bytes(reg, NSTR(qn->head_exact)->s, 1);
- r = compile_tree_empty_check(qn->target, reg, empty_info);
- if (r) return r;
- r = add_opcode_rel_addr(reg, OP_JUMP,
- -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_OR_JUMP_EXACT1));
+ r = add_opcode_rel_addr(reg, OP_PUSH_OR_JUMP_EXACT1,
+ mod_tlen + SIZE_OP_JUMP);
+ if (r) return r;
+ add_bytes(reg, NSTR(qn->head_exact)->s, 1);
+ r = compile_tree_empty_check(qn->target, reg, empty_info);
+ if (r) return r;
+ r = add_opcode_rel_addr(reg, OP_JUMP,
+ -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_OR_JUMP_EXACT1));
}
else
#endif
if (IS_NOT_NULL(qn->next_head_exact)) {
- r = add_opcode_rel_addr(reg, OP_PUSH_IF_PEEK_NEXT,
- mod_tlen + SIZE_OP_JUMP);
- if (r) return r;
- add_bytes(reg, NSTR(qn->next_head_exact)->s, 1);
- r = compile_tree_empty_check(qn->target, reg, empty_info);
- if (r) return r;
- r = add_opcode_rel_addr(reg, OP_JUMP,
+ r = add_opcode_rel_addr(reg, OP_PUSH_IF_PEEK_NEXT,
+ mod_tlen + SIZE_OP_JUMP);
+ if (r) return r;
+ add_bytes(reg, NSTR(qn->next_head_exact)->s, 1);
+ r = compile_tree_empty_check(qn->target, reg, empty_info);
+ if (r) return r;
+ r = add_opcode_rel_addr(reg, OP_JUMP,
-(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_IF_PEEK_NEXT));
}
else {
- r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP);
- if (r) return r;
- r = compile_tree_empty_check(qn->target, reg, empty_info);
- if (r) return r;
- r = add_opcode_rel_addr(reg, OP_JUMP,
- -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH));
+ r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP);
+ if (r) return r;
+ r = compile_tree_empty_check(qn->target, reg, empty_info);
+ if (r) return r;
+ r = add_opcode_rel_addr(reg, OP_JUMP,
+ -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH));
}
}
else {
@@ -1159,7 +1161,7 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg)
for (i = 0; i < n; i++) {
r = add_opcode_rel_addr(reg, OP_PUSH,
- (n - i) * tlen + (n - i - 1) * SIZE_OP_PUSH);
+ (n - i) * tlen + (n - i - 1) * SIZE_OP_PUSH);
if (r) return r;
r = compile_tree(qn->target, reg);
if (r) return r;
@@ -1246,29 +1248,29 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg)
#ifdef USE_SUBEXP_CALL
if (IS_ENCLOSE_CALLED(node)) {
len = SIZE_OP_MEMORY_START_PUSH + tlen
- + SIZE_OP_CALL + SIZE_OP_JUMP + SIZE_OP_RETURN;
+ + SIZE_OP_CALL + SIZE_OP_JUMP + SIZE_OP_RETURN;
if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum))
- len += (IS_ENCLOSE_RECURSION(node)
- ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH);
+ len += (IS_ENCLOSE_RECURSION(node)
+ ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH);
else
- len += (IS_ENCLOSE_RECURSION(node)
- ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END);
+ len += (IS_ENCLOSE_RECURSION(node)
+ ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END);
}
else if (IS_ENCLOSE_RECURSION(node)) {
len = SIZE_OP_MEMORY_START_PUSH;
len += tlen + (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)
- ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_REC);
+ ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_REC);
}
else
#endif
{
if (BIT_STATUS_AT(reg->bt_mem_start, node->regnum))
- len = SIZE_OP_MEMORY_START_PUSH;
+ len = SIZE_OP_MEMORY_START_PUSH;
else
- len = SIZE_OP_MEMORY_START;
+ len = SIZE_OP_MEMORY_START;
len += tlen + (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)
- ? SIZE_OP_MEMORY_END_PUSH : SIZE_OP_MEMORY_END);
+ ? SIZE_OP_MEMORY_END_PUSH : SIZE_OP_MEMORY_END);
}
break;
@@ -1283,7 +1285,7 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg)
if (tlen < 0) return tlen;
len = tlen * qn->lower
- + SIZE_OP_PUSH + tlen + SIZE_OP_POP + SIZE_OP_JUMP;
+ + SIZE_OP_PUSH + tlen + SIZE_OP_POP + SIZE_OP_JUMP;
}
else {
#endif
@@ -1348,11 +1350,11 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
len = compile_length_tree(node->target, reg);
len += (SIZE_OP_MEMORY_START_PUSH + SIZE_OP_RETURN);
if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum))
- len += (IS_ENCLOSE_RECURSION(node)
- ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH);
+ len += (IS_ENCLOSE_RECURSION(node)
+ ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH);
else
- len += (IS_ENCLOSE_RECURSION(node)
- ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END);
+ len += (IS_ENCLOSE_RECURSION(node)
+ ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END);
r = add_opcode_rel_addr(reg, OP_JUMP, len);
if (r) return r;
@@ -1370,11 +1372,11 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
#ifdef USE_SUBEXP_CALL
if (IS_ENCLOSE_CALLED(node)) {
if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum))
- r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node)
- ? OP_MEMORY_END_PUSH_REC : OP_MEMORY_END_PUSH));
+ r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node)
+ ? OP_MEMORY_END_PUSH_REC : OP_MEMORY_END_PUSH));
else
- r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node)
- ? OP_MEMORY_END_REC : OP_MEMORY_END));
+ r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node)
+ ? OP_MEMORY_END_REC : OP_MEMORY_END));
if (r) return r;
r = add_mem_num(reg, node->regnum);
@@ -1383,9 +1385,9 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
}
else if (IS_ENCLOSE_RECURSION(node)) {
if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum))
- r = add_opcode(reg, OP_MEMORY_END_PUSH_REC);
+ r = add_opcode(reg, OP_MEMORY_END_PUSH_REC);
else
- r = add_opcode(reg, OP_MEMORY_END_REC);
+ r = add_opcode(reg, OP_MEMORY_END_REC);
if (r) return r;
r = add_mem_num(reg, node->regnum);
}
@@ -1393,9 +1395,9 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
#endif
{
if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum))
- r = add_opcode(reg, OP_MEMORY_END_PUSH);
+ r = add_opcode(reg, OP_MEMORY_END_PUSH);
else
- r = add_opcode(reg, OP_MEMORY_END);
+ r = add_opcode(reg, OP_MEMORY_END);
if (r) return r;
r = add_mem_num(reg, node->regnum);
}
@@ -1421,7 +1423,7 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
r = add_opcode(reg, OP_POP);
if (r) return r;
r = add_opcode_rel_addr(reg, OP_JUMP,
- -((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP + (int )SIZE_OP_JUMP));
+ -((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP + (int )SIZE_OP_JUMP));
}
else {
#endif
@@ -1579,11 +1581,11 @@ compile_anchor_node(AnchorNode* node, regex_t* reg)
r = add_opcode(reg, OP_LOOK_BEHIND);
if (r) return r;
if (node->char_len < 0) {
- r = get_char_length_tree(node->target, reg, &n);
- if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ r = get_char_length_tree(node->target, reg, &n);
+ if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
}
else
- n = node->char_len;
+ n = node->char_len;
r = add_length(reg, n);
if (r) return r;
r = compile_tree(node->target, reg);
@@ -1595,14 +1597,14 @@ compile_anchor_node(AnchorNode* node, regex_t* reg)
int n;
len = compile_length_tree(node->target, reg);
r = add_opcode_rel_addr(reg, OP_PUSH_LOOK_BEHIND_NOT,
- len + SIZE_OP_FAIL_LOOK_BEHIND_NOT);
+ len + SIZE_OP_FAIL_LOOK_BEHIND_NOT);
if (r) return r;
if (node->char_len < 0) {
- r = get_char_length_tree(node->target, reg, &n);
- if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ r = get_char_length_tree(node->target, reg, &n);
+ if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
}
else
- n = node->char_len;
+ n = node->char_len;
r = add_length(reg, n);
if (r) return r;
r = compile_tree(node->target, reg);
@@ -1641,10 +1643,10 @@ compile_length_tree(Node* node, regex_t* reg)
int n = 0;
len = 0;
do {
- r = compile_length_tree(NCAR(node), reg);
- if (r < 0) return r;
- len += r;
- n++;
+ r = compile_length_tree(NCAR(node), reg);
+ if (r < 0) return r;
+ len += r;
+ n++;
} while (IS_NOT_NULL(node = NCDR(node)));
r = len;
r += (SIZE_OP_PUSH + SIZE_OP_JUMP) * (n - 1);
@@ -1673,17 +1675,17 @@ compile_length_tree(Node* node, regex_t* reg)
#ifdef USE_BACKREF_WITH_LEVEL
if (IS_BACKREF_NEST_LEVEL(br)) {
- r = SIZE_OPCODE + SIZE_OPTION + SIZE_LENGTH +
+ r = SIZE_OPCODE + SIZE_OPTION + SIZE_LENGTH +
SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
}
else
#endif
if (br->back_num == 1) {
- r = ((!IS_IGNORECASE(reg->options) && br->back_static[0] <= 2)
- ? SIZE_OPCODE : (SIZE_OPCODE + SIZE_MEMNUM));
+ r = ((!IS_IGNORECASE(reg->options) && br->back_static[0] <= 2)
+ ? SIZE_OPCODE : (SIZE_OPCODE + SIZE_MEMNUM));
}
else {
- r = SIZE_OPCODE + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
+ r = SIZE_OPCODE + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
}
}
break;
@@ -1732,26 +1734,26 @@ compile_tree(Node* node, regex_t* reg)
Node* x = node;
len = 0;
do {
- len += compile_length_tree(NCAR(x), reg);
- if (NCDR(x) != NULL) {
- len += SIZE_OP_PUSH + SIZE_OP_JUMP;
- }
+ len += compile_length_tree(NCAR(x), reg);
+ if (NCDR(x) != NULL) {
+ len += SIZE_OP_PUSH + SIZE_OP_JUMP;
+ }
} while (IS_NOT_NULL(x = NCDR(x)));
pos = reg->used + len; /* goal position */
do {
- len = compile_length_tree(NCAR(node), reg);
- if (IS_NOT_NULL(NCDR(node))) {
- r = add_opcode_rel_addr(reg, OP_PUSH, len + SIZE_OP_JUMP);
- if (r) break;
- }
- r = compile_tree(NCAR(node), reg);
- if (r) break;
- if (IS_NOT_NULL(NCDR(node))) {
- len = pos - (reg->used + SIZE_OP_JUMP);
- r = add_opcode_rel_addr(reg, OP_JUMP, len);
- if (r) break;
- }
+ len = compile_length_tree(NCAR(node), reg);
+ if (IS_NOT_NULL(NCDR(node))) {
+ r = add_opcode_rel_addr(reg, OP_PUSH, len + SIZE_OP_JUMP);
+ if (r) break;
+ }
+ r = compile_tree(NCAR(node), reg);
+ if (r) break;
+ if (IS_NOT_NULL(NCDR(node))) {
+ len = pos - (reg->used + SIZE_OP_JUMP);
+ r = add_opcode_rel_addr(reg, OP_JUMP, len);
+ if (r) break;
+ }
} while (IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -1773,18 +1775,18 @@ compile_tree(Node* node, regex_t* reg)
switch (NCTYPE(node)->ctype) {
case ONIGENC_CTYPE_WORD:
- if (NCTYPE(node)->ascii_range != 0) {
- if (NCTYPE(node)->not != 0) op = OP_NOT_ASCII_WORD;
- else op = OP_ASCII_WORD;
- }
- else {
- if (NCTYPE(node)->not != 0) op = OP_NOT_WORD;
- else op = OP_WORD;
- }
- break;
+ if (NCTYPE(node)->ascii_range != 0) {
+ if (NCTYPE(node)->not != 0) op = OP_NOT_ASCII_WORD;
+ else op = OP_ASCII_WORD;
+ }
+ else {
+ if (NCTYPE(node)->not != 0) op = OP_NOT_WORD;
+ else op = OP_WORD;
+ }
+ break;
default:
- return ONIGERR_TYPE_BUG;
- break;
+ return ONIGERR_TYPE_BUG;
+ break;
}
r = add_opcode(reg, op);
}
@@ -1803,58 +1805,58 @@ compile_tree(Node* node, regex_t* reg)
#ifdef USE_BACKREF_WITH_LEVEL
if (IS_BACKREF_NEST_LEVEL(br)) {
- r = add_opcode(reg, OP_BACKREF_WITH_LEVEL);
- if (r) return r;
- r = add_option(reg, (reg->options & ONIG_OPTION_IGNORECASE));
- if (r) return r;
- r = add_length(reg, br->nest_level);
- if (r) return r;
-
- goto add_bacref_mems;
+ r = add_opcode(reg, OP_BACKREF_WITH_LEVEL);
+ if (r) return r;
+ r = add_option(reg, (reg->options & ONIG_OPTION_IGNORECASE));
+ if (r) return r;
+ r = add_length(reg, br->nest_level);
+ if (r) return r;
+
+ goto add_bacref_mems;
}
else
#endif
if (br->back_num == 1) {
- n = br->back_static[0];
- if (IS_IGNORECASE(reg->options)) {
- r = add_opcode(reg, OP_BACKREFN_IC);
- if (r) return r;
- r = add_mem_num(reg, n);
- }
- else {
- switch (n) {
- case 1: r = add_opcode(reg, OP_BACKREF1); break;
- case 2: r = add_opcode(reg, OP_BACKREF2); break;
- default:
- r = add_opcode(reg, OP_BACKREFN);
- if (r) return r;
- r = add_mem_num(reg, n);
- break;
- }
- }
+ n = br->back_static[0];
+ if (IS_IGNORECASE(reg->options)) {
+ r = add_opcode(reg, OP_BACKREFN_IC);
+ if (r) return r;
+ r = add_mem_num(reg, n);
+ }
+ else {
+ switch (n) {
+ case 1: r = add_opcode(reg, OP_BACKREF1); break;
+ case 2: r = add_opcode(reg, OP_BACKREF2); break;
+ default:
+ r = add_opcode(reg, OP_BACKREFN);
+ if (r) return r;
+ r = add_mem_num(reg, n);
+ break;
+ }
+ }
}
else {
- int i;
- int* p;
+ int i;
+ int* p;
- if (IS_IGNORECASE(reg->options)) {
- r = add_opcode(reg, OP_BACKREF_MULTI_IC);
- }
- else {
- r = add_opcode(reg, OP_BACKREF_MULTI);
- }
- if (r) return r;
+ if (IS_IGNORECASE(reg->options)) {
+ r = add_opcode(reg, OP_BACKREF_MULTI_IC);
+ }
+ else {
+ r = add_opcode(reg, OP_BACKREF_MULTI);
+ }
+ if (r) return r;
#ifdef USE_BACKREF_WITH_LEVEL
add_bacref_mems:
#endif
- r = add_length(reg, br->back_num);
- if (r) return r;
- p = BACKREFS_P(br);
- for (i = br->back_num - 1; i >= 0; i--) {
- r = add_mem_num(reg, p[i]);
- if (r) return r;
- }
+ r = add_length(reg, br->back_num);
+ if (r) return r;
+ p = BACKREFS_P(br);
+ for (i = br->back_num - 1; i >= 0; i--) {
+ r = add_mem_num(reg, p[i]);
+ if (r) return r;
+ }
}
}
break;
@@ -1909,7 +1911,7 @@ noname_disable_map(Node** plink, GroupNumRemap* map, int* counter)
Node* old = *ptarget;
r = noname_disable_map(ptarget, map, counter);
if (*ptarget != old && NTYPE(*ptarget) == NT_QTFR) {
- onig_reduce_nested_quantifier(node, *ptarget);
+ onig_reduce_nested_quantifier(node, *ptarget);
}
}
break;
@@ -1918,18 +1920,18 @@ noname_disable_map(Node** plink, GroupNumRemap* map, int* counter)
{
EncloseNode* en = NENCLOSE(node);
if (en->type == ENCLOSE_MEMORY) {
- if (IS_ENCLOSE_NAMED_GROUP(en)) {
- (*counter)++;
- map[en->regnum].new_val = *counter;
- en->regnum = *counter;
- }
- else if (en->regnum != 0) {
- *plink = en->target;
- en->target = NULL_NODE;
- onig_node_free(node);
- r = noname_disable_map(plink, map, counter);
- break;
- }
+ if (IS_ENCLOSE_NAMED_GROUP(en)) {
+ (*counter)++;
+ map[en->regnum].new_val = *counter;
+ en->regnum = *counter;
+ }
+ else if (en->regnum != 0) {
+ *plink = en->target;
+ en->target = NULL_NODE;
+ onig_node_free(node);
+ r = noname_disable_map(plink, map, counter);
+ break;
+ }
}
r = noname_disable_map(&(en->target), map, counter);
}
@@ -1995,8 +1997,8 @@ renumber_by_map(Node* node, GroupNumRemap* map, const int num_mem)
{
EncloseNode* en = NENCLOSE(node);
if (en->type == ENCLOSE_CONDITION) {
- if (en->regnum > num_mem) return ONIGERR_INVALID_BACKREF;
- en->regnum = map[en->regnum].new_val;
+ if (en->regnum > num_mem) return ONIGERR_INVALID_BACKREF;
+ en->regnum = map[en->regnum].new_val;
}
r = renumber_by_map(en->target, map, num_mem);
}
@@ -2127,8 +2129,8 @@ quantifiers_memory_node_info(Node* node)
{
int v;
do {
- v = quantifiers_memory_node_info(NCAR(node));
- if (v > r) r = v;
+ v = quantifiers_memory_node_info(NCAR(node));
+ if (v > r) r = v;
} while (v >= 0 && IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -2147,7 +2149,7 @@ quantifiers_memory_node_info(Node* node)
{
QtfrNode* qn = NQTFR(node);
if (qn->upper != 0) {
- r = quantifiers_memory_node_info(qn->target);
+ r = quantifiers_memory_node_info(qn->target);
}
}
break;
@@ -2157,17 +2159,17 @@ quantifiers_memory_node_info(Node* node)
EncloseNode* en = NENCLOSE(node);
switch (en->type) {
case ENCLOSE_MEMORY:
- return NQ_TARGET_IS_EMPTY_MEM;
- break;
+ return NQ_TARGET_IS_EMPTY_MEM;
+ break;
case ENCLOSE_OPTION:
case ENCLOSE_STOP_BACKTRACK:
case ENCLOSE_CONDITION:
case ENCLOSE_ABSENT:
- r = quantifiers_memory_node_info(en->target);
- break;
+ r = quantifiers_memory_node_info(en->target);
+ break;
default:
- break;
+ break;
}
}
break;
@@ -2207,10 +2209,10 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env)
r = get_min_match_length(nodes[backs[0]], min, env);
if (r != 0) break;
for (i = 1; i < br->back_num; i++) {
- if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
- r = get_min_match_length(nodes[backs[i]], &tmin, env);
- if (r != 0) break;
- if (*min > tmin) *min = tmin;
+ if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
+ r = get_min_match_length(nodes[backs[i]], &tmin, env);
+ if (r != 0) break;
+ if (*min > tmin) *min = tmin;
}
}
break;
@@ -2220,7 +2222,7 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env)
if (IS_CALL_RECURSION(NCALL(node))) {
EncloseNode* en = NENCLOSE(NCALL(node)->target);
if (IS_ENCLOSE_MIN_FIXED(en))
- *min = en->min_len;
+ *min = en->min_len;
}
else
r = get_min_match_length(NCALL(node)->target, min, env);
@@ -2239,11 +2241,11 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env)
Node *x, *y;
y = node;
do {
- x = NCAR(y);
- r = get_min_match_length(x, &tmin, env);
- if (r != 0) break;
- if (y == node) *min = tmin;
- else if (*min > tmin) *min = tmin;
+ x = NCAR(y);
+ r = get_min_match_length(x, &tmin, env);
+ if (r != 0) break;
+ if (y == node) *min = tmin;
+ else if (*min > tmin) *min = tmin;
} while (r == 0 && IS_NOT_NULL(y = NCDR(y)));
}
break;
@@ -2269,9 +2271,9 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env)
QtfrNode* qn = NQTFR(node);
if (qn->lower > 0) {
- r = get_min_match_length(qn->target, min, env);
- if (r == 0)
- *min = distance_multiply(*min, qn->lower);
+ r = get_min_match_length(qn->target, min, env);
+ if (r == 0)
+ *min = distance_multiply(*min, qn->lower);
}
}
break;
@@ -2284,28 +2286,28 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env)
if (IS_ENCLOSE_MIN_FIXED(en))
*min = en->min_len;
else {
- if (IS_ENCLOSE_MARK1(NENCLOSE(node)))
- *min = 0; /* recursive */
- else {
- SET_ENCLOSE_STATUS(node, NST_MARK1);
- r = get_min_match_length(en->target, min, env);
- CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
- if (r == 0) {
- en->min_len = *min;
- SET_ENCLOSE_STATUS(node, NST_MIN_FIXED);
- }
- }
+ if (IS_ENCLOSE_MARK1(NENCLOSE(node)))
+ *min = 0; /* recursive */
+ else {
+ SET_ENCLOSE_STATUS(node, NST_MARK1);
+ r = get_min_match_length(en->target, min, env);
+ CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
+ if (r == 0) {
+ en->min_len = *min;
+ SET_ENCLOSE_STATUS(node, NST_MIN_FIXED);
+ }
+ }
}
break;
case ENCLOSE_OPTION:
case ENCLOSE_STOP_BACKTRACK:
case ENCLOSE_CONDITION:
- r = get_min_match_length(en->target, min, env);
- break;
+ r = get_min_match_length(en->target, min, env);
+ break;
case ENCLOSE_ABSENT:
- break;
+ break;
}
}
break;
@@ -2330,7 +2332,7 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env)
do {
r = get_max_match_length(NCAR(node), &tmax, env);
if (r == 0)
- *max = distance_add(*max, tmax);
+ *max = distance_add(*max, tmax);
} while (r == 0 && IS_NOT_NULL(node = NCDR(node)));
break;
@@ -2364,15 +2366,15 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env)
Node** nodes = SCANENV_MEM_NODES(env);
BRefNode* br = NBREF(node);
if (br->state & NST_RECURSION) {
- *max = ONIG_INFINITE_DISTANCE;
- break;
+ *max = ONIG_INFINITE_DISTANCE;
+ break;
}
backs = BACKREFS_P(br);
for (i = 0; i < br->back_num; i++) {
- if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
- r = get_max_match_length(nodes[backs[i]], &tmax, env);
- if (r != 0) break;
- if (*max < tmax) *max = tmax;
+ if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
+ r = get_max_match_length(nodes[backs[i]], &tmax, env);
+ if (r != 0) break;
+ if (*max < tmax) *max = tmax;
}
}
break;
@@ -2391,13 +2393,13 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env)
QtfrNode* qn = NQTFR(node);
if (qn->upper != 0) {
- r = get_max_match_length(qn->target, max, env);
- if (r == 0 && *max != 0) {
- if (! IS_REPEAT_INFINITE(qn->upper))
- *max = distance_multiply(*max, qn->upper);
- else
- *max = ONIG_INFINITE_DISTANCE;
- }
+ r = get_max_match_length(qn->target, max, env);
+ if (r == 0 && *max != 0) {
+ if (! IS_REPEAT_INFINITE(qn->upper))
+ *max = distance_multiply(*max, qn->upper);
+ else
+ *max = ONIG_INFINITE_DISTANCE;
+ }
}
}
break;
@@ -2407,31 +2409,31 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env)
EncloseNode* en = NENCLOSE(node);
switch (en->type) {
case ENCLOSE_MEMORY:
- if (IS_ENCLOSE_MAX_FIXED(en))
- *max = en->max_len;
- else {
- if (IS_ENCLOSE_MARK1(NENCLOSE(node)))
- *max = ONIG_INFINITE_DISTANCE;
- else {
- SET_ENCLOSE_STATUS(node, NST_MARK1);
- r = get_max_match_length(en->target, max, env);
- CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
- if (r == 0) {
- en->max_len = *max;
- SET_ENCLOSE_STATUS(node, NST_MAX_FIXED);
- }
- }
- }
- break;
+ if (IS_ENCLOSE_MAX_FIXED(en))
+ *max = en->max_len;
+ else {
+ if (IS_ENCLOSE_MARK1(NENCLOSE(node)))
+ *max = ONIG_INFINITE_DISTANCE;
+ else {
+ SET_ENCLOSE_STATUS(node, NST_MARK1);
+ r = get_max_match_length(en->target, max, env);
+ CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
+ if (r == 0) {
+ en->max_len = *max;
+ SET_ENCLOSE_STATUS(node, NST_MAX_FIXED);
+ }
+ }
+ }
+ break;
case ENCLOSE_OPTION:
case ENCLOSE_STOP_BACKTRACK:
case ENCLOSE_CONDITION:
- r = get_max_match_length(en->target, max, env);
- break;
+ r = get_max_match_length(en->target, max, env);
+ break;
case ENCLOSE_ABSENT:
- break;
+ break;
}
}
break;
@@ -2461,7 +2463,7 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level)
do {
r = get_char_length_tree1(NCAR(node), reg, &tlen, level);
if (r == 0)
- *len = (int )distance_add(*len, tlen);
+ *len = (int )distance_add(*len, tlen);
} while (r == 0 && IS_NOT_NULL(node = NCDR(node)));
break;
@@ -2472,21 +2474,21 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level)
r = get_char_length_tree1(NCAR(node), reg, &tlen, level);
while (r == 0 && IS_NOT_NULL(node = NCDR(node))) {
- r = get_char_length_tree1(NCAR(node), reg, &tlen2, level);
- if (r == 0) {
- if (tlen != tlen2)
- varlen = 1;
- }
+ r = get_char_length_tree1(NCAR(node), reg, &tlen2, level);
+ if (r == 0) {
+ if (tlen != tlen2)
+ varlen = 1;
+ }
}
if (r == 0) {
- if (varlen != 0) {
- if (level == 1)
- r = GET_CHAR_LEN_TOP_ALT_VARLEN;
- else
- r = GET_CHAR_LEN_VARLEN;
- }
- else
- *len = tlen;
+ if (varlen != 0) {
+ if (level == 1)
+ r = GET_CHAR_LEN_TOP_ALT_VARLEN;
+ else
+ r = GET_CHAR_LEN_VARLEN;
+ }
+ else
+ *len = tlen;
}
}
break;
@@ -2496,8 +2498,8 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level)
StrNode* sn = NSTR(node);
UChar *s = sn->s;
while (s < sn->end) {
- s += enclen(reg->enc, s, sn->end);
- (*len)++;
+ s += enclen(reg->enc, s, sn->end);
+ (*len)++;
}
}
break;
@@ -2506,12 +2508,12 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level)
{
QtfrNode* qn = NQTFR(node);
if (qn->lower == qn->upper) {
- r = get_char_length_tree1(qn->target, reg, &tlen, level);
- if (r == 0)
- *len = (int )distance_multiply(tlen, qn->lower);
+ r = get_char_length_tree1(qn->target, reg, &tlen, level);
+ if (r == 0)
+ *len = (int )distance_multiply(tlen, qn->lower);
}
else
- r = GET_CHAR_LEN_VARLEN;
+ r = GET_CHAR_LEN_VARLEN;
}
break;
@@ -2539,25 +2541,25 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level)
switch (en->type) {
case ENCLOSE_MEMORY:
#ifdef USE_SUBEXP_CALL
- if (IS_ENCLOSE_CLEN_FIXED(en))
- *len = en->char_len;
- else {
- r = get_char_length_tree1(en->target, reg, len, level);
- if (r == 0) {
- en->char_len = *len;
- SET_ENCLOSE_STATUS(node, NST_CLEN_FIXED);
- }
- }
- break;
+ if (IS_ENCLOSE_CLEN_FIXED(en))
+ *len = en->char_len;
+ else {
+ r = get_char_length_tree1(en->target, reg, len, level);
+ if (r == 0) {
+ en->char_len = *len;
+ SET_ENCLOSE_STATUS(node, NST_CLEN_FIXED);
+ }
+ }
+ break;
#endif
case ENCLOSE_OPTION:
case ENCLOSE_STOP_BACKTRACK:
case ENCLOSE_CONDITION:
- r = get_char_length_tree1(en->target, reg, len, level);
- break;
+ r = get_char_length_tree1(en->target, reg, len, level);
+ break;
case ENCLOSE_ABSENT:
default:
- break;
+ break;
}
}
break;
@@ -2596,29 +2598,29 @@ is_not_included(Node* x, Node* y, regex_t* reg)
{
switch (ytype) {
case NT_CTYPE:
- if (NCTYPE(y)->ctype == NCTYPE(x)->ctype &&
- NCTYPE(y)->not != NCTYPE(x)->not &&
- NCTYPE(y)->ascii_range == NCTYPE(x)->ascii_range)
- return 1;
- else
- return 0;
- break;
+ if (NCTYPE(y)->ctype == NCTYPE(x)->ctype &&
+ NCTYPE(y)->not != NCTYPE(x)->not &&
+ NCTYPE(y)->ascii_range == NCTYPE(x)->ascii_range)
+ return 1;
+ else
+ return 0;
+ break;
case NT_CCLASS:
swap:
- {
- Node* tmp;
- tmp = x; x = y; y = tmp;
- goto retry;
- }
- break;
+ {
+ Node* tmp;
+ tmp = x; x = y; y = tmp;
+ goto retry;
+ }
+ break;
case NT_STR:
- goto swap;
- break;
+ goto swap;
+ break;
default:
- break;
+ break;
}
}
break;
@@ -2628,80 +2630,80 @@ is_not_included(Node* x, Node* y, regex_t* reg)
CClassNode* xc = NCCLASS(x);
switch (ytype) {
case NT_CTYPE:
- switch (NCTYPE(y)->ctype) {
- case ONIGENC_CTYPE_WORD:
- if (NCTYPE(y)->not == 0) {
- if (IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) {
- for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
- if (BITSET_AT(xc->bs, i)) {
- if (NCTYPE(y)->ascii_range) {
- if (IS_CODE_SB_WORD(reg->enc, i)) return 0;
- }
- else {
- if (ONIGENC_IS_CODE_WORD(reg->enc, i)) return 0;
- }
- }
- }
- return 1;
- }
- return 0;
- }
- else {
- if (IS_NOT_NULL(xc->mbuf)) return 0;
- for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
- int is_word;
- if (NCTYPE(y)->ascii_range)
- is_word = IS_CODE_SB_WORD(reg->enc, i);
- else
- is_word = ONIGENC_IS_CODE_WORD(reg->enc, i);
- if (! is_word) {
- if (!IS_NCCLASS_NOT(xc)) {
- if (BITSET_AT(xc->bs, i))
- return 0;
- }
- else {
- if (! BITSET_AT(xc->bs, i))
- return 0;
- }
- }
- }
- return 1;
- }
- break;
-
- default:
- break;
- }
- break;
+ switch (NCTYPE(y)->ctype) {
+ case ONIGENC_CTYPE_WORD:
+ if (NCTYPE(y)->not == 0) {
+ if (IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) {
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ if (BITSET_AT(xc->bs, i)) {
+ if (NCTYPE(y)->ascii_range) {
+ if (IS_CODE_SB_WORD(reg->enc, i)) return 0;
+ }
+ else {
+ if (ONIGENC_IS_CODE_WORD(reg->enc, i)) return 0;
+ }
+ }
+ }
+ return 1;
+ }
+ return 0;
+ }
+ else {
+ if (IS_NOT_NULL(xc->mbuf)) return 0;
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ int is_word;
+ if (NCTYPE(y)->ascii_range)
+ is_word = IS_CODE_SB_WORD(reg->enc, i);
+ else
+ is_word = ONIGENC_IS_CODE_WORD(reg->enc, i);
+ if (! is_word) {
+ if (!IS_NCCLASS_NOT(xc)) {
+ if (BITSET_AT(xc->bs, i))
+ return 0;
+ }
+ else {
+ if (! BITSET_AT(xc->bs, i))
+ return 0;
+ }
+ }
+ }
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
case NT_CCLASS:
- {
- int v;
- CClassNode* yc = NCCLASS(y);
-
- for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
- v = BITSET_AT(xc->bs, i);
- if ((v != 0 && !IS_NCCLASS_NOT(xc)) ||
- (v == 0 && IS_NCCLASS_NOT(xc))) {
- v = BITSET_AT(yc->bs, i);
- if ((v != 0 && !IS_NCCLASS_NOT(yc)) ||
- (v == 0 && IS_NCCLASS_NOT(yc)))
- return 0;
- }
- }
- if ((IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) ||
- (IS_NULL(yc->mbuf) && !IS_NCCLASS_NOT(yc)))
- return 1;
- return 0;
- }
- break;
+ {
+ int v;
+ CClassNode* yc = NCCLASS(y);
+
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ v = BITSET_AT(xc->bs, i);
+ if ((v != 0 && !IS_NCCLASS_NOT(xc)) ||
+ (v == 0 && IS_NCCLASS_NOT(xc))) {
+ v = BITSET_AT(yc->bs, i);
+ if ((v != 0 && !IS_NCCLASS_NOT(yc)) ||
+ (v == 0 && IS_NCCLASS_NOT(yc)))
+ return 0;
+ }
+ }
+ if ((IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) ||
+ (IS_NULL(yc->mbuf) && !IS_NCCLASS_NOT(yc)))
+ return 1;
+ return 0;
+ }
+ break;
case NT_STR:
- goto swap;
- break;
+ goto swap;
+ break;
default:
- break;
+ break;
}
}
break;
@@ -2710,60 +2712,60 @@ is_not_included(Node* x, Node* y, regex_t* reg)
{
StrNode* xs = NSTR(x);
if (NSTRING_LEN(x) == 0)
- break;
+ break;
switch (ytype) {
case NT_CTYPE:
- switch (NCTYPE(y)->ctype) {
- case ONIGENC_CTYPE_WORD:
- if (NCTYPE(y)->ascii_range) {
- if (ONIGENC_IS_MBC_ASCII_WORD(reg->enc, xs->s, xs->end))
- return NCTYPE(y)->not;
- else
- return !(NCTYPE(y)->not);
- }
- else {
- if (ONIGENC_IS_MBC_WORD(reg->enc, xs->s, xs->end))
- return NCTYPE(y)->not;
- else
- return !(NCTYPE(y)->not);
- }
- break;
- default:
- break;
- }
- break;
+ switch (NCTYPE(y)->ctype) {
+ case ONIGENC_CTYPE_WORD:
+ if (NCTYPE(y)->ascii_range) {
+ if (ONIGENC_IS_MBC_ASCII_WORD(reg->enc, xs->s, xs->end))
+ return NCTYPE(y)->not;
+ else
+ return !(NCTYPE(y)->not);
+ }
+ else {
+ if (ONIGENC_IS_MBC_WORD(reg->enc, xs->s, xs->end))
+ return NCTYPE(y)->not;
+ else
+ return !(NCTYPE(y)->not);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
case NT_CCLASS:
- {
- CClassNode* cc = NCCLASS(y);
+ {
+ CClassNode* cc = NCCLASS(y);
- code = ONIGENC_MBC_TO_CODE(reg->enc, xs->s,
- xs->s + ONIGENC_MBC_MAXLEN(reg->enc));
- return (onig_is_code_in_cc(reg->enc, code, cc) != 0 ? 0 : 1);
- }
- break;
+ code = ONIGENC_MBC_TO_CODE(reg->enc, xs->s,
+ xs->s + ONIGENC_MBC_MAXLEN(reg->enc));
+ return (onig_is_code_in_cc(reg->enc, code, cc) != 0 ? 0 : 1);
+ }
+ break;
case NT_STR:
- {
- UChar *q;
- StrNode* ys = NSTR(y);
- len = NSTRING_LEN(x);
- if (len > NSTRING_LEN(y)) len = NSTRING_LEN(y);
- if (NSTRING_IS_AMBIG(x) || NSTRING_IS_AMBIG(y)) {
- /* tiny version */
- return 0;
- }
- else {
- for (i = 0, p = ys->s, q = xs->s; (OnigDistance )i < len; i++, p++, q++) {
- if (*p != *q) return 1;
- }
- }
- }
- break;
+ {
+ UChar *q;
+ StrNode* ys = NSTR(y);
+ len = NSTRING_LEN(x);
+ if (len > NSTRING_LEN(y)) len = NSTRING_LEN(y);
+ if (NSTRING_IS_AMBIG(x) || NSTRING_IS_AMBIG(y)) {
+ /* tiny version */
+ return 0;
+ }
+ else {
+ for (i = 0, p = ys->s, q = xs->s; (OnigDistance )i < len; i++, p++, q++) {
+ if (*p != *q) return 1;
+ }
+ }
+ }
+ break;
default:
- break;
+ break;
}
}
break;
@@ -2803,15 +2805,12 @@ get_head_value_node(Node* node, int exact, regex_t* reg)
case NT_STR:
{
StrNode* sn = NSTR(node);
-
if (sn->end <= sn->s)
- break;
+ break;
- if (exact != 0 &&
- !NSTRING_IS_RAW(node) && IS_IGNORECASE(reg->options)) {
- }
- else {
- n = node;
+ if (exact == 0 ||
+ NSTRING_IS_RAW(node) || !IS_IGNORECASE(reg->options)) {
+ n = node;
}
}
break;
@@ -2821,11 +2820,11 @@ get_head_value_node(Node* node, int exact, regex_t* reg)
QtfrNode* qn = NQTFR(node);
if (qn->lower > 0) {
#ifdef USE_OP_PUSH_OR_JUMP_EXACT
- if (IS_NOT_NULL(qn->head_exact))
- n = qn->head_exact;
- else
+ if (IS_NOT_NULL(qn->head_exact))
+ n = qn->head_exact;
+ else
#endif
- n = get_head_value_node(qn->target, exact, reg);
+ n = get_head_value_node(qn->target, exact, reg);
}
}
break;
@@ -2835,23 +2834,23 @@ get_head_value_node(Node* node, int exact, regex_t* reg)
EncloseNode* en = NENCLOSE(node);
switch (en->type) {
case ENCLOSE_OPTION:
- {
- OnigOptionType options = reg->options;
+ {
+ OnigOptionType options = reg->options;
- reg->options = NENCLOSE(node)->option;
- n = get_head_value_node(NENCLOSE(node)->target, exact, reg);
- reg->options = options;
- }
- break;
+ reg->options = NENCLOSE(node)->option;
+ n = get_head_value_node(NENCLOSE(node)->target, exact, reg);
+ reg->options = options;
+ }
+ break;
case ENCLOSE_MEMORY:
case ENCLOSE_STOP_BACKTRACK:
case ENCLOSE_CONDITION:
- n = get_head_value_node(en->target, exact, reg);
- break;
+ n = get_head_value_node(en->target, exact, reg);
+ break;
case ENCLOSE_ABSENT:
- break;
+ break;
}
}
break;
@@ -2882,20 +2881,20 @@ check_type_tree(Node* node, int type_mask, int enclose_mask, int anchor_mask)
case NT_ALT:
do {
r = check_type_tree(NCAR(node), type_mask, enclose_mask,
- anchor_mask);
+ anchor_mask);
} while (r == 0 && IS_NOT_NULL(node = NCDR(node)));
break;
case NT_QTFR:
r = check_type_tree(NQTFR(node)->target, type_mask, enclose_mask,
- anchor_mask);
+ anchor_mask);
break;
case NT_ENCLOSE:
{
EncloseNode* en = NENCLOSE(node);
if ((en->type & enclose_mask) == 0)
- return 1;
+ return 1;
r = check_type_tree(en->target, type_mask, enclose_mask, anchor_mask);
}
@@ -2908,7 +2907,7 @@ check_type_tree(Node* node, int type_mask, int enclose_mask, int anchor_mask)
if (NANCHOR(node)->target)
r = check_type_tree(NANCHOR(node)->target,
- type_mask, enclose_mask, anchor_mask);
+ type_mask, enclose_mask, anchor_mask);
break;
default:
@@ -2938,14 +2937,14 @@ subexp_inf_recursive_check(Node* node, ScanEnv* env, int head)
x = node;
do {
- ret = subexp_inf_recursive_check(NCAR(x), env, head);
- if (ret < 0 || ret == RECURSION_INFINITE) return ret;
- r |= ret;
- if (head) {
- ret = get_min_match_length(NCAR(x), &min, env);
- if (ret != 0) return ret;
- if (min != 0) head = 0;
- }
+ ret = subexp_inf_recursive_check(NCAR(x), env, head);
+ if (ret < 0 || ret == RECURSION_INFINITE) return ret;
+ r |= ret;
+ if (head) {
+ ret = get_min_match_length(NCAR(x), &min, env);
+ if (ret != 0) return ret;
+ if (min != 0) head = 0;
+ }
} while (IS_NOT_NULL(x = NCDR(x)));
}
break;
@@ -2955,9 +2954,9 @@ subexp_inf_recursive_check(Node* node, ScanEnv* env, int head)
int ret;
r = RECURSION_EXIST;
do {
- ret = subexp_inf_recursive_check(NCAR(node), env, head);
- if (ret < 0 || ret == RECURSION_INFINITE) return ret;
- r &= ret;
+ ret = subexp_inf_recursive_check(NCAR(node), env, head);
+ if (ret < 0 || ret == RECURSION_INFINITE) return ret;
+ r &= ret;
} while (IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -2977,8 +2976,8 @@ subexp_inf_recursive_check(Node* node, ScanEnv* env, int head)
case ANCHOR_PREC_READ_NOT:
case ANCHOR_LOOK_BEHIND:
case ANCHOR_LOOK_BEHIND_NOT:
- r = subexp_inf_recursive_check(an->target, env, head);
- break;
+ r = subexp_inf_recursive_check(an->target, env, head);
+ break;
}
}
break;
@@ -3033,8 +3032,8 @@ subexp_inf_recursive_check_trav(Node* node, ScanEnv* env)
case ANCHOR_PREC_READ_NOT:
case ANCHOR_LOOK_BEHIND:
case ANCHOR_LOOK_BEHIND_NOT:
- r = subexp_inf_recursive_check_trav(an->target, env);
- break;
+ r = subexp_inf_recursive_check_trav(an->target, env);
+ break;
}
}
break;
@@ -3044,10 +3043,10 @@ subexp_inf_recursive_check_trav(Node* node, ScanEnv* env)
EncloseNode* en = NENCLOSE(node);
if (IS_ENCLOSE_RECURSION(en)) {
- SET_ENCLOSE_STATUS(node, NST_MARK1);
- r = subexp_inf_recursive_check(en->target, env, 1);
- if (r > 0) return ONIGERR_NEVER_ENDING_RECURSION;
- CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
+ SET_ENCLOSE_STATUS(node, NST_MARK1);
+ r = subexp_inf_recursive_check(en->target, env, 1);
+ if (r > 0) return ONIGERR_NEVER_ENDING_RECURSION;
+ CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
}
r = subexp_inf_recursive_check_trav(en->target, env);
}
@@ -3086,8 +3085,8 @@ subexp_recursive_check(Node* node)
case ANCHOR_PREC_READ_NOT:
case ANCHOR_LOOK_BEHIND:
case ANCHOR_LOOK_BEHIND_NOT:
- r = subexp_recursive_check(an->target);
- break;
+ r = subexp_recursive_check(an->target);
+ break;
}
}
break;
@@ -3132,9 +3131,9 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env)
{
int ret;
do {
- ret = subexp_recursive_check_trav(NCAR(node), env);
- if (ret == FOUND_CALLED_NODE) r = FOUND_CALLED_NODE;
- else if (ret < 0) return ret;
+ ret = subexp_recursive_check_trav(NCAR(node), env);
+ if (ret == FOUND_CALLED_NODE) r = FOUND_CALLED_NODE;
+ else if (ret < 0) return ret;
} while (IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -3143,7 +3142,7 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env)
r = subexp_recursive_check_trav(NQTFR(node)->target, env);
if (NQTFR(node)->upper == 0) {
if (r == FOUND_CALLED_NODE)
- NQTFR(node)->is_referred = 1;
+ NQTFR(node)->is_referred = 1;
}
break;
@@ -3155,8 +3154,8 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env)
case ANCHOR_PREC_READ_NOT:
case ANCHOR_LOOK_BEHIND:
case ANCHOR_LOOK_BEHIND_NOT:
- r = subexp_recursive_check_trav(an->target, env);
- break;
+ r = subexp_recursive_check_trav(an->target, env);
+ break;
}
}
break;
@@ -3166,16 +3165,16 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env)
EncloseNode* en = NENCLOSE(node);
if (! IS_ENCLOSE_RECURSION(en)) {
- if (IS_ENCLOSE_CALLED(en)) {
- SET_ENCLOSE_STATUS(node, NST_MARK1);
- r = subexp_recursive_check(en->target);
- if (r != 0) SET_ENCLOSE_STATUS(node, NST_RECURSION);
- CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
- }
+ if (IS_ENCLOSE_CALLED(en)) {
+ SET_ENCLOSE_STATUS(node, NST_MARK1);
+ r = subexp_recursive_check(en->target);
+ if (r != 0) SET_ENCLOSE_STATUS(node, NST_RECURSION);
+ CLEAR_ENCLOSE_STATUS(node, NST_MARK1);
+ }
}
r = subexp_recursive_check_trav(en->target, env);
if (IS_ENCLOSE_CALLED(en))
- r |= FOUND_CALLED_NODE;
+ r |= FOUND_CALLED_NODE;
}
break;
@@ -3219,60 +3218,60 @@ setup_subexp_call(Node* node, ScanEnv* env)
Node** nodes = SCANENV_MEM_NODES(env);
if (cn->group_num != 0) {
- int gnum = cn->group_num;
+ int gnum = cn->group_num;
# ifdef USE_NAMED_GROUP
- if (env->num_named > 0 &&
- IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
- !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) {
- return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
- }
+ if (env->num_named > 0 &&
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
+ !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) {
+ return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
+ }
# endif
- if (gnum > env->num_mem) {
- onig_scan_env_set_error_string(env,
- ONIGERR_UNDEFINED_GROUP_REFERENCE, cn->name, cn->name_end);
- return ONIGERR_UNDEFINED_GROUP_REFERENCE;
- }
+ if (gnum > env->num_mem) {
+ onig_scan_env_set_error_string(env,
+ ONIGERR_UNDEFINED_GROUP_REFERENCE, cn->name, cn->name_end);
+ return ONIGERR_UNDEFINED_GROUP_REFERENCE;
+ }
# ifdef USE_NAMED_GROUP
set_call_attr:
# endif
- cn->target = nodes[cn->group_num];
- if (IS_NULL(cn->target)) {
- onig_scan_env_set_error_string(env,
- ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end);
- return ONIGERR_UNDEFINED_NAME_REFERENCE;
- }
- SET_ENCLOSE_STATUS(cn->target, NST_CALLED);
- BIT_STATUS_ON_AT(env->bt_mem_start, cn->group_num);
- cn->unset_addr_list = env->unset_addr_list;
+ cn->target = nodes[cn->group_num];
+ if (IS_NULL(cn->target)) {
+ onig_scan_env_set_error_string(env,
+ ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end);
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+ SET_ENCLOSE_STATUS(cn->target, NST_CALLED);
+ BIT_STATUS_ON_AT(env->bt_mem_start, cn->group_num);
+ cn->unset_addr_list = env->unset_addr_list;
}
# ifdef USE_NAMED_GROUP
# ifdef USE_PERL_SUBEXP_CALL
else if (cn->name == cn->name_end) {
- goto set_call_attr;
+ goto set_call_attr;
}
# endif
else {
- int *refs;
-
- int n = onig_name_to_group_numbers(env->reg, cn->name, cn->name_end,
- &refs);
- if (n <= 0) {
- onig_scan_env_set_error_string(env,
- ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end);
- return ONIGERR_UNDEFINED_NAME_REFERENCE;
- }
- else if (n > 1 &&
- ! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME_CALL)) {
- onig_scan_env_set_error_string(env,
- ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL, cn->name, cn->name_end);
- return ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL;
- }
- else {
- cn->group_num = refs[0];
- goto set_call_attr;
- }
+ int *refs;
+
+ int n = onig_name_to_group_numbers(env->reg, cn->name, cn->name_end,
+ &refs);
+ if (n <= 0) {
+ onig_scan_env_set_error_string(env,
+ ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end);
+ return ONIGERR_UNDEFINED_NAME_REFERENCE;
+ }
+ else if (n > 1 &&
+ ! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME_CALL)) {
+ onig_scan_env_set_error_string(env,
+ ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL, cn->name, cn->name_end);
+ return ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL;
+ }
+ else {
+ cn->group_num = refs[0];
+ goto set_call_attr;
+ }
}
# endif
}
@@ -3287,8 +3286,8 @@ setup_subexp_call(Node* node, ScanEnv* env)
case ANCHOR_PREC_READ_NOT:
case ANCHOR_LOOK_BEHIND:
case ANCHOR_LOOK_BEHIND_NOT:
- r = setup_subexp_call(an->target, env);
- break;
+ r = setup_subexp_call(an->target, env);
+ break;
}
}
break;
@@ -3301,6 +3300,14 @@ setup_subexp_call(Node* node, ScanEnv* env)
}
#endif
+#define IN_ALT (1<<0)
+#define IN_NOT (1<<1)
+#define IN_REPEAT (1<<2)
+#define IN_VAR_REPEAT (1<<3)
+#define IN_CALL (1<<4)
+#define IN_RECCALL (1<<5)
+#define IN_LOOK_BEHIND (1<<6)
+
/* divide different length alternatives in look-behind.
(?<=A|B) ==> (?<=A)|(?<=B)
(?<!A|B) ==> (?<!A)(?<!B)
@@ -3370,26 +3377,26 @@ next_setup(Node* node, Node* next_node, regex_t* reg)
Node* n = get_head_value_node(next_node, 1, reg);
/* '\0': for UTF-16BE etc... */
if (IS_NOT_NULL(n) && NSTR(n)->s[0] != '\0') {
- qn->next_head_exact = n;
+ qn->next_head_exact = n;
}
#endif
/* automatic possessification a*b ==> (?>a*)b */
if (qn->lower <= 1) {
- int ttype = NTYPE(qn->target);
- if (IS_NODE_TYPE_SIMPLE(ttype)) {
- Node *x, *y;
- x = get_head_value_node(qn->target, 0, reg);
- if (IS_NOT_NULL(x)) {
- y = get_head_value_node(next_node, 0, reg);
- if (IS_NOT_NULL(y) && is_not_included(x, y, reg)) {
- Node* en = onig_node_new_enclose(ENCLOSE_STOP_BACKTRACK);
- CHECK_NULL_RETURN_MEMERR(en);
- SET_ENCLOSE_STATUS(en, NST_STOP_BT_SIMPLE_REPEAT);
- swap_node(node, en);
- NENCLOSE(node)->target = en;
- }
- }
- }
+ int ttype = NTYPE(qn->target);
+ if (IS_NODE_TYPE_SIMPLE(ttype)) {
+ Node *x, *y;
+ x = get_head_value_node(qn->target, 0, reg);
+ if (IS_NOT_NULL(x)) {
+ y = get_head_value_node(next_node, 0, reg);
+ if (IS_NOT_NULL(y) && is_not_included(x, y, reg)) {
+ Node* en = onig_node_new_enclose(ENCLOSE_STOP_BACKTRACK);
+ CHECK_NULL_RETURN_MEMERR(en);
+ SET_ENCLOSE_STATUS(en, NST_STOP_BT_SIMPLE_REPEAT);
+ swap_node(node, en);
+ NENCLOSE(node)->target = en;
+ }
+ }
+ }
}
}
}
@@ -3425,15 +3432,15 @@ update_string_node_case_fold(regex_t* reg, Node *node)
len = ONIGENC_MBC_CASE_FOLD(reg->enc, reg->case_fold_flag, &p, end, buf);
for (i = 0; i < len; i++) {
if (sp >= ebuf) {
- UChar* p = (UChar* )xrealloc(sbuf, sbuf_size * 2);
- if (IS_NULL(p)) {
- xfree(sbuf);
- return ONIGERR_MEMORY;
- }
- sbuf = p;
- sp = sbuf + sbuf_size;
- sbuf_size *= 2;
- ebuf = sbuf + sbuf_size;
+ UChar* p = (UChar* )xrealloc(sbuf, sbuf_size * 2);
+ if (IS_NULL(p)) {
+ xfree(sbuf);
+ return ONIGERR_MEMORY;
+ }
+ sbuf = p;
+ sp = sbuf + sbuf_size;
+ sbuf_size *= 2;
+ ebuf = sbuf + sbuf_size;
}
*sp++ = buf[i];
@@ -3448,7 +3455,7 @@ update_string_node_case_fold(regex_t* reg, Node *node)
static int
expand_case_fold_make_rem_string(Node** rnode, UChar *s, UChar *end,
- regex_t* reg)
+ regex_t* reg)
{
int r;
Node *node;
@@ -3470,7 +3477,7 @@ expand_case_fold_make_rem_string(Node** rnode, UChar *s, UChar *end,
static int
is_case_fold_variable_len(int item_num, OnigCaseFoldCodeItem items[],
- int slen)
+ int slen)
{
int i;
@@ -3487,8 +3494,8 @@ is_case_fold_variable_len(int item_num, OnigCaseFoldCodeItem items[],
static int
expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[],
- UChar *p, int slen, UChar *end,
- regex_t* reg, Node **rnode)
+ UChar *p, int slen, UChar *end,
+ regex_t* reg, Node **rnode)
{
int r, i, j, len, varlen;
Node *anode, *var_anode, *snode, *xnode, *an;
@@ -3533,8 +3540,8 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[],
for (j = 0; j < items[i].code_len; j++) {
len = ONIGENC_CODE_TO_MBC(reg->enc, items[i].code[j], buf);
if (len < 0) {
- r = len;
- goto mem_err2;
+ r = len;
+ goto mem_err2;
}
r = onig_node_str_cat(snode, buf, buf + len);
@@ -3551,29 +3558,29 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[],
UChar *q = p + items[i].byte_len;
if (q < end) {
- r = expand_case_fold_make_rem_string(&rem, q, end, reg);
- if (r != 0) {
- onig_node_free(an);
- goto mem_err2;
- }
+ r = expand_case_fold_make_rem_string(&rem, q, end, reg);
+ if (r != 0) {
+ onig_node_free(an);
+ goto mem_err2;
+ }
- xnode = onig_node_list_add(NULL_NODE, snode);
- if (IS_NULL(xnode)) {
- onig_node_free(an);
- onig_node_free(rem);
- goto mem_err2;
- }
- if (IS_NULL(onig_node_list_add(xnode, rem))) {
- onig_node_free(an);
- onig_node_free(xnode);
- onig_node_free(rem);
- goto mem_err;
- }
+ xnode = onig_node_list_add(NULL_NODE, snode);
+ if (IS_NULL(xnode)) {
+ onig_node_free(an);
+ onig_node_free(rem);
+ goto mem_err2;
+ }
+ if (IS_NULL(onig_node_list_add(xnode, rem))) {
+ onig_node_free(an);
+ onig_node_free(xnode);
+ onig_node_free(rem);
+ goto mem_err;
+ }
- NCAR(an) = xnode;
+ NCAR(an) = xnode;
}
else {
- NCAR(an) = snode;
+ NCAR(an) = snode;
}
NCDR(var_anode) = an;
@@ -3597,31 +3604,36 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[],
return ONIGERR_MEMORY;
}
-static int
-expand_case_fold_string(Node* node, regex_t* reg)
-{
#define THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION 8
+static int
+expand_case_fold_string(Node* node, regex_t* reg, int state)
+{
int r, n, len, alt_num;
int varlen = 0;
+ int is_in_look_behind;
UChar *start, *end, *p;
Node *top_root, *root, *snode, *prev_node;
OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
- StrNode* sn = NSTR(node);
+ StrNode* sn;
if (NSTRING_IS_AMBIG(node)) return 0;
+ sn = NSTR(node);
+
start = sn->s;
end = sn->end;
if (start >= end) return 0;
+ is_in_look_behind = (state & IN_LOOK_BEHIND) != 0;
+
r = 0;
top_root = root = prev_node = snode = NULL_NODE;
alt_num = 1;
p = start;
while (p < end) {
n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(reg->enc, reg->case_fold_flag,
- p, end, items);
+ p, end, items);
if (n < 0) {
r = n;
goto err;
@@ -3630,25 +3642,25 @@ expand_case_fold_string(Node* node, regex_t* reg)
len = enclen(reg->enc, p, end);
varlen = is_case_fold_variable_len(n, items, len);
- if (n == 0 || varlen == 0) {
+ if (n == 0 || varlen == 0 || is_in_look_behind) {
if (IS_NULL(snode)) {
- if (IS_NULL(root) && IS_NOT_NULL(prev_node)) {
+ if (IS_NULL(root) && IS_NOT_NULL(prev_node)) {
onig_node_free(top_root);
- top_root = root = onig_node_list_add(NULL_NODE, prev_node);
- if (IS_NULL(root)) {
- onig_node_free(prev_node);
- goto mem_err;
- }
- }
+ top_root = root = onig_node_list_add(NULL_NODE, prev_node);
+ if (IS_NULL(root)) {
+ onig_node_free(prev_node);
+ goto mem_err;
+ }
+ }
- prev_node = snode = onig_node_new_str(NULL, NULL);
- if (IS_NULL(snode)) goto mem_err;
- if (IS_NOT_NULL(root)) {
- if (IS_NULL(onig_node_list_add(root, snode))) {
- onig_node_free(snode);
- goto mem_err;
- }
- }
+ prev_node = snode = onig_node_new_str(NULL, NULL);
+ if (IS_NULL(snode)) goto mem_err;
+ if (IS_NOT_NULL(root)) {
+ if (IS_NULL(onig_node_list_add(root, snode))) {
+ onig_node_free(snode);
+ goto mem_err;
+ }
+ }
}
r = onig_node_str_cat(snode, p, p + len);
@@ -3659,42 +3671,42 @@ expand_case_fold_string(Node* node, regex_t* reg)
if (alt_num > THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION) break;
if (IS_NOT_NULL(snode)) {
- r = update_string_node_case_fold(reg, snode);
- if (r == 0) {
- NSTRING_SET_AMBIG(snode);
- }
+ r = update_string_node_case_fold(reg, snode);
+ if (r == 0) {
+ NSTRING_SET_AMBIG(snode);
+ }
}
if (IS_NULL(root) && IS_NOT_NULL(prev_node)) {
onig_node_free(top_root);
- top_root = root = onig_node_list_add(NULL_NODE, prev_node);
- if (IS_NULL(root)) {
- onig_node_free(prev_node);
- goto mem_err;
- }
+ top_root = root = onig_node_list_add(NULL_NODE, prev_node);
+ if (IS_NULL(root)) {
+ onig_node_free(prev_node);
+ goto mem_err;
+ }
}
r = expand_case_fold_string_alt(n, items, p, len, end, reg, &prev_node);
if (r < 0) goto mem_err;
if (r == 1) {
- if (IS_NULL(root)) {
- top_root = prev_node;
- }
- else {
- if (IS_NULL(onig_node_list_add(root, prev_node))) {
- onig_node_free(prev_node);
- goto mem_err;
- }
- }
+ if (IS_NULL(root)) {
+ top_root = prev_node;
+ }
+ else {
+ if (IS_NULL(onig_node_list_add(root, prev_node))) {
+ onig_node_free(prev_node);
+ goto mem_err;
+ }
+ }
- root = NCAR(prev_node);
+ root = NCAR(prev_node);
}
else { /* r == 0 */
- if (IS_NOT_NULL(root)) {
- if (IS_NULL(onig_node_list_add(root, prev_node))) {
- onig_node_free(prev_node);
- goto mem_err;
- }
- }
+ if (IS_NOT_NULL(root)) {
+ if (IS_NULL(onig_node_list_add(root, prev_node))) {
+ onig_node_free(prev_node);
+ goto mem_err;
+ }
+ }
}
snode = NULL_NODE;
@@ -3719,9 +3731,9 @@ expand_case_fold_string(Node* node, regex_t* reg)
onig_node_free(top_root);
top_root = root = onig_node_list_add(NULL_NODE, prev_node);
if (IS_NULL(root)) {
- onig_node_free(srem);
- onig_node_free(prev_node);
- goto mem_err;
+ onig_node_free(srem);
+ onig_node_free(prev_node);
+ goto mem_err;
}
}
@@ -3730,8 +3742,8 @@ expand_case_fold_string(Node* node, regex_t* reg)
}
else {
if (IS_NULL(onig_node_list_add(root, srem))) {
- onig_node_free(srem);
- goto mem_err;
+ onig_node_free(srem);
+ goto mem_err;
}
}
}
@@ -3771,7 +3783,7 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env)
case NT_LIST:
{
do {
- r = setup_comb_exp_check(NCAR(node), r, env);
+ r = setup_comb_exp_check(NCAR(node), r, env);
} while (r >= 0 && IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -3780,8 +3792,8 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env)
{
int ret;
do {
- ret = setup_comb_exp_check(NCAR(node), state, env);
- r |= ret;
+ ret = setup_comb_exp_check(NCAR(node), state, env);
+ r |= ret;
} while (ret >= 0 && IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -3795,55 +3807,55 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env)
int var_num;
if (! IS_REPEAT_INFINITE(qn->upper)) {
- if (qn->upper > 1) {
- /* {0,1}, {1,1} are allowed */
- child_state |= CEC_IN_FINITE_REPEAT;
-
- /* check (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n} */
- if (env->backrefed_mem == 0) {
- if (NTYPE(qn->target) == NT_ENCLOSE) {
- EncloseNode* en = NENCLOSE(qn->target);
- if (en->type == ENCLOSE_MEMORY) {
- if (NTYPE(en->target) == NT_QTFR) {
- QtfrNode* q = NQTFR(en->target);
- if (IS_REPEAT_INFINITE(q->upper)
- && q->greedy == qn->greedy) {
- qn->upper = (qn->lower == 0 ? 1 : qn->lower);
- if (qn->upper == 1)
- child_state = state;
- }
- }
- }
- }
- }
- }
+ if (qn->upper > 1) {
+ /* {0,1}, {1,1} are allowed */
+ child_state |= CEC_IN_FINITE_REPEAT;
+
+ /* check (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n} */
+ if (env->backrefed_mem == 0) {
+ if (NTYPE(qn->target) == NT_ENCLOSE) {
+ EncloseNode* en = NENCLOSE(qn->target);
+ if (en->type == ENCLOSE_MEMORY) {
+ if (NTYPE(en->target) == NT_QTFR) {
+ QtfrNode* q = NQTFR(en->target);
+ if (IS_REPEAT_INFINITE(q->upper)
+ && q->greedy == qn->greedy) {
+ qn->upper = (qn->lower == 0 ? 1 : qn->lower);
+ if (qn->upper == 1)
+ child_state = state;
+ }
+ }
+ }
+ }
+ }
+ }
}
if (state & CEC_IN_FINITE_REPEAT) {
- qn->comb_exp_check_num = -1;
+ qn->comb_exp_check_num = -1;
}
else {
- if (IS_REPEAT_INFINITE(qn->upper)) {
- var_num = CEC_INFINITE_NUM;
- child_state |= CEC_IN_INFINITE_REPEAT;
- }
- else {
- var_num = qn->upper - qn->lower;
- }
+ if (IS_REPEAT_INFINITE(qn->upper)) {
+ var_num = CEC_INFINITE_NUM;
+ child_state |= CEC_IN_INFINITE_REPEAT;
+ }
+ else {
+ var_num = qn->upper - qn->lower;
+ }
- if (var_num >= CEC_THRES_NUM_BIG_REPEAT)
- add_state |= CEC_CONT_BIG_REPEAT;
-
- if (((state & CEC_IN_INFINITE_REPEAT) != 0 && var_num != 0) ||
- ((state & CEC_CONT_BIG_REPEAT) != 0 &&
- var_num >= CEC_THRES_NUM_BIG_REPEAT)) {
- if (qn->comb_exp_check_num == 0) {
- env->num_comb_exp_check++;
- qn->comb_exp_check_num = env->num_comb_exp_check;
- if (env->curr_max_regnum > env->comb_exp_max_regnum)
- env->comb_exp_max_regnum = env->curr_max_regnum;
- }
- }
+ if (var_num >= CEC_THRES_NUM_BIG_REPEAT)
+ add_state |= CEC_CONT_BIG_REPEAT;
+
+ if (((state & CEC_IN_INFINITE_REPEAT) != 0 && var_num != 0) ||
+ ((state & CEC_CONT_BIG_REPEAT) != 0 &&
+ var_num >= CEC_THRES_NUM_BIG_REPEAT)) {
+ if (qn->comb_exp_check_num == 0) {
+ env->num_comb_exp_check++;
+ qn->comb_exp_check_num = env->num_comb_exp_check;
+ if (env->curr_max_regnum > env->comb_exp_max_regnum)
+ env->comb_exp_max_regnum = env->curr_max_regnum;
+ }
+ }
}
r = setup_comb_exp_check(target, child_state, env);
@@ -3857,17 +3869,17 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env)
switch (en->type) {
case ENCLOSE_MEMORY:
- {
- if (env->curr_max_regnum < en->regnum)
- env->curr_max_regnum = en->regnum;
+ {
+ if (env->curr_max_regnum < en->regnum)
+ env->curr_max_regnum = en->regnum;
- r = setup_comb_exp_check(en->target, state, env);
- }
- break;
+ r = setup_comb_exp_check(en->target, state, env);
+ }
+ break;
default:
- r = setup_comb_exp_check(en->target, state, env);
- break;
+ r = setup_comb_exp_check(en->target, state, env);
+ break;
}
}
break;
@@ -3889,13 +3901,6 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env)
}
#endif
-#define IN_ALT (1<<0)
-#define IN_NOT (1<<1)
-#define IN_REPEAT (1<<2)
-#define IN_VAR_REPEAT (1<<3)
-#define IN_CALL (1<<4)
-#define IN_RECCALL (1<<5)
-
/* setup_tree does the following work.
1. check empty loop. (set qn->target_empty_info)
2. expand ignore-case in char class.
@@ -3917,11 +3922,11 @@ restart:
{
Node* prev = NULL_NODE;
do {
- r = setup_tree(NCAR(node), reg, state, env);
- if (IS_NOT_NULL(prev) && r == 0) {
- r = next_setup(prev, NCAR(node), reg);
- }
- prev = NCAR(node);
+ r = setup_tree(NCAR(node), reg, state, env);
+ if (IS_NOT_NULL(prev) && r == 0) {
+ r = next_setup(prev, NCAR(node), reg);
+ }
+ prev = NCAR(node);
} while (r == 0 && IS_NOT_NULL(node = NCDR(node)));
}
break;
@@ -3937,7 +3942,7 @@ restart:
case NT_STR:
if (IS_IGNORECASE(reg->options) && !NSTRING_IS_RAW(node)) {
- r = expand_case_fold_string(node, reg);
+ r = expand_case_fold_string(node, reg, state);
}
break;
@@ -3958,15 +3963,15 @@ restart:
BRefNode* br = NBREF(node);
p = BACKREFS_P(br);
for (i = 0; i < br->back_num; i++) {
- if (p[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
- BIT_STATUS_ON_AT(env->backrefed_mem, p[i]);
- BIT_STATUS_ON_AT(env->bt_mem_start, p[i]);
+ if (p[i] > env->num_mem) return ONIGERR_INVALID_BACKREF;
+ BIT_STATUS_ON_AT(env->backrefed_mem, p[i]);
+ BIT_STATUS_ON_AT(env->bt_mem_start, p[i]);
#ifdef USE_BACKREF_WITH_LEVEL
- if (IS_BACKREF_NEST_LEVEL(br)) {
- BIT_STATUS_ON_AT(env->bt_mem_end, p[i]);
- }
+ if (IS_BACKREF_NEST_LEVEL(br)) {
+ BIT_STATUS_ON_AT(env->bt_mem_end, p[i]);
+ }
#endif
- SET_ENCLOSE_STATUS(nodes[p[i]], NST_MEM_BACKREFED);
+ SET_ENCLOSE_STATUS(nodes[p[i]], NST_MEM_BACKREFED);
}
}
break;
@@ -3978,100 +3983,100 @@ restart:
Node* target = qn->target;
if ((state & IN_REPEAT) != 0) {
- qn->state |= NST_IN_REPEAT;
+ qn->state |= NST_IN_REPEAT;
}
if (IS_REPEAT_INFINITE(qn->upper) || qn->upper >= 1) {
- r = get_min_match_length(target, &d, env);
- if (r) break;
- if (d == 0) {
- qn->target_empty_info = NQ_TARGET_IS_EMPTY;
+ r = get_min_match_length(target, &d, env);
+ if (r) break;
+ if (d == 0) {
+ qn->target_empty_info = NQ_TARGET_IS_EMPTY;
#ifdef USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT
- r = quantifiers_memory_node_info(target);
- if (r < 0) break;
- if (r > 0) {
- qn->target_empty_info = r;
- }
+ r = quantifiers_memory_node_info(target);
+ if (r < 0) break;
+ if (r > 0) {
+ qn->target_empty_info = r;
+ }
#endif
#if 0
- r = get_max_match_length(target, &d, env);
- if (r == 0 && d == 0) {
- /* ()* ==> ()?, ()+ ==> () */
- qn->upper = 1;
- if (qn->lower > 1) qn->lower = 1;
- if (NTYPE(target) == NT_STR) {
- qn->upper = qn->lower = 0; /* /(?:)+/ ==> // */
- }
- }
+ r = get_max_match_length(target, &d, env);
+ if (r == 0 && d == 0) {
+ /* ()* ==> ()?, ()+ ==> () */
+ qn->upper = 1;
+ if (qn->lower > 1) qn->lower = 1;
+ if (NTYPE(target) == NT_STR) {
+ qn->upper = qn->lower = 0; /* /(?:)+/ ==> // */
+ }
+ }
#endif
- }
+ }
}
state |= IN_REPEAT;
if (qn->lower != qn->upper)
- state |= IN_VAR_REPEAT;
+ state |= IN_VAR_REPEAT;
r = setup_tree(target, reg, state, env);
if (r) break;
/* expand string */
#define EXPAND_STRING_MAX_LENGTH 100
if (NTYPE(target) == NT_STR) {
- if (qn->lower > 1) {
- int i, n = qn->lower;
- OnigDistance len = NSTRING_LEN(target);
- StrNode* sn = NSTR(target);
- Node* np;
-
- np = onig_node_new_str(sn->s, sn->end);
- if (IS_NULL(np)) return ONIGERR_MEMORY;
- NSTR(np)->flag = sn->flag;
-
- for (i = 1; i < n && (i+1) * len <= EXPAND_STRING_MAX_LENGTH; i++) {
- r = onig_node_str_cat(np, sn->s, sn->end);
- if (r) {
- onig_node_free(np);
- return r;
- }
- }
- if (i < qn->upper || IS_REPEAT_INFINITE(qn->upper)) {
- Node *np1, *np2;
-
- qn->lower -= i;
- if (! IS_REPEAT_INFINITE(qn->upper))
- qn->upper -= i;
-
- np1 = onig_node_new_list(np, NULL);
- if (IS_NULL(np1)) {
- onig_node_free(np);
- return ONIGERR_MEMORY;
- }
- swap_node(np1, node);
- np2 = onig_node_list_add(node, np1);
- if (IS_NULL(np2)) {
- onig_node_free(np1);
- return ONIGERR_MEMORY;
- }
- }
- else {
- swap_node(np, node);
- onig_node_free(np);
- }
- break; /* break case NT_QTFR: */
- }
+ if (qn->lower > 1) {
+ int i, n = qn->lower;
+ OnigDistance len = NSTRING_LEN(target);
+ StrNode* sn = NSTR(target);
+ Node* np;
+
+ np = onig_node_new_str(sn->s, sn->end);
+ if (IS_NULL(np)) return ONIGERR_MEMORY;
+ NSTR(np)->flag = sn->flag;
+
+ for (i = 1; i < n && (i+1) * len <= EXPAND_STRING_MAX_LENGTH; i++) {
+ r = onig_node_str_cat(np, sn->s, sn->end);
+ if (r) {
+ onig_node_free(np);
+ return r;
+ }
+ }
+ if (i < qn->upper || IS_REPEAT_INFINITE(qn->upper)) {
+ Node *np1, *np2;
+
+ qn->lower -= i;
+ if (! IS_REPEAT_INFINITE(qn->upper))
+ qn->upper -= i;
+
+ np1 = onig_node_new_list(np, NULL);
+ if (IS_NULL(np1)) {
+ onig_node_free(np);
+ return ONIGERR_MEMORY;
+ }
+ swap_node(np1, node);
+ np2 = onig_node_list_add(node, np1);
+ if (IS_NULL(np2)) {
+ onig_node_free(np1);
+ return ONIGERR_MEMORY;
+ }
+ }
+ else {
+ swap_node(np, node);
+ onig_node_free(np);
+ }
+ break; /* break case NT_QTFR: */
+ }
}
#ifdef USE_OP_PUSH_OR_JUMP_EXACT
if (qn->greedy && (qn->target_empty_info != 0)) {
- if (NTYPE(target) == NT_QTFR) {
- QtfrNode* tqn = NQTFR(target);
- if (IS_NOT_NULL(tqn->head_exact)) {
- qn->head_exact = tqn->head_exact;
- tqn->head_exact = NULL;
- }
- }
- else {
- qn->head_exact = get_head_value_node(qn->target, 1, reg);
- }
+ if (NTYPE(target) == NT_QTFR) {
+ QtfrNode* tqn = NQTFR(target);
+ if (IS_NOT_NULL(tqn->head_exact)) {
+ qn->head_exact = tqn->head_exact;
+ tqn->head_exact = NULL;
+ }
+ }
+ else {
+ qn->head_exact = get_head_value_node(qn->target, 1, reg);
+ }
}
#endif
}
@@ -4083,61 +4088,61 @@ restart:
switch (en->type) {
case ENCLOSE_OPTION:
- {
- OnigOptionType options = reg->options;
- reg->options = NENCLOSE(node)->option;
- r = setup_tree(NENCLOSE(node)->target, reg, state, env);
- reg->options = options;
- }
- break;
+ {
+ OnigOptionType options = reg->options;
+ reg->options = NENCLOSE(node)->option;
+ r = setup_tree(NENCLOSE(node)->target, reg, state, env);
+ reg->options = options;
+ }
+ break;
case ENCLOSE_MEMORY:
- if ((state & (IN_ALT | IN_NOT | IN_VAR_REPEAT | IN_CALL)) != 0) {
- BIT_STATUS_ON_AT(env->bt_mem_start, en->regnum);
- /* SET_ENCLOSE_STATUS(node, NST_MEM_IN_ALT_NOT); */
- }
- if (IS_ENCLOSE_CALLED(en))
- state |= IN_CALL;
- if (IS_ENCLOSE_RECURSION(en))
- state |= IN_RECCALL;
- else if ((state & IN_RECCALL) != 0)
- SET_CALL_RECURSION(node);
- r = setup_tree(en->target, reg, state, env);
- break;
+ if ((state & (IN_ALT | IN_NOT | IN_VAR_REPEAT | IN_CALL)) != 0) {
+ BIT_STATUS_ON_AT(env->bt_mem_start, en->regnum);
+ /* SET_ENCLOSE_STATUS(node, NST_MEM_IN_ALT_NOT); */
+ }
+ if (IS_ENCLOSE_CALLED(en))
+ state |= IN_CALL;
+ if (IS_ENCLOSE_RECURSION(en))
+ state |= IN_RECCALL;
+ else if ((state & IN_RECCALL) != 0)
+ SET_CALL_RECURSION(node);
+ r = setup_tree(en->target, reg, state, env);
+ break;
case ENCLOSE_STOP_BACKTRACK:
- {
- Node* target = en->target;
- r = setup_tree(target, reg, state, env);
- if (NTYPE(target) == NT_QTFR) {
- QtfrNode* tqn = NQTFR(target);
- if (IS_REPEAT_INFINITE(tqn->upper) && tqn->lower <= 1 &&
- tqn->greedy != 0) { /* (?>a*), a*+ etc... */
- int qtype = NTYPE(tqn->target);
- if (IS_NODE_TYPE_SIMPLE(qtype))
- SET_ENCLOSE_STATUS(node, NST_STOP_BT_SIMPLE_REPEAT);
- }
- }
- }
- break;
+ {
+ Node* target = en->target;
+ r = setup_tree(target, reg, state, env);
+ if (NTYPE(target) == NT_QTFR) {
+ QtfrNode* tqn = NQTFR(target);
+ if (IS_REPEAT_INFINITE(tqn->upper) && tqn->lower <= 1 &&
+ tqn->greedy != 0) { /* (?>a*), a*+ etc... */
+ int qtype = NTYPE(tqn->target);
+ if (IS_NODE_TYPE_SIMPLE(qtype))
+ SET_ENCLOSE_STATUS(node, NST_STOP_BT_SIMPLE_REPEAT);
+ }
+ }
+ }
+ break;
case ENCLOSE_CONDITION:
#ifdef USE_NAMED_GROUP
- if (! IS_ENCLOSE_NAME_REF(NENCLOSE(node)) &&
- env->num_named > 0 &&
- IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
- !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) {
- return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
- }
+ if (! IS_ENCLOSE_NAME_REF(NENCLOSE(node)) &&
+ env->num_named > 0 &&
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) &&
+ !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) {
+ return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED;
+ }
#endif
- if (NENCLOSE(node)->regnum > env->num_mem)
- return ONIGERR_INVALID_BACKREF;
- r = setup_tree(NENCLOSE(node)->target, reg, state, env);
- break;
+ if (NENCLOSE(node)->regnum > env->num_mem)
+ return ONIGERR_INVALID_BACKREF;
+ r = setup_tree(NENCLOSE(node)->target, reg, state, env);
+ break;
case ENCLOSE_ABSENT:
- r = setup_tree(NENCLOSE(node)->target, reg, state, env);
- break;
+ r = setup_tree(NENCLOSE(node)->target, reg, state, env);
+ break;
}
}
break;
@@ -4148,11 +4153,11 @@ restart:
switch (an->type) {
case ANCHOR_PREC_READ:
- r = setup_tree(an->target, reg, state, env);
- break;
+ r = setup_tree(an->target, reg, state, env);
+ break;
case ANCHOR_PREC_READ_NOT:
- r = setup_tree(an->target, reg, (state | IN_NOT), env);
- break;
+ r = setup_tree(an->target, reg, (state | IN_NOT), env);
+ break;
/* allowed node types in look-behind */
#define ALLOWED_TYPE_IN_LB \
@@ -4174,30 +4179,31 @@ restart:
ANCHOR_WORD_BEGIN | ANCHOR_WORD_END )
case ANCHOR_LOOK_BEHIND:
- {
- r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB,
- ALLOWED_ENCLOSE_IN_LB, ALLOWED_ANCHOR_IN_LB);
- if (r < 0) return r;
- if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
- if (NTYPE(node) != NT_ANCHOR) goto restart;
- r = setup_tree(an->target, reg, state, env);
- if (r != 0) return r;
- r = setup_look_behind(node, reg, env);
- }
- break;
+ {
+ r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB,
+ ALLOWED_ENCLOSE_IN_LB, ALLOWED_ANCHOR_IN_LB);
+ if (r < 0) return r;
+ if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ if (NTYPE(node) != NT_ANCHOR) goto restart;
+ r = setup_tree(an->target, reg, (state | IN_LOOK_BEHIND), env);
+ if (r != 0) return r;
+ r = setup_look_behind(node, reg, env);
+ }
+ break;
case ANCHOR_LOOK_BEHIND_NOT:
- {
- r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB,
- ALLOWED_ENCLOSE_IN_LB_NOT, ALLOWED_ANCHOR_IN_LB_NOT);
- if (r < 0) return r;
- if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
- if (NTYPE(node) != NT_ANCHOR) goto restart;
- r = setup_tree(an->target, reg, (state | IN_NOT), env);
- if (r != 0) return r;
- r = setup_look_behind(node, reg, env);
- }
- break;
+ {
+ r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB,
+ ALLOWED_ENCLOSE_IN_LB_NOT, ALLOWED_ANCHOR_IN_LB_NOT);
+ if (r < 0) return r;
+ if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
+ if (NTYPE(node) != NT_ANCHOR) goto restart;
+ r = setup_tree(an->target, reg, (state | IN_NOT | IN_LOOK_BEHIND),
+ env);
+ if (r != 0) return r;
+ r = setup_look_behind(node, reg, env);
+ }
+ break;
}
}
break;
@@ -4209,169 +4215,73 @@ restart:
return r;
}
-#ifndef USE_SUNDAY_QUICK_SEARCH
-/* set skip map for Boyer-Moore search */
+/* set skip map for Sunday's quick search */
static int
set_bm_skip(UChar* s, UChar* end, regex_t* reg,
- UChar skip[], int** int_skip, int ignore_case)
+ UChar skip[], int ignore_case)
{
OnigDistance i, len;
int clen, flen, n, j, k;
- UChar *p, buf[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM][ONIGENC_MBC_CASE_FOLD_MAXLEN];
+ UChar *p, buf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
OnigEncoding enc = reg->enc;
len = end - s;
- if (len < ONIG_CHAR_TABLE_SIZE) {
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) skip[i] = (UChar )len;
-
- n = 0;
- for (i = 0; i < len - 1; i += clen) {
- p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
- clen = enclen(enc, p, end);
- if (p + clen > end)
- clen = (int )(end - p);
-
- for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- skip[s[i + j]] = (UChar )(len - 1 - i - j);
- for (k = 0; k < n; k++) {
- skip[buf[k][j]] = (UChar )(len - 1 - i - j);
- }
- }
- }
- }
- else {
-# if OPT_EXACT_MAXLEN < ONIG_CHAR_TABLE_SIZE
+ if (len >= ONIG_CHAR_TABLE_SIZE) {
/* This should not happen. */
return ONIGERR_TYPE_BUG;
-# else
- if (IS_NULL(*int_skip)) {
- *int_skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE);
- if (IS_NULL(*int_skip)) return ONIGERR_MEMORY;
- }
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) (*int_skip)[i] = (int )len;
-
- n = 0;
- for (i = 0; i < len - 1; i += clen) {
- p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
- clen = enclen(enc, p, end);
- if (p + clen > end)
- clen = (int )(end - p);
-
- for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- (*int_skip)[s[i + j]] = (int )(len - 1 - i - j);
- for (k = 0; k < n; k++) {
- (*int_skip)[buf[k][j]] = (int )(len - 1 - i - j);
- }
- }
- }
-# endif
}
- return 0;
-}
-
-#else /* USE_SUNDAY_QUICK_SEARCH */
-
-/* set skip map for Sunday's quick search */
-static int
-set_bm_skip(UChar* s, UChar* end, regex_t* reg,
- UChar skip[], int** int_skip, int ignore_case)
-{
- OnigDistance i, len;
- int clen, flen, n, j, k;
- UChar *p, buf[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM][ONIGENC_MBC_CASE_FOLD_MAXLEN];
- OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
- OnigEncoding enc = reg->enc;
-
- len = end - s;
- if (len < ONIG_CHAR_TABLE_SIZE) {
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) skip[i] = (UChar )(len + 1);
- n = 0;
+ if (ignore_case) {
for (i = 0; i < len; i += clen) {
p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
+ n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
+ p, end, items);
clen = enclen(enc, p, end);
if (p + clen > end)
- clen = (int )(end - p);
+ clen = (int )(end - p);
for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- skip[s[i + j]] = (UChar )(len - i - j);
- for (k = 0; k < n; k++) {
- skip[buf[k][j]] = (UChar )(len - i - j);
+ if ((items[j].code_len != 1) || (items[j].byte_len != clen)) {
+ /* Different length isn't supported. Stop optimization at here. */
+ end = p;
+ goto endcheck;
+ }
+ flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf);
+ if (flen != clen) {
+ /* Different length isn't supported. Stop optimization at here. */
+ end = p;
+ goto endcheck;
}
}
}
+endcheck:
+ len = end - s;
}
- else {
-# if OPT_EXACT_MAXLEN < ONIG_CHAR_TABLE_SIZE
- /* This should not happen. */
- return ONIGERR_TYPE_BUG;
-# else
- if (IS_NULL(*int_skip)) {
- *int_skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE);
- if (IS_NULL(*int_skip)) return ONIGERR_MEMORY;
- }
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) (*int_skip)[i] = (int )(len + 1);
-
- n = 0;
- for (i = 0; i < len; i += clen) {
- p = s + i;
- if (ignore_case)
- n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
- p, end, items);
- clen = enclen(enc, p, end);
- if (p + clen > end)
- clen = (int )(end - p);
- for (j = 0; j < n; j++) {
- if ((items[j].code_len != 1) || (items[j].byte_len != clen))
- return 1; /* different length isn't supported. */
- flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf[j]);
- if (flen != clen)
- return 1; /* different length isn't supported. */
- }
- for (j = 0; j < clen; j++) {
- (*int_skip)[s[i + j]] = (int )(len - i - j);
- for (k = 0; k < n; k++) {
- (*int_skip)[buf[k][j]] = (int )(len - i - j);
- }
+ for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++)
+ skip[i] = (UChar )(len + 1);
+ n = 0;
+ for (i = 0; i < len; i += clen) {
+ p = s + i;
+ if (ignore_case)
+ n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag,
+ p, end, items);
+ clen = enclen(enc, p, end);
+ if (p + clen > end)
+ clen = (int )(end - p);
+
+ for (j = 0; j < clen; j++) {
+ skip[s[i + j]] = (UChar )(len - i - j);
+ for (k = 0; k < n; k++) {
+ ONIGENC_CODE_TO_MBC(enc, items[k].code[0], buf);
+ skip[buf[j]] = (UChar )(len - i - j);
}
}
-# endif
}
- return 0;
+
+ return (int )len;
}
-#endif /* USE_SUNDAY_QUICK_SEARCH */
typedef struct {
OnigDistance min; /* min byte length */
@@ -4562,7 +4472,7 @@ copy_opt_anc_info(OptAncInfo* to, OptAncInfo* from)
static void
concat_opt_anc_info(OptAncInfo* to, OptAncInfo* left, OptAncInfo* right,
- OnigDistance left_len, OnigDistance right_len)
+ OnigDistance left_len, OnigDistance right_len)
{
clear_opt_anc_info(to);
@@ -4678,7 +4588,7 @@ concat_opt_exact_info(OptExactInfo* to, OptExactInfo* add, OnigEncoding enc)
static void
concat_opt_exact_info_str(OptExactInfo* to, UChar* s, UChar* end,
- int raw ARG_UNUSED, OnigEncoding enc)
+ int raw ARG_UNUSED, OnigEncoding enc)
{
int i, j, len;
UChar *p;
@@ -4923,7 +4833,7 @@ concat_left_node_opt_info(OnigEncoding enc, NodeOptInfo* to, NodeOptInfo* add)
if (add->exb.len > 0 && to->len.max == 0) {
concat_opt_anc_info(&tanc, &to->anc, &add->exb.anc,
- to->len.max, add->len.max);
+ to->len.max, add->len.max);
copy_opt_anc_info(&add->exb.anc, &tanc);
}
@@ -4954,12 +4864,12 @@ concat_left_node_opt_info(OnigEncoding enc, NodeOptInfo* to, NodeOptInfo* add)
if (to->expr.len > 0) {
if (add->len.max > 0) {
if (to->expr.len > (int )add->len.max)
- to->expr.len = (int )add->len.max;
+ to->expr.len = (int )add->len.max;
if (to->expr.mmd.max == 0)
- select_opt_exact_info(enc, &to->exb, &to->expr);
+ select_opt_exact_info(enc, &to->exb, &to->expr);
else
- select_opt_exact_info(enc, &to->exm, &to->expr);
+ select_opt_exact_info(enc, &to->exm, &to->expr);
}
}
else if (add->expr.len > 0) {
@@ -5005,11 +4915,11 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
copy_opt_env(&nenv, env);
do {
- r = optimize_node_left(NCAR(nd), &nopt, &nenv);
- if (r == 0) {
- add_mml(&nenv.mmd, &nopt.len);
- concat_left_node_opt_info(env->enc, opt, &nopt);
- }
+ r = optimize_node_left(NCAR(nd), &nopt, &nenv);
+ if (r == 0) {
+ add_mml(&nenv.mmd, &nopt.len);
+ concat_left_node_opt_info(env->enc, opt, &nopt);
+ }
} while (r == 0 && IS_NOT_NULL(nd = NCDR(nd)));
}
break;
@@ -5020,11 +4930,11 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
Node* nd = node;
do {
- r = optimize_node_left(NCAR(nd), &nopt, env);
- if (r == 0) {
- if (nd == node) copy_node_opt_info(opt, &nopt);
- else alt_merge_node_opt_info(opt, &nopt, env);
- }
+ r = optimize_node_left(NCAR(nd), &nopt, env);
+ if (r == 0) {
+ if (nd == node) copy_node_opt_info(opt, &nopt);
+ else alt_merge_node_opt_info(opt, &nopt, env);
+ }
} while ((r == 0) && IS_NOT_NULL(nd = NCDR(nd)));
}
break;
@@ -5036,40 +4946,40 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
int is_raw = NSTRING_IS_RAW(node);
if (! NSTRING_IS_AMBIG(node)) {
- concat_opt_exact_info_str(&opt->exb, sn->s, sn->end,
- is_raw, env->enc);
- opt->exb.ignore_case = 0;
- if (slen > 0) {
- add_char_opt_map_info(&opt->map, *(sn->s), env->enc);
- }
- set_mml(&opt->len, slen, slen);
+ concat_opt_exact_info_str(&opt->exb, sn->s, sn->end,
+ is_raw, env->enc);
+ opt->exb.ignore_case = 0;
+ if (slen > 0) {
+ add_char_opt_map_info(&opt->map, *(sn->s), env->enc);
+ }
+ set_mml(&opt->len, slen, slen);
}
else {
- OnigDistance max;
+ OnigDistance max;
- if (NSTRING_IS_DONT_GET_OPT_INFO(node)) {
- int n = onigenc_strlen(env->enc, sn->s, sn->end);
- max = ONIGENC_MBC_MAXLEN_DIST(env->enc) * (OnigDistance)n;
- }
- else {
- concat_opt_exact_info_str(&opt->exb, sn->s, sn->end,
- is_raw, env->enc);
- opt->exb.ignore_case = 1;
-
- if (slen > 0) {
- r = add_char_amb_opt_map_info(&opt->map, sn->s, sn->end,
- env->enc, env->case_fold_flag);
- if (r != 0) break;
- }
-
- max = slen;
- }
+ if (NSTRING_IS_DONT_GET_OPT_INFO(node)) {
+ int n = onigenc_strlen(env->enc, sn->s, sn->end);
+ max = (OnigDistance )ONIGENC_MBC_MAXLEN_DIST(env->enc) * (OnigDistance)n;
+ }
+ else {
+ concat_opt_exact_info_str(&opt->exb, sn->s, sn->end,
+ is_raw, env->enc);
+ opt->exb.ignore_case = 1;
- set_mml(&opt->len, slen, max);
+ if (slen > 0) {
+ r = add_char_amb_opt_map_info(&opt->map, sn->s, sn->end,
+ env->enc, env->case_fold_flag);
+ if (r != 0) break;
+ }
+
+ max = slen;
+ }
+
+ set_mml(&opt->len, slen, max);
}
if ((OnigDistance )opt->exb.len == slen)
- opt->exb.reach_end = 1;
+ opt->exb.reach_end = 1;
}
break;
@@ -5081,19 +4991,19 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
/* no need to check ignore case. (set in setup_tree()) */
if (IS_NOT_NULL(cc->mbuf) || IS_NCCLASS_NOT(cc)) {
- OnigDistance min = ONIGENC_MBC_MINLEN(env->enc);
- OnigDistance max = ONIGENC_MBC_MAXLEN_DIST(env->enc);
+ OnigDistance min = ONIGENC_MBC_MINLEN(env->enc);
+ OnigDistance max = ONIGENC_MBC_MAXLEN_DIST(env->enc);
- set_mml(&opt->len, min, max);
+ set_mml(&opt->len, min, max);
}
else {
- for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
- z = BITSET_AT(cc->bs, i);
- if ((z && !IS_NCCLASS_NOT(cc)) || (!z && IS_NCCLASS_NOT(cc))) {
- add_char_opt_map_info(&opt->map, (UChar )i, env->enc);
- }
- }
- set_mml(&opt->len, 1, 1);
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ z = BITSET_AT(cc->bs, i);
+ if ((z && !IS_NCCLASS_NOT(cc)) || (!z && IS_NCCLASS_NOT(cc))) {
+ add_char_opt_map_info(&opt->map, (UChar )i, env->enc);
+ }
+ }
+ set_mml(&opt->len, 1, 1);
}
}
break;
@@ -5106,30 +5016,30 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
max = ONIGENC_MBC_MAXLEN_DIST(env->enc);
if (max == 1) {
- min = 1;
-
- maxcode = NCTYPE(node)->ascii_range ? 0x80 : SINGLE_BYTE_SIZE;
- switch (NCTYPE(node)->ctype) {
- case ONIGENC_CTYPE_WORD:
- if (NCTYPE(node)->not != 0) {
- for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
- if (! ONIGENC_IS_CODE_WORD(env->enc, i) || i >= maxcode) {
- add_char_opt_map_info(&opt->map, (UChar )i, env->enc);
- }
- }
- }
- else {
- for (i = 0; i < maxcode; i++) {
- if (ONIGENC_IS_CODE_WORD(env->enc, i)) {
- add_char_opt_map_info(&opt->map, (UChar )i, env->enc);
- }
- }
- }
- break;
- }
+ min = 1;
+
+ maxcode = NCTYPE(node)->ascii_range ? 0x80 : SINGLE_BYTE_SIZE;
+ switch (NCTYPE(node)->ctype) {
+ case ONIGENC_CTYPE_WORD:
+ if (NCTYPE(node)->not != 0) {
+ for (i = 0; i < SINGLE_BYTE_SIZE; i++) {
+ if (! ONIGENC_IS_CODE_WORD(env->enc, i) || i >= maxcode) {
+ add_char_opt_map_info(&opt->map, (UChar )i, env->enc);
+ }
+ }
+ }
+ else {
+ for (i = 0; i < maxcode; i++) {
+ if (ONIGENC_IS_CODE_WORD(env->enc, i)) {
+ add_char_opt_map_info(&opt->map, (UChar )i, env->enc);
+ }
+ }
+ }
+ break;
+ }
}
else {
- min = ONIGENC_MBC_MINLEN(env->enc);
+ min = ONIGENC_MBC_MINLEN(env->enc);
}
set_mml(&opt->len, min, max);
}
@@ -5158,20 +5068,20 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
case ANCHOR_PREC_READ:
{
- NodeOptInfo nopt;
+ NodeOptInfo nopt;
- r = optimize_node_left(NANCHOR(node)->target, &nopt, env);
- if (r == 0) {
- if (nopt.exb.len > 0)
- copy_opt_exact_info(&opt->expr, &nopt.exb);
- else if (nopt.exm.len > 0)
- copy_opt_exact_info(&opt->expr, &nopt.exm);
+ r = optimize_node_left(NANCHOR(node)->target, &nopt, env);
+ if (r == 0) {
+ if (nopt.exb.len > 0)
+ copy_opt_exact_info(&opt->expr, &nopt.exb);
+ else if (nopt.exm.len > 0)
+ copy_opt_exact_info(&opt->expr, &nopt.exm);
- opt->expr.reach_end = 0;
+ opt->expr.reach_end = 0;
- if (nopt.map.value > 0)
- copy_opt_map_info(&opt->map, &nopt.map);
- }
+ if (nopt.map.value > 0)
+ copy_opt_map_info(&opt->map, &nopt.map);
+ }
}
break;
@@ -5189,8 +5099,8 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
BRefNode* br = NBREF(node);
if (br->state & NST_RECURSION) {
- set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE);
- break;
+ set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE);
+ break;
}
backs = BACKREFS_P(br);
r = get_min_match_length(nodes[backs[0]], &min, env->scan_env);
@@ -5198,12 +5108,12 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
r = get_max_match_length(nodes[backs[0]], &max, env->scan_env);
if (r != 0) break;
for (i = 1; i < br->back_num; i++) {
- r = get_min_match_length(nodes[backs[i]], &tmin, env->scan_env);
- if (r != 0) break;
- r = get_max_match_length(nodes[backs[i]], &tmax, env->scan_env);
- if (r != 0) break;
- if (min > tmin) min = tmin;
- if (max < tmax) max = tmax;
+ r = get_min_match_length(nodes[backs[i]], &tmin, env->scan_env);
+ if (r != 0) break;
+ r = get_max_match_length(nodes[backs[i]], &tmax, env->scan_env);
+ if (r != 0) break;
+ if (min > tmin) min = tmin;
+ if (max < tmax) max = tmax;
}
if (r == 0) set_mml(&opt->len, min, max);
}
@@ -5232,45 +5142,45 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
r = optimize_node_left(qn->target, &nopt, env);
if (r) break;
- if (/*qn->lower == 0 &&*/ IS_REPEAT_INFINITE(qn->upper)) {
- if (env->mmd.max == 0 &&
- NTYPE(qn->target) == NT_CANY && qn->greedy) {
- if (IS_MULTILINE(env->options))
- /* implicit anchor: /.*a/ ==> /\A.*a/ */
- add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_ML);
- else
- add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR);
- }
+ if (qn->lower == 0 && IS_REPEAT_INFINITE(qn->upper)) {
+ if (env->mmd.max == 0 &&
+ NTYPE(qn->target) == NT_CANY && qn->greedy) {
+ if (IS_MULTILINE(env->options))
+ /* implicit anchor: /.*a/ ==> /\A.*a/ */
+ add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_ML);
+ else
+ add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR);
+ }
}
else {
- if (qn->lower > 0) {
- copy_node_opt_info(opt, &nopt);
- if (nopt.exb.len > 0) {
- if (nopt.exb.reach_end) {
- for (i = 2; i <= qn->lower &&
- ! is_full_opt_exact_info(&opt->exb); i++) {
- concat_opt_exact_info(&opt->exb, &nopt.exb, env->enc);
- }
- if (i < qn->lower) {
- opt->exb.reach_end = 0;
- }
- }
- }
-
- if (qn->lower != qn->upper) {
- opt->exb.reach_end = 0;
- opt->exm.reach_end = 0;
- }
- if (qn->lower > 1)
- opt->exm.reach_end = 0;
- }
+ if (qn->lower > 0) {
+ copy_node_opt_info(opt, &nopt);
+ if (nopt.exb.len > 0) {
+ if (nopt.exb.reach_end) {
+ for (i = 2; i <= qn->lower &&
+ ! is_full_opt_exact_info(&opt->exb); i++) {
+ concat_opt_exact_info(&opt->exb, &nopt.exb, env->enc);
+ }
+ if (i < qn->lower) {
+ opt->exb.reach_end = 0;
+ }
+ }
+ }
+
+ if (qn->lower != qn->upper) {
+ opt->exb.reach_end = 0;
+ opt->exm.reach_end = 0;
+ }
+ if (qn->lower > 1)
+ opt->exm.reach_end = 0;
+ }
}
min = distance_multiply(nopt.len.min, qn->lower);
if (IS_REPEAT_INFINITE(qn->upper))
- max = (nopt.len.max > 0 ? ONIG_INFINITE_DISTANCE : 0);
+ max = (nopt.len.max > 0 ? ONIG_INFINITE_DISTANCE : 0);
else
- max = distance_multiply(nopt.len.max, qn->upper);
+ max = distance_multiply(nopt.len.max, qn->upper);
set_mml(&opt->len, min, max);
}
@@ -5282,47 +5192,47 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
switch (en->type) {
case ENCLOSE_OPTION:
- {
- OnigOptionType save = env->options;
+ {
+ OnigOptionType save = env->options;
- env->options = en->option;
- r = optimize_node_left(en->target, opt, env);
- env->options = save;
- }
- break;
+ env->options = en->option;
+ r = optimize_node_left(en->target, opt, env);
+ env->options = save;
+ }
+ break;
case ENCLOSE_MEMORY:
#ifdef USE_SUBEXP_CALL
- en->opt_count++;
- if (en->opt_count > MAX_NODE_OPT_INFO_REF_COUNT) {
- OnigDistance min, max;
-
- min = 0;
- max = ONIG_INFINITE_DISTANCE;
- if (IS_ENCLOSE_MIN_FIXED(en)) min = en->min_len;
- if (IS_ENCLOSE_MAX_FIXED(en)) max = en->max_len;
- set_mml(&opt->len, min, max);
- }
- else
+ en->opt_count++;
+ if (en->opt_count > MAX_NODE_OPT_INFO_REF_COUNT) {
+ OnigDistance min, max;
+
+ min = 0;
+ max = ONIG_INFINITE_DISTANCE;
+ if (IS_ENCLOSE_MIN_FIXED(en)) min = en->min_len;
+ if (IS_ENCLOSE_MAX_FIXED(en)) max = en->max_len;
+ set_mml(&opt->len, min, max);
+ }
+ else
#endif
- {
- r = optimize_node_left(en->target, opt, env);
+ {
+ r = optimize_node_left(en->target, opt, env);
- if (is_set_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK)) {
- if (BIT_STATUS_AT(env->scan_env->backrefed_mem, en->regnum))
- remove_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK);
- }
- }
- break;
+ if (is_set_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK)) {
+ if (BIT_STATUS_AT(env->scan_env->backrefed_mem, en->regnum))
+ remove_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK);
+ }
+ }
+ break;
case ENCLOSE_STOP_BACKTRACK:
case ENCLOSE_CONDITION:
- r = optimize_node_left(en->target, opt, env);
- break;
+ r = optimize_node_left(en->target, opt, env);
+ break;
case ENCLOSE_ABSENT:
- set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE);
- break;
+ set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE);
+ break;
}
}
break;
@@ -5330,7 +5240,7 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
default:
#ifdef ONIG_DEBUG
fprintf(stderr, "optimize_node_left: undefined node type %d\n",
- NTYPE(node));
+ NTYPE(node));
#endif
r = ONIGERR_TYPE_BUG;
break;
@@ -5342,7 +5252,6 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env)
static int
set_optimize_exact_info(regex_t* reg, OptExactInfo* e)
{
- int r;
int allow_reverse;
if (e->len == 0) return 0;
@@ -5353,18 +5262,27 @@ set_optimize_exact_info(regex_t* reg, OptExactInfo* e)
reg->exact_end = reg->exact + e->len;
allow_reverse =
- ONIGENC_IS_ALLOWED_REVERSE_MATCH(reg->enc, reg->exact, reg->exact_end);
+ ONIGENC_IS_ALLOWED_REVERSE_MATCH(reg->enc, reg->exact, reg->exact_end);
if (e->ignore_case > 0) {
if (e->len >= 3 || (e->len >= 2 && allow_reverse)) {
- r = set_bm_skip(reg->exact, reg->exact_end, reg,
- reg->map, &(reg->int_map), 1);
- if (r == 0) {
- reg->optimize = (allow_reverse != 0
- ? ONIG_OPTIMIZE_EXACT_BM_IC : ONIG_OPTIMIZE_EXACT_BM_NOT_REV_IC);
+ int orig_len = e->len;
+ e->len = set_bm_skip(reg->exact, reg->exact_end, reg,
+ reg->map, 1);
+ if (e->len >= 3) {
+ reg->exact_end = reg->exact + e->len;
+ reg->optimize = (allow_reverse != 0
+ ? ONIG_OPTIMIZE_EXACT_BM_IC : ONIG_OPTIMIZE_EXACT_BM_NOT_REV_IC);
}
else {
- reg->optimize = ONIG_OPTIMIZE_EXACT_IC;
+ /* Even if BM skip table can't be built (e.g., pattern starts with
+ 's' or 'k' which have multi-byte case fold variants), we should
+ still use EXACT_IC optimization with the original pattern.
+ Without this fallback, patterns like /slackware/i have no
+ optimization at all, causing severe performance regression
+ especially with non-ASCII strings. See [Bug #21824] */
+ e->len = orig_len; /* Restore original length for EXACT_IC */
+ reg->optimize = ONIG_OPTIMIZE_EXACT_IC;
}
}
else {
@@ -5373,15 +5291,10 @@ set_optimize_exact_info(regex_t* reg, OptExactInfo* e)
}
else {
if (e->len >= 3 || (e->len >= 2 && allow_reverse)) {
- r = set_bm_skip(reg->exact, reg->exact_end, reg,
- reg->map, &(reg->int_map), 0);
- if (r == 0) {
- reg->optimize = (allow_reverse != 0
- ? ONIG_OPTIMIZE_EXACT_BM : ONIG_OPTIMIZE_EXACT_BM_NOT_REV);
- }
- else {
- reg->optimize = ONIG_OPTIMIZE_EXACT;
- }
+ set_bm_skip(reg->exact, reg->exact_end, reg,
+ reg->map, 0);
+ reg->optimize = (allow_reverse != 0
+ ? ONIG_OPTIMIZE_EXACT_BM : ONIG_OPTIMIZE_EXACT_BM_NOT_REV);
}
else {
reg->optimize = ONIG_OPTIMIZE_EXACT;
@@ -5451,7 +5364,7 @@ set_optimize_info_from_tree(Node* node, regex_t* reg, ScanEnv* scan_env)
reg->anchor &= ~ANCHOR_ANYCHAR_STAR_ML;
reg->anchor |= opt.anc.right_anchor & (ANCHOR_END_BUF | ANCHOR_SEMI_END_BUF |
- ANCHOR_PREC_READ_NOT);
+ ANCHOR_PREC_READ_NOT);
if (reg->anchor & (ANCHOR_END_BUF | ANCHOR_SEMI_END_BUF)) {
reg->anchor_dmin = opt.len.min;
@@ -5461,7 +5374,7 @@ set_optimize_info_from_tree(Node* node, regex_t* reg, ScanEnv* scan_env)
if (opt.exb.len > 0 || opt.exm.len > 0) {
select_opt_exact_info(reg->enc, &opt.exb, &opt.exm);
if (opt.map.value > 0 &&
- comp_opt_exact_or_map_info(&opt.exb, &opt.map) > 0) {
+ comp_opt_exact_or_map_info(&opt.exb, &opt.map) > 0) {
goto set_map;
}
else {
@@ -5503,7 +5416,7 @@ clear_optimize_info(regex_t* reg)
#ifdef ONIG_DEBUG
static void print_enc_string(FILE* fp, OnigEncoding enc,
- const UChar *s, const UChar *end)
+ const UChar *s, const UChar *end)
{
fprintf(fp, "\nPATTERN: /");
@@ -5515,10 +5428,10 @@ static void print_enc_string(FILE* fp, OnigEncoding enc,
while (p < end) {
code = ONIGENC_MBC_TO_CODE(enc, p, end);
if (code >= 0x80) {
- fprintf(fp, " 0x%04x ", (int )code);
+ fprintf(fp, " 0x%04x ", (int )code);
}
else {
- fputc((int )code, fp);
+ fputc((int )code, fp);
}
p += enclen(enc, p, end);
@@ -5639,15 +5552,15 @@ print_optimize_info(FILE* f, regex_t* reg)
c = 0;
fputc('[', f);
for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) {
- if (reg->map[i] != 0) {
- if (c > 0) fputs(", ", f);
- c++;
- if (ONIGENC_MBC_MAXLEN(reg->enc) == 1 &&
- ONIGENC_IS_CODE_PRINT(reg->enc, (OnigCodePoint )i))
- fputc(i, f);
- else
- fprintf(f, "%d", i);
- }
+ if (reg->map[i] != 0) {
+ if (c > 0) fputs(", ", f);
+ c++;
+ if (ONIGENC_MBC_MAXLEN(reg->enc) == 1 &&
+ ONIGENC_IS_CODE_PRINT(reg->enc, (OnigCodePoint )i))
+ fputc(i, f);
+ else
+ fprintf(f, "%d", i);
+ }
}
fprintf(f, "]\n");
}
@@ -5662,8 +5575,6 @@ 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);
@@ -5710,14 +5621,6 @@ onig_reg_copy(regex_t** nreg, regex_t* oreg)
(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;
@@ -5744,10 +5647,6 @@ onig_reg_copy(regex_t** nreg, regex_t* oreg)
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);
@@ -5764,8 +5663,6 @@ onig_memsize(const regex_t *reg)
if (IS_NULL(reg)) return 0;
if (IS_NOT_NULL(reg->p)) size += reg->alloc;
if (IS_NOT_NULL(reg->exact)) size += reg->exact_end - reg->exact;
- if (IS_NOT_NULL(reg->int_map)) size += sizeof(int) * ONIG_CHAR_TABLE_SIZE;
- if (IS_NOT_NULL(reg->int_map_backward)) size += sizeof(int) * ONIG_CHAR_TABLE_SIZE;
if (IS_NOT_NULL(reg->repeat_range)) size += reg->repeat_range_alloc * sizeof(OnigRepeatRange);
if (IS_NOT_NULL(reg->chain)) size += onig_memsize(reg->chain);
@@ -5806,7 +5703,7 @@ static void print_tree(FILE* f, Node* node);
#ifdef RUBY
extern int
onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
- OnigErrorInfo* einfo)
+ OnigErrorInfo* einfo)
{
return onig_compile_ruby(reg, pattern, pattern_end, einfo, NULL, 0);
}
@@ -5815,11 +5712,11 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
#ifdef RUBY
extern int
onig_compile_ruby(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
- OnigErrorInfo* einfo, const char *sourcefile, int sourceline)
+ OnigErrorInfo* einfo, const char *sourcefile, int sourceline)
#else
extern int
onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
- OnigErrorInfo* einfo)
+ OnigErrorInfo* einfo)
#endif
{
#define COMPILE_INIT_SIZE 20
@@ -5936,10 +5833,10 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
if (scan_env.comb_exp_max_regnum > 0) {
int i;
for (i = 1; i <= scan_env.comb_exp_max_regnum; i++) {
- if (BIT_STATUS_AT(scan_env.backrefed_mem, i) != 0) {
- scan_env.num_comb_exp_check = 0;
- break;
- }
+ if (BIT_STATUS_AT(scan_env.backrefed_mem, i) != 0) {
+ scan_env.num_comb_exp_check = 0;
+ break;
+ }
}
}
}
@@ -5973,9 +5870,9 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
reg->stack_pop_level = STACK_POP_LEVEL_ALL;
else {
if (reg->bt_mem_start != 0)
- reg->stack_pop_level = STACK_POP_LEVEL_MEM_START;
+ reg->stack_pop_level = STACK_POP_LEVEL_MEM_START;
else
- reg->stack_pop_level = STACK_POP_LEVEL_FREE;
+ reg->stack_pop_level = STACK_POP_LEVEL_FREE;
}
}
#ifdef USE_SUBEXP_CALL
@@ -6021,8 +5918,8 @@ static int onig_inited = 0;
extern int
onig_reg_init(regex_t* reg, OnigOptionType option,
- OnigCaseFoldType case_fold_flag,
- OnigEncoding enc, const OnigSyntaxType* syntax)
+ OnigCaseFoldType case_fold_flag,
+ OnigEncoding enc, const OnigSyntaxType* syntax)
{
if (! onig_inited)
onig_init();
@@ -6030,6 +5927,12 @@ onig_reg_init(regex_t* reg, OnigOptionType option,
if (IS_NULL(reg))
return ONIGERR_INVALID_ARGUMENT;
+ (reg)->exact = (UChar* )NULL;
+ (reg)->chain = (regex_t* )NULL;
+ (reg)->p = (UChar* )NULL;
+ (reg)->name_table = (void* )NULL;
+ (reg)->repeat_range = (OnigRepeatRange* )NULL;
+
if (ONIGENC_IS_UNDEF(enc))
return ONIGERR_DEFAULT_ENCODING_IS_NOT_SET;
@@ -6049,15 +5952,9 @@ onig_reg_init(regex_t* reg, OnigOptionType option,
(reg)->options = option;
(reg)->syntax = syntax;
(reg)->optimize = 0;
- (reg)->exact = (UChar* )NULL;
- (reg)->int_map = (int* )NULL;
- (reg)->int_map_backward = (int* )NULL;
- (reg)->chain = (regex_t* )NULL;
- (reg)->p = (UChar* )NULL;
(reg)->alloc = 0;
(reg)->used = 0;
- (reg)->name_table = (void* )NULL;
(reg)->case_fold_flag = case_fold_flag;
@@ -6082,8 +5979,8 @@ onig_new_without_alloc(regex_t* reg, const UChar* pattern,
extern int
onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
- OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax,
- OnigErrorInfo* einfo)
+ OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax,
+ OnigErrorInfo* einfo)
{
*reg = (regex_t* )xmalloc(sizeof(regex_t));
if (IS_NULL(*reg)) return ONIGERR_MEMORY;
@@ -6436,9 +6333,9 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar* bpend, UChar** nextp,
break;
case ARG_OPTION:
{
- OnigOptionType option = *((OnigOptionType* )bp);
- bp += SIZE_OPTION;
- fprintf(f, ":%d", option);
+ OnigOptionType option = *((OnigOptionType* )bp);
+ bp += SIZE_OPTION;
+ fprintf(f, ":%d", option);
}
break;
@@ -6487,13 +6384,13 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar* bpend, UChar** nextp,
break;
case OP_EXACTMBN:
{
- int mb_len;
+ int mb_len;
- GET_LENGTH_INC(mb_len, bp);
- GET_LENGTH_INC(len, bp);
- fprintf(f, ":%d:%d:", mb_len, len);
- n = len * mb_len;
- while (n-- > 0) { fputc(*bp++, f); }
+ GET_LENGTH_INC(mb_len, bp);
+ GET_LENGTH_INC(len, bp);
+ fprintf(f, ":%d:%d:", mb_len, len);
+ n = len * mb_len;
+ while (n-- > 0) { fputc(*bp++, f); }
}
break;
@@ -6557,40 +6454,40 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar* bpend, UChar** nextp,
fputs(" ", f);
GET_LENGTH_INC(len, bp);
for (i = 0; i < len; i++) {
- GET_MEMNUM_INC(mem, bp);
- if (i > 0) fputs(", ", f);
- fprintf(f, "%d", mem);
+ GET_MEMNUM_INC(mem, bp);
+ if (i > 0) fputs(", ", f);
+ fprintf(f, "%d", mem);
}
break;
case OP_BACKREF_WITH_LEVEL:
{
- OnigOptionType option;
- LengthType level;
-
- GET_OPTION_INC(option, bp);
- fprintf(f, ":%d", option);
- GET_LENGTH_INC(level, bp);
- fprintf(f, ":%d", level);
-
- fputs(" ", f);
- GET_LENGTH_INC(len, bp);
- for (i = 0; i < len; i++) {
- GET_MEMNUM_INC(mem, bp);
- if (i > 0) fputs(", ", f);
- fprintf(f, "%d", mem);
- }
+ OnigOptionType option;
+ LengthType level;
+
+ GET_OPTION_INC(option, bp);
+ fprintf(f, ":%d", option);
+ GET_LENGTH_INC(level, bp);
+ fprintf(f, ":%d", level);
+
+ fputs(" ", f);
+ GET_LENGTH_INC(len, bp);
+ for (i = 0; i < len; i++) {
+ GET_MEMNUM_INC(mem, bp);
+ if (i > 0) fputs(", ", f);
+ fprintf(f, "%d", mem);
+ }
}
break;
case OP_REPEAT:
case OP_REPEAT_NG:
{
- mem = *((MemNumType* )bp);
- bp += SIZE_MEMNUM;
- addr = *((RelAddrType* )bp);
- bp += SIZE_RELADDR;
- fprintf(f, ":%d:%d", mem, addr);
+ mem = *((MemNumType* )bp);
+ bp += SIZE_MEMNUM;
+ addr = *((RelAddrType* )bp);
+ bp += SIZE_RELADDR;
+ fprintf(f, ":%d:%d", mem, addr);
}
break;
@@ -6631,7 +6528,7 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar* bpend, UChar** nextp,
default:
fprintf(stderr, "onig_print_compiled_byte_code: undefined code %d\n",
- bp[-1]);
+ bp[-1]);
}
}
fputs("]", f);
@@ -6688,8 +6585,8 @@ print_indent_tree(FILE* f, Node* node, int indent)
print_indent_tree(f, NCAR(node), indent + add);
while (IS_NOT_NULL(node = NCDR(node))) {
if (NTYPE(node) != type) {
- fprintf(f, "ERROR: list/alt right is not a cons. %d\n", NTYPE(node));
- exit(0);
+ fprintf(f, "ERROR: list/alt right is not a cons. %d\n", NTYPE(node));
+ exit(0);
}
print_indent_tree(f, NCAR(node), indent + add);
}
@@ -6697,12 +6594,12 @@ print_indent_tree(FILE* f, Node* node, int indent)
case NT_STR:
fprintf(f, "<string%s:%"PRIxPTR">",
- (NSTRING_IS_RAW(node) ? "-raw" : ""), (intptr_t )node);
+ (NSTRING_IS_RAW(node) ? "-raw" : ""), (intptr_t )node);
for (p = NSTR(node)->s; p < NSTR(node)->end; p++) {
if (*p >= 0x20 && *p < 0x7f)
- fputc(*p, f);
+ fputc(*p, f);
else {
- fprintf(f, " 0x%02x", *p);
+ fprintf(f, " 0x%02x", *p);
}
}
break;
@@ -6716,8 +6613,8 @@ print_indent_tree(FILE* f, Node* node, int indent)
OnigCodePoint* end = (OnigCodePoint* )(bbuf->p + bbuf->used);
fprintf(f, "%d", *data++);
for (; data < end; data+=2) {
- fprintf(f, ",");
- fprintf(f, "%04x-%04x", data[0], data[1]);
+ fprintf(f, ",");
+ fprintf(f, "%04x-%04x", data[0], data[1]);
}
}
break;
@@ -6727,9 +6624,9 @@ print_indent_tree(FILE* f, Node* node, int indent)
switch (NCTYPE(node)->ctype) {
case ONIGENC_CTYPE_WORD:
if (NCTYPE(node)->not != 0)
- fputs("not word", f);
+ fputs("not word", f);
else
- fputs("word", f);
+ fputs("word", f);
break;
default:
@@ -6777,8 +6674,8 @@ print_indent_tree(FILE* f, Node* node, int indent)
p = BACKREFS_P(br);
fprintf(f, "<backref:%"PRIxPTR">", (intptr_t )node);
for (i = 0; i < br->back_num; i++) {
- if (i > 0) fputs(", ", f);
- fprintf(f, "%d", p[i]);
+ if (i > 0) fputs(", ", f);
+ fprintf(f, "%d", p[i]);
}
}
break;
@@ -6795,8 +6692,8 @@ print_indent_tree(FILE* f, Node* node, int indent)
case NT_QTFR:
fprintf(f, "<quantifier:%"PRIxPTR">{%d,%d}%s\n", (intptr_t )node,
- NQTFR(node)->lower, NQTFR(node)->upper,
- (NQTFR(node)->greedy ? "" : "?"));
+ NQTFR(node)->lower, NQTFR(node)->upper,
+ (NQTFR(node)->greedy ? "" : "?"));
print_indent_tree(f, NQTFR(node)->target, indent + add);
break;
diff --git a/regenc.c b/regenc.c
index eb523e1ae5..c595f44b29 100644
--- a/regenc.c
+++ b/regenc.c
@@ -3,7 +3,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,7 +89,7 @@ onigenc_get_right_adjust_char_head(OnigEncoding enc, const UChar* start, const U
extern UChar*
onigenc_get_right_adjust_char_head_with_prev(OnigEncoding enc,
- const UChar* start, const UChar* s, const UChar* end, const UChar** prev)
+ const UChar* start, const UChar* s, const UChar* end, const UChar** prev)
{
UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s, end);
@@ -425,8 +425,8 @@ const OnigPairCaseFoldCodes OnigAsciiLowerMap[] = {
extern int
onigenc_ascii_apply_all_case_fold(OnigCaseFoldType flag ARG_UNUSED,
- OnigApplyAllCaseFoldFunc f, void* arg,
- OnigEncoding enc ARG_UNUSED)
+ OnigApplyAllCaseFoldFunc f, void* arg,
+ OnigEncoding enc ARG_UNUSED)
{
OnigCodePoint code;
int i, r;
@@ -446,8 +446,8 @@ onigenc_ascii_apply_all_case_fold(OnigCaseFoldType flag ARG_UNUSED,
extern int
onigenc_ascii_get_case_fold_codes_by_str(OnigCaseFoldType flag ARG_UNUSED,
- const OnigUChar* p, const OnigUChar* end ARG_UNUSED,
- OnigCaseFoldCodeItem items[], OnigEncoding enc ARG_UNUSED)
+ const OnigUChar* p, const OnigUChar* end ARG_UNUSED,
+ OnigCaseFoldCodeItem items[], OnigEncoding enc ARG_UNUSED)
{
if (0x41 <= *p && *p <= 0x5a) {
items[0].byte_len = 1;
@@ -467,7 +467,7 @@ onigenc_ascii_get_case_fold_codes_by_str(OnigCaseFoldType flag ARG_UNUSED,
static int
ss_apply_all_case_fold(OnigCaseFoldType flag ARG_UNUSED,
- OnigApplyAllCaseFoldFunc f, void* arg)
+ OnigApplyAllCaseFoldFunc f, void* arg)
{
OnigCodePoint ss[] = { 0x73, 0x73 };
@@ -513,7 +513,7 @@ onigenc_get_case_fold_codes_by_str_with_map(int map_size,
items[0].code_len = 1;
items[0].code[0] = (OnigCodePoint )(*p + 0x20);
if (*p == 0x53 && ess_tsett_flag != 0 && end > p + 1
- && (*(p+1) == 0x53 || *(p+1) == 0x73)) {
+ && (*(p+1) == 0x53 || *(p+1) == 0x73)) {
/* SS */
items[1].byte_len = 2;
items[1].code_len = 1;
@@ -528,7 +528,7 @@ onigenc_get_case_fold_codes_by_str_with_map(int map_size,
items[0].code_len = 1;
items[0].code[0] = (OnigCodePoint )(*p - 0x20);
if (*p == 0x73 && ess_tsett_flag != 0 && end > p + 1
- && (*(p+1) == 0x73 || *(p+1) == 0x53)) {
+ && (*(p+1) == 0x73 || *(p+1) == 0x53)) {
/* ss */
items[1].byte_len = 2;
items[1].code_len = 1;
@@ -566,16 +566,16 @@ onigenc_get_case_fold_codes_by_str_with_map(int map_size,
for (i = 0; i < map_size; i++) {
if (*p == map[i].from) {
- items[0].byte_len = 1;
- items[0].code_len = 1;
- items[0].code[0] = map[i].to;
- return 1;
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = map[i].to;
+ return 1;
}
else if (*p == map[i].to) {
- items[0].byte_len = 1;
- items[0].code_len = 1;
- items[0].code[0] = map[i].from;
- return 1;
+ items[0].byte_len = 1;
+ items[0].code_len = 1;
+ items[0].code[0] = map[i].from;
+ return 1;
}
}
}
@@ -586,9 +586,9 @@ onigenc_get_case_fold_codes_by_str_with_map(int map_size,
extern int
onigenc_not_support_get_ctype_code_range(OnigCtype ctype ARG_UNUSED,
- OnigCodePoint* sb_out ARG_UNUSED,
- const OnigCodePoint* ranges[] ARG_UNUSED,
- OnigEncoding enc)
+ OnigCodePoint* sb_out ARG_UNUSED,
+ const OnigCodePoint* ranges[] ARG_UNUSED,
+ OnigEncoding enc)
{
return ONIG_NO_SUPPORT_CONFIG;
}
@@ -605,7 +605,7 @@ onigenc_is_mbc_newline_0x0a(const UChar* p, const UChar* end, OnigEncoding enc A
/* for single byte encodings */
extern int
onigenc_ascii_mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED, const UChar** p,
- const UChar* end, UChar* lower, OnigEncoding enc ARG_UNUSED)
+ const UChar* end, UChar* lower, OnigEncoding enc ARG_UNUSED)
{
*lower = ONIGENC_ASCII_CODE_TO_LOWER_CASE(**p);
@@ -616,7 +616,7 @@ onigenc_ascii_mbc_case_fold(OnigCaseFoldType flag ARG_UNUSED, const UChar** p,
#if 0
extern int
onigenc_ascii_is_mbc_ambiguous(OnigCaseFoldType flag ARG_UNUSED,
- const UChar** pp, const UChar* end ARG_UNUSED)
+ const UChar** pp, const UChar* end ARG_UNUSED)
{
const UChar* p = *pp;
@@ -627,56 +627,57 @@ onigenc_ascii_is_mbc_ambiguous(OnigCaseFoldType flag ARG_UNUSED,
extern int
onigenc_single_byte_mbc_enc_len(const UChar* p ARG_UNUSED, const UChar* e ARG_UNUSED,
- OnigEncoding enc ARG_UNUSED)
+ OnigEncoding enc ARG_UNUSED)
{
return 1;
}
extern OnigCodePoint
onigenc_single_byte_mbc_to_code(const UChar* p, const UChar* end ARG_UNUSED,
- OnigEncoding enc ARG_UNUSED)
+ OnigEncoding enc ARG_UNUSED)
{
return (OnigCodePoint )(*p);
}
extern int
-onigenc_single_byte_code_to_mbclen(OnigCodePoint code ARG_UNUSED, OnigEncoding enc ARG_UNUSED)
+onigenc_single_byte_code_to_mbclen(OnigCodePoint code, OnigEncoding enc ARG_UNUSED)
{
+ if (code > 0xff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
return 1;
}
extern int
onigenc_single_byte_code_to_mbc(OnigCodePoint code, UChar *buf, OnigEncoding enc ARG_UNUSED)
{
-#ifdef RUBY
- if (code > 0xff)
- rb_raise(rb_eRangeError, "%u out of char range", code);
-#endif
+ if (code > 0xff) {
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+ }
*buf = (UChar )(code & 0xff);
return 1;
}
extern UChar*
onigenc_single_byte_left_adjust_char_head(const UChar* start ARG_UNUSED,
- const UChar* s,
- const UChar* end ARG_UNUSED,
- OnigEncoding enc ARG_UNUSED)
+ const UChar* s,
+ const UChar* end ARG_UNUSED,
+ OnigEncoding enc ARG_UNUSED)
{
return (UChar* )s;
}
extern int
onigenc_always_true_is_allowed_reverse_match(const UChar* s ARG_UNUSED,
- const UChar* end ARG_UNUSED,
- OnigEncoding enc ARG_UNUSED)
+ const UChar* end ARG_UNUSED,
+ OnigEncoding enc ARG_UNUSED)
{
return TRUE;
}
extern int
onigenc_always_false_is_allowed_reverse_match(const UChar* s ARG_UNUSED,
- const UChar* end ARG_UNUSED,
- OnigEncoding enc ARG_UNUSED)
+ const UChar* end ARG_UNUSED,
+ OnigEncoding enc ARG_UNUSED)
{
return FALSE;
}
@@ -712,7 +713,7 @@ onigenc_mbn_mbc_to_code(OnigEncoding enc, const UChar* p, const UChar* end)
extern int
onigenc_mbn_mbc_case_fold(OnigEncoding enc, OnigCaseFoldType flag ARG_UNUSED,
const UChar** pp, const UChar* end ARG_UNUSED,
- UChar* lower)
+ UChar* lower)
{
int len;
const UChar *p = *pp;
@@ -843,7 +844,7 @@ onigenc_minimum_property_name_to_ctype(OnigEncoding enc, const UChar* p, const U
extern int
onigenc_mb2_is_code_ctype(OnigEncoding enc, OnigCodePoint code,
- unsigned int ctype)
+ unsigned int ctype)
{
if (code < 128)
return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
@@ -858,7 +859,7 @@ onigenc_mb2_is_code_ctype(OnigEncoding enc, OnigCodePoint code,
extern int
onigenc_mb4_is_code_ctype(OnigEncoding enc, OnigCodePoint code,
- unsigned int ctype)
+ unsigned int ctype)
{
if (code < 128)
return ONIGENC_IS_ASCII_CODE_CTYPE(code, ctype);
@@ -961,14 +962,15 @@ onigenc_property_list_add_property(UChar* name, const OnigCodePoint* prop,
*pnum = *pnum + 1;
onig_st_insert_strend(*table, name, name + strlen((char* )name),
- (hash_data_type )(*pnum + ONIGENC_MAX_STD_CTYPE));
+ (hash_data_type )(*pnum + ONIGENC_MAX_STD_CTYPE));
return 0;
}
#endif
+#ifdef USE_CASE_MAP_API
extern int
onigenc_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp, const OnigUChar* end,
- OnigUChar* to, OnigUChar* to_end, const struct OnigEncodingTypeST* enc)
+ OnigUChar* to, OnigUChar* to_end, const struct OnigEncodingTypeST* enc)
{
OnigCodePoint code;
OnigUChar *to_start = to;
@@ -984,9 +986,10 @@ onigenc_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp, const
if (code >= 'a' && code <= 'z' && (flags & ONIGENC_CASE_UPCASE)) {
flags |= ONIGENC_CASE_MODIFIED;
- code += 'A' - 'a';
- } else if (code >= 'A' && code <= 'Z' &&
- (flags & (ONIGENC_CASE_DOWNCASE | ONIGENC_CASE_FOLD))) {
+ code -= 'a' - 'A';
+ }
+ else if (code >= 'A' && code <= 'Z' &&
+ (flags & (ONIGENC_CASE_DOWNCASE | ONIGENC_CASE_FOLD))) {
flags |= ONIGENC_CASE_MODIFIED;
code += 'a' - 'A';
}
@@ -1000,8 +1003,8 @@ onigenc_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp, const
extern int
onigenc_single_byte_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp,
- const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
- const struct OnigEncodingTypeST* enc)
+ const OnigUChar* end, OnigUChar* to, OnigUChar* to_end,
+ const struct OnigEncodingTypeST* enc)
{
OnigCodePoint code;
OnigUChar *to_start = to;
@@ -1012,9 +1015,10 @@ onigenc_single_byte_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar
if (code >= 'a' && code <= 'z' && (flags & ONIGENC_CASE_UPCASE)) {
flags |= ONIGENC_CASE_MODIFIED;
- code += 'A' - 'a';
- } else if (code >= 'A' && code <= 'Z' &&
- (flags & (ONIGENC_CASE_DOWNCASE | ONIGENC_CASE_FOLD))) {
+ code -= 'a' - 'A';
+ }
+ else if (code >= 'A' && code <= 'Z' &&
+ (flags & (ONIGENC_CASE_DOWNCASE | ONIGENC_CASE_FOLD))) {
flags |= ONIGENC_CASE_MODIFIED;
code += 'a' - 'A';
}
@@ -1025,3 +1029,4 @@ onigenc_single_byte_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar
*flagP = flags;
return (int )(to - to_start);
}
+#endif
diff --git a/regenc.h b/regenc.h
index 352a8d7980..fe0440dd74 100644
--- a/regenc.h
+++ b/regenc.h
@@ -5,7 +5,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2008 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -118,6 +118,11 @@ typedef struct {
typedef struct {
short int len;
+#if defined(__has_attribute)
+# if __has_attribute(nonstring)
+ __attribute__((nonstring))
+# endif
+#endif
const UChar name[6];
int ctype;
} PosixBracketEntryType;
@@ -129,11 +134,13 @@ typedef struct {
#define roomof(x, y) (((x) + (y) - 1) / (y))
#define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
+/* config */
#define USE_CRNL_AS_LINE_TERMINATOR
#define USE_UNICODE_PROPERTIES
#define USE_UNICODE_AGE_PROPERTIES
/* #define USE_UNICODE_CASE_FOLD_TURKISH_AZERI */
/* #define USE_UNICODE_ALL_LINE_TERMINATORS */ /* see Unicode.org UTS #18 */
+#define USE_CASE_MAP_API
#define ONIG_ENCODING_INIT_DEFAULT ONIG_ENCODING_ASCII
@@ -187,8 +194,8 @@ ONIG_EXTERN int onigenc_unicode_apply_all_case_fold(OnigCaseFoldType flag, OnigA
#define UTF16_IS_SURROGATE_SECOND(c) (((c) & 0xfc) == 0xdc)
#define UTF16_IS_SURROGATE(c) (((c) & 0xf8) == 0xd8)
#define UNICODE_VALID_CODEPOINT_P(c) ( \
- ((c) <= 0x10ffff) && \
- !((c) < 0x10000 && UTF16_IS_SURROGATE((c) >> 8)))
+ ((c) <= 0x10ffff) && \
+ !((c) < 0x10000 && UTF16_IS_SURROGATE((c) >> 8)))
#define ONIGENC_ISO_8859_1_TO_LOWER_CASE(c) \
OnigEncISO_8859_1_ToLowerCaseTable[c]
@@ -234,8 +241,8 @@ extern int ONIG_ENC_REGISTER(const char *, OnigEncoding);
# define OnigEncodingDefine(f,n) \
OnigEncodingDeclare(n); \
void Init_##f(void) { \
- ONIG_ENC_REGISTER(OnigEncodingName(n).name, \
- &OnigEncodingName(n)); \
+ ONIG_ENC_REGISTER(OnigEncodingName(n).name, \
+ &OnigEncodingName(n)); \
} \
OnigEncodingDeclare(n)
#else
diff --git a/regerror.c b/regerror.c
index b18fc2e88b..c61797564b 100644
--- a/regerror.c
+++ b/regerror.c
@@ -3,7 +3,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@ onig_error_code_to_format(OnigPosition code)
p = "parse depth limit over"; break;
case ONIGERR_DEFAULT_ENCODING_IS_NOT_SET:
p = "default multibyte-encoding is not set"; break;
+#if 0
case ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR:
p = "can't convert to wide-char on specified multibyte-encoding"; break;
+#endif
case ONIGERR_INVALID_ARGUMENT:
p = "invalid argument"; break;
case ONIGERR_END_PATTERN_AT_LEFT_BRACE:
p = "end pattern at left brace"; break;
+#if 0
case ONIGERR_END_PATTERN_AT_LEFT_BRACKET:
p = "end pattern at left bracket"; break;
+#endif
case ONIGERR_EMPTY_CHAR_CLASS:
p = "empty char-class"; break;
case ONIGERR_PREMATURE_END_OF_CHAR_CLASS:
@@ -87,16 +91,20 @@ onig_error_code_to_format(OnigPosition code)
p = "invalid control-code syntax"; break;
case ONIGERR_CHAR_CLASS_VALUE_AT_END_OF_RANGE:
p = "char-class value at end of range"; break;
+#if 0
case ONIGERR_CHAR_CLASS_VALUE_AT_START_OF_RANGE:
p = "char-class value at start of range"; break;
+#endif
case ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS:
p = "unmatched range specifier in char-class"; break;
case ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED:
p = "target of repeat operator is not specified"; break;
case ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID:
p = "target of repeat operator is invalid"; break;
+#if 0
case ONIGERR_NESTED_REPEAT_OPERATOR:
p = "nested repeat operator"; break;
+#endif
case ONIGERR_UNMATCHED_CLOSE_PARENTHESIS:
p = "unmatched close parenthesis"; break;
case ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS:
@@ -121,14 +129,18 @@ onig_error_code_to_format(OnigPosition code)
p = "upper is smaller than lower in repeat range"; break;
case ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS:
p = "empty range in char class"; break;
+#if 0
case ONIGERR_MISMATCH_CODE_LENGTH_IN_CLASS_RANGE:
p = "mismatch multibyte code length in char-class range"; break;
+#endif
case ONIGERR_TOO_MANY_MULTI_BYTE_RANGES:
p = "too many multibyte code ranges are specified"; break;
case ONIGERR_TOO_SHORT_MULTI_BYTE_STRING:
p = "too short multibyte code string"; break;
+#if 0
case ONIGERR_TOO_BIG_BACKREF_NUMBER:
p = "too big backref number"; break;
+#endif
case ONIGERR_INVALID_BACKREF:
#ifdef USE_NAMED_GROUP
p = "invalid backref number/name"; break;
@@ -161,10 +173,16 @@ onig_error_code_to_format(OnigPosition code)
p = "multiplex definition name <%n> call"; break;
case ONIGERR_NEVER_ENDING_RECURSION:
p = "never ending recursion"; break;
+#ifdef USE_CAPTURE_HISTORY
case ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY:
p = "group number is too big for capture history"; break;
+#endif
case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
p = "invalid character property name {%n}"; break;
+ case ONIGERR_TOO_MANY_RANGE_REPEAT:
+ p = "too many range repeat"; break;
+ case ONIGERR_TOO_MANY_NULL_CHECK:
+ p = "too many null check"; break;
case ONIGERR_TOO_MANY_CAPTURE_GROUPS:
p = "too many capture groups are specified"; break;
case ONIGERR_INVALID_CODE_POINT_VALUE:
@@ -194,7 +212,7 @@ static void sprint_byte_with_x(char* s, unsigned int v)
}
static int to_ascii(OnigEncoding enc, UChar *s, UChar *end,
- UChar buf[], int buf_size, int *is_over)
+ UChar buf[], int buf_size, int *is_over)
{
int len;
UChar *p;
@@ -206,24 +224,24 @@ static int to_ascii(OnigEncoding enc, UChar *s, UChar *end,
while (p < end) {
code = ONIGENC_MBC_TO_CODE(enc, p, end);
if (code >= 0x80) {
- if (code > 0xffff && len + 10 <= buf_size) {
- sprint_byte_with_x((char*)(&(buf[len])), (unsigned int)(code >> 24));
- sprint_byte((char*)(&(buf[len+4])), (unsigned int)(code >> 16));
- sprint_byte((char*)(&(buf[len+6])), (unsigned int)(code >> 8));
- sprint_byte((char*)(&(buf[len+8])), (unsigned int)code);
- len += 10;
- }
- else if (len + 6 <= buf_size) {
- sprint_byte_with_x((char*)(&(buf[len])), (unsigned int)(code >> 8));
- sprint_byte((char*)(&(buf[len+4])), (unsigned int)code);
- len += 6;
- }
- else {
- break;
- }
+ if (code > 0xffff && len + 10 <= buf_size) {
+ sprint_byte_with_x((char*)(&(buf[len])), (unsigned int)(code >> 24));
+ sprint_byte((char*)(&(buf[len+4])), (unsigned int)(code >> 16));
+ sprint_byte((char*)(&(buf[len+6])), (unsigned int)(code >> 8));
+ sprint_byte((char*)(&(buf[len+8])), (unsigned int)code);
+ len += 10;
+ }
+ else if (len + 6 <= buf_size) {
+ sprint_byte_with_x((char*)(&(buf[len])), (unsigned int)(code >> 8));
+ sprint_byte((char*)(&(buf[len+4])), (unsigned int)code);
+ len += 6;
+ }
+ else {
+ break;
+ }
}
else {
- buf[len++] = (UChar )code;
+ buf[len++] = (UChar )code;
}
p += enclen(enc, p, end);
@@ -267,27 +285,27 @@ onig_error_code_to_str(UChar* s, OnigPosition code, ...)
case ONIGERR_INVALID_CHAR_PROPERTY_NAME:
einfo = va_arg(vargs, OnigErrorInfo*);
len = to_ascii(einfo->enc, einfo->par, einfo->par_end,
- parbuf, MAX_ERROR_PAR_LEN - 3, &is_over);
+ parbuf, MAX_ERROR_PAR_LEN - 3, &is_over);
q = onig_error_code_to_format(code);
p = s;
while (*q != '\0') {
if (*q == '%') {
- q++;
- if (*q == 'n') { /* '%n': name */
- xmemcpy(p, parbuf, len);
- p += len;
- if (is_over != 0) {
- xmemcpy(p, "...", 3);
- p += 3;
- }
- q++;
- }
- else
- goto normal_char;
+ q++;
+ if (*q == 'n') { /* '%n': name */
+ xmemcpy(p, parbuf, len);
+ p += len;
+ if (is_over != 0) {
+ xmemcpy(p, "...", 3);
+ p += 3;
+ }
+ q++;
+ }
+ else
+ goto normal_char;
}
else {
normal_char:
- *p++ = *q++;
+ *p++ = *q++;
}
}
*p = '\0';
@@ -299,7 +317,8 @@ onig_error_code_to_str(UChar* s, OnigPosition code, ...)
if (q) {
len = onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, q);
xmemcpy(s, q, len);
- } else {
+ }
+ else {
len = 0;
}
s[len] = '\0';
@@ -347,24 +366,24 @@ onig_vsnprintf_with_pattern(UChar buf[], int bufsize, OnigEncoding enc,
}
}
else if (*p == '\\') {
- *s++ = *p++;
- len = enclen(enc, p, pat_end);
- while (len-- > 0) *s++ = *p++;
+ *s++ = *p++;
+ len = enclen(enc, p, pat_end);
+ while (len-- > 0) *s++ = *p++;
}
else if (*p == '/') {
- *s++ = (unsigned char )'\\';
- *s++ = *p++;
+ *s++ = (unsigned char )'\\';
+ *s++ = *p++;
}
else if (!ONIGENC_IS_CODE_PRINT(enc, *p) &&
- (!ONIGENC_IS_CODE_SPACE(enc, *p) ||
+ (!ONIGENC_IS_CODE_SPACE(enc, *p) ||
ONIGENC_IS_CODE_CNTRL(enc, *p))) {
- sprint_byte_with_x((char* )bs, (unsigned int )(*p++));
- len = onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, bs);
+ sprint_byte_with_x((char* )bs, (unsigned int )(*p++));
+ len = onigenc_str_bytelen_null(ONIG_ENCODING_ASCII, bs);
bp = bs;
- while (len-- > 0) *s++ = *bp++;
+ while (len-- > 0) *s++ = *bp++;
}
else {
- *s++ = *p++;
+ *s++ = *p++;
}
}
@@ -381,7 +400,7 @@ onig_snprintf_with_pattern(UChar buf[], int bufsize, OnigEncoding enc,
va_list args;
va_start(args, fmt);
onig_vsnprintf_with_pattern(buf, bufsize, enc,
- pat, pat_end, fmt, args);
+ pat, pat_end, fmt, args);
va_end(args);
}
#endif
diff --git a/regexec.c b/regexec.c
index 8245678355..3210c7cc1b 100644
--- a/regexec.c
+++ b/regexec.c
@@ -2,8 +2,8 @@
regexec.c - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2008 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2018 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,7 @@ rb_enc_asciicompat(OnigEncoding enc)
# define ONIGENC_IS_MBC_ASCII_WORD(enc,s,end) \
(rb_enc_asciicompat(enc) ? (ISALNUM(*s) || *s=='_') : \
onigenc_ascii_is_code_ctype( \
- ONIGENC_MBC_TO_CODE(enc,s,end),ONIGENC_CTYPE_WORD,enc))
+ ONIGENC_MBC_TO_CODE(enc,s,end),ONIGENC_CTYPE_WORD,enc))
#endif /* RUBY */
#ifdef USE_CRNL_AS_LINE_TERMINATOR
@@ -66,28 +66,28 @@ rb_enc_asciicompat(OnigEncoding enc)
is_mbc_newline_ex((enc),(p),(start),(end),(option),(check_prev))
static int
is_mbc_newline_ex(OnigEncoding enc, const UChar *p, const UChar *start,
- const UChar *end, OnigOptionType option, int check_prev)
+ const UChar *end, OnigOptionType option, int check_prev)
{
if (IS_NEWLINE_CRLF(option)) {
if (ONIGENC_MBC_TO_CODE(enc, p, end) == 0x0a) {
if (check_prev) {
- const UChar *prev = onigenc_get_prev_char_head(enc, start, p, end);
- if ((prev != NULL) && ONIGENC_MBC_TO_CODE(enc, prev, end) == 0x0d)
- return 0;
- else
- return 1;
+ const UChar *prev = onigenc_get_prev_char_head(enc, start, p, end);
+ if ((prev != NULL) && ONIGENC_MBC_TO_CODE(enc, prev, end) == 0x0d)
+ return 0;
+ else
+ return 1;
}
else
- return 1;
+ return 1;
}
else {
const UChar *pnext = p + enclen(enc, p, end);
if (pnext < end &&
- ONIGENC_MBC_TO_CODE(enc, p, end) == 0x0d &&
- ONIGENC_MBC_TO_CODE(enc, pnext, end) == 0x0a)
- return 1;
+ ONIGENC_MBC_TO_CODE(enc, p, end) == 0x0d &&
+ ONIGENC_MBC_TO_CODE(enc, pnext, end) == 0x0a)
+ return 1;
if (ONIGENC_IS_MBC_NEWLINE(enc, p, end))
- return 1;
+ return 1;
return 0;
}
}
@@ -111,7 +111,7 @@ history_tree_clear(OnigCaptureTreeNode* node)
if (IS_NOT_NULL(node)) {
for (i = 0; i < node->num_childs; i++) {
if (IS_NOT_NULL(node->childs[i])) {
- history_tree_free(node->childs[i]);
+ history_tree_free(node->childs[i]);
}
}
for (i = 0; i < node->allocated; i++) {
@@ -170,18 +170,18 @@ history_tree_add_child(OnigCaptureTreeNode* parent, OnigCaptureTreeNode* child)
if (IS_NULL(parent->childs)) {
n = HISTORY_TREE_INIT_ALLOC_SIZE;
parent->childs =
- (OnigCaptureTreeNode** )xmalloc(sizeof(OnigCaptureTreeNode*) * n);
+ (OnigCaptureTreeNode** )xmalloc(sizeof(OnigCaptureTreeNode*) * n);
CHECK_NULL_RETURN_MEMERR(parent->childs);
}
else {
OnigCaptureTreeNode** tmp;
n = parent->allocated * 2;
tmp =
- (OnigCaptureTreeNode** )xrealloc(parent->childs,
- sizeof(OnigCaptureTreeNode*) * n);
+ (OnigCaptureTreeNode** )xrealloc(parent->childs,
+ sizeof(OnigCaptureTreeNode*) * n);
if (tmp == 0) {
- history_tree_clear(parent);
- return ONIGERR_MEMORY;
+ history_tree_clear(parent);
+ return ONIGERR_MEMORY;
}
parent->childs = tmp;
}
@@ -276,7 +276,7 @@ static OnigPosition count_num_cache_opcodes_inner(
switch (*p++) {
case OP_FINISH:
case OP_END:
- break;
+ break;
case OP_EXACT1: p++; break;
case OP_EXACT2: p += 2; break;
@@ -284,50 +284,50 @@ 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;
case OP_EXACTMB2N:
- GET_LENGTH_INC(len, p); p += len * 2; break;
+ GET_LENGTH_INC(len, p); p += len * 2; break;
case OP_EXACTMB3N:
- GET_LENGTH_INC(len, p); p += len * 3; break;
+ GET_LENGTH_INC(len, p); p += len * 3; break;
case OP_EXACTMBN:
- {
- int mb_len;
- GET_LENGTH_INC(mb_len, p);
- GET_LENGTH_INC(len, p);
- p += mb_len * len;
- }
- break;
+ {
+ int mb_len;
+ GET_LENGTH_INC(mb_len, p);
+ GET_LENGTH_INC(len, p);
+ p += mb_len * len;
+ }
+ break;
case OP_EXACT1_IC:
- len = enclen(enc, p, pend); p += len; break;
+ len = enclen(enc, p, pend); p += len; break;
case OP_EXACTN_IC:
- GET_LENGTH_INC(len, p); p += len; break;
+ GET_LENGTH_INC(len, p); p += len; break;
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;
+ GET_LENGTH_INC(len, p); p += len; break;
case OP_CCLASS_MIX:
case OP_CCLASS_MIX_NOT:
- p += SIZE_BITSET;
- GET_LENGTH_INC(len, p);
- p += len;
- break;
+ p += SIZE_BITSET;
+ GET_LENGTH_INC(len, p);
+ p += len;
+ break;
case OP_ANYCHAR:
case OP_ANYCHAR_ML:
- break;
+ break;
case OP_ANYCHAR_STAR:
case OP_ANYCHAR_ML_STAR:
- num_cache_opcodes++; break;
+ num_cache_opcodes++; break;
case OP_ANYCHAR_STAR_PEEK_NEXT:
case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
- p++; num_cache_opcodes++; break;
+ p++; num_cache_opcodes++; break;
case OP_WORD:
case OP_NOT_WORD:
@@ -335,7 +335,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_NOT_WORD_BOUND:
case OP_WORD_BEGIN:
case OP_WORD_END:
- break;
+ break;
case OP_ASCII_WORD:
case OP_NOT_ASCII_WORD:
@@ -343,7 +343,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_NOT_ASCII_WORD_BOUND:
case OP_ASCII_WORD_BEGIN:
case OP_ASCII_WORD_END:
- break;
+ break;
case OP_BEGIN_BUF:
case OP_END_BUF:
@@ -351,7 +351,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_END_LINE:
case OP_SEMI_END_BUF:
case OP_BEGIN_POSITION:
- break;
+ break;
case OP_BACKREF1:
case OP_BACKREF2:
@@ -360,7 +360,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 impossible;
case OP_MEMORY_START:
case OP_MEMORY_START_PUSH:
@@ -368,152 +368,158 @@ 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;
+ p += SIZE_MEMNUM;
+ // A memory (capture) in look-around is found.
+ if (lookaround_nesting != 0) {
+ goto impossible;
}
- break;
+ break;
case OP_KEEP:
- break;
+ break;
case OP_FAIL:
- break;
+ break;
case OP_JUMP:
- p += SIZE_RELADDR;
- break;
+ p += SIZE_RELADDR;
+ break;
case OP_PUSH:
- p += SIZE_RELADDR;
- num_cache_opcodes++;
- break;
+ p += SIZE_RELADDR;
+ num_cache_opcodes++;
+ break;
case OP_POP:
- break;
+ 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_cache_opcodes++; break;
case OP_REPEAT:
case OP_REPEAT_NG:
- if (current_repeat_mem != -1) {
- // A nested OP_REPEAT is not yet supported.
- goto impossible;
- }
- GET_MEMNUM_INC(repeat_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;
- }
- {
- OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
- if (repeat_range->lower < repeat_range->upper) {
- num_cache_opcodes++;
- }
+ if (current_repeat_mem != -1) {
+ // A nested OP_REPEAT is not yet supported.
+ goto impossible;
}
- break;
+ GET_MEMNUM_INC(repeat_mem, p);
+ p += SIZE_RELADDR;
+ if (reg->repeat_range[repeat_mem].lower == 0 && reg->repeat_range[repeat_mem].upper == 0) {
+ long dummy_num_cache_opcodes = 0;
+ result = count_num_cache_opcodes_inner(reg, repeat_mem, lookaround_nesting, &p, &dummy_num_cache_opcodes);
+ if (result < 0 || dummy_num_cache_opcodes < 0) {
+ goto fail;
+ }
+ } else {
+ 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;
+ }
+ OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
+ if (repeat_range->lower < repeat_range->upper) {
+ num_cache_opcodes++;
+ }
+ }
+ break;
case OP_REPEAT_INC:
case OP_REPEAT_INC_NG:
- GET_MEMNUM_INC(repeat_mem, p);
- if (repeat_mem != current_repeat_mem) {
- // A lone or invalid OP_REPEAT_INC is found.
- goto impossible;
- }
- goto exit;
+ GET_MEMNUM_INC(repeat_mem, p);
+ if (repeat_mem != current_repeat_mem) {
+ // A lone or invalid OP_REPEAT_INC is found.
+ goto impossible;
+ }
+ goto exit;
case OP_REPEAT_INC_SG:
case OP_REPEAT_INC_NG_SG:
- goto impossible;
+ goto impossible;
case OP_NULL_CHECK_START:
- p += SIZE_MEMNUM;
- break;
+ p += SIZE_MEMNUM;
+ break;
case OP_NULL_CHECK_END:
case OP_NULL_CHECK_END_MEMST_PUSH:
- p += SIZE_MEMNUM;
- break;
+ p += SIZE_MEMNUM;
+ break;
case OP_NULL_CHECK_END_MEMST:
- p += SIZE_MEMNUM;
- break;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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_FAIL_POS:
case OP_FAIL_LOOK_BEHIND_NOT:
case OP_POP_STOP_BT:
- goto exit;
+ goto exit;
case OP_LOOK_BEHIND:
- p += SIZE_LENGTH;
- break;
+ p += SIZE_LENGTH;
+ break;
case OP_PUSH_ABSENT_POS:
case OP_ABSENT_END:
case OP_ABSENT:
- goto impossible;
+ goto impossible;
case OP_CALL:
case OP_RETURN:
- goto impossible;
+ goto impossible;
case OP_CONDITION:
- goto impossible;
+ goto impossible;
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 impossible;
case OP_SET_OPTION_PUSH:
case OP_SET_OPTION:
- p += SIZE_OPTION;
- break;
+ p += SIZE_OPTION;
+ break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
@@ -565,7 +571,7 @@ init_cache_opcodes_inner(
OnigCacheOpcode *cache_opcodes = *cache_opcodes_ptr;
OnigPosition result;
-# define INC_CACHE_OPCODES do {\
+# define INC_CACHE_OPCODES if (cache_opcodes != NULL) {\
cache_opcodes->addr = pbegin;\
cache_opcodes->cache_point = cache_point;\
cache_opcodes->outer_repeat_mem = current_repeat_mem;\
@@ -575,14 +581,14 @@ init_cache_opcodes_inner(
cache_opcodes->match_addr = NULL;\
cache_point += lookaround_nesting != 0 ? 2 : 1;\
cache_opcodes++;\
- } while (0)
+ }
while (p < pend) {
pbegin = p;
switch (*p++) {
case OP_FINISH:
case OP_END:
- break;
+ break;
case OP_EXACT1: p++; break;
case OP_EXACT2: p += 2; break;
@@ -590,53 +596,53 @@ 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;
case OP_EXACTMB2N:
- GET_LENGTH_INC(len, p); p += len * 2; break;
+ GET_LENGTH_INC(len, p); p += len * 2; break;
case OP_EXACTMB3N:
- GET_LENGTH_INC(len, p); p += len * 3; break;
+ GET_LENGTH_INC(len, p); p += len * 3; break;
case OP_EXACTMBN:
- {
- int mb_len;
- GET_LENGTH_INC(mb_len, p);
- GET_LENGTH_INC(len, p);
- p += mb_len * len;
- }
- break;
+ {
+ int mb_len;
+ GET_LENGTH_INC(mb_len, p);
+ GET_LENGTH_INC(len, p);
+ p += mb_len * len;
+ }
+ break;
case OP_EXACT1_IC:
- len = enclen(enc, p, pend); p += len; break;
+ len = enclen(enc, p, pend); p += len; break;
case OP_EXACTN_IC:
- GET_LENGTH_INC(len, p); p += len; break;
+ GET_LENGTH_INC(len, p); p += len; break;
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;
+ GET_LENGTH_INC(len, p); p += len; break;
case OP_CCLASS_MIX:
case OP_CCLASS_MIX_NOT:
- p += SIZE_BITSET;
- GET_LENGTH_INC(len, p);
- p += len;
- break;
+ p += SIZE_BITSET;
+ GET_LENGTH_INC(len, p);
+ p += len;
+ break;
case OP_ANYCHAR:
case OP_ANYCHAR_ML:
- break;
+ break;
case OP_ANYCHAR_STAR:
case OP_ANYCHAR_ML_STAR:
- INC_CACHE_OPCODES;
- break;
+ INC_CACHE_OPCODES;
+ break;
case OP_ANYCHAR_STAR_PEEK_NEXT:
case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
- p++;
- INC_CACHE_OPCODES;
- break;
+ p++;
+ INC_CACHE_OPCODES;
+ break;
case OP_WORD:
case OP_NOT_WORD:
@@ -644,7 +650,7 @@ init_cache_opcodes_inner(
case OP_NOT_WORD_BOUND:
case OP_WORD_BEGIN:
case OP_WORD_END:
- break;
+ break;
case OP_ASCII_WORD:
case OP_NOT_ASCII_WORD:
@@ -652,7 +658,7 @@ init_cache_opcodes_inner(
case OP_NOT_ASCII_WORD_BOUND:
case OP_ASCII_WORD_BEGIN:
case OP_ASCII_WORD_END:
- break;
+ break;
case OP_BEGIN_BUF:
case OP_END_BUF:
@@ -660,7 +666,7 @@ init_cache_opcodes_inner(
case OP_END_LINE:
case OP_SEMI_END_BUF:
case OP_BEGIN_POSITION:
- break;
+ break;
case OP_BACKREF1:
case OP_BACKREF2:
@@ -669,7 +675,7 @@ init_cache_opcodes_inner(
case OP_BACKREF_MULTI:
case OP_BACKREF_MULTI_IC:
case OP_BACKREF_WITH_LEVEL:
- goto unexpected_bytecode_error;
+ goto unexpected_bytecode_error;
case OP_MEMORY_START:
case OP_MEMORY_START_PUSH:
@@ -677,149 +683,158 @@ 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;
+ if (lookaround_nesting != 0) {
+ goto unexpected_bytecode_error;
+ }
+ break;
case OP_KEEP:
- break;
+ break;
case OP_FAIL:
- break;
+ break;
case OP_JUMP:
- p += SIZE_RELADDR;
- break;
+ p += SIZE_RELADDR;
+ break;
case OP_PUSH:
- p += SIZE_RELADDR;
- INC_CACHE_OPCODES;
- break;
+ p += SIZE_RELADDR;
+ INC_CACHE_OPCODES;
+ break;
case OP_POP:
- break;
+ break;
case OP_PUSH_OR_JUMP_EXACT1:
case OP_PUSH_IF_PEEK_NEXT:
- p += SIZE_RELADDR + 1;
- INC_CACHE_OPCODES;
- break;
+ p += SIZE_RELADDR + 1;
+ INC_CACHE_OPCODES;
+ break;
case OP_REPEAT:
case OP_REPEAT_NG:
- GET_MEMNUM_INC(repeat_mem, p);
- p += SIZE_RELADDR;
- if (reg->repeat_range[repeat_mem].lower == 0) {
- INC_CACHE_OPCODES;
- }
- {
- 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];
- 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;
- }
- }
- break;
+ GET_MEMNUM_INC(repeat_mem, p);
+ p += SIZE_RELADDR;
+ if (reg->repeat_range[repeat_mem].lower == 0 && reg->repeat_range[repeat_mem].upper == 0) {
+ long dummy_num_cache_points = 0;
+ OnigCacheOpcode* dummy_cache_opcodes = NULL;
+ result = init_cache_opcodes_inner(reg, repeat_mem, lookaround_nesting, &dummy_cache_opcodes, &p, &dummy_num_cache_points);
+ if (result != 0) {
+ goto fail;
+ }
+ } else {
+ if (reg->repeat_range[repeat_mem].lower == 0) {
+ INC_CACHE_OPCODES;
+ }
+ {
+ 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];
+ 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;
+ }
+ }
+ }
+ break;
case OP_REPEAT_INC:
case OP_REPEAT_INC_NG:
- p += SIZE_MEMNUM;
+ p += SIZE_MEMNUM;
goto exit;
case OP_REPEAT_INC_SG:
case OP_REPEAT_INC_NG_SG:
- goto unexpected_bytecode_error;
+ goto unexpected_bytecode_error;
case OP_NULL_CHECK_START:
- p += SIZE_MEMNUM;
- break;
+ p += SIZE_MEMNUM;
+ break;
case OP_NULL_CHECK_END:
case OP_NULL_CHECK_END_MEMST_PUSH:
- p += SIZE_MEMNUM;
- break;
+ p += SIZE_MEMNUM;
+ break;
case OP_NULL_CHECK_END_MEMST:
- p += SIZE_MEMNUM;
- break;
+ 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;
+ 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;
+ p += SIZE_RELADDR;
goto lookaround;
case OP_PUSH_LOOK_BEHIND_NOT:
- p += SIZE_RELADDR;
- p += SIZE_LENGTH;
+ 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;
+ {
+ 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_FAIL_POS:
case OP_FAIL_LOOK_BEHIND_NOT:
case OP_POP_STOP_BT:
- goto exit;
+ goto exit;
case OP_LOOK_BEHIND:
- p += SIZE_LENGTH;
- break;
+ p += SIZE_LENGTH;
+ break;
case OP_ABSENT_END:
case OP_ABSENT:
- goto unexpected_bytecode_error;
+ goto unexpected_bytecode_error;
case OP_CALL:
case OP_RETURN:
- goto unexpected_bytecode_error;
+ goto unexpected_bytecode_error;
case OP_CONDITION:
- goto unexpected_bytecode_error;
+ goto unexpected_bytecode_error;
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 unexpected_bytecode_error;
+ goto unexpected_bytecode_error;
case OP_SET_OPTION_PUSH:
case OP_SET_OPTION:
- p += SIZE_OPTION;
- break;
+ p += SIZE_OPTION;
+ break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
@@ -1159,13 +1174,15 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
stk_base = stk_alloc;\
stk = stk_base;\
stk_end = stk_base + msa->stack_n;\
- } else {\
+ }\
+ else {\
stk_alloc = (OnigStackType* )xalloca(sizeof(OnigStackType) * (stack_num));\
stk_base = stk_alloc;\
stk = stk_base;\
stk_end = stk_base + (stack_num);\
}\
- } else if (msa->stack_p) {\
+ }\
+ else if (msa->stack_p) {\
alloc_addr = (char* )xalloca(sizeof(OnigStackIndex) * (ptr_num));\
heap_addr = NULL;\
stk_alloc = (OnigStackType* )(msa->stack_p);\
@@ -1175,7 +1192,7 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
}\
else {\
alloc_addr = (char* )xalloca(sizeof(OnigStackIndex) * (ptr_num)\
- + sizeof(OnigStackType) * (stack_num));\
+ + sizeof(OnigStackType) * (stack_num));\
heap_addr = NULL;\
stk_alloc = (OnigStackType* )(alloc_addr + sizeof(OnigStackIndex) * (ptr_num));\
stk_base = stk_alloc;\
@@ -1208,7 +1225,7 @@ onig_set_match_stack_limit_size(unsigned int size)
static int
stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
- OnigStackType** arg_stk, OnigStackType* stk_alloc, OnigMatchArg* msa)
+ OnigStackType** arg_stk, OnigStackType* stk_alloc, OnigMatchArg* msa)
{
size_t n;
OnigStackType *x, *stk_base, *stk_end, *stk;
@@ -1232,9 +1249,9 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
n *= 2;
if (limit_size != 0 && n > limit_size) {
if ((unsigned int )(stk_end - stk_base) == limit_size)
- return ONIGERR_MATCH_STACK_LIMIT_OVER;
+ return ONIGERR_MATCH_STACK_LIMIT_OVER;
else
- n = limit_size;
+ n = limit_size;
}
x = (OnigStackType* )xrealloc(stk_base, sizeof(OnigStackType) * n);
if (IS_NULL(x)) {
@@ -1517,7 +1534,8 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
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) {\
+ }\
+ 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);\
}\
@@ -1538,7 +1556,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
#else
# define INC_NUM_FAILS ((void) 0)
# define MEMOIZE_MATCH_CACHE_POINT ((void) 0)
-# define MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT ((void) 0)
+# define MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(stkp) ((void) 0)
#endif
#define STACK_POP_ONE do {\
@@ -1883,7 +1901,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
} while(0)
static int string_cmp_ic(OnigEncoding enc, int case_fold_flag,
- UChar* s1, UChar** ps2, OnigDistance mblen, const UChar* text_end)
+ UChar* s1, UChar** ps2, OnigDistance mblen, const UChar* text_end)
{
UChar buf1[ONIGENC_MBC_CASE_FOLD_MAXLEN];
UChar buf2[ONIGENC_MBC_CASE_FOLD_MAXLEN];
@@ -1970,29 +1988,29 @@ make_capture_history_tree(OnigCaptureTreeNode* node, OnigStackType** kp,
if (k->type == STK_MEM_START) {
n = k->u.mem.num;
if (n <= ONIG_MAX_CAPTURE_HISTORY_GROUP &&
- BIT_STATUS_AT(reg->capture_history, n) != 0) {
- child = history_node_new();
- CHECK_NULL_RETURN_MEMERR(child);
- child->group = n;
- child->beg = k->u.mem.pstr - str;
- r = history_tree_add_child(node, child);
- if (r != 0) {
- history_tree_free(child);
- return r;
- }
- *kp = (k + 1);
- r = make_capture_history_tree(child, kp, stk_top, str, reg);
- if (r != 0) return r;
+ BIT_STATUS_AT(reg->capture_history, n) != 0) {
+ child = history_node_new();
+ CHECK_NULL_RETURN_MEMERR(child);
+ child->group = n;
+ child->beg = k->u.mem.pstr - str;
+ r = history_tree_add_child(node, child);
+ if (r != 0) {
+ history_tree_free(child);
+ return r;
+ }
+ *kp = (k + 1);
+ r = make_capture_history_tree(child, kp, stk_top, str, reg);
+ if (r != 0) return r;
- k = *kp;
- child->end = k->u.mem.pstr - str;
+ k = *kp;
+ child->end = k->u.mem.pstr - str;
}
}
else if (k->type == STK_MEM_END) {
if (k->u.mem.num == node->group) {
- node->end = k->u.mem.pstr - str;
- *kp = k;
- return 0;
+ node->end = k->u.mem.pstr - str;
+ *kp = k;
+ return 0;
}
}
k++;
@@ -2017,9 +2035,9 @@ mem_is_in_memp(int mem, int num, UChar* memp)
}
static int backref_match_at_nested_level(regex_t* reg,
- OnigStackType* top, OnigStackType* stk_base,
- int ignore_case, int case_fold_flag,
- int nest, int mem_num, UChar* memp, UChar** s, const UChar* send)
+ OnigStackType* top, OnigStackType* stk_base,
+ int ignore_case, int case_fold_flag,
+ int nest, int mem_num, UChar* memp, UChar** s, const UChar* send)
{
UChar *ss, *p, *pstart, *pend = NULL_UCHARP;
int level;
@@ -2037,33 +2055,33 @@ static int backref_match_at_nested_level(regex_t* reg,
}
else if (level == nest) {
if (k->type == STK_MEM_START) {
- if (mem_is_in_memp(k->u.mem.num, mem_num, memp)) {
- pstart = k->u.mem.pstr;
- if (pend != NULL_UCHARP) {
- if (pend - pstart > send - *s) return 0; /* or goto next_mem; */
- p = pstart;
- ss = *s;
-
- if (ignore_case != 0) {
- if (string_cmp_ic(reg->enc, case_fold_flag,
- pstart, &ss, pend - pstart, send) == 0)
- return 0; /* or goto next_mem; */
- }
- else {
- while (p < pend) {
- if (*p++ != *ss++) return 0; /* or goto next_mem; */
- }
- }
-
- *s = ss;
- return 1;
- }
- }
+ if (mem_is_in_memp(k->u.mem.num, mem_num, memp)) {
+ pstart = k->u.mem.pstr;
+ if (pend != NULL_UCHARP) {
+ if (pend - pstart > send - *s) return 0; /* or goto next_mem; */
+ p = pstart;
+ ss = *s;
+
+ if (ignore_case != 0) {
+ if (string_cmp_ic(reg->enc, case_fold_flag,
+ pstart, &ss, pend - pstart, send) == 0)
+ return 0; /* or goto next_mem; */
+ }
+ else {
+ while (p < pend) {
+ if (*p++ != *ss++) return 0; /* or goto next_mem; */
+ }
+ }
+
+ *s = ss;
+ return 1;
+ }
+ }
}
else if (k->type == STK_MEM_END) {
- if (mem_is_in_memp(k->u.mem.num, mem_num, memp)) {
- pend = k->u.mem.pstr;
- }
+ if (mem_is_in_memp(k->u.mem.num, mem_num, memp)) {
+ pend = k->u.mem.pstr;
+ }
}
}
k--;
@@ -2081,7 +2099,7 @@ static int backref_match_at_nested_level(regex_t* reg,
static LARGE_INTEGER ts, te, freq;
# define GETTIME(t) QueryPerformanceCounter(&(t))
# define TIMEDIFF(te,ts) (unsigned long )(((te).QuadPart - (ts).QuadPart) \
- * 1000000 / freq.QuadPart)
+ * 1000000 / freq.QuadPart)
# else /* _WIN32 */
# define USE_TIMEOFDAY
@@ -2147,7 +2165,7 @@ onig_print_statistics(FILE* f)
fprintf(f, " count prev time\n");
for (i = 0; OnigOpInfo[i].opcode >= 0; i++) {
fprintf(f, "%8d: %8d: %10lu: %s\n",
- OpCounter[i], OpPrevCounter[i], OpTime[i], OnigOpInfo[i].name);
+ OpCounter[i], OpPrevCounter[i], OpTime[i], OnigOpInfo[i].name);
}
fprintf(f, "\nmax stack depth: %d\n", MaxStackDepth);
}
@@ -2262,19 +2280,25 @@ find_cache_point(regex_t* reg, const OnigCacheOpcode* cache_opcodes, long num_ca
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) {
+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 {
+ }
+ 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) {
+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 {
+ }
+ else {
match_cache_buf[match_cache_point_index] |= match_cache_point_mask << 1;
}
}
@@ -2286,9 +2310,9 @@ static void memoize_extended_match_cache_point(uint8_t *match_cache_buf, long ma
static OnigPosition
match_at(regex_t* reg, const UChar* str, const UChar* end,
#ifdef USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE
- const UChar* right_range,
+ const UChar* right_range,
#endif
- const UChar* sstart, UChar* sprev, OnigMatchArg* msa)
+ const UChar* sstart, UChar* sprev, OnigMatchArg* msa)
{
static const UChar FinishCode[] = { OP_FINISH };
@@ -2538,16 +2562,16 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
}
#ifndef USE_SUBEXP_CALL
mem_start_stk--; /* for index start from 1,
- mem_start_stk[1]..mem_start_stk[num_mem] */
+ mem_start_stk[1]..mem_start_stk[num_mem] */
mem_end_stk--; /* for index start from 1,
- mem_end_stk[1]..mem_end_stk[num_mem] */
+ mem_end_stk[1]..mem_end_stk[num_mem] */
#endif
#ifdef ONIG_DEBUG_MATCH
fprintf(stderr, "match_at: str: %"PRIuPTR" (%p), end: %"PRIuPTR" (%p), start: %"PRIuPTR" (%p), sprev: %"PRIuPTR" (%p)\n",
- (uintptr_t )str, str, (uintptr_t )end, end, (uintptr_t )sstart, sstart, (uintptr_t )sprev, sprev);
+ (uintptr_t )str, str, (uintptr_t )end, end, (uintptr_t )sstart, sstart, (uintptr_t )sprev, sprev);
fprintf(stderr, "size: %d, start offset: %d\n",
- (int )(end - str), (int )(sstart - str));
+ (int )(end - str), (int )(sstart - str));
fprintf(stderr, "\n ofs> str stk:type addr:opcode\n");
#endif
@@ -2567,10 +2591,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
bp = buf; \
q = s; \
if (*op != OP_FINISH) { /* s may not be a valid pointer if OP_FINISH. */ \
- for (i = 0; i < 7 && q < end; i++) { \
- len = enclen(encode, q, end); \
- while (len-- > 0) *bp++ = *q++; \
- } \
+ for (i = 0; i < 7 && q < end; i++) { \
+ len = enclen(encode, q, end); \
+ while (len-- > 0) *bp++ = *q++; \
+ } \
if (q < end) { xmemcpy(bp, "...", 3); bp += 3; } \
} \
xmemcpy(bp, "\"", 1); bp += 1; \
@@ -2578,9 +2602,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
fputs((char* )buf, stderr); \
for (i = 0; i < 20 - (bp - buf); i++) fputc(' ', stderr); \
fprintf(stderr, "%4"PRIdPTR":%s %4"PRIdPTR":", \
- stk - stk_base - 1, \
- (stk > stk_base) ? stack_type_str(stk[-1].type) : " ", \
- (op == FinishCode) ? (ptrdiff_t )-1 : op - reg->p); \
+ stk - stk_base - 1, \
+ (stk > stk_base) ? stack_type_str(stk[-1].type) : " ", \
+ (op == FinishCode) ? (ptrdiff_t )-1 : op - reg->p); \
onig_print_compiled_byte_code(stderr, op, reg->p+reg->used, NULL, encode); \
fprintf(stderr, "\n"); \
}
@@ -2609,19 +2633,22 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
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)) {\
+ 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;\
+ }\
+ 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;\
+ }\
+ else goto fail;\
}\
}\
STACK_PUSH_MATCH_CACHE_POINT(match_cache_point_index, match_cache_point_mask);\
@@ -2636,66 +2663,66 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_END) MOP_IN(OP_END);
n = s - sstart;
if (n > best_len) {
- OnigRegion* region;
+ OnigRegion* region;
#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
- if (IS_FIND_LONGEST(option)) {
- if (n > msa->best_len) {
- msa->best_len = n;
- msa->best_s = (UChar* )sstart;
- }
- else
- goto end_best_len;
- }
+ if (IS_FIND_LONGEST(option)) {
+ if (n > msa->best_len) {
+ msa->best_len = n;
+ msa->best_s = (UChar* )sstart;
+ }
+ else
+ goto end_best_len;
+ }
#endif
- best_len = n;
- region = msa->region;
- if (region) {
- region->beg[0] = ((pkeep > s) ? s : pkeep) - str;
- region->end[0] = s - str;
- for (i = 1; i <= num_mem; i++) {
- if (mem_end_stk[i] != INVALID_STACK_INDEX) {
- if (BIT_STATUS_AT(reg->bt_mem_start, i))
- region->beg[i] = STACK_AT(mem_start_stk[i])->u.mem.pstr - str;
- else
- region->beg[i] = (UChar* )((void* )mem_start_stk[i]) - str;
-
- region->end[i] = (BIT_STATUS_AT(reg->bt_mem_end, i)
- ? STACK_AT(mem_end_stk[i])->u.mem.pstr
- : (UChar* )((void* )mem_end_stk[i])) - str;
- }
- else {
- region->beg[i] = region->end[i] = ONIG_REGION_NOTPOS;
- }
- }
+ best_len = n;
+ region = msa->region;
+ if (region) {
+ region->beg[0] = ((pkeep > s) ? s : pkeep) - str;
+ region->end[0] = s - str;
+ for (i = 1; i <= num_mem; i++) {
+ if (mem_end_stk[i] != INVALID_STACK_INDEX) {
+ if (BIT_STATUS_AT(reg->bt_mem_start, i))
+ region->beg[i] = STACK_AT(mem_start_stk[i])->u.mem.pstr - str;
+ else
+ region->beg[i] = (UChar* )((void* )mem_start_stk[i]) - str;
+
+ region->end[i] = (BIT_STATUS_AT(reg->bt_mem_end, i)
+ ? STACK_AT(mem_end_stk[i])->u.mem.pstr
+ : (UChar* )((void* )mem_end_stk[i])) - str;
+ }
+ else {
+ region->beg[i] = region->end[i] = ONIG_REGION_NOTPOS;
+ }
+ }
#ifdef USE_CAPTURE_HISTORY
- if (reg->capture_history != 0) {
- int r;
- OnigCaptureTreeNode* node;
-
- if (IS_NULL(region->history_root)) {
- region->history_root = node = history_node_new();
- CHECK_NULL_RETURN_MEMERR(node);
- }
- else {
- node = region->history_root;
- history_tree_clear(node);
- }
-
- node->group = 0;
- node->beg = ((pkeep > s) ? s : pkeep) - str;
- node->end = s - str;
-
- stkp = stk_base;
- r = make_capture_history_tree(region->history_root, &stkp,
- stk, (UChar* )str, reg);
- if (r < 0) {
- best_len = r; /* error code */
- goto finish;
- }
- }
+ if (reg->capture_history != 0) {
+ int r;
+ OnigCaptureTreeNode* node;
+
+ if (IS_NULL(region->history_root)) {
+ region->history_root = node = history_node_new();
+ CHECK_NULL_RETURN_MEMERR(node);
+ }
+ else {
+ node = region->history_root;
+ history_tree_clear(node);
+ }
+
+ node->group = 0;
+ node->beg = ((pkeep > s) ? s : pkeep) - str;
+ node->end = s - str;
+
+ stkp = stk_base;
+ r = make_capture_history_tree(region->history_root, &stkp,
+ stk, (UChar* )str, reg);
+ if (r < 0) {
+ best_len = r; /* error code */
+ goto finish;
+ }
+ }
#endif /* USE_CAPTURE_HISTORY */
- } /* if (region) */
+ } /* if (region) */
} /* n > best_len */
#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
@@ -2704,18 +2731,17 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
MOP_OUT;
if (IS_FIND_CONDITION(option)) {
- if (IS_FIND_NOT_EMPTY(option) && s == sstart) {
- best_len = ONIG_MISMATCH;
- goto fail; /* for retry */
- }
- if (IS_FIND_LONGEST(option) && DATA_ENSURE_CHECK1) {
- goto fail; /* for retry */
- }
+ if (IS_FIND_NOT_EMPTY(option) && s == sstart) {
+ best_len = ONIG_MISMATCH;
+ goto fail; /* for retry */
+ }
+ if (IS_FIND_LONGEST(option) && DATA_ENSURE_CHECK1) {
+ goto fail; /* for retry */
+ }
}
/* default behavior: return first-matching result. */
goto finish;
- NEXT;
CASE(OP_EXACT1) MOP_IN(OP_EXACT1);
DATA_ENSURE(1);
@@ -2726,22 +2752,22 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_EXACT1_IC) MOP_IN(OP_EXACT1_IC);
{
- int len;
- UChar *q, lowbuf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
-
- DATA_ENSURE(1);
- len = ONIGENC_MBC_CASE_FOLD(encode,
- /* DISABLE_CASE_FOLD_MULTI_CHAR(case_fold_flag), */
- case_fold_flag,
- &s, end, lowbuf);
- DATA_ENSURE(0);
- q = lowbuf;
- while (len-- > 0) {
- if (*p != *q) {
- goto fail;
- }
- p++; q++;
- }
+ int len;
+ UChar *q, lowbuf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
+
+ DATA_ENSURE(1);
+ len = ONIGENC_MBC_CASE_FOLD(encode,
+ /* DISABLE_CASE_FOLD_MULTI_CHAR(case_fold_flag), */
+ case_fold_flag,
+ &s, end, lowbuf);
+ DATA_ENSURE(0);
+ q = lowbuf;
+ while (len-- > 0) {
+ if (*p != *q) {
+ goto fail;
+ }
+ p++; q++;
+ }
}
MOP_OUT;
NEXT;
@@ -2802,7 +2828,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_LENGTH_INC(tlen, p);
DATA_ENSURE(tlen);
while (tlen-- > 0) {
- if (*p++ != *s++) goto fail;
+ if (*p++ != *s++) goto fail;
}
sprev = s - 1;
MOP_OUT;
@@ -2810,26 +2836,26 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_EXACTN_IC) MOP_IN(OP_EXACTN_IC);
{
- int len;
- UChar *q, *endp, lowbuf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
-
- GET_LENGTH_INC(tlen, p);
- endp = p + tlen;
-
- while (p < endp) {
- sprev = s;
- DATA_ENSURE(1);
- len = ONIGENC_MBC_CASE_FOLD(encode,
- /* DISABLE_CASE_FOLD_MULTI_CHAR(case_fold_flag), */
- case_fold_flag,
- &s, end, lowbuf);
- DATA_ENSURE(0);
- q = lowbuf;
- while (len-- > 0) {
- if (*p != *q) goto fail;
- p++; q++;
- }
- }
+ int len;
+ UChar *q, *endp, lowbuf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
+
+ GET_LENGTH_INC(tlen, p);
+ endp = p + tlen;
+
+ while (p < endp) {
+ sprev = s;
+ DATA_ENSURE(1);
+ len = ONIGENC_MBC_CASE_FOLD(encode,
+ /* DISABLE_CASE_FOLD_MULTI_CHAR(case_fold_flag), */
+ case_fold_flag,
+ &s, end, lowbuf);
+ DATA_ENSURE(0);
+ q = lowbuf;
+ while (len-- > 0) {
+ if (*p != *q) goto fail;
+ p++; q++;
+ }
+ }
}
MOP_OUT;
@@ -2880,10 +2906,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_LENGTH_INC(tlen, p);
DATA_ENSURE(tlen * 2);
while (tlen-- > 0) {
- if (*p != *s) goto fail;
- p++; s++;
- if (*p != *s) goto fail;
- p++; s++;
+ if (*p != *s) goto fail;
+ p++; s++;
+ if (*p != *s) goto fail;
+ p++; s++;
}
sprev = s - 2;
MOP_OUT;
@@ -2893,12 +2919,12 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_LENGTH_INC(tlen, p);
DATA_ENSURE(tlen * 3);
while (tlen-- > 0) {
- if (*p != *s) goto fail;
- p++; s++;
- if (*p != *s) goto fail;
- p++; s++;
- if (*p != *s) goto fail;
- p++; s++;
+ if (*p != *s) goto fail;
+ p++; s++;
+ if (*p != *s) goto fail;
+ p++; s++;
+ if (*p != *s) goto fail;
+ p++; s++;
}
sprev = s - 3;
MOP_OUT;
@@ -2910,8 +2936,8 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
tlen2 *= tlen;
DATA_ENSURE(tlen2);
while (tlen2-- > 0) {
- if (*p != *s) goto fail;
- p++; s++;
+ if (*p != *s) goto fail;
+ p++; s++;
}
sprev = s - tlen;
MOP_OUT;
@@ -2931,23 +2957,23 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
cclass_mb:
GET_LENGTH_INC(tlen, p);
{
- OnigCodePoint code;
- UChar *ss;
- int mb_len;
+ OnigCodePoint code;
+ UChar *ss;
+ int mb_len;
- DATA_ENSURE(1);
- mb_len = enclen_approx(encode, s, end);
- DATA_ENSURE(mb_len);
- ss = s;
- s += mb_len;
- code = ONIGENC_MBC_TO_CODE(encode, ss, s);
+ DATA_ENSURE(1);
+ mb_len = enclen_approx(encode, s, end);
+ DATA_ENSURE(mb_len);
+ ss = s;
+ s += mb_len;
+ code = ONIGENC_MBC_TO_CODE(encode, ss, s);
#ifdef PLATFORM_UNALIGNED_WORD_ACCESS
- if (! onig_is_in_code_range(p, code)) goto fail;
+ if (! onig_is_in_code_range(p, code)) goto fail;
#else
- q = p;
- ALIGNMENT_RIGHT(q);
- if (! onig_is_in_code_range(q, code)) goto fail;
+ q = p;
+ ALIGNMENT_RIGHT(q);
+ if (! onig_is_in_code_range(q, code)) goto fail;
#endif
}
p += tlen;
@@ -2957,17 +2983,17 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_CCLASS_MIX) MOP_IN(OP_CCLASS_MIX);
DATA_ENSURE(1);
if (ONIGENC_IS_MBC_HEAD(encode, s, end)) {
- p += SIZE_BITSET;
- goto cclass_mb;
+ p += SIZE_BITSET;
+ goto cclass_mb;
}
else {
- if (BITSET_AT(((BitSetRef )p), *s) == 0)
- goto fail;
+ if (BITSET_AT(((BitSetRef )p), *s) == 0)
+ goto fail;
- p += SIZE_BITSET;
- GET_LENGTH_INC(tlen, p);
- p += tlen;
- s++;
+ p += SIZE_BITSET;
+ GET_LENGTH_INC(tlen, p);
+ p += tlen;
+ s++;
}
MOP_OUT;
NEXT;
@@ -2983,36 +3009,36 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_CCLASS_MB_NOT) MOP_IN(OP_CCLASS_MB_NOT);
DATA_ENSURE(1);
if (! ONIGENC_IS_MBC_HEAD(encode, s, end)) {
- s++;
- GET_LENGTH_INC(tlen, p);
- p += tlen;
- goto cc_mb_not_success;
+ s++;
+ GET_LENGTH_INC(tlen, p);
+ p += tlen;
+ goto cc_mb_not_success;
}
cclass_mb_not:
GET_LENGTH_INC(tlen, p);
{
- OnigCodePoint code;
- UChar *ss;
- int mb_len = enclen(encode, s, end);
-
- if (! DATA_ENSURE_CHECK(mb_len)) {
- DATA_ENSURE(1);
- s = (UChar* )end;
- p += tlen;
- goto cc_mb_not_success;
- }
+ OnigCodePoint code;
+ UChar *ss;
+ int mb_len = enclen(encode, s, end);
+
+ if (! DATA_ENSURE_CHECK(mb_len)) {
+ DATA_ENSURE(1);
+ s = (UChar* )end;
+ p += tlen;
+ goto cc_mb_not_success;
+ }
- ss = s;
- s += mb_len;
- code = ONIGENC_MBC_TO_CODE(encode, ss, s);
+ ss = s;
+ s += mb_len;
+ code = ONIGENC_MBC_TO_CODE(encode, ss, s);
#ifdef PLATFORM_UNALIGNED_WORD_ACCESS
- if (onig_is_in_code_range(p, code)) goto fail;
+ if (onig_is_in_code_range(p, code)) goto fail;
#else
- q = p;
- ALIGNMENT_RIGHT(q);
- if (onig_is_in_code_range(q, code)) goto fail;
+ q = p;
+ ALIGNMENT_RIGHT(q);
+ if (onig_is_in_code_range(q, code)) goto fail;
#endif
}
p += tlen;
@@ -3024,17 +3050,17 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_CCLASS_MIX_NOT) MOP_IN(OP_CCLASS_MIX_NOT);
DATA_ENSURE(1);
if (ONIGENC_IS_MBC_HEAD(encode, s, end)) {
- p += SIZE_BITSET;
- goto cclass_mb_not;
+ p += SIZE_BITSET;
+ goto cclass_mb_not;
}
else {
- if (BITSET_AT(((BitSetRef )p), *s) != 0)
- goto fail;
+ if (BITSET_AT(((BitSetRef )p), *s) != 0)
+ goto fail;
- p += SIZE_BITSET;
- GET_LENGTH_INC(tlen, p);
- p += tlen;
- s++;
+ p += SIZE_BITSET;
+ GET_LENGTH_INC(tlen, p);
+ p += tlen;
+ s++;
}
MOP_OUT;
NEXT;
@@ -3058,52 +3084,52 @@ 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;
- STACK_PUSH_ALT(p, s, sprev, pkeep);
- n = enclen_approx(encode, s, end);
- DATA_ENSURE(n);
- if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
- sprev = s;
- s += n;
+ CHECK_MATCH_CACHE;
+ STACK_PUSH_ALT(p, s, sprev, pkeep);
+ n = enclen_approx(encode, s, end);
+ DATA_ENSURE(n);
+ if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
+ sprev = s;
+ s += n;
}
MOP_OUT;
JUMP;
CASE(OP_ANYCHAR_ML_STAR) MOP_IN(OP_ANYCHAR_ML_STAR);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
- STACK_PUSH_ALT(p, s, sprev, pkeep);
- n = enclen_approx(encode, s, end);
- if (n > 1) {
- DATA_ENSURE(n);
- sprev = s;
- s += n;
- }
- else {
- sprev = s;
- s++;
- }
+ CHECK_MATCH_CACHE;
+ STACK_PUSH_ALT(p, s, sprev, pkeep);
+ n = enclen_approx(encode, s, end);
+ if (n > 1) {
+ DATA_ENSURE(n);
+ sprev = s;
+ s += n;
+ }
+ else {
+ sprev = s;
+ s++;
+ }
}
MOP_OUT;
JUMP;
CASE(OP_ANYCHAR_STAR_PEEK_NEXT) MOP_IN(OP_ANYCHAR_STAR_PEEK_NEXT);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
- if (*p == *s) {
- STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
- } else {
+ CHECK_MATCH_CACHE;
+ if (*p == *s) {
+ STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
+ } else {
#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly. */
- /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR` simply in this case.*/
- msa->num_fails++;
+ /* We need to increment num_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);
- DATA_ENSURE(n);
- if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
- sprev = s;
- s += n;
+ }
+ n = enclen_approx(encode, s, end);
+ DATA_ENSURE(n);
+ if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
+ sprev = s;
+ s += n;
}
p++;
MOP_OUT;
@@ -3111,26 +3137,26 @@ 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) {
- STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
- } else {
+ CHECK_MATCH_CACHE;
+ if (*p == *s) {
+ STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
+ } else {
#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly. */
- /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR_ML` simply in this case.*/
- msa->num_fails++;
+ /* We need to increment num_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);
- if (n > 1) {
- DATA_ENSURE(n);
- sprev = s;
- s += n;
- }
- else {
- sprev = s;
- s++;
- }
+ }
+ n = enclen_approx(encode, s, end);
+ if (n > 1) {
+ DATA_ENSURE(n);
+ sprev = s;
+ s += n;
+ }
+ else {
+ sprev = s;
+ s++;
+ }
}
p++;
MOP_OUT;
@@ -3140,15 +3166,15 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_STATE_CHECK_ANYCHAR_STAR) MOP_IN(OP_STATE_CHECK_ANYCHAR_STAR);
GET_STATE_CHECK_NUM_INC(mem, p);
while (DATA_ENSURE_CHECK1) {
- STATE_CHECK_VAL(scv, mem);
- if (scv) goto fail;
-
- STACK_PUSH_ALT_WITH_STATE_CHECK(p, s, sprev, mem, pkeep);
- n = enclen_approx(encode, s, end);
- DATA_ENSURE(n);
- if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
- sprev = s;
- s += n;
+ STATE_CHECK_VAL(scv, mem);
+ if (scv) goto fail;
+
+ STACK_PUSH_ALT_WITH_STATE_CHECK(p, s, sprev, mem, pkeep);
+ n = enclen_approx(encode, s, end);
+ DATA_ENSURE(n);
+ if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
+ sprev = s;
+ s += n;
}
MOP_OUT;
NEXT;
@@ -3158,20 +3184,20 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_STATE_CHECK_NUM_INC(mem, p);
while (DATA_ENSURE_CHECK1) {
- STATE_CHECK_VAL(scv, mem);
- if (scv) goto fail;
-
- STACK_PUSH_ALT_WITH_STATE_CHECK(p, s, sprev, mem, pkeep);
- n = enclen_approx(encode, s, end);
- if (n > 1) {
- DATA_ENSURE(n);
- sprev = s;
- s += n;
- }
- else {
- sprev = s;
- s++;
- }
+ STATE_CHECK_VAL(scv, mem);
+ if (scv) goto fail;
+
+ STACK_PUSH_ALT_WITH_STATE_CHECK(p, s, sprev, mem, pkeep);
+ n = enclen_approx(encode, s, end);
+ if (n > 1) {
+ DATA_ENSURE(n);
+ sprev = s;
+ s += n;
+ }
+ else {
+ sprev = s;
+ s++;
+ }
}
MOP_OUT;
NEXT;
@@ -3180,7 +3206,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_WORD) MOP_IN(OP_WORD);
DATA_ENSURE(1);
if (! ONIGENC_IS_MBC_WORD(encode, s, end))
- goto fail;
+ goto fail;
s += enclen(encode, s, end);
MOP_OUT;
@@ -3189,7 +3215,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ASCII_WORD) MOP_IN(OP_ASCII_WORD);
DATA_ENSURE(1);
if (! ONIGENC_IS_MBC_ASCII_WORD(encode, s, end))
- goto fail;
+ goto fail;
s += enclen(encode, s, end);
MOP_OUT;
@@ -3198,7 +3224,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_NOT_WORD) MOP_IN(OP_NOT_WORD);
DATA_ENSURE(1);
if (ONIGENC_IS_MBC_WORD(encode, s, end))
- goto fail;
+ goto fail;
s += enclen(encode, s, end);
MOP_OUT;
@@ -3207,7 +3233,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_NOT_ASCII_WORD) MOP_IN(OP_NOT_ASCII_WORD);
DATA_ENSURE(1);
if (ONIGENC_IS_MBC_ASCII_WORD(encode, s, end))
- goto fail;
+ goto fail;
s += enclen(encode, s, end);
MOP_OUT;
@@ -3215,70 +3241,70 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_WORD_BOUND) MOP_IN(OP_WORD_BOUND);
if (ON_STR_BEGIN(s)) {
- DATA_ENSURE(1);
- if (! ONIGENC_IS_MBC_WORD(encode, s, end))
- goto fail;
+ DATA_ENSURE(1);
+ if (! ONIGENC_IS_MBC_WORD(encode, s, end))
+ goto fail;
}
else if (ON_STR_END(s)) {
- if (! ONIGENC_IS_MBC_WORD(encode, sprev, end))
- goto fail;
+ if (! ONIGENC_IS_MBC_WORD(encode, sprev, end))
+ goto fail;
}
else {
- if (ONIGENC_IS_MBC_WORD(encode, s, end)
- == ONIGENC_IS_MBC_WORD(encode, sprev, end))
- goto fail;
+ if (ONIGENC_IS_MBC_WORD(encode, s, end)
+ == ONIGENC_IS_MBC_WORD(encode, sprev, end))
+ goto fail;
}
MOP_OUT;
JUMP;
CASE(OP_ASCII_WORD_BOUND) MOP_IN(OP_ASCII_WORD_BOUND);
if (ON_STR_BEGIN(s)) {
- DATA_ENSURE(1);
- if (! ONIGENC_IS_MBC_ASCII_WORD(encode, s, end))
- goto fail;
+ DATA_ENSURE(1);
+ if (! ONIGENC_IS_MBC_ASCII_WORD(encode, s, end))
+ goto fail;
}
else if (ON_STR_END(s)) {
- if (! ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
- goto fail;
+ if (! ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
+ goto fail;
}
else {
- if (ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)
- == ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
- goto fail;
+ if (ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)
+ == ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
+ goto fail;
}
MOP_OUT;
JUMP;
CASE(OP_NOT_WORD_BOUND) MOP_IN(OP_NOT_WORD_BOUND);
if (ON_STR_BEGIN(s)) {
- if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_WORD(encode, s, end))
- goto fail;
+ if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_WORD(encode, s, end))
+ goto fail;
}
else if (ON_STR_END(s)) {
- if (ONIGENC_IS_MBC_WORD(encode, sprev, end))
- goto fail;
+ if (ONIGENC_IS_MBC_WORD(encode, sprev, end))
+ goto fail;
}
else {
- if (ONIGENC_IS_MBC_WORD(encode, s, end)
- != ONIGENC_IS_MBC_WORD(encode, sprev, end))
- goto fail;
+ if (ONIGENC_IS_MBC_WORD(encode, s, end)
+ != ONIGENC_IS_MBC_WORD(encode, sprev, end))
+ goto fail;
}
MOP_OUT;
JUMP;
CASE(OP_NOT_ASCII_WORD_BOUND) MOP_IN(OP_NOT_ASCII_WORD_BOUND);
if (ON_STR_BEGIN(s)) {
- if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_ASCII_WORD(encode, s, end))
- goto fail;
+ if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_ASCII_WORD(encode, s, end))
+ goto fail;
}
else if (ON_STR_END(s)) {
- if (ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
- goto fail;
+ if (ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
+ goto fail;
}
else {
- if (ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)
- != ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
- goto fail;
+ if (ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)
+ != ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end))
+ goto fail;
}
MOP_OUT;
JUMP;
@@ -3286,43 +3312,39 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
#ifdef USE_WORD_BEGIN_END
CASE(OP_WORD_BEGIN) MOP_IN(OP_WORD_BEGIN);
if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_WORD(encode, s, end)) {
- if (ON_STR_BEGIN(s) || !ONIGENC_IS_MBC_WORD(encode, sprev, end)) {
- MOP_OUT;
- JUMP;
+ if (ON_STR_BEGIN(s) || !ONIGENC_IS_MBC_WORD(encode, sprev, end)) {
+ MOP_OUT;
+ JUMP;
}
}
goto fail;
- NEXT;
CASE(OP_ASCII_WORD_BEGIN) MOP_IN(OP_ASCII_WORD_BEGIN);
if (DATA_ENSURE_CHECK1 && ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)) {
- if (ON_STR_BEGIN(s) || !ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end)) {
- MOP_OUT;
- JUMP;
+ if (ON_STR_BEGIN(s) || !ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end)) {
+ MOP_OUT;
+ JUMP;
}
}
goto fail;
- NEXT;
CASE(OP_WORD_END) MOP_IN(OP_WORD_END);
if (!ON_STR_BEGIN(s) && ONIGENC_IS_MBC_WORD(encode, sprev, end)) {
- if (ON_STR_END(s) || !ONIGENC_IS_MBC_WORD(encode, s, end)) {
- MOP_OUT;
- JUMP;
+ if (ON_STR_END(s) || !ONIGENC_IS_MBC_WORD(encode, s, end)) {
+ MOP_OUT;
+ JUMP;
}
}
goto fail;
- NEXT;
CASE(OP_ASCII_WORD_END) MOP_IN(OP_ASCII_WORD_END);
if (!ON_STR_BEGIN(s) && ONIGENC_IS_MBC_ASCII_WORD(encode, sprev, end)) {
- if (ON_STR_END(s) || !ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)) {
- MOP_OUT;
- JUMP;
+ if (ON_STR_END(s) || !ONIGENC_IS_MBC_ASCII_WORD(encode, s, end)) {
+ MOP_OUT;
+ JUMP;
}
}
goto fail;
- NEXT;
#endif
CASE(OP_BEGIN_BUF) MOP_IN(OP_BEGIN_BUF);
@@ -3341,76 +3363,73 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_BEGIN_LINE) MOP_IN(OP_BEGIN_LINE);
if (ON_STR_BEGIN(s)) {
- if (IS_NOTBOL(msa->options)) goto fail;
- MOP_OUT;
- JUMP;
+ if (IS_NOTBOL(msa->options)) goto fail;
+ MOP_OUT;
+ JUMP;
}
else if (ONIGENC_IS_MBC_NEWLINE(encode, sprev, end)
#ifdef USE_CRNL_AS_LINE_TERMINATOR
- && !(IS_NEWLINE_CRLF(option)
- && ONIGENC_IS_MBC_CRNL(encode, sprev, end))
+ && !(IS_NEWLINE_CRLF(option)
+ && ONIGENC_IS_MBC_CRNL(encode, sprev, end))
#endif
- && !ON_STR_END(s)) {
- MOP_OUT;
+ && !ON_STR_END(s)) {
+ MOP_OUT;
JUMP;
}
goto fail;
- NEXT;
CASE(OP_END_LINE) MOP_IN(OP_END_LINE);
if (ON_STR_END(s)) {
#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
- if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE_EX(encode, sprev, str, end, option, 1)) {
+ if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE_EX(encode, sprev, str, end, option, 1)) {
#endif
- if (IS_NOTEOL(msa->options)) goto fail;
- MOP_OUT;
- JUMP;
+ if (IS_NOTEOL(msa->options)) goto fail;
+ MOP_OUT;
+ JUMP;
#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
- }
+ }
#endif
}
else if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 1)) {
- MOP_OUT;
+ MOP_OUT;
JUMP;
}
goto fail;
- NEXT;
CASE(OP_SEMI_END_BUF) MOP_IN(OP_SEMI_END_BUF);
if (ON_STR_END(s)) {
#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
- if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE_EX(encode, sprev, str, end, option, 1)) {
+ if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE_EX(encode, sprev, str, end, option, 1)) {
#endif
- if (IS_NOTEOL(msa->options)) goto fail;
- MOP_OUT;
- JUMP;
+ if (IS_NOTEOL(msa->options)) goto fail;
+ MOP_OUT;
+ JUMP;
#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
- }
+ }
#endif
}
else if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 1)) {
- UChar* ss = s + enclen(encode, s, end);
- if (ON_STR_END(ss)) {
- MOP_OUT;
- JUMP;
- }
+ UChar* ss = s + enclen(encode, s, end);
+ if (ON_STR_END(ss)) {
+ MOP_OUT;
+ JUMP;
+ }
#ifdef USE_CRNL_AS_LINE_TERMINATOR
- else if (IS_NEWLINE_CRLF(option)
- && ONIGENC_IS_MBC_CRNL(encode, s, end)) {
- ss += enclen(encode, ss, end);
- if (ON_STR_END(ss)) {
- MOP_OUT;
- JUMP;
- }
- }
+ else if (IS_NEWLINE_CRLF(option)
+ && ONIGENC_IS_MBC_CRNL(encode, s, end)) {
+ ss += enclen(encode, ss, end);
+ if (ON_STR_END(ss)) {
+ MOP_OUT;
+ JUMP;
+ }
+ }
#endif
}
goto fail;
- NEXT;
CASE(OP_BEGIN_POSITION) MOP_IN(OP_BEGIN_POSITION);
if (s != msa->gpos)
- goto fail;
+ goto fail;
MOP_OUT;
JUMP;
@@ -3460,9 +3479,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_GET_MEM_START(mem, stkp);
if (BIT_STATUS_AT(reg->bt_mem_start, mem))
- mem_start_stk[mem] = GET_STACK_INDEX(stkp);
+ mem_start_stk[mem] = GET_STACK_INDEX(stkp);
else
- mem_start_stk[mem] = (OnigStackIndex )((void* )stkp->u.mem.pstr);
+ mem_start_stk[mem] = (OnigStackIndex )((void* )stkp->u.mem.pstr);
STACK_PUSH_MEM_END_MARK(mem);
MOP_OUT;
@@ -3472,178 +3491,176 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_BACKREF1) MOP_IN(OP_BACKREF1);
mem = 1;
goto backref;
- NEXT;
CASE(OP_BACKREF2) MOP_IN(OP_BACKREF2);
mem = 2;
goto backref;
- NEXT;
CASE(OP_BACKREFN) MOP_IN(OP_BACKREFN);
GET_MEMNUM_INC(mem, p);
backref:
{
- int len;
- UChar *pstart, *pend;
-
- /* if you want to remove following line,
- you should check in parse and compile time. */
- if (mem > num_mem) goto fail;
- if (mem_end_stk[mem] == INVALID_STACK_INDEX) goto fail;
- if (mem_start_stk[mem] == INVALID_STACK_INDEX) goto fail;
-
- if (BIT_STATUS_AT(reg->bt_mem_start, mem))
- pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
- else
- pstart = (UChar* )((void* )mem_start_stk[mem]);
-
- pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
- ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
- : (UChar* )((void* )mem_end_stk[mem]));
- n = pend - pstart;
- DATA_ENSURE(n);
- sprev = s;
- STRING_CMP(pstart, s, n);
- while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
- sprev += len;
-
- MOP_OUT;
- JUMP;
+ int len;
+ UChar *pstart, *pend;
+
+ /* if you want to remove following line,
+ you should check in parse and compile time. */
+ if (mem > num_mem) goto fail;
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) goto fail;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) goto fail;
+
+ if (BIT_STATUS_AT(reg->bt_mem_start, mem))
+ pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
+ else
+ pstart = (UChar* )((void* )mem_start_stk[mem]);
+
+ pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
+ ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
+ : (UChar* )((void* )mem_end_stk[mem]));
+ n = pend - pstart;
+ DATA_ENSURE(n);
+ sprev = s;
+ STRING_CMP(pstart, s, n);
+ while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
+ sprev += len;
+
+ MOP_OUT;
+ JUMP;
}
CASE(OP_BACKREFN_IC) MOP_IN(OP_BACKREFN_IC);
GET_MEMNUM_INC(mem, p);
{
- int len;
- UChar *pstart, *pend;
-
- /* if you want to remove following line,
- you should check in parse and compile time. */
- if (mem > num_mem) goto fail;
- if (mem_end_stk[mem] == INVALID_STACK_INDEX) goto fail;
- if (mem_start_stk[mem] == INVALID_STACK_INDEX) goto fail;
-
- if (BIT_STATUS_AT(reg->bt_mem_start, mem))
- pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
- else
- pstart = (UChar* )((void* )mem_start_stk[mem]);
-
- pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
- ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
- : (UChar* )((void* )mem_end_stk[mem]));
- 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)
- sprev += len;
-
- MOP_OUT;
- JUMP;
+ int len;
+ UChar *pstart, *pend;
+
+ /* if you want to remove following line,
+ you should check in parse and compile time. */
+ if (mem > num_mem) goto fail;
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) goto fail;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) goto fail;
+
+ if (BIT_STATUS_AT(reg->bt_mem_start, mem))
+ pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
+ else
+ pstart = (UChar* )((void* )mem_start_stk[mem]);
+
+ pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
+ ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
+ : (UChar* )((void* )mem_end_stk[mem]));
+ 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)
+ sprev += len;
+
+ MOP_OUT;
+ JUMP;
}
NEXT;
CASE(OP_BACKREF_MULTI) MOP_IN(OP_BACKREF_MULTI);
{
- int len, is_fail;
- UChar *pstart, *pend, *swork;
-
- GET_LENGTH_INC(tlen, p);
- for (i = 0; i < tlen; i++) {
- GET_MEMNUM_INC(mem, p);
-
- if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
- if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
-
- if (BIT_STATUS_AT(reg->bt_mem_start, mem))
- pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
- else
- pstart = (UChar* )((void* )mem_start_stk[mem]);
-
- pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
- ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
- : (UChar* )((void* )mem_end_stk[mem]));
- n = pend - pstart;
- DATA_ENSURE_CONTINUE(n);
- sprev = s;
- swork = s;
- STRING_CMP_VALUE(pstart, swork, n, is_fail);
- if (is_fail) continue;
- s = swork;
- while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
- sprev += len;
-
- p += (SIZE_MEMNUM * (tlen - i - 1));
- break; /* success */
- }
- if (i == tlen) goto fail;
- MOP_OUT;
- JUMP;
+ int len, is_fail;
+ UChar *pstart, *pend, *swork;
+
+ GET_LENGTH_INC(tlen, p);
+ for (i = 0; i < tlen; i++) {
+ GET_MEMNUM_INC(mem, p);
+
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
+
+ if (BIT_STATUS_AT(reg->bt_mem_start, mem))
+ pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
+ else
+ pstart = (UChar* )((void* )mem_start_stk[mem]);
+
+ pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
+ ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
+ : (UChar* )((void* )mem_end_stk[mem]));
+ n = pend - pstart;
+ DATA_ENSURE_CONTINUE(n);
+ sprev = s;
+ swork = s;
+ STRING_CMP_VALUE(pstart, swork, n, is_fail);
+ if (is_fail) continue;
+ s = swork;
+ while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
+ sprev += len;
+
+ p += (SIZE_MEMNUM * (tlen - i - 1));
+ break; /* success */
+ }
+ if (i == tlen) goto fail;
+ MOP_OUT;
+ JUMP;
}
NEXT;
CASE(OP_BACKREF_MULTI_IC) MOP_IN(OP_BACKREF_MULTI_IC);
{
- int len, is_fail;
- UChar *pstart, *pend, *swork;
-
- GET_LENGTH_INC(tlen, p);
- for (i = 0; i < tlen; i++) {
- GET_MEMNUM_INC(mem, p);
-
- if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
- if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
-
- if (BIT_STATUS_AT(reg->bt_mem_start, mem))
- pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
- else
- pstart = (UChar* )((void* )mem_start_stk[mem]);
-
- pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
- ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
- : (UChar* )((void* )mem_end_stk[mem]));
- n = pend - pstart;
- DATA_ENSURE_CONTINUE(n);
- sprev = s;
- swork = s;
- STRING_CMP_VALUE_IC(case_fold_flag, pstart, &swork, n, end, is_fail);
- if (is_fail) continue;
- s = swork;
- while (sprev + (len = enclen(encode, sprev, end)) < s)
- sprev += len;
-
- p += (SIZE_MEMNUM * (tlen - i - 1));
- break; /* success */
- }
- if (i == tlen) goto fail;
- MOP_OUT;
- JUMP;
+ int len, is_fail;
+ UChar *pstart, *pend, *swork;
+
+ GET_LENGTH_INC(tlen, p);
+ for (i = 0; i < tlen; i++) {
+ GET_MEMNUM_INC(mem, p);
+
+ if (mem_end_stk[mem] == INVALID_STACK_INDEX) continue;
+ if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
+
+ if (BIT_STATUS_AT(reg->bt_mem_start, mem))
+ pstart = STACK_AT(mem_start_stk[mem])->u.mem.pstr;
+ else
+ pstart = (UChar* )((void* )mem_start_stk[mem]);
+
+ pend = (BIT_STATUS_AT(reg->bt_mem_end, mem)
+ ? STACK_AT(mem_end_stk[mem])->u.mem.pstr
+ : (UChar* )((void* )mem_end_stk[mem]));
+ n = pend - pstart;
+ DATA_ENSURE_CONTINUE(n);
+ sprev = s;
+ swork = s;
+ STRING_CMP_VALUE_IC(case_fold_flag, pstart, &swork, n, end, is_fail);
+ if (is_fail) continue;
+ s = swork;
+ while (sprev + (len = enclen(encode, sprev, end)) < s)
+ sprev += len;
+
+ p += (SIZE_MEMNUM * (tlen - i - 1));
+ break; /* success */
+ }
+ if (i == tlen) goto fail;
+ MOP_OUT;
+ JUMP;
}
#ifdef USE_BACKREF_WITH_LEVEL
CASE(OP_BACKREF_WITH_LEVEL)
{
- int len;
- OnigOptionType ic;
- LengthType level;
+ int len;
+ OnigOptionType ic;
+ LengthType level;
- GET_OPTION_INC(ic, p);
- GET_LENGTH_INC(level, p);
- GET_LENGTH_INC(tlen, p);
+ GET_OPTION_INC(ic, p);
+ GET_LENGTH_INC(level, p);
+ GET_LENGTH_INC(tlen, p);
- sprev = s;
- if (backref_match_at_nested_level(reg, stk, stk_base, ic,
- case_fold_flag, (int )level, (int )tlen, p, &s, end)) {
- while (sprev + (len = enclen(encode, sprev, end)) < s)
- sprev += len;
+ sprev = s;
+ if (backref_match_at_nested_level(reg, stk, stk_base, ic,
+ case_fold_flag, (int )level, (int )tlen, p, &s, end)) {
+ while (sprev + (len = enclen(encode, sprev, end)) < s)
+ sprev += len;
- p += (SIZE_MEMNUM * tlen);
- }
- else
- goto fail;
+ p += (SIZE_MEMNUM * tlen);
+ }
+ else
+ goto fail;
- MOP_OUT;
- JUMP;
+ MOP_OUT;
+ JUMP;
}
#endif
@@ -3670,33 +3687,33 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_NULL_CHECK_END) MOP_IN(OP_NULL_CHECK_END);
{
- int isnull;
+ int isnull;
- GET_MEMNUM_INC(mem, p); /* mem: null check id */
- STACK_NULL_CHECK(isnull, mem, s);
- if (isnull) {
+ GET_MEMNUM_INC(mem, p); /* mem: null check id */
+ STACK_NULL_CHECK(isnull, mem, s);
+ if (isnull) {
#ifdef ONIG_DEBUG_MATCH
- fprintf(stderr, "NULL_CHECK_END: skip id:%d, s:%"PRIuPTR" (%p)\n",
- (int )mem, (uintptr_t )s, s);
+ fprintf(stderr, "NULL_CHECK_END: skip id:%d, s:%"PRIuPTR" (%p)\n",
+ (int )mem, (uintptr_t )s, s);
#endif
- null_check_found:
- /* empty loop founded, skip next instruction */
- switch (*p++) {
- case OP_JUMP:
- case OP_PUSH:
- p += SIZE_RELADDR;
- break;
- case OP_REPEAT_INC:
- case OP_REPEAT_INC_NG:
- case OP_REPEAT_INC_SG:
- case OP_REPEAT_INC_NG_SG:
- p += SIZE_MEMNUM;
- break;
- default:
- goto unexpected_bytecode_error;
- break;
- }
- }
+ null_check_found:
+ /* empty loop founded, skip next instruction */
+ switch (*p++) {
+ case OP_JUMP:
+ case OP_PUSH:
+ p += SIZE_RELADDR;
+ break;
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ case OP_REPEAT_INC_SG:
+ case OP_REPEAT_INC_NG_SG:
+ p += SIZE_MEMNUM;
+ break;
+ default:
+ goto unexpected_bytecode_error;
+ break;
+ }
+ }
}
MOP_OUT;
JUMP;
@@ -3704,18 +3721,18 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
#ifdef USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT
CASE(OP_NULL_CHECK_END_MEMST) MOP_IN(OP_NULL_CHECK_END_MEMST);
{
- int isnull;
+ int isnull;
- GET_MEMNUM_INC(mem, p); /* mem: null check id */
- STACK_NULL_CHECK_MEMST(isnull, mem, s, reg);
- if (isnull) {
+ GET_MEMNUM_INC(mem, p); /* mem: null check id */
+ STACK_NULL_CHECK_MEMST(isnull, mem, s, reg);
+ if (isnull) {
# ifdef ONIG_DEBUG_MATCH
- fprintf(stderr, "NULL_CHECK_END_MEMST: skip id:%d, s:%"PRIuPTR" (%p)\n",
- (int )mem, (uintptr_t )s, s);
+ fprintf(stderr, "NULL_CHECK_END_MEMST: skip id:%d, s:%"PRIuPTR" (%p)\n",
+ (int )mem, (uintptr_t )s, s);
# endif
- if (isnull == -1) goto fail;
- goto null_check_found;
- }
+ if (isnull == -1) goto fail;
+ goto null_check_found;
+ }
}
MOP_OUT;
JUMP;
@@ -3725,25 +3742,25 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_NULL_CHECK_END_MEMST_PUSH)
MOP_IN(OP_NULL_CHECK_END_MEMST_PUSH);
{
- int isnull;
+ int isnull;
- GET_MEMNUM_INC(mem, p); /* mem: null check id */
+ GET_MEMNUM_INC(mem, p); /* mem: null check id */
# ifdef USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT
- STACK_NULL_CHECK_MEMST_REC(isnull, mem, s, reg);
+ STACK_NULL_CHECK_MEMST_REC(isnull, mem, s, reg);
# else
- STACK_NULL_CHECK_REC(isnull, mem, s);
+ STACK_NULL_CHECK_REC(isnull, mem, s);
# endif
- if (isnull) {
+ if (isnull) {
# ifdef ONIG_DEBUG_MATCH
- fprintf(stderr, "NULL_CHECK_END_MEMST_PUSH: skip id:%d, s:%"PRIuPTR" (%p)\n",
- (int )mem, (uintptr_t )s, s);
+ fprintf(stderr, "NULL_CHECK_END_MEMST_PUSH: skip id:%d, s:%"PRIuPTR" (%p)\n",
+ (int )mem, (uintptr_t )s, s);
# endif
- if (isnull == -1) goto fail;
- goto null_check_found;
- }
- else {
- STACK_PUSH_NULL_CHECK_END(mem);
- }
+ if (isnull == -1) goto fail;
+ goto null_check_found;
+ }
+ else {
+ STACK_PUSH_NULL_CHECK_END(mem);
+ }
}
MOP_OUT;
JUMP;
@@ -3779,10 +3796,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_RELADDR_INC(addr, p);
STATE_CHECK_VAL(scv, mem);
if (scv) {
- p += addr;
+ p += addr;
}
else {
- STACK_PUSH_ALT_WITH_STATE_CHECK(p + addr, s, sprev, mem, pkeep);
+ STACK_PUSH_ALT_WITH_STATE_CHECK(p + addr, s, sprev, mem, pkeep);
}
MOP_OUT;
JUMP;
@@ -3811,11 +3828,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_PUSH_OR_JUMP_EXACT1) MOP_IN(OP_PUSH_OR_JUMP_EXACT1);
GET_RELADDR_INC(addr, p);
if (*p == *s && DATA_ENSURE_CHECK1) {
- p++;
- CHECK_MATCH_CACHE;
- STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
- MOP_OUT;
- JUMP;
+ p++;
+ CHECK_MATCH_CACHE;
+ STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
+ MOP_OUT;
+ JUMP;
}
p += (addr + 1);
MOP_OUT;
@@ -3826,10 +3843,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_RELADDR_INC(addr, p);
CHECK_MATCH_CACHE;
if (*p == *s) {
- p++;
- STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
- MOP_OUT;
- JUMP;
+ p++;
+ STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
+ MOP_OUT;
+ JUMP;
}
p++;
INC_NUM_FAILS;
@@ -3838,35 +3855,35 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_REPEAT) MOP_IN(OP_REPEAT);
{
- GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
- GET_RELADDR_INC(addr, p);
+ GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
+ GET_RELADDR_INC(addr, p);
- STACK_ENSURE(1);
- repeat_stk[mem] = GET_STACK_INDEX(stk);
- STACK_PUSH_REPEAT(mem, p);
+ STACK_ENSURE(1);
+ repeat_stk[mem] = GET_STACK_INDEX(stk);
+ STACK_PUSH_REPEAT(mem, p);
- if (reg->repeat_range[mem].lower == 0) {
- CHECK_MATCH_CACHE;
- STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
- }
+ if (reg->repeat_range[mem].lower == 0) {
+ CHECK_MATCH_CACHE;
+ STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
+ }
}
MOP_OUT;
JUMP;
CASE(OP_REPEAT_NG) MOP_IN(OP_REPEAT_NG);
{
- GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
- GET_RELADDR_INC(addr, p);
+ GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
+ GET_RELADDR_INC(addr, p);
- STACK_ENSURE(1);
- repeat_stk[mem] = GET_STACK_INDEX(stk);
- STACK_PUSH_REPEAT(mem, p);
+ STACK_ENSURE(1);
+ repeat_stk[mem] = GET_STACK_INDEX(stk);
+ STACK_PUSH_REPEAT(mem, p);
- if (reg->repeat_range[mem].lower == 0) {
- CHECK_MATCH_CACHE;
- STACK_PUSH_ALT(p, s, sprev, pkeep);
- p += addr;
- }
+ if (reg->repeat_range[mem].lower == 0) {
+ CHECK_MATCH_CACHE;
+ STACK_PUSH_ALT(p, s, sprev, pkeep);
+ p += addr;
+ }
}
MOP_OUT;
JUMP;
@@ -3879,23 +3896,23 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
repeat_inc:
stkp->u.repeat.count++;
if (stkp->u.repeat.count >= reg->repeat_range[mem].upper) {
- /* end of repeat. Nothing to do. */
+ /* 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) {
+ if (*pbegin == OP_REPEAT_INC) {
#undef MATCH_CACHE_HIT
#define MATCH_CACHE_HIT stkp->u.repeat.count--;
- CHECK_MATCH_CACHE;
+ CHECK_MATCH_CACHE;
#undef MATCH_CACHE_HIT
#define MATCH_CACHE_HIT ((void) 0)
- }
+ }
#endif
- STACK_PUSH_ALT(p, s, sprev, pkeep);
- p = STACK_AT(si)->u.repeat.pcode; /* Don't use stkp after PUSH. */
+ STACK_PUSH_ALT(p, s, sprev, pkeep);
+ p = STACK_AT(si)->u.repeat.pcode; /* Don't use stkp after PUSH. */
}
else {
- p = stkp->u.repeat.pcode;
+ p = stkp->u.repeat.pcode;
}
STACK_PUSH_REPEAT_INC(si);
MOP_OUT;
@@ -3907,7 +3924,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_GET_REPEAT(mem, stkp);
si = GET_STACK_INDEX(stkp);
goto repeat_inc;
- NEXT;
CASE(OP_REPEAT_INC_NG) MOP_IN(OP_REPEAT_INC_NG);
GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
@@ -3917,22 +3933,22 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
repeat_inc_ng:
stkp->u.repeat.count++;
if (stkp->u.repeat.count < reg->repeat_range[mem].upper) {
- if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
- UChar* pcode = stkp->u.repeat.pcode;
-
- STACK_PUSH_REPEAT_INC(si);
- if (*pbegin == OP_REPEAT_INC_NG) {
- CHECK_MATCH_CACHE;
- }
- STACK_PUSH_ALT(pcode, s, sprev, pkeep);
- }
- else {
- p = stkp->u.repeat.pcode;
- STACK_PUSH_REPEAT_INC(si);
- }
+ if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
+ UChar* pcode = stkp->u.repeat.pcode;
+
+ STACK_PUSH_REPEAT_INC(si);
+ if (*pbegin == OP_REPEAT_INC_NG) {
+ CHECK_MATCH_CACHE;
+ }
+ STACK_PUSH_ALT(pcode, s, sprev, pkeep);
+ }
+ else {
+ p = stkp->u.repeat.pcode;
+ STACK_PUSH_REPEAT_INC(si);
+ }
}
else if (stkp->u.repeat.count == reg->repeat_range[mem].upper) {
- STACK_PUSH_REPEAT_INC(si);
+ STACK_PUSH_REPEAT_INC(si);
}
MOP_OUT;
CHECK_INTERRUPT_IN_MATCH_AT;
@@ -3943,7 +3959,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_GET_REPEAT(mem, stkp);
si = GET_STACK_INDEX(stkp);
goto repeat_inc_ng;
- NEXT;
CASE(OP_PUSH_POS) MOP_IN(OP_PUSH_POS);
STACK_PUSH_POS(s, sprev, pkeep);
@@ -3952,9 +3967,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_POP_POS) MOP_IN(OP_POP_POS);
{
- STACK_POS_END(stkp);
- s = stkp->u.state.pstr;
- sprev = stkp->u.state.pstr_prev;
+ STACK_POS_END(stkp);
+ s = stkp->u.state.pstr;
+ sprev = stkp->u.state.pstr_prev;
}
MOP_OUT;
JUMP;
@@ -3968,7 +3983,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_FAIL_POS) MOP_IN(OP_FAIL_POS);
STACK_POP_TIL_POS_NOT;
goto fail;
- NEXT;
CASE(OP_PUSH_STOP_BT) MOP_IN(OP_PUSH_STOP_BT);
STACK_PUSH_STOP_BT;
@@ -3993,15 +4007,15 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_LENGTH_INC(tlen, p);
q = (UChar* )ONIGENC_STEP_BACK(encode, str, s, end, (int )tlen);
if (IS_NULL(q)) {
- /* too short case -> success. ex. /(?<!XXX)a/.match("a")
- If you want to change to fail, replace following line. */
- p += addr;
- /* goto fail; */
+ /* too short case -> success. ex. /(?<!XXX)a/.match("a")
+ If you want to change to fail, replace following line. */
+ p += addr;
+ /* goto fail; */
}
else {
- STACK_PUSH_LOOK_BEHIND_NOT(p + addr, s, sprev, pkeep);
- s = q;
- sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s, end);
+ STACK_PUSH_LOOK_BEHIND_NOT(p + addr, s, sprev, pkeep);
+ s = q;
+ sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s, end);
}
MOP_OUT;
JUMP;
@@ -4009,7 +4023,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_FAIL_LOOK_BEHIND_NOT) MOP_IN(OP_FAIL_LOOK_BEHIND_NOT);
STACK_POP_TIL_LOOK_BEHIND_NOT;
goto fail;
- NEXT;
CASE(OP_PUSH_ABSENT_POS) MOP_IN(OP_PUSH_ABSENT_POS);
/* Save the absent-start-pos and the original end-pos. */
@@ -4019,44 +4032,44 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ABSENT) MOP_IN(OP_ABSENT);
{
- const UChar* aend = ABSENT_END_POS;
- UChar* absent;
- UChar* selfp = p - 1;
+ const UChar* aend = ABSENT_END_POS;
+ UChar* absent;
+ UChar* selfp = p - 1;
- STACK_POP_ABSENT_POS(absent, ABSENT_END_POS); /* Restore end-pos. */
- GET_RELADDR_INC(addr, p);
+ STACK_POP_ABSENT_POS(absent, ABSENT_END_POS); /* Restore end-pos. */
+ GET_RELADDR_INC(addr, p);
#ifdef ONIG_DEBUG_MATCH
- fprintf(stderr, "ABSENT: s:%p, end:%p, absent:%p, aend:%p\n", s, end, absent, aend);
+ fprintf(stderr, "ABSENT: s:%p, end:%p, absent:%p, aend:%p\n", s, end, absent, aend);
#endif
- if ((absent > aend) && (s > absent)) {
- /* An empty match occurred in (?~...) at the start point.
- * Never match. */
- STACK_POP;
- goto fail;
- }
- else if ((s >= aend) && (s > absent)) {
- if (s > aend) {
- /* Only one (or less) character matched in the last iteration.
- * This is not a possible point. */
- goto fail;
- }
- /* All possible points were found. Try matching after (?~...). */
- DATA_ENSURE(0);
- p += addr;
- }
- else if (s == end) {
- /* At the end of the string, just match with it */
- DATA_ENSURE(0);
- p += addr;
- }
- else {
- STACK_PUSH_ALT(p + addr, s, sprev, pkeep); /* Push possible point. */
- n = enclen(encode, s, end);
- STACK_PUSH_ABSENT_POS(absent, ABSENT_END_POS); /* Save the original pos. */
- STACK_PUSH_ALT(selfp, s + n, s, pkeep); /* Next iteration. */
- STACK_PUSH_ABSENT;
- ABSENT_END_POS = aend;
- }
+ if ((absent > aend) && (s > absent)) {
+ /* An empty match occurred in (?~...) at the start point.
+ * Never match. */
+ STACK_POP;
+ goto fail;
+ }
+ else if ((s >= aend) && (s > absent)) {
+ if (s > aend) {
+ /* Only one (or less) character matched in the last iteration.
+ * This is not a possible point. */
+ goto fail;
+ }
+ /* All possible points were found. Try matching after (?~...). */
+ DATA_ENSURE(0);
+ p += addr;
+ }
+ else if (s == end) {
+ /* At the end of the string, just match with it */
+ DATA_ENSURE(0);
+ p += addr;
+ }
+ else {
+ STACK_PUSH_ALT(p + addr, s, sprev, pkeep); /* Push possible point. */
+ n = enclen(encode, s, end);
+ STACK_PUSH_ABSENT_POS(absent, ABSENT_END_POS); /* Save the original pos. */
+ STACK_PUSH_ALT(selfp, s + n, s, pkeep); /* Next iteration. */
+ STACK_PUSH_ABSENT;
+ ABSENT_END_POS = aend;
+ }
}
MOP_OUT;
JUMP;
@@ -4065,13 +4078,12 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
/* The pattern inside (?~...) was matched.
* Set the end-pos temporary and go to next iteration. */
if (sprev < ABSENT_END_POS)
- ABSENT_END_POS = sprev;
+ ABSENT_END_POS = sprev;
#ifdef ONIG_DEBUG_MATCH
fprintf(stderr, "ABSENT_END: end:%p\n", ABSENT_END_POS);
#endif
STACK_POP_TIL_ABSENT;
goto fail;
- NEXT;
#ifdef USE_SUBEXP_CALL
CASE(OP_CALL) MOP_IN(OP_CALL);
@@ -4092,22 +4104,21 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_MEMNUM_INC(mem, p);
GET_RELADDR_INC(addr, p);
if ((mem > num_mem) ||
- (mem_end_stk[mem] == INVALID_STACK_INDEX) ||
- (mem_start_stk[mem] == INVALID_STACK_INDEX)) {
- p += addr;
+ (mem_end_stk[mem] == INVALID_STACK_INDEX) ||
+ (mem_start_stk[mem] == INVALID_STACK_INDEX)) {
+ p += addr;
}
MOP_OUT;
JUMP;
CASE(OP_FINISH)
goto finish;
- NEXT;
CASE(OP_FAIL)
if (0) {
- /* fall */
+ /* fall */
fail:
- MOP_OUT;
+ MOP_OUT;
}
MOP_IN(OP_FAIL);
STACK_POP;
@@ -4118,71 +4129,71 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
#ifdef USE_MATCH_CACHE
if (
- msa->match_cache_status != MATCH_CACHE_STATUS_DISABLED &&
- ++msa->num_fails >= (long)(end - str) * msa->num_cache_opcodes
+ 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;
- }
- if (msa->num_fails < (long)(end - str) * msa->num_cache_opcodes) {
- goto fail_match_cache;
- }
- 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) {
- 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;
+ 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;
+ }
+ if (msa->num_fails < (long)(end - str) * msa->num_cache_opcodes) {
+ goto fail_match_cache;
+ }
+ 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) {
+ 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);
- }
+ 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
- }
- 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;
+ }
+ 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 = %zu (length = %zu)\n", num_match_cache_points, length);
+ fprintf(stderr, "MATCH CACHE: #match cache points = %zu (length = %zu)\n", num_match_cache_points, length);
#endif
- /* Overflow check */
- if (num_match_cache_points / length != (size_t)msa->num_cache_points) {
- return ONIGERR_MEMORY;
- }
- if (num_match_cache_points >= LONG_MAX_LIMIT) {
- return ONIGERR_MEMORY;
- }
- size_t match_cache_buf_length = (num_match_cache_points >> 3) + (num_match_cache_points & 7 ? 1 : 0) + 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;
- }
+ /* 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;
+ }
}
fail_match_cache:
#endif
#ifdef USE_COMBINATION_EXPLOSION_CHECK
if (stk->u.state.state_check != 0) {
- stk->type = STK_STATE_CHECK_MARK;
- stk++;
+ stk->type = STK_STATE_CHECK_MARK;
+ stk++;
}
#endif
@@ -4225,7 +4236,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
static UChar*
slow_search(OnigEncoding enc, UChar* target, UChar* target_end,
- const UChar* text, const UChar* text_end, UChar* text_range)
+ const UChar* text, const UChar* text_end, UChar* text_range)
{
UChar *t, *p, *s, *end;
@@ -4241,10 +4252,10 @@ slow_search(OnigEncoding enc, UChar* target, UChar* target_end,
while (s < end) {
if (*s == *target) {
- p = s + 1;
- t = target + 1;
- if (target_end == t || memcmp(t, p, target_end - t) == 0)
- return s;
+ p = s + 1;
+ t = target + 1;
+ if (target_end == t || memcmp(t, p, target_end - t) == 0)
+ return s;
}
s += n;
}
@@ -4255,7 +4266,7 @@ slow_search(OnigEncoding enc, UChar* target, UChar* target_end,
p = s + 1;
t = target + 1;
if (target_end == t || memcmp(t, p, target_end - t) == 0)
- return s;
+ return s;
}
s += enclen(enc, s, text_end);
}
@@ -4265,8 +4276,8 @@ slow_search(OnigEncoding enc, UChar* target, UChar* target_end,
static int
str_lower_case_match(OnigEncoding enc, int case_fold_flag,
- const UChar* t, const UChar* tend,
- const UChar* p, const UChar* end)
+ const UChar* t, const UChar* tend,
+ const UChar* p, const UChar* end)
{
int lowlen;
UChar *q, lowbuf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
@@ -4285,8 +4296,8 @@ str_lower_case_match(OnigEncoding enc, int case_fold_flag,
static UChar*
slow_search_ic(OnigEncoding enc, int case_fold_flag,
- UChar* target, UChar* target_end,
- const UChar* text, const UChar* text_end, UChar* text_range)
+ UChar* target, UChar* target_end,
+ const UChar* text, const UChar* text_end, UChar* text_range)
{
UChar *s, *end;
@@ -4299,7 +4310,7 @@ slow_search_ic(OnigEncoding enc, int case_fold_flag,
while (s < end) {
if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, text_end))
+ s, text_end))
return s;
s += enclen(enc, s, text_end);
@@ -4310,8 +4321,8 @@ slow_search_ic(OnigEncoding enc, int case_fold_flag,
static UChar*
slow_search_backward(OnigEncoding enc, UChar* target, UChar* target_end,
- const UChar* text, const UChar* adjust_text,
- const UChar* text_end, const UChar* text_start)
+ const UChar* text, const UChar* adjust_text,
+ const UChar* text_end, const UChar* text_start)
{
UChar *t, *p, *s;
@@ -4327,12 +4338,12 @@ slow_search_backward(OnigEncoding enc, UChar* target, UChar* target_end,
p = s + 1;
t = target + 1;
while (t < target_end) {
- if (*t != *p++)
- break;
- t++;
+ if (*t != *p++)
+ break;
+ t++;
}
if (t == target_end)
- return s;
+ return s;
}
s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s, text_end);
}
@@ -4342,9 +4353,9 @@ slow_search_backward(OnigEncoding enc, UChar* target, UChar* target_end,
static UChar*
slow_search_backward_ic(OnigEncoding enc, int case_fold_flag,
- UChar* target, UChar* target_end,
- const UChar* text, const UChar* adjust_text,
- const UChar* text_end, const UChar* text_start)
+ UChar* target, UChar* target_end,
+ const UChar* text, const UChar* adjust_text,
+ const UChar* text_end, const UChar* text_start)
{
UChar *s;
@@ -4357,7 +4368,7 @@ slow_search_backward_ic(OnigEncoding enc, int case_fold_flag,
while (s >= text) {
if (str_lower_case_match(enc, case_fold_flag,
- target, target_end, s, text_end))
+ target, target_end, s, text_end))
return s;
s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s, text_end);
@@ -4366,224 +4377,11 @@ slow_search_backward_ic(OnigEncoding enc, int case_fold_flag,
return (UChar* )NULL;
}
-#ifndef USE_SUNDAY_QUICK_SEARCH
-/* Boyer-Moore-Horspool search applied to a multibyte string */
-static UChar*
-bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end,
- const UChar* text_range)
-{
- const UChar *s, *se, *t, *p, *end;
- const UChar *tail;
- ptrdiff_t skip, tlen1;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_notrev: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
-# endif
-
- tail = target_end - 1;
- tlen1 = tail - target;
- end = text_range;
- if (end + tlen1 > text_end)
- end = text_end - tlen1;
-
- s = text;
-
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- skip = reg->map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- skip = reg->int_map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
-# endif
- }
-
- return (UChar* )NULL;
-}
-
-/* Boyer-Moore-Horspool search */
-static UChar*
-bm_search(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end, const UChar* text_range)
-{
- const UChar *s, *t, *p, *end;
- const UChar *tail;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
-# endif
-
- end = text_range + (target_end - target) - 1;
- if (end > text_end)
- end = text_end;
-
- tail = target_end - 1;
- s = text + (target_end - target) - 1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s;
- t = tail;
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_loop: pos: %"PRIdPTR" %s\n",
- (intptr_t )(s - text), s);
-# endif
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- s += reg->map[*s];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- s += reg->int_map[*s];
- }
-# endif
- }
- return (UChar* )NULL;
-}
-
-/* Boyer-Moore-Horspool search applied to a multibyte string (ignore case) */
-static UChar*
-bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end,
- const UChar* text_range)
-{
- const UChar *s, *se, *t, *end;
- const UChar *tail;
- ptrdiff_t skip, tlen1;
- OnigEncoding enc = reg->enc;
- int case_fold_flag = reg->case_fold_flag;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_notrev_ic: text: %d (%p), text_end: %d (%p), text_range: %d (%p)\n",
- (int )text, text, (int )text_end, text_end, (int )text_range, text_range);
-# endif
-
- tail = target_end - 1;
- tlen1 = tail - target;
- end = text_range;
- if (end + tlen1 > text_end)
- end = text_end - tlen1;
-
- s = text;
-
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- skip = reg->map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- skip = reg->int_map[*se];
- t = s;
- do {
- s += enclen(reg->enc, s, end);
- } while ((s - t) < skip && s < end);
- }
-# endif
- }
-
- return (UChar* )NULL;
-}
-
-/* Boyer-Moore-Horspool search (ignore case) */
-static UChar*
-bm_search_ic(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end, const UChar* text_range)
-{
- const UChar *s, *p, *end;
- const UChar *tail;
- OnigEncoding enc = reg->enc;
- int case_fold_flag = reg->case_fold_flag;
-
-# ifdef ONIG_DEBUG_SEARCH
- fprintf(stderr, "bm_search_ic: text: %d (%p), text_end: %d (%p), text_range: %d (%p)\n",
- (int )text, text, (int )text_end, text_end, (int )text_range, text_range);
-# endif
-
- end = text_range + (target_end - target) - 1;
- if (end > text_end)
- end = text_end;
-
- tail = target_end - 1;
- s = text + (target_end - target) - 1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s - (target_end - target) + 1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- s += reg->map[*s];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s - (target_end - target) + 1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- s += reg->int_map[*s];
- }
-# endif
- }
- return (UChar* )NULL;
-}
-
-#else /* USE_SUNDAY_QUICK_SEARCH */
-
/* Sunday's quick search applied to a multibyte string */
static UChar*
bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end,
- const UChar* text_range)
+ const UChar* text, const UChar* text_end,
+ const UChar* text_range)
{
const UChar *s, *se, *t, *p, *end;
const UChar *tail;
@@ -4592,7 +4390,7 @@ bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
# ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "bm_search_notrev: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
+ (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
# endif
tail = target_end - 1;
@@ -4603,39 +4401,19 @@ bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
s = text;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- if (s + 1 >= end) break;
- skip = reg->map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = se = s + tlen1;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )s;
- p--; t--;
- }
- if (s + 1 >= end) break;
- skip = reg->int_map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
+ while (s < end) {
+ p = se = s + tlen1;
+ t = tail;
+ while (*p == *t) {
+ if (t == target) return (UChar* )s;
+ p--; t--;
}
-# endif
+ if (s + 1 >= end) break;
+ skip = reg->map[se[1]];
+ t = s;
+ do {
+ s += enclen(enc, s, end);
+ } while ((s - t) < skip && s < end);
}
return (UChar* )NULL;
@@ -4644,7 +4422,7 @@ bm_search_notrev(regex_t* reg, const UChar* target, const UChar* target_end,
/* Sunday's quick search */
static UChar*
bm_search(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end, const UChar* text_range)
+ const UChar* text, const UChar* text_end, const UChar* text_range)
{
const UChar *s, *t, *p, *end;
const UChar *tail;
@@ -4652,7 +4430,7 @@ bm_search(regex_t* reg, const UChar* target, const UChar* target_end,
# ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "bm_search: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
+ (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
# endif
tail = target_end - 1;
@@ -4662,40 +4440,25 @@ bm_search(regex_t* reg, const UChar* target, const UChar* target_end,
end = text_end;
s = text + tlen1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- if (s + 1 >= end) break;
- s += reg->map[s[1]];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s;
- t = tail;
- while (*p == *t) {
- if (t == target) return (UChar* )p;
- p--; t--;
- }
- if (s + 1 >= end) break;
- s += reg->int_map[s[1]];
+ while (s < end) {
+ p = s;
+ t = tail;
+ while (*p == *t) {
+ if (t == target) return (UChar* )p;
+ p--; t--;
}
-# endif
+ if (s + 1 >= end) break;
+ s += reg->map[s[1]];
}
+
return (UChar* )NULL;
}
/* Sunday's quick search applied to a multibyte string (ignore case) */
static UChar*
bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end,
- const UChar* text_range)
+ const UChar* text, const UChar* text_end,
+ const UChar* text_range)
{
const UChar *s, *se, *t, *end;
const UChar *tail;
@@ -4705,7 +4468,7 @@ bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
# ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "bm_search_notrev_ic: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
+ (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
# endif
tail = target_end - 1;
@@ -4716,35 +4479,17 @@ bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
s = text;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- if (s + 1 >= end) break;
- skip = reg->map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
- }
- }
- else {
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- se = s + tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- s, se + 1))
- return (UChar* )s;
- if (s + 1 >= end) break;
- skip = reg->int_map[se[1]];
- t = s;
- do {
- s += enclen(enc, s, end);
- } while ((s - t) < skip && s < end);
- }
-# endif
+ while (s < end) {
+ se = s + tlen1;
+ if (str_lower_case_match(enc, case_fold_flag, target, target_end,
+ s, se + 1))
+ return (UChar* )s;
+ if (s + 1 >= end) break;
+ skip = reg->map[se[1]];
+ t = s;
+ do {
+ s += enclen(enc, s, end);
+ } while ((s - t) < skip && s < end);
}
return (UChar* )NULL;
@@ -4753,7 +4498,7 @@ bm_search_notrev_ic(regex_t* reg, const UChar* target, const UChar* target_end,
/* Sunday's quick search (ignore case) */
static UChar*
bm_search_ic(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* text_end, const UChar* text_range)
+ const UChar* text, const UChar* text_end, const UChar* text_range)
{
const UChar *s, *p, *end;
const UChar *tail;
@@ -4763,7 +4508,7 @@ bm_search_ic(regex_t* reg, const UChar* target, const UChar* target_end,
# ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "bm_search_ic: text: %"PRIuPTR" (%p), text_end: %"PRIuPTR" (%p), text_range: %"PRIuPTR" (%p)\n",
- (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
+ (uintptr_t )text, text, (uintptr_t )text_end, text_end, (uintptr_t )text_range, text_range);
# endif
tail = target_end - 1;
@@ -4773,87 +4518,21 @@ bm_search_ic(regex_t* reg, const UChar* target, const UChar* target_end,
end = text_end;
s = text + tlen1;
- if (IS_NULL(reg->int_map)) {
- while (s < end) {
- p = s - tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- if (s + 1 >= end) break;
- s += reg->map[s[1]];
- }
- }
- else { /* see int_map[] */
-# if OPT_EXACT_MAXLEN >= ONIG_CHAR_TABLE_SIZE
- while (s < end) {
- p = s - tlen1;
- if (str_lower_case_match(enc, case_fold_flag, target, target_end,
- p, s + 1))
- return (UChar* )p;
- if (s + 1 >= end) break;
- s += reg->int_map[s[1]];
- }
-# endif
- }
- return (UChar* )NULL;
-}
-#endif /* USE_SUNDAY_QUICK_SEARCH */
-
-#ifdef USE_INT_MAP_BACKWARD
-static int
-set_bm_backward_skip(UChar* s, UChar* end, OnigEncoding enc ARG_UNUSED,
- int** skip)
-{
- int i, len;
-
- if (IS_NULL(*skip)) {
- *skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE);
- if (IS_NULL(*skip)) return ONIGERR_MEMORY;
- }
-
- len = (int )(end - s);
- for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++)
- (*skip)[i] = len;
-
- for (i = len - 1; i > 0; i--)
- (*skip)[s[i]] = i;
-
- return 0;
-}
-
-static UChar*
-bm_search_backward(regex_t* reg, const UChar* target, const UChar* target_end,
- const UChar* text, const UChar* adjust_text,
- const UChar* text_end, const UChar* text_start)
-{
- const UChar *s, *t, *p;
-
- s = text_end - (target_end - target);
- if (text_start < s)
- s = text_start;
- else
- s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s, text_end);
-
- while (s >= text) {
- p = s;
- t = target;
- while (t < target_end && *p == *t) {
- p++; t++;
- }
- if (t == target_end)
- return (UChar* )s;
-
- s -= reg->int_map_backward[*s];
- s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s, text_end);
+ while (s < end) {
+ p = s - tlen1;
+ if (str_lower_case_match(enc, case_fold_flag, target, target_end,
+ p, s + 1))
+ return (UChar* )p;
+ if (s + 1 >= end) break;
+ s += reg->map[s[1]];
}
return (UChar* )NULL;
}
-#endif
static UChar*
map_search(OnigEncoding enc, UChar map[],
- const UChar* text, const UChar* text_range, const UChar* text_end)
+ const UChar* text, const UChar* text_range, const UChar* text_end)
{
const UChar *s = text;
@@ -4867,8 +4546,8 @@ map_search(OnigEncoding enc, UChar map[],
static UChar*
map_search_backward(OnigEncoding enc, UChar map[],
- const UChar* text, const UChar* adjust_text,
- const UChar* text_start, const UChar* text_end)
+ const UChar* text, const UChar* adjust_text,
+ const UChar* text_start, const UChar* text_end)
{
const UChar *s = text_start;
@@ -4882,7 +4561,7 @@ map_search_backward(OnigEncoding enc, UChar map[],
extern OnigPosition
onig_match(regex_t* reg, const UChar* str, const UChar* end, const UChar* at, OnigRegion* region,
- OnigOptionType option)
+ OnigOptionType option)
{
ptrdiff_t r;
UChar *prev;
@@ -4906,9 +4585,9 @@ onig_match(regex_t* reg, const UChar* str, const UChar* end, const UChar* at, On
prev = (UChar* )onigenc_get_prev_char_head(reg->enc, str, at, end);
r = match_at(reg, str, end,
#ifdef USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE
- end,
+ end,
#endif
- at, prev, &msa);
+ at, prev, &msa);
}
MATCH_ARG_FREE(msa);
@@ -4917,14 +4596,14 @@ onig_match(regex_t* reg, const UChar* str, const UChar* end, const UChar* at, On
static int
forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
- UChar* range, UChar** low, UChar** high, UChar** low_prev)
+ 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);
+ (uintptr_t )str, str, (uintptr_t )end, end, (uintptr_t )s, s, (uintptr_t )range, range);
#endif
if (reg->dmin > input_len) {
@@ -4932,14 +4611,14 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
}
p = s;
- if (reg->dmin > 0) {
+ if (reg->dmin != 0) {
+ if ((OnigDistance)(end - p) <= reg->dmin) return 0; /* fail */
if (ONIGENC_IS_SINGLEBYTE(reg->enc)) {
p += reg->dmin;
}
else {
UChar *q = p + reg->dmin;
- if (q >= end) return 0; /* fail */
while (p < q) p += enclen(reg->enc, p, end);
}
}
@@ -4951,7 +4630,7 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
break;
case ONIG_OPTIMIZE_EXACT_IC:
p = slow_search_ic(reg->enc, reg->case_fold_flag,
- reg->exact, reg->exact_end, p, end, range);
+ reg->exact, reg->exact_end, p, end, range);
break;
case ONIG_OPTIMIZE_EXACT_BM:
@@ -4976,7 +4655,7 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
}
if (p && p < range) {
- if (p - reg->dmin < s) {
+ if ((OnigDistance)(p - s) < reg->dmin) {
retry_gate:
pprev = p;
p += enclen(reg->enc, p, end);
@@ -4988,70 +4667,74 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
switch (reg->sub_anchor) {
case ANCHOR_BEGIN_LINE:
- if (!ON_STR_BEGIN(p)) {
- prev = onigenc_get_prev_char_head(reg->enc,
- (pprev ? pprev : str), p, end);
- if (!ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 0))
- goto retry_gate;
- }
- break;
+ if (!ON_STR_BEGIN(p)) {
+ prev = onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), p, end);
+ if (!ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 0))
+ goto retry_gate;
+ }
+ break;
case ANCHOR_END_LINE:
- if (ON_STR_END(p)) {
+ if (ON_STR_END(p)) {
#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
- prev = (UChar* )onigenc_get_prev_char_head(reg->enc,
- (pprev ? pprev : str), p);
- if (prev && ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 1))
- goto retry_gate;
+ prev = (UChar* )onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), p);
+ if (prev && ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 1))
+ goto retry_gate;
#endif
- }
- else if (! ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, p, str, end, reg->options, 1))
- goto retry_gate;
- break;
+ }
+ else if (! ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, p, str, end, reg->options, 1))
+ goto retry_gate;
+ break;
}
}
if (reg->dmax == 0) {
*low = p;
if (low_prev) {
- if (*low > s)
- *low_prev = onigenc_get_prev_char_head(reg->enc, s, p, end);
- else
- *low_prev = onigenc_get_prev_char_head(reg->enc,
- (pprev ? pprev : str), p, end);
+ if (*low > s)
+ *low_prev = onigenc_get_prev_char_head(reg->enc, s, p, end);
+ else
+ *low_prev = onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), p, end);
}
+ *high = p;
}
else {
if (reg->dmax != ONIG_INFINITE_DISTANCE) {
- if (p < str + reg->dmax) {
- *low = (UChar* )str;
- if (low_prev)
- *low_prev = onigenc_get_prev_char_head(reg->enc, str, *low, end);
- }
- else {
- *low = p - reg->dmax;
- if (*low > s) {
- *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s,
- *low, end, (const UChar** )low_prev);
- if (low_prev && IS_NULL(*low_prev))
- *low_prev = onigenc_get_prev_char_head(reg->enc,
- (pprev ? pprev : s), *low, end);
- }
- else {
- if (low_prev)
- *low_prev = onigenc_get_prev_char_head(reg->enc,
- (pprev ? pprev : str), *low, end);
- }
- }
+ if ((OnigDistance)(p - str) < reg->dmax) {
+ *low = (UChar* )str;
+ if (low_prev)
+ *low_prev = onigenc_get_prev_char_head(reg->enc, str, *low, end);
+ }
+ else {
+ *low = p - reg->dmax;
+ if (*low > s) {
+ *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s,
+ *low, end, (const UChar** )low_prev);
+ if (low_prev && IS_NULL(*low_prev))
+ *low_prev = onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : s), *low, end);
+ }
+ else {
+ if (low_prev)
+ *low_prev = onigenc_get_prev_char_head(reg->enc,
+ (pprev ? pprev : str), *low, end);
+ }
+ }
}
+ /* no needs to adjust *high, *high is used as range check only */
+ if ((OnigDistance)(p - str) < reg->dmin)
+ *high = (UChar* )str;
+ else
+ *high = p - reg->dmin;
}
- /* no needs to adjust *high, *high is used as range check only */
- *high = p - reg->dmin;
#ifdef ONIG_DEBUG_SEARCH
fprintf(stderr,
"forward_search_range success: low: %"PRIdPTR", high: %"PRIdPTR", dmin: %"PRIdPTR", dmax: %"PRIdPTR"\n",
- *low - str, *high - str, reg->dmin, reg->dmax);
+ *low - str, *high - str, reg->dmin, reg->dmax);
#endif
return 1; /* success */
}
@@ -5063,8 +4746,8 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
static int
backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
- UChar* s, const UChar* range, UChar* adjrange,
- UChar** low, UChar** high)
+ UChar* s, const UChar* range, UChar* adjrange,
+ UChar** low, UChar** high)
{
UChar *p;
size_t input_len = end - str;
@@ -5073,7 +4756,6 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
return 0;
}
- range += reg->dmin;
p = s;
retry:
@@ -5081,34 +4763,20 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
case ONIG_OPTIMIZE_EXACT:
exact_method:
p = slow_search_backward(reg->enc, reg->exact, reg->exact_end,
- range, adjrange, end, p);
+ range, adjrange, end, p);
break;
case ONIG_OPTIMIZE_EXACT_IC:
case ONIG_OPTIMIZE_EXACT_BM_IC:
case ONIG_OPTIMIZE_EXACT_BM_NOT_REV_IC:
p = slow_search_backward_ic(reg->enc, reg->case_fold_flag,
- reg->exact, reg->exact_end,
- range, adjrange, end, p);
+ reg->exact, reg->exact_end,
+ range, adjrange, end, p);
break;
case ONIG_OPTIMIZE_EXACT_BM:
case ONIG_OPTIMIZE_EXACT_BM_NOT_REV:
-#ifdef USE_INT_MAP_BACKWARD
- if (IS_NULL(reg->int_map_backward)) {
- int r;
- if (s - range < BM_BACKWARD_SEARCH_LENGTH_THRESHOLD)
- goto exact_method;
-
- r = set_bm_backward_skip(reg->exact, reg->exact_end, reg->enc,
- &(reg->int_map_backward));
- if (r) return r;
- }
- p = bm_search_backward(reg, reg->exact, reg->exact_end, range, adjrange,
- end, p);
-#else
goto exact_method;
-#endif
break;
case ONIG_OPTIMIZE_MAP:
@@ -5122,45 +4790,57 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
switch (reg->sub_anchor) {
case ANCHOR_BEGIN_LINE:
- if (!ON_STR_BEGIN(p)) {
- prev = onigenc_get_prev_char_head(reg->enc, str, p, end);
- if (!ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 0)) {
- p = prev;
- goto retry;
- }
- }
- break;
+ if (!ON_STR_BEGIN(p)) {
+ prev = onigenc_get_prev_char_head(reg->enc, str, p, end);
+ if (!ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 0)) {
+ p = prev;
+ goto retry;
+ }
+ }
+ break;
case ANCHOR_END_LINE:
- if (ON_STR_END(p)) {
+ if (ON_STR_END(p)) {
#ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
- prev = onigenc_get_prev_char_head(reg->enc, adjrange, p);
- if (IS_NULL(prev)) goto fail;
- if (ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 1)) {
- p = prev;
- goto retry;
- }
+ prev = onigenc_get_prev_char_head(reg->enc, adjrange, p);
+ if (IS_NULL(prev)) goto fail;
+ if (ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 1)) {
+ p = prev;
+ goto retry;
+ }
#endif
- }
- else if (! ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, p, str, end, reg->options, 1)) {
- p = onigenc_get_prev_char_head(reg->enc, adjrange, p, end);
- if (IS_NULL(p)) goto fail;
- goto retry;
- }
- break;
+ }
+ else if (! ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, p, str, end, reg->options, 1)) {
+ p = onigenc_get_prev_char_head(reg->enc, adjrange, p, end);
+ if (IS_NULL(p)) goto fail;
+ goto retry;
+ }
+ break;
}
}
- /* no needs to adjust *high, *high is used as range check only */
if (reg->dmax != ONIG_INFINITE_DISTANCE) {
- *low = p - reg->dmax;
- *high = p - reg->dmin;
+ if ((OnigDistance)(p - str) < reg->dmax)
+ *low = (UChar* )str;
+ else
+ *low = p - reg->dmax;
+
+ if (reg->dmin != 0) {
+ if ((OnigDistance)(p - str) < reg->dmin)
+ *high = (UChar* )str;
+ else
+ *high = p - reg->dmin;
+ }
+ else {
+ *high = p;
+ }
+
*high = onigenc_get_right_adjust_char_head(reg->enc, adjrange, *high, end);
}
#ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "backward_search_range: low: %d, high: %d\n",
- (int )(*low - str), (int )(*high - str));
+ (int )(*low - str), (int )(*high - str));
#endif
return 1; /* success */
}
@@ -5175,15 +4855,15 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
extern OnigPosition
onig_search(regex_t* reg, const UChar* str, const UChar* end,
- const UChar* start, const UChar* range, OnigRegion* region, OnigOptionType option)
+ const UChar* start, const UChar* range, OnigRegion* region, OnigOptionType option)
{
return onig_search_gpos(reg, str, end, start, start, range, region, option);
}
extern OnigPosition
onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
- const UChar* global_pos,
- const UChar* start, const UChar* range, OnigRegion* region, OnigOptionType option)
+ const UChar* global_pos,
+ const UChar* start, const UChar* range, OnigRegion* region, OnigOptionType option)
{
ptrdiff_t r;
UChar *s, *prev;
@@ -5283,62 +4963,69 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
begin_position:
if (range > start)
{
- if (global_pos > start)
- {
- if (global_pos < range)
- range = global_pos + 1;
- }
- else
- range = start + 1;
+ if (global_pos > start)
+ {
+ if (global_pos < range)
+ range = global_pos + 1;
+ }
+ else
+ range = start + 1;
}
else
- range = start;
+ range = start;
}
else if (reg->anchor & ANCHOR_BEGIN_BUF) {
/* search str-position only */
if (range > start) {
- if (start != str) goto mismatch_no_msa;
- range = str + 1;
+ if (start != str) goto mismatch_no_msa;
+ range = str + 1;
}
else {
- if (range <= str) {
- start = str;
- range = str;
- }
- else
- goto mismatch_no_msa;
+ if (range <= str) {
+ start = str;
+ range = str;
+ }
+ else
+ goto mismatch_no_msa;
}
}
else if (reg->anchor & ANCHOR_END_BUF) {
min_semi_end = max_semi_end = (UChar* )end;
end_buf:
- if ((OnigDistance )(max_semi_end - str) < reg->anchor_dmin)
- goto mismatch_no_msa;
+ if ((OnigDistance)(max_semi_end - str) < reg->anchor_dmin)
+ goto mismatch_no_msa;
if (range > start) {
- if ((OnigDistance )(min_semi_end - start) > reg->anchor_dmax) {
- start = min_semi_end - reg->anchor_dmax;
- if (start < end)
- start = onigenc_get_right_adjust_char_head(reg->enc, str, start, end);
- }
- if ((OnigDistance )(max_semi_end - (range - 1)) < reg->anchor_dmin) {
- range = max_semi_end - reg->anchor_dmin + 1;
- }
+ if ((OnigDistance)(min_semi_end - start) > reg->anchor_dmax) {
+ start = min_semi_end - reg->anchor_dmax;
+ if (start < end)
+ start = onigenc_get_right_adjust_char_head(reg->enc, str, start, end);
+ }
+ if ((OnigDistance)(max_semi_end - (range - 1)) < reg->anchor_dmin) {
+ if ((OnigDistance)(max_semi_end - str + 1) < reg->anchor_dmin)
+ goto mismatch_no_msa;
+ else
+ range = max_semi_end - reg->anchor_dmin + 1;
+ }
- if (start > range) goto mismatch_no_msa;
- /* If start == range, match with empty at end.
- Backward search is used. */
+ if (start > range) goto mismatch_no_msa;
+ /* If start == range, match with empty at end.
+ Backward search is used. */
}
else {
- if ((OnigDistance )(min_semi_end - range) > reg->anchor_dmax) {
- range = min_semi_end - reg->anchor_dmax;
- }
- if ((OnigDistance )(max_semi_end - start) < reg->anchor_dmin) {
- start = max_semi_end - reg->anchor_dmin;
- start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, start, end);
- }
- if (range > start) goto mismatch_no_msa;
+ if ((OnigDistance)(min_semi_end - range) > reg->anchor_dmax) {
+ range = min_semi_end - reg->anchor_dmax;
+ }
+ if ((OnigDistance)(max_semi_end - start) < reg->anchor_dmin) {
+ if ((OnigDistance)(max_semi_end - str) < reg->anchor_dmin)
+ goto mismatch_no_msa;
+ else {
+ start = max_semi_end - reg->anchor_dmin;
+ start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, start, end);
+ }
+ }
+ if (range > start) goto mismatch_no_msa;
}
}
else if (reg->anchor & ANCHOR_SEMI_END_BUF) {
@@ -5346,23 +5033,23 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
max_semi_end = (UChar* )end;
if (ONIGENC_IS_MBC_NEWLINE(reg->enc, pre_end, end)) {
- min_semi_end = pre_end;
+ min_semi_end = pre_end;
#ifdef USE_CRNL_AS_LINE_TERMINATOR
- pre_end = ONIGENC_STEP_BACK(reg->enc, str, pre_end, end, 1);
- if (IS_NOT_NULL(pre_end) &&
- IS_NEWLINE_CRLF(reg->options) &&
- ONIGENC_IS_MBC_CRNL(reg->enc, pre_end, end)) {
- min_semi_end = pre_end;
- }
+ pre_end = ONIGENC_STEP_BACK(reg->enc, str, pre_end, end, 1);
+ if (IS_NOT_NULL(pre_end) &&
+ IS_NEWLINE_CRLF(reg->options) &&
+ ONIGENC_IS_MBC_CRNL(reg->enc, pre_end, end)) {
+ min_semi_end = pre_end;
+ }
#endif
- if (min_semi_end > str && start <= min_semi_end) {
- goto end_buf;
- }
+ if (min_semi_end > str && start <= min_semi_end) {
+ goto end_buf;
+ }
}
else {
- min_semi_end = (UChar* )end;
- goto end_buf;
+ min_semi_end = (UChar* )end;
+ goto end_buf;
}
}
else if ((reg->anchor & ANCHOR_ANYCHAR_STAR_ML)) {
@@ -5394,7 +5081,7 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
#ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "onig_search(apply anchor): end: %d, start: %d, range: %d\n",
- (int )(end - str), (int )(start - str), (int )(range - str));
+ (int )(end - str), (int )(start - str), (int )(range - str));
#endif
MATCH_ARG_INIT(msa, option, region, start, global_pos);
@@ -5415,55 +5102,59 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
if (reg->optimize != ONIG_OPTIMIZE_NONE) {
UChar *sch_range, *low, *high, *low_prev;
- sch_range = (UChar* )range;
if (reg->dmax != 0) {
- if (reg->dmax == ONIG_INFINITE_DISTANCE)
- sch_range = (UChar* )end;
- else {
- sch_range += reg->dmax;
- if (sch_range > end) sch_range = (UChar* )end;
- }
+ if (reg->dmax == ONIG_INFINITE_DISTANCE)
+ sch_range = (UChar* )end;
+ else {
+ if ((OnigDistance)(end - range) < reg->dmax)
+ sch_range = (UChar* )end;
+ else {
+ sch_range = (UChar* )range + reg->dmax;
+ }
+ }
}
+ else
+ sch_range = (UChar* )range;
if ((end - start) < reg->threshold_len)
- goto mismatch;
+ goto mismatch;
if (reg->dmax != ONIG_INFINITE_DISTANCE) {
- do {
- if (! forward_search_range(reg, str, end, s, sch_range,
- &low, &high, &low_prev)) goto mismatch;
- if (s < low) {
- s = low;
- prev = low_prev;
- }
- while (s <= high) {
- MATCH_AND_RETURN_CHECK(orig_range);
- prev = s;
- s += enclen(reg->enc, s, end);
- }
- } while (s < range);
- goto mismatch;
+ do {
+ if (! forward_search_range(reg, str, end, s, sch_range,
+ &low, &high, &low_prev)) goto mismatch;
+ if (s < low) {
+ s = low;
+ prev = low_prev;
+ }
+ while (s <= high) {
+ MATCH_AND_RETURN_CHECK(orig_range);
+ prev = s;
+ s += enclen(reg->enc, s, end);
+ }
+ } while (s < range);
+ goto mismatch;
}
else { /* check only. */
- if (! forward_search_range(reg, str, end, s, sch_range,
- &low, &high, (UChar** )NULL)) goto mismatch;
-
- if ((reg->anchor & ANCHOR_ANYCHAR_STAR) != 0) {
- do {
- MATCH_AND_RETURN_CHECK(orig_range);
- prev = s;
- s += enclen(reg->enc, s, end);
-
- if ((reg->anchor & (ANCHOR_LOOK_BEHIND | ANCHOR_PREC_READ_NOT)) == 0) {
- while (!ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 0)
- && s < range) {
- prev = s;
- s += enclen(reg->enc, s, end);
- }
- }
- } while (s < range);
- goto mismatch;
- }
+ if (! forward_search_range(reg, str, end, s, sch_range,
+ &low, &high, (UChar** )NULL)) goto mismatch;
+
+ if ((reg->anchor & ANCHOR_ANYCHAR_STAR) != 0) {
+ do {
+ MATCH_AND_RETURN_CHECK(orig_range);
+ prev = s;
+ s += enclen(reg->enc, s, end);
+
+ if ((reg->anchor & (ANCHOR_LOOK_BEHIND | ANCHOR_PREC_READ_NOT)) == 0) {
+ while (!ONIGENC_IS_MBC_NEWLINE_EX(reg->enc, prev, str, end, reg->options, 0)
+ && s < range) {
+ prev = s;
+ s += enclen(reg->enc, s, end);
+ }
+ }
+ } while (s < range);
+ goto mismatch;
+ }
}
}
@@ -5480,49 +5171,61 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
else { /* backward search */
if (reg->optimize != ONIG_OPTIMIZE_NONE) {
UChar *low, *high, *adjrange, *sch_start;
+ const UChar *min_range;
if (range < end)
- adjrange = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, range, end);
+ adjrange = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, range, end);
+ else
+ adjrange = (UChar* )end;
+
+ if ((OnigDistance)(end - range) > reg->dmin)
+ min_range = range + reg->dmin;
else
- adjrange = (UChar* )end;
+ min_range = end;
if (reg->dmax != ONIG_INFINITE_DISTANCE &&
- (end - range) >= reg->threshold_len) {
- do {
- sch_start = s + reg->dmax;
- if (sch_start > end) sch_start = (UChar* )end;
- if (backward_search_range(reg, str, end, sch_start, range, adjrange,
- &low, &high) <= 0)
- goto mismatch;
-
- if (s > high)
- s = high;
-
- while (s >= low) {
- prev = onigenc_get_prev_char_head(reg->enc, str, s, end);
- MATCH_AND_RETURN_CHECK(orig_start);
- s = prev;
- }
- } while (s >= range);
- goto mismatch;
+ end - range >= reg->threshold_len) {
+ do {
+ if ((OnigDistance)(end - s) > reg->dmax)
+ sch_start = s + reg->dmax;
+ else
+ sch_start = (UChar* )end;
+
+ if (backward_search_range(reg, str, end, sch_start, min_range, adjrange,
+ &low, &high) <= 0)
+ goto mismatch;
+
+ if (s > high)
+ s = high;
+
+ while (s >= low) {
+ prev = onigenc_get_prev_char_head(reg->enc, str, s, end);
+ MATCH_AND_RETURN_CHECK(orig_start);
+ s = prev;
+ }
+ } while (s >= range);
+ goto mismatch;
}
else { /* check only. */
- if ((end - range) < reg->threshold_len) goto mismatch;
-
- sch_start = s;
- if (reg->dmax != 0) {
- if (reg->dmax == ONIG_INFINITE_DISTANCE)
- sch_start = (UChar* )end;
- else {
- sch_start += reg->dmax;
- if (sch_start > end) sch_start = (UChar* )end;
- else
- sch_start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc,
- start, sch_start, end);
- }
- }
- if (backward_search_range(reg, str, end, sch_start, range, adjrange,
- &low, &high) <= 0) goto mismatch;
+ if (end - range < reg->threshold_len) goto mismatch;
+
+ if (reg->dmax != 0) {
+ if (reg->dmax == ONIG_INFINITE_DISTANCE)
+ sch_start = (UChar* )end;
+ else {
+ if ((OnigDistance)(end - s) > reg->dmax) {
+ sch_start = s + reg->dmax;
+ sch_start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc,
+ start, sch_start, end);
+ } else
+ sch_start = (UChar* )end;
+ }
+ }
+ else
+ sch_start = (UChar* )s;
+
+ if (backward_search_range(reg, str, end, sch_start, min_range, adjrange,
+ &low, &high) <= 0) goto mismatch;
}
}
@@ -5579,9 +5282,9 @@ timeout:
extern OnigPosition
onig_scan(regex_t* reg, const UChar* str, const UChar* end,
- OnigRegion* region, OnigOptionType option,
- int (*scan_callback)(OnigPosition, OnigPosition, OnigRegion*, void*),
- void* callback_arg)
+ OnigRegion* region, OnigOptionType option,
+ int (*scan_callback)(OnigPosition, OnigPosition, OnigRegion*, void*),
+ void* callback_arg)
{
OnigPosition r;
OnigPosition n;
@@ -5596,17 +5299,17 @@ onig_scan(regex_t* reg, const UChar* str, const UChar* end,
rs = scan_callback(n, r, region, callback_arg);
n++;
if (rs != 0)
- return rs;
+ return rs;
if (region->end[0] == start - str) {
- if (start >= end) break;
- start += enclen(reg->enc, start, end);
+ if (start >= end) break;
+ start += enclen(reg->enc, start, end);
}
else
- start = str + region->end[0];
+ start = str + region->end[0];
if (start > end)
- break;
+ break;
}
else if (r == ONIG_MISMATCH) {
break;
diff --git a/regint.h b/regint.h
index 75abfba235..3f4aa919e5 100644
--- a/regint.h
+++ b/regint.h
@@ -5,7 +5,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2013 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,13 +86,12 @@
/* #define USE_OP_PUSH_OR_JUMP_EXACT */
#define USE_QTFR_PEEK_NEXT
#define USE_ST_LIBRARY
-#define USE_SUNDAY_QUICK_SEARCH
#define INIT_MATCH_STACK_SIZE 160
#define DEFAULT_MATCH_STACK_LIMIT_SIZE 0 /* unlimited */
#define DEFAULT_PARSE_DEPTH_LIMIT 4096
-#define OPT_EXACT_MAXLEN 24
+#define OPT_EXACT_MAXLEN 24 /* This must be smaller than ONIG_CHAR_TABLE_SIZE. */
/* check config */
#if defined(USE_PERL_SUBEXP_CALL) || defined(USE_CAPITAL_P_NAMED_GROUP)
@@ -216,9 +215,7 @@
#define xmemcpy memcpy
#define xmemmove memmove
-#if ((defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 90) \
- || (!defined(RUBY_MSVCRT_VERSION) && defined(_WIN32))) \
- && !defined(__GNUC__)
+#if defined(_WIN32) && !defined(__GNUC__)
# define xalloca _alloca
# define xvsnprintf(buf,size,fmt,args) _vsnprintf_s(buf,size,_TRUNCATE,fmt,args)
# define xsnprintf sprintf_s
@@ -267,19 +264,6 @@
# include <stdio.h>
#endif
-#ifdef _WIN32
-# if defined(_MSC_VER) && (_MSC_VER < 1300)
-# ifndef _INTPTR_T_DEFINED
-# define _INTPTR_T_DEFINED
-typedef int intptr_t;
-# endif
-# ifndef _UINTPTR_T_DEFINED
-# define _UINTPTR_T_DEFINED
-typedef unsigned int uintptr_t;
-# endif
-# endif
-#endif /* _WIN32 */
-
#ifndef PRIdPTR
# ifdef _WIN64
# define PRIdPTR "I64d"
diff --git a/regparse.c b/regparse.c
index c7587b53b7..123b3015a5 100644
--- a/regparse.c
+++ b/regparse.c
@@ -3,7 +3,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2008 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -329,7 +329,7 @@ strdup_with_null(OnigEncoding enc, const UChar* s, const UChar* end)
static UChar*
strcat_capa(UChar* dest, UChar* dest_end, const UChar* src, const UChar* src_end,
- size_t capa)
+ size_t capa)
{
UChar* r;
@@ -346,7 +346,7 @@ strcat_capa(UChar* dest, UChar* dest_end, const UChar* src, const UChar* src_end
/* dest on static area */
static UChar*
strcat_capa_from_static(UChar* dest, UChar* dest_end,
- const UChar* src, const UChar* src_end, size_t capa)
+ const UChar* src, const UChar* src_end, size_t capa)
{
UChar* r;
@@ -426,7 +426,7 @@ onig_st_init_strend_table_with_size(st_index_t size)
extern int
onig_st_lookup_strend(hash_table_type* table, const UChar* str_key,
- const UChar* end_key, hash_data_type *value)
+ const UChar* end_key, hash_data_type *value)
{
st_str_end_key key;
@@ -438,7 +438,7 @@ onig_st_lookup_strend(hash_table_type* table, const UChar* str_key,
extern int
onig_st_insert_strend(hash_table_type* table, const UChar* str_key,
- const UChar* end_key, hash_data_type value)
+ const UChar* end_key, hash_data_type value)
{
st_str_end_key* key;
int result;
@@ -629,10 +629,10 @@ i_names(HashDataType key_ ARG_UNUSED, HashDataType e_, HashDataType arg_)
NameEntry* e = (NameEntry *)e_;
INamesArg* arg = (INamesArg *)arg_;
int r = (*(arg->func))(e->name,
- e->name + e->name_len,
- e->back_num,
- (e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
- arg->reg, arg->arg);
+ e->name + e->name_len,
+ e->back_num,
+ (e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
+ arg->reg, arg->arg);
if (r != 0) {
arg->ret = r;
return ST_STOP;
@@ -724,16 +724,16 @@ onig_print_names(FILE* fp, regex_t* reg)
e = &(t->e[i]);
fprintf(fp, "%s: ", e->name);
if (e->back_num == 0) {
- fputs("-", fp);
+ fputs("-", fp);
}
else if (e->back_num == 1) {
- fprintf(fp, "%d", e->back_ref1);
+ fprintf(fp, "%d", e->back_ref1);
}
else {
- for (j = 0; j < e->back_num; j++) {
- if (j > 0) fprintf(fp, ", ");
- fprintf(fp, "%d", e->back_refs[j]);
- }
+ for (j = 0; j < e->back_num; j++) {
+ if (j > 0) fprintf(fp, ", ");
+ fprintf(fp, "%d", e->back_refs[j]);
+ }
}
fputs("\n", fp);
}
@@ -754,13 +754,13 @@ names_clear(regex_t* reg)
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
if (IS_NOT_NULL(e->name)) {
- xfree(e->name);
- e->name = NULL;
- e->name_len = 0;
- e->back_num = 0;
- e->back_alloc = 0;
- xfree(e->back_refs);
- e->back_refs = (int* )NULL;
+ xfree(e->name);
+ e->name = NULL;
+ e->name_len = 0;
+ e->back_num = 0;
+ e->back_alloc = 0;
+ xfree(e->back_refs);
+ e->back_refs = (int* )NULL;
}
}
@@ -840,7 +840,7 @@ name_find(regex_t* reg, const UChar* name, const UChar* name_end)
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
if (len == e->name_len && onig_strncmp(name, e->name, len) == 0)
- return e;
+ return e;
}
}
return (NameEntry* )NULL;
@@ -858,8 +858,8 @@ onig_foreach_name(regex_t* reg,
for (i = 0; i < t->num; i++) {
e = &(t->e[i]);
r = (*func)(e->name, e->name + e->name_len, e->back_num,
- (e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
- reg, arg);
+ (e->back_num > 1 ? e->back_refs : &(e->back_ref1)),
+ reg, arg);
if (r != 0) return r;
}
}
@@ -948,8 +948,8 @@ name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
t->e = (NameEntry* )xmalloc(sizeof(NameEntry) * alloc);
if (IS_NULL(t->e)) {
- xfree(t);
- return ONIGERR_MEMORY;
+ xfree(t);
+ return ONIGERR_MEMORY;
}
t->alloc = alloc;
reg->name_table = t;
@@ -967,11 +967,11 @@ name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
clear:
for (i = t->num; i < t->alloc; i++) {
- t->e[i].name = NULL;
- t->e[i].name_len = 0;
- t->e[i].back_num = 0;
- t->e[i].back_alloc = 0;
- t->e[i].back_refs = (int* )NULL;
+ t->e[i].name = NULL;
+ t->e[i].name_len = 0;
+ t->e[i].back_num = 0;
+ t->e[i].back_alloc = 0;
+ t->e[i].back_refs = (int* )NULL;
}
}
e = &(t->e[t->num]);
@@ -985,7 +985,7 @@ name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
if (e->back_num >= 1 &&
! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME)) {
onig_scan_env_set_error_string(env, ONIGERR_MULTIPLEX_DEFINED_NAME,
- name, name_end);
+ name, name_end);
return ONIGERR_MULTIPLEX_DEFINED_NAME;
}
@@ -1004,12 +1004,12 @@ name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
}
else {
if (e->back_num > e->back_alloc) {
- int* p;
- alloc = e->back_alloc * 2;
- p = (int* )xrealloc(e->back_refs, sizeof(int) * alloc);
- CHECK_NULL_RETURN_MEMERR(p);
- e->back_refs = p;
- e->back_alloc = alloc;
+ int* p;
+ alloc = e->back_alloc * 2;
+ p = (int* )xrealloc(e->back_refs, sizeof(int) * alloc);
+ CHECK_NULL_RETURN_MEMERR(p);
+ e->back_refs = p;
+ e->back_alloc = alloc;
}
e->back_refs[e->back_num - 1] = backref;
}
@@ -1020,7 +1020,7 @@ name_add(regex_t* reg, UChar* name, UChar* name_end, int backref, ScanEnv* env)
extern int
onig_name_to_group_numbers(regex_t* reg, const UChar* name,
- const UChar* name_end, int** nums)
+ const UChar* name_end, int** nums)
{
NameEntry* e = name_find(reg, name, name_end);
@@ -1042,7 +1042,7 @@ onig_name_to_group_numbers(regex_t* reg, const UChar* name,
extern int
onig_name_to_backref_number(regex_t* reg, const UChar* name,
- const UChar* name_end, const OnigRegion *region)
+ const UChar* name_end, const OnigRegion *region)
{
int i, n, *nums;
@@ -1056,8 +1056,8 @@ onig_name_to_backref_number(regex_t* reg, const UChar* name,
else {
if (IS_NOT_NULL(region)) {
for (i = n - 1; i >= 0; i--) {
- if (region->beg[nums[i]] != ONIG_REGION_NOTPOS)
- return nums[i];
+ if (region->beg[nums[i]] != ONIG_REGION_NOTPOS)
+ return nums[i];
}
}
return nums[n - 1];
@@ -1068,14 +1068,14 @@ onig_name_to_backref_number(regex_t* reg, const UChar* name,
extern int
onig_name_to_group_numbers(regex_t* reg, const UChar* name,
- const UChar* name_end, int** nums)
+ const UChar* name_end, int** nums)
{
return ONIG_NO_SUPPORT_CONFIG;
}
extern int
onig_name_to_backref_number(regex_t* reg, const UChar* name,
- const UChar* name_end, const OnigRegion* region)
+ const UChar* name_end, const OnigRegion* region)
{
return ONIG_NO_SUPPORT_CONFIG;
}
@@ -1164,20 +1164,20 @@ scan_env_add_mem_entry(ScanEnv* env)
if (need >= SCANENV_MEMNODES_SIZE) {
if (env->mem_alloc <= need) {
if (IS_NULL(env->mem_nodes_dynamic)) {
- alloc = INIT_SCANENV_MEMNODES_ALLOC_SIZE;
- p = (Node** )xmalloc(sizeof(Node*) * alloc);
- CHECK_NULL_RETURN_MEMERR(p);
- xmemcpy(p, env->mem_nodes_static,
- sizeof(Node*) * SCANENV_MEMNODES_SIZE);
+ alloc = INIT_SCANENV_MEMNODES_ALLOC_SIZE;
+ p = (Node** )xmalloc(sizeof(Node*) * alloc);
+ CHECK_NULL_RETURN_MEMERR(p);
+ xmemcpy(p, env->mem_nodes_static,
+ sizeof(Node*) * SCANENV_MEMNODES_SIZE);
}
else {
- alloc = env->mem_alloc * 2;
- p = (Node** )xrealloc(env->mem_nodes_dynamic, sizeof(Node*) * alloc);
- CHECK_NULL_RETURN_MEMERR(p);
+ alloc = env->mem_alloc * 2;
+ p = (Node** )xrealloc(env->mem_nodes_dynamic, sizeof(Node*) * alloc);
+ CHECK_NULL_RETURN_MEMERR(p);
}
for (i = env->num_mem + 1; i < alloc; i++)
- p[i] = NULL_NODE;
+ p[i] = NULL_NODE;
env->mem_nodes_dynamic = p;
env->mem_alloc = alloc;
@@ -1208,7 +1208,7 @@ onig_node_free(Node* node)
switch (NTYPE(node)) {
case NT_STR:
if (NSTR(node)->capa != 0 &&
- IS_NOT_NULL(NSTR(node)->s) && NSTR(node)->s != NSTR(node)->buf) {
+ IS_NOT_NULL(NSTR(node)->s) && NSTR(node)->s != NSTR(node)->buf) {
xfree(NSTR(node)->s);
}
break;
@@ -1371,9 +1371,9 @@ onig_node_new_anchor(int type)
static Node*
node_new_backref(int back_num, int* backrefs, int by_name,
#ifdef USE_BACKREF_WITH_LEVEL
- int exist_level, int nest_level,
+ int exist_level, int nest_level,
#endif
- ScanEnv* env)
+ ScanEnv* env)
{
int i;
Node* node = node_new();
@@ -1396,7 +1396,7 @@ node_new_backref(int back_num, int* backrefs, int by_name,
for (i = 0; i < back_num; i++) {
if (backrefs[i] <= env->num_mem &&
- IS_NULL(SCANENV_MEM_NODES(env)[backrefs[i]])) {
+ IS_NULL(SCANENV_MEM_NODES(env)[backrefs[i]])) {
NBREF(node)->state |= NST_RECURSION; /* /...(\1).../ */
break;
}
@@ -1521,18 +1521,18 @@ onig_node_str_cat(Node* node, const UChar* s, const UChar* end)
ptrdiff_t capa = len + addlen + NODE_STR_MARGIN;
if (capa <= NSTR(node)->capa) {
- onig_strcpy(NSTR(node)->s + len, s, end);
+ onig_strcpy(NSTR(node)->s + len, s, end);
}
else {
- if (NSTR(node)->s == NSTR(node)->buf)
- p = strcat_capa_from_static(NSTR(node)->s, NSTR(node)->end,
- s, end, capa);
- else
- p = strcat_capa(NSTR(node)->s, NSTR(node)->end, s, end, capa);
+ if (NSTR(node)->s == NSTR(node)->buf)
+ p = strcat_capa_from_static(NSTR(node)->s, NSTR(node)->end,
+ s, end, capa);
+ else
+ p = strcat_capa(NSTR(node)->s, NSTR(node)->end, s, end, capa);
- CHECK_NULL_RETURN_MEMERR(p);
- NSTR(node)->s = p;
- NSTR(node)->capa = (int )capa;
+ CHECK_NULL_RETURN_MEMERR(p);
+ NSTR(node)->s = p;
+ NSTR(node)->capa = (int )capa;
}
}
else {
@@ -1654,7 +1654,7 @@ str_node_split_last_char(StrNode* sn, OnigEncoding enc)
if (p && p > sn->s) { /* can be split. */
n = node_new_str(p, sn->end);
if (IS_NOT_NULL(n) && (sn->flag & NSTR_RAW) != 0)
- NSTRING_SET_RAW(n);
+ NSTRING_SET_RAW(n);
sn->end = (UChar* )p;
}
}
@@ -1702,7 +1702,7 @@ onig_scan_unsigned_number(UChar** src, const UChar* end, OnigEncoding enc)
if (ONIGENC_IS_CODE_DIGIT(enc, c)) {
val = (unsigned int )DIGITVAL(c);
if ((INT_MAX_LIMIT - val) / 10UL < num)
- return -1; /* overflow */
+ return -1; /* overflow */
num = num * 10 + val;
}
@@ -1717,7 +1717,7 @@ onig_scan_unsigned_number(UChar** src, const UChar* end, OnigEncoding enc)
static int
scan_unsigned_hexadecimal_number(UChar** src, UChar* end, int minlen,
- int maxlen, OnigEncoding enc)
+ int maxlen, OnigEncoding enc)
{
OnigCodePoint c;
unsigned int num, val;
@@ -1732,7 +1732,7 @@ scan_unsigned_hexadecimal_number(UChar** src, UChar* end, int minlen,
if (ONIGENC_IS_CODE_XDIGIT(enc, c)) {
val = (unsigned int )XDIGITVAL(enc,c);
if ((INT_MAX_LIMIT - val) / 16UL < num)
- return -1; /* overflow */
+ return -1; /* overflow */
num = (num << 4) + XDIGITVAL(enc,c);
}
@@ -1750,7 +1750,7 @@ scan_unsigned_hexadecimal_number(UChar** src, UChar* end, int minlen,
static int
scan_unsigned_octal_number(UChar** src, UChar* end, int maxlen,
- OnigEncoding enc)
+ OnigEncoding enc)
{
OnigCodePoint c;
unsigned int num, val;
@@ -1763,7 +1763,7 @@ scan_unsigned_octal_number(UChar** src, UChar* end, int maxlen,
if (ONIGENC_IS_CODE_DIGIT(enc, c) && c < '8') {
val = ODIGITVAL(c);
if ((INT_MAX_LIMIT - val) / 8UL < num)
- return -1; /* overflow */
+ return -1; /* overflow */
num = (num << 3) + val;
}
@@ -1804,7 +1804,7 @@ new_code_range(BBuf** pbuf)
static int
add_code_range_to_buf0(BBuf** pbuf, ScanEnv* env, OnigCodePoint from, OnigCodePoint to,
- int checkdup)
+ int checkdup)
{
int r, inc_n, pos;
OnigCodePoint low, high, bound, x;
@@ -1855,7 +1855,7 @@ add_code_range_to_buf0(BBuf** pbuf, ScanEnv* env, OnigCodePoint from, OnigCodePo
if (inc_n != 1) {
if (checkdup && from <= data[low*2+1]
- && (data[low*2] <= from || data[low*2+1] <= to))
+ && (data[low*2] <= from || data[low*2+1] <= to))
CC_DUP_WARN(env, from, to);
if (from > data[low*2])
from = data[low*2];
@@ -1869,8 +1869,8 @@ add_code_range_to_buf0(BBuf** pbuf, ScanEnv* env, OnigCodePoint from, OnigCodePo
if (inc_n > 0) {
if (high < n) {
- int size = (n - high) * 2 * SIZE_CODE_POINT;
- BBUF_MOVE_RIGHT(bbuf, from_pos, to_pos, size);
+ int size = (n - high) * 2 * SIZE_CODE_POINT;
+ BBUF_MOVE_RIGHT(bbuf, from_pos, to_pos, size);
}
}
else {
@@ -1980,10 +1980,10 @@ or_code_range_buf(OnigEncoding enc, BBuf* bbuf1, int not1,
}
else {
if (not2 == 0) {
- return bbuf_clone(pbuf, bbuf2);
+ return bbuf_clone(pbuf, bbuf2);
}
else {
- return not_code_range_buf(enc, bbuf2, pbuf, env);
+ return not_code_range_buf(enc, bbuf2, pbuf, env);
}
}
}
@@ -2014,7 +2014,7 @@ or_code_range_buf(OnigEncoding enc, BBuf* bbuf1, int not1,
static int
and_code_range1(BBuf** pbuf, ScanEnv* env, OnigCodePoint from1, OnigCodePoint to1,
- OnigCodePoint* data, int n)
+ OnigCodePoint* data, int n)
{
int i, r;
OnigCodePoint from2, to2;
@@ -2025,19 +2025,19 @@ and_code_range1(BBuf** pbuf, ScanEnv* env, OnigCodePoint from1, OnigCodePoint to
if (from2 < from1) {
if (to2 < from1) continue;
else {
- from1 = to2 + 1;
+ from1 = to2 + 1;
}
}
else if (from2 <= to1) {
if (to2 < to1) {
- if (from1 <= from2 - 1) {
- r = add_code_range_to_buf(pbuf, env, from1, from2-1);
- if (r != 0) return r;
- }
- from1 = to2 + 1;
+ if (from1 <= from2 - 1) {
+ r = add_code_range_to_buf(pbuf, env, from1, from2-1);
+ if (r != 0) return r;
+ }
+ from1 = to2 + 1;
}
else {
- to1 = from2 - 1;
+ to1 = from2 - 1;
}
}
else {
@@ -2086,14 +2086,14 @@ and_code_range_buf(BBuf* bbuf1, int not1, BBuf* bbuf2, int not2, BBuf** pbuf, Sc
from1 = data1[i*2];
to1 = data1[i*2+1];
for (j = 0; j < n2; j++) {
- from2 = data2[j*2];
- to2 = data2[j*2+1];
- if (from2 > to1) break;
- if (to2 < from1) continue;
- from = MAX(from1, from2);
- to = MIN(to1, to2);
- r = add_code_range_to_buf(pbuf, env, from, to);
- if (r != 0) return r;
+ from2 = data2[j*2];
+ to2 = data2[j*2+1];
+ if (from2 > to1) break;
+ if (to2 < from1) continue;
+ from = MAX(from1, from2);
+ to = MIN(to1, to2);
+ r = add_code_range_to_buf(pbuf, env, from, to);
+ if (r != 0) return r;
}
}
}
@@ -2149,10 +2149,10 @@ and_cclass(CClassNode* dest, CClassNode* cc, ScanEnv* env)
else {
r = and_code_range_buf(buf1, not1, buf2, not2, &pbuf, env);
if (r == 0 && not1 != 0) {
- BBuf *tbuf = 0;
- r = not_code_range_buf(enc, pbuf, &tbuf, env);
- bbuf_free(pbuf);
- pbuf = tbuf;
+ BBuf *tbuf = 0;
+ r = not_code_range_buf(enc, pbuf, &tbuf, env);
+ bbuf_free(pbuf);
+ pbuf = tbuf;
}
}
if (r != 0) {
@@ -2207,10 +2207,10 @@ or_cclass(CClassNode* dest, CClassNode* cc, ScanEnv* env)
else {
r = or_code_range_buf(enc, buf1, not1, buf2, not2, &pbuf, env);
if (r == 0 && not1 != 0) {
- BBuf *tbuf = 0;
- r = not_code_range_buf(enc, pbuf, &tbuf, env);
- bbuf_free(pbuf);
- pbuf = tbuf;
+ BBuf *tbuf = 0;
+ r = not_code_range_buf(enc, pbuf, &tbuf, env);
+ bbuf_free(pbuf);
+ pbuf = tbuf;
}
}
if (r != 0) {
@@ -2242,12 +2242,12 @@ conv_backslash_value(OnigCodePoint c, ScanEnv* env)
case 'e': return '\033';
case 'v':
if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ESC_V_VTAB))
- return '\v';
+ return '\v';
break;
default:
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
- UNKNOWN_ESC_WARN(env, c);
+ UNKNOWN_ESC_WARN(env, c);
break;
}
}
@@ -2506,7 +2506,7 @@ fetch_range_quantifier(UChar** src, UChar* end, OnigToken* tok, ScanEnv* env)
if (p == prev) {
if (non_low != 0)
- goto invalid;
+ goto invalid;
up = REPEAT_INFINITE; /* {n,} : {n,infinite} */
}
}
@@ -2566,8 +2566,8 @@ fetch_escaped_value(UChar** src, UChar* end, ScanEnv* env, OnigCodePoint* val)
if (PEND) return ONIGERR_END_PATTERN_AT_META;
PFETCH_S(c);
if (c == MC_ESC(env->syntax)) {
- v = fetch_escaped_value(&p, end, env, &c);
- if (v < 0) return v;
+ v = fetch_escaped_value(&p, end, env, &c);
+ if (v < 0) return v;
}
c = ((c & 0xff) | 0x80);
}
@@ -2591,14 +2591,14 @@ fetch_escaped_value(UChar** src, UChar* end, ScanEnv* env, OnigCodePoint* val)
if (PEND) return ONIGERR_END_PATTERN_AT_CONTROL;
PFETCH_S(c);
if (c == '?') {
- c = 0177;
+ c = 0177;
}
else {
- if (c == MC_ESC(env->syntax)) {
- v = fetch_escaped_value(&p, end, env, &c);
- if (v < 0) return v;
- }
- c &= 0x9f;
+ if (c == MC_ESC(env->syntax)) {
+ v = fetch_escaped_value(&p, end, env, &c);
+ if (v < 0) return v;
+ }
+ c &= 0x9f;
}
break;
}
@@ -2649,8 +2649,8 @@ get_name_end_code_point(OnigCodePoint start)
*/
static int
fetch_name_with_level(OnigCodePoint start_code, UChar** src, UChar* end,
- UChar** rname_end, ScanEnv* env,
- int* rback_num, int* rlevel)
+ UChar** rname_end, ScanEnv* env,
+ int* rback_num, int* rlevel)
{
int r, sign, is_num, exist_level;
OnigCodePoint end_code;
@@ -2701,11 +2701,11 @@ fetch_name_with_level(OnigCodePoint start_code, UChar** src, UChar* end,
if (is_num != 0) {
if (ONIGENC_IS_CODE_DIGIT(enc, c)) {
- is_num = 1;
+ is_num = 1;
}
else {
- r = ONIGERR_INVALID_GROUP_NAME;
- is_num = 0;
+ r = ONIGERR_INVALID_GROUP_NAME;
+ is_num = 0;
}
}
else if (!ONIGENC_IS_CODE_NAME(enc, c)) {
@@ -2719,8 +2719,8 @@ fetch_name_with_level(OnigCodePoint start_code, UChar** src, UChar* end,
int flag = (c == '-' ? -1 : 1);
if (PEND) {
- r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
- goto end;
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ goto end;
}
PFETCH(c);
if (! ONIGENC_IS_CODE_DIGIT(enc, c)) goto err;
@@ -2731,9 +2731,9 @@ fetch_name_with_level(OnigCodePoint start_code, UChar** src, UChar* end,
exist_level = 1;
if (!PEND) {
- PFETCH(c);
- if (c == end_code)
- goto end;
+ PFETCH(c);
+ if (c == end_code)
+ goto end;
}
}
@@ -2769,7 +2769,7 @@ fetch_name_with_level(OnigCodePoint start_code, UChar** src, UChar* end,
*/
static int
fetch_name(OnigCodePoint start_code, UChar** src, UChar* end,
- UChar** rname_end, ScanEnv* env, int* rback_num, int ref)
+ UChar** rname_end, ScanEnv* env, int* rback_num, int ref)
{
int r, is_num, sign;
OnigCodePoint end_code;
@@ -2798,21 +2798,21 @@ fetch_name(OnigCodePoint start_code, UChar** src, UChar* end,
if (ONIGENC_IS_CODE_DIGIT(enc, c)) {
if (ref == 1)
- is_num = 1;
+ is_num = 1;
else {
- r = ONIGERR_INVALID_GROUP_NAME;
- is_num = 0;
+ r = ONIGERR_INVALID_GROUP_NAME;
+ is_num = 0;
}
}
else if (c == '-') {
if (ref == 1) {
- is_num = 2;
- sign = -1;
- pnum_head = p;
+ is_num = 2;
+ sign = -1;
+ pnum_head = p;
}
else {
- r = ONIGERR_INVALID_GROUP_NAME;
- is_num = 0;
+ r = ONIGERR_INVALID_GROUP_NAME;
+ is_num = 0;
}
}
else if (!ONIGENC_IS_CODE_NAME(enc, c)) {
@@ -2825,30 +2825,30 @@ fetch_name(OnigCodePoint start_code, UChar** src, UChar* end,
name_end = p;
PFETCH_S(c);
if (c == end_code || c == ')') {
- if (is_num == 2) {
- r = ONIGERR_INVALID_GROUP_NAME;
- goto teardown;
- }
- break;
+ if (is_num == 2) {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ goto teardown;
+ }
+ break;
}
if (is_num != 0) {
- if (ONIGENC_IS_CODE_DIGIT(enc, c)) {
- is_num = 1;
- }
- else {
- if (!ONIGENC_IS_CODE_WORD(enc, c))
- r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
- else
- r = ONIGERR_INVALID_GROUP_NAME;
- goto teardown;
- }
+ if (ONIGENC_IS_CODE_DIGIT(enc, c)) {
+ is_num = 1;
+ }
+ else {
+ if (!ONIGENC_IS_CODE_WORD(enc, c))
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ else
+ r = ONIGERR_INVALID_GROUP_NAME;
+ goto teardown;
+ }
}
else {
- if (!ONIGENC_IS_CODE_NAME(enc, c)) {
- r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
- goto teardown;
- }
+ if (!ONIGENC_IS_CODE_NAME(enc, c)) {
+ r = ONIGERR_INVALID_CHAR_IN_GROUP_NAME;
+ goto teardown;
+ }
}
}
@@ -2862,8 +2862,8 @@ fetch_name(OnigCodePoint start_code, UChar** src, UChar* end,
*rback_num = onig_scan_unsigned_number(&pnum_head, name_end, enc);
if (*rback_num < 0) return ONIGERR_TOO_BIG_NUMBER;
else if (*rback_num == 0) {
- r = ONIGERR_INVALID_GROUP_NAME;
- goto err;
+ r = ONIGERR_INVALID_GROUP_NAME;
+ goto err;
}
*rback_num *= sign;
@@ -2879,7 +2879,7 @@ teardown:
name_end = p;
PFETCH_S(c);
if (c == end_code || c == ')')
- break;
+ break;
}
if (PEND)
name_end = end;
@@ -2892,7 +2892,7 @@ teardown:
#else
static int
fetch_name(OnigCodePoint start_code, UChar** src, UChar* end,
- UChar** rname_end, ScanEnv* env, int* rback_num, int ref)
+ UChar** rname_end, ScanEnv* env, int* rback_num, int ref)
{
int r, is_num, sign;
OnigCodePoint end_code;
@@ -2980,8 +2980,8 @@ onig_syntax_warn(ScanEnv *env, const char *fmt, ...)
UChar buf[WARN_BUFSIZE];
va_start(args, fmt);
onig_vsnprintf_with_pattern(buf, WARN_BUFSIZE, env->enc,
- env->pattern, env->pattern_end,
- fmt, args);
+ env->pattern, env->pattern_end,
+ fmt, args);
va_end(args);
#ifdef RUBY
if (env->sourcefile == NULL)
@@ -3043,7 +3043,7 @@ UNKNOWN_ESC_WARN(ScanEnv *env, int c)
static UChar*
find_str_position(OnigCodePoint s[], int n, UChar* from, UChar* to,
- UChar **next, OnigEncoding enc)
+ UChar **next, OnigEncoding enc)
{
int i;
OnigCodePoint x;
@@ -3055,14 +3055,14 @@ find_str_position(OnigCodePoint s[], int n, UChar* from, UChar* to,
q = p + enclen(enc, p, to);
if (x == s[0]) {
for (i = 1; i < n && q < to; i++) {
- x = ONIGENC_MBC_TO_CODE(enc, q, to);
- if (x != s[i]) break;
- q += enclen(enc, q, to);
+ x = ONIGENC_MBC_TO_CODE(enc, q, to);
+ if (x != s[i]) break;
+ q += enclen(enc, q, to);
}
if (i >= n) {
- if (IS_NOT_NULL(next))
- *next = q;
- return p;
+ if (IS_NOT_NULL(next))
+ *next = q;
+ return p;
}
}
p = q;
@@ -3072,7 +3072,7 @@ find_str_position(OnigCodePoint s[], int n, UChar* from, UChar* to,
static int
str_exist_check_with_esc(OnigCodePoint s[], int n, UChar* from, UChar* to,
- OnigCodePoint bad, OnigEncoding enc, const OnigSyntaxType* syn)
+ OnigCodePoint bad, OnigEncoding enc, const OnigSyntaxType* syn)
{
int i, in_esc;
OnigCodePoint x;
@@ -3089,19 +3089,19 @@ str_exist_check_with_esc(OnigCodePoint s[], int n, UChar* from, UChar* to,
x = ONIGENC_MBC_TO_CODE(enc, p, to);
q = p + enclen(enc, p, to);
if (x == s[0]) {
- for (i = 1; i < n && q < to; i++) {
- x = ONIGENC_MBC_TO_CODE(enc, q, to);
- if (x != s[i]) break;
- q += enclen(enc, q, to);
- }
- if (i >= n) return 1;
- p += enclen(enc, p, to);
+ for (i = 1; i < n && q < to; i++) {
+ x = ONIGENC_MBC_TO_CODE(enc, q, to);
+ if (x != s[i]) break;
+ q += enclen(enc, q, to);
+ }
+ if (i >= n) return 1;
+ p += enclen(enc, p, to);
}
else {
- x = ONIGENC_MBC_TO_CODE(enc, p, to);
- if (x == bad) return 0;
- else if (x == MC_ESC(syn)) in_esc = 1;
- p = q;
+ x = ONIGENC_MBC_TO_CODE(enc, p, to);
+ if (x == bad) return 0;
+ else if (x == MC_ESC(syn)) in_esc = 1;
+ p = q;
}
}
}
@@ -3195,22 +3195,22 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
c2 = PPEEK;
if (c2 == '{' &&
- IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY)) {
- PINC;
- tok->type = TK_CHAR_PROPERTY;
- tok->u.prop.not = (c == 'P' ? 1 : 0);
-
- if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT)) {
- PFETCH(c2);
- if (c2 == '^') {
- tok->u.prop.not = (tok->u.prop.not == 0 ? 1 : 0);
- }
- else
- PUNFETCH;
- }
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY)) {
+ PINC;
+ tok->type = TK_CHAR_PROPERTY;
+ tok->u.prop.not = (c == 'P' ? 1 : 0);
+
+ if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT)) {
+ PFETCH(c2);
+ if (c2 == '^') {
+ tok->u.prop.not = (tok->u.prop.not == 0 ? 1 : 0);
+ }
+ else
+ PUNFETCH;
+ }
}
else {
- onig_syntax_warn(env, "invalid Unicode Property \\%c", c);
+ onig_syntax_warn(env, "invalid Unicode Property \\%c", c);
}
break;
@@ -3219,35 +3219,35 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_BRACE_HEX8)) {
- PINC;
- num = scan_unsigned_hexadecimal_number(&p, end, 0, 8, enc);
- if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
- if (!PEND) {
- c2 = PPEEK;
- if (ONIGENC_IS_CODE_XDIGIT(enc, c2))
- return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
- }
-
- if (p > prev + enclen(enc, prev, end) && !PEND && (PPEEK_IS('}'))) {
- PINC;
- tok->type = TK_CODE_POINT;
- tok->base = 16;
- tok->u.code = (OnigCodePoint )num;
- }
- else {
- /* can't read nothing or invalid format */
- p = prev;
- }
+ PINC;
+ num = scan_unsigned_hexadecimal_number(&p, end, 0, 8, enc);
+ if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
+ if (!PEND) {
+ c2 = PPEEK;
+ if (ONIGENC_IS_CODE_XDIGIT(enc, c2))
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if (p > prev + enclen(enc, prev, end) && !PEND && (PPEEK_IS('}'))) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->base = 16;
+ tok->u.code = (OnigCodePoint )num;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
}
else if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_HEX2)) {
- num = scan_unsigned_hexadecimal_number(&p, end, 0, 2, enc);
- if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
- if (p == prev) { /* can't read nothing. */
- num = 0; /* but, it's not error */
- }
- tok->type = TK_RAW_BYTE;
- tok->base = 16;
- tok->u.c = num;
+ num = scan_unsigned_hexadecimal_number(&p, end, 0, 2, enc);
+ if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ num = 0; /* but, it's not error */
+ }
+ tok->type = TK_RAW_BYTE;
+ tok->base = 16;
+ tok->u.c = num;
}
break;
@@ -3256,15 +3256,15 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_U_HEX4)) {
- num = scan_unsigned_hexadecimal_number(&p, end, 4, 4, enc);
- if (num < -1) return ONIGERR_TOO_SHORT_DIGITS;
- else if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
- if (p == prev) { /* can't read nothing. */
- num = 0; /* but, it's not error */
- }
- tok->type = TK_CODE_POINT;
- tok->base = 16;
- tok->u.code = (OnigCodePoint )num;
+ num = scan_unsigned_hexadecimal_number(&p, end, 4, 4, enc);
+ if (num < -1) return ONIGERR_TOO_SHORT_DIGITS;
+ else if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ num = 0; /* but, it's not error */
+ }
+ tok->type = TK_CODE_POINT;
+ tok->base = 16;
+ tok->u.code = (OnigCodePoint )num;
}
break;
@@ -3273,41 +3273,41 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_O_BRACE_OCTAL)) {
- PINC;
- num = scan_unsigned_octal_number(&p, end, 11, enc);
- if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
- if (!PEND) {
- c2 = PPEEK;
- if (ONIGENC_IS_CODE_DIGIT(enc, c2) && c2 < '8')
- return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
- }
-
- if (p > prev + enclen(enc, prev, end) && !PEND && (PPEEK_IS('}'))) {
- PINC;
- tok->type = TK_CODE_POINT;
- tok->base = 8;
- tok->u.code = (OnigCodePoint )num;
- }
- else {
- /* can't read nothing or invalid format */
- p = prev;
- }
+ PINC;
+ num = scan_unsigned_octal_number(&p, end, 11, enc);
+ if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
+ if (!PEND) {
+ c2 = PPEEK;
+ if (ONIGENC_IS_CODE_DIGIT(enc, c2) && c2 < '8')
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if (p > prev + enclen(enc, prev, end) && !PEND && (PPEEK_IS('}'))) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->base = 8;
+ tok->u.code = (OnigCodePoint )num;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
}
break;
case '0':
case '1': case '2': case '3': case '4': case '5': case '6': case '7':
if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_OCTAL3)) {
- PUNFETCH;
- prev = p;
- num = scan_unsigned_octal_number(&p, end, 3, enc);
- if (num < 0 || 0xff < num) return ONIGERR_TOO_BIG_NUMBER;
- if (p == prev) { /* can't read nothing. */
- num = 0; /* but, it's not error */
- }
- tok->type = TK_RAW_BYTE;
- tok->base = 8;
- tok->u.c = num;
+ PUNFETCH;
+ prev = p;
+ num = scan_unsigned_octal_number(&p, end, 3, enc);
+ if (num < 0 || 0xff < num) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ num = 0; /* but, it's not error */
+ }
+ tok->type = TK_RAW_BYTE;
+ tok->base = 8;
+ tok->u.c = num;
}
break;
@@ -3316,8 +3316,8 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
num = fetch_escaped_value(&p, end, env, &c2);
if (num < 0) return num;
if ((OnigCodePoint )tok->u.c != c2) {
- tok->u.code = (OnigCodePoint )c2;
- tok->type = TK_CODE_POINT;
+ tok->u.code = (OnigCodePoint )c2;
+ tok->type = TK_CODE_POINT;
}
break;
}
@@ -3329,26 +3329,26 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
PINC;
if (str_exist_check_with_esc(send, 2, p, end,
(OnigCodePoint )']', enc, syn)) {
- tok->type = TK_POSIX_BRACKET_OPEN;
+ tok->type = TK_POSIX_BRACKET_OPEN;
}
else {
- PUNFETCH;
- goto cc_in_cc;
+ PUNFETCH;
+ goto cc_in_cc;
}
}
else {
cc_in_cc:
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_CCLASS_SET_OP)) {
- tok->type = TK_CC_CC_OPEN;
+ tok->type = TK_CC_CC_OPEN;
}
else {
- CC_ESC_WARN(env, (UChar* )"[");
+ CC_ESC_WARN(env, (UChar* )"[");
}
}
}
else if (c == '&') {
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_CCLASS_SET_OP) &&
- !PEND && (PPEEK_IS('&'))) {
+ !PEND && (PPEEK_IS('&'))) {
PINC;
tok->type = TK_CC_AND;
}
@@ -3362,7 +3362,7 @@ fetch_token_in_cc(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
#ifdef USE_NAMED_GROUP
static int
fetch_named_backref_token(OnigCodePoint c, OnigToken* tok, UChar** src,
- UChar* end, ScanEnv* env)
+ UChar* end, ScanEnv* env)
{
int r, num;
const OnigSyntaxType* syn = env->syntax;
@@ -3377,7 +3377,7 @@ fetch_named_backref_token(OnigCodePoint c, OnigToken* tok, UChar** src,
# ifdef USE_BACKREF_WITH_LEVEL
name_end = NULL_UCHARP; /* no need. escape gcc warning. */
r = fetch_name_with_level(c, &p, end, &name_end,
- env, &back_num, &tok->u.backref.level);
+ env, &back_num, &tok->u.backref.level);
if (r == 1) tok->u.backref.exist_level = 1;
else tok->u.backref.exist_level = 0;
# else
@@ -3389,13 +3389,13 @@ fetch_named_backref_token(OnigCodePoint c, OnigToken* tok, UChar** src,
if (back_num < 0) {
back_num = BACKREF_REL_TO_ABS(back_num, env);
if (back_num <= 0)
- return ONIGERR_INVALID_BACKREF;
+ return ONIGERR_INVALID_BACKREF;
}
if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
if (back_num > env->num_mem ||
- IS_NULL(SCANENV_MEM_NODES(env)[back_num]))
- return ONIGERR_INVALID_BACKREF;
+ IS_NULL(SCANENV_MEM_NODES(env)[back_num]))
+ return ONIGERR_INVALID_BACKREF;
}
tok->type = TK_BACKREF;
tok->u.backref.by_name = 0;
@@ -3406,15 +3406,15 @@ fetch_named_backref_token(OnigCodePoint c, OnigToken* tok, UChar** src,
num = onig_name_to_group_numbers(env->reg, prev, name_end, &backs);
if (num <= 0) {
onig_scan_env_set_error_string(env,
- ONIGERR_UNDEFINED_NAME_REFERENCE, prev, name_end);
+ ONIGERR_UNDEFINED_NAME_REFERENCE, prev, name_end);
return ONIGERR_UNDEFINED_NAME_REFERENCE;
}
if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
int i;
for (i = 0; i < num; i++) {
- if (backs[i] > env->num_mem ||
- IS_NULL(SCANENV_MEM_NODES(env)[backs[i]]))
- return ONIGERR_INVALID_BACKREF;
+ if (backs[i] > env->num_mem ||
+ IS_NULL(SCANENV_MEM_NODES(env)[backs[i]]))
+ return ONIGERR_INVALID_BACKREF;
}
}
@@ -3488,26 +3488,26 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
tok->u.repeat.upper = 1;
greedy_check:
if (!PEND && PPEEK_IS('?') &&
- IS_SYNTAX_OP(syn, ONIG_SYN_OP_QMARK_NON_GREEDY)) {
- PFETCH(c);
- tok->u.repeat.greedy = 0;
- tok->u.repeat.possessive = 0;
+ IS_SYNTAX_OP(syn, ONIG_SYN_OP_QMARK_NON_GREEDY)) {
+ PFETCH(c);
+ tok->u.repeat.greedy = 0;
+ tok->u.repeat.possessive = 0;
}
else {
possessive_check:
- if (!PEND && PPEEK_IS('+') &&
- ((IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT) &&
- tok->type != TK_INTERVAL) ||
- (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL) &&
- tok->type == TK_INTERVAL))) {
- PFETCH(c);
- tok->u.repeat.greedy = 1;
- tok->u.repeat.possessive = 1;
- }
- else {
- tok->u.repeat.greedy = 1;
- tok->u.repeat.possessive = 0;
- }
+ if (!PEND && PPEEK_IS('+') &&
+ ((IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_PLUS_POSSESSIVE_REPEAT) &&
+ tok->type != TK_INTERVAL) ||
+ (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_PLUS_POSSESSIVE_INTERVAL) &&
+ tok->type == TK_INTERVAL))) {
+ PFETCH(c);
+ tok->u.repeat.greedy = 1;
+ tok->u.repeat.possessive = 1;
+ }
+ else {
+ tok->u.repeat.greedy = 1;
+ tok->u.repeat.possessive = 0;
+ }
}
break;
@@ -3517,10 +3517,10 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
if (r < 0) return r; /* error */
if (r == 0) goto greedy_check;
else if (r == 2) { /* {n} */
- if (IS_SYNTAX_BV(syn, ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY))
- goto possessive_check;
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY))
+ goto possessive_check;
- goto greedy_check;
+ goto greedy_check;
}
/* r == 1 : normal char */
break;
@@ -3559,7 +3559,7 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
tok->type = TK_ANCHOR;
tok->u.anchor.subtype = ANCHOR_WORD_BOUND;
tok->u.anchor.ascii_range = IS_ASCII_RANGE(env->option)
- && ! IS_WORD_BOUND_ALL_RANGE(env->option);
+ && ! IS_WORD_BOUND_ALL_RANGE(env->option);
break;
case 'B':
@@ -3567,7 +3567,7 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
tok->type = TK_ANCHOR;
tok->u.anchor.subtype = ANCHOR_NOT_WORD_BOUND;
tok->u.anchor.ascii_range = IS_ASCII_RANGE(env->option)
- && ! IS_WORD_BOUND_ALL_RANGE(env->option);
+ && ! IS_WORD_BOUND_ALL_RANGE(env->option);
break;
#ifdef USE_WORD_BEGIN_END
@@ -3669,33 +3669,33 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_BRACE_HEX8)) {
- PINC;
- num = scan_unsigned_hexadecimal_number(&p, end, 0, 8, enc);
- if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
- if (!PEND) {
- if (ONIGENC_IS_CODE_XDIGIT(enc, PPEEK))
- return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
- }
-
- if ((p > prev + enclen(enc, prev, end)) && !PEND && PPEEK_IS('}')) {
- PINC;
- tok->type = TK_CODE_POINT;
- tok->u.code = (OnigCodePoint )num;
- }
- else {
- /* can't read nothing or invalid format */
- p = prev;
- }
+ PINC;
+ num = scan_unsigned_hexadecimal_number(&p, end, 0, 8, enc);
+ if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
+ if (!PEND) {
+ if (ONIGENC_IS_CODE_XDIGIT(enc, PPEEK))
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if ((p > prev + enclen(enc, prev, end)) && !PEND && PPEEK_IS('}')) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->u.code = (OnigCodePoint )num;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
}
else if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_X_HEX2)) {
- num = scan_unsigned_hexadecimal_number(&p, end, 0, 2, enc);
- if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
- if (p == prev) { /* can't read nothing. */
- num = 0; /* but, it's not error */
- }
- tok->type = TK_RAW_BYTE;
- tok->base = 16;
- tok->u.c = num;
+ num = scan_unsigned_hexadecimal_number(&p, end, 0, 2, enc);
+ if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ num = 0; /* but, it's not error */
+ }
+ tok->type = TK_RAW_BYTE;
+ tok->base = 16;
+ tok->u.c = num;
}
break;
@@ -3704,15 +3704,15 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_U_HEX4)) {
- num = scan_unsigned_hexadecimal_number(&p, end, 4, 4, enc);
- if (num < -1) return ONIGERR_TOO_SHORT_DIGITS;
- else if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
- if (p == prev) { /* can't read nothing. */
- num = 0; /* but, it's not error */
- }
- tok->type = TK_CODE_POINT;
- tok->base = 16;
- tok->u.code = (OnigCodePoint )num;
+ num = scan_unsigned_hexadecimal_number(&p, end, 4, 4, enc);
+ if (num < -1) return ONIGERR_TOO_SHORT_DIGITS;
+ else if (num < 0) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ num = 0; /* but, it's not error */
+ }
+ tok->type = TK_CODE_POINT;
+ tok->base = 16;
+ tok->u.code = (OnigCodePoint )num;
}
break;
@@ -3721,24 +3721,24 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
if (PPEEK_IS('{') && IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_O_BRACE_OCTAL)) {
- PINC;
- num = scan_unsigned_octal_number(&p, end, 11, enc);
- if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
- if (!PEND) {
- OnigCodePoint c = PPEEK;
- if (ONIGENC_IS_CODE_DIGIT(enc, c) && c < '8')
- return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
- }
-
- if ((p > prev + enclen(enc, prev, end)) && !PEND && PPEEK_IS('}')) {
- PINC;
- tok->type = TK_CODE_POINT;
- tok->u.code = (OnigCodePoint )num;
- }
- else {
- /* can't read nothing or invalid format */
- p = prev;
- }
+ PINC;
+ num = scan_unsigned_octal_number(&p, end, 11, enc);
+ if (num < 0) return ONIGERR_TOO_BIG_WIDE_CHAR_VALUE;
+ if (!PEND) {
+ OnigCodePoint c = PPEEK;
+ if (ONIGENC_IS_CODE_DIGIT(enc, c) && c < '8')
+ return ONIGERR_TOO_LONG_WIDE_CHAR_VALUE;
+ }
+
+ if ((p > prev + enclen(enc, prev, end)) && !PEND && PPEEK_IS('}')) {
+ PINC;
+ tok->type = TK_CODE_POINT;
+ tok->u.code = (OnigCodePoint )num;
+ }
+ else {
+ /* can't read nothing or invalid format */
+ p = prev;
+ }
}
break;
@@ -3748,64 +3748,64 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
prev = p;
num = onig_scan_unsigned_number(&p, end, enc);
if (num < 0 || num > ONIG_MAX_BACKREF_NUM) {
- goto skip_backref;
+ goto skip_backref;
}
if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_DECIMAL_BACKREF) &&
- (num <= env->num_mem || num <= 9)) { /* This spec. from GNU regex */
- if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
- if (num > env->num_mem || IS_NULL(SCANENV_MEM_NODES(env)[num]))
- return ONIGERR_INVALID_BACKREF;
- }
-
- tok->type = TK_BACKREF;
- tok->u.backref.num = 1;
- tok->u.backref.ref1 = num;
- tok->u.backref.by_name = 0;
+ (num <= env->num_mem || num <= 9)) { /* This spec. from GNU regex */
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ if (num > env->num_mem || IS_NULL(SCANENV_MEM_NODES(env)[num]))
+ return ONIGERR_INVALID_BACKREF;
+ }
+
+ tok->type = TK_BACKREF;
+ tok->u.backref.num = 1;
+ tok->u.backref.ref1 = num;
+ tok->u.backref.by_name = 0;
#ifdef USE_BACKREF_WITH_LEVEL
- tok->u.backref.exist_level = 0;
+ tok->u.backref.exist_level = 0;
#endif
- break;
+ break;
}
skip_backref:
if (c == '8' || c == '9') {
- /* normal char */
- p = prev; PINC;
- break;
+ /* normal char */
+ p = prev; PINC;
+ break;
}
p = prev;
/* fall through */
case '0':
if (IS_SYNTAX_OP(syn, ONIG_SYN_OP_ESC_OCTAL3)) {
- prev = p;
- num = scan_unsigned_octal_number(&p, end, (c == '0' ? 2:3), enc);
- if (num < 0 || 0xff < num) return ONIGERR_TOO_BIG_NUMBER;
- if (p == prev) { /* can't read nothing. */
- num = 0; /* but, it's not error */
- }
- tok->type = TK_RAW_BYTE;
- tok->base = 8;
- tok->u.c = num;
+ prev = p;
+ num = scan_unsigned_octal_number(&p, end, (c == '0' ? 2:3), enc);
+ if (num < 0 || 0xff < num) return ONIGERR_TOO_BIG_NUMBER;
+ if (p == prev) { /* can't read nothing. */
+ num = 0; /* but, it's not error */
+ }
+ tok->type = TK_RAW_BYTE;
+ tok->base = 8;
+ tok->u.c = num;
}
else if (c != '0') {
- PINC;
+ PINC;
}
break;
#ifdef USE_NAMED_GROUP
case 'k':
if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_K_NAMED_BACKREF)) {
- PFETCH(c);
- if (c == '<' || c == '\'') {
- r = fetch_named_backref_token(c, tok, &p, end, env);
- if (r < 0) return r;
- }
- else {
- PUNFETCH;
- onig_syntax_warn(env, "invalid back reference");
- }
+ PFETCH(c);
+ if (c == '<' || c == '\'') {
+ r = fetch_named_backref_token(c, tok, &p, end, env);
+ if (r < 0) return r;
+ }
+ else {
+ PUNFETCH;
+ onig_syntax_warn(env, "invalid back reference");
+ }
}
break;
#endif
@@ -3814,52 +3814,52 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
case 'g':
# ifdef USE_NAMED_GROUP
if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_G_BRACE_BACKREF)) {
- PFETCH(c);
- if (c == '{') {
- r = fetch_named_backref_token(c, tok, &p, end, env);
- if (r < 0) return r;
- }
- else
- PUNFETCH;
+ PFETCH(c);
+ if (c == '{') {
+ r = fetch_named_backref_token(c, tok, &p, end, env);
+ if (r < 0) return r;
+ }
+ else
+ PUNFETCH;
}
# endif
# ifdef USE_SUBEXP_CALL
if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_G_SUBEXP_CALL)) {
- PFETCH(c);
- if (c == '<' || c == '\'') {
- int gnum = -1, rel = 0;
- UChar* name_end;
- OnigCodePoint cnext;
-
- cnext = PPEEK;
- if (cnext == '0') {
- PINC;
- if (PPEEK_IS(get_name_end_code_point(c))) { /* \g<0>, \g'0' */
- PINC;
- name_end = p;
- gnum = 0;
- }
- }
- else if (cnext == '+') {
- PINC;
- rel = 1;
- }
- prev = p;
- if (gnum < 0) {
- r = fetch_name((OnigCodePoint )c, &p, end, &name_end, env, &gnum, 1);
- if (r < 0) return r;
- }
-
- tok->type = TK_CALL;
- tok->u.call.name = prev;
- tok->u.call.name_end = name_end;
- tok->u.call.gnum = gnum;
- tok->u.call.rel = rel;
- }
- else {
- onig_syntax_warn(env, "invalid subexp call");
- PUNFETCH;
- }
+ PFETCH(c);
+ if (c == '<' || c == '\'') {
+ int gnum = -1, rel = 0;
+ UChar* name_end;
+ OnigCodePoint cnext;
+
+ cnext = PPEEK;
+ if (cnext == '0') {
+ PINC;
+ if (PPEEK_IS(get_name_end_code_point(c))) { /* \g<0>, \g'0' */
+ PINC;
+ name_end = p;
+ gnum = 0;
+ }
+ }
+ else if (cnext == '+') {
+ PINC;
+ rel = 1;
+ }
+ prev = p;
+ if (gnum < 0) {
+ r = fetch_name((OnigCodePoint )c, &p, end, &name_end, env, &gnum, 1);
+ if (r < 0) return r;
+ }
+
+ tok->type = TK_CALL;
+ tok->u.call.name = prev;
+ tok->u.call.name_end = name_end;
+ tok->u.call.gnum = gnum;
+ tok->u.call.rel = rel;
+ }
+ else {
+ onig_syntax_warn(env, "invalid subexp call");
+ PUNFETCH;
+ }
}
# endif
break;
@@ -3867,65 +3867,65 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
case 'Q':
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_Q_QUOTE)) {
- tok->type = TK_QUOTE_OPEN;
+ tok->type = TK_QUOTE_OPEN;
}
break;
case 'p':
case 'P':
if (PPEEK_IS('{') &&
- IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY)) {
- PINC;
- tok->type = TK_CHAR_PROPERTY;
- tok->u.prop.not = (c == 'P' ? 1 : 0);
-
- if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT)) {
- PFETCH(c);
- if (c == '^') {
- tok->u.prop.not = (tok->u.prop.not == 0 ? 1 : 0);
- }
- else
- PUNFETCH;
- }
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CHAR_PROPERTY)) {
+ PINC;
+ tok->type = TK_CHAR_PROPERTY;
+ tok->u.prop.not = (c == 'P' ? 1 : 0);
+
+ if (!PEND && IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_P_BRACE_CIRCUMFLEX_NOT)) {
+ PFETCH(c);
+ if (c == '^') {
+ tok->u.prop.not = (tok->u.prop.not == 0 ? 1 : 0);
+ }
+ else
+ PUNFETCH;
+ }
}
else {
- onig_syntax_warn(env, "invalid Unicode Property \\%c", c);
+ onig_syntax_warn(env, "invalid Unicode Property \\%c", c);
}
break;
case 'R':
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_R_LINEBREAK)) {
- tok->type = TK_LINEBREAK;
+ tok->type = TK_LINEBREAK;
}
break;
case 'X':
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_X_EXTENDED_GRAPHEME_CLUSTER)) {
- tok->type = TK_EXTENDED_GRAPHEME_CLUSTER;
+ tok->type = TK_EXTENDED_GRAPHEME_CLUSTER;
}
break;
case 'K':
if (IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_ESC_CAPITAL_K_KEEP)) {
- tok->type = TK_KEEP;
+ tok->type = TK_KEEP;
}
break;
default:
{
- OnigCodePoint c2;
-
- PUNFETCH;
- num = fetch_escaped_value(&p, end, env, &c2);
- if (num < 0) return num;
- /* set_raw: */
- if ((OnigCodePoint )tok->u.c != c2) {
- tok->type = TK_CODE_POINT;
- tok->u.code = (OnigCodePoint )c2;
- }
- else { /* string */
- p = tok->backp + enclen(enc, tok->backp, end);
- }
+ OnigCodePoint c2;
+
+ PUNFETCH;
+ num = fetch_escaped_value(&p, end, env, &c2);
+ if (num < 0) return num;
+ /* set_raw: */
+ if ((OnigCodePoint )tok->u.c != c2) {
+ tok->type = TK_CODE_POINT;
+ tok->u.code = (OnigCodePoint )c2;
+ }
+ else { /* string */
+ p = tok->backp + enclen(enc, tok->backp, end);
+ }
}
break;
}
@@ -3936,18 +3936,18 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
#ifdef USE_VARIABLE_META_CHARS
if ((c != ONIG_INEFFECTIVE_META_CHAR) &&
- IS_SYNTAX_OP(syn, ONIG_SYN_OP_VARIABLE_META_CHARACTERS)) {
+ IS_SYNTAX_OP(syn, ONIG_SYN_OP_VARIABLE_META_CHARACTERS)) {
if (c == MC_ANYCHAR(syn))
- goto any_char;
+ goto any_char;
else if (c == MC_ANYTIME(syn))
- goto anytime;
+ goto anytime;
else if (c == MC_ZERO_OR_ONE_TIME(syn))
- goto zero_or_one_time;
+ goto zero_or_one_time;
else if (c == MC_ONE_OR_MORE_TIME(syn))
- goto one_or_more_time;
+ goto one_or_more_time;
else if (c == MC_ANYCHAR_ANYTIME(syn)) {
- tok->type = TK_ANYCHAR_ANYTIME;
- goto out;
+ tok->type = TK_ANYCHAR_ANYTIME;
+ goto out;
}
}
#endif
@@ -4000,10 +4000,10 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
if (r < 0) return r; /* error */
if (r == 0) goto greedy_check;
else if (r == 2) { /* {n} */
- if (IS_SYNTAX_BV(syn, ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY))
- goto possessive_check;
+ if (IS_SYNTAX_BV(syn, ONIG_SYN_FIXED_INTERVAL_IS_GREEDY_ONLY))
+ goto possessive_check;
- goto greedy_check;
+ goto greedy_check;
}
/* r == 1 : normal char */
break;
@@ -4015,114 +4015,118 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
case '(':
if (PPEEK_IS('?') &&
- IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_QMARK_GROUP_EFFECT)) {
- PINC;
- if (PPEEK_IS('#')) {
- PFETCH(c);
- while (1) {
- if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
- PFETCH(c);
- if (c == MC_ESC(syn)) {
- if (!PEND) PFETCH(c);
- }
- else {
- if (c == ')') break;
- }
- }
- goto start;
- }
+ IS_SYNTAX_OP2(syn, ONIG_SYN_OP2_QMARK_GROUP_EFFECT)) {
+ PINC;
+ if (PPEEK_IS('#')) {
+ PFETCH(c);
+ while (1) {
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ if (c == MC_ESC(syn)) {
+ if (!PEND) PFETCH(c);
+ }
+ else {
+ if (c == ')') break;
+ }
+ }
+ goto start;
+ }
#ifdef USE_PERL_SUBEXP_CALL
- /* (?&name), (?n), (?R), (?0), (?+n), (?-n) */
- c = PPEEK;
- if ((c == '&' || c == 'R' || ONIGENC_IS_CODE_DIGIT(enc, c)) &&
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_SUBEXP_CALL)) {
- /* (?&name), (?n), (?R), (?0) */
- int gnum;
- UChar *name;
- UChar *name_end;
-
- if (c == 'R' || c == '0') {
- PINC; /* skip 'R' / '0' */
- if (!PPEEK_IS(')')) return ONIGERR_INVALID_GROUP_NAME;
- PINC; /* skip ')' */
- name_end = name = p;
- gnum = 0;
- }
- else {
- int numref = 1;
- if (c == '&') { /* (?&name) */
- PINC;
- numref = 0; /* don't allow number name */
- }
- name = p;
- r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &gnum, numref);
- if (r < 0) return r;
- }
-
- tok->type = TK_CALL;
- tok->u.call.name = name;
- tok->u.call.name_end = name_end;
- tok->u.call.gnum = gnum;
- tok->u.call.rel = 0;
- break;
- }
- else if ((c == '-' || c == '+') &&
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_SUBEXP_CALL)) {
- /* (?+n), (?-n) */
- int gnum;
- UChar *name;
- UChar *name_end;
- OnigCodePoint cnext;
- PFETCH_READY;
-
- PINC; /* skip '-' / '+' */
- cnext = PPEEK;
- if (ONIGENC_IS_CODE_DIGIT(enc, cnext)) {
- if (c == '-') PUNFETCH;
- name = p;
- r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &gnum, 1);
- if (r < 0) return r;
-
- tok->type = TK_CALL;
- tok->u.call.name = name;
- tok->u.call.name_end = name_end;
- tok->u.call.gnum = gnum;
- tok->u.call.rel = 1;
- break;
- }
- }
+ /* (?&name), (?n), (?R), (?0), (?+n), (?-n) */
+ c = PPEEK;
+ if ((c == '&' || c == 'R' || ONIGENC_IS_CODE_DIGIT(enc, c)) &&
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_SUBEXP_CALL)) {
+ /* (?&name), (?n), (?R), (?0) */
+ int gnum;
+ UChar *name;
+ UChar *name_end;
+
+ if (c == 'R' || c == '0') {
+ PINC; /* skip 'R' / '0' */
+ if (!PPEEK_IS(')')) {
+ r = ONIGERR_INVALID_GROUP_NAME;
+ onig_scan_env_set_error_string(env, r, p - 1, p + 1);
+ return r;
+ }
+ PINC; /* skip ')' */
+ name_end = name = p;
+ gnum = 0;
+ }
+ else {
+ int numref = 1;
+ if (c == '&') { /* (?&name) */
+ PINC;
+ numref = 0; /* don't allow number name */
+ }
+ name = p;
+ r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &gnum, numref);
+ if (r < 0) return r;
+ }
+
+ tok->type = TK_CALL;
+ tok->u.call.name = name;
+ tok->u.call.name_end = name_end;
+ tok->u.call.gnum = gnum;
+ tok->u.call.rel = 0;
+ break;
+ }
+ else if ((c == '-' || c == '+') &&
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_SUBEXP_CALL)) {
+ /* (?+n), (?-n) */
+ int gnum;
+ UChar *name;
+ UChar *name_end;
+ OnigCodePoint cnext;
+ PFETCH_READY;
+
+ PINC; /* skip '-' / '+' */
+ cnext = PPEEK;
+ if (ONIGENC_IS_CODE_DIGIT(enc, cnext)) {
+ if (c == '-') PUNFETCH;
+ name = p;
+ r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &gnum, 1);
+ if (r < 0) return r;
+
+ tok->type = TK_CALL;
+ tok->u.call.name = name;
+ tok->u.call.name_end = name_end;
+ tok->u.call.gnum = gnum;
+ tok->u.call.rel = 1;
+ break;
+ }
+ }
#endif /* USE_PERL_SUBEXP_CALL */
#ifdef USE_CAPITAL_P_NAMED_GROUP
- if (PPEEK_IS('P') &&
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_CAPITAL_P_NAMED_GROUP)) {
- int gnum;
- UChar *name;
- UChar *name_end;
- PFETCH_READY;
-
- PINC; /* skip 'P' */
- if (PEND) return ONIGERR_UNDEFINED_GROUP_OPTION;
- PFETCH(c);
- if (c == '=') { /* (?P=name): backref */
- r = fetch_named_backref_token((OnigCodePoint )'(', tok, &p, end, env);
- if (r < 0) return r;
- break;
- }
- else if (c == '>') { /* (?P>name): subexp call */
- name = p;
- r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &gnum, 0);
- if (r < 0) return r;
-
- tok->type = TK_CALL;
- tok->u.call.name = name;
- tok->u.call.name_end = name_end;
- tok->u.call.gnum = gnum;
- tok->u.call.rel = 0;
- break;
- }
- }
+ if (PPEEK_IS('P') &&
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_CAPITAL_P_NAMED_GROUP)) {
+ int gnum;
+ UChar *name;
+ UChar *name_end;
+ PFETCH_READY;
+
+ PINC; /* skip 'P' */
+ if (PEND) return ONIGERR_UNDEFINED_GROUP_OPTION;
+ PFETCH(c);
+ if (c == '=') { /* (?P=name): backref */
+ r = fetch_named_backref_token((OnigCodePoint )'(', tok, &p, end, env);
+ if (r < 0) return r;
+ break;
+ }
+ else if (c == '>') { /* (?P>name): subexp call */
+ name = p;
+ r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &gnum, 0);
+ if (r < 0) return r;
+
+ tok->type = TK_CALL;
+ tok->u.call.name = name;
+ tok->u.call.name_end = name_end;
+ tok->u.call.gnum = gnum;
+ tok->u.call.rel = 0;
+ break;
+ }
+ }
#endif /* USE_CAPITAL_P_NAMED_GROUP */
- PUNFETCH;
+ PUNFETCH;
}
if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LPAREN_SUBEXP)) break;
@@ -4138,14 +4142,14 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LINE_ANCHOR)) break;
tok->type = TK_ANCHOR;
tok->u.anchor.subtype = (IS_SINGLELINE(env->option)
- ? ANCHOR_BEGIN_BUF : ANCHOR_BEGIN_LINE);
+ ? ANCHOR_BEGIN_BUF : ANCHOR_BEGIN_LINE);
break;
case '$':
if (! IS_SYNTAX_OP(syn, ONIG_SYN_OP_LINE_ANCHOR)) break;
tok->type = TK_ANCHOR;
tok->u.anchor.subtype = (IS_SINGLELINE(env->option)
- ? ANCHOR_SEMI_END_BUF : ANCHOR_END_LINE);
+ ? ANCHOR_SEMI_END_BUF : ANCHOR_END_LINE);
break;
case '[':
@@ -4155,24 +4159,24 @@ fetch_token(OnigToken* tok, UChar** src, UChar* end, ScanEnv* env)
case ']':
if (*src > env->pattern) /* /].../ is allowed. */
- CLOSE_BRACKET_WITHOUT_ESC_WARN(env, (UChar* )"]");
+ CLOSE_BRACKET_WITHOUT_ESC_WARN(env, (UChar* )"]");
break;
case '#':
if (IS_EXTEND(env->option)) {
- while (!PEND) {
- PFETCH(c);
- if (ONIGENC_IS_CODE_NEWLINE(enc, c))
- break;
- }
- goto start;
- break;
+ while (!PEND) {
+ PFETCH(c);
+ if (ONIGENC_IS_CODE_NEWLINE(enc, c))
+ break;
+ }
+ goto start;
+ break;
}
break;
case ' ': case '\t': case '\n': case '\r': case '\f':
if (IS_EXTEND(env->option))
- goto start;
+ goto start;
break;
default:
@@ -4201,18 +4205,18 @@ add_ctype_to_cc_by_range(CClassNode* cc, int ctype ARG_UNUSED, int not,
if (not == 0) {
for (i = 0; i < n; i++) {
for (j = ONIGENC_CODE_RANGE_FROM(mbr, i);
- j <= ONIGENC_CODE_RANGE_TO(mbr, i); j++) {
- if (j >= sb_out) {
- if (j > ONIGENC_CODE_RANGE_FROM(mbr, i)) {
- r = add_code_range_to_buf(&(cc->mbuf), env, j,
- ONIGENC_CODE_RANGE_TO(mbr, i));
- if (r != 0) return r;
- i++;
- }
+ j <= ONIGENC_CODE_RANGE_TO(mbr, i); j++) {
+ if (j >= sb_out) {
+ if (j > ONIGENC_CODE_RANGE_FROM(mbr, i)) {
+ r = add_code_range_to_buf(&(cc->mbuf), env, j,
+ ONIGENC_CODE_RANGE_TO(mbr, i));
+ if (r != 0) return r;
+ i++;
+ }
- goto sb_end;
- }
- BITSET_SET_BIT_CHKDUP(cc->bs, j);
+ goto sb_end;
+ }
+ BITSET_SET_BIT_CHKDUP(cc->bs, j);
}
}
@@ -4229,11 +4233,11 @@ add_ctype_to_cc_by_range(CClassNode* cc, int ctype ARG_UNUSED, int not,
for (i = 0; i < n; i++) {
for (j = prev;
- j < ONIGENC_CODE_RANGE_FROM(mbr, i); j++) {
- if (j >= sb_out) {
- goto sb_end2;
- }
- BITSET_SET_BIT_CHKDUP(cc->bs, j);
+ j < ONIGENC_CODE_RANGE_FROM(mbr, i); j++) {
+ if (j >= sb_out) {
+ goto sb_end2;
+ }
+ BITSET_SET_BIT_CHKDUP(cc->bs, j);
}
prev = ONIGENC_CODE_RANGE_TO(mbr, i) + 1;
}
@@ -4246,9 +4250,9 @@ add_ctype_to_cc_by_range(CClassNode* cc, int ctype ARG_UNUSED, int not,
for (i = 0; i < n; i++) {
if (prev < ONIGENC_CODE_RANGE_FROM(mbr, i)) {
- r = add_code_range_to_buf(&(cc->mbuf), env, prev,
+ r = add_code_range_to_buf(&(cc->mbuf), env, prev,
ONIGENC_CODE_RANGE_FROM(mbr, i) - 1);
- if (r != 0) return r;
+ if (r != 0) return r;
}
prev = ONIGENC_CODE_RANGE_TO(mbr, i) + 1;
}
@@ -4276,30 +4280,30 @@ add_ctype_to_cc(CClassNode* cc, int ctype, int not, int ascii_range, ScanEnv* en
CClassNode ccwork;
initialize_cclass(&ccwork);
r = add_ctype_to_cc_by_range(&ccwork, ctype, not, env, sb_out,
- ranges);
+ ranges);
if (r == 0) {
- if (not) {
- r = add_code_range_to_buf0(&(ccwork.mbuf), env, 0x80, ONIG_LAST_CODE_POINT, FALSE);
- }
- else {
- CClassNode ccascii;
- initialize_cclass(&ccascii);
- if (ONIGENC_MBC_MINLEN(env->enc) > 1) {
- r = add_code_range(&(ccascii.mbuf), env, 0x00, 0x7F);
- }
- else {
- bitset_set_range(env, ccascii.bs, 0x00, 0x7F);
- r = 0;
- }
- if (r == 0) {
- r = and_cclass(&ccwork, &ccascii, env);
- }
- if (IS_NOT_NULL(ccascii.mbuf)) bbuf_free(ccascii.mbuf);
- }
- if (r == 0) {
- r = or_cclass(cc, &ccwork, env);
- }
- if (IS_NOT_NULL(ccwork.mbuf)) bbuf_free(ccwork.mbuf);
+ if (not) {
+ r = add_code_range_to_buf0(&(ccwork.mbuf), env, 0x80, ONIG_LAST_CODE_POINT, FALSE);
+ }
+ else {
+ CClassNode ccascii;
+ initialize_cclass(&ccascii);
+ if (ONIGENC_MBC_MINLEN(env->enc) > 1) {
+ r = add_code_range(&(ccascii.mbuf), env, 0x00, 0x7F);
+ }
+ else {
+ bitset_set_range(env, ccascii.bs, 0x00, 0x7F);
+ r = 0;
+ }
+ if (r == 0) {
+ r = and_cclass(&ccwork, &ccascii, env);
+ }
+ if (IS_NOT_NULL(ccascii.mbuf)) bbuf_free(ccascii.mbuf);
+ }
+ if (r == 0) {
+ r = or_cclass(cc, &ccwork, env);
+ }
+ if (IS_NOT_NULL(ccwork.mbuf)) bbuf_free(ccwork.mbuf);
}
}
else {
@@ -4327,15 +4331,15 @@ add_ctype_to_cc(CClassNode* cc, int ctype, int not, int ascii_range, ScanEnv* en
case ONIGENC_CTYPE_ALNUM:
if (not != 0) {
for (c = 0; c < SINGLE_BYTE_SIZE; c++) {
- if (! ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
- BITSET_SET_BIT_CHKDUP(cc->bs, c);
+ if (! ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT_CHKDUP(cc->bs, c);
}
ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
}
else {
for (c = 0; c < SINGLE_BYTE_SIZE; c++) {
- if (ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
- BITSET_SET_BIT_CHKDUP(cc->bs, c);
+ if (ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT_CHKDUP(cc->bs, c);
}
}
break;
@@ -4344,39 +4348,39 @@ add_ctype_to_cc(CClassNode* cc, int ctype, int not, int ascii_range, ScanEnv* en
case ONIGENC_CTYPE_PRINT:
if (not != 0) {
for (c = 0; c < SINGLE_BYTE_SIZE; c++) {
- if (! ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype)
- || c >= maxcode)
- BITSET_SET_BIT_CHKDUP(cc->bs, c);
+ if (! ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype)
+ || c >= maxcode)
+ BITSET_SET_BIT_CHKDUP(cc->bs, c);
}
if (ascii_range)
- ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
}
else {
for (c = 0; c < maxcode; c++) {
- if (ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
- BITSET_SET_BIT_CHKDUP(cc->bs, c);
+ if (ONIGENC_IS_CODE_CTYPE(enc, (OnigCodePoint )c, ctype))
+ BITSET_SET_BIT_CHKDUP(cc->bs, c);
}
if (! ascii_range)
- ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
}
break;
case ONIGENC_CTYPE_WORD:
if (not == 0) {
for (c = 0; c < maxcode; c++) {
- if (ONIGENC_IS_CODE_WORD(enc, c)) BITSET_SET_BIT_CHKDUP(cc->bs, c);
+ if (ONIGENC_IS_CODE_WORD(enc, c)) BITSET_SET_BIT_CHKDUP(cc->bs, c);
}
if (! ascii_range)
- ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
}
else {
for (c = 0; c < SINGLE_BYTE_SIZE; c++) {
- if ((ONIGENC_CODE_TO_MBCLEN(enc, c) > 0) /* check invalid code point */
- && (! ONIGENC_IS_CODE_WORD(enc, c) || c >= maxcode))
- BITSET_SET_BIT_CHKDUP(cc->bs, c);
+ if ((ONIGENC_CODE_TO_MBCLEN(enc, c) > 0) /* check invalid code point */
+ && (! ONIGENC_IS_CODE_WORD(enc, c) || c >= maxcode))
+ BITSET_SET_BIT_CHKDUP(cc->bs, c);
}
if (ascii_range)
- ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
+ ADD_ALL_MULTI_BYTE_RANGE(enc, cc->mbuf);
}
break;
@@ -4390,7 +4394,7 @@ add_ctype_to_cc(CClassNode* cc, int ctype, int not, int ascii_range, ScanEnv* en
static int
parse_posix_bracket(CClassNode* cc, CClassNode* asc_cc,
- UChar** src, UChar* end, ScanEnv* env)
+ UChar** src, UChar* end, ScanEnv* env)
{
#define POSIX_BRACKET_CHECK_LIMIT_LENGTH 20
#define POSIX_BRACKET_NAME_MIN_LEN 4
@@ -4430,22 +4434,22 @@ parse_posix_bracket(CClassNode* cc, CClassNode* asc_cc,
goto not_posix_bracket;
ascii_range = IS_ASCII_RANGE(env->option) &&
- ! IS_POSIX_BRACKET_ALL_RANGE(env->option);
+ ! IS_POSIX_BRACKET_ALL_RANGE(env->option);
for (pb = PBS; pb < PBS + numberof(PBS); pb++) {
if (onigenc_with_ascii_strncmp(enc, p, end, pb->name, pb->len) == 0) {
p = (UChar* )onigenc_step(enc, p, end, pb->len);
if (onigenc_with_ascii_strncmp(enc, p, end, (UChar* )":]", 2) != 0)
- return ONIGERR_INVALID_POSIX_BRACKET_TYPE;
+ return ONIGERR_INVALID_POSIX_BRACKET_TYPE;
r = add_ctype_to_cc(cc, pb->ctype, not, ascii_range, env);
if (r != 0) return r;
if (IS_NOT_NULL(asc_cc)) {
- if (pb->ctype != ONIGENC_CTYPE_WORD &&
- pb->ctype != ONIGENC_CTYPE_ASCII &&
- !ascii_range)
- r = add_ctype_to_cc(asc_cc, pb->ctype, not, ascii_range, env);
- if (r != 0) return r;
+ if (pb->ctype != ONIGENC_CTYPE_WORD &&
+ pb->ctype != ONIGENC_CTYPE_ASCII &&
+ !ascii_range)
+ r = add_ctype_to_cc(asc_cc, pb->ctype, not, ascii_range, env);
+ if (r != 0) return r;
}
PINC_S; PINC_S;
@@ -4466,7 +4470,7 @@ parse_posix_bracket(CClassNode* cc, CClassNode* asc_cc,
if (! PEND) {
PFETCH_S(c);
if (c == ']')
- return ONIGERR_INVALID_POSIX_BRACKET_TYPE;
+ return ONIGERR_INVALID_POSIX_BRACKET_TYPE;
}
}
@@ -4507,7 +4511,7 @@ static int cclass_case_fold(Node** np, CClassNode* cc, CClassNode* asc_cc, ScanE
static int
parse_char_property(Node** np, OnigToken* tok, UChar** src, UChar* end,
- ScanEnv* env)
+ ScanEnv* env)
{
int r, ctype;
CClassNode* cc;
@@ -4545,8 +4549,8 @@ enum CCVALTYPE {
static int
next_state_class(CClassNode* cc, CClassNode* asc_cc,
- OnigCodePoint* vs, enum CCVALTYPE* type,
- enum CCSTATE* state, ScanEnv* env)
+ OnigCodePoint* vs, enum CCVALTYPE* type,
+ enum CCSTATE* state, ScanEnv* env)
{
int r;
@@ -4557,14 +4561,14 @@ next_state_class(CClassNode* cc, CClassNode* asc_cc,
if (*type == CCV_SB) {
BITSET_SET_BIT_CHKDUP(cc->bs, (int )(*vs));
if (IS_NOT_NULL(asc_cc))
- BITSET_SET_BIT(asc_cc->bs, (int )(*vs));
+ BITSET_SET_BIT(asc_cc->bs, (int )(*vs));
}
else if (*type == CCV_CODE_POINT) {
r = add_code_range(&(cc->mbuf), env, *vs, *vs);
if (r < 0) return r;
if (IS_NOT_NULL(asc_cc)) {
- r = add_code_range0(&(asc_cc->mbuf), env, *vs, *vs, 0);
- if (r < 0) return r;
+ r = add_code_range0(&(asc_cc->mbuf), env, *vs, *vs, 0);
+ if (r < 0) return r;
}
}
}
@@ -4576,10 +4580,10 @@ next_state_class(CClassNode* cc, CClassNode* asc_cc,
static int
next_state_val(CClassNode* cc, CClassNode* asc_cc,
- OnigCodePoint *from, OnigCodePoint to,
- int* from_israw, int to_israw,
- enum CCVALTYPE intype, enum CCVALTYPE* type,
- enum CCSTATE* state, ScanEnv* env)
+ OnigCodePoint *from, OnigCodePoint to,
+ int* from_israw, int to_israw,
+ enum CCVALTYPE intype, enum CCVALTYPE* type,
+ enum CCSTATE* state, ScanEnv* env)
{
int r;
@@ -4588,14 +4592,14 @@ next_state_val(CClassNode* cc, CClassNode* asc_cc,
if (*type == CCV_SB) {
BITSET_SET_BIT_CHKDUP(cc->bs, (int )(*from));
if (IS_NOT_NULL(asc_cc))
- BITSET_SET_BIT(asc_cc->bs, (int )(*from));
+ BITSET_SET_BIT(asc_cc->bs, (int )(*from));
}
else if (*type == CCV_CODE_POINT) {
r = add_code_range(&(cc->mbuf), env, *from, *from);
if (r < 0) return r;
if (IS_NOT_NULL(asc_cc)) {
- r = add_code_range0(&(asc_cc->mbuf), env, *from, *from, 0);
- if (r < 0) return r;
+ r = add_code_range0(&(asc_cc->mbuf), env, *from, *from, 0);
+ if (r < 0) return r;
}
}
break;
@@ -4603,42 +4607,42 @@ next_state_val(CClassNode* cc, CClassNode* asc_cc,
case CCS_RANGE:
if (intype == *type) {
if (intype == CCV_SB) {
- if (*from > 0xff || to > 0xff)
- return ONIGERR_INVALID_CODE_POINT_VALUE;
-
- if (*from > to) {
- if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
- goto ccs_range_end;
- else
- return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
- }
- bitset_set_range(env, cc->bs, (int )*from, (int )to);
- if (IS_NOT_NULL(asc_cc))
- bitset_set_range(env, asc_cc->bs, (int )*from, (int )to);
+ if (*from > 0xff || to > 0xff)
+ return ONIGERR_INVALID_CODE_POINT_VALUE;
+
+ if (*from > to) {
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
+ goto ccs_range_end;
+ else
+ return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
+ }
+ bitset_set_range(env, cc->bs, (int )*from, (int )to);
+ if (IS_NOT_NULL(asc_cc))
+ bitset_set_range(env, asc_cc->bs, (int )*from, (int )to);
}
else {
- r = add_code_range(&(cc->mbuf), env, *from, to);
- if (r < 0) return r;
- if (IS_NOT_NULL(asc_cc)) {
- r = add_code_range0(&(asc_cc->mbuf), env, *from, to, 0);
- if (r < 0) return r;
- }
+ r = add_code_range(&(cc->mbuf), env, *from, to);
+ if (r < 0) return r;
+ if (IS_NOT_NULL(asc_cc)) {
+ r = add_code_range0(&(asc_cc->mbuf), env, *from, to, 0);
+ if (r < 0) return r;
+ }
}
}
else {
if (*from > to) {
- if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
- goto ccs_range_end;
- else
- return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_EMPTY_RANGE_IN_CC))
+ goto ccs_range_end;
+ else
+ return ONIGERR_EMPTY_RANGE_IN_CHAR_CLASS;
}
bitset_set_range(env, cc->bs, (int )*from, (int )(to < 0xff ? to : 0xff));
r = add_code_range(&(cc->mbuf), env, (OnigCodePoint )*from, to);
if (r < 0) return r;
if (IS_NOT_NULL(asc_cc)) {
- bitset_set_range(env, asc_cc->bs, (int )*from, (int )(to < 0xff ? to : 0xff));
- r = add_code_range0(&(asc_cc->mbuf), env, (OnigCodePoint )*from, to, 0);
- if (r < 0) return r;
+ bitset_set_range(env, asc_cc->bs, (int )*from, (int )(to < 0xff ? to : 0xff));
+ r = add_code_range0(&(asc_cc->mbuf), env, (OnigCodePoint )*from, to, 0);
+ if (r < 0) return r;
}
}
ccs_range_end:
@@ -4662,7 +4666,7 @@ next_state_val(CClassNode* cc, CClassNode* asc_cc,
static int
code_exist_check(OnigCodePoint c, UChar* from, UChar* end, int ignore_escaped,
- ScanEnv* env)
+ ScanEnv* env)
{
int in_esc;
OnigCodePoint code;
@@ -4685,7 +4689,7 @@ code_exist_check(OnigCodePoint c, UChar* from, UChar* end, int ignore_escaped,
static int
parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* end,
- ScanEnv* env)
+ ScanEnv* env)
{
int r, neg, len, fetched, and_start;
OnigCodePoint v, vs;
@@ -4746,16 +4750,16 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
switch (r) {
case TK_CHAR:
if ((tok->u.code >= SINGLE_BYTE_SIZE) ||
- (len = ONIGENC_CODE_TO_MBCLEN(env->enc, tok->u.c)) > 1) {
- in_type = CCV_CODE_POINT;
+ (len = ONIGENC_CODE_TO_MBCLEN(env->enc, tok->u.c)) > 1) {
+ in_type = CCV_CODE_POINT;
}
else if (len < 0) {
- r = len;
- goto err;
+ r = len;
+ goto err;
}
else {
sb_char:
- in_type = CCV_SB;
+ in_type = CCV_SB;
}
v = (OnigCodePoint )tok->u.c;
in_israw = 0;
@@ -4765,54 +4769,54 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
case TK_RAW_BYTE:
/* tok->base != 0 : octal or hexadec. */
if (! ONIGENC_IS_SINGLEBYTE(env->enc) && tok->base != 0) {
- UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
- UChar* bufe = buf + ONIGENC_CODE_TO_MBC_MAXLEN;
- UChar* psave = p;
- int i, base = tok->base;
-
- buf[0] = (UChar )tok->u.c;
- for (i = 1; i < ONIGENC_MBC_MAXLEN(env->enc); i++) {
- r = fetch_token_in_cc(tok, &p, end, env);
- if (r < 0) goto err;
- if (r != TK_RAW_BYTE || tok->base != base) {
- fetched = 1;
- break;
- }
- buf[i] = (UChar )tok->u.c;
- }
-
- if (i < ONIGENC_MBC_MINLEN(env->enc)) {
- r = ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
- goto err;
- }
-
- len = enclen(env->enc, buf, buf + i);
- if (i < len) {
- r = ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
- goto err;
- }
- else if (i > len) { /* fetch back */
- p = psave;
- for (i = 1; i < len; i++) {
- (void)fetch_token_in_cc(tok, &p, end, env);
- /* no need to check the return value (already checked above) */
- }
- fetched = 0;
- }
-
- if (i == 1) {
- v = (OnigCodePoint )buf[0];
- goto raw_single;
- }
- else {
- v = ONIGENC_MBC_TO_CODE(env->enc, buf, bufe);
- in_type = CCV_CODE_POINT;
- }
+ UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
+ UChar* bufe = buf + ONIGENC_CODE_TO_MBC_MAXLEN;
+ UChar* psave = p;
+ int i, base = tok->base;
+
+ buf[0] = (UChar )tok->u.c;
+ for (i = 1; i < ONIGENC_MBC_MAXLEN(env->enc); i++) {
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+ if (r != TK_RAW_BYTE || tok->base != base) {
+ fetched = 1;
+ break;
+ }
+ buf[i] = (UChar )tok->u.c;
+ }
+
+ if (i < ONIGENC_MBC_MINLEN(env->enc)) {
+ r = ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
+ goto err;
+ }
+
+ len = enclen(env->enc, buf, buf + i);
+ if (i < len) {
+ r = ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
+ goto err;
+ }
+ else if (i > len) { /* fetch back */
+ p = psave;
+ for (i = 1; i < len; i++) {
+ (void)fetch_token_in_cc(tok, &p, end, env);
+ /* no need to check the return value (already checked above) */
+ }
+ fetched = 0;
+ }
+
+ if (i == 1) {
+ v = (OnigCodePoint )buf[0];
+ goto raw_single;
+ }
+ else {
+ v = ONIGENC_MBC_TO_CODE(env->enc, buf, bufe);
+ in_type = CCV_CODE_POINT;
+ }
}
else {
- v = (OnigCodePoint )tok->u.c;
+ v = (OnigCodePoint )tok->u.c;
raw_single:
- in_type = CCV_SB;
+ in_type = CCV_SB;
}
in_israw = 1;
goto val_entry2;
@@ -4824,13 +4828,13 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
val_entry:
len = ONIGENC_CODE_TO_MBCLEN(env->enc, v);
if (len < 0) {
- r = len;
- goto err;
+ r = len;
+ goto err;
}
in_type = (len == 1 ? CCV_SB : CCV_CODE_POINT);
val_entry2:
r = next_state_val(cc, asc_cc, &vs, v, &val_israw, in_israw, in_type, &val_type,
- &state, env);
+ &state, env);
if (r != 0) goto err;
break;
@@ -4838,24 +4842,24 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
r = parse_posix_bracket(cc, asc_cc, &p, end, env);
if (r < 0) goto err;
if (r == 1) { /* is not POSIX bracket */
- CC_ESC_WARN(env, (UChar* )"[");
- p = tok->backp;
- v = (OnigCodePoint )tok->u.c;
- in_israw = 0;
- goto val_entry;
+ CC_ESC_WARN(env, (UChar* )"[");
+ p = tok->backp;
+ v = (OnigCodePoint )tok->u.c;
+ in_israw = 0;
+ goto val_entry;
}
goto next_class;
break;
case TK_CHAR_TYPE:
r = add_ctype_to_cc(cc, tok->u.prop.ctype, tok->u.prop.not,
- IS_ASCII_RANGE(env->option), env);
+ IS_ASCII_RANGE(env->option), env);
if (r != 0) return r;
if (IS_NOT_NULL(asc_cc)) {
- if (tok->u.prop.ctype != ONIGENC_CTYPE_WORD)
- r = add_ctype_to_cc(asc_cc, tok->u.prop.ctype, tok->u.prop.not,
- IS_ASCII_RANGE(env->option), env);
- if (r != 0) return r;
+ if (tok->u.prop.ctype != ONIGENC_CTYPE_WORD)
+ r = add_ctype_to_cc(asc_cc, tok->u.prop.ctype, tok->u.prop.not,
+ IS_ASCII_RANGE(env->option), env);
+ if (r != 0) return r;
}
next_class:
@@ -4865,133 +4869,133 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
case TK_CHAR_PROPERTY:
{
- int ctype;
-
- ctype = fetch_char_property_to_ctype(&p, end, env);
- if (ctype < 0) return ctype;
- r = add_ctype_to_cc(cc, ctype, tok->u.prop.not, 0, env);
- if (r != 0) return r;
- if (IS_NOT_NULL(asc_cc)) {
- if (ctype != ONIGENC_CTYPE_ASCII)
- r = add_ctype_to_cc(asc_cc, ctype, tok->u.prop.not, 0, env);
- if (r != 0) return r;
- }
- goto next_class;
+ int ctype;
+
+ ctype = fetch_char_property_to_ctype(&p, end, env);
+ if (ctype < 0) return ctype;
+ r = add_ctype_to_cc(cc, ctype, tok->u.prop.not, 0, env);
+ if (r != 0) return r;
+ if (IS_NOT_NULL(asc_cc)) {
+ if (ctype != ONIGENC_CTYPE_ASCII)
+ r = add_ctype_to_cc(asc_cc, ctype, tok->u.prop.not, 0, env);
+ if (r != 0) return r;
+ }
+ goto next_class;
}
break;
case TK_CC_RANGE:
if (state == CCS_VALUE) {
- r = fetch_token_in_cc(tok, &p, end, env);
- if (r < 0) goto err;
- fetched = 1;
- if (r == TK_CC_CLOSE) { /* allow [x-] */
- range_end_val:
- v = (OnigCodePoint )'-';
- in_israw = 0;
- goto val_entry;
- }
- else if (r == TK_CC_AND) {
- CC_ESC_WARN(env, (UChar* )"-");
- goto range_end_val;
- }
-
- if (val_type == CCV_CLASS) {
- r = ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS;
- goto err;
- }
-
- state = CCS_RANGE;
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+ fetched = 1;
+ if (r == TK_CC_CLOSE) { /* allow [x-] */
+ range_end_val:
+ v = (OnigCodePoint )'-';
+ in_israw = 0;
+ goto val_entry;
+ }
+ else if (r == TK_CC_AND) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto range_end_val;
+ }
+
+ if (val_type == CCV_CLASS) {
+ r = ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS;
+ goto err;
+ }
+
+ state = CCS_RANGE;
}
else if (state == CCS_START) {
- /* [-xa] is allowed */
- v = (OnigCodePoint )tok->u.c;
- in_israw = 0;
+ /* [-xa] is allowed */
+ v = (OnigCodePoint )tok->u.c;
+ in_israw = 0;
- r = fetch_token_in_cc(tok, &p, end, env);
- if (r < 0) goto err;
- fetched = 1;
- /* [--x] or [a&&-x] is warned. */
- if (r == TK_CC_RANGE || and_start != 0)
- CC_ESC_WARN(env, (UChar* )"-");
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+ fetched = 1;
+ /* [--x] or [a&&-x] is warned. */
+ if (r == TK_CC_RANGE || and_start != 0)
+ CC_ESC_WARN(env, (UChar* )"-");
- goto val_entry;
+ goto val_entry;
}
else if (state == CCS_RANGE) {
- CC_ESC_WARN(env, (UChar* )"-");
- goto sb_char; /* [!--x] is allowed */
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto sb_char; /* [!--x] is allowed */
}
else { /* CCS_COMPLETE */
- r = fetch_token_in_cc(tok, &p, end, env);
- if (r < 0) goto err;
- fetched = 1;
- if (r == TK_CC_CLOSE) goto range_end_val; /* allow [a-b-] */
- else if (r == TK_CC_AND) {
- CC_ESC_WARN(env, (UChar* )"-");
- goto range_end_val;
- }
-
- if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC)) {
- CC_ESC_WARN(env, (UChar* )"-");
- goto range_end_val; /* [0-9-a] is allowed as [0-9\-a] */
- }
- r = ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS;
- goto err;
+ r = fetch_token_in_cc(tok, &p, end, env);
+ if (r < 0) goto err;
+ fetched = 1;
+ if (r == TK_CC_CLOSE) goto range_end_val; /* allow [a-b-] */
+ else if (r == TK_CC_AND) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto range_end_val;
+ }
+
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_DOUBLE_RANGE_OP_IN_CC)) {
+ CC_ESC_WARN(env, (UChar* )"-");
+ goto range_end_val; /* [0-9-a] is allowed as [0-9\-a] */
+ }
+ r = ONIGERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS;
+ goto err;
}
break;
case TK_CC_CC_OPEN: /* [ */
{
- Node *anode, *aasc_node;
- CClassNode* acc;
-
- r = parse_char_class(&anode, &aasc_node, tok, &p, end, env);
- if (r == 0) {
- acc = NCCLASS(anode);
- r = or_cclass(cc, acc, env);
- }
- if (r == 0 && IS_NOT_NULL(aasc_node)) {
- acc = NCCLASS(aasc_node);
- r = or_cclass(asc_cc, acc, env);
- }
- onig_node_free(anode);
- onig_node_free(aasc_node);
- if (r != 0) goto err;
+ Node *anode, *aasc_node;
+ CClassNode* acc;
+
+ r = parse_char_class(&anode, &aasc_node, tok, &p, end, env);
+ if (r == 0) {
+ acc = NCCLASS(anode);
+ r = or_cclass(cc, acc, env);
+ }
+ if (r == 0 && IS_NOT_NULL(aasc_node)) {
+ acc = NCCLASS(aasc_node);
+ r = or_cclass(asc_cc, acc, env);
+ }
+ onig_node_free(anode);
+ onig_node_free(aasc_node);
+ if (r != 0) goto err;
}
break;
case TK_CC_AND: /* && */
{
- if (state == CCS_VALUE) {
- r = next_state_val(cc, asc_cc, &vs, 0, &val_israw, 0, val_type,
- &val_type, &state, env);
- if (r != 0) goto err;
- }
- /* initialize local variables */
- and_start = 1;
- state = CCS_START;
-
- if (IS_NOT_NULL(prev_cc)) {
- r = and_cclass(prev_cc, cc, env);
- if (r != 0) goto err;
- bbuf_free(cc->mbuf);
- if (IS_NOT_NULL(asc_cc)) {
- r = and_cclass(asc_prev_cc, asc_cc, env);
- if (r != 0) goto err;
- bbuf_free(asc_cc->mbuf);
- }
- }
- else {
- prev_cc = cc;
- cc = &work_cc;
- if (IS_NOT_NULL(asc_cc)) {
- asc_prev_cc = asc_cc;
- asc_cc = &asc_work_cc;
- }
- }
- initialize_cclass(cc);
- if (IS_NOT_NULL(asc_cc))
- initialize_cclass(asc_cc);
+ if (state == CCS_VALUE) {
+ r = next_state_val(cc, asc_cc, &vs, 0, &val_israw, 0, val_type,
+ &val_type, &state, env);
+ if (r != 0) goto err;
+ }
+ /* initialize local variables */
+ and_start = 1;
+ state = CCS_START;
+
+ if (IS_NOT_NULL(prev_cc)) {
+ r = and_cclass(prev_cc, cc, env);
+ if (r != 0) goto err;
+ bbuf_free(cc->mbuf);
+ if (IS_NOT_NULL(asc_cc)) {
+ r = and_cclass(asc_prev_cc, asc_cc, env);
+ if (r != 0) goto err;
+ bbuf_free(asc_cc->mbuf);
+ }
+ }
+ else {
+ prev_cc = cc;
+ cc = &work_cc;
+ if (IS_NOT_NULL(asc_cc)) {
+ asc_prev_cc = asc_cc;
+ asc_cc = &asc_work_cc;
+ }
+ }
+ initialize_cclass(cc);
+ if (IS_NOT_NULL(asc_cc))
+ initialize_cclass(asc_cc);
}
break;
@@ -5015,7 +5019,7 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
if (state == CCS_VALUE) {
r = next_state_val(cc, asc_cc, &vs, 0, &val_israw, 0, val_type,
- &val_type, &state, env);
+ &val_type, &state, env);
if (r != 0) goto err;
}
@@ -5054,12 +5058,12 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
#define NEWLINE_CODE 0x0a
if (ONIGENC_IS_CODE_NEWLINE(env->enc, NEWLINE_CODE)) {
- if (ONIGENC_CODE_TO_MBCLEN(env->enc, NEWLINE_CODE) == 1)
- BITSET_SET_BIT_CHKDUP(cc->bs, NEWLINE_CODE);
- else {
- r = add_code_range(&(cc->mbuf), env, NEWLINE_CODE, NEWLINE_CODE);
- if (r < 0) goto err;
- }
+ if (ONIGENC_CODE_TO_MBCLEN(env->enc, NEWLINE_CODE) == 1)
+ BITSET_SET_BIT_CHKDUP(cc->bs, NEWLINE_CODE);
+ else {
+ r = add_code_range(&(cc->mbuf), env, NEWLINE_CODE, NEWLINE_CODE);
+ if (r < 0) goto err;
+ }
}
}
}
@@ -5076,11 +5080,11 @@ parse_char_class(Node** np, Node** asc_np, OnigToken* tok, UChar** src, UChar* e
}
static int parse_subexp(Node** top, OnigToken* tok, int term,
- UChar** src, UChar* end, ScanEnv* env);
+ UChar** src, UChar* end, ScanEnv* env);
static int
parse_enclose(Node** np, OnigToken* tok, int term, UChar** src, UChar* end,
- ScanEnv* env)
+ ScanEnv* env)
{
int r = 0, num;
Node *target, *work1 = NULL, *work2 = NULL;
@@ -5127,28 +5131,28 @@ parse_enclose(Node** np, OnigToken* tok, int term, UChar** src, UChar* end,
break;
case '~': /* (?~...) absent operator */
if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_TILDE_ABSENT)) {
- *np = node_new_enclose(ENCLOSE_ABSENT);
+ *np = node_new_enclose(ENCLOSE_ABSENT);
}
else {
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
}
break;
#ifdef USE_NAMED_GROUP
case '\'':
if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
- goto named_group1;
+ goto named_group1;
}
else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
break;
# ifdef USE_CAPITAL_P_NAMED_GROUP
case 'P': /* (?P<name>...) */
if (!PEND &&
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_CAPITAL_P_NAMED_GROUP)) {
- PFETCH(c);
- if (c == '<') goto named_group1;
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_CAPITAL_P_NAMED_GROUP)) {
+ PFETCH(c);
+ if (c == '<') goto named_group1;
}
return ONIGERR_UNDEFINED_GROUP_OPTION;
break;
@@ -5159,49 +5163,49 @@ parse_enclose(Node** np, OnigToken* tok, int term, UChar** src, UChar* end,
if (PEND) return ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS;
PFETCH(c);
if (c == '=')
- *np = onig_node_new_anchor(ANCHOR_LOOK_BEHIND);
+ *np = onig_node_new_anchor(ANCHOR_LOOK_BEHIND);
else if (c == '!')
- *np = onig_node_new_anchor(ANCHOR_LOOK_BEHIND_NOT);
+ *np = onig_node_new_anchor(ANCHOR_LOOK_BEHIND_NOT);
#ifdef USE_NAMED_GROUP
else { /* (?<name>...) */
- if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
- UChar *name;
- UChar *name_end;
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
+ UChar *name;
+ UChar *name_end;
- PUNFETCH;
- c = '<';
+ PUNFETCH;
+ c = '<';
- named_group1:
- list_capture = 0;
+ named_group1:
+ list_capture = 0;
# ifdef USE_CAPTURE_HISTORY
- named_group2:
+ named_group2:
# endif
- name = p;
- r = fetch_name((OnigCodePoint )c, &p, end, &name_end, env, &num, 0);
- if (r < 0) return r;
-
- num = scan_env_add_mem_entry(env);
- if (num < 0) return num;
- if (list_capture != 0 && num >= (int )BIT_STATUS_BITS_NUM)
- return ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY;
-
- r = name_add(env->reg, name, name_end, num, env);
- if (r != 0) return r;
- *np = node_new_enclose_memory(env->option, 1);
- CHECK_NULL_RETURN_MEMERR(*np);
- NENCLOSE(*np)->regnum = num;
- if (list_capture != 0)
- BIT_STATUS_ON_AT_SIMPLE(env->capture_history, num);
- env->num_named++;
- }
- else {
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- }
+ name = p;
+ r = fetch_name((OnigCodePoint )c, &p, end, &name_end, env, &num, 0);
+ if (r < 0) return r;
+
+ num = scan_env_add_mem_entry(env);
+ if (num < 0) return num;
+ if (list_capture != 0 && num >= (int )BIT_STATUS_BITS_NUM)
+ return ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY;
+
+ r = name_add(env->reg, name, name_end, num, env);
+ if (r != 0) return r;
+ *np = node_new_enclose_memory(env->option, 1);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ NENCLOSE(*np)->regnum = num;
+ if (list_capture != 0)
+ BIT_STATUS_ON_AT_SIMPLE(env->capture_history, num);
+ env->num_named++;
+ }
+ else {
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
}
#else
else {
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
}
#endif
break;
@@ -5210,122 +5214,122 @@ parse_enclose(Node** np, OnigToken* tok, int term, UChar** src, UChar* end,
case '@':
if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_ATMARK_CAPTURE_HISTORY)) {
# ifdef USE_NAMED_GROUP
- if (!PEND &&
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
- PFETCH(c);
- if (c == '<' || c == '\'') {
- list_capture = 1;
- goto named_group2; /* (?@<name>...) */
- }
- PUNFETCH;
- }
+ if (!PEND &&
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LT_NAMED_GROUP)) {
+ PFETCH(c);
+ if (c == '<' || c == '\'') {
+ list_capture = 1;
+ goto named_group2; /* (?@<name>...) */
+ }
+ PUNFETCH;
+ }
# endif
- *np = node_new_enclose_memory(env->option, 0);
- CHECK_NULL_RETURN_MEMERR(*np);
- num = scan_env_add_mem_entry(env);
- if (num < 0) return num;
- if (num >= (int )BIT_STATUS_BITS_NUM)
- return ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY;
+ *np = node_new_enclose_memory(env->option, 0);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ num = scan_env_add_mem_entry(env);
+ if (num < 0) return num;
+ if (num >= (int )BIT_STATUS_BITS_NUM)
+ return ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY;
- NENCLOSE(*np)->regnum = num;
- BIT_STATUS_ON_AT_SIMPLE(env->capture_history, num);
+ NENCLOSE(*np)->regnum = num;
+ BIT_STATUS_ON_AT_SIMPLE(env->capture_history, num);
}
else {
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
}
break;
#endif /* USE_CAPTURE_HISTORY */
case '(': /* conditional expression: (?(cond)yes), (?(cond)yes|no) */
if (!PEND &&
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LPAREN_CONDITION)) {
- UChar *name = NULL;
- UChar *name_end;
- PFETCH(c);
- if (ONIGENC_IS_CODE_DIGIT(enc, c)) { /* (n) */
- PUNFETCH;
- r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &num, 1);
- if (r < 0) return r;
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_LPAREN_CONDITION)) {
+ UChar *name = NULL;
+ UChar *name_end;
+ PFETCH(c);
+ if (ONIGENC_IS_CODE_DIGIT(enc, c)) { /* (n) */
+ PUNFETCH;
+ r = fetch_name((OnigCodePoint )'(', &p, end, &name_end, env, &num, 1);
+ if (r < 0) return r;
#if 0
- /* Relative number is not currently supported. (same as Perl) */
- if (num < 0) {
- num = BACKREF_REL_TO_ABS(num, env);
- if (num <= 0)
- return ONIGERR_INVALID_BACKREF;
- }
+ /* Relative number is not currently supported. (same as Perl) */
+ if (num < 0) {
+ num = BACKREF_REL_TO_ABS(num, env);
+ if (num <= 0)
+ return ONIGERR_INVALID_BACKREF;
+ }
#endif
- if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_STRICT_CHECK_BACKREF)) {
- if (num > env->num_mem ||
- IS_NULL(SCANENV_MEM_NODES(env)[num]))
- return ONIGERR_INVALID_BACKREF;
- }
- }
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_STRICT_CHECK_BACKREF)) {
+ if (num > env->num_mem ||
+ IS_NULL(SCANENV_MEM_NODES(env)[num]))
+ return ONIGERR_INVALID_BACKREF;
+ }
+ }
#ifdef USE_NAMED_GROUP
- else if (c == '<' || c == '\'') { /* (<name>), ('name') */
- name = p;
- r = fetch_named_backref_token(c, tok, &p, end, env);
- if (r < 0) return r;
- if (!PPEEK_IS(')')) return ONIGERR_UNDEFINED_GROUP_OPTION;
- PINC;
-
- if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_USE_LEFT_MOST_NAMED_GROUP)) {
- num = tok->u.backref.ref1;
- }
- else {
- /* FIXME:
- * Use left most named group for now. This is the same as Perl.
- * However this should use the same strategy as normal back-
- * references on Ruby syntax; search right to left. */
- int len = tok->u.backref.num;
- num = len > 1 ? tok->u.backref.refs[0] : tok->u.backref.ref1;
- }
- }
+ else if (c == '<' || c == '\'') { /* (<name>), ('name') */
+ name = p;
+ r = fetch_named_backref_token(c, tok, &p, end, env);
+ if (r < 0) return r;
+ if (!PPEEK_IS(')')) return ONIGERR_UNDEFINED_GROUP_OPTION;
+ PINC;
+
+ if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_USE_LEFT_MOST_NAMED_GROUP)) {
+ num = tok->u.backref.ref1;
+ }
+ else {
+ /* FIXME:
+ * Use left most named group for now. This is the same as Perl.
+ * However this should use the same strategy as normal back-
+ * references on Ruby syntax; search right to left. */
+ int len = tok->u.backref.num;
+ num = len > 1 ? tok->u.backref.refs[0] : tok->u.backref.ref1;
+ }
+ }
#endif
- else
- return ONIGERR_INVALID_CONDITION_PATTERN;
- *np = node_new_enclose(ENCLOSE_CONDITION);
- CHECK_NULL_RETURN_MEMERR(*np);
- NENCLOSE(*np)->regnum = num;
- if (IS_NOT_NULL(name)) NENCLOSE(*np)->state |= NST_NAME_REF;
+ else
+ return ONIGERR_INVALID_CONDITION_PATTERN;
+ *np = node_new_enclose(ENCLOSE_CONDITION);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ NENCLOSE(*np)->regnum = num;
+ if (IS_NOT_NULL(name)) NENCLOSE(*np)->state |= NST_NAME_REF;
}
else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
break;
#if 0
case '|': /* branch reset: (?|...) */
if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_QMARK_VBAR_BRANCH_RESET)) {
- /* TODO */
+ /* TODO */
}
else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
break;
#endif
case '^': /* loads default options */
if (!PEND && IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
- /* d-imsx */
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
- ONOFF(option, ONIG_OPTION_IGNORECASE, 1);
- ONOFF(option, ONIG_OPTION_SINGLELINE, 0);
- ONOFF(option, ONIG_OPTION_MULTILINE, 1);
- ONOFF(option, ONIG_OPTION_EXTEND, 1);
- PFETCH(c);
+ /* d-imsx */
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
+ ONOFF(option, ONIG_OPTION_IGNORECASE, 1);
+ ONOFF(option, ONIG_OPTION_SINGLELINE, 0);
+ ONOFF(option, ONIG_OPTION_MULTILINE, 1);
+ ONOFF(option, ONIG_OPTION_EXTEND, 1);
+ PFETCH(c);
}
#if 0
else if (!PEND && IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) {
- /* d-imx */
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 0);
- ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 0);
- ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 0);
- ONOFF(option, ONIG_OPTION_IGNORECASE, 1);
- ONOFF(option, ONIG_OPTION_MULTILINE, 1);
- ONOFF(option, ONIG_OPTION_EXTEND, 1);
- PFETCH(c);
+ /* d-imx */
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 0);
+ ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 0);
+ ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 0);
+ ONOFF(option, ONIG_OPTION_IGNORECASE, 1);
+ ONOFF(option, ONIG_OPTION_MULTILINE, 1);
+ ONOFF(option, ONIG_OPTION_EXTEND, 1);
+ PFETCH(c);
}
#endif
else {
- return ONIGERR_UNDEFINED_GROUP_OPTION;
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
}
/* fall through */
#ifdef USE_POSIXLINE_OPTION
@@ -5334,120 +5338,120 @@ parse_enclose(Node** np, OnigToken* tok, int term, UChar** src, UChar* end,
case '-': case 'i': case 'm': case 's': case 'x':
case 'a': case 'd': case 'l': case 'u':
{
- int neg = 0;
-
- while (1) {
- switch (c) {
- case ':':
- case ')':
- break;
-
- case '-': neg = 1; break;
- case 'x': ONOFF(option, ONIG_OPTION_EXTEND, neg); break;
- case 'i': ONOFF(option, ONIG_OPTION_IGNORECASE, neg); break;
- case 's':
- if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
- ONOFF(option, ONIG_OPTION_MULTILINE, neg);
- }
- else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- break;
-
- case 'm':
- if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
- ONOFF(option, ONIG_OPTION_SINGLELINE, (neg == 0 ? 1 : 0));
- }
- else if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) {
- ONOFF(option, ONIG_OPTION_MULTILINE, neg);
- }
- else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- break;
+ int neg = 0;
+
+ while (1) {
+ switch (c) {
+ case ':':
+ case ')':
+ break;
+
+ case '-': neg = 1; break;
+ case 'x': ONOFF(option, ONIG_OPTION_EXTEND, neg); break;
+ case 'i': ONOFF(option, ONIG_OPTION_IGNORECASE, neg); break;
+ case 's':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
+ ONOFF(option, ONIG_OPTION_MULTILINE, neg);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ case 'm':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL)) {
+ ONOFF(option, ONIG_OPTION_SINGLELINE, (neg == 0 ? 1 : 0));
+ }
+ else if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) {
+ ONOFF(option, ONIG_OPTION_MULTILINE, neg);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
#ifdef USE_POSIXLINE_OPTION
- case 'p':
- ONOFF(option, ONIG_OPTION_MULTILINE|ONIG_OPTION_SINGLELINE, neg);
- break;
+ case 'p':
+ ONOFF(option, ONIG_OPTION_MULTILINE|ONIG_OPTION_SINGLELINE, neg);
+ break;
#endif
- case 'a': /* limits \d, \s, \w and POSIX brackets to ASCII range */
- if ((IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) ||
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) &&
- (neg == 0)) {
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 0);
- ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 1);
- ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 1);
- }
- else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- break;
-
- case 'u':
- if ((IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) ||
- IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) &&
- (neg == 0)) {
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
- ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 1);
- ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 1);
- }
- else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- break;
-
- case 'd':
- if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) &&
- (neg == 0)) {
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
- }
- else if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY) &&
- (neg == 0)) {
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 0);
- ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 0);
- ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 0);
- }
- else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- break;
-
- case 'l':
- if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) && (neg == 0)) {
- ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
- }
- else
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- break;
-
- default:
- return ONIGERR_UNDEFINED_GROUP_OPTION;
- }
-
- if (c == ')') {
- *np = node_new_option(option);
- CHECK_NULL_RETURN_MEMERR(*np);
- *src = p;
- return 2; /* option only */
- }
- else if (c == ':') {
- OnigOptionType prev = env->option;
-
- env->option = option;
- r = fetch_token(tok, &p, end, env);
- if (r < 0) {
- env->option = prev;
- return r;
- }
- r = parse_subexp(&target, tok, term, &p, end, env);
- env->option = prev;
- if (r < 0) return r;
- *np = node_new_option(option);
- CHECK_NULL_RETURN_MEMERR(*np);
- NENCLOSE(*np)->target = target;
- *src = p;
- return 0;
- }
-
- if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
- PFETCH(c);
- }
+ case 'a': /* limits \d, \s, \w and POSIX brackets to ASCII range */
+ if ((IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) ||
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) &&
+ (neg == 0)) {
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 0);
+ ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 1);
+ ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 1);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ case 'u':
+ if ((IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) ||
+ IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY)) &&
+ (neg == 0)) {
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
+ ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 1);
+ ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 1);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ case 'd':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) &&
+ (neg == 0)) {
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
+ }
+ else if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_RUBY) &&
+ (neg == 0)) {
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 0);
+ ONOFF(option, ONIG_OPTION_POSIX_BRACKET_ALL_RANGE, 0);
+ ONOFF(option, ONIG_OPTION_WORD_BOUND_ALL_RANGE, 0);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ case 'l':
+ if (IS_SYNTAX_OP2(env->syntax, ONIG_SYN_OP2_OPTION_PERL) && (neg == 0)) {
+ ONOFF(option, ONIG_OPTION_ASCII_RANGE, 1);
+ }
+ else
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ break;
+
+ default:
+ return ONIGERR_UNDEFINED_GROUP_OPTION;
+ }
+
+ if (c == ')') {
+ *np = node_new_option(option);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ *src = p;
+ return 2; /* option only */
+ }
+ else if (c == ':') {
+ OnigOptionType prev = env->option;
+
+ env->option = option;
+ r = fetch_token(tok, &p, end, env);
+ if (r < 0) {
+ env->option = prev;
+ return r;
+ }
+ r = parse_subexp(&target, tok, term, &p, end, env);
+ env->option = prev;
+ if (r < 0) return r;
+ *np = node_new_option(option);
+ CHECK_NULL_RETURN_MEMERR(*np);
+ NENCLOSE(*np)->target = target;
+ *src = p;
+ return 0;
+ }
+
+ if (PEND) return ONIGERR_END_PATTERN_IN_GROUP;
+ PFETCH(c);
+ }
}
break;
@@ -5486,14 +5490,14 @@ parse_enclose(Node** np, OnigToken* tok, int term, UChar** src, UChar* end,
}
else if (NENCLOSE(*np)->type == ENCLOSE_CONDITION) {
if (NTYPE(target) != NT_ALT) {
- /* convert (?(cond)yes) to (?(cond)yes|empty) */
- work1 = node_new_empty();
- if (IS_NULL(work1)) goto err;
- work2 = onig_node_new_alt(work1, NULL_NODE);
- if (IS_NULL(work2)) goto err;
- work1 = onig_node_new_alt(target, work2);
- if (IS_NULL(work1)) goto err;
- NENCLOSE(*np)->target = work1;
+ /* convert (?(cond)yes) to (?(cond)yes|empty) */
+ work1 = node_new_empty();
+ if (IS_NULL(work1)) goto err;
+ work2 = onig_node_new_alt(work1, NULL_NODE);
+ if (IS_NULL(work2)) goto err;
+ work1 = onig_node_new_alt(target, work2);
+ if (IS_NULL(work1)) goto err;
+ NENCLOSE(*np)->target = work1;
}
}
}
@@ -5532,11 +5536,11 @@ set_quantifier(Node* qnode, Node* target, int group, ScanEnv* env)
if (! group) {
StrNode* sn = NSTR(target);
if (str_node_can_be_split(sn, env->enc)) {
- Node* n = str_node_split_last_char(sn, env->enc);
- if (IS_NOT_NULL(n)) {
- qn->target = n;
- return 2;
- }
+ Node* n = str_node_split_last_char(sn, env->enc);
+ if (IS_NOT_NULL(n)) {
+ qn->target = n;
+ return 2;
+ }
}
}
break;
@@ -5550,43 +5554,43 @@ set_quantifier(Node* qnode, Node* target, int group, ScanEnv* env)
#ifdef USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR
if (nestq_num >= 0 && targetq_num >= 0 &&
- IS_SYNTAX_BV(env->syntax, ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT)) {
- switch (ReduceTypeTable[targetq_num][nestq_num]) {
- case RQ_ASIS:
- break;
-
- case RQ_DEL:
- if (onig_warn != onig_null_warn) {
- onig_syntax_warn(env, "regular expression has redundant nested repeat operator '%s'",
- PopularQStr[targetq_num]);
- }
- goto warn_exit;
- break;
-
- default:
- if (onig_warn != onig_null_warn) {
- onig_syntax_warn(env, "nested repeat operator '%s' and '%s' was replaced with '%s' in regular expression",
- PopularQStr[targetq_num], PopularQStr[nestq_num],
- ReduceQStr[ReduceTypeTable[targetq_num][nestq_num]]);
- }
- goto warn_exit;
- break;
- }
+ IS_SYNTAX_BV(env->syntax, ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT)) {
+ switch (ReduceTypeTable[targetq_num][nestq_num]) {
+ case RQ_ASIS:
+ break;
+
+ case RQ_DEL:
+ if (onig_warn != onig_null_warn) {
+ onig_syntax_warn(env, "regular expression has redundant nested repeat operator '%s'",
+ PopularQStr[targetq_num]);
+ }
+ goto warn_exit;
+ break;
+
+ default:
+ if (onig_warn != onig_null_warn) {
+ onig_syntax_warn(env, "nested repeat operator '%s' and '%s' was replaced with '%s' in regular expression",
+ PopularQStr[targetq_num], PopularQStr[nestq_num],
+ ReduceQStr[ReduceTypeTable[targetq_num][nestq_num]]);
+ }
+ goto warn_exit;
+ break;
+ }
}
warn_exit:
#endif
if (targetq_num >= 0) {
- if (nestq_num >= 0) {
- onig_reduce_nested_quantifier(qnode, target);
- goto q_exit;
- }
- else if (targetq_num == 1 || targetq_num == 2) { /* * or + */
- /* (?:a*){n,m}, (?:a+){n,m} => (?:a*){n,n}, (?:a+){n,n} */
- if (! IS_REPEAT_INFINITE(qn->upper) && qn->upper > 1 && qn->greedy) {
- qn->upper = (qn->lower == 0 ? 1 : qn->lower);
- }
- }
+ if (nestq_num >= 0) {
+ onig_reduce_nested_quantifier(qnode, target);
+ goto q_exit;
+ }
+ else if (targetq_num == 1 || targetq_num == 2) { /* * or + */
+ /* (?:a*){n,m}, (?:a+){n,m} => (?:a*){n,n}, (?:a+){n,n} */
+ if (! IS_REPEAT_INFINITE(qn->upper) && qn->upper > 1 && qn->greedy) {
+ qn->upper = (qn->lower == 0 ? 1 : qn->lower);
+ }
+ }
}
}
break;
@@ -5652,7 +5656,7 @@ typedef struct {
static int
i_apply_case_fold(OnigCodePoint from, OnigCodePoint to[],
- int to_len, void* arg)
+ int to_len, void* arg)
{
IApplyCaseFoldArg* iarg;
ScanEnv* env;
@@ -5683,11 +5687,12 @@ i_apply_case_fold(OnigCodePoint from, OnigCodePoint to[],
int is_in = onig_is_code_in_cc(env->enc, from, cc);
#ifdef CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
if ((is_in != 0 && !IS_NCCLASS_NOT(cc)) ||
- (is_in == 0 && IS_NCCLASS_NOT(cc))) {
+ (is_in == 0 && IS_NCCLASS_NOT(cc))) {
if (add_flag) {
if (is_singlebyte_range(*to, env->enc)) {
BITSET_SET_BIT(bs, *to);
- } else {
+ }
+ else {
r = add_code_range0(&(cc->mbuf), env, *to, *to, 0);
if (r < 0) return r;
}
@@ -5699,10 +5704,12 @@ i_apply_case_fold(OnigCodePoint from, OnigCodePoint to[],
if (is_singlebyte_range(*to, env->enc)) {
if (IS_NCCLASS_NOT(cc)) {
BITSET_CLEAR_BIT(bs, *to);
- } else {
+ }
+ else {
BITSET_SET_BIT(bs, *to);
}
- } else {
+ }
+ else {
if (IS_NCCLASS_NOT(cc)) clear_not_flag_cclass(cc, env->enc);
r = add_code_range0(&(cc->mbuf), env, *to, *to, 0);
if (r < 0) return r;
@@ -5718,26 +5725,26 @@ i_apply_case_fold(OnigCodePoint from, OnigCodePoint to[],
if (onig_is_code_in_cc(env->enc, from, cc)
#ifdef CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS
- && !IS_NCCLASS_NOT(cc)
+ && !IS_NCCLASS_NOT(cc)
#endif
- ) {
+ ) {
for (i = 0; i < to_len; i++) {
- len = ONIGENC_CODE_TO_MBC(env->enc, to[i], buf);
- if (i == 0) {
- snode = onig_node_new_str(buf, buf + len);
- CHECK_NULL_RETURN_MEMERR(snode);
-
- /* char-class expanded multi-char only
- compare with string folded at match time. */
- NSTRING_SET_AMBIG(snode);
- }
- else {
- r = onig_node_str_cat(snode, buf, buf + len);
- if (r < 0) {
- onig_node_free(snode);
- return r;
- }
- }
+ len = ONIGENC_CODE_TO_MBC(env->enc, to[i], buf);
+ if (i == 0) {
+ snode = onig_node_new_str(buf, buf + len);
+ CHECK_NULL_RETURN_MEMERR(snode);
+
+ /* char-class expanded multi-char only
+ compare with string folded at match time. */
+ NSTRING_SET_AMBIG(snode);
+ }
+ else {
+ r = onig_node_str_cat(snode, buf, buf + len);
+ if (r < 0) {
+ onig_node_free(snode);
+ return r;
+ }
+ }
}
*(iarg->ptail) = onig_node_new_alt(snode, NULL_NODE);
@@ -5762,7 +5769,7 @@ cclass_case_fold(Node** np, CClassNode* cc, CClassNode* asc_cc, ScanEnv* env)
iarg.ptail = &(iarg.alt_root);
r = ONIGENC_APPLY_ALL_CASE_FOLD(env->enc, env->case_fold_flag,
- i_apply_case_fold, &iarg);
+ i_apply_case_fold, &iarg);
if (r != 0) {
onig_node_free(iarg.alt_root);
return r;
@@ -6267,8 +6274,8 @@ is_onechar_cclass(CClassNode* cc, OnigCodePoint* code)
/* only one char found in the bbuf, save the code point. */
c = data[0];
if (((c < SINGLE_BYTE_SIZE) && BITSET_AT(cc->bs, c))) {
- /* skip if c is included in the bitset */
- c = not_found;
+ /* skip if c is included in the bitset */
+ c = not_found;
}
}
else {
@@ -6281,9 +6288,10 @@ is_onechar_cclass(CClassNode* cc, OnigCodePoint* code)
Bits b1 = cc->bs[i];
if (b1 != 0) {
if (((b1 & (b1 - 1)) == 0) && (c == not_found)) {
- c = BITS_IN_ROOM * i + countbits(b1 - 1);
- } else {
- return 0; /* the character class contains multiple chars */
+ c = BITS_IN_ROOM * i + countbits(b1 - 1);
+ }
+ else {
+ return 0; /* the character class contains multiple chars */
}
}
}
@@ -6300,16 +6308,19 @@ is_onechar_cclass(CClassNode* cc, OnigCodePoint* code)
static int
parse_exp(Node** np, OnigToken* tok, int term,
- UChar** src, UChar* end, ScanEnv* env)
+ UChar** src, UChar* end, ScanEnv* env)
{
int r, len, group = 0;
Node* qn;
Node** targetp;
+ unsigned int parse_depth;
*np = NULL;
if (tok->type == (enum TokenSyms )term)
goto end_of_token;
+ parse_depth = env->parse_depth;
+
switch (tok->type) {
case TK_ALT:
case TK_EOT:
@@ -6329,14 +6340,14 @@ parse_exp(Node** np, OnigToken* tok, int term,
env->option = NENCLOSE(*np)->option;
r = fetch_token(tok, src, end, env);
if (r < 0) {
- env->option = prev;
- return r;
+ env->option = prev;
+ return r;
}
r = parse_subexp(&target, tok, term, src, end, env);
env->option = prev;
if (r < 0) {
- onig_node_free(target);
- return r;
+ onig_node_free(target);
+ return r;
}
NENCLOSE(*np)->target = target;
return tok->type;
@@ -6374,20 +6385,20 @@ parse_exp(Node** np, OnigToken* tok, int term,
string_loop:
while (1) {
- r = fetch_token(tok, src, end, env);
- if (r < 0) return r;
- if (r == TK_STRING) {
- r = onig_node_str_cat(*np, tok->backp, *src);
- }
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ if (r == TK_STRING) {
+ r = onig_node_str_cat(*np, tok->backp, *src);
+ }
#ifndef NUMBERED_CHAR_IS_NOT_CASE_AMBIG
- else if (r == TK_CODE_POINT) {
- r = node_str_cat_codepoint(*np, env->enc, tok->u.code);
- }
+ else if (r == TK_CODE_POINT) {
+ r = node_str_cat_codepoint(*np, env->enc, tok->u.code);
+ }
#endif
- else {
- break;
- }
- if (r < 0) return r;
+ else {
+ break;
+ }
+ if (r < 0) return r;
}
string_end:
@@ -6403,36 +6414,36 @@ parse_exp(Node** np, OnigToken* tok, int term,
CHECK_NULL_RETURN_MEMERR(*np);
len = 1;
while (1) {
- if (len >= ONIGENC_MBC_MINLEN(env->enc)) {
- if (len == enclen(env->enc, NSTR(*np)->s, NSTR(*np)->end)) {
- r = fetch_token(tok, src, end, env);
- NSTRING_CLEAR_RAW(*np);
- goto string_end;
- }
- }
-
- r = fetch_token(tok, src, end, env);
- if (r < 0) return r;
- if (r != TK_RAW_BYTE) {
- /* Don't use this, it is wrong for little endian encodings. */
+ if (len >= ONIGENC_MBC_MINLEN(env->enc)) {
+ if (len == enclen(env->enc, NSTR(*np)->s, NSTR(*np)->end)) {
+ r = fetch_token(tok, src, end, env);
+ NSTRING_CLEAR_RAW(*np);
+ goto string_end;
+ }
+ }
+
+ r = fetch_token(tok, src, end, env);
+ if (r < 0) return r;
+ if (r != TK_RAW_BYTE) {
+ /* Don't use this, it is wrong for little endian encodings. */
#ifdef USE_PAD_TO_SHORT_BYTE_CHAR
- int rem;
- if (len < ONIGENC_MBC_MINLEN(env->enc)) {
- rem = ONIGENC_MBC_MINLEN(env->enc) - len;
- (void )node_str_head_pad(NSTR(*np), rem, (UChar )0);
- if (len + rem == enclen(env->enc, NSTR(*np)->s)) {
- NSTRING_CLEAR_RAW(*np);
- goto string_end;
- }
- }
+ int rem;
+ if (len < ONIGENC_MBC_MINLEN(env->enc)) {
+ rem = ONIGENC_MBC_MINLEN(env->enc) - len;
+ (void )node_str_head_pad(NSTR(*np), rem, (UChar )0);
+ if (len + rem == enclen(env->enc, NSTR(*np)->s)) {
+ NSTRING_CLEAR_RAW(*np);
+ goto string_end;
+ }
+ }
#endif
- return ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
- }
+ return ONIGERR_TOO_SHORT_MULTI_BYTE_STRING;
+ }
- r = node_str_cat_char(*np, (UChar )tok->u.c);
- if (r < 0) return r;
+ r = node_str_cat_char(*np, (UChar )tok->u.c);
+ if (r < 0) return r;
- len++;
+ len++;
}
}
break;
@@ -6461,7 +6472,7 @@ parse_exp(Node** np, OnigToken* tok, int term,
qstart = *src;
qend = find_str_position(end_op, 2, qstart, end, &nextp, env->enc);
if (IS_NULL(qend)) {
- nextp = qend = end;
+ nextp = qend = end;
}
*np = node_new_str(qstart, qend);
CHECK_NULL_RETURN_MEMERR(*np);
@@ -6473,30 +6484,30 @@ parse_exp(Node** np, OnigToken* tok, int term,
{
switch (tok->u.prop.ctype) {
case ONIGENC_CTYPE_WORD:
- *np = node_new_ctype(tok->u.prop.ctype, tok->u.prop.not,
- IS_ASCII_RANGE(env->option));
- CHECK_NULL_RETURN_MEMERR(*np);
- break;
+ *np = node_new_ctype(tok->u.prop.ctype, tok->u.prop.not,
+ IS_ASCII_RANGE(env->option));
+ CHECK_NULL_RETURN_MEMERR(*np);
+ break;
case ONIGENC_CTYPE_SPACE:
case ONIGENC_CTYPE_DIGIT:
case ONIGENC_CTYPE_XDIGIT:
- {
- CClassNode* cc;
-
- *np = node_new_cclass();
- CHECK_NULL_RETURN_MEMERR(*np);
- cc = NCCLASS(*np);
- r = add_ctype_to_cc(cc, tok->u.prop.ctype, 0,
- IS_ASCII_RANGE(env->option), env);
- if (r != 0) return r;
- if (tok->u.prop.not != 0) NCCLASS_SET_NOT(cc);
- }
- break;
+ {
+ CClassNode* cc;
+
+ *np = node_new_cclass();
+ CHECK_NULL_RETURN_MEMERR(*np);
+ cc = NCCLASS(*np);
+ r = add_ctype_to_cc(cc, tok->u.prop.ctype, 0,
+ IS_ASCII_RANGE(env->option), env);
+ if (r != 0) return r;
+ if (tok->u.prop.not != 0) NCCLASS_SET_NOT(cc);
+ }
+ break;
default:
- return ONIGERR_PARSER_BUG;
- break;
+ return ONIGERR_PARSER_BUG;
+ break;
}
}
break;
@@ -6514,26 +6525,26 @@ parse_exp(Node** np, OnigToken* tok, int term,
r = parse_char_class(np, &asc_node, tok, src, end, env);
if (r != 0) {
- onig_node_free(asc_node);
- return r;
+ onig_node_free(asc_node);
+ return r;
}
cc = NCCLASS(*np);
if (is_onechar_cclass(cc, &code)) {
- onig_node_free(*np);
- onig_node_free(asc_node);
- *np = node_new_empty();
- CHECK_NULL_RETURN_MEMERR(*np);
- r = node_str_cat_codepoint(*np, env->enc, code);
- if (r != 0) return r;
- goto string_loop;
+ onig_node_free(*np);
+ onig_node_free(asc_node);
+ *np = node_new_empty();
+ CHECK_NULL_RETURN_MEMERR(*np);
+ r = node_str_cat_codepoint(*np, env->enc, code);
+ if (r != 0) return r;
+ goto string_loop;
}
if (IS_IGNORECASE(env->option)) {
- r = cclass_case_fold(np, cc, NCCLASS(asc_node), env);
- if (r != 0) {
- onig_node_free(asc_node);
- return r;
- }
+ r = cclass_case_fold(np, cc, NCCLASS(asc_node), env);
+ if (r != 0) {
+ onig_node_free(asc_node);
+ return r;
+ }
}
onig_node_free(asc_node);
}
@@ -6556,13 +6567,13 @@ parse_exp(Node** np, OnigToken* tok, int term,
case TK_BACKREF:
len = tok->u.backref.num;
*np = node_new_backref(len,
- (len > 1 ? tok->u.backref.refs : &(tok->u.backref.ref1)),
- tok->u.backref.by_name,
+ (len > 1 ? tok->u.backref.refs : &(tok->u.backref.ref1)),
+ tok->u.backref.by_name,
#ifdef USE_BACKREF_WITH_LEVEL
- tok->u.backref.exist_level,
- tok->u.backref.level,
+ tok->u.backref.exist_level,
+ tok->u.backref.level,
#endif
- env);
+ env);
CHECK_NULL_RETURN_MEMERR(*np);
break;
@@ -6572,10 +6583,10 @@ parse_exp(Node** np, OnigToken* tok, int term,
int gnum = tok->u.call.gnum;
if (gnum < 0 || tok->u.call.rel != 0) {
- if (gnum > 0) gnum--;
- gnum = BACKREF_REL_TO_ABS(gnum, env);
- if (gnum <= 0)
- return ONIGERR_INVALID_BACKREF;
+ if (gnum > 0) gnum--;
+ gnum = BACKREF_REL_TO_ABS(gnum, env);
+ if (gnum <= 0)
+ return ONIGERR_INVALID_BACKREF;
}
*np = node_new_call(tok->u.call.name, tok->u.call.name_end, gnum);
CHECK_NULL_RETURN_MEMERR(*np);
@@ -6594,9 +6605,9 @@ parse_exp(Node** np, OnigToken* tok, int term,
case TK_INTERVAL:
if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_CONTEXT_INDEP_REPEAT_OPS)) {
if (IS_SYNTAX_BV(env->syntax, ONIG_SYN_CONTEXT_INVALID_REPEAT_OPS))
- return ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED;
+ return ONIGERR_TARGET_OF_REPEAT_OPERATOR_NOT_SPECIFIED;
else
- *np = node_new_empty();
+ *np = node_new_empty();
}
else {
goto tk_byte;
@@ -6618,49 +6629,53 @@ parse_exp(Node** np, OnigToken* tok, int term,
repeat:
if (r == TK_OP_REPEAT || r == TK_INTERVAL) {
if (is_invalid_quantifier_target(*targetp))
- return ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID;
+ return ONIGERR_TARGET_OF_REPEAT_OPERATOR_INVALID;
+
+ parse_depth++;
+ if (parse_depth > ParseDepthLimit)
+ return ONIGERR_PARSE_DEPTH_LIMIT_OVER;
qn = node_new_quantifier(tok->u.repeat.lower, tok->u.repeat.upper,
- (r == TK_INTERVAL ? 1 : 0));
+ (r == TK_INTERVAL ? 1 : 0));
CHECK_NULL_RETURN_MEMERR(qn);
NQTFR(qn)->greedy = tok->u.repeat.greedy;
r = set_quantifier(qn, *targetp, group, env);
if (r < 0) {
- onig_node_free(qn);
- return r;
+ onig_node_free(qn);
+ return r;
}
if (tok->u.repeat.possessive != 0) {
- Node* en;
- en = node_new_enclose(ENCLOSE_STOP_BACKTRACK);
- if (IS_NULL(en)) {
- onig_node_free(qn);
- return ONIGERR_MEMORY;
- }
- NENCLOSE(en)->target = qn;
- qn = en;
+ Node* en;
+ en = node_new_enclose(ENCLOSE_STOP_BACKTRACK);
+ if (IS_NULL(en)) {
+ onig_node_free(qn);
+ return ONIGERR_MEMORY;
+ }
+ NENCLOSE(en)->target = qn;
+ qn = en;
}
if (r == 0) {
- *targetp = qn;
+ *targetp = qn;
}
else if (r == 1) {
- onig_node_free(qn);
+ onig_node_free(qn);
}
else if (r == 2) { /* split case: /abc+/ */
- Node *tmp;
-
- *targetp = node_new_list(*targetp, NULL);
- if (IS_NULL(*targetp)) {
- onig_node_free(qn);
- return ONIGERR_MEMORY;
- }
- tmp = NCDR(*targetp) = node_new_list(qn, NULL);
- if (IS_NULL(tmp)) {
- onig_node_free(qn);
- return ONIGERR_MEMORY;
- }
- targetp = &(NCAR(tmp));
+ Node *tmp;
+
+ *targetp = node_new_list(*targetp, NULL);
+ if (IS_NULL(*targetp)) {
+ onig_node_free(qn);
+ return ONIGERR_MEMORY;
+ }
+ tmp = NCDR(*targetp) = node_new_list(qn, NULL);
+ if (IS_NULL(tmp)) {
+ onig_node_free(qn);
+ return ONIGERR_MEMORY;
+ }
+ targetp = &(NCAR(tmp));
}
goto re_entry;
}
@@ -6671,7 +6686,7 @@ parse_exp(Node** np, OnigToken* tok, int term,
static int
parse_branch(Node** top, OnigToken* tok, int term,
- UChar** src, UChar* end, ScanEnv* env)
+ UChar** src, UChar* end, ScanEnv* env)
{
int r;
Node *node, **headp;
@@ -6692,18 +6707,18 @@ parse_branch(Node** top, OnigToken* tok, int term,
while (r != TK_EOT && r != term && r != TK_ALT) {
r = parse_exp(&node, tok, term, src, end, env);
if (r < 0) {
- onig_node_free(node);
- return r;
+ onig_node_free(node);
+ return r;
}
if (NTYPE(node) == NT_LIST) {
- *headp = node;
- while (IS_NOT_NULL(NCDR(node))) node = NCDR(node);
- headp = &(NCDR(node));
+ *headp = node;
+ while (IS_NOT_NULL(NCDR(node))) node = NCDR(node);
+ headp = &(NCDR(node));
}
else {
- *headp = node_new_list(node, NULL);
- headp = &(NCDR(*headp));
+ *headp = node_new_list(node, NULL);
+ headp = &(NCDR(*headp));
}
}
}
@@ -6714,10 +6729,10 @@ parse_branch(Node** top, OnigToken* tok, int term,
/* term_tok: TK_EOT or TK_SUBEXP_CLOSE */
static int
parse_subexp(Node** top, OnigToken* tok, int term,
- UChar** src, UChar* end, ScanEnv* env)
+ UChar** src, UChar* end, ScanEnv* env)
{
int r;
- Node *node, **headp;
+ Node *node, *topnode, **headp;
*top = NULL;
env->parse_depth++;
@@ -6733,26 +6748,29 @@ parse_subexp(Node** top, OnigToken* tok, int term,
*top = node;
}
else if (r == TK_ALT) {
- *top = onig_node_new_alt(node, NULL);
- headp = &(NCDR(*top));
+ topnode = onig_node_new_alt(node, NULL);
+ headp = &(NCDR(topnode));
while (r == TK_ALT) {
r = fetch_token(tok, src, end, env);
if (r < 0) {
- onig_node_free(node);
- return r;
+ onig_node_free(topnode);
+ return r;
}
r = parse_branch(&node, tok, term, src, end, env);
if (r < 0) {
- onig_node_free(node);
- return r;
+ onig_node_free(topnode);
+ return r;
}
*headp = onig_node_new_alt(node, NULL);
- headp = &(NCDR(*headp));
+ headp = &(NCDR(*headp));
}
- if (tok->type != (enum TokenSyms )term)
+ if (tok->type != (enum TokenSyms )term) {
+ onig_node_free(topnode);
goto err;
+ }
+ *top = topnode;
}
else {
onig_node_free(node);
@@ -6789,8 +6807,8 @@ parse_regexp(Node** top, UChar** src, UChar* end, ScanEnv* env)
NENCLOSE(np)->target = *top;
r = scan_env_set_mem_node(env, num, np);
if (r != 0) {
- onig_node_free(np);
- return r;
+ onig_node_free(np);
+ return r;
}
*top = np;
}
@@ -6800,7 +6818,7 @@ parse_regexp(Node** top, UChar** src, UChar* end, ScanEnv* env)
extern int
onig_parse_make_tree(Node** root, const UChar* pattern, const UChar* end,
- regex_t* reg, ScanEnv* env)
+ regex_t* reg, ScanEnv* env)
{
int r;
UChar* p;
@@ -6827,7 +6845,7 @@ onig_parse_make_tree(Node** root, const UChar* pattern, const UChar* end,
extern void
onig_scan_env_set_error_string(ScanEnv* env, int ecode ARG_UNUSED,
- UChar* arg, UChar* arg_end)
+ UChar* arg, UChar* arg_end)
{
env->error = arg;
env->error_end = arg_end;
diff --git a/regparse.h b/regparse.h
index de980d0ac8..65da835a55 100644
--- a/regparse.h
+++ b/regparse.h
@@ -5,7 +5,7 @@
**********************************************************************/
/*-
* Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2016 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -69,8 +69,8 @@ RUBY_SYMBOL_EXPORT_BEGIN
#define NTYPE(node) ((node)->u.base.type)
#define SET_NTYPE(node, ntype) \
do { \
- int value = ntype; \
- memcpy(&((node)->u.base.type), &value, sizeof(int)); \
+ int value = ntype; \
+ memcpy(&((node)->u.base.type), &value, sizeof(int)); \
} while (0)
#define NSTR(node) (&((node)->u.str))
diff --git a/ruby.c b/ruby.c
index 49d6b3d091..162287ca71 100644
--- a/ruby.c
+++ b/ruby.c
@@ -106,6 +106,8 @@ void rb_warning_category_update(unsigned int mask, unsigned int bits);
X(frozen_string_literal) \
SEP \
X(yjit) \
+ SEP \
+ X(zjit) \
/* END OF FEATURES */
#define EACH_DEBUG_FEATURES(X, SEP) \
X(frozen_string_literal) \
@@ -117,8 +119,12 @@ enum feature_flag_bits {
EACH_FEATURES(DEFINE_FEATURE, COMMA),
DEFINE_FEATURE(frozen_string_literal_set),
feature_debug_flag_first,
+#if !USE_YJIT && USE_ZJIT
+ DEFINE_FEATURE(jit) = feature_zjit,
+#else
DEFINE_FEATURE(jit) = feature_yjit,
- feature_jit_mask = FEATURE_BIT(yjit),
+#endif
+ feature_jit_mask = FEATURE_BIT(yjit) | FEATURE_BIT(zjit),
feature_debug_flag_begin = feature_debug_flag_first - 1,
EACH_DEBUG_FEATURES(DEFINE_DEBUG_FEATURE, COMMA),
@@ -299,13 +305,17 @@ ruby_show_usage_line(const char *name, const char *secondary, const char *descri
description, help, highlight, width, columns);
}
+RUBY_EXTERN const char ruby_api_version_name[];
+
static void
usage(const char *name, int help, int highlight, int columns)
{
#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
#if USE_YJIT
-# define PLATFORM_JIT_OPTION "--yjit"
+# define DEFAULT_JIT_OPTION "--yjit"
+#elif USE_ZJIT
+# define DEFAULT_JIT_OPTION "--zjit"
#endif
/* This message really ought to be max 23 lines.
@@ -316,7 +326,7 @@ usage(const char *name, int help, int highlight, int columns)
M("-a", "", "Split each input line ($_) into fields ($F)."),
M("-c", "", "Check syntax (no execution)."),
M("-Cdirpath", "", "Execute program in specified directory."),
- M("-d", ", --debug", "Set debugging flag ($DEBUG) to true."),
+ M("-d", ", --debug", "Set debugging flag ($DEBUG) and $VERBOSE to true."),
M("-e 'code'", "", "Execute given Ruby code; multiple -e allowed."),
M("-Eex[:in]", ", --encoding=ex[:in]", "Set default external and internal encodings."),
M("-Fpattern", "", "Set input field separator ($;); used with -a."),
@@ -336,15 +346,18 @@ usage(const char *name, int help, int highlight, int columns)
M("-W[level=2|:category]", "", "Set warning flag ($-W):\n"
"0 for silent; 1 for moderate; 2 for verbose."),
M("-x[dirpath]", "", "Execute Ruby code starting from a #!ruby line."),
-#if USE_YJIT
- M("--jit", "", "Enable JIT for the platform; same as " PLATFORM_JIT_OPTION "."),
+#if USE_YJIT || USE_ZJIT
+ M("--jit", "", "Enable the default JIT for the build; same as " DEFAULT_JIT_OPTION "."),
#endif
#if USE_YJIT
M("--yjit", "", "Enable in-process JIT compiler."),
#endif
+#if USE_ZJIT
+ M("--zjit", "", "Enable method-based JIT compiler."),
+#endif
M("-h", "", "Print this help message; use --help for longer message."),
};
- STATIC_ASSERT(usage_msg_size, numberof(usage_msg) < 25);
+ STATIC_ASSERT(usage_msg_size, numberof(usage_msg) < 26);
static const struct ruby_opt_message help_msg[] = {
M("--backtrace-limit=num", "", "Set backtrace limit."),
@@ -379,6 +392,9 @@ usage(const char *name, int help, int highlight, int columns)
#if USE_YJIT
M("yjit", "", "In-process JIT compiler (default: disabled)."),
#endif
+#if USE_ZJIT
+ M("zjit", "", "Method-based JIT compiler (default: disabled)."),
+#endif
};
static const struct ruby_opt_message warn_categories[] = {
M("deprecated", "", "Deprecated features."),
@@ -416,6 +432,11 @@ usage(const char *name, int help, int highlight, int columns)
printf("%s""YJIT options:%s\n", sb, se);
rb_yjit_show_usage(help, highlight, w, columns);
#endif
+#if USE_ZJIT
+ printf("%s""ZJIT options:%s\n", sb, se);
+ extern void rb_zjit_show_usage(int help, int highlight, unsigned int width, int columns);
+ rb_zjit_show_usage(help, highlight, w, columns);
+#endif
}
#define rubylib_path_new rb_str_new
@@ -425,7 +446,7 @@ ruby_push_include(const char *path, VALUE (*filter)(VALUE))
{
const char sep = PATH_SEP_CHAR;
const char *p, *s;
- VALUE load_path = GET_VM()->load_path;
+ VALUE load_path = rb_root_box()->load_path;
#ifdef __CYGWIN__
char rubylib[FILENAME_MAX];
VALUE buf = 0;
@@ -730,7 +751,7 @@ ruby_init_loadpath(void)
rb_gc_register_address(&ruby_archlibdir_path);
ruby_archlibdir_path = archlibdir;
- load_path = GET_VM()->load_path;
+ load_path = rb_root_box()->load_path;
ruby_push_include(getenv("RUBYLIB"), identical_path);
@@ -742,8 +763,6 @@ ruby_init_loadpath(void)
rb_ary_push(load_path, path);
paths += len + 1;
}
-
- rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), ruby_prefix_path);
}
@@ -779,6 +798,25 @@ require_libraries(VALUE *req_list)
*req_list = 0;
}
+static void
+require_libraries_in_main_box(VALUE *req_list)
+{
+ const rb_box_t *main_box = rb_main_box();
+ VALUE list = *req_list;
+ ID require;
+ rb_encoding *extenc = rb_default_external_encoding();
+
+ CONST_ID(require, "require");
+ while (list && RARRAY_LEN(list) > 0) {
+ VALUE feature = rb_ary_shift(list);
+ rb_enc_associate(feature, extenc);
+ RBASIC_SET_CLASS_RAW(feature, rb_cString);
+ OBJ_FREEZE(feature);
+ rb_funcallv(main_box->box_object, require, 1, &feature);
+ }
+ *req_list = 0;
+}
+
static const struct rb_block*
toplevel_context(rb_binding_t *bind)
{
@@ -894,7 +932,9 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
argc = RSTRING_LEN(argary) / sizeof(ap);
ap = 0;
rb_str_cat(argary, (char *)&ap, sizeof(ap));
- argv = ptr = ALLOC_N(char *, argc);
+
+ VALUE ptr_obj;
+ argv = ptr = RB_ALLOCV_N(char *, ptr_obj, argc);
MEMMOVE(argv, RSTRING_PTR(argary), char *, argc);
while ((i = proc_options(argc, argv, opt, envopt)) > 1 && envopt && (argc -= i) > 0) {
@@ -926,7 +966,8 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
opt->crash_report = crash_report;
}
- ruby_xfree(ptr);
+ RB_ALLOCV_END(ptr_obj);
+
/* get rid of GC */
rb_str_resize(argary, 0);
rb_str_resize(argstr, 0);
@@ -1181,6 +1222,19 @@ setup_yjit_options(const char *s)
}
#endif
+#if USE_ZJIT
+static void
+setup_zjit_options(const char *s)
+{
+ // The option parsing is done in zjit/src/options.rs
+ extern bool rb_zjit_parse_option(const char *s);
+
+ if (!rb_zjit_parse_option(s)) {
+ rb_raise(rb_eRuntimeError, "invalid ZJIT option '%s' (--help will show valid zjit options)", s);
+ }
+}
+#endif
+
/*
* Following proc_*_option functions are tree kinds:
*
@@ -1338,7 +1392,7 @@ proc_0_option(ruby_cmdline_options_t *opt, const char *s)
static void
proc_encoding_option(ruby_cmdline_options_t *opt, const char *s, const char *opt_name)
{
- char *p;
+ const char *p;
# define set_encoding_part(type) \
if (!(p = strchr(s, ':'))) { \
set_##type##_encoding_once(opt, s, 0); \
@@ -1435,7 +1489,7 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **
ruby_verbose = Qtrue;
}
else if (strcmp("jit", s) == 0) {
-#if USE_YJIT
+#if USE_YJIT || USE_ZJIT
FEATURE_SET(opt->features, FEATURE_BIT(jit));
#else
rb_warn("Ruby was built without JIT support");
@@ -1450,6 +1504,15 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **
" You may need to install rustc to build Ruby with YJIT.");
#endif
}
+ else if (is_option_with_optarg("zjit", '-', true, false, false)) {
+#if USE_ZJIT
+ FEATURE_SET(opt->features, FEATURE_BIT(zjit));
+ setup_zjit_options(s);
+#else
+ rb_warn("Ruby was built without ZJIT support."
+ " You may need to install rustc to build Ruby with ZJIT.");
+#endif
+ }
else if (strcmp("yydebug", s) == 0) {
if (envopt) goto noenvopt_long;
opt->dump |= DUMP_BIT(yydebug);
@@ -1727,13 +1790,13 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
return argc0 - argc;
}
+VALUE rb_define_gem_modules(VALUE, VALUE);
void Init_builtin_features(void);
static void
ruby_init_prelude(void)
{
Init_builtin_features();
- rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"));
}
void rb_call_builtin_inits(void);
@@ -1755,26 +1818,6 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
if (opt->dump & dump_exit_bits) return;
- if (FEATURE_SET_P(opt->features, gems)) {
- rb_define_module("Gem");
- if (opt->features.set & FEATURE_BIT(error_highlight)) {
- rb_define_module("ErrorHighlight");
- }
- if (opt->features.set & FEATURE_BIT(did_you_mean)) {
- rb_define_module("DidYouMean");
- }
- if (opt->features.set & FEATURE_BIT(syntax_suggest)) {
- rb_define_module("SyntaxSuggest");
- }
- }
-
- /* [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");
- }
-
Init_ext(); /* load statically linked extensions before rubygems */
Init_extra_exts();
@@ -1783,19 +1826,67 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
GET_VM()->running = 1;
memset(ruby_vm_redefined_flag, 0, sizeof(ruby_vm_redefined_flag));
+ // Register JIT-optimized builtin CMEs before the prelude, which may
+ // redefine core methods (e.g. Kernel.prepend via bundler/setup).
+#if USE_YJIT
+ rb_yjit_init_builtin_cmes();
+#endif
+#if USE_ZJIT
+ extern void rb_zjit_init_builtin_cmes(void);
+ rb_zjit_init_builtin_cmes();
+#endif
+
+ /**
+ * Initialize the root/main boxes before loading libraries to run them
+ * (including RubyGems, written in Ruby) in those boxes themselves
+ */
+ if (rb_box_available()) {
+ rb_initialize_mandatory_boxes();
+ }
+
+ rb_box_init_done();
+
+ if (FEATURE_SET_P(opt->features, gems)) {
+ rb_box_gem_flags_t gem_flags = {
+ .gem = FEATURE_SET_P(opt->features, gems),
+ .error_highlight = opt->features.set & FEATURE_BIT(error_highlight),
+ .did_you_mean = opt->features.set & FEATURE_BIT(did_you_mean),
+ .syntax_suggest = opt->features.set & FEATURE_BIT(syntax_suggest)
+ };
+
+ if (rb_box_available()) {
+ rb_vm_call_cfunc_in_box(Qnil, rb_define_gem_modules, (VALUE)&gem_flags, Qnil,
+ rb_str_new_cstr("before_prelude.root.dummy"), rb_root_box());
+ rb_vm_call_cfunc_in_box(Qnil, rb_define_gem_modules, (VALUE)&gem_flags, Qnil,
+ rb_str_new_cstr("before_prelude.main.dummy"), rb_main_box());
+
+ rb_box_set_gem_flags(&gem_flags);
+ }
+ else {
+ rb_define_gem_modules((VALUE)&gem_flags, Qnil);
+ }
+ }
+
+ // The root/main boxes load gem_prelude here.
+ // User boxes will load it in those #initialize instead.
ruby_init_prelude();
- // Initialize JITs after prelude because JITing prelude is typically not optimal.
+ // Enable JITs after ruby_init_prelude() to avoid JITing prelude code.
#if USE_YJIT
rb_yjit_init(opt->yjit);
#endif
-
- // Call yjit_hook.rb after rb_yjit_init() to use `RubyVM::YJIT.enabled?`
- void Init_builtin_yjit_hook();
- Init_builtin_yjit_hook();
+#if USE_ZJIT
+ extern void rb_zjit_init(bool);
+ rb_zjit_init(opt->zjit);
+#endif
ruby_set_script_name(opt->script_name);
- require_libraries(&opt->req_list);
+ if (rb_box_available()) {
+ require_libraries_in_main_box(&opt->req_list);
+ }
+ else {
+ require_libraries(&opt->req_list);
+ }
}
static int
@@ -1958,7 +2049,7 @@ copy_str(VALUE str, rb_encoding *enc, bool intern)
return rb_enc_interned_str(RSTRING_PTR(str), RSTRING_LEN(str), enc);
}
-#if USE_YJIT
+#if USE_YJIT || USE_ZJIT
// Check that an environment variable is set to a truthy value
static bool
env_var_truthy(const char *name)
@@ -2129,10 +2220,8 @@ prism_script_shebang_callback(pm_options_t *options, const uint8_t *source, size
static void
prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
{
- memset(result, 0, sizeof(pm_parse_result_t));
-
- pm_options_t *options = &result->options;
- pm_options_line_set(options, 1);
+ pm_parse_result_init(result);
+ pm_options_t *options = result->options;
pm_options_main_script_set(options, true);
const bool read_stdin = (strcmp(opt->script, "-") == 0);
@@ -2158,7 +2247,7 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
// If we found an __END__ marker, then we're going to define a global
// DATA constant that is a file object that can be read to read the
// contents after the marker.
- if (NIL_P(error) && result->parser.data_loc.start != NULL) {
+ if (NIL_P(error) && pm_parser_data_loc(result->parser)->length != 0) {
rb_define_global_const("DATA", rb_stdin);
}
}
@@ -2195,17 +2284,20 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
// If we found an __END__ marker, then we're going to define a global
// DATA constant that is a file object that can be read to read the
// contents after the marker.
- if (NIL_P(error) && result->parser.data_loc.start != NULL) {
+ if (NIL_P(error) && pm_parser_data_loc(result->parser)->length != 0) {
int xflag = opt->xflag;
VALUE file = open_load_file(script_name, &xflag);
- const pm_parser_t *parser = &result->parser;
- size_t offset = parser->data_loc.start - parser->start + 7;
+ const pm_parser_t *parser = result->parser;
+ const pm_location_t *data_loc = pm_parser_data_loc(parser);
+ const uint8_t *start = pm_parser_start(parser);
+ const uint8_t *end = pm_parser_end(parser);
+ uint32_t offset = data_loc->start + 7;
- if ((parser->start + offset < parser->end) && parser->start[offset] == '\r') offset++;
- if ((parser->start + offset < parser->end) && parser->start[offset] == '\n') offset++;
+ if ((start + offset < end) && start[offset] == '\r') offset++;
+ if ((start + offset < end) && start[offset] == '\n') offset++;
- rb_funcall(file, rb_intern_const("seek"), 2, SIZET2NUM(offset), INT2FIX(SEEK_SET));
+ rb_funcall(file, rb_intern_const("seek"), 2, UINT2NUM(offset), INT2FIX(SEEK_SET));
rb_define_global_const("DATA", file);
}
}
@@ -2219,11 +2311,11 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
static VALUE
prism_dump_tree(pm_parse_result_t *result)
{
- pm_buffer_t output_buffer = { 0 };
+ pm_buffer_t *output_buffer = pm_buffer_new();
- pm_prettyprint(&output_buffer, &result->parser, result->node.ast_node);
- VALUE tree = rb_str_new(output_buffer.value, output_buffer.length);
- pm_buffer_free(&output_buffer);
+ pm_prettyprint(output_buffer, result->parser, result->node.ast_node);
+ VALUE tree = rb_str_new(pm_buffer_value(output_buffer), pm_buffer_length(output_buffer));
+ pm_buffer_free(output_buffer);
return tree;
}
@@ -2259,6 +2351,16 @@ process_options_global_setup(const ruby_cmdline_options_t *opt, const rb_iseq_t
rb_exec_event_hook_script_compiled(ec, iseq, script);
}
+static bool
+has_dir_sep(const char *path)
+{
+ if (strchr(path, '/')) return true;
+#ifdef _WIN32
+ if (strchr(path, '\\')) return true;
+#endif
+ return false;
+}
+
static VALUE
process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
@@ -2280,8 +2382,8 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
char fbuf[MAXPATHLEN];
int i = (int)proc_options(argc, argv, opt, 0);
unsigned int dump = opt->dump & dump_exit_bits;
- rb_vm_t *vm = GET_VM();
- const long loaded_before_enc = RARRAY_LEN(vm->loaded_features);
+ const rb_box_t *box = rb_root_box();
+ const long loaded_before_enc = RARRAY_LEN(box->loaded_features);
if (opt->dump & (DUMP_BIT(usage)|DUMP_BIT(help))) {
const char *const progname =
@@ -2311,6 +2413,17 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
FEATURE_SET(opt->features, FEATURE_BIT(yjit));
}
#endif
+#if USE_ZJIT
+ if (!FEATURE_USED_P(opt->features, zjit) && env_var_truthy("RUBY_ZJIT_ENABLE")) {
+ FEATURE_SET(opt->features, FEATURE_BIT(zjit));
+
+ // When the --zjit flag is specified, we would have call setup_zjit_options(""),
+ // which would have called rb_zjit_prepare_options() internally. This ensures we
+ // go through the same set up but with less overhead than setup_zjit_options("").
+ extern void rb_zjit_prepare_options();
+ rb_zjit_prepare_options();
+ }
+#endif
}
if (MULTI_BITS_P(FEATURE_SET_BITS(opt->features) & feature_jit_mask)) {
rb_warn("Only one JIT can be enabled at the same time. Exiting");
@@ -2323,6 +2436,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
opt->yjit = !rb_yjit_option_disable(); // set opt->yjit for Init_ruby_description() and calling rb_yjit_init()
}
#endif
+#if USE_ZJIT
+ if (FEATURE_SET_P(opt->features, zjit)) {
+ bool rb_zjit_option_enable(void);
+ opt->zjit = rb_zjit_option_enable(); // set opt->zjit for Init_ruby_description() and calling rb_zjit_init()
+ }
+#endif
ruby_mn_threads_params();
Init_ruby_description(opt);
@@ -2347,7 +2466,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
if (!opt->script || opt->script[0] == '\0') {
opt->script = "-";
}
- else if (opt->do_search) {
+ else if (opt->do_search && !has_dir_sep(opt->script)) {
const char *path = getenv("RUBYPATH");
opt->script = 0;
@@ -2417,7 +2536,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_obj_freeze(opt->script_name);
if (IF_UTF8_PATH(uenc != lenc, 1)) {
long i;
- VALUE load_path = vm->load_path;
+ VALUE load_path = box->load_path;
const ID id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
int modifiable = FALSE;
@@ -2440,11 +2559,11 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
RARRAY_ASET(load_path, i, path);
}
if (modifiable) {
- rb_ary_replace(vm->load_path_snapshot, load_path);
+ rb_ary_replace(box->load_path_snapshot, load_path);
}
}
{
- VALUE loaded_features = vm->loaded_features;
+ VALUE loaded_features = box->loaded_features;
bool modified = false;
for (long i = loaded_before_enc; i < RARRAY_LEN(loaded_features); ++i) {
VALUE path = RARRAY_AREF(loaded_features, i);
@@ -2456,7 +2575,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
RARRAY_ASET(loaded_features, i, path);
}
if (modified) {
- rb_ary_replace(vm->loaded_features_snapshot, loaded_features);
+ rb_ary_replace(box->loaded_features_snapshot, loaded_features);
}
}
diff --git a/ruby.rs b/ruby.rs
new file mode 100644
index 0000000000..b66b2d21ca
--- /dev/null
+++ b/ruby.rs
@@ -0,0 +1,4 @@
+#[cfg(feature = "yjit")]
+pub use yjit::*;
+#[cfg(feature = "zjit")]
+pub use zjit::*;
diff --git a/ruby_atomic.h b/ruby_atomic.h
index 57d341082d..409b9bcfd2 100644
--- a/ruby_atomic.h
+++ b/ruby_atomic.h
@@ -1,4 +1,12 @@
+#ifndef INTERNAL_ATOMIC_H
+#define INTERNAL_ATOMIC_H
+
#include "ruby/atomic.h"
+#ifdef HAVE_STDATOMIC_H
+# include <stdatomic.h>
+#endif
+
+#define RUBY_ATOMIC_VALUE_LOAD(x) rbimpl_atomic_value_load(&(x), RBIMPL_ATOMIC_SEQ_CST)
/* shim macros only */
#define ATOMIC_ADD(var, val) RUBY_ATOMIC_ADD(var, val)
@@ -21,3 +29,85 @@
#define ATOMIC_SUB(var, val) RUBY_ATOMIC_SUB(var, val)
#define ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_VALUE_CAS(var, oldval, val)
#define ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_VALUE_EXCHANGE(var, val)
+
+#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_RELAXED)
+
+typedef RBIMPL_ALIGNAS(8) uint64_t rbimpl_atomic_uint64_t;
+
+static inline uint64_t
+rbimpl_atomic_u64_load_relaxed(const volatile rbimpl_atomic_uint64_t *value)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ return __atomic_load_n(value, __ATOMIC_RELAXED);
+#elif defined(_WIN32)
+ uint64_t val = *value;
+ return InterlockedCompareExchange64(RBIMPL_CAST((uint64_t *)value), val, val);
+#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
+ uint64_t val = *value;
+ return atomic_cas_64(value, val, val);
+#else
+ // TODO: stdatomic
+
+ return *value;
+#endif
+}
+#define ATOMIC_U64_LOAD_RELAXED(var) rbimpl_atomic_u64_load_relaxed(&(var))
+
+static inline void
+rbimpl_atomic_u64_set_relaxed(volatile rbimpl_atomic_uint64_t *address, uint64_t value)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ __atomic_store_n(address, value, __ATOMIC_RELAXED);
+#elif defined(_WIN32)
+ InterlockedExchange64(address, value);
+#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
+ atomic_swap_64(address, value);
+#else
+ // TODO: stdatomic
+
+ *address = value;
+#endif
+}
+#define ATOMIC_U64_SET_RELAXED(var, val) rbimpl_atomic_u64_set_relaxed(&(var), val)
+
+static inline uint64_t
+rbimpl_atomic_u64_fetch_add_relaxed(volatile rbimpl_atomic_uint64_t *value, uint64_t addend)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ return __atomic_fetch_add(value, addend, __ATOMIC_RELAXED);
+#elif defined(_WIN32)
+ return (uint64_t)InterlockedExchangeAdd64((LONG64 *)value, (LONG64)addend);
+#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
+ return atomic_add_64_nv(value, addend) - addend;
+#else
+ // TODO: stdatomic
+ uint64_t prev = *value;
+ *value = prev + addend;
+ return prev;
+#endif
+}
+#define ATOMIC_U64_FETCH_ADD_RELAXED(var, val) rbimpl_atomic_u64_fetch_add_relaxed(&(var), val)
+
+static inline uint64_t
+rbimpl_atomic_u64_load_acquire(const volatile rbimpl_atomic_uint64_t *value)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ return __atomic_load_n(value, __ATOMIC_ACQUIRE);
+#else
+ return rbimpl_atomic_u64_load_relaxed(value);
+#endif
+}
+#define ATOMIC_U64_LOAD_ACQUIRE(var) rbimpl_atomic_u64_load_acquire(&(var))
+
+static inline void
+rbimpl_atomic_u64_set_release(volatile rbimpl_atomic_uint64_t *address, uint64_t value)
+{
+#if defined(HAVE_GCC_ATOMIC_BUILTINS_64)
+ __atomic_store_n(address, value, __ATOMIC_RELEASE);
+#else
+ rbimpl_atomic_u64_set_relaxed(address, value);
+#endif
+}
+#define ATOMIC_U64_SET_RELEASE(var, val) rbimpl_atomic_u64_set_release(&(var), val)
+
+#endif
diff --git a/ruby_parser.c b/ruby_parser.c
index 267f619bf9..a96fc4974b 100644
--- a/ruby_parser.c
+++ b/ruby_parser.c
@@ -407,7 +407,7 @@ static const rb_parser_config_t rb_global_parser_config = {
.set_errinfo = rb_set_errinfo,
.make_exception = rb_make_exception,
- .sized_xfree = ruby_sized_xfree,
+ .sized_xfree = ruby_xfree_sized,
.sized_realloc_n = ruby_sized_realloc_n,
.gc_guard = gc_guard,
.gc_mark = rb_gc_mark,
diff --git a/rubyparser.h b/rubyparser.h
index 16f5cac81f..2ed93e9894 100644
--- a/rubyparser.h
+++ b/rubyparser.h
@@ -248,6 +248,7 @@ typedef struct RNode_SCOPE {
rb_ast_id_table_t *nd_tbl;
struct RNode *nd_body;
+ struct RNode *nd_parent;
struct RNode_ARGS *nd_args;
} rb_node_scope_t;
@@ -288,25 +289,7 @@ typedef struct RNode_CASE {
struct RNode *nd_body;
rb_code_location_t case_keyword_loc;
rb_code_location_t end_keyword_loc;
-} rb_node_case_t;
-
-typedef struct RNode_CASE2 {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- rb_code_location_t case_keyword_loc;
- rb_code_location_t end_keyword_loc;
-} rb_node_case2_t;
-
-typedef struct RNode_CASE3 {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- rb_code_location_t case_keyword_loc;
- rb_code_location_t end_keyword_loc;
-} rb_node_case3_t;
+} rb_node_case_t, rb_node_case2_t, rb_node_case3_t;
typedef struct RNode_WHEN {
NODE node;
@@ -324,6 +307,9 @@ typedef struct RNode_IN {
struct RNode *nd_head;
struct RNode *nd_body;
struct RNode *nd_next;
+ rb_code_location_t in_keyword_loc;
+ rb_code_location_t then_keyword_loc;
+ rb_code_location_t operator_loc;
} rb_node_in_t;
typedef struct RNode_LOOP {
@@ -778,7 +764,7 @@ struct rb_args_info {
struct RNode_OPT_ARG *opt_args;
unsigned int no_kwarg: 1;
- unsigned int ruby2_keywords: 1;
+ unsigned int no_blockarg: 1;
unsigned int forwarding: 1;
};
@@ -901,6 +887,8 @@ typedef struct RNode_MODULE {
struct RNode *nd_cpath;
struct RNode *nd_body;
+ rb_code_location_t module_keyword_loc;
+ rb_code_location_t end_keyword_loc;
} rb_node_module_t;
typedef struct RNode_SCLASS {
@@ -908,6 +896,9 @@ typedef struct RNode_SCLASS {
struct RNode *nd_recv;
struct RNode *nd_body;
+ rb_code_location_t class_keyword_loc;
+ rb_code_location_t operator_loc;
+ rb_code_location_t end_keyword_loc;
} rb_node_sclass_t;
typedef struct RNode_COLON2 {
@@ -915,12 +906,16 @@ typedef struct RNode_COLON2 {
struct RNode *nd_head;
ID nd_mid;
+ rb_code_location_t delimiter_loc;
+ rb_code_location_t name_loc;
} rb_node_colon2_t;
typedef struct RNode_COLON3 {
NODE node;
ID nd_mid;
+ rb_code_location_t delimiter_loc;
+ rb_code_location_t name_loc;
} rb_node_colon3_t;
/* NODE_DOT2, NODE_DOT3, NODE_FLIP2, NODE_FLIP3 */
@@ -958,6 +953,7 @@ typedef struct RNode_DEFINED {
NODE node;
struct RNode *nd_head;
+ rb_code_location_t keyword_loc;
} rb_node_defined_t;
typedef struct RNode_POSTEXE {
@@ -1153,7 +1149,7 @@ typedef struct RNode_ERROR {
#define RNODE_FILE(node) ((rb_node_file_t *)(node))
#define RNODE_ENCODING(node) ((rb_node_encoding_t *)(node))
-/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8: UNUSED, 9: UNUSED, 10: EXIVAR, 11: FREEZE */
+/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8..10: UNUSED, 11: FREEZE */
/* NODE_FL: 0..4: UNUSED, 5: UNUSED, 6: UNUSED, 7: NODE_FL_NEWLINE,
* 8..14: nd_type,
* 15..: nd_line
diff --git a/sample/drb/README.ja.rdoc b/sample/drb/README.ja.rdoc
deleted file mode 100644
index 1697b1b704..0000000000
--- a/sample/drb/README.ja.rdoc
+++ /dev/null
@@ -1,59 +0,0 @@
-= サンプルスクリプト
-
-* Arrayをリモートから利用してイテレータを試す。
- * darray.rb --- server
- * darrayc.rb --- client
-
-* 簡易チャット
- * dchats.rb --- server
- * dchatc.rb --- client
-
-* 分散chasen
- * dhasen.rb --- server
- * dhasenc.rb --- client
-
-* 簡易ログサーバ
- * dlogd.rb --- server
- * dlogc.rb --- client
-
-* Queueサーバ。
- クライアントdqin.rbはQueueサーバの知らないオブジェクト(DQEntry)を
- pushするがDRbUnknownによりクライアントdqout.rbがpopできる。
- * dqueue.rb --- server
- * dqin.rb --- client。DQEntryオブジェクトをpushする
- * dqout.rb --- client。DQEntryオブジェクトをpopする
- * dqlib.rb --- DQEntryを定義したライブラリ
-
-* 名前による参照
- IdConvをカスタマイズしてidでなく名前で参照する例
- * name.rb --- server
- * namec.rb --- client
-
-* extservのサンプル
- * extserv_test.rb
-
-* TimerIdConvの使用例
- * holders.rb --- server。ruby -d hodlers.rbとするとTimerIdConvを使用する。
- * holderc.rb --- client
-
-* rinda.rbの使用例
- * rinda_ts.rb --- TupleSpaceサーバ。
- * rindac.rb --- TupleSpaceのclientでアプリケーションのclient
- * rindas.rb --- TupleSpaceのclientでアプリケーションのserver
-
-* observerの使用例
- cdbiff - http://namazu.org/~satoru/cdbiff/
- * dbiff.rb --- dcdbiff server
- * dcdbiff.rb --- dcdbiff client
-
-* drbsslの使用例
- * drbssl_s.rb
- * drbssl_c.rb
-
-* DRbProtocolの追加例
- * http0.rb
- * http0serv.rb
-
-* ringの使用例
- * ring_place.rb
- * ring_echo.rb
diff --git a/sample/drb/README.rdoc b/sample/drb/README.rdoc
deleted file mode 100644
index e6b457bc5c..0000000000
--- a/sample/drb/README.rdoc
+++ /dev/null
@@ -1,56 +0,0 @@
-= Sample scripts
-
-* array and iterator
- * darray.rb --- server
- * darrayc.rb --- client
-
-* simple chat
- * dchats.rb --- server
- * dchatc.rb --- client
-
-* distributed chasen (for Japanese)
- * dhasen.rb --- server
- * dhasenc.rb --- client
-
-* simple log server
- * dlogd.rb --- server
- * dlogc.rb --- client
-
-* Queue server, and DRbUnknown demo
- * dqueue.rb --- server
- * dqin.rb --- client. push DQEntry objects.
- * dqout.rb --- client. pop DQEntry objects.
- * dqlib.rb --- define DQEntry
-
-* IdConv customize demo: reference by name
- * name.rb --- server
- * namec.rb --- client
-
-* extserv
- * extserv_test.rb
-
-* IdConv customize demo 2: using TimerIdConv
- * holders.rb --- server
- * holderc.rb --- client
-
-* rinda, remote tuplespace
- * rinda_ts.rb --- TupleSpace server.
- * rindas.rb --- provide simple service via TupleSpace.
- * rindac.rb --- service user
-
-* observer
- cdbiff - http://namazu.org/~satoru/cdbiff/
- * dbiff.rb --- dcdbiff server
- * dcdbiff.rb --- dcdbiff client
-
-* drbssl
- * drbssl_s.rb
- * drbssl_c.rb
-
-* add DRbProtocol
- * http0.rb
- * http0serv.rb
-
-* Rinda::Ring
- * ring_place.rb
- * ring_echo.rb
diff --git a/sample/drb/acl.rb b/sample/drb/acl.rb
deleted file mode 100644
index d93eb9c1fc..0000000000
--- a/sample/drb/acl.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'drb/acl'
-
-list = %w(deny all
- allow 192.168.1.1
- allow ::ffff:192.168.1.2
- allow 192.168.1.3
-)
-
-addr = ["AF_INET", 10, "lc630", "192.168.1.3"]
-
-acl = ACL.new
-p acl.allow_addr?(addr)
-
-acl = ACL.new(list, ACL::DENY_ALLOW)
-p acl.allow_addr?(addr)
diff --git a/sample/drb/darray.rb b/sample/drb/darray.rb
deleted file mode 100644
index d2ac39513f..0000000000
--- a/sample/drb/darray.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-=begin
- distributed Ruby --- Array
- Copyright (c) 1999-2001 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-here = ARGV.shift
-DRb.start_service(here, [1, 2, "III", 4, "five", 6])
-puts DRb.uri
-DRb.thread.join
-
diff --git a/sample/drb/darrayc.rb b/sample/drb/darrayc.rb
deleted file mode 100644
index 579e11564e..0000000000
--- a/sample/drb/darrayc.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-=begin
- distributed Ruby --- Array client
- Copyright (c) 1999-2001 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-there = ARGV.shift || raise("usage: #{$0} <server_uri>")
-
-DRb.start_service(nil, nil)
-ro = DRbObject.new(nil, there)
-p ro.size
-
-puts "# collect"
-a = ro.collect { |x|
- x + x
-}
-p a
-
-puts "# find"
-p ro.find { |x| x.kind_of? String }
-
-puts "# each, break"
-ro.each do |x|
- next if x == "five"
- puts x
-end
-
-puts "# each, break"
-ro.each do |x|
- break if x == "five"
- puts x
-end
-
-puts "# each, next"
-ro.each do |x|
- next if x == "five"
- puts x
-end
-
-puts "# each, redo"
-count = 0
-ro.each do |x|
- count += 1
- puts count
- redo if count == 3
-end
diff --git a/sample/drb/dbiff.rb b/sample/drb/dbiff.rb
deleted file mode 100644
index 290eb1d28b..0000000000
--- a/sample/drb/dbiff.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# dbiff.rb - distributed cdbiff (server)
-# * original: cdbiff by Satoru Takabayashi <http://namazu.org/~satoru/cdbiff>
-
-require 'drb/drb'
-require 'drb/eq'
-require 'drb/observer'
-
-class Biff
- include DRb::DRbObservable
-
- def initialize(filename, interval)
- super()
- @filename = filename
- @interval = interval
- end
-
- def run
- last = Time.now
- while true
- begin
- sleep(@interval)
- current = File::mtime(@filename)
- if current > last
- changed
- begin
- notify_observers(@filename, current)
- rescue Error
- end
- last = current
- end
- rescue
- next
- end
- end
- end
-end
-
-def main
- filename = "/var/mail/#{ENV['USER']}"
- interval = 15
- uri = 'druby://:19903'
-
- biff = Biff.new(filename, interval)
-
- DRb.start_service(uri, biff)
- biff.run
-end
-
-main
-
diff --git a/sample/drb/dcdbiff.rb b/sample/drb/dcdbiff.rb
deleted file mode 100644
index 6a24680c33..0000000000
--- a/sample/drb/dcdbiff.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# dcdbiff.rb - distributed cdbiff (client)
-# * original: cdbiff by Satoru Takabayashi <http://namazu.org/~satoru/cdbiff>
-
-require 'drb/drb'
-require 'drb/eq'
-
-class Notify
- include DRbUndumped
-
- def initialize(biff, command)
- @biff = biff
- @command = command
-
- @biff.add_observer(self)
- end
-
- def update(filename, time)
- p [filename, time] if $DEBUG
- system(@command)
- end
-
- def done
- begin
- @biff.delete_observer(self)
- rescue
- end
- end
-end
-
-def main
- command = 'eject'
- uri = 'druby://localhost:19903'
-
- DRb.start_service
- biff = DRbObject.new(nil, uri)
- notify = Notify.new(biff, command)
-
- trap("INT"){ notify.done }
- DRb.thread.join
-end
-
-main
diff --git a/sample/drb/dchatc.rb b/sample/drb/dchatc.rb
deleted file mode 100644
index 2b8ddbf4cc..0000000000
--- a/sample/drb/dchatc.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-=begin
- distributed Ruby --- chat client
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-class ChatClient
- include DRbUndumped
-
- def initialize(name)
- @name = name
- @key = nil
- end
- attr_reader(:name)
- attr_accessor(:key)
-
- def message(there, str)
- raise 'invalid key' unless @key == there
- puts str
- end
-end
-
-if __FILE__ == $0
- begin
- there = ARGV.shift
- name = ARGV.shift
- raise "usage" unless (there and name)
- rescue
- $stderr.puts("usage: #{$0} <server_uri> <your_name>")
- exit 1
- end
- DRb.start_service
- ro = DRbObject.new(nil, there)
-
- chat = ChatClient.new(name)
- entry = ro.add_member(chat)
- while gets
- entry.say($_)
- end
-end
diff --git a/sample/drb/dchats.rb b/sample/drb/dchats.rb
deleted file mode 100644
index c96486a452..0000000000
--- a/sample/drb/dchats.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-=begin
- distributed Ruby --- chat server
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-require 'drb/drb'
-
-class ChatEntry
- include DRbUndumped
-
- def initialize(server, there)
- @server = server
- @there = there
- @name = there.name
- @key = there.key = Time.now
- end
- attr :name, true
- attr :there
-
- def say(str)
- @server.distribute(@there, str)
- end
-
- def listen(str)
- @there.message(@key, str)
- end
-end
-
-
-class ChatServer
- def initialize
- @mutex = Thread::Mutex.new
- @members = {}
- end
-
- def add_member(there)
- client = ChatEntry.new(self, there)
- @mutex.synchronize do
- @members[there] = client
- end
- client
- end
-
- def distribute(there, str)
- name = @members[there].name
- msg = "<#{name}> #{str}"
- msg2 = ">#{name}< #{str}"
- @mutex.synchronize do
- for m in @members.keys
- begin
- if m == there
- @members[m].listen(msg2)
- else
- @members[m].listen(msg)
- end
- rescue
- p $!
- @members.delete(m)
- end
- end
- end
- end
-end
-
-if __FILE__ == $0
- here = ARGV.shift
- DRb.start_service(here, ChatServer.new)
- puts DRb.uri
- DRb.thread.join
-end
diff --git a/sample/drb/dhasen.rb b/sample/drb/dhasen.rb
deleted file mode 100644
index 13ff38940e..0000000000
--- a/sample/drb/dhasen.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-=begin
- distributed Ruby --- dRuby Sample Server --- chasen server
- Copyright (c) 1999-2001 Masatoshi SEKI
-=end
-
-=begin
- How to play.
-
- Terminal 1
- | % ruby dhasen.rb
- | druby://yourhost:7640
-
- Terminal 2
- | % ruby dhasenc.rb druby://yourhost:7640
-
-=end
-
-require 'drb/drb'
-require 'chasen'
-
-class Dhasen
- include DRbUndumped
-
- def initialize
- @mutex = Thread::Mutex.new
- end
-
- def sparse(str, *arg)
- @mutex.synchronize do
- Chasen.getopt(*arg)
- Chasen.sparse(str)
- end
- end
-end
-
-if __FILE__ == $0
- DRb.start_service(nil, Dhasen.new)
- puts DRb.uri
- DRb.thread.join
-end
-
diff --git a/sample/drb/dhasenc.rb b/sample/drb/dhasenc.rb
deleted file mode 100644
index dddac9882c..0000000000
--- a/sample/drb/dhasenc.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- coding: utf-8 -*-
-=begin
- distributed Ruby --- dRuby Sample Client -- chasen client
- Copyright (c) 1999-2001 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-there = ARGV.shift || raise("usage: #{$0} <server_uri>")
-DRb.start_service
-dhasen = DRbObject.new(nil, there)
-
-print dhasen.sparse("本日は、晴天なり。", "-F", '(%BB %m %M)\n', "-j")
-print dhasen.sparse("本日は、晴天なり。", "-F", '(%m %M)\n')
diff --git a/sample/drb/dlogc.rb b/sample/drb/dlogc.rb
deleted file mode 100644
index 3939a71827..0000000000
--- a/sample/drb/dlogc.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-=begin
- distributed Ruby --- Log test
- Copyright (c) 1999-2001 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-there = ARGV.shift || raise("usage: #{$0} <server_uri>")
-
-DRb.start_service
-ro = DRbObject.new(nil, there)
-ro.log(123)
-ro.log("hello")
-sleep 2
-ro.log("wakeup")
-
diff --git a/sample/drb/dlogd.rb b/sample/drb/dlogd.rb
deleted file mode 100644
index a87e660346..0000000000
--- a/sample/drb/dlogd.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-=begin
- distributed Ruby --- Log server
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-class Logger
- def initialize(fname)
- @fname = fname.to_s
- @fp = File.open(@fname, "a+")
- @queue = Thread::Queue.new
- @th = Thread.new { self.flush }
- end
-
- def log(str)
- @queue.push("#{Time.now}\t" + str.to_s)
- end
-
- def flush
- begin
- while(1)
- @fp.puts(@queue.pop)
- @fp.flush
- end
- ensure
- @fp.close
- end
- end
-end
-
-if __FILE__ == $0
- here = ARGV.shift
- DRb.start_service(here, Logger.new('/usr/tmp/dlogd.log'))
- puts DRb.uri
- DRb.thread.join
-end
-
diff --git a/sample/drb/dqin.rb b/sample/drb/dqin.rb
deleted file mode 100644
index 4751335fff..0000000000
--- a/sample/drb/dqin.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-=begin
- distributed Ruby --- store
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-require 'dqlib'
-
-there = ARGV.shift || raise("usage: #{$0} <server_uri>")
-
-DRb.start_service
-queue = DRbObject.new(nil, there)
-queue.push(DQEntry.new(DRb.uri))
diff --git a/sample/drb/dqlib.rb b/sample/drb/dqlib.rb
deleted file mode 100644
index 75f2e6115b..0000000000
--- a/sample/drb/dqlib.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class DQEntry
- def initialize(name)
- @name = name
- end
-
- def greeting
- "Hello, This is #{@name}."
- end
- alias to_s greeting
-end
-
-if __FILE__ == $0
- puts DQEntry.new('DQEntry')
-end
diff --git a/sample/drb/dqout.rb b/sample/drb/dqout.rb
deleted file mode 100644
index f2b0b4ac95..0000000000
--- a/sample/drb/dqout.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-=begin
- distributed Ruby --- fetch
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-require 'dqlib'
-
-there = ARGV.shift || raise("usage: #{$0} <server_uri>")
-
-DRb.start_service
-queue = DRbObject.new(nil, there)
-entry = queue.pop
-puts entry.greeting
diff --git a/sample/drb/dqueue.rb b/sample/drb/dqueue.rb
deleted file mode 100644
index a9afa8c858..0000000000
--- a/sample/drb/dqueue.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-=begin
- distributed Ruby --- Queue
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-DRb.start_service(nil, Thread::Queue.new)
-puts DRb.uri
-DRb.thread.join
-
diff --git a/sample/drb/drbc.rb b/sample/drb/drbc.rb
deleted file mode 100644
index 50a86c39e8..0000000000
--- a/sample/drb/drbc.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-=begin
- distributed Ruby --- dRuby Sample Client
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-class DRbEx2
- include DRbUndumped
-
- def initialize(n)
- @n = n
- end
-
- def to_i
- @n.to_i
- end
-end
-
-if __FILE__ == $0
- there = ARGV.shift
- unless there
- $stderr.puts("usage: #{$0} <server_uri>")
- exit 1
- end
-
- DRb.start_service()
- ro = DRbObject.new_with_uri(there)
-
- puts ro
- p ro.to_a
- puts ro.hello
- p ro.hello
- puts ro.sample(DRbEx2.new(1), 2, 3)
- puts ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3))
-
- begin
- ro.err
- rescue DRb::DRbUnknownError
- p $!
- p $!.unknown
- rescue RuntimeError
- p $!
- end
-end
diff --git a/sample/drb/drbch.rb b/sample/drb/drbch.rb
deleted file mode 100644
index 07fdcd5fae..0000000000
--- a/sample/drb/drbch.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-=begin
- distributed Ruby --- dRuby Sample Client
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-require 'drb/http'
-
-class DRbEx2
- include DRbUndumped
-
- def initialize(n)
- @n = n
- end
-
- def to_i
- @n.to_i
- end
-end
-
-if __FILE__ == $0
- there = ARGV.shift
- unless there
- $stderr.puts("usage: #{$0} <server_uri>")
- exit 1
- end
-
- DRb::DRbConn.proxy_map['x68k'] = 'http://x68k/~mas/http_cgi.rb'
-
- DRb.start_service()
- ro = DRbObject.new(nil, there)
-
- puts ro
- p ro.to_a
- puts ro.hello
- p ro.hello
- puts ro.sample(DRbEx2.new(1), 2, 3)
- puts ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3))
-
- begin
- ro.err
- rescue DRb::DRbUnknownError
- p $!
- p $!.unknown
- rescue RuntimeError
- p $!
- end
-end
diff --git a/sample/drb/drbm.rb b/sample/drb/drbm.rb
deleted file mode 100644
index 3390608cd1..0000000000
--- a/sample/drb/drbm.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-=begin
- multiple DRbServer
- Copyright (c) 1999-2002 Masatoshi SEKI
-=end
-
-=begin
- How to play.
-
- Terminal 1
- | % ruby drbm.rb
- | druby://yourhost:7640 druby://yourhost:7641
-
- Terminal 2
- | % ruby drbmc.rb druby://yourhost:7640 druby://yourhost:7641
- | [#<DRb::DRbObject .... @uri="druby://yourhost:7640">, "FOO"]
- | [#<DRb::DRbObject .... @uri="druby://yourhost:7641">, "FOO"]
-
-=end
-
-require 'drb/drb'
-
-class Hoge
- include DRbUndumped
- def initialize(s)
- @str = s
- end
-
- def to_s
- @str
- end
-end
-
-class Foo
- def initialize(s='FOO')
- @hoge = Hoge.new(s)
- end
-
- def hello
- @hoge
- end
-end
-
-class Bar < Foo
- def initialize(foo)
- @hoge = foo.hello
- end
-end
-
-
-if __FILE__ == $0
- foo = Foo.new
- s1 = DRb::DRbServer.new('druby://:7640', foo)
- s2 = DRb::DRbServer.new('druby://:7641', Bar.new(foo))
-
- puts "#{s1.uri} #{s2.uri}"
-
- s1.thread.join
- s2.thread.join
-end
-
diff --git a/sample/drb/drbmc.rb b/sample/drb/drbmc.rb
deleted file mode 100644
index fd191401e6..0000000000
--- a/sample/drb/drbmc.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-=begin
- multiple DRbServer client
- Copyright (c) 1999-2002 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-if __FILE__ == $0
- s1 = ARGV.shift
- s2 = ARGV.shift
- unless s1 && s2
- $stderr.puts("usage: #{$0} <server_uri1> <server_uri2>")
- exit 1
- end
-
- DRb.start_service()
- r1 = DRbObject.new(nil, s1)
- r2 = DRbObject.new(nil, s2)
-
- p [r1.hello, r1.hello.to_s]
- p [r2.hello, r2.hello.to_s]
-end
diff --git a/sample/drb/drbs-acl.rb b/sample/drb/drbs-acl.rb
deleted file mode 100644
index 71c4f7bf42..0000000000
--- a/sample/drb/drbs-acl.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-=begin
- distributed Ruby --- dRuby Sample Server
- Copyright (c) 1999-2000 Masatoshi SEKI
-=end
-
-=begin
- How to play.
-
- Terminal 1
- | % ruby drbs.rb
- | druby://yourhost:7640
-
- Terminal 2
- | % ruby drbc.rb druby://yourhost:7640
- | "hello"
- | 6
- | 10
-
-=end
-
-require 'drb/drb'
-require 'acl'
-
-class DRbEx
- def initialize
- @hello = 'hello'
- end
-
- def hello
- info = Thread.current['DRb']
- p info['socket'].peeraddr if info
- @hello
- end
-
- def sample(a, b, c)
- a.to_i + b.to_i + c.to_i
- end
-end
-
-if __FILE__ == $0
- acl = ACL.new(%w(deny all
- allow 192.168.1.*
- allow localhost))
-
- DRb.install_acl(acl)
-
- DRb.start_service(nil, DRbEx.new)
- puts DRb.uri
- DRb.thread.join
-end
-
diff --git a/sample/drb/drbs.rb b/sample/drb/drbs.rb
deleted file mode 100644
index 5a913d9918..0000000000
--- a/sample/drb/drbs.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-=begin
- distributed Ruby --- dRuby Sample Server
- Copyright (c) 1999-2000,2002 Masatoshi SEKI
-=end
-
-=begin
- How to play.
-
- Terminal 1
- | % ruby drbs.rb
- | druby://yourhost:7640
-
- Terminal 2
- | % ruby drbc.rb druby://yourhost:7640
- | "hello"
- | ....
-
-=end
-
-require 'drb/drb'
-
-class DRbEx
- include DRbUndumped
-
- def initialize
- @hello = 'hello'
- end
-
- def hello
- cntxt = Thread.current['DRb']
- if cntxt
- p cntxt['server'].uri
- p cntxt['client'].peeraddr
- end
- Foo::Unknown.new
- end
-
- def err
- raise FooError
- end
-
- def sample(a, b, c)
- a.to_i + b.to_i + c.to_i
- end
-end
-
-class Foo
- class Unknown
- end
-end
-
-class FooError < RuntimeError
-end
-
-if __FILE__ == $0
- DRb.start_service(ARGV.shift || 'druby://:7640', DRbEx.new)
- puts DRb.uri
- Thread.new do
- sleep 10
- DRb.stop_service
- end
- DRb.thread.join
-end
-
diff --git a/sample/drb/drbssl_c.rb b/sample/drb/drbssl_c.rb
deleted file mode 100644
index 65112f6e78..0000000000
--- a/sample/drb/drbssl_c.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'drb'
-require 'drb/ssl'
-
-there = ARGV.shift || "drbssl://localhost:3456"
-
-config = Hash.new
-config[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER
-config[:SSLVerifyCallback] = lambda{|ok,x509_store|
- p [ok, x509_store.error_string]
- true
-}
-
-DRb.start_service(nil,nil,config)
-h = DRbObject.new(nil, there)
-while line = gets
- p h.hello(line.chomp)
-end
diff --git a/sample/drb/drbssl_s.rb b/sample/drb/drbssl_s.rb
deleted file mode 100644
index 4d96f591d4..0000000000
--- a/sample/drb/drbssl_s.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'drb'
-require 'drb/ssl'
-
-here = ARGV.shift || "drbssl://localhost:3456"
-
-class HelloWorld
- include DRbUndumped
-
- def hello(name)
- "Hello, #{name}."
- end
-end
-
-config = Hash.new
-config[:verbose] = true
-begin
- data = open("sample.key"){|io| io.read }
- config[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(data)
- data = open("sample.crt"){|io| io.read }
- config[:SSLCertificate] = OpenSSL::X509::Certificate.new(data)
-rescue
- $stderr.puts "Switching to use self-signed certificate"
- config[:SSLCertName] =
- [ ["C","JP"], ["O","Foo.DRuby.Org"], ["CN", "Sample"] ]
-end
-
-DRb.start_service(here, HelloWorld.new, config)
-puts DRb.uri
-DRb.thread.join
diff --git a/sample/drb/extserv_test.rb b/sample/drb/extserv_test.rb
deleted file mode 100644
index 2c4f485dc6..0000000000
--- a/sample/drb/extserv_test.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-=begin
- dRuby sample
- Copyright (c) 2000 Masatoshi SEKI
-
-= How to play
-
-* Terminal 1
-
- % ruby -I. extserv_test.rb server
- druby://yourhost:12345
-
-* Terminal 2
-
- % ruby -I. extserv_test.rb druby://yourhost:12345
- ...
-
-=end
-
-require 'drb/drb'
-
-def ARGV.shift
- it = super()
- raise "usage:\nserver: #{$0} server [<uri>]\nclient: #{$0} [quit] <uri>" unless it
- it
-end
-
-class Foo
- include DRbUndumped
-
- def initialize(str)
- @str = str
- end
-
- def hello(it)
- "#{it}: #{self}"
- end
-
- def to_s
- @str
- end
-end
-
-cmd = ARGV.shift
-case cmd
-when 'itest1', 'itest2'
- require 'drb/extserv'
-
- front = Foo.new(cmd)
- server = DRb::DRbServer.new(nil, front)
- es = DRb::ExtServ.new(ARGV.shift, ARGV.shift, server)
- server.thread.join
-
-when 'server'
- require 'drb/extservm'
-
- DRb::ExtServManager.command['itest1'] = "ruby -I. #{$0} itest1"
- DRb::ExtServManager.command['itest2'] = "ruby -I. #{$0} itest2"
-
- s = DRb::ExtServManager.new
- DRb.start_service(ARGV.shift, s)
- puts DRb.uri
- DRb.thread.join
-
-
-else
- uri = (cmd == 'quit') ? ARGV.shift : cmd
-
- DRb.start_service
- s = DRbObject.new(nil, uri)
- t1 = s.service('itest1').front
- puts t1
- t2 = s.service('itest2').front
- puts t2
- puts t1.hello(t2)
- if (cmd == 'quit')
- s.service('itest1').stop_service
- s.service('itest2').stop_service
- end
-end
-
diff --git a/sample/drb/gw_ct.rb b/sample/drb/gw_ct.rb
deleted file mode 100644
index 0622784018..0000000000
--- a/sample/drb/gw_ct.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'drb/drb'
-
-class Foo
- include DRbUndumped
-
- def foo(n)
- n + n
- end
-
- def bar(n)
- yield(n) + yield(n)
- end
-end
-
-DRb.start_service(nil)
-puts DRb.uri
-
-ro = DRbObject.new(nil, ARGV.shift)
-ro[:tcp] = Foo.new
-gets
-
-it = ro[:unix]
-p [it, it.foo(1)]
-gets
-
-p it.bar('2') {|n| n * 3}
-gets
-
-
diff --git a/sample/drb/gw_cu.rb b/sample/drb/gw_cu.rb
deleted file mode 100644
index 8079cbdc4f..0000000000
--- a/sample/drb/gw_cu.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'drb/drb'
-require 'drb/unix'
-
-class Foo
- include DRbUndumped
-
- def foo(n)
- n + n
- end
-
- def bar(n)
- yield(n) + yield(n)
- end
-end
-
-DRb.start_service('drbunix:', nil)
-puts DRb.uri
-
-ro = DRbObject.new(nil, ARGV.shift)
-ro[:unix] = Foo.new
-gets
-
-it = ro[:tcp]
-p [it, it.foo(1)]
-gets
-
-p it.bar('2') {|n| n * 3}
-gets
diff --git a/sample/drb/gw_s.rb b/sample/drb/gw_s.rb
deleted file mode 100644
index c2bea0baad..0000000000
--- a/sample/drb/gw_s.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'drb/drb'
-require 'drb/unix'
-require 'drb/gw'
-
-DRb.install_id_conv(DRb::GWIdConv.new)
-gw = DRb::GW.new
-s1 = DRb::DRbServer.new(ARGV.shift, gw)
-s2 = DRb::DRbServer.new(ARGV.shift, gw)
-s1.thread.join
-s2.thread.join
diff --git a/sample/drb/holderc.rb b/sample/drb/holderc.rb
deleted file mode 100644
index e627916d76..0000000000
--- a/sample/drb/holderc.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'drb/drb'
-
-begin
- there = ARGV.shift || raise
-rescue
- $stderr.puts("usage: #{$0} <server_uri>")
- exit 1
-end
-
-DRb.start_service()
-ro = DRbObject.new(nil, there)
-
-ary = []
-10.times do
- ary.push(ro.gen)
-end
-
-sleep 5 if $DEBUG
-
-ary.each do |e|
- p e.sample([1])
-end
diff --git a/sample/drb/holders.rb b/sample/drb/holders.rb
deleted file mode 100644
index 293426faa5..0000000000
--- a/sample/drb/holders.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-=begin
-= How to play.
-
-== with timeridconv:
- % ruby -d holders.rb
- druby://yourhost:1234
-
- % ruby holderc.rb druby://yourhost:1234
-
-
-== without timeridconv:
- % ruby holders.rb
- druby://yourhost:1234
-
- % ruby holderc.rb druby://yourhost:1234
-=end
-
-
-require 'drb/drb'
-
-class DRbEx3
- include DRbUndumped
-
- def initialize(n)
- @v = n
- end
-
- def sample(list)
- sum = 0
- list.each do |e|
- sum += e.to_i
- end
- @v * sum
- end
-end
-
-class DRbEx4
- include DRbUndumped
-
- def initialize
- @curr = 1
- end
-
- def gen
- begin
- @curr += 1
- DRbEx3.new(@curr)
- ensure
- GC.start
- end
- end
-end
-
-if __FILE__ == $0
- if $DEBUG
- require 'drb/timeridconv'
- DRb.install_id_conv(DRb::TimerIdConv.new(2))
- end
-
- DRb.start_service(nil, DRbEx4.new)
- puts DRb.uri
- DRb.thread.join
-end
diff --git a/sample/drb/http0.rb b/sample/drb/http0.rb
deleted file mode 100644
index e40d810311..0000000000
--- a/sample/drb/http0.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require 'drb/drb'
-require 'net/http'
-require 'uri'
-
-module DRb
- module HTTP0
- class StrStream
- def initialize(str='')
- @buf = str
- end
- attr_reader :buf
-
- def read(n)
- begin
- return @buf[0,n]
- ensure
- @buf[0,n] = ''
- end
- end
-
- def write(s)
- @buf.concat s
- end
- end
-
- def self.uri_option(uri, config)
- return uri, nil
- end
-
- def self.open(uri, config)
- unless /^http:/ =~ uri
- raise(DRbBadScheme, uri) unless uri =~ /^http:/
- raise(DRbBadURI, 'can\'t parse uri:' + uri)
- end
- ClientSide.new(uri, config)
- end
-
- class ClientSide
- def initialize(uri, config)
- @uri = uri
- @res = nil
- @config = config
- @msg = DRbMessage.new(config)
- @proxy = ENV['HTTP_PROXY']
- end
-
- def close; end
- def alive?; false; end
-
- def send_request(ref, msg_id, *arg, &b)
- stream = StrStream.new
- @msg.send_request(stream, ref, msg_id, *arg, &b)
- @reply_stream = StrStream.new
- post(@uri, stream.buf)
- end
-
- def recv_reply
- @msg.recv_reply(@reply_stream)
- end
-
- def post(url, data)
- it = URI.parse(url)
- path = [(it.path=='' ? '/' : it.path), it.query].compact.join('?')
- http = Net::HTTP.new(it.host, it.port)
- sio = StrStream.new
- http.post(path, data, {'Content-Type'=>'application/octetstream;'}) do |str|
- sio.write(str)
- if @config[:load_limit] < sio.buf.size
- raise TypeError, 'too large packet'
- end
- end
- @reply_stream = sio
- end
- end
- end
- DRbProtocol.add_protocol(HTTP0)
-end
diff --git a/sample/drb/http0serv.rb b/sample/drb/http0serv.rb
deleted file mode 100644
index 2e853312e1..0000000000
--- a/sample/drb/http0serv.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-require 'webrick'
-require 'drb/drb'
-require_relative 'http0'
-
-module DRb
- module HTTP0
-
- def self.open_server(uri, config)
- unless /^http:/ =~ uri
- raise(DRbBadScheme, uri) unless uri =~ /^http:/
- raise(DRbBadURI, 'can\'t parse uri:' + uri)
- end
- Server.new(uri, config)
- end
-
- class Callback < WEBrick::HTTPServlet::AbstractServlet
- def initialize(config, drb)
- @config = config
- @drb = drb
- @queue = Thread::Queue.new
- end
-
- def do_POST(req, res)
- @req = req
- @res = res
- @drb.push(self)
- @res.body = @queue.pop
- @res['content-type'] = 'application/octet-stream;'
- end
-
- def req_body
- @req.body
- end
-
- def reply(body)
- @queue.push(body)
- end
-
- def close
- @queue.push('')
- end
- end
-
- class Server
- def initialize(uri, config)
- @uri = uri
- @config = config
- @queue = Thread::Queue.new
- setup_webrick(uri)
- end
- attr_reader :uri
-
- def close
- @server.shutdown if @server
- @server = nil
- end
-
- def push(callback)
- @queue.push(callback)
- end
-
- def accept
- client = @queue.pop
- ServerSide.new(uri, client, @config)
- end
-
- def setup_webrick(uri)
- logger = WEBrick::Log::new($stderr, WEBrick::Log::FATAL)
- u = URI.parse(uri)
- s = WEBrick::HTTPServer.new(:Port => u.port,
- :AddressFamily => Socket::AF_INET,
- :BindAddress => u.host,
- :Logger => logger,
- :ServerType => Thread)
- s.mount(u.path, Callback, self)
- @server = s
- s.start
- end
- end
-
- class ServerSide
- def initialize(uri, callback, config)
- @uri = uri
- @callback = callback
- @config = config
- @msg = DRbMessage.new(@config)
- @req_stream = StrStream.new(@callback.req_body)
- end
- attr_reader :uri
-
- def close
- @callback.close if @callback
- @callback = nil
- end
-
- def alive?; false; end
-
- def recv_request
- begin
- @msg.recv_request(@req_stream)
- rescue
- close
- raise $!
- end
- end
-
- def send_reply(succ, result)
- begin
- return unless @callback
- stream = StrStream.new
- @msg.send_reply(stream, succ, result)
- @callback.reply(stream.buf)
- rescue
- close
- raise $!
- end
- end
- end
- end
-end
diff --git a/sample/drb/name.rb b/sample/drb/name.rb
deleted file mode 100644
index 6d88186dab..0000000000
--- a/sample/drb/name.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-=begin
- distributed Ruby --- NamedObject Sample
- Copyright (c) 2000-2001 Masatoshi SEKI
-=end
-
-=begin
-How to play.
-
-* start server
- Terminal 1
- | % ruby name.rb druby://yourhost:7640
- | druby://yourhost:7640
- | [return] to exit
-
-* start client
- Terminal 2
- | % ruby namec.rb druby://yourhost:7640
- | #<DRb::DRbObject:0x40164174 @uri="druby://yourhost:7640", @ref="seq">
- | #<DRb::DRbObject:0x40163c9c @uri="druby://yourhost:7640", @ref="mutex">
- | 1
- | 2
- | [return] to continue
-
-* restart server
- Terminal 1
- type [return]
- | % ruby name.rb druby://yourhost:7640
- | druby://yourhost:7640
- | [return] to exit
-
-* continue client
- Terminal 2
- type [return]
- | 1
- | 2
-=end
-
-require 'drb/drb'
-
-module DRbNamedObject
- DRbNAMEDICT = {}
- DRBNAMEMUTEX = Thread::Mutex.new
- attr_reader(:drb_name)
-
- def drb_name=(name)
- @drb_name = name
- DRBNAMEMUTEX.synchronize do
- raise(IndexError, name) if DRbNAMEDICT[name]
- DRbNAMEDICT[name] = self
- end
- end
-end
-
-class DRbNamedIdConv < DRb::DRbIdConv
- def initialize
- @dict = DRbNamedObject::DRbNAMEDICT
- end
-
- def to_obj(ref)
- @dict.fetch(ref) do super end
- end
-
- def to_id(obj)
- if obj.kind_of? DRbNamedObject
- return obj.drb_name
- else
- return super
- end
- end
-end
-
-class Seq
- include DRbUndumped
- include DRbNamedObject
-
- def initialize(v, name)
- @counter = v
- @mutex = Thread::Mutex.new
- self.drb_name = name
- end
-
- def next_value
- @mutex.synchronize do
- @counter += 1
- return @counter
- end
- end
-end
-
-class Front
- def initialize
- seq = Seq.new(0, 'seq')
- mutex = Thread::Mutex.new
- mutex.extend(DRbUndumped)
- mutex.extend(DRbNamedObject)
- mutex.drb_name = 'mutex'
- @name = {}
- @name['seq'] = seq
- @name['mutex'] = mutex
- end
-
- def [](k)
- @name[k]
- end
-end
-
-if __FILE__ == $0
- uri = ARGV.shift
-
- name_conv = DRbNamedIdConv.new
-
- DRb.install_id_conv(name_conv)
- DRb.start_service(uri, Front.new)
- puts DRb.uri
- DRb.thread.join
-end
-
diff --git a/sample/drb/namec.rb b/sample/drb/namec.rb
deleted file mode 100644
index 98b9d0e532..0000000000
--- a/sample/drb/namec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-=begin
- distributed Ruby --- NamedObject Sample Client
- Copyright (c) 2000-2001 Masatoshi SEKI
-=end
-
-require 'drb/drb'
-
-begin
- there = ARGV.shift || raise
-rescue
- puts "usage: #{$0} <server_uri>"
- exit 1
-end
-
-DRb.start_service()
-ro = DRbObject.new(nil, there)
-
-seq = ro["seq"]
-mutex = ro["mutex"]
-
-p seq
-p mutex
-
-mutex.synchronize do
- p seq.next_value
- p seq.next_value
-end
-
-puts '[return] to continue'
-gets
-
-mutex.synchronize do
- p seq.next_value
- p seq.next_value
-end
-
diff --git a/sample/drb/old_tuplespace.rb b/sample/drb/old_tuplespace.rb
deleted file mode 100644
index 2d5310086e..0000000000
--- a/sample/drb/old_tuplespace.rb
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/local/bin/ruby
-# TupleSpace
-# Copyright (c) 1999-2000 Masatoshi SEKI
-# You can redistribute it and/or modify it under the same terms as Ruby.
-
-class TupleSpace
- class Template
- def initialize(list)
- @list = list
- @check_idx = []
- @list.each_with_index do |x, i|
- @check_idx.push i if x
- end
- @size = @list.size
- end
-
- attr :size
- alias length size
-
- def match(tuple)
- return nil if tuple.size != self.size
- @check_idx.each do |i|
- unless @list[i] === tuple[i]
- return false
- end
- end
- return true
- end
- end
-
- def initialize
- @que = {}
- @waiting = {}
- @que.taint # enable tainted communication
- @waiting.taint
- self.taint
- end
-
- def wakeup_waiting(tuple)
- sz = tuple.length
- return nil unless @waiting[sz]
-
- x = nil
- i = -1
- found = false
- @waiting[sz] = @waiting[sz].find_all { |x|
- if x[0].match(tuple)
- begin
- x[1].wakeup
- rescue ThreadError
- end
- false
- else
- true
- end
- }
- end
-
- def put_waiting(template, thread)
- sz = template.length
- @waiting[sz] = [] unless @waiting[sz]
- @waiting[sz].push([Template.new(template), thread])
- end
- private :wakeup_waiting
- private :put_waiting
-
- def get_que(template)
- sz = template.length
- return nil unless @que[sz]
-
- template = Template.new(template)
-
- x = nil
- i = -1
- found = false
- @que[sz].each_with_index do |x, i|
- if template.match(x)
- found = true
- break
- end
- end
- return nil unless found
-
- @que[sz].delete_at(i)
-
- return x
- end
-
- def put_que(tuple)
- sz = tuple.length
- @que[sz] = [] unless @que[sz]
- @que[sz].push tuple
- end
- private :get_que
- private :put_que
-
- def out(*tuples)
- tuples.each do |tuple|
- Thread.critical = true
- put_que(tuple)
- wakeup_waiting(tuple)
- Thread.critical = false
- end
- end
- alias put out
- alias write out
-
- def in(template, non_block=false)
- begin
- loop do
- Thread.critical = true
- tuple = get_que(template)
- unless tuple
- if non_block
- raise ThreadError, "queue empty"
- end
- put_waiting(template, Thread.current)
- Thread.stop
- else
- return tuple
- end
- end
- ensure
- Thread.critical = false
- end
- end
- alias get in
- alias take in
-
- def rd(template, non_block=false)
- tuple = self.in(template, non_block)
- out(tuple)
- tuple
- end
- alias read rd
-
- def mv(dest, template, non_block=false)
- tuple = self.in(template, non_block)
- begin
- dest.out(tuple)
- rescue
- self.out(tuple)
- end
- end
- alias move mv
-end
-
-if __FILE__ == $0
- ts = TupleSpace.new
- clients = []
- servers = []
-
- def server(ts, id)
- Thread.start {
- loop do
- req = ts.in(['req', nil, nil])
- ac = req[1]
- num = req[2]
- sleep id
- ts.out([ac, id, num, num * num])
- end
- }
- end
-
- def client(ts, n)
- Thread.start {
- ac = Object.new
- tuples = (1..10).collect { |i|
- ['req', ac, i * 10 + n]
- }
- ts.out(*tuples)
- ts.out(tuples[0])
- puts "out: #{n}"
- 11.times do |i|
- ans = ts.in([ac, nil, nil, nil])
- puts "client(#{n}) server(#{ans[1]}) #{ans[2]} #{ans[3]}"
- end
- }
- end
-
- def watcher(ts)
- Thread.start {
- loop do
- begin
- sleep 1
- p ts.rd(['req', nil, nil], true)
- rescue ThreadError
- puts "'req' not found."
- end
- end
- }
- end
-
- (0..3).each do |n|
- servers.push(server(ts, n))
- end
-
- (1..6).each do |n|
- clients.push(client(ts, n))
- end
-
- (1..3).each do
- watcher(ts)
- end
-
- clients.each do |t|
- t.join
- end
-end
-
-
-
diff --git a/sample/drb/rinda_ts.rb b/sample/drb/rinda_ts.rb
deleted file mode 100644
index 6f2fae5c0f..0000000000
--- a/sample/drb/rinda_ts.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'drb/drb'
-require 'rinda/tuplespace'
-
-uri = ARGV.shift
-DRb.start_service(uri, Rinda::TupleSpace.new)
-puts DRb.uri
-DRb.thread.join
diff --git a/sample/drb/rindac.rb b/sample/drb/rindac.rb
deleted file mode 100644
index 72be09deaf..0000000000
--- a/sample/drb/rindac.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'drb/drb'
-require 'rinda/rinda'
-
-uri = ARGV.shift || raise("usage: #{$0} <server_uri>")
-
-DRb.start_service
-ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, uri))
-
-(1..10).each do |n|
- ts.write(['sum', DRb.uri, n])
-end
-
-(1..10).each do |n|
- ans = ts.take(['ans', DRb.uri, n, nil])
- p [ans[2], ans[3]]
-end
-
diff --git a/sample/drb/rindas.rb b/sample/drb/rindas.rb
deleted file mode 100644
index 9fd9ada2d1..0000000000
--- a/sample/drb/rindas.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require 'drb/drb'
-require 'rinda/rinda'
-
-def do_it(v)
- puts "do_it(#{v})"
- v + v
-end
-
-uri = ARGV.shift || raise("usage: #{$0} <server_uri>")
-
-DRb.start_service
-ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, uri))
-
-while true
- r = ts.take(['sum', nil, nil])
- v = do_it(r[2])
- ts.write(['ans', r[1], r[2], v])
-end
diff --git a/sample/drb/ring_echo.rb b/sample/drb/ring_echo.rb
deleted file mode 100644
index c54628b54c..0000000000
--- a/sample/drb/ring_echo.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'drb/drb'
-require 'drb/eq'
-require 'rinda/ring'
-
-class RingEcho
- include DRbUndumped
- def initialize(name)
- @name = name
- end
-
- def echo(str)
- "#{@name}: #{str}"
- end
-end
-
-DRb.start_service
-
-renewer = Rinda::SimpleRenewer.new
-
-finder = Rinda::RingFinger.new
-ts = finder.lookup_ring_any
-ts.read_all([:name, :RingEcho, nil, nil]).each do |tuple|
- p tuple[2]
- puts tuple[2].echo('Hello, World') rescue nil
-end
-ts.write([:name, :RingEcho, RingEcho.new(DRb.uri), ''], renewer)
-
-DRb.thread.join
-
diff --git a/sample/drb/ring_inspect.rb b/sample/drb/ring_inspect.rb
deleted file mode 100644
index c096cd7034..0000000000
--- a/sample/drb/ring_inspect.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'rinda/ring'
-require 'drb/drb'
-
-class Inspector
- def initialize
- end
-
- def primary
- Rinda::RingFinger.primary
- end
-
- def list_place
- Rinda::RingFinger.to_a
- end
-
- def list(idx = -1)
- if idx < 0
- ts = primary
- else
- ts = list_place[idx]
- raise "RingNotFound" unless ts
- end
- ts.read_all([:name, nil, nil, nil])
- end
-end
-
-def main
- DRb.start_service
- r = Inspector.new
-end
diff --git a/sample/drb/ring_place.rb b/sample/drb/ring_place.rb
deleted file mode 100644
index 11c6c2fe80..0000000000
--- a/sample/drb/ring_place.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'drb/drb'
-require 'rinda/ring'
-require 'rinda/tuplespace'
-
-unless $DEBUG
- # Run as a daemon...
- exit!( 0 ) if fork
- Process.setsid
- exit!( 0 ) if fork
-end
-
-DRb.start_service(ARGV.shift)
-
-ts = Rinda::TupleSpace.new
-place = Rinda::RingServer.new(ts)
-
-if $DEBUG
- puts DRb.uri
- DRb.thread.join
-else
- STDIN.reopen(IO::NULL)
- STDOUT.reopen(IO::NULL, 'w')
- STDERR.reopen(IO::NULL, 'w')
- DRb.thread.join
-end
diff --git a/sample/drb/simpletuple.rb b/sample/drb/simpletuple.rb
deleted file mode 100644
index 4bb4b1cff9..0000000000
--- a/sample/drb/simpletuple.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/local/bin/ruby
-# SimpleTupleSpace
-# Copyright (c) 1999-2000 Masatoshi SEKI
-# You can redistribute it and/or modify it under the same terms as Ruby.
-
-class SimpleTupleSpace
- def initialize
- @hash = {}
- @waiting = {}
- @hash.taint
- @waiting.taint
- self.taint
- end
-
- def out(key, obj)
- Thread.critical = true
- @hash[key] ||= []
- @waiting[key] ||= []
- @hash[key].push obj
- begin
- t = @waiting[key].shift
- @waiting.delete(key) if @waiting[key].length == 0
- t.wakeup if t
- rescue ThreadError
- retry
- ensure
- Thread.critical = false
- end
- end
-
- def in(key)
- Thread.critical = true
- @hash[key] ||= []
- @waiting[key] ||= []
- begin
- loop do
- if @hash[key].length == 0
- @waiting[key].push Thread.current
- Thread.stop
- else
- return @hash[key].shift
- end
- end
- ensure
- @hash.delete(key) if @hash[key].length == 0
- Thread.critical = false
- end
- end
-end
-
-if __FILE__ == $0
- ts = SimpleTupleSpace.new
- clients = []
- servers = []
-
- def server(ts)
- Thread.start {
- loop do
- req = ts.in('req')
- ac = req[0]
- num = req[1]
- ts.out(ac, num * num)
- end
- }
- end
-
- def client(ts, n)
- Thread.start {
- ac = Object.new
- ts.out('req', [ac, n])
- ans = ts.in(ac)
- puts "#{n}: #{ans}"
- }
- end
-
- 3.times do
- servers.push(server(ts))
- end
-
- (1..6).each do |n|
- clients.push(client(ts, n))
- end
-
- clients.each do |t|
- t.join
- end
-end
-
-
diff --git a/sample/drb/speedc.rb b/sample/drb/speedc.rb
deleted file mode 100644
index 64b8a65021..0000000000
--- a/sample/drb/speedc.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/local/bin/ruby
-
-uri = ARGV.shift || raise("usage: #{$0} URI")
-N = (ARGV.shift || 100).to_i
-
-case uri
-when /^tcpromp:/, /^unixromp:/
- require 'romp'
-
- client = ROMP::Client.new(uri, false)
- foo = client.resolve("foo")
-when /^druby:/
- require 'drb/drb'
-
- DRb.start_service
- foo = DRbObject.new(nil, uri)
-end
-
-N.times do |n|
- foo.foo(n)
-end
diff --git a/sample/drb/speeds.rb b/sample/drb/speeds.rb
deleted file mode 100644
index 7984059423..0000000000
--- a/sample/drb/speeds.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-class Foo
- attr_reader :i
- def initialize
- @i = 0
- end
-
- def foo(i)
- @i = i
- i + i
- end
-end
-
-# server = ROMP::Server.new('tcpromp://localhost:4242', nil, true)
-
-uri = ARGV.shift || raise("usage: #{$0} URI")
-foo = Foo.new
-
-case uri
-when /^tcpromp:/, /^unixromp:/
- require 'romp'
-
- server = ROMP::Server.new(uri, nil, true)
- server.bind(foo, "foo")
-
-when /^druby:/
- require 'drb/drb'
-
- DRb.start_service(uri, Foo.new)
-end
-
-DRb.thread.join
diff --git a/sample/openssl/c_rehash.rb b/sample/openssl/c_rehash.rb
index de4b66e902..8b005bbb84 100644
--- a/sample/openssl/c_rehash.rb
+++ b/sample/openssl/c_rehash.rb
@@ -156,7 +156,7 @@ private
end
def hash_name(name)
- sprintf("%x", name.hash)
+ sprintf("%08x", name.hash)
end
def fingerprint(der)
diff --git a/sample/trick2025/01-omoikane/authors.markdown b/sample/trick2025/01-omoikane/authors.markdown
new file mode 100644
index 0000000000..5c6823c077
--- /dev/null
+++ b/sample/trick2025/01-omoikane/authors.markdown
@@ -0,0 +1,5 @@
+* Don Yang
+ * omoikane@uguu.org
+ * cctld: us
+ * bsky.app/profile/omoikane.bsky.social
+ * twitter.com/uguu_org
diff --git a/sample/trick2025/01-omoikane/bf.rb b/sample/trick2025/01-omoikane/bf.rb
new file mode 100644
index 0000000000..74f5abe7e4
--- /dev/null
+++ b/sample/trick2025/01-omoikane/bf.rb
@@ -0,0 +1,81 @@
+#!/usr/bin/ruby -w
+# Simple BF interpretor.
+#
+# This works by translating input code into ruby and evaluating the
+# translated ruby code. Doing it this way runs much faster than
+# interpreting BF on our own.
+#
+# There is no error reporting whatsoever. A malformed input may result in
+# a syntax error at run time, but good luck in finding where it came from.
+
+
+# Setup empty tape and initial pointer position. Note that tape size is
+# fixed. We can make it infinite by initializing it to "[]" here and
+# adding some nil checks in the generated code, but avoiding those checks
+# makes the program run ~10% faster.
+$code = "t=Array.new(30000,0); p=0;"
+
+# Counters for pending add or shift operations. We buffer incoming +-<>
+# operators and output a single merged operation when we encounter a
+# different operator.
+$buffered_add = 0
+$buffered_shift = 0
+
+# Flush pending add operations, if any.
+def flush_add
+ if $buffered_add != 0
+ $code += "t[p]+=#{$buffered_add};"
+ $buffered_add = 0
+ end
+end
+
+# Flush pending shift operations, if any.
+def flush_shift
+ if $buffered_shift != 0
+ $code += "p+=#{$buffered_shift};"
+ $buffered_shift = 0
+ end
+end
+
+def flush_pending_ops
+ flush_add
+ flush_shift
+end
+
+# Convert input characters to ruby.
+ARGF.each_char{|c|
+ case c
+ when '+'
+ flush_shift
+ $buffered_add += 1
+ when '-'
+ flush_shift
+ $buffered_add -= 1
+ when '<'
+ flush_add
+ $buffered_shift -= 1
+ when '>'
+ flush_add
+ $buffered_shift += 1
+ when ','
+ flush_pending_ops
+ $code += "if c=STDIN.getc;" +
+ "t[p]=c.ord;" +
+ "else;" +
+ "t[p]=-1;" + # EOF is interpreted as -1.
+ "end;"
+ when '.'
+ flush_pending_ops
+ $code += "print t[p].chr;"
+ when '['
+ flush_pending_ops
+ $code += "while t[p]!=0;"
+ when ']'
+ flush_pending_ops
+ $code += "end;"
+ end
+}
+flush_pending_ops
+
+# Evaluate converted code.
+eval $code
diff --git a/sample/trick2025/01-omoikane/entry.rb b/sample/trick2025/01-omoikane/entry.rb
new file mode 100644
index 0000000000..c84f8079ae
--- /dev/null
+++ b/sample/trick2025/01-omoikane/entry.rb
@@ -0,0 +1,32 @@
+ a=+Math::PI/13
+ #Z---z';#za-mRUBY
+ #A-ZaA-Mn--\[+>+>++
+ '"N-Z(\++\[->++++@"
+ b=\[->+> +>+>\[h_
+ p%{} eact
+ zoraq ;%{ GF. rin);
+ %{eb} r A R p *""\]
+ <<<{{{ }<\]<b
+ ]<l(%w| } ; a;a=%Y/
+ evar{|c)} <][ #pgny\W{f
+ chaa,b)]>++[ ->+>>>>>[40v
+ .tr(= ' ;eval(%w{r=u=b= y =0;%{
+ (ct;c ) ; ] <<->--<<< < < ] >>[>,
+ exi}; a * = A RGV.siz e > 0 ? -1:1;
+ z=[] ; A R G F .ea c h _ l i n e{|i
+|i.eac h _ g r aph e m e _ c l u ster
+{|j|i f ( k = j.o r d ) < 3 3 ; r+=k<
+32?k==9? 8 - r%8 : k = = 1 0 | |k==13
+?[u+=1,-r][ 1]: 0 : 1 ; e lse;z+=[[u,
+r,j]];b+=r;y+=u;r+=1;end;}};if(s=z.si
+ze)>0;b/=s;y/=s;m,n=z[0];i=Math::tan(
+a/2);j=Math::sin(a);z.map!{|d|p=d[1]-
+b;q=d[0]-y;p-=(i*q).round;m=[m,q+=(j*
+ p).round].min;n=[n,p-=(i*q).round].
+ min;[q,p,d[2]]};r=n;u=m;z.sort.eac
+ h{|d|p,b=d;r=(u<p)?n:r;print"\n"
+ *(p-u),"\40"*(b-r),d[2];u=p;r=
+ b+1};print"\n";end}*"");%(]>
+ "tyvuts(}}.--.>--.>+.<++'
+ )b\40"gena.(c)2025<<<
+ #)#ehol""+a*.^_^
diff --git a/sample/trick2025/01-omoikane/remarks.markdown b/sample/trick2025/01-omoikane/remarks.markdown
new file mode 100644
index 0000000000..2aa77d64e4
--- /dev/null
+++ b/sample/trick2025/01-omoikane/remarks.markdown
@@ -0,0 +1,71 @@
+### Summary
+
+This is a rot13 filter. Given an input text, it will **rotate** the text by **pi/13** radians. Two modes of operation are available, selected based on number of command line arguments.
+
+Rotate clockwise:
+
+ ruby entry.rb < input.txt
+
+Rotate counterclockwise:
+
+ ruby entry.rb input.txt
+ ruby entry.rb - < input.txt
+
+### Details
+
+This program interprets input as an ASCII art with each character representing individual square pixels, and produces a rotated image to stdout. All non-whitespace characters are preserved in output, only the positions of those characters are adjusted. While all the characters are preserved, the words and sentences will not be as readable in their newly rotated form. This makes the program suitable for obfuscating text.
+
+ ruby entry.rb original.txt > rotated.txt
+ ruby entry.rb < rotated.txt > unrotated.txt
+
+But note that while `unrotated.txt` is often the same as `original.txt`, there is no hard guarantee due to integer rounding intricacies. Whether the original text can be recovered depends a lot on its shape, be sure to check that the output is reversible if you are using this rot13 filter to post spoilers and such.
+
+Reversibility does hold for `entry.rb`:
+
+ ruby entry.rb entry.rb | ruby entry.rb | diff entry.rb -
+ ruby entry.rb < entry.rb | ruby entry.rb - | diff entry.rb -
+
+Also, there is a bit of text embedded in the rotated version:
+
+ ruby entry.rb entry.rb | ruby
+
+But this text is encrypted! No problem, just rotate `entry.rb` the other way for the decryption tool:
+
+ ruby entry.rb < entry.rb > caesar_cipher_shift_13.rb
+ ruby entry.rb entry.rb | ruby | ruby caesar_cipher_shift_13.rb
+
+If current shell is `bash` or `zsh`, this can be done all in one line:
+
+ ruby entry.rb entry.rb | ruby | ruby <(ruby entry.rb < entry.rb)
+
+### Miscellaneous features
+
+To rotate to a different angle, edit the first line of `entry.rb`. Angles between -pi/2 and pi/2 will work best, anything outside that range produces more distortion than rotation, although the output might still be reversible.
+
+Setting angle to zero makes this program a filter that expands tabs, trim whitespaces, and canonicalize end-of-line sequences.
+
+This program preserves non-ASCII characters since input is tokenized with `each_grapheme_cluster`, although all characters that's not an ASCII space/tab/newline are given the same treatment. For example, the full-width space character (U+3000) will be transformed as if it's a half-width non-whitespace ASCII character.
+
+If input contains only whitespace characters, output will be empty.
+
+The layout is meant to resemble a daruma doll. There was still ~119 bytes of space left after fitting in 3 ruby programs, so I embedded a brainfuck program as well.
+
+ ruby bf.rb entry.rb
+
+A `sample_input.txt` has been included for testing. After rotating this file 26 times either clockwise or counterclockwise, you should get back the original `sample_input.txt`.
+
+ ruby entry.rb < sample_input.txt | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | ruby entry.rb | diff sample_input.txt -
+ ruby entry.rb sample_input.txt | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | ruby entry.rb - | diff sample_input.txt -
+
+Additional development notes can be found in `spoiler_rot13.txt` (rotate clockwise to decode).
+
+ ruby entry.rb < spoiler_rot13.txt
+
+### Compatibility
+
+Program has been verified to work under these environments:
+
+ * ruby 3.2.2 on cygwin.
+ * ruby 2.5.1p57 on linux.
+ * ruby 2.7.4p191 on linux.
+ * ruby 2.7.1p83 on jslinux.
diff --git a/sample/trick2025/01-omoikane/sample_input.txt b/sample/trick2025/01-omoikane/sample_input.txt
new file mode 100644
index 0000000000..244530f265
--- /dev/null
+++ b/sample/trick2025/01-omoikane/sample_input.txt
@@ -0,0 +1,35 @@
+ T U
+ S V
+
+ R T U W
+ S V
+
+ Q R W X
+
+ Q X
+ P i h g f Y
+ j e
+ P k d Y
+
+ O l c Z
+ O Z
+ m b
+
+* N N n + a A A *
+
+ o z
+ M B
+ M p y B
+
+ L q x C
+ r w
+ L s t u v C
+ K D
+
+ K J E D
+
+ I F
+ J H G E
+
+ I F
+ H G
diff --git a/sample/trick2025/01-omoikane/spoiler_rot13.txt b/sample/trick2025/01-omoikane/spoiler_rot13.txt
new file mode 100644
index 0000000000..91636176b8
--- /dev/null
+++ b/sample/trick2025/01-omoikane/spoiler_rot13.txt
@@ -0,0 +1,470 @@
+ .
+ text
+ ted t to
+ rota tex
+ dit HTML
+ to etes oss
+ sier wri acr
+ t earb"), ions .
+ ke itry. etat text
+ o ma "en erpr tive
+ ge te.g. e int: erna
+ L paut ( tiplsteps alt edit,he
+ a HTM inp muling cted ach dit tu
+ -w tes nt as havellow expe er ely ere yo
+ uby neragume can e fo the aftrect whethis
+ in/rt gee ar hat y th t. has stepindicesshat
+ usr/bcripingl ext tt tr texsult ion to prois w
+#!/his s a s of t migh inale re rotatededis aich ts.
+# TTakest. ece you origf th tra ts neike , wh tex
+ # stdou a piles, the ck i e exemenuld lusly ated the
+ # ite ang s tod che f th movu wotaneo rot pen
+ # To wrrent edit, an se orsort yoimul and nd o ne.
+ # diffe ome tion1-2. ecaue cu Whats s inal t, a en do
+ # ke srotaeps ous be thve. tex orig ayou t wh
+ # 1. Maply t st tediecausuitiated hold he l tex this
+ # 2. Apepea is lt bunint rot to rom ted. ated but
+ # 3. R cessficu is l and ough le fenabl upd nce, in
+ # pro diftextgina e en L fiipt the atie dable
+ # Thisalsoive ori larg HTMascr paste of p reay
+ # and rnat thedes: at's te a jav opy& bit its. t is Rubke },
+ # alteeditrovi t th nerawith en c fair l ed thar ine-li, %w{
+ # can pt p ayou to geser , th h a manua textasiequot %()
+ # scri a l ipt brow page witose ing 's eple %{},
+ # Make scrin a TML textn th writt itulti of ter
+ ## 1. thisTML the H dit ly o lly:l, buas m use Ras t
+ # Run ut H via ly euick ficaiviauby hakestes. eral wan
+ # 2. outp its anualte q peciy trse R.rb m quo Gen nd we
+ # y ed to mitera by sactlecauntryouble for rs a
+ # Appl eed you g Rut exs, b. ele+d ithm acte
+ # 3. ll nlet ardins nouageientsing Algor char paperpplyg
+ # stiill regons ilangnvenmon ast ces: are nal ply ardin
+ # Youol w hingtatither e co com "A Feren els rigi sim regato
+ # to re trienny o quit the on diff r pix . O andailsnter
+ # e mole oo ma areourse asedtwo e ous. tionates detn ce o
+ # Onltiped tthatof c is bith sincalue rotardine toatio is n
+ # mumparors and ithm h, w ls, er v r of coot du rot here ns d
+ # coerat//, lgor Paet pixeract enteinput, but to r, tratio, an.
+ # op{}, on aAlan ing cha ng cthe as isspecion. ente opeinput two
+ # %W tati by blendinal ardiing ues th reunct on ctionthe ne or
+ # e roion" for orig reghift vale witer f tatirota of a li
+ # Thotat ort the tionut snate car_cen e roise hapeextr
+ # R supperve idera aboordixtra get stablockwhe s an ons.
+ # No pres consthingd coed e see ore terclon tting tatiugh
+ # - to nal any-basee neble, a mcoun lot nser e roltho
+ # itio sayto 0ng, wersi tingise/ds a by i oducd, a
+ # Addsn'trms undit rev elecockwepenible ] prstea
+ # - doensfor routpu in se clIt dvers pi/2t in ly to
+ # trategehe o care utivt. e re i/2, tex ical
+ # inke t tra onsecr ou mad [-pt the omat
+ # ma h exat c othen be weenstorible. aut
+ # wite theachon ca beto divers sted
+ # Evenantecel tati glesnd te re adju s.
+ # guar cane ro y ane tell b l be ment
+ # willn th Onlrang sti wil ele
+ # ofte gle.that ight idth text
+ # n anide ion m . W ble erialink
+ atiooutsrmat/ 13 entss. edita les. he scan l
+ Rotles nsfo:PI elemcell all tup . T we
+ # Ang traath: edit ter to eme) textthat
+ # the = M of harac ched graph ate uch her.
+ #NGLE ightre c.9em" atta al, rotD, sh ot
+ A e hesqua= "0 be seri me toue I eac
+ Linure GHT me to x, aphe uniqs to
+ # ens_HEI s na (y, d grme aation
+ #LINE clas "t" t of s anaphe rot
+ yle SS = a lis nateh grrent
+ # St_CLA as ordi eaciffe
+ EDIT nput he cogivess d
+ ad i ed td to acro
+ # Lo y neaddeheme
+ # onl is grap 0
+ # Wemberame put _y = {|c|
+ # nuhe sd_in] ursor ster
+ # t loa = [ = c ine|_clu 8
+ defdataor_x 0 ne{|lheme x %
+ cursal =h_li_grap 1 sor_r\n" ]
+ seri.eaceach= " "x +=" cur= "\ , c]
+ ARGFine. c =rsor_ "\t 8 - c = rial
+ l if cu c ==x +=" || x, se
+ lsifrsor_ "\n0 sor_
+ e cu c ==x = 1 cur
+ lsifrsor_y += r_y, t
+ e cursor_ urso thay
+ cu [[c= 1 ilityed bext.
+ lse ta +=_x +1 obabollowal t
+ e daursor += e pron frigin
+ cerial ass. s thtatihe o
+ s of m easee roin t l be hat
+ end nter incrkwislts wilges thave
+ m ce nter clocresu heret ed We
+ } a fro n cee. a sa) o, taighion.
+ dat nter atio, i.e ver zer strotat
+ } turn n ce rotible vic frome.g.he r ,
+ re tatio s asvers (or away er, er t tione.
+ nd e ro mase retion und cent aftcts: rotaitiv
+ e mput er ofll brota e rotionld betifa o. ox. ftern pos
+ # Co centon wiise ow wrotashouse ar zerng box aemai r
+ # ing tatilockw to hthe hey the d ofunding bon r othey
+ # Use roterc due ear an tduce nsteaf bounditati s atbilittion
+ # thcoun ely, ts nd tho re ty iter of bor ro factersiul op
+ # a unattifacaggegs t fini cenner oafte arti revusef f
+ # forte arore jthin e ino be cor and get theost er or
+ # Unsiblut mious itivon to before we losehe m centr fo
+ # vime o var postation ts be thatlso be t theedito
+ # coried owardf rotatinate e is we a to ause an and the t
+ # t nd tter of roordi thes andpears ll catesaddsm in tha
+ # Rou center ol co of ter,s ap s wienerrts rithd for
+ # - Set cenat al all cen mas cterly guppoalgo neer).
+ # - Seth th with ther of charat onso sion reatithe
+ # - suc ened d ofente. ing script alotat a gol e
+ # happnsteang cacts emovhis r thahe re iss to
+ # hat es i Usirtif nd rhy tditoent tther thi
+ # Wplacure.the a ng ais wan eplemsure for
+ # featite ertiich ave reimnot need
+ # desp t ins, whTo h to am any
+ # thashiftt. need. Ie is
+ # Note to g texill riptther
+ # massacin we wvascure
+ # repltes,ed jaot sa)
+ # deleerat am n(dat ze
+ # genl (Ienter ta.si
+ # tooet_cy = 0t| / da
+ #ef g = cach{|1] cy
+ d cxta.e+= t[0] ize,
+ da cx += t[ ta.s es.
+ cy / da inat
+ n cx oorda)
+ } etur to ccy, .
+ r ion cx, 2) gain
+ end rotatta, (a / X a
+ ply te(da:tan(a) | r in
+ # AprotaMath::sinp{|tnts. shea
+ def x = Math:a.maonte then
+ ry = n dater c cx Y,
+ retur Cent1] - cy r in me).
+ r # = t[0] - shead aphe eme.
+ x = t[ X, round , gr graph
+ y r in y).round erial ach
+ Shearx * x).roun x, s nd e
+ # -= (ry * y). (y, arou
+ x += (rx * ted ] pan
+ y -= ( updat[3] ne s
+ x urn 2], ith o
+ # Ret, t[ xt wfix)
+ [y, x L te_pre
+ HTM, id
+ } k ofdata0] n
+ d blocock(ata[ ].min
+ en rate e_bl = d t[1]].mi
+ Geneneratin_xt| _x, t[0]
+ # f ge_y, mch{|[min_y,
+ de minta.eax = [min >\n"
+ da min_y = ix}\"
+ min_ x pref
+ min_y {id_
+ } x = min_=\"# r_y)
+ rsor_y = e id{|t| curso
+ cursor_"<preach y -
+ cuxt = ort.t < y * (
+ teata.sx = or_y"\n"
+ d y, curs += = yin_x
+ if textor_y = m
+ cursor_x
+ curs [3] &" "
+ = t== "amp;"
+ end textext = "&= "<
+ ner_er_text xt =lt;"" ' +
+ in inner_tr_te= "&= "> '">
+ if inninneext xt =gt;" SS +_s +
+ sif er_tr_te= "& x) +_CLA].to
+ el inninneext rsor_EDIT t[2
+ sif er_t - cu"' + ix +
+ el inn (x ass=_pref
+ d " *n cl+ id low.
+ en += "<spa="' t + er be
+ ext '" id_tex numb
+ t 'nneran>" ial ns.
+ i</sp+ 1 ser colum
+ "= x re>" next. by
+ r_x n</p the airs them
+ urso + "\ find er p oup
+ c ext er, numbta) d gr
+ } rn t numbrialap(das an
+ retu ial f sewn_my row
+ nd serst or_dors b
+ e eacha liursoumbe
+ For rns te_cal n ]]
+ # Retuneraseri} |t| ] [t[2
+ #ef geort = {ach{t[1]] += ]
+ d # Sumnsrt.emns[t[1] [t[2]
+ cola.socolumns[ ] = n.
+ dat if colu t[1] olum 0]]) .
+ e mns[ ch c [r[ ight
+ elscolu or ea 1] + he r by
+ rs f e - to t sortnext
+ end umbe .siz mber we the
+ al n r| [1, r l nu o if us
+ } seri [] |_, ip(r eria s, s get
+ Add ls =ach{ r.z xt s inateould )
+ # erians.es += e ners. oordhat w [0]]
+ solumrial s d th pai n) c1, t ials
+ c se rial , finmberta) olum by [ser a
+ n se mberal nup(daw, cials 1] + extr
+ }etur l nuseriht_ma (ro ser e - one
+ r eria of _rig with all .siz get
+ end ch slistrsortartotate [2]}ials . e we ,'
+ r eas a e_cues snd r t| t ser airs sinc + '"
+ # Foturnerattuples a. map{|s[1, ue p) ine, o_s
+ # Re genput tuplbersort.erial valairsnewl 1].t
+ def# Input numta.sip(s keyal_ping + t[
+ # inrial= dals.z s asserirail efix
+ # seals eria pairix, ut t + pr
+ serirn s mber(prefitho "'
+ retu l nu_mapies wate. '":
+ eriarsorentrtempl|t| _s +
+ end at st_cumap the .map{].to
+ Formnverate rom airs+ t[0
+ # f coenerne fal_pfix
+ de # Gewliseri pre es.
+ # nurn "' + valu
+ ret' " nate
+ "\n ordi
+ } * f co) a[0]
+ d ge odata dat
+ en ranize(_x =
+ Getet_s minn_x
+ #ef gn_y,= min_y min 1
+ d mix_x = mi|t| , x].max y +
+ max_y ach{t in_x, x].min min_
+ mata.ex = = [max_x, y].max y -
+ da y, n_x = [min_y, y]. max_
+ mix_x = [max_y 1,
+ man_y = [m n_x +
+ mix_y - mi
+ ma x_x
+ n ma
+ }etur
+ r ut
+ end _inp
+ loadty? ) a) GLE)) /td>
+ a = .emp (data(dat -ANNGLE ")}< >
+ datdatarn nter_size cy,y, A d> r> , "Ltd> }</td
+ if retu t_ce get cx,x, c /hea "><tdata)}</"R")
+ = geht = data,a, c le>< ng="4eft_ "M"ta,
+ end cy heig ate(e(dat /tit addiock(lata,t_da
+ cx,th, rototat est< ellpe_block(drigh
+ wid ta = = r te t 1" cerate_bllock(
+ t_dadata >Rota ng="{generatte_b l>
+ lefght_ OT" itle pacip">#{gennera labe
+ ri <<"Ed><t cells="top">##{ge le)</
+ int <hea "1" align="toop"> "> togg or
+ prtml> der=t" valignn="t edit to l> errght,
+ <hody> bor"left" vvalig id="(ESC"><u izes-hei
+ <bableign="lefft" ox" dit nonet. minimline
+ <td align=="le heckble elay: tex hat sing
+ <td allignble>e="c>Enabdisplace . ne tcreap.
+ <ttd a</ta typdit"yle=" repor. anel he oy deerla
+ </tr>nputr="e" sters =cursct p ep tis bo ov
+ <p><il fohelpractmove sele nd keo thes t
+ <labeid=" chas = ab = s, also d lin
+ <div SCII keyft+to. "> aluean ae the ;
+ <li>Arrow shi und riptng vWe ccaus ght)
+ <li>Aab /+Z = vascpacio. ill tHei
+ <li>TCtrliv> xt/jaer-sratich wM");; offse
+ <<li>></d ="te lettect o muId("HT}" / p.
+ </ul typerentd aspt tontByHEIG dth
+ ipt iffesireg thalemeINE_ etWi
+ <scrry de deasin.getE"#{L 2) offs
+ // To thecrementht = 0.0 - p.
+ // tut ddocuHeig x += em";ght}
+ // bp = line= 0; 2; .0; + "{hei
+ var yle.t_x or =x < 2 = x / #
+ p.st bes_err 0; cingdth}
+ var min x = erSpa#{wi
+ var(var lett.abs( )
+ for yle.Mathr > e
+ { p.ste = erro ; ;
+ var min_ r = e"em"
+ if( erro x + t_x;); }";
+ { min__x = bes("L"IGHT
+ best ng =ByIdE_HE
+ Spaciment{LINt_x;"); T}";
+ } tteretEle= "# besd("REIGH
+ e.lent.gight ng =tByINE_H;
+ } stylcumeneHeSpaciemen#{LIst_x
+ p.= doe.littergetEl = "= be
+ p style.leent.eighting
+ p.stylocumineHrSpac ta))}
+ p. = dle.lette e; t_da }
+ p.style.l tate.fals . (lefa))}ata))
+ p.sty le sit = tion ns. _map(datht_d
+ p itabe_ed posi itio down_map(rig
+ / Wrnabl rsor ; pos rsor_down_map )}
+ /ar e t cu "M0" rsor e_cursor_down data)
+ v rrenor = t cu erate_cursor_ eft_)} ))}
+ / Cucurs o nex generate_cu ap(lata)_data
+ /var ng t "L", generat ht_map(dight
+ appi = map("M", gen _right_map(r
+ // Mdown rsor_map("R", ursor_right_m
+ var t_cursor_map( te_cursor_rig
+ { nvert_cursor_ nerate_cursor
+ #{convert_cu , generate_c
+ #{conver ("L", genera rs.
+ #{co ht = _map("M", ge ) pai
+ }; rig ursor_map("R" text
+ var rt_cursor_map nal
+ { onvert_cursor rigi
+ #{convert_c x, o n))
+ #{conve uffi . (dow
+ #{c (id s []; ions tries
+ }; of ist = osit t.en )
+ Listdo_l or p bjec ght)
+ // r un curs of O s(ri
+ va erse}; ue] ntrie
+ Rev = { {}; val ct.e
+ //r upft =[key, Obje
+ var lenst key; of
+ var(co e] = lue]
+ fo valu , va on.
+ { up[ [key ey; siti
+ onst = k e po ;
+ }or(c alue] . e sam tyle;
+ f ft[v okes$/; t th = style;
+ { le ystr!-~] rs a tyle = style
+ ed ke /^[ actele) x).style = s
+ } cepteys = char sty suffix).style
+ / AcditK for (id, (1);" + suffix).s
+ /ar e tyle tyle bstrd("L" + suffi
+ v et s setS d.sutById("M" +
+ // Stion = iementById("R .
+ func uffixetElementByI tion
+ { ar sent.getElemen posi
+ vocument.getEl n. sor
+ document.g itio s cur . 0";
+ docum posd) viou tion ff808
+ d rsoror(i pre posi nd:# ;
+ } te cuCurs t at rsor ); grou xt])
+ Updan set ligh""); w cu f80"back erTe
+ // ctio highor, t ne :#80f = " .inn
+ fun lear curs ht a oundstyle ion. fix)
+ { // Ctyle( hlig ckgrid). osit suf
+ setS hig "bayId( me p "M" +t;
+ pdate id;sor,entB at sa yId(= text;
+ // Usor =(curElem ers entBext = text;
+ curStyle.get ractxt) ElemnerText = tex
+ setument cha, te .get).innerText
+ doc fort(id 1); umentffix).innerT
+ texteTex str( doc + suffix).in
+ } lace plac .subfix,("L" + suffix
+ Repon re = id[sufById("M" + su
+ //ncti fix ush(mentById("R"
+ fu r sufst.ptElementById
+ { vado_lit.getElement
+ uncument.getEle
+ document.ge it. [1];
+ documen t ed ) ntry[1];
+ do ecen = 0 t = entry[1];
+ st r() th = rText = entry
+ } do moundo leng innerText = e
+ / Untion ist. ); ix).innerTex
+ /func do_l pop( suffix).inne
+ { f( un ist. L" + suffix).
+ i urn; do_l[0];Id("M" + suff
+ { ret = unntryntById("R" +
+ try = elementById("
+ }ar enffixgetElementBy x);
+ var suent.getEleme suffi
+ vdocument.getEit ) ] +
+ document.e_ed or[0
+ documnabl curs ";
+ if( e sor( line
+ { tCur "in
+ se us. lay =
+ } statt() it; disp
+ dit _edi e_ed yle. ;
+ } ge eggle nabl ).st one"
+ Chann to = !e) elp" = "n
+ //nctio dit dit ; Id("h play ;
+ fu le_ele_e sor)ntBy .dis edit
+ { enabenab (curleme tyle able_ )
+ if( rsorgetE ").s = en S}")
+ { etCuent. ; help ked CLAS
+ socum "")yId(" chec DIT_
+ d sor,entB t"). ("#{E
+ } e (curElem ("edi Name
+ els tyle.get ById lass
+ { setSment ment sByC {
+ docu tEle ment =>
+ t.ge s. etEle ent)
+ } umen enernt.g (ev
+ doc listcume ick",
+ ent f do ("cl
+ } d ev t o ener ) => {
+ // Adonst Listedit nt) ) )
+ for(c ventble_ id); (eve "Z"
+ { addE ena r(t. n", y ==
+ t. if( urso ydow t.ke
+ { setC r("ke even
+ tene ||
+ } tLis) e" ) = "z"
+ ); Evendit Escap ey =
+ } .addle_e == " nt.k ) )
+ } mentenab key (eve "Z"
+ docuf( ! ent. (); && y ==
+ i ( ev edit rlKey t.ke
+ { if gle_ t.ct even
+ { tog even " ||
+ if( = "z
+ }lse ; ey =
+ e do() nt.k
+ { un (eve
+ n; y && s) )
+ }etur rlKe tKey
+ r t.ct (edi );
+ } even match .key
+ if( (); key. vent
+ { undo ent. or, er]); )
+ ( ev curscurso wUp" e" )
+ } e if ext(ght[ Arro spac
+ els aceTr(ri == " Back
+ { replurso .key ); n" ) == "
+ setC vent rsor] wDow key
+ f( e p[cu Arro vent. )
+ } se i or(u == " || e " "
+ el Curs .key r]); ft" ==
+ { set vent curso owLe .key
+ f( e own[ "Arr event
+ } se i or(d y == ; || M"}
+ el Curs t.ke or]) ght" ": "L"};
+ { set even [curs owRi , "R": "
+ if( left "Arr "L", "R
+ } lse sor( y == ); "M": "R"
+ e tCur t.ke sor] "R", "M":;
+ { se even t[cur b" ) L": "M", r(1)
+ if( righ "Ta ? {"L": subst
+ }lse sor( ey == Key : {"sor.
+ e tCur nt.k hift cur {
+ { se eve ent.s ]] + ) =>
+ if( = ev or[0 vent
+ }else ext [curs " ) , (e
+ { ar n nextsor); cape ick"
+ v r = (cur "Es ("cl
+ ursorsor ey == ener
+ cetCu nt.k tList
+ s eve ); Even
+ } if( dit( (); .add
+ else le_e fault it")
+ { togg ntDe ("ed
+ reve tById
+ } nt.p emen
+ eve etEl();
+ ; nt.gedit
+ })cumegle_
+ do tog
+ ; pt> >
+ })scri html
+ </ y></
+ /bod
+ <OT
+ E
diff --git a/sample/trick2025/02-mame/authors.markdown b/sample/trick2025/02-mame/authors.markdown
new file mode 100644
index 0000000000..0e420fdf5d
--- /dev/null
+++ b/sample/trick2025/02-mame/authors.markdown
@@ -0,0 +1,3 @@
+* Yusuke Endoh
+ * mame@ruby-lang.org
+ * cctld: jp
diff --git a/sample/trick2025/02-mame/entry.rb b/sample/trick2025/02-mame/entry.rb
new file mode 100644
index 0000000000..d5de370dc9
--- /dev/null
+++ b/sample/trick2025/02-mame/entry.rb
@@ -0,0 +1,34 @@
+From:pd <pd-@example.com> (`)
+Date:Wed,01 Jan 2025 00:00:00 +0000
+Subject:[PATCH] +an(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#TRICK2025]}
+
+--- /dev/null
++++ pd.rb
+@@ -0,0 +1,27 @@
++%;`);;BEGIN{eval$s=%q[eval(%q[F=File;puts((dup)?(q="%;`);;BEGIN
++{eval$s=%q[#$s]}";U,*,V=R=(0..33.0).map{|t|q.gsub(/./){i=$`.siz
++e;c=(i/64*2i-26i+i%64-31)*1i**(t/16.5);x,y=c.rect;r=c.abs;r<13?
++4<=r&&r<6&&x>-4||-5<x&&x<=-3&&-6<y&&y<11??.:?X:$&}};B,A="---|%s
++\n+++|%s\n@@|-%s,%s|+%s,%s|@@\nFrom:pd|<pd-@example.com>|(`)\nD
++ate:%a,%d|%b|%Y|%T|%z\nSubject:[PATCH]|".tr(?|,z="\s")[/@.*\n/]
++,$`;(i=R.index(q))?(S,T=i<33?R[i,(f=->i{(Time.gm(2025)+86400*i)
++.strftime$'};o=f[i+1]+(fXXXXXXXXXXXXXXX[0]+q[/.*\z/]+?\n*2+A%["
++/dev/null",v="pd.rb"]+XXXXXXXXXXXXXXXXXXXB%[0,0,1,27]+U.gsub(/^
++/,?+)).lines[-i-2],EXXXXXXXXXXXXXXXXXXXXXXX,a=A%[v,v];V<<"\n(`\
++n#{a+B%[0,0,1,1]}+dXXXXXXXXXXXXXXXXXXXXXXXXXup=(`)";2)]:($*.siz
++e!=2&&abort(["usagXXXXXXXXX.........XXXXXXXXXe:",$0,F,F]*z);$*.
++map{o=A%$*;F.read(XXXXXXXXX..XXXXXX..XXXXXXXX_1)});a=[i=0]*v=(s
++=[s]+S.lines).sizeXXXXXXXXX..XXXXXX..XXXXXXXX;c=b=s.map{c=_1&&[
++c,?-+_1,i+=1]||0};XXXXXXXXX..XXXXXX..XXXXXXXXT.lines{|t|s.map{|
++s|a<<((s)?[x=a[-1]XXXXXXXXX.........XXXXXXXXX,y=a[-v]].max+((f=
++s==t)?1:0):0);c,d=(XXXXXXXX..XXXXXXXXXXXXXXXf)?[v+1,z+t]:s&&(x>
++y)?[1,?-+s]:[v,?++t]XXXXXXX..XXXXXXXXXXXXXX;b<<[b[-c],d,i+=1]}}
++;c=b[-1].flatten;b=c[(XXXXX..XXXXXXXXXXXX1..)%2];(b.map{_1[0]}*
++E).scan(/\s{,3}([-+]\s{,XXXXXXXXXXXXXXX6})*[-+]\s{,3}/){n=c[2*i
++=$`.size];o=o,B%[n%v+1-1/v,(m=c[2.*i+j=$&.size]-n)%v,T>""?n/v+1
++:0,m/v],b[i,j]}):(o=[];a,b=[A,B].map{_1.sub(?+){'\+'}%(['(\S+)'
++]*4)};$<.read=~//;F.write$2,(s=F.readlines$1;o<<[:patching,F,$2
++]*z;(*,n,i,m=[*$~].map{_1.to_i};n+=m;($'=~/\A((-)|\+)?(.*\n)/;$
++2?s[i-=1,1]=[]:$1?s[i-1,0]=$3:n-=1;i+=1;n-=1)while+n>0)while/\A
++#{b}/=~$';s*E)while$'=~/^#{a}/);o):([*[?l]*799,1].shuffle*E).sc
++an(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#TRICK2025]}
diff --git a/sample/trick2025/02-mame/remarks.markdown b/sample/trick2025/02-mame/remarks.markdown
new file mode 100644
index 0000000000..8be86ebc2d
--- /dev/null
+++ b/sample/trick2025/02-mame/remarks.markdown
@@ -0,0 +1,141 @@
+# A Lesser "Patch" Program
+
+This program is a minimalistic version of the traditional "patch" command, which looks like a patch.
+
+## Usage as a "Patch" Command
+
+The program reads a unified diff file from standard input and applies the changes to the specified files.
+
+To apply `test.patch` to `sample.rb`, use the following commands:
+
+```
+$ cp sample.orig.rb sample.rb
+$ ruby entry.rb < test.patch
+```
+
+After running these commands, verify that `sample.rb` has been modified.
+
+## Usage as a Patch File
+
+Interestingly, this program is not just a patch-like tools -- it *is* a patch.
+This duality allows it to be applied like a regular patch file.
+
+The following will create a file named pd.rb.
+
+```
+$ patch < entry.rb
+```
+
+Alternatively, you can achieve the same result using `entry.rb`:
+
+```
+$ ruby entry.rb < entry.rb
+```
+
+The generated `pd.rb` produces a new patch.
+
+```
+$ ruby pd.rb
+```
+
+The produced patch is self-referential, targeting `pd.rb` itself.
+To apply it:
+
+```
+$ ruby pd.rb | ruby entry.rb
+```
+
+You'll notice the `p` logo rotates slightly counterclockwise.
+
+The modified `pd.rb` outputs the patch for itself again, apply the patch repeatedly--a total of 33 times!
+
+## From `p` to `d`
+
+The center `p` logo symbolizes a "patch."
+When rotated 180 degrees, it resembles a `d`, signifying a transformation in functionality.
+`pd.rb` now operates as a simplified "diff" command:
+
+```
+$ ruby pd.rb
+usage: pd.rb File File
+
+$ ruby pd.rb sample.orig.rb sample.rb
+--- sample.orig.rb
++++ sample.rb
+...
+```
+
+## Integration with Git
+
+The patches are compatible with Git's `git am` command, which imports patches in mbox format.
+
+Start fresh by removing `pd.rb` and initializing a Git repository:
+
+```
+$ rm -f pd.rb
+$ git init
+Initialized empty Git repository in /home/...
+```
+
+And import `entry.rb` as a patch to the repository:
+
+```
+$ git am --committer-date-is-author-date entry.rb
+Applying: +(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#_TRICK2025_]}
+applying to an empty history
+```
+
+Verify the commit history:
+
+```
+$ git log
+commit 1e32693f11c1df77bd797c7b3e9f108a3e139824 (HEAD -> main)
+Author: pd (`) <pd-@example.com>
+Date: Wed Jan 1 00:00:00 2025 +0000
+
+ +an(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#TRICK2025]}
+```
+
+Notice that the Author and Date are properly set.
+
+To apply subsequent patches:
+
+```
+$ for i in `seq 0 32`; do ruby pd.rb | git am --committer-date-is-author-date; done
+```
+
+*(A fun details: you will see the `b` logo!)*
+
+Now, view a commit history by the following command:
+
+```
+$ git log --oneline
+```
+
+You will rediscover the original `entry.rb` unexpectedly.
+
+If you set `--committer-date-is-author-date` appropriately, you should be able to run the output of `git log --oneline` as is.
+
+Try this unusual command:
+
+```
+$ git log --oneline | ruby - test.patch
+```
+
+## A Little Something Extra
+
+Interestingly, `pd.rb` -- functioning as a diff command -- is a patch to itself.
+Reveal hidden details with:
+
+```
+$ ruby entry.rb pd.rb
+$ ruby pd.rb
+```
+
+Can you spot the difference?
+
+## Limitations
+
+* I tested it with ruby 3.3.6, git 2.45.2, and GNU patch 2.7.6.
+* No error check at all. The lesser patch do not care if there is a discrepancy between what is written in the patch and the input file, and will write over the existing file without prompt.
+* It is assumed that the text files have a new line at the end.
diff --git a/sample/trick2025/02-mame/sample.orig.rb b/sample/trick2025/02-mame/sample.orig.rb
new file mode 100644
index 0000000000..3d880b387d
--- /dev/null
+++ b/sample/trick2025/02-mame/sample.orig.rb
@@ -0,0 +1,8 @@
+def add(a, b)
+ a + b
+end
+
+if __FILE__ == $0
+ result = add(3, 5)
+ puts "Three plus five is #{ result }"
+end
diff --git a/sample/trick2025/02-mame/test.patch b/sample/trick2025/02-mame/test.patch
new file mode 100644
index 0000000000..0a63ae8a4c
--- /dev/null
+++ b/sample/trick2025/02-mame/test.patch
@@ -0,0 +1,16 @@
+--- sample.rb
++++ sample.rb
+@@ -2,7 +2,13 @@
+ a + b
+ end
+
++def sub(a, b)
++ a - b
++end
++
+ if __FILE__ == $0
+ result = add(3, 5)
+ puts "Three plus five is #{ result }"
++ result = sub(5, 3)
++ puts "five minus three is #{ result }"
+ end
diff --git a/sample/trick2025/03-tompng/authors.markdown b/sample/trick2025/03-tompng/authors.markdown
new file mode 100644
index 0000000000..26ebe24da6
--- /dev/null
+++ b/sample/trick2025/03-tompng/authors.markdown
@@ -0,0 +1,3 @@
+* Tomoya Ishida (tompng)
+ * tomoyapenguin@gmail.com
+ * cctld: jp
diff --git a/sample/trick2025/03-tompng/entry.rb b/sample/trick2025/03-tompng/entry.rb
new file mode 100644
index 0000000000..0de2244979
--- /dev/null
+++ b/sample/trick2025/03-tompng/entry.rb
@@ -0,0 +1,74 @@
+eval->{%w[u=*? a..?i;l=*?j..? r;o=*?s..?z,?_
+;m='#-*&|^`!@$ '.chars;s=[[3] ,[0,1,3,4,6],[
+1,5],[1,4],[0, 4,6],[2,4],[2] ,[1,3,4,6],[],
+ [4], ];a= (0.. 7).m ap{[
+ ?;*_ 1+'a 4',: a1,? x*(_
+ 1+2) ]*"T /#{? x.*6 7-_1
+ }/x; "};v =([c =[?x *150
+ ]*4, a.reverse,[[6, 3,0].map{"a#{_
+ 1}T/ #{?x*15}/x"}*( ?;*42)+';xx']*
+ 30,a .map{_1.tr'14' ,'25'},c,]*n=$
+ /).g sub( /(^| ;)(;
+ *);/ ){$1 +?x* $2.s
+ ize+ ?;}; p,e= [0,1
+ ].ma p{|t |g=( ["(m
+ fT/' /;#{a=(0..9).m ap{"f#{_1}T/l#
+ {_1} =1./"}*?;};C"' ;#{a.tr'l',?u}
+ ;?C" ",(0..9).map{| i|a="l#{i}T/'/
+
+
+;C"' ;";b ="#{o[i-1]+?=i fTi>0}%+";(1..
+9).m ap{a <<l[_1-1]+"T/% #{c=m[_1]}/;";
+b<<c +";# {(d=_1+i)>10?' ca='+o[d-11]:d
+>9?' ca': o[d- 1]}=
+%"+c };a+ b+[m [1..
+],?+ ,?"] *';? '},"
+caT/ '/;C "';" +(1.
+.8).map{u[8-_1 ]+"T/#{u[9-_1] }=1./;"}*''+u[
+0]+h='=1;?"',( 1..9).map{|i|" u#{i}T/'/;C"';
+"+(0..8-i).map {u[8-i-_1]+"T/ #{u[8-_1]}=1./
+ ;"}* ''+u [i-1 ]+h}
+ ]*?; ).sp lit( /([^
+ ;]+; )/); ((0. .43)
+ .map {|y| c='' ;q=-
+ >{a= (y-22).abs;b=( c.size+_1-78).
+ abs; [a<7&&b<59||b< 15,(b-30).abs<
+ 14][ t]};110.times{ c+=q[8]?g.shif
+
+
+ t||? ;:q[-t]??;:'T' };c.gsub(';T',
+ 'TT' ).rstrip}*n).g sub(/(;|T)(;;+
+ )(;| $)/){$1+'/'+?x *($2.size-2)+'
+ /'+$ 3}}; F=Fi
+ le;1 0.ti mes{
+ |i|a ="(n fT/m
+ f=l# {i}= '/;n
+ f=f# {i}=?';def/("+ s[i].map!{"a#{
+ _1}" }*','+')=(';F. write"#{i}",a+
+ ?x*( 150-a.size)+n+ v[..-5]+'))&&'
+ +n}; a,*b ="/)
+ &&de f((C nCn<
+ <A"; c=") )./(
+ ";d= 'T}' ,?A,
+ '__= <<B';u.map{|v| b<<v+"TT%(T<<#
+ {v}T )TT";d=d,v,"AC n#{v}=<<B"};o.
+ zip( l,m){a+=?;+_1+ "T/%#{_3}/";c+
+
+
+=(_3[?#]||?#+_
+3)+"))./("+_2+
+?,};F.write'+'
+,n*2 6+[p [..-
+10]+ (a+c ).tr ('!@',%("')).g
+sub( /%([ '"`] )/,){$1},'#{TT
+T'+b *';T T'+d *n,?B,')=']*n+
+n;a, b=[u ,o].map{|v|(0.
+.8). map{ t=s[9-_1];t[0]
+&&t+ =[1] ;v[8-_1]+"T/#{
+t*?= }#/" }*?; +';a3='+?x*25}
+;F.w rite '=', [n*26]*2*e+a+n
++v+n +(b+ n+v) .tr(?a,?b)[..-
+9]+' )if~ exit
+'+n].join.tr('
+TRICK',_1)}[+"
+\x2025"<<-?\\]
diff --git a/sample/trick2025/03-tompng/remarks.markdown b/sample/trick2025/03-tompng/remarks.markdown
new file mode 100644
index 0000000000..7f3f4ac6cf
--- /dev/null
+++ b/sample/trick2025/03-tompng/remarks.markdown
@@ -0,0 +1,146 @@
+### Remarks
+
+Run it with no argument. It will generate 12 files: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + and =.
+
+```sh
+ruby entry.rb
+```
+
+Concat and syntax highlight them.
+
+```sh
+cat 2 0 + 2 5 = | ruby -run -e colorize
+cat 4 + 1 5 + 4 + 1 8 = | ruby -run -e colorize
+```
+
+I confirmed the following implementations/platforms:
+
+* ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +MN +PRISM [arm64-darwin22]
+* ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +YJIT +MN [arm64-darwin22]
+
+### Description
+
+Did you know that Ruby syntax can perform additive operations on two-digit numbers without Ruby runtime? This entry demonstrates a syntax level computation of Ruby grammar.
+
+`ruby entry.rb` will generate 12 files: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + and =.
+These files constitute a calculator system that runs on Ruby parser.
+
+To calculate `6 + 7`, concat `6`, `+`, `7` and `=`.
+
+```sh
+cat 6 + 7 =
+```
+
+The concatenated output is a Ruby script that does nothing. It is also an ASCII art of `█ + █ = ██` rotated 90 degrees.
+Now, let's try syntax highlighting that code.
+
+```sh
+cat 6 + 7 = | ruby -run -e colorize
+```
+
+Wow! You can see the calculation result `6 + 7 = 13` as a colorized ASCII art!
+
+This system can also add more than two numbers. All numbers should be one or two digits, and the answer should be less than 100.
+
+```sh
+cat 3 1 + 4 + 1 5 + 9 = | ruby -run -e colorize
+cat 1 + 2 + 4 + 8 + 1 6 + 3 2 = | ruby -run -e colorize
+cat 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 1 0 = | ruby -run -e colorize
+```
+
+If the syntax highlighting is hard to see, use this command to change the terminal color.
+
+```sh
+printf "\e]11;#000000\a\e]10;#333333\a\e]4;1;#ffaaaa\a"
+```
+
+### Internals
+
+To perform calculation, you need a storage and a control flow statement.
+Local variable existence can be used as a storage.
+Ruby syntax provides conditional local variable definition and local variable reset with state carry over which can be used as a control flow statement.
+
+#### Conditional Local Variable Definition
+
+Ruby syntax can define new local variables conditionally.
+
+```ruby
+# Defines x and y if a is defined
+a /x = y = 1./
+# Defines x and y if a is not defined
+a /1#/; x = y = 1
+# Defines x or y depend on the existence of local variable a
+a /(x=1);'/;(y=1);?'
+```
+
+#### Local Variables Reset
+
+Local variables can be cleared by creating a new `def` scope.
+
+```ruby
+x = y = z = 1
+def f
+# x, y, z are cleared
+```
+
+#### State Carry Over
+
+Some state should be carried over to the next `def` scope. There are two tricks to do it.
+
+```ruby
+a /%+/i; b /%-/i; def f(x)# +; def f(y) # -; def f(z)
+```
+
+```ruby
+a %(<<A); b %(<<B); def f
+x=<<C
+A
+y=<<C
+B
+z=<<C
+C
+```
+
+In both examples above, local variable defined in the new scope will be:
+
+```ruby
+x # if both a and b are not defined
+y # if a is defined
+z # if b is defined
+```
+
+Combining these two tricks, Ruby syntax can carry over two states to the next `def` scope. In this system, two states represents upper digit and lower digit.
+
+### File Structure
+
+```ruby
+# File 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+(code) &&
+```
+
+```ruby
+# File +
+(code) && def f(arg)=
+```
+
+```ruby
+# File =
+(code) if exit
+```
+
+```ruby
+# cat 1 2 + 3 + 4 5 =
+(one) &&
+(two) &&
+(plus) && def f(arg)=
+(three) &&
+(plus) && def f(arg)=
+(four) &&
+(five) &&
+(equal) if exit
+```
+
+### Limitation
+
+Number to be added must be one or two digits.
+Answer of the addition must be less than 100.
diff --git a/sample/trick2025/04-tompng/authors.markdown b/sample/trick2025/04-tompng/authors.markdown
new file mode 100644
index 0000000000..26ebe24da6
--- /dev/null
+++ b/sample/trick2025/04-tompng/authors.markdown
@@ -0,0 +1,3 @@
+* Tomoya Ishida (tompng)
+ * tomoyapenguin@gmail.com
+ * cctld: jp
diff --git a/sample/trick2025/04-tompng/entry.rb b/sample/trick2025/04-tompng/entry.rb
new file mode 100644
index 0000000000..881c1af871
--- /dev/null
+++ b/sample/trick2025/04-tompng/entry.rb
@@ -0,0 +1,36 @@
+ $c=%q@E="
+ \e[4%d;37m%s\e[m"
+ ;n=32.chr;pu ts"\e
+ [H\e[J#{$c=n*54+' $c=%
+ q'+[64.chr]*2*$c+';e val$
+ c.'+n*10+"\n"+n*57+"spl it*'
+ '"+n*15}";n=l=0;R=->y=0 {n+=1
+ ;l=$c.lines. map{|m|m=(0..79).chunk{380-n+
+ 36*Math.sin(0.04.*it-n )<9*y}.map{a=_2.map{m[it]}*''
+ ;_1&&E%[6,a]||a}*'';m!=l[~-y +=1]&&$><<"\e[#{y}H#{m}\e[37H
+ ";m}};N=(Integer$* [-1]resc ue+30)*H=44100;alias:r:rand
+ ;F=->e,w=1{a=b=c=0;d=( 1-e)**0 .5*20;->v=r-0.5{a=a*w*e+v
+ ;b=b*w*e*e+v;d.*a-2*b+c=c*w *e**3+ v}};A=->u,n,t{(0..n).
+ map{|i|u=u.shuffle.map{|w|R[]; a=u.s ample;b,c,d=[[0.5
+ ,(0.2+r)*H/3*1.1**i,[[1+r/10,1+r/ 10]][ i]||[1.2+
+ r/10,1.3+r/5]],[0.3,r*H/2,[1,1+r/5 ]]][t
+];e,f=d.shuffle;g=b+r;h=b+r;(0..[w. size/e, a.size/f
++c].max).map{g*(w[it*e]||0)+h*(a[[it-c,0].ma x*f]||0)}}}};j=A[A
+[(0..9).map{a=F[0.998,1i**0.02];(0..28097).m ap{a[].real.*0.1**(8.0*i
+t/H)-8e-6}},14,0].transpose.map{|d|a=[0]*3e3 ;15.times{|i|R [];b=r
+ (3e3);d[i].each_with_index{a[c=_2+b]=(a[c] ||0)+_1*0.63**i}} ;a},9,
+ 1][4..].flatten(1).shuffle;y=(0..3).map{F[ 1-1e-5]};m=[-1,1].map {[F[1
+ -1e-4],F[1-5e-5],it]};u=v=w=0;k=[],[],[] ;z=F[0.7,1i**0.5];File.o pen($
+ *.grep(/[^\d]/)[0]||'output.wav','wb') {|f|f<<'RIFF'+[N*4+36,'WA VEfmt
+ ',32,16,1,2,H,H*4,4,16,'data',N*4].p ack('Va7cVvvVVvva4V');N.tim es{|
+ i|$><<E%[4,?#]if(i+1)*80/N!=i*80 /N;t=[i/1e5,(N-i)/2e5,1].min;a,b,c=k
+ .map{it.shift||(j[20*r,0]=[g =j.pop];a=1+r/3;it[0..]=(0..g.size).m
+ ap{g[it*a]||0};0)};u=u *0.96+r-0.5;v=v*0.99+d=r-0.5;w=w*0.8+d
+ ;x=(z[].*1+0 .59i).imag;e=y.map(&:[]);f.<<m.map{|o,
+ p,q|r=a+(b+c)/2+(b-c)*q/5;s=o[r.abs]
+ ;r=t*t*(3-2*t)*(r+s*w/1e4+p[s]*x/1
+ e7+[[u,0],[v,1]].sum{_1*1.5**(e[
+ _2]+q*e[_2+2]/9)}/32)/9;r/(1
+ +r*r)**0.5*32768}.pack'v
+ *'}};puts@;eval$c.
+ split*''
diff --git a/sample/trick2025/04-tompng/remarks.markdown b/sample/trick2025/04-tompng/remarks.markdown
new file mode 100644
index 0000000000..b2d848c07c
--- /dev/null
+++ b/sample/trick2025/04-tompng/remarks.markdown
@@ -0,0 +1,43 @@
+# Seashore - Nature Sound
+
+Listen to the relaxing sound of ocean waves generated by Ruby.
+
+## Usage
+
+```sh
+ruby entry.rb
+ruby entry.rb seashore.wav 60
+```
+
+The default filename is `output.wav` and the default duration is 30 seconds.
+
+Tested with ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +MN +PRISM [arm64-darwin22]
+
+## Noise
+
+Noise sound is created by applying low-pass/band-pass filter to a white noise signal.
+Volume of the noise should change over time. This is also calculated by using low-pass filter.
+
+## Wave
+
+Sound of a single ocean wave is composed of hundreds of water splash sounds.
+Each water splash sound is composed of thousands of water drops and bubbles.
+This program creates this complicated sound by repeating sound mixing.
+
+```ruby
+sound2 = mix(sound1.change_pitch(rand), sound1.change_pitch(rand).delay(rand))
+sound4 = mix(sound2.change_pitch(rand), sound2.change_pitch(rand).delay(rand))
+...
+sound32768 = mix(sound16384.change_pitch(rand), sound16384.change_pitch(rand).delay(rand))
+
+splash1 = mix(sound1.delay(rand), sound2.delay(rand), sound4.delay(rand), ..., sound16384.delay(rand))
+splash2 = mix(splash1.change_pitch(rand), splash1.change_pitch(rand).delay(rand))
+splash4 = mix(splash2.change_pitch(rand), splash2.change_pitch(rand).delay(rand))
+...
+splash1024 = mix(splash512.change_pitch(rand), splash512.change_pitch(rand).delay(rand))
+
+wave_sound = [splash32, splash64, ..., splash1024].sample
+```
+
+This kind of repetition is often used in fractal rendering. In other words, this operation is rendering a fractal shape to the spectrogram canvas.
+It's an efficient way to create complex structure with low computational cost.
diff --git a/sample/trick2025/05-tompng/authors.markdown b/sample/trick2025/05-tompng/authors.markdown
new file mode 100644
index 0000000000..26ebe24da6
--- /dev/null
+++ b/sample/trick2025/05-tompng/authors.markdown
@@ -0,0 +1,3 @@
+* Tomoya Ishida (tompng)
+ * tomoyapenguin@gmail.com
+ * cctld: jp
diff --git a/sample/trick2025/05-tompng/entry.rb b/sample/trick2025/05-tompng/entry.rb
new file mode 100644
index 0000000000..4d30c5b5a9
--- /dev/null
+++ b/sample/trick2025/05-tompng/entry.rb
@@ -0,0 +1,118 @@
+module ReadableFizzBuzz
+ module Chain
+ end
+end
+
+include ReadableFizzBuzz
+
+Chain::Itself = Chain
+
+module Chain::Itself
+ module Void
+ A = B = C = D = E = F = G = H = I = J = K = L = M = Void
+ N = O = P = Q = R = S = T = U = V = W = X = Y = Z = Void
+
+ module Set
+ end
+
+ module Put
+ end
+
+ module WriteBack
+ end
+
+ module Not
+ include Void
+ end
+ end
+
+ module Off
+ include Void
+ end
+
+ module Nil
+ A = B = C = D = E = F = G = H = I = J = K = L = M = Off
+ N = O = P = Q = R = S = T = U = V = W = X = Y = Z = Off
+ end
+
+ module Next
+ include Nil
+ end
+
+ module Current
+ include Nil
+
+ Not = Off
+ Set = Put = Next
+ WriteBack = Current
+ end
+
+ True = If = Current
+ On = Next
+
+ module On
+ INT = 1
+ FIZZ = 'Fizz'
+ BUZZ = 'Buzz'
+ PREFIX = '0b'
+ FORMAT = "%d%s%s\n"
+ NEXT = __FILE__
+ end
+
+ module Off
+ INT = 0
+ FIZZ = BUZZ = nil
+ PREFIX = '0b1'
+ FORMAT = "%2$s%3$s\n"
+ NEXT = '/dev/null'
+ Not = True
+ end
+
+ module Initial
+ C = D = True
+ end
+
+ module ReadableFizzBuzz::Chain::Current
+ include Initial
+ end
+
+ If::C::Set::E = If::E::Set::F = If::F::Set::C = On
+ If::D::Set::G = If::G::Set::H = If::H::Set::I = If::I::Set::J = If::J::Set::D = On
+ If::F::Not::J::Not::Set::B = On
+ If::K::Not::Set::K = On
+ If::K::WriteBack::L = True
+ If::L::Not::M::Set::M = On
+ If::L::M::Not::Put::M = On
+ If::L::M::WriteBack::N = True
+ If::N::Not::O::Set::O = On
+ If::N::O::Not::Put::O = On
+ If::N::O::WriteBack::P = True
+ If::P::Not::Q::Set::Q = On
+ If::P::Q::Not::Put::Q = On
+ If::P::Q::WriteBack::R = True
+ If::R::Not::S::Set::S = On
+ If::R::S::Not::Put::S = On
+ If::R::S::WriteBack::T = True
+ If::T::Not::U::Set::U = On
+ If::T::U::Not::Put::U = On
+ If::T::U::WriteBack::V = True
+ If::V::Not::W::Set::W = On
+ If::V::W::Not::Put::W = On
+ If::V::W::WriteBack::X = True
+ If::X::Not::Y::Set::Y = On
+ If::X::Y::Not::Put::Y = On
+ If::X::Y::WriteBack::Z = True
+ If::Z::Not::Set::A = On
+end
+
+module Chain::Chain
+ Current = Chain::Next
+end
+
+include Chain
+
+module Chain::Current
+ NUMBER = A::PREFIX, Y::INT, W::INT, U::INT, S::INT, Q::INT, O::INT, M::INT, K::INT
+ printf B::FORMAT, NUMBER.join, C::FIZZ, D::BUZZ
+ load A::NEXT
+end
diff --git a/sample/trick2025/05-tompng/remarks.markdown b/sample/trick2025/05-tompng/remarks.markdown
new file mode 100644
index 0000000000..adb4bf4df8
--- /dev/null
+++ b/sample/trick2025/05-tompng/remarks.markdown
@@ -0,0 +1,106 @@
+### Remarks
+
+Just run it with no argument:
+
+```sh
+ruby entry.rb
+```
+
+I confirmed the following implementations/platforms:
+
+- ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +MN +PRISM [arm64-darwin22]
+- ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [aarch64-linux-musl]
+
+### Description
+
+Readability is important even for a simple fizz buzz program.
+
+These are the major ingredients of a spaghetti that makes program tasty and valuable but unreadable.
+
+- Many class definitions
+- Many method definitions
+- Many method calls
+- Many variables
+- Conditional branches
+
+These are what is acceptable for a readable program.
+
+- Many modules: Using only a single module in a program is not good.
+- Many constants: Better than magic numbers.
+- Module#include: Mixins are what module is for.
+- Many file loads: Usually better than loading a large file only once.
+- Minimal method calls: Needed for printing output.
+
+This program is doing something slightly difficult in the last few lines: print output and load ruby program.
+In contrast, the rest part of this program is extremely simple and easy. Module definition, constant definition and module inclusion. That's all.
+
+### Internals
+
+Called methods
+
+- `Module#include`
+- `Array#join`
+- `Kernel#printf`
+- `Kernel#load`
+
+Deeply nested module chain to avoid constant reassignment
+
+```ruby
+10.times do
+ module Root
+ module Chain
+ module X; end
+ module Y; end
+ module Z; end
+ end
+ end
+ include Root
+
+ module Chain::Chain
+ # Not a constant reassignment because Chain::Chain is always a new module
+ X = Chain::Y
+ Y = Chain::Z
+ Z = Chain::X
+ end
+ include Chain
+ p x: X, chain: Chain
+end
+```
+
+Constant allocation
+
+| Constant | Purpose |
+| ---------------------- | ----------------------- |
+| A | Loop condition |
+| B | Format (!Fizz && !Buzz) |
+| C, E, F | Fizz rotation |
+| D, G, H, I, J | Buzz rotation |
+| K, M, O, Q, S, U, W, Y | Iteration bits |
+| L, N, P, R, T, V, X, Z | Temporary carry bits |
+
+Instruction sequence with constant lookup magic
+
+```ruby
+# B = 1 if A
+If::A::Set::B = On
+
+# B = 1 if !A
+If::A::Not::Set::B = On
+
+# C = 1 if !A && B
+If::A::Not::B::Set::C = On
+
+# C = 1 if !A && !B
+If::A::Not::B::Not::Set::C = On
+```
+
+Loop with `load __FILE__`
+
+```ruby
+# A::NEXT is __FILE__ or '/dev/null'
+load A::NEXT
+```
+
+### Limitation
+
+Needs `/dev/null`
diff --git a/sample/trick2025/README.md b/sample/trick2025/README.md
new file mode 100644
index 0000000000..1d71f54620
--- /dev/null
+++ b/sample/trick2025/README.md
@@ -0,0 +1,16 @@
+This directory contains the top-five entries of
+the 5th Transcendental Ruby Imbroglio Contest for rubyKaigi (TRICK 2025).
+
+THESE ARE BAD EXAMPLES! You must NOT use them as a sample code.
+
+* 1st: "Most Revolutionary" - Don Yang
+* 2nd: "Most Useful" - Yusuke Endoh
+* 3rd: "Most Arithmetic" - Tomoya Ishida
+* 4th: "Best ASMR" - Tomoya Ishida
+* 5th: "Most Maintainable" - Tomoya Ishida
+
+These files are licensed under MIT license.
+
+For the contest outline and other winning entries, see:
+
+https://github.com/tric/trick2025
diff --git a/sample/uumerge.rb b/sample/uumerge.rb
index 1b81582c24..23f95ba465 100644
--- a/sample/uumerge.rb
+++ b/sample/uumerge.rb
@@ -22,7 +22,7 @@ while line = gets()
end
end
-raise "missing begin" unless $sawbegin
+raise "missing begin" unless $sawbegin > 0
out.binmode
while line = gets()
diff --git a/scheduler.c b/scheduler.c
index ef5ec7923f..7efd4274cb 100644
--- a/scheduler.c
+++ b/scheduler.c
@@ -9,21 +9,27 @@
**********************************************************************/
#include "vm_core.h"
+#include "eval_intern.h"
#include "ruby/fiber/scheduler.h"
#include "ruby/io.h"
#include "ruby/io/buffer.h"
#include "ruby/thread.h"
-// For `ruby_thread_has_gvl_p`.
+// For `ruby_thread_has_gvl_p`:
#include "internal/thread.h"
+// For atomic operations:
+#include "ruby_atomic.h"
+
static ID id_close;
static ID id_scheduler_close;
static ID id_block;
static ID id_unblock;
+static ID id_yield;
+
static ID id_timeout_after;
static ID id_kernel_sleep;
static ID id_process_wait;
@@ -37,10 +43,215 @@ static ID id_io_close;
static ID id_address_resolve;
static ID id_blocking_operation_wait;
+static ID id_fiber_interrupt;
static ID id_fiber_schedule;
+// Our custom blocking operation class
+static VALUE rb_cFiberSchedulerBlockingOperation;
+
+/*
+ * Custom blocking operation structure for blocking operations
+ * This replaces the use of Ruby procs to avoid use-after-free issues
+ * and provides a cleaner C API for native work pools.
+ */
+
+typedef enum {
+ RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED, // Submitted but not started
+ RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING, // Currently running
+ RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_COMPLETED, // Finished (success/error)
+ RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED // Cancelled
+} rb_fiber_blocking_operation_status_t;
+
+struct rb_fiber_scheduler_blocking_operation {
+ void *(*function)(void *);
+ void *data;
+
+ rb_unblock_function_t *unblock_function;
+ void *data2;
+
+ int flags;
+ struct rb_fiber_scheduler_blocking_operation_state *state;
+
+ // Execution status
+ volatile rb_atomic_t status;
+};
+
+static size_t
+blocking_operation_memsize(const void *ptr)
+{
+ return sizeof(rb_fiber_scheduler_blocking_operation_t);
+}
+
+static const rb_data_type_t blocking_operation_data_type = {
+ "Fiber::Scheduler::BlockingOperation",
+ {
+ NULL, // nothing to mark
+ RUBY_DEFAULT_FREE,
+ blocking_operation_memsize,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+};
+
+/*
+ * Allocate a new blocking operation
+ */
+static VALUE
+blocking_operation_alloc(VALUE klass)
+{
+ rb_fiber_scheduler_blocking_operation_t *blocking_operation;
+ VALUE obj = TypedData_Make_Struct(klass, rb_fiber_scheduler_blocking_operation_t, &blocking_operation_data_type, blocking_operation);
+
+ blocking_operation->function = NULL;
+ blocking_operation->data = NULL;
+ blocking_operation->unblock_function = NULL;
+ blocking_operation->data2 = NULL;
+ blocking_operation->flags = 0;
+ blocking_operation->state = NULL;
+ blocking_operation->status = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED;
+
+ return obj;
+}
+
+/*
+ * Get the blocking operation struct from a Ruby object
+ */
+static rb_fiber_scheduler_blocking_operation_t *
+get_blocking_operation(VALUE obj)
+{
+ rb_fiber_scheduler_blocking_operation_t *blocking_operation;
+ TypedData_Get_Struct(obj, rb_fiber_scheduler_blocking_operation_t, &blocking_operation_data_type, blocking_operation);
+ return blocking_operation;
+}
+
+/*
+ * Document-method: Fiber::Scheduler::BlockingOperation#call
+ *
+ * Execute the blocking operation. This method releases the GVL and calls
+ * the blocking function, then restores the errno value.
+ *
+ * Returns nil. The actual result is stored in the associated state object.
+ */
+static VALUE
+blocking_operation_call(VALUE self)
+{
+ rb_fiber_scheduler_blocking_operation_t *blocking_operation = get_blocking_operation(self);
+
+ if (blocking_operation->status != RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED) {
+ rb_raise(rb_eRuntimeError, "Blocking operation has already been executed!");
+ }
+
+ if (blocking_operation->function == NULL) {
+ rb_raise(rb_eRuntimeError, "Blocking operation has no function to execute!");
+ }
+
+ if (blocking_operation->state == NULL) {
+ rb_raise(rb_eRuntimeError, "Blocking operation has no result object!");
+ }
+
+ // Mark as executing
+ blocking_operation->status = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING;
+
+ // Execute the blocking operation without GVL
+ blocking_operation->state->result = rb_nogvl(blocking_operation->function, blocking_operation->data,
+ blocking_operation->unblock_function, blocking_operation->data2,
+ blocking_operation->flags);
+ blocking_operation->state->saved_errno = rb_errno();
+
+ // Mark as completed
+ blocking_operation->status = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_COMPLETED;
+
+ return Qnil;
+}
+
/*
+ * C API: Extract blocking operation struct from Ruby object (GVL required)
+ *
+ * This function safely extracts the opaque struct from a BlockingOperation VALUE
+ * while holding the GVL. The returned pointer can be passed to worker threads
+ * and used with rb_fiber_scheduler_blocking_operation_execute_opaque_nogvl.
+ *
+ * Returns the opaque struct pointer on success, NULL on error.
+ * Must be called while holding the GVL.
+ */
+rb_fiber_scheduler_blocking_operation_t *
+rb_fiber_scheduler_blocking_operation_extract(VALUE self)
+{
+ return get_blocking_operation(self);
+}
+
+/*
+ * C API: Execute blocking operation from opaque struct (GVL not required)
+ *
+ * This function executes a blocking operation using the opaque struct pointer
+ * obtained from rb_fiber_scheduler_blocking_operation_extract.
+ * It can be called from native threads without holding the GVL.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operation_t *blocking_operation)
+{
+ if (blocking_operation == NULL) {
+ return -1;
+ }
+
+ if (blocking_operation->function == NULL || blocking_operation->state == NULL) {
+ return -1; // Invalid blocking operation
+ }
+
+ // Resolve sentinel values for unblock_function and data2:
+ rb_thread_resolve_unblock_function(&blocking_operation->unblock_function, &blocking_operation->data2, GET_THREAD());
+
+ // Atomically check if we can transition from QUEUED to EXECUTING
+ rb_atomic_t expected = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED;
+ if (RUBY_ATOMIC_CAS(blocking_operation->status, expected, RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING) != expected) {
+ // Already cancelled or in wrong state
+ return -1;
+ }
+
+ // Now we're executing - call the function
+ blocking_operation->state->result = blocking_operation->function(blocking_operation->data);
+ blocking_operation->state->saved_errno = errno;
+
+ // Atomically transition to completed (unless cancelled during execution)
+ expected = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING;
+ if (RUBY_ATOMIC_CAS(blocking_operation->status, expected, RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_COMPLETED) == expected) {
+ // Successfully completed
+ return 0;
+ } else {
+ // Was cancelled during execution
+ blocking_operation->state->saved_errno = EINTR;
+ return -1;
+ }
+}
+
+/*
+ * C API: Create a new blocking operation
+ *
+ * This creates a blocking operation that can be executed by native work pools.
+ * The blocking operation holds references to the function and data safely.
+ */
+VALUE
+rb_fiber_scheduler_blocking_operation_new(void *(*function)(void *), void *data,
+ rb_unblock_function_t *unblock_function, void *data2,
+ int flags, struct rb_fiber_scheduler_blocking_operation_state *state)
+{
+ VALUE self = blocking_operation_alloc(rb_cFiberSchedulerBlockingOperation);
+ rb_fiber_scheduler_blocking_operation_t *blocking_operation = get_blocking_operation(self);
+
+ blocking_operation->function = function;
+ blocking_operation->data = data;
+ blocking_operation->unblock_function = unblock_function;
+ blocking_operation->data2 = data2;
+ blocking_operation->flags = flags;
+ blocking_operation->state = state;
+
+ return self;
+}
+
+/*
+ *
* Document-class: Fiber::Scheduler
*
* This is not an existing class, but documentation of the interface that Scheduler
@@ -69,13 +280,15 @@ static ID id_fiber_schedule;
*
* Hook methods are:
*
- * * #io_wait, #io_read, #io_write, #io_pread, #io_pwrite, and #io_select, #io_close
+ * * #io_wait, #io_read, #io_write, #io_pread, #io_pwrite #io_select, and #io_close
* * #process_wait
* * #kernel_sleep
* * #timeout_after
* * #address_resolve
* * #block and #unblock
* * #blocking_operation_wait
+ * * #fiber_interrupt
+ * * #yield
* * (the list is expanded as Ruby developers make more methods having non-blocking calls)
*
* When not specified otherwise, the hook implementations are mandatory: if they are not
@@ -99,6 +312,7 @@ Init_Fiber_Scheduler(void)
id_block = rb_intern_const("block");
id_unblock = rb_intern_const("unblock");
+ id_yield = rb_intern_const("yield");
id_timeout_after = rb_intern_const("timeout_after");
id_kernel_sleep = rb_intern_const("kernel_sleep");
@@ -116,9 +330,19 @@ Init_Fiber_Scheduler(void)
id_address_resolve = rb_intern_const("address_resolve");
id_blocking_operation_wait = rb_intern_const("blocking_operation_wait");
+ id_fiber_interrupt = rb_intern_const("fiber_interrupt");
id_fiber_schedule = rb_intern_const("fiber");
+ // Define an anonymous BlockingOperation class for internal use only
+ // This is completely hidden from Ruby code and cannot be instantiated directly
+ rb_cFiberSchedulerBlockingOperation = rb_class_new(rb_cObject);
+ rb_define_alloc_func(rb_cFiberSchedulerBlockingOperation, blocking_operation_alloc);
+ rb_define_method(rb_cFiberSchedulerBlockingOperation, "call", blocking_operation_call, 0);
+
+ // Register the anonymous class as a GC root so it doesn't get collected
+ rb_gc_register_mark_object(rb_cFiberSchedulerBlockingOperation);
+
#if 0 /* for RDoc */
rb_cFiberScheduler = rb_define_class_under(rb_cFiber, "Scheduler", rb_cObject);
rb_define_method(rb_cFiberScheduler, "close", rb_fiber_scheduler_close, 0);
@@ -134,8 +358,11 @@ Init_Fiber_Scheduler(void)
rb_define_method(rb_cFiberScheduler, "timeout_after", rb_fiber_scheduler_timeout_after, 3);
rb_define_method(rb_cFiberScheduler, "block", rb_fiber_scheduler_block, 2);
rb_define_method(rb_cFiberScheduler, "unblock", rb_fiber_scheduler_unblock, 2);
- rb_define_method(rb_cFiberScheduler, "fiber", rb_fiber_scheduler, -2);
+ rb_define_method(rb_cFiberScheduler, "fiber", rb_fiber_scheduler_fiber, -2);
rb_define_method(rb_cFiberScheduler, "blocking_operation_wait", rb_fiber_scheduler_blocking_operation_wait, -2);
+ rb_define_method(rb_cFiberScheduler, "yield", rb_fiber_scheduler_yield, 0);
+ rb_define_method(rb_cFiberScheduler, "fiber_interrupt", rb_fiber_scheduler_fiber_interrupt, 2);
+ rb_define_method(rb_cFiberScheduler, "io_close", rb_fiber_scheduler_io_close, 1);
#endif
}
@@ -168,6 +395,10 @@ verify_interface(VALUE scheduler)
if (!rb_respond_to(scheduler, id_io_wait)) {
rb_raise(rb_eArgError, "Scheduler must implement #io_wait");
}
+
+ if (!rb_respond_to(scheduler, id_fiber_interrupt)) {
+ rb_warn("Scheduler should implement #fiber_interrupt");
+ }
}
static VALUE
@@ -212,7 +443,7 @@ rb_fiber_scheduler_set(VALUE scheduler)
}
static VALUE
-rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
+fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
{
RUBY_ASSERT(thread);
@@ -224,15 +455,22 @@ rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
}
}
-VALUE
-rb_fiber_scheduler_current(void)
+VALUE rb_fiber_scheduler_current(void)
{
- return rb_fiber_scheduler_current_for_threadptr(GET_THREAD());
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
+ return fiber_scheduler_current_for_threadptr(GET_THREAD());
}
+// This function is allowed to be called without holding the GVL.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
{
- return rb_fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread));
+ return fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread));
+}
+
+VALUE rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
+{
+ return fiber_scheduler_current_for_threadptr(thread);
}
/*
@@ -281,7 +519,7 @@ rb_fiber_scheduler_make_timeout(struct timeval *timeout)
* Document-method: Fiber::Scheduler#kernel_sleep
* call-seq: kernel_sleep(duration = nil)
*
- * Invoked by Kernel#sleep and Mutex#sleep and is expected to provide
+ * Invoked by Kernel#sleep and Thread::Mutex#sleep and is expected to provide
* an implementation of sleeping in a non-blocking way. Implementation might
* register the current fiber in some list of "which fiber wait until what
* moment", call Fiber.yield to pass control, and then in #close resume
@@ -300,6 +538,23 @@ rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv)
return rb_funcallv(scheduler, id_kernel_sleep, argc, argv);
}
+/**
+ * Document-method: Fiber::Scheduler#yield
+ * call-seq: yield
+ *
+ * Yield to the scheduler, to be resumed on the next scheduling cycle.
+ */
+VALUE
+rb_fiber_scheduler_yield(VALUE scheduler)
+{
+ // First try to call the scheduler's yield method, if it exists:
+ VALUE result = rb_check_funcall(scheduler, id_yield, 0, NULL);
+ if (!UNDEF_P(result)) return result;
+
+ // Otherwise, we can emulate yield by sleeping for 0 seconds:
+ return rb_fiber_scheduler_kernel_sleep(scheduler, RB_INT2NUM(0));
+}
+
#if 0
/*
* Document-method: Fiber::Scheduler#timeout_after
@@ -323,7 +578,7 @@ rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv)
* However, as a result of this design, if the +block+ does not invoke any
* non-blocking operations, it will be impossible to interrupt it. If you
* desire to provide predictable points for timeouts, consider adding
- * +sleep(0)+.
+ * <tt>sleep(0)</tt>.
*
* If the block is executed successfully, its result will be returned.
*
@@ -378,7 +633,7 @@ rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
* Document-method: Fiber::Scheduler#block
* call-seq: block(blocker, timeout = nil)
*
- * Invoked by methods like Thread.join, and by Mutex, to signify that current
+ * Invoked by methods like Thread.join, and by Thread::Mutex, to signify that current
* Fiber is blocked until further notice (e.g. #unblock) or until +timeout+ has
* elapsed.
*
@@ -398,8 +653,8 @@ rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
* Document-method: Fiber::Scheduler#unblock
* call-seq: unblock(blocker, fiber)
*
- * Invoked to wake up Fiber previously blocked with #block (for example, Mutex#lock
- * calls #block and Mutex#unlock calls #unblock). The scheduler should use
+ * Invoked to wake up Fiber previously blocked with #block (for example, Thread::Mutex#lock
+ * calls #block and Thread::Mutex#unlock calls #unblock). The scheduler should use
* the +fiber+ parameter to understand which fiber is unblocked.
*
* +blocker+ is what was awaited for, but it is informational only (for debugging
@@ -412,11 +667,36 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
{
RUBY_ASSERT(rb_obj_is_fiber(fiber));
+ VALUE result;
+ enum ruby_tag_type state;
+
// `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);
+ // We must prevent interrupts while invoking the unblock method, because otherwise fibers can be left permanently blocked if an interrupt occurs during the execution of user code. See also `rb_fiber_scheduler_fiber_interrupt`.
+ rb_execution_context_t *ec = GET_EC();
+ int saved_interrupt_mask = ec->interrupt_mask;
+ ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+
+ rb_control_frame_t *volatile cfp = ec->cfp;
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
+ }
+ else {
+ rb_vm_rewind_cfp(ec, cfp);
+ }
+ EC_POP_TAG();
+
+ ec->interrupt_mask = saved_interrupt_mask;
+
+ if (state) {
+ EC_JUMP_TAG(ec, state);
+ }
+
+ RUBY_VM_CHECK_INTS(ec);
errno = saved_errno;
@@ -442,10 +722,25 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
* Expected to return the subset of events that are ready immediately.
*
*/
+static VALUE
+fiber_scheduler_io_wait(VALUE _argument) {
+ VALUE *arguments = (VALUE*)_argument;
+
+ return rb_funcallv(arguments[0], id_io_wait, 3, arguments + 1);
+}
+
VALUE
rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
{
- return rb_funcall(scheduler, id_io_wait, 3, io, events, timeout);
+ VALUE arguments[] = {
+ scheduler, io, events, timeout
+ };
+
+ if (rb_respond_to(scheduler, id_fiber_interrupt)) {
+ return rb_thread_io_blocking_operation(io, fiber_scheduler_io_wait, (VALUE)&arguments);
+ } else {
+ return fiber_scheduler_io_wait((VALUE)&arguments);
+ }
}
VALUE
@@ -515,18 +810,33 @@ VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
*
* The method should be considered _experimental_.
*/
+static VALUE
+fiber_scheduler_io_read(VALUE _argument) {
+ VALUE *arguments = (VALUE*)_argument;
+
+ return rb_funcallv(arguments[0], id_io_read, 4, arguments + 1);
+}
+
VALUE
rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
{
+ if (!rb_respond_to(scheduler, id_io_read)) {
+ return RUBY_Qundef;
+ }
+
VALUE arguments[] = {
- io, buffer, SIZET2NUM(length), SIZET2NUM(offset)
+ scheduler, io, buffer, SIZET2NUM(length), SIZET2NUM(offset)
};
- return rb_check_funcall(scheduler, id_io_read, 4, arguments);
+ if (rb_respond_to(scheduler, id_fiber_interrupt)) {
+ return rb_thread_io_blocking_operation(io, fiber_scheduler_io_read, (VALUE)&arguments);
+ } else {
+ return fiber_scheduler_io_read((VALUE)&arguments);
+ }
}
/*
- * Document-method: Fiber::Scheduler#io_read
+ * Document-method: Fiber::Scheduler#io_pread
* 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+
@@ -539,18 +849,33 @@ rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t lengt
*
* The method should be considered _experimental_.
*/
+static VALUE
+fiber_scheduler_io_pread(VALUE _argument) {
+ VALUE *arguments = (VALUE*)_argument;
+
+ return rb_funcallv(arguments[0], id_io_pread, 5, arguments + 1);
+}
+
VALUE
rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
{
+ if (!rb_respond_to(scheduler, id_io_pread)) {
+ return RUBY_Qundef;
+ }
+
VALUE arguments[] = {
- io, buffer, OFFT2NUM(from), SIZET2NUM(length), SIZET2NUM(offset)
+ scheduler, io, buffer, OFFT2NUM(from), SIZET2NUM(length), SIZET2NUM(offset)
};
- return rb_check_funcall(scheduler, id_io_pread, 5, arguments);
+ if (rb_respond_to(scheduler, id_fiber_interrupt)) {
+ return rb_thread_io_blocking_operation(io, fiber_scheduler_io_pread, (VALUE)&arguments);
+ } else {
+ return fiber_scheduler_io_pread((VALUE)&arguments);
+ }
}
/*
- * Document-method: Scheduler#io_write
+ * Document-method: Fiber::Scheduler#io_write
* call-seq: io_write(io, buffer, length, offset) -> written length or -errno
*
* Invoked by IO#write or IO::Buffer#write to write +length+ bytes to +io+ from
@@ -577,14 +902,29 @@ rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buff
*
* The method should be considered _experimental_.
*/
+static VALUE
+fiber_scheduler_io_write(VALUE _argument) {
+ VALUE *arguments = (VALUE*)_argument;
+
+ return rb_funcallv(arguments[0], id_io_write, 4, arguments + 1);
+}
+
VALUE
rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
{
+ if (!rb_respond_to(scheduler, id_io_write)) {
+ return RUBY_Qundef;
+ }
+
VALUE arguments[] = {
- io, buffer, SIZET2NUM(length), SIZET2NUM(offset)
+ scheduler, io, buffer, SIZET2NUM(length), SIZET2NUM(offset)
};
- return rb_check_funcall(scheduler, id_io_write, 4, arguments);
+ if (rb_respond_to(scheduler, id_fiber_interrupt)) {
+ return rb_thread_io_blocking_operation(io, fiber_scheduler_io_write, (VALUE)&arguments);
+ } else {
+ return fiber_scheduler_io_write((VALUE)&arguments);
+ }
}
/*
@@ -602,14 +942,31 @@ rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t leng
* The method should be considered _experimental_.
*
*/
+static VALUE
+fiber_scheduler_io_pwrite(VALUE _argument) {
+ VALUE *arguments = (VALUE*)_argument;
+
+ return rb_funcallv(arguments[0], id_io_pwrite, 5, arguments + 1);
+}
+
VALUE
rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
{
+
+
+ if (!rb_respond_to(scheduler, id_io_pwrite)) {
+ return RUBY_Qundef;
+ }
+
VALUE arguments[] = {
- io, buffer, OFFT2NUM(from), SIZET2NUM(length), SIZET2NUM(offset)
+ scheduler, io, buffer, OFFT2NUM(from), SIZET2NUM(length), SIZET2NUM(offset)
};
- return rb_check_funcall(scheduler, id_io_pwrite, 5, arguments);
+ if (rb_respond_to(scheduler, id_fiber_interrupt)) {
+ return rb_thread_io_blocking_operation(io, fiber_scheduler_io_pwrite, (VALUE)&arguments);
+ } else {
+ return fiber_scheduler_io_pwrite((VALUE)&arguments);
+ }
}
VALUE
@@ -660,6 +1017,14 @@ rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, co
return result;
}
+/*
+ * Document-method: Fiber::Scheduler#io_close
+ * call-seq: io_close(fd)
+ *
+ * Invoked by Ruby's core methods to notify scheduler that the IO object is closed. Note that
+ * the method will receive an integer file descriptor of the closed object, not an object
+ * itself.
+ */
VALUE
rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
{
@@ -710,60 +1075,99 @@ rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname)
return rb_check_funcall(scheduler, id_address_resolve, 1, arguments);
}
-struct rb_blocking_operation_wait_arguments {
- void *(*function)(void *);
- void *data;
- rb_unblock_function_t *unblock_function;
- void *data2;
- int flags;
+/*
+ * Document-method: Fiber::Scheduler#blocking_operation_wait
+ * call-seq: blocking_operation_wait(blocking_operation)
+ *
+ * Invoked by Ruby's core methods to run a blocking operation in a non-blocking way.
+ * The blocking_operation is an opaque object that encapsulates the blocking operation
+ * and responds to a <tt>#call</tt> method without any arguments.
+ *
+ * If the scheduler doesn't implement this method, or if the scheduler doesn't execute
+ * the blocking operation, Ruby will fall back to the non-scheduler implementation.
+ *
+ * Minimal suggested implementation is:
+ *
+ * def blocking_operation_wait(blocking_operation)
+ * Thread.new { blocking_operation.call }.join
+ * end
+ */
+VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*function)(void *), void *data, rb_unblock_function_t *unblock_function, void *data2, int flags, struct rb_fiber_scheduler_blocking_operation_state *state)
+{
+ // Check if scheduler supports blocking_operation_wait before creating the object
+ if (!rb_respond_to(scheduler, id_blocking_operation_wait)) {
+ return Qundef;
+ }
- struct rb_fiber_scheduler_blocking_operation_state *state;
-};
+ // Create a new BlockingOperation with the blocking operation
+ VALUE blocking_operation = rb_fiber_scheduler_blocking_operation_new(function, data, unblock_function, data2, flags, state);
-static VALUE
-rb_fiber_scheduler_blocking_operation_wait_proc(RB_BLOCK_CALL_FUNC_ARGLIST(value, _arguments))
-{
- struct rb_blocking_operation_wait_arguments *arguments = (struct rb_blocking_operation_wait_arguments*)_arguments;
+ VALUE result = rb_funcall(scheduler, id_blocking_operation_wait, 1, blocking_operation);
- if (arguments->state == NULL) {
- rb_raise(rb_eRuntimeError, "Blocking function was already invoked!");
- }
+ // Get the operation data to check if it was executed
+ rb_fiber_scheduler_blocking_operation_t *operation = get_blocking_operation(blocking_operation);
+ rb_atomic_t current_status = RUBY_ATOMIC_LOAD(operation->status);
- arguments->state->result = rb_nogvl(arguments->function, arguments->data, arguments->unblock_function, arguments->data2, arguments->flags);
- arguments->state->saved_errno = rb_errno();
+ // Invalidate the operation now that we're done with it
+ operation->function = NULL;
+ operation->state = NULL;
+ operation->data = NULL;
+ operation->data2 = NULL;
+ operation->unblock_function = NULL;
- // Make sure it's only invoked once.
- arguments->state = NULL;
+ // Ensure that the blocking operation remains visible until this point:
+ RB_GC_GUARD(blocking_operation);
- return Qnil;
+ // If the blocking operation was never executed, return Qundef to signal the caller to use rb_nogvl instead
+ if (current_status == RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED) {
+ return Qundef;
+ }
+
+ return result;
}
/*
- * Document-method: Fiber::Scheduler#blocking_operation_wait
- * call-seq: blocking_operation_wait(work)
- *
- * Invoked by Ruby's core methods to run a blocking operation in a non-blocking way.
+ * Document-method: Fiber::Scheduler#fiber_interrupt
+ * call-seq: fiber_interrupt(fiber, exception)
*
- * Minimal suggested implementation is:
+ * Invoked by Ruby's core methods to notify the scheduler that the blocked fiber should be interrupted
+ * with an exception. For example, IO#close uses this method to interrupt fibers that are performing
+ * blocking IO operations.
*
- * def blocking_operation_wait(work)
- * Thread.new(&work).join
- * end
*/
-VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*function)(void *), void *data, rb_unblock_function_t *unblock_function, void *data2, int flags, struct rb_fiber_scheduler_blocking_operation_state *state)
+VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exception)
{
- struct rb_blocking_operation_wait_arguments arguments = {
- .function = function,
- .data = data,
- .unblock_function = unblock_function,
- .data2 = data2,
- .flags = flags,
- .state = state
+ VALUE arguments[] = {
+ fiber, exception
};
- VALUE proc = rb_proc_new(rb_fiber_scheduler_blocking_operation_wait_proc, (VALUE)&arguments);
+ VALUE result;
+ enum ruby_tag_type state;
+
+ // We must prevent interrupts while invoking the fiber_interrupt method, because otherwise fibers can be left permanently blocked if an interrupt occurs during the execution of user code. See also `rb_fiber_scheduler_unblock`.
+ rb_execution_context_t *ec = GET_EC();
+ int saved_interrupt_mask = ec->interrupt_mask;
+ ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+
+ rb_control_frame_t *volatile cfp = ec->cfp;
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ result = rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
+ }
+ else {
+ rb_vm_rewind_cfp(ec, cfp);
+ }
+ EC_POP_TAG();
+
+ ec->interrupt_mask = saved_interrupt_mask;
+
+ if (state) {
+ EC_JUMP_TAG(ec, state);
+ }
+
+ RUBY_VM_CHECK_INTS(ec);
- return rb_check_funcall(scheduler, id_blocking_operation_wait, 1, &proc);
+ return result;
}
/*
@@ -786,3 +1190,54 @@ rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat)
{
return rb_funcall_passing_block_kw(scheduler, id_fiber_schedule, argc, argv, kw_splat);
}
+
+/*
+ * C API: Cancel a blocking operation
+ *
+ * This function cancels a blocking operation. If the operation is queued,
+ * it just marks it as cancelled. If it's executing, it marks it as cancelled
+ * and calls the unblock function to interrupt the operation.
+ *
+ * Returns 1 if unblock function was called, 0 if just marked cancelled, -1 on error.
+ */
+int
+rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operation_t *blocking_operation)
+{
+ if (blocking_operation == NULL) {
+ return -1;
+ }
+
+ rb_atomic_t current_state = RUBY_ATOMIC_LOAD(blocking_operation->status);
+
+ switch (current_state) {
+ case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED:
+ // Work hasn't started - just mark as cancelled:
+ if (RUBY_ATOMIC_CAS(blocking_operation->status, current_state, RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED) == current_state) {
+ // Successfully cancelled before execution:
+ return 0;
+ }
+ // Fall through if state changed between load and CAS
+
+ case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING:
+ // Work is running - mark cancelled AND call unblock function
+ if (RUBY_ATOMIC_CAS(blocking_operation->status, current_state, RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED) != current_state) {
+ // State changed between load and CAS - operation may have completed:
+ return 0;
+ }
+ // Otherwise, we successfully marked it as cancelled, so we can call the unblock function:
+ rb_unblock_function_t *unblock_function = blocking_operation->unblock_function;
+ if (unblock_function) {
+ RUBY_ASSERT(unblock_function != (rb_unblock_function_t *)-1 && "unblock_function is still sentinel value -1, should have been resolved earlier");
+ blocking_operation->unblock_function(blocking_operation->data2);
+ }
+ // Cancelled during execution (unblock function called):
+ return 1;
+
+ case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_COMPLETED:
+ case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED:
+ // Already finished or cancelled:
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/set.c b/set.c
new file mode 100644
index 0000000000..8d6f33329b
--- /dev/null
+++ b/set.c
@@ -0,0 +1,2311 @@
+/* This implements sets using the same hash table implementation as in
+ st.c, but without a value for each hash entry. This results in the
+ same basic performance characteristics as when using an st table,
+ but uses 1/3 less memory.
+ */
+
+#include "id.h"
+#include "internal.h"
+#include "internal/bits.h"
+#include "internal/error.h"
+#include "internal/hash.h"
+#include "internal/proc.h"
+#include "internal/sanitizers.h"
+#include "internal/set_table.h"
+#include "internal/symbol.h"
+#include "internal/variable.h"
+#include "ruby_assert.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+#ifndef SET_DEBUG
+#define SET_DEBUG 0
+#endif
+
+#if SET_DEBUG
+#include "internal/gc.h"
+#endif
+
+static st_index_t
+dbl_to_index(double d)
+{
+ union {double d; st_index_t i;} u;
+ u.d = d;
+ return u.i;
+}
+
+static const uint64_t prime1 = ((uint64_t)0x2e0bb864 << 32) | 0xe9ea7df5;
+static const uint32_t prime2 = 0x830fcab9;
+
+static inline uint64_t
+mult_and_mix(uint64_t m1, uint64_t m2)
+{
+#if defined HAVE_UINT128_T
+ uint128_t r = (uint128_t) m1 * (uint128_t) m2;
+ return (uint64_t) (r >> 64) ^ (uint64_t) r;
+#else
+ uint64_t hm1 = m1 >> 32, hm2 = m2 >> 32;
+ uint64_t lm1 = m1, lm2 = m2;
+ uint64_t v64_128 = hm1 * hm2;
+ uint64_t v32_96 = hm1 * lm2 + lm1 * hm2;
+ uint64_t v1_32 = lm1 * lm2;
+
+ return (v64_128 + (v32_96 >> 32)) ^ ((v32_96 << 32) + v1_32);
+#endif
+}
+
+static inline uint64_t
+key64_hash(uint64_t key, uint32_t seed)
+{
+ return mult_and_mix(key + seed, prime1);
+}
+
+/* Should cast down the result for each purpose */
+#define set_index_hash(index) key64_hash(rb_hash_start(index), prime2)
+
+static st_index_t
+set_ident_hash(st_data_t n)
+{
+#ifdef USE_FLONUM /* RUBY */
+ /*
+ * - flonum (on 64-bit) is pathologically bad, mix the actual
+ * float value in, but do not use the float value as-is since
+ * many integers get interpreted as 2.0 or -2.0 [Bug #10761]
+ */
+ if (FLONUM_P(n)) {
+ n ^= dbl_to_index(rb_float_value(n));
+ }
+#endif
+
+ return (st_index_t)set_index_hash((st_index_t)n);
+}
+
+static const struct st_hash_type identhash = {
+ rb_st_numcmp,
+ set_ident_hash,
+};
+
+static const struct st_hash_type objhash = {
+ rb_any_cmp,
+ rb_any_hash,
+};
+
+VALUE rb_cSet;
+
+#define id_each idEach
+static ID id_each_entry;
+static ID id_any_p;
+static ID id_new;
+static ID id_i_hash;
+static ID id_set_iter_lev;
+static ID id_subclass_compatible;
+static ID id_class_methods;
+
+#define RSET_INITIALIZED FL_USER1
+#define RSET_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
+ FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19)
+#define RSET_LEV_SHIFT (FL_USHIFT + 13)
+#define RSET_LEV_MAX 127 /* 7 bits */
+
+#define SET_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(SET_DEBUG, expr, #expr)
+
+#define RSET_SIZE(set) set_table_size(RSET_TABLE(set))
+#define RSET_EMPTY(set) (RSET_SIZE(set) == 0)
+#define RSET_SIZE_NUM(set) SIZET2NUM(RSET_SIZE(set))
+#define RSET_IS_MEMBER(set, item) set_table_lookup(RSET_TABLE(set), (st_data_t)(item))
+#define RSET_COMPARE_BY_IDENTITY(set) (RSET_TABLE(set)->type == &identhash)
+
+struct set_object {
+ set_table table;
+};
+
+static int
+mark_and_pin_key(st_data_t key, st_data_t data)
+{
+ rb_gc_mark((VALUE)key);
+
+ return ST_CONTINUE;
+}
+
+static int
+mark_key(st_data_t key, st_data_t data)
+{
+ rb_gc_mark_movable((VALUE)key);
+
+ return ST_CONTINUE;
+}
+
+static void
+set_mark(void *ptr)
+{
+ struct set_object *sobj = ptr;
+ if (sobj->table.entries) {
+ if (sobj->table.type == &identhash) {
+ set_table_foreach(&sobj->table, mark_and_pin_key, 0);
+ }
+ else {
+ set_table_foreach(&sobj->table, mark_key, 0);
+ }
+ }
+}
+
+static void
+set_free(void *ptr)
+{
+ struct set_object *sobj = ptr;
+ set_free_embedded_table(&sobj->table);
+}
+
+static size_t
+set_size(const void *ptr)
+{
+ const struct set_object *sobj = ptr;
+ /* Do not count the table size twice, as it is embedded */
+ return (unsigned long)set_memsize(&sobj->table) - sizeof(sobj->table);
+}
+
+static int
+set_foreach_replace(st_data_t key, st_data_t argp, int error)
+{
+ if (rb_gc_location((VALUE)key) != (VALUE)key) {
+ return ST_REPLACE;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+set_replace_ref(st_data_t *key, st_data_t argp, int existing)
+{
+ rb_gc_mark_and_move((VALUE *)key);
+
+ return ST_CONTINUE;
+}
+
+static void
+set_update_references(void *ptr)
+{
+ struct set_object *sobj = ptr;
+ set_foreach_with_replace(&sobj->table, set_foreach_replace, set_replace_ref, 0);
+}
+
+static const rb_data_type_t set_data_type = {
+ .wrap_struct_name = "set",
+ .function = {
+ .dmark = set_mark,
+ .dfree = set_free,
+ .dsize = set_size,
+ .dcompact = set_update_references,
+ },
+ .flags = RUBY_TYPED_EMBEDDABLE | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE
+};
+
+static inline set_table *
+RSET_TABLE(VALUE set)
+{
+ struct set_object *sobj;
+ TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
+ return &sobj->table;
+}
+
+static unsigned long
+iter_lev_in_ivar(VALUE set)
+{
+ VALUE levval = rb_ivar_get(set, id_set_iter_lev);
+ SET_ASSERT(FIXNUM_P(levval));
+ long lev = FIX2LONG(levval);
+ SET_ASSERT(lev >= 0);
+ return (unsigned long)lev;
+}
+
+void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
+
+static void
+iter_lev_in_ivar_set(VALUE set, unsigned long lev)
+{
+ SET_ASSERT(lev >= RSET_LEV_MAX);
+ SET_ASSERT(POSFIXABLE(lev)); /* POSFIXABLE means fitting to long */
+ rb_ivar_set_internal(set, id_set_iter_lev, LONG2FIX((long)lev));
+}
+
+static inline unsigned long
+iter_lev_in_flags(VALUE set)
+{
+ return (unsigned long)((RBASIC(set)->flags >> RSET_LEV_SHIFT) & RSET_LEV_MAX);
+}
+
+static inline void
+iter_lev_in_flags_set(VALUE set, unsigned long lev)
+{
+ SET_ASSERT(lev <= RSET_LEV_MAX);
+ RBASIC(set)->flags = ((RBASIC(set)->flags & ~RSET_LEV_MASK) | ((VALUE)lev << RSET_LEV_SHIFT));
+}
+
+static inline bool
+set_iterating_p(VALUE set)
+{
+ return iter_lev_in_flags(set) > 0;
+}
+
+static void
+set_iter_lev_inc(VALUE set)
+{
+ unsigned long lev = iter_lev_in_flags(set);
+ if (lev == RSET_LEV_MAX) {
+ lev = iter_lev_in_ivar(set) + 1;
+ if (!POSFIXABLE(lev)) { /* paranoiac check */
+ rb_raise(rb_eRuntimeError, "too much nested iterations");
+ }
+ }
+ else {
+ lev += 1;
+ iter_lev_in_flags_set(set, lev);
+ if (lev < RSET_LEV_MAX) return;
+ }
+ iter_lev_in_ivar_set(set, lev);
+}
+
+static void
+set_iter_lev_dec(VALUE set)
+{
+ unsigned long lev = iter_lev_in_flags(set);
+ if (lev == RSET_LEV_MAX) {
+ lev = iter_lev_in_ivar(set);
+ if (lev > RSET_LEV_MAX) {
+ iter_lev_in_ivar_set(set, lev-1);
+ return;
+ }
+ rb_attr_delete(set, id_set_iter_lev);
+ }
+ else if (lev == 0) {
+ rb_raise(rb_eRuntimeError, "iteration level underflow");
+ }
+ iter_lev_in_flags_set(set, lev - 1);
+}
+
+static VALUE
+set_foreach_ensure(VALUE set)
+{
+ set_iter_lev_dec(set);
+ return 0;
+}
+
+typedef int set_foreach_func(VALUE, VALUE);
+
+struct set_foreach_arg {
+ VALUE set;
+ set_foreach_func *func;
+ VALUE arg;
+};
+
+static int
+set_iter_status_check(int status)
+{
+ if (status == ST_CONTINUE) {
+ return ST_CHECK;
+ }
+
+ return status;
+}
+
+static int
+set_foreach_iter(st_data_t key, st_data_t argp, int error)
+{
+ struct set_foreach_arg *arg = (struct set_foreach_arg *)argp;
+
+ if (error) return ST_STOP;
+
+ set_table *tbl = RSET_TABLE(arg->set);
+ int status = (*arg->func)((VALUE)key, arg->arg);
+
+ if (RSET_TABLE(arg->set) != tbl) {
+ rb_raise(rb_eRuntimeError, "reset occurred during iteration");
+ }
+
+ return set_iter_status_check(status);
+}
+
+static VALUE
+set_foreach_call(VALUE arg)
+{
+ VALUE set = ((struct set_foreach_arg *)arg)->set;
+ int ret = 0;
+ ret = set_foreach_check(RSET_TABLE(set), set_foreach_iter,
+ (st_data_t)arg, (st_data_t)Qundef);
+ if (ret) {
+ rb_raise(rb_eRuntimeError, "ret: %d, set modified during iteration", ret);
+ }
+ return Qnil;
+}
+
+static void
+set_iter(VALUE set, set_foreach_func *func, VALUE farg)
+{
+ struct set_foreach_arg arg;
+
+ if (RSET_EMPTY(set))
+ return;
+ arg.set = set;
+ arg.func = func;
+ arg.arg = farg;
+ if (RB_OBJ_FROZEN(set)) {
+ set_foreach_call((VALUE)&arg);
+ }
+ else {
+ set_iter_lev_inc(set);
+ rb_ensure(set_foreach_call, (VALUE)&arg, set_foreach_ensure, set);
+ }
+}
+
+NORETURN(static void no_new_item(void));
+static void
+no_new_item(void)
+{
+ rb_raise(rb_eRuntimeError, "can't add a new item into set during iteration");
+}
+
+static void
+set_compact_after_delete(VALUE set)
+{
+ if (!set_iterating_p(set)) {
+ set_compact_table(RSET_TABLE(set));
+ }
+}
+
+static int
+set_table_insert_wb(set_table *tab, VALUE set, VALUE key)
+{
+ if (tab->type != &identhash && rb_obj_class(key) == rb_cString && !RB_OBJ_FROZEN(key)) {
+ key = rb_hash_key_str(key);
+ }
+ int ret = set_insert(tab, (st_data_t)key);
+ if (ret == 0) RB_OBJ_WRITTEN(set, Qundef, key);
+ return ret;
+}
+
+static int
+set_insert_wb(VALUE set, VALUE key)
+{
+ return set_table_insert_wb(RSET_TABLE(set), set, key);
+}
+
+static VALUE
+set_alloc_with_size(VALUE klass, st_index_t size)
+{
+ VALUE set;
+ struct set_object *sobj;
+
+ set = TypedData_Make_Struct(klass, struct set_object, &set_data_type, sobj);
+ set_init_table_with_size(&sobj->table, &objhash, size);
+
+ return set;
+}
+
+
+static VALUE
+set_s_alloc(VALUE klass)
+{
+ return set_alloc_with_size(klass, 0);
+}
+
+/*
+ * call-seq:
+ * Set[*objects] -> new_set
+ *
+ * Returns a new Set object populated with the given objects,
+ * See Set::new.
+ */
+static VALUE
+set_s_create(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE set = set_alloc_with_size(klass, argc);
+ set_table *table = RSET_TABLE(set);
+ int i;
+
+ for (i=0; i < argc; i++) {
+ set_table_insert_wb(table, set, argv[i]);
+ }
+
+ return set;
+}
+
+static VALUE
+set_s_inherited(VALUE klass, VALUE subclass)
+{
+ if (klass == rb_cSet) {
+ // When subclassing directly from Set, include the compatibility layer
+ rb_require("set/subclass_compatible.rb");
+ VALUE subclass_compatible = rb_const_get(klass, id_subclass_compatible);
+ rb_include_module(subclass, subclass_compatible);
+ rb_extend_object(subclass, rb_const_get(subclass_compatible, id_class_methods));
+ }
+ return Qnil;
+}
+
+static void
+check_set(VALUE arg)
+{
+ if (!rb_obj_is_kind_of(arg, rb_cSet)) {
+ rb_raise(rb_eArgError, "value must be a set");
+ }
+}
+
+static ID
+enum_method_id(VALUE other)
+{
+ if (rb_respond_to(other, id_each_entry)) {
+ return id_each_entry;
+ }
+ else if (rb_respond_to(other, id_each)) {
+ return id_each;
+ }
+ else {
+ rb_raise(rb_eArgError, "value must be enumerable");
+ }
+}
+
+static VALUE
+set_enum_size(VALUE set, VALUE args, VALUE eobj)
+{
+ return RSET_SIZE_NUM(set);
+}
+
+static VALUE
+set_initialize_without_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set))
+{
+ VALUE element = i;
+ set_insert_wb(set, element);
+ return element;
+}
+
+static VALUE
+set_initialize_with_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set))
+{
+ VALUE element = rb_yield(i);
+ set_insert_wb(set, element);
+ return element;
+}
+
+/*
+ * call-seq:
+ * Set.new(object = nil) -> new_set
+ * Set.new(object = nil) {|element| ... } -> new_set
+ *
+ * Returns a new \Set object based on the given +object+,
+ * which must be an Enumerable or +nil+.
+ *
+ * With argument +object+ given as +nil+,
+ * returns a new empty \Set object:
+ *
+ * Set.new # => Set[]
+ * Set.new { fail 'Cannot happen' } # => Set[] # Block not called.
+ *
+ * With no block given and +object+ given as an Enumerable,
+ * populates the new set with the elements of +object+:
+ *
+ * Set.new(%w[ a b c ]) # => Set["a", "b", "c"]
+ * Set.new({foo: 0, bar: 1}) # => Set[[:foo, 0], [:bar, 1]]
+ * Set.new(4..10) # => Set[4, 5, 6, 7, 8, 9, 10]
+ * Set.new(Dir.new('lib')).take(5)
+ * # => [".", "..", "bundled_gems.rb", "bundler", "bundler.rb"]
+ * Set.new(File.new('doc/NEWS/NEWS-4.0.0.md')).take(3)
+ * # => ["# NEWS for Ruby 4.0.0\n", "\n", "This document is a list of user-visible feature changes\n"]
+ *
+ * With a block given and +object+ given as an Enumerable,
+ * calls the block with each element of +object+;
+ * adds the block's return value to the new set:
+ *
+ * Set.new(4..10) {|i| i * 2 } # => Set[8, 10, 12, 14, 16, 18, 20]
+ *
+ */
+static VALUE
+set_i_initialize(int argc, VALUE *argv, VALUE set)
+{
+ if (RBASIC(set)->flags & RSET_INITIALIZED) {
+ rb_raise(rb_eRuntimeError, "cannot reinitialize set");
+ }
+ RBASIC(set)->flags |= RSET_INITIALIZED;
+
+ VALUE other;
+ rb_check_arity(argc, 0, 1);
+
+ if (argc > 0 && (other = argv[0]) != Qnil) {
+ if (RB_TYPE_P(other, T_ARRAY)) {
+ long i;
+ int block_given = rb_block_given_p();
+ set_table *into = RSET_TABLE(set);
+ for (i=0; i<RARRAY_LEN(other); i++) {
+ VALUE key = RARRAY_AREF(other, i);
+ if (block_given) key = rb_yield(key);
+ set_table_insert_wb(into, set, key);
+ }
+ }
+ else {
+ rb_block_call(other, enum_method_id(other), 0, 0,
+ rb_block_given_p() ? set_initialize_with_block : set_initialize_without_block,
+ set);
+ }
+ }
+
+ return set;
+}
+
+/* :nodoc: */
+static VALUE
+set_i_initialize_copy(VALUE set, VALUE other)
+{
+ if (set == other) return set;
+
+ if (set_iterating_p(set)) {
+ rb_raise(rb_eRuntimeError, "cannot replace set during iteration");
+ }
+
+ struct set_object *sobj;
+ TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
+
+ set_free_embedded_table(&sobj->table);
+ set_copy(&sobj->table, RSET_TABLE(other));
+ rb_gc_writebarrier_remember(set);
+
+ return set;
+}
+
+static int
+set_inspect_i(st_data_t key, st_data_t arg)
+{
+ VALUE *args = (VALUE*)arg;
+ VALUE str = args[0];
+ if (args[1] == Qtrue) {
+ rb_str_buf_cat_ascii(str, ", ");
+ }
+ else {
+ args[1] = Qtrue;
+ }
+ rb_str_buf_append(str, rb_inspect((VALUE)key));
+
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_inspect(VALUE set, VALUE dummy, int recur)
+{
+ VALUE str;
+ VALUE klass_name = rb_class_path(CLASS_OF(set));
+
+ if (recur) {
+ str = rb_sprintf("%"PRIsVALUE"[...]", klass_name);
+ return rb_str_export_to_enc(str, rb_usascii_encoding());
+ }
+
+ str = rb_sprintf("%"PRIsVALUE"[", klass_name);
+ VALUE args[2] = {str, Qfalse};
+ set_iter(set, set_inspect_i, (st_data_t)args);
+ rb_str_buf_cat2(str, "]");
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * inspect -> new_string
+ *
+ * Returns a new string containing the set entries:
+ *
+ * s = Set.new
+ * s.inspect # => "Set[]"
+ * s.add(1)
+ * s.inspect # => "Set[1]"
+ * s.add(2)
+ * s.inspect # => "Set[1, 2]"
+ *
+ * Related: see {Methods for Converting}[rdoc-ref:Set@Methods+for+Converting].
+ */
+static VALUE
+set_i_inspect(VALUE set)
+{
+ return rb_exec_recursive(set_inspect, set, 0);
+}
+
+static int
+set_to_a_i(st_data_t key, st_data_t arg)
+{
+ rb_ary_push((VALUE)arg, (VALUE)key);
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * to_a -> array
+ *
+ * Returns an array containing all elements in the set.
+ *
+ * Set[1, 2].to_a #=> [1, 2]
+ * Set[1, 'c', :s].to_a #=> [1, "c", :s]
+ */
+static VALUE
+set_i_to_a(VALUE set)
+{
+ st_index_t size = RSET_SIZE(set);
+ VALUE ary = rb_ary_new_capa(size);
+
+ if (size == 0) return ary;
+
+ if (ST_DATA_COMPATIBLE_P(VALUE)) {
+ RARRAY_PTR_USE(ary, ptr, {
+ size = set_keys(RSET_TABLE(set), ptr, size);
+ });
+ rb_gc_writebarrier_remember(ary);
+ rb_ary_set_len(ary, size);
+ }
+ else {
+ set_iter(set, set_to_a_i, (st_data_t)ary);
+ }
+ return ary;
+}
+
+/*
+ * call-seq:
+ * to_set(&block) -> self or new_set
+ *
+ * Without a block, if +self+ is an instance of +Set+, returns +self+.
+ * Otherwise, calls <tt>Set.new(self, &block)</tt>.
+ */
+static VALUE
+set_i_to_set(VALUE set)
+{
+ if (rb_obj_is_instance_of(set, rb_cSet) && !rb_block_given_p()) {
+ return set;
+ }
+
+ return rb_funcall_passing_block(rb_cSet, id_new, 1, &set);
+}
+
+/*
+ * call-seq:
+ * join(separator=nil)-> new_string
+ *
+ * Returns a string created by converting each element of the set to a string.
+ */
+static VALUE
+set_i_join(int argc, VALUE *argv, VALUE set)
+{
+ rb_check_arity(argc, 0, 1);
+ return rb_ary_join(set_i_to_a(set), argc == 0 ? Qnil : argv[0]);
+}
+
+/*
+ * call-seq:
+ * add(obj) -> self
+ *
+ * Adds the given object to the set and returns self. Use Set#merge to
+ * add many elements at once.
+ *
+ * Set[1, 2].add(3) #=> Set[1, 2, 3]
+ * Set[1, 2].add([3, 4]) #=> Set[1, 2, [3, 4]]
+ * Set[1, 2].add(2) #=> Set[1, 2]
+ */
+static VALUE
+set_i_add(VALUE set, VALUE item)
+{
+ rb_check_frozen(set);
+ if (set_iterating_p(set)) {
+ if (!set_table_lookup(RSET_TABLE(set), (st_data_t)item)) {
+ no_new_item();
+ }
+ }
+ else {
+ set_insert_wb(set, item);
+ }
+ return set;
+}
+
+/*
+ * call-seq:
+ * add?(obj) -> self or nil
+ *
+ * Adds the given object to the set and returns self. If the object is
+ * already in the set, returns nil.
+ *
+ * Set[1, 2].add?(3) #=> Set[1, 2, 3]
+ * Set[1, 2].add?([3, 4]) #=> Set[1, 2, [3, 4]]
+ * Set[1, 2].add?(2) #=> nil
+ */
+static VALUE
+set_i_add_p(VALUE set, VALUE item)
+{
+ rb_check_frozen(set);
+ if (set_iterating_p(set)) {
+ if (!set_table_lookup(RSET_TABLE(set), (st_data_t)item)) {
+ no_new_item();
+ }
+ return Qnil;
+ }
+ else {
+ return set_insert_wb(set, item) ? Qnil : set;
+ }
+}
+
+/*
+ * call-seq:
+ * delete(obj) -> self
+ *
+ * Deletes the given object from the set and returns self. Use subtract
+ * to delete many items at once.
+ */
+static VALUE
+set_i_delete(VALUE set, VALUE item)
+{
+ rb_check_frozen(set);
+ if (set_table_delete(RSET_TABLE(set), (st_data_t *)&item)) {
+ set_compact_after_delete(set);
+ }
+ return set;
+}
+
+/*
+ * call-seq:
+ * delete?(obj) -> self or nil
+ *
+ * Deletes the given object from the set and returns self. If the
+ * object is not in the set, returns nil.
+ */
+static VALUE
+set_i_delete_p(VALUE set, VALUE item)
+{
+ rb_check_frozen(set);
+ if (set_table_delete(RSET_TABLE(set), (st_data_t *)&item)) {
+ set_compact_after_delete(set);
+ return set;
+ }
+ return Qnil;
+}
+
+static int
+set_delete_if_i(st_data_t key, st_data_t dummy)
+{
+ return RTEST(rb_yield((VALUE)key)) ? ST_DELETE : ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * delete_if { |o| ... } -> self
+ * delete_if -> enumerator
+ *
+ * Deletes every element of the set for which block evaluates to
+ * true, and returns self. Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_delete_if(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ rb_check_frozen(set);
+ set_iter(set, set_delete_if_i, 0);
+ set_compact_after_delete(set);
+ return set;
+}
+
+/*
+ * call-seq:
+ * reject! { |o| ... } -> self
+ * reject! -> enumerator
+ *
+ * Equivalent to Set#delete_if, but returns nil if no changes were made.
+ * Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_reject(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ rb_check_frozen(set);
+
+ set_table *table = RSET_TABLE(set);
+ size_t n = set_table_size(table);
+ set_iter(set, set_delete_if_i, 0);
+
+ if (n == set_table_size(table)) return Qnil;
+
+ set_compact_after_delete(set);
+ return set;
+}
+
+static int
+set_classify_i(st_data_t key, st_data_t tmp)
+{
+ VALUE* args = (VALUE*)tmp;
+ VALUE hash = args[0];
+ VALUE hash_key = rb_yield(key);
+ VALUE set = rb_hash_lookup2(hash, hash_key, Qundef);
+ if (set == Qundef) {
+ set = set_s_alloc(args[1]);
+ rb_hash_aset(hash, hash_key, set);
+ }
+ set_i_add(set, key);
+
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * classify { |o| ... } -> hash
+ * classify -> enumerator
+ *
+ * Classifies the set by the return value of the given block and
+ * returns a hash of {value => set of elements} pairs. The block is
+ * called once for each element of the set, passing the element as
+ * parameter.
+ *
+ * files = Set.new(Dir.glob("*.rb"))
+ * hash = files.classify { |f| File.mtime(f).year }
+ * hash #=> {2000 => Set["a.rb", "b.rb"],
+ * # 2001 => Set["c.rb", "d.rb", "e.rb"],
+ * # 2002 => Set["f.rb"]}
+ *
+ * Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_classify(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ VALUE args[2];
+ args[0] = rb_hash_new();
+ args[1] = rb_obj_class(set);
+ set_iter(set, set_classify_i, (st_data_t)args);
+ return args[0];
+}
+
+// Union-find with path compression
+static long
+set_divide_union_find_root(long *uf_parents, long index, long *tmp_array)
+{
+ long root = uf_parents[index];
+ long update_size = 0;
+ while (root != index) {
+ tmp_array[update_size++] = index;
+ index = root;
+ root = uf_parents[index];
+ }
+ for (long j = 0; j < update_size; j++) {
+ long idx = tmp_array[j];
+ uf_parents[idx] = root;
+ }
+ return root;
+}
+
+static void
+set_divide_union_find_merge(long *uf_parents, long i, long j, long *tmp_array)
+{
+ long root_i = set_divide_union_find_root(uf_parents, i, tmp_array);
+ long root_j = set_divide_union_find_root(uf_parents, j, tmp_array);
+ if (root_i != root_j) uf_parents[root_j] = root_i;
+}
+
+static VALUE
+set_divide_arity2(VALUE set)
+{
+ VALUE tmp, uf;
+ long size, *uf_parents, *tmp_array;
+ VALUE set_class = rb_obj_class(set);
+ VALUE items = set_i_to_a(set);
+ rb_ary_freeze(items);
+ size = RARRAY_LEN(items);
+ tmp_array = ALLOCV_N(long, tmp, size);
+ uf_parents = ALLOCV_N(long, uf, size);
+ for (long i = 0; i < size; i++) {
+ uf_parents[i] = i;
+ }
+ for (long i = 0; i < size - 1; i++) {
+ VALUE item1 = RARRAY_AREF(items, i);
+ for (long j = i + 1; j < size; j++) {
+ VALUE item2 = RARRAY_AREF(items, j);
+ if (RTEST(rb_yield_values(2, item1, item2)) &&
+ RTEST(rb_yield_values(2, item2, item1))) {
+ set_divide_union_find_merge(uf_parents, i, j, tmp_array);
+ }
+ }
+ }
+ VALUE final_set = set_s_create(0, 0, rb_cSet);
+ VALUE hash = rb_hash_new();
+ for (long i = 0; i < size; i++) {
+ VALUE v = RARRAY_AREF(items, i);
+ long root = set_divide_union_find_root(uf_parents, i, tmp_array);
+ VALUE set = rb_hash_aref(hash, LONG2FIX(root));
+ if (set == Qnil) {
+ set = set_s_create(0, 0, set_class);
+ rb_hash_aset(hash, LONG2FIX(root), set);
+ set_i_add(final_set, set);
+ }
+ set_i_add(set, v);
+ }
+ ALLOCV_END(tmp);
+ ALLOCV_END(uf);
+ return final_set;
+}
+
+static void set_merge_enum_into(VALUE set, VALUE arg);
+
+/*
+ * call-seq:
+ * divide { |o1, o2| ... } -> set
+ * divide { |o| ... } -> set
+ * divide -> enumerator
+ *
+ * Divides the set into a set of subsets according to the commonality
+ * defined by the given block.
+ *
+ * If the arity of the block is 2, elements o1 and o2 are in common
+ * if both block.call(o1, o2) and block.call(o2, o1) are true.
+ * Otherwise, elements o1 and o2 are in common if
+ * block.call(o1) == block.call(o2).
+ *
+ * numbers = Set[1, 3, 4, 6, 9, 10, 11]
+ * set = numbers.divide { |i,j| (i - j).abs == 1 }
+ * set #=> Set[Set[1],
+ * # Set[3, 4],
+ * # Set[6],
+ * # Set[9, 10, 11]]
+ *
+ * Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_divide(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+
+ if (rb_block_arity() == 2) {
+ return set_divide_arity2(set);
+ }
+
+ VALUE values = rb_hash_values(set_i_classify(set));
+ set = set_alloc_with_size(rb_cSet, RARRAY_LEN(values));
+ set_merge_enum_into(set, values);
+ return set;
+}
+
+static int
+set_clear_i(st_data_t key, st_data_t dummy)
+{
+ return ST_DELETE;
+}
+
+/*
+ * call-seq:
+ * clear -> self
+ *
+ * Removes all elements and returns self.
+ *
+ * set = Set[1, 'c', :s] #=> Set[1, "c", :s]
+ * set.clear #=> Set[]
+ * set #=> Set[]
+ */
+static VALUE
+set_i_clear(VALUE set)
+{
+ rb_check_frozen(set);
+ if (RSET_SIZE(set) == 0) return set;
+ if (set_iterating_p(set)) {
+ set_iter(set, set_clear_i, 0);
+ }
+ else {
+ set_table_clear(RSET_TABLE(set));
+ set_compact_after_delete(set);
+ }
+ return set;
+}
+
+struct set_intersection_data {
+ VALUE set;
+ set_table *into;
+ set_table *other;
+};
+
+static int
+set_intersection_i(st_data_t key, st_data_t tmp)
+{
+ struct set_intersection_data *data = (struct set_intersection_data *)tmp;
+ if (set_table_lookup(data->other, key)) {
+ set_table_insert_wb(data->into, data->set, key);
+ }
+
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_intersection_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, data))
+{
+ set_intersection_i((st_data_t)i, (st_data_t)data);
+ return i;
+}
+
+/*
+ * call-seq:
+ * set & enum -> new_set
+ *
+ * Returns a new set containing elements common to the set and the given
+ * enumerable object.
+ *
+ * Set[1, 3, 5] & Set[3, 2, 1] #=> Set[3, 1]
+ * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> Set["a", "b"]
+ */
+static VALUE
+set_i_intersection(VALUE set, VALUE other)
+{
+ VALUE new_set = set_s_alloc(rb_obj_class(set));
+ set_table *stable = RSET_TABLE(set);
+ set_table *ntable = RSET_TABLE(new_set);
+
+ if (rb_obj_is_kind_of(other, rb_cSet)) {
+ set_table *otable = RSET_TABLE(other);
+ if (set_table_size(stable) >= set_table_size(otable)) {
+ /* Swap so we iterate over the smaller set */
+ otable = stable;
+ set = other;
+ }
+
+ struct set_intersection_data data = {
+ .set = new_set,
+ .into = ntable,
+ .other = otable
+ };
+ set_iter(set, set_intersection_i, (st_data_t)&data);
+ }
+ else {
+ struct set_intersection_data data = {
+ .set = new_set,
+ .into = ntable,
+ .other = stable
+ };
+ rb_block_call(other, enum_method_id(other), 0, 0, set_intersection_block, (VALUE)&data);
+ }
+
+ return new_set;
+}
+
+/*
+ * call-seq:
+ * include?(item) -> true or false
+ *
+ * Returns true if the set contains the given object:
+ *
+ * Set[1, 2, 3].include? 2 #=> true
+ * Set[1, 2, 3].include? 4 #=> false
+ *
+ * Note that <code>include?</code> and <code>member?</code> do not test member
+ * equality using <code>==</code> as do other Enumerables.
+ *
+ * This is aliased to #===, so it is usable in +case+ expressions:
+ *
+ * case :apple
+ * when Set[:potato, :carrot]
+ * "vegetable"
+ * when Set[:apple, :banana]
+ * "fruit"
+ * end
+ * # => "fruit"
+ *
+ * See also Enumerable#include?
+ */
+static VALUE
+set_i_include(VALUE set, VALUE item)
+{
+ return RBOOL(RSET_IS_MEMBER(set, item));
+}
+
+struct set_merge_args {
+ VALUE set;
+ set_table *into;
+};
+
+static int
+set_merge_i(st_data_t key, st_data_t data)
+{
+ struct set_merge_args *args = (struct set_merge_args *)data;
+ set_table_insert_wb(args->into, args->set, key);
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_merge_block(RB_BLOCK_CALL_FUNC_ARGLIST(key, set))
+{
+ VALUE element = key;
+ set_insert_wb(set, element);
+ return element;
+}
+
+static void
+set_merge_enum_into(VALUE set, VALUE arg)
+{
+ if (rb_obj_is_kind_of(arg, rb_cSet)) {
+ struct set_merge_args args = {
+ .set = set,
+ .into = RSET_TABLE(set)
+ };
+ set_iter(arg, set_merge_i, (st_data_t)&args);
+ }
+ else if (RB_TYPE_P(arg, T_ARRAY)) {
+ long i;
+ set_table *into = RSET_TABLE(set);
+ for (i=0; i<RARRAY_LEN(arg); i++) {
+ set_table_insert_wb(into, set, RARRAY_AREF(arg, i));
+ }
+ }
+ else {
+ rb_block_call(arg, enum_method_id(arg), 0, 0, set_merge_block, (VALUE)set);
+ }
+}
+
+/*
+ * call-seq:
+ * merge(*enums, **nil) -> self
+ *
+ * Merges the elements of the given enumerable objects to the set and
+ * returns self.
+ */
+static VALUE
+set_i_merge(int argc, VALUE *argv, VALUE set)
+{
+ if (rb_keyword_given_p()) {
+ rb_raise(rb_eArgError, "no keywords accepted");
+ }
+
+ if (set_iterating_p(set)) {
+ rb_raise(rb_eRuntimeError, "cannot add to set during iteration");
+ }
+
+ rb_check_frozen(set);
+
+ int i;
+
+ for (i=0; i < argc; i++) {
+ set_merge_enum_into(set, argv[i]);
+ }
+
+ return set;
+}
+
+static VALUE
+set_reset_table_with_type(VALUE set, const struct st_hash_type *type)
+{
+ rb_check_frozen(set);
+
+ struct set_object *sobj;
+ TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
+ set_table *old = &sobj->table;
+
+ size_t size = set_table_size(old);
+ if (size > 0) {
+ set_table *new = set_init_table_with_size(NULL, type, size);
+ struct set_merge_args args = {
+ .set = set,
+ .into = new
+ };
+ set_iter(set, set_merge_i, (st_data_t)&args);
+ set_free_embedded_table(&sobj->table);
+ memcpy(&sobj->table, new, sizeof(*new));
+ SIZED_FREE(new);
+ }
+ else {
+ sobj->table.type = type;
+ }
+
+ return set;
+}
+
+/*
+ * call-seq:
+ * compare_by_identity -> self
+ *
+ * Makes the set compare its elements by their identity and returns self.
+ */
+static VALUE
+set_i_compare_by_identity(VALUE set)
+{
+ if (RSET_COMPARE_BY_IDENTITY(set)) return set;
+
+ if (set_iterating_p(set)) {
+ rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
+ }
+
+ return set_reset_table_with_type(set, &identhash);
+}
+
+/*
+ * call-seq:
+ * compare_by_identity? -> true or false
+ *
+ * Returns true if the set will compare its elements by their
+ * identity. Also see Set#compare_by_identity.
+ */
+static VALUE
+set_i_compare_by_identity_p(VALUE set)
+{
+ return RBOOL(RSET_COMPARE_BY_IDENTITY(set));
+}
+
+/*
+ * call-seq:
+ * size -> integer
+ *
+ * Returns the number of elements.
+ */
+static VALUE
+set_i_size(VALUE set)
+{
+ return RSET_SIZE_NUM(set);
+}
+
+/*
+ * call-seq:
+ * empty? -> true or false
+ *
+ * Returns true if the set contains no elements.
+ */
+static VALUE
+set_i_empty(VALUE set)
+{
+ return RBOOL(RSET_EMPTY(set));
+}
+
+static int
+set_xor_i(st_data_t key, st_data_t data)
+{
+ VALUE element = (VALUE)key;
+ VALUE set = (VALUE)data;
+ set_table *table = RSET_TABLE(set);
+ if (set_table_insert_wb(table, set, element)) {
+ set_table_delete(table, &element);
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * set ^ enum -> new_set
+ *
+ * Returns a new set containing elements exclusive between the set and the
+ * given enumerable object. <tt>(set ^ enum)</tt> is equivalent to
+ * <tt>((set | enum) - (set & enum))</tt>.
+ *
+ * Set[1, 2] ^ Set[2, 3] #=> Set[3, 1]
+ * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> Set["d", 1, "c"]
+ */
+static VALUE
+set_i_xor(VALUE set, VALUE other)
+{
+ VALUE new_set = rb_obj_dup(set);
+
+ if (rb_obj_is_kind_of(other, rb_cSet)) {
+ set_iter(other, set_xor_i, (st_data_t)new_set);
+ }
+ else {
+ VALUE tmp = set_s_alloc(rb_cSet);
+ set_merge_enum_into(tmp, other);
+ set_iter(tmp, set_xor_i, (st_data_t)new_set);
+ }
+
+ return new_set;
+}
+
+/*
+ * call-seq:
+ * set | enum -> new_set
+ *
+ * Returns a new set built by merging the set and the elements of the
+ * given enumerable object.
+ *
+ * Set[1, 2, 3] | Set[2, 4, 5] #=> Set[1, 2, 3, 4, 5]
+ * Set[1, 5, 'z'] | (1..6) #=> Set[1, 5, "z", 2, 3, 4, 6]
+ */
+static VALUE
+set_i_union(VALUE set, VALUE other)
+{
+ set = rb_obj_dup(set);
+ set_merge_enum_into(set, other);
+ return set;
+}
+
+static int
+set_remove_i(st_data_t key, st_data_t from)
+{
+ set_table_delete((struct set_table *)from, (st_data_t *)&key);
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_remove_block(RB_BLOCK_CALL_FUNC_ARGLIST(key, set))
+{
+ rb_check_frozen(set);
+ set_table_delete(RSET_TABLE(set), (st_data_t *)&key);
+ return key;
+}
+
+static void
+set_remove_enum_from(VALUE set, VALUE arg)
+{
+ if (rb_obj_is_kind_of(arg, rb_cSet)) {
+ set_iter(arg, set_remove_i, (st_data_t)RSET_TABLE(set));
+ }
+ else {
+ rb_block_call(arg, enum_method_id(arg), 0, 0, set_remove_block, (VALUE)set);
+ }
+}
+
+/*
+ * call-seq:
+ * subtract(enum) -> self
+ *
+ * Deletes every element that appears in the given enumerable object
+ * and returns self.
+ */
+static VALUE
+set_i_subtract(VALUE set, VALUE other)
+{
+ rb_check_frozen(set);
+ set_remove_enum_from(set, other);
+ return set;
+}
+
+/*
+ * call-seq:
+ * set - enum -> new_set
+ *
+ * Returns a new set built by duplicating the set, removing every
+ * element that appears in the given enumerable object.
+ *
+ * Set[1, 3, 5] - Set[1, 5] #=> Set[3]
+ * Set['a', 'b', 'z'] - ['a', 'c'] #=> Set["b", "z"]
+ */
+static VALUE
+set_i_difference(VALUE set, VALUE other)
+{
+ return set_i_subtract(rb_obj_dup(set), other);
+}
+
+static int
+set_each_i(st_data_t key, st_data_t dummy)
+{
+ rb_yield(key);
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * each { |o| ... } -> self
+ * each -> enumerator
+ *
+ * Calls the given block once for each element in the set, passing
+ * the element as parameter. Returns an enumerator if no block is
+ * given.
+ */
+static VALUE
+set_i_each(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ set_iter(set, set_each_i, 0);
+ return set;
+}
+
+static int
+set_collect_i(st_data_t key, st_data_t data)
+{
+ set_insert_wb((VALUE)data, rb_yield((VALUE)key));
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * collect! { |o| ... } -> self
+ * collect! -> enumerator
+ *
+ * Replaces the elements with ones returned by +collect+.
+ * Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_collect(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ rb_check_frozen(set);
+
+ VALUE new_set = set_s_alloc(rb_obj_class(set));
+ set_iter(set, set_collect_i, (st_data_t)new_set);
+ set_i_initialize_copy(set, new_set);
+
+ return set;
+}
+
+static int
+set_keep_if_i(st_data_t key, st_data_t into)
+{
+ if (!RTEST(rb_yield((VALUE)key))) {
+ set_table_delete((set_table *)into, &key);
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * keep_if { |o| ... } -> self
+ * keep_if -> enumerator
+ *
+ * Deletes every element of the set for which block evaluates to false, and
+ * returns self. Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_keep_if(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ rb_check_frozen(set);
+
+ set_iter(set, set_keep_if_i, (st_data_t)RSET_TABLE(set));
+
+ return set;
+}
+
+/*
+ * call-seq:
+ * select! { |o| ... } -> self
+ * select! -> enumerator
+ *
+ * Equivalent to Set#keep_if, but returns nil if no changes were made.
+ * Returns an enumerator if no block is given.
+ */
+static VALUE
+set_i_select(VALUE set)
+{
+ RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
+ rb_check_frozen(set);
+
+ set_table *table = RSET_TABLE(set);
+ size_t n = set_table_size(table);
+ set_iter(set, set_keep_if_i, (st_data_t)table);
+
+ return (n == set_table_size(table)) ? Qnil : set;
+}
+
+/*
+ * call-seq:
+ * replace(enum) -> self
+ *
+ * Replaces the contents of the set with the contents of the given
+ * enumerable object and returns self.
+ *
+ * set = Set[1, 'c', :s] #=> Set[1, "c", :s]
+ * set.replace([1, 2]) #=> Set[1, 2]
+ * set #=> Set[1, 2]
+ */
+static VALUE
+set_i_replace(VALUE set, VALUE other)
+{
+ rb_check_frozen(set);
+
+ if (rb_obj_is_kind_of(other, rb_cSet)) {
+ set_i_initialize_copy(set, other);
+ }
+ else {
+ if (set_iterating_p(set)) {
+ rb_raise(rb_eRuntimeError, "cannot replace set during iteration");
+ }
+
+ // make sure enum is enumerable before calling clear
+ enum_method_id(other);
+
+ set_table_clear(RSET_TABLE(set));
+ set_merge_enum_into(set, other);
+ }
+
+ return set;
+}
+
+/*
+ * call-seq:
+ * reset -> self
+ *
+ * Resets the internal state after modification to existing elements
+ * and returns self. Elements will be reindexed and deduplicated.
+ */
+static VALUE
+set_i_reset(VALUE set)
+{
+ if (set_iterating_p(set)) {
+ rb_raise(rb_eRuntimeError, "reset during iteration");
+ }
+
+ return set_reset_table_with_type(set, RSET_TABLE(set)->type);
+}
+
+static void set_flatten_merge(VALUE set, VALUE from, VALUE seen);
+
+static int
+set_flatten_merge_i(st_data_t item, st_data_t arg)
+{
+ VALUE *args = (VALUE *)arg;
+ VALUE set = args[0];
+ if (rb_obj_is_kind_of(item, rb_cSet)) {
+ VALUE e_id = rb_obj_id(item);
+ VALUE hash = args[2];
+ switch(rb_hash_aref(hash, e_id)) {
+ case Qfalse:
+ return ST_CONTINUE;
+ case Qtrue:
+ rb_raise(rb_eArgError, "tried to flatten recursive Set");
+ default:
+ break;
+ }
+
+ rb_hash_aset(hash, e_id, Qtrue);
+ set_flatten_merge(set, item, hash);
+ rb_hash_aset(hash, e_id, Qfalse);
+ }
+ else {
+ set_i_add(set, item);
+ }
+ return ST_CONTINUE;
+}
+
+static void
+set_flatten_merge(VALUE set, VALUE from, VALUE hash)
+{
+ VALUE args[3] = {set, from, hash};
+ set_iter(from, set_flatten_merge_i, (st_data_t)args);
+}
+
+/*
+ * call-seq:
+ * flatten -> set
+ *
+ * Returns a new set that is a copy of the set, flattening each
+ * containing set recursively.
+ */
+static VALUE
+set_i_flatten(VALUE set)
+{
+ VALUE new_set = set_s_alloc(rb_obj_class(set));
+ set_flatten_merge(new_set, set, rb_hash_new());
+ return new_set;
+}
+
+static int
+set_contains_set_i(st_data_t item, st_data_t arg)
+{
+ if (rb_obj_is_kind_of(item, rb_cSet)) {
+ *(bool *)arg = true;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * flatten! -> self
+ *
+ * Equivalent to Set#flatten, but replaces the receiver with the
+ * result in place. Returns nil if no modifications were made.
+ */
+static VALUE
+set_i_flatten_bang(VALUE set)
+{
+ bool contains_set = false;
+ set_iter(set, set_contains_set_i, (st_data_t)&contains_set);
+ if (!contains_set) return Qnil;
+ rb_check_frozen(set);
+ return set_i_replace(set, set_i_flatten(set));
+}
+
+struct set_subset_data {
+ set_table *table;
+ VALUE result;
+};
+
+static int
+set_le_i(st_data_t key, st_data_t arg)
+{
+ struct set_subset_data *data = (struct set_subset_data *)arg;
+ if (set_table_lookup(data->table, key)) return ST_CONTINUE;
+ data->result = Qfalse;
+ return ST_STOP;
+}
+
+static VALUE
+set_le(VALUE set, VALUE other)
+{
+ struct set_subset_data data = {
+ .table = RSET_TABLE(other),
+ .result = Qtrue
+ };
+ set_iter(set, set_le_i, (st_data_t)&data);
+ return data.result;
+}
+
+/*
+ * call-seq:
+ * proper_subset?(set) -> true or false
+ *
+ * Returns true if the set is a proper subset of the given set.
+ */
+static VALUE
+set_i_proper_subset(VALUE set, VALUE other)
+{
+ check_set(other);
+ if (RSET_SIZE(set) >= RSET_SIZE(other)) return Qfalse;
+ return set_le(set, other);
+}
+
+/*
+ * call-seq:
+ * subset?(set) -> true or false
+ *
+ * Returns true if the set is a subset of the given set.
+ */
+static VALUE
+set_i_subset(VALUE set, VALUE other)
+{
+ check_set(other);
+ if (RSET_SIZE(set) > RSET_SIZE(other)) return Qfalse;
+ return set_le(set, other);
+}
+
+/*
+ * call-seq:
+ * proper_superset?(set) -> true or false
+ *
+ * Returns true if the set is a proper superset of the given set.
+ */
+static VALUE
+set_i_proper_superset(VALUE set, VALUE other)
+{
+ check_set(other);
+ if (RSET_SIZE(set) <= RSET_SIZE(other)) return Qfalse;
+ return set_le(other, set);
+}
+
+/*
+ * call-seq:
+ * superset?(set) -> true or false
+ *
+ * Returns true if the set is a superset of the given set.
+ */
+static VALUE
+set_i_superset(VALUE set, VALUE other)
+{
+ check_set(other);
+ if (RSET_SIZE(set) < RSET_SIZE(other)) return Qfalse;
+ return set_le(other, set);
+}
+
+static int
+set_intersect_i(st_data_t key, st_data_t arg)
+{
+ VALUE *args = (VALUE *)arg;
+ if (set_table_lookup((set_table *)args[0], key)) {
+ args[1] = Qtrue;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * intersect?(set) -> true or false
+ *
+ * Returns true if the set and the given enumerable have at least one
+ * element in common.
+ *
+ * Set[1, 2, 3].intersect? Set[4, 5] #=> false
+ * Set[1, 2, 3].intersect? Set[3, 4] #=> true
+ * Set[1, 2, 3].intersect? 4..5 #=> false
+ * Set[1, 2, 3].intersect? [3, 4] #=> true
+ */
+static VALUE
+set_i_intersect(VALUE set, VALUE other)
+{
+ if (rb_obj_is_kind_of(other, rb_cSet)) {
+ size_t set_size = RSET_SIZE(set);
+ size_t other_size = RSET_SIZE(other);
+ VALUE args[2];
+ args[1] = Qfalse;
+ VALUE iter_arg;
+
+ if (set_size < other_size) {
+ iter_arg = set;
+ args[0] = (VALUE)RSET_TABLE(other);
+ }
+ else {
+ iter_arg = other;
+ args[0] = (VALUE)RSET_TABLE(set);
+ }
+ set_iter(iter_arg, set_intersect_i, (st_data_t)args);
+ return args[1];
+ }
+ else if (rb_obj_is_kind_of(other, rb_mEnumerable)) {
+ return rb_funcall(other, id_any_p, 1, set);
+ }
+ else {
+ rb_raise(rb_eArgError, "value must be enumerable");
+ }
+}
+
+/*
+ * call-seq:
+ * disjoint?(set) -> true or false
+ *
+ * Returns true if the set and the given enumerable have no
+ * element in common. This method is the opposite of +intersect?+.
+ *
+ * Set[1, 2, 3].disjoint? Set[3, 4] #=> false
+ * Set[1, 2, 3].disjoint? Set[4, 5] #=> true
+ * Set[1, 2, 3].disjoint? [3, 4] #=> false
+ * Set[1, 2, 3].disjoint? 4..5 #=> true
+ */
+static VALUE
+set_i_disjoint(VALUE set, VALUE other)
+{
+ return RBOOL(!RTEST(set_i_intersect(set, other)));
+}
+
+/*
+ * call-seq:
+ * set <=> other -> -1, 0, 1, or nil
+ *
+ * Returns 0 if the set are equal, -1 / 1 if the set is a
+ * proper subset / superset of the given set, or nil if
+ * they both have unique elements.
+ */
+static VALUE
+set_i_compare(VALUE set, VALUE other)
+{
+ if (rb_obj_is_kind_of(other, rb_cSet)) {
+ size_t set_size = RSET_SIZE(set);
+ size_t other_size = RSET_SIZE(other);
+
+ if (set_size < other_size) {
+ if (set_le(set, other) == Qtrue) {
+ return INT2NUM(-1);
+ }
+ }
+ else if (set_size > other_size) {
+ if (set_le(other, set) == Qtrue) {
+ return INT2NUM(1);
+ }
+ }
+ else if (set_le(set, other) == Qtrue) {
+ return INT2NUM(0);
+ }
+ }
+
+ return Qnil;
+}
+
+struct set_equal_data {
+ VALUE result;
+ VALUE set;
+};
+
+static int
+set_eql_i(st_data_t item, st_data_t arg)
+{
+ struct set_equal_data *data = (struct set_equal_data *)arg;
+
+ if (!set_table_lookup(RSET_TABLE(data->set), item)) {
+ data->result = Qfalse;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_recursive_eql(VALUE set, VALUE dt, int recur)
+{
+ if (recur) return Qtrue;
+ struct set_equal_data *data = (struct set_equal_data*)dt;
+ data->result = Qtrue;
+ set_iter(set, set_eql_i, dt);
+ return data->result;
+}
+
+/*
+ * call-seq:
+ * set == other -> true or false
+ *
+ * Returns true if two sets are equal.
+ */
+static VALUE
+set_i_eq(VALUE set, VALUE other)
+{
+ if (!rb_obj_is_kind_of(other, rb_cSet)) return Qfalse;
+ if (set == other) return Qtrue;
+
+ set_table *stable = RSET_TABLE(set);
+ set_table *otable = RSET_TABLE(other);
+ size_t ssize = set_table_size(stable);
+ size_t osize = set_table_size(otable);
+
+ if (ssize != osize) return Qfalse;
+ if (ssize == 0 && osize == 0) return Qtrue;
+ if (stable->type != otable->type) return Qfalse;
+
+ struct set_equal_data data;
+ data.set = other;
+ return rb_exec_recursive_paired(set_recursive_eql, set, other, (VALUE)&data);
+}
+
+static int
+set_hash_i(st_data_t item, st_data_t(arg))
+{
+ st_index_t *hval = (st_index_t *)arg;
+ st_index_t ival = rb_hash(item);
+ *hval ^= rb_st_hash(&ival, sizeof(st_index_t), 0);
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * hash -> integer
+ *
+ * Returns hash code for set.
+ */
+static VALUE
+set_i_hash(VALUE set)
+{
+ st_index_t size = RSET_SIZE(set);
+ st_index_t hval = rb_st_hash_start(size);
+ hval = rb_hash_uint(hval, (st_index_t)set_i_hash);
+ if (size) {
+ set_iter(set, set_hash_i, (VALUE)&hval);
+ }
+ hval = rb_st_hash_end(hval);
+ return ST2FIX(hval);
+}
+
+/* :nodoc: */
+static int
+set_to_hash_i(st_data_t key, st_data_t arg)
+{
+ rb_hash_aset((VALUE)arg, (VALUE)key, Qtrue);
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_i_to_h(VALUE set)
+{
+ st_index_t size = RSET_SIZE(set);
+ VALUE hash;
+ if (RSET_COMPARE_BY_IDENTITY(set)) {
+ hash = rb_ident_hash_new_with_size(size);
+ }
+ else {
+ hash = rb_hash_new_with_size(size);
+ }
+ rb_hash_set_default(hash, Qfalse);
+
+ if (size == 0) return hash;
+
+ set_iter(set, set_to_hash_i, (st_data_t)hash);
+ return hash;
+}
+
+static VALUE
+compat_dumper(VALUE set)
+{
+ VALUE dumper = rb_class_new_instance(0, 0, rb_cObject);
+ rb_ivar_set(dumper, id_i_hash, set_i_to_h(set));
+ return dumper;
+}
+
+static int
+set_i_from_hash_i(st_data_t key, st_data_t val, st_data_t set)
+{
+ if ((VALUE)val != Qtrue) {
+ rb_raise(rb_eRuntimeError, "expect true as Set value: %"PRIsVALUE, rb_obj_class((VALUE)val));
+ }
+ set_i_add((VALUE)set, (VALUE)key);
+ return ST_CONTINUE;
+}
+
+static VALUE
+set_i_from_hash(VALUE set, VALUE hash)
+{
+ Check_Type(hash, T_HASH);
+ if (rb_hash_compare_by_id_p(hash)) set_i_compare_by_identity(set);
+ rb_hash_stlike_foreach(hash, set_i_from_hash_i, (st_data_t)set);
+ return set;
+}
+
+static VALUE
+compat_loader(VALUE self, VALUE a)
+{
+ return set_i_from_hash(self, rb_ivar_get(a, id_i_hash));
+}
+
+/* C-API functions */
+
+void
+rb_set_foreach(VALUE set, int (*func)(VALUE element, VALUE arg), VALUE arg)
+{
+ set_iter(set, func, arg);
+}
+
+VALUE
+rb_set_new(void)
+{
+ return set_alloc_with_size(rb_cSet, 0);
+}
+
+VALUE
+rb_set_new_capa(size_t capa)
+{
+ return set_alloc_with_size(rb_cSet, (st_index_t)capa);
+}
+
+bool
+rb_set_lookup(VALUE set, VALUE element)
+{
+ return RSET_IS_MEMBER(set, element);
+}
+
+bool
+rb_set_add(VALUE set, VALUE element)
+{
+ return set_i_add_p(set, element) != Qnil;
+}
+
+VALUE
+rb_set_clear(VALUE set)
+{
+ return set_i_clear(set);
+}
+
+bool
+rb_set_delete(VALUE set, VALUE element)
+{
+ return set_i_delete_p(set, element) != Qnil;
+}
+
+size_t
+rb_set_size(VALUE set)
+{
+ return RSET_SIZE(set);
+}
+
+/*
+ * Document-class: Set
+ *
+ * The Set class implements a collection of unordered values with no
+ * duplicates. It 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
+ * can be converted to Set using the +to_set+ method.
+ *
+ * Set uses a data structure similar to Hash for storage, except that
+ * it only has keys and no values.
+ *
+ * * Equality of elements is determined according to Object#eql? and
+ * Object#hash. Use Set#compare_by_identity to make a set compare
+ * its elements by their identity.
+ * * Set assumes that the identity of each element does not change
+ * while it is stored. Modifying an element of a set will render the
+ * set to an unreliable state.
+ * * When a string is to be stored, a frozen copy of the string is
+ * stored instead unless the original string is already frozen.
+ *
+ * == Comparison
+ *
+ * The comparison operators <tt><</tt>, <tt>></tt>, <tt><=</tt>, and
+ * <tt>>=</tt> are implemented as shorthand for the
+ * {proper_,}{subset?,superset?} methods. The <tt><=></tt>
+ * operator reflects this order, or returns +nil+ for sets that both
+ * have distinct elements (<tt>{x, y}</tt> vs. <tt>{x, z}</tt> for example).
+ *
+ * == Example
+ *
+ * s1 = Set[1, 2] #=> Set[1, 2]
+ * s2 = [1, 2].to_set #=> Set[1, 2]
+ * s1 == s2 #=> true
+ * s1.add("foo") #=> Set[1, 2, "foo"]
+ * s1.merge([2, 6]) #=> Set[1, 2, "foo", 6]
+ * s1.subset?(s2) #=> false
+ * s2.subset?(s1) #=> true
+ *
+ * == Contact
+ *
+ * - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
+ *
+ * == Inheriting from \Set
+ *
+ * Before Ruby 4.0 (released December 2025), \Set had a different, less
+ * efficient implementation. It was reimplemented in C, and the behavior
+ * of some of the core methods were adjusted.
+ *
+ * To keep backward compatibility, when a class is inherited from \Set,
+ * additional module +Set::SubclassCompatible+ is included, which makes
+ * the inherited class behavior, as well as internal method names,
+ * closer to what it was before Ruby 4.0.
+ *
+ * It can be easily seen, for example, in the #inspect method behavior:
+ *
+ * p Set[1, 2, 3]
+ * # prints "Set[1, 2, 3]"
+ *
+ * class MySet < Set
+ * end
+ * p MySet[1, 2, 3]
+ * # prints "#<MySet: {1, 2, 3}>", like it was in Ruby 3.4
+ *
+ * For new code, if backward compatibility is not necessary,
+ * it is recommended to instead inherit from +Set::CoreSet+, which
+ * avoids including the "compatibility" layer:
+ *
+ * class MyCoreSet < Set::CoreSet
+ * end
+ * p MyCoreSet[1, 2, 3]
+ * # prints "MyCoreSet[1, 2, 3]"
+ *
+ * == Set's methods
+ *
+ * First, what's elsewhere. \Class \Set:
+ *
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
+ * which provides dozens of additional methods.
+ *
+ * In particular, class \Set does not have many methods of its own
+ * for fetching or for iterating.
+ * Instead, it relies on those in \Enumerable.
+ *
+ * Here, class \Set provides methods that are useful for:
+ *
+ * - {Creating a Set}[rdoc-ref:Set@Methods+for+Creating+a+Set]
+ * - {Set Operations}[rdoc-ref:Set@Methods+for+Set+Operations]
+ * - {Comparing}[rdoc-ref:Set@Methods+for+Comparing]
+ * - {Querying}[rdoc-ref:Set@Methods+for+Querying]
+ * - {Assigning}[rdoc-ref:Set@Methods+for+Assigning]
+ * - {Deleting}[rdoc-ref:Set@Methods+for+Deleting]
+ * - {Converting}[rdoc-ref:Set@Methods+for+Converting]
+ * - {Iterating}[rdoc-ref:Set@Methods+for+Iterating]
+ * - {And more....}[rdoc-ref:Set@Other+Methods]
+ *
+ * === Methods for Creating a \Set
+ *
+ * - ::[]:
+ * Returns a new set containing the given objects.
+ * - ::new:
+ * Returns a new set containing either the given objects
+ * (if no block given) or the return values from the called block
+ * (if a block given).
+ *
+ * === Methods for \Set Operations
+ *
+ * - #| (aliased as #union and #+):
+ * Returns a new set containing all elements from +self+
+ * and all elements from a given enumerable (no duplicates).
+ * - #& (aliased as #intersection):
+ * Returns a new set containing all elements common to +self+
+ * and a given enumerable.
+ * - #- (aliased as #difference):
+ * Returns a copy of +self+ with all elements
+ * in a given enumerable removed.
+ * - #^: Returns a new set containing all elements from +self+
+ * and a given enumerable except those common to both.
+ *
+ * === Methods for Comparing
+ *
+ * - #<=>: Returns -1, 0, or 1 as +self+ is less than, equal to,
+ * or greater than a given object.
+ * - #==: Returns whether +self+ and a given enumerable are equal,
+ * as determined by Object#eql?.
+ * - #compare_by_identity?:
+ * Returns whether the set considers only identity
+ * when comparing elements.
+ *
+ * === Methods for Querying
+ *
+ * - #length (aliased as #size):
+ * Returns the count of elements.
+ * - #empty?:
+ * Returns whether the set has no elements.
+ * - #include? (aliased as #member? and #===):
+ * Returns whether a given object is an element in the set.
+ * - #subset? (aliased as #<=):
+ * Returns whether a given object is a subset of the set.
+ * - #proper_subset? (aliased as #<):
+ * Returns whether a given enumerable is a proper subset of the set.
+ * - #superset? (aliased as #>=):
+ * Returns whether a given enumerable is a superset of the set.
+ * - #proper_superset? (aliased as #>):
+ * Returns whether a given enumerable is a proper superset of the set.
+ * - #disjoint?:
+ * Returns +true+ if the set and a given enumerable
+ * have no common elements, +false+ otherwise.
+ * - #intersect?:
+ * Returns +true+ if the set and a given enumerable:
+ * have any common elements, +false+ otherwise.
+ * - #compare_by_identity?:
+ * Returns whether the set considers only identity
+ * when comparing elements.
+ *
+ * === Methods for Assigning
+ *
+ * - #add (aliased as #<<):
+ * Adds a given object to the set; returns +self+.
+ * - #add?:
+ * 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+.
+ * - #replace:
+ * Replaces the contents of the set with the contents
+ * of a given enumerable.
+ *
+ * === Methods for Deleting
+ *
+ * - #clear:
+ * Removes all elements in the set; returns +self+.
+ * - #delete:
+ * Removes a given object from the set; returns +self+.
+ * - #delete?:
+ * If the given object is an element in the set,
+ * removes it and returns +self+; otherwise, returns +nil+.
+ * - #subtract:
+ * Removes each given object from the set; returns +self+.
+ * - #delete_if - Removes elements specified by a given block.
+ * - #select! (aliased as #filter!):
+ * Removes elements not specified by a given block.
+ * - #keep_if:
+ * Removes elements not specified by a given block.
+ * - #reject!
+ * Removes elements specified by a given block.
+ *
+ * === Methods for Converting
+ *
+ * - #classify:
+ * Returns a hash that classifies the elements,
+ * as determined by the given block.
+ * - #collect! (aliased as #map!):
+ * Replaces each element with a block return-value.
+ * - #divide:
+ * Returns a hash that classifies the elements,
+ * as determined by the given block;
+ * differs from #classify in that the block may accept
+ * either one or two arguments.
+ * - #flatten:
+ * Returns a new set that is a recursive flattening of +self+.
+ * - #flatten!:
+ * Replaces each nested set in +self+ with the elements from that set.
+ * - #inspect (aliased as #to_s):
+ * Returns a string displaying the elements.
+ * - #join:
+ * Returns a string containing all elements, converted to strings
+ * as needed, and joined by the given record separator.
+ * - #to_a:
+ * Returns an array containing all set elements.
+ * - #to_set:
+ * Returns +self+ if given no arguments and no block;
+ * with a block given, returns a new set consisting of block
+ * return values.
+ *
+ * === Methods for Iterating
+ *
+ * - #each:
+ * Calls the block with each successive element; returns +self+.
+ *
+ * === Other Methods
+ *
+ * - #reset:
+ * Resets the internal state; useful if an object
+ * has been modified while an element in the set.
+ *
+ */
+void
+Init_Set(void)
+{
+ rb_cSet = rb_define_class("Set", rb_cObject);
+ rb_include_module(rb_cSet, rb_mEnumerable);
+
+ id_each_entry = rb_intern_const("each_entry");
+ id_any_p = rb_intern_const("any?");
+ id_new = rb_intern_const("new");
+ id_i_hash = rb_intern_const("@hash");
+ id_subclass_compatible = rb_intern_const("SubclassCompatible");
+ id_class_methods = rb_intern_const("ClassMethods");
+ id_set_iter_lev = rb_make_internal_id();
+
+ rb_define_alloc_func(rb_cSet, set_s_alloc);
+ rb_define_singleton_method(rb_cSet, "[]", set_s_create, -1);
+
+ rb_define_method(rb_cSet, "initialize", set_i_initialize, -1);
+ rb_define_method(rb_cSet, "initialize_copy", set_i_initialize_copy, 1);
+
+ rb_define_method(rb_cSet, "&", set_i_intersection, 1);
+ rb_define_alias(rb_cSet, "intersection", "&");
+ rb_define_method(rb_cSet, "-", set_i_difference, 1);
+ rb_define_alias(rb_cSet, "difference", "-");
+ rb_define_method(rb_cSet, "^", set_i_xor, 1);
+ rb_define_method(rb_cSet, "|", set_i_union, 1);
+ rb_define_alias(rb_cSet, "+", "|");
+ rb_define_alias(rb_cSet, "union", "|");
+ rb_define_method(rb_cSet, "<=>", set_i_compare, 1);
+ rb_define_method(rb_cSet, "==", set_i_eq, 1);
+ rb_define_alias(rb_cSet, "eql?", "==");
+ rb_define_method(rb_cSet, "add", set_i_add, 1);
+ rb_define_alias(rb_cSet, "<<", "add");
+ rb_define_method(rb_cSet, "add?", set_i_add_p, 1);
+ rb_define_method(rb_cSet, "classify", set_i_classify, 0);
+ rb_define_method(rb_cSet, "clear", set_i_clear, 0);
+ rb_define_method(rb_cSet, "collect!", set_i_collect, 0);
+ rb_define_alias(rb_cSet, "map!", "collect!");
+ rb_define_method(rb_cSet, "compare_by_identity", set_i_compare_by_identity, 0);
+ rb_define_method(rb_cSet, "compare_by_identity?", set_i_compare_by_identity_p, 0);
+ rb_define_method(rb_cSet, "delete", set_i_delete, 1);
+ rb_define_method(rb_cSet, "delete?", set_i_delete_p, 1);
+ rb_define_method(rb_cSet, "delete_if", set_i_delete_if, 0);
+ rb_define_method(rb_cSet, "disjoint?", set_i_disjoint, 1);
+ rb_define_method(rb_cSet, "divide", set_i_divide, 0);
+ rb_define_method(rb_cSet, "each", set_i_each, 0);
+ rb_define_method(rb_cSet, "empty?", set_i_empty, 0);
+ rb_define_method(rb_cSet, "flatten", set_i_flatten, 0);
+ rb_define_method(rb_cSet, "flatten!", set_i_flatten_bang, 0);
+ rb_define_method(rb_cSet, "hash", set_i_hash, 0);
+ rb_define_method(rb_cSet, "include?", set_i_include, 1);
+ rb_define_alias(rb_cSet, "member?", "include?");
+ rb_define_alias(rb_cSet, "===", "include?");
+ rb_define_method(rb_cSet, "inspect", set_i_inspect, 0);
+ rb_define_alias(rb_cSet, "to_s", "inspect");
+ rb_define_method(rb_cSet, "intersect?", set_i_intersect, 1);
+ rb_define_method(rb_cSet, "join", set_i_join, -1);
+ rb_define_method(rb_cSet, "keep_if", set_i_keep_if, 0);
+ rb_define_method(rb_cSet, "merge", set_i_merge, -1);
+ rb_define_method(rb_cSet, "proper_subset?", set_i_proper_subset, 1);
+ rb_define_alias(rb_cSet, "<", "proper_subset?");
+ rb_define_method(rb_cSet, "proper_superset?", set_i_proper_superset, 1);
+ rb_define_alias(rb_cSet, ">", "proper_superset?");
+ rb_define_method(rb_cSet, "reject!", set_i_reject, 0);
+ rb_define_method(rb_cSet, "replace", set_i_replace, 1);
+ rb_define_method(rb_cSet, "reset", set_i_reset, 0);
+ rb_define_method(rb_cSet, "size", set_i_size, 0);
+ rb_define_alias(rb_cSet, "length", "size");
+ rb_define_method(rb_cSet, "select!", set_i_select, 0);
+ rb_define_alias(rb_cSet, "filter!", "select!");
+ rb_define_method(rb_cSet, "subset?", set_i_subset, 1);
+ rb_define_alias(rb_cSet, "<=", "subset?");
+ rb_define_method(rb_cSet, "subtract", set_i_subtract, 1);
+ rb_define_method(rb_cSet, "superset?", set_i_superset, 1);
+ rb_define_alias(rb_cSet, ">=", "superset?");
+ rb_define_method(rb_cSet, "to_a", set_i_to_a, 0);
+ rb_define_method(rb_cSet, "to_set", set_i_to_set, 0);
+
+ /* :nodoc: */
+ VALUE compat = rb_define_class_under(rb_cSet, "compatible", rb_cObject);
+ rb_marshal_define_compat(rb_cSet, compat, compat_dumper, compat_loader);
+
+ // Create Set::CoreSet before defining inherited, so it does not include
+ // the backwards compatibility layer.
+ rb_define_class_under(rb_cSet, "CoreSet", rb_cSet);
+ rb_define_private_method(rb_singleton_class(rb_cSet), "inherited", set_s_inherited, 1);
+
+ rb_provide("set.rb");
+}
diff --git a/shape.c b/shape.c
index 1f1f14f434..7a02b23073 100644
--- a/shape.c
+++ b/shape.c
@@ -20,64 +20,72 @@
#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)
/* This depends on that the allocated memory by Ruby's allocator or
* mmap is not located at an odd address. */
#define SINGLE_CHILD_TAG 0x1
-#define TAG_SINGLE_CHILD(x) (struct rb_id_table *)((uintptr_t)(x) | SINGLE_CHILD_TAG)
+#define TAG_SINGLE_CHILD(x) (VALUE)((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 MAX_SHAPE_ID (INVALID_SHAPE_ID - 1)
#define ANCESTOR_SEARCH_MAX_DEPTH 2
-static ID id_frozen;
-static ID id_t_object;
+static ID id_object_id;
+
+// Should be on its own cache line
+static RUBY_ALIGNAS(128) rb_atomic_t redblack_cache_size;
+
+struct redblack_node {
+ ID key;
+ rb_shape_t *value;
+ redblack_id_t l;
+ redblack_id_t r;
+};
+typedef struct redblack_node redblack_node_t;
+
+static redblack_node_t *redblack_cache;
#define LEAF 0
#define BLACK 0x0
#define RED 0x1
+static inline redblack_node_t *
+redblack_node(redblack_id_t id)
+{
+ return id ? &redblack_cache[id - 1] : LEAF;
+}
+
static redblack_node_t *
-redblack_left(redblack_node_t * node)
+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];
+ RUBY_ASSERT(node->l < redblack_cache_size);
+ redblack_node_t *left = redblack_node(node->l);
return left;
}
}
static redblack_node_t *
-redblack_right(redblack_node_t * node)
+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];
+ RUBY_ASSERT(node->r < redblack_cache_size);
+ redblack_node_t *right = redblack_node(node->r);
return right;
}
}
static redblack_node_t *
-redblack_find(redblack_node_t * tree, ID key)
+redblack_find0(redblack_node_t *tree, ID key)
{
if (tree == LEAF) {
return LEAF;
@@ -91,17 +99,23 @@ redblack_find(redblack_node_t * tree, ID key)
}
else {
if (key < tree->key) {
- return redblack_find(redblack_left(tree), key);
+ return redblack_find0(redblack_left(tree), key);
}
else {
- return redblack_find(redblack_right(tree), key);
+ return redblack_find0(redblack_right(tree), key);
}
}
}
}
+static redblack_node_t *
+redblack_find(redblack_id_t tree_id, ID key)
+{
+ return redblack_find0(redblack_node(tree_id), key);
+}
+
static inline rb_shape_t *
-redblack_value(redblack_node_t * node)
+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
@@ -110,35 +124,35 @@ redblack_value(redblack_node_t * node)
#ifdef HAVE_MMAP
static inline char
-redblack_color(redblack_node_t * node)
+redblack_color(redblack_node_t *node)
{
return node && ((uintptr_t)node->value & RED);
}
static inline bool
-redblack_red_p(redblack_node_t * node)
+redblack_red_p(redblack_node_t *node)
{
return redblack_color(node) == RED;
}
static redblack_id_t
-redblack_id_for(redblack_node_t * node)
+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_node_t *redblack_nodes = redblack_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)
+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) {
+ if (redblack_cache_size + 1 >= REDBLACK_CACHE_SIZE) {
// We're out of cache, just quit
return LEAF;
}
@@ -146,8 +160,8 @@ redblack_new(char color, ID key, rb_shape_t * value, redblack_node_t * left, red
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)++];
+ redblack_node_t *redblack_nodes = redblack_cache;
+ redblack_node_t *node = &redblack_nodes[RUBY_ATOMIC_FETCH_ADD(redblack_cache_size, 1)];
node->key = key;
node->value = (rb_shape_t *)((uintptr_t)value | color);
node->l = redblack_id_for(left);
@@ -156,7 +170,7 @@ redblack_new(char color, ID key, rb_shape_t * value, redblack_node_t * left, red
}
static redblack_node_t *
-redblack_balance(char color, ID key, rb_shape_t * value, redblack_node_t * left, redblack_node_t * right)
+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;
@@ -243,7 +257,7 @@ redblack_balance(char color, ID key, rb_shape_t * value, redblack_node_t * left,
}
static redblack_node_t *
-redblack_insert_aux(redblack_node_t * tree, ID key, rb_shape_t * value)
+redblack_insert_aux(redblack_node_t *tree, ID key, rb_shape_t *value)
{
if (tree == LEAF) {
return redblack_new(RED, key, value, LEAF, LEAF);
@@ -277,148 +291,187 @@ redblack_insert_aux(redblack_node_t * tree, ID key, rb_shape_t * value)
}
static redblack_node_t *
-redblack_force_black(redblack_node_t * node)
+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)
+static redblack_id_t
+redblack_insert(redblack_node_t *tree, ID key, rb_shape_t *value)
{
- redblack_node_t * root = redblack_insert_aux(tree, key, value);
+ redblack_node_t *root = redblack_insert_aux(tree, key, value);
if (redblack_red_p(root)) {
- return redblack_force_black(root);
+ return redblack_id_for(redblack_force_black(root));
}
else {
- return root;
+ return redblack_id_for(root);
}
}
#endif
-rb_shape_tree_t *rb_shape_tree_ptr = NULL;
+static VALUE shape_tree_obj = Qfalse;
+rb_shape_tree_t rb_shape_tree = { 0 };
+
+// Should be on its own cache line
+static RUBY_ALIGNAS(128) rb_atomic_t shape_next_id;
-/*
- * Shape getters
- */
rb_shape_t *
rb_shape_get_root_shape(void)
{
- return GET_SHAPE_TREE()->root_shape;
+ return rb_shape_tree.shape_list;
}
-shape_id_t
-rb_shape_id(rb_shape_t * shape)
+static void
+shape_tree_mark_and_move(void *data)
{
- return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list);
+ rb_shape_t *cursor = rb_shape_get_root_shape();
+ rb_shape_t *end = RSHAPE(shape_next_id - 1);
+ while (cursor <= end) {
+ if (cursor->edges && !SINGLE_CHILD_P(cursor->edges)) {
+ rb_gc_mark_and_move(&cursor->edges);
+ }
+ cursor++;
+ }
}
-void
-rb_shape_each_shape(each_shape_callback callback, void *data)
+size_t
+rb_shapes_cache_size(void)
{
- 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);
- while (cursor < end) {
- callback(cursor, data);
- cursor += 1;
- }
+ return redblack_cache ? redblack_cache_size : 0;
}
-RUBY_FUNC_EXPORTED rb_shape_t *
-rb_shape_get_shape_by_id(shape_id_t shape_id)
+size_t
+rb_shapes_count(void)
{
- RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
+ return (size_t)RUBY_ATOMIC_LOAD(shape_next_id);
+}
- rb_shape_t *shape = &GET_SHAPE_TREE()->shape_list[shape_id];
- return shape;
+static size_t
+shape_tree_memsize(const void *data)
+{
+ if (redblack_cache) {
+ return redblack_cache_size * sizeof(redblack_node_t);
+ }
+ return 0;
}
-rb_shape_t *
-rb_shape_get_parent(rb_shape_t * shape)
+static const rb_data_type_t shape_tree_type = {
+ .wrap_struct_name = "VM/shape_tree",
+ .function = {
+ .dmark = shape_tree_mark_and_move,
+ .dfree = NULL, // Nothing to free, done at VM exit in rb_shape_free_all,
+ .dsize = shape_tree_memsize,
+ .dcompact = shape_tree_mark_and_move,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+
+
+/*
+ * Shape getters
+ */
+
+static inline shape_id_t
+SHAPE_OFFSET(rb_shape_t *shape)
{
- return rb_shape_get_shape_by_id(shape->parent_id);
+ RUBY_ASSERT(shape);
+ return (shape_id_t)(shape - rb_shape_tree.shape_list);
}
-#if !SHAPE_IN_BASIC_FLAGS
-shape_id_t rb_generic_shape_id(VALUE obj);
-#endif
+static inline shape_id_t
+SHAPE_ID(rb_shape_t *shape, shape_id_t previous_shape_id)
+{
+ RUBY_ASSERT(shape);
+ shape_id_t offset = (shape_id_t)(shape - rb_shape_tree.shape_list);
+ return offset | RSHAPE_FLAGS(previous_shape_id);
+}
+
+void
+rb_shape_each_shape_id(each_shape_callback callback, void *data)
+{
+ rb_shape_t *start = rb_shape_get_root_shape();
+ rb_shape_t *cursor = start;
+ rb_shape_t *end = RSHAPE(RUBY_ATOMIC_LOAD(shape_next_id));
+ while (cursor < end) {
+ callback((shape_id_t)(cursor - start), data);
+ cursor += 1;
+ }
+}
RUBY_FUNC_EXPORTED shape_id_t
-rb_shape_get_shape_id(VALUE obj)
+rb_obj_shape_id(VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) {
- return SPECIAL_CONST_SHAPE_ID;
+ rb_bug("rb_obj_shape_id: called on a special constant");
}
-#if SHAPE_IN_BASIC_FLAGS
- return RBASIC_SHAPE_ID(obj);
-#else
- switch (BUILTIN_TYPE(obj)) {
- case T_OBJECT:
- return ROBJECT_SHAPE_ID(obj);
- break;
- case T_CLASS:
- case T_MODULE:
- return RCLASS_SHAPE_ID(obj);
- default:
- return rb_generic_shape_id(obj);
+ if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) {
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ shape_id_t base = ROOT_SHAPE_ID;
+ if (fields_obj) {
+ // Remove the layout from the fields object. We want to
+ // combine the shape of the fields object with the layout of the
+ // class / module object.
+ base = RBASIC_SHAPE_ID(fields_obj) & ~SHAPE_ID_LAYOUT_MASK;
+ }
+ return rb_shape_layout(RBASIC_SHAPE_ID(obj)) | base;
}
-#endif
+ return RBASIC_SHAPE_ID(obj);
}
size_t
-rb_shape_depth(rb_shape_t * shape)
+rb_shape_depth(shape_id_t shape_id)
{
size_t depth = 1;
+ rb_shape_t *shape = RSHAPE(shape_id);
- while (shape->parent_id != INVALID_SHAPE_ID) {
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
depth++;
- shape = rb_shape_get_parent(shape);
+ shape = RSHAPE(shape->parent_offset);
}
return depth;
}
-rb_shape_t*
-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++;
+ shape_id_t current, new_id;
- if (shape_id == (MAX_SHAPE_ID + 1)) {
- // TODO: Make an OutOfShapesError ??
- rb_bug("Out of shapes");
- }
+ do {
+ current = RUBY_ATOMIC_LOAD(shape_next_id);
+ if (current > MAX_SHAPE_ID) {
+ return NULL; // Out of shapes
+ }
+ new_id = current + 1;
+ } while (current != RUBY_ATOMIC_CAS(shape_next_id, current, new_id));
- return &GET_SHAPE_TREE()->shape_list[shape_id];
+ return &rb_shape_tree.shape_list[current];
}
static rb_shape_t *
-rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
+rb_shape_alloc_with_parent_offset(ID edge_name, shape_id_t parent_offset)
{
- rb_shape_t * shape = shape_alloc();
+ rb_shape_t *shape = shape_alloc();
+ if (!shape) return NULL;
shape->edge_name = edge_name;
- shape->next_iv_index = 0;
- shape->parent_id = parent_id;
- shape->edges = NULL;
+ shape->next_field_index = 0;
+ shape->parent_offset = parent_offset;
+ shape->edges = 0;
return shape;
}
static rb_shape_t *
-rb_shape_alloc(ID edge_name, rb_shape_t * parent, enum shape_type type)
+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));
+ rb_shape_t *shape = rb_shape_alloc_with_parent_offset(edge_name, SHAPE_OFFSET(parent));
+ if (!shape) return NULL;
+
shape->type = (uint8_t)type;
- shape->heap_index = parent->heap_index;
shape->capacity = parent->capacity;
shape->edges = 0;
return shape;
@@ -426,15 +479,13 @@ rb_shape_alloc(ID edge_name, rb_shape_t * parent, enum shape_type type)
#ifdef HAVE_MMAP
static redblack_node_t *
-redblack_cache_ancestors(rb_shape_t * shape)
+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->ancestor_index || shape->parent_offset == INVALID_SHAPE_ID)) {
+ redblack_node_t *parent_index_node = redblack_cache_ancestors(RSHAPE(shape->parent_offset));
if (shape->type == SHAPE_IVAR) {
- shape->ancestor_index = redblack_insert(parent_index, shape->edge_name, shape);
+ shape->ancestor_index = redblack_insert(parent_index_node, shape->edge_name, shape);
#if RUBY_DEBUG
if (shape->ancestor_index) {
@@ -445,43 +496,59 @@ redblack_cache_ancestors(rb_shape_t * shape)
#endif
}
else {
- shape->ancestor_index = parent_index;
+ shape->ancestor_index = redblack_id_for(parent_index_node);
}
}
- return shape->ancestor_index;
+ return redblack_node(shape->ancestor_index);
}
#else
static redblack_node_t *
-redblack_cache_ancestors(rb_shape_t * shape)
+redblack_cache_ancestors(rb_shape_t *shape)
{
return LEAF;
}
#endif
+static attr_index_t
+shape_grow_capa(attr_index_t current_capa)
+{
+ const attr_index_t *capacities = rb_shape_tree.capacities;
+ size_t heaps_count = rb_shape_tree.heaps_count;
+
+ // First try to use the next size that will be embeddable in a larger object slot.
+ for (size_t i = 0; i < heaps_count; i++) {
+ attr_index_t capa = capacities[i];
+ if (capa > current_capa) {
+ return capa;
+ }
+ }
+ return capacities[rb_shape_tree.heaps_count - 1];
+}
+
static rb_shape_t *
-rb_shape_alloc_new_child(ID id, rb_shape_t * shape, enum shape_type shape_type)
+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);
+ rb_shape_t *new_shape = rb_shape_alloc(id, shape, shape_type);
+ if (!new_shape) return NULL;
switch (shape_type) {
+ case SHAPE_OBJ_ID:
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));
+ if (UNLIKELY(shape->next_field_index >= shape->capacity)) {
+ RUBY_ASSERT(shape->next_field_index == shape->capacity);
+ new_shape->capacity = shape_grow_capa(shape->capacity);
}
- 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);
+
+ RUBY_ASSERT(new_shape->capacity > shape->next_field_index);
+ new_shape->next_field_index = shape->next_field_index + 1;
+ if (new_shape->next_field_index > ANCESTOR_CACHE_THRESHOLD) {
+ RB_VM_LOCKING() {
+ redblack_cache_ancestors(new_shape);
+ }
}
break;
- case SHAPE_FROZEN:
- new_shape->next_iv_index = shape->next_iv_index;
- break;
- case SHAPE_OBJ_TOO_COMPLEX:
case SHAPE_ROOT:
- case SHAPE_T_OBJECT:
rb_bug("Unreachable");
break;
}
@@ -489,259 +556,266 @@ rb_shape_alloc_new_child(ID id, rb_shape_t * shape, enum shape_type shape_type)
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)
+static rb_shape_t *
+get_next_shape_internal_atomic(rb_shape_t *shape, ID id, enum shape_type shape_type, bool *variation_created, bool new_variations_allowed)
{
rb_shape_t *res = NULL;
- // There should never be outgoing edges from "too complex"
- RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
-
*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;
- }
+ VALUE edges_table;
+
+retry:
+ edges_table = RUBY_ATOMIC_VALUE_LOAD(shape->edges);
+
+ // If the current shape has children
+ if (edges_table) {
+ // Check if it only has one child
+ if (SINGLE_CHILD_P(edges_table)) {
+ rb_shape_t *child = SINGLE_CHILD(edges_table);
+ // 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;
- }
+ }
+ else {
+ // If it has more than one child, do a hash lookup to find it.
+ VALUE lookup_result;
+ if (rb_managed_id_table_lookup(edges_table, id, &lookup_result)) {
+ res = (rb_shape_t *)lookup_result;
}
}
+ }
+
+ // If we didn't find the shape we're looking for and we're allowed more variations we create it.
+ if (!res && new_variations_allowed) {
+ VALUE new_edges = 0;
+
+ rb_shape_t *new_shape = rb_shape_alloc_new_child(id, shape, shape_type);
- // 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);
+ // If we're out of shapes, return NULL
+ if (new_shape) {
+ if (!edges_table) {
+ // If the shape had no edge yet, we can directly set the new child
+ new_edges = TAG_SINGLE_CHILD(new_shape);
}
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);
+ // If the edge was single child we need to allocate a table.
+ if (SINGLE_CHILD_P(edges_table)) {
+ rb_shape_t *old_child = SINGLE_CHILD(edges_table);
+ new_edges = rb_managed_id_table_new(2);
+ rb_managed_id_table_insert(new_edges, old_child->edge_name, (VALUE)old_child);
}
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;
+ new_edges = rb_managed_id_table_dup(edges_table);
}
- res = new_shape;
+ rb_managed_id_table_insert(new_edges, new_shape->edge_name, (VALUE)new_shape);
+ *variation_created = true;
}
+
+ if (edges_table != RUBY_ATOMIC_VALUE_CAS(shape->edges, edges_table, new_edges)) {
+ // Another thread updated the table;
+ goto retry;
+ }
+ RB_OBJ_WRITTEN(shape_tree_obj, Qundef, new_edges);
+ res = new_shape;
+ RB_GC_GUARD(new_edges);
}
}
- RB_VM_LOCK_LEAVE();
return res;
}
-int
-rb_shape_frozen_shape_p(rb_shape_t* shape)
-{
- return SHAPE_FROZEN == (enum shape_type)shape->type;
-}
-
static rb_shape_t *
-remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
+get_next_shape_internal(rb_shape_t *shape, ID id, enum shape_type shape_type, bool *variation_created, bool new_variations_allowed)
{
- if (shape->parent_id == INVALID_SHAPE_ID) {
- // We've hit the top of the shape tree and couldn't find the
- // IV we wanted to remove, so return NULL
- return NULL;
+ if (rb_multi_ractor_p()) {
+ return get_next_shape_internal_atomic(shape, id, shape_type, variation_created, new_variations_allowed);
}
- else {
- if (shape->type == SHAPE_IVAR && shape->edge_name == id) {
- *removed_shape = shape;
-
- 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);
-
- // 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;
- }
- RUBY_ASSERT(new_child->capacity <= shape->capacity);
+ rb_shape_t *res = NULL;
+ *variation_created = false;
- return new_child;
+ VALUE edges_table = shape->edges;
+
+ // If the current shape has children
+ if (edges_table) {
+ // Check if it only has one child
+ if (SINGLE_CHILD_P(edges_table)) {
+ rb_shape_t *child = SINGLE_CHILD(edges_table);
+ // If the one child has a matching edge name, then great,
+ // we found what we want.
+ if (child->edge_name == id) {
+ res = child;
}
- else {
- // We went all the way to the top of the shape tree and couldn't
- // find an IV to remove, so return NULL
- return NULL;
+ }
+ else {
+ // If it has more than one child, do a hash lookup to find it.
+ VALUE lookup_result;
+ if (rb_managed_id_table_lookup(edges_table, id, &lookup_result)) {
+ res = (rb_shape_t *)lookup_result;
}
}
}
-}
-
-bool
-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);
- 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;
- }
+ // 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 COMPLEX_SHAPE.
+ if (!new_variations_allowed || rb_shapes_count() > MAX_SHAPE_ID) {
+ res = NULL;
}
+ else {
+ rb_shape_t *new_shape = rb_shape_alloc_new_child(id, shape, shape_type);
- *removed = ivptr[removed_shape->next_iv_index - 1];
+ if (!edges_table) {
+ // 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(edges_table)) {
+ rb_shape_t *old_child = SINGLE_CHILD(edges_table);
+ VALUE new_edges = rb_managed_id_table_new(2);
+ rb_managed_id_table_insert(new_edges, old_child->edge_name, (VALUE)old_child);
+ RB_OBJ_WRITE(shape_tree_obj, &shape->edges, new_edges);
+ }
- 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));
+ rb_managed_id_table_insert(shape->edges, new_shape->edge_name, (VALUE)new_shape);
+ *variation_created = true;
+ }
- // 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);
+ res = new_shape;
}
-
- rb_shape_set_shape(obj, new_shape);
}
- return true;
+
+ return res;
}
-rb_shape_t *
-rb_shape_transition_shape_frozen(VALUE obj)
+shape_id_t
+rb_shape_transition_object_id(shape_id_t original_shape_id)
{
- rb_shape_t* shape = rb_shape_get_shape(obj);
- RUBY_ASSERT(shape);
- RUBY_ASSERT(RB_OBJ_FROZEN(obj));
+ RUBY_ASSERT(!rb_shape_has_object_id(original_shape_id));
- if (rb_shape_frozen_shape_p(shape) || rb_shape_obj_too_complex(obj)) {
- return shape;
+ bool dont_care;
+ rb_shape_t *shape = get_next_shape_internal(RSHAPE(original_shape_id), id_object_id, SHAPE_OBJ_ID, &dont_care, true);
+ if (!shape) {
+ return rb_shape_layout(original_shape_id) | ROOT_COMPLEX_WITH_OBJ_ID | RSHAPE_FLAGS(original_shape_id);
}
- rb_shape_t* next_shape;
+ RUBY_ASSERT(shape);
+ return SHAPE_ID(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
+}
- if (shape == rb_shape_get_root_shape()) {
- return rb_shape_get_shape_by_id(SPECIAL_CONST_SHAPE_ID);
- }
+shape_id_t
+rb_shape_object_id(shape_id_t original_shape_id)
+{
+ RUBY_ASSERT(rb_shape_has_object_id(original_shape_id));
- bool dont_care;
- next_shape = get_next_shape_internal(shape, (ID)id_frozen, SHAPE_FROZEN, &dont_care, true);
+ rb_shape_t *shape = RSHAPE(original_shape_id);
+ while (shape->type != SHAPE_OBJ_ID) {
+ if (UNLIKELY(shape->parent_offset == INVALID_SHAPE_ID)) {
+ rb_bug("Missing object_id in shape tree");
+ }
+ shape = RSHAPE(shape->parent_offset);
+ }
- RUBY_ASSERT(next_shape);
- return next_shape;
+ return SHAPE_ID(shape, original_shape_id) | SHAPE_ID_FL_HAS_OBJECT_ID;
}
/*
* This function is used for assertions where we don't want to increment
* max_iv_count
*/
-rb_shape_t *
-rb_shape_get_next_iv_shape(rb_shape_t* shape, ID id)
+static inline rb_shape_t *
+shape_get_next_iv_shape(rb_shape_t *shape, ID id)
{
RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
bool dont_care;
return get_next_shape_internal(shape, id, SHAPE_IVAR, &dont_care, true);
}
+shape_id_t
+rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id)
+{
+ rb_shape_t *shape = RSHAPE(shape_id);
+ rb_shape_t *next_shape = shape_get_next_iv_shape(shape, id);
+ if (!next_shape) {
+ return INVALID_SHAPE_ID;
+ }
+ return SHAPE_OFFSET(next_shape);
+}
+
+static bool
+shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+{
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
+ if (shape->edge_name == id) {
+ enum shape_type shape_type;
+ shape_type = (enum shape_type)shape->type;
+
+ switch (shape_type) {
+ case SHAPE_IVAR:
+ RUBY_ASSERT(shape->next_field_index > 0);
+ *value = shape->next_field_index - 1;
+ return true;
+ case SHAPE_ROOT:
+ return false;
+ case SHAPE_OBJ_ID:
+ rb_bug("Ivar should not exist on transition");
+ }
+ }
+
+ shape = RSHAPE(shape->parent_offset);
+ }
+
+ return false;
+}
+
static inline rb_shape_t *
-shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
+shape_get_next(rb_shape_t *shape, enum shape_type shape_type, VALUE klass, ID id, bool emit_warnings)
{
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)) {
+ if (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;
-
- if (BUILTIN_TYPE(obj) == T_OBJECT) {
- VALUE klass = rb_obj_class(obj);
- allow_new_shape = RCLASS_EXT(klass)->variation_count < SHAPE_MAX_VARIATIONS;
+ RUBY_ASSERT(rb_shape_tree.max_capacity > 0);
+ if (UNLIKELY(shape->next_field_index >= rb_shape_tree.max_capacity)) {
+ return NULL;
}
+ bool allow_new_shape = RCLASS_VARIATION_COUNT(klass) < SHAPE_MAX_VARIATIONS;
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_type, &variation_created, allow_new_shape);
+
+ if (!new_shape) {
+ // We could create a new variation, transitioning to COMPLEX.
+ return NULL;
+ }
// Check if we should update max_iv_count on the object's class
- if (BUILTIN_TYPE(obj) == T_OBJECT) {
- VALUE klass = rb_obj_class(obj);
- if (new_shape->next_iv_index > RCLASS_EXT(klass)->max_iv_count) {
- RCLASS_EXT(klass)->max_iv_count = new_shape->next_iv_index;
- }
-
- 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
- );
- }
+ if (new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass) && !RCLASS_EXPECT_NO_IVAR(klass)) {
+ RCLASS_SET_MAX_IV_COUNT(klass, new_shape->next_field_index);
+ }
+
+ if (variation_created) {
+ RCLASS_VARIATION_COUNT(klass)++;
+
+ if (emit_warnings && rb_warning_category_enabled_p(RB_WARN_CATEGORY_PERFORMANCE)) {
+ if (RCLASS_VARIATION_COUNT(klass) >= 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
+ );
}
}
}
@@ -749,16 +823,122 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
return new_shape;
}
-rb_shape_t *
-rb_shape_get_next(rb_shape_t *shape, VALUE obj, ID id)
+static VALUE
+obj_get_owner_class(VALUE obj)
{
- return shape_get_next(shape, obj, id, true);
+ VALUE klass;
+ if (IMEMO_TYPE_P(obj, imemo_fields)) {
+ VALUE owner = rb_imemo_fields_owner(obj);
+ switch (BUILTIN_TYPE(owner)) {
+ case T_CLASS:
+ case T_MODULE:
+ klass = rb_singleton_class(owner);
+ break;
+ default:
+ klass = rb_obj_class(owner);
+ break;
+ }
+ }
+ else {
+ klass = rb_obj_class(obj);
+ }
+ return klass;
}
-rb_shape_t *
-rb_shape_get_next_no_warnings(rb_shape_t *shape, VALUE obj, ID id)
+static rb_shape_t *
+remove_shape_recursive(VALUE obj, rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
{
- return shape_get_next(shape, obj, id, false);
+ if (shape->parent_offset == INVALID_SHAPE_ID) {
+ // We've hit the top of the shape tree and couldn't find the
+ // IV we wanted to remove, so return NULL
+ *removed_shape = NULL;
+ return NULL;
+ }
+ else {
+ if (shape->type == SHAPE_IVAR && shape->edge_name == id) {
+ *removed_shape = shape;
+
+ return RSHAPE(shape->parent_offset);
+ }
+ else {
+ // This isn't the IV we want to remove, keep walking up.
+ rb_shape_t *new_parent = remove_shape_recursive(obj, RSHAPE(shape->parent_offset), id, removed_shape);
+
+ // We found a new parent. Create a child of the new parent that
+ // has the same attributes as this shape.
+ if (new_parent) {
+ VALUE klass = obj_get_owner_class(obj);
+ rb_shape_t *new_child = shape_get_next(new_parent, shape->type, klass, shape->edge_name, true);
+ RUBY_ASSERT(!new_child || new_child->capacity <= shape->capacity);
+ return new_child;
+ }
+ else {
+ // We went all the way to the top of the shape tree and couldn't
+ // find an IV to remove so return NULL.
+ return NULL;
+ }
+ }
+ }
+}
+
+shape_id_t
+rb_obj_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id)
+{
+ shape_id_t original_shape_id = RBASIC_SHAPE_ID(obj);
+ RUBY_ASSERT(!rb_shape_frozen_p(original_shape_id));
+
+ if (rb_shape_complex_p(original_shape_id)) {
+ return original_shape_id;
+ }
+
+ rb_shape_t *removed_shape = NULL;
+ rb_shape_t *new_shape = remove_shape_recursive(obj, RSHAPE(original_shape_id), id, &removed_shape);
+
+ if (removed_shape) {
+ *removed_shape_id = SHAPE_OFFSET(removed_shape);
+ }
+
+ if (new_shape) {
+ return SHAPE_ID(new_shape, original_shape_id);
+ }
+ else if (removed_shape) {
+ // We found the shape to remove, but couldn't create a new variation.
+ // We must transition to COMPLEX.
+ shape_id_t next_shape_id = rb_shape_transition_complex(original_shape_id);
+ RUBY_ASSERT(rb_shape_has_object_id(next_shape_id) == rb_shape_has_object_id(original_shape_id));
+ return next_shape_id;
+ }
+ return original_shape_id;
+}
+
+shape_id_t
+rb_obj_shape_transition_add_ivar(VALUE obj, ID id)
+{
+ shape_id_t original_shape_id = RBASIC_SHAPE_ID(obj);
+ RUBY_ASSERT(!rb_shape_frozen_p(original_shape_id));
+
+ VALUE klass = obj_get_owner_class(obj);
+ rb_shape_t *next_shape = shape_get_next(RSHAPE(original_shape_id), SHAPE_IVAR, klass, id, true);
+ if (next_shape) {
+ return SHAPE_ID(next_shape, original_shape_id);
+ }
+ else {
+ return rb_shape_transition_complex(original_shape_id);
+ }
+}
+
+shape_id_t
+rb_shape_transition_add_ivar_no_warnings(shape_id_t original_shape_id, ID id, VALUE klass)
+{
+ RUBY_ASSERT(!rb_shape_frozen_p(original_shape_id));
+
+ rb_shape_t *next_shape = shape_get_next(RSHAPE(original_shape_id), SHAPE_IVAR, klass, id, false);
+ if (next_shape) {
+ return SHAPE_ID(next_shape, original_shape_id);
+ }
+ else {
+ return rb_shape_transition_complex(original_shape_id);
+ }
}
// Same as rb_shape_get_iv_index, but uses a provided valid shape id and index
@@ -767,44 +947,44 @@ bool
rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint)
{
attr_index_t index_hint = *value;
- rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
- rb_shape_t *initial_shape = shape;
if (*shape_id_hint == INVALID_SHAPE_ID) {
*shape_id_hint = shape_id;
- return rb_shape_get_iv_index(shape, id, value);
+ return rb_shape_get_iv_index(shape_id, id, value);
}
- rb_shape_t * shape_hint = rb_shape_get_shape_by_id(*shape_id_hint);
+ rb_shape_t *shape = RSHAPE(shape_id);
+ rb_shape_t *initial_shape = shape;
+ rb_shape_t *shape_hint = RSHAPE(*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) {
+ if (shape->ancestor_index && shape->next_field_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);
+ while (depth > 0 && shape->next_field_index > index_hint) {
+ while (shape_hint->next_field_index > shape->next_field_index) {
+ shape_hint = RSHAPE(shape_hint->parent_offset);
}
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);
+ *shape_id_hint = SHAPE_OFFSET(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);
+ *value = shape->next_field_index - 1;
+ *shape_id_hint = SHAPE_OFFSET(shape);
return true;
}
- shape = rb_shape_get_parent(shape);
+ shape = RSHAPE(shape->parent_offset);
depth--;
}
@@ -814,87 +994,78 @@ rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value,
shape = initial_shape;
}
*shape_id_hint = shape_id;
- return rb_shape_get_iv_index(shape, id, value);
+ return shape_get_iv_index(shape, id, value);
}
static bool
-shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+shape_cache_find_ivar(rb_shape_t *shape, ID id, rb_shape_t **ivar_shape)
{
- while (shape->parent_id != INVALID_SHAPE_ID) {
- if (shape->edge_name == id) {
- enum shape_type shape_type;
- shape_type = (enum shape_type)shape->type;
+ if (shape->ancestor_index && shape->next_field_index >= ANCESTOR_CACHE_THRESHOLD) {
+ redblack_node_t *node = redblack_find(shape->ancestor_index, id);
+ if (node) {
+ *ivar_shape = redblack_value(node);
- switch (shape_type) {
- case SHAPE_IVAR:
- RUBY_ASSERT(shape->next_iv_index > 0);
- *value = shape->next_iv_index - 1;
- return true;
- case SHAPE_ROOT:
- case SHAPE_T_OBJECT:
- return false;
- case SHAPE_OBJ_TOO_COMPLEX:
- case SHAPE_FROZEN:
- rb_bug("Ivar should not exist on transition");
- }
+ return true;
}
-
- 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)
+shape_find_ivar(rb_shape_t *shape, ID id, rb_shape_t **ivar_shape)
{
- 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;
-
-#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
-
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
+ if (shape->edge_name == id) {
+ RUBY_ASSERT(shape->type == SHAPE_IVAR);
+ *ivar_shape = shape;
return true;
}
- /* 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));
+ shape = RSHAPE(shape->parent_offset);
}
return false;
}
bool
-rb_shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+rb_shape_find_ivar(shape_id_t current_shape_id, ID id, shape_id_t *ivar_shape_id)
{
- // 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);
+ RUBY_ASSERT(!rb_shape_complex_p(current_shape_id));
+
+ rb_shape_t *shape = RSHAPE(current_shape_id);
+ rb_shape_t *ivar_shape;
- if (!shape_cache_get_iv_index(shape, id, value)) {
+ if (!shape_cache_find_ivar(shape, id, &ivar_shape)) {
// If it wasn't in the ancestor cache, then don't do a linear search
- if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
+ if (shape->ancestor_index && shape->next_field_index >= ANCESTOR_CACHE_THRESHOLD) {
return false;
}
else {
- return shape_get_iv_index(shape, id, value);
+ if (!shape_find_ivar(shape, id, &ivar_shape)) {
+ return false;
+ }
}
}
+ *ivar_shape_id = SHAPE_ID(ivar_shape, current_shape_id);
+
return true;
}
-void
-rb_shape_set_shape(VALUE obj, rb_shape_t* shape)
+bool
+rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value)
{
- rb_shape_set_shape_id(obj, rb_shape_id(shape));
+ // 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_complex_p(shape_id));
+
+ shape_id_t ivar_shape_id;
+ if (rb_shape_find_ivar(shape_id, id, &ivar_shape_id)) {
+ *value = RSHAPE_INDEX(ivar_shape_id);
+ return true;
+ }
+ return false;
}
int32_t
@@ -903,137 +1074,317 @@ rb_shape_id_offset(void)
return sizeof(uintptr_t) - SHAPE_ID_NUM_BITS / sizeof(uintptr_t);
}
-rb_shape_t *
-rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
+// Rebuild a similar shape with the same ivars but without "non-canonical"
+// edges such as SHAPE_OBJ_ID.
+static rb_shape_t *
+shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape)
{
- RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
- rb_shape_t *next_shape = initial_shape;
+ rb_shape_t *midway_shape;
+
+ RUBY_ASSERT(initial_shape->type == SHAPE_ROOT);
if (dest_shape->type != initial_shape->type) {
- next_shape = rb_shape_traverse_from_new_root(initial_shape, rb_shape_get_parent(dest_shape));
- if (!next_shape) {
+ midway_shape = shape_rebuild(initial_shape, RSHAPE(dest_shape->parent_offset));
+ if (UNLIKELY(!midway_shape)) {
return NULL;
}
}
+ else {
+ midway_shape = initial_shape;
+ }
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;
- }
- }
- 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;
- }
- }
+ midway_shape = shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
break;
+ case SHAPE_OBJ_ID:
case SHAPE_ROOT:
- case SHAPE_T_OBJECT:
- break;
- case SHAPE_OBJ_TOO_COMPLEX:
- rb_bug("Unreachable");
break;
}
- return next_shape;
+ return midway_shape;
}
-rb_shape_t *
-rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape)
+// Rebuild `dest_shape_id` starting from `initial_shape_id`, and keep only SHAPE_IVAR transitions.
+// SHAPE_OBJ_ID and frozen status are lost.
+shape_id_t
+rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id)
{
- RUBY_ASSERT(rb_shape_id(initial_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
- RUBY_ASSERT(rb_shape_id(dest_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
+ RUBY_ASSERT(!rb_shape_complex_p(initial_shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(dest_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;
+ shape_id_t next_shape_id;
+ // The shape has a SHAPE_OBJ_ID edge, it needs to be rebuilt.
+ if (dest_shape_id & SHAPE_ID_FL_HAS_OBJECT_ID) {
+ rb_shape_t *next_shape = shape_rebuild(RSHAPE(initial_shape_id), RSHAPE(dest_shape_id));
+ if (next_shape) {
+ next_shape_id = SHAPE_ID(next_shape, initial_shape_id & ~SHAPE_ID_FL_NON_CANONICAL_MASK);
+ }
+ else {
+ return rb_shape_transition_complex(initial_shape_id | (dest_shape_id & ~SHAPE_ID_FL_NON_CANONICAL_MASK));
}
}
else {
- midway_shape = initial_shape;
+ // Happy path, we have nothing to do other than change the flags.
+ next_shape_id = RSHAPE_OFFSET(dest_shape_id) | RSHAPE_FLAGS(initial_shape_id);
}
+ return next_shape_id;
+}
- switch ((enum shape_type)dest_shape->type) {
- case SHAPE_IVAR:
- midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
- break;
- case SHAPE_ROOT:
- case SHAPE_FROZEN:
- case SHAPE_T_OBJECT:
- break;
- case SHAPE_OBJ_TOO_COMPLEX:
- rb_bug("Unreachable");
- break;
+void
+rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE *src_buf, shape_id_t src_shape_id)
+{
+ rb_shape_t *dest_shape = RSHAPE(dest_shape_id);
+ rb_shape_t *src_shape = RSHAPE(src_shape_id);
+
+ if (src_shape->next_field_index == dest_shape->next_field_index) {
+ // Happy path, we can just memcpy the ivptr content
+ MEMCPY(dest_buf, src_buf, VALUE, dest_shape->next_field_index);
+
+ // Fire write barriers
+ for (uint32_t i = 0; i < dest_shape->next_field_index; i++) {
+ RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]);
+ }
}
+ else {
+ while (src_shape->parent_offset != INVALID_SHAPE_ID) {
+ if (src_shape->type == SHAPE_IVAR) {
+ while (dest_shape->edge_name != src_shape->edge_name) {
+ if (UNLIKELY(dest_shape->parent_offset == INVALID_SHAPE_ID)) {
+ rb_bug("Lost field %s", rb_id2name(src_shape->edge_name));
+ }
+ dest_shape = RSHAPE(dest_shape->parent_offset);
+ }
- return midway_shape;
+ RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]);
+ }
+ src_shape = RSHAPE(src_shape->parent_offset);
+ }
+ }
}
-RUBY_FUNC_EXPORTED bool
-rb_shape_obj_too_complex(VALUE obj)
+void
+rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table)
{
- return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
+ // obj is COMPLEX so we can copy its iv_hash
+ st_table *table = st_copy(fields_table);
+ if (rb_shape_has_object_id(src_shape_id)) {
+ st_data_t id = (st_data_t)id_object_id;
+ st_delete(table, &id, NULL);
+ }
+ rb_obj_init_complex(dest, table);
+ rb_gc_writebarrier_remember(dest);
}
size_t
-rb_shape_edges_count(rb_shape_t *shape)
+rb_shape_edges_count(shape_id_t shape_id)
{
+ rb_shape_t *shape = RSHAPE(shape_id);
if (shape->edges) {
if (SINGLE_CHILD_P(shape->edges)) {
return 1;
}
else {
- return rb_id_table_size(shape->edges);
+ return rb_managed_id_table_size(shape->edges);
}
}
return 0;
}
size_t
-rb_shape_memsize(rb_shape_t *shape)
+rb_shape_memsize(shape_id_t shape_id)
{
+ rb_shape_t *shape = RSHAPE(shape_id);
+
size_t memsize = sizeof(rb_shape_t);
if (shape->edges && !SINGLE_CHILD_P(shape->edges)) {
- memsize += rb_id_table_memsize(shape->edges);
+ memsize += rb_managed_id_table_size(shape->edges);
}
return memsize;
}
-#if SHAPE_DEBUG
+bool
+rb_shape_foreach_field(shape_id_t initial_shape_id, rb_shape_foreach_transition_callback func, void *data)
+{
+ RUBY_ASSERT(!rb_shape_complex_p(initial_shape_id));
+
+ rb_shape_t *shape = RSHAPE(initial_shape_id);
+ if (shape->type == SHAPE_ROOT) {
+ return true;
+ }
+
+ shape_id_t parent_offset = SHAPE_ID(RSHAPE(shape->parent_offset), initial_shape_id);
+ if (rb_shape_foreach_field(parent_offset, func, data)) {
+ switch (func(SHAPE_ID(shape, initial_shape_id), data)) {
+ case ST_STOP:
+ return false;
+ case ST_CHECK:
+ case ST_CONTINUE:
+ break;
+ default:
+ rb_bug("unreachable");
+ }
+ }
+ return true;
+}
+
+#if RUBY_DEBUG
/*
- * Exposing Shape to Ruby via RubyVM.debug_shape
+ * Get the layout of this object. The "layout" indicates what strategy
+ * we should use for fetching instance variables from `obj`. It's based
+ * on the C struct layout for each particular object.
+ *
+ * TODO: make Struct have a similar layout to RDATA
*/
+static shape_id_t
+rb_shape_expected_layout(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_OBJECT:
+ return SHAPE_ID_LAYOUT_ROBJECT;
+ case T_CLASS:
+ case T_MODULE:
+ if (FL_TEST_RAW(obj, RCLASS_BOXABLE)) {
+ return SHAPE_ID_LAYOUT_OTHER;
+ }
+ return SHAPE_ID_LAYOUT_RCLASS;
+ case T_DATA:
+ return SHAPE_ID_LAYOUT_RDATA;
+ case T_IMEMO:
+ if (IMEMO_TYPE_P(obj, imemo_fields)) {
+ return SHAPE_ID_LAYOUT_ROBJECT;
+ }
+ return SHAPE_ID_LAYOUT_OTHER;
+ default:
+ return SHAPE_ID_LAYOUT_OTHER;
+ }
+}
-static VALUE
-rb_shape_too_complex(VALUE self)
+bool
+rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id)
{
- rb_shape_t * shape;
- shape = rb_shape_get_shape_by_id(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
- if (rb_shape_id(shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
- return Qtrue;
+ if (shape_id == INVALID_SHAPE_ID) {
+ rb_bug("Can't set INVALID_SHAPE_ID on an object");
+ }
+
+ shape_id_t actual_layout = rb_shape_layout(rb_obj_shape_id(obj));
+ shape_id_t expected_layout = rb_shape_expected_layout(obj);
+ if (actual_layout != expected_layout) {
+ rb_bug("shape_id layout mismatch: expected=%x actual=%x shape_id=%u obj=%s",
+ expected_layout, actual_layout, shape_id, rb_obj_info(obj));
+ }
+
+ if (shape_id == ROOT_SHAPE_ID) {
+ return true;
+ }
+
+ rb_shape_t *shape = RSHAPE(shape_id);
+
+ bool has_object_id = false;
+ while (shape->parent_offset != INVALID_SHAPE_ID) {
+ if (shape->type == SHAPE_OBJ_ID) {
+ has_object_id = true;
+ break;
+ }
+ shape = RSHAPE(shape->parent_offset);
+ }
+
+ if (rb_shape_has_object_id(shape_id)) {
+ if (!has_object_id) {
+ rb_bug("shape_id claim having obj_id but doesn't shape_id=%u, obj=%s", shape_id, rb_obj_info(obj));
+ }
+ }
+ else {
+ if (has_object_id) {
+ rb_bug("shape_id claim not having obj_id but it does shape_id=%u, obj=%s", shape_id, rb_obj_info(obj));
+ }
+ }
+
+ // Make sure SHAPE_ID_HAS_IVAR_MASK is valid.
+ if (rb_shape_complex_p(shape_id)) {
+ RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
+
+ // Ensure complex object don't appear as embedded
+ if (RB_TYPE_P(obj, T_OBJECT) || IMEMO_TYPE_P(obj, imemo_fields)) {
+ RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP));
+ }
+ }
+ else {
+ attr_index_t ivar_count = RSHAPE_LEN(shape_id);
+ if (has_object_id) {
+ ivar_count--;
+ }
+ if (ivar_count) {
+ RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK);
+ }
+ else {
+ RUBY_ASSERT(!(shape_id & SHAPE_ID_HAS_IVAR_MASK));
+ }
+ }
+
+ uint8_t flags_heap_index = rb_shape_heap_index(shape_id);
+ if (RB_TYPE_P(obj, T_OBJECT)) {
+ RUBY_ASSERT(flags_heap_index > 0);
+ size_t shape_id_slot_size = rb_shape_tree.capacities[flags_heap_index - 1] * sizeof(VALUE) + sizeof(struct RBasic);
+ size_t actual_slot_size = rb_gc_obj_slot_size(obj);
+
+ if (shape_id_slot_size != actual_slot_size) {
+ rb_bug("shape_id heap_index flags mismatch: shape_id_slot_size=%zu, gc_slot_size=%zu\n", shape_id_slot_size, actual_slot_size);
+ }
}
else {
- return Qfalse;
+ if (flags_heap_index) {
+ rb_bug("shape_id indicate heap_index > 0 but object is not T_OBJECT: %s", rb_obj_info(obj));
+ }
+ }
+
+ return true;
+}
+#endif
+
+#if SHAPE_DEBUG
+
+/*
+ * Exposing Shape to Ruby via RubyVM::Shape.of(object)
+ */
+
+static VALUE
+shape_complex(VALUE self)
+{
+ shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
+ return RBOOL(rb_shape_complex_p(shape_id));
+}
+
+static VALUE
+shape_frozen(VALUE self)
+{
+ shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
+ return RBOOL(shape_id & SHAPE_ID_FL_FROZEN);
+}
+
+static VALUE
+shape_has_object_id_p(VALUE self)
+{
+ shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
+ return RBOOL(rb_shape_has_object_id(shape_id));
+}
+
+static VALUE
+shape_layout(VALUE self)
+{
+ shape_id_t shape_id = NUM2UINT(rb_struct_getmember(self, rb_intern("id")));
+
+ switch (rb_shape_layout(shape_id)) {
+ case SHAPE_ID_LAYOUT_ROBJECT:
+ return ID2SYM(rb_intern("robject"));
+ case SHAPE_ID_LAYOUT_RCLASS:
+ return ID2SYM(rb_intern("rclass"));
+ case SHAPE_ID_LAYOUT_RDATA:
+ return ID2SYM(rb_intern("rdata"));
+ case SHAPE_ID_LAYOUT_OTHER:
+ return ID2SYM(rb_intern("other"));
+ default:
+ rb_bug("unknown shape layout: %u", rb_shape_layout(shape_id));
}
}
@@ -1046,21 +1397,23 @@ parse_key(ID key)
return LONG2NUM(key);
}
-static VALUE rb_shape_edge_name(rb_shape_t * shape);
+static VALUE rb_shape_edge_name(rb_shape_t *shape);
static VALUE
-rb_shape_t_to_rb_cShape(rb_shape_t *shape)
+shape_id_t_to_rb_cShape(shape_id_t shape_id)
{
VALUE rb_cShape = rb_const_get(rb_cRubyVM, rb_intern("Shape"));
+ rb_shape_t *shape = RSHAPE(shape_id);
VALUE obj = rb_struct_new(rb_cShape,
- INT2NUM(rb_shape_id(shape)),
- INT2NUM(shape->parent_id),
+ INT2NUM(shape_id),
+ INT2NUM(RSHAPE_OFFSET(shape_id)),
+ INT2NUM(shape->parent_offset),
rb_shape_edge_name(shape),
- INT2NUM(shape->next_iv_index),
- INT2NUM(shape->heap_index),
+ INT2NUM(shape->next_field_index),
+ INT2NUM(rb_shape_heap_index(shape_id)),
INT2NUM(shape->type),
- INT2NUM(shape->capacity));
+ INT2NUM(RSHAPE_CAPACITY(shape_id)));
rb_obj_freeze(obj);
return obj;
}
@@ -1068,26 +1421,26 @@ rb_shape_t_to_rb_cShape(rb_shape_t *shape)
static enum rb_id_table_iterator_result
rb_edges_to_hash(ID key, VALUE value, void *ref)
{
- rb_hash_aset(*(VALUE *)ref, parse_key(key), rb_shape_t_to_rb_cShape((rb_shape_t*)value));
+ rb_hash_aset(*(VALUE *)ref, parse_key(key), shape_id_t_to_rb_cShape(SHAPE_OFFSET((rb_shape_t *)value)));
return ID_TABLE_CONTINUE;
}
static VALUE
rb_shape_edges(VALUE self)
{
- rb_shape_t* shape;
-
- shape = rb_shape_get_shape_by_id(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
+ rb_shape_t *shape = RSHAPE(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
VALUE hash = rb_hash_new();
if (shape->edges) {
if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(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);
+ VALUE edges = shape->edges;
+ rb_managed_id_table_foreach(edges, rb_edges_to_hash, &hash);
+ RB_GC_GUARD(edges);
}
}
@@ -1095,7 +1448,7 @@ rb_shape_edges(VALUE self)
}
static VALUE
-rb_shape_edge_name(rb_shape_t * shape)
+rb_shape_edge_name(rb_shape_t *shape)
{
if (shape->edge_name) {
if (is_instance_id(shape->edge_name)) {
@@ -1109,18 +1462,17 @@ rb_shape_edge_name(rb_shape_t * shape)
static VALUE
rb_shape_export_depth(VALUE self)
{
- rb_shape_t* shape;
- shape = rb_shape_get_shape_by_id(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
- return SIZET2NUM(rb_shape_depth(shape));
+ shape_id_t shape_id = NUM2INT(rb_struct_getmember(self, rb_intern("id")));
+ return SIZET2NUM(rb_shape_depth(shape_id));
}
static VALUE
rb_shape_parent(VALUE self)
{
- rb_shape_t * shape;
- shape = rb_shape_get_shape_by_id(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
- if (shape->parent_id != INVALID_SHAPE_ID) {
- return rb_shape_t_to_rb_cShape(rb_shape_get_parent(shape));
+ rb_shape_t *shape;
+ shape = RSHAPE(NUM2INT(rb_struct_getmember(self, rb_intern("id"))));
+ if (shape->parent_offset != INVALID_SHAPE_ID) {
+ return shape_id_t_to_rb_cShape(shape->parent_offset);
}
else {
return Qnil;
@@ -1130,19 +1482,22 @@ rb_shape_parent(VALUE self)
static VALUE
rb_shape_debug_shape(VALUE self, VALUE obj)
{
- return rb_shape_t_to_rb_cShape(rb_shape_get_shape(obj));
+ if (RB_SPECIAL_CONST_P(obj)) {
+ rb_raise(rb_eArgError, "Can't get shape of special constant");
+ }
+ return shape_id_t_to_rb_cShape(rb_obj_shape_id(obj));
}
static VALUE
rb_shape_root_shape(VALUE self)
{
- return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape());
+ return shape_id_t_to_rb_cShape(ROOT_SHAPE_ID);
}
static VALUE
rb_shape_shapes_available(VALUE self)
{
- return INT2NUM(MAX_SHAPE_ID - (GET_SHAPE_TREE()->next_shape_id - 1));
+ return ULL2NUM(MAX_SHAPE_ID - (rb_shapes_count() - 1));
}
static VALUE
@@ -1150,44 +1505,52 @@ 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;
+ RUBY_ATOMIC_SET(shape_next_id, MAX_SHAPE_ID - offset + 1);
return Qnil;
}
-VALUE rb_obj_shape(rb_shape_t* shape);
+static VALUE
+rb_shape_class_max_iv_count(VALUE self, VALUE klass)
+{
+ return INT2NUM(RCLASS_MAX_IV_COUNT(klass));
+}
+
+static VALUE shape_to_h(rb_shape_t *shape);
static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref)
{
- rb_hash_aset(*(VALUE *)ref, parse_key(key), rb_obj_shape((rb_shape_t*)value));
+ rb_hash_aset(*(VALUE *)ref, parse_key(key), shape_to_h((rb_shape_t *)value));
return ID_TABLE_CONTINUE;
}
-static VALUE edges(struct rb_id_table* edges)
+static VALUE edges(VALUE 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 {
- rb_id_table_foreach(edges, collect_keys_and_values, &hash);
+ if (edges) {
+ if (SINGLE_CHILD_P(edges)) {
+ rb_shape_t *child = SINGLE_CHILD(edges);
+ collect_keys_and_values(child->edge_name, (VALUE)child, &hash);
+ }
+ else {
+ rb_managed_id_table_foreach(edges, collect_keys_and_values, &hash);
+ }
}
return hash;
}
-VALUE
-rb_obj_shape(rb_shape_t* shape)
+static VALUE
+shape_to_h(rb_shape_t *shape)
{
VALUE rb_shape = rb_hash_new();
- rb_hash_aset(rb_shape, ID2SYM(rb_intern("id")), INT2NUM(rb_shape_id(shape)));
+ rb_hash_aset(rb_shape, ID2SYM(rb_intern("id")), INT2NUM(SHAPE_OFFSET(shape)));
rb_hash_aset(rb_shape, ID2SYM(rb_intern("edges")), edges(shape->edges));
if (shape == rb_shape_get_root_shape()) {
- rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(ROOT_SHAPE_ID));
+ rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_offset")), INT2NUM(ROOT_SHAPE_ID));
}
else {
- rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(shape->parent_id));
+ rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_offset")), INT2NUM(shape->parent_offset));
}
rb_hash_aset(rb_shape, ID2SYM(rb_intern("edge_name")), rb_id2str(shape->edge_name));
@@ -1197,17 +1560,17 @@ rb_obj_shape(rb_shape_t* shape)
static VALUE
shape_transition_tree(VALUE self)
{
- return rb_obj_shape(rb_shape_get_root_shape());
+ return shape_to_h(rb_shape_get_root_shape());
}
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 >= rb_shapes_count()) {
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));
+ return shape_id_t_to_rb_cShape(shape_id);
}
#endif
@@ -1218,82 +1581,87 @@ rb_shape_find_by_id(VALUE mod, VALUE id)
void
Init_default_shapes(void)
{
- rb_shape_tree_ptr = xcalloc(1, sizeof(rb_shape_tree_t));
+ size_t *heap_sizes = rb_gc_heap_sizes();
+ size_t heaps_count = 0;
+ while (heap_sizes[heaps_count]) {
+ heaps_count++;
+ }
+
+ if (heaps_count > SHAPE_ID_HEAP_INDEX_MAX) {
+ rb_bug("Init_default_shapes initialized with %zu heaps, only up to %u are supported", heaps_count, SHAPE_ID_HEAP_INDEX_MAX);
+ }
+
+ size_t index;
+ for (index = 0; index < heaps_count; index++) {
+ if (heap_sizes[index] > sizeof(struct RBasic)) {
+ size_t capa = (heap_sizes[index] - sizeof(struct RBasic)) / sizeof(VALUE);
+ RUBY_ASSERT(capa < ATTR_INDEX_NOT_SET);
+ rb_shape_tree.capacities[index] = (attr_index_t)capa;
+ }
+ else {
+ rb_shape_tree.capacities[index] = 0;
+ }
+ }
+ rb_shape_tree.heaps_count = heaps_count;
+ rb_shape_tree.max_capacity = rb_shape_tree.capacities[heaps_count - 1];
#ifdef HAVE_MMAP
size_t shape_list_mmap_size = rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError);
- rb_shape_tree_ptr->shape_list = (rb_shape_t *)mmap(NULL, shape_list_mmap_size,
+ rb_shape_tree.shape_list = (rb_shape_t *)mmap(NULL, shape_list_mmap_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (GET_SHAPE_TREE()->shape_list == MAP_FAILED) {
- GET_SHAPE_TREE()->shape_list = 0;
+ if (rb_shape_tree.shape_list == MAP_FAILED) {
+ rb_shape_tree.shape_list = 0;
}
else {
- ruby_annotate_mmap(rb_shape_tree_ptr->shape_list, shape_list_mmap_size, "Ruby:Init_default_shapes:shape_list");
+ ruby_annotate_mmap(rb_shape_tree.shape_list, shape_list_mmap_size, "Ruby:Init_default_shapes:shape_list");
}
#else
- GET_SHAPE_TREE()->shape_list = xcalloc(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t));
+ rb_shape_tree.shape_list = xcalloc(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t));
#endif
- if (!GET_SHAPE_TREE()->shape_list) {
+ if (!rb_shape_tree.shape_list) {
rb_memerror();
}
- id_frozen = rb_make_internal_id();
- id_t_object = rb_make_internal_id();
+ id_object_id = rb_make_internal_id();
#ifdef HAVE_MMAP
size_t shape_cache_mmap_size = rb_size_mul_or_raise(REDBLACK_CACHE_SIZE, sizeof(redblack_node_t), rb_eRuntimeError);
- rb_shape_tree_ptr->shape_cache = (redblack_node_t *)mmap(NULL, shape_cache_mmap_size,
+ redblack_cache = (redblack_node_t *)mmap(NULL, shape_cache_mmap_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- rb_shape_tree_ptr->cache_size = 0;
+ redblack_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;
+ if (redblack_cache == MAP_FAILED) {
+ redblack_cache = NULL;
+ redblack_cache_size = REDBLACK_CACHE_SIZE;
}
else {
- ruby_annotate_mmap(rb_shape_tree_ptr->shape_cache, shape_cache_mmap_size, "Ruby:Init_default_shapes:shape_cache");
+ ruby_annotate_mmap(redblack_cache, shape_cache_mmap_size, "Ruby:Init_default_shapes:shape_cache");
}
#endif
+ rb_gc_register_address(&shape_tree_obj);
+ shape_tree_obj = TypedData_Wrap_Struct(0, &shape_tree_type, (void *)1);
+
// Root shape
- rb_shape_t *root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
+ rb_shape_t *root = rb_shape_alloc_with_parent_offset(0, INVALID_SHAPE_ID);
root->capacity = 0;
root->type = SHAPE_ROOT;
- root->heap_index = 0;
- GET_SHAPE_TREE()->root_shape = root;
- RUBY_ASSERT(rb_shape_id(GET_SHAPE_TREE()->root_shape) == ROOT_SHAPE_ID);
+ RUBY_ASSERT(SHAPE_OFFSET(root) == ROOT_SHAPE_ID);
+ RUBY_ASSERT(!(SHAPE_OFFSET(root) & SHAPE_ID_HAS_IVAR_MASK));
- bool dont_care;
- // Special const shape
-#if RUBY_DEBUG
- rb_shape_t *special_const_shape =
-#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(rb_shape_frozen_shape_p(special_const_shape));
-
- rb_shape_t *too_complex_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
- too_complex_shape->type = SHAPE_OBJ_TOO_COMPLEX;
- too_complex_shape->heap_index = 0;
- RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
- RUBY_ASSERT(rb_shape_id(too_complex_shape) == OBJ_TOO_COMPLEX_SHAPE_ID);
-
- // Make shapes for T_OBJECT
- size_t *sizes = rb_gc_heap_sizes();
- for (int i = 0; sizes[i] > 0; i++) {
- rb_shape_t *t_object_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
- t_object_shape->type = SHAPE_T_OBJECT;
- t_object_shape->heap_index = i;
- t_object_shape->capacity = (uint32_t)((sizes[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 + FIRST_T_OBJECT_SHAPE_ID));
- }
+ bool dontcare;
+ rb_shape_t *root_with_obj_id = get_next_shape_internal(root, id_object_id, SHAPE_OBJ_ID, &dontcare, true);
+ RUBY_ASSERT(root_with_obj_id);
+ RUBY_ASSERT(SHAPE_OFFSET(root_with_obj_id) == ROOT_SHAPE_WITH_OBJ_ID);
+ RUBY_ASSERT(root_with_obj_id->type == SHAPE_OBJ_ID);
+ RUBY_ASSERT(root_with_obj_id->edge_name == id_object_id);
+ RUBY_ASSERT(root_with_obj_id->next_field_index == 1);
+ RUBY_ASSERT(!(SHAPE_OFFSET(root_with_obj_id) & SHAPE_ID_HAS_IVAR_MASK));
+ (void)root_with_obj_id;
}
void
@@ -1304,9 +1672,10 @@ Init_shape(void)
* :nodoc: */
VALUE rb_cShape = rb_struct_define_under(rb_cRubyVM, "Shape",
"id",
- "parent_id",
+ "offset",
+ "parent_offset",
"edge_name",
- "next_iv_index",
+ "next_field_index",
"heap_index",
"type",
"capacity",
@@ -1315,17 +1684,17 @@ Init_shape(void)
rb_define_method(rb_cShape, "parent", rb_shape_parent, 0);
rb_define_method(rb_cShape, "edges", rb_shape_edges, 0);
rb_define_method(rb_cShape, "depth", rb_shape_export_depth, 0);
- rb_define_method(rb_cShape, "too_complex?", rb_shape_too_complex, 0);
+ rb_define_method(rb_cShape, "complex?", shape_complex, 0);
+ rb_define_method(rb_cShape, "shape_frozen?", shape_frozen, 0);
+ rb_define_method(rb_cShape, "has_object_id?", shape_has_object_id_p, 0);
+ rb_define_method(rb_cShape, "layout", shape_layout, 0);
+
rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT));
rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR));
- rb_define_const(rb_cShape, "SHAPE_T_OBJECT", INT2NUM(SHAPE_T_OBJECT));
- rb_define_const(rb_cShape, "SHAPE_FROZEN", INT2NUM(SHAPE_FROZEN));
rb_define_const(rb_cShape, "SHAPE_ID_NUM_BITS", INT2NUM(SHAPE_ID_NUM_BITS));
rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT));
- 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, "FIRST_T_OBJECT_SHAPE_ID", INT2NUM(FIRST_T_OBJECT_SHAPE_ID));
rb_define_const(rb_cShape, "SHAPE_MAX_VARIATIONS", INT2NUM(SHAPE_MAX_VARIATIONS));
+ rb_define_const(rb_cShape, "SHAPE_MAX_FIELDS", INT2NUM(rb_shape_tree.max_capacity));
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));
@@ -1337,5 +1706,6 @@ Init_shape(void)
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);
+ rb_define_singleton_method(rb_cShape, "class_max_iv_count", rb_shape_class_max_iv_count, 1);
#endif
}
diff --git a/shape.h b/shape.h
index 3fdbc34a39..a319449988 100644
--- a/shape.h
+++ b/shape.h
@@ -2,233 +2,658 @@
#define RUBY_SHAPE_H
#include "internal/gc.h"
+#include "internal/struct.h"
-#if (SIZEOF_UINT64_T <= SIZEOF_VALUE)
-
-#define SIZEOF_SHAPE_T 4
-#define SHAPE_IN_BASIC_FLAGS 1
-typedef uint32_t attr_index_t;
+typedef uint8_t attr_index_t;
typedef uint32_t shape_id_t;
-# define SHAPE_ID_NUM_BITS 32
+#define SHAPE_ID_NUM_BITS 32
+#define SHAPE_ID_OFFSET_NUM_BITS 19
-#else
+STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_BIT);
-#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
+#define SHAPE_BUFFER_SIZE (1 << SHAPE_ID_OFFSET_NUM_BITS)
+#define SHAPE_ID_OFFSET_MASK (SHAPE_BUFFER_SIZE - 1)
-#endif
+#define SHAPE_ID_HEAP_INDEX_BITS 4
+#define SHAPE_ID_HEAP_INDEX_MAX (((attr_index_t)1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
-typedef uint32_t redblack_id_t;
+#define SHAPE_ID_HEAP_INDEX_OFFSET SHAPE_ID_OFFSET_NUM_BITS
+#define SHAPE_ID_FL_USHIFT (SHAPE_ID_OFFSET_NUM_BITS + SHAPE_ID_HEAP_INDEX_BITS)
-#define MAX_IVARS (attr_index_t)(-1)
+// shape_id_t bits:
+// 0-18 SHAPE_ID_OFFSET_MASK
+// index in rb_shape_tree.shape_list. Allow to access `rb_shape_t *`.
+// This is the part that describe how fields are laid out in memory.
+// 19-22 SHAPE_ID_HEAP_INDEX_MASK
+// index in rb_shape_tree.capacities. Allow to access slot size.
+// Currently always 0 except for T_OBJECT.
+// 23 SHAPE_ID_FL_COMPLEX
+// The object is backed by a `st_table`.
+// 24 SHAPE_ID_FL_FROZEN
+// Whether the object is frozen or not.
+// 25 SHAPE_ID_FL_HAS_OBJECT_ID
+// Whether the object has an `SHAPE_OBJ_ID` transition.
+// 26-27 SHAPE_ID_LAYOUT_MASK
+// The object's physical field layout.
-# define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
-# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
+enum shape_id_fl_type {
+#define RBIMPL_SHAPE_ID_FL(n) (1<<(SHAPE_ID_FL_USHIFT+n))
-# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
+ SHAPE_ID_HEAP_INDEX_MASK = ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1) << SHAPE_ID_HEAP_INDEX_OFFSET,
-# define SHAPE_MAX_VARIATIONS 8
+ SHAPE_ID_FL_COMPLEX = RBIMPL_SHAPE_ID_FL(0),
+ SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(1),
+ SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(2),
-# define INVALID_SHAPE_ID SHAPE_MASK
-# define ROOT_SHAPE_ID 0x0
+ // Means IVs are found at an offset from the object's addr, or in a
+ // malloc allocated side table
+ SHAPE_ID_LAYOUT_ROBJECT = 0,
-# define SPECIAL_CONST_SHAPE_ID (ROOT_SHAPE_ID + 1)
-# define OBJ_TOO_COMPLEX_SHAPE_ID (SPECIAL_CONST_SHAPE_ID + 1)
-# define FIRST_T_OBJECT_SHAPE_ID (OBJ_TOO_COMPLEX_SHAPE_ID + 1)
+ // Means this object is a class/module that is NOT RCLASS_BOXABLE, and IV's
+ // are found in the fields_obj found on the rclass struct
+ SHAPE_ID_LAYOUT_RCLASS = RBIMPL_SHAPE_ID_FL(3),
-typedef struct redblack_node redblack_node_t;
+ // Means this object is an RData or RTypedData and IVs are found in the
+ // fields_obj found on the RData/RTypedData struct
+ SHAPE_ID_LAYOUT_RDATA = RBIMPL_SHAPE_ID_FL(4),
-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
- attr_index_t next_iv_index;
- uint32_t capacity; // Total capacity of the object with this shape
- uint8_t type;
- uint8_t heap_index;
- shape_id_t parent_id;
- redblack_node_t * ancestor_index;
-};
+ // Means this is a complicated object: boxable classes, structs, objects
+ // that store IVs on the geniv table
+ SHAPE_ID_LAYOUT_OTHER = SHAPE_ID_LAYOUT_RCLASS | SHAPE_ID_LAYOUT_RDATA,
-typedef struct rb_shape rb_shape_t;
+ SHAPE_ID_LAYOUT_MASK = SHAPE_ID_LAYOUT_OTHER,
+
+ SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID,
+ SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_COMPLEX | SHAPE_ID_LAYOUT_MASK,
+
+#undef RBIMPL_SHAPE_ID_FL
+};
-struct redblack_node {
- ID key;
- rb_shape_t * value;
- redblack_id_t l;
- redblack_id_t r;
+// This mask allows to check if a shape_id contains any ivar.
+// It relies on ROOT_SHAPE_WITH_OBJ_ID==1.
+enum shape_id_mask {
+ SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
};
+// The interpreter doesn't care about frozen status, slot size, or object id, and
+// has its own checks for physical field layout when reading ivars.
+// So we normalize shape_id by clearing these bits to improve cache hits.
+// JITs however might care about some of it.
+#define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK))
+// For write it's the same idea, but here we do care about frozen status.
+#define SHAPE_ID_WRITE_MASK (~(SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK))
+
+typedef uint32_t redblack_id_t;
+
+#define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * CHAR_BIT) - SHAPE_ID_NUM_BITS)
+#define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
+
+#define SHAPE_MAX_VARIATIONS 8
+
+#define INVALID_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
+#define ATTR_INDEX_NOT_SET ((attr_index_t)-1)
+
+#define ROOT_SHAPE_ID 0x0
+#define ROOT_SHAPE_WITH_OBJ_ID 0x1
+#define ROOT_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_COMPLEX)
+#define ROOT_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
+
enum shape_type {
SHAPE_ROOT,
SHAPE_IVAR,
- SHAPE_FROZEN,
- SHAPE_T_OBJECT,
- SHAPE_OBJ_TOO_COMPLEX,
+ SHAPE_OBJ_ID,
+};
+
+struct rb_shape {
+ VALUE edges; // id_table from ID (ivar) to next shape
+ ID edge_name; // ID (ivar) for transition from parent to rb_shape
+ redblack_id_t ancestor_index;
+ shape_id_t parent_offset;
+ attr_index_t next_field_index; // Fields are either ivars or internal properties like `object_id`
+ attr_index_t capacity; // Total capacity of the object with this shape
+ enum shape_type type : 8;
+};
+
+typedef struct rb_shape rb_shape_t;
+
+enum shape_flags {
+ SHAPE_FL_FROZEN = 1 << 0,
+ SHAPE_FL_HAS_OBJECT_ID = 1 << 1,
+ SHAPE_FL_COMPLEX = 1 << 2,
+
+ SHAPE_FL_NON_CANONICAL_MASK = SHAPE_FL_FROZEN | SHAPE_FL_HAS_OBJECT_ID,
};
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;
+ attr_index_t max_capacity;
+ attr_index_t heaps_count;
+ attr_index_t capacities[SHAPE_ID_HEAP_INDEX_MAX];
} 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)
+RUBY_SYMBOL_EXPORT_BEGIN
+RUBY_EXTERN rb_shape_tree_t rb_shape_tree;
+RUBY_SYMBOL_EXPORT_END
+
+size_t rb_shapes_cache_size(void);
+size_t rb_shapes_count(void);
+
+static inline shape_id_t
+RBASIC_SHAPE_ID(VALUE obj)
{
- return rb_shape_tree_ptr;
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
+#if RBASIC_SHAPE_ID_FIELD
+ return (shape_id_t)((RBASIC(obj)->shape_id));
+#else
+ return (shape_id_t)((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT);
+#endif
}
-#define GET_SHAPE_TREE() rb_current_shape_tree()
+// Same as RBASIC_SHAPE_ID but with flags that have no impact
+// on reads removed. e.g. Remove FL_FROZEN.
static inline shape_id_t
-get_shape_id_from_flags(VALUE obj)
+RBASIC_SHAPE_ID_FOR_READ(VALUE obj)
{
- RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
- return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT));
+ return RBASIC_SHAPE_ID(obj) & SHAPE_ID_READ_ONLY_MASK;
}
+#if RUBY_DEBUG
+bool rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id);
+#endif
+
static inline void
-set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
+RBASIC_SET_SHAPE_ID_NO_CHECKS(VALUE obj, shape_id_t shape_id)
{
- // Ractors are occupying the upper 32 bits of flags, but only in debug mode
+#if RBASIC_SHAPE_ID_FIELD
+ RBASIC(obj)->shape_id = (VALUE)shape_id;
+#else
// Object shapes are occupying top bits
RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
+#endif
}
-
-#if SHAPE_IN_BASIC_FLAGS
static inline shape_id_t
-RBASIC_SHAPE_ID(VALUE obj)
+rb_shape_layout(shape_id_t shape_id)
{
- return get_shape_id_from_flags(obj);
+ return shape_id & SHAPE_ID_LAYOUT_MASK;
}
static inline void
RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
- set_shape_id_in_flags(obj, shape_id);
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
+ RUBY_ASSERT(!IMEMO_TYPE_P(obj, imemo_fields) || rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_ROBJECT);
+
+ RBASIC_SET_SHAPE_ID_NO_CHECKS(obj, shape_id);
+
+ RUBY_ASSERT(rb_shape_verify_consistency(obj, shape_id));
}
-#endif
static inline shape_id_t
-ROBJECT_SHAPE_ID(VALUE obj)
+RSHAPE_FLAGS(shape_id_t shape_id)
{
- RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- return get_shape_id_from_flags(obj);
+ return shape_id & SHAPE_ID_FLAGS_MASK;
}
-static inline void
-ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+static inline shape_id_t
+RSHAPE_OFFSET(shape_id_t shape_id)
{
- RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- set_shape_id_in_flags(obj, shape_id);
+ return shape_id & SHAPE_ID_OFFSET_MASK;
+}
+
+static inline rb_shape_t *
+RSHAPE(shape_id_t shape_id)
+{
+ shape_id_t offset = RSHAPE_OFFSET(shape_id);
+ RUBY_ASSERT(offset != INVALID_SHAPE_ID);
+ return &rb_shape_tree.shape_list[offset];
+}
+
+int32_t rb_shape_id_offset(void);
+
+RUBY_FUNC_EXPORTED shape_id_t rb_obj_shape_id(VALUE obj);
+shape_id_t rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id);
+bool rb_shape_get_iv_index(shape_id_t shape_id, 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_find_ivar(shape_id_t shape_id, ID id, shape_id_t *ivar_shape);
+
+typedef int rb_shape_foreach_transition_callback(shape_id_t shape_id, void *data);
+bool rb_shape_foreach_field(shape_id_t shape_id, rb_shape_foreach_transition_callback func, void *data);
+
+shape_id_t rb_shape_transition_add_ivar_no_warnings(shape_id_t shape_id, ID id, VALUE klass);
+
+shape_id_t rb_shape_object_id(shape_id_t original_shape_id);
+shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id);
+void rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE *src_buf, shape_id_t src_shape_id);
+void rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table);
+
+static inline bool
+rb_shape_frozen_p(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_FL_FROZEN;
+}
+
+static inline bool
+rb_shape_complex_p(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_FL_COMPLEX;
+}
+
+static inline bool
+rb_obj_shape_complex_p(VALUE obj)
+{
+ return !RB_SPECIAL_CONST_P(obj) && rb_shape_complex_p(RBASIC_SHAPE_ID(obj));
+}
+
+static inline bool
+rb_shape_has_object_id(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_FL_HAS_OBJECT_ID;
+}
+
+static inline bool
+rb_shape_canonical_p(shape_id_t shape_id)
+{
+ return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK);
}
static inline shape_id_t
-RCLASS_SHAPE_ID(VALUE obj)
+rb_shape_id_with_robject_layout(shape_id_t shape_id)
{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- return get_shape_id_from_flags(obj);
+ return (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_ROBJECT;
}
-static inline void
-RCLASS_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+static inline uint8_t
+rb_shape_heap_index(shape_id_t shape_id)
{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- set_shape_id_in_flags(obj, shape_id);
+ return (uint8_t)((shape_id & SHAPE_ID_HEAP_INDEX_MASK) >> SHAPE_ID_HEAP_INDEX_OFFSET);
}
-rb_shape_t * rb_shape_get_root_shape(void);
-int32_t rb_shape_id_offset(void);
+static inline shape_id_t
+rb_shape_root(size_t heap_id)
+{
+ shape_id_t heap_index = (shape_id_t)(heap_id + 1);
+ shape_id_t heap_flags = heap_index << SHAPE_ID_HEAP_INDEX_OFFSET;
+
+ RUBY_ASSERT((heap_flags & SHAPE_ID_HEAP_INDEX_MASK) == heap_flags);
+ RUBY_ASSERT(rb_shape_heap_index(heap_flags) == heap_index);
-rb_shape_t * rb_shape_get_parent(rb_shape_t * shape);
+ return ROOT_SHAPE_ID | heap_flags;
+}
-RUBY_FUNC_EXPORTED rb_shape_t *rb_shape_get_shape_by_id(shape_id_t shape_id);
-RUBY_FUNC_EXPORTED 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);
-RUBY_FUNC_EXPORTED bool rb_shape_obj_too_complex(VALUE obj);
+static inline shape_id_t
+RSHAPE_PARENT_OFFSET(shape_id_t shape_id)
+{
+ return RSHAPE(shape_id)->parent_offset;
+}
+
+static inline bool
+RSHAPE_DIRECT_CHILD_P(shape_id_t parent_offset, shape_id_t child_id)
+{
+ return RSHAPE_PARENT_OFFSET(child_id) == RSHAPE_OFFSET(parent_offset);
+}
-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);
-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);
+static inline enum shape_type
+RSHAPE_TYPE(shape_id_t shape_id)
+{
+ return RSHAPE(shape_id)->type;
+}
-rb_shape_t * rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape);
+static inline bool
+RSHAPE_TYPE_P(shape_id_t shape_id, enum shape_type type)
+{
+ return RSHAPE_TYPE(shape_id) == type;
+}
+
+static inline attr_index_t
+RSHAPE_EMBEDDED_CAPACITY(shape_id_t shape_id)
+{
+ uint8_t heap_index = rb_shape_heap_index(shape_id);
+ if (heap_index) {
+ return rb_shape_tree.capacities[heap_index - 1];
+ }
+ return 0;
+}
+
+static inline attr_index_t
+RSHAPE_CAPACITY(shape_id_t shape_id)
+{
+ attr_index_t embedded_capacity = RSHAPE_EMBEDDED_CAPACITY(shape_id);
+
+ if (embedded_capacity > RSHAPE(shape_id)->capacity) {
+ return embedded_capacity;
+ }
+ else {
+ return RSHAPE(shape_id)->capacity;
+ }
+}
+
+static inline attr_index_t
+RSHAPE_LEN(shape_id_t shape_id)
+{
+ return RSHAPE(shape_id)->next_field_index;
+}
+
+static inline attr_index_t
+RSHAPE_INDEX(shape_id_t shape_id)
+{
+ RUBY_ASSERT(RSHAPE_LEN(shape_id) > 0);
+ return RSHAPE_LEN(shape_id) - 1;
+}
+
+static inline ID
+RSHAPE_EDGE_NAME(shape_id_t shape_id)
+{
+ return RSHAPE(shape_id)->edge_name;
+}
static inline uint32_t
-ROBJECT_IV_CAPACITY(VALUE obj)
+ROBJECT_FIELDS_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));
- return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->capacity;
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
+ return RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj));
}
static inline st_table *
-ROBJECT_IV_HASH(VALUE obj)
+ROBJECT_FIELDS_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(rb_obj_shape_complex_p(obj));
+ RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP));
+
+ return ROBJECT(obj)->as.hash;
}
static inline void
-ROBJECT_SET_IV_HASH(VALUE obj, const st_table *tbl)
+ROBJECT_SET_FIELDS_HASH(VALUE obj, st_table *tbl)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
- ROBJECT(obj)->as.heap.ivptr = (VALUE *)tbl;
+ RUBY_ASSERT(rb_obj_shape_complex_p(obj));
+ RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP));
+
+ ROBJECT(obj)->as.hash = tbl;
+}
+
+static inline uint32_t
+ROBJECT_FIELDS_COUNT_COMPLEX(VALUE obj)
+{
+ return (uint32_t)rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
}
-size_t rb_id_table_size(const struct rb_id_table *tbl);
+static inline uint32_t
+ROBJECT_FIELDS_COUNT_NOT_COMPLEX(VALUE obj)
+{
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
+ return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
+}
static inline uint32_t
-ROBJECT_IV_COUNT(VALUE obj)
+ROBJECT_FIELDS_COUNT(VALUE obj)
{
- if (rb_shape_obj_too_complex(obj)) {
- return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
+ if (rb_obj_shape_complex_p(obj)) {
+ return ROBJECT_FIELDS_COUNT_COMPLEX(obj);
}
else {
- RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
- return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_iv_index;
+ return ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
}
}
static inline uint32_t
-RBASIC_IV_COUNT(VALUE obj)
+RBASIC_FIELDS_COUNT(VALUE obj)
+{
+ return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
+}
+
+static inline bool
+rb_obj_shape_has_id(VALUE obj)
+{
+ return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
+}
+
+static inline bool
+rb_shape_has_ivars(shape_id_t shape_id)
+{
+ return shape_id & SHAPE_ID_HAS_IVAR_MASK;
+}
+
+static inline bool
+rb_obj_shape_has_ivars(VALUE obj)
+{
+ return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj));
+}
+
+static inline bool
+rb_shape_has_fields(shape_id_t shape_id)
+{
+ return shape_id & (SHAPE_ID_OFFSET_MASK | SHAPE_ID_FL_COMPLEX);
+}
+
+static inline bool
+rb_obj_shape_has_fields(VALUE obj)
{
- return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
+ return rb_shape_has_fields(RBASIC_SHAPE_ID(obj));
}
-rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
+static inline bool
+rb_obj_gen_fields_p(VALUE obj)
+{
+ switch (TYPE(obj)) {
+ case T_NONE:
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ case T_IMEMO:
+ return false;
+ default:
+ break;
+ }
+ return rb_obj_shape_has_fields(obj);
+}
+
+static inline bool
+rb_obj_using_gen_fields_table_p(VALUE obj)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ return false;
+
+ case T_STRUCT:
+ if (!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) return false;
+ break;
+
+ default:
+ break;
+ }
-bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
+ return rb_obj_gen_fields_p(obj);
+}
-VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
+static inline shape_id_t
+rb_shape_transition_frozen(shape_id_t shape_id)
+{
+ return shape_id | SHAPE_ID_FL_FROZEN;
+}
+
+static inline shape_id_t
+rb_shape_transition_complex(shape_id_t shape_id)
+{
+ shape_id_t next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_SHAPE_ID;
+
+ if (rb_shape_has_object_id(shape_id)) {
+ next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_WITH_OBJ_ID;
+ }
+
+ uint8_t heap_index = rb_shape_heap_index(shape_id);
+ if (heap_index) {
+ next_shape_id |= rb_shape_root(heap_index - 1);
+ }
+
+ RUBY_ASSERT(rb_shape_has_object_id(shape_id) == rb_shape_has_object_id(next_shape_id));
+
+ return next_shape_id;
+}
+
+static inline shape_id_t
+rb_shape_transition_offset(shape_id_t shape_id, shape_id_t offset)
+{
+ offset = RSHAPE_OFFSET(offset);
+ RUBY_ASSERT(RSHAPE_OFFSET(shape_id) == offset || RSHAPE_DIRECT_CHILD_P(shape_id, offset));
+ return RSHAPE_FLAGS(shape_id) | offset;
+}
+
+static inline shape_id_t
+rb_shape_transition_heap(shape_id_t shape_id, size_t heap_index)
+{
+ return (shape_id & (~SHAPE_ID_HEAP_INDEX_MASK)) | rb_shape_root(heap_index);
+}
+
+shape_id_t rb_shape_transition_object_id(shape_id_t shape_id);
+
+static inline shape_id_t
+rb_obj_shape_transition_frozen(VALUE obj)
+{
+ RUBY_ASSERT(RB_OBJ_FROZEN(obj));
+ return rb_shape_transition_frozen(RBASIC_SHAPE_ID(obj));
+}
+
+static inline shape_id_t
+rb_obj_shape_transition_complex(VALUE obj)
+{
+ return rb_shape_transition_complex(RBASIC_SHAPE_ID(obj));
+}
+
+static inline shape_id_t
+rb_obj_shape_transition_heap(VALUE obj, size_t heap_index)
+{
+ return rb_shape_transition_heap(RBASIC_SHAPE_ID(obj), heap_index);
+}
+
+static inline shape_id_t
+rb_obj_shape_transition_object_id(VALUE obj)
+{
+ return rb_shape_transition_object_id(RBASIC_SHAPE_ID(obj));
+}
+
+shape_id_t rb_obj_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id);
+shape_id_t rb_obj_shape_transition_add_ivar(VALUE obj, ID id);
// For ext/objspace
RUBY_SYMBOL_EXPORT_BEGIN
-typedef void each_shape_callback(rb_shape_t * shape, void *data);
-void rb_shape_each_shape(each_shape_callback callback, void *data);
-size_t rb_shape_memsize(rb_shape_t *shape);
-size_t rb_shape_edges_count(rb_shape_t *shape);
-size_t rb_shape_depth(rb_shape_t *shape);
-shape_id_t rb_shape_id(rb_shape_t * shape);
+typedef void each_shape_callback(shape_id_t shape_id, void *data);
+void rb_shape_each_shape_id(each_shape_callback callback, void *data);
+size_t rb_shape_memsize(shape_id_t shape);
+size_t rb_shape_edges_count(shape_id_t shape_id);
+size_t rb_shape_depth(shape_id_t shape_id);
RUBY_SYMBOL_EXPORT_END
+// Inline cache helpers
+
+typedef struct {
+ attr_index_t index;
+ shape_id_t shape_offset;
+} rb_getivar_cache;
+
+union rb_getivar_cache {
+ uint64_t pack;
+ rb_getivar_cache unpack;
+};
+STATIC_ASSERT(rb_getivar_cache_size, sizeof(union rb_getivar_cache) <= sizeof(uint64_t));
+
+#define IVAR_CACHE_INIT ((uint64_t)-1)
+#define ATTR_INDEX_T_NUM_BITS (sizeof(attr_index_t) * CHAR_BIT)
+
+static inline rb_getivar_cache
+rb_getivar_cache_unpack(uint64_t packed)
+{
+ union rb_getivar_cache cache = {
+ .pack = packed,
+ };
+
+ // Because caches may initialized with all bits set (IVAR_CACHE_INIT), and `shape_offset` if 32bits,
+ // we need to remove any potential extra bits set in the "padding".
+ cache.unpack.shape_offset &= SHAPE_ID_OFFSET_MASK;
+ return cache.unpack;
+}
+
+static inline uint64_t
+rb_getivar_cache_pack(shape_id_t shape_offset, attr_index_t index)
+{
+ RUBY_ASSERT(shape_offset == RSHAPE_OFFSET(shape_offset));
+ RUBY_ASSERT(shape_offset != INVALID_SHAPE_ID);
+
+ union rb_getivar_cache cache = {
+ .unpack = {
+ .shape_offset = shape_offset,
+ .index = index,
+ },
+ };
+ return cache.pack;
+}
+
+typedef struct {
+ attr_index_t index;
+ shape_id_t source_shape_offset;
+ shape_id_t dest_shape_offset;
+} rb_setivar_cache;
+
+static inline rb_setivar_cache
+rb_setivar_cache_unpack(uint64_t packed)
+{
+ rb_setivar_cache cache = {
+ .index = (attr_index_t)packed,
+ .source_shape_offset = RSHAPE_OFFSET((shape_id_t)(packed >> ATTR_INDEX_T_NUM_BITS)),
+ .dest_shape_offset = RSHAPE_OFFSET((shape_id_t)(packed >> (ATTR_INDEX_T_NUM_BITS + SHAPE_ID_OFFSET_NUM_BITS))),
+ };
+ return cache;
+}
+
+static inline uint64_t
+rb_setivar_cache_pack(shape_id_t shape_offset, shape_id_t dest_shape_offset, attr_index_t index)
+{
+ RUBY_ASSERT(shape_offset == RSHAPE_OFFSET(shape_offset));
+ RUBY_ASSERT(dest_shape_offset == RSHAPE_OFFSET(dest_shape_offset));
+ RUBY_ASSERT(shape_offset == dest_shape_offset || RSHAPE_DIRECT_CHILD_P(shape_offset, dest_shape_offset));
+
+ uint64_t packed_cache = (uint64_t)dest_shape_offset << (ATTR_INDEX_T_NUM_BITS + SHAPE_ID_OFFSET_NUM_BITS);
+ packed_cache |= (uint64_t)shape_offset << ATTR_INDEX_T_NUM_BITS;
+ packed_cache |= (uint64_t)index;
+ return packed_cache;
+}
+
+
+ALWAYS_INLINE(static shape_id_t rb_setivar_cache_revalidate(shape_id_t shape_id, rb_setivar_cache cache));
+static shape_id_t
+rb_setivar_cache_revalidate(shape_id_t shape_id, rb_setivar_cache cache)
+{
+ RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
+ RUBY_ASSERT(cache.dest_shape_offset == INVALID_SHAPE_ID || cache.dest_shape_offset == RSHAPE_OFFSET(cache.dest_shape_offset));
+
+ shape_id_t normalized_shape_id = shape_id & SHAPE_ID_WRITE_MASK;
+ if (UNLIKELY(normalized_shape_id != cache.source_shape_offset)) {
+ return INVALID_SHAPE_ID;
+ }
+
+ if (UNLIKELY(cache.index >= RSHAPE_CAPACITY(shape_id))) {
+ // That's still a hit in term of layout, but the object will need to be resized,
+ // so unfortunately we'll have to go through the slow path regardless...
+ return INVALID_SHAPE_ID;
+ }
+
+ // Cache hit case
+ RUBY_ASSERT(cache.source_shape_offset == cache.dest_shape_offset || RSHAPE_DIRECT_CHILD_P(shape_id, cache.dest_shape_offset));
+ RUBY_ASSERT(cache.index < RSHAPE_CAPACITY(shape_id));
+ RUBY_ASSERT(!rb_shape_frozen_p(shape_id));
+ RUBY_ASSERT(!rb_shape_complex_p(shape_id));
+
+ // We use the cached offset, but combined with the current shape flags.
+ return rb_shape_transition_offset(shape_id, cache.dest_shape_offset);
+}
+
#endif
diff --git a/signal.c b/signal.c
index 6c2a757a98..f37aaf971a 100644
--- a/signal.c
+++ b/signal.c
@@ -45,6 +45,7 @@
#include "ruby_atomic.h"
#include "vm_core.h"
#include "ractor_core.h"
+#include "ruby/internal/attr/nonstring.h"
#ifdef NEED_RUBY_ATOMIC_OPS
rb_atomic_t
@@ -402,7 +403,6 @@ interrupt_init(int argc, VALUE *argv, VALUE self)
return rb_call_super(2, args);
}
-void rb_malloc_info_show_results(void); /* gc.c */
#if defined(USE_SIGALTSTACK) || defined(_WIN32)
static void reset_sigmask(int sig);
#endif
@@ -413,7 +413,6 @@ ruby_default_signal(int sig)
#if USE_DEBUG_COUNTER
rb_debug_counter_show_results("killed by signal.");
#endif
- rb_malloc_info_show_results();
signal(sig, SIG_DFL);
#if defined(USE_SIGALTSTACK) || defined(_WIN32)
@@ -665,6 +664,10 @@ ruby_nativethread_signal(int signum, sighandler_t handler)
#endif
#endif
+#if !defined(POSIX_SIGNAL) && !defined(SIG_GET)
+static rb_nativethread_lock_t sig_check_lock;
+#endif
+
static int
signal_ignored(int sig)
{
@@ -674,9 +677,16 @@ signal_ignored(int sig)
(void)VALGRIND_MAKE_MEM_DEFINED(&old, sizeof(old));
if (sigaction(sig, NULL, &old) < 0) return FALSE;
func = old.sa_handler;
+#elif defined SIG_GET
+ // https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-action-constants
+ // SIG_GET: Returns the current value of the signal.
+ func = signal(sig, SIG_GET);
#else
- sighandler_t old = signal(sig, SIG_DFL);
+ sighandler_t old;
+ rb_native_mutex_lock(&sig_check_lock);
+ old = signal(sig, SIG_DFL);
signal(sig, old);
+ rb_native_mutex_unlock(&sig_check_lock);
func = old;
#endif
if (func == SIG_IGN) return 1;
@@ -708,7 +718,7 @@ sighandler(int sig)
int
rb_signal_buff_size(void)
{
- return signal_buff.size;
+ return RUBY_ATOMIC_LOAD(signal_buff.size);
}
static void
@@ -736,7 +746,7 @@ rb_get_next_signal(void)
{
int i, sig = 0;
- if (signal_buff.size != 0) {
+ if (rb_signal_buff_size() != 0) {
for (i=1; i<RUBY_NSIG; i++) {
if (signal_buff.cnt[i] > 0) {
ATOMIC_DEC(signal_buff.cnt[i]);
@@ -760,7 +770,6 @@ static const char *received_signal;
#endif
#if defined(USE_SIGALTSTACK) || defined(_WIN32)
-NORETURN(void rb_ec_stack_overflow(rb_execution_context_t *ec, int crit));
# if defined __HAIKU__
# define USE_UCONTEXT_REG 1
# elif !(defined(HAVE_UCONTEXT_H) && (defined __i386__ || defined __x86_64__ || defined __amd64__))
@@ -846,13 +855,17 @@ check_stack_overflow(int sig, const uintptr_t addr, const ucontext_t *ctx)
if (sp_page == fault_page || sp_page == fault_page + 1 ||
(sp_page <= fault_page && fault_page <= bp_page)) {
rb_execution_context_t *ec = GET_EC();
- int crit = FALSE;
+ ruby_stack_overflow_critical_level crit = rb_stack_overflow_signal;
int uplevel = roomof(pagesize, sizeof(*ec->tag)) / 2; /* XXX: heuristic */
while ((uintptr_t)ec->tag->buf / pagesize <= fault_page + 1) {
/* drop the last tag if it is close to the fault,
* otherwise it can cause stack overflow again at the same
* place. */
- if ((crit = (!ec->tag->prev || !--uplevel)) != FALSE) break;
+ if (!ec->tag->prev || !--uplevel) {
+ crit = rb_stack_overflow_fatal;
+ break;
+ }
+ rb_vm_tag_jmpbuf_deinit(&ec->tag->buf);
ec->tag = ec->tag->prev;
}
reset_sigmask(sig);
@@ -864,10 +877,12 @@ static void
check_stack_overflow(int sig, const void *addr)
{
int ruby_stack_overflowed_p(const rb_thread_t *, const void *);
- rb_thread_t *th = GET_THREAD();
+ rb_execution_context_t *ec = rb_current_execution_context(false);
+ if (!ec) return;
+ rb_thread_t *th = rb_ec_thread_ptr(ec);
if (ruby_stack_overflowed_p(th, addr)) {
reset_sigmask(sig);
- rb_ec_stack_overflow(th->ec, FALSE);
+ rb_ec_stack_overflow(th->ec, 1);
}
}
# endif
@@ -934,6 +949,20 @@ sigsegv(int sig SIGINFO_ARG)
}
#endif
+#ifdef SIGABRT
+
+static sighandler_t default_sigabrt_handler;
+NORETURN(static ruby_sigaction_t sigabrt);
+
+static void
+sigabrt(int sig SIGINFO_ARG)
+{
+ check_reserved_signal("ABRT");
+ CHECK_STACK_OVERFLOW();
+ rb_bug_for_fatal_signal(default_sigabrt_handler, sig, SIGINFO_CTX, "Aborted" MESSAGE_FAULT_ADDRESS);
+}
+#endif
+
#ifdef SIGILL
static sighandler_t default_sigill_handler;
@@ -975,7 +1004,7 @@ check_reserved_signal_(const char *name, size_t name_len, int signo)
if (prev) {
ssize_t RB_UNUSED_VAR(err);
static const int stderr_fd = 2;
-#define NOZ(name, str) name[sizeof(str)-1] = str
+#define NOZ(name, str) RBIMPL_ATTR_NONSTRING() name[sizeof(str)-1] = str
static const char NOZ(msg1, " received in ");
static const char NOZ(msg2, " handler\n");
@@ -991,8 +1020,20 @@ check_reserved_signal_(const char *name, size_t name_len, int signo)
#if __has_feature(address_sanitizer) || \
__has_feature(memory_sanitizer) || \
defined(HAVE_VALGRIND_MEMCHECK_H)
- ruby_posix_signal(signo, SIG_DFL);
+# define SANITIZING true
+#else
+# define SANITIZING false
+#endif
+
+#ifdef SIGABRT
+// Avoid infinite loop when already aborting
+# define RECURSIVE (signo == SIGABRT)
+#else
+# define RECURSIVE false
#endif
+ if (SANITIZING || RECURSIVE) ruby_signal(signo, SIG_DFL);
+# undef SANITIZING
+# undef RECURSIVE
W(name, name_len);
W(msg1, sizeof(msg1));
W(prev, strlen(prev));
@@ -1037,7 +1078,7 @@ signal_exec(VALUE cmd, int sig)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
VALUE signum = INT2NUM(sig);
- rb_eval_cmd_kw(cmd, rb_ary_new3(1, signum), RB_NO_KEYWORDS);
+ rb_eval_cmd_call_kw(cmd, 1, &signum, RB_NO_KEYWORDS);
}
EC_POP_TAG();
ec = GET_EC();
@@ -1223,11 +1264,6 @@ trap_handler(VALUE *cmd, int sig)
break;
}
}
- else {
- rb_proc_t *proc;
- GetProcPtr(*cmd, proc);
- (void)proc;
- }
}
return func;
@@ -1322,31 +1358,36 @@ reserved_signal_p(int signo)
/*
* call-seq:
- * Signal.trap( signal, command ) -> obj
- * Signal.trap( signal ) {| | block } -> obj
+ * Signal.trap(signal, command) -> obj
+ * Signal.trap(signal) { ... } -> obj
+ *
+ * Specifies the handling of signals. Returns the previous handler for
+ * the given signal.
*
- * Specifies the handling of signals. The first parameter is a signal
- * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
- * signal number. The characters ``SIG'' may be omitted from the
- * signal name. The command or block specifies code to be run when the
+ * Argument +signal+ is a signal name (a string or symbol such
+ * as +SIGALRM+ or +SIGUSR1+) or an integer signal number. When +signal+
+ * is a string or symbol, the leading characters +SIG+ may be omitted.
+ *
+ * Argument +command+ or block provided specifies code to be run when the
* signal is raised.
- * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
- * will be ignored.
- * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
- * will be invoked.
- * If the command is ``EXIT'', the script will be terminated by the signal.
- * If the command is ``SYSTEM_DEFAULT'', the operating system's default
- * handler will be invoked.
- * Otherwise, the given command or block will be run.
- * The special signal name ``EXIT'' or signal number zero will be
- * invoked just prior to program termination.
- * trap returns the previous handler for the given signal.
+ *
+ * Argument +command+ may also be a string or symbol with the following special
+ * values:
+ *
+ * - +IGNORE+, +SIG_IGN+: the signal will be ignored.
+ * - +DEFAULT+, +SIG_DFL+: Ruby's default handler will be invoked.
+ * - +EXIT+: the process will be terminated by the signal.
+ * - +SYSTEM_DEFAULT+: the operating system's default handler will be invoked.
+ *
+ * The special signal name +EXIT+ or signal number zero will be
+ * invoked just prior to program termination:
*
* Signal.trap(0, proc { puts "Terminating: #{$$}" })
* Signal.trap("CLD") { puts "Child died" }
* fork && Process.wait
*
- * <em>produces:</em>
+ * Outputs:
+ *
* Terminating: 27461
* Child died
* Terminating: 27460
@@ -1502,6 +1543,9 @@ Init_signal(void)
rb_define_method(rb_eSignal, "signo", esignal_signo, 0);
rb_alias(rb_eSignal, rb_intern_const("signm"), rb_intern_const("message"));
rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1);
+#if !defined(POSIX_SIGNAL) && !defined(SIG_GET)
+ rb_native_mutex_initialize(&sig_check_lock);
+#endif
// It should be ready to call rb_signal_exec()
VM_ASSERT(GET_THREAD()->pending_interrupt_queue);
@@ -1540,6 +1584,10 @@ Init_signal(void)
RB_ALTSTACK_INIT(GET_VM()->main_altstack, rb_allocate_sigaltstack());
force_install_sighandler(SIGSEGV, (sighandler_t)sigsegv, &default_sigsegv_handler);
#endif
+
+#ifdef SIGABRT
+ force_install_sighandler(SIGABRT, (sighandler_t)sigabrt, &default_sigabrt_handler);
+#endif
}
#ifdef SIGPIPE
install_sighandler(SIGPIPE, sig_do_nothing);
@@ -1554,3 +1602,11 @@ Init_signal(void)
rb_enable_interrupt();
}
+
+void
+rb_signal_atfork(void)
+{
+#if defined(HAVE_WORKING_FORK) && !defined(POSIX_SIGNAL) && !defined(SIG_GET)
+ rb_native_mutex_initialize(&sig_check_lock);
+#endif
+}
diff --git a/siphash.c b/siphash.c
index 61b8604fc9..62de622778 100644
--- a/siphash.c
+++ b/siphash.c
@@ -140,6 +140,9 @@ xor64_to(uint64_t *v, const uint64_t s)
#endif
static const union {
+#if defined(__has_attribute) && __has_attribute(nonstring)
+ __attribute__((nonstring))
+#endif
char bin[32];
uint64_t u64[4];
} sip_init_state_bin = {"uespemos""modnarod""arenegyl""setybdet"};
diff --git a/spec/bin/bundle b/spec/bin/bundle
new file mode 100755
index 0000000000..8f8b535295
--- /dev/null
+++ b/spec/bin/bundle
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require_relative "../bundler/support/activate"
+
+load File.expand_path("bundle", Spec::Path.exedir)
diff --git a/spec/bin/parallel_rspec b/spec/bin/parallel_rspec
index 3b2b003579..412defa58b 100755
--- a/spec/bin/parallel_rspec
+++ b/spec/bin/parallel_rspec
@@ -1,12 +1,7 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
-require_relative "../../spec/bundler/support/rubygems_ext"
-
-require_relative "../../spec/bundler/support/switch_rubygems"
-
-require "rubygems"
-$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
+require_relative "../bundler/support/setup"
require "turbo_tests"
TurboTests::CLI.new(ARGV).run
diff --git a/spec/bin/rspec b/spec/bin/rspec
new file mode 100755
index 0000000000..a41aa4896a
--- /dev/null
+++ b/spec/bin/rspec
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require_relative "../bundler/support/switch_rubygems"
+require_relative "../bundler/support/rubygems_ext"
+
+Spec::Rubygems.gem_load("rspec-core", "rspec")
diff --git a/spec/bundled_gems_spec.rb b/spec/bundled_gems_spec.rb
index 0eb142b7ab..9af06dd181 100644
--- a/spec/bundled_gems_spec.rb
+++ b/spec/bundled_gems_spec.rb
@@ -22,17 +22,12 @@ RSpec.configure do |config|
Gem.ruby = ENV["RUBY"] if ENV["RUBY"]
require_relative "bundler/support/rubygems_ext"
- Spec::Rubygems.test_setup
Spec::Helpers.install_dev_bundler
+ FileUtils.mkdir_p Spec::Path.gem_path
end
config.around(:each) do |example|
FileUtils.cp_r Spec::Path.pristine_system_gem_path, Spec::Path.system_gem_path
- FileUtils.mkdir_p Spec::Path.base_system_gem_path.join("gems")
- %w[sinatra rack tilt rack-protection rack-session rack-test mustermann base64 logger compact_index].each do |gem|
- path = Dir[File.expand_path("../.bundle/gems/#{gem}-*", __dir__)].map(&:to_s).first
- FileUtils.cp_r path, Spec::Path.base_system_gem_path.join("gems")
- end
with_gem_path_as(system_gem_path) do
Bundler.ui.silence { example.run }
@@ -56,11 +51,12 @@ end
RSpec.describe "bundled_gems.rb" do
let(:stub_code) {
+ source_lib_dir = File.realpath(Spec::Path.source_lib_dir.to_s)
<<~STUB
Gem::BUNDLED_GEMS.send(:remove_const, :LIBDIR)
Gem::BUNDLED_GEMS.send(:remove_const, :ARCHDIR)
Gem::BUNDLED_GEMS.send(:remove_const, :SINCE)
- Gem::BUNDLED_GEMS.const_set(:LIBDIR, File.expand_path(File.join(__dir__, "../../..", "lib")) + "/")
+ Gem::BUNDLED_GEMS.const_set(:LIBDIR, "#{source_lib_dir}/")
Gem::BUNDLED_GEMS.const_set(:ARCHDIR, File.expand_path($LOAD_PATH.find{|path| path.include?(".ext/common") }) + "/")
Gem::BUNDLED_GEMS.const_set(:SINCE, { "openssl" => RUBY_VERSION, "fileutils" => RUBY_VERSION, "csv" => "3.4.0", "net-smtp" => "3.1.0" })
STUB
@@ -112,7 +108,7 @@ RSpec.describe "bundled_gems.rb" do
require "active_support/all"
RUBY
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/lib\/active_support\/all\.rb:1/)
end
@@ -158,7 +154,7 @@ RSpec.describe "bundled_gems.rb" do
bundle "exec ruby script.rb"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/script\.rb:8/)
end
@@ -176,7 +172,7 @@ RSpec.describe "bundled_gems.rb" do
bundle "exec ./script.rb"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/script\.rb:9/)
end
@@ -185,7 +181,7 @@ RSpec.describe "bundled_gems.rb" do
create_file("Gemfile", "source 'https://rubygems.org'")
bundle "exec ruby -r./stub -ropenssl -e ''"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
end
it "Show warning when warn is not the standard one in the current scope" do
@@ -208,7 +204,7 @@ RSpec.describe "bundled_gems.rb" do
My.my
RUBY
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/-e:19/)
end
@@ -250,7 +246,7 @@ RSpec.describe "bundled_gems.rb" do
require Gem::BUNDLED_GEMS::ARCHDIR + 'openssl'
RUBY
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
# TODO: We should assert caller location like below:
# test_warn_bootsnap.rb:14: warning: ...
end
@@ -279,7 +275,7 @@ RSpec.describe "bundled_gems.rb" do
# Original issue is childprocess 5.0.0 and logger.
build_lib "fileutils2", "5.0.0" do |s|
# bootsnap expand required feature to full path
- rubylibpath = File.expand_path(File.join(__dir__, "..", "lib"))
+ rubylibpath = File.realpath(File.join(__dir__, "..", "lib"))
s.write "lib/fileutils2.rb", "require '#{rubylibpath}/fileutils'"
end
@@ -319,7 +315,7 @@ RSpec.describe "bundled_gems.rb" do
create_file("Gemfile", "source 'https://rubygems.org'")
bundle "exec ruby script.rb"
- expect(err).to include(/openssl used to be loaded from (.*) since Ruby 3.5.0/)
+ expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/)
expect(err).to include(/script\.rb:13/)
end
@@ -361,4 +357,66 @@ RSpec.describe "bundled_gems.rb" do
expect(err).to be_empty
end
+
+ describe ".force_activate" do
+ before do
+ allow_any_instance_of(Bundler::Runtime).to receive(:setup).and_raise(Bundler::GemNotFound)
+ end
+
+ context "with bundle environment" do
+ before do
+ code = <<-RUBY
+ #!/usr/bin/env ruby
+
+ Gem::BUNDLED_GEMS.force_activate("csv")
+ RUBY
+ create_file("script.rb", code)
+ create_file("Gemfile", "source 'https://rubygems.org'")
+ end
+
+ it "lockfile is available" do
+ bundle "install"
+ bundle "exec ./script.rb"
+
+ expect(err).to include("gem install csv")
+ end
+
+ it "lockfile is not available" do
+ bundle "exec ./script.rb"
+
+ expect(err).to include("gem install csv")
+ end
+ end
+
+ context "with bundler/inline" do
+ it "foo is available on LOAD_PATH" do
+ build_lib "foo", "1.0.0" do |s|
+ s.write "lib/foo.rb", "puts :foo"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ #!/usr/bin/env ruby
+ gemfile do
+ source "https://gem.repo1"
+ path "#{lib_path}" do
+ gem "foo", "1.0.0"
+ end
+ end
+
+ Gem::BUNDLED_GEMS.force_activate("csv")
+ puts $LOAD_PATH
+ RUBY
+
+ expect(err).to include("gem install csv")
+ expect(out).to include("foo-1.0.0/lib")
+ end
+ end
+
+ context "without bundle environment" do
+ it "warns about installation requirement" do
+ expect_any_instance_of(Object).to receive(:warn)
+ Gem::BUNDLED_GEMS.force_activate("csv")
+ end
+ end
+ end
end
diff --git a/spec/bundler/bundler/build_metadata_spec.rb b/spec/bundler/bundler/build_metadata_spec.rb
index afa2d1716f..2e69821f68 100644
--- a/spec/bundler/bundler/build_metadata_spec.rb
+++ b/spec/bundler/bundler/build_metadata_spec.rb
@@ -6,18 +6,20 @@ require "bundler/build_metadata"
RSpec.describe Bundler::BuildMetadata do
before do
allow(Time).to receive(:now).and_return(Time.at(0))
- Bundler::BuildMetadata.instance_variable_set(:@built_at, nil)
+ Bundler::BuildMetadata.instance_variable_set(:@timestamp, nil)
end
- describe "#built_at" do
- it "returns %Y-%m-%d formatted time" do
- expect(Bundler::BuildMetadata.built_at).to eq "1970-01-01"
+ describe "#timestamp" do
+ it "returns %Y-%m-%d formatted current time if built_at not set" do
+ Bundler::BuildMetadata.instance_variable_set(:@built_at, nil)
+ expect(Bundler::BuildMetadata.timestamp).to eq "1970-01-01"
end
- end
- describe "#release?" do
- it "returns false as default" do
- expect(Bundler::BuildMetadata.release?).to be_falsey
+ it "returns %Y-%m-%d formatted current time if built_at not set" do
+ Bundler::BuildMetadata.instance_variable_set(:@built_at, "2025-01-01")
+ expect(Bundler::BuildMetadata.timestamp).to eq "2025-01-01"
+ ensure
+ Bundler::BuildMetadata.instance_variable_set(:@built_at, nil)
end
end
@@ -40,10 +42,9 @@ RSpec.describe Bundler::BuildMetadata do
describe "#to_h" do
subject { Bundler::BuildMetadata.to_h }
- it "returns a hash includes Built At, Git SHA and Released Version" do
- expect(subject["Built At"]).to eq "1970-01-01"
+ it "returns a hash includes Timestamp, and Git SHA" do
+ expect(subject["Timestamp"]).to eq "1970-01-01"
expect(subject["Git SHA"]).to be_instance_of(String)
- expect(subject["Released Version"]).to be_falsey
end
end
end
diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb
index 4db8c00e52..bddcbdaef3 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -52,10 +52,10 @@ RSpec.describe Bundler do
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",
+ s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
+ "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/bundler/CHANGELOG.md",
"homepage_uri" => "https://bundler.io/",
- "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler" }
+ "source_code_uri" => "https://github.com/ruby/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"])
diff --git a/spec/bundler/bundler/cli_common_spec.rb b/spec/bundler/bundler/cli_common_spec.rb
new file mode 100644
index 0000000000..015894b3a1
--- /dev/null
+++ b/spec/bundler/bundler/cli_common_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require "bundler/cli"
+
+RSpec.describe Bundler::CLI::Common do
+ describe "gem_not_found_message" do
+ it "should suggest alternate gem names" do
+ message = subject.gem_not_found_message("ralis", ["BOGUS"])
+ expect(message).to match("Could not find gem 'ralis'.$")
+ message = subject.gem_not_found_message("ralis", ["rails"])
+ expect(message).to match("Did you mean 'rails'?")
+ message = subject.gem_not_found_message("Rails", ["rails"])
+ expect(message).to match("Did you mean 'rails'?")
+ message = subject.gem_not_found_message("meail", %w[email fail eval])
+ expect(message).to match("Did you mean 'email'?")
+ message = subject.gem_not_found_message("nokogri", %w[nokogiri rails sidekiq dog])
+ expect(message).to match("Did you mean 'nokogiri'?")
+ message = subject.gem_not_found_message("methosd", %w[method methods bogus])
+ expect(message).to match(/Did you mean 'method(|s)' or 'method(|s)'?/)
+ end
+ end
+end
diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb
index b2cc1ccfef..56caf9937e 100644
--- a/spec/bundler/bundler/cli_spec.rb
+++ b/spec/bundler/bundler/cli_spec.rb
@@ -87,15 +87,25 @@ RSpec.describe "bundle executable" do
end
context "with no arguments" do
- it "prints a concise help message", bundler: "3" do
- bundle ""
- expect(err).to be_empty
+ it "tries to installs by default but print help on missing Gemfile" do
+ bundle "", raise_on_error: false
+ expect(err).to include("Could not locate Gemfile")
+ expect(out).to include("In a future version of Bundler")
+
expect(out).to include("Bundler version #{Bundler::VERSION}").
and include("\n\nBundler commands:\n\n").
and include("\n\n Primary commands:\n").
and include("\n\n Utilities:\n").
and include("\n\nOptions:\n")
end
+
+ it "runs bundle install when default_cli_command set to install" do
+ bundle_config "default_cli_command install"
+ bundle "", raise_on_error: false
+ expect(out).to_not include("In a future version of Bundler")
+ expect(err).to include("Could not locate Gemfile")
+ expect(exitstatus).to_not be_zero
+ end
end
context "when ENV['BUNDLE_GEMFILE'] is set to an empty string" do
@@ -112,20 +122,34 @@ RSpec.describe "bundle executable" do
end
context "with --verbose" do
- it "prints the running command" do
+ before do
gemfile "source 'https://gem.repo1'"
+ end
+
+ it "prints the running command" do
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
+ bundle "install", 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
- expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
+ it "prints the simulated version too when setting is enabled" do
+ bundle "config set simulate_version 4", verbose: true
+ bundle "info bundler", verbose: true
+ expect(out).to start_with("Running `bundle info bundler --verbose` with bundler #{Bundler::VERSION} (simulating Bundler 4)")
+ end
+ end
+
+ context "with verbose configuration" do
+ before do
+ bundle_config "verbose true"
+ end
+
+ it "prints the running command" do
+ gemfile "source 'https://gem.repo1'"
+ bundle "info bundler"
+ expect(out).to start_with("Running `bundle info bundler` with bundler #{Bundler::VERSION}")
end
end
@@ -179,14 +203,14 @@ RSpec.describe "bundle executable" do
shared_examples_for "no warning" do
it "prints no warning" do
bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
- expect(last_command.stdboth).to eq("Could not find command \"fail\".")
+ expect(stdboth).to eq("Could not find command \"fail\".")
end
end
let(:bundler_version) { "2.0" }
let(:latest_version) { nil }
before do
- bundle "config set --global disable_version_check false"
+ bundle_config_global "disable_version_check false"
pristine_system_gems "bundler-#{bundler_version}"
if latest_version
@@ -227,11 +251,13 @@ To update to the most recent version, run `bundle update --bundler`
context "running a parseable command" do
it "prints no warning" do
+ bundle "config set foo value", env: { "BUNDLER_VERSION" => bundler_version }
bundle "config get --parseable foo", env: { "BUNDLER_VERSION" => bundler_version }
- expect(last_command.stdboth).to eq ""
+ expect(out).to eq "foo=value"
+ expect(err).to eq ""
bundle "platform --ruby", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
- expect(last_command.stdboth).to eq "Could not locate Gemfile"
+ expect(stdboth).to eq "Could not locate Gemfile"
end
end
@@ -250,13 +276,23 @@ 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" do
bundler "--version"
- expect(out).to eq("Bundler version #{Bundler::VERSION}")
- end
+ expect(out).to eq(Bundler::VERSION.to_s)
- it "shows the bundler version just as the `bundle` executable does", bundler: "3" do
+ bundle_config "simulate_version 5"
bundler "--version"
- expect(out).to eq(Bundler::VERSION)
+ expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 5)")
+ end
+
+ it "shows cli_help when bundler install and no Gemfile is found" do
+ bundler "install", raise_on_error: false
+ expect(err).to include("Could not locate Gemfile")
+
+ expect(out).to include("Bundler version #{Bundler::VERSION}").
+ and include("\n\nBundler commands:\n\n").
+ and include("\n\n Primary commands:\n").
+ and include("\n\n Utilities:\n").
+ and include("\n\nOptions:\n")
end
end
diff --git a/spec/bundler/bundler/compact_index_client/parser_spec.rb b/spec/bundler/bundler/compact_index_client/parser_spec.rb
index 1f6b9e593b..6aa867f058 100644
--- a/spec/bundler/bundler/compact_index_client/parser_spec.rb
+++ b/spec/bundler/bundler/compact_index_client/parser_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe Bundler::CompactIndexClient::Parser do
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
+ 3.3.3 a:>= 1.1.0,b:~> 2.0|checksum:ccc3,ruby:>= 3.0.0,rubygems:>= 3.2.3,created_at:2026-05-12T10:00:00Z
INFO
describe "#available?" do
@@ -195,7 +195,7 @@ RSpec.describe Bundler::CompactIndexClient::Parser do
"3.3.3",
nil,
[["a", [">= 1.1.0"]], ["b", ["~> 2.0"]]],
- [["checksum", ["ccc3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
+ [["checksum", ["ccc3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]], ["created_at", ["2026-05-12T10:00:00Z"]]],
],
]
end
@@ -233,5 +233,17 @@ RSpec.describe Bundler::CompactIndexClient::Parser do
VERSIONS
expect(parser.info("a")).to eq(a_result)
end
+
+ it "handles lines without a checksum" 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
+ c 3.0.0,3.0.3,3.3.3 ccc333
+ VERSIONS
+
+ expect(parser.info("a")).to eq(a_result)
+ end
end
end
diff --git a/spec/bundler/bundler/current_ruby_spec.rb b/spec/bundler/bundler/current_ruby_spec.rb
index 61206d258b..79eb802aa5 100644
--- a/spec/bundler/bundler/current_ruby_spec.rb
+++ b/spec/bundler/bundler/current_ruby_spec.rb
@@ -22,7 +22,8 @@ RSpec.describe Bundler::CurrentRuby do
ruby_32: Gem::Platform::RUBY,
ruby_33: Gem::Platform::RUBY,
ruby_34: Gem::Platform::RUBY,
- ruby_35: Gem::Platform::RUBY,
+ ruby_40: Gem::Platform::RUBY,
+ ruby_41: Gem::Platform::RUBY,
mri: Gem::Platform::RUBY,
mri_18: Gem::Platform::RUBY,
mri_19: Gem::Platform::RUBY,
@@ -39,7 +40,8 @@ RSpec.describe Bundler::CurrentRuby do
mri_32: Gem::Platform::RUBY,
mri_33: Gem::Platform::RUBY,
mri_34: Gem::Platform::RUBY,
- mri_35: Gem::Platform::RUBY,
+ mri_40: Gem::Platform::RUBY,
+ mri_41: Gem::Platform::RUBY,
rbx: Gem::Platform::RUBY,
truffleruby: Gem::Platform::RUBY,
jruby: Gem::Platform::JAVA,
@@ -61,7 +63,8 @@ RSpec.describe Bundler::CurrentRuby do
windows_32: Gem::Platform::WINDOWS,
windows_33: Gem::Platform::WINDOWS,
windows_34: Gem::Platform::WINDOWS,
- windows_35: Gem::Platform::WINDOWS }
+ windows_40: Gem::Platform::WINDOWS,
+ windows_41: Gem::Platform::WINDOWS }
end
let(:deprecated) do
@@ -81,7 +84,8 @@ RSpec.describe Bundler::CurrentRuby do
mswin_32: Gem::Platform::MSWIN,
mswin_33: Gem::Platform::MSWIN,
mswin_34: Gem::Platform::MSWIN,
- mswin_35: Gem::Platform::MSWIN,
+ mswin_40: Gem::Platform::MSWIN,
+ mswin_41: Gem::Platform::MSWIN,
mswin64: Gem::Platform::MSWIN64,
mswin64_19: Gem::Platform::MSWIN64,
mswin64_20: Gem::Platform::MSWIN64,
@@ -97,7 +101,8 @@ RSpec.describe Bundler::CurrentRuby do
mswin64_32: Gem::Platform::MSWIN64,
mswin64_33: Gem::Platform::MSWIN64,
mswin64_34: Gem::Platform::MSWIN64,
- mswin64_35: Gem::Platform::MSWIN64,
+ mswin64_40: Gem::Platform::MSWIN64,
+ mswin64_41: Gem::Platform::MSWIN64,
mingw: Gem::Platform::UNIVERSAL_MINGW,
mingw_18: Gem::Platform::UNIVERSAL_MINGW,
mingw_19: Gem::Platform::UNIVERSAL_MINGW,
@@ -114,7 +119,8 @@ RSpec.describe Bundler::CurrentRuby do
mingw_32: Gem::Platform::UNIVERSAL_MINGW,
mingw_33: Gem::Platform::UNIVERSAL_MINGW,
mingw_34: Gem::Platform::UNIVERSAL_MINGW,
- mingw_35: Gem::Platform::UNIVERSAL_MINGW,
+ mingw_40: Gem::Platform::UNIVERSAL_MINGW,
+ mingw_41: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_20: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_21: Gem::Platform::UNIVERSAL_MINGW,
@@ -129,7 +135,8 @@ RSpec.describe Bundler::CurrentRuby do
x64_mingw_32: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_33: Gem::Platform::UNIVERSAL_MINGW,
x64_mingw_34: Gem::Platform::UNIVERSAL_MINGW,
- x64_mingw_35: Gem::Platform::UNIVERSAL_MINGW }
+ x64_mingw_40: Gem::Platform::UNIVERSAL_MINGW,
+ x64_mingw_41: Gem::Platform::UNIVERSAL_MINGW }
end
# rubocop:enable Naming/VariableNumber
@@ -139,18 +146,12 @@ RSpec.describe Bundler::CurrentRuby do
end
describe "Deprecated platform" do
- it "Outputs a deprecation warning when calling maglev?", bundler: "< 3" do
- expect(Bundler.ui).to receive(:warn).with(/`CurrentRuby#maglev\?` is deprecated with no replacement./)
-
- Bundler.current_ruby.maglev?
+ it "outputs an error and aborts when calling maglev?" do
+ expect { Bundler.current_ruby.maglev? }.to raise_error(Bundler::RemovedError, /`CurrentRuby#maglev\?` was removed with no replacement./)
end
- it "Outputs a deprecation warning when calling maglev_31?", bundler: "< 3" do
- expect(Bundler.ui).to receive(:warn).with(/`CurrentRuby#maglev_31\?` is deprecated with no replacement./)
-
- Bundler.current_ruby.maglev_31?
+ it "outputs an error and aborts when calling maglev_31?" do
+ expect { Bundler.current_ruby.maglev_31? }.to raise_error(Bundler::RemovedError, /`CurrentRuby#maglev_31\?` was removed with no replacement./)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
end
diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb
index 8f796877fd..8c4a5a0331 100644
--- a/spec/bundler/bundler/definition_spec.rb
+++ b/spec/bundler/bundler/definition_spec.rb
@@ -3,6 +3,24 @@
require "bundler/definition"
RSpec.describe Bundler::Definition do
+ describe "#overrides" do
+ before do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
+ end
+
+ subject { Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, {}) }
+
+ it "defaults to an empty array" do
+ expect(subject.overrides).to eq([])
+ end
+
+ it "is writable" do
+ override = Bundler::Override.new("rails", :version, ">= 8.0")
+ subject.overrides = [override]
+ expect(subject.overrides).to eq([override])
+ end
+ end
+
describe "#lock" do
before do
allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
@@ -80,7 +98,7 @@ RSpec.describe Bundler::Definition do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -137,7 +155,7 @@ RSpec.describe Bundler::Definition do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(lockfile).to eq(expected_lockfile)
@@ -175,7 +193,7 @@ RSpec.describe Bundler::Definition do
only_java
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -205,7 +223,7 @@ RSpec.describe Bundler::Definition do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
@@ -289,6 +307,57 @@ RSpec.describe Bundler::Definition do
end
end
+ describe "#precompute_source_requirements_for_indirect_dependencies?" do
+ before do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
+ end
+
+ let(:sources) { Bundler::SourceList.new }
+ subject { Bundler::Definition.new(nil, [], sources, []) }
+
+ before do
+ allow(sources).to receive(:non_global_rubygems_sources).and_return(non_global_rubygems_sources)
+ end
+
+ context "when all the scoped sources implement a dependency API" do
+ let(:non_global_rubygems_sources) do
+ [
+ double("non-global-source-0", "dependency_api_available?":true, to_s:"a"),
+ double("non-global-source-1", "dependency_api_available?":true, to_s:"b"),
+ ]
+ end
+
+ it "returns true without warning" do
+ expect(subject).not_to receive(:non_dependency_api_warning)
+
+ expect(subject.send(:precompute_source_requirements_for_indirect_dependencies?)).to be_truthy
+ end
+ end
+
+ context "when some scoped sources do not implement a dependency API" do
+ let(:non_global_rubygems_sources) do
+ [
+ double("non-global-source-0", "dependency_api_available?":true, to_s:"a"),
+ double("non-global-source-1", "dependency_api_available?":false, to_s:"b"),
+ double("non-global-source-2", "dependency_api_available?":false, to_s:"c"),
+ ]
+ end
+
+ it "returns false and warns about the non-API sources" do
+ expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
+Your Gemfile contains scoped sources that don't implement a dependency API, namely:
+
+ * b
+ * c
+
+Using the above gem servers may result in installing unexpected gems. To resolve this warning, make sure you use gem servers that implement dependency APIs, such as gemstash or geminabox gem servers.
+ W
+
+ expect(subject.send(:precompute_source_requirements_for_indirect_dependencies?)).to be_falsy
+ end
+ end
+ end
+
def mock_source_list
Class.new do
def all_sources
@@ -299,10 +368,6 @@ RSpec.describe Bundler::Definition do
[]
end
- def rubygems_remotes
- []
- end
-
def replace_sources!(arg)
nil
end
diff --git a/spec/bundler/bundler/dsl_spec.rb b/spec/bundler/bundler/dsl_spec.rb
index 9dca4ade05..b6e67a312c 100644
--- a/spec/bundler/bundler/dsl_spec.rb
+++ b/spec/bundler/bundler/dsl_spec.rb
@@ -103,7 +103,7 @@ RSpec.describe Bundler::Dsl do
)
end
- context "default hosts", bundler: "< 3" do
+ context "default hosts" do
it "converts :github to URI using https" do
subject.gem("sparks", github: "indirect/sparks")
github_uri = "https://github.com/indirect/sparks.git"
@@ -162,7 +162,7 @@ RSpec.describe Bundler::Dsl do
describe "#method_missing" do
it "raises an error for unknown DSL methods" do
- expect(Bundler).to receive(:read_file).with(source_root.join("Gemfile").to_s).
+ expect(Bundler).to receive(:read_file).with(git_root.join("Gemfile").to_s).
and_return("unknown")
error_msg = "There was an error parsing `Gemfile`: Undefined local variable or method `unknown' for Gemfile. Bundler cannot continue."
@@ -173,13 +173,13 @@ RSpec.describe Bundler::Dsl do
describe "#eval_gemfile" 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(Bundler).to receive(:read_file).with(git_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)
end
it "distinguishes syntax errors from evaluation errors" do
- expect(Bundler).to receive(:read_file).with(source_root.join("Gemfile").to_s).and_return(
+ expect(Bundler).to receive(:read_file).with(git_root.join("Gemfile").to_s).and_return(
"ruby '2.1.5', :engine => 'ruby', :engine_version => '1.2.4'"
)
expect { subject.eval_gemfile("Gemfile") }.
@@ -187,13 +187,13 @@ RSpec.describe Bundler::Dsl do
end
it "populates __dir__ and __FILE__ correctly" do
- abs_path = source_root.join("../fragment.rb").to_s
+ abs_path = git_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_dir)).to eq(git_root.dirname.to_s)
expect(subject.instance_variable_get(:@fragment_file)).to eq(abs_path)
end
end
@@ -201,8 +201,8 @@ RSpec.describe Bundler::Dsl do
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, :ruby_34, :ruby_35, :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, :mri_34, :mri_35, :jruby, :rbx, :truffleruby].each do |platform|
+ :ruby_30, :ruby_31, :ruby_32, :ruby_33, :ruby_34, :ruby_40, :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, :mri_34, :mri_40, :jruby, :rbx, :truffleruby].each do |platform|
it "allows #{platform} as a valid platform" do
subject.gem("foo", platform: platform)
end
@@ -221,8 +221,8 @@ RSpec.describe Bundler::Dsl do
to raise_error(Bundler::GemfileError, /is not a valid platform/)
end
- it "raises a deprecation warning for legacy windows platforms" do
- expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(2, /\APlatform :mswin, :x64_mingw is deprecated/, removed_message: /\APlatform :mswin, :x64_mingw has been removed/)
+ it "warn for legacy windows platforms" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(/\APlatform :mswin, :x64_mingw will be removed in the future./)
subject.gem("foo", platforms: [:mswin, :jruby, :x64_mingw])
end
@@ -291,8 +291,8 @@ RSpec.describe Bundler::Dsl do
end
describe "#platforms" do
- it "raises a deprecation warning for legacy windows platforms" do
- expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(2, /\APlatform :mswin64, :mingw is deprecated/, removed_message: /\APlatform :mswin64, :mingw has been removed/)
+ it "warn for legacy windows platforms" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(/\APlatform :mswin64, :mingw will be removed in the future./)
subject.platforms(:mswin64, :jruby, :mingw) do
subject.gem("foo")
end
@@ -366,4 +366,193 @@ RSpec.describe Bundler::Dsl do
end
end
end
+
+ describe "#source with cooldown" do
+ before do
+ allow(@rubygems).to receive(:add_remote)
+ end
+
+ it "accepts a non-negative integer" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: 7)
+ end.not_to raise_error
+ end
+
+ it "accepts 0 as an explicit disable" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: 0)
+ end.not_to raise_error
+ end
+
+ it "rejects a string" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: "7")
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+
+ it "rejects a float" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: 7.5)
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+
+ it "rejects a negative integer" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: -7)
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+
+ it "rejects an array" do
+ expect do
+ subject.source("https://rubygems.org", cooldown: [7])
+ end.to raise_error(Bundler::InvalidOption, /non-negative integer/)
+ end
+ end
+
+ describe "#override" do
+ it "stores an Override for a gem with a version: operation" do
+ subject.override("rails", version: ">= 8.0")
+
+ expect(subject.overrides.size).to eq(1)
+ override = subject.overrides.first
+ expect(override.target).to eq("rails")
+ expect(override.field).to eq(:version)
+ expect(override.operation).to eq(">= 8.0")
+ end
+
+ it "accepts :ignore_upper as the operation" do
+ subject.override("nokogiri", version: :ignore_upper)
+ expect(subject.overrides.first.operation).to eq(:ignore_upper)
+ end
+
+ it "accepts nil as the operation" do
+ subject.override("legacy", version: nil)
+ expect(subject.overrides.first.operation).to be_nil
+ end
+
+ it "appends to overrides across multiple statements" do
+ subject.override("rails", version: ">= 8.0")
+ subject.override("nokogiri", version: :ignore_upper)
+ expect(subject.overrides.map(&:target)).to eq(["rails", "nokogiri"])
+ end
+
+ it "is empty by default" do
+ expect(subject.overrides).to eq([])
+ end
+
+ it "raises ArgumentError when target is :all and version: is given" do
+ expect do
+ subject.override(:all, version: ">= 8.0")
+ end.to raise_error(ArgumentError, /`override :all, version:` is not allowed/)
+ end
+
+ it "rejects :all + version: even when other fields are also given" do
+ expect do
+ subject.override(:all, required_ruby_version: :ignore_upper, version: ">= 8.0")
+ end.to raise_error(ArgumentError, /`override :all, version:` is not allowed/)
+ end
+
+ it "does not record any override when :all + version: is rejected" do
+ expect do
+ subject.override(:all, version: ">= 8.0")
+ end.to raise_error(ArgumentError)
+ expect(subject.overrides).to eq([])
+ end
+
+ it "raises ArgumentError when target is neither :all nor a string" do
+ expect do
+ subject.override(:rails, version: ">= 8.0")
+ end.to raise_error(ArgumentError, /target must be :all or a gem name string/)
+ end
+
+ it "raises ArgumentError for an unsupported field" do
+ expect do
+ subject.override("rails", as: "y")
+ end.to raise_error(ArgumentError, /unsupported override field `as:`/)
+ end
+
+ it "stores an Override for a gem with a required_ruby_version: operation" do
+ subject.override("rails", required_ruby_version: :ignore_upper)
+ override = subject.overrides.first
+ expect(override.target).to eq("rails")
+ expect(override.field).to eq(:required_ruby_version)
+ expect(override.operation).to eq(:ignore_upper)
+ end
+
+ it "stores an Override for a gem with a required_rubygems_version: operation" do
+ subject.override("rails", required_rubygems_version: nil)
+ override = subject.overrides.first
+ expect(override.field).to eq(:required_rubygems_version)
+ expect(override.operation).to be_nil
+ end
+
+ it "stores an Override targeting :all with a metadata field" do
+ subject.override(:all, required_ruby_version: :ignore_upper)
+ override = subject.overrides.first
+ expect(override.target).to eq(:all)
+ expect(override.field).to eq(:required_ruby_version)
+ expect(override.operation).to eq(:ignore_upper)
+ end
+
+ it "stores an Override targeting :all with required_rubygems_version" do
+ subject.override(:all, required_rubygems_version: nil)
+ override = subject.overrides.first
+ expect(override.target).to eq(:all)
+ expect(override.field).to eq(:required_rubygems_version)
+ end
+
+ it "raises ArgumentError for a non-string, non-symbol, non-nil operation" do
+ expect do
+ subject.override("rails", version: 42)
+ end.to raise_error(ArgumentError, /override operation must be a String, Symbol, or nil/)
+ end
+
+ it "raises ArgumentError for an unsupported symbol operation" do
+ expect do
+ subject.override("rails", version: :explode)
+ end.to raise_error(ArgumentError, /unsupported override operation/)
+ end
+
+ it "raises ArgumentError for an unparsable version string" do
+ expect do
+ subject.override("rails", version: "not a version")
+ end.to raise_error(ArgumentError, /invalid override version requirement/)
+ end
+
+ it "does not record an override when the version string is invalid" do
+ expect do
+ subject.override("rails", version: "not a version")
+ end.to raise_error(ArgumentError)
+ expect(subject.overrides).to eq([])
+ end
+
+ it "rejects atomically when one field in a multi-field call is invalid" do
+ expect do
+ subject.override("rails", version: ">= 8.0", as: "y")
+ end.to raise_error(ArgumentError, /unsupported override field/)
+ expect(subject.overrides).to eq([])
+ end
+
+ it "raises ArgumentError when the same target and field are overridden twice" do
+ subject.override("rails", version: ">= 8.0")
+ expect do
+ subject.override("rails", version: :ignore_upper)
+ end.to raise_error(ArgumentError, /duplicate override for "rails" `version:`/)
+ end
+
+ it "keeps the original override when a duplicate is rejected" do
+ subject.override("rails", version: ">= 8.0")
+ expect do
+ subject.override("rails", version: :ignore_upper)
+ end.to raise_error(ArgumentError)
+ expect(subject.overrides.size).to eq(1)
+ expect(subject.overrides.first.operation).to eq(">= 8.0")
+ end
+
+ it "allows different targets with the same field" do
+ subject.override("rails", version: ">= 8.0")
+ subject.override("nokogiri", version: :ignore_upper)
+ expect(subject.overrides.size).to eq(2)
+ end
+ end
end
diff --git a/spec/bundler/bundler/endpoint_specification_spec.rb b/spec/bundler/bundler/endpoint_specification_spec.rb
index 6518f125ba..4fbd59d48f 100644
--- a/spec/bundler/bundler/endpoint_specification_spec.rb
+++ b/spec/bundler/bundler/endpoint_specification_spec.rb
@@ -46,6 +46,46 @@ RSpec.describe Bundler::EndpointSpecification do
)
end
end
+
+ context "when the metadata has created_at" do
+ let(:metadata) { { "created_at" => ["2026-05-12T10:00:00Z"] } }
+
+ it "parses created_at as a Time" do
+ expect(subject.created_at).to eq(Time.utc(2026, 5, 12, 10, 0, 0))
+ end
+ end
+
+ context "when the metadata has a string created_at (older rubygems shape)" do
+ let(:metadata) { { "created_at" => "2026-05-12T10:00:00Z" } }
+
+ it "still parses created_at" do
+ expect(subject.created_at).to eq(Time.utc(2026, 5, 12, 10, 0, 0))
+ end
+ end
+
+ context "when created_at is truncated (older rubygems splits on colons)" do
+ let(:metadata) { { "created_at" => "2026-05-12T10" } }
+
+ it "leaves created_at as nil instead of raising" do
+ expect(subject.created_at).to be_nil
+ end
+ end
+
+ context "when the metadata has no created_at" do
+ let(:metadata) { { "checksum" => ["abc"] } }
+ let(:spec_fetcher) { double(:spec_fetcher, uri: "https://rubygems.org") }
+
+ it "leaves created_at as nil" do
+ allow(Bundler::Checksum).to receive(:from_api).and_return(nil)
+ expect(subject.created_at).to be_nil
+ end
+ end
+
+ context "when the metadata is nil" do
+ it "leaves created_at as nil" do
+ expect(subject.created_at).to be_nil
+ end
+ end
end
describe "#required_ruby_version" do
diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb
index e0ab0a45e3..259b4ee9dc 100644
--- a/spec/bundler/bundler/env_spec.rb
+++ b/spec/bundler/bundler/env_spec.rb
@@ -217,8 +217,9 @@ 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").
- and_return("git version 1.2.3 (Apple Git-BS)")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3 (Apple Git-BS)", "", status])
expect(Bundler::Source::Git::GitProxy).to receive(:new).and_return(git_proxy_stub)
expect(described_class.report).to include("Git 1.2.3 (Apple Git-BS)")
diff --git a/spec/bundler/bundler/errors_spec.rb b/spec/bundler/bundler/errors_spec.rb
new file mode 100644
index 0000000000..b62d85d32b
--- /dev/null
+++ b/spec/bundler/bundler/errors_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::IncorrectLockfileDependencies do
+ describe "#message" do
+ let(:spec) do
+ double("LazySpecification", full_name: "rubocop-1.82.0")
+ end
+
+ context "without dependency details" do
+ subject { described_class.new(spec) }
+
+ it "provides a basic error message" do
+ expect(subject.message).to include("Bundler found incorrect dependencies in the lockfile for rubocop-1.82.0")
+ expect(subject.message).to include("Please run `bundle install` to regenerate the lockfile.")
+ end
+ end
+
+ context "with dependency details" do
+ let(:actual_dependencies) do
+ [
+ Gem::Dependency.new("json", [">= 2.3", "< 4.0"]),
+ Gem::Dependency.new("parallel", ["~> 1.10"]),
+ Gem::Dependency.new("parser", [">= 3.3.0.2"]),
+ ]
+ end
+
+ let(:lockfile_dependencies) do
+ [
+ Gem::Dependency.new("json", [">= 2.3", "< 3.0"]),
+ Gem::Dependency.new("parallel", ["~> 1.10"]),
+ Gem::Dependency.new("parser", [">= 3.2.0.0"]),
+ ]
+ end
+
+ subject { described_class.new(spec, actual_dependencies, lockfile_dependencies) }
+
+ it "shows only mismatched dependencies" do
+ message = subject.message
+
+ expect(message).to include("json: gemspec specifies")
+ expect(message).to include("parser: gemspec specifies")
+ expect(message).not_to include("parallel")
+ end
+ end
+
+ context "when gemspec has dependencies but lockfile has none" do
+ let(:actual_dependencies) do
+ [
+ Gem::Dependency.new("myrack-test", ["~> 1.0"]),
+ ]
+ end
+
+ let(:lockfile_dependencies) { [] }
+
+ subject { described_class.new(spec, actual_dependencies, lockfile_dependencies) }
+
+ it "shows the dependency as not in lockfile" do
+ message = subject.message
+
+ expect(message).to include("myrack-test: gemspec specifies ~> 1.0, not in lockfile")
+ end
+ end
+
+ context "when gemspec has no dependencies but lockfile has some" do
+ let(:actual_dependencies) { [] }
+
+ let(:lockfile_dependencies) do
+ [
+ Gem::Dependency.new("unexpected", ["~> 1.0"]),
+ ]
+ end
+
+ subject { described_class.new(spec, actual_dependencies, lockfile_dependencies) }
+
+ it "shows the dependency as not in gemspec" do
+ message = subject.message
+
+ expect(message).to include("unexpected: not in gemspec, lockfile has ~> 1.0")
+ end
+ end
+ end
+
+ describe "#status_code" do
+ let(:spec) { double("LazySpecification", full_name: "test-1.0.0") }
+ subject { described_class.new(spec) }
+
+ it "returns 41" do
+ expect(subject.status_code).to eq(41)
+ end
+ end
+end
diff --git a/spec/bundler/bundler/fetcher/dependency_spec.rb b/spec/bundler/bundler/fetcher/dependency_spec.rb
index c420b7c07f..501bc269a5 100644
--- a/spec/bundler/bundler/fetcher/dependency_spec.rb
+++ b/spec/bundler/bundler/fetcher/dependency_spec.rb
@@ -212,7 +212,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:dep_api_uri) { double(:dep_api_uri) }
let(:unmarshalled_gems) { double(:unmarshalled_gems) }
let(:fetch_response) { double(:fetch_response, body: double(:body)) }
- let(:rubygems_limit) { 50 }
+ let(:rubygems_limit) { 100 }
before { allow(subject).to receive(:dependency_api_uri).with(gem_names).and_return(dep_api_uri) }
@@ -222,6 +222,18 @@ RSpec.describe Bundler::Fetcher::Dependency do
expect(Bundler).to receive(:safe_load_marshal).with(fetch_response.body).and_return([unmarshalled_gems])
expect(subject.unmarshalled_dep_gems(gem_names)).to eq([unmarshalled_gems])
end
+
+ it "should fetch as many dependencies as specified" do
+ allow(subject).to receive(:dependency_api_uri).with([%w[foo bar]]).and_return(dep_api_uri)
+ allow(subject).to receive(:dependency_api_uri).with([%w[bundler rubocop]]).and_return(dep_api_uri)
+
+ expect(downloader).to receive(:fetch).twice.with(dep_api_uri).and_return(fetch_response)
+ expect(Bundler).to receive(:safe_load_marshal).twice.with(fetch_response.body).and_return([unmarshalled_gems])
+
+ Bundler.settings.temporary(api_request_size: 1) do
+ expect(subject.unmarshalled_dep_gems(gem_names)).to eq([unmarshalled_gems, unmarshalled_gems])
+ end
+ end
end
describe "#get_formatted_specs_and_deps" do
diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb
index 6164025ac6..edf426328a 100644
--- a/spec/bundler/bundler/fetcher/downloader_spec.rb
+++ b/spec/bundler/bundler/fetcher/downloader_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
/`bundle config set --global www\.uri-to-fetch\.com username:password`.*`BUNDLE_WWW__URI___TO___FETCH__COM`/m)
end
- context "when the there are credentials provided in the request" do
+ context "when there are credentials provided in the request" do
let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
it "should raise a Bundler::Fetcher::BadAuthenticationError that doesn't contain the password" do
@@ -116,7 +116,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
end
- context "when the there are credentials provided in the request" do
+ context "when there are credentials provided in the request" do
let(:uri) { Gem::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
@@ -126,6 +126,38 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
+ context "when the request response is a Gem::Net::HTTPRequestedRangeNotSatisfiable" do
+ let(:http_response) { Gem::Net::HTTPRequestedRangeNotSatisfiable.new("1.1", 416, "Range Not Satisfiable") }
+ let(:success_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
+ let(:options) { { "Range" => "bytes=1000-", "If-None-Match" => "some-etag" } }
+
+ before do
+ # First request returns 416, retry request returns success
+ allow(subject).to receive(:request).with(uri, options).and_return(http_response)
+ allow(subject).to receive(:request).with(uri, { "If-None-Match" => "some-etag" }).and_return(success_response)
+ end
+
+ # The 416 handler removes the Range header and retries without incrementing the counter.
+ # Importantly, it does NOT add Accept-Encoding header, which would break Ruby's
+ # automatic gzip decompression (see issue #9271 for details on that bug).
+ it "should retry the request without the Range header" do
+ expect(subject).to receive(:request).with(uri, options).ordered
+ expect(subject).to receive(:request).with(uri, hash_excluding("Range", "Accept-Encoding")).ordered
+ subject.fetch(uri, options, counter)
+ end
+
+ it "should preserve other headers on retry" do
+ expect(subject).to receive(:request).with(uri, options).ordered
+ expect(subject).to receive(:request).with(uri, hash_including("If-None-Match" => "some-etag")).ordered
+ subject.fetch(uri, options, counter)
+ end
+
+ it "should return the successful response" do
+ result = subject.fetch(uri, options, counter)
+ expect(result).to eq(success_response)
+ end
+ end
+
context "when the request response is some other type" do
let(:http_response) { Gem::Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
@@ -201,39 +233,29 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response causes an error included in HTTP_ERRORS" do
- let(:message) { nil }
- let(:error) { RuntimeError.new(message) }
+ context "when the request response causes an HTTP error" do
+ let(:message) { "error about network" }
+ let(:error) { error_class.new(message) }
before do
- stub_const("Bundler::Fetcher::HTTP_ERRORS", [RuntimeError])
allow(connection).to receive(:request).with(uri, net_http_get) { raise error }
end
- it "should trace log the error" do
- allow(Bundler).to receive_message_chain(:ui, :debug)
- expect(Bundler).to receive_message_chain(:ui, :trace).with(error)
- expect { subject.request(uri, options) }.to raise_error(Bundler::HTTPError)
- end
-
- context "when error message is about the host being down" do
- let(:message) { "host down: http://www.uri-to-fetch.com" }
+ context "that it's retryable" do
+ let(:error_class) { Gem::Timeout::Error }
- it "should raise a Bundler::Fetcher::NetworkDownError" do
- expect { subject.request(uri, options) }.to raise_error(Bundler::Fetcher::NetworkDownError,
- /Could not reach host www.uri-to-fetch.com/)
+ it "should trace log the error" do
+ allow(Bundler).to receive_message_chain(:ui, :debug)
+ expect(Bundler).to receive_message_chain(:ui, :trace).with(error)
+ expect { subject.request(uri, options) }.to raise_error(Bundler::HTTPError)
end
- end
-
- context "when error message is not about host down" do
- let(:message) { "other error about network" }
it "should raise a Bundler::HTTPError" do
expect { subject.request(uri, options) }.to raise_error(Bundler::HTTPError,
- "Network error while fetching http://www.uri-to-fetch.com/api/v2/endpoint (other error about network)")
+ "Network error while fetching http://www.uri-to-fetch.com/api/v2/endpoint (error about network)")
end
- context "when the there are credentials provided in the request" do
+ context "when there are credentials provided in the request" do
let(:uri) { Gem::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")
@@ -241,17 +263,38 @@ RSpec.describe Bundler::Fetcher::Downloader do
it "should raise a Bundler::HTTPError that doesn't contain the password" do
expect { subject.request(uri, options) }.to raise_error(Bundler::HTTPError,
- "Network error while fetching http://username@www.uri-to-fetch.com/api/v2/endpoint (other error about network)")
+ "Network error while fetching http://username@www.uri-to-fetch.com/api/v2/endpoint (error about network)")
end
end
end
- context "when error message is about no route to host" do
+ context "when error is about the host being down" do
+ let(:error_class) { Gem::Net::HTTP::Persistent::Error }
+ let(:message) { "host down: http://www.uri-to-fetch.com" }
+
+ it "should raise a Bundler::Fetcher::NetworkDownError" do
+ expect { subject.request(uri, options) }.to raise_error(Bundler::Fetcher::NetworkDownError,
+ /Could not reach host www.uri-to-fetch.com/)
+ end
+ end
+
+ context "when error is about connection refused" do
+ let(:error_class) { Gem::Net::HTTP::Persistent::Error }
+ let(:message) { "connection refused down: http://www.uri-to-fetch.com" }
+
+ it "should raise a Bundler::Fetcher::NetworkDownError" do
+ expect { subject.request(uri, options) }.to raise_error(Bundler::Fetcher::NetworkDownError,
+ /Could not reach host www.uri-to-fetch.com/)
+ end
+ end
+
+ context "when error is about no route to host" do
+ let(:error_class) { SocketError }
let(:message) { "Failed to open TCP connection to www.uri-to-fetch.com:443 " }
- it "should raise a Bundler::Fetcher::HTTPError" do
- expect { subject.request(uri, options) }.to raise_error(Bundler::HTTPError,
- "Network error while fetching http://www.uri-to-fetch.com/api/v2/endpoint (#{message})")
+ it "should raise a Bundler::Fetcher::NetworkDownError" do
+ expect { subject.request(uri, options) }.to raise_error(Bundler::Fetcher::NetworkDownError,
+ /Could not reach host www.uri-to-fetch.com/)
end
end
end
diff --git a/spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb b/spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb
new file mode 100644
index 0000000000..df1a58d843
--- /dev/null
+++ b/spec/bundler/bundler/fetcher/gem_remote_fetcher_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require "rubygems/remote_fetcher"
+require "bundler/fetcher/gem_remote_fetcher"
+require_relative "../../support/artifice/helpers/artifice"
+require "bundler/vendored_persistent.rb"
+
+RSpec.describe Bundler::Fetcher::GemRemoteFetcher do
+ describe "Parallel download" do
+ it "download using multiple connections from the pool" do
+ unless Bundler.rubygems.provides?(">= 4.0.0.dev")
+ skip "This example can only run when RubyGems supports multiple http connection pool"
+ end
+
+ require_relative "../../support/artifice/helpers/endpoint"
+ concurrent_ruby_path = Dir[scoped_base_system_gem_path.join("gems/concurrent-ruby-*/lib/concurrent-ruby")].first
+ $LOAD_PATH.unshift(concurrent_ruby_path)
+ require "concurrent-ruby"
+
+ require_rack_test
+ responses = []
+
+ latch1 = Concurrent::CountDownLatch.new
+ latch2 = Concurrent::CountDownLatch.new
+ previous_client = Gem::Request::ConnectionPools.client
+ dummy_endpoint = Class.new(Endpoint) do
+ get "/foo" do
+ latch2.count_down
+ latch1.wait
+
+ responses << "foo"
+ end
+
+ get "/bar" do
+ responses << "bar"
+
+ latch1.count_down
+ end
+ end
+
+ Artifice.activate_with(dummy_endpoint)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+
+ first_request = Thread.new do
+ subject.fetch_path("https://example.org/foo")
+ end
+ second_request = Thread.new do
+ latch2.wait
+ subject.fetch_path("https://example.org/bar")
+ end
+
+ [first_request, second_request].each(&:join)
+
+ expect(responses).to eq(["bar", "foo"])
+ ensure
+ Artifice.deactivate
+ Gem::Request::ConnectionPools.client = previous_client
+ end
+ end
+end
diff --git a/spec/bundler/bundler/friendly_errors_spec.rb b/spec/bundler/bundler/friendly_errors_spec.rb
index 255019f40a..426e3c856d 100644
--- a/spec/bundler/bundler/friendly_errors_spec.rb
+++ b/spec/bundler/bundler/friendly_errors_spec.rb
@@ -2,7 +2,8 @@
require "bundler"
require "bundler/friendly_errors"
-require "cgi"
+require "cgi/escape"
+require "cgi/util" unless defined?(CGI::EscapeExt)
RSpec.describe Bundler, "friendly errors" do
context "with invalid YAML in .gemrc" do
@@ -130,17 +131,13 @@ RSpec.describe Bundler, "friendly errors" do
# Does nothing
end
- context "Java::JavaLang::OutOfMemoryError" do
- module Java
- module JavaLang
- class OutOfMemoryError < StandardError; end
- end
- end
-
+ context "Java::JavaLang::OutOfMemoryError", :jruby_only do
it "Bundler.ui receive error" do
- error = Java::JavaLang::OutOfMemoryError.new
- expect(Bundler.ui).to receive(:error).with(/JVM has run out of memory/)
- Bundler::FriendlyErrors.log_error(error)
+ install_gemfile <<-G, raise_on_error: false, env: { "JRUBY_OPTS" => "-J-Xmx32M" }, artifice: nil
+ source "https://gem.repo1"
+ G
+
+ expect(err).to include("JVM has run out of memory")
end
end
@@ -200,7 +197,7 @@ RSpec.describe Bundler, "friendly errors" do
it "generates a search URL for the exception message" do
exception = Exception.new("Exception message")
- expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/rubygems/rubygems/search?q=Exception+message&type=Issues")
+ expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/ruby/rubygems/search?q=Exception+message&type=Issues")
end
it "generates a search URL for only the first line of a multi-line exception message" do
@@ -209,7 +206,7 @@ First line of the exception message
Second line of the exception message
END
- expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/rubygems/rubygems/search?q=First+line+of+the+exception+message&type=Issues")
+ expect(Bundler::FriendlyErrors.issues_url(exception)).to eq("https://github.com/ruby/rubygems/search?q=First+line+of+the+exception+message&type=Issues")
end
it "generates the url without colons" do
@@ -218,7 +215,7 @@ Exception ::: with ::: colons :::
END
issues_url = Bundler::FriendlyErrors.issues_url(exception)
expect(issues_url).not_to include("%3A")
- expect(issues_url).to eq("https://github.com/rubygems/rubygems/search?q=#{CGI.escape("Exception with colons ")}&type=Issues")
+ expect(issues_url).to eq("https://github.com/ruby/rubygems/search?q=#{CGI.escape("Exception with colons ")}&type=Issues")
end
it "removes information after - for Errono::EACCES" do
@@ -228,7 +225,7 @@ END
allow(exception).to receive(:is_a?).with(Errno).and_return(true)
issues_url = Bundler::FriendlyErrors.issues_url(exception)
expect(issues_url).not_to include("/Users/foo/bar")
- expect(issues_url).to eq("https://github.com/rubygems/rubygems/search?q=#{CGI.escape("Errno EACCES Permission denied @ dir_s_mkdir ")}&type=Issues")
+ expect(issues_url).to eq("https://github.com/ruby/rubygems/search?q=#{CGI.escape("Errno EACCES Permission denied @ dir_s_mkdir ")}&type=Issues")
end
end
end
diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb
index 94f66537d3..b4ae2abdc5 100644
--- a/spec/bundler/bundler/gem_helper_spec.rb
+++ b/spec/bundler/bundler/gem_helper_spec.rb
@@ -9,8 +9,12 @@ RSpec.describe Bundler::GemHelper do
let(:app_gemspec_path) { app_path.join("#{app_name}.gemspec") }
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"
+ bundle_config_global "gem.mit false"
+ bundle_config_global "gem.test false"
+ bundle_config_global "gem.coc false"
+ bundle_config_global "gem.linter false"
+ bundle_config_global "gem.ci false"
+ bundle_config_global "gem.changelog false"
git("config --global init.defaultBranch main")
bundle "gem #{app_name}"
prepare_gemspec(app_gemspec_path)
@@ -222,7 +226,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "#{app_name} (#{app_version}) installed."
subject.install_gem(nil, :local)
expect(app_gem_path).to exist
- gem_command :list
+ installed_gems_list
expect(out).to include("#{app_name} (#{app_version})")
end
end
@@ -386,6 +390,7 @@ RSpec.describe Bundler::GemHelper do
credentials = double("credentials", "file?" => true)
allow(Bundler.user_home).to receive(:join).
with(".gem/credentials").and_return(credentials)
+ allow(Bundler.user_home).to receive(:join).and_call_original
end
describe "success messaging" do
diff --git a/spec/bundler/bundler/installer/gem_installer_spec.rb b/spec/bundler/bundler/installer/gem_installer_spec.rb
index 6583bd8181..dbd4e1d2c8 100644
--- a/spec/bundler/bundler/installer/gem_installer_spec.rb
+++ b/spec/bundler/bundler/installer/gem_installer_spec.rb
@@ -23,9 +23,7 @@ RSpec.describe Bundler::GemInstaller do
context "spec_settings is build option" do
it "invokes install method with build_args" do
- allow(Bundler.settings).to receive(:[]).with(:bin)
- allow(Bundler.settings).to receive(:[]).with(:inline)
- allow(Bundler.settings).to receive(:[]).with(:forget_cli_options)
+ allow(Bundler.settings).to receive(:[])
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy")
expect(spec_source).to receive(:install).with(
spec,
@@ -37,9 +35,7 @@ RSpec.describe Bundler::GemInstaller do
context "spec_settings is build option with spaces" do
it "invokes install method with build_args" do
- allow(Bundler.settings).to receive(:[]).with(:bin)
- allow(Bundler.settings).to receive(:[]).with(:inline)
- allow(Bundler.settings).to receive(:[]).with(:forget_cli_options)
+ allow(Bundler.settings).to receive(:[])
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,
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..49bcb5310b
--- /dev/null
+++ b/spec/bundler/bundler/installer/parallel_installer_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require "bundler/installer/parallel_installer"
+require "bundler/rubygems_gem_installer"
+require "rubygems/remote_fetcher"
+require "bundler"
+
+RSpec.describe Bundler::ParallelInstaller do
+ describe "priority queue" do
+ before do
+ require "support/artifice/compact_index"
+
+ @previous_client = Gem::Request::ConnectionPools.client
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+ Gem::RemoteFetcher.fetcher.close_all
+
+ build_repo2 do
+ build_gem "gem_with_extension", &:add_c_extension
+ build_gem "gem_without_extension"
+ end
+
+ gemfile <<~G
+ source "https://gem.repo2"
+
+ gem "gem_with_extension"
+ gem "gem_without_extension"
+ G
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo2/
+ specs:
+ gem_with_extension (1.0)
+ gem_without_extension (1.0)
+
+ DEPENDENCIES
+ gem_with_extension
+ gem_without_extension
+ L
+
+ @old_ui = Bundler.ui
+ Bundler.ui = Bundler::UI::Silent.new
+ end
+
+ after do
+ Bundler.ui = @old_ui
+ Gem::Request::ConnectionPools.client = @previous_client
+ Artifice.deactivate
+ end
+
+ let(:definition) do
+ allow(Bundler).to receive(:root) { bundled_app }
+
+ definition = Bundler::Definition.build(bundled_app.join("Gemfile"), bundled_app.join("Gemfile.lock"), false)
+ definition.tap(&:setup_domain!)
+ end
+ let(:installer) { Bundler::Installer.new(bundled_app, definition) }
+
+ it "queues native extensions in priority" do
+ parallel_installer = Bundler::ParallelInstaller.new(installer, definition.specs, 2, false, true)
+ worker_pool = parallel_installer.send(:worker_pool)
+ expected = 6 # Enqueue to download bundler and the 2 gems. Enqueue to install Bundler and the 2 gems.
+
+ expect(worker_pool).to receive(:enq).exactly(expected).times.and_wrap_original do |original_enq, spec, opts|
+ unless opts.nil? # Enqueued for download, no priority
+ if spec.name == "gem_with_extension"
+ expect(opts).to eq({ priority: true })
+ else
+ expect(opts).to eq({ priority: false })
+ end
+ end
+
+ opts ||= {}
+ original_enq.call(spec, **opts)
+ end
+
+ parallel_installer.call
+ 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..57868766d9 100644
--- a/spec/bundler/bundler/installer/spec_installation_spec.rb
+++ b/spec/bundler/bundler/installer/spec_installation_spec.rb
@@ -3,18 +3,17 @@
require "bundler/installer/parallel_installer"
RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
- let!(:dep) do
- a_spec = Object.new
- def a_spec.name
- "I like tests"
- end
-
- def a_spec.full_name
- "I really like tests"
- end
- a_spec
+ def build_spec(name, extensions: [])
+ spec = Object.new
+ spec.define_singleton_method(:name) { name }
+ spec.define_singleton_method(:full_name) { "#{name}-1.0" }
+ spec.define_singleton_method(:extensions) { extensions }
+ spec.define_singleton_method(:dependencies) { [] }
+ spec
end
+ let!(:dep) { build_spec("I like tests") }
+
describe "#ready_to_enqueue?" do
context "when in enqueued state" do
it "is falsey" do
@@ -39,29 +38,51 @@ RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
end
describe "#dependencies_installed?" 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)]
+ it "returns true when all dependencies are installed" do
+ alpha = described_class.new(build_spec("alpha"))
+ alpha.dependencies = []
+
+ beta = described_class.new(build_spec("beta"))
+ beta.dependencies = [alpha]
+
+ gamma = described_class.new(build_spec("gamma"))
+ gamma.dependencies = [beta]
+
+ expect(gamma.dependencies_installed?({})).to be_falsey
+ expect(gamma.dependencies_installed?({ "beta" => true })).to be_falsey
+ expect(gamma.dependencies_installed?({ "alpha" => true, "beta" => true })).to be_truthy
+ end
+ end
+
+ describe "#ready_to_install?" do
+ context "when spec has no extensions" do
+ it "returns true regardless of dependencies" do
+ beta = described_class.new(build_spec("beta"))
+ beta.dependencies = []
+
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
+ spec.state = :downloaded
+ spec.dependencies = [beta]
+
+ expect(spec.ready_to_install?({})).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)]
- 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
+ context "when spec has extensions" do
+ it "returns true when all dependencies are installed" do
+ alpha = described_class.new(build_spec("alpha"))
+ alpha.dependencies = []
+
+ beta = described_class.new(build_spec("beta"))
+ beta.dependencies = [alpha]
+
+ gamma = described_class.new(build_spec("gamma", extensions: ["ext/Rakefile"]))
+ gamma.state = :downloaded
+ gamma.dependencies = [beta]
+
+ expect(gamma.ready_to_install?({})).to be_falsey
+ expect(gamma.ready_to_install?({ "beta" => true })).to be_falsey
+ expect(gamma.ready_to_install?({ "alpha" => true, "beta" => true })).to be_truthy
end
end
end
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index f38da2c993..7364ab98e5 100644
--- a/spec/bundler/bundler/lockfile_parser_spec.rb
+++ b/spec/bundler/bundler/lockfile_parser_spec.rb
@@ -129,6 +129,7 @@ RSpec.describe Bundler::LockfileParser do
shared_examples_for "parsing" do
it "parses correctly" do
+ expect(subject.valid?).to be(true)
expect(subject.sources).to eq sources
expect(subject.dependencies).to eq dependencies
expect(subject.specs).to eq specs
@@ -191,6 +192,87 @@ RSpec.describe Bundler::LockfileParser do
include_examples "parsing"
end
+ context "when the content does not contain any recognized lockfile sections" do
+ let(:lockfile_contents) { "hello world\nlorem ipsum\n" }
+
+ it "does not raise, is not valid, and deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+
+ it "does not raise when strict: true, and still deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents, strict: true)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+ end
+
+ context "when the content looks like a Gemfile DSL" do
+ let(:lockfile_contents) { <<~G }
+ source "https://rubygems.org"
+ gem "rake"
+ G
+
+ it "does not raise, is not valid, and deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+
+ it "does not raise when strict: true, and still deprecates" do
+ expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
+ /does not appear to be a valid lockfile.*future version of Bundler/m
+ )
+ parser = described_class.new(lockfile_contents, strict: true)
+ expect(parser.valid?).to be(false)
+ expect(parser.specs).to eq([])
+ expect(parser.dependencies).to eq({})
+ end
+ end
+
+ context "when the content is empty" do
+ let(:lockfile_contents) { "" }
+
+ it "does not raise and is valid" do
+ expect { subject }.not_to raise_error
+ expect(subject.valid?).to be(true)
+ end
+ end
+
+ context "when lockfile_path is given" do
+ it "uses the provided path in error messages instead of looking up Bundler.default_lockfile" do
+ expect(Bundler::SharedHelpers).not_to receive(:relative_lockfile_path)
+ parser = described_class.new(lockfile_contents, lockfile_path: "custom/path.lock")
+ expect(parser.valid?).to be(true)
+ rake_spec = parser.specs.last
+ checksums = parser.sources.last.checksum_store.to_lock(rake_spec)
+ expected_checksum = Bundler::Checksum.from_lock(
+ "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
+ "custom/path.lock:20:17"
+ )
+ expect(checksums).to eq("#{rake_spec.lock_name} #{expected_checksum.to_lock}")
+ end
+
+ it "raises with the provided path when the lockfile contains merge conflicts" do
+ expect do
+ described_class.new("<<<<<<<\n", lockfile_path: "custom/path.lock")
+ end.to raise_error(Bundler::LockfileError, %r{custom/path\.lock contains merge conflicts})
+ end
+ end
+
context "when CHECKSUMS has duplicate checksums in the lockfile that don't match" do
let(:bad_checksum) { "sha256=c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11" }
let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) #{bad_checksum}\n").join }
diff --git a/spec/bundler/bundler/override_spec.rb b/spec/bundler/bundler/override_spec.rb
new file mode 100644
index 0000000000..ad8be75520
--- /dev/null
+++ b/spec/bundler/bundler/override_spec.rb
@@ -0,0 +1,175 @@
+# frozen_string_literal: true
+
+RSpec.describe "MatchMetadata override-aware checks" do
+ let(:spec_class) do
+ Class.new do
+ include Bundler::MatchMetadata
+ attr_accessor :name
+ def initialize(name, ruby_req, rubygems_req)
+ @name = name
+ @required_ruby_version = ruby_req
+ @required_rubygems_version = rubygems_req
+ end
+ end
+ end
+
+ it "matches_current_metadata? ignores overrides (strict path)" do
+ spec = spec_class.new("rails", Gem::Requirement.new("< #{Gem.ruby_version}"), Gem::Requirement.default)
+ overrides = [Bundler::Override.new("rails", :required_ruby_version, :ignore_upper)]
+ # Strict method MUST NOT apply overrides; guards SelfManager and other generic callers.
+ expect(spec.matches_current_metadata?).to be(false)
+ expect(spec.matches_current_metadata_with_overrides?(overrides)).to be(true)
+ end
+
+ it "matches_current_ruby_with_overrides? returns the strict result for an empty override list" do
+ spec = spec_class.new("rails", Gem::Requirement.new(">= #{Gem.ruby_version}"), Gem::Requirement.default)
+ expect(spec.matches_current_ruby_with_overrides?([])).to be(true)
+ expect(spec.matches_current_ruby_with_overrides?(nil)).to be(true)
+ end
+
+ it "matches_current_rubygems_with_overrides? honors :all override" do
+ spec = spec_class.new("rails", Gem::Requirement.default, Gem::Requirement.new("< #{Gem.rubygems_version}"))
+ overrides = [Bundler::Override.new(:all, :required_rubygems_version, :ignore_upper)]
+ expect(spec.matches_current_rubygems_with_overrides?(overrides)).to be(true)
+ end
+end
+
+RSpec.describe "LazySpecification override propagation" do
+ let(:overrides) { [Bundler::Override.new("rails", :required_ruby_version, :ignore_upper)] }
+
+ it "carries overrides forward from a source LazySpec via from_spec" do
+ src = Bundler::LazySpecification.new("rails", "8.0", Gem::Platform::RUBY)
+ src.overrides = overrides
+ derived = Bundler::LazySpecification.from_spec(src)
+ expect(derived.overrides).to eq(overrides)
+ end
+
+ it "does not call respond_to? on the source spec, avoiding gemspec lazy load" do
+ # If from_spec used respond_to?(:overrides), a RemoteSpec source would
+ # force-load the backing gemspec. Use a stand-in object whose
+ # respond_to? raises to prove it is never asked.
+ src = Object.new
+ src.define_singleton_method(:name) { "rails" }
+ src.define_singleton_method(:version) { Gem::Version.new("8.0") }
+ src.define_singleton_method(:platform) { Gem::Platform::RUBY }
+ src.define_singleton_method(:source) { nil }
+ src.define_singleton_method(:runtime_dependencies) { [] }
+ src.define_singleton_method(:required_ruby_version) { Gem::Requirement.default }
+ src.define_singleton_method(:required_rubygems_version) { Gem::Requirement.default }
+ src.define_singleton_method(:respond_to?) {|*| raise "from_spec must not call respond_to?" }
+ expect { Bundler::LazySpecification.from_spec(src) }.not_to raise_error
+ end
+end
+
+RSpec.describe Bundler::Override do
+ describe ".find_for" do
+ it "returns the matching override by target and field" do
+ a = described_class.new("rails", :version, ">= 8.0")
+ b = described_class.new("nokogiri", :version, :ignore_upper)
+ expect(described_class.find_for([a, b], "rails", :version)).to be(a)
+ end
+
+ it "returns nil when no override matches the target" do
+ a = described_class.new("rails", :version, ">= 8.0")
+ expect(described_class.find_for([a], "sinatra", :version)).to be_nil
+ end
+
+ it "returns nil when no override matches the field" do
+ a = described_class.new("rails", :version, ">= 8.0")
+ expect(described_class.find_for([a], "rails", :required_ruby_version)).to be_nil
+ end
+
+ it "returns nil for an empty overrides list" do
+ expect(described_class.find_for([], "rails", :version)).to be_nil
+ end
+
+ it "falls back to an :all override on the same field" do
+ a = described_class.new(:all, :required_ruby_version, :ignore_upper)
+ expect(described_class.find_for([a], "rails", :required_ruby_version)).to be(a)
+ end
+
+ it "prefers a per-gem override over a matching :all override" do
+ per_gem = described_class.new("rails", :required_ruby_version, ">= 3.4")
+ all_target = described_class.new(:all, :required_ruby_version, :ignore_upper)
+ expect(described_class.find_for([all_target, per_gem], "rails", :required_ruby_version)).to be(per_gem)
+ end
+
+ it "does not fall back to :all when the field differs" do
+ a = described_class.new(:all, :required_ruby_version, :ignore_upper)
+ expect(described_class.find_for([a], "rails", :required_rubygems_version)).to be_nil
+ end
+ end
+
+ describe "#apply_to" do
+ context "when operation is a version spec string" do
+ it "replaces the existing requirement entirely" do
+ override = described_class.new("rails", :version, ">= 8.0")
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.new(">= 8.0"))
+ end
+
+ it "ignores the existing requirement regardless of its content" do
+ override = described_class.new("rails", :version, "= 1.0")
+ result = override.apply_to(Gem::Requirement.new(">= 99.0"))
+ expect(result).to eq(Gem::Requirement.new("= 1.0"))
+ end
+ end
+
+ context "when operation is :ignore_upper" do
+ it "removes < and <= operators" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.new(">= 1.0"))
+ end
+
+ it "keeps >, >=, = operators" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new("> 1.0", "<= 2.0"))
+ expect(result).to eq(Gem::Requirement.new("> 1.0"))
+ end
+
+ it "converts ~> to >= preserving the lower bound" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new("~> 1.5"))
+ expect(result).to eq(Gem::Requirement.new(">= 1.5"))
+ end
+
+ it "preserves != exclusion constraints" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "!= 1.5.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.new(">= 1.0", "!= 1.5.0"))
+ end
+
+ it "returns the default requirement when only upper bounds remain" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ result = override.apply_to(Gem::Requirement.new("< 2.0"))
+ expect(result).to eq(Gem::Requirement.default)
+ end
+
+ it "returns the default requirement when the input is nil" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ expect(override.apply_to(nil)).to eq(Gem::Requirement.default)
+ end
+
+ it "returns the default requirement when the input is already the default" do
+ override = described_class.new("rails", :version, :ignore_upper)
+ expect(override.apply_to(Gem::Requirement.default)).to eq(Gem::Requirement.default)
+ end
+ end
+
+ context "when operation is nil" do
+ it "returns the default requirement" do
+ override = described_class.new("rails", :version, nil)
+ result = override.apply_to(Gem::Requirement.new(">= 1.0", "< 2.0"))
+ expect(result).to eq(Gem::Requirement.default)
+ end
+ end
+
+ context "when operation is unsupported" do
+ it "raises ArgumentError" do
+ override = described_class.new("rails", :version, 42)
+ expect { override.apply_to(Gem::Requirement.default) }.to raise_error(ArgumentError, /unsupported override operation/)
+ end
+ end
+ end
+end
diff --git a/spec/bundler/bundler/plugin/events_spec.rb b/spec/bundler/bundler/plugin/events_spec.rb
index 28d70c6fdd..77e5fdb74c 100644
--- a/spec/bundler/bundler/plugin/events_spec.rb
+++ b/spec/bundler/bundler/plugin/events_spec.rb
@@ -2,7 +2,17 @@
RSpec.describe Bundler::Plugin::Events do
context "plugin events" do
- before { Bundler::Plugin::Events.send :reset }
+ before do
+ @old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
+ Bundler::Plugin::Events.send :reset
+ end
+
+ after do
+ Bundler::Plugin::Events.send(:reset)
+ Hash[@old_constants].each do |name, value|
+ Bundler::Plugin::Events.send(:define, name, value)
+ end
+ end
describe "#define" do
it "raises when redefining a constant" do
diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb
index 565fc9b088..a28934269b 100644
--- a/spec/bundler/bundler/plugin/index_spec.rb
+++ b/spec/bundler/bundler/plugin/index_spec.rb
@@ -193,4 +193,83 @@ RSpec.describe Bundler::Plugin::Index do
include_examples "it cleans up"
end
end
+
+ describe "relative plugin paths" do
+ let(:plugin_name) { "relative-plugin" }
+
+ before do
+ Bundler::Plugin.reset!
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+
+ plugin_root = Bundler::Plugin.root
+ FileUtils.mkdir_p(plugin_root)
+
+ path = plugin_root.join(plugin_name)
+ FileUtils.mkdir_p(path.join("lib"))
+
+ index.register_plugin(plugin_name, path.to_s, [path.join("lib").to_s], [], [], [])
+ end
+
+ it "stores plugin paths relative to the plugin root" do
+ require "yaml"
+ data = YAML.load_file(index.index_file)
+
+ expect(data["plugin_paths"][plugin_name]).to eq(plugin_name)
+ expect(data["load_paths"][plugin_name]).to eq([File.join(plugin_name, "lib")])
+ end
+
+ it "expands relative paths to absolute on load" do
+ require "bundler/yaml_serializer"
+
+ plugin_root = Bundler::Plugin.root
+
+ relative_index = {
+ "commands" => {},
+ "hooks" => {},
+ "load_paths" => { plugin_name => [File.join(plugin_name, "lib")] },
+ "plugin_paths" => { plugin_name => plugin_name },
+ "sources" => {},
+ }
+
+ File.open(index.index_file, "w") {|f| f.puts Bundler::YAMLSerializer.dump(relative_index) }
+
+ new_index = Index.new
+ expect(new_index.plugin_path(plugin_name)).to eq(plugin_root.join(plugin_name))
+ expect(new_index.load_paths(plugin_name)).to eq([plugin_root.join(plugin_name, "lib").to_s])
+ end
+
+ it "keeps paths outside the plugin root as absolute" do
+ outside_path = tmp.join("outside", "external-plugin")
+ FileUtils.mkdir_p(outside_path.join("lib"))
+
+ index.register_plugin("external-plugin", outside_path.to_s, [outside_path.join("lib").to_s], [], [], [])
+
+ require "yaml"
+ data = YAML.load_file(index.index_file)
+
+ expect(data["plugin_paths"]["external-plugin"]).to eq(outside_path.to_s)
+ expect(data["load_paths"]["external-plugin"]).to eq([outside_path.join("lib").to_s])
+ end
+
+ it "reads legacy index files with absolute paths" do
+ require "bundler/yaml_serializer"
+
+ plugin_root = Bundler::Plugin.root
+ absolute_path = plugin_root.join(plugin_name).to_s
+
+ legacy_index = {
+ "commands" => {},
+ "hooks" => {},
+ "load_paths" => { plugin_name => [File.join(absolute_path, "lib")] },
+ "plugin_paths" => { plugin_name => absolute_path },
+ "sources" => {},
+ }
+
+ File.open(index.index_file, "w") {|f| f.puts Bundler::YAMLSerializer.dump(legacy_index) }
+
+ new_index = Index.new
+ expect(new_index.plugin_path(plugin_name)).to eq(Pathname.new(absolute_path))
+ expect(new_index.load_paths(plugin_name)).to eq([File.join(absolute_path, "lib")])
+ end
+ end
end
diff --git a/spec/bundler/bundler/plugin/installer_spec.rb b/spec/bundler/bundler/plugin/installer_spec.rb
index 8e1879395a..c200a98afa 100644
--- a/spec/bundler/bundler/plugin/installer_spec.rb
+++ b/spec/bundler/bundler/plugin/installer_spec.rb
@@ -47,6 +47,13 @@ RSpec.describe Bundler::Plugin::Installer do
build_plugin "re-plugin"
build_plugin "ma-plugin"
end
+
+ @previous_ui = Bundler.ui
+ Bundler.ui = Bundler::UI::Silent.new
+ end
+
+ after do
+ Bundler.ui = @previous_ui
end
context "git plugins" do
diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb
index fea3925000..b379594c6f 100644
--- a/spec/bundler/bundler/plugin_spec.rb
+++ b/spec/bundler/bundler/plugin_spec.rb
@@ -65,8 +65,8 @@ RSpec.describe Bundler::Plugin do
end
it "passes the name and options to installer" do
- allow(index).to receive(:installed?).
- with("new-plugin")
+ allow(index).to receive(:up_to_date?).
+ with(spec)
allow(installer).to receive(:install).with(["new-plugin"], opts) do
{ "new-plugin" => spec }
end.once
@@ -75,8 +75,8 @@ RSpec.describe Bundler::Plugin do
end
it "validates the installed plugin" do
- allow(index).to receive(:installed?).
- with("new-plugin")
+ allow(index).to receive(:up_to_date?).
+ with(spec)
allow(subject).
to receive(:validate_plugin!).with(lib_path("new-plugin")).once
@@ -84,8 +84,8 @@ RSpec.describe Bundler::Plugin do
end
it "registers the plugin with index" do
- allow(index).to receive(:installed?).
- with("new-plugin")
+ allow(index).to receive(:up_to_date?).
+ with(spec)
allow(index).to receive(:register_plugin).
with("new-plugin", lib_path("new-plugin").to_s, [lib_path("new-plugin").join("lib").to_s], []).once
subject.install ["new-plugin"], opts
@@ -102,7 +102,7 @@ RSpec.describe Bundler::Plugin do
end.once
allow(subject).to receive(:validate_plugin!).twice
- allow(index).to receive(:installed?).twice
+ allow(index).to receive(:up_to_date?).twice
allow(index).to receive(:register_plugin).twice
subject.install ["new-plugin", "another-plugin"], opts
end
@@ -138,7 +138,7 @@ RSpec.describe Bundler::Plugin do
end
before do
- allow(index).to receive(:installed?) { nil }
+ allow(index).to receive(:up_to_date?) { nil }
allow(definition).to receive(:dependencies) { [Bundler::Dependency.new("new-plugin", ">=0"), Bundler::Dependency.new("another-plugin", ">=0")] }
allow(installer).to receive(:install_definition) { plugin_specs }
end
@@ -279,6 +279,7 @@ RSpec.describe Bundler::Plugin do
s.write "plugins.rb", code
end
+ @old_constants = Bundler::Plugin::Events.constants.map {|name| [name, Bundler::Plugin::Events.const_get(name)] }
Bundler::Plugin::Events.send(:reset)
Bundler::Plugin::Events.send(:define, :EVENT1, "event-1")
Bundler::Plugin::Events.send(:define, :EVENT2, "event-2")
@@ -291,6 +292,13 @@ RSpec.describe Bundler::Plugin do
allow(index).to receive(:load_paths).with("foo-plugin").and_return([])
end
+ after do
+ Bundler::Plugin::Events.send(:reset)
+ Hash[@old_constants].each do |name, value|
+ Bundler::Plugin::Events.send(:define, name, value)
+ end
+ end
+
let(:code) { <<-RUBY }
Bundler::Plugin::API.hook("event-1") { puts "hook for event 1" }
RUBY
diff --git a/spec/bundler/bundler/resolver/cooldown_spec.rb b/spec/bundler/bundler/resolver/cooldown_spec.rb
new file mode 100644
index 0000000000..37ec158cba
--- /dev/null
+++ b/spec/bundler/bundler/resolver/cooldown_spec.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::Resolver do
+ let(:resolver) { described_class.allocate }
+
+ def remote(cooldown:)
+ instance_double(Bundler::Source::Rubygems::Remote, effective_cooldown: cooldown)
+ end
+
+ def spec(created_at:, remote:, name: "myrack", version: "1.0.0")
+ Struct.new(:name, :version, :created_at, :remote).new(name, Gem::Version.new(version), created_at, remote)
+ end
+
+ describe "#filter_cooldown" do
+ let(:now) { Time.now }
+
+ context "with a 7-day cooldown" do
+ let(:r) { remote(cooldown: 7) }
+
+ it "rejects versions published within the window" do
+ recent = spec(version: "1.1.0", created_at: now - (2 * 86_400), remote: r)
+ old = spec(version: "1.0.0", created_at: now - (30 * 86_400), remote: r)
+
+ expect(resolver.send(:filter_cooldown, [recent, old])).to eq([old])
+ end
+
+ it "keeps versions published exactly at the threshold" do
+ boundary = spec(created_at: now - (7 * 86_400), remote: r)
+
+ expect(resolver.send(:filter_cooldown, [boundary])).to eq([boundary])
+ end
+
+ it "leaves rolling-delay history intact" do
+ # 7-day cooldown with frequent releases must still expose an older candidate.
+ in_cooldown = spec(version: "1.2.0", created_at: now - 86_400, remote: r)
+ also_in_cooldown = spec(version: "1.1.0", created_at: now - (3 * 86_400), remote: r)
+ eligible = spec(version: "1.0.0", created_at: now - (10 * 86_400), remote: r)
+
+ result = resolver.send(:filter_cooldown, [in_cooldown, also_in_cooldown, eligible])
+
+ expect(result).to eq([eligible])
+ end
+
+ it "drops every spec sharing an excluded [name, version] tuple" do
+ # The cooldown check is by version, not per-spec: a StubSpecification for an
+ # in-cooldown release would otherwise slip through on local install paths.
+ endpoint = spec(version: "2.0.0", created_at: now - 86_400, remote: r)
+ local_stub = Struct.new(:name, :version).new("myrack", Gem::Version.new("2.0.0"))
+ eligible = spec(version: "1.0.0", created_at: now - (30 * 86_400), remote: r)
+
+ result = resolver.send(:filter_cooldown, [endpoint, local_stub, eligible])
+
+ expect(result).to eq([eligible])
+ end
+
+ it "keeps stub-only versions that no endpoint marks as in cooldown" do
+ # If no remote spec carries created_at for a version, cooldown cannot judge it;
+ # the stub stays in.
+ local_only = Struct.new(:name, :version).new("myrack", Gem::Version.new("2.0.0"))
+ eligible = spec(version: "1.0.0", created_at: now - (30 * 86_400), remote: r)
+
+ result = resolver.send(:filter_cooldown, [local_only, eligible])
+
+ expect(result).to eq([local_only, eligible])
+ end
+ end
+
+ context "when created_at is missing (blank metadata)" do
+ it "keeps the spec regardless of cooldown" do
+ s = spec(created_at: nil, remote: remote(cooldown: 7))
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ context "when the remote has no cooldown" do
+ it "keeps every spec" do
+ s = spec(created_at: now - 3600, remote: remote(cooldown: nil))
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ context "when cooldown is 0" do
+ it "keeps every spec (escape hatch)" do
+ s = spec(created_at: now - 3600, remote: remote(cooldown: 0))
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ context "when the spec does not respond to created_at" do
+ it "keeps the spec" do
+ bare = Struct.new(:version).new("1.0.0")
+
+ expect(resolver.send(:filter_cooldown, [bare])).to eq([bare])
+ end
+ end
+
+ context "when the spec has no remote" do
+ it "keeps the spec" do
+ s = spec(created_at: now - 86_400, remote: nil)
+
+ expect(resolver.send(:filter_cooldown, [s])).to eq([s])
+ end
+ end
+
+ it "returns the same array when input is empty" do
+ expect(resolver.send(:filter_cooldown, [])).to eq([])
+ end
+ end
+
+ describe "#cooldown_hint" do
+ let(:now) { Time.now }
+ let(:r) { remote(cooldown: 7) }
+
+ it "returns nil when no spec is excluded" do
+ expect(resolver.send(:cooldown_hint, [])).to be_nil
+ end
+
+ it "returns nil when every spec is outside the cooldown window" do
+ eligible = [spec(created_at: now - (30 * 86_400), remote: r)]
+
+ expect(resolver.send(:cooldown_hint, eligible)).to be_nil
+ end
+
+ it "mentions the count and the bypass flag for one excluded version" do
+ excluded = [spec(created_at: now - 86_400, remote: r)]
+
+ hint = resolver.send(:cooldown_hint, excluded)
+
+ expect(hint).to match(/1 version excluded by the cooldown setting/)
+ expect(hint).to match(/--cooldown 0/)
+ end
+
+ it "uses plural wording when multiple versions are excluded" do
+ excluded = %w[1.0.0 1.1.0 1.2.0].map {|v| spec(version: v, created_at: now - 86_400, remote: r) }
+
+ expect(resolver.send(:cooldown_hint, excluded)).to match(/3 versions excluded/)
+ end
+
+ it "counts each unique version once even when multiple spec instances share it" do
+ duplicates = Array.new(3) { spec(created_at: now - 86_400, remote: r) }
+
+ expect(resolver.send(:cooldown_hint, duplicates)).to match(/1 version excluded/)
+ end
+ end
+end
diff --git a/spec/bundler/bundler/retry_spec.rb b/spec/bundler/bundler/retry_spec.rb
index ffbc078074..5c84d0bea5 100644
--- a/spec/bundler/bundler/retry_spec.rb
+++ b/spec/bundler/bundler/retry_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Bundler::Retry do
end
it "returns the first valid result" do
- jobs = [proc { raise "foo" }, proc { :bar }, proc { raise "foo" }]
+ jobs = [proc { raise "job 1 failed" }, proc { :bar }, proc { raise "job 2 failed" }]
attempts = 0
result = Bundler::Retry.new(nil, nil, 3).attempt do
attempts += 1
@@ -78,4 +78,113 @@ RSpec.describe Bundler::Retry do
end
end
end
+
+ context "exponential backoff" do
+ it "can be disabled by setting base_delay to 0" do
+ attempts = 0
+ expect do
+ Bundler::Retry.new("test", [], 2, base_delay: 0).attempt do
+ attempts += 1
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ # Verify no sleep was called (implicitly - if sleep was called, timing would be different)
+ expect(attempts).to eq(3)
+ end
+
+ it "is enabled by default with 1 second base delay" do
+ original_base_delay = Bundler::Retry.default_base_delay
+ Bundler::Retry.default_base_delay = 1.0
+
+ attempts = 0
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 2, jitter: 0).attempt do
+ attempts += 1
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ expect(attempts).to eq(3)
+ expect(sleep_times.length).to eq(2)
+ # First retry: 1.0 * 2^0 = 1.0
+ expect(sleep_times[0]).to eq(1.0)
+ # Second retry: 1.0 * 2^1 = 2.0
+ expect(sleep_times[1]).to eq(2.0)
+ ensure
+ Bundler::Retry.default_base_delay = original_base_delay
+ end
+
+ it "sleeps with exponential backoff when base_delay is set" do
+ attempts = 0
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 2, base_delay: 1.0, jitter: 0).attempt do
+ attempts += 1
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ expect(attempts).to eq(3)
+ expect(sleep_times.length).to eq(2)
+ # First retry: 1.0 * 2^0 = 1.0
+ expect(sleep_times[0]).to eq(1.0)
+ # Second retry: 1.0 * 2^1 = 2.0
+ expect(sleep_times[1]).to eq(2.0)
+ end
+
+ it "respects max_delay" do
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 3, base_delay: 10.0, max_delay: 15.0, jitter: 0).attempt do
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ # First retry: 10.0 * 2^0 = 10.0
+ expect(sleep_times[0]).to eq(10.0)
+ # Second retry: 10.0 * 2^1 = 20.0, capped at 15.0
+ expect(sleep_times[1]).to eq(15.0)
+ # Third retry: 10.0 * 2^2 = 40.0, capped at 15.0
+ expect(sleep_times[2]).to eq(15.0)
+ end
+
+ it "adds jitter to delay" do
+ sleep_times = []
+
+ allow_any_instance_of(Bundler::Retry).to receive(:sleep) do |_instance, delay|
+ sleep_times << delay
+ end
+
+ expect do
+ Bundler::Retry.new("test", [], 2, base_delay: 1.0, jitter: 0.5).attempt do
+ raise "error"
+ end
+ end.to raise_error(StandardError)
+
+ expect(sleep_times.length).to eq(2)
+ # First retry should be between 1.0 and 1.5 (base + jitter)
+ expect(sleep_times[0]).to be >= 1.0
+ expect(sleep_times[0]).to be <= 1.5
+ # Second retry should be between 2.0 and 2.5
+ expect(sleep_times[1]).to be >= 2.0
+ expect(sleep_times[1]).to be <= 2.5
+ end
+ end
end
diff --git a/spec/bundler/bundler/ruby_dsl_spec.rb b/spec/bundler/bundler/ruby_dsl_spec.rb
index 2607f746e7..45a37c5795 100644
--- a/spec/bundler/bundler/ruby_dsl_spec.rb
+++ b/spec/bundler/bundler/ruby_dsl_spec.rb
@@ -178,11 +178,34 @@ RSpec.describe Bundler::RubyDsl do
let(:file_content) do
<<~TOML
[tools]
- ruby = "#{version}"
+ ruby = #{quote}#{version}#{quote}
TOML
end
- it_behaves_like "it stores the ruby version"
+ context "with double quotes" do
+ let(:quote) { '"' }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "with single quotes" do
+ let(:quote) { "'" }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "with mismatched quotes" do
+ let(:file_content) do
+ <<~TOML
+ [tools]
+ ruby = "#{version}'
+ TOML
+ end
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Bundler::InvalidArgumentError, "= is not a valid requirement on the Ruby version")
+ end
+ end
end
context "with a .tool-versions file format" do
@@ -210,6 +233,16 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
end
+
+ context "when the file does not exist" do
+ let(:ruby_version_file_path) { nil }
+ let(:ruby_version_arg) { nil }
+ let(:file) { "nonexistent.txt" }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Bundler::GemfileError, /Could not find version file nonexistent.txt/)
+ 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..0d41ec9901 100644
--- a/spec/bundler/bundler/ruby_version_spec.rb
+++ b/spec/bundler/bundler/ruby_version_spec.rb
@@ -100,7 +100,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
describe "#to_s" do
it "should return info string with the ruby version, patchlevel, engine, and engine version" do
- expect(subject.to_s).to eq("ruby 2.0.0p645 (jruby 2.0.1)")
+ expect(subject.to_s).to eq("ruby 2.0.0 (jruby 2.0.1)")
end
context "no patchlevel" do
@@ -115,7 +115,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
let(:engine) { "ruby" }
it "should return info string with the ruby version and patchlevel" do
- expect(subject.to_s).to eq("ruby 2.0.0p645")
+ expect(subject.to_s).to eq("ruby 2.0.0")
end
end
@@ -137,7 +137,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
end
- context "the versions, pathlevels, engines, and engine_versions match" do
+ shared_examples_for "the versions, engines, and engine_versions match" do
it "should return true" do
expect(subject).to eq(other_ruby_version)
end
@@ -152,7 +152,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
context "the patchlevels do not match" do
let(:other_patchlevel) { "21" }
- it_behaves_like "two ruby versions are not equal"
+ it_behaves_like "the versions, engines, and engine_versions match"
end
context "the engines do not match" do
@@ -228,9 +228,9 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
end
- shared_examples_for "there is a difference in the patchlevels" do
- it "should return a tuple with :patchlevel and the two different patchlevels" do
- expect(ruby_version.diff(other_ruby_version)).to eq([:patchlevel, patchlevel, other_patchlevel])
+ shared_examples_for "even there is a difference in the patchlevels" do
+ it "should return nil" do
+ expect(ruby_version.diff(other_ruby_version)).to be_nil
end
end
@@ -287,10 +287,10 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
it_behaves_like "there is a difference in the engine versions"
end
- context "detects patchlevel discrepancies last" do
+ context "ignores patchlevel discrepancies last" do
let(:other_patchlevel) { "643" }
- it_behaves_like "there is a difference in the patchlevels"
+ it_behaves_like "even there is a difference in the patchlevels"
end
context "successfully matches gem requirements" do
@@ -355,7 +355,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
let(:other_engine) { "ruby" }
let(:other_engine_version) { "2.0.5" }
- it_behaves_like "there is a difference in the patchlevels"
+ it_behaves_like "even there is a difference in the patchlevels"
end
context "successfully detects bad gem requirements with engine versions" do
@@ -389,7 +389,7 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
context "and comparing with a patchlevel that is not -1" do
let(:other_patchlevel) { "642" }
- it_behaves_like "there is a difference in the patchlevels"
+ it_behaves_like "even there is a difference in the patchlevels"
end
end
end
diff --git a/spec/bundler/bundler/rubygems_ext_spec.rb b/spec/bundler/bundler/rubygems_ext_spec.rb
new file mode 100644
index 0000000000..0fc528f78c
--- /dev/null
+++ b/spec/bundler/bundler/rubygems_ext_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "bundler/rubygems_ext"
+
+RSpec.describe Gem::SplitCompactIndexEntryOnFirstColon do
+ # Reproduces the RubyGems < 4.0.13 `Gem::Resolver::APISet::GemParser` that
+ # split each compact index entry on every colon, corrupting metadata values
+ # that themselves contain colons.
+ let(:legacy_parser_class) do
+ Class.new do
+ def parse_dependency(string)
+ dependency = string.split(":")
+ dependency[-1] = dependency[-1].split("&") if dependency.size > 1
+ dependency[0] = -dependency[0]
+ dependency
+ end
+ end
+ end
+
+ before { legacy_parser_class.prepend(described_class) }
+
+ it "preserves colon-bearing metadata values such as created_at timestamps" do
+ parser = legacy_parser_class.new
+
+ expect(parser.send(:parse_dependency, "created_at:2026-05-12T10:00:00Z")).to eq(["created_at", ["2026-05-12T10:00:00Z"]])
+ end
+
+ it "still parses ordinary name:requirement entries" do
+ parser = legacy_parser_class.new
+
+ expect(parser.send(:parse_dependency, "myrack:>= 1.0")).to eq(["myrack", [">= 1.0"]])
+ end
+
+ it "keeps parse_dependency private" do
+ parser = legacy_parser_class.new
+
+ expect { parser.parse_dependency("created_at:x") }.to raise_error(NoMethodError, /private method/)
+ end
+end
diff --git a/spec/bundler/bundler/settings_spec.rb b/spec/bundler/bundler/settings_spec.rb
index 592db81e9b..5e1aaaa555 100644
--- a/spec/bundler/bundler/settings_spec.rb
+++ b/spec/bundler/bundler/settings_spec.rb
@@ -119,6 +119,11 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
settings.set_local :ssl_verify_mode, "1"
expect(settings[:ssl_verify_mode]).to be 1
end
+
+ it "coerces cooldown to integer" do
+ settings.set_local :cooldown, "7"
+ expect(settings[:cooldown]).to be 7
+ end
end
context "when it's not possible to create the settings directory" do
@@ -318,12 +323,12 @@ 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")
+ bundle_config("BUNDLE_MY__PERSONAL.MYRACK" => "~/Work/git/myrack")
expect(settings["my.personal.myrack"]).to eq("~/Work/git/myrack")
end
it "converts older keys without trailing slashes and double underscore" do
- config("BUNDLE_MIRROR__HTTPS://RUBYGEMS.ORG" => "http://example-mirror.rubygems.org")
+ bundle_config("BUNDLE_MIRROR__HTTPS://RUBYGEMS.ORG" => "http://example-mirror.rubygems.org")
expect(settings["mirror.https://rubygems.org/"]).to eq("http://example-mirror.rubygems.org")
end
@@ -337,7 +342,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
it "converts older keys with dashes" do
- config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
+ bundle_config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
expect(Bundler.ui).to receive(:warn).with(
"Your #{bundled_app(".bundle/config")} config includes `BUNDLE_MY-PERSONAL-SERVER__ORG`, which contains the dash character (`-`).\n" \
"This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \
@@ -347,8 +352,29 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
it "reads newer keys format properly" do
- config("BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/" => "http://example-mirror.rubygems.org")
+ bundle_config("BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/" => "http://example-mirror.rubygems.org")
expect(settings["mirror.https://rubygems.org/"]).to eq("http://example-mirror.rubygems.org")
end
end
+
+ describe "default_cli_command validation" do
+ it "accepts 'install' as a valid value" do
+ expect { settings.set_local("default_cli_command", "install") }.not_to raise_error
+ end
+
+ it "accepts 'cli_help' as a valid value" do
+ expect { settings.set_local("default_cli_command", "cli_help") }.not_to raise_error
+ end
+
+ it "rejects invalid values" do
+ expect { settings.set_local("default_cli_command", "invalid") }.to raise_error(
+ Bundler::InvalidOption,
+ /Setting `default_cli_command` to "invalid" failed:\n - default_cli_command must be either 'install' or 'cli_help'\n - must be one of: install, cli_help/
+ )
+ end
+
+ it "accepts nil values" do
+ expect { settings.set_local("default_cli_command", nil) }.not_to raise_error
+ end
+ end
end
diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb
index d37b63bbec..41115aa667 100644
--- a/spec/bundler/bundler/shared_helpers_spec.rb
+++ b/spec/bundler/bundler/shared_helpers_spec.rb
@@ -159,7 +159,7 @@ RSpec.describe Bundler::SharedHelpers do
let(:pwd_stub) { nil }
it "returns the current absolute path" do
- expect(subject.pwd).to eq(source_root)
+ expect(subject.pwd).to eq(git_root.to_s)
end
end
@@ -423,7 +423,7 @@ RSpec.describe Bundler::SharedHelpers do
it "sets BUNDLE_BIN_PATH to the bundle executable file" do
subject.set_bundle_environment
bin_path = ENV["BUNDLE_BIN_PATH"]
- expect(bin_path).to eq(bindir.join("bundle").to_s)
+ expect(bin_path).to eq(exedir.join("bundle").to_s)
expect(File.exist?(bin_path)).to be true
end
end
@@ -515,34 +515,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 c350904994..1f10ca4b07 100644
--- a/spec/bundler/bundler/source/git/git_proxy_spec.rb
+++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe Bundler::Source::Git::GitProxy do
let(:path) { Pathname("path") }
- let(:uri) { "https://github.com/rubygems/rubygems.git" }
+ let(:uri) { "https://github.com/ruby/rubygems.git" }
let(:ref) { nil }
let(:branch) { nil }
let(:tag) { nil }
@@ -10,7 +10,9 @@ RSpec.describe Bundler::Source::Git::GitProxy do
let(:revision) { nil }
let(:git_source) { nil }
let(:clone_result) { double(Process::Status, success?: true) }
+ let(:fail_result) { double(Process::Status, success?: false) }
let(:base_clone_args) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch"] }
+ let(:base_fetch_args) { ["fetch", "--force", "--quiet", "--no-tags", "--depth", "1"] }
subject(:git_proxy) { described_class.new(path, uri, options, revision, git_source) }
context "with explicit ref" do
@@ -64,7 +66,7 @@ RSpec.describe Bundler::Source::Git::GitProxy 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])
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/ruby/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
@@ -72,13 +74,13 @@ RSpec.describe Bundler::Source::Git::GitProxy do
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])
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/ruby/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "does not add username and password to mismatched URI" do
- Bundler.settings.temporary("https://u:p@github.com/rubygems/rubygems-mismatch.git" => "u:p") do
+ Bundler.settings.temporary("https://u:p@github.com/ruby/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])
subject.checkout
@@ -87,7 +89,7 @@ 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"
+ original = "https://orig:info@github.com/ruby/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])
@@ -99,7 +101,7 @@ 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(described_class).to receive(:full_version).
and_return("git version 1.2.3")
end
@@ -114,7 +116,7 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(described_class).to receive(:full_version).
and_return("git version 1.2.3 (Apple Git-BS)")
end
@@ -129,7 +131,7 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(described_class).to receive(:full_version).
and_return("git version 1.2.3.msysgit.0")
end
@@ -146,8 +148,9 @@ 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").
- and_return("git version 1.2.3")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3", "", status])
end
it "returns the git version number" do
@@ -157,8 +160,9 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
- and_return("git version 1.2.3 (Apple Git-BS)")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3 (Apple Git-BS)", "", status])
end
it "does not strip out OSX specific additions in the version string" do
@@ -168,8 +172,9 @@ RSpec.describe Bundler::Source::Git::GitProxy do
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
- and_return("git version 1.2.3.msysgit.0")
+ status = double("success?" => true)
+ expect(Open3).to receive(:capture3).with("git", "--version").
+ and_return(["git version 1.2.3.msysgit.0", "", status])
end
it "does not strip out msysgit specific additions in the version string" do
@@ -199,14 +204,13 @@ RSpec.describe Bundler::Source::Git::GitProxy do
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) }
+ let(:uri) { "http://github.com/ruby/rubygems.git" }
+ let(:clone_args_without_depth) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--single-branch"] }
- it "retries without --depth when git url is http and fails" do
+ it "retries clone without --depth when dumb http transport 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])
+ expect(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_result])
+ expect(git_proxy).to receive(:capture).with([*clone_args_without_depth, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
@@ -252,4 +256,99 @@ RSpec.describe Bundler::Source::Git::GitProxy do
end
end
end
+
+ describe "#checkout" do
+ context "when the repository isn't cloned" do
+ before do
+ allow(path).to receive(:exist?).and_return(false)
+ end
+
+ it "clones the repository" 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])
+ subject.checkout
+ end
+ end
+
+ context "when the repository is cloned" do
+ before do
+ allow(path).to receive(:exist?).and_return(true)
+ end
+
+ context "with a locked revision" do
+ let(:revision) { Digest::SHA1.hexdigest("ruby") }
+
+ context "when the revision exists locally" do
+ it "uses the cached revision" do
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:git).with("cat-file", "-e", revision, dir: path).and_return(true)
+ subject.checkout
+ end
+ end
+
+ context "when the revision doesn't exist locally" do
+ it "fetches the specific revision" do
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:git).with("cat-file", "-e", revision, dir: path).and_raise(Bundler::GitError)
+ expect(git_proxy).to receive(:capture).with(["fetch", "--force", "--quiet", "--no-tags", "--depth", "1", "--", uri, "#{revision}:refs/#{revision}-sha"], path).and_return(["", "", clone_result])
+ subject.checkout
+ end
+ end
+ end
+
+ context "with no explicit ref" do
+ it "fetches the HEAD revision" do
+ parsed_revision = Digest::SHA1.hexdigest("ruby")
+ allow(git_proxy).to receive(:git_local).with("rev-parse", "--abbrev-ref", "HEAD", dir: path).and_return(parsed_revision)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with(["fetch", "--force", "--quiet", "--no-tags", "--depth", "1", "--", uri, "refs/heads/#{parsed_revision}:refs/heads/#{parsed_revision}"], path).and_return(["", "", clone_result])
+ subject.checkout
+ end
+ end
+
+ context "with a commit ref" do
+ let(:ref) { Digest::SHA1.hexdigest("ruby") }
+
+ context "when the revision exists locally" do
+ it "uses the cached revision" do
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:git).with("cat-file", "-e", ref, dir: path).and_return(true)
+ subject.checkout
+ end
+ end
+
+ context "when the revision doesn't exist locally" do
+ it "fetches the specific revision" do
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:git).with("cat-file", "-e", ref, dir: path).and_raise(Bundler::GitError)
+ expect(git_proxy).to receive(:capture).with(["fetch", "--force", "--quiet", "--no-tags", "--depth", "1", "--", uri, "#{ref}:refs/#{ref}-sha"], path).and_return(["", "", clone_result])
+ subject.checkout
+ end
+ end
+ end
+
+ context "with a non-commit ref" do
+ let(:ref) { "HEAD" }
+
+ it "fetches all revisions" do
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with(["fetch", "--force", "--quiet", "--no-tags", "--", uri, "refs/*:refs/*"], path).and_return(["", "", clone_result])
+ subject.checkout
+ end
+ end
+
+ context "URI is HTTP" do
+ let(:uri) { "http://github.com/ruby/rubygems.git" }
+
+ it "retries fetch without --depth when dumb http transport fails" do
+ parsed_revision = Digest::SHA1.hexdigest("ruby")
+ allow(git_proxy).to receive(:git_local).with("rev-parse", "--abbrev-ref", "HEAD", dir: path).and_return(parsed_revision)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with([*base_fetch_args, "--", uri, "refs/heads/#{parsed_revision}:refs/heads/#{parsed_revision}"], path).and_return(["", "dumb http transport does not support shallow capabilities", fail_result])
+ expect(git_proxy).to receive(:capture).with(["fetch", "--force", "--quiet", "--no-tags", "--", uri, "refs/heads/#{parsed_revision}:refs/heads/#{parsed_revision}"], path).and_return(["", "", clone_result])
+ subject.checkout
+ end
+ end
+ end
+ end
end
diff --git a/spec/bundler/bundler/source/rubygems/remote_spec.rb b/spec/bundler/bundler/source/rubygems/remote_spec.rb
index f2214ca8fe..27430d4a3b 100644
--- a/spec/bundler/bundler/source/rubygems/remote_spec.rb
+++ b/spec/bundler/bundler/source/rubygems/remote_spec.rb
@@ -169,4 +169,39 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
end
end
+
+ describe "#cooldown" do
+ it "is nil by default" do
+ expect(remote(uri_no_auth).cooldown).to be_nil
+ end
+
+ it "returns the value passed to the constructor" do
+ r = Bundler::Source::Rubygems::Remote.new(uri_no_auth, cooldown: 7)
+ expect(r.cooldown).to eq(7)
+ end
+ end
+
+ describe "#effective_cooldown" do
+ it "returns the per-remote value when no override is set" do
+ r = Bundler::Source::Rubygems::Remote.new(uri_no_auth, cooldown: 7)
+ expect(r.effective_cooldown).to eq(7)
+ end
+
+ it "returns nil when neither override nor per-remote value is set" do
+ expect(remote(uri_no_auth).effective_cooldown).to be_nil
+ end
+
+ it "settings override per-remote value" do
+ r = Bundler::Source::Rubygems::Remote.new(uri_no_auth, cooldown: 7)
+ Bundler.settings.temporary(cooldown: 14) do
+ expect(r.effective_cooldown).to eq(14)
+ end
+ end
+
+ it "settings override even when per-remote value is absent" do
+ Bundler.settings.temporary(cooldown: 14) do
+ expect(remote(uri_no_auth).effective_cooldown).to eq(14)
+ end
+ end
+ end
end
diff --git a/spec/bundler/bundler/source/rubygems_spec.rb b/spec/bundler/bundler/source/rubygems_spec.rb
index 884fa81046..feb787498e 100644
--- a/spec/bundler/bundler/source/rubygems_spec.rb
+++ b/spec/bundler/bundler/source/rubygems_spec.rb
@@ -44,4 +44,61 @@ RSpec.describe Bundler::Source::Rubygems do
end
end
end
+
+ describe "#clear_cache" do
+ it "invalidates memoized indexes so subsequent reads rebuild them" do
+ source = described_class.new
+
+ first_specs = source.specs
+ first_installed = source.send(:installed_specs)
+ first_default = source.send(:default_specs)
+ first_cached = source.send(:cached_specs)
+
+ expect(source.specs).to equal(first_specs)
+ expect(source.send(:installed_specs)).to equal(first_installed)
+ expect(source.send(:default_specs)).to equal(first_default)
+ expect(source.send(:cached_specs)).to equal(first_cached)
+
+ source.clear_cache
+
+ expect(source.specs).not_to equal(first_specs)
+ expect(source.send(:installed_specs)).not_to equal(first_installed)
+ expect(source.send(:default_specs)).not_to equal(first_default)
+ expect(source.send(:cached_specs)).not_to equal(first_cached)
+ end
+
+ it "reflects newly-discovered installed gems after clear_cache" do
+ source = described_class.new
+ foo = Gem::Specification.new("foo", "1.0.0")
+ bar = Gem::Specification.new("bar", "1.0.0")
+
+ allow(Bundler.rubygems).to receive(:installed_specs).and_return([foo])
+ expect(source.send(:installed_specs).search("bar")).to be_empty
+
+ allow(Bundler.rubygems).to receive(:installed_specs).and_return([foo, bar])
+ expect(source.send(:installed_specs).search("bar")).to be_empty
+
+ source.clear_cache
+
+ expect(source.send(:installed_specs).search("bar")).not_to be_empty
+ end
+ end
+
+ describe "log debug information" do
+ it "log the time spent downloading and installing a gem" do
+ build_repo2 do
+ build_gem "warning"
+ end
+
+ gemfile_content = <<~G
+ source "https://gem.repo2"
+ gem "warning"
+ G
+
+ stdout = install_gemfile(gemfile_content, env: { "DEBUG" => "1" })
+
+ expect(stdout).to match(/Downloaded warning in: \d+\.\d+s/)
+ expect(stdout).to match(/Installed warning in: \d+\.\d+s/)
+ end
+ end
end
diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb
index 13453cb2a3..61bd99b063 100644
--- a/spec/bundler/bundler/source_list_spec.rb
+++ b/spec/bundler/bundler/source_list_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Bundler::SourceList do
subject(:source_list) { Bundler::SourceList.new }
- let(:rubygems_aggregate) { Bundler::Source::Rubygems.new }
+ let(:global_rubygems_source) { Bundler::Source::Rubygems.new }
let(:metadata_source) { Bundler::Source::Metadata.new }
describe "adding sources" do
@@ -118,17 +118,23 @@ RSpec.describe Bundler::SourceList do
describe "#add_global_rubygems_remote" do
let!(:returned_source) { source_list.add_global_rubygems_remote("https://rubygems.org/") }
- it "returns the aggregate rubygems source" do
+ it "returns the global rubygems source" do
expect(returned_source).to be_instance_of(Bundler::Source::Rubygems)
end
- it "adds the provided remote to the beginning of the aggregate source" do
+ it "adds the provided remote to the beginning of the global 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/"),
]
end
+
+ it "records the per-remote cooldown when supplied" do
+ source_list.add_global_rubygems_remote("https://othersource.org", cooldown: 7)
+ expect(returned_source.cooldown_for(Gem::URI("https://othersource.org/"))).to eq(7)
+ expect(returned_source.cooldown_for(Gem::URI("https://rubygems.org/"))).to be_nil
+ end
end
describe "#add_plugin_source" do
@@ -156,21 +162,21 @@ RSpec.describe Bundler::SourceList do
end
describe "#all_sources" do
- it "includes the aggregate rubygems source when rubygems sources have been added" do
+ it "includes the global rubygems source when rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"])
source_list.add_path_source("path" => "/path/to/gem")
source_list.add_plugin_source("new_source", "uri" => "https://some.url/a")
- expect(source_list.all_sources).to include rubygems_aggregate
+ expect(source_list.all_sources).to include global_rubygems_source
end
- it "includes the aggregate rubygems source when no rubygems sources have been added" do
+ it "includes the global rubygems source when no rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_path_source("path" => "/path/to/gem")
source_list.add_plugin_source("new_source", "uri" => "https://some.url/a")
- expect(source_list.all_sources).to include rubygems_aggregate
+ expect(source_list.all_sources).to include global_rubygems_source
end
it "returns sources of the same type in the reverse order that they were added" do
@@ -204,7 +210,7 @@ RSpec.describe Bundler::SourceList do
Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]),
- rubygems_aggregate,
+ global_rubygems_source,
metadata_source,
]
end
@@ -297,19 +303,19 @@ RSpec.describe Bundler::SourceList do
end
describe "#rubygems_sources" do
- it "includes the aggregate rubygems source when rubygems sources have been added" do
+ it "includes the global rubygems source when rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"])
source_list.add_path_source("path" => "/path/to/gem")
- expect(source_list.rubygems_sources).to include rubygems_aggregate
+ expect(source_list.rubygems_sources).to include global_rubygems_source
end
- it "returns only the aggregate rubygems source when no rubygems sources have been added" do
+ it "returns only the global rubygems source when no rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
source_list.add_path_source("path" => "/path/to/gem")
- expect(source_list.rubygems_sources).to eq [rubygems_aggregate]
+ expect(source_list.rubygems_sources).to eq [global_rubygems_source]
end
it "returns rubygems sources in the reverse order that they were added" do
@@ -331,7 +337,7 @@ RSpec.describe Bundler::SourceList do
Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]),
Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]),
- rubygems_aggregate,
+ global_rubygems_source,
]
end
end
@@ -442,6 +448,16 @@ RSpec.describe Bundler::SourceList do
end
end
+ describe "#clear_cache" do
+ let(:rubygems_source) { source_list.add_rubygems_source("remotes" => ["https://rubygems.org"]) }
+
+ it "calls #clear_cache on all rubygems sources" do
+ expect(rubygems_source).to receive(:clear_cache)
+ expect(source_list.global_rubygems_source).to receive(:clear_cache)
+ source_list.clear_cache
+ end
+ end
+
describe "implicit_global_source?" do
context "when a global rubygem source provided" do
it "returns a falsy value" do
diff --git a/spec/bundler/bundler/spec_set_spec.rb b/spec/bundler/bundler/spec_set_spec.rb
index c4b6676223..1e1ceadf26 100644
--- a/spec/bundler/bundler/spec_set_spec.rb
+++ b/spec/bundler/bundler/spec_set_spec.rb
@@ -43,6 +43,30 @@ RSpec.describe Bundler::SpecSet do
spec = described_class.new(specs).find_by_name_and_platform("b", platform)
expect(spec).to eq platform_spec
end
+
+ it "returns nil when the name is not present" do
+ spec = described_class.new(specs).find_by_name_and_platform("missing", platform)
+ expect(spec).to be_nil
+ end
+
+ it "returns nil when the name exists but no spec is installable on the requested platform" do
+ incompatible_platform = Gem::Platform.new("java")
+ incompatible_spec = build_spec("a", "1.0", incompatible_platform).first
+
+ spec = described_class.new([incompatible_spec]).find_by_name_and_platform("a", platform)
+ expect(spec).to be_nil
+ end
+
+ it "returns the first installable spec for the given name in insertion order" do
+ later_platform_spec = build_spec("b", "3.0", platform).first
+ specs = [
+ platform_spec,
+ later_platform_spec,
+ ]
+
+ spec = described_class.new(specs).find_by_name_and_platform("b", platform)
+ expect(spec).to eq platform_spec
+ end
end
describe "#to_a" do
@@ -55,5 +79,70 @@ RSpec.describe Bundler::SpecSet do
d-2.0
]
end
+
+ it "puts rake first when present" do
+ specs = [
+ build_spec("a", "1.0") {|s| s.dep "rake", ">= 0" },
+ build_spec("rake", "13.0"),
+ ].flatten
+
+ expect(described_class.new(specs).to_a.map(&:full_name)).to eq %w[
+ rake-13.0
+ a-1.0
+ ]
+ end
+ end
+
+ describe "#complete_platform" do
+ let(:platform) { Gem::Platform.new("x86_64-linux") }
+
+ let(:platform_variant) do
+ build_spec("needs_old_ruby", "1.0", platform).first.tap do |s|
+ s.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}")
+ end
+ end
+
+ let(:lazy_spec) do
+ lazy = Bundler::LazySpecification.new("needs_old_ruby", Gem::Version.new("1.0"), Gem::Platform::RUBY)
+ lazy.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}")
+ source = double("source")
+ source_specs = double("source_specs")
+ allow(source).to receive(:specs).and_return(source_specs)
+ allow(source_specs).to receive(:search).
+ with(["needs_old_ruby", Gem::Version.new("1.0")]).and_return([platform_variant])
+ lazy.source = source
+ lazy
+ end
+
+ it "rejects a platform variant whose strict metadata is incompatible when no override is attached" do
+ set = described_class.new([lazy_spec])
+ expect(set.send(:complete_platform, platform)).to be(false)
+ end
+
+ it "accepts a platform variant when the LazySpec carries an override that allows it" do
+ lazy_spec.overrides = [Bundler::Override.new("needs_old_ruby", :required_ruby_version, :ignore_upper)]
+ set = described_class.new([lazy_spec])
+ expect(set.send(:complete_platform, platform)).to be(true)
+ end
+
+ it "carries overrides onto a synthesized LazySpec so a follow-up complete_platform still honors them" do
+ override = Bundler::Override.new("needs_old_ruby", :required_ruby_version, :ignore_upper)
+ lazy_spec.overrides = [override]
+ second_platform = Gem::Platform.new("aarch64-linux")
+ second_variant = build_spec("needs_old_ruby", "1.0", second_platform).first.tap do |s|
+ s.required_ruby_version = Gem::Requirement.new("< #{Gem.ruby_version}")
+ end
+ allow(lazy_spec.source.specs).to receive(:search).
+ with(["needs_old_ruby", Gem::Version.new("1.0")]).and_return([platform_variant, second_variant])
+
+ set = described_class.new([lazy_spec])
+ expect(set.send(:complete_platform, platform)).to be(true)
+ # The synthesized x86_64-linux variant is now in the set. If lookup
+ # picks it as exemplar for the next platform check, the override list
+ # must still be reachable via its overrides accessor.
+ synthesized = set.to_a.find {|s| s.platform == platform }
+ expect(synthesized.overrides).to eq([override])
+ expect(set.send(:complete_platform, second_platform)).to be(true)
+ end
end
end
diff --git a/spec/bundler/bundler/specifications/foo.gemspec b/spec/bundler/bundler/specifications/foo.gemspec
index 81b77d0c86..19b7724e81 100644
--- a/spec/bundler/bundler/specifications/foo.gemspec
+++ b/spec/bundler/bundler/specifications/foo.gemspec
@@ -8,6 +8,6 @@ Gem::Specification.new do |s|
s.version = "1.0.0"
s.loaded_from = __FILE__
s.extensions = "ext/foo"
- s.required_ruby_version = ">= 3.1.0"
+ s.required_ruby_version = ">= 3.2.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..f2faa2ea64 100644
--- a/spec/bundler/bundler/stub_specification_spec.rb
+++ b/spec/bundler/bundler/stub_specification_spec.rb
@@ -49,10 +49,14 @@ RSpec.describe Bundler::StubSpecification do
expect(stub.missing_extensions?).to be false
end
- it "returns true if not manually_installed?" do
+ it "returns #{RUBY_ENGINE == "jruby" ? "false" : "true"} if not manually_installed?" do
stub = described_class.from_stub(with_bundler_stub_spec)
stub.installed_by_version = Gem::Version.new(1)
- expect(stub.missing_extensions?).to be true
+ if RUBY_ENGINE == "jruby"
+ expect(stub.missing_extensions?).to be false
+ else
+ expect(stub.missing_extensions?).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..83f147191e 100644
--- a/spec/bundler/bundler/ui/shell_spec.rb
+++ b/spec/bundler/bundler/ui/shell_spec.rb
@@ -81,4 +81,32 @@ RSpec.describe Bundler::UI::Shell do
end
end
end
+
+ describe "threads" do
+ it "is thread safe when using with_level" do
+ stop_thr1 = false
+ stop_thr2 = false
+
+ expect(subject.level).to eq("debug")
+
+ thr1 = Thread.new do
+ subject.silence do
+ sleep(0.1) until stop_thr1
+ end
+
+ stop_thr2 = true
+ end
+
+ thr2 = Thread.new do
+ subject.silence do
+ stop_thr1 = true
+ sleep(0.1) until stop_thr2
+ end
+ end
+
+ [thr1, thr2].each(&:join)
+
+ expect(subject.level).to eq("debug")
+ end
+ end
end
diff --git a/spec/bundler/bundler/uri_normalizer_spec.rb b/spec/bundler/bundler/uri_normalizer_spec.rb
new file mode 100644
index 0000000000..1308e86014
--- /dev/null
+++ b/spec/bundler/bundler/uri_normalizer_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::URINormalizer do
+ describe ".normalize_suffix" do
+ context "when trailing_slash is true" do
+ it "adds a trailing slash when missing" do
+ expect(described_class.normalize_suffix("https://example.com", trailing_slash: true)).to eq("https://example.com/")
+ end
+
+ it "keeps the trailing slash when present" do
+ expect(described_class.normalize_suffix("https://example.com/", trailing_slash: true)).to eq("https://example.com/")
+ end
+ end
+
+ context "when trailing_slash is false" do
+ it "removes a trailing slash when present" do
+ expect(described_class.normalize_suffix("https://example.com/", trailing_slash: false)).to eq("https://example.com")
+ end
+
+ it "keeps the value unchanged when no trailing slash exists" do
+ expect(described_class.normalize_suffix("https://example.com", trailing_slash: false)).to eq("https://example.com")
+ end
+ end
+ end
+end
diff --git a/spec/bundler/bundler/worker_spec.rb b/spec/bundler/bundler/worker_spec.rb
index e4ebbd2932..2ad2845e37 100644
--- a/spec/bundler/bundler/worker_spec.rb
+++ b/spec/bundler/bundler/worker_spec.rb
@@ -20,6 +20,26 @@ RSpec.describe Bundler::Worker do
end
end
+ describe "priority queue" do
+ it "process elements from the priority queue first" do
+ processed_elements = []
+
+ function = proc do |element, _|
+ processed_elements << element
+ end
+
+ worker = described_class.new(1, "Spec Worker", function)
+ worker.instance_variable_set(:@threads, []) # Prevent the enqueueing from starting work.
+ worker.enq("Normal element")
+ worker.enq("Priority element", priority: true)
+ worker.send(:create_threads)
+
+ worker.stop
+
+ expect(processed_elements).to eq(["Priority element", "Normal element"])
+ end
+ end
+
describe "handling interrupts" do
let(:status) do
pid = Process.fork do
diff --git a/spec/bundler/cache/cache_path_spec.rb b/spec/bundler/cache/cache_path_spec.rb
index d5bd14965b..2a280ea858 100644
--- a/spec/bundler/cache/cache_path_spec.rb
+++ b/spec/bundler/cache/cache_path_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "bundle package" do
context "with config cache_path" do
it "caches gems at given path" do
- bundle "config set cache_path vendor/cache-foo"
+ bundle_config "cache_path vendor/cache-foo"
bundle :cache
expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
end
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb
index 780972b9af..198279d84c 100644
--- a/spec/bundler/cache/gems_spec.rb
+++ b/spec/bundler/cache/gems_spec.rb
@@ -78,13 +78,13 @@ RSpec.describe "bundle cache" do
end
context "using system gems" do
- before { bundle "config set path.system true" }
+ before { bundle_config "path.system true" }
let(:path) { system_gem_path }
it_behaves_like "when there are only gemsources"
end
context "installing into a local path" do
- before { bundle "config set path ./.bundle" }
+ before { bundle_config "path ./.bundle" }
let(:path) { local_gem_path }
it_behaves_like "when there are only gemsources"
end
@@ -136,7 +136,7 @@ RSpec.describe "bundle cache" do
gem "json"
G
- bundle "config set cache_all_platforms true"
+ bundle_config "cache_all_platforms true"
bundle :cache
expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
@@ -157,14 +157,14 @@ RSpec.describe "bundle cache" do
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"
+ bundle_config "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"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -226,7 +226,7 @@ RSpec.describe "bundle cache" do
it "re-caches during install" do
setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
bundle :install
expect(out).to include("Updating files in vendor/cache")
expect(cached_gem("myrack-1.0.0")).to exist
@@ -291,7 +291,7 @@ RSpec.describe "bundle cache" do
expect(cached_gem("platform_specific-1.0-java")).to exist
end
- pristine_system_gems :bundler
+ pristine_system_gems
simulate_platform "x86-darwin-100" do
install_gemfile <<-G
@@ -307,13 +307,13 @@ RSpec.describe "bundle cache" do
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
+ FileUtils.rm_rf cached_myrack
build_gem "myrack", "1.0.0",
path: cached_myrack.parent,
rubygems_version: "1.3.2"
FileUtils.rm_r default_bundle_path
- system_gems :bundler
+ default_system_gems
FileUtils.rm bundled_app_lock
bundle :install, raise_on_error: false
@@ -338,7 +338,7 @@ RSpec.describe "bundle cache" do
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
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
checksums = checksums_section do |c|
@@ -346,7 +346,7 @@ RSpec.describe "bundle cache" do
end
FileUtils.rm_r default_bundle_path
- system_gems :bundler
+ default_system_gems
lockfile <<-L
GEM
@@ -362,16 +362,16 @@ RSpec.describe "bundle cache" do
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
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
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
+ FileUtils.rm_rf cached_gem("myrack-1.0.0")
build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
- pristine_system_gems :bundler
+ pristine_system_gems
lockfile <<-L
GEM
diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb
index b337882a6e..f0976ecac7 100644
--- a/spec/bundler/cache/git_spec.rb
+++ b/spec/bundler/cache/git_spec.rb
@@ -13,6 +13,22 @@ RSpec.describe "git base name" do
end
RSpec.describe "bundle cache with git" do
+ it "does not copy repository to vendor cache when cache_all set to false" do
+ git = build_git "foo"
+ ref = git.ref_for("main", 11)
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle_config "cache_all false"
+ bundle :cache
+ expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).not_to exist
+
+ expect(the_bundle).to include_gems "foo 1.0"
+ end
+
it "copies repository to vendor cache and uses it" do
git = build_git "foo"
ref = git.ref_for("main", 11)
@@ -22,7 +38,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist
@@ -41,9 +56,8 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
@@ -61,7 +75,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
bundle :cache
@@ -79,7 +92,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
update_git "foo" do |s|
@@ -109,7 +121,6 @@ RSpec.describe "bundle cache with git" do
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
update_git "foo" do |s|
@@ -140,7 +151,6 @@ RSpec.describe "bundle cache with git" do
bundle %(config set local.foo #{lib_path("foo-1.0")})
bundle "install"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-invalid-#{ref}")).to exist
@@ -161,12 +171,12 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
- pristine_system_gems :bundler
+ pristine_system_gems
with_path_as "" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
bundle "install --local"
expect(the_bundle).to include_gem "foo 1.0"
end
@@ -179,11 +189,10 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true
- pristine_system_gems :bundler
- bundle "config set frozen true"
+ pristine_system_gems
+ bundle_config "frozen true"
bundle "install --local --verbose"
expect(out).to_not include("Fetching")
expect(the_bundle).to include_gem "foo 1.0"
@@ -196,11 +205,10 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true
- pristine_system_gems :bundler
- bundle "config set frozen true"
+ pristine_system_gems
+ bundle_config "frozen true"
bundle "install --local --verbose"
expect(out).to_not include("Fetching")
expect(the_bundle).to include_gem "foo 1.0"
@@ -213,11 +221,10 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true
- pristine_system_gems :bundler
- bundle "config set frozen true"
+ pristine_system_gems
+ bundle_config "frozen true"
# Remove untracked files (including the empty refs dir in the cache)
Dir.chdir(bundled_app) do
@@ -241,9 +248,8 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set global_gem_cache false"
- bundle "config set cache_all true"
- bundle "config path vendor/bundle"
+ bundle_config "global_gem_cache false"
+ bundle_config "path vendor/bundle"
bundle :install
# Simulate old cache by copying the real cache folder to vendor/cache
@@ -273,9 +279,8 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set global_gem_cache false"
- bundle "config set cache_all true"
- bundle "config path vendor/bundle"
+ bundle_config "global_gem_cache false"
+ bundle_config "path vendor/bundle"
bundle :install
# Simulate old cache by copying the real cache folder to vendor/cache
@@ -303,9 +308,8 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set global_gem_cache false"
- bundle "config set cache_all true"
- bundle "config path vendor/bundle"
+ bundle_config "global_gem_cache false"
+ bundle_config "path vendor/bundle"
bundle :install
# Simulate old cache by copying the real cache folder to vendor/cache
@@ -342,7 +346,6 @@ RSpec.describe "bundle cache with git" do
G
ref = git.ref_for("main", 11)
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}")).to exist
@@ -362,7 +365,6 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
ref = git.ref_for("main", 11)
@@ -377,12 +379,11 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache, "all-platforms" => true, :install => false
- pristine_system_gems :bundler
+ pristine_system_gems
with_path_as "" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
bundle :install, local: true
expect(the_bundle).to include_gem "foo 1.0"
end
@@ -417,7 +418,7 @@ RSpec.describe "bundle cache with git" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
# Simulate an old incorrect situation where vendor/cache would be the install location of git gems
@@ -436,7 +437,6 @@ RSpec.describe "bundle cache with git" do
source "https://gem.repo1"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
# The algorithm for the cache location for a git checkout is
# in Bundle::Source::Git#cache_path
@@ -452,7 +452,7 @@ RSpec.describe "bundle cache with git" 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)
+ # nor in .bundle (bundler 4 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
@@ -498,7 +498,6 @@ RSpec.describe "bundle cache with git" do
end
FileUtils.mkdir_p(bundled_app("vendor/cache"))
- bundle "config set cache_all all"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb
index 966cb6f531..42648aea1f 100644
--- a/spec/bundler/cache/path_spec.rb
+++ b/spec/bundler/cache/path_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{bundled_app("lib/foo")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
expect(the_bundle).to include_gems "foo 1.0"
@@ -23,7 +22,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0")).to exist
expect(bundled_app("vendor/cache/foo-1.0/.bundlecache")).to be_file
@@ -42,7 +40,6 @@ RSpec.describe "bundle cache with path" do
gem "#{libname}", :path => '#{libpath}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/#{libname}")).to exist
expect(bundled_app("vendor/cache/#{libname}/.bundlecache")).to be_file
@@ -58,7 +55,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
build_lib "foo" do |s|
@@ -81,7 +77,6 @@ RSpec.describe "bundle cache with path" do
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0")).to exist
@@ -97,20 +92,21 @@ 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 if cache_all is set to false" do
build_lib "foo"
install_gemfile <<-G
source "https://gem.repo1"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
+ bundle_config "cache_all false"
bundle :cache
expect(err).to be_empty
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" do
build_lib "foo"
install_gemfile <<-G
@@ -122,48 +118,4 @@ RSpec.describe "bundle cache with path" do
expect(err).to be_empty
expect(bundled_app("vendor/cache/foo-1.0")).to exist
end
-
- it "stores the given flag" do
- build_lib "foo"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :path => '#{lib_path("foo-1.0")}'
- G
-
- bundle "config set cache_all true"
- bundle :cache
- build_lib "bar"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :path => '#{lib_path("foo-1.0")}'
- gem "bar", :path => '#{lib_path("bar-1.0")}'
- G
-
- bundle :cache
- expect(bundled_app("vendor/cache/bar-1.0")).to exist
- end
-
- it "can rewind chosen configuration" do
- build_lib "foo"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :path => '#{lib_path("foo-1.0")}'
- G
-
- bundle "config set cache_all true"
- bundle :cache
- build_lib "baz"
-
- gemfile <<-G
- source "https://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
- expect(bundled_app("vendor/cache/baz-1.0")).not_to exist
- end
end
diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb
index 2676b06c78..162650f2e5 100644
--- a/spec/bundler/commands/add_spec.rb
+++ b/spec/bundler/commands/add_spec.rb
@@ -38,34 +38,34 @@ RSpec.describe "bundle add" do
end
describe "without version specified" do
- it "version requirement becomes ~> major.minor.patch when resolved version is < 1.0" do
+ it "version requirement becomes >= major.minor.patch when resolved version is < 1.0" do
bundle "add 'bar'"
- expect(bundled_app_gemfile.read).to match(/gem "bar", "~> 0.12.3"/)
+ expect(bundled_app_gemfile.read).to match(/gem "bar", ">= 0.12.3"/)
expect(the_bundle).to include_gems "bar 0.12.3"
end
- it "version requirement becomes ~> major.minor when resolved version is > 1.0" do
+ it "version requirement becomes >= major.minor when resolved version is > 1.0" do
bundle "add 'baz'"
- expect(bundled_app_gemfile.read).to match(/gem "baz", "~> 1.2"/)
+ expect(bundled_app_gemfile.read).to match(/gem "baz", ">= 1.2"/)
expect(the_bundle).to include_gems "baz 1.2.3"
end
- it "version requirement becomes ~> major.minor.patch.pre when resolved version is < 1.0" do
+ it "version requirement becomes >= major.minor.patch.pre when resolved version is < 1.0" do
bundle "add 'cat'"
- expect(bundled_app_gemfile.read).to match(/gem "cat", "~> 0.12.3.pre"/)
+ expect(bundled_app_gemfile.read).to match(/gem "cat", ">= 0.12.3.pre"/)
expect(the_bundle).to include_gems "cat 0.12.3.pre"
end
- it "version requirement becomes ~> major.minor.pre when resolved version is > 1.0.pre" do
+ it "version requirement becomes >= major.minor.pre when resolved version is >= 1.0.pre" do
bundle "add 'dog'"
- expect(bundled_app_gemfile.read).to match(/gem "dog", "~> 1.1.pre"/)
+ 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
+ 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(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
@@ -100,13 +100,13 @@ RSpec.describe "bundle add" do
describe "with --group" do
it "adds dependency for the specified group" do
bundle "add 'foo' --group='development'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", group: :development/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", group: :development/)
expect(the_bundle).to include_gems "foo 2.0"
end
it "adds dependency to more than one group" do
bundle "add 'foo' --group='development, test'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", groups: \[:development, :test\]/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", groups: \[:development, :test\]/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -115,7 +115,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified source" do
bundle "add 'foo' --source='https://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(%r{gem "foo", ">= 2.0", source: "https://gem.repo2"})
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -124,7 +124,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified path" do
bundle "add 'foo' --path='#{lib_path("foo-2.0")}'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", path: "#{lib_path("foo-2.0")}"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", path: "#{lib_path("foo-2.0")}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -133,7 +133,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified git source" do
bundle "add foo --git=#{lib_path("foo-2.0")}"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -146,7 +146,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified git source and branch" do
bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -155,32 +155,53 @@ RSpec.describe "bundle add" 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"))}"
- expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", ">= 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
describe "with --github" do
+ before do
+ build_git "rake", "13.0"
+ git("config --global url.file://#{lib_path("rake-13.0")}.insteadOf https://github.com/ruby/rake.git")
+ end
+
it "adds dependency with specified github source" 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\.\d+", github: "ruby\/rake"})
end
- end
- describe "with --github and --branch" do
it "adds dependency with specified github source and branch" do
- bundle "add rake --github=ruby/rake --branch=master"
+ bundle "add rake --github=ruby/rake --branch=main"
- 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\.\d+", github: "ruby\/rake", branch: "main"})
end
- end
- describe "with --github and --ref" do
it "adds dependency with specified github source and ref" do
- bundle "add rake --github=ruby/rake --ref=5c60da8"
+ ref = revision_for(lib_path("rake-13.0"))
+ bundle "add rake --github=ruby/rake --ref=#{ref}"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", ref: "#{ref}"})
+ end
+
+ it "adds dependency with specified github source and glob" do
+ bundle "add rake --github=ruby/rake --glob='./*.gemspec'"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "5c60da8"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", glob: "\.\/\*\.gemspec"})
+ end
+
+ it "adds dependency with specified github source, branch and glob" do
+ bundle "add rake --github=ruby/rake --branch=main --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", branch: "main", glob: "\.\/\*\.gemspec"})
+ end
+
+ it "adds dependency with specified github source, ref and glob" do
+ ref = revision_for(lib_path("rake-13.0"))
+ bundle "add rake --github=ruby/rake --ref=#{ref} --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", ">= 13\.\d+", github: "ruby\/rake", ref: "#{ref}", glob: "\.\/\*\.gemspec"})
end
end
@@ -188,7 +209,7 @@ RSpec.describe "bundle add" 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(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
@@ -201,7 +222,7 @@ RSpec.describe "bundle add" do
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(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
@@ -210,32 +231,42 @@ RSpec.describe "bundle add" 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(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'"
+ describe "with mismatched pair in --git/--github, --branch/--ref" do
+ describe "with --git and --github" do
+ it "throws error" do
+ bundle "add 'foo' --git x --github y", raise_on_error: false
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", glob: "\.\/\*\.gemspec"})
+ expect(err).to include("You cannot specify `--git` and `--github` at the same time.")
+ end
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'"
+ describe "with --branch and --ref with --git" do
+ it "throws error" do
+ bundle "add 'foo' --branch x --ref y --git file://git", raise_on_error: false
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "master", glob: "\.\/\*\.gemspec"})
+ expect(err).to include("You cannot specify `--branch` and `--ref` at the same time.")
+ end
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'"
+ describe "with --branch but without --git or --github" do
+ it "throws error" do
+ bundle "add 'foo' --branch x", raise_on_error: false
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "5c60da8", glob: "\.\/\*\.gemspec"})
+ expect(err).to include("You cannot specify `--branch` unless `--git` or `--github` is specified.")
+ end
+ end
+
+ describe "with --ref but without --git or --github" do
+ it "throws error" do
+ bundle "add 'foo' --ref y", raise_on_error: false
+
+ expect(err).to include("You cannot specify `--ref` unless `--git` or `--github` is specified.")
+ end
end
end
@@ -260,7 +291,7 @@ RSpec.describe "bundle add" do
end
it "shows error message when gem cannot be found" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "add 'werk_it'", raise_on_error: false
expect(err).to match("Could not find gem 'werk_it' in")
@@ -277,13 +308,21 @@ RSpec.describe "bundle add" do
end
describe "with --optimistic" do
- it "adds optimistic version" do
+ it "ignores option" do
bundle "add 'foo' --optimistic"
expect(bundled_app_gemfile.read).to include %(gem "foo", ">= 2.0")
expect(the_bundle).to include_gems "foo 2.0"
end
end
+ describe "with --pessimistic" do
+ it "adds pessimistic version" do
+ bundle "add 'foo' --pessimistic"
+ expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 2.0")
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
describe "with --quiet option" do
it "is quiet when there are no warnings" do
bundle "add 'foo' --quiet"
@@ -325,18 +364,18 @@ RSpec.describe "bundle add" do
end
describe "with no option" do
- it "adds pessimistic version" do
+ it "adds optimistic version" do
bundle "add 'foo'"
- expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 2.0")
+ expect(bundled_app_gemfile.read).to include %(gem "foo", ">= 2.0")
expect(the_bundle).to include_gems "foo 2.0"
end
end
- describe "with --optimistic and --strict" do
+ describe "with --pessimistic and --strict" do
it "throws error" do
- bundle "add 'foo' --strict --optimistic", raise_on_error: false
+ bundle "add 'foo' --strict --pessimistic", raise_on_error: false
- expect(err).to include("You cannot specify `--strict` and `--optimistic` at the same time")
+ expect(err).to include("You cannot specify `--strict` and `--pessimistic` at the same time")
end
end
@@ -344,8 +383,8 @@ RSpec.describe "bundle add" do
it "adds multiple gems to gemfile" do
bundle "add bar baz"
- expect(bundled_app_gemfile.read).to match(/gem "bar", "~> 0.12.3"/)
- expect(bundled_app_gemfile.read).to match(/gem "baz", "~> 1.2"/)
+ expect(bundled_app_gemfile.read).to match(/gem "bar", ">= 0.12.3"/)
+ expect(bundled_app_gemfile.read).to match(/gem "baz", ">= 1.2"/)
end
it "throws error if any of the specified gems are present in the gemfile with different version" do
diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb
index c66b9339ee..af4d24a9e8 100644
--- a/spec/bundler/commands/binstubs_spec.rb
+++ b/spec/bundler/commands/binstubs_spec.rb
@@ -156,29 +156,20 @@ RSpec.describe "bundle binstubs <gem>" do
end
end
- context "--path" do
- it "sets the binstubs dir" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- bundle "binstubs myrack --path exec"
-
- expect(bundled_app("exec/myrackup")).to exist
+ context "with the binstubs dir configured" do
+ before do
+ bundle_config "bin exec"
end
- it "setting is saved for bundle install", bundler: "< 3" do
+ it "creates the binstubs in the configured dir" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
- gem "rails"
G
- bundle "binstubs myrack", path: "exec"
- bundle :install
+ bundle "binstubs myrack"
- expect(bundled_app("exec/rails")).to exist
+ expect(bundled_app("exec/myrackup")).to exist
end
end
@@ -201,11 +192,10 @@ RSpec.describe "bundle binstubs <gem>" do
expect(File.read(bundled_app("bin/myrackup"))).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
- end
+ it "generates a standalone binstub at the given path when configured" do
+ bundle_config "bin foo"
+ bundle "binstubs myrack --standalone"
+ expect(bundled_app("foo/myrackup")).to exist
end
context "when specified --all-platforms option" do
@@ -323,7 +313,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "myrack"
G
- bundle "config set auto_install 1"
+ bundle_config "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"
@@ -335,7 +325,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "myrack"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle "binstubs myrack", env: { "BUNDLE_INSTALL" => "1" }
expect(out).not_to include("Installing myrack 1.0.0")
end
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index 3f7a627296..e223d07f7f 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe "bundle cache" do
end
end
- context "with --all" do
+ context "with cache_all configured" do
context "without a gemspec" do
it "caches all dependencies except bundler itself" do
gemfile <<-D
@@ -37,7 +37,7 @@ RSpec.describe "bundle cache" do
gem 'bundler'
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -68,7 +68,7 @@ RSpec.describe "bundle cache" do
gemspec
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -100,7 +100,7 @@ RSpec.describe "bundle cache" do
gemspec
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -145,7 +145,7 @@ RSpec.describe "bundle cache" do
gemspec :name => 'mygem_test'
D
- bundle "config set cache_all true"
+ bundle_config "cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
@@ -158,20 +158,6 @@ RSpec.describe "bundle cache" do
end
end
- context "with --path", bundler: "< 3" do
- it "sets root directory for gems" do
- gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
- D
-
- bundle "cache --path #{bundled_app("test")}"
-
- expect(the_bundle).to include_gems "myrack 1.0.0"
- expect(bundled_app("test/vendor/cache/")).to exist
- end
- end
-
context "with --no-install" do
it "puts the gems in vendor/cache but does not install them" do
gemfile <<-D
@@ -221,26 +207,15 @@ RSpec.describe "bundle cache" do
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, but prints a warning", bundler: "< 3" do
- gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack', :platforms => [:ruby_20, :x64_mingw_20]
- D
-
- bundle "cache --all-platforms"
- expect(err).to include("deprecated")
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- end
-
- it "prints an error when using legacy windows rubies", bundler: "3" do
+ it "prints a warn when using legacy windows rubies" do
gemfile <<-D
source "https://gem.repo1"
gem 'myrack', :platforms => [:ruby_20, :x64_mingw_20]
D
bundle "cache --all-platforms", raise_on_error: false
- expect(err).to include("removed")
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).not_to exist
+ expect(err).to include("will be removed in the future")
+ expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
end
it "does not attempt to install gems in without groups" do
@@ -252,7 +227,7 @@ RSpec.describe "bundle cache" do
end
end
- bundle "config set --local without wo"
+ bundle_config "without wo"
install_gemfile <<-G, artifice: "compact_index_extra_api"
source "https://main.repo"
gem "myrack"
@@ -268,14 +243,14 @@ RSpec.describe "bundle cache" do
expect(the_bundle).to include_gem "myrack 1.0"
expect(the_bundle).not_to include_gems "weakling", "uninstallable"
- bundle "config set --local without wo"
+ bundle_config "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"
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"
+ bundle_config "without wo"
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -291,33 +266,107 @@ RSpec.describe "bundle cache" do
end
context "with frozen configured" do
+ let(:app_cache) { bundled_app("vendor/cache") }
+
before do
+ bundle_config "frozen true"
+ end
+
+ it "tries to install but fails when the lockfile is out of sync" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
- bundle "install"
- end
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ myrack (1.0.0)
+ myrack-obama (1.0)
+ myrack
- subject do
- bundle "config set --local frozen true"
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ myrack
+ myrack-obama
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
bundle :cache, raise_on_error: false
+ expect(exitstatus).to eq(16)
+ expect(err).to include("frozen mode")
+ expect(err).to include("You have deleted from the Gemfile")
+ expect(err).to include("* myrack-obama")
+ bundle "env"
+ expect(out).to include("frozen")
end
- it "tries to install with frozen" do
- bundle "config set deployment true"
+ it "caches gems without installing when lockfile is in sync, and --no-install is passed, even if vendor/cache directory is initially empty" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
- gem "myrack-obama"
G
- subject
- expect(exitstatus).to eq(16)
- expect(err).to include("frozen mode")
- expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
- bundle "env"
- expect(out).to include("frozen").or include("deployment")
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ myrack
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ FileUtils.mkdir_p app_cache
+
+ bundle "cache --no-install"
+ expect(out).not_to include("Installing myrack 1.0.0")
+ expect(out).to include("Fetching myrack 1.0.0")
+ expect(app_cache.join("myrack-1.0.0.gem")).to exist
+ end
+
+ it "completes a partial cache when lockfile is in sync, even if the already cached gem is no longer available remotely" do
+ build_repo4 do
+ build_gem "foo", "1.0.0"
+ end
+
+ build_gem "bar", "1.0.0", path: bundled_app("vendor/cache")
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "foo"
+ gem "bar"
+ G
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ foo (1.0.0)
+ bar (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo
+ bar
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "cache --no-install"
+ expect(out).to include("Fetching foo 1.0.0")
+ expect(out).not_to include("Fetching bar 1.0.0")
+ expect(app_cache.join("foo-1.0.0.gem")).to exist
+ expect(app_cache.join("bar-1.0.0.gem")).to exist
end
end
@@ -340,7 +389,7 @@ RSpec.describe "bundle cache" do
it "installs them properly from cache to a different path" do
bundle "cache"
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install --local"
end
end
@@ -356,7 +405,7 @@ RSpec.describe "bundle install with gem sources" do
G
bundle :cache
- pristine_system_gems :bundler
+ pristine_system_gems
FileUtils.rm_r gem_repo2
bundle "install --local"
@@ -371,11 +420,27 @@ RSpec.describe "bundle install with gem sources" do
G
bundle :cache
- pristine_system_gems :bundler
+ pristine_system_gems
+ FileUtils.rm_r gem_repo2
+
+ bundle_config "deployment true"
+ bundle_config "path vendor/bundle"
+ bundle :install
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "does not hit the remote at all in non frozen mode either" do
+ build_repo2
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ bundle :cache
+ pristine_system_gems
FileUtils.rm_r gem_repo2
- bundle "config set --local deployment true"
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
@@ -388,11 +453,11 @@ RSpec.describe "bundle install with gem sources" do
G
bundle :cache
- pristine_system_gems :bundler
+ pristine_system_gems
FileUtils.rm_r gem_repo2
- bundle "config set --local cache_all_platforms true"
- bundle "config set --local path vendor/bundle"
+ bundle_config "cache_all_platforms true"
+ bundle_config "path vendor/bundle"
bundle "install --local"
expect(out).not_to include("Fetching gem metadata")
expect(the_bundle).to include_gems "myrack 1.0.0"
@@ -437,12 +502,12 @@ RSpec.describe "bundle install with gem sources" do
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
- bundle "config set cache_all_platforms true"
- bundle "config set path vendor/bundle"
+ bundle_config "cache_all_platforms true"
+ bundle_config "path vendor/bundle"
bundle :cache, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
# simulate removal of all remote gems
@@ -482,9 +547,9 @@ RSpec.describe "bundle install with gem sources" do
bundle :cache
end
- pristine_system_gems :bundler
+ pristine_system_gems
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -507,7 +572,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.cp gem_repo4("gems/bcrypt_pbkdf-1.1.1-arm64-darwin.gem"), app_cache
FileUtils.cp gem_repo4("gems/bcrypt_pbkdf-1.1.1.gem"), app_cache
- bundle "config cache_all_platforms true"
+ bundle_config "cache_all_platforms true"
lockfile <<~L
GEM
@@ -524,7 +589,7 @@ RSpec.describe "bundle install with gem sources" do
bcrypt_pbkdf
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-23" do
diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb
index 9263e72720..7fe6897ae3 100644
--- a/spec/bundler/commands/check_spec.rb
+++ b/spec/bundler/commands/check_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe "bundle check" do
bundle :check, raise_on_error: false
expect(err).to include("The following gems are missing")
- expect(err).to include(" * rake (13.2.1)")
+ expect(err).to include(" * rake (#{rake_version})")
expect(err).to include(" * actionpack (2.3.2)")
expect(err).to include(" * activerecord (2.3.2)")
expect(err).to include(" * actionmailer (2.3.2)")
@@ -76,7 +76,7 @@ RSpec.describe "bundle check" do
expect(exitstatus).to be > 0
expect(err).to include("The following gems are missing")
expect(err).to include(" * rails (2.3.2)")
- expect(err).to include(" * rake (13.2.1)")
+ expect(err).to include(" * rake (#{rake_version})")
expect(err).to include(" * actionpack (2.3.2)")
expect(err).to include(" * activerecord (2.3.2)")
expect(err).to include(" * actionmailer (2.3.2)")
@@ -88,7 +88,7 @@ RSpec.describe "bundle check" do
it "prints a generic error if gem git source is not checked out" do
build_git "foo", path: lib_path("foo")
- bundle "config path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<-G
source "https://gem.repo1"
@@ -123,21 +123,8 @@ RSpec.describe "bundle check" do
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "remembers --without option from install", bundler: "< 3" do
- gemfile <<-G
- source "https://gem.repo1"
- group :foo do
- gem "myrack"
- end
- G
-
- bundle "install --without foo"
- bundle "check"
- expect(out).to include("The Gemfile's dependencies are satisfied")
- end
-
it "uses the without setting" do
- bundle "config set without foo"
+ bundle_config "without foo"
install_gemfile <<-G
source "https://gem.repo1"
group :foo do
@@ -155,7 +142,7 @@ RSpec.describe "bundle check" do
gem "myrack", :group => :foo
G
- bundle "config set --local without foo"
+ bundle_config "without foo"
bundle :install
gemfile <<-G
@@ -174,10 +161,10 @@ RSpec.describe "bundle check" do
gem "myrack"
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :cache
- gem_command "uninstall myrack", env: { "GEM_HOME" => vendored_gems.to_s }
+ uninstall_gem("myrack", env: { "GEM_HOME" => vendored_gems.to_s })
bundle "check", raise_on_error: false
expect(err).to include("* myrack (1.0.0)")
@@ -264,7 +251,7 @@ RSpec.describe "bundle check" do
gem "foo"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install"
FileUtils.rm(bundled_app_lock)
@@ -272,46 +259,6 @@ RSpec.describe "bundle check" do
expect(last_command).to be_failure
end
- context "--path", bundler: "< 3" do
- context "after installing gems in the proper directory" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "rails"
- G
- bundle "install --path vendor/bundle"
-
- FileUtils.rm_r(bundled_app(".bundle"))
- end
-
- it "returns success" do
- bundle "check --path vendor/bundle"
- expect(out).to include("The Gemfile's dependencies are satisfied")
- end
-
- it "should write to .bundle/config" do
- bundle "check --path vendor/bundle"
- bundle "check"
- end
- end
-
- context "after installing gems on a different directory" do
- before do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails"
- G
-
- bundle "check --path vendor/bundle", raise_on_error: false
- end
-
- it "returns false" do
- expect(exitstatus).to eq(1)
- expect(err).to match(/The following gems are missing/)
- end
- end
- end
-
describe "when locked" do
before :each do
system_gems "myrack-1.0.0"
@@ -329,7 +276,7 @@ RSpec.describe "bundle check" do
it "shows what is missing with the current Gemfile if it is not satisfied" do
FileUtils.rm_r default_bundle_path
- system_gems :bundler
+ default_system_gems
bundle :check, raise_on_error: false
expect(err).to match(/The following gems are missing/)
expect(err).to include("* myrack (1.0")
@@ -389,7 +336,7 @@ RSpec.describe "bundle check" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -464,7 +411,7 @@ RSpec.describe "bundle check" do
depends_on_myrack!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -535,7 +482,7 @@ RSpec.describe "bundle check" do
dex-dispatch-engine!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -552,7 +499,7 @@ RSpec.describe "bundle check" do
build_gem "bar"
end
- bundle "config set path.system true"
+ bundle_config "path.system true"
# Add all gems to ensure all gems are installed so that a bundle check
# would be successful
@@ -617,7 +564,7 @@ RSpec.describe "bundle check" do
end
before do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index 2559be0205..c77859d378 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -25,8 +25,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -54,8 +54,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -84,8 +84,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -117,9 +117,9 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
- bundle "config set without test_group"
+ bundle_config "without test_group"
bundle "install"
bundle :clean
@@ -145,13 +145,13 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
digest = Digest(:SHA1).hexdigest(git_path.to_s)
- cache_path = Bundler::VERSION.start_with?("2.") ? vendored_gems("cache/bundler/git/foo-1.0-#{digest}") : home(".bundle/cache/git/foo-1.0-#{digest}")
+ cache_path = vendored_gems("cache/bundler/git/foo-1.0-#{digest}")
expect(cache_path).to exist
end
@@ -169,7 +169,7 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
@@ -210,7 +210,7 @@ RSpec.describe "bundle clean" do
FileUtils.mkdir_p(bundled_app("real-path"))
File.symlink(bundled_app("real-path"), bundled_app("symlink-path"))
- bundle "config set path #{bundled_app("symlink-path")}"
+ bundle_config "path #{bundled_app("symlink-path")}"
bundle "install"
bundle :clean
@@ -220,7 +220,7 @@ RSpec.describe "bundle clean" do
expect(bundled_app("symlink-path/#{Bundler.ruby_scope}/bundler/gems/foo-#{revision[0..11]}")).to exist
end
- it "removes old git gems" do
+ it "removes old git gems on bundle update" do
build_git "foo-bar", path: lib_path("foo-bar")
revision = revision_for(lib_path("foo-bar"))
@@ -233,7 +233,7 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
update_git "foo-bar", path: lib_path("foo-bar")
@@ -265,7 +265,7 @@ RSpec.describe "bundle clean" do
gem "activesupport", :git => "#{lib_path("rails")}", :ref => '#{revision}'
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
expect(out).to include("")
@@ -288,8 +288,8 @@ RSpec.describe "bundle clean" do
end
end
G
- bundle "config set path vendor/bundle"
- bundle "config set without test"
+ bundle_config "path vendor/bundle"
+ bundle_config "without test"
bundle "install"
bundle :clean
@@ -311,15 +311,15 @@ RSpec.describe "bundle clean" do
end
G
- bundle "config set path vendor/bundle"
- bundle "config set without development"
+ bundle_config "path vendor/bundle"
+ bundle_config "without development"
bundle "install"
bundle :clean
end
it "displays an error when used without --path" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -341,7 +341,7 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
@@ -364,7 +364,7 @@ RSpec.describe "bundle clean" do
end
it "does not call clean automatically when using system gems" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -379,43 +379,18 @@ RSpec.describe "bundle clean" do
gem "myrack"
G
- gem_command :list
+ installed_gems_list
expect(out).to include("myrack (1.0.0)").and include("thin (1.0)")
end
- it "--clean should override the bundle setting on install", bundler: "< 3" do
- gemfile <<-G
- source "https://gem.repo1"
-
- gem "thin"
- gem "myrack"
- G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
- bundle "install --clean true"
-
- gemfile <<-G
- source "https://gem.repo1"
-
- gem "myrack"
- G
- bundle "install"
-
- should_have_gems "myrack-1.0.0"
- should_not_have_gems "thin-1.0"
- end
-
- it "--clean should override the bundle setting on update", bundler: "< 3" do
+ it "does not clean on bundle update when path has not been set" do
build_repo2
- gemfile <<-G
+ install_gemfile <<-G
source "https://gem.repo2"
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
- bundle "install --clean true"
update_repo2 do
build_gem "foo", "1.0.1"
@@ -423,11 +398,27 @@ RSpec.describe "bundle clean" do
bundle "update", all: true
- should_have_gems "foo-1.0.1"
- should_not_have_gems "foo-1.0"
+ files = Pathname.glob(default_bundle_path("*", "*"))
+ files.map! {|f| f.to_s.sub(default_bundle_path.to_s, "") }
+ expected_files = %W[
+ /bin/bundle
+ /bin/bundler
+ /cache/bundler-#{Bundler::VERSION}.gem
+ /cache/foo-1.0.1.gem
+ /cache/foo-1.0.gem
+ /gems/bundler-#{Bundler::VERSION}
+ /gems/foo-1.0
+ /gems/foo-1.0.1
+ /specifications/bundler-#{Bundler::VERSION}.gemspec
+ /specifications/foo-1.0.1.gemspec
+ /specifications/foo-1.0.gemspec
+ ]
+ expected_files += ["/bin/bundle.bat", "/bin/bundler.bat"] if Gem.win_platform?
+
+ expect(files.sort).to eq(expected_files.sort)
end
- it "automatically cleans when path has not been set", bundler: "3" do
+ it "will automatically clean on bundle update when path has not been set", bundler: "5" do
build_repo2
install_gemfile <<-G
@@ -442,8 +433,8 @@ RSpec.describe "bundle clean" do
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, "") }
+ files = Pathname.glob(local_gem_path("*", "*"))
+ files.map! {|f| f.to_s.sub(local_gem_path.to_s, "") }
expect(files.sort).to eq %w[
/cache/foo-1.0.1.gem
/gems/foo-1.0.1
@@ -451,14 +442,14 @@ RSpec.describe "bundle clean" do
]
end
- it "does not clean automatically on --path" do
+ it "does not clean automatically when path configured" do
gemfile <<-G
source "https://gem.repo1"
gem "thin"
gem "myrack"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
@@ -471,7 +462,7 @@ RSpec.describe "bundle clean" do
should_have_gems "myrack-1.0.0", "thin-1.0"
end
- it "does not clean on bundle update with --path" do
+ it "does not clean on bundle update when path configured" do
build_repo2
gemfile <<-G
@@ -479,7 +470,7 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
update_repo2 do
@@ -490,8 +481,8 @@ RSpec.describe "bundle clean" do
should_have_gems "foo-1.0", "foo-1.0.1"
end
- it "does not clean on bundle update when using --system" do
- bundle "config set path.system true"
+ it "does not clean on bundle update when installing to system gems" do
+ bundle_config "path.system true"
build_repo2
@@ -507,12 +498,12 @@ RSpec.describe "bundle clean" do
end
bundle :update, all: true
- gem_command :list
+ installed_gems_list
expect(out).to include("foo (1.0.1, 1.0)")
end
it "cleans system gems when --force is used" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
gemfile <<-G
source "https://gem.repo1"
@@ -531,7 +522,7 @@ RSpec.describe "bundle clean" do
bundle "clean --force"
expect(out).to include("Removing foo (1.0)")
- gem_command :list
+ installed_gems_list
expect(out).not_to include("foo (1.0)")
expect(out).to include("myrack (1.0.0)")
end
@@ -565,7 +556,7 @@ RSpec.describe "bundle clean" do
expect(err).to include(system_gem_path.to_s)
expect(err).to include("grant write permissions")
- gem_command :list
+ installed_gems_list
expect(out).to include("foo (1.0)")
expect(out).to include("myrack (1.0.0)")
end
@@ -581,7 +572,7 @@ RSpec.describe "bundle clean" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
# mimic 7 length git revisions in Gemfile.lock
@@ -591,7 +582,7 @@ RSpec.describe "bundle clean" do
end
lockfile(bundled_app_lock, gemfile_lock.join("\n"))
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
@@ -602,7 +593,7 @@ RSpec.describe "bundle clean" do
end
it "when using --force on system gems, it doesn't remove binaries" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
build_repo2 do
build_gem "bindir" do |s|
@@ -625,7 +616,7 @@ RSpec.describe "bundle clean" do
expect(out).to eq("1.0")
end
- it "when using --force, it doesn't remove default gem binaries", :realworld do
+ it "when using --force, it doesn't remove default gem binaries" do
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?
@@ -634,8 +625,6 @@ RSpec.describe "bundle clean" do
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"
G
@@ -660,7 +649,7 @@ RSpec.describe "bundle clean" do
gem "bar", "1.0", :path => "#{relative_path}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle :clean
end
@@ -673,8 +662,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -703,8 +692,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -733,10 +722,10 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
- bundle "config set dry_run false"
+ bundle_config "dry_run false"
gemfile <<-G
source "https://gem.repo1"
@@ -765,8 +754,8 @@ RSpec.describe "bundle clean" do
gem "foo"
G
- bundle "config set path vendor/bundle"
- bundle "config set clean false"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean false"
bundle "install"
gemfile <<-G
@@ -776,7 +765,7 @@ RSpec.describe "bundle clean" do
gem "weakling"
G
- bundle "config set auto_install 1"
+ bundle_config "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"
@@ -794,7 +783,7 @@ RSpec.describe "bundle clean" do
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
expect(vendored_gems("bundler/gems/extensions")).to exist
expect(vendored_gems("bundler/gems/very_simple_git_binary-1.0-#{revision[0..11]}")).to exist
@@ -815,7 +804,7 @@ RSpec.describe "bundle clean" do
gem "simple_binary"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
very_simple_binary_extensions_dir =
@@ -855,7 +844,7 @@ RSpec.describe "bundle clean" do
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
very_simple_binary_extensions_dir =
@@ -899,8 +888,8 @@ RSpec.describe "bundle clean" do
G
bundle :lock
- bundle "config set without development"
- bundle "config set path vendor/bundle"
+ bundle_config "without development"
+ bundle_config "path vendor/bundle"
bundle "install", verbose: true
bundle :clean
@@ -909,4 +898,39 @@ RSpec.describe "bundle clean" do
expect(very_simple_binary_extensions_dir).to be_nil
end
+
+ it "does not remove the bundler version currently running" do
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "myrack"
+ G
+
+ bundle_config "path vendor/bundle"
+ bundle "install"
+
+ version = Bundler.gem_version.to_s
+ # Simulate that the locked bundler version is installed in the bundle path
+ # by creating the gem directory and gemspec (as would happen after bundle install with that version)
+ Pathname(vendored_gems("cache/bundler-#{version}.gem")).tap do |path|
+ FileUtils.touch(path)
+ end
+ FileUtils.touch(vendored_gems("gems/bundler-#{version}"))
+ Pathname(vendored_gems("specifications/bundler-#{version}.gemspec")).tap do |path|
+ path.write(<<~GEMSPEC)
+ Gem::Specification.new do |s|
+ s.name = "bundler"
+ s.version = "#{version}"
+ s.authors = ["bundler team"]
+ s.summary = "The best way to manage your application's dependencies"
+ end
+ GEMSPEC
+ end
+
+ should_have_gems "bundler-#{version}"
+
+ bundle :clean
+
+ should_have_gems "bundler-#{version}"
+ end
end
diff --git a/spec/bundler/commands/config_spec.rb b/spec/bundler/commands/config_spec.rb
index 1392b17315..e8ab32ca5d 100644
--- a/spec/bundler/commands/config_spec.rb
+++ b/spec/bundler/commands/config_spec.rb
@@ -313,9 +313,10 @@ RSpec.describe ".bundle/config" do
describe "parseable option" do
it "prints an empty string" do
- bundle "config get foo --parseable"
+ bundle "config get foo --parseable", raise_on_error: false
expect(out).to eq ""
+ expect(last_command).to be_failure
end
it "only prints the value of the config" do
@@ -501,8 +502,9 @@ E
it "get" do
ENV["BUNDLE_BAR"] = "bar_val"
- bundle "config get foo"
+ bundle "config get foo", raise_on_error: false
expect(out).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
ENV["BUNDLE_FOO"] = "foo_val"
@@ -547,7 +549,8 @@ E
bundle "config unset foo"
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`"
+ expect(bundle("config get foo", raise_on_error: false)).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
bundle "config set --local foo 1"
bundle "config set --global foo 2"
@@ -557,7 +560,8 @@ E
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nSet for the current user (#{home(".bundle/config")}): \"2\""
bundle "config unset foo --global"
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`"
+ expect(bundle("config get foo", raise_on_error: false)).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
bundle "config set --local foo 1"
bundle "config set --global foo 2"
@@ -567,7 +571,8 @@ E
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nSet for your local app (#{bundled_app(".bundle/config")}): \"1\""
bundle "config unset foo --local"
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`"
+ expect(bundle("config get foo", raise_on_error: false)).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
+ expect(last_command).to be_failure
bundle "config unset foo --local --global", raise_on_error: false
expect(last_command).to be_failure
@@ -577,6 +582,36 @@ E
end
RSpec.describe "setting gemfile via config" do
+ context "when a default Gemfile exists" do
+ before do
+ gemfile <<-G
+ source "https://gem.repo1"
+ G
+
+ gemfile bundled_app("foo/bar_gemfile"), <<-G
+ source "https://gem.repo1"
+ G
+ end
+
+ it "reports the local gemfile setting without promoting it to the environment" do
+ bundle "config set gemfile foo/bar_gemfile"
+
+ bundle "config list"
+ expect(out).to include("Set for your local app (#{bundled_app(".bundle/config")}): \"foo/bar_gemfile\"")
+ expect(out).not_to include("Set via BUNDLE_GEMFILE")
+ end
+
+ it "unsets the local gemfile setting from the app config" do
+ bundle "config set gemfile foo/bar_gemfile"
+
+ bundle "config unset gemfile"
+ bundle "config get gemfile", raise_on_error: false
+
+ expect(out).to include("You have not configured a value for `gemfile`")
+ expect(File.read(bundled_app(".bundle/config"))).not_to include("BUNDLE_GEMFILE")
+ end
+ end
+
context "when only the non-default Gemfile exists" do
it "persists the gemfile location to .bundle/config" do
gemfile bundled_app("NotGemfile"), <<-G
@@ -592,3 +627,20 @@ RSpec.describe "setting gemfile via config" do
end
end
end
+
+RSpec.describe "setting lockfile via config" do
+ it "persists the lockfile location to .bundle/config" do
+ gemfile bundled_app("NotGemfile"), <<-G
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
+ bundle "config set --local lockfile #{bundled_app("ReallyNotGemfile.lock")}"
+ expect(File.exist?(bundled_app(".bundle/config"))).to eq(true)
+
+ bundle "config list"
+ expect(out).to include("NotGemfile")
+ expect(out).to include("ReallyNotGemfile.lock")
+ end
+end
diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb
index dbfbec874f..a44f607546 100644
--- a/spec/bundler/commands/console_spec.rb
+++ b/spec/bundler/commands/console_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe "bundle console", readline: true do
end
end
- context "when the library has an unrelated error" do
+ context "when the library requires a non-existent file" do
before do
build_lib "loadfuuu", "1.0.0" do |s|
s.write "lib/loadfuuu.rb", "require_relative 'loadfuuu/bar'"
@@ -65,6 +65,30 @@ RSpec.describe "bundle console", readline: true do
end
end
+ context "when the library references a non-existent constant" do
+ before do
+ build_lib "loadfuuu", "1.0.0" do |s|
+ s.write "lib/loadfuuu.rb", "Some::NonExistent::Constant"
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "irb"
+ path "#{lib_path}" do
+ gem "loadfuuu", require: true
+ end
+ G
+ end
+
+ it "does not show the bug report template" do
+ bundle("console", raise_on_error: false) do |input, _, _|
+ input.puts("exit")
+ end
+
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+ end
+ end
+
context "when the library does not have any errors" do
before do
install_gemfile <<-G
@@ -100,7 +124,7 @@ RSpec.describe "bundle console", readline: true do
gem "irb"
gem "pry"
G
- bundle "config set console pry"
+ bundle_config "console pry"
bundle "console" do |input, _, _|
input.puts("__method__")
@@ -112,7 +136,7 @@ RSpec.describe "bundle console", readline: true do
it "falls back to IRB if the other REPL isn't available" do
skip "Does not work in a ruby-core context if irb is in the default $LOAD_PATH because it enables the real IRB, not our dummy one" if ruby_core? && Gem.ruby_version < Gem::Version.new("3.5.0.a")
- bundle "config set console pry"
+ bundle_config "console pry"
# make sure pry isn't there
bundle "console" do |input, _, _|
@@ -177,7 +201,7 @@ RSpec.describe "bundle console", readline: true do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :console do |input, _, _|
input.puts("puts 'hello'")
input.puts("exit")
diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb
index 7c30d0e91b..d350b4b3d1 100644
--- a/spec/bundler/commands/doctor_spec.rb
+++ b/spec/bundler/commands/doctor_spec.rb
@@ -4,6 +4,7 @@ require "find"
require "stringio"
require "bundler/cli"
require "bundler/cli/doctor"
+require "bundler/cli/doctor/diagnose"
RSpec.describe "bundle doctor" do
before(:each) do
@@ -33,6 +34,8 @@ RSpec.describe "bundle doctor" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [unwritable_file] }
allow(File).to receive(:exist?).and_call_original
+ allow(File).to receive(:writable?).and_call_original
+ allow(File).to receive(:readable?).and_call_original
allow(File).to receive(:exist?).with(unwritable_file).and_return(true)
allow(File).to receive(:stat).with(unwritable_file) { stat }
allow(stat).to receive(:uid) { Process.uid }
@@ -46,14 +49,14 @@ RSpec.describe "bundle doctor" do
end
it "exits with a success message if the installed gem has no C extensions" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
allow(doctor).to receive(:lookup_with_fiddle).and_return(false)
expect { doctor.run }.not_to raise_error
expect(@stdout.string).to include("No issues")
end
it "exits with a success message if the installed gem's C extension dylib breakage is fine" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"]
allow(doctor).to receive(:lookup_with_fiddle).with("/usr/lib/libSystem.dylib").and_return(false)
@@ -61,8 +64,14 @@ RSpec.describe "bundle doctor" do
expect(@stdout.string).to include("No issues")
end
+ it "parses otool output correctly" do
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
+ expect(doctor).to receive(:`).with("/usr/bin/otool -L fake").and_return("/home/gem/ruby/3.4.3/gems/blake3-rb-1.5.4.4/lib/digest/blake3/blake3_ext.bundle:\n\t (compatibility version 0.0.0, current version 0.0.0)\n\t/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)")
+ expect(doctor.dylibs_darwin("fake")).to eq(["/usr/lib/libSystem.B.dylib"])
+ end
+
it "exits with a message if one of the linked libraries is missing" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"]
allow(doctor).to receive(:lookup_with_fiddle).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_return(true)
@@ -84,7 +93,7 @@ RSpec.describe "bundle doctor" do
end
it "exits with an error if home contains files that are not readable/writable" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
allow(doctor).to receive(:lookup_with_fiddle).and_return(false)
expect { doctor.run }.not_to raise_error
expect(@stdout.string).to include(
@@ -101,12 +110,14 @@ RSpec.describe "bundle doctor" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [@unwritable_file] }
allow(File).to receive(:exist?).and_call_original
+ allow(File).to receive(:writable?).and_call_original
+ allow(File).to receive(:readable?).and_call_original
allow(File).to receive(:exist?).with(@unwritable_file) { true }
allow(File).to receive(:stat).with(@unwritable_file) { @stat }
end
it "exits with an error if home contains files that are not readable" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
allow(doctor).to receive(:lookup_with_fiddle).and_return(false)
allow(@stat).to receive(:uid) { Process.uid }
allow(File).to receive(:writable?).with(@unwritable_file) { false }
@@ -119,7 +130,7 @@ RSpec.describe "bundle doctor" do
end
it "exits without an error if home contains files that are not writable" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
allow(doctor).to receive(:lookup_with_fiddle).and_return(false)
allow(@stat).to receive(:uid) { Process.uid }
allow(File).to receive(:writable?).with(@unwritable_file) { false }
@@ -137,7 +148,7 @@ RSpec.describe "bundle doctor" do
end
it "exits with an error if home contains files that are not readable/writable and are not owned by the current user" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
allow(doctor).to receive(:lookup_with_fiddle).and_return(false)
allow(File).to receive(:writable?).with(@unwritable_file) { false }
allow(File).to receive(:readable?).with(@unwritable_file) { false }
@@ -149,7 +160,7 @@ RSpec.describe "bundle doctor" do
end
it "exits with a warning if home contains files that are read/write but not owned by current user" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
allow(doctor).to receive(:lookup_with_fiddle).and_return(false)
allow(File).to receive(:writable?).with(@unwritable_file) { true }
allow(File).to receive(:readable?).with(@unwritable_file) { true }
@@ -164,7 +175,7 @@ RSpec.describe "bundle doctor" do
context "when home contains filenames with special characters" do
it "escape filename before command execute" do
- doctor = Bundler::CLI::Doctor.new({})
+ doctor = Bundler::CLI::Doctor::Diagnose.new({})
expect(doctor).to receive(:`).with("/usr/bin/otool -L \\$\\(date\\)\\ \\\"\\'\\\\.bundle").and_return("dummy string")
doctor.dylibs_darwin('$(date) "\'\.bundle')
expect(doctor).to receive(:`).with("/usr/bin/ldd \\$\\(date\\)\\ \\\"\\'\\\\.bundle").and_return("dummy string")
diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb
index 62421410ed..aa35685be8 100644
--- a/spec/bundler/commands/exec_spec.rb
+++ b/spec/bundler/commands/exec_spec.rb
@@ -95,7 +95,7 @@ RSpec.describe "bundle exec" do
end
it "respects custom process title when loading through ruby" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility = <<~'RUBY'
Process.setproctitle("1-2-3-4-5-6-7")
@@ -120,7 +120,7 @@ RSpec.describe "bundle exec" do
end
it "handles --keep-file-descriptors" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
require "tempfile"
@@ -139,7 +139,7 @@ RSpec.describe "bundle exec" do
G
install_gemfile "source \"https://gem.repo1\""
- sys_exec "#{Gem.ruby} #{command.path}"
+ in_bundled_app "#{Gem.ruby} #{command.path}"
expect(out).to be_empty
expect(err).to be_empty
@@ -153,7 +153,7 @@ RSpec.describe "bundle exec" do
end
it "can run a command named --verbose" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
File.open(bundled_app("--verbose"), "w") do |f|
@@ -193,7 +193,10 @@ RSpec.describe "bundle exec" do
end
context "with default gems" do
- let(:default_erb_version) { ruby "gem 'erb', '< 999999'; require 'erb/version'; puts Erb::VERSION", raise_on_error: false }
+ # TODO: Switch to ERB::VERSION once Ruby 3.4 support is dropped, so all
+ # supported rubies include an `erb` gem version where `ERB::VERSION` is
+ # public
+ let(:default_erb_version) { ruby "require 'erb/version'; puts ERB.const_get(:VERSION)" }
context "when not specified in Gemfile" do
before do
@@ -203,7 +206,7 @@ RSpec.describe "bundle exec" do
it "uses version provided by ruby" do
bundle "exec erb --version"
- expect(out).to include(default_erb_version)
+ expect(stdboth).to eq(default_erb_version)
end
end
@@ -224,10 +227,9 @@ RSpec.describe "bundle exec" do
end
it "uses version specified" do
- bundle "exec erb --version", artifice: nil
+ bundle "exec erb --version"
- expect(out).to eq(specified_erb_version)
- expect(err).to be_empty
+ expect(stdboth).to eq(specified_erb_version)
end
end
@@ -249,13 +251,12 @@ RSpec.describe "bundle exec" do
source "https://gem.repo2"
gem "gem_depending_on_old_erb"
G
-
- bundle "exec erb --version", artifice: nil
end
it "uses resolved version" do
- expect(out).to eq(indirect_erb_version)
- expect(err).to be_empty
+ bundle "exec erb --version"
+
+ expect(stdboth).to eq(indirect_erb_version)
end
end
end
@@ -267,7 +268,7 @@ RSpec.describe "bundle exec" do
end
end
- bundle "config set --global path.system true"
+ bundle_config_global "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -288,7 +289,7 @@ RSpec.describe "bundle exec" do
end
it "handles gems installed with --without" do
- bundle "config set --local without middleware"
+ bundle_config "without middleware"
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack" # myrack 0.9.1 and 1.0 exist
@@ -378,13 +379,13 @@ RSpec.describe "bundle exec" do
it "raises a helpful error when exec'ing to something outside of the bundle" do
system_gems(%w[myrack-1.0.0 myrack-0.9.1], path: default_bundle_path)
- bundle "config set clean false" # want to keep the myrackup binstub
+ bundle_config "clean false" # want to keep the myrackup binstub
install_gemfile <<-G
source "https://gem.repo1"
gem "foo"
G
[true, false].each do |l|
- bundle "config set disable_exec_load #{l}"
+ bundle_config "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?"
end
@@ -581,8 +582,8 @@ RSpec.describe "bundle exec" do
gem "foo"
G
- bundle "config set auto_install 1"
- bundle "exec myrackup"
+ bundle_config "auto_install 1"
+ bundle "exec myrackup", artifice: "compact_index"
expect(out).to include("Installing foo 1.0")
end
@@ -596,8 +597,8 @@ RSpec.describe "bundle exec" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- bundle "config set auto_install 1"
- bundle "exec foo"
+ bundle_config "auto_install 1"
+ bundle "exec foo", artifice: "compact_index"
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")
@@ -616,15 +617,15 @@ RSpec.describe "bundle exec" do
system_gems "optparse-999.999.998", gem_repo: gem_repo4
- bundle "config set auto_install 1"
- bundle "config set --local path vendor/bundle"
+ bundle_config "auto_install 1"
+ bundle_config "path vendor/bundle"
gemfile <<~G
source "https://gem.repo4"
gem "fastlane"
G
- bundle "exec fastlane"
+ bundle "exec fastlane", artifice: "compact_index"
expect(out).to include("Installing optparse 999.999.999")
expect(out).to include("2.192.0")
end
@@ -660,8 +661,6 @@ RSpec.describe "bundle exec" do
describe "with gems bundled for deployment" do
it "works when calling bundler from another script" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
gemfile <<-G
source "https://gem.repo1"
@@ -672,7 +671,7 @@ RSpec.describe "bundle exec" do
end
Bundler.rubygems.extend(Monkey)
G
- bundle "config set path.system true"
+ bundle_config "path.system true"
bundle "install"
bundle "exec ruby -e '`bundle -v`; puts $?.success?'", env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(out).to match("true")
@@ -698,6 +697,27 @@ RSpec.describe "bundle exec" do
end
end
+ describe "running gem commands in presence of rubygems plugins" do
+ before do
+ build_repo4 do
+ build_gem "foo" do |s|
+ s.write "lib/rubygems_plugin.rb", "puts 'FAIL'"
+ end
+ end
+
+ system_gems "foo-1.0", path: default_bundle_path, gem_repo: gem_repo4
+
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ G
+ end
+
+ it "does not load plugins outside of the bundle" do
+ bundle "exec #{gem_cmd} -v"
+ expect(out).not_to include("FAIL")
+ 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" }
@@ -708,13 +728,16 @@ RSpec.describe "bundle exec" do
puts "EXEC: \#{caller.grep(/load/).empty? ? 'exec' : 'load'}"
puts "ARGS: \#{$0} \#{ARGV.join(' ')}"
puts "MYRACK: \#{MYRACK}"
- process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
+ if Gem.win_platform?
+ process_title = "ruby"
+ else
+ process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
+ end
puts "PROCESS: \#{process_title}"
RUBY
before do
- bundled_app(path).open("w") {|f| f << executable }
- bundled_app(path).chmod(0o755)
+ create_file(bundled_app(path), executable)
install_gemfile <<-G
source "https://gem.repo1"
@@ -726,9 +749,11 @@ RSpec.describe "bundle exec" do
let(:args) { "ARGS: #{path} arg1 arg2" }
let(:myrack) { "MYRACK: 1.0.0" }
let(:process) do
- title = "PROCESS: #{path}"
- title += " arg1 arg2"
- title
+ if Gem.win_platform?
+ "PROCESS: ruby"
+ else
+ "PROCESS: #{path} arg1 arg2"
+ end
end
let(:exit_code) { 0 }
let(:expected) { [exec, args, myrack, process].join("\n") }
@@ -737,8 +762,6 @@ RSpec.describe "bundle exec" do
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?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -750,8 +773,6 @@ RSpec.describe "bundle exec" do
context "with exit 0" do
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -763,8 +784,6 @@ RSpec.describe "bundle exec" do
let(:exit_code) { 99 }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -786,7 +805,7 @@ RSpec.describe "bundle exec" do
end
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
@@ -803,7 +822,12 @@ RSpec.describe "bundle exec" do
let(:expected) { "" }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ # it's empty, so `create_file` won't add executable permission and bat scripts on Windows
+ bundled_app(path).chmod(0o755)
+ path.sub_ext(".bat").write <<~SCRIPT if Gem.win_platform?
+ @ECHO OFF
+ @"ruby.exe" "%~dpn0" %*
+ SCRIPT
subject
expect(exitstatus).to eq(exit_code)
@@ -816,12 +840,10 @@ 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\)/
+ /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:[0-9]+:in [`']<top \(required\)>': ERROR \(RuntimeError\)/
end
it "runs like a normally executed executable" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to match(expected_err)
@@ -836,8 +858,6 @@ RSpec.describe "bundle exec" do
let(:expected) { super() }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -849,8 +869,6 @@ RSpec.describe "bundle exec" do
let(:shebang) { "#!#{Gem.ruby}" }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -881,8 +899,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -905,8 +921,6 @@ RSpec.describe "bundle exec" do
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.")
@@ -919,8 +933,6 @@ RSpec.describe "bundle exec" do
let(:exit_code) { 1 }
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -930,15 +942,19 @@ RSpec.describe "bundle exec" do
context "when disable_exec_load is set" do
let(:exec) { "EXEC: exec" }
- let(:process) { "PROCESS: ruby #{path} arg1 arg2" }
+ let(:process) do
+ if Gem.win_platform?
+ "PROCESS: ruby"
+ else
+ "PROCESS: ruby #{path} arg1 arg2"
+ end
+ end
before do
- bundle "config set disable_exec_load true"
+ bundle_config "disable_exec_load true"
end
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -961,8 +977,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -979,8 +993,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -997,8 +1009,6 @@ RSpec.describe "bundle exec" do
EOS
it "runs" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
@@ -1010,7 +1020,7 @@ RSpec.describe "bundle exec" do
context "signal handling" do
let(:test_signals) do
open3_reserved_signals = %w[CHLD CLD PIPE]
- reserved_signals = %w[SEGV BUS ILL FPE VTALRM KILL STOP EXIT]
+ reserved_signals = %w[SEGV BUS ILL FPE ABRT IOT VTALRM KILL STOP EXIT]
bundler_signals = %w[INT]
Signal.list.keys - (bundler_signals + reserved_signals + open3_reserved_signals)
@@ -1024,7 +1034,7 @@ RSpec.describe "bundle exec" do
puts 'Started' # For process sync
STDOUT.flush
sleep 1 # ignore quality_spec
- raise "Didn't receive INT at all"
+ raise RuntimeError, "Didn't receive expected INT"
end.join
rescue Interrupt
puts "foo"
@@ -1032,7 +1042,7 @@ RSpec.describe "bundle exec" do
RUBY
it "receives the signal" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
bundle("exec #{path}") do |_, o, thr|
o.gets # Consumes 'Started' and ensures that thread has started
@@ -1055,7 +1065,7 @@ RSpec.describe "bundle exec" do
RUBY
it "makes sure no unexpected signals are restored to DEFAULT" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
test_signals.each do |n|
Signal.trap(n, "IGNORE")
@@ -1072,13 +1082,13 @@ RSpec.describe "bundle exec" do
context "nested bundle exec" do
context "when bundle in a local path" do
before do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
- bundle "config set path vendor/bundler"
+ bundle_config "path vendor/bundler"
bundle :install
end
@@ -1096,7 +1106,7 @@ RSpec.describe "bundle exec" do
context "when Kernel.require uses extra monkeypatches" do
before do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
install_gemfile "source \"https://gem.repo1\""
end
@@ -1139,16 +1149,14 @@ RSpec.describe "bundle exec" do
context "when gemfile and path are configured", :ruby_repo do
before do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
build_repo2 do
build_gem "rails", "6.1.0" do |s|
s.executables = "rails"
end
end
- bundle "config set path vendor/bundle"
- bundle "config set gemfile gemfiles/myrack_6_1.gemfile"
+ bundle_config "path vendor/bundle"
+ bundle_config "gemfile gemfiles/myrack_6_1.gemfile"
gemfile(bundled_app("gemfiles/myrack_6_1.gemfile"), <<~RUBY)
source "https://gem.repo2"
@@ -1199,18 +1207,18 @@ RSpec.describe "bundle exec" do
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 }
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?
+ default_openssl_version = ruby "require 'openssl'; puts OpenSSL::VERSION"
+
+ skip "https://github.com/ruby/rubygems/issues/3351" if Gem.win_platform?
install_gemfile "source \"https://gem.repo1\"" # must happen before installing the broken system gem
build_repo4 do
build_gem "openssl", openssl_version do |s|
s.write("lib/openssl.rb", <<-RUBY)
- raise "custom openssl should not be loaded, it's not in the gemfile!"
+ raise ArgumentError, "custom openssl should not be loaded"
RUBY
end
end
@@ -1228,10 +1236,10 @@ RSpec.describe "bundle exec" do
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}", env: env)).to eq(default_openssl_version)
+ expect(bundle("exec bundle exec #{file}", env: env)).to eq(default_openssl_version)
+ expect(bundle("exec ruby #{file}", env: env)).to eq(default_openssl_version)
+ expect(run(file.read, artifice: nil, env: env)).to eq(default_openssl_version)
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?
@@ -1244,7 +1252,7 @@ RSpec.describe "bundle exec" do
context "with a git gem that includes extensions", :ruby_repo do
before do
build_git "simple_git_binary", &:add_c_extension
- bundle "config set --local path .bundle"
+ bundle_config "path .bundle"
install_gemfile <<-G
source "https://gem.repo1"
gem "simple_git_binary", :git => '#{lib_path("simple_git_binary-1.0")}'
diff --git a/spec/bundler/commands/fund_spec.rb b/spec/bundler/commands/fund_spec.rb
index 6f4e61da30..5883b8a63a 100644
--- a/spec/bundler/commands/fund_spec.rb
+++ b/spec/bundler/commands/fund_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe "bundle fund" do
end
it "considers fund information for installed optional dependencies" do
- bundle "config set with whatever"
+ bundle_config "with whatever"
install_gemfile <<-G
source "https://gem.repo2"
diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb
index 478cf06405..a26b1696fb 100644
--- a/spec/bundler/commands/info_spec.rb
+++ b/spec/bundler/commands/info_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe "bundle info" do
end
it "doesn't claim that bundler is missing, even if using a custom path without bundler there" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
bundle "info bundler"
expect(out).to include("\tPath: #{root}")
@@ -86,7 +86,7 @@ RSpec.describe "bundle info" do
expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
end
- context "given a default gem shippped in ruby", :ruby_repo do
+ context "given a default gem shipped in ruby", :ruby_repo do
it "prints information about the default gem" do
bundle "info json"
expect(out).to include("* json")
@@ -235,7 +235,7 @@ RSpec.describe "bundle info" do
context "with without configured" do
it "does not find the gem, but gives a helpful error" do
- bundle "config without test"
+ bundle_config "without test"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/commands/init_spec.rb b/spec/bundler/commands/init_spec.rb
index 538e61fd47..989d6fa812 100644
--- a/spec/bundler/commands/init_spec.rb
+++ b/spec/bundler/commands/init_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe "bundle init" do
end
context "when init_gems_rb setting is enabled" do
- before { bundle "config set init_gems_rb true" }
+ before { bundle_config "init_gems_rb true" }
it "generates a gems.rb" do
bundle :init
diff --git a/spec/bundler/commands/inject_spec.rb b/spec/bundler/commands/inject_spec.rb
deleted file mode 100644
index 4998b6e89d..0000000000
--- a/spec/bundler/commands/inject_spec.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "bundle inject", bundler: "< 3" do
- before :each do
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- 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/)
- end
- end
-
- context "with a lockfile" do
- before do
- bundle "install"
- 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/)
- 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/)
- 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
- 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
- expect(err).to eq(<<-E.strip)
-ERROR: "bundle inject" was called with arguments ["gem_name", "1", "v"]
-Usage: "bundle inject GEM VERSION"
- E
- end
- end
-
- context "with source option" do
- it "add gem with source option in gemfile" do
- bundle "inject 'foo' '>0' --source https://gem.repo1"
- gemfile = bundled_app_gemfile.read
- str = "gem \"foo\", \"> 0\", source: \"https://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"
- gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-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"
- gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-obama\", \"> 0\", groups: [:development, :test]"
- expect(gemfile).to include str
- end
- end
-
- context "when frozen" do
- before do
- bundle "install"
- if Bundler.feature_flag.bundler_3_mode?
- bundle "config set --local deployment true"
- else
- bundle "config set --local frozen true"
- end
- end
-
- it "injects anyway" do
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_gemfile.read).to match(/myrack-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/)
- end
-
- it "restores frozen afterwards" do
- bundle "inject 'myrack-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"
- G
- bundle "inject 'myrack' '> 0'", raise_on_error: false
- expect(err).to match(/the lockfile can't be updated because frozen mode is set/)
-
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
- end
- end
-end
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index 3c8df46248..3b24434dc7 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -29,23 +29,77 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app_lock).to exist
end
- it "does not create ./.bundle by default", bundler: "< 3" do
- gemfile <<-G
+ it "creates lockfile based on the lockfile method in Gemfile" do
+ install_gemfile <<-G
+ lockfile "OmgFile.lock"
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install"
+
+ expect(bundled_app("OmgFile.lock")).to exist
+ end
+
+ it "creates lockfile using BUNDLE_LOCKFILE instead of lockfile method" do
+ ENV["BUNDLE_LOCKFILE"] = "ReallyOmgFile.lock"
+ install_gemfile <<-G
+ lockfile "OmgFile.lock"
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ expect(bundled_app("ReallyOmgFile.lock")).to exist
+ expect(bundled_app("OmgFile.lock")).not_to exist
+ ensure
+ ENV.delete("BUNDLE_LOCKFILE")
+ end
+
+ it "creates lockfile based on --lockfile option is given" do
+ gemfile bundled_app("OmgFile"), <<-G
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install --gemfile OmgFile --lockfile ReallyOmgFile.lock"
+
+ expect(bundled_app("ReallyOmgFile.lock")).to exist
+ end
+
+ it "does not make a lockfile if lockfile false is used in Gemfile" do
+ install_gemfile <<-G
+ lockfile false
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ expect(bundled_app_lock).not_to exist
+ end
+
+ it "does not create ./.bundle by default" do
+ install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
- bundle :install # can't use install_gemfile since it sets retry
expect(bundled_app(".bundle")).not_to exist
end
+ it "will create a ./.bundle by default", bundler: "5" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ expect(bundled_app(".bundle")).to exist
+ end
+
it "does not create ./.bundle by default when installing to system gems" do
- gemfile <<-G
+ install_gemfile <<-G, env: { "BUNDLE_PATH__SYSTEM" => "true" }
source "https://gem.repo1"
gem "myrack"
G
- bundle :install, env: { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
expect(bundled_app(".bundle")).not_to exist
end
@@ -60,6 +114,29 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app("OmgFile.lock")).to exist
end
+ it "doesn't create a lockfile if --no-lock option is given" do
+ gemfile bundled_app("OmgFile"), <<-G
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install --gemfile OmgFile --no-lock"
+
+ expect(bundled_app("OmgFile.lock")).not_to exist
+ end
+
+ it "doesn't create a lockfile if --no-lock and --lockfile options are given" do
+ gemfile bundled_app("OmgFile"), <<-G
+ source "https://gem.repo1"
+ gem "myrack", "1.0"
+ G
+
+ bundle "install --gemfile OmgFile --no-lock --lockfile ReallyOmgFile.lock"
+
+ expect(bundled_app("OmgFile.lock")).not_to exist
+ expect(bundled_app("ReallyOmgFile.lock")).not_to exist
+ end
+
it "doesn't delete the lockfile if one already exists" do
install_gemfile <<-G
source "https://gem.repo1"
@@ -111,7 +188,7 @@ RSpec.describe "bundle install with gem sources" do
it "does not state that it's constantly reinstalling empty gems" do
build_repo4 do
- build_gem "empty", "1.0.0", no_default: true, allowed_warning: "no files specified"
+ build_gem "empty", "1.0.0", no_default: true
end
install_gemfile <<~G
@@ -260,7 +337,7 @@ RSpec.describe "bundle install with gem sources" do
gem "myrack"
G
- expect(last_command.stdboth).to include(plugin_msg)
+ expect(stdboth).to include(plugin_msg)
end
describe "with a gem that installs multiple platforms" do
@@ -320,53 +397,6 @@ RSpec.describe "bundle install with gem sources" do
end
end
- describe "doing bundle install foo" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
- end
-
- it "works" do
- bundle "config set --local path vendor"
- bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
- end
-
- it "allows running bundle install --system without deleting foo", bundler: "< 3" do
- bundle "install --path vendor"
- bundle "install --system"
- FileUtils.rm_r(bundled_app("vendor"))
- expect(the_bundle).to include_gems "myrack 1.0"
- end
-
- it "allows running bundle install --system after deleting foo", bundler: "< 3" do
- bundle "install --path vendor"
- FileUtils.rm_r(bundled_app("vendor"))
- bundle "install --system"
- expect(the_bundle).to include_gems "myrack 1.0"
- end
- end
-
- it "finds gems in multiple sources", bundler: "< 3" do
- build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
- end
- end
-
- install_gemfile <<-G, artifice: "compact_index_extra"
- source "https://gemserver.test"
- source "https://gemserver.test/extra"
-
- gem "activesupport", "1.2.3"
- gem "myrack", "1.2"
- G
-
- expect(the_bundle).to include_gems "myrack 1.2", "activesupport 1.2.3"
- end
-
it "gives useful errors if no global sources are set, and gems not installed locally, with and without a lockfile" do
install_gemfile <<-G, raise_on_error: false
gem "myrack"
@@ -386,7 +416,7 @@ RSpec.describe "bundle install with gem sources" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install", raise_on_error: false
@@ -608,6 +638,30 @@ RSpec.describe "bundle install with gem sources" do
expect(err).to include("Two gemspec development dependencies have conflicting requirements on the same gem: rubocop (~> 1.36.0) and rubocop (~> 2.0). Bundler cannot continue.")
end
+ it "errors out if a gem is specified in a gemspec and in the Gemfile" do
+ gem = tmp("my-gem-1")
+
+ build_lib "rubocop", path: gem do |s|
+ s.add_development_dependency "rubocop", "~> 1.0"
+ end
+
+ build_repo4 do
+ build_gem "rubocop"
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "rubocop", :path => "#{gem}"
+ gemspec path: "#{gem}"
+ G
+
+ bundle :install, raise_on_error: false
+
+ expect(err).to include("There was an error parsing `Gemfile`: You cannot specify the same gem twice coming from different sources.")
+ expect(err).to include("You specified that rubocop (>= 0) should come from source at `#{gem}` and gemspec at `#{gem}`")
+ 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"
@@ -690,8 +744,6 @@ RSpec.describe "bundle install with gem sources" do
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"
source "http://0.0.0.0:9384" do
@@ -699,20 +751,19 @@ RSpec.describe "bundle install with gem sources" do
end
G
- expect(err).to include("Could not fetch specs from http://0.0.0.0:9384/")
+ expect(err).to eq("Could not reach host 0.0.0.0:9384. Check your network connection and try again.")
expect(err).not_to include("file://")
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|
- bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
+ invalid_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
s.
instance_variable_get(:@spec).
- instance_variable_set(:@dependencies, bad_deps)
-
- raise "failed to set bad deps" unless s.dependencies == bad_deps
+ instance_variable_set(:@dependencies, invalid_deps)
end
+
build_gem "ruby-ajp", "1.0.0"
end
@@ -722,7 +773,7 @@ RSpec.describe "bundle install with gem sources" do
gem "ajp-rails", "0.0.0"
G
- expect(last_command.stdboth).not_to match(/Error Report/i)
+ expect(stdboth).not_to match(/Error Report/i)
expect(err).to include("An error occurred while installing ajp-rails (0.0.0), and Bundler cannot continue.").
and include("Bundler::APIResponseInvalidDependenciesError")
end
@@ -782,10 +833,10 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -808,10 +859,10 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -866,7 +917,7 @@ RSpec.describe "bundle install with gem sources" do
describe "when requesting a quiet install via --quiet" do
it "should be quiet if there are no warnings" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
@@ -879,7 +930,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should still display warnings and errors" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
create_file("install_with_warning.rb", <<~RUBY)
require "#{lib_dir}/bundler"
@@ -924,7 +975,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod(0o500, bundle_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install, raise_on_error: false
expect(err).to include(bundle_path.to_s)
expect(err).to include("grant executable permissions")
@@ -944,7 +995,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", gems_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -974,7 +1025,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", full_gem_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1004,7 +1055,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", bin_dir)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1034,7 +1085,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-w", bin_dir)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1064,7 +1115,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod("-x", extensions_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
begin
bundle :install, raise_on_error: false
@@ -1099,7 +1150,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1107,7 +1158,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod("-x", foo_path)
begin
- bundle "install --redownload", raise_on_error: false
+ bundle "install --force", raise_on_error: false
ensure
FileUtils.chmod("+x", foo_path)
end
@@ -1135,7 +1186,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should still work" do
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1143,7 +1194,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod("-w", gem_home)
begin
- bundle "install --redownload"
+ bundle "install --force"
ensure
FileUtils.chmod("+w", gem_home)
end
@@ -1170,14 +1221,14 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
+ bundle_config "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
+ bundle "install --force", 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
@@ -1201,7 +1252,7 @@ RSpec.describe "bundle install with gem sources" do
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"
+ bundle_config "path vendor"
FileUtils.mkdir_p(gems_path)
FileUtils.chmod(0o777, gems_path)
@@ -1225,7 +1276,7 @@ RSpec.describe "bundle install with gem sources" do
it "should display a proper message to explain the problem" do
FileUtils.chmod(0o500, cache_path)
- bundle "config set --local path vendor"
+ bundle_config "path vendor"
bundle :install, raise_on_error: false
expect(err).to include(cache_path.to_s)
expect(err).to include("grant write permissions")
@@ -1240,7 +1291,7 @@ RSpec.describe "bundle install with gem sources" do
source "https://gem.repo1"
gem 'myrack'
G
- bundle "config path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(out).to include("Bundle complete!")
expect(err).to be_empty
@@ -1255,6 +1306,158 @@ RSpec.describe "bundle install with gem sources" do
end
end
+ describe "when using umask 002 and setgid bit", :permissions do
+ let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
+ let(:foo_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
+
+ FileUtils.mkdir_p(gems_path)
+ FileUtils.chmod("g+s", gems_path)
+ end
+
+ it "should create the gem directory with proper permissions" do
+ with_umask(0o002) do
+ bundle_config "path vendor"
+ bundle :install
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+ # Linux's SysV-derived mkdir(2) propagates the set-group-ID bit
+ # from the parent directory to newly created subdirectories. BSD
+ # (including macOS) inherits the parent's group via mkdir(2) but
+ # does not copy the set-group-ID bit itself, so the expected
+ # mode differs by platform.
+ expected = RUBY_PLATFORM.include?("darwin") ? 0o0775 : 0o2775
+ expect(File.stat(foo_path).mode & 0o7777).to eq(expected)
+ end
+ end
+ end
+
+ describe "parallel make" do
+ before do
+ unless Gem::Installer.private_method_defined?(:build_jobs)
+ skip "This example is runnable when RubyGems::Installer implements `build_jobs`"
+ end
+
+ @old_makeflags = ENV["MAKEFLAGS"]
+ @gemspec = nil
+
+ extconf_code = <<~CODE
+ require "mkmf"
+ create_makefile("foo")
+ CODE
+
+ build_repo4 do
+ build_gem "mypsych", "4.0.6" do |s|
+ @gemspec = s
+ extension = "ext/mypsych/extconf.rb"
+ s.extensions = extension
+
+ s.write(extension, extconf_code)
+ end
+ end
+ end
+
+ after do
+ if @old_makeflags
+ ENV["MAKEFLAGS"] = @old_makeflags
+ else
+ ENV.delete("MAKEFLAGS")
+ end
+ end
+
+ it "doesn't pass down -j to make when MAKEFLAGS is set" do
+ ENV["MAKEFLAGS"] = "-j1"
+
+ install_gemfile(<<~G, env: { "BUNDLE_JOBS" => "8" })
+ source "https://gem.repo4"
+ gem "mypsych"
+ G
+
+ gem_make_out = File.read(File.join(@gemspec.extension_dir, "gem_make.out"))
+
+ expect(gem_make_out).not_to include("make -j8")
+ end
+
+ it "pass down the BUNDLE_JOBS to RubyGems when running the compilation of an extension" do
+ ENV.delete("MAKEFLAGS")
+
+ install_gemfile(<<~G, env: { "BUNDLE_JOBS" => "8" })
+ source "https://gem.repo4"
+ gem "mypsych"
+ G
+
+ gem_make_out = File.read(File.join(@gemspec.extension_dir, "gem_make.out"))
+
+ expect(gem_make_out).to include("make -j8")
+ end
+
+ it "uses nprocessors by default" do
+ ENV.delete("MAKEFLAGS")
+
+ install_gemfile(<<~G)
+ source "https://gem.repo4"
+ gem "mypsych"
+ G
+
+ gem_make_out = File.read(File.join(@gemspec.extension_dir, "gem_make.out"))
+
+ expect(gem_make_out).to include("make -j#{Etc.nprocessors + 1}")
+ end
+ end
+
+ describe "when a native extension requires a transitive dependency at build time" do
+ before do
+ build_repo4 do
+ build_gem "alpha", "1.0.0" do |s|
+ extension = "ext/alpha/extconf.rb"
+ s.extensions = extension
+ s.write(extension, <<~CODE)
+ require "mkmf"
+ sleep 1
+ create_makefile("alpha")
+ CODE
+ s.write "lib/alpha.rb", "ALPHA = '1.0.0'"
+ end
+
+ build_gem "beta", "1.0.0" do |s|
+ s.add_dependency "alpha"
+ s.write "lib/beta.rb", "require 'alpha'\nBETA = '1.0.0'"
+ end
+
+ build_gem "gamma", "1.0.0" do |s|
+ s.add_dependency "beta"
+ extension = "ext/gamma/extconf.rb"
+ s.extensions = extension
+ s.write(extension, <<~EXTCONF)
+ require "beta"
+ require "mkmf"
+ create_makefile("gamma")
+ EXTCONF
+ end
+ end
+ end
+
+ it "installs successfully" do
+ install_gemfile <<~G
+ source "https://gem.repo4"
+ gem "gamma"
+ G
+
+ expect(the_bundle).to include_gems "alpha 1.0.0", "beta 1.0.0", "gamma 1.0.0"
+ end
+ end
+
describe "when configured path is UTF-8 and a file inside a gem package too" do
let(:app_path) do
path = tmp("♥")
@@ -1275,7 +1478,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "works" do
- bundle "config path #{app_path}/vendor/bundle", dir: app_path
+ bundle "config set path #{app_path}/vendor/bundle", dir: app_path
install_gemfile app_path.join("Gemfile"),<<~G, dir: app_path
source "https://gem.repo4"
@@ -1290,7 +1493,7 @@ RSpec.describe "bundle install with gem sources" do
source "https://gem.repo1"
gem "myrack"
G
- bundle "config set --local path bundle"
+ bundle_config "path bundle"
bundle "install", standalone: true
end
@@ -1348,7 +1551,7 @@ RSpec.describe "bundle install with gem sources" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform("x86_64-linux", &example)
@@ -1375,12 +1578,12 @@ RSpec.describe "bundle install with gem sources" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "fails loudly if frozen mode set" do
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install", raise_on_error: false
expect(err).to eq(
@@ -1451,12 +1654,12 @@ RSpec.describe "bundle install with gem sources" do
#{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "automatically fixes the lockfile" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
simulate_platform "x86_64-linux" do
bundle "install", artifice: "compact_index"
@@ -1492,12 +1695,62 @@ RSpec.describe "bundle install with gem sources" do
loofah (~> 2.12.0)
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when lockfile has incorrect dependencies" do
+ before do
+ build_repo2
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack_middleware"
+ G
+
+ system_gems "myrack_middleware-1.0", path: default_bundle_path
+
+ # we want to raise when the 1.0 line should be followed by " myrack (= 0.9.1)" but isn't
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo2/
+ specs:
+ myrack_middleware (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ myrack_middleware
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
+
+ it "raises a clear error message when frozen" do
+ bundle_config "frozen true"
+ bundle "install", raise_on_error: false
+
+ expect(exitstatus).to eq(41)
+ expect(err).to include("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("myrack: gemspec specifies = 0.9.1, not in lockfile")
+ end
+
+ it "updates the lockfile when not frozen" do
+ missing_dep = "myrack (0.9.1)"
+ expect(lockfile).not_to include(missing_dep)
+
+ bundle_config "frozen false"
+ bundle :install
+
+ expect(lockfile).to include(missing_dep)
+ expect(out).to include("now installed")
+ end
end
context "with --local flag" do
@@ -1520,7 +1773,7 @@ RSpec.describe "bundle install with gem sources" do
context "with only option" do
before do
- bundle "config set only a:b"
+ bundle_config "only a:b"
end
it "installs only gems of the specified groups" do
@@ -1634,7 +1887,7 @@ RSpec.describe "bundle install with gem sources" do
before do
symlinked_bundled_app = tmp("bundled_app-symlink")
File.symlink(bundled_app, symlinked_bundled_app)
- bundle "config path #{File.join(symlinked_bundled_app, ".vendor")}"
+ bundle_config "path #{File.join(symlinked_bundled_app, ".vendor")}"
binman_path = tmp("binman")
FileUtils.mkdir_p binman_path
@@ -1723,7 +1976,7 @@ RSpec.describe "bundle install with gem sources" do
zzz!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1773,7 +2026,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "only installs executable files in bin" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<~G
source "https://gem.repo1"
@@ -1785,6 +2038,25 @@ RSpec.describe "bundle install with gem sources" do
expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables)
end
+ it "prevents removing binstubs when BUNDLE_CLEAN is set" do
+ build_repo4 do
+ build_gem "kamal", "4.0.6" do |s|
+ s.executables = ["kamal"]
+ end
+ end
+
+ gemfile = <<~G
+ source "https://gem.repo4"
+ gem "kamal"
+ G
+
+ install_gemfile(gemfile, env: { "BUNDLE_CLEAN" => "true", "BUNDLE_PATH" => "vendor/bundle" })
+
+ expected_executables = [vendored_gems("bin/kamal").to_s]
+ expected_executables << vendored_gems("bin/kamal.bat").to_s if Gem.win_platform?
+ expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables)
+ end
+
it "preserves lockfile versions conservatively" do
build_repo4 do
build_gem "mypsych", "4.0.6" do |s|
@@ -1814,7 +2086,7 @@ RSpec.describe "bundle install with gem sources" do
mypsych (~> 4.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<~G
@@ -1837,7 +2109,7 @@ RSpec.describe "bundle install with gem sources" do
mypsych (~> 5.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/commands/licenses_spec.rb b/spec/bundler/commands/licenses_spec.rb
index bfec938efd..ebfad5ed4a 100644
--- a/spec/bundler/commands/licenses_spec.rb
+++ b/spec/bundler/commands/licenses_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe "bundle licenses" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :licenses
expect(out).to include("Installing foo 1.0")
end
diff --git a/spec/bundler/commands/list_spec.rb b/spec/bundler/commands/list_spec.rb
index cc0db9169d..c890646a81 100644
--- a/spec/bundler/commands/list_spec.rb
+++ b/spec/bundler/commands/list_spec.rb
@@ -1,6 +1,28 @@
# frozen_string_literal: true
+require "json"
+
RSpec.describe "bundle list" do
+ def find_gem_name(json:, name:)
+ parse_json(json)["gems"].detect {|h| h["name"] == name }
+ end
+
+ def parse_json(json)
+ JSON.parse(json)
+ end
+
+ context "in verbose mode" do
+ it "logs the actual flags passed to the command" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ G
+
+ bundle "list --verbose"
+
+ expect(out).to include("Running `bundle list --verbose`")
+ end
+ end
+
context "with name-only and paths option" do
it "raises an error" do
bundle "list --name-only --paths", raise_on_error: false
@@ -17,6 +39,20 @@ RSpec.describe "bundle list" do
end
end
+ context "with invalid format option" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ G
+ end
+
+ it "raises an error" do
+ bundle "list --format=nope", raise_on_error: false
+
+ expect(err).to eq "Unknown option`--format=nope`. Supported formats: `json`"
+ end
+ end
+
describe "with without-group option" do
before do
install_gemfile <<-G
@@ -36,6 +72,17 @@ RSpec.describe "bundle list" do
expect(out).to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
+
+ it "prints the gems not in the specified group with json" do
+ bundle "list --without-group test --format=json"
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem["version"]).to eq("1.0.0")
+ gem = find_gem_name(json: out, name: "rails")
+ expect(gem["version"]).to eq("2.3.2")
+ gem = find_gem_name(json: out, name: "rspec")
+ expect(gem).to be_nil
+ end
end
context "when group is not found" do
@@ -54,6 +101,17 @@ RSpec.describe "bundle list" do
expect(out).not_to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
+
+ it "prints the gems not in the specified groups with json" do
+ bundle "list --without-group test production --format=json"
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem["version"]).to eq("1.0.0")
+ gem = find_gem_name(json: out, name: "rails")
+ expect(gem).to be_nil
+ gem = find_gem_name(json: out, name: "rspec")
+ expect(gem).to be_nil
+ end
end
end
@@ -75,6 +133,15 @@ RSpec.describe "bundle list" do
expect(out).to include(" * myrack (1.0.0)")
expect(out).not_to include(" * rspec (1.2.7)")
end
+
+ it "prints the gems in the specified group with json" do
+ bundle "list --only-group default --format=json"
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem["version"]).to eq("1.0.0")
+ gem = find_gem_name(json: out, name: "rspec")
+ expect(gem).to be_nil
+ end
end
context "when group is not found" do
@@ -93,6 +160,17 @@ RSpec.describe "bundle list" do
expect(out).to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
+
+ it "prints the gems in the specified groups with json" do
+ bundle "list --only-group default production --format=json"
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem["version"]).to eq("1.0.0")
+ gem = find_gem_name(json: out, name: "rails")
+ expect(gem["version"]).to eq("2.3.2")
+ gem = find_gem_name(json: out, name: "rspec")
+ expect(gem).to be_nil
+ end
end
end
@@ -112,6 +190,15 @@ RSpec.describe "bundle list" do
expect(out).to include("myrack")
expect(out).to include("rspec")
end
+
+ it "prints only the name of the gems in the bundle with json" do
+ bundle "list --name-only --format=json"
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem.keys).to eq(["name"])
+ gem = find_gem_name(json: out, name: "rspec")
+ expect(gem.keys).to eq(["name"])
+ end
end
context "with paths option" do
@@ -146,6 +233,27 @@ RSpec.describe "bundle list" do
expect(out).to match(%r{.*\/git_test\-\w})
expect(out).to match(%r{.*\/gemspec_test})
end
+
+ it "prints the path of each gem in the bundle with json" do
+ bundle "list --paths --format=json"
+
+ gem = find_gem_name(json: out, name: "rails")
+ expect(gem["path"]).to match(%r{.*\/rails\-2\.3\.2})
+ expect(gem["git_version"]).to be_nil
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem["path"]).to match(%r{.*\/myrack\-1\.2})
+ expect(gem["git_version"]).to be_nil
+
+ gem = find_gem_name(json: out, name: "git_test")
+ expect(gem["path"]).to match(%r{.*\/git_test\-\w})
+ expect(gem["git_version"]).to be_truthy
+ expect(gem["git_version"].strip).to eq(gem["git_version"])
+
+ gem = find_gem_name(json: out, name: "gemspec_test")
+ expect(gem["path"]).to match(%r{.*\/gemspec_test})
+ expect(gem["git_version"]).to be_nil
+ end
end
context "when no gems are in the gemfile" do
@@ -159,6 +267,11 @@ RSpec.describe "bundle list" do
bundle "list"
expect(out).to include("No gems in the Gemfile")
end
+
+ it "prints empty json" do
+ bundle "list --format=json"
+ expect(parse_json(out)["gems"]).to eq([])
+ end
end
context "without options" do
@@ -175,6 +288,13 @@ RSpec.describe "bundle list" do
bundle "list"
expect(out).to include(" * myrack (1.0.0)")
end
+
+ it "lists gems installed in the bundle with json" do
+ bundle "list --format=json"
+
+ gem = find_gem_name(json: out, name: "myrack")
+ expect(gem["version"]).to eq("1.0.0")
+ end
end
context "when using the ls alias" do
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index 11b8164cbd..8ab3cc7e8d 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -95,15 +95,14 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
let(:gemfile_with_rails_weakling_and_foo_from_repo4) do
build_repo4 do
- FileUtils.cp rake_path, "#{gem_repo4}/gems/"
-
build_gem "rake", "10.0.1"
+ build_gem "rake", rake_version
%w[2.3.1 2.3.2].each do |version|
build_gem "rails", version do |s|
@@ -295,7 +294,7 @@ RSpec.describe "bundle lock" do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(out).to match(/Writing lockfile to.+CustomGemfile\.lock/)
expect(read_lockfile("CustomGemfile.lock")).to eq(lockfile)
@@ -312,6 +311,44 @@ RSpec.describe "bundle lock" do
expect { read_lockfile }.to raise_error(Errno::ENOENT)
end
+ it "updates a specific gem and write to a custom location" do
+ build_repo4 do
+ build_gem "foo", %w[1.0.2 1.0.3]
+ build_gem "warning", %w[1.4.0 1.5.0]
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "foo"
+ gem "warning"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4
+ specs:
+ foo (1.0.2)
+ warning (1.4.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ uri
+ warning
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock --update foo --lockfile=lock"
+
+ lockfile_content = read_lockfile("lock")
+ expect(lockfile_content).to include("foo (1.0.3)")
+ expect(lockfile_content).to include("warning (1.4.0)")
+ end
+
it "writes to custom location using --lockfile when a default lockfile is present" do
gemfile_with_rails_weakling_and_foo_from_repo4
@@ -362,7 +399,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(out).to match(/Writing lockfile to.+lock/)
@@ -416,7 +453,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_with_outdated_rails_and_rake
@@ -473,7 +510,7 @@ RSpec.describe "bundle lock" do
tapioca
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update tapioca --verbose"
@@ -539,7 +576,7 @@ RSpec.describe "bundle lock" do
tapioca
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update tapioca"
@@ -612,7 +649,7 @@ RSpec.describe "bundle lock" do
rake
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update rake --verbose"
@@ -640,8 +677,8 @@ RSpec.describe "bundle lock" do
gem "thin"
gem "myrack_middleware", :group => "test"
G
- bundle "config set without test"
- bundle "config set path vendor/bundle"
+ bundle_config "without test"
+ bundle_config "path vendor/bundle"
bundle "lock", verbose: true
expect(bundled_app("vendor/bundle")).not_to exist
end
@@ -769,7 +806,7 @@ RSpec.describe "bundle lock" do
sequel
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
@@ -795,14 +832,14 @@ RSpec.describe "bundle lock" do
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")
+ expect(lockfile).to end_with("BUNDLED WITH\n 55\n")
- update_repo4 do
+ build_repo4 do
build_gem "bundler", "99"
end
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")
+ expect(lockfile).to end_with("BUNDLED WITH\n 99\n")
end
it "supports adding new platforms when there's no previous lockfile" do
@@ -857,7 +894,7 @@ RSpec.describe "bundle lock" do
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --add-platform java"
@@ -877,7 +914,7 @@ RSpec.describe "bundle lock" do
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -900,7 +937,7 @@ RSpec.describe "bundle lock" do
platform_specific
L
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "lock --add-platform java x86-mingw32"
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
@@ -973,7 +1010,7 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
checksums.delete("nokogiri", Gem::Platform::RUBY)
@@ -995,7 +1032,7 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1072,10 +1109,10 @@ RSpec.describe "bundle lock" do
mixlib-shellout
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle :lock
checksums.checksum gem_repo4, "ffi", "1.9.14"
@@ -1104,7 +1141,7 @@ RSpec.describe "bundle lock" do
mixlib-shellout
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1141,7 +1178,7 @@ RSpec.describe "bundle lock" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
simulate_platform("x86_64-darwin-19") { bundle "lock --update" }
@@ -1188,7 +1225,7 @@ RSpec.describe "bundle lock" do
libv8
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1228,7 +1265,7 @@ RSpec.describe "bundle lock" do
libv8
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
previous_lockfile = lockfile
@@ -1257,11 +1294,6 @@ RSpec.describe "bundle lock" do
end
build_gem "raygun-apm", "1.0.78" do |s|
- s.platform = "x64-mingw32"
- s.required_ruby_version = "< #{next_ruby_minor}.dev"
- end
-
- build_gem "raygun-apm", "1.0.78" do |s|
s.platform = "x64-mingw-ucrt"
s.required_ruby_version = "< #{next_ruby_minor}.dev"
end
@@ -1286,7 +1318,7 @@ RSpec.describe "bundle lock" do
raygun-apm
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --add-platform x86_64-linux"
@@ -1320,7 +1352,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1342,64 +1374,50 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
- it "does not crash on conflicting ruby requirements between platform versions in two different gems" do
+ it "refuses to add platforms incompatible with the lockfile" 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"
+ build_gem "sorbet-static", "0.5.11989" do |s|
+ s.platform = "x86_64-linux"
end
end
gemfile <<~G
source "https://gem.repo4"
- gem "google-protobuf"
- gem "unf_ext"
+ gem "sorbet-static"
G
lockfile <<~L
GEM
remote: https://gem.repo4/
specs:
- google-protobuf (3.21.12)
- unf_ext (0.0.8.2)
+ sorbet-static (0.5.11989-x86_64-linux)
PLATFORMS
- x64-mingw-ucrt
- x64-mingw32
+ x86_64-linux
DEPENDENCIES
- google-protobuf
- unf_ext
+ sorbet-static
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
- bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "DEBUG_RESOLVER" => "1" }
+ simulate_platform "x86_64-linux" do
+ bundle "lock --add-platform ruby", raise_on_error: false
+ end
+
+ nice_error = <<~E.strip
+ Could not find gems matching 'sorbet-static' valid for all resolution platforms (x86_64-linux, ruby) in rubygems repository https://gem.repo4/ or installed locally.
+
+ The source contains the following gems matching 'sorbet-static':
+ * sorbet-static-0.5.11989-x86_64-linux
+ E
+ expect(err).to include(nice_error)
end
it "respects lower bound ruby requirements" do
@@ -1428,7 +1446,7 @@ RSpec.describe "bundle lock" do
our_private_gem
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
@@ -1438,7 +1456,7 @@ RSpec.describe "bundle lock" do
before do
gemfile_with_rails_weakling_and_foo_from_repo4
- update_repo4 do
+ build_repo4 do
build_gem "foo", "2.0"
end
@@ -1492,7 +1510,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(read_lockfile).to eq(expected_lockfile)
@@ -1546,7 +1564,7 @@ RSpec.describe "bundle lock" do
weakling
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(read_lockfile).to eq(expected_lockfile)
@@ -1600,7 +1618,7 @@ RSpec.describe "bundle lock" do
debug
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-22" do
@@ -1623,7 +1641,65 @@ RSpec.describe "bundle lock" do
debug
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when a system gem has incorrect dependencies, different from remote gems" do
+ before do
+ build_repo4 do
+ build_gem "foo", "1.0.0" do |s|
+ s.add_dependency "bar"
+ end
+
+ build_gem "bar", "1.0.0"
+ end
+
+ system_gems "foo-1.0.0", gem_repo: gem_repo4, path: default_bundle_path
+
+ # simulate gemspec with wrong empty dependencies
+ foo_gemspec_path = default_bundle_path("specifications/foo-1.0.0.gemspec")
+ foo_gemspec = Gem::Specification.load(foo_gemspec_path.to_s)
+ foo_gemspec.dependencies.clear
+ File.write(foo_gemspec_path, foo_gemspec.to_ruby)
+ end
+
+ it "generates a lockfile using remote dependencies, and prints a warning" do
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "foo"
+ G
+
+ checksums = checksums_section_when_enabled do |c|
+ c.checksum gem_repo4, "foo", "1.0.0"
+ c.checksum gem_repo4, "bar", "1.0.0"
+ end
+
+ simulate_platform "x86_64-linux" do
+ bundle "lock --verbose"
+ end
+
+ expect(err).to eq("Local specification for foo-1.0.0 has different dependencies than the remote gem, ignoring it")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ bar (1.0.0)
+ foo (1.0.0)
+ bar
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ foo
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
end
@@ -1726,7 +1802,7 @@ RSpec.describe "bundle lock" do
ransack (= 3.1.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expected_error = <<~ERR.strip
@@ -1868,7 +1944,7 @@ RSpec.describe "bundle lock" do
nogokiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1895,7 +1971,7 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1928,7 +2004,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -1955,7 +2031,57 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "adds checksums when source is not specified" do
+ system_gems(%w[myrack-1.0.0], path: default_bundle_path)
+
+ gemfile <<-G
+ gem "myrack"
+ G
+
+ lockfile <<~L
+ GEM
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ myrack
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "lock --add-checksums"
+ end
+
+ # myrack is coming from gem_repo1
+ # but it's simulated to install in the system gems path
+ checksums = checksums_section do |c|
+ c.checksum gem_repo1, "myrack", "1.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ myrack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
@@ -1988,7 +2114,7 @@ RSpec.describe "bundle lock" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-linux" do
@@ -2017,11 +2143,11 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
- it "generates checksums by default if configured to do so" do
+ it "generates checksums by default" do
build_repo4 do
build_gem "nokogiri", "1.14.2"
build_gem "nokogiri", "1.14.2" do |s|
@@ -2029,8 +2155,6 @@ RSpec.describe "bundle lock" do
end
end
- bundle "config lockfile_checksums true"
-
simulate_platform "x86_64-linux" do
install_gemfile <<-G
source "https://gem.repo4"
@@ -2059,7 +2183,136 @@ RSpec.describe "bundle lock" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "disables checksums if configured to do so" do
+ build_repo4 do
+ build_gem "nokogiri", "1.14.2"
+ build_gem "nokogiri", "1.14.2" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ bundle_config "lockfile_checksums false"
+
+ simulate_platform "x86_64-linux" do
+ install_gemfile <<-G
+ source "https://gem.repo4"
+
+ gem "nokogiri"
+ G
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ nokogiri (1.14.2)
+ nokogiri (1.14.2-x86_64-linux)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "add checksums for gems installed on disk" do
+ build_repo4 do
+ build_gem "warning", "18.0.0"
+ end
+
+ bundle_config "lockfile_checksums false"
+
+ simulate_platform "x86_64-linux" do
+ install_gemfile(<<-G, artifice: "endpoint")
+ source "https://gem.repo4"
+
+ gem "warning"
+ G
+
+ bundle "config --delete lockfile_checksums"
+ bundle("lock --add-checksums", artifice: "endpoint")
+ end
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo4, "warning", "18.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ warning (18.0.0)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ warning
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "doesn't add checksum for gems not installed on disk" do
+ lockfile(<<~L)
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ warning (18.0.0)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ warning
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile(<<~G)
+ source "https://gem.repo4"
+
+ gem "warning"
+ G
+
+ build_repo4 do
+ build_gem "warning", "18.0.0"
+ end
+
+ FileUtils.rm_rf("#{gem_repo4}/gems")
+
+ bundle("lock --add-checksums", artifice: "endpoint")
+
+ checksums = checksums_section_when_enabled do |c|
+ c.no_checksum "warning", "18.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ warning (18.0.0)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ warning
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
@@ -2140,7 +2393,7 @@ RSpec.describe "bundle lock" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2170,7 +2423,7 @@ RSpec.describe "bundle lock" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2199,14 +2452,13 @@ RSpec.describe "bundle lock" do
nokogiri (1.14.2-x86_64-linux)
PLATFORMS
- ruby
x86_64-linux
DEPENDENCIES
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2261,7 +2513,7 @@ RSpec.describe "bundle lock" do
govuk_app_config
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2297,7 +2549,7 @@ RSpec.describe "bundle lock" do
govuk_app_config
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2333,7 +2585,7 @@ RSpec.describe "bundle lock" do
ffi
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2357,8 +2609,269 @@ RSpec.describe "bundle lock" do
ffi
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ describe "--normalize-platforms on linux" do
+ let(:normalized_lockfile) do
+ <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ irb (1.0.0)
+ irb (1.0.0-x86_64-linux)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ irb
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ before do
+ build_repo4 do
+ build_gem "irb", "1.0.0"
+
+ build_gem "irb", "1.0.0" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "irb"
+ G
+ end
+
+ context "when already normalized" do
+ before do
+ lockfile normalized_lockfile
+ end
+
+ it "is a noop" do
+ simulate_platform "x86_64-linux" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(normalized_lockfile)
+ end
+ end
+
+ context "when not already normalized" do
+ before do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ irb (1.0.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ irb
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "normalizes the list of platforms and native gems in the lockfile" do
+ simulate_platform "x86_64-linux" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(normalized_lockfile)
+ end
+ end
+ end
+
+ describe "--normalize-platforms on darwin" do
+ let(:normalized_lockfile) do
+ <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ irb (1.0.0)
+ irb (1.0.0-arm64-darwin)
+
+ PLATFORMS
+ arm64-darwin
+ ruby
+
+ DEPENDENCIES
+ irb
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ before do
+ build_repo4 do
+ build_gem "irb", "1.0.0"
+
+ build_gem "irb", "1.0.0" do |s|
+ s.platform = "arm64-darwin"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "irb"
+ G
+ end
+
+ context "when already normalized" do
+ before do
+ lockfile normalized_lockfile
+ end
+
+ it "is a noop" do
+ simulate_platform "arm64-darwin-23" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(normalized_lockfile)
+ end
+ end
+
+ context "when having only ruby" do
+ before do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ irb (1.0.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ irb
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "normalizes the list of platforms and native gems in the lockfile" do
+ simulate_platform "arm64-darwin-23" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(normalized_lockfile)
+ end
+ end
+
+ context "when having only the current platform with version" do
+ before do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ irb (1.0.0-arm64-darwin)
+
+ PLATFORMS
+ arm64-darwin-23
+
+ DEPENDENCIES
+ irb
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "normalizes the list of platforms by removing version" do
+ simulate_platform "arm64-darwin-23" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(normalized_lockfile)
+ end
+ end
+
+ context "when having other platforms with version" do
+ before do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ irb (1.0.0-arm64-darwin)
+
+ PLATFORMS
+ arm64-darwin-22
+
+ DEPENDENCIES
+ irb
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "normalizes the list of platforms by removing version" do
+ simulate_platform "arm64-darwin-23" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(normalized_lockfile)
+ end
+ end
+ end
+
+ describe "--normalize-platforms with gems without generic variant" do
+ let(:original_lockfile) do
+ <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ sorbet-static (1.0-x86_64-linux)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ sorbet-static
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
+
+ before do
+ build_repo4 do
+ build_gem "sorbet-static" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "sorbet-static"
+ G
+
+ lockfile original_lockfile
+ end
+
+ it "removes invalid platforms" do
+ simulate_platform "x86_64-linux" do
+ bundle "lock --normalize-platforms"
+ end
+
+ expect(lockfile).to eq(original_lockfile.gsub(/^ ruby\n/m, ""))
+ end
end
end
diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb
index a7fe31143d..65fbad05aa 100644
--- a/spec/bundler/commands/newgem_spec.rb
+++ b/spec/bundler/commands/newgem_spec.rb
@@ -6,39 +6,54 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/README.md")).to exist
expect(bundled_app("#{gem_name}/Gemfile")).to exist
expect(bundled_app("#{gem_name}/Rakefile")).to exist
- expect(bundled_app("#{gem_name}/lib/#{require_path}.rb")).to exist
- expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb")).to exist
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}.rb")).to exist
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}/version.rb")).to exist
+
+ expect(ignore_paths).to include("bin/")
+ expect(ignore_paths).to include("Gemfile")
end
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 "config set path #{rubocop_gem_path}", 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 "config set path #{standard_gem_path}", 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")) }
-
- let(:gem_name) { "mygem" }
+ def ignore_paths
+ generated = bundled_app("#{gem_name}/#{gem_name}.gemspec").read
+ matched = generated.match(/^\s+f\.start_with\?\(\*%w\[(?<ignored>.*)\]\)$/)
+ matched[:ignored]&.split(" ")
+ end
- let(:require_path) { "mygem" }
+ def installed_go?
+ sys_exec("go version", raise_on_error: true)
+ true
+ rescue StandardError
+ false
+ end
- let(:minitest_test_file_path) { "test/test_mygem.rb" }
+ let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
- let(:minitest_test_class_name) { "class TestMygem < Minitest::Test" }
+ let(:gem_name) { "mygem" }
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"
+ bundle_config_global "gem.mit false"
+ bundle_config_global "gem.test false"
+ bundle_config_global "gem.coc false"
+ bundle_config_global "gem.linter false"
+ bundle_config_global "gem.ci false"
+ bundle_config_global "gem.changelog false"
+ bundle_config_global "gem.bundle false"
end
describe "git repo initialization" do
@@ -152,64 +167,23 @@ RSpec.describe "bundle gem" do
end
end
- shared_examples_for "--rubocop flag" do
- context "is deprecated", bundler: "< 3" do
- before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "gem #{gem_name} --rubocop"
- end
-
- it "generates a gem skeleton with rubocop" do
- gem_skeleton_assertions
- expect(bundled_app("test-gem/Rakefile")).to read_as(
- include("# frozen_string_literal: true").
- and(include('require "rubocop/rake_task"').
- and(include("RuboCop::RakeTask.new").
- and(match(/default:.+:rubocop/))))
- )
- end
-
- it "includes rubocop in generated Gemfile" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
- expect(rubocop_dep).not_to be_nil
- end
-
- it "generates a default .rubocop.yml" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
- end
+ shared_examples_for "--bundle flag" do
+ before do
+ bundle "gem #{gem_name} --bundle"
+ end
+ it "generates a gem skeleton with bundle install" do
+ gem_skeleton_assertions
+ expect(out).to include("Running bundle install in the new gem directory.")
end
end
- shared_examples_for "--no-rubocop flag" do
- context "is deprecated", bundler: "< 3" do
- define_negated_matcher :exclude, :include
-
- before do
- bundle "gem #{gem_name} --no-rubocop"
- end
-
- it "generates a gem skeleton without rubocop" do
- gem_skeleton_assertions
- expect(bundled_app("test-gem/Rakefile")).to read_as(exclude("rubocop"))
- expect(bundled_app("test-gem/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
- end
-
- it "does not include rubocop in generated Gemfile" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
- expect(rubocop_dep).to be_nil
- end
-
- it "doesn't generate a default .rubocop.yml" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- end
+ shared_examples_for "--no-bundle flag" do
+ before do
+ bundle "gem #{gem_name} --no-bundle"
+ end
+ it "generates a gem skeleton without bundle install" do
+ gem_skeleton_assertions
+ expect(out).to_not include("Running bundle install in the new gem directory.")
end
end
@@ -220,7 +194,7 @@ RSpec.describe "bundle gem" do
it "generates a gem skeleton with rubocop" do
gem_skeleton_assertions
- expect(bundled_app("test-gem/Rakefile")).to read_as(
+ expect(bundled_app("#{gem_name}/Rakefile")).to read_as(
include("# frozen_string_literal: true").
and(include('require "rubocop/rake_task"').
and(include("RuboCop::RakeTask.new").
@@ -234,12 +208,17 @@ RSpec.describe "bundle gem" do
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
- expect(rubocop_dep).not_to be_nil
+ expect(rubocop_dep).not_to be_specific
+ expect(rubocop_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
it "generates a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
+
+ it "includes .rubocop.yml into ignore list" do
+ expect(ignore_paths).to include(".rubocop.yml")
+ end
end
shared_examples_for "--linter=standard flag" do
@@ -249,7 +228,7 @@ RSpec.describe "bundle gem" do
it "generates a gem skeleton with standard" do
gem_skeleton_assertions
- expect(bundled_app("test-gem/Rakefile")).to read_as(
+ expect(bundled_app("#{gem_name}/Rakefile")).to read_as(
include('require "standard/rake"').
and(match(/default:.+:standard/))
)
@@ -261,12 +240,17 @@ RSpec.describe "bundle gem" do
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
standard_dep = builder.dependencies.find {|d| d.name == "standard" }
- expect(standard_dep).not_to be_nil
+ expect(standard_dep).not_to be_specific
+ expect(standard_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
it "generates a default .standard.yml" do
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
end
+
+ it "includes .standard.yml into ignore list" do
+ expect(ignore_paths).to include(".standard.yml")
+ end
end
shared_examples_for "--no-linter flag" do
@@ -278,8 +262,8 @@ RSpec.describe "bundle gem" do
it "generates a gem skeleton without rubocop" do
gem_skeleton_assertions
- expect(bundled_app("test-gem/Rakefile")).to read_as(exclude("rubocop"))
- expect(bundled_app("test-gem/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
+ expect(bundled_app("#{gem_name}/Rakefile")).to read_as(exclude("rubocop"))
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
end
it "does not include rubocop in generated Gemfile" do
@@ -304,9 +288,17 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
+ it "does not add .rubocop.yml into ignore list" do
+ expect(ignore_paths).not_to include(".rubocop.yml")
+ end
+
it "doesn't generate a default .standard.yml" do
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
+
+ it "does not add .standard.yml into ignore list" do
+ expect(ignore_paths).not_to include(".standard.yml")
+ end
end
it "has no rubocop offenses when using --linter=rubocop flag" do
@@ -353,7 +345,6 @@ RSpec.describe "bundle gem" do
it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag" 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
bundle "gem #{gem_name} --ext=rust --linter=rubocop"
bundle_exec_rubocop
@@ -362,7 +353,6 @@ RSpec.describe "bundle gem" do
it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag" 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
bundle "gem #{gem_name} --ext=rust --test=minitest --linter=rubocop"
bundle_exec_rubocop
@@ -371,7 +361,6 @@ RSpec.describe "bundle gem" do
it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag" 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
bundle "gem #{gem_name} --ext=rust --test=rspec --linter=rubocop"
bundle_exec_rubocop
@@ -380,7 +369,6 @@ RSpec.describe "bundle gem" do
it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag" 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
bundle "gem #{gem_name} --ext=rust --test=test-unit --linter=rubocop"
bundle_exec_rubocop
@@ -398,11 +386,17 @@ RSpec.describe "bundle gem" do
shared_examples_for "test framework is absent" do
it "does not create any test framework files" do
expect(bundled_app("#{gem_name}/.rspec")).to_not exist
- expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to_not exist
+ expect(bundled_app("#{gem_name}/spec/#{gem_name}_spec.rb")).to_not exist
expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to_not exist
- expect(bundled_app("#{gem_name}/test/#{require_path}.rb")).to_not exist
+ expect(bundled_app("#{gem_name}/test/#{gem_name}.rb")).to_not exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to_not exist
end
+
+ it "does not add any test framework files into ignore list" do
+ expect(ignore_paths).not_to include("test/")
+ expect(ignore_paths).not_to include(".rspec")
+ expect(ignore_paths).not_to include("spec/")
+ end
end
context "README.md" do
@@ -454,10 +448,7 @@ RSpec.describe "bundle gem" do
context "when git is not available" 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" => "" }
+ bundle "gem #{gem_name}", env: { "PATH" => "" }
end
it "creates the gem without the need for git" do
@@ -471,9 +462,13 @@ RSpec.describe "bundle gem" do
it "doesn't create a .gitignore file" do
expect(bundled_app("#{gem_name}/.gitignore")).to_not exist
end
+
+ it "does not add .gitignore into ignore list" do
+ expect(ignore_paths).not_to include(".gitignore")
+ end
end
- it "generates a valid gemspec", :ruby_repo do
+ it "generates a valid gemspec" do
bundle "gem newgem --bin"
prepare_gemspec(bundled_app("newgem", "newgem.gemspec"))
@@ -482,11 +477,10 @@ RSpec.describe "bundle gem" do
build_dummy_irb "9.9.9"
end
gems = ["rake-#{rake_version}", "irb-9.9.9"]
- path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(base: bundled_app("newgem")) : system_gem_path
- system_gems gems, path: path, gem_repo: gem_repo2
+ system_gems gems, path: system_gem_path, gem_repo: gem_repo2
bundle "exec rake build", dir: bundled_app("newgem")
- expect(last_command.stdboth).not_to include("ERROR")
+ expect(stdboth).not_to include("ERROR")
end
context "gem naming with relative paths" do
@@ -537,7 +531,7 @@ RSpec.describe "bundle gem" do
shared_examples_for "github_username configuration" do
context "with github_username setting set to some value" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
+ bundle_config_global "gem.github_username different_username"
bundle "gem #{gem_name}"
end
@@ -553,7 +547,7 @@ RSpec.describe "bundle gem" do
context "with github_username setting set to false" do
before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
+ bundle_config_global "gem.github_username false"
bundle "gem #{gem_name}"
end
@@ -568,914 +562,1108 @@ RSpec.describe "bundle gem" do
end
end
- shared_examples_for "generating a gem" do
- it "generates a gem skeleton" do
- bundle "gem #{gem_name}"
-
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to exist
- expect(bundled_app("#{gem_name}/Gemfile")).to exist
- expect(bundled_app("#{gem_name}/Rakefile")).to exist
- expect(bundled_app("#{gem_name}/lib/#{require_path}.rb")).to exist
- expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb")).to exist
- expect(bundled_app("#{gem_name}/sig/#{require_path}.rbs")).to exist
- expect(bundled_app("#{gem_name}/.gitignore")).to exist
+ it "generates a gem skeleton" do
+ bundle "gem #{gem_name}"
- expect(bundled_app("#{gem_name}/bin/setup")).to exist
- expect(bundled_app("#{gem_name}/bin/console")).to exist
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to exist
+ expect(bundled_app("#{gem_name}/Gemfile")).to exist
+ expect(bundled_app("#{gem_name}/Rakefile")).to exist
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}.rb")).to exist
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}/version.rb")).to exist
+ expect(bundled_app("#{gem_name}/sig/#{gem_name}.rbs")).to exist
+ expect(bundled_app("#{gem_name}/.gitignore")).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 exist
+ expect(bundled_app("#{gem_name}/bin/console")).to exist
- expect(bundled_app("#{gem_name}/bin/setup").read).to start_with("#!")
- expect(bundled_app("#{gem_name}/bin/console").read).to start_with("#!")
+ 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
- it "starts with version 0.1.0" do
+ expect(bundled_app("#{gem_name}/bin/setup").read).to start_with("#!")
+ expect(bundled_app("#{gem_name}/bin/console").read).to start_with("#!")
+ end
+
+ it "includes bin/ into ignore list" do
+ bundle "gem #{gem_name}"
+
+ expect(ignore_paths).to include("bin/")
+ end
+
+ it "includes Gemfile into ignore list" do
+ bundle "gem #{gem_name}"
+
+ expect(ignore_paths).to include("Gemfile")
+ end
+
+ it "includes .gitignore into ignore list" do
+ bundle "gem #{gem_name}"
+
+ expect(ignore_paths).to include(".gitignore")
+ end
+
+ it "starts with version 0.1.0" do
+ bundle "gem #{gem_name}"
+
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}/version.rb").read).to match(/VERSION = "0.1.0"/)
+ end
+
+ it "declare String type for VERSION constant" do
+ bundle "gem #{gem_name}"
+
+ expect(bundled_app("#{gem_name}/sig/#{gem_name}.rbs").read).to match(/VERSION: String/)
+ end
+
+ context "git config user.{name,email} is set" do
+ before do
bundle "gem #{gem_name}"
+ end
+
+ it "sets gemspec author to git user.name if available" do
+ expect(generated_gemspec.authors.first).to eq("Bundler User")
+ end
- expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/VERSION = "0.1.0"/)
+ it "sets gemspec email to git user.email if available" do
+ expect(generated_gemspec.email.first).to eq("user@example.com")
end
+ end
- it "declare String type for VERSION constant" 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")
bundle "gem #{gem_name}"
+ end
- expect(bundled_app("#{gem_name}/sig/#{require_path}.rbs").read).to match(/VERSION: String/)
+ it "sets gemspec author to default message if git user.name is not set or empty" do
+ expect(generated_gemspec.authors.first).to eq("TODO: Write your name")
end
- context "git config user.{name,email} is set" do
- before do
- bundle "gem #{gem_name}"
- end
+ it "sets gemspec email to default message if git user.email is not set or empty" do
+ expect(generated_gemspec.email.first).to eq("TODO: Write your email address")
+ end
+ end
- it "sets gemspec author to git user.name if available" do
- expect(generated_gemspec.authors.first).to eq("Bundler User")
- end
+ it "sets gemspec metadata['allowed_push_host']" do
+ bundle "gem #{gem_name}"
+
+ expect(generated_gemspec.metadata["allowed_push_host"]).
+ to match(/example\.com/)
+ end
+
+ it "includes a commented-out rubygems_mfa_required metadata hint" do
+ bundle "gem #{gem_name}"
+
+ gemspec_contents = bundled_app("#{gem_name}/#{gem_name}.gemspec").read
+
+ expect(gemspec_contents).to include('# spec.metadata["rubygems_mfa_required"] = "true"')
+ expect(gemspec_contents).to include("https://guides.rubygems.org/mfa-requirement-opt-in/")
+ end
+
+ it "sets a minimum ruby version" do
+ bundle "gem #{gem_name}"
+
+ expect(generated_gemspec.required_ruby_version.to_s).to start_with(">=")
+ end
+
+ 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
+
+ expect(bundler_gemspec.files).not_to include("#{gem_name}.gemspec")
+ end
- it "sets gemspec email to git user.email if available" do
- expect(generated_gemspec.email.first).to eq("user@example.com")
+ 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}"]
+
+ rakefile = <<~RAKEFILE
+ task :default do
+ puts 'SUCCESS'
end
+ RAKEFILE
+ File.open(bundled_app("#{gem_name}/Rakefile"), "w") do |file|
+ file.puts rakefile
end
- context "git config user.{name,email} is not set" do
- before do
- git("config --global --unset user.name")
- git("config --global --unset user.email")
- bundle "gem #{gem_name}"
- end
+ sys_exec("rake", dir: bundled_app(gem_name))
+ expect(out).to include("SUCCESS")
+ end
- it "sets gemspec author to default message if git user.name is not set or empty" do
- expect(generated_gemspec.authors.first).to eq("TODO: Write your name")
- end
+ context "--exe parameter set" do
+ before do
+ bundle "gem #{gem_name} --exe"
+ end
- it "sets gemspec email to default message if git user.email is not set or empty" do
- expect(generated_gemspec.email.first).to eq("TODO: Write your email address")
+ 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
+ end
- it "sets gemspec metadata['allowed_push_host']" do
- bundle "gem #{gem_name}"
+ context "--bin parameter set" do
+ before do
+ bundle "gem #{gem_name} --bin"
+ end
- expect(generated_gemspec.metadata["allowed_push_host"]).
- to match(/example\.com/)
+ it "builds exe skeleton" do
+ expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
end
+ end
- it "sets a minimum ruby version" do
+ context "no --test parameter" do
+ before do
bundle "gem #{gem_name}"
-
- expect(generated_gemspec.required_ruby_version.to_s).to start_with(">=")
end
- it "requires the version file" do
- bundle "gem #{gem_name}"
+ it_behaves_like "test framework is absent"
+ end
- expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(%r{require_relative "#{require_relative_path}/version"})
+ context "--test parameter set to rspec" do
+ before do
+ bundle "gem #{gem_name} --test=rspec"
end
- it "creates a base error class" do
- bundle "gem #{gem_name}"
+ it "builds spec skeleton" do
+ expect(bundled_app("#{gem_name}/.rspec")).to exist
+ expect(bundled_app("#{gem_name}/spec/#{gem_name}_spec.rb")).to exist
+ expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
+ end
- expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/class Error < StandardError; end$/)
+ it "includes .rspec and spec/ into ignore list" do
+ expect(ignore_paths).to include(".rspec")
+ expect(ignore_paths).to include("spec/")
+ end
+
+ it "depends on a non-specific version of rspec in generated Gemfile" do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ builder = Bundler::Dsl.new
+ builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
+ builder.dependencies
+ rspec_dep = builder.dependencies.find {|d| d.name == "rspec" }
+ expect(rspec_dep).not_to be_specific
+ expect(rspec_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
+ end
- it "does not include the gemspec file in files" do
+ context "init_gems_rb setting to true" do
+ before do
+ bundle_config "init_gems_rb true"
bundle "gem #{gem_name}"
+ end
- bundler_gemspec = Bundler::GemHelper.new(bundled_app(gem_name), gem_name).gemspec
+ 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
- expect(bundler_gemspec.files).not_to include("#{gem_name}.gemspec")
+ it "includes gems.rb and gems.locked into ignore list" do
+ expect(ignore_paths).to include("gems.rb")
+ expect(ignore_paths).to include("gems.locked")
+ expect(ignore_paths).not_to include("Gemfile")
end
+ end
- it "does not include the Gemfile file in files" do
+ context "init_gems_rb setting to false" do
+ before do
+ bundle_config "init_gems_rb false"
bundle "gem #{gem_name}"
+ end
- bundler_gemspec = Bundler::GemHelper.new(bundled_app(gem_name), gem_name).gemspec
+ 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
- expect(bundler_gemspec.files).not_to include("Gemfile")
+ it "includes Gemfile into ignore list" do
+ expect(ignore_paths).to include("Gemfile")
+ expect(ignore_paths).not_to include("gems.rb")
+ expect(ignore_paths).not_to include("gems.locked")
end
+ end
- it "runs rake without problems" do
+ context "gem.test setting set to rspec" do
+ before do
+ bundle_config "gem.test rspec"
bundle "gem #{gem_name}"
+ end
- system_gems ["rake-#{rake_version}"]
-
- rakefile = <<~RAKEFILE
- task :default do
- puts 'SUCCESS'
- end
- RAKEFILE
- File.open(bundled_app("#{gem_name}/Rakefile"), "w") do |file|
- file.puts rakefile
- end
-
- sys_exec(rake, dir: bundled_app(gem_name))
- expect(out).to include("SUCCESS")
+ it "builds spec skeleton" do
+ expect(bundled_app("#{gem_name}/.rspec")).to exist
+ expect(bundled_app("#{gem_name}/spec/#{gem_name}_spec.rb")).to exist
+ expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
end
- context "--exe parameter set" do
- before do
- bundle "gem #{gem_name} --exe"
- end
+ it "includes .rspec and spec/ into ignore list" do
+ expect(ignore_paths).to include(".rspec")
+ expect(ignore_paths).to include("spec/")
+ end
+ end
- 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
+ context "gem.test setting set to rspec and --test is set to minitest" do
+ before do
+ bundle_config "gem.test rspec"
+ bundle "gem #{gem_name} --test=minitest"
+ end
- it "requires the main file" do
- expect(bundled_app("#{gem_name}/exe/#{gem_name}").read).to match(/require "#{require_path}"/)
- end
+ it "builds spec skeleton" do
+ expect(bundled_app("#{gem_name}/test/test_#{gem_name}.rb")).to exist
+ expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
end
- context "--bin parameter set" do
- before do
- bundle "gem #{gem_name} --bin"
- end
+ it "includes test/ into ignore list" do
+ expect(ignore_paths).to include("test/")
+ end
+ end
- it "builds exe skeleton" do
- expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
- end
+ context "--test parameter set to minitest" do
+ before do
+ bundle "gem #{gem_name} --test=minitest"
+ end
- it "requires the main file" do
- expect(bundled_app("#{gem_name}/exe/#{gem_name}").read).to match(/require "#{require_path}"/)
- end
+ it "depends on a non-specific version of minitest" do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ builder = Bundler::Dsl.new
+ builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
+ builder.dependencies
+ minitest_dep = builder.dependencies.find {|d| d.name == "minitest" }
+ expect(minitest_dep).not_to be_specific
+ expect(minitest_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
- context "no --test parameter" do
- before do
- bundle "gem #{gem_name}"
- end
+ it "builds spec skeleton" do
+ expect(bundled_app("#{gem_name}/test/test_#{gem_name}.rb")).to exist
+ expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
+ end
- it_behaves_like "test framework is absent"
+ it "includes test/ into ignore list" do
+ expect(ignore_paths).to include("test/")
end
- context "--test parameter set to rspec" do
- before do
- bundle "gem #{gem_name} --test=rspec"
- end
+ it "creates a default rake task to run the test suite" do
+ rakefile = <<~RAKEFILE
+ # frozen_string_literal: true
- it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/.rspec")).to exist
- expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
- expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
- end
+ require "bundler/gem_tasks"
+ require "minitest/test_task"
- it "depends on a specific version of rspec in generated Gemfile" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- rspec_dep = builder.dependencies.find {|d| d.name == "rspec" }
- expect(rspec_dep).to be_specific
- end
+ Minitest::TestTask.create
- it "requires the main file" do
- expect(bundled_app("#{gem_name}/spec/spec_helper.rb").read).to include(%(require "#{require_path}"))
- end
+ task default: :test
+ RAKEFILE
- it "creates a default test which fails" do
- expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb").read).to include("expect(false).to eq(true)")
- end
+ expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
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
+ context "gem.test setting set to minitest" do
+ before do
+ bundle_config "gem.test minitest"
+ bundle "gem #{gem_name}"
end
- context "init_gems_rb setting to false" do
- before do
- bundle "config set init_gems_rb false"
- bundle "gem #{gem_name}"
- end
+ it "creates a default rake task to run the test suite" do
+ rakefile = <<~RAKEFILE
+ # frozen_string_literal: true
- 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
+ require "bundler/gem_tasks"
+ require "minitest/test_task"
- context "gem.test setting set to rspec" do
- before do
- bundle "config set gem.test rspec"
- bundle "gem #{gem_name}"
- end
+ Minitest::TestTask.create
- it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/.rspec")).to exist
- expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
- expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
- end
+ task default: :test
+ RAKEFILE
+
+ expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
+ end
- context "gem.test setting set to rspec and --test is set to minitest" do
- before do
- bundle "config set gem.test rspec"
- bundle "gem #{gem_name} --test=minitest"
- end
+ context "--test parameter set to test-unit" do
+ before do
+ bundle "gem #{gem_name} --test=test-unit"
+ end
- it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/#{minitest_test_file_path}")).to exist
- expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
- end
+ it "depends on a non-specific version of test-unit" do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ builder = Bundler::Dsl.new
+ builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
+ builder.dependencies
+ test_unit_dep = builder.dependencies.find {|d| d.name == "test-unit" }
+ expect(test_unit_dep).not_to be_specific
+ expect(test_unit_dep.requirement).to eq(Gem::Requirement.new([">= 0"]))
end
- context "--test parameter set to minitest" do
- before do
- bundle "gem #{gem_name} --test=minitest"
- end
+ it "builds spec skeleton" do
+ expect(bundled_app("#{gem_name}/test/#{gem_name}_test.rb")).to exist
+ expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
+ end
- it "depends on a specific version of minitest" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- minitest_dep = builder.dependencies.find {|d| d.name == "minitest" }
- expect(minitest_dep).to be_specific
- end
+ it "includes test/ into ignore list" do
+ expect(ignore_paths).to include("test/")
+ end
- it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/#{minitest_test_file_path}")).to exist
- expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
- end
+ it "creates a default rake task to run the test suite" do
+ rakefile = <<~RAKEFILE
+ # frozen_string_literal: true
- it "requires the main file" do
- expect(bundled_app("#{gem_name}/test/test_helper.rb").read).to include(%(require "#{require_path}"))
- end
+ require "bundler/gem_tasks"
+ require "rake/testtask"
- it "requires 'test_helper'" do
- expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include(%(require "test_helper"))
- end
+ Rake::TestTask.new(:test) do |t|
+ t.libs << "test"
+ t.libs << "lib"
+ t.test_files = FileList["test/**/*_test.rb"]
+ end
- it "defines valid test class name" do
- expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include(minitest_test_class_name)
- end
+ task default: :test
+ RAKEFILE
- it "creates a default test which fails" do
- expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include("assert false")
- end
+ expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
+ end
- context "gem.test setting set to minitest" do
- before do
- bundle "config set gem.test minitest"
- bundle "gem #{gem_name}"
- end
-
- it "creates a default rake task to run the test suite" do
- rakefile = <<~RAKEFILE
- # frozen_string_literal: true
+ context "--test parameter set to an invalid value" do
+ before do
+ bundle "gem #{gem_name} --test=foo", raise_on_error: false
+ end
- require "bundler/gem_tasks"
- require "minitest/test_task"
+ it "fails loudly" do
+ expect(last_command).to be_failure
+ expect(err).to match(/Expected '--test' to be one of .*; got foo/)
+ end
+ end
- Minitest::TestTask.create
+ context "gem.test set to rspec and --test with no arguments" do
+ before do
+ bundle_config "gem.test rspec"
+ bundle "gem #{gem_name} --test"
+ end
- task default: :test
- RAKEFILE
+ it "builds spec skeleton" do
+ expect(bundled_app("#{gem_name}/.rspec")).to exist
+ expect(bundled_app("#{gem_name}/spec/#{gem_name}_spec.rb")).to exist
+ expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
+ end
- expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
- end
+ it "includes .rspec and spec/ into ignore list" do
+ expect(ignore_paths).to include(".rspec")
+ expect(ignore_paths).to include("spec/")
end
- context "--test parameter set to test-unit" do
- before do
- bundle "gem #{gem_name} --test=test-unit"
- end
+ it "hints that --test is already configured" do
+ expect(out).to match("rspec is already configured, ignoring --test flag.")
+ end
+ end
- it "depends on a specific version of test-unit" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- builder = Bundler::Dsl.new
- builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
- builder.dependencies
- test_unit_dep = builder.dependencies.find {|d| d.name == "test-unit" }
- expect(test_unit_dep).to be_specific
+ context "gem.test setting set to false and --test with no arguments", :readline do
+ before do
+ bundle_config "gem.test false"
+ bundle "gem #{gem_name} --test" do |input, _, _|
+ input.puts
end
+ end
- it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb")).to exist
- expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
- end
+ it "asks to generate test files" do
+ expect(out).to match("Do you want to generate tests with your gem?")
+ end
- it "requires the main file" do
- expect(bundled_app("#{gem_name}/test/test_helper.rb").read).to include(%(require "#{require_path}"))
- end
+ it "hints that the choice will only be applied to the current gem" do
+ expect(out).to match("Your choice will only be applied to this gem.")
+ end
- it "requires 'test_helper'" do
- expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb").read).to include(%(require "test_helper"))
- end
+ it_behaves_like "test framework is absent"
+ end
- it "creates a default test which fails" do
- expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb").read).to include("assert_equal(\"expected\", \"actual\")")
+ context "gem.test setting not set and --test with no arguments", :readline do
+ before do
+ bundle_config_global "BUNDLE_GEM__TEST" => nil
+ bundle "gem #{gem_name} --test" do |input, _, _|
+ input.puts
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 "asks to generate test files" do
+ expect(out).to match("Do you want to generate tests with your gem?")
+ end
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--test' to be one of .*; got foo/)
- end
+ it "hints that the choice will be applied to future bundle gem calls" do
+ hint = "Future `bundle gem` calls will use your choice. " \
+ "This setting can be changed anytime with `bundle config gem.test`."
+ expect(out).to match(hint)
end
- context "gem.test setting set to test-unit" do
- before do
- bundle "config set gem.test test-unit"
- bundle "gem #{gem_name}"
- end
+ it_behaves_like "test framework is absent"
+ end
- it "creates a default rake task to run the test suite" do
- rakefile = <<~RAKEFILE
- # frozen_string_literal: true
+ context "gem.test setting set to a test framework and --no-test" do
+ before do
+ bundle_config "gem.test rspec"
+ bundle "gem #{gem_name} --no-test"
+ end
- require "bundler/gem_tasks"
- require "rake/testtask"
+ it_behaves_like "test framework is absent"
+ end
- Rake::TestTask.new(:test) do |t|
- t.libs << "test"
- t.libs << "lib"
- t.test_files = FileList["test/**/*_test.rb"]
- end
+ context "--ci with no argument" do
+ before do
+ bundle "gem #{gem_name}"
+ end
- task default: :test
- RAKEFILE
+ 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
- expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
- end
+ it "does not add any CI config files into ignore list" do
+ expect(ignore_paths).not_to include(".github/")
+ expect(ignore_paths).not_to include(".gitlab-ci.yml")
+ expect(ignore_paths).not_to include(".circleci/")
end
+ end
- context "gem.test set to rspec and --test with no arguments" do
- before do
- bundle "config set gem.test rspec"
- bundle "gem #{gem_name} --test"
- end
+ context "--ci set to github" do
+ before do
+ bundle "gem #{gem_name} --ci=github"
+ end
- it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/.rspec")).to exist
- expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
- expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
- end
+ it "generates a GitHub Actions config file" do
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
+ end
- it "hints that --test is already configured" do
- expect(out).to match("rspec is already configured, ignoring --test flag.")
- end
+ it "includes .github/ into ignore list" do
+ expect(ignore_paths).to include(".github/")
end
+ end
- context "gem.test setting set to false and --test with no arguments", :readline do
- before do
- bundle "config set gem.test false"
- bundle "gem #{gem_name} --test" do |input, _, _|
- input.puts
- end
- end
+ context "--ci set to gitlab" do
+ before do
+ bundle "gem #{gem_name} --ci=gitlab"
+ end
- it "asks to generate test files" do
- expect(out).to match("Do you want to generate tests with your gem?")
- end
+ it "generates a GitLab CI config file" do
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
+ end
- it "hints that the choice will only be applied to the current gem" do
- expect(out).to match("Your choice will only be applied to this gem.")
- end
+ it "includes .gitlab-ci.yml into ignore list" do
+ expect(ignore_paths).to include(".gitlab-ci.yml")
+ end
+ end
- it_behaves_like "test framework is absent"
+ context "--ci set to circle" do
+ before do
+ bundle "gem #{gem_name} --ci=circle"
end
- context "gem.test setting not set and --test with no arguments", :readline do
- before do
- global_config "BUNDLE_GEM__TEST" => nil
- bundle "gem #{gem_name} --test" do |input, _, _|
- input.puts
- end
- end
+ it "generates a CircleCI config file" do
+ expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
+ end
- it "asks to generate test files" do
- expect(out).to match("Do you want to generate tests with your gem?")
- end
+ it "includes .circleci/ into ignore list" do
+ expect(ignore_paths).to include(".circleci/")
+ end
+ end
- it "hints that the choice will be applied to future bundle gem calls" do
- hint = "Future `bundle gem` calls will use your choice. " \
- "This setting can be changed anytime with `bundle config gem.test`."
- expect(out).to match(hint)
- end
+ context "--ci set to an invalid value" do
+ before do
+ bundle "gem #{gem_name} --ci=foo", raise_on_error: false
+ end
- it_behaves_like "test framework is absent"
+ 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.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
+ context "gem.ci setting set to none" do
+ it "doesn't 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
- it_behaves_like "test framework is absent"
+ context "gem.ci setting set to github" do
+ it "generates a GitHub Actions config file" do
+ bundle_config "gem.ci github"
+ bundle "gem #{gem_name}"
+
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
+ end
- context "--ci with no argument" do
- it "does not generate any CI config" do
- bundle "gem #{gem_name}"
+ context "gem.ci setting set to gitlab" do
+ it "generates a GitLab CI config file" do
+ bundle_config "gem.ci gitlab"
+ bundle "gem #{gem_name}"
- 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
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
end
+ end
- context "--ci set to github" do
- it "generates a GitHub Actions config file" do
- bundle "gem #{gem_name} --ci=github"
+ context "gem.ci setting set to circle" do
+ it "generates a CircleCI config file" do
+ bundle_config "gem.ci circle"
+ bundle "gem #{gem_name}"
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
- end
+ expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
+ end
+ end
- it "contained .gitlab-ci.yml into ignore list" do
- bundle "gem #{gem_name} --ci=github"
+ context "gem.ci set to github and --ci with no arguments" do
+ before do
+ bundle_config "gem.ci github"
+ bundle "gem #{gem_name} --ci"
+ end
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .github appveyor")
- end
+ it "generates a GitHub Actions config file" do
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
- context "--ci set to gitlab" do
- it "generates a GitLab CI config file" do
- bundle "gem #{gem_name} --ci=gitlab"
+ it "hints that --ci is already configured" do
+ expect(out).to match("github is already configured, ignoring --ci flag.")
+ end
+ end
- expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
+ context "gem.ci setting set to false and --ci with no arguments", :readline do
+ before do
+ bundle_config "gem.ci false"
+ bundle "gem #{gem_name} --ci" do |input, _, _|
+ input.puts "github"
end
+ end
+
+ it "asks to setup CI" do
+ expect(out).to match("Do you want to set up continuous integration for your gem?")
+ end
- it "contained .gitlab-ci.yml into ignore list" do
- bundle "gem #{gem_name} --ci=gitlab"
+ it "hints that the choice will only be applied to the current gem" do
+ expect(out).to match("Your choice will only be applied to this gem.")
+ end
+ end
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .gitlab-ci.yml appveyor")
+ context "gem.ci setting not set and --ci with no arguments", :readline do
+ before do
+ bundle_config_global "BUNDLE_GEM__CI" => nil
+ bundle "gem #{gem_name} --ci" do |input, _, _|
+ input.puts "github"
end
end
- context "--ci set to circle" do
- it "generates a CircleCI config file" do
- bundle "gem #{gem_name} --ci=circle"
+ it "asks to setup CI" do
+ expect(out).to match("Do you want to set up continuous integration for your gem?")
+ end
- expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
- end
+ it "hints that the choice will be applied to future bundle gem calls" do
+ hint = "Future `bundle gem` calls will use your choice. " \
+ "This setting can be changed anytime with `bundle config gem.ci`."
+ expect(out).to match(hint)
+ end
+ end
- it "contained .circleci into ignore list" do
- bundle "gem #{gem_name} --ci=circle"
+ context "gem.ci setting set to a CI service and --no-ci" do
+ before do
+ bundle_config "gem.ci github"
+ bundle "gem #{gem_name} --no-ci"
+ end
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .circleci appveyor")
- 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 "--ci set to an invalid value" do
- before do
- bundle "gem #{gem_name} --ci=foo", raise_on_error: false
- end
+ context "--linter with no argument" do
+ before do
+ bundle "gem #{gem_name}"
+ end
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--ci' to be one of .*; got foo/)
- 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
- context "gem.ci setting set to none" do
- it "doesn't 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
+ it "does not add any linter config files into ignore list" do
+ expect(ignore_paths).not_to include(".rubocop.yml")
+ expect(ignore_paths).not_to include(".standard.yml")
end
+ end
- context "gem.ci setting set to github" do
- it "generates a GitHub Actions config file" do
- bundle "config set gem.ci github"
- bundle "gem #{gem_name}"
+ context "--linter set to rubocop" do
+ before do
+ bundle "gem #{gem_name} --linter=rubocop"
+ end
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
- end
+ it "generates a RuboCop config" do
+ expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
+ expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
- context "gem.ci setting set to gitlab" do
- it "generates a GitLab CI config file" do
- bundle "config set gem.ci gitlab"
- bundle "gem #{gem_name}"
+ it "includes .rubocop.yml into ignore list" do
+ expect(ignore_paths).to include(".rubocop.yml")
+ expect(ignore_paths).not_to include(".standard.yml")
+ end
+ end
- expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
- end
+ context "--linter set to standard" do
+ before do
+ bundle "gem #{gem_name} --linter=standard"
end
- context "gem.ci setting set to circle" do
- it "generates a CircleCI config file" do
- bundle "config set gem.ci circle"
- bundle "gem #{gem_name}"
+ it "generates a Standard config" do
+ expect(bundled_app("#{gem_name}/.standard.yml")).to exist
+ expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
+ end
- expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
- end
+ it "includes .standard.yml into ignore list" do
+ expect(ignore_paths).to include(".standard.yml")
+ expect(ignore_paths).not_to include(".rubocop.yml")
end
+ end
- context "gem.ci set to github and --ci with no arguments" do
- before do
- bundle "config set gem.ci github"
- bundle "gem #{gem_name} --ci"
- end
+ context "--linter set to an invalid value" do
+ before do
+ bundle "gem #{gem_name} --linter=foo", raise_on_error: false
+ end
- it "generates a GitHub Actions config file" do
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
- 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
- it "hints that --ci is already configured" do
- expect(out).to match("github is already configured, ignoring --ci flag.")
- end
+ context "gem.linter setting set to none" do
+ before do
+ bundle "gem #{gem_name}"
end
- context "gem.ci setting set to false and --ci with no arguments", :readline do
- before do
- bundle "config set gem.ci false"
- bundle "gem #{gem_name} --ci" do |input, _, _|
- input.puts "github"
- end
- end
+ it "doesn't 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
- it "asks to setup CI" do
- expect(out).to match("Do you want to set up continuous integration for your gem?")
- end
+ it "does not add any linter config files into ignore list" do
+ expect(ignore_paths).not_to include(".rubocop.yml")
+ expect(ignore_paths).not_to include(".standard.yml")
+ end
+ end
- it "hints that the choice will only be applied to the current gem" do
- expect(out).to match("Your choice will only be applied to this gem.")
- end
+ context "gem.linter setting set to rubocop" do
+ before do
+ bundle_config "gem.linter rubocop"
+ bundle "gem #{gem_name}"
end
- context "gem.ci setting not set and --ci with no arguments", :readline do
- before do
- global_config "BUNDLE_GEM__CI" => nil
- bundle "gem #{gem_name} --ci" do |input, _, _|
- input.puts "github"
- end
- end
+ it "generates a RuboCop config file" do
+ expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
+ end
- it "asks to setup CI" do
- expect(out).to match("Do you want to set up continuous integration for your gem?")
- end
+ it "includes .rubocop.yml into ignore list" do
+ expect(ignore_paths).to include(".rubocop.yml")
+ end
+ end
- it "hints that the choice will be applied to future bundle gem calls" do
- hint = "Future `bundle gem` calls will use your choice. " \
- "This setting can be changed anytime with `bundle config gem.ci`."
- expect(out).to match(hint)
- end
+ context "gem.linter setting set to standard" do
+ before do
+ bundle_config "gem.linter standard"
+ bundle "gem #{gem_name}"
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 "generates a Standard config file" do
+ expect(bundled_app("#{gem_name}/.standard.yml")).to exist
+ 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
+ it "includes .standard.yml into ignore list" do
+ expect(ignore_paths).to include(".standard.yml")
end
+ end
- context "--linter with no argument" do
- it "does not generate any linter config" do
- bundle "gem #{gem_name}"
+ context "gem.linter set to rubocop and --linter with no arguments" do
+ before do
+ bundle_config "gem.linter rubocop"
+ bundle "gem #{gem_name} --linter"
+ end
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
- end
+ it "generates a RuboCop config file" do
+ expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
- context "--linter set to rubocop" do
- it "generates a RuboCop config" do
- bundle "gem #{gem_name} --linter=rubocop"
+ it "includes .rubocop.yml into ignore list" do
+ expect(ignore_paths).to include(".rubocop.yml")
+ end
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
- expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
+ it "hints that --linter is already configured" do
+ expect(out).to match("rubocop is already configured, ignoring --linter flag.")
+ end
+ end
+
+ context "gem.linter setting set to false and --linter with no arguments", :readline do
+ before do
+ bundle_config "gem.linter false"
+ bundle "gem #{gem_name} --linter" do |input, _, _|
+ input.puts "rubocop"
end
end
- context "--linter set to standard" do
- it "generates a Standard config" do
- bundle "gem #{gem_name} --linter=standard"
+ it "asks to setup a linter" do
+ expect(out).to match("Do you want to add a code linter and formatter to your gem?")
+ end
- expect(bundled_app("#{gem_name}/.standard.yml")).to exist
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- end
+ it "hints that the choice will only be applied to the current gem" do
+ expect(out).to match("Your choice will only be applied to this gem.")
end
+ end
- context "--linter set to an invalid value" do
- before do
- bundle "gem #{gem_name} --linter=foo", raise_on_error: false
+ context "gem.linter setting not set and --linter with no arguments", :readline do
+ before do
+ bundle_config_global "BUNDLE_GEM__LINTER" => nil
+ bundle "gem #{gem_name} --linter" do |input, _, _|
+ input.puts "rubocop"
end
+ end
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--linter' to be one of .*; got foo/)
- end
+ it "asks to setup a linter" do
+ expect(out).to match("Do you want to add a code linter and formatter to your gem?")
end
- context "gem.linter setting set to none" do
- it "doesn't generate any linter config" do
- bundle "gem #{gem_name}"
+ it "hints that the choice will be applied to future bundle gem calls" do
+ hint = "Future `bundle gem` calls will use your choice. " \
+ "This setting can be changed anytime with `bundle config gem.linter`."
+ expect(out).to match(hint)
+ end
+ end
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
- end
+ context "gem.linter setting set to a linter and --no-linter" do
+ before do
+ bundle_config "gem.linter rubocop"
+ bundle "gem #{gem_name} --no-linter"
end
- context "gem.linter setting set to rubocop" do
- it "generates a RuboCop config file" do
- bundle "config set gem.linter rubocop"
- bundle "gem #{gem_name}"
+ 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
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
- end
+ it "does not add any linter config files into ignore list" do
+ expect(ignore_paths).not_to include(".rubocop.yml")
+ expect(ignore_paths).not_to include(".standard.yml")
end
+ end
- context "gem.linter setting set to standard" do
- it "generates a Standard config file" do
- bundle "config set gem.linter standard"
- bundle "gem #{gem_name}"
+ context "--edit option" do
+ it "opens the generated gemspec in the user's text editor" do
+ output = bundle "gem #{gem_name} --edit=echo"
+ gemspec_path = File.join(bundled_app, gem_name, "#{gem_name}.gemspec")
+ expect(output).to include("echo \"#{gemspec_path}\"")
+ end
+ end
- expect(bundled_app("#{gem_name}/.standard.yml")).to exist
- end
+ shared_examples_for "paths that depend on gem name" do
+ it "generates entrypoint, version file and signatures file at the proper path, with the proper content" do
+ bundle "gem #{gem_name}"
+
+ expect(bundled_app("#{gem_name}/lib/#{require_path}.rb")).to exist
+ expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(%r{require_relative "#{require_relative_path}/version"})
+ expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/class Error < StandardError; end$/)
+
+ expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb")).to exist
+ expect(bundled_app("#{gem_name}/sig/#{require_path}.rbs")).to exist
end
- context "gem.rubocop setting set to true", bundler: "< 3" do
+ context "--exe parameter set" do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "config set gem.rubocop true"
- bundle "gem #{gem_name}"
+ bundle "gem #{gem_name} --exe"
end
- it "generates rubocop config" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
+ it "builds an exe file that requires the proper entrypoint" do
+ expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
+ expect(bundled_app("#{gem_name}/exe/#{gem_name}").read).to match(/require "#{require_path}"/)
end
+ end
- it "unsets gem.rubocop" do
- bundle "config gem.rubocop"
- expect(out).to include("You have not configured a value for `gem.rubocop`")
+ context "--bin parameter set" do
+ before do
+ bundle "gem #{gem_name} --bin"
end
- it "sets gem.linter=rubocop instead" do
- bundle "config gem.linter"
- expect(out).to match(/Set for the current user .*: "rubocop"/)
+ it "builds an exe file that requires the proper entrypoint" do
+ expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
+ expect(bundled_app("#{gem_name}/exe/#{gem_name}").read).to match(/require "#{require_path}"/)
end
end
- context "gem.linter set to rubocop and --linter with no arguments" do
+ context "--test parameter set to rspec" do
before do
- bundle "config set gem.linter rubocop"
- bundle "gem #{gem_name} --linter"
- end
-
- it "generates a RuboCop config file" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
+ bundle "gem #{gem_name} --test=rspec"
end
- it "hints that --linter is already configured" do
- expect(out).to match("rubocop is already configured, ignoring --linter flag.")
+ it "builds a spec helper that requires the proper entrypoint, and a default test in the proper path which fails" do
+ expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
+ expect(bundled_app("#{gem_name}/spec/spec_helper.rb").read).to include(%(require "#{require_path}"))
+ expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
+ expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb").read).to include("expect(false).to eq(true)")
end
end
- context "gem.linter setting set to false and --linter with no arguments", :readline do
+ context "--test parameter set to minitest" do
before do
- bundle "config set gem.linter false"
- bundle "gem #{gem_name} --linter" do |input, _, _|
- input.puts "rubocop"
- end
+ bundle "gem #{gem_name} --test=minitest"
end
- it "asks to setup a linter" do
- expect(out).to match("Do you want to add a code linter and formatter to your gem?")
- end
+ it "builds a test helper that requires the proper entrypoint, and default test file in the proper path that defines the proper test class name, requires helper, and fails" do
+ expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
+ expect(bundled_app("#{gem_name}/test/test_helper.rb").read).to include(%(require "#{require_path}"))
- it "hints that the choice will only be applied to the current gem" do
- expect(out).to match("Your choice will only be applied to this gem.")
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}")).to exist
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include(minitest_test_class_name)
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include(%(require "test_helper"))
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include("assert false")
end
end
- context "gem.linter setting not set and --linter with no arguments", :readline do
+ context "--test parameter set to test-unit" do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "gem #{gem_name} --linter" do |input, _, _|
- input.puts "rubocop"
- end
+ bundle "gem #{gem_name} --test=test-unit"
end
- it "asks to setup a linter" do
- expect(out).to match("Do you want to add a code linter and formatter to your gem?")
+ it "builds a test helper that requires the proper entrypoint, and default test file in the proper path which requires helper and fails" do
+ expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
+ expect(bundled_app("#{gem_name}/test/test_helper.rb").read).to include(%(require "#{require_path}"))
+ expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb")).to exist
+ expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb").read).to include(%(require "test_helper"))
+ expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb").read).to include("assert_equal(\"expected\", \"actual\")")
end
+ end
+ end
- it "hints that the choice will be applied to future bundle gem calls" do
- hint = "Future `bundle gem` calls will use your choice. " \
- "This setting can be changed anytime with `bundle config gem.linter`."
- expect(out).to match(hint)
- end
+ context "with mit option in bundle config settings set to true" do
+ before do
+ bundle_config_global "gem.mit true"
end
+ it_behaves_like "--mit flag"
+ it_behaves_like "--no-mit flag"
+ 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
+ context "with mit option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.mit false"
+ end
+ it_behaves_like "--mit flag"
+ it_behaves_like "--no-mit flag"
+ 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
+ context "with coc option in bundle config settings set to true" do
+ before do
+ bundle_config_global "gem.coc true"
end
+ it_behaves_like "--coc flag"
+ it_behaves_like "--no-coc flag"
+ end
- context "--edit option" do
- it "opens the generated gemspec in the user's text editor" do
- output = bundle "gem #{gem_name} --edit=echo"
- gemspec_path = File.join(bundled_app, gem_name, "#{gem_name}.gemspec")
- expect(output).to include("echo \"#{gemspec_path}\"")
- end
+ context "with coc option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.coc false"
end
+ it_behaves_like "--coc flag"
+ it_behaves_like "--no-coc flag"
end
- context "testing --mit and --coc options against bundle config settings" do
- let(:gem_name) { "test-gem" }
+ context "with rubocop option in bundle config settings set to true" do
+ before do
+ bundle_config_global "gem.rubocop true"
+ end
+ it_behaves_like "--linter=rubocop flag"
+ it_behaves_like "--linter=standard flag"
+ it_behaves_like "--no-linter flag"
+ end
- let(:require_path) { "test/gem" }
+ context "with rubocop option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.rubocop false"
+ end
+ it_behaves_like "--linter=rubocop flag"
+ it_behaves_like "--linter=standard flag"
+ it_behaves_like "--no-linter flag"
+ end
- context "with mit option in bundle config settings set to true" do
- before do
- global_config "BUNDLE_GEM__MIT" => "true"
- end
- it_behaves_like "--mit flag"
- it_behaves_like "--no-mit flag"
+ context "with linter option in bundle config settings set to rubocop" do
+ before do
+ bundle_config_global "gem.linter rubocop"
end
+ it_behaves_like "--linter=rubocop flag"
+ it_behaves_like "--linter=standard flag"
+ it_behaves_like "--no-linter flag"
+ end
- context "with mit option in bundle config settings set to false" do
- before do
- global_config "BUNDLE_GEM__MIT" => "false"
- end
- it_behaves_like "--mit flag"
- it_behaves_like "--no-mit flag"
+ context "with linter option in bundle config settings set to standard" do
+ before do
+ bundle_config_global "gem.linter standard"
end
+ it_behaves_like "--linter=rubocop flag"
+ it_behaves_like "--linter=standard flag"
+ it_behaves_like "--no-linter flag"
+ end
- context "with coc option in bundle config settings set to true" do
- before do
- global_config "BUNDLE_GEM__COC" => "true"
- end
- it_behaves_like "--coc flag"
- it_behaves_like "--no-coc flag"
+ context "with linter option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.linter false"
end
+ it_behaves_like "--linter=rubocop flag"
+ it_behaves_like "--linter=standard flag"
+ it_behaves_like "--no-linter flag"
+ end
- context "with coc option in bundle config settings set to false" do
- before do
- global_config "BUNDLE_GEM__COC" => "false"
- end
- it_behaves_like "--coc flag"
- it_behaves_like "--no-coc flag"
+ context "with changelog option in bundle config settings set to true" do
+ before do
+ bundle_config_global "gem.changelog true"
end
+ it_behaves_like "--changelog flag"
+ it_behaves_like "--no-changelog flag"
+ end
- context "with rubocop option in bundle config settings set to true" do
- before do
- global_config "BUNDLE_GEM__RUBOCOP" => "true"
- end
- it_behaves_like "--linter=rubocop flag"
- it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
- it_behaves_like "--rubocop flag"
- it_behaves_like "--no-rubocop flag"
+ context "with changelog option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.changelog false"
end
+ it_behaves_like "--changelog flag"
+ it_behaves_like "--no-changelog flag"
+ end
- context "with rubocop option in bundle config settings set to false" do
- before do
- global_config "BUNDLE_GEM__RUBOCOP" => "false"
- end
- it_behaves_like "--linter=rubocop flag"
- it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
- it_behaves_like "--rubocop flag"
- it_behaves_like "--no-rubocop flag"
+ context "with bundle option in bundle config settings set to true" do
+ before do
+ bundle_config_global "gem.bundle true"
end
+ it_behaves_like "--bundle flag"
+ it_behaves_like "--no-bundle flag"
- context "with linter option in bundle config settings set to rubocop" do
- before do
- global_config "BUNDLE_GEM__LINTER" => "rubocop"
- end
- it_behaves_like "--linter=rubocop flag"
- it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it "runs bundle install" do
+ bundle "gem #{gem_name}"
+ expect(out).to include("Running bundle install in the new gem directory.")
+ end
+ end
+
+ context "with bundle option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.bundle false"
+ end
+ it_behaves_like "--bundle flag"
+ it_behaves_like "--no-bundle flag"
+
+ it "does not run bundle install" do
+ bundle "gem #{gem_name}"
+ expect(out).to_not include("Running bundle install in the new gem directory.")
end
+ end
- context "with linter option in bundle config settings set to standard" do
+ context "without git config github.user set" do
+ before do
+ git("config --global --unset github.user")
+ end
+ context "with github-username option in bundle config settings set to some value" do
before do
- global_config "BUNDLE_GEM__LINTER" => "standard"
+ bundle_config_global "gem.github_username different_username"
end
- it_behaves_like "--linter=rubocop flag"
- it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--github-username option", "gh_user"
end
- context "with linter option in bundle config settings set to false" do
+ it_behaves_like "github_username configuration"
+
+ context "with github-username option in bundle config settings set to false" do
before do
- global_config "BUNDLE_GEM__LINTER" => "false"
+ bundle_config_global "gem.github_username false"
end
- it_behaves_like "--linter=rubocop flag"
- it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--github-username option", "gh_user"
end
- context "with changelog option in bundle config settings set to true" do
- before do
- global_config "BUNDLE_GEM__CHANGELOG" => "true"
+ context "when changelog is enabled" do
+ it "sets gemspec changelog_uri, homepage, homepage_uri, source_code_uri to TODOs" do
+ bundle "gem #{gem_name} --changelog"
+
+ expect(generated_gemspec.metadata["changelog_uri"]).
+ to eq("TODO: Put your gem's CHANGELOG.md URL here.")
+ expect(generated_gemspec.homepage).to eq("TODO: Put your gem's website or public repo URL here.")
+ expect(generated_gemspec.metadata["homepage_uri"]).to eq("TODO: Put your gem's website or public repo URL here.")
+ expect(generated_gemspec.metadata["source_code_uri"]).to eq("TODO: Put your gem's public repo URL here.")
end
- it_behaves_like "--changelog flag"
- it_behaves_like "--no-changelog flag"
end
- context "with changelog option in bundle config settings set to false" do
- before do
- global_config "BUNDLE_GEM__CHANGELOG" => "false"
+ context "when changelog is not enabled" do
+ it "sets gemspec homepage, homepage_uri, source_code_uri to TODOs and changelog_uri to nil" do
+ bundle "gem #{gem_name}"
+
+ expect(generated_gemspec.metadata["changelog_uri"]).to be_nil
+ expect(generated_gemspec.homepage).to eq("TODO: Put your gem's website or public repo URL here.")
+ expect(generated_gemspec.metadata["homepage_uri"]).to eq("TODO: Put your gem's website or public repo URL here.")
+ expect(generated_gemspec.metadata["source_code_uri"]).to eq("TODO: Put your gem's public repo URL here.")
end
- it_behaves_like "--changelog flag"
- it_behaves_like "--no-changelog flag"
end
end
- context "testing --github-username option against git and bundle config settings" do
- context "without git config set" do
+ context "with git config github.user set" do
+ context "with github-username option in bundle config settings set to some value" do
before do
- git("config --global --unset github.user")
- end
- context "with github-username option in bundle config settings set to some value" do
- before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
- end
- it_behaves_like "--github-username option", "gh_user"
+ bundle_config_global "gem.github_username different_username"
end
+ it_behaves_like "--github-username option", "gh_user"
+ end
- context "with github-username option in bundle config settings set to false" do
- before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
- end
- it_behaves_like "--github-username option", "gh_user"
+ it_behaves_like "github_username configuration"
+
+ context "with github-username option in bundle config settings set to false" do
+ before do
+ bundle_config_global "gem.github_username false"
end
+ it_behaves_like "--github-username option", "gh_user"
end
- context "with git config set" do
- context "with github-username option in bundle config settings set to some value" do
- before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
- end
- it_behaves_like "--github-username option", "gh_user"
+ context "when changelog is enabled" do
+ it "sets gemspec changelog_uri, homepage, homepage_uri, source_code_uri based on git username" do
+ bundle "gem #{gem_name} --changelog"
+
+ expect(generated_gemspec.metadata["changelog_uri"]).
+ to eq("https://github.com/bundleuser/#{gem_name}/blob/main/CHANGELOG.md")
+ expect(generated_gemspec.homepage).to eq("https://github.com/bundleuser/#{gem_name}")
+ expect(generated_gemspec.metadata["homepage_uri"]).to eq("https://github.com/bundleuser/#{gem_name}")
+ expect(generated_gemspec.metadata["source_code_uri"]).to eq("https://github.com/bundleuser/#{gem_name}")
end
+ end
- context "with github-username option in bundle config settings set to false" do
- before do
- global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
- end
- it_behaves_like "--github-username option", "gh_user"
+ context "when changelog is not enabled" do
+ it "sets gemspec source_code_uri, homepage, homepage_uri but not changelog_uri" do
+ bundle "gem #{gem_name}"
+
+ expect(generated_gemspec.metadata["changelog_uri"]).to be_nil
+ expect(generated_gemspec.homepage).to eq("https://github.com/bundleuser/#{gem_name}")
+ expect(generated_gemspec.metadata["homepage_uri"]).to eq("https://github.com/bundleuser/#{gem_name}")
+ expect(generated_gemspec.metadata["source_code_uri"]).to eq("https://github.com/bundleuser/#{gem_name}")
end
end
end
- context "testing github_username bundle config against git config settings" do
- context "without git config set" do
- before do
- git("config --global --unset github.user")
- end
+ context "standard gem naming" do
+ let(:require_path) { gem_name }
- it_behaves_like "github_username configuration"
- end
+ let(:require_relative_path) { gem_name }
- context "with git config set" do
- it_behaves_like "github_username configuration"
- end
+ let(:minitest_test_file_path) { "test/test_#{gem_name}.rb" }
+
+ let(:minitest_test_class_name) { "class TestMygem < Minitest::Test" }
+
+ include_examples "paths that depend on gem name"
end
context "gem naming with underscore" do
@@ -1497,25 +1685,7 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/module TestGem/)
end
- include_examples "generating a gem"
-
- context "--ext parameter with no value" 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]"
- expect(err).to include "`--ext` with no arguments has been deprecated"
- expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
- end
-
- it "prints deprecation when used before gem name" do
- bundle ["gem", gem_name, "--ext"].compact.join(" ")
- expect(err).to include "[DEPRECATED]"
- expect(err).to include "`--ext` with no arguments has been deprecated"
- expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
- end
- end
- end
+ include_examples "paths that depend on gem name"
context "--ext parameter set with C" do
let(:flags) { "--ext=c" }
@@ -1524,16 +1694,19 @@ RSpec.describe "bundle gem" do
bundle ["gem", gem_name, flags].compact.join(" ")
end
- it "is not deprecated" do
- expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated."
- end
-
it "builds ext skeleton" do
expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
end
+ it "generates native extension loading code" do
+ expect(bundled_app("#{gem_name}/lib/#{gem_name}.rb").read).to include(<<~RUBY)
+ require_relative "test_gem/version"
+ require "#{gem_name}/#{gem_name}"
+ RUBY
+ end
+
it "includes rake-compiler, but no Rust related changes" do
expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
@@ -1563,24 +1736,10 @@ RSpec.describe "bundle gem" do
end
end
- context "--ext parameter set with rust and old RubyGems" do
- it "fails in friendly way" do
- if ::Gem::Version.new("3.3.11") <= ::Gem.rubygems_version
- skip "RubyGems compatible with Rust builder"
- end
-
- expect do
- bundle ["gem", gem_name, "--ext=rust"].compact.join(" ")
- end.to raise_error(RuntimeError, /too old to build Rust extension/)
- end
- end
-
context "--ext parameter set with rust" do
let(:flags) { "--ext=rust" }
before do
- skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
-
bundle ["gem", gem_name, flags].compact.join(" ")
end
@@ -1593,12 +1752,12 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/ext/#{gem_name}/Cargo.toml")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/src/lib.rs")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/build.rs")).to exist
end
- it "includes rake-compiler, rb_sys gems and required_rubygems_version constraint" do
+ it "includes rake-compiler and rb_sys gems constraint" do
expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "rb_sys"')
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.required_rubygems_version = ">= ')
end
it "depends on compile task for build" do
@@ -1621,6 +1780,182 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
+
+ it "configures the crate such that `cargo test` works", :ruby_repo, :mri_only do
+ env = setup_rust_env
+ gem_path = bundled_app(gem_name)
+ result = sys_exec("cargo test", env: env, dir: gem_path, timeout: 300)
+
+ expect(result).to include("1 passed")
+ end
+
+ def setup_rust_env
+ skip "rust toolchain of mingw is broken" if RUBY_PLATFORM.match?("mingw")
+
+ env = {
+ "CARGO_HOME" => ENV.fetch("CARGO_HOME", File.join(ENV["HOME"], ".cargo")),
+ "RUSTUP_HOME" => ENV.fetch("RUSTUP_HOME", File.join(ENV["HOME"], ".rustup")),
+ "RUSTUP_TOOLCHAIN" => ENV.fetch("RUSTUP_TOOLCHAIN", "stable"),
+ }
+
+ system(env, "cargo", "-V", out: IO::NULL, err: [:child, :out])
+ skip "cargo not present" unless $?.success?
+ # Hermetic Cargo setup
+ RbConfig::CONFIG.each {|k, v| env["RBCONFIG_#{k}"] = v }
+ env
+ end
+ end
+
+ context "--ext parameter set with go" do
+ let(:flags) { "--ext=go" }
+
+ before do
+ bundle ["gem", gem_name, flags].compact.join(" ")
+ end
+
+ after do
+ sys_exec("go clean -modcache", raise_on_error: true) if installed_go?
+ end
+
+ it "is not deprecated" do
+ expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated."
+ end
+
+ it "builds ext skeleton" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/go.mod")).to exist
+ end
+
+ it "includes extconf.rb in gem_name.gemspec" do
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(%(spec.extensions = ["ext/#{gem_name}/extconf.rb"]))
+ end
+
+ it "includes go_gem in gem_name.gemspec" do
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "go_gem", ">= 0.2"')
+ end
+
+ it "includes go_gem extension in extconf.rb" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb").read).to include(<<~RUBY)
+ require "mkmf"
+ require "go_gem/mkmf"
+ RUBY
+
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb").read).to include(%(create_go_makefile("#{gem_name}/#{gem_name}")))
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb").read).not_to include("create_makefile")
+ end
+
+ it "includes go_gem extension in gem_name.c" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c").read).to eq(<<~C)
+ #include "#{gem_name}.h"
+ #include "_cgo_export.h"
+ C
+ end
+
+ it "includes skeleton code in gem_name.go" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go").read).to include(<<~GO)
+ /*
+ #include "#{gem_name}.h"
+
+ VALUE rb_#{gem_name}_sum(VALUE self, VALUE a, VALUE b);
+ */
+ import "C"
+ GO
+
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go").read).to include(<<~GO)
+ //export rb_#{gem_name}_sum
+ func rb_#{gem_name}_sum(_ C.VALUE, a C.VALUE, b C.VALUE) C.VALUE {
+ GO
+
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.go").read).to include(<<~GO)
+ //export Init_#{gem_name}
+ func Init_#{gem_name}() {
+ GO
+ end
+
+ it "includes valid module name in go.mod" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/go.mod").read).to include("module github.com/bundleuser/#{gem_name}")
+ end
+
+ it "includes go_gem extension in Rakefile" do
+ expect(bundled_app("#{gem_name}/Rakefile").read).to include(<<~RUBY)
+ require "go_gem/rake_task"
+
+ GoGem::RakeTask.new("#{gem_name}")
+ RUBY
+ end
+
+ context "with --no-ci" do
+ let(:flags) { "--ext=go --no-ci" }
+
+ it_behaves_like "CI config is absent"
+ end
+
+ context "--ci set to github" do
+ let(:flags) { "--ext=go --ci=github" }
+
+ it "generates .github/workflows/main.yml" do
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml").read).to include("go-version-file: ext/#{gem_name}/go.mod")
+ end
+ end
+
+ context "--ci set to circle" do
+ let(:flags) { "--ext=go --ci=circle" }
+
+ it "generates a .circleci/config.yml" do
+ expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
+
+ expect(bundled_app("#{gem_name}/.circleci/config.yml").read).to include(<<-YAML.strip)
+ environment:
+ GO_VERSION:
+ YAML
+
+ expect(bundled_app("#{gem_name}/.circleci/config.yml").read).to include(<<-YAML)
+ - run:
+ name: Install Go
+ command: |
+ wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ tar -C /usr/local -xzf /tmp/go.tar.gz
+ echo 'export PATH=/usr/local/go/bin:"$PATH"' >> "$BASH_ENV"
+ YAML
+ end
+ end
+
+ context "--ci set to gitlab" do
+ let(:flags) { "--ext=go --ci=gitlab" }
+
+ it "generates a .gitlab-ci.yml" do
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
+
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml").read).to include(<<-YAML)
+ - wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz
+ - tar -C /usr/local -xzf /tmp/go.tar.gz
+ - export PATH=/usr/local/go/bin:$PATH
+ YAML
+
+ expect(bundled_app("#{gem_name}/.gitlab-ci.yml").read).to include(<<-YAML.strip)
+ variables:
+ GO_VERSION:
+ YAML
+ end
+ end
+
+ context "without github.user" do
+ before do
+ # FIXME: GitHub Actions Windows Runner hang up here for some reason...
+ skip "Workaround for hung up" if Gem.win_platform?
+
+ git("config --global --unset github.user")
+ bundle ["gem", gem_name, flags].compact.join(" ")
+ end
+
+ it "includes valid module name in go.mod" do
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/go.mod").read).to include("module github.com/username/#{gem_name}")
+ end
+ end
end
end
@@ -1641,7 +1976,7 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/module Test\n module Gem/)
end
- include_examples "generating a gem"
+ include_examples "paths that depend on gem name"
end
describe "uncommon gem names" do
@@ -1690,6 +2025,19 @@ Usage: "bundle gem NAME [OPTIONS]"
it { expect(err).to include("Invalid gem name #{subject}") }
end
+ context "starting with a number" do
+ subject { "1gem" }
+ it { expect(err).to include("Invalid gem name #{subject}") }
+ end
+
+ context "including capital letter" do
+ subject { "CAPITAL" }
+ it "should warn but not error" do
+ expect(err).to include("Gem names with capital letters are not recommended")
+ expect(bundled_app("#{subject}/#{subject}.gemspec")).to exist
+ end
+ end
+
context "starting with an existing const name" do
subject { "gem-somenewconstantname" }
it { expect(err).not_to include("Invalid gem name #{subject}") }
@@ -1703,7 +2051,7 @@ Usage: "bundle gem NAME [OPTIONS]"
context "on first run", :readline do
it "asks about test framework" do
- global_config "BUNDLE_GEM__TEST" => nil
+ bundle_config_global "BUNDLE_GEM__TEST" => nil
bundle "gem foobar" do |input, _, _|
input.puts "rspec"
@@ -1726,7 +2074,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CI service" do
- global_config "BUNDLE_GEM__CI" => nil
+ bundle_config_global "BUNDLE_GEM__CI" => nil
bundle "gem foobar" do |input, _, _|
input.puts "github"
@@ -1735,8 +2083,8 @@ Usage: "bundle gem NAME [OPTIONS]"
expect(bundled_app("foobar/.github/workflows/main.yml")).to exist
end
- it "asks about MIT license" do
- global_config "BUNDLE_GEM__MIT" => nil
+ it "asks about MIT license just once" do
+ bundle_config_global "BUNDLE_GEM__MIT" => nil
bundle "config list"
@@ -1745,26 +2093,29 @@ Usage: "bundle gem NAME [OPTIONS]"
end
expect(bundled_app("foobar/LICENSE.txt")).to exist
+ expect(out).to include("Using a MIT license means").once
end
- it "asks about CoC" do
- global_config "BUNDLE_GEM__COC" => nil
+ it "asks about CoC just once" do
+ bundle_config_global "BUNDLE_GEM__COC" => nil
bundle "gem foobar" do |input, _, _|
input.puts "yes"
end
expect(bundled_app("foobar/CODE_OF_CONDUCT.md")).to exist
+ expect(out).to include("Codes of conduct can increase contributions to your project").once
end
- it "asks about CHANGELOG" do
- global_config "BUNDLE_GEM__CHANGELOG" => nil
+ it "asks about CHANGELOG just once" do
+ bundle_config_global "BUNDLE_GEM__CHANGELOG" => nil
bundle "gem foobar" do |input, _, _|
input.puts "yes"
end
expect(bundled_app("foobar/CHANGELOG.md")).to exist
+ expect(out).to include("A changelog is a file which contains").once
end
end
diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb
index e0c79aa407..664dc58919 100644
--- a/spec/bundler/commands/open_spec.rb
+++ b/spec/bundler/commands/open_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe "bundle open" do
it "suggests alternatives for similar-sounding gems" do
bundle "open Rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
- expect(err).to match(/did you mean rails\?/i)
+ expect(err).to match(/did you mean 'rails'\?/i)
end
it "opens the gem with short words" do
@@ -80,12 +80,12 @@ RSpec.describe "bundle open" do
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
- expect(err).to match(/did you mean rails\?/i)
+ 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
- expect(err).to match(/did you mean rails\?/i)
+ expect(err).to match(/did you mean 'rails'\?/i)
end
it "opens subpath of the short worded gem" do
@@ -139,7 +139,7 @@ RSpec.describe "bundle open" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("Installing foo 1.0")
end
diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb
index 09b0e6f32f..28ed51d61e 100644
--- a/spec/bundler/commands/outdated_spec.rb
+++ b/spec/bundler/commands/outdated_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 default
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
weakling 0.0.3 0.2 ~> 0.0.1 default
@@ -53,7 +53,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
AAA 1.0.0 2.0.0 = 1.0.0 default
TABLE
@@ -92,7 +92,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
terranova 8 9 = 8 default
TABLE
@@ -120,7 +120,7 @@ RSpec.describe "bundle outdated" do
end
it "shows the location of the latest version's gemspec if installed" do
- bundle "config set clean false"
+ bundle_config "clean false"
update_repo2 { build_gem "activesupport", "3.0" }
update_repo2 { build_gem "terranova", "9" }
@@ -142,81 +142,15 @@ RSpec.describe "bundle outdated" do
bundle "outdated --verbose", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups Path
+ Gem Current Latest Requested Groups Release Date Path
activesupport 2.3.5 3.0 = 2.3.5 default
- terranova 8 9 = 8 default #{default_bundle_path("specifications/terranova-9.gemspec")}
+ terranova 8 9 = 8 default #{default_bundle_path("specifications/terranova-9.gemspec")}
TABLE
expect(out).to end_with(expected_output)
end
end
- describe "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
- before do
- build_repo2 do
- build_gem "dotenv", "2.7.6"
-
- build_gem "oj", "3.11.3"
- build_gem "oj", "3.11.5"
-
- build_gem "vcr", "6.0.0"
- end
-
- build_repo3 do
- build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
- s.add_dependency "oj"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "dotenv"
-
- source "https://gem.repo3" do
- gem 'pkg-gem-flowbyte-with-dep'
- end
-
- gem "vcr",source: "https://gem.repo2"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- remote: https://gem.repo3/
- specs:
- dotenv (2.7.6)
- oj (3.11.3)
- pkg-gem-flowbyte-with-dep (1.0.0)
- oj
- vcr (6.0.0)
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- dotenv
- pkg-gem-flowbyte-with-dep!
- vcr!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "works" do
- bundle :install, artifice: "compact_index"
- bundle :outdated, artifice: "compact_index", raise_on_error: false
-
- expected_output = <<~TABLE
- Gem Current Latest Requested Groups
- oj 3.11.3 3.11.5
- TABLE
-
- expect(out).to include(expected_output.strip)
- end
- end
-
describe "with --group option" do
before do
build_repo2 do
@@ -263,7 +197,7 @@ RSpec.describe "bundle outdated" do
test_group_option("default")
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
terranova 8 9 = 8 default
TABLE
@@ -274,7 +208,7 @@ RSpec.describe "bundle outdated" do
test_group_option("development")
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
duradura 7.0 8.0 = 7.0 development, test
TABLE
@@ -286,7 +220,7 @@ RSpec.describe "bundle outdated" do
test_group_option("test")
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
duradura 7.0 8.0 = 7.0 development, test
TABLE
@@ -323,7 +257,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --groups", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
bar 2.0.0 3.0.0
TABLE
@@ -365,7 +299,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --groups", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 development, test
duradura 7.0 8.0 = 7.0 development, test
terranova 8 9 = 8 default
@@ -399,7 +333,7 @@ RSpec.describe "bundle outdated" do
build_gem "activesupport", "2.3.4"
end
- bundle "config set clean false"
+ bundle_config "clean false"
install_gemfile <<-G
source "https://gem.repo2"
@@ -409,7 +343,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --local", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.4 2.3.5 = 2.3.4 default
TABLE
@@ -520,7 +454,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated foo", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
TABLE
@@ -551,13 +485,13 @@ RSpec.describe "bundle outdated" do
zeitwerk
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "outdated zeitwerk", raise_on_error: false
expected_output = <<~TABLE.tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
zeitwerk 1.0.0 2.0.0 >= 0 default
TABLE
@@ -605,7 +539,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --pre", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0.0.beta = 2.3.5 default
TABLE
@@ -628,7 +562,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 3.0.0.beta.1 3.0.0.beta.2 = 3.0.0.beta.1 default
TABLE
@@ -664,7 +598,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, "filter-strict": true, raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.0.5 ~> 0.0.1 default
TABLE
@@ -680,7 +614,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, strict: true, raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.0.5 ~> 0.0.1 default
TABLE
@@ -725,7 +659,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, :"filter-strict" => true, "filter-patch" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.0.5 >= 0.0.1 default
TABLE
@@ -747,7 +681,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, :"filter-strict" => true, "filter-minor" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 0.1.5 >= 0.0.1 default
TABLE
@@ -769,7 +703,7 @@ RSpec.describe "bundle outdated" do
bundle :outdated, :"filter-strict" => true, "filter-major" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.0.3 1.1.5 >= 0.0.1 default
TABLE
@@ -814,12 +748,12 @@ RSpec.describe "bundle outdated" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :outdated, raise_on_error: false
expect(out).to include("Installing foo 1.0")
end
- context "after bundle install --deployment", bundler: "< 3" do
+ context "in deployment mode" do
before do
build_repo2
@@ -830,7 +764,7 @@ RSpec.describe "bundle outdated" do
gem "foo"
G
bundle :lock
- bundle :install, deployment: true
+ bundle_config "deployment true"
end
it "outputs a helpful message about being in deployment mode" do
@@ -858,7 +792,7 @@ RSpec.describe "bundle outdated" do
gem "myrack"
gem "foo"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
end
it "outputs a helpful message about being in deployment mode" do
@@ -913,7 +847,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
laduradura 5.15.2 5.15.3 = 5.15.2 default
TABLE
@@ -974,7 +908,7 @@ RSpec.describe "bundle outdated" do
gem "terranova", '8'
G
- pristine_system_gems :bundler
+ pristine_system_gems
update_git "foo", path: lib_path("foo")
update_repo2 do
@@ -1215,7 +1149,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --patch --filter-patch", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
major 1.0.0 1.0.1 >= 0 default
minor 1.0.0 1.0.1 >= 0 default
patch 1.0.0 1.0.1 >= 0 default
@@ -1228,7 +1162,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --minor --filter-minor", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
major 1.0.0 1.1.0 >= 0 default
minor 1.0.0 1.1.0 >= 0 default
TABLE
@@ -1282,7 +1216,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG_RESOLVER" => "1" }
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
bar 2.0.3 2.0.5
foo 1.4.3 1.4.4 >= 0 default
TABLE
@@ -1294,7 +1228,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG" => "1" }
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups Path
+ Gem Current Latest Requested Groups Release Date Path
bar 2.0.3 2.0.5
foo 1.4.3 1.4.4 >= 0 default
TABLE
@@ -1326,7 +1260,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated --only-explicit", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
weakling 0.2 0.3 >= 0 default
TABLE
@@ -1363,7 +1297,7 @@ RSpec.describe "bundle outdated" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -1376,7 +1310,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
nokogiri 1.11.1 1.11.2 >= 0 default
TABLE
@@ -1417,7 +1351,7 @@ RSpec.describe "bundle outdated" do
mini_portile2
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1425,7 +1359,7 @@ RSpec.describe "bundle outdated" do
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
mini_portile2 2.5.2 2.5.3 >= 0 default
TABLE
diff --git a/spec/bundler/commands/platform_spec.rb b/spec/bundler/commands/platform_spec.rb
index 17183e7546..9d7354c54f 100644
--- a/spec/bundler/commands/platform_spec.rb
+++ b/spec/bundler/commands/platform_spec.rb
@@ -227,7 +227,7 @@ G
ruby 1.0.0p127
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "platform --ruby"
@@ -250,7 +250,7 @@ G
DEPENDENCIES
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "platform --ruby"
@@ -302,9 +302,9 @@ G
expect(err).to be_include("Your #{local_ruby_engine} version is #{local_engine_version}, but your Gemfile specified #{local_ruby_engine} #{not_local_engine_version}")
end
- def should_be_patchlevel_incorrect
- expect(exitstatus).to eq(18)
- expect(err).to be_include("Your Ruby patchlevel is #{RUBY_PATCHLEVEL}, but your Gemfile specified #{not_local_patchlevel}")
+ def should_ignore_patchlevel
+ expect(exitstatus).to eq(0)
+ expect(err).to eq("")
end
def should_be_patchlevel_fixnum
@@ -382,7 +382,7 @@ G
should_be_engine_version_incorrect
end
- it "doesn't install when patchlevel doesn't match" do
+ it "does install even when patchlevel doesn't match" do
install_gemfile <<-G, raise_on_error: false
source "https://gem.repo1"
gem "myrack"
@@ -390,8 +390,8 @@ G
#{patchlevel_incorrect}
G
- expect(bundled_app_lock).not_to exist
- should_be_patchlevel_incorrect
+ expect(bundled_app_lock).to exist
+ should_ignore_patchlevel
end
end
@@ -481,7 +481,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "checks fine even when patchlevel doesn't match" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -494,8 +494,8 @@ G
#{patchlevel_incorrect}
G
- bundle :check, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :check
+ should_ignore_patchlevel
end
end
@@ -598,10 +598,10 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "updates fine even when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "https://gem.repo2"
+ gem "activesupport"
#{patchlevel_incorrect}
G
@@ -609,8 +609,9 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :update, all: true
+ should_ignore_patchlevel
+ expect(the_bundle).to include_gems "activesupport 3.0"
end
end
@@ -646,7 +647,7 @@ 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" do
gemfile <<-G
source "https://gem.repo1"
gem "rails"
@@ -658,7 +659,7 @@ G
should_be_ruby_version_incorrect
end
- it "fails if engine doesn't match", bundler: "< 3" do
+ it "fails if engine doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "rails"
@@ -670,7 +671,7 @@ G
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", jruby_only: true do
gemfile <<-G
source "https://gem.repo1"
gem "rails"
@@ -682,19 +683,17 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match", bundler: "< 3" do
+ it "prints path even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
- gem "myrack"
+ gem "rails"
#{patchlevel_incorrect}
G
- update_repo2 do
- build_gem "activesupport", "3.0"
- end
- bundle "show rails", raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle "show rails"
+ should_ignore_patchlevel
+ expect(out).to eq(default_bundle_path("gems", "rails-2.3.2").to_s)
end
end
@@ -766,7 +765,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "copies the .gem file to vendor/cache even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -774,8 +773,9 @@ G
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :cache
+ should_ignore_patchlevel
+ expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
end
end
@@ -847,7 +847,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "copies the .gem file to vendor/cache even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -855,8 +855,9 @@ G
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle :cache
+ should_ignore_patchlevel
+ expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
end
end
@@ -926,7 +927,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "activates the correct gem even when patchlevel doesn't match" do
gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -934,8 +935,9 @@ G
#{patchlevel_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle "exec myrackup"
+ should_ignore_patchlevel
+ expect(out).to include("1.0.0")
end
end
@@ -995,11 +997,15 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "starts IRB with the default group loaded even when patchlevel doesn't match", :readline do
gemfile gemfile + "\n\n#{patchlevel_incorrect}\n"
- bundle "console", raise_on_error: false
- should_be_patchlevel_incorrect
+ bundle "console" do |input, _, _|
+ input.puts("puts MYRACK")
+ input.puts("exit")
+ end
+ should_ignore_patchlevel
+ expect(out).to include("0.9.1")
end
end
@@ -1095,7 +1101,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match" do
+ it "makes a Gemfile.lock even when patchlevel doesn't match" do
install_gemfile <<-G, raise_on_error: false
source "https://gem.repo1"
gem "yard"
@@ -1106,10 +1112,10 @@ 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 }
- expect(bundled_app_lock).not_to exist
- should_be_patchlevel_incorrect
+ should_ignore_patchlevel
+ expect(bundled_app_lock).to exist
end
end
@@ -1143,7 +1149,7 @@ G
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 default
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
TABLE
@@ -1169,7 +1175,7 @@ G
bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
- Gem Current Latest Requested Groups
+ Gem Current Latest Requested Groups Release Date
activesupport 2.3.5 3.0 = 2.3.5 default
foo 1.0 xxxxxxx 1.0 xxxxxxx >= 0 default
TABLE
@@ -1231,7 +1237,7 @@ G
should_be_engine_version_incorrect
end
- it "fails when the patchlevel doesn't match", :jruby_only do
+ it "reports outdated gems even when patchlevel doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
update_git "foo", path: lib_path("foo")
@@ -1246,25 +1252,9 @@ G
G
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")
- end
-
- gemfile <<-G
- source "https://gem.repo2"
- gem "activesupport", "2.3.5"
- gem "foo", :git => "#{lib_path("foo")}"
-
- #{patchlevel_fixnum}
- G
-
- bundle "outdated", raise_on_error: false
- should_be_patchlevel_fixnum
+ expect(err).not_to include("patchlevel")
+ expect(out).to include("activesupport")
+ expect(out).to include("foo")
end
end
end
diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb
index 8671504b25..088fc29fe1 100644
--- a/spec/bundler/commands/post_bundle_message_spec.rb
+++ b/spec/bundler/commands/post_bundle_message_spec.rb
@@ -18,162 +18,140 @@ RSpec.describe "post bundle message" do
let(:bundle_show_path_message) { "Bundled gems are installed into `#{bundle_path}`" }
let(:bundle_complete_message) { "Bundle complete!" }
let(:bundle_updated_message) { "Bundle updated!" }
- let(:installed_gems_stats) { "4 Gemfile dependencies, 5 gems now installed." }
- let(:bundle_show_message) { Bundler::VERSION.split(".").first.to_i < 3 ? bundle_show_system_message : bundle_show_path_message }
+ let(:installed_gems_stats) { "4 Gemfile dependencies, 4 gems now installed." }
+
+ describe "when installing to system gems" do
+ before do
+ bundle_config "path.system true"
+ end
- describe "for fresh bundle install" do
it "shows proper messages according to the configured groups" do
bundle :install
- expect(out).to include(bundle_show_message)
+ expect(out).to include(bundle_show_system_message)
expect(out).not_to include("Gems in the group")
expect(out).to include(bundle_complete_message)
expect(out).to include(installed_gems_stats)
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
- expect(out).to include(bundle_show_message)
+ expect(out).to include(bundle_show_system_message)
expect(out).to include("Gems in the group 'emo' were not installed")
expect(out).to include(bundle_complete_message)
expect(out).to include(installed_gems_stats)
- bundle "config set --local without emo test"
+ bundle_config "without emo test"
bundle :install
- expect(out).to include(bundle_show_message)
+ expect(out).to include(bundle_show_system_message)
expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
expect(out).to include(bundle_complete_message)
- expect(out).to include("4 Gemfile dependencies, 3 gems now installed.")
+ expect(out).to include("4 Gemfile dependencies, 2 gems now installed.")
- bundle "config set --local without emo obama test"
+ bundle_config "without emo obama test"
bundle :install
- expect(out).to include(bundle_show_message)
+ expect(out).to include(bundle_show_system_message)
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
expect(out).to include(bundle_complete_message)
- expect(out).to include("4 Gemfile dependencies, 2 gems now installed.")
+ expect(out).to include("4 Gemfile dependencies, 1 gem now installed.")
end
- describe "with `path` configured" do
- let(:bundle_path) { "./vendor" }
-
- it "shows proper messages according to the configured groups" do
- bundle "config set --local path vendor"
- bundle :install
- expect(out).to include(bundle_show_path_message)
- expect(out).to_not include("Gems in the group")
- expect(out).to include(bundle_complete_message)
-
- bundle "config set --local path vendor"
- bundle "config set --local without emo"
- bundle :install
- expect(out).to include(bundle_show_path_message)
- expect(out).to include("Gems in the group 'emo' were not installed")
- expect(out).to include(bundle_complete_message)
-
- bundle "config set --local path vendor"
- bundle "config set --local without emo test"
- bundle :install
- expect(out).to include(bundle_show_path_message)
- expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
- expect(out).to include(bundle_complete_message)
-
- bundle "config set --local path vendor"
- bundle "config set --local without emo obama test"
- bundle :install
- expect(out).to include(bundle_show_path_message)
- expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
- expect(out).to include(bundle_complete_message)
- end
- end
-
- describe "with an absolute `path` inside the cwd configured" do
- let(:bundle_path) { bundled_app("cache") }
-
- it "shows proper messages according to the configured groups" do
- bundle "config set --local path #{bundle_path}"
- bundle :install
- expect(out).to include("Bundled gems are installed into `./cache`")
- expect(out).to_not include("Gems in the group")
+ describe "for second bundle install run" do
+ it "without any options" do
+ 2.times { bundle :install }
+ expect(out).to include(bundle_show_system_message)
+ expect(out).to_not include("Gems in the groups")
expect(out).to include(bundle_complete_message)
+ expect(out).to include(installed_gems_stats)
end
end
+ end
- describe "with `path` configured to an absolute path outside the cwd" do
- let(:bundle_path) { tmp("not_bundled_app") }
+ describe "with `path` configured" do
+ let(:bundle_path) { "./vendor" }
- it "shows proper messages according to the configured groups" do
- bundle "config set --local path #{bundle_path}"
- bundle :install
- expect(out).to include("Bundled gems are installed into `#{tmp("not_bundled_app")}`")
- expect(out).to_not include("Gems in the group")
- expect(out).to include(bundle_complete_message)
- end
- end
+ it "shows proper messages according to the configured groups" do
+ bundle_config "path vendor"
+ bundle :install
+ expect(out).to include(bundle_show_path_message)
+ expect(out).to_not include("Gems in the group")
+ expect(out).to include(bundle_complete_message)
- describe "with misspelled or non-existent gem name" do
- before do
- bundle "config set force_ruby_platform true"
- end
+ bundle_config "path vendor"
+ bundle_config "without emo"
+ bundle :install
+ expect(out).to include(bundle_show_path_message)
+ expect(out).to include("Gems in the group 'emo' were not installed")
+ expect(out).to include(bundle_complete_message)
- it "should report a helpful error message" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
- 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.
- EOS
- end
+ bundle_config "path vendor"
+ bundle_config "without emo test"
+ bundle :install
+ expect(out).to include(bundle_show_path_message)
+ expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
+ expect(out).to include(bundle_complete_message)
- it "should report a helpful error message with reference to cache if available" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- 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"
- gem "not-a-gem", :group => :development
- G
- expect(err).to include("Could not find gem 'not-a-gem' in").
- and include("or in gems cached in vendor/cache.")
- end
+ bundle_config "path vendor"
+ bundle_config "without emo obama test"
+ bundle :install
+ expect(out).to include(bundle_show_path_message)
+ expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
+ expect(out).to include(bundle_complete_message)
end
end
- 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)
- expect(out).to_not include("Gems in the groups")
- expect(out).to include(bundle_complete_message)
- expect(out).to include(installed_gems_stats)
- end
+ describe "with an absolute `path` inside the cwd configured" do
+ let(:bundle_path) { bundled_app("cache") }
- it "with --without one group" do
- bundle "install --without emo"
+ it "shows proper messages according to the configured groups" do
+ bundle_config "path #{bundle_path}"
bundle :install
- expect(out).to include(bundle_show_message)
- expect(out).to include("Gems in the group 'emo' were not installed")
+ expect(out).to include("Bundled gems are installed into `./cache`")
+ expect(out).to_not include("Gems in the group")
expect(out).to include(bundle_complete_message)
- expect(out).to include(installed_gems_stats)
end
+ end
- it "with --without two groups" do
- bundle "install --without emo test"
+ describe "with `path` configured to an absolute path outside the cwd" do
+ let(:bundle_path) { tmp("not_bundled_app") }
+
+ it "shows proper messages according to the configured groups" do
+ bundle_config "path #{bundle_path}"
bundle :install
- expect(out).to include(bundle_show_message)
- expect(out).to include("Gems in the groups 'emo' and 'test' were not installed")
+ expect(out).to include("Bundled gems are installed into `#{tmp("not_bundled_app")}`")
+ expect(out).to_not include("Gems in the group")
expect(out).to include(bundle_complete_message)
end
+ end
- it "with --without more groups" do
- bundle "install --without emo obama test"
- bundle :install
- expect(out).to include(bundle_show_message)
- expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed")
- expect(out).to include(bundle_complete_message)
+ describe "with misspelled or non-existent gem name" do
+ before do
+ bundle_config "force_ruby_platform true"
+ end
+
+ it "should report a helpful error message" do
+ install_gemfile <<-G, raise_on_error: false
+ source "https://gem.repo1"
+ gem "myrack"
+ 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.
+ 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"
+ 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"
+ gem "not-a-gem", :group => :development
+ G
+ expect(err).to include("Could not find gem 'not-a-gem' in").
+ and include("or in gems cached in vendor/cache.")
end
end
@@ -183,19 +161,19 @@ Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or inst
expect(out).not_to include("Gems in the groups")
expect(out).to include(bundle_updated_message)
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
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_config "without emo test"
bundle :install
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_config "without emo obama test"
bundle :install
bundle :update, all: true
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not updated")
diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb
index 547aa12b6c..5f80b9e534 100644
--- a/spec/bundler/commands/pristine_spec.rb
+++ b/spec/bundler/commands/pristine_spec.rb
@@ -49,13 +49,7 @@ RSpec.describe "bundle pristine" do
bundle "pristine"
bundle "-v"
- expected = if Bundler::VERSION < "3.0"
- "Bundler version"
- else
- Bundler::VERSION
- end
-
- expect(out).to start_with(expected)
+ expect(out).to end_with(Bundler::VERSION)
end
end
@@ -85,7 +79,7 @@ RSpec.describe "bundle pristine" do
it "displays warning and ignores changes when a local config exists" do
spec = find_spec("foo")
- bundle "config set local.#{spec.name} #{lib_path(spec.name)}"
+ bundle_config "local.#{spec.name} #{lib_path(spec.name)}"
changes_txt = Pathname.new(spec.full_gem_path).join("lib/changes.txt")
FileUtils.touch(changes_txt)
@@ -95,6 +89,66 @@ RSpec.describe "bundle pristine" do
expect(changes_txt).to be_file
expect(err).to include("Cannot pristine #{spec.name} (#{spec.version}#{spec.git_version}). Gem is locally overridden.")
end
+
+ it "doesn't run multiple git processes for the same repository" do
+ nested_gems = [
+ "actioncable",
+ "actionmailer",
+ "actionpack",
+ "actionview",
+ "activejob",
+ "activemodel",
+ "activerecord",
+ "activestorage",
+ "activesupport",
+ "railties",
+ ]
+
+ build_repo2 do
+ nested_gems.each do |gem|
+ build_lib gem, path: lib_path("rails/#{gem}")
+ end
+
+ build_git "rails", path: lib_path("rails") do |s|
+ nested_gems.each do |gem|
+ s.add_dependency gem
+ end
+ end
+ end
+
+ install_gemfile <<-G
+ source 'https://rubygems.org'
+
+ git "#{lib_path("rails")}" do
+ gem "rails"
+ gem "actioncable"
+ gem "actionmailer"
+ gem "actionpack"
+ gem "actionview"
+ gem "activejob"
+ gem "activemodel"
+ gem "activerecord"
+ gem "activestorage"
+ gem "activesupport"
+ gem "railties"
+ end
+ G
+
+ changed_files = []
+ diff = "#Pristine spec changes"
+
+ nested_gems.each do |gem|
+ spec = find_spec(gem)
+ changed_files << Pathname.new(spec.full_gem_path).join("lib/#{gem}.rb")
+ File.open(changed_files.last, "a") {|f| f.puts diff }
+ end
+
+ bundle "pristine"
+
+ changed_files.each do |changed_file|
+ expect(File.read(changed_file)).to_not include(diff)
+ end
+ end
end
context "when sourced from gemspec" do
@@ -173,7 +227,7 @@ RSpec.describe "bundle pristine" do
let(:very_simple_binary) { find_spec("very_simple_binary") }
let(:c_ext_dir) { Pathname.new(very_simple_binary.full_gem_path).join("ext") }
let(:build_opt) { "--with-ext-lib=#{c_ext_dir}" }
- before { bundle "config set build.very_simple_binary -- #{build_opt}" }
+ before { bundle_config "build.very_simple_binary -- #{build_opt}" }
# This just verifies that the generated Makefile from the c_ext gem makes
# use of the build_args from the bundle config
@@ -190,7 +244,7 @@ RSpec.describe "bundle pristine" do
let(:git_with_ext) { find_spec("git_with_ext") }
let(:c_ext_dir) { Pathname.new(git_with_ext.full_gem_path).join("ext") }
let(:build_opt) { "--with-ext-lib=#{c_ext_dir}" }
- before { bundle "config set build.git_with_ext -- #{build_opt}" }
+ before { bundle_config "build.git_with_ext -- #{build_opt}" }
# This just verifies that the generated Makefile from the c_ext gem makes
# use of the build_args from the bundle config
diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb
index 84505169ca..8a2e6778ea 100644
--- a/spec/bundler/commands/remove_spec.rb
+++ b/spec/bundler/commands/remove_spec.rb
@@ -43,21 +43,6 @@ RSpec.describe "bundle remove" do
end
end
- context "when --install flag is specified", bundler: "< 3" do
- it "removes gems from .bundle" do
- gemfile <<-G
- source "https://gem.repo1"
-
- gem "myrack"
- G
-
- bundle "remove myrack --install"
-
- expect(out).to include("myrack was removed.")
- expect(the_bundle).to_not include_gems "myrack"
- end
- end
-
describe "remove single gem from gemfile" do
context "when gem is present in gemfile" do
it "shows success for removed gem" do
diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb
index 0ff9416757..d0d55ffbb9 100644
--- a/spec/bundler/commands/show_spec.rb
+++ b/spec/bundler/commands/show_spec.rb
@@ -1,10 +1,12 @@
# frozen_string_literal: true
-RSpec.describe "bundle show", bundler: "< 3" do
+RSpec.describe "bundle show" do
context "with a standard Gemfile" do
before :each do
+ build_repo2
+
install_gemfile <<-G
- source "https://gem.repo1"
+ source "https://gem.repo2"
gem "rails"
G
end
@@ -86,6 +88,24 @@ RSpec.describe "bundle show", bundler: "< 3" do
\tStatus: Up to date
MSG
end
+
+ it "includes up to date status in summary of gems" do
+ update_repo2 do
+ build_gem "rails", "3.0.0"
+ end
+
+ bundle "show --verbose"
+
+ expect(out).to include <<~MSG
+ * rails (2.3.2)
+ \tSummary: This is just a fake gem for testing
+ \tHomepage: http://example.com
+ \tStatus: Outdated - 2.3.2 < 3.0.0
+ MSG
+
+ # check lockfile is not accidentally updated
+ expect(lockfile).to include("actionmailer (2.3.2)")
+ end
end
context "with a git repo in the Gemfile" do
@@ -159,7 +179,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
gem "foo"
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
bundle :show
expect(out).to include("Installing foo 1.0")
end
@@ -190,35 +210,8 @@ RSpec.describe "bundle show", bundler: "< 3" do
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
-
- context "--outdated option" do
- # Regression test for https://github.com/rubygems/bundler/issues/5375
- before do
- build_repo2
- end
-
- it "doesn't update gems to newer versions" do
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "rails"
- G
-
- expect(the_bundle).to include_gem("rails 2.3.2")
-
- update_repo2 do
- build_gem "rails", "3.0.0" do |s|
- s.executables = "rails"
- end
- end
-
- bundle "show --outdated"
-
- bundle "install"
- expect(the_bundle).to include_gem("rails 2.3.2")
- end
- end
end
-RSpec.describe "bundle show", bundler: "3" do
+RSpec.describe "bundle show", bundler: "5" do
pending "shows a friendly error about the command removal"
end
diff --git a/spec/bundler/commands/ssl_spec.rb b/spec/bundler/commands/ssl_spec.rb
new file mode 100644
index 0000000000..4220731b69
--- /dev/null
+++ b/spec/bundler/commands/ssl_spec.rb
@@ -0,0 +1,373 @@
+# frozen_string_literal: true
+
+require "bundler/cli"
+require "bundler/cli/doctor"
+require "bundler/cli/doctor/ssl"
+require_relative "../support/artifice/helpers/artifice"
+require "bundler/vendored_persistent.rb"
+
+RSpec.describe "bundle doctor ssl" do
+ before(:each) do
+ require_rack_test
+ require_relative "../support/artifice/helpers/endpoint"
+
+ @dummy_endpoint = Class.new(Endpoint) do
+ get "/" do
+ end
+ end
+
+ @previous_ui = Bundler.ui
+ Bundler.ui = Bundler::UI::Shell.new
+ Bundler.ui.level = "info"
+
+ @previous_client = Gem::Request::ConnectionPools.client
+ Artifice.activate_with(@dummy_endpoint)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+ end
+
+ after(:each) do
+ Bundler.ui = @previous_ui
+ Artifice.deactivate
+ Gem::Request::ConnectionPools.client = @previous_client
+ end
+
+ context "when a diagnostic fails" do
+ it "prints the diagnostic when openssl can't be loaded" do
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ allow(subject).to receive(:require).with("openssl").and_raise(LoadError)
+
+ expected_err = <<~MSG
+ Oh no! Your Ruby doesn't have OpenSSL, so it can't connect to rubygems.org.
+ You'll need to recompile or reinstall Ruby with OpenSSL support and try again.
+ MSG
+
+ expect { subject.run }.to output("").to_stdout.and output(expected_err).to_stderr
+ end
+
+ it "fails due to certificate verification", :ruby_repo do
+ net_http = Class.new(Artifice::Net::HTTP) do
+ def connect
+ raise OpenSSL::SSL::SSLError, "certificate verify failed"
+ end
+ end
+
+ Artifice.replace_net_http(net_http)
+ Gem::Request::ConnectionPools.client = net_http
+ Gem::RemoteFetcher.fetcher.close_all
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ MSG
+
+ expected_err = <<~MSG
+ Bundler: failed (certificate verification)
+ RubyGems: failed (certificate verification)
+ Ruby net/http: failed
+
+ Unfortunately, this Ruby can't connect to rubygems.org.
+
+ Below affect only Ruby net/http connections:
+ SSL_CERT_FILE: exists #{OpenSSL::X509::DEFAULT_CERT_FILE}
+ SSL_CERT_DIR: exists #{OpenSSL::X509::DEFAULT_CERT_DIR}
+
+ Your Ruby can't connect to rubygems.org because you are missing the certificate files OpenSSL needs to verify you are connecting to the genuine rubygems.org servers.
+
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ end
+
+ it "fails due to a too old tls version" do
+ subject = Bundler::CLI::Doctor::SSL.new({})
+
+ net_http = Class.new(Artifice::Net::HTTP) do
+ def connect
+ raise OpenSSL::SSL::SSLError, "read server hello A"
+ end
+ end
+
+ Artifice.replace_net_http(net_http)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+ Gem::RemoteFetcher.fetcher.close_all
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ MSG
+
+ expected_err = <<~MSG
+ Bundler: failed (SSL/TLS protocol version mismatch)
+ RubyGems: failed (SSL/TLS protocol version mismatch)
+ Ruby net/http: failed
+
+ Unfortunately, this Ruby can't connect to rubygems.org.
+
+ Your Ruby can't connect to rubygems.org because your version of OpenSSL is too old.
+ You'll need to upgrade your OpenSSL install and/or recompile Ruby to use a newer OpenSSL.
+
+ MSG
+
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ end
+
+ it "fails due to unsupported tls 1.3 version" do
+ net_http = Class.new(Artifice::Net::HTTP) do
+ def connect
+ raise OpenSSL::SSL::SSLError, "read server hello A"
+ end
+ end
+
+ Artifice.replace_net_http(net_http)
+ Gem::Request::ConnectionPools.client = net_http
+ Gem::RemoteFetcher.fetcher.close_all
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ MSG
+
+ expected_err = <<~MSG
+ Bundler: failed (SSL/TLS protocol version mismatch)
+ RubyGems: failed (SSL/TLS protocol version mismatch)
+ Ruby net/http: failed
+
+ Unfortunately, this Ruby can't connect to rubygems.org.
+
+ Your Ruby can't connect to rubygems.org because TLS1_3 isn't supported yet.
+
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new("tls-version": "1.3")
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ end
+
+ it "fails due to a bundler and rubygems connection error" do
+ endpoint = Class.new(Endpoint) do
+ get "/" do
+ raise OpenSSL::SSL::SSLError, "read server hello A"
+ end
+ end
+
+ Artifice.activate_with(endpoint)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ Ruby net/http: success
+
+ For some reason, your Ruby installation can connect to rubygems.org, but neither RubyGems nor Bundler can.
+ The most likely fix is to manually upgrade RubyGems by following the instructions at http://ruby.to/ssl-check-failed.
+ After you've done that, run `gem install bundler` to upgrade Bundler, and then run this script again to make sure everything worked. ❣
+
+ MSG
+
+ expected_err = <<~MSG
+ Bundler: failed (SSL/TLS protocol version mismatch)
+ RubyGems: failed (SSL/TLS protocol version mismatch)
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ end
+
+ it "fails due to a bundler connection error" do
+ endpoint = Class.new(Endpoint) do
+ get "/" do
+ if request.user_agent.include?("bundler")
+ raise OpenSSL::SSL::SSLError, "read server hello A"
+ end
+ end
+ end
+
+ Artifice.activate_with(endpoint)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ RubyGems: success
+ Ruby net/http: success
+
+ Although your Ruby installation and RubyGems can both connect to rubygems.org, Bundler is having trouble.
+ The most likely way to fix this is to upgrade Bundler by running `gem install bundler`.
+ Run this script again after doing that to make sure everything is all set.
+ If you're still having trouble, check out the troubleshooting guide at http://ruby.to/ssl-check-failed.
+
+ MSG
+
+ expected_err = <<~MSG
+ Bundler: failed (SSL/TLS protocol version mismatch)
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ end
+
+ it "fails due to a RubyGems connection error" do
+ endpoint = Class.new(Endpoint) do
+ get "/" do
+ if request.user_agent.include?("Ruby, RubyGems")
+ raise OpenSSL::SSL::SSLError, "read server hello A"
+ end
+ end
+ end
+
+ Artifice.activate_with(endpoint)
+ Gem::Request::ConnectionPools.client = Gem::Net::HTTP
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ Bundler: success
+ Ruby net/http: success
+
+ It looks like Ruby and Bundler can connect to rubygems.org, but RubyGems itself cannot.
+ You can likely solve this by manually downloading and installing a RubyGems update.
+ Visit http://ruby.to/ssl-check-failed for instructions on how to manually upgrade RubyGems.
+
+ MSG
+
+ expected_err = <<~MSG
+ RubyGems: failed (SSL/TLS protocol version mismatch)
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ end
+ end
+
+ context "when no diagnostic fails" do
+ it "prints the SSL environment" do
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ Bundler: success
+ RubyGems: success
+ Ruby net/http: success
+
+ Hooray! This Ruby can connect to rubygems.org.
+ You are all set to use Bundler and RubyGems.
+
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ expect { subject.run }.to output(expected_out).to_stdout.and output("").to_stderr
+ end
+
+ it "uses the tls_version verify mode and host when given as option" do
+ net_http = Class.new(Artifice::Net::HTTP) do
+ class << self
+ attr_accessor :verify_mode, :min_version, :max_version
+ end
+
+ def connect
+ self.class.verify_mode = verify_mode
+ self.class.min_version = min_version
+ self.class.max_version = max_version
+
+ super
+ end
+ end
+
+ net_http.endpoint = @dummy_endpoint
+ Artifice.replace_net_http(net_http)
+ Gem::Request::ConnectionPools.client = net_http
+ Gem::RemoteFetcher.fetcher.close_all
+
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://example.org:
+ Bundler: success
+ RubyGems: success
+ Ruby net/http: success
+
+ Hooray! This Ruby can connect to example.org.
+ You are all set to use Bundler and RubyGems.
+
+ MSG
+
+ subject = Bundler::CLI::Doctor::SSL.new("tls-version": "1.3", "verify-mode": :none, host: "example.org")
+ expect { subject.run }.to output(expected_out).to_stdout.and output("").to_stderr
+ expect(net_http.verify_mode).to eq(0)
+ expect(net_http.min_version.to_s).to eq("TLS1_3")
+ expect(net_http.max_version.to_s).to eq("TLS1_3")
+ end
+
+ it "warns when TLS1.2 is not supported" do
+ expected_out = <<~MSG
+ Here's your OpenSSL environment:
+
+ OpenSSL: #{OpenSSL::VERSION}
+ Compiled with: #{OpenSSL::OPENSSL_VERSION}
+ Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
+
+ Trying connections to https://rubygems.org:
+ Bundler: success
+ RubyGems: success
+ Ruby net/http: success
+
+ Hooray! This Ruby can connect to rubygems.org.
+ You are all set to use Bundler and RubyGems.
+
+ MSG
+
+ expected_err = <<~MSG
+
+ WARNING: Although your Ruby can connect to rubygems.org today, your OpenSSL is very old!
+ WARNING: You will need to upgrade OpenSSL to use rubygems.org.
+
+ MSG
+
+ previous_version = OpenSSL::SSL::TLS1_2_VERSION
+ OpenSSL::SSL.send(:remove_const, :TLS1_2_VERSION)
+
+ subject = Bundler::CLI::Doctor::SSL.new({})
+ expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
+ ensure
+ OpenSSL::SSL.const_set(:TLS1_2_VERSION, previous_version)
+ end
+ end
+end
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index c6ab0dcf14..03a3786d80 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -39,6 +39,23 @@ RSpec.describe "bundle update" do
end
end
+ describe "with --verbose" do
+ before do
+ build_repo2
+
+ install_gemfile <<~G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+ end
+
+ it "logs the reason for re-resolving" do
+ bundle "update --verbose"
+ expect(out).not_to include("Found changes from the lockfile")
+ expect(out).to include("Re-resolving dependencies because bundler is unlocking")
+ end
+ end
+
describe "with --all" do
before do
build_repo2
@@ -93,7 +110,7 @@ RSpec.describe "bundle update" do
end
context "when update_requires_all_flag is set" do
- before { bundle "config set update_requires_all_flag true" }
+ before { bundle_config "update_requires_all_flag true" }
it "errors when passed nothing" do
install_gemfile "source 'https://gem.repo1'"
@@ -176,7 +193,7 @@ RSpec.describe "bundle update" do
end
it "should suggest alternatives" do
bundle "update platformspecific", raise_on_error: false
- expect(err).to include "Did you mean platform_specific?"
+ expect(err).to include "Did you mean 'platform_specific'?"
end
end
@@ -230,7 +247,7 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1")
- update_repo4 do
+ build_repo4 do
build_gem "slim", "4.0.0" do |s|
s.add_dependency "tilt", [">= 2.0.6", "< 2.1"]
end
@@ -296,7 +313,7 @@ RSpec.describe "bundle update" do
country_select
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
previous_lockfile = lockfile
@@ -357,7 +374,7 @@ RSpec.describe "bundle update" do
quickbooks-ruby
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update --conservative --verbose"
@@ -418,7 +435,7 @@ RSpec.describe "bundle update" do
sneakers
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update --verbose"
@@ -428,6 +445,49 @@ RSpec.describe "bundle update" do
expect(out).to include("Installing sneakers 2.11.0").and include("Installing rake 13.0.6")
end
+ it "downgrades indirect dependencies if required to fulfill an explicit upgrade request" do
+ build_repo4 do
+ build_gem "rbs", "3.6.1"
+ build_gem "rbs", "3.9.4"
+
+ build_gem "solargraph", "0.56.0" do |s|
+ s.add_dependency "rbs", "~> 3.3"
+ end
+
+ build_gem "solargraph", "0.56.2" do |s|
+ s.add_dependency "rbs", "~> 3.6.1"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem 'solargraph', '~> 0.56.0'
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ rbs (3.9.4)
+ solargraph (0.56.0)
+ rbs (~> 3.3)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ solargraph (~> 0.56.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock --update solargraph"
+
+ expect(lockfile).to include("solargraph (0.56.2)")
+ end
+
it "does not downgrade direct dependencies unnecessarily" do
build_repo4 do
build_gem "redis", "4.8.1"
@@ -484,7 +544,7 @@ RSpec.describe "bundle update" do
sidekiq (~> 6.5)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -512,7 +572,7 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
- update_repo4 do
+ build_repo4 do
build_gem "b", "2.0" do |s|
s.add_dependency "c", "< 2"
end
@@ -596,7 +656,7 @@ RSpec.describe "bundle update" do
activesupport (~> 6.0.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update activesupport"
@@ -648,7 +708,7 @@ RSpec.describe "bundle update" do
myrack-obama
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -755,8 +815,8 @@ RSpec.describe "bundle update" do
G
end
- it "should fail loudly", bundler: "< 3" do
- bundle "install --deployment"
+ it "should fail loudly" do
+ bundle_config "deployment true"
bundle "update", all: true, raise_on_error: false
expect(last_command).to be_failure
@@ -768,7 +828,7 @@ RSpec.describe "bundle update" do
end
it "should fail loudly when frozen is set globally" do
- bundle "config set --global frozen 1"
+ bundle_config_global "frozen 1"
bundle "update", all: true, raise_on_error: false
expect(err).to eq <<~ERROR.strip
Bundler is unlocking, but the lockfile can't be updated because frozen mode is set
@@ -778,7 +838,7 @@ RSpec.describe "bundle update" do
end
it "should fail loudly when deployment is set globally" do
- bundle "config set --global deployment true"
+ bundle_config_global "deployment true"
bundle "update", all: true, raise_on_error: false
expect(err).to eq <<~ERROR.strip
Bundler is unlocking, but the lockfile can't be updated because frozen mode is set
@@ -916,7 +976,7 @@ RSpec.describe "bundle update" do
bundle "update", all: true
expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
- update_repo4 do
+ build_repo4 do
build_gem "foo", "2.0"
end
@@ -977,7 +1037,7 @@ RSpec.describe "bundle update" do
request_store
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1014,71 +1074,9 @@ RSpec.describe "bundle update" do
request_store
BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- context "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
- before do
- build_repo2 do
- build_gem "dotenv", "2.7.6"
-
- build_gem "oj", "3.11.3"
- build_gem "oj", "3.11.5"
-
- build_gem "vcr", "6.0.0"
- end
-
- build_repo3 do
- build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
- s.add_dependency "oj"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "dotenv"
-
- source "https://gem.repo3" do
- gem 'pkg-gem-flowbyte-with-dep'
- end
-
- gem "vcr",source: "https://gem.repo2"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- remote: https://gem.repo3/
- specs:
- dotenv (2.7.6)
- oj (3.11.3)
- pkg-gem-flowbyte-with-dep (1.0.0)
- oj
- vcr (6.0.0)
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- dotenv
- pkg-gem-flowbyte-with-dep!
- vcr!
-
- BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
-
- it "works" do
- 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"
- end
end
end
@@ -1123,7 +1121,7 @@ RSpec.describe "bundle update in more complicated situations" do
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(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"
end
@@ -1141,7 +1139,7 @@ RSpec.describe "bundle update in more complicated situations" do
bundle "update foo"
- expect(last_command.stdboth).not_to include "attempted to update"
+ expect(stdboth).not_to include "attempted to update"
end
it "will not warn when changing gem sources but not versions" do
@@ -1159,7 +1157,7 @@ RSpec.describe "bundle update in more complicated situations" do
bundle "update myrack"
- expect(last_command.stdboth).not_to include "attempted to update"
+ expect(stdboth).not_to include "attempted to update"
end
it "will update only from pinned source" do
@@ -1249,7 +1247,7 @@ RSpec.describe "bundle update in more complicated situations" do
it "is not updated because it is not actually included in the bundle" do
simulate_platform "x86_64-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(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
@@ -1290,7 +1288,7 @@ RSpec.describe "bundle update when a gem depends on a newer version of bundler"
it "should explain that bundler conflicted and how to resolve the conflict" do
bundle "update", all: true, raise_on_error: false
- expect(last_command.stdboth).not_to match(/in snapshot/i)
+ expect(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)
end
@@ -1323,7 +1321,7 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
#{checksums_section_when_enabled}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1355,10 +1353,10 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
#{checksums_section_when_enabled}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1400,7 +1398,7 @@ RSpec.describe "bundle update --ruby" do
ruby 2.1.4p222
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -1421,14 +1419,12 @@ RSpec.describe "bundle update --ruby" do
#{lockfile_platforms}
DEPENDENCIES
-
- CHECKSUMS
-
+ #{checksums_section_when_enabled}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1462,7 +1458,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
@@ -1482,7 +1478,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(the_bundle).to include_gem "myrack 1.0"
@@ -1520,14 +1516,16 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(the_bundle).to include_gem "myrack 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"
+ bundle_config "path.system true"
+
+ pristine_system_gems "bundler-9.0.0"
build_repo4 do
build_gem "myrack", "1.0"
@@ -1535,13 +1533,17 @@ RSpec.describe "bundle update --bundler" do
build_bundler "999.0.0"
end
+ checksums = checksums_section do |c|
+ c.checksum(gem_repo4, "myrack", "1.0")
+ c.checksum(gem_repo4, "bundler", "999.0.0")
+ end
+
install_gemfile <<-G
source "https://gem.repo4"
gem "myrack"
G
- lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.99.9")
- bundle :update, bundler: true, verbose: true, preserve_ruby_flags: true
+ bundle :update, bundler: true, verbose: true
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")
@@ -1558,9 +1560,9 @@ RSpec.describe "bundle update --bundler" do
DEPENDENCIES
myrack
-
+ #{checksums}
BUNDLED WITH
- 999.0.0
+ 999.0.0
L
expect(the_bundle).to include_gems "bundler 999.0.0"
@@ -1568,12 +1570,12 @@ RSpec.describe "bundle update --bundler" do
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"
+ pristine_system_gems "bundler-4.99.0"
build_repo4 do
build_gem "myrack", "3.0.9.1"
- build_bundler "2.99.0"
+ build_bundler "4.99.0"
end
gemfile <<~G
@@ -1618,6 +1620,7 @@ RSpec.describe "bundle update --bundler" do
checksums = checksums_section do |c|
c.checksum(gem_repo4, "myrack", "1.0")
+ c.checksum(gem_repo4, "bundler", "9.9.9")
end
install_gemfile <<-G
@@ -1642,7 +1645,7 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 9.9.9
+ 9.9.9
L
expect(the_bundle).to include_gems "bundler 9.9.9"
@@ -1667,8 +1670,26 @@ RSpec.describe "bundle update --bundler" do
expect(err).to eq("The `bundle update --bundler` target version (999.999.999) does not exist")
end
+ it "errors if the explicit target version does not exist, even if auto switching is disabled" do
+ pristine_system_gems "bundler-9.9.9"
+
+ build_repo4 do
+ build_gem "myrack", "1.0"
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ gem "myrack"
+ G
+
+ bundle :update, bundler: "999.999.999", raise_on_error: false, env: { "BUNDLER_VERSION" => "9.9.9" }
+
+ expect(last_command).to be_failure
+ expect(err).to eq("The `bundle update --bundler` target version (999.999.999) does not exist")
+ end
+
it "allows updating to development versions if already installed locally" do
- system_gems "bundler-2.3.0.dev"
+ system_gems "bundler-9.9.9"
build_repo4 do
build_gem "myrack", "1.0"
@@ -1679,11 +1700,13 @@ RSpec.describe "bundle update --bundler" do
gem "myrack"
G
- bundle :update, bundler: "2.3.0.dev", verbose: "true"
+ system_gems "bundler-9.0.0.dev", path: local_gem_path
+ bundle :update, bundler: "9.0.0.dev", verbose: "true"
checksums = checksums_section_when_enabled do |c|
c.checksum(gem_repo4, "myrack", "1.0")
end
+ checksums.delete("bundler")
expect(lockfile).to eq <<~L
GEM
@@ -1698,14 +1721,14 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 2.3.0.dev
+ 9.0.0.dev
L
- expect(out).to include("Using bundler 2.3.0.dev")
+ expect(out).to include("Using bundler 9.0.0.dev")
end
it "does not touch the network if not necessary" do
- system_gems "bundler-2.3.9"
+ system_gems "bundler-9.9.9"
build_repo4 do
build_gem "myrack", "1.0"
@@ -1715,14 +1738,15 @@ RSpec.describe "bundle update --bundler" do
source "https://gem.repo4"
gem "myrack"
G
-
- bundle :update, bundler: "2.3.9", verbose: true
+ system_gems "bundler-9.0.0", path: local_gem_path
+ bundle :update, bundler: "9.0.0", verbose: true
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")
+ c.checksum(local_gem_path, "bundler", "9.0.0", Gem::Platform::RUBY, "cache")
end
expect(lockfile).to eq <<~L
@@ -1738,14 +1762,14 @@ RSpec.describe "bundle update --bundler" do
myrack
#{checksums}
BUNDLED WITH
- 2.3.9
+ 9.0.0
L
- expect(out).to include("Using bundler 2.3.9")
+ expect(out).to include("Using bundler 9.0.0")
end
it "prints an error when trying to update bundler in frozen mode" do
- system_gems "bundler-2.3.9"
+ system_gems "bundler-9.0.0"
gemfile <<~G
source "https://gem.repo2"
@@ -1762,11 +1786,13 @@ RSpec.describe "bundle update --bundler" do
DEPENDENCIES
BUNDLED WITH
- 2.1.4
+ 9.0.0
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")
+ system_gems "bundler-9.9.9", path: local_gem_path
+
+ bundle "update --bundler=9.9.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
@@ -1810,7 +1836,7 @@ RSpec.describe "bundle update conservative" do
context "with patch set as default update level in config" do
it "should do a patch level update" do
- bundle "config set --local prefer_patch true"
+ bundle_config "prefer_patch true"
bundle "update foo"
expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.0"
@@ -1929,7 +1955,7 @@ RSpec.describe "bundle update conservative" do
CHECKSUMS
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1990,7 +2016,7 @@ RSpec.describe "bundle update conservative" do
shared_owner_b
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2044,7 +2070,7 @@ RSpec.describe "bundle update conservative" do
nokogiri (>= 1.16.4)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
diff --git a/spec/bundler/commands/version_spec.rb b/spec/bundler/commands/version_spec.rb
index 307058a5dd..4320ad0611 100644
--- a/spec/bundler/commands/version_spec.rb
+++ b/spec/bundler/commands/version_spec.rb
@@ -10,38 +10,56 @@ RSpec.describe "bundle version" do
end
context "with -v" do
- it "outputs the version", bundler: "< 3" do
+ it "outputs the version and virtual version if set" do
bundle "-v"
- expect(out).to eq("Bundler version #{Bundler::VERSION}")
- end
+ expect(out).to eq(Bundler::VERSION.to_s)
- it "outputs the version", bundler: "3" do
+ bundle_config "simulate_version 5"
bundle "-v"
- expect(out).to eq(Bundler::VERSION)
+ expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 5)")
end
end
context "with --version" do
- it "outputs the version", bundler: "< 3" do
+ it "outputs the version and virtual version if set" do
bundle "--version"
- expect(out).to eq("Bundler version #{Bundler::VERSION}")
- end
+ expect(out).to eq(Bundler::VERSION.to_s)
- it "outputs the version", bundler: "3" do
+ bundle_config "simulate_version 5"
bundle "--version"
- expect(out).to eq(Bundler::VERSION)
+ expect(out).to eq("#{Bundler::VERSION} (simulating Bundler 5)")
end
end
context "with version" 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/)
+ context "when released", :ruby_repo do
+ before do
+ system_gems "bundler-4.9.9", released: true
+ end
+
+ it "outputs the version, virtual version if set, and build metadata" do
+ bundle "version"
+ expect(out).to match(/\A4\.9\.9 \(2100-01-01 commit #{COMMIT_HASH}\)\z/)
+
+ bundle_config "simulate_version 5"
+ bundle "version"
+ expect(out).to match(/\A4\.9\.9 \(simulating Bundler 5\) \(2100-01-01 commit #{COMMIT_HASH}\)\z/)
+ end
end
- 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/)
+ context "when not released" do
+ before do
+ system_gems "bundler-4.9.9", released: false
+ end
+
+ it "outputs the version, virtual version if set, and build metadata" do
+ bundle "version"
+ expect(out).to match(/\A4\.9\.9 \(20\d{2}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
+
+ bundle_config "simulate_version 5"
+ bundle "version"
+ expect(out).to match(/\A4\.9\.9 \(simulating Bundler 5\) \(20\d{2}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
+ end
end
end
end
diff --git a/spec/bundler/commands/viz_spec.rb b/spec/bundler/commands/viz_spec.rb
deleted file mode 100644
index 712ded4bc4..0000000000
--- a/spec/bundler/commands/viz_spec.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot") 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"
- G
-
- bundle "viz"
- expect(out).to include("gem_graph.png")
-
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
- digraph Gemfile {
- concentrate = "true";
- normalize = "true";
- nodesep = "0.55";
- edge[ weight = "2"];
- 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;
- }
- debugging bundle viz...
- DOT
- end
-
- it "graphs gems that are prereleases" do
- build_repo2 do
- build_gem "myrack", "1.3.pre"
- end
-
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "= 1.3.pre"
- gem "myrack-obama"
- G
-
- bundle "viz"
- expect(out).to include("gem_graph.png")
-
- bundle "viz", format: :debug, version: true
- expect(out).to eq(<<~EOS.strip)
- digraph Gemfile {
- concentrate = "true";
- normalize = "true";
- nodesep = "0.55";
- edge[ weight = "2"];
- 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;
- }
- debugging bundle viz...
- EOS
- end
-
- context "with another gem that has a graphviz file" do
- before do
- build_repo4 do
- build_gem "graphviz", "999" do |s|
- s.write("lib/graphviz.rb", "abort 'wrong graphviz gem loaded'")
- end
- end
-
- 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"
- G
-
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
- digraph Gemfile {
- concentrate = "true";
- normalize = "true";
- nodesep = "0.55";
- edge[ weight = "2"];
- 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;
- }
- debugging bundle viz...
- DOT
- end
- end
-
- context "--without option" do
- it "one group" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
-
- group :rails do
- gem "rails"
- end
- G
-
- bundle "viz --without=rails"
- expect(out).to include("gem_graph.png")
- end
-
- it "two groups" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
-
- group :myrack do
- gem "myrack"
- end
-
- group :rails do
- gem "rails"
- end
- G
-
- bundle "viz --without=rails:myrack"
- expect(out).to include("gem_graph.png")
- end
- end
-end
diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb
index 21b0568f7d..c7ab7c3d7e 100644
--- a/spec/bundler/install/allow_offline_install_spec.rb
+++ b/spec/bundler/install/allow_offline_install_spec.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle install with :allow_offline_install" do
- before do
- bundle "config set allow_offline_install true"
- end
-
+RSpec.describe "bundle install allows offline install" do
context "with no cached data locally" do
it "still installs" do
install_gemfile <<-G, artifice: "compact_index"
@@ -28,7 +24,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
it "will install from the compact index" do
system_gems ["myrack-1.0.0"], path: default_bundle_path
- bundle "config set clean false"
+ bundle_config "clean false"
install_gemfile <<-G, artifice: "compact_index"
source "http://testgemserver.local"
gem "myrack-obama"
@@ -43,7 +39,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
G
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(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")
end
diff --git a/spec/bundler/install/binstubs_spec.rb b/spec/bundler/install/binstubs_spec.rb
index 00765ac6dd..c2eccb3ef2 100644
--- a/spec/bundler/install/binstubs_spec.rb
+++ b/spec/bundler/install/binstubs_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- config "BUNDLE_SYSTEM_BINDIR" => system_gem_path("altbin").to_s
+ bundle_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
diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb
index 56f8431181..86c22dad55 100644
--- a/spec/bundler/install/bundler_spec.rb
+++ b/spec/bundler/install/bundler_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if child dependencies conflict" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
update_repo2 do
build_gem "rails_pinned_to_old_activesupport" do |s|
@@ -163,7 +163,7 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if a child dependency conflicts with the Gemfile" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
update_repo2 do
build_gem "rails_pinned_to_old_activesupport" do |s|
@@ -216,7 +216,7 @@ RSpec.describe "bundle install" do
build_gem "rails", "7.0.4"
end
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo4"
@@ -238,7 +238,7 @@ RSpec.describe "bundle install" do
end
it "can install dependencies with newer bundler version with system gems" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
system_gems "bundler-99999999.99.1"
@@ -252,7 +252,7 @@ RSpec.describe "bundle install" do
end
it "can install dependencies with newer bundler version with a local path" do
- bundle "config set path .bundle"
+ bundle_config "path .bundle"
system_gems "bundler-99999999.99.1"
diff --git a/spec/bundler/install/cooldown_spec.rb b/spec/bundler/install/cooldown_spec.rb
new file mode 100644
index 0000000000..b3f57d93cc
--- /dev/null
+++ b/spec/bundler/install/cooldown_spec.rb
@@ -0,0 +1,272 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with the cooldown setting" do
+ before do
+ build_repo2
+ end
+
+ context "Gemfile DSL" do
+ it "accepts `source ..., cooldown: N` without error" do
+ install_gemfile <<-G, artifice: "compact_index"
+ source "https://gem.repo2", cooldown: 5
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "accepts `cooldown: 0` to disable cooldown for a source" do
+ install_gemfile <<-G, artifice: "compact_index"
+ source "https://gem.repo2", cooldown: 0
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+ end
+
+ context "CLI flag" do
+ before do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+ end
+
+ it "accepts --cooldown N on install" do
+ bundle "install --cooldown 7", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "accepts --cooldown 0 as an escape hatch" do
+ bundle "install --cooldown 0", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "rejects a negative --cooldown value" do
+ bundle "install --cooldown=-7", artifice: "compact_index", raise_on_error: false
+
+ expect(err).to match(/non-negative integer/)
+ end
+ end
+
+ context "configuration" do
+ it "reads BUNDLE_COOLDOWN as an integer" do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ bundle "install", env: { "BUNDLE_COOLDOWN" => "7" }, artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+
+ it "reads `bundle config set cooldown N`" do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ bundle "config set cooldown 7"
+ bundle "install", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ end
+ end
+
+ context "end-to-end with v2 compact index" do
+ before do
+ now = Time.now.utc
+ build_repo3 do
+ build_gem "ripe_gem", "1.0.0" do |s|
+ s.date = now - (30 * 86_400)
+ end
+ build_gem "ripe_gem", "2.0.0" do |s|
+ s.date = now - (1 * 86_400)
+ end
+ end
+ end
+
+ it "excludes versions within the cooldown window" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "selects the latest version when --cooldown 0 is passed" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 0", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "applies cooldown declared per-source in the Gemfile" do
+ gemfile <<-G
+ source "https://gem.repo3", cooldown: 7
+ gem "ripe_gem"
+ G
+
+ bundle "install", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "is overridden by CLI --cooldown when Gemfile sets a different per-source value" do
+ gemfile <<-G
+ source "https://gem.repo3", cooldown: 0
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "bypasses cooldown when bundle install uses an existing lockfile" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (2.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "annotates in-cooldown versions in bundle outdated table output" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem", "1.0.0"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem (= 1.0.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "outdated --cooldown 7", artifice: "compact_index_cooldown", raise_on_error: false
+
+ expect(out).to match(/ripe_gem.*\(cooldown \d+d\)/)
+ end
+
+ it "annotates in-cooldown versions in bundle outdated --parseable output" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem", "1.0.0"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem (= 1.0.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "outdated --cooldown 7 --parseable", artifice: "compact_index_cooldown", raise_on_error: false
+
+ expect(out).to match(/ripe_gem.*in cooldown for \d+ more day/)
+ end
+
+ it "excludes a locally-installed version that is still within the cooldown window" do
+ system_gems "ripe_gem-2.0.0", gem_repo: gem_repo3
+
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 7", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 1.0.0")
+ end
+
+ it "selects a locally-installed in-cooldown version when --cooldown 0 bypasses the filter" do
+ system_gems "ripe_gem-2.0.0", gem_repo: gem_repo3
+
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ bundle "install --cooldown 0", artifice: "compact_index_cooldown"
+
+ expect(the_bundle).to include_gems("ripe_gem 2.0.0")
+ end
+
+ it "surfaces a cooldown hint when bundle update filters every candidate" do
+ gemfile <<-G
+ source "https://gem.repo3"
+ gem "ripe_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ ripe_gem (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ripe_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update ripe_gem --cooldown 99999", artifice: "compact_index_cooldown", raise_on_error: false
+
+ expect(err).to match(/excluded by the cooldown setting/)
+ expect(err).to match(/--cooldown 0/)
+ end
+ end
+end
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index 7db12c0d0b..a3b4a87ecf 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -8,89 +8,23 @@ RSpec.describe "install in deployment or frozen mode" do
G
end
- 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")
- 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")
- end
-
- it "disallows --deployment --system" do
- 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
- 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")
- expect(exitstatus).to eq(15)
- 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
- expect(the_bundle).to include_gems "myrack 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_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_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
bundle "install"
- pristine_system_gems :bundler
- bundle "config set --local deployment true"
- bundle "config set --local path vendor/bundle"
+ pristine_system_gems
+ bundle_config "deployment true"
+ bundle_config "path vendor/bundle"
bundle "install --gemfile #{tmp}/bundled_app/Gemfile", dir: tmp
expect(the_bundle).to include_gems "myrack 1.0"
end
@@ -104,8 +38,8 @@ RSpec.describe "install in deployment or frozen mode" do
end
G
bundle :install
- bundle "config set --local deployment true"
- bundle "config set --local without test"
+ bundle_config "deployment true"
+ bundle_config "without test"
bundle :install
end
@@ -113,7 +47,7 @@ RSpec.describe "install in deployment or frozen mode" do
skip "doesn't find bundle" if Gem.win_platform?
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
bundle "exec bundle check", env: { "PATH" => path }
end
@@ -128,7 +62,7 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
end
@@ -141,7 +75,7 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
end
@@ -152,7 +86,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack-obama", ">= 1.0"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint_strict_basic_authentication"
end
@@ -164,7 +98,7 @@ RSpec.describe "install in deployment or frozen mode" do
end
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0"
@@ -172,7 +106,7 @@ RSpec.describe "install in deployment or frozen mode" do
context "when replacing a host with the same host with credentials" do
before do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle "install"
gemfile <<-G
source "http://user_name:password@localgemserver.test/"
@@ -192,7 +126,7 @@ RSpec.describe "install in deployment or frozen mode" do
myrack
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
end
it "allows the replace" do
@@ -208,7 +142,7 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "installs gems by default to vendor/bundle" do
- bundle "config set deployment true"
+ bundle_config "deployment true"
expect do
bundle "install"
end.not_to change { bundled_app_lock.mtime }
@@ -216,20 +150,20 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "installs gems to custom path if specified" do
- bundle "config set path vendor/bundle2"
- bundle "config set deployment true"
+ bundle_config "path vendor/bundle2"
+ bundle_config "deployment true"
bundle "install"
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_config "deployment true"
bundle "install", env: { "BUNDLE_PATH" => "vendor/bundle2" }
expect(out).to include("vendor/bundle2")
end
it "works with the `frozen` setting" do
- bundle "config set frozen true"
+ bundle_config "frozen true"
expect do
bundle "install"
end.not_to change { bundled_app_lock.mtime }
@@ -248,7 +182,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack-obama"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
@@ -267,9 +201,9 @@ RSpec.describe "install in deployment or frozen mode" do
expect(the_bundle).to include_gems "path_gem 1.0"
FileUtils.rm_r lib_path("path_gem-1.0")
- bundle "config set --local path .bundle"
- bundle "config set --local without development"
- bundle "config set --local deployment true"
+ bundle_config "path .bundle"
+ bundle_config "without development"
+ bundle_config "deployment true"
bundle :install, env: { "DEBUG" => "1" }
run "puts :WIN"
expect(out).to eq("WIN")
@@ -317,7 +251,7 @@ RSpec.describe "install in deployment or frozen mode" do
bar
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
@@ -334,8 +268,8 @@ RSpec.describe "install in deployment or frozen mode" do
expect(the_bundle).to include_gems "path_gem 1.0"
FileUtils.rm_r lib_path("path_gem-1.0")
- bundle "config set --local path .bundle"
- bundle "config set --local deployment true"
+ bundle_config "path .bundle"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("The path `#{lib_path("path_gem-1.0")}` does not exist.")
end
@@ -406,7 +340,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "activesupport"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile:\n* activesupport\n\n")
@@ -417,7 +351,7 @@ RSpec.describe "install in deployment or frozen mode" do
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_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("Some dependencies were deleted")
expect(err).to include("frozen mode")
@@ -431,7 +365,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack", :git => "git://hubz.com"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).not_to include("You have added to the Gemfile")
@@ -451,7 +385,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("frozen mode")
expect(err).not_to include("You have deleted from the Gemfile")
@@ -475,7 +409,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "foo", :git => "#{lib_path("myrack")}"
G
- bundle "config set --local deployment true"
+ bundle_config "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`")
@@ -496,7 +430,7 @@ RSpec.describe "install in deployment or frozen mode" do
gem "myrack", :git => "https:/my-git-repo-for-myrack"
G
- bundle "config set --local frozen true"
+ bundle_config "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`")
@@ -507,7 +441,7 @@ RSpec.describe "install in deployment or frozen mode" do
it "remembers that the bundle is frozen at runtime" do
bundle :lock
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
gemfile <<-G
source "https://gem.repo1"
@@ -540,15 +474,14 @@ RSpec.describe "install in deployment or frozen mode" do
bundle :install
expect(the_bundle).to include_gems "foo 1.0"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo")).to be_directory
bundle "install --local"
expect(out).to include("Updating files in vendor/cache")
- pristine_system_gems :bundler
- bundle "config set --local deployment true"
+ pristine_system_gems
+ bundle_config "deployment true"
bundle "install --verbose"
expect(out).not_to include("can't be updated because frozen mode is set")
expect(out).not_to include("You have added to the Gemfile")
diff --git a/spec/bundler/install/failure_spec.rb b/spec/bundler/install/failure_spec.rb
index 2c2773e849..32ca455439 100644
--- a/spec/bundler/install/failure_spec.rb
+++ b/spec/bundler/install/failure_spec.rb
@@ -48,4 +48,38 @@ In Gemfile:
end
end
end
+
+ context "when lockfile dependencies don't match the gemspec" do
+ before do
+ build_repo4 do
+ build_gem "myrack", "1.0.0" do |s|
+ s.add_dependency "myrack-test", "~> 1.0"
+ end
+
+ build_gem "myrack-test", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "myrack"
+ G
+
+ # First install to generate lockfile
+ bundle :install
+
+ # Manually edit lockfile to have incorrect dependencies
+ lockfile_content = File.read(bundled_app_lock)
+ # Remove the myrack-test dependency from myrack
+ lockfile_content.gsub!(/^ myrack \(1\.0\.0\)\n myrack-test \(~> 1\.0\)\n/, " myrack (1.0.0)\n")
+ File.write(bundled_app_lock, lockfile_content)
+ end
+
+ it "reports the mismatch with detailed information" do
+ bundle :install, raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
+
+ expect(err).to include("Bundler found incorrect dependencies in the lockfile for myrack-1.0.0")
+ expect(err).to include("myrack-test: gemspec specifies ~> 1.0, not in lockfile")
+ expect(err).to include("Please run `bundle install` to regenerate the lockfile.")
+ end
+ end
end
diff --git a/spec/bundler/install/force_spec.rb b/spec/bundler/install/force_spec.rb
new file mode 100644
index 0000000000..e0f6fb6364
--- /dev/null
+++ b/spec/bundler/install/force_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install" do
+ before :each do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+ end
+
+ shared_examples_for "an option to force reinstalling gems" do
+ it "re-installs installed gems" do
+ myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
+
+ bundle :install
+ myrack_lib.open("w") {|f| f.write("blah blah blah") }
+ bundle :install, flag => true
+
+ expect(out).to include "Installing myrack 1.0.0"
+ expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "works on first bundle install" do
+ bundle :install, flag => true
+
+ expect(out).to include "Installing myrack 1.0.0"
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ context "with a git gem" do
+ let!(:ref) { build_git("foo", "1.0").ref_for("HEAD", 11) }
+
+ before do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "foo", :git => "#{lib_path("foo-1.0")}"
+ G
+ end
+
+ it "re-installs installed gems" do
+ foo_lib = default_bundle_path("bundler/gems/foo-1.0-#{ref}/lib/foo.rb")
+
+ bundle :install
+ foo_lib.open("w") {|f| f.write("blah blah blah") }
+ bundle :install, flag => true
+
+ expect(foo_lib.open(&:read)).to eq("FOO = '1.0'\n")
+ expect(the_bundle).to include_gems "foo 1.0"
+ end
+
+ it "works on first bundle install" do
+ bundle :install, flag => true
+
+ expect(the_bundle).to include_gems "foo 1.0"
+ end
+ end
+ end
+
+ describe "with --force" do
+ it_behaves_like "an option to force reinstalling gems" do
+ let(:flag) { "force" }
+ end
+ end
+
+ describe "with --redownload" do
+ it_behaves_like "an option to force reinstalling gems" do
+ let(:flag) { "redownload" }
+ end
+ end
+end
diff --git a/spec/bundler/install/gemfile/eval_gemfile_spec.rb b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
index a507e52485..3afa4f5daa 100644
--- a/spec/bundler/install/gemfile/eval_gemfile_spec.rb
+++ b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
# parsed lockfile and the evaluated gemfile.
it "bundles with deployment mode configured" do
bundle :install
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
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..bcc1f36823 100644
--- a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
+++ b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
@@ -117,7 +117,7 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
platform_specific
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86-darwin-100" do
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb
index 4e83b7e9c3..e51fc9247d 100644
--- a/spec/bundler/install/gemfile/gemspec_spec.rb
+++ b/spec/bundler/install/gemfile/gemspec_spec.rb
@@ -126,7 +126,7 @@ RSpec.describe "bundle install from an existing gemspec" do
# 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"
+ bundle_config "deployment true"
output = bundle("install", dir: tmp("foo"), artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s })
expect(output).not_to match(/You have added to the Gemfile/)
expect(output).not_to match(/You have deleted from the Gemfile/)
@@ -192,7 +192,7 @@ RSpec.describe "bundle install from an existing gemspec" do
install_gemfile <<-G, raise_on_error: false
gemspec :path => '#{tmp("foo")}'
G
- expect(last_command.stdboth).not_to include("ahh")
+ expect(stdboth).not_to include("ahh")
end
it "allows the gemspec to activate other gems" do
@@ -260,6 +260,25 @@ RSpec.describe "bundle install from an existing gemspec" do
expect(out).to eq("WIN")
end
+ it "does not make Gem.try_activate warn when local gem has extensions" do
+ build_lib("foo", path: tmp("foo")) do |s|
+ s.version = "1.0.0"
+ s.add_c_extension
+ end
+ build_repo2
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gemspec :path => '#{tmp("foo")}'
+ G
+
+ expect(the_bundle).to include_gems "foo 1.0.0"
+
+ run "Gem.try_activate('irb/lc/es/error.rb'); puts 'WIN'"
+ expect(out).to eq("WIN")
+ expect(err).to be_empty
+ end
+
it "handles downgrades" do
build_lib "omg", "2.0", path: lib_path("omg")
@@ -293,7 +312,7 @@ RSpec.describe "bundle install from an existing gemspec" do
s.add_dependency "activesupport", ">= 1.0.1"
end
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, raise_on_error: false
expect(err).to include("changed")
@@ -361,7 +380,7 @@ RSpec.describe "bundle install from an existing gemspec" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -401,12 +420,13 @@ RSpec.describe "bundle install from an existing gemspec" do
end
build_lib "foo", path: bundled_app do |s|
- if platform_specific_type == :runtime
+ case platform_specific_type
+ when :runtime
s.add_runtime_dependency dependency
- elsif platform_specific_type == :development
+ when :development
s.add_development_dependency dependency
else
- raise "wrong dependency type #{platform_specific_type}, can only be :development or :runtime"
+ raise ArgumentError, "wrong dependency type #{platform_specific_type}, can only be :development or :runtime"
end
end
@@ -415,18 +435,18 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec
G
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
simulate_new_machine
simulate_platform("jruby") { bundle "install" }
expect(lockfile).to include("platform_specific (1.0-java)")
- simulate_platform("x64-mingw32") { bundle "install" }
+ simulate_platform("x64-mingw-ucrt") { bundle "install" }
end
context "on ruby" do
before do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle :install
end
@@ -438,7 +458,7 @@ RSpec.describe "bundle install from an existing gemspec" do
c.no_checksum "foo", "1.0"
c.checksum gem_repo2, "platform_specific", "1.0"
c.checksum gem_repo2, "platform_specific", "1.0", "java"
- c.checksum gem_repo2, "platform_specific", "1.0", "x64-mingw32"
+ c.checksum gem_repo2, "platform_specific", "1.0", "x64-mingw-ucrt"
end
expect(lockfile).to eq <<~L
@@ -453,18 +473,18 @@ RSpec.describe "bundle install from an existing gemspec" do
specs:
platform_specific (1.0)
platform_specific (1.0-java)
- platform_specific (1.0-x64-mingw32)
+ platform_specific (1.0-x64-mingw-ucrt)
PLATFORMS
java
ruby
- x64-mingw32
+ x64-mingw-ucrt
DEPENDENCIES
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -479,7 +499,7 @@ RSpec.describe "bundle install from an existing gemspec" do
c.no_checksum "foo", "1.0"
c.checksum gem_repo2, "platform_specific", "1.0"
c.checksum gem_repo2, "platform_specific", "1.0", "java"
- c.checksum gem_repo2, "platform_specific", "1.0", "x64-mingw32"
+ c.checksum gem_repo2, "platform_specific", "1.0", "x64-mingw-ucrt"
end
expect(lockfile).to eq <<~L
@@ -493,19 +513,19 @@ RSpec.describe "bundle install from an existing gemspec" do
specs:
platform_specific (1.0)
platform_specific (1.0-java)
- platform_specific (1.0-x64-mingw32)
+ platform_specific (1.0-x64-mingw-ucrt)
PLATFORMS
java
ruby
- x64-mingw32
+ x64-mingw-ucrt
DEPENDENCIES
foo!
platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -522,7 +542,7 @@ RSpec.describe "bundle install from an existing gemspec" do
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"
- c.checksum gem_repo2, "platform_specific", "1.0", "x64-mingw32"
+ c.checksum gem_repo2, "platform_specific", "1.0", "x64-mingw-ucrt"
end
expect(lockfile).to eq <<~L
@@ -538,19 +558,19 @@ RSpec.describe "bundle install from an existing gemspec" do
platform_specific
platform_specific (1.0)
platform_specific (1.0-java)
- platform_specific (1.0-x64-mingw32)
+ platform_specific (1.0-x64-mingw-ucrt)
PLATFORMS
java
ruby
- x64-mingw32
+ x64-mingw-ucrt
DEPENDENCIES
foo!
indirect_platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -568,7 +588,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "installs the ruby platform gemspec" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -579,9 +599,9 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "installs the ruby platform gemspec and skips dev deps with `without development` configured" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
- bundle "config set --local without development"
+ bundle_config "without development"
install_gemfile <<-G
source "https://gem.repo1"
gemspec :path => '#{tmp("foo")}', :name => 'foo'
@@ -596,14 +616,14 @@ RSpec.describe "bundle install from an existing gemspec" do
before do
build_lib("chef", path: tmp("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
+ s.write "chef-universal-mingw-ucrt.gemspec", build_spec("chef", "17.1.17", "universal-mingw-ucrt") {|sw| sw.runtime "win32-api", "~> 1.5.3" }.first.to_ruby
end
end
it "does not remove the platform specific specs from the lockfile when updating" do
build_repo4 do
build_gem "win32-api", "1.5.3" do |s|
- s.platform = "universal-mingw32"
+ s.platform = "universal-mingw-ucrt"
end
end
@@ -614,8 +634,8 @@ RSpec.describe "bundle install from an existing gemspec" do
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"
+ c.no_checksum "chef", "17.1.17", "universal-mingw-ucrt"
+ c.checksum gem_repo4, "win32-api", "1.5.3", "universal-mingw-ucrt"
end
initial_lockfile = <<~L
@@ -623,22 +643,22 @@ RSpec.describe "bundle install from an existing gemspec" do
remote: ../chef
specs:
chef (17.1.17)
- chef (17.1.17-universal-mingw32)
+ chef (17.1.17-universal-mingw-ucrt)
win32-api (~> 1.5.3)
GEM
remote: https://gem.repo4/
specs:
- win32-api (1.5.3-universal-mingw32)
+ win32-api (1.5.3-universal-mingw-ucrt)
PLATFORMS
- #{lockfile_platforms("ruby", "x64-mingw32", "x86-mingw32")}
+ #{lockfile_platforms("ruby", "x64-mingw-ucrt", "x86-mingw32")}
DEPENDENCIES
chef!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile initial_lockfile
@@ -701,7 +721,7 @@ RSpec.describe "bundle install from an existing gemspec" do
jruby-openssl
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemspec = tmp("activeadmin/activeadmin.gemspec")
diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb
index c763da4c00..b2a82caf01 100644
--- a/spec/bundler/install/gemfile/git_spec.rb
+++ b/spec/bundler/install/gemfile/git_spec.rb
@@ -2,12 +2,8 @@
RSpec.describe "bundle install with git sources" do
describe "when floating on main" do
- before :each do
- build_git "foo" do |s|
- s.executables = "foobar"
- end
-
- install_gemfile <<-G
+ let(:base_gemfile) do
+ <<-G
source "https://gem.repo1"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
@@ -15,7 +11,16 @@ RSpec.describe "bundle install with git sources" do
G
end
+ let(:install_base_gemfile) do
+ build_git "foo" do |s|
+ s.executables = "foobar"
+ end
+
+ install_gemfile base_gemfile
+ end
+
it "fetches gems" do
+ install_base_gemfile
expect(the_bundle).to include_gems("foo 1.0")
run <<-RUBY
@@ -26,19 +31,59 @@ 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
+ it "does not (yet?) enforce CHECKSUMS" do
+ build_git "foo"
+ revision = revision_for(lib_path("foo-1.0"))
+
+ bundle_config "lockfile_checksums true"
+ gemfile base_gemfile
+
+ lockfile <<~L
+ GIT
+ remote: #{lib_path("foo-1.0")}
+ revision: #{revision}
+ specs:
+ foo (1.0)
+
+ GEM
+ remote: https://gem.repo1/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+
+ CHECKSUMS
+ foo (1.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle_config "frozen true"
+
+ bundle "install"
+ expect(the_bundle).to include_gems("foo 1.0")
+ end
+
+ it "caches the git repo" do
+ install_base_gemfile
+ expect(Dir["#{default_cache_path}/git/foo-1.0-*"]).to have_attributes size: 1
end
it "does not write to cache on bundler/setup" do
+ install_base_gemfile
FileUtils.rm_r(default_cache_path)
ruby "require 'bundler/setup'"
expect(default_cache_path).not_to exist
end
it "caches the git repo globally and properly uses the cached repo on the next invocation" do
- pristine_system_gems :bundler
- bundle "config set global_gem_cache true"
+ install_base_gemfile
+ pristine_system_gems
+ bundle_config "global_gem_cache true"
bundle :install
expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes size: 1
@@ -48,6 +93,7 @@ RSpec.describe "bundle install with git sources" do
end
it "caches the evaluated gemspec" do
+ install_base_gemfile
git = update_git "foo" do |s|
s.executables = ["foobar"] # we added this the first time, so keep it now
s.files = ["bin/foobar"] # updating git nukes the files list
@@ -66,6 +112,7 @@ RSpec.describe "bundle install with git sources" do
end
it "does not update the git source implicitly" do
+ install_base_gemfile
update_git "foo"
install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
@@ -84,6 +131,7 @@ RSpec.describe "bundle install with git sources" do
end
it "sets up git gem executables on the path" do
+ install_base_gemfile
bundle "exec foobar"
expect(out).to eq("1.0")
end
@@ -135,8 +183,8 @@ RSpec.describe "bundle install with git sources" do
end
it "still works after moving the application directory" do
- bundle "config set --local path vendor/bundle"
- bundle "install"
+ bundle_config "path vendor/bundle"
+ install_base_gemfile
FileUtils.mv bundled_app, tmp("bundled_app.bck")
@@ -144,8 +192,8 @@ RSpec.describe "bundle install with git sources" do
end
it "can still install after moving the application directory" do
- bundle "config set --local path vendor/bundle"
- bundle "install"
+ bundle_config "path vendor/bundle"
+ install_base_gemfile
FileUtils.mv bundled_app, tmp("bundled_app.bck")
@@ -333,7 +381,7 @@ RSpec.describe "bundle install with git sources" do
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"))
- bundle "config set global_gem_cache true"
+ bundle_config "global_gem_cache true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -430,7 +478,7 @@ RSpec.describe "bundle install with git sources" do
update_git("foo", path: repo, tag: tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "https://gem.repo1"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -1030,7 +1078,7 @@ RSpec.describe "bundle install with git sources" do
expect(out).to eq("WIN")
end
- it "does not to a remote fetch if the revision is cached locally" do
+ it "does not do a remote fetch if the revision is cached locally" do
build_git "foo"
install_gemfile <<-G
@@ -1151,6 +1199,30 @@ RSpec.describe "bundle install with git sources" do
expect(the_bundle).to include_gem "rails 7.1.4", "activesupport 7.1.4"
end
+
+ it "doesn't explode when adding an explicit ref to a git gem with dependencies" do
+ lib_root = lib_path("rails")
+
+ build_lib "activesupport", "7.1.4", path: lib_root.join("activesupport")
+ build_git "rails", "7.1.4", path: lib_root do |s|
+ s.add_dependency "activesupport", "= 7.1.4"
+ end
+
+ old_revision = revision_for(lib_root)
+ update_git "rails", "7.1.4", path: lib_root
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "rails", "7.1.4", :git => "#{lib_root}"
+ G
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "rails", :git => "#{lib_root}", :ref => "#{old_revision}"
+ 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
@@ -1217,9 +1289,9 @@ RSpec.describe "bundle install with git sources" do
gem "valim", "= 1.0", :git => "#{lib_path("valim")}"
G
- pristine_system_gems :bundler
+ pristine_system_gems
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install
end
end
@@ -1332,7 +1404,7 @@ RSpec.describe "bundle install with git sources" do
File.open(git_reader.path.join("ext/foo.c"), "w") do |file|
file.write <<-C
#include "ruby.h"
- VALUE foo() { return INT2FIX(#{i}); }
+ VALUE foo(VALUE self) { return INT2FIX(#{i}); }
void Init_foo() { rb_define_global_function("foo", &foo, 0); }
C
end
@@ -1566,7 +1638,7 @@ In Gemfile:
rake!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
with_path_as("") do
@@ -1602,9 +1674,9 @@ In Gemfile:
gem 'foo'
end
G
- bundle "config set --global path vendor/bundle"
+ bundle_config_global "path vendor/bundle"
bundle :install
- pristine_system_gems :bundler
+ pristine_system_gems
bundle "install", env: { "PATH" => "" }
expect(out).to_not include("You need to install git to be able to use gems from git repositories.")
@@ -1613,7 +1685,7 @@ In Gemfile:
describe "when the git source is overridden with a local git repo" do
before do
- bundle "config set --global local.foo #{lib_path("foo")}"
+ bundle_config_global "local.foo #{lib_path("foo")}"
end
describe "and git output is colorized" do
@@ -1649,7 +1721,7 @@ In Gemfile:
end
G
- expect(last_command.stdboth).to_not include("password1")
+ expect(stdboth).to_not include("password1")
expect(out).to include("Fetching https://user1@github.com/company/private-repo")
end
end
@@ -1665,7 +1737,7 @@ In Gemfile:
end
G
- expect(last_command.stdboth).to_not include("oauth_token")
+ expect(stdboth).to_not include("oauth_token")
expect(out).to include("Fetching https://x-oauth-basic@github.com/company/private-repo")
end
end
diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb
index c5f50a8c5d..4013b112ec 100644
--- a/spec/bundler/install/gemfile/groups_spec.rb
+++ b/spec/bundler/install/gemfile/groups_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "bundle install with groups" do
puts ACTIVESUPPORT
R
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- activesupport/)
end
it "installs gems with inline :groups into those groups" do
@@ -36,7 +36,7 @@ RSpec.describe "bundle install with groups" do
puts THIN
R
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- thin/)
end
it "sets up everything if Bundler.setup is used with no groups" do
@@ -57,7 +57,7 @@ RSpec.describe "bundle install with groups" do
puts THIN
RUBY
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- thin/)
end
it "sets up old groups when they have previously been removed" do
@@ -86,13 +86,13 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 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_config_global "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
bundle "config list"
@@ -100,34 +100,27 @@ RSpec.describe "bundle install with groups" do
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
- bundle "config set without emo"
+ it "allows running application where groups where configured by a different user" do
+ bundle_config "without emo"
bundle :install
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_config "without emo"
bundle :install
expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
end
- 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
- expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- end
-
it "does not say it installed gems from the excluded group" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(out).not_to include("activesupport")
end
it "allows Bundler.setup for specific groups" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
run("require 'myrack'; puts MYRACK", :default)
expect(out).to eq("1.0.0")
@@ -142,7 +135,7 @@ RSpec.describe "bundle install with groups" do
end
G
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.2", groups: [:default]
end
@@ -159,34 +152,13 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITHOUT"] = nil
end
- 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
- bundle "install --without emo"
-
- bundle :install
- expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- end
-
it "does not install gems from the optional group" do
bundle :install
expect(the_bundle).not_to include_gems "thin 1.0"
end
it "installs gems from the optional group when requested" do
- bundle "config set --local with debugging"
- bundle :install
- expect(the_bundle).to include_gems "thin 1.0"
- end
-
- 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_config "with debugging"
bundle :install
expect(the_bundle).to include_gems "thin 1.0"
end
@@ -198,30 +170,6 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITH"] = nil
end
- 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
- 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
- bundle "config set --local with debugging"
- 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
- expect(last_command).to be_failure
- expect(err).to include("The offending groups are: emo")
- end
-
it "allows the BUNDLE_WITH setting to override BUNDLE_WITHOUT" do
ENV["BUNDLE_WITH"] = "debugging"
@@ -235,20 +183,14 @@ 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
- 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"
- end
-
it "has no effect when listing a not optional group in with" do
- bundle "config set --local with emo"
+ bundle_config "with emo"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
it "has no effect when listing an optional group in without" do
- bundle "config set --local without debugging"
+ bundle_config "without debugging"
bundle :install
expect(the_bundle).not_to include_gems "thin 1.0"
end
@@ -266,13 +208,13 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- bundle "config set --local without emo lolercoaster"
+ bundle_config "without emo lolercoaster"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
end
@@ -294,15 +236,15 @@ RSpec.describe "bundle install with groups" do
end
it "installs the gem unless all groups are excluded" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
- bundle "config set --local without lolercoaster"
+ bundle_config "without lolercoaster"
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
- bundle "config set --local without emo lolercoaster"
+ bundle_config "without emo lolercoaster"
bundle :install
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -327,13 +269,13 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- bundle "config set --local without emo lolercoaster"
+ bundle_config "without emo lolercoaster"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
- bundle "config set --local without emo"
+ bundle_config "without emo"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
end
@@ -365,13 +307,13 @@ RSpec.describe "bundle install with groups" do
end
end
- describe "when locked and installed with `without` option" do
+ describe "when locked and installed with `without` setting" do
before(:each) do
build_repo2
system_gems "myrack-0.9.1"
- bundle "config set --local without myrack"
+ bundle_config "without myrack"
install_gemfile <<-G
source "https://gem.repo2"
gem "myrack"
@@ -382,7 +324,7 @@ RSpec.describe "bundle install with groups" do
G
end
- it "uses the correct versions even if --without was used on the original" do
+ it "uses versions from excluded gems in a machine without the without configuration" do
expect(the_bundle).to include_gems "myrack 0.9.1"
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
simulate_new_machine
@@ -395,9 +337,9 @@ RSpec.describe "bundle install with groups" do
it "does not hit the remote a second time" do
FileUtils.rm_r gem_repo2
- bundle "config set --local without myrack"
+ bundle_config "without myrack"
bundle :install, verbose: true
- expect(last_command.stdboth).not_to match(/fetching/i)
+ expect(stdboth).not_to match(/fetching/i)
end
end
end
diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb
index 170b58c4c0..05a6d15129 100644
--- a/spec/bundler/install/gemfile/install_if_spec.rb
+++ b/spec/bundler/install/gemfile/install_if_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe "bundle install with install_if conditionals" do
thin
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/install/gemfile/lockfile_spec.rb b/spec/bundler/install/gemfile/lockfile_spec.rb
index ee747c05de..19bd7074b2 100644
--- a/spec/bundler/install/gemfile/lockfile_spec.rb
+++ b/spec/bundler/install/gemfile/lockfile_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "bundle install with a lockfile present" do
context "with plugins disabled" do
before do
- bundle "config set plugins false"
+ bundle_config "plugins false"
end
it "does not evaluate the gemfile twice when the gem is already installed" do
diff --git a/spec/bundler/install/gemfile/override_spec.rb b/spec/bundler/install/gemfile/override_spec.rb
new file mode 100644
index 0000000000..02b0e7d772
--- /dev/null
+++ b/spec/bundler/install/gemfile/override_spec.rb
@@ -0,0 +1,401 @@
+# frozen_string_literal: true
+
+RSpec.describe "override DSL" do
+ context "with a version: string operation" do
+ it "replaces a direct dependency requirement with the override version spec" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems "myrack 0.9.1"
+ end
+
+ it "replaces a transitive dependency requirement" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 1.0.0"
+ gem "myrack_middleware"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0", "myrack_middleware 1.0"
+ end
+
+ it "replaces the requirement even when the Gemfile pins a different version" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack", "= 1.0.0"
+ G
+
+ expect(the_bundle).to include_gems "myrack 0.9.1"
+ end
+
+ it "applies the override against an existing lockfile" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack"
+ G
+
+ bundle :install
+
+ expect(the_bundle).to include_gems "myrack 0.9.1"
+ end
+
+ it "pins a prerelease version that the Gemfile dependency would otherwise filter out" do
+ build_repo2 do
+ build_gem "has_prerelease", "1.0"
+ build_gem "has_prerelease", "1.1.pre"
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override "has_prerelease", version: "= 1.1.pre"
+ gem "has_prerelease"
+ G
+
+ expect(the_bundle).to include_gems "has_prerelease 1.1.pre"
+ end
+ end
+
+ context "with a version: :ignore_upper operation" do
+ it "strips a < upper bound on a direct dependency" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: :ignore_upper
+ gem "myrack", "< 1.0"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "folds ~> into >= so newer versions become reachable" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: :ignore_upper
+ gem "myrack", "~> 0.9.1"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+ end
+
+ context "with a version: nil operation" do
+ it "drops a direct dependency's pin entirely" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: nil
+ gem "myrack", "= 0.9.1"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "drops a transitive dependency's pin entirely" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: nil
+ gem "myrack_middleware"
+ G
+
+ expect(the_bundle).to include_gems "myrack 1.0.0", "myrack_middleware 1.0"
+ end
+
+ it "applies a transitive-only override against an existing lockfile" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack_middleware"
+ G
+
+ expect(the_bundle).to include_gems "myrack 0.9.1", "myrack_middleware 1.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 1.0.0"
+ gem "myrack_middleware"
+ G
+
+ bundle :install
+
+ expect(the_bundle).to include_gems "myrack 1.0.0", "myrack_middleware 1.0"
+ end
+ end
+
+ context "lockfile contents" do
+ it "does not record the override directive in Gemfile.lock" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ override "myrack", version: "= 0.9.1"
+ gem "myrack"
+ G
+
+ expect(lockfile).not_to match(/override/i)
+ end
+ end
+
+ context "with a required_ruby_version: operation" do
+ it "lets the resolver pick a gem whose required_ruby_version excludes the current Ruby with :ignore_upper" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: :ignore_upper
+ gem "needs_old_ruby"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby (1.0)")
+ end
+
+ it "lets the resolver pick the gem with required_ruby_version: nil" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: nil
+ gem "needs_old_ruby"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby (1.0)")
+ end
+
+ it "applies to a transitive dependency's required_ruby_version" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "wraps_old", "1.0" do |s|
+ s.add_dependency "needs_old_ruby"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: :ignore_upper
+ gem "wraps_old"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby (1.0)")
+ expect(lockfile).to include("wraps_old (1.0)")
+ end
+
+ it "re-resolves a direct dep when a metadata override is added against an existing lockfile" do
+ build_repo2 do
+ build_gem "selectable", "1.0"
+ build_gem "selectable", "2.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "selectable"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("selectable (1.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "selectable", required_ruby_version: :ignore_upper
+ gem "selectable"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("selectable (2.0)")
+ end
+ end
+
+ context "with a required_rubygems_version: operation" do
+ it "lets the resolver pick a gem whose required_rubygems_version excludes the current RubyGems with :ignore_upper" do
+ build_repo2 do
+ build_gem "needs_old_rubygems", "1.0" do |s|
+ s.required_rubygems_version = "< #{Gem.rubygems_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_rubygems", required_rubygems_version: :ignore_upper
+ gem "needs_old_rubygems"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_rubygems (1.0)")
+ end
+ end
+
+ context "with an :all target" do
+ it "applies required_ruby_version: :ignore_upper to every gem" do
+ build_repo2 do
+ build_gem "needs_old_ruby_a", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "needs_old_ruby_b", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ gem "needs_old_ruby_a"
+ gem "needs_old_ruby_b"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("needs_old_ruby_a (1.0)")
+ expect(lockfile).to include("needs_old_ruby_b (1.0)")
+ end
+
+ it "is overridden by a per-gem override on the same field" do
+ build_repo2 do
+ build_gem "permissive", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "still_blocked", "1.0" do |s|
+ s.required_ruby_version = "= #{Gem.ruby_version}.999"
+ end
+ end
+
+ # :all says ignore_upper (would unblock both), but per-gem on
+ # still_blocked nails it to a hard requirement that still fails.
+ gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ override "still_blocked", required_ruby_version: "= #{Gem.ruby_version}.999"
+ gem "permissive"
+ gem "still_blocked"
+ G
+
+ bundle :lock, raise_on_error: false
+ expect(err).to include("still_blocked")
+ end
+
+ it "preserves locked versions when an :all metadata override is added without bundle update" do
+ build_repo2 do
+ build_gem "selectable", "1.0"
+ build_gem "selectable", "2.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "selectable"
+ G
+
+ bundle :lock
+ expect(lockfile).to include("selectable (1.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ gem "selectable"
+ G
+
+ # :all override alone does not pre-unlock locked specs; narrow change
+ # should not trigger unrelated lockfile churn.
+ bundle :lock
+ expect(lockfile).to include("selectable (1.0)")
+
+ # bundle update opts the user into re-resolution under the override.
+ bundle "update selectable"
+ expect(lockfile).to include("selectable (2.0)")
+ end
+ end
+
+ context "diagnostic on resolve failure" do
+ it "lists active overrides with their Gemfile location" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "= #{Gem.ruby_version}.999"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: "= #{Gem.ruby_version}.999"
+ gem "needs_old_ruby"
+ G
+
+ bundle :lock, raise_on_error: false
+ expect(err).to include("Bundler applied the following overrides")
+ expect(err).to include("override \"needs_old_ruby\", required_ruby_version:")
+ expect(err).to match(/declared at Gemfile:\d+/)
+ end
+ end
+
+ context "install-time compatibility" do
+ it "installs a gem whose required_ruby_version excludes the current Ruby when an override removes the constraint" do
+ build_repo2 do
+ build_gem "needs_old_ruby", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_ruby", required_ruby_version: nil
+ gem "needs_old_ruby"
+ G
+
+ expect(the_bundle).to include_gems "needs_old_ruby 1.0"
+ end
+
+ it "installs a gem whose required_rubygems_version excludes the current RubyGems when an override removes it" do
+ build_repo2 do
+ build_gem "needs_old_rubygems", "1.0" do |s|
+ s.required_rubygems_version = "< #{Gem.rubygems_version}"
+ end
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override "needs_old_rubygems", required_rubygems_version: nil
+ gem "needs_old_rubygems"
+ G
+
+ expect(the_bundle).to include_gems "needs_old_rubygems 1.0"
+ end
+
+ it "installs every gem when :all required_ruby_version override is in effect" do
+ build_repo2 do
+ build_gem "needs_old_ruby_a", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ build_gem "needs_old_ruby_b", "1.0" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ override :all, required_ruby_version: :ignore_upper
+ gem "needs_old_ruby_a"
+ gem "needs_old_ruby_b"
+ G
+
+ expect(the_bundle).to include_gems "needs_old_ruby_a 1.0", "needs_old_ruby_b 1.0"
+ end
+ end
+end
diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb
index 7525404b24..b069488531 100644
--- a/spec/bundler/install/gemfile/path_spec.rb
+++ b/spec/bundler/install/gemfile/path_spec.rb
@@ -1,22 +1,10 @@
# frozen_string_literal: true
RSpec.describe "bundle install with explicit source paths" do
- it "fetches gems with a global path source", bundler: "< 3" do
- build_lib "foo"
-
- install_gemfile <<-G
- path "#{lib_path("foo-1.0")}"
- gem 'foo'
- G
-
- expect(the_bundle).to include_gems("foo 1.0")
- end
-
it "fetches gems" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -29,7 +17,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
@@ -42,7 +29,6 @@ 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"
gem 'foo', :path => "#{relative_path}"
G
@@ -55,7 +41,6 @@ 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"
gem 'foo', :path => "~/#{relative_path}"
G
@@ -70,7 +55,6 @@ RSpec.describe "bundle install with explicit source paths" do
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"
gem 'foo', :path => "~#{username}/#{relative_path}"
G
expect(err).to match("There was an error while trying to use the path `~#{username}/#{relative_path}`.")
@@ -81,7 +65,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo", path: bundled_app("foo-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
gem 'foo', :path => "./foo-1.0"
G
@@ -126,7 +109,7 @@ RSpec.describe "bundle install with explicit source paths" do
demo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install, dir: lib_path("demo")
@@ -139,11 +122,10 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo", path: bundled_app("foo-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
gem 'foo', :path => File.expand_path("foo-1.0", __dir__)
G
- bundle "config set --local frozen true"
+ bundle_config "frozen true"
bundle :install
end
@@ -159,7 +141,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
gem "foo", :path => "#{lib_path("nested")}"
G
@@ -179,7 +160,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo", "1.0.0", path: lib_path("omg/foo")
install_gemfile <<-G
- source "https://gem.repo1"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -256,7 +236,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "omg", "2.0", path: lib_path("omg")
install_gemfile <<-G
- source "https://gem.repo1"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -280,7 +259,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
gem "premailer", :path => "#{lib_path("premailer")}"
G
@@ -302,11 +280,9 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
- expect(err).to_not include("Your Gemfile has no gem server sources.")
expect(err).to match(/is not valid. Please fix this gemspec./)
expect(err).to match(/The validation error was 'missing value for attribute version'/)
expect(err).to match(/You have one or more invalid gemspecs that need to be fixed/)
@@ -370,7 +346,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_path, original_lockfile
@@ -440,7 +416,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
gemspec :path => "#{lib_path("foo")}"
G
@@ -454,7 +429,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
gemspec :path => "#{lib_path("foo")}", :name => "foo"
G
@@ -467,7 +441,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -481,11 +454,10 @@ RSpec.describe "bundle install with explicit source paths" do
it "handles directories in bin/" do
build_lib "foo"
- lib_path("foo-1.0").join("foo.gemspec").rmtree
+ FileUtils.rm_rf lib_path("foo-1.0").join("foo.gemspec")
lib_path("foo-1.0").join("bin/performance").mkpath
install_gemfile <<-G
- source "https://gem.repo1"
gem 'foo', '1.0', :path => "#{lib_path("foo-1.0")}"
G
expect(err).to be_empty
@@ -495,7 +467,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
@@ -508,7 +479,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "hi2u"
install_gemfile <<-G
- source "https://gem.repo1"
path "#{lib_path}" do
gem "omg"
gem "hi2u"
@@ -527,7 +497,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
gem "foo", :path => "#{lib_path("foo")}"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -539,7 +508,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo", gemspec: false
gemfile <<-G
- source "https://gem.repo1"
gem "foo", "1.0", :path => "#{lib_path("foo-1.0")}"
G
@@ -553,15 +521,11 @@ RSpec.describe "bundle install with explicit source paths" do
PATH
remote: vendor/bar
specs:
-
- GEM
- remote: http://rubygems.org/
L
FileUtils.mkdir_p(bundled_app("vendor/bar"))
install_gemfile <<-G
- source "http://rubygems.org"
gem "bar", "1.0.0", path: "vendor/bar", require: "bar/nyard"
G
end
@@ -606,7 +570,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -622,7 +585,6 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "bar", "1.0", path: lib_path("foo/bar")
install_gemfile <<-G
- source "https://gem.repo1"
gem "foo", :path => "#{lib_path("foo")}"
G
end
@@ -699,7 +661,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
build_lib "foo", "1.0", path: lib_path("foo") do |s|
@@ -727,7 +689,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(the_bundle).to include_gems "myrack 0.9.1"
@@ -766,7 +728,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
build_lib "foo", "1.0", path: lib_path("foo") do |s|
@@ -799,7 +761,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(the_bundle).to include_gems "myrack 0.9.1"
@@ -827,7 +789,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -853,11 +815,60 @@ RSpec.describe "bundle install with explicit source paths" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
+ context "when platform specific version locked, and having less dependencies that the generic version that's actually installed" do
+ before do
+ build_repo4 do
+ build_gem "racc", "1.8.1"
+ build_gem "mini_portile2", "2.8.2"
+ end
+
+ build_lib "nokogiri", "1.18.9", path: lib_path("nokogiri") do |s|
+ s.add_dependency "mini_portile2", "~> 2.8.2"
+ s.add_dependency "racc", "~> 1.4"
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "nokogiri", path: "#{lib_path("nokogiri")}"
+ G
+
+ lockfile <<~L
+ PATH
+ remote: #{lib_path("nokogiri")}
+ specs:
+ nokogiri (1.18.9)
+ mini_portile2 (~> 2.8.2)
+ racc (~> 1.4)
+ nokogiri (1.18.9-arm64-darwin)
+ racc (~> 1.4)
+
+ GEM
+ remote: https://rubygems.org/
+ specs:
+ racc (1.8.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ nokogiri!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "works" do
+ bundle "install"
+ 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|
@@ -869,12 +880,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
gem "bar", :git => "#{lib_path("bar")}"
G
install_gemfile <<-G
- source "https://gem.repo1"
gem "bar", :path => "#{lib_path("bar")}"
G
@@ -929,7 +938,6 @@ RSpec.describe "bundle install with explicit source paths" do
it "runs pre-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -949,7 +957,6 @@ RSpec.describe "bundle install with explicit source paths" do
it "runs post-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -969,7 +976,6 @@ RSpec.describe "bundle install with explicit source paths" do
it "complains if the install hook fails" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1000,7 +1006,6 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://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 d517c12125..e12933ebcf 100644
--- a/spec/bundler/install/gemfile/platform_spec.rb
+++ b/spec/bundler/install/gemfile/platform_spec.rb
@@ -65,7 +65,7 @@ RSpec.describe "bundle install across platforms" do
platform_specific
G
- bundle "config set --local frozen true"
+ bundle_config "frozen true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -161,8 +161,8 @@ RSpec.describe "bundle install across platforms" do
expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
- pristine_system_gems :bundler
- bundle "config set --local force_ruby_platform true"
+ pristine_system_gems
+ bundle_config "force_ruby_platform true"
bundle "install"
expect(the_bundle).to include_gems "nokogiri 1.4.2"
@@ -235,7 +235,7 @@ RSpec.describe "bundle install across platforms" do
pry
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --add-platform ruby"
@@ -269,7 +269,7 @@ RSpec.describe "bundle install across platforms" do
pry
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
expect(lockfile).to eq good_lockfile
@@ -365,7 +365,7 @@ RSpec.describe "bundle install across platforms" do
gem "myrack", "1.0.0"
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
FileUtils.mv(vendored_gems, bundled_app("vendor/bundle", Gem.ruby_engine, "1.8"))
@@ -394,7 +394,7 @@ RSpec.describe "bundle install across platforms" do
#{checksums}
G
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -420,7 +420,7 @@ RSpec.describe "bundle install across platforms" do
platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
@@ -486,7 +486,7 @@ RSpec.describe "bundle install with platform conditionals" do
tzinfo (~> 1.2)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -542,7 +542,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not attempt to install gems from :rbx when using --local" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
@@ -554,7 +554,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not attempt to install gems from other rubies when using --local" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
gem "some_gem", platform: :ruby_22
@@ -565,7 +565,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not print a warning when a dependency is unused on a platform different from the current one" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
gemfile <<-G
source "https://gem.repo1"
@@ -589,12 +589,12 @@ RSpec.describe "bundle install with platform conditionals" do
myrack
#{checksums_section_when_enabled}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
it "resolves fine when a dependency is unused on a platform different from the current one, but reintroduced transitively" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
build_repo4 do
build_gem "listen", "3.7.1" do |s|
diff --git a/spec/bundler/install/gemfile/ruby_spec.rb b/spec/bundler/install/gemfile/ruby_spec.rb
index 3e15d82bbe..d937abd714 100644
--- a/spec/bundler/install/gemfile/ruby_spec.rb
+++ b/spec/bundler/install/gemfile/ruby_spec.rb
@@ -83,10 +83,10 @@ RSpec.describe "ruby requirement" do
myrack
RUBY VERSION
- ruby 2.1.4p422
+ ruby 2.1.4
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index e1a5245800..654d638e1f 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -4,153 +4,6 @@ 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
- context "without source affinity" do
- before do
- # Oh no! Someone evil is trying to hijack myrack :(
- # 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'"
- end
- end
- end
-
- context "with multiple toplevel sources" do
- let(:repo3_myrack_version) { "1.0.0" }
-
- before do
- gemfile <<-G
- source "https://gem.repo3"
- source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack"
- 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)
-
- 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
- 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
- end
- end
-
- context "when different versions of the same gem are in multiple sources" do
- let(:repo3_myrack_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
- 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.")
- 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 "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
@@ -189,7 +42,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/myrack-obama-1.0.gem")).to exist
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0")
@@ -313,189 +166,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
end
end
-
- context "and in yet another source" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo2"
- source "https://gem.repo3" do
- gem "depends_on_myrack"
- 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.")
- 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)
-
- 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(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"
-
- 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(lockfile).to eq(previous_lockfile)
- 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 "and only the dependency is pinned" 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'"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo3" # contains depends_on_myrack
- source "https://gem.repo2" # contains broken myrack
-
- gem "depends_on_myrack" # installed from gem_repo3
- gem "myrack", :source => "https://gem.repo1"
- G
- end
-
- 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")
-
- # In https://github.com/rubygems/bundler/issues/3585 this failed
- # when there is already a lockfile, and the gems are missing, so try again
- system_gems []
- 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")
- 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
end
context "when a top-level gem can only be found in an scoped source" do
@@ -524,39 +194,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- 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_gem "depends_on_missing", "1.0.1" do |s|
- s.add_dependency "missing"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo2"
-
- source "https://gem.repo3"
-
- gem "depends_on_missing"
- G
- end
-
- it "fails" do
- 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.
- So, because Gemfile depends on depends_on_missing >= 0,
- version solving has failed.
- E
- end
- end
-
context "when a top-level gem has an indirect dependency" do
before do
build_repo gem_repo2 do
@@ -714,337 +351,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when the lockfile has aggregated rubygems sources and newer versions of dependencies are available" do
- before do
- build_repo gem_repo2 do
- build_gem "activesupport", "6.0.3.4" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
- s.add_dependency "i18n", ">= 0.7", "< 2"
- s.add_dependency "minitest", "~> 5.1"
- s.add_dependency "tzinfo", "~> 1.1"
- s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2"
- end
-
- build_gem "activesupport", "6.1.2.1" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
- s.add_dependency "i18n", ">= 1.6", "< 2"
- s.add_dependency "minitest", ">= 5.1"
- s.add_dependency "tzinfo", "~> 2.0"
- s.add_dependency "zeitwerk", "~> 2.3"
- end
-
- build_gem "concurrent-ruby", "1.1.8"
- build_gem "concurrent-ruby", "1.1.9"
- build_gem "connection_pool", "2.2.3"
-
- build_gem "i18n", "1.8.9" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0"
- end
-
- build_gem "minitest", "5.14.3"
- build_gem "myrack", "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 "redis", ">= 4.2.0"
- end
-
- build_gem "thread_safe", "0.3.6"
-
- build_gem "tzinfo", "1.2.9" do |s|
- s.add_dependency "thread_safe", "~> 0.1"
- end
-
- build_gem "tzinfo", "2.0.4" do |s|
- s.add_dependency "concurrent-ruby", "~> 1.0"
- end
-
- build_gem "zeitwerk", "2.4.2"
- end
-
- build_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"
- end
- end
-
- gemfile <<-G
- # frozen_string_literal: true
-
- source "https://gem.repo2"
-
- gem "activesupport"
-
- source "https://gem.repo3" do
- gem "sidekiq-pro"
- 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/
- remote: https://gem.repo3/
- specs:
- activesupport (6.0.3.4)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- concurrent-ruby (1.1.8)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
- thread_safe (0.3.6)
- tzinfo (1.2.9)
- thread_safe (~> 0.1)
- zeitwerk (2.4.2)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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"
- expect(err).to be_empty
-
- expect(the_bundle).to include_gems("activesupport 6.0.3.4")
- expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
- expect(the_bundle).to include_gems("tzinfo 1.2.9")
- expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
- expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
- expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- activesupport (6.0.3.4)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- concurrent-ruby (1.1.8)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- thread_safe (0.3.6)
- tzinfo (1.2.9)
- thread_safe (~> 0.1)
- zeitwerk (2.4.2)
-
- GEM
- remote: https://gem.repo3/
- specs:
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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
- initial_lockfile = lockfile
-
- bundle "config set --local frozen true"
- bundle :install, artifice: "compact_index"
-
- expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
-
- expect(the_bundle).to include_gems("activesupport 6.0.3.4")
- expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
- expect(the_bundle).to include_gems("tzinfo 1.2.9")
- expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
- expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
- expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
-
- expect(lockfile).to eq(initial_lockfile)
- end
-
- 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
-
- expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
-
- expect(lockfile).to eq(initial_lockfile)
- end
-
- it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
- 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
- remote: https://gem.repo2/
- specs:
- activesupport (6.1.2.1)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 1.6, < 2)
- minitest (>= 5.1)
- tzinfo (~> 2.0)
- zeitwerk (~> 2.3)
- concurrent-ruby (1.1.9)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- tzinfo (2.0.4)
- concurrent-ruby (~> 1.0)
- zeitwerk (2.4.2)
-
- GEM
- remote: https://gem.repo3/
- specs:
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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"
- expect(err).to be_empty
-
- expect(the_bundle).to include_gems("activesupport 6.0.3.4")
- expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
- expect(the_bundle).to include_gems("tzinfo 1.2.9")
- expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
- 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/
- specs:
- activesupport (6.0.3.4)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 0.7, < 2)
- minitest (~> 5.1)
- tzinfo (~> 1.1)
- zeitwerk (~> 2.2, >= 2.2.2)
- concurrent-ruby (1.1.9)
- connection_pool (2.2.3)
- i18n (1.8.9)
- concurrent-ruby (~> 1.0)
- minitest (5.14.3)
- myrack (2.2.3)
- redis (4.2.5)
- sidekiq (6.1.3)
- connection_pool (>= 2.2.2)
- myrack (~> 2.0)
- redis (>= 4.2.0)
- thread_safe (0.3.6)
- tzinfo (1.2.9)
- thread_safe (~> 0.1)
- zeitwerk (2.4.2)
-
- GEM
- remote: https://gem.repo3/
- specs:
- sidekiq-pro (5.2.1)
- connection_pool (>= 2.2.3)
- sidekiq (>= 6.1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- activesupport
- sidekiq-pro!
- #{@locked_checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
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")
@@ -1134,7 +440,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose", artifice: "compact_index"
@@ -1207,112 +513,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "with a lockfile with aggregated rubygems sources" do
- let(:aggregate_gem_section_lockfile) do
- <<~L
- GEM
- remote: https://gem.repo1/
- remote: https://gem.repo3/
- specs:
- myrack (0.9.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- let(:split_gem_section_lockfile) do
- <<~L
- GEM
- remote: https://gem.repo1/
- specs:
-
- GEM
- remote: https://gem.repo3/
- specs:
- myrack (0.9.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- before do
- build_repo3 do
- build_gem "myrack", "0.9.1"
- end
-
- gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo3" do
- gem 'myrack'
- 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
- bundle "config set --local deployment true"
- bundle "config set --local disable_checksum_validation true"
-
- 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
- end
-
- it "refuses to install the existing lockfile and prints an error", bundler: "3" do
- bundle "config set --local deployment true"
-
- bundle "install", artifice: "compact_index", raise_on_error: false
-
- 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(out).to be_empty
- end
- end
-
context "with a path gem in the same Gemfile" do
before do
build_lib "foo"
@@ -1366,11 +566,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
gem 'bar', '~> 0.1', :source => 'https://gem.repo4'
G
- bundle "config set --local path ../gems/system"
+ bundle_config "path ../gems/system"
bundle :install, artifice: "compact_index"
# And then we add some new versions...
- update_repo4 do
+ build_repo4 do
build_gem "foo", "0.2"
build_gem "bar", "0.3"
end
@@ -1583,38 +783,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
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
- it "succeeds but warns, suggesting a source block" do
- build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
- end
- build_gem "myrack"
- 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"
- end
-
- source "https://scoped.source" 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/
- 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
- expect(the_bundle).to be_locked
- 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" do
it "raises, suggesting a source block" do
build_repo4 do
build_gem "depends_on_myrack" do |s|
@@ -1645,83 +814,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when upgrading a lockfile suffering from dependency confusion" do
- before do
- build_repo4 do
- build_gem "mime-types", "3.0.0"
- end
-
- build_repo2 do
- build_gem "capybara", "2.5.0" do |s|
- s.add_dependency "mime-types", ">= 1.16"
- end
-
- build_gem "mime-types", "3.3.1"
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "capybara", "~> 2.5.0"
-
- source "https://gem.repo4" do
- gem "mime-types", "~> 3.0"
- end
- G
-
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- remote: https://gem.repo4/
- specs:
- capybara (2.5.0)
- mime-types (>= 1.16)
- mime-types (3.3.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- 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
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- capybara (2.5.0)
- mime-types (>= 1.16)
-
- GEM
- remote: https://gem.repo4/
- specs:
- mime-types (3.0.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- capybara (~> 2.5.0)
- mime-types (~> 3.0)!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
context "when default source includes old gems with nil required_ruby_version" do
before do
build_repo2 do
@@ -1775,7 +867,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
ruport (= 1.7.0.3)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1833,7 +925,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
ruport (= 1.7.0.3)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1878,7 +970,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
pdf-writer (= 1.1.8)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1946,7 +1038,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1987,4 +1079,235 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq original_lockfile.gsub("bigdecimal (1.0.0)", "bigdecimal (3.3.1)")
end
end
+
+ context "when switching a gem with components from rubygems to git source" do
+ before do
+ build_repo2 do
+ build_gem "rails", "7.0.0" do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+ build_gem "actionpack", "7.0.0"
+ build_gem "activerecord", "7.0.0"
+ # propshaft also depends on actionpack, creating the conflict
+ build_gem "propshaft", "1.0.0" do |s|
+ s.add_dependency "actionpack", ">= 7.0.0"
+ end
+ end
+
+ build_git "rails", "7.0.0", path: lib_path("rails") do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+
+ build_git "actionpack", "7.0.0", path: lib_path("rails")
+ build_git "activerecord", "7.0.0", path: lib_path("rails")
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", "7.0.0"
+ gem "propshaft"
+ G
+ end
+
+ it "moves component gems to the git source in the lockfile" do
+ expect(lockfile).to include("remote: https://gem.repo2")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+ expect(lockfile).to include("propshaft (1.0.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", git: "#{lib_path("rails")}"
+ gem "propshaft"
+ G
+
+ bundle "install"
+
+ expect(lockfile).to include("remote: #{lib_path("rails")}")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+
+ # Component gems should NOT remain in the GEM section
+ # Extract just the GEM section by splitting on GIT first, then GEM
+ gem_section = lockfile.split("GEM\n").last.split(/\n(PLATFORMS|DEPENDENCIES)/)[0]
+ expect(gem_section).not_to include("actionpack (7.0.0)")
+ expect(gem_section).not_to include("activerecord (7.0.0)")
+ end
+ end
+
+ context "when switching a gem with components from rubygems to path source" do
+ before do
+ build_repo2 do
+ build_gem "rails", "7.0.0" do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+ build_gem "actionpack", "7.0.0"
+ build_gem "activerecord", "7.0.0"
+ # propshaft also depends on actionpack, creating the conflict
+ build_gem "propshaft", "1.0.0" do |s|
+ s.add_dependency "actionpack", ">= 7.0.0"
+ end
+ end
+
+ build_lib "rails", "7.0.0", path: lib_path("rails") do |s|
+ s.add_dependency "actionpack", "7.0.0"
+ s.add_dependency "activerecord", "7.0.0"
+ end
+
+ build_lib "actionpack", "7.0.0", path: lib_path("rails")
+ build_lib "activerecord", "7.0.0", path: lib_path("rails")
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", "7.0.0"
+ gem "propshaft"
+ G
+ end
+
+ it "moves component gems to the path source in the lockfile" do
+ expect(lockfile).to include("remote: https://gem.repo2")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+ expect(lockfile).to include("propshaft (1.0.0)")
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "rails", path: "#{lib_path("rails")}"
+ gem "propshaft"
+ G
+
+ bundle "install"
+
+ expect(lockfile).to include("remote: #{lib_path("rails")}")
+ expect(lockfile).to include("rails (7.0.0)")
+ expect(lockfile).to include("actionpack (7.0.0)")
+ expect(lockfile).to include("activerecord (7.0.0)")
+
+ # Component gems should NOT remain in the GEM section
+ # Extract just the GEM section by splitting appropriately
+ gem_section = lockfile.split("GEM\n").last.split(/\n(PLATFORMS|DEPENDENCIES)/)[0]
+ expect(gem_section).not_to include("actionpack (7.0.0)")
+ expect(gem_section).not_to include("activerecord (7.0.0)")
+ end
+ end
+
+ context "when a scoped rubygems source is missing a transitive dependency" do
+ before do
+ build_repo2 do
+ build_gem "fallback_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_repo3 do
+ build_gem "private_parent", "1.0.0" do |s|
+ s.add_dependency "fallback_dep"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ source "https://gem.repo3" do
+ gem "private_parent", "1.0.0"
+ end
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("private_parent 1.0.0", "fallback_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("private_parent 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("fallback_dep 1.0.0", source: "remote2")
+ end
+ end
+
+ context "when a path gem has a transitive dependency that does not exist in the path source" do
+ before do
+ build_repo2 do
+ build_gem "missing_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_lib "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s|
+ s.add_dependency "missing_dep"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ gem "parent_gem", path: "#{lib_path("parent_gem")}"
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency when updating" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "path@#{lib_path("parent_gem")}")
+ expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2")
+ end
+ end
+
+ context "when a git gem has a transitive dependency that does not exist in the git source" do
+ before do
+ build_repo2 do
+ build_gem "missing_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_git "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s|
+ s.add_dependency "missing_dep"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ gem "parent_gem", git: "#{lib_path("parent_gem")}"
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency when updating" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "git@#{lib_path("parent_gem")}")
+ expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2")
+ end
+ end
end
diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb
index 7f147adcb0..97b1d233bf 100644
--- a/spec/bundler/install/gemfile/specific_platform_spec.rb
+++ b/spec/bundler/install/gemfile/specific_platform_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe "bundle install with specific platforms" do
sass-embedded
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -70,7 +70,7 @@ RSpec.describe "bundle install with specific platforms" do
setup_multiplatform_gem
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile(google_protobuf)
@@ -88,11 +88,11 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
# force strict usage of the lockfile by setting frozen mode
- bundle "config set --local frozen true"
+ bundle_config "frozen true"
# 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")
@@ -104,7 +104,7 @@ RSpec.describe "bundle install with specific platforms" do
setup_multiplatform_gem
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
gemfile google_protobuf
@@ -126,7 +126,7 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -151,12 +151,17 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
context "when running on a legacy lockfile locked only to ruby" do
+ # Exercises the legacy lockfile path (use_exact_resolved_specifications? = false)
+ # because most_specific_locked_platform is ruby, matching the generic platform.
+ # Key insight: when target (arm64-darwin-22) != platform (ruby), the code tries
+ # both platforms before falling back, preserving lockfile integrity.
+
around do |example|
build_repo4 do
build_gem "nokogiri", "1.3.10"
@@ -185,20 +190,76 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
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")
+ bundle "install"
+ expect(the_bundle).to include_gem("nokogiri 1.3.10")
+ expect(the_bundle).not_to include_gem("nokogiri 1.3.10 arm64-darwin")
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")
+ bundle "install", env: { "BUNDLE_FROZEN" => "true" }
+ expect(the_bundle).to include_gem("nokogiri 1.3.10")
+ expect(the_bundle).not_to include_gem("nokogiri 1.3.10 arm64-darwin")
+ end
+ end
+
+ context "when platform-specific gem has incompatible required_ruby_version" do
+ # Key insight: candidate_platforms tries [target, platform, ruby] in order.
+ # Ruby platform is last since it requires compilation, but works when
+ # precompiled gems are incompatible with the current Ruby version.
+ #
+ # Note: This fix requires the lockfile to include both ruby and platform-
+ # specific variants (typical after `bundle lock --add-platform`). If the
+ # lockfile only has platform-specific gems, frozen mode cannot help because
+ # Bundler.setup would still expect the locked (incompatible) gem.
+
+ # Exercises the exact spec path (use_exact_resolved_specifications? = true)
+ # because lockfile has platform-specific entry as most_specific_locked_platform
+ it "falls back to ruby platform in frozen mode when lockfile includes both variants" do
+ build_repo4 do
+ build_gem "nokogiri", "1.18.10"
+ build_gem "nokogiri", "1.18.10" do |s|
+ s.platform = "x86_64-linux"
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "nokogiri"
+ G
+
+ # Lockfile has both ruby and platform-specific gem (typical after `bundle lock --add-platform`)
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ nokogiri (1.18.10)
+ nokogiri (1.18.10-x86_64-linux)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "install", env: { "BUNDLE_FROZEN" => "true" }
+ expect(the_bundle).to include_gem("nokogiri 1.18.10")
+ expect(the_bundle).not_to include_gem("nokogiri 1.18.10 x86_64-linux")
+ end
end
end
@@ -214,7 +275,7 @@ RSpec.describe "bundle install with specific platforms" do
end
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
gemfile <<-G
source "https://gem.repo2"
@@ -235,7 +296,7 @@ RSpec.describe "bundle install with specific platforms" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -273,7 +334,7 @@ RSpec.describe "bundle install with specific platforms" do
grpc
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose", artifice: "compact_index_precompiled_before"
@@ -298,7 +359,7 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
gemfile(google_protobuf)
- bundle "config set --local cache_all_platforms true"
+ bundle_config "cache_all_platforms true"
bundle "cache"
expect(cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")).to exist
@@ -333,10 +394,9 @@ RSpec.describe "bundle install with specific platforms" do
pg_array_parser!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
- bundle "config set --local cache_all true"
bundle "cache --all-platforms"
expect(err).to be_empty
@@ -367,12 +427,12 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
install_gemfile(google_protobuf)
- bundle "lock --add-platform=x64-mingw32"
+ bundle "lock --add-platform=x64-mingw-ucrt"
- expect(the_bundle.locked_platforms).to include("x64-mingw32", "universal-darwin")
+ expect(the_bundle.locked_platforms).to include("x64-mingw-ucrt", "universal-darwin")
expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(*%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
+ google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw-ucrt
])
end
end
@@ -392,7 +452,23 @@ RSpec.describe "bundle install with specific platforms" do
end
end
- it "installs sorbet-static, which does not provide a pure ruby variant, just fine", :truffleruby do
+ it "installs sorbet-static, which does not provide a pure ruby variant, in absence of a lockfile, just fine", :truffleruby do
+ skip "does not apply to Windows" if Gem.win_platform?
+
+ build_repo2 do
+ build_gem("sorbet-static", "0.5.6403") {|s| s.platform = Bundler.local_platform }
+ end
+
+ gemfile <<~G
+ source "https://gem.repo2"
+
+ gem "sorbet-static", "0.5.6403"
+ G
+
+ bundle "install --verbose"
+ end
+
+ it "installs sorbet-static, which does not provide a pure ruby variant, in presence of a lockfile, just fine", :truffleruby do
skip "does not apply to Windows" if Gem.win_platform?
build_repo2 do
@@ -418,7 +494,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static (= 0.5.6403)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -459,6 +535,41 @@ RSpec.describe "bundle install with specific platforms" do
expect(err).to include(error_message).once
end
+ it "shows a platform mismatch hint when the current platform is not in the lockfile's platforms" do
+ build_repo4 do
+ build_gem("sorbet-static", "0.5.6433") {|s| s.platform = "x86_64-linux-musl" }
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "sorbet-static", "0.5.6433"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ sorbet-static (0.5.6433-x86_64-linux-musl)
+
+ PLATFORMS
+ x86_64-linux-musl
+
+ DEPENDENCIES
+ sorbet-static (= 0.5.6433)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-linux" do
+ bundle "install", raise_on_error: false
+ end
+
+ expect(err).to include("Your current platform (x86_64-linux) is not included in the lockfile's platforms (x86_64-linux-musl)")
+ expect(err).to include("bundle lock --add-platform x86_64-linux")
+ end
+
it "does not resolve if the current platform does not match any of available platform specific variants for a transitive dependency" do
build_repo4 do
build_gem("sorbet", "0.5.6433") {|s| s.add_dependency "sorbet-static", "= 0.5.6433" }
@@ -565,7 +676,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -596,7 +707,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -648,7 +759,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "x86_64-darwin-22" do
@@ -670,7 +781,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -717,7 +828,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -748,7 +859,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static-and-runtime
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -792,7 +903,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -821,7 +932,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -866,7 +977,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "update"
@@ -891,7 +1002,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -934,7 +1045,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static (= 0.5.10549)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -953,7 +1064,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static (= 0.5.10549)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -990,7 +1101,7 @@ RSpec.describe "bundle install with specific platforms" do
ibandit (~> 0.7.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock --update i18n"
@@ -1010,7 +1121,7 @@ RSpec.describe "bundle install with specific platforms" do
ibandit (~> 0.7.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1051,7 +1162,7 @@ RSpec.describe "bundle install with specific platforms" do
tzinfo (~> 1.2)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1095,7 +1206,7 @@ RSpec.describe "bundle install with specific platforms" do
tzinfo (~> 1.2)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1138,7 +1249,7 @@ RSpec.describe "bundle install with specific platforms" do
concurrent-ruby
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -1158,7 +1269,7 @@ RSpec.describe "bundle install with specific platforms" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1189,7 +1300,7 @@ RSpec.describe "bundle install with specific platforms" do
my-precompiled-gem
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install
@@ -1234,7 +1345,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri (= 1.14.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle :install
@@ -1258,7 +1369,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri (= 1.14.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1292,7 +1403,7 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -1312,7 +1423,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1328,7 +1439,7 @@ RSpec.describe "bundle install with specific platforms" do
s.platform = "arm-linux"
end
build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x64-mingw32"
+ s.platform = "x64-mingw-ucrt"
end
build_gem "nokogiri", "1.14.0" do |s|
s.platform = "java"
@@ -1374,7 +1485,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<~G
@@ -1411,12 +1522,12 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-static
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{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
+ 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" do
build_repo4 do
build_gem "nokogiri", "1.15.5"
@@ -1466,7 +1577,7 @@ RSpec.describe "bundle install with specific platforms" do
sass-embedded
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1508,7 +1619,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1555,14 +1666,14 @@ RSpec.describe "bundle install with specific platforms" do
rcee_precompiled (= 0.5.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
end
end
- it "adds current musl platform, when there are also gnu variants", rubygems: ">= 3.3.21" do
+ it "adds current musl platform, when there are also gnu variants" do
build_repo4 do
build_gem "rcee_precompiled", "0.5.0" do |s|
s.platform = "x86_64-linux-gnu"
@@ -1602,7 +1713,7 @@ RSpec.describe "bundle install with specific platforms" do
rcee_precompiled (= 0.5.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1640,7 +1751,7 @@ RSpec.describe "bundle install with specific platforms" do
rcee_precompiled (= 0.5.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1669,7 +1780,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
simulate_platform "arm64-darwin-23" do
@@ -1712,7 +1823,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1763,7 +1874,7 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1805,7 +1916,7 @@ RSpec.describe "bundle install with specific platforms" do
google-protobuf (~> 3.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile original_lockfile
@@ -1823,11 +1934,11 @@ RSpec.describe "bundle install with specific platforms" do
build_repo2 do
build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1")
build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86_64-linux" }
- build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x64-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x64-mingw-ucrt" }
build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "universal-darwin" }
build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86_64-linux" }
- build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x64-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x64-mingw-ucrt" }
build_gem("google-protobuf", "3.0.0.alpha.5.0.5")
build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "universal-darwin" }
diff --git a/spec/bundler/install/gemfile_spec.rb b/spec/bundler/install/gemfile_spec.rb
index 0e3b847767..83875a3d0e 100644
--- a/spec/bundler/install/gemfile_spec.rb
+++ b/spec/bundler/install/gemfile_spec.rb
@@ -27,6 +27,35 @@ RSpec.describe "bundle install" do
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
expect(the_bundle).to include_gems "myrack 1.0.0"
end
+
+ it "respects lockfile and BUNDLE_LOCKFILE" do
+ gemfile bundled_app("NotGemfile"), <<-G
+ lockfile "ReallyNotGemfile.lock"
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ bundle :install, gemfile: bundled_app("NotGemfile")
+
+ ENV["BUNDLE_GEMFILE"] = "NotGemfile"
+ ENV["BUNDLE_LOCKFILE"] = "ReallyNotGemfile.lock"
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "respects BUNDLE_LOCKFILE during bundle install" do
+ ENV["BUNDLE_LOCKFILE"] = "ReallyNotGemfile.lock"
+
+ gemfile bundled_app("NotGemfile"), <<-G
+ source "https://gem.repo1"
+ gem 'myrack'
+ G
+
+ bundle :install, gemfile: bundled_app("NotGemfile")
+ expect(bundled_app("ReallyNotGemfile.lock")).to exist
+
+ ENV["BUNDLE_GEMFILE"] = "NotGemfile"
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
end
context "with gemfile set via config" do
@@ -36,7 +65,7 @@ RSpec.describe "bundle install" do
gem 'myrack'
G
- bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
+ bundle_config "gemfile #{bundled_app("NotGemfile")}"
end
it "uses the gemfile to install" do
bundle "install"
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb
index 6f34cbbe85..9db73b84b5 100644
--- a/spec/bundler/install/gems/compact_index_spec.rb
+++ b/spec/bundler/install/gems/compact_index_spec.rb
@@ -95,7 +95,7 @@ RSpec.describe "compact index api" do
G
bundle :install, artifice: "compact_index"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
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"
@@ -132,7 +132,7 @@ RSpec.describe "compact index api" do
bundle :install, artifice: "compact_index"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
@@ -146,7 +146,7 @@ RSpec.describe "compact index api" do
G
bundle "install", artifice: "compact_index"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("foo 1.0")
@@ -302,7 +302,7 @@ RSpec.describe "compact index api" do
end
system_gems %w[myrack-1.0.0 thin-1.0 net_a-1.0], gem_repo: gem_repo2
- bundle "config set --local path.system true"
+ bundle_config "path.system true"
ENV["BUNDLER_SPEC_ALL_REQUESTS"] = <<~EOS.strip
#{source_uri}/versions
#{source_uri}/info/myrack
@@ -313,28 +313,10 @@ RSpec.describe "compact index api" do
gem "myrack"
G
- expect(last_command.stdboth).not_to include "Double checking"
+ expect(stdboth).not_to include "Double checking"
end
- 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"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "compact_index_extra"
- expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
- end
-
- it "fetches again when more dependencies are found in subsequent sources with source blocks" do
+ it "fetches again when more dependencies are found in subsequent sources" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -375,11 +357,13 @@ RSpec.describe "compact index api" do
expect(the_bundle).to include_gems "myrack 1.2"
end
- 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
- # repo and installs it.
+ it "resolves indirect dependencies to the most scoped source that includes them" 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 tries to
+ # use the version in the most scoped source, even if not compatible, and
+ # gives a resolution error
build_repo4 do
build_gem "activesupport", "1.2.0"
build_gem "somegem", "1.0.0" do |s|
@@ -389,14 +373,14 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem 'somegem', '1.0.0'
+ source "#{source_uri}/extra" do
+ gem 'somegem', '1.0.0'
+ end
G
- bundle :install, artifice: "compact_index_extra_api"
+ bundle :install, artifice: "compact_index_extra_api", raise_on_error: false
- expect(the_bundle).to include_gems "somegem 1.0.0"
- expect(the_bundle).to include_gems "activesupport 1.2.3"
+ expect(err).to include("Could not find compatible versions")
end
it "prints API output properly with back deps" do
@@ -471,27 +455,7 @@ RSpec.describe "compact index api" do
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
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "compact_index_extra"
- bundle "config --set local deployment true"
- bundle :install, artifice: "compact_index_extra"
- 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 with blocks" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -507,7 +471,7 @@ RSpec.describe "compact index api" do
G
bundle :install, artifice: "compact_index_extra"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -529,40 +493,6 @@ RSpec.describe "compact index api" do
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs", bundler: "< 3" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --binstubs", artifice: "compact_index"
-
- gembin "myrackup"
- expect(out).to eq("1.0.0")
- end
-
- it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle", artifice: "compact_index"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
- it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle --no-clean", artifice: "compact_index"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
@@ -617,19 +547,6 @@ RSpec.describe "compact index api" do
expect(the_bundle).to include_gems "myrack 1.0.0"
end
- 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"
- G
-
- bundle :install, artifice: "compact_index_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
@@ -742,7 +659,7 @@ RSpec.describe "compact index api" do
gem "myrack"
G
- bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false, artifice: nil
+ bundle :install, env: { "RUBYOPT" => "-I#{bundled_app("broken_ssl")}" }, raise_on_error: false, artifice: nil
expect(err).to include("recompile Ruby").and include("cannot load such file")
end
end
@@ -781,7 +698,7 @@ RSpec.describe "compact index api" do
bundle :install, artifice: "compact_index_forbidden"
ensure
- home(".gemrc").rmtree
+ FileUtils.rm_rf home(".gemrc")
end
end
end
@@ -853,7 +770,7 @@ RSpec.describe "compact index api" do
gem 'myrack', '0.9.1'
G
- update_repo4 do
+ build_repo4 do
build_gem "myrack", "1.0.0"
end
@@ -894,7 +811,7 @@ RSpec.describe "compact index api" do
gem 'myrack', '0.9.1'
G
- update_repo4 do
+ build_repo4 do
build_gem "myrack", "1.0.0"
end
@@ -916,7 +833,7 @@ RSpec.describe "compact index api" do
gem 'myrack', '0.9.1'
G
- update_repo4 do
+ build_repo4 do
build_gem "myrack", "1.0.0"
end
@@ -988,7 +905,7 @@ RSpec.describe "compact index api" do
DEPENDENCIES
#{checksums_section}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1010,11 +927,7 @@ RSpec.describe "compact index api" do
gem "myrack"
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
+ gem_path = default_cache_path.dirname.join("myrack-1.0.0.gem")
expect(exitstatus).to eq(37)
expect(err).to eq <<~E.strip
@@ -1043,7 +956,7 @@ RSpec.describe "compact index api" do
end
it "does not raise when disable_checksum_validation is set" do
- bundle "config set disable_checksum_validation true"
+ bundle_config "disable_checksum_validation true"
install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum"
source "#{source_uri}"
gem "myrack"
@@ -1084,9 +997,16 @@ Running `bundle update rails` should fix the problem.
gem "activemerchant"
end
G
- gem_command "uninstall activemerchant"
+ uninstall_gem("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)
end
+
+ it "handles an API that does not provide checksums info (undocumented, support may get removed)" do
+ install_gemfile <<-G, artifice: "compact_index_no_checksums"
+ source "https://gem.repo1"
+ gem "rake"
+ G
+ end
end
diff --git a/spec/bundler/install/gems/dependency_api_fallback_spec.rb b/spec/bundler/install/gems/dependency_api_fallback_spec.rb
index 42239311e2..c7b0c537e4 100644
--- a/spec/bundler/install/gems/dependency_api_fallback_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_fallback_spec.rb
@@ -3,44 +3,16 @@
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"
- require_relative "../../support/silent_logger"
-
- 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
+ bundle_config "timeout 1"
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}"
+ install_gemfile <<-G, artifice: "endpoint_timeout"
+ source "https://gem.repo1"
gem "myrack"
G
- expect(out).to include("Fetching source index from #{@server_uri}/")
+ expect(out).to include("Fetching source index from https://gem.repo1/")
expect(the_bundle).to include_gems "myrack 1.0.0"
end
end
diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb
index 283f1208f2..32a1b98b6d 100644
--- a/spec/bundler/install/gems/dependency_api_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe "gemcutter's dependency API" do
G
bundle :install, artifice: "endpoint"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "myrack 1.0.0"
@@ -97,7 +97,7 @@ RSpec.describe "gemcutter's dependency API" do
bundle :install, artifice: "endpoint"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
@@ -111,7 +111,7 @@ RSpec.describe "gemcutter's dependency API" do
G
bundle "install", artifice: "endpoint"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("foo 1.0")
@@ -254,25 +254,7 @@ RSpec.describe "gemcutter's dependency API" do
end
end
- 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"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "endpoint_extra"
- expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
- end
-
- it "fetches again when more dependencies are found in subsequent sources using blocks" do
+ it "fetches again when more dependencies are found in subsequent sources" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -313,11 +295,13 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "myrack 1.2"
end
- 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
- # repo and installs it.
+ it "resolves indirect dependencies to the most scoped source that includes them" 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 tries to
+ # use the version in the most scoped source, even if not compatible, and
+ # gives a resolution error
build_repo4 do
build_gem "activesupport", "1.2.0"
build_gem "somegem", "1.0.0" do |s|
@@ -327,14 +311,14 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- source "#{source_uri}/extra"
- gem 'somegem', '1.0.0'
+ source "#{source_uri}/extra" do
+ gem 'somegem', '1.0.0'
+ end
G
- bundle :install, artifice: "endpoint_extra_api"
+ bundle :install, artifice: "compact_index_extra_api", raise_on_error: false
- expect(the_bundle).to include_gems "somegem 1.0.0"
- expect(the_bundle).to include_gems "activesupport 1.2.3"
+ expect(err).to include("Could not find compatible versions")
end
it "prints API output properly with back deps" do
@@ -358,26 +342,7 @@ RSpec.describe "gemcutter's dependency API" do
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
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- build_gem "missing"
-
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- install_gemfile <<-G, artifice: "endpoint_extra_missing"
- source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- 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 when doing back deps" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -397,27 +362,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
- build_repo2 do
- build_gem "back_deps" do |s|
- s.add_dependency "foo"
- end
- FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")]
- end
-
- gemfile <<-G
- source "#{source_uri}"
- source "#{source_uri}/extra"
- gem "back_deps"
- G
-
- bundle :install, artifice: "endpoint_extra"
- bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint_extra"
- 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 with blocks" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -433,7 +378,7 @@ RSpec.describe "gemcutter's dependency API" do
G
bundle :install, artifice: "endpoint_extra"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
bundle "install", artifice: "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -471,40 +416,6 @@ RSpec.describe "gemcutter's dependency API" do
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs", bundler: "< 3" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --binstubs", artifice: "endpoint"
-
- gembin "myrackup"
- expect(out).to eq("1.0.0")
- end
-
- it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle", artifice: "endpoint"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
- it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle "install --path vendor/bundle --no-clean", artifice: "endpoint"
-
- expect(vendored_gems("bin/myrackup")).to exist
- end
-
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
@@ -580,19 +491,6 @@ RSpec.describe "gemcutter's dependency API" do
expect(out).not_to include("#{user}:#{password}")
end
- 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"
- G
-
- bundle :install, artifice: "endpoint_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
@@ -712,7 +610,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "myrack"
G
- bundle :install, artifice: "fail", env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false
+ bundle :install, artifice: "fail", env: { "RUBYOPT" => "-I#{bundled_app("broken_ssl")}" }, raise_on_error: false
expect(err).to include("recompile Ruby").and include("cannot load such file")
end
end
@@ -751,7 +649,7 @@ RSpec.describe "gemcutter's dependency API" do
bundle "install", artifice: "endpoint_marshal_fail"
ensure
- home(".gemrc").rmtree
+ FileUtils.rm_rf home(".gemrc")
end
end
end
diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb
index 522ee6b779..a30b53d6ad 100644
--- a/spec/bundler/install/gems/flex_spec.rb
+++ b/spec/bundler/install/gems/flex_spec.rb
@@ -191,7 +191,7 @@ RSpec.describe "bundle flex_install" do
end
it "discards the locked gems when the Gemfile requires different versions than the lock" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
nice_error = <<~E.strip
Could not find compatible versions
@@ -208,7 +208,7 @@ RSpec.describe "bundle flex_install" do
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"
+ bundle_config "force_ruby_platform true"
bad_error = <<~E.strip
Bundler could not find compatible versions for gem "myrack-obama":
@@ -289,7 +289,7 @@ RSpec.describe "bundle flex_install" do
myrack-obama
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -317,7 +317,7 @@ RSpec.describe "bundle flex_install" do
myrack-obama
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -358,7 +358,7 @@ RSpec.describe "bundle flex_install" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb
index 0855a62b86..8a3a51270a 100644
--- a/spec/bundler/install/gems/fund_spec.rb
+++ b/spec/bundler/install/gems/fund_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe "bundle install" do
context "when gems include a fund URI but `ignore_funding_requests` is configured" do
before do
- bundle "config set ignore_funding_requests true"
+ bundle_config "ignore_funding_requests true"
end
it "does not display the plural fund message after installing" do
diff --git a/spec/bundler/install/gems/gemfile_source_header_spec.rb b/spec/bundler/install/gems/gemfile_source_header_spec.rb
new file mode 100644
index 0000000000..dc35c8d741
--- /dev/null
+++ b/spec/bundler/install/gems/gemfile_source_header_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+RSpec.describe "fetching dependencies with a mirrored source" do
+ let(:mirror) { "https://server.example.org" }
+
+ before do
+ build_repo2
+
+ gemfile <<-G
+ source "#{mirror}"
+ gem 'weakling'
+ G
+
+ bundle_config "mirror.#{mirror} https://gem.repo2"
+ end
+
+ it "sets the 'X-Gemfile-Source' and 'User-Agent' headers and bundles successfully" do
+ bundle :install, artifice: "endpoint_mirror_source"
+
+ expect(out).to include("Installing weakling")
+ expect(out).to include("Bundle complete")
+ expect(the_bundle).to include_gems "weakling 0.0.3"
+ end
+end
diff --git a/spec/bundler/install/gems/mirror_probe_spec.rb b/spec/bundler/install/gems/mirror_probe_spec.rb
new file mode 100644
index 0000000000..564062ccf6
--- /dev/null
+++ b/spec/bundler/install/gems/mirror_probe_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+RSpec.describe "fetching dependencies with a not available mirror" do
+ before do
+ build_repo2
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem 'weakling'
+ G
+ end
+
+ context "with a specific fallback timeout" do
+ before do
+ bundle_config_global("BUNDLE_MIRROR__HTTPS://GEM__REPO2/__FALLBACK_TIMEOUT/" => "true",
+ "BUNDLE_MIRROR__HTTPS://GEM__REPO2/" => "https://gem.mirror")
+ end
+
+ it "install a gem using the original uri when the mirror is not responding" do
+ bundle :install, env: { "BUNDLER_SPEC_FAKE_RESOLVE" => "gem.mirror" }, verbose: true
+
+ expect(out).to include("Installing weakling")
+ expect(out).to include("Bundle complete")
+ expect(the_bundle).to include_gems "weakling 0.0.3"
+ end
+ end
+
+ context "with a global fallback timeout" do
+ before do
+ bundle_config_global("BUNDLE_MIRROR__ALL__FALLBACK_TIMEOUT/" => "1",
+ "BUNDLE_MIRROR__ALL" => "https://gem.mirror")
+ end
+
+ it "install a gem using the original uri when the mirror is not responding" do
+ bundle :install, env: { "BUNDLER_SPEC_FAKE_RESOLVE" => "gem.mirror" }
+
+ expect(out).to include("Installing weakling")
+ expect(out).to include("Bundle complete")
+ expect(the_bundle).to include_gems "weakling 0.0.3"
+ end
+ end
+
+ context "with a specific mirror without a fallback timeout" do
+ before do
+ bundle_config_global("BUNDLE_MIRROR__HTTPS://GEM__REPO2/" => "https://gem.mirror")
+ end
+
+ it "fails to install the gem with a timeout error when the mirror is not responding" do
+ bundle :install, artifice: "compact_index_mirror_down", raise_on_error: false
+
+ expect(out).to be_empty
+ expect(err).to eq("Could not reach host gem.mirror. Check your network connection and try again.")
+ end
+ end
+
+ context "with a global mirror without a fallback timeout" do
+ before do
+ bundle_config_global("BUNDLE_MIRROR__ALL" => "https://gem.mirror")
+ end
+
+ it "fails to install the gem with a timeout error when the mirror is not responding" do
+ bundle :install, artifice: "compact_index_mirror_down", raise_on_error: false
+
+ expect(out).to be_empty
+ expect(err).to eq("Could not reach host gem.mirror. Check your network connection and try again.")
+ end
+ end
+end
diff --git a/spec/bundler/install/gems/mirror_spec.rb b/spec/bundler/install/gems/mirror_spec.rb
index 70c0da50ef..e1fbeac454 100644
--- a/spec/bundler/install/gems/mirror_spec.rb
+++ b/spec/bundler/install/gems/mirror_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe "bundle install with a mirror configured" do
gem "myrack"
G
- bundle "config set --local mirror.http://gems.example.org http://gem-mirror.example.org"
+ bundle_config "mirror.http://gems.example.org http://gem-mirror.example.org"
end
it "installs from the normal location" do
@@ -26,7 +26,7 @@ RSpec.describe "bundle install with a mirror configured" do
gem "myrack"
G
- bundle "config set --local mirror.https://gem.repo2 https://gem.repo1"
+ bundle_config "mirror.https://gem.repo2 https://gem.repo1"
end
it "installs the gem from the mirror" do
diff --git a/spec/bundler/install/gems/native_extensions_spec.rb b/spec/bundler/install/gems/native_extensions_spec.rb
index 874818fa87..d5b10d2c8f 100644
--- a/spec/bundler/install/gems/native_extensions_spec.rb
+++ b/spec/bundler/install/gems/native_extensions_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle"
dir_config(name)
- raise "OMG" unless with_config("c_extension") == "hello"
+ raise ArgumentError unless with_config("c_extension") == "hello"
create_makefile(name)
E
@@ -37,7 +37,7 @@ RSpec.describe "installing a gem with native extensions" do
gem "c_extension"
G
- bundle "config set build.c_extension --with-c_extension=hello"
+ bundle_config "build.c_extension --with-c_extension=hello"
bundle "install"
expect(out).to include("Installing c_extension 1.0 with native extensions")
@@ -53,7 +53,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle"
dir_config(name)
- raise "OMG" unless with_config("c_extension") == "hello"
+ raise ArgumentError unless with_config("c_extension") == "hello"
create_makefile(name)
E
@@ -75,7 +75,7 @@ RSpec.describe "installing a gem with native extensions" do
C
end
- bundle "config set build.c_extension --with-c_extension=hello"
+ bundle_config "build.c_extension --with-c_extension=hello"
install_gemfile <<-G
source "https://gem.repo1"
@@ -97,7 +97,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle_#{n}"
dir_config(name)
- raise "OMG" unless with_config("c_extension_#{n}") == "#{n}"
+ raise ArgumentError unless with_config("c_extension_#{n}") == "#{n}"
create_makefile(name)
E
@@ -122,8 +122,8 @@ RSpec.describe "installing a gem with native extensions" do
build_git "gems", path: lib_path("gems"), gemspec: false
end
- bundle "config set build.c_extension_one --with-c_extension_one=one"
- bundle "config set build.c_extension_two --with-c_extension_two=two"
+ bundle_config "build.c_extension_one --with-c_extension_one=one"
+ bundle_config "build.c_extension_two --with-c_extension_two=two"
# 1st time, require only one gem -- only one of the extensions gets built.
install_gemfile <<-G
@@ -149,7 +149,7 @@ RSpec.describe "installing a gem with native extensions" do
require "mkmf"
name = "c_extension_bundle"
dir_config(name)
- raise "OMG" unless with_config("c_extension") == "hello" && with_config("c_extension_bundle-dir") == "hola"
+ raise ArgumentError unless with_config("c_extension") == "hello" && with_config("c_extension_bundle-dir") == "hola"
create_makefile(name)
E
@@ -171,7 +171,7 @@ RSpec.describe "installing a gem with native extensions" do
C
end
- bundle "config set build.c_extension --with-c_extension=hello --with-c_extension_bundle-dir=hola"
+ bundle_config "build.c_extension --with-c_extension=hello --with-c_extension_bundle-dir=hola"
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/install/gems/no_build_extension_spec.rb b/spec/bundler/install/gems/no_build_extension_spec.rb
new file mode 100644
index 0000000000..31f0170433
--- /dev/null
+++ b/spec/bundler/install/gems/no_build_extension_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with --no-build-extension" do
+ before do
+ build_repo2 do
+ build_gem "with_extension" do |s|
+ s.extensions << "Rakefile"
+ s.write "Rakefile", <<-RUBY
+ task :default do
+ path = File.expand_path("lib", __dir__)
+ FileUtils.mkdir_p(path)
+ File.open("\#{path}/with_extension.rb", "w") do |f|
+ f.puts "WITH_EXTENSION = 'YES'"
+ end
+ end
+ RUBY
+ end
+ end
+ end
+
+ it "skips building native extensions and warns when no_build_extension is set" do
+ bundle_config "no_build_extension true"
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_extension"
+ gem "rake"
+ G
+
+ bundle :install
+
+ build_complete = default_bundle_path("extensions").join(
+ Gem::Platform.local.to_s,
+ Gem.extension_api_version.to_s,
+ "with_extension-1.0",
+ "gem.build_complete"
+ )
+ expect(build_complete).not_to exist
+ expect(err).to include("with_extension-1.0 contains native extensions that were not built")
+ expect(err).to include("unset no_build_extension and run `bundle pristine with_extension`")
+ end
+
+ it "builds native extensions by default" do
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_extension"
+ gem "rake"
+ G
+
+ bundle :install
+
+ expect(out).to include("Installing with_extension 1.0 with native extensions")
+ end
+end
diff --git a/spec/bundler/install/gems/no_install_plugin_spec.rb b/spec/bundler/install/gems/no_install_plugin_spec.rb
new file mode 100644
index 0000000000..e040e6b813
--- /dev/null
+++ b/spec/bundler/install/gems/no_install_plugin_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with --no-install-plugin" do
+ before do
+ build_repo2 do
+ build_gem "with_plugin", "1.0" do |s|
+ s.write "lib/rubygems_plugin.rb", "# plugin code"
+ end
+
+ build_gem "with_plugin", "2.0"
+ end
+ end
+
+ let(:plugin_path) { default_bundle_path("plugins", "with_plugin_plugin.rb") }
+
+ it "does not generate the plugin wrapper and warns when no_install_plugin is set" do
+ bundle_config "no_install_plugin true"
+
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "1.0"
+ G
+
+ expect(plugin_path).not_to exist
+ expect(err).to include("with_plugin-1.0 contains plugins that were not installed")
+ expect(err).to include("unset no_install_plugin and run `bundle pristine with_plugin`")
+ end
+
+ it "removes a stale plugin wrapper from a prior version when no_install_plugin is set" do
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "1.0"
+ G
+ expect(plugin_path).to exist
+
+ bundle_config "no_install_plugin true"
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "2.0"
+ G
+
+ expect(plugin_path).not_to exist
+ end
+
+ it "generates the plugin wrapper by default" do
+ install_gemfile <<-G
+ source "https://gem.repo2"
+ gem "with_plugin", "1.0"
+ G
+
+ expect(plugin_path).to exist
+ end
+end
diff --git a/spec/bundler/install/gems/post_install_spec.rb b/spec/bundler/install/gems/post_install_spec.rb
index af753dba3e..e49fd2a9a3 100644
--- a/spec/bundler/install/gems/post_install_spec.rb
+++ b/spec/bundler/install/gems/post_install_spec.rb
@@ -127,7 +127,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- bundle "config set ignore_messages.myrack true"
+ bundle_config "ignore_messages.myrack true"
bundle :install
expect(out).not_to include("Post-install message")
@@ -141,7 +141,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- bundle "config set ignore_messages true"
+ bundle_config "ignore_messages true"
bundle :install
expect(out).not_to include("Post-install message")
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index eb6e5aa995..111d361aab 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -275,7 +275,7 @@ RSpec.describe "bundle install with install-time dependencies" do
parallel_tests
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -299,17 +299,16 @@ RSpec.describe "bundle install with install-time dependencies" do
parallel_tests
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
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", env: { "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}")
- expect(err).not_to include("That means the author of parallel_tests (3.8.0) has removed it.")
+ expect(err).to eq("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}, which is incompatible with the current version, #{Gem.ruby_version}")
end
end
@@ -359,10 +358,10 @@ RSpec.describe "bundle install with install-time dependencies" do
#{lockfile_platforms}
DEPENDENCIES
- parallel_tests
+ rubocop
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -389,7 +388,7 @@ RSpec.describe "bundle install with install-time dependencies" do
rubocop
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -426,7 +425,7 @@ RSpec.describe "bundle install with install-time dependencies" do
sorbet (= 0.5.10554)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -441,7 +440,9 @@ RSpec.describe "bundle install with install-time dependencies" do
The source contains the following gems matching 'sorbet-static (= 0.5.10554)':
* sorbet-static-0.5.10554-universal-darwin-21
E
- expect(err).to end_with(nice_error)
+ expect(err).to include(nice_error)
+ expect(err).to include("Your current platform (aarch64-linux) is not included in the lockfile's platforms (arm64-darwin-21)")
+ expect(err).to include("bundle lock --add-platform aarch64-linux")
end
end
@@ -476,7 +477,7 @@ RSpec.describe "bundle install with install-time dependencies" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<~G
@@ -518,7 +519,7 @@ RSpec.describe "bundle install with install-time dependencies" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -540,7 +541,7 @@ RSpec.describe "bundle install with install-time dependencies" do
lockfile original_lockfile
end
- it "keeps both variants in the lockfile, and uses the generic one since it's compatible" do
+ it "keeps both variants in the lockfile when installing, and uses the generic one since it's compatible" do
simulate_platform "x86_64-linux" do
bundle "install --verbose"
@@ -548,6 +549,15 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(the_bundle).to include_gems("nokogiri 1.16.3")
end
end
+
+ it "keeps both variants in the lockfile when updating, and uses the generic one since it's compatible" do
+ simulate_platform "x86_64-linux" do
+ bundle "update --verbose"
+
+ expect(lockfile).to eq(original_lockfile)
+ expect(the_bundle).to include_gems("nokogiri 1.16.3")
+ end
+ end
end
it "gives a meaningful error on ruby version mismatches between dependencies" do
@@ -768,7 +778,7 @@ RSpec.describe "bundle install with install-time dependencies" do
foo
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index abd77d33de..96a305bb76 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples "bundle install --standalone" do
+RSpec.describe "bundle install --standalone" do
shared_examples "common functionality" do
it "still makes the gems available to normal bundler" do
args = expected_gems.map {|k, v| "#{k} #{v}" }
@@ -42,7 +42,7 @@ RSpec.shared_examples "bundle install --standalone" do
testrb << "\nrequire \"#{k}\""
testrb << "\nputs #{k.upcase}"
end
- sys_exec %(#{Gem.ruby} --disable-gems -w -e #{testrb.shellescape})
+ in_bundled_app %(#{Gem.ruby} --disable-gems -w -e #{testrb.shellescape})
expect(out).to eq(expected_gems.values.join("\n"))
end
@@ -113,7 +113,7 @@ RSpec.shared_examples "bundle install --standalone" do
testrb << "\nrequire \"#{k}\""
testrb << "\nputs #{k.upcase}"
end
- sys_exec %(#{Gem.ruby} -w -e #{testrb.shellescape})
+ in_bundled_app %(#{Gem.ruby} -w -e #{testrb.shellescape})
expect(out).to eq(expected_gems.values.join("\n"))
end
@@ -125,7 +125,7 @@ RSpec.shared_examples "bundle install --standalone" do
source "https://gem.repo1"
gem "rails"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
end
@@ -140,15 +140,8 @@ RSpec.shared_examples "bundle install --standalone" do
end
describe "with default gems and a lockfile", :ruby_repo do
- before do
- necessary_system_gems = ["tsort --version 0.1.0"]
- realworld_system_gems(*necessary_system_gems)
- end
-
it "works and points to the vendored copies, not to the default copies" do
- necessary_gems_in_bundle_path = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.4.3", "stringio --version 3.1.0"]
- necessary_gems_in_bundle_path += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
- realworld_system_gems(*necessary_gems_in_bundle_path, path: scoped_gem_path(bundled_app("bundle")))
+ base_system_gems "stringio", "psych", "etc", path: scoped_gem_path(bundled_app("bundle"))
build_gem "foo", "1.0.0", to_system: true, default: true do |s|
s.add_dependency "bar"
@@ -171,17 +164,9 @@ RSpec.shared_examples "bundle install --standalone" do
bundle "lock", dir: cwd
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
- # Make sure rubyinstaller2 does not activate the etc gem in its
- # `operating_system.rb` file, but completely disable that since it's not
- # really needed here
- if Gem.win_platform?
- FileUtils.mkdir_p bundled_app("rubygems/defaults")
- FileUtils.touch bundled_app("rubygems/defaults/operating_system.rb")
- end
-
- bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }, load_path: bundled_app
+ bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") }
@@ -193,9 +178,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "works for gems with extensions and points to the vendored copies, not to the default copies" do
simulate_platform "arm64-darwin-23" do
- necessary_gems_in_bundle_path = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.4.3", "stringio --version 3.1.0", "shellwords --version 0.2.0", "open3 --version 0.2.1"]
- necessary_gems_in_bundle_path += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
- realworld_system_gems(*necessary_gems_in_bundle_path, path: scoped_gem_path(bundled_app("bundle")))
+ base_system_gems "stringio", "psych", "etc", "shellwords", "open3", path: scoped_gem_path(bundled_app("bundle"))
build_gem "baz", "1.0.0", to_system: true, default: true, &:add_c_extension
@@ -208,19 +191,11 @@ RSpec.shared_examples "bundle install --standalone" do
gem "baz"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle "lock", dir: cwd
- # Make sure rubyinstaller2 does not activate the etc gem in its
- # `operating_system.rb` file, but completely disable that since it's not
- # really needed here
- if Gem.win_platform?
- FileUtils.mkdir_p bundled_app("rubygems/defaults")
- FileUtils.touch bundled_app("rubygems/defaults/operating_system.rb")
- end
-
- bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }, load_path: bundled_app
+ bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
end
load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") }
@@ -262,6 +237,8 @@ RSpec.shared_examples "bundle install --standalone" do
end
end
+ let(:cwd) { bundled_app }
+
describe "with Gemfiles using relative path sources and app moved to a different root" do
before do
FileUtils.mkdir_p bundled_app("app/vendor")
@@ -293,7 +270,7 @@ RSpec.shared_examples "bundle install --standalone" do
describe "with gems with native extension" do
before do
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
install_gemfile <<-G, standalone: true, dir: cwd
source "https://gem.repo1"
gem "very_simple_binary"
@@ -331,7 +308,7 @@ RSpec.shared_examples "bundle install --standalone" do
end
G
end
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
install_gemfile <<-G, standalone: true, dir: cwd, raise_on_error: false
source "https://gem.repo1"
gem "bar", :git => "#{lib_path("bar-1.0")}"
@@ -353,7 +330,7 @@ RSpec.shared_examples "bundle install --standalone" do
gem "rails"
gem "devise", :git => "#{lib_path("devise-1.0")}"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
end
@@ -381,7 +358,7 @@ RSpec.shared_examples "bundle install --standalone" do
gem "myrack-test"
end
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
end
@@ -395,7 +372,7 @@ RSpec.shared_examples "bundle install --standalone" do
include_examples "common functionality"
it "allows creating a standalone file with limited groups" do
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: "default", dir: cwd
load_error_ruby <<-RUBY, "spec"
@@ -408,12 +385,12 @@ RSpec.shared_examples "bundle install --standalone" do
RUBY
expect(out).to eq("2.3.2")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
it "allows `without` configuration to limit the groups used in a standalone" do
- bundle "config set --local path #{bundled_app("bundle")}"
- bundle "config set --local without test"
+ bundle_config "path #{bundled_app("bundle")}"
+ bundle_config "without test"
bundle :install, standalone: true, dir: cwd
load_error_ruby <<-RUBY, "spec"
@@ -426,11 +403,11 @@ RSpec.shared_examples "bundle install --standalone" do
RUBY
expect(out).to eq("2.3.2")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
it "allows `path` configuration to change the location of the standalone bundle" do
- bundle "config set --local path path/to/bundle"
+ bundle_config "path path/to/bundle"
bundle "install", standalone: true, dir: cwd
ruby <<-RUBY
@@ -445,9 +422,9 @@ RSpec.shared_examples "bundle install --standalone" do
end
it "allows `without` to limit the groups used in a standalone" do
- bundle "config set --local without test"
+ bundle_config "without test"
bundle :install, dir: cwd
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, dir: cwd
load_error_ruby <<-RUBY, "spec"
@@ -460,7 +437,7 @@ RSpec.shared_examples "bundle install --standalone" do
RUBY
expect(out).to eq("2.3.2")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
end
@@ -473,7 +450,7 @@ RSpec.shared_examples "bundle install --standalone" do
source "#{source_uri}"
gem "rails"
G
- bundle "config set --local path #{bundled_app("bundle")}"
+ bundle_config "path #{bundled_app("bundle")}"
bundle :install, standalone: true, artifice: "endpoint", dir: cwd
end
@@ -487,67 +464,37 @@ RSpec.shared_examples "bundle install --standalone" do
include_examples "common functionality"
end
end
+end
- describe "with --binstubs", bundler: "< 3" do
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "rails"
- G
- bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, binstubs: true, dir: cwd
- end
+RSpec.describe "bundle install --standalone run in a subdirectory" do
+ let(:cwd) { bundled_app("bob").tap(&:mkpath) }
- let(:expected_gems) do
- {
- "actionpack" => "2.3.2",
- "rails" => "2.3.2",
- }
- end
+ before do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "rails"
+ G
+ end
- include_examples "common functionality"
+ it "generates the script in the proper place" do
+ bundle :install, standalone: true, dir: cwd
- it "creates stubs that use the standalone load path" do
- expect(sys_exec("bin/rails -v").chomp).to eql "2.3.2"
- end
+ expect(bundled_app("bundle/bundler/setup.rb")).to exist
+ end
- it "creates stubs that can be executed from anywhere" do
- require "tmpdir"
- sys_exec(%(#{bundled_app("bin/rails")} -v), dir: Dir.tmpdir)
- expect(out).to eq("2.3.2")
+ context "when path set to a relative path" do
+ before do
+ bundle_config "path bundle"
end
- it "creates stubs that can be symlinked" do
- skip "symlinks unsupported" if Gem.win_platform?
-
- symlink_dir = tmp("symlink")
- FileUtils.mkdir_p(symlink_dir)
- symlink = File.join(symlink_dir, "rails")
-
- File.symlink(bundled_app("bin/rails"), symlink)
- sys_exec("#{symlink} -v")
- expect(out).to eq("2.3.2")
- end
+ it "generates the script in the proper place" do
+ bundle :install, standalone: true, dir: cwd
- it "creates stubs with the correct load path" do
- extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip
- expect(extension_line).to eq %($:.unshift File.expand_path "../bundle", __dir__)
+ expect(bundled_app("bundle/bundler/setup.rb")).to exist
end
end
end
-RSpec.describe "bundle install --standalone" do
- let(:cwd) { bundled_app }
-
- include_examples("bundle install --standalone")
-end
-
-RSpec.describe "bundle install --standalone run in a subdirectory" do
- let(:cwd) { bundled_app("bob").tap(&:mkpath) }
-
- include_examples("bundle install --standalone")
-end
-
RSpec.describe "bundle install --standalone --local" do
before do
gemfile <<-G
@@ -572,6 +519,6 @@ RSpec.describe "bundle install --standalone --local" do
RUBY
expect(out).to eq("1.0.0")
- expect(err).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to match(/cannot load such file -- spec/)
end
end
diff --git a/spec/bundler/install/gemspecs_spec.rb b/spec/bundler/install/gemspecs_spec.rb
index dee8e547e4..fb2271c830 100644
--- a/spec/bundler/install/gemspecs_spec.rb
+++ b/spec/bundler/install/gemspecs_spec.rb
@@ -122,7 +122,7 @@ RSpec.describe "bundle install" do
expect(the_bundle).to include_gems "foo 1.0"
end
- it "fails and complains about patchlevel on patchlevel mismatch",
+ it "installs gems ignoring the mismatch even when patchlevel is mismatch",
if: RUBY_PATCHLEVEL >= 0 do
patchlevel = RUBY_PATCHLEVEL.to_i + 1
build_lib("foo", path: bundled_app) do |s|
@@ -135,9 +135,7 @@ RSpec.describe "bundle install" do
gemspec
G
- expect(err).to include("Ruby patchlevel")
- expect(err).to include("but your Gemfile specified")
- expect(exitstatus).to eq(18)
+ expect(the_bundle).to include_gems "foo 1.0"
end
it "fails and complains about version on version mismatch" do
diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb
index 670bd1fb72..1172d661ae 100644
--- a/spec/bundler/install/git_spec.rb
+++ b/spec/bundler/install/git_spec.rb
@@ -28,14 +28,14 @@ RSpec.describe "bundle install" do
end
it "displays the correct default branch", git: ">= 2.28.0" do
- build_git "foo", "1.0", path: lib_path("foo"), default_branch: "main"
+ build_git "foo", "1.0", path: lib_path("foo"), default_branch: "non-standard"
install_gemfile <<-G, verbose: true
source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo")}"
G
- expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main@#{revision_for(lib_path("foo"))[0..6]})")
+ expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at non-standard@#{revision_for(lib_path("foo"))[0..6]})")
expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
end
@@ -85,8 +85,8 @@ RSpec.describe "bundle install" do
foo!
L
- bundle "config set --local path vendor/bundle"
- bundle "config set --local without development"
+ bundle_config "path vendor/bundle"
+ bundle_config "without development"
bundle :install
expect(out).to include("Bundle complete!")
@@ -157,7 +157,7 @@ RSpec.describe "bundle install" do
test!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
# If GH#6743 is present, the first `bundle install` will change the
@@ -188,8 +188,8 @@ RSpec.describe "bundle install" do
build_git "foo", "1.0", path: lib_path("foo")
rev = revision_for(lib_path("foo"))
- bundle "config set path vendor/bundle"
- bundle "config set clean true"
+ bundle_config "path vendor/bundle"
+ bundle_config "clean true"
install_gemfile <<-G, verbose: true
source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo")}"
@@ -290,4 +290,80 @@ RSpec.describe "bundle install" do
end
end
end
+
+ describe "with excluded groups" do
+ it "works if you exclude a group with a git gem", ruby: ">= 3.3" do
+ build_git "production_gem", "1.0"
+ build_git "development_gem", "1.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "production_gem", :git => "#{lib_path("production_gem-1.0")}"
+
+ group :development do
+ gem "development_gem", :git => "#{lib_path("development_gem-1.0")}"
+ end
+ G
+
+ # First install all groups to create lockfile
+ bundle :install
+
+ # Set without and reinstall
+ bundle_config "without development"
+ bundle :install
+
+ # Verify only production gem is available
+ expect(the_bundle).to include_gems("production_gem 1.0")
+ expect(the_bundle).not_to include_gems("development_gem 1.0")
+ end
+
+ it "resolves indirect dependencies from a git source not in the requested groups" do
+ build_lib "activesupport", "1.0", path: lib_path("rails/activesupport")
+ build_git "activerecord", "1.0", path: lib_path("rails") do |s|
+ s.add_dependency "activesupport", "= 1.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "activerecord", :git => "#{lib_path("rails")}"
+
+ group :ci do
+ gem "myrack"
+ end
+ G
+
+ bundle_config "only ci"
+ bundle :install
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).not_to include_gems("activerecord 1.0")
+ end
+
+ it "resolves indirect dependencies from a git source not in the requested groups (without compact_index dependency API)" do
+ build_lib "activesupport", "1.0", path: lib_path("rails/activesupport")
+ build_git "activerecord", "1.0", path: lib_path("rails") do |s|
+ s.add_dependency "activesupport", "= 1.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "activerecord", :git => "#{lib_path("rails")}"
+
+ group :ci do
+ gem "myrack"
+ end
+ G
+
+ # Force the RubygemsAggregate code path in find_source_requirements by
+ # making the dependency API unavailable.
+ bundle_config "only ci"
+ bundle :install, artifice: "endpoint_api_forbidden"
+
+ expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).not_to include_gems("activerecord 1.0")
+ end
+ end
end
diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb
index 6893038cb7..4cffa65b2a 100644
--- a/spec/bundler/install/global_cache_spec.rb
+++ b/spec/bundler/install/global_cache_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
RSpec.describe "global gem caching" do
+ # Uses subprocess because this setting must apply across multiple app directories (bundled_app and bundled_app2)
before { bundle "config set global_gem_cache true" }
describe "using the cross-application user cache" do
@@ -8,7 +9,13 @@ RSpec.describe "global gem caching" do
let(:source2) { "http://gemserver.example.org" }
def cache_base
- home(".bundle", "cache", "gems")
+ # Use the unified global gem cache path if available (from RubyGems),
+ # otherwise fall back to the Bundler-specific cache location
+ if Gem.respond_to?(:global_gem_cache_path)
+ Pathname.new(Gem.global_gem_cache_path)
+ else
+ home(".bundle", "cache", "gems")
+ end
end
def source_global_cache(*segments)
@@ -42,6 +49,8 @@ RSpec.describe "global gem caching" do
end
it "shows a proper error message if a cached gem is corrupted" do
+ skip "This example is not working on ruby/ruby repo" if ruby_core?
+
source_global_cache.mkpath
FileUtils.touch(source_global_cache("myrack-1.0.0.gem"))
@@ -88,14 +97,14 @@ RSpec.describe "global gem caching" do
describe "when the same gem from different sources is installed" do
it "should use the appropriate one from the global cache" do
- bundle "config path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
gem "myrack"
G
- pristine_system_gems :bundler
+ pristine_system_gems
expect(the_bundle).not_to include_gems "myrack 1.0.0"
expect(source_global_cache("myrack-1.0.0.gem")).to exist
# myrack 1.0.0 is not installed and it is in the global cache
@@ -105,7 +114,7 @@ RSpec.describe "global gem caching" do
gem "myrack", "0.9.1"
G
- pristine_system_gems :bundler
+ pristine_system_gems
expect(the_bundle).not_to include_gems "myrack 0.9.1"
expect(source2_global_cache("myrack-0.9.1.gem")).to exist
# myrack 0.9.1 is not installed and it is in the global cache
@@ -119,7 +128,7 @@ RSpec.describe "global gem caching" do
# myrack 1.0.0 is installed and myrack 0.9.1 is not
expect(the_bundle).to include_gems "myrack 1.0.0"
expect(the_bundle).not_to include_gems "myrack 0.9.1"
- pristine_system_gems :bundler
+ pristine_system_gems
gemfile <<-G
source "#{source2}"
@@ -133,7 +142,7 @@ RSpec.describe "global gem caching" do
end
it "should not install if the wrong source is provided" do
- bundle "config path.system true"
+ bundle_config "path.system true"
gemfile <<-G
source "#{source}"
@@ -141,7 +150,7 @@ RSpec.describe "global gem caching" do
G
bundle :install, artifice: "compact_index"
- pristine_system_gems :bundler
+ pristine_system_gems
expect(the_bundle).not_to include_gems "myrack 1.0.0"
expect(source_global_cache("myrack-1.0.0.gem")).to exist
# myrack 1.0.0 is not installed and it is in the global cache
@@ -152,7 +161,7 @@ RSpec.describe "global gem caching" do
G
bundle :install, artifice: "compact_index"
- pristine_system_gems :bundler
+ pristine_system_gems
expect(the_bundle).not_to include_gems "myrack 0.9.1"
expect(source2_global_cache("myrack-0.9.1.gem")).to exist
# myrack 0.9.1 is not installed and it is in the global cache
@@ -191,7 +200,7 @@ RSpec.describe "global gem caching" do
describe "when installing gems from a different directory" do
it "uses the global cache as a source" do
- bundle "config path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
@@ -204,7 +213,7 @@ RSpec.describe "global gem caching" do
expect(the_bundle).to include_gems "activesupport 2.3.5"
expect(source_global_cache("myrack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
- pristine_system_gems :bundler
+ pristine_system_gems
# Both gems are now only in the global cache
expect(the_bundle).not_to include_gems "myrack 1.0.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -248,6 +257,7 @@ RSpec.describe "global gem caching" do
describe "extension caching" do
it "works" do
skip "gets incorrect ref in path" if Gem.win_platform?
+ skip "fails for unknown reason when run by ruby-core" if ruby_core?
build_git "very_simple_git_binary", &:add_c_extension
build_lib "very_simple_path_binary", &:add_c_extension
@@ -275,12 +285,12 @@ RSpec.describe "global gem caching" do
R
expect(out).to eq "VERY_SIMPLE_BINARY_IN_C\nVERY_SIMPLE_GIT_BINARY_IN_C"
- FileUtils.rm_rf Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]
+ FileUtils.rm_r Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]
gem_binary_cache.join("very_simple_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" }
git_binary_cache.join("very_simple_git_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" }
- bundle "config set --local path different_path"
+ bundle_config "path different_path"
bundle :install
expect(Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]).to all(end_with(".rb"))
diff --git a/spec/bundler/install/path_spec.rb b/spec/bundler/install/path_spec.rb
index 1412e8dd24..49360e511e 100644
--- a/spec/bundler/install/path_spec.rb
+++ b/spec/bundler/install/path_spec.rb
@@ -14,14 +14,14 @@ RSpec.describe "bundle install" do
end
it "does not use available system gems with `vendor/bundle" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "uses system gems with `path.system` configured with more priority than `path`" do
- bundle "config set --local path.system true"
- bundle "config set --global path vendor/bundle"
+ bundle_config "path.system true"
+ bundle_config_global "path vendor/bundle"
bundle :install
run "require 'myrack'", raise_on_error: false
expect(out).to include("FAIL")
@@ -31,57 +31,45 @@ RSpec.describe "bundle install" do
dir = bundled_app("bun++dle")
dir.mkpath
- bundle "config set --local path #{dir.join("vendor/bundle")}"
+ bundle_config "path #{dir.join("vendor/bundle")}"
bundle :install, dir: dir
expect(out).to include("installed into `./vendor/bundle`")
- dir.rmtree
+ FileUtils.rm_rf dir
end
it "prints a message to let the user know where gems where installed" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(out).to include("gems are installed into `./vendor/bundle`")
end
- it "disallows --path vendor/bundle --system", bundler: "< 3" do
- bundle "install --path vendor/bundle --system", raise_on_error: false
- expect(err).to include("Please choose only one option.")
- expect(exitstatus).to eq(15)
+ it "installs the bundle relatively to repository root, when Bundler run from the same directory" do
+ bundle "config set path vendor/bundle", dir: bundled_app.parent
+ bundle "install --gemfile='#{bundled_app}/Gemfile'", dir: bundled_app.parent
+ expect(out).to include("installed into `./bundled_app/vendor/bundle`")
+ expect(bundled_app("vendor/bundle")).to be_directory
+ expect(the_bundle).to include_gems "myrack 1.0.0"
end
- it "remembers to disable system gems after the first time with bundle --path vendor/bundle", bundler: "< 3" do
- bundle "install --path vendor/bundle"
- FileUtils.rm_r bundled_app("vendor")
- bundle "install"
-
- expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
+ it "installs the bundle relatively to repository root, when Bundler run from a different directory" do
+ bundle "config set path vendor/bundle", dir: bundled_app
+ bundle "install --gemfile='#{bundled_app}/Gemfile'", dir: bundled_app.parent
+ expect(out).to include("installed into `./bundled_app/vendor/bundle`")
+ expect(bundled_app("vendor/bundle")).to be_directory
expect(the_bundle).to include_gems "myrack 1.0.0"
end
- context "with path_relative_to_cwd set to true" do
- before { bundle "config set path_relative_to_cwd true" }
-
- it "installs the bundle relatively to current working directory", bundler: "< 3" do
- bundle "install --gemfile='#{bundled_app}/Gemfile' --path vendor/bundle", dir: bundled_app.parent
- expect(out).to include("installed into `./vendor/bundle`")
- expect(bundled_app("../vendor/bundle")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "installs the standalone bundle relative to the cwd" do
- bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app.parent
- expect(out).to include("installed into `./bundled_app/bundle`")
- expect(bundled_app("bundle")).to be_directory
- expect(bundled_app("bundle/ruby")).to be_directory
+ it "installs the standalone bundle relative to the cwd" do
+ bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app.parent
+ expect(out).to include("installed into `./bundled_app/bundle`")
+ expect(bundled_app("bundle")).to be_directory
+ expect(bundled_app("bundle/ruby")).to be_directory
- bundle "config unset path"
-
- bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app("subdir").tap(&:mkpath)
- expect(out).to include("installed into `../bundle`")
- expect(bundled_app("bundle")).to be_directory
- expect(bundled_app("bundle/ruby")).to be_directory
- end
+ bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app("subdir").tap(&:mkpath)
+ expect(out).to include("installed into `../bundle`")
+ expect(bundled_app("bundle")).to be_directory
+ expect(bundled_app("bundle/ruby")).to be_directory
end
end
@@ -109,7 +97,7 @@ RSpec.describe "bundle install" do
context "when set via #{type}" do
it "installs gems to a path if one is specified" do
set_bundle_path(type, bundled_app("vendor2").to_s)
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
@@ -119,7 +107,7 @@ RSpec.describe "bundle install" do
it "installs gems to ." do
set_bundle_path(type, ".")
- bundle "config set --global disable_shared_gems true"
+ bundle_config_global "disable_shared_gems true"
bundle :install
@@ -150,7 +138,7 @@ RSpec.describe "bundle install" do
end
it "installs gems to BUNDLE_PATH from .bundle/config" do
- config "BUNDLE_PATH" => bundled_app("vendor/bundle").to_s
+ bundle_config "BUNDLE_PATH" => bundled_app("vendor/bundle").to_s
bundle :install
@@ -159,7 +147,7 @@ RSpec.describe "bundle install" do
end
it "sets BUNDLE_PATH as the first argument to bundle install" do
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
@@ -169,7 +157,7 @@ RSpec.describe "bundle install" do
it "disables system gems when passing a path to install" do
# This is so that vendored gems can be distributed to others
build_gem "myrack", "1.1.0", to_system: true
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
@@ -186,19 +174,19 @@ RSpec.describe "bundle install" do
gem "very_simple_binary"
G
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
expect(vendored_gems("extensions")).to be_directory
expect(the_bundle).to include_gems "very_simple_binary 1.0", source: "remote1"
- vendored_gems("extensions").rmtree
+ FileUtils.rm_rf vendored_gems("extensions")
run "require 'very_simple_binary_c'", raise_on_error: false
expect(err).to include("Bundler::GemNotFound")
- bundle "config set --local path ./vendor/bundle"
+ bundle_config "path ./vendor/bundle"
bundle :install
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
@@ -218,7 +206,7 @@ RSpec.describe "bundle install" do
gem "myrack"
G
- bundle "config set --local path bundle"
+ bundle_config "path bundle"
bundle :install, raise_on_error: false
expect(err).to include("file already exists")
end
diff --git a/spec/bundler/install/process_lock_spec.rb b/spec/bundler/install/process_lock_spec.rb
index 344caa3a93..b096291d1a 100644
--- a/spec/bundler/install/process_lock_spec.rb
+++ b/spec/bundler/install/process_lock_spec.rb
@@ -53,5 +53,61 @@ RSpec.describe "process lock spec" do
expect(processed).to eq true
end
end
+
+ it "refreshes gem specification cache after waiting for lock" do
+ build_repo2 do
+ build_gem "myrack", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ # First, install the gem so it's available
+ bundle "install"
+ expect(out).to include("Installing myrack")
+
+ # Queue for thread-safe communication
+ lock_acquired = Queue.new
+ can_release_lock = Queue.new
+ install_output = Queue.new
+
+ # Thread holds lock (simulating another bundle process that just finished installing)
+ thread = Thread.new do
+ Bundler::ProcessLock.lock(default_bundle_path) do
+ # Signal that we have the lock
+ lock_acquired << true
+ # Wait until main thread signals we can release
+ can_release_lock.pop
+ end
+ end
+
+ # Wait for thread to acquire lock
+ lock_acquired.pop
+
+ # Start another install in a thread - it will wait for the lock
+ install_thread = Thread.new do
+ bundle "install", verbose: true
+ install_output << out
+ end
+
+ # Give subprocess time to start and begin waiting for lock
+ sleep 0.5
+
+ # Signal thread to release the lock
+ can_release_lock << true
+
+ # Wait for both threads to complete
+ thread.join
+ install_thread.join
+
+ second_install_out = install_output.pop
+
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ # The second install should have refreshed its cache after acquiring
+ # the lock and seen that myrack was already installed
+ expect(second_install_out).to include("Using myrack")
+ end
end
end
diff --git a/spec/bundler/install/redownload_spec.rb b/spec/bundler/install/redownload_spec.rb
deleted file mode 100644
index b522e22bd5..0000000000
--- a/spec/bundler/install/redownload_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "bundle install" do
- before :each do
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
- end
-
- shared_examples_for "an option to force redownloading gems" do
- it "re-installs installed gems" do
- myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
-
- bundle :install
- myrack_lib.open("w") {|f| f.write("blah blah blah") }
- bundle :install, flag => true
-
- expect(out).to include "Installing myrack 1.0.0"
- expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "works on first bundle install" do
- bundle :install, flag => true
-
- expect(out).to include "Installing myrack 1.0.0"
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- context "with a git gem" do
- let!(:ref) { build_git("foo", "1.0").ref_for("HEAD", 11) }
-
- before do
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}"
- G
- end
-
- it "re-installs installed gems" do
- foo_lib = default_bundle_path("bundler/gems/foo-1.0-#{ref}/lib/foo.rb")
-
- bundle :install
- foo_lib.open("w") {|f| f.write("blah blah blah") }
- bundle :install, flag => true
-
- expect(foo_lib.open(&:read)).to eq("FOO = '1.0'\n")
- expect(the_bundle).to include_gems "foo 1.0"
- end
-
- it "works on first bundle install" do
- bundle :install, flag => true
-
- expect(the_bundle).to include_gems "foo 1.0"
- end
- end
- end
-
- describe "with --force", bundler: 2 do
- it_behaves_like "an option to force redownloading gems" do
- let(:flag) { "force" }
- end
-
- it "shows a deprecation when single flag passed" do
- bundle "install --force"
- expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
-
- it "shows a deprecation when multiple flags passed" do
- bundle "install --no-color --force"
- expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
- end
-
- describe "with --redownload" do
- it_behaves_like "an option to force redownloading gems" do
- let(:flag) { "redownload" }
- end
-
- it "does not show a deprecation when single flag passed" do
- bundle "install --redownload"
- expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
-
- it "does not show a deprecation when single multiple flags passed" do
- bundle "install --no-color --redownload"
- expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
- end
-end
diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb
index ffe962d9f3..c92af7bfb0 100644
--- a/spec/bundler/install/yanked_spec.rb
+++ b/spec/bundler/install/yanked_spec.rb
@@ -47,7 +47,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
foo (= 1.0.0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -118,7 +118,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
build_gem "foo", "9.0.0"
end
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
install_gemfile <<-G, raise_on_error: false
source "https://gem.repo4"
@@ -154,7 +154,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
bar
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -182,7 +182,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
foo
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
diff --git a/spec/bundler/lock/git_spec.rb b/spec/bundler/lock/git_spec.rb
index 49c0a2af1c..c9f76115dc 100644
--- a/spec/bundler/lock/git_spec.rb
+++ b/spec/bundler/lock/git_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe "bundle lock with git gems" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install", raise_on_error: false
@@ -123,7 +123,7 @@ RSpec.describe "bundle lock with git gems" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -161,7 +161,7 @@ RSpec.describe "bundle lock with git gems" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -206,7 +206,7 @@ RSpec.describe "bundle lock with git gems" do
activesupport
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<~G
@@ -220,4 +220,39 @@ RSpec.describe "bundle lock with git gems" do
expect(lockfile).to include("securerandom (0.3.2)")
end
+
+ it "does not lock versions that don't exist in the repository when changing a GIT direct dep to a GEM direct dep" do
+ build_repo4 do
+ build_gem "ruby-lsp", "0.16.1"
+ end
+
+ path = lib_path("ruby-lsp")
+ revision = build_git("ruby-lsp", "0.16.2", path: path).ref_for("HEAD")
+
+ lockfile <<~L
+ GIT
+ remote: #{path}
+ revision: #{revision}
+ specs:
+ ruby-lsp (0.16.2)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruby-lsp!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile <<~G
+ source "https://gem.repo4"
+ gem "ruby-lsp"
+ G
+
+ bundle "lock"
+
+ expect(lockfile).to include("ruby-lsp (0.16.1)")
+ end
end
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb
index d43d926798..654ac02aa7 100644
--- a/spec/bundler/lock/lockfile_spec.rb
+++ b/spec/bundler/lock/lockfile_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -80,7 +80,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -109,7 +109,7 @@ RSpec.describe "the lockfile format" do
#{version}
L
- install_gemfile <<-G, verbose: true, preserve_ruby_flags: true
+ install_gemfile <<-G, verbose: true
source "https://gem.repo4"
gem "myrack"
@@ -168,7 +168,7 @@ RSpec.describe "the lockfile format" do
myrack (> 0)
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -215,7 +215,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{current_version}
+ #{current_version}
G
end
@@ -246,7 +246,7 @@ RSpec.describe "the lockfile format" do
myrack-obama
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -277,7 +277,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -324,7 +324,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -371,7 +371,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_without_credentials
@@ -432,7 +432,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lockfile lockfile_with_credentials
@@ -468,7 +468,7 @@ RSpec.describe "the lockfile format" do
net-sftp
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
expect(the_bundle).to include_gems "net-sftp 1.1.1", "net-ssh 1.0.0"
@@ -504,7 +504,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -540,7 +540,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -579,7 +579,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -615,7 +615,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -651,7 +651,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -710,7 +710,7 @@ RSpec.describe "the lockfile format" do
ckeditor!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "lock"
@@ -737,7 +737,7 @@ RSpec.describe "the lockfile format" do
ckeditor!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -770,7 +770,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -786,7 +786,6 @@ RSpec.describe "the lockfile format" do
c.no_checksum "foo", "1.0"
end
- bundle "config set cache_all true"
bundle :cache
bundle :install, local: true
@@ -807,7 +806,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -855,7 +854,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -883,7 +882,7 @@ RSpec.describe "the lockfile format" do
myrack!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -926,7 +925,7 @@ RSpec.describe "the lockfile format" do
thin
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -975,7 +974,7 @@ RSpec.describe "the lockfile format" do
rails
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -983,7 +982,7 @@ RSpec.describe "the lockfile format" do
update_repo2 do
# Capistrano did this (at least until version 2.5.10)
# RubyGems 2.2 doesn't allow the specifying of a dependency twice
- # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f
+ # See https://github.com/ruby/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f
build_gem "double_deps", "1.0", skip_validation: true do |s|
s.add_dependency "net-ssh", ">= 1.0.0"
s.add_dependency "net-ssh"
@@ -1016,7 +1015,7 @@ RSpec.describe "the lockfile format" do
double_deps
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1047,7 +1046,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1078,7 +1077,7 @@ RSpec.describe "the lockfile format" do
myrack-obama (>= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1113,7 +1112,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1148,7 +1147,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1183,7 +1182,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1216,7 +1215,7 @@ RSpec.describe "the lockfile format" do
foo!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1238,7 +1237,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
install_gemfile <<-G
@@ -1262,7 +1261,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1306,7 +1305,7 @@ RSpec.describe "the lockfile format" do
google-protobuf
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -1341,7 +1340,7 @@ RSpec.describe "the lockfile format" do
platform_specific
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
@@ -1378,7 +1377,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1406,7 +1405,7 @@ RSpec.describe "the lockfile format" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1434,7 +1433,7 @@ RSpec.describe "the lockfile format" do
myrack (= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1462,7 +1461,7 @@ RSpec.describe "the lockfile format" do
myrack (= 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1511,7 +1510,7 @@ RSpec.describe "the lockfile format" do
myrack (> 0.9, < 1.0)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1539,10 +1538,10 @@ RSpec.describe "the lockfile format" do
myrack (> 0.9, < 1.0)
#{checksums}
RUBY VERSION
- #{Bundler::RubyVersion.system}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1560,7 +1559,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1583,7 +1582,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1601,7 +1600,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
@@ -1609,7 +1608,8 @@ RSpec.describe "the lockfile format" do
gem "myrack_middleware"
G
- expect(err).to eq("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
+ expect(err).to include("myrack: gemspec specifies = 0.9.1, not in lockfile")
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
end
@@ -1629,7 +1629,7 @@ RSpec.describe "the lockfile format" do
CHECKSUMS
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
@@ -1638,7 +1638,7 @@ RSpec.describe "the lockfile format" do
G
expect(err).to eq <<~L.strip
- Your lockfile is missing a checksums entry for \"myrack_middleware\", but can't be updated because frozen mode is set
+ Your lockfile is missing a CHECKSUMS entry for \"myrack_middleware\", but can't be updated because frozen mode is set
Run `bundle install` elsewhere and add the updated Gemfile.lock to version control.
L
@@ -1646,6 +1646,40 @@ RSpec.describe "the lockfile format" do
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
end
+ it "raises a clear error when frozen mode is set and lockfile has empty checksums in CHECKSUMS section, and does not install any gems" do
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo2/
+ specs:
+ myrack (0.9.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ myrack
+
+ CHECKSUMS
+ myrack (0.9.1)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
+ source "https://gem.repo2"
+ gem "myrack"
+ G
+
+ expect(err).to eq <<~L.strip
+ Your lockfile has an empty CHECKSUMS entry for \"myrack\", but can't be updated because frozen mode is set
+
+ Run `bundle install` elsewhere and add the updated Gemfile.lock to version control.
+ L
+
+ expect(the_bundle).not_to include_gems "myrack 0.9.1"
+ end
+
it "automatically fixes the lockfile when it's missing deps, they conflict with other locked deps, but conflicts are fixable" do
build_repo4 do
build_gem "other_dep", "0.9"
@@ -1674,7 +1708,7 @@ RSpec.describe "the lockfile format" do
other_dep
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1701,7 +1735,7 @@ RSpec.describe "the lockfile format" do
other_dep
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1736,7 +1770,7 @@ RSpec.describe "the lockfile format" do
another_dep_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1764,7 +1798,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1796,7 +1830,7 @@ RSpec.describe "the lockfile format" do
other_dep
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, raise_on_error: false
@@ -1839,7 +1873,7 @@ RSpec.describe "the lockfile format" do
direct_dependency
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
install_gemfile <<-G
@@ -1863,7 +1897,7 @@ RSpec.describe "the lockfile format" do
direct_dependency
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -1881,7 +1915,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G
@@ -1904,7 +1938,7 @@ RSpec.describe "the lockfile format" do
myrack_middleware
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1938,7 +1972,7 @@ RSpec.describe "the lockfile format" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -1961,7 +1995,7 @@ RSpec.describe "the lockfile format" do
foo!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -1995,7 +2029,7 @@ RSpec.describe "the lockfile format" do
foo (= 1.0)!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -2018,7 +2052,7 @@ RSpec.describe "the lockfile format" do
foo (= 1.0)!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2054,7 +2088,7 @@ RSpec.describe "the lockfile format" do
net-smtp
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -2074,7 +2108,75 @@ RSpec.describe "the lockfile format" do
net-smtp
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "successfully updates the lockfile when a new gem is added in the Gemfile includes a gem that shouldn't be included" do
+ build_repo4 do
+ build_gem "logger", "1.7.0"
+ build_gem "rack", "3.2.0"
+ build_gem "net-smtp", "0.5.0"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "logger"
+ gem "net-smtp"
+
+ install_if -> { false } do
+ gem 'rack', github: 'rack/rack'
+ end
+ G
+
+ lockfile <<~L
+ GIT
+ remote: https://github.com/rack/rack.git
+ revision: 2fface9ac09fc582a81386becd939c987ad33f99
+ specs:
+ rack (3.2.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ logger (1.7.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ logger
+ rack!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(lockfile).to eq <<~L
+ GIT
+ remote: https://github.com/rack/rack.git
+ revision: 2fface9ac09fc582a81386becd939c987ad33f99
+ specs:
+ rack (3.2.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ logger (1.7.0)
+ net-smtp (0.5.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ logger
+ net-smtp
+ rack!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
@@ -2107,7 +2209,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
cache_gems "minitest-bisect-1.6.0", "path_expander-1.1.1", gem_repo: gem_repo4
@@ -2128,7 +2230,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
end
@@ -2173,7 +2275,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install --verbose"
@@ -2194,7 +2296,7 @@ RSpec.describe "the lockfile format" do
minitest-bisect
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
@@ -2294,7 +2396,7 @@ RSpec.describe "the lockfile format" do
myrack
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
install_gemfile <<-G, raise_on_error: false
@@ -2308,19 +2410,7 @@ RSpec.describe "the lockfile format" do
private
- def prerelease?(version)
- Gem::Version.new(version).prerelease?
- end
-
def previous_major(version)
version.split(".").map.with_index {|v, i| i == 0 ? v.to_i - 1 : v }.join(".")
end
-
- def bump_minor(version)
- bump(version, 1)
- end
-
- def bump(version, segment)
- version.split(".").map.with_index {|v, i| i == segment ? v.to_i + 1 : v }.join(".")
- end
end
diff --git a/spec/bundler/other/cli_dispatch_spec.rb b/spec/bundler/other/cli_dispatch_spec.rb
index 48b285045a..a2c745b070 100644
--- a/spec/bundler/other/cli_dispatch_spec.rb
+++ b/spec/bundler/other/cli_dispatch_spec.rb
@@ -4,17 +4,17 @@ RSpec.describe "bundle command names" do
it "work when given fully" do
bundle "install", raise_on_error: false
expect(err).to eq("Could not locate Gemfile")
- expect(last_command.stdboth).not_to include("Ambiguous command")
+ expect(stdboth).not_to include("Ambiguous command")
end
it "work when not ambiguous" do
bundle "ins", raise_on_error: false
expect(err).to eq("Could not locate Gemfile")
- expect(last_command.stdboth).not_to include("Ambiguous command")
+ expect(stdboth).not_to include("Ambiguous command")
end
it "print a friendly error when ambiguous" do
bundle "in", raise_on_error: false
- expect(err).to eq("Ambiguous command in matches [info, init, inject, install]")
+ expect(err).to eq("Ambiguous command in matches [info, init, install]")
end
end
diff --git a/spec/bundler/other/cli_man_pages_spec.rb b/spec/bundler/other/cli_man_pages_spec.rb
index 84ffca14e6..4e8f155309 100644
--- a/spec/bundler/other/cli_man_pages_spec.rb
+++ b/spec/bundler/other/cli_man_pages_spec.rb
@@ -1,49 +1,78 @@
# frozen_string_literal: true
RSpec.describe "bundle commands" do
- it "expects all commands to have a man page" do
- Bundler::CLI.all_commands.each_key do |command_name|
- next if command_name == "cli_help"
+ it "expects all commands to have all options and subcommands documented" do
+ check_commands!(Bundler::CLI)
- expect(man_page(command_name)).to exist
+ Bundler::CLI.subcommand_classes.each_value do |klass|
+ check_commands!(klass)
end
end
- it "expects all commands to have all options documented" do
- Bundler::CLI.all_commands.each do |command_name, command|
- next if command_name == "cli_help"
+ private
- man_page_content = man_page(command_name).read
+ def check_commands!(command_class)
+ command_class.commands.each do |command_name, command|
+ if command.is_a?(Bundler::Thor::HiddenCommand)
+ man_page = man_page(command_name)
+ expect(man_page).not_to exist
+ expect(main_man_page.read).not_to include("bundle #{command_name}")
+ elsif command_class == Bundler::CLI
+ man_page = man_page(command_name)
+ expect(man_page).to exist
- command.options.each do |_, option|
- aliases = option.aliases
- formatted_aliases = aliases.sort.map {|name| "`#{name}`" }.join(", ") if aliases
+ check_options!(command, man_page)
+ else
+ man_page = man_page(command.ancestor_name)
+ expect(man_page).to exist
- help = if option.type == :boolean
- "* #{append_aliases("`#{option.switch_name}`", formatted_aliases)}:"
- elsif option.enum
- formatted_aliases = "`#{option.switch_name}`" if aliases.empty? && option.lazy_default
- "* #{prepend_aliases(option.enum.sort.map {|enum| "`#{option.switch_name}=#{enum}`" }.join(", "), formatted_aliases)}:"
- else
- names = [option.switch_name, *aliases]
- value =
- case option.type
- when :array then "<list>"
- when :numeric then "<number>"
- else option.name.upcase
- end
+ check_options!(command, man_page)
+ check_subcommand!(command_name, man_page)
+ end
+ end
+ end
- value = option.type != :numeric && option.lazy_default ? "[=#{value}]" : "=#{value}"
+ def check_options!(command, man_page)
+ command.options.each do |_, option|
+ check_option!(option, man_page)
+ end
+ end
+
+ def check_option!(option, man_page)
+ man_page_content = man_page.read
- "* #{names.map {|name| "`#{name}#{value}`" }.join(", ")}:"
+ aliases = option.aliases
+ formatted_aliases = aliases.sort.map {|name| "`#{name}`" }.join(", ") if aliases
+
+ help = if option.type == :boolean
+ "* #{append_aliases("`#{option.switch_name}`", formatted_aliases)}:"
+ elsif option.enum
+ formatted_aliases = "`#{option.switch_name}`" if aliases.empty? && option.lazy_default
+ "* #{prepend_aliases(option.enum.sort.map {|enum| "`#{option.switch_name}=#{enum}`" }.join(", "), formatted_aliases)}:"
+ else
+ names = [option.switch_name, *aliases]
+ value =
+ case option.type
+ when :array then "<list>"
+ when :numeric then "<number>"
+ else option.name.upcase
end
- expect(man_page_content).to include(help)
- end
+ value = option.type != :numeric && option.lazy_default ? "[=#{value}]" : "=#{value}"
+
+ "* #{names.map {|name| "`#{name}#{value}`" }.join(", ")}:"
+ end
+
+ if option.banner.include?("(removed)")
+ expect(man_page_content).not_to include(help)
+ else
+ expect(man_page_content).to include(help)
end
end
- private
+ def check_subcommand!(name, man_page)
+ expect(man_page.read).to match(name)
+ end
def append_aliases(text, aliases)
return text if aliases.empty?
@@ -57,7 +86,15 @@ RSpec.describe "bundle commands" do
"#{aliases}, #{text}"
end
+ def man_page_content(command_name)
+ man_page(command_name).read
+ end
+
def man_page(command_name)
source_root.join("lib/bundler/man/bundle-#{command_name}.1.ronn")
end
+
+ def main_man_page
+ source_root.join("lib/bundler/man/bundle.1.ronn")
+ end
end
diff --git a/spec/bundler/other/ext_spec.rb b/spec/bundler/other/ext_spec.rb
index bdfc83d47e..a883eefe06 100644
--- a/spec/bundler/other/ext_spec.rb
+++ b/spec/bundler/other/ext_spec.rb
@@ -1,57 +1,20 @@
# frozen_string_literal: true
-RSpec.describe "Gem::Specification#match_platform" do
+RSpec.describe "Gem::Specification#installable_on_platform?" do
it "does not match platforms other than the gem platform" do
darwin = gem "lol", "1.0", "platform_specific-1.0-x86-darwin-10"
- expect(darwin.match_platform(pl("java"))).to eq(false)
+ expect(darwin.installable_on_platform?(pl("java"))).to eq(false)
end
context "when platform is a string" do
it "matches when platform is a string" do
lazy_spec = Bundler::LazySpecification.new("lol", "1.0", "universal-mingw32")
- expect(lazy_spec.match_platform(pl("x86-mingw32"))).to eq(true)
- expect(lazy_spec.match_platform(pl("x64-mingw32"))).to eq(true)
+ expect(lazy_spec.installable_on_platform?(pl("x86-mingw32"))).to eq(true)
+ expect(lazy_spec.installable_on_platform?(pl("x64-mingw32"))).to eq(true)
end
end
end
-RSpec.describe "Bundler::GemHelpers#generic" do
- include Bundler::GemHelpers
-
- it "converts non-windows platforms into ruby" do
- expect(generic(pl("x86-darwin-10"))).to eq(pl("ruby"))
- expect(generic(pl("ruby"))).to eq(pl("ruby"))
- end
-
- it "converts java platform variants into java" do
- expect(generic(pl("universal-java-17"))).to eq(pl("java"))
- expect(generic(pl("java"))).to eq(pl("java"))
- end
-
- it "converts mswin platform variants into x86-mswin32" do
- expect(generic(pl("mswin32"))).to eq(pl("x86-mswin32"))
- expect(generic(pl("i386-mswin32"))).to eq(pl("x86-mswin32"))
- expect(generic(pl("x86-mswin32"))).to eq(pl("x86-mswin32"))
- end
-
- it "converts 32-bit mingw platform variants into universal-mingw" do
- expect(generic(pl("i386-mingw32"))).to eq(pl("universal-mingw"))
- expect(generic(pl("x86-mingw32"))).to eq(pl("universal-mingw"))
- end
-
- it "converts 64-bit mingw platform variants into universal-mingw" do
- expect(generic(pl("x64-mingw32"))).to eq(pl("universal-mingw"))
- end
-
- it "converts x64 mingw UCRT platform variants into universal-mingw" do
- expect(generic(pl("x64-mingw-ucrt"))).to eq(pl("universal-mingw"))
- end
-
- it "converts aarch64 mingw UCRT platform variants into universal-mingw" do
- expect(generic(pl("aarch64-mingw-ucrt"))).to eq(pl("universal-mingw"))
- end
-end
-
RSpec.describe "Gem::SourceIndex#refresh!" do
before do
install_gemfile <<-G
diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb
index 036c855c4e..ab7589d698 100644
--- a/spec/bundler/other/major_deprecation_spec.rb
+++ b/spec/bundler/other/major_deprecation_spec.rb
@@ -14,81 +14,67 @@ RSpec.describe "major deprecations" do
describe ".clean_env" do
before do
source = "Bundler.clean_env"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_env", bundler: "< 3" do
- expect(deprecations).to include \
- "`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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_env and shows a helpful error message about it" do
+ expect(err).to include \
+ "`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`" \
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".with_clean_env" do
before do
source = "Bundler.with_clean_env {}"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_env", bundler: "< 3" do
- expect(deprecations).to include(
- "`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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_env and shows a helpful error message about it" do
+ expect(err).to include(
+ "`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`"
)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".clean_system" do
before do
source = "Bundler.clean_system('ls')"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_system", bundler: "< 3" do
- expect(deprecations).to include(
- "`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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_system and shows a helpful error message about it" do
+ expect(err).to include(
+ "`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`" \
)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".clean_exec" do
before do
source = "Bundler.clean_exec('ls')"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .unbundled_exec", bundler: "< 3" do
- expect(deprecations).to include(
- "`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` " \
- "(called at -e:1)"
+ it "is removed in favor of .unbundled_exec and shows a helpful error message about it" do
+ expect(err).to include(
+ "`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`" \
)
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".environment" do
before do
source = "Bundler.environment"
- bundle "exec ruby -e #{source.dump}"
+ bundle "exec ruby -e #{source.dump}", raise_on_error: false
end
- it "is deprecated in favor of .load", bundler: "< 3" do
- expect(deprecations).to include "Bundler.environment has been removed in favor of Bundler.load (called at -e:1)"
+ it "is removed in favor of .load and shows a helpful error message about it" do
+ expect(err).to include "Bundler.environment has been removed in favor of Bundler.load"
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
end
@@ -97,11 +83,9 @@ RSpec.describe "major deprecations" do
bundle "exec --no-keep-file-descriptors -e 1", raise_on_error: false
end
- it "is deprecated", bundler: "< 3" do
- expect(deprecations).to include "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"
+ it "is removed and shows a helpful error message about it" do
+ expect(err).to include "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"
end
-
- pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe "bundle update --quiet" do
@@ -121,16 +105,14 @@ RSpec.describe "major deprecations" do
bundle "check --path vendor/bundle", raise_on_error: false
end
- it "should print a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include(
- "The `--path` 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 " \
- "path 'vendor/bundle'`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--path` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set path 'vendor/bundle'`, " \
+ "and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "3"
end
context "bundle check --path=" do
@@ -143,16 +125,34 @@ RSpec.describe "major deprecations" do
bundle "check --path=vendor/bundle", raise_on_error: false
end
- it "should print a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include(
- "The `--path` 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 " \
- "path 'vendor/bundle'`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--path` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set path 'vendor/bundle'`, " \
+ "and stop using this flag"
)
end
+ end
- pending "fails with a helpful error", bundler: "3"
+ context "bundle binstubs --path=" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "binstubs myrack --path=binpath", raise_on_error: false
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--path` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set bin 'binpath'`, " \
+ "and stop using this flag"
+ )
+ end
end
context "bundle cache --all" do
@@ -162,19 +162,37 @@ RSpec.describe "major deprecations" do
gem "myrack"
G
- bundle "cache --all", raise_on_error: false
+ bundle "cache --all --verbose", raise_on_error: false
end
- it "should print a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include(
- "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"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--all` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set cache_all true`, " \
+ "and stop using this flag"
)
end
+ end
+
+ context "bundle cache --no-all" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
- pending "fails with a helpful error", bundler: "3"
+ bundle "cache --no-all", raise_on_error: false
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--no-all` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set cache_all false`, " \
+ "and stop using this flag"
+ )
+ end
end
context "bundle cache --path" do
@@ -187,16 +205,74 @@ RSpec.describe "major deprecations" do
bundle "cache --path foo", raise_on_error: false
end
- it "should print a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include(
- "The `--path` flag is deprecated because its semantics are unclear. " \
+ it "should print a removal error" do
+ expect(err).to include(
+ "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, " \
+ "and stop using this flag"
+ )
+ end
+ end
+
+ context "bundle cache --path=" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "cache --path=foo", raise_on_error: false
+ end
+
+ it "should print a deprecation warning" do
+ expect(err).to include(
+ "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, " \
"and stop using this flag"
)
end
+ end
+
+ context "bundle cache --frozen" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "cache --frozen", raise_on_error: false
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--frozen` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set frozen true`, " \
+ "and stop using this flag"
+ )
+ end
+ end
- pending "fails with a helpful error", bundler: "3"
+ context "bundle cache --no-prune" do
+ before do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "cache --no-prune", raise_on_error: false
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `--no-prune` flag has been removed because it relied on being " \
+ "remembered across bundler invocations, which bundler no longer " \
+ "does. Instead please use `bundle config set no_prune true`, " \
+ "and stop using this flag"
+ )
+ end
end
describe "bundle config" do
@@ -205,23 +281,23 @@ RSpec.describe "major deprecations" do
bundle "config"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config list` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old get interface" do
before do
- bundle "config waka"
+ bundle "config waka", raise_on_error: false
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config get waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old set interface" do
@@ -229,11 +305,11 @@ RSpec.describe "major deprecations" do
bundle "config waka wakapun"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set waka wakapun` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old set interface with --local" do
@@ -241,11 +317,11 @@ RSpec.describe "major deprecations" do
bundle "config --local waka wakapun"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set --local waka wakapun` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old set interface with --global" do
@@ -253,11 +329,11 @@ RSpec.describe "major deprecations" do
bundle "config --global waka wakapun"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set --global waka wakapun` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old unset interface" do
@@ -265,11 +341,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete waka"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old unset interface with --local" do
@@ -277,11 +353,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete --local waka"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset --local waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
describe "old unset interface with --global" do
@@ -289,11 +365,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete --global waka"
end
- it "warns", bundler: "3" do
+ it "warns", bundler: "4" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset --global waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", bundler: "5"
end
end
@@ -305,12 +381,12 @@ RSpec.describe "major deprecations" do
G
end
- it "warns when no options are given", bundler: "3" do
+ it "warns when no options are given", bundler: "4" do
bundle "update"
expect(deprecations).to include("Pass --all to `bundle update` to update everything")
end
- pending "fails with a helpful error when no options are given", bundler: "3"
+ pending "fails with a helpful error when no options are given", bundler: "5"
it "does not warn when --all is passed" do
bundle "update --all"
@@ -320,17 +396,15 @@ RSpec.describe "major deprecations" do
describe "bundle install --binstubs" do
before do
- install_gemfile <<-G, binstubs: true
+ install_gemfile <<-G, binstubs: true, raise_on_error: false
source "https://gem.repo1"
gem "myrack"
G
end
- it "should output a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include("The --binstubs option will be removed in favor of `bundle binstubs --all`")
+ it "fails with a helpful error" do
+ expect(err).to include("The --binstubs option has been removed in favor of `bundle binstubs --all`")
end
-
- pending "fails with a helpful error", bundler: "3"
end
context "bundle install with both gems.rb and Gemfile present" do
@@ -361,7 +435,7 @@ RSpec.describe "major deprecations" do
context "bundle install with flags" do
before do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
install_gemfile <<-G
source "https://gem.repo1"
@@ -383,76 +457,85 @@ RSpec.describe "major deprecations" do
}.each do |name, expectations|
option_name, value = *expectations
flag_name = "--#{name}"
+ args = %w[true false].include?(value) ? flag_name : "#{flag_name} #{value}"
context "with the #{flag_name} flag" do
before do
bundle "install" # to create a lockfile, which deployment or frozen need
- bundle "install #{flag_name} #{value}"
+
+ bundle "install #{args}", raise_on_error: false
end
- it "should print a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include(
- "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} #{value}`, and stop using this flag"
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "The `#{flag_name}` flag has been removed because it relied on " \
+ "being remembered across bundler invocations, which bundler no " \
+ "longer does. Instead please use `bundle config set " \
+ "#{option_name} #{value}`, and stop using this flag"
)
end
-
- pending "fails with a helpful error", bundler: "3"
end
end
end
context "bundle install with multiple sources" do
before do
- install_gemfile <<-G
+ install_gemfile <<-G, raise_on_error: false
source "https://gem.repo3"
source "https://gem.repo1"
G
end
- it "shows a deprecation", bundler: "< 3" do
- expect(deprecations).to include(
- "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."
+ it "fails with a helpful error" do
+ expect(err).to include(
+ "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
)
end
- it "doesn't show lockfile deprecations if there's a lockfile", bundler: "< 3" do
- bundle "install"
+ it "doesn't show lockfile deprecations if there's a lockfile" do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo3/
+ remote: https://gem.repo1/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
- expect(deprecations).to include(
- "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."
+ DEPENDENCIES
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ bundle "install", raise_on_error: false
+
+ expect(err).to include(
+ "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
)
- expect(deprecations).not_to include(
+ expect(err).not_to include(
"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."
)
- bundle "config set --local frozen true"
- bundle "install"
-
- expect(deprecations).to include(
- "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."
+ bundle_config "frozen true"
+ bundle "install", raise_on_error: false
+
+ expect(err).to include(
+ "This Gemfile contains multiple global sources. " \
+ "Each source after the first must include a block to indicate which gems " \
+ "should come from that source"
)
- expect(deprecations).not_to include(
+ expect(err).not_to include(
"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."
)
end
-
- pending "fails with a helpful error", bundler: "3"
end
- context "bundle install in frozen mode with a lockfile with a single rubygems section with multiple remotes" do
+ context "bundle install with a lockfile with a single rubygems section with multiple remotes" do
before do
build_repo3 do
build_gem "myrack", "0.9.1"
@@ -479,19 +562,62 @@ RSpec.describe "major deprecations" do
myrack!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
+ end
- bundle "config set --local frozen true"
+ it "shows an error" do
+ bundle "install", raise_on_error: false
+
+ expect(err).to include("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.")
end
+ end
- it "shows a deprecation", bundler: "< 3" do
- bundle "install"
+ context "bundle install with a lockfile including X64_MINGW_LEGACY platform" do
+ before do
+ gemfile <<~G
+ source "https://gem.repo1"
+ gem "rake"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://rubygems.org/
+ specs:
+ rake (10.3.2)
+
+ PLATFORMS
+ ruby
+ x64-mingw32
- expect(deprecations).to include("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.")
+ DEPENDENCIES
+ rake
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
end
- pending "fails with a helpful error", bundler: "3"
+ it "warns a helpful error" do
+ bundle "install", raise_on_error: false
+
+ expect(err).to include("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.")
+ end
+ end
+
+ context "with a global path source" do
+ before do
+ build_lib "foo"
+
+ install_gemfile <<-G, raise_on_error: false
+ path "#{lib_path("foo-1.0")}"
+ gem 'foo'
+ G
+ end
+
+ it "shows an error" do
+ expect(err).to include("You can no longer specify a path source by itself")
+ end
end
context "when Bundler.setup is run in a ruby script" do
@@ -519,19 +645,41 @@ RSpec.describe "major deprecations" do
context "when `bundler/deployment` is required in a ruby script" do
before do
- ruby <<-RUBY
+ ruby <<-RUBY, raise_on_error: false
require 'bundler/deployment'
RUBY
end
- it "should print a capistrano deprecation warning", bundler: "< 3" do
- expect(deprecations).to include("Bundler no longer integrates " \
+ it "should print a capistrano deprecation warning" do
+ expect(err).to include("Bundler no longer integrates " \
"with Capistrano, but Capistrano provides " \
"its own integration with Bundler via the " \
"capistrano-bundler gem. Use it instead.")
end
+ end
- pending "fails with a helpful error", bundler: "3"
+ context "when `bundler/capistrano` is required in a ruby script" do
+ before do
+ ruby <<-RUBY, raise_on_error: false
+ require 'bundler/capistrano'
+ RUBY
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include("[REMOVED] The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler")
+ end
+ end
+
+ context "when `bundler/vlad` is required in a ruby script" do
+ before do
+ ruby <<-RUBY, raise_on_error: false
+ require 'bundler/vlad'
+ RUBY
+ end
+
+ it "fails with a helpful error" do
+ expect(err).to include("[REMOVED] The Bundler task for Vlad")
+ end
end
context "bundle show" do
@@ -544,14 +692,12 @@ RSpec.describe "major deprecations" do
context "with --outdated flag" do
before do
- bundle "show --outdated"
+ bundle "show --outdated", raise_on_error: false
end
- it "prints a deprecation warning informing about its removal", bundler: "< 3" do
- expect(deprecations).to include("the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement")
+ it "fails with a helpful message" do
+ expect(err).to include("the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`")
end
-
- pending "fails with a helpful message", bundler: "3"
end
end
@@ -564,28 +710,32 @@ RSpec.describe "major deprecations" do
end
context "with --install" do
- it "shows a deprecation warning", bundler: "< 3" do
- bundle "remove myrack --install"
+ it "fails with a helpful message" do
+ bundle "remove myrack --install", raise_on_error: false
- expect(err).to include "[DEPRECATED] The `--install` flag has been deprecated. `bundle install` is triggered by default."
+ expect(err).to include "The `--install` flag has been removed. `bundle install` is triggered by default."
end
-
- pending "fails with a helpful message", bundler: "3"
end
end
- context "bundle viz", :realworld do
+ context "bundle viz" do
before do
- realworld_system_gems "ruby-graphviz --version 1.2.5"
- create_file "gems.rb", "source 'https://gem.repo1'"
- bundle "viz"
+ bundle "viz", raise_on_error: false
end
- it "prints a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
+ it "fails with a helpful message" do
+ expect(err).to include "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
end
+ end
- pending "fails with a helpful message", bundler: "3"
+ context "bundle inject" do
+ before do
+ bundle "inject", raise_on_error: false
+ end
+
+ it "fails with a helpful message" do
+ expect(err).to include "The `inject` command has been replaced by the `add` command"
+ end
end
context "bundle plugin install --local_git" do
@@ -595,20 +745,20 @@ RSpec.describe "major deprecations" do
end
end
- it "prints a deprecation warning", bundler: "< 3" do
- bundle "plugin install foo --local_git #{lib_path("foo-1.0")}"
+ it "fails with a helpful message" do
+ bundle "plugin install foo --local_git #{lib_path("foo-1.0")}", raise_on_error: false
- expect(out).to include("Installed plugin foo")
- expect(deprecations).to include "--local_git is deprecated, use --git"
+ expect(err).to include "--local_git has been removed, use --git"
end
-
- pending "fails with a helpful message", bundler: "3"
end
- describe "deprecating rubocop" do
+ describe "removing rubocop" do
before do
- global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false",
- "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
+ bundle_config_global "gem.mit false"
+ bundle_config_global "gem.test false"
+ bundle_config_global "gem.coc false"
+ bundle_config_global "gem.ci false"
+ bundle_config_global "gem.changelog false"
end
context "bundle gem --rubocop" do
@@ -616,9 +766,9 @@ RSpec.describe "major deprecations" do
bundle "gem my_new_gem --rubocop", raise_on_error: false
end
- it "prints a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include \
- "--rubocop is deprecated, use --linter=rubocop"
+ it "prints an error" do
+ expect(err).to include \
+ "--rubocop has been removed, use --linter=rubocop"
end
end
@@ -627,32 +777,22 @@ RSpec.describe "major deprecations" do
bundle "gem my_new_gem --no-rubocop", raise_on_error: false
end
- it "prints a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include \
- "--no-rubocop is deprecated, use --linter"
+ it "prints an error" do
+ expect(err).to include \
+ "--no-rubocop has been removed, use --no-linter"
end
end
+ end
- context "bundle gem with gem.rubocop set to true" do
- before do
- bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "true" }, raise_on_error: false
- end
-
- it "prints a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include \
- "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
- end
+ context " bundle gem --ext parameter with no value" do
+ it "prints error when used before gem name" do
+ bundle "gem --ext foo", raise_on_error: false
+ expect(err).to include "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."
end
- context "bundle gem with gem.rubocop set to false" do
- before do
- bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "false" }, raise_on_error: false
- end
-
- it "prints a deprecation warning", bundler: "< 3" do
- expect(deprecations).to include \
- "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
- end
+ it "prints error when used after gem name" do
+ bundle "gem foo --ext", raise_on_error: false
+ expect(err).to include "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."
end
end
end
diff --git a/spec/bundler/plugins/command_spec.rb b/spec/bundler/plugins/command_spec.rb
index f8dacb0e51..05d535a70c 100644
--- a/spec/bundler/plugins/command_spec.rb
+++ b/spec/bundler/plugins/command_spec.rb
@@ -53,6 +53,40 @@ RSpec.describe "command plugins" do
expect(out).to eq("You gave me tacos, tofu, lasange")
end
+ it "passes help flag to plugin" do
+ update_repo2 do
+ build_plugin "helpful" do |s|
+ s.write "plugins.rb", <<-RUBY
+ module Helpful
+ class Command
+ Bundler::Plugin::API.command "greet", self
+
+ def exec(command, args)
+ if args.include?("--help") || args.include?("-h")
+ puts "Usage: bundle greet [NAME]"
+ else
+ puts "Hello"
+ end
+ end
+ end
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install helpful --source https://gem.repo2"
+ expect(out).to include("Installed plugin helpful")
+
+ bundle "greet --help"
+ expect(out).to eq("Usage: bundle greet [NAME]")
+
+ bundle "greet -h"
+ expect(out).to eq("Usage: bundle greet [NAME]")
+
+ bundle "help greet"
+ expect(out).to eq("Usage: bundle greet [NAME]")
+ end
+
it "raises error on redeclaration of command" do
update_repo2 do
build_plugin "copycat" do |s|
diff --git a/spec/bundler/plugins/hook_spec.rb b/spec/bundler/plugins/hook_spec.rb
index 3f9053bbc8..ad8a4daeff 100644
--- a/spec/bundler/plugins/hook_spec.rb
+++ b/spec/bundler/plugins/hook_spec.rb
@@ -193,6 +193,129 @@ RSpec.describe "hook plugins" do
end
end
+ context "before-eval hook" do
+ before do
+ build_repo2 do
+ build_plugin "before-eval-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_EVAL do |gemfile, lockfile|
+ puts "hooked eval start of \#{File.basename(gemfile)} to \#{File.basename(lockfile)}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install before-eval-plugin --source https://gem.repo2"
+ end
+
+ it "runs before the Gemfile is evaluated" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "rake"
+ G
+
+ expect(out).to include "hooked eval start of Gemfile to Gemfile.lock"
+ end
+ end
+
+ context "after-eval hook" do
+ before do
+ build_repo2 do
+ build_plugin "after-eval-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_EVAL do |defn|
+ puts "hooked eval after with gems \#{defn.dependencies.map(&:name).join(", ")}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install after-eval-plugin --source https://gem.repo2"
+ end
+
+ it "runs after the Gemfile is evaluated" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ gem "rake"
+ G
+
+ expect(out).to include "hooked eval after with gems myrack, rake"
+ end
+ end
+
+ context "before-fetch and after-fetch hooks" do
+ before do
+ build_repo2 do
+ build_plugin "fetch-timing-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ @timing_start = nil
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_FETCH do |spec|
+ @timing_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "gem \#{spec.name} started fetch at \#{@timing_start}"
+ end
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_FETCH do |spec|
+ timing_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "gem \#{spec.name} took \#{timing_end - @timing_start} to fetch"
+ @timing_start = nil
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install fetch-timing-plugin --source https://gem.repo2"
+ end
+
+ it "runs around each gem download" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "rake"
+ gem "myrack"
+ G
+
+ expect(out).to include "gem rake started fetch at"
+ expect(out).to match(/gem rake took \d+\.\d+ to fetch/)
+ expect(out).to include "gem myrack started fetch at"
+ expect(out).to match(/gem myrack took \d+\.\d+ to fetch/)
+ end
+ end
+
+ context "before-git-fetch and after-git-fetch hooks" do
+ before do
+ build_repo2 do
+ build_plugin "git-fetch-timing-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ @timing_start = nil
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GIT_BEFORE_FETCH do |source|
+ @timing_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "git source \#{source.name} started fetch at \#{@timing_start}"
+ end
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GIT_AFTER_FETCH do |source|
+ timing_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ puts "git source \#{source.name} took \#{timing_end - @timing_start} to fetch"
+ @timing_start = nil
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install git-fetch-timing-plugin --source https://gem.repo2"
+ end
+
+ it "runs around each git source fetch" do
+ build_git "foo", "1.0", path: lib_path("foo")
+
+ relative_path = lib_path("foo").relative_path_from(bundled_app)
+ install_gemfile <<-G, verbose: true
+ source "https://gem.repo1"
+ gem "foo", :git => "#{relative_path}"
+ G
+
+ expect(out).to include "git source foo started fetch at"
+ expect(out).to match(/git source foo took \d+\.\d+ to fetch/)
+ end
+ end
+
def install_gemfile_and_bundler_require
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb
index d0de607e6c..dcacf764be 100644
--- a/spec/bundler/plugins/install_spec.rb
+++ b/spec/bundler/plugins/install_spec.rb
@@ -168,7 +168,7 @@ RSpec.describe "bundler plugin install" do
build_repo2 do
build_plugin "chaplin" do |s|
s.write "plugins.rb", <<-RUBY
- raise "I got you man"
+ raise RuntimeError, "threw exception on load"
RUBY
end
end
@@ -203,13 +203,6 @@ RSpec.describe "bundler plugin install" do
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
end
-
- it "raises an error when both git and local git sources are specified", bundler: "< 3" do
- bundle "plugin install foo --git /phony/path/project --local_git git@gitphony.com:/repo/project", raise_on_error: false
-
- expect(exitstatus).not_to eq(0)
- expect(err).to eq("Remote and local plugin git sources can't be both specified")
- end
end
context "path plugins" do
@@ -272,6 +265,43 @@ RSpec.describe "bundler plugin install" do
plugin_should_be_installed("foo")
end
+ it "overrides the index with the new plugin version" do
+ gemfile <<-G
+ source 'https://gem.repo2'
+ plugin 'foo', "1.0"
+ gem 'myrack', "1.0.0"
+ G
+
+ bundle "install"
+
+ update_repo2 do
+ build_plugin "foo", "2.0.0"
+ end
+
+ gemfile <<-G
+ source 'https://gem.repo2'
+ plugin 'foo', "2.0"
+ gem 'myrack', "1.0.0"
+ G
+
+ bundle "install"
+
+ expected = local_plugin_gem("foo-2.0.0", "lib").to_s
+ expect(Bundler::Plugin.index.load_paths("foo")).to eq([expected])
+ end
+
+ it "respects bundler groups" do
+ gemfile <<-G
+ source 'https://gem.repo2'
+ plugin 'foo'
+ gem 'myrack', "1.0.0"
+ G
+
+ bundle "install", env: { "BUNDLE_WITHOUT" => "default" }
+
+ expect(out).to include("Bundle complete! 1 Gemfile dependency, 0 gems now installed.")
+ end
+
it "accepts plugin version" do
update_repo2 do
build_plugin "foo", "1.1.0"
@@ -341,7 +371,7 @@ RSpec.describe "bundler plugin install" do
gem 'myrack', "1.0.0"
G
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
install_gemfile <<-G
source 'https://gem.repo2'
plugin 'foo'
diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb
index f962446314..4cd4a1a931 100644
--- a/spec/bundler/plugins/source/example_spec.rb
+++ b/spec/bundler/plugins/source/example_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe "real source plugins" do
a-path-gem!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -124,7 +124,6 @@ RSpec.describe "real source plugins" do
let(:uri_hash) { Digest(:SHA1).hexdigest(lib_path("a-path-gem-1.0").to_s) }
it "copies repository to vendor cache and uses it" do
bundle "install"
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist
@@ -136,9 +135,8 @@ RSpec.describe "real source plugins" do
end
it "copies repository to vendor cache and uses it even when installed with `path` configured" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist
@@ -148,9 +146,8 @@ RSpec.describe "real source plugins" do
end
it "bundler package copies repository to vendor cache" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist
@@ -180,7 +177,7 @@ RSpec.describe "real source plugins" do
a-path-gem!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -363,7 +360,7 @@ RSpec.describe "real source plugins" do
ma-gitp-gem!
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -389,7 +386,7 @@ RSpec.describe "real source plugins" do
ma-gitp-gem!
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
@@ -446,7 +443,6 @@ RSpec.describe "real source plugins" do
end
G
- bundle "config set cache_all true"
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist
diff --git a/spec/bundler/quality_es_spec.rb b/spec/bundler/quality_es_spec.rb
index 0dbd77e451..e68674c030 100644
--- a/spec/bundler/quality_es_spec.rb
+++ b/spec/bundler/quality_es_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "La biblioteca si misma" do
]
pattern = /\b#{Regexp.union(useless_words)}\b/i
- File.readlines(filename).each_with_index do |line, number|
+ File.readlines(File.expand_path(filename, source_root)).each_with_index do |line, number|
next unless word_found = pattern.match(line)
failing_line_message << "#{filename}:#{number.succ} contiene '#{word_found}'. Esta palabra tiene un significado subjetivo y es mejor obviarla en textos técnicos."
end
@@ -29,7 +29,7 @@ RSpec.describe "La biblioteca si misma" do
failing_line_message = []
specific_pronouns = /\b(él|ella|ellos|ellas)\b/i
- File.readlines(filename).each_with_index do |line, number|
+ File.readlines(File.expand_path(filename, source_root)).each_with_index do |line, number|
next unless word_found = specific_pronouns.match(line)
failing_line_message << "#{filename}:#{number.succ} contiene '#{word_found}'. Use pronombres más genéricos en la documentación."
end
diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb
index c7fce17b62..16b7f18788 100644
--- a/spec/bundler/quality_spec.rb
+++ b/spec/bundler/quality_spec.rb
@@ -20,6 +20,9 @@ RSpec.describe "The library itself" do
end
def check_for_tab_characters(filename)
+ # Because Go uses hard tabs
+ return if filename.end_with?(".go.tt")
+
failing_lines = []
each_line(filename) do |line, number|
failing_lines << number + 1 if line.include?("\t")
@@ -106,7 +109,7 @@ RSpec.describe "The library itself" do
it "does not include any unresolved merge conflicts" do
error_messages = []
- exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb}
+ exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser}
tracked_files.each do |filename|
next if filename&.match?(exempt)
error_messages << check_for_git_merge_conflicts(filename)
@@ -115,10 +118,8 @@ RSpec.describe "The library itself" do
end
it "maintains language quality of the documentation" do
- included = /ronn/
error_messages = []
man_tracked_files.each do |filename|
- next unless filename&.match?(included)
error_messages << check_for_expendable_words(filename)
error_messages << check_for_specific_pronouns(filename)
end
@@ -138,12 +139,12 @@ RSpec.describe "The library itself" do
it "documents all used settings" do
exemptions = %w[
- forget_cli_options
gem.changelog
gem.ci
gem.coc
gem.linter
gem.mit
+ gem.bundle
gem.rubocop
gem.test
git.allow_insecure
@@ -165,7 +166,8 @@ RSpec.describe "The library itself" do
line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `#{filename}:#{number.succ}`" }
end
end
- documented_settings = File.read("lib/bundler/man/bundle-config.1.ronn")[/LIST OF AVAILABLE KEYS.*/m].scan(/^\* `#{key_pattern}`/).flatten
+ settings_section = File.read(source_root.join("lib/bundler/man/bundle-config.1.ronn")).split(/^## /).find {|section| section.start_with?("LIST OF AVAILABLE KEYS") }
+ documented_settings = settings_section.scan(/^\* `#{key_pattern}`/).flatten
documented_settings.each do |s|
all_settings.delete(s)
@@ -185,8 +187,8 @@ RSpec.describe "The library itself" do
end
it "can still be built" do
- with_built_bundler do |_gem_path|
- expect(err).to be_empty, "bundler should build as a gem without warnings, but\n#{err}"
+ with_built_bundler do |gem_path|
+ expect(File.exist?(gem_path)).to be true
end
end
@@ -216,7 +218,7 @@ RSpec.describe "The library itself" do
end
end
- warnings = last_command.stdboth.split("\n")
+ warnings = stdboth.split("\n")
# ignore warnings around deprecated Object#=~ method in RubyGems
warnings.reject! {|w| w =~ %r{rubygems\/version.rb.*deprecated\ Object#=~} }
@@ -254,6 +256,6 @@ RSpec.describe "The library itself" do
private
def each_line(filename, &block)
- File.readlines(filename, encoding: "UTF-8").each_with_index(&block)
+ File.readlines(File.expand_path(filename, source_root), encoding: "UTF-8").each_with_index(&block)
end
end
diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb
index fb434aba70..391aa0cef6 100644
--- a/spec/bundler/realworld/edgecases_spec.rb
+++ b/spec/bundler/realworld/edgecases_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe "real world edgecases", realworld: true do
index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
end
if rubygem.nil?
- raise "Could not find #{name} (#{requirement}) on rubygems.org!\n" \
+ raise ArgumentError, "Could not find #{name} (#{requirement}) on rubygems.org!\n" \
"Found specs:\n\#{index.send(:specs).inspect}"
end
puts "#{name} (\#{rubygem.version})"
@@ -63,141 +63,6 @@ RSpec.describe "real world edgecases", realworld: true do
expect(lockfile).to include(rubygems_version("activesupport", "~> 3.0"))
end
- it "is able to update a top-level dependency when there is a conflict on a shared transitive child" do
- # from https://github.com/rubygems/bundler/issues/5031
-
- pristine_system_gems "bundler-1.99.0"
-
- gemfile <<-G
- source "https://rubygems.org"
- gem 'rails', '~> 4.2.7.1'
- gem 'paperclip', '~> 5.1.0'
- G
-
- lockfile <<-L
- GEM
- remote: https://rubygems.org/
- specs:
- actionmailer (4.2.7.1)
- actionpack (= 4.2.7.1)
- actionview (= 4.2.7.1)
- activejob (= 4.2.7.1)
- mail (~> 2.5, >= 2.5.4)
- rails-dom-testing (~> 1.0, >= 1.0.5)
- actionpack (4.2.7.1)
- actionview (= 4.2.7.1)
- activesupport (= 4.2.7.1)
- rack (~> 1.6)
- rack-test (~> 0.6.2)
- rails-dom-testing (~> 1.0, >= 1.0.5)
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (4.2.7.1)
- activesupport (= 4.2.7.1)
- builder (~> 3.1)
- erubis (~> 2.7.0)
- rails-dom-testing (~> 1.0, >= 1.0.5)
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
- activejob (4.2.7.1)
- activesupport (= 4.2.7.1)
- globalid (>= 0.3.0)
- activemodel (4.2.7.1)
- activesupport (= 4.2.7.1)
- builder (~> 3.1)
- activerecord (4.2.7.1)
- activemodel (= 4.2.7.1)
- activesupport (= 4.2.7.1)
- arel (~> 6.0)
- activesupport (4.2.7.1)
- i18n (~> 0.7)
- json (~> 1.7, >= 1.7.7)
- minitest (~> 5.1)
- thread_safe (~> 0.3, >= 0.3.4)
- tzinfo (~> 1.1)
- arel (6.0.3)
- builder (3.2.2)
- climate_control (0.0.3)
- activesupport (>= 3.0)
- cocaine (0.5.8)
- climate_control (>= 0.0.3, < 1.0)
- concurrent-ruby (1.0.2)
- erubis (2.7.0)
- globalid (0.3.7)
- activesupport (>= 4.1.0)
- i18n (0.7.0)
- json (1.8.3)
- loofah (2.0.3)
- nokogiri (>= 1.5.9)
- mail (2.6.4)
- mime-types (>= 1.16, < 4)
- mime-types (3.1)
- mime-types-data (~> 3.2015)
- mime-types-data (3.2016.0521)
- mimemagic (0.3.2)
- mini_portile2 (2.1.0)
- minitest (5.9.1)
- nokogiri (1.6.8)
- mini_portile2 (~> 2.1.0)
- pkg-config (~> 1.1.7)
- paperclip (5.1.0)
- activemodel (>= 4.2.0)
- activesupport (>= 4.2.0)
- cocaine (~> 0.5.5)
- mime-types
- mimemagic (~> 0.3.0)
- pkg-config (1.1.7)
- rack (1.6.4)
- rack-test (0.6.3)
- rack (>= 1.0)
- rails (4.2.7.1)
- actionmailer (= 4.2.7.1)
- actionpack (= 4.2.7.1)
- actionview (= 4.2.7.1)
- activejob (= 4.2.7.1)
- activemodel (= 4.2.7.1)
- activerecord (= 4.2.7.1)
- activesupport (= 4.2.7.1)
- bundler (>= 1.3.0, < 2.0)
- railties (= 4.2.7.1)
- sprockets-rails
- rails-deprecated_sanitizer (1.0.3)
- activesupport (>= 4.2.0.alpha)
- rails-dom-testing (1.0.7)
- activesupport (>= 4.2.0.beta, < 5.0)
- nokogiri (~> 1.6.0)
- rails-deprecated_sanitizer (>= 1.0.1)
- rails-html-sanitizer (1.0.3)
- loofah (~> 2.0)
- railties (4.2.7.1)
- actionpack (= 4.2.7.1)
- activesupport (= 4.2.7.1)
- rake (>= 0.8.7)
- thor (>= 0.18.1, < 2.0)
- rake (11.3.0)
- sprockets (3.7.0)
- concurrent-ruby (~> 1.0)
- rack (> 1, < 3)
- sprockets-rails (3.2.0)
- actionpack (>= 4.0)
- activesupport (>= 4.0)
- sprockets (>= 3.0.0)
- thor (0.19.1)
- thread_safe (0.3.5)
- tzinfo (1.2.2)
- thread_safe (~> 0.1)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- paperclip (~> 5.1.0)
- rails (~> 4.2.7.1)
- L
-
- bundle "lock --update paperclip", env: { "BUNDLER_VERSION" => "1.99.0" }
-
- expect(lockfile).to include(rubygems_version("paperclip", "~> 5.1.0"))
- end
-
it "outputs a helpful warning when gems have a gemspec with invalid `require_paths`" do
install_gemfile <<-G, standalone: true, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
source 'https://rubygems.org'
diff --git a/spec/bundler/realworld/ffi_spec.rb b/spec/bundler/realworld/ffi_spec.rb
index 5f40b43a0f..bede372b41 100644
--- a/spec/bundler/realworld/ffi_spec.rb
+++ b/spec/bundler/realworld/ffi_spec.rb
@@ -42,12 +42,12 @@ RSpec.describe "loading dynamically linked library on a bundle exec context", re
}
C
- sys_exec "gcc -g -o libfoo.so -shared -fpic libfoo.c"
+ in_bundled_app "gcc -g -o libfoo.so -shared -fpic libfoo.c"
install_gemfile <<-G
source "https://rubygems.org"
- gem 'ffi'
+ gem 'ffi', force_ruby_platform: true
G
bundle "exec ruby foo.rb"
diff --git a/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock b/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock
index c9ded0fd78..c2df2f9229 100644
--- a/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/tapioca/Gemfile.lock
@@ -31,8 +31,8 @@ GEM
spoom (>= 1.2.0)
thor (>= 1.2.0)
yard-sorbet
- thor (1.3.2)
- yard (0.9.37)
+ thor (1.4.0)
+ yard (0.9.42)
yard-sorbet (0.9.0)
sorbet-runtime
yard
@@ -46,4 +46,4 @@ DEPENDENCIES
tapioca
BUNDLED WITH
- 2.7.0.dev
+ 4.1.0.dev
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile b/spec/bundler/realworld/fixtures/warbler/Gemfile
index e4d3e8ea96..5687bbd975 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile
@@ -3,5 +3,5 @@
source "https://rubygems.org"
gem "demo", path: "./demo"
-gem "jruby-jars", "~> 9.4"
-gem "warbler", "~> 2.0"
+gem "jruby-jars", "~> 10.0"
+gem "warbler", "~> 2.1"
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
index dc73661271..05f3bc4e3f 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
@@ -6,25 +6,30 @@ PATH
GEM
remote: https://rubygems.org/
specs:
- jruby-jars (9.4.10.0)
- jruby-rack (1.1.21)
- rake (13.0.1)
- rubyzip (1.3.0)
- warbler (2.0.5)
- jruby-jars (>= 9.0.0.0)
- jruby-rack (>= 1.1.1, < 1.3)
- rake (>= 10.1.0)
- rubyzip (~> 1.0, < 1.4)
+ jruby-jars (10.0.0.1)
+ jruby-rack (1.2.7)
+ ostruct (0.6.3)
+ rake (13.3.0)
+ rexml (3.4.2)
+ rubyzip (3.3.0)
+ warbler (2.1.0)
+ jruby-jars (>= 9.4, < 10.1)
+ jruby-rack (>= 1.2.3, < 1.3)
+ ostruct (~> 0.6.2)
+ rake (~> 13.0, >= 13.0.3)
+ rexml (~> 3.0)
+ rubyzip (>= 3.0.0)
PLATFORMS
+ arm64-darwin
java
ruby
- universal-java-11
+ universal-java
DEPENDENCIES
demo!
- jruby-jars (~> 9.4)
- warbler (~> 2.0)
+ jruby-jars (~> 10.0)
+ warbler (~> 2.1)
BUNDLED WITH
- 2.7.0.dev
+ 4.1.0.dev
diff --git a/spec/bundler/realworld/gemfile_source_header_spec.rb b/spec/bundler/realworld/gemfile_source_header_spec.rb
deleted file mode 100644
index c532c6a867..0000000000
--- a/spec/bundler/realworld/gemfile_source_header_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "fetching dependencies with a mirrored source", realworld: true do
- let(:mirror) { "https://server.example.org" }
- let(:original) { "http://127.0.0.1:#{@port}" }
-
- before do
- setup_server
- bundle "config set --local mirror.#{mirror} #{original}"
- end
-
- after do
- Artifice.deactivate
- @t.kill
- @t.join
- end
-
- it "sets the 'X-Gemfile-Source' and 'User-Agent' headers and bundles successfully" do
- gemfile <<-G
- source "#{mirror}"
- gem 'weakling'
- G
-
- bundle :install, artifice: nil
-
- expect(out).to include("Installing weakling")
- expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gems "weakling 0.0.3"
- end
-
- private
-
- def setup_server
- require_rack
- @port = find_unused_port
- @server_uri = "http://127.0.0.1:#{@port}"
-
- require_relative "../support/artifice/endpoint_mirror_source"
- require_relative "../support/silent_logger"
-
- require "rackup/server"
-
- @t = Thread.new do
- Rackup::Server.start(app: EndpointMirrorSource,
- Host: "0.0.0.0",
- Port: @port,
- server: "webrick",
- AccessLog: [],
- Logger: Spec::SilentLogger.new)
- end.run
-
- wait_for_server("127.0.0.1", @port)
- end
-end
diff --git a/spec/bundler/realworld/mirror_probe_spec.rb b/spec/bundler/realworld/mirror_probe_spec.rb
deleted file mode 100644
index 66a553da28..0000000000
--- a/spec/bundler/realworld/mirror_probe_spec.rb
+++ /dev/null
@@ -1,132 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "fetching dependencies with a not available mirror", realworld: true do
- let(:mirror) { @mirror_uri }
- let(:original) { @server_uri }
- let(:server_port) { @server_port }
- let(:host) { "127.0.0.1" }
-
- before do
- require_rack
- setup_server
- setup_mirror
- end
-
- after do
- Artifice.deactivate
- @server_thread.kill
- @server_thread.join
- end
-
- context "with a specific fallback timeout" do
- before do
- global_config("BUNDLE_MIRROR__HTTP://127__0__0__1:#{server_port}/__FALLBACK_TIMEOUT/" => "true",
- "BUNDLE_MIRROR__HTTP://127__0__0__1:#{server_port}/" => mirror)
- end
-
- it "install a gem using the original uri when the mirror is not responding" do
- gemfile <<-G
- source "#{original}"
- gem 'weakling'
- G
-
- bundle :install, artifice: nil
-
- expect(out).to include("Installing weakling")
- expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gems "weakling 0.0.3"
- end
- end
-
- context "with a global fallback timeout" do
- before do
- global_config("BUNDLE_MIRROR__ALL__FALLBACK_TIMEOUT/" => "1",
- "BUNDLE_MIRROR__ALL" => mirror)
- end
-
- it "install a gem using the original uri when the mirror is not responding" do
- gemfile <<-G
- source "#{original}"
- gem 'weakling'
- G
-
- bundle :install, artifice: nil
-
- expect(out).to include("Installing weakling")
- expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gems "weakling 0.0.3"
- end
- end
-
- context "with a specific mirror without a fallback timeout" do
- before do
- global_config("BUNDLE_MIRROR__HTTP://127__0__0__1:#{server_port}/" => mirror)
- end
-
- it "fails to install the gem with a timeout error" do
- gemfile <<-G
- source "#{original}"
- gem 'weakling'
- G
-
- bundle :install, artifice: nil, raise_on_error: false
-
- expect(out).to include("Fetching source index from #{mirror}")
-
- err_lines = err.split("\n")
- expect(err_lines).to include(%r{\ARetrying fetcher due to error \(2/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
- expect(err_lines).to include(%r{\ARetrying fetcher due to error \(3/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
- expect(err_lines).to include(%r{\ARetrying fetcher due to error \(4/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
- expect(err_lines).to include(%r{\ACould not fetch specs from #{mirror}/ due to underlying error <})
- end
- end
-
- context "with a global mirror without a fallback timeout" do
- before do
- global_config("BUNDLE_MIRROR__ALL" => mirror)
- end
-
- it "fails to install the gem with a timeout error" do
- gemfile <<-G
- source "#{original}"
- gem 'weakling'
- G
-
- bundle :install, artifice: nil, raise_on_error: false
-
- expect(out).to include("Fetching source index from #{mirror}")
-
- err_lines = err.split("\n")
- expect(err_lines).to include(%r{\ARetrying fetcher due to error \(2/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
- expect(err_lines).to include(%r{\ARetrying fetcher due to error \(3/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
- expect(err_lines).to include(%r{\ARetrying fetcher due to error \(4/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
- expect(err_lines).to include(%r{\ACould not fetch specs from #{mirror}/ due to underlying error <})
- end
- end
-
- def setup_server
- @server_port = find_unused_port
- @server_uri = "http://#{host}:#{@server_port}"
-
- require_relative "../support/artifice/endpoint"
- require_relative "../support/silent_logger"
-
- require "rackup/server"
-
- @server_thread = Thread.new do
- Rackup::Server.start(app: Endpoint,
- Host: host,
- Port: @server_port,
- server: "webrick",
- AccessLog: [],
- Logger: Spec::SilentLogger.new)
- end.run
-
- wait_for_server(host, @server_port)
- end
-
- def setup_mirror
- @mirror_port = find_unused_port
- @mirror_uri = "http://#{host}:#{@mirror_port}"
- end
-end
diff --git a/spec/bundler/realworld/slow_perf_spec.rb b/spec/bundler/realworld/slow_perf_spec.rb
index 32e266ff1b..5d36ba7455 100644
--- a/spec/bundler/realworld/slow_perf_spec.rb
+++ b/spec/bundler/realworld/slow_perf_spec.rb
@@ -30,115 +30,6 @@ RSpec.describe "bundle install with complex dependencies", realworld: true do
G
bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
- expect(out).to include("Solution found after 1 attempts")
- end
-
- it "resolves big gemfile quickly" do
- gemfile <<~G
- # frozen_string_literal: true
-
- source "https://rubygems.org"
-
- gem "rails"
- gem "pg", ">= 0.18", "< 2.0"
- gem "goldiloader"
- gem "awesome_nested_set"
- gem "circuitbox"
- gem "passenger"
- gem "globalid"
- gem "rack-cors"
- gem "rails-pg-extras"
- gem "linear_regression_trend"
- gem "rack-protection"
- gem "pundit"
- gem "remote_ip_proxy_scrubber"
- gem "bcrypt"
- gem "searchkick"
- gem "excon"
- gem "faraday_middleware-aws-sigv4"
- gem "typhoeus"
- gem "sidekiq"
- gem "sidekiq-undertaker"
- gem "sidekiq-cron"
- gem "storext"
- gem "appsignal"
- gem "fcm"
- gem "business_time"
- gem "tzinfo"
- gem "holidays"
- gem "bigdecimal"
- gem "progress_bar"
- gem "redis"
- gem "hiredis"
- gem "state_machines"
- gem "state_machines-audit_trail"
- gem "state_machines-activerecord"
- gem "interactor"
- gem "ar_transaction_changes"
- gem "redis-rails"
- gem "seed_migration"
- gem "lograge"
- gem "graphiql-rails", group: :development
- gem "graphql"
- gem "pusher"
- gem "rbnacl"
- gem "jwt"
- gem "json-schema"
- gem "discard"
- gem "money"
- gem "strip_attributes"
- gem "validates_email_format_of"
- gem "audited"
- gem "concurrent-ruby"
- gem "with_advisory_lock"
-
- group :test do
- gem "rspec-sidekiq"
- gem "simplecov", require: false
- end
-
- group :development, :test do
- gem "byebug", platform: :mri
- gem "guard"
- gem "guard-bundler"
- gem "guard-rspec"
- gem "rb-fsevent"
- gem "rspec_junit_formatter"
- gem "rspec-collection_matchers"
- gem "rspec-rails"
- gem "rspec-retry"
- gem "state_machines-rspec"
- gem "dotenv-rails"
- gem "database_cleaner-active_record"
- gem "database_cleaner-redis"
- gem "timecop"
- end
-
- gem "factory_bot_rails"
- gem "faker"
-
- group :development do
- gem "listen"
- gem "sql_queries_count"
- gem "rubocop"
- gem "rubocop-performance"
- gem "rubocop-rspec"
- gem "rubocop-rails"
- gem "brakeman"
- gem "bundler-audit"
- gem "solargraph"
- gem "annotate"
- end
- G
-
- if Bundler.feature_flag.bundler_3_mode?
- bundle "lock", env: { "DEBUG_RESOLVER" => "1" }, raise_on_error: false
-
- expect(out).to include("backtracking").exactly(26).times
- else
- bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
-
- expect(out).to include("Solution found after 10 attempts")
- end
+ expect(out).to include("Solution found after 2 attempts")
end
end
diff --git a/spec/bundler/resolver/basic_spec.rb b/spec/bundler/resolver/basic_spec.rb
index 05c6f24ff7..185df1b1c7 100644
--- a/spec/bundler/resolver/basic_spec.rb
+++ b/spec/bundler/resolver/basic_spec.rb
@@ -238,7 +238,7 @@ RSpec.describe "Resolving" do
it "resolves foo only to latest patch - changing dependency declared case" do
# bar is locked AND a declared dependency in the Gemfile, so it will not move, and therefore
# foo can only move up to 1.4.4.
- @base << Bundler::LazySpecification.new("bar", Gem::Version.new("2.0.3"), nil)
+ @base = Bundler::SpecSet.new([Bundler::LazySpecification.new("bar", Gem::Version.new("2.0.3"), nil)])
should_conservative_resolve_and_include :patch, ["foo"], %w[foo-1.4.4 bar-2.0.3]
end
diff --git a/spec/bundler/resolver/platform_spec.rb b/spec/bundler/resolver/platform_spec.rb
index 8e51911bbd..a1d095d024 100644
--- a/spec/bundler/resolver/platform_spec.rb
+++ b/spec/bundler/resolver/platform_spec.rb
@@ -48,11 +48,11 @@ RSpec.describe "Resolving platform craziness" do
it "takes the latest ruby gem, even if an older platform specific version is available" do
@index = build_index do
gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32"
+ gem "foo", "1.0.0", "x64-mingw-ucrt"
gem "foo", "1.1.0"
end
dep "foo"
- platforms "x64-mingw32"
+ platforms "x64-mingw-ucrt"
should_resolve_as %w[foo-1.1.0]
end
@@ -61,12 +61,12 @@ RSpec.describe "Resolving platform craziness" do
@index = build_index do
gem "bar", "1.0.0"
gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32" do
+ gem "foo", "1.0.0", "x64-mingw-ucrt" do
dep "bar", "< 1"
end
end
dep "foo"
- platforms "x64-mingw32"
+ platforms "x64-mingw-ucrt"
should_resolve_as %w[foo-1.0.0]
end
@@ -74,12 +74,12 @@ RSpec.describe "Resolving platform craziness" do
it "prefers the platform specific gem to the ruby version" do
@index = build_index do
gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32"
+ gem "foo", "1.0.0", "x64-mingw-ucrt"
end
dep "foo"
- platforms "x64-mingw32"
+ platforms "x64-mingw-ucrt"
- should_resolve_as %w[foo-1.0.0-x64-mingw32]
+ should_resolve_as %w[foo-1.0.0-x64-mingw-ucrt]
end
describe "on a linux platform" do
@@ -159,15 +159,15 @@ RSpec.describe "Resolving platform craziness" do
before do
@index = build_index do
gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32"
+ gem "foo", "1.0.0", "x64-mingw-ucrt"
gem "foo", "1.1.0"
- gem "foo", "1.1.0", "x64-mingw32" do |s|
+ gem "foo", "1.1.0", "x64-mingw-ucrt" do |s|
s.required_ruby_version = [">= 2.0", "< 2.4"]
end
gem "Ruby\0", "2.5.1"
end
dep "Ruby\0", "2.5.1"
- platforms "x64-mingw32"
+ platforms "x64-mingw-ucrt"
end
it "takes the latest ruby gem" do
@@ -186,18 +186,18 @@ RSpec.describe "Resolving platform craziness" do
it "takes the latest ruby gem with required_ruby_version if the platform specific gem doesn't match the required_ruby_version" do
@index = build_index do
gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32"
+ gem "foo", "1.0.0", "x64-mingw-ucrt"
gem "foo", "1.1.0" do |s|
s.required_ruby_version = [">= 2.0"]
end
- gem "foo", "1.1.0", "x64-mingw32" do |s|
+ gem "foo", "1.1.0", "x64-mingw-ucrt" do |s|
s.required_ruby_version = [">= 2.0", "< 2.4"]
end
gem "Ruby\0", "2.5.1"
end
dep "foo"
dep "Ruby\0", "2.5.1"
- platforms "x64-mingw32"
+ platforms "x64-mingw-ucrt"
should_resolve_as %w[foo-1.1.0]
end
@@ -205,18 +205,18 @@ RSpec.describe "Resolving platform craziness" do
it "takes the latest ruby gem if the platform specific gem doesn't match the required_ruby_version with multiple platforms" do
@index = build_index do
gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32"
+ gem "foo", "1.0.0", "x64-mingw-ucrt"
gem "foo", "1.1.0" do |s|
s.required_ruby_version = [">= 2.0"]
end
- gem "foo", "1.1.0", "x64-mingw32" do |s|
+ gem "foo", "1.1.0", "x64-mingw-ucrt" do |s|
s.required_ruby_version = [">= 2.0", "< 2.4"]
end
gem "Ruby\0", "2.5.1"
end
dep "foo"
dep "Ruby\0", "2.5.1"
- platforms "x86_64-linux", "x64-mingw32"
+ platforms "x86_64-linux", "x64-mingw-ucrt"
should_resolve_as %w[foo-1.1.0]
end
@@ -342,7 +342,7 @@ RSpec.describe "Resolving platform craziness" do
describe "with mingw32" do
before :each do
@index = build_index do
- platforms "mingw32 mswin32 x64-mingw32 x64-mingw-ucrt" do |platform|
+ platforms "mingw32 mswin32 x64-mingw-ucrt" do |platform|
gem "thin", "1.2.7", platform
end
gem "win32-api", "1.5.1", "universal-mingw32"
@@ -363,10 +363,10 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[thin-1.2.7-mingw32]
end
- it "finds x64-mingw32 gems" do
- platforms "x64-mingw32"
+ it "finds x64-mingw-ucrt gems" do
+ platforms "x64-mingw-ucrt"
dep "thin"
- should_resolve_as %w[thin-1.2.7-x64-mingw32]
+ should_resolve_as %w[thin-1.2.7-x64-mingw-ucrt]
end
it "finds universal-mingw gems on x86-mingw" do
@@ -376,7 +376,7 @@ RSpec.describe "Resolving platform craziness" do
end
it "finds universal-mingw gems on x64-mingw" do
- platform "x64-mingw32"
+ platform "x64-mingw-ucrt"
dep "win32-api"
should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
end
@@ -387,7 +387,7 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[thin-1.2.7-x64-mingw-ucrt]
end
- it "finds universal-mingw gems on x64-mingw-ucrt", rubygems: ">= 3.3.18" do
+ it "finds universal-mingw gems on x64-mingw-ucrt" do
platform "x64-mingw-ucrt"
dep "win32-api"
should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
diff --git a/spec/bundler/runtime/env_helpers_spec.rb b/spec/bundler/runtime/env_helpers_spec.rb
index a1607cd057..c4ebdd1fd2 100644
--- a/spec/bundler/runtime/env_helpers_spec.rb
+++ b/spec/bundler/runtime/env_helpers_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "env helpers" do
path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo"
with_path_as(path) do
bundle_exec_ruby(bundled_app("source.rb").to_s)
- expect(last_command.stdboth).to eq(path)
+ expect(stdboth).to eq(path)
end
end
@@ -35,7 +35,7 @@ RSpec.describe "env helpers" do
gem_path = ENV["GEM_PATH"] + "#{File::PATH_SEPARATOR}/foo"
with_gem_path_as(gem_path) do
bundle_exec_ruby(bundled_app("source.rb").to_s)
- expect(last_command.stdboth).to eq(gem_path)
+ expect(stdboth).to eq(gem_path)
end
end
@@ -62,9 +62,6 @@ RSpec.describe "env helpers" do
end
it "removes variables that bundler added", :ruby_repo do
- # Simulate bundler has not yet been loaded
- ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) })
-
original = ruby('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")', artifice: "fail")
create_file("source.rb", <<-RUBY)
puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n")
@@ -74,77 +71,65 @@ RSpec.describe "env helpers" do
end
end
- shared_examples_for "an unbundling helper" do
+ describe "Bundler.unbundled_env" do
it "should delete BUNDLE_PATH" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}.has_key?('BUNDLE_PATH')
+ print Bundler.unbundled_env.has_key?('BUNDLE_PATH')
RUBY
ENV["BUNDLE_PATH"] = "./foo"
bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include "false"
+ expect(stdboth).to include "false"
end
it "should remove absolute path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYOPT']
+ print Bundler.unbundled_env['RUBYOPT']
RUBY
setup_require = "-r#{lib_dir}/bundler/setup"
ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}"
bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).not_to include(setup_require)
+ expect(stdboth).not_to include(setup_require)
end
it "should remove relative path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYOPT']
+ print Bundler.unbundled_env['RUBYOPT']
RUBY
ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).not_to include("-rbundler/setup")
+ expect(stdboth).not_to include("-rbundler/setup")
end
it "should delete BUNDLER_SETUP even if it was present in original env" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}.has_key?('BUNDLER_SETUP')
+ print Bundler.unbundled_env.has_key?('BUNDLER_SETUP')
RUBY
ENV["BUNDLER_ORIG_BUNDLER_SETUP"] = system_gem_path("gems/bundler-#{Bundler::VERSION}/lib/bundler/setup").to_s
bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include "false"
+ expect(stdboth).to include "false"
end
it "should restore RUBYLIB", :ruby_repo do
create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYLIB']
+ print Bundler.unbundled_env['RUBYLIB']
RUBY
ENV["RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo"
ENV["BUNDLER_ORIG_RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo-original"
bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include("/foo-original")
+ expect(stdboth).to include("/foo-original")
end
it "should restore the original MANPATH" do
create_file("source.rb", <<-RUBY)
- print #{modified_env}['MANPATH']
+ print Bundler.unbundled_env['MANPATH']
RUBY
ENV["MANPATH"] = "/foo"
ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original"
bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include("/foo-original")
+ expect(stdboth).to include("/foo-original")
end
end
- describe "Bundler.unbundled_env" do
- let(:modified_env) { "Bundler.unbundled_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
- describe "Bundler.clean_env", bundler: 2 do
- let(:modified_env) { "Bundler.clean_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
describe "Bundler.with_original_env" do
it "should set ENV to original_env in the block" do
expected = Bundler.original_env
@@ -161,26 +146,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.with_clean_env", bundler: 2 do
- it "should set ENV to unbundled_env in the block" do
- expected = Bundler.unbundled_env
-
- actual = Bundler.ui.silence do
- Bundler.with_clean_env { ENV.to_hash }
- end
-
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.ui.silence do
- Bundler.with_clean_env { ENV["FOO"] = "hello" }
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
describe "Bundler.with_unbundled_env" do
it "should set ENV to unbundled_env in the block" do
expected = Bundler.unbundled_env
@@ -212,21 +177,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.clean_system", bundler: 2 do
- before do
- create_file("source.rb", <<-'RUBY')
- Bundler.ui.silence { Bundler.clean_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'") }
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_clean_env" do
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(42)
- end
- end
-
describe "Bundler.unbundled_system" do
before do
create_file("source.rb", <<-'RUBY')
@@ -263,27 +213,6 @@ RSpec.describe "env helpers" do
end
end
- describe "Bundler.clean_exec", bundler: 2 do
- before do
- create_file("source.rb", <<-'RUBY')
- Process.fork do
- exit Bundler.ui.silence { Bundler.clean_exec(%(test "\$BUNDLE_FOO" = "bar")) }
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_clean_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(1)
- end
- end
-
describe "Bundler.unbundled_exec" do
before do
create_file("source.rb", <<-'RUBY')
@@ -297,7 +226,7 @@ RSpec.describe "env helpers" do
RUBY
end
- it "runs exec inside with_clean_env" do
+ it "runs exec inside with_unbundled_env" do
skip "Fork not implemented" if Gem.win_platform?
run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
diff --git a/spec/bundler/runtime/executable_spec.rb b/spec/bundler/runtime/executable_spec.rb
index a4226ed51e..89cee21b00 100644
--- a/spec/bundler/runtime/executable_spec.rb
+++ b/spec/bundler/runtime/executable_spec.rb
@@ -19,8 +19,9 @@ RSpec.describe "Running bin/* commands" do
expect(out).to eq("1.0.0")
end
- it "allows the location of the gem stubs to be specified" do
- bundle "binstubs myrack", path: "gbin"
+ it "allows the location of the gem stubs to be configured" do
+ bundle_config "bin gbin"
+ bundle "binstubs myrack"
expect(bundled_app("bin")).not_to exist
expect(bundled_app("gbin/myrackup")).to exist
@@ -30,7 +31,8 @@ RSpec.describe "Running bin/* commands" do
end
it "allows absolute paths as a specification of where to install bin stubs" do
- bundle "binstubs myrack", path: tmp("bin")
+ bundle_config "bin #{tmp("bin")}"
+ bundle "binstubs myrack"
gembin tmp("bin/myrackup")
expect(out).to eq("1.0.0")
@@ -96,38 +98,6 @@ RSpec.describe "Running bin/* commands" do
expect(bundled_app("bin/myrackup")).not_to exist
end
- it "allows you to stop installing binstubs", bundler: "< 3" do
- skip "delete permission error" if Gem.win_platform?
-
- bundle "install --binstubs bin/"
- bundled_app("bin/myrackup").rmtree
- bundle "install --binstubs \"\""
-
- expect(bundled_app("bin/myrackup")).not_to exist
-
- bundle "config bin"
- expect(out).to include("You have not configured a value for `bin`")
- end
-
- it "remembers that the option was specified", bundler: "< 3" do
- gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
- G
-
- bundle :install, binstubs: "bin"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "activesupport"
- gem "myrack"
- G
-
- bundle "install"
-
- expect(bundled_app("bin/myrackup")).to exist
- end
-
it "rewrites bins on binstubs with --force option" do
install_gemfile <<-G
source "https://gem.repo1"
diff --git a/spec/bundler/runtime/gem_tasks_spec.rb b/spec/bundler/runtime/gem_tasks_spec.rb
index 046300391b..b855142e60 100644
--- a/spec/bundler/runtime/gem_tasks_spec.rb
+++ b/spec/bundler/runtime/gem_tasks_spec.rb
@@ -66,9 +66,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do
it "includes the relevant tasks" do
define_local_gem_using_gem_tasks
- with_gem_path_as(base_system_gem_path.to_s) do
- sys_exec "#{rake} -T", env: { "GEM_HOME" => system_gem_path.to_s }
- end
+ in_bundled_app "rake -T"
expect(err).to be_empty
expected_tasks = [
@@ -85,9 +83,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do
it "defines a working `rake install` task", :ruby_repo do
define_local_gem_using_gem_tasks
- with_gem_path_as(base_system_gem_path.to_s) do
- sys_exec "#{rake} install", env: { "GEM_HOME" => system_gem_path.to_s }
- end
+ in_bundled_app "rake install"
expect(err).to be_empty
@@ -136,7 +132,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do
before do
define_local_gem_using_gem_tasks
- bundle "config set path vendor/bundle"
+ bundle_config "path vendor/bundle"
end
it "works", :ruby_repo do
@@ -155,9 +151,8 @@ RSpec.describe "require 'bundler/gem_tasks'" do
it "adds 'pkg' to rake/clean's CLOBBER" do
define_local_gem_using_gem_tasks
- with_gem_path_as(base_system_gem_path.to_s) do
- sys_exec %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect'), env: { "GEM_HOME" => system_gem_path.to_s }
- end
+ in_bundled_app %(rake -e 'load "Rakefile"; puts CLOBBER.inspect')
+
expect(out).to eq '["pkg"]'
end
end
diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb
index 48385b452d..c6f9bbdbd7 100644
--- a/spec/bundler/runtime/inline_spec.rb
+++ b/spec/bundler/runtime/inline_spec.rb
@@ -380,7 +380,7 @@ RSpec.describe "bundler/inline#gemfile" do
rake
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
script <<-RUBY
@@ -414,7 +414,7 @@ RSpec.describe "bundler/inline#gemfile" do
rake
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
script <<-RUBY
@@ -499,7 +499,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "skips platform warnings" do
- bundle "config set --local force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
script <<-RUBY
gemfile(true) do
@@ -512,7 +512,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "still installs if the application has `bundle package` no_install config set" do
- bundle "config set --local no_install true"
+ bundle_config "no_install true"
script <<-RUBY
gemfile do
@@ -590,37 +590,10 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
- it "when requiring fileutils after does not show redefinition warnings" do
- Dir.mkdir tmp("path_without_gemfile")
-
- default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", raise_on_error: false
- skip "fileutils isn't a default gem" if default_fileutils_version.empty?
-
- realworld_system_gems "fileutils --version 1.4.1"
-
- realworld_system_gems "pathname --version 0.2.0"
-
- script <<-RUBY, dir: tmp("path_without_gemfile"), env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s, "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- require "bundler/inline"
-
- gemfile(true) do
- source "https://gem.repo2"
- end
-
- require "fileutils"
- RUBY
-
- expect(err).to eq("The Gemfile specifies no dependencies")
- end
-
- it "does not load default timeout" do
+ it "does not load default timeout", rubygems: ">= 3.5.0" do
default_timeout_version = ruby "gem 'timeout', '< 999999'; require 'timeout'; puts Timeout::VERSION", raise_on_error: false
skip "timeout isn't a default gem" if default_timeout_version.empty?
- # This only works on RubyGems 3.5.0 or higher
- ruby "require 'rubygems/timeout'", raise_on_error: false
- skip "rubygems under test does not yet vendor timeout" unless last_command.success?
-
build_repo4 do
build_gem "timeout", "999"
end
@@ -705,8 +678,54 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to include("Installing psych 999")
expect(out).to include("Installing stringio 999")
- expect(out).to include("The psych gem was resolved to 999")
- expect(out).to include("The stringio gem was resolved to 999")
+ if Gem.respond_to?(:use_psych?) && Gem.use_psych?
+ expect(out).to include("The psych gem was resolved to 999")
+ expect(out).to include("The stringio gem was resolved to 999")
+ end
+ end
+
+ it "installs a conflicting default gem and non-default gems together" do
+ build_repo4 do
+ build_gem "securerandom", "999"
+ build_gem "myrack", "1.0.0"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ gemfile(true) do
+ source "https://gem.repo4"
+ gem "securerandom"
+ gem "myrack"
+ end
+
+ puts MYRACK
+ RUBY
+
+ expect(out).to include("Installing securerandom 999")
+ expect(out).to include("Installing myrack 1.0.0")
+ expect(out).to include("1.0.0")
+ expect(err).to be_empty
+ end
+
+ it "installs a conflicting default gem alongside git sources" do
+ build_repo4 do
+ build_gem "securerandom", "999"
+ end
+
+ build_git "foo", "1.0.0"
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ gemfile(true) do
+ source "https://gem.repo4"
+ gem "securerandom"
+ gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump}
+ end
+
+ puts FOO
+ RUBY
+
+ expect(out).to include("Installing securerandom 999")
+ expect(out).to include("1.0.0")
+ expect(err).to be_empty
end
it "leaves a lockfile in the same directory as the inline script alone" do
diff --git a/spec/bundler/runtime/load_spec.rb b/spec/bundler/runtime/load_spec.rb
index 15f3d0eb5b..472cde87c5 100644
--- a/spec/bundler/runtime/load_spec.rb
+++ b/spec/bundler/runtime/load_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe "Bundler.load" do
begin
expect { Bundler.load }.to raise_error(Bundler::GemfileNotFound)
ensure
- bundler_gemfile.rmtree if @remove_bundler_gemfile
+ FileUtils.rm_rf bundler_gemfile if @remove_bundler_gemfile
end
end
end
diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb
index 562184ce17..6d96758956 100644
--- a/spec/bundler/runtime/platform_spec.rb
+++ b/spec/bundler/runtime/platform_spec.rb
@@ -100,7 +100,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri (~> 1.11)
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
gemfile <<-G
@@ -143,7 +143,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -219,7 +219,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -233,7 +233,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -247,7 +247,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -282,7 +282,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
platform_specific
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -316,7 +316,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
libv8
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -344,7 +344,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
platform_specific
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
bundle "install"
@@ -377,7 +377,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
gem "platform_specific"
G
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
@@ -398,7 +398,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle :lock
simulate_platform "x86-mswin32" do
- bundle "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
bundle "install"
expect(the_bundle).to include_gems "myrack 1.0"
@@ -411,7 +411,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
s.add_dependency "platform_specific"
end
end
- simulate_platform "x64-mingw32" do
+ simulate_platform "x64-mingw-ucrt" do
lockfile <<-L
GEM
remote: https://gem.repo2/
@@ -421,7 +421,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
platform_specific
PLATFORMS
- x64-mingw32
+ x64-mingw-ucrt
x86-mingw32
DEPENDENCIES
@@ -434,11 +434,11 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
G
expect(out).to include("lockfile does not have all gems needed for the current platform")
- expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw32"
+ expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw-ucrt"
end
end
- %w[x86-mswin32 x64-mswin64 x86-mingw32 x64-mingw32 x64-mingw-ucrt aarch64-mingw-ucrt].each do |platform|
+ %w[x86-mswin32 x64-mswin64 x86-mingw32 x64-mingw-ucrt aarch64-mingw-ucrt].each do |platform|
it "allows specifying platform windows on #{platform} platform" do
simulate_platform platform do
lockfile <<-L
diff --git a/spec/bundler/runtime/requiring_spec.rb b/spec/bundler/runtime/requiring_spec.rb
index 1f32269622..f0e0aeacaf 100644
--- a/spec/bundler/runtime/requiring_spec.rb
+++ b/spec/bundler/runtime/requiring_spec.rb
@@ -2,14 +2,14 @@
RSpec.describe "Requiring bundler" do
it "takes care of requiring rubygems when entrypoint is bundler/setup" do
- sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", env: { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", env: { "RUBYOPT" => "--disable=gems" })
- expect(last_command.stdboth).to eq("true")
+ expect(stdboth).to eq("true")
end
it "takes care of requiring rubygems when requiring just bundler" do
- sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler -e'puts true'", env: { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler -e'puts true'", env: { "RUBYOPT" => "--disable=gems" })
- expect(last_command.stdboth).to eq("true")
+ expect(stdboth).to eq("true")
end
end
diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb
index a0b2d83d0e..176c2a3121 100644
--- a/spec/bundler/runtime/self_management_spec.rb
+++ b/spec/bundler/runtime/self_management_spec.rb
@@ -3,11 +3,11 @@
RSpec.describe "Self management" do
describe "auto switching" do
let(:previous_minor) do
- "2.3.0"
+ "9.3.0"
end
let(:current_version) do
- "2.4.0"
+ "9.4.0"
end
before do
@@ -24,22 +24,24 @@ RSpec.describe "Self management" do
gem "myrack"
G
+
+ pristine_system_gems "bundler-#{current_version}"
end
it "installs locked version when using system path and uses it" do
lockfile_bundled_with(previous_minor)
- bundle "config set --local path.system true"
- bundle "install", preserve_ruby_flags: true
- expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ bundle_config "path.system true"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
# It uninstalls the older system bundler
bundle "clean --force", artifice: nil
- expect(out).to eq("Removing bundler (#{Bundler::VERSION})")
+ expect(out).to eq("Removing bundler (#{current_version})")
# App now uses locked version
bundle "-v", artifice: nil
- expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+ expect(out).to eq(previous_minor)
# ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff
unless ruby_core?
@@ -48,26 +50,26 @@ RSpec.describe "Self management" do
create_file file, <<-RUBY
#!#{Gem.ruby}
require 'bundler/setup'
- puts Bundler::VERSION
+ puts '#{previous_minor}'
RUBY
file.chmod(0o777)
cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb"
- sys_exec cmd, artifice: nil
+ in_bundled_app cmd
expect(out).to eq(previous_minor)
end
# Subsequent installs use the locked version without reinstalling
bundle "install --verbose", artifice: nil
expect(out).to include("Using bundler #{previous_minor}")
- expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
end
it "installs locked version when using local path and uses it" do
lockfile_bundled_with(previous_minor)
- bundle "config set --local path vendor/bundle"
- bundle "install", preserve_ruby_flags: true
- expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ bundle_config "path vendor/bundle"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
# It does not uninstall the locked bundler
@@ -76,7 +78,11 @@ RSpec.describe "Self management" do
# App now uses locked version
bundle "-v"
- expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+ expect(out).to eq(previous_minor)
+
+ # Preserves original gem home when auto-switching
+ bundle "exec ruby -e 'puts Bundler.original_env[\"GEM_HOME\"]'"
+ expect(out).to eq(ENV["GEM_HOME"])
# ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff
unless ruby_core?
@@ -85,26 +91,26 @@ RSpec.describe "Self management" do
create_file file, <<-RUBY
#!#{Gem.ruby}
require 'bundler/setup'
- puts Bundler::VERSION
+ puts '#{previous_minor}'
RUBY
file.chmod(0o777)
cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb"
- sys_exec cmd, artifice: nil
+ in_bundled_app cmd
expect(out).to eq(previous_minor)
end
# Subsequent installs use the locked version without reinstalling
bundle "install --verbose"
expect(out).to include("Using bundler #{previous_minor}")
- expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
end
it "installs locked version when using deployment option and uses it" do
lockfile_bundled_with(previous_minor)
- bundle "config set --local deployment true"
- bundle "install", preserve_ruby_flags: true
- expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ bundle_config "deployment true"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
# It does not uninstall the locked bundler
@@ -113,12 +119,12 @@ RSpec.describe "Self management" do
# App now uses locked version
bundle "-v"
- expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+ expect(out).to eq(previous_minor)
# Subsequent installs use the locked version without reinstalling
bundle "install --verbose"
expect(out).to include("Using bundler #{previous_minor}")
- expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
end
it "does not try to install a development version" do
@@ -128,76 +134,92 @@ RSpec.describe "Self management" do
expect(out).not_to match(/restarting using that version/)
bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ expect(out).to eq(current_version)
end
it "does not try to install when --local is passed" do
lockfile_bundled_with(previous_minor)
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "myrack-1.0.0", path: local_gem_path
bundle "install --local"
expect(out).not_to match(/Installing Bundler/)
bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ expect(out).to eq(current_version)
end
it "shows a discrete message if locked bundler does not exist" do
- missing_minor = "#{Bundler::VERSION[0]}.999.999"
+ missing_minor = "#{current_version[0]}.999.999"
lockfile_bundled_with(missing_minor)
bundle "install"
- expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{Bundler::VERSION}")
+ expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{current_version}")
bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ expect(out).to eq(current_version)
end
it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do
lockfile_bundled_with(current_version)
- bundle "config set --local version #{previous_minor}"
- bundle "install", preserve_ruby_flags: true
- expect(out).to include("Bundler #{Bundler::VERSION} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ bundle_config "version #{previous_minor}"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
bundle "-v"
- expect(out).to eq(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+ expect(out).to eq(previous_minor)
+ end
+
+ it "requires the right bundler version from the config and run bundle CLI without re-exec" do
+ unless Bundler.rubygems.provides?(">= 4.1.0.dev")
+ skip "This spec can only run when Gem::BundlerVersionFinder.bundler_versions reads bundler configs"
+ end
+
+ lockfile_bundled_with(current_version)
+
+ bundle_config "version #{previous_minor}"
+ bundle_config "path.system true"
+ bundle "install"
+
+ script = bundled_app("script.rb")
+ create_file(script, "p 'executed once'")
+
+ bundle "-v", env: { "RUBYOPT" => "-r#{script}" }
+ expect(out).to eq(%("executed once"\n9.3.0))
end
it "does not try to install when using bundle config version global" do
lockfile_bundled_with(previous_minor)
- bundle "config set version system"
+ bundle_config "version system"
bundle "install"
expect(out).not_to match(/restarting using that version/)
bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ expect(out).to eq(current_version)
end
it "does not try to install when using bundle config version <dev-version>" do
lockfile_bundled_with(previous_minor)
- bundle "config set version #{previous_minor}.dev"
+ bundle_config "version #{previous_minor}.dev"
bundle "install"
expect(out).not_to match(/restarting using that version/)
bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ expect(out).to eq(current_version)
end
it "ignores malformed lockfile version" do
lockfile_bundled_with("2.3.")
bundle "install --verbose"
- expect(out).to include("Using bundler #{Bundler::VERSION}")
+ expect(out).to include("Using bundler #{current_version}")
end
it "uses the right original script when re-execing, if `$0` has been changed to something that's not a script", :ruby_repo do
- bundle "config path vendor/bundle"
-
- system_gems "bundler-9.9.9", path: vendored_gems
+ system_gems "bundler-9.9.9", path: local_gem_path
test = bundled_app("test.rb")
@@ -208,15 +230,13 @@ RSpec.describe "Self management" do
lockfile_bundled_with("9.9.9")
- sys_exec "#{Gem.ruby} #{test}", artifice: nil, raise_on_error: false
+ in_bundled_app "#{Gem.ruby} #{test}", raise_on_error: false
expect(err).to include("Could not find myrack-1.0.0")
expect(err).not_to include("this is the program name")
end
it "uses modified $0 when re-execing, if `$0` has been changed to a script", :ruby_repo do
- bundle "config path vendor/bundle"
-
- system_gems "bundler-9.9.9", path: vendored_gems
+ system_gems "bundler-9.9.9", path: local_gem_path
runner = bundled_app("runner.rb")
@@ -232,7 +252,7 @@ RSpec.describe "Self management" do
lockfile_bundled_with("9.9.9")
- sys_exec "#{Gem.ruby} #{runner} #{script}", artifice: nil, raise_on_error: false
+ in_bundled_app "#{Gem.ruby} #{runner} #{script}", raise_on_error: false
expect(err).to include("Could not find myrack-1.0.0")
end
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index 200d30302d..ceb6fcf66a 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe "Bundler.setup" do
end
it "orders the load path correctly when there are dependencies" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -163,7 +163,7 @@ RSpec.describe "Bundler.setup" do
end
it "falls back to order the load path alphabetically for backwards compatibility" do
- bundle "config set path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -286,7 +286,7 @@ RSpec.describe "Bundler.setup" do
G
bundle "install"
- bundle "config set --local deployment true"
+ bundle_config "deployment true"
ENV["BUNDLE_GEMFILE"] = "Gemfile"
ruby <<-R
@@ -303,6 +303,32 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
end
+
+ context "user sets it via `config set --local gemfile`" do
+ it "uses the value in the config" do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ gemfile bundled_app("CustomGemfile"), <<-G
+ source "https://gem.repo1"
+ gem "activesupport", "2.3.5"
+ G
+
+ bundle_config "gemfile #{bundled_app("CustomGemfile")}"
+ bundle "install"
+
+ ruby <<-R
+ require 'bundler'
+ Bundler.setup
+ require 'activesupport'
+ puts ACTIVESUPPORT
+ R
+
+ expect(out).to eq("2.3.5")
+ end
+ end
end
it "prioritizes gems in BUNDLE_PATH over gems in GEM_HOME" do
@@ -464,7 +490,7 @@ RSpec.describe "Bundler.setup" do
end
it "does not randomly change the path when specifying --path and the bundle directory becomes read only" do
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
with_read_only("#{bundled_app}/**/*") do
@@ -473,7 +499,7 @@ RSpec.describe "Bundler.setup" do
end
it "finds git gem when default bundle path becomes read only" do
- bundle "config set --local path .bundle"
+ bundle_config "path .bundle"
bundle "install"
with_read_only("#{bundled_app(".bundle")}/**/*") do
@@ -568,7 +594,7 @@ RSpec.describe "Bundler.setup" do
describe "when excluding groups" do
it "doesn't change the resolve if --without is used" do
- bundle "config set --local without rails"
+ bundle_config "without rails"
install_gemfile <<-G
source "https://gem.repo1"
gem "activesupport"
@@ -584,7 +610,7 @@ RSpec.describe "Bundler.setup" do
end
it "remembers --without and does not bail on bare Bundler.setup" do
- bundle "config set --local without rails"
+ bundle_config "without rails"
install_gemfile <<-G
source "https://gem.repo1"
gem "activesupport"
@@ -600,7 +626,7 @@ RSpec.describe "Bundler.setup" do
end
it "remembers --without and does not bail on bare Bundler.setup, even in the case of path gems no longer available" do
- bundle "config set --local without development"
+ bundle_config "without development"
path = bundled_app(File.join("vendor", "foo"))
build_lib "foo", path: path
@@ -666,7 +692,7 @@ RSpec.describe "Bundler.setup" do
end
it "remembers --without and does not include groups passed to Bundler.setup" do
- bundle "config set --local without rails"
+ bundle_config "without rails"
install_gemfile <<-G
source "https://gem.repo1"
gem "activesupport"
@@ -728,46 +754,52 @@ RSpec.describe "Bundler.setup" do
G
run <<-R
- File.open(File.join(Gem.dir, "specifications", "broken.gemspec"), "w") do |f|
+ File.open(File.join(Gem.dir, "specifications", "invalid.gemspec"), "w") do |f|
f.write <<-RUBY
# -*- encoding: utf-8 -*-
-# stub: broken 1.0.0 ruby lib
+# stub: invalid 1.0.0 ruby lib
Gem::Specification.new do |s|
- s.name = "broken"
+ s.name = "invalid"
s.version = "1.0.0"
- raise "BROKEN GEMSPEC"
+ s.authors = ["Invalid Author"]
+ s.files = ["lib/invalid.rb"]
+ s.add_dependency "nonexistent-gem", "~> 999.999.999"
+ s.validate!
end
RUBY
end
R
run <<-R
- File.open(File.join(Gem.dir, "specifications", "broken-ext.gemspec"), "w") do |f|
+ File.open(File.join(Gem.dir, "specifications", "invalid-ext.gemspec"), "w") do |f|
f.write <<-RUBY
# -*- encoding: utf-8 -*-
-# stub: broken-ext 1.0.0 ruby lib
+# stub: invalid-ext 1.0.0 ruby lib
# stub: a.ext\\0b.ext
Gem::Specification.new do |s|
- s.name = "broken-ext"
+ s.name = "invalid-ext"
s.version = "1.0.0"
- raise "BROKEN GEMSPEC EXT"
+ s.authors = ["Invalid Author"]
+ s.files = ["lib/invalid.rb"]
+ s.required_ruby_version = "~> 0.8.0"
+ s.validate!
end
RUBY
end
# Need to write the gem.build_complete file,
# otherwise the full spec is loaded to check the installed_by_version
extensions_dir = Gem.default_ext_dir_for(Gem.dir) || File.join(Gem.dir, "extensions", Gem::Platform.local.to_s, Gem.extension_api_version)
- Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "broken-ext-1.0.0"))
- File.open(File.join(extensions_dir, "broken-ext-1.0.0", "gem.build_complete"), "w") {}
+ Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "invalid-ext-1.0.0"))
+ File.open(File.join(extensions_dir, "invalid-ext-1.0.0", "gem.build_complete"), "w") {}
R
run <<-R
- puts "WIN"
+ puts "Success"
R
- expect(out).to eq("WIN")
+ expect(out).to eq("Success")
end
it "ignores empty gem paths" do
@@ -1082,7 +1114,7 @@ end
describe "with system gems in the bundle" do
before :each do
- bundle "config set path.system true"
+ bundle_config "path.system true"
system_gems "myrack-1.0.0"
install_gemfile <<-G
@@ -1151,7 +1183,7 @@ end
bundler_module = class << Bundler; self; end
bundler_module.send(:remove_method, :require)
def Bundler.require(path)
- raise "LOSE"
+ raise StandardError, "didn't use binding from top level"
end
Bundler.load
RUBY
@@ -1196,7 +1228,7 @@ end
end
before do
- bundle "config set --local path.system true"
+ bundle_config "path.system true"
install_gemfile <<-G
source "https://gem.repo1"
@@ -1261,7 +1293,7 @@ end
lock += <<~L
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lock
@@ -1277,7 +1309,12 @@ end
end
context "is not present" do
- it "does not change the lock" do
+ # Skipped on ruby-core because `ruby "require 'bundler/setup'"` does not
+ # activate bundler as a gem there, so Source::Metadata falls back to a
+ # synthetic spec whose cache_file does not exist on disk and
+ # LockfileGenerator#bundler_checksum drops the bundler checksum, while
+ # the on-disk lockfile still has it.
+ it "does not change the lock", :ruby_repo do
expect { ruby "require 'bundler/setup'" }.not_to change { lockfile }
end
end
@@ -1323,7 +1360,7 @@ end
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
- bundle :install
+ bundle :install, env: { "BUNDLE_LOCKFILE_CHECKSUMS" => "false" }
ruby <<-RUBY, artifice: nil
require 'bundler/setup'
@@ -1406,7 +1443,6 @@ end
describe "default gem activation" do
let(:exemptions) do
exempts = %w[did_you_mean bundler uri pathname]
- exempts << "etc" if (Gem.ruby_version < Gem::Version.new("3.2") || Gem.ruby_version >= Gem::Version.new("3.3.2")) && Gem.win_platform?
exempts << "error_highlight" # added in Ruby 3.1 as a default gem
exempts << "ruby2_keywords" # added in Ruby 3.1 as a default gem
exempts << "syntax_suggest" # added in Ruby 3.2 as a default gem
@@ -1465,7 +1501,7 @@ end
install_gemfile "source 'https://gem.repo1'"
create_file("script.rb", "#!/usr/bin/env ruby\n\n#{code}")
FileUtils.chmod(0o777, bundled_app("script.rb"))
- bundle "exec ./script.rb", artifice: nil, env: { "RUBYOPT" => activation_warning_hack_rubyopt }
+ bundle "exec ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
@@ -1481,7 +1517,7 @@ end
gem "net-http-pipeline", "1.0.1"
G
- bundle "config set --local path vendor/bundle"
+ bundle_config "path vendor/bundle"
bundle :install
@@ -1525,22 +1561,7 @@ end
end
describe "after setup" do
- it "allows calling #gem on random objects", bundler: "< 3" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- ruby <<-RUBY
- require "bundler/setup"
- Object.new.gem "myrack"
- puts Gem.loaded_specs["myrack"].full_name
- RUBY
-
- expect(out).to eq("myrack-1.0.0")
- end
-
- it "keeps Kernel#gem private", bundler: "3" do
+ it "keeps Kernel#gem private" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
@@ -1552,7 +1573,7 @@ end
puts "FAIL"
RUBY
- expect(last_command.stdboth).not_to include "FAIL"
+ expect(stdboth).not_to include "FAIL"
expect(err).to match(/private method [`']gem'/)
end
@@ -1568,7 +1589,7 @@ end
puts "FAIL"
RUBY
- expect(last_command.stdboth).not_to include "FAIL"
+ expect(stdboth).not_to include "FAIL"
expect(err).to match(/private method [`']require'/)
end
@@ -1647,7 +1668,7 @@ end
gem "myrack", :group => :test
G
- bundle "config set auto_install 1"
+ bundle_config "auto_install 1"
ruby <<-RUBY, artifice: "compact_index"
require 'bundler/setup'
@@ -1672,7 +1693,7 @@ end
DEPENDENCIES
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
end
diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb
index 470bf3e414..27ddc6a771 100644
--- a/spec/bundler/spec_helper.rb
+++ b/spec/bundler/spec_helper.rb
@@ -9,18 +9,26 @@ if File.expand_path(__FILE__) =~ %r{([^\w/\.:\-])}
abort "The bundler specs cannot be run from a path that contains special characters (particularly #{$1.inspect})"
end
-# Bundler CLI will have different help text depending on whether this variable
-# is set, since the `-e` flag `bundle gem` with require an explicit value if
-# `EDITOR` is not set, but will use `EDITOR` by default is set. So make sure
-# it's `nil` before loading bundler to get a consistent help text, since some
-# tests rely on that.
+# Bundler CLI will have different help text depending on whether any of these
+# variables is set, since the `-e` flag `bundle gem` with require an explicit
+# value if they are not set, but will use their value by default if set. So make
+# sure they are `nil` before loading bundler to get a consistent help text,
+# since some tests rely on that.
ENV["EDITOR"] = nil
+ENV["VISUAL"] = nil
+ENV["BUNDLER_EDITOR"] = nil
require "bundler"
+# If we use shared GEM_HOME and install multiple versions, it may cause
+# unexpected test failures.
+gem "diff-lcs", "< 2.0"
+
require "rspec/core"
require "rspec/expectations"
require "rspec/mocks"
require "rspec/support/differ"
+gem "rubygems-generate_index"
+require "rubygems/indexer"
require_relative "support/builders"
require_relative "support/checksums"
@@ -30,6 +38,38 @@ require_relative "support/indexes"
require_relative "support/matchers"
require_relative "support/permissions"
require_relative "support/platforms"
+require_relative "support/shards"
+
+begin
+ raise LoadError if File.exist?(File.expand_path("../../lib/bundler/bundler.gemspec", __dir__))
+
+ gem "simplecov_json_formatter"
+ require "simplecov"
+
+ SimpleCov.start do
+ command_name "bundler:#{Process.pid}"
+ root File.expand_path("../bundler", __dir__)
+ coverage_dir File.expand_path("../coverage", __dir__)
+
+ add_filter "/spec/"
+ add_filter "/test/"
+ add_filter "/lib/rubygems/"
+ add_filter "/lib/bundler/vendor/"
+ add_filter "/tool/"
+ add_filter "/tmp/"
+ add_filter ".gemspec"
+ end
+
+ SimpleCov.print_error_status = false
+ SimpleCov.at_exit do
+ $stdout = File.open(File::NULL, "w")
+ SimpleCov.result.format!
+ ensure
+ $stdout = STDOUT
+ end
+rescue LoadError
+ # SimpleCov is not installed
+end
$debug = false
@@ -48,6 +88,7 @@ RSpec.configure do |config|
config.include Spec::Path
config.include Spec::Platforms
config.include Spec::Permissions
+ config.include Spec::Shards
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
@@ -82,28 +123,42 @@ RSpec.configure do |config|
require_relative "support/rubygems_ext"
Spec::Rubygems.test_setup
+
+ # Disable retry delays in tests to speed them up
+ Bundler::Retry.default_base_delay = 0
+
+ # Simulate bundler has not yet been loaded
+ ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) })
+
ENV["BUNDLER_SPEC_RUN"] = "true"
ENV["BUNDLE_USER_CONFIG"] = ENV["BUNDLE_USER_CACHE"] = ENV["BUNDLE_USER_PLUGIN"] = nil
ENV["BUNDLE_APP_CONFIG"] = nil
ENV["BUNDLE_SILENCE_ROOT_WARNING"] = nil
ENV["RUBYGEMS_GEMDEPS"] = nil
ENV["XDG_CONFIG_HOME"] = nil
+ ENV["XDG_CACHE_HOME"] = nil
ENV["GEMRC"] = nil
+ # Prevent tests from modifying the user's global git config.
+ # GIT_CONFIG_GLOBAL and GIT_CONFIG_NOSYSTEM are available since Git 2.32.
+ git_version = `git --version`[/(\d+\.\d+\.\d+)/, 1]
+ if Gem::Version.new(git_version) >= Gem::Version.new("2.32")
+ ENV["GIT_CONFIG_GLOBAL"] = File.join(ENV["HOME"], ".gitconfig")
+ ENV["GIT_CONFIG_NOSYSTEM"] = "1"
+ end
+
# Don't wrap output in tests
ENV["THOR_COLUMNS"] = "10000"
extend(Spec::Builders)
- check_test_gems!
-
build_repo1
- reset_paths!
+ reset!
end
config.around :each do |example|
- FileUtils.cp_r pristine_system_gem_path, system_gem_path
+ default_system_gems
with_gem_path_as(system_gem_path) do
Bundler.ui.silence { example.run }
@@ -120,7 +175,18 @@ RSpec.configure do |config|
reset!
end
- config.after :suite do
- FileUtils.rm_r Spec::Path.pristine_system_gem_path
+ Spec::Shards::EXAMPLE_MAPPINGS.each do |tag, file_paths|
+ file_pattern = Regexp.union(file_paths.map {|path| Regexp.new(Regexp.escape(path) + "$") })
+
+ config.define_derived_metadata(file_path: file_pattern) do |metadata|
+ metadata[tag] = true
+ end
end
+
+ config.before(:context) do |example|
+ metadata = example.class.metadata
+ if metadata[:type] != :aruba && !metadata[:realworld] && metadata.keys.none? {|k| Spec::Shards::EXAMPLE_MAPPINGS.keys.include?(k) }
+ warn "#{metadata[:file_path]} is not assigned to any shard. see spec/support/shards.rb for details."
+ end
+ end unless Spec::Path.ruby_core?
end
diff --git a/spec/bundler/support/artifice/compact_index_cooldown.rb b/spec/bundler/support/artifice/compact_index_cooldown.rb
new file mode 100644
index 0000000000..85e3173c98
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_cooldown.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index_cooldown"
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexCooldownAPI)
diff --git a/spec/bundler/support/artifice/compact_index_etag_match.rb b/spec/bundler/support/artifice/compact_index_etag_match.rb
index 08d7b5ec53..6c62166051 100644
--- a/spec/bundler/support/artifice/compact_index_etag_match.rb
+++ b/spec/bundler/support/artifice/compact_index_etag_match.rb
@@ -4,7 +4,7 @@ require_relative "helpers/compact_index"
class CompactIndexEtagMatch < CompactIndexAPI
get "/versions" do
- raise "ETag header should be present" unless env["HTTP_IF_NONE_MATCH"]
+ raise ArgumentError, "ETag header should be present" unless env["HTTP_IF_NONE_MATCH"]
headers "ETag" => env["HTTP_IF_NONE_MATCH"]
status 304
body ""
diff --git a/spec/bundler/support/artifice/compact_index_mirror_down.rb b/spec/bundler/support/artifice/compact_index_mirror_down.rb
new file mode 100644
index 0000000000..88983c715d
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_mirror_down.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+require_relative "helpers/artifice"
+require_relative "helpers/rack_request"
+
+module Artifice
+ module Net
+ class HTTPMirrorDown < HTTP
+ def connect
+ raise SocketError if address == "gem.mirror"
+
+ super
+ end
+ end
+
+ HTTP.endpoint = CompactIndexAPI
+ end
+
+ replace_net_http(Net::HTTPMirrorDown)
+end
diff --git a/spec/bundler/support/artifice/compact_index_no_checksums.rb b/spec/bundler/support/artifice/compact_index_no_checksums.rb
new file mode 100644
index 0000000000..ecb7fc7d7c
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_no_checksums.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+
+class CompactIndexNoChecksums < CompactIndexAPI
+ get "/info/:name" do
+ etag_response do
+ gem = gems.find {|g| g.name == params[:name] }
+ gem.versions.map(&:number).join("\n")
+ end
+ end
+end
+
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexNoChecksums)
diff --git a/spec/bundler/support/artifice/helpers/compact_index.rb b/spec/bundler/support/artifice/helpers/compact_index.rb
index ba331e483f..e684aa8628 100644
--- a/spec/bundler/support/artifice/helpers/compact_index.rb
+++ b/spec/bundler/support/artifice/helpers/compact_index.rb
@@ -2,7 +2,7 @@
require_relative "endpoint"
-$LOAD_PATH.unshift Dir[Spec::Path.base_system_gem_path.join("gems/compact_index*/lib")].first.to_s
+$LOAD_PATH.unshift Spec::Path.tmp_root.join("compact_index/lib").to_s
require "compact_index"
require "digest"
@@ -90,13 +90,17 @@ class CompactIndexAPI < Endpoint
rescue StandardError
checksum = nil
end
- CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
- deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s)
+ build_gem_version(spec, deps, checksum)
end
CompactIndex::Gem.new(name, gem_versions)
end
end
end
+
+ def build_gem_version(spec, deps, checksum)
+ CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
+ deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s)
+ end
end
get "/names" do
diff --git a/spec/bundler/support/artifice/helpers/compact_index_cooldown.rb b/spec/bundler/support/artifice/helpers/compact_index_cooldown.rb
new file mode 100644
index 0000000000..9920fd2c95
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/compact_index_cooldown.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require_relative "compact_index"
+
+class CompactIndexCooldownAPI < CompactIndexAPI
+ helpers do
+ def build_gem_version(spec, deps, checksum)
+ created_at = spec.date&.utc&.iso8601
+ CompactIndex::GemVersionV2.new(spec.version.version, spec.platform.to_s, checksum, nil,
+ deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s, created_at)
+ end
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/endpoint.rb b/spec/bundler/support/artifice/helpers/endpoint.rb
index 1ceadb5900..9590611dfe 100644
--- a/spec/bundler/support/artifice/helpers/endpoint.rb
+++ b/spec/bundler/support/artifice/helpers/endpoint.rb
@@ -27,7 +27,7 @@ class Endpoint < Sinatra::Base
set :raise_errors, true
set :show_exceptions, false
- set :host_authorization, permitted_hosts: [".example.org", ".local", ".repo", ".repo1", ".repo2", ".repo3", ".repo4", ".rubygems.org", ".security", ".source", ".test", "127.0.0.1"]
+ set :host_authorization, permitted_hosts: [".example.org", ".local", ".mirror", ".repo", ".repo1", ".repo2", ".repo3", ".repo4", ".rubygems.org", ".security", ".source", ".test", "127.0.0.1"]
def call!(*)
super.tap do
diff --git a/spec/bundler/support/artifice/vcr.rb b/spec/bundler/support/artifice/vcr.rb
index 2386a4c6b7..0bf5ade8f6 100644
--- a/spec/bundler/support/artifice/vcr.rb
+++ b/spec/bundler/support/artifice/vcr.rb
@@ -24,7 +24,7 @@ class BundlerVCRHTTP < Gem::Net::HTTP
end
File.open(USED_CASSETTES_PATH, "a+") do |f|
- f.puts request_pair_paths.map {|path| Pathname.new(path).relative_path_from(Spec::Path.source_root).to_s }.join("\n")
+ f.puts request_pair_paths.map {|path| Pathname.new(path).relative_path_from(Spec::Path.git_root).to_s }.join("\n")
end
if recorded_response?
diff --git a/spec/bundler/support/build_metadata.rb b/spec/bundler/support/build_metadata.rb
index 189100edb7..2eade4137b 100644
--- a/spec/bundler/support/build_metadata.rb
+++ b/spec/bundler/support/build_metadata.rb
@@ -8,11 +8,10 @@ module Spec
include Spec::Path
include Spec::Helpers
- def write_build_metadata(dir: source_root)
+ def write_build_metadata(dir: source_root, version: Bundler::VERSION)
build_metadata = {
git_commit_sha: git_commit_sha,
- built_at: loaded_gemspec.date.utc.strftime("%Y-%m-%d"),
- release: true,
+ built_at: release_date_for(version, dir: dir),
}
replace_build_metadata(build_metadata, dir: dir)
@@ -20,7 +19,7 @@ module Spec
def reset_build_metadata(dir: source_root)
build_metadata = {
- release: false,
+ built_at: nil,
}
replace_build_metadata(build_metadata, dir: dir)
@@ -44,6 +43,11 @@ module Spec
ruby_core_tarball? ? "unknown" : git("rev-parse --short HEAD", source_root).strip
end
+ def release_date_for(version, dir:)
+ changelog = File.expand_path("CHANGELOG.md", dir)
+ File.readlines(changelog)[2].scan(/^## #{Regexp.escape(version)} \((.*)\)/).first&.first if File.exist?(changelog)
+ end
+
extend self
end
end
diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb
index 13c21bf5cc..43ab7e053d 100644
--- a/spec/bundler/support/builders.rb
+++ b/spec/bundler/support/builders.rb
@@ -2,6 +2,8 @@
require "bundler/shared_helpers"
require "shellwords"
+require "fileutils"
+require "rubygems/package"
require_relative "build_metadata"
@@ -24,10 +26,6 @@ module Spec
Gem::Platform.new(platform)
end
- def rake_version
- "13.2.1"
- end
-
def build_repo1
build_repo gem_repo1 do
FileUtils.cp rake_path, "#{gem_repo1}/gems/"
@@ -111,10 +109,6 @@ module Spec
end
build_gem "platform_specific" do |s|
- s.platform = "x64-mingw32"
- end
-
- build_gem "platform_specific" do |s|
s.platform = "x64-mingw-ucrt"
end
@@ -193,17 +187,25 @@ module Spec
# A repo that has no pre-installed gems included. (The caller completely
# determines the contents with the block.)
+ #
+ # If the repo already exists, `#update_repo` will be called.
def build_repo3(**kwargs, &blk)
- raise "gem_repo3 already exists -- use update_repo3 instead" if File.exist?(gem_repo3)
- build_repo gem_repo3, **kwargs, &blk
+ if File.exist?(gem_repo3)
+ update_repo(gem_repo3, &blk)
+ else
+ build_repo gem_repo3, **kwargs, &blk
+ end
end
# Like build_repo3, this is a repo that has no pre-installed gems included.
- # We have two different methods for situations where two different empty
- # sources are needed.
+ #
+ # If the repo already exists, `#udpate_repo` will be called
def build_repo4(**kwargs, &blk)
- raise "gem_repo4 already exists -- use update_repo4 instead" if File.exist?(gem_repo4)
- build_repo gem_repo4, **kwargs, &blk
+ if File.exist?(gem_repo4)
+ update_repo gem_repo4, &blk
+ else
+ build_repo gem_repo4, **kwargs, &blk
+ end
end
def update_repo2(**kwargs, &blk)
@@ -214,10 +216,6 @@ module Spec
update_repo(gem_repo3, &blk)
end
- def update_repo4(&blk)
- update_repo(gem_repo4, &blk)
- end
-
def build_security_repo
build_repo security_repo do
build_gem "myrack"
@@ -276,16 +274,8 @@ module Spec
update_repo(path,**kwargs, &blk)
end
- def check_test_gems!
- if rake_path.nil?
- Spec::Rubygems.install_test_deps
- end
-
- Helpers.install_dev_bundler unless pristine_system_gem_path.exist?
- end
-
def update_repo(path, build_compact_index: true)
- exempted_caller = Gem.ruby_version >= Gem::Version.new("3.4.0.dev") ? "#{Module.nesting.first}#build_repo" : "build_repo"
+ exempted_caller = Gem.ruby_version >= Gem::Version.new("3.4.0.dev") && RUBY_ENGINE != "jruby" ? "#{Module.nesting.first}#build_repo" : "build_repo"
if path == gem_repo1 && caller_locations(1, 1).first.label != exempted_caller
raise "Updating gem_repo1 is unsupported -- use gem_repo2 instead"
end
@@ -293,14 +283,8 @@ module Spec
@_build_path = "#{path}/gems"
@_build_repo = File.basename(path)
yield
- with_gem_path_as base_system_gem_path do
- Dir[base_system_gem_path.join("gems/rubygems-generate_index*/lib")].first ||
- raise("Could not find rubygems-generate_index lib directory in #{base_system_gem_path}")
-
- command = "generate_index"
- command += " --no-compact" if !build_compact_index && gem_command(command + " --help").include?("--[no-]compact")
- gem_command command, dir: path
- end
+ options = { build_compact: build_compact_index }
+ Gem::Indexer.new(path, options).generate_index
ensure
@_build_path = nil
@_build_repo = nil
@@ -439,18 +423,23 @@ module Spec
end
class BundlerBuilder
- attr_writer :required_ruby_version
-
def initialize(context, name, version)
- raise "can only build bundler" unless name == "bundler"
-
@context = context
- @version = version || Bundler::VERSION
+ @spec = Spec::Path.loaded_gemspec.dup
+ @spec.version = version || Bundler::VERSION
+ end
+
+ def required_ruby_version
+ @spec.required_ruby_version
+ end
+
+ def required_ruby_version=(x)
+ @spec.required_ruby_version = x
end
def _build(options = {})
- full_name = "bundler-#{@version}"
- build_path = @context.tmp + full_name
+ full_name = "bundler-#{@spec.version}"
+ build_path = (options[:build_path] || @context.tmp) + full_name
bundler_path = build_path + "#{full_name}.gem"
FileUtils.mkdir_p build_path
@@ -461,15 +450,19 @@ module Spec
target_shipped_file = build_path + target_shipped_file
target_shipped_dir = File.dirname(target_shipped_file)
FileUtils.mkdir_p target_shipped_dir unless File.directory?(target_shipped_dir)
- FileUtils.cp shipped_file, target_shipped_file, preserve: true
+ FileUtils.cp File.expand_path(shipped_file, @context.source_root), target_shipped_file, preserve: true
end
- @context.replace_version_file(@version, dir: build_path)
- @context.replace_required_ruby_version(@required_ruby_version, dir: build_path) if @required_ruby_version
+ @context.replace_version_file(@spec.version, dir: build_path)
+ @context.replace_changelog(@spec.version, dir: build_path) if options[:released]
- Spec::BuildMetadata.write_build_metadata(dir: build_path)
+ Spec::BuildMetadata.write_build_metadata(dir: build_path, version: @spec.version.to_s)
- @context.gem_command "build #{@context.relative_gemspec}", dir: build_path
+ Dir.chdir build_path do
+ Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do
+ Gem::Package.build(@spec)
+ end
+ end
if block_given?
yield(bundler_path)
@@ -477,7 +470,7 @@ module Spec
FileUtils.mv bundler_path, options[:path]
end
ensure
- build_path.rmtree
+ FileUtils.rm_rf build_path
end
end
@@ -671,9 +664,9 @@ module Spec
Bundler.rubygems.build(@spec, opts[:skip_validation])
end
elsif opts[:skip_validation]
- @context.gem_command "build --force #{@spec.name}", dir: lib_path
+ Dir.chdir(lib_path) { Gem::Package.build(@spec, true) }
else
- @context.gem_command "build #{@spec.name}", dir: lib_path, allowed_warning: opts[:allowed_warning]
+ Dir.chdir(lib_path) { Gem::Package.build(@spec) }
end
gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path)
@@ -702,54 +695,54 @@ module Spec
TEST_CERT = <<~CERT
-----BEGIN CERTIFICATE-----
- MIIDMjCCAhqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAnMQwwCgYDVQQDDAN5b3Ux
+ MIIDNTCCAh2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAnMQwwCgYDVQQDDAN5b3Ux
FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTE1MDIwODAwMTIyM1oXDTQyMDYy
NTAwMTIyM1owJzEMMAoGA1UEAwwDeW91MRcwFQYKCZImiZPyLGQBGRYHZXhhbXBs
- ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANlvFdpN43c4DMS9Jo06
- m0a7k3bQ3HWQ1yrYhZMi77F1F73NpBknYHIzDktQpGn6hs/4QFJT4m4zNEBF47UL
- jHU5nTK5rjkS3niGYUjvh3ZEzVeo9zHUlD/UwflDo4ALl3TSo2KY/KdPS/UTdLXL
- ajkQvaVJtEDgBPE3DPhlj5whp+Ik3mDHej7qpV6F502leAwYaFyOtlEG/ZGNG+nZ
- L0clH0j77HpP42AylHDi+vakEM3xcjo9BeWQ6Vkboic93c9RTt6CWBWxMQP7Nol1
- MOebz9XOSQclxpxWteXNfPRtMdAhmRl76SMI8ywzThNPpa4EH/yz34ftebVOgKyM
- nd0CAwEAAaNpMGcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFA7D
- n9qo0np23qi3aOYuAAPn/5IdMBYGA1UdEQQPMA2BC3lvdUBleGFtcGxlMBYGA1Ud
- EgQPMA2BC3lvdUBleGFtcGxlMA0GCSqGSIb3DQEBBQUAA4IBAQA7Gyk62sWOUX/N
- vk4tJrgKESph6Ns8+E36A7n3jt8zCep8ldzMvwTWquf9iqhsC68FilEoaDnUlWw7
- d6oNuaFkv7zfrWGLlvqQJC+cu2X5EpcCksg5oRp8VNbwJysJ6JgwosxzROII8eXc
- R+j1j6mDvQYqig2QOnzf480pjaqbP+tspfDFZbhKPrgM3Blrb3ZYuFpv4zkqI7aB
- 6fuk2DUhNO1CuwrJA84TqC+jGo73bDKaT5hrIDiaJRrN5+zcWja2uEWrj5jSbep4
- oXdEdyH73hOHMBP40uds3PqnUsxEJhzjB2sCCe1geV24kw9J4m7EQXPVkUKDgKrt
- LlpDmOoo
+ ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMkupYkg3Nd1oXM3fo0d
+ mVJBWNrni88lKDuIIQXwcKe6XCgiloZG708ecLTOws9+o9MkTl9Wtpf/WGXT98NK
+ EPUYakd2Fv1SuD1jWYlP7iDR6hB3RkWBm5ziujYftVJ4ZrPD42PLjDASvlh75Tvr
+ MeM7yq/qkcgNsd9dQyUvMNPks3tla9je7Dt7Auli2IN3CNXys7gIOfwJH0Bb/M6t
+ y7oUfpoUKAfLzwe61abztgDu1lSNgdFBM1kcxYflyh/FkX5TlAcWeAXzLrnxAXGR
+ UxXrxW4oPC+kZi/pDRBd7X4zQDx7bCmr1+FsS3M05i3w5E08Tt9iKRk4V8nCmE4i
+ k6UCAwEAAaNsMGowCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYE
+ FOOOFw5TNAqt/TcRRZEU3Dg/58XuMBYGA1UdEQQPMA2BC3lvdUBleGFtcGxlMBYG
+ A1UdEgQPMA2BC3lvdUBleGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQAy3xnmobxU
+ 1SyhHvoIXTJmG0wt1DQ/Dqwjy362LpEf1UHt29wtg1Mph58eVtl93z5Vd2t4/O77
+ E2BHpSu9ujc6/Br4+2uA/Qk/xRyLBtZAwty6J4uFvOOg985HonN+RCUZbKSUTmtA
+ TZvNtIDAZFQ8Tu75K4gIBxDcz7biGi4i1VJ3F3GNCNeossr9IQwKvb+UWFq14U5R
+ IzUnGgMIzcjUG2kKQvddRD1CjS+egtcLvShbOfm5bs4w4rfQ2FPF+Aaf9v7fxa/c
+ Jrf3K+cB19eAy7O4nlPG1xurvnZd0QpqRk++werrBuKe1Pgga7YBLePfJhzwqcZv
+ wVOSsB870yeO
-----END CERTIFICATE-----
CERT
TEST_PKEY = <<~PKEY
-----BEGIN RSA PRIVATE KEY-----
- MIIEowIBAAKCAQEA2W8V2k3jdzgMxL0mjTqbRruTdtDcdZDXKtiFkyLvsXUXvc2k
- GSdgcjMOS1CkafqGz/hAUlPibjM0QEXjtQuMdTmdMrmuORLeeIZhSO+HdkTNV6j3
- MdSUP9TB+UOjgAuXdNKjYpj8p09L9RN0tctqORC9pUm0QOAE8TcM+GWPnCGn4iTe
- YMd6PuqlXoXnTaV4DBhoXI62UQb9kY0b6dkvRyUfSPvsek/jYDKUcOL69qQQzfFy
- Oj0F5ZDpWRuiJz3dz1FO3oJYFbExA/s2iXUw55vP1c5JByXGnFa15c189G0x0CGZ
- GXvpIwjzLDNOE0+lrgQf/LPfh+15tU6ArIyd3QIDAQABAoIBACbDqz20TS1gDMa2
- gj0DidNedbflHKjJHdNBru7Ad8NHgOgR1YO2hXdWquG6itVqGMbTF4SV9/R1pIcg
- 7qvEV1I+50u31tvOBWOvcYCzU48+TO2n7gowQA3xPHPYHzog1uu48fAOHl0lwgD7
- av9OOK3b0jO5pC08wyTOD73pPWU0NrkTh2+N364leIi1pNuI1z4V+nEuIIm7XpVd
- 5V4sXidMTiEMJwE6baEDfTjHKaoRndXrrPo3ryIXmcX7Ag1SwAQwF5fBCRToCgIx
- dszEZB1bJD5gA6r+eGnJLB/F60nK607az5o3EdguoB2LKa6q6krpaRCmZU5svvoF
- J7xgBPECgYEA8RIzHAQ3zbaibKdnllBLIgsqGdSzebTLKheFuigRotEV3Or/z5Lg
- k/nVnThWVkTOSRqXTNpJAME6a4KTdcVSxYP+SdZVO1esazHrGb7xPVb7MWSE1cqp
- WEk3Yy8OUOPoPQMc4dyGzd30Mi8IBB6gnFIYOTrpUo0XtkBv8rGGhfsCgYEA5uYn
- 6QgL4NqNT84IXylmMb5ia3iBt6lhxI/A28CDtQvfScl4eYK0IjBwdfG6E1vJgyzg
- nJzv3xEVo9bz+Kq7CcThWpK5JQaPnsV0Q74Wjk0ShHet15txOdJuKImnh5F6lylC
- GTLR9gnptytfMH/uuw4ws0Q2kcg4l5NHKOWOnAcCgYEAvAwIVkhsB0n59Wu4gCZu
- FUZENxYWUk/XUyQ6KnZrG2ih90xQ8+iMyqFOIm/52R2fFKNrdoWoALC6E3ct8+ZS
- pMRLrelFXx8K3it4SwMJR2H8XBEfFW4bH0UtsW7Zafv+AunUs9LETP5gKG1LgXsq
- qgXX43yy2LQ61O365YPZfdUCgYBVbTvA3MhARbvYldrFEnUL3GtfZbNgdxuD9Mee
- xig0eJMBIrgfBLuOlqtVB70XYnM4xAbKCso4loKSHnofO1N99siFkRlM2JOUY2tz
- kMWZmmxKdFjuF0WZ5f/5oYxI/QsFGC+rUQEbbWl56mMKd5qkvEhKWudxoklF0yiV
- ufC8SwKBgDWb8iWqWN5a/kfvKoxFcDM74UHk/SeKMGAL+ujKLf58F+CbweM5pX9C
- EUsxeoUEraVWTiyFVNqD81rCdceus9TdBj0ZIK1vUttaRZyrMAwF0uQSfjtxsOpd
- l69BkyvzjgDPkmOHVGiSZDLi3YDvypbUpo6LOy4v5rVg5U2F/A0v
+ MIIEowIBAAKCAQEAyS6liSDc13Whczd+jR2ZUkFY2ueLzyUoO4ghBfBwp7pcKCKW
+ hkbvTx5wtM7Cz36j0yROX1a2l/9YZdP3w0oQ9RhqR3YW/VK4PWNZiU/uINHqEHdG
+ RYGbnOK6Nh+1Unhms8PjY8uMMBK+WHvlO+sx4zvKr+qRyA2x311DJS8w0+Sze2Vr
+ 2N7sO3sC6WLYg3cI1fKzuAg5/AkfQFv8zq3LuhR+mhQoB8vPB7rVpvO2AO7WVI2B
+ 0UEzWRzFh+XKH8WRflOUBxZ4BfMuufEBcZFTFevFbig8L6RmL+kNEF3tfjNAPHts
+ KavX4WxLczTmLfDkTTxO32IpGThXycKYTiKTpQIDAQABAoIBABpyrHEWRed5X7aN
+ kXCBzKSN/LLChT8VNnB6bppLnV501yVbmV2hDlg2EJZkfCMvwIptwnPcKs2uqZ4G
+ u2gMC6X9Bgkg/YK4u4nZJBiIzoMNYEUL48wYGYS1dcokaapO3nQ8M1+XjyAexrFL
+ 5btL1IIisScRTQWiGe6FtzcN43sSNkBISyDF5zG4Kodynqi0ekITmMl2q5XLWcsM
+ KBnmZcRFEmFae2YYczVy8SXNApkZEvN69znvAX1iDNnZ3sJFchXo1nRPt4stOOKw
+ mydgIYqaNQ22aF3OkblvoA4Y4m+X2Qt1sfkryKa5xTT7DSE81GmmazNI64EWqtES
+ 6Xde6P0CgYEA+V1vuSnE5fWX188abWMbVwNMC71WfHbntFmI+qwWYPEpickm+RGX
+ DDfXs5unlVX4KUmjfplgavO29op1GZTuD9TlRnUAV0+0aJnNq4DY6XsHfD84qsBr
+ gQGEHeJ1cMGNDnZR/EV3eudMalj9Qjpx9NoXNzMykb0/SUYZQemiqwcCgYEAzokC
+ s0GoHVJqan4dfU0h0G5QPncrajW9DGG1ySxK/A2eqbVB8W2ZQx39OS26/Gydb31p
+ cR7zm8PZpNbzLqlIMEbD4F6q22xxvYVtDx/HHPjxHMi87yxwQ9uLDUHoMa/LciTO
+ djv3D1xTDDGxbpjmsdmINetunAs3htxku7JY5PMCgYBs3/TVvXzwgmhHm28Ib4sS
+ VKgxP/uw4CGORsFd4SDsNp9SP3c6rAltFjyheMaUlzKApFwz/DdyuvIZdp5mCvZe
+ BzALsS3y8SPtv6lixiDu3/6GqvvM4bKOYuESQzvPfVJfDB4DrTjben2MuUnqTqZO
+ p6IXQc1EgIJPNcH1W1LgpQKBgAKZlPAevngIBpDqn4JpSyititMOevxuSr/yJvCu
+ Xw9HOJ0YTAk3APvoT7y9h6IP1/eEU6R56EUotP+vOQZ4WRFKgsK7TllOxyvElzfe
+ hYom1BoxqLc2Dv+7rsdu8fZWKTB5qCOy44xM9DquEXa79AN/IojTOuQ5++v1sErw
+ ls/jAoGBANneGe9ogN51mYkrLyg1fhU1i24gFRq+sPGEvsCUoE6Vjw/lawQQ80T8
+ v45TFqvhoGpgznqy3qxDJyguquZg6HN2yW6HE2Dvk7uk3XogcjdXgNDmWqb2j0eE
+ z9pKzHCqfwNVPuYf44Znyo2YeyZ2kHn42MU73oXuFshUs3QHcH+P
-----END RSA PRIVATE KEY-----
PKEY
end
diff --git a/spec/bundler/support/bundle b/spec/bundler/support/bundle
new file mode 100755
index 0000000000..8f8b535295
--- /dev/null
+++ b/spec/bundler/support/bundle
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require_relative "../bundler/support/activate"
+
+load File.expand_path("bundle", Spec::Path.exedir)
diff --git a/spec/bundler/support/bundle.rb b/spec/bundler/support/bundle.rb
index 5d6d658040..aa7b121706 100644
--- a/spec/bundler/support/bundle.rb
+++ b/spec/bundler/support/bundle.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
-require_relative "activate"
+require_relative "path"
-load File.expand_path("bundle", Spec::Path.bindir)
+warn "#{__FILE__} is deprecated. Please use #{Spec::Path.dev_binstub} instead"
+
+load Spec::Path.dev_binstub
diff --git a/spec/bundler/support/checksums.rb b/spec/bundler/support/checksums.rb
index f3aa13ca9f..7b69bba668 100644
--- a/spec/bundler/support/checksums.rb
+++ b/spec/bundler/support/checksums.rb
@@ -3,6 +3,8 @@
module Spec
module Checksums
class ChecksumsBuilder
+ attr_reader :bundler_registered
+
def initialize(enabled = true, &block)
@enabled = enabled
@checksums = {}
@@ -14,9 +16,11 @@ module Spec
@checksums = @checksums.dup
end
- def checksum(repo, name, version, platform = Gem::Platform::RUBY)
+ def checksum(repo, name, version, platform = Gem::Platform::RUBY, folder = "gems")
+ @bundler_registered = true if name == "bundler"
+
name_tuple = Gem::NameTuple.new(name, version, platform)
- gem_file = File.join(repo, "gems", "#{name_tuple.full_name}.gem")
+ gem_file = File.join(repo, folder, "#{name_tuple.full_name}.gem")
File.open(gem_file, "rb") do |f|
register(name_tuple, Bundler::Checksum.from_gem(f, "#{gem_file} (via ChecksumsBuilder#checksum)"))
end
@@ -50,21 +54,26 @@ module Spec
end
end
- def checksums_section(enabled = true, &block)
- ChecksumsBuilder.new(enabled, &block)
+ def checksums_section(enabled = true, bundler_checksum: true, &block)
+ ChecksumsBuilder.new(enabled, &block).tap do |builder|
+ next if builder.bundler_registered || !bundler_checksum
+
+ next if Bundler::VERSION.to_s.end_with?(".dev")
+ builder.checksum(system_gem_path, "bundler", Bundler::VERSION, Gem::Platform::RUBY, "cache")
+ end
end
def checksums_section_when_enabled(target_lockfile = nil, &block)
begin
enabled = (target_lockfile || lockfile).match?(/^CHECKSUMS$/)
rescue Errno::ENOENT
- enabled = Bundler.feature_flag.bundler_3_mode?
+ enabled = true
end
checksums_section(enabled, &block)
end
def checksum_to_lock(*args)
- checksums_section do |c|
+ checksums_section(true, bundler_checksum: false) do |c|
c.checksum(*args)
end.to_s.sub(/^CHECKSUMS\n/, "").strip
end
diff --git a/spec/bundler/support/command_execution.rb b/spec/bundler/support/command_execution.rb
index 02726744d3..e2915b996d 100644
--- a/spec/bundler/support/command_execution.rb
+++ b/spec/bundler/support/command_execution.rb
@@ -2,9 +2,8 @@
module Spec
class CommandExecution
- def initialize(command, working_directory:, timeout:)
+ def initialize(command, timeout:)
@command = command
- @working_directory = working_directory
@timeout = timeout
@original_stdout = String.new
@original_stderr = String.new
@@ -73,7 +72,7 @@ module Spec
attr_reader :failure_reason
def normalize(string)
- string.force_encoding(Encoding::UTF_8).strip.gsub("\r\n", "\n")
+ string.dup.force_encoding(Encoding::UTF_8).scrub.strip.gsub("\r\n", "\n")
end
end
end
diff --git a/spec/bundler/support/filters.rb b/spec/bundler/support/filters.rb
index 663b7fa44b..2be25b4a78 100644
--- a/spec/bundler/support/filters.rb
+++ b/spec/bundler/support/filters.rb
@@ -1,17 +1,10 @@
# frozen_string_literal: true
class RequirementChecker < Proc
- def self.against(present, major_only: false)
- present = present.split(".")[0] if major_only
- provided = Gem::Version.new(present)
-
+ def self.against(provided)
new do |required|
requirement = Gem::Requirement.new(required)
- if major_only && !requirement.requirements.map(&:last).all? {|version| version.segments.one? }
- raise "this filter only supports major versions, but #{required} was given"
- end
-
!requirement.satisfied_by?(provided)
end.tap do |checker|
checker.provided = provided
@@ -25,11 +18,13 @@ class RequirementChecker < Proc
end
end
+git_version = Gem::Version.new(`git --version`[/(\d+\.\d+\.\d+)/, 1])
+
RSpec.configure do |config|
config.filter_run_excluding realworld: true
- config.filter_run_excluding bundler: RequirementChecker.against(Bundler::VERSION, major_only: true)
- config.filter_run_excluding rubygems: RequirementChecker.against(Gem::VERSION)
+ config.filter_run_excluding rubygems: RequirementChecker.against(Gem.rubygems_version)
+ config.filter_run_excluding git: RequirementChecker.against(git_version)
config.filter_run_excluding ruby_repo: !ENV["GEM_COMMAND"].nil?
config.filter_run_excluding no_color_tty: Gem.win_platform? || !ENV["GITHUB_ACTION"].nil?
config.filter_run_excluding permissions: Gem.win_platform?
@@ -37,6 +32,11 @@ RSpec.configure do |config|
config.filter_run_excluding jruby_only: RUBY_ENGINE != "jruby"
config.filter_run_excluding truffleruby_only: RUBY_ENGINE != "truffleruby"
config.filter_run_excluding man: Gem.win_platform?
+ config.filter_run_excluding mri_only: RUBY_ENGINE != "ruby"
config.filter_run_when_matching :focus unless ENV["CI"]
+
+ config.before(:each, :bundler) do |example|
+ bundle_config "simulate_version #{example.metadata[:bundler]}"
+ end
end
diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb
index 01bad64ce7..46718f5fa4 100644
--- a/spec/bundler/support/hax.rb
+++ b/spec/bundler/support/hax.rb
@@ -51,4 +51,24 @@ module Gem
File.singleton_class.prepend ReadOnly
end
+
+ if ENV["BUNDLER_SPEC_FAKE_RESOLVE"]
+ module FakeResolv
+ def getaddrinfo(host, port)
+ if host == ENV["BUNDLER_SPEC_FAKE_RESOLVE"]
+ [["AF_INET", port, "127.0.0.1", "127.0.0.1", 2, 2, 17]]
+ else
+ super
+ end
+ end
+ end
+
+ Socket.singleton_class.prepend FakeResolv
+ end
+end
+
+# mise installed rubygems_plugin.rb to system wide `site_ruby` directory.
+# This empty module avoid to call `mise` command.
+module ReshimInstaller
+ def self.reshim; end
end
diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb
index 951c370064..b0d4b5008b 100644
--- a/spec/bundler/support/helpers.rb
+++ b/spec/bundler/support/helpers.rb
@@ -24,16 +24,13 @@ module Spec
end
FileUtils.mkdir_p(home)
FileUtils.mkdir_p(tmpdir)
- reset_paths!
- end
-
- def reset_paths!
Bundler.reset!
+ Bundler::Source::Git::GitProxy.reset
Gem.clear_paths
end
- def the_bundle(*args)
- TheBundle.new(*args)
+ def the_bundle
+ TheBundle.new
end
MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/
@@ -43,7 +40,7 @@ module Spec
end
def deprecations
- err.split("\n").select {|l| l =~ MAJOR_DEPRECATION }.join("\n").split(MAJOR_DEPRECATION)
+ err.split("\n").filter_map {|l| l.sub(MAJOR_DEPRECATION, "") if l.match?(MAJOR_DEPRECATION) }
end
def run(cmd, *args)
@@ -58,7 +55,7 @@ module Spec
begin
#{ruby}
rescue LoadError => e
- warn "ZOMG LOAD ERROR" if e.message.include?("-- #{name}")
+ warn e.message if e.message.include?("-- #{name}")
end
RUBY
opts = args.last.is_a?(Hash) ? args.pop : {}
@@ -66,12 +63,15 @@ module Spec
run(cmd, *args)
end
+ def in_bundled_app(cmd, options = {})
+ sys_exec(cmd, dir: bundled_app, raise_on_error: options[:raise_on_error])
+ end
+
def bundle(cmd, options = {}, &block)
bundle_bin = options.delete(:bundle_bin)
bundle_bin ||= installed_bindir.join("bundle")
env = options.delete(:env) || {}
- preserve_ruby_flags = options.delete(:preserve_ruby_flags)
requires = options.delete(:requires) || []
@@ -79,15 +79,14 @@ module Spec
custom_load_path = options.delete(:load_path)
load_path = []
- load_path << spec_dir
load_path << custom_load_path if custom_load_path
- build_ruby_options = { load_path: load_path, requires: requires, env: env }
- build_ruby_options.merge!(artifice: options.delete(:artifice)) if options.key?(:artifice)
+ build_env_options = { load_path: load_path, requires: requires, env: env }
+ build_env_options.merge!(artifice: options.delete(:artifice)) if options.key?(:artifice) || cmd.start_with?("exec")
match_source(cmd)
- env, ruby_cmd = build_ruby_cmd(build_ruby_options)
+ env = build_env(build_env_options)
raise_on_error = options.delete(:raise_on_error)
@@ -102,8 +101,7 @@ module Spec
end
end.join
- cmd = "#{ruby_cmd} #{bundle_bin} #{cmd}#{args}"
- env["BUNDLER_SPEC_ORIGINAL_CMD"] = "#{ruby_cmd} #{bundle_bin}" if preserve_ruby_flags
+ cmd = "#{Gem.ruby} #{bundle_bin} #{cmd}#{args}"
sys_exec(cmd, { env: env, dir: dir, raise_on_error: raise_on_error }, &block)
end
@@ -123,10 +121,11 @@ module Spec
end
def ruby(ruby, options = {})
- env, ruby_cmd = build_ruby_cmd({ artifice: nil }.merge(options))
+ env = build_env({ artifice: nil }.merge(options))
escaped_ruby = ruby.shellescape
options[:env] = env if env
- sys_exec(%(#{ruby_cmd} -w -e #{escaped_ruby}), options)
+ options[:dir] ||= bundled_app
+ sys_exec(%(#{Gem.ruby} -w -e #{escaped_ruby}), options)
end
def load_error_ruby(ruby, name, opts = {})
@@ -134,22 +133,24 @@ module Spec
begin
#{ruby}
rescue LoadError => e
- warn "ZOMG LOAD ERROR" if e.message.include?("-- #{name}")
+ warn e.message if e.message.include?("-- #{name}")
end
R
end
- def build_ruby_cmd(options = {})
- libs = options.delete(:load_path)
- lib_option = libs ? "-I#{libs.join(File::PATH_SEPARATOR)}" : []
-
+ def build_env(options = {})
env = options.delete(:env) || {}
+ libs = options.delete(:load_path) || []
+ env["RUBYOPT"] = opt_add("-I#{libs.join(File::PATH_SEPARATOR)}", env["RUBYOPT"]) if libs.any?
+
current_example = RSpec.current_example
main_source = @gemfile_source if defined?(@gemfile_source)
compact_index_main_source = main_source&.start_with?("https://gem.repo", "https://gems.security")
requires = options.delete(:requires) || []
+ requires << hax
+
artifice = options.delete(:artifice) do
if current_example && current_example.metadata[:realworld]
"vcr"
@@ -172,11 +173,9 @@ module Spec
requires << "#{Path.spec_dir}/support/artifice/#{artifice}.rb"
end
- requires << "#{Path.spec_dir}/support/hax.rb"
+ requires.each {|r| env["RUBYOPT"] = opt_add("-r#{r}", env["RUBYOPT"]) }
- require_option = requires.map {|r| "-r#{r}" }
-
- [env, [Gem.ruby, *lib_option, *require_option].compact.join(" ")]
+ env
end
def gembin(cmd, options = {})
@@ -184,39 +183,20 @@ module Spec
sys_exec(cmd.to_s, options)
end
- def gem_command(command, options = {})
- env = options[:env] || {}
- env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/hax.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
- options[:env] = env
-
- # Sometimes `gem install` commands hang at dns resolution, which has a
- # default timeout of 60 seconds. When that happens, the timeout for a
- # command is expired too. So give `gem install` commands a bit more time.
- options[:timeout] = 120
-
- allowed_warning = options.delete(:allowed_warning)
-
- output = sys_exec("#{Path.gem_bin} #{command}", options)
- stderr = last_command.stderr
-
- raise stderr if stderr.include?("WARNING") && !allowed_rubygems_warning?(stderr, allowed_warning)
- output
- end
-
- def rake
- "#{Gem.ruby} -S #{ENV["GEM_PATH"]}/bin/rake"
- end
-
def sys_exec(cmd, options = {}, &block)
env = options[:env] || {}
env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
options[:env] = env
- options[:dir] ||= bundled_app
sh(cmd, options, &block)
end
- def config(config = nil, path = bundled_app(".bundle/config"))
+ def bundle_config(config = nil, path = bundled_app(".bundle/config"))
+ if config.is_a?(String)
+ key, value = config.split(" ", 2)
+ config = { Bundler::Settings.key_for(key) => value }
+ end
+
current = File.exist?(path) ? Psych.load_file(path) : {}
return current unless config
@@ -233,8 +213,8 @@ module Spec
new_config
end
- def global_config(config = nil)
- config(config, home(".bundle/config"))
+ def bundle_config_global(config = nil)
+ bundle_config(config, home(".bundle/config"))
end
def create_file(path, contents = "")
@@ -306,6 +286,10 @@ module Spec
bundle :lock, opts
end
+ def base_system_gems(*names, **options)
+ system_gems names.map {|name| find_base_path(name) }, **options
+ end
+
def system_gems(*gems)
gems = gems.flatten
options = gems.last.is_a?(Hash) ? gems.pop : {}
@@ -313,9 +297,10 @@ module Spec
default = options.fetch(:default, false)
gems.each do |g|
gem_name = g.to_s
- if gem_name.start_with?("bundler")
- version = gem_name.match(/\Abundler-(?<version>.*)\z/)[:version] if gem_name != "bundler"
- with_built_bundler(version) {|gem_path| install_gem(gem_path, install_dir, default) }
+ bundler = gem_name.match(/\Abundler-(?<version>.*)\z/)
+
+ if bundler
+ with_built_bundler(bundler[:version], released: options.fetch(:released, false)) {|gem_path| install_gem(gem_path, install_dir, default) }
elsif %r{\A(?:[a-zA-Z]:)?/.*\.gem\z}.match?(gem_name)
install_gem(gem_name, install_dir, default)
else
@@ -328,22 +313,96 @@ module Spec
def self.install_dev_bundler
extend self
- system_gems :bundler, path: pristine_system_gem_path
+ with_built_bundler(nil, build_path: tmp_root) {|gem_path| install_gem(gem_path, pristine_system_gem_path) }
end
def install_gem(path, install_dir, default = false)
- raise "OMG `#{path}` does not exist!" unless File.exist?(path)
+ raise ArgumentError, "`#{path}` does not exist!" unless File.exist?(path)
+
+ require "rubygems/installer"
+
+ with_simulated_platform do
+ installer = Gem::Installer.at(
+ path.to_s,
+ install_dir: install_dir.to_s,
+ document: [],
+ ignore_dependencies: true,
+ wrappers: true,
+ env_shebang: true,
+ force: true
+ )
+ installer.install
+ end
+
+ if default
+ gem = Pathname.new(path).basename.to_s.match(/(.*)\.gem/)[1]
+
+ # Revert Gem::Installer#write_spec and apply Gem::Installer#write_default_spec
+ FileUtils.mkdir_p File.join(install_dir, "specifications", "default")
+ File.rename File.join(install_dir, "specifications", gem + ".gemspec"),
+ File.join(install_dir, "specifications", "default", gem + ".gemspec")
+
+ # Revert Gem::Installer#write_cache_file
+ File.delete File.join(install_dir, "cache", gem + ".gem")
+ end
+ end
+
+ def uninstall_gem(name, options = {})
+ require "rubygems/uninstaller"
+
+ gem_home = options.dig(:env, "GEM_HOME") || system_gem_path.to_s
+
+ with_env_vars("GEM_HOME" => gem_home) do
+ Gem.clear_paths
+
+ uninstaller = Gem::Uninstaller.new(
+ name,
+ ignore: true,
+ executables: true,
+ all: true
+ )
+ uninstaller.uninstall
+ ensure
+ Gem.clear_paths
+ end
+ end
- args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}"
- args += " --default" if default
+ def installed_gems_list(options = {})
+ gem_home = options.dig(:env, "GEM_HOME") || system_gem_path.to_s
- gem_command "install #{args} '#{path}'"
+ # Temporarily set GEM_HOME for the command
+ old_gem_home = ENV["GEM_HOME"]
+ ENV["GEM_HOME"] = gem_home
+ Gem.clear_paths
+
+ begin
+ require "rubygems/commands/list_command"
+
+ # Capture output from the list command
+ require "stringio"
+ output_io = StringIO.new
+ cmd = Gem::Commands::ListCommand.new
+ cmd.ui = Gem::StreamUI.new(StringIO.new, output_io, StringIO.new, false)
+ cmd.invoke
+ output = output_io.string.strip
+ ensure
+ ENV["GEM_HOME"] = old_gem_home
+ Gem.clear_paths
+ end
+
+ # Create a fake command execution so `out` helper works
+ command_execution = Spec::CommandExecution.new("gem list", timeout: 60)
+ command_execution.original_stdout << output
+ command_execution.exitstatus = 0
+ command_executions << command_execution
+
+ output
end
- def with_built_bundler(version = nil, &block)
+ def with_built_bundler(version = nil, opts = {}, &block)
require_relative "builders"
- Builders::BundlerBuilder.new(self, "bundler", version)._build(&block)
+ Builders::BundlerBuilder.new(self, "bundler", version)._build(opts, &block)
end
def with_gem_path_as(path)
@@ -371,6 +430,36 @@ module Spec
ENV.replace(backup)
end
+ # Simulate the platform set by BUNDLER_SPEC_PLATFORM for in-process
+ # operations, mirroring what hax.rb does for subprocesses.
+ def with_simulated_platform
+ spec_platform = ENV["BUNDLER_SPEC_PLATFORM"]
+ unless spec_platform
+ return yield
+ end
+
+ old_arch = RbConfig::CONFIG["arch"]
+ old_host_os = RbConfig::CONFIG["host_os"]
+
+ if /mingw|mswin/.match?(spec_platform)
+ Gem.class_variable_set(:@@win_platform, nil) # rubocop:disable Style/ClassVars
+ RbConfig::CONFIG["host_os"] = spec_platform.gsub(/^[^-]+-/, "").tr("-", "_")
+ end
+
+ RbConfig::CONFIG["arch"] = spec_platform
+ Gem::Platform.instance_variable_set(:@local, nil)
+ Gem.instance_variable_set(:@platforms, [])
+
+ yield
+ ensure
+ if spec_platform
+ RbConfig::CONFIG["arch"] = old_arch
+ RbConfig::CONFIG["host_os"] = old_host_os
+ Gem::Platform.instance_variable_set(:@local, nil)
+ Gem.instance_variable_set(:@platforms, [])
+ end
+ end
+
def with_path_added(path)
with_path_as([path.to_s, ENV["PATH"]].join(File::PATH_SEPARATOR)) do
yield
@@ -398,16 +487,10 @@ module Spec
def pristine_system_gems(*gems)
FileUtils.rm_r(system_gem_path)
- system_gems(*gems)
- end
-
- def realworld_system_gems(*gems)
- gems = gems.flatten
- opts = gems.last.is_a?(Hash) ? gems.pop : {}
- path = opts.fetch(:path, system_gem_path)
-
- gems.each do |gem|
- gem_command "install --no-document --verbose --install-dir #{path} #{gem}"
+ if gems.any?
+ system_gems(*gems)
+ else
+ default_system_gems
end
end
@@ -418,14 +501,18 @@ module Spec
gems.each do |g|
path = "#{gem_repo}/gems/#{g}.gem"
- raise "OMG `#{path}` does not exist!" unless File.exist?(path)
+ raise ArgumentError, "`#{path}` does not exist!" unless File.exist?(path)
FileUtils.cp(path, "#{bundled_app}/vendor/cache")
end
end
def simulate_new_machine
FileUtils.rm_r bundled_app(".bundle")
- pristine_system_gems :bundler
+ pristine_system_gems
+ end
+
+ def default_system_gems
+ FileUtils.cp_r pristine_system_gem_path, system_gem_path
end
def simulate_ruby_platform(ruby_platform)
@@ -452,12 +539,6 @@ module Spec
ruby_major_minor.map.with_index {|s, i| i == 1 ? s + 1 : s }.join(".")
end
- def previous_ruby_minor
- return "2.7" if ruby_major_minor == [3, 0]
-
- ruby_major_minor.map.with_index {|s, i| i == 1 ? s - 1 : s }.join(".")
- end
-
def ruby_major_minor
Gem.ruby_version.segments[0..1]
end
@@ -515,34 +596,14 @@ module Spec
end
end
- def require_rack
- # need to hack, so we can require rack
+ def require_rack_test
+ # need to hack, so we can require rack for testing
old_gem_home = ENV["GEM_HOME"]
- ENV["GEM_HOME"] = Spec::Path.base_system_gem_path.to_s
- require "rack"
+ ENV["GEM_HOME"] = Spec::Path.scoped_base_system_gem_path.to_s
+ require "rack/test"
ENV["GEM_HOME"] = old_gem_home
end
- def wait_for_server(host, port, seconds = 15)
- tries = 0
- sleep 0.5
- TCPSocket.new(host, port)
- rescue StandardError => e
- raise(e) if tries > (seconds * 2)
- tries += 1
- retry
- end
-
- def find_unused_port
- port = 21_453
- begin
- port += 1 while TCPSocket.new("127.0.0.1", port)
- rescue StandardError
- false
- end
- port
- end
-
def exit_status_for_signal(signal_number)
# For details see: https://en.wikipedia.org/wiki/Exit_status#Shell_and_scripts
128 + signal_number
@@ -556,14 +617,6 @@ module Spec
private
- def allowed_rubygems_warning?(text, extra_allowed_warning)
- allowed_warnings = ["open-ended", "is a symlink", "rake based", "expected RubyGems version"]
- allowed_warnings << extra_allowed_warning if extra_allowed_warning
- allowed_warnings.any? do |warning|
- text.include?(warning)
- end
- end
-
def match_source(contents)
match = /source ["']?(?<source>http[^"']+)["']?/.match(contents)
return unless match
diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb
index 2d592808f0..1fbdd49abe 100644
--- a/spec/bundler/support/indexes.rb
+++ b/spec/bundler/support/indexes.rb
@@ -122,7 +122,7 @@ module Spec
end
versions "1.0 1.2 1.2.1 1.2.2 1.3 1.3.0.1 1.3.5 1.4.0 1.4.2 1.4.2.1" do |version|
- platforms "ruby java mswin32 mingw32 x64-mingw32" do |platform|
+ platforms "ruby java mswin32 mingw32 x64-mingw-ucrt" do |platform|
next if version == v("1.4.2.1") && platform != pl("x86-mswin32")
next if version == v("1.4.2") && platform == pl("x86-mswin32")
gem "nokogiri", version, platform do
diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb
index 9f311fc0d7..5a3c38a4db 100644
--- a/spec/bundler/support/matchers.rb
+++ b/spec/bundler/support/matchers.rb
@@ -52,7 +52,7 @@ module Spec
end
def self.define_compound_matcher(matcher, preconditions, &declarations)
- raise "Must have preconditions to define a compound matcher" if preconditions.empty?
+ raise ArgumentError, "Must have preconditions to define a compound matcher" if preconditions.empty?
define_method(matcher) do |*expected, &block_arg|
Precondition.new(
RSpec::Matchers::DSL::Matcher.new(matcher, declarations, self, *expected, &block_arg),
diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb
index 9b67ab0229..2e6486412f 100644
--- a/spec/bundler/support/path.rb
+++ b/spec/bundler/support/path.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "pathname"
+require "pathname" unless defined?(Pathname)
require "rbconfig"
require_relative "env"
@@ -10,7 +10,7 @@ module Spec
include Spec::Env
def source_root
- @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../..").expand_path(__dir__)
+ @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../../bundler").expand_path(__dir__)
end
def root
@@ -25,12 +25,8 @@ module Spec
@relative_gemspec ||= ruby_core? ? "lib/bundler/bundler.gemspec" : "bundler.gemspec"
end
- def gemspec_dir
- @gemspec_dir ||= gemspec.parent
- end
-
def loaded_gemspec
- @loaded_gemspec ||= Gem::Specification.load(gemspec.to_s)
+ @loaded_gemspec ||= Dir.chdir(source_root) { Gem::Specification.load(gemspec.to_s) }
end
def test_gemfile
@@ -49,8 +45,16 @@ module Spec
@dev_gemfile ||= tool_dir.join("dev_gems.rb")
end
+ def dev_binstub
+ @dev_binstub ||= bindir.join("bundle")
+ end
+
def bindir
- @bindir ||= source_root.join(ruby_core? ? "libexec" : "exe")
+ @bindir ||= source_root.join(ruby_core? ? "spec/bin" : "../bin")
+ end
+
+ def exedir
+ @exedir ||= source_root.join(ruby_core? ? "libexec" : "exe")
end
def installed_bindir
@@ -67,18 +71,22 @@ module Spec
def path
env_path = ENV["PATH"]
- env_path = env_path.split(File::PATH_SEPARATOR).reject {|path| path == bindir.to_s }.join(File::PATH_SEPARATOR) if ruby_core?
+ env_path = env_path.split(File::PATH_SEPARATOR).reject {|path| path == exedir.to_s }.join(File::PATH_SEPARATOR) if ruby_core?
env_path
end
def spec_dir
- @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "spec")
+ @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "../spec")
end
def man_dir
@man_dir ||= lib_dir.join("bundler/man")
end
+ def hax
+ @hax ||= spec_dir.join("support/hax.rb")
+ end
+
def tracked_files
@tracked_files ||= git_ls_files(tracked_files_glob)
end
@@ -102,11 +110,21 @@ module Spec
end
def tmp(*path)
- tmp_root(scope).join(*path)
- end
-
- def tmp_root(scope)
- source_root.join("tmp", "#{test_env_version}.#{scope}")
+ tmp_root.join("#{test_env_version}.#{scope}").join(*path)
+ end
+
+ def tmp_root
+ if ruby_core? && (tmpdir = ENV["TMPDIR"])
+ # Use realpath to resolve any symlinks in TMPDIR (e.g., on macOS /var -> /private/var)
+ real = begin
+ File.realpath(tmpdir)
+ rescue Errno::ENOENT, Errno::EACCES
+ tmpdir
+ end
+ Pathname(real)
+ else
+ (ruby_core? ? source_root : source_root.parent).join("tmp")
+ end
end
# Bump this version whenever you make a breaking change to the spec setup
@@ -128,19 +146,11 @@ module Spec
end
def default_bundle_path(*path)
- if Bundler.feature_flag.default_install_uses_path?
- local_gem_path(*path)
- else
- system_gem_path(*path)
- end
+ system_gem_path(*path)
end
def default_cache_path(*path)
- if Bundler.feature_flag.global_gem_cache?
- home(".bundle/cache", *path)
- else
- default_bundle_path("cache/bundler", *path)
- end
+ default_bundle_path("cache/bundler", *path)
end
def compact_index_cache_path
@@ -175,20 +185,20 @@ module Spec
bundled_app("Gemfile.lock")
end
- def base_system_gem_path
- scoped_gem_path(base_system_gems)
+ def scoped_base_system_gem_path
+ scoped_gem_path(base_system_gem_path)
end
- def base_system_gems
- tmp("gems/base")
+ def base_system_gem_path
+ tmp_root.join("gems/base")
end
- def rubocop_gems
- tmp("gems/rubocop")
+ def rubocop_gem_path
+ tmp_root.join("gems/rubocop")
end
- def standard_gems
- tmp("gems/standard")
+ def standard_gem_path
+ tmp_root.join("gems/standard")
end
def file_uri_for(path)
@@ -199,35 +209,35 @@ module Spec
end
def gem_repo1(*args)
- tmp("gems/remote1", *args)
+ gem_path("remote1", *args)
end
def gem_repo_missing(*args)
- tmp("gems/missing", *args)
+ gem_path("missing", *args)
end
def gem_repo2(*args)
- tmp("gems/remote2", *args)
+ gem_path("remote2", *args)
end
def gem_repo3(*args)
- tmp("gems/remote3", *args)
+ gem_path("remote3", *args)
end
def gem_repo4(*args)
- tmp("gems/remote4", *args)
+ gem_path("remote4", *args)
end
def security_repo(*args)
- tmp("gems/security_repo", *args)
+ gem_path("security_repo", *args)
end
def system_gem_path(*path)
- tmp("gems/system", *path)
+ gem_path("system", *path)
end
def pristine_system_gem_path
- tmp("gems/base_system")
+ tmp_root.join("gems/pristine_system")
end
def local_gem_path(*path, base: bundled_app)
@@ -238,6 +248,10 @@ module Spec
base.join(Gem.ruby_engine, RbConfig::CONFIG["ruby_version"])
end
+ def gem_path(*args)
+ tmp("gems", *args)
+ end
+
def lib_path(*args)
tmp("libs", *args)
end
@@ -265,7 +279,7 @@ module Spec
def replace_version_file(version, dir: source_root)
version_file = File.expand_path("lib/bundler/version.rb", dir)
contents = File.read(version_file)
- contents.sub!(/(^\s+VERSION\s*=\s*)"#{Gem::Version::VERSION_PATTERN}"/, %(\\1"#{version}"))
+ contents.sub!(/(^\s+VERSION\s*=\s*).*$/, %(\\1"#{version}"))
File.open(version_file, "w") {|f| f << contents }
end
@@ -276,29 +290,54 @@ module Spec
File.open(gemspec_file, "w") {|f| f << contents }
end
+ def replace_changelog(version, dir:)
+ changelog = File.expand_path("CHANGELOG.md", dir)
+ contents = File.readlines(changelog)
+ contents = [contents[0], contents[1], "## #{version} (2100-01-01)\n", *contents[3..-1]].join
+ File.open(changelog, "w") {|f| f << contents }
+ end
+
def git_root
ruby_core? ? source_root : source_root.parent
end
def rake_path
- Dir["#{base_system_gems}/#{Bundler.ruby_scope}/**/rake*.gem"].first
+ find_base_path("rake")
+ end
+
+ def rake_version
+ File.basename(rake_path).delete_prefix("rake-").delete_suffix(".gem")
end
def sinatra_dependency_paths
deps = %w[
mustermann
rack
+ rack-protection
+ rack-session
tilt
sinatra
- ruby2_keywords
base64
logger
+ compact_index
]
- Dir[base_system_gem_path.join("gems/{#{deps.join(",")}}-*/lib")].map(&:to_s)
+ path = if deps.all? {|dep| !Dir[scoped_base_system_gem_path.join("gems/#{dep}-*")].empty? }
+ scoped_base_system_gem_path
+ elsif ruby_core? && deps.all? {|dep| !Dir[source_root.join(".bundle/gems/#{dep}-*")].empty? }
+ source_root.join(".bundle")
+ else
+ scoped_base_system_gem_path
+ end
+
+ Dir[path.join("gems/{#{deps.join(",")}}-*/lib")].map(&:to_s)
end
private
+ def find_base_path(name)
+ Dir["#{scoped_base_system_gem_path}/**/#{name}-*.gem"].first
+ end
+
def git_ls_files(glob)
skip "Not running on a git context, since running tests from a tarball" if ruby_core_tarball?
@@ -306,7 +345,7 @@ module Spec
end
def tracked_files_glob
- ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "lib exe spec CHANGELOG.md LICENSE.md README.md bundler.gemspec"
+ ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "lib exe CHANGELOG.md LICENSE.md README.md bundler.gemspec"
end
def lib_tracked_files_glob
@@ -314,7 +353,7 @@ module Spec
end
def man_tracked_files_glob
- ruby_core? ? "man/bundle* man/gemfile*" : "lib/bundler/man/bundle*.1 lib/bundler/man/gemfile*.5"
+ "lib/bundler/man/bundle*.1.ronn lib/bundler/man/gemfile*.5.ronn"
end
def ruby_core_tarball?
diff --git a/spec/bundler/support/platforms.rb b/spec/bundler/support/platforms.rb
index e09c6fe66a..56a0843005 100644
--- a/spec/bundler/support/platforms.rb
+++ b/spec/bundler/support/platforms.rb
@@ -2,12 +2,18 @@
module Spec
module Platforms
- include Bundler::GemHelpers
-
def not_local
generic_local_platform == Gem::Platform::RUBY ? "java" : Gem::Platform::RUBY
end
+ def local_platform
+ Bundler.local_platform
+ end
+
+ def generic_local_platform
+ Gem::Platform.generic(local_platform)
+ end
+
def local_tag
if Gem.java_platform?
:jruby
@@ -61,7 +67,7 @@ module Spec
end
def generic_default_locked_platform
- return unless generic_local_platform_is_ruby?
+ return unless Bundler::MatchPlatform.generic_local_platform_is_ruby?
Gem::Platform::RUBY
end
diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb
index 67d49ac363..812dc4deaa 100644
--- a/spec/bundler/support/rubygems_ext.rb
+++ b/spec/bundler/support/rubygems_ext.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-abort "RubyGems only supports Ruby 3.1 or higher" if RUBY_VERSION < "3.1.0"
+abort "RubyGems only supports Ruby 3.2 or higher" if RUBY_VERSION < "3.2.0"
require_relative "path"
@@ -10,10 +10,6 @@ module Spec
module Rubygems
extend self
- def dev_setup
- install_gems(dev_gemfile)
- end
-
def gem_load(gem_name, bin_container)
require_relative "switch_rubygems"
@@ -32,6 +28,9 @@ module Spec
end
def test_setup
+ # Install test dependencies unless parallel-rspec is being used, since in that case they should be setup already
+ install_test_deps unless ENV["RSPEC_FORMATTER_OUTPUT_ID"]
+
setup_test_paths
require "fileutils"
@@ -44,47 +43,78 @@ module Spec
# sign extension bundles on macOS, to avoid trying to find the specified key
# from the fake $HOME/Library/Keychains directory.
ENV.delete "RUBY_CODESIGN"
- ENV["TMPDIR"] = Path.tmpdir.to_s
+ if Path.ruby_core?
+ if (tmpdir = ENV["TMPDIR"])
+ tmpdir_real = begin
+ File.realpath(tmpdir)
+ rescue Errno::ENOENT, Errno::EACCES
+ tmpdir
+ end
+ ENV["TMPDIR"] = tmpdir_real if tmpdir_real != tmpdir
+ end
+ else
+ ENV["TMPDIR"] = Path.tmpdir.to_s
+ end
require "rubygems/user_interaction"
Gem::DefaultUserInteraction.ui = Gem::SilentUI.new
end
- def install_parallel_test_deps
- Gem.clear_paths
-
- require "parallel"
- require "fileutils"
-
- install_test_deps
-
- (2..Parallel.processor_count).each do |n|
- source = Path.tmp_root("1")
- destination = Path.tmp_root(n.to_s)
-
- FileUtils.cp_r source, destination, remove_destination: true
- end
- end
-
def setup_test_paths
- Gem.clear_paths
-
ENV["BUNDLE_PATH"] = nil
- ENV["GEM_HOME"] = ENV["GEM_PATH"] = Path.base_system_gem_path.to_s
ENV["PATH"] = [Path.system_gem_path("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR)
- ENV["PATH"] = [Path.bindir, ENV["PATH"]].join(File::PATH_SEPARATOR) if Path.ruby_core?
+ ENV["PATH"] = [Path.exedir, ENV["PATH"]].join(File::PATH_SEPARATOR) if Path.ruby_core?
end
def install_test_deps
- Gem.clear_paths
+ dev_bundle("install", gemfile: test_gemfile, path: Path.base_system_gem_path.to_s)
+ dev_bundle("install", gemfile: rubocop_gemfile, path: Path.rubocop_gem_path.to_s)
+ dev_bundle("install", gemfile: standard_gemfile, path: Path.standard_gem_path.to_s)
- install_gems(test_gemfile, Path.base_system_gems.to_s)
- install_gems(rubocop_gemfile, Path.rubocop_gems.to_s)
- install_gems(standard_gemfile, Path.standard_gems.to_s)
+ require_relative "helpers"
+ Helpers.install_dev_bundler
- # For some reason, doing this here crashes on JRuby + Windows. So defer to
- # when the test suite is running in that case.
- Helpers.install_dev_bundler unless Gem.win_platform? && RUBY_ENGINE == "jruby"
+ install_vendored_compact_index
+ end
+
+ # Vendor `rubygems/rubygems.org#lib/compact_index/` under `tmp/compact_index/`
+ # so the artifice can serve compact-index responses without a runtime gem
+ # dependency. Pinned to a reviewed commit; override with COMPACT_INDEX_REF
+ # to refresh against another ref (the existing vendor copy is discarded).
+ def install_vendored_compact_index
+ target_root = Path.tmp_root.join("compact_index")
+ require "fileutils"
+ FileUtils.mkdir_p(Path.tmp_root)
+
+ files = %w[
+ lib/compact_index.rb
+ lib/compact_index/dependency.rb
+ lib/compact_index/gem.rb
+ lib/compact_index/gem_version.rb
+ lib/compact_index/versions_file.rb
+ ]
+
+ # Serialize installs so parallel test setups don't race on the same
+ # vendor tree, and only skip the download when every file is present so
+ # an interrupted run can't leave a partial copy behind.
+ File.open(Path.tmp_root.join("compact_index.lock"), File::CREAT | File::RDWR) do |lock|
+ lock.flock(File::LOCK_EX)
+
+ FileUtils.rm_rf(target_root) if ENV["COMPACT_INDEX_REF"]
+
+ next if files.all? {|path| File.exist?(target_root.join(path)) }
+
+ require "open-uri"
+ ref = ENV["COMPACT_INDEX_REF"] || "7c68a7b39761c61a66f9299f85b889ec39afc02c"
+ files.each do |path|
+ url = "https://raw.githubusercontent.com/rubygems/rubygems.org/#{ref}/#{path}"
+ target = target_root.join(path)
+ FileUtils.mkdir_p(File.dirname(target))
+ tmp = "#{target}.tmp"
+ File.write(tmp, URI.parse(url).open(&:read))
+ File.rename(tmp, target)
+ end
+ end
end
def check_source_control_changes(success_message:, error_message:)
@@ -107,6 +137,36 @@ module Spec
end
end
+ def dev_bundle(*args, gemfile: dev_gemfile, path: nil)
+ old_gemfile = ENV["BUNDLE_GEMFILE"]
+ old_orig_gemfile = ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"]
+ ENV["BUNDLE_GEMFILE"] = gemfile.to_s
+ ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = nil
+
+ if path
+ old_path = ENV["BUNDLE_PATH"]
+ ENV["BUNDLE_PATH"] = path
+ else
+ old_path__system = ENV["BUNDLE_PATH__SYSTEM"]
+ ENV["BUNDLE_PATH__SYSTEM"] = "true"
+ end
+
+ require "shellwords"
+ # We don't use `Open3` here because it does not work on JRuby + Windows
+ output = `ruby #{Path.dev_binstub} #{args.shelljoin}`
+ raise output unless $?.success?
+ output
+ ensure
+ if path
+ ENV["BUNDLE_PATH"] = old_path
+ else
+ ENV["BUNDLE_PATH__SYSTEM"] = old_path__system
+ end
+
+ ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = old_orig_gemfile
+ ENV["BUNDLE_GEMFILE"] = old_gemfile
+ end
+
private
def gem_load_and_activate(gem_name, bin_container)
@@ -135,34 +195,6 @@ module Spec
gem gem_name, gem_requirement
end
- def install_gems(gemfile, path = nil)
- old_gemfile = ENV["BUNDLE_GEMFILE"]
- old_orig_gemfile = ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"]
- ENV["BUNDLE_GEMFILE"] = gemfile.to_s
- ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = nil
-
- if path
- old_path = ENV["BUNDLE_PATH"]
- ENV["BUNDLE_PATH"] = path
- else
- old_path__system = ENV["BUNDLE_PATH__SYSTEM"]
- ENV["BUNDLE_PATH__SYSTEM"] = "true"
- end
-
- # We don't use `Open3` here because it does not work on JRuby + Windows
- output = `#{Gem.ruby} #{File.expand_path("support/bundle.rb", Path.spec_dir)} install`
- raise output unless $?.success?
- ensure
- if path
- ENV["BUNDLE_PATH"] = old_path
- else
- ENV["BUNDLE_PATH__SYSTEM"] = old_path__system
- end
-
- ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = old_orig_gemfile
- ENV["BUNDLE_GEMFILE"] = old_gemfile
- end
-
def test_gemfile
Path.test_gemfile
end
diff --git a/spec/bundler/support/setup.rb b/spec/bundler/support/setup.rb
new file mode 100644
index 0000000000..4ac2e5b472
--- /dev/null
+++ b/spec/bundler/support/setup.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require_relative "switch_rubygems"
+
+require_relative "rubygems_ext"
+Spec::Rubygems.install_test_deps
+
+require_relative "path"
+$LOAD_PATH.unshift(File.expand_path("../../lib", __dir__)) if Spec::Path.ruby_core?
diff --git a/spec/bundler/support/shards.rb b/spec/bundler/support/shards.rb
new file mode 100644
index 0000000000..ce33896539
--- /dev/null
+++ b/spec/bundler/support/shards.rb
@@ -0,0 +1,200 @@
+# frozen_string_literal: true
+
+# This classifies test files into 4 shards by running `bin/rspec --profile 10000`
+# to ensure balanced execution times. When adding new test files, it is recommended to
+# re-aggregate and adjust the shards to keep them balanced.
+# For now, please add new files to shard 'shard_d'.
+
+module Spec
+ module Shards
+ EXAMPLE_MAPPINGS = {
+ shard_a: [
+ "spec/runtime/setup_spec.rb",
+ "spec/commands/install_spec.rb",
+ "spec/commands/add_spec.rb",
+ "spec/install/gems/compact_index_spec.rb",
+ "spec/commands/config_spec.rb",
+ "spec/commands/pristine_spec.rb",
+ "spec/install/gemfile/path_spec.rb",
+ "spec/update/git_spec.rb",
+ "spec/commands/open_spec.rb",
+ "spec/commands/remove_spec.rb",
+ "spec/commands/show_spec.rb",
+ "spec/plugins/source/example_spec.rb",
+ "spec/commands/console_spec.rb",
+ "spec/runtime/require_spec.rb",
+ "spec/runtime/env_helpers_spec.rb",
+ "spec/runtime/gem_tasks_spec.rb",
+ "spec/install/gemfile_spec.rb",
+ "spec/commands/fund_spec.rb",
+ "spec/commands/init_spec.rb",
+ "spec/bundler/ruby_dsl_spec.rb",
+ "spec/bundler/mirror_spec.rb",
+ "spec/bundler/source/git/git_proxy_spec.rb",
+ "spec/bundler/source_list_spec.rb",
+ "spec/bundler/plugin/installer_spec.rb",
+ "spec/bundler/errors_spec.rb",
+ "spec/bundler/friendly_errors_spec.rb",
+ "spec/resolver/platform_spec.rb",
+ "spec/bundler/fetcher/downloader_spec.rb",
+ "spec/update/force_spec.rb",
+ "spec/bundler/env_spec.rb",
+ "spec/install/gems/mirror_spec.rb",
+ "spec/install/failure_spec.rb",
+ "spec/bundler/yaml_serializer_spec.rb",
+ "spec/bundler/environment_preserver_spec.rb",
+ "spec/install/gemfile/install_if_spec.rb",
+ "spec/install/gems/gemfile_source_header_spec.rb",
+ "spec/bundler/fetcher/base_spec.rb",
+ "spec/bundler/rubygems_integration_spec.rb",
+ "spec/bundler/worker_spec.rb",
+ "spec/bundler/dependency_spec.rb",
+ "spec/bundler/ui_spec.rb",
+ "spec/bundler/plugin/source_list_spec.rb",
+ "spec/bundler/source/path_spec.rb",
+ ],
+ shard_b: [
+ "spec/install/gemfile/git_spec.rb",
+ "spec/install/gems/standalone_spec.rb",
+ "spec/commands/lock_spec.rb",
+ "spec/cache/gems_spec.rb",
+ "spec/other/major_deprecation_spec.rb",
+ "spec/install/gems/dependency_api_spec.rb",
+ "spec/install/gemfile/gemspec_spec.rb",
+ "spec/plugins/install_spec.rb",
+ "spec/commands/binstubs_spec.rb",
+ "spec/install/gems/flex_spec.rb",
+ "spec/runtime/inline_spec.rb",
+ "spec/commands/post_bundle_message_spec.rb",
+ "spec/runtime/executable_spec.rb",
+ "spec/lock/git_spec.rb",
+ "spec/plugins/hook_spec.rb",
+ "spec/install/allow_offline_install_spec.rb",
+ "spec/install/gems/post_install_spec.rb",
+ "spec/install/gemfile/ruby_spec.rb",
+ "spec/install/security_policy_spec.rb",
+ "spec/install/yanked_spec.rb",
+ "spec/update/gemfile_spec.rb",
+ "spec/runtime/load_spec.rb",
+ "spec/plugins/command_spec.rb",
+ "spec/commands/version_spec.rb",
+ "spec/install/prereleases_spec.rb",
+ "spec/bundler/uri_credentials_filter_spec.rb",
+ "spec/bundler/plugin_spec.rb",
+ "spec/install/gems/mirror_probe_spec.rb",
+ "spec/plugins/list_spec.rb",
+ "spec/bundler/compact_index_client/parser_spec.rb",
+ "spec/bundler/gem_version_promoter_spec.rb",
+ "spec/other/cli_dispatch_spec.rb",
+ "spec/bundler/source/rubygems_spec.rb",
+ "spec/cache/platform_spec.rb",
+ "spec/update/gems/fund_spec.rb",
+ "spec/bundler/stub_specification_spec.rb",
+ "spec/bundler/retry_spec.rb",
+ "spec/bundler/installer/spec_installation_spec.rb",
+ "spec/bundler/spec_set_spec.rb",
+ "spec/quality_es_spec.rb",
+ "spec/bundler/index_spec.rb",
+ "spec/other/cli_man_pages_spec.rb",
+ ],
+ shard_c: [
+ "spec/commands/newgem_spec.rb",
+ "spec/commands/exec_spec.rb",
+ "spec/commands/clean_spec.rb",
+ "spec/commands/platform_spec.rb",
+ "spec/cache/git_spec.rb",
+ "spec/install/gemfile/groups_spec.rb",
+ "spec/commands/cache_spec.rb",
+ "spec/commands/check_spec.rb",
+ "spec/commands/list_spec.rb",
+ "spec/install/path_spec.rb",
+ "spec/bundler/cli_spec.rb",
+ "spec/install/bundler_spec.rb",
+ "spec/install/git_spec.rb",
+ "spec/commands/doctor_spec.rb",
+ "spec/bundler/dsl_spec.rb",
+ "spec/install/gems/fund_spec.rb",
+ "spec/install/gems/env_spec.rb",
+ "spec/bundler/ruby_version_spec.rb",
+ "spec/bundler/definition_spec.rb",
+ "spec/install/gemfile/eval_gemfile_spec.rb",
+ "spec/plugins/source_spec.rb",
+ "spec/install/gems/dependency_api_fallback_spec.rb",
+ "spec/plugins/uninstall_spec.rb",
+ "spec/bundler/plugin/index_spec.rb",
+ "spec/bundler/bundler_spec.rb",
+ "spec/bundler/fetcher_spec.rb",
+ "spec/bundler/source/rubygems/remote_spec.rb",
+ "spec/bundler/lockfile_parser_spec.rb",
+ "spec/cache/cache_path_spec.rb",
+ "spec/bundler/source/git_spec.rb",
+ "spec/bundler/source_spec.rb",
+ "spec/commands/ssl_spec.rb",
+ "spec/bundler/fetcher/compact_index_spec.rb",
+ "spec/bundler/plugin/api_spec.rb",
+ "spec/bundler/endpoint_specification_spec.rb",
+ "spec/bundler/fetcher/index_spec.rb",
+ "spec/bundler/settings/validator_spec.rb",
+ "spec/bundler/build_metadata_spec.rb",
+ "spec/bundler/current_ruby_spec.rb",
+ "spec/bundler/installer/gem_installer_spec.rb",
+ "spec/bundler/installer/parallel_installer_spec.rb",
+ "spec/bundler/cli_common_spec.rb",
+ "spec/bundler/ci_detector_spec.rb",
+ ],
+ shard_d: [
+ "spec/bundler/rubygems_ext_spec.rb",
+ "spec/bundler/resolver/cooldown_spec.rb",
+ "spec/install/cooldown_spec.rb",
+ "spec/commands/outdated_spec.rb",
+ "spec/commands/update_spec.rb",
+ "spec/lock/lockfile_spec.rb",
+ "spec/install/deploy_spec.rb",
+ "spec/install/gemfile/sources_spec.rb",
+ "spec/runtime/self_management_spec.rb",
+ "spec/install/gemfile/specific_platform_spec.rb",
+ "spec/commands/info_spec.rb",
+ "spec/install/gems/resolving_spec.rb",
+ "spec/install/gemfile/platform_spec.rb",
+ "spec/bundler/gem_helper_spec.rb",
+ "spec/install/global_cache_spec.rb",
+ "spec/runtime/platform_spec.rb",
+ "spec/update/gems/post_install_spec.rb",
+ "spec/install/gems/native_extensions_spec.rb",
+ "spec/install/force_spec.rb",
+ "spec/cache/path_spec.rb",
+ "spec/install/gemspecs_spec.rb",
+ "spec/commands/help_spec.rb",
+ "spec/bundler/shared_helpers_spec.rb",
+ "spec/bundler/settings_spec.rb",
+ "spec/resolver/basic_spec.rb",
+ "spec/install/gemfile/force_ruby_platform_spec.rb",
+ "spec/commands/licenses_spec.rb",
+ "spec/install/gemfile/lockfile_spec.rb",
+ "spec/bundler/fetcher/dependency_spec.rb",
+ "spec/quality_spec.rb",
+ "spec/bundler/remote_specification_spec.rb",
+ "spec/install/process_lock_spec.rb",
+ "spec/install/binstubs_spec.rb",
+ "spec/bundler/compact_index_client/updater_spec.rb",
+ "spec/bundler/ui/shell_spec.rb",
+ "spec/other/ext_spec.rb",
+ "spec/commands/issue_spec.rb",
+ "spec/update/path_spec.rb",
+ "spec/bundler/plugin/api/source_spec.rb",
+ "spec/install/gems/win32_spec.rb",
+ "spec/bundler/plugin/dsl_spec.rb",
+ "spec/runtime/requiring_spec.rb",
+ "spec/bundler/plugin/events_spec.rb",
+ "spec/bundler/resolver/candidate_spec.rb",
+ "spec/bundler/digest_spec.rb",
+ "spec/bundler/fetcher/gem_remote_fetcher_spec.rb",
+ "spec/bundler/uri_normalizer_spec.rb",
+ "spec/install/gems/no_build_extension_spec.rb",
+ "spec/install/gems/no_install_plugin_spec.rb",
+ "spec/bundler/override_spec.rb",
+ "spec/install/gemfile/override_spec.rb",
+ ],
+ }.freeze
+ end
+end
diff --git a/spec/bundler/support/silent_logger.rb b/spec/bundler/support/silent_logger.rb
deleted file mode 100644
index 4b270330fd..0000000000
--- a/spec/bundler/support/silent_logger.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-require "webrick"
-module Spec
- class SilentLogger < WEBrick::BasicLog
- def initialize(log_file = nil, level = nil)
- super(log_file, level || FATAL)
- end
- end
-end
diff --git a/spec/bundler/support/subprocess.rb b/spec/bundler/support/subprocess.rb
index a4842166b9..91db80da48 100644
--- a/spec/bundler/support/subprocess.rb
+++ b/spec/bundler/support/subprocess.rb
@@ -22,6 +22,10 @@ module Spec
last_command.stderr
end
+ def stdboth
+ last_command.stdboth
+ end
+
def exitstatus
last_command.exitstatus
end
@@ -34,11 +38,14 @@ module Spec
dir = options[:dir]
env = options[:env] || {}
- command_execution = CommandExecution.new(cmd.to_s, working_directory: dir, timeout: options[:timeout] || 60)
+ command_execution = CommandExecution.new(cmd.to_s, timeout: options[:timeout] || 60)
+
+ open3_opts = {}
+ open3_opts[:chdir] = dir if dir
require "open3"
require "shellwords"
- Open3.popen3(env, *cmd.shellsplit, chdir: dir) do |stdin, stdout, stderr, wait_thr|
+ Open3.popen3(env, *cmd.shellsplit, **open3_opts) do |stdin, stdout, stderr, wait_thr|
yield stdin, stdout, wait_thr if block_given?
stdin.close
diff --git a/spec/bundler/support/switch_rubygems.rb b/spec/bundler/support/switch_rubygems.rb
index a138d22333..640b9f83b7 100644
--- a/spec/bundler/support/switch_rubygems.rb
+++ b/spec/bundler/support/switch_rubygems.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
require_relative "rubygems_version_manager"
+ENV["RGV"] ||= "."
RubygemsVersionManager.new(ENV["RGV"]).switch
diff --git a/spec/bundler/support/the_bundle.rb b/spec/bundler/support/the_bundle.rb
index bda717f3b0..452abd7d41 100644
--- a/spec/bundler/support/the_bundle.rb
+++ b/spec/bundler/support/the_bundle.rb
@@ -8,10 +8,8 @@ module Spec
attr_accessor :bundle_dir
- def initialize(opts = {})
- opts = opts.dup
- @bundle_dir = Pathname.new(opts.delete(:bundle_dir) { bundled_app })
- raise "Too many options! #{opts}" unless opts.empty?
+ def initialize
+ @bundle_dir = Pathname.new(bundled_app)
end
def to_s
@@ -28,7 +26,7 @@ module Spec
end
def locked_gems
- raise "Cannot read lockfile if it doesn't exist" unless locked?
+ raise ArgumentError, "Cannot read lockfile if it doesn't exist" unless locked?
Bundler::LockfileParser.new(lockfile.read)
end
diff --git a/spec/bundler/update/force_spec.rb b/spec/bundler/update/force_spec.rb
new file mode 100644
index 0000000000..325f58088a
--- /dev/null
+++ b/spec/bundler/update/force_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle update" do
+ before :each do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+ end
+
+ it "re-installs installed gems with --force" do
+ myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
+ myrack_lib.open("w") {|f| f.write("blah blah blah") }
+ bundle :update, force: true
+
+ expect(out).to include "Installing myrack 1.0.0"
+ expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+
+ it "re-installs installed gems with --redownload" do
+ myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
+ myrack_lib.open("w") {|f| f.write("blah blah blah") }
+ bundle :update, redownload: true
+
+ expect(out).to include "Installing myrack 1.0.0"
+ expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
+ expect(the_bundle).to include_gems "myrack 1.0.0"
+ end
+end
diff --git a/spec/bundler/update/gemfile_spec.rb b/spec/bundler/update/gemfile_spec.rb
index cb94799061..f8849640b6 100644
--- a/spec/bundler/update/gemfile_spec.rb
+++ b/spec/bundler/update/gemfile_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "bundle update" do
gem 'myrack'
G
- bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
+ bundle_config "gemfile #{bundled_app("NotGemfile")}"
bundle :install
end
diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb
index 2cb0abe02f..526e988ab7 100644
--- a/spec/bundler/update/git_spec.rb
+++ b/spec/bundler/update/git_spec.rb
@@ -199,7 +199,7 @@ RSpec.describe "bundle update" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- lib_path("foo-1.0").join(".git").rmtree
+ FileUtils.rm_rf lib_path("foo-1.0").join(".git")
bundle :update, all: true, raise_on_error: false
expect(err).to include(lib_path("foo-1.0").to_s).
@@ -334,7 +334,7 @@ RSpec.describe "bundle update" do
myrack
#{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
G
end
end
diff --git a/spec/bundler/update/redownload_spec.rb b/spec/bundler/update/redownload_spec.rb
deleted file mode 100644
index 66437fb938..0000000000
--- a/spec/bundler/update/redownload_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "bundle update" do
- before :each do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
- end
-
- describe "with --force" do
- it "shows a deprecation when single flag passed", bundler: 2 do
- bundle "update myrack --force"
- expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
-
- it "shows a deprecation when multiple flags passed", bundler: 2 do
- bundle "update myrack --no-color --force"
- expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
- end
-
- describe "with --redownload" do
- it "does not show a deprecation when single flag passed" do
- bundle "update myrack --redownload"
- expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
-
- it "does not show a deprecation when single multiple flags passed" do
- bundle "update myrack --no-color --redownload"
- expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
- end
-
- it "re-installs installed gems" do
- myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
- myrack_lib.open("w") {|f| f.write("blah blah blah") }
- bundle :update, redownload: true
-
- expect(out).to include "Installing myrack 1.0.0"
- expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
- end
-end
diff --git a/spec/default.mspec b/spec/default.mspec
index 058835cd10..d756dc31ff 100644
--- a/spec/default.mspec
+++ b/spec/default.mspec
@@ -9,6 +9,7 @@ ENV["CHECK_CONSTANT_LEAKS"] ||= "true"
require "./rbconfig" unless defined?(RbConfig)
require_relative "../tool/test-coverage" if ENV.key?("COVERAGE")
+require_relative "../tool/lib/test/jobserver"
load File.dirname(__FILE__) + '/ruby/default.mspec'
OBJDIR = File.expand_path("spec/ruby/optional/capi/ext") unless defined?(OBJDIR)
class MSpecScript
@@ -50,34 +51,10 @@ end
module MSpecScript::JobServer
def cores(max = 1)
- if max > 1 and /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ ENV["MAKEFLAGS"]
- cores = 1
- begin
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- jobtokens = r.read_nonblock(max - 1)
- cores = jobtokens.size
- if cores > 0
- cores += 1
- jobserver = w
- w = nil
- at_exit {
- jobserver.print(jobtokens)
- jobserver.close
- }
- MSpecScript::JobServer.module_eval do
- remove_method :cores
- define_method(:cores) do
- cores
- end
- end
- return cores
- end
- rescue Errno::EBADF
- ensure
- r&.close
- w&.close
- end
+ MSpecScript::JobServer.remove_method :cores
+ if cores = Test::JobServer.max_jobs(max)
+ MSpecScript::JobServer.define_method(:cores) { cores }
+ return cores
end
super
end
diff --git a/spec/mspec/lib/mspec/commands/mspec-ci.rb b/spec/mspec/lib/mspec/commands/mspec-ci.rb
index 9959059ca1..8951572f69 100644
--- a/spec/mspec/lib/mspec/commands/mspec-ci.rb
+++ b/spec/mspec/lib/mspec/commands/mspec-ci.rb
@@ -18,6 +18,7 @@ class MSpecCI < MSpecScript
options.chdir
options.prefix
options.configure { |f| load f }
+ options.repeat
options.pretend
options.interrupt
options.timeout
diff --git a/spec/mspec/lib/mspec/commands/mspec-tag.rb b/spec/mspec/lib/mspec/commands/mspec-tag.rb
index 8b1cb83809..9ce9f048c6 100644
--- a/spec/mspec/lib/mspec/commands/mspec-tag.rb
+++ b/spec/mspec/lib/mspec/commands/mspec-tag.rb
@@ -112,6 +112,7 @@ class MSpecTag < MSpecScript
MSpec.register_mode :pretend
MSpec.register_mode :unguarded
config[:formatter] = false
+ config[:xtags] = []
else
raise ArgumentError, "No recognized action given"
end
diff --git a/spec/mspec/lib/mspec/matchers/base.rb b/spec/mspec/lib/mspec/matchers/base.rb
index d9d7f6fec0..3534520d88 100644
--- a/spec/mspec/lib/mspec/matchers/base.rb
+++ b/spec/mspec/lib/mspec/matchers/base.rb
@@ -36,6 +36,14 @@ class SpecPositiveOperatorMatcher < BasicObject
end
end
+ def raise(exception = ::Exception, message = nil, options = nil, &block)
+ matcher = ::RaiseErrorMatcher.new(exception, message, options, &block)
+ unless matcher.matches? @actual
+ expected, actual = matcher.failure_message
+ ::SpecExpectation.fail_with(expected, actual)
+ end
+ end
+
def method_missing(name, *args, &block)
result = @actual.__send__(name, *args, &block)
unless result
@@ -70,6 +78,14 @@ class SpecNegativeOperatorMatcher < BasicObject
end
end
+ def raise(exception = ::Exception, message = nil, options = nil, &block)
+ matcher = ::RaiseErrorMatcher.new(exception, message, options, &block)
+ if matcher.matches? @actual
+ expected, actual = matcher.negative_failure_message
+ ::SpecExpectation.fail_with(expected, actual)
+ end
+ end
+
def method_missing(name, *args, &block)
result = @actual.__send__(name, *args, &block)
if result
diff --git a/spec/mspec/lib/mspec/matchers/raise_error.rb b/spec/mspec/lib/mspec/matchers/raise_error.rb
index 54378bb34c..8cba842ce3 100644
--- a/spec/mspec/lib/mspec/matchers/raise_error.rb
+++ b/spec/mspec/lib/mspec/matchers/raise_error.rb
@@ -1,11 +1,18 @@
class RaiseErrorMatcher
FAILURE_MESSAGE_FOR_EXCEPTION = {}.compare_by_identity
+ UNDEF_CAUSE = Object.new
attr_writer :block
- def initialize(exception, message, &block)
+ def initialize(exception, message = nil, options = nil, &block)
+ if message.is_a? Hash
+ @message = nil
+ options = message
+ else
+ @message = message
+ end
+ @cause = options ? options.fetch(:cause, UNDEF_CAUSE) : UNDEF_CAUSE
@exception = exception
- @message = message
@block = block
@actual = nil
end
@@ -45,24 +52,45 @@ class RaiseErrorMatcher
end
end
+ def matching_cause?(exc)
+ case @cause
+ when UNDEF_CAUSE
+ true
+ else
+ @cause == exc.cause
+ end
+ end
+
def matching_exception?(exc)
- matching_class?(exc) and matching_message?(exc)
+ matching_class?(exc) and matching_message?(exc) and matching_cause?(exc)
end
- def exception_class_and_message(exception_class, message)
- if message
- "#{exception_class} (#{message})"
- else
- "#{exception_class}"
+ def exception_class_and_message_and_cause(exception_class, message, cause)
+ string = "#{exception_class}"
+ prefixed = false
+ prefix = -> { prefixed ? ", " : prefixed = "(" }
+
+ if message != nil
+ string << "#{prefix.()}#{message.inspect}"
+ end
+
+ if cause != UNDEF_CAUSE
+ string << "#{prefix.()}cause: #{cause.inspect}"
end
+
+ string << ")" if prefixed
+
+ string
end
def format_expected_exception
- exception_class_and_message(@exception, @message)
+ exception_class_and_message_and_cause(@exception, @message, @cause)
end
def format_exception(exception)
- exception_class_and_message(exception.class, exception.message)
+ exception_class_and_message_and_cause(exception.class,
+ @message == nil ? nil : exception.message,
+ @cause == UNDEF_CAUSE ? UNDEF_CAUSE : exception.cause)
end
def failure_message
@@ -87,7 +115,18 @@ class RaiseErrorMatcher
end
module MSpecMatchers
- private def raise_error(exception = Exception, message = nil, &block)
- RaiseErrorMatcher.new(exception, message, &block)
+ private def raise_error(exception = Exception, message = nil, options = nil, &block)
+ RaiseErrorMatcher.new(exception, message, options, &block)
+ end
+
+ # CRuby < 4.1 has inconsistent coercion errors:
+ # https://bugs.ruby-lang.org/issues/21864
+ # This matcher ignores the message on CRuby < 4.1
+ # and checks the message for all other cases, including other Rubies
+ private def raise_consistent_error(exception = Exception, message = nil, options = nil, &block)
+ if RUBY_ENGINE == "ruby" and ruby_version_is ""..."4.1"
+ message = nil
+ end
+ RaiseErrorMatcher.new(exception, message, options, &block)
end
end
diff --git a/spec/mspec/lib/mspec/runner/formatters/base.rb b/spec/mspec/lib/mspec/runner/formatters/base.rb
index e3b5bb23e0..882e15c8c2 100644
--- a/spec/mspec/lib/mspec/runner/formatters/base.rb
+++ b/spec/mspec/lib/mspec/runner/formatters/base.rb
@@ -46,7 +46,7 @@ class BaseFormatter
LeakCheckerAction.new.register
end
- if ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']
+ if (ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']) && ENV['CHECK_CONSTANT_LEAKS'] != 'false'
save = ENV['CHECK_LEAKS'] == 'save' || ENV['CHECK_CONSTANT_LEAKS'] == 'save'
ConstantsLeakCheckerAction.new(save).register
end
diff --git a/spec/mspec/lib/mspec/runner/mspec.rb b/spec/mspec/lib/mspec/runner/mspec.rb
index 97c3f365bc..0e016c67a7 100644
--- a/spec/mspec/lib/mspec/runner/mspec.rb
+++ b/spec/mspec/lib/mspec/runner/mspec.rb
@@ -365,6 +365,7 @@ module MSpec
# Writes each tag in +tags+ to the tag file. Overwrites the
# tag file if it exists.
def self.write_tags(tags)
+ return delete_tags if tags.empty?
file = tags_file
make_tag_dir(file)
File.open(file, "w:utf-8") do |f|
diff --git a/spec/mspec/lib/mspec/utils/name_map.rb b/spec/mspec/lib/mspec/utils/name_map.rb
index bf70e651a2..9b04112e2e 100644
--- a/spec/mspec/lib/mspec/utils/name_map.rb
+++ b/spec/mspec/lib/mspec/utils/name_map.rb
@@ -66,10 +66,17 @@ class NameMap
end
def class_or_module(c)
- const = Object.const_get(c, false)
+ begin
+ const = Object.const_get(c, false)
+ rescue NameError, RuntimeError
+ # Either the constant doesn't exist or it is
+ # explicitly raising an error, like `SortedSet`.
+ return nil
+ end
+ return nil unless Module === const
+
filtered = @filter && EXCLUDED.include?(const.name)
- return const if Module === const and !filtered
- rescue NameError
+ return const unless filtered
end
def namespace(mod, const)
diff --git a/spec/mspec/spec/commands/mspec_ci_spec.rb b/spec/mspec/spec/commands/mspec_ci_spec.rb
index bcbc5b4224..b8dc9d062f 100644
--- a/spec/mspec/spec/commands/mspec_ci_spec.rb
+++ b/spec/mspec/spec/commands/mspec_ci_spec.rb
@@ -78,6 +78,11 @@ RSpec.describe MSpecCI, "#options" do
@script.options []
end
+ it "enables the repeat option" do
+ expect(@options).to receive(:repeat)
+ @script.options @argv
+ end
+
it "calls #custom_options" do
expect(@script).to receive(:custom_options).with(@options)
@script.options []
diff --git a/spec/mspec/spec/commands/mspec_run_spec.rb b/spec/mspec/spec/commands/mspec_run_spec.rb
index 62acd49d7f..f96be2b43e 100644
--- a/spec/mspec/spec/commands/mspec_run_spec.rb
+++ b/spec/mspec/spec/commands/mspec_run_spec.rb
@@ -105,6 +105,11 @@ RSpec.describe MSpecRun, "#options" do
@script.options @argv
end
+ it "enables the repeat option" do
+ expect(@options).to receive(:repeat)
+ @script.options @argv
+ end
+
it "exits if there are no files to process and './spec' is not a directory" do
expect(File).to receive(:directory?).with("./spec").and_return(false)
expect(@options).to receive(:parse).and_return([])
diff --git a/spec/mspec/spec/matchers/raise_error_spec.rb b/spec/mspec/spec/matchers/raise_error_spec.rb
index 8613eee118..3849c7dd2a 100644
--- a/spec/mspec/spec/matchers/raise_error_spec.rb
+++ b/spec/mspec/spec/matchers/raise_error_spec.rb
@@ -84,10 +84,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (message)", "but got: UnexpectedException (message)"]
+ ['Expected ExpectedException("message")', 'but got: UnexpectedException("message")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (message)\nbut got: UnexpectedException (message)"
+ "Expected ExpectedException(\"message\")\nbut got: UnexpectedException(\"message\")"
)
else
raise "no exception"
@@ -103,10 +103,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue ExpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but got: ExpectedException (unexpected)"]
+ ['Expected ExpectedException("expected")', 'but got: ExpectedException("unexpected")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (expected)\nbut got: ExpectedException (unexpected)"
+ "Expected ExpectedException(\"expected\")\nbut got: ExpectedException(\"unexpected\")"
)
else
raise "no exception"
@@ -122,10 +122,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but got: UnexpectedException (unexpected)"]
+ ['Expected ExpectedException("expected")', 'but got: UnexpectedException("unexpected")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (expected)\nbut got: UnexpectedException (unexpected)"
+ "Expected ExpectedException(\"expected\")\nbut got: UnexpectedException(\"unexpected\")"
)
else
raise "no exception"
@@ -137,7 +137,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (120 was returned)"]
+ ['Expected ExpectedException("expected")', "but no exception was raised (120 was returned)"]
)
end
@@ -146,7 +146,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (nil was returned)"]
+ ['Expected ExpectedException("expected")', "but no exception was raised (nil was returned)"]
)
end
@@ -159,7 +159,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (#<Object>(#pretty_inspect raised #<ArgumentError: bad>) was returned)"]
+ ['Expected ExpectedException("expected")', 'but no exception was raised (#<Object>(#pretty_inspect raised #<ArgumentError: bad>) was returned)']
)
end
@@ -168,7 +168,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.negative_failure_message).to eq(
- ["Expected to not get ExpectedException (expected)", ""]
+ ['Expected to not get ExpectedException("expected")', ""]
)
end
@@ -177,7 +177,58 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(Exception, nil)
matcher.matches?(proc)
expect(matcher.negative_failure_message).to eq(
- ["Expected to not get Exception", "but got: UnexpectedException (unexpected)"]
+ ['Expected to not get Exception', 'but got: UnexpectedException']
)
end
+
+ it "matches cause if given" do
+ cause = RuntimeError.new("foo")
+ proc = -> do
+ raise cause
+ rescue
+ raise "bar"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, cause: cause)
+ expect(matcher.matches?(proc)).to eq(true)
+ end
+
+ it "matches message and cause if given" do
+ cause = RuntimeError.new("foo")
+ proc = -> do
+ raise cause
+ rescue
+ raise "bar"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, "bar", cause: cause)
+ expect(matcher.matches?(proc)).to eq(true)
+ end
+
+ it "provides useful negative failure message when cause does not match" do
+ cause = RuntimeError.new("bar")
+ proc = -> do
+ raise "foo"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, cause: cause)
+
+ begin
+ matcher.matches?(proc)
+ rescue RuntimeError
+ expect(matcher.failure_message).to eq(
+ ['Expected RuntimeError(cause: #<RuntimeError: bar>)', 'but got: RuntimeError(cause: nil)']
+ )
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, "foo", cause: cause)
+
+ begin
+ matcher.matches?(proc)
+ rescue RuntimeError
+ expect(matcher.failure_message).to eq(
+ ['Expected RuntimeError("foo", cause: #<RuntimeError: bar>)', 'but got: RuntimeError("foo", cause: nil)']
+ )
+ end
+ end
end
diff --git a/spec/mspec/spec/utils/fixtures/this_file_raises.rb b/spec/mspec/spec/utils/fixtures/this_file_raises.rb
new file mode 100644
index 0000000000..8e37a587bf
--- /dev/null
+++ b/spec/mspec/spec/utils/fixtures/this_file_raises.rb
@@ -0,0 +1 @@
+raise "This is a BAD file"
diff --git a/spec/mspec/spec/utils/fixtures/this_file_raises2.rb b/spec/mspec/spec/utils/fixtures/this_file_raises2.rb
new file mode 100644
index 0000000000..8efc10199a
--- /dev/null
+++ b/spec/mspec/spec/utils/fixtures/this_file_raises2.rb
@@ -0,0 +1 @@
+raise "This is a BAD file 2"
diff --git a/spec/mspec/spec/utils/name_map_spec.rb b/spec/mspec/spec/utils/name_map_spec.rb
index a18a481500..a42dc9ffec 100644
--- a/spec/mspec/spec/utils/name_map_spec.rb
+++ b/spec/mspec/spec/utils/name_map_spec.rb
@@ -21,6 +21,9 @@ module NameMapSpecs
def f; end
end
+ autoload :BadFile, "#{__dir__}/fixtures/this_file_raises.rb"
+ autoload :BadFile2, "#{__dir__}/fixtures/this_file_raises2.rb"
+
def self.n; end
def n; end
end
@@ -84,6 +87,15 @@ RSpec.describe NameMap, "#class_or_module" do
expect(@map.class_or_module("Hell")).to eq(nil)
expect(@map.class_or_module("Bush::Brain")).to eq(nil)
end
+
+ it "returns nil if accessing the constant raises RuntimeError" do
+ expect { NameMapSpecs::BadFile }.to raise_error(RuntimeError)
+ expect(@map.class_or_module("NameMapSpecs::BadFile")).to eq(nil)
+ end
+
+ it "returns nil if accessing the constant raises RuntimeError when not triggering the autoload before" do
+ expect(@map.class_or_module("NameMapSpecs::BadFile2")).to eq(nil)
+ end
end
RSpec.describe NameMap, "#dir_name" do
diff --git a/spec/mspec/tool/remove_old_guards.rb b/spec/mspec/tool/remove_old_guards.rb
index 75c48e0584..bc5612c78d 100755
--- a/spec/mspec/tool/remove_old_guards.rb
+++ b/spec/mspec/tool/remove_old_guards.rb
@@ -31,6 +31,12 @@ def each_spec_file(&block)
Dir["*/**/*.rb"].each(&block)
end
+def each_file(&block)
+ Dir["**/*"].each { |path|
+ yield path if File.file?(path)
+ }
+end
+
def remove_guards(guard, keep)
each_spec_file do |file|
contents = File.binread(file)
@@ -109,7 +115,7 @@ def remove_unused_shared_specs
end
def search(regexp)
- each_spec_file do |file|
+ each_file do |file|
contents = File.binread(file)
if contents =~ regexp
puts file
@@ -136,3 +142,4 @@ remove_unused_shared_specs
puts "Search:"
search(/(["'])#{version}\1/)
search(/^\s*#.+#{version}/)
+search(/RUBY_VERSION_IS_#{version.tr('.', '_')}/)
diff --git a/spec/mspec/tool/sync/sync-rubyspec.rb b/spec/mspec/tool/sync/sync-rubyspec.rb
index effccc1567..86c43d0dc8 100644
--- a/spec/mspec/tool/sync/sync-rubyspec.rb
+++ b/spec/mspec/tool/sync/sync-rubyspec.rb
@@ -3,7 +3,7 @@
IMPLS = {
truffleruby: {
- git: "https://github.com/oracle/truffleruby.git",
+ git: "https://github.com/truffleruby/truffleruby.git",
from_commit: "f10ab6988d",
},
jruby: {
@@ -34,6 +34,13 @@ raise RUBYSPEC_REPO unless Dir.exist?(RUBYSPEC_REPO)
SOURCE_REPO = MSPEC ? MSPEC_REPO : RUBYSPEC_REPO
+# LAST_MERGE is a commit of ruby/spec or ruby/mspec
+# which is the spec/mspec commit that was last imported in the Ruby implementation
+# (i.e. the commit in "Update to ruby/spec@commit").
+# It is normally automatically computed, but can be manually set when
+# e.g. the last update of specs wasn't merged in the Ruby implementation.
+LAST_MERGE = ENV["LAST_MERGE"]
+
NOW = Time.now
BRIGHT_RED = "\e[31;1m"
@@ -142,8 +149,8 @@ def rebase_commits(impl)
else
sh "git", "checkout", impl.name
- if ENV["LAST_MERGE"]
- last_merge = `git log -n 1 --format='%H %ct' #{ENV["LAST_MERGE"]}`
+ if LAST_MERGE
+ last_merge = `git log -n 1 --format='%H %ct' #{LAST_MERGE}`
else
last_merge = `git log --grep='^#{impl.last_merge_message}' -n 1 --format='%H %ct'`
end
@@ -183,30 +190,20 @@ def test_new_specs
Dir.chdir(SOURCE_REPO) do
workflow = YAML.load_file(".github/workflows/ci.yml")
job_name = MSPEC ? "test" : "specs"
- versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby")
+ versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby").map(&:to_s)
versions = versions.grep(/^\d+\./) # Test on MRI
min_version, max_version = versions.minmax
test_command = MSPEC ? "bundle install && bundle exec rspec" : "../mspec/bin/mspec -j"
run_test = -> version {
- command = "chruby #{version} && #{test_command}"
+ command = "chruby ruby-#{version} && #{test_command}"
sh ENV["SHELL"], "-c", command
}
run_test[min_version]
run_test[max_version]
- run_test["ruby-master"] if TEST_MASTER
- end
-end
-
-def verify_commits(impl)
- puts
- Dir.chdir(SOURCE_REPO) do
- puts "Manually check commit messages:"
- print "Press enter >"
- STDIN.gets
- system "git", "log", "master..."
+ run_test["master"] if TEST_MASTER
end
end
@@ -236,7 +233,6 @@ def main(impls)
rebase_commits(impl)
if new_commits?(impl)
test_new_specs
- verify_commits(impl)
fast_forward_master(impl)
check_ci
else
diff --git a/spec/mspec/tool/tag_from_output.rb b/spec/mspec/tool/tag_from_output.rb
index b6b4603855..41aa70f932 100755
--- a/spec/mspec/tool/tag_from_output.rb
+++ b/spec/mspec/tool/tag_from_output.rb
@@ -20,7 +20,7 @@ end
NUMBER = /^\d+\)$/
ERROR_OR_FAILED = / (ERROR|FAILED)$/
-SPEC_FILE = /^(\/.+_spec\.rb)\:\d+/
+SPEC_FILE = /^((?:\/|[CD]:\/).+_spec\.rb)\:\d+/
output.slice_before(NUMBER).select { |number, *rest|
number =~ NUMBER and rest.any? { |line| line =~ ERROR_OR_FAILED }
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index a385b5e79c..0b5dcb80a2 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -1,7 +1,7 @@
inherit_from: .rubocop_todo.yml
AllCops:
- TargetRubyVersion: 3.1
+ TargetRubyVersion: 3.2
DisplayCopNames: true
Exclude:
- command_line/fixtures/bad_syntax.rb
@@ -54,10 +54,6 @@ Lint/RedundantRequireStatement:
- library/fiber/**/*.rb
- optional/capi/fiber_spec.rb
-Lint/RedundantSafeNavigation:
- Exclude:
- - language/safe_navigator_spec.rb
-
Lint/RedundantSplatExpansion:
Enabled: false
@@ -197,6 +193,7 @@ Style/Lambda:
- 'language/lambda_spec.rb'
- 'language/proc_spec.rb'
- 'language/numbered_parameters_spec.rb'
+ - 'language/it_parameter_spec.rb'
- 'core/kernel/lambda_spec.rb'
Style/EmptyLambdaParameter:
diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml
index 6b43db9b9a..f998002c6d 100644
--- a/spec/ruby/.rubocop_todo.yml
+++ b/spec/ruby/.rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2024-10-12 16:01:45 UTC using RuboCop version 1.66.1.
+# on 2026-05-29 08:10:07 UTC using RuboCop version 1.86.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -11,17 +11,22 @@ Lint/DuplicateCaseCondition:
Exclude:
- 'language/case_spec.rb'
-# Offense count: 6
+# Offense count: 20
Lint/DuplicateMethods:
Exclude:
- 'core/array/fixtures/encoded_strings.rb'
- 'core/method/fixtures/classes.rb'
+ - 'core/module/const_added_spec.rb'
+ - 'core/module/define_method_spec.rb'
- 'core/module/fixtures/classes.rb'
+ - 'core/module/method_added_spec.rb'
+ - 'core/module/name_spec.rb'
+ - 'core/proc/new_spec.rb'
- 'core/unboundmethod/fixtures/classes.rb'
- 'fixtures/class.rb'
+ - 'language/assignments_spec.rb'
# Offense count: 8
-# This cop supports safe autocorrection (--autocorrect).
Lint/EnsureReturn:
Exclude:
- 'language/fixtures/ensure.rb'
@@ -39,10 +44,11 @@ Lint/FloatOutOfRange:
Exclude:
- 'core/string/modulo_spec.rb'
-# Offense count: 2
+# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
Lint/ImplicitStringConcatenation:
Exclude:
+ - 'core/string/chilled_string_spec.rb'
- 'language/string_spec.rb'
# Offense count: 4
@@ -52,12 +58,11 @@ Lint/IneffectiveAccessModifier:
- 'core/module/fixtures/classes.rb'
- 'language/fixtures/private.rb'
-# Offense count: 71
+# Offense count: 12
# This cop supports safe autocorrection (--autocorrect).
Lint/LiteralInInterpolation:
Exclude:
- 'core/module/refine_spec.rb'
- - 'core/regexp/shared/new.rb'
- 'core/string/shared/to_sym.rb'
- 'language/alias_spec.rb'
- 'language/defined_spec.rb'
@@ -79,6 +84,16 @@ Lint/ParenthesesAsGroupedExpression:
- 'language/block_spec.rb'
- 'language/method_spec.rb'
+# Offense count: 1
+# This cop supports unsafe autocorrection (--autocorrect-all).
+# Configuration parameters: AllowedMethods, InferNonNilReceiver, AdditionalNilMethods.
+# AllowedMethods: instance_of?, kind_of?, is_a?, eql?, respond_to?, equal?
+# AdditionalNilMethods: present?, blank?, try, try!
+Lint/RedundantSafeNavigation:
+ Exclude:
+ - 'language/safe_navigator_spec.rb'
+ - 'language/fixtures/rescue_captures.rb'
+
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
Lint/RedundantStringCoercion:
@@ -86,6 +101,7 @@ Lint/RedundantStringCoercion:
- 'core/io/print_spec.rb'
# Offense count: 1
+# Configuration parameters: AllowRBSInlineAnnotation.
Lint/SelfAssignment:
Exclude:
- 'core/gc/auto_compact_spec.rb'
@@ -96,7 +112,7 @@ Lint/ShadowedArgument:
Exclude:
- 'language/fixtures/super.rb'
-# Offense count: 45
+# Offense count: 49
# Configuration parameters: AllowComments, AllowNil.
Lint/SuppressedException:
Enabled: false
@@ -109,13 +125,14 @@ Lint/UnderscorePrefixedVariableName:
- 'core/io/popen_spec.rb'
- 'language/block_spec.rb'
-# Offense count: 7
+# Offense count: 9
# This cop supports safe autocorrection (--autocorrect).
-# Configuration parameters: AutoCorrect, ContextCreatingMethods, MethodCreatingMethods.
+# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
Lint/UselessAccessModifier:
Exclude:
- 'core/module/define_method_spec.rb'
- 'core/module/fixtures/classes.rb'
- 'core/module/module_function_spec.rb'
- 'core/module/private_class_method_spec.rb'
+ - 'language/fixtures/def.rb'
- 'language/fixtures/send.rb'
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md
index 366b484bad..a474e205f0 100644
--- a/spec/ruby/CONTRIBUTING.md
+++ b/spec/ruby/CONTRIBUTING.md
@@ -55,6 +55,11 @@ which indicates the file was generated but the method unspecified.
Here is a list of frequently-used matchers, which should be enough for most specs.
There are a few extra specific matchers used in the couple specs that need it.
+The general idea is: add `.should` just before the predicate you expect to be truthy, and done!
+This works for most needs and provides a great error when it fails.
+It's immediately clear which method is used and there no need to remember a mapping like in RSpec between e.g. `eq` and `==`.
+See [this blog post](https://eregon.me/blog/2019/10/07/a-new-should-syntax.html) for the motivation behind that syntax.
+
#### Comparison matchers
```ruby
@@ -83,43 +88,37 @@ File.should.equal?(File) # Calls #equal? (tests identity)
(0.1 + 0.2).should be_close(0.3, TOLERANCE) # (0.2-0.1).abs < TOLERANCE
(0.0/0.0).should.nan?
-(1.0/0.0).should be_positive_infinity
-(-1.0/0.0).should be_negative_infinity
-3.14.should be_an_instance_of(Float) # Calls #instance_of?
-3.14.should be_kind_of(Numeric) # Calls #is_a?
-Numeric.should be_ancestor_of(Float) # Float.ancestors.include?(Numeric)
+3.14.should.instance_of?(Float) # Calls #instance_of?
+3.14.should.is_a?(Numeric) # Calls #is_a?
3.14.should.respond_to?(:to_i)
-Integer.should have_instance_method(:+)
-Array.should have_method(:new)
+Integer.should.method_defined?(:+, false)
```
-Also `have_constant`, `have_private_instance_method`, `have_singleton_method`, etc.
-
#### Exception matchers
```ruby
-> {
raise "oops"
-}.should raise_error(RuntimeError, /oops/)
+}.should.raise(RuntimeError, /oops/)
-> {
raise "oops"
-}.should raise_error(RuntimeError) { |e|
+}.should.raise(RuntimeError) { |e|
# Custom checks on the Exception object
e.message.should.include?("oops")
e.cause.should == nil
}
```
-##### `should_not raise_error`
+##### `should_not.raise`
**Avoid this!** Instead, use an expectation testing what the code in the lambda does.
If an exception is raised, it will fail the example anyway.
```ruby
--> { ... }.should_not raise_error
+-> { ... }.should_not.raise
```
#### Warning matcher
@@ -230,7 +229,7 @@ to avoid duplication of specs, we have shared specs that are re-used in other sp
bit tricky however, so let's go over it.
Commonly, if a shared spec is only reused within its own module, the shared spec will live within a
-shared directory inside that module's directory. For example, the `core/hash/shared/key.rb` spec is
+shared directory inside that module's directory. For example, the `core/hash/shared/iteration.rb` spec is
only used by `Hash` specs, and so it lives inside `core/hash/shared/`.
When a shared spec is used across multiple modules or classes, it lives within the `shared/` directory.
@@ -244,25 +243,25 @@ variables from the implementor spec: `@method` and `@object`, which the implemen
Here's an example of a snippet of a shared spec and two specs which integrates it:
```ruby
-# core/hash/shared/key.rb
-describe :hash_key_p, shared: true do
- it "returns true if the key's matching value was false" do
- { xyz: false }.send(@method, :xyz).should == true
+# core/hash/shared/iteration.rb
+describe :hash_iteration_no_block, shared: true do
+ it "returns an Enumerator if called on a non-empty hash without a block" do
+ { 1 => 2 }.send(@method).should.instance_of?(Enumerator)
end
end
-# core/hash/key_spec.rb
-describe "Hash#key?" do
- it_behaves_like :hash_key_p, :key?
+# core/hash/select_spec.rb
+describe "Hash#select" do
+ it_behaves_like :hash_iteration_no_block, :select
end
-# core/hash/include_spec.rb
-describe "Hash#include?" do
- it_behaves_like :hash_key_p, :include?
+# core/hash/reject_spec.rb
+describe "Hash#reject" do
+ it_behaves_like :hash_iteration_no_block, :reject
end
```
-In the example, the first `describe` defines the shared spec `:hash_key_p`, which defines a spec that
+In the example, the first `describe` defines the shared spec `:hash_iteration_no_block`, which defines a spec that
calls the `@method` method with an expectation. In the implementor spec, we use `it_behaves_like` to
integrate the shared spec. `it_behaves_like` takes 3 parameters: the key of the shared spec, a method,
and an object. These last two parameters are accessible via `@method` and `@object` in the shared spec.
@@ -274,7 +273,7 @@ how this is used currently:
```ruby
describe :kernel_sprintf, shared: true do
it "raises TypeError exception if cannot convert to Integer" do
- -> { @method.call("%b", Object.new) }.should raise_error(TypeError)
+ -> { @method.call("%b", Object.new) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index ee1015c24c..b259a97e21 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -26,12 +26,12 @@ ruby/spec is known to be tested in these implementations for every commit:
* [MRI](https://rubyci.org/) on 30 platforms and 4 versions
* [JRuby](https://github.com/jruby/jruby/tree/master/spec/ruby) for both 1.7 and 9.x
-* [TruffleRuby](https://github.com/oracle/truffleruby/tree/master/spec/ruby)
+* [TruffleRuby](https://github.com/truffleruby/truffleruby/tree/master/spec/ruby)
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)
-ruby/spec describes the behavior of Ruby 3.1 and more recent Ruby versions.
-More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.1.x, 3.2.x, etc), and those are tested in CI.
+ruby/spec describes the behavior of Ruby 3.3 and more recent Ruby versions.
+More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.3.x, 3.4.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations
@@ -63,6 +63,8 @@ For older specs try these commits:
* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661)
* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
* Ruby 3.0.7 - [Suite](https://github.com/ruby/spec/commit/affef93d9940f615e4836f64b011da211f570913) using [MSpec](https://github.com/ruby/mspec/commit/0aabb3e548eb5ea6cad0125f8f46cee34542b6b7)
+* Ruby 3.1.6 - [Suite](https://github.com/ruby/spec/commit/ec960f2389d1c2265d32397fa8afa6d462014efc) using [MSpec](https://github.com/ruby/mspec/commit/484310dbed35b84c74484fd674602f88c42d063a)
+* Ruby 3.2.9 - [Suite](https://github.com/ruby/spec/commit/97f076242b7fc6e60703e6a6053365065cd6fc30) using [MSpec](https://github.com/ruby/mspec/commit/54704795e21128a930af2021c72c49cb87065134)
### Running the specs
diff --git a/spec/ruby/bin/rubocop b/spec/ruby/bin/rubocop
index 38254f13e4..0937c47906 100755
--- a/spec/ruby/bin/rubocop
+++ b/spec/ruby/bin/rubocop
@@ -6,7 +6,7 @@ require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
- gem 'rubocop', '1.66.1'
+ gem 'rubocop', '1.86.2'
end
exec(Gem.bin_path('rubocop', 'rubocop'), *ARGV)
diff --git a/spec/ruby/command_line/dash_0_spec.rb b/spec/ruby/command_line/dash_0_spec.rb
index 73c5e29004..2ce4f49b5e 100755
--- a/spec/ruby/command_line/dash_0_spec.rb
+++ b/spec/ruby/command_line/dash_0_spec.rb
@@ -5,7 +5,7 @@ describe "The -0 command line option" do
ruby_exe("puts $/, $-0", options: "-072").should == ":\n:\n"
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "sets $/ and $-0 as a frozen string" do
ruby_exe("puts $/.frozen?, $-0.frozen?", options: "-072").should == "true\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb
index 9f673c53dc..0de9ba2e24 100644
--- a/spec/ruby/command_line/dash_r_spec.rb
+++ b/spec/ruby/command_line/dash_r_spec.rb
@@ -8,18 +8,15 @@ describe "The -r command line option" do
it "requires the specified file" do
out = ruby_exe(@script, options: "-r #{@test_file}")
- out.should include("REQUIRED")
- out.should include(@test_file + ".rb")
+ out.should.include?("REQUIRED")
+ out.should.include?(@test_file + ".rb")
end
it "requires the file before parsing the main script" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1)
$?.should_not.success?
- out.should include("REQUIRED")
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should.include?("REQUIRED")
+ out.should.include?("SyntaxError")
end
it "does not require the file if the main script file does not exist" do
diff --git a/spec/ruby/command_line/dash_upper_i_spec.rb b/spec/ruby/command_line/dash_upper_i_spec.rb
index 4cafb724e3..4005a27d23 100644
--- a/spec/ruby/command_line/dash_upper_i_spec.rb
+++ b/spec/ruby/command_line/dash_upper_i_spec.rb
@@ -6,7 +6,7 @@ describe "The -I command line option" do
end
it "adds the path to the load path ($:)" do
- ruby_exe(@script, options: "-I fixtures").should include("fixtures")
+ ruby_exe(@script, options: "-I fixtures").should.include?("fixtures")
end
it "adds the path at the front of $LOAD_PATH" do
@@ -18,16 +18,16 @@ describe "The -I command line option" do
idx.should < 2
idx.should < lines.size-1
else
- lines[0].should include("fixtures")
+ lines[0].should.include?("fixtures")
end
end
it "adds the path expanded from CWD to $LOAD_PATH" do
- ruby_exe(@script, options: "-I fixtures").lines.should include "#{Dir.pwd}/fixtures\n"
+ ruby_exe(@script, options: "-I fixtures").lines.should.include? "#{Dir.pwd}/fixtures\n"
end
it "expands a path from CWD even if it does not exist" do
- ruby_exe(@script, options: "-I not_exist/not_exist").lines.should include "#{Dir.pwd}/not_exist/not_exist\n"
+ ruby_exe(@script, options: "-I not_exist/not_exist").lines.should.include? "#{Dir.pwd}/not_exist/not_exist\n"
end
end
@@ -45,7 +45,7 @@ platform_is_not :windows do
end
it "does not expand symlinks" do
- ruby_exe(@script, options: "-I #{@symlink}").lines.should include "#{@symlink}\n"
+ ruby_exe(@script, options: "-I #{@symlink}").lines.should.include? "#{@symlink}\n"
end
end
end
diff --git a/spec/ruby/command_line/dash_upper_s_spec.rb b/spec/ruby/command_line/dash_upper_s_spec.rb
index 17991503f1..71c6016659 100644
--- a/spec/ruby/command_line/dash_upper_s_spec.rb
+++ b/spec/ruby/command_line/dash_upper_s_spec.rb
@@ -2,7 +2,8 @@ require_relative '../spec_helper'
describe 'The -S command line option' do
before :each do
- @path = [ENV['PATH'], fixture(__FILE__, "bin")].join(':')
+ @bin = fixture(__FILE__, "bin")
+ @path = [ENV['PATH'], @bin].join(File::PATH_SEPARATOR)
end
platform_is_not :windows do
@@ -10,20 +11,57 @@ describe 'The -S command line option' do
# and MRI shows warning when including world writable path in ENV['PATH'].
# This is why we are using /success$/ matching in the following cases.
+ it "runs launcher found in RUBYPATH, but only code after the first /\#!.*ruby.*/-ish line in target file" do
+ result = ruby_exe(nil, options: '-S hybrid_launcher.sh', env: { 'RUBYPATH' => @bin }, args: '2>&1')
+ result.should =~ /success$/
+ end
+
it "runs launcher found in PATH, but only code after the first /\#!.*ruby.*/-ish line in target file" do
result = ruby_exe(nil, options: '-S hybrid_launcher.sh', env: { 'PATH' => @path }, args: '2>&1')
result.should =~ /success$/
end
+ it "runs launcher found in RUBYPATH" do
+ result = ruby_exe(nil, options: '-S launcher.rb', env: { 'RUBYPATH' => @bin }, args: '2>&1')
+ result.should =~ /success$/
+ end
+
it "runs launcher found in PATH" do
result = ruby_exe(nil, options: '-S launcher.rb', env: { 'PATH' => @path }, args: '2>&1')
result.should =~ /success$/
end
+ it "runs launcher found in RUBYPATH and sets the exit status to 1 if it fails" do
+ result = ruby_exe(nil, options: '-S dash_s_fail', env: { 'RUBYPATH' => @bin }, args: '2>&1', exit_status: 1)
+ result.should =~ /\bdie\b/
+ $?.exitstatus.should == 1
+ end
+
it "runs launcher found in PATH and sets the exit status to 1 if it fails" do
result = ruby_exe(nil, options: '-S dash_s_fail', env: { 'PATH' => @path }, args: '2>&1', exit_status: 1)
result.should =~ /\bdie\b/
$?.exitstatus.should == 1
end
+
+ ruby_version_is "4.1" do
+ describe "if the script name contains separator" do
+ before(:each) do
+ @bin = File.dirname(@bin)
+ @path = [ENV['PATH'], @bin].join(File::PATH_SEPARATOR)
+ end
+
+ it "does not search launcher in RUBYPATH" do
+ result = ruby_exe(nil, options: '-S bin/launcher.rb', env: { 'RUBYPATH' => @bin }, args: '2>&1', exit_status: 1)
+ result.should =~ /LoadError/
+ $?.should_not.success?
+ end
+
+ it "does not search launcher in PATH" do
+ result = ruby_exe(nil, options: '-S bin/launcher.rb', env: { 'PATH' => @path }, args: '2>&1', exit_status: 1)
+ result.should =~ /LoadError/
+ $?.should_not.success?
+ end
+ end
+ end
end
end
diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb
index d30efa37d6..6a4f7d3a15 100644
--- a/spec/ruby/command_line/dash_v_spec.rb
+++ b/spec/ruby/command_line/dash_v_spec.rb
@@ -6,7 +6,7 @@ describe "The -v command line option" do
describe "when used alone" do
it "prints version and ends" do
- ruby_exe(nil, args: '-v').sub("+PRISM ", "").should include(RUBY_DESCRIPTION.sub("+PRISM ", ""))
+ ruby_exe(nil, args: '-v').gsub("+PRISM ", "").should.include?(RUBY_DESCRIPTION.gsub("+PRISM ", ""))
end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) ||
(defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?) ||
(ENV['RUBY_GC_LIBRARY'] && ENV['RUBY_GC_LIBRARY'].length > 0) ||
diff --git a/spec/ruby/command_line/dash_x_spec.rb b/spec/ruby/command_line/dash_x_spec.rb
index ae14b61070..38f97a5ab1 100644
--- a/spec/ruby/command_line/dash_x_spec.rb
+++ b/spec/ruby/command_line/dash_x_spec.rb
@@ -10,7 +10,7 @@ describe "The -x command line option" do
it "fails when /\#!.*ruby.*/-ish line in target file is not found" do
bad_embedded_ruby = fixture __FILE__, "bin/bad_embedded_ruby.txt"
result = ruby_exe(bad_embedded_ruby, options: '-x', args: '2>&1', exit_status: 1)
- result.should include "no Ruby script found in input"
+ result.should.include? "no Ruby script found in input"
end
it "behaves as -x was set when non-ruby shebang is encountered on first line" do
diff --git a/spec/ruby/command_line/error_message_spec.rb b/spec/ruby/command_line/error_message_spec.rb
index 02150f30ce..157cb8969c 100644
--- a/spec/ruby/command_line/error_message_spec.rb
+++ b/spec/ruby/command_line/error_message_spec.rb
@@ -8,4 +8,9 @@ describe "The error message caused by an exception" do
out = ruby_exe("end #syntax error", args: "2> #{File::NULL}", exit_status: 1)
out.chomp.should.empty?
end
+
+ it "is not modified with extra escaping of control characters and backslashes" do
+ out = ruby_exe('raise "\e[31mRed\e[0m error\\\\message"', args: "2>&1", exit_status: 1)
+ out.chomp.should.include?("\e[31mRed\e[0m error\\message")
+ end
end
diff --git a/spec/ruby/command_line/feature_spec.rb b/spec/ruby/command_line/feature_spec.rb
index 4a24cc6795..0a3252b88d 100644
--- a/spec/ruby/command_line/feature_spec.rb
+++ b/spec/ruby/command_line/feature_spec.rb
@@ -51,7 +51,7 @@ describe "The --enable and --disable flags" do
env = {'RUBYOPT' => '-w'}
# Use a single variant here because it can be quite slow as it might enable jit, etc
ruby_exe(e, options: "--enable-all", env: env).chomp.should == "[\"constant\", \"constant\", true, true]"
- end
+ end unless defined?(RubyVM::YJIT) && defined?(RubyVM::ZJIT) && RubyVM::ZJIT.enabled? # You're not supposed to enable YJIT with --enable-all when ZJIT options are passed.
end
it "can be used with all for disable" do
@@ -62,10 +62,10 @@ describe "The --enable and --disable flags" do
end
it "prints a warning for unknown features" do
- ruby_exe("p 14", options: "--enable=ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --enable')
- ruby_exe("p 14", options: "--disable=ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --disable')
- ruby_exe("p 14", options: "--enable-ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --enable')
- ruby_exe("p 14", options: "--disable-ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --disable')
+ ruby_exe("p 14", options: "--enable=ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --enable')
+ ruby_exe("p 14", options: "--disable=ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --disable')
+ ruby_exe("p 14", options: "--enable-ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --enable')
+ ruby_exe("p 14", options: "--disable-ruby-spec-feature-does-not-exist 2>&1").chomp.should.include?('warning: unknown argument for --disable')
end
end
diff --git a/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt
index a2b7ad085f..61b946977a 100644
--- a/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt
+++ b/spec/ruby/command_line/fixtures/bin/bad_embedded_ruby.txt
@@ -1,3 +1,3 @@
-@@@This line is not value Ruby
+@@@This line is not valid Ruby
#!rub_y
puts 'success'
diff --git a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
index 1da779b1b9..0ec0f358db 100644
--- a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
+++ b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
@@ -1,3 +1,3 @@
-@@@This line is not value Ruby
+@@@This line is not valid Ruby
#!ruby
puts 'success'
diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb
index 014153e0b4..32ff7d0371 100644
--- a/spec/ruby/command_line/frozen_strings_spec.rb
+++ b/spec/ruby/command_line/frozen_strings_spec.rb
@@ -42,8 +42,28 @@ describe "With neither --enable-frozen-string-literal nor --disable-frozen-strin
ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false"
end
- it "if file has no frozen_string_literal comment produce different mutable strings each time" do
- ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
+ context "if file has no frozen_string_literal comment" do
+ it "produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
+ end
+
+ guard -> { ruby_version_is "3.4" and !"test".frozen? } do
+ it "complain about modification of produced mutable strings" do
+ -> { eval(<<~RUBY) }.should complain(/warning: literal string will be frozen in the future \(run with --debug-frozen-string-literal for more information\)/)
+ "test" << "!"
+ RUBY
+ end
+
+ it "does not complain about modification if Warning[:deprecated] is false" do
+ deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ -> { eval(<<~RUBY) }.should_not complain
+ "test" << "!"
+ RUBY
+ ensure
+ Warning[:deprecated] = deprecated
+ end
+ end
end
it "if file has frozen_string_literal:true comment produce same frozen strings each time" do
@@ -58,17 +78,17 @@ end
describe "The --debug flag produces" do
it "debugging info on attempted frozen string modification" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '--enable-frozen-string-literal --debug', args: "2>&1")
- error_str.should include("can't modify frozen String")
- error_str.should include("created at")
- error_str.should include("command_line/fixtures/debug_info.rb:1")
+ error_str.should.include?("can't modify frozen String")
+ error_str.should.include?("created at")
+ error_str.should.include?("command_line/fixtures/debug_info.rb:1")
end
guard -> { ruby_version_is "3.4" and !"test".frozen? } do
it "debugging info on mutating chilled string" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '-w --debug', args: "2>&1")
- error_str.should include("literal string will be frozen in the future")
- error_str.should include("the string was created here")
- error_str.should include("command_line/fixtures/debug_info.rb:1")
+ error_str.should.include?("literal string will be frozen in the future")
+ error_str.should.include?("the string was created here")
+ error_str.should.include?("command_line/fixtures/debug_info.rb:1")
end
end
end
diff --git a/spec/ruby/command_line/rubylib_spec.rb b/spec/ruby/command_line/rubylib_spec.rb
index b45919b997..1bedd146e3 100644
--- a/spec/ruby/command_line/rubylib_spec.rb
+++ b/spec/ruby/command_line/rubylib_spec.rb
@@ -14,15 +14,15 @@ describe "The RUBYLIB environment variable" do
dir = tmp("rubylib/incl")
ENV["RUBYLIB"] = @pre + dir
paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp)
- paths.should include(dir)
+ paths.should.include?(dir)
end
it "adds a File::PATH_SEPARATOR-separated list of directories to $LOAD_PATH" do
dir1, dir2 = tmp("rubylib/incl1"), tmp("rubylib/incl2")
ENV["RUBYLIB"] = @pre + "#{dir1}#{File::PATH_SEPARATOR}#{dir2}"
paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp)
- paths.should include(dir1)
- paths.should include(dir2)
+ paths.should.include?(dir1)
+ paths.should.include?(dir2)
paths.index(dir1).should < paths.index(dir2)
end
@@ -46,8 +46,8 @@ describe "The RUBYLIB environment variable" do
rubylib_dir = tmp("rubylib_include")
ENV["RUBYLIB"] = @pre + rubylib_dir
paths = ruby_exe("puts $LOAD_PATH", options: "-I #{dash_i_dir}").lines.map(&:chomp)
- paths.should include(dash_i_dir)
- paths.should include(rubylib_dir)
+ paths.should.include?(dash_i_dir)
+ paths.should.include?(rubylib_dir)
paths.index(dash_i_dir).should < paths.index(rubylib_dir)
end
@@ -56,14 +56,14 @@ describe "The RUBYLIB environment variable" do
rubylib_dir = tmp("rubylib_include")
ENV["RUBYLIB"] = @pre + rubylib_dir
paths = ruby_exe("puts $LOAD_PATH", env: { "RUBYOPT" => "-I#{rubyopt_dir}" }).lines.map(&:chomp)
- paths.should include(rubyopt_dir)
- paths.should include(rubylib_dir)
+ paths.should.include?(rubyopt_dir)
+ paths.should.include?(rubylib_dir)
paths.index(rubyopt_dir).should < paths.index(rubylib_dir)
end
it "keeps spaces in the value" do
ENV["RUBYLIB"] = @pre + " rubylib/incl "
out = ruby_exe("puts $LOAD_PATH")
- out.should include(" rubylib/incl ")
+ out.should.include?(" rubylib/incl ")
end
end
diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb
index e940f912af..eb297cd6fe 100644
--- a/spec/ruby/command_line/rubyopt_spec.rb
+++ b/spec/ruby/command_line/rubyopt_spec.rb
@@ -25,12 +25,12 @@ describe "Processing RUBYOPT" do
guard -> { RbConfig::CONFIG["CROSS_COMPILING"] != "yes" } do
it "prints the version number for '-v'" do
ENV["RUBYOPT"] = '-v'
- ruby_exe("").sub("+PRISM ", "").sub(/\+GC(\[\w+\]\s|\s)?/, "")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "").sub(/\+GC(\[\w+\]\s|\s)?/, "")
+ ruby_exe("")[/\A.*/].gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "").should == RUBY_DESCRIPTION.gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "")
end
it "ignores whitespace around the option" do
ENV["RUBYOPT"] = ' -v '
- ruby_exe("").sub("+PRISM ", "").sub(/\+GC(\[\w+\]\s|\s)?/, "")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "").sub(/\+GC(\[\w+\]\s|\s)?/, "")
+ ruby_exe("")[/\A.*/].gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "").should == RUBY_DESCRIPTION.gsub(/\s\+(YJIT( \w+)?|ZJIT( \w+)?|PRISM|GC(\[\w+\])?)(?=\s)/, "")
end
end
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
index 9ba87b9e22..88864c048e 100644
--- a/spec/ruby/command_line/syntax_error_spec.rb
+++ b/spec/ruby/command_line/syntax_error_spec.rb
@@ -3,17 +3,11 @@ require_relative '../spec_helper'
describe "The interpreter" do
it "prints an error when given a file with invalid syntax" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should.include?("SyntaxError")
end
it "prints an error when given code via -e with invalid syntax" do
out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should.include?("SyntaxError")
end
end
diff --git a/spec/ruby/core/argf/argf_spec.rb b/spec/ruby/core/argf/argf_spec.rb
index af67170b98..f9468539bb 100644
--- a/spec/ruby/core/argf/argf_spec.rb
+++ b/spec/ruby/core/argf/argf_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "ARGF" do
it "is extended by the Enumerable module" do
- ARGF.should be_kind_of(Enumerable)
+ ARGF.should.is_a?(Enumerable)
end
it "is an instance of ARGF.class" do
- ARGF.should be_an_instance_of(ARGF.class)
+ ARGF.should.instance_of?(ARGF.class)
end
end
diff --git a/spec/ruby/core/argf/argv_spec.rb b/spec/ruby/core/argf/argv_spec.rb
index eab03c450f..77dfe78c21 100644
--- a/spec/ruby/core/argf/argv_spec.rb
+++ b/spec/ruby/core/argf/argv_spec.rb
@@ -7,7 +7,7 @@ describe "ARGF.argv" do
end
it "returns ARGV for the initial ARGF" do
- ARGF.argv.should equal ARGV
+ ARGF.argv.should.equal? ARGV
end
it "returns the remaining arguments to treat" do
diff --git a/spec/ruby/core/argf/binmode_spec.rb b/spec/ruby/core/argf/binmode_spec.rb
index e083a30a27..5288e3199d 100644
--- a/spec/ruby/core/argf/binmode_spec.rb
+++ b/spec/ruby/core/argf/binmode_spec.rb
@@ -9,7 +9,7 @@ describe "ARGF.binmode" do
it "returns self" do
argf [@bin_file] do
- @argf.binmode.should equal @argf
+ @argf.binmode.should.equal? @argf
end
end
diff --git a/spec/ruby/core/argf/close_spec.rb b/spec/ruby/core/argf/close_spec.rb
index d4d6a51e72..8ca7d71dc2 100644
--- a/spec/ruby/core/argf/close_spec.rb
+++ b/spec/ruby/core/argf/close_spec.rb
@@ -10,20 +10,20 @@ describe "ARGF.close" do
argf [@file1_name, @file2_name] do
io = @argf.to_io
@argf.close
- io.closed?.should be_true
+ io.closed?.should == true
end
end
it "returns self" do
argf [@file1_name, @file2_name] do
- @argf.close.should equal(@argf)
+ @argf.close.should.equal?(@argf)
end
end
it "doesn't raise an IOError if called on a closed stream" do
argf [@file1_name] do
- -> { @argf.close }.should_not raise_error
- -> { @argf.close }.should_not raise_error
+ -> { @argf.close }.should_not.raise
+ -> { @argf.close }.should_not.raise
end
end
end
diff --git a/spec/ruby/core/argf/closed_spec.rb b/spec/ruby/core/argf/closed_spec.rb
index e2dd6134e5..769381e8c3 100644
--- a/spec/ruby/core/argf/closed_spec.rb
+++ b/spec/ruby/core/argf/closed_spec.rb
@@ -11,7 +11,7 @@ describe "ARGF.closed?" do
stream = @argf.to_io
stream.close
- @argf.closed?.should be_true
+ @argf.closed?.should == true
stream.reopen(@argf.filename, 'r')
end
end
diff --git a/spec/ruby/core/argf/each_byte_spec.rb b/spec/ruby/core/argf/each_byte_spec.rb
index c5cce9f250..d9e4e7fe5b 100644
--- a/spec/ruby/core/argf/each_byte_spec.rb
+++ b/spec/ruby/core/argf/each_byte_spec.rb
@@ -1,6 +1,60 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_byte'
describe "ARGF.each_byte" do
- it_behaves_like :argf_each_byte, :each_byte
+ before :each do
+ @file1_name = fixture __FILE__, "file1.txt"
+ @file2_name = fixture __FILE__, "file2.txt"
+
+ @bytes = []
+ File.read(@file1_name).each_byte { |b| @bytes << b }
+ File.read(@file2_name).each_byte { |b| @bytes << b }
+ end
+
+ it "yields each byte of all streams to the passed block" do
+ argf [@file1_name, @file2_name] do
+ bytes = []
+ @argf.each_byte { |b| bytes << b }
+ bytes.should == @bytes
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_byte {}.should.equal?(@argf)
+ end
+ end
+
+ it "returns an Enumerator when passed no block" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_byte
+ enum.should.instance_of?(Enumerator)
+
+ bytes = []
+ enum.each { |b| bytes << b }
+ bytes.should == @bytes
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_byte
+ enum.should.instance_of?(Enumerator)
+
+ bytes = []
+ enum.each { |b| bytes << b }
+ bytes.should == @bytes
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_byte.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_char_spec.rb b/spec/ruby/core/argf/each_char_spec.rb
index 724e5e6e3e..62d19b6574 100644
--- a/spec/ruby/core/argf/each_char_spec.rb
+++ b/spec/ruby/core/argf/each_char_spec.rb
@@ -1,6 +1,60 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_char'
describe "ARGF.each_char" do
- it_behaves_like :argf_each_char, :each_char
+ before :each do
+ @file1_name = fixture __FILE__, "file1.txt"
+ @file2_name = fixture __FILE__, "file2.txt"
+
+ @chars = []
+ File.read(@file1_name).each_char { |c| @chars << c }
+ File.read(@file2_name).each_char { |c| @chars << c }
+ end
+
+ it "yields each char of all streams to the passed block" do
+ argf [@file1_name, @file2_name] do
+ chars = []
+ @argf.each_char { |c| chars << c }
+ chars.should == @chars
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_char {}.should.equal?(@argf)
+ end
+ end
+
+ it "returns an Enumerator when passed no block" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_char
+ enum.should.instance_of?(Enumerator)
+
+ chars = []
+ enum.each { |c| chars << c }
+ chars.should == @chars
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf [@file1_name, @file2_name] do
+ enum = @argf.each_char
+ enum.should.instance_of?(Enumerator)
+
+ chars = []
+ enum.each { |c| chars << c }
+ chars.should == @chars
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_char.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_codepoint_spec.rb b/spec/ruby/core/argf/each_codepoint_spec.rb
index 0bf8bf9764..ad55785cba 100644
--- a/spec/ruby/core/argf/each_codepoint_spec.rb
+++ b/spec/ruby/core/argf/each_codepoint_spec.rb
@@ -1,6 +1,60 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_codepoint'
describe "ARGF.each_codepoint" do
- it_behaves_like :argf_each_codepoint, :each_codepoint
+ before :each do
+ file1_name = fixture __FILE__, "file1.txt"
+ file2_name = fixture __FILE__, "file2.txt"
+ @filenames = [file1_name, file2_name]
+
+ @codepoints = File.read(file1_name).codepoints
+ @codepoints.concat File.read(file2_name).codepoints
+ end
+
+ it "is a public method" do
+ argf @filenames do
+ @argf.public_methods(false).should.include?(:each_codepoint)
+ end
+ end
+
+ it "does not require arguments" do
+ argf @filenames do
+ @argf.method(:each_codepoint).arity.should == 0
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf @filenames do
+ @argf.each_codepoint {}.should.equal?(@argf)
+ end
+ end
+
+ it "returns an Enumerator when passed no block" do
+ argf @filenames do
+ @argf.each_codepoint.should.instance_of?(Enumerator)
+ end
+ end
+
+ it "yields each codepoint of all streams" do
+ argf @filenames do
+ @argf.each_codepoint.to_a.should == @codepoints
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf @filenames do
+ @argf.each_codepoint.should.instance_of?(Enumerator)
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf @filenames do
+ @argf.each_codepoint.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_line_spec.rb b/spec/ruby/core/argf/each_line_spec.rb
index 52a7e5c411..fc4d6433b8 100644
--- a/spec/ruby/core/argf/each_line_spec.rb
+++ b/spec/ruby/core/argf/each_line_spec.rb
@@ -1,6 +1,64 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_line'
describe "ARGF.each_line" do
- it_behaves_like :argf_each_line, :each_line
+ before :each do
+ @file1_name = fixture __FILE__, "file1.txt"
+ @file2_name = fixture __FILE__, "file2.txt"
+
+ @lines = File.readlines @file1_name
+ @lines += File.readlines @file2_name
+ end
+
+ it "is a public method" do
+ argf [@file1_name, @file2_name] do
+ @argf.public_methods(false).should.include?(:each_line)
+ end
+ end
+
+ it "requires multiple arguments" do
+ argf [@file1_name, @file2_name] do
+ @argf.method(:each_line).arity.should < 0
+ end
+ end
+
+ it "reads each line of files" do
+ argf [@file1_name, @file2_name] do
+ lines = []
+ @argf.each_line { |b| lines << b }
+ lines.should == @lines
+ end
+ end
+
+ it "returns self when passed a block" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_line {}.should.equal?(@argf)
+ end
+ end
+
+ describe "with a separator" do
+ it "yields each separated section of all streams" do
+ argf [@file1_name, @file2_name] do
+ @argf.send(:each_line, '.').to_a.should ==
+ (File.readlines(@file1_name, '.') + File.readlines(@file2_name, '.'))
+ end
+ end
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_line.should.instance_of?(Enumerator)
+ end
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ argf [@file1_name, @file2_name] do
+ @argf.each_line.size.should == nil
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/argf/each_spec.rb b/spec/ruby/core/argf/each_spec.rb
index 5742ba43bd..25f60b31d2 100644
--- a/spec/ruby/core/argf/each_spec.rb
+++ b/spec/ruby/core/argf/each_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/each_line'
describe "ARGF.each" do
- it_behaves_like :argf_each_line, :each
+ it "is an alias of ARGF.each_line" do
+ ARGF.method(:each).should == ARGF.method(:each_line)
+ end
end
diff --git a/spec/ruby/core/argf/eof_spec.rb b/spec/ruby/core/argf/eof_spec.rb
index 518f6e566e..940d104d69 100644
--- a/spec/ruby/core/argf/eof_spec.rb
+++ b/spec/ruby/core/argf/eof_spec.rb
@@ -1,10 +1,32 @@
require_relative '../../spec_helper'
-require_relative 'shared/eof'
describe "ARGF.eof" do
- it_behaves_like :argf_eof, :eof
+ it "is an alias of ARGF.eof?" do
+ ARGF.method(:eof).should == ARGF.method(:eof?)
+ end
end
describe "ARGF.eof?" do
- it_behaves_like :argf_eof, :eof?
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "returns true when reaching the end of a file" do
+ argf [@file1, @file2] do
+ result = []
+ while @argf.gets
+ result << @argf.eof?
+ end
+ result.should == [false, true, false, true]
+ end
+ end
+
+ it "raises IOError when called on a closed stream" do
+ argf [@file1] do
+ @argf.read
+ -> { @argf.eof? }.should.raise(IOError)
+ end
+ end
end
diff --git a/spec/ruby/core/argf/filename_spec.rb b/spec/ruby/core/argf/filename_spec.rb
index 7c0446269d..f4b6e922c6 100644
--- a/spec/ruby/core/argf/filename_spec.rb
+++ b/spec/ruby/core/argf/filename_spec.rb
@@ -1,6 +1,30 @@
require_relative '../../spec_helper'
-require_relative 'shared/filename'
describe "ARGF.filename" do
- it_behaves_like :argf_filename, :filename
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "returns the current file name on each file" do
+ argf [@file1, @file2] do
+ result = []
+ # returns first current file even when not yet open
+ result << @argf.filename
+ result << @argf.filename while @argf.gets
+ # returns last current file even when closed
+ result << @argf.filename
+
+ result.map! { |f| File.expand_path(f) }
+ result.should == [@file1, @file1, @file1, @file2, @file2, @file2]
+ end
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "sets the $FILENAME global variable with the current file name on each file" do
+ script = fixture __FILE__, "filename.rb"
+ out = ruby_exe(script, args: [@file1, @file2])
+ out.should == "#{@file1}\n#{@file1}\n#{@file2}\n#{@file2}\n#{@file2}\n"
+ end
end
diff --git a/spec/ruby/core/argf/fileno_spec.rb b/spec/ruby/core/argf/fileno_spec.rb
index 29d50c3582..99245f043c 100644
--- a/spec/ruby/core/argf/fileno_spec.rb
+++ b/spec/ruby/core/argf/fileno_spec.rb
@@ -1,6 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'shared/fileno'
describe "ARGF.fileno" do
- it_behaves_like :argf_fileno, :fileno
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ # NOTE: this test assumes that fixtures files have two lines each
+ it "returns the current file number on each file" do
+ argf [@file1, @file2] do
+ result = []
+ # returns first current file even when not yet open
+ result << @argf.fileno while @argf.gets
+ # returns last current file even when closed
+ result.map { |d| d.class }.should == [Integer, Integer, Integer, Integer]
+ end
+ end
+
+ it "raises an ArgumentError when called on a closed stream" do
+ argf [@file1] do
+ @argf.read
+ -> { @argf.fileno }.should.raise(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/argf/inspect_spec.rb b/spec/ruby/core/argf/inspect_spec.rb
new file mode 100644
index 0000000000..df0e3ba8dc
--- /dev/null
+++ b/spec/ruby/core/argf/inspect_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "ARGF.inspect" do
+ it "is an alias of ARGF.to_s" do
+ ARGF.method(:inspect).should == ARGF.method(:to_s)
+ end
+end
diff --git a/spec/ruby/core/argf/path_spec.rb b/spec/ruby/core/argf/path_spec.rb
index 7120f7d0e3..2f7b91999f 100644
--- a/spec/ruby/core/argf/path_spec.rb
+++ b/spec/ruby/core/argf/path_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/filename'
describe "ARGF.path" do
- it_behaves_like :argf_filename, :path
+ it "is an alias of ARGF.filename" do
+ ARGF.method(:path).should == ARGF.method(:filename)
+ end
end
diff --git a/spec/ruby/core/argf/pos_spec.rb b/spec/ruby/core/argf/pos_spec.rb
index fb3f25b945..1ff16e4f17 100644
--- a/spec/ruby/core/argf/pos_spec.rb
+++ b/spec/ruby/core/argf/pos_spec.rb
@@ -1,8 +1,35 @@
require_relative '../../spec_helper'
-require_relative 'shared/pos'
describe "ARGF.pos" do
- it_behaves_like :argf_pos, :pos
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+ end
+
+ it "gives the correct position for each read operation" do
+ argf [@file1, @file2] do
+ size1 = File.size(@file1)
+ size2 = File.size(@file2)
+
+ @argf.read(2)
+ @argf.pos.should == 2
+ @argf.read(size1-2)
+ @argf.pos.should == size1
+ @argf.read(6)
+ @argf.pos.should == 6
+ @argf.rewind
+ @argf.pos.should == 0
+ @argf.read(size2)
+ @argf.pos.should == size2
+ end
+ end
+
+ it "raises an ArgumentError when called on a closed stream" do
+ argf [@file1] do
+ @argf.read
+ -> { @argf.pos }.should.raise(ArgumentError)
+ end
+ end
end
describe "ARGF.pos=" do
diff --git a/spec/ruby/core/argf/read_nonblock_spec.rb b/spec/ruby/core/argf/read_nonblock_spec.rb
index 804a459a62..5c6bd52d80 100644
--- a/spec/ruby/core/argf/read_nonblock_spec.rb
+++ b/spec/ruby/core/argf/read_nonblock_spec.rb
@@ -66,7 +66,7 @@ platform_is_not :windows do
argf ['-'] do
-> {
@argf.read_nonblock(4)
- }.should raise_error(IO::EAGAINWaitReadable)
+ }.should.raise(IO::EAGAINWaitReadable)
end
end
diff --git a/spec/ruby/core/argf/readchar_spec.rb b/spec/ruby/core/argf/readchar_spec.rb
index 4eca2efcf7..63632721ec 100644
--- a/spec/ruby/core/argf/readchar_spec.rb
+++ b/spec/ruby/core/argf/readchar_spec.rb
@@ -13,7 +13,7 @@ describe "ARGF.readchar" do
it "raises EOFError when end of stream reached" do
argf [@file1, @file2] do
- -> { while @argf.readchar; end }.should raise_error(EOFError)
+ -> { while @argf.readchar; end }.should.raise(EOFError)
end
end
end
diff --git a/spec/ruby/core/argf/readline_spec.rb b/spec/ruby/core/argf/readline_spec.rb
index db53c499e9..8c23549b1b 100644
--- a/spec/ruby/core/argf/readline_spec.rb
+++ b/spec/ruby/core/argf/readline_spec.rb
@@ -17,7 +17,7 @@ describe "ARGF.readline" do
it "raises an EOFError when reaching end of files" do
argf [@file1, @file2] do
- -> { while @argf.readline; end }.should raise_error(EOFError)
+ -> { while @argf.readline; end }.should.raise(EOFError)
end
end
end
diff --git a/spec/ruby/core/argf/readlines_spec.rb b/spec/ruby/core/argf/readlines_spec.rb
index 30be936dab..156bb6a33f 100644
--- a/spec/ruby/core/argf/readlines_spec.rb
+++ b/spec/ruby/core/argf/readlines_spec.rb
@@ -1,6 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'shared/readlines'
describe "ARGF.readlines" do
- it_behaves_like :argf_readlines, :readlines
+ before :each do
+ @file1 = fixture __FILE__, "file1.txt"
+ @file2 = fixture __FILE__, "file2.txt"
+
+ @lines = File.readlines(@file1)
+ @lines += File.readlines(@file2)
+ end
+
+ it "reads all lines of all files" do
+ argf [@file1, @file2] do
+ @argf.readlines.should == @lines
+ end
+ end
+
+ it "returns an empty Array when end of stream reached" do
+ argf [@file1, @file2] do
+ @argf.read
+ @argf.readlines.should == []
+ end
+ end
end
diff --git a/spec/ruby/core/argf/readpartial_spec.rb b/spec/ruby/core/argf/readpartial_spec.rb
index ea4301f25c..9f04e72cc2 100644
--- a/spec/ruby/core/argf/readpartial_spec.rb
+++ b/spec/ruby/core/argf/readpartial_spec.rb
@@ -16,7 +16,7 @@ describe "ARGF.readpartial" do
it "raises an ArgumentError if called without a maximum read length" do
argf [@file1_name] do
- -> { @argf.readpartial }.should raise_error(ArgumentError)
+ -> { @argf.readpartial }.should.raise(ArgumentError)
end
end
@@ -59,8 +59,8 @@ describe "ARGF.readpartial" do
@argf.readpartial(@file1.size)
@argf.readpartial(1)
@argf.readpartial(@file2.size)
- -> { @argf.readpartial(1) }.should raise_error(EOFError)
- -> { @argf.readpartial(1) }.should raise_error(EOFError)
+ -> { @argf.readpartial(1) }.should.raise(EOFError)
+ -> { @argf.readpartial(1) }.should.raise(EOFError)
end
end
diff --git a/spec/ruby/core/argf/rewind_spec.rb b/spec/ruby/core/argf/rewind_spec.rb
index b29f0b75b7..9255f790fe 100644
--- a/spec/ruby/core/argf/rewind_spec.rb
+++ b/spec/ruby/core/argf/rewind_spec.rb
@@ -33,7 +33,7 @@ describe "ARGF.rewind" do
it "raises an ArgumentError when end of stream reached" do
argf [@file1_name, @file2_name] do
@argf.read
- -> { @argf.rewind }.should raise_error(ArgumentError)
+ -> { @argf.rewind }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/argf/seek_spec.rb b/spec/ruby/core/argf/seek_spec.rb
index 2b73bd46fb..c1ea1ea438 100644
--- a/spec/ruby/core/argf/seek_spec.rb
+++ b/spec/ruby/core/argf/seek_spec.rb
@@ -57,7 +57,7 @@ describe "ARGF.seek" do
it "takes at least one argument (offset)" do
argf [@file1_name] do
- -> { @argf.seek }.should raise_error(ArgumentError)
+ -> { @argf.seek }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/argf/shared/each_byte.rb b/spec/ruby/core/argf/shared/each_byte.rb
deleted file mode 100644
index 6b1dc1dae2..0000000000
--- a/spec/ruby/core/argf/shared/each_byte.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :argf_each_byte, shared: true do
- before :each do
- @file1_name = fixture __FILE__, "file1.txt"
- @file2_name = fixture __FILE__, "file2.txt"
-
- @bytes = []
- File.read(@file1_name).each_byte { |b| @bytes << b }
- File.read(@file2_name).each_byte { |b| @bytes << b }
- end
-
- it "yields each byte of all streams to the passed block" do
- argf [@file1_name, @file2_name] do
- bytes = []
- @argf.send(@method) { |b| bytes << b }
- bytes.should == @bytes
- end
- end
-
- it "returns self when passed a block" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- it "returns an Enumerator when passed no block" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- bytes = []
- enum.each { |b| bytes << b }
- bytes.should == @bytes
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- bytes = []
- enum.each { |b| bytes << b }
- bytes.should == @bytes
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/each_char.rb b/spec/ruby/core/argf/shared/each_char.rb
deleted file mode 100644
index 9e333ecc5b..0000000000
--- a/spec/ruby/core/argf/shared/each_char.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :argf_each_char, shared: true do
- before :each do
- @file1_name = fixture __FILE__, "file1.txt"
- @file2_name = fixture __FILE__, "file2.txt"
-
- @chars = []
- File.read(@file1_name).each_char { |c| @chars << c }
- File.read(@file2_name).each_char { |c| @chars << c }
- end
-
- it "yields each char of all streams to the passed block" do
- argf [@file1_name, @file2_name] do
- chars = []
- @argf.send(@method) { |c| chars << c }
- chars.should == @chars
- end
- end
-
- it "returns self when passed a block" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- it "returns an Enumerator when passed no block" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- chars = []
- enum.each { |c| chars << c }
- chars.should == @chars
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf [@file1_name, @file2_name] do
- enum = @argf.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- chars = []
- enum.each { |c| chars << c }
- chars.should == @chars
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/each_codepoint.rb b/spec/ruby/core/argf/shared/each_codepoint.rb
deleted file mode 100644
index e2a2dfff46..0000000000
--- a/spec/ruby/core/argf/shared/each_codepoint.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-describe :argf_each_codepoint, shared: true do
- before :each do
- file1_name = fixture __FILE__, "file1.txt"
- file2_name = fixture __FILE__, "file2.txt"
- @filenames = [file1_name, file2_name]
-
- @codepoints = File.read(file1_name).codepoints
- @codepoints.concat File.read(file2_name).codepoints
- end
-
- it "is a public method" do
- argf @filenames do
- @argf.public_methods(false).should include(@method)
- end
- end
-
- it "does not require arguments" do
- argf @filenames do
- @argf.method(@method).arity.should == 0
- end
- end
-
- it "returns self when passed a block" do
- argf @filenames do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- it "returns an Enumerator when passed no block" do
- argf @filenames do
- @argf.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- it "yields each codepoint of all streams" do
- argf @filenames do
- @argf.send(@method).to_a.should == @codepoints
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf @filenames do
- @argf.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf @filenames do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/each_line.rb b/spec/ruby/core/argf/shared/each_line.rb
deleted file mode 100644
index c0ef77dc54..0000000000
--- a/spec/ruby/core/argf/shared/each_line.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-describe :argf_each_line, shared: true do
- before :each do
- @file1_name = fixture __FILE__, "file1.txt"
- @file2_name = fixture __FILE__, "file2.txt"
-
- @lines = File.readlines @file1_name
- @lines += File.readlines @file2_name
- end
-
- it "is a public method" do
- argf [@file1_name, @file2_name] do
- @argf.public_methods(false).should include(@method)
- end
- end
-
- it "requires multiple arguments" do
- argf [@file1_name, @file2_name] do
- @argf.method(@method).arity.should < 0
- end
- end
-
- it "reads each line of files" do
- argf [@file1_name, @file2_name] do
- lines = []
- @argf.send(@method) { |b| lines << b }
- lines.should == @lines
- end
- end
-
- it "returns self when passed a block" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method) {}.should equal(@argf)
- end
- end
-
- describe "with a separator" do
- it "yields each separated section of all streams" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method, '.').to_a.should ==
- (File.readlines(@file1_name, '.') + File.readlines(@file2_name, '.'))
- end
- end
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- argf [@file1_name, @file2_name] do
- @argf.send(@method).size.should == nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/eof.rb b/spec/ruby/core/argf/shared/eof.rb
deleted file mode 100644
index 0e684f943f..0000000000
--- a/spec/ruby/core/argf/shared/eof.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-describe :argf_eof, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "returns true when reaching the end of a file" do
- argf [@file1, @file2] do
- result = []
- while @argf.gets
- result << @argf.send(@method)
- end
- result.should == [false, true, false, true]
- end
- end
-
- it "raises IOError when called on a closed stream" do
- argf [@file1] do
- @argf.read
- -> { @argf.send(@method) }.should raise_error(IOError)
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/filename.rb b/spec/ruby/core/argf/shared/filename.rb
deleted file mode 100644
index f47c673dc0..0000000000
--- a/spec/ruby/core/argf/shared/filename.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-describe :argf_filename, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "returns the current file name on each file" do
- argf [@file1, @file2] do
- result = []
- # returns first current file even when not yet open
- result << @argf.send(@method)
- result << @argf.send(@method) while @argf.gets
- # returns last current file even when closed
- result << @argf.send(@method)
-
- result.map! { |f| File.expand_path(f) }
- result.should == [@file1, @file1, @file1, @file2, @file2, @file2]
- end
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "sets the $FILENAME global variable with the current file name on each file" do
- script = fixture __FILE__, "filename.rb"
- out = ruby_exe(script, args: [@file1, @file2])
- out.should == "#{@file1}\n#{@file1}\n#{@file2}\n#{@file2}\n#{@file2}\n"
- end
-end
diff --git a/spec/ruby/core/argf/shared/fileno.rb b/spec/ruby/core/argf/shared/fileno.rb
deleted file mode 100644
index 4350d43747..0000000000
--- a/spec/ruby/core/argf/shared/fileno.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-describe :argf_fileno, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- # NOTE: this test assumes that fixtures files have two lines each
- it "returns the current file number on each file" do
- argf [@file1, @file2] do
- result = []
- # returns first current file even when not yet open
- result << @argf.send(@method) while @argf.gets
- # returns last current file even when closed
- result.map { |d| d.class }.should == [Integer, Integer, Integer, Integer]
- end
- end
-
- it "raises an ArgumentError when called on a closed stream" do
- argf [@file1] do
- @argf.read
- -> { @argf.send(@method) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/pos.rb b/spec/ruby/core/argf/shared/pos.rb
deleted file mode 100644
index 9836d5f1e4..0000000000
--- a/spec/ruby/core/argf/shared/pos.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :argf_pos, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
- end
-
- it "gives the correct position for each read operation" do
- argf [@file1, @file2] do
- size1 = File.size(@file1)
- size2 = File.size(@file2)
-
- @argf.read(2)
- @argf.send(@method).should == 2
- @argf.read(size1-2)
- @argf.send(@method).should == size1
- @argf.read(6)
- @argf.send(@method).should == 6
- @argf.rewind
- @argf.send(@method).should == 0
- @argf.read(size2)
- @argf.send(@method).should == size2
- end
- end
-
- it "raises an ArgumentError when called on a closed stream" do
- argf [@file1] do
- @argf.read
- -> { @argf.send(@method) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/core/argf/shared/readlines.rb b/spec/ruby/core/argf/shared/readlines.rb
deleted file mode 100644
index 505fa94acb..0000000000
--- a/spec/ruby/core/argf/shared/readlines.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-describe :argf_readlines, shared: true do
- before :each do
- @file1 = fixture __FILE__, "file1.txt"
- @file2 = fixture __FILE__, "file2.txt"
-
- @lines = File.readlines(@file1)
- @lines += File.readlines(@file2)
- end
-
- it "reads all lines of all files" do
- argf [@file1, @file2] do
- @argf.send(@method).should == @lines
- end
- end
-
- it "returns an empty Array when end of stream reached" do
- argf [@file1, @file2] do
- @argf.read
- @argf.send(@method).should == []
- end
- end
-end
diff --git a/spec/ruby/core/argf/skip_spec.rb b/spec/ruby/core/argf/skip_spec.rb
index 0181801c2d..bb1c0ae110 100644
--- a/spec/ruby/core/argf/skip_spec.rb
+++ b/spec/ruby/core/argf/skip_spec.rb
@@ -37,6 +37,6 @@ describe "ARGF.skip" do
# which as a side-effect calls argf.file which will initialize
# internals of ARGF enough for this to work.
it "has no effect when nothing has been processed yet" do
- -> { ARGF.class.new(@file1_name).skip }.should_not raise_error
+ -> { ARGF.class.new(@file1_name).skip }.should_not.raise
end
end
diff --git a/spec/ruby/core/argf/tell_spec.rb b/spec/ruby/core/argf/tell_spec.rb
index 16d9f29920..bb28df74a2 100644
--- a/spec/ruby/core/argf/tell_spec.rb
+++ b/spec/ruby/core/argf/tell_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/pos'
describe "ARGF.tell" do
- it_behaves_like :argf_pos, :tell
+ it "is an alias of ARGF.pos" do
+ ARGF.method(:tell).should == ARGF.method(:pos)
+ end
end
diff --git a/spec/ruby/core/argf/to_a_spec.rb b/spec/ruby/core/argf/to_a_spec.rb
index b17a93db33..d95dc732ec 100644
--- a/spec/ruby/core/argf/to_a_spec.rb
+++ b/spec/ruby/core/argf/to_a_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/readlines'
describe "ARGF.to_a" do
- it_behaves_like :argf_readlines, :to_a
+ it "is an alias of ARGF.readlines" do
+ ARGF.method(:to_a).should == ARGF.method(:readlines)
+ end
end
diff --git a/spec/ruby/core/argf/to_i_spec.rb b/spec/ruby/core/argf/to_i_spec.rb
index 2183de6cd4..e8df378f4e 100644
--- a/spec/ruby/core/argf/to_i_spec.rb
+++ b/spec/ruby/core/argf/to_i_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/fileno'
describe "ARGF.to_i" do
- it_behaves_like :argf_fileno, :to_i
+ it "is an alias of ARGF.fileno" do
+ ARGF.method(:to_i).should == ARGF.method(:fileno)
+ end
end
diff --git a/spec/ruby/core/argf/to_io_spec.rb b/spec/ruby/core/argf/to_io_spec.rb
index 062383d291..ab5de58bcf 100644
--- a/spec/ruby/core/argf/to_io_spec.rb
+++ b/spec/ruby/core/argf/to_io_spec.rb
@@ -15,7 +15,7 @@ describe "ARGF.to_io" do
result << @argf.to_io
end
- result.each { |io| io.should be_kind_of(IO) }
+ result.each { |io| io.should.is_a?(IO) }
result[0].should == result[1]
result[2].should == result[3]
end
diff --git a/spec/ruby/core/array/allocate_spec.rb b/spec/ruby/core/array/allocate_spec.rb
index 04f7c0d0ad..c9eceef590 100644
--- a/spec/ruby/core/array/allocate_spec.rb
+++ b/spec/ruby/core/array/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Array.allocate" do
it "returns an instance of Array" do
ary = Array.allocate
- ary.should be_an_instance_of(Array)
+ ary.should.instance_of?(Array)
end
it "returns a fully-formed instance of Array" do
@@ -14,6 +14,6 @@ describe "Array.allocate" do
end
it "does not accept any arguments" do
- -> { Array.allocate(1) }.should raise_error(ArgumentError)
+ -> { Array.allocate(1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/append_spec.rb b/spec/ruby/core/array/append_spec.rb
index c12473dc07..5480d9f65e 100644
--- a/spec/ruby/core/array/append_spec.rb
+++ b/spec/ruby/core/array/append_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/push'
describe "Array#<<" do
it "pushes the object onto the end of the array" do
@@ -10,8 +9,8 @@ describe "Array#<<" do
it "returns self to allow chaining" do
a = []
b = a
- (a << 1).should equal(b)
- (a << 2 << 3).should equal(b)
+ (a << 1).should.equal?(b)
+ (a << 2 << 3).should.equal?(b)
end
it "correctly resizes the Array" do
@@ -31,10 +30,12 @@ describe "Array#<<" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array << 5 }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array << 5 }.should.raise(FrozenError)
end
end
describe "Array#append" do
- it_behaves_like :array_push, :append
+ it "is an alias of Array#push" do
+ Array.instance_method(:append).should == Array.instance_method(:push)
+ end
end
diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb
index f0be3de795..a5026cf5d4 100644
--- a/spec/ruby/core/array/assoc_spec.rb
+++ b/spec/ruby/core/array/assoc_spec.rb
@@ -10,14 +10,14 @@ describe "Array#assoc" do
s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil]
- a.assoc(s1.first).should equal(s1)
- a.assoc(s2.first).should equal(s2)
- a.assoc(s3.first).should equal(s3)
- a.assoc(s4.first).should equal(s1)
- a.assoc(s5.first).should equal(s2)
- a.assoc(s_nil.first).should equal(s_nil)
- a.assoc(4).should equal(s3)
- a.assoc("key not in array").should be_nil
+ a.assoc(s1.first).should.equal?(s1)
+ a.assoc(s2.first).should.equal?(s2)
+ a.assoc(s3.first).should.equal?(s3)
+ a.assoc(s4.first).should.equal?(s1)
+ a.assoc(s5.first).should.equal?(s2)
+ a.assoc(s_nil.first).should.equal?(s_nil)
+ a.assoc(4).should.equal?(s3)
+ a.assoc("key not in array").should == nil
end
it "calls == on first element of each array" do
@@ -25,17 +25,17 @@ describe "Array#assoc" do
key2 = mock('key2')
items = [['not it', 1], [ArraySpecs::AssocKey.new, 2], ['na', 3]]
- items.assoc(key1).should equal(items[1])
- items.assoc(key2).should be_nil
+ items.assoc(key1).should.equal?(items[1])
+ items.assoc(key2).should == nil
end
it "ignores any non-Array elements" do
- [1, 2, 3].assoc(2).should be_nil
+ [1, 2, 3].assoc(2).should == nil
s1 = [4]
s2 = [5, 4, 3]
a = ["foo", [], s1, s2, nil, []]
- a.assoc(s1.first).should equal(s1)
- a.assoc(s2.first).should equal(s2)
+ a.assoc(s1.first).should.equal?(s1)
+ a.assoc(s2.first).should.equal?(s2)
end
it "calls to_ary on non-array elements" do
@@ -44,9 +44,9 @@ describe "Array#assoc" do
a = [s1, s2]
s1.should_not_receive(:to_ary)
- a.assoc(s1.first).should equal(s1)
+ a.assoc(s1.first).should.equal?(s1)
a.assoc(2).should == [2, 3]
- s2.called.should equal(:to_ary)
+ s2.called.should.equal?(:to_ary)
end
end
diff --git a/spec/ruby/core/array/at_spec.rb b/spec/ruby/core/array/at_spec.rb
index 8bc789fef7..3c7c99fdff 100644
--- a/spec/ruby/core/array/at_spec.rb
+++ b/spec/ruby/core/array/at_spec.rb
@@ -47,10 +47,10 @@ describe "Array#at" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].at("cat") }.should raise_error(TypeError)
+ -> { [].at("cat") }.should.raise(TypeError)
end
it "raises an ArgumentError when 2 or more arguments are passed" do
- -> { [:a, :b].at(0,1) }.should raise_error(ArgumentError)
+ -> { [:a, :b].at(0,1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb
index 94d85b37f3..e1d5eb66bb 100644
--- a/spec/ruby/core/array/bsearch_index_spec.rb
+++ b/spec/ruby/core/array/bsearch_index_spec.rb
@@ -8,11 +8,11 @@ describe "Array#bsearch_index" do
end
it "returns an Enumerator" do
- @enum.should be_an_instance_of(Enumerator)
+ @enum.should.instance_of?(Enumerator)
end
it "returns an Enumerator with unknown size" do
- @enum.size.should be_nil
+ @enum.size.should == nil
end
it "returns index of element when block condition is satisfied" do
@@ -21,11 +21,11 @@ describe "Array#bsearch_index" do
end
it "raises a TypeError when block returns a String" do
- -> { [1, 2, 3].bsearch_index { "not ok" } }.should raise_error(TypeError)
+ -> { [1, 2, 3].bsearch_index { "not ok" } }.should.raise(TypeError)
end
it "returns nil when block is empty" do
- [1, 2, 3].bsearch_index {}.should be_nil
+ [1, 2, 3].bsearch_index {}.should == nil
end
context "minimum mode" do
@@ -40,8 +40,8 @@ describe "Array#bsearch_index" do
end
it "returns nil when block condition is never satisfied" do
- @array.bsearch_index { false }.should be_nil
- @array.bsearch_index { |x| x >= 100 }.should be_nil
+ @array.bsearch_index { false }.should == nil
+ @array.bsearch_index { |x| x >= 100 }.should == nil
end
end
@@ -51,30 +51,30 @@ describe "Array#bsearch_index" do
end
it "returns the index of any matched elements where element is between 4 <= x < 8" do
- [1, 2].should include(@array.bsearch_index { |x| 1 - x / 4 })
+ [1, 2].should.include?(@array.bsearch_index { |x| 1 - x / 4 })
end
it "returns the index of any matched elements where element is between 8 <= x < 10" do
- @array.bsearch_index { |x| 4 - x / 2 }.should be_nil
+ @array.bsearch_index { |x| 4 - x / 2 }.should == nil
end
it "returns nil when block never returns 0" do
- @array.bsearch_index { |x| 1 }.should be_nil
- @array.bsearch_index { |x| -1 }.should be_nil
+ @array.bsearch_index { |x| 1 }.should == nil
+ @array.bsearch_index { |x| -1 }.should == nil
end
context "magnitude does not effect the result" do
it "returns the index of any matched elements where element is between 4n <= xn < 8n" do
- [1, 2].should include(@array.bsearch_index { |x| (1 - x / 4) * (2**100) })
+ [1, 2].should.include?(@array.bsearch_index { |x| (1 - x / 4) * (2**100) })
end
it "returns nil when block never returns 0" do
- @array.bsearch_index { |x| 1 * (2**100) }.should be_nil
- @array.bsearch_index { |x| (-1) * (2**100) }.should be_nil
+ @array.bsearch_index { |x| 1 * (2**100) }.should == nil
+ @array.bsearch_index { |x| (-1) * (2**100) }.should == nil
end
it "handles values from Integer#coerce" do
- [1, 2].should include(@array.bsearch_index { |x| (2**100).coerce((1 - x / 4) * (2**100)).first })
+ [1, 2].should.include?(@array.bsearch_index { |x| (2**100).coerce((1 - x / 4) * (2**100)).first })
end
end
end
diff --git a/spec/ruby/core/array/bsearch_spec.rb b/spec/ruby/core/array/bsearch_spec.rb
index 8fa6245dbf..12aec60654 100644
--- a/spec/ruby/core/array/bsearch_spec.rb
+++ b/spec/ruby/core/array/bsearch_spec.rb
@@ -3,26 +3,26 @@ require_relative '../enumerable/shared/enumeratorized'
describe "Array#bsearch" do
it "returns an Enumerator when not passed a block" do
- [1].bsearch.should be_an_instance_of(Enumerator)
+ [1].bsearch.should.instance_of?(Enumerator)
end
it_behaves_like :enumeratorized_with_unknown_size, :bsearch, [1,2,3]
it "raises a TypeError if the block returns an Object" do
- -> { [1].bsearch { Object.new } }.should raise_error(TypeError)
+ -> { [1].bsearch { Object.new } }.should.raise(TypeError)
end
it "raises a TypeError if the block returns a String" do
- -> { [1].bsearch { "1" } }.should raise_error(TypeError)
+ -> { [1].bsearch { "1" } }.should.raise(TypeError)
end
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- [0, 1, 2, 3].bsearch { |x| x > 3 }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| x > 3 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- [0, 1, 2, 3].bsearch { |x| nil }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| nil }.should == nil
end
it "returns element at zero if the block returns true for every element" do
@@ -38,21 +38,21 @@ describe "Array#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- [0, 1, 2, 3].bsearch { |x| x <=> 5 }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| x <=> 5 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- [0, 1, 2, 3].bsearch { |x| x <=> -1 }.should be_nil
+ [0, 1, 2, 3].bsearch { |x| x <=> -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- [0, 1, 3, 4].bsearch { |x| x <=> 2 }.should be_nil
+ [0, 1, 3, 4].bsearch { |x| x <=> 2 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- [0, 1, 3, 4].bsearch { |x| Float::INFINITY }.should be_nil
- [0, 1, 3, 4].bsearch { |x| -Float::INFINITY }.should be_nil
+ [0, 1, 3, 4].bsearch { |x| Float::INFINITY }.should == nil
+ [0, 1, 3, 4].bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -62,17 +62,17 @@ describe "Array#bsearch" do
it "returns an element at an index for which block returns 0" do
result = [0, 1, 2, 3, 4].bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2].should include(result)
+ [1, 2].should.include?(result)
end
end
context "with a block that calls break" do
it "returns nil if break is called without a value" do
- ['a', 'b', 'c'].bsearch { |v| break }.should be_nil
+ ['a', 'b', 'c'].bsearch { |v| break }.should == nil
end
it "returns nil if break is called with a nil value" do
- ['a', 'b', 'c'].bsearch { |v| break nil }.should be_nil
+ ['a', 'b', 'c'].bsearch { |v| break nil }.should == nil
end
it "returns object if break is called with an object" do
diff --git a/spec/ruby/core/array/clear_spec.rb b/spec/ruby/core/array/clear_spec.rb
index 81ba56e01e..15778f864f 100644
--- a/spec/ruby/core/array/clear_spec.rb
+++ b/spec/ruby/core/array/clear_spec.rb
@@ -4,13 +4,13 @@ require_relative 'fixtures/classes'
describe "Array#clear" do
it "removes all elements" do
a = [1, 2, 3, 4]
- a.clear.should equal(a)
+ a.clear.should.equal?(a)
a.should == []
end
it "returns self" do
a = [1]
- a.should equal a.clear
+ a.should.equal? a.clear
end
it "leaves the Array empty" do
@@ -21,12 +21,12 @@ describe "Array#clear" do
end
it "does not accept any arguments" do
- -> { [1].clear(true) }.should raise_error(ArgumentError)
+ -> { [1].clear(true) }.should.raise(ArgumentError)
end
it "raises a FrozenError on a frozen array" do
a = [1]
a.freeze
- -> { a.clear }.should raise_error(FrozenError)
+ -> { a.clear }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/clone_spec.rb b/spec/ruby/core/array/clone_spec.rb
index e22a6c6d53..7ce9d40a81 100644
--- a/spec/ruby/core/array/clone_spec.rb
+++ b/spec/ruby/core/array/clone_spec.rb
@@ -23,9 +23,9 @@ describe "Array#clone" do
aa = a.clone
bb = b.clone
- a.respond_to?(:a_singleton_method).should be_true
- b.respond_to?(:a_singleton_method).should be_false
- aa.respond_to?(:a_singleton_method).should be_true
- bb.respond_to?(:a_singleton_method).should be_false
+ a.respond_to?(:a_singleton_method).should == true
+ b.respond_to?(:a_singleton_method).should == false
+ aa.respond_to?(:a_singleton_method).should == true
+ bb.respond_to?(:a_singleton_method).should == false
end
end
diff --git a/spec/ruby/core/array/collect_spec.rb b/spec/ruby/core/array/collect_spec.rb
index 0ad4c283b1..43a539f805 100644
--- a/spec/ruby/core/array/collect_spec.rb
+++ b/spec/ruby/core/array/collect_spec.rb
@@ -1,11 +1,143 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/collect'
+require_relative '../enumerable/shared/enumeratorized'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#collect" do
- it_behaves_like :array_collect, :collect
+ it "returns a copy of array with each element replaced by the value returned by block" do
+ a = ['a', 'b', 'c', 'd']
+ b = a.collect { |i| i + '!' }
+ b.should == ["a!", "b!", "c!", "d!"]
+ b.should_not.equal? a
+ end
+
+ it "does not return subclass instance" do
+ ArraySpecs::MyArray[1, 2, 3].collect { |x| x + 1 }.should.instance_of?(Array)
+ end
+
+ it "does not change self" do
+ a = ['a', 'b', 'c', 'd']
+ a.collect { |i| i + '!' }
+ a.should == ['a', 'b', 'c', 'd']
+ end
+
+ it "returns the evaluated value of block if it broke in the block" do
+ a = ['a', 'b', 'c', 'd']
+ b = a.collect {|i|
+ if i == 'c'
+ break 0
+ else
+ i + '!'
+ end
+ }
+ b.should == 0
+ end
+
+ it "returns an Enumerator when no block given" do
+ a = [1, 2, 3]
+ a.collect.should.instance_of?(Enumerator)
+ end
+
+ it "raises an ArgumentError when no block and with arguments" do
+ a = [1, 2, 3]
+ -> {
+ a.collect(:foo)
+ }.should.raise(ArgumentError)
+ end
+
+ before :each do
+ @object = [1, 2, 3, 4]
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :collect
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :collect
end
describe "Array#collect!" do
- it_behaves_like :array_collect_b, :collect!
+ it "replaces each element with the value returned by block" do
+ a = [7, 9, 3, 5]
+ a.collect! { |i| i - 1 }.should.equal?(a)
+ a.should == [6, 8, 2, 4]
+ end
+
+ it "returns self" do
+ a = [1, 2, 3, 4, 5]
+ b = a.collect! {|i| i+1 }
+ a.should.equal? b
+ end
+
+ it "returns the evaluated value of block but its contents is partially modified, if it broke in the block" do
+ a = ['a', 'b', 'c', 'd']
+ b = a.collect! {|i|
+ if i == 'c'
+ break 0
+ else
+ i + '!'
+ end
+ }
+ b.should == 0
+ a.should == ['a!', 'b!', 'c', 'd']
+ end
+
+ it "returns an Enumerator when no block given, and the enumerator can modify the original array" do
+ a = [1, 2, 3]
+ enum = a.collect!
+ enum.should.instance_of?(Enumerator)
+ enum.each{|i| "#{i}!" }
+ a.should == ["1!", "2!", "3!"]
+ end
+
+ describe "when frozen" do
+ it "raises a FrozenError" do
+ -> { ArraySpecs.frozen_array.collect! {} }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError when empty" do
+ -> { ArraySpecs.empty_frozen_array.collect! {} }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError when calling #each on the returned Enumerator" do
+ enumerator = ArraySpecs.frozen_array.collect!
+ -> { enumerator.each {|x| x } }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError when calling #each on the returned Enumerator when empty" do
+ enumerator = ArraySpecs.empty_frozen_array.collect!
+ -> { enumerator.each {|x| x } }.should.raise(FrozenError)
+ end
+ end
+
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.collect! { raise StandardError, 'Oops' }
+ rescue
+ end
+
+ a.should == [1, 2, 3]
+ end
+
+ it "only changes elements before error is raised, keeping the element which raised an error." do
+ a = [1, 2, 3, 4]
+ begin
+ a.collect! do |e|
+ case e
+ when 1 then -1
+ when 2 then -2
+ when 3 then raise StandardError, 'Oops'
+ else 0
+ end
+ end
+ rescue StandardError
+ end
+
+ a.should == [-1, -2, 3, 4]
+ end
+
+ before :each do
+ @object = [1, 2, 3, 4]
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :collect!
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :collect!
end
diff --git a/spec/ruby/core/array/combination_spec.rb b/spec/ruby/core/array/combination_spec.rb
index f16d6f98fc..ac570687ca 100644
--- a/spec/ruby/core/array/combination_spec.rb
+++ b/spec/ruby/core/array/combination_spec.rb
@@ -6,11 +6,11 @@ describe "Array#combination" do
end
it "returns an enumerator when no block is provided" do
- @array.combination(2).should be_an_instance_of(Enumerator)
+ @array.combination(2).should.instance_of?(Enumerator)
end
it "returns self when a block is given" do
- @array.combination(2){}.should equal(@array)
+ @array.combination(2){}.should.equal?(@array)
end
it "yields nothing for out of bounds length and return self" do
@@ -30,7 +30,7 @@ describe "Array#combination" do
it "yields a copy of self if the argument is the size of the receiver" do
r = @array.combination(4).to_a
r.should == [@array]
- r[0].should_not equal(@array)
+ r[0].should_not.equal?(@array)
end
it "yields [] when length is 0" do
diff --git a/spec/ruby/core/array/compact_spec.rb b/spec/ruby/core/array/compact_spec.rb
index 83b3fa2a89..dbcd16da35 100644
--- a/spec/ruby/core/array/compact_spec.rb
+++ b/spec/ruby/core/array/compact_spec.rb
@@ -15,30 +15,30 @@ describe "Array#compact" do
it "does not return self" do
a = [1, 2, 3]
- a.compact.should_not equal(a)
+ a.compact.should_not.equal?(a)
end
it "does not return subclass instance for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3, nil].compact.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3, nil].compact.should.instance_of?(Array)
end
end
describe "Array#compact!" do
it "removes all nil elements" do
a = ['a', nil, 'b', false, 'c']
- a.compact!.should equal(a)
+ a.compact!.should.equal?(a)
a.should == ["a", "b", false, "c"]
a = [nil, 'a', 'b', false, 'c']
- a.compact!.should equal(a)
+ a.compact!.should.equal?(a)
a.should == ["a", "b", false, "c"]
a = ['a', 'b', false, 'c', nil]
- a.compact!.should equal(a)
+ a.compact!.should.equal?(a)
a.should == ["a", "b", false, "c"]
end
it "returns self if some nil elements are removed" do
a = ['a', nil, 'b', false, 'c']
- a.compact!.should equal a
+ a.compact!.should.equal? a
end
it "returns nil if there are no nil elements to remove" do
@@ -46,6 +46,6 @@ describe "Array#compact!" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.compact! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.compact! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/comparison_spec.rb b/spec/ruby/core/array/comparison_spec.rb
index 5d1c3265f1..14e8931e5a 100644
--- a/spec/ruby/core/array/comparison_spec.rb
+++ b/spec/ruby/core/array/comparison_spec.rb
@@ -92,6 +92,6 @@ describe "Array#<=>" do
end
it "returns nil when the argument is not array-like" do
- ([] <=> false).should be_nil
+ ([] <=> false).should == nil
end
end
diff --git a/spec/ruby/core/array/concat_spec.rb b/spec/ruby/core/array/concat_spec.rb
index f3cab9c17c..1e8d20c36c 100644
--- a/spec/ruby/core/array/concat_spec.rb
+++ b/spec/ruby/core/array/concat_spec.rb
@@ -4,12 +4,12 @@ require_relative 'fixtures/classes'
describe "Array#concat" do
it "returns the array itself" do
ary = [1,2,3]
- ary.concat([4,5,6]).equal?(ary).should be_true
+ ary.concat([4,5,6]).equal?(ary).should == true
end
it "appends the elements in the other array" do
ary = [1, 2, 3]
- ary.concat([9, 10, 11]).should equal(ary)
+ ary.concat([9, 10, 11]).should.equal?(ary)
ary.should == [1, 2, 3, 9, 10, 11]
ary.concat([])
ary.should == [1, 2, 3, 9, 10, 11]
@@ -33,12 +33,12 @@ describe "Array#concat" do
end
it "raises a FrozenError when Array is frozen and modification occurs" do
- -> { ArraySpecs.frozen_array.concat [1] }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.concat [1] }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError when Array is frozen and no modification occurs" do
- -> { ArraySpecs.frozen_array.concat([]) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.concat([]) }.should.raise(FrozenError)
end
it "appends elements to an Array with enough capacity that has been shifted" do
@@ -68,7 +68,7 @@ describe "Array#concat" do
it "returns self when given no arguments" do
ary = [1, 2]
- ary.concat.should equal(ary)
+ ary.concat.should.equal?(ary)
ary.should == [1, 2]
end
end
diff --git a/spec/ruby/core/array/constructor_spec.rb b/spec/ruby/core/array/constructor_spec.rb
index 6f36074c45..c4398c535d 100644
--- a/spec/ruby/core/array/constructor_spec.rb
+++ b/spec/ruby/core/array/constructor_spec.rb
@@ -7,7 +7,7 @@ describe "Array.[]" do
Array.[](5, true, nil, 'a', "Ruby", obj).should == [5, true, nil, "a", "Ruby", obj]
a = ArraySpecs::MyArray.[](5, true, nil, 'a', "Ruby", obj)
- a.should be_an_instance_of(ArraySpecs::MyArray)
+ a.should.instance_of?(ArraySpecs::MyArray)
a.inspect.should == [5, true, nil, "a", "Ruby", obj].inspect
end
end
@@ -18,7 +18,7 @@ describe "Array[]" do
Array[5, true, nil, 'a', "Ruby", obj].should == Array.[](5, true, nil, "a", "Ruby", obj)
a = ArraySpecs::MyArray[5, true, nil, 'a', "Ruby", obj]
- a.should be_an_instance_of(ArraySpecs::MyArray)
+ a.should.instance_of?(ArraySpecs::MyArray)
a.inspect.should == [5, true, nil, "a", "Ruby", obj].inspect
end
end
diff --git a/spec/ruby/core/array/cycle_spec.rb b/spec/ruby/core/array/cycle_spec.rb
index 7219b49883..29284257e9 100644
--- a/spec/ruby/core/array/cycle_spec.rb
+++ b/spec/ruby/core/array/cycle_spec.rb
@@ -10,17 +10,17 @@ describe "Array#cycle" do
end
it "does not yield and returns nil when the array is empty and passed value is an integer" do
- [].cycle(6, &@prc).should be_nil
+ [].cycle(6, &@prc).should == nil
ScratchPad.recorded.should == []
end
it "does not yield and returns nil when the array is empty and passed value is nil" do
- [].cycle(nil, &@prc).should be_nil
+ [].cycle(nil, &@prc).should == nil
ScratchPad.recorded.should == []
end
it "does not yield and returns nil when passed 0" do
- @array.cycle(0, &@prc).should be_nil
+ @array.cycle(0, &@prc).should == nil
ScratchPad.recorded.should == []
end
@@ -48,13 +48,13 @@ describe "Array#cycle" do
it "does not rescue StopIteration when not passed a count" do
-> do
@array.cycle { raise StopIteration }
- end.should raise_error(StopIteration)
+ end.should.raise(StopIteration)
end
it "does not rescue StopIteration when passed a count" do
-> do
@array.cycle(3) { raise StopIteration }
- end.should raise_error(StopIteration)
+ end.should.raise(StopIteration)
end
it "iterates the array Integer(count) times when passed a Float count" do
@@ -74,23 +74,23 @@ describe "Array#cycle" do
count = mock("cycle count 2")
count.should_receive(:to_int).and_return("2")
- -> { @array.cycle(count, &@prc) }.should raise_error(TypeError)
+ -> { @array.cycle(count, &@prc) }.should.raise(TypeError)
end
it "raises a TypeError if passed a String" do
- -> { @array.cycle("4") { } }.should raise_error(TypeError)
+ -> { @array.cycle("4") { } }.should.raise(TypeError)
end
it "raises a TypeError if passed an Object" do
- -> { @array.cycle(mock("cycle count")) { } }.should raise_error(TypeError)
+ -> { @array.cycle(mock("cycle count")) { } }.should.raise(TypeError)
end
it "raises a TypeError if passed true" do
- -> { @array.cycle(true) { } }.should raise_error(TypeError)
+ -> { @array.cycle(true) { } }.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
- -> { @array.cycle(false) { } }.should raise_error(TypeError)
+ -> { @array.cycle(false) { } }.should.raise(TypeError)
end
before :all do
diff --git a/spec/ruby/core/array/deconstruct_spec.rb b/spec/ruby/core/array/deconstruct_spec.rb
index ad67abe47b..11bb8e72c4 100644
--- a/spec/ruby/core/array/deconstruct_spec.rb
+++ b/spec/ruby/core/array/deconstruct_spec.rb
@@ -4,6 +4,6 @@ describe "Array#deconstruct" do
it "returns self" do
array = [1]
- array.deconstruct.should equal array
+ array.deconstruct.should.equal? array
end
end
diff --git a/spec/ruby/core/array/delete_at_spec.rb b/spec/ruby/core/array/delete_at_spec.rb
index 80ec643702..1e298b6730 100644
--- a/spec/ruby/core/array/delete_at_spec.rb
+++ b/spec/ruby/core/array/delete_at_spec.rb
@@ -36,6 +36,6 @@ describe "Array#delete_at" do
end
it "raises a FrozenError on a frozen array" do
- -> { [1,2,3].freeze.delete_at(0) }.should raise_error(FrozenError)
+ -> { [1,2,3].freeze.delete_at(0) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb
index 10972eee0e..701a612395 100644
--- a/spec/ruby/core/array/delete_if_spec.rb
+++ b/spec/ruby/core/array/delete_if_spec.rb
@@ -17,7 +17,7 @@ describe "Array#delete_if" do
end
it "returns self" do
- @a.delete_if{ true }.equal?(@a).should be_true
+ @a.delete_if{ true }.equal?(@a).should == true
end
it_behaves_like :enumeratorize, :delete_if
@@ -25,27 +25,27 @@ describe "Array#delete_if" do
it "returns self when called on an Array emptied with #shift" do
array = [1]
array.shift
- array.delete_if { |x| true }.should equal(array)
+ array.delete_if { |x| true }.should.equal?(array)
end
it "returns an Enumerator if no block given, and the enumerator can modify the original array" do
enum = @a.delete_if
- enum.should be_an_instance_of(Enumerator)
- @a.should_not be_empty
+ enum.should.instance_of?(Enumerator)
+ @a.should_not.empty?
enum.each { true }
- @a.should be_empty
+ @a.should.empty?
end
it "returns an Enumerator if no block given, and the array is frozen" do
- @a.freeze.delete_if.should be_an_instance_of(Enumerator)
+ @a.freeze.delete_if.should.instance_of?(Enumerator)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.delete_if {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.delete_if {} }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.delete_if {} }.should.raise(FrozenError)
end
it "does not truncate the array is the block raises an exception" do
diff --git a/spec/ruby/core/array/delete_spec.rb b/spec/ruby/core/array/delete_spec.rb
index dddbbe6bd3..0d80b2839d 100644
--- a/spec/ruby/core/array/delete_spec.rb
+++ b/spec/ruby/core/array/delete_spec.rb
@@ -41,6 +41,6 @@ describe "Array#delete" do
end
it "raises a FrozenError on a frozen array" do
- -> { [1, 2, 3].freeze.delete(1) }.should raise_error(FrozenError)
+ -> { [1, 2, 3].freeze.delete(1) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/difference_spec.rb b/spec/ruby/core/array/difference_spec.rb
index 9f7d4c4a1a..63e32feca0 100644
--- a/spec/ruby/core/array/difference_spec.rb
+++ b/spec/ruby/core/array/difference_spec.rb
@@ -8,11 +8,11 @@ describe "Array#difference" do
it "returns a copy when called without any parameter" do
x = [1, 2, 3, 2]
x.difference.should == x
- x.difference.should_not equal x
+ x.difference.should_not.equal? x
end
it "does not return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].difference.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].difference.should.instance_of?(Array)
end
it "accepts multiple arguments" do
diff --git a/spec/ruby/core/array/dig_spec.rb b/spec/ruby/core/array/dig_spec.rb
index f2d8ff47fd..4166ff9f1f 100644
--- a/spec/ruby/core/array/dig_spec.rb
+++ b/spec/ruby/core/array/dig_spec.rb
@@ -4,7 +4,7 @@ describe "Array#dig" do
it "returns #at with one arg" do
['a'].dig(0).should == 'a'
- ['a'].dig(1).should be_nil
+ ['a'].dig(1).should == nil
end
it "recurses array elements" do
@@ -22,20 +22,20 @@ describe "Array#dig" do
it "raises a TypeError for a non-numeric index" do
-> {
['a'].dig(:first)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if any intermediate step does not respond to #dig" do
a = [1, 2]
-> {
a.dig(0, 1)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises an ArgumentError if no arguments provided" do
-> {
[10].dig()
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns nil if any intermediate step is nil" do
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index 5926c291b8..c0e1c9edce 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -7,7 +7,7 @@ describe "Array#drop" do
end
it "raises an ArgumentError if the number of elements specified is negative" do
- -> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
+ -> { [1, 2].drop(-3) }.should.raise(ArgumentError)
end
it "returns an empty Array if all elements are dropped" do
@@ -40,17 +40,17 @@ describe "Array#drop" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [1, 2].drop("cat") }.should raise_error(TypeError)
+ -> { [1, 2].drop("cat") }.should.raise(TypeError)
end
it "raises a TypeError when the passed argument isn't an integer and #to_int returns non-Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("cat")
- -> { [1, 2].drop(obj) }.should raise_error(TypeError)
+ -> { [1, 2].drop(obj) }.should.raise(TypeError)
end
it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb
index bd46e8b882..4fead3ff06 100644
--- a/spec/ruby/core/array/drop_while_spec.rb
+++ b/spec/ruby/core/array/drop_while_spec.rb
@@ -19,6 +19,6 @@ describe "Array#drop_while" do
end
it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/dup_spec.rb b/spec/ruby/core/array/dup_spec.rb
index 17f467d5fc..f14aeca3b5 100644
--- a/spec/ruby/core/array/dup_spec.rb
+++ b/spec/ruby/core/array/dup_spec.rb
@@ -12,8 +12,8 @@ describe "Array#dup" do
aa = a.dup
bb = b.dup
- aa.frozen?.should be_false
- bb.frozen?.should be_false
+ aa.frozen?.should == false
+ bb.frozen?.should == false
end
it "does not copy singleton methods" do
@@ -23,9 +23,9 @@ describe "Array#dup" do
aa = a.dup
bb = b.dup
- a.respond_to?(:a_singleton_method).should be_true
- b.respond_to?(:a_singleton_method).should be_false
- aa.respond_to?(:a_singleton_method).should be_false
- bb.respond_to?(:a_singleton_method).should be_false
+ a.respond_to?(:a_singleton_method).should == true
+ b.respond_to?(:a_singleton_method).should == false
+ aa.respond_to?(:a_singleton_method).should == false
+ bb.respond_to?(:a_singleton_method).should == false
end
end
diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb
index 3a4bca9251..b238a89d8a 100644
--- a/spec/ruby/core/array/each_index_spec.rb
+++ b/spec/ruby/core/array/each_index_spec.rb
@@ -20,7 +20,7 @@ describe "Array#each_index" do
it "returns self" do
a = [:a, :b, :c]
- a.each_index { |i| }.should equal(a)
+ a.each_index { |i| }.should.equal?(a)
end
it "is not confused by removing elements from the front" do
diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb
index f4b5b758d0..73a4c36b17 100644
--- a/spec/ruby/core/array/each_spec.rb
+++ b/spec/ruby/core/array/each_spec.rb
@@ -13,7 +13,7 @@ describe "Array#each" do
it "yields each element to the block" do
a = []
x = [1, 2, 3]
- x.each { |item| a << item }.should equal(x)
+ x.each { |item| a << item }.should.equal?(x)
a.should == [1, 2, 3]
end
diff --git a/spec/ruby/core/array/element_reference_spec.rb b/spec/ruby/core/array/element_reference_spec.rb
index 31e5578a09..d5f4b54961 100644
--- a/spec/ruby/core/array/element_reference_spec.rb
+++ b/spec/ruby/core/array/element_reference_spec.rb
@@ -1,9 +1,862 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/slice'
describe "Array#[]" do
- it_behaves_like :array_slice, :[]
+ it "returns the element at index with [index]" do
+ [ "a", "b", "c", "d", "e" ][1].should == "b"
+
+ a = [1, 2, 3, 4]
+
+ a[0].should == 1
+ a[1].should == 2
+ a[2].should == 3
+ a[3].should == 4
+ a[4].should == nil
+ a[10].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns the element at index from the end of the array with [-index]" do
+ [ "a", "b", "c", "d", "e" ][-2].should == "d"
+
+ a = [1, 2, 3, 4]
+
+ a[-1].should == 4
+ a[-2].should == 3
+ a[-3].should == 2
+ a[-4].should == 1
+ a[-5].should == nil
+ a[-10].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns count elements starting from index with [index, count]" do
+ [ "a", "b", "c", "d", "e" ][2, 3].should == ["c", "d", "e"]
+
+ a = [1, 2, 3, 4]
+
+ a[0, 0].should == []
+ a[0, 1].should == [1]
+ a[0, 2].should == [1, 2]
+ a[0, 4].should == [1, 2, 3, 4]
+ a[0, 6].should == [1, 2, 3, 4]
+ a[0, -1].should == nil
+ a[0, -2].should == nil
+ a[0, -4].should == nil
+
+ a[2, 0].should == []
+ a[2, 1].should == [3]
+ a[2, 2].should == [3, 4]
+ a[2, 4].should == [3, 4]
+ a[2, -1].should == nil
+
+ a[4, 0].should == []
+ a[4, 2].should == []
+ a[4, -1].should == nil
+
+ a[5, 0].should == nil
+ a[5, 2].should == nil
+ a[5, -1].should == nil
+
+ a[6, 0].should == nil
+ a[6, 2].should == nil
+ a[6, -1].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns count elements starting at index from the end of array with [-index, count]" do
+ [ "a", "b", "c", "d", "e" ][-2, 2].should == ["d", "e"]
+
+ a = [1, 2, 3, 4]
+
+ a[-1, 0].should == []
+ a[-1, 1].should == [4]
+ a[-1, 2].should == [4]
+ a[-1, -1].should == nil
+
+ a[-2, 0].should == []
+ a[-2, 1].should == [3]
+ a[-2, 2].should == [3, 4]
+ a[-2, 4].should == [3, 4]
+ a[-2, -1].should == nil
+
+ a[-4, 0].should == []
+ a[-4, 1].should == [1]
+ a[-4, 2].should == [1, 2]
+ a[-4, 4].should == [1, 2, 3, 4]
+ a[-4, 6].should == [1, 2, 3, 4]
+ a[-4, -1].should == nil
+
+ a[-5, 0].should == nil
+ a[-5, 1].should == nil
+ a[-5, 10].should == nil
+ a[-5, -1].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns the first count elements with [0, count]" do
+ [ "a", "b", "c", "d", "e" ][0, 3].should == ["a", "b", "c"]
+ end
+
+ it "returns the subarray which is independent to self with [index,count]" do
+ a = [1, 2, 3]
+ sub = a[1, 2]
+ sub.replace([:a, :b])
+ a.should == [1, 2, 3]
+ end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.stub!(:to_int).and_return(2)
+
+ a = [1, 2, 3, 4]
+ a[obj].should == 3
+ a[obj, 1].should == [3]
+ a[obj, obj].should == [3, 4]
+ a[0, obj].should == [1, 2]
+ end
+
+ it "raises TypeError if to_int returns non-integer" do
+ from = mock('from')
+ to = mock('to')
+
+ # So we can construct a range out of them...
+ def from.<=>(o) 0 end
+ def to.<=>(o) 0 end
+
+ a = [1, 2, 3, 4, 5]
+
+ def from.to_int() 'cat' end
+ def to.to_int() -2 end
+
+ -> { a[from..to] }.should.raise(TypeError)
+
+ def from.to_int() 1 end
+ def to.to_int() 'cat' end
+
+ -> { a[from..to] }.should.raise(TypeError)
+ end
+
+ it "returns the elements specified by Range indexes with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][1..3].should == ["b", "c", "d"]
+ [ "a", "b", "c", "d", "e" ][4..-1].should == ['e']
+ [ "a", "b", "c", "d", "e" ][3..3].should == ['d']
+ [ "a", "b", "c", "d", "e" ][3..-2].should == ['d']
+ ['a'][0..-1].should == ['a']
+
+ a = [1, 2, 3, 4]
+
+ a[0..-10].should == []
+ a[0..0].should == [1]
+ a[0..1].should == [1, 2]
+ a[0..2].should == [1, 2, 3]
+ a[0..3].should == [1, 2, 3, 4]
+ a[0..4].should == [1, 2, 3, 4]
+ a[0..10].should == [1, 2, 3, 4]
+
+ a[2..-10].should == []
+ a[2..0].should == []
+ a[2..2].should == [3]
+ a[2..3].should == [3, 4]
+ a[2..4].should == [3, 4]
+
+ a[3..0].should == []
+ a[3..3].should == [4]
+ a[3..4].should == [4]
+
+ a[4..0].should == []
+ a[4..4].should == []
+ a[4..5].should == []
+
+ a[5..0].should == nil
+ a[5..5].should == nil
+ a[5..6].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns elements specified by Range indexes except the element at index n with [m...n]" do
+ [ "a", "b", "c", "d", "e" ][1...3].should == ["b", "c"]
+
+ a = [1, 2, 3, 4]
+
+ a[0...-10].should == []
+ a[0...0].should == []
+ a[0...1].should == [1]
+ a[0...2].should == [1, 2]
+ a[0...3].should == [1, 2, 3]
+ a[0...4].should == [1, 2, 3, 4]
+ a[0...10].should == [1, 2, 3, 4]
+
+ a[2...-10].should == []
+ a[2...0].should == []
+ a[2...2].should == []
+ a[2...3].should == [3]
+ a[2...4].should == [3, 4]
+
+ a[3...0].should == []
+ a[3...3].should == []
+ a[3...4].should == [4]
+
+ a[4...0].should == []
+ a[4...4].should == []
+ a[4...5].should == []
+
+ a[5...0].should == nil
+ a[5...5].should == nil
+ a[5...6].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns elements that exist if range start is in the array but range end is not with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][4..7].should == ["e"]
+ end
+
+ it "accepts Range instances having a negative m and both signs for n with [m..n] and [m...n]" do
+ a = [1, 2, 3, 4]
+
+ a[-1..-1].should == [4]
+ a[-1...-1].should == []
+ a[-1..3].should == [4]
+ a[-1...3].should == []
+ a[-1..4].should == [4]
+ a[-1...4].should == [4]
+ a[-1..10].should == [4]
+ a[-1...10].should == [4]
+ a[-1..0].should == []
+ a[-1..-4].should == []
+ a[-1...-4].should == []
+ a[-1..-6].should == []
+ a[-1...-6].should == []
+
+ a[-2..-2].should == [3]
+ a[-2...-2].should == []
+ a[-2..-1].should == [3, 4]
+ a[-2...-1].should == [3]
+ a[-2..10].should == [3, 4]
+ a[-2...10].should == [3, 4]
+
+ a[-4..-4].should == [1]
+ a[-4..-2].should == [1, 2, 3]
+ a[-4...-2].should == [1, 2]
+ a[-4..-1].should == [1, 2, 3, 4]
+ a[-4...-1].should == [1, 2, 3]
+ a[-4..3].should == [1, 2, 3, 4]
+ a[-4...3].should == [1, 2, 3]
+ a[-4..4].should == [1, 2, 3, 4]
+ a[-4...4].should == [1, 2, 3, 4]
+ a[-4...4].should == [1, 2, 3, 4]
+ a[-4..0].should == [1]
+ a[-4...0].should == []
+ a[-4..1].should == [1, 2]
+ a[-4...1].should == [1]
+
+ a[-5..-5].should == nil
+ a[-5...-5].should == nil
+ a[-5..-4].should == nil
+ a[-5..-1].should == nil
+ a[-5..10].should == nil
+
+ a.should == [1, 2, 3, 4]
+ end
+
+ it "returns the subarray which is independent to self with [m..n]" do
+ a = [1, 2, 3]
+ sub = a[1..2]
+ sub.replace([:a, :b])
+ a.should == [1, 2, 3]
+ end
+
+ it "tries to convert Range elements to Integers using #to_int with [m..n] and [m...n]" do
+ from = mock('from')
+ to = mock('to')
+
+ # So we can construct a range out of them...
+ def from.<=>(o) 0 end
+ def to.<=>(o) 0 end
+
+ def from.to_int() 1 end
+ def to.to_int() -2 end
+
+ a = [1, 2, 3, 4]
+
+ a[from..to].should == [2, 3]
+ a[from...to].should == [2]
+ a[1..0].should == []
+ a[1...0].should == []
+
+ -> { a["a" .. "b"] }.should.raise(TypeError)
+ -> { a["a" ... "b"] }.should.raise(TypeError)
+ -> { a[from .. "b"] }.should.raise(TypeError)
+ -> { a[from ... "b"] }.should.raise(TypeError)
+ end
+
+ it "returns the same elements as [m..n] and [m...n] with Range subclasses" do
+ a = [1, 2, 3, 4]
+ range_incl = ArraySpecs::MyRange.new(1, 2)
+ range_excl = ArraySpecs::MyRange.new(-3, -1, true)
+
+ a[range_incl].should == [2, 3]
+ a[range_excl].should == [2, 3]
+ end
+
+ it "returns nil for a requested index not in the array with [index]" do
+ [ "a", "b", "c", "d", "e" ][5].should == nil
+ end
+
+ it "returns [] if the index is valid but length is zero with [index, length]" do
+ [ "a", "b", "c", "d", "e" ][0, 0].should == []
+ [ "a", "b", "c", "d", "e" ][2, 0].should == []
+ end
+
+ it "returns nil if length is zero but index is invalid with [index, length]" do
+ [ "a", "b", "c", "d", "e" ][100, 0].should == nil
+ [ "a", "b", "c", "d", "e" ][-50, 0].should == nil
+ end
+
+ # This is by design. It is in the official documentation.
+ it "returns [] if index == array.size with [index, length]" do
+ %w|a b c d e|[5, 2].should == []
+ end
+
+ it "returns nil if index > array.size with [index, length]" do
+ %w|a b c d e|[6, 2].should == nil
+ end
+
+ it "returns nil if length is negative with [index, length]" do
+ %w|a b c d e|[3, -1].should == nil
+ %w|a b c d e|[2, -2].should == nil
+ %w|a b c d e|[1, -100].should == nil
+ end
+
+ it "returns nil if no requested index is in the array with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][6..10].should == nil
+ end
+
+ it "returns nil if range start is not in the array with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][-10..2].should == nil
+ [ "a", "b", "c", "d", "e" ][10..12].should == nil
+ end
+
+ it "returns an empty array when m == n with [m...n]" do
+ [1, 2, 3, 4, 5][1...1].should == []
+ end
+
+ it "returns an empty array with [0...0]" do
+ [1, 2, 3, 4, 5][0...0].should == []
+ end
+
+ it "returns a subarray where m, n negatives and m < n with [m..n]" do
+ [ "a", "b", "c", "d", "e" ][-3..-2].should == ["c", "d"]
+ end
+
+ it "returns an array containing the first element with [0..0]" do
+ [1, 2, 3, 4, 5][0..0].should == [1]
+ end
+
+ it "returns the entire array with [0..-1]" do
+ [1, 2, 3, 4, 5][0..-1].should == [1, 2, 3, 4, 5]
+ end
+
+ it "returns all but the last element with [0...-1]" do
+ [1, 2, 3, 4, 5][0...-1].should == [1, 2, 3, 4]
+ end
+
+ it "returns [3] for [2..-1] out of [1, 2, 3]" do
+ [1,2,3][2..-1].should == [3]
+ end
+
+ it "returns an empty array when m > n and m, n are positive with [m..n]" do
+ [1, 2, 3, 4, 5][3..2].should == []
+ end
+
+ it "returns an empty array when m > n and m, n are negative with [m..n]" do
+ [1, 2, 3, 4, 5][-2..-3].should == []
+ end
+
+ it "does not expand array when the indices are outside of the array bounds" do
+ a = [1, 2]
+ a[4].should == nil
+ a.should == [1, 2]
+ a[4, 0].should == nil
+ a.should == [1, 2]
+ a[6, 1].should == nil
+ a.should == [1, 2]
+ a[8...8].should == nil
+ a.should == [1, 2]
+ a[10..10].should == nil
+ a.should == [1, 2]
+ end
+
+ describe "with a subclass of Array" do
+ before :each do
+ ScratchPad.clear
+
+ @array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
+ end
+
+ it "returns a Array instance with [n, m]" do
+ @array[0, 2].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [-n, m]" do
+ @array[-3, 2].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [n..m]" do
+ @array[1..3].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [n...m]" do
+ @array[1...3].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [-n..-m]" do
+ @array[-3..-1].should.instance_of?(Array)
+ end
+
+ it "returns a Array instance with [-n...-m]" do
+ @array[-3...-1].should.instance_of?(Array)
+ end
+
+ it "returns an empty array when m == n with [m...n]" do
+ @array[1...1].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns an empty array with [0...0]" do
+ @array[0...0].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns an empty array when m > n and m, n are positive with [m..n]" do
+ @array[3..2].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns an empty array when m > n and m, n are negative with [m..n]" do
+ @array[-2..-3].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns [] if index == array.size with [index, length]" do
+ @array[5, 2].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "returns [] if the index is valid but length is zero with [index, length]" do
+ @array[0, 0].should == []
+ @array[2, 0].should == []
+ ScratchPad.recorded.should == nil
+ end
+
+ it "does not call #initialize on the subclass instance" do
+ @array[0, 3].should == [1, 2, 3]
+ ScratchPad.recorded.should == nil
+ end
+ end
+
+ it "raises a RangeError when the start index is out of range of Fixnum" do
+ array = [1, 2, 3, 4, 5, 6]
+ obj = mock('large value')
+ obj.should_receive(:to_int).and_return(bignum_value)
+ -> { array[obj] }.should.raise(RangeError)
+
+ obj = 8e19
+ -> { array[obj] }.should.raise(RangeError)
+
+ # boundary value when longs are 64 bits
+ -> { array[2.0**63] }.should.raise(RangeError)
+
+ # just under the boundary value when longs are 64 bits
+ array[max_long.to_f.prev_float].should == nil
+ end
+
+ it "raises a RangeError when the length is out of range of Fixnum" do
+ array = [1, 2, 3, 4, 5, 6]
+ obj = mock('large value')
+ obj.should_receive(:to_int).and_return(bignum_value)
+ -> { array[1, obj] }.should.raise(RangeError)
+
+ obj = 8e19
+ -> { array[1, obj] }.should.raise(RangeError)
+ end
+
+ it "raises a type error if a range is passed with a length" do
+ ->{ [1, 2, 3][1..2, 1] }.should.raise(TypeError)
+ end
+
+ it "raises a RangeError if passed a range with a bound that is too large" do
+ array = [1, 2, 3, 4, 5, 6]
+ -> { array[bignum_value..(bignum_value + 1)] }.should.raise(RangeError)
+ -> { array[0..bignum_value] }.should.raise(RangeError)
+ end
+
+ it "can accept endless ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a[eval("(2..)")].should == [2, 3, 4, 5]
+ a[eval("(2...)")].should == [2, 3, 4, 5]
+ a[eval("(-2..)")].should == [4, 5]
+ a[eval("(-2...)")].should == [4, 5]
+ a[eval("(9..)")].should == nil
+ a[eval("(9...)")].should == nil
+ a[eval("(-9..)")].should == nil
+ a[eval("(-9...)")].should == nil
+ end
+
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ before :each do
+ @array = [0, 1, 2, 3, 4, 5]
+ end
+
+ it "has endless range and positive steps" do
+ @array[eval("(0..).step(1)")].should == [0, 1, 2, 3, 4, 5]
+ @array[eval("(0..).step(2)")].should == [0, 2, 4]
+ @array[eval("(0..).step(10)")].should == [0]
+
+ @array[eval("(2..).step(1)")].should == [2, 3, 4, 5]
+ @array[eval("(2..).step(2)")].should == [2, 4]
+ @array[eval("(2..).step(10)")].should == [2]
+
+ @array[eval("(-3..).step(1)")].should == [3, 4, 5]
+ @array[eval("(-3..).step(2)")].should == [3, 5]
+ @array[eval("(-3..).step(10)")].should == [3]
+ end
+
+ it "has beginless range and positive steps" do
+ # end with zero index
+ @array[(..0).step(1)].should == [0]
+ @array[(...0).step(1)].should == []
+
+ @array[(..0).step(2)].should == [0]
+ @array[(...0).step(2)].should == []
+
+ @array[(..0).step(10)].should == [0]
+ @array[(...0).step(10)].should == []
+
+ # end with positive index
+ @array[(..3).step(1)].should == [0, 1, 2, 3]
+ @array[(...3).step(1)].should == [0, 1, 2]
+
+ @array[(..3).step(2)].should == [0, 2]
+ @array[(...3).step(2)].should == [0, 2]
+
+ @array[(..3).step(10)].should == [0]
+ @array[(...3).step(10)].should == [0]
+
+ # end with negative index
+ @array[(..-2).step(1)].should == [0, 1, 2, 3, 4,]
+ @array[(...-2).step(1)].should == [0, 1, 2, 3]
+
+ @array[(..-2).step(2)].should == [0, 2, 4]
+ @array[(...-2).step(2)].should == [0, 2]
+
+ @array[(..-2).step(10)].should == [0]
+ @array[(...-2).step(10)].should == [0]
+ end
+
+ it "has endless range and negative steps" do
+ @array[eval("(0..).step(-1)")].should == [0]
+ @array[eval("(0..).step(-2)")].should == [0]
+ @array[eval("(0..).step(-10)")].should == [0]
+
+ @array[eval("(2..).step(-1)")].should == [2, 1, 0]
+ @array[eval("(2..).step(-2)")].should == [2, 0]
+
+ @array[eval("(-3..).step(-1)")].should == [3, 2, 1, 0]
+ @array[eval("(-3..).step(-2)")].should == [3, 1]
+ end
+
+ it "has closed range and positive steps" do
+ # start and end with 0
+ @array[eval("(0..0).step(1)")].should == [0]
+ @array[eval("(0...0).step(1)")].should == []
+
+ @array[eval("(0..0).step(2)")].should == [0]
+ @array[eval("(0...0).step(2)")].should == []
+
+ @array[eval("(0..0).step(10)")].should == [0]
+ @array[eval("(0...0).step(10)")].should == []
+
+ # start and end with positive index
+ @array[eval("(1..3).step(1)")].should == [1, 2, 3]
+ @array[eval("(1...3).step(1)")].should == [1, 2]
+
+ @array[eval("(1..3).step(2)")].should == [1, 3]
+ @array[eval("(1...3).step(2)")].should == [1]
+
+ @array[eval("(1..3).step(10)")].should == [1]
+ @array[eval("(1...3).step(10)")].should == [1]
+
+ # start with positive index, end with negative index
+ @array[eval("(1..-2).step(1)")].should == [1, 2, 3, 4]
+ @array[eval("(1...-2).step(1)")].should == [1, 2, 3]
+
+ @array[eval("(1..-2).step(2)")].should == [1, 3]
+ @array[eval("(1...-2).step(2)")].should == [1, 3]
+
+ @array[eval("(1..-2).step(10)")].should == [1]
+ @array[eval("(1...-2).step(10)")].should == [1]
+
+ # start with negative index, end with positive index
+ @array[eval("(-4..4).step(1)")].should == [2, 3, 4]
+ @array[eval("(-4...4).step(1)")].should == [2, 3]
+
+ @array[eval("(-4..4).step(2)")].should == [2, 4]
+ @array[eval("(-4...4).step(2)")].should == [2]
+
+ @array[eval("(-4..4).step(10)")].should == [2]
+ @array[eval("(-4...4).step(10)")].should == [2]
+
+ # start with negative index, end with negative index
+ @array[eval("(-4..-2).step(1)")].should == [2, 3, 4]
+ @array[eval("(-4...-2).step(1)")].should == [2, 3]
+
+ @array[eval("(-4..-2).step(2)")].should == [2, 4]
+ @array[eval("(-4...-2).step(2)")].should == [2]
+
+ @array[eval("(-4..-2).step(10)")].should == [2]
+ @array[eval("(-4...-2).step(10)")].should == [2]
+ end
+
+ it "has closed range and negative steps" do
+ # start and end with 0
+ @array[eval("(0..0).step(-1)")].should == [0]
+ @array[eval("(0...0).step(-1)")].should == []
+
+ @array[eval("(0..0).step(-2)")].should == [0]
+ @array[eval("(0...0).step(-2)")].should == []
+
+ @array[eval("(0..0).step(-10)")].should == [0]
+ @array[eval("(0...0).step(-10)")].should == []
+
+ # start and end with positive index
+ @array[eval("(1..3).step(-1)")].should == []
+ @array[eval("(1...3).step(-1)")].should == []
+
+ @array[eval("(1..3).step(-2)")].should == []
+ @array[eval("(1...3).step(-2)")].should == []
+
+ @array[eval("(1..3).step(-10)")].should == []
+ @array[eval("(1...3).step(-10)")].should == []
+
+ # start with positive index, end with negative index
+ @array[eval("(1..-2).step(-1)")].should == []
+ @array[eval("(1...-2).step(-1)")].should == []
+
+ @array[eval("(1..-2).step(-2)")].should == []
+ @array[eval("(1...-2).step(-2)")].should == []
+
+ @array[eval("(1..-2).step(-10)")].should == []
+ @array[eval("(1...-2).step(-10)")].should == []
+
+ # start with negative index, end with positive index
+ @array[eval("(-4..4).step(-1)")].should == []
+ @array[eval("(-4...4).step(-1)")].should == []
+
+ @array[eval("(-4..4).step(-2)")].should == []
+ @array[eval("(-4...4).step(-2)")].should == []
+
+ @array[eval("(-4..4).step(-10)")].should == []
+ @array[eval("(-4...4).step(-10)")].should == []
+
+ # start with negative index, end with negative index
+ @array[eval("(-4..-2).step(-1)")].should == []
+ @array[eval("(-4...-2).step(-1)")].should == []
+
+ @array[eval("(-4..-2).step(-2)")].should == []
+ @array[eval("(-4...-2).step(-2)")].should == []
+
+ @array[eval("(-4..-2).step(-10)")].should == []
+ @array[eval("(-4...-2).step(-10)")].should == []
+ end
+
+ it "has inverted closed range and positive steps" do
+ # start and end with positive index
+ @array[eval("(3..1).step(1)")].should == []
+ @array[eval("(3...1).step(1)")].should == []
+
+ @array[eval("(3..1).step(2)")].should == []
+ @array[eval("(3...1).step(2)")].should == []
+
+ @array[eval("(3..1).step(10)")].should == []
+ @array[eval("(3...1).step(10)")].should == []
+
+ # start with negative index, end with positive index
+ @array[eval("(-2..1).step(1)")].should == []
+ @array[eval("(-2...1).step(1)")].should == []
+
+ @array[eval("(-2..1).step(2)")].should == []
+ @array[eval("(-2...1).step(2)")].should == []
+
+ @array[eval("(-2..1).step(10)")].should == []
+ @array[eval("(-2...1).step(10)")].should == []
+
+ # start with positive index, end with negative index
+ @array[eval("(4..-4).step(1)")].should == []
+ @array[eval("(4...-4).step(1)")].should == []
+
+ @array[eval("(4..-4).step(2)")].should == []
+ @array[eval("(4...-4).step(2)")].should == []
+
+ @array[eval("(4..-4).step(10)")].should == []
+ @array[eval("(4...-4).step(10)")].should == []
+
+ # start with negative index, end with negative index
+ @array[eval("(-2..-4).step(1)")].should == []
+ @array[eval("(-2...-4).step(1)")].should == []
+
+ @array[eval("(-2..-4).step(2)")].should == []
+ @array[eval("(-2...-4).step(2)")].should == []
+
+ @array[eval("(-2..-4).step(10)")].should == []
+ @array[eval("(-2...-4).step(10)")].should == []
+ end
+
+ it "has range with bounds outside of array" do
+ # end is equal to array's length
+ @array[(0..6).step(1)].should == [0, 1, 2, 3, 4, 5]
+ -> { @array[(0..6).step(2)] }.should.raise(RangeError)
+
+ # end is greater than length with positive steps
+ @array[(1..6).step(2)].should == [1, 3, 5]
+ @array[(2..7).step(2)].should == [2, 4]
+ -> { @array[(2..8).step(2)] }.should.raise(RangeError)
+
+ # begin is greater than length with negative steps
+ @array[(6..1).step(-2)].should == [5, 3, 1]
+ @array[(7..2).step(-2)].should == [5, 3]
+ -> { @array[(8..2).step(-2)] }.should.raise(RangeError)
+ end
+
+ it "has endless range with start outside of array's bounds" do
+ @array[eval("(6..).step(1)")].should == []
+ @array[eval("(7..).step(1)")].should == nil
+
+ @array[eval("(6..).step(2)")].should == []
+ -> { @array[eval("(7..).step(2)")] }.should.raise(RangeError)
+ end
+ end
+
+ it "can accept beginless ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a[(..3)].should == [0, 1, 2, 3]
+ a[(...3)].should == [0, 1, 2]
+ a[(..-3)].should == [0, 1, 2, 3]
+ a[(...-3)].should == [0, 1, 2]
+ a[(..0)].should == [0]
+ a[(...0)].should == []
+ a[(..9)].should == [0, 1, 2, 3, 4, 5]
+ a[(...9)].should == [0, 1, 2, 3, 4, 5]
+ a[(..-9)].should == []
+ a[(...-9)].should == []
+ end
+
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ it "with infinite/inverted ranges and negative steps" do
+ array = [0, 1, 2, 3, 4, 5]
+ array[(2..).step(-1)].should == [2, 1, 0]
+ array[(2..).step(-2)].should == [2, 0]
+ array[(2..).step(-3)].should == [2]
+ array[(2..).step(-4)].should == [2]
+
+ array[(-3..).step(-1)].should == [3, 2, 1, 0]
+ array[(-3..).step(-2)].should == [3, 1]
+ array[(-3..).step(-3)].should == [3, 0]
+ array[(-3..).step(-4)].should == [3]
+ array[(-3..).step(-5)].should == [3]
+
+ array[(..0).step(-1)].should == [5, 4, 3, 2, 1, 0]
+ array[(..0).step(-2)].should == [5, 3, 1]
+ array[(..0).step(-3)].should == [5, 2]
+ array[(..0).step(-4)].should == [5, 1]
+ array[(..0).step(-5)].should == [5, 0]
+ array[(..0).step(-6)].should == [5]
+ array[(..0).step(-7)].should == [5]
+
+ array[(...0).step(-1)].should == [5, 4, 3, 2, 1]
+ array[(...0).step(-2)].should == [5, 3, 1]
+ array[(...0).step(-3)].should == [5, 2]
+ array[(...0).step(-4)].should == [5, 1]
+ array[(...0).step(-5)].should == [5]
+ array[(...0).step(-6)].should == [5]
+
+ array[(...1).step(-1)].should == [5, 4, 3, 2]
+ array[(...1).step(-2)].should == [5, 3]
+ array[(...1).step(-3)].should == [5, 2]
+ array[(...1).step(-4)].should == [5]
+ array[(...1).step(-5)].should == [5]
+
+ array[(..-5).step(-1)].should == [5, 4, 3, 2, 1]
+ array[(..-5).step(-2)].should == [5, 3, 1]
+ array[(..-5).step(-3)].should == [5, 2]
+ array[(..-5).step(-4)].should == [5, 1]
+ array[(..-5).step(-5)].should == [5]
+ array[(..-5).step(-6)].should == [5]
+
+ array[(...-5).step(-1)].should == [5, 4, 3, 2]
+ array[(...-5).step(-2)].should == [5, 3]
+ array[(...-5).step(-3)].should == [5, 2]
+ array[(...-5).step(-4)].should == [5]
+ array[(...-5).step(-5)].should == [5]
+
+ array[(4..1).step(-1)].should == [4, 3, 2, 1]
+ array[(4..1).step(-2)].should == [4, 2]
+ array[(4..1).step(-3)].should == [4, 1]
+ array[(4..1).step(-4)].should == [4]
+ array[(4..1).step(-5)].should == [4]
+
+ array[(4...1).step(-1)].should == [4, 3, 2]
+ array[(4...1).step(-2)].should == [4, 2]
+ array[(4...1).step(-3)].should == [4]
+ array[(4...1).step(-4)].should == [4]
+
+ array[(-2..1).step(-1)].should == [4, 3, 2, 1]
+ array[(-2..1).step(-2)].should == [4, 2]
+ array[(-2..1).step(-3)].should == [4, 1]
+ array[(-2..1).step(-4)].should == [4]
+ array[(-2..1).step(-5)].should == [4]
+
+ array[(-2...1).step(-1)].should == [4, 3, 2]
+ array[(-2...1).step(-2)].should == [4, 2]
+ array[(-2...1).step(-3)].should == [4]
+ array[(-2...1).step(-4)].should == [4]
+
+ array[(4..-5).step(-1)].should == [4, 3, 2, 1]
+ array[(4..-5).step(-2)].should == [4, 2]
+ array[(4..-5).step(-3)].should == [4, 1]
+ array[(4..-5).step(-4)].should == [4]
+ array[(4..-5).step(-5)].should == [4]
+
+ array[(4...-5).step(-1)].should == [4, 3, 2]
+ array[(4...-5).step(-2)].should == [4, 2]
+ array[(4...-5).step(-3)].should == [4]
+ array[(4...-5).step(-4)].should == [4]
+
+ array[(-2..-5).step(-1)].should == [4, 3, 2, 1]
+ array[(-2..-5).step(-2)].should == [4, 2]
+ array[(-2..-5).step(-3)].should == [4, 1]
+ array[(-2..-5).step(-4)].should == [4]
+ array[(-2..-5).step(-5)].should == [4]
+
+ array[(-2...-5).step(-1)].should == [4, 3, 2]
+ array[(-2...-5).step(-2)].should == [4, 2]
+ array[(-2...-5).step(-3)].should == [4]
+ array[(-2...-5).step(-4)].should == [4]
+ end
+ end
+
+ it "can accept nil...nil ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a[eval("(nil...nil)")].should == a
+ a[(...nil)].should == a
+ a[eval("(nil..)")].should == a
+ end
end
describe "Array.[]" do
@@ -39,12 +892,12 @@ describe "Array.[]" do
end
it "returns an instance of the subclass" do
- ArraySpecs::MyArray[1, 2, 3].should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, 2, 3].should.instance_of?(ArraySpecs::MyArray)
end
it "does not call #initialize on the subclass instance" do
ArraySpecs::MyArray[1, 2, 3].should == [1, 2, 3]
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
end
diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb
index df5ca9582e..671e4338de 100644
--- a/spec/ruby/core/array/element_set_spec.rb
+++ b/spec/ruby/core/array/element_set_spec.rb
@@ -95,8 +95,8 @@ describe "Array#[]=" do
it "checks frozen before attempting to coerce arguments" do
a = [1,2,3,4].freeze
- -> {a[:foo] = 1}.should raise_error(FrozenError)
- -> {a[:foo, :bar] = 1}.should raise_error(FrozenError)
+ -> {a[:foo] = 1}.should.raise(FrozenError)
+ -> {a[:foo, :bar] = 1}.should.raise(FrozenError)
end
it "sets elements in the range arguments when passed ranges" do
@@ -197,25 +197,25 @@ describe "Array#[]=" do
a[to .. from] = ["x"]
a.should == [1, "a", "b", "x", "c", 4]
- -> { a["a" .. "b"] = [] }.should raise_error(TypeError)
- -> { a[from .. "b"] = [] }.should raise_error(TypeError)
+ -> { a["a" .. "b"] = [] }.should.raise(TypeError)
+ -> { a[from .. "b"] = [] }.should.raise(TypeError)
end
it "raises an IndexError when passed indexes out of bounds" do
a = [1, 2, 3, 4]
- -> { a[-5] = "" }.should raise_error(IndexError)
- -> { a[-5, -1] = "" }.should raise_error(IndexError)
- -> { a[-5, 0] = "" }.should raise_error(IndexError)
- -> { a[-5, 1] = "" }.should raise_error(IndexError)
- -> { a[-5, 2] = "" }.should raise_error(IndexError)
- -> { a[-5, 10] = "" }.should raise_error(IndexError)
-
- -> { a[-5..-5] = "" }.should raise_error(RangeError)
- -> { a[-5...-5] = "" }.should raise_error(RangeError)
- -> { a[-5..-4] = "" }.should raise_error(RangeError)
- -> { a[-5...-4] = "" }.should raise_error(RangeError)
- -> { a[-5..10] = "" }.should raise_error(RangeError)
- -> { a[-5...10] = "" }.should raise_error(RangeError)
+ -> { a[-5] = "" }.should.raise(IndexError)
+ -> { a[-5, -1] = "" }.should.raise(IndexError)
+ -> { a[-5, 0] = "" }.should.raise(IndexError)
+ -> { a[-5, 1] = "" }.should.raise(IndexError)
+ -> { a[-5, 2] = "" }.should.raise(IndexError)
+ -> { a[-5, 10] = "" }.should.raise(IndexError)
+
+ -> { a[-5..-5] = "" }.should.raise(RangeError)
+ -> { a[-5...-5] = "" }.should.raise(RangeError)
+ -> { a[-5..-4] = "" }.should.raise(RangeError)
+ -> { a[-5...-4] = "" }.should.raise(RangeError)
+ -> { a[-5..10] = "" }.should.raise(RangeError)
+ -> { a[-5...10] = "" }.should.raise(RangeError)
# ok
a[0..-9] = [1]
@@ -239,7 +239,7 @@ describe "Array#[]=" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array[0, 0] = [] }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array[0, 0] = [] }.should.raise(FrozenError)
end
end
@@ -349,12 +349,12 @@ describe "Array#[]= with [index, count]" do
it "raises an IndexError when passed start and negative length" do
a = [1, 2, 3, 4]
- -> { a[-2, -1] = "" }.should raise_error(IndexError)
- -> { a[0, -1] = "" }.should raise_error(IndexError)
- -> { a[2, -1] = "" }.should raise_error(IndexError)
- -> { a[4, -1] = "" }.should raise_error(IndexError)
- -> { a[10, -1] = "" }.should raise_error(IndexError)
- -> { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should raise_error(IndexError)
+ -> { a[-2, -1] = "" }.should.raise(IndexError)
+ -> { a[0, -1] = "" }.should.raise(IndexError)
+ -> { a[2, -1] = "" }.should.raise(IndexError)
+ -> { a[4, -1] = "" }.should.raise(IndexError)
+ -> { a[10, -1] = "" }.should.raise(IndexError)
+ -> { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should.raise(IndexError)
end
end
diff --git a/spec/ruby/core/array/eql_spec.rb b/spec/ruby/core/array/eql_spec.rb
index 8565b94c60..9a7447c2e8 100644
--- a/spec/ruby/core/array/eql_spec.rb
+++ b/spec/ruby/core/array/eql_spec.rb
@@ -6,7 +6,7 @@ describe "Array#eql?" do
it_behaves_like :array_eql, :eql?
it "returns false if any corresponding elements are not #eql?" do
- [1, 2, 3, 4].should_not eql([1, 2, 3, 4.0])
+ [1, 2, 3, 4].should_not.eql?([1, 2, 3, 4.0])
end
it "returns false if other is not a kind of Array" do
@@ -14,6 +14,6 @@ describe "Array#eql?" do
obj.should_not_receive(:to_ary)
obj.should_not_receive(:eql?)
- [1, 2, 3].should_not eql(obj)
+ [1, 2, 3].should_not.eql?(obj)
end
end
diff --git a/spec/ruby/core/array/equal_value_spec.rb b/spec/ruby/core/array/equal_value_spec.rb
index a82e07b218..4f7c0ce5e3 100644
--- a/spec/ruby/core/array/equal_value_spec.rb
+++ b/spec/ruby/core/array/equal_value_spec.rb
@@ -10,17 +10,17 @@ describe "Array#==" do
obj.should_receive(:respond_to?).at_least(1).with(:to_ary).and_return(true)
obj.should_receive(:==).with([1]).at_least(1).and_return(true)
- ([1] == obj).should be_true
- ([[1]] == [obj]).should be_true
- ([[[1], 3], 2] == [[obj, 3], 2]).should be_true
+ ([1] == obj).should == true
+ ([[1]] == [obj]).should == true
+ ([[[1], 3], 2] == [[obj, 3], 2]).should == true
# recursive arrays
arr1 = [[1]]
arr1 << arr1
arr2 = [obj]
arr2 << arr2
- (arr1 == arr2).should be_true
- (arr2 == arr1).should be_true
+ (arr1 == arr2).should == true
+ (arr2 == arr1).should == true
end
it "returns false if any corresponding elements are not #==" do
diff --git a/spec/ruby/core/array/fetch_spec.rb b/spec/ruby/core/array/fetch_spec.rb
index b81c0b48d7..ee94cfcbb2 100644
--- a/spec/ruby/core/array/fetch_spec.rb
+++ b/spec/ruby/core/array/fetch_spec.rb
@@ -12,9 +12,9 @@ describe "Array#fetch" do
end
it "raises an IndexError if there is no element at index" do
- -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError)
- -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError)
- -> { [].fetch(0) }.should raise_error(IndexError)
+ -> { [1, 2, 3].fetch(3) }.should.raise(IndexError, "index 3 outside of array bounds: -3...3")
+ -> { [1, 2, 3].fetch(-4) }.should.raise(IndexError, "index -4 outside of array bounds: -3...3")
+ -> { [].fetch(0) }.should.raise(IndexError, "index 0 outside of array bounds: 0...0")
end
it "returns default if there is no element at index if passed a default value" do
@@ -33,7 +33,7 @@ describe "Array#fetch" do
o = mock('5')
def o.to_int(); 5; end
- [1, 2, 3].fetch(o) { |i| i }.should equal(o)
+ [1, 2, 3].fetch(o) { |i| i }.should.equal?(o)
end
it "gives precedence to the default block over the default argument" do
@@ -50,6 +50,6 @@ describe "Array#fetch" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch("cat") }.should raise_error(TypeError)
+ -> { [].fetch("cat") }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
end
diff --git a/spec/ruby/core/array/fetch_values_spec.rb b/spec/ruby/core/array/fetch_values_spec.rb
index 075dcc7a52..237d6ad7f7 100644
--- a/spec/ruby/core/array/fetch_values_spec.rb
+++ b/spec/ruby/core/array/fetch_values_spec.rb
@@ -21,7 +21,7 @@ describe "Array#fetch_values" do
describe "with unmatched indexes" do
it "raises a index error if no block is provided" do
- -> { @array.fetch_values(0, 1, 44) }.should raise_error(IndexError)
+ -> { @array.fetch_values(0, 1, 44) }.should.raise(IndexError, "index 44 outside of array bounds: -3...3")
end
it "returns the default value from block" do
@@ -42,8 +42,14 @@ describe "Array#fetch_values" do
@array.fetch_values(obj).should == [:c]
end
+ it "does not support a Range object as argument" do
+ -> {
+ @array.fetch_values(1..2)
+ }.should.raise(TypeError, "no implicit conversion of Range into Integer")
+ end
+
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch_values("cat") }.should raise_error(TypeError)
+ -> { [].fetch_values("cat") }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
end
end
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index 2c3b5d9e84..e4d51bd998 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -10,7 +10,7 @@ describe "Array#fill" do
it "returns self" do
ary = [1, 2, 3]
- ary.fill(:a).should equal(ary)
+ ary.fill(:a).should.equal?(ary)
end
it "is destructive" do
@@ -25,10 +25,10 @@ describe "Array#fill" do
ary.fill(str).should == [str, str, str, str]
str << "y"
ary.should == [str, str, str, str]
- ary[0].should equal(str)
- ary[1].should equal(str)
- ary[2].should equal(str)
- ary[3].should equal(str)
+ ary[0].should.equal?(str)
+ ary[1].should.equal?(str)
+ ary[2].should.equal?(str)
+ ary[3].should.equal?(str)
end
it "replaces all elements in the array with the filler if not given a index nor a length" do
@@ -44,29 +44,29 @@ describe "Array#fill" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.fill('x') }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.fill('x') }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.fill('x') }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.fill('x') }.should.raise(FrozenError)
end
it "raises an ArgumentError if 4 or more arguments are passed when no block given" do
[].fill('a').should == []
[].fill('a', 1).should == []
[].fill('a', 1, 2).should == [nil, 'a', 'a']
- -> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError)
+ -> { [].fill('a', 1, 2, true) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if no argument passed and no block given" do
- -> { [].fill }.should raise_error(ArgumentError)
+ -> { [].fill }.should.raise(ArgumentError)
end
it "raises an ArgumentError if 3 or more arguments are passed when a block given" do
[].fill() {|i|}.should == []
[].fill(1) {|i|}.should == []
[].fill(1, 2) {|i|}.should == [nil, nil, nil]
- -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
+ -> { [].fill(1, 2, true) {|i|} }.should.raise(ArgumentError)
end
it "does not truncate the array is the block raises an exception" do
@@ -237,24 +237,24 @@ describe "Array#fill with (filler, index, length)" do
end
it "raises a TypeError if the index is not numeric" do
- -> { [].fill 'a', true }.should raise_error(TypeError)
+ -> { [].fill 'a', true }.should.raise(TypeError)
obj = mock('nonnumeric')
- -> { [].fill('a', obj) }.should raise_error(TypeError)
+ -> { [].fill('a', obj) }.should.raise(TypeError)
end
it "raises a TypeError when the length is not numeric" do
- -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
- -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/)
- -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/)
+ -> { [1, 2, 3].fill("x", 1, "foo") }.should.raise(TypeError, /no implicit conversion of String into Integer/)
+ -> { [1, 2, 3].fill("x", 1, :"foo") }.should.raise(TypeError, /no implicit conversion of Symbol into Integer/)
+ -> { [1, 2, 3].fill("x", 1, Object.new) }.should.raise(TypeError, /no implicit conversion of Object into Integer/)
end
not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do
error_types = [RangeError, ArgumentError]
arr = [1, 2, 3]
- -> { arr.fill(10, 1, fixnum_max) }.should raise_error { |err| error_types.should include(err.class) }
- -> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError)
+ -> { arr.fill(10, 1, fixnum_max) }.should.raise { |err| error_types.should.include?(err.class) }
+ -> { arr.fill(10, 1, bignum_value) }.should.raise(RangeError)
end
end
end
@@ -284,7 +284,7 @@ describe "Array#fill with (filler, range)" do
end
it "raises a TypeError with range and length argument" do
- -> { [].fill('x', 0 .. 2, 5) }.should raise_error(TypeError)
+ -> { [].fill('x', 0 .. 2, 5) }.should.raise(TypeError)
end
it "replaces elements between the (-m)th to the last and the (n+1)th from the first if given an range m..n where m < 0 and n >= 0" do
@@ -336,13 +336,13 @@ describe "Array#fill with (filler, range)" do
end
it "raises an exception if some of the given range lies before the first of the array" do
- -> { [1, 2, 3].fill('x', -5..-3) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill('x', -5...-3) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill('x', -5..-4) }.should raise_error(RangeError)
+ -> { [1, 2, 3].fill('x', -5..-3) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill('x', -5...-3) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill('x', -5..-4) }.should.raise(RangeError)
- -> { [1, 2, 3].fill(-5..-3, &@never_passed) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill(-5...-3, &@never_passed) }.should raise_error(RangeError)
- -> { [1, 2, 3].fill(-5..-4, &@never_passed) }.should raise_error(RangeError)
+ -> { [1, 2, 3].fill(-5..-3, &@never_passed) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill(-5...-3, &@never_passed) }.should.raise(RangeError)
+ -> { [1, 2, 3].fill(-5..-4, &@never_passed) }.should.raise(RangeError)
end
it "tries to convert the start and end of the passed range to Integers using #to_int" do
@@ -357,7 +357,7 @@ describe "Array#fill with (filler, range)" do
it "raises a TypeError if the start or end of the passed range is not numeric" do
obj = mock('nonnumeric')
def obj.<=>(rhs); rhs == self ? 0 : nil end
- -> { [].fill('a', obj..obj) }.should raise_error(TypeError)
+ -> { [].fill('a', obj..obj) }.should.raise(TypeError)
end
it "works with endless ranges" do
diff --git a/spec/ruby/core/array/filter_spec.rb b/spec/ruby/core/array/filter_spec.rb
index 156ad14f9c..6ebda61069 100644
--- a/spec/ruby/core/array/filter_spec.rb
+++ b/spec/ruby/core/array/filter_spec.rb
@@ -1,14 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
describe "Array#filter" do
- it_behaves_like :array_select, :filter
+ it "is an alias of Array#select" do
+ Array.instance_method(:filter).should == Array.instance_method(:select)
+ end
end
describe "Array#filter!" do
- it "returns nil if no changes were made in the array" do
- [1, 2, 3].filter! { true }.should be_nil
+ it "is an alias of Array#select!" do
+ Array.instance_method(:filter!).should == Array.instance_method(:select!)
end
-
- it_behaves_like :keep_if, :filter!
end
diff --git a/spec/ruby/core/array/find_index_spec.rb b/spec/ruby/core/array/find_index_spec.rb
index 759472024a..17ff6c04a7 100644
--- a/spec/ruby/core/array/find_index_spec.rb
+++ b/spec/ruby/core/array/find_index_spec.rb
@@ -1,6 +1,42 @@
require_relative '../../spec_helper'
-require_relative 'shared/index'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#find_index" do
- it_behaves_like :array_index, :find_index
+ it "returns the index of the first element == to object" do
+ x = mock('3')
+ def x.==(obj) 3 == obj; end
+
+ [2, x, 3, 1, 3, 1].find_index(3).should == 1
+ [2, 3.0, 3, x, 1, 3, 1].find_index(x).should == 1
+ end
+
+ it "returns 0 if first element == to object" do
+ [2, 1, 3, 2, 5].find_index(2).should == 0
+ end
+
+ it "returns size-1 if only last element == to object" do
+ [2, 1, 3, 1, 5].find_index(5).should == 4
+ end
+
+ it "returns nil if no element == to object" do
+ [2, 1, 1, 1, 1].find_index(3).should == nil
+ end
+
+ it "accepts a block instead of an argument" do
+ [4, 2, 1, 5, 1, 3].find_index {|x| x < 2}.should == 2
+ end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ [4, 2, 1, 5, 1, 3].find_index(5) {|x| x < 2}.should == 3
+ }.should complain(/given block not used/)
+ end
+
+ describe "given no argument and no block" do
+ it "produces an Enumerator" do
+ [].find_index.should.instance_of?(Enumerator)
+ end
+ end
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :find_index
end
diff --git a/spec/ruby/core/array/first_spec.rb b/spec/ruby/core/array/first_spec.rb
index 66eeba6565..2c343ac8f6 100644
--- a/spec/ruby/core/array/first_spec.rb
+++ b/spec/ruby/core/array/first_spec.rb
@@ -30,11 +30,11 @@ describe "Array#first" do
end
it "raises an ArgumentError when count is negative" do
- -> { [1, 2].first(-1) }.should raise_error(ArgumentError)
+ -> { [1, 2].first(-1) }.should.raise(ArgumentError)
end
it "raises a RangeError when count is a Bignum" do
- -> { [].first(bignum_value) }.should raise_error(RangeError)
+ -> { [].first(bignum_value) }.should.raise(RangeError)
end
it "returns the entire array when count > length" do
@@ -53,10 +53,10 @@ describe "Array#first" do
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- empty.first.should equal(empty)
+ empty.first.should.equal?(empty)
ary = ArraySpecs.head_recursive_array
- ary.first.should equal(ary)
+ ary.first.should.equal?(ary)
end
it "tries to convert the passed argument to an Integer using #to_int" do
@@ -66,19 +66,19 @@ describe "Array#first" do
end
it "raises a TypeError if the passed argument is not numeric" do
- -> { [1,2].first(nil) }.should raise_error(TypeError)
- -> { [1,2].first("a") }.should raise_error(TypeError)
+ -> { [1,2].first(nil) }.should.raise(TypeError)
+ -> { [1,2].first("a") }.should.raise(TypeError)
obj = mock("nonnumeric")
- -> { [1,2].first(obj) }.should raise_error(TypeError)
+ -> { [1,2].first(obj) }.should.raise(TypeError)
end
it "does not return subclass instance when passed count on Array subclasses" do
- ArraySpecs::MyArray[].first(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[].first(2).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].first(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].first(1).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].first(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[].first(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[].first(2).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].first(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].first(1).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].first(2).should.instance_of?(Array)
end
it "is not destructive" do
diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb
index 8c97000c79..272406b8f9 100644
--- a/spec/ruby/core/array/flatten_spec.rb
+++ b/spec/ruby/core/array/flatten_spec.rb
@@ -13,7 +13,7 @@ describe "Array#flatten" do
it "returns dup when the level of recursion is 0" do
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten(0).should == a
- a.flatten(0).should_not equal(a)
+ a.flatten(0).should_not.equal?(a)
end
it "ignores negative levels" do
@@ -30,7 +30,7 @@ describe "Array#flatten" do
it "raises a TypeError when the passed Object can't be converted to an Integer" do
obj = mock("Not converted")
- -> { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should raise_error(TypeError)
+ -> { [ 1, 2, [3, [4, 5] ] ].flatten(obj) }.should.raise(TypeError)
end
it "does not call flatten on elements" do
@@ -46,13 +46,13 @@ describe "Array#flatten" do
it "raises an ArgumentError on recursive arrays" do
x = []
x << x
- -> { x.flatten }.should raise_error(ArgumentError)
+ -> { x.flatten }.should.raise(ArgumentError)
x = []
y = []
x << y
y << x
- -> { x.flatten }.should raise_error(ArgumentError)
+ -> { x.flatten }.should.raise(ArgumentError)
end
it "flattens any element which responds to #to_ary, using the return value of said method" do
@@ -76,11 +76,11 @@ describe "Array#flatten" do
end
it "returns Array instance for Array subclasses" do
- ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[].flatten.should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should.instance_of?(Array)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should.instance_of?(Array)
ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
- [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should.instance_of?(Array)
end
it "is not destructive" do
@@ -106,7 +106,7 @@ describe "Array#flatten" do
it "raises a TypeError if #to_ary does not return an Array" do
@obj.should_receive(:to_ary).and_return(1)
- -> { [@obj].flatten }.should raise_error(TypeError)
+ -> { [@obj].flatten }.should.raise(TypeError)
end
it "calls respond_to_missing?(:to_ary, true) to try coercing" do
@@ -125,7 +125,7 @@ describe "Array#flatten" do
it "calls #to_ary if not defined when #respond_to_missing? returns true" do
def @obj.respond_to_missing?(name, priv) ScratchPad << name; true end
- -> { [@obj].flatten }.should raise_error(NoMethodError)
+ -> { [@obj].flatten }.should.raise(NoMethodError)
ScratchPad.recorded.should == [:to_ary]
end
@@ -168,7 +168,7 @@ describe "Array#flatten!" do
it "returns self if made some modifications" do
a = [[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []]
- a.flatten!.should equal(a)
+ a.flatten!.should.equal?(a)
end
it "returns nil if no modifications took place" do
@@ -208,7 +208,7 @@ describe "Array#flatten!" do
it "raises a TypeError when the passed Object can't be converted to an Integer" do
obj = mock("Not converted")
- -> { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should raise_error(TypeError)
+ -> { [ 1, 2, [3, [4, 5] ] ].flatten!(obj) }.should.raise(TypeError)
end
it "does not call flatten! on elements" do
@@ -224,13 +224,13 @@ describe "Array#flatten!" do
it "raises an ArgumentError on recursive arrays" do
x = []
x << x
- -> { x.flatten! }.should raise_error(ArgumentError)
+ -> { x.flatten! }.should.raise(ArgumentError)
x = []
y = []
x << y
y << x
- -> { x.flatten! }.should raise_error(ArgumentError)
+ -> { x.flatten! }.should.raise(ArgumentError)
end
it "flattens any elements which responds to #to_ary, using the return value of said method" do
@@ -248,19 +248,19 @@ describe "Array#flatten!" do
ary = [ArraySpecs::MyArray[1, 2, 3]]
ary.flatten!
- ary.should be_an_instance_of(Array)
+ ary.should.instance_of?(Array)
ary.should == [1, 2, 3]
end
it "raises a FrozenError on frozen arrays when the array is modified" do
nested_ary = [1, 2, []]
nested_ary.freeze
- -> { nested_ary.flatten! }.should raise_error(FrozenError)
+ -> { nested_ary.flatten! }.should.raise(FrozenError)
end
# see [ruby-core:23663]
it "raises a FrozenError on frozen arrays when the array would not be modified" do
- -> { ArraySpecs.frozen_array.flatten! }.should raise_error(FrozenError)
- -> { ArraySpecs.empty_frozen_array.flatten! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.flatten! }.should.raise(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.flatten! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/hash_spec.rb b/spec/ruby/core/array/hash_spec.rb
index f3bcc83fce..3b7b6d5bed 100644
--- a/spec/ruby/core/array/hash_spec.rb
+++ b/spec/ruby/core/array/hash_spec.rb
@@ -7,16 +7,16 @@ describe "Array#hash" do
[[], [1, 2, 3]].each do |ary|
ary.hash.should == ary.dup.hash
- ary.hash.should be_an_instance_of(Integer)
+ ary.hash.should.instance_of?(Integer)
end
end
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- -> { empty.hash }.should_not raise_error
+ -> { empty.hash }.should_not.raise
array = ArraySpecs.recursive_array
- -> { array.hash }.should_not raise_error
+ -> { array.hash }.should_not.raise
end
it "returns the same hash for equal recursive arrays" do
@@ -74,7 +74,7 @@ describe "Array#hash" do
a.fill 'a', 0..3
b = %w|a a a a|
a.hash.should == b.hash
- a.should eql(b)
+ a.should.eql?(b)
end
it "produces different hashes for nested arrays with different values and empty terminator" do
diff --git a/spec/ruby/core/array/index_spec.rb b/spec/ruby/core/array/index_spec.rb
index 3acb7d0ef3..b66cb6eb53 100644
--- a/spec/ruby/core/array/index_spec.rb
+++ b/spec/ruby/core/array/index_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/index'
describe "Array#index" do
- it_behaves_like :array_index, :index
+ it "is an alias of Array#find_index" do
+ Array.instance_method(:index).should == Array.instance_method(:find_index)
+ end
end
diff --git a/spec/ruby/core/array/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb
index b9fa77b16e..19ee37825e 100644
--- a/spec/ruby/core/array/initialize_spec.rb
+++ b/spec/ruby/core/array/initialize_spec.rb
@@ -7,7 +7,7 @@ describe "Array#initialize" do
end
it "is private" do
- Array.should have_private_instance_method("initialize")
+ Array.private_instance_methods(false).should.include?(:initialize)
end
it "is called on subclasses" do
@@ -19,26 +19,26 @@ describe "Array#initialize" do
it "preserves the object's identity even when changing its value" do
a = [1, 2, 3]
- a.send(:initialize).should equal(a)
+ a.send(:initialize).should.equal?(a)
a.should_not == [1, 2, 3]
end
it "raises an ArgumentError if passed 3 or more arguments" do
-> do
[1, 2].send :initialize, 1, 'x', true
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[1, 2].send(:initialize, 1, 'x', true) {}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises a FrozenError on frozen arrays" do
-> do
ArraySpecs.frozen_array.send :initialize
- end.should raise_error(FrozenError)
+ end.should.raise(FrozenError)
-> do
ArraySpecs.frozen_array.send :initialize, ArraySpecs.frozen_array
- end.should raise_error(FrozenError)
+ end.should.raise(FrozenError)
end
it "calls #to_ary to convert the value to an array, even if it's private" do
@@ -49,12 +49,12 @@ end
describe "Array#initialize with no arguments" do
it "makes the array empty" do
- [1, 2, 3].send(:initialize).should be_empty
+ [1, 2, 3].send(:initialize).should.empty?
end
it "does not use the given block" do
-> {
- -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
+ -> { [1, 2, 3].send(:initialize) { raise } }.should_not.raise
}.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
end
end
@@ -66,7 +66,7 @@ describe "Array#initialize with (array)" do
end
it "does not use the given block" do
- ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
+ ->{ [1, 2, 3].send(:initialize) { raise } }.should_not.raise
end
it "calls #to_ary to convert the value to an array" do
@@ -83,7 +83,7 @@ describe "Array#initialize with (array)" do
end
it "raises a TypeError if an Array type argument and a default object" do
- -> { [].send(:initialize, [1, 2], 1) }.should raise_error(TypeError)
+ -> { [].send(:initialize, [1, 2], 1) }.should.raise(TypeError)
end
end
@@ -92,8 +92,8 @@ describe "Array#initialize with (size, object=nil)" do
a = []
obj = [3]
a.send(:initialize, 2, obj).should == [obj, obj]
- a[0].should equal(obj)
- a[1].should equal(obj)
+ a[0].should.equal?(obj)
+ a[1].should.equal?(obj)
b = []
b.send(:initialize, 3, 14).should == [14, 14, 14]
@@ -105,12 +105,12 @@ describe "Array#initialize with (size, object=nil)" do
end
it "raises an ArgumentError if size is negative" do
- -> { [].send(:initialize, -1, :a) }.should raise_error(ArgumentError)
- -> { [].send(:initialize, -1) }.should raise_error(ArgumentError)
+ -> { [].send(:initialize, -1, :a) }.should.raise(ArgumentError)
+ -> { [].send(:initialize, -1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if size is too large" do
- -> { [].send(:initialize, fixnum_max+1) }.should raise_error(ArgumentError)
+ -> { [].send(:initialize, fixnum_max+1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the size argument to an Integer when object is given" do
@@ -128,7 +128,7 @@ describe "Array#initialize with (size, object=nil)" do
it "raises a TypeError if the size argument is not an Integer type" do
obj = mock('nonnumeric')
obj.stub!(:to_ary).and_return([1, 2])
- ->{ [].send(:initialize, obj, :a) }.should raise_error(TypeError)
+ ->{ [].send(:initialize, obj, :a) }.should.raise(TypeError)
end
it "yields the index of the element and sets the element to the value of the block" do
diff --git a/spec/ruby/core/array/insert_spec.rb b/spec/ruby/core/array/insert_spec.rb
index 9e1757f68b..38e132fd25 100644
--- a/spec/ruby/core/array/insert_spec.rb
+++ b/spec/ruby/core/array/insert_spec.rb
@@ -4,8 +4,8 @@ require_relative 'fixtures/classes'
describe "Array#insert" do
it "returns self" do
ary = []
- ary.insert(0).should equal(ary)
- ary.insert(0, :a).should equal(ary)
+ ary.insert(0).should.equal?(ary)
+ ary.insert(0, :a).should.equal?(ary)
end
it "inserts objects before the element at index for non-negative index" do
@@ -46,8 +46,8 @@ describe "Array#insert" do
end
it "raises an IndexError if the negative index is out of bounds" do
- -> { [].insert(-2, 1) }.should raise_error(IndexError)
- -> { [1].insert(-3, 2) }.should raise_error(IndexError)
+ -> { [].insert(-2, 1) }.should.raise(IndexError)
+ -> { [1].insert(-3, 2) }.should.raise(IndexError)
end
it "does nothing of no object is passed" do
@@ -64,15 +64,15 @@ describe "Array#insert" do
end
it "raises an ArgumentError if no argument passed" do
- -> { [].insert() }.should raise_error(ArgumentError)
+ -> { [].insert() }.should.raise(ArgumentError)
end
it "raises a FrozenError on frozen arrays when the array is modified" do
- -> { ArraySpecs.frozen_array.insert(0, 'x') }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.insert(0, 'x') }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on frozen arrays when the array would not be modified" do
- -> { ArraySpecs.frozen_array.insert(0) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.insert(0) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/inspect_spec.rb b/spec/ruby/core/array/inspect_spec.rb
index 0832224f5a..e5dca82889 100644
--- a/spec/ruby/core/array/inspect_spec.rb
+++ b/spec/ruby/core/array/inspect_spec.rb
@@ -1,7 +1,108 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/inspect'
describe "Array#inspect" do
- it_behaves_like :array_inspect, :inspect
+ it "returns a string" do
+ [1, 2, 3].inspect.should.instance_of?(String)
+ end
+
+ it "returns '[]' for an empty Array" do
+ [].inspect.should == "[]"
+ end
+
+ it "calls inspect on its elements and joins the results with commas" do
+ items = Array.new(3) do |i|
+ obj = mock(i.to_s)
+ obj.should_receive(:inspect).and_return(i.to_s)
+ obj
+ end
+ items.inspect.should == "[0, 1, 2]"
+ end
+
+ it "does not call #to_s on a String returned from #inspect" do
+ str = +"abc"
+ str.should_not_receive(:to_s)
+
+ [str].inspect.should == '["abc"]'
+ end
+
+ it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
+ obj = mock("Array#inspect/to_s calls #to_s")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_return("abc")
+
+ [obj].inspect.should == "[abc]"
+ end
+
+ it "does not call #to_str on the object returned from #inspect when it is not a String" do
+ obj = mock("Array#inspect/to_s does not call #to_str")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_not_receive(:to_str)
+
+ [obj].inspect.should =~ /^\[#<MockObject:0x[0-9a-f]+>\]$/
+ end
+
+ it "does not call #to_str on the object returned from #to_s when it is not a String" do
+ obj = mock("Array#inspect/to_s does not call #to_str on #to_s result")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_return(obj)
+ obj.should_not_receive(:to_str)
+
+ [obj].inspect.should =~ /^\[#<MockObject:0x[0-9a-f]+>\]$/
+ end
+
+ it "does not swallow exceptions raised by #to_s" do
+ obj = mock("Array#inspect/to_s does not swallow #to_s exceptions")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_raise(Exception)
+
+ -> { [obj].inspect }.should.raise(Exception)
+ end
+
+ it "represents a recursive element with '[...]'" do
+ ArraySpecs.recursive_array.inspect.should == "[1, \"two\", 3.0, [...], [...], [...], [...], [...]]"
+ ArraySpecs.head_recursive_array.inspect.should == "[[...], [...], [...], [...], [...], 1, \"two\", 3.0]"
+ ArraySpecs.empty_recursive_array.inspect.should == "[[...]]"
+ end
+
+ describe "with encoding" do
+ before :each do
+ @default_external_encoding = Encoding.default_external
+ end
+
+ after :each do
+ Encoding.default_external = @default_external_encoding
+ end
+
+ it "returns a US-ASCII string for an empty Array" do
+ [].inspect.encoding.should == Encoding::US_ASCII
+ end
+
+ it "use the default external encoding if it is ascii compatible" do
+ Encoding.default_external = Encoding.find('UTF-8')
+
+ utf8 = "utf8".encode("UTF-8")
+ jp = "jp".encode("EUC-JP")
+ array = [jp, utf8]
+
+ array.inspect.encoding.name.should == "UTF-8"
+ end
+
+ it "use US-ASCII encoding if the default external encoding is not ascii compatible" do
+ Encoding.default_external = Encoding.find('UTF-32')
+
+ utf8 = "utf8".encode("UTF-8")
+ jp = "jp".encode("EUC-JP")
+ array = [jp, utf8]
+
+ array.inspect.encoding.name.should == "US-ASCII"
+ end
+
+ it "does not raise if inspected result is not default external encoding" do
+ utf_16be = mock(+"utf_16be")
+ utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
+
+ [utf_16be].inspect.should == '["utf_16be \u3042"]'
+ end
+ end
end
diff --git a/spec/ruby/core/array/join_spec.rb b/spec/ruby/core/array/join_spec.rb
index e78ea6f9e1..3b4946a99f 100644
--- a/spec/ruby/core/array/join_spec.rb
+++ b/spec/ruby/core/array/join_spec.rb
@@ -4,7 +4,6 @@ require_relative 'shared/join'
describe "Array#join" do
it_behaves_like :array_join_with_string_separator, :join
- it_behaves_like :array_join_with_default_separator, :join
it "does not separate elements when the passed separator is nil" do
[1, 2, 3].join(nil).should == '123'
@@ -24,11 +23,108 @@ describe "Array#join" do
it "raises a TypeError if the separator cannot be coerced to a String by calling #to_str" do
obj = mock("not a string")
- -> { [1, 2].join(obj) }.should raise_error(TypeError)
+ -> { [1, 2].join(obj) }.should.raise(TypeError)
end
it "raises a TypeError if passed false as the separator" do
- -> { [1, 2].join(false) }.should raise_error(TypeError)
+ -> { [1, 2].join(false) }.should.raise(TypeError)
+ end
+end
+
+describe "Array#join with default separator" do
+ before :each do
+ @separator = $,
+ end
+
+ after :each do
+ $, = @separator
+ end
+
+ it "returns an empty string if the Array is empty" do
+ [].join.should == ''
+ end
+
+ it "returns a US-ASCII string for an empty Array" do
+ [].join.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns a string formed by concatenating each String element separated by $," do
+ suppress_warning {
+ $, = " | "
+ ["1", "2", "3"].join.should == "1 | 2 | 3"
+ }
+ end
+
+ it "attempts coercion via #to_str first" do
+ obj = mock('foo')
+ obj.should_receive(:to_str).any_number_of_times.and_return("foo")
+ [obj].join.should == "foo"
+ end
+
+ it "attempts coercion via #to_ary second" do
+ obj = mock('foo')
+ obj.should_receive(:to_str).any_number_of_times.and_return(nil)
+ obj.should_receive(:to_ary).any_number_of_times.and_return(["foo"])
+ [obj].join.should == "foo"
+ end
+
+ it "attempts coercion via #to_s third" do
+ obj = mock('foo')
+ obj.should_receive(:to_str).any_number_of_times.and_return(nil)
+ obj.should_receive(:to_ary).any_number_of_times.and_return(nil)
+ obj.should_receive(:to_s).any_number_of_times.and_return("foo")
+ [obj].join.should == "foo"
+ end
+
+ it "raises a NoMethodError if an element does not respond to #to_str, #to_ary, or #to_s" do
+ obj = mock('o')
+ class << obj; undef :to_s; end
+ -> { [1, obj].join }.should.raise(NoMethodError)
+ end
+
+ it "raises an ArgumentError when the Array is recursive" do
+ -> { ArraySpecs.recursive_array.join }.should.raise(ArgumentError)
+ -> { ArraySpecs.head_recursive_array.join }.should.raise(ArgumentError)
+ -> { ArraySpecs.empty_recursive_array.join }.should.raise(ArgumentError)
+ end
+
+ it "uses the first encoding when other strings are compatible" do
+ ary1 = ArraySpecs.array_with_7bit_utf8_and_usascii_strings
+ ary2 = ArraySpecs.array_with_usascii_and_7bit_utf8_strings
+ ary3 = ArraySpecs.array_with_utf8_and_7bit_binary_strings
+ ary4 = ArraySpecs.array_with_usascii_and_7bit_binary_strings
+
+ ary1.join.encoding.should == Encoding::UTF_8
+ ary2.join.encoding.should == Encoding::US_ASCII
+ ary3.join.encoding.should == Encoding::UTF_8
+ ary4.join.encoding.should == Encoding::US_ASCII
+ end
+
+ it "uses the widest common encoding when other strings are incompatible" do
+ ary1 = ArraySpecs.array_with_utf8_and_usascii_strings
+ ary2 = ArraySpecs.array_with_usascii_and_utf8_strings
+
+ ary1.join.encoding.should == Encoding::UTF_8
+ ary2.join.encoding.should == Encoding::UTF_8
+ end
+
+ it "fails for arrays with incompatibly-encoded strings" do
+ ary_utf8_bad_binary = ArraySpecs.array_with_utf8_and_binary_strings
+
+ -> { ary_utf8_bad_binary.join }.should.raise(EncodingError)
+ end
+
+ context "when $, is not nil" do
+ before do
+ suppress_warning do
+ $, = '*'
+ end
+ end
+
+ it "warns" do
+ -> { [].join }.should complain(/warning: \$, is set to non-nil value/)
+ -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/)
+ end
end
end
diff --git a/spec/ruby/core/array/keep_if_spec.rb b/spec/ruby/core/array/keep_if_spec.rb
index 40f7329b7c..62a65a04e8 100644
--- a/spec/ruby/core/array/keep_if_spec.rb
+++ b/spec/ruby/core/array/keep_if_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/keep_if'
describe "Array#keep_if" do
it "returns the same array if no changes were made" do
array = [1, 2, 3]
- array.keep_if { true }.should equal(array)
+ array.keep_if { true }.should.equal?(array)
end
it_behaves_like :keep_if, :keep_if
diff --git a/spec/ruby/core/array/last_spec.rb b/spec/ruby/core/array/last_spec.rb
index d6fefada09..ed417bcd2a 100644
--- a/spec/ruby/core/array/last_spec.rb
+++ b/spec/ruby/core/array/last_spec.rb
@@ -28,7 +28,7 @@ describe "Array#last" do
end
it "raises an ArgumentError when count is negative" do
- -> { [1, 2].last(-1) }.should raise_error(ArgumentError)
+ -> { [1, 2].last(-1) }.should.raise(ArgumentError)
end
it "returns the entire array when count > length" do
@@ -47,10 +47,10 @@ describe "Array#last" do
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- empty.last.should equal(empty)
+ empty.last.should.equal?(empty)
array = ArraySpecs.recursive_array
- array.last.should equal(array)
+ array.last.should.equal?(array)
end
it "tries to convert the passed argument to an Integer using #to_int" do
@@ -60,19 +60,19 @@ describe "Array#last" do
end
it "raises a TypeError if the passed argument is not numeric" do
- -> { [1,2].last(nil) }.should raise_error(TypeError)
- -> { [1,2].last("a") }.should raise_error(TypeError)
+ -> { [1,2].last(nil) }.should.raise(TypeError)
+ -> { [1,2].last("a") }.should.raise(TypeError)
obj = mock("nonnumeric")
- -> { [1,2].last(obj) }.should raise_error(TypeError)
+ -> { [1,2].last(obj) }.should.raise(TypeError)
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[].last(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[].last(2).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].last(0).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].last(1).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].last(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[].last(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[].last(2).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].last(0).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].last(1).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].last(2).should.instance_of?(Array)
end
it "is not destructive" do
diff --git a/spec/ruby/core/array/length_spec.rb b/spec/ruby/core/array/length_spec.rb
index a90c001300..74b2eb3a08 100644
--- a/spec/ruby/core/array/length_spec.rb
+++ b/spec/ruby/core/array/length_spec.rb
@@ -1,7 +1,14 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Array#length" do
- it_behaves_like :array_length, :length
+ it "returns the number of elements" do
+ [].length.should == 0
+ [1, 2, 3].length.should == 3
+ end
+
+ it "properly handles recursive arrays" do
+ ArraySpecs.empty_recursive_array.length.should == 1
+ ArraySpecs.recursive_array.length.should == 8
+ end
end
diff --git a/spec/ruby/core/array/map_spec.rb b/spec/ruby/core/array/map_spec.rb
index 0c7f3afa8c..f5e88c8624 100644
--- a/spec/ruby/core/array/map_spec.rb
+++ b/spec/ruby/core/array/map_spec.rb
@@ -1,11 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/collect'
describe "Array#map" do
- it_behaves_like :array_collect, :map
+ it "is an alias of Array#collect" do
+ Array.instance_method(:map).should == Array.instance_method(:collect)
+ end
end
describe "Array#map!" do
- it_behaves_like :array_collect_b, :map!
+ it "is an alias of Array#collect!" do
+ Array.instance_method(:map!).should == Array.instance_method(:collect!)
+ end
end
diff --git a/spec/ruby/core/array/max_spec.rb b/spec/ruby/core/array/max_spec.rb
index d1c64519d0..868275a748 100644
--- a/spec/ruby/core/array/max_spec.rb
+++ b/spec/ruby/core/array/max_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Array#max" do
it "is defined on Array" do
- [1].method(:max).owner.should equal Array
+ [1].method(:max).owner.should.equal? Array
end
it "returns nil with no values" do
@@ -70,16 +70,16 @@ describe "Array#max" do
it "raises a NoMethodError for elements without #<=>" do
-> do
[BasicObject.new, BasicObject.new].max
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
[11,"22"].max
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[11,12,22,33].max{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns the maximum element (with block)" do
diff --git a/spec/ruby/core/array/min_spec.rb b/spec/ruby/core/array/min_spec.rb
index 3bdef0dd00..5913e08cf8 100644
--- a/spec/ruby/core/array/min_spec.rb
+++ b/spec/ruby/core/array/min_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Array#min" do
it "is defined on Array" do
- [1].method(:max).owner.should equal Array
+ [1].method(:max).owner.should.equal? Array
end
it "returns nil with no values" do
@@ -64,22 +64,22 @@ describe "Array#min" do
end
it "returns nil for an empty Enumerable" do
- [].min.should be_nil
+ [].min.should == nil
end
it "raises a NoMethodError for elements without #<=>" do
-> do
[BasicObject.new, BasicObject.new].min
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
[11,"22"].min
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[11,12,22,33].min{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns the minimum when using a block rule" do
diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb
index eca51142fb..1ac14e1b09 100644
--- a/spec/ruby/core/array/multiply_spec.rb
+++ b/spec/ruby/core/array/multiply_spec.rb
@@ -17,7 +17,7 @@ describe "Array#*" do
it "raises a TypeError if the argument can neither be converted to a string nor an integer" do
obj = mock('not a string or integer')
- ->{ [1,2] * obj }.should raise_error(TypeError)
+ ->{ [1,2] * obj }.should.raise(TypeError)
end
it "converts the passed argument to a String rather than an Integer" do
@@ -28,15 +28,15 @@ describe "Array#*" do
end
it "raises a TypeError is the passed argument is nil" do
- ->{ [1,2] * nil }.should raise_error(TypeError)
+ ->{ [1,2] * nil }.should.raise(TypeError)
end
it "raises an ArgumentError when passed 2 or more arguments" do
- ->{ [1,2].send(:*, 1, 2) }.should raise_error(ArgumentError)
+ ->{ [1,2].send(:*, 1, 2) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed no arguments" do
- ->{ [1,2].send(:*) }.should raise_error(ArgumentError)
+ ->{ [1,2].send(:*) }.should.raise(ArgumentError)
end
end
@@ -50,7 +50,7 @@ describe "Array#* with an integer" do
it "does not return self even if the passed integer is 1" do
ary = [1, 2, 3]
- (ary * 1).should_not equal(ary)
+ (ary * 1).should_not.equal?(ary)
end
it "properly handles recursive arrays" do
@@ -65,8 +65,8 @@ describe "Array#* with an integer" do
end
it "raises an ArgumentError when passed a negative integer" do
- -> { [ 1, 2, 3 ] * -1 }.should raise_error(ArgumentError)
- -> { [] * -1 }.should raise_error(ArgumentError)
+ -> { [ 1, 2, 3 ] * -1 }.should.raise(ArgumentError)
+ -> { [] * -1 }.should.raise(ArgumentError)
end
describe "with a subclass of Array" do
@@ -77,14 +77,14 @@ describe "Array#* with an integer" do
end
it "returns an Array instance" do
- (@array * 0).should be_an_instance_of(Array)
- (@array * 1).should be_an_instance_of(Array)
- (@array * 2).should be_an_instance_of(Array)
+ (@array * 0).should.instance_of?(Array)
+ (@array * 1).should.instance_of?(Array)
+ (@array * 2).should.instance_of?(Array)
end
it "does not call #initialize on the subclass instance" do
(@array * 2).should == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
end
diff --git a/spec/ruby/core/array/new_spec.rb b/spec/ruby/core/array/new_spec.rb
index b50a4857b0..b2f23e2f6b 100644
--- a/spec/ruby/core/array/new_spec.rb
+++ b/spec/ruby/core/array/new_spec.rb
@@ -3,31 +3,31 @@ require_relative 'fixtures/classes'
describe "Array.new" do
it "returns an instance of Array" do
- Array.new.should be_an_instance_of(Array)
+ Array.new.should.instance_of?(Array)
end
it "returns an instance of a subclass" do
- ArraySpecs::MyArray.new(1, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray.new(1, 2).should.instance_of?(ArraySpecs::MyArray)
end
it "raises an ArgumentError if passed 3 or more arguments" do
-> do
[1, 2].send :initialize, 1, 'x', true
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
[1, 2].send(:initialize, 1, 'x', true) {}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Array.new with no arguments" do
it "returns an empty array" do
- Array.new.should be_empty
+ Array.new.should.empty?
end
it "does not use the given block" do
-> {
- -> { Array.new { raise } }.should_not raise_error
+ -> { Array.new { raise } }.should_not.raise
}.should complain(/warning: given block not used/, verbose: true)
end
end
@@ -39,7 +39,7 @@ describe "Array.new with (array)" do
end
it "does not use the given block" do
- ->{ Array.new([1, 2]) { raise } }.should_not raise_error
+ ->{ Array.new([1, 2]) { raise } }.should_not.raise
end
it "calls #to_ary to convert the value to an array" do
@@ -56,7 +56,7 @@ describe "Array.new with (array)" do
end
it "raises a TypeError if an Array type argument and a default object" do
- -> { Array.new([1, 2], 1) }.should raise_error(TypeError)
+ -> { Array.new([1, 2], 1) }.should.raise(TypeError)
end
end
@@ -65,8 +65,8 @@ describe "Array.new with (size, object=nil)" do
obj = [3]
a = Array.new(2, obj)
a.should == [obj, obj]
- a[0].should equal(obj)
- a[1].should equal(obj)
+ a[0].should.equal?(obj)
+ a[1].should.equal?(obj)
Array.new(3, 14).should == [14, 14, 14]
end
@@ -76,12 +76,12 @@ describe "Array.new with (size, object=nil)" do
end
it "raises an ArgumentError if size is negative" do
- -> { Array.new(-1, :a) }.should raise_error(ArgumentError)
- -> { Array.new(-1) }.should raise_error(ArgumentError)
+ -> { Array.new(-1, :a) }.should.raise(ArgumentError)
+ -> { Array.new(-1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if size is too large" do
- -> { Array.new(fixnum_max+1) }.should raise_error(ArgumentError)
+ -> { Array.new(fixnum_max+1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the size argument to an Integer when object is given" do
@@ -99,7 +99,7 @@ describe "Array.new with (size, object=nil)" do
it "raises a TypeError if the size argument is not an Integer type" do
obj = mock('nonnumeric')
obj.stub!(:to_ary).and_return([1, 2])
- ->{ Array.new(obj, :a) }.should raise_error(TypeError)
+ ->{ Array.new(obj, :a) }.should.raise(TypeError)
end
it "yields the index of the element and sets the element to the value of the block" do
diff --git a/spec/ruby/core/array/pack/a_spec.rb b/spec/ruby/core/array/pack/a_spec.rb
index f4a40502c2..03bfd8214c 100644
--- a/spec/ruby/core/array/pack/a_spec.rb
+++ b/spec/ruby/core/array/pack/a_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -19,15 +19,15 @@ describe "Array#pack with format 'A'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('A') }.should raise_error(TypeError)
- -> { [0].pack('a') }.should raise_error(TypeError)
+ -> { [0].pack('A') }.should.raise(TypeError)
+ -> { [0].pack('a') }.should.raise(TypeError)
end
it "adds all the bytes to the output when passed the '*' modifier" do
["abc"].pack("A*").should == "abc"
end
- it "padds the output with spaces when the count exceeds the size of the String" do
+ it "pads the output with spaces when the count exceeds the size of the String" do
["abc"].pack("A6").should == "abc "
end
@@ -55,7 +55,7 @@ describe "Array#pack with format 'a'" do
["abc"].pack("a*").should == "abc"
end
- it "padds the output with NULL bytes when the count exceeds the size of the String" do
+ it "pads the output with NULL bytes when the count exceeds the size of the String" do
["abc"].pack("a6").should == "abc\x00\x00\x00"
end
diff --git a/spec/ruby/core/array/pack/at_spec.rb b/spec/ruby/core/array/pack/at_spec.rb
index 3942677913..bb9801440a 100644
--- a/spec/ruby/core/array/pack/at_spec.rb
+++ b/spec/ruby/core/array/pack/at_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/b_spec.rb b/spec/ruby/core/array/pack/b_spec.rb
index ec82b7d1ab..f7576846ef 100644
--- a/spec/ruby/core/array/pack/b_spec.rb
+++ b/spec/ruby/core/array/pack/b_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -19,8 +19,8 @@ describe "Array#pack with format 'B'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('B') }.should raise_error(TypeError)
- -> { [0].pack('b') }.should raise_error(TypeError)
+ -> { [0].pack('B') }.should.raise(TypeError)
+ -> { [0].pack('b') }.should.raise(TypeError)
end
it "encodes one bit for each character starting with the most significant bit" do
diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb
index b77b2d1efa..d104c80186 100644
--- a/spec/ruby/core/array/pack/buffer_spec.rb
+++ b/spec/ruby/core/array/pack/buffer_spec.rb
@@ -7,7 +7,7 @@ describe "Array#pack with :buffer option" do
n = [ 65, 66, 67 ]
buffer = " "*3
result = n.pack("ccc", buffer: buffer) #=> "ABC"
- result.should equal(buffer)
+ result.should.equal?(buffer)
end
it "adds result at the end of buffer content" do
@@ -24,12 +24,12 @@ describe "Array#pack with :buffer option" do
end
it "raises TypeError exception if buffer is not String" do
- -> { [65].pack("ccc", buffer: []) }.should raise_error(
+ -> { [65].pack("ccc", buffer: []) }.should.raise(
TypeError, "buffer must be String, not Array")
end
it "raise FrozenError if buffer is frozen" do
- -> { [65].pack("c", buffer: "frozen-string".freeze) }.should raise_error(FrozenError)
+ -> { [65].pack("c", buffer: "frozen-string".freeze) }.should.raise(FrozenError)
end
it "preserves the encoding of the given buffer" do
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index ac133ff9b6..de06207a23 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
@@ -45,20 +45,10 @@ describe :array_pack_8bit, shared: true do
[1, 2, 3, 4, 5].pack(pack_format('*')).should == "\x01\x02\x03\x04\x05"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [1, 2, 3].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/comment_spec.rb b/spec/ruby/core/array/pack/comment_spec.rb
index 254c827ccc..daf1cff06a 100644
--- a/spec/ruby/core/array/pack/comment_spec.rb
+++ b/spec/ruby/core/array/pack/comment_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/array/pack/h_spec.rb b/spec/ruby/core/array/pack/h_spec.rb
index 2c1dac8d4a..1492d02b1f 100644
--- a/spec/ruby/core/array/pack/h_spec.rb
+++ b/spec/ruby/core/array/pack/h_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -19,8 +19,8 @@ describe "Array#pack with format 'H'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('H') }.should raise_error(TypeError)
- -> { [0].pack('h') }.should raise_error(TypeError)
+ -> { [0].pack('H') }.should.raise(TypeError)
+ -> { [0].pack('h') }.should.raise(TypeError)
end
it "encodes the first character as the most significant nibble when passed no count modifier" do
diff --git a/spec/ruby/core/array/pack/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb
index c6364af12d..fb670d120e 100644
--- a/spec/ruby/core/array/pack/m_spec.rb
+++ b/spec/ruby/core/array/pack/m_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -155,7 +155,7 @@ describe "Array#pack with format 'M'" do
it "encodes a recursive array" do
empty = ArraySpecs.empty_recursive_array
- empty.pack('M').should be_an_instance_of(String)
+ empty.pack('M').should.instance_of?(String)
array = ArraySpecs.recursive_array
array.pack('M').should == "1=\n"
@@ -172,7 +172,7 @@ describe "Array#pack with format 'M'" do
obj = mock("pack M non-string")
obj.should_receive(:to_s).and_return(2)
- [obj].pack("M").should be_an_instance_of(String)
+ [obj].pack("M").should.instance_of?(String)
end
it "encodes a Symbol as a String" do
@@ -293,16 +293,16 @@ describe "Array#pack with format 'm'" do
it "raises a TypeError if #to_str does not return a String" do
obj = mock("pack m non-string")
- -> { [obj].pack("m") }.should raise_error(TypeError)
+ -> { [obj].pack("m") }.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
- -> { [nil].pack("m") }.should raise_error(TypeError)
+ -> { [nil].pack("m") }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer" do
- -> { [0].pack("m") }.should raise_error(TypeError)
- -> { [bignum_value].pack("m") }.should raise_error(TypeError)
+ -> { [0].pack("m") }.should.raise(TypeError)
+ -> { [bignum_value].pack("m") }.should.raise(TypeError)
end
it "does not emit a newline if passed zero as the count modifier" do
diff --git a/spec/ruby/core/array/pack/percent_spec.rb b/spec/ruby/core/array/pack/percent_spec.rb
index 5d56dea5fe..29b119732a 100644
--- a/spec/ruby/core/array/pack/percent_spec.rb
+++ b/spec/ruby/core/array/pack/percent_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "Array#pack with format '%'" do
it "raises an Argument Error" do
- -> { [1].pack("%") }.should raise_error(ArgumentError)
+ -> { [1].pack("%") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/pack/r_spec.rb b/spec/ruby/core/array/pack/r_spec.rb
new file mode 100644
index 0000000000..cefe1388d2
--- /dev/null
+++ b/spec/ruby/core/array/pack/r_spec.rb
@@ -0,0 +1,89 @@
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/numeric_basic'
+require_relative 'shared/integer'
+
+ruby_version_is "4.1" do
+ describe "Array#pack with format 'R'" do
+ it_behaves_like :array_pack_basic, 'R'
+ it_behaves_like :array_pack_basic_non_float, 'R'
+ it_behaves_like :array_pack_arguments, 'R'
+ it_behaves_like :array_pack_numeric_basic, 'R'
+ it_behaves_like :array_pack_integer, 'R'
+
+ it "encodes a ULEB128 integer" do
+ [ [[0], "\x00"],
+ [[1], "\x01"],
+ [[127], "\x7f"],
+ [[128], "\x80\x01"],
+ [[0x3fff], "\xff\x7f"],
+ [[0x4000], "\x80\x80\x01"],
+ [[0xffffffff], "\xff\xff\xff\xff\x0f"],
+ [[0x100000000], "\x80\x80\x80\x80\x10"],
+ [[0xffff_ffff_ffff_ffff], "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"],
+ [[0xffff_ffff_ffff_ffff_ffff_ffff], "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x1f"],
+ ].should be_computed_by(:pack, "R")
+ end
+
+ it "encodes multiple values with '*' modifier" do
+ [1, 2].pack("R*").should == "\x01\x02"
+ [127, 128].pack("R*").should == "\x7f\x80\x01"
+ end
+
+ it "raises an ArgumentError when passed a negative value" do
+ -> { [-1].pack("R") }.should.raise(ArgumentError)
+ -> { [-100].pack("R") }.should.raise(ArgumentError)
+ end
+
+ it "round-trips values through pack and unpack" do
+ values = [0, 1, 127, 128, 0x3fff, 0x4000, 0xffffffff, 0x100000000]
+ values.pack("R*").unpack("R*").should == values
+ end
+ end
+
+ describe "Array#pack with format 'r'" do
+ it_behaves_like :array_pack_basic, 'r'
+ it_behaves_like :array_pack_basic_non_float, 'r'
+ it_behaves_like :array_pack_arguments, 'r'
+ it_behaves_like :array_pack_numeric_basic, 'r'
+ it_behaves_like :array_pack_integer, 'r'
+
+ it "encodes a SLEB128 integer" do
+ [ [[0], "\x00"],
+ [[1], "\x01"],
+ [[-1], "\x7f"],
+ [[-2], "\x7e"],
+ [[127], "\xff\x00"],
+ [[128], "\x80\x01"],
+ [[-127], "\x81\x7f"],
+ [[-128], "\x80\x7f"],
+ ].should be_computed_by(:pack, "r")
+ end
+
+ it "encodes larger positive numbers" do
+ [0x3fff].pack("r").should == "\xff\xff\x00"
+ [0x4000].pack("r").should == "\x80\x80\x01"
+ end
+
+ it "encodes larger negative numbers" do
+ [-0x3fff].pack("r").should == "\x81\x80\x7f"
+ [-0x4000].pack("r").should == "\x80\x80\x7f"
+ end
+
+ it "encodes very large numbers" do
+ [0xffff_ffff_ffff_ffff_ffff_ffff].pack("r").should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1F"
+ [-0xffff_ffff_ffff_ffff_ffff_ffff].pack("r").should == "\x81\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x60"
+ end
+
+ it "encodes multiple values with '*' modifier" do
+ [0, 1, -1].pack("r*").should == "\x00\x01\x7f"
+ end
+
+ it "round-trips values through pack and unpack" do
+ values = [0, 1, -1, 127, -127, 128, -128, 0x3fff, -0x3fff, 0x4000, -0x4000]
+ values.pack("r*").unpack("r*").should == values
+ end
+ end
+end
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index 4b28de7ed0..2894369c71 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -1,6 +1,6 @@
describe :array_pack_arguments, shared: true do
it "raises an ArgumentError if there are fewer elements than the format requires" do
- -> { [].pack(pack_format(1)) }.should raise_error(ArgumentError)
+ -> { [].pack(pack_format(1)) }.should.raise(ArgumentError)
end
end
@@ -10,11 +10,11 @@ describe :array_pack_basic, shared: true do
end
it "raises a TypeError when passed nil" do
- -> { [@obj].pack(nil) }.should raise_error(TypeError)
+ -> { [@obj].pack(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { [@obj].pack(1) }.should raise_error(TypeError)
+ -> { [@obj].pack(1) }.should.raise(TypeError)
end
end
@@ -24,74 +24,50 @@ describe :array_pack_basic_non_float, shared: true do
end
it "ignores whitespace in the format string" do
- [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should be_an_instance_of(String)
+ [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should.instance_of?(String)
end
it "ignores comments in the format string" do
# 2 additional directives ('a') are required for the X directive
- [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String)
+ [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should.instance_of?(String)
end
- ruby_version_is ""..."3.2" do
- it "warns in verbose mode that a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/, verbose: true)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/, verbose: true)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/, verbose: true)
- end
- end
-
- ruby_version_is "3.2"..."3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- # NOTE: it's just a plan of the Ruby core team
- it "warns that a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/)
- end
- end
-
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- # NOTE: Added this case just to not forget about the decision in the ticket
- it "raise ArgumentError when a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/)
- end
+ it "raise ArgumentError when a directive is unknown" do
+ # additional directive ('a') is required for the X directive
+ -> { [@obj, @obj].pack("a K" + pack_format) }.should.raise(ArgumentError, /unknown pack directive 'K'/)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should.raise(ArgumentError, /unknown pack directive '0'/)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should.raise(ArgumentError, /unknown pack directive ':'/)
end
it "calls #to_str to coerce the directives string" do
d = mock("pack directive")
d.should_receive(:to_str).and_return("x"+pack_format)
- [@obj, @obj].pack(d).should be_an_instance_of(String)
+ [@obj, @obj].pack(d).should.instance_of?(String)
end
end
describe :array_pack_basic_float, shared: true do
it "ignores whitespace in the format string" do
- [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should be_an_instance_of(String)
+ [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should.instance_of?(String)
end
it "ignores comments in the format string" do
- [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should be_an_instance_of(String)
+ [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should.instance_of?(String)
end
it "calls #to_str to coerce the directives string" do
d = mock("pack directive")
d.should_receive(:to_str).and_return("x"+pack_format)
- [1.2, 4.7].pack(d).should be_an_instance_of(String)
+ [1.2, 4.7].pack(d).should.instance_of?(String)
end
end
describe :array_pack_no_platform, shared: true do
it "raises ArgumentError when the format modifier is '_'" do
- ->{ [1].pack(pack_format("_")) }.should raise_error(ArgumentError)
+ ->{ [1].pack(pack_format("_")) }.should.raise(ArgumentError)
end
it "raises ArgumentError when the format modifier is '!'" do
- ->{ [1].pack(pack_format("!")) }.should raise_error(ArgumentError)
+ ->{ [1].pack(pack_format("!")) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/encodings.rb b/spec/ruby/core/array/pack/shared/encodings.rb
index 6b7ffac764..0b5a5cc8a0 100644
--- a/spec/ruby/core/array/pack/shared/encodings.rb
+++ b/spec/ruby/core/array/pack/shared/encodings.rb
@@ -5,12 +5,12 @@ describe :array_pack_hex, shared: true do
it "raises a TypeError if the object does not respond to #to_str" do
obj = mock("pack hex non-string")
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
obj = mock("pack hex non-string")
obj.should_receive(:to_str).and_return(1)
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 1780d7635e..c1efcd7677 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :array_pack_float_le, shared: true do
it "encodes a positive Float" do
@@ -14,7 +14,7 @@ describe :array_pack_float_le, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -25,20 +25,10 @@ describe :array_pack_float_le, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -55,7 +45,7 @@ describe :array_pack_float_le, shared: true do
it "encodes NaN" do
nans = ["\x00\x00\xc0\xff", "\x00\x00\xc0\x7f", "\xFF\xFF\xFF\x7F"]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
@@ -94,7 +84,7 @@ describe :array_pack_float_be, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -105,20 +95,10 @@ describe :array_pack_float_be, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -135,7 +115,7 @@ describe :array_pack_float_be, shared: true do
it "encodes NaN" do
nans = ["\xff\xc0\x00\x00", "\x7f\xc0\x00\x00", "\x7F\xFF\xFF\xFF"]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
@@ -166,7 +146,7 @@ describe :array_pack_double_le, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -177,20 +157,10 @@ describe :array_pack_double_le, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -211,7 +181,7 @@ describe :array_pack_double_le, shared: true do
"\x00\x00\x00\x00\x00\x00\xf8\x7f",
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"
]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
@@ -237,7 +207,7 @@ describe :array_pack_double_be, shared: true do
end
it "raises a TypeError if passed a String representation of a floating point number" do
- -> { ["13"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["13"].pack(pack_format) }.should.raise(TypeError)
end
it "encodes the number of array elements specified by the count modifier" do
@@ -248,20 +218,10 @@ describe :array_pack_double_be, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [5.3, 9.2].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -282,7 +242,7 @@ describe :array_pack_double_be, shared: true do
"\x7f\xf8\x00\x00\x00\x00\x00\x00",
"\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
]
- nans.should include([nan_value].pack(pack_format))
+ nans.should.include?([nan_value].pack(pack_format))
end
it "encodes a positive Float outside the range of a single precision float" do
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index a89b5b733b..1cdd386cc1 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :array_pack_16bit_le, shared: true do
it "encodes the least significant 16 bits of a positive number" do
@@ -41,21 +41,10 @@ describe :array_pack_16bit_le, shared: true do
str.should == "\x78\x65\xcd\xab\x21\x43"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\xcd\xab"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -105,21 +94,10 @@ describe :array_pack_16bit_be, shared: true do
str.should == "\x65\x78\xab\xcd\x43\x21"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x65\x78\xab\xcd"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -169,21 +147,10 @@ describe :array_pack_32bit_le, shared: true do
str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -233,21 +200,10 @@ describe :array_pack_32bit_be, shared: true do
str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -357,21 +313,10 @@ describe :array_pack_64bit_le, shared: true do
str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -429,21 +374,10 @@ describe :array_pack_64bit_be, shared: true do
str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/shared/numeric_basic.rb b/spec/ruby/core/array/pack/shared/numeric_basic.rb
index 545e215e64..6594914933 100644
--- a/spec/ruby/core/array/pack/shared/numeric_basic.rb
+++ b/spec/ruby/core/array/pack/shared/numeric_basic.rb
@@ -4,15 +4,15 @@ describe :array_pack_numeric_basic, shared: true do
end
it "raises a TypeError when passed nil" do
- -> { [nil].pack(pack_format) }.should raise_error(TypeError)
+ -> { [nil].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when passed true" do
- -> { [true].pack(pack_format) }.should raise_error(TypeError)
+ -> { [true].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when passed false" do
- -> { [false].pack(pack_format) }.should raise_error(TypeError)
+ -> { [false].pack(pack_format) }.should.raise(TypeError)
end
it "returns a binary string" do
@@ -24,27 +24,27 @@ end
describe :array_pack_integer, shared: true do
it "raises a TypeError when the object does not respond to #to_int" do
obj = mock('not an integer')
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { ["5"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["5"].pack(pack_format) }.should.raise(TypeError)
end
end
describe :array_pack_float, shared: true do
it "raises a TypeError if a String does not represent a floating point number" do
- -> { ["a"].pack(pack_format) }.should raise_error(TypeError)
+ -> { ["a"].pack(pack_format) }.should.raise(TypeError)
end
it "raises a TypeError when the object is not Numeric" do
obj = Object.new
- -> { [obj].pack(pack_format) }.should raise_error(TypeError, /can't convert Object into Float/)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError, /can't convert Object into Float/)
end
it "raises a TypeError when the Numeric object does not respond to #to_f" do
klass = Class.new(Numeric)
obj = klass.new
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/string.rb b/spec/ruby/core/array/pack/shared/string.rb
index 2f70dc3951..b02257059f 100644
--- a/spec/ruby/core/array/pack/shared/string.rb
+++ b/spec/ruby/core/array/pack/shared/string.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :array_pack_string, shared: true do
it "adds count bytes of a String to the output" do
["abc"].pack(pack_format(2)).should == "ab"
@@ -17,11 +17,11 @@ describe :array_pack_string, shared: true do
end
it "raises an ArgumentError when the Array is empty" do
- -> { [].pack(pack_format) }.should raise_error(ArgumentError)
+ -> { [].pack(pack_format) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the Array has too few elements" do
- -> { ["a"].pack(pack_format(nil, 2)) }.should raise_error(ArgumentError)
+ -> { ["a"].pack(pack_format(nil, 2)) }.should.raise(ArgumentError)
end
it "calls #to_str to convert the element to a String" do
@@ -33,7 +33,7 @@ describe :array_pack_string, shared: true do
it "raises a TypeError when the object does not respond to #to_str" do
obj = mock("not a string")
- -> { [obj].pack(pack_format) }.should raise_error(TypeError)
+ -> { [obj].pack(pack_format) }.should.raise(TypeError)
end
it "returns a string in encoding of common to the concatenated results" do
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index 4d8eaef323..58ba8a8b23 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -26,7 +26,7 @@ describe :array_pack_unicode, shared: true do
it "constructs strings with valid encodings" do
str = [0x85].pack("U*")
str.should == "\xc2\x85"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
end
it "encodes values larger than UTF-8 max codepoints" do
@@ -64,23 +64,13 @@ describe :array_pack_unicode, shared: true do
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock('to_int')
obj.should_receive(:to_int).and_return("5")
- -> { [obj].pack("U") }.should raise_error(TypeError)
+ -> { [obj].pack("U") }.should.raise(TypeError)
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack("U\x00U").should == "\x01\x02"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [1, 2, 3].pack("U\x00U")
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("U\x00U")
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -88,11 +78,11 @@ describe :array_pack_unicode, shared: true do
end
it "raises a RangeError if passed a negative number" do
- -> { [-1].pack("U") }.should raise_error(RangeError)
+ -> { [-1].pack("U") }.should.raise(RangeError)
end
it "raises a RangeError if passed a number larger than an unsigned 32-bit integer" do
- -> { [2**32].pack("U") }.should raise_error(RangeError)
+ -> { [2**32].pack("U") }.should.raise(RangeError)
end
it "sets the output string to UTF-8 encoding" do
diff --git a/spec/ruby/core/array/pack/u_spec.rb b/spec/ruby/core/array/pack/u_spec.rb
index b20093a647..c6a0d77eb2 100644
--- a/spec/ruby/core/array/pack/u_spec.rb
+++ b/spec/ruby/core/array/pack/u_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -25,7 +25,7 @@ describe "Array#pack with format 'u'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('u') }.should raise_error(TypeError)
+ -> { [0].pack('u') }.should.raise(TypeError)
end
it "encodes an empty string as an empty string" do
@@ -122,16 +122,16 @@ describe "Array#pack with format 'u'" do
it "raises a TypeError if #to_str does not return a String" do
obj = mock("pack m non-string")
- -> { [obj].pack("u") }.should raise_error(TypeError)
+ -> { [obj].pack("u") }.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
- -> { [nil].pack("u") }.should raise_error(TypeError)
+ -> { [nil].pack("u") }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer" do
- -> { [0].pack("u") }.should raise_error(TypeError)
- -> { [bignum_value].pack("u") }.should raise_error(TypeError)
+ -> { [0].pack("u") }.should.raise(TypeError)
+ -> { [bignum_value].pack("u") }.should.raise(TypeError)
end
it "sets the output string to US-ASCII encoding" do
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index 48ed4496a5..263e2a2288 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -24,20 +24,10 @@ describe "Array#pack with format 'w'" do
[obj].pack("w").should == "\x05"
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack("w\x00w").should == "\x01\x02"
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- [1, 2, 3].pack("w\x00w")
- }.should raise_error(ArgumentError, /unknown pack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("w\x00w")
+ }.should.raise(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
@@ -45,7 +35,7 @@ describe "Array#pack with format 'w'" do
end
it "raises an ArgumentError when passed a negative value" do
- -> { [-1].pack("w") }.should raise_error(ArgumentError)
+ -> { [-1].pack("w") }.should.raise(ArgumentError)
end
it "returns a binary string" do
diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb
index 86c3ad1aa4..7ff587a01e 100644
--- a/spec/ruby/core/array/pack/x_spec.rb
+++ b/spec/ruby/core/array/pack/x_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -56,10 +56,10 @@ describe "Array#pack with format 'X'" do
end
it "raises an ArgumentError if the output string is empty" do
- -> { [1, 2, 3].pack("XC") }.should raise_error(ArgumentError)
+ -> { [1, 2, 3].pack("XC") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the count modifier is greater than the bytes in the string" do
- -> { [1, 2, 3].pack("C2X3") }.should raise_error(ArgumentError)
+ -> { [1, 2, 3].pack("C2X3") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/pack/z_spec.rb b/spec/ruby/core/array/pack/z_spec.rb
index 5ad3afd69e..5cd084c825 100644
--- a/spec/ruby/core/array/pack/z_spec.rb
+++ b/spec/ruby/core/array/pack/z_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -19,14 +19,14 @@ describe "Array#pack with format 'Z'" do
end
it "will not implicitly convert a number to a string" do
- -> { [0].pack('Z') }.should raise_error(TypeError)
+ -> { [0].pack('Z') }.should.raise(TypeError)
end
it "adds all the bytes and appends a NULL byte when passed the '*' modifier" do
["abc"].pack("Z*").should == "abc\x00"
end
- it "padds the output with NULL bytes when the count exceeds the size of the String" do
+ it "pads the output with NULL bytes when the count exceeds the size of the String" do
["abc"].pack("Z6").should == "abc\x00\x00\x00"
end
diff --git a/spec/ruby/core/array/partition_spec.rb b/spec/ruby/core/array/partition_spec.rb
index be36fffcab..bd3f3a6b6f 100644
--- a/spec/ruby/core/array/partition_spec.rb
+++ b/spec/ruby/core/array/partition_spec.rb
@@ -36,8 +36,8 @@ describe "Array#partition" do
it "does not return subclass instances on Array subclasses" do
result = ArraySpecs::MyArray[1, 2, 3].partition { |x| x % 2 == 0 }
- result.should be_an_instance_of(Array)
- result[0].should be_an_instance_of(Array)
- result[1].should be_an_instance_of(Array)
+ result.should.instance_of?(Array)
+ result[0].should.instance_of?(Array)
+ result[1].should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/permutation_spec.rb b/spec/ruby/core/array/permutation_spec.rb
index f15bd76639..b5df84b52b 100644
--- a/spec/ruby/core/array/permutation_spec.rb
+++ b/spec/ruby/core/array/permutation_spec.rb
@@ -11,7 +11,7 @@ describe "Array#permutation" do
it "returns an Enumerator of all permutations when called without a block or arguments" do
enum = @numbers.permutation
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.sort.should == [
[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
].sort
@@ -19,13 +19,13 @@ describe "Array#permutation" do
it "returns an Enumerator of permutations of given length when called with an argument but no block" do
enum = @numbers.permutation(1)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.sort.should == [[1],[2],[3]]
end
it "yields all permutations to the block then returns self when called with block but no arguments" do
array = @numbers.permutation {|n| @yielded << n}
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array.sort.should == @numbers.sort
@yielded.sort.should == [
[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
@@ -34,7 +34,7 @@ describe "Array#permutation" do
it "yields all permutations of given length to the block then returns self when called with block and argument" do
array = @numbers.permutation(2) {|n| @yielded << n}
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array.sort.should == @numbers.sort
@yielded.sort.should == [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]].sort
end
@@ -78,7 +78,7 @@ describe "Array#permutation" do
[3, 1], [3, 2], [3, [4, 5]],
[[4, 5], 1], [[4, 5], 2], [[4, 5], 3]
]
- expected.each {|e| got.include?(e).should be_true}
+ expected.each {|e| got.include?(e).should == true}
got.size.should == expected.size
end
diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb
index b7153fd3ef..7ead927fc0 100644
--- a/spec/ruby/core/array/plus_spec.rb
+++ b/spec/ruby/core/array/plus_spec.rb
@@ -22,14 +22,14 @@ describe "Array#+" do
end
it "raises a TypeError if the given argument can't be converted to an array" do
- -> { [1, 2, 3] + nil }.should raise_error(TypeError)
- -> { [1, 2, 3] + "abc" }.should raise_error(TypeError)
+ -> { [1, 2, 3] + nil }.should.raise(TypeError)
+ -> { [1, 2, 3] + "abc" }.should.raise(TypeError)
end
it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
obj = mock("hello")
obj.should_receive(:to_ary).and_raise(NoMethodError)
- -> { [1, 2, 3] + obj }.should raise_error(NoMethodError)
+ -> { [1, 2, 3] + obj }.should.raise(NoMethodError)
end
end
@@ -45,9 +45,9 @@ describe "Array#+" do
end
it "does return subclass instances with Array subclasses" do
- (ArraySpecs::MyArray[1, 2, 3] + []).should be_an_instance_of(Array)
- (ArraySpecs::MyArray[1, 2, 3] + ArraySpecs::MyArray[]).should be_an_instance_of(Array)
- ([1, 2, 3] + ArraySpecs::MyArray[]).should be_an_instance_of(Array)
+ (ArraySpecs::MyArray[1, 2, 3] + []).should.instance_of?(Array)
+ (ArraySpecs::MyArray[1, 2, 3] + ArraySpecs::MyArray[]).should.instance_of?(Array)
+ ([1, 2, 3] + ArraySpecs::MyArray[]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/pop_spec.rb b/spec/ruby/core/array/pop_spec.rb
index 2a19408660..069083331c 100644
--- a/spec/ruby/core/array/pop_spec.rb
+++ b/spec/ruby/core/array/pop_spec.rb
@@ -31,11 +31,11 @@ describe "Array#pop" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.pop }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.pop }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.pop }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.pop }.should.raise(FrozenError)
end
describe "passed a number n as an argument" do
@@ -71,7 +71,7 @@ describe "Array#pop" do
popped2.should == []
a.should == []
- popped1.should_not equal(popped2)
+ popped1.should_not.equal?(popped2)
end
it "returns whole elements if n exceeds size of the array" do
@@ -82,14 +82,14 @@ describe "Array#pop" do
it "does not return self even when it returns whole elements" do
a = [1, 2, 3, 4, 5]
- a.pop(5).should_not equal(a)
+ a.pop(5).should_not.equal?(a)
a = [1, 2, 3, 4, 5]
- a.pop(6).should_not equal(a)
+ a.pop(6).should_not.equal?(a)
end
it "raises an ArgumentError if n is negative" do
- ->{ [1, 2, 3].pop(-1) }.should raise_error(ArgumentError)
+ ->{ [1, 2, 3].pop(-1) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -104,21 +104,21 @@ describe "Array#pop" do
end
it "raises a TypeError when the passed n cannot be coerced to Integer" do
- ->{ [1, 2].pop("cat") }.should raise_error(TypeError)
- ->{ [1, 2].pop(nil) }.should raise_error(TypeError)
+ ->{ [1, 2].pop("cat") }.should.raise(TypeError)
+ ->{ [1, 2].pop(nil) }.should.raise(TypeError)
end
it "raises an ArgumentError if more arguments are passed" do
- ->{ [1, 2].pop(1, 2) }.should raise_error(ArgumentError)
+ ->{ [1, 2].pop(1, 2) }.should.raise(ArgumentError)
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].pop(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].pop(2).should.instance_of?(Array)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.pop(2) }.should raise_error(FrozenError)
- -> { ArraySpecs.frozen_array.pop(0) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.pop(2) }.should.raise(FrozenError)
+ -> { ArraySpecs.frozen_array.pop(0) }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/array/prepend_spec.rb b/spec/ruby/core/array/prepend_spec.rb
index 368b8dcfcd..2d0ce31c71 100644
--- a/spec/ruby/core/array/prepend_spec.rb
+++ b/spec/ruby/core/array/prepend_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/unshift'
describe "Array#prepend" do
- it_behaves_like :array_unshift, :prepend
+ it "is an alias of Array#unshift" do
+ Array.instance_method(:prepend).should == Array.instance_method(:unshift)
+ end
end
diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb
index 6fb3818508..837f0eaf34 100644
--- a/spec/ruby/core/array/product_spec.rb
+++ b/spec/ruby/core/array/product_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Array#product" do
it "returns converted arguments using :to_ary" do
- ->{ [1].product(2..3) }.should raise_error(TypeError)
+ ->{ [1].product(2..3) }.should.raise(TypeError)
ar = ArraySpecs::ArrayConvertible.new(2,3)
[1].product(ar).should == [[1,2],[1,3]]
ar.called.should == :to_ary
@@ -31,7 +31,7 @@ describe "Array#product" do
a = (0..100).to_a
-> do
a.product(a, a, a, a, a, a, a, a, a, a)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
describe "when given a block" do
@@ -43,7 +43,7 @@ describe "Array#product" do
acc = []
[1,2].product([3,4,5],[],[6,8]){|array| acc << array}
- acc.should be_empty
+ acc.should.empty?
end
it "returns self" do
@@ -56,18 +56,18 @@ describe "Array#product" do
a = (0..100).to_a
-> do
a.product(a, a, a, a, a, a, a, a, a, a)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
end
describe "when given an empty block" do
it "returns self" do
arr = [1,2]
- arr.product([3,4,5],[6,8]){}.should equal(arr)
+ arr.product([3,4,5],[6,8]){}.should.equal?(arr)
arr = []
- arr.product([3,4,5],[6,8]){}.should equal(arr)
+ arr.product([3,4,5],[6,8]){}.should.equal?(arr)
arr = [1,2]
- arr.product([]){}.should equal(arr)
+ arr.product([]){}.should.equal?(arr)
end
end
end
diff --git a/spec/ruby/core/array/push_spec.rb b/spec/ruby/core/array/push_spec.rb
index 607cbc7b4d..6255a84371 100644
--- a/spec/ruby/core/array/push_spec.rb
+++ b/spec/ruby/core/array/push_spec.rb
@@ -1,7 +1,36 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/push'
describe "Array#push" do
- it_behaves_like :array_push, :push
+ it "appends the arguments to the array" do
+ a = [ "a", "b", "c" ]
+ a.push("d", "e", "f").should.equal?(a)
+ a.push.should == ["a", "b", "c", "d", "e", "f"]
+ a.push(5)
+ a.should == ["a", "b", "c", "d", "e", "f", 5]
+
+ a = [0, 1]
+ a.push(2)
+ a.should == [0, 1, 2]
+ end
+
+ it "isn't confused by previous shift" do
+ a = [ "a", "b", "c" ]
+ a.shift
+ a.push("foo")
+ a.should == ["b", "c", "foo"]
+ end
+
+ it "properly handles recursive arrays" do
+ empty = ArraySpecs.empty_recursive_array
+ empty.push(:last).should == [empty, :last]
+
+ array = ArraySpecs.recursive_array
+ array.push(:last).should == [1, 'two', 3.0, array, array, array, array, array, :last]
+ end
+
+ it "raises a FrozenError on a frozen array" do
+ -> { ArraySpecs.frozen_array.push(1) }.should.raise(FrozenError)
+ -> { ArraySpecs.frozen_array.push }.should.raise(FrozenError)
+ end
end
diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb
index 632a05e8b3..95e4ed1892 100644
--- a/spec/ruby/core/array/rassoc_spec.rb
+++ b/spec/ruby/core/array/rassoc_spec.rb
@@ -12,11 +12,11 @@ describe "Array#rassoc" do
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
- empty.rassoc([]).should be_nil
+ empty.rassoc([]).should == nil
[[empty, empty]].rassoc(empty).should == [empty, empty]
array = ArraySpecs.recursive_array
- array.rassoc(array).should be_nil
+ array.rassoc(array).should == nil
[[empty, array]].rassoc(array).should == [empty, array]
end
@@ -36,17 +36,15 @@ describe "Array#rassoc" do
[[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1]
end
- ruby_version_is "3.3" do
- it "calls to_ary on non-array elements" do
- s1 = [1, 2]
- s2 = ArraySpecs::ArrayConvertible.new(2, 3)
- a = [s1, s2]
+ it "calls to_ary on non-array elements" do
+ s1 = [1, 2]
+ s2 = ArraySpecs::ArrayConvertible.new(2, 3)
+ a = [s1, s2]
- s1.should_not_receive(:to_ary)
- a.rassoc(2).should equal(s1)
+ s1.should_not_receive(:to_ary)
+ a.rassoc(2).should.equal?(s1)
- a.rassoc(3).should == [2, 3]
- s2.called.should equal(:to_ary)
- end
+ a.rassoc(3).should == [2, 3]
+ s2.called.should.equal?(:to_ary)
end
end
diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb
index 81a467e364..8d237b3a75 100644
--- a/spec/ruby/core/array/reject_spec.rb
+++ b/spec/ruby/core/array/reject_spec.rb
@@ -10,9 +10,9 @@ describe "Array#reject" do
ary = [1, 2, 3, 4, 5]
ary.reject { true }.should == []
ary.reject { false }.should == ary
- ary.reject { false }.should_not equal ary
+ ary.reject { false }.should_not.equal? ary
ary.reject { nil }.should == ary
- ary.reject { nil }.should_not equal ary
+ ary.reject { nil }.should_not.equal? ary
ary.reject { 5 }.should == []
ary.reject { |i| i < 3 }.should == [3, 4, 5]
ary.reject { |i| i % 2 == 0 }.should == [1, 3, 5]
@@ -35,7 +35,7 @@ describe "Array#reject" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].reject { |x| x % 2 == 0 }.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].reject { |x| x % 2 == 0 }.should.instance_of?(Array)
end
it "does not retain instance variables" do
@@ -55,7 +55,7 @@ end
describe "Array#reject!" do
it "removes elements for which block is true" do
a = [3, 4, 5, 6, 7, 8, 9, 10, 11]
- a.reject! { |i| i % 2 == 0 }.should equal(a)
+ a.reject! { |i| i % 2 == 0 }.should.equal?(a)
a.should == [3, 5, 7, 9, 11]
a.reject! { |i| i > 8 }
a.should == [3, 5, 7]
@@ -105,20 +105,20 @@ describe "Array#reject!" do
end
it "returns an Enumerator if no block given, and the array is frozen" do
- ArraySpecs.frozen_array.reject!.should be_an_instance_of(Enumerator)
+ ArraySpecs.frozen_array.reject!.should.instance_of?(Enumerator)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.reject! {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.reject! {} }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.reject! {} }.should.raise(FrozenError)
end
it "raises a FrozenError on a frozen array only during iteration if called without a block" do
enum = ArraySpecs.frozen_array.reject!
- -> { enum.each {} }.should raise_error(FrozenError)
+ -> { enum.each {} }.should.raise(FrozenError)
end
it "does not truncate the array is the block raises an exception" do
diff --git a/spec/ruby/core/array/repeated_combination_spec.rb b/spec/ruby/core/array/repeated_combination_spec.rb
index b62382024a..a714f05f54 100644
--- a/spec/ruby/core/array/repeated_combination_spec.rb
+++ b/spec/ruby/core/array/repeated_combination_spec.rb
@@ -6,16 +6,16 @@ describe "Array#repeated_combination" do
end
it "returns an enumerator when no block is provided" do
- @array.repeated_combination(2).should be_an_instance_of(Enumerator)
+ @array.repeated_combination(2).should.instance_of?(Enumerator)
end
it "returns self when a block is given" do
- @array.repeated_combination(2){}.should equal(@array)
+ @array.repeated_combination(2){}.should.equal?(@array)
end
it "yields nothing for negative length and return self" do
- @array.repeated_combination(-1){ fail }.should equal(@array)
- @array.repeated_combination(-10){ fail }.should equal(@array)
+ @array.repeated_combination(-1){ fail }.should.equal?(@array)
+ @array.repeated_combination(-10){ fail }.should.equal?(@array)
end
it "yields the expected repeated_combinations" do
diff --git a/spec/ruby/core/array/repeated_permutation_spec.rb b/spec/ruby/core/array/repeated_permutation_spec.rb
index a165fda09e..c54a8c0c2b 100644
--- a/spec/ruby/core/array/repeated_permutation_spec.rb
+++ b/spec/ruby/core/array/repeated_permutation_spec.rb
@@ -10,13 +10,13 @@ describe "Array#repeated_permutation" do
it "returns an Enumerator of all repeated permutations of given length when called without a block" do
enum = @numbers.repeated_permutation(2)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.sort.should == @permutations
end
it "yields all repeated_permutations to the block then returns self when called with block but no arguments" do
yielded = []
- @numbers.repeated_permutation(2) {|n| yielded << n}.should equal(@numbers)
+ @numbers.repeated_permutation(2) {|n| yielded << n}.should.equal?(@numbers)
yielded.sort.should == @permutations
end
diff --git a/spec/ruby/core/array/replace_spec.rb b/spec/ruby/core/array/replace_spec.rb
index 2f53338f5e..ee6a98a646 100644
--- a/spec/ruby/core/array/replace_spec.rb
+++ b/spec/ruby/core/array/replace_spec.rb
@@ -1,7 +1,63 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/replace'
describe "Array#replace" do
- it_behaves_like :array_replace, :replace
+ it "replaces the elements with elements from other array" do
+ a = [1, 2, 3, 4, 5]
+ b = ['a', 'b', 'c']
+ a.replace(b).should.equal?(a)
+ a.should == b
+ a.should_not.equal?(b)
+
+ a.replace([4] * 10)
+ a.should == [4] * 10
+
+ a.replace([])
+ a.should == []
+ end
+
+ it "properly handles recursive arrays" do
+ orig = [1, 2, 3]
+ empty = ArraySpecs.empty_recursive_array
+ orig.replace(empty)
+ orig.should == empty
+
+ array = ArraySpecs.recursive_array
+ orig.replace(array)
+ orig.should == array
+ end
+
+ it "returns self" do
+ ary = [1, 2, 3]
+ other = [:a, :b, :c]
+ ary.replace(other).should.equal?(ary)
+ end
+
+ it "does not make self dependent to the original array" do
+ ary = [1, 2, 3]
+ other = [:a, :b, :c]
+ ary.replace(other)
+ ary.should == [:a, :b, :c]
+ ary << :d
+ ary.should == [:a, :b, :c, :d]
+ other.should == [:a, :b, :c]
+ end
+
+ it "tries to convert the passed argument to an Array using #to_ary" do
+ obj = mock('to_ary')
+ obj.stub!(:to_ary).and_return([1, 2, 3])
+ [].replace(obj).should == [1, 2, 3]
+ end
+
+ it "does not call #to_ary on Array subclasses" do
+ obj = ArraySpecs::ToAryArray[5, 6, 7]
+ obj.should_not_receive(:to_ary)
+ [].replace(ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7]
+ end
+
+ it "raises a FrozenError on a frozen array" do
+ -> {
+ ArraySpecs.frozen_array.replace(ArraySpecs.frozen_array)
+ }.should.raise(FrozenError)
+ end
end
diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb
index 59dabcd33d..8fa5ce6da1 100644
--- a/spec/ruby/core/array/reverse_each_spec.rb
+++ b/spec/ruby/core/array/reverse_each_spec.rb
@@ -19,7 +19,7 @@ describe "Array#reverse_each" do
it "returns self" do
a = [:a, :b, :c]
- a.reverse_each { |x| }.should equal(a)
+ a.reverse_each { |x| }.should.equal?(a)
end
it "yields only the top level element of an empty recursive arrays" do
diff --git a/spec/ruby/core/array/reverse_spec.rb b/spec/ruby/core/array/reverse_spec.rb
index 05dbd2efcf..f25a484be8 100644
--- a/spec/ruby/core/array/reverse_spec.rb
+++ b/spec/ruby/core/array/reverse_spec.rb
@@ -16,14 +16,14 @@ describe "Array#reverse" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].reverse.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].reverse.should.instance_of?(Array)
end
end
describe "Array#reverse!" do
it "reverses the elements in place" do
a = [6, 3, 4, 2, 1]
- a.reverse!.should equal(a)
+ a.reverse!.should.equal?(a)
a.should == [1, 2, 4, 3, 6]
[].reverse!.should == []
end
@@ -37,6 +37,6 @@ describe "Array#reverse!" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.reverse! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.reverse! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb
index 13de88818c..858c39dc92 100644
--- a/spec/ruby/core/array/rindex_spec.rb
+++ b/spec/ruby/core/array/rindex_spec.rb
@@ -41,7 +41,7 @@ describe "Array#rindex" do
it "properly handles empty recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty.rindex(empty).should == 0
- empty.rindex(1).should be_nil
+ empty.rindex(1).should == nil
end
it "properly handles recursive arrays" do
@@ -86,7 +86,7 @@ describe "Array#rindex" do
describe "given no argument and no block" do
it "produces an Enumerator" do
enum = [4, 2, 1, 5, 1, 3].rindex
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |x| x < 2 }.should == 4
end
end
diff --git a/spec/ruby/core/array/rotate_spec.rb b/spec/ruby/core/array/rotate_spec.rb
index 60dcc8b113..009ce5ed49 100644
--- a/spec/ruby/core/array/rotate_spec.rb
+++ b/spec/ruby/core/array/rotate_spec.rb
@@ -29,10 +29,10 @@ describe "Array#rotate" do
it "raises a TypeError if not passed an integer-like argument" do
-> {
[1, 2].rotate(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
[1, 2].rotate("4")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -50,18 +50,18 @@ describe "Array#rotate" do
[].freeze.rotate
[2].freeze.rotate(2)
[1,2,3].freeze.rotate(-3)
- }.should_not raise_error
+ }.should_not.raise
end
it "does not return self" do
a = [1, 2, 3]
- a.rotate.should_not equal(a)
+ a.rotate.should_not.equal?(a)
a = []
- a.rotate(0).should_not equal(a)
+ a.rotate(0).should_not.equal?(a)
end
it "does not return subclass instance for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].rotate.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].rotate.should.instance_of?(Array)
end
end
@@ -69,7 +69,7 @@ describe "Array#rotate!" do
describe "when passed no argument" do
it "moves the first element to the end and returns self" do
a = [1, 2, 3, 4, 5]
- a.rotate!.should equal(a)
+ a.rotate!.should.equal?(a)
a.should == [2, 3, 4, 5, 1]
end
end
@@ -77,11 +77,11 @@ describe "Array#rotate!" do
describe "with an argument n" do
it "moves the first (n % size) elements at the end and returns self" do
a = [1, 2, 3, 4, 5]
- a.rotate!(2).should equal(a)
+ a.rotate!(2).should.equal?(a)
a.should == [3, 4, 5, 1, 2]
- a.rotate!(-12).should equal(a)
+ a.rotate!(-12).should.equal?(a)
a.should == [1, 2, 3, 4, 5]
- a.rotate!(13).should equal(a)
+ a.rotate!(13).should.equal?(a)
a.should == [4, 5, 1, 2, 3]
end
@@ -96,34 +96,34 @@ describe "Array#rotate!" do
it "raises a TypeError if not passed an integer-like argument" do
-> {
[1, 2].rotate!(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
[1, 2].rotate!("4")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
it "does nothing and returns self when the length is zero or one" do
a = [1]
- a.rotate!.should equal(a)
+ a.rotate!.should.equal?(a)
a.should == [1]
- a.rotate!(2).should equal(a)
+ a.rotate!(2).should.equal?(a)
a.should == [1]
- a.rotate!(-21).should equal(a)
+ a.rotate!(-21).should.equal?(a)
a.should == [1]
a = []
- a.rotate!.should equal(a)
+ a.rotate!.should.equal?(a)
a.should == []
- a.rotate!(2).should equal(a)
+ a.rotate!(2).should.equal?(a)
a.should == []
- a.rotate!(-21).should equal(a)
+ a.rotate!(-21).should.equal?(a)
a.should == []
end
it "raises a FrozenError on a frozen array" do
- -> { [1, 2, 3].freeze.rotate!(0) }.should raise_error(FrozenError)
- -> { [1].freeze.rotate!(42) }.should raise_error(FrozenError)
- -> { [].freeze.rotate! }.should raise_error(FrozenError)
+ -> { [1, 2, 3].freeze.rotate!(0) }.should.raise(FrozenError)
+ -> { [1].freeze.rotate!(42) }.should.raise(FrozenError)
+ -> { [].freeze.rotate! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index d4e945152d..fd443b47de 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -14,23 +14,23 @@ describe "Array#sample" do
end
it "returns nil for an empty Array" do
- [].sample.should be_nil
+ [].sample.should == nil
end
it "returns nil for an empty array when called without n and a Random is given" do
- [].sample(random: Random.new(42)).should be_nil
+ [].sample(random: Random.new(42)).should == nil
end
it "returns a single value when not passed a count" do
- [4].sample.should equal(4)
+ [4].sample.should.equal?(4)
end
it "returns a single value when not passed a count and a Random is given" do
- [4].sample(random: Random.new(42)).should equal(4)
+ [4].sample(random: Random.new(42)).should.equal?(4)
end
it "returns a single value when not passed a count and a Random class is given" do
- [4].sample(random: Random).should equal(4)
+ [4].sample(random: Random).should.equal?(4)
end
it "returns an empty Array when passed zero" do
@@ -38,12 +38,12 @@ describe "Array#sample" do
end
it "returns an Array of elements when passed a count" do
- [1, 2, 3, 4].sample(3).should be_an_instance_of(Array)
+ [1, 2, 3, 4].sample(3).should.instance_of?(Array)
end
it "returns elements from the Array" do
array = [1, 2, 3, 4]
- array.sample(3).all? { |x| array.should include(x) }
+ array.sample(3).all? { |x| array.should.include?(x) }
end
it "returns at most the number of elements in the Array" do
@@ -67,11 +67,11 @@ describe "Array#sample" do
end
it "raises ArgumentError when passed a negative count" do
- -> { [1, 2].sample(-1) }.should raise_error(ArgumentError)
+ -> { [1, 2].sample(-1) }.should.raise(ArgumentError)
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].sample(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].sample(2).should.instance_of?(Array)
end
describe "with options" do
@@ -79,13 +79,13 @@ describe "Array#sample" do
obj = mock("array_sample_random")
obj.should_receive(:rand).and_return(0.5)
- [1, 2].sample(random: obj).should be_an_instance_of(Integer)
+ [1, 2].sample(random: obj).should.instance_of?(Integer)
end
it "raises a NoMethodError if an object passed for the RNG does not define #rand" do
obj = BasicObject.new
- -> { [1, 2].sample(random: obj) }.should raise_error(NoMethodError)
+ -> { [1, 2].sample(random: obj) }.should.raise(NoMethodError)
end
describe "when the object returned by #rand is an Integer" do
@@ -105,21 +105,21 @@ describe "Array#sample" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(-1)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is equal to the Array size" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(2)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is greater than the Array size" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(3)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
end
end
@@ -140,7 +140,7 @@ describe "Array#sample" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(value)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is equal to the Array size" do
@@ -149,7 +149,7 @@ describe "Array#sample" do
random = mock("array_sample_random")
random.should_receive(:rand).and_return(value)
- -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].sample(random: random) }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/array/select_spec.rb b/spec/ruby/core/array/select_spec.rb
index 298b591744..57ec0b2540 100644
--- a/spec/ruby/core/array/select_spec.rb
+++ b/spec/ruby/core/array/select_spec.rb
@@ -1,13 +1,42 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
+require_relative '../enumerable/shared/enumeratorized'
+require_relative 'fixtures/classes'
+require_relative 'shared/enumeratorize'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
+require_relative 'shared/keep_if'
describe "Array#select" do
- it_behaves_like :array_select, :select
+ it_behaves_like :enumeratorize, :select
+
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :select
+
+ before :each do
+ @object = [1,2,3]
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :select
+
+ it "returns a new array of elements for which block is true" do
+ [1, 3, 4, 5, 6, 9].select { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6]
+ end
+
+ it "does not return subclass instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].select { true }.should.instance_of?(Array)
+ end
+
+ it "properly handles recursive arrays" do
+ empty = ArraySpecs.empty_recursive_array
+ empty.select { true }.should == empty
+ empty.select { false }.should == []
+
+ array = ArraySpecs.recursive_array
+ array.select { true }.should == [1, 'two', 3.0, array, array, array, array, array]
+ array.select { false }.should == []
+ end
end
describe "Array#select!" do
it "returns nil if no changes were made in the array" do
- [1, 2, 3].select! { true }.should be_nil
+ [1, 2, 3].select! { true }.should == nil
end
it_behaves_like :keep_if, :select!
diff --git a/spec/ruby/core/array/shared/clone.rb b/spec/ruby/core/array/shared/clone.rb
index 035b45ec99..1a45c2fe2c 100644
--- a/spec/ruby/core/array/shared/clone.rb
+++ b/spec/ruby/core/array/shared/clone.rb
@@ -1,14 +1,14 @@
describe :array_clone, shared: true do
it "returns an Array or a subclass instance" do
- [].send(@method).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2].send(@method).should be_an_instance_of(ArraySpecs::MyArray)
+ [].send(@method).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2].send(@method).should.instance_of?(ArraySpecs::MyArray)
end
it "produces a shallow copy where the references are directly copied" do
a = [mock('1'), mock('2')]
b = a.send @method
- b.first.should equal a.first
- b.last.should equal a.last
+ b.first.should.equal? a.first
+ b.last.should.equal? a.last
end
it "creates a new array containing all elements or the original" do
diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb
deleted file mode 100644
index 030302ced6..0000000000
--- a/spec/ruby/core/array/shared/collect.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-require_relative '../../enumerable/shared/enumeratorized'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
-
-describe :array_collect, shared: true do
- it "returns a copy of array with each element replaced by the value returned by block" do
- a = ['a', 'b', 'c', 'd']
- b = a.send(@method) { |i| i + '!' }
- b.should == ["a!", "b!", "c!", "d!"]
- b.should_not equal a
- end
-
- it "does not return subclass instance" do
- ArraySpecs::MyArray[1, 2, 3].send(@method) { |x| x + 1 }.should be_an_instance_of(Array)
- end
-
- it "does not change self" do
- a = ['a', 'b', 'c', 'd']
- a.send(@method) { |i| i + '!' }
- a.should == ['a', 'b', 'c', 'd']
- end
-
- it "returns the evaluated value of block if it broke in the block" do
- a = ['a', 'b', 'c', 'd']
- b = a.send(@method) {|i|
- if i == 'c'
- break 0
- else
- i + '!'
- end
- }
- b.should == 0
- end
-
- it "returns an Enumerator when no block given" do
- a = [1, 2, 3]
- a.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "raises an ArgumentError when no block and with arguments" do
- a = [1, 2, 3]
- -> {
- a.send(@method, :foo)
- }.should raise_error(ArgumentError)
- end
-
- before :all do
- @object = [1, 2, 3, 4]
- end
- it_should_behave_like :enumeratorized_with_origin_size
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
-end
-
-describe :array_collect_b, shared: true do
- it "replaces each element with the value returned by block" do
- a = [7, 9, 3, 5]
- a.send(@method) { |i| i - 1 }.should equal(a)
- a.should == [6, 8, 2, 4]
- end
-
- it "returns self" do
- a = [1, 2, 3, 4, 5]
- b = a.send(@method) {|i| i+1 }
- a.should equal b
- end
-
- it "returns the evaluated value of block but its contents is partially modified, if it broke in the block" do
- a = ['a', 'b', 'c', 'd']
- b = a.send(@method) {|i|
- if i == 'c'
- break 0
- else
- i + '!'
- end
- }
- b.should == 0
- a.should == ['a!', 'b!', 'c', 'd']
- end
-
- it "returns an Enumerator when no block given, and the enumerator can modify the original array" do
- a = [1, 2, 3]
- enum = a.send(@method)
- enum.should be_an_instance_of(Enumerator)
- enum.each{|i| "#{i}!" }
- a.should == ["1!", "2!", "3!"]
- end
-
- describe "when frozen" do
- it "raises a FrozenError" do
- -> { ArraySpecs.frozen_array.send(@method) {} }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError when empty" do
- -> { ArraySpecs.empty_frozen_array.send(@method) {} }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError when calling #each on the returned Enumerator" do
- enumerator = ArraySpecs.frozen_array.send(@method)
- -> { enumerator.each {|x| x } }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError when calling #each on the returned Enumerator when empty" do
- enumerator = ArraySpecs.empty_frozen_array.send(@method)
- -> { enumerator.each {|x| x } }.should raise_error(FrozenError)
- end
- end
-
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.send(@method) do |e|
- case e
- when 1 then -1
- when 2 then -2
- when 3 then raise StandardError, 'Oops'
- else 0
- end
- end
- rescue StandardError
- end
-
- a.should == [-1, -2, 3, 4]
- end
-
- before :all do
- @object = [1, 2, 3, 4]
- end
- it_should_behave_like :enumeratorized_with_origin_size
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
-end
diff --git a/spec/ruby/core/array/shared/difference.rb b/spec/ruby/core/array/shared/difference.rb
index 3e69050d82..3fe22331bd 100644
--- a/spec/ruby/core/array/shared/difference.rb
+++ b/spec/ruby/core/array/shared/difference.rb
@@ -27,13 +27,13 @@ describe :array_binary_difference, shared: true do
it "raises a TypeError if the argument cannot be coerced to an Array by calling #to_ary" do
obj = mock('not an array')
- -> { [1, 2, 3].send(@method, obj) }.should raise_error(TypeError)
+ -> { [1, 2, 3].send(@method, obj) }.should.raise(TypeError)
end
it "does not return subclass instance for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[]).should be_an_instance_of(Array)
- [1, 2, 3].send(@method, ArraySpecs::MyArray[]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, []).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[]).should.instance_of?(Array)
+ [1, 2, 3].send(@method, ArraySpecs::MyArray[]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/shared/enumeratorize.rb b/spec/ruby/core/array/shared/enumeratorize.rb
index a19a5d3b9b..5beab5c4c4 100644
--- a/spec/ruby/core/array/shared/enumeratorize.rb
+++ b/spec/ruby/core/array/shared/enumeratorize.rb
@@ -1,5 +1,5 @@
describe :enumeratorize, shared: true do
it "returns an Enumerator if no block given" do
- [1,2].send(@method).should be_an_instance_of(Enumerator)
+ [1,2].send(@method).should.instance_of?(Enumerator)
end
end
diff --git a/spec/ruby/core/array/shared/eql.rb b/spec/ruby/core/array/shared/eql.rb
index b5d9128434..5e770bf167 100644
--- a/spec/ruby/core/array/shared/eql.rb
+++ b/spec/ruby/core/array/shared/eql.rb
@@ -1,59 +1,59 @@
describe :array_eql, shared: true do
it "returns true if other is the same array" do
a = [1]
- a.send(@method, a).should be_true
+ a.send(@method, a).should == true
end
it "returns true if corresponding elements are #eql?" do
- [].send(@method, []).should be_true
- [1, 2, 3, 4].send(@method, [1, 2, 3, 4]).should be_true
+ [].send(@method, []).should == true
+ [1, 2, 3, 4].send(@method, [1, 2, 3, 4]).should == true
end
it "returns false if other is shorter than self" do
- [1, 2, 3, 4].send(@method, [1, 2, 3]).should be_false
+ [1, 2, 3, 4].send(@method, [1, 2, 3]).should == false
end
it "returns false if other is longer than self" do
- [1, 2, 3, 4].send(@method, [1, 2, 3, 4, 5]).should be_false
+ [1, 2, 3, 4].send(@method, [1, 2, 3, 4, 5]).should == false
end
it "returns false immediately when sizes of the arrays differ" do
obj = mock('1')
obj.should_not_receive(@method)
- [] .send(@method, [obj] ).should be_false
- [obj] .send(@method, [] ).should be_false
+ [] .send(@method, [obj] ).should == false
+ [obj] .send(@method, [] ).should == false
end
it "handles well recursive arrays" do
a = ArraySpecs.empty_recursive_array
- a .send(@method, [a] ).should be_true
- a .send(@method, [[a]] ).should be_true
- [a] .send(@method, a ).should be_true
- [[a]] .send(@method, a ).should be_true
+ a .send(@method, [a] ).should == true
+ a .send(@method, [[a]] ).should == true
+ [a] .send(@method, a ).should == true
+ [[a]] .send(@method, a ).should == true
# These may be surprising, but no difference can be
# found between these arrays, so they are ==.
# There is no "path" that will lead to a difference
# (contrary to other examples below)
a2 = ArraySpecs.empty_recursive_array
- a .send(@method, a2 ).should be_true
- a .send(@method, [a2] ).should be_true
- a .send(@method, [[a2]] ).should be_true
- [a] .send(@method, a2 ).should be_true
- [[a]] .send(@method, a2 ).should be_true
+ a .send(@method, a2 ).should == true
+ a .send(@method, [a2] ).should == true
+ a .send(@method, [[a2]] ).should == true
+ [a] .send(@method, a2 ).should == true
+ [[a]] .send(@method, a2 ).should == true
back = []
forth = [back]; back << forth;
- back .send(@method, a ).should be_true
+ back .send(@method, a ).should == true
x = []; x << x << x
- x .send(@method, a ).should be_false # since x.size != a.size
- x .send(@method, [a, a] ).should be_false # since x[0].size != [a, a][0].size
- x .send(@method, [x, a] ).should be_false # since x[1].size != [x, a][1].size
- [x, a] .send(@method, [a, x] ).should be_false # etc...
- x .send(@method, [x, x] ).should be_true
- x .send(@method, [[x, x], [x, x]] ).should be_true
+ x .send(@method, a ).should == false # since x.size != a.size
+ x .send(@method, [a, a] ).should == false # since x[0].size != [a, a][0].size
+ x .send(@method, [x, a] ).should == false # since x[1].size != [x, a][1].size
+ [x, a] .send(@method, [a, x] ).should == false # etc...
+ x .send(@method, [x, x] ).should == true
+ x .send(@method, [[x, x], [x, x]] ).should == true
tree = [];
branch = []; branch << tree << tree; tree << branch
@@ -62,31 +62,31 @@ describe :array_eql, shared: true do
forest = [tree, branch, :bird, a]; forest << forest
forest2 = [tree2, branch2, :bird, a2]; forest2 << forest2
- forest .send(@method, forest2 ).should be_true
- forest .send(@method, [tree2, branch, :bird, a, forest2]).should be_true
+ forest .send(@method, forest2 ).should == true
+ forest .send(@method, [tree2, branch, :bird, a, forest2]).should == true
diffforest = [branch2, tree2, :bird, a2]; diffforest << forest2
- forest .send(@method, diffforest ).should be_false # since forest[0].size == 1 != 3 == diffforest[0]
- forest .send(@method, [nil] ).should be_false
- forest .send(@method, [forest] ).should be_false
+ forest .send(@method, diffforest ).should == false # since forest[0].size == 1 != 3 == diffforest[0]
+ forest .send(@method, [nil] ).should == false
+ forest .send(@method, [forest] ).should == false
end
it "does not call #to_ary on its argument" do
obj = mock('to_ary')
obj.should_not_receive(:to_ary)
- [1, 2, 3].send(@method, obj).should be_false
+ [1, 2, 3].send(@method, obj).should == false
end
it "does not call #to_ary on Array subclasses" do
ary = ArraySpecs::ToAryArray[5, 6, 7]
ary.should_not_receive(:to_ary)
- [5, 6, 7].send(@method, ary).should be_true
+ [5, 6, 7].send(@method, ary).should == true
end
it "ignores array class differences" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, [1, 2, 3]).should be_true
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_true
- [1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_true
+ ArraySpecs::MyArray[1, 2, 3].send(@method, [1, 2, 3]).should == true
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should == true
+ [1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should == true
end
end
diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb
deleted file mode 100644
index a4a0adbab6..0000000000
--- a/spec/ruby/core/array/shared/index.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../shared/iterable_and_tolerating_size_increasing'
-
-describe :array_index, shared: true do
- it "returns the index of the first element == to object" do
- x = mock('3')
- def x.==(obj) 3 == obj; end
-
- [2, x, 3, 1, 3, 1].send(@method, 3).should == 1
- [2, 3.0, 3, x, 1, 3, 1].send(@method, x).should == 1
- end
-
- it "returns 0 if first element == to object" do
- [2, 1, 3, 2, 5].send(@method, 2).should == 0
- end
-
- it "returns size-1 if only last element == to object" do
- [2, 1, 3, 1, 5].send(@method, 5).should == 4
- end
-
- it "returns nil if no element == to object" do
- [2, 1, 1, 1, 1].send(@method, 3).should == nil
- end
-
- it "accepts a block instead of an argument" do
- [4, 2, 1, 5, 1, 3].send(@method) {|x| x < 2}.should == 2
- end
-
- it "ignores the block if there is an argument" do
- -> {
- [4, 2, 1, 5, 1, 3].send(@method, 5) {|x| x < 2}.should == 3
- }.should complain(/given block not used/)
- end
-
- describe "given no argument and no block" do
- it "produces an Enumerator" do
- [].send(@method).should be_an_instance_of(Enumerator)
- end
- end
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
-end
diff --git a/spec/ruby/core/array/shared/inspect.rb b/spec/ruby/core/array/shared/inspect.rb
deleted file mode 100644
index af5128c645..0000000000
--- a/spec/ruby/core/array/shared/inspect.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-require_relative '../fixtures/encoded_strings'
-
-describe :array_inspect, shared: true do
- it "returns a string" do
- [1, 2, 3].send(@method).should be_an_instance_of(String)
- end
-
- it "returns '[]' for an empty Array" do
- [].send(@method).should == "[]"
- end
-
- it "calls inspect on its elements and joins the results with commas" do
- items = Array.new(3) do |i|
- obj = mock(i.to_s)
- obj.should_receive(:inspect).and_return(i.to_s)
- obj
- end
- items.send(@method).should == "[0, 1, 2]"
- end
-
- it "does not call #to_s on a String returned from #inspect" do
- str = +"abc"
- str.should_not_receive(:to_s)
-
- [str].send(@method).should == '["abc"]'
- end
-
- it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
- obj = mock("Array#inspect/to_s calls #to_s")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_return("abc")
-
- [obj].send(@method).should == "[abc]"
- end
-
- it "does not call #to_str on the object returned from #inspect when it is not a String" do
- obj = mock("Array#inspect/to_s does not call #to_str")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_not_receive(:to_str)
-
- [obj].send(@method).should =~ /^\[#<MockObject:0x[0-9a-f]+>\]$/
- end
-
- it "does not call #to_str on the object returned from #to_s when it is not a String" do
- obj = mock("Array#inspect/to_s does not call #to_str on #to_s result")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_return(obj)
- obj.should_not_receive(:to_str)
-
- [obj].send(@method).should =~ /^\[#<MockObject:0x[0-9a-f]+>\]$/
- end
-
- it "does not swallow exceptions raised by #to_s" do
- obj = mock("Array#inspect/to_s does not swallow #to_s exceptions")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_raise(Exception)
-
- -> { [obj].send(@method) }.should raise_error(Exception)
- end
-
- it "represents a recursive element with '[...]'" do
- ArraySpecs.recursive_array.send(@method).should == "[1, \"two\", 3.0, [...], [...], [...], [...], [...]]"
- ArraySpecs.head_recursive_array.send(@method).should == "[[...], [...], [...], [...], [...], 1, \"two\", 3.0]"
- ArraySpecs.empty_recursive_array.send(@method).should == "[[...]]"
- end
-
- describe "with encoding" do
- before :each do
- @default_external_encoding = Encoding.default_external
- end
-
- after :each do
- Encoding.default_external = @default_external_encoding
- end
-
- it "returns a US-ASCII string for an empty Array" do
- [].send(@method).encoding.should == Encoding::US_ASCII
- end
-
- it "use the default external encoding if it is ascii compatible" do
- Encoding.default_external = Encoding.find('UTF-8')
-
- utf8 = "utf8".encode("UTF-8")
- jp = "jp".encode("EUC-JP")
- array = [jp, utf8]
-
- array.send(@method).encoding.name.should == "UTF-8"
- end
-
- it "use US-ASCII encoding if the default external encoding is not ascii compatible" do
- Encoding.default_external = Encoding.find('UTF-32')
-
- utf8 = "utf8".encode("UTF-8")
- jp = "jp".encode("EUC-JP")
- array = [jp, utf8]
-
- array.send(@method).encoding.name.should == "US-ASCII"
- end
-
- it "does not raise if inspected result is not default external encoding" do
- utf_16be = mock(+"utf_16be")
- utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
-
- [utf_16be].send(@method).should == '["utf_16be \u3042"]'
- end
- end
-end
diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb
index 0b4166ab63..dda72e8bd7 100644
--- a/spec/ruby/core/array/shared/intersection.rb
+++ b/spec/ruby/core/array/shared/intersection.rb
@@ -66,9 +66,9 @@ describe :array_intersection, shared: true do
end
it "does return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
- [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, []).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
+ [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/shared/join.rb b/spec/ruby/core/array/shared/join.rb
index 507b13e3c8..93d5329ee3 100644
--- a/spec/ruby/core/array/shared/join.rb
+++ b/spec/ruby/core/array/shared/join.rb
@@ -1,103 +1,6 @@
require_relative '../fixtures/classes'
require_relative '../fixtures/encoded_strings'
-describe :array_join_with_default_separator, shared: true do
- before :each do
- @separator = $,
- end
-
- after :each do
- $, = @separator
- end
-
- it "returns an empty string if the Array is empty" do
- [].send(@method).should == ''
- end
-
- it "returns a US-ASCII string for an empty Array" do
- [].send(@method).encoding.should == Encoding::US_ASCII
- end
-
- it "returns a string formed by concatenating each String element separated by $," do
- suppress_warning {
- $, = " | "
- ["1", "2", "3"].send(@method).should == "1 | 2 | 3"
- }
- end
-
- it "attempts coercion via #to_str first" do
- obj = mock('foo')
- obj.should_receive(:to_str).any_number_of_times.and_return("foo")
- [obj].send(@method).should == "foo"
- end
-
- it "attempts coercion via #to_ary second" do
- obj = mock('foo')
- obj.should_receive(:to_str).any_number_of_times.and_return(nil)
- obj.should_receive(:to_ary).any_number_of_times.and_return(["foo"])
- [obj].send(@method).should == "foo"
- end
-
- it "attempts coercion via #to_s third" do
- obj = mock('foo')
- obj.should_receive(:to_str).any_number_of_times.and_return(nil)
- obj.should_receive(:to_ary).any_number_of_times.and_return(nil)
- obj.should_receive(:to_s).any_number_of_times.and_return("foo")
- [obj].send(@method).should == "foo"
- end
-
- it "raises a NoMethodError if an element does not respond to #to_str, #to_ary, or #to_s" do
- obj = mock('o')
- class << obj; undef :to_s; end
- -> { [1, obj].send(@method) }.should raise_error(NoMethodError)
- end
-
- it "raises an ArgumentError when the Array is recursive" do
- -> { ArraySpecs.recursive_array.send(@method) }.should raise_error(ArgumentError)
- -> { ArraySpecs.head_recursive_array.send(@method) }.should raise_error(ArgumentError)
- -> { ArraySpecs.empty_recursive_array.send(@method) }.should raise_error(ArgumentError)
- end
-
- it "uses the first encoding when other strings are compatible" do
- ary1 = ArraySpecs.array_with_7bit_utf8_and_usascii_strings
- ary2 = ArraySpecs.array_with_usascii_and_7bit_utf8_strings
- ary3 = ArraySpecs.array_with_utf8_and_7bit_binary_strings
- ary4 = ArraySpecs.array_with_usascii_and_7bit_binary_strings
-
- ary1.send(@method).encoding.should == Encoding::UTF_8
- ary2.send(@method).encoding.should == Encoding::US_ASCII
- ary3.send(@method).encoding.should == Encoding::UTF_8
- ary4.send(@method).encoding.should == Encoding::US_ASCII
- end
-
- it "uses the widest common encoding when other strings are incompatible" do
- ary1 = ArraySpecs.array_with_utf8_and_usascii_strings
- ary2 = ArraySpecs.array_with_usascii_and_utf8_strings
-
- ary1.send(@method).encoding.should == Encoding::UTF_8
- ary2.send(@method).encoding.should == Encoding::UTF_8
- end
-
- it "fails for arrays with incompatibly-encoded strings" do
- ary_utf8_bad_binary = ArraySpecs.array_with_utf8_and_binary_strings
-
- -> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError)
- end
-
- context "when $, is not nil" do
- before do
- suppress_warning do
- $, = '*'
- end
- end
-
- it "warns" do
- -> { [].join }.should complain(/warning: \$, is set to non-nil value/)
- -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/)
- end
- end
-end
-
describe :array_join_with_string_separator, shared: true do
it "returns a string formed by concatenating each element.to_str separated by separator" do
obj = mock('foo')
diff --git a/spec/ruby/core/array/shared/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb
index 43a047c0a7..44625eebd1 100644
--- a/spec/ruby/core/array/shared/keep_if.rb
+++ b/spec/ruby/core/array/shared/keep_if.rb
@@ -4,12 +4,12 @@ require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :keep_if, shared: true do
it "deletes elements for which the block returns a false value" do
array = [1, 2, 3, 4, 5]
- array.send(@method) {|item| item > 3 }.should equal(array)
+ array.send(@method) {|item| item > 3 }.should.equal?(array)
array.should == [4, 5]
end
it "returns an enumerator if no block is given" do
- [1, 2, 3].send(@method).should be_an_instance_of(Enumerator)
+ [1, 2, 3].send(@method).should.instance_of?(Enumerator)
end
it "updates the receiver after all blocks" do
@@ -33,34 +33,34 @@ describe :keep_if, shared: true do
end
it "returns an Enumerator if no block is given" do
- @frozen.send(@method).should be_an_instance_of(Enumerator)
+ @frozen.send(@method).should.instance_of?(Enumerator)
end
describe "with truthy block" do
it "keeps elements after any exception" do
- -> { @frozen.send(@method) { true } }.should raise_error(Exception)
+ -> { @frozen.send(@method) { true } }.should.raise(Exception)
@frozen.should == @origin
end
it "raises a FrozenError" do
- -> { @frozen.send(@method) { true } }.should raise_error(FrozenError)
+ -> { @frozen.send(@method) { true } }.should.raise(FrozenError)
end
end
describe "with falsy block" do
it "keeps elements after any exception" do
- -> { @frozen.send(@method) { false } }.should raise_error(Exception)
+ -> { @frozen.send(@method) { false } }.should.raise(Exception)
@frozen.should == @origin
end
it "raises a FrozenError" do
- -> { @frozen.send(@method) { false } }.should raise_error(FrozenError)
+ -> { @frozen.send(@method) { false } }.should.raise(FrozenError)
end
end
it "raises a FrozenError on a frozen array only during iteration if called without a block" do
enum = @frozen.send(@method)
- -> { enum.each {} }.should raise_error(FrozenError)
+ -> { enum.each {} }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/array/shared/length.rb b/spec/ruby/core/array/shared/length.rb
deleted file mode 100644
index f84966d0ba..0000000000
--- a/spec/ruby/core/array/shared/length.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-describe :array_length, shared: true do
- it "returns the number of elements" do
- [].send(@method).should == 0
- [1, 2, 3].send(@method).should == 3
- end
-
- it "properly handles recursive arrays" do
- ArraySpecs.empty_recursive_array.send(@method).should == 1
- ArraySpecs.recursive_array.send(@method).should == 8
- end
-end
diff --git a/spec/ruby/core/array/shared/push.rb b/spec/ruby/core/array/shared/push.rb
deleted file mode 100644
index ac790fb6a4..0000000000
--- a/spec/ruby/core/array/shared/push.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-describe :array_push, shared: true do
- it "appends the arguments to the array" do
- a = [ "a", "b", "c" ]
- a.send(@method, "d", "e", "f").should equal(a)
- a.send(@method).should == ["a", "b", "c", "d", "e", "f"]
- a.send(@method, 5)
- a.should == ["a", "b", "c", "d", "e", "f", 5]
-
- a = [0, 1]
- a.send(@method, 2)
- a.should == [0, 1, 2]
- end
-
- it "isn't confused by previous shift" do
- a = [ "a", "b", "c" ]
- a.shift
- a.send(@method, "foo")
- a.should == ["b", "c", "foo"]
- end
-
- it "properly handles recursive arrays" do
- empty = ArraySpecs.empty_recursive_array
- empty.send(@method, :last).should == [empty, :last]
-
- array = ArraySpecs.recursive_array
- array.send(@method, :last).should == [1, 'two', 3.0, array, array, array, array, array, :last]
- end
-
- it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(FrozenError)
- -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError)
- end
-end
diff --git a/spec/ruby/core/array/shared/replace.rb b/spec/ruby/core/array/shared/replace.rb
deleted file mode 100644
index 9a6e60c1b0..0000000000
--- a/spec/ruby/core/array/shared/replace.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-describe :array_replace, shared: true do
- it "replaces the elements with elements from other array" do
- a = [1, 2, 3, 4, 5]
- b = ['a', 'b', 'c']
- a.send(@method, b).should equal(a)
- a.should == b
- a.should_not equal(b)
-
- a.send(@method, [4] * 10)
- a.should == [4] * 10
-
- a.send(@method, [])
- a.should == []
- end
-
- it "properly handles recursive arrays" do
- orig = [1, 2, 3]
- empty = ArraySpecs.empty_recursive_array
- orig.send(@method, empty)
- orig.should == empty
-
- array = ArraySpecs.recursive_array
- orig.send(@method, array)
- orig.should == array
- end
-
- it "returns self" do
- ary = [1, 2, 3]
- other = [:a, :b, :c]
- ary.send(@method, other).should equal(ary)
- end
-
- it "does not make self dependent to the original array" do
- ary = [1, 2, 3]
- other = [:a, :b, :c]
- ary.send(@method, other)
- ary.should == [:a, :b, :c]
- ary << :d
- ary.should == [:a, :b, :c, :d]
- other.should == [:a, :b, :c]
- end
-
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('to_ary')
- obj.stub!(:to_ary).and_return([1, 2, 3])
- [].send(@method, obj).should == [1, 2, 3]
- end
-
- it "does not call #to_ary on Array subclasses" do
- obj = ArraySpecs::ToAryArray[5, 6, 7]
- obj.should_not_receive(:to_ary)
- [].send(@method, ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7]
- end
-
- it "raises a FrozenError on a frozen array" do
- -> {
- ArraySpecs.frozen_array.send(@method, ArraySpecs.frozen_array)
- }.should raise_error(FrozenError)
- end
-end
diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb
deleted file mode 100644
index 9c2cbf76c4..0000000000
--- a/spec/ruby/core/array/shared/select.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/enumeratorize'
-require_relative '../shared/keep_if'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
-require_relative '../../enumerable/shared/enumeratorized'
-
-describe :array_select, shared: true do
- it_should_behave_like :enumeratorize
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
-
- before :each do
- @object = [1,2,3]
- end
- it_should_behave_like :enumeratorized_with_origin_size
-
- it "returns a new array of elements for which block is true" do
- [1, 3, 4, 5, 6, 9].send(@method) { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6]
- end
-
- it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method) { true }.should be_an_instance_of(Array)
- end
-
- it "properly handles recursive arrays" do
- empty = ArraySpecs.empty_recursive_array
- empty.send(@method) { true }.should == empty
- empty.send(@method) { false }.should == []
-
- array = ArraySpecs.recursive_array
- array.send(@method) { true }.should == [1, 'two', 3.0, array, array, array, array, array]
- array.send(@method) { false }.should == []
- end
-end
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
deleted file mode 100644
index d2866970a5..0000000000
--- a/spec/ruby/core/array/shared/slice.rb
+++ /dev/null
@@ -1,859 +0,0 @@
-describe :array_slice, shared: true do
- it "returns the element at index with [index]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 1).should == "b"
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0).should == 1
- a.send(@method, 1).should == 2
- a.send(@method, 2).should == 3
- a.send(@method, 3).should == 4
- a.send(@method, 4).should == nil
- a.send(@method, 10).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns the element at index from the end of the array with [-index]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -2).should == "d"
-
- a = [1, 2, 3, 4]
-
- a.send(@method, -1).should == 4
- a.send(@method, -2).should == 3
- a.send(@method, -3).should == 2
- a.send(@method, -4).should == 1
- a.send(@method, -5).should == nil
- a.send(@method, -10).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns count elements starting from index with [index, count]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 2, 3).should == ["c", "d", "e"]
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0, 0).should == []
- a.send(@method, 0, 1).should == [1]
- a.send(@method, 0, 2).should == [1, 2]
- a.send(@method, 0, 4).should == [1, 2, 3, 4]
- a.send(@method, 0, 6).should == [1, 2, 3, 4]
- a.send(@method, 0, -1).should == nil
- a.send(@method, 0, -2).should == nil
- a.send(@method, 0, -4).should == nil
-
- a.send(@method, 2, 0).should == []
- a.send(@method, 2, 1).should == [3]
- a.send(@method, 2, 2).should == [3, 4]
- a.send(@method, 2, 4).should == [3, 4]
- a.send(@method, 2, -1).should == nil
-
- a.send(@method, 4, 0).should == []
- a.send(@method, 4, 2).should == []
- a.send(@method, 4, -1).should == nil
-
- a.send(@method, 5, 0).should == nil
- a.send(@method, 5, 2).should == nil
- a.send(@method, 5, -1).should == nil
-
- a.send(@method, 6, 0).should == nil
- a.send(@method, 6, 2).should == nil
- a.send(@method, 6, -1).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns count elements starting at index from the end of array with [-index, count]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -2, 2).should == ["d", "e"]
-
- a = [1, 2, 3, 4]
-
- a.send(@method, -1, 0).should == []
- a.send(@method, -1, 1).should == [4]
- a.send(@method, -1, 2).should == [4]
- a.send(@method, -1, -1).should == nil
-
- a.send(@method, -2, 0).should == []
- a.send(@method, -2, 1).should == [3]
- a.send(@method, -2, 2).should == [3, 4]
- a.send(@method, -2, 4).should == [3, 4]
- a.send(@method, -2, -1).should == nil
-
- a.send(@method, -4, 0).should == []
- a.send(@method, -4, 1).should == [1]
- a.send(@method, -4, 2).should == [1, 2]
- a.send(@method, -4, 4).should == [1, 2, 3, 4]
- a.send(@method, -4, 6).should == [1, 2, 3, 4]
- a.send(@method, -4, -1).should == nil
-
- a.send(@method, -5, 0).should == nil
- a.send(@method, -5, 1).should == nil
- a.send(@method, -5, 10).should == nil
- a.send(@method, -5, -1).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns the first count elements with [0, count]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 0, 3).should == ["a", "b", "c"]
- end
-
- it "returns the subarray which is independent to self with [index,count]" do
- a = [1, 2, 3]
- sub = a.send(@method, 1,2)
- sub.replace([:a, :b])
- a.should == [1, 2, 3]
- end
-
- it "tries to convert the passed argument to an Integer using #to_int" do
- obj = mock('to_int')
- obj.stub!(:to_int).and_return(2)
-
- a = [1, 2, 3, 4]
- a.send(@method, obj).should == 3
- a.send(@method, obj, 1).should == [3]
- a.send(@method, obj, obj).should == [3, 4]
- a.send(@method, 0, obj).should == [1, 2]
- end
-
- it "raises TypeError if to_int returns non-integer" do
- from = mock('from')
- to = mock('to')
-
- # So we can construct a range out of them...
- def from.<=>(o) 0 end
- def to.<=>(o) 0 end
-
- a = [1, 2, 3, 4, 5]
-
- def from.to_int() 'cat' end
- def to.to_int() -2 end
-
- -> { a.send(@method, from..to) }.should raise_error(TypeError)
-
- def from.to_int() 1 end
- def to.to_int() 'cat' end
-
- -> { a.send(@method, from..to) }.should raise_error(TypeError)
- end
-
- it "returns the elements specified by Range indexes with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 1..3).should == ["b", "c", "d"]
- [ "a", "b", "c", "d", "e" ].send(@method, 4..-1).should == ['e']
- [ "a", "b", "c", "d", "e" ].send(@method, 3..3).should == ['d']
- [ "a", "b", "c", "d", "e" ].send(@method, 3..-2).should == ['d']
- ['a'].send(@method, 0..-1).should == ['a']
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0..-10).should == []
- a.send(@method, 0..0).should == [1]
- a.send(@method, 0..1).should == [1, 2]
- a.send(@method, 0..2).should == [1, 2, 3]
- a.send(@method, 0..3).should == [1, 2, 3, 4]
- a.send(@method, 0..4).should == [1, 2, 3, 4]
- a.send(@method, 0..10).should == [1, 2, 3, 4]
-
- a.send(@method, 2..-10).should == []
- a.send(@method, 2..0).should == []
- a.send(@method, 2..2).should == [3]
- a.send(@method, 2..3).should == [3, 4]
- a.send(@method, 2..4).should == [3, 4]
-
- a.send(@method, 3..0).should == []
- a.send(@method, 3..3).should == [4]
- a.send(@method, 3..4).should == [4]
-
- a.send(@method, 4..0).should == []
- a.send(@method, 4..4).should == []
- a.send(@method, 4..5).should == []
-
- a.send(@method, 5..0).should == nil
- a.send(@method, 5..5).should == nil
- a.send(@method, 5..6).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns elements specified by Range indexes except the element at index n with [m...n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 1...3).should == ["b", "c"]
-
- a = [1, 2, 3, 4]
-
- a.send(@method, 0...-10).should == []
- a.send(@method, 0...0).should == []
- a.send(@method, 0...1).should == [1]
- a.send(@method, 0...2).should == [1, 2]
- a.send(@method, 0...3).should == [1, 2, 3]
- a.send(@method, 0...4).should == [1, 2, 3, 4]
- a.send(@method, 0...10).should == [1, 2, 3, 4]
-
- a.send(@method, 2...-10).should == []
- a.send(@method, 2...0).should == []
- a.send(@method, 2...2).should == []
- a.send(@method, 2...3).should == [3]
- a.send(@method, 2...4).should == [3, 4]
-
- a.send(@method, 3...0).should == []
- a.send(@method, 3...3).should == []
- a.send(@method, 3...4).should == [4]
-
- a.send(@method, 4...0).should == []
- a.send(@method, 4...4).should == []
- a.send(@method, 4...5).should == []
-
- a.send(@method, 5...0).should == nil
- a.send(@method, 5...5).should == nil
- a.send(@method, 5...6).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns elements that exist if range start is in the array but range end is not with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 4..7).should == ["e"]
- end
-
- it "accepts Range instances having a negative m and both signs for n with [m..n] and [m...n]" do
- a = [1, 2, 3, 4]
-
- a.send(@method, -1..-1).should == [4]
- a.send(@method, -1...-1).should == []
- a.send(@method, -1..3).should == [4]
- a.send(@method, -1...3).should == []
- a.send(@method, -1..4).should == [4]
- a.send(@method, -1...4).should == [4]
- a.send(@method, -1..10).should == [4]
- a.send(@method, -1...10).should == [4]
- a.send(@method, -1..0).should == []
- a.send(@method, -1..-4).should == []
- a.send(@method, -1...-4).should == []
- a.send(@method, -1..-6).should == []
- a.send(@method, -1...-6).should == []
-
- a.send(@method, -2..-2).should == [3]
- a.send(@method, -2...-2).should == []
- a.send(@method, -2..-1).should == [3, 4]
- a.send(@method, -2...-1).should == [3]
- a.send(@method, -2..10).should == [3, 4]
- a.send(@method, -2...10).should == [3, 4]
-
- a.send(@method, -4..-4).should == [1]
- a.send(@method, -4..-2).should == [1, 2, 3]
- a.send(@method, -4...-2).should == [1, 2]
- a.send(@method, -4..-1).should == [1, 2, 3, 4]
- a.send(@method, -4...-1).should == [1, 2, 3]
- a.send(@method, -4..3).should == [1, 2, 3, 4]
- a.send(@method, -4...3).should == [1, 2, 3]
- a.send(@method, -4..4).should == [1, 2, 3, 4]
- a.send(@method, -4...4).should == [1, 2, 3, 4]
- a.send(@method, -4...4).should == [1, 2, 3, 4]
- a.send(@method, -4..0).should == [1]
- a.send(@method, -4...0).should == []
- a.send(@method, -4..1).should == [1, 2]
- a.send(@method, -4...1).should == [1]
-
- a.send(@method, -5..-5).should == nil
- a.send(@method, -5...-5).should == nil
- a.send(@method, -5..-4).should == nil
- a.send(@method, -5..-1).should == nil
- a.send(@method, -5..10).should == nil
-
- a.should == [1, 2, 3, 4]
- end
-
- it "returns the subarray which is independent to self with [m..n]" do
- a = [1, 2, 3]
- sub = a.send(@method, 1..2)
- sub.replace([:a, :b])
- a.should == [1, 2, 3]
- end
-
- it "tries to convert Range elements to Integers using #to_int with [m..n] and [m...n]" do
- from = mock('from')
- to = mock('to')
-
- # So we can construct a range out of them...
- def from.<=>(o) 0 end
- def to.<=>(o) 0 end
-
- def from.to_int() 1 end
- def to.to_int() -2 end
-
- a = [1, 2, 3, 4]
-
- a.send(@method, from..to).should == [2, 3]
- a.send(@method, from...to).should == [2]
- a.send(@method, 1..0).should == []
- a.send(@method, 1...0).should == []
-
- -> { a.send(@method, "a" .. "b") }.should raise_error(TypeError)
- -> { a.send(@method, "a" ... "b") }.should raise_error(TypeError)
- -> { a.send(@method, from .. "b") }.should raise_error(TypeError)
- -> { a.send(@method, from ... "b") }.should raise_error(TypeError)
- end
-
- it "returns the same elements as [m..n] and [m...n] with Range subclasses" do
- a = [1, 2, 3, 4]
- range_incl = ArraySpecs::MyRange.new(1, 2)
- range_excl = ArraySpecs::MyRange.new(-3, -1, true)
-
- a.send(@method, range_incl).should == [2, 3]
- a.send(@method, range_excl).should == [2, 3]
- end
-
- it "returns nil for a requested index not in the array with [index]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 5).should == nil
- end
-
- it "returns [] if the index is valid but length is zero with [index, length]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 0, 0).should == []
- [ "a", "b", "c", "d", "e" ].send(@method, 2, 0).should == []
- end
-
- it "returns nil if length is zero but index is invalid with [index, length]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 100, 0).should == nil
- [ "a", "b", "c", "d", "e" ].send(@method, -50, 0).should == nil
- end
-
- # This is by design. It is in the official documentation.
- it "returns [] if index == array.size with [index, length]" do
- %w|a b c d e|.send(@method, 5, 2).should == []
- end
-
- it "returns nil if index > array.size with [index, length]" do
- %w|a b c d e|.send(@method, 6, 2).should == nil
- end
-
- it "returns nil if length is negative with [index, length]" do
- %w|a b c d e|.send(@method, 3, -1).should == nil
- %w|a b c d e|.send(@method, 2, -2).should == nil
- %w|a b c d e|.send(@method, 1, -100).should == nil
- end
-
- it "returns nil if no requested index is in the array with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, 6..10).should == nil
- end
-
- it "returns nil if range start is not in the array with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -10..2).should == nil
- [ "a", "b", "c", "d", "e" ].send(@method, 10..12).should == nil
- end
-
- it "returns an empty array when m == n with [m...n]" do
- [1, 2, 3, 4, 5].send(@method, 1...1).should == []
- end
-
- it "returns an empty array with [0...0]" do
- [1, 2, 3, 4, 5].send(@method, 0...0).should == []
- end
-
- it "returns a subarray where m, n negatives and m < n with [m..n]" do
- [ "a", "b", "c", "d", "e" ].send(@method, -3..-2).should == ["c", "d"]
- end
-
- it "returns an array containing the first element with [0..0]" do
- [1, 2, 3, 4, 5].send(@method, 0..0).should == [1]
- end
-
- it "returns the entire array with [0..-1]" do
- [1, 2, 3, 4, 5].send(@method, 0..-1).should == [1, 2, 3, 4, 5]
- end
-
- it "returns all but the last element with [0...-1]" do
- [1, 2, 3, 4, 5].send(@method, 0...-1).should == [1, 2, 3, 4]
- end
-
- it "returns [3] for [2..-1] out of [1, 2, 3]" do
- [1,2,3].send(@method, 2..-1).should == [3]
- end
-
- it "returns an empty array when m > n and m, n are positive with [m..n]" do
- [1, 2, 3, 4, 5].send(@method, 3..2).should == []
- end
-
- it "returns an empty array when m > n and m, n are negative with [m..n]" do
- [1, 2, 3, 4, 5].send(@method, -2..-3).should == []
- end
-
- it "does not expand array when the indices are outside of the array bounds" do
- a = [1, 2]
- a.send(@method, 4).should == nil
- a.should == [1, 2]
- a.send(@method, 4, 0).should == nil
- a.should == [1, 2]
- a.send(@method, 6, 1).should == nil
- a.should == [1, 2]
- a.send(@method, 8...8).should == nil
- a.should == [1, 2]
- a.send(@method, 10..10).should == nil
- a.should == [1, 2]
- end
-
- describe "with a subclass of Array" do
- before :each do
- ScratchPad.clear
-
- @array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
- end
-
- it "returns a Array instance with [n, m]" do
- @array.send(@method, 0, 2).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [-n, m]" do
- @array.send(@method, -3, 2).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [n..m]" do
- @array.send(@method, 1..3).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [n...m]" do
- @array.send(@method, 1...3).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [-n..-m]" do
- @array.send(@method, -3..-1).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [-n...-m]" do
- @array.send(@method, -3...-1).should be_an_instance_of(Array)
- end
-
- it "returns an empty array when m == n with [m...n]" do
- @array.send(@method, 1...1).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns an empty array with [0...0]" do
- @array.send(@method, 0...0).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns an empty array when m > n and m, n are positive with [m..n]" do
- @array.send(@method, 3..2).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns an empty array when m > n and m, n are negative with [m..n]" do
- @array.send(@method, -2..-3).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns [] if index == array.size with [index, length]" do
- @array.send(@method, 5, 2).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "returns [] if the index is valid but length is zero with [index, length]" do
- @array.send(@method, 0, 0).should == []
- @array.send(@method, 2, 0).should == []
- ScratchPad.recorded.should be_nil
- end
-
- it "does not call #initialize on the subclass instance" do
- @array.send(@method, 0, 3).should == [1, 2, 3]
- ScratchPad.recorded.should be_nil
- end
- end
-
- it "raises a RangeError when the start index is out of range of Fixnum" do
- array = [1, 2, 3, 4, 5, 6]
- obj = mock('large value')
- obj.should_receive(:to_int).and_return(bignum_value)
- -> { array.send(@method, obj) }.should raise_error(RangeError)
-
- obj = 8e19
- -> { array.send(@method, obj) }.should raise_error(RangeError)
-
- # boundary value when longs are 64 bits
- -> { array.send(@method, 2.0**63) }.should raise_error(RangeError)
-
- # just under the boundary value when longs are 64 bits
- array.send(@method, max_long.to_f.prev_float).should == nil
- end
-
- it "raises a RangeError when the length is out of range of Fixnum" do
- array = [1, 2, 3, 4, 5, 6]
- obj = mock('large value')
- obj.should_receive(:to_int).and_return(bignum_value)
- -> { array.send(@method, 1, obj) }.should raise_error(RangeError)
-
- obj = 8e19
- -> { array.send(@method, 1, obj) }.should raise_error(RangeError)
- end
-
- it "raises a type error if a range is passed with a length" do
- ->{ [1, 2, 3].send(@method, 1..2, 1) }.should raise_error(TypeError)
- end
-
- it "raises a RangeError if passed a range with a bound that is too large" do
- array = [1, 2, 3, 4, 5, 6]
- -> { array.send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
- -> { array.send(@method, 0..bignum_value) }.should raise_error(RangeError)
- end
-
- it "can accept endless ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(2..)")).should == [2, 3, 4, 5]
- a.send(@method, eval("(2...)")).should == [2, 3, 4, 5]
- a.send(@method, eval("(-2..)")).should == [4, 5]
- a.send(@method, eval("(-2...)")).should == [4, 5]
- a.send(@method, eval("(9..)")).should == nil
- a.send(@method, eval("(9...)")).should == nil
- a.send(@method, eval("(-9..)")).should == nil
- a.send(@method, eval("(-9...)")).should == nil
- end
-
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- before :each do
- @array = [0, 1, 2, 3, 4, 5]
- end
-
- it "has endless range and positive steps" do
- @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
- @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
- @array.send(@method, eval("(0..).step(10)")).should == [0]
-
- @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
- @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
- @array.send(@method, eval("(2..).step(10)")).should == [2]
-
- @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
- @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
- @array.send(@method, eval("(-3..).step(10)")).should == [3]
- end
-
- it "has beginless range and positive steps" do
- # end with zero index
- @array.send(@method, (..0).step(1)).should == [0]
- @array.send(@method, (...0).step(1)).should == []
-
- @array.send(@method, (..0).step(2)).should == [0]
- @array.send(@method, (...0).step(2)).should == []
-
- @array.send(@method, (..0).step(10)).should == [0]
- @array.send(@method, (...0).step(10)).should == []
-
- # end with positive index
- @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3]
- @array.send(@method, (...3).step(1)).should == [0, 1, 2]
-
- @array.send(@method, (..3).step(2)).should == [0, 2]
- @array.send(@method, (...3).step(2)).should == [0, 2]
-
- @array.send(@method, (..3).step(10)).should == [0]
- @array.send(@method, (...3).step(10)).should == [0]
-
- # end with negative index
- @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,]
- @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3]
-
- @array.send(@method, (..-2).step(2)).should == [0, 2, 4]
- @array.send(@method, (...-2).step(2)).should == [0, 2]
-
- @array.send(@method, (..-2).step(10)).should == [0]
- @array.send(@method, (...-2).step(10)).should == [0]
- end
-
- it "has endless range and negative steps" do
- @array.send(@method, eval("(0..).step(-1)")).should == [0]
- @array.send(@method, eval("(0..).step(-2)")).should == [0]
- @array.send(@method, eval("(0..).step(-10)")).should == [0]
-
- @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
- @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
-
- @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
- @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
- end
-
- it "has closed range and positive steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(1)")).should == [0]
- @array.send(@method, eval("(0...0).step(1)")).should == []
-
- @array.send(@method, eval("(0..0).step(2)")).should == [0]
- @array.send(@method, eval("(0...0).step(2)")).should == []
-
- @array.send(@method, eval("(0..0).step(10)")).should == [0]
- @array.send(@method, eval("(0...0).step(10)")).should == []
-
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
-
- @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...3).step(2)")).should == [1]
-
- @array.send(@method, eval("(1..3).step(10)")).should == [1]
- @array.send(@method, eval("(1...3).step(10)")).should == [1]
-
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
- @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
-
- @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
-
- @array.send(@method, eval("(1..-2).step(10)")).should == [1]
- @array.send(@method, eval("(1...-2).step(10)")).should == [1]
-
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
-
- @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...4).step(2)")).should == [2]
-
- @array.send(@method, eval("(-4..4).step(10)")).should == [2]
- @array.send(@method, eval("(-4...4).step(10)")).should == [2]
-
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
-
- @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
-
- @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
- @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
- end
-
- it "has closed range and negative steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(-1)")).should == [0]
- @array.send(@method, eval("(0...0).step(-1)")).should == []
-
- @array.send(@method, eval("(0..0).step(-2)")).should == [0]
- @array.send(@method, eval("(0...0).step(-2)")).should == []
-
- @array.send(@method, eval("(0..0).step(-10)")).should == [0]
- @array.send(@method, eval("(0...0).step(-10)")).should == []
-
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(-1)")).should == []
- @array.send(@method, eval("(1...3).step(-1)")).should == []
-
- @array.send(@method, eval("(1..3).step(-2)")).should == []
- @array.send(@method, eval("(1...3).step(-2)")).should == []
-
- @array.send(@method, eval("(1..3).step(-10)")).should == []
- @array.send(@method, eval("(1...3).step(-10)")).should == []
-
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(-1)")).should == []
- @array.send(@method, eval("(1...-2).step(-1)")).should == []
-
- @array.send(@method, eval("(1..-2).step(-2)")).should == []
- @array.send(@method, eval("(1...-2).step(-2)")).should == []
-
- @array.send(@method, eval("(1..-2).step(-10)")).should == []
- @array.send(@method, eval("(1...-2).step(-10)")).should == []
-
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(-1)")).should == []
- @array.send(@method, eval("(-4...4).step(-1)")).should == []
-
- @array.send(@method, eval("(-4..4).step(-2)")).should == []
- @array.send(@method, eval("(-4...4).step(-2)")).should == []
-
- @array.send(@method, eval("(-4..4).step(-10)")).should == []
- @array.send(@method, eval("(-4...4).step(-10)")).should == []
-
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(-1)")).should == []
- @array.send(@method, eval("(-4...-2).step(-1)")).should == []
-
- @array.send(@method, eval("(-4..-2).step(-2)")).should == []
- @array.send(@method, eval("(-4...-2).step(-2)")).should == []
-
- @array.send(@method, eval("(-4..-2).step(-10)")).should == []
- @array.send(@method, eval("(-4...-2).step(-10)")).should == []
- end
-
- it "has inverted closed range and positive steps" do
- # start and end with positive index
- @array.send(@method, eval("(3..1).step(1)")).should == []
- @array.send(@method, eval("(3...1).step(1)")).should == []
-
- @array.send(@method, eval("(3..1).step(2)")).should == []
- @array.send(@method, eval("(3...1).step(2)")).should == []
-
- @array.send(@method, eval("(3..1).step(10)")).should == []
- @array.send(@method, eval("(3...1).step(10)")).should == []
-
- # start with negative index, end with positive index
- @array.send(@method, eval("(-2..1).step(1)")).should == []
- @array.send(@method, eval("(-2...1).step(1)")).should == []
-
- @array.send(@method, eval("(-2..1).step(2)")).should == []
- @array.send(@method, eval("(-2...1).step(2)")).should == []
-
- @array.send(@method, eval("(-2..1).step(10)")).should == []
- @array.send(@method, eval("(-2...1).step(10)")).should == []
-
- # start with positive index, end with negative index
- @array.send(@method, eval("(4..-4).step(1)")).should == []
- @array.send(@method, eval("(4...-4).step(1)")).should == []
-
- @array.send(@method, eval("(4..-4).step(2)")).should == []
- @array.send(@method, eval("(4...-4).step(2)")).should == []
-
- @array.send(@method, eval("(4..-4).step(10)")).should == []
- @array.send(@method, eval("(4...-4).step(10)")).should == []
-
- # start with negative index, end with negative index
- @array.send(@method, eval("(-2..-4).step(1)")).should == []
- @array.send(@method, eval("(-2...-4).step(1)")).should == []
-
- @array.send(@method, eval("(-2..-4).step(2)")).should == []
- @array.send(@method, eval("(-2...-4).step(2)")).should == []
-
- @array.send(@method, eval("(-2..-4).step(10)")).should == []
- @array.send(@method, eval("(-2...-4).step(10)")).should == []
- end
-
- it "has range with bounds outside of array" do
- # end is equal to array's length
- @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
- -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
-
- # end is greater than length with positive steps
- @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
- @array.send(@method, (2..7).step(2)).should == [2, 4]
- -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
-
- # begin is greater than length with negative steps
- @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
- @array.send(@method, (7..2).step(-2)).should == [5, 3]
- -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
- end
-
- it "has endless range with start outside of array's bounds" do
- @array.send(@method, eval("(6..).step(1)")).should == []
- @array.send(@method, eval("(7..).step(1)")).should == nil
-
- @array.send(@method, eval("(6..).step(2)")).should == []
- -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
- end
- end
-
- it "can accept beginless ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, (..3)).should == [0, 1, 2, 3]
- a.send(@method, (...3)).should == [0, 1, 2]
- a.send(@method, (..-3)).should == [0, 1, 2, 3]
- a.send(@method, (...-3)).should == [0, 1, 2]
- a.send(@method, (..0)).should == [0]
- a.send(@method, (...0)).should == []
- a.send(@method, (..9)).should == [0, 1, 2, 3, 4, 5]
- a.send(@method, (...9)).should == [0, 1, 2, 3, 4, 5]
- a.send(@method, (..-9)).should == []
- a.send(@method, (...-9)).should == []
- end
-
- ruby_version_is "3.2" do
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- it "with infinite/inverted ranges and negative steps" do
- @array = [0, 1, 2, 3, 4, 5]
- @array.send(@method, (2..).step(-1)).should == [2, 1, 0]
- @array.send(@method, (2..).step(-2)).should == [2, 0]
- @array.send(@method, (2..).step(-3)).should == [2]
- @array.send(@method, (2..).step(-4)).should == [2]
-
- @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0]
- @array.send(@method, (-3..).step(-2)).should == [3, 1]
- @array.send(@method, (-3..).step(-3)).should == [3, 0]
- @array.send(@method, (-3..).step(-4)).should == [3]
- @array.send(@method, (-3..).step(-5)).should == [3]
-
- @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0]
- @array.send(@method, (..0).step(-2)).should == [5, 3, 1]
- @array.send(@method, (..0).step(-3)).should == [5, 2]
- @array.send(@method, (..0).step(-4)).should == [5, 1]
- @array.send(@method, (..0).step(-5)).should == [5, 0]
- @array.send(@method, (..0).step(-6)).should == [5]
- @array.send(@method, (..0).step(-7)).should == [5]
-
- @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1]
- @array.send(@method, (...0).step(-2)).should == [5, 3, 1]
- @array.send(@method, (...0).step(-3)).should == [5, 2]
- @array.send(@method, (...0).step(-4)).should == [5, 1]
- @array.send(@method, (...0).step(-5)).should == [5]
- @array.send(@method, (...0).step(-6)).should == [5]
-
- @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2]
- @array.send(@method, (...1).step(-2)).should == [5, 3]
- @array.send(@method, (...1).step(-3)).should == [5, 2]
- @array.send(@method, (...1).step(-4)).should == [5]
- @array.send(@method, (...1).step(-5)).should == [5]
-
- @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1]
- @array.send(@method, (..-5).step(-2)).should == [5, 3, 1]
- @array.send(@method, (..-5).step(-3)).should == [5, 2]
- @array.send(@method, (..-5).step(-4)).should == [5, 1]
- @array.send(@method, (..-5).step(-5)).should == [5]
- @array.send(@method, (..-5).step(-6)).should == [5]
-
- @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2]
- @array.send(@method, (...-5).step(-2)).should == [5, 3]
- @array.send(@method, (...-5).step(-3)).should == [5, 2]
- @array.send(@method, (...-5).step(-4)).should == [5]
- @array.send(@method, (...-5).step(-5)).should == [5]
-
- @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (4..1).step(-2)).should == [4, 2]
- @array.send(@method, (4..1).step(-3)).should == [4, 1]
- @array.send(@method, (4..1).step(-4)).should == [4]
- @array.send(@method, (4..1).step(-5)).should == [4]
-
- @array.send(@method, (4...1).step(-1)).should == [4, 3, 2]
- @array.send(@method, (4...1).step(-2)).should == [4, 2]
- @array.send(@method, (4...1).step(-3)).should == [4]
- @array.send(@method, (4...1).step(-4)).should == [4]
-
- @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (-2..1).step(-2)).should == [4, 2]
- @array.send(@method, (-2..1).step(-3)).should == [4, 1]
- @array.send(@method, (-2..1).step(-4)).should == [4]
- @array.send(@method, (-2..1).step(-5)).should == [4]
-
- @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2]
- @array.send(@method, (-2...1).step(-2)).should == [4, 2]
- @array.send(@method, (-2...1).step(-3)).should == [4]
- @array.send(@method, (-2...1).step(-4)).should == [4]
-
- @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (4..-5).step(-2)).should == [4, 2]
- @array.send(@method, (4..-5).step(-3)).should == [4, 1]
- @array.send(@method, (4..-5).step(-4)).should == [4]
- @array.send(@method, (4..-5).step(-5)).should == [4]
-
- @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2]
- @array.send(@method, (4...-5).step(-2)).should == [4, 2]
- @array.send(@method, (4...-5).step(-3)).should == [4]
- @array.send(@method, (4...-5).step(-4)).should == [4]
-
- @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (-2..-5).step(-2)).should == [4, 2]
- @array.send(@method, (-2..-5).step(-3)).should == [4, 1]
- @array.send(@method, (-2..-5).step(-4)).should == [4]
- @array.send(@method, (-2..-5).step(-5)).should == [4]
-
- @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2]
- @array.send(@method, (-2...-5).step(-2)).should == [4, 2]
- @array.send(@method, (-2...-5).step(-3)).should == [4]
- @array.send(@method, (-2...-5).step(-4)).should == [4]
- end
- end
- end
-
- it "can accept nil...nil ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(nil...nil)")).should == a
- a.send(@method, (...nil)).should == a
- a.send(@method, eval("(nil..)")).should == a
- end
-end
diff --git a/spec/ruby/core/array/shared/union.rb b/spec/ruby/core/array/shared/union.rb
index 0b60df9ca4..0b225b9a31 100644
--- a/spec/ruby/core/array/shared/union.rb
+++ b/spec/ruby/core/array/shared/union.rb
@@ -60,9 +60,9 @@ describe :array_binary_union, shared: true do
end
it "does not return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].send(@method, []).should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
- [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, []).should.instance_of?(Array)
+ ArraySpecs::MyArray[1, 2, 3].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
+ [].send(@method, ArraySpecs::MyArray[1, 2, 3]).should.instance_of?(Array)
end
it "does not call to_ary on array subclasses" do
diff --git a/spec/ruby/core/array/shared/unshift.rb b/spec/ruby/core/array/shared/unshift.rb
deleted file mode 100644
index 4941e098f6..0000000000
--- a/spec/ruby/core/array/shared/unshift.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-describe :array_unshift, shared: true do
- it "prepends object to the original array" do
- a = [1, 2, 3]
- a.send(@method, "a").should equal(a)
- a.should == ['a', 1, 2, 3]
- a.send(@method).should equal(a)
- a.should == ['a', 1, 2, 3]
- a.send(@method, 5, 4, 3)
- a.should == [5, 4, 3, 'a', 1, 2, 3]
-
- # shift all but one element
- a = [1, 2]
- a.shift
- a.send(@method, 3, 4)
- a.should == [3, 4, 2]
-
- # now shift all elements
- a.shift
- a.shift
- a.shift
- a.send(@method, 3, 4)
- a.should == [3, 4]
- end
-
- it "returns self" do
- a = [1, 2, 3]
- a.send(@method, "a").should.equal?(a)
- end
-
- it "quietly ignores unshifting nothing" do
- [].send(@method).should == []
- end
-
- it "properly handles recursive arrays" do
- empty = ArraySpecs.empty_recursive_array
- empty.send(@method, :new).should == [:new, empty]
-
- array = ArraySpecs.recursive_array
- array.send(@method, :new)
- array[0..5].should == [:new, 1, 'two', 3.0, array, array]
- end
-
- it "raises a FrozenError on a frozen array when the array is modified" do
- -> { ArraySpecs.frozen_array.send(@method, 1) }.should raise_error(FrozenError)
- end
-
- # see [ruby-core:23666]
- it "raises a FrozenError on a frozen array when the array would not be modified" do
- -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError)
- end
-
- # https://github.com/oracle/truffleruby/issues/2772
- it "doesn't rely on Array#[]= so it can be overridden" do
- subclass = Class.new(Array) do
- def []=(*)
- raise "[]= is called"
- end
- end
-
- array = subclass.new
- array.send(@method, 1)
- array.should == [1]
- end
-end
diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb
index 6b4ef39f77..09dfa79c45 100644
--- a/spec/ruby/core/array/shift_spec.rb
+++ b/spec/ruby/core/array/shift_spec.rb
@@ -31,10 +31,10 @@ describe "Array#shift" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.shift }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.shift }.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.shift }.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.shift }.should.raise(FrozenError)
end
describe "passed a number n as an argument" do
@@ -72,7 +72,7 @@ describe "Array#shift" do
popped2.should == []
a.should == []
- popped1.should_not equal(popped2)
+ popped1.should_not.equal?(popped2)
end
it "returns whole elements if n exceeds size of the array" do
@@ -83,14 +83,14 @@ describe "Array#shift" do
it "does not return self even when it returns whole elements" do
a = [1, 2, 3, 4, 5]
- a.shift(5).should_not equal(a)
+ a.shift(5).should_not.equal?(a)
a = [1, 2, 3, 4, 5]
- a.shift(6).should_not equal(a)
+ a.shift(6).should_not.equal?(a)
end
it "raises an ArgumentError if n is negative" do
- ->{ [1, 2, 3].shift(-1) }.should raise_error(ArgumentError)
+ ->{ [1, 2, 3].shift(-1) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -105,16 +105,16 @@ describe "Array#shift" do
end
it "raises a TypeError when the passed n cannot be coerced to Integer" do
- ->{ [1, 2].shift("cat") }.should raise_error(TypeError)
- ->{ [1, 2].shift(nil) }.should raise_error(TypeError)
+ ->{ [1, 2].shift("cat") }.should.raise(TypeError)
+ ->{ [1, 2].shift(nil) }.should.raise(TypeError)
end
it "raises an ArgumentError if more arguments are passed" do
- ->{ [1, 2].shift(1, 2) }.should raise_error(ArgumentError)
+ ->{ [1, 2].shift(1, 2) }.should.raise(ArgumentError)
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].shift(2).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].shift(2).should.instance_of?(Array)
end
end
end
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index b84394bcb5..9bc9df73ac 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -10,7 +10,7 @@ describe "Array#shuffle" do
s.sort.should == a
different ||= (a != s)
end
- different.should be_true # Will fail once in a blue moon (4!^10)
+ different.should == true # Will fail once in a blue moon (4!^10)
end
it "is not destructive" do
@@ -22,7 +22,7 @@ describe "Array#shuffle" do
end
it "does not return subclass instances with Array subclass" do
- ArraySpecs::MyArray[1, 2, 3].shuffle.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].shuffle.should.instance_of?(Array)
end
it "calls #rand on the Object passed by the :random key in the arguments Hash" do
@@ -31,24 +31,24 @@ describe "Array#shuffle" do
result = [1, 2].shuffle(random: obj)
result.size.should == 2
- result.should include(1, 2)
+ result.sort.should == [1, 2]
end
it "raises a NoMethodError if an object passed for the RNG does not define #rand" do
obj = BasicObject.new
- -> { [1, 2].shuffle(random: obj) }.should raise_error(NoMethodError)
+ -> { [1, 2].shuffle(random: obj) }.should.raise(NoMethodError)
end
it "accepts a Float for the value returned by #rand" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(0.3)
- [1, 2].shuffle(random: random).should be_an_instance_of(Array)
+ [1, 2].shuffle(random: random).should.instance_of?(Array)
end
it "accepts a Random class for the value for random: argument" do
- [1, 2].shuffle(random: Random).should be_an_instance_of(Array)
+ [1, 2].shuffle(random: Random).should.instance_of?(Array)
end
it "calls #to_int on the Object returned by #rand" do
@@ -57,7 +57,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
- [1, 2].shuffle(random: random).should be_an_instance_of(Array)
+ [1, 2].shuffle(random: random).should.instance_of?(Array)
end
it "raises a RangeError if the value is less than zero" do
@@ -66,7 +66,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).and_return(value)
- -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].shuffle(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is equal to the Array size" do
@@ -75,7 +75,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
- -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].shuffle(random: random) }.should.raise(RangeError)
end
it "raises a RangeError if the value is greater than the Array size" do
@@ -84,7 +84,7 @@ describe "Array#shuffle" do
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
- -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ -> { [1, 2].shuffle(random: random) }.should.raise(RangeError)
end
end
@@ -98,13 +98,13 @@ describe "Array#shuffle!" do
a.sort.should == [1, 2, 3, 4]
different ||= (a != [1, 2, 3, 4])
end
- different.should be_true # Will fail once in a blue moon (4!^10)
- a.should equal(original)
+ different.should == true # Will fail once in a blue moon (4!^10)
+ a.should.equal?(original)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
- -> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.shuffle! }.should.raise(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.shuffle! }.should.raise(FrozenError)
end
it "matches CRuby with random:" do
diff --git a/spec/ruby/core/array/size_spec.rb b/spec/ruby/core/array/size_spec.rb
index d68f956a83..83e8969012 100644
--- a/spec/ruby/core/array/size_spec.rb
+++ b/spec/ruby/core/array/size_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Array#size" do
- it_behaves_like :array_length, :size
+ it "is an alias of Array#length" do
+ Array.instance_method(:size).should == Array.instance_method(:length)
+ end
end
diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb
index 731c129251..230d1dc5d1 100644
--- a/spec/ruby/core/array/slice_spec.rb
+++ b/spec/ruby/core/array/slice_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/slice'
describe "Array#slice!" do
it "removes and return the element at index" do
@@ -116,8 +115,8 @@ describe "Array#slice!" do
a.slice!(from .. to).should == [2, 3, 4]
a.should == [1, 5]
- -> { a.slice!("a" .. "b") }.should raise_error(TypeError)
- -> { a.slice!(from .. "b") }.should raise_error(TypeError)
+ -> { a.slice!("a" .. "b") }.should.raise(TypeError)
+ -> { a.slice!(from .. "b") }.should.raise(TypeError)
end
it "returns last element for consecutive calls at zero index" do
@@ -151,7 +150,7 @@ describe "Array#slice!" do
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.slice!(0, 0) }.should.raise(FrozenError)
end
it "works with endless ranges" do
@@ -188,31 +187,33 @@ describe "Array#slice!" do
end
it "returns a Array instance with [n, m]" do
- @array.slice!(0, 2).should be_an_instance_of(Array)
+ @array.slice!(0, 2).should.instance_of?(Array)
end
it "returns a Array instance with [-n, m]" do
- @array.slice!(-3, 2).should be_an_instance_of(Array)
+ @array.slice!(-3, 2).should.instance_of?(Array)
end
it "returns a Array instance with [n..m]" do
- @array.slice!(1..3).should be_an_instance_of(Array)
+ @array.slice!(1..3).should.instance_of?(Array)
end
it "returns a Array instance with [n...m]" do
- @array.slice!(1...3).should be_an_instance_of(Array)
+ @array.slice!(1...3).should.instance_of?(Array)
end
it "returns a Array instance with [-n..-m]" do
- @array.slice!(-3..-1).should be_an_instance_of(Array)
+ @array.slice!(-3..-1).should.instance_of?(Array)
end
it "returns a Array instance with [-n...-m]" do
- @array.slice!(-3...-1).should be_an_instance_of(Array)
+ @array.slice!(-3...-1).should.instance_of?(Array)
end
end
end
describe "Array#slice" do
- it_behaves_like :array_slice, :slice
+ it "is an alias of Array#[]" do
+ Array.instance_method(:slice).should == Array.instance_method(:[])
+ end
end
diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb
index 0334f953f6..132abb028a 100644
--- a/spec/ruby/core/array/sort_by_spec.rb
+++ b/spec/ruby/core/array/sort_by_spec.rb
@@ -11,30 +11,30 @@ describe "Array#sort_by!" do
end
it "returns an Enumerator if not given a block" do
- (1..10).to_a.sort_by!.should be_an_instance_of(Enumerator)
+ (1..10).to_a.sort_by!.should.instance_of?(Enumerator)
end
it "completes when supplied a block that always returns the same result" do
a = [2, 3, 5, 1, 4]
a.sort_by!{ 1 }
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
a.sort_by!{ 0 }
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
a.sort_by!{ -1 }
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.sort_by! {}}.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.sort_by! {}}.should.raise(FrozenError)
end
it "raises a FrozenError on an empty frozen array" do
- -> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.sort_by! {}}.should.raise(FrozenError)
end
it "raises a FrozenError on a frozen array only during iteration if called without a block" do
enum = ArraySpecs.frozen_array.sort_by!
- -> { enum.each {} }.should raise_error(FrozenError)
+ -> { enum.each {} }.should.raise(FrozenError)
end
it "returns the specified value when it would break in the given block" do
@@ -47,7 +47,7 @@ describe "Array#sort_by!" do
ary.sort_by!{|x,y| break if x==i; x<=>y}
ary
}
- partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should be_true
+ partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should == true
end
it "changes nothing when called on a single element array" do
diff --git a/spec/ruby/core/array/sort_spec.rb b/spec/ruby/core/array/sort_spec.rb
index e20b650516..27300c3385 100644
--- a/spec/ruby/core/array/sort_spec.rb
+++ b/spec/ruby/core/array/sort_spec.rb
@@ -42,7 +42,7 @@ describe "Array#sort" do
a = [1, 2, 3]
sorted = a.sort
sorted.should == a
- sorted.should_not equal(a)
+ sorted.should_not.equal?(a)
end
it "properly handles recursive arrays" do
@@ -68,7 +68,7 @@ describe "Array#sort" do
-> {
[o, 1].sort
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "may take a block which is used to determine the order of objects a and b described as -1, 0 or +1" do
@@ -78,28 +78,28 @@ describe "Array#sort" do
end
it "raises an error when a given block returns nil" do
- -> { [1, 2].sort {} }.should raise_error(ArgumentError)
+ -> { [1, 2].sort {} }.should.raise(ArgumentError)
end
it "does not call #<=> on contained objects when invoked with a block" do
a = Array.new(25)
(0...25).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort { -1 }.should be_an_instance_of(Array)
+ a.sort { -1 }.should.instance_of?(Array)
end
it "does not call #<=> on elements when invoked with a block even if Array is large (Rubinius #412)" do
a = Array.new(1500)
(0...1500).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort { -1 }.should be_an_instance_of(Array)
+ a.sort { -1 }.should.instance_of?(Array)
end
it "completes when supplied a block that always returns the same result" do
a = [2, 3, 5, 1, 4]
- a.sort { 1 }.should be_an_instance_of(Array)
- a.sort { 0 }.should be_an_instance_of(Array)
- a.sort { -1 }.should be_an_instance_of(Array)
+ a.sort { 1 }.should.instance_of?(Array)
+ a.sort { 0 }.should.instance_of?(Array)
+ a.sort { -1 }.should.instance_of?(Array)
end
it "does not freezes self during being sorted" do
@@ -136,7 +136,7 @@ describe "Array#sort" do
}.should == [-4, 1, 2, 5, 7, 10, 12]
-> {
a.sort { |n, m| (n - m).to_s }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "sorts an array that has a value shifted off without a block" do
@@ -155,7 +155,7 @@ describe "Array#sort" do
it "raises an error if objects can't be compared" do
a=[ArraySpecs::Uncomparable.new, ArraySpecs::Uncomparable.new]
- -> {a.sort}.should raise_error(ArgumentError)
+ -> {a.sort}.should.raise(ArgumentError)
end
# From a strange Rubinius bug
@@ -166,7 +166,7 @@ describe "Array#sort" do
it "does not return subclass instance on Array subclasses" do
ary = ArraySpecs::MyArray[1, 2, 3]
- ary.sort.should be_an_instance_of(Array)
+ ary.sort.should.instance_of?(Array)
end
end
@@ -184,13 +184,13 @@ describe "Array#sort!" do
it "returns self if the order of elements changed" do
a = [6, 7, 2, 3, 7]
- a.sort!.should equal(a)
+ a.sort!.should.equal?(a)
a.should == [2, 3, 6, 7, 7]
end
it "returns self even if makes no modification" do
a = [1, 2, 3, 4, 5]
- a.sort!.should equal(a)
+ a.sort!.should.equal?(a)
a.should == [1, 2, 3, 4, 5]
end
@@ -216,25 +216,25 @@ describe "Array#sort!" do
a = Array.new(25)
(0...25).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort! { -1 }.should be_an_instance_of(Array)
+ a.sort! { -1 }.should.instance_of?(Array)
end
it "does not call #<=> on elements when invoked with a block even if Array is large (Rubinius #412)" do
a = Array.new(1500)
(0...1500).each {|i| a[i] = ArraySpecs::UFOSceptic.new }
- a.sort! { -1 }.should be_an_instance_of(Array)
+ a.sort! { -1 }.should.instance_of?(Array)
end
it "completes when supplied a block that always returns the same result" do
a = [2, 3, 5, 1, 4]
- a.sort!{ 1 }.should be_an_instance_of(Array)
- a.sort!{ 0 }.should be_an_instance_of(Array)
- a.sort!{ -1 }.should be_an_instance_of(Array)
+ a.sort!{ 1 }.should.instance_of?(Array)
+ a.sort!{ 0 }.should.instance_of?(Array)
+ a.sort!{ -1 }.should.instance_of?(Array)
end
it "raises a FrozenError on a frozen array" do
- -> { ArraySpecs.frozen_array.sort! }.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.sort! }.should.raise(FrozenError)
end
it "returns the specified value when it would break in the given block" do
@@ -247,6 +247,6 @@ describe "Array#sort!" do
ary.sort!{|x,y| break if x==i; x<=>y}
ary
}
- partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should be_true
+ partially_sorted.any?{|ary| ary != [1, 2, 3, 4, 5]}.should == true
end
end
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
index 06abe06135..cd4ba4c2d8 100644
--- a/spec/ruby/core/array/sum_spec.rb
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -60,11 +60,11 @@ describe "Array#sum" do
end
it 'raises TypeError if any element are not numeric' do
- -> { ["a"].sum }.should raise_error(TypeError)
+ -> { ["a"].sum }.should.raise(TypeError)
end
it 'raises TypeError if any element cannot be added to init value' do
- -> { [1].sum([]) }.should raise_error(TypeError)
+ -> { [1].sum([]) }.should.raise(TypeError)
end
it "calls + to sum the elements" do
@@ -74,13 +74,11 @@ describe "Array#sum" do
[b].sum(a).should == 42
end
- ruby_bug '#19530', ''...'3.3' do
- it "calls + on the init value" do
- a = mock("a")
- b = mock("b")
- a.should_receive(:+).with(42).and_return(b)
- [42].sum(a).should == b
- end
+ it "calls + on the init value" do
+ a = mock("a")
+ b = mock("b")
+ a.should_receive(:+).with(42).and_return(b)
+ [42].sum(a).should == b
end
end
diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb
index c4f0ac9aa4..837c734b77 100644
--- a/spec/ruby/core/array/take_spec.rb
+++ b/spec/ruby/core/array/take_spec.rb
@@ -23,10 +23,10 @@ describe "Array#take" do
end
it "raises an ArgumentError when the argument is negative" do
- ->{ [1].take(-3) }.should raise_error(ArgumentError)
+ ->{ [1].take(-3) }.should.raise(ArgumentError)
end
it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb
index 8f50260b42..7811edab9e 100644
--- a/spec/ruby/core/array/take_while_spec.rb
+++ b/spec/ruby/core/array/take_while_spec.rb
@@ -16,7 +16,7 @@ describe "Array#take_while" do
end
it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/to_a_spec.rb b/spec/ruby/core/array/to_a_spec.rb
index 49d0a4782e..078de1638a 100644
--- a/spec/ruby/core/array/to_a_spec.rb
+++ b/spec/ruby/core/array/to_a_spec.rb
@@ -5,12 +5,12 @@ describe "Array#to_a" do
it "returns self" do
a = [1, 2, 3]
a.to_a.should == [1, 2, 3]
- a.should equal(a.to_a)
+ a.should.equal?(a.to_a)
end
it "does not return subclass instance on Array subclasses" do
e = ArraySpecs::MyArray.new(1, 2)
- e.to_a.should be_an_instance_of(Array)
+ e.to_a.should.instance_of?(Array)
e.to_a.should == [1, 2]
end
diff --git a/spec/ruby/core/array/to_ary_spec.rb b/spec/ruby/core/array/to_ary_spec.rb
index 314699b709..dc5193158d 100644
--- a/spec/ruby/core/array/to_ary_spec.rb
+++ b/spec/ruby/core/array/to_ary_spec.rb
@@ -4,9 +4,9 @@ require_relative 'fixtures/classes'
describe "Array#to_ary" do
it "returns self" do
a = [1, 2, 3]
- a.should equal(a.to_ary)
+ a.should.equal?(a.to_ary)
a = ArraySpecs::MyArray[1, 2, 3]
- a.should equal(a.to_ary)
+ a.should.equal?(a.to_ary)
end
it "properly handles recursive arrays" do
diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb
index 1c814f3d01..1d626763c2 100644
--- a/spec/ruby/core/array/to_h_spec.rb
+++ b/spec/ruby/core/array/to_h_spec.rb
@@ -25,19 +25,19 @@ describe "Array#to_h" do
end
it "raises TypeError if an element is not an array" do
- -> { [:x].to_h }.should raise_error(TypeError)
+ -> { [:x].to_h }.should.raise(TypeError)
end
it "raises ArgumentError if an element is not a [key, value] pair" do
- -> { [[:x]].to_h }.should raise_error(ArgumentError)
+ -> { [[:x]].to_h }.should.raise(ArgumentError)
end
it "does not accept arguments" do
- -> { [].to_h(:a, :b) }.should raise_error(ArgumentError)
+ -> { [].to_h(:a, :b) }.should.raise(ArgumentError)
end
it "produces a hash that returns nil for a missing element" do
- [[:a, 1], [:b, 2]].to_h[:c].should be_nil
+ [[:a, 1], [:b, 2]].to_h[:c].should == nil
end
context "with block" do
@@ -54,17 +54,17 @@ describe "Array#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
[:a, :b].to_h { |k| [k, k.to_s, 1] }
- end.should raise_error(ArgumentError, /wrong array length at 0/)
+ end.should.raise(ArgumentError, /wrong array length at 0/)
-> do
[:a, :b].to_h { |k| [k] }
- end.should raise_error(ArgumentError, /wrong array length at 0/)
+ end.should.raise(ArgumentError, /wrong array length at 0/)
end
it "raises TypeError if block returns something other than Array" do
-> do
[:a, :b].to_h { |k| "not-array" }
- end.should raise_error(TypeError, /wrong element type String at 0/)
+ end.should.raise(TypeError, /wrong element type String at 0/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -80,7 +80,7 @@ describe "Array#to_h" do
-> do
[:a].to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject at 0/)
+ end.should.raise(TypeError, /wrong element type MockObject at 0/)
end
end
end
diff --git a/spec/ruby/core/array/to_s_spec.rb b/spec/ruby/core/array/to_s_spec.rb
index e8476702ec..483e14f902 100644
--- a/spec/ruby/core/array/to_s_spec.rb
+++ b/spec/ruby/core/array/to_s_spec.rb
@@ -1,8 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/join'
-require_relative 'shared/inspect'
describe "Array#to_s" do
- it_behaves_like :array_inspect, :to_s
+ it "is an alias of Array#inspect" do
+ Array.instance_method(:to_s).should == Array.instance_method(:inspect)
+ end
end
diff --git a/spec/ruby/core/array/transpose_spec.rb b/spec/ruby/core/array/transpose_spec.rb
index b39077f4c9..d45e9c351c 100644
--- a/spec/ruby/core/array/transpose_spec.rb
+++ b/spec/ruby/core/array/transpose_spec.rb
@@ -32,7 +32,7 @@ describe "Array#transpose" do
end
it "raises a TypeError if the passed Argument does not respond to #to_ary" do
- -> { [Object.new, [:a, :b]].transpose }.should raise_error(TypeError)
+ -> { [Object.new, [:a, :b]].transpose }.should.raise(TypeError)
end
it "does not call to_ary on array subclass elements" do
@@ -41,13 +41,13 @@ describe "Array#transpose" do
end
it "raises an IndexError if the arrays are not of the same length" do
- -> { [[1, 2], [:a]].transpose }.should raise_error(IndexError)
+ -> { [[1, 2], [:a]].transpose }.should.raise(IndexError)
end
it "does not return subclass instance on Array subclasses" do
result = ArraySpecs::MyArray[ArraySpecs::MyArray[1, 2, 3], ArraySpecs::MyArray[4, 5, 6]].transpose
- result.should be_an_instance_of(Array)
- result[0].should be_an_instance_of(Array)
- result[1].should be_an_instance_of(Array)
+ result.should.instance_of?(Array)
+ result[0].should.instance_of?(Array)
+ result[1].should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index bea8815006..3eaa0f4b7c 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -4,47 +4,47 @@ require_relative 'fixtures/classes'
describe "Array.try_convert" do
it "returns the argument if it's an Array" do
x = Array.new
- Array.try_convert(x).should equal(x)
+ Array.try_convert(x).should.equal?(x)
end
it "returns the argument if it's a kind of Array" do
x = ArraySpecs::MyArray[]
- Array.try_convert(x).should equal(x)
+ Array.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_ary" do
- Array.try_convert(Object.new).should be_nil
+ Array.try_convert(Object.new).should == nil
end
it "sends #to_ary to the argument and returns the result if it's nil" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(nil)
- Array.try_convert(obj).should be_nil
+ Array.try_convert(obj).should == nil
end
it "sends #to_ary to the argument and returns the result if it's an Array" do
x = Array.new
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(x)
- Array.try_convert(obj).should equal(x)
+ Array.try_convert(obj).should.equal?(x)
end
it "sends #to_ary to the argument and returns the result if it's a kind of Array" do
x = ArraySpecs::MyArray[]
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(x)
- Array.try_convert(obj).should equal(x)
+ Array.try_convert(obj).should.equal?(x)
end
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)")
+ -> { Array.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into Array (MockObject#to_ary gives Object)")
end
it "does not rescue exceptions raised by #to_ary" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_raise(RuntimeError)
- -> { Array.try_convert obj }.should raise_error(RuntimeError)
+ -> { Array.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/array/union_spec.rb b/spec/ruby/core/array/union_spec.rb
index ba2cc0d6b7..110894e83d 100644
--- a/spec/ruby/core/array/union_spec.rb
+++ b/spec/ruby/core/array/union_spec.rb
@@ -15,7 +15,7 @@ describe "Array#union" do
end
it "does not return subclass instances for Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].union.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].union.should.instance_of?(Array)
end
it "accepts multiple arguments" do
diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb
index d5d826db15..0289bee7c2 100644
--- a/spec/ruby/core/array/uniq_spec.rb
+++ b/spec/ruby/core/array/uniq_spec.rb
@@ -86,7 +86,7 @@ describe "Array#uniq" do
end
it "returns Array instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].uniq.should.instance_of?(Array)
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
@@ -138,7 +138,7 @@ describe "Array#uniq!" do
it "returns self" do
a = [ "a", "a", "b", "b", "c" ]
- a.should equal(a.uniq!)
+ a.should.equal?(a.uniq!)
end
it "properly handles recursive arrays" do
@@ -185,17 +185,17 @@ describe "Array#uniq!" do
it "raises a FrozenError on a frozen array when the array is modified" do
dup_ary = [1, 1, 2]
dup_ary.freeze
- -> { dup_ary.uniq! }.should raise_error(FrozenError)
+ -> { dup_ary.uniq! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen array when the array would not be modified" do
- -> { ArraySpecs.frozen_array.uniq!}.should raise_error(FrozenError)
- -> { ArraySpecs.empty_frozen_array.uniq!}.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.uniq!}.should.raise(FrozenError)
+ -> { ArraySpecs.empty_frozen_array.uniq!}.should.raise(FrozenError)
end
it "doesn't yield to the block on a frozen array" do
- -> { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should raise_error(FrozenError)
+ -> { ArraySpecs.frozen_array.uniq!{ raise RangeError, "shouldn't yield"}}.should.raise(FrozenError)
end
it "compares elements based on the value returned from the block" do
diff --git a/spec/ruby/core/array/unshift_spec.rb b/spec/ruby/core/array/unshift_spec.rb
index b8b675e5f8..c190db4d02 100644
--- a/spec/ruby/core/array/unshift_spec.rb
+++ b/spec/ruby/core/array/unshift_spec.rb
@@ -1,7 +1,67 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/unshift'
describe "Array#unshift" do
- it_behaves_like :array_unshift, :unshift
+ it "prepends object to the original array" do
+ a = [1, 2, 3]
+ a.unshift("a").should.equal?(a)
+ a.should == ['a', 1, 2, 3]
+ a.unshift.should.equal?(a)
+ a.should == ['a', 1, 2, 3]
+ a.unshift(5, 4, 3)
+ a.should == [5, 4, 3, 'a', 1, 2, 3]
+
+ # shift all but one element
+ a = [1, 2]
+ a.shift
+ a.unshift(3, 4)
+ a.should == [3, 4, 2]
+
+ # now shift all elements
+ a.shift
+ a.shift
+ a.shift
+ a.unshift(3, 4)
+ a.should == [3, 4]
+ end
+
+ it "returns self" do
+ a = [1, 2, 3]
+ a.unshift("a").should.equal?(a)
+ end
+
+ it "quietly ignores unshifting nothing" do
+ [].unshift.should == []
+ end
+
+ it "properly handles recursive arrays" do
+ empty = ArraySpecs.empty_recursive_array
+ empty.unshift(:new).should == [:new, empty]
+
+ array = ArraySpecs.recursive_array
+ array.unshift(:new)
+ array[0..5].should == [:new, 1, 'two', 3.0, array, array]
+ end
+
+ it "raises a FrozenError on a frozen array when the array is modified" do
+ -> { ArraySpecs.frozen_array.unshift(1) }.should.raise(FrozenError)
+ end
+
+ # see [ruby-core:23666]
+ it "raises a FrozenError on a frozen array when the array would not be modified" do
+ -> { ArraySpecs.frozen_array.unshift }.should.raise(FrozenError)
+ end
+
+ # https://github.com/truffleruby/truffleruby/issues/2772
+ it "doesn't rely on Array#[]= so it can be overridden" do
+ subclass = Class.new(Array) do
+ def []=(*)
+ raise "[]= is called"
+ end
+ end
+
+ array = subclass.new
+ array.unshift(1)
+ array.should == [1]
+ end
end
diff --git a/spec/ruby/core/array/values_at_spec.rb b/spec/ruby/core/array/values_at_spec.rb
index e85bbee400..e11e7e4451 100644
--- a/spec/ruby/core/array/values_at_spec.rb
+++ b/spec/ruby/core/array/values_at_spec.rb
@@ -59,7 +59,7 @@ describe "Array#values_at" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).should.instance_of?(Array)
end
it "works when given endless ranges" do
diff --git a/spec/ruby/core/array/zip_spec.rb b/spec/ruby/core/array/zip_spec.rb
index 2a0f64cb49..3ccdf143d6 100644
--- a/spec/ruby/core/array/zip_spec.rb
+++ b/spec/ruby/core/array/zip_spec.rb
@@ -60,12 +60,12 @@ describe "Array#zip" do
end
it "does not return subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should.instance_of?(Array)
end
it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do
- -> { [1, 2, 3].zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)")
- -> { [1, 2, 3].zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)")
- -> { [1, 2, 3].zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)")
+ -> { [1, 2, 3].zip(Object.new) }.should.raise(TypeError, "wrong argument type Object (must respond to :each)")
+ -> { [1, 2, 3].zip(1) }.should.raise(TypeError, "wrong argument type Integer (must respond to :each)")
+ -> { [1, 2, 3].zip(true) }.should.raise(TypeError, "wrong argument type TrueClass (must respond to :each)")
end
end
diff --git a/spec/ruby/core/basicobject/__send___spec.rb b/spec/ruby/core/basicobject/__send___spec.rb
index 005b1d0d90..2f814e448c 100644
--- a/spec/ruby/core/basicobject/__send___spec.rb
+++ b/spec/ruby/core/basicobject/__send___spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/basicobject/send'
describe "BasicObject#__send__" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:__send__)
+ BasicObject.public_instance_methods(false).should.include?(:__send__)
end
it_behaves_like :basicobject_send, :__send__
diff --git a/spec/ruby/core/basicobject/basicobject_spec.rb b/spec/ruby/core/basicobject/basicobject_spec.rb
index 27a322e72c..af28de0687 100644
--- a/spec/ruby/core/basicobject/basicobject_spec.rb
+++ b/spec/ruby/core/basicobject/basicobject_spec.rb
@@ -8,23 +8,23 @@ describe "BasicObject" do
end
it "raises NameError when referencing built-in constants" do
- -> { class BasicObjectSpecs::BOSubclass; Kernel; end }.should raise_error(NameError)
+ -> { class BasicObjectSpecs::BOSubclass; Kernel; end }.should.raise(NameError)
end
it "does not define built-in constants (according to const_defined?)" do
- BasicObject.const_defined?(:Kernel).should be_false
+ BasicObject.const_defined?(:Kernel).should == false
end
it "does not define built-in constants (according to defined?)" do
- BasicObjectSpecs::BOSubclass.kernel_defined?.should be_nil
+ BasicObjectSpecs::BOSubclass.kernel_defined?.should == nil
end
it "is included in Object's list of constants" do
- Object.constants(false).should include(:BasicObject)
+ Object.constants(false).should.include?(:BasicObject)
end
it "includes itself in its list of constants" do
- BasicObject.constants(false).should include(:BasicObject)
+ BasicObject.constants(false).should.include?(:BasicObject)
end
end
@@ -34,11 +34,11 @@ describe "BasicObject metaclass" do
end
it "is an instance of Class" do
- @meta.should be_an_instance_of(Class)
+ @meta.should.instance_of?(Class)
end
it "has Class as superclass" do
- @meta.superclass.should equal(Class)
+ @meta.superclass.should.equal?(Class)
end
it "contains methods for the BasicObject class" do
@@ -57,11 +57,11 @@ describe "BasicObject instance metaclass" do
end
it "is an instance of Class" do
- @meta.should be_an_instance_of(Class)
+ @meta.should.instance_of?(Class)
end
it "has BasicObject as superclass" do
- @meta.superclass.should equal(BasicObject)
+ @meta.superclass.should.equal?(BasicObject)
end
it "contains methods defined for the BasicObject instance" do
@@ -85,7 +85,7 @@ describe "BasicObject subclass" do
describe "BasicObject references" do
it "can refer to BasicObject from within itself" do
- -> { BasicObject::BasicObject }.should_not raise_error
+ -> { BasicObject::BasicObject }.should_not.raise
end
end
end
diff --git a/spec/ruby/core/basicobject/equal_spec.rb b/spec/ruby/core/basicobject/equal_spec.rb
index ce28eaed95..c0f41dc0c0 100644
--- a/spec/ruby/core/basicobject/equal_spec.rb
+++ b/spec/ruby/core/basicobject/equal_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/kernel/equal'
describe "BasicObject#equal?" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:equal?)
+ BasicObject.public_instance_methods(false).should.include?(:equal?)
end
it_behaves_like :object_equal, :equal?
@@ -15,7 +15,7 @@ describe "BasicObject#equal?" do
def o1.__id__; 10; end
def o2.__id__; 10; end
}
- o1.equal?(o2).should be_false
+ o1.equal?(o2).should == false
end
it "is unaffected by overriding object_id" do
@@ -23,7 +23,7 @@ describe "BasicObject#equal?" do
o1.stub!(:object_id).and_return(10)
o2 = mock("object")
o2.stub!(:object_id).and_return(10)
- o1.equal?(o2).should be_false
+ o1.equal?(o2).should == false
end
it "is unaffected by overriding ==" do
@@ -31,12 +31,12 @@ describe "BasicObject#equal?" do
o1 = mock("object")
o1.stub!(:==).and_return(true)
o2 = mock("object")
- o1.equal?(o2).should be_false
+ o1.equal?(o2).should == false
# same objects, overriding == to return false
o3 = mock("object")
o3.stub!(:==).and_return(false)
- o3.equal?(o3).should be_true
+ o3.equal?(o3).should == true
end
it "is unaffected by overriding eql?" do
@@ -44,11 +44,11 @@ describe "BasicObject#equal?" do
o1 = mock("object")
o1.stub!(:eql?).and_return(true)
o2 = mock("object")
- o1.equal?(o2).should be_false
+ o1.equal?(o2).should == false
# same objects, overriding eql? to return false
o3 = mock("object")
o3.stub!(:eql?).and_return(false)
- o3.equal?(o3).should be_true
+ o3.equal?(o3).should == true
end
end
diff --git a/spec/ruby/core/basicobject/equal_value_spec.rb b/spec/ruby/core/basicobject/equal_value_spec.rb
index 6c825513c1..eb951a8305 100644
--- a/spec/ruby/core/basicobject/equal_value_spec.rb
+++ b/spec/ruby/core/basicobject/equal_value_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/kernel/equal'
describe "BasicObject#==" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:==)
+ BasicObject.public_instance_methods(false).should.include?(:==)
end
it_behaves_like :object_equal, :==
diff --git a/spec/ruby/core/basicobject/initialize_spec.rb b/spec/ruby/core/basicobject/initialize_spec.rb
index b7ce73ffd5..09e86676b6 100644
--- a/spec/ruby/core/basicobject/initialize_spec.rb
+++ b/spec/ruby/core/basicobject/initialize_spec.rb
@@ -2,12 +2,12 @@ require_relative '../../spec_helper'
describe "BasicObject#initialize" do
it "is a private instance method" do
- BasicObject.should have_private_instance_method(:initialize)
+ BasicObject.private_instance_methods(false).should.include?(:initialize)
end
it "does not accept arguments" do
-> {
BasicObject.new("This", "makes it easier", "to call super", "from other constructors")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index 633b5c2cb1..124d179b5a 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -7,31 +7,31 @@ describe "BasicObject#instance_eval" do
end
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:instance_eval)
+ BasicObject.public_instance_methods(false).should.include?(:instance_eval)
end
it "sets self to the receiver in the context of the passed block" do
a = BasicObject.new
- a.instance_eval { self }.equal?(a).should be_true
+ a.instance_eval { self }.equal?(a).should == true
end
it "evaluates strings" do
a = BasicObject.new
- a.instance_eval('self').equal?(a).should be_true
+ a.instance_eval('self').equal?(a).should == true
end
it "raises an ArgumentError when no arguments and no block are given" do
- -> { "hola".instance_eval }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
+ -> { "hola".instance_eval }.should.raise(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
end
it "raises an ArgumentError when a block and normal arguments are given" do
- -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 0)")
end
it "raises an ArgumentError when more than 3 arguments are given" do
-> {
"hola".instance_eval("1 + 1", "some file", 0, "bogus")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "yields the object to the block" do
@@ -51,7 +51,7 @@ describe "BasicObject#instance_eval" do
end
end
f.foo.should == 1
- -> { Object.new.foo }.should raise_error(NoMethodError)
+ -> { Object.new.foo }.should.raise(NoMethodError)
end
it "preserves self in the original block when passed a block argument" do
@@ -71,9 +71,9 @@ describe "BasicObject#instance_eval" do
it "binds self to the receiver" do
s = "hola"
- (s == s.instance_eval { self }).should be_true
+ (s == s.instance_eval { self }).should == true
o = mock('o')
- (o == o.instance_eval("self")).should be_true
+ (o == o.instance_eval("self")).should == true
end
it "executes in the context of the receiver" do
@@ -84,11 +84,9 @@ describe "BasicObject#instance_eval" do
end
- ruby_version_is "3.3" do
- it "uses the caller location as default location" do
- f = Object.new
- f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
+ it "uses the caller location as default location" do
+ f = Object.new
+ f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
it "has access to receiver's instance variables" do
@@ -97,15 +95,15 @@ describe "BasicObject#instance_eval" do
end
it "raises TypeError for frozen objects when tries to set receiver's instance variables" do
- -> { nil.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen NilClass: nil")
- -> { true.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen TrueClass: true")
- -> { false.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen FalseClass: false")
- -> { 1.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Integer: 1")
- -> { :symbol.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Symbol: :symbol")
+ -> { nil.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen NilClass: nil")
+ -> { true.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen TrueClass: true")
+ -> { false.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen FalseClass: false")
+ -> { 1.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen Integer: 1")
+ -> { :symbol.instance_eval { @foo = 42 } }.should.raise(FrozenError, "can't modify frozen Symbol: :symbol")
obj = Object.new
obj.freeze
- -> { obj.instance_eval { @foo = 42 } }.should raise_error(FrozenError)
+ -> { obj.instance_eval { @foo = 42 } }.should.raise(FrozenError)
end
it "treats block-local variables as local to the block" do
@@ -130,7 +128,7 @@ describe "BasicObject#instance_eval" do
class B; end
B
}
- obj.singleton_class.const_get(:B).should be_an_instance_of(Class)
+ obj.singleton_class.const_get(:B).should.instance_of?(Class)
end
describe "constants lookup when a String given" do
@@ -171,16 +169,16 @@ describe "BasicObject#instance_eval" do
end
it "doesn't get constants in the receiver if a block given" do
- BasicObjectSpecs::InstEvalOuter::Inner::X_BY_BLOCK.should be_nil
+ BasicObjectSpecs::InstEvalOuter::Inner::X_BY_BLOCK.should == nil
end
it "raises a TypeError when defining methods on an immediate" do
-> do
1.instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
:foo.instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
describe "class variables lookup" do
@@ -219,23 +217,23 @@ describe "BasicObject#instance_eval" do
it "does not have access to class variables in the receiver class when called with a String" do
receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
- -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
+ -> { caller.get_class_variable_with_string(receiver) }.should.raise(NameError, /uninitialized class variable @@cvar/)
end
it "does not have access to class variables in the receiver's singleton class when called with a String" do
receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverWithCVarDefinedInSingletonClass
caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
- -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
+ -> { caller.get_class_variable_with_string(receiver) }.should.raise(NameError, /uninitialized class variable @@cvar/)
end
end
it "raises a TypeError when defining methods on numerics" do
-> do
(1.0).instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
(1 << 64).instance_eval { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "evaluates procs originating from methods" do
@@ -286,7 +284,7 @@ describe "BasicObject#instance_eval" do
def source_code.to_str() :symbol end
a = BasicObject.new
- -> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { a.instance_eval(source_code) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "converts filename argument with #to_str method" do
@@ -305,7 +303,7 @@ describe "BasicObject#instance_eval" do
filename = Object.new
def filename.to_str() :symbol end
- -> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { Object.new.instance_eval("raise", filename) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "converts lineno argument with #to_int method" do
@@ -324,6 +322,6 @@ describe "BasicObject#instance_eval" do
lineno = Object.new
def lineno.to_int() :symbol end
- -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/)
+ -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_consistent_error(TypeError, /can't convert Object into Integer/)
end
end
diff --git a/spec/ruby/core/basicobject/instance_exec_spec.rb b/spec/ruby/core/basicobject/instance_exec_spec.rb
index 370f03d33c..cfce9a65ad 100644
--- a/spec/ruby/core/basicobject/instance_exec_spec.rb
+++ b/spec/ruby/core/basicobject/instance_exec_spec.rb
@@ -3,21 +3,21 @@ require_relative 'fixtures/classes'
describe "BasicObject#instance_exec" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:instance_exec)
+ BasicObject.public_instance_methods(false).should.include?(:instance_exec)
end
it "sets self to the receiver in the context of the passed block" do
a = BasicObject.new
- a.instance_exec { self }.equal?(a).should be_true
+ a.instance_exec { self }.equal?(a).should == true
end
it "passes arguments to the block" do
a = BasicObject.new
- a.instance_exec(1) { |b| b }.should equal(1)
+ a.instance_exec(1) { |b| b }.should.equal?(1)
end
it "raises a LocalJumpError unless given a block" do
- -> { "hola".instance_exec }.should raise_error(LocalJumpError)
+ -> { "hola".instance_exec }.should.raise(LocalJumpError)
end
it "has an arity of -1" do
@@ -25,17 +25,23 @@ describe "BasicObject#instance_exec" do
end
it "accepts arguments with a block" do
- -> { "hola".instance_exec(4, 5) { |a,b| a + b } }.should_not raise_error
+ -> { "hola".instance_exec(4, 5) { |a,b| a + b } }.should_not.raise
end
it "doesn't pass self to the block as an argument" do
- "hola".instance_exec { |o| o }.should be_nil
+ "hola".instance_exec { |o| o }.should == nil
end
it "passes any arguments to the block" do
Object.new.instance_exec(1,2) {|one, two| one + two}.should == 3
end
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ Object.new.instance_exec([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
+ end
+
it "only binds the exec to the receiver" do
f = Object.new
f.instance_exec do
@@ -44,7 +50,7 @@ describe "BasicObject#instance_exec" do
end
end
f.foo.should == 1
- -> { Object.new.foo }.should raise_error(NoMethodError)
+ -> { Object.new.foo }.should.raise(NoMethodError)
end
# TODO: This should probably be replaced with a "should behave like" that uses
@@ -71,17 +77,17 @@ describe "BasicObject#instance_exec" do
end
it "sets class variables in the receiver" do
- BasicObjectSpecs::InstExec.class_variables.should include(:@@count)
+ BasicObjectSpecs::InstExec.class_variables.should.include?(:@@count)
BasicObjectSpecs::InstExec.send(:class_variable_get, :@@count).should == 2
end
it "raises a TypeError when defining methods on an immediate" do
-> do
1.instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
:foo.instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
quarantine! do # Not clean, leaves cvars lying around to break other specs
@@ -99,9 +105,9 @@ describe "BasicObject#instance_exec" do
it "raises a TypeError when defining methods on numerics" do
-> do
(1.0).instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
(1 << 64).instance_exec { def foo; end }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/basicobject/method_missing_spec.rb b/spec/ruby/core/basicobject/method_missing_spec.rb
index a29d4375bc..8785b41b21 100644
--- a/spec/ruby/core/basicobject/method_missing_spec.rb
+++ b/spec/ruby/core/basicobject/method_missing_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/basicobject/method_missing'
describe "BasicObject#method_missing" do
it "is a private method" do
- BasicObject.should have_private_instance_method(:method_missing)
+ BasicObject.private_instance_methods(false).should.include?(:method_missing)
end
end
diff --git a/spec/ruby/core/basicobject/not_equal_spec.rb b/spec/ruby/core/basicobject/not_equal_spec.rb
index 9329128c43..29b14b0fff 100644
--- a/spec/ruby/core/basicobject/not_equal_spec.rb
+++ b/spec/ruby/core/basicobject/not_equal_spec.rb
@@ -2,24 +2,24 @@ require_relative '../../spec_helper'
describe "BasicObject#!=" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:'!=')
+ BasicObject.public_instance_methods(false).should.include?(:'!=')
end
it "returns true if other is not identical to self" do
a = BasicObject.new
b = BasicObject.new
- (a != b).should be_true
+ (a != b).should == true
end
it "returns true if other is an Object" do
a = BasicObject.new
b = Object.new
- (a != b).should be_true
+ (a != b).should == true
end
it "returns false if other is identical to self" do
a = BasicObject.new
- (a != a).should be_false
+ (a != a).should == false
end
it "dispatches to #==" do
@@ -27,19 +27,19 @@ describe "BasicObject#!=" do
b = BasicObject.new
a.should_receive(:==).and_return(true)
- (a != b).should be_false
+ (a != b).should == false
end
describe "when invoked using Kernel#send" do
it "returns true if other is not identical to self" do
a = Object.new
b = Object.new
- a.send(:!=, b).should be_true
+ a.send(:!=, b).should == true
end
it "returns false if other is identical to self" do
a = Object.new
- a.send(:!=, a).should be_false
+ a.send(:!=, a).should == false
end
it "dispatches to #==" do
@@ -47,7 +47,7 @@ describe "BasicObject#!=" do
b = Object.new
a.should_receive(:==).and_return(true)
- a.send(:!=, b).should be_false
+ a.send(:!=, b).should == false
end
end
end
diff --git a/spec/ruby/core/basicobject/not_spec.rb b/spec/ruby/core/basicobject/not_spec.rb
index ca4cb6f5ff..a6f58ae6f5 100644
--- a/spec/ruby/core/basicobject/not_spec.rb
+++ b/spec/ruby/core/basicobject/not_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "BasicObject#!" do
it "is a public instance method" do
- BasicObject.should have_public_instance_method(:'!')
+ BasicObject.public_instance_methods(false).should.include?(:'!')
end
it "returns false" do
- (!BasicObject.new).should be_false
+ (!BasicObject.new).should == false
end
end
diff --git a/spec/ruby/core/basicobject/singleton_method_added_spec.rb b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
index bd21458ea7..f39b91768c 100644
--- a/spec/ruby/core/basicobject/singleton_method_added_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
@@ -7,7 +7,7 @@ describe "BasicObject#singleton_method_added" do
end
it "is a private method" do
- BasicObject.should have_private_instance_method(:singleton_method_added)
+ BasicObject.private_instance_methods(false).should.include?(:singleton_method_added)
end
it "is called when a singleton method is defined on an object" do
@@ -35,7 +35,7 @@ describe "BasicObject#singleton_method_added" do
end
end
- ScratchPad.recorded.should_not include(:new_instance_method)
+ ScratchPad.recorded.should_not.include?(:new_instance_method)
end
it "is called when a singleton method is defined on a module" do
@@ -94,7 +94,7 @@ describe "BasicObject#singleton_method_added" do
-> {
def self.foo
end
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
+ }.should.raise(NoMethodError, /undefined method [`']singleton_method_added' for/)
end
ensure
BasicObjectSpecs.send(:remove_const, :NoSingletonMethodAdded)
@@ -108,16 +108,16 @@ describe "BasicObject#singleton_method_added" do
-> {
def foo
end
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should.raise(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
-> {
define_method(:bar) {}
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should.raise(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
end
-> {
object.define_singleton_method(:baz) {}
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should.raise(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
end
it "calls #method_missing" do
diff --git a/spec/ruby/core/basicobject/singleton_method_removed_spec.rb b/spec/ruby/core/basicobject/singleton_method_removed_spec.rb
index 46f9a6894c..1831e3c070 100644
--- a/spec/ruby/core/basicobject/singleton_method_removed_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_removed_spec.rb
@@ -6,7 +6,7 @@ describe "BasicObject#singleton_method_removed" do
end
it "is a private method" do
- BasicObject.should have_private_instance_method(:singleton_method_removed)
+ BasicObject.private_instance_methods(false).should.include?(:singleton_method_removed)
end
it "is called when a method is removed on self" do
diff --git a/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb b/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb
index 7d6c7207db..cc47341878 100644
--- a/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_undefined_spec.rb
@@ -6,7 +6,7 @@ describe "BasicObject#singleton_method_undefined" do
end
it "is a private method" do
- BasicObject.should have_private_instance_method(:singleton_method_undefined)
+ BasicObject.private_instance_methods(false).should.include?(:singleton_method_undefined)
end
it "is called when a method is removed on self" do
diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb
index 4eff66bd9a..f5f0c72d5d 100644
--- a/spec/ruby/core/binding/dup_spec.rb
+++ b/spec/ruby/core/binding/dup_spec.rb
@@ -21,7 +21,7 @@ describe "Binding#dup" do
eval("a", bind2).should == 2
eval("b = 2", bind2)
- -> { eval("b", bind1) }.should raise_error(NameError)
+ -> { eval("b", bind1) }.should.raise(NameError)
eval("b", bind2).should == 2
bind1.local_variables.sort.should == [:a, :bind1, :bind2]
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index bb2036f739..f1d8591320 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -7,7 +7,7 @@ describe "Binding#eval" do
bind = obj.get_binding
bind.eval("@secret += square(3)").should == 10
- bind.eval("a").should be_true
+ bind.eval("a").should == true
bind.eval("class Inside; end")
bind.eval("Inside.name").should == "BindingSpecs::Demo::Inside"
@@ -60,14 +60,6 @@ describe "Binding#eval" do
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
- ruby_version_is ""..."3.3" do
- it "uses (eval) as __FILE__ if single argument given" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__FILE__").should == '(eval)'
- end
- end
-
it "uses 1 as __LINE__" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
@@ -107,9 +99,7 @@ describe "Binding#eval" do
bind.eval("'bar'.foo").should == "foo"
end
- ruby_version_is "3.3" do
- it "uses the caller location as default filename" do
- binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
+ it "uses the caller location as default filename" do
+ binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
end
diff --git a/spec/ruby/core/binding/local_variable_get_spec.rb b/spec/ruby/core/binding/local_variable_get_spec.rb
index 005670becc..d97100deda 100644
--- a/spec/ruby/core/binding/local_variable_get_spec.rb
+++ b/spec/ruby/core/binding/local_variable_get_spec.rb
@@ -13,7 +13,7 @@ describe "Binding#local_variable_get" do
-> {
bind.local_variable_get(:no_such_variable)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "reads variables added later to the binding" do
@@ -21,7 +21,7 @@ describe "Binding#local_variable_get" do
-> {
bind.local_variable_get(:a)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
bind.local_variable_set(:a, 42)
@@ -45,12 +45,12 @@ describe "Binding#local_variable_get" do
it "raises a NameError on global access" do
bind = binding
- -> { bind.local_variable_get(:$0) }.should raise_error(NameError)
+ -> { bind.local_variable_get(:$0) }.should.raise(NameError)
end
it "raises a NameError on special variable access" do
bind = binding
- -> { bind.local_variable_get(:$~) }.should raise_error(NameError)
- -> { bind.local_variable_get(:$_) }.should raise_error(NameError)
+ -> { bind.local_variable_get(:$~) }.should.raise(NameError)
+ -> { bind.local_variable_get(:$_) }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/binding/local_variable_set_spec.rb b/spec/ruby/core/binding/local_variable_set_spec.rb
index 1456c6dda1..3e4f407fc3 100644
--- a/spec/ruby/core/binding/local_variable_set_spec.rb
+++ b/spec/ruby/core/binding/local_variable_set_spec.rb
@@ -38,7 +38,7 @@ describe "Binding#local_variable_set" do
bind = binding
bind.local_variable_set(:number, 10)
- -> { number }.should raise_error(NameError)
+ -> { number }.should.raise(NameError)
end
it 'overwrites an existing local variable defined before a Binding' do
@@ -59,13 +59,13 @@ describe "Binding#local_variable_set" do
it "raises a NameError on global access" do
bind = binding
- -> { bind.local_variable_set(:$0, "") }.should raise_error(NameError)
+ -> { bind.local_variable_set(:$0, "") }.should.raise(NameError)
end
it "raises a NameError on special variable access" do
bind = binding
- -> { bind.local_variable_set(:$~, "") }.should raise_error(NameError)
- -> { bind.local_variable_set(:$_, "") }.should raise_error(NameError)
+ -> { bind.local_variable_set(:$~, "") }.should.raise(NameError)
+ -> { bind.local_variable_set(:$_, "") }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/binding/local_variables_spec.rb b/spec/ruby/core/binding/local_variables_spec.rb
index 92c817b9a8..0f59681342 100644
--- a/spec/ruby/core/binding/local_variables_spec.rb
+++ b/spec/ruby/core/binding/local_variables_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Binding#local_variables" do
it "returns an Array" do
- binding.local_variables.should be_kind_of(Array)
+ binding.local_variables.should.is_a?(Array)
end
it "includes local variables in the current scope" do
diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
index eaf311783a..67b3339aa6 100644
--- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
+++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "RUBY_VERSION" do
it "is a String" do
- RUBY_VERSION.should be_kind_of(String)
+ RUBY_VERSION.should.is_a?(String)
end
it "is frozen" do
@@ -12,13 +12,13 @@ end
describe "RUBY_PATCHLEVEL" do
it "is an Integer" do
- RUBY_PATCHLEVEL.should be_kind_of(Integer)
+ RUBY_PATCHLEVEL.should.is_a?(Integer)
end
end
describe "RUBY_COPYRIGHT" do
it "is a String" do
- RUBY_COPYRIGHT.should be_kind_of(String)
+ RUBY_COPYRIGHT.should.is_a?(String)
end
it "is frozen" do
@@ -28,7 +28,7 @@ end
describe "RUBY_DESCRIPTION" do
it "is a String" do
- RUBY_DESCRIPTION.should be_kind_of(String)
+ RUBY_DESCRIPTION.should.is_a?(String)
end
it "is frozen" do
@@ -38,7 +38,7 @@ end
describe "RUBY_ENGINE" do
it "is a String" do
- RUBY_ENGINE.should be_kind_of(String)
+ RUBY_ENGINE.should.is_a?(String)
end
it "is frozen" do
@@ -46,9 +46,19 @@ describe "RUBY_ENGINE" do
end
end
+describe "RUBY_ENGINE_VERSION" do
+ it "is a String" do
+ RUBY_ENGINE_VERSION.should.is_a?(String)
+ end
+
+ it "is frozen" do
+ RUBY_ENGINE_VERSION.should.frozen?
+ end
+end
+
describe "RUBY_PLATFORM" do
it "is a String" do
- RUBY_PLATFORM.should be_kind_of(String)
+ RUBY_PLATFORM.should.is_a?(String)
end
it "is frozen" do
@@ -58,7 +68,7 @@ end
describe "RUBY_RELEASE_DATE" do
it "is a String" do
- RUBY_RELEASE_DATE.should be_kind_of(String)
+ RUBY_RELEASE_DATE.should.is_a?(String)
end
it "is frozen" do
@@ -68,10 +78,72 @@ end
describe "RUBY_REVISION" do
it "is a String" do
- RUBY_REVISION.should be_kind_of(String)
+ RUBY_REVISION.should.is_a?(String)
end
it "is frozen" do
RUBY_REVISION.should.frozen?
end
end
+
+ruby_version_is "4.0" do
+ describe "Ruby" do
+ it "is a Module" do
+ Ruby.should.instance_of?(Module)
+ end
+ end
+
+ describe "Ruby::VERSION" do
+ it "is equal to RUBY_VERSION" do
+ Ruby::VERSION.should.equal?(RUBY_VERSION)
+ end
+ end
+
+ describe "RUBY::PATCHLEVEL" do
+ it "is equal to RUBY_PATCHLEVEL" do
+ Ruby::PATCHLEVEL.should.equal?(RUBY_PATCHLEVEL)
+ end
+ end
+
+ describe "Ruby::COPYRIGHT" do
+ it "is equal to RUBY_COPYRIGHT" do
+ Ruby::COPYRIGHT.should.equal?(RUBY_COPYRIGHT)
+ end
+ end
+
+ describe "Ruby::DESCRIPTION" do
+ it "is equal to RUBY_DESCRIPTION" do
+ Ruby::DESCRIPTION.should.equal?(RUBY_DESCRIPTION)
+ end
+ end
+
+ describe "Ruby::ENGINE" do
+ it "is equal to RUBY_ENGINE" do
+ Ruby::ENGINE.should.equal?(RUBY_ENGINE)
+ end
+ end
+
+ describe "Ruby::ENGINE_VERSION" do
+ it "is equal to RUBY_ENGINE_VERSION" do
+ Ruby::ENGINE_VERSION.should.equal?(RUBY_ENGINE_VERSION)
+ end
+ end
+
+ describe "Ruby::PLATFORM" do
+ it "is equal to RUBY_PLATFORM" do
+ Ruby::PLATFORM.should.equal?(RUBY_PLATFORM)
+ end
+ end
+
+ describe "Ruby::RELEASE_DATE" do
+ it "is equal to RUBY_RELEASE_DATE" do
+ Ruby::RELEASE_DATE.should.equal?(RUBY_RELEASE_DATE)
+ end
+ end
+
+ describe "Ruby::REVISION" do
+ it "is equal to RUBY_REVISION" do
+ Ruby::REVISION.should.equal?(RUBY_REVISION)
+ end
+ end
+end
diff --git a/spec/ruby/core/class/allocate_spec.rb b/spec/ruby/core/class/allocate_spec.rb
index b39622e06a..b8950a678e 100644
--- a/spec/ruby/core/class/allocate_spec.rb
+++ b/spec/ruby/core/class/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Class#allocate" do
it "returns an instance of self" do
klass = Class.new
- klass.allocate.should be_an_instance_of(klass)
+ klass.allocate.should.instance_of?(klass)
end
it "returns a fully-formed instance of Module" do
@@ -16,7 +16,7 @@ describe "Class#allocate" do
klass = Class.allocate
-> do
klass.new
- end.should raise_error(Exception)
+ end.should.raise(Exception)
end
it "does not call initialize on the new instance" do
@@ -36,6 +36,6 @@ describe "Class#allocate" do
it "raises TypeError for #superclass" do
-> do
Class.allocate.superclass
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb
index f1c0f63a44..b75e61ca07 100644
--- a/spec/ruby/core/class/attached_object_spec.rb
+++ b/spec/ruby/core/class/attached_object_spec.rb
@@ -1,31 +1,29 @@
require_relative '../../spec_helper'
-ruby_version_is '3.2' do
- describe "Class#attached_object" do
- it "returns the object that is attached to a singleton class" do
- a = Class.new
+describe "Class#attached_object" do
+ it "returns the object that is attached to a singleton class" do
+ a = Class.new
- a_obj = a.new
- a_obj.singleton_class.attached_object.should == a_obj
- end
+ a_obj = a.new
+ a_obj.singleton_class.attached_object.should == a_obj
+ end
- it "returns the class object that is attached to a class's singleton class" do
- a = Class.new
- singleton_class = (class << a; self; end)
+ it "returns the class object that is attached to a class's singleton class" do
+ a = Class.new
+ singleton_class = (class << a; self; end)
- singleton_class.attached_object.should == a
- end
+ singleton_class.attached_object.should == a
+ end
- it "raises TypeError if the class is not a singleton class" do
- a = Class.new
+ it "raises TypeError if the class is not a singleton class" do
+ a = Class.new
- -> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/)
- end
+ -> { a.attached_object }.should.raise(TypeError, /is not a singleton class/)
+ end
- it "raises TypeError for special singleton classes" do
- -> { nil.singleton_class.attached_object }.should raise_error(TypeError, /[`']NilClass' is not a singleton class/)
- -> { true.singleton_class.attached_object }.should raise_error(TypeError, /[`']TrueClass' is not a singleton class/)
- -> { false.singleton_class.attached_object }.should raise_error(TypeError, /[`']FalseClass' is not a singleton class/)
- end
+ it "raises TypeError for special singleton classes" do
+ -> { nil.singleton_class.attached_object }.should.raise(TypeError, /[`']NilClass' is not a singleton class/)
+ -> { true.singleton_class.attached_object }.should.raise(TypeError, /[`']TrueClass' is not a singleton class/)
+ -> { false.singleton_class.attached_object }.should.raise(TypeError, /[`']FalseClass' is not a singleton class/)
end
end
diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb
index 1ff9abf7b4..17c0171ceb 100644
--- a/spec/ruby/core/class/dup_spec.rb
+++ b/spec/ruby/core/class/dup_spec.rb
@@ -53,7 +53,7 @@ describe "Class#dup" do
it "sets the name from the class to nil if not assigned to a constant" do
copy = CoreClassSpecs::Record.dup
- copy.name.should be_nil
+ copy.name.should == nil
end
it "stores the new name if assigned to a constant" do
@@ -64,6 +64,6 @@ describe "Class#dup" do
end
it "raises TypeError if called on BasicObject" do
- -> { BasicObject.dup }.should raise_error(TypeError, "can't copy the root class")
+ -> { BasicObject.dup }.should.raise(TypeError, "can't copy the root class")
end
end
diff --git a/spec/ruby/core/class/fixtures/callback_order.rb b/spec/ruby/core/class/fixtures/callback_order.rb
deleted file mode 100644
index b7b52ab778..0000000000
--- a/spec/ruby/core/class/fixtures/callback_order.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module CoreClassSpecs
- module Callbacks
- class Base
- def self.inherited(subclass)
- subclass.const_set(:INHERITED_NAME, subclass.name)
- ORDER << [
- :inherited,
- subclass,
- eval("defined?(#{subclass.name})"),
- Object.const_source_location(subclass.name) ? :location : :unknown_location,
- ]
- super
- end
- end
-
- ORDER = []
-
- def self.const_added(const_name)
- ORDER << [
- :const_added,
- const_name,
- eval("defined?(#{const_name})"),
- const_source_location(const_name) ? :location : :unknown_location,
- ]
- super
- end
-
- class Child < Base
- end
- end
-end
diff --git a/spec/ruby/core/class/inherited_spec.rb b/spec/ruby/core/class/inherited_spec.rb
index 15d0c3ddb9..c9acc740a1 100644
--- a/spec/ruby/core/class/inherited_spec.rb
+++ b/spec/ruby/core/class/inherited_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'fixtures/callback_order'
describe "Class.inherited" do
@@ -93,22 +92,27 @@ describe "Class.inherited" do
end
class << top; private :inherited; end
- -> { Class.new(top) }.should_not raise_error
+ -> { Class.new(top) }.should_not.raise
class << top; protected :inherited; end
- -> { Class.new(top) }.should_not raise_error
+ -> { Class.new(top) }.should_not.raise
end
- it "is invoked after the class is named when using class definition syntax" do
- CoreClassSpecs::Callbacks::Child::INHERITED_NAME.should == "CoreClassSpecs::Callbacks::Child"
- end
+ it "if the subclass is assigned to a constant, it is all set" do
+ ScratchPad.record []
- ruby_version_is "3.5" do # https://bugs.ruby-lang.org/issues/21143
- it "is invoked before `const_added`" do
- CoreClassSpecs::Callbacks::ORDER.should == [
- [:inherited, CoreClassSpecs::Callbacks::Child, "constant", :location],
- [:const_added, :Child, "constant", :location],
- ]
+ parent = Class.new do
+ def self.inherited(subclass)
+ ScratchPad << defined?(self::C)
+ ScratchPad << const_defined?(:C)
+ ScratchPad << constants
+ ScratchPad << const_get(:C)
+ ScratchPad << subclass.name.match?(/\A#<Class:0x\w+>::C\z/)
+ end
end
+
+ class parent::C < parent; end
+
+ ScratchPad.recorded.should == ["constant", true, [:C], parent::C, true]
end
end
diff --git a/spec/ruby/core/class/initialize_spec.rb b/spec/ruby/core/class/initialize_spec.rb
index 6348758485..ab8f0a157e 100644
--- a/spec/ruby/core/class/initialize_spec.rb
+++ b/spec/ruby/core/class/initialize_spec.rb
@@ -2,24 +2,24 @@ require_relative '../../spec_helper'
describe "Class#initialize" do
it "is private" do
- Class.should have_private_method(:initialize)
+ Class.private_methods(false).should.include?(:initialize)
end
it "raises a TypeError when called on already initialized classes" do
->{
Integer.send :initialize
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
->{
Object.send :initialize
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
# See [redmine:2601]
it "raises a TypeError when called on BasicObject" do
->{
BasicObject.send :initialize
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
describe "when given the Class" do
@@ -28,7 +28,7 @@ describe "Class#initialize" do
end
it "raises a TypeError" do
- ->{@uninitialized.send(:initialize, Class)}.should raise_error(TypeError)
+ ->{@uninitialized.send(:initialize, Class)}.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/class/new_spec.rb b/spec/ruby/core/class/new_spec.rb
index 6fe54c3209..111e31252e 100644
--- a/spec/ruby/core/class/new_spec.rb
+++ b/spec/ruby/core/class/new_spec.rb
@@ -7,7 +7,7 @@ describe "Class.new with a block given" do
klass = Class.new do
self_in_block = self
end
- self_in_block.should equal klass
+ self_in_block.should.equal? klass
end
it "uses the given block as the class' body" do
@@ -70,11 +70,11 @@ describe "Class.new" do
it "raises a TypeError if passed a metaclass" do
obj = mock("Class.new metaclass")
meta = obj.singleton_class
- -> { Class.new meta }.should raise_error(TypeError)
+ -> { Class.new meta }.should.raise(TypeError)
end
it "creates a class without a name" do
- Class.new.name.should be_nil
+ Class.new.name.should == nil
end
it "creates a class that can be given a name by assigning it to a constant" do
@@ -98,12 +98,12 @@ describe "Class.new" do
it "raises a TypeError when given a non-Class" do
error_msg = /superclass must be a.*Class/
- -> { Class.new("") }.should raise_error(TypeError, error_msg)
- -> { Class.new(1) }.should raise_error(TypeError, error_msg)
- -> { Class.new(:symbol) }.should raise_error(TypeError, error_msg)
- -> { Class.new(mock('o')) }.should raise_error(TypeError, error_msg)
- -> { Class.new(Module.new) }.should raise_error(TypeError, error_msg)
- -> { Class.new(BasicObject.new) }.should raise_error(TypeError, error_msg)
+ -> { Class.new("") }.should.raise(TypeError, error_msg)
+ -> { Class.new(1) }.should.raise(TypeError, error_msg)
+ -> { Class.new(:symbol) }.should.raise(TypeError, error_msg)
+ -> { Class.new(mock('o')) }.should.raise(TypeError, error_msg)
+ -> { Class.new(Module.new) }.should.raise(TypeError, error_msg)
+ -> { Class.new(BasicObject.new) }.should.raise(TypeError, error_msg)
end
end
@@ -141,8 +141,8 @@ describe "Class#new" do
end
instance = klass.new
- instance.should be_kind_of klass
- instance.class.should equal klass
+ instance.should.is_a? klass
+ instance.class.should.equal? klass
end
it "passes the block to #initialize" do
diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb
index f692152787..c3d7b07e12 100644
--- a/spec/ruby/core/class/subclasses_spec.rb
+++ b/spec/ruby/core/class/subclasses_spec.rb
@@ -50,7 +50,7 @@ describe "Class#subclasses" do
42
end
- a.subclasses.should_not include(a_obj.singleton_class)
+ a.subclasses.should_not.include?(a_obj.singleton_class)
end
it "has 1 entry per module or class" do
@@ -76,7 +76,7 @@ describe "Class#subclasses" do
classes = threads.map(&:value)
superclass.subclasses.size.should == t * n
- superclass.subclasses.each { |c| c.should be_kind_of(Class) }
+ superclass.subclasses.each { |c| c.should.is_a?(Class) }
end
def assert_subclasses(mod,subclasses)
diff --git a/spec/ruby/core/class/superclass_spec.rb b/spec/ruby/core/class/superclass_spec.rb
index 00579238a6..87d9b20490 100644
--- a/spec/ruby/core/class/superclass_spec.rb
+++ b/spec/ruby/core/class/superclass_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Class#superclass" do
it "returns the superclass of self" do
- BasicObject.superclass.should be_nil
+ BasicObject.superclass.should == nil
Object.superclass.should == BasicObject
Class.superclass.should == Module
Class.new.superclass.should == Object
diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb
index 796d4a18c1..eb1dc1ff98 100644
--- a/spec/ruby/core/comparable/clamp_spec.rb
+++ b/spec/ruby/core/comparable/clamp_spec.rb
@@ -7,9 +7,9 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- -> { c.clamp(two, one) }.should raise_error(ArgumentError)
+ -> { c.clamp(two, one) }.should.raise(ArgumentError)
one.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { c.clamp(one, two) }.should raise_error(ArgumentError)
+ -> { c.clamp(one, two) }.should.raise(ArgumentError)
end
it 'returns self if within the given parameters' do
@@ -18,18 +18,18 @@ describe 'Comparable#clamp' do
three = ComparableSpecs::WithOnlyCompareDefined.new(3)
c = ComparableSpecs::Weird.new(2)
- c.clamp(one, two).should equal(c)
- c.clamp(two, two).should equal(c)
- c.clamp(one, three).should equal(c)
- c.clamp(two, three).should equal(c)
+ c.clamp(one, two).should.equal?(c)
+ c.clamp(two, two).should.equal?(c)
+ c.clamp(one, three).should.equal?(c)
+ c.clamp(two, three).should.equal?(c)
end
- it 'returns the min parameter if smaller than it' do
+ it 'returns the min parameter if less than it' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(0)
- c.clamp(one, two).should equal(one)
+ c.clamp(one, two).should.equal?(one)
end
it 'returns the max parameter if greater than it' do
@@ -37,7 +37,40 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- c.clamp(one, two).should equal(two)
+ c.clamp(one, two).should.equal?(two)
+ end
+
+ context 'max is nil' do
+ it 'returns min if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+ c.clamp(one, nil).should.equal?(one)
+ end
+
+ it 'always returns self if greater than min' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+ c.clamp(one, nil).should.equal?(c)
+ end
+ end
+
+ context 'min is nil' do
+ it 'returns max if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+ c.clamp(nil, one).should.equal?(one)
+ end
+
+ it 'always returns self if less than max' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+ c.clamp(nil, one).should.equal?(c)
+ end
+ end
+
+ it 'always returns self when min is nil and max is nil' do
+ c = ComparableSpecs::Weird.new(1)
+ c.clamp(nil, nil).should.equal?(c)
end
it 'returns self if within the given range parameters' do
@@ -46,18 +79,18 @@ describe 'Comparable#clamp' do
three = ComparableSpecs::WithOnlyCompareDefined.new(3)
c = ComparableSpecs::Weird.new(2)
- c.clamp(one..two).should equal(c)
- c.clamp(two..two).should equal(c)
- c.clamp(one..three).should equal(c)
- c.clamp(two..three).should equal(c)
+ c.clamp(one..two).should.equal?(c)
+ c.clamp(two..two).should.equal?(c)
+ c.clamp(one..three).should.equal?(c)
+ c.clamp(two..three).should.equal?(c)
end
- it 'returns the minimum value of the range parameters if smaller than it' do
+ it 'returns the minimum value of the range parameters if less than it' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(0)
- c.clamp(one..two).should equal(one)
+ c.clamp(one..two).should.equal?(one)
end
it 'returns the maximum value of the range parameters if greater than it' do
@@ -65,7 +98,7 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- c.clamp(one..two).should equal(two)
+ c.clamp(one..two).should.equal?(two)
end
it 'raises an Argument error if the range parameter is exclusive' do
@@ -73,6 +106,118 @@ describe 'Comparable#clamp' do
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(3)
- -> { c.clamp(one...two) }.should raise_error(ArgumentError)
+ -> { c.clamp(one...two) }.should.raise(ArgumentError)
+ end
+
+ context 'with nil as the max argument' do
+ it 'returns min argument if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one, nil).should.equal?(one)
+ c.clamp(zero, nil).should.equal?(c)
+ end
+
+ it 'always returns self if greater than min argument' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one, nil).should.equal?(c)
+ c.clamp(two, nil).should.equal?(c)
+ end
+ end
+
+ context 'with endless range' do
+ it 'returns minimum value of the range parameters if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one..).should.equal?(one)
+ c.clamp(zero..).should.equal?(c)
+ end
+
+ it 'always returns self if greater than minimum value of the range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one..).should.equal?(c)
+ c.clamp(two..).should.equal?(c)
+ end
+
+ it 'works with exclusive range' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one...).should.equal?(c)
+ end
+ end
+
+ context 'with nil as the min argument' do
+ it 'returns max argument if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(nil, one).should.equal?(one)
+ end
+
+ it 'always returns self if less than max argument' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(nil, one).should.equal?(c)
+ c.clamp(nil, zero).should.equal?(c)
+ end
+ end
+
+ context 'with beginless range' do
+ it 'returns maximum value of the range parameters if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(..one).should.equal?(one)
+ end
+
+ it 'always returns self if less than maximum value of the range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(..one).should.equal?(c)
+ c.clamp(..zero).should.equal?(c)
+ end
+
+ it 'raises an Argument error if the range parameter is exclusive' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+
+ -> { c.clamp(...one) }.should.raise(ArgumentError)
+ end
+ end
+
+ context 'with nil as the min and the max argument' do
+ it 'always returns self' do
+ c = ComparableSpecs::Weird.new(1)
+
+ c.clamp(nil, nil).should.equal?(c)
+ end
+ end
+
+ context 'with beginless-and-endless range' do
+ it 'always returns self' do
+ c = ComparableSpecs::Weird.new(1)
+
+ c.clamp(nil..nil).should.equal?(c)
+ end
+
+ it 'works with exclusive range' do
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(nil...nil).should.equal?(c)
+ end
end
end
diff --git a/spec/ruby/core/comparable/equal_value_spec.rb b/spec/ruby/core/comparable/equal_value_spec.rb
index ddcc03cb41..3af40d1c7e 100644
--- a/spec/ruby/core/comparable/equal_value_spec.rb
+++ b/spec/ruby/core/comparable/equal_value_spec.rb
@@ -39,7 +39,7 @@ describe "Comparable#==" do
end
it "returns false" do
- (a == b).should be_false
+ (a == b).should == false
end
end
@@ -49,7 +49,7 @@ describe "Comparable#==" do
end
it "raises an ArgumentError" do
- -> { (a == b) }.should raise_error(ArgumentError)
+ -> { (a == b) }.should.raise(ArgumentError)
end
end
@@ -60,7 +60,7 @@ describe "Comparable#==" do
end
it "lets it go through" do
- -> { (a == b) }.should raise_error(StandardError)
+ -> { (a == b) }.should.raise(StandardError)
end
end
@@ -71,13 +71,13 @@ describe "Comparable#==" do
end
it "lets it go through" do
- -> { (a == b) }.should raise_error(TypeError)
+ -> { (a == b) }.should.raise(TypeError)
end
end
it "lets it go through if it is not a StandardError" do
a.should_receive(:<=>).once.and_raise(Exception)
- -> { (a == b) }.should raise_error(Exception)
+ -> { (a == b) }.should.raise(Exception)
end
end
diff --git a/spec/ruby/core/comparable/fixtures/classes.rb b/spec/ruby/core/comparable/fixtures/classes.rb
index 4239a47d2f..2bdabbf014 100644
--- a/spec/ruby/core/comparable/fixtures/classes.rb
+++ b/spec/ruby/core/comparable/fixtures/classes.rb
@@ -7,6 +7,7 @@ module ComparableSpecs
end
def <=>(other)
+ return nil if other.nil?
self.value <=> other.value
end
end
diff --git a/spec/ruby/core/comparable/gt_spec.rb b/spec/ruby/core/comparable/gt_spec.rb
index 150e653dc7..cebb5464ad 100644
--- a/spec/ruby/core/comparable/gt_spec.rb
+++ b/spec/ruby/core/comparable/gt_spec.rb
@@ -38,6 +38,6 @@ describe "Comparable#>" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a > b) }.should raise_error(ArgumentError)
+ -> { (a > b) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/comparable/gte_spec.rb b/spec/ruby/core/comparable/gte_spec.rb
index 328f58c66c..16da81b3ea 100644
--- a/spec/ruby/core/comparable/gte_spec.rb
+++ b/spec/ruby/core/comparable/gte_spec.rb
@@ -42,6 +42,6 @@ describe "Comparable#>=" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a >= b) }.should raise_error(ArgumentError)
+ -> { (a >= b) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/comparable/lt_spec.rb b/spec/ruby/core/comparable/lt_spec.rb
index bca95f8d25..175646d0d7 100644
--- a/spec/ruby/core/comparable/lt_spec.rb
+++ b/spec/ruby/core/comparable/lt_spec.rb
@@ -38,12 +38,12 @@ describe "Comparable#<" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a < b) }.should raise_error(ArgumentError)
+ -> { (a < b) }.should.raise(ArgumentError)
end
it "raises an argument error with a message containing the value" do
- -> { ("foo" < 7) }.should raise_error(ArgumentError) { |e|
- e.message.should == "comparison of String with 7 failed"
+ -> { ("foo" < 7) }.should.raise(ArgumentError) { |e|
+ e.message.should.include? "String with 7 failed"
}
end
end
diff --git a/spec/ruby/core/comparable/lte_spec.rb b/spec/ruby/core/comparable/lte_spec.rb
index b5cb9cc4e7..8cbbd5ebb4 100644
--- a/spec/ruby/core/comparable/lte_spec.rb
+++ b/spec/ruby/core/comparable/lte_spec.rb
@@ -41,6 +41,6 @@ describe "Comparable#<=" do
b = ComparableSpecs::Weird.new(20)
a.should_receive(:<=>).any_number_of_times.and_return(nil)
- -> { (a <= b) }.should raise_error(ArgumentError)
+ -> { (a <= b) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/complex/abs_spec.rb b/spec/ruby/core/complex/abs_spec.rb
index 43912c517f..ed5aebb11d 100644
--- a/spec/ruby/core/complex/abs_spec.rb
+++ b/spec/ruby/core/complex/abs_spec.rb
@@ -1,6 +1,12 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
describe "Complex#abs" do
- it_behaves_like :complex_abs, :abs
+ it "returns the modulus: |a + bi| = sqrt((a ^ 2) + (b ^ 2))" do
+ Complex(0, 0).abs.should == 0
+ Complex(3, 4).abs.should == 5 # well-known integer case
+ Complex(-3, 4).abs.should == 5
+ Complex(1, -1).abs.should be_close(Math.sqrt(2), TOLERANCE)
+ Complex(6.5, 0).abs.should be_close(6.5, TOLERANCE)
+ Complex(0, -7.2).abs.should be_close(7.2, TOLERANCE)
+ end
end
diff --git a/spec/ruby/core/complex/angle_spec.rb b/spec/ruby/core/complex/angle_spec.rb
index 4aa176956f..7551214d2b 100644
--- a/spec/ruby/core/complex/angle_spec.rb
+++ b/spec/ruby/core/complex/angle_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Complex#angle" do
- it_behaves_like :complex_arg, :angle
+ it "is an alias of Complex#arg" do
+ Complex.instance_method(:angle).should == Complex.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/complex/arg_spec.rb b/spec/ruby/core/complex/arg_spec.rb
index 009f19429f..dd64102d77 100644
--- a/spec/ruby/core/complex/arg_spec.rb
+++ b/spec/ruby/core/complex/arg_spec.rb
@@ -1,6 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Complex#arg" do
- it_behaves_like :complex_arg, :arg
+ it "returns the argument -- i.e., the angle from (1, 0) in the complex plane" do
+ two_pi = 2 * Math::PI
+ (Complex(1, 0).arg % two_pi).should be_close(0, TOLERANCE)
+ (Complex(0, 2).arg % two_pi).should be_close(Math::PI * 0.5, TOLERANCE)
+ (Complex(-100, 0).arg % two_pi).should be_close(Math::PI, TOLERANCE)
+ (Complex(0, -75.3).arg % two_pi).should be_close(Math::PI * 1.5, TOLERANCE)
+ end
end
diff --git a/spec/ruby/core/complex/coerce_spec.rb b/spec/ruby/core/complex/coerce_spec.rb
index a30a6c1d5f..d4ea85a713 100644
--- a/spec/ruby/core/complex/coerce_spec.rb
+++ b/spec/ruby/core/complex/coerce_spec.rb
@@ -8,37 +8,37 @@ describe "Complex#coerce" do
it "returns an array containing other and self as Complex when other is an Integer" do
result = @one.coerce(2)
result.should == [2, 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self as Complex when other is a Float" do
result = @one.coerce(20.5)
result.should == [20.5, 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self as Complex when other is a Bignum" do
result = @one.coerce(4294967296)
result.should == [4294967296, 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self as Complex when other is a Rational" do
result = @one.coerce(Rational(5,6))
result.should == [Rational(5,6), 1]
- result.first.should be_kind_of(Complex)
- result.last.should be_kind_of(Complex)
+ result.first.should.is_a?(Complex)
+ result.last.should.is_a?(Complex)
end
it "returns an array containing other and self when other is a Complex" do
other = Complex(2)
result = @one.coerce(other)
result.should == [other, @one]
- result.first.should equal(other)
- result.last.should equal(@one)
+ result.first.should.equal?(other)
+ result.last.should.equal?(@one)
end
it "returns an array containing other as Complex and self when other is a Numeric which responds to #real? with true" do
@@ -46,25 +46,25 @@ describe "Complex#coerce" do
other.should_receive(:real?).any_number_of_times.and_return(true)
result = @one.coerce(other)
result.should == [other, @one]
- result.first.should eql(Complex(other))
- result.last.should equal(@one)
+ result.first.should.eql?(Complex(other))
+ result.last.should.equal?(@one)
end
it "raises TypeError when other is a Numeric which responds to #real? with false" do
other = mock_numeric('other')
other.should_receive(:real?).any_number_of_times.and_return(false)
- -> { @one.coerce(other) }.should raise_error(TypeError)
+ -> { @one.coerce(other) }.should.raise(TypeError)
end
it "raises a TypeError when other is a String" do
- -> { @one.coerce("20") }.should raise_error(TypeError)
+ -> { @one.coerce("20") }.should.raise(TypeError)
end
it "raises a TypeError when other is nil" do
- -> { @one.coerce(nil) }.should raise_error(TypeError)
+ -> { @one.coerce(nil) }.should.raise(TypeError)
end
it "raises a TypeError when other is false" do
- -> { @one.coerce(false) }.should raise_error(TypeError)
+ -> { @one.coerce(false) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/complex/comparison_spec.rb b/spec/ruby/core/complex/comparison_spec.rb
index 3a3142f234..3115f4e205 100644
--- a/spec/ruby/core/complex/comparison_spec.rb
+++ b/spec/ruby/core/complex/comparison_spec.rb
@@ -2,15 +2,15 @@ require_relative '../../spec_helper'
describe "Complex#<=>" do
it "returns nil if either self or argument has imaginary part" do
- (Complex(5, 1) <=> Complex(2)).should be_nil
- (Complex(1) <=> Complex(2, 1)).should be_nil
- (5 <=> Complex(2, 1)).should be_nil
+ (Complex(5, 1) <=> Complex(2)).should == nil
+ (Complex(1) <=> Complex(2, 1)).should == nil
+ (5 <=> Complex(2, 1)).should == nil
end
it "returns nil if argument is not numeric" do
- (Complex(5, 1) <=> "cmp").should be_nil
- (Complex(1) <=> "cmp").should be_nil
- (Complex(1) <=> Object.new).should be_nil
+ (Complex(5, 1) <=> "cmp").should == nil
+ (Complex(1) <=> "cmp").should == nil
+ (Complex(1) <=> Object.new).should == nil
end
it "returns 0, 1, or -1 if self and argument do not have imaginary part" do
diff --git a/spec/ruby/core/complex/conj_spec.rb b/spec/ruby/core/complex/conj_spec.rb
index 5e3bc1acb8..063c85faec 100644
--- a/spec/ruby/core/complex/conj_spec.rb
+++ b/spec/ruby/core/complex/conj_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
describe "Complex#conj" do
- it_behaves_like :complex_conjugate, :conj
+ it "is an alias of Complex#conjugate" do
+ Complex.instance_method(:conj).should == Complex.instance_method(:conjugate)
+ end
end
diff --git a/spec/ruby/core/complex/conjugate_spec.rb b/spec/ruby/core/complex/conjugate_spec.rb
index f658bab4da..256fe4b3be 100644
--- a/spec/ruby/core/complex/conjugate_spec.rb
+++ b/spec/ruby/core/complex/conjugate_spec.rb
@@ -1,6 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
describe "Complex#conjugate" do
- it_behaves_like :complex_conjugate, :conjugate
+ it "returns the complex conjugate: conj a + bi = a - bi" do
+ Complex(3, 5).conjugate.should == Complex(3, -5)
+ Complex(3, -5).conjugate.should == Complex(3, 5)
+ Complex(-3.0, 5.2).conjugate.should be_close(Complex(-3.0, -5.2), TOLERANCE)
+ Complex(3.0, -5.2).conjugate.should be_close(Complex(3.0, 5.2), TOLERANCE)
+ end
end
diff --git a/spec/ruby/core/complex/constants_spec.rb b/spec/ruby/core/complex/constants_spec.rb
index 50303de16c..200e97731a 100644
--- a/spec/ruby/core/complex/constants_spec.rb
+++ b/spec/ruby/core/complex/constants_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "Complex::I" do
it "is Complex(0, 1)" do
- Complex::I.should eql(Complex(0, 1))
+ Complex::I.should.eql?(Complex(0, 1))
end
end
diff --git a/spec/ruby/core/complex/divide_spec.rb b/spec/ruby/core/complex/divide_spec.rb
index bebf862312..d5b4aa3885 100644
--- a/spec/ruby/core/complex/divide_spec.rb
+++ b/spec/ruby/core/complex/divide_spec.rb
@@ -1,6 +1,84 @@
require_relative '../../spec_helper'
-require_relative 'shared/divide'
describe "Complex#/" do
- it_behaves_like :complex_divide, :/
+ describe "with Complex" do
+ it "divides according to the usual rule for complex numbers" do
+ a = Complex((1 * 10) - (2 * 20), (1 * 20) + (2 * 10))
+ b = Complex(1, 2)
+ (a / b).should == Complex(10, 20)
+
+ c = Complex((1.5 * 100.2) - (2.1 * -30.3), (1.5 * -30.3) + (2.1 * 100.2))
+ d = Complex(1.5, 2.1)
+ # remember the floating-point arithmetic
+ (c / d).should be_close(Complex(100.2, -30.3), TOLERANCE)
+ end
+ end
+
+ describe "with Fixnum" do
+ it "divides both parts of the Complex number" do
+ (Complex(20, 40) / 2).should == Complex(10, 20)
+ (Complex(30, 30) / 10).should == Complex(3, 3)
+ end
+
+ it "raises a ZeroDivisionError when given zero" do
+ -> { Complex(20, 40) / 0 }.should.raise(ZeroDivisionError)
+ end
+
+ it "produces Rational parts" do
+ (Complex(5, 9) / 2).should.eql?(Complex(Rational(5,2), Rational(9,2)))
+ end
+ end
+
+ describe "with Bignum" do
+ it "divides both parts of the Complex number" do
+ (Complex(20, 40) / 2).should == Complex(10, 20)
+ (Complex(15, 16) / 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
+ end
+ end
+
+ describe "with Float" do
+ it "divides both parts of the Complex number" do
+ (Complex(3, 9) / 1.5).should == Complex(2, 6)
+ (Complex(15, 16) / 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
+ end
+
+ it "returns Complex(Infinity, Infinity) when given zero" do
+ (Complex(20, 40) / 0.0).real.infinite?.should == 1
+ (Complex(20, 40) / 0.0).imag.infinite?.should == 1
+ (Complex(-20, 40) / 0.0).real.infinite?.should == -1
+ (Complex(-20, 40) / 0.0).imag.infinite?.should == 1
+ end
+ end
+
+ describe "with Object" do
+ it "tries to coerce self into other" do
+ value = Complex(3, 9)
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(value).and_return([4, 2])
+ (value / obj).should == 2
+ end
+ end
+
+ describe "with a Numeric which responds to #real? with true" do
+ it "returns Complex(real.quo(other), imag.quo(other))" do
+ other = mock_numeric('other')
+ real = mock_numeric('real')
+ imag = mock_numeric('imag')
+ other.should_receive(:real?).and_return(true)
+ real.should_receive(:quo).with(other).and_return(1)
+ imag.should_receive(:quo).with(other).and_return(2)
+ (Complex(real, imag) / other).should == Complex(1, 2)
+ end
+ end
+
+ describe "with a Numeric which responds to #real? with false" do
+ it "coerces the passed argument to Complex and divides the resulting elements" do
+ complex = Complex(3, 0)
+ other = mock_numeric('other')
+ other.should_receive(:real?).any_number_of_times.and_return(false)
+ other.should_receive(:coerce).with(complex).and_return([5, 2])
+ (complex / other).should.eql?(Rational(5, 2))
+ end
+ end
end
diff --git a/spec/ruby/core/complex/eql_spec.rb b/spec/ruby/core/complex/eql_spec.rb
index 9194efc074..2082a22feb 100644
--- a/spec/ruby/core/complex/eql_spec.rb
+++ b/spec/ruby/core/complex/eql_spec.rb
@@ -2,23 +2,23 @@ require_relative '../../spec_helper'
describe "Complex#eql?" do
it "returns false if other is not Complex" do
- Complex(1).eql?(1).should be_false
+ Complex(1).eql?(1).should == false
end
it "returns true when the respective parts are of the same classes and self == other" do
- Complex(1, 2).eql?(Complex(1, 2)).should be_true
+ Complex(1, 2).eql?(Complex(1, 2)).should == true
end
it "returns false when the real parts are of different classes" do
- Complex(1).eql?(Complex(1.0)).should be_false
+ Complex(1).eql?(Complex(1.0)).should == false
end
it "returns false when the imaginary parts are of different classes" do
- Complex(1, 2).eql?(Complex(1, 2.0)).should be_false
+ Complex(1, 2).eql?(Complex(1, 2.0)).should == false
end
it "returns false when self == other is false" do
- Complex(1, 2).eql?(Complex(2, 3)).should be_false
+ Complex(1, 2).eql?(Complex(2, 3)).should == false
end
it "does NOT send #eql? to real or imaginary parts" do
@@ -26,6 +26,6 @@ describe "Complex#eql?" do
imag = mock_numeric('imag')
real.should_not_receive(:eql?)
imag.should_not_receive(:eql?)
- Complex(real, imag).eql?(Complex(real, imag)).should be_true
+ Complex(real, imag).eql?(Complex(real, imag)).should == true
end
end
diff --git a/spec/ruby/core/complex/equal_value_spec.rb b/spec/ruby/core/complex/equal_value_spec.rb
index 97c486d820..b3562ff3fb 100644
--- a/spec/ruby/core/complex/equal_value_spec.rb
+++ b/spec/ruby/core/complex/equal_value_spec.rb
@@ -60,7 +60,7 @@ describe "Complex#==" do
obj = mock("Object")
obj.should_receive(:==).with(value).and_return(:expected)
- (value == obj).should_not be_false
+ (value == obj).should_not == false
end
end
@@ -73,11 +73,11 @@ describe "Complex#==" do
it "returns real == other when the imaginary part is zero" do
real = mock_numeric('real')
real.should_receive(:==).with(@other).and_return(true)
- (Complex(real, 0) == @other).should be_true
+ (Complex(real, 0) == @other).should == true
end
it "returns false when the imaginary part is not zero" do
- (Complex(3, 1) == @other).should be_false
+ (Complex(3, 1) == @other).should == false
end
end
@@ -87,7 +87,7 @@ describe "Complex#==" do
other = mock_numeric('other')
other.should_receive(:real?).any_number_of_times.and_return(false)
other.should_receive(:==).with(complex).and_return(true)
- (complex == other).should be_true
+ (complex == other).should == true
end
end
end
diff --git a/spec/ruby/core/complex/exponent_spec.rb b/spec/ruby/core/complex/exponent_spec.rb
index 86f827aece..d0db0a40c2 100644
--- a/spec/ruby/core/complex/exponent_spec.rb
+++ b/spec/ruby/core/complex/exponent_spec.rb
@@ -3,13 +3,13 @@ require_relative '../../spec_helper'
describe "Complex#**" do
describe "with Integer 0" do
it "returns Complex(1)" do
- (Complex(3, 4) ** 0).should eql(Complex(1))
+ (Complex(3, 4) ** 0).should.eql?(Complex(1))
end
end
describe "with Float 0.0" do
it "returns Complex(1.0, 0.0)" do
- (Complex(3, 4) ** 0.0).should eql(Complex(1.0, 0.0))
+ (Complex(3, 4) ** 0.0).should.eql?(Complex(1.0, 0.0))
end
end
diff --git a/spec/ruby/core/complex/fdiv_spec.rb b/spec/ruby/core/complex/fdiv_spec.rb
index 68f7d1b309..fdcbc6a95d 100644
--- a/spec/ruby/core/complex/fdiv_spec.rb
+++ b/spec/ruby/core/complex/fdiv_spec.rb
@@ -2,44 +2,44 @@ require_relative '../../spec_helper'
describe "Complex#fdiv" do
it "accepts a numeric argument" do
- -> { Complex(20).fdiv(2) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(2.0) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(bignum_value) }.should_not raise_error(TypeError)
+ -> { Complex(20).fdiv(2) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(2.0) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(bignum_value) }.should_not.raise(TypeError)
end
it "accepts a negative numeric argument" do
- -> { Complex(20).fdiv(-2) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(-2.0) }.should_not raise_error(TypeError)
- -> { Complex(20).fdiv(-bignum_value) }.should_not raise_error(TypeError)
+ -> { Complex(20).fdiv(-2) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(-2.0) }.should_not.raise(TypeError)
+ -> { Complex(20).fdiv(-bignum_value) }.should_not.raise(TypeError)
end
it "raises a TypeError if passed a non-numeric argument" do
- -> { Complex(20).fdiv([]) }.should raise_error(TypeError)
- -> { Complex(20).fdiv(:sym) }.should raise_error(TypeError)
- -> { Complex(20).fdiv('s') }.should raise_error(TypeError)
+ -> { Complex(20).fdiv([]) }.should.raise(TypeError)
+ -> { Complex(20).fdiv(:sym) }.should.raise(TypeError)
+ -> { Complex(20).fdiv('s') }.should.raise(TypeError)
end
it "sets the real part to NaN if self's real part is NaN" do
- Complex(nan_value).fdiv(2).real.nan?.should be_true
+ Complex(nan_value).fdiv(2).real.nan?.should == true
end
it "sets the imaginary part to NaN if self's imaginary part is NaN" do
- Complex(2, nan_value).fdiv(2).imag.nan?.should be_true
+ Complex(2, nan_value).fdiv(2).imag.nan?.should == true
end
it "sets the real and imaginary part to NaN if self's real and imaginary parts are NaN" do
- Complex(nan_value, nan_value).fdiv(2).imag.nan?.should be_true
- Complex(nan_value, nan_value).fdiv(2).real.nan?.should be_true
+ Complex(nan_value, nan_value).fdiv(2).imag.nan?.should == true
+ Complex(nan_value, nan_value).fdiv(2).real.nan?.should == true
end
it "sets the real and imaginary part to NaN if self's real part and the argument are both NaN" do
- Complex(nan_value, 2).fdiv(nan_value).imag.nan?.should be_true
- Complex(nan_value, 2).fdiv(nan_value).real.nan?.should be_true
+ Complex(nan_value, 2).fdiv(nan_value).imag.nan?.should == true
+ Complex(nan_value, 2).fdiv(nan_value).real.nan?.should == true
end
it "sets the real and imaginary part to NaN if self's real part, self's imaginary part, and the argument are NaN" do
- Complex(nan_value, nan_value).fdiv(nan_value).imag.nan?.should be_true
- Complex(nan_value, nan_value).fdiv(nan_value).real.nan?.should be_true
+ Complex(nan_value, nan_value).fdiv(nan_value).imag.nan?.should == true
+ Complex(nan_value, nan_value).fdiv(nan_value).real.nan?.should == true
end
it "sets the real part to Infinity if self's real part is Infinity" do
@@ -58,8 +58,8 @@ describe "Complex#fdiv" do
end
it "sets the real part to NaN and the imaginary part to NaN if self's imaginary part, self's real part, and the argument are Infinity" do
- Complex(infinity_value, infinity_value).fdiv(infinity_value).real.nan?.should be_true
- Complex(infinity_value, infinity_value).fdiv(infinity_value).imag.nan?.should be_true
+ Complex(infinity_value, infinity_value).fdiv(infinity_value).real.nan?.should == true
+ Complex(infinity_value, infinity_value).fdiv(infinity_value).imag.nan?.should == true
end
end
@@ -71,7 +71,7 @@ describe "Complex#fdiv with no imaginary part" do
it "returns a Complex number" do
@numbers.each do |real|
@numbers.each do |other|
- Complex(real).fdiv(other).should be_an_instance_of(Complex)
+ Complex(real).fdiv(other).should.instance_of?(Complex)
end
end
end
@@ -103,7 +103,7 @@ describe "Complex#fdiv with an imaginary part" do
@numbers.each_with_index do |other,idx|
Complex(
real,@numbers[idx == 0 ? -1 : idx-1]
- ).fdiv(other).should be_an_instance_of(Complex)
+ ).fdiv(other).should.instance_of?(Complex)
end
end
end
diff --git a/spec/ruby/core/complex/imag_spec.rb b/spec/ruby/core/complex/imag_spec.rb
index 2bafd1ab54..225f168e78 100644
--- a/spec/ruby/core/complex/imag_spec.rb
+++ b/spec/ruby/core/complex/imag_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/image'
describe "Complex#imag" do
- it_behaves_like :complex_image, :imag
+ it "is an alias of Complex#imaginary" do
+ Complex.instance_method(:imag).should == Complex.instance_method(:imaginary)
+ end
end
diff --git a/spec/ruby/core/complex/imaginary_spec.rb b/spec/ruby/core/complex/imaginary_spec.rb
index a8a1bfea90..ac9284e934 100644
--- a/spec/ruby/core/complex/imaginary_spec.rb
+++ b/spec/ruby/core/complex/imaginary_spec.rb
@@ -1,6 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/image'
describe "Complex#imaginary" do
- it_behaves_like :complex_image, :imaginary
+ it "returns the imaginary part of self" do
+ Complex(1, 0).imaginary.should == 0
+ Complex(2, 1).imaginary.should == 1
+ Complex(6.7, 8.9).imaginary.should == 8.9
+ Complex(1, bignum_value).imaginary.should == bignum_value
+ end
end
diff --git a/spec/ruby/core/complex/integer_spec.rb b/spec/ruby/core/complex/integer_spec.rb
index 0957accb70..559bfbccfd 100644
--- a/spec/ruby/core/complex/integer_spec.rb
+++ b/spec/ruby/core/complex/integer_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Complex#integer?" do
it "returns false for a Complex with no imaginary part" do
- Complex(20).integer?.should be_false
+ Complex(20).integer?.should == false
end
it "returns false for a Complex with an imaginary part" do
- Complex(20,3).integer?.should be_false
+ Complex(20,3).integer?.should == false
end
end
diff --git a/spec/ruby/core/complex/magnitude_spec.rb b/spec/ruby/core/complex/magnitude_spec.rb
index 86f3b29868..6341b4eec8 100644
--- a/spec/ruby/core/complex/magnitude_spec.rb
+++ b/spec/ruby/core/complex/magnitude_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/abs'
describe "Complex#magnitude" do
- it_behaves_like :complex_abs, :magnitude
+ it "is an alias of Complex#abs" do
+ Complex.instance_method(:magnitude).should == Complex.instance_method(:abs)
+ end
end
diff --git a/spec/ruby/core/complex/marshal_dump_spec.rb b/spec/ruby/core/complex/marshal_dump_spec.rb
index 116899b0ad..201d55e9e5 100644
--- a/spec/ruby/core/complex/marshal_dump_spec.rb
+++ b/spec/ruby/core/complex/marshal_dump_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Complex#marshal_dump" do
it "is a private method" do
- Complex.should have_private_instance_method(:marshal_dump, false)
+ Complex.private_instance_methods(false).should.include?(:marshal_dump)
end
it "dumps real and imaginary parts" do
diff --git a/spec/ruby/core/complex/negative_spec.rb b/spec/ruby/core/complex/negative_spec.rb
index 62ab89c04a..566975b8e1 100644
--- a/spec/ruby/core/complex/negative_spec.rb
+++ b/spec/ruby/core/complex/negative_spec.rb
@@ -4,10 +4,10 @@ describe "Complex#negative?" do
it "is undefined" do
c = Complex(1)
- c.methods.should_not include(:negative?)
+ c.methods.should_not.include?(:negative?)
-> {
c.negative?
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/complex/phase_spec.rb b/spec/ruby/core/complex/phase_spec.rb
index 89574bf533..2ab90989e1 100644
--- a/spec/ruby/core/complex/phase_spec.rb
+++ b/spec/ruby/core/complex/phase_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/arg'
describe "Complex#phase" do
- it_behaves_like :complex_arg, :phase
+ it "is an alias of Complex#arg" do
+ Complex.instance_method(:phase).should == Complex.instance_method(:arg)
+ end
end
diff --git a/spec/ruby/core/complex/polar_spec.rb b/spec/ruby/core/complex/polar_spec.rb
index 3bb3751bc6..824211fcd0 100644
--- a/spec/ruby/core/complex/polar_spec.rb
+++ b/spec/ruby/core/complex/polar_spec.rb
@@ -7,24 +7,22 @@ describe "Complex.polar" do
end
it "raises a TypeError when given non real arguments" do
- ->{ Complex.polar(nil) }.should raise_error(TypeError)
- ->{ Complex.polar(nil, nil) }.should raise_error(TypeError)
+ ->{ Complex.polar(nil) }.should.raise(TypeError)
+ ->{ Complex.polar(nil, nil) }.should.raise(TypeError)
end
- ruby_bug "#19004", ""..."3.2" do
- it "computes the real values of the real & imaginary parts from the polar form" do
- a = Complex.polar(1.0+0.0i, Math::PI/2+0.0i)
- a.real.should be_close(0.0, TOLERANCE)
- a.imag.should be_close(1.0, TOLERANCE)
- a.real.real?.should be_true
- a.imag.real?.should be_true
+ it "computes the real values of the real & imaginary parts from the polar form" do
+ a = Complex.polar(1.0+0.0i, Math::PI/2+0.0i)
+ a.real.should be_close(0.0, TOLERANCE)
+ a.imag.should be_close(1.0, TOLERANCE)
+ a.real.real?.should == true
+ a.imag.real?.should == true
- b = Complex.polar(1+0.0i)
- b.real.should be_close(1.0, TOLERANCE)
- b.imag.should be_close(0.0, TOLERANCE)
- b.real.real?.should be_true
- b.imag.real?.should be_true
- end
+ b = Complex.polar(1+0.0i)
+ b.real.should be_close(1.0, TOLERANCE)
+ b.imag.should be_close(0.0, TOLERANCE)
+ b.real.real?.should == true
+ b.imag.real?.should == true
end
end
diff --git a/spec/ruby/core/complex/positive_spec.rb b/spec/ruby/core/complex/positive_spec.rb
index f1bad8608c..d2fb256538 100644
--- a/spec/ruby/core/complex/positive_spec.rb
+++ b/spec/ruby/core/complex/positive_spec.rb
@@ -4,10 +4,10 @@ describe "Complex#positive?" do
it "is undefined" do
c = Complex(1)
- c.methods.should_not include(:positive?)
+ c.methods.should_not.include?(:positive?)
-> {
c.positive?
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/complex/quo_spec.rb b/spec/ruby/core/complex/quo_spec.rb
index ee6fd65c79..be0a44d532 100644
--- a/spec/ruby/core/complex/quo_spec.rb
+++ b/spec/ruby/core/complex/quo_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/divide'
describe "Complex#quo" do
- it_behaves_like :complex_divide, :quo
+ it "is an alias of Complex#/" do
+ Complex.instance_method(:quo).should == Complex.instance_method(:/)
+ end
end
diff --git a/spec/ruby/core/complex/rationalize_spec.rb b/spec/ruby/core/complex/rationalize_spec.rb
index 043b8ddf2a..d49bb52def 100644
--- a/spec/ruby/core/complex/rationalize_spec.rb
+++ b/spec/ruby/core/complex/rationalize_spec.rb
@@ -2,11 +2,11 @@ require_relative '../../spec_helper'
describe "Complex#rationalize" do
it "raises RangeError if self has non-zero imaginary part" do
- -> { Complex(1,5).rationalize }.should raise_error(RangeError)
+ -> { Complex(1,5).rationalize }.should.raise(RangeError)
end
it "raises RangeError if self has 0.0 imaginary part" do
- -> { Complex(1,0.0).rationalize }.should raise_error(RangeError)
+ -> { Complex(1,0.0).rationalize }.should.raise(RangeError)
end
it "returns a Rational if self has zero imaginary part" do
@@ -25,7 +25,7 @@ describe "Complex#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { Complex(1,0).rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { Complex(1,0).rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { Complex(1,0).rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { Complex(1,0).rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/complex/real_spec.rb b/spec/ruby/core/complex/real_spec.rb
index 2ea791c005..41734b23f0 100644
--- a/spec/ruby/core/complex/real_spec.rb
+++ b/spec/ruby/core/complex/real_spec.rb
@@ -11,18 +11,18 @@ end
describe "Complex#real?" do
it "returns false if there is an imaginary part" do
- Complex(2,3).real?.should be_false
+ Complex(2,3).real?.should == false
end
it "returns false if there is not an imaginary part" do
- Complex(2).real?.should be_false
+ Complex(2).real?.should == false
end
it "returns false if the real part is Infinity" do
- Complex(infinity_value).real?.should be_false
+ Complex(infinity_value).real?.should == false
end
it "returns false if the real part is NaN" do
- Complex(nan_value).real?.should be_false
+ Complex(nan_value).real?.should == false
end
end
diff --git a/spec/ruby/core/complex/rect_spec.rb b/spec/ruby/core/complex/rect_spec.rb
index 9e95f3efc2..72f2bf9930 100644
--- a/spec/ruby/core/complex/rect_spec.rb
+++ b/spec/ruby/core/complex/rect_spec.rb
@@ -1,10 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'shared/rect'
describe "Complex#rect" do
- it_behaves_like :complex_rect, :rect
+ it "is an alias of Complex#rectangular" do
+ Complex.instance_method(:rect).should == Complex.instance_method(:rectangular)
+ end
end
describe "Complex.rect" do
- it_behaves_like :complex_rect_class, :rect
+ it "is an alias of Complex#rectangular" do
+ Complex.method(:rect).should == Complex.method(:rectangular)
+ end
end
diff --git a/spec/ruby/core/complex/rectangular_spec.rb b/spec/ruby/core/complex/rectangular_spec.rb
index d4b8ad9782..7789bf925e 100644
--- a/spec/ruby/core/complex/rectangular_spec.rb
+++ b/spec/ruby/core/complex/rectangular_spec.rb
@@ -1,10 +1,114 @@
require_relative '../../spec_helper'
-require_relative 'shared/rect'
describe "Complex#rectangular" do
- it_behaves_like :complex_rect, :rectangular
+ before :each do
+ @numbers = [
+ Complex(1),
+ Complex(0, 20),
+ Complex(0, 0),
+ Complex(0.0),
+ Complex(9999999**99),
+ Complex(-20),
+ Complex.polar(76, 10)
+ ]
+ end
+
+ it "returns an Array" do
+ @numbers.each do |number|
+ number.rectangular.should.instance_of?(Array)
+ end
+ end
+
+ it "returns a two-element Array" do
+ @numbers.each do |number|
+ number.rectangular.size.should == 2
+ end
+ end
+
+ it "returns the real part of self as the first element" do
+ @numbers.each do |number|
+ number.rectangular.first.should == number.real
+ end
+ end
+
+ it "returns the imaginary part of self as the last element" do
+ @numbers.each do |number|
+ number.rectangular.last.should == number.imaginary
+ end
+ end
+
+ it "raises an ArgumentError if given any arguments" do
+ @numbers.each do |number|
+ -> { number.rectangular(number) }.should.raise(ArgumentError)
+ end
+ end
end
describe "Complex.rectangular" do
- it_behaves_like :complex_rect_class, :rectangular
+ describe "passed a Numeric n which responds to #real? with true" do
+ it "returns a Complex with real part n and imaginary part 0" do
+ n = mock_numeric('n')
+ n.should_receive(:real?).any_number_of_times.and_return(true)
+ result = Complex.rectangular(n)
+ result.real.should == n
+ result.imag.should == 0
+ end
+ end
+
+ describe "passed a Numeric which responds to #real? with false" do
+ it "raises TypeError" do
+ n = mock_numeric('n')
+ n.should_receive(:real?).any_number_of_times.and_return(false)
+ -> { Complex.rectangular(n) }.should.raise(TypeError)
+ end
+ end
+
+ describe "passed Numerics n1 and n2 and at least one responds to #real? with false" do
+ [[false, false], [false, true], [true, false]].each do |r1, r2|
+ it "raises TypeError" do
+ n1 = mock_numeric('n1')
+ n2 = mock_numeric('n2')
+ n1.should_receive(:real?).any_number_of_times.and_return(r1)
+ n2.should_receive(:real?).any_number_of_times.and_return(r2)
+ -> { Complex.rectangular(n1, n2) }.should.raise(TypeError)
+ end
+ end
+ end
+
+ describe "passed Numerics n1 and n2 and both respond to #real? with true" do
+ it "returns a Complex with real part n1 and imaginary part n2" do
+ n1 = mock_numeric('n1')
+ n2 = mock_numeric('n2')
+ n1.should_receive(:real?).any_number_of_times.and_return(true)
+ n2.should_receive(:real?).any_number_of_times.and_return(true)
+ result = Complex.rectangular(n1, n2)
+ result.real.should == n1
+ result.imag.should == n2
+ end
+ end
+
+ describe "when passed a Complex" do
+ it "raises a TypeError when the imaginary part is not zero" do
+ -> {
+ Complex.rectangular(1.0+1i, 2)
+ }.should.raise(TypeError)
+
+ -> {
+ Complex.rectangular(1.0, 2i)
+ }.should.raise(TypeError)
+ end
+
+ it "ignores the imaginary part if it is zero" do
+ result = Complex.rectangular(1.0+0i, 2+0.0i)
+ result.real.should == 1.0
+ result.imag.should == 2
+ end
+ end
+
+ describe "passed a non-Numeric" do
+ it "raises TypeError" do
+ -> { Complex.rectangular(:sym) }.should.raise(TypeError)
+ -> { Complex.rectangular(0, :sym) }.should.raise(TypeError)
+ end
+ end
end
diff --git a/spec/ruby/core/complex/shared/abs.rb b/spec/ruby/core/complex/shared/abs.rb
deleted file mode 100644
index 2299479341..0000000000
--- a/spec/ruby/core/complex/shared/abs.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-describe :complex_abs, shared: true do
- it "returns the modulus: |a + bi| = sqrt((a ^ 2) + (b ^ 2))" do
- Complex(0, 0).send(@method).should == 0
- Complex(3, 4).send(@method).should == 5 # well-known integer case
- Complex(-3, 4).send(@method).should == 5
- Complex(1, -1).send(@method).should be_close(Math.sqrt(2), TOLERANCE)
- Complex(6.5, 0).send(@method).should be_close(6.5, TOLERANCE)
- Complex(0, -7.2).send(@method).should be_close(7.2, TOLERANCE)
- end
-end
diff --git a/spec/ruby/core/complex/shared/arg.rb b/spec/ruby/core/complex/shared/arg.rb
deleted file mode 100644
index c81f197433..0000000000
--- a/spec/ruby/core/complex/shared/arg.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :complex_arg, shared: true do
- it "returns the argument -- i.e., the angle from (1, 0) in the complex plane" do
- two_pi = 2 * Math::PI
- (Complex(1, 0).send(@method) % two_pi).should be_close(0, TOLERANCE)
- (Complex(0, 2).send(@method) % two_pi).should be_close(Math::PI * 0.5, TOLERANCE)
- (Complex(-100, 0).send(@method) % two_pi).should be_close(Math::PI, TOLERANCE)
- (Complex(0, -75.3).send(@method) % two_pi).should be_close(Math::PI * 1.5, TOLERANCE)
- end
-end
diff --git a/spec/ruby/core/complex/shared/conjugate.rb b/spec/ruby/core/complex/shared/conjugate.rb
deleted file mode 100644
index d1ae47bcb6..0000000000
--- a/spec/ruby/core/complex/shared/conjugate.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :complex_conjugate, shared: true do
- it "returns the complex conjugate: conj a + bi = a - bi" do
- Complex(3, 5).send(@method).should == Complex(3, -5)
- Complex(3, -5).send(@method).should == Complex(3, 5)
- Complex(-3.0, 5.2).send(@method).should be_close(Complex(-3.0, -5.2), TOLERANCE)
- Complex(3.0, -5.2).send(@method).should be_close(Complex(3.0, 5.2), TOLERANCE)
- end
-end
diff --git a/spec/ruby/core/complex/shared/divide.rb b/spec/ruby/core/complex/shared/divide.rb
deleted file mode 100644
index a60802c74c..0000000000
--- a/spec/ruby/core/complex/shared/divide.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-describe :complex_divide, shared: true do
- describe "with Complex" do
- it "divides according to the usual rule for complex numbers" do
- a = Complex((1 * 10) - (2 * 20), (1 * 20) + (2 * 10))
- b = Complex(1, 2)
- a.send(@method, b).should == Complex(10, 20)
-
- c = Complex((1.5 * 100.2) - (2.1 * -30.3), (1.5 * -30.3) + (2.1 * 100.2))
- d = Complex(1.5, 2.1)
- # remember the floating-point arithmetic
- c.send(@method, d).should be_close(Complex(100.2, -30.3), TOLERANCE)
- end
- end
-
- describe "with Fixnum" do
- it "divides both parts of the Complex number" do
- Complex(20, 40).send(@method, 2).should == Complex(10, 20)
- Complex(30, 30).send(@method, 10).should == Complex(3, 3)
- end
-
- it "raises a ZeroDivisionError when given zero" do
- -> { Complex(20, 40).send(@method, 0) }.should raise_error(ZeroDivisionError)
- end
-
- it "produces Rational parts" do
- Complex(5, 9).send(@method, 2).should eql(Complex(Rational(5,2), Rational(9,2)))
- end
- end
-
- describe "with Bignum" do
- it "divides both parts of the Complex number" do
- Complex(20, 40).send(@method, 2).should == Complex(10, 20)
- Complex(15, 16).send(@method, 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
- end
- end
-
- describe "with Float" do
- it "divides both parts of the Complex number" do
- Complex(3, 9).send(@method, 1.5).should == Complex(2, 6)
- Complex(15, 16).send(@method, 2.0).should be_close(Complex(7.5, 8), TOLERANCE)
- end
-
- it "returns Complex(Infinity, Infinity) when given zero" do
- Complex(20, 40).send(@method, 0.0).real.infinite?.should == 1
- Complex(20, 40).send(@method, 0.0).imag.infinite?.should == 1
- Complex(-20, 40).send(@method, 0.0).real.infinite?.should == -1
- Complex(-20, 40).send(@method, 0.0).imag.infinite?.should == 1
- end
- end
-
- describe "with Object" do
- it "tries to coerce self into other" do
- value = Complex(3, 9)
-
- obj = mock("Object")
- obj.should_receive(:coerce).with(value).and_return([4, 2])
- value.send(@method, obj).should == 2
- end
- end
-
- describe "with a Numeric which responds to #real? with true" do
- it "returns Complex(real.quo(other), imag.quo(other))" do
- other = mock_numeric('other')
- real = mock_numeric('real')
- imag = mock_numeric('imag')
- other.should_receive(:real?).and_return(true)
- real.should_receive(:quo).with(other).and_return(1)
- imag.should_receive(:quo).with(other).and_return(2)
- Complex(real, imag).send(@method, other).should == Complex(1, 2)
- end
- end
-
- describe "with a Numeric which responds to #real? with false" do
- it "coerces the passed argument to Complex and divides the resulting elements" do
- complex = Complex(3, 0)
- other = mock_numeric('other')
- other.should_receive(:real?).any_number_of_times.and_return(false)
- other.should_receive(:coerce).with(complex).and_return([5, 2])
- complex.send(@method, other).should eql(Rational(5, 2))
- end
- end
-end
diff --git a/spec/ruby/core/complex/shared/image.rb b/spec/ruby/core/complex/shared/image.rb
deleted file mode 100644
index f839dbcaf9..0000000000
--- a/spec/ruby/core/complex/shared/image.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :complex_image, shared: true do
- it "returns the imaginary part of self" do
- Complex(1, 0).send(@method).should == 0
- Complex(2, 1).send(@method).should == 1
- Complex(6.7, 8.9).send(@method).should == 8.9
- Complex(1, bignum_value).send(@method).should == bignum_value
- end
-end
diff --git a/spec/ruby/core/complex/shared/rect.rb b/spec/ruby/core/complex/shared/rect.rb
deleted file mode 100644
index 4ac294e771..0000000000
--- a/spec/ruby/core/complex/shared/rect.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-describe :complex_rect, shared: true do
- before :each do
- @numbers = [
- Complex(1),
- Complex(0, 20),
- Complex(0, 0),
- Complex(0.0),
- Complex(9999999**99),
- Complex(-20),
- Complex.polar(76, 10)
- ]
- end
-
- it "returns an Array" do
- @numbers.each do |number|
- number.send(@method).should be_an_instance_of(Array)
- end
- end
-
- it "returns a two-element Array" do
- @numbers.each do |number|
- number.send(@method).size.should == 2
- end
- end
-
- it "returns the real part of self as the first element" do
- @numbers.each do |number|
- number.send(@method).first.should == number.real
- end
- end
-
- it "returns the imaginary part of self as the last element" do
- @numbers.each do |number|
- number.send(@method).last.should == number.imaginary
- end
- end
-
- it "raises an ArgumentError if given any arguments" do
- @numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
- end
- end
-end
-
-describe :complex_rect_class, shared: true do
- describe "passed a Numeric n which responds to #real? with true" do
- it "returns a Complex with real part n and imaginary part 0" do
- n = mock_numeric('n')
- n.should_receive(:real?).any_number_of_times.and_return(true)
- result = Complex.send(@method, n)
- result.real.should == n
- result.imag.should == 0
- end
- end
-
- describe "passed a Numeric which responds to #real? with false" do
- it "raises TypeError" do
- n = mock_numeric('n')
- n.should_receive(:real?).any_number_of_times.and_return(false)
- -> { Complex.send(@method, n) }.should raise_error(TypeError)
- end
- end
-
- describe "passed Numerics n1 and n2 and at least one responds to #real? with false" do
- [[false, false], [false, true], [true, false]].each do |r1, r2|
- it "raises TypeError" do
- n1 = mock_numeric('n1')
- n2 = mock_numeric('n2')
- n1.should_receive(:real?).any_number_of_times.and_return(r1)
- n2.should_receive(:real?).any_number_of_times.and_return(r2)
- -> { Complex.send(@method, n1, n2) }.should raise_error(TypeError)
- end
- end
- end
-
- describe "passed Numerics n1 and n2 and both respond to #real? with true" do
- it "returns a Complex with real part n1 and imaginary part n2" do
- n1 = mock_numeric('n1')
- n2 = mock_numeric('n2')
- n1.should_receive(:real?).any_number_of_times.and_return(true)
- n2.should_receive(:real?).any_number_of_times.and_return(true)
- result = Complex.send(@method, n1, n2)
- result.real.should == n1
- result.imag.should == n2
- end
- end
-
- describe "passed a non-Numeric" do
- it "raises TypeError" do
- -> { Complex.send(@method, :sym) }.should raise_error(TypeError)
- -> { Complex.send(@method, 0, :sym) }.should raise_error(TypeError)
- end
- end
-end
diff --git a/spec/ruby/core/complex/to_c_spec.rb b/spec/ruby/core/complex/to_c_spec.rb
index 5ce01d9d4e..cd7195556c 100644
--- a/spec/ruby/core/complex/to_c_spec.rb
+++ b/spec/ruby/core/complex/to_c_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Complex#to_c" do
it "returns self" do
value = Complex(1, 5)
- value.to_c.should equal(value)
+ value.to_c.should.equal?(value)
end
it 'returns the same value' do
diff --git a/spec/ruby/core/complex/to_f_spec.rb b/spec/ruby/core/complex/to_f_spec.rb
index b53471c1fc..9f3265cdb9 100644
--- a/spec/ruby/core/complex/to_f_spec.rb
+++ b/spec/ruby/core/complex/to_f_spec.rb
@@ -29,13 +29,13 @@ describe "Complex#to_f" do
describe "when the imaginary part is non-zero" do
it "raises RangeError" do
- -> { Complex(0, 1).to_f }.should raise_error(RangeError)
+ -> { Complex(0, 1).to_f }.should.raise(RangeError)
end
end
describe "when the imaginary part is Float 0.0" do
it "raises RangeError" do
- -> { Complex(0, 0.0).to_f }.should raise_error(RangeError)
+ -> { Complex(0, 0.0).to_f }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/complex/to_i_spec.rb b/spec/ruby/core/complex/to_i_spec.rb
index 1e78f5ec0e..9149ffbbaa 100644
--- a/spec/ruby/core/complex/to_i_spec.rb
+++ b/spec/ruby/core/complex/to_i_spec.rb
@@ -29,13 +29,13 @@ describe "Complex#to_i" do
describe "when the imaginary part is non-zero" do
it "raises RangeError" do
- -> { Complex(0, 1).to_i }.should raise_error(RangeError)
+ -> { Complex(0, 1).to_i }.should.raise(RangeError)
end
end
describe "when the imaginary part is Float 0.0" do
it "raises RangeError" do
- -> { Complex(0, 0.0).to_i }.should raise_error(RangeError)
+ -> { Complex(0, 0.0).to_i }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/complex/to_r_spec.rb b/spec/ruby/core/complex/to_r_spec.rb
index 788027a500..6587ae9e2e 100644
--- a/spec/ruby/core/complex/to_r_spec.rb
+++ b/spec/ruby/core/complex/to_r_spec.rb
@@ -29,14 +29,14 @@ describe "Complex#to_r" do
describe "when the imaginary part is non-zero" do
it "raises RangeError" do
- -> { Complex(0, 1).to_r }.should raise_error(RangeError)
+ -> { Complex(0, 1).to_r }.should.raise(RangeError)
end
end
describe "when the imaginary part is Float 0.0" do
ruby_version_is ''...'3.4' do
it "raises RangeError" do
- -> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
+ -> { Complex(0, 0.0).to_r }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb
index 55a7b89c72..16c7b4cc8d 100644
--- a/spec/ruby/core/conditionvariable/broadcast_spec.rb
+++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb
@@ -24,7 +24,7 @@ describe "ConditionVariable#broadcast" do
# wait until all threads are sleeping (ie waiting)
Thread.pass until threads.all?(&:stop?)
- r2.should be_empty
+ r2.should.empty?
m.synchronize do
cv.broadcast
end
diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
index 88b1cc38c1..594c178e88 100644
--- a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
+++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "ConditionVariable#marshal_dump" do
it "raises a TypeError" do
cv = ConditionVariable.new
- -> { cv.marshal_dump }.should raise_error(TypeError, /can't dump/)
+ -> { cv.marshal_dump }.should.raise(TypeError, /can't dump/)
end
end
diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb
index 43a9cc611b..3b266cf8c6 100644
--- a/spec/ruby/core/conditionvariable/signal_spec.rb
+++ b/spec/ruby/core/conditionvariable/signal_spec.rb
@@ -24,7 +24,7 @@ describe "ConditionVariable#signal" do
# wait until all threads are sleeping (ie waiting)
Thread.pass until threads.all?(&:stop?)
- r2.should be_empty
+ r2.should.empty?
100.times do |i|
m.synchronize do
cv.signal
diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb
index fe73e513c0..1af53a15a2 100644
--- a/spec/ruby/core/conditionvariable/wait_spec.rb
+++ b/spec/ruby/core/conditionvariable/wait_spec.rb
@@ -163,7 +163,7 @@ describe "ConditionVariable#wait" do
# On TruffleRuby, this causes a safepoint which has interesting
# interactions with the ConditionVariable.
bt = t.backtrace
- bt.should be_kind_of(Array)
+ bt.should.is_a?(Array)
bt.size.should >= 2
}
end
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb
index 2eb43d501e..ad0b1ddea7 100644
--- a/spec/ruby/core/data/constants_spec.rb
+++ b/spec/ruby/core/data/constants_spec.rb
@@ -1,21 +1,11 @@
require_relative '../../spec_helper'
-ruby_version_is ''...'3.2' do
- describe "Data" do
- it "does not exist anymore" do
- Object.should_not have_constant(:Data)
- end
+describe "Data" do
+ it "is a new constant" do
+ Data.superclass.should == Object
end
-end
-
-ruby_version_is '3.2' do
- describe "Data" do
- it "is a new constant" do
- Data.superclass.should == Object
- end
- it "is not deprecated" do
- -> { Data }.should_not complain
- end
+ it "is not deprecated" do
+ -> { Data }.should_not complain
end
end
diff --git a/spec/ruby/core/data/deconstruct_keys_spec.rb b/spec/ruby/core/data/deconstruct_keys_spec.rb
index 07af87771d..7e81f966ea 100644
--- a/spec/ruby/core/data/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/data/deconstruct_keys_spec.rb
@@ -1,107 +1,110 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#deconstruct" do
- it "returns a hash of attributes" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
- d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
- end
+describe "Data#deconstruct_keys" do
+ it "returns a hash of attributes" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- it "requires one argument" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
+ end
- -> {
- d.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
- end
+ it "requires one argument" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- it "returns only specified keys" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ -> {
+ d.deconstruct_keys
+ }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ end
- d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
- d.deconstruct_keys([:x] ).should == {x: 1}
- d.deconstruct_keys([] ).should == {}
- end
+ it "returns only specified keys" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- it "accepts string attribute names" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
- d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
- end
+ d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
+ d.deconstruct_keys([:x] ).should == {x: 1}
+ d.deconstruct_keys([] ).should == {}
+ end
- it "accepts argument position number as well but returns them as keys" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ it "accepts string attribute names" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2}
- d.deconstruct_keys([0] ).should == {0 => 1}
- d.deconstruct_keys([-1] ).should == {-1 => 2}
- end
+ d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
+ end
- it "ignores incorrect position numbers" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ it "returns an empty hash when there are more keys than attributes" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- d.deconstruct_keys([0, 3]).should == {0 => 1}
- end
+ d.deconstruct_keys([:x, :y, :x]).should == {}
+ end
- it "support mixing attribute names and argument position numbers" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ it "returns at first not existing attribute name" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
- end
+ d.deconstruct_keys([:a, :x]).should == {}
+ d.deconstruct_keys([:x, :a]).should == {x: 1}
+ end
- it "returns an empty hash when there are more keys than attributes" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
- d.deconstruct_keys([:x, :y, :x]).should == {}
- end
+ it "accepts nil argument and return all the attributes" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- it "returns at first not existing attribute name" do
+ d.deconstruct_keys(nil).should == {x: 1, y: 2}
+ end
+
+ ruby_version_is "4.0" do # https://bugs.ruby-lang.org/issues/21844
+ it "tries to convert a key with #to_str if index is not a String nor a Symbol, but responds to #to_str" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
- d.deconstruct_keys([:a, :x]).should == {}
- d.deconstruct_keys([:x, :a]).should == {x: 1}
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return("y")
+
+ d.deconstruct_keys([key]).should == { "y" => 2 }
end
- it "returns at first not existing argument position number" do
+ it "raise an error on argument position number" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
- d.deconstruct_keys([3, 0]).should == {}
- d.deconstruct_keys([0, 3]).should == {0 => 1}
+ -> {
+ d.deconstruct_keys([0, 1])
+ }.should.raise(TypeError, "0 is not a symbol nor a string")
end
- it "accepts nil argument and return all the attributes" do
+ it "raises a TypeError if the conversion with #to_str does not return a String" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
- d.deconstruct_keys(nil).should == {x: 1, y: 2}
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return(0)
+
+ -> {
+ d.deconstruct_keys([key])
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
end
- it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
+ it "raises TypeError if index is not a Symbol and not convertible to String" do
klass = Data.define(:x, :y)
d = klass.new(1, 2)
-> {
d.deconstruct_keys([0, []])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ }.should.raise(TypeError, "0 is not a symbol nor a string")
end
+ end
- it "raise TypeError if passed anything except nil or array" do
- klass = Data.define(:x, :y)
- d = klass.new(1, 2)
+ it "raise TypeError if passed anything except nil or array" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
- -> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
- end
+ -> { d.deconstruct_keys('x') }.should.raise(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, /expected Array or nil/)
end
end
diff --git a/spec/ruby/core/data/deconstruct_spec.rb b/spec/ruby/core/data/deconstruct_spec.rb
index f0995e8fed..4ca0b87039 100644
--- a/spec/ruby/core/data/deconstruct_spec.rb
+++ b/spec/ruby/core/data/deconstruct_spec.rb
@@ -1,10 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#deconstruct" do
- it "returns an array of attribute values" do
- DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"]
- end
+describe "Data#deconstruct" do
+ it "returns an array of attribute values" do
+ DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"]
end
end
diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb
index 2aa2c50d4c..c0b4671e39 100644
--- a/spec/ruby/core/data/define_spec.rb
+++ b/spec/ruby/core/data/define_spec.rb
@@ -1,36 +1,34 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data.define" do
- it "accepts no arguments" do
- empty_data = Data.define
- empty_data.members.should == []
- end
+describe "Data.define" do
+ it "accepts no arguments" do
+ empty_data = Data.define
+ empty_data.members.should == []
+ end
- it "accepts symbols" do
- movie = Data.define(:title, :year)
- movie.members.should == [:title, :year]
- end
+ it "accepts symbols" do
+ movie = Data.define(:title, :year)
+ movie.members.should == [:title, :year]
+ end
- it "accepts strings" do
- movie = Data.define("title", "year")
- movie.members.should == [:title, :year]
- end
+ it "accepts strings" do
+ movie = Data.define("title", "year")
+ movie.members.should == [:title, :year]
+ end
- it "accepts a mix of strings and symbols" do
- movie = Data.define("title", :year, "genre")
- movie.members.should == [:title, :year, :genre]
- end
+ it "accepts a mix of strings and symbols" do
+ movie = Data.define("title", :year, "genre")
+ movie.members.should == [:title, :year, :genre]
+ end
- it "accepts a block" do
- movie = Data.define(:title, :year) do
- def title_with_year
- "#{title} (#{year})"
- end
+ it "accepts a block" do
+ movie = Data.define(:title, :year) do
+ def title_with_year
+ "#{title} (#{year})"
end
- movie.members.should == [:title, :year]
- movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
end
+ movie.members.should == [:title, :year]
+ movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
end
end
diff --git a/spec/ruby/core/data/eql_spec.rb b/spec/ruby/core/data/eql_spec.rb
index 906e46316c..6958d5de4a 100644
--- a/spec/ruby/core/data/eql_spec.rb
+++ b/spec/ruby/core/data/eql_spec.rb
@@ -1,65 +1,63 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#eql?" do
- it "returns true if the other is the same object" do
- a = DataSpecs::Measure.new(42, "km")
- a.should.eql?(a)
- end
+describe "Data#eql?" do
+ it "returns true if the other is the same object" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.should.eql?(a)
+ end
- it "returns true if the other has all the same fields" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42, "km")
- a.should.eql?(b)
- end
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "km")
+ a.should.eql?(b)
+ end
- it "returns false if the other is a different object or has different fields" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42, "mi")
- a.should_not.eql?(b)
- end
+ it "returns false if the other is a different object or has different fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "mi")
+ a.should_not.eql?(b)
+ end
- it "returns false if other is of a different class" do
- a = DataSpecs::Measure.new(42, "km")
- klass = Data.define(*DataSpecs::Measure.members)
- b = klass.new(42, "km")
- a.should_not.eql?(b)
- end
+ it "returns false if other is of a different class" do
+ a = DataSpecs::Measure.new(42, "km")
+ klass = Data.define(*DataSpecs::Measure.members)
+ b = klass.new(42, "km")
+ a.should_not.eql?(b)
+ end
- it "returns false if any corresponding elements are not equal with #eql?" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42.0, "mi")
- a.should_not.eql?(b)
- end
+ it "returns false if any corresponding elements are not equal with #eql?" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42.0, "mi")
+ a.should_not.eql?(b)
+ end
- context "recursive structure" do
- it "returns true the other is the same object" do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: 42, unit: a)
+ context "recursive structure" do
+ it "returns true the other is the same object" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
- a.should.eql?(a)
- end
+ a.should.eql?(a)
+ end
- it "returns true if the other has all the same fields" do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: 42, unit: a)
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
- b = DataSpecs::Measure.allocate
- b.send(:initialize, amount: 42, unit: b)
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: 42, unit: b)
- a.should.eql?(b)
- end
+ a.should.eql?(b)
+ end
- it "returns false if any corresponding elements are not equal with #eql?" do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: a, unit: "km")
+ it "returns false if any corresponding elements are not equal with #eql?" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: a, unit: "km")
- b = DataSpecs::Measure.allocate
- b.send(:initialize, amount: b, unit: "mi")
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: b, unit: "mi")
- a.should_not.eql?(b)
- end
+ a.should_not.eql?(b)
end
end
end
diff --git a/spec/ruby/core/data/equal_value_spec.rb b/spec/ruby/core/data/equal_value_spec.rb
index f90a7d7a62..d9a0dcff3e 100644
--- a/spec/ruby/core/data/equal_value_spec.rb
+++ b/spec/ruby/core/data/equal_value_spec.rb
@@ -1,65 +1,63 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#==" do
- it "returns true if the other is the same object" do
- a = DataSpecs::Measure.new(42, "km")
- a.should == a
- end
+describe "Data#==" do
+ it "returns true if the other is the same object" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.should == a
+ end
- it "returns true if the other has all the same fields" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42, "km")
- a.should == b
- end
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "km")
+ a.should == b
+ end
- it "returns false if the other is a different object or has different fields" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42, "mi")
- a.should_not == b
- end
+ it "returns false if the other is a different object or has different fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "mi")
+ a.should_not == b
+ end
- it "returns false if other is of a different class" do
- a = DataSpecs::Measure.new(42, "km")
- klass = Data.define(*DataSpecs::Measure.members)
- b = klass.new(42, "km")
- a.should_not == b
- end
+ it "returns false if other is of a different class" do
+ a = DataSpecs::Measure.new(42, "km")
+ klass = Data.define(*DataSpecs::Measure.members)
+ b = klass.new(42, "km")
+ a.should_not == b
+ end
- it "returns false if any corresponding elements are not equal with #==" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42.0, "mi")
- a.should_not == b
- end
+ it "returns false if any corresponding elements are not equal with #==" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42.0, "mi")
+ a.should_not == b
+ end
- context "recursive structure" do
- it "returns true the other is the same object" do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: 42, unit: a)
+ context "recursive structure" do
+ it "returns true the other is the same object" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
- a.should == a
- end
+ a.should == a
+ end
- it "returns true if the other has all the same fields" do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: 42, unit: a)
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
- b = DataSpecs::Measure.allocate
- b.send(:initialize, amount: 42, unit: b)
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: 42, unit: b)
- a.should == b
- end
+ a.should == b
+ end
- it "returns false if any corresponding elements are not equal with #==" do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: a, unit: "km")
+ it "returns false if any corresponding elements are not equal with #==" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: a, unit: "km")
- b = DataSpecs::Measure.allocate
- b.send(:initialize, amount: b, unit: "mi")
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: b, unit: "mi")
- a.should_not == b
- end
+ a.should_not == b
end
end
end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
index f0a526517d..147293ee45 100644
--- a/spec/ruby/core/data/fixtures/classes.rb
+++ b/spec/ruby/core/data/fixtures/classes.rb
@@ -1,6 +1,7 @@
module DataSpecs
- guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
+ if Data.respond_to?(:define)
Measure = Data.define(:amount, :unit)
+ Single = Data.define(:value)
class MeasureWithOverriddenName < Measure
def self.name
@@ -8,6 +9,33 @@ module DataSpecs
end
end
+ class SingleWithOverriddenName < Single
+ def self.name
+ "A"
+ end
+ end
+
class DataSubclass < Data; end
+
+ MeasureSubclass = Class.new(Measure) do
+ def initialize(amount:, unit:)
+ super
+ end
+ end
+
+ Empty = Data.define()
+
+ DataWithOverriddenInitialize = Data.define(:amount, :unit) do
+ def initialize(*rest, **kw)
+ super
+ ScratchPad.record [:initialize, rest, kw]
+ end
+ end
+
+ Area = Data.define(:width, :height, :area) do
+ def initialize(width:, height:)
+ super(width: width, height: height, area: width * height)
+ end
+ end
end
end
diff --git a/spec/ruby/core/data/hash_spec.rb b/spec/ruby/core/data/hash_spec.rb
index 324a2abca4..bab146c92e 100644
--- a/spec/ruby/core/data/hash_spec.rb
+++ b/spec/ruby/core/data/hash_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#hash" do
- it "returns the same integer for objects with the same content" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42, "km")
- a.hash.should == b.hash
- a.hash.should be_an_instance_of(Integer)
- end
+describe "Data#hash" do
+ it "returns the same integer for objects with the same content" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "km")
+ a.hash.should == b.hash
+ a.hash.should.instance_of?(Integer)
+ end
- it "returns different hashes for objects with different values" do
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(42, "ml")
- a.hash.should_not == b.hash
+ it "returns different hashes for objects with different values" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "ml")
+ a.hash.should_not == b.hash
- a = DataSpecs::Measure.new(42, "km")
- b = DataSpecs::Measure.new(13, "km")
- a.hash.should_not == b.hash
- end
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(13, "km")
+ a.hash.should_not == b.hash
+ end
- it "returns different hashes for different classes" do
- Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash
- end
+ it "returns different hashes for different classes" do
+ Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash
end
end
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
index 2c36bd3ac4..0320ca880c 100644
--- a/spec/ruby/core/data/initialize_spec.rb
+++ b/spec/ruby/core/data/initialize_spec.rb
@@ -1,65 +1,204 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#initialize" do
- it "accepts positional arguments" do
- data = DataSpecs::Measure.new(42, "km")
+describe "Data#initialize" do
+ context "with no members" do
+ ruby_bug "#21819", ""..."4.0.1" do
+ it "is frozen" do
+ data = Data.define
- data.amount.should == 42
- data.unit.should == "km"
+ data.new.should.frozen?
+ end
end
+ end
- it "accepts alternative positional arguments" do
- data = DataSpecs::Measure[42, "km"]
+ it "accepts positional arguments" do
+ data = DataSpecs::Measure.new(42, "km")
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ it "accepts alternative positional arguments" do
+ data = DataSpecs::Measure[42, "km"]
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- it "accepts alternative keyword arguments" do
- data = DataSpecs::Measure[amount: 42, unit: "km"]
+ it "accepts keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- it "accepts String keyword arguments" do
- data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
+ it "accepts alternative keyword arguments" do
+ data = DataSpecs::Measure[amount: 42, unit: "km"]
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- it "raises ArgumentError if no arguments are given" do
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts the last entry when a keyword is given as both String and Symbol" do
+ data = DataSpecs::Single.new("value" => -1, value: 42)
+
+ data.value.should == 42
+ end
+
+ it "accepts positional arguments with empty keyword arguments" do
+ data = DataSpecs::Single.new(42, **{})
+
+ data.value.should == 42
+
+ data = DataSpecs::Measure.new(42, "km", **{})
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "raises ArgumentError if no arguments are given" do
+ -> {
+ DataSpecs::Measure.new
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?("missing keywords: :amount, :unit")
+ }
+ end
+
+ it "raises ArgumentError if at least one argument is missing" do
+ -> {
+ DataSpecs::Measure.new(unit: "km")
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?("missing keyword: :amount")
+ }
+ end
+
+ ruby_version_is "4.0" do # https://bugs.ruby-lang.org/issues/21844
+ it "raises ArgumentError if at least one argument is missing and other is provided as both String and Symbol" do
-> {
- DataSpecs::Measure.new
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keywords: :amount, :unit")
+ DataSpecs::Measure.new(unit: "km", "unit" => "km")
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?("missing keyword: :amount")
}
end
+ end
+
+ it "raises ArgumentError if unknown keyword is given" do
+ -> {
+ DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?("unknown keyword: :system")
+ }
+ end
+
+ ruby_version_is "4.0" do # https://bugs.ruby-lang.org/issues/21844
+ it "raises ArgumentError if unknown keyword is given which is convertable to String" do
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return("system")
- it "raises ArgumentError if at least one argument is missing" do
-> {
- DataSpecs::Measure.new(unit: "km")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keyword: :amount")
+ DataSpecs::Measure.new(amount: 42, unit: "km", key => "metric")
+ }.should.raise(ArgumentError) { |e|
+ e.message.should.include?('unknown keyword: "system"')
}
end
- it "raises ArgumentError if unknown keyword is given" do
+ it "raises TypeError when the keyword is not convertable to String" do
-> {
- DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("unknown keyword: :system")
+ DataSpecs::Measure.new(1 => 2)
+ }.should.raise(TypeError) { |e|
+ e.message.should == "1 is not a symbol nor a string"
}
end
+
+ it "raises TypeError if the conversion with #to_str does not return a String" do
+ klass = Data.define(:x, :y)
+
+ key = mock("to_str")
+ key.should_receive(:to_str).and_return(0)
+
+ -> {
+ klass.new(key => 2)
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
+ end
+ end
+
+ it "supports super from a subclass" do
+ ms = DataSpecs::MeasureSubclass.new(amount: 1, unit: "km")
+
+ ms.amount.should == 1
+ ms.unit.should == "km"
+ end
+
+ it "supports Data with no fields" do
+ -> { DataSpecs::Empty.new }.should_not.raise
+ end
+
+ it "can be overridden" do
+ ScratchPad.record []
+
+ measure_class = Data.define(:amount, :unit) do
+ def initialize(*, **)
+ super
+ ScratchPad << :initialize
+ end
+ end
+
+ measure_class.new(42, "m")
+ ScratchPad.recorded.should == [:initialize]
+ end
+
+ context "when it is overridden" do
+ it "is called with keyword arguments when given positional arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize.new(42, "m")
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
+ end
+
+ it "is called with keyword arguments when given keyword arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize.new(amount: 42, unit: "m")
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
+ end
+
+ it "is called with keyword arguments when given alternative positional arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize[42, "m"]
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
+ end
+
+ it "is called with keyword arguments when given alternative keyword arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize[amount: 42, unit: "m"]
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
+ end
+
+ it "accepts positional arguments with empty keyword arguments" do
+ data = DataSpecs::SingleWithOverriddenName.new(42, **{})
+
+ data.value.should == 42
+
+ data = DataSpecs::MeasureWithOverriddenName.new(42, "km", **{})
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ # See https://github.com/ruby/psych/pull/765
+ it "can be deserialized by calling Data.instance_method(:initialize)" do
+ d1 = DataSpecs::Area.new(width: 2, height: 3)
+ d1.area.should == 6
+
+ d2 = DataSpecs::Area.allocate
+ Data.instance_method(:initialize).bind_call(d2, **d1.to_h)
+ d2.should == d1
+ end
end
end
diff --git a/spec/ruby/core/data/inspect_spec.rb b/spec/ruby/core/data/inspect_spec.rb
index 3d337fac68..6c97a719e3 100644
--- a/spec/ruby/core/data/inspect_spec.rb
+++ b/spec/ruby/core/data/inspect_spec.rb
@@ -1,8 +1,63 @@
require_relative '../../spec_helper'
-require_relative 'shared/inspect'
+require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#inspect" do
- it_behaves_like :data_inspect, :inspect
+describe "Data#inspect" do
+ it "returns a string representation showing members and values" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.inspect.should == '#<data DataSpecs::Measure amount=42, unit="km">'
+ end
+
+ it "returns a string representation without the class name for anonymous structs" do
+ Data.define(:a).new("").inspect.should == '#<data a="">'
+ end
+
+ it "returns a string representation without the class name for structs nested in anonymous classes" do
+ c = Class.new
+ c.class_eval <<~DOC
+ Foo = Data.define(:a)
+ DOC
+
+ c::Foo.new("").inspect.should == '#<data a="">'
+ end
+
+ it "returns a string representation without the class name for structs nested in anonymous modules" do
+ m = Module.new
+ m.class_eval <<~DOC
+ Foo = Data.define(:a)
+ DOC
+
+ m::Foo.new("").inspect.should == '#<data a="">'
+ end
+
+ it "does not call #name method" do
+ struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
+ struct.inspect.should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
+ end
+
+ it "does not call #name method when struct is anonymous" do
+ klass = Class.new(DataSpecs::Measure) do
+ def self.name
+ "A"
+ end
+ end
+ struct = klass.new(42, "km")
+ struct.inspect.should == '#<data amount=42, unit="km">'
+ end
+
+ context "recursive structure" do
+ it "returns string representation with recursive attribute replaced with ..." do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.inspect.should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
+ end
+
+ it "returns string representation with recursive attribute replaced with ... when an anonymous class" do
+ klass = Class.new(DataSpecs::Measure)
+ a = klass.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.inspect.should =~ /#<data amount=42, unit=#<data #<Class:0x.+?>:\.\.\.>>/
+ end
end
end
diff --git a/spec/ruby/core/data/members_spec.rb b/spec/ruby/core/data/members_spec.rb
index 1776b0b9c1..457a90a0d6 100644
--- a/spec/ruby/core/data/members_spec.rb
+++ b/spec/ruby/core/data/members_spec.rb
@@ -1,23 +1,21 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#members" do
- it "returns an array of attribute names" do
- measure = DataSpecs::Measure.new(amount: 42, unit: 'km')
- measure.members.should == [:amount, :unit]
- end
+describe "Data#members" do
+ it "returns an array of attribute names" do
+ measure = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ measure.members.should == [:amount, :unit]
end
+end
- describe "DataClass#members" do
- it "returns an array of attribute names" do
- DataSpecs::Measure.members.should == [:amount, :unit]
- end
+describe "DataClass#members" do
+ it "returns an array of attribute names" do
+ DataSpecs::Measure.members.should == [:amount, :unit]
+ end
- context "class inheriting Data" do
- it "isn't available in a subclass" do
- DataSpecs::DataSubclass.should_not.respond_to?(:members)
- end
+ context "class inheriting Data" do
+ it "isn't available in a subclass" do
+ DataSpecs::DataSubclass.should_not.respond_to?(:members)
end
end
end
diff --git a/spec/ruby/core/data/shared/inspect.rb b/spec/ruby/core/data/shared/inspect.rb
deleted file mode 100644
index 7f54a46de3..0000000000
--- a/spec/ruby/core/data/shared/inspect.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :data_inspect, shared: true do
- it "returns a string representation showing members and values" do
- a = DataSpecs::Measure.new(42, "km")
- a.send(@method).should == '#<data DataSpecs::Measure amount=42, unit="km">'
- end
-
- it "returns a string representation without the class name for anonymous structs" do
- Data.define(:a).new("").send(@method).should == '#<data a="">'
- end
-
- it "returns a string representation without the class name for structs nested in anonymous classes" do
- c = Class.new
- c.class_eval <<~DOC
- Foo = Data.define(:a)
- DOC
-
- c::Foo.new("").send(@method).should == '#<data a="">'
- end
-
- it "returns a string representation without the class name for structs nested in anonymous modules" do
- m = Module.new
- m.class_eval <<~DOC
- Foo = Data.define(:a)
- DOC
-
- m::Foo.new("").send(@method).should == '#<data a="">'
- end
-
- it "does not call #name method" do
- struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
- struct.send(@method).should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
- end
-
- it "does not call #name method when struct is anonymous" do
- klass = Class.new(DataSpecs::Measure) do
- def self.name
- "A"
- end
- end
- struct = klass.new(42, "km")
- struct.send(@method).should == '#<data amount=42, unit="km">'
- end
-
- context "recursive structure" do
- it "returns string representation with recursive attribute replaced with ..." do
- a = DataSpecs::Measure.allocate
- a.send(:initialize, amount: 42, unit: a)
-
- a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
- end
- end
-end
diff --git a/spec/ruby/core/data/to_h_spec.rb b/spec/ruby/core/data/to_h_spec.rb
index 41d6960c97..41925cf3b2 100644
--- a/spec/ruby/core/data/to_h_spec.rb
+++ b/spec/ruby/core/data/to_h_spec.rb
@@ -1,65 +1,63 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#to_h" do
- it "transforms the data object into a hash" do
+describe "Data#to_h" do
+ it "transforms the data object into a hash" do
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ data.to_h.should == { amount: 42, unit: 'km' }
+ end
+
+ context "with block" do
+ it "transforms [key, value] pairs returned by the block into a hash" do
data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h.should == { amount: 42, unit: 'km' }
+ data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit }
end
- context "with block" do
- it "transforms [key, value] pairs returned by the block into a hash" do
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit }
- end
-
- it "passes to a block each pair's key and value as separate arguments" do
- ScratchPad.record []
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
- ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
+ it "passes to a block each pair's key and value as separate arguments" do
+ ScratchPad.record []
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ data.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
+ ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
- ScratchPad.record []
- data.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
- end
+ ScratchPad.record []
+ data.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
+ ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
+ end
- it "raises ArgumentError if block returns longer or shorter array" do
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- -> do
- data.to_h { |k, v| [k.to_s, v*v, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ it "raises ArgumentError if block returns longer or shorter array" do
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ -> do
+ data.to_h { |k, v| [k.to_s, v*v, 1] }
+ end.should.raise(ArgumentError, /element has wrong array length/)
- -> do
- data.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
- end
+ -> do
+ data.to_h { |k, v| [k] }
+ end.should.raise(ArgumentError, /element has wrong array length/)
+ end
- it "raises TypeError if block returns something other than Array" do
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- -> do
- data.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
- end
+ it "raises TypeError if block returns something other than Array" do
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ -> do
+ data.to_h { |k, v| "not-array" }
+ end.should.raise(TypeError, /wrong element type String/)
+ end
- it "coerces returned pair to Array with #to_ary" do
- x = mock('x')
- x.stub!(:to_ary).and_return([:b, 'b'])
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ it "coerces returned pair to Array with #to_ary" do
+ x = mock('x')
+ x.stub!(:to_ary).and_return([:b, 'b'])
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h { |k| x }.should == { :b => 'b' }
- end
+ data.to_h { |k| x }.should == { :b => 'b' }
+ end
- it "does not coerce returned pair to Array with #to_a" do
- x = mock('x')
- x.stub!(:to_a).and_return([:b, 'b'])
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ it "does not coerce returned pair to Array with #to_a" do
+ x = mock('x')
+ x.stub!(:to_a).and_return([:b, 'b'])
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- -> do
- data.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
- end
+ -> do
+ data.to_h { |k| x }
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/data/to_s_spec.rb b/spec/ruby/core/data/to_s_spec.rb
index 0b9099f035..a552e4659b 100644
--- a/spec/ruby/core/data/to_s_spec.rb
+++ b/spec/ruby/core/data/to_s_spec.rb
@@ -1,8 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/inspect'
+require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#to_s" do
- it_behaves_like :data_inspect, :to_s
+describe "Data#to_s" do
+ it "is an alias of Data#inspect" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.method(:to_s).should == a.method(:inspect)
end
end
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
index 97e34c951f..b74df185c7 100644
--- a/spec/ruby/core/data/with_spec.rb
+++ b/spec/ruby/core/data/with_spec.rb
@@ -1,35 +1,55 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#with" do
- it "returns self if given no arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with.should.equal?(data)
- end
+describe "Data#with" do
+ it "returns self if given no arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with.should.equal?(data)
+ end
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with(amount: 4, unit: "m")
+ it "accepts keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with(amount: 4, unit: "m")
- data.amount.should == 4
- data.unit.should == "m"
- end
+ data.amount.should == 4
+ data.unit.should == "m"
+ end
- it "accepts String keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with("amount" => 4, "unit" => "m")
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with("amount" => 4, "unit" => "m")
- data.amount.should == 4
- data.unit.should == "m"
- end
+ data.amount.should == 4
+ data.unit.should == "m"
+ end
+
+ it "raises ArgumentError if no keyword arguments are given" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
- it "raises ArgumentError if no keyword arguments are given" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ -> {
+ data.with(4, "m")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ end
+
+ it "does not depend on the Data.new method" do
+ subclass = Class.new(DataSpecs::Measure)
+ data = subclass.new(amount: 42, unit: "km")
- -> {
- data.with(4, "m")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ def subclass.new(*)
+ raise "Data.new is called"
end
+
+ data_copy = data.with(unit: "m")
+ data_copy.amount.should == 42
+ data_copy.unit.should == "m"
+ end
+
+ it "calls #initialize" do
+ data = DataSpecs::DataWithOverriddenInitialize.new(42, "m")
+ ScratchPad.clear
+
+ data.with(amount: 0)
+
+ ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}]
end
end
diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb
index 1da9307599..2dc598e2a9 100644
--- a/spec/ruby/core/dir/chdir_spec.rb
+++ b/spec/ruby/core/dir/chdir_spec.rb
@@ -90,8 +90,8 @@ describe "Dir.chdir" do
end
it "raises an Errno::ENOENT if the directory does not exist" do
- -> { Dir.chdir DirSpecs.nonexistent }.should raise_error(Errno::ENOENT)
- -> { Dir.chdir(DirSpecs.nonexistent) { } }.should raise_error(Errno::ENOENT)
+ -> { Dir.chdir DirSpecs.nonexistent }.should.raise(Errno::ENOENT)
+ -> { Dir.chdir(DirSpecs.nonexistent) { } }.should.raise(Errno::ENOENT)
end
it "raises an Errno::ENOENT if the original directory no longer exists" do
@@ -106,7 +106,7 @@ describe "Dir.chdir" do
Dir.chdir dir1 do
Dir.chdir(dir2) { Dir.unlink dir1 }
end
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
ensure
Dir.unlink dir1 if Dir.exist?(dir1)
Dir.unlink dir2 if Dir.exist?(dir2)
@@ -125,96 +125,94 @@ describe "Dir.chdir" do
end
end
-ruby_version_is '3.3' do
- describe "Dir#chdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+describe "Dir#chdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "changes the current working directory to self" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir
- Dir.pwd.should == DirSpecs.mock_dir
- ensure
- dir.close
- end
+ it "changes the current working directory to self" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
- it "changes the current working directory to self for duration of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- pwd_in_block = nil
+ it "changes the current working directory to self for duration of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ pwd_in_block = nil
- dir.chdir { pwd_in_block = Dir.pwd }
+ dir.chdir { pwd_in_block = Dir.pwd }
- pwd_in_block.should == DirSpecs.mock_dir
- Dir.pwd.should == @original
- ensure
- dir.close
- end
+ pwd_in_block.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
- it "returns 0 when successfully changing directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir.should == 0
- ensure
- dir.close
- end
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir.should == 0
+ ensure
+ dir.close
+ end
- it "returns the value of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir { :block_value }.should == :block_value
- ensure
- dir.close
- end
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
+
+ platform_is_not :windows do
+ it "does not raise an Errno::ENOENT if the original directory no longer exists" do
+ dir_name1 = tmp('testdir1')
+ dir_name2 = tmp('testdir2')
+ Dir.should_not.exist?(dir_name1)
+ Dir.should_not.exist?(dir_name2)
+ Dir.mkdir dir_name1
+ Dir.mkdir dir_name2
- guard -> { Dir.respond_to? :fchdir } do
- it "does not raise an Errno::ENOENT if the original directory no longer exists" do
- dir_name1 = tmp('testdir1')
- dir_name2 = tmp('testdir2')
- Dir.should_not.exist?(dir_name1)
- Dir.should_not.exist?(dir_name2)
- Dir.mkdir dir_name1
- Dir.mkdir dir_name2
-
- dir2 = Dir.new(dir_name2)
-
- begin
- Dir.chdir(dir_name1) do
- dir2.chdir { Dir.unlink dir_name1 }
- end
- Dir.pwd.should == @original
- ensure
- Dir.unlink dir_name1 if Dir.exist?(dir_name1)
- Dir.unlink dir_name2 if Dir.exist?(dir_name2)
+ dir2 = Dir.new(dir_name2)
+
+ begin
+ Dir.chdir(dir_name1) do
+ dir2.chdir { Dir.unlink dir_name1 }
end
+ Dir.pwd.should == @original
ensure
- dir2.close
+ Dir.unlink dir_name1 if Dir.exist?(dir_name1)
+ Dir.unlink dir_name2 if Dir.exist?(dir_name2)
end
+ ensure
+ dir2.close
end
+ end
- it "always returns to the original directory when given a block" do
- dir = Dir.new(DirSpecs.mock_dir)
+ it "always returns to the original directory when given a block" do
+ dir = Dir.new(DirSpecs.mock_dir)
- begin
- dir.chdir do
- raise StandardError, "something bad happened"
- end
- rescue StandardError
+ begin
+ dir.chdir do
+ raise StandardError, "something bad happened"
end
-
- Dir.pwd.should == @original
- ensure
- dir.close
+ rescue StandardError
end
+
+ Dir.pwd.should == @original
+ ensure
+ dir.close
end
end
diff --git a/spec/ruby/core/dir/children_spec.rb b/spec/ruby/core/dir/children_spec.rb
index 0ad3df4669..6e6da1dd44 100644
--- a/spec/ruby/core/dir/children_spec.rb
+++ b/spec/ruby/core/dir/children_spec.rb
@@ -47,25 +47,25 @@ describe "Dir.children" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- children.should include("こんにちは.txt".dup.force_encoding(encoding))
+ children.should.include?("こんにちは.txt".dup.force_encoding(encoding))
end
- children.first.encoding.should equal(Encoding.find("filesystem"))
+ children.first.encoding.should.equal?(Encoding.find("filesystem"))
end
it "returns children encoded with the specified encoding" do
dir = File.join(DirSpecs.mock_dir, 'special')
children = Dir.children(dir, encoding: "euc-jp").sort
- children.first.encoding.should equal(Encoding::EUC_JP)
+ children.first.encoding.should.equal?(Encoding::EUC_JP)
end
it "returns children transcoded to the default internal encoding" do
Encoding.default_internal = Encoding::EUC_KR
children = Dir.children(File.join(DirSpecs.mock_dir, 'special')).sort
- children.first.encoding.should equal(Encoding::EUC_KR)
+ children.first.encoding.should.equal?(Encoding::EUC_KR)
end
it "raises a SystemCallError if called with a nonexistent directory" do
- -> { Dir.children DirSpecs.nonexistent }.should raise_error(SystemCallError)
+ -> { Dir.children DirSpecs.nonexistent }.should.raise(SystemCallError)
end
end
@@ -113,23 +113,23 @@ describe "Dir#children" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- children.should include("こんにちは.txt".dup.force_encoding(encoding))
+ children.should.include?("こんにちは.txt".dup.force_encoding(encoding))
end
- children.first.encoding.should equal(Encoding.find("filesystem"))
+ children.first.encoding.should.equal?(Encoding.find("filesystem"))
end
it "returns children encoded with the specified encoding" do
path = File.join(DirSpecs.mock_dir, 'special')
@dir = Dir.new(path, encoding: "euc-jp")
children = @dir.children.sort
- children.first.encoding.should equal(Encoding::EUC_JP)
+ children.first.encoding.should.equal?(Encoding::EUC_JP)
end
it "returns children transcoded to the default internal encoding" do
Encoding.default_internal = Encoding::EUC_KR
@dir = Dir.new(File.join(DirSpecs.mock_dir, 'special'))
children = @dir.children.sort
- children.first.encoding.should equal(Encoding::EUC_KR)
+ children.first.encoding.should.equal?(Encoding::EUC_KR)
end
it "returns the same result when called repeatedly" do
diff --git a/spec/ruby/core/dir/chroot_spec.rb b/spec/ruby/core/dir/chroot_spec.rb
index a5ca8943fc..79ad9759b0 100644
--- a/spec/ruby/core/dir/chroot_spec.rb
+++ b/spec/ruby/core/dir/chroot_spec.rb
@@ -21,17 +21,17 @@ platform_is_not :windows do
end
it "raises an Errno::EPERM exception if the directory exists" do
- -> { Dir.chroot('.') }.should raise_error(Errno::EPERM)
+ -> { Dir.chroot('.') }.should.raise(Errno::EPERM)
end
it "raises a SystemCallError if the directory doesn't exist" do
- -> { Dir.chroot('xgwhwhsjai2222jg') }.should raise_error(SystemCallError)
+ -> { Dir.chroot('xgwhwhsjai2222jg') }.should.raise(SystemCallError)
end
it "calls #to_path on non-String argument" do
p = mock('path')
p.should_receive(:to_path).and_return('.')
- -> { Dir.chroot(p) }.should raise_error(Errno::EPERM)
+ -> { Dir.chroot(p) }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/dir/close_spec.rb b/spec/ruby/core/dir/close_spec.rb
index 5fbf5fcaf2..9902d98934 100644
--- a/spec/ruby/core/dir/close_spec.rb
+++ b/spec/ruby/core/dir/close_spec.rb
@@ -14,8 +14,8 @@ describe "Dir#close" do
dir.close.should == nil
dir.close.should == nil
- guard -> { dir.respond_to? :fileno } do
- -> { dir.fileno }.should raise_error(IOError, /closed directory/)
+ platform_is_not :windows do
+ -> { dir.fileno }.should.raise(IOError, /closed directory/)
end
end
@@ -24,8 +24,8 @@ describe "Dir#close" do
dir.close.should == nil
end
- ruby_version_is '3.3'...'3.4' do
- guard -> { Dir.respond_to? :for_fd } do
+ ruby_version_is ''...'3.4' do
+ platform_is_not :windows do
it "does not raise an error even if the file descriptor is closed with another Dir instance" do
dir = Dir.open DirSpecs.mock_dir
dir_new = Dir.for_fd(dir.fileno)
@@ -33,20 +33,20 @@ describe "Dir#close" do
dir.close
dir_new.close
- -> { dir.fileno }.should raise_error(IOError, /closed directory/)
- -> { dir_new.fileno }.should raise_error(IOError, /closed directory/)
+ -> { dir.fileno }.should.raise(IOError, /closed directory/)
+ -> { dir_new.fileno }.should.raise(IOError, /closed directory/)
end
end
end
ruby_version_is '3.4' do
- guard -> { Dir.respond_to? :for_fd } do
+ platform_is_not :windows do
it "raises an error if the file descriptor is closed with another Dir instance" do
dir = Dir.open DirSpecs.mock_dir
dir_new = Dir.for_fd(dir.fileno)
dir.close
- -> { dir_new.close }.should raise_error(Errno::EBADF, 'Bad file descriptor - closedir')
+ -> { dir_new.close }.should.raise(Errno::EBADF, 'Bad file descriptor - closedir')
end
end
end
diff --git a/spec/ruby/core/dir/each_child_spec.rb b/spec/ruby/core/dir/each_child_spec.rb
index 7194273b95..4d6575df39 100644
--- a/spec/ruby/core/dir/each_child_spec.rb
+++ b/spec/ruby/core/dir/each_child_spec.rb
@@ -36,12 +36,12 @@ describe "Dir.each_child" do
end
it "raises a SystemCallError if passed a nonexistent directory" do
- -> { Dir.each_child(DirSpecs.nonexistent) {} }.should raise_error(SystemCallError)
+ -> { Dir.each_child(DirSpecs.nonexistent) {} }.should.raise(SystemCallError)
end
describe "when no block is given" do
it "returns an Enumerator" do
- Dir.each_child(DirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Dir.each_child(DirSpecs.mock_dir).should.instance_of?(Enumerator)
Dir.each_child(DirSpecs.mock_dir).to_a.sort.should == DirSpecs.expected_paths - %w[. ..]
end
@@ -103,7 +103,7 @@ describe "Dir#each_child" do
it "returns an Enumerator" do
@dir = Dir.new(DirSpecs.mock_dir)
- @dir.each_child.should be_an_instance_of(Enumerator)
+ @dir.each_child.should.instance_of?(Enumerator)
@dir.each_child.to_a.sort.should == DirSpecs.expected_paths - %w|. ..|
end
diff --git a/spec/ruby/core/dir/each_spec.rb b/spec/ruby/core/dir/each_spec.rb
index 7674663d82..e997e340b1 100644
--- a/spec/ruby/core/dir/each_spec.rb
+++ b/spec/ruby/core/dir/each_spec.rb
@@ -32,7 +32,7 @@ describe "Dir#each" do
@dir.each {}.should == @dir
@dir.read.should == nil
@dir.rewind
- ls.should include(@dir.read)
+ ls.should.include?(@dir.read)
end
it "returns the same result when called repeatedly" do
@@ -48,7 +48,7 @@ describe "Dir#each" do
describe "when no block is given" do
it "returns an Enumerator" do
- @dir.each.should be_an_instance_of(Enumerator)
+ @dir.each.should.instance_of?(Enumerator)
@dir.each.to_a.sort.should == DirSpecs.expected_paths
end
diff --git a/spec/ruby/core/dir/empty_spec.rb b/spec/ruby/core/dir/empty_spec.rb
index 8cc8757798..3b6b2bac85 100644
--- a/spec/ruby/core/dir/empty_spec.rb
+++ b/spec/ruby/core/dir/empty_spec.rb
@@ -12,20 +12,20 @@ describe "Dir.empty?" do
it "returns true for empty directories" do
result = Dir.empty? @empty_dir
- result.should be_true
+ result.should == true
end
it "returns false for non-empty directories" do
result = Dir.empty? __dir__
- result.should be_false
+ result.should == false
end
it "returns false for a non-directory" do
result = Dir.empty? __FILE__
- result.should be_false
+ result.should == false
end
it "raises ENOENT for nonexistent directories" do
- -> { Dir.empty? tmp("nonexistent") }.should raise_error(Errno::ENOENT)
+ -> { Dir.empty? tmp("nonexistent") }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/dir/entries_spec.rb b/spec/ruby/core/dir/entries_spec.rb
index 7462542acf..f3ca49b26d 100644
--- a/spec/ruby/core/dir/entries_spec.rb
+++ b/spec/ruby/core/dir/entries_spec.rb
@@ -47,24 +47,24 @@ describe "Dir.entries" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- entries.should include("こんにちは.txt".dup.force_encoding(encoding))
+ entries.should.include?("こんにちは.txt".dup.force_encoding(encoding))
end
- entries.first.encoding.should equal(Encoding.find("filesystem"))
+ entries.first.encoding.should.equal?(Encoding.find("filesystem"))
end
it "returns entries encoded with the specified encoding" do
dir = File.join(DirSpecs.mock_dir, 'special')
entries = Dir.entries(dir, encoding: "euc-jp").sort
- entries.first.encoding.should equal(Encoding::EUC_JP)
+ entries.first.encoding.should.equal?(Encoding::EUC_JP)
end
it "returns entries transcoded to the default internal encoding" do
Encoding.default_internal = Encoding::EUC_KR
entries = Dir.entries(File.join(DirSpecs.mock_dir, 'special')).sort
- entries.first.encoding.should equal(Encoding::EUC_KR)
+ entries.first.encoding.should.equal?(Encoding::EUC_KR)
end
it "raises a SystemCallError if called with a nonexistent directory" do
- -> { Dir.entries DirSpecs.nonexistent }.should raise_error(SystemCallError)
+ -> { Dir.entries DirSpecs.nonexistent }.should.raise(SystemCallError)
end
end
diff --git a/spec/ruby/core/dir/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb
index 9023de533f..05ad67dd03 100644
--- a/spec/ruby/core/dir/exist_spec.rb
+++ b/spec/ruby/core/dir/exist_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/exist'
describe "Dir.exist?" do
before :all do
@@ -11,13 +10,65 @@ describe "Dir.exist?" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_exist, :exist?
+ it "returns true if the given directory exists" do
+ Dir.exist?(__dir__).should == true
+ end
+
+ it "returns true for '.'" do
+ Dir.exist?('.').should == true
+ end
+
+ it "returns true for '..'" do
+ Dir.exist?('..').should == true
+ end
+
+ it "understands non-ASCII paths" do
+ subdir = File.join(tmp("\u{9876}\u{665}"))
+ Dir.exist?(subdir).should == false
+ Dir.mkdir(subdir)
+ Dir.exist?(subdir).should == true
+ Dir.rmdir(subdir)
+ end
+
+ it "understands relative paths" do
+ Dir.exist?(__dir__ + '/../').should == true
+ end
+
+ it "returns false if the given directory doesn't exist" do
+ Dir.exist?('y26dg27n2nwjs8a/').should == false
+ end
+
+ it "doesn't require the name to have a trailing slash" do
+ dir = __dir__
+ dir.sub!(/\/$/,'')
+ Dir.exist?(dir).should == true
+ end
+
+ it "doesn't expand paths" do
+ skip "$HOME not valid directory" unless ENV['HOME'] && File.directory?(ENV['HOME'])
+ Dir.exist?(File.expand_path('~')).should == true
+ Dir.exist?('~').should == false
+ end
+
+ it "returns false if the argument exists but is a file" do
+ File.should.exist?(__FILE__)
+ Dir.exist?(__FILE__).should == false
+ end
+
+ it "doesn't set $! when file doesn't exist" do
+ Dir.exist?("/path/to/non/existent/dir")
+ $!.should == nil
+ end
+
+ it "calls #to_path on non String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(__dir__)
+ Dir.exist?(p)
+ end
end
-ruby_version_is "3.2" do
- describe "Dir.exists?" do
- it "has been removed" do
- Dir.should_not.respond_to?(:exists?)
- end
+describe "Dir.exists?" do
+ it "has been removed" do
+ Dir.should_not.respond_to?(:exists?)
end
end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
index d9dec13aab..bd1a92b05e 100644
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -1,73 +1,71 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-ruby_version_is '3.3' do
- guard -> { Dir.respond_to? :fchdir } do
- describe "Dir.fchdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+platform_is_not :windows do
+ describe "Dir.fchdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "changes the current working directory to the directory specified by the integer file descriptor" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir dir.fileno
- Dir.pwd.should == DirSpecs.mock_dir
- ensure
- dir.close
- end
+ it "changes the current working directory to the directory specified by the integer file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir dir.fileno
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
- it "returns 0 when successfully changing directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno).should == 0
- ensure
- dir.close
- end
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno).should == 0
+ ensure
+ dir.close
+ end
- it "returns the value of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
- ensure
- dir.close
- end
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
- it "changes to the specified directory for the duration of the block" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
- Dir.pwd.should == @original
- ensure
- dir.close
- end
+ it "changes to the specified directory for the duration of the block" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
- -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
- end
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.fchdir(-1) }.should.raise(SystemCallError, "Bad file descriptor - fchdir")
+ -> { Dir.fchdir(-1) { } }.should.raise(SystemCallError, "Bad file descriptor - fchdir")
+ end
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
- -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
- end
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.fchdir $stdout.fileno }.should.raise(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
+ -> { Dir.fchdir($stdout.fileno) { } }.should.raise(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
end
end
+end
- guard_not -> { Dir.respond_to? :fchdir } do
- describe "Dir.fchdir" do
- it "raises NotImplementedError" do
- -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
- -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError)
- end
+platform_is :windows do
+ describe "Dir.fchdir" do
+ it "raises NotImplementedError" do
+ -> { Dir.fchdir 1 }.should.raise(NotImplementedError)
+ -> { Dir.fchdir(1) { } }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/dir/fileno_spec.rb b/spec/ruby/core/dir/fileno_spec.rb
index bb84ef5378..3b563eb18f 100644
--- a/spec/ruby/core/dir/fileno_spec.rb
+++ b/spec/ruby/core/dir/fileno_spec.rb
@@ -27,11 +27,11 @@ describe "Dir#fileno" do
if has_dir_fileno
it "returns the file descriptor of the dir" do
- @dir.fileno.should be_kind_of(Integer)
+ @dir.fileno.should.is_a?(Integer)
end
else
it "raises an error when not implemented on the platform" do
- -> { @dir.fileno }.should raise_error(NotImplementedError)
+ -> { @dir.fileno }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb
index 087f46b331..cfec91f68f 100644
--- a/spec/ruby/core/dir/fixtures/common.rb
+++ b/spec/ruby/core/dir/fixtures/common.rb
@@ -115,6 +115,7 @@ module DirSpecs
end
def self.create_mock_dirs
+ delete_mock_dirs
mock_dir_files.each do |name|
file = File.join mock_dir, name
mkdir_p File.dirname(file)
@@ -172,33 +173,31 @@ module DirSpecs
end
end
+ def self.expected_paths_with_type
+ [
+ [".", :directory],
+ ["..", :directory],
+ [".dotfile", :file],
+ [".dotsubdir", :directory],
+ ["brace", :directory],
+ ["deeply", :directory],
+ ["dir", :directory],
+ ["dir_filename_ordering", :file],
+ ["file_one.ext", :file],
+ ["file_two.ext", :file],
+ ["nested", :directory],
+ ["nondotfile", :file],
+ ["special", :directory],
+ ["subdir_one", :directory],
+ ["subdir_two", :directory],
+ ]
+ end
+
def self.expected_paths
- %w[
- .
- ..
- .dotfile
- .dotsubdir
- brace
- deeply
- dir
- dir_filename_ordering
- file_one.ext
- file_two.ext
- nested
- nondotfile
- special
- subdir_one
- subdir_two
- ]
+ expected_paths_with_type.map(&:first)
end
- if RUBY_VERSION > '3.1'
- def self.expected_glob_paths
- expected_paths - ['..']
- end
- else
- def self.expected_glob_paths
- expected_paths
- end
+ def self.expected_glob_paths
+ expected_paths - ['..']
end
end
diff --git a/spec/ruby/core/dir/for_fd_spec.rb b/spec/ruby/core/dir/for_fd_spec.rb
index 3afcc7e949..bbc75e0f8f 100644
--- a/spec/ruby/core/dir/for_fd_spec.rb
+++ b/spec/ruby/core/dir/for_fd_spec.rb
@@ -2,77 +2,75 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
quarantine! do # leads to "Errno::EBADF: Bad file descriptor - closedir" in DirSpecs.delete_mock_dirs
-ruby_version_is '3.3' do
- guard -> { Dir.respond_to? :for_fd } do
- describe "Dir.for_fd" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+platform_is_not :windows do
+ describe "Dir.for_fd" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir_new = Dir.for_fd(dir.fileno)
+ it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
- dir_new.should.instance_of?(Dir)
- dir_new.children.should == dir.children
- dir_new.fileno.should == dir.fileno
- ensure
- dir.close
- end
+ dir_new.should.instance_of?(Dir)
+ dir_new.children.should == dir.children
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
- it "returns a new Dir object without associated path" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir_new = Dir.for_fd(dir.fileno)
+ it "returns a new Dir object without associated path" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
- dir_new.path.should == nil
- ensure
- dir.close
- end
+ dir_new.path.should == nil
+ ensure
+ dir.close
+ end
- it "calls #to_int to convert a value to an Integer" do
- dir = Dir.new(DirSpecs.mock_dir)
- obj = mock("fd")
- obj.should_receive(:to_int).and_return(dir.fileno)
+ it "calls #to_int to convert a value to an Integer" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ obj = mock("fd")
+ obj.should_receive(:to_int).and_return(dir.fileno)
- dir_new = Dir.for_fd(obj)
- dir_new.fileno.should == dir.fileno
- ensure
- dir.close
- end
+ dir_new = Dir.for_fd(obj)
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
- it "raises TypeError when value cannot be converted to Integer" do
- -> {
- Dir.for_fd(nil)
- }.should raise_error(TypeError, "no implicit conversion from nil to integer")
- end
+ it "raises TypeError when value cannot be converted to Integer" do
+ -> {
+ Dir.for_fd(nil)
+ }.should raise_consistent_error(TypeError, "no implicit conversion of nil into Integer")
+ end
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir")
- end
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.for_fd(-1) }.should.raise(SystemCallError, "Bad file descriptor - fdopendir")
+ end
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir")
- end
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.for_fd $stdout.fileno }.should.raise(SystemCallError, "Not a directory - fdopendir")
end
end
+end
- guard_not -> { Dir.respond_to? :for_fd } do
- describe "Dir.for_fd" do
- it "raises NotImplementedError" do
- -> { Dir.for_fd 1 }.should raise_error(NotImplementedError)
- end
+platform_is :windows do
+ describe "Dir.for_fd" do
+ it "raises NotImplementedError" do
+ -> { Dir.for_fd 1 }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/dir/foreach_spec.rb b/spec/ruby/core/dir/foreach_spec.rb
index 9cf34b1d71..2a2265a029 100644
--- a/spec/ruby/core/dir/foreach_spec.rb
+++ b/spec/ruby/core/dir/foreach_spec.rb
@@ -31,11 +31,11 @@ describe "Dir.foreach" do
end
it "raises a SystemCallError if passed a nonexistent directory" do
- -> { Dir.foreach(DirSpecs.nonexistent) {} }.should raise_error(SystemCallError)
+ -> { Dir.foreach(DirSpecs.nonexistent) {} }.should.raise(SystemCallError)
end
it "returns an Enumerator if no block given" do
- Dir.foreach(DirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Dir.foreach(DirSpecs.mock_dir).should.instance_of?(Enumerator)
Dir.foreach(DirSpecs.mock_dir).to_a.sort.should == DirSpecs.expected_paths
end
@@ -53,7 +53,7 @@ describe "Dir.foreach" do
describe "when no block is given" do
it "returns an Enumerator" do
- Dir.foreach(DirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Dir.foreach(DirSpecs.mock_dir).should.instance_of?(Enumerator)
Dir.foreach(DirSpecs.mock_dir).to_a.sort.should == DirSpecs.expected_paths
end
diff --git a/spec/ruby/core/dir/getwd_spec.rb b/spec/ruby/core/dir/getwd_spec.rb
index 132634347c..138481821f 100644
--- a/spec/ruby/core/dir/getwd_spec.rb
+++ b/spec/ruby/core/dir/getwd_spec.rb
@@ -1,15 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-require_relative 'shared/pwd'
describe "Dir.getwd" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir.pwd" do
+ Dir.method(:getwd).should == Dir.method(:pwd)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_pwd, :getwd
end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index a60b233bc0..9e81feb15f 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -149,7 +149,7 @@ describe "Dir.glob" do
it "accepts a block and yields it with each elements" do
ary = []
ret = Dir.glob(["file_o*", "file_t*"]) { |t| ary << t }
- ret.should be_nil
+ ret.should == nil
ary.should == %w!file_one.ext file_two.ext!
end
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index 3cf745ab46..f0b20e0687 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -33,40 +33,32 @@ describe "Dir.home" do
end
platform_is :windows do
- ruby_version_is "3.2" do
- it "returns the home directory with forward slashs and as UTF-8" do
- ENV['HOME'] = "C:\\rubyspäc\\home"
- home = Dir.home
- home.should == "C:/rubyspäc/home"
- home.encoding.should == Encoding::UTF_8
- end
+ it "returns the home directory with forward slashs and as UTF-8" do
+ ENV['HOME'] = "C:\\rubyspäc\\home"
+ home = Dir.home
+ home.should == "C:/rubyspäc/home"
+ home.encoding.should == Encoding::UTF_8
+ end
- it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
- old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
+ it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
+ old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
- Dir.home.should == old_dirs[1].gsub("\\", "/")
- ENV['HOMEDRIVE'] = "C:"
- ENV['HOMEPATH'] = "\\rubyspec\\home1"
- Dir.home.should == "C:/rubyspec/home1"
- ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
- Dir.home.should == "C:/rubyspec/home2"
- ENV['HOME'] = "C:\\rubyspec\\home3"
- Dir.home.should == "C:/rubyspec/home3"
- ensure
- ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
- end
+ Dir.home.should == old_dirs[1].gsub("\\", "/")
+ ENV['HOMEDRIVE'] = "C:"
+ ENV['HOMEPATH'] = "\\rubyspec\\home1"
+ Dir.home.should == "C:/rubyspec/home1"
+ ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
+ Dir.home.should == "C:/rubyspec/home2"
+ ENV['HOME'] = "C:\\rubyspec\\home3"
+ Dir.home.should == "C:/rubyspec/home3"
+ ensure
+ ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
end
end
end
describe "when called with the current user name" do
- platform_is :solaris do
- it "returns the named user's home directory from the user database" do
- Dir.home(ENV['USER']).should == `getent passwd #{ENV['USER']}|cut -d: -f6`.chomp
- end
- end
-
- platform_is_not :windows, :solaris, :android, :wasi do
+ platform_is_not :windows, :android, :wasi do
it "returns the named user's home directory, from the user database" do
Dir.home(ENV['USER']).should == `echo ~#{ENV['USER']}`.chomp
end
@@ -82,7 +74,7 @@ describe "Dir.home" do
end
it "raises an ArgumentError if the named user doesn't exist" do
- -> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError)
+ -> { Dir.home('geuw2n288dh2k') }.should.raise(ArgumentError)
end
describe "when called with a nil user name" do
diff --git a/spec/ruby/core/dir/inspect_spec.rb b/spec/ruby/core/dir/inspect_spec.rb
index 37338a97d4..eabaa54ce0 100644
--- a/spec/ruby/core/dir/inspect_spec.rb
+++ b/spec/ruby/core/dir/inspect_spec.rb
@@ -11,7 +11,7 @@ describe "Dir#inspect" do
end
it "returns a String" do
- @dir.inspect.should be_an_instance_of(String)
+ @dir.inspect.should.instance_of?(String)
end
it "includes the class name" do
@@ -19,6 +19,6 @@ describe "Dir#inspect" do
end
it "includes the directory name" do
- @dir.inspect.should include(Dir.getwd)
+ @dir.inspect.should.include?(Dir.getwd)
end
end
diff --git a/spec/ruby/core/dir/mkdir_spec.rb b/spec/ruby/core/dir/mkdir_spec.rb
index 076ec19dd9..37513e417a 100644
--- a/spec/ruby/core/dir/mkdir_spec.rb
+++ b/spec/ruby/core/dir/mkdir_spec.rb
@@ -67,19 +67,19 @@ describe "Dir.mkdir" do
path = DirSpecs.mock_dir('nonexisting')
permissions = Object.new
- -> { Dir.mkdir(path, permissions) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
+ -> { Dir.mkdir(path, permissions) }.should.raise(TypeError, 'no implicit conversion of Object into Integer')
end
it "raises a SystemCallError if any of the directories in the path before the last does not exist" do
- -> { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should raise_error(SystemCallError)
+ -> { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should.raise(SystemCallError)
end
it "raises Errno::EEXIST if the specified directory already exists" do
- -> { Dir.mkdir("#{DirSpecs.mock_dir}/dir") }.should raise_error(Errno::EEXIST)
+ -> { Dir.mkdir("#{DirSpecs.mock_dir}/dir") }.should.raise(Errno::EEXIST)
end
it "raises Errno::EEXIST if the argument points to the existing file" do
- -> { Dir.mkdir("#{DirSpecs.mock_dir}/file_one.ext") }.should raise_error(Errno::EEXIST)
+ -> { Dir.mkdir("#{DirSpecs.mock_dir}/file_one.ext") }.should.raise(Errno::EEXIST)
end
end
@@ -100,7 +100,7 @@ platform_is_not :windows do
it "raises a SystemCallError when lacking adequate permissions in the parent dir" do
Dir.mkdir @dir, 0000
- -> { Dir.mkdir "#{@dir}/subdir" }.should raise_error(SystemCallError)
+ -> { Dir.mkdir "#{@dir}/subdir" }.should.raise(SystemCallError)
end
end
end
diff --git a/spec/ruby/core/dir/open_spec.rb b/spec/ruby/core/dir/open_spec.rb
index 27f362320b..be01638fbc 100644
--- a/spec/ruby/core/dir/open_spec.rb
+++ b/spec/ruby/core/dir/open_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/open'
describe "Dir.open" do
before :all do
@@ -11,5 +10,75 @@ describe "Dir.open" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_open, :open
+ it "returns a Dir instance representing the specified directory" do
+ dir = Dir.open(DirSpecs.mock_dir)
+ dir.should.is_a?(Dir)
+ dir.close
+ end
+
+ it "raises a SystemCallError if the directory does not exist" do
+ -> do
+ Dir.open(DirSpecs.nonexistent)
+ end.should.raise(SystemCallError)
+ end
+
+ it "may take a block which is yielded to with the Dir instance" do
+ Dir.open(DirSpecs.mock_dir) {|dir| dir.should.is_a?(Dir)}
+ end
+
+ it "returns the value of the block if a block is given" do
+ Dir.open(DirSpecs.mock_dir) {|dir| :value }.should == :value
+ end
+
+ it "closes the Dir instance when the block exits if given a block" do
+ closed_dir = Dir.open(DirSpecs.mock_dir) { |dir| dir }
+ -> { closed_dir.read }.should.raise(IOError)
+ end
+
+ it "closes the Dir instance when the block exits the block even due to an exception" do
+ closed_dir = nil
+
+ -> do
+ Dir.open(DirSpecs.mock_dir) do |dir|
+ closed_dir = dir
+ raise "dir specs"
+ end
+ end.should.raise(RuntimeError, "dir specs")
+
+ -> { closed_dir.read }.should.raise(IOError)
+ end
+
+ it "calls #to_path on non-String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(DirSpecs.mock_dir)
+ Dir.open(p) { true }
+ end
+
+ it "accepts an options Hash" do
+ dir = Dir.open(DirSpecs.mock_dir, encoding: "utf-8") {|d| d }
+ dir.should.is_a?(Dir)
+ end
+
+ it "calls #to_hash to convert the options object" do
+ options = mock("dir_open")
+ options.should_receive(:to_hash).and_return({ encoding: Encoding::UTF_8 })
+
+ dir = Dir.open(DirSpecs.mock_dir, **options) {|d| d }
+ dir.should.is_a?(Dir)
+ end
+
+ it "ignores the :encoding option if it is nil" do
+ dir = Dir.open(DirSpecs.mock_dir, encoding: nil) {|d| d }
+ dir.should.is_a?(Dir)
+ end
+
+ platform_is_not :windows do
+ it 'sets the close-on-exec flag for the directory file descriptor' do
+ Dir.open(DirSpecs.mock_dir) do |dir|
+ io = IO.for_fd(dir.fileno)
+ io.autoclose = false
+ io.should.close_on_exec?
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/dir/path_spec.rb b/spec/ruby/core/dir/path_spec.rb
index b1c24c406b..02ddd2cd42 100644
--- a/spec/ruby/core/dir/path_spec.rb
+++ b/spec/ruby/core/dir/path_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/path'
describe "Dir#path" do
before :all do
@@ -11,5 +10,28 @@ describe "Dir#path" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_path, :path
+ it "returns the path that was supplied to .new or .open" do
+ dir = Dir.open DirSpecs.mock_dir
+ begin
+ dir.path.should == DirSpecs.mock_dir
+ ensure
+ dir.close rescue nil
+ end
+ end
+
+ it "returns the path even when called on a closed Dir instance" do
+ dir = Dir.open DirSpecs.mock_dir
+ dir.close
+ dir.path.should == DirSpecs.mock_dir
+ end
+
+ it "returns a String with the same encoding as the argument to .open" do
+ path = DirSpecs.mock_dir.force_encoding Encoding::IBM866
+ dir = Dir.open path
+ begin
+ dir.path.encoding.should.equal?(Encoding::IBM866)
+ ensure
+ dir.close
+ end
+ end
end
diff --git a/spec/ruby/core/dir/pos_spec.rb b/spec/ruby/core/dir/pos_spec.rb
index b382bff81f..f8ca06d778 100644
--- a/spec/ruby/core/dir/pos_spec.rb
+++ b/spec/ruby/core/dir/pos_spec.rb
@@ -1,30 +1,11 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/closed'
require_relative 'shared/pos'
describe "Dir#pos" do
- before :all do
- DirSpecs.create_mock_dirs
- end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_pos, :pos
-end
-
-describe "Dir#pos" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir#tell" do
+ Dir.instance_method(:pos).should == Dir.instance_method(:tell)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_closed, :pos
end
describe "Dir#pos=" do
diff --git a/spec/ruby/core/dir/pwd_spec.rb b/spec/ruby/core/dir/pwd_spec.rb
index ad01286c90..70208b03d6 100644
--- a/spec/ruby/core/dir/pwd_spec.rb
+++ b/spec/ruby/core/dir/pwd_spec.rb
@@ -1,7 +1,6 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-require_relative 'shared/pwd'
describe "Dir.pwd" do
before :all do
@@ -12,7 +11,49 @@ describe "Dir.pwd" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_pwd, :pwd
+ before :each do
+ @fs_encoding = Encoding.find('filesystem')
+ end
+
+ it "returns the current working directory" do
+ pwd = Dir.pwd
+
+ File.directory?(pwd).should == true
+
+ # On ubuntu gutsy, for example, /bin/pwd does not
+ # understand -P. With just `pwd -P`, /bin/pwd is run.
+
+ # The following uses inode rather than file names to account for
+ # case insensitive file systems like default OS/X file systems
+ platform_is_not :windows do
+ File.stat(pwd).ino.should == File.stat(`/bin/sh -c "pwd -P"`.chomp).ino
+ end
+ platform_is :windows do
+ File.stat(pwd).ino.should == File.stat(File.expand_path(`cd`.chomp)).ino
+ end
+ end
+
+ it "returns an absolute path" do
+ pwd = Dir.pwd
+ pwd.should == File.expand_path(pwd)
+ end
+
+ it "returns an absolute path even when chdir to a relative path" do
+ Dir.chdir(".") do
+ pwd = Dir.pwd
+ File.directory?(pwd).should == true
+ pwd.should == File.expand_path(pwd)
+ end
+ end
+
+ it "returns a String with the filesystem encoding" do
+ enc = Dir.pwd.encoding
+ if @fs_encoding == Encoding::US_ASCII
+ [Encoding::US_ASCII, Encoding::BINARY].should.include?(enc)
+ else
+ enc.should.equal?(@fs_encoding)
+ end
+ end
end
describe "Dir.pwd" do
diff --git a/spec/ruby/core/dir/read_spec.rb b/spec/ruby/core/dir/read_spec.rb
index 276930c6b7..3f842457f4 100644
--- a/spec/ruby/core/dir/read_spec.rb
+++ b/spec/ruby/core/dir/read_spec.rb
@@ -15,7 +15,7 @@ describe "Dir#read" do
# an FS does not necessarily impose order
ls = Dir.entries DirSpecs.mock_dir
dir = Dir.open DirSpecs.mock_dir
- ls.should include(dir.read)
+ ls.should.include?(dir.read)
dir.close
end
@@ -61,7 +61,7 @@ describe "Dir#read" do
while entry = d.read
shift_jis_entries << entry
end
- }.should_not raise_error
+ }.should_not.raise
end
ensure
Encoding.default_internal = old_internal_encoding
diff --git a/spec/ruby/core/dir/scan_spec.rb b/spec/ruby/core/dir/scan_spec.rb
new file mode 100644
index 0000000000..3aa071337b
--- /dev/null
+++ b/spec/ruby/core/dir/scan_spec.rb
@@ -0,0 +1,224 @@
+# encoding: utf-8
+
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+require_relative '../file/fixtures/file_types'
+
+ruby_version_is "4.1" do
+ describe "Dir.scan" do
+ before :all do
+ FileSpecs.configure_types
+ end
+
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_internal = @internal
+ end
+
+ it "returns an Array of filename and type pairs in an existing directory including dotfiles" do
+ a = Dir.scan(DirSpecs.mock_dir).sort
+
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ a = Dir.scan("#{DirSpecs.mock_dir}/deeply/nested").sort
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "yields filename and type in an existing directory including dotfiles" do
+ a = []
+ Dir.scan(DirSpecs.mock_dir) do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ a = []
+ Dir.scan("#{DirSpecs.mock_dir}/deeply/nested") do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "calls #to_path on non-String arguments" do
+ p = mock('path')
+ p.should_receive(:to_path).and_return(DirSpecs.mock_dir)
+ Dir.scan(p)
+ end
+
+ it "accepts an options Hash" do
+ a = Dir.scan("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").sort
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "returns children names encoded with the filesystem encoding by default" do
+ # This spec depends on the locale not being US-ASCII because if it is, the
+ # children that are not ascii_only? will be BINARY encoded.
+ children = Dir.scan(File.join(DirSpecs.mock_dir, 'special')).sort
+ encoding = Encoding.find("filesystem")
+ encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
+ platform_is_not :windows do
+ children.should.include?(["こんにちは.txt".dup.force_encoding(encoding), :file])
+ end
+ children.first.first.encoding.should.equal?(Encoding.find("filesystem"))
+ end
+
+ it "returns children names encoded with the specified encoding" do
+ dir = File.join(DirSpecs.mock_dir, 'special')
+ children = Dir.scan(dir, encoding: "euc-jp").sort
+ children.first.first.encoding.should.equal?(Encoding::EUC_JP)
+ end
+
+ it "returns children names transcoded to the default internal encoding" do
+ Encoding.default_internal = Encoding::EUC_KR
+ children = Dir.scan(File.join(DirSpecs.mock_dir, 'special')).sort
+ children.first.first.encoding.should.equal?(Encoding::EUC_KR)
+ end
+
+ it "raises a SystemCallError if called with a nonexistent directory" do
+ -> { Dir.scan DirSpecs.nonexistent }.should.raise(SystemCallError)
+ end
+
+ it "handles symlink" do
+ FileSpecs.symlink do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:link)
+ end
+ end
+
+ platform_is_not :windows do
+ it "handles socket" do
+ FileSpecs.socket do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:socket)
+ end
+ end
+
+ it "handles FIFO" do
+ FileSpecs.fifo do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:fifo)
+ end
+ end
+
+ it "handles character devices" do
+ FileSpecs.character_device do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:characterSpecial)
+ end
+ end
+ end
+
+ platform_is_not :freebsd, :windows do
+ with_block_device do
+ it "handles block devices" do
+ FileSpecs.block_device do |path|
+ Dir.scan(File.dirname(path)).map(&:last).should.include?(:blockSpecial)
+ end
+ end
+ end
+ end
+ end
+
+ describe "Dir#scan" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_internal = @internal
+ @dir.close if @dir
+ end
+
+ it "returns an Array of filenames in an existing directory including dotfiles" do
+ @dir = Dir.new(DirSpecs.mock_dir)
+ a = @dir.scan.sort
+ @dir.close
+
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested")
+ a = @dir.scan.sort
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "yields filename and type in an existing directory including dotfiles" do
+ @dir = Dir.new(DirSpecs.mock_dir)
+ a = []
+ @dir.scan do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == DirSpecs.expected_paths_with_type - [[".", :directory], ["..", :directory]]
+
+ @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested")
+ a = []
+ @dir.scan do |n, t|
+ a << [n, t]
+ end
+ a.sort!
+ a.should == [[".dotfile.ext", :file], ["directory", :directory]]
+ end
+
+ it "accepts an encoding keyword for the encoding of the entries" do
+ @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8")
+ dirs = @dir.to_a.sort
+ dirs.each { |d| d.encoding.should == Encoding::UTF_8 }
+ end
+
+ it "returns children names encoded with the filesystem encoding by default" do
+ # This spec depends on the locale not being US-ASCII because if it is, the
+ # children that are not ascii_only? will be BINARY encoded.
+ @dir = Dir.new(File.join(DirSpecs.mock_dir, 'special'))
+ children = @dir.scan.sort
+ encoding = Encoding.find("filesystem")
+ encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
+ platform_is_not :windows do
+ children.should.include?(["こんにちは.txt".dup.force_encoding(encoding), :file])
+ end
+ children.first.first.encoding.should.equal?(Encoding.find("filesystem"))
+ end
+
+ it "returns children names encoded with the specified encoding" do
+ path = File.join(DirSpecs.mock_dir, 'special')
+ @dir = Dir.new(path, encoding: "euc-jp")
+ children = @dir.children.sort
+ children.first.encoding.should.equal?(Encoding::EUC_JP)
+ end
+
+ it "returns children names transcoded to the default internal encoding" do
+ Encoding.default_internal = Encoding::EUC_KR
+ @dir = Dir.new(File.join(DirSpecs.mock_dir, 'special'))
+ children = @dir.scan.sort
+ children.first.first.encoding.should.equal?(Encoding::EUC_KR)
+ end
+
+ it "returns the same result when called repeatedly" do
+ @dir = Dir.open DirSpecs.mock_dir
+
+ a = []
+ @dir.each {|dir| a << dir}
+
+ b = []
+ @dir.each {|dir| b << dir}
+
+ a.sort.should == b.sort
+ a.sort.should == DirSpecs.expected_paths
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/shared/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb
index a8f7c10a19..e4e6103799 100644
--- a/spec/ruby/core/dir/shared/chroot.rb
+++ b/spec/ruby/core/dir/shared/chroot.rb
@@ -18,7 +18,7 @@ describe :dir_chroot_as_root, shared: true do
compilations_ci = ENV["GITHUB_WORKFLOW"] == "Compilations"
it "can be used to change the process' root directory" do
- -> { Dir.send(@method, __dir__) }.should_not raise_error
+ -> { Dir.send(@method, __dir__) }.should_not.raise
File.should.exist?("/#{File.basename(__FILE__)}")
end unless compilations_ci
@@ -27,7 +27,7 @@ describe :dir_chroot_as_root, shared: true do
end
it "raises an Errno::ENOENT exception if the directory doesn't exist" do
- -> { Dir.send(@method, 'xgwhwhsjai2222jg') }.should raise_error(Errno::ENOENT)
+ -> { Dir.send(@method, 'xgwhwhsjai2222jg') }.should.raise(Errno::ENOENT)
end
it "can be escaped from with ../" do
diff --git a/spec/ruby/core/dir/shared/closed.rb b/spec/ruby/core/dir/shared/closed.rb
index 17d8332c2a..c868fd6e6d 100644
--- a/spec/ruby/core/dir/shared/closed.rb
+++ b/spec/ruby/core/dir/shared/closed.rb
@@ -4,6 +4,6 @@ describe :dir_closed, shared: true do
dir = Dir.open DirSpecs.mock_dir
dir.close
dir.send(@method) {}
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/dir/shared/delete.rb b/spec/ruby/core/dir/shared/delete.rb
index 49e88360e8..ba013e8615 100644
--- a/spec/ruby/core/dir/shared/delete.rb
+++ b/spec/ruby/core/dir/shared/delete.rb
@@ -17,26 +17,16 @@ describe :dir_delete, shared: true do
Dir.send(@method, p)
end
- platform_is_not :solaris do
- it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do
- -> do
- Dir.send @method, DirSpecs.mock_rmdir("nonempty")
- end.should raise_error(Errno::ENOTEMPTY)
- end
- end
-
- platform_is :solaris do
- it "raises an Errno::EEXIST when trying to remove a nonempty directory" do
- -> do
- Dir.send @method, DirSpecs.mock_rmdir("nonempty")
- end.should raise_error(Errno::EEXIST)
- end
+ it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do
+ -> do
+ Dir.send @method, DirSpecs.mock_rmdir("nonempty")
+ end.should.raise(Errno::ENOTEMPTY)
end
it "raises an Errno::ENOENT when trying to remove a non-existing directory" do
-> do
Dir.send @method, DirSpecs.nonexistent
- end.should raise_error(Errno::ENOENT)
+ end.should.raise(Errno::ENOENT)
end
it "raises an Errno::ENOTDIR when trying to remove a non-directory" do
@@ -44,7 +34,7 @@ describe :dir_delete, shared: true do
touch(file)
-> do
Dir.send @method, file
- end.should raise_error(Errno::ENOTDIR)
+ end.should.raise(Errno::ENOTDIR)
end
# this won't work on Windows, since chmod(0000) does not remove all permissions
@@ -56,7 +46,7 @@ describe :dir_delete, shared: true do
File.chmod(0000, parent)
-> do
Dir.send @method, child
- end.should raise_error(Errno::EACCES)
+ end.should.raise(Errno::EACCES)
end
end
end
diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb
deleted file mode 100644
index 3097f57715..0000000000
--- a/spec/ruby/core/dir/shared/exist.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-describe :dir_exist, shared: true do
- it "returns true if the given directory exists" do
- Dir.send(@method, __dir__).should be_true
- end
-
- it "returns true for '.'" do
- Dir.send(@method, '.').should be_true
- end
-
- it "returns true for '..'" do
- Dir.send(@method, '..').should be_true
- end
-
- it "understands non-ASCII paths" do
- subdir = File.join(tmp("\u{9876}\u{665}"))
- Dir.send(@method, subdir).should be_false
- Dir.mkdir(subdir)
- Dir.send(@method, subdir).should be_true
- Dir.rmdir(subdir)
- end
-
- it "understands relative paths" do
- Dir.send(@method, __dir__ + '/../').should be_true
- end
-
- it "returns false if the given directory doesn't exist" do
- Dir.send(@method, 'y26dg27n2nwjs8a/').should be_false
- end
-
- it "doesn't require the name to have a trailing slash" do
- dir = __dir__
- dir.sub!(/\/$/,'')
- Dir.send(@method, dir).should be_true
- end
-
- it "doesn't expand paths" do
- skip "$HOME not valid directory" unless ENV['HOME'] && File.directory?(ENV['HOME'])
- Dir.send(@method, File.expand_path('~')).should be_true
- Dir.send(@method, '~').should be_false
- end
-
- it "returns false if the argument exists but is a file" do
- File.should.exist?(__FILE__)
- Dir.send(@method, __FILE__).should be_false
- end
-
- it "doesn't set $! when file doesn't exist" do
- Dir.send(@method, "/path/to/non/existent/dir")
- $!.should be_nil
- end
-
- it "calls #to_path on non String arguments" do
- p = mock('path')
- p.should_receive(:to_path).and_return(__dir__)
- Dir.send(@method, p)
- end
-end
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index b1fc924f08..86aa105259 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -13,7 +13,7 @@ describe :dir_glob, shared: true do
it "raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII" do
pattern = "files*".dup.force_encoding Encoding::UTF_16BE
- -> { Dir.send(@method, pattern) }.should raise_error(Encoding::CompatibilityError)
+ -> { Dir.send(@method, pattern) }.should.raise(Encoding::CompatibilityError)
end
it "calls #to_path to convert a pattern" do
@@ -24,7 +24,7 @@ describe :dir_glob, shared: true do
end
it "raises an ArgumentError if the string contains \\0" do
- -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/
+ -> {Dir.send(@method, "file_o*\0file_t*")}.should.raise ArgumentError, /nul-separated/
end
it "result is sorted by default" do
@@ -43,9 +43,9 @@ describe :dir_glob, shared: true do
end
it "raises an ArgumentError if sort: is not true or false" do
- -> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
- -> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
- -> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: 0) }.should.raise ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: nil) }.should.raise ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: 'false') }.should.raise ArgumentError, /expected true or false/
end
it "matches non-dotfiles with '*'" do
@@ -373,7 +373,7 @@ describe :dir_glob, shared: true do
it "raises TypeError when cannot convert value to string" do
-> {
Dir.send(@method, "*", base: [])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "handles '' as current directory path" do
diff --git a/spec/ruby/core/dir/shared/open.rb b/spec/ruby/core/dir/shared/open.rb
deleted file mode 100644
index 920845cba1..0000000000
--- a/spec/ruby/core/dir/shared/open.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-describe :dir_open, shared: true do
- it "returns a Dir instance representing the specified directory" do
- dir = Dir.send(@method, DirSpecs.mock_dir)
- dir.should be_kind_of(Dir)
- dir.close
- end
-
- it "raises a SystemCallError if the directory does not exist" do
- -> do
- Dir.send @method, DirSpecs.nonexistent
- end.should raise_error(SystemCallError)
- end
-
- it "may take a block which is yielded to with the Dir instance" do
- Dir.send(@method, DirSpecs.mock_dir) {|dir| dir.should be_kind_of(Dir)}
- end
-
- it "returns the value of the block if a block is given" do
- Dir.send(@method, DirSpecs.mock_dir) {|dir| :value }.should == :value
- end
-
- it "closes the Dir instance when the block exits if given a block" do
- closed_dir = Dir.send(@method, DirSpecs.mock_dir) { |dir| dir }
- -> { closed_dir.read }.should raise_error(IOError)
- end
-
- it "closes the Dir instance when the block exits the block even due to an exception" do
- closed_dir = nil
-
- -> do
- Dir.send(@method, DirSpecs.mock_dir) do |dir|
- closed_dir = dir
- raise "dir specs"
- end
- end.should raise_error(RuntimeError, "dir specs")
-
- -> { closed_dir.read }.should raise_error(IOError)
- end
-
- it "calls #to_path on non-String arguments" do
- p = mock('path')
- p.should_receive(:to_path).and_return(DirSpecs.mock_dir)
- Dir.send(@method, p) { true }
- end
-
- it "accepts an options Hash" do
- dir = Dir.send(@method, DirSpecs.mock_dir, encoding: "utf-8") {|d| d }
- dir.should be_kind_of(Dir)
- end
-
- it "calls #to_hash to convert the options object" do
- options = mock("dir_open")
- options.should_receive(:to_hash).and_return({ encoding: Encoding::UTF_8 })
-
- dir = Dir.send(@method, DirSpecs.mock_dir, **options) {|d| d }
- dir.should be_kind_of(Dir)
- end
-
- it "ignores the :encoding option if it is nil" do
- dir = Dir.send(@method, DirSpecs.mock_dir, encoding: nil) {|d| d }
- dir.should be_kind_of(Dir)
- end
-
- platform_is_not :windows do
- it 'sets the close-on-exec flag for the directory file descriptor' do
- Dir.send(@method, DirSpecs.mock_dir) do |dir|
- io = IO.for_fd(dir.fileno)
- io.autoclose = false
- io.should.close_on_exec?
- end
- end
- end
-end
diff --git a/spec/ruby/core/dir/shared/path.rb b/spec/ruby/core/dir/shared/path.rb
deleted file mode 100644
index 494dcca775..0000000000
--- a/spec/ruby/core/dir/shared/path.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/common'
-require_relative 'closed'
-
-describe :dir_path, shared: true do
- it "returns the path that was supplied to .new or .open" do
- dir = Dir.open DirSpecs.mock_dir
- begin
- dir.send(@method).should == DirSpecs.mock_dir
- ensure
- dir.close rescue nil
- end
- end
-
- it "returns the path even when called on a closed Dir instance" do
- dir = Dir.open DirSpecs.mock_dir
- dir.close
- dir.send(@method).should == DirSpecs.mock_dir
- end
-
- it "returns a String with the same encoding as the argument to .open" do
- path = DirSpecs.mock_dir.force_encoding Encoding::IBM866
- dir = Dir.open path
- begin
- dir.send(@method).encoding.should equal(Encoding::IBM866)
- ensure
- dir.close
- end
- end
-end
diff --git a/spec/ruby/core/dir/shared/pos.rb b/spec/ruby/core/dir/shared/pos.rb
index 2165932d99..741de8918c 100644
--- a/spec/ruby/core/dir/shared/pos.rb
+++ b/spec/ruby/core/dir/shared/pos.rb
@@ -1,30 +1,3 @@
-describe :dir_pos, shared: true do
- before :each do
- @dir = Dir.open DirSpecs.mock_dir
- end
-
- after :each do
- @dir.close rescue nil
- end
-
- it "returns an Integer representing the current position in the directory" do
- @dir.send(@method).should be_kind_of(Integer)
- @dir.send(@method).should be_kind_of(Integer)
- @dir.send(@method).should be_kind_of(Integer)
- end
-
- it "returns a different Integer if moved from previous position" do
- a = @dir.send(@method)
- @dir.read
- b = @dir.send(@method)
-
- a.should be_kind_of(Integer)
- b.should be_kind_of(Integer)
-
- a.should_not == b
- end
-end
-
describe :dir_pos_set, shared: true do
before :each do
@dir = Dir.open DirSpecs.mock_dir
diff --git a/spec/ruby/core/dir/shared/pwd.rb b/spec/ruby/core/dir/shared/pwd.rb
deleted file mode 100644
index 2a8d7fe790..0000000000
--- a/spec/ruby/core/dir/shared/pwd.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-describe :dir_pwd, shared: true do
- before :each do
- @fs_encoding = Encoding.find('filesystem')
- end
-
- it "returns the current working directory" do
- pwd = Dir.send(@method)
-
- File.directory?(pwd).should == true
-
- # On ubuntu gutsy, for example, /bin/pwd does not
- # understand -P. With just `pwd -P`, /bin/pwd is run.
-
- # The following uses inode rather than file names to account for
- # case insensitive file systems like default OS/X file systems
- platform_is_not :windows do
- File.stat(pwd).ino.should == File.stat(`/bin/sh -c "pwd -P"`.chomp).ino
- end
- platform_is :windows do
- File.stat(pwd).ino.should == File.stat(File.expand_path(`cd`.chomp)).ino
- end
- end
-
- it "returns an absolute path" do
- pwd = Dir.send(@method)
- pwd.should == File.expand_path(pwd)
- end
-
- it "returns an absolute path even when chdir to a relative path" do
- Dir.chdir(".") do
- pwd = Dir.send(@method)
- File.directory?(pwd).should == true
- pwd.should == File.expand_path(pwd)
- end
- end
-
- it "returns a String with the filesystem encoding" do
- enc = Dir.send(@method).encoding
- if @fs_encoding == Encoding::US_ASCII
- [Encoding::US_ASCII, Encoding::BINARY].should include(enc)
- else
- enc.should equal(@fs_encoding)
- end
- end
-end
diff --git a/spec/ruby/core/dir/tell_spec.rb b/spec/ruby/core/dir/tell_spec.rb
index af86dc1598..dcbb40438f 100644
--- a/spec/ruby/core/dir/tell_spec.rb
+++ b/spec/ruby/core/dir/tell_spec.rb
@@ -12,7 +12,30 @@ describe "Dir#tell" do
DirSpecs.delete_mock_dirs
end
- it_behaves_like :dir_pos, :tell
-
it_behaves_like :dir_closed, :tell
+
+ before :each do
+ @dir = Dir.open DirSpecs.mock_dir
+ end
+
+ after :each do
+ @dir.close rescue nil
+ end
+
+ it "returns an Integer representing the current position in the directory" do
+ @dir.tell.should.is_a?(Integer)
+ @dir.tell.should.is_a?(Integer)
+ @dir.tell.should.is_a?(Integer)
+ end
+
+ it "returns a different Integer if moved from previous position" do
+ a = @dir.tell
+ @dir.read
+ b = @dir.tell
+
+ a.should.is_a?(Integer)
+ b.should.is_a?(Integer)
+
+ a.should_not == b
+ end
end
diff --git a/spec/ruby/core/dir/to_path_spec.rb b/spec/ruby/core/dir/to_path_spec.rb
index 77404a3dc8..2ed533e757 100644
--- a/spec/ruby/core/dir/to_path_spec.rb
+++ b/spec/ruby/core/dir/to_path_spec.rb
@@ -1,15 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-require_relative 'shared/path'
describe "Dir#to_path" do
- before :all do
- DirSpecs.create_mock_dirs
+ it "is an alias of Dir#path" do
+ Dir.instance_method(:to_path).should == Dir.instance_method(:path)
end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- it_behaves_like :dir_path, :to_path
end
diff --git a/spec/ruby/core/encoding/aliases_spec.rb b/spec/ruby/core/encoding/aliases_spec.rb
index 786157981a..12c6c6cf85 100644
--- a/spec/ruby/core/encoding/aliases_spec.rb
+++ b/spec/ruby/core/encoding/aliases_spec.rb
@@ -2,24 +2,24 @@ require_relative '../../spec_helper'
describe "Encoding.aliases" do
it "returns a Hash" do
- Encoding.aliases.should be_an_instance_of(Hash)
+ Encoding.aliases.should.instance_of?(Hash)
end
it "has Strings as keys" do
Encoding.aliases.keys.each do |key|
- key.should be_an_instance_of(String)
+ key.should.instance_of?(String)
end
end
it "has Strings as values" do
Encoding.aliases.values.each do |value|
- value.should be_an_instance_of(String)
+ value.should.instance_of?(String)
end
end
it "has alias names as its keys" do
- Encoding.aliases.key?('BINARY').should be_true
- Encoding.aliases.key?('ASCII').should be_true
+ Encoding.aliases.key?('BINARY').should == true
+ Encoding.aliases.key?('ASCII').should == true
end
it "has the names of the aliased encoding as its values" do
diff --git a/spec/ruby/core/encoding/ascii_compatible_spec.rb b/spec/ruby/core/encoding/ascii_compatible_spec.rb
index 4804300e85..04fc159bb8 100644
--- a/spec/ruby/core/encoding/ascii_compatible_spec.rb
+++ b/spec/ruby/core/encoding/ascii_compatible_spec.rb
@@ -2,10 +2,21 @@ require_relative '../../spec_helper'
describe "Encoding#ascii_compatible?" do
it "returns true if self represents an ASCII-compatible encoding" do
- Encoding::UTF_8.ascii_compatible?.should be_true
+ Encoding::UTF_8.ascii_compatible?.should == true
end
it "returns false if self does not represent an ASCII-compatible encoding" do
- Encoding::UTF_16LE.ascii_compatible?.should be_false
+ Encoding::UTF_16LE.ascii_compatible?.should == false
+ end
+
+ it "returns false for UTF_16 and UTF_32" do
+ Encoding::UTF_16.should_not.ascii_compatible?
+ Encoding::UTF_32.should_not.ascii_compatible?
+ end
+
+ it "is always false for dummy encodings" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ encoding.should_not.ascii_compatible?
+ end
end
end
diff --git a/spec/ruby/core/encoding/compatible_spec.rb b/spec/ruby/core/encoding/compatible_spec.rb
index 61a651893b..0d620e5bf3 100644
--- a/spec/ruby/core/encoding/compatible_spec.rb
+++ b/spec/ruby/core/encoding/compatible_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
@@ -55,7 +55,7 @@ describe "Encoding.compatible? String, String" do
it "returns nil if the second's Encoding is not ASCII compatible" do
a = "abc".dup.force_encoding("UTF-8")
b = "1234".dup.force_encoding("UTF-16LE")
- Encoding.compatible?(a, b).should be_nil
+ Encoding.compatible?(a, b).should == nil
end
end
@@ -69,7 +69,7 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil if the second encoding is ASCII compatible but neither String's encoding is ASCII only" do
- Encoding.compatible?("\xff", "\u3042".encode("utf-8")).should be_nil
+ Encoding.compatible?("\xff", "\u3042".encode("utf-8")).should == nil
end
end
@@ -79,15 +79,15 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil when the second String is US-ASCII" do
- Encoding.compatible?(@str, "def".encode("us-ascii")).should be_nil
+ Encoding.compatible?(@str, "def".encode("us-ascii")).should == nil
end
it "returns nil when the second String is BINARY and ASCII only" do
- Encoding.compatible?(@str, "\x7f").should be_nil
+ Encoding.compatible?(@str, "\x7f").should == nil
end
it "returns nil when the second String is BINARY but not ASCII only" do
- Encoding.compatible?(@str, "\xff").should be_nil
+ Encoding.compatible?(@str, "\xff").should == nil
end
it "returns the Encoding when the second's Encoding is not ASCII compatible but the same as the first's Encoding" do
@@ -110,15 +110,15 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil when the second's Encoding is BINARY but not ASCII only" do
- Encoding.compatible?(@str, "\xff").should be_nil
+ Encoding.compatible?(@str, "\xff").should == nil
end
it "returns nil when the second's Encoding is invalid and ASCII only" do
- Encoding.compatible?(@str, "\x7f\x7f".dup.force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\x7f\x7f".dup.force_encoding("utf-16be")).should == nil
end
it "returns nil when the second's Encoding is invalid and not ASCII only" do
- Encoding.compatible?(@str, "\xff\xff".dup.force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\xff\xff".dup.force_encoding("utf-16be")).should == nil
end
it "returns the Encoding when the second's Encoding is invalid but the same as the first" do
@@ -171,7 +171,7 @@ describe "Encoding.compatible? String, String" do
# Use the following script to regenerate the matrix:
#
# ```
-# # -*- encoding: binary -*-
+# # encoding: binary
#
# ENCODINGS = [
# "US-ASCII",
@@ -557,6 +557,11 @@ describe "Encoding.compatible? String, Regexp" do
[Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
+
+ it "returns the Regexp's Encoding if the String is ASCII only and the Regexp is not" do
+ r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ Encoding.compatible?("hello".dup.force_encoding("utf-8"), r).should == Encoding::EUC_JP
+ end
end
describe "Encoding.compatible? String, Symbol" do
@@ -584,11 +589,11 @@ end
describe "Encoding.compatible? String, Encoding" do
it "returns nil if the String's encoding is not ASCII compatible" do
- Encoding.compatible?("abc".encode("utf-32le"), Encoding::US_ASCII).should be_nil
+ Encoding.compatible?("abc".encode("utf-32le"), Encoding::US_ASCII).should == nil
end
it "returns nil if the Encoding is not ASCII compatible" do
- Encoding.compatible?("abc".encode("us-ascii"), Encoding::UTF_32LE).should be_nil
+ Encoding.compatible?("abc".encode("us-ascii"), Encoding::UTF_32LE).should == nil
end
it "returns the String's encoding if the Encoding is US-ASCII" do
@@ -609,7 +614,7 @@ describe "Encoding.compatible? String, Encoding" do
end
it "returns nil if the String's encoding is ASCII compatible but the string is not ASCII only" do
- Encoding.compatible?("\u3042".encode("utf-8"), Encoding::BINARY).should be_nil
+ Encoding.compatible?("\u3042".encode("utf-8"), Encoding::BINARY).should == nil
end
end
@@ -619,6 +624,15 @@ describe "Encoding.compatible? Regexp, String" do
Encoding.compatible?(/abc/, str).should == Encoding::US_ASCII
end
+ it "returns the String's Encoding when the String is ASCII only with a different encoding" do
+ r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ Encoding.compatible?(r, "hello".dup.force_encoding("utf-8")).should == Encoding::UTF_8
+ end
+
+ it "returns the Regexp's Encoding if the String has the same non-ASCII encoding" do
+ r = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ Encoding.compatible?(r, "hello".dup.force_encoding("euc-jp")).should == Encoding::EUC_JP
+ end
end
describe "Encoding.compatible? Regexp, Regexp" do
@@ -727,32 +741,32 @@ end
describe "Encoding.compatible? Object, Object" do
it "returns nil for Object, String" do
- Encoding.compatible?(Object.new, "abc").should be_nil
+ Encoding.compatible?(Object.new, "abc").should == nil
end
it "returns nil for Object, Regexp" do
- Encoding.compatible?(Object.new, /./).should be_nil
+ Encoding.compatible?(Object.new, /./).should == nil
end
it "returns nil for Object, Symbol" do
- Encoding.compatible?(Object.new, :sym).should be_nil
+ Encoding.compatible?(Object.new, :sym).should == nil
end
it "returns nil for String, Object" do
- Encoding.compatible?("abc", Object.new).should be_nil
+ Encoding.compatible?("abc", Object.new).should == nil
end
it "returns nil for Regexp, Object" do
- Encoding.compatible?(/./, Object.new).should be_nil
+ Encoding.compatible?(/./, Object.new).should == nil
end
it "returns nil for Symbol, Object" do
- Encoding.compatible?(:sym, Object.new).should be_nil
+ Encoding.compatible?(:sym, Object.new).should == nil
end
end
describe "Encoding.compatible? nil, nil" do
it "returns nil" do
- Encoding.compatible?(nil, nil).should be_nil
+ Encoding.compatible?(nil, nil).should == nil
end
end
diff --git a/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb b/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb
index 1beb40af3f..07c7a88356 100644
--- a/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb
+++ b/spec/ruby/core/encoding/converter/asciicompat_encoding_spec.rb
@@ -24,14 +24,14 @@ describe "Encoding::Converter.asciicompat_encoding" do
end
it "returns nil when the given encoding is ASCII compatible" do
- Encoding::Converter.asciicompat_encoding('ASCII').should be_nil
- Encoding::Converter.asciicompat_encoding('UTF-8').should be_nil
+ Encoding::Converter.asciicompat_encoding('ASCII').should == nil
+ Encoding::Converter.asciicompat_encoding('UTF-8').should == nil
end
it "handles encoding names who resolve to nil encodings" do
internal = Encoding.default_internal
Encoding.default_internal = nil
- Encoding::Converter.asciicompat_encoding('internal').should be_nil
+ Encoding::Converter.asciicompat_encoding('internal').should == nil
Encoding.default_internal = internal
end
end
diff --git a/spec/ruby/core/encoding/converter/constants_spec.rb b/spec/ruby/core/encoding/converter/constants_spec.rb
index 7d29bdb278..e2d21b5429 100644
--- a/spec/ruby/core/encoding/converter/constants_spec.rb
+++ b/spec/ruby/core/encoding/converter/constants_spec.rb
@@ -2,130 +2,130 @@ require_relative '../../../spec_helper'
describe "Encoding::Converter::INVALID_MASK" do
it "exists" do
- Encoding::Converter.should have_constant(:INVALID_MASK)
+ Encoding::Converter.should.const_defined?(:INVALID_MASK, false)
end
it "has an Integer value" do
- Encoding::Converter::INVALID_MASK.should be_an_instance_of(Integer)
+ Encoding::Converter::INVALID_MASK.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::INVALID_REPLACE" do
it "exists" do
- Encoding::Converter.should have_constant(:INVALID_REPLACE)
+ Encoding::Converter.should.const_defined?(:INVALID_REPLACE, false)
end
it "has an Integer value" do
- Encoding::Converter::INVALID_REPLACE.should be_an_instance_of(Integer)
+ Encoding::Converter::INVALID_REPLACE.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNDEF_MASK" do
it "exists" do
- Encoding::Converter.should have_constant(:UNDEF_MASK)
+ Encoding::Converter.should.const_defined?(:UNDEF_MASK, false)
end
it "has an Integer value" do
- Encoding::Converter::UNDEF_MASK.should be_an_instance_of(Integer)
+ Encoding::Converter::UNDEF_MASK.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNDEF_REPLACE" do
it "exists" do
- Encoding::Converter.should have_constant(:UNDEF_REPLACE)
+ Encoding::Converter.should.const_defined?(:UNDEF_REPLACE, false)
end
it "has an Integer value" do
- Encoding::Converter::UNDEF_REPLACE.should be_an_instance_of(Integer)
+ Encoding::Converter::UNDEF_REPLACE.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNDEF_HEX_CHARREF" do
it "exists" do
- Encoding::Converter.should have_constant(:UNDEF_HEX_CHARREF)
+ Encoding::Converter.should.const_defined?(:UNDEF_HEX_CHARREF, false)
end
it "has an Integer value" do
- Encoding::Converter::UNDEF_HEX_CHARREF.should be_an_instance_of(Integer)
+ Encoding::Converter::UNDEF_HEX_CHARREF.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::PARTIAL_INPUT" do
it "exists" do
- Encoding::Converter.should have_constant(:PARTIAL_INPUT)
+ Encoding::Converter.should.const_defined?(:PARTIAL_INPUT, false)
end
it "has an Integer value" do
- Encoding::Converter::PARTIAL_INPUT.should be_an_instance_of(Integer)
+ Encoding::Converter::PARTIAL_INPUT.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::AFTER_OUTPUT" do
it "exists" do
- Encoding::Converter.should have_constant(:AFTER_OUTPUT)
+ Encoding::Converter.should.const_defined?(:AFTER_OUTPUT, false)
end
it "has an Integer value" do
- Encoding::Converter::AFTER_OUTPUT.should be_an_instance_of(Integer)
+ Encoding::Converter::AFTER_OUTPUT.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:UNIVERSAL_NEWLINE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:UNIVERSAL_NEWLINE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::CRLF_NEWLINE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:CRLF_NEWLINE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:CRLF_NEWLINE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::CRLF_NEWLINE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::CRLF_NEWLINE_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::CR_NEWLINE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:CR_NEWLINE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:CR_NEWLINE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::CR_NEWLINE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::CR_NEWLINE_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::XML_TEXT_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:XML_TEXT_DECORATOR)
+ Encoding::Converter.should.const_defined?(:XML_TEXT_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::XML_TEXT_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::XML_TEXT_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::XML_ATTR_CONTENT_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:XML_ATTR_CONTENT_DECORATOR)
+ Encoding::Converter.should.const_defined?(:XML_ATTR_CONTENT_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::XML_ATTR_CONTENT_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::XML_ATTR_CONTENT_DECORATOR.should.instance_of?(Integer)
end
end
describe "Encoding::Converter::XML_ATTR_QUOTE_DECORATOR" do
it "exists" do
- Encoding::Converter.should have_constant(:XML_ATTR_QUOTE_DECORATOR)
+ Encoding::Converter.should.const_defined?(:XML_ATTR_QUOTE_DECORATOR, false)
end
it "has an Integer value" do
- Encoding::Converter::XML_ATTR_QUOTE_DECORATOR.should be_an_instance_of(Integer)
+ Encoding::Converter::XML_ATTR_QUOTE_DECORATOR.should.instance_of?(Integer)
end
end
diff --git a/spec/ruby/core/encoding/converter/convert_spec.rb b/spec/ruby/core/encoding/converter/convert_spec.rb
index 7f249d90a3..c95e88a491 100644
--- a/spec/ruby/core/encoding/converter/convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/convert_spec.rb
@@ -1,11 +1,11 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: true
require_relative '../../../spec_helper'
describe "Encoding::Converter#convert" do
it "returns a String" do
ec = Encoding::Converter.new('ascii', 'utf-8')
- ec.convert('glark').should be_an_instance_of(String)
+ ec.convert('glark').should.instance_of?(String)
end
it "sets the encoding of the result to the target encoding" do
@@ -34,13 +34,12 @@ describe "Encoding::Converter#convert" do
it "raises UndefinedConversionError if the String contains characters invalid for the target encoding" do
ec = Encoding::Converter.new('UTF-8', Encoding.find('macCyrillic'))
- -> { ec.convert("\u{6543}".dup.force_encoding('UTF-8')) }.should \
- raise_error(Encoding::UndefinedConversionError)
+ -> { ec.convert("\u{6543}".dup.force_encoding('UTF-8')) }.should.raise(Encoding::UndefinedConversionError)
end
it "raises an ArgumentError if called on a finished stream" do
ec = Encoding::Converter.new('UTF-8', Encoding.find('macCyrillic'))
ec.finish
- -> { ec.convert("\u{65}") }.should raise_error(ArgumentError)
+ -> { ec.convert("\u{65}") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/encoding/converter/finish_spec.rb b/spec/ruby/core/encoding/converter/finish_spec.rb
index 22e66df38c..e13b7415f8 100644
--- a/spec/ruby/core/encoding/converter/finish_spec.rb
+++ b/spec/ruby/core/encoding/converter/finish_spec.rb
@@ -7,7 +7,7 @@ describe "Encoding::Converter#finish" do
it "returns a String" do
@ec.convert('foo')
- @ec.finish.should be_an_instance_of(String)
+ @ec.finish.should.instance_of?(String)
end
it "returns an empty String if there is nothing more to convert" do
diff --git a/spec/ruby/core/encoding/converter/last_error_spec.rb b/spec/ruby/core/encoding/converter/last_error_spec.rb
index 78779be70b..3984a628f5 100644
--- a/spec/ruby/core/encoding/converter/last_error_spec.rb
+++ b/spec/ruby/core/encoding/converter/last_error_spec.rb
@@ -1,54 +1,54 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::Converter#last_error" do
it "returns nil when the no conversion has been attempted" do
ec = Encoding::Converter.new('ascii','utf-8')
- ec.last_error.should be_nil
+ ec.last_error.should == nil
end
it "returns nil when the last conversion did not produce an error" do
ec = Encoding::Converter.new('ascii','utf-8')
ec.convert('a'.dup.force_encoding('ascii'))
- ec.last_error.should be_nil
+ ec.last_error.should == nil
end
it "returns nil when #primitive_convert last returned :destination_buffer_full" do
ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
ec.primitive_convert(+"\u{9999}", +"", 0, 0, partial_input: false) \
.should == :destination_buffer_full
- ec.last_error.should be_nil
+ ec.last_error.should == nil
end
it "returns nil when #primitive_convert last returned :finished" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
ec.primitive_convert("glark".dup.force_encoding('utf-8'), +"").should == :finished
- ec.last_error.should be_nil
+ ec.last_error.should == nil
end
it "returns nil if the last conversion succeeded but the penultimate failed" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
ec.primitive_convert(+"\xf1abcd", +"").should == :invalid_byte_sequence
ec.primitive_convert("glark".dup.force_encoding('utf-8'), +"").should == :finished
- ec.last_error.should be_nil
+ ec.last_error.should == nil
end
it "returns an Encoding::InvalidByteSequenceError when #primitive_convert last returned :invalid_byte_sequence" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
ec.primitive_convert(+"\xf1abcd", +"").should == :invalid_byte_sequence
- ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
+ ec.last_error.should.instance_of?(Encoding::InvalidByteSequenceError)
end
it "returns an Encoding::UndefinedConversionError when #primitive_convert last returned :undefined_conversion" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
ec.primitive_convert(+"\u{9876}", +"").should == :undefined_conversion
- ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
+ ec.last_error.should.instance_of?(Encoding::UndefinedConversionError)
end
it "returns an Encoding::InvalidByteSequenceError when #primitive_convert last returned :incomplete_input" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
ec.primitive_convert(+"\xa4", +"", nil, 10).should == :incomplete_input
- ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
+ ec.last_error.should.instance_of?(Encoding::InvalidByteSequenceError)
end
it "returns an Encoding::InvalidByteSequenceError when the last call to #convert produced one" do
@@ -56,10 +56,10 @@ describe "Encoding::Converter#last_error" do
exception = nil
-> {
ec.convert("\xf1abcd")
- }.should raise_error(Encoding::InvalidByteSequenceError) { |e|
+ }.should.raise(Encoding::InvalidByteSequenceError) { |e|
exception = e
}
- ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
+ ec.last_error.should.instance_of?(Encoding::InvalidByteSequenceError)
ec.last_error.message.should == exception.message
end
@@ -68,12 +68,12 @@ describe "Encoding::Converter#last_error" do
exception = nil
-> {
ec.convert("\u{9899}")
- }.should raise_error(Encoding::UndefinedConversionError) { |e|
+ }.should.raise(Encoding::UndefinedConversionError) { |e|
exception = e
}
- ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
+ ec.last_error.should.instance_of?(Encoding::UndefinedConversionError)
ec.last_error.message.should == exception.message
- ec.last_error.message.should include "from UTF-8 to ISO-8859-1"
+ ec.last_error.message.should.include? "from UTF-8 to ISO-8859-1"
end
it "returns the last error of #convert with a message showing the transcoding path" do
@@ -81,11 +81,11 @@ describe "Encoding::Converter#last_error" do
exception = nil
-> {
ec.convert("\xE9") # é in ISO-8859-1
- }.should raise_error(Encoding::UndefinedConversionError) { |e|
+ }.should.raise(Encoding::UndefinedConversionError) { |e|
exception = e
}
- ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
+ ec.last_error.should.instance_of?(Encoding::UndefinedConversionError)
ec.last_error.message.should == exception.message
- ec.last_error.message.should include "from ISO-8859-1 to UTF-8 to Big5"
+ ec.last_error.message.should.include? "from ISO-8859-1 to UTF-8 to Big5"
end
end
diff --git a/spec/ruby/core/encoding/converter/new_spec.rb b/spec/ruby/core/encoding/converter/new_spec.rb
index db9c3364d7..bbdfb48bce 100644
--- a/spec/ruby/core/encoding/converter/new_spec.rb
+++ b/spec/ruby/core/encoding/converter/new_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::Converter.new" do
@@ -25,7 +25,7 @@ describe "Encoding::Converter.new" do
it "raises an Encoding::ConverterNotFoundError if both encodings are the same" do
-> do
Encoding::Converter.new "utf-8", "utf-8"
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
it "calls #to_str to convert the source encoding argument to an encoding name" do
@@ -67,25 +67,25 @@ describe "Encoding::Converter.new" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: obj)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed true for the replacement object" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: true)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false for the replacement object" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer for the replacement object" do
-> do
Encoding::Converter.new("us-ascii", "utf-8", replace: 1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "accepts an empty String for the replacement object" do
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index 63f25eddef..ab9ce6a992 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: false
require_relative '../../../spec_helper'
@@ -8,23 +8,23 @@ describe "Encoding::Converter#primitive_convert" do
end
it "accepts a nil source buffer" do
- -> { @ec.primitive_convert(nil,"") }.should_not raise_error
+ -> { @ec.primitive_convert(nil,"") }.should_not.raise
end
it "accepts a String as the source buffer" do
- -> { @ec.primitive_convert("","") }.should_not raise_error
+ -> { @ec.primitive_convert("","") }.should_not.raise
end
it "raises FrozenError when the destination buffer is a frozen String" do
- -> { @ec.primitive_convert("", "".freeze) }.should raise_error(FrozenError)
+ -> { @ec.primitive_convert("", "".freeze) }.should.raise(FrozenError)
end
it "accepts nil for the destination byte offset" do
- -> { @ec.primitive_convert("","", nil) }.should_not raise_error
+ -> { @ec.primitive_convert("","", nil) }.should_not.raise
end
it "accepts an integer for the destination byte offset" do
- -> { @ec.primitive_convert("","a", 1) }.should_not raise_error
+ -> { @ec.primitive_convert("","a", 1) }.should_not.raise
end
it "calls #to_int to convert the destination byte offset" do
@@ -35,10 +35,10 @@ describe "Encoding::Converter#primitive_convert" do
end
it "raises an ArgumentError if the destination byte offset is greater than the bytesize of the destination buffer" do
- -> { @ec.primitive_convert("","am", 0) }.should_not raise_error
- -> { @ec.primitive_convert("","am", 1) }.should_not raise_error
- -> { @ec.primitive_convert("","am", 2) }.should_not raise_error
- -> { @ec.primitive_convert("","am", 3) }.should raise_error(ArgumentError)
+ -> { @ec.primitive_convert("","am", 0) }.should_not.raise
+ -> { @ec.primitive_convert("","am", 1) }.should_not.raise
+ -> { @ec.primitive_convert("","am", 2) }.should_not.raise
+ -> { @ec.primitive_convert("","am", 3) }.should.raise(ArgumentError)
end
it "uses the destination byte offset to determine where to write the result in the destination buffer" do
@@ -54,19 +54,19 @@ describe "Encoding::Converter#primitive_convert" do
end
it "accepts nil for the destination bytesize" do
- -> { @ec.primitive_convert("","", nil, nil) }.should_not raise_error
+ -> { @ec.primitive_convert("","", nil, nil) }.should_not.raise
end
it "accepts an integer for the destination bytesize" do
- -> { @ec.primitive_convert("","", nil, 0) }.should_not raise_error
+ -> { @ec.primitive_convert("","", nil, 0) }.should_not.raise
end
it "allows a destination bytesize value greater than the bytesize of the source buffer" do
- -> { @ec.primitive_convert("am","", nil, 3) }.should_not raise_error
+ -> { @ec.primitive_convert("am","", nil, 3) }.should_not.raise
end
it "allows a destination bytesize value less than the bytesize of the source buffer" do
- -> { @ec.primitive_convert("am","", nil, 1) }.should_not raise_error
+ -> { @ec.primitive_convert("am","", nil, 1) }.should_not.raise
end
it "calls #to_int to convert the destination byte size" do
diff --git a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
index 668eb9a924..580e2e37e1 100644
--- a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: false
require_relative '../../../spec_helper'
@@ -55,7 +55,7 @@ describe "Encoding::Converter#primitive_errinfo" do
it "returns the state, source encoding, target encoding, erroneous bytes, and the read-again bytes when #convert last raised InvalidByteSequenceError" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- -> { ec.convert("\xf1abcd") }.should raise_error(Encoding::InvalidByteSequenceError)
+ -> { ec.convert("\xf1abcd") }.should.raise(Encoding::InvalidByteSequenceError)
ec.primitive_errinfo.should ==
[:invalid_byte_sequence, "UTF-8", "ISO-8859-1", "\xF1", "a"]
end
@@ -63,7 +63,7 @@ describe "Encoding::Converter#primitive_errinfo" do
it "returns the state, source encoding, target encoding, erroneous bytes, and the read-again bytes when #finish last raised InvalidByteSequenceError" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
ec.convert("\xa4")
- -> { ec.finish }.should raise_error(Encoding::InvalidByteSequenceError)
+ -> { ec.finish }.should.raise(Encoding::InvalidByteSequenceError)
ec.primitive_errinfo.should == [:incomplete_input, "EUC-JP", "UTF-8", "\xA4", ""]
end
end
diff --git a/spec/ruby/core/encoding/converter/putback_spec.rb b/spec/ruby/core/encoding/converter/putback_spec.rb
index e19fe6c314..a85cec5145 100644
--- a/spec/ruby/core/encoding/converter/putback_spec.rb
+++ b/spec/ruby/core/encoding/converter/putback_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::Converter#putback" do
@@ -8,7 +8,7 @@ describe "Encoding::Converter#putback" do
end
it "returns a String" do
- @ec.putback.should be_an_instance_of(String)
+ @ec.putback.should.instance_of?(String)
end
it "returns a String in the source encoding" do
diff --git a/spec/ruby/core/encoding/converter/replacement_spec.rb b/spec/ruby/core/encoding/converter/replacement_spec.rb
index ea514ca8dd..c25ec36517 100644
--- a/spec/ruby/core/encoding/converter/replacement_spec.rb
+++ b/spec/ruby/core/encoding/converter/replacement_spec.rb
@@ -33,7 +33,7 @@ describe "Encoding::Converter#replacement=" do
it "raises a TypeError if assigned a non-String argument" do
ec = Encoding::Converter.new("utf-8", "us-ascii")
- -> { ec.replacement = nil }.should raise_error(TypeError)
+ -> { ec.replacement = nil }.should.raise(TypeError)
end
it "sets #replacement" do
@@ -47,16 +47,14 @@ describe "Encoding::Converter#replacement=" do
ec = Encoding::Converter.new("sjis", "ascii")
utf8_q = "\u{986}".dup.force_encoding('utf-8')
ec.primitive_convert(utf8_q.dup, +"").should == :undefined_conversion
- -> { ec.replacement = utf8_q }.should \
- raise_error(Encoding::UndefinedConversionError)
+ -> { ec.replacement = utf8_q }.should.raise(Encoding::UndefinedConversionError)
end
it "does not change the replacement character if the argument cannot be converted into the destination encoding" do
ec = Encoding::Converter.new("sjis", "ascii")
utf8_q = "\u{986}".dup.force_encoding('utf-8')
ec.primitive_convert(utf8_q.dup, +"").should == :undefined_conversion
- -> { ec.replacement = utf8_q }.should \
- raise_error(Encoding::UndefinedConversionError)
+ -> { ec.replacement = utf8_q }.should.raise(Encoding::UndefinedConversionError)
ec.replacement.should == "?".dup.force_encoding('us-ascii')
end
diff --git a/spec/ruby/core/encoding/converter/search_convpath_spec.rb b/spec/ruby/core/encoding/converter/search_convpath_spec.rb
index 59fe4520c0..cac44765f8 100644
--- a/spec/ruby/core/encoding/converter/search_convpath_spec.rb
+++ b/spec/ruby/core/encoding/converter/search_convpath_spec.rb
@@ -25,6 +25,6 @@ describe "Encoding::Converter.search_convpath" do
it "raises an Encoding::ConverterNotFoundError if no conversion path exists" do
-> do
Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
end
diff --git a/spec/ruby/core/encoding/default_external_spec.rb b/spec/ruby/core/encoding/default_external_spec.rb
index 9aae4976e0..2a2bd7f6ae 100644
--- a/spec/ruby/core/encoding/default_external_spec.rb
+++ b/spec/ruby/core/encoding/default_external_spec.rb
@@ -10,7 +10,7 @@ describe "Encoding.default_external" do
end
it "returns an Encoding object" do
- Encoding.default_external.should be_an_instance_of(Encoding)
+ Encoding.default_external.should.instance_of?(Encoding)
end
it "returns the default external encoding" do
@@ -60,10 +60,10 @@ describe "Encoding.default_external=" do
end
it "raises a TypeError unless the argument is an Encoding or convertible to a String" do
- -> { Encoding.default_external = [] }.should raise_error(TypeError)
+ -> { Encoding.default_external = [] }.should.raise(TypeError)
end
it "raises an ArgumentError if the argument is nil" do
- -> { Encoding.default_external = nil }.should raise_error(ArgumentError)
+ -> { Encoding.default_external = nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/encoding/default_internal_spec.rb b/spec/ruby/core/encoding/default_internal_spec.rb
index 855f4e9f32..38aef9dce9 100644
--- a/spec/ruby/core/encoding/default_internal_spec.rb
+++ b/spec/ruby/core/encoding/default_internal_spec.rb
@@ -10,17 +10,17 @@ describe "Encoding.default_internal" do
end
it "is nil by default" do
- Encoding.default_internal.should be_nil
+ Encoding.default_internal.should == nil
end
it "returns an Encoding object if a default internal encoding is set" do
Encoding.default_internal = Encoding::ASCII
- Encoding.default_internal.should be_an_instance_of(Encoding)
+ Encoding.default_internal.should.instance_of?(Encoding)
end
it "returns nil if no default internal encoding is set" do
Encoding.default_internal = nil
- Encoding.default_internal.should be_nil
+ Encoding.default_internal.should == nil
end
it "returns the default internal encoding" do
@@ -60,15 +60,15 @@ describe "Encoding.default_internal=" do
obj = mock('string')
obj.should_receive(:to_str).at_least(1).times.and_return(1)
- -> { Encoding.default_internal = obj }.should raise_error(TypeError)
+ -> { Encoding.default_internal = obj }.should.raise(TypeError)
end
it "raises a TypeError when passed an object not providing #to_str" do
- -> { Encoding.default_internal = mock("encoding") }.should raise_error(TypeError)
+ -> { Encoding.default_internal = mock("encoding") }.should.raise(TypeError)
end
it "accepts an argument of nil to unset the default internal encoding" do
Encoding.default_internal = nil
- Encoding.default_internal.should be_nil
+ Encoding.default_internal.should == nil
end
end
diff --git a/spec/ruby/core/encoding/dummy_spec.rb b/spec/ruby/core/encoding/dummy_spec.rb
index 75ffcd5a4e..05530a8186 100644
--- a/spec/ruby/core/encoding/dummy_spec.rb
+++ b/spec/ruby/core/encoding/dummy_spec.rb
@@ -2,13 +2,24 @@ require_relative '../../spec_helper'
describe "Encoding#dummy?" do
it "returns false for proper encodings" do
- Encoding::UTF_8.dummy?.should be_false
- Encoding::ASCII.dummy?.should be_false
+ Encoding::UTF_8.dummy?.should == false
+ Encoding::ASCII.dummy?.should == false
end
it "returns true for dummy encodings" do
- Encoding::ISO_2022_JP.dummy?.should be_true
- Encoding::CP50221.dummy?.should be_true
- Encoding::UTF_7.dummy?.should be_true
+ Encoding::ISO_2022_JP.dummy?.should == true
+ Encoding::CP50221.dummy?.should == true
+ Encoding::UTF_7.dummy?.should == true
+ end
+
+ it "returns true for UTF_16 and UTF_32" do
+ Encoding::UTF_16.should.dummy?
+ Encoding::UTF_32.should.dummy?
+ end
+
+ it "implies not #ascii_compatible?" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ encoding.should_not.ascii_compatible?
+ end
end
end
diff --git a/spec/ruby/core/encoding/find_spec.rb b/spec/ruby/core/encoding/find_spec.rb
index 8a0873070f..c5356560eb 100644
--- a/spec/ruby/core/encoding/find_spec.rb
+++ b/spec/ruby/core/encoding/find_spec.rb
@@ -7,18 +7,18 @@ describe "Encoding.find" do
it "returns the corresponding Encoding object if given a valid encoding name" do
@encodings.each do |enc|
- Encoding.find(enc).should be_an_instance_of(Encoding)
+ Encoding.find(enc).should.instance_of?(Encoding)
end
end
it "returns the corresponding Encoding object if given a valid alias name" do
Encoding.aliases.keys.each do |enc_alias|
- Encoding.find(enc_alias).should be_an_instance_of(Encoding)
+ Encoding.find(enc_alias).should.instance_of?(Encoding)
end
end
it "raises a TypeError if passed a Symbol" do
- -> { Encoding.find(:"utf-8") }.should raise_error(TypeError)
+ -> { Encoding.find(:"utf-8") }.should.raise(TypeError)
end
it "returns the passed Encoding object" do
@@ -50,7 +50,7 @@ describe "Encoding.find" do
end
it "raises an ArgumentError if the given encoding does not exist" do
- -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError)
+ -> { Encoding.find('dh2dh278d') }.should.raise(ArgumentError, 'unknown encoding name - dh2dh278d')
end
# Not sure how to do a better test, since locale depends on weird platform-specific stuff
diff --git a/spec/ruby/core/encoding/fixtures/classes.rb b/spec/ruby/core/encoding/fixtures/classes.rb
index 12e9a4f348..943865e8d8 100644
--- a/spec/ruby/core/encoding/fixtures/classes.rb
+++ b/spec/ruby/core/encoding/fixtures/classes.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
module EncodingSpecs
class UndefinedConversionError
def self.exception
diff --git a/spec/ruby/core/encoding/inspect_spec.rb b/spec/ruby/core/encoding/inspect_spec.rb
index df96141db9..ab7f8cf9fc 100644
--- a/spec/ruby/core/encoding/inspect_spec.rb
+++ b/spec/ruby/core/encoding/inspect_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Encoding#inspect" do
it "returns a String" do
- Encoding::UTF_8.inspect.should be_an_instance_of(String)
+ Encoding::UTF_8.inspect.should.instance_of?(String)
end
ruby_version_is ""..."3.4" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
index 2b15fc1a0f..7d3cc77c0b 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
@@ -8,8 +8,8 @@ describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
end
it "returns a String" do
- @exception.destination_encoding_name.should be_an_instance_of(String)
- @exception2.destination_encoding_name.should be_an_instance_of(String)
+ @exception.destination_encoding_name.should.instance_of?(String)
+ @exception2.destination_encoding_name.should.instance_of?(String)
end
it "is equal to the destination encoding name of the object that raised it" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
index c2ed6de1d8..264c409b1c 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
@@ -8,8 +8,8 @@ describe "Encoding::InvalidByteSequenceError#destination_encoding" do
end
it "returns an Encoding object" do
- @exception.destination_encoding.should be_an_instance_of(Encoding)
- @exception2.destination_encoding.should be_an_instance_of(Encoding)
+ @exception.destination_encoding.should.instance_of?(Encoding)
+ @exception2.destination_encoding.should.instance_of?(Encoding)
end
it "is equal to the destination encoding of the object that raised it" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
index d2fc360dce..40a9a35caf 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
@@ -9,8 +9,8 @@ describe "Encoding::InvalidByteSequenceError#error_bytes" do
end
it "returns a String" do
- @exception.error_bytes.should be_an_instance_of(String)
- @exception2.error_bytes.should be_an_instance_of(String)
+ @exception.error_bytes.should.instance_of?(String)
+ @exception2.error_bytes.should.instance_of?(String)
end
it "returns the bytes that caused the exception" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
index 8a3f3de69a..143db7b6da 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
@@ -1,9 +1,9 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
it "returns nil by default" do
- Encoding::InvalidByteSequenceError.new.incomplete_input?.should be_nil
+ Encoding::InvalidByteSequenceError.new.incomplete_input?.should == nil
end
it "returns true if #primitive_convert returned :incomplete_input for the same data" do
@@ -12,7 +12,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
begin
ec.convert("\xA1")
rescue Encoding::InvalidByteSequenceError => e
- e.incomplete_input?.should be_true
+ e.incomplete_input?.should == true
end
end
@@ -22,7 +22,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
begin
ec.convert("\xfffffffff")
rescue Encoding::InvalidByteSequenceError => e
- e.incomplete_input?.should be_false
+ e.incomplete_input?.should == false
end
end
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
index a5e2824984..e4fc81aac6 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
@@ -9,8 +9,8 @@ describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
end
it "returns a String" do
- @exception.readagain_bytes.should be_an_instance_of(String)
- @exception2.readagain_bytes.should be_an_instance_of(String)
+ @exception.readagain_bytes.should.instance_of?(String)
+ @exception2.readagain_bytes.should.instance_of?(String)
end
it "returns the bytes to be read again" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
index a9464114a8..b00e1ad4e8 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
@@ -8,7 +8,7 @@ describe "Encoding::UndefinedConversionError#source_encoding_name" do
end
it "returns a String" do
- @exception.source_encoding_name.should be_an_instance_of(String)
+ @exception.source_encoding_name.should.instance_of?(String)
end
it "is equal to the source encoding name of the object that raised it" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
index 7fdc0a122b..32ad25dbb5 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
@@ -8,8 +8,8 @@ describe "Encoding::InvalidByteSequenceError#source_encoding" do
end
it "returns an Encoding object" do
- @exception.source_encoding.should be_an_instance_of(Encoding)
- @exception2.source_encoding.should be_an_instance_of(Encoding)
+ @exception.source_encoding.should.instance_of?(Encoding)
+ @exception2.source_encoding.should.instance_of?(Encoding)
end
it "is equal to the source encoding of the object that raised it" do
diff --git a/spec/ruby/core/encoding/list_spec.rb b/spec/ruby/core/encoding/list_spec.rb
index bd3d5b7bc0..9fe336c608 100644
--- a/spec/ruby/core/encoding/list_spec.rb
+++ b/spec/ruby/core/encoding/list_spec.rb
@@ -2,12 +2,12 @@ require_relative '../../spec_helper'
describe "Encoding.list" do
it "returns an Array" do
- Encoding.list.should be_an_instance_of(Array)
+ Encoding.list.should.instance_of?(Array)
end
it "returns an Array of Encoding objects" do
Encoding.list.each do |enc|
- enc.should be_an_instance_of(Encoding)
+ enc.should.instance_of?(Encoding)
end
end
@@ -17,18 +17,18 @@ describe "Encoding.list" do
end
it "includes the default external encoding" do
- Encoding.list.include?(Encoding.default_external).should be_true
+ Encoding.list.include?(Encoding.default_external).should == true
end
it "does not include any alias names" do
Encoding.aliases.keys.each do |enc_alias|
- Encoding.list.include?(enc_alias).should be_false
+ Encoding.list.include?(enc_alias).should == false
end
end
it "includes all aliased encodings" do
Encoding.aliases.values.each do |enc_alias|
- Encoding.list.include?(Encoding.find(enc_alias)).should be_true
+ Encoding.list.include?(Encoding.find(enc_alias)).should == true
end
end
diff --git a/spec/ruby/core/encoding/locale_charmap_spec.rb b/spec/ruby/core/encoding/locale_charmap_spec.rb
index 8143b9083a..0d77bf227b 100644
--- a/spec/ruby/core/encoding/locale_charmap_spec.rb
+++ b/spec/ruby/core/encoding/locale_charmap_spec.rb
@@ -2,55 +2,55 @@ require_relative '../../spec_helper'
describe "Encoding.locale_charmap" do
it "returns a String" do
- Encoding.locale_charmap.should be_an_instance_of(String)
+ Encoding.locale_charmap.should.instance_of?(String)
end
- # FIXME: Get this working on Windows
- platform_is :linux do
- platform_is_not :android do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'ANSI_X3.4-1968'
- ENV['LC_ALL'] = old_lc_all
+ describe "when setting LC_ALL=C" do
+ before :each do
+ @old_lc_all = ENV['LC_ALL']
+ end
+
+ after :each do
+ ENV['LC_ALL'] = @old_lc_all
+ end
+
+ # FIXME: Get this working on Windows
+ platform_is :linux do
+ platform_is_not :android do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'ANSI_X3.4-1968'
+ end
end
end
- end
- platform_is :freebsd, :openbsd, :darwin do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'US-ASCII'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :freebsd, :openbsd, :darwin do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'US-ASCII'
+ end
end
- end
- platform_is :netbsd do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == '646'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :netbsd do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == '646'
+ end
end
- end
- platform_is :android do
- it "always returns UTF-8" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'UTF-8'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :android do
+ it "always returns UTF-8" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'UTF-8'
+ end
end
- end
- platform_is :bsd, :darwin, :linux do
- it "is unaffected by assigning to ENV['LC_ALL'] in the same process" do
- old_charmap = Encoding.locale_charmap
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- Encoding.locale_charmap.should == old_charmap
- ENV['LC_ALL'] = old_lc_all
+ platform_is :bsd, :darwin, :linux do
+ it "is unaffected by assigning to ENV['LC_ALL'] in the same process" do
+ old_charmap = Encoding.locale_charmap
+ ENV['LC_ALL'] = 'C'
+ Encoding.locale_charmap.should == old_charmap
+ end
end
end
end
diff --git a/spec/ruby/core/encoding/name_list_spec.rb b/spec/ruby/core/encoding/name_list_spec.rb
index 836381c4d8..1ba8d383bc 100644
--- a/spec/ruby/core/encoding/name_list_spec.rb
+++ b/spec/ruby/core/encoding/name_list_spec.rb
@@ -2,22 +2,22 @@ require_relative '../../spec_helper'
describe "Encoding.name_list" do
it "returns an Array" do
- Encoding.name_list.should be_an_instance_of(Array)
+ Encoding.name_list.should.instance_of?(Array)
end
it "returns encoding names as Strings" do
- Encoding.name_list.each {|e| e.should be_an_instance_of(String) }
+ Encoding.name_list.each {|e| e.should.instance_of?(String) }
end
it "includes all aliases" do
Encoding.aliases.keys.each do |enc_alias|
- Encoding.name_list.include?(enc_alias).should be_true
+ Encoding.name_list.include?(enc_alias).should == true
end
end
it "includes all non-dummy encodings" do
Encoding.list.each do |enc|
- Encoding.name_list.include?(enc.name).should be_true
+ Encoding.name_list.include?(enc.name).should == true
end
end
end
diff --git a/spec/ruby/core/encoding/name_spec.rb b/spec/ruby/core/encoding/name_spec.rb
index dce9347978..1d625c9379 100644
--- a/spec/ruby/core/encoding/name_spec.rb
+++ b/spec/ruby/core/encoding/name_spec.rb
@@ -1,6 +1,15 @@
require_relative "../../spec_helper"
-require_relative 'shared/name'
describe "Encoding#name" do
- it_behaves_like :encoding_name, :name
+ it "returns a String" do
+ Encoding.list.each do |e|
+ e.name.should.instance_of?(String)
+ end
+ end
+
+ it "uniquely identifies an encoding" do
+ Encoding.list.each do |e|
+ e.should == Encoding.find(e.name)
+ end
+ end
end
diff --git a/spec/ruby/core/encoding/names_spec.rb b/spec/ruby/core/encoding/names_spec.rb
index 9ded043bbb..e6bcbf474a 100644
--- a/spec/ruby/core/encoding/names_spec.rb
+++ b/spec/ruby/core/encoding/names_spec.rb
@@ -4,7 +4,7 @@ describe "Encoding#names" do
it "returns an Array" do
Encoding.name_list.each do |name|
e = Encoding.find(name) or next
- e.names.should be_an_instance_of(Array)
+ e.names.should.instance_of?(Array)
end
end
@@ -12,7 +12,7 @@ describe "Encoding#names" do
Encoding.name_list.each do |name|
e = Encoding.find(name) or next
e.names.each do |this_name|
- this_name.should be_an_instance_of(String)
+ this_name.should.instance_of?(String)
end
end
end
@@ -29,7 +29,7 @@ describe "Encoding#names" do
e = Encoding.find(name) or next
aliases = Encoding.aliases.select{|a,n| n == name}.keys
names = e.names
- aliases.each {|a| names.include?(a).should be_true}
+ aliases.each {|a| names.include?(a).should == true}
end
end
end
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index e22673db7d..9fe0ba8747 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -1,88 +1,8 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
describe "Encoding#replicate" do
- ruby_version_is ""..."3.3" do
- before :all do
- @i = 0
- end
-
- before :each do
- @i += 1
- @prefix = "RS#{@i}"
- end
-
- it "returns a replica of ASCII" do
- name = @prefix + '-ASCII'
- e = suppress_warning { Encoding::ASCII.replicate(name) }
- e.name.should == name
- Encoding.find(name).should == e
-
- "a".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
- end
-
- it "returns a replica of UTF-8" do
- name = @prefix + 'UTF-8'
- e = suppress_warning { Encoding::UTF_8.replicate(name) }
- e.name.should == name
- Encoding.find(name).should == e
-
- "a".dup.force_encoding(e).valid_encoding?.should be_true
- "\u3042".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
- end
-
- it "returns a replica of UTF-16BE" do
- name = @prefix + 'UTF-16-BE'
- e = suppress_warning { Encoding::UTF_16BE.replicate(name) }
- e.name.should == name
- Encoding.find(name).should == e
-
- "a".dup.force_encoding(e).valid_encoding?.should be_false
- "\x30\x42".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
- end
-
- it "returns a replica of ISO-2022-JP" do
- name = @prefix + 'ISO-2022-JP'
- e = suppress_warning { Encoding::ISO_2022_JP.replicate(name) }
- Encoding.find(name).should == e
-
- e.name.should == name
- e.dummy?.should be_true
- end
-
- # NOTE: it's unclear of the value of this (for the complexity cost of it),
- # but it is the current CRuby behavior.
- it "can be associated with a String" do
- name = @prefix + '-US-ASCII'
- e = suppress_warning { Encoding::US_ASCII.replicate(name) }
- e.name.should == name
- Encoding.find(name).should == e
-
- s = "abc".dup.force_encoding(e)
- s.encoding.should == e
- s.encoding.name.should == name
- end
- end
-
- ruby_version_is "3.2"..."3.3" do
- it "warns about deprecation" do
- -> {
- Encoding::US_ASCII.replicate('MY-US-ASCII')
- }.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
- end
-
- it "raises EncodingError if too many encodings" do
- code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
- ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
- end
- end
-
- ruby_version_is "3.3" do
- it "has been removed" do
- Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
- end
+ it "has been removed" do
+ Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
end
end
diff --git a/spec/ruby/core/encoding/shared/name.rb b/spec/ruby/core/encoding/shared/name.rb
deleted file mode 100644
index cd37ea06db..0000000000
--- a/spec/ruby/core/encoding/shared/name.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe :encoding_name, shared: true do
- it "returns a String" do
- Encoding.list.each do |e|
- e.send(@method).should be_an_instance_of(String)
- end
- end
-
- it "uniquely identifies an encoding" do
- Encoding.list.each do |e|
- e.should == Encoding.find(e.send(@method))
- end
- end
-end
diff --git a/spec/ruby/core/encoding/to_s_spec.rb b/spec/ruby/core/encoding/to_s_spec.rb
index bab394a888..ee5e3b4abe 100644
--- a/spec/ruby/core/encoding/to_s_spec.rb
+++ b/spec/ruby/core/encoding/to_s_spec.rb
@@ -1,6 +1,7 @@
require_relative "../../spec_helper"
-require_relative 'shared/name'
describe "Encoding#to_s" do
- it_behaves_like :encoding_name, :to_s
+ it "is an alias of Encoding#name" do
+ Encoding.instance_method(:to_s).should == Encoding.instance_method(:name)
+ end
end
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
index a51a9f46a0..bc36695ca7 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
@@ -7,7 +7,7 @@ describe "Encoding::UndefinedConversionError#destination_encoding_name" do
end
it "returns a String" do
- @exception.destination_encoding_name.should be_an_instance_of(String)
+ @exception.destination_encoding_name.should.instance_of?(String)
end
it "is equal to the destination encoding name of the object that raised it" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
index 905556407c..c0fcf8de58 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
@@ -7,7 +7,7 @@ describe "Encoding::UndefinedConversionError#destination_encoding" do
end
it "returns an Encoding object" do
- @exception.destination_encoding.should be_an_instance_of(Encoding)
+ @exception.destination_encoding.should.instance_of?(Encoding)
end
it "is equal to the destination encoding of the object that raised it" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
index 9cb55e6d95..333acf5ee6 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
@@ -8,8 +8,8 @@ describe "Encoding::UndefinedConversionError#error_char" do
end
it "returns a String" do
- @exception.error_char.should be_an_instance_of(String)
- @exception2.error_char.should be_an_instance_of(String)
+ @exception.error_char.should.instance_of?(String)
+ @exception2.error_char.should.instance_of?(String)
end
it "returns the one-character String that caused the exception" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
index d5e60e78db..4932a25ed7 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
@@ -8,7 +8,7 @@ describe "Encoding::UndefinedConversionError#source_encoding_name" do
end
it "returns a String" do
- @exception.source_encoding_name.should be_an_instance_of(String)
+ @exception.source_encoding_name.should.instance_of?(String)
end
it "is equal to the source encoding name of the object that raised it" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
index de456a4b5a..cf12020ad2 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
@@ -8,8 +8,8 @@ describe "Encoding::UndefinedConversionError#source_encoding" do
end
it "returns an Encoding object" do
- @exception.source_encoding.should be_an_instance_of(Encoding)
- @exception2.source_encoding.should be_an_instance_of(Encoding)
+ @exception.source_encoding.should.instance_of?(Encoding)
+ @exception2.source_encoding.should.instance_of?(Encoding)
end
it "is equal to the source encoding of the object that raised it" do
diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb
index 160cd52628..cbdd63f86a 100644
--- a/spec/ruby/core/enumerable/all_spec.rb
+++ b/spec/ruby/core/enumerable/all_spec.rb
@@ -21,19 +21,19 @@ describe "Enumerable#all?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.all?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].all?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.all?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.all?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].all?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.all?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.all?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.all? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
@@ -60,7 +60,7 @@ describe "Enumerable#all?" do
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithFalse.new
- multi.all?.should be_true
+ multi.all?.should == true
end
end
@@ -106,7 +106,7 @@ describe "Enumerable#all?" do
it "does not hide exceptions out of the block" do
-> {
@enum.all? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -125,7 +125,7 @@ describe "Enumerable#all?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x >= 0 }
@enum1.all?(pattern).should == false
pattern.yielded.should == [[0], [1], [2], [-1]]
@@ -140,7 +140,7 @@ describe "Enumerable#all?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.all?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern never returns false or nil" do
@@ -168,7 +168,7 @@ describe "Enumerable#all?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.all?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb
index 243f8735d5..4405d4740a 100644
--- a/spec/ruby/core/enumerable/any_spec.rb
+++ b/spec/ruby/core/enumerable/any_spec.rb
@@ -21,19 +21,19 @@ describe "Enumerable#any?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.any?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].any?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.any?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.any?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].any?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.any?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.any?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.any? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
@@ -60,7 +60,7 @@ describe "Enumerable#any?" do
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithFalse.new
- multi.any?.should be_true
+ multi.any?.should == true
end
end
@@ -120,7 +120,7 @@ describe "Enumerable#any?" do
it "does not hide exceptions out of the block" do
-> {
@enum.any? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -139,7 +139,7 @@ describe "Enumerable#any?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x == 2 }
@enum1.any?(pattern).should == true
pattern.yielded.should == [[0], [1], [2]]
@@ -154,7 +154,7 @@ describe "Enumerable#any?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.any?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern ever returns a truthy value" do
@@ -181,7 +181,7 @@ describe "Enumerable#any?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.any?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/chain_spec.rb b/spec/ruby/core/enumerable/chain_spec.rb
index 5e2105d294..a0597e46a1 100644
--- a/spec/ruby/core/enumerable/chain_spec.rb
+++ b/spec/ruby/core/enumerable/chain_spec.rb
@@ -18,6 +18,6 @@ describe "Enumerable#chain" do
end
it "returns an Enumerator::Chain if given a block" do
- EnumerableSpecs::Numerous.new.chain.should be_an_instance_of(Enumerator::Chain)
+ EnumerableSpecs::Numerous.new.chain.should.instance_of?(Enumerator::Chain)
end
end
diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb
index ed6304307f..7c9b31c991 100644
--- a/spec/ruby/core/enumerable/chunk_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_spec.rb
@@ -8,13 +8,13 @@ describe "Enumerable#chunk" do
it "returns an Enumerator if called without a block" do
chunk = EnumerableSpecs::Numerous.new(1, 2, 3, 1, 2).chunk
- chunk.should be_an_instance_of(Enumerator)
+ chunk.should.instance_of?(Enumerator)
result = chunk.with_index {|elt, i| elt - i }.to_a
result.should == [[1, [1, 2, 3]], [-2, [1, 2]]]
end
it "returns an Enumerator if given a block" do
- EnumerableSpecs::Numerous.new.chunk {}.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.chunk {}.should.instance_of?(Enumerator)
end
it "yields the current element and the current chunk to the block" do
@@ -59,14 +59,14 @@ describe "Enumerable#chunk" do
it "raises a RuntimeError if the block returns a Symbol starting with an underscore other than :_alone or :_separator" do
e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1)
- -> { e.chunk { |x| :_arbitrary }.to_a }.should raise_error(RuntimeError)
+ -> { e.chunk { |x| :_arbitrary }.to_a }.should.raise(RuntimeError)
end
it "does not accept arguments" do
e = EnumerableSpecs::Numerous.new(1, 2, 3)
-> {
e.chunk(1) {}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it 'returned Enumerator size returns nil' do
diff --git a/spec/ruby/core/enumerable/chunk_while_spec.rb b/spec/ruby/core/enumerable/chunk_while_spec.rb
index 26bcc983db..286f717442 100644
--- a/spec/ruby/core/enumerable/chunk_while_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_while_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#chunk_while" do
context "when given a block" do
it "returns an enumerator" do
- @result.should be_an_instance_of(Enumerator)
+ @result.should.instance_of?(Enumerator)
end
it "splits chunks between adjacent elements i and j where the block returns false" do
@@ -30,7 +30,7 @@ describe "Enumerable#chunk_while" do
context "when not given a block" do
it "raises an ArgumentError" do
- -> { @enum.chunk_while }.should raise_error(ArgumentError)
+ -> { @enum.chunk_while }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/cycle_spec.rb b/spec/ruby/core/enumerable/cycle_spec.rb
index 487086cba3..1fb3cc3d41 100644
--- a/spec/ruby/core/enumerable/cycle_spec.rb
+++ b/spec/ruby/core/enumerable/cycle_spec.rb
@@ -17,7 +17,7 @@ describe "Enumerable#cycle" do
it "returns nil if there are no elements" do
out = EnumerableSpecs::Empty.new.cycle { break :nope }
- out.should be_nil
+ out.should == nil
end
it "yields successive elements of the array repeatedly" do
@@ -44,8 +44,8 @@ describe "Enumerable#cycle" do
describe "passed a number n as an argument" do
it "returns nil and does nothing for non positive n" do
- EnumerableSpecs::ThrowingEach.new.cycle(0) {}.should be_nil
- EnumerableSpecs::NoEach.new.cycle(-22) {}.should be_nil
+ EnumerableSpecs::ThrowingEach.new.cycle(0) {}.should == nil
+ EnumerableSpecs::NoEach.new.cycle(-22) {}.should == nil
end
it "calls each at most once" do
@@ -71,12 +71,12 @@ describe "Enumerable#cycle" do
it "raises a TypeError when the passed n cannot be coerced to Integer" do
enum = EnumerableSpecs::Numerous.new
- ->{ enum.cycle("cat"){} }.should raise_error(TypeError)
+ ->{ enum.cycle("cat"){} }.should.raise(TypeError)
end
it "raises an ArgumentError if more arguments are passed" do
enum = EnumerableSpecs::Numerous.new
- ->{ enum.cycle(1, 2) {} }.should raise_error(ArgumentError)
+ ->{ enum.cycle(1, 2) {} }.should.raise(ArgumentError)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/drop_spec.rb b/spec/ruby/core/enumerable/drop_spec.rb
index 423cc0088b..8d95f464b3 100644
--- a/spec/ruby/core/enumerable/drop_spec.rb
+++ b/spec/ruby/core/enumerable/drop_spec.rb
@@ -7,13 +7,13 @@ describe "Enumerable#drop" do
end
it "requires exactly one argument" do
- ->{ @enum.drop{} }.should raise_error(ArgumentError)
- ->{ @enum.drop(1, 2){} }.should raise_error(ArgumentError)
+ ->{ @enum.drop{} }.should.raise(ArgumentError)
+ ->{ @enum.drop(1, 2){} }.should.raise(ArgumentError)
end
describe "passed a number n as an argument" do
it "raises ArgumentError if n < 0" do
- ->{ @enum.drop(-1) }.should raise_error(ArgumentError)
+ ->{ @enum.drop(-1) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -35,8 +35,8 @@ describe "Enumerable#drop" do
end
it "raises a TypeError when the passed n cannot be coerced to Integer" do
- ->{ @enum.drop("hat") }.should raise_error(TypeError)
- ->{ @enum.drop(nil) }.should raise_error(TypeError)
+ ->{ @enum.drop("hat") }.should.raise(TypeError)
+ ->{ @enum.drop(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/enumerable/drop_while_spec.rb b/spec/ruby/core/enumerable/drop_while_spec.rb
index 636c3d284a..4b4fdf2d4f 100644
--- a/spec/ruby/core/enumerable/drop_while_spec.rb
+++ b/spec/ruby/core/enumerable/drop_while_spec.rb
@@ -8,7 +8,7 @@ describe "Enumerable#drop_while" do
end
it "returns an Enumerator if no block given" do
- @enum.drop_while.should be_an_instance_of(Enumerator)
+ @enum.drop_while.should.instance_of?(Enumerator)
end
it "returns no/all elements for {true/false} block" do
@@ -38,7 +38,7 @@ describe "Enumerable#drop_while" do
it "doesn't return self when it could" do
a = [1,2,3]
- a.drop_while{false}.should_not equal(a)
+ a.drop_while{false}.should_not.equal?(a)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb
index ed77741862..c5e299fd00 100644
--- a/spec/ruby/core/enumerable/each_cons_spec.rb
+++ b/spec/ruby/core/enumerable/each_cons_spec.rb
@@ -15,14 +15,14 @@ describe "Enumerable#each_cons" do
end
it "raises an ArgumentError if there is not a single parameter > 0" do
- ->{ @enum.each_cons(0){} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(-2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons{} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(2,2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(0) }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(-2) }.should raise_error(ArgumentError)
- ->{ @enum.each_cons }.should raise_error(ArgumentError)
- ->{ @enum.each_cons(2,2) }.should raise_error(ArgumentError)
+ ->{ @enum.each_cons(0){} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(-2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons{} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(2,2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(0) }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(-2) }.should.raise(ArgumentError)
+ ->{ @enum.each_cons }.should.raise(ArgumentError)
+ ->{ @enum.each_cons(2,2) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -63,7 +63,7 @@ describe "Enumerable#each_cons" do
describe "when no block is given" do
it "returns an enumerator" do
e = @enum.each_cons(3)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @in_threes
end
diff --git a/spec/ruby/core/enumerable/each_entry_spec.rb b/spec/ruby/core/enumerable/each_entry_spec.rb
index edf00f3137..9dc89ec28e 100644
--- a/spec/ruby/core/enumerable/each_entry_spec.rb
+++ b/spec/ruby/core/enumerable/each_entry_spec.rb
@@ -11,13 +11,13 @@ describe "Enumerable#each_entry" do
it "yields multiple arguments as an array" do
acc = []
- @enum.each_entry {|g| acc << g}.should equal(@enum)
+ @enum.each_entry {|g| acc << g}.should.equal?(@enum)
acc.should == @entries
end
it "returns an enumerator if no block" do
e = @enum.each_entry
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @entries
end
@@ -27,8 +27,8 @@ describe "Enumerable#each_entry" do
end
it "raises an ArgumentError when extra arguments" do
- -> { @enum.each_entry("one").to_a }.should raise_error(ArgumentError)
- -> { @enum.each_entry("one"){}.to_a }.should raise_error(ArgumentError)
+ -> { @enum.each_entry("one").to_a }.should.raise(ArgumentError)
+ -> { @enum.each_entry("one"){}.to_a }.should.raise(ArgumentError)
end
it "passes extra arguments to #each" do
diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb
index 47b8c9ba33..d05abad1e9 100644
--- a/spec/ruby/core/enumerable/each_slice_spec.rb
+++ b/spec/ruby/core/enumerable/each_slice_spec.rb
@@ -15,14 +15,14 @@ describe "Enumerable#each_slice" do
end
it "raises an ArgumentError if there is not a single parameter > 0" do
- ->{ @enum.each_slice(0){} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(-2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice{} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(2,2){} }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(0) }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(-2) }.should raise_error(ArgumentError)
- ->{ @enum.each_slice }.should raise_error(ArgumentError)
- ->{ @enum.each_slice(2,2) }.should raise_error(ArgumentError)
+ ->{ @enum.each_slice(0){} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(-2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice{} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(2,2){} }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(0) }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(-2) }.should.raise(ArgumentError)
+ ->{ @enum.each_slice }.should.raise(ArgumentError)
+ ->{ @enum.each_slice(2,2) }.should.raise(ArgumentError)
end
it "tries to convert n to an Integer using #to_int" do
@@ -53,7 +53,7 @@ describe "Enumerable#each_slice" do
it "returns an enumerator if no block" do
e = @enum.each_slice(3)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @sliced
end
@@ -69,7 +69,7 @@ describe "Enumerable#each_slice" do
describe "when no block is given" do
it "returns an enumerator" do
e = @enum.each_slice(3)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == @sliced
end
diff --git a/spec/ruby/core/enumerable/each_with_index_spec.rb b/spec/ruby/core/enumerable/each_with_index_spec.rb
index 122e88eab7..fcb2f82f84 100644
--- a/spec/ruby/core/enumerable/each_with_index_spec.rb
+++ b/spec/ruby/core/enumerable/each_with_index_spec.rb
@@ -26,19 +26,19 @@ describe "Enumerable#each_with_index" do
acc = []
res = @b.each_with_index {|a,i| acc << [a,i]}
[[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]].should == acc
- res.should eql(@b)
+ res.should.eql?(@b)
end
it "binds splat arguments properly" do
acc = []
res = @b.each_with_index { |*b| c,d = b; acc << c; acc << d }
[2, 0, 5, 1, 3, 2, 6, 3, 1, 4, 4, 5].should == acc
- res.should eql(@b)
+ res.should.eql?(@b)
end
it "returns an enumerator if no block" do
e = @b.each_with_index
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]]
end
diff --git a/spec/ruby/core/enumerable/each_with_object_spec.rb b/spec/ruby/core/enumerable/each_with_object_spec.rb
index 35665e7019..1760d3b267 100644
--- a/spec/ruby/core/enumerable/each_with_object_spec.rb
+++ b/spec/ruby/core/enumerable/each_with_object_spec.rb
@@ -12,10 +12,10 @@ describe "Enumerable#each_with_object" do
it "passes each element and its argument to the block" do
acc = []
@enum.each_with_object(@initial) do |elem, obj|
- obj.should equal(@initial)
+ obj.should.equal?(@initial)
obj = 42
acc << elem
- end.should equal(@initial)
+ end.should.equal?(@initial)
acc.should == @values
end
@@ -23,10 +23,10 @@ describe "Enumerable#each_with_object" do
acc = []
e = @enum.each_with_object(@initial)
e.each do |elem, obj|
- obj.should equal(@initial)
+ obj.should.equal?(@initial)
obj = 42
acc << elem
- end.should equal(@initial)
+ end.should.equal?(@initial)
acc.should == @values
end
diff --git a/spec/ruby/core/enumerable/filter_map_spec.rb b/spec/ruby/core/enumerable/filter_map_spec.rb
index aa4894230b..1ed131a960 100644
--- a/spec/ruby/core/enumerable/filter_map_spec.rb
+++ b/spec/ruby/core/enumerable/filter_map_spec.rb
@@ -19,6 +19,6 @@ describe 'Enumerable#filter_map' do
end
it 'returns an enumerator when no block given' do
- @numerous.filter_map.should be_an_instance_of(Enumerator)
+ @numerous.filter_map.should.instance_of?(Enumerator)
end
end
diff --git a/spec/ruby/core/enumerable/filter_spec.rb b/spec/ruby/core/enumerable/filter_spec.rb
index c9ee23c541..1c3a7e9ff5 100644
--- a/spec/ruby/core/enumerable/filter_spec.rb
+++ b/spec/ruby/core/enumerable/filter_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/find_all'
describe "Enumerable#filter" do
- it_behaves_like(:enumerable_find_all, :filter)
+ it_behaves_like :enumerable_find_all, :filter
end
diff --git a/spec/ruby/core/enumerable/find_index_spec.rb b/spec/ruby/core/enumerable/find_index_spec.rb
index 542660fe04..2e714367ba 100644
--- a/spec/ruby/core/enumerable/find_index_spec.rb
+++ b/spec/ruby/core/enumerable/find_index_spec.rb
@@ -47,7 +47,7 @@ describe "Enumerable#find_index" do
end
it "returns an Enumerator if no block given" do
- @numerous.find_index.should be_an_instance_of(Enumerator)
+ @numerous.find_index.should.instance_of?(Enumerator)
end
it "uses #== for testing equality" do
diff --git a/spec/ruby/core/enumerable/first_spec.rb b/spec/ruby/core/enumerable/first_spec.rb
index ed1ba599b4..592dff1ebc 100644
--- a/spec/ruby/core/enumerable/first_spec.rb
+++ b/spec/ruby/core/enumerable/first_spec.rb
@@ -19,7 +19,7 @@ describe "Enumerable#first" do
it "raises a RangeError when passed a Bignum" do
enum = EnumerableSpecs::Empty.new
- -> { enum.first(bignum_value) }.should raise_error(RangeError)
+ -> { enum.first(bignum_value) }.should.raise(RangeError)
end
describe "when passed an argument" do
diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb
index 2701c6999c..b5feafcfb7 100644
--- a/spec/ruby/core/enumerable/fixtures/classes.rb
+++ b/spec/ruby/core/enumerable/fixtures/classes.rb
@@ -38,12 +38,14 @@ module EnumerableSpecs
class Empty
include Enumerable
def each
+ self
end
end
class EmptyWithSize
include Enumerable
def each
+ self
end
def size
0
@@ -343,9 +345,6 @@ module EnumerableSpecs
end
end
- # Set is a core class since Ruby 3.2
- ruby_version_is '3.2' do
- class SetSubclass < Set
- end
+ class SetSubclass < Set
end
end # EnumerableSpecs utility classes
diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb
index 989358f01b..965e183766 100644
--- a/spec/ruby/core/enumerable/grep_spec.rb
+++ b/spec/ruby/core/enumerable/grep_spec.rb
@@ -81,7 +81,7 @@ describe "Enumerable#grep" do
end
it "raises an ArgumentError when not given a pattern" do
- -> { @numerous.grep { |e| e } }.should raise_error(ArgumentError)
+ -> { @numerous.grep { |e| e } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb
index ba19216968..ee99a77ac1 100644
--- a/spec/ruby/core/enumerable/grep_v_spec.rb
+++ b/spec/ruby/core/enumerable/grep_v_spec.rb
@@ -55,7 +55,7 @@ describe "Enumerable#grep_v" do
end
it "raises an ArgumentError when not given a pattern" do
- -> { @numerous.grep_v }.should raise_error(ArgumentError)
+ -> { @numerous.grep_v }.should.raise(ArgumentError)
end
end
@@ -70,7 +70,7 @@ describe "Enumerable#grep_v" do
end
it "raises an ArgumentError when not given a pattern" do
- -> { @numerous.grep_v { |e| e } }.should raise_error(ArgumentError)
+ -> { @numerous.grep_v { |e| e } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/group_by_spec.rb b/spec/ruby/core/enumerable/group_by_spec.rb
index 4fd1603819..904e5d6c68 100644
--- a/spec/ruby/core/enumerable/group_by_spec.rb
+++ b/spec/ruby/core/enumerable/group_by_spec.rb
@@ -16,13 +16,13 @@ describe "Enumerable#group_by" do
it "returns a hash without default_proc" do
e = EnumerableSpecs::Numerous.new("foo", "bar", "baz")
h = e.group_by { |word| word[0..0].to_sym }
- h[:some].should be_nil
- h.default_proc.should be_nil
- h.default.should be_nil
+ h[:some].should == nil
+ h.default_proc.should == nil
+ h.default.should == nil
end
it "returns an Enumerator if called without a block" do
- EnumerableSpecs::Numerous.new.group_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.group_by.should.instance_of?(Enumerator)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/lazy_spec.rb b/spec/ruby/core/enumerable/lazy_spec.rb
index 9a9ead81a0..935e574067 100644
--- a/spec/ruby/core/enumerable/lazy_spec.rb
+++ b/spec/ruby/core/enumerable/lazy_spec.rb
@@ -5,6 +5,6 @@ require_relative 'fixtures/classes'
describe "Enumerable#lazy" do
it "returns an instance of Enumerator::Lazy" do
- EnumerableSpecs::Numerous.new.lazy.should be_an_instance_of(Enumerator::Lazy)
+ EnumerableSpecs::Numerous.new.lazy.should.instance_of?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerable/max_by_spec.rb b/spec/ruby/core/enumerable/max_by_spec.rb
index ec1738ea3b..f67b5d15ea 100644
--- a/spec/ruby/core/enumerable/max_by_spec.rb
+++ b/spec/ruby/core/enumerable/max_by_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#max_by" do
it "returns an enumerator if no block" do
- EnumerableSpecs::Numerous.new(42).max_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new(42).max_by.should.instance_of?(Enumerator)
end
it "returns nil if #each yields no objects" do
@@ -18,7 +18,7 @@ describe "Enumerable#max_by" do
it "returns the object that appears first in #each in case of a tie" do
a, b, c = '1', '2', '2'
- EnumerableSpecs::Numerous.new(a, b, c).max_by {|obj| obj.to_i }.should equal(b)
+ EnumerableSpecs::Numerous.new(a, b, c).max_by {|obj| obj.to_i }.should.equal?(b)
end
it "uses max.<=>(current) to determine order" do
@@ -48,7 +48,7 @@ describe "Enumerable#max_by" do
context "without a block" do
it "returns an enumerator" do
- @enum.max_by(2).should be_an_instance_of(Enumerator)
+ @enum.max_by(2).should.instance_of?(Enumerator)
end
end
@@ -67,7 +67,7 @@ describe "Enumerable#max_by" do
context "when n is negative" do
it "raises an ArgumentError" do
- -> { @enum.max_by(-1) { |i| i.to_s } }.should raise_error(ArgumentError)
+ -> { @enum.max_by(-1) { |i| i.to_s } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/max_spec.rb b/spec/ruby/core/enumerable/max_spec.rb
index 0c11ca0969..d92700258b 100644
--- a/spec/ruby/core/enumerable/max_spec.rb
+++ b/spec/ruby/core/enumerable/max_spec.rb
@@ -38,16 +38,16 @@ describe "Enumerable#max" do
it "raises a NoMethodError for elements without #<=>" do
-> do
EnumerableSpecs::EachDefiner.new(BasicObject.new, BasicObject.new).max
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
EnumerableSpecs::EachDefiner.new(11,"22").max
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
EnumerableSpecs::EachDefiner.new(11,12,22,33).max{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
context "when passed a block" do
@@ -106,7 +106,7 @@ describe "Enumerable#max" do
context "that is negative" do
it "raises an ArgumentError" do
- -> { @e_ints.max(-1) }.should raise_error(ArgumentError)
+ -> { @e_ints.max(-1) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/min_by_spec.rb b/spec/ruby/core/enumerable/min_by_spec.rb
index 3ff87e49d8..4f949e2130 100644
--- a/spec/ruby/core/enumerable/min_by_spec.rb
+++ b/spec/ruby/core/enumerable/min_by_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#min_by" do
it "returns an enumerator if no block" do
- EnumerableSpecs::Numerous.new(42).min_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new(42).min_by.should.instance_of?(Enumerator)
end
it "returns nil if #each yields no objects" do
@@ -18,7 +18,7 @@ describe "Enumerable#min_by" do
it "returns the object that appears first in #each in case of a tie" do
a, b, c = '2', '1', '1'
- EnumerableSpecs::Numerous.new(a, b, c).min_by {|obj| obj.to_i }.should equal(b)
+ EnumerableSpecs::Numerous.new(a, b, c).min_by {|obj| obj.to_i }.should.equal?(b)
end
it "uses min.<=>(current) to determine order" do
@@ -48,7 +48,7 @@ describe "Enumerable#min_by" do
context "without a block" do
it "returns an enumerator" do
- @enum.min_by(2).should be_an_instance_of(Enumerator)
+ @enum.min_by(2).should.instance_of?(Enumerator)
end
end
@@ -67,7 +67,7 @@ describe "Enumerable#min_by" do
context "when n is negative" do
it "raises an ArgumentError" do
- -> { @enum.min_by(-1) { |i| i.to_s } }.should raise_error(ArgumentError)
+ -> { @enum.min_by(-1) { |i| i.to_s } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/min_spec.rb b/spec/ruby/core/enumerable/min_spec.rb
index 4b6ae248fa..f05d59c2c9 100644
--- a/spec/ruby/core/enumerable/min_spec.rb
+++ b/spec/ruby/core/enumerable/min_spec.rb
@@ -32,22 +32,22 @@ describe "Enumerable#min" do
end
it "returns nil for an empty Enumerable" do
- EnumerableSpecs::EachDefiner.new.min.should be_nil
+ EnumerableSpecs::EachDefiner.new.min.should == nil
end
it "raises a NoMethodError for elements without #<=>" do
-> do
EnumerableSpecs::EachDefiner.new(BasicObject.new, BasicObject.new).min
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "raises an ArgumentError for incomparable elements" do
-> do
EnumerableSpecs::EachDefiner.new(11,"22").min
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| nil}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns the minimum when using a block rule" do
@@ -110,7 +110,7 @@ describe "Enumerable#min" do
context "that is negative" do
it "raises an ArgumentError" do
- -> { @e_ints.min(-1) }.should raise_error(ArgumentError)
+ -> { @e_ints.min(-1) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/enumerable/minmax_by_spec.rb b/spec/ruby/core/enumerable/minmax_by_spec.rb
index a6a9249270..30c88cfcfb 100644
--- a/spec/ruby/core/enumerable/minmax_by_spec.rb
+++ b/spec/ruby/core/enumerable/minmax_by_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/enumerable_enumeratorized'
describe "Enumerable#minmax_by" do
it "returns an enumerator if no block" do
- EnumerableSpecs::Numerous.new(42).minmax_by.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new(42).minmax_by.should.instance_of?(Enumerator)
end
it "returns nil if #each yields no objects" do
@@ -19,8 +19,8 @@ describe "Enumerable#minmax_by" do
it "returns the object that appears first in #each in case of a tie" do
a, b, c, d = '1', '1', '2', '2'
mm = EnumerableSpecs::Numerous.new(a, b, c, d).minmax_by {|obj| obj.to_i }
- mm[0].should equal(a)
- mm[1].should equal(c)
+ mm[0].should.equal?(a)
+ mm[1].should.equal?(c)
end
it "uses min/max.<=>(current) to determine order" do
diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb
index fb42f13386..d9ee0b441e 100644
--- a/spec/ruby/core/enumerable/none_spec.rb
+++ b/spec/ruby/core/enumerable/none_spec.rb
@@ -15,35 +15,35 @@ describe "Enumerable#none?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.none?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].none?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.none?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.none?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].none?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.none?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.none?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.none? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
it "returns true if none of the elements in self are true" do
e = EnumerableSpecs::Numerous.new(false, nil, false)
- e.none?.should be_true
+ e.none?.should == true
end
it "returns false if at least one of the elements in self are true" do
e = EnumerableSpecs::Numerous.new(false, nil, true, false)
- e.none?.should be_false
+ e.none?.should == false
end
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithFalse.new
- multi.none?.should be_false
+ multi.none?.should == false
end
end
@@ -65,17 +65,17 @@ describe "Enumerable#none?" do
end
it "returns true if the block never returns true" do
- @e.none? {|e| false }.should be_true
+ @e.none? {|e| false }.should == true
end
it "returns false if the block ever returns true" do
- @e.none? {|e| e == 3 ? true : false }.should be_false
+ @e.none? {|e| e == 3 ? true : false }.should == false
end
it "does not hide exceptions out of the block" do
-> {
@enum.none? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -94,7 +94,7 @@ describe "Enumerable#none?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x == 3 }
@enum1.none?(pattern).should == true
pattern.yielded.should == [[0], [1], [2], [-1]]
@@ -109,7 +109,7 @@ describe "Enumerable#none?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.none?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern never returns a truthy value" do
@@ -134,7 +134,7 @@ describe "Enumerable#none?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.none?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb
index 4bf8623d2e..cf966d4a9b 100644
--- a/spec/ruby/core/enumerable/one_spec.rb
+++ b/spec/ruby/core/enumerable/one_spec.rb
@@ -15,57 +15,57 @@ describe "Enumerable#one?" do
end
it "raises an ArgumentError when more than 1 argument is provided" do
- -> { @enum.one?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { [].one?(1, 2, 3) }.should raise_error(ArgumentError)
- -> { {}.one?(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @enum.one?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { [].one?(1, 2, 3) }.should.raise(ArgumentError)
+ -> { {}.one?(1, 2, 3) }.should.raise(ArgumentError)
end
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.one?
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
-> {
EnumerableSpecs::ThrowingEach.new.one? { false }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
describe "with no block" do
it "returns true if only one element evaluates to true" do
- [false, nil, true].one?.should be_true
+ [false, nil, true].one?.should == true
end
it "returns false if two elements evaluate to true" do
- [false, :value, nil, true].one?.should be_false
+ [false, :value, nil, true].one?.should == false
end
it "returns false if all elements evaluate to false" do
- [false, nil, false].one?.should be_false
+ [false, nil, false].one?.should == false
end
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMultiWithSingleTrue.new
- multi.one?.should be_false
+ multi.one?.should == false
end
end
describe "with a block" do
it "returns true if block returns true once" do
- [:a, :b, :c].one? { |s| s == :a }.should be_true
+ [:a, :b, :c].one? { |s| s == :a }.should == true
end
it "returns false if the block returns true more than once" do
- [:a, :b, :c].one? { |s| s == :a || s == :b }.should be_false
+ [:a, :b, :c].one? { |s| s == :a || s == :b }.should == false
end
it "returns false if the block only returns false" do
- [:a, :b, :c].one? { |s| s == :d }.should be_false
+ [:a, :b, :c].one? { |s| s == :d }.should == false
end
it "does not hide exceptions out of the block" do
-> {
@enum.one? { raise "from block" }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "gathers initial args as elements when each yields multiple" do
@@ -84,7 +84,7 @@ describe "Enumerable#one?" do
end
describe 'when given a pattern argument' do
- it "calls `===` on the pattern the return value " do
+ it "calls `===` on the pattern the return value" do
pattern = EnumerableSpecs::Pattern.new { |x| x == 1 }
@enum1.one?(pattern).should == true
pattern.yielded.should == [[0], [1], [2], [-1]]
@@ -99,7 +99,7 @@ describe "Enumerable#one?" do
it "does not hide exceptions out of #each" do
-> {
EnumerableSpecs::ThrowingEach.new.one?(Integer)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "returns true if the pattern returns a truthy value only once" do
@@ -135,7 +135,7 @@ describe "Enumerable#one?" do
pattern = EnumerableSpecs::Pattern.new { raise "from pattern" }
-> {
@enum.one?(pattern)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "calls the pattern with gathered array when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/partition_spec.rb b/spec/ruby/core/enumerable/partition_spec.rb
index d3d220b4b4..8272ee189e 100644
--- a/spec/ruby/core/enumerable/partition_spec.rb
+++ b/spec/ruby/core/enumerable/partition_spec.rb
@@ -8,7 +8,7 @@ describe "Enumerable#partition" do
end
it "returns an Enumerator if called without a block" do
- EnumerableSpecs::Numerous.new.partition.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.partition.should.instance_of?(Enumerator)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/reject_spec.rb b/spec/ruby/core/enumerable/reject_spec.rb
index 0d86b49ea2..31e89f5b0e 100644
--- a/spec/ruby/core/enumerable/reject_spec.rb
+++ b/spec/ruby/core/enumerable/reject_spec.rb
@@ -13,7 +13,7 @@ describe "Enumerable#reject" do
end
it "returns an Enumerator if called without a block" do
- EnumerableSpecs::Numerous.new.reject.should be_an_instance_of(Enumerator)
+ EnumerableSpecs::Numerous.new.reject.should.instance_of?(Enumerator)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/reverse_each_spec.rb b/spec/ruby/core/enumerable/reverse_each_spec.rb
index 2b1c233488..4753956724 100644
--- a/spec/ruby/core/enumerable/reverse_each_spec.rb
+++ b/spec/ruby/core/enumerable/reverse_each_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#reverse_each" do
it "returns an Enumerator if no block given" do
enum = EnumerableSpecs::Numerous.new.reverse_each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [4, 1, 6, 3, 5, 2]
end
diff --git a/spec/ruby/core/enumerable/shared/collect.rb b/spec/ruby/core/enumerable/shared/collect.rb
index 6df1a616eb..4696d32454 100644
--- a/spec/ruby/core/enumerable/shared/collect.rb
+++ b/spec/ruby/core/enumerable/shared/collect.rb
@@ -30,7 +30,7 @@ describe :enumerable_collect, shared: true do
it "returns an enumerator when no block given" do
enum = EnumerableSpecs::Numerous.new.send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |i| -i }.should == [-2, -5, -3, -6, -1, -4]
end
@@ -86,7 +86,7 @@ describe :enumerable_collect, shared: true do
-> do
{ 1 => 'a', 2 => 'b' }.map(&m)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "calls the each method on sub-classes" do
diff --git a/spec/ruby/core/enumerable/shared/collect_concat.rb b/spec/ruby/core/enumerable/shared/collect_concat.rb
index ddd431baeb..1694e3fdce 100644
--- a/spec/ruby/core/enumerable/shared/collect_concat.rb
+++ b/spec/ruby/core/enumerable/shared/collect_concat.rb
@@ -41,12 +41,12 @@ describe :enumerable_collect_concat, shared: true do
obj = mock("to_ary defined")
obj.should_receive(:to_ary).and_return("array")
- -> { [1, obj, 3].send(@method) { |i| i } }.should raise_error(TypeError)
+ -> { [1, obj, 3].send(@method) { |i| i } }.should.raise(TypeError)
end
it "returns an enumerator when no block given" do
enum = EnumerableSpecs::Numerous.new(1, 2).send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each{ |i| [i] * i }.should == [1, 2, 2]
end
diff --git a/spec/ruby/core/enumerable/shared/find.rb b/spec/ruby/core/enumerable/shared/find.rb
index 61d63ba3d5..cdff640415 100644
--- a/spec/ruby/core/enumerable/shared/find.rb
+++ b/spec/ruby/core/enumerable/shared/find.rb
@@ -59,7 +59,7 @@ describe :enumerable_find, shared: true do
end
it "returns an enumerator when no block given" do
- @numerous.send(@method).should be_an_instance_of(Enumerator)
+ @numerous.send(@method).should.instance_of?(Enumerator)
end
it "passes the ifnone proc to the enumerator" do
diff --git a/spec/ruby/core/enumerable/shared/find_all.rb b/spec/ruby/core/enumerable/shared/find_all.rb
index 1bbe71f372..27f01de6e0 100644
--- a/spec/ruby/core/enumerable/shared/find_all.rb
+++ b/spec/ruby/core/enumerable/shared/find_all.rb
@@ -14,7 +14,7 @@ describe :enumerable_find_all, shared: true do
end
it "returns an enumerator when no block given" do
- @numerous.send(@method).should be_an_instance_of(Enumerator)
+ @numerous.send(@method).should.instance_of?(Enumerator)
end
it "passes through the values yielded by #each_with_index" do
diff --git a/spec/ruby/core/enumerable/shared/include.rb b/spec/ruby/core/enumerable/shared/include.rb
index 569f350fd5..ea250f032b 100644
--- a/spec/ruby/core/enumerable/shared/include.rb
+++ b/spec/ruby/core/enumerable/shared/include.rb
@@ -28,7 +28,7 @@ describe :enumerable_include, shared: true do
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method, [1,2]).should be_true
+ multi.send(@method, [1,2]).should == true
end
end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
index 92f220efa4..7da4f0ca99 100644
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ b/spec/ruby/core/enumerable/shared/inject.rb
@@ -31,8 +31,8 @@ describe :enumerable_inject, shared: true do
end
it "raises TypeError when the second argument is not Symbol or String and it cannot be converted to String if two arguments" do
- -> { EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { [1, 2, 3].send(@method, 10, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { [1, 2, 3].send(@method, 10, Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "ignores the block if two arguments" do
@@ -73,8 +73,8 @@ describe :enumerable_inject, shared: true do
end
it "raises TypeError when passed not Symbol or String method name argument and it cannot be converted to String" do
- -> { EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { [10, 1, 2, 3].send(@method, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { [10, 1, 2, 3].send(@method, Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "without argument takes a block with an accumulator (with first element as initial value) and the current element. Value of block becomes new accumulator" do
@@ -103,7 +103,7 @@ describe :enumerable_inject, shared: true do
it "without inject arguments(legacy rubycon)" do
# no inject argument
- EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| 999 } .should == 2
+ EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| 999 }.should == 2
EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| acc }.should == 2
EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| x }.should == 2
@@ -135,10 +135,8 @@ describe :enumerable_inject, shared: true do
actual.sort_by(&:to_s).should == expected.sort_by(&:to_s)
end
- ruby_bug '#18635', ''...'3.2' do
- it "raises an ArgumentError when no parameters or block is given" do
- -> { [1,2].send(@method) }.should raise_error(ArgumentError)
- -> { {one: 1, two: 2}.send(@method) }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when no parameters or block is given" do
+ -> { [1,2].send(@method) }.should.raise(ArgumentError)
+ -> { {one: 1, two: 2}.send(@method) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/shared/take.rb b/spec/ruby/core/enumerable/shared/take.rb
index ce2ace20fa..a6da06325f 100644
--- a/spec/ruby/core/enumerable/shared/take.rb
+++ b/spec/ruby/core/enumerable/shared/take.rb
@@ -25,7 +25,7 @@ describe :enumerable_take, shared: true do
end
it "raises an ArgumentError when count is negative" do
- -> { @enum.send(@method, -1) }.should raise_error(ArgumentError)
+ -> { @enum.send(@method, -1) }.should.raise(ArgumentError)
end
it "returns the entire array when count > length" do
@@ -40,11 +40,11 @@ describe :enumerable_take, shared: true do
end
it "raises a TypeError if the passed argument is not numeric" do
- -> { @enum.send(@method, nil) }.should raise_error(TypeError)
- -> { @enum.send(@method, "a") }.should raise_error(TypeError)
+ -> { @enum.send(@method, nil) }.should.raise(TypeError)
+ -> { @enum.send(@method, "a") }.should.raise(TypeError)
obj = mock("nonnumeric")
- -> { @enum.send(@method, obj) }.should raise_error(TypeError)
+ -> { @enum.send(@method, obj) }.should.raise(TypeError)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/shared/value_packing.rb b/spec/ruby/core/enumerable/shared/value_packing.rb
new file mode 100644
index 0000000000..ff77f45cdf
--- /dev/null
+++ b/spec/ruby/core/enumerable/shared/value_packing.rb
@@ -0,0 +1,26 @@
+# This is the behavior of rb_enum_values_pack() in CRuby
+describe :enumerable_value_packing, shared: true do
+ # @take must be set to a Proc that returns the take-result whose #each
+ # yields packed values (e.g. -> e { e.take(1) } or -> e { e.lazy.take(1) }).
+
+ it "yields a single nil for a zero-argument source yield" do
+ e = Enumerator.new { |y| y.yield }
+ args = nil
+ @take.call(e).each { |*a| args = a }
+ args.should == [nil]
+ end
+
+ it "yields the value for a single-argument source yield" do
+ e = Enumerator.new { |y| y.yield :v }
+ args = nil
+ @take.call(e).each { |*a| args = a }
+ args.should == [:v]
+ end
+
+ it "yields a packed Array for a multi-argument source yield" do
+ e = Enumerator.new { |y| y.yield 1, 2 }
+ args = nil
+ @take.call(e).each { |*a| args = a }
+ args.should == [[1, 2]]
+ end
+end
diff --git a/spec/ruby/core/enumerable/slice_after_spec.rb b/spec/ruby/core/enumerable/slice_after_spec.rb
index 0e46688db1..1ef37195e5 100644
--- a/spec/ruby/core/enumerable/slice_after_spec.rb
+++ b/spec/ruby/core/enumerable/slice_after_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#slice_after" do
arg = mock("filter")
arg.should_receive(:===).and_return(false, true, false, false, false, true, false)
e = @enum.slice_after(arg)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]]
end
@@ -34,21 +34,21 @@ describe "Enumerable#slice_after" do
describe "and no argument" do
it "calls the block to determine when to yield" do
e = @enum.slice_after{ |i| i == 6 || i == 2 }
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7, 6], [5, 4, 3, 2], [1]]
end
end
describe "and an argument" do
it "raises an ArgumentError" do
- -> { @enum.slice_after(42) { |i| i == 6 } }.should raise_error(ArgumentError)
+ -> { @enum.slice_after(42) { |i| i == 6 } }.should.raise(ArgumentError)
end
end
end
it "raises an ArgumentError when given an incorrect number of arguments" do
- -> { @enum.slice_after("one", "two") }.should raise_error(ArgumentError)
- -> { @enum.slice_after }.should raise_error(ArgumentError)
+ -> { @enum.slice_after("one", "two") }.should.raise(ArgumentError)
+ -> { @enum.slice_after }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/slice_before_spec.rb b/spec/ruby/core/enumerable/slice_before_spec.rb
index f9b33f7b28..7eb4410a25 100644
--- a/spec/ruby/core/enumerable/slice_before_spec.rb
+++ b/spec/ruby/core/enumerable/slice_before_spec.rb
@@ -12,7 +12,7 @@ describe "Enumerable#slice_before" do
arg = mock "filter"
arg.should_receive(:===).and_return(false, true, false, false, false, true, false)
e = @enum.slice_before(arg)
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]]
end
@@ -35,7 +35,7 @@ describe "Enumerable#slice_before" do
describe "and no argument" do
it "calls the block to determine when to yield" do
e = @enum.slice_before{|i| i == 6 || i == 2}
- e.should be_an_instance_of(Enumerator)
+ e.should.instance_of?(Enumerator)
e.to_a.should == [[7], [6, 5, 4, 3], [2, 1]]
end
end
@@ -43,13 +43,13 @@ describe "Enumerable#slice_before" do
it "does not accept arguments" do
-> {
@enum.slice_before(1) {}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError when given an incorrect number of arguments" do
- -> { @enum.slice_before("one", "two") }.should raise_error(ArgumentError)
- -> { @enum.slice_before }.should raise_error(ArgumentError)
+ -> { @enum.slice_before("one", "two") }.should.raise(ArgumentError)
+ -> { @enum.slice_before }.should.raise(ArgumentError)
end
describe "when an iterator method yields more than one value" do
diff --git a/spec/ruby/core/enumerable/slice_when_spec.rb b/spec/ruby/core/enumerable/slice_when_spec.rb
index 6b8ea0923e..fe1ecd31e2 100644
--- a/spec/ruby/core/enumerable/slice_when_spec.rb
+++ b/spec/ruby/core/enumerable/slice_when_spec.rb
@@ -11,7 +11,7 @@ describe "Enumerable#slice_when" do
context "when given a block" do
it "returns an enumerator" do
- @result.should be_an_instance_of(Enumerator)
+ @result.should.instance_of?(Enumerator)
end
it "splits chunks between adjacent elements i and j where the block returns true" do
@@ -39,7 +39,7 @@ describe "Enumerable#slice_when" do
context "when not given a block" do
it "raises an ArgumentError" do
- -> { @enum.slice_when }.should raise_error(ArgumentError)
+ -> { @enum.slice_when }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/sort_by_spec.rb b/spec/ruby/core/enumerable/sort_by_spec.rb
index 8fdd923fb4..62cf38ce3e 100644
--- a/spec/ruby/core/enumerable/sort_by_spec.rb
+++ b/spec/ruby/core/enumerable/sort_by_spec.rb
@@ -18,7 +18,7 @@ describe "Enumerable#sort_by" do
it "returns an Enumerator when a block is not supplied" do
a = EnumerableSpecs::Numerous.new("a","b")
- a.sort_by.should be_an_instance_of(Enumerator)
+ a.sort_by.should.instance_of?(Enumerator)
a.to_a.should == ["a", "b"]
end
diff --git a/spec/ruby/core/enumerable/sort_spec.rb b/spec/ruby/core/enumerable/sort_spec.rb
index 6fc64f325e..427b1cd8f1 100644
--- a/spec/ruby/core/enumerable/sort_spec.rb
+++ b/spec/ruby/core/enumerable/sort_spec.rb
@@ -16,7 +16,7 @@ describe "Enumerable#sort" do
it "raises a NoMethodError if elements do not define <=>" do
-> do
EnumerableSpecs::Numerous.new(BasicObject.new, BasicObject.new, BasicObject.new).sort
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "sorts enumerables that contain nils" do
@@ -35,12 +35,12 @@ describe "Enumerable#sort" do
}.should == [6, 5, 4, 3, 2, 1]
-> {
EnumerableSpecs::Numerous.new.sort { |n, m| (n <=> m).to_s }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if objects can't be compared" do
a=EnumerableSpecs::Numerous.new(EnumerableSpecs::Uncomparable.new, EnumerableSpecs::Uncomparable.new)
- -> {a.sort}.should raise_error(ArgumentError)
+ -> {a.sort}.should.raise(ArgumentError)
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/take_spec.rb b/spec/ruby/core/enumerable/take_spec.rb
index 41a7438330..ca439b750d 100644
--- a/spec/ruby/core/enumerable/take_spec.rb
+++ b/spec/ruby/core/enumerable/take_spec.rb
@@ -1,13 +1,21 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/take'
+require_relative 'shared/value_packing'
describe "Enumerable#take" do
it "requires an argument" do
- ->{ EnumerableSpecs::Numerous.new.take}.should raise_error(ArgumentError)
+ ->{ EnumerableSpecs::Numerous.new.take}.should.raise(ArgumentError)
end
describe "when passed an argument" do
it_behaves_like :enumerable_take, :take
end
+
+ describe "value packing of source yields" do
+ before :each do
+ @take = -> e { e.take(1) }
+ end
+ it_behaves_like :enumerable_value_packing, nil
+ end
end
diff --git a/spec/ruby/core/enumerable/take_while_spec.rb b/spec/ruby/core/enumerable/take_while_spec.rb
index 26db39ac4b..918bfc897d 100644
--- a/spec/ruby/core/enumerable/take_while_spec.rb
+++ b/spec/ruby/core/enumerable/take_while_spec.rb
@@ -8,7 +8,7 @@ describe "Enumerable#take_while" do
end
it "returns an Enumerator if no block given" do
- @enum.take_while.should be_an_instance_of(Enumerator)
+ @enum.take_while.should.instance_of?(Enumerator)
end
it "returns no/all elements for {true/false} block" do
@@ -38,7 +38,7 @@ describe "Enumerable#take_while" do
it "doesn't return self when it could" do
a = [1,2,3]
- a.take_while{true}.should_not equal(a)
+ a.take_while{true}.should_not.equal?(a)
end
it "calls the block with initial args when yielded with multiple arguments" do
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index 95c64c1294..deef741407 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -13,8 +13,8 @@ describe "Enumerable#tally" do
it "returns a hash without default" do
hash = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz').tally
- hash.default_proc.should be_nil
- hash.default.should be_nil
+ hash.default_proc.should == nil
+ hash.default.should == nil
end
it "returns an empty hash for empty enumerables" do
@@ -45,7 +45,7 @@ describe "Enumerable#tally with a hash" do
it "returns the given hash" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }
- enum.tally(hash).should equal(hash)
+ enum.tally(hash).should.equal?(hash)
end
it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
@@ -58,14 +58,14 @@ describe "Enumerable#tally with a hash" do
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
- -> { enum.tally(hash) }.should raise_error(FrozenError)
+ -> { enum.tally(hash) }.should.raise(FrozenError)
hash.should == { 'foo' => 1 }
end
it "raises a FrozenError even if enumerable is empty" do
enum = EnumerableSpecs::Numerous.new()
hash = { 'foo' => 1 }.freeze
- -> { enum.tally(hash) }.should raise_error(FrozenError)
+ -> { enum.tally(hash) }.should.raise(FrozenError)
end
it "does not call given block" do
@@ -86,6 +86,6 @@ describe "Enumerable#tally with a hash" do
it "needs the values counting each elements to be an integer" do
enum = EnumerableSpecs::Numerous.new('foo')
- -> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
+ -> { enum.tally({ 'foo' => 'bar' }) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/enumerable/to_h_spec.rb b/spec/ruby/core/enumerable/to_h_spec.rb
index 11a4933c10..38847eccfb 100644
--- a/spec/ruby/core/enumerable/to_h_spec.rb
+++ b/spec/ruby/core/enumerable/to_h_spec.rb
@@ -36,12 +36,12 @@ describe "Enumerable#to_h" do
it "raises TypeError if an element is not an array" do
enum = EnumerableSpecs::EachDefiner.new(:x)
- -> { enum.to_h }.should raise_error(TypeError)
+ -> { enum.to_h }.should.raise(TypeError)
end
it "raises ArgumentError if an element is not a [key, value] pair" do
enum = EnumerableSpecs::EachDefiner.new([:x])
- -> { enum.to_h }.should raise_error(ArgumentError)
+ -> { enum.to_h }.should.raise(ArgumentError)
end
context "with block" do
@@ -64,17 +64,17 @@ describe "Enumerable#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
@enum.to_h { |k| [k, k.to_s, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
@enum.to_h { |k| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
@enum.to_h { |k| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -90,7 +90,7 @@ describe "Enumerable#to_h" do
-> do
@enum.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb
index c21a2772c4..7b04c72bce 100644
--- a/spec/ruby/core/enumerable/to_set_spec.rb
+++ b/spec/ruby/core/enumerable/to_set_spec.rb
@@ -1,29 +1,30 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Enumerable#to_set" do
- it "returns a new Set created from self" do
- [1, 2, 3].to_set.should == Set[1, 2, 3]
- {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
- end
+describe "Enumerable#to_set" do
+ it "returns a new Set created from self" do
+ [1, 2, 3].to_set.should == Set[1, 2, 3]
+ {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
+ end
- it "passes down passed blocks" do
- [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
- end
+ it "passes down passed blocks" do
+ [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+ ruby_version_is "4.0"..."4.1" do
it "instantiates an object of provided as the first argument set class" do
- set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)
- set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set = nil
+ proc{set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)}.should complain(/Enumerable#to_set/)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
set.to_a.sort.should == [1, 2, 3]
end
+ end
- it "does not need explicit `require 'set'`" do
- output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
- puts [1, 2, 3].to_set
- RUBY
-
- output.chomp.should == "#<Set: {1, 2, 3}>"
+ ruby_version_is ""..."4.0" do
+ it "instantiates an object of provided as the first argument set class" do
+ set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
end
end
end
diff --git a/spec/ruby/core/enumerable/zip_spec.rb b/spec/ruby/core/enumerable/zip_spec.rb
index ab148f2a6e..c5f9a3e4d4 100644
--- a/spec/ruby/core/enumerable/zip_spec.rb
+++ b/spec/ruby/core/enumerable/zip_spec.rb
@@ -39,8 +39,8 @@ describe "Enumerable#zip" do
end
it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do
- -> { EnumerableSpecs::Numerous.new(1,2,3).zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)")
- -> { EnumerableSpecs::Numerous.new(1,2,3).zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)")
- -> { EnumerableSpecs::Numerous.new(1,2,3).zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(Object.new) }.should.raise(TypeError, "wrong argument type Object (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(1) }.should.raise(TypeError, "wrong argument type Integer (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(true) }.should.raise(TypeError, "wrong argument type TrueClass (must respond to :each)")
end
end
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb
index d4fff3e01f..0a83019d49 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb
@@ -12,6 +12,6 @@ describe "Enumerator::ArithmeticSequence#each" do
end
it "returns self" do
- @seq.each { |item| }.should equal(@seq)
+ @seq.each { |item| }.should.equal?(@seq)
end
end
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb
index bdb308074b..a18c554fb3 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../../spec_helper'
describe "Enumerator::ArithmeticSequence#hash" do
it "is based on begin, end, step and exclude_end?" do
- 1.step(10).hash.should be_an_instance_of(Integer)
+ 1.step(10).hash.should.instance_of?(Integer)
1.step(10).hash.should == 1.step(10).hash
1.step(10, 5).hash.should == 1.step(10, 5).hash
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb
index 2015983826..1bd2f7f0f7 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb
@@ -4,7 +4,7 @@ describe "Enumerator::ArithmeticSequence.new" do
it "is not defined" do
-> {
Enumerator::ArithmeticSequence.new
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -12,6 +12,6 @@ describe "Enumerator::ArithmeticSequence.allocate" do
it "is not defined" do
-> {
Enumerator::ArithmeticSequence.allocate
- }.should raise_error(TypeError, 'allocator undefined for Enumerator::ArithmeticSequence')
+ }.should.raise(TypeError, 'allocator undefined for Enumerator::ArithmeticSequence')
end
end
diff --git a/spec/ruby/core/enumerator/chain/initialize_spec.rb b/spec/ruby/core/enumerator/chain/initialize_spec.rb
index daa30351d7..1df1dec5f8 100644
--- a/spec/ruby/core/enumerator/chain/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/chain/initialize_spec.rb
@@ -6,26 +6,26 @@ describe "Enumerator::Chain#initialize" do
end
it "is a private method" do
- Enumerator::Chain.should have_private_instance_method(:initialize, false)
+ Enumerator::Chain.private_instance_methods(false).should.include?(:initialize)
end
it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
+ @uninitialized.send(:initialize).should.equal?(@uninitialized)
end
it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
+ @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should.equal?(@uninitialized)
end
it "accepts arguments that are not Enumerable nor responding to :each" do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
+ @uninitialized.send(:initialize, Object.new).should.equal?(@uninitialized)
end
describe "on frozen instance" do
it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize)
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/chain/rewind_spec.rb b/spec/ruby/core/enumerator/chain/rewind_spec.rb
index 5f51ce2cf1..4525b82f7b 100644
--- a/spec/ruby/core/enumerator/chain/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/chain/rewind_spec.rb
@@ -10,7 +10,7 @@ describe "Enumerator::Chain#rewind" do
end
it "returns self" do
- @enum.rewind.should equal @enum
+ @enum.rewind.should.equal? @enum
end
it "does nothing if receiver has not been iterated" do
@@ -35,7 +35,7 @@ describe "Enumerator::Chain#rewind" do
@obj.should_not_receive(:rewind)
@second.should_receive(:rewind).and_raise(RuntimeError)
@enum.each {}
- -> { @enum.rewind }.should raise_error(RuntimeError)
+ -> { @enum.rewind }.should.raise(RuntimeError)
end
it "calls rewind only for objects that have actually been iterated on" do
@@ -45,7 +45,7 @@ describe "Enumerator::Chain#rewind" do
@obj.should_receive(:rewind)
@second.should_not_receive(:rewind)
- -> { @enum.each {} }.should raise_error(RuntimeError)
+ -> { @enum.each {} }.should.raise(RuntimeError)
@enum.rewind
end
end
diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb
index 3af16e5587..03be53fe05 100644
--- a/spec/ruby/core/enumerator/each_spec.rb
+++ b/spec/ruby/core/enumerator/each_spec.rb
@@ -51,17 +51,17 @@ describe "Enumerator#each" do
enum = Object.new.to_enum
-> do
enum.each { |e| e }
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "returns self if not given arguments and not given a block" do
- @enum_with_arguments.each.should equal(@enum_with_arguments)
+ @enum_with_arguments.each.should.equal?(@enum_with_arguments)
- @enum_with_yielder.each.should equal(@enum_with_yielder)
+ @enum_with_yielder.each.should.equal?(@enum_with_yielder)
end
it "returns the same value from receiver.each if block is given" do
- @enum_with_arguments.each {}.should equal(:method_returned)
+ @enum_with_arguments.each {}.should.equal?(:method_returned)
end
it "passes given arguments at initialized to receiver.each" do
@@ -78,12 +78,27 @@ describe "Enumerator#each" do
end
it "returns the same value from receiver.each if block and arguments are given" do
- @enum_with_arguments.each(:each1, :each2) {}.should equal(:method_returned)
+ @enum_with_arguments.each(:each1, :each2) {}.should.equal?(:method_returned)
end
it "returns new Enumerator if given arguments but not given a block" do
ret = @enum_with_arguments.each 1
- ret.should be_an_instance_of(Enumerator)
- ret.should_not equal(@enum_with_arguments)
+ ret.should.instance_of?(Enumerator)
+ ret.should_not.equal?(@enum_with_arguments)
+ end
+
+ it "does not destructure yielded array values when chaining each.map" do
+ result = [[[1]]].each.map { |a, b| [a, b] }
+ result.should == [[[1], nil]]
+ end
+
+ it "preserves array values yielded from the enumerator" do
+ result = [[1, 2]].each.map { |a| a }
+ result.should == [[1, 2]]
+ end
+
+ it "allows destructuring to occur in the block, not the enumerator" do
+ result = [[1, 2]].each.map { |a, b| a }
+ result.should == [1]
end
end
diff --git a/spec/ruby/core/enumerator/each_with_index_spec.rb b/spec/ruby/core/enumerator/each_with_index_spec.rb
index 4898e86fa9..0630b7045e 100644
--- a/spec/ruby/core/enumerator/each_with_index_spec.rb
+++ b/spec/ruby/core/enumerator/each_with_index_spec.rb
@@ -9,14 +9,14 @@ describe "Enumerator#each_with_index" do
it "returns a new Enumerator when no block is given" do
enum1 = [1,2,3].select
enum2 = enum1.each_with_index
- enum2.should be_an_instance_of(Enumerator)
+ enum2.should.instance_of?(Enumerator)
enum1.should_not == enum2
end
it "raises an ArgumentError if passed extra arguments" do
-> do
[1].to_enum.each_with_index(:glark)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "passes on the given block's return value" do
diff --git a/spec/ruby/core/enumerator/feed_spec.rb b/spec/ruby/core/enumerator/feed_spec.rb
index e387c6cd39..781947a8c7 100644
--- a/spec/ruby/core/enumerator/feed_spec.rb
+++ b/spec/ruby/core/enumerator/feed_spec.rb
@@ -33,20 +33,20 @@ describe "Enumerator#feed" do
end
it "returns nil" do
- @enum.feed(:a).should be_nil
+ @enum.feed(:a).should == nil
end
it "raises a TypeError if called more than once without advancing the enumerator" do
@enum.feed :a
@enum.next
- -> { @enum.feed :b }.should raise_error(TypeError)
+ -> { @enum.feed :b }.should.raise(TypeError)
end
it "sets the return value of Yielder#yield" do
enum = Enumerator.new { |y| ScratchPad << y.yield }
enum.next
enum.feed :a
- -> { enum.next }.should raise_error(StopIteration)
+ -> { enum.next }.should.raise(StopIteration)
ScratchPad.recorded.should == [:a]
end
end
diff --git a/spec/ruby/core/enumerator/generator/each_spec.rb b/spec/ruby/core/enumerator/generator/each_spec.rb
deleted file mode 100644
index a43805dd16..0000000000
--- a/spec/ruby/core/enumerator/generator/each_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Generator#each" do
- before :each do
- @generator = Enumerator::Generator.new do |y, *args|
- y << 3 << 2 << 1
- y << args unless args.empty?
- :block_returned
- end
- end
-
- it "is an enumerable" do
- @generator.should be_kind_of(Enumerable)
- end
-
- it "supports enumeration with a block" do
- r = []
- @generator.each { |v| r << v }
-
- r.should == [3, 2, 1]
- end
-
- it "raises a LocalJumpError if no block given" do
- -> { @generator.each }.should raise_error(LocalJumpError)
- end
-
- it "returns the block returned value" do
- @generator.each {}.should equal(:block_returned)
- end
-
- it "requires multiple arguments" do
- Enumerator::Generator.instance_method(:each).arity.should < 0
- end
-
- it "appends given arguments to receiver.each" do
- yields = []
- @generator.each(:each0, :each1) { |yielded| yields << yielded }
- yields.should == [3, 2, 1, [:each0, :each1]]
- end
-end
diff --git a/spec/ruby/core/enumerator/generator/initialize_spec.rb b/spec/ruby/core/enumerator/generator/initialize_spec.rb
deleted file mode 100644
index acc1174253..0000000000
--- a/spec/ruby/core/enumerator/generator/initialize_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Generator#initialize" do
- before :each do
- @class = Enumerator::Generator
- @uninitialized = @class.allocate
- end
-
- it "is a private method" do
- @class.should have_private_instance_method(:initialize, false)
- end
-
- it "returns self when given a block" do
- @uninitialized.send(:initialize) {}.should equal(@uninitialized)
- end
-
- describe "on frozen instance" do
- it "raises a FrozenError" do
- -> {
- @uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/initialize_spec.rb b/spec/ruby/core/enumerator/initialize_spec.rb
index 5e0256ca46..9929494b5a 100644
--- a/spec/ruby/core/enumerator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/initialize_spec.rb
@@ -8,11 +8,11 @@ describe "Enumerator#initialize" do
end
it "is a private method" do
- Enumerator.should have_private_instance_method(:initialize, false)
+ Enumerator.private_instance_methods(false).should.include?(:initialize)
end
it "returns self when given a block" do
- @uninitialized.send(:initialize) {}.should equal(@uninitialized)
+ @uninitialized.send(:initialize) {}.should.equal?(@uninitialized)
end
# Maybe spec should be broken up?
@@ -21,22 +21,22 @@ describe "Enumerator#initialize" do
r = yielder.yield 3
yielder << r << 2 << 1
end
- @uninitialized.should be_an_instance_of(Enumerator)
+ @uninitialized.should.instance_of?(Enumerator)
r = []
@uninitialized.each{|x| r << x; x * 2}
r.should == [3, 6, 2, 1]
end
it "sets size to nil if size is not given" do
- @uninitialized.send(:initialize) {}.size.should be_nil
+ @uninitialized.send(:initialize) {}.size.should == nil
end
it "sets size to nil if the given size is nil" do
- @uninitialized.send(:initialize, nil) {}.size.should be_nil
+ @uninitialized.send(:initialize, nil) {}.size.should == nil
end
it "sets size to the given size if the given size is Float::INFINITY" do
- @uninitialized.send(:initialize, Float::INFINITY) {}.size.should equal(Float::INFINITY)
+ @uninitialized.send(:initialize, Float::INFINITY) {}.size.should.equal?(Float::INFINITY)
end
it "sets size to the given size if the given size is an Integer" do
@@ -51,7 +51,7 @@ describe "Enumerator#initialize" do
it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/chunk_spec.rb b/spec/ruby/core/enumerator/lazy/chunk_spec.rb
index 87d2b0c206..d0179d32b6 100644
--- a/spec/ruby/core/enumerator/lazy/chunk_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/chunk_spec.rb
@@ -17,8 +17,8 @@ describe "Enumerator::Lazy#chunk" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.chunk {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -27,7 +27,7 @@ describe "Enumerator::Lazy#chunk" do
it "returns an Enumerator if called without a block" do
chunk = @yieldsmixed.chunk
- chunk.should be_an_instance_of(Enumerator::Lazy)
+ chunk.should.instance_of?(Enumerator::Lazy)
res = chunk.each { |v| true }.force
res.should == [[true, EnumeratorLazySpecs::YieldsMixed.gathered_yields]]
diff --git a/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb b/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb
index 772bd42de9..edba8e1363 100644
--- a/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/chunk_while_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#chunk_while" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.chunk_while { |a, b| false }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.chunk_while { |a, b| false }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb
index 65c544f062..7305e1c9c4 100644
--- a/spec/ruby/core/enumerator/lazy/compact_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Enumerator::Lazy#compact" do
it 'returns array without nil elements' do
arr = [1, nil, 3, false, 5].to_enum.lazy.compact
- arr.should be_an_instance_of(Enumerator::Lazy)
+ arr.should.instance_of?(Enumerator::Lazy)
arr.force.should == [1, 3, false, 5]
end
diff --git a/spec/ruby/core/enumerator/lazy/drop_spec.rb b/spec/ruby/core/enumerator/lazy/drop_spec.rb
index 822b8034fb..95ac7e9ecc 100644
--- a/spec/ruby/core/enumerator/lazy/drop_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/drop_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#drop" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.drop(1)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets difference of given count with old size to new size" do
diff --git a/spec/ruby/core/enumerator/lazy/drop_while_spec.rb b/spec/ruby/core/enumerator/lazy/drop_while_spec.rb
index 4f6e366f88..65f3007dec 100644
--- a/spec/ruby/core/enumerator/lazy/drop_while_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/drop_while_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#drop_while" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.drop_while {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -40,7 +40,7 @@ describe "Enumerator::Lazy#drop_while" do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.drop_while }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.drop_while }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/grep_spec.rb b/spec/ruby/core/enumerator/lazy/grep_spec.rb
index e67686c9a3..383f80a918 100644
--- a/spec/ruby/core/enumerator/lazy/grep_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/grep_spec.rb
@@ -20,12 +20,12 @@ describe "Enumerator::Lazy#grep" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.grep(Object) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
ret = @yieldsmixed.grep(Object)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
diff --git a/spec/ruby/core/enumerator/lazy/grep_v_spec.rb b/spec/ruby/core/enumerator/lazy/grep_v_spec.rb
index 67173021bb..19c917f254 100644
--- a/spec/ruby/core/enumerator/lazy/grep_v_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/grep_v_spec.rb
@@ -18,12 +18,12 @@ describe "Enumerator::Lazy#grep_v" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.grep_v(Object) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
ret = @yieldsmixed.grep_v(Object)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
diff --git a/spec/ruby/core/enumerator/lazy/initialize_spec.rb b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
index e1e0b1d608..47765d32c3 100644
--- a/spec/ruby/core/enumerator/lazy/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
@@ -16,11 +16,11 @@ describe "Enumerator::Lazy#initialize" do
end
it "is a private method" do
- Enumerator::Lazy.should have_private_instance_method(:initialize, false)
+ Enumerator::Lazy.private_instance_methods(false).should.include?(:initialize)
end
it "returns self" do
- @uninitialized.send(:initialize, @receiver) {}.should equal(@uninitialized)
+ @uninitialized.send(:initialize, @receiver) {}.should.equal?(@uninitialized)
end
describe "when the returned lazy enumerator is evaluated by Enumerable#first" do
@@ -32,15 +32,15 @@ describe "Enumerator::Lazy#initialize" do
end
it "sets #size to nil if not given a size" do
- @uninitialized.send(:initialize, @receiver) {}.size.should be_nil
+ @uninitialized.send(:initialize, @receiver) {}.size.should == nil
end
it "sets #size to nil if given size is nil" do
- @uninitialized.send(:initialize, @receiver, nil) {}.size.should be_nil
+ @uninitialized.send(:initialize, @receiver, nil) {}.size.should == nil
end
it "sets given size to own size if the given size is Float::INFINITY" do
- @uninitialized.send(:initialize, @receiver, Float::INFINITY) {}.size.should equal(Float::INFINITY)
+ @uninitialized.send(:initialize, @receiver, Float::INFINITY) {}.size.should.equal?(Float::INFINITY)
end
it "sets given size to own size if the given size is an Integer" do
@@ -52,12 +52,12 @@ describe "Enumerator::Lazy#initialize" do
end
it "raises an ArgumentError when block is not given" do
- -> { @uninitialized.send :initialize, @receiver }.should raise_error(ArgumentError)
+ -> { @uninitialized.send :initialize, @receiver }.should.raise(ArgumentError)
end
describe "on frozen instance" do
it "raises a FrozenError" do
- -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(FrozenError)
+ -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
index b43864b673..12107383d6 100644
--- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
@@ -4,24 +4,24 @@ require_relative '../../../spec_helper'
describe "Enumerator::Lazy" do
it "is a subclass of Enumerator" do
- Enumerator::Lazy.superclass.should equal(Enumerator)
+ Enumerator::Lazy.superclass.should.equal?(Enumerator)
end
it "defines lazy versions of a whitelist of Enumerator methods" do
- lazy_methods = [
+ lazy_methods = Set[
:chunk, :chunk_while, :collect, :collect_concat, :compact, :drop, :drop_while, :enum_for,
:find_all, :flat_map, :force, :grep, :grep_v, :lazy, :map, :reject,
:select, :slice_after, :slice_before, :slice_when, :take, :take_while,
:to_enum, :uniq, :zip
]
- Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
+ Enumerator::Lazy.instance_methods(false).to_set.should >= lazy_methods
end
end
describe "Enumerator::Lazy#lazy" do
it "returns self" do
lazy = (1..3).to_enum.lazy
- lazy.lazy.should equal(lazy)
+ lazy.lazy.should.equal?(lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/reject_spec.rb b/spec/ruby/core/enumerator/lazy/reject_spec.rb
index 0e1632d667..374d4df14e 100644
--- a/spec/ruby/core/enumerator/lazy/reject_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/reject_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#reject" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.reject {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -42,7 +42,7 @@ describe "Enumerator::Lazy#reject" do
-> {
lazy.first
- }.should raise_error(RuntimeError, "foo")
+ }.should.raise(RuntimeError, "foo")
end
it "calls the block with a gathered array when yield with multiple arguments" do
@@ -52,7 +52,7 @@ describe "Enumerator::Lazy#reject" do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.reject }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.reject }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/shared/collect.rb b/spec/ruby/core/enumerator/lazy/shared/collect.rb
index 5690255a0c..0ed04c8e02 100644
--- a/spec/ruby/core/enumerator/lazy/shared/collect.rb
+++ b/spec/ruby/core/enumerator/lazy/shared/collect.rb
@@ -16,8 +16,8 @@ describe :enumerator_lazy_collect, shared: true do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.send(@method) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "keeps size" do
diff --git a/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb b/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb
index 00d7941a61..685e6d0594 100644
--- a/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb
+++ b/spec/ruby/core/enumerator/lazy/shared/collect_concat.rb
@@ -16,8 +16,8 @@ describe :enumerator_lazy_collect_concat, shared: true do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.send(@method) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -34,7 +34,7 @@ describe :enumerator_lazy_collect_concat, shared: true do
it "flattens elements when the given block returned an array or responding to .each and .force" do
(0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.chars }.first(6).should == %w[0 1 0 2 0 3]
- (0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should be_true
+ (0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should == true
(0..Float::INFINITY).lazy.send(@method) { |n| (n * 10).to_s.each_char.lazy }.first(6).should == %w[0 1 0 2 0 3]
end
end
@@ -46,7 +46,7 @@ describe :enumerator_lazy_collect_concat, shared: true do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.send(@method) }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.send(@method) }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
@@ -64,7 +64,7 @@ describe :enumerator_lazy_collect_concat, shared: true do
it "flattens elements when the given block returned an array or responding to .each and .force" do
(0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.chars }.first(6).should == %w[0 1 0 2 0 3]
- (0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should be_true
+ (0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.each_char }.first(6).all? { |o| o.instance_of? Enumerator }.should == true
(0..Float::INFINITY).lazy.map {|n| n * 10 }.send(@method) { |n| n.to_s.each_char.lazy }.first(6).should == %w[0 1 0 2 0 3]
end
end
diff --git a/spec/ruby/core/enumerator/lazy/shared/select.rb b/spec/ruby/core/enumerator/lazy/shared/select.rb
index 50a00bcbf4..2d15176620 100644
--- a/spec/ruby/core/enumerator/lazy/shared/select.rb
+++ b/spec/ruby/core/enumerator/lazy/shared/select.rb
@@ -16,8 +16,8 @@ describe :enumerator_lazy_select, shared: true do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.send(@method) {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -40,7 +40,7 @@ describe :enumerator_lazy_select, shared: true do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.send(@method) }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.send(@method) }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/shared/to_enum.rb b/spec/ruby/core/enumerator/lazy/shared/to_enum.rb
index 0c91ea55b9..75b9aefe8c 100644
--- a/spec/ruby/core/enumerator/lazy/shared/to_enum.rb
+++ b/spec/ruby/core/enumerator/lazy/shared/to_enum.rb
@@ -13,8 +13,8 @@ describe :enumerator_lazy_to_enum, shared: true do
it "returns a new instance of Enumerator::Lazy" do
ret = @infinite.send @method
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@infinite)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@infinite)
end
it "sets #size to nil when not given a block" do
@@ -43,7 +43,7 @@ describe :enumerator_lazy_to_enum, shared: true do
each_entry: [],
each_cons: [2]
}.each_pair do |method, args|
- @infinite.send(method, *args).should be_an_instance_of(Enumerator::Lazy)
+ @infinite.send(method, *args).should.instance_of?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/slice_after_spec.rb b/spec/ruby/core/enumerator/lazy/slice_after_spec.rb
index 8b08a1ecfd..f8cd97178f 100644
--- a/spec/ruby/core/enumerator/lazy/slice_after_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/slice_after_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#slice_after" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.slice_after { |n| true }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.slice_after { |n| true }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/slice_before_spec.rb b/spec/ruby/core/enumerator/lazy/slice_before_spec.rb
index 9c1ec9ba4a..192e853343 100644
--- a/spec/ruby/core/enumerator/lazy/slice_before_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/slice_before_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#slice_before" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.slice_before { |n| true }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.slice_before { |n| true }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/slice_when_spec.rb b/spec/ruby/core/enumerator/lazy/slice_when_spec.rb
index f83403425d..fc9d5f5069 100644
--- a/spec/ruby/core/enumerator/lazy/slice_when_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/slice_when_spec.rb
@@ -9,6 +9,6 @@ describe "Enumerator::Lazy#slice_when" do
it "should return a lazy enumerator" do
s = 0..Float::INFINITY
- s.lazy.slice_when { |a, b| true }.should be_kind_of(Enumerator::Lazy)
+ s.lazy.slice_when { |a, b| true }.should.is_a?(Enumerator::Lazy)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/take_spec.rb b/spec/ruby/core/enumerator/lazy/take_spec.rb
index 9fc17e969f..2dd5b939e2 100644
--- a/spec/ruby/core/enumerator/lazy/take_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/take_spec.rb
@@ -2,8 +2,16 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../../enumerable/shared/value_packing'
describe "Enumerator::Lazy#take" do
+ describe "value packing of source yields (matches Enumerable#take)" do
+ before :each do
+ @take = -> e { e.lazy.take(1) }
+ end
+ it_behaves_like :enumerable_value_packing, nil
+ end
+
before :each do
@yieldsmixed = EnumeratorLazySpecs::YieldsMixed.new.to_enum.lazy
@eventsmixed = EnumeratorLazySpecs::EventsMixed.new.to_enum.lazy
@@ -16,8 +24,8 @@ describe "Enumerator::Lazy#take" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.take(1)
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets given count to size if the given count is less than old size" do
diff --git a/spec/ruby/core/enumerator/lazy/take_while_spec.rb b/spec/ruby/core/enumerator/lazy/take_while_spec.rb
index bcea0b1419..c369712c56 100644
--- a/spec/ruby/core/enumerator/lazy/take_while_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/take_while_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#take_while" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.take_while {}
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "sets #size to nil" do
@@ -40,7 +40,7 @@ describe "Enumerator::Lazy#take_while" do
end
it "raises an ArgumentError when not given a block" do
- -> { @yieldsmixed.take_while }.should raise_error(ArgumentError)
+ -> { @yieldsmixed.take_while }.should.raise(ArgumentError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/lazy/uniq_spec.rb b/spec/ruby/core/enumerator/lazy/uniq_spec.rb
index ce67ace5ab..d30ed8df2f 100644
--- a/spec/ruby/core/enumerator/lazy/uniq_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/uniq_spec.rb
@@ -8,7 +8,7 @@ describe 'Enumerator::Lazy#uniq' do
end
it 'returns a lazy enumerator' do
- @lazy.should be_an_instance_of(Enumerator::Lazy)
+ @lazy.should.instance_of?(Enumerator::Lazy)
@lazy.force.should == [0, 1]
end
@@ -28,7 +28,7 @@ describe 'Enumerator::Lazy#uniq' do
end
it 'returns a lazy enumerator' do
- @lazy.should be_an_instance_of(Enumerator::Lazy)
+ @lazy.should.instance_of?(Enumerator::Lazy)
@lazy.force.should == [0, 1]
end
diff --git a/spec/ruby/core/enumerator/lazy/with_index_spec.rb b/spec/ruby/core/enumerator/lazy/with_index_spec.rb
index a6b5c38777..2e983fd3b1 100644
--- a/spec/ruby/core/enumerator/lazy/with_index_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/with_index_spec.rb
@@ -17,7 +17,7 @@ describe "Enumerator::Lazy#with_index" do
end
it "raises TypeError when offset does not convert to Integer" do
- -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError)
+ -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should.raise(TypeError)
end
it "enumerates with a given block" do
diff --git a/spec/ruby/core/enumerator/lazy/zip_spec.rb b/spec/ruby/core/enumerator/lazy/zip_spec.rb
index 5a828c1dcc..9f612542d7 100644
--- a/spec/ruby/core/enumerator/lazy/zip_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/zip_spec.rb
@@ -16,8 +16,8 @@ describe "Enumerator::Lazy#zip" do
it "returns a new instance of Enumerator::Lazy" do
ret = @yieldsmixed.zip []
- ret.should be_an_instance_of(Enumerator::Lazy)
- ret.should_not equal(@yieldsmixed)
+ ret.should.instance_of?(Enumerator::Lazy)
+ ret.should_not.equal?(@yieldsmixed)
end
it "keeps size" do
@@ -40,11 +40,11 @@ describe "Enumerator::Lazy#zip" do
end
it "returns a Lazy when no arguments given" do
- @yieldsmixed.zip.should be_an_instance_of(Enumerator::Lazy)
+ @yieldsmixed.zip.should.instance_of?(Enumerator::Lazy)
end
it "raises a TypeError if arguments contain non-list object" do
- -> { @yieldsmixed.zip [], Object.new, [] }.should raise_error(TypeError)
+ -> { @yieldsmixed.zip [], Object.new, [] }.should.raise(TypeError)
end
describe "on a nested Lazy" do
diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb
index 671912224f..eb6c13759e 100644
--- a/spec/ruby/core/enumerator/new_spec.rb
+++ b/spec/ruby/core/enumerator/new_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Enumerator.new" do
context "no block given" do
it "raises" do
- -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
+ -> { Enumerator.new(1, :upto, 3) }.should.raise(ArgumentError)
end
end
@@ -42,35 +42,74 @@ describe "Enumerator.new" do
enum.to_a.should == ["a\n", "b\n", "c"]
end
- describe 'yielded values' do
- it 'handles yield arguments properly' do
+ describe '#yield' do
+ it 'accepts a single argument' do
Enumerator.new { |y| y.yield(1) }.to_a.should == [1]
Enumerator.new { |y| y.yield(1) }.first.should == 1
+ end
- Enumerator.new { |y| y.yield([1]) }.to_a.should == [[1]]
- Enumerator.new { |y| y.yield([1]) }.first.should == [1]
-
+ it 'accepts multiple arguments' do
Enumerator.new { |y| y.yield(1, 2) }.to_a.should == [[1, 2]]
Enumerator.new { |y| y.yield(1, 2) }.first.should == [1, 2]
+ end
+
+ it "doesn't double-wrap arrays" do
+ Enumerator.new { |y| y.yield([1]) }.to_a.should == [[1]]
+ Enumerator.new { |y| y.yield([1]) }.first.should == [1]
Enumerator.new { |y| y.yield([1, 2]) }.to_a.should == [[1, 2]]
Enumerator.new { |y| y.yield([1, 2]) }.first.should == [1, 2]
end
- it 'handles << arguments properly' do
+ it 'returns nil' do
+ ScratchPad.record []
+ Enumerator.new do |y|
+ ScratchPad << y.yield(1)
+ end.to_a
+
+ ScratchPad.recorded.should == [nil]
+ end
+
+ it 'accepts keyword arguments and treats them as a positional hash' do
+ Enumerator.new { |y| y.yield(foo: 42) }.to_a.should == [{ foo: 42 }]
+ Enumerator.new { |y| y.yield(foo: 42) }.first.should == { foo: 42 }
+
+ Enumerator.new { |y| y.yield(123, foo: 42) }.to_a.should == [[123, { foo: 42 }]]
+ Enumerator.new { |y| y.yield(123, foo: 42) }.first.should == [123, { foo: 42 }]
+ end
+ end
+
+ describe '#<<' do
+ it 'accepts a single argument' do
Enumerator.new { |y| y.<<(1) }.to_a.should == [1]
Enumerator.new { |y| y.<<(1) }.first.should == 1
+ end
+ it "doesn't double-wrap arrays" do
Enumerator.new { |y| y.<<([1]) }.to_a.should == [[1]]
Enumerator.new { |y| y.<<([1]) }.first.should == [1]
- # << doesn't accept multiple arguments
- # Enumerator.new { |y| y.<<(1, 2) }.to_a.should == [[1, 2]]
- # Enumerator.new { |y| y.<<(1, 2) }.first.should == [1, 2]
-
Enumerator.new { |y| y.<<([1, 2]) }.to_a.should == [[1, 2]]
Enumerator.new { |y| y.<<([1, 2]) }.first.should == [1, 2]
end
+
+ it 'accepts keyword arguments and treats them as a positional hash' do
+ Enumerator.new { |y| y.<<(foo: 42) }.to_a.should == [{ foo: 42 }]
+ Enumerator.new { |y| y.<<(foo: 42) }.first.should == { foo: 42 }
+ end
+
+ it 'can be chained' do
+ enum = Enumerator.new do |y|
+ y << 1 << 2
+ end
+ enum.to_a.should == [1, 2]
+ end
+
+ it 'raises ArgumentError when given more than one argument' do
+ -> {
+ Enumerator.new { |y| y.<<(1, 2) }.to_a
+ }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
end
end
end
diff --git a/spec/ruby/core/enumerator/next_spec.rb b/spec/ruby/core/enumerator/next_spec.rb
index a5e01a399d..77e79185a9 100644
--- a/spec/ruby/core/enumerator/next_spec.rb
+++ b/spec/ruby/core/enumerator/next_spec.rb
@@ -13,14 +13,14 @@ describe "Enumerator#next" do
it "raises a StopIteration exception at the end of the stream" do
3.times { @enum.next }
- -> { @enum.next }.should raise_error(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
end
it "cannot be called again until the enumerator is rewound" do
3.times { @enum.next }
- -> { @enum.next }.should raise_error(StopIteration)
- -> { @enum.next }.should raise_error(StopIteration)
- -> { @enum.next }.should raise_error(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
+ -> { @enum.next }.should.raise(StopIteration)
@enum.rewind
@enum.next.should == 1
end
diff --git a/spec/ruby/core/enumerator/next_values_spec.rb b/spec/ruby/core/enumerator/next_values_spec.rb
index 2202700c58..63e024e2b4 100644
--- a/spec/ruby/core/enumerator/next_values_spec.rb
+++ b/spec/ruby/core/enumerator/next_values_spec.rb
@@ -56,6 +56,6 @@ describe "Enumerator#next_values" do
it "raises StopIteration if called on a finished enumerator" do
8.times { @e.next }
- -> { @e.next_values }.should raise_error(StopIteration)
+ -> { @e.next_values }.should.raise(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/peek_spec.rb b/spec/ruby/core/enumerator/peek_spec.rb
index 2334385437..096fd2b10c 100644
--- a/spec/ruby/core/enumerator/peek_spec.rb
+++ b/spec/ruby/core/enumerator/peek_spec.rb
@@ -31,6 +31,6 @@ describe "Enumerator#peek" do
it "raises StopIteration if called on a finished enumerator" do
5.times { @e.next }
- -> { @e.peek }.should raise_error(StopIteration)
+ -> { @e.peek }.should.raise(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/peek_values_spec.rb b/spec/ruby/core/enumerator/peek_values_spec.rb
index 8b84fc8afc..63f7988bcd 100644
--- a/spec/ruby/core/enumerator/peek_values_spec.rb
+++ b/spec/ruby/core/enumerator/peek_values_spec.rb
@@ -58,6 +58,6 @@ describe "Enumerator#peek_values" do
it "raises StopIteration if called on a finished enumerator" do
8.times { @e.next }
- -> { @e.peek_values }.should raise_error(StopIteration)
+ -> { @e.peek_values }.should.raise(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/plus_spec.rb b/spec/ruby/core/enumerator/plus_spec.rb
index 755be5b4eb..d6c0fa93ac 100644
--- a/spec/ruby/core/enumerator/plus_spec.rb
+++ b/spec/ruby/core/enumerator/plus_spec.rb
@@ -12,7 +12,7 @@ describe "Enumerator#+" do
chain = one + two + three
- chain.should be_an_instance_of(Enumerator::Chain)
+ chain.should.instance_of?(Enumerator::Chain)
chain.each { |item| ScratchPad << item }
ScratchPad.recorded.should == [1, 2, 3]
end
diff --git a/spec/ruby/core/enumerator/produce_spec.rb b/spec/ruby/core/enumerator/produce_spec.rb
index c69fb49303..eb1b09294e 100644
--- a/spec/ruby/core/enumerator/produce_spec.rb
+++ b/spec/ruby/core/enumerator/produce_spec.rb
@@ -3,6 +3,8 @@ require_relative '../../spec_helper'
describe "Enumerator.produce" do
it "creates an infinite enumerator" do
enum = Enumerator.produce(0) { |prev| prev + 1 }
+
+ enum.size.should == Float::INFINITY
enum.take(5).should == [0, 1, 2, 3, 4]
end
@@ -31,4 +33,46 @@ describe "Enumerator.produce" do
lines.should == ["a\n", "b\n", "c\n", "d"]
end
end
+
+ it "raises ArgumentError when no block is given" do
+ -> { Enumerator.produce }.should.raise(ArgumentError, "no block given")
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "accepts keyword arguments as the initial value" do
+ enum = Enumerator.produce(a: 1, b: 1) {}
+ enum.take(1).should == [{a: 1, b: 1}]
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError for unknown keyword arguments" do
+ -> { Enumerator.produce(a: 1, b: 1) {} }.should.raise(ArgumentError, /unknown keywords/)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ context "with size keyword argument" do
+ it "sets the size of the enumerator" do
+ enum = Enumerator.produce(0, size: 10) { |n| n + 1 }
+
+ enum.size.should == 10
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
+
+ it "accepts a callable" do
+ enum = Enumerator.produce(0, size: -> { 5 * 5 }) { |n| n + 1 }
+
+ enum.size.should == 25
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
+
+ it "accepts nil" do
+ enum = Enumerator.produce(0, size: nil) { |n| n + 1 }
+
+ enum.size.should == nil
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb
index cabeb9d93a..a5dced4db1 100644
--- a/spec/ruby/core/enumerator/product/each_spec.rb
+++ b/spec/ruby/core/enumerator/product/each_spec.rb
@@ -1,73 +1,85 @@
require_relative '../../../spec_helper'
require_relative '../../enumerable/shared/enumeratorized'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#each" do
- it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
-
- it "yields each element of Cartesian product of enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+describe "Enumerator::Product#each" do
+ it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
+
+ it "yields each element of Cartesian product of enumerators" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ acc = []
+ enum.each { |e| acc << e }
+ acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "calls #each_entry method on enumerators" do
- object1 = Object.new
- def object1.each_entry
- yield 1
- yield 2
- end
-
- object2 = Object.new
- def object2.each_entry
- yield :a
- yield :b
- end
-
- enum = Enumerator::Product.new(object1, object2)
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ it "calls #each_entry method on enumerators" do
+ object1 = Object.new
+ def object1.each_entry
+ yield 1
+ yield 2
end
- it "raises a NoMethodError if the object doesn't respond to #each_entry" do
- -> {
- Enumerator::Product.new(Object.new).each {}
- }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
+ object2 = Object.new
+ def object2.each_entry
+ yield :a
+ yield :b
end
- it "returns enumerator if not given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.should.kind_of?(Enumerator)
+ enum = Enumerator::Product.new(object1, object2)
+ acc = []
+ enum.each { |e| acc << e }
+ acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "raises a NoMethodError if the object doesn't respond to #each_entry" do
+ -> {
+ Enumerator::Product.new(Object.new).each {}
+ }.should.raise(NoMethodError, /undefined method [`']each_entry' for/)
+ end
- it "returns self if given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each {}.should.equal?(enum)
- end
+ it "returns enumerator if not given a block" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each.should.kind_of?(Enumerator)
- it "doesn't accept arguments" do
- Enumerator::Product.instance_method(:each).arity.should == 0
- end
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "yields each element to a block that takes multiple arguments" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
+ it "returns self if given a block" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each {}.should.equal?(enum)
+ end
- acc = []
- enum.each { |x, y| acc << x }
- acc.should == [1, 1, 2, 2]
+ it "doesn't accept arguments" do
+ Enumerator::Product.instance_method(:each).arity.should == 0
+ end
- acc = []
- enum.each { |x, y| acc << y }
- acc.should == [:a, :b, :a, :b]
+ it "yields each element to a block that takes multiple arguments" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
- acc = []
- enum.each { |x, y, z| acc << z }
- acc.should == [nil, nil, nil, nil]
- end
+ acc = []
+ enum.each { |x, y| acc << x }
+ acc.should == [1, 1, 2, 2]
+
+ acc = []
+ enum.each { |x, y| acc << y }
+ acc.should == [:a, :b, :a, :b]
+
+ acc = []
+ enum.each { |x, y, z| acc << z }
+ acc.should == [nil, nil, nil, nil]
+ end
+
+ it "yields no element when any enumerable is empty" do
+ enum = Enumerator::Product.new([], [1])
+
+ acc = []
+ enum.each { |x| acc << x }
+ acc.should == []
+
+ enum = Enumerator::Product.new([1], [])
+
+ acc = []
+ enum.each { |x| acc << x }
+ acc.should == []
end
end
diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
index 46e8421322..b5d2b345a9 100644
--- a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
+++ b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
@@ -1,54 +1,52 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize_copy" do
- it "replaces content of the receiver with content of the other object" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
+describe "Enumerator::Product#initialize_copy" do
+ it "replaces content of the receiver with content of the other object" do
+ enum = Enumerator::Product.new([true, false])
+ enum2 = Enumerator::Product.new([1, 2], [:a, :b])
- enum.send(:initialize_copy, enum2)
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ enum.send(:initialize_copy, enum2)
+ enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "returns self" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
+ it "returns self" do
+ enum = Enumerator::Product.new([true, false])
+ enum2 = Enumerator::Product.new([1, 2], [:a, :b])
- enum.send(:initialize_copy, enum2).should.equal?(enum)
- end
+ enum.send(:initialize_copy, enum2).should.equal?(enum)
+ end
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
- end
+ it "is a private method" do
+ Enumerator::Product.private_instance_methods(false).should.include?(:initialize_copy)
+ end
- it "does nothing if the argument is the same as the receiver" do
- enum = Enumerator::Product.new(1..2)
- enum.send(:initialize_copy, enum).should.equal?(enum)
+ it "does nothing if the argument is the same as the receiver" do
+ enum = Enumerator::Product.new(1..2)
+ enum.send(:initialize_copy, enum).should.equal?(enum)
- enum.freeze
- enum.send(:initialize_copy, enum).should.equal?(enum)
- end
+ enum.freeze
+ enum.send(:initialize_copy, enum).should.equal?(enum)
+ end
- it "raises FrozenError if the receiver is frozen" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.new(3..4)
+ it "raises FrozenError if the receiver is frozen" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Enumerator::Product.new(3..4)
- -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
- end
+ -> { enum.freeze.send(:initialize_copy, enum2) }.should.raise(FrozenError)
+ end
- it "raises TypeError if the objects are of different class" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Class.new(Enumerator::Product).new(3..4)
+ it "raises TypeError if the objects are of different class" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Class.new(Enumerator::Product).new(3..4)
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- end
+ -> { enum.send(:initialize_copy, enum2) }.should.raise(TypeError, 'initialize_copy should take same class object')
+ -> { enum2.send(:initialize_copy, enum) }.should.raise(TypeError, 'initialize_copy should take same class object')
+ end
- it "raises ArgumentError if the argument is not initialized yet" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.allocate
+ it "raises ArgumentError if the argument is not initialized yet" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Enumerator::Product.allocate
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product')
- end
+ -> { enum.send(:initialize_copy, enum2) }.should.raise(ArgumentError, 'uninitialized product')
end
end
diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb
index 4b60564240..8814f9d3c7 100644
--- a/spec/ruby/core/enumerator/product/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/product/initialize_spec.rb
@@ -1,33 +1,31 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize" do
- before :each do
- @uninitialized = Enumerator::Product.allocate
- end
+describe "Enumerator::Product#initialize" do
+ before :each do
+ @uninitialized = Enumerator::Product.allocate
+ end
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize, false)
- end
+ it "is a private method" do
+ Enumerator::Product.private_instance_methods(false).should.include?(:initialize)
+ end
- it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
- end
+ it "returns self" do
+ @uninitialized.send(:initialize).should.equal?(@uninitialized)
+ end
- it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
- end
+ it "accepts many arguments" do
+ @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should.equal?(@uninitialized)
+ end
- it "accepts arguments that are not Enumerable nor responding to :each_entry" do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
- end
+ it "accepts arguments that are not Enumerable nor responding to :each_entry" do
+ @uninitialized.send(:initialize, Object.new).should.equal?(@uninitialized)
+ end
- describe "on frozen instance" do
- it "raises a FrozenError" do
- -> {
- @uninitialized.freeze.send(:initialize, 0..1)
- }.should raise_error(FrozenError)
- end
+ describe "on frozen instance" do
+ it "raises a FrozenError" do
+ -> {
+ @uninitialized.freeze.send(:initialize, 0..1)
+ }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/product/inspect_spec.rb b/spec/ruby/core/enumerator/product/inspect_spec.rb
index 1ea8e9c49b..e0d7441f26 100644
--- a/spec/ruby/core/enumerator/product/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/product/inspect_spec.rb
@@ -1,22 +1,20 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#inspect" do
- it "returns a String including enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
- end
+describe "Enumerator::Product#inspect" do
+ it "returns a String including enumerators" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
+ end
- it "represents a recursive element with '[...]'" do
- enum = [1, 2]
- enum_recursive = Enumerator::Product.new(enum)
+ it "represents a recursive element with '[...]'" do
+ enum = [1, 2]
+ enum_recursive = Enumerator::Product.new(enum)
- enum << enum_recursive
- enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
- end
+ enum << enum_recursive
+ enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
+ end
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
- end
+ it "returns a not initialized representation if #initialized is not called yet" do
+ Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
end
end
diff --git a/spec/ruby/core/enumerator/product/rewind_spec.rb b/spec/ruby/core/enumerator/product/rewind_spec.rb
index e8ee730239..2beffaf5c1 100644
--- a/spec/ruby/core/enumerator/product/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/product/rewind_spec.rb
@@ -1,64 +1,62 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#rewind" do
- before :each do
- @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
- end
+describe "Enumerator::Product#rewind" do
+ before :each do
+ @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
+ end
- it "resets the enumerator to its initial state" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "resets the enumerator to its initial state" do
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "returns self" do
- @enum.rewind.should.equal? @enum
- end
+ it "returns self" do
+ @enum.rewind.should.equal? @enum
+ end
- it "has no effect on a new enumerator" do
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "has no effect on a new enumerator" do
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "has no effect if called multiple, consecutive times" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "has no effect if called multiple, consecutive times" do
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ @enum.rewind
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "calls the enclosed object's rewind method if one exists" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
+ it "calls the enclosed object's rewind method if one exists" do
+ obj = mock('rewinder')
+ enum = Enumerator::Product.new(obj.to_enum)
- obj.should_receive(:rewind)
- enum.rewind
- end
+ obj.should_receive(:rewind)
+ enum.rewind
+ end
- it "does nothing if the object doesn't have a #rewind method" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
+ it "does nothing if the object doesn't have a #rewind method" do
+ obj = mock('rewinder')
+ enum = Enumerator::Product.new(obj.to_enum)
- enum.rewind.should == enum
- end
+ enum.rewind.should == enum
+ end
- it "calls a rewind method on each enumerable in direct order" do
- ScratchPad.record []
+ it "calls a rewind method on each enumerable in direct order" do
+ ScratchPad.record []
- object1 = Object.new
- def object1.rewind; ScratchPad << :object1; end
+ object1 = Object.new
+ def object1.rewind; ScratchPad << :object1; end
- object2 = Object.new
- def object2.rewind; ScratchPad << :object2; end
+ object2 = Object.new
+ def object2.rewind; ScratchPad << :object2; end
- object3 = Object.new
- def object3.rewind; ScratchPad << :object3; end
+ object3 = Object.new
+ def object3.rewind; ScratchPad << :object3; end
- enum = Enumerator::Product.new(object1, object2, object3)
- enum.rewind
+ enum = Enumerator::Product.new(object1, object2, object3)
+ enum.rewind
- ScratchPad.recorded.should == [:object1, :object2, :object3]
- end
+ ScratchPad.recorded.should == [:object1, :object2, :object3]
end
end
diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb
index 46958b1a22..0ba427af9a 100644
--- a/spec/ruby/core/enumerator/product/size_spec.rb
+++ b/spec/ruby/core/enumerator/product/size_spec.rb
@@ -1,56 +1,64 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#size" do
- it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do
- product = Enumerator::Product.new(1..2, 1..3, 1..4)
- product.size.should == 24 # 2 * 3 * 4
- end
+describe "Enumerator::Product#size" do
+ it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do
+ product = Enumerator::Product.new(1..2, 1..3, 1..4)
+ product.size.should == 24 # 2 * 3 * 4
+ end
- it "returns nil if any enumerable reports its size as nil" do
- enum = Object.new
- def enum.size; nil; end
+ it "returns nil if any enumerable reports its size as nil" do
+ enum = Object.new
+ def enum.size; nil; end
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
- it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do
- enum = Object.new
- def enum.size; Float::INFINITY; end
+ it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do
+ enum = Object.new
+ def enum.size; Float::INFINITY; end
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == Float::INFINITY
- end
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == Float::INFINITY
+ end
- it "returns nil if any enumerable reports its size as Float::NAN" do
- enum = Object.new
- def enum.size; Float::NAN; end
+ it "returns nil if any enumerable reports its size as Float::NAN" do
+ enum = Object.new
+ def enum.size; Float::NAN; end
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
- it "returns nil if any enumerable doesn't respond to #size" do
- enum = Object.new
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
+ it "returns nil if any enumerable doesn't respond to #size" do
+ enum = Object.new
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
- it "returns nil if any enumerable reports a not-convertible to Integer" do
- enum = Object.new
- def enum.size; :symbol; end
+ it "returns nil if any enumerable reports a not-convertible to Integer" do
+ enum = Object.new
+ def enum.size; :symbol; end
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
+
+ it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do
+ enum = Object.new
+ def enum.size; 1.0; end
+
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
- it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do
- enum = Object.new
- def enum.size; 1.0; end
+ ruby_version_is "3.4" do
+ it "returns zero when any enumerable reports zero" do
+ enum = Enumerator::Product.new(1...1, ["A", "B"])
+ enum.size.should == 0
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
+ enum = Enumerator::Product.new(["A", "B"], 1...1)
+ enum.size.should == 0
end
end
end
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
index 0acca6690e..0f37ef76e7 100644
--- a/spec/ruby/core/enumerator/product_spec.rb
+++ b/spec/ruby/core/enumerator/product_spec.rb
@@ -1,93 +1,91 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator.product" do
- it "returns a Cartesian product of enumerators" do
- enum = Enumerator.product(1..2, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
- end
-
- it "accepts a list of enumerators of any length" do
- enum = Enumerator.product(1..2)
- enum.to_a.should == [[1], [2]]
+describe "Enumerator.product" do
+ it "returns a Cartesian product of enumerators" do
+ enum = Enumerator.product(1..2, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
- enum = Enumerator.product(1..2, ["A"])
- enum.to_a.should == [[1, "A"], [2, "A"]]
+ it "accepts a list of enumerators of any length" do
+ enum = Enumerator.product(1..2)
+ enum.to_a.should == [[1], [2]]
- enum = Enumerator.product(1..2, ["A"], ["B"])
- enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
+ enum = Enumerator.product(1..2, ["A"])
+ enum.to_a.should == [[1, "A"], [2, "A"]]
- enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
- enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
- end
+ enum = Enumerator.product(1..2, ["A"], ["B"])
+ enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
- it "returns an enumerator with an empty array when no arguments passed" do
- enum = Enumerator.product
- enum.to_a.should == [[]]
- end
+ enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
+ enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
+ end
- it "returns an instance of Enumerator::Product" do
- enum = Enumerator.product
- enum.class.should == Enumerator::Product
- end
+ it "returns an enumerator with an empty array when no arguments passed" do
+ enum = Enumerator.product
+ enum.to_a.should == [[]]
+ end
- it "accepts infinite enumerators and returns infinite enumerator" do
- enum = Enumerator.product(1.., ["A", "B"])
- enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
- enum.size.should == Float::INFINITY
- end
+ it "returns an instance of Enumerator::Product" do
+ enum = Enumerator.product
+ enum.class.should == Enumerator::Product
+ end
- it "accepts a block" do
- elems = []
- enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
+ it "accepts infinite enumerators and returns infinite enumerator" do
+ enum = Enumerator.product(1.., ["A", "B"])
+ enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
+ enum.size.should == Float::INFINITY
+ end
- elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
- end
+ it "accepts a block" do
+ elems = []
+ enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
- it "returns nil when a block passed" do
- Enumerator.product(1..2) {}.should == nil
- end
+ elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
+ end
- # https://bugs.ruby-lang.org/issues/19829
- it "reject keyword arguments" do
- -> {
- Enumerator.product(1..3, foo: 1, bar: 2)
- }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
- end
+ it "returns nil when a block passed" do
+ Enumerator.product(1..2) {}.should == nil
+ end
- it "calls only #each_entry method on arguments" do
- object = Object.new
- def object.each_entry
- yield 1
- yield 2
- end
+ # https://bugs.ruby-lang.org/issues/19829
+ it "reject keyword arguments" do
+ -> {
+ Enumerator.product(1..3, foo: 1, bar: 2)
+ }.should.raise(ArgumentError, "unknown keywords: :foo, :bar")
+ end
- enum = Enumerator.product(object, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ it "calls only #each_entry method on arguments" do
+ object = Object.new
+ def object.each_entry
+ yield 1
+ yield 2
end
- it "raises NoMethodError when argument doesn't respond to #each_entry" do
- -> {
- Enumerator.product(Object.new).to_a
- }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
- end
+ enum = Enumerator.product(object, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
- it "calls #each_entry lazily" do
- Enumerator.product(Object.new).should be_kind_of(Enumerator)
- end
+ it "raises NoMethodError when argument doesn't respond to #each_entry" do
+ -> {
+ Enumerator.product(Object.new).to_a
+ }.should.raise(NoMethodError, /undefined method [`']each_entry' for/)
+ end
+
+ it "calls #each_entry lazily" do
+ Enumerator.product(Object.new).should.is_a?(Enumerator)
+ end
- it "iterates through consuming enumerator elements only once" do
- a = [1, 2, 3]
- i = 0
+ it "iterates through consuming enumerator elements only once" do
+ a = [1, 2, 3]
+ i = 0
- enum = Enumerator.new do |y|
- while i < a.size
- y << a[i]
- i += 1
- end
+ enum = Enumerator.new do |y|
+ while i < a.size
+ y << a[i]
+ i += 1
end
-
- Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
end
+
+ Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
end
end
diff --git a/spec/ruby/core/enumerator/shared/enum_for.rb b/spec/ruby/core/enumerator/shared/enum_for.rb
index a67a76c461..4388103ecf 100644
--- a/spec/ruby/core/enumerator/shared/enum_for.rb
+++ b/spec/ruby/core/enumerator/shared/enum_for.rb
@@ -1,10 +1,10 @@
describe :enum_for, shared: true do
it "is defined in Kernel" do
- Kernel.method_defined?(@method).should be_true
+ Kernel.method_defined?(@method).should == true
end
it "returns a new enumerator" do
- "abc".send(@method).should be_an_instance_of(Enumerator)
+ "abc".send(@method).should.instance_of?(Enumerator)
end
it "defaults the first argument to :each" do
@@ -49,7 +49,7 @@ describe :enum_for, shared: true do
100
end
- ScratchPad.recorded.should be_empty
+ ScratchPad.recorded.should.empty?
enum.size
ScratchPad.recorded.should == [:called]
diff --git a/spec/ruby/core/enumerator/shared/with_index.rb b/spec/ruby/core/enumerator/shared/with_index.rb
index 78771ffe82..0992397e95 100644
--- a/spec/ruby/core/enumerator/shared/with_index.rb
+++ b/spec/ruby/core/enumerator/shared/with_index.rb
@@ -16,7 +16,7 @@ describe :enum_with_index, shared: true do
end
it "returns the object being enumerated when given a block" do
- @enum.send(@method) { |o, i| :glark }.should equal(@origin)
+ @enum.send(@method) { |o, i| :glark }.should.equal?(@origin)
end
it "binds splat arguments properly" do
@@ -27,7 +27,7 @@ describe :enum_with_index, shared: true do
it "returns an enumerator if no block is supplied" do
ewi = @enum.send(@method)
- ewi.should be_an_instance_of(Enumerator)
+ ewi.should.instance_of?(Enumerator)
ewi.to_a.should == [[1, 0], [2, 1], [3, 2], [4, 3]]
end
end
diff --git a/spec/ruby/core/enumerator/shared/with_object.rb b/spec/ruby/core/enumerator/shared/with_object.rb
index d8e9d8e9f7..50d4f24eb3 100644
--- a/spec/ruby/core/enumerator/shared/with_object.rb
+++ b/spec/ruby/core/enumerator/shared/with_object.rb
@@ -16,18 +16,18 @@ describe :enum_with_object, shared: true do
ret = @enum.send(@method, @memo) do |elm, memo|
# nothing
end
- ret.should equal(@memo)
+ ret.should.equal?(@memo)
end
context "the block parameter" do
it "passes each element to first parameter" do
- @block_params[0][0].should equal(:a)
- @block_params[1][0].should equal(:b)
+ @block_params[0][0].should.equal?(:a)
+ @block_params[1][0].should.equal?(:b)
end
it "passes the given object to last parameter" do
- @block_params[0][1].should equal(@memo)
- @block_params[1][1].should equal(@memo)
+ @block_params[0][1].should.equal?(@memo)
+ @block_params[1][1].should.equal?(@memo)
end
end
end
@@ -35,8 +35,8 @@ describe :enum_with_object, shared: true do
context "without block" do
it "returns new Enumerator" do
ret = @enum.send(@method, @memo)
- ret.should be_an_instance_of(Enumerator)
- ret.should_not equal(@enum)
+ ret.should.instance_of?(Enumerator)
+ ret.should_not.equal?(@enum)
end
end
end
diff --git a/spec/ruby/core/enumerator/size_spec.rb b/spec/ruby/core/enumerator/size_spec.rb
index 6accd26a4e..4b2beffbbe 100644
--- a/spec/ruby/core/enumerator/size_spec.rb
+++ b/spec/ruby/core/enumerator/size_spec.rb
@@ -6,7 +6,7 @@ describe "Enumerator#size" do
end
it "returns nil if set size is nil" do
- Enumerator.new(nil) {}.size.should be_nil
+ Enumerator.new(nil) {}.size.should == nil
end
it "returns returning value from size.call if set size is a Proc" do
diff --git a/spec/ruby/core/enumerator/with_index_spec.rb b/spec/ruby/core/enumerator/with_index_spec.rb
index e49aa7a939..ca90fd18f7 100644
--- a/spec/ruby/core/enumerator/with_index_spec.rb
+++ b/spec/ruby/core/enumerator/with_index_spec.rb
@@ -9,20 +9,20 @@ describe "Enumerator#with_index" do
it "returns a new Enumerator when no block is given" do
enum1 = [1,2,3].select
enum2 = enum1.with_index
- enum2.should be_an_instance_of(Enumerator)
+ enum2.should.instance_of?(Enumerator)
enum1.should_not === enum2
end
it "accepts an optional argument when given a block" do
-> do
@enum.with_index(1) { |f| f}
- end.should_not raise_error(ArgumentError)
+ end.should_not.raise(ArgumentError)
end
it "accepts an optional argument when not given a block" do
-> do
@enum.with_index(1)
- end.should_not raise_error(ArgumentError)
+ end.should_not.raise(ArgumentError)
end
it "numbers indices from the given index when given an offset but no block" do
@@ -38,7 +38,7 @@ describe "Enumerator#with_index" do
it "raises a TypeError when the argument cannot be converted to numeric" do
-> do
@enum.with_index('1') {|*i| i}
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "converts non-numeric arguments to Integer via #to_int" do
diff --git a/spec/ruby/core/enumerator/yielder/append_spec.rb b/spec/ruby/core/enumerator/yielder/append_spec.rb
deleted file mode 100644
index a36e5d64b6..0000000000
--- a/spec/ruby/core/enumerator/yielder/append_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#<<" do
- # TODO: There's some common behavior between yield and <<; move to a shared spec
- it "yields the value to the block" do
- ary = []
- y = Enumerator::Yielder.new {|x| ary << x}
- y << 1
-
- ary.should == [1]
- end
-
- it "doesn't double-wrap Arrays" do
- yields = []
- y = Enumerator::Yielder.new {|args| yields << args }
- y << [1]
- yields.should == [[1]]
- end
-
- it "returns self" do
- y = Enumerator::Yielder.new {|x| x + 1}
- (y << 1).should equal(y)
- end
-
- context "when multiple arguments passed" do
- it "raises an ArgumentError" do
- ary = []
- y = Enumerator::Yielder.new { |*x| ary << x }
-
- -> {
- y.<<(1, 2)
- }.should raise_error(ArgumentError, /wrong number of arguments/)
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/yielder/initialize_spec.rb b/spec/ruby/core/enumerator/yielder/initialize_spec.rb
deleted file mode 100644
index 5a6eee2d0f..0000000000
--- a/spec/ruby/core/enumerator/yielder/initialize_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- encoding: us-ascii -*-
-
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#initialize" do
- before :each do
- @class = Enumerator::Yielder
- @uninitialized = @class.allocate
- end
-
- it "is a private method" do
- @class.should have_private_instance_method(:initialize, false)
- end
-
- it "returns self when given a block" do
- @uninitialized.send(:initialize) {}.should equal(@uninitialized)
- end
-end
diff --git a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
deleted file mode 100644
index 1d3681ab50..0000000000
--- a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#to_proc" do
- it "returns a Proc object that takes an argument and yields it to the block" do
- ScratchPad.record []
- y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" }
-
- callable = y.to_proc
- callable.class.should == Proc
-
- result = callable.call(1, 2)
- ScratchPad.recorded.should == [[1, 2]]
-
- result.should == "foobar"
- end
-end
diff --git a/spec/ruby/core/enumerator/yielder/yield_spec.rb b/spec/ruby/core/enumerator/yielder/yield_spec.rb
deleted file mode 100644
index acfdf114b6..0000000000
--- a/spec/ruby/core/enumerator/yielder/yield_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Enumerator::Yielder#yield" do
- it "yields the value to the block" do
- ary = []
- y = Enumerator::Yielder.new {|x| ary << x}
- y.yield 1
-
- ary.should == [1]
- end
-
- it "yields with passed arguments" do
- yields = []
- y = Enumerator::Yielder.new {|*args| yields << args }
- y.yield 1, 2
- yields.should == [[1, 2]]
- end
-
- it "returns the result of the block for the given value" do
- y = Enumerator::Yielder.new {|x| x + 1}
- y.yield(1).should == 2
- end
-
- context "when multiple arguments passed" do
- it "yields the arguments list to the block" do
- ary = []
- y = Enumerator::Yielder.new { |*x| ary << x }
- y.yield(1, 2)
-
- ary.should == [[1, 2]]
- end
- end
-end
diff --git a/spec/ruby/core/env/assoc_spec.rb b/spec/ruby/core/env/assoc_spec.rb
index c7a388db75..b81be7ddf2 100644
--- a/spec/ruby/core/env/assoc_spec.rb
+++ b/spec/ruby/core/env/assoc_spec.rb
@@ -26,6 +26,6 @@ describe "ENV.assoc" do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV.assoc(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.assoc(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/clear_spec.rb b/spec/ruby/core/env/clear_spec.rb
index 48b034ba1d..c0d20193ad 100644
--- a/spec/ruby/core/env/clear_spec.rb
+++ b/spec/ruby/core/env/clear_spec.rb
@@ -4,7 +4,7 @@ describe "ENV.clear" do
it "deletes all environment variables" do
orig = ENV.to_hash
begin
- ENV.clear.should equal(ENV)
+ ENV.clear.should.equal?(ENV)
# This used 'env' the helper before. That shells out to 'env' which
# itself sets up certain environment variables before it runs, because
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
index 991e4e6774..bb3c7ff2f8 100644
--- a/spec/ruby/core/env/clone_spec.rb
+++ b/spec/ruby/core/env/clone_spec.rb
@@ -4,20 +4,18 @@ describe "ENV#clone" do
it "raises ArgumentError when keyword argument 'freeze' is neither nil nor boolean" do
-> {
ENV.clone(freeze: 1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError when keyword argument is not 'freeze'" do
-> {
ENV.clone(foo: nil)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
- ruby_version_is "3.2" do
- it "raises TypeError" do
- -> {
- ENV.clone
- }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
+ it "raises TypeError" do
+ -> {
+ ENV.clone
+ }.should.raise(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
diff --git a/spec/ruby/core/env/delete_if_spec.rb b/spec/ruby/core/env/delete_if_spec.rb
index d2de51c225..4b05064eba 100644
--- a/spec/ruby/core/env/delete_if_spec.rb
+++ b/spec/ruby/core/env/delete_if_spec.rb
@@ -22,15 +22,15 @@ describe "ENV.delete_if" do
end
it "returns ENV when block given" do
- ENV.delete_if { |k, v| ["foo", "bar"].include?(k) }.should equal(ENV)
+ ENV.delete_if { |k, v| ["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV even if nothing deleted" do
- ENV.delete_if { false }.should equal(ENV)
+ ENV.delete_if { false }.should.equal?(ENV)
end
it "returns an Enumerator if no block given" do
- ENV.delete_if.should be_an_instance_of(Enumerator)
+ ENV.delete_if.should.instance_of?(Enumerator)
end
it "deletes pairs through enumerator" do
@@ -42,12 +42,12 @@ describe "ENV.delete_if" do
it "returns ENV from enumerator" do
enum = ENV.delete_if
- enum.each { |k, v| ["foo", "bar"].include?(k) }.should equal(ENV)
+ enum.each { |k, v| ["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV from enumerator even if nothing deleted" do
enum = ENV.delete_if
- enum.each { false }.should equal(ENV)
+ enum.each { false }.should.equal?(ENV)
end
it_behaves_like :enumeratorized_with_origin_size, :delete_if, ENV
diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb
index f28ac97911..db6d07b057 100644
--- a/spec/ruby/core/env/delete_spec.rb
+++ b/spec/ruby/core/env/delete_spec.rb
@@ -50,6 +50,6 @@ describe "ENV.delete" do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV.delete(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.delete(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
index ac66b455cd..d8cfac891d 100644
--- a/spec/ruby/core/env/dup_spec.rb
+++ b/spec/ruby/core/env/dup_spec.rb
@@ -4,6 +4,6 @@ describe "ENV#dup" do
it "raises TypeError" do
-> {
ENV.dup
- }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
+ }.should.raise(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
diff --git a/spec/ruby/core/env/each_key_spec.rb b/spec/ruby/core/env/each_key_spec.rb
index 0efcb09900..ad2cb560a0 100644
--- a/spec/ruby/core/env/each_key_spec.rb
+++ b/spec/ruby/core/env/each_key_spec.rb
@@ -10,9 +10,9 @@ describe "ENV.each_key" do
ENV.clear
ENV["1"] = "3"
ENV["2"] = "4"
- ENV.each_key { |k| e << k }.should equal(ENV)
- e.should include("1")
- e.should include("2")
+ ENV.each_key { |k| e << k }.should.equal?(ENV)
+ e.should.include?("1")
+ e.should.include?("2")
ensure
ENV.replace orig
end
@@ -20,7 +20,7 @@ describe "ENV.each_key" do
it "returns an Enumerator if called without a block" do
enum = ENV.each_key
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ENV.keys
end
diff --git a/spec/ruby/core/env/each_value_spec.rb b/spec/ruby/core/env/each_value_spec.rb
index cc3c9ebfb8..6f65e923e6 100644
--- a/spec/ruby/core/env/each_value_spec.rb
+++ b/spec/ruby/core/env/each_value_spec.rb
@@ -10,9 +10,9 @@ describe "ENV.each_value" do
ENV.clear
ENV["1"] = "3"
ENV["2"] = "4"
- ENV.each_value { |v| e << v }.should equal(ENV)
- e.should include("3")
- e.should include("4")
+ ENV.each_value { |v| e << v }.should.equal?(ENV)
+ e.should.include?("3")
+ e.should.include?("4")
ensure
ENV.replace orig
end
@@ -20,7 +20,7 @@ describe "ENV.each_value" do
it "returns an Enumerator if called without a block" do
enum = ENV.each_value
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ENV.values
end
diff --git a/spec/ruby/core/env/element_reference_spec.rb b/spec/ruby/core/env/element_reference_spec.rb
index 560c127a9c..e3ac979418 100644
--- a/spec/ruby/core/env/element_reference_spec.rb
+++ b/spec/ruby/core/env/element_reference_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/common'
@@ -28,7 +28,7 @@ describe "ENV.[]" do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV[Object.new] }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV[Object.new] }.should.raise(TypeError, "no implicit conversion of Object into String")
end
platform_is :windows do
@@ -71,6 +71,6 @@ describe "ENV.[]" do
ENV[@variable] = ""
Encoding.default_internal = Encoding::IBM437
- ENV[@variable].encoding.should equal(Encoding::IBM437)
+ ENV[@variable].encoding.should.equal?(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/env/fetch_spec.rb b/spec/ruby/core/env/fetch_spec.rb
index 2c5d7cc3a0..a2ec79c62b 100644
--- a/spec/ruby/core/env/fetch_spec.rb
+++ b/spec/ruby/core/env/fetch_spec.rb
@@ -16,7 +16,7 @@ describe "ENV.fetch" do
end
it "raises a TypeError if the key is not a String" do
- -> { ENV.fetch Object.new }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.fetch Object.new }.should.raise(TypeError, "no implicit conversion of Object into String")
end
context "when the key is not found" do
@@ -25,7 +25,7 @@ describe "ENV.fetch" do
it "formats the object with #inspect in the KeyError message" do
-> {
ENV.fetch('foo')
- }.should raise_error(KeyError, 'key not found: "foo"')
+ }.should.raise(KeyError, 'key not found: "foo"')
end
end
diff --git a/spec/ruby/core/env/fetch_values_spec.rb b/spec/ruby/core/env/fetch_values_spec.rb
new file mode 100644
index 0000000000..302cde2fd1
--- /dev/null
+++ b/spec/ruby/core/env/fetch_values_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+
+ruby_version_is "4.1" do
+ describe "ENV.fetch_values" do
+ before :each do
+ @saved_foo = ENV["foo"]
+ @saved_bar = ENV["bar"]
+ ENV.delete("foo")
+ ENV.delete("bar")
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ ENV["bar"] = @saved_bar
+ end
+
+ it "returns an array of the values corresponding to the given keys" do
+ ENV["foo"] = "oof"
+ ENV["bar"] = "rab"
+ ENV.fetch_values("bar", "foo").should == ["rab", "oof"]
+ end
+
+ it "returns the default value from block" do
+ ENV["foo"] = "oof"
+ ENV.fetch_values("bar") { |key| "`#{key}' is not found" }.should == ["`bar' is not found"]
+ ENV.fetch_values("bar", "foo") { |key| "`#{key}' is not found" }.should == ["`bar' is not found", "oof"]
+ end
+
+ it "returns an empty array if no keys specified" do
+ ENV.fetch_values.should == []
+ end
+
+ it "raises KeyError when there is no matching key" do
+ ENV["foo"] = "oof"
+ ENV["bar"] = "rab"
+ -> {
+ ENV.fetch_values("bar", "y", "foo", "z")
+ }.should.raise(KeyError, 'key not found: "y"')
+ end
+
+ it "uses the locale encoding" do
+ ENV.fetch_values(ENV.keys.first).first.encoding.should == ENVSpecs.encoding
+ end
+
+ it "raises TypeError when a key is not coercible to String" do
+ ENV["foo"] = "oof"
+ -> { ENV.fetch_values("foo", Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
+ end
+ end
+end
diff --git a/spec/ruby/core/env/keep_if_spec.rb b/spec/ruby/core/env/keep_if_spec.rb
index 64b6a207d0..f24981e216 100644
--- a/spec/ruby/core/env/keep_if_spec.rb
+++ b/spec/ruby/core/env/keep_if_spec.rb
@@ -22,15 +22,15 @@ describe "ENV.keep_if" do
end
it "returns ENV when block given" do
- ENV.keep_if { |k, v| !["foo", "bar"].include?(k) }.should equal(ENV)
+ ENV.keep_if { |k, v| !["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV even if nothing deleted" do
- ENV.keep_if { true }.should equal(ENV)
+ ENV.keep_if { true }.should.equal?(ENV)
end
it "returns an Enumerator if no block given" do
- ENV.keep_if.should be_an_instance_of(Enumerator)
+ ENV.keep_if.should.instance_of?(Enumerator)
end
it "deletes pairs through enumerator" do
@@ -42,12 +42,12 @@ describe "ENV.keep_if" do
it "returns ENV from enumerator" do
enum = ENV.keep_if
- enum.each { |k, v| !["foo", "bar"].include?(k) }.should equal(ENV)
+ enum.each { |k, v| !["foo", "bar"].include?(k) }.should.equal?(ENV)
end
it "returns ENV from enumerator even if nothing deleted" do
enum = ENV.keep_if
- enum.each { true }.should equal(ENV)
+ enum.each { true }.should.equal?(ENV)
end
it_behaves_like :enumeratorized_with_origin_size, :keep_if, ENV
diff --git a/spec/ruby/core/env/key_spec.rb b/spec/ruby/core/env/key_spec.rb
index cf70286409..677cf35216 100644
--- a/spec/ruby/core/env/key_spec.rb
+++ b/spec/ruby/core/env/key_spec.rb
@@ -21,7 +21,7 @@ describe "ENV.key" do
it "returns nil if the passed value is not found" do
ENV.delete("foo")
- ENV.key("foo").should be_nil
+ ENV.key("foo").should == nil
end
it "coerces the key element with #to_str" do
@@ -34,6 +34,6 @@ describe "ENV.key" do
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> {
ENV.key(Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/rassoc_spec.rb b/spec/ruby/core/env/rassoc_spec.rb
index ab9fe68088..e4ac5ce5e2 100644
--- a/spec/ruby/core/env/rassoc_spec.rb
+++ b/spec/ruby/core/env/rassoc_spec.rb
@@ -22,7 +22,7 @@ describe "ENV.rassoc" do
[
["foo", "bar"],
["baz", "bar"],
- ].should include(ENV.rassoc("bar"))
+ ].should.include?(ENV.rassoc("bar"))
end
it "returns nil if no environment variable with the given value exists" do
diff --git a/spec/ruby/core/env/reject_spec.rb b/spec/ruby/core/env/reject_spec.rb
index 6a9794925d..4df864493d 100644
--- a/spec/ruby/core/env/reject_spec.rb
+++ b/spec/ruby/core/env/reject_spec.rb
@@ -25,15 +25,15 @@ describe "ENV.reject!" do
it "returns itself or nil" do
ENV.reject! { false }.should == nil
ENV["foo"] = "bar"
- ENV.reject! { |k, v| k == "foo" }.should equal(ENV)
+ ENV.reject! { |k, v| k == "foo" }.should.equal?(ENV)
ENV["foo"].should == nil
end
it "returns an Enumerator if called without a block" do
ENV["foo"] = "bar"
enum = ENV.reject!
- enum.should be_an_instance_of(Enumerator)
- enum.each { |k, v| k == "foo" }.should equal(ENV)
+ enum.should.instance_of?(Enumerator)
+ enum.each { |k, v| k == "foo" }.should.equal?(ENV)
ENV["foo"].should == nil
end
@@ -41,7 +41,7 @@ describe "ENV.reject!" do
orig = ENV.to_hash
begin
ENV.clear
- -> { ENV.reject! }.should_not raise_error(LocalJumpError)
+ -> { ENV.reject! }.should_not.raise(LocalJumpError)
ensure
ENV.replace orig
end
@@ -76,13 +76,13 @@ describe "ENV.reject" do
end
it "returns a Hash" do
- ENV.reject { false }.should be_kind_of(Hash)
+ ENV.reject { false }.should.is_a?(Hash)
end
it "returns an Enumerator if called without a block" do
ENV["foo"] = "bar"
enum = ENV.reject
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |k, v| k == "foo"}
ENV["foo"] = nil
end
@@ -91,7 +91,7 @@ describe "ENV.reject" do
orig = ENV.to_hash
begin
ENV.clear
- -> { ENV.reject }.should_not raise_error(LocalJumpError)
+ -> { ENV.reject }.should_not.raise(LocalJumpError)
ensure
ENV.replace orig
end
diff --git a/spec/ruby/core/env/replace_spec.rb b/spec/ruby/core/env/replace_spec.rb
index 9fc67643d1..27eb3e45dd 100644
--- a/spec/ruby/core/env/replace_spec.rb
+++ b/spec/ruby/core/env/replace_spec.rb
@@ -11,41 +11,41 @@ describe "ENV.replace" do
end
it "replaces ENV with a Hash" do
- ENV.replace("foo" => "0", "bar" => "1").should equal(ENV)
+ ENV.replace("foo" => "0", "bar" => "1").should.equal?(ENV)
ENV.size.should == 2
ENV["foo"].should == "0"
ENV["bar"].should == "1"
end
it "raises TypeError if the argument is not a Hash" do
- -> { ENV.replace(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Hash")
+ -> { ENV.replace(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into Hash")
ENV.to_hash.should == @orig
end
it "raises TypeError if a key is not a String" do
- -> { ENV.replace(Object.new => "0") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace(Object.new => "0") }.should.raise(TypeError, "no implicit conversion of Object into String")
ENV.to_hash.should == @orig
end
it "raises TypeError if a value is not a String" do
- -> { ENV.replace("foo" => Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace("foo" => Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
ENV.to_hash.should == @orig
end
it "raises Errno::EINVAL when the key contains the '=' character" do
- -> { ENV.replace("foo=" =>"bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.replace("foo=" =>"bar") }.should.raise(Errno::EINVAL)
end
it "raises Errno::EINVAL when the key is an empty string" do
- -> { ENV.replace("" => "bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.replace("" => "bar") }.should.raise(Errno::EINVAL)
end
it "does not accept good data preceding an error" do
- -> { ENV.replace("foo" => "1", Object.new => Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace("foo" => "1", Object.new => Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "does not accept good data following an error" do
- -> { ENV.replace(Object.new => Object.new, "foo" => "0") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.replace(Object.new => Object.new, "foo" => "0") }.should.raise(TypeError, "no implicit conversion of Object into String")
ENV.to_hash.should == @orig
end
end
diff --git a/spec/ruby/core/env/shared/each.rb b/spec/ruby/core/env/shared/each.rb
index d901b854c4..0661ca924c 100644
--- a/spec/ruby/core/env/shared/each.rb
+++ b/spec/ruby/core/env/shared/each.rb
@@ -8,9 +8,9 @@ describe :env_each, shared: true do
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "boo"
- ENV.send(@method) { |k, v| e << [k, v] }.should equal(ENV)
- e.should include(["foo", "bar"])
- e.should include(["baz", "boo"])
+ ENV.send(@method) { |k, v| e << [k, v] }.should.equal?(ENV)
+ e.should.include?(["foo", "bar"])
+ e.should.include?(["baz", "boo"])
ensure
ENV.replace orig
end
@@ -18,7 +18,7 @@ describe :env_each, shared: true do
it "returns an Enumerator if called without a block" do
enum = ENV.send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each do |name, value|
ENV[name].should == value
end
@@ -55,9 +55,9 @@ describe :env_each, shared: true do
Encoding.default_internal = internal = Encoding::IBM437
ENV.send(@method) do |key, value|
- key.encoding.should equal(internal)
+ key.encoding.should.equal?(internal)
if value.ascii_only?
- value.encoding.should equal(internal)
+ value.encoding.should.equal?(internal)
end
end
end
diff --git a/spec/ruby/core/env/shared/include.rb b/spec/ruby/core/env/shared/include.rb
index 70aa555301..ceca02e3eb 100644
--- a/spec/ruby/core/env/shared/include.rb
+++ b/spec/ruby/core/env/shared/include.rb
@@ -25,6 +25,6 @@ describe :env_include, shared: true do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV.send(@method, Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.send(@method, Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/shared/select.rb b/spec/ruby/core/env/shared/select.rb
index 75ba112a32..8ec648a637 100644
--- a/spec/ruby/core/env/shared/select.rb
+++ b/spec/ruby/core/env/shared/select.rb
@@ -14,7 +14,7 @@ describe :env_select, shared: true do
it "returns an Enumerator when no block is given" do
enum = ENV.send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
end
it "selects via the enumerator" do
@@ -49,7 +49,7 @@ describe :env_select!, shared: true do
end
it "returns an Enumerator if called without a block" do
- ENV.send(@method).should be_an_instance_of(Enumerator)
+ ENV.send(@method).should.instance_of?(Enumerator)
end
it "selects via the enumerator" do
diff --git a/spec/ruby/core/env/shared/store.rb b/spec/ruby/core/env/shared/store.rb
index d6265c66a5..388208a8ac 100644
--- a/spec/ruby/core/env/shared/store.rb
+++ b/spec/ruby/core/env/shared/store.rb
@@ -14,13 +14,13 @@ describe :env_store, shared: true do
it "returns the value" do
value = "bar"
- ENV.send(@method, "foo", value).should equal(value)
+ ENV.send(@method, "foo", value).should.equal?(value)
end
it "deletes the environment variable when the value is nil" do
ENV["foo"] = "bar"
ENV.send(@method, "foo", nil)
- ENV.key?("foo").should be_false
+ ENV.key?("foo").should == false
end
it "coerces the key argument with #to_str" do
@@ -38,23 +38,23 @@ describe :env_store, shared: true do
end
it "raises TypeError when the key is not coercible to String" do
- -> { ENV.send(@method, Object.new, "bar") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.send(@method, Object.new, "bar") }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises TypeError when the value is not coercible to String" do
- -> { ENV.send(@method, "foo", Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.send(@method, "foo", Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises Errno::EINVAL when the key contains the '=' character" do
- -> { ENV.send(@method, "foo=", "bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.send(@method, "foo=", "bar") }.should.raise(Errno::EINVAL)
end
it "raises Errno::EINVAL when the key is an empty string" do
- -> { ENV.send(@method, "", "bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.send(@method, "", "bar") }.should.raise(Errno::EINVAL)
end
it "does nothing when the key is not a valid environment variable key and the value is nil" do
ENV.send(@method, "foo=", nil)
- ENV.key?("foo=").should be_false
+ ENV.key?("foo=").should == false
end
end
diff --git a/spec/ruby/core/env/shared/to_hash.rb b/spec/ruby/core/env/shared/to_hash.rb
index a0d4d7ce69..7868690c38 100644
--- a/spec/ruby/core/env/shared/to_hash.rb
+++ b/spec/ruby/core/env/shared/to_hash.rb
@@ -10,7 +10,7 @@ describe :env_to_hash, shared: true do
it "returns the ENV as a hash" do
ENV["foo"] = "bar"
h = ENV.send(@method)
- h.should be_an_instance_of(Hash)
+ h.should.instance_of?(Hash)
h["foo"].should == "bar"
end
@@ -24,7 +24,7 @@ describe :env_to_hash, shared: true do
it "duplicates the ENV when converting to a Hash" do
h = ENV.send(@method)
- h.should_not equal ENV
+ h.should_not.equal? ENV
h.size.should == ENV.size
h.each_pair do |k, v|
ENV[k].should == v
diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb
index 7d4799955b..112cc2505d 100644
--- a/spec/ruby/core/env/shared/update.rb
+++ b/spec/ruby/core/env/shared/update.rb
@@ -10,21 +10,19 @@ describe :env_update, shared: true do
end
it "adds the parameter hash to ENV, returning ENV" do
- ENV.send(@method, "foo" => "0", "bar" => "1").should equal(ENV)
+ ENV.send(@method, "foo" => "0", "bar" => "1").should.equal?(ENV)
ENV["foo"].should == "0"
ENV["bar"].should == "1"
end
- ruby_version_is "3.2" do
- it "adds the multiple parameter hashes to ENV, returning ENV" do
- ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should equal(ENV)
- ENV["foo"].should == "multi1"
- ENV["bar"].should == "multi2"
- end
+ it "adds the multiple parameter hashes to ENV, returning ENV" do
+ ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should.equal?(ENV)
+ ENV["foo"].should == "multi1"
+ ENV["bar"].should == "multi2"
end
it "returns ENV when no block given" do
- ENV.send(@method, {"foo" => "0", "bar" => "1"}).should equal(ENV)
+ ENV.send(@method, {"foo" => "0", "bar" => "1"}).should.equal?(ENV)
end
it "yields key, the old value and the new value when replacing an entry" do
@@ -65,23 +63,23 @@ describe :env_update, shared: true do
end
it "returns ENV when block given" do
- ENV.send(@method, {"foo" => "0", "bar" => "1"}){}.should equal(ENV)
+ ENV.send(@method, {"foo" => "0", "bar" => "1"}){}.should.equal?(ENV)
end
it "raises TypeError when a name is not coercible to String" do
- -> { ENV.send @method, Object.new => "0" }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.send @method, Object.new => "0" }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises TypeError when a value is not coercible to String" do
- -> { ENV.send @method, "foo" => Object.new }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.send @method, "foo" => Object.new }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises Errno::EINVAL when a name contains the '=' character" do
- -> { ENV.send(@method, "foo=" => "bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.send(@method, "foo=" => "bar") }.should.raise(Errno::EINVAL)
end
it "raises Errno::EINVAL when a name is an empty string" do
- -> { ENV.send(@method, "" => "bar") }.should raise_error(Errno::EINVAL)
+ -> { ENV.send(@method, "" => "bar") }.should.raise(Errno::EINVAL)
end
it "updates good data preceding an error" do
diff --git a/spec/ruby/core/env/shift_spec.rb b/spec/ruby/core/env/shift_spec.rb
index 1b92e5d1e4..52bd0f9139 100644
--- a/spec/ruby/core/env/shift_spec.rb
+++ b/spec/ruby/core/env/shift_spec.rb
@@ -33,15 +33,15 @@ describe "ENV.shift" do
Encoding.default_internal = nil
pair = ENV.shift
- pair.first.encoding.should equal(ENVSpecs.encoding)
- pair.last.encoding.should equal(ENVSpecs.encoding)
+ pair.first.encoding.should.equal?(ENVSpecs.encoding)
+ pair.last.encoding.should.equal?(ENVSpecs.encoding)
end
it "transcodes from the locale encoding to Encoding.default_internal if set" do
Encoding.default_internal = Encoding::IBM437
pair = ENV.shift
- pair.first.encoding.should equal(Encoding::IBM437)
- pair.last.encoding.should equal(Encoding::IBM437)
+ pair.first.encoding.should.equal?(Encoding::IBM437)
+ pair.last.encoding.should.equal?(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/env/slice_spec.rb b/spec/ruby/core/env/slice_spec.rb
index 959239d2b2..4c0416547d 100644
--- a/spec/ruby/core/env/slice_spec.rb
+++ b/spec/ruby/core/env/slice_spec.rb
@@ -32,6 +32,6 @@ describe "ENV.slice" do
end
it "raises TypeError if any argument is not a String and does not respond to #to_str" do
- -> { ENV.slice(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.slice(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/to_h_spec.rb b/spec/ruby/core/env/to_h_spec.rb
index 58ea2d2030..7e0fef2120 100644
--- a/spec/ruby/core/env/to_h_spec.rb
+++ b/spec/ruby/core/env/to_h_spec.rb
@@ -38,17 +38,17 @@ describe "ENV.to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
ENV.to_h { |k, v| [k, v.upcase, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
ENV.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
ENV.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -64,7 +64,7 @@ describe "ENV.to_h" do
-> do
ENV.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/env/values_at_spec.rb b/spec/ruby/core/env/values_at_spec.rb
index 338680e820..4a733f4ed5 100644
--- a/spec/ruby/core/env/values_at_spec.rb
+++ b/spec/ruby/core/env/values_at_spec.rb
@@ -33,6 +33,6 @@ describe "ENV.values_at" do
end
it "raises TypeError when a key is not coercible to String" do
- -> { ENV.values_at("foo", Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { ENV.values_at("foo", Object.new) }.should.raise(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/exception/backtrace_locations_spec.rb b/spec/ruby/core/exception/backtrace_locations_spec.rb
index 86eb9d3413..62eab8a0f3 100644
--- a/spec/ruby/core/exception/backtrace_locations_spec.rb
+++ b/spec/ruby/core/exception/backtrace_locations_spec.rb
@@ -7,15 +7,15 @@ describe "Exception#backtrace_locations" do
end
it "returns nil if no backtrace was set" do
- Exception.new.backtrace_locations.should be_nil
+ Exception.new.backtrace_locations.should == nil
end
it "returns an Array" do
- @backtrace.should be_an_instance_of(Array)
+ @backtrace.should.instance_of?(Array)
end
it "sets each element to a Thread::Backtrace::Location" do
- @backtrace.each {|l| l.should be_an_instance_of(Thread::Backtrace::Location)}
+ @backtrace.each {|l| l.should.instance_of?(Thread::Backtrace::Location)}
end
it "produces a backtrace for an exception captured using $!" do
diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb
index 9a65ea3820..a4a8272030 100644
--- a/spec/ruby/core/exception/backtrace_spec.rb
+++ b/spec/ruby/core/exception/backtrace_spec.rb
@@ -7,15 +7,15 @@ describe "Exception#backtrace" do
end
it "returns nil if no backtrace was set" do
- Exception.new.backtrace.should be_nil
+ Exception.new.backtrace.should == nil
end
it "returns an Array" do
- @backtrace.should be_an_instance_of(Array)
+ @backtrace.should.instance_of?(Array)
end
it "sets each element to a String" do
- @backtrace.each {|l| l.should be_an_instance_of(String)}
+ @backtrace.each {|l| l.should.instance_of?(String)}
end
it "includes the filename of the location where self raised in the first element" do
@@ -94,13 +94,13 @@ describe "Exception#backtrace" do
raise
rescue RuntimeError => err
bt = err.backtrace
- err.dup.backtrace.should equal(bt)
+ err.dup.backtrace.should.equal?(bt)
new_bt = ['hi']
err.set_backtrace new_bt
err.backtrace.should == new_bt
- err.dup.backtrace.should equal(new_bt)
+ err.dup.backtrace.should.equal?(new_bt)
end
end
end
diff --git a/spec/ruby/core/exception/cause_spec.rb b/spec/ruby/core/exception/cause_spec.rb
index cf4aaeb188..cfc15bdda3 100644
--- a/spec/ruby/core/exception/cause_spec.rb
+++ b/spec/ruby/core/exception/cause_spec.rb
@@ -4,53 +4,35 @@ describe "Exception#cause" do
it "returns the active exception when an exception is raised" do
begin
raise Exception, "the cause"
- rescue Exception
- begin
+ rescue Exception => cause
+ -> {
raise RuntimeError, "the consequence"
- rescue RuntimeError => e
- e.should be_an_instance_of(RuntimeError)
- e.message.should == "the consequence"
-
- e.cause.should be_an_instance_of(Exception)
- e.cause.message.should == "the cause"
- end
+ }.should.raise(RuntimeError, "the consequence", cause:)
end
end
it "is set for user errors caused by internal errors" do
- -> {
- begin
- 1 / 0
- rescue
- raise "foo"
- end
- }.should raise_error(RuntimeError) { |e|
- e.cause.should be_kind_of(ZeroDivisionError)
- }
+ begin
+ 1 / 0
+ rescue => cause
+ -> { raise "foo" }.should.raise(RuntimeError, cause:)
+ end
end
it "is set for internal errors caused by user errors" do
cause = RuntimeError.new "cause"
- -> {
- begin
- raise cause
- rescue
- 1 / 0
- end
- }.should raise_error(ZeroDivisionError) { |e|
- e.cause.should equal(cause)
- }
+ begin
+ raise cause
+ rescue
+ -> { 1 / 0 }.should.raise(ZeroDivisionError, cause:)
+ end
end
it "is not set to the exception itself when it is re-raised" do
- -> {
- begin
- raise RuntimeError
- rescue RuntimeError => e
- raise e
- end
- }.should raise_error(RuntimeError) { |e|
- e.cause.should == nil
- }
+ begin
+ raise RuntimeError
+ rescue RuntimeError => e
+ -> { raise e }.should.raise(RuntimeError, cause: nil)
+ end
end
end
diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb
index 8178278b2b..9df164a1cf 100644
--- a/spec/ruby/core/exception/detailed_message_spec.rb
+++ b/spec/ruby/core/exception/detailed_message_spec.rb
@@ -2,51 +2,49 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
describe "Exception#detailed_message" do
- ruby_version_is "3.2" do
- it "returns decorated message" do
- RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
- end
+ it "returns decorated message" do
+ RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
+ end
- it "is called by #full_message to allow message customization" do
- exception = Exception.new("new error")
- def exception.detailed_message(**)
- "<prefix>#{message}<suffix>"
- end
- exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
+ it "is called by #full_message to allow message customization" do
+ exception = Exception.new("new error")
+ def exception.detailed_message(**)
+ "<prefix>#{message}<suffix>"
end
+ exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
+ end
- it "returns just a message if exception class is anonymous" do
- Class.new(RuntimeError).new("message").detailed_message.should == "message"
- end
+ it "returns just a message if exception class is anonymous" do
+ Class.new(RuntimeError).new("message").detailed_message.should == "message"
+ end
- it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message.should == "unhandled exception"
- end
+ it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
+ RuntimeError.new("").detailed_message.should == "unhandled exception"
+ end
- it "returns just class name for an instance other than RuntimeError with empty message" do
- DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
- StandardError.new("").detailed_message.should == "StandardError"
- end
+ it "returns just class name for an instance other than RuntimeError with empty message" do
+ DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
+ StandardError.new("").detailed_message.should == "StandardError"
+ end
- it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
- klass = Class.new(RuntimeError)
- klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
- end
+ it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
+ klass = Class.new(RuntimeError)
+ klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
+ end
- it "accepts highlight keyword argument and adds escape control sequences" do
- RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
- end
+ it "accepts highlight keyword argument and adds escape control sequences" do
+ RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
+ end
- it "accepts highlight keyword argument and adds escape control sequences for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message(highlight: true).should == "\e[1;4munhandled exception\e[m"
- end
+ it "accepts highlight keyword argument and adds escape control sequences for an instance of RuntimeError with empty message" do
+ RuntimeError.new("").detailed_message(highlight: true).should == "\e[1;4munhandled exception\e[m"
+ end
- it "accepts highlight keyword argument and adds escape control sequences for an instance other than RuntimeError with empty message" do
- StandardError.new("").detailed_message(highlight: true).should == "\e[1;4mStandardError\e[m"
- end
+ it "accepts highlight keyword argument and adds escape control sequences for an instance other than RuntimeError with empty message" do
+ StandardError.new("").detailed_message(highlight: true).should == "\e[1;4mStandardError\e[m"
+ end
- it "allows and ignores other keyword arguments" do
- RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
- end
+ it "allows and ignores other keyword arguments" do
+ RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
end
end
diff --git a/spec/ruby/core/exception/dup_spec.rb b/spec/ruby/core/exception/dup_spec.rb
index edd54bfb37..b53ad79bf3 100644
--- a/spec/ruby/core/exception/dup_spec.rb
+++ b/spec/ruby/core/exception/dup_spec.rb
@@ -20,7 +20,7 @@ describe "Exception#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- -> { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should.raise(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -29,7 +29,7 @@ describe "Exception#dup" do
end
dup = @obj.dup
- -> { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should.raise(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -38,7 +38,7 @@ describe "Exception#dup" do
end
dup = @obj.dup
- -> { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should.raise(NameError)
end
it "does copy the message" do
@@ -61,13 +61,13 @@ describe "Exception#dup" do
it "does copy the cause" do
begin
- raise StandardError, "the cause"
+ raise StandardError
rescue StandardError => cause
begin
- raise RuntimeError, "the consequence"
+ raise RuntimeError
rescue RuntimeError => e
- e.cause.should equal(cause)
- e.dup.cause.should equal(cause)
+ e.cause.should.equal?(cause)
+ e.dup.cause.should.equal?(cause)
end
end
end
diff --git a/spec/ruby/core/exception/equal_value_spec.rb b/spec/ruby/core/exception/equal_value_spec.rb
index e8f3ce0f8d..b76b3bcd4a 100644
--- a/spec/ruby/core/exception/equal_value_spec.rb
+++ b/spec/ruby/core/exception/equal_value_spec.rb
@@ -31,10 +31,10 @@ describe "Exception#==" do
it "returns false if the two exceptions inherit from Exception but have different classes" do
one = RuntimeError.new("message")
one.set_backtrace [__dir__]
- one.should be_kind_of(Exception)
+ one.should.is_a?(Exception)
two = TypeError.new("message")
two.set_backtrace [__dir__]
- two.should be_kind_of(Exception)
+ two.should.is_a?(Exception)
one.should_not == two
end
diff --git a/spec/ruby/core/exception/errno_spec.rb b/spec/ruby/core/exception/errno_spec.rb
index 1ab4277700..36beae9976 100644
--- a/spec/ruby/core/exception/errno_spec.rb
+++ b/spec/ruby/core/exception/errno_spec.rb
@@ -4,21 +4,21 @@ require_relative 'fixtures/common'
describe "Errno::EINVAL.new" do
it "can be called with no arguments" do
exc = Errno::EINVAL.new
- exc.should be_an_instance_of(Errno::EINVAL)
+ exc.should.instance_of?(Errno::EINVAL)
exc.errno.should == Errno::EINVAL::Errno
exc.message.should == "Invalid argument"
end
it "accepts an optional custom message" do
exc = Errno::EINVAL.new('custom message')
- exc.should be_an_instance_of(Errno::EINVAL)
+ exc.should.instance_of?(Errno::EINVAL)
exc.errno.should == Errno::EINVAL::Errno
exc.message.should == "Invalid argument - custom message"
end
it "accepts an optional custom message and location" do
exc = Errno::EINVAL.new('custom message', 'location')
- exc.should be_an_instance_of(Errno::EINVAL)
+ exc.should.instance_of?(Errno::EINVAL)
exc.errno.should == Errno::EINVAL::Errno
exc.message.should == "Invalid argument @ location - custom message"
end
@@ -28,7 +28,7 @@ describe "Errno::EMFILE" do
it "can be subclassed" do
ExceptionSpecs::EMFILESub = Class.new(Errno::EMFILE)
exc = ExceptionSpecs::EMFILESub.new
- exc.should be_an_instance_of(ExceptionSpecs::EMFILESub)
+ exc.should.instance_of?(ExceptionSpecs::EMFILESub)
ensure
ExceptionSpecs.send(:remove_const, :EMFILESub)
end
@@ -47,7 +47,7 @@ end
describe "Errno::ENOTSUP" do
it "is defined" do
- Errno.should have_constant(:ENOTSUP)
+ Errno.should.const_defined?(:ENOTSUP, false)
end
it "is the same class as Errno::EOPNOTSUPP if they represent the same errno value" do
diff --git a/spec/ruby/core/exception/exception_spec.rb b/spec/ruby/core/exception/exception_spec.rb
index d6f5283bd9..f5424cdabd 100644
--- a/spec/ruby/core/exception/exception_spec.rb
+++ b/spec/ruby/core/exception/exception_spec.rb
@@ -20,7 +20,7 @@ describe "Exception#exception" do
it "returns an exception of the same class as self with the message given as argument" do
e = RuntimeError.new
e2 = e.exception("message")
- e2.should be_an_instance_of(RuntimeError)
+ e2.should.instance_of?(RuntimeError)
e2.message.should == "message"
end
@@ -62,7 +62,7 @@ describe "Exception#exception" do
it "returns an exception of the same class as self with the message given as argument, but without reinitializing" do
e = CustomArgumentError.new(:boom)
e2 = e.exception("message")
- e2.should be_an_instance_of(CustomArgumentError)
+ e2.should.instance_of?(CustomArgumentError)
e2.val.should == :boom
e2.message.should == "message"
end
diff --git a/spec/ruby/core/exception/exit_value_spec.rb b/spec/ruby/core/exception/exit_value_spec.rb
index 99987dd1bc..bb6cff1831 100644
--- a/spec/ruby/core/exception/exit_value_spec.rb
+++ b/spec/ruby/core/exception/exit_value_spec.rb
@@ -6,7 +6,7 @@ describe "LocalJumpError#exit_value" do
end
it "returns the value given to return" do
- -> { get_me_a_return.call }.should raise_error(LocalJumpError) { |e|
+ -> { get_me_a_return.call }.should.raise(LocalJumpError) { |e|
e.exit_value.should == 42
}
end
diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb
index 979ec2ff98..a28f524b54 100644
--- a/spec/ruby/core/exception/frozen_error_spec.rb
+++ b/spec/ruby/core/exception/frozen_error_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "FrozenError.new" do
it "should take optional receiver argument" do
o = Object.new
- FrozenError.new("msg", receiver: o).receiver.should equal(o)
+ FrozenError.new("msg", receiver: o).receiver.should.equal?(o)
end
end
@@ -13,14 +13,30 @@ describe "FrozenError#receiver" do
begin
def o.x; end
rescue => e
- e.should be_kind_of(FrozenError)
- e.receiver.should equal(o)
+ e.should.is_a?(FrozenError)
+ e.receiver.should.equal?(o)
else
raise
end
end
end
+describe "FrozenError#message" do
+ it "includes a receiver" do
+ object = Object.new
+ object.freeze
+
+ msg_class = ruby_version_is("4.0") ? "Object" : "object"
+
+ -> {
+ def object.x; end
+ }.should.raise(FrozenError, "can't modify frozen #{msg_class}: #{object}")
+
+ object = [].freeze
+ -> { object << nil }.should.raise(FrozenError, "can't modify frozen Array: []")
+ end
+end
+
describe "Modifying a frozen object" do
context "#inspect is redefined and modifies the object" do
it "returns ... instead of String representation of object" do
@@ -32,7 +48,7 @@ describe "Modifying a frozen object" do
# CRuby's message contains multiple whitespaces before '...'.
# So handle both multiple and single whitespace.
- -> { object.modify }.should raise_error(FrozenError, /can't modify frozen .*?: \s*.../)
+ -> { object.modify }.should.raise(FrozenError, /can't modify frozen .*?: \s*.../)
end
end
end
diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb
index d752083db2..5a5e0a2b3a 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -6,10 +6,10 @@ describe "Exception#full_message" do
e.set_backtrace(["a.rb:1", "b.rb:2"])
full_message = e.full_message
- full_message.should include "RuntimeError"
- full_message.should include "Some runtime error"
- full_message.should include "a.rb:1"
- full_message.should include "b.rb:2"
+ full_message.should.include? "RuntimeError"
+ full_message.should.include? "Some runtime error"
+ full_message.should.include? "a.rb:1"
+ full_message.should.include? "b.rb:2"
end
it "supports :highlight option and adds escape sequences to highlight some strings" do
@@ -141,8 +141,8 @@ describe "Exception#full_message" do
exception = e
end
- exception.full_message.should include "main exception"
- exception.full_message.should include "the cause"
+ exception.full_message.should.include? "main exception"
+ exception.full_message.should.include? "the cause"
end
it 'contains all the chain of exceptions' do
@@ -160,57 +160,67 @@ describe "Exception#full_message" do
exception = e
end
- exception.full_message.should include "last exception"
- exception.full_message.should include "intermediate exception"
- exception.full_message.should include "origin exception"
+ exception.full_message.should.include? "last exception"
+ exception.full_message.should.include? "intermediate exception"
+ exception.full_message.should.include? "origin exception"
end
- ruby_version_is "3.2" do
- it "relies on #detailed_message" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
+ it "relies on #detailed_message" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
+
+ it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
+ e = RuntimeError.new("new error")
+ options_passed = nil
+ e.define_singleton_method(:detailed_message) do |**options|
+ options_passed = options
+ "DETAILED MESSAGE"
end
- it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
- e = RuntimeError.new("new error")
- options_passed = nil
- e.define_singleton_method(:detailed_message) do |**options|
- options_passed = options
- "DETAILED MESSAGE"
- end
+ e.full_message(foo: "bar")
+ options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
+ end
- e.full_message(foo: "bar")
- options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
- end
+ it "converts #detailed_message returned value to String if it isn't a String" do
+ message = Object.new
+ def message.to_str; "DETAILED MESSAGE"; end
- it "converts #detailed_message returned value to String if it isn't a String" do
- message = Object.new
- def message.to_str; "DETAILED MESSAGE"; end
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| message }
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| message }
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
- end
+ it "uses class name if #detailed_message returns nil" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| nil }
- it "uses class name if #detailed_message returns nil" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| nil }
+ e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
+ e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ end
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ it "uses class name if exception object doesn't respond to #detailed_message" do
+ e = RuntimeError.new("new error")
+ class << e
+ undef :detailed_message
end
- it "uses class name if exception object doesn't respond to #detailed_message" do
- e = RuntimeError.new("new error")
- class << e
- undef :detailed_message
- end
+ e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
+ e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ end
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ it "allows cause with empty backtrace" do
+ begin
+ raise RuntimeError.new("Some runtime error"), cause: RuntimeError.new("Some other runtime error")
+ rescue => e
end
+
+ full_message = e.full_message
+ full_message.should.include? "RuntimeError"
+ full_message.should.include? "Some runtime error"
+ full_message.should.include? "Some other runtime error"
end
end
diff --git a/spec/ruby/core/exception/io_error_spec.rb b/spec/ruby/core/exception/io_error_spec.rb
index ab8a72518f..940d5be876 100644
--- a/spec/ruby/core/exception/io_error_spec.rb
+++ b/spec/ruby/core/exception/io_error_spec.rb
@@ -3,14 +3,14 @@ require_relative '../../spec_helper'
describe "IO::EAGAINWaitReadable" do
it "combines Errno::EAGAIN and IO::WaitReadable" do
IO::EAGAINWaitReadable.superclass.should == Errno::EAGAIN
- IO::EAGAINWaitReadable.ancestors.should include IO::WaitReadable
+ IO::EAGAINWaitReadable.ancestors.should.include? IO::WaitReadable
end
it "is the same as IO::EWOULDBLOCKWaitReadable if Errno::EAGAIN is the same as Errno::EWOULDBLOCK" do
if Errno::EAGAIN.equal? Errno::EWOULDBLOCK
- IO::EAGAINWaitReadable.should equal IO::EWOULDBLOCKWaitReadable
+ IO::EAGAINWaitReadable.should.equal? IO::EWOULDBLOCKWaitReadable
else
- IO::EAGAINWaitReadable.should_not equal IO::EWOULDBLOCKWaitReadable
+ IO::EAGAINWaitReadable.should_not.equal? IO::EWOULDBLOCKWaitReadable
end
end
end
@@ -18,21 +18,21 @@ end
describe "IO::EWOULDBLOCKWaitReadable" do
it "combines Errno::EWOULDBLOCK and IO::WaitReadable" do
IO::EWOULDBLOCKWaitReadable.superclass.should == Errno::EWOULDBLOCK
- IO::EAGAINWaitReadable.ancestors.should include IO::WaitReadable
+ IO::EAGAINWaitReadable.ancestors.should.include? IO::WaitReadable
end
end
describe "IO::EAGAINWaitWritable" do
it "combines Errno::EAGAIN and IO::WaitWritable" do
IO::EAGAINWaitWritable.superclass.should == Errno::EAGAIN
- IO::EAGAINWaitWritable.ancestors.should include IO::WaitWritable
+ IO::EAGAINWaitWritable.ancestors.should.include? IO::WaitWritable
end
it "is the same as IO::EWOULDBLOCKWaitWritable if Errno::EAGAIN is the same as Errno::EWOULDBLOCK" do
if Errno::EAGAIN.equal? Errno::EWOULDBLOCK
- IO::EAGAINWaitWritable.should equal IO::EWOULDBLOCKWaitWritable
+ IO::EAGAINWaitWritable.should.equal? IO::EWOULDBLOCKWaitWritable
else
- IO::EAGAINWaitWritable.should_not equal IO::EWOULDBLOCKWaitWritable
+ IO::EAGAINWaitWritable.should_not.equal? IO::EWOULDBLOCKWaitWritable
end
end
end
@@ -40,6 +40,6 @@ end
describe "IO::EWOULDBLOCKWaitWritable" do
it "combines Errno::EWOULDBLOCK and IO::WaitWritable" do
IO::EWOULDBLOCKWaitWritable.superclass.should == Errno::EWOULDBLOCK
- IO::EAGAINWaitWritable.ancestors.should include IO::WaitWritable
+ IO::EAGAINWaitWritable.ancestors.should.include? IO::WaitWritable
end
end
diff --git a/spec/ruby/core/exception/name_spec.rb b/spec/ruby/core/exception/name_spec.rb
index c8a49b40e2..6e0e99d194 100644
--- a/spec/ruby/core/exception/name_spec.rb
+++ b/spec/ruby/core/exception/name_spec.rb
@@ -4,25 +4,25 @@ describe "NameError#name" do
it "returns a method name as a symbol" do
-> {
doesnt_exist
- }.should raise_error(NameError) {|e| e.name.should == :doesnt_exist }
+ }.should.raise(NameError) {|e| e.name.should == :doesnt_exist }
end
it "returns a constant name as a symbol" do
-> {
DoesntExist
- }.should raise_error(NameError) {|e| e.name.should == :DoesntExist }
+ }.should.raise(NameError) {|e| e.name.should == :DoesntExist }
end
it "returns a constant name without namespace as a symbol" do
-> {
Object::DoesntExist
- }.should raise_error(NameError) {|e| e.name.should == :DoesntExist }
+ }.should.raise(NameError) {|e| e.name.should == :DoesntExist }
end
it "returns a class variable name as a symbol" do
-> {
eval("class singleton_class::A; @@doesnt_exist end", binding, __FILE__, __LINE__)
- }.should raise_error(NameError) { |e| e.name.should == :@@doesnt_exist }
+ }.should.raise(NameError) { |e| e.name.should == :@@doesnt_exist }
end
it "returns the first argument passed to the method when a NameError is raised from #instance_variable_get" do
@@ -30,7 +30,7 @@ describe "NameError#name" do
-> {
Object.new.instance_variable_get(invalid_ivar_name)
- }.should raise_error(NameError) {|e| e.name.should equal(invalid_ivar_name) }
+ }.should.raise(NameError) {|e| e.name.should.equal?(invalid_ivar_name) }
end
it "returns the first argument passed to the method when a NameError is raised from #class_variable_get" do
@@ -38,6 +38,6 @@ describe "NameError#name" do
-> {
Object.class_variable_get(invalid_cvar_name)
- }.should raise_error(NameError) {|e| e.name.should equal(invalid_cvar_name) }
+ }.should.raise(NameError) {|e| e.name.should.equal?(invalid_cvar_name) }
end
end
diff --git a/spec/ruby/core/exception/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb
index 772c569f67..9f92104082 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -35,7 +35,7 @@ describe "NoMethodError#args" do
NoMethodErrorSpecs::NoMethodErrorB.new.foo(1,a)
rescue Exception => e
e.args.should == [1,a]
- e.args[1].should equal a
+ e.args[1].should.equal? a
end
end
end
@@ -45,7 +45,7 @@ describe "NoMethodError#message" do
begin
NoMethodErrorSpecs::NoMethodErrorD.new.foo
rescue Exception => e
- e.should be_kind_of(NoMethodError)
+ e.should.is_a?(NoMethodError)
end
end
@@ -53,7 +53,7 @@ describe "NoMethodError#message" do
begin
NoMethodErrorSpecs::NoMethodErrorC.new.a_protected_method
rescue Exception => e
- e.should be_kind_of(NoMethodError)
+ e.should.is_a?(NoMethodError)
end
end
@@ -61,209 +61,150 @@ describe "NoMethodError#message" do
begin
NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method
rescue Exception => e
- e.should be_kind_of(NoMethodError)
+ e.should.is_a?(NoMethodError)
e.message.lines[0].should =~ /private method [`']a_private_method' called for /
end
end
- ruby_version_is ""..."3.3" do
- it "calls #inspect when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for <inspect>:#<Class:0x\h+>$/
- ScratchPad.recorded.should == [:inspect_called]
- end
- end
-
- it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
- test_class = Class.new do
- def inspect
- raise NoMethodErrorSpecs::InstanceException
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- message = error.message
- message.should =~ /undefined method.+\bbar\b/
- message.should include test_class.inspect
- end
- end
-
- it "uses #name to display the receiver if it is a class" do
- klass = Class.new { def self.name; "MyClass"; end }
-
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/
- end
+ it "uses a literal name when receiver is nil" do
+ begin
+ nil.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
end
+ end
- it "uses #name to display the receiver if it is a module" do
- mod = Module.new { def self.name; "MyModule"; end }
-
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/
- end
+ it "uses a literal name when receiver is true" do
+ begin
+ true.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for true\Z/
end
end
- ruby_version_is "3.3" do
- it "uses a literal name when receiver is nil" do
- begin
- nil.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
- end
+ it "uses a literal name when receiver is false" do
+ begin
+ false.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for false\Z/
end
+ end
- it "uses a literal name when receiver is true" do
- begin
- true.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for true\Z/
- end
- end
+ it "uses #name when receiver is a class" do
+ klass = Class.new { def self.name; "MyClass"; end }
- it "uses a literal name when receiver is false" do
- begin
- false.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for false\Z/
- end
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
end
+ end
- it "uses #name when receiver is a class" do
- klass = Class.new { def self.name; "MyClass"; end }
+ it "uses class' string representation when receiver is an anonymous class" do
+ klass = Class.new
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
- end
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
end
+ end
- it "uses class' string representation when receiver is an anonymous class" do
- klass = Class.new
+ it "uses class' string representation when receiver is a singleton class" do
+ obj = Object.new
+ singleton_class = obj.singleton_class
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
- end
+ begin
+ singleton_class.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/
end
+ end
- it "uses class' string representation when receiver is a singleton class" do
- obj = Object.new
- singleton_class = obj.singleton_class
+ it "uses #name when receiver is a module" do
+ mod = Module.new { def self.name; "MyModule"; end }
- begin
- singleton_class.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/
- end
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
end
+ end
- it "uses #name when receiver is a module" do
- mod = Module.new { def self.name; "MyModule"; end }
+ it "uses module's string representation when receiver is an anonymous module" do
+ m = Module.new
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
- end
+ begin
+ m.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
end
+ end
- it "uses module's string representation when receiver is an anonymous module" do
- m = Module.new
+ it "uses class #name when receiver is an ordinary object" do
+ klass = Class.new { def self.name; "MyClass"; end }
+ instance = klass.new
- begin
- m.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
end
+ end
- it "uses class #name when receiver is an ordinary object" do
- klass = Class.new { def self.name; "MyClass"; end }
- instance = klass.new
+ it "uses class string representation when receiver is an instance of anonymous class" do
+ klass = Class.new
+ instance = klass.new
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
end
+ end
- it "uses class string representation when receiver is an instance of anonymous class" do
- klass = Class.new
- instance = klass.new
+ it "uses class name when receiver has a singleton class" do
+ instance = NoMethodErrorSpecs::NoMethodErrorA.new
+ def instance.foo; end
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
end
+ end
- it "uses class name when receiver has a singleton class" do
- instance = NoMethodErrorSpecs::NoMethodErrorA.new
- def instance.foo; end
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
+ it "does not call #inspect when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ "<inspect>"
end
end
+ instance = test_class.new
- it "does not call #inspect when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
- ScratchPad.recorded.should == []
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
+ ScratchPad.recorded.should == []
end
+ end
- it "does not truncate long class names" do
- class_name = 'ExceptionSpecs::A' + 'a'*100
+ it "does not truncate long class names" do
+ class_name = 'ExceptionSpecs::A' + 'a'*100
- begin
- eval <<~RUBY
- class #{class_name}
- end
+ begin
+ eval <<~RUBY
+ class #{class_name}
+ end
- obj = #{class_name}.new
- obj.foo
- RUBY
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
- end
+ obj = #{class_name}.new
+ obj.foo
+ RUBY
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
end
end
end
diff --git a/spec/ruby/core/exception/reason_spec.rb b/spec/ruby/core/exception/reason_spec.rb
index 210bbc9725..d7022768b6 100644
--- a/spec/ruby/core/exception/reason_spec.rb
+++ b/spec/ruby/core/exception/reason_spec.rb
@@ -6,7 +6,7 @@ describe "LocalJumpError#reason" do
end
it "returns 'return' for a return" do
- -> { get_me_a_return.call }.should raise_error(LocalJumpError) { |e|
+ -> { get_me_a_return.call }.should.raise(LocalJumpError) { |e|
e.reason.should == :return
}
end
diff --git a/spec/ruby/core/exception/receiver_spec.rb b/spec/ruby/core/exception/receiver_spec.rb
index d1c23b67be..6ecf640ad8 100644
--- a/spec/ruby/core/exception/receiver_spec.rb
+++ b/spec/ruby/core/exception/receiver_spec.rb
@@ -11,31 +11,31 @@ describe "NameError#receiver" do
-> {
receiver.doesnt_exist
- }.should raise_error(NameError) {|e| e.receiver.should equal(receiver) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(receiver) }
end
it "returns the Object class when an undefined constant is called without namespace" do
-> {
DoesntExist
- }.should raise_error(NameError) {|e| e.receiver.should equal(Object) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(Object) }
end
it "returns a class when an undefined constant is called" do
-> {
NameErrorSpecs::ReceiverClass::DoesntExist
- }.should raise_error(NameError) {|e| e.receiver.should equal(NameErrorSpecs::ReceiverClass) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(NameErrorSpecs::ReceiverClass) }
end
it "returns the Object class when an undefined class variable is called" do
-> {
eval("class singleton_class::A; @@doesnt_exist end", binding, __FILE__, __LINE__)
- }.should raise_error(NameError) {|e| e.receiver.should equal(singleton_class::A) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(singleton_class::A) }
end
it "returns a class when an undefined class variable is called in a subclass' namespace" do
-> {
NameErrorSpecs::ReceiverClass.new.call_undefined_class_variable
- }.should raise_error(NameError) {|e| e.receiver.should equal(NameErrorSpecs::ReceiverClass) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(NameErrorSpecs::ReceiverClass) }
end
it "returns the receiver when raised from #instance_variable_get" do
@@ -43,16 +43,16 @@ describe "NameError#receiver" do
-> {
receiver.instance_variable_get("invalid_ivar_name")
- }.should raise_error(NameError) {|e| e.receiver.should equal(receiver) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(receiver) }
end
it "returns the receiver when raised from #class_variable_get" do
-> {
Object.class_variable_get("invalid_cvar_name")
- }.should raise_error(NameError) {|e| e.receiver.should equal(Object) }
+ }.should.raise(NameError) {|e| e.receiver.should.equal?(Object) }
end
it "raises an ArgumentError when the receiver is none" do
- -> { NameError.new.receiver }.should raise_error(ArgumentError)
+ -> { NameError.new.receiver }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/exception/result_spec.rb b/spec/ruby/core/exception/result_spec.rb
index d42fcdffcb..451ff43af5 100644
--- a/spec/ruby/core/exception/result_spec.rb
+++ b/spec/ruby/core/exception/result_spec.rb
@@ -14,8 +14,8 @@ describe "StopIteration#result" do
it "returns the method-returned-object from an Enumerator" do
@enum.next
@enum.next
- -> { @enum.next }.should raise_error(StopIteration) { |error|
- error.result.should equal(:method_returned)
+ -> { @enum.next }.should.raise(StopIteration) { |error|
+ error.result.should.equal?(:method_returned)
}
end
end
diff --git a/spec/ruby/core/exception/set_backtrace_spec.rb b/spec/ruby/core/exception/set_backtrace_spec.rb
index 12c1da919c..2cd93326ec 100644
--- a/spec/ruby/core/exception/set_backtrace_spec.rb
+++ b/spec/ruby/core/exception/set_backtrace_spec.rb
@@ -1,13 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
+require_relative 'shared/set_backtrace'
describe "Exception#set_backtrace" do
- it "accepts an Array of Strings" do
- err = RuntimeError.new
- err.set_backtrace ["unhappy"]
- err.backtrace.should == ["unhappy"]
- end
-
it "allows the user to set the backtrace from a rescued exception" do
bt = ExceptionSpecs::Backtrace.backtrace
err = RuntimeError.new
@@ -20,65 +15,9 @@ describe "Exception#set_backtrace" do
err.backtrace_locations.should == nil
end
- ruby_version_is "3.4" do
- it "allows the user to set backtrace locations from a rescued exception" do
- bt_locations = ExceptionSpecs::Backtrace.backtrace_locations
- err = RuntimeError.new
- err.backtrace.should == nil
- err.backtrace_locations.should == nil
-
- err.set_backtrace bt_locations
-
- err.backtrace_locations.size.should == bt_locations.size
- err.backtrace_locations.each_with_index do |loc, index|
- other_loc = bt_locations[index]
-
- loc.path.should == other_loc.path
- loc.label.should == other_loc.label
- loc.base_label.should == other_loc.base_label
- loc.lineno.should == other_loc.lineno
- loc.absolute_path.should == other_loc.absolute_path
- loc.to_s.should == other_loc.to_s
- end
- err.backtrace.size.should == err.backtrace_locations.size
- end
- end
-
- it "accepts an empty Array" do
- err = RuntimeError.new
- err.set_backtrace []
- err.backtrace.should == []
- end
-
- it "accepts a String" do
+ it_behaves_like :exception_set_backtrace, -> backtrace {
err = RuntimeError.new
- err.set_backtrace "unhappy"
- err.backtrace.should == ["unhappy"]
- end
-
- it "accepts nil" do
- err = RuntimeError.new
- err.set_backtrace nil
- err.backtrace.should be_nil
- end
-
- it "raises a TypeError when passed a Symbol" do
- err = RuntimeError.new
- -> { err.set_backtrace :unhappy }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when the Array contains a Symbol" do
- err = RuntimeError.new
- -> { err.set_backtrace ["String", :unhappy] }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when the array contains nil" do
- err = Exception.new
- -> { err.set_backtrace ["String", nil] }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when the argument is a nested array" do
- err = Exception.new
- -> { err.set_backtrace ["String", ["String"]] }.should raise_error(TypeError)
- end
+ err.set_backtrace(backtrace)
+ err
+ }
end
diff --git a/spec/ruby/core/exception/shared/new.rb b/spec/ruby/core/exception/shared/new.rb
index bcde8ee4b2..048fd14dd2 100644
--- a/spec/ruby/core/exception/shared/new.rb
+++ b/spec/ruby/core/exception/shared/new.rb
@@ -1,6 +1,6 @@
describe :exception_new, shared: true do
it "creates a new instance of Exception" do
- Exception.should be_ancestor_of(Exception.send(@method).class)
+ Exception.send(@method).class.ancestors.should.include?(Exception)
end
it "sets the message of the Exception when passes a message" do
@@ -12,7 +12,7 @@ describe :exception_new, shared: true do
end
it "returns the exception when it has a custom constructor" do
- ExceptionSpecs::ConstructorException.send(@method).should be_kind_of(ExceptionSpecs::ConstructorException)
+ ExceptionSpecs::ConstructorException.send(@method).should.is_a?(ExceptionSpecs::ConstructorException)
end
end
diff --git a/spec/ruby/core/exception/shared/set_backtrace.rb b/spec/ruby/core/exception/shared/set_backtrace.rb
new file mode 100644
index 0000000000..934bf3dc5f
--- /dev/null
+++ b/spec/ruby/core/exception/shared/set_backtrace.rb
@@ -0,0 +1,64 @@
+require_relative '../fixtures/common'
+
+describe :exception_set_backtrace, shared: true do
+ it "accepts an Array of Strings" do
+ err = @method.call(["unhappy"])
+ err.backtrace.should == ["unhappy"]
+ end
+
+ it "allows the user to set the backtrace from a rescued exception" do
+ bt = ExceptionSpecs::Backtrace.backtrace
+ err = @method.call(bt)
+ err.backtrace.should == bt
+ end
+
+ ruby_version_is "3.4" do
+ it "allows the user to set backtrace locations from a rescued exception" do
+ bt_locations = ExceptionSpecs::Backtrace.backtrace_locations
+ err = @method.call(bt_locations)
+ err.backtrace_locations.size.should == bt_locations.size
+ err.backtrace_locations.each_with_index do |loc, index|
+ other_loc = bt_locations[index]
+
+ loc.path.should == other_loc.path
+ loc.label.should == other_loc.label
+ loc.base_label.should == other_loc.base_label
+ loc.lineno.should == other_loc.lineno
+ loc.absolute_path.should == other_loc.absolute_path
+ loc.to_s.should == other_loc.to_s
+ end
+ err.backtrace.size.should == err.backtrace_locations.size
+ end
+ end
+
+ it "accepts an empty Array" do
+ err = @method.call([])
+ err.backtrace.should == []
+ end
+
+ it "accepts a String" do
+ err = @method.call("unhappy")
+ err.backtrace.should == ["unhappy"]
+ end
+
+ it "accepts nil" do
+ err = @method.call(nil)
+ err.backtrace.should == nil
+ end
+
+ it "raises a TypeError when passed a Symbol" do
+ -> { @method.call(:unhappy) }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when the Array contains a Symbol" do
+ -> { @method.call(["String", :unhappy]) }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when the array contains nil" do
+ -> { @method.call(["String", nil]) }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError when the argument is a nested array" do
+ -> { @method.call(["String", ["String"]]) }.should.raise(TypeError)
+ end
+end
diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb
index 1a0940743f..010181bc55 100644
--- a/spec/ruby/core/exception/signal_exception_spec.rb
+++ b/spec/ruby/core/exception/signal_exception_spec.rb
@@ -9,7 +9,7 @@ describe "SignalException.new" do
end
it "raises an exception with an invalid signal number" do
- -> { SignalException.new(100000) }.should raise_error(ArgumentError)
+ -> { SignalException.new(100000) }.should.raise(ArgumentError)
end
it "takes a signal name without SIG prefix as the first argument" do
@@ -27,11 +27,11 @@ describe "SignalException.new" do
end
it "raises an exception with an invalid signal name" do
- -> { SignalException.new("NONEXISTENT") }.should raise_error(ArgumentError)
+ -> { SignalException.new("NONEXISTENT") }.should.raise(ArgumentError)
end
it "raises an exception with an invalid first argument type" do
- -> { SignalException.new(Object.new) }.should raise_error(ArgumentError)
+ -> { SignalException.new(Object.new) }.should.raise(ArgumentError)
end
it "takes a signal symbol without SIG prefix as the first argument" do
@@ -49,7 +49,7 @@ describe "SignalException.new" do
end
it "raises an exception with an invalid signal name" do
- -> { SignalException.new(:NONEXISTENT) }.should raise_error(ArgumentError)
+ -> { SignalException.new(:NONEXISTENT) }.should.raise(ArgumentError)
end
it "takes an optional message argument with a signal number" do
@@ -60,7 +60,7 @@ describe "SignalException.new" do
end
it "raises an exception for an optional argument with a signal name" do
- -> { SignalException.new("INT","name") }.should raise_error(ArgumentError)
+ -> { SignalException.new("INT","name") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/exception/signm_spec.rb b/spec/ruby/core/exception/signm_spec.rb
index 4adff3b5ee..cabcc7ad58 100644
--- a/spec/ruby/core/exception/signm_spec.rb
+++ b/spec/ruby/core/exception/signm_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "SignalException#signm" do
it "returns the signal name" do
- -> { Process.kill(:TERM, Process.pid) }.should raise_error(SignalException) { |e|
+ -> { Process.kill(:TERM, Process.pid) }.should.raise(SignalException) { |e|
e.signm.should == 'SIGTERM'
}
end
diff --git a/spec/ruby/core/exception/signo_spec.rb b/spec/ruby/core/exception/signo_spec.rb
index 62fc321516..46e79a8daf 100644
--- a/spec/ruby/core/exception/signo_spec.rb
+++ b/spec/ruby/core/exception/signo_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "SignalException#signo" do
it "returns the signal number" do
- -> { Process.kill(:TERM, Process.pid) }.should raise_error(SignalException) { |e|
+ -> { Process.kill(:TERM, Process.pid) }.should.raise(SignalException) { |e|
e.signo.should == Signal.list['TERM']
}
end
diff --git a/spec/ruby/core/exception/standard_error_spec.rb b/spec/ruby/core/exception/standard_error_spec.rb
index 17e98ce7f0..b05d247f67 100644
--- a/spec/ruby/core/exception/standard_error_spec.rb
+++ b/spec/ruby/core/exception/standard_error_spec.rb
@@ -18,6 +18,6 @@ describe "StandardError" do
end
it "does not rescue superclass of StandardError" do
- -> { begin; raise Exception; rescue; end }.should raise_error(Exception)
+ -> { begin; raise Exception; rescue; end }.should.raise(Exception)
end
end
diff --git a/spec/ruby/core/exception/status_spec.rb b/spec/ruby/core/exception/status_spec.rb
index 8ace00fe10..7369b0815d 100644
--- a/spec/ruby/core/exception/status_spec.rb
+++ b/spec/ruby/core/exception/status_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "SystemExit#status" do
it "returns the exit status" do
- -> { exit 42 }.should raise_error(SystemExit) { |e|
+ -> { exit 42 }.should.raise(SystemExit) { |e|
e.status.should == 42
}
end
diff --git a/spec/ruby/core/exception/success_spec.rb b/spec/ruby/core/exception/success_spec.rb
index 6f21743340..5ab8f94454 100644
--- a/spec/ruby/core/exception/success_spec.rb
+++ b/spec/ruby/core/exception/success_spec.rb
@@ -2,13 +2,13 @@ require_relative '../../spec_helper'
describe "SystemExit#success?" do
it "returns true if the process exited successfully" do
- -> { exit 0 }.should raise_error(SystemExit) { |e|
+ -> { exit 0 }.should.raise(SystemExit) { |e|
e.should.success?
}
end
it "returns false if the process exited unsuccessfully" do
- -> { exit(-1) }.should raise_error(SystemExit) { |e|
+ -> { exit(-1) }.should.raise(SystemExit) { |e|
e.should_not.success?
}
end
diff --git a/spec/ruby/core/exception/syntax_error_spec.rb b/spec/ruby/core/exception/syntax_error_spec.rb
index 6cc8522de3..66eb5649aa 100644
--- a/spec/ruby/core/exception/syntax_error_spec.rb
+++ b/spec/ruby/core/exception/syntax_error_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "SyntaxError#path" do
- it "returns the file path provided to eval" do
- filename = "speccing.rb"
+describe "SyntaxError#path" do
+ it "returns the file path provided to eval" do
+ filename = "speccing.rb"
- -> {
- eval("if true", TOPLEVEL_BINDING, filename)
- }.should raise_error(SyntaxError) { |e|
- e.path.should == filename
- }
- end
+ -> {
+ eval("if true", TOPLEVEL_BINDING, filename)
+ }.should.raise(SyntaxError) { |e|
+ e.path.should == filename
+ }
+ end
- it "returns the file path that raised an exception" do
- expected_path = fixture(__FILE__, "syntax_error.rb")
+ it "returns the file path that raised an exception" do
+ expected_path = fixture(__FILE__, "syntax_error.rb")
- -> {
- require_relative "fixtures/syntax_error"
- }.should raise_error(SyntaxError) { |e| e.path.should == expected_path }
- end
+ -> {
+ require_relative "fixtures/syntax_error"
+ }.should.raise(SyntaxError) { |e| e.path.should == expected_path }
+ end
- it "returns nil when constructed directly" do
- SyntaxError.new.path.should == nil
- end
+ it "returns nil when constructed directly" do
+ SyntaxError.new.path.should == nil
end
end
diff --git a/spec/ruby/core/exception/system_call_error_spec.rb b/spec/ruby/core/exception/system_call_error_spec.rb
index 4fe51901c8..da01c5b6b0 100644
--- a/spec/ruby/core/exception/system_call_error_spec.rb
+++ b/spec/ruby/core/exception/system_call_error_spec.rb
@@ -14,8 +14,8 @@ describe "SystemCallError" do
end
exc = ExceptionSpecs::SCESub.new
- ScratchPad.recorded.should equal(:initialize)
- exc.should be_an_instance_of(ExceptionSpecs::SCESub)
+ ScratchPad.recorded.should.equal?(:initialize)
+ exc.should.instance_of?(ExceptionSpecs::SCESub)
ensure
ExceptionSpecs.send(:remove_const, :SCESub)
end
@@ -31,7 +31,7 @@ describe "SystemCallError.new" do
end
it "requires at least one argument" do
- -> { SystemCallError.new }.should raise_error(ArgumentError)
+ -> { SystemCallError.new }.should.raise(ArgumentError)
end
it "accepts single Integer argument as errno" do
@@ -44,16 +44,16 @@ describe "SystemCallError.new" do
end
it "constructs a SystemCallError for an unknown error number" do
- SystemCallError.new(-2**24).should be_an_instance_of(SystemCallError)
- SystemCallError.new(-1).should be_an_instance_of(SystemCallError)
- SystemCallError.new(@unknown_errno).should be_an_instance_of(SystemCallError)
- SystemCallError.new(2**24).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(-2**24).should.instance_of?(SystemCallError)
+ SystemCallError.new(-1).should.instance_of?(SystemCallError)
+ SystemCallError.new(@unknown_errno).should.instance_of?(SystemCallError)
+ SystemCallError.new(2**24).should.instance_of?(SystemCallError)
end
it "constructs the appropriate Errno class" do
e = SystemCallError.new(@example_errno)
- e.should be_kind_of(SystemCallError)
- e.should be_an_instance_of(@example_errno_class)
+ e.should.is_a?(SystemCallError)
+ e.should.instance_of?(@example_errno_class)
end
it "sets an error message corresponding to an appropriate Errno class" do
@@ -63,14 +63,14 @@ describe "SystemCallError.new" do
it "accepts an optional custom message preceding the errno" do
exc = SystemCallError.new("custom message", @example_errno)
- exc.should be_an_instance_of(@example_errno_class)
+ exc.should.instance_of?(@example_errno_class)
exc.errno.should == @example_errno
exc.message.should == 'Invalid argument - custom message'
end
it "accepts an optional third argument specifying the location" do
exc = SystemCallError.new("custom message", @example_errno, "location")
- exc.should be_an_instance_of(@example_errno_class)
+ exc.should.instance_of?(@example_errno_class)
exc.errno.should == @example_errno
exc.message.should == 'Invalid argument @ location - custom message'
end
@@ -90,7 +90,7 @@ describe "SystemCallError.new" do
end
it "treats nil errno as unknown error value" do
- SystemCallError.new(nil).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(nil).should.instance_of?(SystemCallError)
end
it "treats nil custom message as if it is not passed at all" do
@@ -111,15 +111,15 @@ describe "SystemCallError.new" do
end
it "raises TypeError if message is not a String" do
- -> { SystemCallError.new(:foo, 1) }.should raise_error(TypeError, /no implicit conversion of Symbol into String/)
+ -> { SystemCallError.new(:foo, 1) }.should.raise(TypeError, /no implicit conversion of Symbol into String/)
end
it "raises TypeError if errno is not an Integer" do
- -> { SystemCallError.new('foo', 'bar') }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
+ -> { SystemCallError.new('foo', 'bar') }.should.raise(TypeError, /no implicit conversion of String into Integer/)
end
it "raises RangeError if errno is a Complex not convertible to Integer" do
- -> { SystemCallError.new('foo', Complex(2.9, 1)) }.should raise_error(RangeError, /can't convert/)
+ -> { SystemCallError.new('foo', Complex(2.9, 1)) }.should.raise(RangeError, /can't convert/)
end
end
diff --git a/spec/ruby/core/false/dup_spec.rb b/spec/ruby/core/false/dup_spec.rb
index 1a569a2f4f..b0eb85529e 100644
--- a/spec/ruby/core/false/dup_spec.rb
+++ b/spec/ruby/core/false/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "FalseClass#dup" do
it "returns self" do
- false.dup.should equal(false)
+ false.dup.should.equal?(false)
end
end
diff --git a/spec/ruby/core/false/falseclass_spec.rb b/spec/ruby/core/false/falseclass_spec.rb
index c018ef2421..8dfe5ae891 100644
--- a/spec/ruby/core/false/falseclass_spec.rb
+++ b/spec/ruby/core/false/falseclass_spec.rb
@@ -4,12 +4,12 @@ describe "FalseClass" do
it ".allocate raises a TypeError" do
-> do
FalseClass.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
FalseClass.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb
index 738794b46c..72aee8609a 100644
--- a/spec/ruby/core/false/singleton_method_spec.rb
+++ b/spec/ruby/core/false/singleton_method_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../spec_helper'
describe "FalseClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether FalseClass defines the method" do
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (false).foo; end
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- FalseClass.send(:remove_method, :foo)
- end
+ it "raises regardless of whether FalseClass defines the method" do
+ -> { false.singleton_method(:foo) }.should.raise(NameError)
+ begin
+ def (false).foo; end
+ -> { false.singleton_method(:foo) }.should.raise(NameError)
+ ensure
+ FalseClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/false/to_s_spec.rb b/spec/ruby/core/false/to_s_spec.rb
index 62f67f6f55..9e24be26a2 100644
--- a/spec/ruby/core/false/to_s_spec.rb
+++ b/spec/ruby/core/false/to_s_spec.rb
@@ -10,6 +10,6 @@ describe "FalseClass#to_s" do
end
it "always returns the same string" do
- false.to_s.should equal(false.to_s)
+ false.to_s.should.equal?(false.to_s)
end
end
diff --git a/spec/ruby/core/fiber/alive_spec.rb b/spec/ruby/core/fiber/alive_spec.rb
index a1df582435..6fb1229d95 100644
--- a/spec/ruby/core/fiber/alive_spec.rb
+++ b/spec/ruby/core/fiber/alive_spec.rb
@@ -3,18 +3,18 @@ require_relative '../../spec_helper'
describe "Fiber#alive?" do
it "returns true for a Fiber that hasn't had #resume called" do
fiber = Fiber.new { true }
- fiber.alive?.should be_true
+ fiber.alive?.should == true
end
# FIXME: Better description?
it "returns true for a Fiber that's yielded to the caller" do
fiber = Fiber.new { Fiber.yield }
fiber.resume
- fiber.alive?.should be_true
+ fiber.alive?.should == true
end
it "returns true when called from its Fiber" do
- fiber = Fiber.new { fiber.alive?.should be_true }
+ fiber = Fiber.new { fiber.alive?.should == true }
fiber.resume
end
@@ -28,17 +28,17 @@ describe "Fiber#alive?" do
it "returns false for a Fiber that's dead" do
fiber = Fiber.new { true }
fiber.resume
- -> { fiber.resume }.should raise_error(FiberError)
- fiber.alive?.should be_false
+ -> { fiber.resume }.should.raise(FiberError)
+ fiber.alive?.should == false
end
it "always returns false for a dead Fiber" do
fiber = Fiber.new { true }
fiber.resume
- -> { fiber.resume }.should raise_error(FiberError)
- fiber.alive?.should be_false
- -> { fiber.resume }.should raise_error(FiberError)
- fiber.alive?.should be_false
- fiber.alive?.should be_false
+ -> { fiber.resume }.should.raise(FiberError)
+ fiber.alive?.should == false
+ -> { fiber.resume }.should.raise(FiberError)
+ fiber.alive?.should == false
+ fiber.alive?.should == false
end
end
diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb
index ed3c057516..d5caf81fbe 100644
--- a/spec/ruby/core/fiber/blocking_spec.rb
+++ b/spec/ruby/core/fiber/blocking_spec.rb
@@ -57,19 +57,17 @@ describe "Fiber#blocking?" do
end
end
-ruby_version_is "3.2" do
- describe "Fiber.blocking" do
- context "when fiber is non-blocking" do
- it "can become blocking" do
- fiber = Fiber.new(blocking: false) do
- Fiber.blocking do |f|
- f.blocking? ? :blocking : :non_blocking
- end
+describe "Fiber.blocking" do
+ context "when fiber is non-blocking" do
+ it "can become blocking" do
+ fiber = Fiber.new(blocking: false) do
+ Fiber.blocking do |f|
+ f.blocking? ? :blocking : :non_blocking
end
-
- blocking = fiber.resume
- blocking.should == :blocking
end
+
+ blocking = fiber.resume
+ blocking.should == :blocking
end
end
end
diff --git a/spec/ruby/core/fiber/current_spec.rb b/spec/ruby/core/fiber/current_spec.rb
index b93df77a89..cc5c9117b6 100644
--- a/spec/ruby/core/fiber/current_spec.rb
+++ b/spec/ruby/core/fiber/current_spec.rb
@@ -3,20 +3,20 @@ require_relative '../../spec_helper'
describe "Fiber.current" do
it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current
- root.should be_an_instance_of(Fiber)
+ root.should.instance_of?(Fiber)
# We can always transfer to the root Fiber; it will never die
5.times do
- root.transfer.should be_nil
- root.alive?.should be_true
+ root.transfer.should == nil
+ root.alive?.should == true
end
end
it "returns the current Fiber when called from a Fiber" do
fiber = Fiber.new do
this = Fiber.current
- this.should be_an_instance_of(Fiber)
+ this.should.instance_of?(Fiber)
this.should == fiber
- this.alive?.should be_true
+ this.alive?.should == true
end
fiber.resume
end
@@ -26,9 +26,9 @@ describe "Fiber.current" do
fiber = Fiber.new do
states << :fiber
this = Fiber.current
- this.should be_an_instance_of(Fiber)
+ this.should.instance_of?(Fiber)
this.should == fiber
- this.alive?.should be_true
+ this.alive?.should == true
end
fiber2 = Fiber.new do
diff --git a/spec/ruby/core/fiber/fixtures/classes.rb b/spec/ruby/core/fiber/fixtures/classes.rb
index c00facd6e1..6b0e0fbc42 100644
--- a/spec/ruby/core/fiber/fixtures/classes.rb
+++ b/spec/ruby/core/fiber/fixtures/classes.rb
@@ -1,10 +1,20 @@
module FiberSpecs
class NewFiberToRaise
- def self.raise(*args)
- fiber = Fiber.new { Fiber.yield }
+ def self.raise(*args, **kwargs, &block)
+ fiber = Fiber.new do
+ if block_given?
+ block.call do
+ Fiber.yield
+ end
+ else
+ Fiber.yield
+ end
+ end
+
fiber.resume
- fiber.raise(*args)
+
+ fiber.raise(*args, **kwargs)
end
end
diff --git a/spec/ruby/core/fiber/fixtures/scheduler.rb b/spec/ruby/core/fiber/fixtures/scheduler.rb
new file mode 100644
index 0000000000..16bd2f6b44
--- /dev/null
+++ b/spec/ruby/core/fiber/fixtures/scheduler.rb
@@ -0,0 +1,35 @@
+module FiberSpecs
+
+ class LoggingScheduler
+ attr_reader :events
+ def initialize
+ @events = []
+ end
+
+ def block(*args)
+ @events << { event: :block, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def io_wait(*args)
+ @events << { event: :io_wait, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def kernel_sleep(*args)
+ @events << { event: :kernel_sleep, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def unblock(*args)
+ @events << { event: :unblock, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def fiber_interrupt(*args)
+ @events << { event: :fiber_interrupt, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+ end
+
+end
diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb
index 2f4c499280..abf23ff176 100644
--- a/spec/ruby/core/fiber/kill_spec.rb
+++ b/spec/ruby/core/fiber/kill_spec.rb
@@ -2,89 +2,87 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
-ruby_version_is "3.3" do
- describe "Fiber#kill" do
- it "kills a non-resumed fiber" do
- fiber = Fiber.new{}
+describe "Fiber#kill" do
+ it "kills a non-resumed fiber" do
+ fiber = Fiber.new{}
- fiber.alive?.should == true
+ fiber.alive?.should == true
- fiber.kill
- fiber.alive?.should == false
- end
-
- it "kills a resumed fiber" do
- fiber = Fiber.new{while true; Fiber.yield; end}
- fiber.resume
-
- fiber.alive?.should == true
+ fiber.kill
+ fiber.alive?.should == false
+ end
- fiber.kill
- fiber.alive?.should == false
- end
+ it "kills a resumed fiber" do
+ fiber = Fiber.new{while true; Fiber.yield; end}
+ fiber.resume
- it "can kill itself" do
- fiber = Fiber.new do
- Fiber.current.kill
- end
+ fiber.alive?.should == true
- fiber.alive?.should == true
+ fiber.kill
+ fiber.alive?.should == false
+ end
- fiber.resume
- fiber.alive?.should == false
+ it "can kill itself" do
+ fiber = Fiber.new do
+ Fiber.current.kill
end
- it "kills a resumed fiber from a child" do
- parent = Fiber.new do
- child = Fiber.new do
- parent.kill
- parent.alive?.should == true
- end
+ fiber.alive?.should == true
+
+ fiber.resume
+ fiber.alive?.should == false
+ end
- child.resume
+ it "kills a resumed fiber from a child" do
+ parent = Fiber.new do
+ child = Fiber.new do
+ parent.kill
+ parent.alive?.should == true
end
- parent.resume
- parent.alive?.should == false
+ child.resume
end
- it "executes the ensure block" do
- ensure_executed = false
+ parent.resume
+ parent.alive?.should == false
+ end
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- ensure_executed = true
- end
+ it "executes the ensure block" do
+ ensure_executed = false
- fiber.resume
- fiber.kill
- ensure_executed.should == true
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ ensure
+ ensure_executed = true
end
- it "does not execute rescue block" do
- rescue_executed = false
+ fiber.resume
+ fiber.kill
+ ensure_executed.should == true
+ end
- fiber = Fiber.new do
- while true; Fiber.yield; end
- rescue Exception
- rescue_executed = true
- end
+ it "does not execute rescue block" do
+ rescue_executed = false
- fiber.resume
- fiber.kill
- rescue_executed.should == false
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ rescue Exception
+ rescue_executed = true
end
- it "repeatedly kills a fiber" do
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- while true; Fiber.yield; end
- end
+ fiber.resume
+ fiber.kill
+ rescue_executed.should == false
+ end
- fiber.kill
- fiber.alive?.should == false
+ it "repeatedly kills a fiber" do
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ ensure
+ while true; Fiber.yield; end
end
+
+ fiber.kill
+ fiber.alive?.should == false
end
end
diff --git a/spec/ruby/core/fiber/new_spec.rb b/spec/ruby/core/fiber/new_spec.rb
index b43c1386be..d31167496d 100644
--- a/spec/ruby/core/fiber/new_spec.rb
+++ b/spec/ruby/core/fiber/new_spec.rb
@@ -4,7 +4,7 @@ describe "Fiber.new" do
it "creates a fiber from the given block" do
fiber = Fiber.new {}
fiber.resume
- fiber.should be_an_instance_of(Fiber)
+ fiber.should.instance_of?(Fiber)
end
it "creates a fiber from a subclass" do
@@ -12,17 +12,17 @@ describe "Fiber.new" do
end
fiber = MyFiber.new {}
fiber.resume
- fiber.should be_an_instance_of(MyFiber)
+ fiber.should.instance_of?(MyFiber)
end
it "raises an ArgumentError if called without a block" do
- -> { Fiber.new }.should raise_error(ArgumentError)
+ -> { Fiber.new }.should.raise(ArgumentError)
end
it "does not invoke the block" do
invoked = false
fiber = Fiber.new { invoked = true }
- invoked.should be_false
+ invoked.should == false
fiber.resume
end
diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb
index 124f56fe7d..107e5bd4ce 100644
--- a/spec/ruby/core/fiber/raise_spec.rb
+++ b/spec/ruby/core/fiber/raise_spec.rb
@@ -3,56 +3,62 @@ require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
describe "Fiber#raise" do
+ it "is a public method" do
+ Fiber.public_instance_methods.should.include?(:raise)
+ end
+
it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
-end
+ it_behaves_like :kernel_raise_across_contexts, :raise, FiberSpecs::NewFiberToRaise
+ ruby_version_is "4.0" do
+ it_behaves_like :kernel_raise_with_cause, :raise, FiberSpecs::NewFiberToRaise
+ end
-describe "Fiber#raise" do
it 'raises RuntimeError by default' do
- -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError)
+ -> { FiberSpecs::NewFiberToRaise.raise }.should.raise(RuntimeError)
end
it "raises FiberError if Fiber is not born" do
fiber = Fiber.new { true }
- -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber")
+ -> { fiber.raise }.should.raise(FiberError, "cannot raise exception on unborn fiber")
end
it "raises FiberError if Fiber is dead" do
fiber = Fiber.new { true }
fiber.resume
- -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ -> { fiber.raise }.should.raise(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end
it 'accepts error class' do
- -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError)
+ -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should.raise(FiberSpecs::CustomError)
end
it 'accepts error message' do
- -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message")
+ -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should.raise(RuntimeError, "error message")
end
it 'does not accept array of backtrace information only' do
- -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError)
+ -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should.raise(TypeError)
end
it 'does not accept integer' do
- -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError)
+ -> { FiberSpecs::NewFiberToRaise.raise 100 }.should.raise(TypeError)
end
it 'accepts error class with error message' do
- -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error')
+ -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should.raise(FiberSpecs::CustomError, 'test error')
end
it 'accepts error class with error message and backtrace information' do
-> {
FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo']
- }.should raise_error(FiberSpecs::CustomError) { |e|
+ }.should.raise(FiberSpecs::CustomError) { |e|
e.message.should == 'test error'
e.backtrace.should == ['foo', 'boo']
}
end
it 'does not accept only error message and backtrace information' do
- -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError)
+ -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should.raise(TypeError)
end
it "raises a FiberError if invoked from a different Thread" do
@@ -61,15 +67,15 @@ describe "Fiber#raise" do
Thread.new do
-> {
fiber.raise
- }.should raise_error(FiberError, "fiber called across threads")
+ }.should.raise(FiberError, "fiber called across threads")
end.join
end
it "kills Fiber" do
fiber = Fiber.new { Fiber.yield :first; :second }
fiber.resume
- -> { fiber.raise }.should raise_error
- -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ -> { fiber.raise }.should.raise
+ -> { fiber.resume }.should.raise(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end
it "returns to calling fiber after raise" do
@@ -101,13 +107,13 @@ describe "Fiber#raise" do
-> do
f2.raise(RuntimeError, "Expected error")
- end.should raise_error(RuntimeError, "Expected error")
+ end.should.raise(RuntimeError, "Expected error")
end
it "raises on itself" do
-> do
Fiber.current.raise(RuntimeError, "Expected error")
- end.should raise_error(RuntimeError, "Expected error")
+ end.should.raise(RuntimeError, "Expected error")
end
it "should raise on parent fiber" do
@@ -122,17 +128,14 @@ describe "Fiber#raise" do
-> do
f2.resume
- end.should raise_error(RuntimeError, "Expected error")
+ end.should.raise(RuntimeError, "Expected error")
end
end
-end
-
-describe "Fiber#raise" do
it "transfers and raises on a transferring fiber" do
root = Fiber.current
fiber = Fiber.new { root.transfer }
fiber.transfer
- -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
+ -> { fiber.raise "msg" }.should.raise(RuntimeError, "msg")
end
end
diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb
index 4b20f4b4bf..e183cc10d9 100644
--- a/spec/ruby/core/fiber/resume_spec.rb
+++ b/spec/ruby/core/fiber/resume_spec.rb
@@ -30,7 +30,7 @@ describe "Fiber#resume" do
it "raises a FiberError if the Fiber tries to resume itself" do
fiber = Fiber.new { fiber.resume }
- -> { fiber.resume }.should raise_error(FiberError, /current fiber/)
+ -> { fiber.resume }.should.raise(FiberError, /current fiber/)
end
it "returns control to the calling Fiber if called from one" do
@@ -78,6 +78,6 @@ describe "Fiber#resume" do
it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
root_fiber = Fiber.current
fiber1 = Fiber.new { root_fiber.resume }
- -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
+ -> { fiber1.resume }.should.raise(FiberError, /attempt to resume a resuming fiber/)
end
end
diff --git a/spec/ruby/core/fiber/scheduler_spec.rb b/spec/ruby/core/fiber/scheduler_spec.rb
new file mode 100644
index 0000000000..15a03c1479
--- /dev/null
+++ b/spec/ruby/core/fiber/scheduler_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/scheduler'
+
+require "fiber"
+
+describe "Fiber.scheduler" do
+ it_behaves_like :scheduler, :scheduler
+end
diff --git a/spec/ruby/core/fiber/set_scheduler_spec.rb b/spec/ruby/core/fiber/set_scheduler_spec.rb
new file mode 100644
index 0000000000..82f6acbe86
--- /dev/null
+++ b/spec/ruby/core/fiber/set_scheduler_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/scheduler'
+
+require "fiber"
+
+describe "Fiber.scheduler" do
+ it_behaves_like :scheduler, :set_scheduler
+end
diff --git a/spec/ruby/core/fiber/shared/resume.rb b/spec/ruby/core/fiber/shared/resume.rb
index 5ee27d1d24..ff4bb72c73 100644
--- a/spec/ruby/core/fiber/shared/resume.rb
+++ b/spec/ruby/core/fiber/shared/resume.rb
@@ -9,7 +9,7 @@ describe :fiber_resume, shared: true do
Thread.new do
-> {
fiber.send(@method)
- }.should raise_error(FiberError)
+ }.should.raise(FiberError)
end.join
# Check the Fiber can still be used
@@ -20,12 +20,12 @@ describe :fiber_resume, shared: true do
invoked = false
fiber = Fiber.new { invoked = true }
fiber.send(@method)
- invoked.should be_true
+ invoked.should == true
end
it "returns the last value encountered on first invocation" do
fiber = Fiber.new { 1+1; true }
- fiber.send(@method).should be_true
+ fiber.send(@method).should == true
end
it "runs until the end of the block" do
@@ -37,22 +37,22 @@ describe :fiber_resume, shared: true do
it "accepts any number of arguments" do
fiber = Fiber.new { |a| }
- -> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error
+ -> { fiber.send(@method, *(1..10).to_a) }.should_not.raise
end
it "raises a FiberError if the Fiber is dead" do
fiber = Fiber.new { true }
fiber.send(@method)
- -> { fiber.send(@method) }.should raise_error(FiberError)
+ -> { fiber.send(@method) }.should.raise(FiberError)
end
it "raises a LocalJumpError if the block includes a return statement" do
fiber = Fiber.new { return; }
- -> { fiber.send(@method) }.should raise_error(LocalJumpError)
+ -> { fiber.send(@method) }.should.raise(LocalJumpError)
end
it "raises a LocalJumpError if the block includes a break statement" do
fiber = Fiber.new { break; }
- -> { fiber.send(@method) }.should raise_error(LocalJumpError)
+ -> { fiber.send(@method) }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/core/fiber/shared/scheduler.rb b/spec/ruby/core/fiber/shared/scheduler.rb
new file mode 100644
index 0000000000..04bdded53a
--- /dev/null
+++ b/spec/ruby/core/fiber/shared/scheduler.rb
@@ -0,0 +1,51 @@
+describe :scheduler, shared: true do
+ it "validates the scheduler for required methods" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ required_methods.each do |missing_method|
+ scheduler = Object.new
+ required_methods.difference([missing_method]).each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ -> {
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ }.should.raise(ArgumentError, /Scheduler must implement ##{missing_method}/)
+ end
+ end
+
+ it "can set and get the scheduler" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ Fiber.scheduler.should == scheduler
+ end
+
+ it "returns the scheduler after setting it" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ result = suppress_warning { Fiber.set_scheduler(scheduler) }
+ result.should == scheduler
+ end
+
+ it "can remove the scheduler" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ Fiber.set_scheduler(nil)
+ Fiber.scheduler.should == nil
+ end
+
+ it "can assign a nil scheduler multiple times" do
+ Fiber.set_scheduler(nil)
+ Fiber.set_scheduler(nil)
+ Fiber.scheduler.should == nil
+ end
+end
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
index 03e9e3b822..a3f6bf9cad 100644
--- a/spec/ruby/core/fiber/storage_spec.rb
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -1,183 +1,177 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Fiber.new(storage:)" do
- it "creates a Fiber with the given storage" do
- storage = {life: 42}
- fiber = Fiber.new(storage: storage) { Fiber.current.storage }
- fiber.resume.should == storage
- end
+describe "Fiber.new(storage:)" do
+ it "creates a Fiber with the given storage" do
+ storage = {life: 42}
+ fiber = Fiber.new(storage: storage) { Fiber.current.storage }
+ fiber.resume.should == storage
+ end
- it "creates a fiber with lazily initialized storage" do
- Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10}
- end
+ it "creates a fiber with lazily initialized storage" do
+ Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10}
+ end
- it "creates a fiber by inheriting the storage of the parent fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Fiber.new { Fiber.current.storage }.resume
- end
- fiber.resume.should == {life: 42}
+ it "creates a fiber by inheriting the storage of the parent fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.new { Fiber.current.storage }.resume
end
+ fiber.resume.should == {life: 42}
+ end
- it "cannot create a fiber with non-hash storage" do
- -> { Fiber.new(storage: 42) {} }.should raise_error(TypeError)
- end
+ it "cannot create a fiber with non-hash storage" do
+ -> { Fiber.new(storage: 42) {} }.should.raise(TypeError)
+ end
- it "cannot create a fiber with a frozen hash as storage" do
- -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError)
- end
+ it "cannot create a fiber with a frozen hash as storage" do
+ -> { Fiber.new(storage: {life: 43}.freeze) {} }.should.raise(FrozenError)
+ end
- it "cannot create a fiber with a storage hash with non-symbol keys" do
- -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should raise_error(TypeError)
- end
+ it "cannot create a fiber with a storage hash with non-symbol keys" do
+ -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should.raise(TypeError)
end
+end
- describe "Fiber#storage" do
- it "cannot be accessed from a different fiber" do
- f = Fiber.new(storage: {life: 42}) { nil }
- -> {
- f.storage
- }.should raise_error(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
- end
+describe "Fiber#storage" do
+ it "cannot be accessed from a different fiber" do
+ f = Fiber.new(storage: {life: 42}) { nil }
+ -> {
+ f.storage
+ }.should.raise(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
end
+end
- describe "Fiber#storage=" do
- it "can clear the storage of the fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Fiber.current.storage = nil
- Fiber[:x] = 10
- Fiber.current.storage
- end
- fiber.resume.should == {x: 10}
+describe "Fiber#storage=" do
+ it "can clear the storage of the fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.current.storage = nil
+ Fiber[:x] = 10
+ Fiber.current.storage
end
+ fiber.resume.should == {x: 10}
+ end
- it "can set the storage of the fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Fiber.current.storage = {life: 43}
- Fiber.current.storage
- end
- fiber.resume.should == {life: 43}
+ it "can set the storage of the fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.current.storage = {life: 43}
+ Fiber.current.storage
end
+ fiber.resume.should == {life: 43}
+ end
- it "can't set the storage of the fiber to non-hash" do
- -> { Fiber.current.storage = 42 }.should raise_error(TypeError)
- end
+ it "can't set the storage of the fiber to non-hash" do
+ -> { Fiber.current.storage = 42 }.should.raise(TypeError)
+ end
- it "can't set the storage of the fiber to a frozen hash" do
- -> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError)
- end
+ it "can't set the storage of the fiber to a frozen hash" do
+ -> { Fiber.current.storage = {life: 43}.freeze }.should.raise(FrozenError)
+ end
- it "can't set the storage of the fiber to a hash with non-symbol keys" do
- -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
- end
+ it "can't set the storage of the fiber to a hash with non-symbol keys" do
+ -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should.raise(TypeError)
end
+end
- describe "Fiber.[]" do
- it "returns the value of the given key in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42
- end
+describe "Fiber.[]" do
+ it "returns the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42
+ end
- it "returns nil if the key is not present in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should be_nil
- end
+ it "returns nil if the key is not present in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should == nil
+ end
+
+ it "returns nil if the current fiber has no storage" do
+ Fiber.new { Fiber[:life] }.resume.should == nil
+ end
- it "returns nil if the current fiber has no storage" do
- Fiber.new { Fiber[:life] }.resume.should be_nil
+ it "can use dynamically defined keys" do
+ key = :"#{self.class.name}#.#{self.object_id}"
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
+ end
+
+ it "can't use invalid keys" do
+ invalid_keys = [Object.new, 12]
+ invalid_keys.each do |key|
+ -> { Fiber[key] }.should.raise(TypeError)
end
+ end
- ruby_version_is "3.2.3" do
- it "can use dynamically defined keys" do
- key = :"#{self.class.name}#.#{self.object_id}"
- Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
- end
-
- it "can't use invalid keys" do
- invalid_keys = [Object.new, 12]
- invalid_keys.each do |key|
- -> { Fiber[key] }.should raise_error(TypeError)
- end
- end
+ ruby_bug "#20978", ""..."3.4" do
+ it "can use keys as strings" do
+ key = Object.new
+ def key.to_str; "Foo"; end
+ Fiber.new { Fiber[key] = 42; Fiber["Foo"] }.resume.should == 42
end
- ruby_bug "#20978", "3.2"..."3.4" do
- it "can use keys as strings" do
- key = Object.new
- def key.to_str; "Foo"; end
- Fiber.new { Fiber[key] = 42; Fiber["Foo"] }.resume.should == 42
- end
-
- it "converts a String key into a Symbol" do
- Fiber.new { Fiber["key"] = 42; Fiber[:key] }.resume.should == 42
- Fiber.new { Fiber[:key] = 42; Fiber["key"] }.resume.should == 42
- end
-
- it "can use any object that responds to #to_str as a key" do
- key = mock("key")
- key.should_receive(:to_str).twice.and_return("key")
- Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
- end
+ it "converts a String key into a Symbol" do
+ Fiber.new { Fiber["key"] = 42; Fiber[:key] }.resume.should == 42
+ Fiber.new { Fiber[:key] = 42; Fiber["key"] }.resume.should == 42
end
- it "does not call #to_sym on the key" do
+ it "can use any object that responds to #to_str as a key" do
key = mock("key")
- key.should_not_receive(:to_sym)
- -> { Fiber[key] }.should raise_error(TypeError)
+ key.should_receive(:to_str).twice.and_return("key")
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
end
+ end
- it "can access the storage of the parent fiber" do
- f = Fiber.new(storage: {life: 42}) do
- Fiber.new { Fiber[:life] }.resume
- end
- f.resume.should == 42
- end
+ it "does not call #to_sym on the key" do
+ key = mock("key")
+ key.should_not_receive(:to_sym)
+ -> { Fiber[key] }.should.raise(TypeError)
+ end
- it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] }.should raise_error(TypeError)
+ it "can access the storage of the parent fiber" do
+ f = Fiber.new(storage: {life: 42}) do
+ Fiber.new { Fiber[:life] }.resume
end
+ f.resume.should == 42
end
- describe "Fiber.[]=" do
- it "sets the value of the given key in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
- end
+ it "can't access the storage of the fiber with non-symbol keys" do
+ -> { Fiber[Object.new] }.should.raise(TypeError)
+ end
+end
- it "sets the value of the given key in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:death] = 43; Fiber[:death] }.resume.should == 43
- end
+describe "Fiber.[]=" do
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
+ end
- it "sets the value of the given key in the storage of the current fiber" do
- Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
- end
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:death] = 43; Fiber[:death] }.resume.should == 43
+ end
- it "does not overwrite the storage of the parent fiber" do
- f = Fiber.new(storage: {life: 42}) do
- Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume
- Fiber[:life]
- end
- f.resume.should == 43 # Value of the inner fiber
- f.resume.should == 42 # Value of the outer fiber
- end
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
+ end
- it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] = 44 }.should raise_error(TypeError)
+ it "does not overwrite the storage of the parent fiber" do
+ f = Fiber.new(storage: {life: 42}) do
+ Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume
+ Fiber[:life]
end
+ f.resume.should == 43 # Value of the inner fiber
+ f.resume.should == 42 # Value of the outer fiber
+ end
- ruby_version_is "3.3" do
- it "deletes the fiber storage key when assigning nil" do
- Fiber.new(storage: {life: 42}) {
- Fiber[:life] = nil
- Fiber.current.storage
- }.resume.should == {}
- end
- end
+ it "can't access the storage of the fiber with non-symbol keys" do
+ -> { Fiber[Object.new] = 44 }.should.raise(TypeError)
end
- describe "Thread.new" do
- it "creates a thread with the storage of the current fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Thread.new { Fiber.current.storage }.value
- end
- fiber.resume.should == {life: 42}
+ it "deletes the fiber storage key when assigning nil" do
+ Fiber.new(storage: {life: 42}) {
+ Fiber[:life] = nil
+ Fiber.current.storage
+ }.resume.should == {}
+ end
+end
+
+describe "Thread.new" do
+ it "creates a thread with the storage of the current fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Thread.new { Fiber.current.storage }.value
end
+ fiber.resume.should == {life: 42}
end
end
diff --git a/spec/ruby/core/fiber/transfer_spec.rb b/spec/ruby/core/fiber/transfer_spec.rb
index 238721475d..d8737aeeb3 100644
--- a/spec/ruby/core/fiber/transfer_spec.rb
+++ b/spec/ruby/core/fiber/transfer_spec.rb
@@ -37,12 +37,12 @@ describe "Fiber#transfer" do
fiber1 = Fiber.new { states << :fiber1 }
fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end}
fiber2.resume.should == [:fiber2_start, :fiber1]
- -> { fiber2.transfer }.should raise_error(FiberError)
+ -> { fiber2.transfer }.should.raise(FiberError)
end
it "raises a FiberError when transferring to a Fiber which resumes itself" do
fiber = Fiber.new { fiber.resume }
- -> { fiber.transfer }.should raise_error(FiberError)
+ -> { fiber.transfer }.should.raise(FiberError)
end
it "works if Fibers in different Threads each transfer to a Fiber in the same Thread" do
@@ -58,7 +58,7 @@ describe "Fiber#transfer" do
end
io_fiber.transfer(Fiber.current)
value = Object.new
- io_fiber.transfer(value).should equal value
+ io_fiber.transfer(value).should.equal? value
end.join
end
end
diff --git a/spec/ruby/core/fiber/yield_spec.rb b/spec/ruby/core/fiber/yield_spec.rb
index b010912c87..12ec6ebcef 100644
--- a/spec/ruby/core/fiber/yield_spec.rb
+++ b/spec/ruby/core/fiber/yield_spec.rb
@@ -18,7 +18,7 @@ describe "Fiber.yield" do
it "returns nil to the caller if given no arguments" do
fiber = Fiber.new { true; Fiber.yield; true }
- fiber.resume.should be_nil
+ fiber.resume.should == nil
fiber.resume
end
@@ -44,6 +44,6 @@ describe "Fiber.yield" do
end
it "raises a FiberError if called from the root Fiber" do
- ->{ Fiber.yield }.should raise_error(FiberError)
+ ->{ Fiber.yield }.should.raise(FiberError)
end
end
diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb
index 315eead34f..fc12985a75 100644
--- a/spec/ruby/core/file/absolute_path_spec.rb
+++ b/spec/ruby/core/file/absolute_path_spec.rb
@@ -6,47 +6,47 @@ describe "File.absolute_path?" do
end
it "returns true if it's an absolute pathname" do
- File.absolute_path?(@abs).should be_true
+ File.absolute_path?(@abs).should == true
end
it "returns false if it's a relative path" do
- File.absolute_path?(File.basename(__FILE__)).should be_false
+ File.absolute_path?(File.basename(__FILE__)).should == false
end
it "returns false if it's a tricky relative path" do
- File.absolute_path?("C:foo\\bar").should be_false
+ File.absolute_path?("C:foo\\bar").should == false
end
it "does not expand '~' to a home directory." do
- File.absolute_path?('~').should be_false
+ File.absolute_path?('~').should == false
end
it "does not expand '~user' to a home directory." do
path = File.dirname(@abs)
Dir.chdir(path) do
- File.absolute_path?('~user').should be_false
+ File.absolute_path?('~user').should == false
end
end
it "calls #to_path on its argument" do
mock = mock_to_path(File.expand_path(__FILE__))
- File.absolute_path?(mock).should be_true
+ File.absolute_path?(mock).should == true
end
platform_is_not :windows do
it "takes into consideration the platform's root" do
- File.absolute_path?("C:\\foo\\bar").should be_false
- File.absolute_path?("C:/foo/bar").should be_false
- File.absolute_path?("/foo/bar\\baz").should be_true
+ File.absolute_path?("C:\\foo\\bar").should == false
+ File.absolute_path?("C:/foo/bar").should == false
+ File.absolute_path?("/foo/bar\\baz").should == true
end
end
platform_is :windows do
it "takes into consideration the platform path separator(s)" do
- File.absolute_path?("C:\\foo\\bar").should be_true
- File.absolute_path?("C:/foo/bar").should be_true
- File.absolute_path?("/foo/bar\\baz").should be_false
+ File.absolute_path?("C:\\foo\\bar").should == true
+ File.absolute_path?("C:/foo/bar").should == true
+ File.absolute_path?("/foo/bar\\baz").should == false
end
end
end
diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb
index e47e70e5ac..5c6c110eec 100644
--- a/spec/ruby/core/file/atime_spec.rb
+++ b/spec/ruby/core/file/atime_spec.rb
@@ -12,7 +12,7 @@ describe "File.atime" do
it "returns the last access time for the named file as a Time object" do
File.atime(@file)
- File.atime(@file).should be_kind_of(Time)
+ File.atime(@file).should.is_a?(Time)
end
platform_is :linux, :windows do
@@ -35,7 +35,7 @@ describe "File.atime" do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.atime('a_fake_file') }.should raise_error(Errno::ENOENT)
+ -> { File.atime('a_fake_file') }.should.raise(Errno::ENOENT)
end
it "accepts an object that has a #to_path method" do
@@ -55,6 +55,6 @@ describe "File#atime" do
it "returns the last access time to self" do
@file.atime
- @file.atime.should be_kind_of(Time)
+ @file.atime.should.is_a?(Time)
end
end
diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb
index 989409d76b..77afe5c22f 100644
--- a/spec/ruby/core/file/basename_spec.rb
+++ b/spec/ruby/core/file/basename_spec.rb
@@ -42,7 +42,7 @@ describe "File.basename" do
end
it "returns an string" do
- File.basename("foo").should be_kind_of(String)
+ File.basename("foo").should.is_a?(String)
end
it "returns the basename for unix format" do
@@ -105,10 +105,10 @@ describe "File.basename" do
end
it "raises a TypeError if the arguments are not String types" do
- -> { File.basename(nil) }.should raise_error(TypeError)
- -> { File.basename(1) }.should raise_error(TypeError)
- -> { File.basename("bar.txt", 1) }.should raise_error(TypeError)
- -> { File.basename(true) }.should raise_error(TypeError)
+ -> { File.basename(nil) }.should.raise(TypeError)
+ -> { File.basename(1) }.should.raise(TypeError)
+ -> { File.basename("bar.txt", 1) }.should.raise(TypeError)
+ -> { File.basename(true) }.should.raise(TypeError)
end
it "accepts an object that has a #to_path method" do
@@ -116,7 +116,7 @@ describe "File.basename" do
end
it "raises an ArgumentError if passed more than two arguments" do
- -> { File.basename('bar.txt', '.txt', '.txt') }.should raise_error(ArgumentError)
+ -> { File.basename('bar.txt', '.txt', '.txt') }.should.raise(ArgumentError)
end
# specific to MS Windows
@@ -151,8 +151,30 @@ describe "File.basename" do
File.basename("c:\\bar.txt", ".*").should == "bar"
File.basename("c:\\bar.txt.exe", ".*").should == "bar.txt"
end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do
+ # dir\fileソname.txt
+ path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should == true
+ File.basename(path).should == "file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ end
+ end
+
+ it "rejects strings encoded with non ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
+ path = "/foo/bar".encode(enc)
+
+ -> {
+ File.basename(path)
+ }.should.raise(Encoding::CompatibilityError)
+ end
end
+ it "works with all ASCII-compatible encodings" do
+ Encoding.list.select(&:ascii_compatible?).each do |enc|
+ File.basename("/foo/bar".encode(enc)).should == "bar".encode(enc)
+ end
+ end
it "returns the extension for a multibyte filename" do
File.basename('/path/Офис.m4a').should == "Офис.m4a"
@@ -174,7 +196,7 @@ describe "File.basename" do
else
File.basename(original)
end
- result.should_not equal(original)
+ result.should_not.equal?(original)
result.frozen?.should == false
end
end
diff --git a/spec/ruby/core/file/birthtime_spec.rb b/spec/ruby/core/file/birthtime_spec.rb
index 755601df64..039fd7572c 100644
--- a/spec/ruby/core/file/birthtime_spec.rb
+++ b/spec/ruby/core/file/birthtime_spec.rb
@@ -1,60 +1,56 @@
require_relative '../../spec_helper'
-describe "File.birthtime" do
- before :each do
- @file = __FILE__
- end
+platform_is :windows, :darwin, :freebsd, :netbsd, :linux do
+ not_implemented_messages = [
+ "birthtime() function is unimplemented", # unsupported OS/version
+ "birthtime is unimplemented", # unsupported filesystem
+ ]
+
+ describe "File.birthtime" do
+ before :each do
+ @file = __FILE__
+ end
- after :each do
- @file = nil
- end
+ after :each do
+ @file = nil
+ end
- platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birth time for the named file as a Time object" do
File.birthtime(@file)
- File.birthtime(@file).should be_kind_of(Time)
+ File.birthtime(@file).should.is_a?(Time)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
it "accepts an object that has a #to_path method" do
+ File.birthtime(@file) # Avoid to failure of mock object with old Kernel and glibc
File.birthtime(mock_to_path(@file))
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.birthtime('bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.birthtime('bogus') }.should.raise(Errno::ENOENT)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
end
- platform_is :openbsd do
- it "raises an NotImplementedError" do
- -> { File.birthtime(@file) }.should raise_error(NotImplementedError)
+ describe "File#birthtime" do
+ before :each do
+ @file = File.open(__FILE__)
end
- end
-
- # TODO: depends on Linux kernel version
-end
-describe "File#birthtime" do
- before :each do
- @file = File.open(__FILE__)
- end
-
- after :each do
- @file.close
- @file = nil
- end
+ after :each do
+ @file.close
+ @file = nil
+ end
- platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birth time for self" do
@file.birthtime
- @file.birthtime.should be_kind_of(Time)
+ @file.birthtime.should.is_a?(Time)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
end
-
- platform_is :openbsd do
- it "raises an NotImplementedError" do
- -> { @file.birthtime }.should raise_error(NotImplementedError)
- end
- end
-
- # TODO: depends on Linux kernel version
end
diff --git a/spec/ruby/core/file/chmod_spec.rb b/spec/ruby/core/file/chmod_spec.rb
index 5ca15c9748..e0fd10ceb1 100644
--- a/spec/ruby/core/file/chmod_spec.rb
+++ b/spec/ruby/core/file/chmod_spec.rb
@@ -16,8 +16,8 @@ describe "File#chmod" do
end
it "raises RangeError with too large values" do
- -> { @file.chmod(2**64) }.should raise_error(RangeError)
- -> { @file.chmod(-2**63 - 1) }.should raise_error(RangeError)
+ -> { @file.chmod(2**64) }.should.raise(RangeError)
+ -> { @file.chmod(-2**63 - 1) }.should.raise(RangeError)
end
it "invokes to_int on non-integer argument" do
@@ -97,8 +97,8 @@ describe "File.chmod" do
end
it "raises RangeError with too large values" do
- -> { File.chmod(2**64, @file) }.should raise_error(RangeError)
- -> { File.chmod(-2**63 - 1, @file) }.should raise_error(RangeError)
+ -> { File.chmod(2**64, @file) }.should.raise(RangeError)
+ -> { File.chmod(-2**63 - 1, @file) }.should.raise(RangeError)
end
it "accepts an object that has a #to_path method" do
@@ -106,13 +106,13 @@ describe "File.chmod" do
end
it "throws a TypeError if the given path is not coercible into a string" do
- -> { File.chmod(0, []) }.should raise_error(TypeError)
+ -> { File.chmod(0, []) }.should.raise(TypeError)
end
it "raises an error for a non existent path" do
-> {
File.chmod(0644, "#{@file}.not.existing")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
it "invokes to_int on non-integer argument" do
diff --git a/spec/ruby/core/file/chown_spec.rb b/spec/ruby/core/file/chown_spec.rb
index 4db0e3712c..3353aafc70 100644
--- a/spec/ruby/core/file/chown_spec.rb
+++ b/spec/ruby/core/file/chown_spec.rb
@@ -68,7 +68,7 @@ describe "File.chown" do
it "raises an error for a non existent path" do
-> {
File.chown(nil, nil, "#{@fname}_not_existing")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/file/constants/constants_spec.rb b/spec/ruby/core/file/constants/constants_spec.rb
index bba248c21e..9d9c1c3b25 100644
--- a/spec/ruby/core/file/constants/constants_spec.rb
+++ b/spec/ruby/core/file/constants/constants_spec.rb
@@ -7,7 +7,7 @@ require_relative '../../../spec_helper'
"RDWR", "TRUNC", "WRONLY", "SHARE_DELETE"].each do |const|
describe "File::Constants::#{const}" do
it "is defined" do
- File::Constants.const_defined?(const).should be_true
+ File::Constants.const_defined?(const).should == true
end
end
end
@@ -15,7 +15,7 @@ end
platform_is :windows do
describe "File::Constants::BINARY" do
it "is defined" do
- File::Constants.const_defined?(:BINARY).should be_true
+ File::Constants.const_defined?(:BINARY).should == true
end
end
end
@@ -24,7 +24,7 @@ platform_is_not :windows do
["NOCTTY", "SYNC"].each do |const|
describe "File::Constants::#{const}" do
it "is defined" do
- File::Constants.const_defined?(const).should be_true
+ File::Constants.const_defined?(const).should == true
end
end
end
diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb
index 718f26d5cc..cf37d1f4ee 100644
--- a/spec/ruby/core/file/ctime_spec.rb
+++ b/spec/ruby/core/file/ctime_spec.rb
@@ -11,7 +11,7 @@ describe "File.ctime" do
it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself)." do
File.ctime(@file)
- File.ctime(@file).should be_kind_of(Time)
+ File.ctime(@file).should.is_a?(Time)
end
platform_is :linux, :windows do
@@ -33,7 +33,7 @@ describe "File.ctime" do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.ctime('bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.ctime('bogus') }.should.raise(Errno::ENOENT)
end
end
@@ -49,6 +49,6 @@ describe "File#ctime" do
it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself)." do
@file.ctime
- @file.ctime.should be_kind_of(Time)
+ @file.ctime.should.is_a?(Time)
end
end
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index 8e6016ce6f..855148a684 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -25,7 +25,7 @@ describe "File.dirname" do
it "raises ArgumentError if the level is negative" do
-> {
File.dirname('/home/jason', -1)
- }.should raise_error(ArgumentError, "negative level: -1")
+ }.should.raise(ArgumentError, "negative level: -1")
end
it "returns '/' when level exceeds the number of segments in the path" do
@@ -41,7 +41,7 @@ describe "File.dirname" do
end
it "returns a String" do
- File.dirname("foo").should be_kind_of(String)
+ File.dirname("foo").should.is_a?(String)
end
it "does not modify its argument" do
@@ -78,7 +78,33 @@ describe "File.dirname" do
File.dirname("foo/../").should == "foo"
end
+ it "rejects strings encoded with non ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
+ path = "/foo/bar".encode(enc)
+ -> {
+ File.dirname(path)
+ }.should.raise(Encoding::CompatibilityError)
+ end
+ end
+
+ it "works with all ASCII-compatible encodings" do
+ Encoding.list.select(&:ascii_compatible?).each do |enc|
+ File.dirname("/foo/bar".encode(enc)).should == "/foo".encode(enc)
+ end
+ end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do
+ # dir/fileソname.txt
+ path = "dir/file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should == true
+ File.dirname(path).should == "dir"
+ end
+
platform_is_not :windows do
+ it "ignores repeated leading / (edge cases on non-windows)" do
+ File.dirname("/////foo/bar/").should == "/foo"
+ end
+
it "returns all the components of filename except the last one (edge cases on non-windows)" do
File.dirname('/////').should == '/'
File.dirname("//foo//").should == "/"
@@ -94,6 +120,13 @@ describe "File.dirname" do
File.dirname("//foo//").should == "//foo"
File.dirname('/////').should == '//'
end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence (windows)" do
+ # dir\fileソname.txt
+ path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should == true
+ File.dirname(path).should == "dir"
+ end
end
it "accepts an object that has a #to_path method" do
@@ -101,10 +134,10 @@ describe "File.dirname" do
end
it "raises a TypeError if not passed a String type" do
- -> { File.dirname(nil) }.should raise_error(TypeError)
- -> { File.dirname(0) }.should raise_error(TypeError)
- -> { File.dirname(true) }.should raise_error(TypeError)
- -> { File.dirname(false) }.should raise_error(TypeError)
+ -> { File.dirname(nil) }.should.raise(TypeError)
+ -> { File.dirname(0) }.should.raise(TypeError)
+ -> { File.dirname(true) }.should.raise(TypeError)
+ -> { File.dirname(false) }.should.raise(TypeError)
end
# Windows specific tests
diff --git a/spec/ruby/core/file/empty_spec.rb b/spec/ruby/core/file/empty_spec.rb
index 77f132303e..e8c9941676 100644
--- a/spec/ruby/core/file/empty_spec.rb
+++ b/spec/ruby/core/file/empty_spec.rb
@@ -4,10 +4,4 @@ require_relative '../../shared/file/zero'
describe "File.empty?" do
it_behaves_like :file_zero, :empty?, File
it_behaves_like :file_zero_missing, :empty?, File
-
- platform_is :solaris do
- it "returns false for /dev/null" do
- File.empty?('/dev/null').should == true
- end
- end
end
diff --git a/spec/ruby/core/file/exist_spec.rb b/spec/ruby/core/file/exist_spec.rb
index 2633376880..b5600e5b07 100644
--- a/spec/ruby/core/file/exist_spec.rb
+++ b/spec/ruby/core/file/exist_spec.rb
@@ -5,10 +5,8 @@ describe "File.exist?" do
it_behaves_like :file_exist, :exist?, File
end
-ruby_version_is "3.2" do
- describe "File.exists?" do
- it "has been removed" do
- File.should_not.respond_to?(:exists?)
- end
+describe "File.exists?" do
+ it "has been removed" do
+ File.should_not.respond_to?(:exists?)
end
end
diff --git a/spec/ruby/core/file/expand_path_spec.rb b/spec/ruby/core/file/expand_path_spec.rb
index 1abcf93900..160494f145 100644
--- a/spec/ruby/core/file/expand_path_spec.rb
+++ b/spec/ruby/core/file/expand_path_spec.rb
@@ -92,7 +92,7 @@ describe "File.expand_path" do
end
it "raises an ArgumentError if the path is not valid" do
- -> { File.expand_path("~a_not_existing_user") }.should raise_error(ArgumentError)
+ -> { File.expand_path("~a_not_existing_user") }.should.raise(ArgumentError)
end
it "expands ~ENV['USER'] to the user's home directory" do
@@ -117,9 +117,9 @@ describe "File.expand_path" do
end
it "raises a TypeError if not passed a String type" do
- -> { File.expand_path(1) }.should raise_error(TypeError)
- -> { File.expand_path(nil) }.should raise_error(TypeError)
- -> { File.expand_path(true) }.should raise_error(TypeError)
+ -> { File.expand_path(1) }.should.raise(TypeError)
+ -> { File.expand_path(nil) }.should.raise(TypeError)
+ -> { File.expand_path(true) }.should.raise(TypeError)
end
platform_is_not :windows do
@@ -138,10 +138,10 @@ describe "File.expand_path" do
Encoding.default_external = Encoding::SHIFT_JIS
path = "./a".dup.force_encoding Encoding::CP1251
- File.expand_path(path).encoding.should equal(Encoding::CP1251)
+ File.expand_path(path).encoding.should.equal?(Encoding::CP1251)
weird_path = [222, 173, 190, 175].pack('C*')
- File.expand_path(weird_path).encoding.should equal(Encoding::BINARY)
+ File.expand_path(weird_path).encoding.should.equal?(Encoding::BINARY)
end
platform_is_not :windows do
@@ -159,7 +159,7 @@ describe "File.expand_path" do
platform_is_not :windows do
it "raises an Encoding::CompatibilityError if the external encoding is not compatible" do
Encoding.default_external = Encoding::UTF_16BE
- -> { File.expand_path("./a") }.should raise_error(Encoding::CompatibilityError)
+ -> { File.expand_path("./a") }.should.raise(Encoding::CompatibilityError)
end
end
@@ -179,7 +179,7 @@ describe "File.expand_path" do
str = FileSpecs::SubString.new "./a/b/../c"
path = File.expand_path(str, @base)
path.should == "#{@base}/a/c"
- path.should be_an_instance_of(String)
+ path.should.instance_of?(String)
end
end
@@ -244,7 +244,7 @@ platform_is_not :windows do
it "raises an ArgumentError when passed '~' if HOME == ''" do
ENV["HOME"] = ""
- -> { File.expand_path("~") }.should raise_error(ArgumentError)
+ -> { File.expand_path("~") }.should.raise(ArgumentError)
end
end
@@ -259,7 +259,7 @@ platform_is_not :windows do
it "raises an ArgumentError" do
ENV["HOME"] = "non-absolute"
- -> { File.expand_path("~") }.should raise_error(ArgumentError, 'non-absolute home')
+ -> { File.expand_path("~") }.should.raise(ArgumentError, 'non-absolute home')
end
end
end
diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb
index d20cf813d9..995d0ea31a 100644
--- a/spec/ruby/core/file/extname_spec.rb
+++ b/spec/ruby/core/file/extname_spec.rb
@@ -57,15 +57,15 @@ describe "File.extname" do
end
it "raises a TypeError if not passed a String type" do
- -> { File.extname(nil) }.should raise_error(TypeError)
- -> { File.extname(0) }.should raise_error(TypeError)
- -> { File.extname(true) }.should raise_error(TypeError)
- -> { File.extname(false) }.should raise_error(TypeError)
+ -> { File.extname(nil) }.should.raise(TypeError)
+ -> { File.extname(0) }.should.raise(TypeError)
+ -> { File.extname(true) }.should.raise(TypeError)
+ -> { File.extname(false) }.should.raise(TypeError)
end
it "raises an ArgumentError if not passed one argument" do
- -> { File.extname }.should raise_error(ArgumentError)
- -> { File.extname("foo.bar", "foo.baz") }.should raise_error(ArgumentError)
+ -> { File.extname }.should.raise(ArgumentError)
+ -> { File.extname("foo.bar", "foo.baz") }.should.raise(ArgumentError)
end
diff --git a/spec/ruby/core/file/flock_spec.rb b/spec/ruby/core/file/flock_spec.rb
index 070d830bc4..23ddf89ed8 100644
--- a/spec/ruby/core/file/flock_spec.rb
+++ b/spec/ruby/core/file/flock_spec.rb
@@ -72,35 +72,3 @@ describe "File#flock" do
end
end
end
-
-platform_is :solaris do
- describe "File#flock on Solaris" do
- before :each do
- @name = tmp("flock_test")
- touch(@name)
-
- @read_file = File.open @name, "r"
- @write_file = File.open @name, "w"
- end
-
- after :each do
- @read_file.flock File::LOCK_UN
- @read_file.close
- @write_file.flock File::LOCK_UN
- @write_file.close
- rm_r @name
- end
-
- it "fails with EBADF acquiring exclusive lock on read-only File" do
- -> do
- @read_file.flock File::LOCK_EX
- end.should raise_error(Errno::EBADF)
- end
-
- it "fails with EBADF acquiring shared lock on read-only File" do
- -> do
- @write_file.flock File::LOCK_SH
- end.should raise_error(Errno::EBADF)
- end
- end
-end
diff --git a/spec/ruby/core/file/ftype_spec.rb b/spec/ruby/core/file/ftype_spec.rb
index cdddc404dc..ab9f76b79b 100644
--- a/spec/ruby/core/file/ftype_spec.rb
+++ b/spec/ruby/core/file/ftype_spec.rb
@@ -7,19 +7,19 @@ describe "File.ftype" do
end
it "raises ArgumentError if not given exactly one filename" do
- -> { File.ftype }.should raise_error(ArgumentError)
- -> { File.ftype('blah', 'bleh') }.should raise_error(ArgumentError)
+ -> { File.ftype }.should.raise(ArgumentError)
+ -> { File.ftype('blah', 'bleh') }.should.raise(ArgumentError)
end
it "raises Errno::ENOENT if the file is not valid" do
-> {
File.ftype("/#{$$}#{Time.now.to_f}")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
it "returns a String" do
FileSpecs.normal_file do |file|
- File.ftype(file).should be_kind_of(String)
+ File.ftype(file).should.is_a?(String)
end
end
diff --git a/spec/ruby/core/file/inspect_spec.rb b/spec/ruby/core/file/inspect_spec.rb
index 148e789c62..fe87429e8d 100644
--- a/spec/ruby/core/file/inspect_spec.rb
+++ b/spec/ruby/core/file/inspect_spec.rb
@@ -12,6 +12,6 @@ describe "File#inspect" do
end
it "returns a String" do
- @file.inspect.should be_an_instance_of(String)
+ @file.inspect.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/file/join_spec.rb b/spec/ruby/core/file/join_spec.rb
index 0feedbae93..0f0911ea31 100644
--- a/spec/ruby/core/file/join_spec.rb
+++ b/spec/ruby/core/file/join_spec.rb
@@ -52,7 +52,7 @@ describe "File.join" do
it "returns a duplicate string when given a single argument" do
str = "usr"
File.join(str).should == str
- File.join(str).should_not equal(str)
+ File.join(str).should_not.equal?(str)
end
it "supports any number of arguments" do
@@ -104,15 +104,15 @@ describe "File.join" do
it "raises an ArgumentError if passed a recursive array" do
a = ["a"]
a << a
- -> { File.join a }.should raise_error(ArgumentError)
+ -> { File.join a }.should.raise(ArgumentError)
end
it "raises a TypeError exception when args are nil" do
- -> { File.join nil }.should raise_error(TypeError)
+ -> { File.join nil }.should.raise(TypeError)
end
it "calls #to_str" do
- -> { File.join(mock('x')) }.should raise_error(TypeError)
+ -> { File.join(mock('x')) }.should.raise(TypeError)
bin = mock("bin")
bin.should_receive(:to_str).exactly(:twice).and_return("bin")
@@ -129,7 +129,7 @@ describe "File.join" do
end
it "calls #to_path" do
- -> { File.join(mock('x')) }.should raise_error(TypeError)
+ -> { File.join(mock('x')) }.should.raise(TypeError)
bin = mock("bin")
bin.should_receive(:to_path).exactly(:twice).and_return("bin")
@@ -138,10 +138,10 @@ describe "File.join" do
end
it "raises errors for null bytes" do
- -> { File.join("\x00x", "metadata.gz") }.should raise_error(ArgumentError) { |e|
+ -> { File.join("\x00x", "metadata.gz") }.should.raise(ArgumentError) { |e|
e.message.should == 'string contains null byte'
}
- -> { File.join("metadata.gz", "\x00x") }.should raise_error(ArgumentError) { |e|
+ -> { File.join("metadata.gz", "\x00x") }.should.raise(ArgumentError) { |e|
e.message.should == 'string contains null byte'
}
end
diff --git a/spec/ruby/core/file/lchmod_spec.rb b/spec/ruby/core/file/lchmod_spec.rb
index 7420b95e4a..3c44374983 100644
--- a/spec/ruby/core/file/lchmod_spec.rb
+++ b/spec/ruby/core/file/lchmod_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "File.lchmod" do
- platform_is_not :linux, :windows, :openbsd, :solaris, :aix do
+ platform_is_not :linux, :windows, :openbsd, :aix do
before :each do
@fname = tmp('file_chmod_test')
@lname = @fname + '.lnk'
diff --git a/spec/ruby/core/file/link_spec.rb b/spec/ruby/core/file/link_spec.rb
index a5d5b4815f..768ee4b0fa 100644
--- a/spec/ruby/core/file/link_spec.rb
+++ b/spec/ruby/core/file/link_spec.rb
@@ -22,18 +22,18 @@ describe "File.link" do
it "raises an Errno::EEXIST if the target already exists" do
File.link(@file, @link)
- -> { File.link(@file, @link) }.should raise_error(Errno::EEXIST)
+ -> { File.link(@file, @link) }.should.raise(Errno::EEXIST)
end
it "raises an ArgumentError if not passed two arguments" do
- -> { File.link }.should raise_error(ArgumentError)
- -> { File.link(@file) }.should raise_error(ArgumentError)
- -> { File.link(@file, @link, @file) }.should raise_error(ArgumentError)
+ -> { File.link }.should.raise(ArgumentError)
+ -> { File.link(@file) }.should.raise(ArgumentError)
+ -> { File.link(@file, @link, @file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed String types" do
- -> { File.link(@file, nil) }.should raise_error(TypeError)
- -> { File.link(@file, 1) }.should raise_error(TypeError)
+ -> { File.link(@file, nil) }.should.raise(TypeError)
+ -> { File.link(@file, 1) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/file/mkfifo_spec.rb b/spec/ruby/core/file/mkfifo_spec.rb
index 19298c967c..ce4a67fe31 100644
--- a/spec/ruby/core/file/mkfifo_spec.rb
+++ b/spec/ruby/core/file/mkfifo_spec.rb
@@ -19,13 +19,13 @@ describe "File.mkfifo" do
context "when path passed is not a String value" do
it "raises a TypeError" do
- -> { File.mkfifo(:"/tmp/fifo") }.should raise_error(TypeError)
+ -> { File.mkfifo(:"/tmp/fifo") }.should.raise(TypeError)
end
end
context "when path does not exist" do
it "raises an Errno::ENOENT exception" do
- -> { File.mkfifo("/bogus/path") }.should raise_error(Errno::ENOENT)
+ -> { File.mkfifo("/bogus/path") }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb
index 0e9c95caee..d83725e25d 100644
--- a/spec/ruby/core/file/mtime_spec.rb
+++ b/spec/ruby/core/file/mtime_spec.rb
@@ -11,7 +11,7 @@ describe "File.mtime" do
end
it "returns the modification Time of the file" do
- File.mtime(@filename).should be_kind_of(Time)
+ File.mtime(@filename).should.is_a?(Time)
File.mtime(@filename).should be_close(@mtime, TIME_TOLERANCE)
end
@@ -34,7 +34,7 @@ describe "File.mtime" do
end
it "raises an Errno::ENOENT exception if the file is not found" do
- -> { File.mtime('bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.mtime('bogus') }.should.raise(Errno::ENOENT)
end
end
@@ -50,7 +50,7 @@ describe "File#mtime" do
end
it "returns the modification Time of the file" do
- @f.mtime.should be_kind_of(Time)
+ @f.mtime.should.is_a?(Time)
end
end
diff --git a/spec/ruby/core/file/new_spec.rb b/spec/ruby/core/file/new_spec.rb
index 1e82a070b1..4cd2cb5dcb 100644
--- a/spec/ruby/core/file/new_spec.rb
+++ b/spec/ruby/core/file/new_spec.rb
@@ -16,13 +16,13 @@ describe "File.new" do
it "returns a new File with mode string" do
@fh = File.new(@file, 'w')
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File with mode num" do
@fh = File.new(@file, @flags)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -30,7 +30,7 @@ describe "File.new" do
rm_r @file
File.umask(0011)
@fh = File.new(@file, @flags, 0755)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
platform_is_not :windows do
File.stat(@file).mode.to_s(8).should == "100744"
end
@@ -44,7 +44,7 @@ describe "File.new" do
rm_r @file
begin
f = File.new(@file, "w", 0444)
- -> { f.puts("test") }.should_not raise_error(IOError)
+ -> { f.puts("test") }.should_not.raise(IOError)
ensure
f.close
end
@@ -74,14 +74,14 @@ describe "File.new" do
@fh = File.new(@file)
fh_copy = File.new(@fh.fileno)
fh_copy.autoclose = false
- fh_copy.should be_kind_of(File)
+ fh_copy.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new read-only File when mode is not specified" do
@fh = File.new(@file)
- -> { @fh.puts("test") }.should raise_error(IOError)
+ -> { @fh.puts("test") }.should.raise(IOError)
@fh.read.should == ""
File.should.exist?(@file)
end
@@ -89,68 +89,68 @@ describe "File.new" do
it "returns a new read-only File when mode is not specified but flags option is present" do
@fh = File.new(@file, flags: File::CREAT)
- -> { @fh.puts("test") }.should raise_error(IOError)
+ -> { @fh.puts("test") }.should.raise(IOError)
@fh.read.should == ""
File.should.exist?(@file)
end
it "creates a new file when use File::EXCL mode" do
@fh = File.new(@file, File::EXCL)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "raises an Errno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do
- -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST)
+ -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should.raise(Errno::EEXIST)
end
it "creates a new file when use File::WRONLY|File::APPEND mode" do
@fh = File.new(@file, File::WRONLY|File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File when use File::APPEND mode" do
@fh = File.new(@file, File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File when use File::RDONLY|File::APPEND mode" do
@fh = File.new(@file, File::RDONLY|File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new File when use File::RDONLY|File::WRONLY mode" do
@fh = File.new(@file, File::RDONLY|File::WRONLY)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "creates a new file when use File::WRONLY|File::TRUNC mode" do
@fh = File.new(@file, File::WRONLY|File::TRUNC)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "returns a new read-only File when use File::RDONLY|File::CREAT mode" do
@fh = File.new(@file, File::RDONLY|File::CREAT)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
# it's read-only
- -> { @fh.puts("test") }.should raise_error(IOError)
+ -> { @fh.puts("test") }.should.raise(IOError)
@fh.read.should == ""
end
it "returns a new read-only File when use File::CREAT mode" do
@fh = File.new(@file, File::CREAT)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
# it's read-only
- -> { @fh.puts("test") }.should raise_error(IOError)
+ -> { @fh.puts("test") }.should.raise(IOError)
@fh.read.should == ""
end
@@ -170,22 +170,22 @@ describe "File.new" do
it "accepts options as a keyword argument" do
@fh = File.new(@file, 'w', 0755, flags: @flags)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
@fh.close
-> {
@fh = File.new(@file, 'w', 0755, {flags: @flags})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "bitwise-ORs mode and flags option" do
-> {
@fh = File.new(@file, 'w', flags: File::EXCL)
- }.should raise_error(Errno::EEXIST, /File exists/)
+ }.should.raise(Errno::EEXIST, /File exists/)
-> {
@fh = File.new(@file, mode: 'w', flags: File::EXCL)
- }.should raise_error(Errno::EEXIST, /File exists/)
+ }.should.raise(Errno::EEXIST, /File exists/)
end
it "does not use the given block and warns to use File::open" do
@@ -195,16 +195,16 @@ describe "File.new" do
end
it "raises a TypeError if the first parameter can't be coerced to a string" do
- -> { File.new(true) }.should raise_error(TypeError)
- -> { File.new(false) }.should raise_error(TypeError)
+ -> { File.new(true) }.should.raise(TypeError)
+ -> { File.new(false) }.should.raise(TypeError)
end
it "raises a TypeError if the first parameter is nil" do
- -> { File.new(nil) }.should raise_error(TypeError)
+ -> { File.new(nil) }.should.raise(TypeError)
end
it "raises an Errno::EBADF if the first parameter is an invalid file descriptor" do
- -> { File.new(-1) }.should raise_error(Errno::EBADF)
+ -> { File.new(-1) }.should.raise(Errno::EBADF)
end
platform_is_not :windows do
@@ -213,7 +213,7 @@ describe "File.new" do
-> {
f = File.new(@fh.fileno, @flags)
f.autoclose = false
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
end
diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb
index 6bfc16bbf9..7318c31636 100644
--- a/spec/ruby/core/file/open_spec.rb
+++ b/spec/ruby/core/file/open_spec.rb
@@ -40,7 +40,7 @@ describe "File.open" do
it "propagates non-StandardErrors produced by close" do
-> {
File.open(@file, 'r') { |f| FileSpecs.make_closer f, Exception }
- }.should raise_error(Exception)
+ }.should.raise(Exception)
ScratchPad.recorded.should == [:file_opened, :file_closed]
end
@@ -48,7 +48,7 @@ describe "File.open" do
it "propagates StandardErrors produced by close" do
-> {
File.open(@file, 'r') { |f| FileSpecs.make_closer f, StandardError }
- }.should raise_error(StandardError)
+ }.should.raise(StandardError)
ScratchPad.recorded.should == [:file_opened, :file_closed]
end
@@ -62,13 +62,13 @@ describe "File.open" do
it "opens the file (basic case)" do
@fh = File.open(@file)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens the file with unicode characters" do
@fh = File.open(@unicode_path, "w")
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@unicode_path)
end
@@ -79,7 +79,7 @@ describe "File.open" do
it "opens with mode string" do
@fh = File.open(@file, 'w')
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -90,7 +90,7 @@ describe "File.open" do
it "opens a file with mode num" do
@fh = File.open(@file, @flags)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -101,7 +101,7 @@ describe "File.open" do
it "opens a file with mode and permission as nil" do
@fh = File.open(@file, nil, nil)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
end
# For this test we delete the file first to reset the perms
@@ -109,7 +109,7 @@ describe "File.open" do
rm_r @file
File.umask(0011)
@fh = File.open(@file, @flags, 0755)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
platform_is_not :windows do
@fh.lstat.mode.to_s(8).should == "100744"
end
@@ -161,69 +161,69 @@ describe "File.open" do
@fh = File.open(@file)
fh_copy = File.open(@fh.fileno)
fh_copy.autoclose = false
- fh_copy.should be_kind_of(File)
+ fh_copy.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file that no exists when use File::WRONLY mode" do
- -> { File.open(@nonexistent, File::WRONLY) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::WRONLY) }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use File::RDONLY mode" do
- -> { File.open(@nonexistent, File::RDONLY) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::RDONLY) }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use 'r' mode" do
- -> { File.open(@nonexistent, 'r') }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, 'r') }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use File::EXCL mode" do
- -> { File.open(@nonexistent, File::EXCL) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::EXCL) }.should.raise(Errno::ENOENT)
end
it "opens a file that no exists when use File::NONBLOCK mode" do
- -> { File.open(@nonexistent, File::NONBLOCK) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::NONBLOCK) }.should.raise(Errno::ENOENT)
end
platform_is_not :openbsd, :windows do
it "opens a file that no exists when use File::TRUNC mode" do
- -> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::TRUNC) }.should.raise(Errno::ENOENT)
end
end
platform_is :openbsd, :windows do
it "does not open a file that does no exists when using File::TRUNC mode" do
- -> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::EINVAL)
+ -> { File.open(@nonexistent, File::TRUNC) }.should.raise(Errno::EINVAL)
end
end
platform_is_not :windows do
it "opens a file that no exists when use File::NOCTTY mode" do
- -> { File.open(@nonexistent, File::NOCTTY) }.should raise_error(Errno::ENOENT)
+ -> { File.open(@nonexistent, File::NOCTTY) }.should.raise(Errno::ENOENT)
end
end
it "opens a file that no exists when use File::CREAT mode" do
@fh = File.open(@nonexistent, File::CREAT) { |f| f }
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file that no exists when use 'a' mode" do
@fh = File.open(@nonexistent, 'a') { |f| f }
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file that no exists when use 'w' mode" do
@fh = File.open(@nonexistent, 'w') { |f| f }
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
# Check the grants associated to the different open modes combinations.
it "raises an ArgumentError exception when call with an unknown mode" do
- -> { File.open(@file, "q") }.should raise_error(ArgumentError)
+ -> { File.open(@file, "q") }.should.raise(ArgumentError)
end
it "can read in a block when call open with RDONLY mode" do
@@ -240,13 +240,13 @@ describe "File.open" do
it "raises an IO exception when write in a block opened with RDONLY mode" do
File.open(@file, File::RDONLY) do |f|
- -> { f.puts "writing ..." }.should raise_error(IOError)
+ -> { f.puts "writing ..." }.should.raise(IOError)
end
end
it "raises an IO exception when write in a block opened with 'r' mode" do
File.open(@file, "r") do |f|
- -> { f.puts "writing ..." }.should raise_error(IOError)
+ -> { f.puts "writing ..." }.should.raise(IOError)
end
end
@@ -261,7 +261,7 @@ describe "File.open" do
File.open(@file, File::WRONLY|File::RDONLY ) do |f|
f.gets.should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "can write in a block when call open with WRONLY mode" do
@@ -278,39 +278,39 @@ describe "File.open" do
it "raises an IOError when read in a block opened with WRONLY mode" do
File.open(@file, File::WRONLY) do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'w' mode" do
File.open(@file, "w") do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'a' mode" do
File.open(@file, "a") do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'a' mode" do
File.open(@file, "a") do |f|
f.puts("writing").should == nil
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with 'a' mode" do
File.open(@file, File::WRONLY|File::APPEND ) do |f|
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
it "raises an IOError when read in a block opened with File::WRONLY|File::APPEND mode" do
File.open(@file, File::WRONLY|File::APPEND ) do |f|
f.puts("writing").should == nil
- -> { f.gets }.should raise_error(IOError)
+ -> { f.gets }.should.raise(IOError)
end
end
@@ -319,7 +319,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::APPEND ) do |f|
f.puts("writing")
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "can read and write in a block when call open with RDWR mode" do
@@ -336,7 +336,7 @@ describe "File.open" do
File.open(@file, File::EXCL) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "can read in a block when call open with File::EXCL mode" do
@@ -359,12 +359,12 @@ describe "File.open" do
File.open(@file, File::CREAT|File::EXCL) do |f|
f.puts("writing")
end
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
end
it "creates a new file when use File::WRONLY|File::APPEND mode" do
@fh = File.open(@file, File::WRONLY|File::APPEND)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -386,7 +386,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::APPEND) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
platform_is_not :openbsd, :windows do
@@ -407,7 +407,7 @@ describe "File.open" do
fh1 = File.open(@file, "w")
begin
@fh = File.open(@file, File::WRONLY|File::TRUNC)
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
ensure
fh1.close
@@ -420,7 +420,7 @@ describe "File.open" do
File.open(@file, File::TRUNC) do |f|
f.puts("writing")
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
@@ -428,7 +428,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
@@ -438,7 +438,7 @@ describe "File.open" do
File.open(@file, File::TRUNC) do |f|
f.puts("writing")
end
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
@@ -446,7 +446,7 @@ describe "File.open" do
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
end
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
end
@@ -455,7 +455,7 @@ describe "File.open" do
it "raises an Errno::EACCES when opening non-permitted file" do
@fh = File.open(@file, "w")
@fh.chmod(000)
- -> { fh1 = File.open(@file); fh1.close }.should raise_error(Errno::EACCES)
+ -> { fh1 = File.open(@file); fh1.close }.should.raise(Errno::EACCES)
end
end
end
@@ -464,19 +464,19 @@ describe "File.open" do
it "raises an Errno::EACCES when opening read-only file" do
@fh = File.open(@file, "w")
@fh.chmod(0444)
- -> { File.open(@file, "w") }.should raise_error(Errno::EACCES)
+ -> { File.open(@file, "w") }.should.raise(Errno::EACCES)
end
end
it "opens a file for binary read" do
@fh = File.open(@file, "rb")
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
it "opens a file for binary write" do
@fh = File.open(@file, "wb")
- @fh.should be_kind_of(File)
+ @fh.should.is_a?(File)
File.should.exist?(@file)
end
@@ -543,21 +543,21 @@ describe "File.open" do
end
it "raises a TypeError if passed a filename that is not a String or Integer type" do
- -> { File.open(true) }.should raise_error(TypeError)
- -> { File.open(false) }.should raise_error(TypeError)
- -> { File.open(nil) }.should raise_error(TypeError)
+ -> { File.open(true) }.should.raise(TypeError)
+ -> { File.open(false) }.should.raise(TypeError)
+ -> { File.open(nil) }.should.raise(TypeError)
end
it "raises a SystemCallError if passed an invalid Integer type" do
- -> { File.open(-1) }.should raise_error(SystemCallError)
+ -> { File.open(-1) }.should.raise(SystemCallError)
end
it "raises an ArgumentError if passed the wrong number of arguments" do
- -> { File.open(@file, File::CREAT, 0755, 'test') }.should raise_error(ArgumentError)
+ -> { File.open(@file, File::CREAT, 0755, 'test') }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed an invalid string for mode" do
- -> { File.open(@file, 'fake') }.should raise_error(ArgumentError)
+ -> { File.open(@file, 'fake') }.should.raise(ArgumentError)
end
it "defaults external_encoding to BINARY for binary modes" do
@@ -567,16 +567,16 @@ describe "File.open" do
it "accepts options as a keyword argument" do
@fh = File.open(@file, 'w', 0755, flags: File::CREAT)
- @fh.should be_an_instance_of(File)
+ @fh.should.instance_of?(File)
-> {
File.open(@file, 'w', 0755, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "uses the second argument as an options Hash" do
@fh = File.open(@file, mode: "r")
- @fh.should be_an_instance_of(File)
+ @fh.should.instance_of?(File)
end
it "calls #to_hash to convert the second argument to a Hash" do
@@ -589,17 +589,17 @@ describe "File.open" do
it "accepts extra flags as a keyword argument and combine with a string mode" do
-> {
File.open(@file, "w", flags: File::EXCL) { }
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
-> {
File.open(@file, mode: "w", flags: File::EXCL) { }
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
end
it "accepts extra flags as a keyword argument and combine with an integer mode" do
-> {
File.open(@file, File::WRONLY | File::CREAT, flags: File::EXCL) { }
- }.should raise_error(Errno::EEXIST)
+ }.should.raise(Errno::EEXIST)
end
platform_is_not :windows do
@@ -643,7 +643,7 @@ describe "File.open" do
it "raises ArgumentError if mixing :newline and binary mode" do
-> {
File.open(@file, "rb", newline: :universal) {}
- }.should raise_error(ArgumentError, "newline decorator with binary mode")
+ }.should.raise(ArgumentError, "newline decorator with binary mode")
end
context "'x' flag" do
@@ -663,12 +663,12 @@ describe "File.open" do
it "throws a Errno::EEXIST error if the file exists" do
touch @xfile
- -> { File.open(@xfile, "wx") }.should raise_error(Errno::EEXIST)
+ -> { File.open(@xfile, "wx") }.should.raise(Errno::EEXIST)
end
it "can't be used with 'r' and 'a' flags" do
- -> { File.open(@xfile, "rx") }.should raise_error(ArgumentError, 'invalid access mode rx')
- -> { File.open(@xfile, "ax") }.should raise_error(ArgumentError, 'invalid access mode ax')
+ -> { File.open(@xfile, "rx") }.should.raise(ArgumentError, 'invalid access mode rx')
+ -> { File.open(@xfile, "ax") }.should.raise(ArgumentError, 'invalid access mode ax')
end
end
end
@@ -688,8 +688,8 @@ describe "File.open when passed a file descriptor" do
it "opens a file" do
@file = File.open(@fd, "w")
- @file.should be_an_instance_of(File)
- @file.fileno.should equal(@fd)
+ @file.should.instance_of?(File)
+ @file.fileno.should.equal?(@fd)
@file.write @content
@file.flush
File.read(@name).should == @content
@@ -697,8 +697,8 @@ describe "File.open when passed a file descriptor" do
it "opens a file when passed a block" do
@file = File.open(@fd, "w") do |f|
- f.should be_an_instance_of(File)
- f.fileno.should equal(@fd)
+ f.should.instance_of?(File)
+ f.fileno.should.equal?(@fd)
f.write @content
f
end
diff --git a/spec/ruby/core/file/path_spec.rb b/spec/ruby/core/file/path_spec.rb
index dfa0c4ec02..ce78dbeede 100644
--- a/spec/ruby/core/file/path_spec.rb
+++ b/spec/ruby/core/file/path_spec.rb
@@ -37,4 +37,45 @@ describe "File.path" do
path.should_receive(:to_path).and_return("abc")
File.path(path).should == "abc"
end
+
+ it "raises TypeError when #to_path result is not a string" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return(nil)
+ -> { File.path(path) }.should.raise TypeError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return(42)
+ -> { File.path(path) }.should.raise TypeError
+ end
+
+ it "raises ArgumentError for string argument contains NUL character" do
+ -> { File.path("\0") }.should.raise ArgumentError
+ -> { File.path("a\0") }.should.raise ArgumentError
+ -> { File.path("a\0c") }.should.raise ArgumentError
+ end
+
+ it "raises ArgumentError when #to_path result contains NUL character" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return("\0")
+ -> { File.path(path) }.should.raise ArgumentError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return("a\0")
+ -> { File.path(path) }.should.raise ArgumentError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return("a\0c")
+ -> { File.path(path) }.should.raise ArgumentError
+ end
+
+ it "raises Encoding::CompatibilityError for ASCII-incompatible string argument" do
+ path = "abc".encode(Encoding::UTF_32BE)
+ -> { File.path(path) }.should.raise Encoding::CompatibilityError
+ end
+
+ it "raises Encoding::CompatibilityError when #to_path result is ASCII-incompatible" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return("abc".encode(Encoding::UTF_32BE))
+ -> { File.path(path) }.should.raise Encoding::CompatibilityError
+ end
end
diff --git a/spec/ruby/core/file/readlink_spec.rb b/spec/ruby/core/file/readlink_spec.rb
index 20741ba121..568692b9b6 100644
--- a/spec/ruby/core/file/readlink_spec.rb
+++ b/spec/ruby/core/file/readlink_spec.rb
@@ -26,12 +26,12 @@ describe "File.readlink" do
it "raises an Errno::ENOENT if there is no such file" do
# TODO: missing_file
- -> { File.readlink("/this/surely/does/not/exist") }.should raise_error(Errno::ENOENT)
+ -> { File.readlink("/this/surely/does/not/exist") }.should.raise(Errno::ENOENT)
end
it "raises an Errno::EINVAL if called with a normal file" do
touch @file
- -> { File.readlink(@file) }.should raise_error(Errno::EINVAL)
+ -> { File.readlink(@file) }.should.raise(Errno::EINVAL)
end
end
@@ -49,7 +49,7 @@ describe "File.readlink" do
it "returns the name of the file referenced by the given link" do
touch @file
result = File.readlink(@link)
- result.encoding.should equal Encoding.find('filesystem')
+ result.encoding.should.equal? Encoding.find('filesystem')
result.should == @file.dup.force_encoding(Encoding.find('filesystem'))
end
end
diff --git a/spec/ruby/core/file/realdirpath_spec.rb b/spec/ruby/core/file/realdirpath_spec.rb
index 74053afce3..ecf1e0c6d9 100644
--- a/spec/ruby/core/file/realdirpath_spec.rb
+++ b/spec/ruby/core/file/realdirpath_spec.rb
@@ -61,7 +61,7 @@ platform_is_not :windows do
it "raises an Errno::ELOOP if the symlink points to itself" do
File.unlink @link
File.symlink(@link, @link)
- -> { File.realdirpath(@link) }.should raise_error(Errno::ELOOP)
+ -> { File.realdirpath(@link) }.should.raise(Errno::ELOOP)
end
it "returns the real (absolute) pathname if the file is absent" do
@@ -69,7 +69,7 @@ platform_is_not :windows do
end
it "raises Errno::ENOENT if the directory is absent" do
- -> { File.realdirpath(@fake_file_in_fake_dir) }.should raise_error(Errno::ENOENT)
+ -> { File.realdirpath(@fake_file_in_fake_dir) }.should.raise(Errno::ENOENT)
end
it "returns the real (absolute) pathname if the symlink points to an absent file" do
@@ -77,7 +77,7 @@ platform_is_not :windows do
end
it "raises Errno::ENOENT if the symlink points to an absent directory" do
- -> { File.realdirpath(@fake_link_to_fake_dir) }.should raise_error(Errno::ENOENT)
+ -> { File.realdirpath(@fake_link_to_fake_dir) }.should.raise(Errno::ENOENT)
end
end
end
diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb
index bd25bfdecf..ccb981eff1 100644
--- a/spec/ruby/core/file/realpath_spec.rb
+++ b/spec/ruby/core/file/realpath_spec.rb
@@ -61,15 +61,15 @@ platform_is_not :windows do
it "raises an Errno::ELOOP if the symlink points to itself" do
File.unlink @link
File.symlink(@link, @link)
- -> { File.realpath(@link) }.should raise_error(Errno::ELOOP)
+ -> { File.realpath(@link) }.should.raise(Errno::ELOOP)
end
it "raises Errno::ENOENT if the file is absent" do
- -> { File.realpath(@fake_file) }.should raise_error(Errno::ENOENT)
+ -> { File.realpath(@fake_file) }.should.raise(Errno::ENOENT)
end
it "raises Errno::ENOENT if the symlink points to an absent file" do
- -> { File.realpath(@fake_link) }.should raise_error(Errno::ENOENT)
+ -> { File.realpath(@fake_link) }.should.raise(Errno::ENOENT)
end
it "converts the argument with #to_path" do
diff --git a/spec/ruby/core/file/rename_spec.rb b/spec/ruby/core/file/rename_spec.rb
index f2c18d4905..70ea669a68 100644
--- a/spec/ruby/core/file/rename_spec.rb
+++ b/spec/ruby/core/file/rename_spec.rb
@@ -23,15 +23,15 @@ describe "File.rename" do
it "raises an Errno::ENOENT if the source does not exist" do
rm_r @old
- -> { File.rename(@old, @new) }.should raise_error(Errno::ENOENT)
+ -> { File.rename(@old, @new) }.should.raise(Errno::ENOENT)
end
it "raises an ArgumentError if not passed two arguments" do
- -> { File.rename }.should raise_error(ArgumentError)
- -> { File.rename(@file) }.should raise_error(ArgumentError)
+ -> { File.rename }.should.raise(ArgumentError)
+ -> { File.rename(@file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed String types" do
- -> { File.rename(1, 2) }.should raise_error(TypeError)
+ -> { File.rename(1, 2) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/file/setuid_spec.rb b/spec/ruby/core/file/setuid_spec.rb
index 281ef01ab9..9e5e86df61 100644
--- a/spec/ruby/core/file/setuid_spec.rb
+++ b/spec/ruby/core/file/setuid_spec.rb
@@ -26,10 +26,6 @@ describe "File.setuid?" do
platform_is_not :windows do
it "returns true when the gid bit is set" do
- platform_is :solaris do
- # Solaris requires execute bit before setting suid
- system "chmod u+x #{@name}"
- end
system "chmod u+s #{@name}"
File.setuid?(@name).should == true
diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb
index db4b5c5d8c..b9140d027d 100644
--- a/spec/ruby/core/file/shared/fnmatch.rb
+++ b/spec/ruby/core/file/shared/fnmatch.rb
@@ -222,48 +222,48 @@ describe :file_fnmatch, shared: true do
it "returns false if '/' in pattern do not match '/' in path when flags includes FNM_PATHNAME" do
pattern = '*/*'
- File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME).should be_false
+ File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME).should == false
pattern = '**/foo'
- File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should be_false
+ File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should == false
end
it "returns true if '/' in pattern match '/' in path when flags includes FNM_PATHNAME" do
pattern = '*/*'
- File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
pattern = '**/foo'
- File.send(@method, pattern, 'a/b/c/foo', File::FNM_PATHNAME).should be_true
- File.send(@method, pattern, '/a/b/c/foo', File::FNM_PATHNAME).should be_true
- File.send(@method, pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME).should be_true
- File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, pattern, 'a/b/c/foo', File::FNM_PATHNAME).should == true
+ File.send(@method, pattern, '/a/b/c/foo', File::FNM_PATHNAME).should == true
+ File.send(@method, pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME).should == true
+ File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
end
it "has special handling for ./ when using * and FNM_PATHNAME" do
- File.send(@method, './*', '.', File::FNM_PATHNAME).should be_false
- File.send(@method, './*', './', File::FNM_PATHNAME).should be_true
- File.send(@method, './*/', './', File::FNM_PATHNAME).should be_false
- File.send(@method, './**', './', File::FNM_PATHNAME).should be_true
- File.send(@method, './**/', './', File::FNM_PATHNAME).should be_true
- File.send(@method, './*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
- File.send(@method, './*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, './*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
- File.send(@method, './**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, './**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, './*', '.', File::FNM_PATHNAME).should == false
+ File.send(@method, './*', './', File::FNM_PATHNAME).should == true
+ File.send(@method, './*/', './', File::FNM_PATHNAME).should == false
+ File.send(@method, './**', './', File::FNM_PATHNAME).should == true
+ File.send(@method, './**/', './', File::FNM_PATHNAME).should == true
+ File.send(@method, './*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false
+ File.send(@method, './*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.send(@method, './*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false
+ File.send(@method, './**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.send(@method, './**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
end
it "matches **/* with FNM_PATHNAME to recurse directories" do
- File.send(@method, 'nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should be_true
- File.send(@method, 'nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should be_true
- File.send(@method, 'nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, 'nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, 'nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should == true
+ File.send(@method, 'nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should == true
+ File.send(@method, 'nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.send(@method, 'nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
end
it "matches ** with FNM_PATHNAME only in current directory" do
- File.send(@method, 'nested/**', 'nested/subdir', File::FNM_PATHNAME).should be_true
- File.send(@method, 'nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should be_false
- File.send(@method, 'nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, 'nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
+ File.send(@method, 'nested/**', 'nested/subdir', File::FNM_PATHNAME).should == true
+ File.send(@method, 'nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should == false
+ File.send(@method, 'nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true
+ File.send(@method, 'nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false
end
it "accepts an object that has a #to_path method" do
@@ -271,21 +271,21 @@ describe :file_fnmatch, shared: true do
end
it "raises a TypeError if the first and second arguments are not string-like" do
- -> { File.send(@method, nil, nil, 0, 0) }.should raise_error(ArgumentError)
- -> { File.send(@method, 1, 'some/thing') }.should raise_error(TypeError)
- -> { File.send(@method, 'some/thing', 1) }.should raise_error(TypeError)
- -> { File.send(@method, 1, 1) }.should raise_error(TypeError)
+ -> { File.send(@method, nil, nil, 0, 0) }.should.raise(ArgumentError)
+ -> { File.send(@method, 1, 'some/thing') }.should.raise(TypeError)
+ -> { File.send(@method, 'some/thing', 1) }.should.raise(TypeError)
+ -> { File.send(@method, 1, 1) }.should.raise(TypeError)
end
it "raises a TypeError if the third argument is not an Integer" do
- -> { File.send(@method, "*/place", "path/to/file", "flags") }.should raise_error(TypeError)
- -> { File.send(@method, "*/place", "path/to/file", nil) }.should raise_error(TypeError)
+ -> { File.send(@method, "*/place", "path/to/file", "flags") }.should.raise(TypeError)
+ -> { File.send(@method, "*/place", "path/to/file", nil) }.should.raise(TypeError)
end
it "does not raise a TypeError if the third argument can be coerced to an Integer" do
flags = mock("flags")
flags.should_receive(:to_int).and_return(10)
- -> { File.send(@method, "*/place", "path/to/file", flags) }.should_not raise_error
+ -> { File.send(@method, "*/place", "path/to/file", flags) }.should_not.raise
end
it "matches multibyte characters" do
diff --git a/spec/ruby/core/file/shared/open.rb b/spec/ruby/core/file/shared/open.rb
index 677a82a351..67149235ca 100644
--- a/spec/ruby/core/file/shared/open.rb
+++ b/spec/ruby/core/file/shared/open.rb
@@ -4,7 +4,7 @@ describe :open_directory, shared: true do
it "opens directories" do
file = File.send(@method, tmp(""))
begin
- file.should be_kind_of(File)
+ file.should.is_a?(File)
ensure
file.close
end
diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb
index 5a9fe1b0c5..6c6f7d4234 100644
--- a/spec/ruby/core/file/shared/path.rb
+++ b/spec/ruby/core/file/shared/path.rb
@@ -12,7 +12,7 @@ describe :file_path, shared: true do
it "returns a String" do
@file = File.new @path
- @file.send(@method).should be_an_instance_of(String)
+ @file.send(@method).should.instance_of?(String)
end
it "returns a different String on every call" do
diff --git a/spec/ruby/core/file/shared/read.rb b/spec/ruby/core/file/shared/read.rb
index f232235298..f60800bb2f 100644
--- a/spec/ruby/core/file/shared/read.rb
+++ b/spec/ruby/core/file/shared/read.rb
@@ -3,13 +3,13 @@ require_relative '../../dir/fixtures/common'
describe :file_read_directory, shared: true do
platform_is :darwin, :linux, :freebsd, :openbsd, :windows do
it "raises an Errno::EISDIR when passed a path that is a directory" do
- -> { @object.send(@method, ".") }.should raise_error(Errno::EISDIR)
+ -> { @object.send(@method, ".") }.should.raise(Errno::EISDIR)
end
end
platform_is :netbsd do
it "does not raises any exception when passed a path that is a directory" do
- -> { @object.send(@method, ".") }.should_not raise_error
+ -> { @object.send(@method, ".") }.should_not.raise
end
end
end
diff --git a/spec/ruby/core/file/shared/stat.rb b/spec/ruby/core/file/shared/stat.rb
index fdaf97ea61..879a7f11ff 100644
--- a/spec/ruby/core/file/shared/stat.rb
+++ b/spec/ruby/core/file/shared/stat.rb
@@ -10,13 +10,13 @@ describe :file_stat, shared: true do
it "returns a File::Stat object if the given file exists" do
st = File.send(@method, @file)
- st.should be_an_instance_of(File::Stat)
+ st.should.instance_of?(File::Stat)
end
it "returns a File::Stat object when called on an instance of File" do
File.open(@file) do |f|
st = f.send(@method)
- st.should be_an_instance_of(File::Stat)
+ st.should.instance_of?(File::Stat)
end
end
@@ -27,6 +27,6 @@ describe :file_stat, shared: true do
it "raises an Errno::ENOENT if the file does not exist" do
-> {
File.send(@method, "fake_file")
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/core/file/shared/unlink.rb b/spec/ruby/core/file/shared/unlink.rb
index e339e93271..0032907ba2 100644
--- a/spec/ruby/core/file/shared/unlink.rb
+++ b/spec/ruby/core/file/shared/unlink.rb
@@ -31,11 +31,11 @@ describe :file_unlink, shared: true do
end
it "raises a TypeError if not passed a String type" do
- -> { File.send(@method, 1) }.should raise_error(TypeError)
+ -> { File.send(@method, 1) }.should.raise(TypeError)
end
it "raises an Errno::ENOENT when the given file doesn't exist" do
- -> { File.send(@method, 'bogus') }.should raise_error(Errno::ENOENT)
+ -> { File.send(@method, 'bogus') }.should.raise(Errno::ENOENT)
end
it "coerces a given parameter into a string if possible" do
diff --git a/spec/ruby/core/file/size_spec.rb b/spec/ruby/core/file/size_spec.rb
index 11d20cbacb..784c18c26e 100644
--- a/spec/ruby/core/file/size_spec.rb
+++ b/spec/ruby/core/file/size_spec.rb
@@ -56,11 +56,11 @@ describe "File#size" do
end
it "is an instance method" do
- @file.respond_to?(:size).should be_true
+ @file.respond_to?(:size).should == true
end
it "returns the file's size as an Integer" do
- @file.size.should be_an_instance_of(Integer)
+ @file.size.should.instance_of?(Integer)
end
it "returns the file's size in bytes" do
@@ -81,7 +81,7 @@ describe "File#size" do
it "raises an IOError on a closed file" do
@file.close
- -> { @file.size }.should raise_error(IOError)
+ -> { @file.size }.should.raise(IOError)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/file/socket_spec.rb b/spec/ruby/core/file/socket_spec.rb
index 5d12e21f55..d3f4eb013a 100644
--- a/spec/ruby/core/file/socket_spec.rb
+++ b/spec/ruby/core/file/socket_spec.rb
@@ -1,42 +1,10 @@
require_relative '../../spec_helper'
require_relative '../../shared/file/socket'
-require 'socket'
describe "File.socket?" do
it_behaves_like :file_socket, :socket?, File
-end
-describe "File.socket?" do
it "returns false if file does not exist" do
File.socket?("I_am_a_bogus_file").should == false
end
-
- it "returns false if the file is not a socket" do
- filename = tmp("i_exist")
- touch(filename)
-
- File.socket?(filename).should == false
-
- rm_r filename
- end
-end
-
-platform_is_not :windows do
- describe "File.socket?" do
- before :each do
- # We need a really short name here.
- # On Linux the path length is limited to 107, see unix(7).
- @name = tmp("s")
- @server = UNIXServer.new @name
- end
-
- after :each do
- @server.close
- rm_r @name
- end
-
- it "returns true if the file is a socket" do
- File.socket?(@name).should == true
- end
- end
end
diff --git a/spec/ruby/core/file/split_spec.rb b/spec/ruby/core/file/split_spec.rb
index 7b958621b9..e989a6b86e 100644
--- a/spec/ruby/core/file/split_spec.rb
+++ b/spec/ruby/core/file/split_spec.rb
@@ -44,12 +44,12 @@ describe "File.split" do
end
it "raises an ArgumentError when not passed a single argument" do
- -> { File.split }.should raise_error(ArgumentError)
- -> { File.split('string', 'another string') }.should raise_error(ArgumentError)
+ -> { File.split }.should.raise(ArgumentError)
+ -> { File.split('string', 'another string') }.should.raise(ArgumentError)
end
it "raises a TypeError if the argument is not a String type" do
- -> { File.split(1) }.should raise_error(TypeError)
+ -> { File.split(1) }.should.raise(TypeError)
end
it "coerces the argument with to_str if it is not a String type" do
diff --git a/spec/ruby/core/file/stat/atime_spec.rb b/spec/ruby/core/file/stat/atime_spec.rb
index 9f1111ced1..2fecaed300 100644
--- a/spec/ruby/core/file/stat/atime_spec.rb
+++ b/spec/ruby/core/file/stat/atime_spec.rb
@@ -12,7 +12,7 @@ describe "File::Stat#atime" do
it "returns the atime of a File::Stat object" do
st = File.stat(@file)
- st.atime.should be_kind_of(Time)
+ st.atime.should.is_a?(Time)
st.atime.should <= Time.now
end
end
diff --git a/spec/ruby/core/file/stat/birthtime_spec.rb b/spec/ruby/core/file/stat/birthtime_spec.rb
index a727bbe566..728f635397 100644
--- a/spec/ruby/core/file/stat/birthtime_spec.rb
+++ b/spec/ruby/core/file/stat/birthtime_spec.rb
@@ -1,27 +1,29 @@
require_relative '../../../spec_helper'
-describe "File::Stat#birthtime" do
- before :each do
- @file = tmp('i_exist')
- touch(@file) { |f| f.write "rubinius" }
- end
+platform_is(:windows, :darwin, :freebsd, :netbsd,
+ *ruby_version_is("4.0") { :linux },
+ ) do
+ not_implemented_messages = [
+ "birthtime() function is unimplemented", # unsupported OS/version
+ "birthtime is unimplemented", # unsupported filesystem
+ ]
- after :each do
- rm_r @file
- end
+ describe "File::Stat#birthtime" do
+ before :each do
+ @file = tmp('i_exist')
+ touch(@file) { |f| f.write "rubinius" }
+ end
- platform_is :windows, :darwin, :freebsd, :netbsd do
- it "returns the birthtime of a File::Stat object" do
- st = File.stat(@file)
- st.birthtime.should be_kind_of(Time)
- st.birthtime.should <= Time.now
+ after :each do
+ rm_r @file
end
- end
- platform_is :linux, :openbsd do
- it "raises an NotImplementedError" do
+ it "returns the birthtime of a File::Stat object" do
st = File.stat(@file)
- -> { st.birthtime }.should raise_error(NotImplementedError)
+ st.birthtime.should.is_a?(Time)
+ st.birthtime.should <= Time.now
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
end
end
diff --git a/spec/ruby/core/file/stat/blocks_spec.rb b/spec/ruby/core/file/stat/blocks_spec.rb
index f3f903d0f7..5e0efc8bc2 100644
--- a/spec/ruby/core/file/stat/blocks_spec.rb
+++ b/spec/ruby/core/file/stat/blocks_spec.rb
@@ -21,7 +21,7 @@ describe "File::Stat#blocks" do
platform_is :windows do
it "returns nil" do
st = File.stat(@file)
- st.blocks.should be_nil
+ st.blocks.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/ctime_spec.rb b/spec/ruby/core/file/stat/ctime_spec.rb
index fd50487a0a..dbf43a7453 100644
--- a/spec/ruby/core/file/stat/ctime_spec.rb
+++ b/spec/ruby/core/file/stat/ctime_spec.rb
@@ -12,7 +12,7 @@ describe "File::Stat#ctime" do
it "returns the ctime of a File::Stat object" do
st = File.stat(@file)
- st.ctime.should be_kind_of(Time)
+ st.ctime.should.is_a?(Time)
st.ctime.should <= Time.now
end
end
diff --git a/spec/ruby/core/file/stat/dev_major_spec.rb b/spec/ruby/core/file/stat/dev_major_spec.rb
index 4966d609e2..a199eaaa11 100644
--- a/spec/ruby/core/file/stat/dev_major_spec.rb
+++ b/spec/ruby/core/file/stat/dev_major_spec.rb
@@ -11,13 +11,13 @@ describe "File::Stat#dev_major" do
platform_is_not :windows do
it "returns the major part of File::Stat#dev" do
- File.stat(@name).dev_major.should be_kind_of(Integer)
+ File.stat(@name).dev_major.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).dev_major.should be_nil
+ File.stat(@name).dev_major.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/dev_minor_spec.rb b/spec/ruby/core/file/stat/dev_minor_spec.rb
index ea79c12b99..8ce94778ca 100644
--- a/spec/ruby/core/file/stat/dev_minor_spec.rb
+++ b/spec/ruby/core/file/stat/dev_minor_spec.rb
@@ -11,13 +11,13 @@ describe "File::Stat#dev_minor" do
platform_is_not :windows do
it "returns the minor part of File::Stat#dev" do
- File.stat(@name).dev_minor.should be_kind_of(Integer)
+ File.stat(@name).dev_minor.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).dev_minor.should be_nil
+ File.stat(@name).dev_minor.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/dev_spec.rb b/spec/ruby/core/file/stat/dev_spec.rb
index e953fcaa58..cd5e3d175e 100644
--- a/spec/ruby/core/file/stat/dev_spec.rb
+++ b/spec/ruby/core/file/stat/dev_spec.rb
@@ -10,6 +10,6 @@ describe "File::Stat#dev" do
end
it "returns the number of the device on which the file exists" do
- File.stat(@name).dev.should be_kind_of(Integer)
+ File.stat(@name).dev.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/file/stat/ftype_spec.rb b/spec/ruby/core/file/stat/ftype_spec.rb
index eb892eae5f..df2e3ada1e 100644
--- a/spec/ruby/core/file/stat/ftype_spec.rb
+++ b/spec/ruby/core/file/stat/ftype_spec.rb
@@ -8,7 +8,7 @@ describe "File::Stat#ftype" do
it "returns a String" do
FileSpecs.normal_file do |file|
- File.lstat(file).ftype.should be_kind_of(String)
+ File.lstat(file).ftype.should.is_a?(String)
end
end
diff --git a/spec/ruby/core/file/stat/ino_spec.rb b/spec/ruby/core/file/stat/ino_spec.rb
index 42370aecb7..c09b6448c7 100644
--- a/spec/ruby/core/file/stat/ino_spec.rb
+++ b/spec/ruby/core/file/stat/ino_spec.rb
@@ -13,7 +13,7 @@ describe "File::Stat#ino" do
platform_is_not :windows do
it "returns the ino of a File::Stat object" do
st = File.stat(@file)
- st.ino.should be_kind_of(Integer)
+ st.ino.should.is_a?(Integer)
st.ino.should > 0
end
end
@@ -21,7 +21,7 @@ describe "File::Stat#ino" do
platform_is :windows do
it "returns BY_HANDLE_FILE_INFORMATION.nFileIndexHigh/Low of a File::Stat object" do
st = File.stat(@file)
- st.ino.should be_kind_of(Integer)
+ st.ino.should.is_a?(Integer)
st.ino.should > 0
end
end
diff --git a/spec/ruby/core/file/stat/mtime_spec.rb b/spec/ruby/core/file/stat/mtime_spec.rb
index 08a2b83463..7844491212 100644
--- a/spec/ruby/core/file/stat/mtime_spec.rb
+++ b/spec/ruby/core/file/stat/mtime_spec.rb
@@ -12,7 +12,7 @@ describe "File::Stat#mtime" do
it "returns the mtime of a File::Stat object" do
st = File.stat(@file)
- st.mtime.should be_kind_of(Time)
+ st.mtime.should.is_a?(Time)
st.mtime.should <= Time.now
end
end
diff --git a/spec/ruby/core/file/stat/new_spec.rb b/spec/ruby/core/file/stat/new_spec.rb
index c0d9432ac8..b8c3600028 100644
--- a/spec/ruby/core/file/stat/new_spec.rb
+++ b/spec/ruby/core/file/stat/new_spec.rb
@@ -15,12 +15,12 @@ describe "File::Stat#initialize" do
it "raises an exception if the file doesn't exist" do
-> {
File::Stat.new(tmp("i_am_a_dummy_file_that_doesnt_exist"))
- }.should raise_error(Errno::ENOENT)
+ }.should.raise(Errno::ENOENT)
end
it "creates a File::Stat object for the given file" do
st = File::Stat.new(@file)
- st.should be_kind_of(File::Stat)
+ st.should.is_a?(File::Stat)
st.ftype.should == 'file'
end
diff --git a/spec/ruby/core/file/stat/rdev_major_spec.rb b/spec/ruby/core/file/stat/rdev_major_spec.rb
index f8a8d1b107..e1b44fc2d0 100644
--- a/spec/ruby/core/file/stat/rdev_major_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_major_spec.rb
@@ -2,30 +2,23 @@ require_relative '../../../spec_helper'
describe "File::Stat#rdev_major" do
before :each do
- platform_is :solaris do
- @name = "/dev/zfs"
- end
- platform_is_not :solaris do
- @name = tmp("file.txt")
- touch(@name)
- end
+ @name = tmp("file.txt")
+ touch(@name)
end
after :each do
- platform_is_not :solaris do
- rm_r @name
- end
+ rm_r @name
end
platform_is_not :windows do
it "returns the major part of File::Stat#rdev" do
- File.stat(@name).rdev_major.should be_kind_of(Integer)
+ File.stat(@name).rdev_major.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).rdev_major.should be_nil
+ File.stat(@name).rdev_major.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/rdev_minor_spec.rb b/spec/ruby/core/file/stat/rdev_minor_spec.rb
index dc30c1f56c..8af3b9f587 100644
--- a/spec/ruby/core/file/stat/rdev_minor_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_minor_spec.rb
@@ -2,30 +2,23 @@ require_relative '../../../spec_helper'
describe "File::Stat#rdev_minor" do
before :each do
- platform_is :solaris do
- @name = "/dev/zfs"
- end
- platform_is_not :solaris do
- @name = tmp("file.txt")
- touch(@name)
- end
+ @name = tmp("file.txt")
+ touch(@name)
end
after :each do
- platform_is_not :solaris do
- rm_r @name
- end
+ rm_r @name
end
platform_is_not :windows do
it "returns the minor part of File::Stat#rdev" do
- File.stat(@name).rdev_minor.should be_kind_of(Integer)
+ File.stat(@name).rdev_minor.should.is_a?(Integer)
end
end
platform_is :windows do
it "returns nil" do
- File.stat(@name).rdev_minor.should be_nil
+ File.stat(@name).rdev_minor.should == nil
end
end
end
diff --git a/spec/ruby/core/file/stat/rdev_spec.rb b/spec/ruby/core/file/stat/rdev_spec.rb
index 9e1aee692d..7e4252fcc6 100644
--- a/spec/ruby/core/file/stat/rdev_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_spec.rb
@@ -10,6 +10,6 @@ describe "File::Stat#rdev" do
end
it "returns the number of the device this file represents which the file exists" do
- File.stat(@name).rdev.should be_kind_of(Integer)
+ File.stat(@name).rdev.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/file/stat_spec.rb b/spec/ruby/core/file/stat_spec.rb
index 6365500057..d5238b6331 100644
--- a/spec/ruby/core/file/stat_spec.rb
+++ b/spec/ruby/core/file/stat_spec.rb
@@ -28,9 +28,9 @@ platform_is_not :windows do
st.size.should == 8
st.size?.should == 8
st.blksize.should >= 0
- st.atime.should be_kind_of(Time)
- st.ctime.should be_kind_of(Time)
- st.mtime.should be_kind_of(Time)
+ st.atime.should.is_a?(Time)
+ st.ctime.should.is_a?(Time)
+ st.mtime.should.is_a?(Time)
end
end
@@ -46,9 +46,9 @@ platform_is_not :windows do
missing_path = "/missingfilepath\xE3E4".b
-> {
File.stat(missing_path)
- }.should raise_error(SystemCallError) { |e|
- [Errno::ENOENT, Errno::EILSEQ].should include(e.class)
- e.message.should include(missing_path)
+ }.should.raise(SystemCallError) { |e|
+ [Errno::ENOENT, Errno::EILSEQ].should.include?(e.class)
+ e.message.should.include?(missing_path)
}
end
end
diff --git a/spec/ruby/core/file/symlink_spec.rb b/spec/ruby/core/file/symlink_spec.rb
index 0e8b0a5a20..4ceeb28c84 100644
--- a/spec/ruby/core/file/symlink_spec.rb
+++ b/spec/ruby/core/file/symlink_spec.rb
@@ -32,18 +32,18 @@ describe "File.symlink" do
it "raises an Errno::EEXIST if the target already exists" do
File.symlink(@file, @link)
- -> { File.symlink(@file, @link) }.should raise_error(Errno::EEXIST)
+ -> { File.symlink(@file, @link) }.should.raise(Errno::EEXIST)
end
it "raises an ArgumentError if not called with two arguments" do
- -> { File.symlink }.should raise_error(ArgumentError)
- -> { File.symlink(@file) }.should raise_error(ArgumentError)
+ -> { File.symlink }.should.raise(ArgumentError)
+ -> { File.symlink(@file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not called with String types" do
- -> { File.symlink(@file, nil) }.should raise_error(TypeError)
- -> { File.symlink(@file, 1) }.should raise_error(TypeError)
- -> { File.symlink(1, 1) }.should raise_error(TypeError)
+ -> { File.symlink(@file, nil) }.should.raise(TypeError)
+ -> { File.symlink(@file, 1) }.should.raise(TypeError)
+ -> { File.symlink(1, 1) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/file/truncate_spec.rb b/spec/ruby/core/file/truncate_spec.rb
index b4a2e3e577..5f37f34155 100644
--- a/spec/ruby/core/file/truncate_spec.rb
+++ b/spec/ruby/core/file/truncate_spec.rb
@@ -54,29 +54,29 @@ describe "File.truncate" do
rm_r not_existing_file
begin
- -> { File.truncate(not_existing_file, 5) }.should raise_error(Errno::ENOENT)
+ -> { File.truncate(not_existing_file, 5) }.should.raise(Errno::ENOENT)
ensure
rm_r not_existing_file
end
end
it "raises an ArgumentError if not passed two arguments" do
- -> { File.truncate }.should raise_error(ArgumentError)
- -> { File.truncate(@name) }.should raise_error(ArgumentError)
+ -> { File.truncate }.should.raise(ArgumentError)
+ -> { File.truncate(@name) }.should.raise(ArgumentError)
end
platform_is_not :netbsd, :openbsd do
it "raises an Errno::EINVAL if the length argument is not valid" do
- -> { File.truncate(@name, -1) }.should raise_error(Errno::EINVAL) # May fail
+ -> { File.truncate(@name, -1) }.should.raise(Errno::EINVAL) # May fail
end
end
it "raises a TypeError if not passed a String type for the first argument" do
- -> { File.truncate(1, 1) }.should raise_error(TypeError)
+ -> { File.truncate(1, 1) }.should.raise(TypeError)
end
it "raises a TypeError if not passed an Integer type for the second argument" do
- -> { File.truncate(@name, nil) }.should raise_error(TypeError)
+ -> { File.truncate(@name, nil) }.should.raise(TypeError)
end
it "accepts an object that has a #to_path method" do
@@ -149,29 +149,29 @@ describe "File#truncate" do
end
it "raises an ArgumentError if not passed one argument" do
- -> { @file.truncate }.should raise_error(ArgumentError)
- -> { @file.truncate(1) }.should_not raise_error(ArgumentError)
+ -> { @file.truncate }.should.raise(ArgumentError)
+ -> { @file.truncate(1) }.should_not.raise(ArgumentError)
end
platform_is_not :netbsd do
it "raises an Errno::EINVAL if the length argument is not valid" do
- -> { @file.truncate(-1) }.should raise_error(Errno::EINVAL) # May fail
+ -> { @file.truncate(-1) }.should.raise(Errno::EINVAL) # May fail
end
end
it "raises an IOError if file is closed" do
@file.close
@file.should.closed?
- -> { @file.truncate(42) }.should raise_error(IOError)
+ -> { @file.truncate(42) }.should.raise(IOError)
end
it "raises an IOError if file is not opened for writing" do
File.open(@name, 'r') do |file|
- -> { file.truncate(42) }.should raise_error(IOError)
+ -> { file.truncate(42) }.should.raise(IOError)
end
end
it "raises a TypeError if not passed an Integer type for the for the argument" do
- -> { @file.truncate(nil) }.should raise_error(TypeError)
+ -> { @file.truncate(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/file/umask_spec.rb b/spec/ruby/core/file/umask_spec.rb
index 7f7e40abbc..fea8cf7633 100644
--- a/spec/ruby/core/file/umask_spec.rb
+++ b/spec/ruby/core/file/umask_spec.rb
@@ -13,7 +13,7 @@ describe "File.umask" do
end
it "returns an Integer" do
- File.umask.should be_kind_of(Integer)
+ File.umask.should.is_a?(Integer)
end
platform_is_not :windows do
@@ -47,11 +47,11 @@ describe "File.umask" do
end
it "raises RangeError with too large values" do
- -> { File.umask(2**64) }.should raise_error(RangeError)
- -> { File.umask(-2**63 - 1) }.should raise_error(RangeError)
+ -> { File.umask(2**64) }.should.raise(RangeError)
+ -> { File.umask(-2**63 - 1) }.should.raise(RangeError)
end
it "raises ArgumentError when more than one argument is provided" do
- -> { File.umask(022, 022) }.should raise_error(ArgumentError)
+ -> { File.umask(022, 022) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/file/world_readable_spec.rb b/spec/ruby/core/file/world_readable_spec.rb
index 11b8e67d0b..0f5e0b13d7 100644
--- a/spec/ruby/core/file/world_readable_spec.rb
+++ b/spec/ruby/core/file/world_readable_spec.rb
@@ -7,6 +7,6 @@ describe "File.world_readable?" do
it "returns nil if the file does not exist" do
file = rand.to_s + $$.to_s
File.should_not.exist?(file)
- File.world_readable?(file).should be_nil
+ File.world_readable?(file).should == nil
end
end
diff --git a/spec/ruby/core/file/world_writable_spec.rb b/spec/ruby/core/file/world_writable_spec.rb
index d378cf2eb9..46ba6832f9 100644
--- a/spec/ruby/core/file/world_writable_spec.rb
+++ b/spec/ruby/core/file/world_writable_spec.rb
@@ -7,6 +7,6 @@ describe "File.world_writable?" do
it "returns nil if the file does not exist" do
file = rand.to_s + $$.to_s
File.should_not.exist?(file)
- File.world_writable?(file).should be_nil
+ File.world_writable?(file).should == nil
end
end
diff --git a/spec/ruby/core/file/zero_spec.rb b/spec/ruby/core/file/zero_spec.rb
index 63dd85ee46..01c7505ef2 100644
--- a/spec/ruby/core/file/zero_spec.rb
+++ b/spec/ruby/core/file/zero_spec.rb
@@ -4,10 +4,4 @@ require_relative '../../shared/file/zero'
describe "File.zero?" do
it_behaves_like :file_zero, :zero?, File
it_behaves_like :file_zero_missing, :zero?, File
-
- platform_is :solaris do
- it "returns false for /dev/null" do
- File.zero?('/dev/null').should == true
- end
- end
end
diff --git a/spec/ruby/core/filetest/exist_spec.rb b/spec/ruby/core/filetest/exist_spec.rb
index a95d3f91a1..612ffa9fcb 100644
--- a/spec/ruby/core/filetest/exist_spec.rb
+++ b/spec/ruby/core/filetest/exist_spec.rb
@@ -5,10 +5,8 @@ describe "FileTest.exist?" do
it_behaves_like :file_exist, :exist?, FileTest
end
-ruby_version_is "3.2" do
- describe "FileTest.exists?" do
- it "has been removed" do
- FileTest.should_not.respond_to?(:exists?)
- end
+describe "FileTest.exists?" do
+ it "has been removed" do
+ FileTest.should_not.respond_to?(:exists?)
end
end
diff --git a/spec/ruby/core/filetest/grpowned_spec.rb b/spec/ruby/core/filetest/grpowned_spec.rb
index d073cb9770..d6bd6abd71 100644
--- a/spec/ruby/core/filetest/grpowned_spec.rb
+++ b/spec/ruby/core/filetest/grpowned_spec.rb
@@ -5,6 +5,6 @@ describe "FileTest.grpowned?" do
it_behaves_like :file_grpowned, :grpowned?, FileTest
it "returns false if the file doesn't exist" do
- FileTest.grpowned?("xxx-tmp-doesnt_exist-blah").should be_false
+ FileTest.grpowned?("xxx-tmp-doesnt_exist-blah").should == false
end
end
diff --git a/spec/ruby/core/filetest/socket_spec.rb b/spec/ruby/core/filetest/socket_spec.rb
index 63a6a31ecb..f274be6318 100644
--- a/spec/ruby/core/filetest/socket_spec.rb
+++ b/spec/ruby/core/filetest/socket_spec.rb
@@ -3,4 +3,8 @@ require_relative '../../shared/file/socket'
describe "FileTest.socket?" do
it_behaves_like :file_socket, :socket?, FileTest
+
+ it "returns false if file does not exist" do
+ FileTest.socket?("I_am_a_bogus_file").should == false
+ end
end
diff --git a/spec/ruby/core/filetest/zero_spec.rb b/spec/ruby/core/filetest/zero_spec.rb
index dd6a164ec9..92cab67f1b 100644
--- a/spec/ruby/core/filetest/zero_spec.rb
+++ b/spec/ruby/core/filetest/zero_spec.rb
@@ -4,10 +4,4 @@ require_relative '../../shared/file/zero'
describe "FileTest.zero?" do
it_behaves_like :file_zero, :zero?, FileTest
it_behaves_like :file_zero_missing, :zero?, FileTest
-
- platform_is :solaris do
- it "returns false for /dev/null" do
- File.zero?('/dev/null').should == true
- end
- end
end
diff --git a/spec/ruby/core/float/ceil_spec.rb b/spec/ruby/core/float/ceil_spec.rb
index 75f5610292..efd1e6feb2 100644
--- a/spec/ruby/core/float/ceil_spec.rb
+++ b/spec/ruby/core/float/ceil_spec.rb
@@ -2,25 +2,27 @@ require_relative '../../spec_helper'
require_relative '../integer/shared/integer_ceil_precision'
describe "Float#ceil" do
- context "with precision" do
+ context "with values equal to integers" do
it_behaves_like :integer_ceil_precision, :Float
end
it "returns the smallest Integer greater than or equal to self" do
- -1.2.ceil.should eql( -1)
- -1.0.ceil.should eql( -1)
- 0.0.ceil.should eql( 0 )
- 1.3.ceil.should eql( 2 )
- 3.0.ceil.should eql( 3 )
- -9223372036854775808.1.ceil.should eql(-9223372036854775808)
- +9223372036854775808.1.ceil.should eql(+9223372036854775808)
+ -1.2.ceil.should.eql?( -1)
+ -1.0.ceil.should.eql?( -1)
+ 0.0.ceil.should.eql?( 0 )
+ 1.3.ceil.should.eql?( 2 )
+ 3.0.ceil.should.eql?( 3 )
+ -9223372036854775808.1.ceil.should.eql?(-9223372036854775808)
+ +9223372036854775808.1.ceil.should.eql?(+9223372036854775808)
end
it "returns the smallest number greater than or equal to self with an optionally given precision" do
- 2.1679.ceil(0).should eql(3)
- 214.94.ceil(-1).should eql(220)
- 7.0.ceil(1).should eql(7.0)
- -1.234.ceil(2).should eql(-1.23)
- 5.123812.ceil(4).should eql(5.1239)
+ 2.1679.ceil(0).should.eql?(3)
+ 214.94.ceil(-1).should.eql?(220)
+ 7.0.ceil(1).should.eql?(7.0)
+ 200.0.ceil(-2).should.eql?(200)
+ -1.234.ceil(2).should.eql?(-1.23)
+ 5.123812.ceil(4).should.eql?(5.1239)
+ 10.00001.ceil(5).should.eql?(10.00001)
end
end
diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb
index 0cd290f4ad..e9adf2fd6a 100644
--- a/spec/ruby/core/float/comparison_spec.rb
+++ b/spec/ruby/core/float/comparison_spec.rb
@@ -29,10 +29,10 @@ describe "Float#<=>" do
end
it "returns nil when the given argument is not a Float" do
- (1.0 <=> "1").should be_nil
- (1.0 <=> "1".freeze).should be_nil
- (1.0 <=> :one).should be_nil
- (1.0 <=> true).should be_nil
+ (1.0 <=> "1").should == nil
+ (1.0 <=> "1".freeze).should == nil
+ (1.0 <=> :one).should == nil
+ (1.0 <=> true).should == nil
end
it "compares using #coerce when argument is not a Float" do
@@ -62,7 +62,7 @@ describe "Float#<=>" do
bad_coercible = klass.new
-> {
4.2 <=> bad_coercible
- }.should raise_error(TypeError, "coerce must return [x, y]")
+ }.should.raise(TypeError, "coerce must return [x, y]")
end
it "returns the correct result when one side is infinite" do
diff --git a/spec/ruby/core/float/constants_spec.rb b/spec/ruby/core/float/constants_spec.rb
index 497e0ae188..1b71ee8adf 100644
--- a/spec/ruby/core/float/constants_spec.rb
+++ b/spec/ruby/core/float/constants_spec.rb
@@ -50,6 +50,6 @@ describe "Float constant" do
end
it "NAN is 'not a number'" do
- Float::NAN.nan?.should be_true
+ Float::NAN.nan?.should == true
end
end
diff --git a/spec/ruby/core/float/denominator_spec.rb b/spec/ruby/core/float/denominator_spec.rb
index 6f4fcfcf23..85beaa98cd 100644
--- a/spec/ruby/core/float/denominator_spec.rb
+++ b/spec/ruby/core/float/denominator_spec.rb
@@ -12,7 +12,7 @@ describe "Float#denominator" do
it "returns an Integer" do
@numbers.each do |number|
- number.denominator.should be_kind_of(Integer)
+ number.denominator.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/float/divide_spec.rb b/spec/ruby/core/float/divide_spec.rb
index 72ab7527bd..68a2c550a7 100644
--- a/spec/ruby/core/float/divide_spec.rb
+++ b/spec/ruby/core/float/divide_spec.rb
@@ -16,25 +16,25 @@ describe "Float#/" do
end
it "returns +Infinity when dividing non-zero by zero of the same sign" do
- (1.0 / 0.0).should be_positive_infinity
- (-1.0 / -0.0).should be_positive_infinity
+ (1.0 / 0.0).should.infinite? == 1
+ (-1.0 / -0.0).should.infinite? == 1
end
it "returns -Infinity when dividing non-zero by zero of opposite sign" do
- (-1.0 / 0.0).should be_negative_infinity
- (1.0 / -0.0).should be_negative_infinity
+ (-1.0 / 0.0).should.infinite? == -1
+ (1.0 / -0.0).should.infinite? == -1
end
it "returns NaN when dividing zero by zero" do
- (0.0 / 0.0).should be_nan
- (-0.0 / 0.0).should be_nan
- (0.0 / -0.0).should be_nan
- (-0.0 / -0.0).should be_nan
+ (0.0 / 0.0).should.nan?
+ (-0.0 / 0.0).should.nan?
+ (0.0 / -0.0).should.nan?
+ (-0.0 / -0.0).should.nan?
end
it "raises a TypeError when given a non-Numeric" do
- -> { 13.0 / "10" }.should raise_error(TypeError)
- -> { 13.0 / :symbol }.should raise_error(TypeError)
+ -> { 13.0 / "10" }.should.raise(TypeError)
+ -> { 13.0 / :symbol }.should.raise(TypeError)
end
it "divides correctly by Rational numbers" do
diff --git a/spec/ruby/core/float/divmod_spec.rb b/spec/ruby/core/float/divmod_spec.rb
index dad45a9b89..7ed6cd3487 100644
--- a/spec/ruby/core/float/divmod_spec.rb
+++ b/spec/ruby/core/float/divmod_spec.rb
@@ -3,41 +3,41 @@ require_relative '../../spec_helper'
describe "Float#divmod" do
it "returns an [quotient, modulus] from dividing self by other" do
values = 3.14.divmod(2)
- values[0].should eql(1)
+ values[0].should.eql?(1)
values[1].should be_close(1.14, TOLERANCE)
values = 2.8284.divmod(3.1415)
- values[0].should eql(0)
+ values[0].should.eql?(0)
values[1].should be_close(2.8284, TOLERANCE)
values = -1.0.divmod(bignum_value)
- values[0].should eql(-1)
+ values[0].should.eql?(-1)
values[1].should be_close(18446744073709551616.0, TOLERANCE)
values = -1.0.divmod(1)
- values[0].should eql(-1)
- values[1].should eql(0.0)
+ values[0].should.eql?(-1)
+ values[1].should.eql?(0.0)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if self is NaN" do
- -> { nan_value.divmod(1) }.should raise_error(FloatDomainError)
+ -> { nan_value.divmod(1) }.should.raise(FloatDomainError)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if other is NaN" do
- -> { 1.0.divmod(nan_value) }.should raise_error(FloatDomainError)
+ -> { 1.0.divmod(nan_value) }.should.raise(FloatDomainError)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if self is Infinity" do
- -> { infinity_value.divmod(1) }.should raise_error(FloatDomainError)
+ -> { infinity_value.divmod(1) }.should.raise(FloatDomainError)
end
it "raises a ZeroDivisionError if other is zero" do
- -> { 1.0.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { 1.0.divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { 1.0.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { 1.0.divmod(0.0) }.should.raise(ZeroDivisionError)
end
# redmine #5276"
it "returns the correct [quotient, modulus] even for large quotient" do
- 0.59.divmod(7.761021455128987e-11).first.should eql(7602092113)
+ 0.59.divmod(7.761021455128987e-11).first.should.eql?(7602092113)
end
end
diff --git a/spec/ruby/core/float/dup_spec.rb b/spec/ruby/core/float/dup_spec.rb
index 294da8e2bc..b474e21325 100644
--- a/spec/ruby/core/float/dup_spec.rb
+++ b/spec/ruby/core/float/dup_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "Float#dup" do
it "returns self" do
float = 2.4
- float.dup.should equal(float)
+ float.dup.should.equal?(float)
end
end
diff --git a/spec/ruby/core/float/eql_spec.rb b/spec/ruby/core/float/eql_spec.rb
index 6b5f91db33..cf1ad8416f 100644
--- a/spec/ruby/core/float/eql_spec.rb
+++ b/spec/ruby/core/float/eql_spec.rb
@@ -2,15 +2,15 @@ require_relative '../../spec_helper'
describe "Float#eql?" do
it "returns true if other is a Float equal to self" do
- 0.0.eql?(0.0).should be_true
+ 0.0.eql?(0.0).should == true
end
it "returns false if other is a Float not equal to self" do
- 1.0.eql?(1.1).should be_false
+ 1.0.eql?(1.1).should == false
end
it "returns false if other is not a Float" do
- 1.0.eql?(1).should be_false
- 1.0.eql?(:one).should be_false
+ 1.0.eql?(1).should == false
+ 1.0.eql?(:one).should == false
end
end
diff --git a/spec/ruby/core/float/float_spec.rb b/spec/ruby/core/float/float_spec.rb
index 263ae82079..46b2eff372 100644
--- a/spec/ruby/core/float/float_spec.rb
+++ b/spec/ruby/core/float/float_spec.rb
@@ -8,12 +8,12 @@ describe "Float" do
it ".allocate raises a TypeError" do
-> do
Float.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
Float.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/float/floor_spec.rb b/spec/ruby/core/float/floor_spec.rb
index 8b492ef473..f77300eb04 100644
--- a/spec/ruby/core/float/floor_spec.rb
+++ b/spec/ruby/core/float/floor_spec.rb
@@ -2,25 +2,27 @@ require_relative '../../spec_helper'
require_relative '../integer/shared/integer_floor_precision'
describe "Float#floor" do
- context "with precision" do
+ context "with values equal to integers" do
it_behaves_like :integer_floor_precision, :Float
end
it "returns the largest Integer less than or equal to self" do
- -1.2.floor.should eql( -2)
- -1.0.floor.should eql( -1)
- 0.0.floor.should eql( 0 )
- 1.0.floor.should eql( 1 )
- 5.9.floor.should eql( 5 )
- -9223372036854775808.1.floor.should eql(-9223372036854775808)
- +9223372036854775808.1.floor.should eql(+9223372036854775808)
+ -1.2.floor.should.eql?( -2)
+ -1.0.floor.should.eql?( -1)
+ 0.0.floor.should.eql?( 0 )
+ 1.0.floor.should.eql?( 1 )
+ 5.9.floor.should.eql?( 5 )
+ -9223372036854775808.1.floor.should.eql?(-9223372036854775808)
+ +9223372036854775808.1.floor.should.eql?(+9223372036854775808)
end
it "returns the largest number less than or equal to self with an optionally given precision" do
- 2.1679.floor(0).should eql(2)
- 214.94.floor(-1).should eql(210)
- 7.0.floor(1).should eql(7.0)
- -1.234.floor(2).should eql(-1.24)
- 5.123812.floor(4).should eql(5.1238)
+ 2.1679.floor(0).should.eql?(2)
+ 214.94.floor(-1).should.eql?(210)
+ 7.0.floor(1).should.eql?(7.0)
+ 200.0.floor(-2).should.eql?(200)
+ -1.234.floor(2).should.eql?(-1.24)
+ 5.123812.floor(4).should.eql?(5.1238)
+ 10.00001.floor(5).should.eql?(10.00001)
end
end
diff --git a/spec/ruby/core/float/gt_spec.rb b/spec/ruby/core/float/gt_spec.rb
index 33078e07ce..5194796b46 100644
--- a/spec/ruby/core/float/gt_spec.rb
+++ b/spec/ruby/core/float/gt_spec.rb
@@ -11,8 +11,8 @@ describe "Float#>" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 > "4" }.should raise_error(ArgumentError)
- -> { 5.0 > mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 > "4" }.should.raise(ArgumentError)
+ -> { 5.0 > mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/gte_spec.rb b/spec/ruby/core/float/gte_spec.rb
index 44c0a81b43..4a62725d53 100644
--- a/spec/ruby/core/float/gte_spec.rb
+++ b/spec/ruby/core/float/gte_spec.rb
@@ -11,8 +11,8 @@ describe "Float#>=" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 >= "4" }.should raise_error(ArgumentError)
- -> { 5.0 >= mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 >= "4" }.should.raise(ArgumentError)
+ -> { 5.0 >= mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/lt_spec.rb b/spec/ruby/core/float/lt_spec.rb
index 94dcfc42f8..0f0e1752bd 100644
--- a/spec/ruby/core/float/lt_spec.rb
+++ b/spec/ruby/core/float/lt_spec.rb
@@ -11,8 +11,8 @@ describe "Float#<" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 < "4" }.should raise_error(ArgumentError)
- -> { 5.0 < mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 < "4" }.should.raise(ArgumentError)
+ -> { 5.0 < mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/lte_spec.rb b/spec/ruby/core/float/lte_spec.rb
index 7b5a86ee76..afb64ade09 100644
--- a/spec/ruby/core/float/lte_spec.rb
+++ b/spec/ruby/core/float/lte_spec.rb
@@ -12,8 +12,8 @@ describe "Float#<=" do
end
it "raises an ArgumentError when given a non-Numeric" do
- -> { 5.0 <= "4" }.should raise_error(ArgumentError)
- -> { 5.0 <= mock('x') }.should raise_error(ArgumentError)
+ -> { 5.0 <= "4" }.should.raise(ArgumentError)
+ -> { 5.0 <= mock('x') }.should.raise(ArgumentError)
end
it "returns false if one side is NaN" do
diff --git a/spec/ruby/core/float/multiply_spec.rb b/spec/ruby/core/float/multiply_spec.rb
index 2adb8796cd..edaaba7e61 100644
--- a/spec/ruby/core/float/multiply_spec.rb
+++ b/spec/ruby/core/float/multiply_spec.rb
@@ -11,7 +11,7 @@ describe "Float#*" do
end
it "raises a TypeError when given a non-Numeric" do
- -> { 13.0 * "10" }.should raise_error(TypeError)
- -> { 13.0 * :symbol }.should raise_error(TypeError)
+ -> { 13.0 * "10" }.should.raise(TypeError)
+ -> { 13.0 * :symbol }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/float/negative_spec.rb b/spec/ruby/core/float/negative_spec.rb
index 511d92ade6..484e636adb 100644
--- a/spec/ruby/core/float/negative_spec.rb
+++ b/spec/ruby/core/float/negative_spec.rb
@@ -3,31 +3,31 @@ require_relative '../../spec_helper'
describe "Float#negative?" do
describe "on positive numbers" do
it "returns false" do
- 0.1.negative?.should be_false
+ 0.1.negative?.should == false
end
end
describe "on zero" do
it "returns false" do
- 0.0.negative?.should be_false
+ 0.0.negative?.should == false
end
end
describe "on negative zero" do
it "returns false" do
- -0.0.negative?.should be_false
+ -0.0.negative?.should == false
end
end
describe "on negative numbers" do
it "returns true" do
- -0.1.negative?.should be_true
+ -0.1.negative?.should == true
end
end
describe "on NaN" do
it "returns false" do
- nan_value.negative?.should be_false
+ nan_value.negative?.should == false
end
end
end
diff --git a/spec/ruby/core/float/next_float_spec.rb b/spec/ruby/core/float/next_float_spec.rb
index 29e2d31146..59892be343 100644
--- a/spec/ruby/core/float/next_float_spec.rb
+++ b/spec/ruby/core/float/next_float_spec.rb
@@ -9,7 +9,7 @@ describe "Float#next_float" do
barely_positive.should < barely_positive.next_float
midpoint = barely_positive / 2
- [0.0, barely_positive].should include midpoint
+ [0.0, barely_positive].should.include? midpoint
end
it "returns Float::INFINITY for Float::INFINITY" do
diff --git a/spec/ruby/core/float/numerator_spec.rb b/spec/ruby/core/float/numerator_spec.rb
index 7832e8f056..53b32fdd3d 100644
--- a/spec/ruby/core/float/numerator_spec.rb
+++ b/spec/ruby/core/float/numerator_spec.rb
@@ -15,7 +15,7 @@ describe "Float#numerator" do
it "converts self to a Rational object then returns its numerator" do
@numbers.each do |number|
- number.infinite?.should be_nil
+ number.infinite?.should == nil
number.numerator.should == Rational(number).numerator
end
end
@@ -25,7 +25,7 @@ describe "Float#numerator" do
end
it "returns NaN for NaN" do
- nan_value.numerator.nan?.should be_true
+ nan_value.numerator.nan?.should == true
end
it "returns Infinity for Infinity" do
diff --git a/spec/ruby/core/float/positive_spec.rb b/spec/ruby/core/float/positive_spec.rb
index 575f92a720..aa87c03151 100644
--- a/spec/ruby/core/float/positive_spec.rb
+++ b/spec/ruby/core/float/positive_spec.rb
@@ -3,31 +3,31 @@ require_relative '../../spec_helper'
describe "Float#positive?" do
describe "on positive numbers" do
it "returns true" do
- 0.1.positive?.should be_true
+ 0.1.positive?.should == true
end
end
describe "on zero" do
it "returns false" do
- 0.0.positive?.should be_false
+ 0.0.positive?.should == false
end
end
describe "on negative zero" do
it "returns false" do
- -0.0.positive?.should be_false
+ -0.0.positive?.should == false
end
end
describe "on negative numbers" do
it "returns false" do
- -0.1.positive?.should be_false
+ -0.1.positive?.should == false
end
end
describe "on NaN" do
it "returns false" do
- nan_value.positive?.should be_false
+ nan_value.positive?.should == false
end
end
end
diff --git a/spec/ruby/core/float/prev_float_spec.rb b/spec/ruby/core/float/prev_float_spec.rb
index 5e50269da7..2d1f136254 100644
--- a/spec/ruby/core/float/prev_float_spec.rb
+++ b/spec/ruby/core/float/prev_float_spec.rb
@@ -9,7 +9,7 @@ describe "Float#prev_float" do
barely_negative.should > barely_negative.prev_float
midpoint = barely_negative / 2
- [0.0, barely_negative].should include midpoint
+ [0.0, barely_negative].should.include? midpoint
end
it "returns -Float::INFINITY for -Float::INFINITY" do
diff --git a/spec/ruby/core/float/rationalize_spec.rb b/spec/ruby/core/float/rationalize_spec.rb
index 0c5bef7ac4..fa8fb5c841 100644
--- a/spec/ruby/core/float/rationalize_spec.rb
+++ b/spec/ruby/core/float/rationalize_spec.rb
@@ -29,15 +29,15 @@ describe "Float#rationalize" do
end
it "raises a FloatDomainError for Infinity" do
- -> {infinity_value.rationalize}.should raise_error(FloatDomainError)
+ -> {infinity_value.rationalize}.should.raise(FloatDomainError)
end
it "raises a FloatDomainError for NaN" do
- -> { nan_value.rationalize }.should raise_error(FloatDomainError)
+ -> { nan_value.rationalize }.should.raise(FloatDomainError)
end
it "raises ArgumentError when passed more than one argument" do
- -> { 0.3.rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { 0.3.rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { 0.3.rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { 0.3.rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 7e8c792051..63c1d5689c 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -16,17 +16,17 @@ describe "Float#round" do
end
it "raises FloatDomainError for exceptional values" do
- -> { (+infinity_value).round }.should raise_error(FloatDomainError)
- -> { (-infinity_value).round }.should raise_error(FloatDomainError)
- -> { nan_value.round }.should raise_error(FloatDomainError)
+ -> { (+infinity_value).round }.should.raise(FloatDomainError)
+ -> { (-infinity_value).round }.should.raise(FloatDomainError)
+ -> { nan_value.round }.should.raise(FloatDomainError)
end
it "rounds self to an optionally given precision" do
- 5.5.round(0).should eql(6)
- 5.7.round(1).should eql(5.7)
+ 5.5.round(0).should.eql?(6)
+ 5.7.round(1).should.eql?(5.7)
1.2345678.round(2).should == 1.23
- 123456.78.round(-2).should eql(123500) # rounded up
- -123456.78.round(-2).should eql(-123500)
+ 123456.78.round(-2).should.eql?(123500) # rounded up
+ -123456.78.round(-2).should.eql?(-123500)
12.345678.round(3.999).should == 12.346
end
@@ -36,36 +36,37 @@ describe "Float#round" do
end
it "returns zero when passed a negative argument with magnitude greater than magnitude of the whole number portion of the Float" do
- 0.8346268.round(-1).should eql(0)
+ 0.8346268.round(-1).should.eql?(0)
end
it "raises a TypeError when its argument can not be converted to an Integer" do
- -> { 1.0.round("4") }.should raise_error(TypeError)
- -> { 1.0.round(nil) }.should raise_error(TypeError)
+ -> { 1.0.round("4") }.should.raise(TypeError)
+ -> { 1.0.round(nil) }.should.raise(TypeError)
end
it "raises FloatDomainError for exceptional values when passed a non-positive precision" do
- -> { Float::INFINITY.round( 0) }.should raise_error(FloatDomainError)
- -> { Float::INFINITY.round(-2) }.should raise_error(FloatDomainError)
- -> { (-Float::INFINITY).round( 0) }.should raise_error(FloatDomainError)
- -> { (-Float::INFINITY).round(-2) }.should raise_error(FloatDomainError)
+ -> { Float::INFINITY.round( 0) }.should.raise(FloatDomainError)
+ -> { Float::INFINITY.round(-2) }.should.raise(FloatDomainError)
+ -> { (-Float::INFINITY).round( 0) }.should.raise(FloatDomainError)
+ -> { (-Float::INFINITY).round(-2) }.should.raise(FloatDomainError)
end
it "raises RangeError for NAN when passed a non-positive precision" do
- -> { Float::NAN.round(0) }.should raise_error(RangeError)
- -> { Float::NAN.round(-2) }.should raise_error(RangeError)
+ -> { Float::NAN.round(0) }.should.raise(RangeError)
+ -> { Float::NAN.round(-2) }.should.raise(RangeError)
end
it "returns self for exceptional values when passed a non-negative precision" do
Float::INFINITY.round(2).should == Float::INFINITY
(-Float::INFINITY).round(2).should == -Float::INFINITY
- Float::NAN.round(2).should be_nan
+ Float::NAN.round(2).should.nan?
end
# redmine:5227
it "works for corner cases" do
- 42.0.round(308).should eql(42.0)
- 1.0e307.round(2).should eql(1.0e307)
+ 42.0.round(308).should.eql?(42.0)
+ 1.0e307.round(2).should.eql?(1.0e307)
+ 120.0.round(-1).should.eql?(120)
end
# redmine:5271
@@ -78,114 +79,112 @@ describe "Float#round" do
end
it "returns big values rounded to nearest" do
- +2.5e20.round(-20).should eql( +3 * 10 ** 20 )
- -2.5e20.round(-20).should eql( -3 * 10 ** 20 )
+ +2.5e20.round(-20).should.eql?( +3 * 10 ** 20 )
+ -2.5e20.round(-20).should.eql?( -3 * 10 ** 20 )
end
# redmine #5272
it "returns rounded values for big values" do
- +2.4e20.round(-20).should eql( +2 * 10 ** 20 )
- -2.4e20.round(-20).should eql( -2 * 10 ** 20 )
- +2.5e200.round(-200).should eql( +3 * 10 ** 200 )
- +2.4e200.round(-200).should eql( +2 * 10 ** 200 )
- -2.5e200.round(-200).should eql( -3 * 10 ** 200 )
- -2.4e200.round(-200).should eql( -2 * 10 ** 200 )
+ +2.4e20.round(-20).should.eql?( +2 * 10 ** 20 )
+ -2.4e20.round(-20).should.eql?( -2 * 10 ** 20 )
+ +2.5e200.round(-200).should.eql?( +3 * 10 ** 200 )
+ +2.4e200.round(-200).should.eql?( +2 * 10 ** 200 )
+ -2.5e200.round(-200).should.eql?( -3 * 10 ** 200 )
+ -2.4e200.round(-200).should.eql?( -2 * 10 ** 200 )
end
it "returns different rounded values depending on the half option" do
- 2.5.round(half: nil).should eql(3)
- 2.5.round(half: :up).should eql(3)
- 2.5.round(half: :down).should eql(2)
- 2.5.round(half: :even).should eql(2)
- 3.5.round(half: nil).should eql(4)
- 3.5.round(half: :up).should eql(4)
- 3.5.round(half: :down).should eql(3)
- 3.5.round(half: :even).should eql(4)
- (-2.5).round(half: nil).should eql(-3)
- (-2.5).round(half: :up).should eql(-3)
- (-2.5).round(half: :down).should eql(-2)
- (-2.5).round(half: :even).should eql(-2)
+ 2.5.round(half: nil).should.eql?(3)
+ 2.5.round(half: :up).should.eql?(3)
+ 2.5.round(half: :down).should.eql?(2)
+ 2.5.round(half: :even).should.eql?(2)
+ 3.5.round(half: nil).should.eql?(4)
+ 3.5.round(half: :up).should.eql?(4)
+ 3.5.round(half: :down).should.eql?(3)
+ 3.5.round(half: :even).should.eql?(4)
+ (-2.5).round(half: nil).should.eql?(-3)
+ (-2.5).round(half: :up).should.eql?(-3)
+ (-2.5).round(half: :down).should.eql?(-2)
+ (-2.5).round(half: :even).should.eql?(-2)
end
it "rounds self to an optionally given precision with a half option" do
- 5.55.round(1, half: nil).should eql(5.6)
- 5.55.round(1, half: :up).should eql(5.6)
- 5.55.round(1, half: :down).should eql(5.5)
- 5.55.round(1, half: :even).should eql(5.6)
- -5.55.round(1, half: nil).should eql(-5.6)
- -5.55.round(1, half: :up).should eql(-5.6)
- -5.55.round(1, half: :down).should eql(-5.5)
- -5.55.round(1, half: :even).should eql(-5.6)
+ 5.55.round(1, half: nil).should.eql?(5.6)
+ 5.55.round(1, half: :up).should.eql?(5.6)
+ 5.55.round(1, half: :down).should.eql?(5.5)
+ 5.55.round(1, half: :even).should.eql?(5.6)
+ -5.55.round(1, half: nil).should.eql?(-5.6)
+ -5.55.round(1, half: :up).should.eql?(-5.6)
+ -5.55.round(1, half: :down).should.eql?(-5.5)
+ -5.55.round(1, half: :even).should.eql?(-5.6)
end
it "preserves cases where neighbouring floating pointer number increase the decimal places" do
- 4.8100000000000005.round(5, half: nil).should eql(4.81)
- 4.8100000000000005.round(5, half: :up).should eql(4.81)
- 4.8100000000000005.round(5, half: :down).should eql(4.81)
- 4.8100000000000005.round(5, half: :even).should eql(4.81)
- -4.8100000000000005.round(5, half: nil).should eql(-4.81)
- -4.8100000000000005.round(5, half: :up).should eql(-4.81)
- -4.8100000000000005.round(5, half: :down).should eql(-4.81)
- -4.8100000000000005.round(5, half: :even).should eql(-4.81)
- 4.81.round(5, half: nil).should eql(4.81)
- 4.81.round(5, half: :up).should eql(4.81)
- 4.81.round(5, half: :down).should eql(4.81)
- 4.81.round(5, half: :even).should eql(4.81)
- -4.81.round(5, half: nil).should eql(-4.81)
- -4.81.round(5, half: :up).should eql(-4.81)
- -4.81.round(5, half: :down).should eql(-4.81)
- -4.81.round(5, half: :even).should eql(-4.81)
- 4.809999999999999.round(5, half: nil).should eql(4.81)
- 4.809999999999999.round(5, half: :up).should eql(4.81)
- 4.809999999999999.round(5, half: :down).should eql(4.81)
- 4.809999999999999.round(5, half: :even).should eql(4.81)
- -4.809999999999999.round(5, half: nil).should eql(-4.81)
- -4.809999999999999.round(5, half: :up).should eql(-4.81)
- -4.809999999999999.round(5, half: :down).should eql(-4.81)
- -4.809999999999999.round(5, half: :even).should eql(-4.81)
- end
-
- ruby_bug "#19318", ""..."3.3" do
- # These numbers are neighbouring floating point numbers round a
- # precise value. They test that the rounding modes work correctly
- # round that value and precision is not lost which might cause
- # incorrect results.
- it "does not lose precision during the rounding process" do
- 767573.1875850001.round(5, half: nil).should eql(767573.18759)
- 767573.1875850001.round(5, half: :up).should eql(767573.18759)
- 767573.1875850001.round(5, half: :down).should eql(767573.18759)
- 767573.1875850001.round(5, half: :even).should eql(767573.18759)
- -767573.1875850001.round(5, half: nil).should eql(-767573.18759)
- -767573.1875850001.round(5, half: :up).should eql(-767573.18759)
- -767573.1875850001.round(5, half: :down).should eql(-767573.18759)
- -767573.1875850001.round(5, half: :even).should eql(-767573.18759)
- 767573.187585.round(5, half: nil).should eql(767573.18759)
- 767573.187585.round(5, half: :up).should eql(767573.18759)
- 767573.187585.round(5, half: :down).should eql(767573.18758)
- 767573.187585.round(5, half: :even).should eql(767573.18758)
- -767573.187585.round(5, half: nil).should eql(-767573.18759)
- -767573.187585.round(5, half: :up).should eql(-767573.18759)
- -767573.187585.round(5, half: :down).should eql(-767573.18758)
- -767573.187585.round(5, half: :even).should eql(-767573.18758)
- 767573.1875849998.round(5, half: nil).should eql(767573.18758)
- 767573.1875849998.round(5, half: :up).should eql(767573.18758)
- 767573.1875849998.round(5, half: :down).should eql(767573.18758)
- 767573.1875849998.round(5, half: :even).should eql(767573.18758)
- -767573.1875849998.round(5, half: nil).should eql(-767573.18758)
- -767573.1875849998.round(5, half: :up).should eql(-767573.18758)
- -767573.1875849998.round(5, half: :down).should eql(-767573.18758)
- -767573.1875849998.round(5, half: :even).should eql(-767573.18758)
- end
+ 4.8100000000000005.round(5, half: nil).should.eql?(4.81)
+ 4.8100000000000005.round(5, half: :up).should.eql?(4.81)
+ 4.8100000000000005.round(5, half: :down).should.eql?(4.81)
+ 4.8100000000000005.round(5, half: :even).should.eql?(4.81)
+ -4.8100000000000005.round(5, half: nil).should.eql?(-4.81)
+ -4.8100000000000005.round(5, half: :up).should.eql?(-4.81)
+ -4.8100000000000005.round(5, half: :down).should.eql?(-4.81)
+ -4.8100000000000005.round(5, half: :even).should.eql?(-4.81)
+ 4.81.round(5, half: nil).should.eql?(4.81)
+ 4.81.round(5, half: :up).should.eql?(4.81)
+ 4.81.round(5, half: :down).should.eql?(4.81)
+ 4.81.round(5, half: :even).should.eql?(4.81)
+ -4.81.round(5, half: nil).should.eql?(-4.81)
+ -4.81.round(5, half: :up).should.eql?(-4.81)
+ -4.81.round(5, half: :down).should.eql?(-4.81)
+ -4.81.round(5, half: :even).should.eql?(-4.81)
+ 4.809999999999999.round(5, half: nil).should.eql?(4.81)
+ 4.809999999999999.round(5, half: :up).should.eql?(4.81)
+ 4.809999999999999.round(5, half: :down).should.eql?(4.81)
+ 4.809999999999999.round(5, half: :even).should.eql?(4.81)
+ -4.809999999999999.round(5, half: nil).should.eql?(-4.81)
+ -4.809999999999999.round(5, half: :up).should.eql?(-4.81)
+ -4.809999999999999.round(5, half: :down).should.eql?(-4.81)
+ -4.809999999999999.round(5, half: :even).should.eql?(-4.81)
+ end
+
+ # These numbers are neighbouring floating point numbers round a
+ # precise value. They test that the rounding modes work correctly
+ # round that value and precision is not lost which might cause
+ # incorrect results.
+ it "does not lose precision during the rounding process" do
+ 767573.1875850001.round(5, half: nil).should.eql?(767573.18759)
+ 767573.1875850001.round(5, half: :up).should.eql?(767573.18759)
+ 767573.1875850001.round(5, half: :down).should.eql?(767573.18759)
+ 767573.1875850001.round(5, half: :even).should.eql?(767573.18759)
+ -767573.1875850001.round(5, half: nil).should.eql?(-767573.18759)
+ -767573.1875850001.round(5, half: :up).should.eql?(-767573.18759)
+ -767573.1875850001.round(5, half: :down).should.eql?(-767573.18759)
+ -767573.1875850001.round(5, half: :even).should.eql?(-767573.18759)
+ 767573.187585.round(5, half: nil).should.eql?(767573.18759)
+ 767573.187585.round(5, half: :up).should.eql?(767573.18759)
+ 767573.187585.round(5, half: :down).should.eql?(767573.18758)
+ 767573.187585.round(5, half: :even).should.eql?(767573.18758)
+ -767573.187585.round(5, half: nil).should.eql?(-767573.18759)
+ -767573.187585.round(5, half: :up).should.eql?(-767573.18759)
+ -767573.187585.round(5, half: :down).should.eql?(-767573.18758)
+ -767573.187585.round(5, half: :even).should.eql?(-767573.18758)
+ 767573.1875849998.round(5, half: nil).should.eql?(767573.18758)
+ 767573.1875849998.round(5, half: :up).should.eql?(767573.18758)
+ 767573.1875849998.round(5, half: :down).should.eql?(767573.18758)
+ 767573.1875849998.round(5, half: :even).should.eql?(767573.18758)
+ -767573.1875849998.round(5, half: nil).should.eql?(-767573.18758)
+ -767573.1875849998.round(5, half: :up).should.eql?(-767573.18758)
+ -767573.1875849998.round(5, half: :down).should.eql?(-767573.18758)
+ -767573.1875849998.round(5, half: :even).should.eql?(-767573.18758)
end
it "raises FloatDomainError for exceptional values with a half option" do
- -> { (+infinity_value).round(half: :up) }.should raise_error(FloatDomainError)
- -> { (-infinity_value).round(half: :down) }.should raise_error(FloatDomainError)
- -> { nan_value.round(half: :even) }.should raise_error(FloatDomainError)
+ -> { (+infinity_value).round(half: :up) }.should.raise(FloatDomainError)
+ -> { (-infinity_value).round(half: :down) }.should.raise(FloatDomainError)
+ -> { nan_value.round(half: :even) }.should.raise(FloatDomainError)
end
it "raise for a non-existent round mode" do
- -> { 14.2.round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
+ -> { 14.2.round(half: :nonsense) }.should.raise(ArgumentError, "invalid rounding mode: nonsense")
end
describe "when 0.0 is given" do
@@ -197,7 +196,13 @@ describe "Float#round" do
it "returns 0 for 0 or undefined ndigits" do
(0.0).round.should == 0
(-0.0).round(0).should == 0
- (0.0).round(half: :up) == 0
+ (0.0).round(half: :up).should == 0
+ end
+
+ it "returns 0 for negative ndigits" do
+ (0.0).round(-1).should == 0
+ (-0.0).round(-1).should == 0
+ (0.0).round(-1, half: :up).should == 0
end
end
end
diff --git a/spec/ruby/core/float/shared/abs.rb b/spec/ruby/core/float/shared/abs.rb
index 607983322d..ab21480e24 100644
--- a/spec/ruby/core/float/shared/abs.rb
+++ b/spec/ruby/core/float/shared/abs.rb
@@ -16,6 +16,6 @@ describe :float_abs, shared: true do
end
it "returns NaN if NaN" do
- nan_value.send(@method).nan?.should be_true
+ nan_value.send(@method).nan?.should == true
end
end
diff --git a/spec/ruby/core/float/shared/arg.rb b/spec/ruby/core/float/shared/arg.rb
index 136cf19ec8..de0024313d 100644
--- a/spec/ruby/core/float/shared/arg.rb
+++ b/spec/ruby/core/float/shared/arg.rb
@@ -1,12 +1,12 @@
describe :float_arg, shared: true do
it "returns NaN if NaN" do
f = nan_value
- f.send(@method).nan?.should be_true
+ f.send(@method).nan?.should == true
end
it "returns self if NaN" do
f = nan_value
- f.send(@method).should equal(f)
+ f.send(@method).should.equal?(f)
end
it "returns 0 if positive" do
diff --git a/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb b/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb
index eec92d858f..bd3bf9019f 100644
--- a/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb
+++ b/spec/ruby/core/float/shared/arithmetic_exception_in_coerce.rb
@@ -6,6 +6,6 @@ describe :float_arithmetic_exception_in_coerce, shared: true do
b.should_receive(:coerce).and_raise(FloatSpecs::CoerceError)
# e.g. 1.0 > b
- -> { 1.0.send(@method, b) }.should raise_error(FloatSpecs::CoerceError)
+ -> { 1.0.send(@method, b) }.should.raise(FloatSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb b/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb
index 3e2c1e28dd..eec5d8daf9 100644
--- a/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb
+++ b/spec/ruby/core/float/shared/comparison_exception_in_coerce.rb
@@ -6,6 +6,6 @@ describe :float_comparison_exception_in_coerce, shared: true do
b.should_receive(:coerce).and_raise(FloatSpecs::CoerceError)
# e.g. 1.0 > b
- -> { 1.0.send(@method, b) }.should raise_error(FloatSpecs::CoerceError)
+ -> { 1.0.send(@method, b) }.should.raise(FloatSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/float/shared/modulo.rb b/spec/ruby/core/float/shared/modulo.rb
index 6700bd4f4e..1efee1476d 100644
--- a/spec/ruby/core/float/shared/modulo.rb
+++ b/spec/ruby/core/float/shared/modulo.rb
@@ -16,13 +16,13 @@ describe :float_modulo, shared: true do
end
it "returns NaN when called on NaN or Infinities" do
- Float::NAN.send(@method, 42).should be_nan
- Float::INFINITY.send(@method, 42).should be_nan
- (-Float::INFINITY).send(@method, 42).should be_nan
+ Float::NAN.send(@method, 42).should.nan?
+ Float::INFINITY.send(@method, 42).should.nan?
+ (-Float::INFINITY).send(@method, 42).should.nan?
end
it "returns NaN when modulus is NaN" do
- 4.2.send(@method, Float::NAN).should be_nan
+ 4.2.send(@method, Float::NAN).should.nan?
end
it "returns -0.0 when called on -0.0 with a non zero modulus" do
@@ -42,7 +42,7 @@ describe :float_modulo, shared: true do
end
it "raises a ZeroDivisionError if other is zero" do
- -> { 1.0.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { 1.0.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
+ -> { 1.0.send(@method, 0) }.should.raise(ZeroDivisionError)
+ -> { 1.0.send(@method, 0.0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/float/shared/quo.rb b/spec/ruby/core/float/shared/quo.rb
index 0c90171b87..930187aaf7 100644
--- a/spec/ruby/core/float/shared/quo.rb
+++ b/spec/ruby/core/float/shared/quo.rb
@@ -12,8 +12,8 @@ describe :float_quo, shared: true do
end
it "returns NaN when the argument is NaN" do
- -1819.999999.send(@method, nan_value).nan?.should be_true
- 11109.1981271.send(@method, nan_value).nan?.should be_true
+ -1819.999999.send(@method, nan_value).nan?.should == true
+ 11109.1981271.send(@method, nan_value).nan?.should == true
end
it "returns Infinity when the argument is 0.0" do
@@ -50,10 +50,10 @@ describe :float_quo, shared: true do
end
it "raises a TypeError when argument isn't numeric" do
- -> { 27292.2.send(@method, mock('non-numeric')) }.should raise_error(TypeError)
+ -> { 27292.2.send(@method, mock('non-numeric')) }.should.raise(TypeError)
end
it "raises an ArgumentError when passed multiple arguments" do
- -> { 272.221.send(@method, 6,0.2) }.should raise_error(ArgumentError)
+ -> { 272.221.send(@method, 6,0.2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/float/shared/to_i.rb b/spec/ruby/core/float/shared/to_i.rb
index 33b32ca533..1e6f941467 100644
--- a/spec/ruby/core/float/shared/to_i.rb
+++ b/spec/ruby/core/float/shared/to_i.rb
@@ -1,14 +1,14 @@
describe :float_to_i, shared: true do
it "returns self truncated to an Integer" do
- 899.2.send(@method).should eql(899)
- -1.122256e-45.send(@method).should eql(0)
- 5_213_451.9201.send(@method).should eql(5213451)
- 1.233450999123389e+12.send(@method).should eql(1233450999123)
- -9223372036854775808.1.send(@method).should eql(-9223372036854775808)
- 9223372036854775808.1.send(@method).should eql(9223372036854775808)
+ 899.2.send(@method).should.eql?(899)
+ -1.122256e-45.send(@method).should.eql?(0)
+ 5_213_451.9201.send(@method).should.eql?(5213451)
+ 1.233450999123389e+12.send(@method).should.eql?(1233450999123)
+ -9223372036854775808.1.send(@method).should.eql?(-9223372036854775808)
+ 9223372036854775808.1.send(@method).should.eql?(9223372036854775808)
end
it "raises a FloatDomainError for NaN" do
- -> { nan_value.send(@method) }.should raise_error(FloatDomainError)
+ -> { nan_value.send(@method) }.should.raise(FloatDomainError)
end
end
diff --git a/spec/ruby/core/float/shared/to_s.rb b/spec/ruby/core/float/shared/to_s.rb
index 0925efc0f7..81ffdd9e81 100644
--- a/spec/ruby/core/float/shared/to_s.rb
+++ b/spec/ruby/core/float/shared/to_s.rb
@@ -297,12 +297,12 @@ describe :float_to_s, shared: true do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- 1.23.send(@method).encoding.should equal(Encoding::US_ASCII)
+ 1.23.send(@method).encoding.should.equal?(Encoding::US_ASCII)
end
it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
Encoding.default_internal = Encoding::IBM437
- 5.47.send(@method).encoding.should equal(Encoding::US_ASCII)
+ 5.47.send(@method).encoding.should.equal?(Encoding::US_ASCII)
end
end
end
diff --git a/spec/ruby/core/float/truncate_spec.rb b/spec/ruby/core/float/truncate_spec.rb
index 2c80145f9f..1750e3fdbc 100644
--- a/spec/ruby/core/float/truncate_spec.rb
+++ b/spec/ruby/core/float/truncate_spec.rb
@@ -5,10 +5,10 @@ describe "Float#truncate" do
it_behaves_like :float_to_i, :truncate
it "returns self truncated to an optionally given precision" do
- 2.1679.truncate(0).should eql(2)
- 7.1.truncate(1).should eql(7.1)
- 214.94.truncate(-1).should eql(210)
- -1.234.truncate(2).should eql(-1.23)
- 5.123812.truncate(4).should eql(5.1238)
+ 2.1679.truncate(0).should.eql?(2)
+ 7.1.truncate(1).should.eql?(7.1)
+ 214.94.truncate(-1).should.eql?(210)
+ -1.234.truncate(2).should.eql?(-1.23)
+ 5.123812.truncate(4).should.eql?(5.1238)
end
end
diff --git a/spec/ruby/core/float/uplus_spec.rb b/spec/ruby/core/float/uplus_spec.rb
index 936123558c..b979b2717a 100644
--- a/spec/ruby/core/float/uplus_spec.rb
+++ b/spec/ruby/core/float/uplus_spec.rb
@@ -4,6 +4,6 @@ describe "Float#+@" do
it "returns the same value with same sign (twos complement)" do
34.56.send(:+@).should == 34.56
-34.56.send(:+@).should == -34.56
- 0.0.send(:+@).should eql(0.0)
+ 0.0.send(:+@).should.eql?(0.0)
end
end
diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb
new file mode 100644
index 0000000000..57160f122c
--- /dev/null
+++ b/spec/ruby/core/gc/config_spec.rb
@@ -0,0 +1,97 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "GC.config" do
+ context "without arguments" do
+ it "returns a hash of current settings" do
+ GC.config.should.is_a?(Hash)
+ end
+
+ it "includes the name of currently loaded GC implementation as a global key" do
+ GC.config.should.include?(:implementation)
+ GC.config[:implementation].should.is_a?(String)
+ end
+ end
+
+ context "with a hash of options" do
+ it "allows to set GC implementation's options, returning the new config" do
+ config = GC.config({})
+ # Try to find a boolean setting to reliably test changing it.
+ key, _value = config.find { |_k, v| v == true }
+ skip unless key
+
+ GC.config(key => false).should == config.merge(key => false)
+ GC.config[key].should == false
+ GC.config(key => true).should == config
+ GC.config[key].should == true
+ ensure
+ GC.config(config.except(:implementation))
+ end
+
+ it "does not change settings that aren't present in the hash" do
+ previous = GC.config
+ GC.config({})
+ GC.config.should == previous
+ end
+
+ it "ignores unknown keys" do
+ previous = GC.config
+ GC.config(foo: "bar")
+ GC.config.should == previous
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "returns the same as GC.config but without the :implementation key" do
+ previous = GC.config
+ GC.config({}).should == previous.except(:implementation)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "returns the same as GC.config, including the :implementation key" do
+ previous = GC.config
+ GC.config({}).should == previous
+ end
+ end
+
+ it "raises an ArgumentError if options include global keys" do
+ -> { GC.config(implementation: "default") }.should.raise(ArgumentError, 'Attempting to set read-only key "Implementation"')
+ end
+ end
+
+ context "with a non-hash argument" do
+ it "returns current settings if argument is nil" do
+ GC.config(nil).should == GC.config
+ end
+
+ it "raises ArgumentError for all other arguments" do
+ -> { GC.config([]) }.should.raise(ArgumentError)
+ -> { GC.config("default") }.should.raise(ArgumentError)
+ -> { GC.config(1) }.should.raise(ArgumentError)
+ end
+ end
+
+ guard -> { PlatformGuard.standard? && GC.config[:implementation] == "default" } do
+ context "with default GC implementation on MRI" do
+ before do
+ @default_config = GC.config({})
+ end
+
+ after do
+ GC.config(@default_config.except(:implementation))
+ end
+
+ it "includes :rgengc_allow_full_mark option, true by default" do
+ GC.config.should.include?(:rgengc_allow_full_mark)
+ GC.config[:rgengc_allow_full_mark].should == true
+ end
+
+ it "allows to set :rgengc_allow_full_mark" do
+ # This key maps truthy and falsey values to true and false.
+ GC.config(rgengc_allow_full_mark: nil).should == @default_config.merge(rgengc_allow_full_mark: false)
+ GC.config(rgengc_allow_full_mark: 1.23).should == @default_config.merge(rgengc_allow_full_mark: true)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/gc/count_spec.rb b/spec/ruby/core/gc/count_spec.rb
index af2fbbe713..fe20c4ed2b 100644
--- a/spec/ruby/core/gc/count_spec.rb
+++ b/spec/ruby/core/gc/count_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "GC.count" do
it "returns an integer" do
- GC.count.should be_kind_of(Integer)
+ GC.count.should.is_a?(Integer)
end
it "increases as collections are run" do
diff --git a/spec/ruby/core/gc/profiler/enabled_spec.rb b/spec/ruby/core/gc/profiler/enabled_spec.rb
index 23677be555..cfcd0951f0 100644
--- a/spec/ruby/core/gc/profiler/enabled_spec.rb
+++ b/spec/ruby/core/gc/profiler/enabled_spec.rb
@@ -11,11 +11,11 @@ describe "GC::Profiler.enabled?" do
it "reports as enabled when enabled" do
GC::Profiler.enable
- GC::Profiler.enabled?.should be_true
+ GC::Profiler.enabled?.should == true
end
it "reports as disabled when disabled" do
GC::Profiler.disable
- GC::Profiler.enabled?.should be_false
+ GC::Profiler.enabled?.should == false
end
end
diff --git a/spec/ruby/core/gc/profiler/result_spec.rb b/spec/ruby/core/gc/profiler/result_spec.rb
index 2ab46a8371..e888f975dc 100644
--- a/spec/ruby/core/gc/profiler/result_spec.rb
+++ b/spec/ruby/core/gc/profiler/result_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "GC::Profiler.result" do
it "returns a string" do
- GC::Profiler.result.should be_kind_of(String)
+ GC::Profiler.result.should.is_a?(String)
end
end
diff --git a/spec/ruby/core/gc/profiler/total_time_spec.rb b/spec/ruby/core/gc/profiler/total_time_spec.rb
index 7709f168dd..a351e922af 100644
--- a/spec/ruby/core/gc/profiler/total_time_spec.rb
+++ b/spec/ruby/core/gc/profiler/total_time_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "GC::Profiler.total_time" do
it "returns an float" do
- GC::Profiler.total_time.should be_kind_of(Float)
+ GC::Profiler.total_time.should.is_a?(Float)
end
end
diff --git a/spec/ruby/core/gc/stat_spec.rb b/spec/ruby/core/gc/stat_spec.rb
index 3b43b28a92..6e4800b3e3 100644
--- a/spec/ruby/core/gc/stat_spec.rb
+++ b/spec/ruby/core/gc/stat_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "GC.stat" do
it "returns hash of values" do
stat = GC.stat
- stat.should be_kind_of(Hash)
+ stat.should.is_a?(Hash)
stat.keys.should.include?(:count)
end
@@ -11,18 +11,18 @@ describe "GC.stat" do
hash = { count: "hello", __other__: "world" }
stat = GC.stat(hash)
- stat.should be_kind_of(Hash)
- stat.should equal hash
- stat[:count].should be_kind_of(Integer)
+ stat.should.is_a?(Hash)
+ stat.should.equal? hash
+ stat[:count].should.is_a?(Integer)
stat[:__other__].should == "world"
end
it "the values are all Integer since rb_gc_stat() returns size_t" do
- GC.stat.values.each { |value| value.should be_kind_of(Integer) }
+ GC.stat.values.each { |value| value.should.is_a?(Integer) }
end
it "can return a single value" do
- GC.stat(:count).should be_kind_of(Integer)
+ GC.stat(:count).should.is_a?(Integer)
end
it "increases count after GC is run" do
@@ -38,25 +38,25 @@ describe "GC.stat" do
end
it "provides some number for count" do
- GC.stat(:count).should be_kind_of(Integer)
- GC.stat[:count].should be_kind_of(Integer)
+ GC.stat(:count).should.is_a?(Integer)
+ GC.stat[:count].should.is_a?(Integer)
end
it "provides some number for heap_free_slots" do
- GC.stat(:heap_free_slots).should be_kind_of(Integer)
- GC.stat[:heap_free_slots].should be_kind_of(Integer)
+ GC.stat(:heap_free_slots).should.is_a?(Integer)
+ GC.stat[:heap_free_slots].should.is_a?(Integer)
end
it "provides some number for total_allocated_objects" do
- GC.stat(:total_allocated_objects).should be_kind_of(Integer)
- GC.stat[:total_allocated_objects].should be_kind_of(Integer)
+ GC.stat(:total_allocated_objects).should.is_a?(Integer)
+ GC.stat[:total_allocated_objects].should.is_a?(Integer)
end
it "raises an error if argument is not nil, a symbol, or a hash" do
- -> { GC.stat(7) }.should raise_error(TypeError, "non-hash or symbol given")
+ -> { GC.stat(7) }.should.raise(TypeError, "non-hash or symbol given")
end
it "raises an error if an unknown key is given" do
- -> { GC.stat(:foo) }.should raise_error(ArgumentError, "unknown key: foo")
+ -> { GC.stat(:foo) }.should.raise(ArgumentError, "unknown key: foo")
end
end
diff --git a/spec/ruby/core/gc/stress_spec.rb b/spec/ruby/core/gc/stress_spec.rb
index ca62c0cb4e..227a795e7f 100644
--- a/spec/ruby/core/gc/stress_spec.rb
+++ b/spec/ruby/core/gc/stress_spec.rb
@@ -7,11 +7,11 @@ describe "GC.stress" do
end
it "returns current status of GC stress mode" do
- GC.stress.should be_false
+ GC.stress.should == false
GC.stress = true
- GC.stress.should be_true
+ GC.stress.should == true
GC.stress = false
- GC.stress.should be_false
+ GC.stress.should == false
end
end
@@ -22,6 +22,6 @@ describe "GC.stress=" do
it "sets the stress mode" do
GC.stress = true
- GC.stress.should be_true
+ GC.stress.should == true
end
end
diff --git a/spec/ruby/core/gc/total_time_spec.rb b/spec/ruby/core/gc/total_time_spec.rb
index a8430fbe9a..f10e0ad742 100644
--- a/spec/ruby/core/gc/total_time_spec.rb
+++ b/spec/ruby/core/gc/total_time_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "GC.total_time" do
it "returns an Integer" do
- GC.total_time.should be_kind_of(Integer)
+ GC.total_time.should.is_a?(Integer)
end
it "increases as collections are run" do
diff --git a/spec/ruby/core/hash/allocate_spec.rb b/spec/ruby/core/hash/allocate_spec.rb
index 93420de866..a92accc161 100644
--- a/spec/ruby/core/hash/allocate_spec.rb
+++ b/spec/ruby/core/hash/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Hash.allocate" do
it "returns an instance of Hash" do
hsh = Hash.allocate
- hsh.should be_an_instance_of(Hash)
+ hsh.should.instance_of?(Hash)
end
it "returns a fully-formed instance of Hash" do
diff --git a/spec/ruby/core/hash/assoc_spec.rb b/spec/ruby/core/hash/assoc_spec.rb
index 62b2a11b30..51af51a20f 100644
--- a/spec/ruby/core/hash/assoc_spec.rb
+++ b/spec/ruby/core/hash/assoc_spec.rb
@@ -6,7 +6,7 @@ describe "Hash#assoc" do
end
it "returns an Array if the argument is == to a key of the Hash" do
- @h.assoc(:apple).should be_an_instance_of(Array)
+ @h.assoc(:apple).should.instance_of?(Array)
end
it "returns a 2-element Array if the argument is == to a key of the Hash" do
@@ -40,11 +40,11 @@ describe "Hash#assoc" do
end
it "returns nil if the argument is not a key of the Hash" do
- @h.assoc(:green).should be_nil
+ @h.assoc(:green).should == nil
end
it "returns nil if the argument is not a key of the Hash even when there is a default" do
- Hash.new(42).merge!( foo: :bar ).assoc(42).should be_nil
- Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).assoc(42).should be_nil
+ Hash.new(42).merge!( foo: :bar ).assoc(42).should == nil
+ Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).assoc(42).should == nil
end
end
diff --git a/spec/ruby/core/hash/clear_spec.rb b/spec/ruby/core/hash/clear_spec.rb
index cf05e36ac9..beff925a63 100644
--- a/spec/ruby/core/hash/clear_spec.rb
+++ b/spec/ruby/core/hash/clear_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#clear" do
it "removes all key, value pairs" do
h = { 1 => 2, 3 => 4 }
- h.clear.should equal(h)
+ h.clear.should.equal?(h)
h.should == {}
end
@@ -26,7 +26,7 @@ describe "Hash#clear" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.clear }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.clear }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.clear }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.clear }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/clone_spec.rb b/spec/ruby/core/hash/clone_spec.rb
index 6c96fc0c67..d135a84453 100644
--- a/spec/ruby/core/hash/clone_spec.rb
+++ b/spec/ruby/core/hash/clone_spec.rb
@@ -7,6 +7,6 @@ describe "Hash#clone" do
clone = hash.clone
clone.should == hash
- clone.should_not equal hash
+ clone.should_not.equal? hash
end
end
diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb
index 76aa43949d..de83dabed3 100644
--- a/spec/ruby/core/hash/compact_spec.rb
+++ b/spec/ruby/core/hash/compact_spec.rb
@@ -10,7 +10,7 @@ describe "Hash#compact" do
it "returns new object that rejects pair has nil value" do
ret = @hash.compact
- ret.should_not equal(@hash)
+ ret.should_not.equal?(@hash)
ret.should == @compact
end
@@ -19,28 +19,26 @@ describe "Hash#compact" do
@hash.should == @initial_pairs
end
- ruby_version_is '3.3' do
- it "retains the default value" do
- hash = Hash.new(1)
- hash.compact.default.should == 1
- hash[:a] = 1
- hash.compact.default.should == 1
- end
+ it "retains the default value" do
+ hash = Hash.new(1)
+ hash.compact.default.should == 1
+ hash[:a] = 1
+ hash.compact.default.should == 1
+ end
- it "retains the default_proc" do
- pr = proc { |h, k| h[k] = [] }
- hash = Hash.new(&pr)
- hash.compact.default_proc.should == pr
- hash[:a] = 1
- hash.compact.default_proc.should == pr
- end
+ it "retains the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ hash.compact.default_proc.should == pr
+ hash[:a] = 1
+ hash.compact.default_proc.should == pr
+ end
- it "retains compare_by_identity_flag" do
- hash = {}.compare_by_identity
- hash.compact.compare_by_identity?.should == true
- hash[:a] = 1
- hash.compact.compare_by_identity?.should == true
- end
+ it "retains compare_by_identity flag" do
+ hash = {}.compare_by_identity
+ hash.compact.compare_by_identity?.should == true
+ hash[:a] = 1
+ hash.compact.compare_by_identity?.should == true
end
end
@@ -52,7 +50,7 @@ describe "Hash#compact!" do
end
it "returns self" do
- @hash.compact!.should equal(@hash)
+ @hash.compact!.should.equal?(@hash)
end
it "rejects own pair has nil value" do
@@ -66,7 +64,7 @@ describe "Hash#compact!" do
end
it "returns nil" do
- @hash.compact!.should be_nil
+ @hash.compact!.should == nil
end
end
@@ -76,7 +74,7 @@ describe "Hash#compact!" do
end
it "keeps pairs and raises a FrozenError" do
- ->{ @hash.compact! }.should raise_error(FrozenError)
+ ->{ @hash.compact! }.should.raise(FrozenError)
@hash.should == @initial_pairs
end
end
diff --git a/spec/ruby/core/hash/compare_by_identity_spec.rb b/spec/ruby/core/hash/compare_by_identity_spec.rb
index 2975526a97..1abf9d5666 100644
--- a/spec/ruby/core/hash/compare_by_identity_spec.rb
+++ b/spec/ruby/core/hash/compare_by_identity_spec.rb
@@ -11,7 +11,7 @@ describe "Hash#compare_by_identity" do
@h[[1]] = :a
@h[[1]].should == :a
@h.compare_by_identity
- @h[[1].dup].should be_nil
+ @h[[1].dup].should == nil
end
it "rehashes internally so that old keys can be looked up" do
@@ -27,21 +27,21 @@ describe "Hash#compare_by_identity" do
it "returns self" do
h = {}
h[:foo] = :bar
- h.compare_by_identity.should equal h
+ h.compare_by_identity.should.equal? h
end
it "has no effect on an already compare_by_identity hash" do
@idh[:foo] = :bar
- @idh.compare_by_identity.should equal @idh
+ @idh.compare_by_identity.should.equal? @idh
@idh.should.compare_by_identity?
@idh[:foo].should == :bar
end
it "uses the semantics of BasicObject#equal? to determine key identity" do
- [1].should_not equal([1])
+ [1].should_not.equal?([1])
@idh[[1]] = :c
@idh[[1]] = :d
- :bar.should equal(:bar)
+ :bar.should.equal?(:bar)
@idh[:bar] = :e
@idh[:bar] = :f
@idh.values.should == [:c, :d, :f]
@@ -64,13 +64,13 @@ describe "Hash#compare_by_identity" do
it "regards #dup'd objects as having different identities" do
key = ['foo']
@idh[key.dup] = :str
- @idh[key].should be_nil
+ @idh[key].should == nil
end
it "regards #clone'd objects as having different identities" do
key = ['foo']
@idh[key.clone] = :str
- @idh[key].should be_nil
+ @idh[key].should == nil
end
it "regards references to the same object as having the same identity" do
@@ -82,7 +82,7 @@ describe "Hash#compare_by_identity" do
it "raises a FrozenError on frozen hashes" do
@h = @h.freeze
- -> { @h.compare_by_identity }.should raise_error(FrozenError)
+ -> { @h.compare_by_identity }.should.raise(FrozenError)
end
# Behaviour confirmed in https://bugs.ruby-lang.org/issues/1871
@@ -107,7 +107,7 @@ describe "Hash#compare_by_identity" do
@idh[foo] = true
@idh[foo] = true
@idh.size.should == 1
- @idh.keys.first.should equal foo
+ @idh.keys.first.should.equal? foo
end
# Check `#[]=` call with a String literal.
@@ -128,20 +128,20 @@ end
describe "Hash#compare_by_identity?" do
it "returns false by default" do
h = {}
- h.compare_by_identity?.should be_false
+ h.compare_by_identity?.should == false
end
it "returns true once #compare_by_identity has been invoked on self" do
h = {}
h.compare_by_identity
- h.compare_by_identity?.should be_true
+ h.compare_by_identity?.should == true
end
it "returns true when called multiple times on the same ident hash" do
h = {}
h.compare_by_identity
- h.compare_by_identity?.should be_true
- h.compare_by_identity?.should be_true
- h.compare_by_identity?.should be_true
+ h.compare_by_identity?.should == true
+ h.compare_by_identity?.should == true
+ h.compare_by_identity?.should == true
end
end
diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb
index 8d29773909..c16f373160 100644
--- a/spec/ruby/core/hash/constructor_spec.rb
+++ b/spec/ruby/core/hash/constructor_spec.rb
@@ -44,23 +44,23 @@ describe "Hash.[]" do
it "raises for elements that are not arrays" do
-> {
- Hash[[:a]].should == {}
- }.should raise_error(ArgumentError)
+ Hash[[:a]]
+ }.should.raise(ArgumentError, "wrong element type Symbol at 0 (expected array)")
-> {
- Hash[[:nil]].should == {}
- }.should raise_error(ArgumentError)
+ Hash[[nil]]
+ }.should.raise(ArgumentError, "wrong element type nil at 0 (expected array)")
end
it "raises an ArgumentError for arrays of more than 2 elements" do
- ->{ Hash[[[:a, :b, :c]]].should == {} }.should raise_error(ArgumentError)
+ ->{
+ Hash[[[:a, :b, :c]]]
+ }.should.raise(ArgumentError, "invalid number of elements (3 for 1..2)")
end
it "raises an ArgumentError when passed a list of value-invalid-pairs in an array" do
-> {
- -> {
- Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
- }.should complain(/ignoring wrong elements/)
- }.should raise_error(ArgumentError)
+ Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
+ }.should.raise(ArgumentError, "wrong element type Integer at 2 (expected array)")
end
describe "passed a single argument which responds to #to_hash" do
@@ -71,13 +71,13 @@ describe "Hash.[]" do
result = Hash[to_hash]
result.should == h
- result.should_not equal(h)
+ result.should_not.equal?(h)
end
end
it "raises an ArgumentError when passed an odd number of arguments" do
- -> { Hash[1, 2, 3] }.should raise_error(ArgumentError)
- -> { Hash[1, 2, { 3 => 4 }] }.should raise_error(ArgumentError)
+ -> { Hash[1, 2, 3] }.should.raise(ArgumentError)
+ -> { Hash[1, 2, { 3 => 4 }] }.should.raise(ArgumentError)
end
it "calls to_hash" do
@@ -87,42 +87,41 @@ describe "Hash.[]" do
end
it "returns an instance of a subclass when passed an Array" do
- HashSpecs::MyHash[1,2,3,4].should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[1,2,3,4].should.instance_of?(HashSpecs::MyHash)
end
it "returns instances of subclasses" do
- HashSpecs::MyHash[].should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[].should.instance_of?(HashSpecs::MyHash)
end
it "returns an instance of the class it's called on" do
Hash[HashSpecs::MyHash[1, 2]].class.should == Hash
- HashSpecs::MyHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[Hash[1, 2]].should.instance_of?(HashSpecs::MyHash)
end
it "does not call #initialize on the subclass instance" do
- HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash)
+ HashSpecs::MyInitializerHash[Hash[1, 2]].should.instance_of?(HashSpecs::MyInitializerHash)
end
- it "removes the default value" do
+ it "does not retain the default value" do
hash = Hash.new(1)
- Hash[hash].default.should be_nil
+ Hash[hash].default.should == nil
hash[:a] = 1
- Hash[hash].default.should be_nil
+ Hash[hash].default.should == nil
end
- it "removes the default_proc" do
+ it "does not retain the default_proc" do
hash = Hash.new { |h, k| h[k] = [] }
- Hash[hash].default_proc.should be_nil
+ Hash[hash].default_proc.should == nil
hash[:a] = 1
- Hash[hash].default_proc.should be_nil
+ Hash[hash].default_proc.should == nil
end
- ruby_version_is '3.3' do
- it "does not retain compare_by_identity_flag" do
- hash = {}.compare_by_identity
- Hash[hash].compare_by_identity?.should == false
- hash[:a] = 1
- Hash[hash].compare_by_identity?.should == false
- end
+ it "does not retain compare_by_identity flag" do
+ hash = { a: 1 }.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
+
+ hash = {}.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
end
end
diff --git a/spec/ruby/core/hash/deconstruct_keys_spec.rb b/spec/ruby/core/hash/deconstruct_keys_spec.rb
index bbcd8932e5..f6ff3a2818 100644
--- a/spec/ruby/core/hash/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/hash/deconstruct_keys_spec.rb
@@ -4,13 +4,13 @@ describe "Hash#deconstruct_keys" do
it "returns self" do
hash = {a: 1, b: 2}
- hash.deconstruct_keys([:a, :b]).should equal hash
+ hash.deconstruct_keys([:a, :b]).should.equal? hash
end
it "requires one argument" do
-> {
{a: 1}.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "ignores argument" do
diff --git a/spec/ruby/core/hash/default_proc_spec.rb b/spec/ruby/core/hash/default_proc_spec.rb
index f4e4803632..4830e02acd 100644
--- a/spec/ruby/core/hash/default_proc_spec.rb
+++ b/spec/ruby/core/hash/default_proc_spec.rb
@@ -25,24 +25,24 @@ describe "Hash#default_proc=" do
h = Hash.new { 'Paris' }
obj = mock('to_proc')
obj.should_receive(:to_proc).and_return(Proc.new { 'Montreal' })
- (h.default_proc = obj).should equal(obj)
+ (h.default_proc = obj).should.equal?(obj)
h[:cool_city].should == 'Montreal'
end
it "overrides the static default" do
h = Hash.new(42)
h.default_proc = Proc.new { 6 }
- h.default.should be_nil
+ h.default.should == nil
h.default_proc.call.should == 6
end
it "raises an error if passed stuff not convertible to procs" do
- ->{{}.default_proc = 42}.should raise_error(TypeError)
+ ->{{}.default_proc = 42}.should.raise(TypeError)
end
it "returns the passed Proc" do
new_proc = Proc.new {}
- ({}.default_proc = new_proc).should equal(new_proc)
+ ({}.default_proc = new_proc).should.equal?(new_proc)
end
it "clears the default proc if passed nil" do
@@ -53,28 +53,28 @@ describe "Hash#default_proc=" do
end
it "returns nil if passed nil" do
- ({}.default_proc = nil).should be_nil
+ ({}.default_proc = nil).should == nil
end
it "accepts a lambda with an arity of 2" do
h = {}
-> do
h.default_proc = -> a, b { }
- end.should_not raise_error(TypeError)
+ end.should_not.raise(TypeError)
end
it "raises a TypeError if passed a lambda with an arity other than 2" do
h = {}
-> do
h.default_proc = -> a { }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
h.default_proc = -> a, b, c { }
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a FrozenError if self is frozen" do
- -> { {}.freeze.default_proc = Proc.new {} }.should raise_error(FrozenError)
- -> { {}.freeze.default_proc = nil }.should raise_error(FrozenError)
+ -> { {}.freeze.default_proc = Proc.new {} }.should.raise(FrozenError)
+ -> { {}.freeze.default_proc = nil }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/default_spec.rb b/spec/ruby/core/hash/default_spec.rb
index d8b62ea196..17ee032e2b 100644
--- a/spec/ruby/core/hash/default_spec.rb
+++ b/spec/ruby/core/hash/default_spec.rb
@@ -40,7 +40,7 @@ describe "Hash#default=" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.default = nil }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.default = nil }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.default = nil }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.default = nil }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/delete_if_spec.rb b/spec/ruby/core/hash/delete_if_spec.rb
index c9e670ffc3..3090633d88 100644
--- a/spec/ruby/core/hash/delete_if_spec.rb
+++ b/spec/ruby/core/hash/delete_if_spec.rb
@@ -12,13 +12,13 @@ describe "Hash#delete_if" do
it "removes every entry for which block is true and returns self" do
h = { a: 1, b: 2, c: 3, d: 4 }
- h.delete_if { |k,v| v % 2 == 1 }.should equal(h)
+ h.delete_if { |k,v| v % 2 == 1 }.should.equal?(h)
h.should == { b: 2, d: 4 }
end
it "removes all entries if the block is true" do
h = { a: 1, b: 2, c: 3 }
- h.delete_if { |k,v| true }.should equal(h)
+ h.delete_if { |k,v| true }.should.equal?(h)
h.should == {}
end
@@ -35,8 +35,8 @@ describe "Hash#delete_if" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete_if { false } }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.delete_if { true } }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete_if { false } }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.delete_if { true } }.should.raise(FrozenError)
end
it_behaves_like :hash_iteration_no_block, :delete_if
diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb
index 3e3479c69c..33ff01bf36 100644
--- a/spec/ruby/core/hash/delete_spec.rb
+++ b/spec/ruby/core/hash/delete_spec.rb
@@ -52,7 +52,7 @@ describe "Hash#delete" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete("foo") }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.delete("foo") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/dig_spec.rb b/spec/ruby/core/hash/dig_spec.rb
index aa0ecadd2f..94ac94e850 100644
--- a/spec/ruby/core/hash/dig_spec.rb
+++ b/spec/ruby/core/hash/dig_spec.rb
@@ -5,16 +5,16 @@ describe "Hash#dig" do
it "returns #[] with one arg" do
h = { 0 => false, a: 1 }
h.dig(:a).should == 1
- h.dig(0).should be_false
- h.dig(1).should be_nil
+ h.dig(0).should == false
+ h.dig(1).should == nil
end
it "returns the nested value specified by the sequence of keys" do
h = { foo: { bar: { baz: 1 } } }
h.dig(:foo, :bar, :baz).should == 1
- h.dig(:foo, :bar, :nope).should be_nil
- h.dig(:foo, :baz).should be_nil
- h.dig(:bar, :baz, :foo).should be_nil
+ h.dig(:foo, :bar, :nope).should == nil
+ h.dig(:foo, :baz).should == nil
+ h.dig(:bar, :baz, :foo).should == nil
end
it "returns the nested value specified if the sequence includes an index" do
@@ -28,7 +28,7 @@ describe "Hash#dig" do
end
it "raises an ArgumentError if no arguments provided" do
- -> { { the: 'borg' }.dig() }.should raise_error(ArgumentError)
+ -> { { the: 'borg' }.dig() }.should.raise(ArgumentError)
end
it "handles type-mixed deep digging" do
@@ -47,8 +47,8 @@ describe "Hash#dig" do
it "raises TypeError if an intermediate element does not respond to #dig" do
h = {}
h[:foo] = [ { bar: [ 1 ] }, [ nil, 'str' ] ]
- -> { h.dig(:foo, 0, :bar, 0, 0) }.should raise_error(TypeError)
- -> { h.dig(:foo, 1, 1, 0) }.should raise_error(TypeError)
+ -> { h.dig(:foo, 0, :bar, 0, 0) }.should.raise(TypeError)
+ -> { h.dig(:foo, 1, 1, 0) }.should.raise(TypeError)
end
it "calls #dig on the result of #[] with the remaining arguments" do
@@ -60,7 +60,7 @@ describe "Hash#dig" do
it "respects Hash's default" do
default = {bar: 42}
h = Hash.new(default)
- h.dig(:foo).should equal default
+ h.dig(:foo).should.equal? default
h.dig(:foo, :bar).should == 42
end
end
diff --git a/spec/ruby/core/hash/each_key_spec.rb b/spec/ruby/core/hash/each_key_spec.rb
index c84dd696d5..5b2e9deb63 100644
--- a/spec/ruby/core/hash/each_key_spec.rb
+++ b/spec/ruby/core/hash/each_key_spec.rb
@@ -7,7 +7,7 @@ describe "Hash#each_key" do
it "calls block once for each key, passing key" do
r = {}
h = { 1 => -1, 2 => -2, 3 => -3, 4 => -4 }
- h.each_key { |k| r[k] = k }.should equal(h)
+ h.each_key { |k| r[k] = k }.should.equal?(h)
r.should == { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }
end
diff --git a/spec/ruby/core/hash/each_pair_spec.rb b/spec/ruby/core/hash/each_pair_spec.rb
index eb6656681d..01810c130c 100644
--- a/spec/ruby/core/hash/each_pair_spec.rb
+++ b/spec/ruby/core/hash/each_pair_spec.rb
@@ -1,11 +1,111 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
require_relative 'shared/iteration'
-require_relative 'shared/each'
require_relative '../enumerable/shared/enumeratorized'
describe "Hash#each_pair" do
- it_behaves_like :hash_each, :each_pair
it_behaves_like :hash_iteration_no_block, :each_pair
it_behaves_like :enumeratorized_with_origin_size, :each_pair, { 1 => 2, 3 => 4, 5 => 6 }
+
+ # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair()
+ it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do
+ all_args = []
+ { 1 => 2, 3 => 4 }.each_pair { |*args| all_args << args }
+ all_args.sort.should == [[[1, 2]], [[3, 4]]]
+ end
+
+ it "yields the key and value of each pair to a block expecting |key, value|" do
+ r = {}
+ h = { a: 1, b: 2, c: 3, d: 5 }
+ h.each_pair { |k,v| r[k.to_s] = v.to_s }.should.equal?(h)
+ r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" }
+ end
+
+ it "yields the key only to a block expecting |key,|" do
+ ary = []
+ h = { "a" => 1, "b" => 2, "c" => 3 }
+ h.each_pair { |k,| ary << k }
+ ary.sort.should == ["a", "b", "c"]
+ end
+
+ it "always yields an Array of 2 elements, even when given a callable of arity 2" do
+ obj = Object.new
+ def obj.foo(key, value)
+ end
+
+ -> {
+ { "a" => 1 }.each_pair(&obj.method(:foo))
+ }.should.raise(ArgumentError)
+
+ -> {
+ { "a" => 1 }.each_pair(&-> key, value { })
+ }.should.raise(ArgumentError)
+ end
+
+ it "yields an Array of 2 elements when given a callable of arity 1" do
+ obj = Object.new
+ def obj.foo(key_value)
+ ScratchPad << key_value
+ end
+
+ ScratchPad.record([])
+ { "a" => 1 }.each_pair(&obj.method(:foo))
+ ScratchPad.recorded.should == [["a", 1]]
+ end
+
+ it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do
+ obj = Object.new
+ def obj.foo(key, value, extra)
+ end
+
+ -> {
+ { "a" => 1 }.each_pair(&obj.method(:foo))
+ }.should.raise(ArgumentError)
+ end
+
+ it "uses the same order as keys() and values()" do
+ h = { a: 1, b: 2, c: 3, d: 5 }
+ keys = []
+ values = []
+
+ h.each_pair do |k, v|
+ keys << k
+ values << v
+ end
+
+ keys.should == h.keys
+ values.should == h.values
+ end
+
+ # Confirming the argument-splatting works from child class for both k, v and [k, v]
+ it "properly expands (or not) child class's 'each'-yielded args" do
+ cls1 = Class.new(Hash) do
+ attr_accessor :k_v
+ def each
+ super do |k, v|
+ @k_v = [k, v]
+ yield k, v
+ end
+ end
+ end
+
+ cls2 = Class.new(Hash) do
+ attr_accessor :k_v
+ def each
+ super do |k, v|
+ @k_v = [k, v]
+ yield([k, v])
+ end
+ end
+ end
+
+ obj1 = cls1.new
+ obj1['a'] = 'b'
+ obj1.map {|k, v| [k, v]}.should == [['a', 'b']]
+ obj1.k_v.should == ['a', 'b']
+
+ obj2 = cls2.new
+ obj2['a'] = 'b'
+ obj2.map {|k, v| [k, v]}.should == [['a', 'b']]
+ obj2.k_v.should == ['a', 'b']
+ end
end
diff --git a/spec/ruby/core/hash/each_spec.rb b/spec/ruby/core/hash/each_spec.rb
index f0de0bdee5..1644b63216 100644
--- a/spec/ruby/core/hash/each_spec.rb
+++ b/spec/ruby/core/hash/each_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/iteration'
-require_relative 'shared/each'
-require_relative '../enumerable/shared/enumeratorized'
describe "Hash#each" do
- it_behaves_like :hash_each, :each
- it_behaves_like :hash_iteration_no_block, :each
- it_behaves_like :enumeratorized_with_origin_size, :each, { 1 => 2, 3 => 4, 5 => 6 }
+ it "is an alias of Hash#each_pair" do
+ Hash.instance_method(:each).should == Hash.instance_method(:each_pair)
+ end
end
diff --git a/spec/ruby/core/hash/each_value_spec.rb b/spec/ruby/core/hash/each_value_spec.rb
index 19b076730d..2df95a8789 100644
--- a/spec/ruby/core/hash/each_value_spec.rb
+++ b/spec/ruby/core/hash/each_value_spec.rb
@@ -7,7 +7,7 @@ describe "Hash#each_value" do
it "calls block once for each key, passing value" do
r = []
h = { a: -5, b: -3, c: -2, d: -1, e: -1 }
- h.each_value { |v| r << v }.should equal(h)
+ h.each_value { |v| r << v }.should.equal?(h)
r.sort.should == [-5, -3, -2, -1, -1]
end
diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb
index d5859cb342..3d074b346d 100644
--- a/spec/ruby/core/hash/element_reference_spec.rb
+++ b/spec/ruby/core/hash/element_reference_spec.rb
@@ -36,7 +36,7 @@ describe "Hash#[]" do
b = h[:b]
a << "bar"
- a.should equal(b)
+ a.should.equal?(b)
a.should == "foobar"
b.should == "foobar"
end
diff --git a/spec/ruby/core/hash/element_set_spec.rb b/spec/ruby/core/hash/element_set_spec.rb
index 67c5a04d73..bb805477ca 100644
--- a/spec/ruby/core/hash/element_set_spec.rb
+++ b/spec/ruby/core/hash/element_set_spec.rb
@@ -1,7 +1,121 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/store'
describe "Hash#[]=" do
- it_behaves_like :hash_store, :[]=
+ it "associates the key with the value" do
+ h = { a: 1 }
+ h[:b] = 2
+ h.should == { b:2, a:1 }
+ end
+
+ it "returns the assigned value" do
+ h = {}
+ h.send(:[]=, 1, 2).should == 2
+ end
+
+ it "duplicates string keys using dup semantics" do
+ # dup doesn't copy singleton methods
+ key = +"foo"
+ def key.reverse() "bar" end
+ h = {}
+ h[key] = 0
+ h.keys[0].reverse.should == "oof"
+ end
+
+ it "stores unequal keys that hash to the same value" do
+ h = {}
+ k1 = ["x"]
+ k2 = ["y"]
+ # So they end up in the same bucket
+ k1.should_receive(:hash).and_return(0)
+ k2.should_receive(:hash).and_return(0)
+
+ h[k1] = 1
+ h[k2] = 2
+ h.size.should == 2
+ end
+
+ it "accepts keys with private #hash method" do
+ key = HashSpecs::KeyWithPrivateHash.new
+ h = {}
+ h[key] = "foo"
+ h[key].should == "foo"
+ end
+
+ it " accepts keys with an Integer hash" do
+ o = mock(hash: 1 << 100)
+ h = {}
+ h[o] = 1
+ h[o].should == 1
+ end
+
+ it "duplicates and freezes string keys" do
+ key = +"foo"
+ h = {}
+ h[key] = 0
+ key << "bar"
+
+ h.should == { "foo" => 0 }
+ h.keys[0].should.frozen?
+ end
+
+ it "doesn't duplicate and freeze already frozen string keys" do
+ key = "foo".freeze
+ h = {}
+ h[key] = 0
+ h.keys[0].should.equal?(key)
+ end
+
+ it "keeps the existing key in the hash if there is a matching one" do
+ h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
+ key1 = HashSpecs::ByValueKey.new(13)
+ key2 = HashSpecs::ByValueKey.new(13)
+ h[key1] = 41
+ key_in_hash = h.keys.last
+ key_in_hash.should.equal?(key1)
+ h[key2] = 42
+ last_key = h.keys.last
+ last_key.should.equal?(key_in_hash)
+ last_key.should_not.equal?(key2)
+ end
+
+ it "keeps the existing String key in the hash if there is a matching one" do
+ h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
+ key1 = "foo".dup
+ key2 = "foo".dup
+ key1.should_not.equal?(key2)
+ h[key1] = 41
+ frozen_key = h.keys.last
+ frozen_key.should_not.equal?(key1)
+ h[key2] = 42
+ h.keys.last.should.equal?(frozen_key)
+ h.keys.last.should_not.equal?(key2)
+ end
+
+ it "raises a FrozenError if called on a frozen instance" do
+ -> { HashSpecs.frozen_hash[1] = 2 }.should.raise(FrozenError)
+ end
+
+ it "does not raise an exception if changing the value of an existing key during iteration" do
+ hash = {1 => 2, 3 => 4, 5 => 6}
+ hash.each { hash[1] = :foo }
+ hash.should == {1 => :foo, 3 => 4, 5 => 6}
+ end
+
+ it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do
+ code = <<-EOC
+ load '#{fixture __FILE__, "name.rb"}'
+ hash = {}
+ [true, false, 1, 2.0, "hello", :ok].each do |value|
+ hash[value] = 42
+ raise "incorrect value" unless hash[value] == 42
+ hash[value] = 43
+ raise "incorrect value" unless hash[value] == 43
+ end
+ puts "OK"
+ puts hash.size
+ EOC
+ result = ruby_exe(code, args: "2>&1")
+ result.should == "OK\n6\n"
+ end
end
diff --git a/spec/ruby/core/hash/equal_value_spec.rb b/spec/ruby/core/hash/equal_value_spec.rb
index ae13a42679..ab14f81489 100644
--- a/spec/ruby/core/hash/equal_value_spec.rb
+++ b/spec/ruby/core/hash/equal_value_spec.rb
@@ -13,6 +13,6 @@ describe "Hash#==" do
l_val.should_receive(:==).with(r_val).and_return(true)
- ({ 1 => l_val } == { 1 => r_val }).should be_true
+ ({ 1 => l_val } == { 1 => r_val }).should == true
end
end
diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb
index ac84f9975c..77a020e9b7 100644
--- a/spec/ruby/core/hash/except_spec.rb
+++ b/spec/ruby/core/hash/except_spec.rb
@@ -7,7 +7,7 @@ describe "Hash#except" do
it "returns a new duplicate hash without arguments" do
ret = @hash.except
- ret.should_not equal(@hash)
+ ret.should_not.equal?(@hash)
ret.should == @hash
end
@@ -19,14 +19,24 @@ describe "Hash#except" do
@hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 }
end
- it "always returns a Hash without a default" do
- klass = Class.new(Hash)
- h = klass.new(:default)
- h[:bar] = 12
- h[:foo] = 42
- r = h.except(:foo)
- r.should == {bar: 12}
- r.class.should == Hash
- r.default.should == nil
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.except(:a).default.should == nil
+ h[:a] = 1
+ h.except(:a).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.except(:a).default_proc.should == nil
+ h[:a] = 1
+ h.except(:a).default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.except(:a)
+ h2.compare_by_identity?.should == true
end
end
diff --git a/spec/ruby/core/hash/fetch_spec.rb b/spec/ruby/core/hash/fetch_spec.rb
index 6e0d207224..f9b80b6c49 100644
--- a/spec/ruby/core/hash/fetch_spec.rb
+++ b/spec/ruby/core/hash/fetch_spec.rb
@@ -12,7 +12,7 @@ describe "Hash#fetch" do
it "formats the object with #inspect in the KeyError message" do
-> {
{}.fetch('foo')
- }.should raise_error(KeyError, 'key not found: "foo"')
+ }.should.raise(KeyError, 'key not found: "foo"')
end
end
@@ -38,7 +38,7 @@ describe "Hash#fetch" do
end
it "raises an ArgumentError when not passed one or two arguments" do
- -> { {}.fetch() }.should raise_error(ArgumentError)
- -> { {}.fetch(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { {}.fetch() }.should.raise(ArgumentError)
+ -> { {}.fetch(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/hash/filter_spec.rb b/spec/ruby/core/hash/filter_spec.rb
index 7dabe44984..625a7feb90 100644
--- a/spec/ruby/core/hash/filter_spec.rb
+++ b/spec/ruby/core/hash/filter_spec.rb
@@ -1,10 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
describe "Hash#filter" do
- it_behaves_like :hash_select, :filter
+ it "is an alias of Hash#select" do
+ Hash.instance_method(:filter).should == Hash.instance_method(:select)
+ end
end
describe "Hash#filter!" do
- it_behaves_like :hash_select!, :filter!
+ it "is an alias of Hash#select!" do
+ Hash.instance_method(:filter!).should == Hash.instance_method(:select!)
+ end
end
diff --git a/spec/ruby/core/hash/flatten_spec.rb b/spec/ruby/core/hash/flatten_spec.rb
index 825da15bfc..18e9a7b56a 100644
--- a/spec/ruby/core/hash/flatten_spec.rb
+++ b/spec/ruby/core/hash/flatten_spec.rb
@@ -9,7 +9,7 @@ describe "Hash#flatten" do
end
it "returns an Array" do
- {}.flatten.should be_an_instance_of(Array)
+ {}.flatten.should.instance_of?(Array)
end
it "returns an empty Array for an empty Hash" do
@@ -57,6 +57,6 @@ describe "Hash#flatten" do
it "raises a TypeError if given a non-Integer argument" do
-> do
@h.flatten(Object.new)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/hash/gt_spec.rb b/spec/ruby/core/hash/gt_spec.rb
index cd541d4d83..69d23b7d29 100644
--- a/spec/ruby/core/hash/gt_spec.rb
+++ b/spec/ruby/core/hash/gt_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#>" do
it "returns false if both hashes are identical" do
h = { a: 1, b: 2 }
- (h > h).should be_false
+ (h > h).should == false
end
end
diff --git a/spec/ruby/core/hash/gte_spec.rb b/spec/ruby/core/hash/gte_spec.rb
index 99b89e7217..be5060ea4f 100644
--- a/spec/ruby/core/hash/gte_spec.rb
+++ b/spec/ruby/core/hash/gte_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#>=" do
it "returns true if both hashes are identical" do
h = { a: 1, b: 2 }
- (h >= h).should be_true
+ (h >= h).should == true
end
end
diff --git a/spec/ruby/core/hash/has_key_spec.rb b/spec/ruby/core/hash/has_key_spec.rb
index 4af53579e5..9a6244c6f6 100644
--- a/spec/ruby/core/hash/has_key_spec.rb
+++ b/spec/ruby/core/hash/has_key_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
describe "Hash#has_key?" do
- it_behaves_like :hash_key_p, :has_key?
+ it "is an alias of Hash#include?" do
+ Hash.instance_method(:has_key?).should == Hash.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/hash/has_value_spec.rb b/spec/ruby/core/hash/has_value_spec.rb
index 39f1627fd3..d40e52ebfd 100644
--- a/spec/ruby/core/hash/has_value_spec.rb
+++ b/spec/ruby/core/hash/has_value_spec.rb
@@ -1,7 +1,16 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/value'
describe "Hash#has_value?" do
- it_behaves_like :hash_value_p, :has_value?
+ it "returns true if the value exists in the hash" do
+ { a: :b }.has_value?(:a).should == false
+ { 1 => 2 }.has_value?(2).should == true
+ h = Hash.new(5)
+ h.has_value?(5).should == false
+ h = Hash.new { 5 }
+ h.has_value?(5).should == false
+ end
+
+ it "uses == semantics for comparing values" do
+ { 5 => 2.0 }.has_value?(2).should == true
+ end
end
diff --git a/spec/ruby/core/hash/include_spec.rb b/spec/ruby/core/hash/include_spec.rb
index f3959dc589..1c32e9fb23 100644
--- a/spec/ruby/core/hash/include_spec.rb
+++ b/spec/ruby/core/hash/include_spec.rb
@@ -1,7 +1,40 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
describe "Hash#include?" do
- it_behaves_like :hash_key_p, :include?
+ it "returns true if argument is a key" do
+ h = { a: 1, b: 2, c: 3, 4 => 0 }
+ h.include?(:a).should == true
+ h.include?(:b).should == true
+ h.include?(2).should == false
+ h.include?(4).should == true
+
+ not_supported_on :opal do
+ h.include?('b').should == false
+ h.include?(4.0).should == false
+ end
+ end
+
+ it "returns true if the key's matching value was nil" do
+ { xyz: nil }.include?(:xyz).should == true
+ end
+
+ it "returns true if the key's matching value was false" do
+ { xyz: false }.include?(:xyz).should == true
+ end
+
+ it "returns true if the key is nil" do
+ { nil => 'b' }.include?(nil).should == true
+ { nil => nil }.include?(nil).should == true
+ end
+
+ it "compares keys with the same #hash value via #eql?" do
+ x = mock('x')
+ x.stub!(:hash).and_return(42)
+
+ y = mock('y')
+ y.stub!(:hash).and_return(42)
+ y.should_receive(:eql?).and_return(false)
+
+ { x => nil }.include?(y).should == false
+ end
end
diff --git a/spec/ruby/core/hash/initialize_spec.rb b/spec/ruby/core/hash/initialize_spec.rb
index d13496ba3b..cdba598813 100644
--- a/spec/ruby/core/hash/initialize_spec.rb
+++ b/spec/ruby/core/hash/initialize_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Hash#initialize" do
it "is private" do
- Hash.should have_private_instance_method("initialize")
+ Hash.private_instance_methods(false).should.include?(:initialize)
end
it "can be used to reset default_proc" do
@@ -42,20 +42,20 @@ describe "Hash#initialize" do
it "returns self" do
h = Hash.new
- h.send(:initialize).should equal(h)
+ h.send(:initialize).should.equal?(h)
end
it "raises a FrozenError if called on a frozen instance" do
block = -> { HashSpecs.frozen_hash.instance_eval { initialize() }}
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
block = -> { HashSpecs.frozen_hash.instance_eval { initialize(nil) } }
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
block = -> { HashSpecs.frozen_hash.instance_eval { initialize(5) } }
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
block = -> { HashSpecs.frozen_hash.instance_eval { initialize { 5 } } }
- block.should raise_error(FrozenError)
+ block.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/inspect_spec.rb b/spec/ruby/core/hash/inspect_spec.rb
index f41ebb70a6..359b13360f 100644
--- a/spec/ruby/core/hash/inspect_spec.rb
+++ b/spec/ruby/core/hash/inspect_spec.rb
@@ -1,7 +1,123 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "Hash#inspect" do
- it_behaves_like :hash_to_s, :inspect
+ it "returns a string representation with same order as each()" do
+ h = { a: [1, 2], b: -2, d: -6, nil => nil }
+ expected = ruby_version_is("3.4") ? "{a: [1, 2], b: -2, d: -6, nil => nil}" : "{:a=>[1, 2], :b=>-2, :d=>-6, nil=>nil}"
+ h.inspect.should == expected
+ end
+
+ it "calls #inspect on keys and values" do
+ key = mock('key')
+ val = mock('val')
+ key.should_receive(:inspect).and_return('key')
+ val.should_receive(:inspect).and_return('val')
+ expected = ruby_version_is("3.4") ? "{key => val}" : "{key=>val}"
+ { key => val }.inspect.should == expected
+ end
+
+ it "does not call #to_s on a String returned from #inspect" do
+ str = +"abc"
+ str.should_not_receive(:to_s)
+ expected = ruby_version_is("3.4") ? '{a: "abc"}' : '{:a=>"abc"}'
+ { a: str }.inspect.should == expected
+ end
+
+ it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
+ obj = mock("Hash#inspect/to_s calls #to_s")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_return("abc")
+ expected = ruby_version_is("3.4") ? "{a: abc}" : "{:a=>abc}"
+ { a: obj }.inspect.should == expected
+ end
+
+ it "does not call #to_str on the object returned from #inspect when it is not a String" do
+ obj = mock("Hash#inspect/to_s does not call #to_str")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_not_receive(:to_str)
+ expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
+ { a: obj }.inspect.should =~ expected_pattern
+ end
+
+ it "does not call #to_str on the object returned from #to_s when it is not a String" do
+ obj = mock("Hash#inspect/to_s does not call #to_str on #to_s result")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_return(obj)
+ obj.should_not_receive(:to_str)
+ expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
+ { a: obj }.inspect.should =~ expected_pattern
+ end
+
+ it "does not swallow exceptions raised by #to_s" do
+ obj = mock("Hash#inspect/to_s does not swallow #to_s exceptions")
+ obj.should_receive(:inspect).and_return(obj)
+ obj.should_receive(:to_s).and_raise(Exception)
+
+ -> { { a: obj }.inspect }.should.raise(Exception)
+ end
+
+ it "handles hashes with recursive values" do
+ x = {}
+ x[0] = x
+ expected = ruby_version_is("3.4") ? '{0 => {...}}' : '{0=>{...}}'
+ x.inspect.should == expected
+
+ x = {}
+ y = {}
+ x[0] = y
+ y[1] = x
+ expected_x = ruby_version_is("3.4") ? '{0 => {1 => {...}}}' : '{0=>{1=>{...}}}'
+ expected_y = ruby_version_is("3.4") ? '{1 => {0 => {...}}}' : '{1=>{0=>{...}}}'
+ x.inspect.should == expected_x
+ y.inspect.should == expected_y
+ end
+
+ it "does not raise if inspected result is not default external encoding" do
+ utf_16be = mock("utf_16be")
+ utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
+ expected = ruby_version_is("3.4") ? '{a: "utf_16be \u3042"}' : '{:a=>"utf_16be \u3042"}'
+ {a: utf_16be}.inspect.should == expected
+ end
+
+ it "works for keys and values whose #inspect return a frozen String" do
+ expected = ruby_version_is("3.4") ? "{true => false}" : "{true=>false}"
+ { true => false }.inspect.should == expected
+ end
+
+ ruby_version_is "3.4" do
+ it "adds quotes to symbol keys that are not valid symbol literals" do
+ { "needs-quotes": 1 }.inspect.should == '{"needs-quotes": 1}'
+ end
+
+ it "can be evaled" do
+ no_quote = '{a: 1, a!: 1, a?: 1}'
+ eval(no_quote).inspect.should == no_quote
+ [
+ '{"": 1}',
+ '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}',
+ '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}',
+ '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}',
+ ].each do |quote|
+ eval(quote).inspect.should == quote
+ end
+ end
+
+ it "can be evaled when Encoding.default_external is changed" do
+ external = Encoding.default_external
+
+ Encoding.default_external = Encoding::ASCII
+ utf8_ascii_hash = '{"\\u3042": 1}'
+ eval(utf8_ascii_hash).inspect.should == utf8_ascii_hash
+
+ Encoding.default_external = Encoding::UTF_8
+ utf8_hash = "{\u3042: 1}"
+ eval(utf8_hash).inspect.should == utf8_hash
+
+ Encoding.default_external = Encoding::Windows_31J
+ sjis_hash = "{\x87]: 1}".dup.force_encoding('sjis')
+ eval(sjis_hash).inspect.should == sjis_hash
+ ensure
+ Encoding.default_external = external
+ end
+ end
end
diff --git a/spec/ruby/core/hash/invert_spec.rb b/spec/ruby/core/hash/invert_spec.rb
index 73377a9e97..ea441751f2 100644
--- a/spec/ruby/core/hash/invert_spec.rb
+++ b/spec/ruby/core/hash/invert_spec.rb
@@ -24,4 +24,25 @@ describe "Hash#invert" do
HashSpecs::MyHash[1 => 2, 3 => 4].invert.class.should == Hash
HashSpecs::MyHash[].invert.class.should == Hash
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.invert.default.should == nil
+ h[:a] = 1
+ h.invert.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.invert.default_proc.should == nil
+ h[:a] = 1
+ h.invert.default_proc.should == nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.invert
+ h2.compare_by_identity?.should == false
+ end
end
diff --git a/spec/ruby/core/hash/keep_if_spec.rb b/spec/ruby/core/hash/keep_if_spec.rb
index d50d969467..c975efc5f8 100644
--- a/spec/ruby/core/hash/keep_if_spec.rb
+++ b/spec/ruby/core/hash/keep_if_spec.rb
@@ -12,24 +12,24 @@ describe "Hash#keep_if" do
it "keeps every entry for which block is true and returns self" do
h = { a: 1, b: 2, c: 3, d: 4 }
- h.keep_if { |k,v| v % 2 == 0 }.should equal(h)
+ h.keep_if { |k,v| v % 2 == 0 }.should.equal?(h)
h.should == { b: 2, d: 4 }
end
it "removes all entries if the block is false" do
h = { a: 1, b: 2, c: 3 }
- h.keep_if { |k,v| false }.should equal(h)
+ h.keep_if { |k,v| false }.should.equal?(h)
h.should == {}
end
it "returns self even if unmodified" do
h = { 1 => 2, 3 => 4 }
- h.keep_if { true }.should equal(h)
+ h.keep_if { true }.should.equal?(h)
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.keep_if { true } }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.keep_if { false } }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.keep_if { true } }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.keep_if { false } }.should.raise(FrozenError)
end
it_behaves_like :hash_iteration_no_block, :keep_if
diff --git a/spec/ruby/core/hash/key_spec.rb b/spec/ruby/core/hash/key_spec.rb
index 73eecbc98e..c2d7049aed 100644
--- a/spec/ruby/core/hash/key_spec.rb
+++ b/spec/ruby/core/hash/key_spec.rb
@@ -1,12 +1,32 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
-require_relative 'shared/index'
describe "Hash#key?" do
- it_behaves_like :hash_key_p, :key?
+ it "is an alias of Hash#include?" do
+ Hash.instance_method(:key?).should == Hash.instance_method(:include?)
+ end
end
describe "Hash#key" do
- it_behaves_like :hash_index, :key
+ it "returns the corresponding key for value" do
+ { 2 => 'a', 1 => 'b' }.key('b').should == 1
+ end
+
+ it "returns nil if the value is not found" do
+ { a: -1, b: 3.14, c: 2.718 }.key(1).should == nil
+ end
+
+ it "doesn't return default value if the value is not found" do
+ Hash.new(5).key(5).should == nil
+ end
+
+ it "compares values using ==" do
+ { 1 => 0 }.key(0.0).should == 1
+ { 1 => 0.0 }.key(0).should == 1
+
+ needle = mock('needle')
+ inhash = mock('inhash')
+ inhash.should_receive(:==).with(needle).and_return(true)
+
+ { 1 => inhash }.key(needle).should == 1
+ end
end
diff --git a/spec/ruby/core/hash/keys_spec.rb b/spec/ruby/core/hash/keys_spec.rb
index 9a067085e5..789c413bee 100644
--- a/spec/ruby/core/hash/keys_spec.rb
+++ b/spec/ruby/core/hash/keys_spec.rb
@@ -5,11 +5,11 @@ describe "Hash#keys" do
it "returns an array with the keys in the order they were inserted" do
{}.keys.should == []
- {}.keys.should be_kind_of(Array)
+ {}.keys.should.is_a?(Array)
Hash.new(5).keys.should == []
Hash.new { 5 }.keys.should == []
{ 1 => 2, 4 => 8, 2 => 4 }.keys.should == [1, 4, 2]
- { 1 => 2, 2 => 4, 4 => 8 }.keys.should be_kind_of(Array)
+ { 1 => 2, 2 => 4, 4 => 8 }.keys.should.is_a?(Array)
{ nil => nil }.keys.should == [nil]
end
diff --git a/spec/ruby/core/hash/length_spec.rb b/spec/ruby/core/hash/length_spec.rb
index d0af0945df..325973306f 100644
--- a/spec/ruby/core/hash/length_spec.rb
+++ b/spec/ruby/core/hash/length_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Hash#length" do
- it_behaves_like :hash_length, :length
+ it "is an alias of Hash#size" do
+ Hash.instance_method(:size).should == Hash.instance_method(:length)
+ end
end
diff --git a/spec/ruby/core/hash/lt_spec.rb b/spec/ruby/core/hash/lt_spec.rb
index 2219615880..4ca326d077 100644
--- a/spec/ruby/core/hash/lt_spec.rb
+++ b/spec/ruby/core/hash/lt_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#<" do
it "returns false if both hashes are identical" do
h = { a: 1, b: 2 }
- (h < h).should be_false
+ (h < h).should == false
end
end
diff --git a/spec/ruby/core/hash/lte_spec.rb b/spec/ruby/core/hash/lte_spec.rb
index a166e5bca4..29e60273d1 100644
--- a/spec/ruby/core/hash/lte_spec.rb
+++ b/spec/ruby/core/hash/lte_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#<=" do
it "returns true if both hashes are identical" do
h = { a: 1, b: 2 }
- (h <= h).should be_true
+ (h <= h).should == true
end
end
diff --git a/spec/ruby/core/hash/member_spec.rb b/spec/ruby/core/hash/member_spec.rb
index 37c0414559..e7309c3f7d 100644
--- a/spec/ruby/core/hash/member_spec.rb
+++ b/spec/ruby/core/hash/member_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/key'
describe "Hash#member?" do
- it_behaves_like :hash_key_p, :member?
+ it "is an alias of Hash#include?" do
+ Hash.instance_method(:member?).should == Hash.instance_method(:include?)
+ end
end
diff --git a/spec/ruby/core/hash/merge_spec.rb b/spec/ruby/core/hash/merge_spec.rb
index 5521864297..9e566fcee9 100644
--- a/spec/ruby/core/hash/merge_spec.rb
+++ b/spec/ruby/core/hash/merge_spec.rb
@@ -1,7 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iteration'
-require_relative 'shared/update'
describe "Hash#merge" do
it "returns a new hash by combining self with the contents of other" do
@@ -30,7 +28,7 @@ describe "Hash#merge" do
-> {
h1.merge(h2) { |k, x, y| raise(IndexError) }
- }.should raise_error(IndexError)
+ }.should.raise(IndexError)
r = h1.merge(h1) { |k,x,y| :x }
r.should == { a: :x, b: :x, d: :x }
@@ -47,8 +45,8 @@ describe "Hash#merge" do
end
it "returns subclass instance for subclasses" do
- HashSpecs::MyHash[1 => 2, 3 => 4].merge({ 1 => 2 }).should be_an_instance_of(HashSpecs::MyHash)
- HashSpecs::MyHash[].merge({ 1 => 2 }).should be_an_instance_of(HashSpecs::MyHash)
+ HashSpecs::MyHash[1 => 2, 3 => 4].merge({ 1 => 2 }).should.instance_of?(HashSpecs::MyHash)
+ HashSpecs::MyHash[].merge({ 1 => 2 }).should.instance_of?(HashSpecs::MyHash)
{ 1 => 2, 3 => 4 }.merge(HashSpecs::MyHash[1 => 2]).class.should == Hash
{}.merge(HashSpecs::MyHash[1 => 2]).class.should == Hash
@@ -90,11 +88,36 @@ describe "Hash#merge" do
hash = { a: 1 }
merged = hash.merge
- merged.should eql(hash)
- merged.should_not equal(hash)
+ merged.should.eql?(hash)
+ merged.should_not.equal?(hash)
+ end
+
+ it "retains the default value" do
+ h = Hash.new(1)
+ h.merge(b: 1, d: 2).default.should == 1
+ end
+
+ it "retains the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.merge(b: 1, d: 2).default_proc.should == pr
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.merge(b: 1, d: 2)
+ h2.compare_by_identity?.should == true
+ end
+
+ it "ignores compare_by_identity flag of an argument" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = { b: 1, d: 2 }.merge(h)
+ h2.compare_by_identity?.should == false
end
end
describe "Hash#merge!" do
- it_behaves_like :hash_update, :merge!
+ it "is an alias of Hash#update" do
+ Hash.instance_method(:merge!).should == Hash.instance_method(:update)
+ end
end
diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb
index 5ae3e1f98d..207fc2931f 100644
--- a/spec/ruby/core/hash/new_spec.rb
+++ b/spec/ruby/core/hash/new_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+# Actually these are specs of Hash#initialize, there is no Hash.new it's just Class.new.
describe "Hash.new" do
it "creates an empty Hash if passed no arguments" do
Hash.new.should == {}
@@ -14,7 +15,7 @@ describe "Hash.new" do
it "does not create a copy of the default argument" do
str = "foo"
- Hash.new(str).default.should equal(str)
+ Hash.new(str).default.should.equal?(str)
end
it "creates a Hash with a default_proc if passed a block" do
@@ -26,22 +27,22 @@ describe "Hash.new" do
end
it "raises an ArgumentError if more than one argument is passed" do
- -> { Hash.new(5,6) }.should raise_error(ArgumentError)
+ -> { Hash.new(5,6) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed both default argument and default block" do
- -> { Hash.new(5) { 0 } }.should raise_error(ArgumentError)
- -> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError)
+ -> { Hash.new(5) { 0 } }.should.raise(ArgumentError)
+ -> { Hash.new(nil) { 0 } }.should.raise(ArgumentError)
end
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "emits a deprecation warning if keyword arguments are passed" do
-> { Hash.new(unknown: true) }.should complain(
Regexp.new(Regexp.escape("Calling Hash.new with keyword arguments is deprecated and will be removed in Ruby 3.4; use Hash.new({ key: value }) instead"))
)
- -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError)
- -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError)
+ -> { Hash.new(1, unknown: true) }.should.raise(ArgumentError)
+ -> { Hash.new(unknown: true) { 0 } }.should.raise(ArgumentError)
Hash.new({ unknown: true }).default.should == { unknown: true }
end
@@ -55,13 +56,13 @@ describe "Hash.new" do
end
it "ignores negative capacity" do
- -> { Hash.new(capacity: -42) }.should_not raise_error
+ -> { Hash.new(capacity: -42) }.should_not.raise
end
it "raises an error if unknown keyword arguments are passed" do
- -> { Hash.new(unknown: true) }.should raise_error(ArgumentError)
- -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError)
- -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError)
+ -> { Hash.new(unknown: true) }.should.raise(ArgumentError)
+ -> { Hash.new(1, unknown: true) }.should.raise(ArgumentError)
+ -> { Hash.new(unknown: true) { 0 } }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/hash/rassoc_spec.rb b/spec/ruby/core/hash/rassoc_spec.rb
index f3b2a6de20..73379f6867 100644
--- a/spec/ruby/core/hash/rassoc_spec.rb
+++ b/spec/ruby/core/hash/rassoc_spec.rb
@@ -6,7 +6,7 @@ describe "Hash#rassoc" do
end
it "returns an Array if the argument is a value of the Hash" do
- @h.rassoc(:green).should be_an_instance_of(Array)
+ @h.rassoc(:green).should.instance_of?(Array)
end
it "returns a 2-element Array if the argument is a value of the Hash" do
@@ -28,15 +28,15 @@ describe "Hash#rassoc" do
it "uses #== to compare the argument to the values" do
@h[:key] = 1.0
1.should == 1.0
- @h.rassoc(1).should eql [:key, 1.0]
+ @h.rassoc(1).should.eql? [:key, 1.0]
end
it "returns nil if the argument is not a value of the Hash" do
- @h.rassoc(:banana).should be_nil
+ @h.rassoc(:banana).should == nil
end
it "returns nil if the argument is not a value of the Hash even when there is a default" do
- Hash.new(42).merge!( foo: :bar ).rassoc(42).should be_nil
- Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).rassoc(42).should be_nil
+ Hash.new(42).merge!( foo: :bar ).rassoc(42).should == nil
+ Hash.new{|h, k| h[k] = 42}.merge!( foo: :bar ).rassoc(42).should == nil
end
end
diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb
index db3e91b166..fcd5a037bd 100644
--- a/spec/ruby/core/hash/rehash_spec.rb
+++ b/spec/ruby/core/hash/rehash_spec.rb
@@ -20,7 +20,7 @@ describe "Hash#rehash" do
h.keys.include?(k1).should == true
- h.rehash.should equal(h)
+ h.rehash.should.equal?(h)
h.key?(k1).should == true
h[k1].should == :v1
end
@@ -108,7 +108,7 @@ describe "Hash#rehash" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.rehash }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.rehash }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb
index dd8e817237..aa1a074897 100644
--- a/spec/ruby/core/hash/reject_spec.rb
+++ b/spec/ruby/core/hash/reject_spec.rb
@@ -28,8 +28,8 @@ describe "Hash#reject" do
context "with extra state" do
it "returns Hash instance for subclasses" do
- HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should be_kind_of(Hash)
- HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should be_kind_of(Hash)
+ HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should.is_a?(Hash)
+ HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should.is_a?(Hash)
end
end
@@ -44,6 +44,27 @@ describe "Hash#reject" do
reject_pairs.should == reject_bang_pairs
end
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.reject { false }.default.should == nil
+ h[:a] = 1
+ h.reject { false }.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.reject { false }.default_proc.should == nil
+ h[:a] = 1
+ h.reject { false }.default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.reject { |k, _| k == :a }
+ h2.compare_by_identity?.should == true
+ end
+
it_behaves_like :hash_iteration_no_block, :reject
it_behaves_like :enumeratorized_with_origin_size, :reject, { 1 => 2, 3 => 4, 5 => 6 }
end
@@ -58,7 +79,7 @@ describe "Hash#reject!" do
it "removes all entries if the block is true" do
h = { a: 1, b: 2, c: 3 }
- h.reject! { |k,v| true }.should equal(h)
+ h.reject! { |k,v| true }.should.equal?(h)
h.should == {}
end
@@ -83,11 +104,11 @@ describe "Hash#reject!" do
end
it "raises a FrozenError if called on a frozen instance that is modified" do
- -> { HashSpecs.empty_frozen_hash.reject! { true } }.should raise_error(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.reject! { true } }.should.raise(FrozenError)
end
it "raises a FrozenError if called on a frozen instance that would not be modified" do
- -> { HashSpecs.frozen_hash.reject! { false } }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.reject! { false } }.should.raise(FrozenError)
end
it_behaves_like :hash_iteration_no_block, :reject!
diff --git a/spec/ruby/core/hash/replace_spec.rb b/spec/ruby/core/hash/replace_spec.rb
index a26a31f5f9..4dacbf9779 100644
--- a/spec/ruby/core/hash/replace_spec.rb
+++ b/spec/ruby/core/hash/replace_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#replace" do
it "replaces the contents of self with other" do
h = { a: 1, b: 2 }
- h.replace(c: -1, d: -2).should equal(h)
+ h.replace(c: -1, d: -2).should.equal?(h)
h.should == { c: -1, d: -2 }
end
@@ -23,48 +23,57 @@ describe "Hash#replace" do
h.should == { 1 => 2 }
end
- it "transfers the compare_by_identity flag" do
- hash_a = { a: 1 }
- hash_b = { b: 2 }
- hash_b.compare_by_identity
- hash_a.should_not.compare_by_identity?
- hash_a.replace(hash_b)
- hash_a.should.compare_by_identity?
+ it "does not retain the default value" do
+ hash = Hash.new(1)
+ hash.replace(b: 2).default.should == nil
+ end
- hash_a = { a: 1 }
- hash_b = { b: 2 }
- hash_a.compare_by_identity
- hash_a.should.compare_by_identity?
- hash_a.replace(hash_b)
- hash_a.should_not.compare_by_identity?
+ it "transfers the default value of an argument" do
+ hash = Hash.new(1)
+ { a: 1 }.replace(hash).default.should == 1
end
- it "does not transfer default values" do
- hash_a = {}
- hash_b = Hash.new(5)
- hash_a.replace(hash_b)
- hash_a.default.should == 5
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ hash.replace(b: 2).default_proc.should == nil
+ end
- hash_a = {}
- hash_b = Hash.new { |h, k| k * 2 }
- hash_a.replace(hash_b)
- hash_a.default(5).should == 10
+ it "transfers the default_proc of an argument" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ { a: 1 }.replace(hash).default_proc.should == pr
+ end
+ it "does not call the default_proc of an argument" do
hash_a = Hash.new { |h, k| k * 5 }
hash_b = Hash.new(-> { raise "Should not invoke lambda" })
hash_a.replace(hash_b)
hash_a.default.should == hash_b.default
end
+ it "transfers compare_by_identity flag of an argument" do
+ h = { a: 1, c: 3 }
+ h2 = { b: 2, d: 4 }.compare_by_identity
+ h.replace(h2)
+ h.compare_by_identity?.should == true
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 1, c: 3 }.compare_by_identity
+ h.replace(b: 2, d: 4)
+ h.compare_by_identity?.should == false
+ end
+
it "raises a FrozenError if called on a frozen instance that would not be modified" do
-> do
HashSpecs.frozen_hash.replace(HashSpecs.frozen_hash)
- end.should raise_error(FrozenError)
+ end.should.raise(FrozenError)
end
it "raises a FrozenError if called on a frozen instance that is modified" do
-> do
HashSpecs.frozen_hash.replace(HashSpecs.empty_frozen_hash)
- end.should raise_error(FrozenError)
+ end.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
index 7dbb9c0a98..609a53f81f 100644
--- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
+++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
@@ -16,7 +16,7 @@ describe "Hash.ruby2_keywords_hash?" do
end
it "raises TypeError for non-Hash" do
- -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError)
+ -> { Hash.ruby2_keywords_hash?(nil) }.should.raise(TypeError)
end
end
@@ -54,7 +54,7 @@ describe "Hash.ruby2_keywords_hash" do
end
it "raises TypeError for non-Hash" do
- -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError)
+ -> { Hash.ruby2_keywords_hash(nil) }.should.raise(TypeError)
end
it "retains the default value" do
@@ -72,12 +72,10 @@ describe "Hash.ruby2_keywords_hash" do
Hash.ruby2_keywords_hash(hash).default_proc.should == pr
end
- ruby_version_is '3.3' do
- it "retains compare_by_identity_flag" do
- hash = {}.compare_by_identity
- Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
- hash[:a] = 1
- Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
- end
+ it "retains compare_by_identity_flag" do
+ hash = {}.compare_by_identity
+ Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
+ hash[:a] = 1
+ Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
end
end
diff --git a/spec/ruby/core/hash/select_spec.rb b/spec/ruby/core/hash/select_spec.rb
index 38b0180b0e..60b2ce67c1 100644
--- a/spec/ruby/core/hash/select_spec.rb
+++ b/spec/ruby/core/hash/select_spec.rb
@@ -1,10 +1,112 @@
require_relative '../../spec_helper'
-require_relative 'shared/select'
+require_relative '../enumerable/shared/enumeratorized'
+require_relative 'fixtures/classes'
+require_relative 'shared/iteration'
describe "Hash#select" do
- it_behaves_like :hash_select, :select
+ before :each do
+ @hsh = { 1 => 2, 3 => 4, 5 => 6 }
+ @empty = {}
+ end
+
+ it "yields two arguments: key and value" do
+ all_args = []
+ { 1 => 2, 3 => 4 }.select { |*args| all_args << args }
+ all_args.sort.should == [[1, 2], [3, 4]]
+ end
+
+ it "returns a Hash of entries for which block is true" do
+ a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.select { |k,v| v % 2 == 0 }
+ a_pairs.should.instance_of?(Hash)
+ a_pairs.sort.should == [['c', 4], ['d', 2]]
+ end
+
+ it "processes entries with the same order as reject" do
+ h = { a: 9, c: 4, b: 5, d: 2 }
+
+ select_pairs = []
+ reject_pairs = []
+ h.dup.select{ |*pair| select_pairs << pair }
+ h.reject { |*pair| reject_pairs << pair }
+
+ select_pairs.should == reject_pairs
+ end
+
+ it "returns an Enumerator when called on a non-empty hash without a block" do
+ @hsh.select.should.instance_of?(Enumerator)
+ end
+
+ it "returns an Enumerator when called on an empty hash without a block" do
+ @empty.select.should.instance_of?(Enumerator)
+ end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.select { true }.default.should == nil
+ h[:a] = 1
+ h.select { true }.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.select { true }.default_proc.should == nil
+ h[:a] = 1
+ h.select { true }.default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.select { |k, _| k == :a }
+ h2.compare_by_identity?.should == true
+ end
+
+ it_behaves_like :hash_iteration_no_block, :select
+
+ before :each do
+ @object = { 1 => 2, 3 => 4, 5 => 6 }
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :select
end
describe "Hash#select!" do
- it_behaves_like :hash_select!, :select!
+ before :each do
+ @hsh = { 1 => 2, 3 => 4, 5 => 6 }
+ @empty = {}
+ end
+
+ it "is equivalent to keep_if if changes are made" do
+ h = { a: 2 }
+ h.select! { |k,v| v <= 1 }.should.equal? h
+
+ h = { 1 => 2, 3 => 4 }
+ all_args_select = []
+ h.dup.select! { |*args| all_args_select << args }
+ all_args_select.should == [[1, 2], [3, 4]]
+ end
+
+ it "removes all entries if the block is false" do
+ h = { a: 1, b: 2, c: 3 }
+ h.select! { |k,v| false }.should.equal?(h)
+ h.should == {}
+ end
+
+ it "returns nil if no changes were made" do
+ { a: 1 }.select! { |k,v| v <= 1 }.should == nil
+ end
+
+ it "raises a FrozenError if called on an empty frozen instance" do
+ -> { HashSpecs.empty_frozen_hash.select! { false } }.should.raise(FrozenError)
+ end
+
+ it "raises a FrozenError if called on a frozen instance that would not be modified" do
+ -> { HashSpecs.frozen_hash.select! { true } }.should.raise(FrozenError)
+ end
+
+ it_behaves_like :hash_iteration_no_block, :select!
+
+ before :each do
+ @object = { 1 => 2, 3 => 4, 5 => 6 }
+ end
+ it_behaves_like :enumeratorized_with_origin_size, :select!
end
diff --git a/spec/ruby/core/hash/shared/comparison.rb b/spec/ruby/core/hash/shared/comparison.rb
index 07564e4cec..2b62837232 100644
--- a/spec/ruby/core/hash/shared/comparison.rb
+++ b/spec/ruby/core/hash/shared/comparison.rb
@@ -1,15 +1,15 @@
describe :hash_comparison, shared: true do
it "raises a TypeError if the right operand is not a hash" do
- -> { { a: 1 }.send(@method, 1) }.should raise_error(TypeError)
- -> { { a: 1 }.send(@method, nil) }.should raise_error(TypeError)
- -> { { a: 1 }.send(@method, []) }.should raise_error(TypeError)
+ -> { { a: 1 }.send(@method, 1) }.should.raise(TypeError)
+ -> { { a: 1 }.send(@method, nil) }.should.raise(TypeError)
+ -> { { a: 1 }.send(@method, []) }.should.raise(TypeError)
end
it "returns false if both hashes have the same keys but different values" do
h1 = { a: 1 }
h2 = { a: 2 }
- h1.send(@method, h2).should be_false
- h2.send(@method, h1).should be_false
+ h1.send(@method, h2).should == false
+ h2.send(@method, h1).should == false
end
end
diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb
deleted file mode 100644
index f9839ff58f..0000000000
--- a/spec/ruby/core/hash/shared/each.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-describe :hash_each, shared: true do
-
- # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair()
- it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do
- all_args = []
- { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args }
- all_args.sort.should == [[[1, 2]], [[3, 4]]]
- end
-
- it "yields the key and value of each pair to a block expecting |key, value|" do
- r = {}
- h = { a: 1, b: 2, c: 3, d: 5 }
- h.send(@method) { |k,v| r[k.to_s] = v.to_s }.should equal(h)
- r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" }
- end
-
- it "yields the key only to a block expecting |key,|" do
- ary = []
- h = { "a" => 1, "b" => 2, "c" => 3 }
- h.send(@method) { |k,| ary << k }
- ary.sort.should == ["a", "b", "c"]
- end
-
- it "always yields an Array of 2 elements, even when given a callable of arity 2" do
- obj = Object.new
- def obj.foo(key, value)
- end
-
- -> {
- { "a" => 1 }.send(@method, &obj.method(:foo))
- }.should raise_error(ArgumentError)
-
- -> {
- { "a" => 1 }.send(@method, &-> key, value { })
- }.should raise_error(ArgumentError)
- end
-
- it "yields an Array of 2 elements when given a callable of arity 1" do
- obj = Object.new
- def obj.foo(key_value)
- ScratchPad << key_value
- end
-
- ScratchPad.record([])
- { "a" => 1 }.send(@method, &obj.method(:foo))
- ScratchPad.recorded.should == [["a", 1]]
- end
-
- it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do
- obj = Object.new
- def obj.foo(key, value, extra)
- end
-
- -> {
- { "a" => 1 }.send(@method, &obj.method(:foo))
- }.should raise_error(ArgumentError)
- end
-
- it "uses the same order as keys() and values()" do
- h = { a: 1, b: 2, c: 3, d: 5 }
- keys = []
- values = []
-
- h.send(@method) do |k, v|
- keys << k
- values << v
- end
-
- keys.should == h.keys
- values.should == h.values
- end
-
- # Confirming the argument-splatting works from child class for both k, v and [k, v]
- it "properly expands (or not) child class's 'each'-yielded args" do
- cls1 = Class.new(Hash) do
- attr_accessor :k_v
- def each
- super do |k, v|
- @k_v = [k, v]
- yield k, v
- end
- end
- end
-
- cls2 = Class.new(Hash) do
- attr_accessor :k_v
- def each
- super do |k, v|
- @k_v = [k, v]
- yield([k, v])
- end
- end
- end
-
- obj1 = cls1.new
- obj1['a'] = 'b'
- obj1.map {|k, v| [k, v]}.should == [['a', 'b']]
- obj1.k_v.should == ['a', 'b']
-
- obj2 = cls2.new
- obj2['a'] = 'b'
- obj2.map {|k, v| [k, v]}.should == [['a', 'b']]
- obj2.k_v.should == ['a', 'b']
- end
-end
diff --git a/spec/ruby/core/hash/shared/eql.rb b/spec/ruby/core/hash/shared/eql.rb
index 68db49f76d..512e1ad016 100644
--- a/spec/ruby/core/hash/shared/eql.rb
+++ b/spec/ruby/core/hash/shared/eql.rb
@@ -3,7 +3,7 @@ describe :hash_eql, shared: true do
value = mock('x')
value.should_not_receive(:==)
value.should_not_receive(:eql?)
- { 1 => value }.send(@method, { 2 => value }).should be_false
+ { 1 => value }.send(@method, { 2 => value }).should == false
end
it "returns false when the numbers of keys differ without comparing any elements" do
@@ -13,8 +13,8 @@ describe :hash_eql, shared: true do
obj.should_not_receive(:==)
obj.should_not_receive(:eql?)
- {}.send(@method, h).should be_false
- h.send(@method, {}).should be_false
+ {}.send(@method, h).should == false
+ h.send(@method, {}).should == false
end
it "first compares keys via hash" do
@@ -23,7 +23,7 @@ describe :hash_eql, shared: true do
y = mock('y')
y.should_receive(:hash).any_number_of_times.and_return(0)
- { x => 1 }.send(@method, { y => 1 }).should be_false
+ { x => 1 }.send(@method, { y => 1 }).should == false
end
it "does not compare keys with different hash codes via eql?" do
@@ -35,39 +35,39 @@ describe :hash_eql, shared: true do
x.should_receive(:hash).any_number_of_times.and_return(0)
y.should_receive(:hash).any_number_of_times.and_return(1)
- { x => 1 }.send(@method, { y => 1 }).should be_false
+ { x => 1 }.send(@method, { y => 1 }).should == false
end
it "computes equality for recursive hashes" do
h = {}
h[:a] = h
- h.send(@method, h[:a]).should be_true
- (h == h[:a]).should be_true
+ h.send(@method, h[:a]).should == true
+ (h == h[:a]).should == true
end
it "doesn't call to_hash on objects" do
mock_hash = mock("fake hash")
def mock_hash.to_hash() {} end
- {}.send(@method, mock_hash).should be_false
+ {}.send(@method, mock_hash).should == false
end
it "computes equality for complex recursive hashes" do
a, b = {}, {}
a.merge! self: a, other: b
b.merge! self: b, other: a
- a.send(@method, b).should be_true # they both have the same structure!
+ a.send(@method, b).should == true # they both have the same structure!
c = {}
c.merge! other: c, self: c
- c.send(@method, a).should be_true # subtle, but they both have the same structure!
+ c.send(@method, a).should == true # subtle, but they both have the same structure!
a[:delta] = c[:delta] = a
- c.send(@method, a).should be_false # not quite the same structure, as a[:other][:delta] = nil
+ c.send(@method, a).should == false # not quite the same structure, as a[:other][:delta] = nil
c[:delta] = 42
- c.send(@method, a).should be_false
+ c.send(@method, a).should == false
a[:delta] = 42
- c.send(@method, a).should be_false
+ c.send(@method, a).should == false
b[:delta] = 42
- c.send(@method, a).should be_true
+ c.send(@method, a).should == true
end
it "computes equality for recursive hashes & arrays" do
@@ -76,19 +76,19 @@ describe :hash_eql, shared: true do
x << a
y << c
z << b
- b.send(@method, c).should be_true # they clearly have the same structure!
- y.send(@method, z).should be_true
- a.send(@method, b).should be_true # subtle, but they both have the same structure!
- x.send(@method, y).should be_true
+ b.send(@method, c).should == true # they clearly have the same structure!
+ y.send(@method, z).should == true
+ a.send(@method, b).should == true # subtle, but they both have the same structure!
+ x.send(@method, y).should == true
y << x
- y.send(@method, z).should be_false
+ y.send(@method, z).should == false
z << x
- y.send(@method, z).should be_true
+ y.send(@method, z).should == true
a[:foo], a[:bar] = a[:bar], a[:foo]
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
b[:bar] = b[:foo]
- b.send(@method, c).should be_false
+ b.send(@method, c).should == false
end
end
@@ -100,7 +100,7 @@ describe :hash_eql_additional, shared: true do
def y.==(o) false end
def x.eql?(o) false end
def y.eql?(o) false end
- { 1 => x }.send(@method, { 1 => y }).should be_false
+ { 1 => x }.send(@method, { 1 => y }).should == false
x = mock('x')
y = mock('y')
@@ -108,45 +108,45 @@ describe :hash_eql_additional, shared: true do
def y.==(o) true end
def x.eql?(o) true end
def y.eql?(o) true end
- { 1 => x }.send(@method, { 1 => y }).should be_true
+ { 1 => x }.send(@method, { 1 => y }).should == true
end
it "compares keys with eql? semantics" do
- { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should be_true
- { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should be_true
- { 1 => "x" }.send(@method, { 1.0 => "x" }).should be_false
- { 1.0 => "x" }.send(@method, { 1 => "x" }).should be_false
+ { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should == true
+ { 1.0 => "x" }.send(@method, { 1.0 => "x" }).should == true
+ { 1 => "x" }.send(@method, { 1.0 => "x" }).should == false
+ { 1.0 => "x" }.send(@method, { 1 => "x" }).should == false
end
it "returns true if and only if other Hash has the same number of keys and each key-value pair matches" do
a = { a: 5 }
b = {}
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
b[:a] = 5
- a.send(@method, b).should be_true
+ a.send(@method, b).should == true
not_supported_on :opal do
c = { "a" => 5 }
- a.send(@method, c).should be_false
+ a.send(@method, c).should == false
end
c = { "A" => 5 }
- a.send(@method, c).should be_false
+ a.send(@method, c).should == false
c = { a: 6 }
- a.send(@method, c).should be_false
+ a.send(@method, c).should == false
end
it "does not call to_hash on hash subclasses" do
- { 5 => 6 }.send(@method, HashSpecs::ToHashHash[5 => 6]).should be_true
+ { 5 => 6 }.send(@method, HashSpecs::ToHashHash[5 => 6]).should == true
end
it "ignores hash class differences" do
h = { 1 => 2, 3 => 4 }
- HashSpecs::MyHash[h].send(@method, h).should be_true
- HashSpecs::MyHash[h].send(@method, HashSpecs::MyHash[h]).should be_true
- h.send(@method, HashSpecs::MyHash[h]).should be_true
+ HashSpecs::MyHash[h].send(@method, h).should == true
+ HashSpecs::MyHash[h].send(@method, HashSpecs::MyHash[h]).should == true
+ h.send(@method, HashSpecs::MyHash[h]).should == true
end
# Why isn't this true of eql? too ?
@@ -163,7 +163,7 @@ describe :hash_eql_additional, shared: true do
obj
end
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false
+ { a[0] => 1 }.send(@method, { a[1] => 1 }).should == false
a = Array.new(2) do
obj = mock('0')
@@ -176,7 +176,7 @@ describe :hash_eql_additional, shared: true do
obj
end
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true
+ { a[0] => 1 }.send(@method, { a[1] => 1 }).should == true
end
it "compares the values in self to values in other hash" do
@@ -185,20 +185,20 @@ describe :hash_eql_additional, shared: true do
l_val.should_receive(:eql?).with(r_val).and_return(true)
- { 1 => l_val }.eql?({ 1 => r_val }).should be_true
+ { 1 => l_val }.eql?({ 1 => r_val }).should == true
end
end
describe :hash_eql_additional_more, shared: true do
it "returns true if other Hash has the same number of keys and each key-value pair matches, even though the default-value are not same" do
- Hash.new(5).send(@method, Hash.new(1)).should be_true
- Hash.new {|h, k| 1}.send(@method, Hash.new {}).should be_true
- Hash.new {|h, k| 1}.send(@method, Hash.new(2)).should be_true
+ Hash.new(5).send(@method, Hash.new(1)).should == true
+ Hash.new {|h, k| 1}.send(@method, Hash.new {}).should == true
+ Hash.new {|h, k| 1}.send(@method, Hash.new(2)).should == true
d = Hash.new {|h, k| 1}
e = Hash.new {}
d[1] = 2
e[1] = 2
- d.send(@method, e).should be_true
+ d.send(@method, e).should == true
end
end
diff --git a/spec/ruby/core/hash/shared/greater_than.rb b/spec/ruby/core/hash/shared/greater_than.rb
index 1f8b9fcfb7..dfe0b80250 100644
--- a/spec/ruby/core/hash/shared/greater_than.rb
+++ b/spec/ruby/core/hash/shared/greater_than.rb
@@ -5,11 +5,11 @@ describe :hash_greater_than, shared: true do
end
it "returns true if the other hash is a subset of self" do
- @h1.send(@method, @h2).should be_true
+ @h1.send(@method, @h2).should == true
end
it "returns false if the other hash is not a subset of self" do
- @h2.send(@method, @h1).should be_false
+ @h2.send(@method, @h1).should == false
end
it "converts the right operand to a hash before comparing" do
@@ -18,6 +18,6 @@ describe :hash_greater_than, shared: true do
{ a: 1, b: 2 }
end
- @h1.send(@method, o).should be_true
+ @h1.send(@method, o).should == true
end
end
diff --git a/spec/ruby/core/hash/shared/index.rb b/spec/ruby/core/hash/shared/index.rb
deleted file mode 100644
index 7f6a186464..0000000000
--- a/spec/ruby/core/hash/shared/index.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :hash_index, shared: true do
- it "returns the corresponding key for value" do
- suppress_warning do # for Hash#index
- { 2 => 'a', 1 => 'b' }.send(@method, 'b').should == 1
- end
- end
-
- it "returns nil if the value is not found" do
- suppress_warning do # for Hash#index
- { a: -1, b: 3.14, c: 2.718 }.send(@method, 1).should be_nil
- end
- end
-
- it "doesn't return default value if the value is not found" do
- suppress_warning do # for Hash#index
- Hash.new(5).send(@method, 5).should be_nil
- end
- end
-
- it "compares values using ==" do
- suppress_warning do # for Hash#index
- { 1 => 0 }.send(@method, 0.0).should == 1
- { 1 => 0.0 }.send(@method, 0).should == 1
- end
-
- needle = mock('needle')
- inhash = mock('inhash')
- inhash.should_receive(:==).with(needle).and_return(true)
-
- suppress_warning do # for Hash#index
- { 1 => inhash }.send(@method, needle).should == 1
- end
- end
-end
diff --git a/spec/ruby/core/hash/shared/iteration.rb b/spec/ruby/core/hash/shared/iteration.rb
index d27c2443f8..322e4b9a2f 100644
--- a/spec/ruby/core/hash/shared/iteration.rb
+++ b/spec/ruby/core/hash/shared/iteration.rb
@@ -5,15 +5,15 @@ describe :hash_iteration_no_block, shared: true do
end
it "returns an Enumerator if called on a non-empty hash without a block" do
- @hsh.send(@method).should be_an_instance_of(Enumerator)
+ @hsh.send(@method).should.instance_of?(Enumerator)
end
it "returns an Enumerator if called on an empty hash without a block" do
- @empty.send(@method).should be_an_instance_of(Enumerator)
+ @empty.send(@method).should.instance_of?(Enumerator)
end
it "returns an Enumerator if called on a frozen instance" do
@hsh.freeze
- @hsh.send(@method).should be_an_instance_of(Enumerator)
+ @hsh.send(@method).should.instance_of?(Enumerator)
end
end
diff --git a/spec/ruby/core/hash/shared/key.rb b/spec/ruby/core/hash/shared/key.rb
deleted file mode 100644
index 17f9f81457..0000000000
--- a/spec/ruby/core/hash/shared/key.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-describe :hash_key_p, shared: true do
- it "returns true if argument is a key" do
- h = { a: 1, b: 2, c: 3, 4 => 0 }
- h.send(@method, :a).should == true
- h.send(@method, :b).should == true
- h.send(@method, 2).should == false
- h.send(@method, 4).should == true
-
- not_supported_on :opal do
- h.send(@method, 'b').should == false
- h.send(@method, 4.0).should == false
- end
- end
-
- it "returns true if the key's matching value was nil" do
- { xyz: nil }.send(@method, :xyz).should == true
- end
-
- it "returns true if the key's matching value was false" do
- { xyz: false }.send(@method, :xyz).should == true
- end
-
- it "returns true if the key is nil" do
- { nil => 'b' }.send(@method, nil).should == true
- { nil => nil }.send(@method, nil).should == true
- end
-
- it "compares keys with the same #hash value via #eql?" do
- x = mock('x')
- x.stub!(:hash).and_return(42)
-
- y = mock('y')
- y.stub!(:hash).and_return(42)
- y.should_receive(:eql?).and_return(false)
-
- { x => nil }.send(@method, y).should == false
- end
-end
diff --git a/spec/ruby/core/hash/shared/length.rb b/spec/ruby/core/hash/shared/length.rb
deleted file mode 100644
index 24f5563759..0000000000
--- a/spec/ruby/core/hash/shared/length.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-describe :hash_length, shared: true do
- it "returns the number of entries" do
- { a: 1, b: 'c' }.send(@method).should == 2
- h = { a: 1, b: 2 }
- h[:a] = 2
- h.send(@method).should == 2
- { a: 1, b: 1, c: 1 }.send(@method).should == 3
- {}.send(@method).should == 0
- Hash.new(5).send(@method).should == 0
- Hash.new { 5 }.send(@method).should == 0
- end
-end
diff --git a/spec/ruby/core/hash/shared/less_than.rb b/spec/ruby/core/hash/shared/less_than.rb
index cdc6f14546..071b3e97bb 100644
--- a/spec/ruby/core/hash/shared/less_than.rb
+++ b/spec/ruby/core/hash/shared/less_than.rb
@@ -5,11 +5,11 @@ describe :hash_less_than, shared: true do
end
it "returns true if self is a subset of the other hash" do
- @h1.send(@method, @h2).should be_true
+ @h1.send(@method, @h2).should == true
end
it "returns false if self is not a subset of the other hash" do
- @h2.send(@method, @h1).should be_false
+ @h2.send(@method, @h1).should == false
end
it "converts the right operand to a hash before comparing" do
@@ -18,6 +18,6 @@ describe :hash_less_than, shared: true do
{ a: 1, b: 2, c: 3 }
end
- @h1.send(@method, o).should be_true
+ @h1.send(@method, o).should == true
end
end
diff --git a/spec/ruby/core/hash/shared/select.rb b/spec/ruby/core/hash/shared/select.rb
deleted file mode 100644
index 5170af50d6..0000000000
--- a/spec/ruby/core/hash/shared/select.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/iteration'
-require_relative '../../enumerable/shared/enumeratorized'
-
-describe :hash_select, shared: true do
- before :each do
- @hsh = { 1 => 2, 3 => 4, 5 => 6 }
- @empty = {}
- end
-
- it "yields two arguments: key and value" do
- all_args = []
- { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args }
- all_args.sort.should == [[1, 2], [3, 4]]
- end
-
- it "returns a Hash of entries for which block is true" do
- a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.send(@method) { |k,v| v % 2 == 0 }
- a_pairs.should be_an_instance_of(Hash)
- a_pairs.sort.should == [['c', 4], ['d', 2]]
- end
-
- it "processes entries with the same order as reject" do
- h = { a: 9, c: 4, b: 5, d: 2 }
-
- select_pairs = []
- reject_pairs = []
- h.dup.send(@method) { |*pair| select_pairs << pair }
- h.reject { |*pair| reject_pairs << pair }
-
- select_pairs.should == reject_pairs
- end
-
- it "returns an Enumerator when called on a non-empty hash without a block" do
- @hsh.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it "returns an Enumerator when called on an empty hash without a block" do
- @empty.send(@method).should be_an_instance_of(Enumerator)
- end
-
- it_should_behave_like :hash_iteration_no_block
-
- before :each do
- @object = { 1 => 2, 3 => 4, 5 => 6 }
- end
- it_should_behave_like :enumeratorized_with_origin_size
-end
-
-describe :hash_select!, shared: true do
- before :each do
- @hsh = { 1 => 2, 3 => 4, 5 => 6 }
- @empty = {}
- end
-
- it "is equivalent to keep_if if changes are made" do
- h = { a: 2 }
- h.send(@method) { |k,v| v <= 1 }.should equal h
-
- h = { 1 => 2, 3 => 4 }
- all_args_select = []
- h.dup.send(@method) { |*args| all_args_select << args }
- all_args_select.should == [[1, 2], [3, 4]]
- end
-
- it "removes all entries if the block is false" do
- h = { a: 1, b: 2, c: 3 }
- h.send(@method) { |k,v| false }.should equal(h)
- h.should == {}
- end
-
- it "returns nil if no changes were made" do
- { a: 1 }.send(@method) { |k,v| v <= 1 }.should == nil
- end
-
- it "raises a FrozenError if called on an empty frozen instance" do
- -> { HashSpecs.empty_frozen_hash.send(@method) { false } }.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError if called on a frozen instance that would not be modified" do
- -> { HashSpecs.frozen_hash.send(@method) { true } }.should raise_error(FrozenError)
- end
-
- it_should_behave_like :hash_iteration_no_block
-
- before :each do
- @object = { 1 => 2, 3 => 4, 5 => 6 }
- end
- it_should_behave_like :enumeratorized_with_origin_size
-end
diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb
deleted file mode 100644
index 72a462a42f..0000000000
--- a/spec/ruby/core/hash/shared/store.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :hash_store, shared: true do
- it "associates the key with the value and return the value" do
- h = { a: 1 }
- h.send(@method, :b, 2).should == 2
- h.should == { b:2, a:1 }
- end
-
- it "duplicates string keys using dup semantics" do
- # dup doesn't copy singleton methods
- key = +"foo"
- def key.reverse() "bar" end
- h = {}
- h.send(@method, key, 0)
- h.keys[0].reverse.should == "oof"
- end
-
- it "stores unequal keys that hash to the same value" do
- h = {}
- k1 = ["x"]
- k2 = ["y"]
- # So they end up in the same bucket
- k1.should_receive(:hash).and_return(0)
- k2.should_receive(:hash).and_return(0)
-
- h.send(@method, k1, 1)
- h.send(@method, k2, 2)
- h.size.should == 2
- end
-
- it "accepts keys with private #hash method" do
- key = HashSpecs::KeyWithPrivateHash.new
- h = {}
- h.send(@method, key, "foo")
- h[key].should == "foo"
- end
-
- it " accepts keys with an Integer hash" do
- o = mock(hash: 1 << 100)
- h = {}
- h[o] = 1
- h[o].should == 1
- end
-
- it "duplicates and freezes string keys" do
- key = +"foo"
- h = {}
- h.send(@method, key, 0)
- key << "bar"
-
- h.should == { "foo" => 0 }
- h.keys[0].should.frozen?
- end
-
- it "doesn't duplicate and freeze already frozen string keys" do
- key = "foo".freeze
- h = {}
- h.send(@method, key, 0)
- h.keys[0].should equal(key)
- end
-
- it "keeps the existing key in the hash if there is a matching one" do
- h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
- key1 = HashSpecs::ByValueKey.new(13)
- key2 = HashSpecs::ByValueKey.new(13)
- h[key1] = 41
- key_in_hash = h.keys.last
- key_in_hash.should equal(key1)
- h[key2] = 42
- last_key = h.keys.last
- last_key.should equal(key_in_hash)
- last_key.should_not equal(key2)
- end
-
- it "keeps the existing String key in the hash if there is a matching one" do
- h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
- key1 = "foo".dup
- key2 = "foo".dup
- key1.should_not equal(key2)
- h[key1] = 41
- frozen_key = h.keys.last
- frozen_key.should_not equal(key1)
- h[key2] = 42
- h.keys.last.should equal(frozen_key)
- h.keys.last.should_not equal(key2)
- end
-
- it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.send(@method, 1, 2) }.should raise_error(FrozenError)
- end
-
- it "does not raise an exception if changing the value of an existing key during iteration" do
- hash = {1 => 2, 3 => 4, 5 => 6}
- hash.each { hash.send(@method, 1, :foo) }
- hash.should == {1 => :foo, 3 => 4, 5 => 6}
- end
-
- it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do
- code = <<-EOC
- load '#{fixture __FILE__, "name.rb"}'
- hash = {}
- [true, false, 1, 2.0, "hello", :ok].each do |value|
- hash[value] = 42
- raise "incorrect value" unless hash[value] == 42
- hash[value] = 43
- raise "incorrect value" unless hash[value] == 43
- end
- puts "OK"
- puts hash.size
- EOC
- result = ruby_exe(code, args: "2>&1")
- result.should == "OK\n6\n"
- end
-end
diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb
deleted file mode 100644
index 5f0a8f97fd..0000000000
--- a/spec/ruby/core/hash/shared/to_s.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :hash_to_s, shared: true do
- it "returns a string representation with same order as each()" do
- h = { a: [1, 2], b: -2, d: -6, nil => nil }
- expected = ruby_version_is("3.4") ? "{a: [1, 2], b: -2, d: -6, nil => nil}" : "{:a=>[1, 2], :b=>-2, :d=>-6, nil=>nil}"
- h.send(@method).should == expected
- end
-
- it "calls #inspect on keys and values" do
- key = mock('key')
- val = mock('val')
- key.should_receive(:inspect).and_return('key')
- val.should_receive(:inspect).and_return('val')
- expected = ruby_version_is("3.4") ? "{key => val}" : "{key=>val}"
- { key => val }.send(@method).should == expected
- end
-
- it "does not call #to_s on a String returned from #inspect" do
- str = +"abc"
- str.should_not_receive(:to_s)
- expected = ruby_version_is("3.4") ? '{a: "abc"}' : '{:a=>"abc"}'
- { a: str }.send(@method).should == expected
- end
-
- it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
- obj = mock("Hash#inspect/to_s calls #to_s")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_return("abc")
- expected = ruby_version_is("3.4") ? "{a: abc}" : "{:a=>abc}"
- { a: obj }.send(@method).should == expected
- end
-
- it "does not call #to_str on the object returned from #inspect when it is not a String" do
- obj = mock("Hash#inspect/to_s does not call #to_str")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_not_receive(:to_str)
- expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
- { a: obj }.send(@method).should =~ expected_pattern
- end
-
- it "does not call #to_str on the object returned from #to_s when it is not a String" do
- obj = mock("Hash#inspect/to_s does not call #to_str on #to_s result")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_return(obj)
- obj.should_not_receive(:to_str)
- expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
- { a: obj }.send(@method).should =~ expected_pattern
- end
-
- it "does not swallow exceptions raised by #to_s" do
- obj = mock("Hash#inspect/to_s does not swallow #to_s exceptions")
- obj.should_receive(:inspect).and_return(obj)
- obj.should_receive(:to_s).and_raise(Exception)
-
- -> { { a: obj }.send(@method) }.should raise_error(Exception)
- end
-
- it "handles hashes with recursive values" do
- x = {}
- x[0] = x
- expected = ruby_version_is("3.4") ? '{0 => {...}}' : '{0=>{...}}'
- x.send(@method).should == expected
-
- x = {}
- y = {}
- x[0] = y
- y[1] = x
- expected_x = ruby_version_is("3.4") ? '{0 => {1 => {...}}}' : '{0=>{1=>{...}}}'
- expected_y = ruby_version_is("3.4") ? '{1 => {0 => {...}}}' : '{1=>{0=>{...}}}'
- x.send(@method).should == expected_x
- y.send(@method).should == expected_y
- end
-
- it "does not raise if inspected result is not default external encoding" do
- utf_16be = mock("utf_16be")
- utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
- expected = ruby_version_is("3.4") ? '{a: "utf_16be \u3042"}' : '{:a=>"utf_16be \u3042"}'
- {a: utf_16be}.send(@method).should == expected
- end
-
- it "works for keys and values whose #inspect return a frozen String" do
- expected = ruby_version_is("3.4") ? "{true => false}" : "{true=>false}"
- { true => false }.to_s.should == expected
- end
-end
diff --git a/spec/ruby/core/hash/shared/update.rb b/spec/ruby/core/hash/shared/update.rb
deleted file mode 100644
index 1b0eb809bf..0000000000
--- a/spec/ruby/core/hash/shared/update.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-describe :hash_update, shared: true do
- it "adds the entries from other, overwriting duplicate keys. Returns self" do
- h = { _1: 'a', _2: '3' }
- h.send(@method, _1: '9', _9: 2).should equal(h)
- h.should == { _1: "9", _2: "3", _9: 2 }
- end
-
- it "sets any duplicate key to the value of block if passed a block" do
- h1 = { a: 2, b: -1 }
- h2 = { a: -2, c: 1 }
- h1.send(@method, h2) { |k,x,y| 3.14 }.should equal(h1)
- h1.should == { c: 1, b: -1, a: 3.14 }
-
- h1.send(@method, h1) { nil }
- h1.should == { a: nil, b: nil, c: nil }
- end
-
- it "tries to convert the passed argument to a hash using #to_hash" do
- obj = mock('{1=>2}')
- obj.should_receive(:to_hash).and_return({ 1 => 2 })
- { 3 => 4 }.send(@method, obj).should == { 1 => 2, 3 => 4 }
- end
-
- it "does not call to_hash on hash subclasses" do
- { 3 => 4 }.send(@method, HashSpecs::ToHashHash[1 => 2]).should == { 1 => 2, 3 => 4 }
- end
-
- it "processes entries with same order as merge()" do
- h = { 1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => [] }
- merge_bang_pairs = []
- merge_pairs = []
- h.merge(h) { |*arg| merge_pairs << arg }
- h.send(@method, h) { |*arg| merge_bang_pairs << arg }
- merge_bang_pairs.should == merge_pairs
- end
-
- it "raises a FrozenError on a frozen instance that is modified" do
- -> do
- HashSpecs.frozen_hash.send(@method, 1 => 2)
- end.should raise_error(FrozenError)
- end
-
- it "checks frozen status before coercing an object with #to_hash" do
- obj = mock("to_hash frozen")
- # This is necessary because mock cleanup code cannot run on the frozen
- # object.
- def obj.to_hash() raise Exception, "should not receive #to_hash" end
- obj.freeze
-
- -> { HashSpecs.frozen_hash.send(@method, obj) }.should raise_error(FrozenError)
- end
-
- # see redmine #1571
- it "raises a FrozenError on a frozen instance that would not be modified" do
- -> do
- HashSpecs.frozen_hash.send(@method, HashSpecs.empty_frozen_hash)
- end.should raise_error(FrozenError)
- end
-
- it "does not raise an exception if changing the value of an existing key during iteration" do
- hash = {1 => 2, 3 => 4, 5 => 6}
- hash2 = {1 => :foo, 3 => :bar}
- hash.each { hash.send(@method, hash2) }
- hash.should == {1 => :foo, 3 => :bar, 5 => 6}
- end
-
- it "accepts multiple hashes" do
- result = { a: 1 }.send(@method, { b: 2 }, { c: 3 }, { d: 4 })
- result.should == { a: 1, b: 2, c: 3, d: 4 }
- end
-
- it "accepts zero arguments" do
- hash = { a: 1 }
- hash.send(@method).should eql(hash)
- end
-end
diff --git a/spec/ruby/core/hash/shared/value.rb b/spec/ruby/core/hash/shared/value.rb
deleted file mode 100644
index aac76c253e..0000000000
--- a/spec/ruby/core/hash/shared/value.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :hash_value_p, shared: true do
- it "returns true if the value exists in the hash" do
- { a: :b }.send(@method, :a).should == false
- { 1 => 2 }.send(@method, 2).should == true
- h = Hash.new(5)
- h.send(@method, 5).should == false
- h = Hash.new { 5 }
- h.send(@method, 5).should == false
- end
-
- it "uses == semantics for comparing values" do
- { 5 => 2.0 }.send(@method, 2).should == true
- end
-end
diff --git a/spec/ruby/core/hash/shared/values_at.rb b/spec/ruby/core/hash/shared/values_at.rb
deleted file mode 100644
index ef3b0e8ba0..0000000000
--- a/spec/ruby/core/hash/shared/values_at.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :hash_values_at, shared: true do
- it "returns an array of values for the given keys" do
- h = { a: 9, b: 'a', c: -10, d: nil }
- h.send(@method).should be_kind_of(Array)
- h.send(@method).should == []
- h.send(@method, :a, :d, :b).should be_kind_of(Array)
- h.send(@method, :a, :d, :b).should == [9, nil, 'a']
- end
-end
diff --git a/spec/ruby/core/hash/shift_spec.rb b/spec/ruby/core/hash/shift_spec.rb
index ea36488a04..6095d2e55f 100644
--- a/spec/ruby/core/hash/shift_spec.rb
+++ b/spec/ruby/core/hash/shift_spec.rb
@@ -8,7 +8,7 @@ describe "Hash#shift" do
h.size.times do |i|
r = h.shift
- r.should be_kind_of(Array)
+ r.should.is_a?(Array)
h2[r.first].should == r.last
h.size.should == h2.size - i - 1
end
@@ -30,45 +30,22 @@ describe "Hash#shift" do
h.should == {}
end
- ruby_version_is '3.2' do
- it "returns nil if the Hash is empty" do
- h = {}
- def h.default(key)
- raise
- end
- h.shift.should == nil
- end
- end
-
- ruby_version_is ''...'3.2' do
- it "calls #default with nil if the Hash is empty" do
- h = {}
- def h.default(key)
- key.should == nil
- :foo
- end
- h.shift.should == :foo
+ it "returns nil if the Hash is empty" do
+ h = {}
+ def h.default(key)
+ raise
end
+ h.shift.should == nil
end
it "returns nil from an empty hash" do
{}.shift.should == nil
end
- ruby_version_is '3.2' do
- it "returns nil for empty hashes with defaults and default procs" do
- Hash.new(5).shift.should == nil
- h = Hash.new { |*args| args }
- h.shift.should == nil
- end
- end
-
- ruby_version_is ''...'3.2' do
- it "returns (computed) default for empty hashes" do
- Hash.new(5).shift.should == 5
- h = Hash.new { |*args| args }
- h.shift.should == [h, nil]
- end
+ it "returns nil for empty hashes with defaults and default procs" do
+ Hash.new(5).shift.should == nil
+ h = Hash.new { |*args| args }
+ h.shift.should == nil
end
it "preserves Hash invariants when removing the last item" do
@@ -80,8 +57,8 @@ describe "Hash#shift" do
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.shift }.should raise_error(FrozenError)
- -> { HashSpecs.empty_frozen_hash.shift }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.shift }.should.raise(FrozenError)
+ -> { HashSpecs.empty_frozen_hash.shift }.should.raise(FrozenError)
end
it "works when the hash is at capacity" do
diff --git a/spec/ruby/core/hash/size_spec.rb b/spec/ruby/core/hash/size_spec.rb
index 1e8abd8d97..5e5008a5dc 100644
--- a/spec/ruby/core/hash/size_spec.rb
+++ b/spec/ruby/core/hash/size_spec.rb
@@ -1,7 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/length'
describe "Hash#size" do
- it_behaves_like :hash_length, :size
+ it "returns the number of entries" do
+ { a: 1, b: 'c' }.size.should == 2
+ h = { a: 1, b: 2 }
+ h[:a] = 2
+ h.size.should == 2
+ { a: 1, b: 1, c: 1 }.size.should == 3
+ {}.size.should == 0
+ Hash.new(5).size.should == 0
+ Hash.new { 5 }.size.should == 0
+ end
end
diff --git a/spec/ruby/core/hash/slice_spec.rb b/spec/ruby/core/hash/slice_spec.rb
index e3046d83d7..fd93254517 100644
--- a/spec/ruby/core/hash/slice_spec.rb
+++ b/spec/ruby/core/hash/slice_spec.rb
@@ -7,8 +7,8 @@ describe "Hash#slice" do
it "returns a new empty hash without arguments" do
ret = @hash.slice
- ret.should_not equal(@hash)
- ret.should be_an_instance_of(Hash)
+ ret.should_not.equal?(@hash)
+ ret.should.instance_of?(Hash)
ret.should == {}
end
@@ -50,4 +50,25 @@ describe "Hash#slice" do
ScratchPad.recorded.should == []
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.slice(:a).default.should == nil
+ h[:a] = 1
+ h.slice(:a).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.slice(:a).default_proc.should == nil
+ h[:a] = 1
+ h.slice(:a).default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.slice(:a)
+ h2.compare_by_identity?.should == true
+ end
end
diff --git a/spec/ruby/core/hash/store_spec.rb b/spec/ruby/core/hash/store_spec.rb
index 7e975380ec..7017d8ba2b 100644
--- a/spec/ruby/core/hash/store_spec.rb
+++ b/spec/ruby/core/hash/store_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/store'
describe "Hash#store" do
- it_behaves_like :hash_store, :store
+ it "is an alias of Hash#[]=" do
+ Hash.instance_method(:store).should == Hash.instance_method(:[]=)
+ end
end
diff --git a/spec/ruby/core/hash/to_a_spec.rb b/spec/ruby/core/hash/to_a_spec.rb
index 5baf677929..8c638db6c3 100644
--- a/spec/ruby/core/hash/to_a_spec.rb
+++ b/spec/ruby/core/hash/to_a_spec.rb
@@ -10,7 +10,7 @@ describe "Hash#to_a" do
pairs << [key, value]
end
- h.to_a.should be_kind_of(Array)
+ h.to_a.should.is_a?(Array)
h.to_a.should == pairs
end
@@ -23,7 +23,7 @@ describe "Hash#to_a" do
end
ent = h.entries
- ent.should be_kind_of(Array)
+ ent.should.is_a?(Array)
ent.should == pairs
end
end
diff --git a/spec/ruby/core/hash/to_h_spec.rb b/spec/ruby/core/hash/to_h_spec.rb
index e17ca7e671..5d5a280dac 100644
--- a/spec/ruby/core/hash/to_h_spec.rb
+++ b/spec/ruby/core/hash/to_h_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#to_h" do
it "returns self for Hash instances" do
h = {}
- h.to_h.should equal(h)
+ h.to_h.should.equal?(h)
end
describe "when called on a subclass of Hash" do
@@ -14,22 +14,27 @@ describe "Hash#to_h" do
end
it "returns a new Hash instance" do
- @h.to_h.should be_an_instance_of(Hash)
+ @h.to_h.should.instance_of?(Hash)
@h.to_h.should == @h
@h[:foo].should == :bar
end
- it "copies the default" do
+ it "retains the default" do
@h.default = 42
@h.to_h.default.should == 42
@h[:hello].should == 42
end
- it "copies the default_proc" do
+ it "retains the default_proc" do
@h.default_proc = prc = Proc.new{ |h, k| h[k] = 2 * k }
@h.to_h.default_proc.should == prc
@h[42].should == 84
end
+
+ it "retains compare_by_identity flag" do
+ @h.compare_by_identity
+ @h.to_h.compare_by_identity?.should == true
+ end
end
context "with block" do
@@ -50,17 +55,17 @@ describe "Hash#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
{ a: 1, b: 2 }.to_h { |k, v| [k.to_s, v*v, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
{ a: 1, b: 2 }.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
{ a: 1, b: 2 }.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -76,7 +81,26 @@ describe "Hash#to_h" do
-> do
{ a: 1 }.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
+ end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.default_proc.should == nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.compare_by_identity?.should == false
end
end
end
diff --git a/spec/ruby/core/hash/to_hash_spec.rb b/spec/ruby/core/hash/to_hash_spec.rb
index f479fa1fb2..f5622b3d9c 100644
--- a/spec/ruby/core/hash/to_hash_spec.rb
+++ b/spec/ruby/core/hash/to_hash_spec.rb
@@ -4,11 +4,11 @@ require_relative 'fixtures/classes'
describe "Hash#to_hash" do
it "returns self for Hash instances" do
h = {}
- h.to_hash.should equal(h)
+ h.to_hash.should.equal?(h)
end
it "returns self for instances of subclasses of Hash" do
h = HashSpecs::MyHash.new
- h.to_hash.should equal(h)
+ h.to_hash.should.equal?(h)
end
end
diff --git a/spec/ruby/core/hash/to_proc_spec.rb b/spec/ruby/core/hash/to_proc_spec.rb
index 9dbc79e5eb..bc4756600d 100644
--- a/spec/ruby/core/hash/to_proc_spec.rb
+++ b/spec/ruby/core/hash/to_proc_spec.rb
@@ -11,7 +11,7 @@ describe "Hash#to_proc" do
end
it "returns an instance of Proc" do
- @hash.to_proc.should be_an_instance_of Proc
+ @hash.to_proc.should.instance_of? Proc
end
describe "the returned proc" do
@@ -30,22 +30,22 @@ describe "Hash#to_proc" do
it "raises ArgumentError if not passed exactly one argument" do
-> {
@proc.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@proc.call 1, 2
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
context "with a stored key" do
it "returns the paired value" do
- @proc.call(@key).should equal(@value)
+ @proc.call(@key).should.equal?(@value)
end
end
context "passed as a block" do
it "retrieves the hash's values" do
- [@key].map(&@proc)[0].should equal(@value)
+ [@key].map(&@proc)[0].should.equal?(@value)
end
context "to instance_exec" do
@@ -63,7 +63,7 @@ describe "Hash#to_proc" do
context "with no stored key" do
it "returns nil" do
- @proc.call(@unstored).should be_nil
+ @proc.call(@unstored).should == nil
end
context "when the hash has a default value" do
@@ -72,7 +72,7 @@ describe "Hash#to_proc" do
end
it "returns the default value" do
- @proc.call(@unstored).should equal(@default)
+ @proc.call(@unstored).should.equal?(@default)
end
end
@@ -85,7 +85,7 @@ describe "Hash#to_proc" do
end
it "raises an ArgumentError when calling #call on the Proc with no arguments" do
- -> { @hash.to_proc.call }.should raise_error(ArgumentError)
+ -> { @hash.to_proc.call }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/hash/to_s_spec.rb b/spec/ruby/core/hash/to_s_spec.rb
index e52b09962e..2915db6ef8 100644
--- a/spec/ruby/core/hash/to_s_spec.rb
+++ b/spec/ruby/core/hash/to_s_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/to_s'
describe "Hash#to_s" do
- it_behaves_like :hash_to_s, :to_s
+ it "is an alias of Hash#inspect" do
+ Hash.instance_method(:to_s).should == Hash.instance_method(:inspect)
+ end
end
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index f63d39ecc8..d37a2b8616 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -7,8 +7,8 @@ describe "Hash#transform_keys" do
it "returns new hash" do
ret = @hash.transform_keys(&:succ)
- ret.should_not equal(@hash)
- ret.should be_an_instance_of(Hash)
+ ret.should_not.equal?(@hash)
+ ret.should.instance_of?(Hash)
end
it "sets the result as transformed keys with the given block" do
@@ -22,13 +22,13 @@ describe "Hash#transform_keys" do
it "makes both hashes to share values" do
value = [1, 2, 3]
new_hash = { a: value }.transform_keys(&:upcase)
- new_hash[:A].should equal(value)
+ new_hash[:A].should.equal?(value)
end
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_keys
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:succ).should == { b: 1, c: 2, d: 3 }
end
@@ -54,6 +54,27 @@ describe "Hash#transform_keys" do
it "allows a combination of hash and block argument" do
@hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.transform_keys(&:succ).default.should == nil
+ h[:a] = 1
+ h.transform_keys(&:succ).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.transform_values(&:succ).default_proc.should == nil
+ h[:a] = 1
+ h.transform_values(&:succ).default_proc.should == nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.transform_keys(&:succ)
+ h2.compare_by_identity?.should == false
+ end
end
describe "Hash#transform_keys!" do
@@ -63,7 +84,7 @@ describe "Hash#transform_keys!" do
end
it "returns self" do
- @hash.transform_keys!(&:succ).should equal(@hash)
+ @hash.transform_keys!(&:succ).should.equal?(@hash)
end
it "updates self as transformed values with the given block" do
@@ -91,7 +112,7 @@ describe "Hash#transform_keys!" do
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_keys!
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:upcase).should == { A: 1, B: 2, C: 3, D: 4 }
end
@@ -108,21 +129,21 @@ describe "Hash#transform_keys!" do
end
it "raises a FrozenError on an empty hash" do
- ->{ {}.freeze.transform_keys!(&:upcase) }.should raise_error(FrozenError)
+ ->{ {}.freeze.transform_keys!(&:upcase) }.should.raise(FrozenError)
end
it "keeps pairs and raises a FrozenError" do
- ->{ @hash.transform_keys!(&:upcase) }.should raise_error(FrozenError)
+ ->{ @hash.transform_keys!(&:upcase) }.should.raise(FrozenError)
@hash.should == @initial_pairs
end
it "raises a FrozenError on hash argument" do
- ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
+ ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should.raise(FrozenError)
end
context "when no block is given" do
it "does not raise an exception" do
- @hash.transform_keys!.should be_an_instance_of(Enumerator)
+ @hash.transform_keys!.should.instance_of?(Enumerator)
end
end
end
diff --git a/spec/ruby/core/hash/transform_values_spec.rb b/spec/ruby/core/hash/transform_values_spec.rb
index acb469416a..b19543a9f4 100644
--- a/spec/ruby/core/hash/transform_values_spec.rb
+++ b/spec/ruby/core/hash/transform_values_spec.rb
@@ -7,8 +7,8 @@ describe "Hash#transform_values" do
it "returns new hash" do
ret = @hash.transform_values(&:succ)
- ret.should_not equal(@hash)
- ret.should be_an_instance_of(Hash)
+ ret.should_not.equal?(@hash)
+ ret.should.instance_of?(Hash)
end
it "sets the result as transformed values with the given block" do
@@ -19,13 +19,13 @@ describe "Hash#transform_values" do
key = [1, 2, 3]
new_hash = { key => 1 }.transform_values(&:succ)
new_hash[key].should == 2
- new_hash.keys[0].should equal(key)
+ new_hash.keys[0].should.equal?(key)
end
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_values
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:succ).should == { a: 2, b: 3, c: 4 }
end
@@ -39,6 +39,27 @@ describe "Hash#transform_values" do
r[:foo].should == 84
r.class.should == Hash
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.transform_values(&:succ).default.should == nil
+ h[:a] = 1
+ h.transform_values(&:succ).default.should == nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.transform_values(&:succ).default_proc.should == nil
+ h[:a] = 1
+ h.transform_values(&:succ).default_proc.should == nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.transform_values(&:succ)
+ h2.compare_by_identity?.should == true
+ end
end
describe "Hash#transform_values!" do
@@ -48,7 +69,7 @@ describe "Hash#transform_values!" do
end
it "returns self" do
- @hash.transform_values!(&:succ).should equal(@hash)
+ @hash.transform_values!(&:succ).should.equal?(@hash)
end
it "updates self as transformed values with the given block" do
@@ -67,7 +88,7 @@ describe "Hash#transform_values!" do
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_values!
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
enumerator.size.should == @hash.size
enumerator.each(&:succ)
@hash.should == { a: 2, b: 3, c: 4 }
@@ -80,17 +101,17 @@ describe "Hash#transform_values!" do
end
it "raises a FrozenError on an empty hash" do
- ->{ {}.freeze.transform_values!(&:succ) }.should raise_error(FrozenError)
+ ->{ {}.freeze.transform_values!(&:succ) }.should.raise(FrozenError)
end
it "keeps pairs and raises a FrozenError" do
- ->{ @hash.transform_values!(&:succ) }.should raise_error(FrozenError)
+ ->{ @hash.transform_values!(&:succ) }.should.raise(FrozenError)
@hash.should == @initial_pairs
end
context "when no block is given" do
it "does not raise an exception" do
- @hash.transform_values!.should be_an_instance_of(Enumerator)
+ @hash.transform_values!.should.instance_of?(Enumerator)
end
end
end
diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb
index d359ae49d8..c321183356 100644
--- a/spec/ruby/core/hash/try_convert_spec.rb
+++ b/spec/ruby/core/hash/try_convert_spec.rb
@@ -4,47 +4,47 @@ require_relative 'fixtures/classes'
describe "Hash.try_convert" do
it "returns the argument if it's a Hash" do
x = Hash.new
- Hash.try_convert(x).should equal(x)
+ Hash.try_convert(x).should.equal?(x)
end
it "returns the argument if it's a kind of Hash" do
x = HashSpecs::MyHash.new
- Hash.try_convert(x).should equal(x)
+ Hash.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_hash" do
- Hash.try_convert(Object.new).should be_nil
+ Hash.try_convert(Object.new).should == nil
end
it "sends #to_hash to the argument and returns the result if it's nil" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(nil)
- Hash.try_convert(obj).should be_nil
+ Hash.try_convert(obj).should == nil
end
it "sends #to_hash to the argument and returns the result if it's a Hash" do
x = Hash.new
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(x)
- Hash.try_convert(obj).should equal(x)
+ Hash.try_convert(obj).should.equal?(x)
end
it "sends #to_hash to the argument and returns the result if it's a kind of Hash" do
x = HashSpecs::MyHash.new
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(x)
- Hash.try_convert(obj).should equal(x)
+ Hash.try_convert(obj).should.equal?(x)
end
it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(Object.new)
- -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)")
+ -> { Hash.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into Hash (MockObject#to_hash gives Object)")
end
it "does not rescue exceptions raised by #to_hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_raise(RuntimeError)
- -> { Hash.try_convert obj }.should raise_error(RuntimeError)
+ -> { Hash.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/hash/update_spec.rb b/spec/ruby/core/hash/update_spec.rb
index 0975045ad1..f3a3e6b4db 100644
--- a/spec/ruby/core/hash/update_spec.rb
+++ b/spec/ruby/core/hash/update_spec.rb
@@ -1,7 +1,79 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/update'
describe "Hash#update" do
- it_behaves_like :hash_update, :update
+ it "adds the entries from other, overwriting duplicate keys. Returns self" do
+ h = { _1: 'a', _2: '3' }
+ h.update(_1: '9', _9: 2).should.equal?(h)
+ h.should == { _1: "9", _2: "3", _9: 2 }
+ end
+
+ it "sets any duplicate key to the value of block if passed a block" do
+ h1 = { a: 2, b: -1 }
+ h2 = { a: -2, c: 1 }
+ h1.update(h2) { |k,x,y| 3.14 }.should.equal?(h1)
+ h1.should == { c: 1, b: -1, a: 3.14 }
+
+ h1.update(h1) { nil }
+ h1.should == { a: nil, b: nil, c: nil }
+ end
+
+ it "tries to convert the passed argument to a hash using #to_hash" do
+ obj = mock('{1=>2}')
+ obj.should_receive(:to_hash).and_return({ 1 => 2 })
+ { 3 => 4 }.update(obj).should == { 1 => 2, 3 => 4 }
+ end
+
+ it "does not call to_hash on hash subclasses" do
+ { 3 => 4 }.update(HashSpecs::ToHashHash[1 => 2]).should == { 1 => 2, 3 => 4 }
+ end
+
+ it "processes entries with same order as merge()" do
+ h = { 1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => [] }
+ merge_bang_pairs = []
+ merge_pairs = []
+ h.merge(h) { |*arg| merge_pairs << arg }
+ h.update(h) { |*arg| merge_bang_pairs << arg }
+ merge_bang_pairs.should == merge_pairs
+ end
+
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> do
+ HashSpecs.frozen_hash.update(1 => 2)
+ end.should.raise(FrozenError)
+ end
+
+ it "checks frozen status before coercing an object with #to_hash" do
+ obj = mock("to_hash frozen")
+ # This is necessary because mock cleanup code cannot run on the frozen
+ # object.
+ def obj.to_hash() raise Exception, "should not receive #to_hash" end
+ obj.freeze
+
+ -> { HashSpecs.frozen_hash.update(obj) }.should.raise(FrozenError)
+ end
+
+ # see redmine #1571
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> do
+ HashSpecs.frozen_hash.update(HashSpecs.empty_frozen_hash)
+ end.should.raise(FrozenError)
+ end
+
+ it "does not raise an exception if changing the value of an existing key during iteration" do
+ hash = {1 => 2, 3 => 4, 5 => 6}
+ hash2 = {1 => :foo, 3 => :bar}
+ hash.each { hash.update(hash2) }
+ hash.should == {1 => :foo, 3 => :bar, 5 => 6}
+ end
+
+ it "accepts multiple hashes" do
+ result = { a: 1 }.update({ b: 2 }, { c: 3 }, { d: 4 })
+ result.should == { a: 1, b: 2, c: 3, d: 4 }
+ end
+
+ it "accepts zero arguments" do
+ hash = { a: 1 }
+ hash.update.should.eql?(hash)
+ end
end
diff --git a/spec/ruby/core/hash/value_spec.rb b/spec/ruby/core/hash/value_spec.rb
index 0ab16a5d1b..9cfbe576d2 100644
--- a/spec/ruby/core/hash/value_spec.rb
+++ b/spec/ruby/core/hash/value_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/value'
describe "Hash#value?" do
- it_behaves_like :hash_value_p, :value?
+ it "is an alias of Hash#has_value?" do
+ Hash.instance_method(:value?).should == Hash.instance_method(:has_value?)
+ end
end
diff --git a/spec/ruby/core/hash/values_at_spec.rb b/spec/ruby/core/hash/values_at_spec.rb
index b620a279ba..78dcd8df6a 100644
--- a/spec/ruby/core/hash/values_at_spec.rb
+++ b/spec/ruby/core/hash/values_at_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/values_at'
describe "Hash#values_at" do
- it_behaves_like :hash_values_at, :values_at
+ it "returns an array of values for the given keys" do
+ h = { a: 9, b: 'a', c: -10, d: nil }
+ h.values_at.should.is_a?(Array)
+ h.values_at.should == []
+ h.values_at(:a, :d, :b).should.is_a?(Array)
+ h.values_at(:a, :d, :b).should == [9, nil, 'a']
+ end
end
diff --git a/spec/ruby/core/hash/values_spec.rb b/spec/ruby/core/hash/values_spec.rb
index 9f2a481a48..1fe5f48ad6 100644
--- a/spec/ruby/core/hash/values_spec.rb
+++ b/spec/ruby/core/hash/values_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Hash#values" do
it "returns an array of values" do
h = { 1 => :a, 'a' => :a, 'the' => 'lang' }
- h.values.should be_kind_of(Array)
+ h.values.should.is_a?(Array)
h.values.sort {|a, b| a.to_s <=> b.to_s}.should == [:a, :a, 'lang']
end
end
diff --git a/spec/ruby/core/integer/allbits_spec.rb b/spec/ruby/core/integer/allbits_spec.rb
index edce4b15e7..6023cc32bf 100644
--- a/spec/ruby/core/integer/allbits_spec.rb
+++ b/spec/ruby/core/integer/allbits_spec.rb
@@ -30,8 +30,8 @@ describe "Integer#allbits?" do
-> {
(obj = mock('10')).should_receive(:coerce).any_number_of_times.and_return([42,10])
13.allbits?(obj)
- }.should raise_error(TypeError)
- -> { 13.allbits?("10") }.should raise_error(TypeError)
- -> { 13.allbits?(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.allbits?("10") }.should.raise(TypeError)
+ -> { 13.allbits?(:symbol) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/anybits_spec.rb b/spec/ruby/core/integer/anybits_spec.rb
index e0449074a2..1ea47b76dc 100644
--- a/spec/ruby/core/integer/anybits_spec.rb
+++ b/spec/ruby/core/integer/anybits_spec.rb
@@ -29,8 +29,8 @@ describe "Integer#anybits?" do
-> {
(obj = mock('10')).should_receive(:coerce).any_number_of_times.and_return([42,10])
13.anybits?(obj)
- }.should raise_error(TypeError)
- -> { 13.anybits?("10") }.should raise_error(TypeError)
- -> { 13.anybits?(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.anybits?("10") }.should.raise(TypeError)
+ -> { 13.anybits?(:symbol) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb
index e7face39ac..4098ad7c7b 100644
--- a/spec/ruby/core/integer/bit_and_spec.rb
+++ b/spec/ruby/core/integer/bit_and_spec.rb
@@ -35,14 +35,14 @@ describe "Integer#&" do
end
it "raises a TypeError when passed a Float" do
- -> { (3 & 3.4) }.should raise_error(TypeError)
+ -> { (3 & 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("fixnum bit and")
obj.should_not_receive(:to_int)
- -> { 3 & obj }.should raise_error(TypeError)
+ -> { 3 & obj }.should.raise(TypeError)
end
end
@@ -84,14 +84,14 @@ describe "Integer#&" do
end
it "raises a TypeError when passed a Float" do
- -> { (@bignum & 3.4) }.should raise_error(TypeError)
+ -> { (@bignum & 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("bignum bit and")
obj.should_not_receive(:to_int)
- -> { @bignum & obj }.should raise_error(TypeError)
+ -> { @bignum & obj }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/bit_or_spec.rb b/spec/ruby/core/integer/bit_or_spec.rb
index fdf8a191e5..c380cd729e 100644
--- a/spec/ruby/core/integer/bit_or_spec.rb
+++ b/spec/ruby/core/integer/bit_or_spec.rb
@@ -36,14 +36,14 @@ describe "Integer#|" do
end
it "raises a TypeError when passed a Float" do
- -> { (3 | 3.4) }.should raise_error(TypeError)
+ -> { (3 | 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("integer bit or")
obj.should_not_receive(:to_int)
- -> { 3 | obj }.should raise_error(TypeError)
+ -> { 3 | obj }.should.raise(TypeError)
end
end
@@ -74,16 +74,16 @@ describe "Integer#|" do
not_supported_on :opal do
-> {
bignum_value | bignum_value(0xffff).to_f
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
- -> { @bignum | 9.9 }.should raise_error(TypeError)
+ -> { @bignum | 9.9 }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("bignum bit or")
obj.should_not_receive(:to_int)
- -> { @bignum | obj }.should raise_error(TypeError)
+ -> { @bignum | obj }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/bit_xor_spec.rb b/spec/ruby/core/integer/bit_xor_spec.rb
index 1f46bc52f3..c0cf8405f7 100644
--- a/spec/ruby/core/integer/bit_xor_spec.rb
+++ b/spec/ruby/core/integer/bit_xor_spec.rb
@@ -34,14 +34,14 @@ describe "Integer#^" do
end
it "raises a TypeError when passed a Float" do
- -> { (3 ^ 3.4) }.should raise_error(TypeError)
+ -> { (3 ^ 3.4) }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("integer bit xor")
obj.should_not_receive(:to_int)
- -> { 3 ^ obj }.should raise_error(TypeError)
+ -> { 3 ^ obj }.should.raise(TypeError)
end
end
@@ -78,16 +78,16 @@ describe "Integer#^" do
not_supported_on :opal do
-> {
bignum_value ^ bignum_value(0xffff).to_f
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
- -> { @bignum ^ 14.5 }.should raise_error(TypeError)
+ -> { @bignum ^ 14.5 }.should.raise(TypeError)
end
it "raises a TypeError and does not call #to_int when defined on an object" do
obj = mock("bignum bit xor")
obj.should_not_receive(:to_int)
- -> { @bignum ^ obj }.should raise_error(TypeError)
+ -> { @bignum ^ obj }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/ceil_spec.rb b/spec/ruby/core/integer/ceil_spec.rb
index eb633fba78..395be58fbd 100644
--- a/spec/ruby/core/integer/ceil_spec.rb
+++ b/spec/ruby/core/integer/ceil_spec.rb
@@ -10,15 +10,4 @@ describe "Integer#ceil" do
context "with precision" do
it_behaves_like :integer_ceil_precision, :Integer
end
-
- context "precision argument specified as part of the ceil method is negative" do
- it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do
- 18.ceil(-1).should eql(20)
- 18.ceil(-2).should eql(100)
- 18.ceil(-3).should eql(1000)
- -1832.ceil(-1).should eql(-1830)
- -1832.ceil(-2).should eql(-1800)
- -1832.ceil(-3).should eql(-1000)
- end
- end
end
diff --git a/spec/ruby/core/integer/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb
index 18d07c66d0..91f63832f8 100644
--- a/spec/ruby/core/integer/ceildiv_spec.rb
+++ b/spec/ruby/core/integer/ceildiv_spec.rb
@@ -1,22 +1,20 @@
require_relative '../../spec_helper'
describe "Integer#ceildiv" do
- ruby_version_is '3.2' do
- it "returns a quotient of division which is rounded up to the nearest integer" do
- 0.ceildiv(3).should eql(0)
- 1.ceildiv(3).should eql(1)
- 3.ceildiv(3).should eql(1)
- 4.ceildiv(3).should eql(2)
+ it "returns a quotient of division which is rounded up to the nearest integer" do
+ 0.ceildiv(3).should.eql?(0)
+ 1.ceildiv(3).should.eql?(1)
+ 3.ceildiv(3).should.eql?(1)
+ 4.ceildiv(3).should.eql?(2)
- 4.ceildiv(-3).should eql(-1)
- -4.ceildiv(3).should eql(-1)
- -4.ceildiv(-3).should eql(2)
+ 4.ceildiv(-3).should.eql?(-1)
+ -4.ceildiv(3).should.eql?(-1)
+ -4.ceildiv(-3).should.eql?(2)
- 3.ceildiv(1.2).should eql(3)
- 3.ceildiv(6/5r).should eql(3)
+ 3.ceildiv(1.2).should.eql?(3)
+ 3.ceildiv(6/5r).should.eql?(3)
- (10**100-11).ceildiv(10**99-1).should eql(10)
- (10**100-9).ceildiv(10**99-1).should eql(11)
- end
+ (10**100-11).ceildiv(10**99-1).should.eql?(10)
+ (10**100-9).ceildiv(10**99-1).should.eql?(11)
end
end
diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb
index 39cafe2874..72784e1833 100644
--- a/spec/ruby/core/integer/chr_spec.rb
+++ b/spec/ruby/core/integer/chr_spec.rb
@@ -2,20 +2,20 @@ require_relative '../../spec_helper'
describe "Integer#chr without argument" do
it "returns a String" do
- 17.chr.should be_an_instance_of(String)
+ 17.chr.should.instance_of?(String)
end
it "returns a new String for each call" do
- 82.chr.should_not equal(82.chr)
+ 82.chr.should_not.equal?(82.chr)
end
it "raises a RangeError is self is less than 0" do
- -> { -1.chr }.should raise_error(RangeError, /-1 out of char range/)
- -> { (-bignum_value).chr }.should raise_error(RangeError, /bignum out of char range/)
+ -> { -1.chr }.should.raise(RangeError, /-1 out of char range/)
+ -> { (-bignum_value).chr }.should.raise(RangeError, /bignum out of char range/)
end
it "raises a RangeError if self is too large" do
- -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError, /2206368128 out of char range/)
+ -> { 2206368128.chr(Encoding::UTF_8) }.should.raise(RangeError, /2206368128 out of char range/)
end
describe "when Encoding.default_internal is nil" do
@@ -48,8 +48,8 @@ describe "Integer#chr without argument" do
end
it "raises a RangeError is self is greater than 255" do
- -> { 256.chr }.should raise_error(RangeError, /256 out of char range/)
- -> { bignum_value.chr }.should raise_error(RangeError, /bignum out of char range/)
+ -> { 256.chr }.should.raise(RangeError, /256 out of char range/)
+ -> { bignum_value.chr }.should.raise(RangeError, /bignum out of char range/)
end
end
@@ -137,7 +137,7 @@ describe "Integer#chr without argument" do
[620, "TIS-620"]
].each do |integer, encoding_name|
Encoding.default_internal = Encoding.find(encoding_name)
- -> { integer.chr }.should raise_error(RangeError, /(invalid codepoint|out of char range)/)
+ -> { integer.chr }.should.raise(RangeError, /(invalid codepoint|out of char range)/)
end
end
end
@@ -146,15 +146,15 @@ end
describe "Integer#chr with an encoding argument" do
it "returns a String" do
- 900.chr(Encoding::UTF_8).should be_an_instance_of(String)
+ 900.chr(Encoding::UTF_8).should.instance_of?(String)
end
it "returns a new String for each call" do
- 8287.chr(Encoding::UTF_8).should_not equal(8287.chr(Encoding::UTF_8))
+ 8287.chr(Encoding::UTF_8).should_not.equal?(8287.chr(Encoding::UTF_8))
end
it "accepts a String as an argument" do
- -> { 0xA4A2.chr('euc-jp') }.should_not raise_error
+ -> { 0xA4A2.chr('euc-jp') }.should_not.raise
end
it "converts a String to an Encoding as Encoding.find does" do
@@ -165,12 +165,12 @@ describe "Integer#chr with an encoding argument" do
# http://redmine.ruby-lang.org/issues/4869
it "raises a RangeError is self is less than 0" do
- -> { -1.chr(Encoding::UTF_8) }.should raise_error(RangeError, /-1 out of char range/)
- -> { (-bignum_value).chr(Encoding::EUC_JP) }.should raise_error(RangeError, /bignum out of char range/)
+ -> { -1.chr(Encoding::UTF_8) }.should.raise(RangeError, /-1 out of char range/)
+ -> { (-bignum_value).chr(Encoding::EUC_JP) }.should.raise(RangeError, /bignum out of char range/)
end
it "raises a RangeError if self is too large" do
- -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError, /2206368128 out of char range/)
+ -> { 2206368128.chr(Encoding::UTF_8) }.should.raise(RangeError, /2206368128 out of char range/)
end
it "returns a String with the specified encoding" do
@@ -223,25 +223,25 @@ describe "Integer#chr with an encoding argument" do
# #5864
it "raises RangeError if self is invalid as a codepoint in the specified encoding" do
- -> { 0x80.chr("US-ASCII") }.should raise_error(RangeError)
- -> { 0x0100.chr("BINARY") }.should raise_error(RangeError)
- -> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError)
- -> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError)
- -> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError)
- -> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError)
- -> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError)
- -> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError)
- -> { 620.chr("TIS-620") }.should raise_error(RangeError)
+ -> { 0x80.chr("US-ASCII") }.should.raise(RangeError)
+ -> { 0x0100.chr("BINARY") }.should.raise(RangeError)
+ -> { 0x0100.chr("EUC-JP") }.should.raise(RangeError)
+ -> { 0xA1A0.chr("EUC-JP") }.should.raise(RangeError)
+ -> { 0xA1.chr("EUC-JP") }.should.raise(RangeError)
+ -> { 0x80.chr("SHIFT_JIS") }.should.raise(RangeError)
+ -> { 0xE0.chr("SHIFT_JIS") }.should.raise(RangeError)
+ -> { 0x0100.chr("ISO-8859-9") }.should.raise(RangeError)
+ -> { 620.chr("TIS-620") }.should.raise(RangeError)
# UTF-16 surrogate range
- -> { 0xD800.chr("UTF-8") }.should raise_error(RangeError)
- -> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError)
- -> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError)
- -> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xD800.chr("UTF-8") }.should.raise(RangeError)
+ -> { 0xDBFF.chr("UTF-8") }.should.raise(RangeError)
+ -> { 0xDC00.chr("UTF-8") }.should.raise(RangeError)
+ -> { 0xDFFF.chr("UTF-8") }.should.raise(RangeError)
# UTF-16 surrogate range
- -> { 0xD800.chr("UTF-16") }.should raise_error(RangeError)
- -> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError)
- -> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError)
- -> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xD800.chr("UTF-16") }.should.raise(RangeError)
+ -> { 0xDBFF.chr("UTF-16") }.should.raise(RangeError)
+ -> { 0xDC00.chr("UTF-16") }.should.raise(RangeError)
+ -> { 0xDFFF.chr("UTF-16") }.should.raise(RangeError)
end
it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do
diff --git a/spec/ruby/core/integer/coerce_spec.rb b/spec/ruby/core/integer/coerce_spec.rb
index 1d6dc9713f..c0e642da03 100644
--- a/spec/ruby/core/integer/coerce_spec.rb
+++ b/spec/ruby/core/integer/coerce_spec.rb
@@ -11,7 +11,7 @@ describe "Integer#coerce" do
describe "when given a String" do
it "raises an ArgumentError when trying to coerce with a non-number String" do
- -> { 1.coerce(":)") }.should raise_error(ArgumentError)
+ -> { 1.coerce(":)") }.should.raise(ArgumentError)
end
it "returns an array containing two Floats" do
@@ -21,7 +21,7 @@ describe "Integer#coerce" do
end
it "raises a TypeError when trying to coerce with nil" do
- -> { 1.coerce(nil) }.should raise_error(TypeError)
+ -> { 1.coerce(nil) }.should.raise(TypeError)
end
it "tries to convert the given Object into a Float by using #to_f" do
@@ -29,13 +29,13 @@ describe "Integer#coerce" do
2.coerce(obj).should == [1.0, 2.0]
(obj = mock('0')).should_receive(:to_f).and_return('0')
- -> { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError)
+ -> { 2.coerce(obj).should == [1.0, 2.0] }.should.raise(TypeError)
end
it "raises a TypeError when given an Object that does not respond to #to_f" do
- -> { 1.coerce(mock('x')) }.should raise_error(TypeError)
- -> { 1.coerce(1..4) }.should raise_error(TypeError)
- -> { 1.coerce(:test) }.should raise_error(TypeError)
+ -> { 1.coerce(mock('x')) }.should.raise(TypeError)
+ -> { 1.coerce(1..4) }.should.raise(TypeError)
+ -> { 1.coerce(:test) }.should.raise(TypeError)
end
end
@@ -44,8 +44,8 @@ describe "Integer#coerce" do
a = bignum_value
ary = a.coerce(2)
- ary[0].should be_kind_of(Integer)
- ary[1].should be_kind_of(Integer)
+ ary[0].should.is_a?(Integer)
+ ary[1].should.is_a?(Integer)
ary.should == [2, a]
end
@@ -54,18 +54,18 @@ describe "Integer#coerce" do
b = bignum_value
ary = a.coerce(b)
- ary[0].should be_kind_of(Integer)
- ary[1].should be_kind_of(Integer)
+ ary[0].should.is_a?(Integer)
+ ary[1].should.is_a?(Integer)
ary.should == [b, a]
end
it "raises a TypeError when not passed a Fixnum or Bignum" do
a = bignum_value
- -> { a.coerce(nil) }.should raise_error(TypeError)
- -> { a.coerce(mock('str')) }.should raise_error(TypeError)
- -> { a.coerce(1..4) }.should raise_error(TypeError)
- -> { a.coerce(:test) }.should raise_error(TypeError)
+ -> { a.coerce(nil) }.should.raise(TypeError)
+ -> { a.coerce(mock('str')) }.should.raise(TypeError)
+ -> { a.coerce(1..4) }.should.raise(TypeError)
+ -> { a.coerce(:test) }.should.raise(TypeError)
end
it "coerces both values to Floats and returns [other, self] when passed a Float" do
diff --git a/spec/ruby/core/integer/comparison_spec.rb b/spec/ruby/core/integer/comparison_spec.rb
index 408c8e52ce..cc5cbe2506 100644
--- a/spec/ruby/core/integer/comparison_spec.rb
+++ b/spec/ruby/core/integer/comparison_spec.rb
@@ -128,17 +128,17 @@ describe "Integer#<=>" do
@num.should_receive(:coerce).with(@big).and_raise(RuntimeError.new("my error"))
-> {
@big <=> @num
- }.should raise_error(RuntimeError, "my error")
+ }.should.raise(RuntimeError, "my error")
end
it "raises an exception if #coerce raises a non-StandardError exception" do
@num.should_receive(:coerce).with(@big).and_raise(Exception)
- -> { @big <=> @num }.should raise_error(Exception)
+ -> { @big <=> @num }.should.raise(Exception)
end
it "returns nil if #coerce does not return an Array" do
@num.should_receive(:coerce).with(@big).and_return(nil)
- (@big <=> @num).should be_nil
+ (@big <=> @num).should == nil
end
it "returns -1 if the coerced value is larger" do
@@ -157,6 +157,14 @@ describe "Integer#<=>" do
end
end
+ describe "with a Float" do
+ it "does not lose precision for values that don't fit in a double" do
+ (bignum_value(1) <=> bignum_value.to_f).should == 1
+ (bignum_value <=> bignum_value.to_f).should == 0
+ ((bignum_value - 1) <=> bignum_value.to_f).should == -1
+ end
+ end
+
# The tests below are taken from matz's revision 23730 for Ruby trunk
it "returns 1 when self is Infinity and other is a Bignum" do
(infinity_value <=> Float::MAX.to_i*2).should == 1
diff --git a/spec/ruby/core/integer/constants_spec.rb b/spec/ruby/core/integer/constants_spec.rb
index 2077ad451e..937806c72f 100644
--- a/spec/ruby/core/integer/constants_spec.rb
+++ b/spec/ruby/core/integer/constants_spec.rb
@@ -1,41 +1,13 @@
require_relative '../../spec_helper'
describe "Fixnum" do
- ruby_version_is ""..."3.2" do
- it "is unified into Integer" do
- suppress_warning do
- Fixnum.should equal(Integer)
- end
- end
-
- it "is deprecated" do
- -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/)
- end
- end
-
- ruby_version_is "3.2" do
- it "is no longer defined" do
- Object.should_not.const_defined?(:Fixnum)
- end
+ it "is no longer defined" do
+ Object.should_not.const_defined?(:Fixnum)
end
end
describe "Bignum" do
- ruby_version_is ""..."3.2" do
- it "is unified into Integer" do
- suppress_warning do
- Bignum.should equal(Integer)
- end
- end
-
- it "is deprecated" do
- -> { Bignum }.should complain(/constant ::Bignum is deprecated/)
- end
- end
-
- ruby_version_is "3.2" do
- it "is no longer defined" do
- Object.should_not.const_defined?(:Bignum)
- end
+ it "is no longer defined" do
+ Object.should_not.const_defined?(:Bignum)
end
end
diff --git a/spec/ruby/core/integer/digits_spec.rb b/spec/ruby/core/integer/digits_spec.rb
index 3d0a64c25f..c4ebf2cd88 100644
--- a/spec/ruby/core/integer/digits_spec.rb
+++ b/spec/ruby/core/integer/digits_spec.rb
@@ -19,15 +19,15 @@ describe "Integer#digits" do
end
it "raises ArgumentError when calling with a radix less than 2" do
- -> { 12345.digits(1) }.should raise_error(ArgumentError)
+ -> { 12345.digits(1) }.should.raise(ArgumentError)
end
it "raises ArgumentError when calling with a negative radix" do
- -> { 12345.digits(-2) }.should raise_error(ArgumentError)
+ -> { 12345.digits(-2) }.should.raise(ArgumentError)
end
it "raises Math::DomainError when calling digits on a negative number" do
- -> { -12345.digits(7) }.should raise_error(Math::DomainError)
+ -> { -12345.digits(7) }.should.raise(Math::DomainError)
end
it "returns integer values > 9 when base is above 10" do
diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb
index 2eb9c0623b..220ca4a73e 100644
--- a/spec/ruby/core/integer/div_spec.rb
+++ b/spec/ruby/core/integer/div_spec.rb
@@ -46,21 +46,21 @@ describe "Integer#div" do
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { 0.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { 10.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { -10.div(0.0) }.should raise_error(ZeroDivisionError)
+ -> { 0.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { 10.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { -10.div(0.0) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the given argument is 0 and not a Float" do
- -> { 13.div(0) }.should raise_error(ZeroDivisionError)
- -> { 13.div(-0) }.should raise_error(ZeroDivisionError)
+ -> { 13.div(0) }.should.raise(ZeroDivisionError)
+ -> { 13.div(-0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-numeric argument" do
- -> { 13.div(mock('10')) }.should raise_error(TypeError)
- -> { 5.div("2") }.should raise_error(TypeError)
- -> { 5.div(:"2") }.should raise_error(TypeError)
- -> { 5.div([]) }.should raise_error(TypeError)
+ -> { 13.div(mock('10')) }.should.raise(TypeError)
+ -> { 5.div("2") }.should.raise(TypeError)
+ -> { 5.div(:"2") }.should.raise(TypeError)
+ -> { 5.div([]) }.should.raise(TypeError)
end
end
@@ -118,29 +118,29 @@ describe "Integer#div" do
end
it "raises a TypeError when given a non-numeric" do
- -> { @bignum.div(mock("10")) }.should raise_error(TypeError)
- -> { @bignum.div("2") }.should raise_error(TypeError)
- -> { @bignum.div(:symbol) }.should raise_error(TypeError)
+ -> { @bignum.div(mock("10")) }.should.raise(TypeError)
+ -> { @bignum.div("2") }.should.raise(TypeError)
+ -> { @bignum.div(:symbol) }.should.raise(TypeError)
end
it "returns a result of integer division of self by a float argument" do
- @bignum.div(4294967295.5).should eql(4294967296)
+ @bignum.div(4294967295.5).should.eql?(4294967296)
not_supported_on :opal do
- @bignum.div(4294967295.0).should eql(4294967297)
- @bignum.div(bignum_value(88).to_f).should eql(1)
- @bignum.div((-bignum_value(88)).to_f).should eql(-1)
+ @bignum.div(4294967295.0).should.eql?(4294967297)
+ @bignum.div(bignum_value(88).to_f).should.eql?(1)
+ @bignum.div((-bignum_value(88)).to_f).should.eql?(-1)
end
end
# #5490
it "raises ZeroDivisionError if the argument is 0 and is a Float" do
- -> { @bignum.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { @bignum.div(-0.0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { @bignum.div(-0.0) }.should.raise(ZeroDivisionError)
end
it "raises ZeroDivisionError if the argument is 0 and is not a Float" do
- -> { @bignum.div(0) }.should raise_error(ZeroDivisionError)
- -> { @bignum.div(-0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.div(0) }.should.raise(ZeroDivisionError)
+ -> { @bignum.div(-0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/integer/divide_spec.rb b/spec/ruby/core/integer/divide_spec.rb
index 665f4d57be..e75432fd83 100644
--- a/spec/ruby/core/integer/divide_spec.rb
+++ b/spec/ruby/core/integer/divide_spec.rb
@@ -32,7 +32,7 @@ describe "Integer#/" do
end
it "raises a ZeroDivisionError if the given argument is zero and not a Float" do
- -> { 1 / 0 }.should raise_error(ZeroDivisionError)
+ -> { 1 / 0 }.should.raise(ZeroDivisionError)
end
it "does NOT raise ZeroDivisionError if the given argument is zero and is a Float" do
@@ -46,9 +46,9 @@ describe "Integer#/" do
end
it "raises a TypeError when given a non-Integer" do
- -> { 13 / mock('10') }.should raise_error(TypeError)
- -> { 13 / "10" }.should raise_error(TypeError)
- -> { 13 / :symbol }.should raise_error(TypeError)
+ -> { 13 / mock('10') }.should.raise(TypeError)
+ -> { 13 / "10" }.should.raise(TypeError)
+ -> { 13 / :symbol }.should.raise(TypeError)
end
end
@@ -97,13 +97,30 @@ describe "Integer#/" do
end
it "raises a ZeroDivisionError if other is zero and not a Float" do
- -> { @bignum / 0 }.should raise_error(ZeroDivisionError)
+ -> { @bignum / 0 }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-numeric" do
- -> { @bignum / mock('10') }.should raise_error(TypeError)
- -> { @bignum / "2" }.should raise_error(TypeError)
- -> { @bignum / :symbol }.should raise_error(TypeError)
+ -> { @bignum / mock('10') }.should.raise(TypeError)
+ -> { @bignum / "2" }.should.raise(TypeError)
+ -> { @bignum / :symbol }.should.raise(TypeError)
end
end
+
+ it "coerces the RHS and calls #coerce" do
+ obj = mock("integer plus")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 / obj).should == 2
+ end
+
+ it "coerces the RHS and calls #coerce even if it's private" do
+ obj = Object.new
+ class << obj
+ private def coerce(n)
+ [n, 3]
+ end
+ end
+
+ (6 / obj).should == 2
+ end
end
diff --git a/spec/ruby/core/integer/divmod_spec.rb b/spec/ruby/core/integer/divmod_spec.rb
index 7a489e9344..db470c5731 100644
--- a/spec/ruby/core/integer/divmod_spec.rb
+++ b/spec/ruby/core/integer/divmod_spec.rb
@@ -14,24 +14,24 @@ describe "Integer#divmod" do
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { 13.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { 0.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { -10.divmod(0) }.should raise_error(ZeroDivisionError)
+ -> { 13.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { 0.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { -10.divmod(0) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { 0.divmod(0.0) }.should raise_error(ZeroDivisionError)
- -> { 10.divmod(0.0) }.should raise_error(ZeroDivisionError)
- -> { -10.divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { 0.divmod(0.0) }.should.raise(ZeroDivisionError)
+ -> { 10.divmod(0.0) }.should.raise(ZeroDivisionError)
+ -> { -10.divmod(0.0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-Integer" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13.divmod(obj)
- }.should raise_error(TypeError)
- -> { 13.divmod("10") }.should raise_error(TypeError)
- -> { 13.divmod(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.divmod("10") }.should.raise(TypeError)
+ -> { 13.divmod(:symbol) }.should.raise(TypeError)
end
end
@@ -94,24 +94,24 @@ describe "Integer#divmod" do
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { @bignum.divmod(0) }.should raise_error(ZeroDivisionError)
- -> { (-@bignum).divmod(0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.divmod(0) }.should.raise(ZeroDivisionError)
+ -> { (-@bignum).divmod(0) }.should.raise(ZeroDivisionError)
end
# Behaviour established as correct in r23953
it "raises a FloatDomainError if other is NaN" do
- -> { @bignum.divmod(nan_value) }.should raise_error(FloatDomainError)
+ -> { @bignum.divmod(nan_value) }.should.raise(FloatDomainError)
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { @bignum.divmod(0.0) }.should raise_error(ZeroDivisionError)
- -> { (-@bignum).divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.divmod(0.0) }.should.raise(ZeroDivisionError)
+ -> { (-@bignum).divmod(0.0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when the given argument is not an Integer" do
- -> { @bignum.divmod(mock('10')) }.should raise_error(TypeError)
- -> { @bignum.divmod("10") }.should raise_error(TypeError)
- -> { @bignum.divmod(:symbol) }.should raise_error(TypeError)
+ -> { @bignum.divmod(mock('10')) }.should.raise(TypeError)
+ -> { @bignum.divmod("10") }.should.raise(TypeError)
+ -> { @bignum.divmod(:symbol) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/downto_spec.rb b/spec/ruby/core/integer/downto_spec.rb
index 987704b02e..a244d3df55 100644
--- a/spec/ruby/core/integer/downto_spec.rb
+++ b/spec/ruby/core/integer/downto_spec.rb
@@ -27,8 +27,8 @@ describe "Integer#downto [stop] when self and stop are Integers" do
end
it "raises an ArgumentError for invalid endpoints" do
- -> {1.downto("A") {|x| p x } }.should raise_error(ArgumentError)
- -> {1.downto(nil) {|x| p x } }.should raise_error(ArgumentError)
+ -> {1.downto("A") {|x| p x } }.should.raise(ArgumentError)
+ -> {1.downto(nil) {|x| p x } }.should.raise(ArgumentError)
end
describe "when no block is given" do
@@ -45,9 +45,9 @@ describe "Integer#downto [stop] when self and stop are Integers" do
describe "size" do
it "raises an ArgumentError for invalid endpoints" do
enum = 1.downto("A")
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
enum = 1.downto(nil)
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
end
it "returns self - stop + 1" do
diff --git a/spec/ruby/core/integer/dup_spec.rb b/spec/ruby/core/integer/dup_spec.rb
index 7f4d512465..3e5739ad37 100644
--- a/spec/ruby/core/integer/dup_spec.rb
+++ b/spec/ruby/core/integer/dup_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "Integer#dup" do
it "returns self for small integers" do
integer = 1_000
- integer.dup.should equal(integer)
+ integer.dup.should.equal?(integer)
end
it "returns self for large integers" do
integer = 4_611_686_018_427_387_905
- integer.dup.should equal(integer)
+ integer.dup.should.equal?(integer)
end
end
diff --git a/spec/ruby/core/integer/element_reference_spec.rb b/spec/ruby/core/integer/element_reference_spec.rb
index cb7e0dc9b0..c69ec2315d 100644
--- a/spec/ruby/core/integer/element_reference_spec.rb
+++ b/spec/ruby/core/integer/element_reference_spec.rb
@@ -59,13 +59,13 @@ describe "Integer#[]" do
end
it "raises a TypeError when passed a String" do
- -> { 3["3"] }.should raise_error(TypeError)
+ -> { 3["3"] }.should.raise(TypeError)
end
it "raises a TypeError when #to_int does not return an Integer" do
obj = mock('asdf')
obj.should_receive(:to_int).and_return("asdf")
- -> { 3[obj] }.should raise_error(TypeError)
+ -> { 3[obj] }.should.raise(TypeError)
end
it "calls #to_int to coerce a String to a Bignum and returns 0" do
@@ -137,8 +137,8 @@ describe "Integer#[]" do
end
it "raises FloatDomainError if any boundary is infinity" do
- -> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/)
- -> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/)
+ -> { 0x0001[3..Float::INFINITY] }.should.raise(FloatDomainError, /Infinity/)
+ -> { 0x0001[-Float::INFINITY..3] }.should.raise(FloatDomainError, /-Infinity/)
end
context "when passed (..i)" do
@@ -151,7 +151,7 @@ describe "Integer#[]" do
it "raises ArgumentError if any of i bit equals 1" do
-> {
eval("0b111110[..3]")
- }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
+ }.should.raise(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
end
end
end
@@ -179,10 +179,10 @@ describe "Integer#[]" do
it "raises a TypeError when the given argument can't be converted to Integer" do
obj = mock('asdf')
- -> { @bignum[obj] }.should raise_error(TypeError)
+ -> { @bignum[obj] }.should.raise(TypeError)
obj.should_receive(:to_int).and_return("asdf")
- -> { @bignum[obj] }.should raise_error(TypeError)
+ -> { @bignum[obj] }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/eql_spec.rb b/spec/ruby/core/integer/eql_spec.rb
new file mode 100644
index 0000000000..9c80173206
--- /dev/null
+++ b/spec/ruby/core/integer/eql_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+describe "Integer#eql?" do
+ context "bignum" do
+ it "returns true for the same value" do
+ bignum_value.eql?(bignum_value).should == true
+ end
+
+ it "returns false for a different Integer value" do
+ bignum_value.eql?(bignum_value(1)).should == false
+ end
+
+ it "returns false for a Float with the same numeric value" do
+ bignum_value.eql?(bignum_value.to_f).should == false
+ end
+
+ it "returns false for a Rational with the same numeric value" do
+ bignum_value.eql?(Rational(bignum_value)).should == false
+ end
+
+ it "returns false for a Fixnum-range Integer" do
+ bignum_value.eql?(42).should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/even_spec.rb b/spec/ruby/core/integer/even_spec.rb
index a314cc6b19..578979320e 100644
--- a/spec/ruby/core/integer/even_spec.rb
+++ b/spec/ruby/core/integer/even_spec.rb
@@ -3,38 +3,38 @@ require_relative '../../spec_helper'
describe "Integer#even?" do
context "fixnum" do
it "returns true for a Fixnum when it is an even number" do
- (-2).even?.should be_true
- (-1).even?.should be_false
+ (-2).even?.should == true
+ (-1).even?.should == false
- 0.even?.should be_true
- 1.even?.should be_false
- 2.even?.should be_true
+ 0.even?.should == true
+ 1.even?.should == false
+ 2.even?.should == true
end
it "returns true for a Bignum when it is an even number" do
- bignum_value(0).even?.should be_true
- bignum_value(1).even?.should be_false
+ bignum_value(0).even?.should == true
+ bignum_value(1).even?.should == false
- (-bignum_value(0)).even?.should be_true
- (-bignum_value(1)).even?.should be_false
+ (-bignum_value(0)).even?.should == true
+ (-bignum_value(1)).even?.should == false
end
end
context "bignum" do
it "returns true if self is even and positive" do
- (10000**10).even?.should be_true
+ (10000**10).even?.should == true
end
it "returns true if self is even and negative" do
- (-10000**10).even?.should be_true
+ (-10000**10).even?.should == true
end
it "returns false if self is odd and positive" do
- (9879**976).even?.should be_false
+ (9879**976).even?.should == false
end
it "returns false if self is odd and negative" do
- (-9879**976).even?.should be_false
+ (-9879**976).even?.should == false
end
end
end
diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb
index d9ea2fdf8d..7854d66dec 100644
--- a/spec/ruby/core/integer/fdiv_spec.rb
+++ b/spec/ruby/core/integer/fdiv_spec.rb
@@ -65,8 +65,8 @@ describe "Integer#fdiv" do
end
it "returns NaN when the argument is NaN" do
- -1.fdiv(nan_value).nan?.should be_true
- 1.fdiv(nan_value).nan?.should be_true
+ -1.fdiv(nan_value).nan?.should == true
+ 1.fdiv(nan_value).nan?.should == true
end
it "returns Infinity when the argument is 0" do
@@ -86,11 +86,11 @@ describe "Integer#fdiv" do
end
it "raises a TypeError when argument isn't numeric" do
- -> { 1.fdiv(mock('non-numeric')) }.should raise_error(TypeError)
+ -> { 1.fdiv(mock('non-numeric')) }.should.raise(TypeError)
end
it "raises an ArgumentError when passed multiple arguments" do
- -> { 1.fdiv(6,0.2) }.should raise_error(ArgumentError)
+ -> { 1.fdiv(6,0.2) }.should.raise(ArgumentError)
end
it "follows the coercion protocol" do
diff --git a/spec/ruby/core/integer/fixtures/classes.rb b/spec/ruby/core/integer/fixtures/classes.rb
index 6ebfbd1565..65948efb9f 100644
--- a/spec/ruby/core/integer/fixtures/classes.rb
+++ b/spec/ruby/core/integer/fixtures/classes.rb
@@ -1,4 +1,14 @@
module IntegerSpecs
class CoerceError < StandardError
end
+
+ class CoercibleNumeric
+ def initialize(v) @v = v end
+ def coerce(other) [self.class.new(other), self] end
+ def >(other) @v.to_i > other.to_i end
+ def >=(other) @v.to_i >= other.to_i end
+ def <(other) @v.to_i < other.to_i end
+ def <=(other) @v.to_i <= other.to_i end
+ def to_i() @v.to_i end
+ end
end
diff --git a/spec/ruby/core/integer/gcd_spec.rb b/spec/ruby/core/integer/gcd_spec.rb
index 961f1c5c2e..1fff785927 100644
--- a/spec/ruby/core/integer/gcd_spec.rb
+++ b/spec/ruby/core/integer/gcd_spec.rb
@@ -7,8 +7,8 @@ describe "Integer#gcd" do
end
it "returns an Integer" do
- 36.gcd(6).should be_kind_of(Integer)
- 4.gcd(20981).should be_kind_of(Integer)
+ 36.gcd(6).should.is_a?(Integer)
+ 4.gcd(20981).should.is_a?(Integer)
end
it "returns the greatest common divisor of self and argument" do
@@ -33,13 +33,13 @@ describe "Integer#gcd" do
it "accepts a Bignum argument" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
99.gcd(bignum).should == 99
end
it "works if self is a Bignum" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
bignum.gcd(99).should == 99
end
@@ -55,15 +55,15 @@ describe "Integer#gcd" do
end
it "raises an ArgumentError if not given an argument" do
- -> { 12.gcd }.should raise_error(ArgumentError)
+ -> { 12.gcd }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given more than one argument" do
- -> { 12.gcd(30, 20) }.should raise_error(ArgumentError)
+ -> { 12.gcd(30, 20) }.should.raise(ArgumentError)
end
it "raises a TypeError unless the argument is an Integer" do
- -> { 39.gcd(3.8) }.should raise_error(TypeError)
- -> { 45872.gcd([]) }.should raise_error(TypeError)
+ -> { 39.gcd(3.8) }.should.raise(TypeError)
+ -> { 45872.gcd([]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/gcdlcm_spec.rb b/spec/ruby/core/integer/gcdlcm_spec.rb
index ebf45e55a1..419bf9f275 100644
--- a/spec/ruby/core/integer/gcdlcm_spec.rb
+++ b/spec/ruby/core/integer/gcdlcm_spec.rb
@@ -7,8 +7,8 @@ describe "Integer#gcdlcm" do
end
it "returns an Array" do
- 36.gcdlcm(6).should be_kind_of(Array)
- 4.gcdlcm(20981).should be_kind_of(Array)
+ 36.gcdlcm(6).should.is_a?(Array)
+ 4.gcdlcm(20981).should.is_a?(Array)
end
it "returns a two-element Array" do
@@ -28,26 +28,26 @@ describe "Integer#gcdlcm" do
it "accepts a Bignum argument" do
bignum = 91999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
99.gcdlcm(bignum).should == [99.gcd(bignum), 99.lcm(bignum)]
end
it "works if self is a Bignum" do
bignum = 9999**89
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
bignum.gcdlcm(99).should == [bignum.gcd(99), bignum.lcm(99)]
end
it "raises an ArgumentError if not given an argument" do
- -> { 12.gcdlcm }.should raise_error(ArgumentError)
+ -> { 12.gcdlcm }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given more than one argument" do
- -> { 12.gcdlcm(30, 20) }.should raise_error(ArgumentError)
+ -> { 12.gcdlcm(30, 20) }.should.raise(ArgumentError)
end
it "raises a TypeError unless the argument is an Integer" do
- -> { 39.gcdlcm(3.8) }.should raise_error(TypeError)
- -> { 45872.gcdlcm([]) }.should raise_error(TypeError)
+ -> { 39.gcdlcm(3.8) }.should.raise(TypeError)
+ -> { 45872.gcdlcm([]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/gt_spec.rb b/spec/ruby/core/integer/gt_spec.rb
index f0179e566d..75436144cf 100644
--- a/spec/ruby/core/integer/gt_spec.rb
+++ b/spec/ruby/core/integer/gt_spec.rb
@@ -17,8 +17,8 @@ describe "Integer#>" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 > "4" }.should raise_error(ArgumentError)
- -> { 5 > mock('x') }.should raise_error(ArgumentError)
+ -> { 5 > "4" }.should.raise(ArgumentError)
+ -> { 5 > mock('x') }.should.raise(ArgumentError)
end
end
@@ -36,8 +36,13 @@ describe "Integer#>" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum > "4" }.should raise_error(ArgumentError)
- -> { @bignum > mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum > "4" }.should.raise(ArgumentError)
+ -> { @bignum > mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value > IntegerSpecs::CoercibleNumeric.new(1)).should == true
+ (bignum_value > IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/gte_spec.rb b/spec/ruby/core/integer/gte_spec.rb
index 6237fc2c51..e5cb892efd 100644
--- a/spec/ruby/core/integer/gte_spec.rb
+++ b/spec/ruby/core/integer/gte_spec.rb
@@ -18,8 +18,8 @@ describe "Integer#>=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 >= "4" }.should raise_error(ArgumentError)
- -> { 5 >= mock('x') }.should raise_error(ArgumentError)
+ -> { 5 >= "4" }.should.raise(ArgumentError)
+ -> { 5 >= mock('x') }.should.raise(ArgumentError)
end
end
@@ -36,8 +36,13 @@ describe "Integer#>=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum >= "4" }.should raise_error(ArgumentError)
- -> { @bignum >= mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum >= "4" }.should.raise(ArgumentError)
+ -> { @bignum >= mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value >= IntegerSpecs::CoercibleNumeric.new(1)).should == true
+ (bignum_value >= IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/integer_spec.rb b/spec/ruby/core/integer/integer_spec.rb
index 2d5d2e3e92..19a962d548 100644
--- a/spec/ruby/core/integer/integer_spec.rb
+++ b/spec/ruby/core/integer/integer_spec.rb
@@ -6,8 +6,8 @@ describe "Integer" do
end
it "is the class of both small and large integers" do
- 42.class.should equal(Integer)
- bignum_value.class.should equal(Integer)
+ 42.class.should.equal?(Integer)
+ bignum_value.class.should.equal?(Integer)
end
end
diff --git a/spec/ruby/core/integer/lcm_spec.rb b/spec/ruby/core/integer/lcm_spec.rb
index 296a001c8c..6659247d1e 100644
--- a/spec/ruby/core/integer/lcm_spec.rb
+++ b/spec/ruby/core/integer/lcm_spec.rb
@@ -7,8 +7,8 @@ describe "Integer#lcm" do
end
it "returns an Integer" do
- 36.lcm(6).should be_kind_of(Integer)
- 4.lcm(20981).should be_kind_of(Integer)
+ 36.lcm(6).should.is_a?(Integer)
+ 4.lcm(20981).should.is_a?(Integer)
end
it "returns the least common multiple of self and argument" do
@@ -33,26 +33,26 @@ describe "Integer#lcm" do
it "accepts a Bignum argument" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
99.lcm(bignum).should == bignum
end
it "works if self is a Bignum" do
bignum = 9999**99
- bignum.should be_kind_of(Integer)
+ bignum.should.is_a?(Integer)
bignum.lcm(99).should == bignum
end
it "raises an ArgumentError if not given an argument" do
- -> { 12.lcm }.should raise_error(ArgumentError)
+ -> { 12.lcm }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given more than one argument" do
- -> { 12.lcm(30, 20) }.should raise_error(ArgumentError)
+ -> { 12.lcm(30, 20) }.should.raise(ArgumentError)
end
it "raises a TypeError unless the argument is an Integer" do
- -> { 39.lcm(3.8) }.should raise_error(TypeError)
- -> { 45872.lcm([]) }.should raise_error(TypeError)
+ -> { 39.lcm(3.8) }.should.raise(TypeError)
+ -> { 45872.lcm([]) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb
index 0781371d93..7eedb91228 100644
--- a/spec/ruby/core/integer/left_shift_spec.rb
+++ b/spec/ruby/core/integer/left_shift_spec.rb
@@ -58,13 +58,13 @@ describe "Integer#<< (with n << m)" do
it "returns a Bignum == fixnum_max * 2 when fixnum_max << 1 and n > 0" do
result = fixnum_max << 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max * 2
end
it "returns a Bignum == fixnum_min * 2 when fixnum_min << 1 and n < 0" do
result = fixnum_min << 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min * 2
end
@@ -82,15 +82,15 @@ describe "Integer#<< (with n << m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { 3 << obj }.should raise_error(TypeError)
+ -> { 3 << obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { 3 << nil }.should raise_error(TypeError)
+ -> { 3 << nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { 3 << "4" }.should raise_error(TypeError)
+ -> { 3 << "4" }.should.raise(TypeError)
end
end
@@ -129,13 +129,13 @@ describe "Integer#<< (with n << m)" do
it "returns a Fixnum == fixnum_max when (fixnum_max * 2) << -1 and n > 0" do
result = (fixnum_max * 2) << -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max
end
it "returns a Fixnum == fixnum_min when (fixnum_min * 2) << -1 and n < 0" do
result = (fixnum_min * 2) << -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min
end
@@ -150,15 +150,15 @@ describe "Integer#<< (with n << m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { @bignum << obj }.should raise_error(TypeError)
+ -> { @bignum << obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @bignum << nil }.should raise_error(TypeError)
+ -> { @bignum << nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { @bignum << "4" }.should raise_error(TypeError)
+ -> { @bignum << "4" }.should.raise(TypeError)
end
end
@@ -181,10 +181,8 @@ describe "Integer#<< (with n << m)" do
(bignum_value << -(2**40)).should == 0
end
- ruby_bug "#18517", ""..."3.2" do
- it "returns 0 when m > 0 long and n == 0" do
- (0 << (2**40)).should == 0
- end
+ it "returns 0 when m > 0 long and n == 0" do
+ (0 << (2**40)).should == 0
end
it "returns 0 when m > 0 bignum and n == 0" do
@@ -203,10 +201,10 @@ describe "Integer#<< (with n << m)" do
exps << bignum_value << coerce_bignum if bignum_value >= limit
exps.each { |exp|
- -> { (1 << exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-1 << exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (bignum_value << exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-bignum_value << exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (1 << exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-1 << exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (bignum_value << exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-bignum_value << exp) }.should.raise(RangeError, 'shift width too big')
}
end
end
diff --git a/spec/ruby/core/integer/lt_spec.rb b/spec/ruby/core/integer/lt_spec.rb
index c182f82555..dd1391d093 100644
--- a/spec/ruby/core/integer/lt_spec.rb
+++ b/spec/ruby/core/integer/lt_spec.rb
@@ -17,8 +17,8 @@ describe "Integer#<" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 < "4" }.should raise_error(ArgumentError)
- -> { 5 < mock('x') }.should raise_error(ArgumentError)
+ -> { 5 < "4" }.should.raise(ArgumentError)
+ -> { 5 < mock('x') }.should.raise(ArgumentError)
end
end
@@ -38,8 +38,13 @@ describe "Integer#<" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum < "4" }.should raise_error(ArgumentError)
- -> { @bignum < mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum < "4" }.should.raise(ArgumentError)
+ -> { @bignum < mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value < IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == true
+ (bignum_value < IntegerSpecs::CoercibleNumeric.new(1)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/lte_spec.rb b/spec/ruby/core/integer/lte_spec.rb
index 65b71d77f2..9ef1c9f604 100644
--- a/spec/ruby/core/integer/lte_spec.rb
+++ b/spec/ruby/core/integer/lte_spec.rb
@@ -18,8 +18,8 @@ describe "Integer#<=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { 5 <= "4" }.should raise_error(ArgumentError)
- -> { 5 <= mock('x') }.should raise_error(ArgumentError)
+ -> { 5 <= "4" }.should.raise(ArgumentError)
+ -> { 5 <= mock('x') }.should.raise(ArgumentError)
end
end
@@ -46,8 +46,13 @@ describe "Integer#<=" do
end
it "raises an ArgumentError when given a non-Integer" do
- -> { @bignum <= "4" }.should raise_error(ArgumentError)
- -> { @bignum <= mock('str') }.should raise_error(ArgumentError)
+ -> { @bignum <= "4" }.should.raise(ArgumentError)
+ -> { @bignum <= mock('str') }.should.raise(ArgumentError)
+ end
+
+ it "dispatches the correct operator after coercion" do
+ (bignum_value <= IntegerSpecs::CoercibleNumeric.new(bignum_value * 2)).should == true
+ (bignum_value <= IntegerSpecs::CoercibleNumeric.new(1)).should == false
end
end
end
diff --git a/spec/ruby/core/integer/minus_spec.rb b/spec/ruby/core/integer/minus_spec.rb
index aadf416a05..5fd3a81a72 100644
--- a/spec/ruby/core/integer/minus_spec.rb
+++ b/spec/ruby/core/integer/minus_spec.rb
@@ -17,9 +17,9 @@ describe "Integer#-" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13 - obj
- }.should raise_error(TypeError)
- -> { 13 - "10" }.should raise_error(TypeError)
- -> { 13 - :symbol }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13 - "10" }.should.raise(TypeError)
+ -> { 13 - :symbol }.should.raise(TypeError)
end
end
@@ -35,9 +35,26 @@ describe "Integer#-" do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum - mock('10') }.should raise_error(TypeError)
- -> { @bignum - "10" }.should raise_error(TypeError)
- -> { @bignum - :symbol }.should raise_error(TypeError)
+ -> { @bignum - mock('10') }.should.raise(TypeError)
+ -> { @bignum - "10" }.should.raise(TypeError)
+ -> { @bignum - :symbol }.should.raise(TypeError)
end
end
+
+ it "coerces the RHS and calls #coerce" do
+ obj = mock("integer plus")
+ obj.should_receive(:coerce).with(5).and_return([5, 10])
+ (5 - obj).should == -5
+ end
+
+ it "coerces the RHS and calls #coerce even if it's private" do
+ obj = Object.new
+ class << obj
+ private def coerce(n)
+ [n, 10]
+ end
+ end
+
+ (5 - obj).should == -5
+ end
end
diff --git a/spec/ruby/core/integer/multiply_spec.rb b/spec/ruby/core/integer/multiply_spec.rb
index 5037d27458..7f30eebaa5 100644
--- a/spec/ruby/core/integer/multiply_spec.rb
+++ b/spec/ruby/core/integer/multiply_spec.rb
@@ -18,9 +18,9 @@ describe "Integer#*" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13 * obj
- }.should raise_error(TypeError)
- -> { 13 * "10" }.should raise_error(TypeError)
- -> { 13 * :symbol }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13 * "10" }.should.raise(TypeError)
+ -> { 13 * :symbol }.should.raise(TypeError)
end
end
@@ -37,9 +37,9 @@ describe "Integer#*" do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum * mock('10') }.should raise_error(TypeError)
- -> { @bignum * "10" }.should raise_error(TypeError)
- -> { @bignum * :symbol }.should raise_error(TypeError)
+ -> { @bignum * mock('10') }.should.raise(TypeError)
+ -> { @bignum * "10" }.should.raise(TypeError)
+ -> { @bignum * :symbol }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/nobits_spec.rb b/spec/ruby/core/integer/nobits_spec.rb
index 685759ffa3..f1a3aca9d5 100644
--- a/spec/ruby/core/integer/nobits_spec.rb
+++ b/spec/ruby/core/integer/nobits_spec.rb
@@ -29,8 +29,8 @@ describe "Integer#nobits?" do
-> {
(obj = mock('10')).should_receive(:coerce).any_number_of_times.and_return([42,10])
13.nobits?(obj)
- }.should raise_error(TypeError)
- -> { 13.nobits?("10") }.should raise_error(TypeError)
- -> { 13.nobits?(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.nobits?("10") }.should.raise(TypeError)
+ -> { 13.nobits?(:symbol) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/odd_spec.rb b/spec/ruby/core/integer/odd_spec.rb
index dd779fa44b..f9e50ec790 100644
--- a/spec/ruby/core/integer/odd_spec.rb
+++ b/spec/ruby/core/integer/odd_spec.rb
@@ -3,36 +3,36 @@ require_relative '../../spec_helper'
describe "Integer#odd?" do
context "fixnum" do
it "returns true when self is an odd number" do
- (-2).odd?.should be_false
- (-1).odd?.should be_true
+ (-2).odd?.should == false
+ (-1).odd?.should == true
- 0.odd?.should be_false
- 1.odd?.should be_true
- 2.odd?.should be_false
+ 0.odd?.should == false
+ 1.odd?.should == true
+ 2.odd?.should == false
- bignum_value(0).odd?.should be_false
- bignum_value(1).odd?.should be_true
+ bignum_value(0).odd?.should == false
+ bignum_value(1).odd?.should == true
- (-bignum_value(0)).odd?.should be_false
- (-bignum_value(1)).odd?.should be_true
+ (-bignum_value(0)).odd?.should == false
+ (-bignum_value(1)).odd?.should == true
end
end
context "bignum" do
it "returns true if self is odd and positive" do
- (987279**19).odd?.should be_true
+ (987279**19).odd?.should == true
end
it "returns true if self is odd and negative" do
- (-9873389**97).odd?.should be_true
+ (-9873389**97).odd?.should == true
end
it "returns false if self is even and positive" do
- (10000000**10).odd?.should be_false
+ (10000000**10).odd?.should == false
end
it "returns false if self is even and negative" do
- (-1000000**100).odd?.should be_false
+ (-1000000**100).odd?.should == false
end
end
end
diff --git a/spec/ruby/core/integer/ord_spec.rb b/spec/ruby/core/integer/ord_spec.rb
index bcb57bea98..8b7dfe460d 100644
--- a/spec/ruby/core/integer/ord_spec.rb
+++ b/spec/ruby/core/integer/ord_spec.rb
@@ -2,16 +2,16 @@ require_relative '../../spec_helper'
describe "Integer#ord" do
it "returns self" do
- 20.ord.should eql(20)
- 40.ord.should eql(40)
+ 20.ord.should.eql?(20)
+ 40.ord.should.eql?(40)
- 0.ord.should eql(0)
- (-10).ord.should eql(-10)
+ 0.ord.should.eql?(0)
+ (-10).ord.should.eql?(-10)
- ?a.ord.should eql(97)
- ?Z.ord.should eql(90)
+ ?a.ord.should.eql?(97)
+ ?Z.ord.should.eql?(90)
- bignum_value.ord.should eql(bignum_value)
- (-bignum_value).ord.should eql(-bignum_value)
+ bignum_value.ord.should.eql?(bignum_value)
+ (-bignum_value).ord.should.eql?(-bignum_value)
end
end
diff --git a/spec/ruby/core/integer/plus_spec.rb b/spec/ruby/core/integer/plus_spec.rb
index d01a76ab58..b684377bd5 100644
--- a/spec/ruby/core/integer/plus_spec.rb
+++ b/spec/ruby/core/integer/plus_spec.rb
@@ -17,9 +17,9 @@ describe "Integer#+" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13 + obj
- }.should raise_error(TypeError)
- -> { 13 + "10" }.should raise_error(TypeError)
- -> { 13 + :symbol }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13 + "10" }.should.raise(TypeError)
+ -> { 13 + :symbol }.should.raise(TypeError)
end
end
@@ -35,9 +35,9 @@ describe "Integer#+" do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum + mock('10') }.should raise_error(TypeError)
- -> { @bignum + "10" }.should raise_error(TypeError)
- -> { @bignum + :symbol}.should raise_error(TypeError)
+ -> { @bignum + mock('10') }.should.raise(TypeError)
+ -> { @bignum + "10" }.should.raise(TypeError)
+ -> { @bignum + :symbol}.should.raise(TypeError)
end
end
@@ -55,4 +55,21 @@ describe "Integer#+" do
RUBY
ruby_exe(code).should == "-1"
end
+
+ it "coerces the RHS and calls #coerce" do
+ obj = mock("integer plus")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 + obj).should == 9
+ end
+
+ it "coerces the RHS and calls #coerce even if it's private" do
+ obj = Object.new
+ class << obj
+ private def coerce(n)
+ [n, 3]
+ end
+ end
+
+ (6 + obj).should == 9
+ end
end
diff --git a/spec/ruby/core/integer/pow_spec.rb b/spec/ruby/core/integer/pow_spec.rb
index ecaca01eff..12a3839c40 100644
--- a/spec/ruby/core/integer/pow_spec.rb
+++ b/spec/ruby/core/integer/pow_spec.rb
@@ -16,10 +16,10 @@ describe "Integer#pow" do
end
it "works well with bignums" do
- 2.pow(61, 5843009213693951).should eql 3697379018277258
- 2.pow(62, 5843009213693952).should eql 1551748822859776
- 2.pow(63, 5843009213693953).should eql 3103497645717974
- 2.pow(64, 5843009213693954).should eql 363986077738838
+ 2.pow(61, 5843009213693951).should.eql? 3697379018277258
+ 2.pow(62, 5843009213693952).should.eql? 1551748822859776
+ 2.pow(63, 5843009213693953).should.eql? 3103497645717974
+ 2.pow(64, 5843009213693954).should.eql? 363986077738838
end
it "handles sign like #divmod does" do
@@ -30,22 +30,22 @@ describe "Integer#pow" do
end
it "ensures all arguments are integers" do
- -> { 2.pow(5, 12.0) }.should raise_error(TypeError, /2nd argument not allowed unless all arguments are integers/)
- -> { 2.pow(5, Rational(12, 1)) }.should raise_error(TypeError, /2nd argument not allowed unless all arguments are integers/)
+ -> { 2.pow(5, 12.0) }.should.raise(TypeError, /2nd argument not allowed unless all arguments are integers/)
+ -> { 2.pow(5, Rational(12, 1)) }.should.raise(TypeError, /2nd argument not allowed unless all arguments are integers/)
end
it "raises TypeError for non-numeric value" do
- -> { 2.pow(5, "12") }.should raise_error(TypeError)
- -> { 2.pow(5, []) }.should raise_error(TypeError)
- -> { 2.pow(5, nil) }.should raise_error(TypeError)
+ -> { 2.pow(5, "12") }.should.raise(TypeError)
+ -> { 2.pow(5, []) }.should.raise(TypeError)
+ -> { 2.pow(5, nil) }.should.raise(TypeError)
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { 2.pow(5, 0) }.should raise_error(ZeroDivisionError)
+ -> { 2.pow(5, 0) }.should.raise(ZeroDivisionError)
end
it "raises a RangeError when the first argument is negative and the second argument is present" do
- -> { 2.pow(-5, 1) }.should raise_error(RangeError)
+ -> { 2.pow(-5, 1) }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/core/integer/pred_spec.rb b/spec/ruby/core/integer/pred_spec.rb
index 86750ebfd1..fce536b5a2 100644
--- a/spec/ruby/core/integer/pred_spec.rb
+++ b/spec/ruby/core/integer/pred_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Integer#pred" do
it "returns the Integer equal to self - 1" do
- 0.pred.should eql(-1)
- -1.pred.should eql(-2)
- bignum_value.pred.should eql(bignum_value(-1))
- fixnum_min.pred.should eql(fixnum_min - 1)
- 20.pred.should eql(19)
+ 0.pred.should.eql?(-1)
+ -1.pred.should.eql?(-2)
+ bignum_value.pred.should.eql?(bignum_value(-1))
+ fixnum_min.pred.should.eql?(fixnum_min - 1)
+ 20.pred.should.eql?(19)
end
end
diff --git a/spec/ruby/core/integer/rationalize_spec.rb b/spec/ruby/core/integer/rationalize_spec.rb
index 09d741af33..272eca6911 100644
--- a/spec/ruby/core/integer/rationalize_spec.rb
+++ b/spec/ruby/core/integer/rationalize_spec.rb
@@ -12,7 +12,7 @@ describe "Integer#rationalize" do
it "returns a Rational object" do
@numbers.each do |number|
- number.rationalize.should be_an_instance_of(Rational)
+ number.rationalize.should.instance_of?(Rational)
end
end
@@ -33,7 +33,7 @@ describe "Integer#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { 1.rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { 1.rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { 1.rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { 1.rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/integer/remainder_spec.rb b/spec/ruby/core/integer/remainder_spec.rb
index 757e42fbe8..deb81fb2a5 100644
--- a/spec/ruby/core/integer/remainder_spec.rb
+++ b/spec/ruby/core/integer/remainder_spec.rb
@@ -22,10 +22,10 @@ describe "Integer#remainder" do
end
it "raises TypeError if passed non-numeric argument" do
- -> { 5.remainder("3") }.should raise_error(TypeError)
- -> { 5.remainder(:"3") }.should raise_error(TypeError)
- -> { 5.remainder([]) }.should raise_error(TypeError)
- -> { 5.remainder(nil) }.should raise_error(TypeError)
+ -> { 5.remainder("3") }.should.raise(TypeError)
+ -> { 5.remainder(:"3") }.should.raise(TypeError)
+ -> { 5.remainder([]) }.should.raise(TypeError)
+ -> { 5.remainder(nil) }.should.raise(TypeError)
end
end
@@ -38,14 +38,14 @@ describe "Integer#remainder" do
end
it "raises a ZeroDivisionError if other is zero and not a Float" do
- -> { bignum_value(66).remainder(0) }.should raise_error(ZeroDivisionError)
+ -> { bignum_value(66).remainder(0) }.should.raise(ZeroDivisionError)
end
it "does raises ZeroDivisionError if other is zero and a Float" do
a = bignum_value(7)
b = bignum_value(32)
- -> { a.remainder(0.0) }.should raise_error(ZeroDivisionError)
- -> { b.remainder(-0.0) }.should raise_error(ZeroDivisionError)
+ -> { a.remainder(0.0) }.should.raise(ZeroDivisionError)
+ -> { b.remainder(-0.0) }.should.raise(ZeroDivisionError)
end
end
end
diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb
index e91613d8d1..4281d3b7ab 100644
--- a/spec/ruby/core/integer/right_shift_spec.rb
+++ b/spec/ruby/core/integer/right_shift_spec.rb
@@ -54,13 +54,13 @@ describe "Integer#>> (with n >> m)" do
it "returns a Bignum == fixnum_max * 2 when fixnum_max >> -1 and n > 0" do
result = fixnum_max >> -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max * 2
end
it "returns a Bignum == fixnum_min * 2 when fixnum_min >> -1 and n < 0" do
result = fixnum_min >> -1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min * 2
end
@@ -78,15 +78,15 @@ describe "Integer#>> (with n >> m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { 3 >> obj }.should raise_error(TypeError)
+ -> { 3 >> obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { 3 >> nil }.should raise_error(TypeError)
+ -> { 3 >> nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { 3 >> "4" }.should raise_error(TypeError)
+ -> { 3 >> "4" }.should.raise(TypeError)
end
end
@@ -151,13 +151,13 @@ describe "Integer#>> (with n >> m)" do
it "returns a Fixnum == fixnum_max when (fixnum_max * 2) >> 1 and n > 0" do
result = (fixnum_max * 2) >> 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_max
end
it "returns a Fixnum == fixnum_min when (fixnum_min * 2) >> 1 and n < 0" do
result = (fixnum_min * 2) >> 1
- result.should be_an_instance_of(Integer)
+ result.should.instance_of?(Integer)
result.should == fixnum_min
end
@@ -172,15 +172,15 @@ describe "Integer#>> (with n >> m)" do
obj = mock("a string")
obj.should_receive(:to_int).and_return("asdf")
- -> { @bignum >> obj }.should raise_error(TypeError)
+ -> { @bignum >> obj }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @bignum >> nil }.should raise_error(TypeError)
+ -> { @bignum >> nil }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { @bignum >> "4" }.should raise_error(TypeError)
+ -> { @bignum >> "4" }.should.raise(TypeError)
end
end
@@ -203,10 +203,8 @@ describe "Integer#>> (with n >> m)" do
(bignum_value >> (2**40)).should == 0
end
- ruby_bug "#18517", ""..."3.2" do
- it "returns 0 when m < 0 long and n == 0" do
- (0 >> -(2**40)).should == 0
- end
+ it "returns 0 when m < 0 long and n == 0" do
+ (0 >> -(2**40)).should == 0
end
it "returns 0 when m < 0 bignum and n == 0" do
@@ -225,10 +223,10 @@ describe "Integer#>> (with n >> m)" do
exps << -bignum_value << coerce_bignum if bignum_value >= limit
exps.each { |exp|
- -> { (1 >> exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-1 >> exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (1 >> exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-1 >> exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (bignum_value >> exp) }.should.raise(RangeError, 'shift width too big')
+ -> { (-bignum_value >> exp) }.should.raise(RangeError, 'shift width too big')
}
end
end
diff --git a/spec/ruby/core/integer/round_spec.rb b/spec/ruby/core/integer/round_spec.rb
index 189384f11a..a3f11e7a76 100644
--- a/spec/ruby/core/integer/round_spec.rb
+++ b/spec/ruby/core/integer/round_spec.rb
@@ -8,37 +8,37 @@ describe "Integer#round" do
# redmine:5228
it "returns itself rounded if passed a negative value" do
- +249.round(-2).should eql(+200)
- -249.round(-2).should eql(-200)
- (+25 * 10**70 - 1).round(-71).should eql(+20 * 10**70)
- (-25 * 10**70 + 1).round(-71).should eql(-20 * 10**70)
+ +249.round(-2).should.eql?(+200)
+ -249.round(-2).should.eql?(-200)
+ (+25 * 10**70 - 1).round(-71).should.eql?(+20 * 10**70)
+ (-25 * 10**70 + 1).round(-71).should.eql?(-20 * 10**70)
end
it "returns itself rounded to nearest if passed a negative value" do
- +250.round(-2).should eql(+300)
- -250.round(-2).should eql(-300)
- (+25 * 10**70).round(-71).should eql(+30 * 10**70)
- (-25 * 10**70).round(-71).should eql(-30 * 10**70)
+ +250.round(-2).should.eql?(+300)
+ -250.round(-2).should.eql?(-300)
+ (+25 * 10**70).round(-71).should.eql?(+30 * 10**70)
+ (-25 * 10**70).round(-71).should.eql?(-30 * 10**70)
end
it "raises a RangeError when passed a big negative value" do
- -> { 42.round(min_long - 1) }.should raise_error(RangeError)
+ -> { 42.round(min_long - 1) }.should.raise(RangeError)
end
it "raises a RangeError when passed Float::INFINITY" do
- -> { 42.round(Float::INFINITY) }.should raise_error(RangeError)
+ -> { 42.round(Float::INFINITY) }.should.raise(RangeError)
end
it "raises a RangeError when passed a beyond signed int" do
- -> { 42.round(1<<31) }.should raise_error(RangeError)
+ -> { 42.round(1<<31) }.should.raise(RangeError)
end
it "raises a TypeError when passed a String" do
- -> { 42.round("4") }.should raise_error(TypeError)
+ -> { 42.round("4") }.should.raise(TypeError)
end
it "raises a TypeError when its argument cannot be converted to an Integer" do
- -> { 42.round(nil) }.should raise_error(TypeError)
+ -> { 42.round(nil) }.should.raise(TypeError)
end
it "calls #to_int on the argument to convert it to an Integer" do
@@ -50,32 +50,32 @@ describe "Integer#round" do
it "raises a TypeError when #to_int does not return an Integer" do
obj = mock("Object")
obj.stub!(:to_int).and_return([])
- -> { 42.round(obj) }.should raise_error(TypeError)
+ -> { 42.round(obj) }.should.raise(TypeError)
end
it "returns different rounded values depending on the half option" do
- 25.round(-1, half: :up).should eql(30)
- 25.round(-1, half: :down).should eql(20)
- 25.round(-1, half: :even).should eql(20)
- 25.round(-1, half: nil).should eql(30)
- 35.round(-1, half: :up).should eql(40)
- 35.round(-1, half: :down).should eql(30)
- 35.round(-1, half: :even).should eql(40)
- 35.round(-1, half: nil).should eql(40)
- (-25).round(-1, half: :up).should eql(-30)
- (-25).round(-1, half: :down).should eql(-20)
- (-25).round(-1, half: :even).should eql(-20)
- (-25).round(-1, half: nil).should eql(-30)
+ 25.round(-1, half: :up).should.eql?(30)
+ 25.round(-1, half: :down).should.eql?(20)
+ 25.round(-1, half: :even).should.eql?(20)
+ 25.round(-1, half: nil).should.eql?(30)
+ 35.round(-1, half: :up).should.eql?(40)
+ 35.round(-1, half: :down).should.eql?(30)
+ 35.round(-1, half: :even).should.eql?(40)
+ 35.round(-1, half: nil).should.eql?(40)
+ (-25).round(-1, half: :up).should.eql?(-30)
+ (-25).round(-1, half: :down).should.eql?(-20)
+ (-25).round(-1, half: :even).should.eql?(-20)
+ (-25).round(-1, half: nil).should.eql?(-30)
end
it "returns itself if passed a positive precision and the half option" do
- 35.round(1, half: :up).should eql(35)
- 35.round(1, half: :down).should eql(35)
- 35.round(1, half: :even).should eql(35)
+ 35.round(1, half: :up).should.eql?(35)
+ 35.round(1, half: :down).should.eql?(35)
+ 35.round(1, half: :even).should.eql?(35)
end
it "raises ArgumentError for an unknown rounding mode" do
- -> { 42.round(-1, half: :foo) }.should raise_error(ArgumentError, /invalid rounding mode: foo/)
- -> { 42.round(1, half: :foo) }.should raise_error(ArgumentError, /invalid rounding mode: foo/)
+ -> { 42.round(-1, half: :foo) }.should.raise(ArgumentError, /invalid rounding mode: foo/)
+ -> { 42.round(1, half: :foo) }.should.raise(ArgumentError, /invalid rounding mode: foo/)
end
end
diff --git a/spec/ruby/core/integer/shared/arithmetic_coerce.rb b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
index 1260192df1..561b18fe52 100644
--- a/spec/ruby/core/integer/shared/arithmetic_coerce.rb
+++ b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
@@ -6,6 +6,6 @@ describe :integer_arithmetic_coerce_not_rescue, shared: true do
b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
# e.g. 1 + b
- -> { 1.send(@method, b) }.should raise_error(IntegerSpecs::CoerceError)
+ -> { 1.send(@method, b) }.should.raise(IntegerSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/integer/shared/comparison_coerce.rb b/spec/ruby/core/integer/shared/comparison_coerce.rb
index af52f5e99b..4bb7404183 100644
--- a/spec/ruby/core/integer/shared/comparison_coerce.rb
+++ b/spec/ruby/core/integer/shared/comparison_coerce.rb
@@ -6,6 +6,6 @@ describe :integer_comparison_coerce_not_rescue, shared: true do
b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
# e.g. 1 > b
- -> { 1.send(@method, b) }.should raise_error(IntegerSpecs::CoerceError)
+ -> { 1.send(@method, b) }.should.raise(IntegerSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/integer/shared/equal.rb b/spec/ruby/core/integer/shared/equal.rb
index ecee17831c..c621ba3f81 100644
--- a/spec/ruby/core/integer/shared/equal.rb
+++ b/spec/ruby/core/integer/shared/equal.rb
@@ -54,5 +54,10 @@ describe :integer_equal, shared: true do
@bignum.send(@method, obj).should == true
@bignum.send(@method, obj).should == false
end
+
+ it "does not lose precision when comparing with a Float" do
+ (bignum_value(1).send(@method, bignum_value.to_f)).should == false
+ (bignum_value.send(@method, bignum_value.to_f)).should == true
+ end
end
end
diff --git a/spec/ruby/core/integer/shared/exponent.rb b/spec/ruby/core/integer/shared/exponent.rb
index 5ef6d686d8..0be13859f9 100644
--- a/spec/ruby/core/integer/shared/exponent.rb
+++ b/spec/ruby/core/integer/shared/exponent.rb
@@ -1,51 +1,51 @@
describe :integer_exponent, shared: true do
context "fixnum" do
it "returns self raised to the given power" do
- 2.send(@method, 0).should eql 1
- 2.send(@method, 1).should eql 2
- 2.send(@method, 2).should eql 4
+ 2.send(@method, 0).should.eql? 1
+ 2.send(@method, 1).should.eql? 2
+ 2.send(@method, 2).should.eql? 4
- 9.send(@method, 0.5).should eql 3.0
- 9.send(@method, Rational(1, 2)).should eql 3.0
+ 9.send(@method, 0.5).should.eql? 3.0
+ 9.send(@method, Rational(1, 2)).should.eql? 3.0
5.send(@method, -1).to_f.to_s.should == '0.2'
- 2.send(@method, 40).should eql 1099511627776
+ 2.send(@method, 40).should.eql? 1099511627776
end
it "overflows the answer to a bignum transparently" do
- 2.send(@method, 29).should eql 536870912
- 2.send(@method, 30).should eql 1073741824
- 2.send(@method, 31).should eql 2147483648
- 2.send(@method, 32).should eql 4294967296
+ 2.send(@method, 29).should.eql? 536870912
+ 2.send(@method, 30).should.eql? 1073741824
+ 2.send(@method, 31).should.eql? 2147483648
+ 2.send(@method, 32).should.eql? 4294967296
- 2.send(@method, 61).should eql 2305843009213693952
- 2.send(@method, 62).should eql 4611686018427387904
- 2.send(@method, 63).should eql 9223372036854775808
- 2.send(@method, 64).should eql 18446744073709551616
- 8.send(@method, 23).should eql 590295810358705651712
+ 2.send(@method, 61).should.eql? 2305843009213693952
+ 2.send(@method, 62).should.eql? 4611686018427387904
+ 2.send(@method, 63).should.eql? 9223372036854775808
+ 2.send(@method, 64).should.eql? 18446744073709551616
+ 8.send(@method, 23).should.eql? 590295810358705651712
end
it "raises negative numbers to the given power" do
- (-2).send(@method, 29).should eql(-536870912)
- (-2).send(@method, 30).should eql(1073741824)
- (-2).send(@method, 31).should eql(-2147483648)
- (-2).send(@method, 32).should eql(4294967296)
- (-2).send(@method, 33).should eql(-8589934592)
+ (-2).send(@method, 29).should.eql?(-536870912)
+ (-2).send(@method, 30).should.eql?(1073741824)
+ (-2).send(@method, 31).should.eql?(-2147483648)
+ (-2).send(@method, 32).should.eql?(4294967296)
+ (-2).send(@method, 33).should.eql?(-8589934592)
- (-2).send(@method, 61).should eql(-2305843009213693952)
- (-2).send(@method, 62).should eql(4611686018427387904)
- (-2).send(@method, 63).should eql(-9223372036854775808)
- (-2).send(@method, 64).should eql(18446744073709551616)
- (-2).send(@method, 65).should eql(-36893488147419103232)
+ (-2).send(@method, 61).should.eql?(-2305843009213693952)
+ (-2).send(@method, 62).should.eql?(4611686018427387904)
+ (-2).send(@method, 63).should.eql?(-9223372036854775808)
+ (-2).send(@method, 64).should.eql?(18446744073709551616)
+ (-2).send(@method, 65).should.eql?(-36893488147419103232)
end
it "can raise 1 to a bignum safely" do
- 1.send(@method, 4611686018427387904).should eql 1
+ 1.send(@method, 4611686018427387904).should.eql? 1
end
it "can raise -1 to a bignum safely" do
- (-1).send(@method, 4611686018427387904).should eql(1)
- (-1).send(@method, 4611686018427387905).should eql(-1)
+ (-1).send(@method, 4611686018427387904).should.eql?(1)
+ (-1).send(@method, 4611686018427387905).should.eql?(-1)
end
ruby_version_is ""..."3.4" do
@@ -57,14 +57,22 @@ describe :integer_exponent, shared: true do
end
ruby_version_is "3.4" do
- it "raises an ArgumentError when the number is too big" do
- -> { 100000000.send(@method, 1000000000) }.should raise_error(ArgumentError)
+ it "returns an Integer for results larger than the old 32MB limit" do
+ # 2 ** 40000000 requires 40000001 bits
+ # This exceeds the old 32MB limit but is within the new 16GB limit
+ result = 2.send(@method, 40000000)
+ result.should.is_a?(Integer)
+ result.bit_length.should == 40000001
+ end
+
+ it "raises an ArgumentError when the result size exceeds the limit" do
+ -> { 100000000.send(@method, 1000000000) }.should.raise(ArgumentError)
end
end
it "raises a ZeroDivisionError for 0 ** -1" do
- -> { 0.send(@method, -1) }.should raise_error(ZeroDivisionError)
- -> { 0.send(@method, Rational(-1, 1)) }.should raise_error(ZeroDivisionError)
+ -> { 0.send(@method, -1) }.should.raise(ZeroDivisionError)
+ -> { 0.send(@method, Rational(-1, 1)) }.should.raise(ZeroDivisionError)
end
it "returns Float::INFINITY for 0 ** -1.0" do
@@ -72,9 +80,9 @@ describe :integer_exponent, shared: true do
end
it "raises a TypeError when given a non-numeric power" do
- -> { 13.send(@method, "10") }.should raise_error(TypeError)
- -> { 13.send(@method, :symbol) }.should raise_error(TypeError)
- -> { 13.send(@method, nil) }.should raise_error(TypeError)
+ -> { 13.send(@method, "10") }.should.raise(TypeError)
+ -> { 13.send(@method, :symbol) }.should.raise(TypeError)
+ -> { 13.send(@method, nil) }.should.raise(TypeError)
end
it "coerces power and calls #**" do
@@ -111,9 +119,9 @@ describe :integer_exponent, shared: true do
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum.send(@method, mock('10')) }.should raise_error(TypeError)
- -> { @bignum.send(@method, "10") }.should raise_error(TypeError)
- -> { @bignum.send(@method, :symbol) }.should raise_error(TypeError)
+ -> { @bignum.send(@method, mock('10')) }.should.raise(TypeError)
+ -> { @bignum.send(@method, "10") }.should.raise(TypeError)
+ -> { @bignum.send(@method, :symbol) }.should.raise(TypeError)
end
ruby_version_is ""..."3.4" do
@@ -122,16 +130,26 @@ describe :integer_exponent, shared: true do
-> {
flt = @bignum.send(@method, @bignum)
}.should complain(/warning: in a\*\*b, b may be too big/)
- flt.should be_kind_of(Float)
+ flt.should.is_a?(Float)
flt.infinite?.should == 1
end
end
ruby_version_is "3.4" do
- it "does not switch to a Float when the values is too big" do
+ it "returns an Integer for large Bignum results exceeding the old limit" do
+ # (2 ** 70) ** 500000 requires 35000001 bits
+ # This exceeds the old 32MB limit but is within the new 16GB limit
+ bignum_base = 2 ** 70
+ result = bignum_base.send(@method, 500000)
+ result.should.is_a?(Integer)
+ result.bit_length.should == 35000001
+ end
+
+ it "raises an ArgumentError when Bignum result exceeds the limit" do
+ # @bignum ** @bignum would require enormous memory
-> {
@bignum.send(@method, @bignum)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/integer/shared/integer_ceil_precision.rb b/spec/ruby/core/integer/shared/integer_ceil_precision.rb
index 9f31c2cf61..b23c17937f 100644
--- a/spec/ruby/core/integer/shared/integer_ceil_precision.rb
+++ b/spec/ruby/core/integer/shared/integer_ceil_precision.rb
@@ -1,6 +1,6 @@
describe :integer_ceil_precision, shared: true do
context "precision is zero" do
- it "returns integer self" do
+ it "returns Integer equal to self" do
send(@method, 0).ceil(0).should.eql?(0)
send(@method, 123).ceil(0).should.eql?(123)
send(@method, -123).ceil(0).should.eql?(-123)
@@ -23,7 +23,16 @@ describe :integer_ceil_precision, shared: true do
send(@method, 0).ceil(-10).should.eql?(0)
end
- it "returns largest integer less than self with at least precision.abs trailing zeros" do
+ it "returns Integer equal to self if there are already at least precision.abs trailing zeros" do
+ send(@method, 10).ceil(-1).should.eql?(10)
+ send(@method, 100).ceil(-1).should.eql?(100)
+ send(@method, 100).ceil(-2).should.eql?(100)
+ send(@method, -10).ceil(-1).should.eql?(-10)
+ send(@method, -100).ceil(-1).should.eql?(-100)
+ send(@method, -100).ceil(-2).should.eql?(-100)
+ end
+
+ it "returns smallest Integer greater than self with at least precision.abs trailing zeros" do
send(@method, 123).ceil(-1).should.eql?(130)
send(@method, 123).ceil(-2).should.eql?(200)
send(@method, 123).ceil(-3).should.eql?(1000)
@@ -31,13 +40,15 @@ describe :integer_ceil_precision, shared: true do
send(@method, -123).ceil(-1).should.eql?(-120)
send(@method, -123).ceil(-2).should.eql?(-100)
send(@method, -123).ceil(-3).should.eql?(0)
+
+ send(@method, 100).ceil(-3).should.eql?(1000)
+ send(@method, -100).ceil(-3).should.eql?(0)
end
- ruby_bug "#20654", ""..."3.4" do
- it "returns 10**precision.abs when precision.abs is larger than the number digits of self" do
- send(@method, 123).ceil(-20).should.eql?(100000000000000000000)
- send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000)
- end
+ # Bug #20654
+ it "returns 10**precision.abs when precision.abs has more digits than self" do
+ send(@method, 123).ceil(-20).should.eql?(100000000000000000000)
+ send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000)
end
end
end
diff --git a/spec/ruby/core/integer/shared/integer_floor_precision.rb b/spec/ruby/core/integer/shared/integer_floor_precision.rb
index 4c5888c6c4..6247907d4c 100644
--- a/spec/ruby/core/integer/shared/integer_floor_precision.rb
+++ b/spec/ruby/core/integer/shared/integer_floor_precision.rb
@@ -33,11 +33,10 @@ describe :integer_floor_precision, shared: true do
send(@method, -123).floor(-3).should.eql?(-1000)
end
- ruby_bug "#20654", ""..."3.4" do
- it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do
- send(@method, -123).floor(-20).should.eql?(-100000000000000000000)
- send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000)
- end
+ # Bug #20654
+ it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do
+ send(@method, -123).floor(-20).should.eql?(-100000000000000000000)
+ send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000)
end
end
end
diff --git a/spec/ruby/core/integer/shared/integer_rounding.rb b/spec/ruby/core/integer/shared/integer_rounding.rb
index 56d1819f84..92f2a2327c 100644
--- a/spec/ruby/core/integer/shared/integer_rounding.rb
+++ b/spec/ruby/core/integer/shared/integer_rounding.rb
@@ -1,19 +1,19 @@
describe :integer_rounding_positive_precision, shared: true do
it "returns self if not passed a precision" do
[2, -4, 10**70, -10**100].each do |v|
- v.send(@method).should eql(v)
+ v.send(@method).should.eql?(v)
end
end
it "returns self if passed a precision of zero" do
[2, -4, 10**70, -10**100].each do |v|
- v.send(@method, 0).should eql(v)
+ v.send(@method, 0).should.eql?(v)
end
end
it "returns itself if passed a positive precision" do
[2, -4, 10**70, -10**100].each do |v|
- v.send(@method, 42).should eql(v)
+ v.send(@method, 42).should.eql?(v)
end
end
end
diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb
index f678a10806..d0b5e26ed5 100644
--- a/spec/ruby/core/integer/shared/modulo.rb
+++ b/spec/ruby/core/integer/shared/modulo.rb
@@ -1,6 +1,12 @@
describe :integer_modulo, shared: true do
context "fixnum" do
it "returns the modulus obtained from dividing self by the given argument" do
+ # test all possible combinations:
+ # - integer/double/bignum argument
+ # - positive/negative argument
+ # - positive/negative self
+ # - self greater/smaller than argument
+
13.send(@method, 4).should == 1
4.send(@method, 13).should == 4
@@ -16,59 +22,93 @@ describe :integer_modulo, shared: true do
(200).send(@method, -256).should == -56
(1000).send(@method, -512).should == -24
+ 13.send(@method, -4.0).should == -3.0
+ 4.send(@method, -13.0).should == -9.0
+
+ -13.send(@method, -4.0).should == -1.0
+ -4.send(@method, -13.0).should == -4.0
+
+ -13.send(@method, 4.0).should == 3.0
+ -4.send(@method, 13.0).should == 9.0
+
1.send(@method, 2.0).should == 1.0
200.send(@method, bignum_value).should == 200
+
+ 4.send(@method, bignum_value(10)).should == 4
+ 4.send(@method, -bignum_value(10)).should == -18446744073709551622
+ -4.send(@method, bignum_value(10)).should == 18446744073709551622
+ -4.send(@method, -bignum_value(10)).should == -4
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { 13.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { 0.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { -10.send(@method, 0) }.should raise_error(ZeroDivisionError)
+ -> { 13.send(@method, 0) }.should.raise(ZeroDivisionError)
+ -> { 0.send(@method, 0) }.should.raise(ZeroDivisionError)
+ -> { -10.send(@method, 0) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { 0.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- -> { 10.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- -> { -10.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
+ -> { 0.send(@method, 0.0) }.should.raise(ZeroDivisionError)
+ -> { 10.send(@method, 0.0) }.should.raise(ZeroDivisionError)
+ -> { -10.send(@method, 0.0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-Integer" do
-> {
(obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10)
13.send(@method, obj)
- }.should raise_error(TypeError)
- -> { 13.send(@method, "10") }.should raise_error(TypeError)
- -> { 13.send(@method, :symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.send(@method, "10") }.should.raise(TypeError)
+ -> { 13.send(@method, :symbol) }.should.raise(TypeError)
end
end
context "bignum" do
before :each do
- @bignum = bignum_value
+ @bignum = bignum_value(10)
end
it "returns the modulus obtained from dividing self by the given argument" do
+ # test all possible combinations:
+ # - integer/double/bignum argument
+ # - positive/negative argument
+ # - positive/negative self
+ # - self greater/smaller than argument
+
@bignum.send(@method, 5).should == 1
@bignum.send(@method, -5).should == -4
- @bignum.send(@method, -100).should == -84
+ (-@bignum).send(@method, 5).should == 4
+ (-@bignum).send(@method, -5).should == -1
+
@bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE)
- @bignum.send(@method, bignum_value(10)).should == 18446744073709551616
+ @bignum.send(@method, -2.22).should be_close(-0.6596396396394968, TOLERANCE)
+ (-@bignum).send(@method, 2.22).should be_close(0.6596396396394968, TOLERANCE)
+ (-@bignum).send(@method, -2.22).should be_close(-1.5603603603605034, TOLERANCE)
+
+ @bignum.send(@method, @bignum + 10).should == 18446744073709551626
+ @bignum.send(@method, -(@bignum + 10)).should == -10
+ (-@bignum).send(@method, @bignum + 10).should == 10
+ (-@bignum).send(@method, -(@bignum + 10)).should == -18446744073709551626
+
+ (@bignum + 10).send(@method, @bignum).should == 10
+ (@bignum + 10).send(@method, -@bignum).should == -18446744073709551616
+ (-(@bignum + 10)).send(@method, @bignum).should == 18446744073709551616
+ (-(@bignum + 10)).send(@method, -@bignum).should == -10
end
it "raises a ZeroDivisionError when the given argument is 0" do
- -> { @bignum.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { (-@bignum).send(@method, 0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.send(@method, 0) }.should.raise(ZeroDivisionError)
+ -> { (-@bignum).send(@method, 0) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the given argument is 0 and a Float" do
- -> { @bignum.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
- -> { -@bignum.send(@method, 0.0) }.should raise_error(ZeroDivisionError)
+ -> { @bignum.send(@method, 0.0) }.should.raise(ZeroDivisionError)
+ -> { -@bignum.send(@method, 0.0) }.should.raise(ZeroDivisionError)
end
it "raises a TypeError when given a non-Integer" do
- -> { @bignum.send(@method, mock('10')) }.should raise_error(TypeError)
- -> { @bignum.send(@method, "10") }.should raise_error(TypeError)
- -> { @bignum.send(@method, :symbol) }.should raise_error(TypeError)
+ -> { @bignum.send(@method, mock('10')) }.should.raise(TypeError)
+ -> { @bignum.send(@method, "10") }.should.raise(TypeError)
+ -> { @bignum.send(@method, :symbol) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/integer/shared/to_i.rb b/spec/ruby/core/integer/shared/to_i.rb
index 7b974cd3a7..2b6a50484a 100644
--- a/spec/ruby/core/integer/shared/to_i.rb
+++ b/spec/ruby/core/integer/shared/to_i.rb
@@ -1,8 +1,8 @@
describe :integer_to_i, shared: true do
it "returns self" do
- 10.send(@method).should eql(10)
- (-15).send(@method).should eql(-15)
- bignum_value.send(@method).should eql(bignum_value)
- (-bignum_value).send(@method).should eql(-bignum_value)
+ 10.send(@method).should.eql?(10)
+ (-15).send(@method).should.eql?(-15)
+ bignum_value.send(@method).should.eql?(bignum_value)
+ (-bignum_value).send(@method).should.eql?(-bignum_value)
end
end
diff --git a/spec/ruby/core/integer/sqrt_spec.rb b/spec/ruby/core/integer/sqrt_spec.rb
index 4149ca2cc9..bf90ea747e 100644
--- a/spec/ruby/core/integer/sqrt_spec.rb
+++ b/spec/ruby/core/integer/sqrt_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Integer.sqrt" do
it "returns an integer" do
- Integer.sqrt(10).should be_kind_of(Integer)
+ Integer.sqrt(10).should.is_a?(Integer)
end
it "returns the integer square root of the argument" do
@@ -14,7 +14,7 @@ describe "Integer.sqrt" do
end
it "raises a Math::DomainError if the argument is negative" do
- -> { Integer.sqrt(-4) }.should raise_error(Math::DomainError)
+ -> { Integer.sqrt(-4) }.should.raise(Math::DomainError)
end
it "accepts any argument that can be coerced to Integer" do
@@ -26,6 +26,6 @@ describe "Integer.sqrt" do
end
it "raises a TypeError if the argument cannot be coerced to Integer" do
- -> { Integer.sqrt("test") }.should raise_error(TypeError)
+ -> { Integer.sqrt("test") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/integer/to_f_spec.rb b/spec/ruby/core/integer/to_f_spec.rb
index 9f1df9ada9..0681236095 100644
--- a/spec/ruby/core/integer/to_f_spec.rb
+++ b/spec/ruby/core/integer/to_f_spec.rb
@@ -11,9 +11,9 @@ describe "Integer#to_f" do
context "bignum" do
it "returns self converted to a Float" do
- bignum_value(0x4000_0aa0_0bb0_0000).to_f.should eql(23_058_441_774_644_068_352.0)
- bignum_value(0x8000_0000_0000_0ccc).to_f.should eql(27_670_116_110_564_330_700.0)
- (-bignum_value(99)).to_f.should eql(-18_446_744_073_709_551_715.0)
+ bignum_value(0x4000_0aa0_0bb0_0000).to_f.should.eql?(23_058_441_774_644_068_352.0)
+ bignum_value(0x8000_0000_0000_0ccc).to_f.should.eql?(27_670_116_110_564_330_700.0)
+ (-bignum_value(99)).to_f.should.eql?(-18_446_744_073_709_551_715.0)
end
it "converts number close to Float::MAX without exceeding MAX or producing NaN" do
diff --git a/spec/ruby/core/integer/to_r_spec.rb b/spec/ruby/core/integer/to_r_spec.rb
index 7732bedca1..2649c7c78d 100644
--- a/spec/ruby/core/integer/to_r_spec.rb
+++ b/spec/ruby/core/integer/to_r_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Integer#to_r" do
it "returns a Rational object" do
- 309.to_r.should be_an_instance_of(Rational)
+ 309.to_r.should.instance_of?(Rational)
end
it "constructs a rational number with self as the numerator" do
@@ -15,12 +15,12 @@ describe "Integer#to_r" do
it "works even if self is a Bignum" do
bignum = 99999**999
- bignum.should be_an_instance_of(Integer)
+ bignum.should.instance_of?(Integer)
bignum.to_r.should == Rational(bignum, 1)
end
it "raises an ArgumentError if given any arguments" do
- -> { 287.to_r(2) }.should raise_error(ArgumentError)
- -> { 9102826.to_r(309, [], 71) }.should raise_error(ArgumentError)
+ -> { 287.to_r(2) }.should.raise(ArgumentError)
+ -> { 9102826.to_r(309, [], 71) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/integer/to_s_spec.rb b/spec/ruby/core/integer/to_s_spec.rb
index ca08dad95c..4970a2a12f 100644
--- a/spec/ruby/core/integer/to_s_spec.rb
+++ b/spec/ruby/core/integer/to_s_spec.rb
@@ -13,10 +13,10 @@ describe "Integer#to_s" do
end
it "raises an ArgumentError if the base is less than 2 or higher than 36" do
- -> { 123.to_s(-1) }.should raise_error(ArgumentError)
- -> { 123.to_s(0) }.should raise_error(ArgumentError)
- -> { 123.to_s(1) }.should raise_error(ArgumentError)
- -> { 123.to_s(37) }.should raise_error(ArgumentError)
+ -> { 123.to_s(-1) }.should.raise(ArgumentError)
+ -> { 123.to_s(0) }.should.raise(ArgumentError)
+ -> { 123.to_s(1) }.should.raise(ArgumentError)
+ -> { 123.to_s(37) }.should.raise(ArgumentError)
end
end
@@ -39,12 +39,12 @@ describe "Integer#to_s" do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- 1.to_s.encoding.should equal(Encoding::US_ASCII)
+ 1.to_s.encoding.should.equal?(Encoding::US_ASCII)
end
it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
Encoding.default_internal = Encoding::IBM437
- 1.to_s.encoding.should equal(Encoding::US_ASCII)
+ 1.to_s.encoding.should.equal?(Encoding::US_ASCII)
end
end
@@ -59,10 +59,10 @@ describe "Integer#to_s" do
end
it "raises an ArgumentError if the base is less than 2 or higher than 36" do
- -> { 123.to_s(-1) }.should raise_error(ArgumentError)
- -> { 123.to_s(0) }.should raise_error(ArgumentError)
- -> { 123.to_s(1) }.should raise_error(ArgumentError)
- -> { 123.to_s(37) }.should raise_error(ArgumentError)
+ -> { 123.to_s(-1) }.should.raise(ArgumentError)
+ -> { 123.to_s(0) }.should.raise(ArgumentError)
+ -> { 123.to_s(1) }.should.raise(ArgumentError)
+ -> { 123.to_s(37) }.should.raise(ArgumentError)
end
end
@@ -84,12 +84,12 @@ describe "Integer#to_s" do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- bignum_value.to_s.encoding.should equal(Encoding::US_ASCII)
+ bignum_value.to_s.encoding.should.equal?(Encoding::US_ASCII)
end
it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
Encoding.default_internal = Encoding::IBM437
- bignum_value.to_s.encoding.should equal(Encoding::US_ASCII)
+ bignum_value.to_s.encoding.should.equal?(Encoding::US_ASCII)
end
end
end
diff --git a/spec/ruby/core/integer/truncate_spec.rb b/spec/ruby/core/integer/truncate_spec.rb
index db16e74be4..b95c183cf3 100644
--- a/spec/ruby/core/integer/truncate_spec.rb
+++ b/spec/ruby/core/integer/truncate_spec.rb
@@ -8,12 +8,12 @@ describe "Integer#truncate" do
context "precision argument specified as part of the truncate method is negative" do
it "returns an integer with at least precision.abs trailing zeros" do
- 1832.truncate(-1).should eql(1830)
- 1832.truncate(-2).should eql(1800)
- 1832.truncate(-3).should eql(1000)
- -1832.truncate(-1).should eql(-1830)
- -1832.truncate(-2).should eql(-1800)
- -1832.truncate(-3).should eql(-1000)
+ 1832.truncate(-1).should.eql?(1830)
+ 1832.truncate(-2).should.eql?(1800)
+ 1832.truncate(-3).should.eql?(1000)
+ -1832.truncate(-1).should.eql?(-1830)
+ -1832.truncate(-2).should.eql?(-1800)
+ -1832.truncate(-3).should.eql?(-1000)
end
end
end
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 8a0ca671a9..8c9b4276b9 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -4,24 +4,24 @@ require_relative 'fixtures/classes'
describe "Integer.try_convert" do
it "returns the argument if it's an Integer" do
x = 42
- Integer.try_convert(x).should equal(x)
+ Integer.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_int" do
- Integer.try_convert(Object.new).should be_nil
+ Integer.try_convert(Object.new).should == nil
end
it "sends #to_int to the argument and returns the result if it's nil" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(nil)
- Integer.try_convert(obj).should be_nil
+ Integer.try_convert(obj).should == nil
end
it "sends #to_int to the argument and returns the result if it's an Integer" do
x = 234
obj = mock("to_int")
obj.should_receive(:to_int).and_return(x)
- Integer.try_convert(obj).should equal(x)
+ Integer.try_convert(obj).should.equal?(x)
end
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
@@ -29,7 +29,7 @@ describe "Integer.try_convert" do
obj.should_receive(:to_int).and_return(Object.new)
-> {
Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives Object)")
end
it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
@@ -37,12 +37,12 @@ describe "Integer.try_convert" do
obj.should_receive(:to_int).and_return("A String")
-> {
Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives String)")
end
it "does not rescue exceptions raised by #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_raise(RuntimeError)
- -> { Integer.try_convert obj }.should raise_error(RuntimeError)
+ -> { Integer.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/integer/upto_spec.rb b/spec/ruby/core/integer/upto_spec.rb
index dd6995e94b..ba63dcc9ea 100644
--- a/spec/ruby/core/integer/upto_spec.rb
+++ b/spec/ruby/core/integer/upto_spec.rb
@@ -27,8 +27,8 @@ describe "Integer#upto [stop] when self and stop are Integers" do
end
it "raises an ArgumentError for non-numeric endpoints" do
- -> { 1.upto("A") {|x| p x} }.should raise_error(ArgumentError)
- -> { 1.upto(nil) {|x| p x} }.should raise_error(ArgumentError)
+ -> { 1.upto("A") {|x| p x} }.should.raise(ArgumentError)
+ -> { 1.upto(nil) {|x| p x} }.should.raise(ArgumentError)
end
describe "when no block is given" do
@@ -45,9 +45,9 @@ describe "Integer#upto [stop] when self and stop are Integers" do
describe "size" do
it "raises an ArgumentError for non-numeric endpoints" do
enum = 1.upto("A")
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
enum = 1.upto(nil)
- -> { enum.size }.should raise_error(ArgumentError)
+ -> { enum.size }.should.raise(ArgumentError)
end
it "returns stop - self + 1" do
diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb
index 651fc52378..b77ed53ad4 100644
--- a/spec/ruby/core/io/advise_spec.rb
+++ b/spec/ruby/core/io/advise_spec.rb
@@ -14,73 +14,73 @@ describe "IO#advise" do
it "raises a TypeError if advise is not a Symbol" do
-> {
@io.advise("normal")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if offset cannot be coerced to an Integer" do
-> {
@io.advise(:normal, "wat")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if len cannot be coerced to an Integer" do
-> {
@io.advise(:normal, 0, "wat")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a RangeError if offset is too big" do
-> {
@io.advise(:normal, 10 ** 32)
- }.should raise_error(RangeError)
+ }.should.raise(RangeError)
end
it "raises a RangeError if len is too big" do
-> {
@io.advise(:normal, 0, 10 ** 32)
- }.should raise_error(RangeError)
+ }.should.raise(RangeError)
end
it "raises a NotImplementedError if advise is not recognized" do
->{
@io.advise(:foo)
- }.should raise_error(NotImplementedError)
+ }.should.raise(NotImplementedError)
end
it "supports the normal advice type" do
- @io.advise(:normal).should be_nil
+ @io.advise(:normal).should == nil
end
it "supports the sequential advice type" do
- @io.advise(:sequential).should be_nil
+ @io.advise(:sequential).should == nil
end
it "supports the random advice type" do
- @io.advise(:random).should be_nil
+ @io.advise(:random).should == nil
end
it "supports the dontneed advice type" do
- @io.advise(:dontneed).should be_nil
+ @io.advise(:dontneed).should == nil
end
it "supports the noreuse advice type" do
- @io.advise(:noreuse).should be_nil
+ @io.advise(:noreuse).should == nil
end
platform_is_not :linux do
it "supports the willneed advice type" do
- @io.advise(:willneed).should be_nil
+ @io.advise(:willneed).should == nil
end
end
guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported
it "supports the willneed advice type" do
- @io.advise(:willneed).should be_nil
+ @io.advise(:willneed).should == nil
end
end
it "raises an IOError if the stream is closed" do
@io.close
- -> { @io.advise(:normal) }.should raise_error(IOError)
+ -> { @io.advise(:normal) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/autoclose_spec.rb b/spec/ruby/core/io/autoclose_spec.rb
index 715ada7c93..596f3d6934 100644
--- a/spec/ruby/core/io/autoclose_spec.rb
+++ b/spec/ruby/core/io/autoclose_spec.rb
@@ -17,7 +17,7 @@ describe "IO#autoclose?" do
it "cannot be queried on a closed IO object" do
@io.close
- -> { @io.autoclose? }.should raise_error(IOError, /closed stream/)
+ -> { @io.autoclose? }.should.raise(IOError, /closed stream/)
end
end
@@ -72,6 +72,6 @@ describe "IO#autoclose=" do
it "cannot be set on a closed IO object" do
@io.close
- -> { @io.autoclose = false }.should raise_error(IOError, /closed stream/)
+ -> { @io.autoclose = false }.should.raise(IOError, /closed stream/)
end
end
diff --git a/spec/ruby/core/io/binmode_spec.rb b/spec/ruby/core/io/binmode_spec.rb
index 342cac2a9b..8117229c91 100644
--- a/spec/ruby/core/io/binmode_spec.rb
+++ b/spec/ruby/core/io/binmode_spec.rb
@@ -13,11 +13,11 @@ describe "IO#binmode" do
it "returns self" do
@io = new_io(@name)
- @io.binmode.should equal(@io)
+ @io.binmode.should.equal?(@io)
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.binmode }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.binmode }.should.raise(IOError)
end
it "sets external encoding to binary" do
@@ -47,9 +47,9 @@ describe "IO#binmode?" do
end
it "is true after a call to IO#binmode" do
- @file.binmode?.should be_false
+ @file.binmode?.should == false
@file.binmode
- @file.binmode?.should be_true
+ @file.binmode?.should == true
end
it "propagates to dup'ed IO objects" do
@@ -59,6 +59,6 @@ describe "IO#binmode?" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.binmode? }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.binmode? }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb
index 418e89213b..3023c7f177 100644
--- a/spec/ruby/core/io/binread_spec.rb
+++ b/spec/ruby/core/io/binread_spec.rb
@@ -38,14 +38,14 @@ describe "IO.binread" do
end
it "raises an ArgumentError when not passed a valid length" do
- -> { IO.binread @fname, -1 }.should raise_error(ArgumentError)
+ -> { IO.binread @fname, -1 }.should.raise(ArgumentError)
end
it "raises an Errno::EINVAL when not passed a valid offset" do
- -> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL)
+ -> { IO.binread @fname, 0, -1 }.should.raise(Errno::EINVAL)
end
- ruby_version_is "3.3" do
+ ruby_version_is ""..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
cmd = "|echo ok"
diff --git a/spec/ruby/core/io/buffer/and_spec.rb b/spec/ruby/core/io/buffer/and_spec.rb
new file mode 100644
index 0000000000..3cea163b0e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/and_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_and, shared: true do
+ it "applies the argument buffer as an AND bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\x30\x02\x30\x04\x30".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\x30\x02\x00\x00\x00".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should.raise(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should.raise(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should.raise(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#&" do
+ it_behaves_like :io_buffer_and, :&
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer & mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#and!" do
+ it_behaves_like :io_buffer_and, :and!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.and!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/bit_count_spec.rb b/spec/ruby/core/io/buffer/bit_count_spec.rb
new file mode 100644
index 0000000000..62f56f5b98
--- /dev/null
+++ b/spec/ruby/core/io/buffer/bit_count_spec.rb
@@ -0,0 +1,64 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "4.1" do
+ describe "IO::Buffer#bit_count" do
+ it "counts all set bits in the whole buffer" do
+ IO::Buffer.for(+"\xFF\x00\x0F") do |buffer|
+ buffer.bit_count.should == 12
+ end
+ end
+
+ it "returns 0 for a buffer of all zero bytes" do
+ IO::Buffer.for(+"\x00\x00\x00") do |buffer|
+ buffer.bit_count.should == 0
+ end
+ end
+
+ it "returns 8 * size for a buffer of all 0xFF bytes" do
+ IO::Buffer.for(+"\xFF" * 9) do |buffer|
+ buffer.bit_count.should == 72
+ end
+ end
+
+ it "returns 0 for an empty buffer" do
+ IO::Buffer.new(0).bit_count.should == 0
+ end
+
+ it "accepts an offset to start counting from (length defaults to remaining bytes)" do
+ IO::Buffer.for(+"\xFF\x00\x0F") do |buffer|
+ buffer.bit_count(0).should == 12 # offset=0 => entire buffer
+ buffer.bit_count(1).should == 4 # offset=1 => 0x00 + 0x0F
+ buffer.bit_count(2).should == 4 # offset=2 => 0x0F only
+ end
+ end
+
+ it "accepts an offset and length to restrict the counted region" do
+ IO::Buffer.for(+"\xFF\x00\x0F") do |buffer|
+ buffer.bit_count(0, 1).should == 8 # just 0xFF
+ buffer.bit_count(1, 1).should == 0 # just 0x00
+ buffer.bit_count(2, 1).should == 4 # just 0x0F
+ buffer.bit_count(1, 2).should == 4 # 0x00 + 0x0F
+ end
+ end
+
+ it "handles 8-byte aligned buffers efficiently" do
+ IO::Buffer.for(+"\xAA" * 8) do |buffer|
+ # 0xAA = 10101010 => 4 bits per byte => 32 total
+ buffer.bit_count.should == 32
+ end
+ end
+
+ it "raises ArgumentError when offset + length exceeds buffer size" do
+ IO::Buffer.for(+"\xFF") do |buffer|
+ -> { buffer.bit_count(0, 2) }.should.raise(ArgumentError)
+ -> { buffer.bit_count(1, 1) }.should.raise(ArgumentError)
+ end
+ end
+
+ it "returns an Integer" do
+ IO::Buffer.for(+"\xFF") do |buffer|
+ buffer.bit_count.should.is_a?(Integer)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/empty_spec.rb b/spec/ruby/core/io/buffer/empty_spec.rb
new file mode 100644
index 0000000000..4cceb4dc0d
--- /dev/null
+++ b/spec/ruby/core/io/buffer/empty_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/null_and_empty'
+
+describe "IO::Buffer#empty?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it_behaves_like :io_buffer_null_and_empty, :empty?
+
+ it "is true for a 0-length String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("")
+ @buffer.empty?.should == true
+ end
+
+ it "is true for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.empty?.should == true
+ end
+ end
+
+ it "is true for a 0-length slice of a buffer with size > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(3, 0).empty?.should == true
+ end
+end
diff --git a/spec/ruby/core/io/buffer/external_spec.rb b/spec/ruby/core/io/buffer/external_spec.rb
new file mode 100644
index 0000000000..18b2ee0d06
--- /dev/null
+++ b/spec/ruby/core/io/buffer/external_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#external?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer with externally-managed memory" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.external?.should == true
+ end
+
+ it "is false for a buffer with self-managed memory" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.external?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.external?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/for_spec.rb b/spec/ruby/core/io/buffer/for_spec.rb
new file mode 100644
index 0000000000..4c614f74b0
--- /dev/null
+++ b/spec/ruby/core/io/buffer/for_spec.rb
@@ -0,0 +1,95 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.for" do
+ before :each do
+ @string = +"för striñg"
+ end
+
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "without a block" do
+ it "copies string's contents, creating a separate read-only buffer" do
+ @buffer = IO::Buffer.for(@string)
+
+ @buffer.size.should == @string.bytesize
+ @buffer.get_string.should == @string.b
+
+ @string[0] = "d"
+ @buffer.get_string(0, 1).should == "f".b
+
+ -> { @buffer.set_string("d") }.should.raise(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+
+ it "creates an external, read-only buffer" do
+ @buffer = IO::Buffer.for(@string)
+
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should.external?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.private?
+ @buffer.should.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+ end
+
+ context "with a block" do
+ it "returns the last value in the block" do
+ value =
+ IO::Buffer.for(@string) do |buffer|
+ buffer.size * 3
+ end
+ value.should == @string.bytesize * 3
+ end
+
+ it "frees the buffer at the end of the block" do
+ IO::Buffer.for(@string) do |buffer|
+ @buffer = buffer
+ @buffer.should_not.null?
+ end
+ @buffer.should.null?
+ end
+
+ context "if string is not frozen" do
+ it "creates a modifiable string-backed buffer" do
+ IO::Buffer.for(@string) do |buffer|
+ buffer.size.should == @string.bytesize
+ buffer.get_string.should == @string.b
+
+ buffer.should_not.readonly?
+ buffer.should_not.locked?
+
+ buffer.set_string("ghost shell")
+ @string.should == "ghost shellg"
+ end
+ end
+
+ it "locks the original string to prevent modification" do
+ IO::Buffer.for(@string) do |_buffer|
+ -> { @string[0] = "t" }.should.raise(RuntimeError, "can't modify string; temporarily locked")
+ end
+ @string[1] = "u"
+ @string.should == "fur striñg"
+ end
+ end
+
+ context "if string is frozen" do
+ it "creates a read-only string-backed buffer" do
+ IO::Buffer.for(@string.freeze) do |buffer|
+ buffer.should.readonly?
+
+ -> { buffer.set_string("ghost shell") }.should.raise(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/free_spec.rb b/spec/ruby/core/io/buffer/free_spec.rb
new file mode 100644
index 0000000000..20fb7b901f
--- /dev/null
+++ b/spec/ruby/core/io/buffer/free_spec.rb
@@ -0,0 +1,102 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#free" do
+ context "with a buffer created with .new" do
+ it "frees internal memory and nullifies the buffer" do
+ buffer = IO::Buffer.new(4)
+ buffer.free
+ buffer.null?.should == true
+ end
+
+ it "frees mapped memory and nullifies the buffer" do
+ buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ buffer.free
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "frees mapped memory and nullifies the buffer" do
+ File.open(__FILE__, "r") do |file|
+ buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ buffer.free
+ buffer.null?.should == true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string = +"test"
+ buffer = IO::Buffer.for(string)
+ # Read-only buffer, can't modify the string.
+ buffer.free
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a block" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string = +"test"
+ IO::Buffer.for(string) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should == true
+ end
+ string.should == "meat"
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string =
+ IO::Buffer.string(4) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should == true
+ end
+ string.should == "meat"
+ end
+ end
+
+ it "can be called repeatedly without an error" do
+ buffer = IO::Buffer.new(4)
+ buffer.free
+ buffer.null?.should == true
+ buffer.free
+ buffer.null?.should == true
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ buffer = IO::Buffer.new(4)
+ buffer.locked do
+ -> { buffer.free }.should.raise(IO::Buffer::LockedError, "Buffer is locked!")
+ end
+ buffer.free
+ buffer.null?.should == true
+ end
+
+ context "with a slice of a buffer" do
+ it "nullifies the slice, not touching the buffer" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+
+ slice.free
+ slice.null?.should == true
+ buffer.null?.should == false
+
+ buffer.free
+ end
+
+ it "nullifies buffer, invalidating the slice" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+
+ buffer.free
+ slice.null?.should == false
+ slice.valid?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/initialize_spec.rb b/spec/ruby/core/io/buffer/initialize_spec.rb
new file mode 100644
index 0000000000..dba6fddc79
--- /dev/null
+++ b/spec/ruby/core/io/buffer/initialize_spec.rb
@@ -0,0 +1,119 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#initialize" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "creates a new zero-filled buffer with default size" do
+ @buffer = IO::Buffer.new
+ @buffer.size.should == IO::Buffer::DEFAULT_SIZE
+ @buffer.each(:U8).should.all? { |_offset, value| value.eql?(0) }
+ end
+
+ it "creates a buffer with default state" do
+ @buffer = IO::Buffer.new
+
+ @buffer.should_not.external?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.private?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ context "with size argument" do
+ it "creates a new internal buffer if size is less than IO::Buffer::PAGE_SIZE" do
+ size = IO::Buffer::PAGE_SIZE - 1
+ @buffer = IO::Buffer.new(size)
+ @buffer.size.should == size
+ @buffer.should_not.empty?
+
+ @buffer.should.internal?
+ @buffer.should_not.mapped?
+ end
+
+ it "creates a new mapped buffer if size is greater than or equal to IO::Buffer::PAGE_SIZE" do
+ size = IO::Buffer::PAGE_SIZE
+ @buffer = IO::Buffer.new(size)
+ @buffer.size.should == size
+ @buffer.should_not.empty?
+
+ @buffer.should_not.internal?
+ @buffer.should.mapped?
+ end
+
+ it "creates a null buffer if size is 0" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.should.null?
+ @buffer.should.empty?
+ end
+
+ it "raises TypeError if size is not an Integer" do
+ -> { IO::Buffer.new(nil) }.should.raise(TypeError, "not an Integer")
+ -> { IO::Buffer.new(10.0) }.should.raise(TypeError, "not an Integer")
+ end
+
+ it "raises ArgumentError if size is negative" do
+ -> { IO::Buffer.new(-1) }.should.raise(ArgumentError, "Size can't be negative!")
+ end
+ end
+
+ context "with size and flags arguments" do
+ it "forces mapped buffer with IO::Buffer::MAPPED flag" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE - 1, IO::Buffer::MAPPED)
+ @buffer.should.mapped?
+ @buffer.should_not.internal?
+ @buffer.should_not.empty?
+ end
+
+ it "forces internal buffer with IO::Buffer::INTERNAL flag" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::INTERNAL)
+ @buffer.should.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.empty?
+ end
+
+ it "allows extra flags" do
+ @buffer = IO::Buffer.new(10, IO::Buffer::INTERNAL | IO::Buffer::SHARED | IO::Buffer::READONLY)
+ @buffer.should.internal?
+ @buffer.should.shared?
+ @buffer.should.readonly?
+ end
+
+ it "ignores flags if size is 0" do
+ @buffer = IO::Buffer.new(0, 0xffff)
+ @buffer.should.null?
+ @buffer.should.empty?
+
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.external?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ it "raises IO::Buffer::AllocationError if neither IO::Buffer::MAPPED nor IO::Buffer::INTERNAL is given" do
+ -> { IO::Buffer.new(10, IO::Buffer::READONLY) }.should.raise(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ -> { IO::Buffer.new(10, 0) }.should.raise(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ end
+
+ it "raises ArgumentError if flags is negative" do
+ -> { IO::Buffer.new(10, -1) }.should.raise(ArgumentError, "Flags can't be negative!")
+ end
+
+ it "raises TypeError with non-Integer flags" do
+ -> { IO::Buffer.new(10, 0.0) }.should.raise(TypeError, "not an Integer")
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/internal_spec.rb b/spec/ruby/core/io/buffer/internal_spec.rb
new file mode 100644
index 0000000000..73e19eb85e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/internal_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#internal?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for an internally-allocated buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.internal?.should == true
+ end
+
+ it "is false for an externally-allocated buffer" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.internal?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.internal?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/locked_spec.rb b/spec/ruby/core/io/buffer/locked_spec.rb
new file mode 100644
index 0000000000..249026aa8a
--- /dev/null
+++ b/spec/ruby/core/io/buffer/locked_spec.rb
@@ -0,0 +1,75 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#locked" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "when buffer is locked" do
+ it "allows reading and writing operations on the buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ @buffer.locked do
+ @buffer.get_string.should == "test"
+ @buffer.set_string("meat")
+ end
+ @buffer.get_string.should == "meat"
+ end
+
+ it "disallows operations changing buffer itself, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ # Just an example, each method is responsible for checking the lock state.
+ -> { @buffer.resize(8) }.should.raise(IO::Buffer::LockedError)
+ end
+ end
+ end
+
+ it "disallows reentrant locking, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.locked {} }.should.raise(IO::Buffer::LockedError, "Buffer already locked!")
+ end
+ end
+
+ it "does not propagate to buffer's slices" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.locked do
+ @buffer.locked?.should == true
+ slice.locked?.should == false
+ slice.locked { slice.locked?.should == true }
+ end
+ end
+
+ it "does not propagate backwards from buffer's slices" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ slice.locked do
+ slice.locked?.should == true
+ @buffer.locked?.should == false
+ @buffer.locked { @buffer.locked?.should == true }
+ end
+ end
+end
+
+describe "IO::Buffer#locked?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is false by default" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked?.should == false
+ end
+
+ it "is true only inside of #locked block" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ @buffer.locked?.should == true
+ end
+ @buffer.locked?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/map_spec.rb b/spec/ruby/core/io/buffer/map_spec.rb
new file mode 100644
index 0000000000..4b28539ad8
--- /dev/null
+++ b/spec/ruby/core/io/buffer/map_spec.rb
@@ -0,0 +1,343 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.map" do
+ before :all do
+ @tmp_files = []
+
+ @big_file_name = nil
+ @small_file_name = nil
+ end
+
+ after :all do
+ @tmp_files.each {|file| File.delete(file)}
+ end
+
+ def open_fixture
+ unless @small_file_name
+ @small_file_name = tmp("read_text.txt")
+ File.copy_stream(fixture(__dir__, "read_text.txt"), @small_file_name)
+ @tmp_files << @small_file_name
+ end
+ File.open(@small_file_name, "rb+")
+ end
+
+ def open_big_file_fixture
+ unless @big_file_name
+ @big_file_name = tmp("big_file")
+ # Usually 4 kibibytes + 16 bytes
+ File.write(@big_file_name, "12345678" * (IO::Buffer::PAGE_SIZE / 8 + 2))
+ @tmp_files << @big_file_name
+ end
+ File.open(@big_file_name, "rb+")
+ end
+
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ @file&.close
+ @file = nil
+ end
+
+ it "creates a new buffer mapped from a file" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file)
+
+ @buffer.size.should == 9
+ @buffer.get_string.should == "abcâdef\n".b
+ end
+
+ it "allows to close the file after creating buffer, retaining mapping" do
+ file = open_fixture
+ @buffer = IO::Buffer.map(file)
+ file.close
+
+ @buffer.get_string.should == "abcâdef\n".b
+ end
+
+ it "creates a mapped, external, shared buffer" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file)
+
+ @buffer.should_not.internal?
+ @buffer.should.mapped?
+ @buffer.should.external?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should.shared?
+ @buffer.should_not.private?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ guard -> { Process.respond_to?(:fork) } do
+ it "is shareable across processes" do
+ file_name = tmp("shared_buffer")
+ @file = File.open(file_name, "w+")
+ @file << "I'm private"
+ @file.rewind
+ @buffer = IO::Buffer.map(@file)
+
+ IO.popen("-") do |child_pipe|
+ if child_pipe
+ # Synchronize on child's output.
+ child_pipe.readlines.first.chomp.should == @buffer.to_s
+ @buffer.get_string.should == "I'm shared!"
+
+ @file.read.should == "I'm shared!"
+ else
+ @buffer.set_string("I'm shared!")
+ puts @buffer
+ end
+ ensure
+ child_pipe&.close
+ end
+ ensure
+ File.unlink(file_name)
+ end
+ end
+
+ context "with an empty file" do
+ ruby_version_is "4.0" do
+ it "raises ArgumentError" do
+ file_name = tmp("empty.txt")
+ @file = File.open(file_name, "wb+")
+ @tmp_files << file_name
+ -> { IO::Buffer.map(@file) }.should.raise(ArgumentError, "Invalid negative or zero file size!")
+ end
+ end
+ end
+
+ context "with a file opened only for reading" do
+ it "raises a SystemCallError unless read-only" do
+ @file = File.open(fixture(__dir__, "read_text.txt"), "rb")
+ -> { IO::Buffer.map(@file) }.should.raise(SystemCallError)
+ end
+ end
+
+ context "with size argument" do
+ it "limits the buffer to the specified size in bytes, starting from the start of the file" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, 4)
+
+ @buffer.size.should == 4
+ @buffer.get_string.should == "abc\xC3".b
+ end
+
+ it "maps the whole file if size is nil" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil)
+
+ @buffer.size.should == 9
+ end
+
+ context "if size is 0" do
+ ruby_version_is "4.0" do
+ it "raises ArgumentError" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 0) }.should.raise(ArgumentError, "Size can't be zero!")
+ end
+ end
+ end
+
+ it "raises TypeError if size is not an Integer or nil" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, "10") }.should.raise(TypeError, "not an Integer")
+ -> { IO::Buffer.map(@file, 10.0) }.should.raise(TypeError, "not an Integer")
+ end
+
+ it "raises ArgumentError if size is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, -1) }.should.raise(ArgumentError, "Size can't be negative!")
+ end
+
+ ruby_version_is ""..."4.0" do
+ # May or may not cause a crash on access.
+ it "is undefined behavior if size is larger than file size"
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if size is larger than file size" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 8192) }.should.raise(ArgumentError, "Size can't be larger than file size!")
+ end
+ end
+ end
+
+ context "with size and offset arguments" do
+ # Neither Windows nor macOS have clear, stable behavior with non-zero offset.
+ # https://bugs.ruby-lang.org/issues/21700
+ platform_is :linux do
+ context "if offset is an allowed value for system call" do
+ it "maps the span specified by size starting from the offset" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, 14, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == 14
+ @buffer.get_string(0, 14).should == "12345678123456"
+ end
+
+ context "if size is nil" do
+ ruby_version_is ""..."4.0" do
+ it "maps the rest of the file" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.get_string(0, 1).should == "1"
+ end
+
+ it "incorrectly sets buffer's size to file's full size" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == @file.size
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "maps the rest of the file" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.get_string(0, 1).should == "1"
+ end
+
+ it "sets buffer's size to file's remaining size" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == (@file.size - IO::Buffer::PAGE_SIZE)
+ end
+ end
+ end
+ end
+ end
+
+ it "maps the file from the start if offset is 0" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, 4, 0)
+
+ @buffer.size.should == 4
+ @buffer.get_string.should == "abc\xC3".b
+ end
+
+ ruby_version_is ""..."4.0" do
+ # May or may not cause a crash on access.
+ it "is undefined behavior if offset+size is larger than file size"
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if offset+size is larger than file size" do
+ @file = open_big_file_fixture
+ -> { IO::Buffer.map(@file, 17, IO::Buffer::PAGE_SIZE) }.should.raise(ArgumentError, "Offset too large!")
+ ensure
+ # Windows requires the file to be closed before deletion.
+ @file.close unless @file.closed?
+ end
+ end
+
+ it "raises TypeError if offset is not convertible to Integer" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, "4096") }.should.raise(TypeError, /no implicit conversion/)
+ -> { IO::Buffer.map(@file, 4, nil) }.should.raise(TypeError, /no implicit conversion/)
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if offset is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, -1) }.should.raise(ArgumentError, "Offset can't be negative!")
+ end
+ end
+ end
+
+ context "with flags argument" do
+ context "when READONLY flag is specified" do
+ it "sets readonly flag on the buffer, allowing only reads" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ @buffer.should.readonly?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ end
+
+ it "allows mapping read-only files" do
+ @file = File.open(fixture(__dir__, "read_text.txt"), "rb")
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ @buffer.should.readonly?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ end
+
+ it "causes IO::Buffer::AccessError on write" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ -> { @buffer.set_string("test") }.should.raise(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+ end
+
+ context "when PRIVATE is specified" do
+ it "sets private flag on the buffer, making it freely modifiable" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ @buffer.should.private?
+ @buffer.should_not.shared?
+ @buffer.should_not.external?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ @buffer.set_string("test12345")
+ @buffer.get_string.should == "test12345".b
+
+ @file.read.should == "abcâdef\n".b
+ end
+
+ it "allows mapping read-only files and modifying the buffer" do
+ @file = File.open(fixture(__dir__, "read_text.txt"), "rb")
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ @buffer.should.private?
+ @buffer.should_not.shared?
+ @buffer.should_not.external?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ @buffer.set_string("test12345")
+ @buffer.get_string.should == "test12345".b
+
+ @file.read.should == "abcâdef\n".b
+ end
+
+ guard -> { Process.respond_to?(:fork) } do
+ it "is not shared across processes" do
+ file_name = tmp("shared_buffer")
+ @file = File.open(file_name, "w+")
+ @file << "I'm private"
+ @file.rewind
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ IO.popen("-") do |child_pipe|
+ if child_pipe
+ # Synchronize on child's output.
+ child_pipe.readlines.first.chomp.should == @buffer.to_s
+ @buffer.get_string.should == "I'm private"
+
+ @file.read.should == "I'm private"
+ else
+ @buffer.set_string("I'm shared!")
+ puts @buffer
+ end
+ ensure
+ child_pipe&.close
+ end
+ ensure
+ File.unlink(file_name)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/mapped_spec.rb b/spec/ruby/core/io/buffer/mapped_spec.rb
new file mode 100644
index 0000000000..0decb97704
--- /dev/null
+++ b/spec/ruby/core/io/buffer/mapped_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#mapped?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer with mapped memory" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.mapped?.should == true
+ end
+
+ it "is false for a buffer with non-mapped memory" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.mapped?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.mapped?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/not_spec.rb b/spec/ruby/core/io/buffer/not_spec.rb
new file mode 100644
index 0000000000..4737a30bde
--- /dev/null
+++ b/spec/ruby/core/io/buffer/not_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_not, shared: true do
+ it "inverts every bit of the buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = buffer.send(@method)
+ result.get_string.should == "\xCE\xCD\xCC\xCB\xCA".b
+ result.free
+ end
+ end
+end
+
+describe "IO::Buffer#~" do
+ it_behaves_like :io_buffer_not, :~
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = ~buffer
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ end
+ end
+end
+
+describe "IO::Buffer#not!" do
+ it_behaves_like :io_buffer_not, :not!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = buffer.not!
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/null_spec.rb b/spec/ruby/core/io/buffer/null_spec.rb
new file mode 100644
index 0000000000..380a98bde1
--- /dev/null
+++ b/spec/ruby/core/io/buffer/null_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/null_and_empty'
+
+describe "IO::Buffer#null?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it_behaves_like :io_buffer_null_and_empty, :null?
+
+ it "is false for a 0-length String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("")
+ @buffer.null?.should == false
+ end
+
+ it "is false for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.null?.should == false
+ end
+ end
+
+ it "is false for a 0-length slice of a buffer with size > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(3, 0).null?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/or_spec.rb b/spec/ruby/core/io/buffer/or_spec.rb
new file mode 100644
index 0000000000..3e627c216c
--- /dev/null
+++ b/spec/ruby/core/io/buffer/or_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_or, shared: true do
+ it "applies the argument buffer as an OR bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xF9\xBF\xFB\xBF\xFD".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xF9\xBF345".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should.raise(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should.raise(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should.raise(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#|" do
+ it_behaves_like :io_buffer_or, :|
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer | mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#or!" do
+ it_behaves_like :io_buffer_or, :or!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.or!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/private_spec.rb b/spec/ruby/core/io/buffer/private_spec.rb
new file mode 100644
index 0000000000..6e6afee34c
--- /dev/null
+++ b/spec/ruby/core/io/buffer/private_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#private?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer created with PRIVATE flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::PRIVATE)
+ @buffer.private?.should == true
+ end
+
+ it "is false for a buffer created without PRIVATE flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL)
+ @buffer.private?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.private?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/readonly_spec.rb b/spec/ruby/core/io/buffer/readonly_spec.rb
new file mode 100644
index 0000000000..4eefc9f29f
--- /dev/null
+++ b/spec/ruby/core/io/buffer/readonly_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#readonly?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer created with READONLY flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::READONLY)
+ @buffer.readonly?.should == true
+ end
+
+ it "is true for a buffer that is non-writable" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.readonly?.should == true
+ end
+
+ it "is false for a modifiable buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.readonly?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.readonly?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/resize_spec.rb b/spec/ruby/core/io/buffer/resize_spec.rb
new file mode 100644
index 0000000000..6e684475f3
--- /dev/null
+++ b/spec/ruby/core/io/buffer/resize_spec.rb
@@ -0,0 +1,151 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#resize" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "resizes internal buffer, preserving type" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(IO::Buffer::PAGE_SIZE)
+ @buffer.size.should == IO::Buffer::PAGE_SIZE
+ @buffer.internal?.should == true
+ @buffer.mapped?.should == false
+ end
+
+ platform_is :linux do
+ it "resizes mapped buffer, preserving type" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
+ @buffer.resize(4)
+ @buffer.size.should == 4
+ @buffer.internal?.should == false
+ @buffer.mapped?.should == true
+ end
+ end
+
+ platform_is_not :linux do
+ it "resizes mapped buffer, changing type to internal" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
+ @buffer.resize(4)
+ @buffer.size.should == 4
+ @buffer.internal?.should == true
+ @buffer.mapped?.should == false
+ end
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "disallows resizing shared buffer, raising IO::Buffer::AccessError" do
+ File.open(__FILE__, "r+") do |file|
+ @buffer = IO::Buffer.map(file)
+ -> { @buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+
+ it "resizes private buffer, discarding excess contents" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.get_string.should == "require_re"
+ @buffer.resize(12)
+ @buffer.size.should == 12
+ @buffer.get_string.should == "require_re\0\0"
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ @buffer = IO::Buffer.for(+"test")
+ -> { @buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+
+ context "with a block" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.for(+'test') do |buffer|
+ -> { buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.string(4) do |buffer|
+ -> { buffer.resize(10) }.should.raise(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+ end
+
+ context "with a null buffer" do
+ it "allows resizing a 0-sized buffer, creating a regular buffer according to new size" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.resize(IO::Buffer::PAGE_SIZE)
+ @buffer.size.should == IO::Buffer::PAGE_SIZE
+ @buffer.internal?.should == false
+ @buffer.mapped?.should == true
+ end
+
+ it "allows resizing after a free, creating a regular buffer according to new size" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.free
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.internal?.should == true
+ @buffer.mapped?.should == false
+ end
+ end
+
+ it "allows resizing to 0, freeing memory" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(0)
+ @buffer.null?.should == true
+ end
+
+ it "can be called repeatedly" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(10)
+ @buffer.resize(27)
+ @buffer.resize(1)
+ @buffer.size.should == 1
+ end
+
+ it "always clears extra memory" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ # This should not cause a re-allocation, just a technical resizing,
+ # even with very aggressive memory allocation.
+ @buffer.resize(2)
+ @buffer.resize(4)
+ @buffer.get_string.should == "te\0\0"
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.resize(10) }.should.raise(IO::Buffer::LockedError, "Cannot resize locked buffer!")
+ end
+ end
+
+ it "raises ArgumentError if size is negative" do
+ @buffer = IO::Buffer.new(4)
+ -> { @buffer.resize(-1) }.should.raise(ArgumentError, "Size can't be negative!")
+ end
+
+ it "raises TypeError if size is not an Integer" do
+ @buffer = IO::Buffer.new(4)
+ -> { @buffer.resize(nil) }.should.raise(TypeError, "not an Integer")
+ -> { @buffer.resize(10.0) }.should.raise(TypeError, "not an Integer")
+ end
+
+ context "with a slice of a buffer" do
+ # Current behavior of slice resizing seems unintended (it's undocumented, too).
+ # It either creates a completely new buffer, or breaks the slice on size 0.
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/io/buffer/shared/null_and_empty.rb b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
new file mode 100644
index 0000000000..f8abc5f0fc
--- /dev/null
+++ b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
@@ -0,0 +1,57 @@
+describe :io_buffer_null_and_empty, shared: true do
+ it "is false for a buffer with size > 0" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.send(@method).should == false
+ end
+
+ it "is false for a slice with length > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(1, 2).send(@method).should == false
+ end
+
+ it "is false for a file-mapped buffer" do
+ File.open(__FILE__, "rb") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.send(@method).should == false
+ end
+ end
+
+ it "is false for a non-empty String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.send(@method).should == false
+ end
+
+ it "is false for a non-empty String-backed buffer created with .string" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.send(@method).should == false
+ end
+ end
+
+ it "is true for a 0-sized buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.send(@method).should == true
+ end
+
+ it "is true for a slice of a 0-sized buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.slice(0, 0).send(@method).should == true
+ end
+
+ it "is true for a freed buffer" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.free
+ @buffer.send(@method).should == true
+ end
+
+ it "is true for a buffer resized to 0" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.resize(0)
+ @buffer.send(@method).should == true
+ end
+
+ it "is true for a buffer whose memory was transferred" do
+ buffer = IO::Buffer.new(1)
+ @buffer = buffer.transfer
+ buffer.send(@method).should == true
+ end
+end
diff --git a/spec/ruby/core/io/buffer/shared_spec.rb b/spec/ruby/core/io/buffer/shared_spec.rb
new file mode 100644
index 0000000000..2cc93e6d08
--- /dev/null
+++ b/spec/ruby/core/io/buffer/shared_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#shared?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is true for a buffer created with SHARED flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::SHARED)
+ @buffer.shared?.should == true
+ end
+
+ it "is true for a non-private buffer created with .map" do
+ path = fixture(__dir__, "read_text.txt")
+ file = File.open(path, "r+")
+ @buffer = IO::Buffer.map(file)
+ @buffer.shared?.should == true
+ ensure
+ @buffer.free
+ file.close
+ end
+
+ it "is false for an unshared buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.shared?.should == false
+ end
+
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.shared?.should == false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/string_spec.rb b/spec/ruby/core/io/buffer/string_spec.rb
new file mode 100644
index 0000000000..4c73ba5e1e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/string_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.string" do
+ it "creates a modifiable buffer for the duration of the block" do
+ IO::Buffer.string(7) do |buffer|
+ @buffer = buffer
+
+ buffer.size.should == 7
+ buffer.get_string.should == "\0\0\0\0\0\0\0".b
+
+ buffer.set_string("test")
+ buffer.get_string.should == "test\0\0\0"
+ end
+ @buffer.should.null?
+ end
+
+ it "returns contents of the buffer as a binary string" do
+ string =
+ IO::Buffer.string(7) do |buffer|
+ buffer.set_string("ä test")
+ end
+ string.should == "\xC3\xA4 test".b
+ end
+
+ it "creates an external buffer" do
+ IO::Buffer.string(8) do |buffer|
+ buffer.should_not.internal?
+ buffer.should_not.mapped?
+ buffer.should.external?
+
+ buffer.should_not.empty?
+ buffer.should_not.null?
+
+ buffer.should_not.shared?
+ buffer.should_not.private?
+ buffer.should_not.readonly?
+
+ buffer.should_not.locked?
+ buffer.should.valid?
+ end
+ end
+
+ it "returns an empty string if size is 0" do
+ string =
+ IO::Buffer.string(0) do |buffer|
+ buffer.size.should == 0
+ end
+ string.should == ""
+ end
+
+ it "raises ArgumentError if size is negative" do
+ -> { IO::Buffer.string(-1) {} }.should.raise(ArgumentError, "negative string size (or size too big)")
+ end
+
+ it "raises RangeError if size is too large" do
+ -> { IO::Buffer.string(2 ** 232) {} }.should.raise(RangeError, /\Abignum too big to convert into [`']long'\z/)
+ end
+
+ it "raises LocalJumpError if no block is given" do
+ -> { IO::Buffer.string(7) }.should.raise(LocalJumpError, "no block given")
+ end
+end
diff --git a/spec/ruby/core/io/buffer/transfer_spec.rb b/spec/ruby/core/io/buffer/transfer_spec.rb
new file mode 100644
index 0000000000..3bc08998dd
--- /dev/null
+++ b/spec/ruby/core/io/buffer/transfer_spec.rb
@@ -0,0 +1,117 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#transfer" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "transfers internal memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.new(4)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+
+ it "transfers mapped memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "transfers mapped memory to a new buffer, nullifying the original" do
+ File.open(__FILE__, "r") do |file|
+ buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "transfers memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.for("test")
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ end
+
+ context "with a block" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.for(+"test") do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ @buffer.null?.should == false
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.string(4) do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should == true
+ end
+ @buffer.null?.should == false
+ end
+ end
+
+ it "allows multiple transfers" do
+ buffer_1 = IO::Buffer.new(4)
+ buffer_2 = buffer_1.transfer
+ @buffer = buffer_2.transfer
+ buffer_1.null?.should == true
+ buffer_2.null?.should == true
+ @buffer.null?.should == false
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.transfer }.should.raise(IO::Buffer::LockedError, "Cannot transfer ownership of locked buffer!")
+ end
+ end
+
+ context "with a slice of a buffer" do
+ it "transfers source to a new slice, not touching the buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ slice = @buffer.slice(0, 2)
+ slice.get_string.should == "te"
+
+ new_slice = slice.transfer
+ slice.null?.should == true
+ new_slice.null?.should == false
+ @buffer.null?.should == false
+
+ new_slice.set_string("ea")
+ @buffer.get_string.should == "east"
+ end
+
+ it "nullifies buffer, invalidating the slice" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+ @buffer = buffer.transfer
+
+ slice.null?.should == false
+ slice.valid?.should == false
+ -> { slice.get_string }.should.raise(IO::Buffer::InvalidatedError, "Buffer has been invalidated!")
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/valid_spec.rb b/spec/ruby/core/io/buffer/valid_spec.rb
new file mode 100644
index 0000000000..b84bdd0cfd
--- /dev/null
+++ b/spec/ruby/core/io/buffer/valid_spec.rb
@@ -0,0 +1,99 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#valid?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ # Non-slices are always valid
+ context "with a non-slice buffer" do
+ it "is true for a regular buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.valid?.should == true
+ end
+
+ it "is true for a 0-size buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.valid?.should == true
+ end
+
+ it "is true for a freed buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.free
+ @buffer.valid?.should == true
+ end
+
+ it "is true for a freed file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.valid?.should == true
+ @buffer.free
+ @buffer.valid?.should == true
+ end
+ end
+
+ it "is true for a freed string-backed buffer" do
+ @buffer = IO::Buffer.for("hello")
+ @buffer.valid?.should == true
+ @buffer.free
+ @buffer.valid?.should == true
+ end
+ end
+
+ # "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."
+ context "with a slice" do
+ it "is true for a slice of a live buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should == true
+ end
+
+ context "when buffer is resized" do
+ it "is false when slice becomes outside the buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(2, 2)
+ @buffer.resize(3)
+ slice.valid?.should == false
+ end
+ end
+
+ it "is false for a slice of a transferred buffer" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+ @buffer = buffer.transfer
+ slice.valid?.should == false
+ end
+
+ it "is false for a slice of a freed buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.free
+ slice.valid?.should == false
+ end
+
+ it "is false for a slice of a freed file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should == true
+ @buffer.free
+ slice.valid?.should == false
+ end
+ end
+
+ it "is true for a slice of a freed string-backed buffer while string is alive" do
+ @buffer = IO::Buffer.for("alive")
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should == true
+ @buffer.free
+ slice.valid?.should == true
+ end
+
+ # There probably should be a test with a garbage-collected string,
+ # but it's not clear how to force that.
+
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/io/buffer/xor_spec.rb b/spec/ruby/core/io/buffer/xor_spec.rb
new file mode 100644
index 0000000000..9287611f7f
--- /dev/null
+++ b/spec/ruby/core/io/buffer/xor_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_xor, shared: true do
+ it "applies the argument buffer as an XOR bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xC9\xBD\xCB\xBB\xCD".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xC9\xBD345".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should.raise(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should.raise(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should.raise(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#^" do
+ it_behaves_like :io_buffer_xor, :^
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer ^ mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#xor!" do
+ it_behaves_like :io_buffer_xor, :xor!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.xor!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/close_on_exec_spec.rb b/spec/ruby/core/io/close_on_exec_spec.rb
index 4e89e08d61..28cdb967b9 100644
--- a/spec/ruby/core/io/close_on_exec_spec.rb
+++ b/spec/ruby/core/io/close_on_exec_spec.rb
@@ -42,7 +42,7 @@ describe "IO#close_on_exec=" do
it "raises IOError if called on a closed IO" do
@io.close
- -> { @io.close_on_exec = true }.should raise_error(IOError)
+ -> { @io.close_on_exec = true }.should.raise(IOError)
end
end
end
@@ -70,7 +70,7 @@ describe "IO#close_on_exec?" do
it "raises IOError if called on a closed IO" do
@io.close
- -> { @io.close_on_exec? }.should raise_error(IOError)
+ -> { @io.close_on_exec? }.should.raise(IOError)
end
end
end
diff --git a/spec/ruby/core/io/close_read_spec.rb b/spec/ruby/core/io/close_read_spec.rb
index e700e85bd9..c505289d72 100644
--- a/spec/ruby/core/io/close_read_spec.rb
+++ b/spec/ruby/core/io/close_read_spec.rb
@@ -17,26 +17,26 @@ describe "IO#close_read" do
it "closes the read end of a duplex I/O stream" do
@io.close_read
- -> { @io.read }.should raise_error(IOError)
+ -> { @io.read }.should.raise(IOError)
end
it "does nothing on subsequent invocations" do
@io.close_read
- @io.close_read.should be_nil
+ @io.close_read.should == nil
end
it "allows subsequent invocation of close" do
@io.close_read
- -> { @io.close }.should_not raise_error
+ -> { @io.close }.should_not.raise
end
it "raises an IOError if the stream is writable and not duplexed" do
io = File.open @path, 'w'
begin
- -> { io.close_read }.should raise_error(IOError)
+ -> { io.close_read }.should.raise(IOError)
ensure
io.close unless io.closed?
end
@@ -56,6 +56,6 @@ describe "IO#close_read" do
it "does nothing on closed stream" do
@io.close
- @io.close_read.should be_nil
+ @io.close_read.should == nil
end
end
diff --git a/spec/ruby/core/io/close_spec.rb b/spec/ruby/core/io/close_spec.rb
index 3a44cc8b17..afd84ba101 100644
--- a/spec/ruby/core/io/close_spec.rb
+++ b/spec/ruby/core/io/close_spec.rb
@@ -23,25 +23,25 @@ describe "IO#close" do
it "raises an IOError reading from a closed IO" do
@io.close
- -> { @io.read }.should raise_error(IOError)
+ -> { @io.read }.should.raise(IOError)
end
it "raises an IOError writing to a closed IO" do
@io.close
- -> { @io.write "data" }.should raise_error(IOError)
+ -> { @io.write "data" }.should.raise(IOError)
end
it 'does not close the stream if autoclose is false' do
other_io = IO.new(@io.fileno)
other_io.autoclose = false
other_io.close
- -> { @io.write "data" }.should_not raise_error(IOError)
+ -> { @io.write "data" }.should_not.raise(IOError)
end
it "does nothing if already closed" do
@io.close
- @io.close.should be_nil
+ @io.close.should == nil
end
it "does not call the #flush method but flushes the stream internally" do
@@ -80,7 +80,7 @@ describe "IO#close" do
matching_exception&.tap {|ex| raise ex}
end
- end.should raise_error(IOError, IOSpecs::THREAD_CLOSE_ERROR_MESSAGE)
+ end.should.raise(IOError, IOSpecs::THREAD_CLOSE_ERROR_MESSAGE)
end
end
@@ -93,7 +93,7 @@ describe "IO#close on an IO.popen stream" do
io.close
- -> { io.pid }.should raise_error(IOError)
+ -> { io.pid }.should.raise(IOError)
end
it "sets $?" do
diff --git a/spec/ruby/core/io/close_write_spec.rb b/spec/ruby/core/io/close_write_spec.rb
index 70610a3e9d..60b41505c3 100644
--- a/spec/ruby/core/io/close_write_spec.rb
+++ b/spec/ruby/core/io/close_write_spec.rb
@@ -16,26 +16,26 @@ describe "IO#close_write" do
it "closes the write end of a duplex I/O stream" do
@io.close_write
- -> { @io.write "attempt to write" }.should raise_error(IOError)
+ -> { @io.write "attempt to write" }.should.raise(IOError)
end
it "does nothing on subsequent invocations" do
@io.close_write
- @io.close_write.should be_nil
+ @io.close_write.should == nil
end
it "allows subsequent invocation of close" do
@io.close_write
- -> { @io.close }.should_not raise_error
+ -> { @io.close }.should_not.raise
end
it "raises an IOError if the stream is readable and not duplexed" do
io = File.open @path, 'w+'
begin
- -> { io.close_write }.should raise_error(IOError)
+ -> { io.close_write }.should.raise(IOError)
ensure
io.close unless io.closed?
end
@@ -63,6 +63,6 @@ describe "IO#close_write" do
it "does nothing on closed stream" do
@io.close
- @io.close_write.should be_nil
+ @io.close_write.should == nil
end
end
diff --git a/spec/ruby/core/io/closed_spec.rb b/spec/ruby/core/io/closed_spec.rb
index 7316546a0d..1f10858e28 100644
--- a/spec/ruby/core/io/closed_spec.rb
+++ b/spec/ruby/core/io/closed_spec.rb
@@ -11,10 +11,10 @@ describe "IO#closed?" do
end
it "returns true on closed stream" do
- IOSpecs.closed_io.closed?.should be_true
+ IOSpecs.closed_io.closed?.should == true
end
it "returns false on open stream" do
- @io.closed?.should be_false
+ @io.closed?.should == false
end
end
diff --git a/spec/ruby/core/io/copy_stream_spec.rb b/spec/ruby/core/io/copy_stream_spec.rb
index ffa2ea992c..31383f9b0f 100644
--- a/spec/ruby/core/io/copy_stream_spec.rb
+++ b/spec/ruby/core/io/copy_stream_spec.rb
@@ -31,7 +31,7 @@ describe :io_copy_stream_to_file, shared: true do
obj = mock("io_copy_stream_to")
obj.should_receive(:to_path).and_return(1)
- -> { IO.copy_stream(@object.from, obj) }.should raise_error(TypeError)
+ -> { IO.copy_stream(@object.from, obj) }.should.raise(TypeError)
end
end
@@ -71,7 +71,7 @@ describe :io_copy_stream_to_io, shared: true do
it "raises an IOError if the destination IO is not open for writing" do
to_io = new_io __FILE__, "r"
begin
- -> { IO.copy_stream @object.from, to_io }.should raise_error(IOError)
+ -> { IO.copy_stream @object.from, to_io }.should.raise(IOError)
ensure
to_io.close
end
@@ -79,7 +79,7 @@ describe :io_copy_stream_to_io, shared: true do
it "does not close the destination IO" do
IO.copy_stream(@object.from, @to_io)
- @to_io.closed?.should be_false
+ @to_io.closed?.should == false
end
it "copies only length bytes when specified" do
@@ -129,12 +129,12 @@ describe "IO.copy_stream" do
it "raises an IOError if the source IO is not open for reading" do
@from_io.close
@from_io = new_io @from_bigfile, "a"
- -> { IO.copy_stream @from_io, @to_name }.should raise_error(IOError)
+ -> { IO.copy_stream @from_io, @to_name }.should.raise(IOError)
end
it "does not close the source IO" do
IO.copy_stream(@from_io, @to_name)
- @from_io.closed?.should be_false
+ @from_io.closed?.should == false
end
platform_is_not :windows do
@@ -206,7 +206,7 @@ describe "IO.copy_stream" do
obj = mock("io_copy_stream_from")
obj.should_receive(:to_path).and_return(1)
- -> { IO.copy_stream(obj, @to_name) }.should raise_error(TypeError)
+ -> { IO.copy_stream(obj, @to_name) }.should.raise(TypeError)
end
describe "to a file name" do
@@ -240,12 +240,12 @@ describe "IO.copy_stream" do
it "does not close the source IO" do
IO.copy_stream(@from_io, @to_name)
- @from_io.closed?.should be_false
+ @from_io.closed?.should == false
end
platform_is_not :windows do
it "raises an error when an offset is specified" do
- -> { IO.copy_stream(@from_io, @to_name, 8, 4) }.should raise_error(Errno::ESPIPE)
+ -> { IO.copy_stream(@from_io, @to_name, 8, 4) }.should.raise(Errno::ESPIPE)
end
end
@@ -300,6 +300,14 @@ describe "IO.copy_stream" do
@io.should_not_receive(:pos)
IO.copy_stream(@io, @to_name)
end
+
+ it "does not call #read on the source or #write on the destination if zero length is given" do
+ from = mock("io_copy_stream_to_object_zero_length_read")
+ to = mock("io_copy_stream_to_object_zero_length_write")
+ from.should_not_receive(:read)
+ to.should_not_receive(:write)
+ IO.copy_stream(from, to, 0)
+ end
end
describe "with a destination that does partial reads" do
diff --git a/spec/ruby/core/io/dup_spec.rb b/spec/ruby/core/io/dup_spec.rb
index 564e007438..db4e9fe641 100644
--- a/spec/ruby/core/io/dup_spec.rb
+++ b/spec/ruby/core/io/dup_spec.rb
@@ -49,7 +49,7 @@ describe "IO#dup" do
it "allows closing the new IO without affecting the original" do
@i.close
- -> { @f.gets }.should_not raise_error(Exception)
+ -> { @f.gets }.should_not.raise(Exception)
@i.should.closed?
@f.should_not.closed?
@@ -57,14 +57,14 @@ describe "IO#dup" do
it "allows closing the original IO without affecting the new one" do
@f.close
- -> { @i.gets }.should_not raise_error(Exception)
+ -> { @i.gets }.should_not.raise(Exception)
@i.should_not.closed?
@f.should.closed?
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.dup }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.dup }.should.raise(IOError)
end
it "always sets the close-on-exec flag for the new IO object" do
diff --git a/spec/ruby/core/io/each_byte_spec.rb b/spec/ruby/core/io/each_byte_spec.rb
index ea618e8c0c..fe299f0fba 100644
--- a/spec/ruby/core/io/each_byte_spec.rb
+++ b/spec/ruby/core/io/each_byte_spec.rb
@@ -12,7 +12,7 @@ describe "IO#each_byte" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.each_byte {} }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.each_byte {} }.should.raise(IOError)
end
it "yields each byte" do
@@ -28,7 +28,7 @@ describe "IO#each_byte" do
describe "when no block is given" do
it "returns an Enumerator" do
enum = @io.each_byte
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.first(5).should == [86, 111, 105, 99, 105]
end
@@ -52,6 +52,6 @@ describe "IO#each_byte" do
end
it "returns self on an empty stream" do
- @io.each_byte { |b| }.should equal(@io)
+ @io.each_byte { |b| }.should.equal?(@io)
end
end
diff --git a/spec/ruby/core/io/each_codepoint_spec.rb b/spec/ruby/core/io/each_codepoint_spec.rb
index 07a4037c8a..26cc87fc0e 100644
--- a/spec/ruby/core/io/each_codepoint_spec.rb
+++ b/spec/ruby/core/io/each_codepoint_spec.rb
@@ -24,7 +24,7 @@ describe "IO#each_codepoint" do
end
it "returns self" do
- @io.each_codepoint { |l| l }.should equal(@io)
+ @io.each_codepoint { |l| l }.should.equal?(@io)
end
end
@@ -38,6 +38,6 @@ describe "IO#each_codepoint" do
end
it "raises an exception at incomplete character before EOF when conversion takes place" do
- -> { @io.each_codepoint {} }.should raise_error(ArgumentError)
+ -> { @io.each_codepoint {} }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/eof_spec.rb b/spec/ruby/core/io/eof_spec.rb
index b4850df437..c8955abde0 100644
--- a/spec/ruby/core/io/eof_spec.rb
+++ b/spec/ruby/core/io/eof_spec.rb
@@ -18,7 +18,7 @@ describe "IO#eof?" do
it "raises IOError on stream not opened for reading" do
-> do
File.open(@name, "w") { |f| f.eof? }
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -67,12 +67,12 @@ describe "IO#eof?" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.eof? }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.eof? }.should.raise(IOError)
end
it "raises IOError on stream closed for reading by close_read" do
@io.close_read
- -> { @io.eof? }.should raise_error(IOError)
+ -> { @io.eof? }.should.raise(IOError)
end
it "returns true on one-byte stream after single-byte read" do
diff --git a/spec/ruby/core/io/external_encoding_spec.rb b/spec/ruby/core/io/external_encoding_spec.rb
index 7765c6c0f5..72d246cc2b 100644
--- a/spec/ruby/core/io/external_encoding_spec.rb
+++ b/spec/ruby/core/io/external_encoding_spec.rb
@@ -10,19 +10,19 @@ describe :io_external_encoding_write, shared: true do
it "returns nil" do
@io = new_io @name, @object
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should be_nil
+ @io.external_encoding.should == nil
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "#{@object}:ibm866"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "#{@object}:ibm866"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -35,19 +35,19 @@ describe :io_external_encoding_write, shared: true do
it "returns the value of Encoding.default_external when the instance was created" do
@io = new_io @name, @object
Encoding.default_external = Encoding::UTF_8
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "#{@object}:ibm866"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "#{@object}:ibm866"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -60,19 +60,19 @@ describe :io_external_encoding_write, shared: true do
it "returns the value of Encoding.default_external when the instance was created" do
@io = new_io @name, @object
Encoding.default_external = Encoding::UTF_8
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "#{@object}:ibm866"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "#{@object}:ibm866"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
end
@@ -97,7 +97,7 @@ describe "IO#external_encoding" do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
- io.external_encoding.should equal(Encoding.default_external)
+ io.external_encoding.should.equal?(Encoding.default_external)
end
describe "with 'r' mode" do
@@ -109,25 +109,25 @@ describe "IO#external_encoding" do
it "returns Encoding.default_external if the external encoding is not set" do
@io = new_io @name, "r"
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns Encoding.default_external when that encoding is changed after the instance is created" do
@io = new_io @name, "r"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "r:utf-8"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::UTF_8)
+ @io.external_encoding.should.equal?(Encoding::UTF_8)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "r:utf-8"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -140,19 +140,19 @@ describe "IO#external_encoding" do
it "returns the value of Encoding.default_external when the instance was created" do
@io = new_io @name, "r"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM866)
end
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "r:utf-8"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::UTF_8)
+ @io.external_encoding.should.equal?(Encoding::UTF_8)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "r:utf-8"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -166,13 +166,13 @@ describe "IO#external_encoding" do
it "returns the external encoding specified when the instance was created" do
@io = new_io @name, "r:utf-8"
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::UTF_8)
+ @io.external_encoding.should.equal?(Encoding::UTF_8)
end
it "returns the encoding set by #set_encoding" do
@io = new_io @name, "r:utf-8"
@io.set_encoding Encoding::EUC_JP, nil
- @io.external_encoding.should equal(Encoding::EUC_JP)
+ @io.external_encoding.should.equal?(Encoding::EUC_JP)
end
end
end
@@ -180,12 +180,12 @@ describe "IO#external_encoding" do
describe "with 'rb' mode" do
it "returns Encoding::BINARY" do
@io = new_io @name, "rb"
- @io.external_encoding.should equal(Encoding::BINARY)
+ @io.external_encoding.should.equal?(Encoding::BINARY)
end
it "returns the external encoding specified by the mode argument" do
@io = new_io @name, "rb:ibm437"
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
end
@@ -200,12 +200,12 @@ describe "IO#external_encoding" do
describe "with 'wb' mode" do
it "returns Encoding::BINARY" do
@io = new_io @name, "wb"
- @io.external_encoding.should equal(Encoding::BINARY)
+ @io.external_encoding.should.equal?(Encoding::BINARY)
end
it "returns the external encoding specified by the mode argument" do
@io = new_io @name, "wb:ibm437"
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
end
diff --git a/spec/ruby/core/io/fcntl_spec.rb b/spec/ruby/core/io/fcntl_spec.rb
index 30b4876fe3..be6d06c672 100644
--- a/spec/ruby/core/io/fcntl_spec.rb
+++ b/spec/ruby/core/io/fcntl_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "IO#fcntl" do
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.fcntl(5, 5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.fcntl(5, 5) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/fileno_spec.rb b/spec/ruby/core/io/fileno_spec.rb
index 647609bf42..22fd68d166 100644
--- a/spec/ruby/core/io/fileno_spec.rb
+++ b/spec/ruby/core/io/fileno_spec.rb
@@ -7,6 +7,6 @@ describe "IO#fileno" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.fileno }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.fileno }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/flush_spec.rb b/spec/ruby/core/io/flush_spec.rb
index f7d5ba77fc..4c3e8d12af 100644
--- a/spec/ruby/core/io/flush_spec.rb
+++ b/spec/ruby/core/io/flush_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "IO#flush" do
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.flush }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.flush }.should.raise(IOError)
end
describe "on a pipe" do
@@ -29,8 +29,8 @@ describe "IO#flush" do
@w.write "foo"
@r.close
- -> { @w.flush }.should raise_error(Errno::EPIPE, /Broken pipe/)
- -> { @w.close }.should raise_error(Errno::EPIPE, /Broken pipe/)
+ -> { @w.flush }.should.raise(Errno::EPIPE, /Broken pipe/)
+ -> { @w.close }.should.raise(Errno::EPIPE, /Broken pipe/)
end
end
end
diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb
index c361d27879..015988f9fb 100644
--- a/spec/ruby/core/io/foreach_spec.rb
+++ b/spec/ruby/core/io/foreach_spec.rb
@@ -14,45 +14,45 @@ describe "IO.foreach" do
IO.foreach(@name) { $..should == @count += 1 }
end
- describe "when the filename starts with |" do
- it "gets data from the standard out of the subprocess" do
- cmd = "|sh -c 'echo hello;echo line2'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello&echo line2"
- end
+ ruby_version_is ""..."4.0" do
+ describe "when the filename starts with |" do
+ it "gets data from the standard out of the subprocess" do
+ cmd = "|sh -c 'echo hello;echo line2'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello&echo line2"
+ end
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach(cmd) { |l| ScratchPad << l }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.foreach(cmd) { |l| ScratchPad << l }
+ end
+ ScratchPad.recorded.should == ["hello\n", "line2\n"]
end
- ScratchPad.recorded.should == ["hello\n", "line2\n"]
- end
- platform_is_not :windows do
- it "gets data from a fork when passed -" do
- parent_pid = $$
+ platform_is_not :windows do
+ it "gets data from a fork when passed -" do
+ parent_pid = $$
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach("|-") { |l| ScratchPad << l }
- end
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.foreach("|-") { |l| ScratchPad << l }
+ end
- if $$ == parent_pid
- ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
- else # child
- puts "hello"
- puts "from a fork"
- exit!
+ if $$ == parent_pid
+ ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
+ else # child
+ puts "hello"
+ puts "from a fork"
+ exit!
+ end
end
end
end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.foreach(cmd).to_a
- }.should complain(/IO process creation with a leading '\|'/)
- end
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ IO.foreach(cmd).to_a
+ }.should complain(/IO process creation with a leading '\|'/)
end
end
end
@@ -73,12 +73,12 @@ describe "IO.foreach" do
it "sets $_ to nil" do
$_ = "test"
IO.foreach(@name) { }
- $_.should be_nil
+ $_.should == nil
end
describe "when no block is given" do
it "returns an Enumerator" do
- IO.foreach(@name).should be_an_instance_of(Enumerator)
+ IO.foreach(@name).should.instance_of?(Enumerator)
IO.foreach(@name).to_a.should == IOSpecs.lines
end
diff --git a/spec/ruby/core/io/fsync_spec.rb b/spec/ruby/core/io/fsync_spec.rb
index 6e6123de94..0317cbc805 100644
--- a/spec/ruby/core/io/fsync_spec.rb
+++ b/spec/ruby/core/io/fsync_spec.rb
@@ -12,7 +12,7 @@ describe "IO#fsync" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.fsync }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.fsync }.should.raise(IOError)
end
it "writes the buffered data to permanent storage" do
diff --git a/spec/ruby/core/io/getbyte_spec.rb b/spec/ruby/core/io/getbyte_spec.rb
index b4351160e6..668d81519c 100644
--- a/spec/ruby/core/io/getbyte_spec.rb
+++ b/spec/ruby/core/io/getbyte_spec.rb
@@ -23,7 +23,7 @@ describe "IO#getbyte" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.getbyte }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.getbyte }.should.raise(IOError)
end
end
@@ -53,6 +53,6 @@ describe "IO#getbyte" do
end
it "raises an IOError if the stream is not readable" do
- -> { @io.getbyte }.should raise_error(IOError)
+ -> { @io.getbyte }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/getc_spec.rb b/spec/ruby/core/io/getc_spec.rb
index 3949b5cb28..3be86203c0 100644
--- a/spec/ruby/core/io/getc_spec.rb
+++ b/spec/ruby/core/io/getc_spec.rb
@@ -19,11 +19,11 @@ describe "IO#getc" do
it "returns nil when invoked at the end of the stream" do
@io.read
- @io.getc.should be_nil
+ @io.getc.should == nil
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.getc }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.getc }.should.raise(IOError)
end
end
@@ -37,6 +37,6 @@ describe "IO#getc" do
end
it "returns nil on empty stream" do
- @io.getc.should be_nil
+ @io.getc.should == nil
end
end
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index ca64bf860e..ce3ee73b94 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -27,7 +27,7 @@ describe "IO#gets" do
it "sets $_ to nil after the last line has been read" do
while @io.gets
end
- $_.should be_nil
+ $_.should == nil
end
it "returns nil if called at the end of the stream" do
@@ -36,7 +36,7 @@ describe "IO#gets" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.gets }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.gets }.should.raise(IOError)
end
describe "with no separator" do
@@ -156,11 +156,11 @@ describe "IO#gets" do
end
it "raises exception when options passed as Hash" do
- -> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
+ -> { @io.gets({ chomp: true }) }.should.raise(TypeError)
-> {
@io.gets("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
@@ -175,11 +175,11 @@ describe "IO#gets" do
end
it "raises an IOError if the stream is opened for append only" do
- -> { File.open(@name, "a:utf-8") { |f| f.gets } }.should raise_error(IOError)
+ -> { File.open(@name, "a:utf-8") { |f| f.gets } }.should.raise(IOError)
end
it "raises an IOError if the stream is opened for writing only" do
- -> { File.open(@name, "w:utf-8") { |f| f.gets } }.should raise_error(IOError)
+ -> { File.open(@name, "w:utf-8") { |f| f.gets } }.should.raise(IOError)
end
end
@@ -251,7 +251,7 @@ describe "IO#gets" do
end
it "does not accept limit that doesn't fit in a C off_t" do
- -> { @io.gets(2**128) }.should raise_error(RangeError)
+ -> { @io.gets(2**128) }.should.raise(RangeError)
end
end
@@ -338,23 +338,11 @@ describe "IO#gets" do
@io.gets.encoding.should == Encoding::BINARY
end
- ruby_version_is ''...'3.3' do
- it "transcodes to internal encoding if the IO object's external encoding is BINARY" do
- Encoding.default_external = Encoding::BINARY
- Encoding.default_internal = Encoding::UTF_8
- @io = new_io @name, 'r'
- @io.set_encoding Encoding::BINARY, Encoding::UTF_8
- @io.gets.encoding.should == Encoding::UTF_8
- end
- end
-
- ruby_version_is '3.3' do
- it "ignores the internal encoding if the IO object's external encoding is BINARY" do
- Encoding.default_external = Encoding::BINARY
- Encoding.default_internal = Encoding::UTF_8
- @io = new_io @name, 'r'
- @io.set_encoding Encoding::BINARY, Encoding::UTF_8
- @io.gets.encoding.should == Encoding::BINARY
- end
+ it "ignores the internal encoding if the IO object's external encoding is BINARY" do
+ Encoding.default_external = Encoding::BINARY
+ Encoding.default_internal = Encoding::UTF_8
+ @io = new_io @name, 'r'
+ @io.set_encoding Encoding::BINARY, Encoding::UTF_8
+ @io.gets.encoding.should == Encoding::BINARY
end
end
diff --git a/spec/ruby/core/io/initialize_spec.rb b/spec/ruby/core/io/initialize_spec.rb
index 026252a13d..3425e5ac37 100644
--- a/spec/ruby/core/io/initialize_spec.rb
+++ b/spec/ruby/core/io/initialize_spec.rb
@@ -35,26 +35,26 @@ describe "IO#initialize" do
-> {
@io.send(:initialize, fd, "w", {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
end
it "raises a TypeError when passed an IO" do
- -> { @io.send :initialize, STDOUT, 'w' }.should raise_error(TypeError)
+ -> { @io.send :initialize, STDOUT, 'w' }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @io.send :initialize, nil, 'w' }.should raise_error(TypeError)
+ -> { @io.send :initialize, nil, 'w' }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { @io.send :initialize, "4", 'w' }.should raise_error(TypeError)
+ -> { @io.send :initialize, "4", 'w' }.should.raise(TypeError)
end
it "raises IOError on closed stream" do
- -> { @io.send :initialize, IOSpecs.closed_io.fileno }.should raise_error(IOError)
+ -> { @io.send :initialize, IOSpecs.closed_io.fileno }.should.raise(IOError)
end
it "raises an Errno::EBADF when given an invalid file descriptor" do
- -> { @io.send :initialize, -1, 'w' }.should raise_error(Errno::EBADF)
+ -> { @io.send :initialize, -1, 'w' }.should.raise(Errno::EBADF)
end
end
diff --git a/spec/ruby/core/io/inspect_spec.rb b/spec/ruby/core/io/inspect_spec.rb
index c653c307c4..37dc459f22 100644
--- a/spec/ruby/core/io/inspect_spec.rb
+++ b/spec/ruby/core/io/inspect_spec.rb
@@ -8,13 +8,13 @@ describe "IO#inspect" do
it "contains the file descriptor number" do
@r, @w = IO.pipe
- @r.inspect.should include("fd #{@r.fileno}")
+ @r.inspect.should.include?("fd #{@r.fileno}")
end
it "contains \"(closed)\" if the stream is closed" do
@r, @w = IO.pipe
@r.close
- @r.inspect.should include("(closed)")
+ @r.inspect.should.include?("(closed)")
end
it "reports IO as its Method object's owner" do
diff --git a/spec/ruby/core/io/internal_encoding_spec.rb b/spec/ruby/core/io/internal_encoding_spec.rb
index 7a583d4bcb..9963a93f33 100644
--- a/spec/ruby/core/io/internal_encoding_spec.rb
+++ b/spec/ruby/core/io/internal_encoding_spec.rb
@@ -9,25 +9,25 @@ describe :io_internal_encoding, shared: true do
it "returns nil if the internal encoding is not set" do
@io = new_io @name, @object
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns nil if Encoding.default_internal is changed after the instance is created" do
@io = new_io @name, @object
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns the value set when the instance was created" do
@io = new_io @name, "#{@object}:utf-8:euc-jp"
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should equal(Encoding::EUC_JP)
+ @io.internal_encoding.should.equal?(Encoding::EUC_JP)
end
it "returns the value set by #set_encoding" do
@io = new_io @name, @object
@io.set_encoding(Encoding::US_ASCII, Encoding::IBM437)
- @io.internal_encoding.should equal(Encoding::IBM437)
+ @io.internal_encoding.should.equal?(Encoding::IBM437)
end
end
@@ -39,13 +39,13 @@ describe :io_internal_encoding, shared: true do
it "returns nil" do
@io = new_io @name, @object
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns nil regardless of Encoding.default_internal changes" do
@io = new_io @name, @object
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
end
@@ -57,41 +57,41 @@ describe :io_internal_encoding, shared: true do
it "returns the value of Encoding.default_internal when the instance was created if the internal encoding is not set" do
@io = new_io @name, @object
- @io.internal_encoding.should equal(Encoding::IBM866)
+ @io.internal_encoding.should.equal?(Encoding::IBM866)
end
it "does not change when Encoding.default_internal is changed" do
@io = new_io @name, @object
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should equal(Encoding::IBM866)
+ @io.internal_encoding.should.equal?(Encoding::IBM866)
end
it "returns the internal encoding set when the instance was created" do
@io = new_io @name, "#{@object}:utf-8:euc-jp"
- @io.internal_encoding.should equal(Encoding::EUC_JP)
+ @io.internal_encoding.should.equal?(Encoding::EUC_JP)
end
it "does not change when set and Encoding.default_internal is changed" do
@io = new_io @name, "#{@object}:utf-8:euc-jp"
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should equal(Encoding::EUC_JP)
+ @io.internal_encoding.should.equal?(Encoding::EUC_JP)
end
it "returns the value set by #set_encoding" do
@io = new_io @name, @object
@io.set_encoding(Encoding::US_ASCII, Encoding::IBM437)
- @io.internal_encoding.should equal(Encoding::IBM437)
+ @io.internal_encoding.should.equal?(Encoding::IBM437)
end
it "returns nil when Encoding.default_external is BINARY and the internal encoding is not set" do
Encoding.default_external = Encoding::BINARY
@io = new_io @name, @object
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "returns nil when the external encoding is BINARY and the internal encoding is not set" do
@io = new_io @name, "#{@object}:binary"
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
end
end
@@ -116,7 +116,7 @@ describe "IO#internal_encoding" do
it "can be retrieved from a closed stream" do
io = IOSpecs.io_fixture("lines.txt", "r")
io.close
- io.internal_encoding.should equal(Encoding.default_internal)
+ io.internal_encoding.should.equal?(Encoding.default_internal)
end
describe "with 'r' mode" do
diff --git a/spec/ruby/core/io/ioctl_spec.rb b/spec/ruby/core/io/ioctl_spec.rb
index 3f7b5ad5d7..15a5d6ec22 100644
--- a/spec/ruby/core/io/ioctl_spec.rb
+++ b/spec/ruby/core/io/ioctl_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "IO#ioctl" do
platform_is_not :windows do
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.ioctl(5, 5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.ioctl(5, 5) }.should.raise(IOError)
end
end
@@ -15,7 +15,7 @@ describe "IO#ioctl" do
buffer = +''
# FIONREAD in /usr/include/asm-generic/ioctls.h
f.ioctl 0x541B, buffer
- buffer.unpack('I').first.should be_kind_of(Integer)
+ buffer.unpack('I').first.should.is_a?(Integer)
end
end
end
@@ -25,7 +25,7 @@ describe "IO#ioctl" do
-> {
# TIOCGWINSZ in /usr/include/asm-generic/ioctls.h
f.ioctl 0x5413, nil
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
end
end
diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb
index e82cdd9f17..93b505652a 100644
--- a/spec/ruby/core/io/lineno_spec.rb
+++ b/spec/ruby/core/io/lineno_spec.rb
@@ -11,14 +11,14 @@ describe "IO#lineno" do
end
it "raises an IOError on a closed stream" do
- -> { IOSpecs.closed_io.lineno }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.lineno }.should.raise(IOError)
end
it "raises an IOError on a write-only stream" do
name = tmp("io_lineno.txt")
begin
File.open(name, 'w') do |f|
- -> { f.lineno }.should raise_error(IOError)
+ -> { f.lineno }.should.raise(IOError)
end
ensure
rm_r name
@@ -29,7 +29,7 @@ describe "IO#lineno" do
cmd = platform_is(:windows) ? 'rem' : 'cat'
IO.popen(cmd, 'r+') do |p|
p.close_read
- -> { p.lineno }.should raise_error(IOError)
+ -> { p.lineno }.should.raise(IOError)
end
end
@@ -56,14 +56,14 @@ describe "IO#lineno=" do
end
it "raises an IOError on a closed stream" do
- -> { IOSpecs.closed_io.lineno = 5 }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.lineno = 5 }.should.raise(IOError)
end
it "raises an IOError on a write-only stream" do
name = tmp("io_lineno.txt")
begin
File.open(name, 'w') do |f|
- -> { f.lineno = 0 }.should raise_error(IOError)
+ -> { f.lineno = 0 }.should.raise(IOError)
end
ensure
rm_r name
@@ -74,7 +74,7 @@ describe "IO#lineno=" do
cmd = platform_is(:windows) ? 'rem' : 'cat'
IO.popen(cmd, 'r+') do |p|
p.close_read
- -> { p.lineno = 0 }.should raise_error(IOError)
+ -> { p.lineno = 0 }.should.raise(IOError)
end
end
@@ -95,12 +95,12 @@ describe "IO#lineno=" do
end
it "raises TypeError if cannot convert argument to Integer implicitly" do
- -> { @io.lineno = "1" }.should raise_error(TypeError, 'no implicit conversion of String into Integer')
- -> { @io.lineno = nil }.should raise_error(TypeError, 'no implicit conversion from nil to integer')
+ -> { @io.lineno = "1" }.should.raise(TypeError, 'no implicit conversion of String into Integer')
+ -> { @io.lineno = nil }.should raise_consistent_error(TypeError, 'no implicit conversion of nil into Integer')
end
it "does not accept Integers that don't fit in a C int" do
- -> { @io.lineno = 2**32 }.should raise_error(RangeError)
+ -> { @io.lineno = 2**32 }.should.raise(RangeError)
end
it "sets the current line number to the given value" do
diff --git a/spec/ruby/core/io/open_spec.rb b/spec/ruby/core/io/open_spec.rb
index d151da9ce5..ff22d14685 100644
--- a/spec/ruby/core/io/open_spec.rb
+++ b/spec/ruby/core/io/open_spec.rb
@@ -32,7 +32,7 @@ describe "IO.open" do
super()
ScratchPad.record :called
end
- io.closed?.should be_false
+ io.closed?.should == false
end
ScratchPad.recorded.should == :called
end
@@ -46,7 +46,7 @@ describe "IO.open" do
end
raise Exception
end
- end.should raise_error(Exception)
+ end.should.raise(Exception)
ScratchPad.recorded.should == :called
end
@@ -59,7 +59,7 @@ describe "IO.open" do
raise Exception
end
end
- end.should raise_error(Exception)
+ end.should.raise(Exception)
ScratchPad.recorded.should == :called
end
@@ -72,7 +72,7 @@ describe "IO.open" do
raise StandardError
end
end
- end.should raise_error(StandardError)
+ end.should.raise(StandardError)
ScratchPad.recorded.should == :called
end
diff --git a/spec/ruby/core/io/output_spec.rb b/spec/ruby/core/io/output_spec.rb
index 2aafb305f4..0decf8c95b 100644
--- a/spec/ruby/core/io/output_spec.rb
+++ b/spec/ruby/core/io/output_spec.rb
@@ -16,7 +16,7 @@ describe "IO#<<" do
it "raises an error if the stream is closed" do
io = IOSpecs.closed_io
- -> { io << "test" }.should raise_error(IOError)
+ -> { io << "test" }.should.raise(IOError)
end
it "returns self" do
diff --git a/spec/ruby/core/io/path_spec.rb b/spec/ruby/core/io/path_spec.rb
index 8145c32f39..798adb2163 100644
--- a/spec/ruby/core/io/path_spec.rb
+++ b/spec/ruby/core/io/path_spec.rb
@@ -1,14 +1,12 @@
require_relative '../../spec_helper'
describe "IO#path" do
- ruby_version_is "3.2" do
- it "returns the path of the file associated with the IO object" do
- path = tmp("io_path.txt")
- File.open(path, "w") do |file|
- IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path
- end
- ensure
- File.unlink(path)
+ it "returns the path of the file associated with the IO object" do
+ path = tmp("io_path.txt")
+ File.open(path, "w") do |file|
+ IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path
end
+ ensure
+ File.unlink(path)
end
end
diff --git a/spec/ruby/core/io/pid_spec.rb b/spec/ruby/core/io/pid_spec.rb
index bc09fe7c3b..04956887ff 100644
--- a/spec/ruby/core/io/pid_spec.rb
+++ b/spec/ruby/core/io/pid_spec.rb
@@ -25,11 +25,11 @@ describe "IO#pid" do
end
it "returns the ID of a process associated with stream" do
- @io.pid.should_not be_nil
+ @io.pid.should_not == nil
end
it "raises an IOError on closed stream" do
@io.close
- -> { @io.pid }.should raise_error(IOError)
+ -> { @io.pid }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/pipe_spec.rb b/spec/ruby/core/io/pipe_spec.rb
index aee0d9003f..9f1b01a5cd 100644
--- a/spec/ruby/core/io/pipe_spec.rb
+++ b/spec/ruby/core/io/pipe_spec.rb
@@ -16,14 +16,14 @@ describe "IO.pipe" do
it "returns two IO objects" do
@r, @w = IO.pipe
- @r.should be_kind_of(IO)
- @w.should be_kind_of(IO)
+ @r.should.is_a?(IO)
+ @w.should.is_a?(IO)
end
it "returns instances of a subclass when called on a subclass" do
@r, @w = IOSpecs::SubIO.pipe
- @r.should be_an_instance_of(IOSpecs::SubIO)
- @w.should be_an_instance_of(IOSpecs::SubIO)
+ @r.should.instance_of?(IOSpecs::SubIO)
+ @w.should.instance_of?(IOSpecs::SubIO)
end
it "does not use IO.new method to create pipes and allows its overriding" do
@@ -33,8 +33,8 @@ describe "IO.pipe" do
@r, @w = IOSpecs::SubIOWithRedefinedNew.pipe
ScratchPad.recorded.should == [:call_original_initialize, :call_original_initialize] # called 2 times - for each pipe (r and w)
- @r.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
- @w.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
+ @r.should.instance_of?(IOSpecs::SubIOWithRedefinedNew)
+ @w.should.instance_of?(IOSpecs::SubIOWithRedefinedNew)
end
end
@@ -42,8 +42,8 @@ describe "IO.pipe" do
describe "passed a block" do
it "yields two IO objects" do
IO.pipe do |r, w|
- r.should be_kind_of(IO)
- w.should be_kind_of(IO)
+ r.should.is_a?(IO)
+ w.should.is_a?(IO)
end
end
@@ -67,7 +67,7 @@ describe "IO.pipe" do
w = _w
raise RuntimeError
end
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
r.should.closed?
w.should.closed?
end
@@ -100,7 +100,7 @@ describe "IO.pipe" do
IO.pipe do |r, w|
r.external_encoding.should == Encoding::ISO_8859_1
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
@@ -120,14 +120,14 @@ describe "IO.pipe" do
IO.pipe do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
it "sets the external encoding of the read end when passed an Encoding argument" do
IO.pipe(Encoding::UTF_8) do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
@@ -141,14 +141,14 @@ describe "IO.pipe" do
it "sets the external encoding of the read end when passed the name of an Encoding" do
IO.pipe("UTF-8") do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
it "accepts 'bom|' prefix for external encoding" do
IO.pipe("BOM|UTF-8") do |r, w|
r.external_encoding.should == Encoding::UTF_8
- r.internal_encoding.should be_nil
+ r.internal_encoding.should == nil
end
end
@@ -213,13 +213,13 @@ describe "IO.pipe" do
it "sets no external encoding for the write end" do
IO.pipe(Encoding::UTF_8) do |r, w|
- w.external_encoding.should be_nil
+ w.external_encoding.should == nil
end
end
it "sets no internal encoding for the write end" do
IO.pipe(Encoding::UTF_8) do |r, w|
- w.external_encoding.should be_nil
+ w.external_encoding.should == nil
end
end
end
diff --git a/spec/ruby/core/io/popen_spec.rb b/spec/ruby/core/io/popen_spec.rb
index e9d32c5c7d..b5747bf255 100644
--- a/spec/ruby/core/io/popen_spec.rb
+++ b/spec/ruby/core/io/popen_spec.rb
@@ -21,7 +21,7 @@ describe "IO.popen" do
it "returns an open IO" do
@io = IO.popen(ruby_cmd('exit'), "r")
- @io.closed?.should be_false
+ @io.closed?.should == false
end
it "reads a read-only pipe" do
@@ -31,7 +31,7 @@ describe "IO.popen" do
it "raises IOError when writing a read-only pipe" do
@io = IO.popen('echo foo', "r")
- -> { @io.write('bar') }.should raise_error(IOError)
+ -> { @io.write('bar') }.should.raise(IOError)
@io.read.should == "foo\n"
end
@@ -52,7 +52,7 @@ describe "IO.popen" do
it "raises IOError when reading a write-only pipe" do
@io = IO.popen(ruby_cmd('IO.copy_stream(STDIN,STDOUT)'), "w")
- -> { @io.read }.should raise_error(IOError)
+ -> { @io.read }.should.raise(IOError)
end
it "reads and writes a read/write pipe" do
@@ -86,7 +86,7 @@ describe "IO.popen" do
it "returns an instance of a subclass when called on a subclass" do
@io = IOSpecs::SubIO.popen(ruby_cmd('exit'), "r")
- @io.should be_an_instance_of(IOSpecs::SubIO)
+ @io.should.instance_of?(IOSpecs::SubIO)
end
it "coerces mode argument with #to_str" do
@@ -95,27 +95,43 @@ describe "IO.popen" do
@io = IO.popen(ruby_cmd('exit 0'), mode)
end
+ it "accepts a path using the chdir: keyword argument" do
+ path = File.dirname(@fname)
+
+ @io = IO.popen(ruby_cmd("puts Dir.pwd"), "r", chdir: path)
+ @io.read.chomp.should == path
+ end
+
+ it "accepts a path using the chdir: keyword argument and a coercible path" do
+ path = File.dirname(@fname)
+ object = mock("path")
+ object.should_receive(:to_path).and_return(path)
+
+ @io = IO.popen(ruby_cmd("puts Dir.pwd"), "r", chdir: object)
+ @io.read.chomp.should == path
+ end
+
describe "with a block" do
it "yields an open IO to the block" do
IO.popen(ruby_cmd('exit'), "r") do |io|
- io.closed?.should be_false
+ io.closed?.should == false
end
end
it "yields an instance of a subclass when called on a subclass" do
IOSpecs::SubIO.popen(ruby_cmd('exit'), "r") do |io|
- io.should be_an_instance_of(IOSpecs::SubIO)
+ io.should.instance_of?(IOSpecs::SubIO)
end
end
it "closes the IO after yielding" do
io = IO.popen(ruby_cmd('exit'), "r") { |_io| _io }
- io.closed?.should be_true
+ io.closed?.should == true
end
it "allows the IO to be closed inside the block" do
io = IO.popen(ruby_cmd('exit'), 'r') { |_io| _io.close; _io }
- io.closed?.should be_true
+ io.closed?.should == true
end
it "returns the value of the block" do
@@ -153,7 +169,7 @@ describe "IO.popen" do
it "sets the internal encoding to nil if it's the same as the external encoding" do
@io = IO.popen(ruby_cmd('exit'), external_encoding: Encoding::EUC_JP,
internal_encoding: Encoding::EUC_JP)
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
context "with a leading ENV Hash" do
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index dc7bcedf3e..cfb8dc4c68 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -1,140 +1,138 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
- describe "IO#pread" do
- before :each do
- @fname = tmp("io_pread.txt")
- @contents = "1234567890"
- touch(@fname) { |f| f.write @contents }
- @file = File.open(@fname, "r+")
- end
+describe "IO#pread" do
+ before :each do
+ @fname = tmp("io_pread.txt")
+ @contents = "1234567890"
+ touch(@fname) { |f| f.write @contents }
+ @file = File.open(@fname, "r+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "accepts a length, and an offset" do
- @file.pread(4, 0).should == "1234"
- @file.pread(3, 4).should == "567"
- end
+ it "accepts a length, and an offset" do
+ @file.pread(4, 0).should == "1234"
+ @file.pread(3, 4).should == "567"
+ end
- it "accepts a length, an offset, and an output buffer" do
- buffer = +"foo"
- @file.pread(3, 4, buffer).should.equal?(buffer)
- buffer.should == "567"
- end
+ it "accepts a length, an offset, and an output buffer" do
+ buffer = +"foo"
+ @file.pread(3, 4, buffer).should.equal?(buffer)
+ buffer.should == "567"
+ end
- it "shrinks the buffer in case of less bytes read" do
- buffer = +"foo"
- @file.pread(1, 0, buffer)
- buffer.should == "1"
- end
+ it "shrinks the buffer in case of less bytes read" do
+ buffer = +"foo"
+ @file.pread(1, 0, buffer)
+ buffer.should == "1"
+ end
- it "grows the buffer in case of more bytes read" do
- buffer = +"foo"
- @file.pread(5, 0, buffer)
- buffer.should == "12345"
- end
+ it "grows the buffer in case of more bytes read" do
+ buffer = +"foo"
+ @file.pread(5, 0, buffer)
+ buffer.should == "12345"
+ end
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @file.pread(10, 0, buffer)
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @file.pread(10, 0, buffer)
- buffer.encoding.should == Encoding::ISO_8859_1
- end
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
- it "does not advance the file pointer" do
- @file.pread(4, 0).should == "1234"
- @file.read.should == "1234567890"
- end
+ it "does not advance the file pointer" do
+ @file.pread(4, 0).should == "1234"
+ @file.read.should == "1234567890"
+ end
- it "ignores the current offset" do
- @file.pos = 3
- @file.pread(4, 0).should == "1234"
- end
+ it "ignores the current offset" do
+ @file.pos = 3
+ @file.pread(4, 0).should == "1234"
+ end
- it "returns an empty string for maxlen = 0" do
- @file.pread(0, 4).should == ""
- end
+ it "returns an empty string for maxlen = 0" do
+ @file.pread(0, 4).should == ""
+ end
- it "returns a buffer for maxlen = 0 when buffer specified" do
- buffer = +"foo"
- @file.pread(0, 4, buffer).should.equal?(buffer)
- buffer.should == "foo"
- end
+ it "returns a buffer for maxlen = 0 when buffer specified" do
+ buffer = +"foo"
+ @file.pread(0, 4, buffer).should.equal?(buffer)
+ buffer.should == "foo"
+ end
- it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
- @file.pread(0, 400).should == ""
- end
+ it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
+ @file.pread(0, 400).should == ""
+ end
- it "does not reset the buffer when reading with maxlen = 0" do
- buffer = +"foo"
- @file.pread(0, 4, buffer)
- buffer.should == "foo"
+ it "does not reset the buffer when reading with maxlen = 0" do
+ buffer = +"foo"
+ @file.pread(0, 4, buffer)
+ buffer.should == "foo"
- @file.pread(0, 400, buffer)
- buffer.should == "foo"
- end
+ @file.pread(0, 400, buffer)
+ buffer.should == "foo"
+ end
- it "converts maxlen to Integer using #to_int" do
- maxlen = mock('maxlen')
- maxlen.should_receive(:to_int).and_return(4)
- @file.pread(maxlen, 0).should == "1234"
- end
+ it "converts maxlen to Integer using #to_int" do
+ maxlen = mock('maxlen')
+ maxlen.should_receive(:to_int).and_return(4)
+ @file.pread(maxlen, 0).should == "1234"
+ end
- it "converts offset to Integer using #to_int" do
- offset = mock('offset')
- offset.should_receive(:to_int).and_return(0)
- @file.pread(4, offset).should == "1234"
- end
+ it "converts offset to Integer using #to_int" do
+ offset = mock('offset')
+ offset.should_receive(:to_int).and_return(0)
+ @file.pread(4, offset).should == "1234"
+ end
- it "converts a buffer to String using to_str" do
- buffer = mock('buffer')
- buffer.should_receive(:to_str).at_least(1).and_return(+"foo")
- @file.pread(4, 0, buffer)
- buffer.should_not.is_a?(String)
- buffer.to_str.should == "1234"
- end
+ it "converts a buffer to String using to_str" do
+ buffer = mock('buffer')
+ buffer.should_receive(:to_str).at_least(1).and_return(+"foo")
+ @file.pread(4, 0, buffer)
+ buffer.should_not.is_a?(String)
+ buffer.to_str.should == "1234"
+ end
- it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do
- maxlen = Object.new
- -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
- end
+ it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do
+ maxlen = Object.new
+ -> { @file.pread(maxlen, 0) }.should.raise(TypeError, 'no implicit conversion of Object into Integer')
+ end
- it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do
- offset = Object.new
- -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
- end
+ it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do
+ offset = Object.new
+ -> { @file.pread(4, offset) }.should.raise(TypeError, 'no implicit conversion of Object into Integer')
+ end
- it "raises ArgumentError for negative values of maxlen" do
- -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)')
- end
+ it "raises ArgumentError for negative values of maxlen" do
+ -> { @file.pread(-4, 0) }.should.raise(ArgumentError, 'negative string size (or size too big)')
+ end
- it "raised Errno::EINVAL for negative values of offset" do
- -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/)
- end
+ it "raised Errno::EINVAL for negative values of offset" do
+ -> { @file.pread(4, -1) }.should.raise(Errno::EINVAL, /Invalid argument/)
+ end
- it "raises TypeError if the buffer is not a String and cannot be coerced into String" do
- buffer = Object.new
- -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
+ it "raises TypeError if the buffer is not a String and cannot be coerced into String" do
+ buffer = Object.new
+ -> { @file.pread(4, 0, buffer) }.should.raise(TypeError, 'no implicit conversion of Object into String')
+ end
- it "raises EOFError if end-of-file is reached" do
- -> { @file.pread(1, 10) }.should raise_error(EOFError)
- end
+ it "raises EOFError if end-of-file is reached" do
+ -> { @file.pread(1, 10) }.should.raise(EOFError)
+ end
- it "raises IOError when file is not open in read mode" do
- File.open(@fname, "w") do |file|
- -> { file.pread(1, 1) }.should raise_error(IOError)
- end
+ it "raises IOError when file is not open in read mode" do
+ File.open(@fname, "w") do |file|
+ -> { file.pread(1, 1) }.should.raise(IOError)
end
+ end
- it "raises IOError when file is closed" do
- file = File.open(@fname, "r+")
- file.close
- -> { file.pread(1, 1) }.should raise_error(IOError)
- end
+ it "raises IOError when file is closed" do
+ file = File.open(@fname, "r+")
+ file.close
+ -> { file.pread(1, 1) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/print_spec.rb b/spec/ruby/core/io/print_spec.rb
index 085852024c..065cb3b8cb 100644
--- a/spec/ruby/core/io/print_spec.rb
+++ b/spec/ruby/core/io/print_spec.rb
@@ -21,7 +21,7 @@ describe "IO#print" do
end
it "returns nil" do
- touch(@name) { |f| f.print.should be_nil }
+ touch(@name) { |f| f.print.should == nil }
end
it "writes $_.to_s followed by $\\ (if any) to the stream if no arguments given" do
@@ -61,6 +61,6 @@ describe "IO#print" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.print("stuff") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.print("stuff") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/printf_spec.rb b/spec/ruby/core/io/printf_spec.rb
index baa00f14ce..d5519bdaa3 100644
--- a/spec/ruby/core/io/printf_spec.rb
+++ b/spec/ruby/core/io/printf_spec.rb
@@ -27,6 +27,6 @@ describe "IO#printf" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.printf("stuff") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.printf("stuff") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/puts_spec.rb b/spec/ruby/core/io/puts_spec.rb
index a186ddaa5d..df526ea56a 100644
--- a/spec/ruby/core/io/puts_spec.rb
+++ b/spec/ruby/core/io/puts_spec.rb
@@ -111,7 +111,7 @@ describe "IO#puts" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.puts("stuff") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.puts("stuff") }.should.raise(IOError)
end
it "writes crlf when IO is opened with newline: :crlf" do
diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb
index 2bc508b37d..c318d551bc 100644
--- a/spec/ruby/core/io/pwrite_spec.rb
+++ b/spec/ruby/core/io/pwrite_spec.rb
@@ -1,69 +1,67 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
- describe "IO#pwrite" do
- before :each do
- @fname = tmp("io_pwrite.txt")
- @file = File.open(@fname, "w+")
- end
+describe "IO#pwrite" do
+ before :each do
+ @fname = tmp("io_pwrite.txt")
+ @file = File.open(@fname, "w+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "returns the number of bytes written" do
- @file.pwrite("foo", 0).should == 3
- end
+ it "returns the number of bytes written" do
+ @file.pwrite("foo", 0).should == 3
+ end
- it "accepts a string and an offset" do
- @file.pwrite("foo", 2)
- @file.pread(3, 2).should == "foo"
- end
+ it "accepts a string and an offset" do
+ @file.pwrite("foo", 2)
+ @file.pread(3, 2).should == "foo"
+ end
- it "does not advance the pointer in the file" do
- @file.pwrite("bar", 3)
- @file.write("foo")
- @file.pread(6, 0).should == "foobar"
- end
+ it "does not advance the pointer in the file" do
+ @file.pwrite("bar", 3)
+ @file.write("foo")
+ @file.pread(6, 0).should == "foobar"
+ end
- it "calls #to_s on the object to be written" do
- object = mock("to_s")
- object.should_receive(:to_s).and_return("foo")
- @file.pwrite(object, 0)
- @file.pread(3, 0).should == "foo"
- end
+ it "calls #to_s on the object to be written" do
+ object = mock("to_s")
+ object.should_receive(:to_s).and_return("foo")
+ @file.pwrite(object, 0)
+ @file.pread(3, 0).should == "foo"
+ end
- it "calls #to_int on the offset" do
- offset = mock("to_int")
- offset.should_receive(:to_int).and_return(2)
- @file.pwrite("foo", offset)
- @file.pread(3, 2).should == "foo"
- end
+ it "calls #to_int on the offset" do
+ offset = mock("to_int")
+ offset.should_receive(:to_int).and_return(2)
+ @file.pwrite("foo", offset)
+ @file.pread(3, 2).should == "foo"
+ end
- it "raises IOError when file is not open in write mode" do
- File.open(@fname, "r") do |file|
- -> { file.pwrite("foo", 1) }.should raise_error(IOError, "not opened for writing")
- end
+ it "raises IOError when file is not open in write mode" do
+ File.open(@fname, "r") do |file|
+ -> { file.pwrite("foo", 1) }.should.raise(IOError, "not opened for writing")
end
+ end
- it "raises IOError when file is closed" do
- file = File.open(@fname, "w+")
- file.close
- -> { file.pwrite("foo", 1) }.should raise_error(IOError, "closed stream")
- end
+ it "raises IOError when file is closed" do
+ file = File.open(@fname, "w+")
+ file.close
+ -> { file.pwrite("foo", 1) }.should.raise(IOError, "closed stream")
+ end
- it "raises a NoMethodError if object does not respond to #to_s" do
- -> {
- @file.pwrite(BasicObject.new, 0)
- }.should raise_error(NoMethodError, /undefined method [`']to_s'/)
- end
+ it "raises a NoMethodError if object does not respond to #to_s" do
+ -> {
+ @file.pwrite(BasicObject.new, 0)
+ }.should.raise(NoMethodError, /undefined method [`']to_s'/)
+ end
- it "raises a TypeError if the offset cannot be converted to an Integer" do
- -> {
- @file.pwrite("foo", Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
+ it "raises a TypeError if the offset cannot be converted to an Integer" do
+ -> {
+ @file.pwrite("foo", Object.new)
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
end
diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb
index 51e7cd6bd2..511cf03263 100644
--- a/spec/ruby/core/io/read_nonblock_spec.rb
+++ b/spec/ruby/core/io/read_nonblock_spec.rb
@@ -12,12 +12,12 @@ describe "IO#read_nonblock" do
end
it "raises an exception extending IO::WaitReadable when there is no data" do
- -> { @read.read_nonblock(5) }.should raise_error(IO::WaitReadable) { |e|
+ -> { @read.read_nonblock(5) }.should.raise(IO::WaitReadable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
@@ -36,7 +36,7 @@ describe "IO#read_nonblock" do
@read.read_nonblock(5)
- @read.read_nonblock(5, exception: false).should be_nil
+ @read.read_nonblock(5, exception: false).should == nil
end
end
end
@@ -73,7 +73,7 @@ describe "IO#read_nonblock" do
)
c = @read.getc
@read.ungetc(c)
- -> { @read.read_nonblock(3).should == "foo" }.should raise_error(IOError)
+ -> { @read.read_nonblock(3).should == "foo" }.should.raise(IOError)
end
it "returns less data if that is all that is available" do
@@ -92,7 +92,7 @@ describe "IO#read_nonblock" do
end
it "raises ArgumentError when length is less than 0" do
- -> { @read.read_nonblock(-1) }.should raise_error(ArgumentError)
+ -> { @read.read_nonblock(-1) }.should.raise(ArgumentError)
end
it "reads into the passed buffer" do
@@ -106,7 +106,7 @@ describe "IO#read_nonblock" do
buffer = +""
@write.write("1")
output = @read.read_nonblock(1, buffer)
- output.should equal(buffer)
+ output.should.equal?(buffer)
end
it "discards the existing buffer content upon successful read" do
@@ -120,12 +120,12 @@ describe "IO#read_nonblock" do
it "discards the existing buffer content upon error" do
buffer = +"existing content"
@write.close
- -> { @read.read_nonblock(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @read.read_nonblock(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.read_nonblock(5) }.should.raise(IOError)
end
it "raises EOFError when the end is reached" do
@@ -134,7 +134,7 @@ describe "IO#read_nonblock" do
@read.read_nonblock(5)
- -> { @read.read_nonblock(5) }.should raise_error(EOFError)
+ -> { @read.read_nonblock(5) }.should.raise(EOFError)
end
it "preserves the encoding of the given buffer" do
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 567daa55df..dd787c9b60 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -29,7 +29,7 @@ describe "IO.read" do
-> {
IO.read(@fname, 3, 0, {mode: "r+"})
- }.should raise_error(ArgumentError, /wrong number of arguments/)
+ }.should.raise(ArgumentError, /wrong number of arguments/)
end
it "accepts an empty options Hash" do
@@ -45,11 +45,11 @@ describe "IO.read" do
end
it "raises an IOError if the options Hash specifies write mode" do
- -> { IO.read(@fname, 3, 0, mode: "w") }.should raise_error(IOError)
+ -> { IO.read(@fname, 3, 0, mode: "w") }.should.raise(IOError)
end
it "raises an IOError if the options Hash specifies append only mode" do
- -> { IO.read(@fname, mode: "a") }.should raise_error(IOError)
+ -> { IO.read(@fname, mode: "a") }.should.raise(IOError)
end
it "reads the file if the options Hash includes read mode" do
@@ -65,15 +65,6 @@ describe "IO.read" do
end
platform_is_not :windows do
- ruby_version_is ""..."3.3" do
- it "uses an :open_args option" do
- string = IO.read(@fname, nil, 0, open_args: ["r", nil, {encoding: Encoding::US_ASCII}])
- string.encoding.should == Encoding::US_ASCII
-
- string = IO.read(@fname, nil, 0, open_args: ["r", nil, {}])
- string.encoding.should == Encoding::UTF_8
- end
- end
end
it "disregards other options if :open_args is given" do
@@ -124,29 +115,20 @@ describe "IO.read" do
it "raises an Errno::ENOENT when the requested file does not exist" do
rm_r @fname
- -> { IO.read @fname }.should raise_error(Errno::ENOENT)
+ -> { IO.read @fname }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when not passed a String type" do
- -> { IO.read nil }.should raise_error(TypeError)
+ -> { IO.read nil }.should.raise(TypeError)
end
it "raises an ArgumentError when not passed a valid length" do
- -> { IO.read @fname, -1 }.should raise_error(ArgumentError)
- end
-
- ruby_version_is ''...'3.3' do
- it "raises an Errno::EINVAL when not passed a valid offset" do
- -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL)
- -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL)
- end
+ -> { IO.read @fname, -1 }.should.raise(ArgumentError)
end
- ruby_version_is '3.3' do
- it "raises an ArgumentError when not passed a valid offset" do
- -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError)
- -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when not passed a valid offset" do
+ -> { IO.read @fname, 0, -1 }.should.raise(ArgumentError)
+ -> { IO.read @fname, -1, -1 }.should.raise(ArgumentError)
end
it "uses the external encoding specified via the :external_encoding option" do
@@ -168,72 +150,72 @@ describe "IO.read" do
end
end
-describe "IO.read from a pipe" do
- it "runs the rest as a subprocess and returns the standard output" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
- end
-
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd).should == "hello\n"
- end
- end
-
- platform_is_not :windows do
- it "opens a pipe to a fork if the rest is -" do
- str = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- str = IO.read("|-")
+ruby_version_is ""..."4.0" do
+ describe "IO.read from a pipe" do
+ it "runs the rest as a subprocess and returns the standard output" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
end
- if str # parent
- str.should == "hello from child\n"
- else #child
- puts "hello from child"
- exit!
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd).should == "hello\n"
end
end
- end
- it "reads only the specified number of bytes requested" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
- end
+ platform_is_not :windows do
+ it "opens a pipe to a fork if the rest is -" do
+ str = nil
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ str = IO.read("|-")
+ end
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd, 1).should == "h"
+ if str # parent
+ str.should == "hello from child\n"
+ else #child
+ puts "hello from child"
+ exit!
+ end
+ end
end
- end
- platform_is_not :windows do
- it "raises Errno::ESPIPE if passed an offset" do
- -> {
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|sh -c 'echo hello'", 1, 1)
- end
- }.should raise_error(Errno::ESPIPE)
+ it "reads only the specified number of bytes requested" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
+ end
+
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd, 1).should == "h"
+ end
end
- end
- quarantine! do # The process tried to write to a nonexistent pipe.
- platform_is :windows do
- # TODO: It should raise Errno::ESPIPE on Windows as well
- # once https://bugs.ruby-lang.org/issues/12230 is fixed.
- it "raises Errno::EINVAL if passed an offset" do
+ platform_is_not :windows do
+ it "raises Errno::ESPIPE if passed an offset" do
-> {
suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|cmd.exe /C echo hello", 1, 1)
+ IO.read("|sh -c 'echo hello'", 1, 1)
end
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::ESPIPE)
+ end
+ end
+
+ quarantine! do # The process tried to write to a nonexistent pipe.
+ platform_is :windows do
+ # TODO: It should raise Errno::ESPIPE on Windows as well
+ # once https://bugs.ruby-lang.org/issues/12230 is fixed.
+ it "raises Errno::EINVAL if passed an offset" do
+ -> {
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read("|cmd.exe /C echo hello", 1, 1)
+ end
+ }.should.raise(Errno::EINVAL)
+ end
end
end
- end
- ruby_version_is "3.3" do
# https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
+ it "warns about deprecation" do
cmd = "|echo ok"
-> {
IO.read(cmd)
@@ -288,7 +270,7 @@ describe "IO#read" do
end
it "raises an ArgumentError when not passed a valid length" do
- -> { @io.read(-1) }.should raise_error(ArgumentError)
+ -> { @io.read(-1) }.should.raise(ArgumentError)
end
it "clears the output buffer if there is nothing to read" do
@@ -315,16 +297,14 @@ describe "IO#read" do
it "raise FrozenError if the output buffer is frozen" do
@io.read
- -> { @io.read(0, 'frozen-string'.freeze) }.should raise_error(FrozenError)
- -> { @io.read(1, 'frozen-string'.freeze) }.should raise_error(FrozenError)
- -> { @io.read(nil, 'frozen-string'.freeze) }.should raise_error(FrozenError)
+ -> { @io.read(0, 'frozen-string'.freeze) }.should.raise(FrozenError)
+ -> { @io.read(1, 'frozen-string'.freeze) }.should.raise(FrozenError)
+ -> { @io.read(nil, 'frozen-string'.freeze) }.should.raise(FrozenError)
end
- ruby_bug "", ""..."3.3" do
- it "raise FrozenError if the output buffer is frozen (2)" do
- @io.read
- -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError)
- end
+ it "raise FrozenError if the output buffer is frozen (2)" do
+ @io.read
+ -> { @io.read(1, ''.freeze) }.should.raise(FrozenError)
end
it "consumes zero bytes when reading zero bytes" do
@@ -394,14 +374,14 @@ describe "IO#read" do
it "returns the given buffer" do
buf = +""
- @io.read(nil, buf).should equal buf
+ @io.read(nil, buf).should.equal? buf
end
it "returns the given buffer when there is nothing to read" do
buf = +""
@io.read
- @io.read(nil, buf).should equal buf
+ @io.read(nil, buf).should.equal? buf
end
it "coerces the second argument to string and uses it as a buffer" do
@@ -409,7 +389,7 @@ describe "IO#read" do
obj = mock("buff")
obj.should_receive(:to_str).any_number_of_times.and_return(buf)
- @io.read(15, obj).should_not equal obj
+ @io.read(15, obj).should_not.equal? obj
buf.should == @contents
end
@@ -443,11 +423,11 @@ describe "IO#read" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.read }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.read }.should.raise(IOError)
end
it "raises ArgumentError when length is less than 0" do
- -> { @io.read(-1) }.should raise_error(ArgumentError)
+ -> { @io.read(-1) }.should.raise(ArgumentError)
end
platform_is_not :windows do
@@ -464,7 +444,7 @@ describe "IO#read" do
Thread.pass until t.stop?
r.close
t.join
- t.value.should be_kind_of(IOError)
+ t.value.should.is_a?(IOError)
w.close
end
end
@@ -598,20 +578,20 @@ describe :io_read_internal_encoding, shared: true do
end
it "sets the String encoding to the internal encoding" do
- @io.read.encoding.should equal(Encoding::UTF_8)
+ @io.read.encoding.should.equal?(Encoding::UTF_8)
end
describe "when passed nil for limit" do
it "sets the buffer to a transcoded String" do
result = @io.read(nil, buf = +"")
- buf.should equal(result)
+ buf.should.equal?(result)
buf.should == "ありがとう\n"
end
it "sets the buffer's encoding to the internal encoding" do
buf = "".dup.force_encoding Encoding::ISO_8859_1
@io.read(nil, buf)
- buf.encoding.should equal(Encoding::UTF_8)
+ buf.encoding.should.equal?(Encoding::UTF_8)
end
end
end
@@ -622,24 +602,24 @@ describe :io_read_size_internal_encoding, shared: true do
end
it "returns a String in BINARY when passed a size" do
- @io.read(4).encoding.should equal(Encoding::BINARY)
- @io.read(0).encoding.should equal(Encoding::BINARY)
+ @io.read(4).encoding.should.equal?(Encoding::BINARY)
+ @io.read(0).encoding.should.equal?(Encoding::BINARY)
end
it "does not change the buffer's encoding when passed a limit" do
buf = "".dup.force_encoding Encoding::ISO_8859_1
@io.read(4, buf)
buf.should == [164, 162, 164, 234].pack('C*').force_encoding(Encoding::ISO_8859_1)
- buf.encoding.should equal(Encoding::ISO_8859_1)
+ buf.encoding.should.equal?(Encoding::ISO_8859_1)
end
it "truncates the buffer but does not change the buffer's encoding when no data remains" do
buf = "abc".dup.force_encoding Encoding::ISO_8859_1
@io.read
- @io.read(1, buf).should be_nil
+ @io.read(1, buf).should == nil
buf.size.should == 0
- buf.encoding.should equal(Encoding::ISO_8859_1)
+ buf.encoding.should.equal?(Encoding::ISO_8859_1)
end
end
@@ -657,7 +637,7 @@ describe "IO#read" do
end
it "sets the String encoding to Encoding.default_external" do
- @io.read.encoding.should equal(Encoding.default_external)
+ @io.read.encoding.should.equal?(Encoding.default_external)
end
end
@@ -676,7 +656,7 @@ describe "IO#read" do
end
it "sets the String encoding to the external encoding" do
- @io.read.encoding.should equal(Encoding::EUC_JP)
+ @io.read.encoding.should.equal?(Encoding::EUC_JP)
end
it_behaves_like :io_read_size_internal_encoding, nil
diff --git a/spec/ruby/core/io/readbyte_spec.rb b/spec/ruby/core/io/readbyte_spec.rb
index 14426c28ac..07da1da919 100644
--- a/spec/ruby/core/io/readbyte_spec.rb
+++ b/spec/ruby/core/io/readbyte_spec.rb
@@ -19,6 +19,6 @@ describe "IO#readbyte" do
@io.seek(999999)
-> do
@io.readbyte
- end.should raise_error EOFError
+ end.should.raise EOFError
end
end
diff --git a/spec/ruby/core/io/readchar_spec.rb b/spec/ruby/core/io/readchar_spec.rb
index a66773851a..29d14880ff 100644
--- a/spec/ruby/core/io/readchar_spec.rb
+++ b/spec/ruby/core/io/readchar_spec.rb
@@ -7,7 +7,7 @@ describe :io_readchar_internal_encoding, shared: true do
end
it "sets the String encoding to the internal encoding" do
- @io.readchar.encoding.should equal(Encoding::UTF_8)
+ @io.readchar.encoding.should.equal?(Encoding::UTF_8)
end
end
@@ -31,11 +31,11 @@ describe "IO#readchar" do
it "raises an EOFError when invoked at the end of the stream" do
@io.read
- -> { @io.readchar }.should raise_error(EOFError)
+ -> { @io.readchar }.should.raise(EOFError)
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.readchar }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.readchar }.should.raise(IOError)
end
end
@@ -54,7 +54,7 @@ describe "IO#readchar with internal encoding" do
end
it "sets the String encoding to the external encoding" do
- @io.readchar.encoding.should equal(Encoding::EUC_JP)
+ @io.readchar.encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -105,6 +105,6 @@ describe "IO#readchar" do
end
it "raises EOFError on empty stream" do
- -> { @io.readchar }.should raise_error(EOFError)
+ -> { @io.readchar }.should.raise(EOFError)
end
end
diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb
index a814c1be90..009687710a 100644
--- a/spec/ruby/core/io/readline_spec.rb
+++ b/spec/ruby/core/io/readline_spec.rb
@@ -29,11 +29,11 @@ describe "IO#readline" do
it "raises EOFError on end of stream" do
IOSpecs.lines.length.times { @io.readline }
- -> { @io.readline }.should raise_error(EOFError)
+ -> { @io.readline }.should.raise(EOFError)
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.readline }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.readline }.should.raise(IOError)
end
it "assigns the returned line to $_" do
@@ -53,7 +53,7 @@ describe "IO#readline" do
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { @io.readline(2**128) }.should raise_error(RangeError)
+ -> { @io.readline(2**128) }.should.raise(RangeError)
end
end
@@ -74,11 +74,11 @@ describe "IO#readline" do
end
it "raises exception when options passed as Hash" do
- -> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
+ -> { @io.readline({ chomp: true }) }.should.raise(TypeError)
-> {
@io.readline("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index 3a6ff3d0f3..640e253200 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -17,7 +17,7 @@ describe "IO#readlines" do
it "raises an IOError if the stream is closed" do
@io.close
- -> { @io.readlines }.should raise_error(IOError)
+ -> { @io.readlines }.should.raise(IOError)
end
describe "when passed no arguments" do
@@ -37,12 +37,12 @@ describe "IO#readlines" do
describe "when passed no arguments" do
it "updates self's position" do
@io.readlines
- @io.pos.should eql(137)
+ @io.pos.should.eql?(137)
end
it "updates self's lineno based on the number of lines read" do
@io.readlines
- @io.lineno.should eql(9)
+ @io.lineno.should.eql?(9)
end
it "does not change $_" do
@@ -81,12 +81,12 @@ describe "IO#readlines" do
it "updates self's lineno based on the number of lines read" do
@io.readlines("r")
- @io.lineno.should eql(5)
+ @io.lineno.should.eql?(5)
end
it "updates self's position based on the number of characters read" do
@io.readlines("r")
- @io.pos.should eql(137)
+ @io.pos.should.eql?(137)
end
it "does not change $_" do
@@ -104,11 +104,11 @@ describe "IO#readlines" do
describe "when passed limit" do
it "raises ArgumentError when passed 0 as a limit" do
- -> { @io.readlines(0) }.should raise_error(ArgumentError)
+ -> { @io.readlines(0) }.should.raise(ArgumentError)
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { @io.readlines(2**128) }.should raise_error(RangeError)
+ -> { @io.readlines(2**128) }.should.raise(RangeError)
end
end
@@ -118,11 +118,11 @@ describe "IO#readlines" do
end
it "raises exception when options passed as Hash" do
- -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
+ -> { @io.readlines({ chomp: true }) }.should.raise(TypeError)
-> {
@io.readlines("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
@@ -145,13 +145,13 @@ describe "IO#readlines" do
it "raises an IOError if the stream is opened for append only" do
-> do
File.open(@name, "a:utf-8") { |f| f.readlines }
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
it "raises an IOError if the stream is opened for write only" do
-> do
File.open(@name, "w:utf-8") { |f| f.readlines }
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -174,39 +174,39 @@ describe "IO.readlines" do
$_.should == "test"
end
- describe "when passed a string that starts with a |" do
- it "gets data from the standard out of the subprocess" do
- cmd = "|sh -c 'echo hello;echo line2'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello&echo line2"
- end
-
- lines = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- lines = IO.readlines(cmd)
- end
- lines.should == ["hello\n", "line2\n"]
- end
+ ruby_version_is ""..."4.0" do
+ describe "when passed a string that starts with a |" do
+ it "gets data from the standard out of the subprocess" do
+ cmd = "|sh -c 'echo hello;echo line2'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello&echo line2"
+ end
- platform_is_not :windows do
- it "gets data from a fork when passed -" do
lines = nil
suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- lines = IO.readlines("|-")
+ lines = IO.readlines(cmd)
end
+ lines.should == ["hello\n", "line2\n"]
+ end
- if lines # parent
- lines.should == ["hello\n", "from a fork\n"]
- else
- puts "hello"
- puts "from a fork"
- exit!
+ platform_is_not :windows do
+ it "gets data from a fork when passed -" do
+ lines = nil
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ lines = IO.readlines("|-")
+ end
+
+ if lines # parent
+ lines.should == ["hello\n", "from a fork\n"]
+ else
+ puts "hello"
+ puts "from a fork"
+ exit!
+ end
end
end
end
- end
- ruby_version_is "3.3" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
cmd = "|echo ok"
@@ -237,7 +237,7 @@ describe "IO.readlines" do
it "encodes lines using the default external encoding" do
Encoding.default_external = Encoding::UTF_8
lines = IO.readlines(@name)
- lines.all? { |s| s.encoding == Encoding::UTF_8 }.should be_true
+ lines.all? { |s| s.encoding == Encoding::UTF_8 }.should == true
end
it "encodes lines using the default internal encoding, when set" do
@@ -245,13 +245,13 @@ describe "IO.readlines" do
Encoding.default_internal = Encoding::UTF_16
suppress_warning {$/ = $/.encode Encoding::UTF_16}
lines = IO.readlines(@name)
- lines.all? { |s| s.encoding == Encoding::UTF_16 }.should be_true
+ lines.all? { |s| s.encoding == Encoding::UTF_16 }.should == true
end
it "ignores the default internal encoding if the external encoding is BINARY" do
Encoding.default_external = Encoding::BINARY
Encoding.default_internal = Encoding::UTF_8
lines = IO.readlines(@name)
- lines.all? { |s| s.encoding == Encoding::BINARY }.should be_true
+ lines.all? { |s| s.encoding == Encoding::BINARY }.should == true
end
end
diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb
index 547da0677d..d3f5545c8f 100644
--- a/spec/ruby/core/io/readpartial_spec.rb
+++ b/spec/ruby/core/io/readpartial_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -15,10 +15,10 @@ describe "IO#readpartial" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.readpartial(10) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.readpartial(10) }.should.raise(IOError)
@rd.close
- -> { @rd.readpartial(10) }.should raise_error(IOError)
+ -> { @rd.readpartial(10) }.should.raise(IOError)
end
it "reads at most the specified number of bytes" do
@@ -70,29 +70,34 @@ describe "IO#readpartial" do
@wr.write("abc")
@wr.close
@rd.readpartial(10).should == 'abc'
- -> { @rd.readpartial(10) }.should raise_error(EOFError)
+ -> { @rd.readpartial(10) }.should.raise(EOFError)
end
it "discards the existing buffer content upon error" do
buffer = +'hello'
@wr.close
- -> { @rd.readpartial(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @rd.readpartial(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "raises IOError if the stream is closed" do
@wr.close
- -> { @rd.readpartial(1) }.should raise_error(IOError)
+ -> { @rd.readpartial(1) }.should.raise(IOError)
end
it "raises ArgumentError if the negative argument is provided" do
- -> { @rd.readpartial(-1) }.should raise_error(ArgumentError)
+ -> { @rd.readpartial(-1) }.should.raise(ArgumentError)
end
it "immediately returns an empty string if the length argument is 0" do
@rd.readpartial(0).should == ""
end
+ it "raises IOError if the stream is closed and the length argument is 0" do
+ @rd.close
+ -> { @rd.readpartial(0) }.should.raise(IOError, "closed stream")
+ end
+
it "clears and returns the given buffer if the length argument is 0" do
buffer = +"existing content"
@rd.readpartial(0, buffer).should == buffer
diff --git a/spec/ruby/core/io/reopen_spec.rb b/spec/ruby/core/io/reopen_spec.rb
index 8ff0f217f4..3b972d8978 100644
--- a/spec/ruby/core/io/reopen_spec.rb
+++ b/spec/ruby/core/io/reopen_spec.rb
@@ -27,35 +27,35 @@ describe "IO#reopen" do
it "changes the class of the instance to the class of the object returned by #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return(@other_io)
- @io.reopen(obj).should be_an_instance_of(File)
+ @io.reopen(obj).should.instance_of?(File)
end
it "raises an IOError if the object returned by #to_io is closed" do
obj = mock("io")
obj.should_receive(:to_io).and_return(IOSpecs.closed_io)
- -> { @io.reopen obj }.should raise_error(IOError)
+ -> { @io.reopen obj }.should.raise(IOError)
end
it "raises a TypeError if #to_io does not return an IO instance" do
obj = mock("io")
obj.should_receive(:to_io).and_return("something else")
- -> { @io.reopen obj }.should raise_error(TypeError)
+ -> { @io.reopen obj }.should.raise(TypeError)
end
it "raises an IOError when called on a closed stream with an object" do
@io.close
obj = mock("io")
obj.should_not_receive(:to_io)
- -> { @io.reopen(STDOUT) }.should raise_error(IOError)
+ -> { @io.reopen(STDOUT) }.should.raise(IOError)
end
it "raises an IOError if the IO argument is closed" do
- -> { @io.reopen(IOSpecs.closed_io) }.should raise_error(IOError)
+ -> { @io.reopen(IOSpecs.closed_io) }.should.raise(IOError)
end
it "raises an IOError when called on a closed stream with an IO" do
@io.close
- -> { @io.reopen(STDOUT) }.should raise_error(IOError)
+ -> { @io.reopen(STDOUT) }.should.raise(IOError)
end
end
@@ -77,12 +77,12 @@ describe "IO#reopen with a String" do
it "does not raise an exception when called on a closed stream with a path" do
@io.close
@io.reopen @name, "r"
- @io.closed?.should be_false
+ @io.closed?.should == false
@io.gets.should == "Line 1: One\n"
end
it "returns self" do
- @io.reopen(@name).should equal(@io)
+ @io.reopen(@name).should.equal?(@io)
end
it "positions a newly created instance at the beginning of the new stream" do
@@ -188,7 +188,7 @@ describe "IO#reopen with a String" do
it "raises an Errno::ENOENT if the file does not exist and the IO is not opened in write mode" do
@io = new_io @name, "r"
- -> { @io.reopen(@other_name) }.should raise_error(Errno::ENOENT)
+ -> { @io.reopen(@other_name) }.should.raise(Errno::ENOENT)
end
end
@@ -214,9 +214,9 @@ describe "IO#reopen with an IO at EOF" do
end
it "resets the EOF status to false" do
- @io.eof?.should be_true
+ @io.eof?.should == true
@io.reopen @other_io
- @io.eof?.should be_false
+ @io.eof?.should == false
end
end
@@ -244,7 +244,7 @@ describe "IO#reopen with an IO" do
# MRI actually changes the class of @io in the call to #reopen
# but does not preserve the existing singleton class of @io.
def @io.to_io; flunk; end
- @io.reopen(@other_io).should be_an_instance_of(IO)
+ @io.reopen(@other_io).should.instance_of?(IO)
end
it "does not change the object_id" do
@@ -303,7 +303,7 @@ describe "IO#reopen with an IO" do
it "may change the class of the instance" do
@io.reopen @other_io
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
it "sets path equals to the other IO's path if other IO is File" do
diff --git a/spec/ruby/core/io/rewind_spec.rb b/spec/ruby/core/io/rewind_spec.rb
index 5579cbd988..43834ef307 100644
--- a/spec/ruby/core/io/rewind_spec.rb
+++ b/spec/ruby/core/io/rewind_spec.rb
@@ -48,6 +48,6 @@ describe "IO#rewind" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.rewind }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.rewind }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/seek_spec.rb b/spec/ruby/core/io/seek_spec.rb
index 2fa4a73ac9..d26629fb89 100644
--- a/spec/ruby/core/io/seek_spec.rb
+++ b/spec/ruby/core/io/seek_spec.rb
@@ -17,7 +17,7 @@ describe "IO#seek" do
end
it "moves the read position relative to the current position with SEEK_CUR" do
- -> { @io.seek(-1) }.should raise_error(Errno::EINVAL)
+ -> { @io.seek(-1) }.should.raise(Errno::EINVAL)
@io.seek(10, IO::SEEK_CUR)
@io.readline.should == "igne une.\n"
@io.seek(-5, IO::SEEK_CUR)
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 3893e7620f..0a43fc6f5f 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -18,6 +18,10 @@ describe "IO.select" do
@wr.syswrite("be ready")
IO.pipe do |_, wr|
result = IO.select [@rd], [wr], nil, 0
+ unless result
+ # On some platforms (e.g., Windows), pipe readiness may not be immediate
+ result = IO.select [@rd], [wr], nil, 2
+ end
result.should == [[@rd], [wr], []]
end
end
@@ -91,28 +95,38 @@ describe "IO.select" do
end
it "raises TypeError if supplied objects are not IO" do
- -> { IO.select([Object.new]) }.should raise_error(TypeError)
- -> { IO.select(nil, [Object.new]) }.should raise_error(TypeError)
+ -> { IO.select([Object.new]) }.should.raise(TypeError)
+ -> { IO.select(nil, [Object.new]) }.should.raise(TypeError)
obj = mock("io")
obj.should_receive(:to_io).any_number_of_times.and_return(nil)
- -> { IO.select([obj]) }.should raise_error(TypeError)
- -> { IO.select(nil, [obj]) }.should raise_error(TypeError)
+ -> { IO.select([obj]) }.should.raise(TypeError)
+ -> { IO.select(nil, [obj]) }.should.raise(TypeError)
end
it "raises a TypeError if the specified timeout value is not Numeric" do
- -> { IO.select([@rd], nil, nil, Object.new) }.should raise_error(TypeError)
+ -> { IO.select([@rd], nil, nil, Object.new) }.should.raise(TypeError)
end
it "raises TypeError if the first three arguments are not Arrays" do
- -> { IO.select(Object.new)}.should raise_error(TypeError)
- -> { IO.select(nil, Object.new)}.should raise_error(TypeError)
- -> { IO.select(nil, nil, Object.new)}.should raise_error(TypeError)
+ -> { IO.select(Object.new)}.should.raise(TypeError)
+ -> { IO.select(nil, Object.new)}.should.raise(TypeError)
+ -> { IO.select(nil, nil, Object.new)}.should.raise(TypeError)
end
it "raises an ArgumentError when passed a negative timeout" do
- -> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError)
+ -> { IO.select(nil, nil, nil, -5)}.should.raise(ArgumentError, "time interval must not be negative")
+ end
+
+ ruby_version_is "4.0" do
+ it "raises an ArgumentError when passed negative infinity as timeout" do
+ -> { IO.select(nil, nil, nil, -Float::INFINITY)}.should.raise(ArgumentError, "time interval must not be negative")
+ end
+ end
+
+ it "raises an RangeError when passed NaN as timeout" do
+ -> { IO.select(nil, nil, nil, Float::NAN)}.should.raise(RangeError, "NaN out of Time range")
end
describe "returns the available descriptors when the file descriptor" do
@@ -149,16 +163,28 @@ describe "IO.select" do
end
end
-describe "IO.select when passed nil for timeout" do
- it "sleeps forever and sets the thread status to 'sleep'" do
- t = Thread.new do
- IO.select(nil, nil, nil, nil)
+describe "IO.select with infinite timeout" do
+ describe :io_select_infinite_timeout, shared: true do
+ it "sleeps forever and sets the thread status to 'sleep'" do
+ t = Thread.new do
+ IO.select(nil, nil, nil, @method)
+ end
+
+ Thread.pass while t.status && t.status != "sleep"
+ t.join unless t.status
+ t.status.should == "sleep"
+ t.kill
+ t.join
end
+ end
- Thread.pass while t.status && t.status != "sleep"
- t.join unless t.status
- t.status.should == "sleep"
- t.kill
- t.join
+ describe "IO.select when passed nil for timeout" do
+ it_behaves_like :io_select_infinite_timeout, nil
+ end
+
+ ruby_version_is "4.0" do
+ describe "IO.select when passed Float::INFINITY for timeout" do
+ it_behaves_like :io_select_infinite_timeout, Float::INFINITY
+ end
end
end
diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb
index 30d5ce5a5a..5436879f11 100644
--- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb
+++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb
@@ -15,7 +15,7 @@ describe "IO#set_encoding_by_bom" do
it "returns nil if not readable" do
not_readable_io = new_io(@name, 'wb')
- not_readable_io.set_encoding_by_bom.should be_nil
+ not_readable_io.set_encoding_by_bom.should == nil
not_readable_io.external_encoding.should == Encoding::ASCII_8BIT
ensure
not_readable_io.close
@@ -102,7 +102,7 @@ describe "IO#set_encoding_by_bom" do
end
it "returns nil if io is empty" do
- @io.set_encoding_by_bom.should be_nil
+ @io.set_encoding_by_bom.should == nil
@io.external_encoding.should == Encoding::ASCII_8BIT
end
@@ -243,7 +243,7 @@ describe "IO#set_encoding_by_bom" do
it 'returns exception if io not in binary mode' do
not_binary_io = new_io(@name, 'r')
- -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode')
+ -> { not_binary_io.set_encoding_by_bom }.should.raise(ArgumentError, 'ASCII incompatible encoding needs binmode')
ensure
not_binary_io.close
end
@@ -251,12 +251,12 @@ describe "IO#set_encoding_by_bom" do
it 'returns exception if encoding already set' do
@io.set_encoding("utf-8")
- -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already')
+ -> { @io.set_encoding_by_bom }.should.raise(ArgumentError, 'encoding is set to UTF-8 already')
end
it 'returns exception if encoding conversion is already set' do
@io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE)
- -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set')
+ -> { @io.set_encoding_by_bom }.should.raise(ArgumentError, 'encoding conversion is set')
end
end
diff --git a/spec/ruby/core/io/set_encoding_spec.rb b/spec/ruby/core/io/set_encoding_spec.rb
index 22d9017635..237251de5b 100644
--- a/spec/ruby/core/io/set_encoding_spec.rb
+++ b/spec/ruby/core/io/set_encoding_spec.rb
@@ -5,21 +5,21 @@ describe :io_set_encoding_write, shared: true do
@io = new_io @name, "#{@object}:ibm437:ibm866"
@io.set_encoding nil, nil
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
end
it "sets the encodings to nil when the IO is built with no explicit encoding" do
@io = new_io @name, @object
# Checking our assumptions first
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
@io.set_encoding nil, nil
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
end
it "prevents the encodings from changing when Encoding defaults are changed" do
@@ -29,8 +29,8 @@ describe :io_set_encoding_write, shared: true do
Encoding.default_external = Encoding::IBM437
Encoding.default_internal = Encoding::IBM866
- @io.external_encoding.should be_nil
- @io.internal_encoding.should be_nil
+ @io.external_encoding.should == nil
+ @io.internal_encoding.should == nil
end
it "sets the encodings to the current Encoding defaults" do
@@ -75,8 +75,8 @@ describe "IO#set_encoding when passed nil, nil" do
Encoding.default_internal = Encoding::IBM866
@io.set_encoding nil, nil
- @io.external_encoding.should equal(Encoding::IBM437)
- @io.internal_encoding.should equal(Encoding::IBM866)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
+ @io.internal_encoding.should.equal?(Encoding::IBM866)
end
it "prevents the #internal_encoding from changing when Encoding.default_internal is changed" do
@@ -85,7 +85,7 @@ describe "IO#set_encoding when passed nil, nil" do
Encoding.default_internal = Encoding::IBM437
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "allows the #external_encoding to change when Encoding.default_external is changed" do
@@ -94,17 +94,17 @@ describe "IO#set_encoding when passed nil, nil" do
Encoding.default_external = Encoding::IBM437
- @io.external_encoding.should equal(Encoding::IBM437)
+ @io.external_encoding.should.equal?(Encoding::IBM437)
end
end
describe "with 'rb' mode" do
it "returns Encoding.default_external" do
@io = new_io @name, "rb"
- @io.external_encoding.should equal(Encoding::BINARY)
+ @io.external_encoding.should.equal?(Encoding::BINARY)
@io.set_encoding nil, nil
- @io.external_encoding.should equal(Encoding.default_external)
+ @io.external_encoding.should.equal?(Encoding.default_external)
end
end
@@ -158,13 +158,13 @@ describe "IO#set_encoding" do
end
it "returns self" do
- @io.set_encoding(Encoding::UTF_8).should equal(@io)
+ @io.set_encoding(Encoding::UTF_8).should.equal?(@io)
end
it "sets the external encoding when passed an Encoding argument" do
@io.set_encoding(Encoding::UTF_8)
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "sets the external and internal encoding when passed two Encoding arguments" do
@@ -176,19 +176,19 @@ describe "IO#set_encoding" do
it "sets the external encoding when passed the name of an Encoding" do
@io.set_encoding("utf-8")
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "ignores the internal encoding if the same as external when passed Encoding objects" do
@io.set_encoding(Encoding::UTF_8, Encoding::UTF_8)
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "ignores the internal encoding if the same as external when passed encoding names separated by ':'" do
@io.set_encoding("utf-8:utf-8")
@io.external_encoding.should == Encoding::UTF_8
- @io.internal_encoding.should be_nil
+ @io.internal_encoding.should == nil
end
it "sets the external and internal encoding when passed the names of Encodings separated by ':'" do
@@ -229,10 +229,10 @@ describe "IO#set_encoding" do
end
it "raises ArgumentError when no arguments are given" do
- -> { @io.set_encoding() }.should raise_error(ArgumentError)
+ -> { @io.set_encoding() }.should.raise(ArgumentError)
end
it "raises ArgumentError when too many arguments are given" do
- -> { @io.set_encoding(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @io.set_encoding(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/shared/binwrite.rb b/spec/ruby/core/io/shared/binwrite.rb
index e51093329b..64793b1936 100644
--- a/spec/ruby/core/io/shared/binwrite.rb
+++ b/spec/ruby/core/io/shared/binwrite.rb
@@ -26,7 +26,7 @@ describe :io_binwrite, shared: true do
-> {
IO.send(@method, @filename, "hi", 0, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 2..3)")
end
it "creates a file if missing" do
@@ -81,7 +81,7 @@ describe :io_binwrite, shared: true do
end
it "raises an error if readonly mode is specified" do
- -> { IO.send(@method, @filename, "abcde", mode: "r") }.should raise_error(IOError)
+ -> { IO.send(@method, @filename, "abcde", mode: "r") }.should.raise(IOError)
end
it "truncates if empty :opts provided and offset skipped" do
diff --git a/spec/ruby/core/io/shared/chars.rb b/spec/ruby/core/io/shared/chars.rb
index 266566f221..efd4d5ee10 100644
--- a/spec/ruby/core/io/shared/chars.rb
+++ b/spec/ruby/core/io/shared/chars.rb
@@ -24,7 +24,7 @@ describe :io_chars, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
enum = @io.send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.first(5).should == ["V", "o", "i", "c", "i"]
end
@@ -38,19 +38,19 @@ describe :io_chars, shared: true do
end
it "returns itself" do
- @io.send(@method) { |c| }.should equal(@io)
+ @io.send(@method) { |c| }.should.equal?(@io)
end
it "returns an enumerator for a closed stream" do
- IOSpecs.closed_io.send(@method).should be_an_instance_of(Enumerator)
+ IOSpecs.closed_io.send(@method).should.instance_of?(Enumerator)
end
it "raises an IOError when an enumerator created on a closed stream is accessed" do
- -> { IOSpecs.closed_io.send(@method).first }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method).first }.should.raise(IOError)
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method) {} }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/shared/codepoints.rb b/spec/ruby/core/io/shared/codepoints.rb
index 6872846c1a..21c756986f 100644
--- a/spec/ruby/core/io/shared/codepoints.rb
+++ b/spec/ruby/core/io/shared/codepoints.rb
@@ -13,7 +13,7 @@ describe :io_codepoints, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
- @enum.should be_an_instance_of(Enumerator)
+ @enum.should.instance_of?(Enumerator)
end
describe "returned Enumerator" do
@@ -39,7 +39,7 @@ describe :io_codepoints, shared: true do
it "raises an error if reading invalid sequence" do
@io.pos = 60 # inside of a multibyte sequence
- -> { @enum.first }.should raise_error(ArgumentError)
+ -> { @enum.first }.should.raise(ArgumentError)
end
it "does not change $_" do
@@ -49,6 +49,6 @@ describe :io_codepoints, shared: true do
end
it "raises an IOError when self is not readable" do
- -> { IOSpecs.closed_io.send(@method).to_a }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method).to_a }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
index aca622834f..ae60c3506a 100644
--- a/spec/ruby/core/io/shared/each.rb
+++ b/spec/ruby/core/io/shared/each.rb
@@ -24,7 +24,7 @@ describe :io_each, shared: true do
end
it "returns self" do
- @io.send(@method) { |l| l }.should equal(@io)
+ @io.send(@method) { |l| l }.should.equal?(@io)
end
it "does not change $_" do
@@ -34,7 +34,7 @@ describe :io_each, shared: true do
end
it "raises an IOError when self is not readable" do
- -> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method) {} }.should.raise(IOError)
end
it "makes line count accessible via lineno" do
@@ -50,7 +50,7 @@ describe :io_each, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
enum = @io.send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |l| ScratchPad << l }
ScratchPad.recorded.should == IOSpecs.lines
@@ -70,12 +70,12 @@ describe :io_each, shared: true do
describe "when limit is 0" do
it "raises an ArgumentError" do
# must pass block so Enumerator is evaluated and raises
- -> { @io.send(@method, 0){} }.should raise_error(ArgumentError)
+ -> { @io.send(@method, 0){} }.should.raise(ArgumentError)
end
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { @io.send(@method, 2**128){} }.should raise_error(RangeError)
+ -> { @io.send(@method, 2**128){} }.should.raise(RangeError)
end
end
@@ -126,7 +126,7 @@ describe :io_each, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
enum = @io.send(@method, nil, 1024)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each { |l| ScratchPad << l }
ScratchPad.recorded.should == [IOSpecs.lines.join]
@@ -143,7 +143,7 @@ describe :io_each, shared: true do
describe "when a block is given" do
it "accepts an empty block" do
- @io.send(@method, nil, 1024) {}.should equal(@io)
+ @io.send(@method, nil, 1024) {}.should.equal?(@io)
end
describe "when passed nil as a separator" do
@@ -179,11 +179,11 @@ describe :io_each, shared: true do
it "raises exception when options passed as Hash" do
-> {
@io.send(@method, { chomp: true }) { |s| }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
@io.send(@method, "\n", 1, { chomp: true }) { |s| }
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
@@ -202,20 +202,10 @@ describe :io_each, shared: true do
end
describe "when passed chomp and nil as a separator" do
- ruby_version_is "3.2" do
- it "yields self's content" do
- @io.pos = 100
- @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
- end
- end
-
- ruby_version_is ""..."3.2" do
- it "yields self's content without trailing new line character" do
- @io.pos = 100
- @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."]
- end
+ it "yields self's content" do
+ @io.pos = 100
+ @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
end
end
@@ -237,7 +227,7 @@ describe :io_each, shared: true do
it "raises ArgumentError" do
-> {
@io.send(@method, "", 1, "excess argument", chomp: true) {}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/io/shared/gets_ascii.rb b/spec/ruby/core/io/shared/gets_ascii.rb
index 2a8fe3c9a5..2bd5470d99 100644
--- a/spec/ruby/core/io/shared/gets_ascii.rb
+++ b/spec/ruby/core/io/shared/gets_ascii.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :io_gets_ascii, shared: true do
describe "with ASCII separator" do
before :each do
diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb
index cba5f33ebf..6f318ddee5 100644
--- a/spec/ruby/core/io/shared/new.rb
+++ b/spec/ruby/core/io/shared/new.rb
@@ -22,7 +22,7 @@ describe :io_new, shared: true do
it "creates an IO instance from an Integer argument" do
@io = IO.send(@method, @fd, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
it "creates an IO instance when STDOUT is closed" do
@@ -32,7 +32,7 @@ describe :io_new, shared: true do
begin
@io = IO.send(@method, @fd, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
ensure
STDOUT = stdout
rm_r stdout_file
@@ -49,7 +49,7 @@ describe :io_new, shared: true do
begin
@io = IO.send(@method, @fd, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
ensure
STDERR = stderr
rm_r stderr_file
@@ -61,7 +61,7 @@ describe :io_new, shared: true do
obj = mock("file descriptor")
obj.should_receive(:to_int).and_return(@fd)
@io = IO.send(@method, obj, "w")
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
it "accepts options as keyword arguments" do
@@ -70,7 +70,7 @@ describe :io_new, shared: true do
-> {
IO.send(@method, @fd, "w", {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
end
it "accepts a :mode option" do
@@ -208,10 +208,30 @@ describe :io_new, shared: true do
@io.internal_encoding.to_s.should == 'IBM866'
end
+ it "does not use binary encoding when mode encoding is specified along with binmode: true option" do
+ @io = IO.send(@method, @fd, 'w:iso-8859-1', binmode: true)
+ @io.external_encoding.to_s.should == 'ISO-8859-1'
+ end
+
+ it "does not use textmode argument when mode encoding is specified" do
+ @io = IO.send(@method, @fd, 'w:ascii-8bit', textmode: true)
+ @io.external_encoding.to_s.should == 'ASCII-8BIT'
+ end
+
+ it "does not use binmode argument when external encoding is specified via the :external_encoding option" do
+ @io = IO.send(@method, @fd, 'w', binmode: true, external_encoding: 'iso-8859-1')
+ @io.external_encoding.to_s.should == 'ISO-8859-1'
+ end
+
+ it "does not use textmode argument when external encoding is specified via the :external_encoding option" do
+ @io = IO.send(@method, @fd, 'w', textmode: true, external_encoding: 'ascii-8bit')
+ @io.external_encoding.to_s.should == 'ASCII-8BIT'
+ end
+
it "raises ArgumentError for nil options" do
-> {
IO.send(@method, @fd, 'w', nil)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "coerces mode with #to_str" do
@@ -294,97 +314,100 @@ describe :io_new_errors, shared: true do
end
it "raises an Errno::EBADF if the file descriptor is not valid" do
- -> { IO.send(@method, -1, "w") }.should raise_error(Errno::EBADF)
+ -> { IO.send(@method, -1, "w") }.should.raise(Errno::EBADF)
end
it "raises an IOError if passed a closed stream" do
- -> { IO.send(@method, IOSpecs.closed_io.fileno, 'w') }.should raise_error(IOError)
+ -> { IO.send(@method, IOSpecs.closed_io.fileno, 'w') }.should.raise(IOError)
end
platform_is_not :windows do
it "raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode" do
- -> { IO.send(@method, @fd, "r") }.should raise_error(Errno::EINVAL)
+ -> { IO.send(@method, @fd, "r") }.should.raise(Errno::EINVAL)
end
end
it "raises ArgumentError if passed an empty mode string" do
- -> { IO.send(@method, @fd, "") }.should raise_error(ArgumentError)
+ -> { IO.send(@method, @fd, "") }.should.raise(ArgumentError)
end
it "raises an error if passed modes two ways" do
-> {
IO.send(@method, @fd, "w", mode: "w")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed encodings two ways" do
-> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1', encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
+ -> {
+ @io = IO.send(@method, @fd, 'w:ISO-8859-1', internal_encoding: 'ISO-8859-1')
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed matching binary/text mode two ways" do
-> {
@io = IO.send(@method, @fd, "wb", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wb", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed conflicting binary/text mode two ways" do
-> {
@io = IO.send(@method, @fd, "wb", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wb", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, "wt", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error when trying to set both binmode and textmode" do
-> {
@io = IO.send(@method, @fd, "w", textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, File::Constants::WRONLY, textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if not passed a hash or nil for options" do
-> {
@io = IO.send(@method, @fd, 'w', false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, false, false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = IO.send(@method, @fd, nil, false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if passed a hash for mode and nil for options" do
-> {
@io = IO.send(@method, @fd, {mode: 'w'}, nil)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/shared/pos.rb b/spec/ruby/core/io/shared/pos.rb
index 3fdd3eb2b3..f4d0405863 100644
--- a/spec/ruby/core/io/shared/pos.rb
+++ b/spec/ruby/core/io/shared/pos.rb
@@ -19,7 +19,7 @@ describe :io_pos, shared: true do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send(@method) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method) }.should.raise(IOError)
end
it "resets #eof?" do
@@ -62,17 +62,17 @@ describe :io_set_pos, shared: true do
it "raises TypeError when cannot convert implicitly argument to Integer" do
File.open @fname do |io|
- -> { io.send @method, Object.new }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ -> { io.send @method, Object.new }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
end
it "does not accept Integers that don't fit in a C off_t" do
File.open @fname do |io|
- -> { io.send @method, 2**128 }.should raise_error(RangeError)
+ -> { io.send @method, 2**128 }.should.raise(RangeError)
end
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send @method, 0 }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send @method, 0 }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 6c1fa11a59..f54fccc2e3 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -1,11 +1,11 @@
describe :io_readlines, shared: true do
it "raises TypeError if the first parameter is nil" do
- -> { IO.send(@method, nil, &@object) }.should raise_error(TypeError)
+ -> { IO.send(@method, nil, &@object) }.should.raise(TypeError)
end
it "raises an Errno::ENOENT if the file does not exist" do
name = tmp("nonexistent.txt")
- -> { IO.send(@method, name, &@object) }.should raise_error(Errno::ENOENT)
+ -> { IO.send(@method, name, &@object) }.should.raise(Errno::ENOENT)
end
it "yields a single string with entire content when the separator is nil" do
@@ -80,14 +80,12 @@ describe :io_readlines_options_19, shared: true do
end
it "does not accept Integers that don't fit in a C off_t" do
- -> { IO.send(@method, @name, 2**128, &@object) }.should raise_error(RangeError)
+ -> { IO.send(@method, @name, 2**128, &@object) }.should.raise(RangeError)
end
- ruby_bug "#18767", ""..."3.3" do
- describe "when passed limit" do
- it "raises ArgumentError when passed 0 as a limit" do
- -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError)
- end
+ describe "when passed limit" do
+ it "raises ArgumentError when passed 0 as a limit" do
+ -> { IO.send(@method, @name, 0, &@object) }.should.raise(ArgumentError)
end
end
end
@@ -108,7 +106,7 @@ describe :io_readlines_options_19, shared: true do
it "raises TypeError exception" do
-> {
IO.send(@method, @name, { chomp: true }, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -118,7 +116,7 @@ describe :io_readlines_options_19, shared: true do
-> {
IO.send(@method, @name, obj, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
@@ -172,7 +170,7 @@ describe :io_readlines_options_19, shared: true do
-> {
IO.send(@method, @name, " ", obj, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -180,7 +178,7 @@ describe :io_readlines_options_19, shared: true do
it "raises TypeError exception" do
-> {
IO.send(@method, @name, "", { chomp: true }, &@object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
@@ -190,7 +188,7 @@ describe :io_readlines_options_19, shared: true do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, 10, mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -198,7 +196,7 @@ describe :io_readlines_options_19, shared: true do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
@@ -209,7 +207,7 @@ describe :io_readlines_options_19, shared: true do
-> do
IO.send(@method, @filename, sep, mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
end
end
@@ -239,7 +237,7 @@ describe :io_readlines_options_19, shared: true do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", 10, mode: "w", &@object)
- end.should raise_error(IOError)
+ end.should.raise(IOError)
end
describe "when passed chomp, nil as a separator, and a limit" do
diff --git a/spec/ruby/core/io/shared/tty.rb b/spec/ruby/core/io/shared/tty.rb
index 89ac08ec86..1dc0e95739 100644
--- a/spec/ruby/core/io/shared/tty.rb
+++ b/spec/ruby/core/io/shared/tty.rb
@@ -19,6 +19,6 @@ describe :io_tty, shared: true do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send @method }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send @method }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb
index 964064746a..5de9fe4335 100644
--- a/spec/ruby/core/io/shared/write.rb
+++ b/spec/ruby/core/io/shared/write.rb
@@ -23,7 +23,7 @@ describe :io_write, shared: true do
end
it "checks if the file is writable if writing more than zero bytes" do
- -> { @readonly_file.send(@method, "abcde") }.should raise_error(IOError)
+ -> { @readonly_file.send(@method, "abcde") }.should.raise(IOError)
end
it "returns the number of bytes written" do
@@ -66,7 +66,7 @@ describe :io_write, shared: true do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.send(@method, "hello") }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.send(@method, "hello") }.should.raise(IOError)
end
describe "on a pipe" do
@@ -92,7 +92,7 @@ describe :io_write, shared: true do
guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do
it "raises Errno::EPIPE if the read end is closed and does not die from SIGPIPE" do
@r.close
- -> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, /Broken pipe/)
+ -> { @w.send(@method, "foo") }.should.raise(Errno::EPIPE, /Broken pipe/)
end
end
end
@@ -126,7 +126,7 @@ describe :io_write_transcode, shared: true do
File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
file.external_encoding.should == Encoding::UTF_16BE
- -> { file.send(@method, str) }.should raise_error(Encoding::UndefinedConversionError)
+ -> { file.send(@method, str) }.should.raise(Encoding::UndefinedConversionError)
end
end
end
diff --git a/spec/ruby/core/io/stat_spec.rb b/spec/ruby/core/io/stat_spec.rb
index 717c45d0a3..f9fc232ee0 100644
--- a/spec/ruby/core/io/stat_spec.rb
+++ b/spec/ruby/core/io/stat_spec.rb
@@ -12,14 +12,14 @@ describe "IO#stat" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.stat }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.stat }.should.raise(IOError)
end
it "returns a File::Stat object for the stream" do
- STDOUT.stat.should be_an_instance_of(File::Stat)
+ STDOUT.stat.should.instance_of?(File::Stat)
end
it "can stat pipes" do
- @io.stat.should be_an_instance_of(File::Stat)
+ @io.stat.should.instance_of?(File::Stat)
end
end
diff --git a/spec/ruby/core/io/sync_spec.rb b/spec/ruby/core/io/sync_spec.rb
index 993b7ee244..b537db335b 100644
--- a/spec/ruby/core/io/sync_spec.rb
+++ b/spec/ruby/core/io/sync_spec.rb
@@ -27,7 +27,7 @@ describe "IO#sync=" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.sync = true }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.sync = true }.should.raise(IOError)
end
end
@@ -45,7 +45,7 @@ describe "IO#sync" do
end
it "raises an IOError on closed stream" do
- -> { IOSpecs.closed_io.sync }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.sync }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/sysopen_spec.rb b/spec/ruby/core/io/sysopen_spec.rb
index 7ad379df3a..325d51ed23 100644
--- a/spec/ruby/core/io/sysopen_spec.rb
+++ b/spec/ruby/core/io/sysopen_spec.rb
@@ -13,16 +13,16 @@ describe "IO.sysopen" do
it "returns the file descriptor for a given path" do
@fd = IO.sysopen(@filename, "w")
- @fd.should be_kind_of(Integer)
- @fd.should_not equal(0)
+ @fd.should.is_a?(Integer)
+ @fd.should_not.equal?(0)
end
# opening a directory is not supported on Windows
platform_is_not :windows do
it "works on directories" do
@fd = IO.sysopen(tmp("")) # /tmp
- @fd.should be_kind_of(Integer)
- @fd.should_not equal(0)
+ @fd.should.is_a?(Integer)
+ @fd.should_not.equal?(0)
end
end
@@ -33,18 +33,18 @@ describe "IO.sysopen" do
end
it "accepts a mode as second argument" do
- -> { @fd = IO.sysopen(@filename, "w") }.should_not raise_error
- @fd.should_not equal(0)
+ -> { @fd = IO.sysopen(@filename, "w") }.should_not.raise
+ @fd.should_not.equal?(0)
end
it "accepts permissions as third argument" do
@fd = IO.sysopen(@filename, "w", 777)
- @fd.should_not equal(0)
+ @fd.should_not.equal?(0)
end
it "accepts mode & permission that are nil" do
touch @filename # create the file
@fd = IO.sysopen(@filename, nil, nil)
- @fd.should_not equal(0)
+ @fd.should_not.equal?(0)
end
end
diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb
index 8851214283..2d58db2250 100644
--- a/spec/ruby/core/io/sysread_spec.rb
+++ b/spec/ruby/core/io/sysread_spec.rb
@@ -52,7 +52,7 @@ describe "IO#sysread on a file" do
it "raises an error when called after buffered reads" do
@file.readline
- -> { @file.sysread(5) }.should raise_error(IOError)
+ -> { @file.sysread(5) }.should.raise(IOError)
end
it "reads normally even when called immediately after a buffered IO#read" do
@@ -63,13 +63,13 @@ describe "IO#sysread on a file" do
it "does not raise error if called after IO#read followed by IO#write" do
@file.read(5)
@file.write("abcde")
- -> { @file.sysread(5) }.should_not raise_error(IOError)
+ -> { @file.sysread(5) }.should_not.raise(IOError)
end
it "does not raise error if called after IO#read followed by IO#syswrite" do
@file.read(5)
@file.syswrite("abcde")
- -> { @file.sysread(5) }.should_not raise_error(IOError)
+ -> { @file.sysread(5) }.should_not.raise(IOError)
end
it "reads updated content after the flushed buffered IO#write" do
@@ -82,7 +82,7 @@ describe "IO#sysread on a file" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.sysread(5) }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.sysread(5) }.should.raise(IOError)
end
it "immediately returns an empty string if the length argument is 0" do
@@ -104,8 +104,8 @@ describe "IO#sysread on a file" do
it "discards the existing buffer content upon error" do
buffer = +"existing content"
@file.seek(0, :END)
- -> { @file.sysread(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @file.sysread(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "preserves the encoding of the given buffer" do
@@ -131,9 +131,7 @@ describe "IO#sysread" do
@read.sysread(3).should == "ab"
end
- guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do # https://bugs.ruby-lang.org/issues/18880
- it "raises ArgumentError when length is less than 0" do
- -> { @read.sysread(-1) }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError when length is less than 0" do
+ -> { @read.sysread(-1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/sysseek_spec.rb b/spec/ruby/core/io/sysseek_spec.rb
index 002f2a14eb..2384895dc5 100644
--- a/spec/ruby/core/io/sysseek_spec.rb
+++ b/spec/ruby/core/io/sysseek_spec.rb
@@ -23,7 +23,7 @@ describe "IO#sysseek" do
it "raises an error when called after buffered reads" do
@io.readline
- -> { @io.sysseek(-5, IO::SEEK_CUR) }.should raise_error(IOError)
+ -> { @io.sysseek(-5, IO::SEEK_CUR) }.should.raise(IOError)
end
it "seeks normally even when called immediately after a buffered IO#read" do
@@ -41,7 +41,7 @@ describe "IO#sysseek" do
# this is the safest way of checking the EOF when
# sys-* methods are invoked
- -> { @io.sysread(1) }.should raise_error(EOFError)
+ -> { @io.sysread(1) }.should.raise(EOFError)
@io.sysseek(-25, IO::SEEK_END)
@io.sysread(7).should == "cinco.\n"
diff --git a/spec/ruby/core/io/to_i_spec.rb b/spec/ruby/core/io/to_i_spec.rb
index acf138c663..1d0cf2a1f6 100644
--- a/spec/ruby/core/io/to_i_spec.rb
+++ b/spec/ruby/core/io/to_i_spec.rb
@@ -7,6 +7,6 @@ describe "IO#to_i" do
end
it "raises IOError on closed stream" do
- -> { IOSpecs.closed_io.to_i }.should raise_error(IOError)
+ -> { IOSpecs.closed_io.to_i }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/to_io_spec.rb b/spec/ruby/core/io/to_io_spec.rb
index 55a0977740..0b1809dffa 100644
--- a/spec/ruby/core/io/to_io_spec.rb
+++ b/spec/ruby/core/io/to_io_spec.rb
@@ -11,11 +11,11 @@ describe "IO#to_io" do
end
it "returns self for open stream" do
- @io.to_io.should equal(@io)
+ @io.to_io.should.equal?(@io)
end
it "returns self for closed stream" do
io = IOSpecs.closed_io
- io.to_io.should equal(io)
+ io.to_io.should.equal?(io)
end
end
diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb
index a9e99de7aa..7600b01b75 100644
--- a/spec/ruby/core/io/try_convert_spec.rb
+++ b/spec/ruby/core/io/try_convert_spec.rb
@@ -13,7 +13,7 @@ describe "IO.try_convert" do
end
it "returns the passed IO object" do
- IO.try_convert(@io).should equal(@io)
+ IO.try_convert(@io).should.equal?(@io)
end
it "does not call #to_io on an IO instance" do
@@ -24,26 +24,26 @@ describe "IO.try_convert" do
it "calls #to_io to coerce an object" do
obj = mock("io")
obj.should_receive(:to_io).and_return(@io)
- IO.try_convert(obj).should equal(@io)
+ IO.try_convert(obj).should.equal?(@io)
end
it "returns nil when the passed object does not respond to #to_io" do
- IO.try_convert(mock("io")).should be_nil
+ IO.try_convert(mock("io")).should == nil
end
it "return nil when BasicObject is passed" do
- IO.try_convert(BasicObject.new).should be_nil
+ IO.try_convert(BasicObject.new).should == nil
end
it "raises a TypeError if the object does not return an IO from #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return("io")
- -> { IO.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to IO (MockObject#to_io gives String)")
+ -> { IO.try_convert(obj) }.should raise_consistent_error(TypeError, "can't convert MockObject into IO (MockObject#to_io gives String)")
end
it "propagates an exception raised by #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_raise(TypeError.new)
- ->{ IO.try_convert(obj) }.should raise_error(TypeError)
+ ->{ IO.try_convert(obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/io/ungetbyte_spec.rb b/spec/ruby/core/io/ungetbyte_spec.rb
index 716743a6af..e0615cd76c 100644
--- a/spec/ruby/core/io/ungetbyte_spec.rb
+++ b/spec/ruby/core/io/ungetbyte_spec.rb
@@ -13,12 +13,12 @@ describe "IO#ungetbyte" do
end
it "does nothing when passed nil" do
- @io.ungetbyte(nil).should be_nil
+ @io.ungetbyte(nil).should == nil
@io.getbyte.should == 97
end
it "puts back each byte in a String argument" do
- @io.ungetbyte("cat").should be_nil
+ @io.ungetbyte("cat").should == nil
@io.getbyte.should == 99
@io.getbyte.should == 97
@io.getbyte.should == 116
@@ -29,7 +29,7 @@ describe "IO#ungetbyte" do
str = mock("io ungetbyte")
str.should_receive(:to_str).and_return("dog")
- @io.ungetbyte(str).should be_nil
+ @io.ungetbyte(str).should == nil
@io.getbyte.should == 100
@io.getbyte.should == 111
@io.getbyte.should == 103
@@ -38,17 +38,17 @@ describe "IO#ungetbyte" do
it "never raises RangeError" do
for i in [4095, 0x4f7574206f6620636861722072616e67ff] do
- @io.ungetbyte(i).should be_nil
+ @io.ungetbyte(i).should == nil
@io.getbyte.should == 255
end
end
it "raises IOError on stream not opened for reading" do
- -> { STDOUT.ungetbyte(42) }.should raise_error(IOError, "not opened for reading")
+ -> { STDOUT.ungetbyte(42) }.should.raise(IOError, "not opened for reading")
end
it "raises an IOError if the IO is closed" do
@io.close
- -> { @io.ungetbyte(42) }.should raise_error(IOError)
+ -> { @io.ungetbyte(42) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/ungetc_spec.rb b/spec/ruby/core/io/ungetc_spec.rb
index 47a4e99ebf..4a9e67f126 100644
--- a/spec/ruby/core/io/ungetc_spec.rb
+++ b/spec/ruby/core/io/ungetc_spec.rb
@@ -100,17 +100,17 @@ describe "IO#ungetc" do
it "makes subsequent unbuffered operations to raise IOError" do
@io.getc
@io.ungetc(100)
- -> { @io.sysread(1) }.should raise_error(IOError)
+ -> { @io.sysread(1) }.should.raise(IOError)
end
it "raises TypeError if passed nil" do
@io.getc.should == ?V
- proc{@io.ungetc(nil)}.should raise_error(TypeError)
+ proc{@io.ungetc(nil)}.should.raise(TypeError)
end
it "puts one or more characters back in the stream" do
@io.gets
- @io.ungetc("Aquí ").should be_nil
+ @io.ungetc("Aquí ").should == nil
@io.gets.chomp.should == "Aquí Qui è la linea due."
end
@@ -118,21 +118,21 @@ describe "IO#ungetc" do
chars = mock("io ungetc")
chars.should_receive(:to_str).and_return("Aquí ")
- @io.ungetc(chars).should be_nil
+ @io.ungetc(chars).should == nil
@io.gets.chomp.should == "Aquí Voici la ligne une."
end
it "returns nil when invoked on stream that was not yet read" do
- @io.ungetc(100).should be_nil
+ @io.ungetc(100).should == nil
end
it "raises IOError on stream not opened for reading" do
- -> { STDOUT.ungetc(100) }.should raise_error(IOError, "not opened for reading")
+ -> { STDOUT.ungetc(100) }.should.raise(IOError, "not opened for reading")
end
it "raises IOError on closed stream" do
@io.getc
@io.close
- -> { @io.ungetc(100) }.should raise_error(IOError)
+ -> { @io.ungetc(100) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb
index 5bfc690f9b..a6bd43c058 100644
--- a/spec/ruby/core/io/write_nonblock_spec.rb
+++ b/spec/ruby/core/io/write_nonblock_spec.rb
@@ -44,7 +44,7 @@ platform_is_not :windows do
it "checks if the file is writable if writing zero bytes" do
-> {
@readonly_file.write_nonblock("")
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
@@ -67,12 +67,12 @@ describe 'IO#write_nonblock' do
it "raises an exception extending IO::WaitWritable when the write would block" do
-> {
loop { @write.write_nonblock('a' * 10_000) }
- }.should raise_error(IO::WaitWritable) { |e|
+ }.should.raise(IO::WaitWritable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index 4a26f8dbaf..1a745ba012 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -21,7 +21,7 @@ describe "IO#write on a file" do
end
it "does not check if the file is writable if writing zero bytes" do
- -> { @readonly_file.write("") }.should_not raise_error
+ -> { @readonly_file.write("") }.should_not.raise
end
before :each do
@@ -102,11 +102,18 @@ describe "IO#write on a file" do
File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
end
+ it "ignores the 'bom|' prefix" do
+ File.open(@filename, "w", encoding: 'bom|utf-8') do |file|
+ file.write("hi")
+ end
+ File.binread(@filename).should == "hi"
+ end
+
it "raises a invalid byte sequence error if invalid bytes are being written" do
# pack "\xFEhi" to avoid utf-8 conflict
xFEhi = ([254].pack('C*') + 'hi').force_encoding('utf-8')
File.open(@filename, "w", encoding: Encoding::US_ASCII) do |file|
- -> { file.write(xFEhi) }.should raise_error(Encoding::InvalidByteSequenceError)
+ -> { file.write(xFEhi) }.should.raise(Encoding::InvalidByteSequenceError)
end
end
@@ -150,7 +157,7 @@ describe "IO.write" do
it "requires mode to be specified in :open_args" do
-> {
IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true}])
- }.should raise_error(IOError, "not opened for writing")
+ }.should.raise(IOError, "not opened for writing")
IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true}]).should == 8
IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, mode: "w"}]).should == 8
@@ -159,7 +166,7 @@ describe "IO.write" do
it "requires mode to be specified in :open_args even if flags option passed" do
-> {
IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}])
- }.should raise_error(IOError, "not opened for writing")
+ }.should.raise(IOError, "not opened for writing")
IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}]).should == 8
IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT, mode: "w"}]).should == 8
@@ -172,11 +179,11 @@ describe "IO.write" do
it "raises ArgumentError if encoding is specified in mode parameter and is given as :encoding option" do
-> {
IO.write(@filename, 'hi', mode: "w:UTF-16LE:UTF-16BE", encoding: Encoding::UTF_32LE)
- }.should raise_error(ArgumentError, "encoding specified twice")
+ }.should.raise(ArgumentError, "encoding specified twice")
-> {
IO.write(@filename, 'hi', mode: "w:UTF-16BE", encoding: Encoding::UTF_32LE)
- }.should raise_error(ArgumentError, "encoding specified twice")
+ }.should.raise(ArgumentError, "encoding specified twice")
end
it "writes the file with the permissions in the :perm parameter" do
@@ -220,7 +227,7 @@ describe "IO.write" do
end
end
- ruby_version_is "3.3" do
+ ruby_version_is ""..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
-> {
diff --git a/spec/ruby/core/kernel/Array_spec.rb b/spec/ruby/core/kernel/Array_spec.rb
index b4a8bb7599..063faf7097 100644
--- a/spec/ruby/core/kernel/Array_spec.rb
+++ b/spec/ruby/core/kernel/Array_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel" do
it "has private instance method Array()" do
- Kernel.should have_private_instance_method(:Array)
+ Kernel.private_instance_methods(false).should.include?(:Array)
end
end
@@ -77,14 +77,14 @@ describe :kernel_Array, shared: true do
obj = mock("Array() string")
obj.should_receive(:to_ary).and_return("string")
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_a does not return an Array" do
obj = mock("Array() string")
obj.should_receive(:to_a).and_return("string")
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index 346d50ab5e..92ce183cc8 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -19,19 +19,19 @@ describe "Kernel.Complex()" do
describe "when passed [Integer, Integer]" do
it "returns a new Complex number" do
- Complex(1, 2).should be_an_instance_of(Complex)
+ Complex(1, 2).should.instance_of?(Complex)
Complex(1, 2).real.should == 1
Complex(1, 2).imag.should == 2
- Complex(-3, -5).should be_an_instance_of(Complex)
+ Complex(-3, -5).should.instance_of?(Complex)
Complex(-3, -5).real.should == -3
Complex(-3, -5).imag.should == -5
- Complex(3.5, -4.5).should be_an_instance_of(Complex)
+ Complex(3.5, -4.5).should.instance_of?(Complex)
Complex(3.5, -4.5).real.should == 3.5
Complex(3.5, -4.5).imag.should == -4.5
- Complex(bignum_value, 30).should be_an_instance_of(Complex)
+ Complex(bignum_value, 30).should.instance_of?(Complex)
Complex(bignum_value, 30).real.should == bignum_value
Complex(bignum_value, 30).imag.should == 30
end
@@ -41,19 +41,19 @@ describe "Kernel.Complex()" do
it "returns a new Complex number with 0 as the imaginary component" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
- Complex(1).should be_an_instance_of(Complex)
+ Complex(1).should.instance_of?(Complex)
Complex(1).imag.should == 0
Complex(1).real.should == 1
- Complex(-3).should be_an_instance_of(Complex)
+ Complex(-3).should.instance_of?(Complex)
Complex(-3).imag.should == 0
Complex(-3).real.should == -3
- Complex(-4.5).should be_an_instance_of(Complex)
+ Complex(-4.5).should.instance_of?(Complex)
Complex(-4.5).imag.should == 0
Complex(-4.5).real.should == -4.5
- Complex(bignum_value).should be_an_instance_of(Complex)
+ Complex(bignum_value).should.instance_of?(Complex)
Complex(bignum_value).imag.should == 0
Complex(bignum_value).real.should == bignum_value
end
@@ -67,47 +67,47 @@ describe "Kernel.Complex()" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
-> {
Complex("79+4i".encode("UTF-16"))
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
it "raises ArgumentError for unrecognised Strings" do
-> {
Complex("ruby")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "ruby"')
end
it "raises ArgumentError for trailing garbage" do
-> {
Complex("79+4iruby")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "79+4iruby"')
end
it "does not understand Float::INFINITY" do
-> {
Complex("Infinity")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "Infinity"')
-> {
Complex("-Infinity")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "-Infinity"')
end
it "does not understand Float::NAN" do
-> {
Complex("NaN")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "NaN"')
end
it "does not understand a sequence of _" do
-> {
Complex("7__9+4__0i")
- }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
+ }.should.raise(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
end
it "does not allow null-byte" do
-> {
Complex("1-2i\0")
- }.should raise_error(ArgumentError, "string contains null byte")
+ }.should.raise(ArgumentError, "string contains null byte")
end
end
@@ -115,7 +115,7 @@ describe "Kernel.Complex()" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
-> {
Complex("79+4i".encode("UTF-16"), exception: false)
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
it "returns nil for unrecognised Strings" do
@@ -160,7 +160,7 @@ describe "Kernel.Complex()" do
it "returns the passed argument" do
n = mock_numeric("unreal")
n.should_receive(:real?).any_number_of_times.and_return(false)
- Complex(n).should equal(n)
+ Complex(n).should.equal?(n)
end
end
@@ -169,8 +169,8 @@ describe "Kernel.Complex()" do
n = mock_numeric("real")
n.should_receive(:real?).any_number_of_times.and_return(true)
result = Complex(n)
- result.real.should equal(n)
- result.imag.should equal(0)
+ result.real.should.equal?(n)
+ result.imag.should.equal?(0)
end
end
@@ -185,7 +185,7 @@ describe "Kernel.Complex()" do
n2.should_receive(:real?).any_number_of_times.and_return(r2)
n2.should_receive(:*).with(Complex(0, 1)).and_return(n3)
n1.should_receive(:+).with(n3).and_return(n4)
- Complex(n1, n2).should equal(n4)
+ Complex(n1, n2).should.equal?(n4)
end
end
end
@@ -197,8 +197,8 @@ describe "Kernel.Complex()" do
n1.should_receive(:real?).any_number_of_times.and_return(true)
n2.should_receive(:real?).any_number_of_times.and_return(true)
result = Complex(n1, n2)
- result.real.should equal(n1)
- result.imag.should equal(n2)
+ result.real.should.equal?(n1)
+ result.imag.should.equal?(n2)
end
end
@@ -207,22 +207,22 @@ describe "Kernel.Complex()" do
n = mock("n")
c = Complex(0, 0)
n.should_receive(:to_c).and_return(c)
- Complex(n).should equal(c)
+ Complex(n).should.equal?(c)
end
end
describe "when passed a non-Numeric second argument" do
it "raises TypeError" do
- -> { Complex(:sym, :sym) }.should raise_error(TypeError)
- -> { Complex(0, :sym) }.should raise_error(TypeError)
+ -> { Complex(:sym, :sym) }.should.raise(TypeError)
+ -> { Complex(0, :sym) }.should.raise(TypeError)
end
end
describe "when passed nil" do
it "raises TypeError" do
- -> { Complex(nil) }.should raise_error(TypeError, "can't convert nil into Complex")
- -> { Complex(0, nil) }.should raise_error(TypeError, "can't convert nil into Complex")
- -> { Complex(nil, 0) }.should raise_error(TypeError, "can't convert nil into Complex")
+ -> { Complex(nil) }.should.raise(TypeError, "can't convert nil into Complex")
+ -> { Complex(0, nil) }.should.raise(TypeError, "can't convert nil into Complex")
+ -> { Complex(nil, 0) }.should.raise(TypeError, "can't convert nil into Complex")
end
end
@@ -241,7 +241,7 @@ describe "Kernel.Complex()" do
describe "and [non-Numeric, Numeric] argument" do
it "throws a TypeError" do
- -> { Complex(:sym, 0, exception: false) }.should raise_error(TypeError, "not a real")
+ -> { Complex(:sym, 0, exception: false) }.should.raise(TypeError, "not a real")
end
end
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index 6cedfe0617..f5566067ba 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -6,7 +6,7 @@ describe :kernel_float, shared: true do
float = 1.12
float2 = @object.send(:Float, float)
float2.should == float
- float2.should equal float
+ float2.should.equal? float
end
it "returns a Float for Fixnums" do
@@ -22,22 +22,22 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for nil" do
- -> { @object.send(:Float, nil) }.should raise_error(TypeError)
+ -> { @object.send(:Float, nil) }.should.raise(TypeError)
end
it "returns the identical NaN for NaN" do
nan = nan_value
- nan.nan?.should be_true
+ nan.nan?.should == true
nan2 = @object.send(:Float, nan)
- nan2.nan?.should be_true
- nan2.should equal(nan)
+ nan2.nan?.should == true
+ nan2.should.equal?(nan)
end
it "returns the same Infinity for Infinity" do
infinity = infinity_value
infinity2 = @object.send(:Float, infinity)
infinity2.should == infinity_value
- infinity.should equal(infinity2)
+ infinity.should.equal?(infinity2)
end
it "converts Strings to floats without calling #to_f" do
@@ -51,30 +51,30 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for a String of word characters" do
- -> { @object.send(:Float, "float") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "float") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with string in error message" do
- -> { @object.send(:Float, "foo") }.should raise_error(ArgumentError) { |e|
+ -> { @object.send(:Float, "foo") }.should.raise(ArgumentError) { |e|
e.message.should == 'invalid value for Float(): "foo"'
}
end
it "raises an ArgumentError if there are two decimal points in the String" do
- -> { @object.send(:Float, "10.0.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10.0.0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String of numbers followed by word characters" do
- -> { @object.send(:Float, "10D") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10D") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String of word characters followed by numbers" do
- -> { @object.send(:Float, "D10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "D10") }.should.raise(ArgumentError)
end
it "is strict about the string form even across newlines" do
- -> { @object.send(:Float, "not a number\n10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "10\nnot a number") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "not a number\n10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "10\nnot a number") }.should.raise(ArgumentError)
end
it "converts String subclasses to floats without calling #to_f" do
@@ -96,17 +96,17 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if a + or - is embedded in a String" do
- -> { @object.send(:Float, "1+1") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "1-1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1+1") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "1-1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if a String has a trailing + or -" do
- -> { @object.send(:Float, "11+") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "11-") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "11+") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "11-") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with a leading _" do
- -> { @object.send(:Float, "_1") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "_1") }.should.raise(ArgumentError)
end
it "returns a value for a String with an embedded _" do
@@ -114,31 +114,31 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError for a String with a trailing _" do
- -> { @object.send(:Float, "10_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "10_") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String of \\0" do
- -> { @object.send(:Float, "\0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with a leading \\0" do
- -> { @object.send(:Float, "\01") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "\01") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with an embedded \\0" do
- -> { @object.send(:Float, "1\01") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1\01") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String with a trailing \\0" do
- -> { @object.send(:Float, "1\0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String that is just an empty space" do
- -> { @object.send(:Float, " ") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, " ") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a String that with an embedded space" do
- -> { @object.send(:Float, "1 2") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1 2") }.should.raise(ArgumentError)
end
it "returns a value for a String with a leading space" do
@@ -159,10 +159,11 @@ describe :kernel_float, shared: true do
ruby_version_is ""..."3.4" do
it "raises ArgumentError if a fractional part is missing" do
- -> { @object.send(:Float, "1.") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "+1.") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "-1.") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "1.e+0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1.") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "+1.") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "-1.") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "1.e+0") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "1.e-2") }.should.raise(ArgumentError)
end
end
@@ -172,16 +173,17 @@ describe :kernel_float, shared: true do
@object.send(:Float, "+1.").should == 1.0
@object.send(:Float, "-1.").should == -1.0
@object.send(:Float, "1.e+0").should == 1.0
+ @object.send(:Float, "1.e-2").should be_close(0.01, TOLERANCE)
end
end
%w(e E).each do |e|
it "raises an ArgumentError if #{e} is the trailing character" do
- -> { @object.send(:Float, "2#{e}") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "2#{e}") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if #{e} is the leading character" do
- -> { @object.send(:Float, "#{e}2") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "#{e}2") }.should.raise(ArgumentError)
end
it "returns Infinity for '2#{e}1000'" do
@@ -199,18 +201,18 @@ describe :kernel_float, shared: true do
end
it "raises an exception if a space is embedded on either side of the '#{e}'" do
- -> { @object.send(:Float, "2 0#{e}100") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "20#{e}1 00") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "2 0#{e}100") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "20#{e}1 00") }.should.raise(ArgumentError)
end
it "raises an exception if there's a leading _ on either side of the '#{e}'" do
- -> { @object.send(:Float, "_20#{e}100") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "20#{e}_100") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "_20#{e}100") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "20#{e}_100") }.should.raise(ArgumentError)
end
it "raises an exception if there's a trailing _ on either side of the '#{e}'" do
- -> { @object.send(:Float, "20_#{e}100") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "20#{e}100_") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20_#{e}100") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "20#{e}100_") }.should.raise(ArgumentError)
end
it "allows decimal points on the left side of the '#{e}'" do
@@ -218,63 +220,111 @@ describe :kernel_float, shared: true do
end
it "raises an ArgumentError if there's a decimal point on the right side of the '#{e}'" do
- -> { @object.send(:Float, "20#{e}2.0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "20#{e}2.0") }.should.raise(ArgumentError)
end
end
- describe "for hexadecimal literals with binary exponent" do
- %w(p P).each do |p|
- it "interprets the fractional part (on the left side of '#{p}') in hexadecimal" do
- @object.send(:Float, "0x10#{p}0").should == 16.0
- end
-
- it "interprets the exponent (on the right of '#{p}') in decimal" do
- @object.send(:Float, "0x1#{p}10").should == 1024.0
- end
-
- it "raises an ArgumentError if #{p} is the trailing character" do
- -> { @object.send(:Float, "0x1#{p}") }.should raise_error(ArgumentError)
- end
-
- it "raises an ArgumentError if #{p} is the leading character" do
- -> { @object.send(:Float, "0x#{p}1") }.should raise_error(ArgumentError)
- end
+ context "for hexadecimal literals" do
+ it "interprets the 0x prefix as hexadecimal" do
+ @object.send(:Float, "0x10").should == 16.0
+ @object.send(:Float, "0x0F").should == 15.0
+ @object.send(:Float, "0x0f").should == 15.0
+ end
- it "returns Infinity for '0x1#{p}10000'" do
- @object.send(:Float, "0x1#{p}10000").should == Float::INFINITY
- end
+ it "interprets negative hex value" do
+ @object.send(:Float, "-0x10").should == -16.0
+ end
- it "returns 0 for '0x1#{p}-10000'" do
- @object.send(:Float, "0x1#{p}-10000").should == 0
- end
+ it "accepts embedded _ if the number does not contain a-f" do
+ @object.send(:Float, "0x1_0").should == 16.0
+ end
- it "allows embedded _ in a number on either side of the #{p}" do
- @object.send(:Float, "0x1_0#{p}10").should == 16384.0
- @object.send(:Float, "0x10#{p}1_0").should == 16384.0
- @object.send(:Float, "0x1_0#{p}1_0").should == 16384.0
+ ruby_version_is ""..."3.4.3" do
+ it "does not accept embedded _ if the number contains a-f" do
+ -> { @object.send(:Float, "0x1_0a") }.should.raise(ArgumentError)
+ @object.send(:Float, "0x1_0a", exception: false).should == nil
end
+ end
- it "raises an exception if a space is embedded on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x1 0#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}1 0") }.should raise_error(ArgumentError)
+ ruby_version_is "3.4.3" do
+ it "accepts embedded _ if the number contains a-f" do
+ @object.send(:Float, "0x1_0a").should == 0x10a.to_f
end
+ end
- it "raises an exception if there's a leading _ on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x_10#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}_10") }.should raise_error(ArgumentError)
- end
+ it "does not accept _ before, after or inside the 0x prefix" do
+ -> { @object.send(:Float, "_0x10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0_x10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x_10") }.should.raise(ArgumentError)
+ @object.send(:Float, "_0x10", exception: false).should == nil
+ @object.send(:Float, "0_x10", exception: false).should == nil
+ @object.send(:Float, "0x_10", exception: false).should == nil
+ end
- it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x10_#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}10_") }.should raise_error(ArgumentError)
- end
+ it "parses negative hexadecimal string as negative float" do
+ @object.send(:Float, "-0x7b").should == -123.0
+ end
- it "allows hexadecimal points on the left side of the '#{p}'" do
- @object.send(:Float, "0x1.8#{p}0").should == 1.5
+ ruby_version_is "3.4" do
+ it "accepts a fractional part" do
+ @object.send(:Float, "0x0.8").should == 0.5
end
+ end
- it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
- -> { @object.send(:Float, "0x1#{p}1.0") }.should raise_error(ArgumentError)
+ describe "with binary exponent" do
+ %w(p P).each do |p|
+ it "interprets the fractional part (on the left side of '#{p}') in hexadecimal" do
+ @object.send(:Float, "0x10#{p}0").should == 16.0
+ end
+
+ it "interprets the exponent (on the right of '#{p}') in decimal" do
+ @object.send(:Float, "0x1#{p}10").should == 1024.0
+ end
+
+ it "raises an ArgumentError if #{p} is the trailing character" do
+ -> { @object.send(:Float, "0x1#{p}") }.should.raise(ArgumentError)
+ end
+
+ it "raises an ArgumentError if #{p} is the leading character" do
+ -> { @object.send(:Float, "0x#{p}1") }.should.raise(ArgumentError)
+ end
+
+ it "returns Infinity for '0x1#{p}10000'" do
+ @object.send(:Float, "0x1#{p}10000").should == Float::INFINITY
+ end
+
+ it "returns 0 for '0x1#{p}-10000'" do
+ @object.send(:Float, "0x1#{p}-10000").should == 0
+ end
+
+ it "allows embedded _ in a number on either side of the #{p}" do
+ @object.send(:Float, "0x1_0#{p}10").should == 16384.0
+ @object.send(:Float, "0x10#{p}1_0").should == 16384.0
+ @object.send(:Float, "0x1_0#{p}1_0").should == 16384.0
+ end
+
+ it "raises an exception if a space is embedded on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x1 0#{p}10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}1 0") }.should.raise(ArgumentError)
+ end
+
+ it "raises an exception if there's a leading _ on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x_10#{p}10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}_10") }.should.raise(ArgumentError)
+ end
+
+ it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x10_#{p}10") }.should.raise(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}10_") }.should.raise(ArgumentError)
+ end
+
+ it "allows hexadecimal points on the left side of the '#{p}'" do
+ @object.send(:Float, "0x1.8#{p}0").should == 1.5
+ end
+
+ it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
+ -> { @object.send(:Float, "0x1#{p}1.0") }.should.raise(ArgumentError)
+ end
end
end
end
@@ -294,34 +344,34 @@ describe :kernel_float, shared: true do
nan = nan_value
(nan_to_f = mock('NaN')).should_receive(:to_f).once.and_return(nan)
nan2 = @object.send(:Float, nan_to_f)
- nan2.nan?.should be_true
- nan2.should equal(nan)
+ nan2.nan?.should == true
+ nan2.should.equal?(nan)
end
it "returns the identical Infinity if #to_f is called and it returns Infinity" do
infinity = infinity_value
(infinity_to_f = mock('Infinity')).should_receive(:to_f).once.and_return(infinity)
infinity2 = @object.send(:Float, infinity_to_f)
- infinity2.should equal(infinity)
+ infinity2.should.equal?(infinity)
end
it "raises a TypeError if #to_f is not provided" do
- -> { @object.send(:Float, mock('x')) }.should raise_error(TypeError)
+ -> { @object.send(:Float, mock('x')) }.should.raise(TypeError)
end
it "raises a TypeError if #to_f returns a String" do
(obj = mock('ha!')).should_receive(:to_f).once.and_return('ha!')
- -> { @object.send(:Float, obj) }.should raise_error(TypeError)
+ -> { @object.send(:Float, obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_f returns an Integer" do
(obj = mock('123')).should_receive(:to_f).once.and_return(123)
- -> { @object.send(:Float, obj) }.should raise_error(TypeError)
+ -> { @object.send(:Float, obj) }.should.raise(TypeError)
end
it "raises a RangeError when passed a Complex argument" do
c = Complex(2, 3)
- -> { @object.send(:Float, c) }.should raise_error(RangeError)
+ -> { @object.send(:Float, c) }.should.raise(RangeError)
end
describe "when passed exception: false" do
@@ -358,6 +408,6 @@ end
describe "Kernel#Float" do
it "is a private method" do
- Kernel.should have_private_instance_method(:Float)
+ Kernel.private_instance_methods(false).should.include?(:Float)
end
end
diff --git a/spec/ruby/core/kernel/Hash_spec.rb b/spec/ruby/core/kernel/Hash_spec.rb
index cbe098a8ac..ee16f56a90 100644
--- a/spec/ruby/core/kernel/Hash_spec.rb
+++ b/spec/ruby/core/kernel/Hash_spec.rb
@@ -13,7 +13,7 @@ end
describe "Kernel" do
it "has private instance method Hash()" do
- Kernel.should have_private_instance_method(:Hash)
+ Kernel.private_instance_methods(false).should.include?(:Hash)
end
end
@@ -43,14 +43,14 @@ describe :kernel_Hash, shared: true do
end
it "raises a TypeError if it doesn't respond to #to_hash" do
- -> { @object.send(@method, mock("")) }.should raise_error(TypeError)
+ -> { @object.send(@method, mock("")) }.should.raise(TypeError)
end
it "raises a TypeError if #to_hash does not return an Hash" do
obj = mock("Hash() string")
obj.should_receive(:to_hash).and_return("string")
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 74dd3e0dd2..978fd8ef08 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -14,7 +14,9 @@ describe :kernel_integer, shared: true do
obj = mock("object")
obj.should_receive(:to_int).and_return("1")
obj.should_receive(:to_i).and_return(nil)
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_i gives nil)")
end
it "return a result of to_i when to_int does not return an Integer" do
@@ -24,13 +26,36 @@ describe :kernel_integer, shared: true do
Integer(obj).should == 42
end
+ it "returns a result of to_str" do
+ obj = mock("obj")
+ obj.should_receive(:to_str).and_return("1")
+
+ Integer(obj).should == 1
+ end
+
+ it "returns a result of to_int when both to_int and to_str are defined" do
+ obj = mock("obj")
+ obj.should_receive(:to_int).and_return(1)
+ obj.should_not_receive(:to_str)
+
+ Integer(obj).should == 1
+ end
+
+ it "returns a result of to_str when both to_str and to_i are defined" do
+ obj = mock("obj")
+ obj.should_receive(:to_str).and_return("1")
+ obj.should_not_receive(:to_i)
+
+ Integer(obj).should == 1
+ end
+
it "raises a TypeError when passed nil" do
- -> { Integer(nil) }.should raise_error(TypeError)
+ -> { Integer(nil) }.should.raise(TypeError, "can't convert nil into Integer")
end
it "returns an Integer object" do
- Integer(2).should be_an_instance_of(Integer)
- Integer(9**99).should be_an_instance_of(Integer)
+ Integer(2).should.instance_of?(Integer)
+ Integer(9**99).should.instance_of?(Integer)
end
it "truncates Floats" do
@@ -67,26 +92,32 @@ describe :kernel_integer, shared: true do
it "raises a TypeError if to_i returns a value that is not an Integer" do
obj = mock("object")
obj.should_receive(:to_i).and_return("1")
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_i gives String)")
end
it "raises a TypeError if no to_int or to_i methods exist" do
obj = mock("object")
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should.raise(TypeError, "can't convert MockObject into Integer")
end
it "raises a TypeError if to_int returns nil and no to_i exists" do
obj = mock("object")
obj.should_receive(:to_i).and_return(nil)
- -> { Integer(obj) }.should raise_error(TypeError)
+ -> {
+ Integer(obj)
+ }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_i gives nil)")
end
it "raises a FloatDomainError when passed NaN" do
- -> { Integer(nan_value) }.should raise_error(FloatDomainError)
+ -> { Integer(nan_value) }.should.raise(FloatDomainError)
end
it "raises a FloatDomainError when passed Infinity" do
- -> { Integer(infinity_value) }.should raise_error(FloatDomainError)
+ -> { Integer(infinity_value) }.should.raise(FloatDomainError)
end
describe "when passed exception: false" do
@@ -147,19 +178,19 @@ end
describe :kernel_integer_string, shared: true do
it "raises an ArgumentError if the String is a null byte" do
- -> { Integer("\0") }.should raise_error(ArgumentError)
+ -> { Integer("\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String starts with a null byte" do
- -> { Integer("\01") }.should raise_error(ArgumentError)
+ -> { Integer("\01") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String ends with a null byte" do
- -> { Integer("1\0") }.should raise_error(ArgumentError)
+ -> { Integer("1\0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String contains a null byte" do
- -> { Integer("1\01") }.should raise_error(ArgumentError)
+ -> { Integer("1\01") }.should.raise(ArgumentError)
end
it "ignores leading whitespace" do
@@ -175,13 +206,13 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there are leading _s" do
- -> { Integer("_1") }.should raise_error(ArgumentError)
- -> { Integer("___1") }.should raise_error(ArgumentError)
+ -> { Integer("_1") }.should.raise(ArgumentError)
+ -> { Integer("___1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing _s" do
- -> { Integer("1_") }.should raise_error(ArgumentError)
- -> { Integer("1___") }.should raise_error(ArgumentError)
+ -> { Integer("1_") }.should.raise(ArgumentError)
+ -> { Integer("1___") }.should.raise(ArgumentError)
end
it "ignores an embedded _" do
@@ -189,8 +220,8 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there are multiple embedded _s" do
- -> { Integer("1__1") }.should raise_error(ArgumentError)
- -> { Integer("1___1") }.should raise_error(ArgumentError)
+ -> { Integer("1__1") }.should.raise(ArgumentError)
+ -> { Integer("1___1") }.should.raise(ArgumentError)
end
it "ignores a single leading +" do
@@ -198,17 +229,17 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there is a space between the + and number" do
- -> { Integer("+ 1") }.should raise_error(ArgumentError)
+ -> { Integer("+ 1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are multiple leading +s" do
- -> { Integer("++1") }.should raise_error(ArgumentError)
- -> { Integer("+++1") }.should raise_error(ArgumentError)
+ -> { Integer("++1") }.should.raise(ArgumentError)
+ -> { Integer("+++1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing +s" do
- -> { Integer("1+") }.should raise_error(ArgumentError)
- -> { Integer("1+++") }.should raise_error(ArgumentError)
+ -> { Integer("1+") }.should.raise(ArgumentError)
+ -> { Integer("1+++") }.should.raise(ArgumentError)
end
it "makes the number negative if there's a leading -" do
@@ -216,21 +247,21 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if there are multiple leading -s" do
- -> { Integer("--1") }.should raise_error(ArgumentError)
- -> { Integer("---1") }.should raise_error(ArgumentError)
+ -> { Integer("--1") }.should.raise(ArgumentError)
+ -> { Integer("---1") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing -s" do
- -> { Integer("1-") }.should raise_error(ArgumentError)
- -> { Integer("1---") }.should raise_error(ArgumentError)
+ -> { Integer("1-") }.should.raise(ArgumentError)
+ -> { Integer("1---") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there is a period" do
- -> { Integer("0.0") }.should raise_error(ArgumentError)
+ -> { Integer("0.0") }.should.raise(ArgumentError)
end
it "raises an ArgumentError for an empty String" do
- -> { Integer("") }.should raise_error(ArgumentError)
+ -> { Integer("") }.should.raise(ArgumentError)
end
describe "when passed exception: false" do
@@ -280,7 +311,7 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as hex" do
- -> { Integer("0#{x}g") }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}g") }.should.raise(ArgumentError)
end
end
@@ -301,7 +332,7 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as binary" do
- -> { Integer("0#{b}2") }.should raise_error(ArgumentError)
+ -> { Integer("0#{b}2") }.should.raise(ArgumentError)
end
end
@@ -322,7 +353,7 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as octal" do
- -> { Integer("0#{o}9") }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}9") }.should.raise(ArgumentError)
end
end
@@ -343,26 +374,26 @@ describe :kernel_integer_string, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as decimal" do
- -> { Integer("0#{d}a") }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}a") }.should.raise(ArgumentError)
end
end
end
describe :kernel_integer_string_base, shared: true do
it "raises an ArgumentError if the String is a null byte" do
- -> { Integer("\0", 2) }.should raise_error(ArgumentError)
+ -> { Integer("\0", 2) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String starts with a null byte" do
- -> { Integer("\01", 3) }.should raise_error(ArgumentError)
+ -> { Integer("\01", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String ends with a null byte" do
- -> { Integer("1\0", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1\0", 4) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the String contains a null byte" do
- -> { Integer("1\01", 5) }.should raise_error(ArgumentError)
+ -> { Integer("1\01", 5) }.should.raise(ArgumentError)
end
it "ignores leading whitespace" do
@@ -378,13 +409,13 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there are leading _s" do
- -> { Integer("_1", 7) }.should raise_error(ArgumentError)
- -> { Integer("___1", 7) }.should raise_error(ArgumentError)
+ -> { Integer("_1", 7) }.should.raise(ArgumentError)
+ -> { Integer("___1", 7) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing _s" do
- -> { Integer("1_", 12) }.should raise_error(ArgumentError)
- -> { Integer("1___", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1_", 12) }.should.raise(ArgumentError)
+ -> { Integer("1___", 12) }.should.raise(ArgumentError)
end
it "ignores an embedded _" do
@@ -392,8 +423,8 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there are multiple embedded _s" do
- -> { Integer("1__1", 4) }.should raise_error(ArgumentError)
- -> { Integer("1___1", 4) }.should raise_error(ArgumentError)
+ -> { Integer("1__1", 4) }.should.raise(ArgumentError)
+ -> { Integer("1___1", 4) }.should.raise(ArgumentError)
end
it "ignores a single leading +" do
@@ -401,17 +432,17 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there is a space between the + and number" do
- -> { Integer("+ 1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("+ 1", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are multiple leading +s" do
- -> { Integer("++1", 3) }.should raise_error(ArgumentError)
- -> { Integer("+++1", 3) }.should raise_error(ArgumentError)
+ -> { Integer("++1", 3) }.should.raise(ArgumentError)
+ -> { Integer("+++1", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing +s" do
- -> { Integer("1+", 3) }.should raise_error(ArgumentError)
- -> { Integer("1+++", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1+", 3) }.should.raise(ArgumentError)
+ -> { Integer("1+++", 12) }.should.raise(ArgumentError)
end
it "makes the number negative if there's a leading -" do
@@ -419,29 +450,29 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if there are multiple leading -s" do
- -> { Integer("--1", 9) }.should raise_error(ArgumentError)
- -> { Integer("---1", 9) }.should raise_error(ArgumentError)
+ -> { Integer("--1", 9) }.should.raise(ArgumentError)
+ -> { Integer("---1", 9) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there are trailing -s" do
- -> { Integer("1-", 12) }.should raise_error(ArgumentError)
- -> { Integer("1---", 12) }.should raise_error(ArgumentError)
+ -> { Integer("1-", 12) }.should.raise(ArgumentError)
+ -> { Integer("1---", 12) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if there is a period" do
- -> { Integer("0.0", 3) }.should raise_error(ArgumentError)
+ -> { Integer("0.0", 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError for an empty String" do
- -> { Integer("", 12) }.should raise_error(ArgumentError)
+ -> { Integer("", 12) }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a base of 1" do
- -> { Integer("1", 1) }.should raise_error(ArgumentError)
+ -> { Integer("1", 1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError for a base of 37" do
- -> { Integer("1", 37) }.should raise_error(ArgumentError)
+ -> { Integer("1", 37) }.should.raise(ArgumentError)
end
it "accepts wholly lowercase alphabetic strings for bases > 10" do
@@ -469,8 +500,8 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError for letters invalid in the given base" do
- -> { Integer('z',19) }.should raise_error(ArgumentError)
- -> { Integer('c00o',2) }.should raise_error(ArgumentError)
+ -> { Integer('z',19) }.should.raise(ArgumentError)
+ -> { Integer('c00o',2) }.should.raise(ArgumentError)
end
%w(x X).each do |x|
@@ -491,12 +522,12 @@ describe :kernel_integer_string_base, shared: true do
2.upto(15) do |base|
it "raises an ArgumentError if the number begins with 0#{x} and the base is #{base}" do
- -> { Integer("0#{x}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}1", base) }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError if the number cannot be parsed as hex and the base is 16" do
- -> { Integer("0#{x}g", 16) }.should raise_error(ArgumentError)
+ -> { Integer("0#{x}g", 16) }.should.raise(ArgumentError)
end
end
@@ -517,7 +548,7 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as binary and the base is 2" do
- -> { Integer("0#{b}2", 2) }.should raise_error(ArgumentError)
+ -> { Integer("0#{b}2", 2) }.should.raise(ArgumentError)
end
end
@@ -538,12 +569,12 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as octal and the base is 8" do
- -> { Integer("0#{o}9", 8) }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}9", 8) }.should.raise(ArgumentError)
end
2.upto(7) do |base|
it "raises an ArgumentError if the number begins with 0#{o} and the base is #{base}" do
- -> { Integer("0#{o}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{o}1", base) }.should.raise(ArgumentError)
end
end
end
@@ -565,18 +596,18 @@ describe :kernel_integer_string_base, shared: true do
end
it "raises an ArgumentError if the number cannot be parsed as decimal and the base is 10" do
- -> { Integer("0#{d}a", 10) }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}a", 10) }.should.raise(ArgumentError)
end
2.upto(9) do |base|
it "raises an ArgumentError if the number begins with 0#{d} and the base is #{base}" do
- -> { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
+ -> { Integer("0#{d}1", base) }.should.raise(ArgumentError)
end
end
end
it "raises an ArgumentError if a base is given for a non-String value" do
- -> { Integer(98, 15) }.should raise_error(ArgumentError)
+ -> { Integer(98, 15) }.should.raise(ArgumentError, "base specified for non string value")
end
it "tries to convert the base to an integer using to_int" do
@@ -586,19 +617,10 @@ describe :kernel_integer_string_base, shared: true do
Integer("777", obj).should == 0777
end
- # https://bugs.ruby-lang.org/issues/19349
- ruby_version_is ''...'3.3' do
- it "ignores the base if it is not an integer and does not respond to #to_i" do
- Integer("777", "8").should == 777
- end
- end
-
- ruby_version_is '3.3' do
- it "raises a TypeError if it is not an integer and does not respond to #to_i" do
- -> {
- Integer("777", "8")
- }.should raise_error(TypeError, "no implicit conversion of String into Integer")
- end
+ it "raises a TypeError if it is not an integer and does not respond to #to_i" do
+ -> {
+ Integer("777", "8")
+ }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
describe "when passed exception: false" do
@@ -621,176 +643,176 @@ end
describe :kernel_Integer, shared: true do
it "raises an ArgumentError when the String contains digits out of range of radix 2" do
str = "23456789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 2) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 2) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 3" do
str = "3456789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 3) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 3) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 4" do
str = "456789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 4) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 4) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 5" do
str = "56789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 5) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 5) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 6" do
str = "6789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 6) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 6) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 7" do
str = "789abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 7) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 7) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 8" do
str = "89abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 8) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 8) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 9" do
str = "9abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 9) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 9) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 10" do
str = "abcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 10) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 10) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 11" do
str = "bcdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 11) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 11) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 12" do
str = "cdefghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 12) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 12) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 13" do
str = "defghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 13) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 13) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 14" do
str = "efghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 14) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 14) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 15" do
str = "fghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 15) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 15) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 16" do
str = "ghijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 16) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 16) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 17" do
str = "hijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 17) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 17) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 18" do
str = "ijklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 18) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 18) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 19" do
str = "jklmnopqrstuvwxyz"
- -> { @object.send(@method, str, 19) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 19) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 20" do
str = "klmnopqrstuvwxyz"
- -> { @object.send(@method, str, 20) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 20) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 21" do
str = "lmnopqrstuvwxyz"
- -> { @object.send(@method, str, 21) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 21) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 22" do
str = "mnopqrstuvwxyz"
- -> { @object.send(@method, str, 22) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 22) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 23" do
str = "nopqrstuvwxyz"
- -> { @object.send(@method, str, 23) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 23) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 24" do
str = "opqrstuvwxyz"
- -> { @object.send(@method, str, 24) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 24) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 25" do
str = "pqrstuvwxyz"
- -> { @object.send(@method, str, 25) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 25) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 26" do
str = "qrstuvwxyz"
- -> { @object.send(@method, str, 26) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 26) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 27" do
str = "rstuvwxyz"
- -> { @object.send(@method, str, 27) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 27) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 28" do
str = "stuvwxyz"
- -> { @object.send(@method, str, 28) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 28) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 29" do
str = "tuvwxyz"
- -> { @object.send(@method, str, 29) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 29) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 30" do
str = "uvwxyz"
- -> { @object.send(@method, str, 30) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 30) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 31" do
str = "vwxyz"
- -> { @object.send(@method, str, 31) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 31) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 32" do
str = "wxyz"
- -> { @object.send(@method, str, 32) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 32) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 33" do
str = "xyz"
- -> { @object.send(@method, str, 33) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 33) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 34" do
str = "yz"
- -> { @object.send(@method, str, 34) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 34) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 35" do
str = "z"
- -> { @object.send(@method, str, 35) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, str, 35) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the String contains digits out of range of radix 36" do
- -> { @object.send(@method, "{", 36) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, "{", 36) }.should.raise(ArgumentError)
end
end
@@ -818,6 +840,6 @@ describe "Kernel#Integer" do
it_behaves_like :kernel_integer_string_base, :Integer
it "is a private method" do
- Kernel.should have_private_instance_method(:Integer)
+ Kernel.private_instance_methods(false).should.include?(:Integer)
end
end
diff --git a/spec/ruby/core/kernel/Rational_spec.rb b/spec/ruby/core/kernel/Rational_spec.rb
index 841c8e8c64..b13ab4cf55 100644
--- a/spec/ruby/core/kernel/Rational_spec.rb
+++ b/spec/ruby/core/kernel/Rational_spec.rb
@@ -6,9 +6,9 @@ describe "Kernel.Rational" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns a new Rational number with 1 as the denominator" do
- Rational(1).should eql(Rational(1, 1))
- Rational(-3).should eql(Rational(-3, 1))
- Rational(bignum_value).should eql(Rational(bignum_value, 1))
+ Rational(1).should.eql?(Rational(1, 1))
+ Rational(-3).should.eql?(Rational(-3, 1))
+ Rational(bignum_value).should.eql?(Rational(bignum_value, 1))
end
end
end
@@ -18,17 +18,17 @@ describe "Kernel.Rational" do
rat = Rational(1, 2)
rat.numerator.should == 1
rat.denominator.should == 2
- rat.should be_an_instance_of(Rational)
+ rat.should.instance_of?(Rational)
rat = Rational(-3, -5)
rat.numerator.should == 3
rat.denominator.should == 5
- rat.should be_an_instance_of(Rational)
+ rat.should.instance_of?(Rational)
rat = Rational(bignum_value, 3)
rat.numerator.should == bignum_value
rat.denominator.should == 3
- rat.should be_an_instance_of(Rational)
+ rat.should.instance_of?(Rational)
end
it "reduces the Rational" do
@@ -76,34 +76,84 @@ describe "Kernel.Rational" do
end
describe "when passed a Complex" do
- it "returns a Rational from the real part if the imaginary part is 0" do
- Rational(Complex(1, 0)).should == Rational(1)
+ context "[Complex]" do
+ it "returns a Rational from the real part if the imaginary part is 0" do
+ Rational(Complex(1, 0)).should == Rational(1)
+ end
+
+ it "raises a RangeError if the imaginary part is not 0" do
+ -> { Rational(Complex(1, 2)) }.should.raise(RangeError, "can't convert 1+2i into Rational")
+ end
end
- it "raises a RangeError if the imaginary part is not 0" do
- -> { Rational(Complex(1, 2)) }.should raise_error(RangeError)
+ context "[Numeric, Complex]" do
+ it "uses the real part if the imaginary part is 0" do
+ Rational(1, Complex(2, 0)).should == Rational(1, 2)
+ end
+
+ it "divides a numerator by the Complex denominator if the imaginary part is not 0" do
+ Rational(1, Complex(2, 1)).should == Complex(2/5r, -1/5r)
+ end
+ end
+ end
+
+ context "when passed neither a Numeric nor a String" do
+ it "converts to Rational with #to_r method" do
+ obj = Object.new
+ def obj.to_r; 1/2r; end
+
+ Rational(obj).should == 1/2r
+ end
+
+ it "tries to convert to Integer with #to_int method if it does not respond to #to_r" do
+ obj = Object.new
+ def obj.to_int; 1; end
+
+ Rational(obj).should == 1r
+ end
+
+ it "raises TypeError if it neither responds to #to_r nor #to_int method" do
+ -> { Rational([]) }.should.raise(TypeError, "can't convert Array into Rational")
+ -> { Rational({}) }.should.raise(TypeError, "can't convert Hash into Rational")
+ -> { Rational(nil) }.should.raise(TypeError, "can't convert nil into Rational")
+ end
+
+ it "swallows exception raised in #to_int method" do
+ object = Object.new
+ def object.to_int() raise NoMethodError; end
+
+ -> { Rational(object) }.should.raise(TypeError)
+ -> { Rational(object, 1) }.should.raise(TypeError)
+ -> { Rational(1, object) }.should.raise(TypeError)
+ end
+
+ it "raises TypeError if #to_r does not return Rational" do
+ obj = Object.new
+ def obj.to_r; []; end
+
+ -> { Rational(obj) }.should raise_consistent_error(TypeError, "can't convert Object into Rational (Object#to_r gives Array)")
end
end
it "raises a ZeroDivisionError if the second argument is 0" do
- -> { Rational(1, 0) }.should raise_error(ZeroDivisionError, "divided by 0")
- -> { Rational(1, 0.0) }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(1, 0) }.should.raise(ZeroDivisionError, "divided by 0")
+ -> { Rational(1, 0.0) }.should.raise(ZeroDivisionError, "divided by 0")
end
it "raises a TypeError if the first argument is nil" do
- -> { Rational(nil) }.should raise_error(TypeError)
+ -> { Rational(nil) }.should.raise(TypeError, "can't convert nil into Rational")
end
it "raises a TypeError if the second argument is nil" do
- -> { Rational(1, nil) }.should raise_error(TypeError)
+ -> { Rational(1, nil) }.should.raise(TypeError, "can't convert nil into Rational")
end
it "raises a TypeError if the first argument is a Symbol" do
- -> { Rational(:sym) }.should raise_error(TypeError)
+ -> { Rational(:sym) }.should.raise(TypeError)
end
it "raises a TypeError if the second argument is a Symbol" do
- -> { Rational(1, :sym) }.should raise_error(TypeError)
+ -> { Rational(1, :sym) }.should.raise(TypeError)
end
describe "when passed exception: false" do
@@ -112,6 +162,18 @@ describe "Kernel.Rational" do
Rational(:sym, exception: false).should == nil
Rational("abc", exception: false).should == nil
end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, exception: false).should == nil
+ end
end
describe "and [non-Numeric, Numeric]" do
@@ -119,6 +181,18 @@ describe "Kernel.Rational" do
Rational(:sym, 1, exception: false).should == nil
Rational("abc", 1, exception: false).should == nil
end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
end
describe "and [anything, non-Numeric]" do
@@ -126,6 +200,18 @@ describe "Kernel.Rational" do
Rational(:sym, :sym, exception: false).should == nil
Rational("abc", :sym, exception: false).should == nil
end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
end
describe "and non-Numeric String arguments" do
diff --git a/spec/ruby/core/kernel/String_spec.rb b/spec/ruby/core/kernel/String_spec.rb
index 7caec6eda5..a9b0758ad7 100644
--- a/spec/ruby/core/kernel/String_spec.rb
+++ b/spec/ruby/core/kernel/String_spec.rb
@@ -32,7 +32,7 @@ describe :kernel_String, shared: true do
undef_method :to_s
end
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
# #5158
@@ -44,7 +44,7 @@ describe :kernel_String, shared: true do
end
end
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_s is not defined, even though #respond_to?(:to_s) returns true" do
@@ -57,7 +57,7 @@ describe :kernel_String, shared: true do
end
end
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "calls #to_s if #respond_to?(:to_s) returns true" do
@@ -74,14 +74,14 @@ describe :kernel_String, shared: true do
it "raises a TypeError if #to_s does not return a String" do
(obj = mock('123')).should_receive(:to_s).and_return(123)
- -> { @object.send(@method, obj) }.should raise_error(TypeError)
+ -> { @object.send(@method, obj) }.should.raise(TypeError)
end
it "returns the same object if it is already a String" do
string = +"Hello"
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
- string.should equal(string2)
+ string.should.equal?(string2)
end
it "returns the same object if it is an instance of a String subclass" do
@@ -89,7 +89,7 @@ describe :kernel_String, shared: true do
string = subklass.new("Hello")
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
- string.should equal(string2)
+ string.should.equal?(string2)
end
end
@@ -101,6 +101,6 @@ describe "Kernel#String" do
it_behaves_like :kernel_String, :String, Object.new
it "is a private method" do
- Kernel.should have_private_instance_method(:String)
+ Kernel.private_instance_methods(false).should.include?(:String)
end
end
diff --git a/spec/ruby/core/kernel/abort_spec.rb b/spec/ruby/core/kernel/abort_spec.rb
index f8152718c5..b75138182d 100644
--- a/spec/ruby/core/kernel/abort_spec.rb
+++ b/spec/ruby/core/kernel/abort_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/process/abort'
describe "Kernel#abort" do
it "is a private method" do
- Kernel.should have_private_instance_method(:abort)
+ Kernel.private_instance_methods(false).should.include?(:abort)
end
it_behaves_like :process_abort, :abort, KernelSpecs::Method.new
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index ebd9a71d15..fdb0eaf34c 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -6,11 +6,11 @@ describe "Kernel.at_exit" do
it_behaves_like :kernel_at_exit, :at_exit
it "is a private method" do
- Kernel.should have_private_instance_method(:at_exit)
+ Kernel.private_instance_methods(false).should.include?(:at_exit)
end
it "raises ArgumentError if called without a block" do
- -> { at_exit }.should raise_error(ArgumentError, "called without a block")
+ -> { at_exit }.should.raise(ArgumentError, "called without a block")
end
end
diff --git a/spec/ruby/core/kernel/autoload_relative_spec.rb b/spec/ruby/core/kernel/autoload_relative_spec.rb
new file mode 100644
index 0000000000..7d03da8a40
--- /dev/null
+++ b/spec/ruby/core/kernel/autoload_relative_spec.rb
@@ -0,0 +1,114 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+# Specs for Kernel#autoload_relative
+
+ruby_version_is "4.1" do
+ describe "Kernel#autoload_relative" do
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ # Clean up constants defined by these tests
+ [:KSAutoloadRelativeA, :KSAutoloadRelativeB, :KSAutoloadRelativeC,
+ :KSAutoloadRelativeE, :KSAutoloadRelativeF, :KSAutoloadRelativeG,
+ :KSAutoloadRelativeH, :KSAutoloadRelativeI].each do |const|
+ KernelSpecs.send(:remove_const, const) if KernelSpecs.const_defined?(const, false)
+ end
+ [:KSAutoloadRelativeD, :NestedTest].each do |const|
+ Object.send(:remove_const, const) if Object.const_defined?(const, false)
+ end
+ end
+
+ it "is a private method" do
+ Kernel.private_instance_methods(false).should.include?(:autoload_relative)
+ end
+
+ it "registers a file to load relative to the current file" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeA, "fixtures/autoload_relative_b.rb"
+ path = KernelSpecs.autoload?(:KSAutoloadRelativeA)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_b.rb")
+ File.exist?(path).should == true
+ end
+
+ it "loads the file when the constant is accessed" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeB, "fixtures/autoload_relative_b.rb"
+ KernelSpecs::KSAutoloadRelativeB.loaded.should == :ksautoload_b
+ end
+
+ it "sets the autoload constant in the constant table" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeC, "fixtures/autoload_relative_b.rb"
+ KernelSpecs.should.const_defined?(:KSAutoloadRelativeC, false)
+ end
+
+ it "can autoload in instance_eval with a file context" do
+ result = Object.new.instance_eval(<<-CODE, __FILE__, __LINE__)
+ autoload_relative :KSAutoloadRelativeD, "fixtures/autoload_relative_d.rb"
+ KSAutoloadRelativeD.loaded
+ CODE
+ result.should == :ksautoload_d
+ end
+
+ it "raises LoadError if called from eval without file context" do
+ -> {
+ eval('autoload_relative :Foo, "foo.rb"')
+ }.should.raise(LoadError, /autoload_relative called without file context/)
+ end
+
+ it "accepts both string and symbol for constant name" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeE, "fixtures/autoload_relative_b.rb"
+ KernelSpecs.autoload_relative "KSAutoloadRelativeF", "fixtures/autoload_relative_b.rb"
+
+ KernelSpecs.should.const_defined?(:KSAutoloadRelativeE, false)
+ KernelSpecs.should.const_defined?(:KSAutoloadRelativeF, false)
+ end
+
+ it "returns nil" do
+ KernelSpecs.autoload_relative(:KSAutoloadRelativeG, "fixtures/autoload_relative_b.rb").should == nil
+ end
+
+ it "resolves nested directory paths correctly" do
+ -> {
+ autoload_relative :NestedTest, "../kernel/fixtures/autoload_relative_b.rb"
+ autoload?(:NestedTest)
+ }.should_not.raise
+ end
+
+ it "resolves paths starting with ./" do
+ KernelSpecs.autoload_relative :KSAutoloadRelativeH, "./fixtures/autoload_relative_b.rb"
+ path = KernelSpecs.autoload?(:KSAutoloadRelativeH)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_b.rb")
+ end
+
+ it "ignores $LOAD_PATH and uses only relative path resolution" do
+ original_load_path = $LOAD_PATH.dup
+ $LOAD_PATH.clear
+ begin
+ KernelSpecs.autoload_relative :KSAutoloadRelativeI, "fixtures/autoload_relative_b.rb"
+ path = KernelSpecs.autoload?(:KSAutoloadRelativeI)
+ path.should_not == nil
+ # Should still resolve even with empty $LOAD_PATH
+ File.exist?(path).should == true
+ ensure
+ $LOAD_PATH.replace(original_load_path)
+ end
+ end
+
+ describe "when Object is frozen" do
+ it "raises a FrozenError before defining the constant" do
+ ruby_exe(<<-RUBY).should.include?("FrozenError")
+ Object.freeze
+ begin
+ autoload_relative :Foo, "autoload_b.rb"
+ rescue => e
+ puts e.class
+ end
+ RUBY
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/autoload_spec.rb b/spec/ruby/core/kernel/autoload_spec.rb
index 0404caec6d..46783734c4 100644
--- a/spec/ruby/core/kernel/autoload_spec.rb
+++ b/spec/ruby/core/kernel/autoload_spec.rb
@@ -7,7 +7,9 @@ require_relative 'fixtures/classes'
autoload :KSAutoloadA, "autoload_a.rb"
autoload :KSAutoloadB, fixture(__FILE__, "autoload_b.rb")
-autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+define_autoload_KSAutoloadCallsRequire = -> {
+ autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+}
def check_autoload(const)
autoload? const
@@ -23,7 +25,7 @@ describe "Kernel#autoload" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:autoload)
+ Kernel.private_instance_methods(false).should.include?(:autoload)
end
it "registers a file to load the first time the named constant is accessed" do
@@ -35,7 +37,7 @@ describe "Kernel#autoload" do
end
it "sets the autoload constant in Object's constant table" do
- Object.should have_constant(:KSAutoloadA)
+ Object.should.const_defined?(:KSAutoloadA, false)
end
it "loads the file when the constant is accessed" do
@@ -43,10 +45,11 @@ describe "Kernel#autoload" do
end
it "calls main.require(path) to load the file" do
+ define_autoload_KSAutoloadCallsRequire.call
main = TOPLEVEL_BINDING.eval("self")
main.should_receive(:require).with("main_autoload_not_exist.rb")
# The constant won't be defined since require is mocked to do nothing
- -> { KSAutoloadCallsRequire }.should raise_error(NameError)
+ -> { KSAutoloadCallsRequire }.should.raise(NameError)
end
it "can autoload in instance_eval" do
@@ -99,7 +102,7 @@ end
describe "Kernel#autoload?" do
it "is a private method" do
- Kernel.should have_private_instance_method(:autoload?)
+ Kernel.private_instance_methods(false).should.include?(:autoload?)
end
it "returns the name of the file that will be autoloaded" do
@@ -107,7 +110,7 @@ describe "Kernel#autoload?" do
end
it "returns nil if no file has been registered for a constant" do
- check_autoload(:Manualload).should be_nil
+ check_autoload(:Manualload).should == nil
end
end
@@ -134,7 +137,7 @@ describe "Kernel.autoload" do
end
it "sets the autoload constant in Object's constant table" do
- Object.should have_constant(:KSAutoloadBB)
+ Object.should.const_defined?(:KSAutoloadBB, false)
end
it "calls #to_path on non-String filenames" do
@@ -170,6 +173,6 @@ describe "Kernel.autoload?" do
end
it "returns nil if no file has been registered for a constant" do
- Kernel.autoload?(:Manualload).should be_nil
+ Kernel.autoload?(:Manualload).should == nil
end
end
diff --git a/spec/ruby/core/kernel/backtick_spec.rb b/spec/ruby/core/kernel/backtick_spec.rb
index 834d5636c1..42e0f975f5 100644
--- a/spec/ruby/core/kernel/backtick_spec.rb
+++ b/spec/ruby/core/kernel/backtick_spec.rb
@@ -11,7 +11,7 @@ describe "Kernel#`" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:`)
+ Kernel.private_instance_methods(false).should.include?(:`)
end
it "returns the standard output of the executed sub-process" do
@@ -28,11 +28,11 @@ describe "Kernel#`" do
it "produces a String in the default external encoding" do
Encoding.default_external = Encoding::SHIFT_JIS
- `echo disc`.encoding.should equal(Encoding::SHIFT_JIS)
+ `echo disc`.encoding.should.equal?(Encoding::SHIFT_JIS)
end
it "raises an Errno::ENOENT if the command is not executable" do
- -> { `nonexistent_command` }.should raise_error(Errno::ENOENT)
+ -> { `nonexistent_command` }.should.raise(Errno::ENOENT)
end
platform_is_not :windows do
@@ -43,13 +43,13 @@ describe "Kernel#`" do
it "sets $? to the exit status of the executed sub-process" do
ip = 'world'
`echo disc #{ip}`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 0
$?.should.success?
`echo disc #{ip}; exit 99`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 99
@@ -61,13 +61,13 @@ describe "Kernel#`" do
it "sets $? to the exit status of the executed sub-process" do
ip = 'world'
`echo disc #{ip}`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 0
$?.should.success?
`echo disc #{ip}& exit 99`
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.should_not.stopped?
$?.should.exited?
$?.exitstatus.should == 99
diff --git a/spec/ruby/core/kernel/binding_spec.rb b/spec/ruby/core/kernel/binding_spec.rb
index f1c9c6ec9f..6f27b26f37 100644
--- a/spec/ruby/core/kernel/binding_spec.rb
+++ b/spec/ruby/core/kernel/binding_spec.rb
@@ -9,7 +9,7 @@ end
describe "Kernel#binding" do
it "is a private method" do
- Kernel.should have_private_instance_method(:binding)
+ Kernel.private_instance_methods(false).should.include?(:binding)
end
before :each do
@@ -35,7 +35,7 @@ describe "Kernel#binding" do
end
it "raises a NameError on undefined variable" do
- -> { eval("a_fake_variable", @b1) }.should raise_error(NameError)
+ -> { eval("a_fake_variable", @b1) }.should.raise(NameError)
end
it "uses the closure's self as self in the binding" do
diff --git a/spec/ruby/core/kernel/block_given_spec.rb b/spec/ruby/core/kernel/block_given_spec.rb
index aece4c821d..20bb90ae96 100644
--- a/spec/ruby/core/kernel/block_given_spec.rb
+++ b/spec/ruby/core/kernel/block_given_spec.rb
@@ -30,7 +30,7 @@ describe "Kernel#block_given?" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:block_given?)
+ Kernel.private_instance_methods(false).should.include?(:block_given?)
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index aaacd9a910..04cf806ef4 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/caller_locations'
describe 'Kernel#caller_locations' do
it 'is a private method' do
- Kernel.should have_private_instance_method(:caller_locations)
+ Kernel.private_instance_methods(false).should.include?(:caller_locations)
end
it 'returns an Array of caller locations' do
@@ -83,7 +83,7 @@ describe 'Kernel#caller_locations' do
end
end
- ruby_version_is "3.4" do
+ ruby_version_is "3.4"..."4.0" do
it "includes core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
file.should.start_with?('<internal:')
@@ -94,5 +94,20 @@ describe 'Kernel#caller_locations' do
loc.path.should.start_with? "<internal:"
end
end
+
+ ruby_version_is "4.0" do
+ it "does not include core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ # CRuby hides the file which defines the method: https://bugs.ruby-lang.org/issues/20968
+ unless loc.path == __FILE__
+ loc.path.should.start_with? "<internal:"
+ end
+ end
+ end
end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index 33c7929a31..225f6fc458 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/caller'
describe 'Kernel#caller' do
it 'is a private method' do
- Kernel.should have_private_instance_method(:caller)
+ Kernel.private_instance_methods(false).should.include?(:caller)
end
it 'returns an Array of caller locations' do
@@ -32,7 +32,7 @@ describe 'Kernel#caller' do
locations = KernelSpecs::CallerTest.locations
line = __LINE__ - 1
- locations[0].should include("#{__FILE__}:#{line}:in")
+ locations[0].should.include?("#{__FILE__}:#{line}:in")
end
it "returns an Array with the block given to #at_exit at the base of the stack" do
@@ -84,13 +84,38 @@ describe 'Kernel#caller' do
end
guard -> { Kernel.instance_method(:tap).source_location } do
- it "includes core library methods defined in Ruby" do
- file, line = Kernel.instance_method(:tap).source_location
- file.should.start_with?('<internal:')
+ ruby_version_is ""..."3.4" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ loc.should =~ /\A<internal:.*in `tap'\z/
+ end
+ end
+
+ ruby_version_is "3.4"..."4.0" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ loc.should =~ /\A<internal:.*in 'Kernel#tap'\z/
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "does not include core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
- loc = nil
- tap { loc = caller(1, 1)[0] }
- loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ # CRuby hides the file which defines the method: https://bugs.ruby-lang.org/issues/20968
+ loc.should =~ /\A(<internal:|#{__FILE__}:).*in 'Kernel#tap'\z/
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/case_compare_spec.rb b/spec/ruby/core/kernel/case_compare_spec.rb
index b8d30960e8..c74bbf63b9 100644
--- a/spec/ruby/core/kernel/case_compare_spec.rb
+++ b/spec/ruby/core/kernel/case_compare_spec.rb
@@ -58,18 +58,18 @@ describe "Kernel#=== for a class with #== overridden to consider other object's
end
it "returns true if #== returns true even if #equal? is false" do
- @o1.should_not equal(@o2)
+ @o1.should_not.equal?(@o2)
(@o1 == @o2).should == true
(@o1 === @o2).should == true
end
it "returns true if #equal? returns true" do
- @o1.should equal(@o1)
+ @o1.should.equal?(@o1)
(@o1 === @o1).should == true
end
it "returns false if neither #== nor #equal? returns true" do
- @o1.should_not equal(@o)
+ @o1.should_not.equal?(@o)
(@o1 == @o).should == false
(@o1 === @o).should == false
end
@@ -83,13 +83,13 @@ describe "Kernel#=== for a class with #equal? overridden to always be false" do
end
it "returns true if #== returns true even if #equal? is false" do
- @o1.should_not equal(@o1)
+ @o1.should_not.equal?(@o1)
(@o1 == @o1).should == true
(@o1 === @o1).should == true
end
it "returns false if neither #== nor #equal? returns true" do
- @o1.should_not equal(@o)
+ @o1.should_not.equal?(@o)
(@o1 == @o).should == false
(@o1 === @o).should == false
end
@@ -105,7 +105,7 @@ describe "Kernel#=== for a class with #== and #equal? overridden to always be fa
it "returns true if the object id is the same even if both #== and #equal? return false" do
@o1.object_id.should == @o1.object_id
- @o1.should_not equal(@o1)
+ @o1.should_not.equal?(@o1)
(@o1 == @o1).should == false
(@o1 === @o1).should == true
@@ -114,7 +114,7 @@ describe "Kernel#=== for a class with #== and #equal? overridden to always be fa
it "returns false if the object id is not the same and both #== and #equal? return false" do
@o1.object_id.should_not == @o2.object_id
- @o1.should_not equal(@o2)
+ @o1.should_not.equal?(@o2)
(@o1 == @o2).should == false
(@o1 === @o2).should == false
diff --git a/spec/ruby/core/kernel/catch_spec.rb b/spec/ruby/core/kernel/catch_spec.rb
index 9f59d3b384..9f02303678 100644
--- a/spec/ruby/core/kernel/catch_spec.rb
+++ b/spec/ruby/core/kernel/catch_spec.rb
@@ -31,11 +31,11 @@ describe "Kernel.catch" do
end
it "raises an ArgumentError if a Symbol is thrown for a String catch value" do
- -> { catch("exit") { throw :exit } }.should raise_error(ArgumentError)
+ -> { catch("exit") { throw :exit } }.should.raise(ArgumentError)
end
it "raises an ArgumentError if a String with different identity is thrown" do
- -> { catch("exit".dup) { throw "exit".dup } }.should raise_error(ArgumentError)
+ -> { catch("exit".dup) { throw "exit".dup } }.should.raise(ArgumentError)
end
it "catches a Symbol when thrown a matching Symbol" do
@@ -60,7 +60,7 @@ describe "Kernel.catch" do
end
it "yields an object when called without arguments" do
- catch { |tag| tag }.should be_an_instance_of(Object)
+ catch { |tag| tag }.should.instance_of?(Object)
end
it "can be used even in a method different from where throw is called" do
@@ -116,12 +116,12 @@ describe "Kernel.catch" do
end
it "raises LocalJumpError if no block is given" do
- -> { catch :blah }.should raise_error(LocalJumpError)
+ -> { catch :blah }.should.raise(LocalJumpError)
end
end
describe "Kernel#catch" do
it "is a private method" do
- Kernel.should have_private_instance_method(:catch)
+ Kernel.private_instance_methods(false).should.include?(:catch)
end
end
diff --git a/spec/ruby/core/kernel/chomp_spec.rb b/spec/ruby/core/kernel/chomp_spec.rb
index d30e77c35a..434bf652f9 100644
--- a/spec/ruby/core/kernel/chomp_spec.rb
+++ b/spec/ruby/core/kernel/chomp_spec.rb
@@ -26,7 +26,7 @@ end
describe :kernel_chomp_private, shared: true do
it "is a private method" do
- KernelSpecs.has_private_method(@method).should be_true
+ KernelSpecs.has_private_method(@method).should == true
end
end
diff --git a/spec/ruby/core/kernel/chop_spec.rb b/spec/ruby/core/kernel/chop_spec.rb
index 9b91c011bc..bbf3c3f724 100644
--- a/spec/ruby/core/kernel/chop_spec.rb
+++ b/spec/ruby/core/kernel/chop_spec.rb
@@ -14,7 +14,7 @@ end
describe :kernel_chop_private, shared: true do
it "is a private method" do
- KernelSpecs.has_private_method(@method).should be_true
+ KernelSpecs.has_private_method(@method).should == true
end
end
diff --git a/spec/ruby/core/kernel/class_spec.rb b/spec/ruby/core/kernel/class_spec.rb
index b1d9df1671..0a7f774d14 100644
--- a/spec/ruby/core/kernel/class_spec.rb
+++ b/spec/ruby/core/kernel/class_spec.rb
@@ -3,24 +3,24 @@ require_relative 'fixtures/classes'
describe "Kernel#class" do
it "returns the class of the object" do
- Object.new.class.should equal(Object)
+ Object.new.class.should.equal?(Object)
- 1.class.should equal(Integer)
- 3.14.class.should equal(Float)
- :hello.class.should equal(Symbol)
- "hello".class.should equal(String)
- [1, 2].class.should equal(Array)
- { 1 => 2 }.class.should equal(Hash)
+ 1.class.should.equal?(Integer)
+ 3.14.class.should.equal?(Float)
+ :hello.class.should.equal?(Symbol)
+ "hello".class.should.equal?(String)
+ [1, 2].class.should.equal?(Array)
+ { 1 => 2 }.class.should.equal?(Hash)
end
it "returns Class for a class" do
- BasicObject.class.should equal(Class)
- String.class.should equal(Class)
+ BasicObject.class.should.equal?(Class)
+ String.class.should.equal?(Class)
end
it "returns the first non-singleton class" do
a = +"hello"
def a.my_singleton_method; end
- a.class.should equal(String)
+ a.class.should.equal?(String)
end
end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index 5adcbbe603..4ddb23d6e6 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -25,7 +25,7 @@ describe "Kernel#clone" do
end
clone = instance.clone
- clone.class.should equal klass
+ clone.class.should.equal? klass
end
describe "with no arguments" do
@@ -40,7 +40,7 @@ describe "Kernel#clone" do
it 'copies frozen?' do
o = ''.freeze.clone
- o.frozen?.should be_true
+ o.frozen?.should == true
end
end
@@ -56,7 +56,7 @@ describe "Kernel#clone" do
it "copies frozen?" do
o = "".freeze.clone(freeze: nil)
- o.frozen?.should be_true
+ o.frozen?.should == true
end
end
@@ -78,7 +78,7 @@ describe "Kernel#clone" do
it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
obj = KernelSpecs::Clone.new
- -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ -> { obj.clone(freeze: true) }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
@@ -100,15 +100,15 @@ describe "Kernel#clone" do
it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
obj = KernelSpecs::Clone.new
- -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ -> { obj.clone(freeze: false) }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
describe "with freeze: anything else" do
it 'raises ArgumentError when passed not true/false/nil' do
- -> { @obj.clone(freeze: 1) }.should raise_error(ArgumentError, /unexpected value for freeze: Integer/)
- -> { @obj.clone(freeze: "") }.should raise_error(ArgumentError, /unexpected value for freeze: String/)
- -> { @obj.clone(freeze: Object.new) }.should raise_error(ArgumentError, /unexpected value for freeze: Object/)
+ -> { @obj.clone(freeze: 1) }.should.raise(ArgumentError, /unexpected value for freeze: Integer/)
+ -> { @obj.clone(freeze: "") }.should.raise(ArgumentError, /unexpected value for freeze: String/)
+ -> { @obj.clone(freeze: Object.new) }.should.raise(ArgumentError, /unexpected value for freeze: Object/)
end
end
diff --git a/spec/ruby/core/kernel/comparison_spec.rb b/spec/ruby/core/kernel/comparison_spec.rb
index affdc5c00d..48f17e1172 100644
--- a/spec/ruby/core/kernel/comparison_spec.rb
+++ b/spec/ruby/core/kernel/comparison_spec.rb
@@ -15,17 +15,17 @@ describe "Kernel#<=>" do
it "returns nil if self is eql? but not == to the argument" do
obj = mock('has eql?')
obj.should_not_receive(:eql?)
- obj.<=>(Object.new).should be_nil
+ obj.<=>(Object.new).should == nil
end
it "returns nil if self.==(arg) returns nil" do
obj = mock('wrong ==')
obj.should_receive(:==).and_return(nil)
- obj.<=>(Object.new).should be_nil
+ obj.<=>(Object.new).should == nil
end
it "returns nil if self is not == to the argument" do
obj = Object.new
- obj.<=>(3.14).should be_nil
+ obj.<=>(3.14).should == nil
end
end
diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb
index 24acec84f5..ec48581db8 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -14,14 +14,14 @@ describe "Kernel#define_singleton_method" do
end
it "adds the new method to the methods list" do
- DefineSingletonMethodSpecClass.should have_method(:another_test_method)
+ DefineSingletonMethodSpecClass.should.respond_to?(:another_test_method)
end
it "defines any Child class method from any Parent's class methods" do
um = KernelSpecs::Parent.method(:parent_class_method).unbind
KernelSpecs::Child.send :define_singleton_method, :child_class_method, um
KernelSpecs::Child.child_class_method.should == :foo
- ->{KernelSpecs::Parent.child_class_method}.should raise_error(NoMethodError)
+ ->{KernelSpecs::Parent.child_class_method}.should.raise(NoMethodError)
end
it "will raise when attempting to define an object's singleton method from another object's singleton method" do
@@ -33,7 +33,7 @@ describe "Kernel#define_singleton_method" do
end
end
um = p.method(:singleton_method).unbind
- ->{ other.send :define_singleton_method, :other_singleton_method, um }.should raise_error(TypeError)
+ ->{ other.send :define_singleton_method, :other_singleton_method, um }.should.raise(TypeError)
end
end
@@ -52,11 +52,11 @@ describe "Kernel#define_singleton_method" do
it "raises a TypeError when the given method is no Method/Proc" do
-> {
Class.new { define_singleton_method(:test, "self") }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Class.new { define_singleton_method(:test, 1234) }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "defines a new singleton method for objects" do
@@ -65,7 +65,7 @@ describe "Kernel#define_singleton_method" do
obj.test.should == "world!"
-> {
Object.new.test
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "maintains the Proc's scope" do
@@ -83,7 +83,7 @@ describe "Kernel#define_singleton_method" do
obj = Object.new
-> {
obj.define_singleton_method(:test)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not use the caller block when no block is given" do
@@ -94,7 +94,7 @@ describe "Kernel#define_singleton_method" do
-> {
o.define(:foo) { raise "not used" }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "always defines the method with public visibility" do
@@ -109,12 +109,12 @@ describe "Kernel#define_singleton_method" do
cls.define(:foo) { :ok }
end
cls.foo.should == :ok
- }.should_not raise_error(NoMethodError)
+ }.should_not.raise(NoMethodError)
end
it "cannot define a singleton method with a frozen singleton class" do
o = Object.new
o.freeze
- -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError)
+ -> { o.define_singleton_method(:foo) { 1 } }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/kernel/dup_spec.rb b/spec/ruby/core/kernel/dup_spec.rb
index 70198abdb7..99de5e3732 100644
--- a/spec/ruby/core/kernel/dup_spec.rb
+++ b/spec/ruby/core/kernel/dup_spec.rb
@@ -25,7 +25,7 @@ describe "Kernel#dup" do
end
dup = instance.dup
- dup.class.should equal klass
+ dup.class.should.equal? klass
end
it "does not copy frozen state from the original" do
@@ -44,7 +44,7 @@ describe "Kernel#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- -> { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should.raise(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -53,7 +53,7 @@ describe "Kernel#dup" do
end
dup = @obj.dup
- -> { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should.raise(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -62,6 +62,6 @@ describe "Kernel#dup" do
end
dup = @obj.dup
- -> { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/kernel/eql_spec.rb b/spec/ruby/core/kernel/eql_spec.rb
index e62a601a79..b3289090e5 100644
--- a/spec/ruby/core/kernel/eql_spec.rb
+++ b/spec/ruby/core/kernel/eql_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../shared/kernel/equal'
describe "Kernel#eql?" do
it "is a public instance method" do
- Kernel.should have_public_instance_method(:eql?)
+ Kernel.public_instance_methods(false).should.include?(:eql?)
end
it_behaves_like :object_equal, :eql?
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index c189d5f0a2..f9ca47866e 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -5,7 +5,7 @@ EvalSpecs::A.new.c
describe "Kernel#eval" do
it "is a private method" do
- Kernel.should have_private_instance_method(:eval)
+ Kernel.private_instance_methods(false).should.include?(:eval)
end
it "is a module function" do
@@ -76,12 +76,12 @@ describe "Kernel#eval" do
x = 1
bind = proc {}
- -> { eval("x", bind) }.should raise_error(TypeError)
+ -> { eval("x", bind) }.should.raise(TypeError)
end
it "does not make Proc locals visible to evaluated code" do
bind = proc { inner = 4 }
- -> { eval("inner", bind.binding) }.should raise_error(NameError)
+ -> { eval("inner", bind.binding) }.should.raise(NameError)
end
# REWRITE ME: This obscures the real behavior of where locals are stored
@@ -119,7 +119,7 @@ describe "Kernel#eval" do
outer_binding = binding
eval("if false; a = 1; end", outer_binding)
- eval("a", outer_binding).should be_nil
+ eval("a", outer_binding).should == nil
end
it "allows creating a new class in a binding" do
@@ -136,7 +136,7 @@ describe "Kernel#eval" do
expected = 'speccing.rb'
-> {
eval('if true', TOPLEVEL_BINDING, expected)
- }.should raise_error(SyntaxError) { |e|
+ }.should.raise(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
end
@@ -145,7 +145,7 @@ describe "Kernel#eval" do
expected_file = 'speccing.rb'
-> {
eval('if true', TOPLEVEL_BINDING, expected_file, -100)
- }.should raise_error(SyntaxError) { |e|
+ }.should.raise(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}
end
@@ -159,36 +159,87 @@ describe "Kernel#eval" do
end
end
- ruby_version_is ""..."3.3" do
- it "uses (eval) filename if none is provided" do
- eval("__FILE__").should == "(eval)"
- eval("__FILE__", binding).should == "(eval)"
- eval("__FILE__", binding, "success").should == "success"
- eval("eval '__FILE__', binding").should == "(eval)"
- eval("eval '__FILE__', binding", binding).should == "(eval)"
- eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
- eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ context "parameter forwarding" do
+ it "allows anonymous rest parameter forwarding" do
+ object = Object.new
+ def object.foo(a, b, c)
+ [a, b, c]
+ end
+ def object.bar(*)
+ eval "foo(*)"
+ end
+
+ object.bar(1, 2, 3).should == [1, 2, 3]
end
- it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do
- eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1]
+ it "allows anonymous keyword parameters forwarding" do
+ object = Object.new
+ def object.foo(a:, b:, c:)
+ [a, b, c]
+ end
+ def object.bar(**)
+ eval "foo(**)"
+ end
+
+ object.bar(a: 1, b: 2, c: 3).should == [1, 2, 3]
end
- end
- ruby_version_is "3.3" do
- it "uses (eval at __FILE__:__LINE__) if none is provided" do
- eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
- eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})"
- eval("__FILE__", binding, "success").should == "success"
- eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
- eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
- eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)"
- eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ it "allows anonymous block parameter forwarding" do
+ object = Object.new
+ def object.foo(&block)
+ block.call
+ end
+ def object.bar(&)
+ eval "foo(&)"
+ end
+
+ object.bar { :foobar }.should == :foobar
end
- it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do
- eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ it "allows ... forwarding" do
+ object = Object.new
+ def object.foo(a, b:, &block)
+ [a, b, block.call]
+ end
+ def object.bar(...)
+ eval "foo(...)"
+ end
+
+ object.bar(1, b: 2) { 3 }.should == [1, 2, 3]
end
+
+ it "allows parameter forwarding to super" do
+ m = Module.new do
+ def foo(a, b:, &block)
+ [a, b, block.call]
+ end
+ end
+
+ c = Class.new do
+ include m
+
+ def foo(a, b:, &block)
+ eval "super"
+ end
+ end
+
+ object = c.new
+ object.foo(1, b: 2) { 3 }.should == [1, 2, 3]
+ end
+ end
+
+ it "uses (eval at __FILE__:__LINE__) if none is provided" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding, "success").should == "success"
+ eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)"
+ eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ end
+
+ it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
# Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do
@@ -212,14 +263,14 @@ describe "Kernel#eval" do
# See http://jira.codehaus.org/browse/JRUBY-5163
it "uses the receiver as self inside the eval" do
- eval("self").should equal(self)
- Kernel.eval("self").should equal(Kernel)
+ eval("self").should.equal?(self)
+ Kernel.eval("self").should.equal?(Kernel)
end
it "does not pass the block to the method being eval'ed" do
-> {
eval('KernelSpecs::EvalTest.call_yield') { "content" }
- }.should raise_error(LocalJumpError)
+ }.should.raise(LocalJumpError)
end
it "returns from the scope calling #eval when evaluating 'return'" do
@@ -257,7 +308,7 @@ describe "Kernel#eval" do
it "has the correct default definee when called through Method#call" do
class EvalSpecs
method(:eval).call("def eval_spec_method_call; end")
- EvalSpecs.should have_instance_method(:eval_spec_method_call)
+ EvalSpecs.should.method_defined?(:eval_spec_method_call, false)
end
end
@@ -311,7 +362,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπ")
+ EvalSpecs.constants(false).should.include?(:"Vπ")
EvalSpecs::Vπ.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπ)
@@ -326,7 +377,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπemacs")
+ EvalSpecs.constants(false).should.include?(:"Vπemacs")
EvalSpecs::Vπemacs.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπemacs)
@@ -341,7 +392,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπspaces")
+ EvalSpecs.constants(false).should.include?(:"Vπspaces")
EvalSpecs::Vπspaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπspaces)
@@ -357,7 +408,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπshebang")
+ EvalSpecs.constants(false).should.include?(:"Vπshebang")
EvalSpecs::Vπshebang.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang)
@@ -373,7 +424,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπshebang_spaces")
+ EvalSpecs.constants(false).should.include?(:"Vπshebang_spaces")
EvalSpecs::Vπshebang_spaces.should == 3.14
ensure
EvalSpecs.send(:remove_const, :Vπshebang_spaces)
@@ -391,7 +442,7 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπstring")
+ EvalSpecs.constants(false).should.include?(:"Vπstring")
EvalSpecs::Vπstring.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
@@ -408,10 +459,10 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should include(:"Vπsame_line")
+ EvalSpecs.constants(false).should.include?(:"Vπsame_line")
EvalSpecs::Vπsame_line.should == "frozen"
EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8
- EvalSpecs::Vπsame_line.frozen?.should be_true
+ EvalSpecs::Vπsame_line.frozen?.should == true
ensure
EvalSpecs.send(:remove_const, :Vπsame_line)
end
@@ -427,9 +478,9 @@ end
CODE
code.encoding.should == Encoding::BINARY
eval(code)
- EvalSpecs.constants(false).should_not include(:"Vπfrozen_first")
+ EvalSpecs.constants(false).should_not.include?(:"Vπfrozen_first")
binary_constant = "Vπfrozen_first".b.to_sym
- EvalSpecs.constants(false).should include(binary_constant)
+ EvalSpecs.constants(false).should.include?(binary_constant)
value = EvalSpecs.const_get(binary_constant)
value.should == "frozen"
value.encoding.should == Encoding::BINARY
diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb
index 3d9520ad67..fd8485791a 100644
--- a/spec/ruby/core/kernel/exec_spec.rb
+++ b/spec/ruby/core/kernel/exec_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#exec" do
it "is a private method" do
- Kernel.should have_private_instance_method(:exec)
+ Kernel.private_instance_methods(false).should.include?(:exec)
end
it "runs the specified command, replacing current process" do
diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb
index 93cec3fee5..864ff84449 100644
--- a/spec/ruby/core/kernel/exit_spec.rb
+++ b/spec/ruby/core/kernel/exit_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/process/exit'
describe "Kernel#exit" do
it "is a private method" do
- Kernel.should have_private_instance_method(:exit)
+ Kernel.private_instance_methods(false).should.include?(:exit)
end
it_behaves_like :process_exit, :exit, KernelSpecs::Method.new
@@ -16,7 +16,7 @@ end
describe "Kernel#exit!" do
it "is a private method" do
- Kernel.should have_private_instance_method(:exit!)
+ Kernel.private_instance_methods(false).should.include?(:exit!)
end
it_behaves_like :process_exit!, :exit!, "self"
diff --git a/spec/ruby/core/kernel/extend_spec.rb b/spec/ruby/core/kernel/extend_spec.rb
index 6342d8cae1..a344c7b5ca 100644
--- a/spec/ruby/core/kernel/extend_spec.rb
+++ b/spec/ruby/core/kernel/extend_spec.rb
@@ -53,13 +53,13 @@ describe "Kernel#extend" do
end
it "raises an ArgumentError when no arguments given" do
- -> { Object.new.extend }.should raise_error(ArgumentError)
+ -> { Object.new.extend }.should.raise(ArgumentError)
end
it "raises a TypeError when the argument is not a Module" do
o = mock('o')
klass = Class.new
- -> { o.extend(klass) }.should raise_error(TypeError)
+ -> { o.extend(klass) }.should.raise(TypeError)
end
describe "on frozen instance" do
@@ -69,11 +69,11 @@ describe "Kernel#extend" do
end
it "raises an ArgumentError when no arguments given" do
- -> { @frozen.extend }.should raise_error(ArgumentError)
+ -> { @frozen.extend }.should.raise(ArgumentError)
end
it "raises a FrozenError" do
- -> { @frozen.extend @module }.should raise_error(FrozenError)
+ -> { @frozen.extend @module }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/kernel/fail_spec.rb b/spec/ruby/core/kernel/fail_spec.rb
index fab622037e..ac379b67d5 100644
--- a/spec/ruby/core/kernel/fail_spec.rb
+++ b/spec/ruby/core/kernel/fail_spec.rb
@@ -3,11 +3,11 @@ require_relative 'fixtures/classes'
describe "Kernel#fail" do
it "is a private method" do
- Kernel.should have_private_instance_method(:fail)
+ Kernel.private_instance_methods(false).should.include?(:fail)
end
it "raises a RuntimeError" do
- -> { fail }.should raise_error(RuntimeError)
+ -> { fail }.should.raise(RuntimeError)
end
it "accepts an Object with an exception method returning an Exception" do
@@ -15,12 +15,12 @@ describe "Kernel#fail" do
def obj.exception(msg)
StandardError.new msg
end
- -> { fail obj, "..." }.should raise_error(StandardError, "...")
+ -> { fail obj, "..." }.should.raise(StandardError, "...")
end
it "instantiates the specified exception class" do
error_class = Class.new(RuntimeError)
- -> { fail error_class }.should raise_error(error_class)
+ -> { fail error_class }.should.raise(error_class)
end
it "uses the specified message" do
@@ -33,7 +33,7 @@ describe "Kernel#fail" do
else
raise Exception
end
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/kernel/fixtures/autoload_relative_b.rb b/spec/ruby/core/kernel/fixtures/autoload_relative_b.rb
new file mode 100644
index 0000000000..6de6f5091d
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/autoload_relative_b.rb
@@ -0,0 +1,7 @@
+module KernelSpecs
+ module KSAutoloadRelativeB
+ def self.loaded
+ :ksautoload_b
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/autoload_relative_d.rb b/spec/ruby/core/kernel/fixtures/autoload_relative_d.rb
new file mode 100644
index 0000000000..5b6b5e1fa2
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/autoload_relative_d.rb
@@ -0,0 +1,5 @@
+module KSAutoloadRelativeD
+ def self.loaded
+ :ksautoload_d
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb
index 0e2b81988f..ad82f3cef5 100644
--- a/spec/ruby/core/kernel/fixtures/classes.rb
+++ b/spec/ruby/core/kernel/fixtures/classes.rb
@@ -180,6 +180,25 @@ module KernelSpecs
alias aliased_pub_method pub_method
end
+ class BasicA < BasicObject
+ define_method(:respond_to?, ::Kernel.instance_method(:respond_to?))
+
+ def pub_method; :public_method; end
+
+ def undefed_method; :undefed_method; end
+ undef_method :undefed_method
+
+ protected
+ def protected_method; :protected_method; end
+
+ private
+ def private_method; :private_method; end
+ end
+
+ class MissingA < A
+ undef :respond_to_missing?
+ end
+
class VisibilityChange
class << self
private :new
diff --git a/spec/ruby/core/kernel/fork_spec.rb b/spec/ruby/core/kernel/fork_spec.rb
index b37f9980e0..4a2c848202 100644
--- a/spec/ruby/core/kernel/fork_spec.rb
+++ b/spec/ruby/core/kernel/fork_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/process/fork'
describe "Kernel#fork" do
it "is a private method" do
- Kernel.should have_private_instance_method(:fork)
+ Kernel.private_instance_methods(false).should.include?(:fork)
end
it_behaves_like :process_fork, :fork, KernelSpecs::Method.new
diff --git a/spec/ruby/core/kernel/format_spec.rb b/spec/ruby/core/kernel/format_spec.rb
index 1d0c000c15..35c752b1ab 100644
--- a/spec/ruby/core/kernel/format_spec.rb
+++ b/spec/ruby/core/kernel/format_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# NOTE: most specs are in sprintf_spec.rb, this is just an alias
describe "Kernel#format" do
it "is a private method" do
- Kernel.should have_private_instance_method(:format)
+ Kernel.private_instance_methods(false).should.include?(:format)
end
end
@@ -20,7 +20,7 @@ describe "Kernel.format" do
format("test", 1)
RUBY
- ruby_exe(code, args: "2>&1").should include("warning: too many arguments for format string")
+ ruby_exe(code, args: "2>&1").should.include?("warning: too many arguments for format string")
end
it "does not warns if too many keyword arguments are passed" do
@@ -29,7 +29,7 @@ describe "Kernel.format" do
format("test %{test}", test: 1, unused: 2)
RUBY
- ruby_exe(code, args: "2>&1").should_not include("warning")
+ ruby_exe(code, args: "2>&1").should_not.include?("warning")
end
ruby_bug "#20593", ""..."3.4" do
@@ -40,7 +40,7 @@ describe "Kernel.format" do
format("test", {})
RUBY
- ruby_exe(code, args: "2>&1").should_not include("warning")
+ ruby_exe(code, args: "2>&1").should_not.include?("warning")
end
end
end
diff --git a/spec/ruby/core/kernel/freeze_spec.rb b/spec/ruby/core/kernel/freeze_spec.rb
index fa32d321cf..079617dce4 100644
--- a/spec/ruby/core/kernel/freeze_spec.rb
+++ b/spec/ruby/core/kernel/freeze_spec.rb
@@ -4,46 +4,46 @@ require_relative 'fixtures/classes'
describe "Kernel#freeze" do
it "prevents self from being further modified" do
o = mock('o')
- o.frozen?.should be_false
+ o.frozen?.should == false
o.freeze
- o.frozen?.should be_true
+ o.frozen?.should == true
end
it "returns self" do
o = Object.new
- o.freeze.should equal(o)
+ o.freeze.should.equal?(o)
end
describe "on integers" do
it "has no effect since they are already frozen" do
- 1.frozen?.should be_true
+ 1.frozen?.should == true
1.freeze
bignum = bignum_value
- bignum.frozen?.should be_true
+ bignum.frozen?.should == true
bignum.freeze
end
end
describe "on a Float" do
it "has no effect since it is already frozen" do
- 1.2.frozen?.should be_true
+ 1.2.frozen?.should == true
1.2.freeze
end
end
describe "on a Symbol" do
it "has no effect since it is already frozen" do
- :sym.frozen?.should be_true
+ :sym.frozen?.should == true
:sym.freeze
end
end
describe "on true, false and nil" do
it "has no effect since they are already frozen" do
- nil.frozen?.should be_true
- true.frozen?.should be_true
- false.frozen?.should be_true
+ nil.frozen?.should == true
+ true.frozen?.should == true
+ false.frozen?.should == true
nil.freeze
true.freeze
@@ -54,7 +54,7 @@ describe "Kernel#freeze" do
describe "on a Complex" do
it "has no effect since it is already frozen" do
c = Complex(1.3, 3.1)
- c.frozen?.should be_true
+ c.frozen?.should == true
c.freeze
end
end
@@ -62,7 +62,7 @@ describe "Kernel#freeze" do
describe "on a Rational" do
it "has no effect since it is already frozen" do
r = Rational(1, 3)
- r.frozen?.should be_true
+ r.frozen?.should == true
r.freeze
end
end
@@ -72,13 +72,13 @@ describe "Kernel#freeze" do
def mutate; @foo = 1; end
end.new
o.freeze
- -> {o.mutate}.should raise_error(RuntimeError)
+ -> {o.mutate}.should.raise(RuntimeError)
end
it "causes instance_variable_set to raise RuntimeError" do
o = Object.new
o.freeze
- -> {o.instance_variable_set(:@foo, 1)}.should raise_error(RuntimeError)
+ -> {o.instance_variable_set(:@foo, 1)}.should.raise(RuntimeError)
end
it "freezes an object's singleton class" do
diff --git a/spec/ruby/core/kernel/frozen_spec.rb b/spec/ruby/core/kernel/frozen_spec.rb
index a4cec4263d..8b8fad3de7 100644
--- a/spec/ruby/core/kernel/frozen_spec.rb
+++ b/spec/ruby/core/kernel/frozen_spec.rb
@@ -12,9 +12,9 @@ describe "Kernel#frozen?" do
describe "on true, false and nil" do
it "returns true" do
- true.frozen?.should be_true
- false.frozen?.should be_true
- nil.frozen?.should be_true
+ true.frozen?.should == true
+ false.frozen?.should == true
+ nil.frozen?.should == true
end
end
@@ -25,8 +25,8 @@ describe "Kernel#frozen?" do
end
it "returns true" do
- @fixnum.frozen?.should be_true
- @bignum.frozen?.should be_true
+ @fixnum.frozen?.should == true
+ @bignum.frozen?.should == true
end
end
@@ -36,7 +36,7 @@ describe "Kernel#frozen?" do
end
it "returns true" do
- @float.frozen?.should be_true
+ @float.frozen?.should == true
end
end
@@ -46,31 +46,31 @@ describe "Kernel#frozen?" do
end
it "returns true" do
- @symbol.frozen?.should be_true
+ @symbol.frozen?.should == true
end
end
describe "on a Complex" do
it "returns true" do
c = Complex(1.3, 3.1)
- c.frozen?.should be_true
+ c.frozen?.should == true
end
it "literal returns true" do
c = eval "1.3i"
- c.frozen?.should be_true
+ c.frozen?.should == true
end
end
describe "on a Rational" do
it "returns true" do
r = Rational(1, 3)
- r.frozen?.should be_true
+ r.frozen?.should == true
end
it "literal returns true" do
r = eval "1/3r"
- r.frozen?.should be_true
+ r.frozen?.should == true
end
end
end
diff --git a/spec/ruby/core/kernel/gets_spec.rb b/spec/ruby/core/kernel/gets_spec.rb
index 104613dbfa..1b2b36fbb9 100644
--- a/spec/ruby/core/kernel/gets_spec.rb
+++ b/spec/ruby/core/kernel/gets_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#gets" do
it "is a private method" do
- Kernel.should have_private_instance_method(:gets)
+ Kernel.private_instance_methods(false).should.include?(:gets)
end
it "calls ARGF.gets" do
diff --git a/spec/ruby/core/kernel/global_variables_spec.rb b/spec/ruby/core/kernel/global_variables_spec.rb
index 8bce8e25b7..d41bdff49a 100644
--- a/spec/ruby/core/kernel/global_variables_spec.rb
+++ b/spec/ruby/core/kernel/global_variables_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel.global_variables" do
it "is a private method" do
- Kernel.should have_private_instance_method(:global_variables)
+ Kernel.private_instance_methods(false).should.include?(:global_variables)
end
before :all do
@@ -11,13 +11,13 @@ describe "Kernel.global_variables" do
end
it "finds subset starting with std" do
- global_variables.grep(/std/).should include(:$stderr, :$stdin, :$stdout)
+ global_variables.grep(/std/).to_set.should >= Set[:$stderr, :$stdin, :$stdout]
a = global_variables.size
gvar_name = "$foolish_global_var#{@i += 1}"
global_variables.include?(gvar_name.to_sym).should == false
eval("#{gvar_name} = 1")
global_variables.size.should == a+1
- global_variables.should include(gvar_name.to_sym)
+ global_variables.should.include?(gvar_name.to_sym)
end
end
diff --git a/spec/ruby/core/kernel/gsub_spec.rb b/spec/ruby/core/kernel/gsub_spec.rb
index a0cb9f2a70..e05349e2b5 100644
--- a/spec/ruby/core/kernel/gsub_spec.rb
+++ b/spec/ruby/core/kernel/gsub_spec.rb
@@ -6,20 +6,20 @@ require_relative 'fixtures/classes'
ruby_version_is ""..."1.9" do
describe "Kernel#gsub" do
it "is a private method" do
- Kernel.should have_private_instance_method(:gsub)
+ Kernel.private_instance_methods(false).should.include?(:gsub)
end
it "raises a TypeError if $_ is not a String" do
-> {
$_ = 123
gsub(/./, "!")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "when matches sets $_ to a new string, leaving the former value unaltered" do
orig_value = $_ = "hello"
gsub("ello", "ola")
- $_.should_not equal(orig_value)
+ $_.should_not.equal?(orig_value)
$_.should == "hola"
orig_value.should == "hello"
end
@@ -86,7 +86,7 @@ ruby_version_is ""..."1.9" do
describe "Kernel#gsub!" do
it "is a private method" do
- Kernel.should have_private_instance_method(:gsub!)
+ Kernel.private_instance_methods(false).should.include?(:gsub!)
end
end
diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb
index 21a90c19f0..0033eadffb 100644
--- a/spec/ruby/core/kernel/initialize_clone_spec.rb
+++ b/spec/ruby/core/kernel/initialize_clone_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Kernel#initialize_clone" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:initialize_clone)
+ Kernel.private_instance_methods(false).should.include?(:initialize_clone)
end
it "returns the receiver" do
diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb
index d71ca9f60f..ebac0c14de 100644
--- a/spec/ruby/core/kernel/initialize_copy_spec.rb
+++ b/spec/ruby/core/kernel/initialize_copy_spec.rb
@@ -17,8 +17,8 @@ describe "Kernel#initialize_copy" do
end
it "raises FrozenError if the receiver is frozen" do
- -> { Object.new.freeze.send(:initialize_copy, Object.new) }.should raise_error(FrozenError)
- -> { 1.send(:initialize_copy, Object.new) }.should raise_error(FrozenError)
+ -> { Object.new.freeze.send(:initialize_copy, Object.new) }.should.raise(FrozenError)
+ -> { 1.send(:initialize_copy, Object.new) }.should.raise(FrozenError)
end
it "raises TypeError if the objects are of different class" do
@@ -27,10 +27,10 @@ describe "Kernel#initialize_copy" do
a = klass.new
b = sub.new
message = 'initialize_copy should take same class object'
- -> { a.send(:initialize_copy, b) }.should raise_error(TypeError, message)
- -> { b.send(:initialize_copy, a) }.should raise_error(TypeError, message)
+ -> { a.send(:initialize_copy, b) }.should.raise(TypeError, message)
+ -> { b.send(:initialize_copy, a) }.should.raise(TypeError, message)
- -> { a.send(:initialize_copy, 1) }.should raise_error(TypeError, message)
- -> { a.send(:initialize_copy, 1.0) }.should raise_error(TypeError, message)
+ -> { a.send(:initialize_copy, 1) }.should.raise(TypeError, message)
+ -> { a.send(:initialize_copy, 1.0) }.should.raise(TypeError, message)
end
end
diff --git a/spec/ruby/core/kernel/initialize_dup_spec.rb b/spec/ruby/core/kernel/initialize_dup_spec.rb
index 6dff34b7ad..f144647eb8 100644
--- a/spec/ruby/core/kernel/initialize_dup_spec.rb
+++ b/spec/ruby/core/kernel/initialize_dup_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Kernel#initialize_dup" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:initialize_dup)
+ Kernel.private_instance_methods(false).should.include?(:initialize_dup)
end
it "returns the receiver" do
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index 1f9ce834ab..8fc3ab51cd 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#inspect" do
it "returns a String" do
- Object.new.inspect.should be_an_instance_of(String)
+ Object.new.inspect.should.instance_of?(String)
end
it "does not call #to_s if it is defined" do
@@ -26,6 +26,78 @@ describe "Kernel#inspect" do
class << obj
undef_method :class
end
- obj.inspect.should be_kind_of(String)
+ obj.inspect.should.is_a?(String)
+ end
+
+ ruby_version_is "4.0" do
+ it "calls #instance_variables_to_inspect private method to know which variables to display" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = %i[@host @user @does_not_exist]
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == '#<Object:0x00 @host="localhost", @user="root">'
+
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = []
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == "#<Object:0x00>"
+ end
+
+ it "displays all instance variables if #instance_variables_to_inspect returns nil" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = nil
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == %{#<Object:0x00 @host="localhost", @user="root", @password="hunter2">}
+ end
+
+ it "displays all instance variables if #instance_variables_to_inspect is not defined" do
+ obj = BasicObject.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ method_inspect = Kernel.instance_method(:inspect)
+
+ inspected = method_inspect.bind(obj).call.sub(/^#<BasicObject:0x[0-9a-f]+/, '#<BasicObject:0x00')
+ inspected.should == %{#<BasicObject:0x00 @host="localhost", @user="root", @password="hunter2">}
+ end
+
+ it "raises an error if #instance_variables_to_inspect returns an invalid value" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = {}
+ end
+
+ ->{ obj.inspect }.should.raise(TypeError, "Expected #instance_variables_to_inspect to return an Array or nil, but it returned Hash")
+ end
end
end
diff --git a/spec/ruby/core/kernel/instance_of_spec.rb b/spec/ruby/core/kernel/instance_of_spec.rb
index d1170d5047..8d19974aa3 100644
--- a/spec/ruby/core/kernel/instance_of_spec.rb
+++ b/spec/ruby/core/kernel/instance_of_spec.rb
@@ -33,8 +33,8 @@ describe "Kernel#instance_of?" do
end
it "raises a TypeError if given an object that is not a Class nor a Module" do
- -> { @o.instance_of?(Object.new) }.should raise_error(TypeError)
- -> { @o.instance_of?('KernelSpecs::InstanceClass') }.should raise_error(TypeError)
- -> { @o.instance_of?(1) }.should raise_error(TypeError)
+ -> { @o.instance_of?(Object.new) }.should.raise(TypeError)
+ -> { @o.instance_of?('KernelSpecs::InstanceClass') }.should.raise(TypeError)
+ -> { @o.instance_of?(1) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_defined_spec.rb b/spec/ruby/core/kernel/instance_variable_defined_spec.rb
index 2ebb582b43..512f811393 100644
--- a/spec/ruby/core/kernel/instance_variable_defined_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_defined_spec.rb
@@ -8,21 +8,21 @@ describe "Kernel#instance_variable_defined?" do
describe "when passed a String" do
it "returns false if the instance variable is not defined" do
- @instance.instance_variable_defined?("@goodbye").should be_false
+ @instance.instance_variable_defined?("@goodbye").should == false
end
it "returns true if the instance variable is defined" do
- @instance.instance_variable_defined?("@greeting").should be_true
+ @instance.instance_variable_defined?("@greeting").should == true
end
end
describe "when passed a Symbol" do
it "returns false if the instance variable is not defined" do
- @instance.instance_variable_defined?(:@goodbye).should be_false
+ @instance.instance_variable_defined?(:@goodbye).should == false
end
it "returns true if the instance variable is defined" do
- @instance.instance_variable_defined?(:@greeting).should be_true
+ @instance.instance_variable_defined?(:@greeting).should == true
end
end
@@ -30,12 +30,12 @@ describe "Kernel#instance_variable_defined?" do
-> do
obj = mock("kernel instance_variable_defined?")
@instance.instance_variable_defined? obj
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "returns false if the instance variable is not defined for different types" do
[nil, false, true, 1, 2.0, :test, "test"].each do |obj|
- obj.instance_variable_defined?("@goodbye").should be_false
+ obj.instance_variable_defined?("@goodbye").should == false
end
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb
index f1d2a45df8..8404c94192 100644
--- a/spec/ruby/core/kernel/instance_variable_get_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb
@@ -20,29 +20,29 @@ describe "Kernel#instance_variable_get" do
end
it "returns nil when the referred instance variable does not exist" do
- @obj.instance_variable_get(:@does_not_exist).should be_nil
+ @obj.instance_variable_get(:@does_not_exist).should == nil
end
it "raises a TypeError when the passed argument does not respond to #to_str" do
- -> { @obj.instance_variable_get(Object.new) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(Object.new) }.should.raise(TypeError)
end
it "raises a TypeError when the passed argument can't be converted to a String" do
obj = mock("to_str")
obj.stub!(:to_str).and_return(123)
- -> { @obj.instance_variable_get(obj) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(obj) }.should.raise(TypeError)
end
it "raises a NameError when the conversion result does not start with an '@'" do
obj = mock("to_str")
obj.stub!(:to_str).and_return("test")
- -> { @obj.instance_variable_get(obj) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(obj) }.should.raise(NameError)
end
it "raises a NameError when passed just '@'" do
obj = mock("to_str")
obj.stub!(:to_str).and_return('@')
- -> { @obj.instance_variable_get(obj) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(obj) }.should.raise(NameError)
end
end
@@ -57,20 +57,20 @@ describe "Kernel#instance_variable_get when passed Symbol" do
end
it "raises a NameError when passed :@ as an instance variable name" do
- -> { @obj.instance_variable_get(:"@") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:"@") }.should.raise(NameError)
end
it "raises a NameError when the passed Symbol does not start with an '@'" do
- -> { @obj.instance_variable_get(:test) }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:test) }.should.raise(NameError)
end
it "raises a NameError when the passed Symbol is an invalid instance variable name" do
- -> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get(:"@0") }.should.raise(NameError)
end
it "returns nil or raises for frozen objects" do
nil.instance_variable_get(:@foo).should == nil
- -> { nil.instance_variable_get(:foo) }.should raise_error(NameError)
+ -> { nil.instance_variable_get(:foo) }.should.raise(NameError)
:foo.instance_variable_get(:@foo).should == nil
end
end
@@ -86,15 +86,15 @@ describe "Kernel#instance_variable_get when passed String" do
end
it "raises a NameError when the passed String does not start with an '@'" do
- -> { @obj.instance_variable_get("test") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("test") }.should.raise(NameError)
end
it "raises a NameError when the passed String is an invalid instance variable name" do
- -> { @obj.instance_variable_get("@0") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("@0") }.should.raise(NameError)
end
it "raises a NameError when passed '@' as an instance variable name" do
- -> { @obj.instance_variable_get("@") }.should raise_error(NameError)
+ -> { @obj.instance_variable_get("@") }.should.raise(NameError)
end
end
@@ -105,7 +105,7 @@ describe "Kernel#instance_variable_get when passed Integer" do
end
it "raises a TypeError" do
- -> { @obj.instance_variable_get(10) }.should raise_error(TypeError)
- -> { @obj.instance_variable_get(-10) }.should raise_error(TypeError)
+ -> { @obj.instance_variable_get(10) }.should.raise(TypeError)
+ -> { @obj.instance_variable_get(-10) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb
index 2c25f4366f..bf165a824e 100644
--- a/spec/ruby/core/kernel/instance_variable_set_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb
@@ -18,26 +18,26 @@ describe "Kernel#instance_variable_set" do
it "raises a NameError exception if the argument is not of form '@x'" do
no_dog = Class.new
- -> { no_dog.new.instance_variable_set(:c, "cat") }.should raise_error(NameError)
+ -> { no_dog.new.instance_variable_set(:c, "cat") }.should.raise(NameError)
end
it "raises a NameError exception if the argument is an invalid instance variable name" do
digit_dog = Class.new
- -> { digit_dog.new.instance_variable_set(:"@0", "cat") }.should raise_error(NameError)
+ -> { digit_dog.new.instance_variable_set(:"@0", "cat") }.should.raise(NameError)
end
it "raises a NameError when the argument is '@'" do
dog_at = Class.new
- -> { dog_at.new.instance_variable_set(:"@", "cat") }.should raise_error(NameError)
+ -> { dog_at.new.instance_variable_set(:"@", "cat") }.should.raise(NameError)
end
it "raises a TypeError if the instance variable name is an Integer" do
- -> { "".instance_variable_set(1, 2) }.should raise_error(TypeError)
+ -> { "".instance_variable_set(1, 2) }.should.raise(TypeError)
end
it "raises a TypeError if the instance variable name is an object that does not respond to to_str" do
class KernelSpecs::A; end
- -> { "".instance_variable_set(KernelSpecs::A.new, 3) }.should raise_error(TypeError)
+ -> { "".instance_variable_set(KernelSpecs::A.new, 3) }.should.raise(TypeError)
end
it "raises a NameError if the passed object, when coerced with to_str, does not start with @" do
@@ -46,11 +46,11 @@ describe "Kernel#instance_variable_set" do
":c"
end
end
- -> { "".instance_variable_set(KernelSpecs::B.new, 4) }.should raise_error(NameError)
+ -> { "".instance_variable_set(KernelSpecs::B.new, 4) }.should.raise(NameError)
end
it "raises a NameError if pass an object that cannot be a symbol" do
- -> { "".instance_variable_set(:c, 1) }.should raise_error(NameError)
+ -> { "".instance_variable_set(:c, 1) }.should.raise(NameError)
end
it "accepts as instance variable name any instance of a class that responds to to_str" do
@@ -78,16 +78,16 @@ describe "Kernel#instance_variable_set" do
end
it "keeps stored object after any exceptions" do
- -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(Exception)
- @frozen.ivar.should equal(:origin)
+ -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should.raise(Exception)
+ @frozen.ivar.should.equal?(:origin)
end
it "raises a FrozenError when passed replacement is identical to stored object" do
- -> { @frozen.instance_variable_set(:@ivar, :origin) }.should raise_error(FrozenError)
+ -> { @frozen.instance_variable_set(:@ivar, :origin) }.should.raise(FrozenError)
end
it "raises a FrozenError when passed replacement is different from stored object" do
- -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(FrozenError)
+ -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should.raise(FrozenError)
end
it "accepts unicode instance variable names" do
@@ -97,9 +97,9 @@ describe "Kernel#instance_variable_set" do
end
it "raises for frozen objects" do
- -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
- -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError)
- -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ -> { nil.instance_variable_set(:@foo, 42) }.should.raise(FrozenError)
+ -> { nil.instance_variable_set(:foo, 42) }.should.raise(NameError)
+ -> { :foo.instance_variable_set(:@foo, 42) }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/kernel/instance_variables_spec.rb b/spec/ruby/core/kernel/instance_variables_spec.rb
index 677d8bb7b2..75c1d8f752 100644
--- a/spec/ruby/core/kernel/instance_variables_spec.rb
+++ b/spec/ruby/core/kernel/instance_variables_spec.rb
@@ -11,7 +11,7 @@ describe "Kernel#instance_variables" do
it "returns the correct array if an instance variable is added" do
a = 0
- ->{ a.instance_variable_set("@test", 1) }.should raise_error(RuntimeError)
+ ->{ a.instance_variable_set("@test", 1) }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/kernel/itself_spec.rb b/spec/ruby/core/kernel/itself_spec.rb
index c906d7c3e8..c1f01fdc5e 100644
--- a/spec/ruby/core/kernel/itself_spec.rb
+++ b/spec/ruby/core/kernel/itself_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "Kernel#itself" do
it "returns the receiver itself" do
foo = Object.new
- foo.itself.should equal foo
+ foo.itself.should.equal? foo
end
end
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 565536ac0d..6ab89c2bbb 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -8,92 +8,52 @@ describe "Kernel.lambda" do
it_behaves_like :kernel_lambda, :lambda
it "is a private method" do
- Kernel.should have_private_instance_method(:lambda)
+ Kernel.private_instance_methods(false).should.include?(:lambda)
end
it "creates a lambda-style Proc if given a literal block" do
l = lambda { 42 }
- l.lambda?.should be_true
+ l.lambda?.should == true
end
it "creates a lambda-style Proc if given a literal block via #send" do
l = send(:lambda) { 42 }
- l.lambda?.should be_true
+ l.lambda?.should == true
end
it "creates a lambda-style Proc if given a literal block via #__send__" do
l = __send__(:lambda) { 42 }
- l.lambda?.should be_true
- end
-
- ruby_version_is ""..."3.3" do
- it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
- suppress_warning do
- l = Kernel.public_send(:lambda) { 42 }
- l.lambda?.should be_true
- end
- end
-
- it "returns the passed Proc if given an existing Proc" do
- some_proc = proc {}
- l = suppress_warning {lambda(&some_proc)}
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
-
- it "creates a lambda-style Proc when called with zsuper" do
- suppress_warning do
- l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
- l.lambda?.should be_true
- l.call.should == 42
-
- lambda { l.call(:extra) }.should raise_error(ArgumentError)
- end
- end
-
- it "returns the passed Proc if given an existing Proc through super" do
- some_proc = proc { }
- l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
-
- it "does not create lambda-style Procs when captured with #method" do
- kernel_lambda = method(:lambda)
- l = suppress_warning {kernel_lambda.call { 42 }}
- l.lambda?.should be_false
- l.call(:extra).should == 42
- end
+ l.lambda?.should == true
end
it "checks the arity of the call when no args are specified" do
l = lambda { :called }
l.call.should == :called
- lambda { l.call(1) }.should raise_error(ArgumentError)
- lambda { l.call(1, 2) }.should raise_error(ArgumentError)
+ lambda { l.call(1) }.should.raise(ArgumentError)
+ lambda { l.call(1, 2) }.should.raise(ArgumentError)
end
it "checks the arity when 1 arg is specified" do
l = lambda { |a| :called }
l.call(1).should == :called
- lambda { l.call }.should raise_error(ArgumentError)
- lambda { l.call(1, 2) }.should raise_error(ArgumentError)
+ lambda { l.call }.should.raise(ArgumentError)
+ lambda { l.call(1, 2) }.should.raise(ArgumentError)
end
it "does not check the arity when passing a Proc with &" do
l = lambda { || :called }
p = proc { || :called }
- lambda { l.call(1) }.should raise_error(ArgumentError)
+ lambda { l.call(1) }.should.raise(ArgumentError)
p.call(1).should == :called
end
it "accepts 0 arguments when used with ||" do
lambda {
lambda { || }.call(1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "strictly checks the arity when 0 or 2..inf args are specified" do
@@ -101,15 +61,15 @@ describe "Kernel.lambda" do
lambda {
l.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
lambda {
l.call(1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
lambda {
l.call(1,2)
- }.should_not raise_error(ArgumentError)
+ }.should_not.raise(ArgumentError)
end
it "returns from the lambda itself, not the creation site of the lambda" do
@@ -119,7 +79,7 @@ describe "Kernel.lambda" do
@reached_end_of_method = true
end
test
- @reached_end_of_method.should be_true
+ @reached_end_of_method.should == true
end
it "allows long returns to flow through it" do
@@ -134,21 +94,13 @@ describe "Kernel.lambda" do
2
end
end
- klass.new.lambda { 42 }.should be_an_instance_of Proc
+ klass.new.lambda { 42 }.should.instance_of? Proc
klass.new.ret.should == 1
end
context "when called without a literal block" do
- ruby_version_is ""..."3.3" do
- it "warns when proc isn't a lambda" do
- -> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n")
- end
- end
-
- ruby_version_is "3.3" do
- it "raises when proc isn't a lambda" do
- -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/)
- end
+ it "raises when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should.raise(ArgumentError, /the lambda method requires a literal block/)
end
it "doesn't warn when proc is lambda" do
diff --git a/spec/ruby/core/kernel/load_spec.rb b/spec/ruby/core/kernel/load_spec.rb
index a165cc4acd..890aab8c27 100644
--- a/spec/ruby/core/kernel/load_spec.rb
+++ b/spec/ruby/core/kernel/load_spec.rb
@@ -13,7 +13,7 @@ describe "Kernel#load" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:load)
+ Kernel.private_instance_methods(false).should.include?(:load)
end
it_behaves_like :kernel_require_basic, :load, CodeLoadingSpecs::Method.new
diff --git a/spec/ruby/core/kernel/local_variables_spec.rb b/spec/ruby/core/kernel/local_variables_spec.rb
index f6f1e15f52..40c343f7e4 100644
--- a/spec/ruby/core/kernel/local_variables_spec.rb
+++ b/spec/ruby/core/kernel/local_variables_spec.rb
@@ -7,14 +7,13 @@ describe "Kernel#local_variables" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:local_variables)
+ Kernel.private_instance_methods(false).should.include?(:local_variables)
end
it "contains locals as they are added" do
a = 1
b = 2
- local_variables.should include(:a, :b)
- local_variables.length.should == 2
+ local_variables.sort.should == [:a, :b]
end
it "is accessible from bindings" do
@@ -25,14 +24,12 @@ describe "Kernel#local_variables" do
end
foo_binding = local_var_foo()
res = eval("local_variables",foo_binding)
- res.should include(:a, :b)
- res.length.should == 2
+ res.sort.should == [:a, :b]
end
it "is accessible in eval" do
eval "a=1; b=2; ScratchPad.record local_variables"
- ScratchPad.recorded.should include(:a, :b)
- ScratchPad.recorded.length.should == 2
+ ScratchPad.recorded.sort.should == [:a, :b]
end
it "includes only unique variable names" do
diff --git a/spec/ruby/core/kernel/loop_spec.rb b/spec/ruby/core/kernel/loop_spec.rb
index 7c76c7d28e..c2976e5cc5 100644
--- a/spec/ruby/core/kernel/loop_spec.rb
+++ b/spec/ruby/core/kernel/loop_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel.loop" do
it "is a private method" do
- Kernel.should have_private_instance_method(:loop)
+ Kernel.private_instance_methods(false).should.include?(:loop)
end
it "calls block until it is terminated by a break" do
@@ -30,7 +30,7 @@ describe "Kernel.loop" do
it "returns an enumerator if no block given" do
enum = loop
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
cnt = 0
enum.each do |*args|
raise "Args should be empty #{args.inspect}" unless args.empty?
@@ -55,7 +55,7 @@ describe "Kernel.loop" do
end
it "does not rescue other errors" do
- ->{ loop do raise StandardError end }.should raise_error( StandardError )
+ ->{ loop do raise StandardError end }.should.raise( StandardError )
end
it "returns StopIteration#result, the result value of a finished iterator" do
diff --git a/spec/ruby/core/kernel/match_spec.rb b/spec/ruby/core/kernel/match_spec.rb
index aa25006163..cd6330fe91 100644
--- a/spec/ruby/core/kernel/match_spec.rb
+++ b/spec/ruby/core/kernel/match_spec.rb
@@ -1,30 +1,7 @@
require_relative '../../spec_helper'
describe "Kernel#=~" do
- ruby_version_is ''...'3.2' do
- it "returns nil matching any object" do
- o = Object.new
-
- suppress_warning do
- (o =~ /Object/).should be_nil
- (o =~ 'Object').should be_nil
- (o =~ Object).should be_nil
- (o =~ Object.new).should be_nil
- (o =~ nil).should be_nil
- (o =~ true).should be_nil
- end
- end
-
- it "is deprecated" do
- -> do
- Object.new =~ /regexp/
- end.should complain(/deprecated Object#=~ is called on Object/, verbose: true)
- end
- end
-
- ruby_version_is '3.2' do
- it "is no longer defined" do
- Object.new.should_not.respond_to?(:=~)
- end
+ it "is no longer defined" do
+ Object.new.should_not.respond_to?(:=~)
end
end
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index 3fc566d6a6..9187b8c7e7 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -11,12 +11,12 @@ describe "Kernel#method" do
it "can be called on a private method" do
@obj.send(:private_method).should == :private_method
- @obj.method(:private_method).should be_an_instance_of(Method)
+ @obj.method(:private_method).should.instance_of?(Method)
end
it "can be called on a protected method" do
@obj.send(:protected_method).should == :protected_method
- @obj.method(:protected_method).should be_an_instance_of(Method)
+ @obj.method(:protected_method).should.instance_of?(Method)
end
it "will see an alias of the original method as == when in a derived class" do
@@ -31,7 +31,7 @@ describe "Kernel#method" do
it "can be called even if we only respond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
end
@@ -45,7 +45,7 @@ describe "Kernel#method" do
end
end
m = cls.new.method(:foo)
- -> { m.call }.should raise_error(ArgumentError)
+ -> { m.call }.should.raise(ArgumentError)
cls = Class.new do
def respond_to_missing?(name, *)
@@ -67,14 +67,22 @@ describe "Kernel#method" do
end
it "raises a TypeError if the given name can't be converted to a String" do
- -> { Object.method(nil) }.should raise_error(TypeError)
- -> { Object.method([]) }.should raise_error(TypeError)
+ -> { Object.method(nil) }.should.raise(TypeError)
+ -> { Object.method([]) }.should.raise(TypeError)
end
it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
name = mock("method-name")
name.should_receive(:to_str).and_raise(NoMethodError)
- -> { Object.method(name) }.should raise_error(NoMethodError)
+ -> { Object.method(name) }.should.raise(NoMethodError)
+
+ name = mock("method-name")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ begin
+ raise RuntimeError.new
+ rescue => cause
+ -> { Object.method(name) }.should.raise(NoMethodError, cause:)
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/methods_spec.rb b/spec/ruby/core/kernel/methods_spec.rb
index fb7a7e8be9..cfa22aa05a 100644
--- a/spec/ruby/core/kernel/methods_spec.rb
+++ b/spec/ruby/core/kernel/methods_spec.rb
@@ -5,67 +5,67 @@ require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#methods" do
it "returns singleton methods defined by obj.meth" do
- KernelSpecs::Methods.methods(false).should include(:ichi)
+ KernelSpecs::Methods.methods(false).should.include?(:ichi)
end
it "returns singleton methods defined in 'class << self'" do
- KernelSpecs::Methods.methods(false).should include(:san)
+ KernelSpecs::Methods.methods(false).should.include?(:san)
end
it "returns private singleton methods defined by obj.meth" do
- KernelSpecs::Methods.methods(false).should include(:shi)
+ KernelSpecs::Methods.methods(false).should.include?(:shi)
end
it "returns singleton methods defined in 'class << self' when it follows 'private'" do
- KernelSpecs::Methods.methods(false).should include(:roku)
+ KernelSpecs::Methods.methods(false).should.include?(:roku)
end
it "does not return private singleton methods defined in 'class << self'" do
- KernelSpecs::Methods.methods(false).should_not include(:shichi)
+ KernelSpecs::Methods.methods(false).should_not.include?(:shichi)
end
it "returns the publicly accessible methods of the object" do
meths = KernelSpecs::Methods.methods(false)
- meths.should include(:hachi, :ichi, :juu, :juu_ichi,
- :juu_ni, :roku, :san, :shi)
+ meths.to_set.should >= Set[:hachi, :ichi, :juu, :juu_ichi,
+ :juu_ni, :roku, :san, :shi]
KernelSpecs::Methods.new.methods(false).should == []
end
it "returns the publicly accessible methods in the object, its ancestors and mixed-in modules" do
meths = KernelSpecs::Methods.methods(false) & KernelSpecs::Methods.methods
- meths.should include(:hachi, :ichi, :juu, :juu_ichi,
- :juu_ni, :roku, :san, :shi)
+ meths.to_set.should >= Set[:hachi, :ichi, :juu, :juu_ichi,
+ :juu_ni, :roku, :san, :shi]
- KernelSpecs::Methods.new.methods.should include(:ku, :ni, :juu_san)
+ KernelSpecs::Methods.new.methods.to_set.should >= Set[:ku, :ni, :juu_san]
end
it "returns methods added to the metaclass through extend" do
meth = KernelSpecs::Methods.new
- meth.methods.should_not include(:peekaboo)
+ meth.methods.should_not.include?(:peekaboo)
meth.extend(KernelSpecs::Methods::MetaclassMethods)
- meth.methods.should include(:peekaboo)
+ meth.methods.should.include?(:peekaboo)
end
it "does not return undefined singleton methods defined by obj.meth" do
o = KernelSpecs::Child.new
def o.single; end
- o.methods.should include(:single)
+ o.methods.should.include?(:single)
class << o; self; end.send :undef_method, :single
- o.methods.should_not include(:single)
+ o.methods.should_not.include?(:single)
end
it "does not return superclass methods undefined in the object's class" do
- KernelSpecs::Child.new.methods.should_not include(:parent_method)
+ KernelSpecs::Child.new.methods.should_not.include?(:parent_method)
end
it "does not return superclass methods undefined in a superclass" do
- KernelSpecs::Grandchild.new.methods.should_not include(:parent_method)
+ KernelSpecs::Grandchild.new.methods.should_not.include?(:parent_method)
end
it "does not return included module methods undefined in the object's class" do
- KernelSpecs::Grandchild.new.methods.should_not include(:parent_mixin_method)
+ KernelSpecs::Grandchild.new.methods.should_not.include?(:parent_mixin_method)
end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index f8dd82fad8..4ed7ea7b42 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -14,18 +14,8 @@ describe "Kernel#!~" do
(obj !~ :foo).should == false
end
- ruby_version_is ""..."3.2" do
- it "returns true if self does not respond to #=~" do
- suppress_warning do
- (Object.new !~ :foo).should == true
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises NoMethodError if self does not respond to #=~" do
- -> { Object.new !~ :foo }.should raise_error(NoMethodError)
- end
+ it "raises NoMethodError if self does not respond to #=~" do
+ -> { Object.new !~ :foo }.should.raise(NoMethodError)
end
it 'can be overridden in subclasses' do
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index bb42c31f31..14a3c43cad 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -15,70 +15,70 @@ describe "Kernel#open" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:open)
+ Kernel.private_instance_methods(false).should.include?(:open)
end
it "opens a file when given a valid filename" do
@file = open(@name)
- @file.should be_kind_of(File)
+ @file.should.is_a?(File)
end
it "opens a file when called with a block" do
open(@name, "r") { |f| f.gets }.should == @content
end
- platform_is_not :windows, :wasi do
- it "opens an io when path starts with a pipe" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @io = open("|date")
+ ruby_version_is ""..."4.0" do
+ platform_is_not :windows, :wasi do
+ it "opens an io when path starts with a pipe" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date")
+ end
+ begin
+ @io.should.is_a?(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
- end
- end
- it "opens an io when called with a block" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @output = open("|date") { |f| f.read }
+ it "opens an io when called with a block" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date") { |f| f.read }
+ end
+ @output.should_not == ''
end
- @output.should_not == ''
- end
- it "opens an io for writing" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- -> {
- bytes = open("|cat", "w") { |io| io.write(".") }
- bytes.should == 1
- }.should output_to_fd(".")
+ it "opens an io for writing" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ -> {
+ bytes = open("|cat", "w") { |io| io.write(".") }
+ bytes.should == 1
+ }.should output_to_fd(".")
+ end
end
end
- end
- platform_is :windows do
- it "opens an io when path starts with a pipe" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @io = open("|date /t")
+ platform_is :windows do
+ it "opens an io when path starts with a pipe" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date /t")
+ end
+ begin
+ @io.should.is_a?(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
- end
- end
- it "opens an io when called with a block" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @output = open("|date /t") { |f| f.read }
+ it "opens an io when called with a block" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date /t") { |f| f.read }
+ end
+ @output.should_not == ''
end
- @output.should_not == ''
end
- end
- ruby_version_is "3.3" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
cmd = "|echo ok"
@@ -89,16 +89,16 @@ describe "Kernel#open" do
end
it "raises an ArgumentError if not passed one argument" do
- -> { open }.should raise_error(ArgumentError)
+ -> { open }.should.raise(ArgumentError)
end
it "accepts options as keyword arguments" do
@file = open(@name, "r", 0666, flags: File::CREAT)
- @file.should be_kind_of(File)
+ @file.should.is_a?(File)
-> {
open(@name, "r", 0666, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
describe "when given an object that responds to to_open" do
@@ -106,7 +106,7 @@ describe "Kernel#open" do
ScratchPad.clear
end
- it "calls #to_path to covert the argument to a String before calling #to_str" do
+ it "calls #to_path to convert the argument to a String before calling #to_str" do
obj = mock("open to_path")
obj.should_receive(:to_path).at_least(1).times.and_return(@name)
obj.should_not_receive(:to_str)
@@ -126,7 +126,7 @@ describe "Kernel#open" do
@file = File.open(@name)
obj.should_receive(:to_open).and_return(@file)
@file = open(obj)
- @file.should be_kind_of(File)
+ @file.should.is_a?(File)
end
it "returns the value from #to_open" do
@@ -167,9 +167,9 @@ describe "Kernel#open" do
it "raises a TypeError if passed a non-String that does not respond to #to_open" do
obj = mock('non-fileish')
- -> { open(obj) }.should raise_error(TypeError)
- -> { open(nil) }.should raise_error(TypeError)
- -> { open(7) }.should raise_error(TypeError)
+ -> { open(obj) }.should.raise(TypeError)
+ -> { open(nil) }.should.raise(TypeError)
+ -> { open(7) }.should.raise(TypeError)
end
it "accepts nil for mode and permission" do
diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb
index eae191aa54..f89716899a 100644
--- a/spec/ruby/core/kernel/p_spec.rb
+++ b/spec/ruby/core/kernel/p_spec.rb
@@ -13,7 +13,7 @@ describe "Kernel#p" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:p)
+ Kernel.private_instance_methods(false).should.include?(:p)
end
# TODO: fix
diff --git a/spec/ruby/core/kernel/print_spec.rb b/spec/ruby/core/kernel/print_spec.rb
index 7e7c9b822d..5473d22f71 100644
--- a/spec/ruby/core/kernel/print_spec.rb
+++ b/spec/ruby/core/kernel/print_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#print" do
it "is a private method" do
- Kernel.should have_private_instance_method(:print)
+ Kernel.private_instance_methods(false).should.include?(:print)
end
it "delegates to $stdout" do
diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb
index 61bf955c25..50939b3794 100644
--- a/spec/ruby/core/kernel/printf_spec.rb
+++ b/spec/ruby/core/kernel/printf_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/sprintf'
describe "Kernel#printf" do
it "is a private method" do
- Kernel.should have_private_instance_method(:printf)
+ Kernel.private_instance_methods(false).should.include?(:printf)
end
end
diff --git a/spec/ruby/core/kernel/private_methods_spec.rb b/spec/ruby/core/kernel/private_methods_spec.rb
index 041634d1e5..b0e6d042a9 100644
--- a/spec/ruby/core/kernel/private_methods_spec.rb
+++ b/spec/ruby/core/kernel/private_methods_spec.rb
@@ -6,23 +6,23 @@ require_relative '../../fixtures/reflection'
describe "Kernel#private_methods" do
it "returns a list of the names of privately accessible methods in the object" do
m = KernelSpecs::Methods.private_methods(false)
- m.should include(:shichi)
+ m.should.include?(:shichi)
m = KernelSpecs::Methods.new.private_methods(false)
- m.should include(:juu_shi)
+ m.should.include?(:juu_shi)
end
it "returns a list of the names of privately accessible methods in the object and its ancestors and mixed-in modules" do
m = (KernelSpecs::Methods.private_methods(false) & KernelSpecs::Methods.private_methods)
- m.should include(:shichi)
+ m.should.include?(:shichi)
m = KernelSpecs::Methods.new.private_methods
- m.should include(:juu_shi)
+ m.should.include?(:juu_shi)
end
it "returns private methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
- m.private_methods.should include(:shoo)
+ m.private_methods.should.include?(:shoo)
end
end
diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb
index 6553b8fd04..1ba662177b 100644
--- a/spec/ruby/core/kernel/proc_spec.rb
+++ b/spec/ruby/core/kernel/proc_spec.rb
@@ -6,20 +6,20 @@ require_relative 'shared/lambda'
describe "Kernel.proc" do
it "is a private method" do
- Kernel.should have_private_instance_method(:proc)
+ Kernel.private_instance_methods(false).should.include?(:proc)
end
it "creates a proc-style Proc if given a literal block" do
l = proc { 42 }
- l.lambda?.should be_false
+ l.lambda?.should == false
end
it "returned the passed Proc if given an existing Proc" do
some_lambda = -> {}
- some_lambda.lambda?.should be_true
+ some_lambda.lambda?.should == true
l = proc(&some_lambda)
- l.should equal(some_lambda)
- l.lambda?.should be_true
+ l.should.equal?(some_lambda)
+ l.lambda?.should == true
end
it_behaves_like :kernel_lambda, :proc
@@ -31,7 +31,7 @@ describe "Kernel.proc" do
@reached_end_of_method = true
end
test
- @reached_end_of_method.should be_nil
+ @reached_end_of_method.should == nil
end
end
@@ -43,6 +43,6 @@ describe "Kernel#proc" do
it "raises an ArgumentError when passed no block" do
-> {
some_method { "hello" }
- }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ }.should.raise(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/kernel/protected_methods_spec.rb b/spec/ruby/core/kernel/protected_methods_spec.rb
index d3334e886b..aecb9f5ffb 100644
--- a/spec/ruby/core/kernel/protected_methods_spec.rb
+++ b/spec/ruby/core/kernel/protected_methods_spec.rb
@@ -8,21 +8,21 @@ require_relative '../../fixtures/reflection'
# You should use have_protected_method() with the exception of this spec.
describe "Kernel#protected_methods" do
it "returns a list of the names of protected methods accessible in the object" do
- KernelSpecs::Methods.protected_methods(false).sort.should include(:juu_ichi)
- KernelSpecs::Methods.new.protected_methods(false).should include(:ku)
+ KernelSpecs::Methods.protected_methods(false).sort.should.include?(:juu_ichi)
+ KernelSpecs::Methods.new.protected_methods(false).should.include?(:ku)
end
it "returns a list of the names of protected methods accessible in the object and from its ancestors and mixed-in modules" do
l1 = KernelSpecs::Methods.protected_methods(false)
l2 = KernelSpecs::Methods.protected_methods
- (l1 & l2).should include(:juu_ichi)
- KernelSpecs::Methods.new.protected_methods.should include(:ku)
+ (l1 & l2).should.include?(:juu_ichi)
+ KernelSpecs::Methods.new.protected_methods.should.include?(:ku)
end
it "returns methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
- m.protected_methods.should include(:nopeeking)
+ m.protected_methods.should.include?(:nopeeking)
end
end
diff --git a/spec/ruby/core/kernel/public_method_spec.rb b/spec/ruby/core/kernel/public_method_spec.rb
index c5d54c777e..42b8f797d3 100644
--- a/spec/ruby/core/kernel/public_method_spec.rb
+++ b/spec/ruby/core/kernel/public_method_spec.rb
@@ -13,20 +13,20 @@ describe "Kernel#public_method" do
@obj.send(:private_method).should == :private_method
-> do
@obj.public_method(:private_method)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when called on a protected method" do
@obj.send(:protected_method).should == :protected_method
-> {
@obj.public_method(:protected_method)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "raises a NameError if we only repond_to_missing? method, true" do
obj = KernelSpecs::RespondViaMissing.new
-> do
obj.public_method(:handled_privately)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/kernel/public_methods_spec.rb b/spec/ruby/core/kernel/public_methods_spec.rb
index a5512784fb..e334ac9a55 100644
--- a/spec/ruby/core/kernel/public_methods_spec.rb
+++ b/spec/ruby/core/kernel/public_methods_spec.rb
@@ -5,31 +5,30 @@ require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Kernel#public_methods" do
it "returns a list of the names of publicly accessible methods in the object" do
- KernelSpecs::Methods.public_methods(false).sort.should include(:hachi,
- :ichi, :juu, :juu_ni, :roku, :san, :shi)
- KernelSpecs::Methods.new.public_methods(false).sort.should include(:juu_san, :ni)
+ KernelSpecs::Methods.public_methods(false).to_set.should >= Set[:hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi]
+ KernelSpecs::Methods.new.public_methods(false).to_set.should >= Set[:juu_san, :ni]
end
it "returns a list of names without protected accessible methods in the object" do
- KernelSpecs::Methods.public_methods(false).sort.should_not include(:juu_ichi)
- KernelSpecs::Methods.new.public_methods(false).sort.should_not include(:ku)
+ KernelSpecs::Methods.public_methods(false).sort.should_not.include?(:juu_ichi)
+ KernelSpecs::Methods.new.public_methods(false).sort.should_not.include?(:ku)
end
it "returns a list of the names of publicly accessible methods in the object and its ancestors and mixed-in modules" do
- (KernelSpecs::Methods.public_methods(false) & KernelSpecs::Methods.public_methods).sort.should include(
- :hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi)
+ (KernelSpecs::Methods.public_methods(false) & KernelSpecs::Methods.public_methods).to_set.should >= Set[
+ :hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi]
m = KernelSpecs::Methods.new.public_methods
- m.should include(:ni, :juu_san)
+ m.to_set.should >= Set[:ni, :juu_san]
end
it "returns methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
- m.public_methods.should include(:peekaboo)
+ m.public_methods.should.include?(:peekaboo)
end
it "returns public methods for immediates" do
- 10.public_methods.should include(:divmod)
+ 10.public_methods.should.include?(:divmod)
end
end
diff --git a/spec/ruby/core/kernel/public_send_spec.rb b/spec/ruby/core/kernel/public_send_spec.rb
index b684b1729c..6a4a969c77 100644
--- a/spec/ruby/core/kernel/public_send_spec.rb
+++ b/spec/ruby/core/kernel/public_send_spec.rb
@@ -29,7 +29,7 @@ describe "Kernel#public_send" do
'done'
end
end
- -> { KernelSpecs::Foo.new.public_send(:bar)}.should raise_error(NoMethodError)
+ -> { KernelSpecs::Foo.new.public_send(:bar)}.should.raise(NoMethodError)
end
it "raises a NoMethodError if the named method is private" do
@@ -41,7 +41,7 @@ describe "Kernel#public_send" do
end
-> {
KernelSpecs::Foo.new.public_send(:bar)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
context 'called from own public method' do
@@ -70,11 +70,11 @@ describe "Kernel#public_send" do
end
it "raises a NoMethodError if the method is protected" do
- -> { @receiver.call_protected_method }.should raise_error(NoMethodError)
+ -> { @receiver.call_protected_method }.should.raise(NoMethodError)
end
it "raises a NoMethodError if the method is private" do
- -> { @receiver.call_private_method }.should raise_error(NoMethodError)
+ -> { @receiver.call_private_method }.should.raise(NoMethodError)
end
end
@@ -88,7 +88,7 @@ describe "Kernel#public_send" do
end
-> {
KernelSpecs::Foo.new.public_send(:aka)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "raises a NoMethodError if the named method is an alias of a protected method" do
@@ -101,15 +101,15 @@ describe "Kernel#public_send" do
end
-> {
KernelSpecs::Foo.new.public_send(:aka)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "includes `public_send` in the backtrace when passed not enough arguments" do
- -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
+ -> { public_send() }.should.raise(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it "includes `public_send` in the backtrace when passed a single incorrect argument" do
- -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
+ -> { public_send(Object.new) }.should.raise(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it_behaves_like :basicobject_send, :public_send
diff --git a/spec/ruby/core/kernel/putc_spec.rb b/spec/ruby/core/kernel/putc_spec.rb
index 74bd3765db..e6a20a9af1 100644
--- a/spec/ruby/core/kernel/putc_spec.rb
+++ b/spec/ruby/core/kernel/putc_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/io/putc'
describe "Kernel#putc" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:putc)
+ Kernel.private_instance_methods(false).should.include?(:putc)
end
end
diff --git a/spec/ruby/core/kernel/puts_spec.rb b/spec/ruby/core/kernel/puts_spec.rb
index 6eb38e8fcf..eed18fcd50 100644
--- a/spec/ruby/core/kernel/puts_spec.rb
+++ b/spec/ruby/core/kernel/puts_spec.rb
@@ -15,7 +15,7 @@ describe "Kernel#puts" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:puts)
+ Kernel.private_instance_methods(false).should.include?(:puts)
end
it "delegates to $stdout.puts" do
diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb
index a038dcf031..6162677e17 100644
--- a/spec/ruby/core/kernel/raise_spec.rb
+++ b/spec/ruby/core/kernel/raise_spec.rb
@@ -4,9 +4,19 @@ require_relative '../../shared/kernel/raise'
describe "Kernel#raise" do
it "is a private method" do
- Kernel.should have_private_instance_method(:raise)
+ Kernel.private_instance_methods.should.include?(:raise)
end
+ # Shared specs expect a public #raise method.
+ public_raiser = Object.new
+ class << public_raiser
+ public :raise
+ end
+ it_behaves_like :kernel_raise, :raise, public_raiser
+ it_behaves_like :kernel_raise_with_cause, :raise, public_raiser
+end
+
+describe "Kernel#raise with previously rescued exception" do
it "re-raises the previously rescued exception if no exception is specified" do
ScratchPad.record nil
@@ -23,51 +33,190 @@ describe "Kernel#raise" do
raise
ScratchPad.record :no_reraise
end
- end.should raise_error(Exception, "outer")
+ end.should.raise(Exception, "outer")
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
- it "accepts a cause keyword argument that sets the cause" do
- cause = StandardError.new
- -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
+ it "re-raises a previously rescued exception without overwriting the cause" do
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2
+ end
+ rescue => e
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception with overwriting the cause when it's explicitly specified with :cause option" do
+ e4 = RuntimeError.new("Error 4")
+
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2, cause: e4
+ end
+ rescue => e
+ e.cause.should == e4
+ end
end
- it "accepts a cause keyword argument that overrides the last exception" do
+ it "re-raises a previously rescued exception without overwriting the cause when it's explicitly specified with :cause option and has nil value" do
begin
- raise "first raise"
- rescue => ignored
- cause = StandardError.new
- -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2, cause: nil
+ end
+ rescue => e
+ e.cause.should == e1
end
end
- it "raises an ArgumentError when only cause is given" do
- cause = StandardError.new
- -> { raise(cause: cause) }.should raise_error(ArgumentError)
+ it "re-raises a previously rescued exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
end
- it "re-raises a rescued exception" do
- -> do
+ it "re-raises a previously rescued exception that has a cause without setting a cause implicitly" do
+ begin
begin
- raise StandardError, "aaa"
- rescue Exception
+ raise "Error 1"
+ rescue => e1
begin
- raise ArgumentError
- rescue ArgumentError
+ raise "Error 2"
+ rescue => e2
+ raise
end
+ end
+ rescue => e
+ e.should == e2
+ e.cause.should == e1
+ end
+ end
- # should raise StandardError "aaa"
- raise
+ it "re-raises a previously rescued exception that doesn't have a cause and isn't a cause of any other exception with setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ raise "Error 3"
+ end
end
- end.should raise_error(StandardError, "aaa")
+ rescue => e
+ e.message.should == "Error 3"
+ e.cause.should == e2
+ end
end
-end
-describe "Kernel#raise" do
- it_behaves_like :kernel_raise, :raise, Kernel
+ it "re-raises a previously rescued exception that doesn't have a cause and is a cause of other exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ e1.cause.should == nil
+ e2.cause.should == e1
+ raise e1
+ end
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and is a cause of other exception (that wasn't raised explicitly) without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ foo # raises NameError
+ rescue => e2
+ e1.cause.should == nil
+ e2.cause.should == e1
+ raise e1
+ end
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that has a cause but isn't a cause of any other exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ begin
+ raise "Error 3", cause: RuntimeError.new("Error 4")
+ rescue => e3
+ e2.cause.should == e1
+ e3.cause.should_not == e2
+ raise e2
+ end
+ end
+ end
+ rescue => e
+ e.should == e2
+ e.cause.should == e1
+ end
+ end
end
describe "Kernel.raise" do
- it "needs to be reviewed for spec completeness"
+ it "is a public method" do
+ Kernel.singleton_class.should.public_method_defined?(:raise)
+ end
+
+ it_behaves_like :kernel_raise, :raise, Kernel
+ it_behaves_like :kernel_raise_with_cause, :raise, Kernel
end
diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb
index 355e425792..1bf5e225d9 100644
--- a/spec/ruby/core/kernel/rand_spec.rb
+++ b/spec/ruby/core/kernel/rand_spec.rb
@@ -3,42 +3,42 @@ require_relative 'fixtures/classes'
describe "Kernel#rand" do
it "is a private method" do
- Kernel.should have_private_instance_method(:rand)
+ Kernel.private_instance_methods(false).should.include?(:rand)
end
it "returns a float if no argument is passed" do
- rand.should be_kind_of(Float)
+ rand.should.is_a?(Float)
end
it "returns an integer for an integer argument" do
- rand(77).should be_kind_of(Integer)
+ rand(77).should.is_a?(Integer)
end
it "returns an integer for a float argument greater than 1" do
- rand(1.3).should be_kind_of(Integer)
+ rand(1.3).should.is_a?(Integer)
end
it "returns a float for an argument between -1 and 1" do
- rand(-0.999).should be_kind_of(Float)
- rand(-0.01).should be_kind_of(Float)
- rand(0).should be_kind_of(Float)
- rand(0.01).should be_kind_of(Float)
- rand(0.999).should be_kind_of(Float)
+ rand(-0.999).should.is_a?(Float)
+ rand(-0.01).should.is_a?(Float)
+ rand(0).should.is_a?(Float)
+ rand(0.01).should.is_a?(Float)
+ rand(0.999).should.is_a?(Float)
end
it "ignores the sign of the argument" do
- [0, 1, 2, 3].should include(rand(-4))
+ [0, 1, 2, 3].should.include?(rand(-4))
end
it "never returns a value greater or equal to 1.0 with no arguments" do
1000.times do
- (0...1.0).should include(rand)
+ (0...1.0).should.include?(rand)
end
end
it "never returns a value greater or equal to any passed in max argument" do
1000.times do
- (0...100).to_a.should include(rand(100))
+ (0...100).to_a.should.include?(rand(100))
end
end
@@ -53,32 +53,32 @@ describe "Kernel#rand" do
it "returns an Integer between the two Integers" do
1000.times do
x = rand(4...6)
- x.should be_kind_of(Integer)
- (4...6).should include(x)
+ x.should.is_a?(Integer)
+ (4...6).should.include?(x)
end
end
it "returns a Float between the given Integer and Float" do
1000.times do
x = rand(4...6.5)
- x.should be_kind_of(Float)
- (4...6.5).should include(x)
+ x.should.is_a?(Float)
+ (4...6.5).should.include?(x)
end
end
it "returns a Float between the given Float and Integer" do
1000.times do
x = rand(3.5...6)
- x.should be_kind_of(Float)
- (3.5...6).should include(x)
+ x.should.is_a?(Float)
+ (3.5...6).should.include?(x)
end
end
it "returns a Float between the two given Floats" do
1000.times do
x = rand(3.5...6.5)
- x.should be_kind_of(Float)
- (3.5...6.5).should include(x)
+ x.should.is_a?(Float)
+ (3.5...6.5).should.include?(x)
end
end
end
@@ -87,32 +87,32 @@ describe "Kernel#rand" do
it "returns an Integer between the two Integers" do
1000.times do
x = rand(4..6)
- x.should be_kind_of(Integer)
- (4..6).should include(x)
+ x.should.is_a?(Integer)
+ (4..6).should.include?(x)
end
end
it "returns a Float between the given Integer and Float" do
1000.times do
x = rand(4..6.5)
- x.should be_kind_of(Float)
- (4..6.5).should include(x)
+ x.should.is_a?(Float)
+ (4..6.5).should.include?(x)
end
end
it "returns a Float between the given Float and Integer" do
1000.times do
x = rand(3.5..6)
- x.should be_kind_of(Float)
- (3.5..6).should include(x)
+ x.should.is_a?(Float)
+ (3.5..6).should.include?(x)
end
end
it "returns a Float between the two given Floats" do
1000.times do
x = rand(3.5..6.5)
- x.should be_kind_of(Float)
- (3.5..6.5).should include(x)
+ x.should.is_a?(Float)
+ (3.5..6.5).should.include?(x)
end
end
end
@@ -120,8 +120,8 @@ describe "Kernel#rand" do
context "given an inclusive range between 0 and 1" do
it "returns an Integer between the two Integers" do
x = rand(0..1)
- x.should be_kind_of(Integer)
- (0..1).should include(x)
+ x.should.is_a?(Integer)
+ (0..1).should.include?(x)
end
it "returns a Float if at least one side is Float" do
@@ -130,19 +130,19 @@ describe "Kernel#rand" do
x2 = Random.new(seed).rand(0.0..1.0)
x3 = Random.new(seed).rand(0.0..1)
- x3.should be_kind_of(Float)
- x1.should eql(x3)
- x2.should eql(x3)
+ x3.should.is_a?(Float)
+ x1.should.eql?(x3)
+ x2.should.eql?(x3)
- (0.0..1.0).should include(x3)
+ (0.0..1.0).should.include?(x3)
end
end
context "given an exclusive range between 0 and 1" do
it "returns zero as an Integer" do
x = rand(0...1)
- x.should be_kind_of(Integer)
- x.should eql(0)
+ x.should.is_a?(Integer)
+ x.should.eql?(0)
end
it "returns a Float if at least one side is Float" do
@@ -151,34 +151,34 @@ describe "Kernel#rand" do
x2 = Random.new(seed).rand(0.0...1.0)
x3 = Random.new(seed).rand(0.0...1)
- x3.should be_kind_of(Float)
- x1.should eql(x3)
- x2.should eql(x3)
+ x3.should.is_a?(Float)
+ x1.should.eql?(x3)
+ x2.should.eql?(x3)
- (0.0...1.0).should include(x3)
+ (0.0...1.0).should.include?(x3)
end
end
it "returns a numeric for an range argument where max is < 1" do
- rand(0.25..0.75).should be_kind_of(Numeric)
+ rand(0.25..0.75).should.is_a?(Numeric)
end
it "returns nil when range is backwards" do
- rand(1..0).should be_nil
+ rand(1..0).should == nil
end
it "returns the range start/end when Float range is 0" do
- rand(1.0..1.0).should eql(1.0)
+ rand(1.0..1.0).should.eql?(1.0)
end
it "returns the range start/end when Integer range is 0" do
- rand(42..42).should eql(42)
+ rand(42..42).should.eql?(42)
end
it "supports custom object types" do
- rand(KernelSpecs::CustomRangeInteger.new(1)..KernelSpecs::CustomRangeInteger.new(42)).should be_an_instance_of(KernelSpecs::CustomRangeInteger)
- rand(KernelSpecs::CustomRangeFloat.new(1.0)..KernelSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(KernelSpecs::CustomRangeFloat)
- rand(Time.now..Time.now).should be_an_instance_of(Time)
+ rand(KernelSpecs::CustomRangeInteger.new(1)..KernelSpecs::CustomRangeInteger.new(42)).should.instance_of?(KernelSpecs::CustomRangeInteger)
+ rand(KernelSpecs::CustomRangeFloat.new(1.0)..KernelSpecs::CustomRangeFloat.new(42.0)).should.instance_of?(KernelSpecs::CustomRangeFloat)
+ rand(Time.now..Time.now).should.instance_of?(Time)
end
it "is random on boot" do
diff --git a/spec/ruby/core/kernel/readline_spec.rb b/spec/ruby/core/kernel/readline_spec.rb
index dce7b03dc8..86899d78d2 100644
--- a/spec/ruby/core/kernel/readline_spec.rb
+++ b/spec/ruby/core/kernel/readline_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#readline" do
it "is a private method" do
- Kernel.should have_private_instance_method(:readline)
+ Kernel.private_instance_methods(false).should.include?(:readline)
end
end
diff --git a/spec/ruby/core/kernel/readlines_spec.rb b/spec/ruby/core/kernel/readlines_spec.rb
index 2b6d65fff2..c758014aab 100644
--- a/spec/ruby/core/kernel/readlines_spec.rb
+++ b/spec/ruby/core/kernel/readlines_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#readlines" do
it "is a private method" do
- Kernel.should have_private_instance_method(:readlines)
+ Kernel.private_instance_methods(false).should.include?(:readlines)
end
end
diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
index 4e5ba5e018..114536064f 100644
--- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb
+++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
@@ -9,7 +9,7 @@ describe :kernel_remove_instance_variable, shared: true do
it "removes the instance variable" do
@instance.send :remove_instance_variable, @object
- @instance.instance_variable_defined?(@object).should be_false
+ @instance.instance_variable_defined?(@object).should == false
end
end
@@ -19,39 +19,39 @@ describe "Kernel#remove_instance_variable" do
end
it "is a public method" do
- Kernel.should have_public_instance_method(:remove_instance_variable, false)
+ Kernel.public_instance_methods(false).should.include?(:remove_instance_variable)
end
it "raises a NameError if the instance variable is not defined" do
-> do
@instance.send :remove_instance_variable, :@unknown
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the argument is not a valid instance variable name" do
-> do
@instance.send :remove_instance_variable, :"@0"
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a TypeError if passed an Object not defining #to_str" do
-> do
obj = mock("kernel remove_instance_variable")
@instance.send :remove_instance_variable, obj
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a FrozenError if self is frozen" do
o = Object.new
o.freeze
- -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
- -> { o.remove_instance_variable(:foo) }.should raise_error(NameError)
+ -> { o.remove_instance_variable(:@foo) }.should.raise(FrozenError)
+ -> { o.remove_instance_variable(:foo) }.should.raise(NameError)
end
it "raises for frozen objects" do
- -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
- -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError)
- -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { nil.remove_instance_variable(:@foo) }.should.raise(FrozenError)
+ -> { nil.remove_instance_variable(:foo) }.should.raise(NameError)
+ -> { :foo.remove_instance_variable(:@foo) }.should.raise(FrozenError)
end
describe "when passed a String" do
diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb
index 6188d13a4e..332045b200 100644
--- a/spec/ruby/core/kernel/require_relative_spec.rb
+++ b/spec/ruby/core/kernel/require_relative_spec.rb
@@ -27,14 +27,14 @@ describe "Kernel#require_relative with a relative path" do
end
it "loads a path relative to current file" do
- require_relative(@link).should be_true
+ require_relative(@link).should == true
ScratchPad.recorded.should == [:loaded]
end
end
end
it "loads a path relative to the current file" do
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -42,14 +42,14 @@ describe "Kernel#require_relative with a relative path" do
it "synthetic file base name loads a file base name relative to the working directory" do
Dir.chdir @abs_dir do
- Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "foo.rb").should be_true
+ Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "foo.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
it "synthetic file path loads a relative path relative to the working directory plus the directory of the synthetic path" do
Dir.chdir @abs_dir do
- Object.new.instance_eval("require_relative(File.join('..', #{File.basename(@path).inspect}))", "bar/foo.rb").should be_true
+ Object.new.instance_eval("require_relative(File.join('..', #{File.basename(@path).inspect}))", "bar/foo.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -57,14 +57,14 @@ describe "Kernel#require_relative with a relative path" do
platform_is_not :windows do
it "synthetic relative file path with a Windows path separator specified loads a relative path relative to the working directory" do
Dir.chdir @abs_dir do
- Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "bar\\foo.rb").should be_true
+ Object.new.instance_eval("require_relative(#{File.basename(@path).inspect})", "bar\\foo.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
end
it "absolute file path loads a path relative to the absolute path" do
- Object.new.instance_eval("require_relative(#{@path.inspect})", __FILE__).should be_true
+ Object.new.instance_eval("require_relative(#{@path.inspect})", __FILE__).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -74,34 +74,34 @@ describe "Kernel#require_relative with a relative path" do
root = File.dirname(root)
end
root_relative = @abs_path[root.size..-1]
- Object.new.instance_eval("require_relative(#{root_relative.inspect})", "/").should be_true
+ Object.new.instance_eval("require_relative(#{root_relative.inspect})", "/").should == true
ScratchPad.recorded.should == [:loaded]
end
end
it "loads a file defining many methods" do
- require_relative("#{@dir}/methods_fixture.rb").should be_true
+ require_relative("#{@dir}/methods_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
- -> { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ -> { require_relative("#{@dir}/nonexistent.rb") }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
it "raises a LoadError that includes the missing path" do
missing_path = "#{@dir}/nonexistent.rb"
expanded_missing_path = File.expand_path(missing_path, __dir__)
- -> { require_relative(missing_path) }.should raise_error(LoadError) { |e|
- e.message.should include(expanded_missing_path)
+ -> { require_relative(missing_path) }.should.raise(LoadError) { |e|
+ e.message.should.include?(expanded_missing_path)
e.path.should == expanded_missing_path
}
ScratchPad.recorded.should == []
end
it "raises a LoadError if basepath does not exist" do
- -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
+ -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should.raise(LoadError)
end
it "stores the missing path in a LoadError object" do
@@ -117,34 +117,34 @@ describe "Kernel#require_relative with a relative path" do
it "calls #to_str on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a TypeError if argument does not respond to #to_str" do
- -> { require_relative(nil) }.should raise_error(TypeError)
- -> { require_relative(42) }.should raise_error(TypeError)
+ -> { require_relative(nil) }.should.raise(TypeError)
+ -> { require_relative(42) }.should.raise(TypeError)
-> {
require_relative([@path,@path])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
name = mock("load_fixture.rb mock")
name.stub!(:to_s).and_return(@path)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "calls #to_path on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_path).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -153,13 +153,13 @@ describe "Kernel#require_relative with a relative path" do
to_path = mock("load_fixture_rb #to_path mock")
name.should_receive(:to_path).and_return(to_path)
to_path.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
describe "(file extensions)" do
it "loads a .rb extensioned file when passed a non-extensioned path" do
- require_relative("#{@dir}/load_fixture").should be_true
+ require_relative("#{@dir}/load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -168,20 +168,20 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dll"
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a .rb extensioned file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.rb"
- require_relative("#{@dir}/load_fixture").should be_false
+ require_relative("#{@dir}/load_fixture").should == false
ScratchPad.recorded.should == []
end
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded" do
@@ -189,22 +189,22 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dll"
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.rb"
- require_relative("#{@dir}/load_fixture.ext").should be_false
+ require_relative("#{@dir}/load_fixture.ext").should == false
ScratchPad.recorded.should == []
end
end
describe "($LOADED_FEATURES)" do
it "stores an absolute path" do
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
end
platform_is_not :windows, :wasi do
@@ -231,8 +231,8 @@ describe "Kernel#require_relative with a relative path" do
ScratchPad.recorded.should == [:loaded]
features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
- features.should include(absolute_path)
- features.should_not include(canonical_path)
+ features.should.include?(absolute_path)
+ features.should_not.include?(canonical_path)
end
it "stores the same path that __FILE__ returns in the required file" do
@@ -249,26 +249,26 @@ describe "Kernel#require_relative with a relative path" do
it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup
- -> { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { require_relative("#{@dir}/raise_fixture.rb") }.should.raise(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
it "does not load an absolute path that is already stored" do
$LOADED_FEATURES << @abs_path
- require_relative(@path).should be_false
+ require_relative(@path).should == false
ScratchPad.recorded.should == []
end
it "adds the suffix of the resolved filename" do
- require_relative("#{@dir}/load_fixture").should be_true
- $LOADED_FEATURES.should include("#{@abs_dir}/load_fixture.rb")
+ require_relative("#{@dir}/load_fixture").should == true
+ $LOADED_FEATURES.should.include?("#{@abs_dir}/load_fixture.rb")
end
it "loads a path for a file already loaded with a relative path" do
$LOAD_PATH << File.expand_path(@dir)
$LOADED_FEATURES << "load_fixture.rb" << "load_fixture"
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
ScratchPad.recorded.should == [:loaded]
end
end
@@ -288,22 +288,22 @@ describe "Kernel#require_relative with an absolute path" do
end
it "loads a path relative to the current file" do
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file defining many methods" do
- require_relative("#{@dir}/methods_fixture.rb").should be_true
+ require_relative("#{@dir}/methods_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
- -> { require_relative("#{@dir}/nonexistent.rb") }.should raise_error(LoadError)
+ -> { require_relative("#{@dir}/nonexistent.rb") }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
it "raises a LoadError if basepath does not exist" do
- -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should raise_error(LoadError)
+ -> { eval("require_relative('#{@dir}/nonexistent.rb')") }.should.raise(LoadError)
end
it "stores the missing path in a LoadError object" do
@@ -319,34 +319,34 @@ describe "Kernel#require_relative with an absolute path" do
it "calls #to_str on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a TypeError if argument does not respond to #to_str" do
- -> { require_relative(nil) }.should raise_error(TypeError)
- -> { require_relative(42) }.should raise_error(TypeError)
+ -> { require_relative(nil) }.should.raise(TypeError)
+ -> { require_relative(42) }.should.raise(TypeError)
-> {
require_relative([@path,@path])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
name = mock("load_fixture.rb mock")
name.stub!(:to_s).and_return(@path)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- -> { require_relative(name) }.should raise_error(TypeError)
+ -> { require_relative(name) }.should.raise(TypeError)
end
it "calls #to_path on non-String objects" do
name = mock("load_fixture.rb mock")
name.should_receive(:to_path).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -355,13 +355,13 @@ describe "Kernel#require_relative with an absolute path" do
to_path = mock("load_fixture_rb #to_path mock")
name.should_receive(:to_path).and_return(to_path)
to_path.should_receive(:to_str).and_return(@path)
- require_relative(name).should be_true
+ require_relative(name).should == true
ScratchPad.recorded.should == [:loaded]
end
describe "(file extensions)" do
it "loads a .rb extensioned file when passed a non-extensioned path" do
- require_relative("#{@dir}/load_fixture").should be_true
+ require_relative("#{@dir}/load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -370,20 +370,20 @@ describe "Kernel#require_relative with an absolute path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.dll"
- require_relative(@path).should be_true
+ require_relative(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a .rb extensioned file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.rb"
- require_relative("#{@dir}/load_fixture").should be_false
+ require_relative("#{@dir}/load_fixture").should == false
ScratchPad.recorded.should == []
end
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded" do
@@ -391,46 +391,46 @@ describe "Kernel#require_relative with an absolute path" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dylib"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.so"
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.dll"
- require_relative("#{@dir}/load_fixture.ext").should be_true
+ require_relative("#{@dir}/load_fixture.ext").should == true
ScratchPad.recorded.should == [:loaded]
- $LOADED_FEATURES.should include "#{@abs_dir}/load_fixture.ext.rb"
+ $LOADED_FEATURES.should.include? "#{@abs_dir}/load_fixture.ext.rb"
end
it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
$LOADED_FEATURES << "#{@abs_dir}/load_fixture.ext.rb"
- require_relative("#{@dir}/load_fixture.ext").should be_false
+ require_relative("#{@dir}/load_fixture.ext").should == false
ScratchPad.recorded.should == []
end
end
describe "($LOAD_FEATURES)" do
it "stores an absolute path" do
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
end
it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup
- -> { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { require_relative("#{@dir}/raise_fixture.rb") }.should.raise(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
it "does not load an absolute path that is already stored" do
$LOADED_FEATURES << @abs_path
- require_relative(@path).should be_false
+ require_relative(@path).should == false
ScratchPad.recorded.should == []
end
it "adds the suffix of the resolved filename" do
- require_relative("#{@dir}/load_fixture").should be_true
- $LOADED_FEATURES.should include("#{@abs_dir}/load_fixture.rb")
+ require_relative("#{@dir}/load_fixture").should == true
+ $LOADED_FEATURES.should.include?("#{@abs_dir}/load_fixture.rb")
end
it "loads a path for a file already loaded with a relative path" do
$LOAD_PATH << File.expand_path(@dir)
$LOADED_FEATURES << "load_fixture.rb" << "load_fixture"
- require_relative(@path).should be_true
- $LOADED_FEATURES.should include(@abs_path)
+ require_relative(@path).should == true
+ $LOADED_FEATURES.should.include?(@abs_path)
ScratchPad.recorded.should == [:loaded]
end
end
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index e78e7176ec..62d954c2bf 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -13,24 +13,40 @@ describe "Kernel#require" do
# if this fails, update your rubygems
it "is a private method" do
- Kernel.should have_private_instance_method(:require)
+ Kernel.private_instance_methods(false).should.include?(:require)
end
- provided = %w[complex enumerator fiber rational thread ruby2_keywords]
+ it "provided features are already required" do
+ provided = %w[complex enumerator fiber rational thread ruby2_keywords]
+ ruby_version_is "4.0" do
+ provided += %w[set pathname]
+ end
+ ruby_version_is "4.1" do
+ provided += %w[monitor]
+ end
- it "#{provided.join(', ')} are already required" do
out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
- features = out.lines.map { |line| File.basename(line.chomp, '.*') }
+ features = out.lines.map(&:chomp)
- # Ignore CRuby internals
- features -= %w[encdb transdb windows_1252 windows_31j]
- features.reject! { |feature| feature.end_with?('-fake') }
+ # Ignore engine-specific internals
+ case RUBY_ENGINE
+ when "jruby"
+ features -= %w[java.rb jruby/util.rb]
+ when "ruby"
+ so = RbConfig::CONFIG['DLEXT']
+ features -= ["windows_1252.#{so}", "windows_31.#{so}"]
+ features.reject! { |feature| feature.end_with? "encdb.#{so}" }
+ features.reject! { |feature| feature.end_with? "transdb.#{so}" }
+ features.reject! { |feature| feature.include?('-fake') }
+ end
- features.sort.should == provided.sort
+ features_no_ext = features.map { |path| File.basename(path, '.*') }
+ features_no_ext.sort.should == provided.sort
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ requires = features
+ code = requires.map { |f| "puts require #{f.inspect}\n" }.join
required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
+ required.should == "false\n" * requires.size
end
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
diff --git a/spec/ruby/core/kernel/respond_to_missing_spec.rb b/spec/ruby/core/kernel/respond_to_missing_spec.rb
index cc82031e26..08c9184fb4 100644
--- a/spec/ruby/core/kernel/respond_to_missing_spec.rb
+++ b/spec/ruby/core/kernel/respond_to_missing_spec.rb
@@ -7,7 +7,7 @@ describe "Kernel#respond_to_missing?" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:respond_to_missing?, false)
+ Kernel.private_instance_methods(false).should.include?(:respond_to_missing?)
end
it "is only an instance method" do
@@ -18,7 +18,7 @@ describe "Kernel#respond_to_missing?" do
obj = mock('object')
obj.stub!(:glark)
obj.should_not_receive(:respond_to_missing?)
- obj.respond_to?(:glark).should be_true
+ obj.respond_to?(:glark).should == true
end
it "is called with a 2nd argument of false when #respond_to? is" do
@@ -48,39 +48,39 @@ describe "Kernel#respond_to_missing?" do
it "causes #respond_to? to return true if called and not returning false" do
obj = mock('object')
obj.should_receive(:respond_to_missing?).with(:undefined_method, false).and_return(:glark)
- obj.respond_to?(:undefined_method).should be_true
+ obj.respond_to?(:undefined_method).should == true
end
it "causes #respond_to? to return false if called and returning false" do
obj = mock('object')
obj.should_receive(:respond_to_missing?).with(:undefined_method, false).and_return(false)
- obj.respond_to?(:undefined_method).should be_false
+ obj.respond_to?(:undefined_method).should == false
end
it "causes #respond_to? to return false if called and returning nil" do
obj = mock('object')
obj.should_receive(:respond_to_missing?).with(:undefined_method, false).and_return(nil)
- obj.respond_to?(:undefined_method).should be_false
+ obj.respond_to?(:undefined_method).should == false
end
it "isn't called when obj responds to the given public method" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:pub_method).should be_true
+ @a.respond_to?(:pub_method).should == true
end
it "isn't called when obj responds to the given public method, include_private = true" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:pub_method, true).should be_true
+ @a.respond_to?(:pub_method, true).should == true
end
it "is called when obj responds to the given protected method, include_private = false" do
@a.should_receive(:respond_to_missing?)
- @a.respond_to?(:protected_method, false).should be_false
+ @a.respond_to?(:protected_method, false).should == false
end
it "isn't called when obj responds to the given protected method, include_private = true" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:protected_method, true).should be_true
+ @a.respond_to?(:protected_method, true).should == true
end
it "is called when obj responds to the given private method, include_private = false" do
@@ -90,7 +90,7 @@ describe "Kernel#respond_to_missing?" do
it "isn't called when obj responds to the given private method, include_private = true" do
@a.should_not_receive(:respond_to_missing?)
- @a.respond_to?(:private_method, true).should be_true
+ @a.respond_to?(:private_method, true).should == true
end
it "is called for missing class methods" do
diff --git a/spec/ruby/core/kernel/respond_to_spec.rb b/spec/ruby/core/kernel/respond_to_spec.rb
index 5b3ea3f651..72ab4eebe1 100644
--- a/spec/ruby/core/kernel/respond_to_spec.rb
+++ b/spec/ruby/core/kernel/respond_to_spec.rb
@@ -7,7 +7,7 @@ describe "Kernel#respond_to?" do
end
it "is a public method" do
- Kernel.should have_public_instance_method(:respond_to?, false)
+ Kernel.public_instance_methods(false).should.include?(:respond_to?)
end
it "is only an instance method" do
@@ -25,7 +25,7 @@ describe "Kernel#respond_to?" do
end
it "throws a type error if argument can't be coerced into a Symbol" do
- -> { @a.respond_to?(Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { @a.respond_to?(Object.new) }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "returns false if obj responds to the given protected method" do
@@ -61,7 +61,7 @@ describe "Kernel#respond_to?" do
it "does not change method visibility when finding private method" do
KernelSpecs::VisibilityChange.respond_to?(:new, false).should == false
KernelSpecs::VisibilityChange.respond_to?(:new, true).should == true
- -> { KernelSpecs::VisibilityChange.new }.should raise_error(NoMethodError)
+ -> { KernelSpecs::VisibilityChange.new }.should.raise(NoMethodError)
end
it "indicates if an object responds to a particular message" do
@@ -69,4 +69,31 @@ describe "Kernel#respond_to?" do
KernelSpecs::Foo.new.respond_to?(:bar).should == true
KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false
end
+
+ context "if object does not have #respond_to_missing?" do
+ it "returns true if object responds to the given public method" do
+ KernelSpecs::BasicA.new.respond_to?(:pub_method).should == true
+ KernelSpecs::MissingA.new.respond_to?(:pub_method).should == true
+ end
+
+ it "returns false if object responds to the given protected method" do
+ KernelSpecs::BasicA.new.respond_to?(:protected_method).should == false
+ KernelSpecs::MissingA.new.respond_to?(:protected_method).should == false
+ end
+
+ it "returns false if object responds to the given private method" do
+ KernelSpecs::BasicA.new.respond_to?(:private_method).should == false
+ KernelSpecs::MissingA.new.respond_to?(:private_method).should == false
+ end
+
+ it "returns false if the given method was undefined" do
+ KernelSpecs::BasicA.new.respond_to?(:undefed_method).should == false
+ KernelSpecs::MissingA.new.respond_to?(:undefed_method).should == false
+ end
+
+ it "returns false if the given method never existed" do
+ KernelSpecs::BasicA.new.respond_to?(:invalid_and_silly_method_name).should == false
+ KernelSpecs::MissingA.new.respond_to?(:invalid_and_silly_method_name).should == false
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/select_spec.rb b/spec/ruby/core/kernel/select_spec.rb
index df23414b28..58c963c1a4 100644
--- a/spec/ruby/core/kernel/select_spec.rb
+++ b/spec/ruby/core/kernel/select_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#select" do
it "is a private method" do
- Kernel.should have_private_instance_method(:select)
+ Kernel.private_instance_methods(false).should.include?(:select)
end
end
diff --git a/spec/ruby/core/kernel/set_trace_func_spec.rb b/spec/ruby/core/kernel/set_trace_func_spec.rb
index 1f43e7a009..5201812f2f 100644
--- a/spec/ruby/core/kernel/set_trace_func_spec.rb
+++ b/spec/ruby/core/kernel/set_trace_func_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#set_trace_func" do
it "is a private method" do
- Kernel.should have_private_instance_method(:set_trace_func)
+ Kernel.private_instance_methods(false).should.include?(:set_trace_func)
end
end
diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb
index 4fac6006e1..3fbf918283 100644
--- a/spec/ruby/core/kernel/shared/dup_clone.rb
+++ b/spec/ruby/core/kernel/shared/dup_clone.rb
@@ -40,7 +40,7 @@ describe :kernel_dup_clone, shared: true do
o.obj = array
o2 = o.send(@method)
- o2.obj.should equal(o.obj)
+ o2.obj.should.equal?(o.obj)
end
it "calls #initialize_copy on the NEW object if available, passing in original object" do
@@ -49,7 +49,7 @@ describe :kernel_dup_clone, shared: true do
o.obj.should == :original
o2.obj.should == :init_copy
- o2.original.should equal(o)
+ o2.original.should.equal?(o)
end
it "does not preserve the object_id" do
@@ -81,11 +81,11 @@ describe :kernel_dup_clone, shared: true do
it "returns self for Complex" do
c = Complex(1.3, 3.1)
- c.send(@method).should equal c
+ c.send(@method).should.equal? c
end
it "returns self for Rational" do
r = Rational(1, 3)
- r.send(@method).should equal r
+ r.send(@method).should.equal? r
end
end
diff --git a/spec/ruby/core/kernel/shared/kind_of.rb b/spec/ruby/core/kernel/shared/kind_of.rb
index aef6f1c1d8..a5e0eab08f 100644
--- a/spec/ruby/core/kernel/shared/kind_of.rb
+++ b/spec/ruby/core/kernel/shared/kind_of.rb
@@ -40,10 +40,10 @@ describe :kernel_kind_of, shared: true do
end
it "raises a TypeError if given an object that is not a Class nor a Module" do
- -> { @o.send(@method, 1) }.should raise_error(TypeError)
- -> { @o.send(@method, 'KindaClass') }.should raise_error(TypeError)
- -> { @o.send(@method, :KindaClass) }.should raise_error(TypeError)
- -> { @o.send(@method, Object.new) }.should raise_error(TypeError)
+ -> { @o.send(@method, 1) }.should.raise(TypeError)
+ -> { @o.send(@method, 'KindaClass') }.should.raise(TypeError)
+ -> { @o.send(@method, :KindaClass) }.should.raise(TypeError)
+ -> { @o.send(@method, Object.new) }.should.raise(TypeError)
end
it "does not take into account `class` method overriding" do
diff --git a/spec/ruby/core/kernel/shared/lambda.rb b/spec/ruby/core/kernel/shared/lambda.rb
index c70640082a..83de06bb41 100644
--- a/spec/ruby/core/kernel/shared/lambda.rb
+++ b/spec/ruby/core/kernel/shared/lambda.rb
@@ -5,7 +5,7 @@ describe :kernel_lambda, shared: true do
it "raises an ArgumentError when no block is given" do
suppress_warning do
- -> { send(@method) }.should raise_error(ArgumentError)
+ -> { send(@method) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 62c5c7be9b..20d23a623e 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -15,19 +15,19 @@ describe :kernel_load, shared: true do
# This behavior is specific to Kernel#load, it differs for Kernel#require
it "loads a non-extensioned file as a Ruby source file" do
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.load(path).should be_true
+ @object.load(path).should == true
ScratchPad.recorded.should == [:no_ext]
end
it "loads a non .rb extensioned file as a Ruby source file" do
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.load(path).should be_true
+ @object.load(path).should == true
ScratchPad.recorded.should == [:no_rb_ext]
end
it "loads from the current working directory" do
Dir.chdir CODE_LOADING_DIR do
- @object.load("load_fixture.rb").should be_true
+ @object.load("load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
end
@@ -35,88 +35,88 @@ describe :kernel_load, shared: true do
# This behavior is specific to Kernel#load, it differs for Kernel#require
it "does not look for a c-extension file when passed a path without extension (when no .rb is present)" do
path = File.join CODE_LOADING_DIR, "a", "load_fixture"
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
end
end
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
- @object.load(path).should be_true
+ @object.load(path).should == true
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file that recursively loads itself" do
path = File.expand_path "recursive_load_fixture.rb", CODE_LOADING_DIR
- @object.load(path).should be_true
+ @object.load(path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file each time the method is called" do
- @object.load(@path).should be_true
- @object.load(@path).should be_true
+ @object.load(@path).should == true
+ @object.load(@path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file even when the name appears in $LOADED_FEATURES" do
$LOADED_FEATURES << @path
- @object.load(@path).should be_true
+ @object.load(@path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file that has been loaded by #require" do
- @object.require(@path).should be_true
- @object.load(@path).should be_true
+ @object.require(@path).should == true
+ @object.load(@path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads file even after $LOAD_PATH change" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.load("load_fixture.rb").should be_true
+ @object.load("load_fixture.rb").should == true
$LOAD_PATH.unshift CODE_LOADING_DIR + "/gem"
- @object.load("load_fixture.rb").should be_true
+ @object.load("load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded, :loaded_gem]
end
it "does not cause #require with the same path to fail" do
- @object.load(@path).should be_true
- @object.require(@path).should be_true
+ @object.load(@path).should == true
+ @object.require(@path).should == true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "does not add the loaded path to $LOADED_FEATURES" do
saved_loaded_features = $LOADED_FEATURES.dup
- @object.load(@path).should be_true
+ @object.load(@path).should == true
$LOADED_FEATURES.should == saved_loaded_features
end
it "raises a LoadError if passed a non-extensioned path that does not exist but a .rb extensioned path does exist" do
path = File.expand_path "load_ext_fixture", CODE_LOADING_DIR
- -> { @object.load(path) }.should raise_error(LoadError)
+ -> { @object.load(path) }.should.raise(LoadError)
end
describe "when passed true for 'wrap'" do
it "loads from an existing path" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
- @object.load(path, true).should be_true
+ @object.load(path, true).should == true
end
it "sets the enclosing scope to an anonymous module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
- Object.const_defined?(:LoadSpecWrap).should be_false
+ Object.const_defined?(:LoadSpecWrap).should == false
wrap_module = ScratchPad.recorded[1]
- wrap_module.should be_an_instance_of(Module)
+ wrap_module.should.instance_of?(Module)
end
it "allows referencing outside namespaces" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
- ScratchPad.recorded[0].should equal(String)
+ ScratchPad.recorded[0].should.equal?(String)
end
it "sets self as a copy of the top-level main" do
@@ -126,8 +126,8 @@ describe :kernel_load, shared: true do
top_level = ScratchPad.recorded[2]
top_level.to_s.should == "main"
top_level.method(:to_s).owner.should == top_level.singleton_class
- top_level.should_not equal(main)
- top_level.should be_an_instance_of(Object)
+ top_level.should_not.equal?(main)
+ top_level.should.instance_of?(Object)
end
it "includes modules included in main's singleton class in self's class" do
@@ -159,7 +159,7 @@ describe :kernel_load, shared: true do
end
it "does not pollute the receiver" do
- -> { @object.send(:top_level_method) }.should raise_error(NameError)
+ -> { @object.send(:top_level_method) }.should.raise(NameError)
end
end
end
@@ -170,8 +170,8 @@ describe :kernel_load, shared: true do
mod = Module.new
@object.load(path, mod)
- Object.const_defined?(:LoadSpecWrap).should be_false
- mod.const_defined?(:LoadSpecWrap).should be_true
+ Object.const_defined?(:LoadSpecWrap).should == false
+ mod.const_defined?(:LoadSpecWrap).should == true
wrap_module = ScratchPad.recorded[1]
wrap_module.should == mod
@@ -208,7 +208,7 @@ describe :kernel_load, shared: true do
end
it "expands a tilde to the HOME environment variable as the path to load" do
- @object.require("~/load_fixture.rb").should be_true
+ @object.require("~/load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
end
diff --git a/spec/ruby/core/kernel/shared/method.rb b/spec/ruby/core/kernel/shared/method.rb
index 8b6ab23fd3..82abc287d1 100644
--- a/spec/ruby/core/kernel/shared/method.rb
+++ b/spec/ruby/core/kernel/shared/method.rb
@@ -4,26 +4,26 @@ describe :kernel_method, shared: true do
it "returns a method object for a valid method" do
class KernelSpecs::Foo; def bar; 'done'; end; end
m = KernelSpecs::Foo.new.send(@method, :bar)
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call.should == 'done'
end
it "returns a method object for a valid singleton method" do
class KernelSpecs::Foo; def self.bar; 'class done'; end; end
m = KernelSpecs::Foo.send(@method, :bar)
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call.should == 'class done'
end
it "returns a method object if respond_to_missing?(method) is true" do
m = KernelSpecs::RespondViaMissing.new.send(@method, :handled_publicly)
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call(42).should == "Done handled_publicly([42])"
end
it "the returned method object if respond_to_missing?(method) calls #method_missing with a Symbol name" do
m = KernelSpecs::RespondViaMissing.new.send(@method, "handled_publicly")
- m.should be_an_instance_of Method
+ m.should.instance_of? Method
m.call(42).should == "Done handled_publicly([42])"
end
@@ -31,12 +31,12 @@ describe :kernel_method, shared: true do
class KernelSpecs::Foo; def bar; 'done'; end; end
-> {
KernelSpecs::Foo.new.send(@method, :invalid_and_silly_method_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "raises a NameError for an invalid singleton method name" do
class KernelSpecs::Foo; def self.bar; 'done'; end; end
- -> { KernelSpecs::Foo.send(@method, :baz) }.should raise_error(NameError)
+ -> { KernelSpecs::Foo.send(@method, :baz) }.should.raise(NameError)
end
it "changes the method called for super on a target aliased method" do
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index b31c89e3bf..6272b00665 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -2,26 +2,26 @@ describe :kernel_require_basic, shared: true do
describe "(path resolution)" do
it "loads an absolute path" do
path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a non-canonical absolute path" do
path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file defining many methods" do
path = File.expand_path "methods_fixture.rb", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a LoadError if the file does not exist" do
path = File.expand_path "nonexistent.rb", CODE_LOADING_DIR
File.should_not.exist?(path)
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
@@ -42,7 +42,7 @@ describe :kernel_require_basic, shared: true do
it "raises a LoadError" do
File.should.exist?(@path)
- -> { @object.send(@method, @path) }.should raise_error(LoadError)
+ -> { @object.send(@method, @path) }.should.raise(LoadError)
end
end
end
@@ -52,24 +52,24 @@ describe :kernel_require_basic, shared: true do
path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
name = mock("load_fixture.rb mock")
name.should_receive(:to_str).and_return(path)
- @object.send(@method, name).should be_true
+ @object.send(@method, name).should == true
ScratchPad.recorded.should == [:loaded]
end
it "raises a TypeError if passed nil" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer" do
- -> { @object.send(@method, 42) }.should raise_error(TypeError)
+ -> { @object.send(@method, 42) }.should.raise(TypeError)
end
it "raises a TypeError if passed an Array" do
- -> { @object.send(@method, []) }.should raise_error(TypeError)
+ -> { @object.send(@method, []) }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not provide #to_str" do
- -> { @object.send(@method, mock("not a filename")) }.should raise_error(TypeError)
+ -> { @object.send(@method, mock("not a filename")) }.should.raise(TypeError)
end
it "raises a TypeError if passed an object that has #to_s but not #to_str" do
@@ -77,14 +77,14 @@ describe :kernel_require_basic, shared: true do
name.stub!(:to_s).and_return("load_fixture.rb")
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- -> { @object.send(@method, name) }.should raise_error(TypeError)
+ -> { @object.send(@method, name) }.should.raise(TypeError)
end
end
it "raises a TypeError if #to_str does not return a String" do
name = mock("#to_str returns nil")
name.should_receive(:to_str).at_least(1).times.and_return(nil)
- -> { @object.send(@method, name) }.should raise_error(TypeError)
+ -> { @object.send(@method, name) }.should.raise(TypeError)
end
it "calls #to_path on non-String objects" do
@@ -92,7 +92,7 @@ describe :kernel_require_basic, shared: true do
name.stub!(:to_path).and_return("load_fixture.rb")
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, name).should be_true
+ @object.send(@method, name).should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -101,7 +101,7 @@ describe :kernel_require_basic, shared: true do
path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
str = mock("load_fixture.rb mock")
str.should_receive(:to_path).and_return(path)
- @object.send(@method, str).should be_true
+ @object.send(@method, str).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -111,21 +111,21 @@ describe :kernel_require_basic, shared: true do
to_path = mock("load_fixture_rb #to_path mock")
name.should_receive(:to_path).and_return(to_path)
to_path.should_receive(:to_str).and_return(path)
- @object.send(@method, name).should be_true
+ @object.send(@method, name).should == true
ScratchPad.recorded.should == [:loaded]
end
# "http://redmine.ruby-lang.org/issues/show/2578"
it "loads a ./ relative path from the current working directory with empty $LOAD_PATH" do
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "./load_fixture.rb").should be_true
+ @object.send(@method, "./load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
it "loads a ../ relative path from the current working directory with empty $LOAD_PATH" do
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture.rb").should be_true
+ @object.send(@method, "../code/load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -133,7 +133,7 @@ describe :kernel_require_basic, shared: true do
it "loads a ./ relative path from the current working directory with non-empty $LOAD_PATH" do
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "./load_fixture.rb").should be_true
+ @object.send(@method, "./load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -141,7 +141,7 @@ describe :kernel_require_basic, shared: true do
it "loads a ../ relative path from the current working directory with non-empty $LOAD_PATH" do
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture.rb").should be_true
+ @object.send(@method, "../code/load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -149,14 +149,14 @@ describe :kernel_require_basic, shared: true do
it "loads a non-canonical path from the current working directory with non-empty $LOAD_PATH" do
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/../code/load_fixture.rb").should be_true
+ @object.send(@method, "../code/../code/load_fixture.rb").should == true
end
ScratchPad.recorded.should == [:loaded]
end
it "resolves a filename against $LOAD_PATH entries" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.send(@method, "load_fixture.rb").should be_true
+ @object.send(@method, "load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -164,15 +164,15 @@ describe :kernel_require_basic, shared: true do
obj = mock("to_path")
obj.should_receive(:to_path).at_least(:once).and_return(CODE_LOADING_DIR)
$LOAD_PATH << obj
- @object.send(@method, "load_fixture.rb").should be_true
+ @object.send(@method, "load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not require file twice after $LOAD_PATH change" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture.rb").should be_true
+ @object.require("load_fixture.rb").should == true
$LOAD_PATH.push CODE_LOADING_DIR + "/gem"
- @object.require("load_fixture.rb").should be_false
+ @object.require("load_fixture.rb").should == false
ScratchPad.recorded.should == [:loaded]
end
@@ -180,7 +180,7 @@ describe :kernel_require_basic, shared: true do
$LOAD_PATH << CODE_LOADING_DIR
-> do
@object.send(@method, "./load_fixture.rb")
- end.should raise_error(LoadError)
+ end.should.raise(LoadError)
ScratchPad.recorded.should == []
end
@@ -188,13 +188,13 @@ describe :kernel_require_basic, shared: true do
$LOAD_PATH << CODE_LOADING_DIR
-> do
@object.send(@method, "../code/load_fixture.rb")
- end.should raise_error(LoadError)
+ end.should.raise(LoadError)
ScratchPad.recorded.should == []
end
it "resolves a non-canonical path against $LOAD_PATH entries" do
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.send(@method, "code/../code/load_fixture.rb").should be_true
+ @object.send(@method, "code/../code/load_fixture.rb").should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -203,7 +203,7 @@ describe :kernel_require_basic, shared: true do
sep = File::Separator + File::Separator
path = ["..", "code", "load_fixture.rb"].join(sep)
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
end
ScratchPad.recorded.should == [:loaded]
end
@@ -214,7 +214,7 @@ describe :kernel_require, shared: true do
describe "(path resolution)" do
it "loads .rb file when passed absolute path without extension" do
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
+ @object.send(@method, path).should == true
# This should _not_ be [:no_ext]
ScratchPad.recorded.should == [:loaded]
end
@@ -223,7 +223,7 @@ describe :kernel_require, shared: true do
it "loads c-extension file when passed absolute path without extension when no .rb is present" do
# the error message is specific to what dlerror() returns
path = File.join CODE_LOADING_DIR, "a", "load_fixture"
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
end
end
@@ -231,20 +231,20 @@ describe :kernel_require, shared: true do
it "loads .bundle file when passed absolute path with .so" do
# the error message is specific to what dlerror() returns
path = File.join CODE_LOADING_DIR, "a", "load_fixture.so"
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
end
end
it "does not try an extra .rb if the path already ends in .rb" do
path = File.join CODE_LOADING_DIR, "d", "load_fixture.rb"
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ -> { @object.send(@method, path) }.should.raise(LoadError)
end
# For reference see [ruby-core:24155] in which matz confirms this feature is
# intentional for security reasons.
it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do
Dir.chdir CODE_LOADING_DIR do
- -> { @object.require("load_fixture.rb") }.should raise_error(LoadError)
+ -> { @object.require("load_fixture.rb") }.should.raise(LoadError)
ScratchPad.recorded.should == []
end
end
@@ -253,7 +253,7 @@ describe :kernel_require, shared: true do
Dir.chdir File.dirname(CODE_LOADING_DIR) do
-> do
@object.require("code/load_fixture.rb")
- end.should raise_error(LoadError)
+ end.should.raise(LoadError)
ScratchPad.recorded.should == []
end
end
@@ -261,20 +261,18 @@ describe :kernel_require, shared: true do
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
- @object.require(path).should be_true
+ @object.require(path).should == true
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded]
end
- ruby_bug "#17340", ''...'3.3' do
- it "loads a file concurrently" do
- path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
- ScratchPad.record(@object)
- -> {
- @object.require(path)
- }.should_not complain(/circular require considered harmful/, verbose: true)
- ScratchPad.recorded.join
- end
+ it "loads a file concurrently" do
+ path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
+ ScratchPad.record(@object)
+ -> {
+ @object.require(path)
+ }.should_not complain(/circular require considered harmful/, verbose: true)
+ ScratchPad.recorded.join
end
end
@@ -286,15 +284,25 @@ describe :kernel_require, shared: true do
end
it "loads a .rb extensioned file when a C-extension file exists on an earlier load path" do
- @object.require("load_fixture").should be_true
+ @object.require("load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a feature twice when $LOAD_PATH has been modified" do
$LOAD_PATH.replace [CODE_LOADING_DIR]
- @object.require("load_fixture").should be_true
+ @object.require("load_fixture").should == true
$LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
- @object.require("load_fixture").should be_false
+ @object.require("load_fixture").should == false
+ end
+
+ it "stores the missing path in a LoadError object" do
+ path = "abcd1234"
+
+ -> {
+ @object.send(@method, path)
+ }.should.raise(LoadError) { |e|
+ e.path.should == path
+ }
end
end
@@ -302,7 +310,7 @@ describe :kernel_require, shared: true do
it "loads a .rb extensioned file when passed a non-extensioned path" do
path = File.expand_path "load_fixture", CODE_LOADING_DIR
File.should.exist?(path)
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -312,21 +320,21 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << File.expand_path("load_fixture.so", CODE_LOADING_DIR)
$LOADED_FEATURES << File.expand_path("load_fixture.dll", CODE_LOADING_DIR)
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a .rb extensioned file is already loaded" do
$LOADED_FEATURES << File.expand_path("load_fixture.rb", CODE_LOADING_DIR)
path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.require(path).should be_false
+ @object.require(path).should == false
ScratchPad.recorded.should == []
end
it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
File.should.exist?(path)
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
@@ -336,14 +344,14 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << File.expand_path("load_fixture.ext.so", CODE_LOADING_DIR)
$LOADED_FEATURES << File.expand_path("load_fixture.ext.dll", CODE_LOADING_DIR)
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.require(path).should be_true
+ @object.require(path).should == true
ScratchPad.recorded.should == [:loaded]
end
it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
$LOADED_FEATURES << File.expand_path("load_fixture.ext.rb", CODE_LOADING_DIR)
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.require(path).should be_false
+ @object.require(path).should == false
ScratchPad.recorded.should == []
end
end
@@ -354,8 +362,8 @@ describe :kernel_require, shared: true do
end
it "stores an absolute path" do
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require(@path).should == true
+ $LOADED_FEATURES.should.include?(@path)
end
platform_is_not :windows do
@@ -375,23 +383,23 @@ describe :kernel_require, shared: true do
it "does not canonicalize the path and stores a path with symlinks" do
symlink_path = "#{@symlink_to_code_dir}/load_fixture.rb"
canonical_path = "#{CODE_LOADING_DIR}/load_fixture.rb"
- @object.require(symlink_path).should be_true
+ @object.require(symlink_path).should == true
ScratchPad.recorded.should == [:loaded]
features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
- features.should include(symlink_path)
- features.should_not include(canonical_path)
+ features.should.include?(symlink_path)
+ features.should_not.include?(canonical_path)
end
it "stores the same path that __FILE__ returns in the required file" do
symlink_path = "#{@symlink_to_code_dir}/load_fixture_and__FILE__.rb"
- @object.require(symlink_path).should be_true
+ @object.require(symlink_path).should == true
loaded_feature = $LOADED_FEATURES.last
ScratchPad.recorded.should == [loaded_feature]
end
it "requires only once when a new matching file added to path" do
- @object.require('load_fixture').should be_true
+ @object.require('load_fixture').should == true
ScratchPad.recorded.should == [:loaded]
symlink_to_code_dir_two = tmp("codesymlinktwo")
@@ -399,7 +407,7 @@ describe :kernel_require, shared: true do
begin
$LOAD_PATH.unshift(symlink_to_code_dir_two)
- @object.require('load_fixture').should be_false
+ @object.require('load_fixture').should == false
ensure
rm_r symlink_to_code_dir_two
end
@@ -425,7 +433,7 @@ describe :kernel_require, shared: true do
it "canonicalizes the entry in $LOAD_PATH but not the filename passed to #require" do
$LOAD_PATH.unshift(@symlink_to_dir)
- @object.require("symfile").should be_true
+ @object.require("symfile").should == true
loaded_feature = "#{@dir}/symfile.rb"
ScratchPad.recorded.should == [loaded_feature]
$".last.should == loaded_feature
@@ -437,20 +445,20 @@ describe :kernel_require, shared: true do
it "does not store the path if the load fails" do
$LOAD_PATH << CODE_LOADING_DIR
saved_loaded_features = $LOADED_FEATURES.dup
- -> { @object.require("raise_fixture.rb") }.should raise_error(RuntimeError)
+ -> { @object.require("raise_fixture.rb") }.should.raise(RuntimeError)
$LOADED_FEATURES.should == saved_loaded_features
end
it "does not load an absolute path that is already stored" do
$LOADED_FEATURES << @path
- @object.require(@path).should be_false
+ @object.require(@path).should == false
ScratchPad.recorded.should == []
end
it "does not load a ./ relative path that is already stored" do
$LOADED_FEATURES << "./load_fixture.rb"
Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_false
+ @object.require("./load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -458,7 +466,7 @@ describe :kernel_require, shared: true do
it "does not load a ../ relative path that is already stored" do
$LOADED_FEATURES << "../load_fixture.rb"
Dir.chdir CODE_LOADING_DIR do
- @object.require("../load_fixture.rb").should be_false
+ @object.require("../load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -466,27 +474,27 @@ describe :kernel_require, shared: true do
it "does not load a non-canonical path that is already stored" do
$LOADED_FEATURES << "code/../code/load_fixture.rb"
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/../code/load_fixture.rb").should be_false
+ @object.require("code/../code/load_fixture.rb").should == false
ScratchPad.recorded.should == []
end
it "respects being replaced with a new array" do
prev = $LOADED_FEATURES.dup
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require(@path).should == true
+ $LOADED_FEATURES.should.include?(@path)
$LOADED_FEATURES.replace(prev)
- $LOADED_FEATURES.should_not include(@path)
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should_not.include?(@path)
+ @object.require(@path).should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "does not load twice the same file with and without extension" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture.rb").should be_true
- @object.require("load_fixture").should be_false
+ @object.require("load_fixture.rb").should == true
+ @object.require("load_fixture").should == false
end
describe "when a non-extensioned file is in $LOADED_FEATURES" do
@@ -496,19 +504,19 @@ describe :kernel_require, shared: true do
it "loads a .rb extensioned file when a non extensioned file is in $LOADED_FEATURES" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture").should be_true
+ @object.require("load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
it "loads a .rb extensioned file from a subdirectory" do
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/load_fixture").should be_true
+ @object.require("code/load_fixture").should == true
ScratchPad.recorded.should == [:loaded]
end
it "returns false if the file is not found" do
Dir.chdir File.dirname(CODE_LOADING_DIR) do
- @object.require("load_fixture").should be_false
+ @object.require("load_fixture").should == false
ScratchPad.recorded.should == []
end
end
@@ -516,7 +524,7 @@ describe :kernel_require, shared: true do
it "returns false when passed a path and the file is not found" do
$LOADED_FEATURES << "code/load_fixture"
Dir.chdir CODE_LOADING_DIR do
- @object.require("code/load_fixture").should be_false
+ @object.require("code/load_fixture").should == false
ScratchPad.recorded.should == []
end
end
@@ -524,16 +532,16 @@ describe :kernel_require, shared: true do
it "stores ../ relative paths as absolute paths" do
Dir.chdir CODE_LOADING_DIR do
- @object.require("../code/load_fixture.rb").should be_true
+ @object.require("../code/load_fixture.rb").should == true
end
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should.include?(@path)
end
it "stores ./ relative paths as absolute paths" do
Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_true
+ @object.require("./load_fixture.rb").should == true
end
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should.include?(@path)
end
it "collapses duplicate path separators" do
@@ -541,27 +549,27 @@ describe :kernel_require, shared: true do
sep = File::Separator + File::Separator
path = ["..", "code", "load_fixture.rb"].join(sep)
Dir.chdir CODE_LOADING_DIR do
- @object.require(path).should be_true
+ @object.require(path).should == true
end
- $LOADED_FEATURES.should include(@path)
+ $LOADED_FEATURES.should.include?(@path)
end
it "expands absolute paths containing .." do
path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
- @object.require(path).should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require(path).should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "adds the suffix of the resolved filename" do
$LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture").should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require("load_fixture").should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "does not load a non-canonical path for a file already loaded" do
$LOADED_FEATURES << @path
$LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/../code/load_fixture.rb").should be_false
+ @object.require("code/../code/load_fixture.rb").should == false
ScratchPad.recorded.should == []
end
@@ -569,7 +577,7 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << @path
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_false
+ @object.require("./load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -578,7 +586,7 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES << @path
$LOAD_PATH << "an_irrelevant_dir"
Dir.chdir CODE_LOADING_DIR do
- @object.require("../code/load_fixture.rb").should be_false
+ @object.require("../code/load_fixture.rb").should == false
end
ScratchPad.recorded.should == []
end
@@ -586,26 +594,26 @@ describe :kernel_require, shared: true do
it "unicode_normalize is part of core and not $LOADED_FEATURES" do
features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
features.lines.each { |feature|
- feature.should_not include("unicode_normalize")
+ feature.should_not.include?("unicode_normalize")
}
- -> { @object.require("unicode_normalize") }.should raise_error(LoadError)
+ -> { @object.require("unicode_normalize") }.should.raise(LoadError)
end
it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture").should be_true
+ @object.send(@method, "../code/load_fixture").should == true
end
ScratchPad.recorded.should == [:loaded]
$LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
# This loads because the above load was not on the $LOAD_PATH
- @object.send(@method, "load_fixture").should be_true
+ @object.send(@method, "load_fixture").should == true
ScratchPad.recorded.should == [:loaded, :loaded]
$LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
# This does not load because the above load was on the $LOAD_PATH
- @object.send(@method, "load_fixture").should be_false
+ @object.send(@method, "load_fixture").should == false
ScratchPad.recorded.should == [:loaded, :loaded]
end
end
@@ -623,13 +631,13 @@ describe :kernel_require, shared: true do
# "#3171"
it "performs tilde expansion on a .rb file before storing paths in $LOADED_FEATURES" do
- @object.require("~/load_fixture.rb").should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require("~/load_fixture.rb").should == true
+ $LOADED_FEATURES.should.include?(@path)
end
it "performs tilde expansion on a non-extensioned file before storing paths in $LOADED_FEATURES" do
- @object.require("~/load_fixture").should be_true
- $LOADED_FEATURES.should include(@path)
+ @object.require("~/load_fixture").should == true
+ $LOADED_FEATURES.should.include?(@path)
end
end
@@ -686,8 +694,8 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t1_res.should be_true
- t2_res.should be_false
+ t1_res.should == true
+ t2_res.should == false
ScratchPad.recorded.should == [:con_pre, :con_post, :t2_post, :t1_post]
end
@@ -711,8 +719,8 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t1_res.should be_true
- t2_res.should be_true
+ t1_res.should == true
+ t2_res.should == true
ScratchPad.recorded.should == [:con2_pre, :con3, :con2_post]
end
@@ -730,7 +738,7 @@ describe :kernel_require, shared: true do
-> {
@object.require(@path)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
Thread.pass until fin
ScratchPad.recorded << :t1_post
@@ -751,7 +759,7 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t2_res.should be_true
+ t2_res.should == true
ScratchPad.recorded.should == [:con_pre, :con_pre, :con_post, :t2_post, :t1_post]
end
@@ -771,7 +779,7 @@ describe :kernel_require, shared: true do
-> {
@object.require(@path)
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
raised = true
@@ -799,8 +807,8 @@ describe :kernel_require, shared: true do
t1.join
t2.join
- t1_res.should be_false
- t2_res.should be_true
+ t1_res.should == false
+ t2_res.should == true
ScratchPad.recorded.should == [:con_pre, :con_pre, :con_post, :t2_post, :t1_post]
end
@@ -811,8 +819,28 @@ describe :kernel_require, shared: true do
-> {
@object.send(@method, path)
- }.should raise_error(LoadError) { |e|
+ }.should.raise(LoadError) { |e|
e.path.should == path
}
end
+
+ platform_is :linux, :darwin do
+ it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path without extension" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should.raise(LoadError) { |e|
+ e.path.should == nil
+ }
+ end
+ end
+
+ platform_is :darwin do
+ it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path with extension" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture.bundle"
+ -> { @object.send(@method, path) }.should.raise(LoadError) { |e|
+ e.path.should == nil
+ }
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 13dc6e97f0..b40bd95f59 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -22,12 +22,13 @@ describe :kernel_sprintf, shared: true do
@method.call("%d", "112").should == "112"
@method.call("%d", "0127").should == "87"
@method.call("%d", "0xc4").should == "196"
+ @method.call("%d", "0").should == "0"
end
it "raises TypeError exception if cannot convert to Integer" do
-> {
@method.call("%b", Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
["b", "B"].each do |f|
@@ -104,6 +105,20 @@ describe :kernel_sprintf, shared: true do
@method.call("%X", -1).should == "..F"
end
end
+
+ %w[b B d i u o x X].each do |f|
+ describe f do
+ it "converts to the empty string if precision is 0 and value is 0" do
+ @method.call("%.#{f}", 0).should == ""
+ @method.call("%.0#{f}", 0).should == ""
+ end
+
+ it "pads the empty string if precision is 0 and value is 0" do
+ @method.call("%2.#{f}", 0).should == " "
+ @method.call("%2.0#{f}", 0).should == " "
+ end
+ end
+ end
end
describe "float formats" do
@@ -116,7 +131,7 @@ describe :kernel_sprintf, shared: true do
it "raises TypeError exception if cannot convert to Float" do
-> {
@method.call("%f", Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
{"e" => "e", "E" => "E"}.each_pair do |f, exp|
@@ -289,40 +304,28 @@ describe :kernel_sprintf, shared: true do
@method.call("%c", "a").should == "a"
end
- ruby_version_is ""..."3.2" do
- it "raises ArgumentError if argument is a string of several characters" do
- -> {
- @method.call("%c", "abc")
- }.should raise_error(ArgumentError, /%c requires a character/)
- end
-
- it "raises ArgumentError if argument is an empty string" do
- -> {
- @method.call("%c", "")
- }.should raise_error(ArgumentError, /%c requires a character/)
- end
+ it "displays only the first character if argument is a string of several characters" do
+ @method.call("%c", "abc").should == "a"
end
- ruby_version_is "3.2" do
- it "displays only the first character if argument is a string of several characters" do
- @method.call("%c", "abc").should == "a"
- end
+ it "displays only the first character if argument is a string of several multibyte characters" do
+ @method.call("%c", "あいうえお").should == "あ"
+ end
- it "displays no characters if argument is an empty string" do
- @method.call("%c", "").should == ""
- end
+ it "displays no characters if argument is an empty string" do
+ @method.call("%c", "").should == ""
end
it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
-> {
@method.call("%c", [])
- }.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
+ }.should raise_consistent_error(TypeError, /no implicit conversion of Array into Integer/)
end
it "raises TypeError if argument is nil" do
-> {
@method.call("%c", nil)
- }.should raise_error(TypeError, /no implicit conversion from nil to integer/)
+ }.should raise_consistent_error(TypeError, /no implicit conversion of nil into Integer/)
end
it "tries to convert argument to String with to_str" do
@@ -351,7 +354,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to String/)
+ }.should raise_consistent_error(TypeError, /can't convert BasicObject into String/)
end
it "raises TypeError if converting to Integer with to_int returns non-Integer" do
@@ -362,7 +365,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
+ }.should raise_consistent_error(TypeError, /can't convert BasicObject into Integer/)
end
end
@@ -372,6 +375,10 @@ describe :kernel_sprintf, shared: true do
obj.should_receive(:inspect).and_return("<inspect-result>")
@method.call("%p", obj).should == "<inspect-result>"
end
+
+ it "substitutes 'nil' for nil" do
+ @method.call("%p", nil).should == "nil"
+ end
end
describe "s" do
@@ -397,7 +404,7 @@ describe :kernel_sprintf, shared: true do
-> {
@method.call("%s", obj)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "formats a partial substring without including omitted characters" do
@@ -450,12 +457,12 @@ describe :kernel_sprintf, shared: true do
it "alone raises an ArgumentError" do
-> {
@method.call("%")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "is escaped by %" do
@method.call("%%").should == "%"
- @method.call("%%d", 10).should == "%d"
+ @method.call("%%d").should == "%d"
end
end
end
@@ -557,7 +564,7 @@ describe :kernel_sprintf, shared: true do
it "raises exception if argument number is bigger than actual arguments list" do
-> {
@method.call("%4$d", 1, 2, 3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "ignores '-' sign" do
@@ -568,7 +575,7 @@ describe :kernel_sprintf, shared: true do
it "raises ArgumentError exception when absolute and relative argument numbers are mixed" do
-> {
@method.call("%1$d %d", 1, 2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -600,11 +607,28 @@ describe :kernel_sprintf, shared: true do
@method.call("%#b", 0).should == "0"
@method.call("%#B", 0).should == "0"
- @method.call("%#o", 0).should == "0"
-
@method.call("%#x", 0).should == "0"
@method.call("%#X", 0).should == "0"
end
+
+ it "does nothing for zero argument when combined with zero precision" do
+ @method.call("%#.0b", 0).should == ""
+ @method.call("%#.0B", 0).should == ""
+
+ @method.call("%#.0x", 0).should == ""
+ @method.call("%#.0X", 0).should == ""
+ end
+ end
+
+ context "applies to format o" do
+ it "does nothing for zero argument" do
+ @method.call("%#o", 0).should == "0"
+ @method.call("%#.1o", 0).should == "0"
+ end
+
+ it "increases the precision if precision zero is requested with zero argument" do
+ @method.call("%#.0o", 0).should == "0"
+ end
end
context "applies to formats aAeEfgG" do
@@ -818,7 +842,7 @@ describe :kernel_sprintf, shared: true do
it "raises ArgumentError when is mixed with width" do
-> {
@method.call("%*10d", 10, 112)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
@@ -917,7 +941,7 @@ describe :kernel_sprintf, shared: true do
it "cannot be mixed with unnamed style" do
-> {
@method.call("%d %<foo>d", 1, foo: "123")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -937,13 +961,30 @@ describe :kernel_sprintf, shared: true do
it "cannot be mixed with unnamed style" do
-> {
@method.call("%d %{foo}", 1, foo: "123")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
+ end
+
+ it "respects Hash#default when there is no set key" do
+ @method.call("%{foo}", Hash.new(123)).should == "123"
+ @method.call("%{foo}", Hash.new { 123 }).should == "123"
end
- it "raises KeyError when there is no matching key" do
+ it "raises KeyError when Hash#default returns nil" do
-> {
@method.call("%{foo}", {})
- }.should raise_error(KeyError)
+ }.should.raise(KeyError, 'key{foo} not found')
+
+ -> {
+ @method.call("%{foo}", Hash.new(nil))
+ }.should.raise(KeyError, 'key{foo} not found')
+
+ -> {
+ @method.call("%{foo}", Hash.new { nil })
+ }.should.raise(KeyError, 'key{foo} not found')
+ end
+
+ it "accepts a nil value for an existing key" do
+ @method.call("%{foo}", { foo: nil }).should == ""
end
it "converts value to String with to_s" do
@@ -967,21 +1008,21 @@ describe :kernel_sprintf, shared: true do
it "raises a KeyError" do
-> {
@method.call("%<foo>s", @object)
- }.should raise_error(KeyError)
+ }.should.raise(KeyError)
end
it "sets the Hash as the receiver of KeyError" do
-> {
@method.call("%<foo>s", @object)
- }.should raise_error(KeyError) { |err|
- err.receiver.should equal(@object)
+ }.should.raise(KeyError) { |err|
+ err.receiver.should.equal?(@object)
}
end
it "sets the unmatched key as the key of KeyError" do
-> {
@method.call("%<foo>s", @object)
- }.should raise_error(KeyError) { |err|
+ }.should.raise(KeyError) { |err|
err.key.to_s.should == 'foo'
}
end
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index 7ec0fe4c48..849c95cbb7 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -4,19 +4,19 @@ describe :kernel_sprintf_encoding, shared: true do
it "can produce a string with valid encoding" do
string = @method.call("good day %{valid}", valid: "e")
string.encoding.should == Encoding::UTF_8
- string.valid_encoding?.should be_true
+ string.valid_encoding?.should == true
end
it "can produce a string with invalid encoding" do
string = @method.call("good day %{invalid}", invalid: "\x80")
string.encoding.should == Encoding::UTF_8
- string.valid_encoding?.should be_false
+ string.valid_encoding?.should == false
end
it "returns a String in the same encoding as the format String if compatible" do
string = "%s".dup.force_encoding(Encoding::KOI8_U)
result = @method.call(string, "dogs")
- result.encoding.should equal(Encoding::KOI8_U)
+ result.encoding.should.equal?(Encoding::KOI8_U)
end
it "returns a String in the argument's encoding if format encoding is more restrictive" do
@@ -24,7 +24,7 @@ describe :kernel_sprintf_encoding, shared: true do
argument = "b\303\274r".dup.force_encoding(Encoding::UTF_8)
result = @method.call(string, argument)
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do
@@ -33,7 +33,7 @@ describe :kernel_sprintf_encoding, shared: true do
-> {
@method.call(string, argument)
- }.should raise_error(Encoding::CompatibilityError)
+ }.should.raise(Encoding::CompatibilityError)
end
describe "%c" do
@@ -52,7 +52,7 @@ describe :kernel_sprintf_encoding, shared: true do
-> {
@method.call(format, 1286)
- }.should raise_error(RangeError, /out of char range/)
+ }.should.raise(RangeError, /out of char range/)
end
it "uses the encoding of the format string to interpret codepoints" do
diff --git a/spec/ruby/core/kernel/shared/then.rb b/spec/ruby/core/kernel/shared/then.rb
index b52075371f..c71393bf50 100644
--- a/spec/ruby/core/kernel/shared/then.rb
+++ b/spec/ruby/core/kernel/shared/then.rb
@@ -1,20 +1,20 @@
describe :kernel_then, shared: true do
it "yields self" do
object = Object.new
- object.send(@method) { |o| o.should equal object }
+ object.send(@method) { |o| o.should.equal? object }
end
it "returns the block return value" do
object = Object.new
- object.send(@method) { 42 }.should equal 42
+ object.send(@method) { 42 }.should.equal? 42
end
it "returns a sized Enumerator when no block given" do
object = Object.new
enum = object.send(@method)
- enum.should be_an_instance_of Enumerator
- enum.size.should equal 1
- enum.peek.should equal object
- enum.first.should equal object
+ enum.should.instance_of? Enumerator
+ enum.size.should.equal? 1
+ enum.peek.should.equal? object
+ enum.first.should.equal? object
end
end
diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb
index 23c400f9bd..7915272937 100644
--- a/spec/ruby/core/kernel/singleton_class_spec.rb
+++ b/spec/ruby/core/kernel/singleton_class_spec.rb
@@ -21,27 +21,27 @@ describe "Kernel#singleton_class" do
end
it "raises TypeError for Integer" do
- -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { 123.singleton_class }.should.raise(TypeError, "can't define singleton")
end
it "raises TypeError for Float" do
- -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { 3.14.singleton_class }.should.raise(TypeError, "can't define singleton")
end
it "raises TypeError for Symbol" do
- -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { :foo.singleton_class }.should.raise(TypeError, "can't define singleton")
end
it "raises TypeError for a frozen deduplicated String" do
- -> { (-"string").singleton_class }.should raise_error(TypeError, "can't define singleton")
- -> { a = -"string"; a.singleton_class }.should raise_error(TypeError, "can't define singleton")
- -> { a = "string"; (-a).singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { (-"string").singleton_class }.should.raise(TypeError, "can't define singleton")
+ -> { a = -"string"; a.singleton_class }.should.raise(TypeError, "can't define singleton")
+ -> { a = "string"; (-a).singleton_class }.should.raise(TypeError, "can't define singleton")
end
it "returns a frozen singleton class if object is frozen" do
obj = Object.new
obj.freeze
- obj.singleton_class.frozen?.should be_true
+ obj.singleton_class.frozen?.should == true
end
context "for an IO object with a replaced singleton class" do
diff --git a/spec/ruby/core/kernel/singleton_method_spec.rb b/spec/ruby/core/kernel/singleton_method_spec.rb
index 0bdf125ad8..fe8e23eb02 100644
--- a/spec/ruby/core/kernel/singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/singleton_method_spec.rb
@@ -1,10 +1,10 @@
require_relative '../../spec_helper'
describe "Kernel#singleton_method" do
- it "find a method defined on the singleton class" do
+ it "finds a method defined on the singleton class" do
obj = Object.new
def obj.foo; end
- obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).should.instance_of?(Method)
end
it "returns a Method which can be called" do
@@ -23,7 +23,7 @@ describe "Kernel#singleton_method" do
obj.foo.should == 42
-> {
obj.singleton_method(:foo)
- }.should raise_error(NameError) { |e|
+ }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -33,9 +33,53 @@ describe "Kernel#singleton_method" do
obj = Object.new
-> {
obj.singleton_method(:not_existing)
- }.should raise_error(NameError) { |e|
+ }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
end
+
+ ruby_bug "#20620", ""..."3.4" do
+ it "finds a method defined in a module included in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.include(m)
+
+ obj.singleton_method(:foo).should.instance_of?(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module prepended in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.prepend(m)
+
+ obj.singleton_method(:foo).should.instance_of?(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module that an object is extended with" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.extend(m)
+
+ obj.singleton_method(:foo).should.instance_of?(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/singleton_methods_spec.rb b/spec/ruby/core/kernel/singleton_methods_spec.rb
index a127a439de..a7f6969519 100644
--- a/spec/ruby/core/kernel/singleton_methods_spec.rb
+++ b/spec/ruby/core/kernel/singleton_methods_spec.rb
@@ -8,33 +8,33 @@ describe :kernel_singleton_methods, shared: true do
end
it "returns the names of module methods for a module" do
- ReflectSpecs::M.singleton_methods(*@object).should include(:ms_pro, :ms_pub)
+ ReflectSpecs::M.singleton_methods(*@object).to_set.should >= Set[:ms_pro, :ms_pub]
end
it "does not return private module methods for a module" do
- ReflectSpecs::M.singleton_methods(*@object).should_not include(:ms_pri)
+ ReflectSpecs::M.singleton_methods(*@object).should_not.include?(:ms_pri)
end
it "returns the names of class methods for a class" do
- ReflectSpecs::A.singleton_methods(*@object).should include(:as_pro, :as_pub)
+ ReflectSpecs::A.singleton_methods(*@object).to_set.should >= Set[:as_pro, :as_pub]
end
it "does not return private class methods for a class" do
- ReflectSpecs::A.singleton_methods(*@object).should_not include(:as_pri)
+ ReflectSpecs::A.singleton_methods(*@object).should_not.include?(:as_pri)
end
it "returns the names of singleton methods for an object" do
- ReflectSpecs.os.singleton_methods(*@object).should include(:os_pro, :os_pub)
+ ReflectSpecs.os.singleton_methods(*@object).to_set.should >= Set[:os_pro, :os_pub]
end
end
describe :kernel_singleton_methods_modules, shared: true do
it "does not return any included methods for a module including a module" do
- ReflectSpecs::N.singleton_methods(*@object).should include(:ns_pro, :ns_pub)
+ ReflectSpecs::N.singleton_methods(*@object).to_set.should >= Set[:ns_pro, :ns_pub]
end
it "does not return any included methods for a class including a module" do
- ReflectSpecs::D.singleton_methods(*@object).should include(:ds_pro, :ds_pub)
+ ReflectSpecs::D.singleton_methods(*@object).to_set.should >= Set[:ds_pro, :ds_pub]
end
it "for a module does not return methods in a module prepended to Module itself" do
@@ -44,7 +44,7 @@ describe :kernel_singleton_methods_modules, shared: true do
ancestors = mod.singleton_class.ancestors
ancestors[0...2].should == [ mod.singleton_class, mod ]
- ancestors.should include(SingletonMethodsSpecs::Prepended)
+ ancestors.should.include?(SingletonMethodsSpecs::Prepended)
# Do not search prepended modules of `Module`, as that's a non-singleton class
mod.singleton_methods.should == []
@@ -53,7 +53,7 @@ end
describe :kernel_singleton_methods_supers, shared: true do
it "returns the names of singleton methods for an object extended with a module" do
- ReflectSpecs.oe.singleton_methods(*@object).should include(:m_pro, :m_pub)
+ ReflectSpecs.oe.singleton_methods(*@object).to_set.should >= Set[:m_pro, :m_pub]
end
it "returns a unique list for an object extended with a module" do
@@ -63,15 +63,15 @@ describe :kernel_singleton_methods_supers, shared: true do
end
it "returns the names of singleton methods for an object extended with two modules" do
- ReflectSpecs.oee.singleton_methods(*@object).should include(:m_pro, :m_pub, :n_pro, :n_pub)
+ ReflectSpecs.oee.singleton_methods(*@object).to_set.should >= Set[:m_pro, :m_pub, :n_pro, :n_pub]
end
it "returns the names of singleton methods for an object extended with a module including a module" do
- ReflectSpecs.oei.singleton_methods(*@object).should include(:n_pro, :n_pub, :m_pro, :m_pub)
+ ReflectSpecs.oei.singleton_methods(*@object).to_set.should >= Set[:n_pro, :n_pub, :m_pro, :m_pub]
end
it "returns the names of inherited singleton methods for a subclass" do
- ReflectSpecs::B.singleton_methods(*@object).should include(:as_pro, :as_pub, :bs_pro, :bs_pub)
+ ReflectSpecs::B.singleton_methods(*@object).to_set.should >= Set[:as_pro, :as_pub, :bs_pro, :bs_pub]
end
it "returns a unique list for a subclass" do
@@ -81,7 +81,7 @@ describe :kernel_singleton_methods_supers, shared: true do
end
it "returns the names of inherited singleton methods for a subclass including a module" do
- ReflectSpecs::C.singleton_methods(*@object).should include(:as_pro, :as_pub, :cs_pro, :cs_pub)
+ ReflectSpecs::C.singleton_methods(*@object).to_set.should >= Set[:as_pro, :as_pub, :cs_pro, :cs_pub]
end
it "returns a unique list for a subclass including a module" do
@@ -91,57 +91,62 @@ describe :kernel_singleton_methods_supers, shared: true do
end
it "returns the names of inherited singleton methods for a subclass of a class including a module" do
- ReflectSpecs::E.singleton_methods(*@object).should include(:ds_pro, :ds_pub, :es_pro, :es_pub)
+ ReflectSpecs::E.singleton_methods(*@object).to_set.should >= Set[:ds_pro, :ds_pub, :es_pro, :es_pub]
end
it "returns the names of inherited singleton methods for a subclass of a class that includes a module, where the subclass also includes a module" do
- ReflectSpecs::F.singleton_methods(*@object).should include(:ds_pro, :ds_pub, :fs_pro, :fs_pub)
+ ReflectSpecs::F.singleton_methods(*@object).to_set.should >= Set[:ds_pro, :ds_pub, :fs_pro, :fs_pub]
end
it "returns the names of inherited singleton methods for a class extended with a module" do
- ReflectSpecs::P.singleton_methods(*@object).should include(:m_pro, :m_pub)
+ ReflectSpecs::P.singleton_methods(*@object).to_set.should >= Set[:m_pro, :m_pub]
end
end
describe :kernel_singleton_methods_private_supers, shared: true do
it "does not return private singleton methods for an object extended with a module" do
- ReflectSpecs.oe.singleton_methods(*@object).should_not include(:m_pri)
+ ReflectSpecs.oe.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private singleton methods for an object extended with two modules" do
- ReflectSpecs.oee.singleton_methods(*@object).should_not include(:m_pri)
+ ReflectSpecs.oee.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private singleton methods for an object extended with a module including a module" do
- ReflectSpecs.oei.singleton_methods(*@object).should_not include(:n_pri, :m_pri)
+ ReflectSpecs.oei.singleton_methods(*@object).should_not.include?(:n_pri)
+ ReflectSpecs.oei.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private singleton methods for a class extended with a module" do
- ReflectSpecs::P.singleton_methods(*@object).should_not include(:m_pri)
+ ReflectSpecs::P.singleton_methods(*@object).should_not.include?(:m_pri)
end
it "does not return private inherited singleton methods for a module including a module" do
- ReflectSpecs::N.singleton_methods(*@object).should_not include(:ns_pri)
+ ReflectSpecs::N.singleton_methods(*@object).should_not.include?(:ns_pri)
end
it "does not return private inherited singleton methods for a class including a module" do
- ReflectSpecs::D.singleton_methods(*@object).should_not include(:ds_pri)
+ ReflectSpecs::D.singleton_methods(*@object).should_not.include?(:ds_pri)
end
it "does not return private inherited singleton methods for a subclass" do
- ReflectSpecs::B.singleton_methods(*@object).should_not include(:as_pri, :bs_pri)
+ ReflectSpecs::B.singleton_methods(*@object).should_not.include?(:as_pri)
+ ReflectSpecs::B.singleton_methods(*@object).should_not.include?(:bs_pri)
end
it "does not return private inherited singleton methods for a subclass including a module" do
- ReflectSpecs::C.singleton_methods(*@object).should_not include(:as_pri, :cs_pri)
+ ReflectSpecs::C.singleton_methods(*@object).should_not.include?(:as_pri)
+ ReflectSpecs::C.singleton_methods(*@object).should_not.include?(:cs_pri)
end
it "does not return private inherited singleton methods for a subclass of a class including a module" do
- ReflectSpecs::E.singleton_methods(*@object).should_not include(:ds_pri, :es_pri)
+ ReflectSpecs::E.singleton_methods(*@object).should_not.include?(:ds_pri)
+ ReflectSpecs::E.singleton_methods(*@object).should_not.include?(:es_pri)
end
it "does not return private inherited singleton methods for a subclass of a class that includes a module, where the subclass also includes a module" do
- ReflectSpecs::F.singleton_methods(*@object).should_not include(:ds_pri, :fs_pri)
+ ReflectSpecs::F.singleton_methods(*@object).should_not.include?(:ds_pri)
+ ReflectSpecs::F.singleton_methods(*@object).should_not.include?(:fs_pri)
end
end
@@ -178,15 +183,17 @@ describe "Kernel#singleton_methods" do
end
it "returns the names of singleton methods of the subclass" do
- ReflectSpecs::B.singleton_methods(false).should include(:bs_pro, :bs_pub)
+ ReflectSpecs::B.singleton_methods(false).to_set.should >= Set[:bs_pro, :bs_pub]
end
it "does not return names of inherited singleton methods for a subclass" do
- ReflectSpecs::B.singleton_methods(false).should_not include(:as_pro, :as_pub)
+ ReflectSpecs::B.singleton_methods(false).should_not.include?(:as_pro)
+ ReflectSpecs::B.singleton_methods(false).should_not.include?(:as_pub)
end
it "does not return the names of inherited singleton methods for a class extended with a module" do
- ReflectSpecs::P.singleton_methods(false).should_not include(:m_pro, :m_pub)
+ ReflectSpecs::P.singleton_methods(false).should_not.include?(:m_pro)
+ ReflectSpecs::P.singleton_methods(false).should_not.include?(:m_pub)
end
end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index 4401e54256..61d8cc2380 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,12 +1,13 @@
require_relative '../../spec_helper'
+require_relative '../fiber/fixtures/scheduler'
describe "Kernel#sleep" do
it "is a private method" do
- Kernel.should have_private_instance_method(:sleep)
+ Kernel.private_instance_methods(false).should.include?(:sleep)
end
it "returns an Integer" do
- sleep(0.001).should be_kind_of(Integer)
+ sleep(0.001).should.is_a?(Integer)
end
it "accepts a Float" do
@@ -28,12 +29,12 @@ describe "Kernel#sleep" do
end
it "raises an ArgumentError when passed a negative duration" do
- -> { sleep(-0.1) }.should raise_error(ArgumentError)
- -> { sleep(-1) }.should raise_error(ArgumentError)
+ -> { sleep(-0.1) }.should.raise(ArgumentError)
+ -> { sleep(-1) }.should.raise(ArgumentError)
end
it "raises a TypeError when passed a String" do
- -> { sleep('2') }.should raise_error(TypeError)
+ -> { sleep('2') }.should.raise(TypeError)
end
it "pauses execution indefinitely if not given a duration" do
@@ -62,26 +63,52 @@ describe "Kernel#sleep" do
actual_duration.should > 0.01 # 100 * 0.0001 => 0.01
end
- ruby_version_is ""..."3.3" do
- it "raises a TypeError when passed nil" do
- -> { sleep(nil) }.should raise_error(TypeError)
+ it "accepts a nil duration" do
+ running = false
+ t = Thread.new do
+ running = true
+ sleep(nil)
+ 5
end
+
+ Thread.pass until running
+ Thread.pass while t.status and t.status != "sleep"
+
+ t.wakeup
+ t.value.should == 5
end
- ruby_version_is "3.3" do
- it "accepts a nil duration" do
- running = false
- t = Thread.new do
- running = true
- sleep(nil)
- 5
+ context "Kernel.sleep with Fiber scheduler" do
+ before :each do
+ Fiber.set_scheduler(FiberSpecs::LoggingScheduler.new)
+ end
+
+ after :each do
+ Fiber.set_scheduler(nil)
+ end
+
+ it "calls the scheduler without arguments when no duration is given" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep
end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [] }]
+ end
- Thread.pass until running
- Thread.pass while t.status and t.status != "sleep"
+ it "calls the scheduler with the given duration" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [0.01] }]
+ end
- t.wakeup
- t.value.should == 5
+ it "does not call the scheduler if the fiber is blocking" do
+ sleeper = Fiber.new(blocking: true) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == []
end
end
end
diff --git a/spec/ruby/core/kernel/spawn_spec.rb b/spec/ruby/core/kernel/spawn_spec.rb
index ba05b629d5..3432fc31da 100644
--- a/spec/ruby/core/kernel/spawn_spec.rb
+++ b/spec/ruby/core/kernel/spawn_spec.rb
@@ -6,7 +6,7 @@ require_relative 'fixtures/classes'
# run here as it is redundant and takes too long for little gain.
describe "Kernel#spawn" do
it "is a private method" do
- Kernel.should have_private_instance_method(:spawn)
+ Kernel.private_instance_methods(false).should.include?(:spawn)
end
it "executes the given command" do
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index 9ef7f86f16..5a4a90ff7a 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -13,28 +13,52 @@ end
describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
describe "Kernel.sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
diff --git a/spec/ruby/core/kernel/srand_spec.rb b/spec/ruby/core/kernel/srand_spec.rb
index 95bb406f46..cbc3a7f4b8 100644
--- a/spec/ruby/core/kernel/srand_spec.rb
+++ b/spec/ruby/core/kernel/srand_spec.rb
@@ -11,7 +11,7 @@ describe "Kernel#srand" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:srand)
+ Kernel.private_instance_methods(false).should.include?(:srand)
end
it "returns the previous seed value" do
@@ -31,7 +31,7 @@ describe "Kernel#srand" do
end
it "defaults number to a random value" do
- -> { srand }.should_not raise_error
+ -> { srand }.should_not.raise
srand.should_not == 0
end
@@ -60,11 +60,11 @@ describe "Kernel#srand" do
end
it "raises a TypeError when passed nil" do
- -> { srand(nil) }.should raise_error(TypeError)
+ -> { srand(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { srand("7") }.should raise_error(TypeError)
+ -> { srand("7") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/sub_spec.rb b/spec/ruby/core/kernel/sub_spec.rb
index 9130bd159c..b175e371dc 100644
--- a/spec/ruby/core/kernel/sub_spec.rb
+++ b/spec/ruby/core/kernel/sub_spec.rb
@@ -6,13 +6,13 @@ require_relative 'fixtures/classes'
ruby_version_is ""..."1.9" do
describe "Kernel#sub" do
it "is a private method" do
- Kernel.should have_private_instance_method(:sub)
+ Kernel.private_instance_methods(false).should.include?(:sub)
end
end
describe "Kernel#sub!" do
it "is a private method" do
- Kernel.should have_private_instance_method(:sub!)
+ Kernel.private_instance_methods(false).should.include?(:sub!)
end
end
diff --git a/spec/ruby/core/kernel/syscall_spec.rb b/spec/ruby/core/kernel/syscall_spec.rb
index 32d07b3ae2..63943cdad5 100644
--- a/spec/ruby/core/kernel/syscall_spec.rb
+++ b/spec/ruby/core/kernel/syscall_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#syscall" do
it "is a private method" do
- Kernel.should have_private_instance_method(:syscall)
+ Kernel.private_instance_methods(false).should.include?(:syscall)
end
end
diff --git a/spec/ruby/core/kernel/system_spec.rb b/spec/ruby/core/kernel/system_spec.rb
index 9bc03924dd..b24956104a 100644
--- a/spec/ruby/core/kernel/system_spec.rb
+++ b/spec/ruby/core/kernel/system_spec.rb
@@ -5,14 +5,14 @@ describe :kernel_system, shared: true do
it "executes the specified command in a subprocess" do
-> { @object.system("echo a") }.should output_to_fd("a\n")
- $?.should be_an_instance_of Process::Status
+ $?.should.instance_of? Process::Status
$?.should.success?
end
it "returns true when the command exits with a zero exit status" do
@object.system(ruby_cmd('exit 0')).should == true
- $?.should be_an_instance_of Process::Status
+ $?.should.instance_of? Process::Status
$?.should.success?
$?.exitstatus.should == 0
end
@@ -20,24 +20,24 @@ describe :kernel_system, shared: true do
it "returns false when the command exits with a non-zero exit status" do
@object.system(ruby_cmd('exit 1')).should == false
- $?.should be_an_instance_of Process::Status
+ $?.should.instance_of? Process::Status
$?.should_not.success?
$?.exitstatus.should == 1
end
it "raises RuntimeError when `exception: true` is given and the command exits with a non-zero exit status" do
- -> { @object.system(ruby_cmd('exit 1'), exception: true) }.should raise_error(RuntimeError)
+ -> { @object.system(ruby_cmd('exit 1'), exception: true) }.should.raise(RuntimeError)
end
it "raises Errno::ENOENT when `exception: true` is given and the specified command does not exist" do
- -> { @object.system('feature_14386', exception: true) }.should raise_error(Errno::ENOENT)
+ -> { @object.system('feature_14386', exception: true) }.should.raise(Errno::ENOENT)
end
it "returns nil when command execution fails" do
- @object.system("sad").should be_nil
+ @object.system("sad").should == nil
- $?.should be_an_instance_of Process::Status
- $?.pid.should be_kind_of(Integer)
+ $?.should.instance_of? Process::Status
+ $?.pid.should.is_a?(Integer)
$?.should_not.success?
end
@@ -121,7 +121,7 @@ end
describe "Kernel#system" do
it "is a private method" do
- Kernel.should have_private_instance_method(:system)
+ Kernel.private_instance_methods(false).should.include?(:system)
end
it_behaves_like :kernel_system, :system, KernelSpecs::Method.new
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 0c16b1dbbf..9a2efbaea0 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -2,26 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#taint" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new
- o.taint
- o.should_not.tainted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- obj = mock("tainted")
- obj.taint
- }.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:taint)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:taint)
end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index fcae433069..837eb1dafb 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -2,28 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should_not.tainted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = mock('o')
- o.tainted?
- }.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:tainted?)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:tainted?)
end
end
diff --git a/spec/ruby/core/kernel/tap_spec.rb b/spec/ruby/core/kernel/tap_spec.rb
index f7720a6dc7..453b9b84d5 100644
--- a/spec/ruby/core/kernel/tap_spec.rb
+++ b/spec/ruby/core/kernel/tap_spec.rb
@@ -4,10 +4,10 @@ require_relative 'fixtures/classes'
describe "Kernel#tap" do
it "always yields self and returns self" do
a = KernelSpecs::A.new
- a.tap{|o| o.should equal(a); 42}.should equal(a)
+ a.tap{|o| o.should.equal?(a); 42}.should.equal?(a)
end
it "raises a LocalJumpError when no block given" do
- -> { 3.tap }.should raise_error(LocalJumpError)
+ -> { 3.tap }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb
index d26dc06361..30717dfd98 100644
--- a/spec/ruby/core/kernel/test_spec.rb
+++ b/spec/ruby/core/kernel/test_spec.rb
@@ -8,7 +8,7 @@ describe "Kernel#test" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:test)
+ Kernel.private_instance_methods(false).should.include?(:test)
end
it "returns true when passed ?f if the argument is a regular file" do
@@ -28,7 +28,7 @@ describe "Kernel#test" do
link = tmp("file_symlink.lnk")
File.symlink(@file, link)
begin
- Kernel.test(?l, link).should be_true
+ Kernel.test(?l, link).should == true
ensure
rm_r link
end
@@ -36,11 +36,11 @@ describe "Kernel#test" do
end
it "returns true when passed ?r if the argument is readable by the effective uid" do
- Kernel.test(?r, @file).should be_true
+ Kernel.test(?r, @file).should == true
end
it "returns true when passed ?R if the argument is readable by the real uid" do
- Kernel.test(?R, @file).should be_true
+ Kernel.test(?R, @file).should == true
end
context "writable test" do
@@ -54,11 +54,11 @@ describe "Kernel#test" do
end
it "returns true when passed ?w if the argument is readable by the effective uid" do
- Kernel.test(?w, @tmp_file).should be_true
+ Kernel.test(?w, @tmp_file).should == true
end
it "returns true when passed ?W if the argument is readable by the real uid" do
- Kernel.test(?W, @tmp_file).should be_true
+ Kernel.test(?W, @tmp_file).should == true
end
end
diff --git a/spec/ruby/core/kernel/throw_spec.rb b/spec/ruby/core/kernel/throw_spec.rb
index 64bfccb413..1086126176 100644
--- a/spec/ruby/core/kernel/throw_spec.rb
+++ b/spec/ruby/core/kernel/throw_spec.rb
@@ -7,7 +7,7 @@ describe "Kernel.throw" do
:value
throw :blah
fail("throw didn't transfer the control")
- end.should be_nil
+ end.should == nil
end
it "transfers control to the innermost catch block waiting for the same symbol" do
@@ -42,11 +42,11 @@ describe "Kernel.throw" do
end
it "raises an ArgumentError if there is no catch block for the symbol" do
- -> { throw :blah }.should raise_error(ArgumentError)
+ -> { throw :blah }.should.raise(ArgumentError)
end
it "raises an UncaughtThrowError if there is no catch block for the symbol" do
- -> { throw :blah }.should raise_error(UncaughtThrowError)
+ -> { throw :blah }.should.raise(UncaughtThrowError)
end
it "raises ArgumentError if 3 or more arguments provided" do
@@ -54,13 +54,13 @@ describe "Kernel.throw" do
catch :blah do
throw :blah, :return_value, 2
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
catch :blah do
throw :blah, :return_value, 2, 3, 4, 5
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "can throw an object" do
@@ -69,12 +69,12 @@ describe "Kernel.throw" do
catch obj do
throw obj
end
- }.should_not raise_error(NameError)
+ }.should_not.raise(NameError)
end
end
describe "Kernel#throw" do
it "is a private method" do
- Kernel.should have_private_instance_method(:throw)
+ Kernel.private_instance_methods(false).should.include?(:throw)
end
end
diff --git a/spec/ruby/core/kernel/trace_var_spec.rb b/spec/ruby/core/kernel/trace_var_spec.rb
index 3c84aa5e60..150c3da266 100644
--- a/spec/ruby/core/kernel/trace_var_spec.rb
+++ b/spec/ruby/core/kernel/trace_var_spec.rb
@@ -14,7 +14,7 @@ describe "Kernel#trace_var" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:trace_var)
+ Kernel.private_instance_methods(false).should.include?(:trace_var)
end
it "hooks assignments to a global variable" do
@@ -49,6 +49,6 @@ describe "Kernel#trace_var" do
it "raises ArgumentError if no block or proc is provided" do
-> do
trace_var :$Kernel_trace_var_global
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/kernel/trap_spec.rb b/spec/ruby/core/kernel/trap_spec.rb
index 4c801a7215..8f44f3af4b 100644
--- a/spec/ruby/core/kernel/trap_spec.rb
+++ b/spec/ruby/core/kernel/trap_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Kernel#trap" do
it "is a private method" do
- Kernel.should have_private_instance_method(:trap)
+ Kernel.private_instance_methods(false).should.include?(:trap)
end
# Behaviour is specified for Signal.trap
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index db6f17e0fb..ef3fa9a3e1 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -2,27 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#trust" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new.untrust
- o.should_not.untrusted?
- o.trust
- o.should_not.untrusted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = Object.new.untrust
- o.trust
- }.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:trust)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:trust)
end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 26b2aabbe9..47e8544bd4 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -2,27 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new.taint
- o.should_not.tainted?
- o.untaint
- o.should_not.tainted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = Object.new.taint
- o.untaint
- }.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untaint)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untaint)
end
end
diff --git a/spec/ruby/core/kernel/untrace_var_spec.rb b/spec/ruby/core/kernel/untrace_var_spec.rb
index 1925a3a836..8b219801c8 100644
--- a/spec/ruby/core/kernel/untrace_var_spec.rb
+++ b/spec/ruby/core/kernel/untrace_var_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Kernel#untrace_var" do
it "is a private method" do
- Kernel.should have_private_instance_method(:untrace_var)
+ Kernel.private_instance_methods(false).should.include?(:untrace_var)
end
end
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index 5310cd8eb4..8787ab3fc9 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -2,26 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new
- o.untrust
- o.should_not.untrusted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = Object.new
- o.untrust
- }.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untrust)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrust)
end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index ea36d6c98c..29261be9c4 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -2,27 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should_not.untrusted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = mock('o')
- o.untrusted?
- }.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untrusted?)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrusted?)
end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 00164ad90b..189129dd31 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -14,7 +14,7 @@ describe "Kernel#warn" do
end
it "is a private method" do
- Kernel.should have_private_instance_method(:warn)
+ Kernel.private_instance_methods(false).should.include?(:warn)
end
it "accepts multiple arguments" do
@@ -112,6 +112,12 @@ describe "Kernel#warn" do
ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
end
+ it "doesn't show the caller when the uplevel is `nil`" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4("foo", nil) }.should output(nil, "foo\n")
+ end
+
guard -> { Kernel.instance_method(:tap).source_location } do
it "skips <internal: core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
@@ -155,7 +161,7 @@ describe "Kernel#warn" do
-> {
$VERBOSE = true
warn("message", category: Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "converts first arg using to_s" do
@@ -188,19 +194,19 @@ describe "Kernel#warn" do
end
it "raises ArgumentError if passed negative value" do
- -> { warn "", uplevel: -2 }.should raise_error(ArgumentError)
- -> { warn "", uplevel: -100 }.should raise_error(ArgumentError)
+ -> { warn "", uplevel: -2 }.should.raise(ArgumentError)
+ -> { warn "", uplevel: -100 }.should.raise(ArgumentError)
end
it "raises ArgumentError if passed -1" do
- -> { warn "", uplevel: -1 }.should raise_error(ArgumentError)
+ -> { warn "", uplevel: -1 }.should.raise(ArgumentError)
end
it "raises TypeError if passed not Integer" do
- -> { warn "", uplevel: "" }.should raise_error(TypeError)
- -> { warn "", uplevel: [] }.should raise_error(TypeError)
- -> { warn "", uplevel: {} }.should raise_error(TypeError)
- -> { warn "", uplevel: Object.new }.should raise_error(TypeError)
+ -> { warn "", uplevel: "" }.should.raise(TypeError)
+ -> { warn "", uplevel: [] }.should.raise(TypeError)
+ -> { warn "", uplevel: {} }.should.raise(TypeError)
+ -> { warn "", uplevel: Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/main/define_method_spec.rb b/spec/ruby/core/main/define_method_spec.rb
index d85c5e8119..5279d078c3 100644
--- a/spec/ruby/core/main/define_method_spec.rb
+++ b/spec/ruby/core/main/define_method_spec.rb
@@ -14,15 +14,15 @@ describe "main#define_method" do
it 'creates a public method in TOPLEVEL_BINDING' do
eval @code, TOPLEVEL_BINDING
- Object.should have_method :boom
+ Object.should.respond_to? :boom
end
it 'creates a public method in script binding' do
eval @code, script_binding
- Object.should have_method :boom
+ Object.should.respond_to? :boom
end
it 'returns the method name as symbol' do
- eval(@code, TOPLEVEL_BINDING).should equal :boom
+ eval(@code, TOPLEVEL_BINDING).should.equal? :boom
end
end
diff --git a/spec/ruby/core/main/include_spec.rb b/spec/ruby/core/main/include_spec.rb
index 9f5a5f54ea..09f8d4d3b5 100644
--- a/spec/ruby/core/main/include_spec.rb
+++ b/spec/ruby/core/main/include_spec.rb
@@ -4,13 +4,13 @@ require_relative 'fixtures/classes'
describe "main#include" do
it "includes the given Module in Object" do
eval "include MainSpecs::Module", TOPLEVEL_BINDING
- Object.ancestors.should include(MainSpecs::Module)
+ Object.ancestors.should.include?(MainSpecs::Module)
end
context "in a file loaded with wrapping" do
it "includes the given Module in the load wrapper" do
load(File.expand_path("../fixtures/wrapped_include.rb", __FILE__), true)
- Object.ancestors.should_not include(MainSpecs::WrapIncludeModule)
+ Object.ancestors.should_not.include?(MainSpecs::WrapIncludeModule)
end
end
end
diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb
index 76895fd649..56a39ae3c1 100644
--- a/spec/ruby/core/main/private_spec.rb
+++ b/spec/ruby/core/main/private_spec.rb
@@ -10,33 +10,33 @@ describe "main#private" do
context "when single argument is passed and it is not an array" do
it "sets the visibility of the given methods to private" do
eval "private :main_public_method", TOPLEVEL_BINDING
- Object.should have_private_method(:main_public_method)
+ Object.private_methods(true).should.include?(:main_public_method)
end
end
context "when multiple arguments are passed" do
it "sets the visibility of the given methods to private" do
eval "private :main_public_method, :main_public_method2", TOPLEVEL_BINDING
- Object.should have_private_method(:main_public_method)
- Object.should have_private_method(:main_public_method2)
+ Object.private_methods(true).should.include?(:main_public_method)
+ Object.private_methods(true).should.include?(:main_public_method2)
end
end
context "when single argument is passed and is an array" do
it "sets the visibility of the given methods to private" do
eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING
- Object.should have_private_method(:main_public_method)
- Object.should have_private_method(:main_public_method2)
+ Object.private_methods(true).should.include?(:main_public_method)
+ Object.private_methods(true).should.include?(:main_public_method2)
end
end
it "returns argument" do
- eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
+ eval("private :main_public_method", TOPLEVEL_BINDING).should.equal?(:main_public_method)
end
it "raises a NameError when at least one of given method names is undefined" do
-> do
eval "private :main_public_method, :main_undefined_method", TOPLEVEL_BINDING
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb
index 3c77798fbc..89368ebb0d 100644
--- a/spec/ruby/core/main/public_spec.rb
+++ b/spec/ruby/core/main/public_spec.rb
@@ -10,34 +10,34 @@ describe "main#public" do
context "when single argument is passed and it is not an array" do
it "sets the visibility of the given methods to public" do
eval "public :main_private_method", TOPLEVEL_BINDING
- Object.should_not have_private_method(:main_private_method)
+ Object.private_methods(true).should_not.include?(:main_private_method)
end
end
context "when multiple arguments are passed" do
it "sets the visibility of the given methods to public" do
eval "public :main_private_method, :main_private_method2", TOPLEVEL_BINDING
- Object.should_not have_private_method(:main_private_method)
- Object.should_not have_private_method(:main_private_method2)
+ Object.private_methods(true).should_not.include?(:main_private_method)
+ Object.private_methods(true).should_not.include?(:main_private_method2)
end
end
context "when single argument is passed and is an array" do
it "sets the visibility of the given methods to public" do
eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING
- Object.should_not have_private_method(:main_private_method)
- Object.should_not have_private_method(:main_private_method2)
+ Object.private_methods(true).should_not.include?(:main_private_method)
+ Object.private_methods(true).should_not.include?(:main_private_method2)
end
end
it "returns argument" do
- eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
+ eval("public :main_private_method", TOPLEVEL_BINDING).should.equal?(:main_private_method)
end
it "raises a NameError when given an undefined name" do
-> do
eval "public :main_undefined_method", TOPLEVEL_BINDING
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/main/ruby2_keywords_spec.rb b/spec/ruby/core/main/ruby2_keywords_spec.rb
index 27ceae3253..d12c0ed4e4 100644
--- a/spec/ruby/core/main/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/main/ruby2_keywords_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "main.ruby2_keywords" do
it "is the same as Object.ruby2_keywords" do
main = TOPLEVEL_BINDING.receiver
- main.should have_private_method(:ruby2_keywords)
+ main.private_methods(false).should.include?(:ruby2_keywords)
end
end
diff --git a/spec/ruby/core/main/using_spec.rb b/spec/ruby/core/main/using_spec.rb
index 8a23970c4b..314a6be416 100644
--- a/spec/ruby/core/main/using_spec.rb
+++ b/spec/ruby/core/main/using_spec.rb
@@ -5,11 +5,11 @@ describe "main.using" do
it "requires one Module argument" do
-> do
eval('using', TOPLEVEL_BINDING)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
-> do
eval('using "foo"', TOPLEVEL_BINDING)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "uses refinements from the given module only in the target file" do
@@ -19,7 +19,7 @@ describe "main.using" do
MainSpecs::DATA[:toplevel].should == 'foo'
-> do
'hello'.foo
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
it "uses refinements from the given module for method calls in the target file" do
@@ -27,7 +27,7 @@ describe "main.using" do
load File.expand_path('../fixtures/string_refinement_user.rb', __FILE__)
-> do
'hello'.foo
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
MainSpecs.call_foo('hello').should == 'foo'
end
@@ -133,20 +133,18 @@ describe "main.using" do
it "raises error when called from method in wrapped script" do
-> do
load File.expand_path('../fixtures/using_in_method.rb', __FILE__), true
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
end
it "raises error when called on toplevel from module" do
-> do
load File.expand_path('../fixtures/using_in_main.rb', __FILE__), true
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
end
- ruby_version_is "3.2" do
- it "does not raise error when wrapped with module" do
- -> do
- load File.expand_path('../fixtures/using.rb', __FILE__), true
- end.should_not raise_error
- end
+ it "does not raise error when wrapped with module" do
+ -> do
+ load File.expand_path('../fixtures/using.rb', __FILE__), true
+ end.should_not.raise
end
end
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index c2a2b77999..9bbb7809af 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'fixtures/marshal_data'
@@ -116,7 +116,7 @@ describe "Marshal.dump" do
end
it "raises TypeError if an Object is an instance of an anonymous class" do
- -> { Marshal.dump(Class.new(UserMarshal).new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Class.new(UserMarshal).new) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "uses object links for objects repeatedly dumped" do
@@ -157,11 +157,11 @@ describe "Marshal.dump" do
it "raises a TypeError if _dump returns a non-string" do
m = mock("marshaled")
m.should_receive(:_dump).and_return(0)
- -> { Marshal.dump(m) }.should raise_error(TypeError)
+ -> { Marshal.dump(m) }.should.raise(TypeError)
end
it "raises TypeError if an Object is an instance of an anonymous class" do
- -> { Marshal.dump(Class.new(UserDefined).new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Class.new(UserDefined).new) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "favors marshal_dump over _dump" do
@@ -231,9 +231,12 @@ describe "Marshal.dump" do
Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName"
end
- it "dumps a class with multibyte characters in name" do
- source_object = eval("MarshalSpec::MultibyteぁあぃいClass".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class"
+ ruby_version_is "4.0" do
+ it "dumps a class with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteぁあぃいClass".dup.force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bIc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class\x06:\x06ET"
+ Marshal.load(Marshal.dump(source_object)) == source_object
+ end
end
it "uses object links for objects repeatedly dumped" do
@@ -241,11 +244,11 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Class" do
- -> { Marshal.dump(Class.new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Class.new) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "raises TypeError with a singleton Class" do
- -> { Marshal.dump(class << self; self end) }.should raise_error(TypeError)
+ -> { Marshal.dump(class << self; self end) }.should.raise(TypeError)
end
end
@@ -258,9 +261,12 @@ describe "Marshal.dump" do
Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName"
end
- it "dumps a module with multibyte characters in name" do
- source_object = eval("MarshalSpec::MultibyteけげこごModule".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module"
+ ruby_version_is "4.0" do
+ it "dumps a module with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteけげこごModule".dup.force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bIm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module\x06:\x06ET"
+ Marshal.load(Marshal.dump(source_object)) == source_object
+ end
end
it "uses object links for objects repeatedly dumped" do
@@ -268,7 +274,7 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Module" do
- -> { Marshal.dump(Module.new) }.should raise_error(TypeError, /can't dump anonymous module/)
+ -> { Marshal.dump(Module.new) }.should.raise(TypeError, /can't dump anonymous module/)
end
end
@@ -361,30 +367,28 @@ describe "Marshal.dump" do
end
end
- ruby_version_is "3.2" do
- describe "with a Data" do
- it "dumps a Data" do
- Marshal.dump(MarshalSpec::DataSpec::Measure.new(100, 'km')).should == "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- end
+ describe "with a Data" do
+ it "dumps a Data" do
+ Marshal.dump(MarshalSpec::DataSpec::Measure.new(100, 'km')).should == "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ end
- it "dumps an extended Data" do
- obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
- Marshal.dump(obj).should == "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
- end
+ it "dumps an extended Data" do
+ obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
+ Marshal.dump(obj).should == "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
+ end
- it "ignores overridden name method" do
- obj = MarshalSpec::DataSpec::MeasureWithOverriddenName.new(100, "km")
- Marshal.dump(obj).should == "\x04\bS:5MarshalSpec::DataSpec::MeasureWithOverriddenName\a:\vamountii:\tunit\"\akm"
- end
+ it "ignores overridden name method" do
+ obj = MarshalSpec::DataSpec::MeasureWithOverriddenName.new(100, "km")
+ Marshal.dump(obj).should == "\x04\bS:5MarshalSpec::DataSpec::MeasureWithOverriddenName\a:\vamountii:\tunit\"\akm"
+ end
- it "uses object links for objects repeatedly dumped" do
- d = MarshalSpec::DataSpec::Measure.new(100, 'km')
- Marshal.dump([d, d]).should == "\x04\b[\aS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm@\x06" # @\x06 is a link to the object
- end
+ it "uses object links for objects repeatedly dumped" do
+ d = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ Marshal.dump([d, d]).should == "\x04\b[\aS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm@\x06" # @\x06 is a link to the object
+ end
- it "raises TypeError with an anonymous Struct" do
- -> { Marshal.dump(Data.define(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
+ it "raises TypeError with an anonymous Struct" do
+ -> { Marshal.dump(Data.define(:a).new(1)) }.should.raise(TypeError, /can't dump anonymous class/)
end
end
@@ -469,14 +473,26 @@ describe "Marshal.dump" do
Marshal.dump(//im).should == "\x04\bI/\x00\x05\x06:\x06EF"
end
- it "dumps a Regexp with instance variables" do
- o = Regexp.new("")
+ it "dumps a Regexp subclass with instance variables" do
+ o = UserRegexp.new("")
o.instance_variable_set(:@ivar, :ivar)
- Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar"
+ Marshal.dump(o).should == "\x04\bIC:\x0FUserRegexp/\x00\x00\a:\x06EF:\n@ivar:\tivar"
+ end
+
+ it "dumps an extended Regexp subclass" do
+ Marshal.dump(UserRegexp.new("").extend(Meths)).should == "\x04\bIe:\nMethsC:\x0FUserRegexp/\x00\x00\x06:\x06EF"
end
- it "dumps an extended Regexp" do
- Marshal.dump(Regexp.new("").extend(Meths)).should == "\x04\bIe:\nMeths/\x00\x00\x06:\x06EF"
+ ruby_version_is ""..."4.1" do
+ it "dumps a Regexp with instance variables" do
+ o = Regexp.new("")
+ o.instance_variable_set(:@ivar, :ivar)
+ Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar"
+ end
+
+ it "dumps an extended Regexp" do
+ Marshal.dump(Regexp.new("").extend(Meths)).should == "\x04\bIe:\nMeths/\x00\x00\x06:\x06EF"
+ end
end
it "dumps a Regexp subclass" do
@@ -614,7 +630,7 @@ describe "Marshal.dump" do
end
it "raises a TypeError with hash having default proc" do
- -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError, "can't dump hash with default proc")
+ -> { Marshal.dump(Hash.new {}) }.should.raise(TypeError, "can't dump hash with default proc")
end
it "dumps a Hash with instance variables" do
@@ -690,7 +706,7 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Struct" do
- -> { Marshal.dump(Struct.new(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Struct.new(:a).new(1)) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "adds instance variables after the object itself into the objects table" do
@@ -749,7 +765,7 @@ describe "Marshal.dump" do
def obj.foo; end
-> {
Marshal.dump(obj)
- }.should raise_error(TypeError, "singleton can't be dumped")
+ }.should.raise(TypeError, "singleton can't be dumped")
end
it "raises TypeError if an Object has a singleton class and singleton instance variables" do
@@ -760,14 +776,14 @@ describe "Marshal.dump" do
-> {
Marshal.dump(obj)
- }.should raise_error(TypeError, "singleton can't be dumped")
+ }.should.raise(TypeError, "singleton can't be dumped")
end
it "raises TypeError if an Object is an instance of an anonymous class" do
anonymous_class = Class.new
obj = anonymous_class.new
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(obj) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "raises TypeError if an Object extends an anonymous module" do
@@ -775,7 +791,7 @@ describe "Marshal.dump" do
obj = Object.new
obj.extend(anonymous_module)
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(obj) }.should.raise(TypeError, /can't dump anonymous class/)
end
it "dumps a BasicObject subclass if it defines respond_to?" do
@@ -831,7 +847,7 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Range subclass" do
- -> { Marshal.dump(Class.new(Range).new(1, 2)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Class.new(Range).new(1, 2)) }.should.raise(TypeError, /can't dump anonymous class/)
end
end
@@ -861,7 +877,7 @@ describe "Marshal.dump" do
base = "\x04\bIu:\tTime\r#{@t_dump}\a"
offset = ":\voffseti\x020*"
zone = ":\tzoneI\"\bAST\x06:\x06EF" # Last is 'F' (US-ASCII)
- [ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should include(dump)
+ [ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should.include?(dump)
end
end
@@ -873,12 +889,15 @@ describe "Marshal.dump" do
it "ignores overridden name method" do
obj = MarshalSpec::TimeWithOverriddenName.new
- Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName")
+ Marshal.dump(obj).should.include?("MarshalSpec::TimeWithOverriddenName")
end
- it "dumps a Time subclass with multibyte characters in name" do
- source_object = eval("MarshalSpec::MultibyteぁあぃいTime".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time"
+ ruby_version_is "4.0" do
+ it "dumps a Time subclass with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteぁあぃいTime".dup.force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bIc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time\x06:\x06ET"
+ Marshal.load(Marshal.dump(source_object)) == source_object
+ end
end
it "uses object links for objects repeatedly dumped" do
@@ -902,7 +921,7 @@ describe "Marshal.dump" do
end
it "raises TypeError with an anonymous Time subclass" do
- -> { Marshal.dump(Class.new(Time).now) }.should raise_error(TypeError)
+ -> { Marshal.dump(Class.new(Time).now) }.should.raise(TypeError)
end
end
@@ -935,13 +954,13 @@ describe "Marshal.dump" do
begin
raise RuntimeError, "the consequence"
rescue RuntimeError => e
- e.cause.should equal(cause)
+ e.cause.should.equal?(cause)
exc = e
end
end
reloaded = Marshal.load(Marshal.dump(exc))
- reloaded.cause.should be_an_instance_of(StandardError)
+ reloaded.cause.should.instance_of?(StandardError)
reloaded.cause.message.should == "the cause"
end
@@ -974,7 +993,7 @@ describe "Marshal.dump" do
anonymous_class = Class.new(Exception)
obj = anonymous_class.new
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(obj) }.should.raise(TypeError, /can't dump anonymous class/)
end
end
@@ -995,10 +1014,10 @@ describe "Marshal.dump" do
it "raises an ArgumentError when the recursion limit is exceeded" do
h = {'one' => {'two' => {'three' => 0}}}
- -> { Marshal.dump(h, 3) }.should raise_error(ArgumentError)
- -> { Marshal.dump([h], 4) }.should raise_error(ArgumentError)
- -> { Marshal.dump([], 0) }.should raise_error(ArgumentError)
- -> { Marshal.dump([[[]]], 1) }.should raise_error(ArgumentError)
+ -> { Marshal.dump(h, 3) }.should.raise(ArgumentError)
+ -> { Marshal.dump([h], 4) }.should.raise(ArgumentError)
+ -> { Marshal.dump([], 0) }.should.raise(ArgumentError)
+ -> { Marshal.dump([[[]]], 1) }.should.raise(ArgumentError)
end
it "ignores the recursion limit if the limit is negative" do
@@ -1020,7 +1039,7 @@ describe "Marshal.dump" do
it "raises an Error when the IO-Object does not respond to #write" do
obj = mock('test')
- -> { Marshal.dump("test", obj) }.should raise_error(TypeError)
+ -> { Marshal.dump("test", obj) }.should.raise(TypeError)
end
@@ -1035,29 +1054,29 @@ describe "Marshal.dump" do
describe "when passed a StringIO" do
it "should raise an error" do
require "stringio"
- -> { Marshal.dump(StringIO.new) }.should raise_error(TypeError)
+ -> { Marshal.dump(StringIO.new) }.should.raise(TypeError)
end
end
it "raises a TypeError if marshalling a Method instance" do
- -> { Marshal.dump(Marshal.method(:dump)) }.should raise_error(TypeError)
+ -> { Marshal.dump(Marshal.method(:dump)) }.should.raise(TypeError)
end
it "raises a TypeError if marshalling a Proc" do
- -> { Marshal.dump(proc {}) }.should raise_error(TypeError)
+ -> { Marshal.dump(proc {}) }.should.raise(TypeError)
end
it "raises a TypeError if dumping a IO/File instance" do
- -> { Marshal.dump(STDIN) }.should raise_error(TypeError)
- -> { File.open(__FILE__) { |f| Marshal.dump(f) } }.should raise_error(TypeError)
+ -> { Marshal.dump(STDIN) }.should.raise(TypeError)
+ -> { File.open(__FILE__) { |f| Marshal.dump(f) } }.should.raise(TypeError)
end
it "raises a TypeError if dumping a MatchData instance" do
- -> { Marshal.dump(/(.)/.match("foo")) }.should raise_error(TypeError)
+ -> { Marshal.dump(/(.)/.match("foo")) }.should.raise(TypeError)
end
it "raises a TypeError if dumping a Mutex instance" do
m = Mutex.new
- -> { Marshal.dump(m) }.should raise_error(TypeError)
+ -> { Marshal.dump(m) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb
index 3ba85aa6eb..c16d9e4bb6 100644
--- a/spec/ruby/core/marshal/fixtures/marshal_data.rb
+++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative 'marshal_multibyte_data'
@@ -532,18 +532,16 @@ module MarshalSpec
"Random" => random_data,
}
- if defined? Data # TODO: remove the condition when minimal supported version is 3.2
- module DataSpec
- Measure = Data.define(:amount, :unit)
- Empty = Data.define
+ module DataSpec
+ Measure = Data.define(:amount, :unit)
+ Empty = Data.define
- MeasureExtended = Class.new(Measure)
- MeasureExtended.extend(Enumerable)
+ MeasureExtended = Class.new(Measure)
+ MeasureExtended.extend(Enumerable)
- class MeasureWithOverriddenName < Measure
- def self.name
- "Foo"
- end
+ class MeasureWithOverriddenName < Measure
+ def self.name
+ "Foo"
end
end
end
diff --git a/spec/ruby/core/marshal/float_spec.rb b/spec/ruby/core/marshal/float_spec.rb
index 5793bbd564..5b2d68d6e1 100644
--- a/spec/ruby/core/marshal/float_spec.rb
+++ b/spec/ruby/core/marshal/float_spec.rb
@@ -40,7 +40,7 @@ end
describe "Marshal.load with Float" do
it "loads NaN" do
- Marshal.load("\004\bf\bnan").should be_nan
+ Marshal.load("\004\bf\bnan").should.nan?
end
it "loads +Infinity" do
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index f73fa67e9a..02c8e7f0b1 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../fixtures/marshal_data'
describe :marshal_load, shared: true do
@@ -8,11 +8,11 @@ describe :marshal_load, shared: true do
it "raises an ArgumentError when the dumped data is truncated" do
obj = {first: 1, second: 2, third: 3}
- -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError, "marshal data too short")
+ -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should.raise(ArgumentError, "marshal data too short")
end
it "raises an ArgumentError when the argument is empty String" do
- -> { Marshal.send(@method, "") }.should raise_error(ArgumentError, "marshal data too short")
+ -> { Marshal.send(@method, "") }.should.raise(ArgumentError, "marshal data too short")
end
it "raises an ArgumentError when the dumped class is missing" do
@@ -20,7 +20,7 @@ describe :marshal_load, shared: true do
kaboom = Marshal.dump(KaBoom.new)
Object.send(:remove_const, :KaBoom)
- -> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, kaboom) }.should.raise(ArgumentError)
end
describe "when called with freeze: true" do
@@ -111,7 +111,7 @@ describe :marshal_load, shared: true do
source_object = ["foo" + "bar", "foobar"]
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- object[0].should equal(object[1])
+ object[0].should.equal?(object[1])
end
end
@@ -127,36 +127,32 @@ describe :marshal_load, shared: true do
Object.should_not.frozen?
end
- ruby_bug "#19427", ""..."3.3" do
- it "does freeze extended objects" do
- object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
- object.should.frozen?
- end
+ it "does freeze extended objects" do
+ object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
+ object.should.frozen?
+ end
- it "does freeze extended objects with instance variables" do
- object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
- object.should.frozen?
- end
+ it "does freeze extended objects with instance variables" do
+ object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
+ object.should.frozen?
end
- ruby_bug "#19427", "3.1"..."3.3" do
- it "returns frozen object having #_dump method" do
- object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
- object.should.frozen?
- end
+ it "returns frozen object having #_dump method" do
+ object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
+ object.should.frozen?
+ end
- it "returns frozen object responding to #marshal_dump and #marshal_load" do
- object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
- object.should.frozen?
- end
+ it "returns frozen object responding to #marshal_dump and #marshal_load" do
+ object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
+ object.should.frozen?
+ end
- it "returns frozen object extended by a module" do
- object = Object.new
- object.extend(MarshalSpec::ModuleToExtendBy)
+ it "returns frozen object extended by a module" do
+ object = Object.new
+ object.extend(MarshalSpec::ModuleToExtendBy)
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
- object.should.frozen?
- end
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
end
it "does not call freeze method" do
@@ -239,12 +235,10 @@ describe :marshal_load, shared: true do
string.should.frozen?
end
- ruby_bug "#19427", ""..."3.3" do
- it "call the proc with extended objects" do
- objs = []
- obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o })
- objs.should == [obj]
- end
+ it "call the proc with extended objects" do
+ objs = []
+ obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o })
+ objs.should == [obj]
end
it "returns the value of the proc" do
@@ -303,9 +297,9 @@ describe :marshal_load, shared: true do
UserPreviouslyDefinedWithInitializedIvar.should_receive(:_load).and_return(UserPreviouslyDefinedWithInitializedIvar.new)
marshaled_obj = Marshal.send(@method, dump_str)
- marshaled_obj.should be_an_instance_of(UserPreviouslyDefinedWithInitializedIvar)
- marshaled_obj.field1.should be_nil
- marshaled_obj.field2.should be_nil
+ marshaled_obj.should.instance_of?(UserPreviouslyDefinedWithInitializedIvar)
+ marshaled_obj.field1.should == nil
+ marshaled_obj.field2.should == nil
end
it "loads the String in non US-ASCII and non UTF-8 encoding" do
@@ -409,20 +403,20 @@ describe :marshal_load, shared: true do
marshal_data[0] = (Marshal::MAJOR_VERSION).chr
marshal_data[1] = (Marshal::MINOR_VERSION + 1).chr
- -> { Marshal.send(@method, marshal_data) }.should raise_error(TypeError)
+ -> { Marshal.send(@method, marshal_data) }.should.raise(TypeError)
marshal_data = +'\xff\xff'
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
marshal_data[1] = (Marshal::MINOR_VERSION).chr
- -> { Marshal.send(@method, marshal_data) }.should raise_error(TypeError)
+ -> { Marshal.send(@method, marshal_data) }.should.raise(TypeError)
end
it "raises EOFError on loading an empty file" do
temp_file = tmp("marshal.rubyspec.tmp.#{Process.pid}")
file = File.new(temp_file, "w+")
begin
- -> { Marshal.send(@method, file) }.should raise_error(EOFError)
+ -> { Marshal.send(@method, file) }.should.raise(EOFError)
ensure
file.close
rm_r temp_file
@@ -468,7 +462,7 @@ describe :marshal_load, shared: true do
obj.instance_variable_set(:@mix, s)
new_obj = Marshal.send(@method, "\004\bI[\b\"\0065I\"\twell\006:\t@fooi\017\"\ahi\006:\t@mix@\a")
new_obj.should == obj
- new_obj.instance_variable_get(:@mix).should equal new_obj[1]
+ new_obj.instance_variable_get(:@mix).should.equal? new_obj[1]
new_obj[1].instance_variable_get(:@foo).should == 10
end
@@ -619,7 +613,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\x04\b:\nhel")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -639,7 +633,7 @@ describe :marshal_load, shared: true do
it "sets binmode if it is loading through StringIO stream" do
io = StringIO.new("\004\b:\vsymbol")
def io.binmode; raise "binmode"; end
- -> { Marshal.load(io) }.should raise_error(RuntimeError, "binmode")
+ -> { Marshal.load(io) }.should.raise(RuntimeError, "binmode")
end
it "loads a string with an ivar" do
@@ -649,7 +643,7 @@ describe :marshal_load, shared: true do
it "loads a String subclass with custom constructor" do
str = Marshal.send(@method, "\x04\bC: UserCustomConstructorString\"\x00")
- str.should be_an_instance_of(UserCustomConstructorString)
+ str.should.instance_of?(UserCustomConstructorString)
end
it "loads a US-ASCII String" do
@@ -657,7 +651,7 @@ describe :marshal_load, shared: true do
data = "\x04\bI\"\babc\x06:\x06EF"
result = Marshal.send(@method, data)
result.should == str
- result.encoding.should equal(Encoding::US_ASCII)
+ result.encoding.should.equal?(Encoding::US_ASCII)
end
it "loads a UTF-8 String" do
@@ -665,7 +659,7 @@ describe :marshal_load, shared: true do
data = "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
result = Marshal.send(@method, data)
result.should == str
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "loads a String in another encoding" do
@@ -673,7 +667,7 @@ describe :marshal_load, shared: true do
data = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
result = Marshal.send(@method, data)
result.should == str
- result.encoding.should equal(Encoding::UTF_16LE)
+ result.encoding.should.equal?(Encoding::UTF_16LE)
end
it "loads a String as BINARY if no encoding is specified at the end" do
@@ -689,7 +683,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\x04\b\"\nhel")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -739,31 +733,29 @@ describe :marshal_load, shared: true do
end
end
- ruby_version_is "3.2" do
- describe "for a Data" do
- it "loads a Data" do
- obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
- dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
+ describe "for a Data" do
+ it "loads a Data" do
+ obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
- Marshal.send(@method, dumped).should == obj
- end
+ Marshal.send(@method, dumped).should == obj
+ end
- it "loads an extended Data" do
- obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
- dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
+ it "loads an extended Data" do
+ obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
+ dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
- Marshal.send(@method, dumped).should == obj
- end
+ Marshal.send(@method, dumped).should == obj
+ end
- it "returns a frozen object" do
- obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
- dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
+ it "returns a frozen object" do
+ obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
- Marshal.send(@method, dumped).should.frozen?
- end
+ Marshal.send(@method, dumped).should.frozen?
end
end
@@ -815,7 +807,7 @@ describe :marshal_load, shared: true do
describe "for an Object" do
it "loads an object" do
- Marshal.send(@method, "\004\bo:\vObject\000").should be_kind_of(Object)
+ Marshal.send(@method, "\004\bo:\vObject\000").should.is_a?(Object)
end
it "loads an extended Object" do
@@ -851,7 +843,7 @@ describe :marshal_load, shared: true do
it "raises ArgumentError if the object from an 'o' stream is not dumpable as 'o' type user class" do
-> do
Marshal.send(@method, "\x04\bo:\tFile\001\001:\001\005@path\"\x10/etc/passwd")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when end of byte sequence reached before class name end" do
@@ -859,7 +851,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\x04\bo:\vObj")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -887,7 +879,7 @@ describe :marshal_load, shared: true do
end
it "loads a UserObject" do
- Marshal.send(@method, "\004\bo:\017UserObject\000").should be_kind_of(UserObject)
+ Marshal.send(@method, "\004\bo:\017UserObject\000").should.is_a?(UserObject)
end
describe "that extends a core type other than Object or BasicObject" do
@@ -900,23 +892,61 @@ describe :marshal_load, shared: true do
data = Marshal.dump(MarshalSpec::SwappedClass.new)
MarshalSpec.set_swapped_class(Class.new(Array))
- -> { Marshal.send(@method, data) }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, data) }.should.raise(ArgumentError)
MarshalSpec.set_swapped_class(Class.new)
- -> { Marshal.send(@method, data) }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, data) }.should.raise(ArgumentError)
end
end
end
describe "for a Regexp" do
- it "loads an extended Regexp" do
- obj = /[a-z]/.dup.extend(Meths, MethsMore)
- new_obj = Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
+ ruby_version_is "4.1" do
+ it "raises FrozenError for an extended Regexp" do
+ -> {
+ Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
+ }.should.raise(FrozenError)
+ end
+
+ it "raises FrozenError when regexp has instance variables" do
+ -> {
+ Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ }.should.raise(FrozenError)
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "loads an extended Regexp" do
+ obj = /[a-z]/.dup.extend(Meths, MethsMore)
+ new_obj = Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
+
+ new_obj.should == obj
+ new_obj_metaclass_ancestors = class << new_obj; ancestors; end
+ new_obj_metaclass_ancestors[@num_self_class, 3].should ==
+ [Meths, MethsMore, Regexp]
+ end
+
+ it "restore the regexp instance variables" do
+ obj = Regexp.new("hello")
+ obj.instance_variable_set(:@regexp_ivar, [42])
+
+ new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ new_obj.instance_variables.should == [:@regexp_ivar]
+ new_obj.instance_variable_get(:@regexp_ivar).should == [42]
+ end
+ end
+
+ it "loads a Regexp subclass instance variables" do
+ obj = UserRegexp.new('abc')
+ obj.instance_variable_set(:@noise, 'much')
+
+ new_obj = Marshal.send(@method, Marshal.dump(obj))
new_obj.should == obj
+ new_obj.instance_variable_get(:@noise).should == 'much'
new_obj_metaclass_ancestors = class << new_obj; ancestors; end
- new_obj_metaclass_ancestors[@num_self_class, 3].should ==
- [Meths, MethsMore, Regexp]
+ new_obj_metaclass_ancestors[@num_self_class, 2].should ==
+ [UserRegexp, Regexp]
end
it "loads a Regexp subclass instance variables when it is extended with a module" do
@@ -932,17 +962,6 @@ describe :marshal_load, shared: true do
[Meths, UserRegexp, Regexp]
end
- ruby_bug "#19439", ""..."3.3" do
- it "restore the regexp instance variables" do
- obj = Regexp.new("hello")
- obj.instance_variable_set(:@regexp_ivar, [42])
-
- new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
- new_obj.instance_variables.should == [:@regexp_ivar]
- new_obj.instance_variable_get(:@regexp_ivar).should == [42]
- end
- end
-
it "preserves Regexp encoding" do
source_object = Regexp.new("a".encode("utf-32le"))
regexp = Marshal.send(@method, Marshal.dump(source_object))
@@ -956,7 +975,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\x04\bI/\x10hel")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -985,7 +1004,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\004\bf\v1")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -1039,7 +1058,7 @@ describe :marshal_load, shared: true do
"\004\bi\004\0",
"\004\bi\004\0\0",
"\004\bi\004\0\0\0"].each do |invalid|
- -> { Marshal.send(@method, invalid) }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, invalid) }.should.raise(ArgumentError)
end
end
@@ -1100,7 +1119,7 @@ describe :marshal_load, shared: true do
t = Time.new
t1, t2 = Marshal.send(@method, Marshal.dump([t, t]))
- t1.should equal t2
+ t1.should.equal? t2
end
it "keeps the local zone" do
@@ -1148,19 +1167,19 @@ describe :marshal_load, shared: true do
describe "for nil" do
it "loads" do
- Marshal.send(@method, "\x04\b0").should be_nil
+ Marshal.send(@method, "\x04\b0").should == nil
end
end
describe "for true" do
it "loads" do
- Marshal.send(@method, "\x04\bT").should be_true
+ Marshal.send(@method, "\x04\bT").should == true
end
end
describe "for false" do
it "loads" do
- Marshal.send(@method, "\x04\bF").should be_false
+ Marshal.send(@method, "\x04\bF").should == false
end
end
@@ -1170,11 +1189,11 @@ describe :marshal_load, shared: true do
end
it "raises ArgumentError if given the name of a non-Module" do
- -> { Marshal.send(@method, "\x04\bc\vKernel") }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, "\x04\bc\vKernel") }.should.raise(ArgumentError)
end
it "raises ArgumentError if given a nonexistent class" do
- -> { Marshal.send(@method, "\x04\bc\vStrung") }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, "\x04\bc\vStrung") }.should.raise(ArgumentError)
end
it "raises ArgumentError when end of byte sequence reached before class name end" do
@@ -1182,7 +1201,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\x04\bc\vStr")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -1192,7 +1211,7 @@ describe :marshal_load, shared: true do
end
it "raises ArgumentError if given the name of a non-Class" do
- -> { Marshal.send(@method, "\x04\bm\vString") }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, "\x04\bm\vString") }.should.raise(ArgumentError)
end
it "loads an old module" do
@@ -1204,7 +1223,7 @@ describe :marshal_load, shared: true do
-> {
Marshal.send(@method, "\x04\bm\vKer")
- }.should raise_error(ArgumentError, "marshal data too short")
+ }.should.raise(ArgumentError, "marshal data too short")
end
end
@@ -1239,13 +1258,13 @@ describe :marshal_load, shared: true do
data = "\x04\bd:\x1AUnloadableDumpableDirI\"\x06.\x06:\x06ET"
- -> { Marshal.send(@method, data) }.should raise_error(TypeError)
+ -> { Marshal.send(@method, data) }.should.raise(TypeError)
end
it "raises ArgumentError when the local class is a regular object" do
data = "\004\bd:\020UserDefined\0"
- -> { Marshal.send(@method, data) }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, data) }.should.raise(ArgumentError)
end
end
@@ -1258,7 +1277,7 @@ describe :marshal_load, shared: true do
it "raises an ArgumentError" do
message = "undefined class/module NamespaceTest::SameName"
- -> { Marshal.send(@method, @data) }.should raise_error(ArgumentError, message)
+ -> { Marshal.send(@method, @data) }.should.raise(ArgumentError, message)
end
end
@@ -1267,6 +1286,6 @@ describe :marshal_load, shared: true do
@data = Marshal.dump(NamespaceTest::KaBoom.new)
NamespaceTest.send(:remove_const, :KaBoom)
- -> { Marshal.send(@method, @data) }.should raise_error(ArgumentError, /NamespaceTest::KaBoom/)
+ -> { Marshal.send(@method, @data) }.should.raise(ArgumentError, /NamespaceTest::KaBoom/)
end
end
diff --git a/spec/ruby/core/matchdata/allocate_spec.rb b/spec/ruby/core/matchdata/allocate_spec.rb
index 142ce639c2..f41e2d5481 100644
--- a/spec/ruby/core/matchdata/allocate_spec.rb
+++ b/spec/ruby/core/matchdata/allocate_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "MatchData.allocate" do
it "is undefined" do
# https://bugs.ruby-lang.org/issues/16294
- -> { MatchData.allocate }.should raise_error(NoMethodError)
+ -> { MatchData.allocate }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/matchdata/begin_spec.rb b/spec/ruby/core/matchdata/begin_spec.rb
index 54b4e0a33f..b4be077ae4 100644
--- a/spec/ruby/core/matchdata/begin_spec.rb
+++ b/spec/ruby/core/matchdata/begin_spec.rb
@@ -12,7 +12,7 @@ describe "MatchData#begin" do
it "returns nil when the nth match isn't found" do
match_data = /something is( not)? (right)/.match("something is right")
- match_data.begin(1).should be_nil
+ match_data.begin(1).should == nil
end
it "returns the character offset for multi-byte strings" do
@@ -42,11 +42,11 @@ describe "MatchData#begin" do
-> {
match_data.begin(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
+ }.should.raise(IndexError, "index -1 out of matches")
-> {
match_data.begin(3)
- }.should raise_error(IndexError, "index 3 out of matches")
+ }.should.raise(IndexError, "index 3 out of matches")
end
end
@@ -86,7 +86,7 @@ describe "MatchData#begin" do
-> {
match_data.begin("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
+ }.should.raise(IndexError, "undefined group name reference: y")
end
end
@@ -126,7 +126,7 @@ describe "MatchData#begin" do
-> {
match_data.begin(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
+ }.should.raise(IndexError, "undefined group name reference: y")
end
end
end
diff --git a/spec/ruby/core/matchdata/bytebegin_spec.rb b/spec/ruby/core/matchdata/bytebegin_spec.rb
new file mode 100644
index 0000000000..fa44ec3b41
--- /dev/null
+++ b/spec/ruby/core/matchdata/bytebegin_spec.rb
@@ -0,0 +1,132 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "MatchData#bytebegin" do
+ context "when passed an integer argument" do
+ it "returns the byte-based offset of the start of the nth element" do
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 2
+ end
+
+ it "returns nil when the nth match isn't found" do
+ match_data = /something is( not)? (right)/.match("something is right")
+ match_data.bytebegin(1).should == nil
+ end
+
+ it "returns the byte-based offset for multi-byte strings" do
+ match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 3
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi-byte strings with unicode regexp" do
+ match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 3
+ end
+ end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(2)
+
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(obj).should == 2
+ end
+
+ it "raises IndexError if index is out of bounds" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin(-1)
+ }.should.raise(IndexError, "index -1 out of matches")
+
+ -> {
+ match_data.bytebegin(3)
+ }.should.raise(IndexError, "index 3 out of matches")
+ end
+ end
+
+ context "when passed a String argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 3
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 4
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("a").should == 3
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("æ").should == 1
+ end
+
+ it "raises IndexError if there is no group with the provided name" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin("y")
+ }.should.raise(IndexError, "undefined group name reference: y")
+ end
+ end
+
+ context "when passed a Symbol argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 3
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 4
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:a).should == 3
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:æ).should == 1
+ end
+
+ it "raises IndexError if there is no group with the provided name" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin(:y)
+ }.should.raise(IndexError, "undefined group name reference: y")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/byteend_spec.rb b/spec/ruby/core/matchdata/byteend_spec.rb
new file mode 100644
index 0000000000..e77cbf8b0d
--- /dev/null
+++ b/spec/ruby/core/matchdata/byteend_spec.rb
@@ -0,0 +1,104 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "MatchData#byteend" do
+ context "when passed an integer argument" do
+ it "returns the byte-based offset of the end of the nth element" do
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.byteend(0).should == 7
+ match_data.byteend(2).should == 3
+ end
+
+ it "returns nil when the nth match isn't found" do
+ match_data = /something is( not)? (right)/.match("something is right")
+ match_data.byteend(1).should == nil
+ end
+
+ it "returns the byte-based offset for multi-byte strings" do
+ match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
+ match_data.byteend(0).should == 8
+ match_data.byteend(2).should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi-byte strings with unicode regexp" do
+ match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend(0).should == 8
+ match_data.byteend(2).should == 4
+ end
+ end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(2)
+
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.byteend(obj).should == 3
+ end
+ end
+
+ context "when passed a String argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("a").should == 2
+ match_data.byteend("b").should == 6
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.byteend("a").should == 3
+ match_data.byteend("b").should == 7
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend("a").should == 3
+ match_data.byteend("b").should == 7
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("a").should == 6
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("æ").should == 2
+ end
+ end
+
+ context "when passed a Symbol argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:a).should == 2
+ match_data.byteend(:b).should == 6
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.byteend(:a).should == 3
+ match_data.byteend(:b).should == 7
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend(:a).should == 3
+ match_data.byteend(:b).should == 7
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:a).should == 6
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:æ).should == 2
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
index b27267fd0e..062e84027c 100644
--- a/spec/ruby/core/matchdata/byteoffset_spec.rb
+++ b/spec/ruby/core/matchdata/byteoffset_spec.rb
@@ -1,95 +1,93 @@
require_relative '../../spec_helper'
describe "MatchData#byteoffset" do
- ruby_version_is "3.2" do
- it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- m.byteoffset(0).should == [1, 7]
- end
+ it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.byteoffset(0).should == [1, 7]
+ end
- it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- m.byteoffset(2).should == [2, 3]
- m.byteoffset(3).should == [3, 6]
- m.byteoffset(4).should == [6, 7]
- end
+ m.byteoffset(2).should == [2, 3]
+ m.byteoffset(3).should == [3, 6]
+ m.byteoffset(4).should == [6, 7]
+ end
- it "accepts String as a reference to a named capture" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.byteoffset("f").should == [0, 3]
- m.byteoffset("b").should == [3, 6]
- end
+ m.byteoffset("f").should == [0, 3]
+ m.byteoffset("b").should == [3, 6]
+ end
- it "accepts Symbol as a reference to a named capture" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.byteoffset(:f).should == [0, 3]
- m.byteoffset(:b).should == [3, 6]
- end
+ m.byteoffset(:f).should == [0, 3]
+ m.byteoffset(:b).should == [3, 6]
+ end
- it "returns [nil, nil] if a capturing group is optional and doesn't match" do
- m = /(?<x>q..)?/.match("foobarbaz")
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
- m.byteoffset("x").should == [nil, nil]
- m.byteoffset(1).should == [nil, nil]
- end
+ m.byteoffset("x").should == [nil, nil]
+ m.byteoffset(1).should == [nil, nil]
+ end
- it "returns correct beginning and ending byte-based offset for multi-byte strings" do
- m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+ it "returns correct beginning and ending byte-based offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
- m.byteoffset(1).should == [3, 6]
- m.byteoffset(3).should == [6, 9]
- end
+ m.byteoffset(1).should == [3, 6]
+ m.byteoffset(3).should == [6, 9]
+ end
- it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
- m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+ it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
- m.byteoffset(2).should == [nil, nil]
- end
+ m.byteoffset(2).should == [nil, nil]
+ end
- it "converts argument into integer if is not String nor Symbol" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "converts argument into integer if is not String nor Symbol" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- obj = Object.new
- def obj.to_int; 2; end
+ obj = Object.new
+ def obj.to_int; 2; end
- m.byteoffset(1r).should == [0, 3]
- m.byteoffset(1.1).should == [0, 3]
- m.byteoffset(obj).should == [3, 6]
- end
+ m.byteoffset(1r).should == [0, 3]
+ m.byteoffset(1.1).should == [0, 3]
+ m.byteoffset(obj).should == [3, 6]
+ end
- it "raises IndexError if there is no group with the provided name" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "raises IndexError if there is no group with the provided name" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.byteoffset("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
+ -> {
+ m.byteoffset("y")
+ }.should.raise(IndexError, "undefined group name reference: y")
- -> {
- m.byteoffset(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
- end
+ -> {
+ m.byteoffset(:y)
+ }.should.raise(IndexError, "undefined group name reference: y")
+ end
- it "raises IndexError if index is out of bounds" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "raises IndexError if index is out of bounds" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.byteoffset(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
+ -> {
+ m.byteoffset(-1)
+ }.should.raise(IndexError, "index -1 out of matches")
- -> {
- m.byteoffset(3)
- }.should raise_error(IndexError, "index 3 out of matches")
- end
+ -> {
+ m.byteoffset(3)
+ }.should.raise(IndexError, "index 3 out of matches")
+ end
- it "raises TypeError if can't convert argument into Integer" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "raises TypeError if can't convert argument into Integer" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.byteoffset([])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
- end
+ -> {
+ m.byteoffset([])
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
index 5b68f886c7..9126d20394 100644
--- a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
@@ -1,65 +1,78 @@
require_relative '../../spec_helper'
describe "MatchData#deconstruct_keys" do
- ruby_version_is "3.2" do
- it "returns whole hash for nil as an argument" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "returns whole hash for nil as an argument" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
- end
+ m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
+ end
+
+ it "returns only specified keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- it "returns only specified keys" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([:f]).should == { f: "foo" }
+ end
- m.deconstruct_keys([:f]).should == { f: "foo" }
- end
+ it "requires one argument" do
+ m = /l/.match("l")
- it "requires one argument" do
- m = /l/.match("l")
+ -> {
+ m.deconstruct_keys
+ }.should.raise(ArgumentError, "wrong number of arguments (given 0, expected 1)")
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> { m.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array)")
+ -> { m.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array)")
+ -> { m.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array)")
+ -> { m.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array)")
+ end
- -> {
- m.deconstruct_keys
- }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
- end
+ it "returns {} when passed []" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- it "it raises error when argument is neither nil nor array" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([]).should == {}
+ end
- -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)")
- -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)")
- -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)")
- -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)")
- end
+ it "does not accept non-Symbol keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- it "returns {} when passed []" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ -> {
+ m.deconstruct_keys(['year', :foo])
+ }.should.raise(TypeError, "wrong argument type String (expected Symbol)")
+ end
- m.deconstruct_keys([]).should == {}
- end
+ it "process keys till the first non-existing one" do
+ m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
- it "does not accept non-Symbol keys" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
+ end
- -> {
- m.deconstruct_keys(['year', :foo])
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
- end
+ it "returns {} when there are no named captured groups at all" do
+ m = /foo.+/.match("foobar")
- it "process keys till the first non-existing one" do
- m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
+ m.deconstruct_keys(nil).should == {}
+ end
- m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
- end
+ it "returns {} when passed more keys than named captured groups" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([:f, :b, :c]).should == {}
+ end
- it "returns {} when there are no named captured groups at all" do
- m = /foo.+/.match("foobar")
+ it "includes non-participating captures as nil for nil argument" do
+ m = "hello".match(/(?<a>hello)(?<b>world)?/)
+ m.deconstruct_keys(nil).should == { a: "hello", b: nil }
+ end
- m.deconstruct_keys(nil).should == {}
- end
+ it "includes non-participating captures as nil for explicit keys" do
+ m = "hello".match(/(?<a>hello)(?<b>world)?/)
+ m.deconstruct_keys([:a, :b]).should == { a: "hello", b: nil }
+ end
- it "returns {} when passed more keys than named captured groups" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys([:f, :b, :c]).should == {}
- end
+ it "does not stop iterating at a non-participating capture" do
+ m = "hello!".match(/(?<a>hello)(?<b>world)?(?<c>!)/)
+ m.deconstruct_keys([:b, :c, :a]).should == { b: nil, c: "!", a: "hello" }
end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb
index 6af55113b6..c55095665d 100644
--- a/spec/ruby/core/matchdata/deconstruct_spec.rb
+++ b/spec/ruby/core/matchdata/deconstruct_spec.rb
@@ -2,7 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/captures'
describe "MatchData#deconstruct" do
- ruby_version_is "3.2" do
- it_behaves_like :matchdata_captures, :deconstruct
- end
+ it_behaves_like :matchdata_captures, :deconstruct
end
diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb
index 0924be0aae..5509371cd2 100644
--- a/spec/ruby/core/matchdata/element_reference_spec.rb
+++ b/spec/ruby/core/matchdata/element_reference_spec.rb
@@ -55,7 +55,7 @@ describe "MatchData#[]" do
it "returns instances of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) }
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should.instance_of?(String) }
end
end
@@ -108,12 +108,12 @@ describe "MatchData#[Symbol]" do
it "raises an IndexError if there is no named match corresponding to the Symbol" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
- -> { md[:baz] }.should raise_error(IndexError, /baz/)
+ -> { md[:baz] }.should.raise(IndexError, /baz/)
end
it "raises an IndexError if there is no named match corresponding to the String" do
md = 'haystack'.match(/(?<t>t(?<a>ack))/)
- -> { md['baz'] }.should raise_error(IndexError, /baz/)
+ -> { md['baz'] }.should.raise(IndexError, /baz/)
end
it "returns matches in the String's encoding" do
diff --git a/spec/ruby/core/matchdata/end_spec.rb b/spec/ruby/core/matchdata/end_spec.rb
index d01b0a8b30..4fee24a763 100644
--- a/spec/ruby/core/matchdata/end_spec.rb
+++ b/spec/ruby/core/matchdata/end_spec.rb
@@ -12,7 +12,7 @@ describe "MatchData#end" do
it "returns nil when the nth match isn't found" do
match_data = /something is( not)? (right)/.match("something is right")
- match_data.end(1).should be_nil
+ match_data.end(1).should == nil
end
it "returns the character offset for multi-byte strings" do
diff --git a/spec/ruby/core/matchdata/inspect_spec.rb b/spec/ruby/core/matchdata/inspect_spec.rb
index 5315257677..cacbe10c5d 100644
--- a/spec/ruby/core/matchdata/inspect_spec.rb
+++ b/spec/ruby/core/matchdata/inspect_spec.rb
@@ -6,7 +6,7 @@ describe "MatchData#inspect" do
end
it "returns a String" do
- @match_data.inspect.should be_kind_of(String)
+ @match_data.inspect.should.is_a?(String)
end
it "returns a human readable representation that contains entire matched string and the captures" do
diff --git a/spec/ruby/core/matchdata/integer_at_spec.rb b/spec/ruby/core/matchdata/integer_at_spec.rb
new file mode 100644
index 0000000000..65f73a7bee
--- /dev/null
+++ b/spec/ruby/core/matchdata/integer_at_spec.rb
@@ -0,0 +1,38 @@
+# -*- encoding: utf-8 -*-
+
+require_relative '../../spec_helper'
+
+ruby_version_is "4.1" do
+ describe "MatchData#integer_at" do
+ it "converts the corresponding match to an Integer and returns it when given an Integer" do
+ md = /(\d{4})(\d{2})(\d{2})/.match("20260308")
+ md.integer_at(0).should == 20260308
+ md.integer_at(1).should == 2026
+ md.integer_at(2).should == 3
+ end
+
+ it "returns nil on non-matching index matches" do
+ md = /\b(\d)?\b/.match("THX1138.")
+ md.integer_at(1).should == nil
+ end
+
+ it "returns nil on non-integer matches" do
+ md = /(\w)?/.match("THX1138.")
+ md.integer_at(1).should == nil
+ end
+
+ it "converts the match to an Integer in the given base" do
+ md = /\w+/.match("0c")
+ md.integer_at(0).should == 0
+ md.integer_at(0, 16).should == 12
+ end
+
+ it "converts the match to an Integer in the prefix when given base is zero" do
+ /\w+/.match("010").integer_at(0, 0).should == 010
+ /\w+/.match("0x10").integer_at(0, 0).should == 0x10
+ /\w+/.match("0d10").integer_at(0, 0).should == 0d10
+ /\w+/.match("0o10").integer_at(0, 0).should == 0o10
+ /\w+/.match("0b10").integer_at(0, 0).should == 0b10
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb
index 5e4693d62d..10b1f884d6 100644
--- a/spec/ruby/core/matchdata/named_captures_spec.rb
+++ b/spec/ruby/core/matchdata/named_captures_spec.rb
@@ -13,15 +13,13 @@ describe 'MatchData#named_captures' do
/\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' }
end
- ruby_version_is "3.3" do
- it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do
- /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
- /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil }
- end
+ it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do
+ /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
+ /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil }
+ end
- it 'returns a Hash with String keys when symbolize_names is provided a false value' do
- /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
- /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
- end
+ it 'returns a Hash with String keys when symbolize_names is provided a false value' do
+ /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
+ /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
end
end
diff --git a/spec/ruby/core/matchdata/names_spec.rb b/spec/ruby/core/matchdata/names_spec.rb
index 25ca06ced9..dca15985b0 100644
--- a/spec/ruby/core/matchdata/names_spec.rb
+++ b/spec/ruby/core/matchdata/names_spec.rb
@@ -3,12 +3,12 @@ require_relative '../../spec_helper'
describe "MatchData#names" do
it "returns an Array" do
md = 'haystack'.match(/(?<yellow>hay)/)
- md.names.should be_an_instance_of(Array)
+ md.names.should.instance_of?(Array)
end
it "sets each element to a String" do
'haystack'.match(/(?<yellow>hay)/).names.all? do |e|
- e.should be_an_instance_of(String)
+ e.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/offset_spec.rb b/spec/ruby/core/matchdata/offset_spec.rb
index 1ccb54b7a7..5a923d6ce0 100644
--- a/spec/ruby/core/matchdata/offset_spec.rb
+++ b/spec/ruby/core/matchdata/offset_spec.rb
@@ -1,30 +1,102 @@
-# -*- encoding: utf-8 -*-
-
require_relative '../../spec_helper'
describe "MatchData#offset" do
- it "returns a two element array with the begin and end of the nth match" do
- match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns beginning and ending character offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.offset(0).should == [1, 7]
+ end
+
+ it "returns beginning and ending character offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+
+ m.offset(2).should == [2, 3]
+ m.offset(3).should == [3, 6]
+ m.offset(4).should == [6, 7]
+ end
+
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.offset("f").should == [0, 3]
+ m.offset("b").should == [3, 6]
+ end
+
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.offset(:f).should == [0, 3]
+ m.offset(:b).should == [3, 6]
end
- it "returns [nil, nil] when the nth match isn't found" do
- match_data = /something is( not)? (right)/.match("something is right")
- match_data.offset(1).should == [nil, nil]
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
+
+ m.offset("x").should == [nil, nil]
+ m.offset(1).should == [nil, nil]
end
- it "returns the offset for multi byte strings" do
- match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns correct beginning and ending character offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.offset(1).should == [1, 2]
+ m.offset(3).should == [2, 3]
end
not_supported_on :opal do
- it "returns the offset for multi byte strings with unicode regexp" do
- match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns correct character offset for multi-byte strings with unicode regexp" do
+ m = /\A\u3042(.)(.)?(.)\z/u.match("\u3042\u3043\u3044")
+
+ m.offset(1).should == [1, 2]
+ m.offset(3).should == [2, 3]
end
end
+
+ it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.offset(2).should == [nil, nil]
+ end
+
+ it "converts argument into integer if is not String nor Symbol" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ obj = Object.new
+ def obj.to_int; 2; end
+
+ m.offset(1r).should == [0, 3]
+ m.offset(1.1).should == [0, 3]
+ m.offset(obj).should == [3, 6]
+ end
+
+ it "raises IndexError if there is no group with the provided name" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.offset("y")
+ }.should.raise(IndexError, "undefined group name reference: y")
+
+ -> {
+ m.offset(:y)
+ }.should.raise(IndexError, "undefined group name reference: y")
+ end
+
+ it "raises IndexError if index is out of bounds" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.offset(-1)
+ }.should.raise(IndexError, "index -1 out of matches")
+
+ -> {
+ m.offset(3)
+ }.should.raise(IndexError, "index 3 out of matches")
+ end
+
+ it "raises TypeError if can't convert argument into Integer" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.offset([])
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
+ end
end
diff --git a/spec/ruby/core/matchdata/post_match_spec.rb b/spec/ruby/core/matchdata/post_match_spec.rb
index 7bfe6df119..b50d637124 100644
--- a/spec/ruby/core/matchdata/post_match_spec.rb
+++ b/spec/ruby/core/matchdata/post_match_spec.rb
@@ -9,16 +9,16 @@ describe "MatchData#post_match" do
it "sets the encoding to the encoding of the source String" do
str = "abc".dup.force_encoding Encoding::EUC_JP
- str.match(/b/).post_match.encoding.should equal(Encoding::EUC_JP)
+ str.match(/b/).post_match.encoding.should.equal?(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
str = "abc".dup.force_encoding Encoding::ISO_8859_1
- str.match(/c/).post_match.encoding.should equal(Encoding::ISO_8859_1)
+ str.match(/c/).post_match.encoding.should.equal?(Encoding::ISO_8859_1)
end
it "returns an instance of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String)
+ /(.)(.)(\d+)(\d)/.match(str).post_match.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/pre_match_spec.rb b/spec/ruby/core/matchdata/pre_match_spec.rb
index 2f1ba9b8f6..106612a4f7 100644
--- a/spec/ruby/core/matchdata/pre_match_spec.rb
+++ b/spec/ruby/core/matchdata/pre_match_spec.rb
@@ -9,16 +9,16 @@ describe "MatchData#pre_match" do
it "sets the encoding to the encoding of the source String" do
str = "abc".dup.force_encoding Encoding::EUC_JP
- str.match(/b/).pre_match.encoding.should equal(Encoding::EUC_JP)
+ str.match(/b/).pre_match.encoding.should.equal?(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
str = "abc".dup.force_encoding Encoding::ISO_8859_1
- str.match(/a/).pre_match.encoding.should equal(Encoding::ISO_8859_1)
+ str.match(/a/).pre_match.encoding.should.equal?(Encoding::ISO_8859_1)
end
it "returns an instance of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String)
+ /(.)(.)(\d+)(\d)/.match(str).pre_match.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/regexp_spec.rb b/spec/ruby/core/matchdata/regexp_spec.rb
index 099b59c559..7dcb0e62db 100644
--- a/spec/ruby/core/matchdata/regexp_spec.rb
+++ b/spec/ruby/core/matchdata/regexp_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "MatchData#regexp" do
it "returns a Regexp object" do
m = 'haystack'.match(/hay/)
- m.regexp.should be_an_instance_of(Regexp)
+ m.regexp.should.instance_of?(Regexp)
end
it "returns the pattern used in the match" do
diff --git a/spec/ruby/core/matchdata/shared/captures.rb b/spec/ruby/core/matchdata/shared/captures.rb
index 33f834561a..de5870f543 100644
--- a/spec/ruby/core/matchdata/shared/captures.rb
+++ b/spec/ruby/core/matchdata/shared/captures.rb
@@ -8,6 +8,6 @@ describe :matchdata_captures, shared: true do
it "returns instances of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).send(@method).each { |c| c.should be_an_instance_of(String) }
+ /(.)(.)(\d+)(\d)/.match(str).send(@method).each { |c| c.should.instance_of?(String) }
end
end
diff --git a/spec/ruby/core/matchdata/shared/eql.rb b/spec/ruby/core/matchdata/shared/eql.rb
index e021baa178..e4bb8797b7 100644
--- a/spec/ruby/core/matchdata/shared/eql.rb
+++ b/spec/ruby/core/matchdata/shared/eql.rb
@@ -4,23 +4,23 @@ describe :matchdata_eql, shared: true do
it "returns true if both operands have equal target strings, patterns, and match positions" do
a = 'haystack'.match(/hay/)
b = 'haystack'.match(/hay/)
- a.send(@method, b).should be_true
+ a.send(@method, b).should == true
end
it "returns false if the operands have different target strings" do
a = 'hay'.match(/hay/)
b = 'haystack'.match(/hay/)
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
end
it "returns false if the operands have different patterns" do
a = 'haystack'.match(/h.y/)
b = 'haystack'.match(/hay/)
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
end
it "returns false if the argument is not a MatchData object" do
a = 'haystack'.match(/hay/)
- a.send(@method, Object.new).should be_false
+ a.send(@method, Object.new).should == false
end
end
diff --git a/spec/ruby/core/matchdata/string_spec.rb b/spec/ruby/core/matchdata/string_spec.rb
index 952e953318..50bbb5a64f 100644
--- a/spec/ruby/core/matchdata/string_spec.rb
+++ b/spec/ruby/core/matchdata/string_spec.rb
@@ -14,7 +14,7 @@ describe "MatchData#string" do
it "returns the same frozen string for every call" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")
- md.string.should equal(md.string)
+ md.string.should.equal?(md.string)
end
it "returns a frozen copy of the matched string for gsub!(String)" do
diff --git a/spec/ruby/core/matchdata/to_a_spec.rb b/spec/ruby/core/matchdata/to_a_spec.rb
index 4fa11ff604..c77fc4ab37 100644
--- a/spec/ruby/core/matchdata/to_a_spec.rb
+++ b/spec/ruby/core/matchdata/to_a_spec.rb
@@ -8,6 +8,6 @@ describe "MatchData#to_a" do
it "returns instances of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) }
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should.instance_of?(String) }
end
end
diff --git a/spec/ruby/core/matchdata/to_s_spec.rb b/spec/ruby/core/matchdata/to_s_spec.rb
index cd1c4dbca2..cbcc5e8a21 100644
--- a/spec/ruby/core/matchdata/to_s_spec.rb
+++ b/spec/ruby/core/matchdata/to_s_spec.rb
@@ -8,6 +8,6 @@ describe "MatchData#to_s" do
it "returns an instance of String when given a String subclass" do
str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String)
+ /(.)(.)(\d+)(\d)/.match(str).to_s.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/matchdata/values_at_spec.rb b/spec/ruby/core/matchdata/values_at_spec.rb
index 535719a2ee..ba5b0e662c 100644
--- a/spec/ruby/core/matchdata/values_at_spec.rb
+++ b/spec/ruby/core/matchdata/values_at_spec.rb
@@ -26,7 +26,7 @@ describe "MatchData#values_at" do
end
it "raises RangeError if any element of the range is negative and out of range" do
- -> { /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6..3) }.should raise_error(RangeError, "-6..3 out of range")
+ -> { /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6..3) }.should.raise(RangeError, "-6..3 out of range")
end
it "supports endless Range" do
@@ -71,6 +71,6 @@ describe "MatchData#values_at" do
it "fails when passed arguments of unsupported types" do
-> {
/(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
end
diff --git a/spec/ruby/core/math/acos_spec.rb b/spec/ruby/core/math/acos_spec.rb
index 8b321ab29b..4649dc527c 100644
--- a/spec/ruby/core/math/acos_spec.rb
+++ b/spec/ruby/core/math/acos_spec.rb
@@ -8,7 +8,7 @@ describe "Math.acos" do
end
it "returns a float" do
- Math.acos(1).should be_kind_of(Float )
+ Math.acos(1).should.is_a?(Float )
end
it "returns the arccosine of the argument" do
@@ -21,27 +21,27 @@ describe "Math.acos" do
end
it "raises an Math::DomainError if the argument is greater than 1.0" do
- -> { Math.acos(1.0001) }.should raise_error(Math::DomainError)
+ -> { Math.acos(1.0001) }.should.raise(Math::DomainError)
end
it "raises an Math::DomainError if the argument is less than -1.0" do
- -> { Math.acos(-1.0001) }.should raise_error(Math::DomainError)
+ -> { Math.acos(-1.0001) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the string argument cannot be coerced with Float()" do
- -> { Math.acos("test") }.should raise_error(TypeError)
+ -> { Math.acos("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.acos(nan_value).nan?.should be_true
+ Math.acos(nan_value).nan?.should == true
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.acos(MathSpecs::UserClass.new) }.should raise_error(TypeError)
+ -> { Math.acos(MathSpecs::UserClass.new) }.should.raise(TypeError)
end
it "raises a TypeError if the argument is nil" do
- -> { Math.acos(nil) }.should raise_error(TypeError)
+ -> { Math.acos(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/acosh_spec.rb b/spec/ruby/core/math/acosh_spec.rb
index 6707de95d3..ccacda37e0 100644
--- a/spec/ruby/core/math/acosh_spec.rb
+++ b/spec/ruby/core/math/acosh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.acosh" do
it "returns a float" do
- Math.acosh(1.0).should be_kind_of(Float)
+ Math.acosh(1.0).should.is_a?(Float)
end
it "returns the principle value of the inverse hyperbolic cosine of the argument" do
@@ -12,21 +12,21 @@ describe "Math.acosh" do
end
it "raises Math::DomainError if the passed argument is less than -1.0 or greater than 1.0" do
- -> { Math.acosh(1.0 - TOLERANCE) }.should raise_error(Math::DomainError)
- -> { Math.acosh(0) }.should raise_error(Math::DomainError)
- -> { Math.acosh(-1.0) }.should raise_error(Math::DomainError)
+ -> { Math.acosh(1.0 - TOLERANCE) }.should.raise(Math::DomainError)
+ -> { Math.acosh(0) }.should.raise(Math::DomainError)
+ -> { Math.acosh(-1.0) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.acosh("test") }.should raise_error(TypeError)
+ -> { Math.acosh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.acosh(nan_value).nan?.should be_true
+ Math.acosh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.acosh(nil) }.should raise_error(TypeError)
+ -> { Math.acosh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/asin_spec.rb b/spec/ruby/core/math/asin_spec.rb
index 3a674a1147..1386bccc06 100644
--- a/spec/ruby/core/math/asin_spec.rb
+++ b/spec/ruby/core/math/asin_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# arcsine : (-1.0, 1.0) --> (-PI/2, PI/2)
describe "Math.asin" do
it "returns a float" do
- Math.asin(1).should be_kind_of(Float)
+ Math.asin(1).should.is_a?(Float)
end
it "returns the arcsine of the argument" do
@@ -17,23 +17,23 @@ describe "Math.asin" do
end
it "raises an Math::DomainError if the argument is greater than 1.0" do
- -> { Math.asin(1.0001) }.should raise_error( Math::DomainError)
+ -> { Math.asin(1.0001) }.should.raise( Math::DomainError)
end
it "raises an Math::DomainError if the argument is less than -1.0" do
- -> { Math.asin(-1.0001) }.should raise_error( Math::DomainError)
+ -> { Math.asin(-1.0001) }.should.raise( Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.asin("test") }.should raise_error(TypeError)
+ -> { Math.asin("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.asin(nan_value).nan?.should be_true
+ Math.asin(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.asin(nil) }.should raise_error(TypeError)
+ -> { Math.asin(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/asinh_spec.rb b/spec/ruby/core/math/asinh_spec.rb
index ff8210df0a..8aa019f05f 100644
--- a/spec/ruby/core/math/asinh_spec.rb
+++ b/spec/ruby/core/math/asinh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.asinh" do
it "returns a float" do
- Math.asinh(1.5).should be_kind_of(Float)
+ Math.asinh(1.5).should.is_a?(Float)
end
it "returns the inverse hyperbolic sin of the argument" do
@@ -19,15 +19,15 @@ describe "Math.asinh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.asinh("test") }.should raise_error(TypeError)
+ -> { Math.asinh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.asinh(nan_value).nan?.should be_true
+ Math.asinh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.asinh(nil) }.should raise_error(TypeError)
+ -> { Math.asinh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/atan2_spec.rb b/spec/ruby/core/math/atan2_spec.rb
index d4ef369d2a..1f1de506c5 100644
--- a/spec/ruby/core/math/atan2_spec.rb
+++ b/spec/ruby/core/math/atan2_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.atan2" do
it "returns a float" do
- Math.atan2(1.2, 0.5).should be_kind_of(Float)
+ Math.atan2(1.2, 0.5).should.is_a?(Float)
end
it "returns the arc tangent of y, x" do
@@ -14,15 +14,15 @@ describe "Math.atan2" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.atan2(1.0, "test") }.should raise_error(TypeError)
- -> { Math.atan2("test", 0.0) }.should raise_error(TypeError)
- -> { Math.atan2("test", "this") }.should raise_error(TypeError)
+ -> { Math.atan2(1.0, "test") }.should.raise(TypeError)
+ -> { Math.atan2("test", 0.0) }.should.raise(TypeError)
+ -> { Math.atan2("test", "this") }.should.raise(TypeError)
end
it "raises a TypeError if the argument is nil" do
- -> { Math.atan2(nil, 1.0) }.should raise_error(TypeError)
- -> { Math.atan2(-1.0, nil) }.should raise_error(TypeError)
- -> { Math.atan2(nil, nil) }.should raise_error(TypeError)
+ -> { Math.atan2(nil, 1.0) }.should.raise(TypeError)
+ -> { Math.atan2(-1.0, nil) }.should.raise(TypeError)
+ -> { Math.atan2(nil, nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/atan_spec.rb b/spec/ruby/core/math/atan_spec.rb
index 15edf68c05..07d04cdf82 100644
--- a/spec/ruby/core/math/atan_spec.rb
+++ b/spec/ruby/core/math/atan_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# arctangent : (-Inf, Inf) --> (-PI/2, PI/2)
describe "Math.atan" do
it "returns a float" do
- Math.atan(1).should be_kind_of(Float)
+ Math.atan(1).should.is_a?(Float)
end
it "returns the arctangent of the argument" do
@@ -17,15 +17,15 @@ describe "Math.atan" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.atan("test") }.should raise_error(TypeError)
+ -> { Math.atan("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.atan(nan_value).nan?.should be_true
+ Math.atan(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.atan(nil) }.should raise_error(TypeError)
+ -> { Math.atan(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/cbrt_spec.rb b/spec/ruby/core/math/cbrt_spec.rb
index 01cf923c71..4e2383043b 100644
--- a/spec/ruby/core/math/cbrt_spec.rb
+++ b/spec/ruby/core/math/cbrt_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.cbrt" do
it "returns a float" do
- Math.cbrt(1).should be_an_instance_of(Float)
+ Math.cbrt(1).should.instance_of?(Float)
end
it "returns the cubic root of the argument" do
@@ -14,11 +14,11 @@ describe "Math.cbrt" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.cbrt("foobar") }.should raise_error(TypeError)
+ -> { Math.cbrt("foobar") }.should.raise(TypeError)
end
it "raises a TypeError if the argument is nil" do
- -> { Math.cbrt(nil) }.should raise_error(TypeError)
+ -> { Math.cbrt(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/cos_spec.rb b/spec/ruby/core/math/cos_spec.rb
index 006afeb2cc..e8602cde3c 100644
--- a/spec/ruby/core/math/cos_spec.rb
+++ b/spec/ruby/core/math/cos_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# cosine : (-Inf, Inf) --> (-1.0, 1.0)
describe "Math.cos" do
it "returns a float" do
- Math.cos(Math::PI).should be_kind_of(Float)
+ Math.cos(Math::PI).should.is_a?(Float)
end
it "returns the cosine of the argument expressed in radians" do
@@ -16,11 +16,11 @@ describe "Math.cos" do
end
it "raises a TypeError unless the argument is Numeric and has #to_f" do
- -> { Math.cos("test") }.should raise_error(TypeError)
+ -> { Math.cos("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.cos(nan_value).nan?.should be_true
+ Math.cos(nan_value).nan?.should == true
end
describe "coerces its argument with #to_f" do
@@ -31,14 +31,14 @@ describe "Math.cos" do
end
it "raises a TypeError if the given argument can't be converted to a Float" do
- -> { Math.cos(nil) }.should raise_error(TypeError)
- -> { Math.cos(:abc) }.should raise_error(TypeError)
+ -> { Math.cos(nil) }.should.raise(TypeError)
+ -> { Math.cos(:abc) }.should.raise(TypeError)
end
it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a Float" do
object = mock_numeric('mock-float')
object.should_receive(:to_f).and_raise(NoMethodError)
- -> { Math.cos(object) }.should raise_error(NoMethodError)
+ -> { Math.cos(object) }.should.raise(NoMethodError)
end
end
end
diff --git a/spec/ruby/core/math/cosh_spec.rb b/spec/ruby/core/math/cosh_spec.rb
index 049e117e56..2093d8a74a 100644
--- a/spec/ruby/core/math/cosh_spec.rb
+++ b/spec/ruby/core/math/cosh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.cosh" do
it "returns a float" do
- Math.cosh(1.0).should be_kind_of(Float)
+ Math.cosh(1.0).should.is_a?(Float)
end
it "returns the hyperbolic cosine of the argument" do
@@ -14,15 +14,15 @@ describe "Math.cosh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.cosh("test") }.should raise_error(TypeError)
+ -> { Math.cosh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.cosh(nan_value).nan?.should be_true
+ Math.cosh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.cosh(nil) }.should raise_error(TypeError)
+ -> { Math.cosh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/erf_spec.rb b/spec/ruby/core/math/erf_spec.rb
index b4e6248e43..5384e73ae9 100644
--- a/spec/ruby/core/math/erf_spec.rb
+++ b/spec/ruby/core/math/erf_spec.rb
@@ -5,7 +5,7 @@ require_relative 'fixtures/classes'
# distribution (which is a normalized form of the Gaussian function).
describe "Math.erf" do
it "returns a float" do
- Math.erf(1).should be_kind_of(Float)
+ Math.erf(1).should.is_a?(Float)
end
it "returns the error function of the argument" do
@@ -21,15 +21,15 @@ describe "Math.erf" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.erf("test") }.should raise_error(TypeError)
+ -> { Math.erf("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.erf(nan_value).nan?.should be_true
+ Math.erf(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.erf(nil) }.should raise_error(TypeError)
+ -> { Math.erf(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/erfc_spec.rb b/spec/ruby/core/math/erfc_spec.rb
index e465f5cf58..4e09a68d1e 100644
--- a/spec/ruby/core/math/erfc_spec.rb
+++ b/spec/ruby/core/math/erfc_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# erfc is the complementary error function
describe "Math.erfc" do
it "returns a float" do
- Math.erf(1).should be_kind_of(Float)
+ Math.erf(1).should.is_a?(Float)
end
it "returns the complementary error function of the argument" do
@@ -20,15 +20,15 @@ describe "Math.erfc" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.erfc("test") }.should raise_error(TypeError)
+ -> { Math.erfc("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.erfc(nan_value).nan?.should be_true
+ Math.erfc(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.erfc(nil) }.should raise_error(TypeError)
+ -> { Math.erfc(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/exp_spec.rb b/spec/ruby/core/math/exp_spec.rb
index 36eb49a8c7..3688482457 100644
--- a/spec/ruby/core/math/exp_spec.rb
+++ b/spec/ruby/core/math/exp_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.exp" do
it "returns a float" do
- Math.exp(1.0).should be_kind_of(Float)
+ Math.exp(1.0).should.is_a?(Float)
end
it "returns the base-e exponential of the argument" do
@@ -14,15 +14,15 @@ describe "Math.exp" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.exp("test") }.should raise_error(TypeError)
+ -> { Math.exp("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.exp(nan_value).nan?.should be_true
+ Math.exp(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.exp(nil) }.should raise_error(TypeError)
+ -> { Math.exp(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/expm1_spec.rb b/spec/ruby/core/math/expm1_spec.rb
new file mode 100644
index 0000000000..35f62b5dbd
--- /dev/null
+++ b/spec/ruby/core/math/expm1_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "4.0" do
+ describe "Math.expm1" do
+ it "calculates Math.exp(arg) - 1" do
+ Math.expm1(3).should == Math.exp(3) - 1
+ end
+
+ it "preserves precision that can be lost otherwise" do
+ Math.expm1(1.0e-16).should be_close(1.0e-16, TOLERANCE)
+ Math.expm1(1.0e-16).should != 0.0
+ end
+
+ it "raises a TypeError if the argument cannot be coerced with Float()" do
+ -> { Math.expm1("test") }.should.raise(TypeError, "can't convert String into Float")
+ end
+
+ it "returns NaN given NaN" do
+ Math.expm1(nan_value).nan?.should == true
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.expm1(nil) }.should.raise(TypeError, "can't convert nil into Float")
+ end
+
+ it "accepts any argument that can be coerced with Float()" do
+ Math.expm1(MathSpecs::Float.new).should be_close(Math::E - 1, TOLERANCE)
+ end
+ end
+
+ describe "Math#expm1" do
+ it "is accessible as a private instance method" do
+ IncludesMath.new.send(:expm1, 23.1415).should be_close(11226018483.0012, TOLERANCE)
+ end
+ end
+end
diff --git a/spec/ruby/core/math/frexp_spec.rb b/spec/ruby/core/math/frexp_spec.rb
index 7dfb493d20..6853e4672f 100644
--- a/spec/ruby/core/math/frexp_spec.rb
+++ b/spec/ruby/core/math/frexp_spec.rb
@@ -9,16 +9,16 @@ describe "Math.frexp" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.frexp("test") }.should raise_error(TypeError)
+ -> { Math.frexp("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
frac, _exp = Math.frexp(nan_value)
- frac.nan?.should be_true
+ frac.nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.frexp(nil) }.should raise_error(TypeError)
+ -> { Math.frexp(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/gamma_spec.rb b/spec/ruby/core/math/gamma_spec.rb
index 386162a087..9a0b14448a 100644
--- a/spec/ruby/core/math/gamma_spec.rb
+++ b/spec/ruby/core/math/gamma_spec.rb
@@ -51,7 +51,7 @@ describe "Math.gamma" do
end
it "raises Math::DomainError given -1" do
- -> { Math.gamma(-1) }.should raise_error(Math::DomainError)
+ -> { Math.gamma(-1) }.should.raise(Math::DomainError)
end
# See https://bugs.ruby-lang.org/issues/10642
@@ -60,10 +60,10 @@ describe "Math.gamma" do
end
it "raises Math::DomainError given negative infinity" do
- -> { Math.gamma(-Float::INFINITY) }.should raise_error(Math::DomainError)
+ -> { Math.gamma(-Float::INFINITY) }.should.raise(Math::DomainError)
end
it "returns NaN given NaN" do
- Math.gamma(nan_value).nan?.should be_true
+ Math.gamma(nan_value).nan?.should == true
end
end
diff --git a/spec/ruby/core/math/hypot_spec.rb b/spec/ruby/core/math/hypot_spec.rb
index 3e0ce74597..4ab5bd4e88 100644
--- a/spec/ruby/core/math/hypot_spec.rb
+++ b/spec/ruby/core/math/hypot_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.hypot" do
it "returns a float" do
- Math.hypot(3, 4).should be_kind_of(Float)
+ Math.hypot(3, 4).should.is_a?(Float)
end
it "returns the length of the hypotenuse of a right triangle with legs given by the arguments" do
@@ -16,17 +16,17 @@ describe "Math.hypot" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.hypot("test", "this") }.should raise_error(TypeError)
+ -> { Math.hypot("test", "this") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.hypot(nan_value, 0).nan?.should be_true
- Math.hypot(0, nan_value).nan?.should be_true
- Math.hypot(nan_value, nan_value).nan?.should be_true
+ Math.hypot(nan_value, 0).nan?.should == true
+ Math.hypot(0, nan_value).nan?.should == true
+ Math.hypot(nan_value, nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.hypot(nil, nil) }.should raise_error(TypeError)
+ -> { Math.hypot(nil, nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/ldexp_spec.rb b/spec/ruby/core/math/ldexp_spec.rb
index 6dcf94a663..1864b7455a 100644
--- a/spec/ruby/core/math/ldexp_spec.rb
+++ b/spec/ruby/core/math/ldexp_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.ldexp" do
it "returns a float" do
- Math.ldexp(1.0, 2).should be_kind_of(Float)
+ Math.ldexp(1.0, 2).should.is_a?(Float)
end
it "returns the argument multiplied by 2**n" do
@@ -15,27 +15,27 @@ describe "Math.ldexp" do
end
it "raises a TypeError if the first argument cannot be coerced with Float()" do
- -> { Math.ldexp("test", 2) }.should raise_error(TypeError)
+ -> { Math.ldexp("test", 2) }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.ldexp(nan_value, 0).nan?.should be_true
+ Math.ldexp(nan_value, 0).nan?.should == true
end
it "raises RangeError if NaN is given as the second arg" do
- -> { Math.ldexp(0, nan_value) }.should raise_error(RangeError)
+ -> { Math.ldexp(0, nan_value) }.should.raise(RangeError)
end
it "raises a TypeError if the second argument cannot be coerced with Integer()" do
- -> { Math.ldexp(3.2, "this") }.should raise_error(TypeError)
+ -> { Math.ldexp(3.2, "this") }.should.raise(TypeError)
end
it "raises a TypeError if the first argument is nil" do
- -> { Math.ldexp(nil, 2) }.should raise_error(TypeError)
+ -> { Math.ldexp(nil, 2) }.should.raise(TypeError)
end
it "raises a TypeError if the second argument is nil" do
- -> { Math.ldexp(3.1, nil) }.should raise_error(TypeError)
+ -> { Math.ldexp(3.1, nil) }.should.raise(TypeError)
end
it "accepts any first argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/lgamma_spec.rb b/spec/ruby/core/math/lgamma_spec.rb
index 33e7836448..38f07d0bf8 100644
--- a/spec/ruby/core/math/lgamma_spec.rb
+++ b/spec/ruby/core/math/lgamma_spec.rb
@@ -5,10 +5,8 @@ describe "Math.lgamma" do
Math.lgamma(0).should == [infinity_value, 1]
end
- platform_is_not :windows do
- it "returns [Infinity, 1] when passed -1" do
- Math.lgamma(-1).should == [infinity_value, 1]
- end
+ it "returns [Infinity, ...] when passed -1" do
+ Math.lgamma(-1)[0].should == infinity_value
end
it "returns [Infinity, -1] when passed -0.0" do
@@ -40,15 +38,14 @@ describe "Math.lgamma" do
end
it "raises Math::DomainError when passed -Infinity" do
- -> { Math.lgamma(-infinity_value) }.should raise_error(Math::DomainError)
+ -> { Math.lgamma(-infinity_value) }.should.raise(Math::DomainError)
end
it "returns [Infinity, 1] when passed Infinity" do
Math.lgamma(infinity_value).should == [infinity_value, 1]
end
- it "returns [NaN, 1] when passed NaN" do
- Math.lgamma(nan_value)[0].nan?.should be_true
- Math.lgamma(nan_value)[1].should == 1
+ it "returns [NaN, ...] when passed NaN" do
+ Math.lgamma(nan_value)[0].should.nan?
end
end
diff --git a/spec/ruby/core/math/log10_spec.rb b/spec/ruby/core/math/log10_spec.rb
index c4daedcd5c..7576a67002 100644
--- a/spec/ruby/core/math/log10_spec.rb
+++ b/spec/ruby/core/math/log10_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# The common logarithm, having base 10
describe "Math.log10" do
it "returns a float" do
- Math.log10(1).should be_kind_of(Float)
+ Math.log10(1).should.is_a?(Float)
end
it "returns the base-10 logarithm of the argument" do
@@ -16,19 +16,23 @@ describe "Math.log10" do
end
it "raises an Math::DomainError if the argument is less than 0" do
- -> { Math.log10(-1e-15) }.should raise_error(Math::DomainError)
+ -> { Math.log10(-1e-15) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.log10("test") }.should raise_error(TypeError)
+ -> { Math.log10("test") }.should.raise(TypeError)
+ end
+
+ it "raises a TypeError if passed a numerical argument as a string" do
+ -> { Math.log10("1.0") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.log10(nan_value).nan?.should be_true
+ Math.log10(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.log10(nil) }.should raise_error(TypeError)
+ -> { Math.log10(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/log1p_spec.rb b/spec/ruby/core/math/log1p_spec.rb
new file mode 100644
index 0000000000..181b462ded
--- /dev/null
+++ b/spec/ruby/core/math/log1p_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "4.0" do
+ describe "Math.log1p" do
+ it "calculates Math.log(1 + arg)" do
+ Math.log1p(3).should == Math.log(1 + 3)
+ end
+
+ it "preserves precision that can be lost otherwise" do
+ Math.log1p(1e-16).should be_close(1.0e-16, TOLERANCE)
+ Math.log1p(1e-16).should != 0.0
+ end
+
+ it "raises an Math::DomainError if the argument is less than 1" do
+ -> { Math.log1p(-1-1e-15) }.should.raise(Math::DomainError, "Numerical argument is out of domain - log1p")
+ end
+
+ it "raises a TypeError if the argument cannot be coerced with Float()" do
+ -> { Math.log1p("test") }.should.raise(TypeError, "can't convert String into Float")
+ end
+
+ it "raises a TypeError for numerical values passed as string" do
+ -> { Math.log1p("10") }.should.raise(TypeError, "can't convert String into Float")
+ end
+
+ it "does not accept a second argument for the base" do
+ -> { Math.log1p(9, 3) }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+
+ it "returns NaN given NaN" do
+ Math.log1p(nan_value).nan?.should == true
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.log1p(nil) }.should.raise(TypeError, "can't convert nil into Float")
+ end
+
+ it "accepts any argument that can be coerced with Float()" do
+ Math.log1p(MathSpecs::Float.new).should be_close(0.6931471805599453, TOLERANCE)
+ end
+ end
+
+ describe "Math#log1p" do
+ it "is accessible as a private instance method" do
+ IncludesMath.new.send(:log1p, 4.21).should be_close(1.65057985576528, TOLERANCE)
+ end
+ end
+end
diff --git a/spec/ruby/core/math/log2_spec.rb b/spec/ruby/core/math/log2_spec.rb
index 3d4d41d130..e38a8bb67f 100644
--- a/spec/ruby/core/math/log2_spec.rb
+++ b/spec/ruby/core/math/log2_spec.rb
@@ -16,23 +16,23 @@ describe "Math.log2" do
end
it "raises Math::DomainError if the argument is less than 0" do
- -> { Math.log2(-1e-15) }.should raise_error( Math::DomainError)
+ -> { Math.log2(-1e-15) }.should.raise( Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.log2("test") }.should raise_error(TypeError)
+ -> { Math.log2("test") }.should.raise(TypeError)
end
it "raises a TypeError if passed a numerical argument as a string" do
- -> { Math.log2("1.0") }.should raise_error(TypeError)
+ -> { Math.log2("1.0") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.log2(nan_value).nan?.should be_true
+ Math.log2(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.log2(nil) }.should raise_error(TypeError)
+ -> { Math.log2(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/log_spec.rb b/spec/ruby/core/math/log_spec.rb
index 6c5036ba81..7e0bc13bc6 100644
--- a/spec/ruby/core/math/log_spec.rb
+++ b/spec/ruby/core/math/log_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# The natural logarithm, having base Math::E
describe "Math.log" do
it "returns a float" do
- Math.log(1).should be_kind_of(Float)
+ Math.log(1).should.is_a?(Float)
end
it "returns the natural logarithm of the argument" do
@@ -16,15 +16,15 @@ describe "Math.log" do
end
it "raises an Math::DomainError if the argument is less than 0" do
- -> { Math.log(-1e-15) }.should raise_error(Math::DomainError)
+ -> { Math.log(-1e-15) }.should.raise(Math::DomainError)
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.log("test") }.should raise_error(TypeError)
+ -> { Math.log("test") }.should.raise(TypeError)
end
it "raises a TypeError for numerical values passed as string" do
- -> { Math.log("10") }.should raise_error(TypeError)
+ -> { Math.log("10") }.should.raise(TypeError)
end
it "accepts a second argument for the base" do
@@ -33,16 +33,16 @@ describe "Math.log" do
end
it "raises a TypeError when the numerical base cannot be coerced to a float" do
- -> { Math.log(10, "2") }.should raise_error(TypeError)
- -> { Math.log(10, nil) }.should raise_error(TypeError)
+ -> { Math.log(10, "2") }.should.raise(TypeError)
+ -> { Math.log(10, nil) }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.log(nan_value).nan?.should be_true
+ Math.log(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.log(nil) }.should raise_error(TypeError)
+ -> { Math.log(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/shared/atanh.rb b/spec/ruby/core/math/shared/atanh.rb
index 3fb64153a0..48a6bf836e 100644
--- a/spec/ruby/core/math/shared/atanh.rb
+++ b/spec/ruby/core/math/shared/atanh.rb
@@ -1,6 +1,6 @@
describe :math_atanh_base, shared: true do
it "returns a float" do
- @object.send(@method, 0.5).should be_an_instance_of(Float)
+ @object.send(@method, 0.5).should.instance_of?(Float)
end
it "returns the inverse hyperbolic tangent of the argument" do
@@ -11,11 +11,11 @@ describe :math_atanh_base, shared: true do
end
it "raises a TypeError if the argument is nil" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError if the argument is not a Numeric" do
- -> { @object.send(@method, "test") }.should raise_error(TypeError)
+ -> { @object.send(@method, "test") }.should.raise(TypeError)
end
it "returns Infinity if x == 1.0" do
@@ -29,16 +29,16 @@ end
describe :math_atanh_private, shared: true do
it "is a private instance method" do
- Math.should have_private_instance_method(@method)
+ Math.private_instance_methods(false).should.include?(@method)
end
end
describe :math_atanh_no_complex, shared: true do
it "raises a Math::DomainError for arguments greater than 1.0" do
- -> { @object.send(@method, 1.0 + Float::EPSILON) }.should raise_error(Math::DomainError)
+ -> { @object.send(@method, 1.0 + Float::EPSILON) }.should.raise(Math::DomainError)
end
it "raises a Math::DomainError for arguments less than -1.0" do
- -> { @object.send(@method, -1.0 - Float::EPSILON) }.should raise_error(Math::DomainError)
+ -> { @object.send(@method, -1.0 - Float::EPSILON) }.should.raise(Math::DomainError)
end
end
diff --git a/spec/ruby/core/math/sin_spec.rb b/spec/ruby/core/math/sin_spec.rb
index 8e944bc95f..a9479e3aec 100644
--- a/spec/ruby/core/math/sin_spec.rb
+++ b/spec/ruby/core/math/sin_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# sine : (-Inf, Inf) --> (-1.0, 1.0)
describe "Math.sin" do
it "returns a float" do
- Math.sin(Math::PI).should be_kind_of(Float)
+ Math.sin(Math::PI).should.is_a?(Float)
end
it "returns the sine of the argument expressed in radians" do
@@ -16,15 +16,15 @@ describe "Math.sin" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.sin("test") }.should raise_error(TypeError)
+ -> { Math.sin("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.sin(nan_value).nan?.should be_true
+ Math.sin(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.sin(nil) }.should raise_error(TypeError)
+ -> { Math.sin(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/sinh_spec.rb b/spec/ruby/core/math/sinh_spec.rb
index 027c2395a7..de0f06affa 100644
--- a/spec/ruby/core/math/sinh_spec.rb
+++ b/spec/ruby/core/math/sinh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.sinh" do
it "returns a float" do
- Math.sinh(1.2).should be_kind_of(Float)
+ Math.sinh(1.2).should.is_a?(Float)
end
it "returns the hyperbolic sin of the argument" do
@@ -14,15 +14,15 @@ describe "Math.sinh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.sinh("test") }.should raise_error(TypeError)
+ -> { Math.sinh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.sinh(nan_value).nan?.should be_true
+ Math.sinh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.sinh(nil) }.should raise_error(TypeError)
+ -> { Math.sinh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/sqrt_spec.rb b/spec/ruby/core/math/sqrt_spec.rb
index 918e7c3a17..545fa4d1c2 100644
--- a/spec/ruby/core/math/sqrt_spec.rb
+++ b/spec/ruby/core/math/sqrt_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.sqrt" do
it "returns a float" do
- Math.sqrt(1).should be_kind_of(Float)
+ Math.sqrt(1).should.is_a?(Float)
end
it "returns the square root of the argument" do
@@ -13,15 +13,15 @@ describe "Math.sqrt" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.sqrt("test") }.should raise_error(TypeError)
+ -> { Math.sqrt("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.sqrt(nan_value).nan?.should be_true
+ Math.sqrt(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.sqrt(nil) }.should raise_error(TypeError)
+ -> { Math.sqrt(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
@@ -29,7 +29,7 @@ describe "Math.sqrt" do
end
it "raises a Math::DomainError when given a negative number" do
- -> { Math.sqrt(-1) }.should raise_error(Math::DomainError)
+ -> { Math.sqrt(-1) }.should.raise(Math::DomainError)
end
end
diff --git a/spec/ruby/core/math/tan_spec.rb b/spec/ruby/core/math/tan_spec.rb
index 67307f1e6e..c3e773f318 100644
--- a/spec/ruby/core/math/tan_spec.rb
+++ b/spec/ruby/core/math/tan_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.tan" do
it "returns a float" do
- Math.tan(1.35).should be_kind_of(Float)
+ Math.tan(1.35).should.is_a?(Float)
end
it "returns the tangent of the argument" do
@@ -19,15 +19,15 @@ describe "Math.tan" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.tan("test") }.should raise_error(TypeError)
+ -> { Math.tan("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.tan(nan_value).nan?.should be_true
+ Math.tan(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.tan(nil) }.should raise_error(TypeError)
+ -> { Math.tan(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/math/tanh_spec.rb b/spec/ruby/core/math/tanh_spec.rb
index 568f8dfa77..74a938ffd8 100644
--- a/spec/ruby/core/math/tanh_spec.rb
+++ b/spec/ruby/core/math/tanh_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Math.tanh" do
it "returns a float" do
- Math.tanh(0.5).should be_kind_of(Float)
+ Math.tanh(0.5).should.is_a?(Float)
end
it "returns the hyperbolic tangent of the argument" do
@@ -16,15 +16,15 @@ describe "Math.tanh" do
end
it "raises a TypeError if the argument cannot be coerced with Float()" do
- -> { Math.tanh("test") }.should raise_error(TypeError)
+ -> { Math.tanh("test") }.should.raise(TypeError)
end
it "returns NaN given NaN" do
- Math.tanh(nan_value).nan?.should be_true
+ Math.tanh(nan_value).nan?.should == true
end
it "raises a TypeError if the argument is nil" do
- -> { Math.tanh(nil) }.should raise_error(TypeError)
+ -> { Math.tanh(nil) }.should.raise(TypeError)
end
it "accepts any argument that can be coerced with Float()" do
diff --git a/spec/ruby/core/method/curry_spec.rb b/spec/ruby/core/method/curry_spec.rb
index 219de0f6b5..79c5d7c662 100644
--- a/spec/ruby/core/method/curry_spec.rb
+++ b/spec/ruby/core/method/curry_spec.rb
@@ -7,7 +7,7 @@ describe "Method#curry" do
def x.foo(a,b,c); [a,b,c]; end
c = x.method(:foo).curry
- c.should be_kind_of(Proc)
+ c.should.is_a?(Proc)
c.call(1).call(2, 3).should == [1,2,3]
end
@@ -17,20 +17,20 @@ describe "Method#curry" do
end
it "returns a curried proc when given correct arity" do
- @obj.method(:one_req).curry(1).should be_kind_of(Proc)
- @obj.method(:zero_with_splat).curry(100).should be_kind_of(Proc)
- @obj.method(:two_req_with_splat).curry(2).should be_kind_of(Proc)
+ @obj.method(:one_req).curry(1).should.is_a?(Proc)
+ @obj.method(:zero_with_splat).curry(100).should.is_a?(Proc)
+ @obj.method(:two_req_with_splat).curry(2).should.is_a?(Proc)
end
it "raises ArgumentError when the method requires less arguments than the given arity" do
- -> { @obj.method(:zero).curry(1) }.should raise_error(ArgumentError)
- -> { @obj.method(:one_req_one_opt).curry(3) }.should raise_error(ArgumentError)
- -> { @obj.method(:two_req_one_opt_with_block).curry(4) }.should raise_error(ArgumentError)
+ -> { @obj.method(:zero).curry(1) }.should.raise(ArgumentError)
+ -> { @obj.method(:one_req_one_opt).curry(3) }.should.raise(ArgumentError)
+ -> { @obj.method(:two_req_one_opt_with_block).curry(4) }.should.raise(ArgumentError)
end
it "raises ArgumentError when the method requires more arguments than the given arity" do
- -> { @obj.method(:two_req_with_splat).curry(1) }.should raise_error(ArgumentError)
- -> { @obj.method(:one_req).curry(0) }.should raise_error(ArgumentError)
+ -> { @obj.method(:two_req_with_splat).curry(1) }.should.raise(ArgumentError)
+ -> { @obj.method(:one_req).curry(0) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb
index 464a519aea..41904df1d1 100644
--- a/spec/ruby/core/method/fixtures/classes.rb
+++ b/spec/ruby/core/method/fixtures/classes.rb
@@ -27,6 +27,7 @@ module MethodSpecs
alias bar foo
alias baz bar
+ alias qux baz
def same_as_foo
true
diff --git a/spec/ruby/core/method/inspect_spec.rb b/spec/ruby/core/method/inspect_spec.rb
index e0fe1afdd0..97ff2d8c11 100644
--- a/spec/ruby/core/method/inspect_spec.rb
+++ b/spec/ruby/core/method/inspect_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/to_s'
+require_relative 'shared/aliased_inspect'
describe "Method#inspect" do
it_behaves_like :method_to_s, :inspect
+ it_behaves_like :method_to_s_aliased, :inspect, -> meth { meth }
end
diff --git a/spec/ruby/core/method/original_name_spec.rb b/spec/ruby/core/method/original_name_spec.rb
index 676fdaedb4..b92cf35154 100644
--- a/spec/ruby/core/method/original_name_spec.rb
+++ b/spec/ruby/core/method/original_name_spec.rb
@@ -19,4 +19,41 @@ describe "Method#original_name" do
obj.method(:baz).original_name.should == :foo
obj.method(:baz).unbind.bind(obj).original_name.should == :foo
end
+
+ it "returns the original name even when aliased thrice" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:qux).original_name.should == :foo
+ obj.method(:qux).unbind.bind(obj).original_name.should == :foo
+ end
+
+ it "returns the source UnboundMethod's name (not the name given to define_method)" do
+ klass = Class.new { define_method(:my_inspect, ::Kernel.instance_method(:inspect)) }
+ klass.new.method(:my_inspect).original_name.should == :inspect
+ end
+
+ it "preserves the source method's name through define_method and alias" do
+ source = Class.new { def my_method; end }
+ klass = Class.new(source) do
+ define_method(:renamed, source.instance_method(:my_method))
+ alias aliased renamed
+ end
+ klass.new.method(:renamed).original_name.should == :my_method
+ klass.new.method(:aliased).original_name.should == :my_method
+ end
+
+ it "returns the source UnboundMethod's name for Kernel#is_a? and Kernel#kind_of?" do
+ klass = Class.new { define_method(:my_is_a?, ::Kernel.instance_method(:is_a?)) }
+ klass.new.method(:my_is_a?).original_name.should == :is_a?
+
+ klass = Class.new { define_method(:my_kind_of?, ::Kernel.instance_method(:kind_of?)) }
+ klass.new.method(:my_kind_of?).original_name.should == :kind_of?
+ end
+
+ it "preserves the source name when aliasing a define_method'd Kernel method" do
+ klass = Class.new do
+ define_method(:my_is_a?, ::Kernel.instance_method(:is_a?))
+ alias_method :renamed_is_a?, :my_is_a?
+ end
+ klass.new.method(:renamed_is_a?).original_name.should == :is_a?
+ end
end
diff --git a/spec/ruby/core/method/owner_spec.rb b/spec/ruby/core/method/owner_spec.rb
index 05422f1697..1cdc4edfa7 100644
--- a/spec/ruby/core/method/owner_spec.rb
+++ b/spec/ruby/core/method/owner_spec.rb
@@ -24,9 +24,7 @@ describe "Method#owner" do
end
end
- ruby_version_is "3.2" do
- it "returns the class on which public was called for a private method in ancestor" do
- MethodSpecs::InheritedMethods::C.new.method(:derp).owner.should == MethodSpecs::InheritedMethods::C
- end
+ it "returns the class on which public was called for a private method in ancestor" do
+ MethodSpecs::InheritedMethods::C.new.method(:derp).owner.should == MethodSpecs::InheritedMethods::C
end
end
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index 0178a61de6..fd88e8dcb8 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -22,6 +22,12 @@ describe "Method#parameters" do
local_is_not_parameter = {}
end
+ ruby_version_is "4.1" do
+ eval <<-RUBY
+ def one_noblock(&nil); end
+ RUBY
+ end
+
def forward_parameters(...) end
def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
@@ -187,6 +193,13 @@ describe "Method#parameters" do
m.parameters.should == [[:nokey]]
end
+ ruby_version_is "4.1" do
+ it "returns [[:noblock]] for a method with a single &nil parameter" do
+ m = MethodSpecs::Methods.instance_method(:one_noblock)
+ m.parameters.should == [[:noblock]]
+ end
+ end
+
it "works with ->(){} as the value of an optional argument" do
m = MethodSpecs::Methods.instance_method(:one_opt_with_stabby)
m.parameters.should == [[:opt,:a]]
@@ -233,28 +246,14 @@ describe "Method#parameters" do
m.method(:handled_via_method_missing).parameters.should == [[:rest]]
end
- ruby_version_is '3.2' do
- it "adds rest arg with name * for \"star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]]
- end
-
- it "adds keyrest arg with ** as a name for \"double star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]]
- end
+ it "adds rest arg with name * for \"star\" argument" do
+ m = MethodSpecs::Methods.new
+ m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]]
end
- ruby_version_is ''...'3.2' do
- it "adds nameless rest arg for \"star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_splat).parameters.should == [[:rest]]
- end
-
- it "adds nameless keyrest arg for \"double star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest]]
- end
+ it "adds keyrest arg with ** as a name for \"double star\" argument" do
+ m = MethodSpecs::Methods.new
+ m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]]
end
it "adds block arg with name & for anonymous block argument" do
@@ -309,7 +308,7 @@ describe "Method#parameters" do
[
[[:rest]],
[[:opt]]
- ].should include([].method(:pop).parameters)
+ ].should.include?([].method(:pop).parameters)
end
it "returns [[:req]] for each parameter for core methods with fixed-length argument lists" do
diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb
index 9b67a77243..e708542b2e 100644
--- a/spec/ruby/core/method/private_spec.rb
+++ b/spec/ruby/core/method/private_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#private?" do
- ruby_version_is ""..."3.2" do
- it "returns false when the method is public" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).private?.should == false
- end
-
- it "returns false when the method is protected" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).private?.should == false
- end
-
- it "returns true when the method is private" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).private?.should == true
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).should_not.respond_to?(:private?)
- end
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).should_not.respond_to?(:private?)
end
end
diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb
index 28c60c7536..f9e422ae3d 100644
--- a/spec/ruby/core/method/protected_spec.rb
+++ b/spec/ruby/core/method/protected_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#protected?" do
- ruby_version_is ""..."3.2" do
- it "returns false when the method is public" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).protected?.should == false
- end
-
- it "returns true when the method is protected" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).protected?.should == true
- end
-
- it "returns false when the method is private" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).protected?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).should_not.respond_to?(:protected?)
- end
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).should_not.respond_to?(:protected?)
end
end
diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb
index 4844f4b90b..4cb23f4cf1 100644
--- a/spec/ruby/core/method/public_spec.rb
+++ b/spec/ruby/core/method/public_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#public?" do
- ruby_version_is ""..."3.2" do
- it "returns true when the method is public" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).public?.should == true
- end
-
- it "returns false when the method is protected" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).public?.should == false
- end
-
- it "returns false when the method is private" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).public?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).should_not.respond_to?(:public?)
- end
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).should_not.respond_to?(:public?)
end
end
diff --git a/spec/ruby/core/method/receiver_spec.rb b/spec/ruby/core/method/receiver_spec.rb
index 2b2e11dd2e..315a08d288 100644
--- a/spec/ruby/core/method/receiver_spec.rb
+++ b/spec/ruby/core/method/receiver_spec.rb
@@ -4,19 +4,19 @@ require_relative 'fixtures/classes'
describe "Method#receiver" do
it "returns the receiver of the method" do
s = "abc"
- s.method(:upcase).receiver.should equal(s)
+ s.method(:upcase).receiver.should.equal?(s)
end
it "returns the right receiver even when aliased" do
obj = MethodSpecs::Methods.new
- obj.method(:foo).receiver.should equal(obj)
- obj.method(:bar).receiver.should equal(obj)
+ obj.method(:foo).receiver.should.equal?(obj)
+ obj.method(:bar).receiver.should.equal?(obj)
end
describe "for a Method generated by respond_to_missing?" do
it "returns the receiver of the method" do
m = MethodSpecs::Methods.new
- m.method(:handled_via_method_missing).receiver.should equal(m)
+ m.method(:handled_via_method_missing).receiver.should.equal?(m)
end
end
end
diff --git a/spec/ruby/core/method/shared/aliased_inspect.rb b/spec/ruby/core/method/shared/aliased_inspect.rb
new file mode 100644
index 0000000000..2a622c2f97
--- /dev/null
+++ b/spec/ruby/core/method/shared/aliased_inspect.rb
@@ -0,0 +1,31 @@
+describe :method_to_s_aliased, shared: true do
+ # @object converts a bound Method to either a Method (identity) or an
+ # UnboundMethod (-> meth { meth.unbind }), so these expectations cover both
+ # Method#to_s/#inspect and UnboundMethod#to_s/#inspect.
+
+ it "shows the original name in parentheses for an aliased method" do
+ klass = Class.new do
+ def original_method; end
+ alias_method :renamed_method, :original_method
+ end
+ @object.call(klass.new.method(:renamed_method)).send(@method).should.include? '#renamed_method(original_method)'
+ end
+
+ it "shows the source UnboundMethod's name in parentheses for a define_method'd method" do
+ klass = Class.new { define_method(:renamed_is_a?, ::Kernel.instance_method(:is_a?)) }
+ @object.call(klass.new.method(:renamed_is_a?)).send(@method).should.include? '#renamed_is_a?(is_a?)'
+ end
+
+ it "does not annotate a directly looked-up Kernel method with a shared internal name" do
+ @object.call(Object.new.method(:is_a?)).send(@method).should_not.include? '(kind_of?)'
+ @object.call(Object.new.method(:kind_of?)).send(@method).should_not.include? '(is_a?)'
+ end
+
+ it "shows the source name when aliasing a define_method'd Kernel method" do
+ klass = Class.new do
+ define_method(:my_is_a?, ::Kernel.instance_method(:is_a?))
+ alias_method :renamed_is_a?, :my_is_a?
+ end
+ @object.call(klass.new.method(:renamed_is_a?)).send(@method).should.include? '#renamed_is_a?(is_a?)'
+ end
+end
diff --git a/spec/ruby/core/method/shared/call.rb b/spec/ruby/core/method/shared/call.rb
index f26e373695..41ee2b06cb 100644
--- a/spec/ruby/core/method/shared/call.rb
+++ b/spec/ruby/core/method/shared/call.rb
@@ -11,10 +11,10 @@ describe :method_call, shared: true do
it "raises an ArgumentError when given incorrect number of arguments" do
-> {
MethodSpecs::Methods.new.method(:two_req).send(@method, 1, 2, 3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
MethodSpecs::Methods.new.method(:two_req).send(@method, 1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
describe "for a Method generated by respond_to_missing?" do
diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb
index c74847083f..eee790890a 100644
--- a/spec/ruby/core/method/shared/dup.rb
+++ b/spec/ruby/core/method/shared/dup.rb
@@ -4,7 +4,7 @@ describe :method_dup, shared: true do
b = a.send(@method)
a.should == b
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
ruby_version_is "3.4" do
diff --git a/spec/ruby/core/method/shared/eql.rb b/spec/ruby/core/method/shared/eql.rb
index 5c720cbac1..3c340202b7 100644
--- a/spec/ruby/core/method/shared/eql.rb
+++ b/spec/ruby/core/method/shared/eql.rb
@@ -12,54 +12,54 @@ describe :method_equal, shared: true do
it "returns true if methods are the same" do
m2 = @m.method(:foo)
- @m_foo.send(@method, @m_foo).should be_true
- @m_foo.send(@method, m2).should be_true
+ @m_foo.send(@method, @m_foo).should == true
+ @m_foo.send(@method, m2).should == true
end
it "returns true on aliased methods" do
m_bar = @m.method(:bar)
- m_bar.send(@method, @m_foo).should be_true
+ m_bar.send(@method, @m_foo).should == true
end
it "returns true if the two core methods are aliases" do
s = "hello"
a = s.method(:size)
b = s.method(:length)
- a.send(@method, b).should be_true
+ a.send(@method, b).should == true
end
it "returns false on a method which is neither aliased nor the same method" do
m2 = @m.method(:zero)
- @m_foo.send(@method, m2).should be_false
+ @m_foo.send(@method, m2).should == false
end
it "returns false for a method which is not bound to the same object" do
m2_foo = @m2.method(:foo)
a_baz = @a.method(:baz)
- @m_foo.send(@method, m2_foo).should be_false
- @m_foo.send(@method, a_baz).should be_false
+ @m_foo.send(@method, m2_foo).should == false
+ @m_foo.send(@method, a_baz).should == false
end
it "returns false if the two methods are bound to the same object but were defined independently" do
m2 = @m.method(:same_as_foo)
- @m_foo.send(@method, m2).should be_false
+ @m_foo.send(@method, m2).should == false
end
it "returns true if a method was defined using the other one" do
MethodSpecs::Methods.send :define_method, :defined_foo, MethodSpecs::Methods.instance_method(:foo)
m2 = @m.method(:defined_foo)
- @m_foo.send(@method, m2).should be_true
+ @m_foo.send(@method, m2).should == true
end
it "returns false if comparing a method defined via define_method and def" do
defn = @m.method(:zero)
defined = @m.method(:zero_defined_method)
- defn.send(@method, defined).should be_false
- defined.send(@method, defn).should be_false
+ defn.send(@method, defined).should == false
+ defined.send(@method, defn).should == false
end
describe 'missing methods' do
@@ -68,8 +68,8 @@ describe :method_equal, shared: true do
miss1bis = @m.method(:handled_via_method_missing)
miss2 = @m.method(:also_handled)
- miss1.send(@method, miss1bis).should be_true
- miss1.send(@method, miss2).should be_false
+ miss1.send(@method, miss1bis).should == true
+ miss1.send(@method, miss2).should == false
end
it 'calls respond_to_missing? with true to include private methods' do
@@ -81,14 +81,14 @@ describe :method_equal, shared: true do
it "returns false if the two methods are bound to different objects, have the same names, and identical bodies" do
a = MethodSpecs::Eql.instance_method(:same_body)
b = MethodSpecs::Eql2.instance_method(:same_body)
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
end
it "returns false if the argument is not a Method object" do
- String.instance_method(:size).send(@method, 7).should be_false
+ String.instance_method(:size).send(@method, 7).should == false
end
it "returns false if the argument is an unbound version of self" do
- method(:load).send(@method, method(:load).unbind).should be_false
+ method(:load).send(@method, method(:load).unbind).should == false
end
end
diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb
index b2d27d370f..bfb58e6896 100644
--- a/spec/ruby/core/method/shared/to_s.rb
+++ b/spec/ruby/core/method/shared/to_s.rb
@@ -8,12 +8,12 @@ describe :method_to_s, shared: true do
end
it "returns a String" do
- @m.send(@method).should be_kind_of(String)
+ @m.send(@method).should.is_a?(String)
end
it "returns a String for methods defined with attr_accessor" do
m = MethodSpecs::Methods.new.method :attr
- m.send(@method).should be_kind_of(String)
+ m.send(@method).should.is_a?(String)
end
it "returns a String containing 'Method'" do
diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb
index 23d956ebec..22fcb98c74 100644
--- a/spec/ruby/core/method/source_location_spec.rb
+++ b/spec/ruby/core/method/source_location_spec.rb
@@ -7,27 +7,27 @@ describe "Method#source_location" do
end
it "returns an Array" do
- @method.source_location.should be_an_instance_of(Array)
+ @method.source_location.should.instance_of?(Array)
end
it "sets the first value to the path of the file in which the method was defined" do
- file = @method.source_location[0]
- file.should be_an_instance_of(String)
+ file = @method.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end
it "sets the last value to an Integer representing the line on which the method was defined" do
- line = @method.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @method.source_location.last
+ line.should.instance_of?(Integer)
line.should == 5
end
it "returns the last place the method was defined" do
- MethodSpecs::SourceLocation.method(:redefined).source_location[1].should == 13
+ MethodSpecs::SourceLocation.method(:redefined).source_location.last.should == 13
end
it "returns the location of the original method even if it was aliased" do
- MethodSpecs::SourceLocation.new.method(:aka).source_location[1].should == 17
+ MethodSpecs::SourceLocation.new.method(:aka).source_location.last.should == 17
end
it "works for methods defined with a block" do
@@ -92,7 +92,7 @@ describe "Method#source_location" do
loc.should == nil
else
loc[0].should.start_with?('<internal:')
- loc[1].should be_kind_of(Integer)
+ loc[1].should.is_a?(Integer)
end
loc = method(:tap).source_location
@@ -100,7 +100,7 @@ describe "Method#source_location" do
loc.should == nil
else
loc[0].should.start_with?('<internal:')
- loc[1].should be_kind_of(Integer)
+ loc[1].should.is_a?(Integer)
end
end
@@ -108,19 +108,13 @@ describe "Method#source_location" do
c = Class.new do
eval('def self.m; end', nil, "foo", 100)
end
- location = c.method(:m).source_location
- ruby_version_is(""..."3.5") do
- location.should == ["foo", 100]
- end
- ruby_version_is("3.5") do
- location.should == ["foo", 100, 0, 100, 15]
- end
+ c.method(:m).source_location.should == ["foo", 100]
end
describe "for a Method generated by respond_to_missing?" do
it "returns nil" do
m = MethodSpecs::Methods.new
- m.method(:handled_via_method_missing).source_location.should be_nil
+ m.method(:handled_via_method_missing).source_location.should == nil
end
end
end
diff --git a/spec/ruby/core/method/to_s_spec.rb b/spec/ruby/core/method/to_s_spec.rb
index 9f19011302..ba0b4fa3c6 100644
--- a/spec/ruby/core/method/to_s_spec.rb
+++ b/spec/ruby/core/method/to_s_spec.rb
@@ -1,6 +1,8 @@
require_relative '../../spec_helper'
require_relative 'shared/to_s'
+require_relative 'shared/aliased_inspect'
describe "Method#to_s" do
it_behaves_like :method_to_s, :to_s
+ it_behaves_like :method_to_s_aliased, :to_s, -> meth { meth }
end
diff --git a/spec/ruby/core/method/unbind_spec.rb b/spec/ruby/core/method/unbind_spec.rb
index bdedd513ce..994c3a8879 100644
--- a/spec/ruby/core/method/unbind_spec.rb
+++ b/spec/ruby/core/method/unbind_spec.rb
@@ -11,7 +11,7 @@ describe "Method#unbind" do
end
it "returns an UnboundMethod" do
- @normal_um.should be_kind_of(UnboundMethod)
+ @normal_um.should.is_a?(UnboundMethod)
end
describe "#inspect" do
@@ -27,16 +27,8 @@ describe "Method#unbind" do
@string.should =~ /MethodSpecs::MyMod/
end
- ruby_version_is ""..."3.2" do
- it "returns a String containing the Module the method is referenced from" do
- @string.should =~ /MethodSpecs::MySub/
- end
- end
-
- ruby_version_is "3.2" do
- it "returns a String containing the Module the method is referenced from" do
- @string.should =~ /MethodSpecs::MyMod/
- end
+ it "returns a String containing the Module the method is referenced from" do
+ @string.should =~ /MethodSpecs::MyMod/
end
end
diff --git a/spec/ruby/core/module/alias_method_spec.rb b/spec/ruby/core/module/alias_method_spec.rb
index c36dedd2d8..852879cc8a 100644
--- a/spec/ruby/core/module/alias_method_spec.rb
+++ b/spec/ruby/core/module/alias_method_spec.rb
@@ -28,12 +28,12 @@ describe "Module#alias_method" do
it "retains method visibility" do
@class.make_alias :private_ichi, :private_one
- -> { @object.private_one }.should raise_error(NameError)
- -> { @object.private_ichi }.should raise_error(NameError)
+ -> { @object.private_one }.should.raise(NameError)
+ -> { @object.private_ichi }.should.raise(NameError)
@class.make_alias :public_ichi, :public_one
@object.public_ichi.should == @object.public_one
@class.make_alias :protected_ichi, :protected_one
- -> { @object.protected_ichi }.should raise_error(NameError)
+ -> { @object.protected_ichi }.should.raise(NameError)
end
it "handles aliasing a stub that changes visibility" do
@@ -55,7 +55,7 @@ describe "Module#alias_method" do
end
it "fails if origin method not found" do
- -> { @class.make_alias :ni, :san }.should raise_error(NameError) { |e|
+ -> { @class.make_alias :ni, :san }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -63,7 +63,7 @@ describe "Module#alias_method" do
it "raises FrozenError if frozen" do
@class.freeze
- -> { @class.make_alias :uno, :public_one }.should raise_error(FrozenError)
+ -> { @class.make_alias :uno, :public_one }.should.raise(FrozenError)
end
it "converts the names using #to_str" do
@@ -78,23 +78,23 @@ describe "Module#alias_method" do
end
it "raises a TypeError when the given name can't be converted using to_str" do
- -> { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError)
+ -> { @class.make_alias mock('x'), :public_one }.should.raise(TypeError)
end
it "raises a NoMethodError if the given name raises a NoMethodError during type coercion using to_str" do
obj = mock("mock-name")
obj.should_receive(:to_str).and_raise(NoMethodError)
- -> { @class.make_alias obj, :public_one }.should raise_error(NoMethodError)
+ -> { @class.make_alias obj, :public_one }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:alias_method, false)
+ Module.public_instance_methods(false).should.include?(:alias_method)
end
describe "returned value" do
it "returns symbol of the defined method name" do
- @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value)
- @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value)
+ @class.send(:alias_method, :checking_return_value, :public_one).should.equal?(:checking_return_value)
+ @class.send(:alias_method, 'checking_return_value', :public_one).should.equal?(:checking_return_value)
end
end
@@ -104,14 +104,14 @@ describe "Module#alias_method" do
it "works on private module methods in a module that has been reopened" do
ModuleSpecs::ReopeningModule.foo.should == true
- -> { ModuleSpecs::ReopeningModule.foo2 }.should_not raise_error(NoMethodError)
+ -> { ModuleSpecs::ReopeningModule.foo2 }.should_not.raise(NoMethodError)
end
it "accesses a method defined on Object from Kernel" do
- Kernel.should_not have_public_instance_method(:module_specs_public_method_on_object)
+ Kernel.public_instance_methods(true).should_not.include?(:module_specs_public_method_on_object)
- Kernel.should have_public_instance_method(:module_specs_alias_on_kernel)
- Object.should have_public_instance_method(:module_specs_alias_on_kernel)
+ Kernel.public_instance_methods(false).should.include?(:module_specs_alias_on_kernel)
+ Object.public_instance_methods(true).should.include?(:module_specs_alias_on_kernel)
end
it "can call a method with super aliased twice" do
@@ -130,42 +130,42 @@ describe "Module#alias_method" do
it "keeps initialize private when aliasing" do
@class.make_alias(:initialize, :public_one)
- @class.private_instance_methods.include?(:initialize).should be_true
+ @class.private_instance_methods.include?(:initialize).should == true
@subclass.make_alias(:initialize, :public_one)
- @subclass.private_instance_methods.include?(:initialize).should be_true
+ @subclass.private_instance_methods.include?(:initialize).should == true
end
it "keeps initialize_copy private when aliasing" do
@class.make_alias(:initialize_copy, :public_one)
- @class.private_instance_methods.include?(:initialize_copy).should be_true
+ @class.private_instance_methods.include?(:initialize_copy).should == true
@subclass.make_alias(:initialize_copy, :public_one)
- @subclass.private_instance_methods.include?(:initialize_copy).should be_true
+ @subclass.private_instance_methods.include?(:initialize_copy).should == true
end
it "keeps initialize_clone private when aliasing" do
@class.make_alias(:initialize_clone, :public_one)
- @class.private_instance_methods.include?(:initialize_clone).should be_true
+ @class.private_instance_methods.include?(:initialize_clone).should == true
@subclass.make_alias(:initialize_clone, :public_one)
- @subclass.private_instance_methods.include?(:initialize_clone).should be_true
+ @subclass.private_instance_methods.include?(:initialize_clone).should == true
end
it "keeps initialize_dup private when aliasing" do
@class.make_alias(:initialize_dup, :public_one)
- @class.private_instance_methods.include?(:initialize_dup).should be_true
+ @class.private_instance_methods.include?(:initialize_dup).should == true
@subclass.make_alias(:initialize_dup, :public_one)
- @subclass.private_instance_methods.include?(:initialize_dup).should be_true
+ @subclass.private_instance_methods.include?(:initialize_dup).should == true
end
it "keeps respond_to_missing? private when aliasing" do
@class.make_alias(:respond_to_missing?, :public_one)
- @class.private_instance_methods.include?(:respond_to_missing?).should be_true
+ @class.private_instance_methods.include?(:respond_to_missing?).should == true
@subclass.make_alias(:respond_to_missing?, :public_one)
- @subclass.private_instance_methods.include?(:respond_to_missing?).should be_true
+ @subclass.private_instance_methods.include?(:respond_to_missing?).should == true
end
end
end
diff --git a/spec/ruby/core/module/ancestors_spec.rb b/spec/ruby/core/module/ancestors_spec.rb
index 43ebdb864f..f85884a4f3 100644
--- a/spec/ruby/core/module/ancestors_spec.rb
+++ b/spec/ruby/core/module/ancestors_spec.rb
@@ -7,14 +7,21 @@ describe "Module#ancestors" do
ModuleSpecs.ancestors.should == [ModuleSpecs]
ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic]
ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic]
- ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
- [ModuleSpecs::Parent, Object, Kernel, BasicObject]
- ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
- [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject]
+ if defined?(Ruby::Box) && Ruby::Box.enabled?
+ ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
+ [ModuleSpecs::Parent, Object, Ruby::Box::Loader, Kernel, BasicObject]
+ ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
+ [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Ruby::Box::Loader, Kernel, BasicObject]
+ else
+ ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
+ [ModuleSpecs::Parent, Object, Kernel, BasicObject]
+ ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
+ [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject]
+ end
end
it "returns only modules and classes" do
- class << ModuleSpecs::Child; self; end.ancestors.should include(ModuleSpecs::Internal, Class, Module, Object, Kernel)
+ class << ModuleSpecs::Child; self; end.ancestors.to_set.should >= Set[ModuleSpecs::Internal, Class, Module, Object, Kernel]
end
it "has 1 entry per module or class" do
@@ -38,7 +45,7 @@ describe "Module#ancestors" do
child = Class.new(parent)
schild = child.singleton_class
- schild.ancestors.should include(schild,
+ schild.ancestors.to_set.should >= Set[schild,
parent.singleton_class,
Object.singleton_class,
BasicObject.singleton_class,
@@ -46,14 +53,14 @@ describe "Module#ancestors" do
Module,
Object,
Kernel,
- BasicObject)
+ BasicObject]
end
describe 'for a standalone module' do
it 'does not include Class' do
s_mod = ModuleSpecs.singleton_class
- s_mod.ancestors.should_not include(Class)
+ s_mod.ancestors.should_not.include?(Class)
end
it 'does not include other singleton classes' do
@@ -62,19 +69,19 @@ describe "Module#ancestors" do
s_object = Object.singleton_class
s_basic_object = BasicObject.singleton_class
- s_standalone_mod.ancestors.should_not include(s_module, s_object, s_basic_object)
+ (s_standalone_mod.ancestors & [s_module, s_object, s_basic_object]).should.empty?
end
it 'includes its own singleton class' do
s_mod = ModuleSpecs.singleton_class
- s_mod.ancestors.should include(s_mod)
+ s_mod.ancestors.should.include?(s_mod)
end
it 'includes standard chain' do
s_mod = ModuleSpecs.singleton_class
- s_mod.ancestors.should include(Module, Object, Kernel, BasicObject)
+ s_mod.ancestors.to_set.should >= Set[Module, Object, Kernel, BasicObject]
end
end
end
diff --git a/spec/ruby/core/module/append_features_spec.rb b/spec/ruby/core/module/append_features_spec.rb
index 1724cde5d6..4d2207330d 100644
--- a/spec/ruby/core/module/append_features_spec.rb
+++ b/spec/ruby/core/module/append_features_spec.rb
@@ -3,18 +3,18 @@ require_relative 'fixtures/classes'
describe "Module#append_features" do
it "is a private method" do
- Module.should have_private_instance_method(:append_features)
+ Module.private_instance_methods(false).should.include?(:append_features)
end
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:append_features, true)
+ Class.private_instance_methods(true).should_not.include?(:append_features)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:append_features).bind(Class.new).call Module.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -39,11 +39,11 @@ describe "Module#append_features" do
it "raises an ArgumentError on a cyclic include" do
-> {
ModuleSpecs::CyclicAppendA.send(:append_features, ModuleSpecs::CyclicAppendA)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
ModuleSpecs::CyclicAppendB.send(:append_features, ModuleSpecs::CyclicAppendA)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
@@ -54,8 +54,8 @@ describe "Module#append_features" do
end
it "raises a FrozenError before appending self" do
- -> { @receiver.send(:append_features, @other) }.should raise_error(FrozenError)
- @other.ancestors.should_not include(@receiver)
+ -> { @receiver.send(:append_features, @other) }.should.raise(FrozenError)
+ @other.ancestors.should_not.include?(@receiver)
end
end
end
diff --git a/spec/ruby/core/module/attr_accessor_spec.rb b/spec/ruby/core/module/attr_accessor_spec.rb
index 503dccc61e..a608760cf2 100644
--- a/spec/ruby/core/module/attr_accessor_spec.rb
+++ b/spec/ruby/core/module/attr_accessor_spec.rb
@@ -34,7 +34,7 @@ describe "Module#attr_accessor" do
attr_accessor :spec_attr_accessor
end
- -> { true.spec_attr_accessor = "a" }.should raise_error(FrozenError)
+ -> { true.spec_attr_accessor = "a" }.should.raise(FrozenError)
end
it "raises FrozenError if the receiver if frozen" do
@@ -46,7 +46,7 @@ describe "Module#attr_accessor" do
obj.foo.should == 1
obj.freeze
- -> { obj.foo = 42 }.should raise_error(FrozenError)
+ -> { obj.foo = 42 }.should.raise(FrozenError)
obj.foo.should == 1
end
@@ -62,9 +62,9 @@ describe "Module#attr_accessor" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('o')
- -> { Class.new { attr_accessor o } }.should raise_error(TypeError)
+ -> { Class.new { attr_accessor o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr_accessor o } }.should raise_error(TypeError)
+ -> { Class.new { attr_accessor o } }.should.raise(TypeError)
end
it "applies current visibility to methods created" do
@@ -73,12 +73,12 @@ describe "Module#attr_accessor" do
attr_accessor :foo
end
- -> { c.new.foo }.should raise_error(NoMethodError)
- -> { c.new.foo=1 }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
+ -> { c.new.foo=1 }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:attr_accessor, false)
+ Module.public_instance_methods(false).should.include?(:attr_accessor)
end
it "returns an array of defined method names as symbols" do
@@ -104,7 +104,7 @@ describe "Module#attr_accessor" do
end
it "can read through the accessor" do
- 1.foobar.should be_nil
+ 1.foobar.should == nil
end
end
diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb
index 37fd537ff5..2b4ca2100e 100644
--- a/spec/ruby/core/module/attr_reader_spec.rb
+++ b/spec/ruby/core/module/attr_reader_spec.rb
@@ -30,7 +30,7 @@ describe "Module#attr_reader" do
attr_reader :spec_attr_reader
end
- -> { true.instance_variable_set("@spec_attr_reader", "a") }.should raise_error(RuntimeError)
+ -> { true.instance_variable_set("@spec_attr_reader", "a") }.should.raise(RuntimeError)
end
it "converts non string/symbol names to strings using to_str" do
@@ -45,9 +45,9 @@ describe "Module#attr_reader" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('o')
- -> { Class.new { attr_reader o } }.should raise_error(TypeError)
+ -> { Class.new { attr_reader o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr_reader o } }.should raise_error(TypeError)
+ -> { Class.new { attr_reader o } }.should.raise(TypeError)
end
it "applies current visibility to methods created" do
@@ -56,11 +56,11 @@ describe "Module#attr_reader" do
attr_reader :foo
end
- -> { c.new.foo }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:attr_reader, false)
+ Module.public_instance_methods(false).should.include?(:attr_reader)
end
it "returns an array of defined method names as symbols" do
diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb
index 2f9f4e26dc..d696864955 100644
--- a/spec/ruby/core/module/attr_spec.rb
+++ b/spec/ruby/core/module/attr_spec.rb
@@ -90,8 +90,8 @@ describe "Module#attr" do
attr :foo, true
end
- -> { c.new.foo }.should raise_error(NoMethodError)
- -> { c.new.foo=1 }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
+ -> { c.new.foo=1 }.should.raise(NoMethodError)
end
it "creates a getter but no setter for all given attribute names" do
@@ -121,8 +121,8 @@ describe "Module#attr" do
attr :foo, :bar
end
- -> { c.new.foo }.should raise_error(NoMethodError)
- -> { c.new.bar }.should raise_error(NoMethodError)
+ -> { c.new.foo }.should.raise(NoMethodError)
+ -> { c.new.bar }.should.raise(NoMethodError)
end
it "converts non string/symbol names to strings using to_str" do
@@ -132,9 +132,9 @@ describe "Module#attr" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('o')
- -> { Class.new { attr o } }.should raise_error(TypeError)
+ -> { Class.new { attr o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr o } }.should raise_error(TypeError)
+ -> { Class.new { attr o } }.should.raise(TypeError)
end
it "with a boolean argument emits a warning when $VERBOSE is true" do
@@ -144,7 +144,7 @@ describe "Module#attr" do
end
it "is a public method" do
- Module.should have_public_instance_method(:attr, false)
+ Module.public_instance_methods(false).should.include?(:attr)
end
it "returns an array of defined method names as symbols" do
diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb
index 5b863ef88c..6089b52495 100644
--- a/spec/ruby/core/module/attr_writer_spec.rb
+++ b/spec/ruby/core/module/attr_writer_spec.rb
@@ -30,7 +30,7 @@ describe "Module#attr_writer" do
attr_writer :spec_attr_writer
end
- -> { true.spec_attr_writer = "a" }.should raise_error(FrozenError)
+ -> { true.spec_attr_writer = "a" }.should.raise(FrozenError)
end
it "raises FrozenError if the receiver if frozen" do
@@ -40,7 +40,7 @@ describe "Module#attr_writer" do
obj = c.new
obj.freeze
- -> { obj.foo = 42 }.should raise_error(FrozenError)
+ -> { obj.foo = 42 }.should.raise(FrozenError)
end
it "converts non string/symbol names to strings using to_str" do
@@ -55,9 +55,9 @@ describe "Module#attr_writer" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
o = mock('test1')
- -> { Class.new { attr_writer o } }.should raise_error(TypeError)
+ -> { Class.new { attr_writer o } }.should.raise(TypeError)
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { Class.new { attr_writer o } }.should raise_error(TypeError)
+ -> { Class.new { attr_writer o } }.should.raise(TypeError)
end
it "applies current visibility to methods created" do
@@ -66,11 +66,11 @@ describe "Module#attr_writer" do
attr_writer :foo
end
- -> { c.new.foo=1 }.should raise_error(NoMethodError)
+ -> { c.new.foo=1 }.should.raise(NoMethodError)
end
it "is a public method" do
- Module.should have_public_instance_method(:attr_writer, false)
+ Module.public_instance_methods(false).should.include?(:attr_writer)
end
it "returns an array of defined method names as symbols" do
diff --git a/spec/ruby/core/module/autoload_relative_spec.rb b/spec/ruby/core/module/autoload_relative_spec.rb
new file mode 100644
index 0000000000..2e7d85496b
--- /dev/null
+++ b/spec/ruby/core/module/autoload_relative_spec.rb
@@ -0,0 +1,128 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+# Specs for Module#autoload_relative
+module ModuleSpecs
+ module AutoloadRelative
+ # Will be used for testing
+ end
+end
+
+ruby_version_is "4.1" do
+ describe "Module#autoload_relative" do
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ end
+
+ it "is a public method" do
+ Module.public_instance_methods(false).should.include?(:autoload_relative)
+ end
+
+ it "registers a file to load relative to the current file the first time the named constant is accessed" do
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeA, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:AutoloadRelativeA)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_a.rb")
+ File.exist?(path).should == true
+ end
+
+ it "loads the registered file when the constant is accessed" do
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeB, "fixtures/autoload_relative_a.rb"
+ ModuleSpecs::Autoload::AutoloadRelativeB.should.is_a?(Module)
+ end
+
+ it "returns nil" do
+ ModuleSpecs::Autoload.autoload_relative(:AutoloadRelativeC, "fixtures/autoload_relative_a.rb").should == nil
+ end
+
+ it "registers a file to load the first time the named constant is accessed" do
+ module ModuleSpecs::Autoload::AutoloadRelativeTest
+ autoload_relative :D, "fixtures/autoload_relative_a.rb"
+ end
+ path = ModuleSpecs::Autoload::AutoloadRelativeTest.autoload?(:D)
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_a.rb")
+ end
+
+ it "sets the autoload constant in the constants table" do
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeTableTest, "fixtures/autoload_relative_a.rb"
+ ModuleSpecs::Autoload.should.const_defined?(:AutoloadRelativeTableTest, false)
+ end
+
+ it "calls #to_path on non-String filenames" do
+ name = mock("autoload_relative mock")
+ name.should_receive(:to_path).and_return("fixtures/autoload_relative_a.rb")
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeToPath, name
+ ModuleSpecs::Autoload.autoload?(:AutoloadRelativeToPath).should_not == nil
+ end
+
+ it "calls #to_str on non-String filenames" do
+ name = mock("autoload_relative mock")
+ name.should_receive(:to_str).and_return("fixtures/autoload_relative_a.rb")
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeToStr, name
+ ModuleSpecs::Autoload.autoload?(:AutoloadRelativeToStr).should_not == nil
+ end
+
+ it "raises a TypeError if the filename argument is not a String or pathname" do
+ -> {
+ ModuleSpecs::Autoload.autoload_relative :AutoloadRelativeTypError, nil
+ }.should.raise(TypeError)
+ end
+
+ it "raises a NameError if the constant name is not valid" do
+ -> {
+ ModuleSpecs::Autoload.autoload_relative :invalid_name, "fixtures/autoload_relative_a.rb"
+ }.should.raise(NameError)
+ end
+
+ it "raises an ArgumentError if the constant name starts with a lowercase letter" do
+ -> {
+ ModuleSpecs::Autoload.autoload_relative :autoload, "fixtures/autoload_relative_a.rb"
+ }.should.raise(NameError)
+ end
+
+ it "raises LoadError if called from eval without file context" do
+ -> {
+ ModuleSpecs::Autoload.module_eval('autoload_relative :EvalTest, "fixtures/autoload_relative_a.rb"')
+ }.should.raise(LoadError, /autoload_relative called without file context/)
+ end
+
+ it "can autoload in instance_eval with a file context" do
+ path = nil
+ ModuleSpecs::Autoload.instance_eval(<<-CODE, __FILE__, __LINE__)
+ autoload_relative :InstanceEvalTest, "fixtures/autoload_relative_a.rb"
+ path = autoload?(:InstanceEvalTest)
+ CODE
+ path.should_not == nil
+ path.should.end_with?("autoload_relative_a.rb")
+ end
+
+ it "resolves paths relative to the file where it's called" do
+ # Using fixtures/autoload_relative_a.rb which exists
+ ModuleSpecs::Autoload.autoload_relative :RelativePathTest, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:RelativePathTest)
+ path.should.include?("fixtures")
+ path.should.end_with?("autoload_relative_a.rb")
+ end
+
+ it "can load nested directory paths" do
+ ModuleSpecs::Autoload.autoload_relative :NestedPath, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:NestedPath)
+ path.should_not == nil
+ File.exist?(path).should == true
+ end
+
+ describe "interoperability with autoload?" do
+ it "returns the absolute path with autoload?" do
+ ModuleSpecs::Autoload.autoload_relative :QueryTest, "fixtures/autoload_relative_a.rb"
+ path = ModuleSpecs::Autoload.autoload?(:QueryTest)
+ # Should be an absolute path
+ Pathname.new(path).absolute?.should == true
+ end
+ end
+end
+end
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 3cdc48f9ba..057237a92f 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -9,7 +9,7 @@ describe "Module#autoload?" do
end
it "returns nil if no file has been registered for a constant" do
- ModuleSpecs::Autoload.autoload?(:Manualload).should be_nil
+ ModuleSpecs::Autoload.autoload?(:Manualload).should == nil
end
it "returns the name of the file that will be autoloaded if an ancestor defined that autoload" do
@@ -19,7 +19,7 @@ describe "Module#autoload?" do
it "returns nil if an ancestor defined that autoload but recursion is disabled" do
ModuleSpecs::Autoload::Parent.autoload :InheritedAutoload, "inherited_autoload.rb"
- ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should be_nil
+ ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should == nil
end
it "returns the name of the file that will be loaded if recursion is disabled but the autoload is defined on the class itself" do
@@ -55,7 +55,7 @@ describe "Module#autoload" do
it "sets the autoload constant in the constants table" do
ModuleSpecs::Autoload.autoload :B, @non_existent
- ModuleSpecs::Autoload.should have_constant(:B)
+ ModuleSpecs::Autoload.should.const_defined?(:B, false)
end
it "can be overridden with a second autoload on the same constant" do
@@ -71,7 +71,7 @@ describe "Module#autoload" do
end
it "loads the registered constant when it is accessed" do
- ModuleSpecs::Autoload.should_not have_constant(:X)
+ ModuleSpecs::Autoload.should_not.const_defined?(:X)
ModuleSpecs::Autoload.autoload :X, fixture(__FILE__, "autoload_x.rb")
@remove << :X
ModuleSpecs::Autoload::X.should == :x
@@ -82,7 +82,7 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::DynClass = cls
@remove << :DynClass
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
ModuleSpecs::Autoload::DynClass::C.new.loaded.should == :dynclass_c
ScratchPad.recorded.should == :loaded
end
@@ -92,7 +92,7 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::DynModule = mod
@remove << :DynModule
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
ModuleSpecs::Autoload::DynModule::D.new.loaded.should == :dynmodule_d
ScratchPad.recorded.should == :loaded
end
@@ -131,7 +131,7 @@ describe "Module#autoload" do
@remove << :I
ModuleSpecs::Autoload.const_set :I, 3
ModuleSpecs::Autoload::I.should == 3
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "loads a file with .rb extension when passed the name without the extension" do
@@ -144,7 +144,7 @@ describe "Module#autoload" do
main = TOPLEVEL_BINDING.eval("self")
main.should_receive(:require).with("module_autoload_not_exist.rb")
# The constant won't be defined since require is mocked to do nothing
- -> { ModuleSpecs::Autoload::ModuleAutoloadCallsRequire }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::ModuleAutoloadCallsRequire }.should.raise(NameError)
end
it "does not load the file if the file is manually required" do
@@ -156,9 +156,9 @@ describe "Module#autoload" do
ScratchPad.recorded.should == :loaded
ScratchPad.clear
- ModuleSpecs::Autoload::KHash.should be_kind_of(Class)
+ ModuleSpecs::Autoload::KHash.should.is_a?(Class)
ModuleSpecs::Autoload::KHash::K.should == :autoload_k
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "ignores the autoload request if the file is already loaded" do
@@ -171,7 +171,7 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :S, filename
@remove << :S
- ModuleSpecs::Autoload.autoload?(:S).should be_nil
+ ModuleSpecs::Autoload.autoload?(:S).should == nil
end
it "retains the autoload even if the request to require fails" do
@@ -182,7 +182,7 @@ describe "Module#autoload" do
-> {
require filename
- }.should raise_error(LoadError)
+ }.should.raise(LoadError)
ModuleSpecs::Autoload.autoload?(:NotThere).should == filename
end
@@ -205,7 +205,7 @@ describe "Module#autoload" do
filename = fixture(__FILE__, "autoload_during_require_current_file.rb")
require filename
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
describe "interacting with defined?" do
@@ -215,9 +215,9 @@ describe "Module#autoload" do
end
defined?(ModuleSpecs::Autoload::Dog::R).should == "constant"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
- ModuleSpecs::Autoload::Dog.should have_constant(:R)
+ ModuleSpecs::Autoload::Dog.should.const_defined?(:R, false)
end
it "loads an autoloaded parent when referencing a nested constant" do
@@ -235,7 +235,7 @@ describe "Module#autoload" do
autoload :BadParent, fixture(__FILE__, "autoload_exception.rb")
end
- defined?(ModuleSpecs::Autoload::BadParent::Nested).should be_nil
+ defined?(ModuleSpecs::Autoload::BadParent::Nested).should == nil
ScratchPad.recorded.should == :exception
end
end
@@ -454,16 +454,16 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :Fail, @non_existent
ModuleSpecs::Autoload.const_defined?(:Fail).should == true
- ModuleSpecs::Autoload.should have_constant(:Fail)
+ ModuleSpecs::Autoload.should.const_defined?(:Fail, false)
ModuleSpecs::Autoload.autoload?(:Fail).should == @non_existent
- -> { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
+ -> { ModuleSpecs::Autoload::Fail }.should.raise(LoadError)
- ModuleSpecs::Autoload.should have_constant(:Fail)
+ ModuleSpecs::Autoload.should.const_defined?(:Fail, false)
ModuleSpecs::Autoload.const_defined?(:Fail).should == true
ModuleSpecs::Autoload.autoload?(:Fail).should == @non_existent
- -> { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
+ -> { ModuleSpecs::Autoload::Fail }.should.raise(LoadError)
end
it "does not remove the constant from Module#constants if load raises a RuntimeError and keeps it as an autoload" do
@@ -472,17 +472,17 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :Raise, path
ModuleSpecs::Autoload.const_defined?(:Raise).should == true
- ModuleSpecs::Autoload.should have_constant(:Raise)
+ ModuleSpecs::Autoload.should.const_defined?(:Raise, false)
ModuleSpecs::Autoload.autoload?(:Raise).should == path
- -> { ModuleSpecs::Autoload::Raise }.should raise_error(RuntimeError)
+ -> { ModuleSpecs::Autoload::Raise }.should.raise(RuntimeError)
ScratchPad.recorded.should == [:raise]
- ModuleSpecs::Autoload.should have_constant(:Raise)
+ ModuleSpecs::Autoload.should.const_defined?(:Raise, false)
ModuleSpecs::Autoload.const_defined?(:Raise).should == true
ModuleSpecs::Autoload.autoload?(:Raise).should == path
- -> { ModuleSpecs::Autoload::Raise }.should raise_error(RuntimeError)
+ -> { ModuleSpecs::Autoload::Raise }.should.raise(RuntimeError)
ScratchPad.recorded.should == [:raise, :raise]
end
@@ -492,15 +492,15 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.autoload :O, path
ModuleSpecs::Autoload.const_defined?(:O).should == true
- ModuleSpecs::Autoload.should have_constant(:O)
+ ModuleSpecs::Autoload.should.const_defined?(:O, false)
ModuleSpecs::Autoload.autoload?(:O).should == path
- -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::O }.should.raise(NameError)
ModuleSpecs::Autoload.const_defined?(:O).should == false
- ModuleSpecs::Autoload.should_not have_constant(:O)
+ ModuleSpecs::Autoload.should_not.const_defined?(:O)
ModuleSpecs::Autoload.autoload?(:O).should == nil
- -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload.const_get(:O) }.should.raise(NameError)
end
it "does not try to load the file again if the loaded file did not define the constant" do
@@ -508,13 +508,13 @@ describe "Module#autoload" do
ScratchPad.record []
ModuleSpecs::Autoload.autoload :NotDefinedByFile, path
- -> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::NotDefinedByFile }.should.raise(NameError)
ScratchPad.recorded.should == [:loaded]
- -> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::NotDefinedByFile }.should.raise(NameError)
ScratchPad.recorded.should == [:loaded]
Thread.new {
- -> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::NotDefinedByFile }.should.raise(NameError)
}.join
ScratchPad.recorded.should == [:loaded]
end
@@ -524,7 +524,7 @@ describe "Module#autoload" do
autoload :R, fixture(__FILE__, "autoload.rb")
defined?(R).should == 'constant'
end
- ModuleSpecs::Autoload::Q.should have_constant(:R)
+ ModuleSpecs::Autoload::Q.should.const_defined?(:R, false)
end
it "does not load the file when removing an autoload constant" do
@@ -532,13 +532,13 @@ describe "Module#autoload" do
autoload :R, fixture(__FILE__, "autoload.rb")
remove_const :R
end
- ModuleSpecs::Autoload::Q.should_not have_constant(:R)
+ ModuleSpecs::Autoload::Q.should_not.const_defined?(:R)
end
it "does not load the file when accessing the constants table of the module" do
ModuleSpecs::Autoload.autoload :P, @non_existent
- ModuleSpecs::Autoload.const_defined?(:P).should be_true
- ModuleSpecs::Autoload.const_defined?("P").should be_true
+ ModuleSpecs::Autoload.const_defined?(:P).should == true
+ ModuleSpecs::Autoload.const_defined?("P").should == true
end
it "loads the file when opening a module that is the autoloaded constant" do
@@ -573,8 +573,8 @@ describe "Module#autoload" do
DeclaredAndDefinedInParent.should == :declared_and_defined_in_parent
# The constant is really in Autoload, not Autoload::LexicalScope
- self.should_not have_constant(:DeclaredAndDefinedInParent)
- -> { const_get(:DeclaredAndDefinedInParent) }.should raise_error(NameError)
+ self.should_not.const_defined?(:DeclaredAndDefinedInParent)
+ -> { const_get(:DeclaredAndDefinedInParent) }.should.raise(NameError)
end
DeclaredAndDefinedInParent.should == :declared_and_defined_in_parent
end
@@ -597,38 +597,36 @@ describe "Module#autoload" do
# Basically, the parent autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInParentDefinedInCurrent).should == nil
const_defined?(:DeclaredInParentDefinedInCurrent).should == false
- -> { DeclaredInParentDefinedInCurrent }.should raise_error(NameError)
+ -> { DeclaredInParentDefinedInCurrent }.should.raise(NameError)
ModuleSpecs::Autoload::LexicalScope.send(:remove_const, :DeclaredInParentDefinedInCurrent)
end
end
- ruby_version_is "3.2" do
- it "warns once in verbose mode if the constant was defined in a parent scope" do
- ScratchPad.record -> {
- ModuleSpecs::DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
- }
+ it "warns once in verbose mode if the constant was defined in a parent scope" do
+ ScratchPad.record -> {
+ ModuleSpecs::DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
+ }
- module ModuleSpecs
- module Autoload
- autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == fixture(__FILE__, "autoload_callback.rb")
- const_defined?(:DeclaredInCurrentDefinedInParent).should == true
-
- -> {
- DeclaredInCurrentDefinedInParent
- }.should complain(
- /Expected .*autoload_callback.rb to define ModuleSpecs::Autoload::DeclaredInCurrentDefinedInParent but it didn't/,
- verbose: true,
- )
-
- -> {
- DeclaredInCurrentDefinedInParent
- }.should_not complain(/.*/, verbose: true)
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
- const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- ModuleSpecs.const_defined?(:DeclaredInCurrentDefinedInParent).should == true
- end
+ module ModuleSpecs
+ module Autoload
+ autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == fixture(__FILE__, "autoload_callback.rb")
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == true
+
+ -> {
+ DeclaredInCurrentDefinedInParent
+ }.should complain(
+ /Expected .*autoload_callback.rb to define ModuleSpecs::Autoload::DeclaredInCurrentDefinedInParent but it didn't/,
+ verbose: true,
+ )
+
+ -> {
+ DeclaredInCurrentDefinedInParent
+ }.should_not complain(/.*/, verbose: true)
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == false
+ ModuleSpecs.const_defined?(:DeclaredInCurrentDefinedInParent).should == true
end
end
end
@@ -642,11 +640,11 @@ describe "Module#autoload" do
class LexicalScope
autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError)
+ -> { DeclaredInCurrentDefinedInParent }.should_not.raise(NameError)
# Basically, the autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
+ -> { const_get(:DeclaredInCurrentDefinedInParent) }.should.raise(NameError)
end
DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
@@ -716,10 +714,25 @@ describe "Module#autoload" do
end
end
end
- ModuleSpecs::Autoload.r.should be_kind_of(ModuleSpecs::Autoload::MetaScope)
+ ModuleSpecs::Autoload.r.should.is_a?(ModuleSpecs::Autoload::MetaScope)
end
end
+ it "should trigger the autoload when using `private_constant`" do
+ @remove << :DynClass
+ module ModuleSpecs::Autoload
+ autoload :DynClass, fixture(__FILE__, "autoload_c.rb")
+ private_constant :DynClass
+
+ ScratchPad.recorded.should == nil
+
+ DynClass::C.new.loaded.should == :dynclass_c
+ ScratchPad.recorded.should == :loaded
+ end
+
+ -> { ModuleSpecs::Autoload::DynClass }.should.raise(NameError, /private constant/)
+ end
+
# [ruby-core:19127] [ruby-core:29941]
it "does NOT raise a NameError when the autoload file did not define the constant and a module is opened with the same name" do
module ModuleSpecs::Autoload
@@ -732,7 +745,7 @@ describe "Module#autoload" do
end
@remove << :W
- ModuleSpecs::Autoload::W::Y.should be_kind_of(Class)
+ ModuleSpecs::Autoload::W::Y.should.is_a?(Class)
ScratchPad.recorded.should == :loaded
end
@@ -747,7 +760,7 @@ describe "Module#autoload" do
-> {
Kernel.require fixture(__FILE__, "autoload_during_require.rb")
}.should_not complain(verbose: true)
- ModuleSpecs::Autoload::AutoloadDuringRequire.should be_kind_of(Class)
+ ModuleSpecs::Autoload::AutoloadDuringRequire.should.is_a?(Class)
end
it "does not call #require a second time and does not warn if feature sets and trigger autoload on itself" do
@@ -757,15 +770,15 @@ describe "Module#autoload" do
-> {
Kernel.require fixture(__FILE__, "autoload_self_during_require.rb")
}.should_not complain(verbose: true)
- ModuleSpecs::Autoload::AutoloadSelfDuringRequire.should be_kind_of(Class)
+ ModuleSpecs::Autoload::AutoloadSelfDuringRequire.should.is_a?(Class)
end
it "handles multiple autoloads in the same file" do
$LOAD_PATH.unshift(File.expand_path('../fixtures/multi', __FILE__))
begin
require 'foo/bar_baz'
- ModuleSpecs::Autoload::Foo::Bar.should be_kind_of(Class)
- ModuleSpecs::Autoload::Foo::Baz.should be_kind_of(Class)
+ ModuleSpecs::Autoload::Foo::Bar.should.is_a?(Class)
+ ModuleSpecs::Autoload::Foo::Baz.should.is_a?(Class)
ensure
$LOAD_PATH.shift
end
@@ -778,19 +791,19 @@ describe "Module#autoload" do
end
it "raises an ArgumentError when an empty filename is given" do
- -> { ModuleSpecs.autoload :A, "" }.should raise_error(ArgumentError)
+ -> { ModuleSpecs.autoload :A, "" }.should.raise(ArgumentError)
end
it "raises a NameError when the constant name starts with a lower case letter" do
- -> { ModuleSpecs.autoload "a", @non_existent }.should raise_error(NameError)
+ -> { ModuleSpecs.autoload "a", @non_existent }.should.raise(NameError)
end
it "raises a NameError when the constant name starts with a number" do
- -> { ModuleSpecs.autoload "1two", @non_existent }.should raise_error(NameError)
+ -> { ModuleSpecs.autoload "1two", @non_existent }.should.raise(NameError)
end
it "raises a NameError when the constant name has a space in it" do
- -> { ModuleSpecs.autoload "a name", @non_existent }.should raise_error(NameError)
+ -> { ModuleSpecs.autoload "a name", @non_existent }.should.raise(NameError)
end
it "shares the autoload request across dup'ed copies of modules" do
@@ -807,7 +820,7 @@ describe "Module#autoload" do
mod2.autoload?(:T).should == filename
mod1::T.should == :autoload_t
- -> { mod2::T }.should raise_error(NameError)
+ -> { mod2::T }.should.raise(NameError)
end
it "raises a TypeError if opening a class with a different superclass than the class defined in the autoload file" do
@@ -818,27 +831,27 @@ describe "Module#autoload" do
-> do
class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if not passed a String or object responding to #to_path for the filename" do
name = mock("autoload_name.rb")
- -> { ModuleSpecs::Autoload.autoload :Str, name }.should raise_error(TypeError)
+ -> { ModuleSpecs::Autoload.autoload :Str, name }.should.raise(TypeError)
end
it "calls #to_path on non-String filename arguments" do
name = mock("autoload_name.rb")
name.should_receive(:to_path).and_return("autoload_name.rb")
- -> { ModuleSpecs::Autoload.autoload :Str, name }.should_not raise_error
+ -> { ModuleSpecs::Autoload.autoload :Str, name }.should_not.raise
end
describe "on a frozen module" do
it "raises a FrozenError before setting the name" do
frozen_module = Module.new.freeze
- -> { frozen_module.autoload :Foo, @non_existent }.should raise_error(FrozenError)
- frozen_module.should_not have_constant(:Foo)
+ -> { frozen_module.autoload :Foo, @non_existent }.should.raise(FrozenError)
+ frozen_module.should_not.const_defined?(:Foo)
end
end
@@ -903,7 +916,7 @@ describe "Module#autoload" do
t1_val.should == 1
t2_val.should == t1_val
- t2_exc.should be_nil
+ t2_exc.should == nil
end
# https://bugs.ruby-lang.org/issues/10892
@@ -935,7 +948,7 @@ describe "Module#autoload" do
begin
Object.const_get(mod_name).foo
- rescue NoMethodError
+ rescue NameError, NoMethodError # rubocop:disable Lint/ShadowedException
barrier.disable!
break false
end
@@ -943,8 +956,8 @@ describe "Module#autoload" do
end
end
- # check that no thread got a NoMethodError because of partially loaded module
- threads.all? {|t| t.value}.should be_true
+ # check that no thread got a NameError or NoMethodError because of partially loaded module
+ threads.all? {|t| t.value}.should == true
# check that the autoloaded file was evaled exactly once
ScratchPad.recorded.get.should == mod_count
@@ -952,6 +965,8 @@ describe "Module#autoload" do
mod_names.each do |mod_name|
Object.send(:remove_const, mod_name)
end
+ ensure
+ threads.each(&:join) if threads
end
it "raises a NameError in each thread if the constant is not set" do
@@ -975,7 +990,7 @@ describe "Module#autoload" do
start = true
threads.each { |t|
- t.value.should be_an_instance_of(NameError)
+ t.value.should.instance_of?(NameError)
}
end
@@ -1000,7 +1015,7 @@ describe "Module#autoload" do
start = true
threads.each { |t|
- t.value.should be_an_instance_of(LoadError)
+ t.value.should.instance_of?(LoadError)
}
end
end
diff --git a/spec/ruby/core/module/class_variable_defined_spec.rb b/spec/ruby/core/module/class_variable_defined_spec.rb
index c0f2072a37..dedce9589a 100644
--- a/spec/ruby/core/module/class_variable_defined_spec.rb
+++ b/spec/ruby/core/module/class_variable_defined_spec.rb
@@ -19,13 +19,13 @@ describe "Module#class_variable_defined?" do
obj = mock("metaclass class variable")
meta = obj.singleton_class
meta.send :class_variable_set, :@@var, 1
- meta.send(:class_variable_defined?, :@@var).should be_true
+ meta.send(:class_variable_defined?, :@@var).should == true
end
it "returns false if the class variable is not defined in a metaclass" do
obj = mock("metaclass class variable")
meta = obj.singleton_class
- meta.class_variable_defined?(:@@var).should be_false
+ meta.class_variable_defined?(:@@var).should == false
end
it "returns true if a class variables with the given name is defined in an included module" do
@@ -44,11 +44,11 @@ describe "Module#class_variable_defined?" do
-> {
c.class_variable_defined?(:invalid_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
-> {
c.class_variable_defined?("@invalid_name")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "converts a non string/symbol name to string using to_str" do
@@ -62,11 +62,11 @@ describe "Module#class_variable_defined?" do
o = mock('123')
-> {
c.class_variable_defined?(o)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
-> {
c.class_variable_defined?(o)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/class_variable_get_spec.rb b/spec/ruby/core/module/class_variable_get_spec.rb
index e5d06731ec..13f06cb94a 100644
--- a/spec/ruby/core/module/class_variable_get_spec.rb
+++ b/spec/ruby/core/module/class_variable_get_spec.rb
@@ -15,8 +15,8 @@ describe "Module#class_variable_get" do
it "raises a NameError for a class variable named '@@'" do
c = Class.new
- -> { c.send(:class_variable_get, "@@") }.should raise_error(NameError)
- -> { c.send(:class_variable_get, :"@@") }.should raise_error(NameError)
+ -> { c.send(:class_variable_get, "@@") }.should.raise(NameError)
+ -> { c.send(:class_variable_get, :"@@") }.should.raise(NameError)
end
it "raises a NameError for a class variables with the given name defined in an extended module" do
@@ -24,7 +24,7 @@ describe "Module#class_variable_get" do
c.extend ModuleSpecs::MVars
-> {
c.send(:class_variable_get, "@@mvar")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns class variables defined in the class body and accessed in the metaclass" do
@@ -49,15 +49,15 @@ describe "Module#class_variable_get" do
it "raises a NameError when an uninitialized class variable is accessed" do
c = Class.new
[:@@no_class_var, "@@no_class_var"].each do |cvar|
- -> { c.send(:class_variable_get, cvar) }.should raise_error(NameError)
+ -> { c.send(:class_variable_get, cvar) }.should.raise(NameError)
end
end
it "raises a NameError when the given name is not allowed" do
c = Class.new
- -> { c.send(:class_variable_get, :invalid_name) }.should raise_error(NameError)
- -> { c.send(:class_variable_get, "@invalid_name") }.should raise_error(NameError)
+ -> { c.send(:class_variable_get, :invalid_name) }.should.raise(NameError)
+ -> { c.send(:class_variable_get, "@invalid_name") }.should.raise(NameError)
end
it "converts a non string/symbol name to string using to_str" do
@@ -69,8 +69,8 @@ describe "Module#class_variable_get" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
c = Class.new { class_variable_set :@@class_var, "test" }
o = mock('123')
- -> { c.send(:class_variable_get, o) }.should raise_error(TypeError)
+ -> { c.send(:class_variable_get, o) }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { c.send(:class_variable_get, o) }.should raise_error(TypeError)
+ -> { c.send(:class_variable_get, o) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/class_variable_set_spec.rb b/spec/ruby/core/module/class_variable_set_spec.rb
index 63f32f5389..a3d759767b 100644
--- a/spec/ruby/core/module/class_variable_set_spec.rb
+++ b/spec/ruby/core/module/class_variable_set_spec.rb
@@ -28,10 +28,10 @@ describe "Module#class_variable_set" do
it "raises a FrozenError when self is frozen" do
-> {
Class.new.freeze.send(:class_variable_set, :@@test, "test")
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
-> {
Module.new.freeze.send(:class_variable_set, :@@test, "test")
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
it "raises a NameError when the given name is not allowed" do
@@ -39,10 +39,10 @@ describe "Module#class_variable_set" do
-> {
c.send(:class_variable_set, :invalid_name, "test")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
-> {
c.send(:class_variable_set, "@invalid_name", "test")
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "converts a non string/symbol name to string using to_str" do
@@ -55,8 +55,8 @@ describe "Module#class_variable_set" do
it "raises a TypeError when the given names can't be converted to strings using to_str" do
c = Class.new { class_variable_set :@@class_var, "test" }
o = mock('123')
- -> { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError)
+ -> { c.send(:class_variable_set, o, "test") }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError)
+ -> { c.send(:class_variable_set, o, "test") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/class_variables_spec.rb b/spec/ruby/core/module/class_variables_spec.rb
index e155f1deac..9529df48ae 100644
--- a/spec/ruby/core/module/class_variables_spec.rb
+++ b/spec/ruby/core/module/class_variables_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
describe "Module#class_variables" do
it "returns an Array with the names of class variables of self" do
- ModuleSpecs::ClassVars::A.class_variables.should include(:@@a_cvar)
- ModuleSpecs::ClassVars::M.class_variables.should include(:@@m_cvar)
+ ModuleSpecs::ClassVars::A.class_variables.should.include?(:@@a_cvar)
+ ModuleSpecs::ClassVars::M.class_variables.should.include?(:@@m_cvar)
end
it "returns an Array of Symbols of class variable names defined in a metaclass" do
@@ -15,13 +15,13 @@ describe "Module#class_variables" do
end
it "returns an Array with names of class variables defined in metaclasses" do
- ModuleSpecs::CVars.class_variables.should include(:@@cls, :@@meta)
+ ModuleSpecs::CVars.class_variables.to_set.should >= Set[:@@cls, :@@meta]
end
it "does not return class variables defined in extended modules" do
c = Class.new
c.extend ModuleSpecs::MVars
- c.class_variables.should_not include(:@@mvar)
+ c.class_variables.should_not.include?(:@@mvar)
end
it "returns the correct class variables when inherit is given" do
diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb
index 4b10dd5963..b60af7a2e8 100644
--- a/spec/ruby/core/module/const_added_spec.rb
+++ b/spec/ruby/core/module/const_added_spec.rb
@@ -3,201 +3,236 @@ require_relative 'fixtures/classes'
require_relative 'fixtures/const_added'
describe "Module#const_added" do
- ruby_version_is "3.2" do
- it "is a private instance method" do
- Module.should have_private_instance_method(:const_added)
+ it "is a private instance method" do
+ Module.private_instance_methods(false).should.include?(:const_added)
+ end
+
+ it "returns nil in the default implementation" do
+ Module.new do
+ const_added(:TEST).should == nil
end
+ end
+
+ it "for a class defined with the `class` keyword, const_added runs before inherited" do
+ ScratchPad.record []
- it "returns nil in the default implementation" do
- Module.new do
- const_added(:TEST).should == nil
+ mod = Module.new do
+ def self.const_added(_)
+ ScratchPad << :const_added
end
end
- it "is called when a new constant is assigned on self" do
- ScratchPad.record []
-
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ parent = Class.new do
+ def self.inherited(_)
+ ScratchPad << :inherited
end
+ end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 1
- RUBY
+ class mod::C < parent; end
- ScratchPad.recorded.should == [:TEST]
- end
+ ScratchPad.recorded.should == [:const_added, :inherited]
+ end
- it "is called when a new constant is assigned on self through const_set" do
- ScratchPad.record []
+ it "the superclass of a class assigned to a constant is set before const_added is called" do
+ ScratchPad.record []
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ parent = Class.new do
+ def self.const_added(name)
+ ScratchPad << name
+ ScratchPad << const_get(name).superclass
end
+ end
- mod.const_set(:TEST, 1)
+ class parent::C < parent; end
- ScratchPad.recorded.should == [:TEST]
- end
+ ScratchPad.recorded.should == [:C, parent]
+ end
- it "is called when a new module is defined under self" do
- ScratchPad.record []
+ it "is called when a new constant is assigned on self" do
+ ScratchPad.record []
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
end
+ end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- module SubModule
- end
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 1
+ RUBY
- module SubModule
- end
- RUBY
+ ScratchPad.recorded.should == [:TEST]
+ end
- ScratchPad.recorded.should == [:SubModule]
+ it "is called when a new constant is assigned on self through const_set" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
end
- it "is called when a new module is defined under a named module (assigned to a constant)" do
- ScratchPad.record []
+ mod.const_set(:TEST, 1)
- ModuleSpecs::ConstAddedSpecs::NamedModule = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ ScratchPad.recorded.should == [:TEST]
+ end
- module self::A
- def self.const_added(name)
- ScratchPad << name
- end
+ it "is called when a new module is defined under self" do
+ ScratchPad.record []
- module self::B
- end
- end
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
end
-
- ScratchPad.recorded.should == [:A, :B]
end
- it "is called when a new class is defined under self" do
- ScratchPad.record []
-
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ module SubModule
end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- class SubClass
- end
+ module SubModule
+ end
+ RUBY
- class SubClass
- end
- RUBY
+ ScratchPad.recorded.should == [:SubModule]
+ end
- ScratchPad.recorded.should == [:SubClass]
- end
+ it "is called when a new module is defined under a named module (assigned to a constant)" do
+ ScratchPad.record []
- it "is called when a new class is defined under a named module (assigned to a constant)" do
- ScratchPad.record []
+ ModuleSpecs::ConstAddedSpecs::NamedModule = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
- ModuleSpecs::ConstAddedSpecs::NamedModuleB = Module.new do
+ module self::A
def self.const_added(name)
ScratchPad << name
end
- class self::A
- def self.const_added(name)
- ScratchPad << name
- end
-
- class self::B
- end
+ module self::B
end
end
+ end
+
+ ScratchPad.recorded.should == [:A, :B]
+ ModuleSpecs::ConstAddedSpecs.send :remove_const, :NamedModule
+ end
- ScratchPad.recorded.should == [:A, :B]
+ it "is called when a new class is defined under self" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
end
- it "is called when an autoload is defined" do
- ScratchPad.record []
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ class SubClass
+ end
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ class SubClass
end
+ RUBY
- mod.autoload :Autoload, "foo"
- ScratchPad.recorded.should == [:Autoload]
- end
+ ScratchPad.recorded.should == [:SubClass]
+ end
+
+ it "is called when a new class is defined under a named module (assigned to a constant)" do
+ ScratchPad.record []
- it "is called with a precise caller location with the line of definition" do
- ScratchPad.record []
+ ModuleSpecs::ConstAddedSpecs::NamedModuleB = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
- mod = Module.new do
+ class self::A
def self.const_added(name)
- location = caller_locations(1, 1)[0]
- ScratchPad << location.lineno
+ ScratchPad << name
+ end
+
+ class self::B
end
end
+ end
- line = __LINE__
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 1
+ ScratchPad.recorded.should == [:A, :B]
+ ModuleSpecs::ConstAddedSpecs.send :remove_const, :NamedModuleB
+ end
- module SubModule
- end
+ it "is called when an autoload is defined" do
+ ScratchPad.record []
- class SubClass
- end
- RUBY
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
+ end
- mod.const_set(:CONST_SET, 1)
+ mod.autoload :Autoload, "foo"
+ ScratchPad.recorded.should == [:Autoload]
+ end
+
+ it "is called with a precise caller location with the line of definition" do
+ ScratchPad.record []
- ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11]
+ mod = Module.new do
+ def self.const_added(name)
+ location = caller_locations(1, 1)[0]
+ ScratchPad << location.lineno
+ end
end
- it "is called when the constant is already assigned a value" do
- ScratchPad.record []
+ line = __LINE__
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 1
- mod = Module.new do
- def self.const_added(name)
- ScratchPad.record const_get(name)
- end
+ module SubModule
end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 123
- RUBY
+ class SubClass
+ end
+ RUBY
- ScratchPad.recorded.should == 123
- end
+ mod.const_set(:CONST_SET, 1)
- it "records re-definition of existing constants" do
- ScratchPad.record []
+ ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11]
+ end
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << const_get(name)
- end
+ it "is called when the constant is already assigned a value" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad.record const_get(name)
end
+ end
+
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 123
+ RUBY
+
+ ScratchPad.recorded.should == 123
+ end
- -> {
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 123
- TEST = 456
- RUBY
- }.should complain(/warning: already initialized constant .+::TEST/)
+ it "records re-definition of existing constants" do
+ ScratchPad.record []
- ScratchPad.recorded.should == [123, 456]
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << const_get(name)
+ end
end
+
+ -> {
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 123
+ TEST = 456
+ RUBY
+ }.should complain(/warning: already initialized constant .+::TEST/)
+
+ ScratchPad.recorded.should == [123, 456]
end
end
diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb
index 8b137cd134..9d973c2b2b 100644
--- a/spec/ruby/core/module/const_defined_spec.rb
+++ b/spec/ruby/core/module/const_defined_spec.rb
@@ -14,40 +14,40 @@ describe "Module#const_defined?" do
it "returns true if the constant is defined in the receiver's superclass" do
# CS_CONST4 is defined in the superclass of ChildA
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should == true
end
it "returns true if the constant is defined in a mixed-in module of the receiver's parent" do
# CS_CONST10 is defined in a module included by ChildA
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should == true
end
it "returns true if the constant is defined in a mixed-in module (with prepends) of the receiver" do
# CS_CONST11 is defined in the module included by ContainerPrepend
- ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should be_true
+ ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should == true
end
it "returns true if the constant is defined in Object and the receiver is a module" do
# CS_CONST1 is defined in Object
- ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true
+ ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should == true
end
it "returns true if the constant is defined in Object and the receiver is a class that has Object among its ancestors" do
# CS_CONST1 is defined in Object
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST1).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST1).should == true
end
it "returns false if the constant is defined in the receiver's superclass and the inherit flag is false" do
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, false).should be_false
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, false).should == false
end
it "returns true if the constant is defined in the receiver's superclass and the inherit flag is true" do
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, true).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, true).should == true
end
it "coerces the inherit flag to a boolean" do
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, nil).should be_false
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, :true).should be_true
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, nil).should == false
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, :true).should == true
end
it "returns true if the given String names a constant defined in the receiver" do
@@ -58,23 +58,23 @@ describe "Module#const_defined?" do
end
it "returns true when passed a constant name with unicode characters" do
- ConstantUnicodeSpecs.const_defined?("CS_CONSTλ").should be_true
+ ConstantUnicodeSpecs.const_defined?("CS_CONSTλ").should == true
end
it "returns true when passed a constant name with EUC-JP characters" do
str = "CS_CONSTλ".encode("euc-jp")
ConstantSpecs.const_set str, 1
- ConstantSpecs.const_defined?(str).should be_true
+ ConstantSpecs.const_defined?(str).should == true
ensure
ConstantSpecs.send(:remove_const, str)
end
it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do
# The following constant isn't defined at all.
- ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4726).should be_false
+ ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4726).should == false
# DETACHED_CONSTANT is defined in ConstantSpecs::Detached, which isn't
# included by or inherited from ParentA
- ConstantSpecs::ParentA.const_defined?(:DETACHED_CONSTANT).should be_false
+ ConstantSpecs::ParentA.const_defined?(:DETACHED_CONSTANT).should == false
end
it "does not call #const_missing if the constant is not defined in the receiver" do
@@ -90,59 +90,59 @@ describe "Module#const_defined?" do
end
it "raises a TypeError if the given name can't be converted to a String" do
- -> { ConstantSpecs.const_defined?(nil) }.should raise_error(TypeError)
- -> { ConstantSpecs.const_defined?([]) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined?(nil) }.should.raise(TypeError)
+ -> { ConstantSpecs.const_defined?([]) }.should.raise(TypeError)
end
it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
name = mock("classA")
name.should_receive(:to_str).and_raise(NoMethodError)
- -> { ConstantSpecs.const_defined?(name) }.should raise_error(NoMethodError)
+ -> { ConstantSpecs.const_defined?(name) }.should.raise(NoMethodError)
end
end
it "special cases Object and checks it's included Modules" do
- Object.const_defined?(:CS_CONST10).should be_true
+ Object.const_defined?(:CS_CONST10).should == true
end
it "returns true for toplevel constant when the name begins with '::'" do
- ConstantSpecs.const_defined?("::Array").should be_true
+ ConstantSpecs.const_defined?("::Array").should == true
end
it "returns true when passed a scoped constant name" do
- ConstantSpecs.const_defined?("ClassC::CS_CONST1").should be_true
+ ConstantSpecs.const_defined?("ClassC::CS_CONST1").should == true
end
it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is default" do
- ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2").should be_true
+ ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2").should == true
end
it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is true" do
- ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", true).should be_true
+ ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", true).should == true
end
it "returns false when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is false" do
- ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", false).should be_false
+ ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", false).should == false
end
it "returns false when the name begins with '::' and the toplevel constant does not exist" do
- ConstantSpecs.const_defined?("::Name").should be_false
+ ConstantSpecs.const_defined?("::Name").should == false
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_defined? "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with '_'" do
- -> { ConstantSpecs.const_defined? "__CONSTX__" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "__CONSTX__" }.should.raise(NameError)
end
it "raises a NameError if the name starts with '@'" do
- -> { ConstantSpecs.const_defined? "@Name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "@Name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with '!'" do
- -> { ConstantSpecs.const_defined? "!Name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "!Name" }.should.raise(NameError)
end
it "returns true or false for the nested name" do
@@ -155,15 +155,15 @@ describe "Module#const_defined?" do
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
ConstantSpecs.const_defined?("CS_CONSTX").should == false
- -> { ConstantSpecs.const_defined? "Name=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_defined? "Name?" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_defined? "Name=" }.should.raise(NameError)
+ -> { ConstantSpecs.const_defined? "Name?" }.should.raise(NameError)
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined? name }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined? name }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb
index 4b53cbe7b3..68b5594faa 100644
--- a/spec/ruby/core/module/const_get_spec.rb
+++ b/spec/ruby/core/module/const_get_spec.rb
@@ -9,28 +9,28 @@ describe "Module#const_get" do
end
it "raises a NameError if no constant is defined in the search path" do
- -> { ConstantSpecs.const_get :CS_CONSTX }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get :CS_CONSTX }.should.raise(NameError)
end
it "raises a NameError with the not found constant symbol" do
error_inspection = -> e { e.name.should == :CS_CONSTX }
- -> { ConstantSpecs.const_get :CS_CONSTX }.should raise_error(NameError, &error_inspection)
+ -> { ConstantSpecs.const_get :CS_CONSTX }.should.raise(NameError, &error_inspection)
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_get "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_get "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.const_get "@CS_CONST1" }.should raise_error(NameError)
- -> { ConstantSpecs.const_get "!CS_CONST1" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get "__CONSTX__" }.should.raise(NameError)
+ -> { ConstantSpecs.const_get "@CS_CONST1" }.should.raise(NameError)
+ -> { ConstantSpecs.const_get "!CS_CONST1" }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
Object.const_get("CS_CONST1").should == :const1
- -> { ConstantSpecs.const_get "CS_CONST1=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_get "CS_CONST1?" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get "CS_CONST1=" }.should.raise(NameError)
+ -> { ConstantSpecs.const_get "CS_CONST1?" }.should.raise(NameError)
end
it "calls #to_str to convert the given name to a String" do
@@ -41,10 +41,10 @@ describe "Module#const_get" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_get(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_get(name) }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_get(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_get(name) }.should.raise(TypeError)
end
it "calls #const_missing on the receiver if unable to locate the constant" do
@@ -55,21 +55,21 @@ describe "Module#const_get" do
it "does not search the singleton class of a Class or Module" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST14)
- end.should raise_error(NameError)
- -> { ConstantSpecs.const_get(:CS_CONST14) }.should raise_error(NameError)
+ end.should.raise(NameError)
+ -> { ConstantSpecs.const_get(:CS_CONST14) }.should.raise(NameError)
end
it "does not search the containing scope" do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST20).should == :const20_2
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST5)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the constant is defined in the receiver's superclass and the inherit flag is false" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST4, false)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "searches into the receiver superclasses if the inherit flag is true" do
@@ -79,13 +79,13 @@ describe "Module#const_get" do
it "raises a NameError when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do
-> do
ConstantSpecs::ModuleA.const_get(:CS_CONST1, false)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST1, false)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "coerces the inherit flag to a boolean" do
@@ -93,7 +93,7 @@ describe "Module#const_get" do
-> do
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST1, nil)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "accepts a toplevel scope qualifier" do
@@ -102,7 +102,7 @@ describe "Module#const_get" do
it "accepts a toplevel scope qualifier when inherit is false" do
ConstantSpecs.const_get("::CS_CONST1", false).should == :const1
- -> { ConstantSpecs.const_get("CS_CONST1", false) }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get("CS_CONST1", false) }.should.raise(NameError)
end
it "returns a constant whose module is defined the toplevel" do
@@ -115,19 +115,19 @@ describe "Module#const_get" do
end
it "raises a NameError if the name includes two successive scope separators" do
- -> { ConstantSpecs.const_get("ClassA::::CS_CONST10") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get("ClassA::::CS_CONST10") }.should.raise(NameError)
end
it "raises a NameError if only '::' is passed" do
- -> { ConstantSpecs.const_get("::") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get("::") }.should.raise(NameError)
end
it "raises a NameError if a Symbol has a toplevel scope qualifier" do
- -> { ConstantSpecs.const_get(:'::CS_CONST1') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get(:'::CS_CONST1') }.should.raise(NameError)
end
it "raises a NameError if a Symbol is a scoped constant name" do
- -> { ConstantSpecs.const_get(:'ClassA::CS_CONST10') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_get(:'ClassA::CS_CONST10') }.should.raise(NameError)
end
it "does read private constants" do
@@ -151,7 +151,7 @@ describe "Module#const_get" do
end
it "raises a NameError when the nested constant does not exist on the module but exists in Object" do
- -> { Object.const_get('ConstantSpecs::CS_CONST1') }.should raise_error(NameError)
+ -> { Object.const_get('ConstantSpecs::CS_CONST1') }.should.raise(NameError)
end
describe "with statically assigned constants" do
diff --git a/spec/ruby/core/module/const_missing_spec.rb b/spec/ruby/core/module/const_missing_spec.rb
index 742218281c..80a2caccab 100644
--- a/spec/ruby/core/module/const_missing_spec.rb
+++ b/spec/ruby/core/module/const_missing_spec.rb
@@ -13,7 +13,7 @@ describe "Module#const_missing" do
it "raises NameError and includes the name of the value that wasn't found" do
-> {
ConstantSpecs.const_missing("HelloMissing")
- }.should raise_error(NameError, /ConstantSpecs::HelloMissing/)
+ }.should.raise(NameError, /ConstantSpecs::HelloMissing/)
end
it "raises NameError and does not include toplevel Object" do
diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb
index 823768b882..aa3c6bbcfc 100644
--- a/spec/ruby/core/module/const_set_spec.rb
+++ b/spec/ruby/core/module/const_set_spec.rb
@@ -50,20 +50,20 @@ describe "Module#const_set" do
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_set "name", 1 }.should raise_error(NameError)
+ -> { ConstantSpecs.const_set "name", 1 }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_set "__CONSTX__", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "@Name", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "!Name", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "::Name", 1 }.should raise_error(NameError)
+ -> { ConstantSpecs.const_set "__CONSTX__", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "@Name", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "!Name", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "::Name", 1 }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
ConstantSpecs.const_set("CS_CONST404", :const404).should == :const404
- -> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
- -> { ConstantSpecs.const_set "Name?", 1 }.should raise_error(NameError)
+ -> { ConstantSpecs.const_set "Name=", 1 }.should.raise(NameError)
+ -> { ConstantSpecs.const_set "Name?", 1 }.should.raise(NameError)
ensure
ConstantSpecs.send(:remove_const, :CS_CONST404)
end
@@ -79,10 +79,10 @@ describe "Module#const_set" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_set name, 1 }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_set name, 1 }.should.raise(TypeError)
end
describe "when overwriting an existing constant" do
@@ -110,7 +110,7 @@ describe "Module#const_set" do
mod = Module.new
mod.autoload :Foo, path
- -> { mod::Foo }.should raise_error(NameError)
+ -> { mod::Foo }.should.raise(NameError)
mod.const_defined?(:Foo).should == false
mod.autoload?(:Foo).should == nil
@@ -138,8 +138,8 @@ describe "Module#const_set" do
end
it "raises a FrozenError before setting the name" do
- -> { @frozen.const_set @name, nil }.should raise_error(FrozenError)
- @frozen.should_not have_constant(@name)
+ -> { @frozen.const_set @name, nil }.should.raise(FrozenError)
+ @frozen.should_not.const_defined?(@name)
end
end
end
diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb
index 06b3b215c2..e6cef727e2 100644
--- a/spec/ruby/core/module/const_source_location_spec.rb
+++ b/spec/ruby/core/module/const_source_location_spec.rb
@@ -142,19 +142,19 @@ describe "Module#const_source_location" do
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "__CONSTX__" }.should.raise(NameError)
+ -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should.raise(NameError)
+ -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
- -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should.raise(NameError)
+ -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should.raise(NameError)
end
it "calls #to_str to convert the given name to a String" do
@@ -165,10 +165,10 @@ describe "Module#const_source_location" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_source_location(name) }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_source_location(name) }.should.raise(TypeError)
end
it "does not search the singleton class of a Class or Module" do
@@ -213,19 +213,19 @@ describe "Module#const_source_location" do
end
it "raises a NameError if the name includes two successive scope separators" do
- -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should.raise(NameError)
end
it "raises a NameError if only '::' is passed" do
- -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location("::") }.should.raise(NameError)
end
it "raises a NameError if a Symbol has a toplevel scope qualifier" do
- -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should.raise(NameError)
end
it "raises a NameError if a Symbol is a scoped constant name" do
- -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should.raise(NameError)
end
it "does search private constants path" do
@@ -245,6 +245,14 @@ describe "Module#const_source_location" do
@line = __LINE__ - 1
end
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ end
+
it 'returns the autoload location while not resolved' do
ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line]
end
@@ -265,6 +273,8 @@ describe "Module#const_source_location" do
ConstantSpecs.const_source_location(:ConstSource).should == autoload_location
ConstantSpecs::ConstSource::LOCATION.should == ConstantSpecs.const_source_location(:ConstSource)
ConstantSpecs::BEFORE_DEFINE_LOCATION.should == autoload_location
+ ConstantSpecs.send :remove_const, :ConstSource
+ ConstantSpecs.send :remove_const, :BEFORE_DEFINE_LOCATION
end
end
end
diff --git a/spec/ruby/core/module/constants_spec.rb b/spec/ruby/core/module/constants_spec.rb
index 330da1cc88..f2f12761e3 100644
--- a/spec/ruby/core/module/constants_spec.rb
+++ b/spec/ruby/core/module/constants_spec.rb
@@ -13,12 +13,13 @@ describe "Module.constants" do
it "returns an array of Symbol names" do
# This in NOT an exhaustive list
- Module.constants.should include(:Array, :Class, :Comparable, :Dir,
+ Module.constants.to_set.should >= Set[
+ :Array, :Class, :Comparable, :Dir,
:Enumerable, :ENV, :Exception, :FalseClass,
:File, :Float, :Hash, :Integer, :IO,
:Kernel, :Math, :Method, :Module, :NilClass,
:Numeric, :Object, :Range, :Regexp, :String,
- :Symbol, :Thread, :Time, :TrueClass)
+ :Symbol, :Thread, :Time, :TrueClass]
end
it "returns Module's constants when given a parameter" do
@@ -92,6 +93,6 @@ describe "Module#constants" do
end
it "includes names of constants defined after a module is included" do
- ConstantSpecs::ContainerA.constants.should include(:CS_CONST251)
+ ConstantSpecs::ContainerA.constants.should.include?(:CS_CONST251)
end
end
diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb
index c5dfc53764..f838e2b85f 100644
--- a/spec/ruby/core/module/define_method_spec.rb
+++ b/spec/ruby/core/module/define_method_spec.rb
@@ -12,7 +12,7 @@ describe "passed { |a, b = 1| } creates a method that" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "has a default value for b when passed one argument" do
@@ -24,7 +24,7 @@ describe "passed { |a, b = 1| } creates a method that" do
end
it "raises an ArgumentError when passed three arguments" do
- -> { @klass.new.m(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { @klass.new.m(1, 2, 3) }.should.raise(ArgumentError)
end
end
@@ -47,7 +47,7 @@ describe "Module#define_method when given an UnboundMethod" do
end
define_method(:another_test_method, instance_method(:test_method))
end
- klass.new.should have_method(:another_test_method)
+ klass.new.should.respond_to?(:another_test_method)
end
describe "defining a method on a singleton class" do
@@ -83,7 +83,7 @@ describe "Module#define_method when given an UnboundMethod" do
define_method :piggy, instance_method(:ziggy)
end
- -> { foo.new.ziggy }.should raise_error(NoMethodError)
+ -> { foo.new.ziggy }.should.raise(NoMethodError)
foo.new.piggy.should == 'piggy'
end
end
@@ -115,8 +115,8 @@ describe "Module#define_method when name is not a special private name" do
define_method(:baz, ModuleSpecs::EmptyFooMethod)
end
- klass.should have_public_instance_method(:bar)
- klass.should have_private_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.private_instance_methods(false).should.include?(:baz)
end
end
@@ -129,8 +129,8 @@ describe "Module#define_method when name is not a special private name" do
klass.send(:define_method, :baz, ModuleSpecs::EmptyFooMethod)
end
- klass.should have_public_instance_method(:bar)
- klass.should have_public_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.public_instance_methods(false).should.include?(:baz)
end
end
@@ -155,8 +155,8 @@ describe "Module#define_method when name is not a special private name" do
define_method(:baz) {}
end
- klass.should have_public_instance_method(:bar)
- klass.should have_private_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.private_instance_methods(false).should.include?(:baz)
end
end
@@ -169,8 +169,8 @@ describe "Module#define_method when name is not a special private name" do
klass.send(:define_method, :baz) {}
end
- klass.should have_public_instance_method(:bar)
- klass.should have_public_instance_method(:baz)
+ klass.public_instance_methods(false).should.include?(:bar)
+ klass.public_instance_methods(false).should.include?(:baz)
end
end
end
@@ -182,7 +182,7 @@ describe "Module#define_method when name is :initialize" do
klass = Class.new do
define_method(:initialize) { }
end
- klass.should have_private_instance_method(:initialize)
+ klass.private_instance_methods(false).should.include?(:initialize)
end
end
@@ -193,7 +193,7 @@ describe "Module#define_method when name is :initialize" do
end
define_method(:initialize, instance_method(:test_method))
end
- klass.should have_private_instance_method(:initialize)
+ klass.private_instance_methods(false).should.include?(:initialize)
end
end
end
@@ -233,11 +233,11 @@ describe "Module#define_method" do
it "raises TypeError if name cannot converted to String" do
-> {
Class.new { define_method(1001, -> {}) }
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+ }.should.raise(TypeError, /is not a symbol nor a string/)
-> {
Class.new { define_method([], -> {}) }
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+ }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "converts non-String name to String with #to_str" do
@@ -254,21 +254,21 @@ describe "Module#define_method" do
-> {
Class.new { define_method(obj, -> {}) }
- }.should raise_error(TypeError, /can't convert Object to String/)
+ }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "raises a TypeError when the given method is no Method/Proc" do
-> {
Class.new { define_method(:test, "self") }
- }.should raise_error(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)")
+ }.should.raise(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)")
-> {
Class.new { define_method(:test, 1234) }
- }.should raise_error(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)")
+ }.should.raise(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)")
-> {
Class.new { define_method(:test, nil) }
- }.should raise_error(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)")
+ }.should.raise(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)")
end
it "uses provided Method/Proc even if block is specified" do
@@ -284,7 +284,7 @@ describe "Module#define_method" do
it "raises an ArgumentError when no block is given" do
-> {
Class.new { define_method(:test) }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not use the caller block when no block is given" do
@@ -297,7 +297,7 @@ describe "Module#define_method" do
-> {
o.define(:foo) { raise "not used" }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not change the arity check style of the original proc" do
@@ -307,13 +307,13 @@ describe "Module#define_method" do
end
obj = DefineMethodSpecClass.new
- -> { obj.proc_style_test :arg }.should raise_error(ArgumentError)
+ -> { obj.proc_style_test :arg }.should.raise(ArgumentError)
end
it "raises a FrozenError if frozen" do
-> {
Class.new { freeze; define_method(:foo) {} }
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
end
it "accepts a Method (still bound)" do
@@ -326,13 +326,13 @@ describe "Module#define_method" do
o = DefineMethodSpecClass.new
o.data = :foo
m = o.method(:inspect_data)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
klass = Class.new(DefineMethodSpecClass)
klass.send(:define_method,:other_inspect, m)
c = klass.new
c.data = :bar
c.other_inspect.should == "data is bar"
- ->{o.other_inspect}.should raise_error(NoMethodError)
+ ->{o.other_inspect}.should.raise(NoMethodError)
end
it "raises a TypeError when a Method from a singleton class is defined on another class" do
@@ -346,7 +346,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method :bar, m }
- }.should raise_error(TypeError, /can't bind singleton method to a different class/)
+ }.should.raise(TypeError, /can't bind singleton method to a different class/)
end
it "raises a TypeError when a Method from one class is defined on an unrelated class" do
@@ -358,7 +358,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method :bar, m }
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "accepts an UnboundMethod from an attr_accessor method" do
@@ -370,7 +370,7 @@ describe "Module#define_method" do
o = DefineMethodSpecClass.new
DefineMethodSpecClass.send(:undef_method, :accessor_method)
- -> { o.accessor_method }.should raise_error(NoMethodError)
+ -> { o.accessor_method }.should.raise(NoMethodError)
DefineMethodSpecClass.send(:define_method, :accessor_method, m)
@@ -415,7 +415,7 @@ describe "Module#define_method" do
end
o = DefineMethodByProcClass.new
- o.proc_test.should be_true
+ o.proc_test.should == true
end
it "accepts a String method name" do
@@ -429,7 +429,7 @@ describe "Module#define_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:define_method)
+ Module.public_instance_methods(false).should.include?(:define_method)
end
it "returns its symbol" do
@@ -443,7 +443,7 @@ describe "Module#define_method" do
klass = Class.new {
define_method :bar, ModuleSpecs::UnboundMethodTest.instance_method(:foo)
}
- klass.new.should respond_to(:bar)
+ klass.new.should.respond_to?(:bar)
end
it "allows an UnboundMethod from a parent class to be defined on a child class" do
@@ -451,7 +451,7 @@ describe "Module#define_method" do
child = Class.new(parent) {
define_method :baz, parent.instance_method(:foo)
}
- child.new.should respond_to(:baz)
+ child.new.should.respond_to?(:baz)
end
it "allows an UnboundMethod from a module to be defined on another unrelated module" do
@@ -459,7 +459,7 @@ describe "Module#define_method" do
define_method :bar, ModuleSpecs::UnboundMethodTest.instance_method(:foo)
}
klass = Class.new { include mod }
- klass.new.should respond_to(:bar)
+ klass.new.should.respond_to?(:bar)
end
@@ -475,7 +475,7 @@ describe "Module#define_method" do
ParentClass = Class.new { define_method(:foo) { :bar } }
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
- }.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/)
+ }.should.raise(TypeError, /bind argument must be a subclass of ChildClass/)
ensure
Object.send(:remove_const, :ParentClass)
Object.send(:remove_const, :ChildClass)
@@ -486,7 +486,7 @@ describe "Module#define_method" do
DestinationClass = Class.new {
define_method :bar, ModuleSpecs::InstanceMeth.instance_method(:foo)
}
- }.should raise_error(TypeError, /bind argument must be a subclass of ModuleSpecs::InstanceMeth/)
+ }.should.raise(TypeError, /bind argument must be a subclass of ModuleSpecs::InstanceMeth/)
end
it "raises a TypeError when an UnboundMethod from a singleton class is defined on another class" do
@@ -500,7 +500,7 @@ describe "Module#define_method" do
-> {
Class.new { define_method :bar, m }
- }.should raise_error(TypeError, /can't bind singleton method to a different class/)
+ }.should.raise(TypeError, /can't bind singleton method to a different class/)
end
it "defines a new method with public visibility when a Method passed and the class/module of the context isn't equal to the receiver of #define_method" do
@@ -527,7 +527,7 @@ describe "Module#define_method" do
define_method(:bar, c.new.method(:foo))
end
- -> { object.bar }.should raise_error(NoMethodError)
+ -> { object.bar }.should.raise(NoMethodError)
end
end
@@ -544,11 +544,11 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
end
@@ -564,11 +564,11 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
end
@@ -580,15 +580,15 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed zero arguments and a block" do
- -> { @klass.new.m { :computed } }.should raise_error(ArgumentError)
+ -> { @klass.new.m { :computed } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
it "receives the value passed as the argument when passed one argument" do
@@ -604,15 +604,15 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed zero arguments and a block" do
- -> { @klass.new.m { :computed } }.should raise_error(ArgumentError)
+ -> { @klass.new.m { :computed } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
- -> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2 }.should.raise(ArgumentError)
end
it "receives the value passed as the argument when passed one argument" do
@@ -654,7 +654,7 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "returns the value computed by the block when passed one argument" do
@@ -682,19 +682,19 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument and a block" do
- -> { @klass.new.m(1) { } }.should raise_error(ArgumentError)
+ -> { @klass.new.m(1) { } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed three arguments" do
- -> { @klass.new.m 1, 2, 3 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1, 2, 3 }.should.raise(ArgumentError)
end
end
@@ -706,15 +706,15 @@ describe "Module#define_method" do
end
it "raises an ArgumentError when passed zero arguments" do
- -> { @klass.new.m }.should raise_error(ArgumentError)
+ -> { @klass.new.m }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument" do
- -> { @klass.new.m 1 }.should raise_error(ArgumentError)
+ -> { @klass.new.m 1 }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed one argument and a block" do
- -> { @klass.new.m(1) { } }.should raise_error(ArgumentError)
+ -> { @klass.new.m(1) { } }.should.raise(ArgumentError)
end
it "receives an empty array as the third argument when passed two arguments" do
@@ -795,7 +795,7 @@ describe "Module#define_method when passed a Proc object" do
o = c.new
o.test
- o.should_not have_method :nested_method_in_proc_for_define_method
+ o.should_not.respond_to? :nested_method_in_proc_for_define_method
t.new.nested_method_in_proc_for_define_method.should == 42
end
diff --git a/spec/ruby/core/module/deprecate_constant_spec.rb b/spec/ruby/core/module/deprecate_constant_spec.rb
index ec0de6782f..597379eb87 100644
--- a/spec/ruby/core/module/deprecate_constant_spec.rb
+++ b/spec/ruby/core/module/deprecate_constant_spec.rb
@@ -19,9 +19,9 @@ describe "Module#deprecate_constant" do
-> {
value = @module::PUBLIC1
}.should complain(/warning: constant .+::PUBLIC1 is deprecated/)
- value.should equal(@value)
+ value.should.equal?(@value)
- -> { @module::PRIVATE }.should raise_error(NameError)
+ -> { @module::PRIVATE }.should.raise(NameError)
end
it "warns with a message" do
@@ -61,10 +61,10 @@ describe "Module#deprecate_constant" do
end
it "returns self" do
- @module.deprecate_constant(:PUBLIC1).should equal(@module)
+ @module.deprecate_constant(:PUBLIC1).should.equal?(@module)
end
it "raises a NameError when given an undefined name" do
- -> { @module.deprecate_constant :UNDEFINED }.should raise_error(NameError)
+ -> { @module.deprecate_constant :UNDEFINED }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/extend_object_spec.rb b/spec/ruby/core/module/extend_object_spec.rb
index 1fd1abc0b5..b428eb7924 100644
--- a/spec/ruby/core/module/extend_object_spec.rb
+++ b/spec/ruby/core/module/extend_object_spec.rb
@@ -7,18 +7,18 @@ describe "Module#extend_object" do
end
it "is a private method" do
- Module.should have_private_instance_method(:extend_object)
+ Module.private_instance_methods(false).should.include?(:extend_object)
end
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:extend_object, true)
+ Class.private_instance_methods(true).should_not.include?(:extend_object)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:extend_object).bind(Class.new).call Object.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -49,8 +49,8 @@ describe "Module#extend_object" do
end
it "raises a RuntimeError before extending the object" do
- -> { @receiver.send(:extend_object, @object) }.should raise_error(RuntimeError)
- @object.should_not be_kind_of(@receiver)
+ -> { @receiver.send(:extend_object, @object) }.should.raise(RuntimeError)
+ @object.should_not.is_a?(@receiver)
end
end
end
diff --git a/spec/ruby/core/module/extended_spec.rb b/spec/ruby/core/module/extended_spec.rb
index c6300ffa0b..a4ec5a4ba7 100644
--- a/spec/ruby/core/module/extended_spec.rb
+++ b/spec/ruby/core/module/extended_spec.rb
@@ -39,6 +39,6 @@ describe "Module#extended" do
end
it "is private in its default implementation" do
- Module.new.private_methods.should include(:extended)
+ Module.new.private_methods.should.include?(:extended)
end
end
diff --git a/spec/ruby/core/module/fixtures/autoload_relative_a.rb b/spec/ruby/core/module/fixtures/autoload_relative_a.rb
new file mode 100644
index 0000000000..494181adc2
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/autoload_relative_a.rb
@@ -0,0 +1,9 @@
+module ModuleSpecs
+ module Autoload
+ class AutoloadRelativeA
+ end
+
+ class AutoloadRelativeB
+ end
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index a434e7b0b8..964f64c593 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -1,6 +1,6 @@
module ModuleSpecs
def self.without_test_modules(modules)
- ignore = %w[MSpecRSpecAdapter PP::ObjectMixin ModuleSpecs::IncludedInObject MainSpecs::Module ConstantSpecs::ModuleA]
+ ignore = %w[MSpecRSpecAdapter PP::ObjectMixin MainSpecs::Module ConstantSpecs::ModuleA]
modules.reject { |k| ignore.include?(k.name) }
end
diff --git a/spec/ruby/core/module/gt_spec.rb b/spec/ruby/core/module/gt_spec.rb
index b8a73c9ff9..04cdd90efb 100644
--- a/spec/ruby/core/module/gt_spec.rb
+++ b/spec/ruby/core/module/gt_spec.rb
@@ -3,10 +3,10 @@ require_relative 'fixtures/classes'
describe "Module#>" do
it "returns false if self is a subclass of or includes the given module" do
- (ModuleSpecs::Child > ModuleSpecs::Parent).should be_false
- (ModuleSpecs::Child > ModuleSpecs::Basic).should be_false
- (ModuleSpecs::Child > ModuleSpecs::Super).should be_false
- (ModuleSpecs::Super > ModuleSpecs::Basic).should be_false
+ (ModuleSpecs::Child > ModuleSpecs::Parent).should == false
+ (ModuleSpecs::Child > ModuleSpecs::Basic).should == false
+ (ModuleSpecs::Child > ModuleSpecs::Super).should == false
+ (ModuleSpecs::Super > ModuleSpecs::Basic).should == false
end
it "returns true if self is a superclass of or included by the given module" do
@@ -31,6 +31,6 @@ describe "Module#>" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent > mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent > mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/gte_spec.rb b/spec/ruby/core/module/gte_spec.rb
index 18c60ba586..b19fc9fac3 100644
--- a/spec/ruby/core/module/gte_spec.rb
+++ b/spec/ruby/core/module/gte_spec.rb
@@ -28,6 +28,6 @@ describe "Module#>=" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent >= mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent >= mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb
index a1bfd3a6f5..b6201550e4 100644
--- a/spec/ruby/core/module/include_spec.rb
+++ b/spec/ruby/core/module/include_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#include" do
it "is a public method" do
- Module.should have_public_instance_method(:include, false)
+ Module.public_instance_methods(false).should.include?(:include)
end
it "calls #append_features(self) in reversed order on each module" do
@@ -33,56 +33,40 @@ describe "Module#include" do
end
it "adds all ancestor modules when a previously included module is included again" do
- ModuleSpecs::MultipleIncludes.ancestors.should include(ModuleSpecs::MA, ModuleSpecs::MB)
+ ModuleSpecs::MultipleIncludes.ancestors.to_set.should >= Set[ModuleSpecs::MA, ModuleSpecs::MB]
ModuleSpecs::MB.include(ModuleSpecs::MC)
ModuleSpecs::MultipleIncludes.include(ModuleSpecs::MB)
- ModuleSpecs::MultipleIncludes.ancestors.should include(ModuleSpecs::MA, ModuleSpecs::MB, ModuleSpecs::MC)
+ ModuleSpecs::MultipleIncludes.ancestors.to_set.should >= Set[ModuleSpecs::MA, ModuleSpecs::MB, ModuleSpecs::MC]
end
it "raises a TypeError when the argument is not a Module" do
- -> { ModuleSpecs::Basic.include(Class.new) }.should raise_error(TypeError)
+ -> { ModuleSpecs::Basic.include(Class.new) }.should.raise(TypeError)
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
class ModuleSpecs::SubclassSpec::AClass
end
- -> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
+ -> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not.raise(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
- ruby_version_is ""..."3.2" do
- it "raises ArgumentError when the argument is a refinement" do
- refinement = nil
+ it "raises a TypeError when the argument is a refinement" do
+ refinement = nil
- Module.new do
- refine String do
- refinement = self
- end
+ Module.new do
+ refine String do
+ refinement = self
end
-
- -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed")
end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError when the argument is a refinement" do
- refinement = nil
- Module.new do
- refine String do
- refinement = self
- end
- end
-
- -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement")
- end
+ -> { ModuleSpecs::Basic.include(refinement) }.should.raise(TypeError, "Cannot include refinement")
end
it "imports constants to modules and classes" do
- ModuleSpecs::A.constants.should include(:CONSTANT_A)
- ModuleSpecs::B.constants.should include(:CONSTANT_A, :CONSTANT_B)
- ModuleSpecs::C.constants.should include(:CONSTANT_A, :CONSTANT_B)
+ ModuleSpecs::A.constants.should.include?(:CONSTANT_A)
+ ModuleSpecs::B.constants.to_set.should >= Set[:CONSTANT_A, :CONSTANT_B]
+ ModuleSpecs::C.constants.to_set.should >= Set[:CONSTANT_A, :CONSTANT_B]
end
it "shadows constants from ancestors" do
@@ -100,9 +84,9 @@ describe "Module#include" do
end
it "imports instance methods to modules and classes" do
- ModuleSpecs::A.instance_methods.should include(:ma)
- ModuleSpecs::B.instance_methods.should include(:ma,:mb)
- ModuleSpecs::C.instance_methods.should include(:ma,:mb)
+ ModuleSpecs::A.instance_methods.should.include?(:ma)
+ ModuleSpecs::B.instance_methods.to_set.should >= Set[:ma,:mb]
+ ModuleSpecs::C.instance_methods.to_set.should >= Set[:ma,:mb]
end
it "does not import methods to modules and classes" do
@@ -162,7 +146,7 @@ describe "Module#include" do
anc = B.ancestors
[B, U, V, W, A, X].each do |i|
- anc.include?(i).should be_true
+ anc.include?(i).should == true
end
class B; include V; end
@@ -170,7 +154,7 @@ describe "Module#include" do
# the only new module is Y, it is added after U since it follows U in V mixin list:
anc = B.ancestors
[B, U, Y, V, W, A, X].each do |i|
- anc.include?(i).should be_true
+ anc.include?(i).should == true
end
end
end
@@ -194,7 +178,7 @@ describe "Module#include" do
module ModuleSpecs::M
include ModuleSpecs::M
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "doesn't accept no-arguments" do
@@ -202,7 +186,7 @@ describe "Module#include" do
Module.new do
include
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns the class it's included into" do
@@ -638,7 +622,7 @@ describe "Module#include?" do
end
it "raises a TypeError when no module was given" do
- -> { ModuleSpecs::Child.include?("Test") }.should raise_error(TypeError)
- -> { ModuleSpecs::Child.include?(ModuleSpecs::Parent) }.should raise_error(TypeError)
+ -> { ModuleSpecs::Child.include?("Test") }.should.raise(TypeError)
+ -> { ModuleSpecs::Child.include?(ModuleSpecs::Parent) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/included_modules_spec.rb b/spec/ruby/core/module/included_modules_spec.rb
index ce94ed1285..e22ee5e6cf 100644
--- a/spec/ruby/core/module/included_modules_spec.rb
+++ b/spec/ruby/core/module/included_modules_spec.rb
@@ -5,10 +5,10 @@ describe "Module#included_modules" do
it "returns a list of modules included in self" do
ModuleSpecs.included_modules.should == []
- ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel)
- ModuleSpecs::Parent.included_modules.should include(Kernel)
+ ModuleSpecs::Child.included_modules.to_set.should >= Set[ModuleSpecs::Super, ModuleSpecs::Basic, Kernel]
+ ModuleSpecs::Parent.included_modules.should.include?(Kernel)
ModuleSpecs::Basic.included_modules.should == []
- ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic)
- ModuleSpecs::WithPrependedModule.included_modules.should include(ModuleSpecs::ModuleWithPrepend)
+ ModuleSpecs::Super.included_modules.should.include?(ModuleSpecs::Basic)
+ ModuleSpecs::WithPrependedModule.included_modules.should.include?(ModuleSpecs::ModuleWithPrepend)
end
end
diff --git a/spec/ruby/core/module/included_spec.rb b/spec/ruby/core/module/included_spec.rb
index 2fdd4325f2..d8a6c3f839 100644
--- a/spec/ruby/core/module/included_spec.rb
+++ b/spec/ruby/core/module/included_spec.rb
@@ -34,7 +34,7 @@ describe "Module#included" do
end
it "is private in its default implementation" do
- Module.should have_private_instance_method(:included)
+ Module.private_instance_methods(false).should.include?(:included)
end
it "works with super using a singleton class" do
diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb
index 8d006e647e..8615e352f6 100644
--- a/spec/ruby/core/module/instance_method_spec.rb
+++ b/spec/ruby/core/module/instance_method_spec.rb
@@ -9,7 +9,7 @@ describe "Module#instance_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:instance_method, false)
+ Module.public_instance_methods(false).should.include?(:instance_method)
end
it "requires an argument" do
@@ -17,26 +17,26 @@ describe "Module#instance_method" do
end
it "returns an UnboundMethod corresponding to the given name" do
- @parent_um.should be_kind_of(UnboundMethod)
+ @parent_um.should.is_a?(UnboundMethod)
@parent_um.bind(ModuleSpecs::InstanceMeth.new).call.should == :foo
end
it "returns an UnboundMethod corresponding to the given name from a superclass" do
- @child_um.should be_kind_of(UnboundMethod)
+ @child_um.should.is_a?(UnboundMethod)
@child_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :foo
end
it "returns an UnboundMethod corresponding to the given name from an included Module" do
- @mod_um.should be_kind_of(UnboundMethod)
+ @mod_um.should.is_a?(UnboundMethod)
@mod_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :bar
end
it "returns an UnboundMethod when given a protected method name" do
- ModuleSpecs::Basic.instance_method(:protected_module).should be_an_instance_of(UnboundMethod)
+ ModuleSpecs::Basic.instance_method(:protected_module).should.instance_of?(UnboundMethod)
end
it "returns an UnboundMethod when given a private method name" do
- ModuleSpecs::Basic.instance_method(:private_module).should be_an_instance_of(UnboundMethod)
+ ModuleSpecs::Basic.instance_method(:private_module).should.instance_of?(UnboundMethod)
end
it "gives UnboundMethod method name, Module defined in and Module extracted from" do
@@ -48,28 +48,23 @@ describe "Module#instance_method" do
@mod_um.inspect.should =~ /\bbar\b/
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/
-
- ruby_version_is ""..."3.2" do
- @child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
- @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
- end
end
it "raises a TypeError if the given name is not a String/Symbol" do
- -> { Object.instance_method([]) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { Object.instance_method(0) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { Object.instance_method(nil) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { Object.instance_method(mock('x')) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method([]) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(0) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(nil) }.should.raise(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(mock('x')) }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "accepts String name argument" do
method = ModuleSpecs::InstanceMeth.instance_method(:foo)
- method.should be_kind_of(UnboundMethod)
+ method.should.is_a?(UnboundMethod)
end
it "accepts Symbol name argument" do
method = ModuleSpecs::InstanceMeth.instance_method("foo")
- method.should be_kind_of(UnboundMethod)
+ method.should.is_a?(UnboundMethod)
end
it "converts non-String name by calling #to_str method" do
@@ -77,14 +72,14 @@ describe "Module#instance_method" do
def obj.to_str() "foo" end
method = ModuleSpecs::InstanceMeth.instance_method(obj)
- method.should be_kind_of(UnboundMethod)
+ method.should.is_a?(UnboundMethod)
end
it "raises TypeError when passed non-String name and #to_str returns non-String value" do
obj = Object.new
def obj.to_str() [] end
- -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
it "raises a NameError if the method has been undefined" do
@@ -94,11 +89,11 @@ describe "Module#instance_method" do
um.should == @parent_um
-> do
child.instance_method(:foo)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method does not exist" do
- -> { Object.instance_method(:missing) }.should raise_error(NameError)
+ -> { Object.instance_method(:missing) }.should.raise(NameError)
end
it "sets the NameError#name attribute to the name of the missing method" do
diff --git a/spec/ruby/core/module/instance_methods_spec.rb b/spec/ruby/core/module/instance_methods_spec.rb
index d2d38cdda2..dbb6df8c34 100644
--- a/spec/ruby/core/module/instance_methods_spec.rb
+++ b/spec/ruby/core/module/instance_methods_spec.rb
@@ -4,21 +4,22 @@ require_relative 'fixtures/classes'
describe "Module#instance_methods" do
it "does not return methods undefined in a superclass" do
methods = ModuleSpecs::Parent.instance_methods(false)
- methods.should_not include(:undefed_method)
+ methods.should_not.include?(:undefed_method)
end
it "only includes module methods on an included module" do
methods = ModuleSpecs::Basic.instance_methods(false)
- methods.should include(:public_module)
+ methods.should.include?(:public_module)
# Child is an including class
methods = ModuleSpecs::Child.instance_methods(false)
- methods.should include(:public_child)
- methods.should_not include(:public_module)
+ methods.should.include?(:public_child)
+ methods.should_not.include?(:public_module)
end
it "does not return methods undefined in a subclass" do
methods = ModuleSpecs::Grandchild.instance_methods
- methods.should_not include(:parent_method, :another_parent_method)
+ methods.should_not.include?(:parent_method)
+ methods.should_not.include?(:another_parent_method)
end
it "does not return methods undefined in the current class" do
@@ -28,34 +29,35 @@ describe "Module#instance_methods" do
end
ModuleSpecs::Child.send(:undef_method, :undefed_child)
methods = ModuleSpecs::Child.instance_methods
- methods.should_not include(:undefed_method, :undefed_child)
+ methods.should_not.include?(:undefed_method)
+ methods.should_not.include?(:undefed_child)
end
it "does not return methods from an included module that are undefined in the class" do
- ModuleSpecs::Grandchild.instance_methods.should_not include(:super_included_method)
+ ModuleSpecs::Grandchild.instance_methods.should_not.include?(:super_included_method)
end
it "returns the public and protected methods of self if include_super is false" do
methods = ModuleSpecs::Parent.instance_methods(false)
- methods.should include(:protected_parent, :public_parent)
+ methods.to_set.should >= Set[:protected_parent, :public_parent]
methods = ModuleSpecs::Child.instance_methods(false)
- methods.should include(:protected_child, :public_child)
+ methods.to_set.should >= Set[:protected_child, :public_child]
end
it "returns the public and protected methods of self and it's ancestors" do
methods = ModuleSpecs::Basic.instance_methods
- methods.should include(:protected_module, :public_module)
+ methods.to_set.should >= Set[:protected_module, :public_module]
methods = ModuleSpecs::Super.instance_methods
- methods.should include(:protected_module, :protected_super_module,
- :public_module, :public_super_module)
+ methods.to_set.should >= Set[:protected_module, :protected_super_module,
+ :public_module, :public_super_module]
end
it "makes a private Object instance method public in Kernel" do
methods = Kernel.instance_methods
- methods.should include(:module_specs_private_method_on_object_for_kernel_public)
+ methods.should.include?(:module_specs_private_method_on_object_for_kernel_public)
methods = Object.instance_methods
- methods.should_not include(:module_specs_private_method_on_object_for_kernel_public)
+ methods.should_not.include?(:module_specs_private_method_on_object_for_kernel_public)
end
end
diff --git a/spec/ruby/core/module/lt_spec.rb b/spec/ruby/core/module/lt_spec.rb
index d7771e07a8..8567a24993 100644
--- a/spec/ruby/core/module/lt_spec.rb
+++ b/spec/ruby/core/module/lt_spec.rb
@@ -10,10 +10,10 @@ describe "Module#<" do
end
it "returns false if self is a superclass of or included by the given module" do
- (ModuleSpecs::Parent < ModuleSpecs::Child).should be_false
- (ModuleSpecs::Basic < ModuleSpecs::Child).should be_false
- (ModuleSpecs::Super < ModuleSpecs::Child).should be_false
- (ModuleSpecs::Basic < ModuleSpecs::Super).should be_false
+ (ModuleSpecs::Parent < ModuleSpecs::Child).should == false
+ (ModuleSpecs::Basic < ModuleSpecs::Child).should == false
+ (ModuleSpecs::Super < ModuleSpecs::Child).should == false
+ (ModuleSpecs::Basic < ModuleSpecs::Super).should == false
end
it "returns false if self is the same as the given module" do
@@ -31,6 +31,6 @@ describe "Module#<" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent < mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent < mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/lte_spec.rb b/spec/ruby/core/module/lte_spec.rb
index 7a0e8496b8..c6aab94e9f 100644
--- a/spec/ruby/core/module/lte_spec.rb
+++ b/spec/ruby/core/module/lte_spec.rb
@@ -28,6 +28,6 @@ describe "Module#<=" do
end
it "raises a TypeError if the argument is not a class/module" do
- -> { ModuleSpecs::Parent <= mock('x') }.should raise_error(TypeError)
+ -> { ModuleSpecs::Parent <= mock('x') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/module/method_added_spec.rb b/spec/ruby/core/module/method_added_spec.rb
index ec92cddc1e..996a14eb86 100644
--- a/spec/ruby/core/module/method_added_spec.rb
+++ b/spec/ruby/core/module/method_added_spec.rb
@@ -7,7 +7,7 @@ describe "Module#method_added" do
end
it "is a private instance method" do
- Module.should have_private_instance_method(:method_added)
+ Module.private_instance_methods(false).should.include?(:method_added)
end
it "returns nil in the default implementation" do
@@ -57,7 +57,7 @@ describe "Module#method_added" do
undef_method :method_to_undef
end
- m.should_not have_method(:method_to_undef)
+ m.should_not.respond_to?(:method_to_undef)
end
it "is not called when a method changes visibility" do
diff --git a/spec/ruby/core/module/method_defined_spec.rb b/spec/ruby/core/module/method_defined_spec.rb
index bc5b420e11..e6b4c7b817 100644
--- a/spec/ruby/core/module/method_defined_spec.rb
+++ b/spec/ruby/core/module/method_defined_spec.rb
@@ -27,17 +27,17 @@ describe "Module#method_defined?" do
it "does not search Object or Kernel when called on a module" do
m = Module.new
- m.method_defined?(:module_specs_public_method_on_kernel).should be_false
+ m.method_defined?(:module_specs_public_method_on_kernel).should == false
end
it "raises a TypeError when the given object is not a string/symbol" do
c = Class.new
o = mock('123')
- -> { c.method_defined?(o) }.should raise_error(TypeError)
+ -> { c.method_defined?(o) }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { c.method_defined?(o) }.should raise_error(TypeError)
+ -> { c.method_defined?(o) }.should.raise(TypeError)
end
it "converts the given name to a string using to_str" do
diff --git a/spec/ruby/core/module/method_removed_spec.rb b/spec/ruby/core/module/method_removed_spec.rb
index 9b39eb77a6..80e546406c 100644
--- a/spec/ruby/core/module/method_removed_spec.rb
+++ b/spec/ruby/core/module/method_removed_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#method_removed" do
it "is a private instance method" do
- Module.should have_private_instance_method(:method_removed)
+ Module.private_instance_methods(false).should.include?(:method_removed)
end
it "returns nil in the default implementation" do
diff --git a/spec/ruby/core/module/method_undefined_spec.rb b/spec/ruby/core/module/method_undefined_spec.rb
index a94388fe0a..596c5c50e2 100644
--- a/spec/ruby/core/module/method_undefined_spec.rb
+++ b/spec/ruby/core/module/method_undefined_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#method_undefined" do
it "is a private instance method" do
- Module.should have_private_instance_method(:method_undefined)
+ Module.private_instance_methods(false).should.include?(:method_undefined)
end
it "returns nil in the default implementation" do
diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb
index 51f647142e..41bd152608 100644
--- a/spec/ruby/core/module/module_function_spec.rb
+++ b/spec/ruby/core/module/module_function_spec.rb
@@ -3,22 +3,22 @@ require_relative 'fixtures/classes'
describe "Module#module_function" do
it "is a private method" do
- Module.should have_private_instance_method(:module_function)
+ Module.private_instance_methods(false).should.include?(:module_function)
end
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:module_function, true)
+ Class.private_instance_methods(true).should_not.include?(:module_function)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:module_function).bind(Class.new).call
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Module.instance_method(:module_function).bind(Class.new).call :foo
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
@@ -41,7 +41,7 @@ describe "Module#module_function with specific method names" do
it "returns argument or arguments if given" do
Module.new do
def foo; end
- module_function(:foo).should equal(:foo)
+ module_function(:foo).should.equal?(:foo)
module_function(:foo, :foo).should == [:foo, :foo]
end
end
@@ -83,9 +83,9 @@ describe "Module#module_function with specific method names" do
(o = mock('x')).extend(m)
o.respond_to?(:test).should == false
- m.should have_private_instance_method(:test)
+ m.private_instance_methods(false).should.include?(:test)
o.send(:test).should == "hello"
- -> { o.test }.should raise_error(NoMethodError)
+ -> { o.test }.should.raise(NoMethodError)
end
it "makes the new Module methods public" do
@@ -114,17 +114,17 @@ describe "Module#module_function with specific method names" do
it "raises a TypeError when the given names can't be converted to string using to_str" do
o = mock('123')
- -> { Module.new { module_function(o) } }.should raise_error(TypeError)
+ -> { Module.new { module_function(o) } }.should.raise(TypeError)
o.should_receive(:to_str).and_return(123)
- -> { Module.new { module_function(o) } }.should raise_error(TypeError)
+ -> { Module.new { module_function(o) } }.should.raise(TypeError)
end
it "can make accessible private methods" do # JRUBY-4214
m = Module.new do
module_function :require
end
- m.respond_to?(:require).should be_true
+ m.respond_to?(:require).should == true
end
it "creates Module methods that super up the singleton class of the module" do
@@ -207,7 +207,7 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "returns nil" do
Module.new do
- module_function.should equal(nil)
+ module_function.should.equal?(nil)
end
end
diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb
index b5c1f771f8..332c08d782 100644
--- a/spec/ruby/core/module/name_spec.rb
+++ b/spec/ruby/core/module/name_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/module'
describe "Module#name" do
it "is nil for an anonymous module" do
- Module.new.name.should be_nil
+ Module.new.name.should == nil
end
it "is not nil when assigned to a constant in an anonymous module" do
@@ -19,9 +19,9 @@ describe "Module#name" do
end
it "returns nil for a singleton class" do
- Module.new.singleton_class.name.should be_nil
- String.singleton_class.name.should be_nil
- Object.new.singleton_class.name.should be_nil
+ Module.new.singleton_class.name.should == nil
+ String.singleton_class.name.should == nil
+ Object.new.singleton_class.name.should == nil
end
it "changes when the module is reachable through a constant path" do
@@ -148,50 +148,49 @@ describe "Module#name" do
"ModuleSpecs::Anonymous::StoredInMultiplePlaces::N",
"ModuleSpecs::Anonymous::StoredInMultiplePlaces::O"
]
- valid_names.should include(m::N.name) # You get one of the two, but you don't know which one.
+ valid_names.should.include?(m::N.name) # You get one of the two, but you don't know which one.
ensure
ModuleSpecs::Anonymous.send(:remove_const, :StoredInMultiplePlaces)
end
- ruby_version_is "3.2" do
- it "is set in #const_added callback when a module defined in the top-level scope" do
- ruby_exe(<<~RUBY, args: "2>&1").chomp.should == "TEST1\nTEST2"
- class Module
- def const_added(name)
- puts const_get(name).name
- end
+ it "is set in #const_added callback when a module defined in the top-level scope" do
+ ruby_exe(<<~RUBY, args: "2>&1").chomp.should == "TEST1\nTEST2"
+ class Module
+ def const_added(name)
+ puts const_get(name).name
end
+ end
- # module with name
- module TEST1
- end
+ # module with name
+ module TEST1
+ end
- # anonymous module
- TEST2 = Module.new
- RUBY
- end
+ # anonymous module
+ TEST2 = Module.new
+ RUBY
+ end
- it "is set in #const_added callback for a nested module when an outer module defined in the top-level scope" do
- ScratchPad.record []
+ it "is set in #const_added callback for a nested module when an outer module defined in the top-level scope" do
+ ScratchPad.record []
- ModuleSpecs::NameSpecs::NamedModule = Module.new do
+ ModuleSpecs::NameSpecs::NamedModule = Module.new do
+ def self.const_added(name)
+ ScratchPad << const_get(name).name
+ end
+
+ module self::A
def self.const_added(name)
ScratchPad << const_get(name).name
end
- module self::A
- def self.const_added(name)
- ScratchPad << const_get(name).name
- end
-
- module self::B
- end
+ module self::B
end
end
-
- ScratchPad.recorded.should.one?(/#<Module.+>::A$/)
- ScratchPad.recorded.should.one?(/#<Module.+>::A::B$/)
end
+
+ ScratchPad.recorded.should.one?(/#<Module.+>::A$/)
+ ScratchPad.recorded.should.one?(/#<Module.+>::A::B$/)
+ ModuleSpecs::NameSpecs.send :remove_const, :NamedModule
end
it "returns a frozen String" do
@@ -201,6 +200,6 @@ describe "Module#name" do
it "always returns the same String for a given Module" do
s1 = ModuleSpecs.name
s2 = ModuleSpecs.name
- s1.should equal(s2)
+ s1.should.equal?(s2)
end
end
diff --git a/spec/ruby/core/module/new_spec.rb b/spec/ruby/core/module/new_spec.rb
index ec521360bd..ec7a0cfa77 100644
--- a/spec/ruby/core/module/new_spec.rb
+++ b/spec/ruby/core/module/new_spec.rb
@@ -7,7 +7,7 @@ describe "Module.new" do
end
it "creates a module without a name" do
- Module.new.name.should be_nil
+ Module.new.name.should == nil
end
it "creates a new Module and passes it to the provided block" do
diff --git a/spec/ruby/core/module/prepend_features_spec.rb b/spec/ruby/core/module/prepend_features_spec.rb
index 09c15c5c15..3a50f2c2a4 100644
--- a/spec/ruby/core/module/prepend_features_spec.rb
+++ b/spec/ruby/core/module/prepend_features_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#prepend_features" do
it "is a private method" do
- Module.should have_private_instance_method(:prepend_features, true)
+ Module.private_instance_methods(false).should.include?(:prepend_features)
end
it "gets called when self is included in another module/class" do
@@ -25,7 +25,7 @@ describe "Module#prepend_features" do
it "raises an ArgumentError on a cyclic prepend" do
-> {
ModuleSpecs::CyclicPrepend.send(:prepend_features, ModuleSpecs::CyclicPrepend)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "clears caches of the given module" do
@@ -52,13 +52,13 @@ describe "Module#prepend_features" do
describe "on Class" do
it "is undefined" do
- Class.should_not have_private_instance_method(:prepend_features, true)
+ Class.private_instance_methods(true).should_not.include?(:prepend_features)
end
it "raises a TypeError if calling after rebinded to Class" do
-> {
Module.instance_method(:prepend_features).bind(Class.new).call Module.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index 9508fbf182..f7887e6d6a 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#prepend" do
it "is a public method" do
- Module.should have_public_instance_method(:prepend, false)
+ Module.public_instance_methods(false).should.include?(:prepend)
end
it "does not affect the superclass" do
@@ -444,58 +444,42 @@ describe "Module#prepend" do
end
it "raises a TypeError when the argument is not a Module" do
- -> { ModuleSpecs::Basic.prepend(Class.new) }.should raise_error(TypeError)
+ -> { ModuleSpecs::Basic.prepend(Class.new) }.should.raise(TypeError)
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" do
class ModuleSpecs::SubclassSpec::AClass
end
- -> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
+ -> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not.raise(TypeError)
ensure
ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
- ruby_version_is ""..."3.2" do
- it "raises ArgumentError when the argument is a refinement" do
- refinement = nil
+ it "raises a TypeError when the argument is a refinement" do
+ refinement = nil
- Module.new do
- refine String do
- refinement = self
- end
+ Module.new do
+ refine String do
+ refinement = self
end
-
- -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed")
end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError when the argument is a refinement" do
- refinement = nil
- Module.new do
- refine String do
- refinement = self
- end
- end
-
- -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement")
- end
+ -> { ModuleSpecs::Basic.prepend(refinement) }.should.raise(TypeError, "Cannot prepend refinement")
end
it "imports constants" do
m1 = Module.new
m1::MY_CONSTANT = 1
m2 = Module.new { prepend(m1) }
- m2.constants.should include(:MY_CONSTANT)
+ m2.constants.should.include?(:MY_CONSTANT)
end
it "imports instance methods" do
- Module.new { prepend ModuleSpecs::A }.instance_methods.should include(:ma)
+ Module.new { prepend ModuleSpecs::A }.instance_methods.should.include?(:ma)
end
it "does not import methods to modules and classes" do
- Module.new { prepend ModuleSpecs::A }.methods.should_not include(:ma)
+ Module.new { prepend ModuleSpecs::A }.methods.should_not.include?(:ma)
end
it "allows wrapping methods" do
@@ -521,7 +505,7 @@ describe "Module#prepend" do
it "includes prepended modules in ancestors" do
m = Module.new
- Class.new { prepend(m) }.ancestors.should include(m)
+ Class.new { prepend(m) }.ancestors.should.include?(m)
end
it "reports the prepended module as the method owner" do
@@ -558,13 +542,13 @@ describe "Module#prepend" do
it "sees an instance of a prepended class as kind of the prepended module" do
m = Module.new
c = Class.new { prepend(m) }
- c.new.should be_kind_of(m)
+ c.new.should.is_a?(m)
end
it "keeps the module in the chain when dupping the class" do
m = Module.new
c = Class.new { prepend(m) }
- c.dup.new.should be_kind_of(m)
+ c.dup.new.should.is_a?(m)
end
it "uses only new module when dupping the module" do
@@ -575,14 +559,14 @@ describe "Module#prepend" do
m2dup.ancestors.should == [m1,m2dup]
c2 = Class.new { prepend(m2dup) }
c1.ancestors[0,3].should == [m1,m2,c1]
- c1.new.should be_kind_of(m1)
+ c1.new.should.is_a?(m1)
c2.ancestors[0,3].should == [m1,m2dup,c2]
- c2.new.should be_kind_of(m1)
+ c2.new.should.is_a?(m1)
end
it "depends on prepend_features to add the module" do
m = Module.new { def self.prepend_features(mod) end }
- Class.new { prepend(m) }.ancestors.should_not include(m)
+ Class.new { prepend(m) }.ancestors.should_not.include?(m)
end
it "adds the module in the subclass chains" do
@@ -643,7 +627,7 @@ describe "Module#prepend" do
super << :class
end
end
- -> { c.new.chain }.should raise_error(NoMethodError)
+ -> { c.new.chain }.should.raise(NoMethodError)
end
it "calls prepended after prepend_features" do
@@ -679,7 +663,7 @@ describe "Module#prepend" do
module ModuleSpecs::P
prepend ModuleSpecs::P
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "doesn't accept no-arguments" do
@@ -687,7 +671,7 @@ describe "Module#prepend" do
Module.new do
prepend
end
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns the class it's included into" do
@@ -833,7 +817,7 @@ describe "Module#prepend" do
pre = Module.new
mod.prepend pre
- cls.instance_methods.should include(:foo)
+ cls.instance_methods.should.include?(:foo)
end
end
end
diff --git a/spec/ruby/core/module/prepended_spec.rb b/spec/ruby/core/module/prepended_spec.rb
index bd95d8fd05..ccd450d668 100644
--- a/spec/ruby/core/module/prepended_spec.rb
+++ b/spec/ruby/core/module/prepended_spec.rb
@@ -8,7 +8,7 @@ describe "Module#prepended" do
end
it "is a private method" do
- Module.should have_private_instance_method(:prepended, true)
+ Module.private_instance_methods(false).should.include?(:prepended)
end
it "is invoked when self is prepended to another module or class" do
diff --git a/spec/ruby/core/module/private_class_method_spec.rb b/spec/ruby/core/module/private_class_method_spec.rb
index f899c71a57..7ce07f1600 100644
--- a/spec/ruby/core/module/private_class_method_spec.rb
+++ b/spec/ruby/core/module/private_class_method_spec.rb
@@ -22,11 +22,11 @@ describe "Module#private_class_method" do
it "makes an existing class method private" do
ModuleSpecs::Parent.private_method_1.should == nil
ModuleSpecs::Parent.private_class_method :private_method_1
- -> { ModuleSpecs::Parent.private_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.private_method_1 }.should.raise(NoMethodError)
# Technically above we're testing the Singleton classes, class method(right?).
# Try a "real" class method set private.
- -> { ModuleSpecs::Parent.private_method }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.private_method }.should.raise(NoMethodError)
end
it "makes an existing class method private up the inheritance tree" do
@@ -34,8 +34,8 @@ describe "Module#private_class_method" do
ModuleSpecs::Child.private_method_1.should == nil
ModuleSpecs::Child.private_class_method :private_method_1
- -> { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError)
- -> { ModuleSpecs::Child.private_method }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Child.private_method_1 }.should.raise(NoMethodError)
+ -> { ModuleSpecs::Child.private_method }.should.raise(NoMethodError)
end
it "accepts more than one method at a time" do
@@ -44,14 +44,14 @@ describe "Module#private_class_method" do
ModuleSpecs::Child.private_class_method :private_method_1, :private_method_2
- -> { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError)
- -> { ModuleSpecs::Child.private_method_2 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Child.private_method_1 }.should.raise(NoMethodError)
+ -> { ModuleSpecs::Child.private_method_2 }.should.raise(NoMethodError)
end
it "raises a NameError if class method doesn't exist" do
-> do
ModuleSpecs.private_class_method :no_method_here
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "makes a class method private" do
@@ -59,7 +59,7 @@ describe "Module#private_class_method" do
def self.foo() "foo" end
private_class_method :foo
end
- -> { c.foo }.should raise_error(NoMethodError)
+ -> { c.foo }.should.raise(NoMethodError)
end
it "raises a NameError when the given name is not a method" do
@@ -67,7 +67,7 @@ describe "Module#private_class_method" do
Class.new do
private_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when the given name is an instance method" do
@@ -76,7 +76,7 @@ describe "Module#private_class_method" do
def foo() "foo" end
private_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
context "when single argument is passed and is an array" do
@@ -85,7 +85,7 @@ describe "Module#private_class_method" do
def self.foo() "foo" end
private_class_method [:foo]
end
- -> { c.foo }.should raise_error(NoMethodError)
+ -> { c.foo }.should.raise(NoMethodError)
end
end
end
diff --git a/spec/ruby/core/module/private_constant_spec.rb b/spec/ruby/core/module/private_constant_spec.rb
index 3a91b3c3cd..ca0df48c0b 100644
--- a/spec/ruby/core/module/private_constant_spec.rb
+++ b/spec/ruby/core/module/private_constant_spec.rb
@@ -8,7 +8,7 @@ describe "Module#private_constant" do
-> do
cls2.send :private_constant, :Foo
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "accepts strings as constant names" do
@@ -16,7 +16,7 @@ describe "Module#private_constant" do
cls.const_set :Foo, true
cls.send :private_constant, "Foo"
- -> { cls::Foo }.should raise_error(NameError)
+ -> { cls::Foo }.should.raise(NameError)
end
it "accepts multiple names" do
@@ -26,7 +26,7 @@ describe "Module#private_constant" do
mod.send :private_constant, :Foo, :Bar
- -> {mod::Foo}.should raise_error(NameError)
- -> {mod::Bar}.should raise_error(NameError)
+ -> {mod::Foo}.should.raise(NameError)
+ -> {mod::Bar}.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/private_instance_methods_spec.rb b/spec/ruby/core/module/private_instance_methods_spec.rb
index cce0f001bf..ae0f21d1dd 100644
--- a/spec/ruby/core/module/private_instance_methods_spec.rb
+++ b/spec/ruby/core/module/private_instance_methods_spec.rb
@@ -5,20 +5,20 @@ require_relative '../../fixtures/reflection'
# TODO: rewrite
describe "Module#private_instance_methods" do
it "returns a list of private methods in module and its ancestors" do
- ModuleSpecs::CountsMixin.should have_private_instance_method(:private_3)
+ ModuleSpecs::CountsMixin.private_instance_methods(false).should.include?(:private_3)
- ModuleSpecs::CountsParent.should have_private_instance_method(:private_2)
- ModuleSpecs::CountsParent.should have_private_instance_method(:private_3)
+ ModuleSpecs::CountsParent.private_instance_methods(false).should.include?(:private_2)
+ ModuleSpecs::CountsParent.private_instance_methods(true).should.include?(:private_3)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_1)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_2)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_3)
+ ModuleSpecs::CountsChild.private_instance_methods(false).should.include?(:private_1)
+ ModuleSpecs::CountsChild.private_instance_methods(true).should.include?(:private_2)
+ ModuleSpecs::CountsChild.private_instance_methods(true).should.include?(:private_3)
end
it "when passed false as a parameter, should return only methods defined in that module" do
- ModuleSpecs::CountsMixin.should have_private_instance_method(:private_3, false)
- ModuleSpecs::CountsParent.should have_private_instance_method(:private_2, false)
- ModuleSpecs::CountsChild.should have_private_instance_method(:private_1, false)
+ ModuleSpecs::CountsMixin.private_instance_methods(false).should.include?(:private_3)
+ ModuleSpecs::CountsParent.private_instance_methods(false).should.include?(:private_2)
+ ModuleSpecs::CountsChild.private_instance_methods(false).should.include?(:private_1)
end
it "default list should be the same as passing true as an argument" do
diff --git a/spec/ruby/core/module/private_method_defined_spec.rb b/spec/ruby/core/module/private_method_defined_spec.rb
index 01fc8f8fb9..f730decc0a 100644
--- a/spec/ruby/core/module/private_method_defined_spec.rb
+++ b/spec/ruby/core/module/private_method_defined_spec.rb
@@ -34,25 +34,25 @@ describe "Module#private_method_defined?" do
it "raises a TypeError if passed an Integer" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(nil)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not defined #to_str" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(mock('x'))
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that defines #to_sym" do
@@ -61,7 +61,7 @@ describe "Module#private_method_defined?" do
-> do
ModuleSpecs::CountsMixin.private_method_defined?(sym)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "calls #to_str to convert an Object" do
diff --git a/spec/ruby/core/module/private_spec.rb b/spec/ruby/core/module/private_spec.rb
index 9e1a297eea..e60fdb24cc 100644
--- a/spec/ruby/core/module/private_spec.rb
+++ b/spec/ruby/core/module/private_spec.rb
@@ -17,7 +17,7 @@ describe "Module#private" do
private :foo
end
- -> { obj.foo }.should raise_error(NoMethodError)
+ -> { obj.foo }.should.raise(NoMethodError)
end
it "makes a public Object instance method private in a new module" do
@@ -25,33 +25,33 @@ describe "Module#private" do
private :module_specs_public_method_on_object
end
- m.should have_private_instance_method(:module_specs_public_method_on_object)
+ m.private_instance_methods(false).should.include?(:module_specs_public_method_on_object)
# Ensure we did not change Object's method
- Object.should_not have_private_instance_method(:module_specs_public_method_on_object)
+ Object.private_instance_methods(true).should_not.include?(:module_specs_public_method_on_object)
end
it "makes a public Object instance method private in Kernel" do
- Kernel.should have_private_instance_method(
+ Kernel.private_instance_methods(false).should.include?(
:module_specs_public_method_on_object_for_kernel_private)
- Object.should_not have_private_instance_method(
+ Object.private_instance_methods(true).should_not.include?(
:module_specs_public_method_on_object_for_kernel_private)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
- private(:foo).should equal(:foo)
+ private(:foo).should.equal?(:foo)
private([:foo, :foo]).should == [:foo, :foo]
private(:foo, :foo).should == [:foo, :foo]
- private.should equal(nil)
+ private.should.equal?(nil)
end
end
it "raises a NameError when given an undefined name" do
-> do
Module.new.send(:private, :undefined)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "only makes the method private in the class it is called on" do
@@ -71,7 +71,7 @@ describe "Module#private" do
base.new.wrapped.should == 1
-> do
klass.new.wrapped
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "continues to allow a prepended module method to call super" do
diff --git a/spec/ruby/core/module/protected_instance_methods_spec.rb b/spec/ruby/core/module/protected_instance_methods_spec.rb
index 78ce7e788f..ea7ded030e 100644
--- a/spec/ruby/core/module/protected_instance_methods_spec.rb
+++ b/spec/ruby/core/module/protected_instance_methods_spec.rb
@@ -6,16 +6,16 @@ require_relative '../../fixtures/reflection'
describe "Module#protected_instance_methods" do
it "returns a list of protected methods in module and its ancestors" do
methods = ModuleSpecs::CountsMixin.protected_instance_methods
- methods.should include(:protected_3)
+ methods.should.include?(:protected_3)
methods = ModuleSpecs::CountsParent.protected_instance_methods
- methods.should include(:protected_3)
- methods.should include(:protected_2)
+ methods.should.include?(:protected_3)
+ methods.should.include?(:protected_2)
methods = ModuleSpecs::CountsChild.protected_instance_methods
- methods.should include(:protected_3)
- methods.should include(:protected_2)
- methods.should include(:protected_1)
+ methods.should.include?(:protected_3)
+ methods.should.include?(:protected_2)
+ methods.should.include?(:protected_1)
end
it "when passed false as a parameter, should return only methods defined in that module" do
diff --git a/spec/ruby/core/module/protected_method_defined_spec.rb b/spec/ruby/core/module/protected_method_defined_spec.rb
index 31e24a16c1..78ba120c2f 100644
--- a/spec/ruby/core/module/protected_method_defined_spec.rb
+++ b/spec/ruby/core/module/protected_method_defined_spec.rb
@@ -34,25 +34,25 @@ describe "Module#protected_method_defined?" do
it "raises a TypeError if passed an Integer" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(nil)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not defined #to_str" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(mock('x'))
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that defines #to_sym" do
@@ -61,7 +61,7 @@ describe "Module#protected_method_defined?" do
-> do
ModuleSpecs::CountsMixin.protected_method_defined?(sym)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "calls #to_str to convert an Object" do
diff --git a/spec/ruby/core/module/protected_spec.rb b/spec/ruby/core/module/protected_spec.rb
index 9e37223e18..3ef6c76fae 100644
--- a/spec/ruby/core/module/protected_spec.rb
+++ b/spec/ruby/core/module/protected_spec.rb
@@ -18,7 +18,7 @@ describe "Module#protected" do
protected :protected_method_1
end
- -> { ModuleSpecs::Parent.protected_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.protected_method_1 }.should.raise(NoMethodError)
end
it "makes a public Object instance method protected in a new module" do
@@ -26,32 +26,32 @@ describe "Module#protected" do
protected :module_specs_public_method_on_object
end
- m.should have_protected_instance_method(:module_specs_public_method_on_object)
+ m.protected_instance_methods(false).should.include?(:module_specs_public_method_on_object)
# Ensure we did not change Object's method
- Object.should_not have_protected_instance_method(:module_specs_public_method_on_object)
+ Object.protected_instance_methods(true).should_not.include?(:module_specs_public_method_on_object)
end
it "makes a public Object instance method protected in Kernel" do
- Kernel.should have_protected_instance_method(
+ Kernel.protected_instance_methods(false).should.include?(
:module_specs_public_method_on_object_for_kernel_protected)
- Object.should_not have_protected_instance_method(
+ Object.protected_instance_methods(true).should_not.include?(
:module_specs_public_method_on_object_for_kernel_protected)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
- protected(:foo).should equal(:foo)
+ protected(:foo).should.equal?(:foo)
protected([:foo, :foo]).should == [:foo, :foo]
protected(:foo, :foo).should == [:foo, :foo]
- protected.should equal(nil)
+ protected.should.equal?(nil)
end
end
it "raises a NameError when given an undefined name" do
-> do
Module.new.send(:protected, :undefined)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/public_class_method_spec.rb b/spec/ruby/core/module/public_class_method_spec.rb
index 71b20acda5..4aca4d4311 100644
--- a/spec/ruby/core/module/public_class_method_spec.rb
+++ b/spec/ruby/core/module/public_class_method_spec.rb
@@ -18,7 +18,7 @@ describe "Module#public_class_method" do
end
it "makes an existing class method public" do
- -> { ModuleSpecs::Parent.public_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Parent.public_method_1 }.should.raise(NoMethodError)
ModuleSpecs::Parent.public_class_method :public_method_1
ModuleSpecs::Parent.public_method_1.should == nil
@@ -29,7 +29,7 @@ describe "Module#public_class_method" do
it "makes an existing class method public up the inheritance tree" do
ModuleSpecs::Child.private_class_method :public_method_1
- -> { ModuleSpecs::Child.public_method_1 }.should raise_error(NoMethodError)
+ -> { ModuleSpecs::Child.public_method_1 }.should.raise(NoMethodError)
ModuleSpecs::Child.public_class_method :public_method_1
ModuleSpecs::Child.public_method_1.should == nil
@@ -37,8 +37,8 @@ describe "Module#public_class_method" do
end
it "accepts more than one method at a time" do
- -> { ModuleSpecs::Parent.public_method_1 }.should raise_error(NameError)
- -> { ModuleSpecs::Parent.public_method_2 }.should raise_error(NameError)
+ -> { ModuleSpecs::Parent.public_method_1 }.should.raise(NameError)
+ -> { ModuleSpecs::Parent.public_method_2 }.should.raise(NameError)
ModuleSpecs::Child.public_class_method :public_method_1, :public_method_2
@@ -49,7 +49,7 @@ describe "Module#public_class_method" do
it "raises a NameError if class method doesn't exist" do
-> do
ModuleSpecs.public_class_method :no_method_here
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "makes a class method public" do
@@ -66,7 +66,7 @@ describe "Module#public_class_method" do
Class.new do
public_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError when the given name is an instance method" do
@@ -75,7 +75,7 @@ describe "Module#public_class_method" do
def foo() "foo" end
public_class_method :foo
end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
context "when single argument is passed and is an array" do
diff --git a/spec/ruby/core/module/public_constant_spec.rb b/spec/ruby/core/module/public_constant_spec.rb
index e624d45fd2..87a051f125 100644
--- a/spec/ruby/core/module/public_constant_spec.rb
+++ b/spec/ruby/core/module/public_constant_spec.rb
@@ -8,7 +8,7 @@ describe "Module#public_constant" do
-> do
cls2.send :public_constant, :Foo
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "accepts strings as constant names" do
diff --git a/spec/ruby/core/module/public_instance_method_spec.rb b/spec/ruby/core/module/public_instance_method_spec.rb
index ba19ad0404..87c1bae599 100644
--- a/spec/ruby/core/module/public_instance_method_spec.rb
+++ b/spec/ruby/core/module/public_instance_method_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Module#public_instance_method" do
it "is a public method" do
- Module.should have_public_instance_method(:public_instance_method, false)
+ Module.public_instance_methods(false).should.include?(:public_instance_method)
end
it "requires an argument" do
@@ -13,12 +13,12 @@ describe "Module#public_instance_method" do
describe "when given a public method name" do
it "returns an UnboundMethod corresponding to the defined Module" do
ret = ModuleSpecs::Super.public_instance_method(:public_module)
- ret.should be_an_instance_of(UnboundMethod)
- ret.owner.should equal(ModuleSpecs::Basic)
+ ret.should.instance_of?(UnboundMethod)
+ ret.owner.should.equal?(ModuleSpecs::Basic)
ret = ModuleSpecs::Super.public_instance_method(:public_super_module)
- ret.should be_an_instance_of(UnboundMethod)
- ret.owner.should equal(ModuleSpecs::Super)
+ ret.should.instance_of?(UnboundMethod)
+ ret.owner.should.equal?(ModuleSpecs::Super)
end
it "accepts if the name is a Symbol or String" do
@@ -28,31 +28,31 @@ describe "Module#public_instance_method" do
end
it "raises a TypeError when given a name is not Symbol or String" do
- -> { Module.new.public_instance_method(nil) }.should raise_error(TypeError)
+ -> { Module.new.public_instance_method(nil) }.should.raise(TypeError)
end
it "raises a NameError when given a protected method name" do
-> do
ModuleSpecs::Basic.public_instance_method(:protected_module)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method is private" do
-> do
ModuleSpecs::Basic.public_instance_method(:private_module)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method has been undefined" do
-> do
ModuleSpecs::Parent.public_instance_method(:undefed_method)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "raises a NameError if the method does not exist" do
-> do
Module.new.public_instance_method(:missing)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "sets the NameError#name attribute to the name of the missing method" do
diff --git a/spec/ruby/core/module/public_instance_methods_spec.rb b/spec/ruby/core/module/public_instance_methods_spec.rb
index ae7d9b5ffb..edea00d927 100644
--- a/spec/ruby/core/module/public_instance_methods_spec.rb
+++ b/spec/ruby/core/module/public_instance_methods_spec.rb
@@ -7,19 +7,19 @@ require_relative '../../fixtures/reflection'
describe "Module#public_instance_methods" do
it "returns a list of public methods in module and its ancestors" do
methods = ModuleSpecs::CountsMixin.public_instance_methods
- methods.should include(:public_3)
+ methods.should.include?(:public_3)
methods = ModuleSpecs::CountsParent.public_instance_methods
- methods.should include(:public_3)
- methods.should include(:public_2)
+ methods.should.include?(:public_3)
+ methods.should.include?(:public_2)
methods = ModuleSpecs::CountsChild.public_instance_methods
- methods.should include(:public_3)
- methods.should include(:public_2)
- methods.should include(:public_1)
+ methods.should.include?(:public_3)
+ methods.should.include?(:public_2)
+ methods.should.include?(:public_1)
methods = ModuleSpecs::Child2.public_instance_methods
- methods.should include(:foo)
+ methods.should.include?(:foo)
end
it "when passed false as a parameter, should return only methods defined in that module" do
diff --git a/spec/ruby/core/module/public_method_defined_spec.rb b/spec/ruby/core/module/public_method_defined_spec.rb
index 5c9bdf1ccc..70cd992358 100644
--- a/spec/ruby/core/module/public_method_defined_spec.rb
+++ b/spec/ruby/core/module/public_method_defined_spec.rb
@@ -34,25 +34,25 @@ describe "Module#public_method_defined?" do
it "raises a TypeError if passed an Integer" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(1)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(nil)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed false" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(false)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that does not defined #to_str" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(mock('x'))
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if passed an object that defines #to_sym" do
@@ -61,7 +61,7 @@ describe "Module#public_method_defined?" do
-> do
ModuleSpecs::CountsMixin.public_method_defined?(sym)
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "calls #to_str to convert an Object" do
diff --git a/spec/ruby/core/module/public_spec.rb b/spec/ruby/core/module/public_spec.rb
index ce31eb5d0e..f35c64143b 100644
--- a/spec/ruby/core/module/public_spec.rb
+++ b/spec/ruby/core/module/public_spec.rb
@@ -14,32 +14,32 @@ describe "Module#public" do
public :module_specs_private_method_on_object
end
- m.should have_public_instance_method(:module_specs_private_method_on_object)
+ m.public_instance_methods(false).should.include?(:module_specs_private_method_on_object)
# Ensure we did not change Object's method
- Object.should_not have_public_instance_method(:module_specs_private_method_on_object)
+ Object.public_instance_methods(true).should_not.include?(:module_specs_private_method_on_object)
end
it "makes a private Object instance method public in Kernel" do
- Kernel.should have_public_instance_method(
+ Kernel.public_instance_methods(false).should.include?(
:module_specs_private_method_on_object_for_kernel_public)
- Object.should_not have_public_instance_method(
+ Object.public_instance_methods(true).should_not.include?(
:module_specs_private_method_on_object_for_kernel_public)
end
it "returns argument or arguments if given" do
(class << Object.new; self; end).class_eval do
def foo; end
- public(:foo).should equal(:foo)
+ public(:foo).should.equal?(:foo)
public([:foo, :foo]).should == [:foo, :foo]
public(:foo, :foo).should == [:foo, :foo]
- public.should equal(nil)
+ public.should.equal?(nil)
end
end
it "raises a NameError when given an undefined name" do
-> do
Module.new.send(:public, :undefined)
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index 7a5d607c4f..d0fc7015f8 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -11,7 +11,7 @@ describe "Module#refine" do
end
mod.should_not == inner_self
- inner_self.should be_kind_of(Module)
+ inner_self.should.is_a?(Module)
inner_self.name.should == nil
end
@@ -43,7 +43,7 @@ describe "Module#refine" do
end
end
- inner_self.public_instance_methods.should include(:blah)
+ inner_self.public_instance_methods.should.include?(:blah)
end
it "returns created anonymous module" do
@@ -63,7 +63,7 @@ describe "Module#refine" do
Module.new do
refine {}
end
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises TypeError if not passed a class" do
@@ -71,7 +71,7 @@ describe "Module#refine" do
Module.new do
refine("foo") {}
end
- end.should raise_error(TypeError, "wrong argument type String (expected Class or Module)")
+ end.should.raise(TypeError, "wrong argument type String (expected Class or Module)")
end
it "accepts a module as argument" do
@@ -84,7 +84,7 @@ describe "Module#refine" do
end
end
- inner_self.public_instance_methods.should include(:blah)
+ inner_self.public_instance_methods.should.include?(:blah)
end
it "applies refinements to the module" do
@@ -117,7 +117,7 @@ describe "Module#refine" do
Module.new do
refine String
end
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "applies refinements to calls in the refine block" do
@@ -136,7 +136,7 @@ describe "Module#refine" do
refine(String) {def foo; "foo"; end}
-> {
"hello".foo
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -145,7 +145,7 @@ describe "Module#refine" do
refine(String) {def foo; 'foo'; end}
end
- -> {"hello".foo}.should raise_error(NoMethodError)
+ -> {"hello".foo}.should.raise(NoMethodError)
end
# When defining multiple refinements in the same module,
@@ -209,7 +209,7 @@ describe "Module#refine" do
[1, 2].to_json_format
end
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
# method lookup:
@@ -243,32 +243,6 @@ describe "Module#refine" do
result.should == "foo from singleton class"
end
- ruby_version_is ""..."3.2" do
- it "looks in the included modules for builtin methods" do
- result = ruby_exe(<<-RUBY)
- a = Module.new do
- def /(other) quo(other) end
- end
-
- refinement = Module.new do
- refine Integer do
- include a
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = 1 / 2
- end
-
- print result.class
- RUBY
-
- result.should == 'Rational'
- end
- end
-
it "looks in later included modules of the refined module first" do
a = Module.new do
def foo
@@ -622,7 +596,7 @@ describe "Module#refine" do
using refinement_with_super
-> {
refined_class.new.bar
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
end
@@ -636,7 +610,7 @@ describe "Module#refine" do
}
[1,2].orig_count.should == 2
end
- -> { [1,2].orig_count }.should raise_error(NoMethodError)
+ -> { [1,2].orig_count }.should.raise(NoMethodError)
end
it 'and alias_method aliases a method within a refinement module, but not outside it' do
@@ -648,7 +622,7 @@ describe "Module#refine" do
}
[1,2].orig_count.should == 2
end
- -> { [1,2].orig_count }.should raise_error(NoMethodError)
+ -> { [1,2].orig_count }.should.raise(NoMethodError)
end
it "and instance_methods returns a list of methods including those of the refined module" do
@@ -730,11 +704,10 @@ describe "Module#refine" do
end
end
end
- spec = self
- klass = Class.new { instance_methods.should_not spec.send(:include, :refinement_only_method) }
+ klass = Class.new { instance_methods.should_not.include?(:refinement_only_method) }
instance = klass.new
- instance.methods.should_not include :refinement_only_method
+ instance.methods.should_not.include? :refinement_only_method
instance.respond_to?(:refinement_only_method).should == false
- -> { instance.method :refinement_only_method }.should raise_error(NameError)
+ -> { instance.method :refinement_only_method }.should.raise(NameError)
end
end
diff --git a/spec/ruby/core/module/refinements_spec.rb b/spec/ruby/core/module/refinements_spec.rb
index 5648fcbd6f..05658a8b0e 100644
--- a/spec/ruby/core/module/refinements_spec.rb
+++ b/spec/ruby/core/module/refinements_spec.rb
@@ -1,45 +1,43 @@
require_relative '../../spec_helper'
describe "Module#refinements" do
- ruby_version_is "3.2" do
- it "returns refinements defined in a module" do
- ScratchPad.record []
-
- m = Module.new do
- refine String do
- ScratchPad << self
- end
-
- refine Array do
- ScratchPad << self
- end
+ it "returns refinements defined in a module" do
+ ScratchPad.record []
+
+ m = Module.new do
+ refine String do
+ ScratchPad << self
end
- m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
+ refine Array do
+ ScratchPad << self
+ end
end
- it "does not return refinements defined in the included module" do
- ScratchPad.record []
+ m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
+ end
- m1 = Module.new do
- refine Integer do
- nil
- end
+ it "does not return refinements defined in the included module" do
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ nil
end
+ end
- m2 = Module.new do
- include m1
+ m2 = Module.new do
+ include m1
- refine String do
- ScratchPad << self
- end
+ refine String do
+ ScratchPad << self
end
-
- m2.refinements.should == ScratchPad.recorded
end
- it "returns an empty array if no refinements defined in a module" do
- Module.new.refinements.should == []
- end
+ m2.refinements.should == ScratchPad.recorded
+ end
+
+ it "returns an empty array if no refinements defined in a module" do
+ Module.new.refinements.should == []
end
end
diff --git a/spec/ruby/core/module/remove_class_variable_spec.rb b/spec/ruby/core/module/remove_class_variable_spec.rb
index ab9514adf6..fccb29f52d 100644
--- a/spec/ruby/core/module/remove_class_variable_spec.rb
+++ b/spec/ruby/core/module/remove_class_variable_spec.rb
@@ -18,27 +18,27 @@ describe "Module#remove_class_variable" do
meta = obj.singleton_class
meta.send :class_variable_set, :@@var, 1
meta.send(:remove_class_variable, :@@var).should == 1
- meta.class_variable_defined?(:@@var).should be_false
+ meta.class_variable_defined?(:@@var).should == false
end
it "raises a NameError when removing class variable declared in included module" do
c = ModuleSpecs::RemoveClassVariable.new { include ModuleSpecs::MVars.dup }
- -> { c.send(:remove_class_variable, :@@mvar) }.should raise_error(NameError)
+ -> { c.send(:remove_class_variable, :@@mvar) }.should.raise(NameError)
end
it "raises a NameError when passed a symbol with one leading @" do
- -> { ModuleSpecs::MVars.send(:remove_class_variable, :@mvar) }.should raise_error(NameError)
+ -> { ModuleSpecs::MVars.send(:remove_class_variable, :@mvar) }.should.raise(NameError)
end
it "raises a NameError when passed a symbol with no leading @" do
- -> { ModuleSpecs::MVars.send(:remove_class_variable, :mvar) }.should raise_error(NameError)
+ -> { ModuleSpecs::MVars.send(:remove_class_variable, :mvar) }.should.raise(NameError)
end
it "raises a NameError when an uninitialized class variable is given" do
- -> { ModuleSpecs::MVars.send(:remove_class_variable, :@@nonexisting_class_variable) }.should raise_error(NameError)
+ -> { ModuleSpecs::MVars.send(:remove_class_variable, :@@nonexisting_class_variable) }.should.raise(NameError)
end
it "is public" do
- Module.should_not have_private_instance_method(:remove_class_variable)
+ Module.private_instance_methods(true).should_not.include?(:remove_class_variable)
end
end
diff --git a/spec/ruby/core/module/remove_const_spec.rb b/spec/ruby/core/module/remove_const_spec.rb
index 35a9d65105..4e4b9fcb45 100644
--- a/spec/ruby/core/module/remove_const_spec.rb
+++ b/spec/ruby/core/module/remove_const_spec.rb
@@ -7,13 +7,13 @@ describe "Module#remove_const" do
ConstantSpecs::ModuleM::CS_CONST252.should == :const252
ConstantSpecs::ModuleM.send :remove_const, :CS_CONST252
- -> { ConstantSpecs::ModuleM::CS_CONST252 }.should raise_error(NameError)
+ -> { ConstantSpecs::ModuleM::CS_CONST252 }.should.raise(NameError)
ConstantSpecs::ModuleM::CS_CONST253 = :const253
ConstantSpecs::ModuleM::CS_CONST253.should == :const253
ConstantSpecs::ModuleM.send :remove_const, "CS_CONST253"
- -> { ConstantSpecs::ModuleM::CS_CONST253 }.should raise_error(NameError)
+ -> { ConstantSpecs::ModuleM::CS_CONST253 }.should.raise(NameError)
end
it "returns the value of the removed constant" do
@@ -23,7 +23,7 @@ describe "Module#remove_const" do
it "raises a NameError and does not call #const_missing if the constant is not defined" do
ConstantSpecs.should_not_receive(:const_missing)
- -> { ConstantSpecs.send(:remove_const, :Nonexistent) }.should raise_error(NameError)
+ -> { ConstantSpecs.send(:remove_const, :Nonexistent) }.should.raise(NameError)
end
it "raises a NameError and does not call #const_missing if the constant is not defined directly in the module" do
@@ -34,28 +34,28 @@ describe "Module#remove_const" do
-> do
ConstantSpecs::ContainerA.send :remove_const, :CS_CONST255
- end.should raise_error(NameError)
+ end.should.raise(NameError)
ensure
ConstantSpecs::ModuleM.send :remove_const, "CS_CONST255"
end
end
it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.send :remove_const, "name" }.should raise_error(NameError)
+ -> { ConstantSpecs.send :remove_const, "name" }.should.raise(NameError)
end
it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.send :remove_const, "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "@Name" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "!Name" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "::Name" }.should raise_error(NameError)
+ -> { ConstantSpecs.send :remove_const, "__CONSTX__" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "@Name" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "!Name" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "::Name" }.should.raise(NameError)
end
it "raises a NameError if the name contains non-alphabetic characters except '_'" do
ConstantSpecs::ModuleM::CS_CONST256 = :const256
ConstantSpecs::ModuleM.send :remove_const, "CS_CONST256"
- -> { ConstantSpecs.send :remove_const, "Name=" }.should raise_error(NameError)
- -> { ConstantSpecs.send :remove_const, "Name?" }.should raise_error(NameError)
+ -> { ConstantSpecs.send :remove_const, "Name=" }.should.raise(NameError)
+ -> { ConstantSpecs.send :remove_const, "Name?" }.should.raise(NameError)
end
it "calls #to_str to convert the given name to a String" do
@@ -67,19 +67,19 @@ describe "Module#remove_const" do
it "raises a TypeError if conversion to a String by calling #to_str fails" do
name = mock('123')
- -> { ConstantSpecs.send :remove_const, name }.should raise_error(TypeError)
+ -> { ConstantSpecs.send :remove_const, name }.should.raise(TypeError)
name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.send :remove_const, name }.should raise_error(TypeError)
+ -> { ConstantSpecs.send :remove_const, name }.should.raise(TypeError)
end
it "is a private method" do
- Module.private_methods.should include(:remove_const)
+ Module.private_methods.should.include?(:remove_const)
end
it "returns nil when removing autoloaded constant" do
ConstantSpecs.autoload :AutoloadedConstant, 'a_file'
- ConstantSpecs.send(:remove_const, :AutoloadedConstant).should be_nil
+ ConstantSpecs.send(:remove_const, :AutoloadedConstant).should == nil
end
it "updates the constant value" do
diff --git a/spec/ruby/core/module/remove_method_spec.rb b/spec/ruby/core/module/remove_method_spec.rb
index 94b255df62..39add01e36 100644
--- a/spec/ruby/core/module/remove_method_spec.rb
+++ b/spec/ruby/core/module/remove_method_spec.rb
@@ -21,7 +21,7 @@ describe "Module#remove_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:remove_method, false)
+ Module.public_instance_methods(false).should.include?(:remove_method)
end
it "removes the method from a class" do
@@ -88,14 +88,14 @@ describe "Module#remove_method" do
end
it "returns self" do
- @module.send(:remove_method, :method_to_remove).should equal(@module)
+ @module.send(:remove_method, :method_to_remove).should.equal?(@module)
end
it "raises a NameError when attempting to remove method further up the inheritance tree" do
Class.new(ModuleSpecs::Second) do
-> {
remove_method :method_to_remove
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
@@ -103,7 +103,7 @@ describe "Module#remove_method" do
Class.new(ModuleSpecs::Second) do
-> {
remove_method :blah
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
@@ -113,19 +113,19 @@ describe "Module#remove_method" do
end
it "raises a FrozenError when passed a name" do
- -> { @frozen.send :remove_method, :method_to_remove }.should raise_error(FrozenError)
+ -> { @frozen.send :remove_method, :method_to_remove }.should.raise(FrozenError)
end
it "raises a FrozenError when passed a missing name" do
- -> { @frozen.send :remove_method, :not_exist }.should raise_error(FrozenError)
+ -> { @frozen.send :remove_method, :not_exist }.should.raise(FrozenError)
end
it "raises a TypeError when passed a not name" do
- -> { @frozen.send :remove_method, Object.new }.should raise_error(TypeError)
+ -> { @frozen.send :remove_method, Object.new }.should.raise(TypeError)
end
it "does not raise exceptions when no arguments given" do
- @frozen.send(:remove_method).should equal(@frozen)
+ @frozen.send(:remove_method).should.equal?(@frozen)
end
end
end
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
index aca419f522..e392642978 100644
--- a/spec/ruby/core/module/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -76,122 +76,60 @@ describe "Module#ruby2_keywords" do
Hash.ruby2_keywords_hash?(marked).should == true
end
- ruby_version_is "3.2" do
- it "makes a copy and unmark the Hash when calling a method taking (*args)" do
- obj = Object.new
- obj.singleton_class.class_exec do
- def splat(*args)
- args.last
- end
-
- def splat1(arg, *args)
- args.last
- end
+ it "makes a copy and unmark the Hash when calling a method taking (*args)" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def splat(*args)
+ args.last
+ end
- def proc_call(*args)
- -> *a { a.last }.call(*args)
- end
+ def splat1(arg, *args)
+ args.last
end
- h = { a: 1 }
- args = mark(**h)
- marked = args.last
- Hash.ruby2_keywords_hash?(marked).should == true
-
- after_usage = obj.splat(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(1, **h)
- marked = args.last
- after_usage = obj.splat1(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.proc_call(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.send(:splat, *args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
+ def proc_call(*args)
+ -> *a { a.last }.call(*args)
+ end
end
- end
- ruby_version_is ""..."3.2" do
- # https://bugs.ruby-lang.org/issues/18625
- it "does NOT copy the Hash when calling a method taking (*args)" do
- obj = Object.new
- obj.singleton_class.class_exec do
- def splat(*args)
- args.last
- end
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
- def splat1(arg, *args)
- args.last
- end
+ after_usage = obj.splat(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
- def proc_call(*args)
- -> *a { a.last }.call(*args)
- end
- end
+ args = mark(1, **h)
+ marked = args.last
+ after_usage = obj.splat1(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
- h = { a: 1 }
- args = mark(**h)
- marked = args.last
- Hash.ruby2_keywords_hash?(marked).should == true
-
- after_usage = obj.splat(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(1, **h)
- marked = args.last
- after_usage = obj.splat1(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.proc_call(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.send(:splat, *args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- send_copies = RUBY_ENGINE == "ruby" # inconsistent with Proc#call above for CRuby
- after_usage.equal?(marked).should == !send_copies
- Hash.ruby2_keywords_hash?(after_usage).should == !send_copies
- Hash.ruby2_keywords_hash?(marked).should == true
- end
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.proc_call(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.send(:splat, *args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
end
it "applies to the underlying method and applies across aliasing" do
@@ -237,7 +175,7 @@ describe "Module#ruby2_keywords" do
obj.singleton_class.class_exec do
ruby2_keywords :not_existing
end
- }.should raise_error(NameError, /undefined method [`']not_existing'/)
+ }.should.raise(NameError, /undefined method [`']not_existing'/)
end
it "accepts String as well" do
@@ -259,7 +197,7 @@ describe "Module#ruby2_keywords" do
obj.singleton_class.class_exec do
ruby2_keywords Object.new
end
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+ }.should.raise(TypeError, /is not a symbol nor a string/)
end
it "prints warning when a method does not accept argument splat" do
@@ -275,7 +213,7 @@ describe "Module#ruby2_keywords" do
it "prints warning when a method accepts keywords" do
obj = Object.new
- def obj.foo(a:, b:) end
+ def obj.foo(*a, b:) end
-> {
obj.singleton_class.class_exec do
@@ -286,7 +224,7 @@ describe "Module#ruby2_keywords" do
it "prints warning when a method accepts keyword splat" do
obj = Object.new
- def obj.foo(**a) end
+ def obj.foo(*a, **b) end
-> {
obj.singleton_class.class_exec do
@@ -294,4 +232,17 @@ describe "Module#ruby2_keywords" do
end
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
+
+ ruby_version_is "4.0" do
+ it "prints warning when a method accepts post arguments" do
+ obj = Object.new
+ def obj.foo(*a, b) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+ end
end
diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb
index 12c1c214dd..7c159121fa 100644
--- a/spec/ruby/core/module/set_temporary_name_spec.rb
+++ b/spec/ruby/core/module/set_temporary_name_spec.rb
@@ -1,146 +1,145 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_temporary_name'
-ruby_version_is "3.3" do
- describe "Module#set_temporary_name" do
- it "can assign a temporary name" do
- m = Module.new
- m.name.should be_nil
+describe "Module#set_temporary_name" do
+ it "can assign a temporary name" do
+ m = Module.new
+ m.name.should == nil
- m.set_temporary_name("fake_name")
- m.name.should == "fake_name"
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
- m.set_temporary_name(nil)
- m.name.should be_nil
- end
+ m.set_temporary_name(nil)
+ m.name.should == nil
+ end
- it "returns self" do
- m = Module.new
- m.set_temporary_name("fake_name").should.equal? m
- end
+ it "returns self" do
+ m = Module.new
+ m.set_temporary_name("fake_name").should.equal? m
+ end
- it "can assign a temporary name which is not a valid constant path" do
- m = Module.new
+ it "can assign a temporary name which is not a valid constant path" do
+ m = Module.new
- m.set_temporary_name("name")
- m.name.should == "name"
+ m.set_temporary_name("name")
+ m.name.should == "name"
- m.set_temporary_name("Template['foo.rb']")
- m.name.should == "Template['foo.rb']"
+ m.set_temporary_name("Template['foo.rb']")
+ m.name.should == "Template['foo.rb']"
- m.set_temporary_name("a::B")
- m.name.should == "a::B"
+ m.set_temporary_name("a::B")
+ m.name.should == "a::B"
- m.set_temporary_name("A::b")
- m.name.should == "A::b"
+ m.set_temporary_name("A::b")
+ m.name.should == "A::b"
- m.set_temporary_name("A::B::")
- m.name.should == "A::B::"
+ m.set_temporary_name("A::B::")
+ m.name.should == "A::B::"
- m.set_temporary_name("A::::B")
- m.name.should == "A::::B"
+ m.set_temporary_name("A::::B")
+ m.name.should == "A::::B"
- m.set_temporary_name("A=")
- m.name.should == "A="
- end
+ m.set_temporary_name("A=")
+ m.name.should == "A="
+ end
- it "can't assign empty string as name" do
- m = Module.new
- -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name")
- end
+ it "can't assign empty string as name" do
+ m = Module.new
+ -> { m.set_temporary_name("") }.should.raise(ArgumentError, "empty class/module name")
+ end
- it "can't assign a constant name as a temporary name" do
- m = Module.new
- -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- end
+ it "can't assign a constant name as a temporary name" do
+ m = Module.new
+ -> { m.set_temporary_name("Object") }.should.raise(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ end
- it "can't assign a constant path as a temporary name" do
- m = Module.new
- -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- end
+ it "can't assign a constant path as a temporary name" do
+ m = Module.new
+ -> { m.set_temporary_name("A::B") }.should.raise(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ -> { m.set_temporary_name("::A") }.should.raise(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ -> { m.set_temporary_name("::A::B") }.should.raise(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ end
- it "can't assign name to permanent module" do
- -> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name")
- end
+ it "can't assign name to permanent module" do
+ -> { Object.set_temporary_name("fake_name") }.should.raise(RuntimeError, "can't change permanent name")
+ end
- it "can assign a temporary name to a module nested into an anonymous module" do
- m = Module.new
- module m::N; end
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+ it "can assign a temporary name to a module nested into an anonymous module" do
+ m = Module.new
+ module m::N; end
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
- m::N.set_temporary_name("fake_name")
- m::N.name.should == "fake_name"
+ m::N.set_temporary_name("fake_name")
+ m::N.name.should == "fake_name"
- m::N.set_temporary_name(nil)
- m::N.name.should be_nil
- end
+ m::N.set_temporary_name(nil)
+ m::N.name.should == nil
+ end
- it "discards a temporary name when an outer anonymous module gets a permanent name" do
- m = Module.new
- module m::N; end
+ it "discards a temporary name when an outer anonymous module gets a permanent name" do
+ m = Module.new
+ module m::N; end
- m::N.set_temporary_name("fake_name")
- m::N.name.should == "fake_name"
+ m::N.set_temporary_name("fake_name")
+ m::N.name.should == "fake_name"
- ModuleSpecs::SetTemporaryNameSpec::M = m
- m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
- end
+ ModuleSpecs::SetTemporaryNameSpec::M = m
+ m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
+ ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M
+ end
- it "can update the name when assigned to a constant" do
- m = Module.new
- m::N = Module.new
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
- m::N.set_temporary_name(nil)
+ it "can update the name when assigned to a constant" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+ m::N.set_temporary_name(nil)
- m::M = m::N
- m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m
- end
+ m::M = m::N
+ m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m
+ end
- it "can reassign a temporary name repeatedly" do
- m = Module.new
+ it "can reassign a temporary name repeatedly" do
+ m = Module.new
- m.set_temporary_name("fake_name")
- m.name.should == "fake_name"
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
- m.set_temporary_name("fake_name_2")
- m.name.should == "fake_name_2"
- end
+ m.set_temporary_name("fake_name_2")
+ m.name.should == "fake_name_2"
+ end
- ruby_bug "#21094", ""..."3.5" do
- it "also updates a name of a nested module" do
- m = Module.new
- m::N = Module.new
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+ ruby_bug "#21094", ""..."4.0" do
+ it "also updates a name of a nested module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
- m.set_temporary_name "m"
- m::N.name.should == "m::N"
+ m.set_temporary_name "m"
+ m::N.name.should == "m::N"
- m.set_temporary_name nil
- m::N.name.should == nil
- end
+ m.set_temporary_name nil
+ m::N.name.should == nil
end
+ end
- it "keeps temporary name when assigned in an anonymous module" do
- outer = Module.new
- m = Module.new
- m.set_temporary_name "m"
- m.name.should == "m"
- outer::M = m
- m.name.should == "m"
- m.inspect.should == "m"
- end
+ it "keeps temporary name when assigned in an anonymous module" do
+ outer = Module.new
+ m = Module.new
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
+ end
- it "keeps temporary name when assigned in an anonymous module and nested before" do
- outer = Module.new
- m = Module.new
- outer::A = m
- m.set_temporary_name "m"
- m.name.should == "m"
- outer::M = m
- m.name.should == "m"
- m.inspect.should == "m"
- end
+ it "keeps temporary name when assigned in an anonymous module and nested before" do
+ outer = Module.new
+ m = Module.new
+ outer::A = m
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
end
end
diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb
index b1d5cb3814..ee2860449a 100644
--- a/spec/ruby/core/module/shared/class_eval.rb
+++ b/spec/ruby/core/module/shared/class_eval.rb
@@ -14,7 +14,7 @@ describe :module_class_eval, shared: true do
'foo'
end
end
- -> {42.foo}.should raise_error(NoMethodError)
+ -> {42.foo}.should.raise(NoMethodError)
end
it "resolves constants in the caller scope" do
@@ -45,17 +45,15 @@ describe :module_class_eval, shared: true do
ModuleSpecs.send(@method) do |block_parameter|
given = block_parameter
end
- given.should equal ModuleSpecs
+ given.should.equal? ModuleSpecs
end
it "uses the optional filename and lineno parameters for error messages" do
ModuleSpecs.send(@method, "[__FILE__, __LINE__]", "test", 102).should == ["test", 102]
end
- ruby_version_is "3.3" do
- it "uses the caller location as default filename" do
- ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
+ it "uses the caller location as default filename" do
+ ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
it "converts a non-string filename to a string using to_str" do
@@ -68,7 +66,7 @@ describe :module_class_eval, shared: true do
it "raises a TypeError when the given filename can't be converted to string using to_str" do
(file = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/)
+ -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
end
it "converts non string eval-string to string using to_str" do
@@ -84,26 +82,26 @@ describe :module_class_eval, shared: true do
it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
o = mock('x')
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
+ -> { ModuleSpecs.send(@method, o) }.should.raise(TypeError, "no implicit conversion of MockObject into String")
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/)
+ -> { ModuleSpecs.send(@method, o) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
end
it "raises an ArgumentError when no arguments and no block are given" do
- -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
+ -> { ModuleSpecs.send(@method) }.should.raise(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
end
it "raises an ArgumentError when more than 3 arguments are given" do
-> {
ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "raises an ArgumentError when a block and normal arguments are given" do
-> {
ModuleSpecs.send(@method, "1 + 1") { 1 + 1 }
- }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
+ }.should.raise(ArgumentError, "wrong number of arguments (given 1, expected 0)")
end
# This case was found because Rubinius was caching the compiled
diff --git a/spec/ruby/core/module/shared/class_exec.rb b/spec/ruby/core/module/shared/class_exec.rb
index c7a9e5297f..e51af1966d 100644
--- a/spec/ruby/core/module/shared/class_exec.rb
+++ b/spec/ruby/core/module/shared/class_exec.rb
@@ -5,7 +5,7 @@ describe :module_class_exec, shared: true do
'foo'
end
end
- -> {42.foo}.should raise_error(NoMethodError)
+ -> {42.foo}.should.raise(NoMethodError)
end
it "defines method in the receiver's scope" do
@@ -19,11 +19,17 @@ describe :module_class_exec, shared: true do
end
it "raises a LocalJumpError when no block is given" do
- -> { ModuleSpecs::Subclass.send(@method) }.should raise_error(LocalJumpError)
+ -> { ModuleSpecs::Subclass.send(@method) }.should.raise(LocalJumpError)
end
it "passes arguments to the block" do
a = ModuleSpecs::Subclass
- a.send(@method, 1) { |b| b }.should equal(1)
+ a.send(@method, 1) { |b| b }.should.equal?(1)
+ end
+
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ ModuleSpecs::Subclass.send(@method, [1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
end
end
diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb
index a1586dd2bd..38cc2ad260 100644
--- a/spec/ruby/core/module/shared/set_visibility.rb
+++ b/spec/ruby/core/module/shared/set_visibility.rb
@@ -2,7 +2,7 @@
describe :set_visibility, shared: true do
it "is a private method" do
- Module.should have_private_instance_method(@method, false)
+ Module.private_instance_methods(false).should.include?(@method)
end
describe "with argument" do
@@ -17,8 +17,8 @@ describe :set_visibility, shared: true do
def test2() end
send visibility, :test1, :test2
}
- mod.should send(:"have_#{visibility}_instance_method", :test1, false)
- mod.should send(:"have_#{visibility}_instance_method", :test2, false)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test1)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test2)
end
end
@@ -33,8 +33,8 @@ describe :set_visibility, shared: true do
def test2() end
send visibility, [:test1, :test2]
}
- mod.should send(:"have_#{visibility}_instance_method", :test1, false)
- mod.should send(:"have_#{visibility}_instance_method", :test2, false)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test1)
+ mod.send(:"#{visibility}_instance_methods", false).should.include?(:test2)
end
end
@@ -50,7 +50,7 @@ describe :set_visibility, shared: true do
send(visibility, :test_method)
}
- child.should_not send(:"have_#{visibility}_instance_method", :test_method, false)
+ child.send(:"#{visibility}_instance_methods", false).should_not.include?(:test_method)
end
end
@@ -64,8 +64,8 @@ describe :set_visibility, shared: true do
def test2() end
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
- mod.should send(:"have_#{@method}_instance_method", :test2, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test2)
end
it "stops setting visibility if the body encounters other visibility setters without arguments" do
@@ -78,7 +78,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should send(:"have_#{new_visibility}_instance_method", :test1, false)
+ mod.send(:"#{new_visibility}_instance_methods", false).should.include?(:test1)
end
it "continues setting visibility if the body encounters other visibility setters with arguments" do
@@ -90,7 +90,7 @@ describe :set_visibility, shared: true do
def test2() end
}
- mod.should send(:"have_#{@method}_instance_method", :test2, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test2)
end
it "does not affect module_evaled method definitions when itself is outside the eval" do
@@ -102,8 +102,8 @@ describe :set_visibility, shared: true do
module_eval " def test2() end "
}
- mod.should have_public_instance_method(:test1, false)
- mod.should have_public_instance_method(:test2, false)
+ mod.public_instance_methods(false).should.include?(:test1)
+ mod.public_instance_methods(false).should.include?(:test2)
end
it "does not affect outside method definitions when itself is inside a module_eval" do
@@ -114,7 +114,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should have_public_instance_method(:test1, false)
+ mod.public_instance_methods(false).should.include?(:test1)
end
it "affects normally if itself and method definitions are inside a module_eval" do
@@ -127,7 +127,7 @@ describe :set_visibility, shared: true do
}
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
it "does not affect method definitions when itself is inside an eval and method definitions are outside" do
@@ -140,7 +140,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should send(:"have_#{initialized_visibility}_instance_method", :test1, false)
+ mod.send(:"#{initialized_visibility}_instance_methods", false).should.include?(:test1)
end
it "affects evaled method definitions when itself is outside the eval" do
@@ -151,7 +151,7 @@ describe :set_visibility, shared: true do
eval "def test1() end"
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
it "affects normally if itself and following method definitions are inside a eval" do
@@ -164,7 +164,7 @@ describe :set_visibility, shared: true do
CODE
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
describe "within a closure" do
@@ -177,7 +177,7 @@ describe :set_visibility, shared: true do
def test1() end
}
- mod.should send(:"have_#{@method}_instance_method", :test1, false)
+ mod.send(:"#{@method}_instance_methods", false).should.include?(:test1)
end
end
end
diff --git a/spec/ruby/core/module/undef_method_spec.rb b/spec/ruby/core/module/undef_method_spec.rb
index d4efcd51cb..d77640cb7e 100644
--- a/spec/ruby/core/module/undef_method_spec.rb
+++ b/spec/ruby/core/module/undef_method_spec.rb
@@ -19,7 +19,7 @@ describe "Module#undef_method" do
end
it "is a public method" do
- Module.should have_public_instance_method(:undef_method, false)
+ Module.public_instance_methods(false).should.include?(:undef_method)
end
it "requires multiple arguments" do
@@ -34,8 +34,8 @@ describe "Module#undef_method" do
x = klass.new
klass.send(:undef_method, :method_to_undef, :another_method_to_undef)
- -> { x.method_to_undef }.should raise_error(NoMethodError)
- -> { x.another_method_to_undef }.should raise_error(NoMethodError)
+ -> { x.method_to_undef }.should.raise(NoMethodError)
+ -> { x.another_method_to_undef }.should.raise(NoMethodError)
end
it "does not undef any instance methods when argument not given" do
@@ -46,11 +46,11 @@ describe "Module#undef_method" do
end
it "returns self" do
- @module.send(:undef_method, :method_to_undef).should equal(@module)
+ @module.send(:undef_method, :method_to_undef).should.equal?(@module)
end
it "raises a NameError when passed a missing name for a module" do
- -> { @module.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for module [`']#{@module}'/) { |e|
+ -> { @module.send :undef_method, :not_exist }.should.raise(NameError, /undefined method [`']not_exist' for module [`']#{@module}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -58,7 +58,7 @@ describe "Module#undef_method" do
it "raises a NameError when passed a missing name for a class" do
klass = Class.new
- -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']#{klass}'/) { |e|
+ -> { klass.send :undef_method, :not_exist }.should.raise(NameError, /undefined method [`']not_exist' for class [`']#{klass}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -69,7 +69,7 @@ describe "Module#undef_method" do
obj = klass.new
sclass = obj.singleton_class
- -> { sclass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']#{sclass}'/) { |e|
+ -> { sclass.send :undef_method, :not_exist }.should.raise(NameError, /undefined method [`']not_exist' for class [`']#{sclass}'/) { |e|
e.message.should =~ /[`']#<Class:#<#<Class:/
# a NameError and not a NoMethodError
@@ -79,7 +79,7 @@ describe "Module#undef_method" do
it "raises a NameError when passed a missing name for a metaclass" do
klass = String.singleton_class
- -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']String'/) { |e|
+ -> { klass.send :undef_method, :not_exist }.should.raise(NameError, /undefined method [`']not_exist' for class [`']String'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -91,19 +91,19 @@ describe "Module#undef_method" do
end
it "raises a FrozenError when passed a name" do
- -> { @frozen.send :undef_method, :method_to_undef }.should raise_error(FrozenError)
+ -> { @frozen.send :undef_method, :method_to_undef }.should.raise(FrozenError)
end
it "raises a FrozenError when passed a missing name" do
- -> { @frozen.send :undef_method, :not_exist }.should raise_error(FrozenError)
+ -> { @frozen.send :undef_method, :not_exist }.should.raise(FrozenError)
end
it "raises a TypeError when passed a not name" do
- -> { @frozen.send :undef_method, Object.new }.should raise_error(TypeError)
+ -> { @frozen.send :undef_method, Object.new }.should.raise(TypeError)
end
it "does not raise exceptions when no arguments given" do
- @frozen.send(:undef_method).should equal(@frozen)
+ @frozen.send(:undef_method).should.equal?(@frozen)
end
end
end
@@ -120,7 +120,7 @@ describe "Module#undef_method with symbol" do
klass.send :undef_method, :method_to_undef
- -> { x.method_to_undef }.should raise_error(NoMethodError)
+ -> { x.method_to_undef }.should.raise(NoMethodError)
end
it "removes a method defined in a super class" do
@@ -130,7 +130,7 @@ describe "Module#undef_method with symbol" do
child_class.send :undef_method, :method_to_undef
- -> { child.method_to_undef }.should raise_error(NoMethodError)
+ -> { child.method_to_undef }.should.raise(NoMethodError)
end
it "does not remove a method defined in a super class when removed from a subclass" do
@@ -156,7 +156,7 @@ describe "Module#undef_method with string" do
klass.send :undef_method, 'another_method_to_undef'
- -> { x.another_method_to_undef }.should raise_error(NoMethodError)
+ -> { x.another_method_to_undef }.should.raise(NoMethodError)
end
it "removes a method defined in a super class" do
@@ -166,7 +166,7 @@ describe "Module#undef_method with string" do
child_class.send :undef_method, 'another_method_to_undef'
- -> { child.another_method_to_undef }.should raise_error(NoMethodError)
+ -> { child.another_method_to_undef }.should.raise(NoMethodError)
end
it "does not remove a method defined in a super class when removed from a subclass" do
diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb
index 3be860d053..9f731c6adf 100644
--- a/spec/ruby/core/module/undefined_instance_methods_spec.rb
+++ b/spec/ruby/core/module/undefined_instance_methods_spec.rb
@@ -2,25 +2,24 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Module#undefined_instance_methods" do
- ruby_version_is "3.2" do
- it "returns methods undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
- methods.should == [:undefed_method]
- end
+ it "returns methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
+ methods.should == [:undefed_method]
+ end
- it "returns inherited methods undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
- methods.should include(:parent_method, :another_parent_method)
- end
+ it "returns inherited methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
+ methods.to_set.should >= Set[:parent_method, :another_parent_method]
+ end
- it "returns methods from an included module that are undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
- methods.should include(:super_included_method)
- end
+ it "returns methods from an included module that are undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should.include?(:super_included_method)
+ end
- it "does not returns ancestors undefined methods" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
- methods.should_not include(:parent_method, :another_parent_method)
- end
+ it "does not returns ancestors undefined methods" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should_not.include?(:parent_method)
+ methods.should_not.include?(:another_parent_method)
end
end
diff --git a/spec/ruby/core/module/used_refinements_spec.rb b/spec/ruby/core/module/used_refinements_spec.rb
index c16cab0e3c..40dd4a444e 100644
--- a/spec/ruby/core/module/used_refinements_spec.rb
+++ b/spec/ruby/core/module/used_refinements_spec.rb
@@ -1,87 +1,85 @@
require_relative '../../spec_helper'
describe "Module.used_refinements" do
- ruby_version_is "3.2" do
- it "returns list of all refinements imported in the current scope" do
- refinement_int = nil
- refinement_str = nil
- ScratchPad.record []
-
- m1 = Module.new do
- refine Integer do
- refinement_int = self
- end
+ it "returns list of all refinements imported in the current scope" do
+ refinement_int = nil
+ refinement_str = nil
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ refinement_int = self
end
+ end
- m2 = Module.new do
- refine String do
- refinement_str = self
- end
+ m2 = Module.new do
+ refine String do
+ refinement_str = self
end
+ end
- Module.new do
- using m1
- using m2
+ Module.new do
+ using m1
+ using m2
- Module.used_refinements.each { |r| ScratchPad << r }
- end
-
- ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
+ Module.used_refinements.each { |r| ScratchPad << r }
end
- it "returns empty array if does not have any refinements imported" do
- used_refinements = nil
+ ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
+ end
- Module.new do
- used_refinements = Module.used_refinements
- end
+ it "returns empty array if does not have any refinements imported" do
+ used_refinements = nil
- used_refinements.should == []
+ Module.new do
+ used_refinements = Module.used_refinements
end
- it "ignores refinements imported in a module that is included into the current one" do
- used_refinements = nil
+ used_refinements.should == []
+ end
- m1 = Module.new do
- refine Integer do
- nil
- end
- end
+ it "ignores refinements imported in a module that is included into the current one" do
+ used_refinements = nil
- m2 = Module.new do
- using m1
+ m1 = Module.new do
+ refine Integer do
+ nil
end
+ end
- Module.new do
- include m2
+ m2 = Module.new do
+ using m1
+ end
- used_refinements = Module.used_refinements
- end
+ Module.new do
+ include m2
- used_refinements.should == []
+ used_refinements = Module.used_refinements
end
- it "returns refinements even not defined directly in a module refinements are imported from" do
- used_refinements = nil
- ScratchPad.record []
+ used_refinements.should == []
+ end
- m1 = Module.new do
- refine Integer do
- ScratchPad << self
- end
- end
+ it "returns refinements even not defined directly in a module refinements are imported from" do
+ used_refinements = nil
+ ScratchPad.record []
- m2 = Module.new do
- include m1
+ m1 = Module.new do
+ refine Integer do
+ ScratchPad << self
end
+ end
- Module.new do
- using m2
+ m2 = Module.new do
+ include m1
+ end
- used_refinements = Module.used_refinements
- end
+ Module.new do
+ using m2
- used_refinements.should == ScratchPad.recorded
+ used_refinements = Module.used_refinements
end
+
+ used_refinements.should == ScratchPad.recorded
end
end
diff --git a/spec/ruby/core/module/using_spec.rb b/spec/ruby/core/module/using_spec.rb
index a908363c96..cff0edef28 100644
--- a/spec/ruby/core/module/using_spec.rb
+++ b/spec/ruby/core/module/using_spec.rb
@@ -28,7 +28,7 @@ describe "Module#using" do
Module.new do
using refinement
end
- }.should_not raise_error
+ }.should_not.raise
end
it "accepts module without refinements" do
@@ -38,7 +38,7 @@ describe "Module#using" do
Module.new do
using mod
end
- }.should_not raise_error
+ }.should_not.raise
end
it "does not accept class" do
@@ -48,7 +48,7 @@ describe "Module#using" do
Module.new do
using klass
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if passed something other than module" do
@@ -56,7 +56,7 @@ describe "Module#using" do
Module.new do
using "foo"
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "returns self" do
@@ -67,7 +67,7 @@ describe "Module#using" do
result = using refinement
end
- result.should equal(mod)
+ result.should.equal?(mod)
end
it "works in classes too" do
@@ -95,7 +95,7 @@ describe "Module#using" do
-> {
mod.foo
- }.should raise_error(RuntimeError, /Module#using is not permitted in methods/)
+ }.should.raise(RuntimeError, /Module#using is not permitted in methods/)
end
it "activates refinement even for existed objects" do
diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb
index e9d33f5fd9..4fee29091a 100644
--- a/spec/ruby/core/mutex/lock_spec.rb
+++ b/spec/ruby/core/mutex/lock_spec.rb
@@ -20,11 +20,73 @@ describe "Mutex#lock" do
# Unable to find a specific ticket but behavior change may be
# related to this ML thread.
- it "raises a ThreadError when used recursively" do
+ it "raises a deadlock ThreadError when used recursively" do
m = Mutex.new
m.lock
-> {
m.lock
- }.should raise_error(ThreadError)
+ }.should.raise(ThreadError, /deadlock/)
+ end
+
+ it "raises a deadlock ThreadError when multiple fibers from the same thread try to lock" do
+ m = Mutex.new
+
+ m.lock
+ f0 = Fiber.new do
+ m.lock
+ end
+ -> { f0.resume }.should.raise(ThreadError, /deadlock/)
+
+ m.unlock
+ f1 = Fiber.new do
+ m.lock
+ Fiber.yield
+ end
+ f2 = Fiber.new do
+ m.lock
+ end
+ f1.resume
+ -> { f2.resume }.should.raise(ThreadError, /deadlock/)
+ end
+
+ it "does not raise deadlock if a fiber's attempt to lock was interrupted" do
+ lock = Mutex.new
+ main = Thread.current
+
+ t2 = nil
+ t1 = Thread.new do
+ loop do
+ # interrupt fiber below looping on synchronize
+ sleep 0.01
+ t2.raise if t2
+ end
+ end
+
+ # loop ten times to try to handle the interrupt during synchronize
+ t2 = Thread.new do
+ 10.times do
+ Fiber.new do
+ begin
+ loop { lock.synchronize {} }
+ rescue RuntimeError
+ end
+ end.resume
+
+ Fiber.new do
+ -> do
+ lock.synchronize {}
+ end.should_not.raise(ThreadError)
+ end.resume
+ rescue RuntimeError
+ retry
+ end
+ end
+ t2.join
+ ensure
+ t1.kill rescue nil
+ t2.kill rescue nil
+
+ t1.join
+ t2.join
end
end
diff --git a/spec/ruby/core/mutex/locked_spec.rb b/spec/ruby/core/mutex/locked_spec.rb
index 1bf3ed6394..1818cdb4f3 100644
--- a/spec/ruby/core/mutex/locked_spec.rb
+++ b/spec/ruby/core/mutex/locked_spec.rb
@@ -4,12 +4,12 @@ describe "Mutex#locked?" do
it "returns true if locked" do
m = Mutex.new
m.lock
- m.locked?.should be_true
+ m.locked?.should == true
end
it "returns false if unlocked" do
m = Mutex.new
- m.locked?.should be_false
+ m.locked?.should == false
end
it "returns the status of the lock" do
@@ -27,10 +27,10 @@ describe "Mutex#locked?" do
Thread.pass until m1_locked
- m1.locked?.should be_true
+ m1.locked?.should == true
m2.unlock # release th
th.join
# A Thread releases its locks upon termination
- m1.locked?.should be_false
+ m1.locked?.should == false
end
end
diff --git a/spec/ruby/core/mutex/owned_spec.rb b/spec/ruby/core/mutex/owned_spec.rb
index 7bfc7d8f83..ea7d5faf1c 100644
--- a/spec/ruby/core/mutex/owned_spec.rb
+++ b/spec/ruby/core/mutex/owned_spec.rb
@@ -4,7 +4,7 @@ describe "Mutex#owned?" do
describe "when unlocked" do
it "returns false" do
m = Mutex.new
- m.owned?.should be_false
+ m.owned?.should == false
end
end
@@ -12,7 +12,7 @@ describe "Mutex#owned?" do
it "returns true" do
m = Mutex.new
m.lock
- m.owned?.should be_true
+ m.owned?.should == true
end
end
@@ -37,7 +37,7 @@ describe "Mutex#owned?" do
end
Thread.pass until locked
- m.owned?.should be_false
+ m.owned?.should == false
end
end
diff --git a/spec/ruby/core/mutex/sleep_spec.rb b/spec/ruby/core/mutex/sleep_spec.rb
index 9832e3125e..71b089d251 100644
--- a/spec/ruby/core/mutex/sleep_spec.rb
+++ b/spec/ruby/core/mutex/sleep_spec.rb
@@ -4,21 +4,21 @@ describe "Mutex#sleep" do
describe "when not locked by the current thread" do
it "raises a ThreadError" do
m = Mutex.new
- -> { m.sleep }.should raise_error(ThreadError)
+ -> { m.sleep }.should.raise(ThreadError)
end
it "raises an ArgumentError if passed a negative duration" do
m = Mutex.new
- -> { m.sleep(-0.1) }.should raise_error(ArgumentError)
- -> { m.sleep(-1) }.should raise_error(ArgumentError)
+ -> { m.sleep(-0.1) }.should.raise(ArgumentError)
+ -> { m.sleep(-1) }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError if passed a negative duration" do
m = Mutex.new
m.lock
- -> { m.sleep(-0.1) }.should raise_error(ArgumentError)
- -> { m.sleep(-1) }.should raise_error(ArgumentError)
+ -> { m.sleep(-0.1) }.should.raise(ArgumentError)
+ -> { m.sleep(-1) }.should.raise(ArgumentError)
end
it "pauses execution for approximately the duration requested" do
@@ -38,7 +38,7 @@ describe "Mutex#sleep" do
th = Thread.new { m.lock; locked = true; m.sleep }
Thread.pass until locked
Thread.pass until th.stop?
- m.locked?.should be_false
+ m.locked?.should == false
th.run
th.join
end
@@ -47,7 +47,7 @@ describe "Mutex#sleep" do
m = Mutex.new
m.lock
m.sleep(0.001)
- m.locked?.should be_true
+ m.locked?.should == true
end
it "relocks the mutex when woken by an exception being raised" do
@@ -65,7 +65,7 @@ describe "Mutex#sleep" do
Thread.pass until locked
Thread.pass until th.stop?
th.raise(Exception)
- th.value.should be_true
+ th.value.should == true
end
it "returns the rounded number of seconds asleep" do
@@ -79,7 +79,15 @@ describe "Mutex#sleep" do
Thread.pass until locked
Thread.pass until th.stop?
th.wakeup
- th.value.should be_kind_of(Integer)
+ th.value.should.is_a?(Integer)
+ end
+
+ it "accepts nil as a sleep duration" do
+ m = Mutex.new
+ -> {
+ m.lock
+ m.sleep(nil)
+ }.should block_caller
end
it "wakes up when requesting sleep times near or equal to zero" do
@@ -97,7 +105,7 @@ describe "Mutex#sleep" do
m.lock
times.each do |time|
# just testing that sleep completes
- -> {m.sleep(time)}.should_not raise_error
+ -> {m.sleep(time)}.should_not.raise
end
end
end
diff --git a/spec/ruby/core/mutex/synchronize_spec.rb b/spec/ruby/core/mutex/synchronize_spec.rb
index 7942885197..823f29a634 100644
--- a/spec/ruby/core/mutex/synchronize_spec.rb
+++ b/spec/ruby/core/mutex/synchronize_spec.rb
@@ -14,15 +14,15 @@ describe "Mutex#synchronize" do
m2.lock
raise Exception
end
- end.should raise_error(Exception)
+ end.should.raise(Exception)
end
Thread.pass until synchronized
- m1.locked?.should be_true
+ m1.locked?.should == true
m2.unlock
th.join
- m1.locked?.should be_false
+ m1.locked?.should == false
end
it "blocks the caller if already locked" do
@@ -60,7 +60,7 @@ describe "Mutex#synchronize" do
m = Mutex.new
m.synchronize do
- -> { m.synchronize { } }.should raise_error(ThreadError)
+ -> { m.synchronize { } }.should.raise(ThreadError)
end
end
end
diff --git a/spec/ruby/core/mutex/try_lock_spec.rb b/spec/ruby/core/mutex/try_lock_spec.rb
index 8d521f4c6b..1da0735d6a 100644
--- a/spec/ruby/core/mutex/try_lock_spec.rb
+++ b/spec/ruby/core/mutex/try_lock_spec.rb
@@ -4,13 +4,13 @@ describe "Mutex#try_lock" do
describe "when unlocked" do
it "returns true" do
m = Mutex.new
- m.try_lock.should be_true
+ m.try_lock.should == true
end
it "locks the mutex" do
m = Mutex.new
m.try_lock
- m.locked?.should be_true
+ m.locked?.should == true
end
end
@@ -18,7 +18,7 @@ describe "Mutex#try_lock" do
it "returns false" do
m = Mutex.new
m.lock
- m.try_lock.should be_false
+ m.try_lock.should == false
end
end
@@ -26,7 +26,7 @@ describe "Mutex#try_lock" do
it "returns false" do
m = Mutex.new
m.lock
- Thread.new { m.try_lock }.value.should be_false
+ Thread.new { m.try_lock }.value.should == false
end
end
end
diff --git a/spec/ruby/core/mutex/unlock_spec.rb b/spec/ruby/core/mutex/unlock_spec.rb
index d999e66842..ed493cf84a 100644
--- a/spec/ruby/core/mutex/unlock_spec.rb
+++ b/spec/ruby/core/mutex/unlock_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Mutex#unlock" do
it "raises ThreadError unless Mutex is locked" do
mutex = Mutex.new
- -> { mutex.unlock }.should raise_error(ThreadError)
+ -> { mutex.unlock }.should.raise(ThreadError)
end
it "raises ThreadError unless thread owns Mutex" do
@@ -19,7 +19,7 @@ describe "Mutex#unlock" do
Thread.pass until mutex.locked?
Thread.pass until th.stop?
- -> { mutex.unlock }.should raise_error(ThreadError)
+ -> { mutex.unlock }.should.raise(ThreadError)
wait.unlock
th.join
@@ -33,6 +33,6 @@ describe "Mutex#unlock" do
th.join
- -> { mutex.unlock }.should raise_error(ThreadError)
+ -> { mutex.unlock }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/nil/dup_spec.rb b/spec/ruby/core/nil/dup_spec.rb
index 0324b3f1f4..e0be9540a6 100644
--- a/spec/ruby/core/nil/dup_spec.rb
+++ b/spec/ruby/core/nil/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "NilClass#dup" do
it "returns self" do
- nil.dup.should equal(nil)
+ nil.dup.should.equal?(nil)
end
end
diff --git a/spec/ruby/core/nil/match_spec.rb b/spec/ruby/core/nil/match_spec.rb
index bc1c591793..27ebc53c3d 100644
--- a/spec/ruby/core/nil/match_spec.rb
+++ b/spec/ruby/core/nil/match_spec.rb
@@ -5,13 +5,13 @@ describe "NilClass#=~" do
o = nil
suppress_warning do
- (o =~ /Object/).should be_nil
- (o =~ 'Object').should be_nil
- (o =~ Object).should be_nil
- (o =~ Object.new).should be_nil
- (o =~ nil).should be_nil
- (o =~ false).should be_nil
- (o =~ true).should be_nil
+ (o =~ /Object/).should == nil
+ (o =~ 'Object').should == nil
+ (o =~ Object).should == nil
+ (o =~ Object.new).should == nil
+ (o =~ nil).should == nil
+ (o =~ false).should == nil
+ (o =~ true).should == nil
end
end
diff --git a/spec/ruby/core/nil/nilclass_spec.rb b/spec/ruby/core/nil/nilclass_spec.rb
index 7f6d8af25d..55c5d0eba7 100644
--- a/spec/ruby/core/nil/nilclass_spec.rb
+++ b/spec/ruby/core/nil/nilclass_spec.rb
@@ -4,12 +4,12 @@ describe "NilClass" do
it ".allocate raises a TypeError" do
-> do
NilClass.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
NilClass.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/nil/rationalize_spec.rb b/spec/ruby/core/nil/rationalize_spec.rb
index 84d6e6f056..69fb257a7f 100644
--- a/spec/ruby/core/nil/rationalize_spec.rb
+++ b/spec/ruby/core/nil/rationalize_spec.rb
@@ -10,7 +10,7 @@ describe "NilClass#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { nil.rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { nil.rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { nil.rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { nil.rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb
index 8d898b1cc9..f121b42f81 100644
--- a/spec/ruby/core/nil/singleton_method_spec.rb
+++ b/spec/ruby/core/nil/singleton_method_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../spec_helper'
describe "NilClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether NilClass defines the method" do
- -> { nil.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (nil).foo; end
- -> { nil.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- NilClass.send(:remove_method, :foo)
- end
+ it "raises regardless of whether NilClass defines the method" do
+ -> { nil.singleton_method(:foo) }.should.raise(NameError)
+ begin
+ def (nil).foo; end
+ -> { nil.singleton_method(:foo) }.should.raise(NameError)
+ ensure
+ NilClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/nil/to_c_spec.rb b/spec/ruby/core/nil/to_c_spec.rb
index e0052be5bd..f449ddb6a3 100644
--- a/spec/ruby/core/nil/to_c_spec.rb
+++ b/spec/ruby/core/nil/to_c_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "NilClass#to_c" do
it "returns Complex(0, 0)" do
- nil.to_c.should eql(Complex(0, 0))
+ nil.to_c.should.eql?(Complex(0, 0))
end
end
diff --git a/spec/ruby/core/nil/to_s_spec.rb b/spec/ruby/core/nil/to_s_spec.rb
index fa0b929677..016ba4165a 100644
--- a/spec/ruby/core/nil/to_s_spec.rb
+++ b/spec/ruby/core/nil/to_s_spec.rb
@@ -10,6 +10,6 @@ describe "NilClass#to_s" do
end
it "always returns the same string" do
- nil.to_s.should equal(nil.to_s)
+ nil.to_s.should.equal?(nil.to_s)
end
end
diff --git a/spec/ruby/core/numeric/abs2_spec.rb b/spec/ruby/core/numeric/abs2_spec.rb
index 0e60cd0ae7..12866f9c47 100644
--- a/spec/ruby/core/numeric/abs2_spec.rb
+++ b/spec/ruby/core/numeric/abs2_spec.rb
@@ -18,7 +18,7 @@ describe "Numeric#abs2" do
it "returns the square of the absolute value of self" do
@numbers.each do |number|
- number.abs2.should eql(number.abs ** 2)
+ number.abs2.should.eql?(number.abs ** 2)
end
end
@@ -29,6 +29,6 @@ describe "Numeric#abs2" do
end
it "returns NaN when self is NaN" do
- nan_value.abs2.nan?.should be_true
+ nan_value.abs2.nan?.should == true
end
end
diff --git a/spec/ruby/core/numeric/clone_spec.rb b/spec/ruby/core/numeric/clone_spec.rb
index 423cec85dd..1d06fdb050 100644
--- a/spec/ruby/core/numeric/clone_spec.rb
+++ b/spec/ruby/core/numeric/clone_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "Numeric#clone" do
it "returns self" do
value = 1
- value.clone.should equal(value)
+ value.clone.should.equal?(value)
subclass = Class.new(Numeric)
value = subclass.new
- value.clone.should equal(value)
+ value.clone.should.equal?(value)
end
it "does not change frozen status" do
@@ -16,15 +16,15 @@ describe "Numeric#clone" do
it "accepts optional keyword argument :freeze" do
value = 1
- value.clone(freeze: true).should equal(value)
+ value.clone(freeze: true).should.equal?(value)
end
it "raises ArgumentError if passed freeze: false" do
- -> { 1.clone(freeze: false) }.should raise_error(ArgumentError, /can't unfreeze/)
+ -> { 1.clone(freeze: false) }.should.raise(ArgumentError, /can't unfreeze/)
end
it "does not change frozen status if passed freeze: nil" do
value = 1
- value.clone(freeze: nil).should equal(value)
+ value.clone(freeze: nil).should.equal?(value)
end
end
diff --git a/spec/ruby/core/numeric/coerce_spec.rb b/spec/ruby/core/numeric/coerce_spec.rb
index 4c4416d30b..9344d99ee6 100644
--- a/spec/ruby/core/numeric/coerce_spec.rb
+++ b/spec/ruby/core/numeric/coerce_spec.rb
@@ -25,7 +25,7 @@ describe "Numeric#coerce" do
class << a; true; end
# watch it explode
- -> { a.coerce(b) }.should raise_error(TypeError)
+ -> { a.coerce(b) }.should.raise(TypeError)
end
end
@@ -38,22 +38,22 @@ describe "Numeric#coerce" do
it "raise TypeError if they are instances of different classes and other does not respond to #to_f" do
other = mock("numeric")
- -> { @obj.coerce(other) }.should raise_error(TypeError)
+ -> { @obj.coerce(other) }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @obj.coerce(nil) }.should raise_error(TypeError)
+ -> { @obj.coerce(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a boolean" do
- -> { @obj.coerce(false) }.should raise_error(TypeError)
+ -> { @obj.coerce(false) }.should.raise(TypeError)
end
it "raises a TypeError when passed a Symbol" do
- -> { @obj.coerce(:symbol) }.should raise_error(TypeError)
+ -> { @obj.coerce(:symbol) }.should.raise(TypeError)
end
it "raises an ArgumentError when passed a non-numeric String" do
- -> { @obj.coerce("test") }.should raise_error(ArgumentError)
+ -> { @obj.coerce("test") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/numeric/comparison_spec.rb b/spec/ruby/core/numeric/comparison_spec.rb
index 4b4d52501a..b0a9390cc0 100644
--- a/spec/ruby/core/numeric/comparison_spec.rb
+++ b/spec/ruby/core/numeric/comparison_spec.rb
@@ -26,22 +26,22 @@ describe "Numeric#<=>" do
end
it "is called when instances are compared with #<" do
- (@a < @b).should be_false
+ (@a < @b).should == false
ScratchPad.recorded.should == :numeric_comparison
end
it "is called when instances are compared with #<=" do
- (@a <= @b).should be_false
+ (@a <= @b).should == false
ScratchPad.recorded.should == :numeric_comparison
end
it "is called when instances are compared with #>" do
- (@a > @b).should be_true
+ (@a > @b).should == true
ScratchPad.recorded.should == :numeric_comparison
end
it "is called when instances are compared with #>=" do
- (@a >= @b).should be_true
+ (@a >= @b).should == true
ScratchPad.recorded.should == :numeric_comparison
end
end
diff --git a/spec/ruby/core/numeric/div_spec.rb b/spec/ruby/core/numeric/div_spec.rb
index 53917b84c9..a17961850c 100644
--- a/spec/ruby/core/numeric/div_spec.rb
+++ b/spec/ruby/core/numeric/div_spec.rb
@@ -15,8 +15,8 @@ describe "Numeric#div" do
end
it "raises ZeroDivisionError for 0" do
- -> { @obj.div(0) }.should raise_error(ZeroDivisionError)
- -> { @obj.div(0.0) }.should raise_error(ZeroDivisionError)
- -> { @obj.div(Complex(0,0)) }.should raise_error(ZeroDivisionError)
+ -> { @obj.div(0) }.should.raise(ZeroDivisionError)
+ -> { @obj.div(0.0) }.should.raise(ZeroDivisionError)
+ -> { @obj.div(Complex(0,0)) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/numeric/dup_spec.rb b/spec/ruby/core/numeric/dup_spec.rb
index 189a7ef44d..c158c618de 100644
--- a/spec/ruby/core/numeric/dup_spec.rb
+++ b/spec/ruby/core/numeric/dup_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "Numeric#dup" do
it "returns self" do
value = 1
- value.dup.should equal(value)
+ value.dup.should.equal?(value)
subclass = Class.new(Numeric)
value = subclass.new
- value.dup.should equal(value)
+ value.dup.should.equal?(value)
end
it "does not change frozen status" do
diff --git a/spec/ruby/core/numeric/eql_spec.rb b/spec/ruby/core/numeric/eql_spec.rb
index b33e00e51f..80c58caef4 100644
--- a/spec/ruby/core/numeric/eql_spec.rb
+++ b/spec/ruby/core/numeric/eql_spec.rb
@@ -7,16 +7,16 @@ describe "Numeric#eql?" do
end
it "returns false if self's and other's types don't match" do
- @obj.should_not eql(1)
- @obj.should_not eql(-1.5)
- @obj.should_not eql(bignum_value)
- @obj.should_not eql(:sym)
+ @obj.should_not.eql?(1)
+ @obj.should_not.eql?(-1.5)
+ @obj.should_not.eql?(bignum_value)
+ @obj.should_not.eql?(:sym)
end
it "returns the result of calling self#== with other when self's and other's types match" do
other = NumericSpecs::Subclass.new
@obj.should_receive(:==).with(other).and_return("result", nil)
- @obj.should eql(other)
- @obj.should_not eql(other)
+ @obj.should.eql?(other)
+ @obj.should_not.eql?(other)
end
end
diff --git a/spec/ruby/core/numeric/fdiv_spec.rb b/spec/ruby/core/numeric/fdiv_spec.rb
index e97fa77f79..2c22c6a86a 100644
--- a/spec/ruby/core/numeric/fdiv_spec.rb
+++ b/spec/ruby/core/numeric/fdiv_spec.rb
@@ -18,7 +18,7 @@ describe "Numeric#fdiv" do
end
it "returns a Float" do
- bignum_value.fdiv(Float::MAX).should be_an_instance_of(Float)
+ bignum_value.fdiv(Float::MAX).should.instance_of?(Float)
end
it "returns Infinity if other is 0" do
@@ -26,6 +26,6 @@ describe "Numeric#fdiv" do
end
it "returns NaN if other is NaN" do
- 3334.fdiv(nan_value).nan?.should be_true
+ 3334.fdiv(nan_value).nan?.should == true
end
end
diff --git a/spec/ruby/core/numeric/finite_spec.rb b/spec/ruby/core/numeric/finite_spec.rb
index 05b5eebbd6..2c18c89466 100644
--- a/spec/ruby/core/numeric/finite_spec.rb
+++ b/spec/ruby/core/numeric/finite_spec.rb
@@ -3,6 +3,6 @@ require_relative '../../spec_helper'
describe "Numeric#finite?" do
it "returns true by default" do
o = mock_numeric("finite")
- o.finite?.should be_true
+ o.finite?.should == true
end
end
diff --git a/spec/ruby/core/numeric/i_spec.rb b/spec/ruby/core/numeric/i_spec.rb
index 621ecc09ec..f5fb99dfd3 100644
--- a/spec/ruby/core/numeric/i_spec.rb
+++ b/spec/ruby/core/numeric/i_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Numeric#i" do
it "returns a Complex object" do
- 34.i.should be_an_instance_of(Complex)
+ 34.i.should.instance_of?(Complex)
end
it "sets the real part to 0" do
diff --git a/spec/ruby/core/numeric/negative_spec.rb b/spec/ruby/core/numeric/negative_spec.rb
index 9c6f95fd87..f2d8a847da 100644
--- a/spec/ruby/core/numeric/negative_spec.rb
+++ b/spec/ruby/core/numeric/negative_spec.rb
@@ -4,22 +4,22 @@ require_relative 'fixtures/classes'
describe "Numeric#negative?" do
describe "on positive numbers" do
it "returns false" do
- 1.negative?.should be_false
- 0.1.negative?.should be_false
+ 1.negative?.should == false
+ 0.1.negative?.should == false
end
end
describe "on zero" do
it "returns false" do
- 0.negative?.should be_false
- 0.0.negative?.should be_false
+ 0.negative?.should == false
+ 0.0.negative?.should == false
end
end
describe "on negative numbers" do
it "returns true" do
- -1.negative?.should be_true
- -0.1.negative?.should be_true
+ -1.negative?.should == true
+ -0.1.negative?.should == true
end
end
end
diff --git a/spec/ruby/core/numeric/polar_spec.rb b/spec/ruby/core/numeric/polar_spec.rb
index b594e408b2..0695d7afb2 100644
--- a/spec/ruby/core/numeric/polar_spec.rb
+++ b/spec/ruby/core/numeric/polar_spec.rb
@@ -17,7 +17,7 @@ describe "Numeric#polar" do
it "returns a two-element Array" do
@numbers.each do |number|
- number.polar.should be_an_instance_of(Array)
+ number.polar.should.instance_of?(Array)
number.polar.size.should == 2
end
end
@@ -44,7 +44,7 @@ describe "Numeric#polar" do
it "returns [NaN, NaN] if self is NaN" do
nan_value.polar.size.should == 2
- nan_value.polar.first.nan?.should be_true
- nan_value.polar.last.nan?.should be_true
+ nan_value.polar.first.nan?.should == true
+ nan_value.polar.last.nan?.should == true
end
end
diff --git a/spec/ruby/core/numeric/positive_spec.rb b/spec/ruby/core/numeric/positive_spec.rb
index 3b831b4d34..7c8d15cd9f 100644
--- a/spec/ruby/core/numeric/positive_spec.rb
+++ b/spec/ruby/core/numeric/positive_spec.rb
@@ -4,22 +4,22 @@ require_relative 'fixtures/classes'
describe "Numeric#positive?" do
describe "on positive numbers" do
it "returns true" do
- 1.positive?.should be_true
- 0.1.positive?.should be_true
+ 1.positive?.should == true
+ 0.1.positive?.should == true
end
end
describe "on zero" do
it "returns false" do
- 0.positive?.should be_false
- 0.0.positive?.should be_false
+ 0.positive?.should == false
+ 0.0.positive?.should == false
end
end
describe "on negative numbers" do
it "returns false" do
- -1.positive?.should be_false
- -0.1.positive?.should be_false
+ -1.positive?.should == false
+ -0.1.positive?.should == false
end
end
end
diff --git a/spec/ruby/core/numeric/quo_spec.rb b/spec/ruby/core/numeric/quo_spec.rb
index 6e3ce7a374..66ff019231 100644
--- a/spec/ruby/core/numeric/quo_spec.rb
+++ b/spec/ruby/core/numeric/quo_spec.rb
@@ -3,11 +3,11 @@ require_relative 'fixtures/classes'
describe "Numeric#quo" do
it "returns the result of self divided by the given Integer as a Rational" do
- 5.quo(2).should eql(Rational(5,2))
+ 5.quo(2).should.eql?(Rational(5,2))
end
it "returns the result of self divided by the given Float as a Float" do
- 2.quo(2.5).should eql(0.8)
+ 2.quo(2.5).should.eql?(0.8)
end
it "returns the result of self divided by the given Bignum as a Float" do
@@ -15,11 +15,11 @@ describe "Numeric#quo" do
end
it "raises a ZeroDivisionError when the given Integer is 0" do
- -> { 0.quo(0) }.should raise_error(ZeroDivisionError)
- -> { 10.quo(0) }.should raise_error(ZeroDivisionError)
- -> { -10.quo(0) }.should raise_error(ZeroDivisionError)
- -> { bignum_value.quo(0) }.should raise_error(ZeroDivisionError)
- -> { (-bignum_value).quo(0) }.should raise_error(ZeroDivisionError)
+ -> { 0.quo(0) }.should.raise(ZeroDivisionError)
+ -> { 10.quo(0) }.should.raise(ZeroDivisionError)
+ -> { -10.quo(0) }.should.raise(ZeroDivisionError)
+ -> { bignum_value.quo(0) }.should.raise(ZeroDivisionError)
+ -> { (-bignum_value).quo(0) }.should.raise(ZeroDivisionError)
end
it "calls #to_r to convert the object to a Rational" do
@@ -33,16 +33,16 @@ describe "Numeric#quo" do
obj = NumericSpecs::Subclass.new
obj.should_receive(:to_r).and_return(1)
- -> { obj.quo(19) }.should raise_error(TypeError)
+ -> { obj.quo(19) }.should.raise(TypeError)
end
it "raises a TypeError when given a non-Integer" do
-> {
(obj = mock('x')).should_not_receive(:to_int)
13.quo(obj)
- }.should raise_error(TypeError)
- -> { 13.quo("10") }.should raise_error(TypeError)
- -> { 13.quo(:symbol) }.should raise_error(TypeError)
+ }.should.raise(TypeError)
+ -> { 13.quo("10") }.should.raise(TypeError)
+ -> { 13.quo(:symbol) }.should.raise(TypeError)
end
it "returns the result of calling self#/ with other" do
@@ -53,7 +53,7 @@ describe "Numeric#quo" do
end
it "raises a ZeroDivisionError if the given argument is zero and not a Float" do
- -> { 1.quo(0) }.should raise_error(ZeroDivisionError)
+ -> { 1.quo(0) }.should.raise(ZeroDivisionError)
end
it "returns infinity if the given argument is zero and is a Float" do
diff --git a/spec/ruby/core/numeric/real_spec.rb b/spec/ruby/core/numeric/real_spec.rb
index 2d2499bcce..09d482a691 100644
--- a/spec/ruby/core/numeric/real_spec.rb
+++ b/spec/ruby/core/numeric/real_spec.rb
@@ -16,7 +16,7 @@ describe "Numeric#real" do
it "returns self" do
@numbers.each do |number|
if number.to_f.nan?
- number.real.nan?.should be_true
+ number.real.nan?.should == true
else
number.real.should == number
end
@@ -25,7 +25,7 @@ describe "Numeric#real" do
it "raises an ArgumentError if given any arguments" do
@numbers.each do |number|
- -> { number.real(number) }.should raise_error(ArgumentError)
+ -> { number.real(number) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/numeric/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb
index 674fa22d8e..bdf7358b21 100644
--- a/spec/ruby/core/numeric/remainder_spec.rb
+++ b/spec/ruby/core/numeric/remainder_spec.rb
@@ -6,16 +6,14 @@ describe "Numeric#remainder" do
@obj = NumericSpecs::Subclass.new
@result = mock("Numeric#% result")
@other = mock("Passed Object")
- ruby_version_is "3.3" do
- @other.should_receive(:coerce).with(@obj).and_return([@obj, @other])
- end
+ @other.should_receive(:coerce).with(@obj).and_return([@obj, @other])
end
it "returns the result of calling self#% with other if self is 0" do
@obj.should_receive(:%).with(@other).and_return(@result)
@result.should_receive(:==).with(0).and_return(true)
- @obj.remainder(@other).should equal(@result)
+ @obj.remainder(@other).should.equal?(@result)
end
it "returns the result of calling self#% with other if self and other are greater than 0" do
@@ -27,7 +25,7 @@ describe "Numeric#remainder" do
@obj.should_receive(:>).with(0).and_return(true)
@other.should_receive(:<).with(0).and_return(false)
- @obj.remainder(@other).should equal(@result)
+ @obj.remainder(@other).should.equal?(@result)
end
it "returns the result of calling self#% with other if self and other are less than 0" do
@@ -39,7 +37,7 @@ describe "Numeric#remainder" do
@obj.should_receive(:>).with(0).and_return(false)
- @obj.remainder(@other).should equal(@result)
+ @obj.remainder(@other).should.equal?(@result)
end
it "returns the result of calling self#% with other - other if self is greater than 0 and other is less than 0" do
diff --git a/spec/ruby/core/numeric/shared/conj.rb b/spec/ruby/core/numeric/shared/conj.rb
index 6d5197ecab..1a661fbbe8 100644
--- a/spec/ruby/core/numeric/shared/conj.rb
+++ b/spec/ruby/core/numeric/shared/conj.rb
@@ -14,7 +14,7 @@ describe :numeric_conj, shared: true do
it "returns self" do
@numbers.each do |number|
- number.send(@method).should equal(number)
+ number.send(@method).should.equal?(number)
end
end
end
diff --git a/spec/ruby/core/numeric/shared/imag.rb b/spec/ruby/core/numeric/shared/imag.rb
index 4f117e243a..605a23d8c6 100644
--- a/spec/ruby/core/numeric/shared/imag.rb
+++ b/spec/ruby/core/numeric/shared/imag.rb
@@ -20,7 +20,7 @@ describe :numeric_imag, shared: true do
it "raises an ArgumentError if given any arguments" do
@numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
+ -> { number.send(@method, number) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/numeric/shared/rect.rb b/spec/ruby/core/numeric/shared/rect.rb
index 120a69b1c4..32d03e45d2 100644
--- a/spec/ruby/core/numeric/shared/rect.rb
+++ b/spec/ruby/core/numeric/shared/rect.rb
@@ -14,7 +14,7 @@ describe :numeric_rect, shared: true do
it "returns an Array" do
@numbers.each do |number|
- number.send(@method).should be_an_instance_of(Array)
+ number.send(@method).should.instance_of?(Array)
end
end
@@ -27,7 +27,7 @@ describe :numeric_rect, shared: true do
it "returns self as the first element" do
@numbers.each do |number|
if Float === number and number.nan?
- number.send(@method).first.nan?.should be_true
+ number.send(@method).first.nan?.should == true
else
number.send(@method).first.should == number
end
@@ -42,7 +42,7 @@ describe :numeric_rect, shared: true do
it "raises an ArgumentError if given any arguments" do
@numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
+ -> { number.send(@method, number) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb
index 977ec6de02..66b8c1af0d 100644
--- a/spec/ruby/core/numeric/shared/step.rb
+++ b/spec/ruby/core/numeric/shared/step.rb
@@ -13,7 +13,7 @@ describe :numeric_step, shared: true do
it "defaults to step = 1" do
@step.call(1, 5, &@prc)
- ScratchPad.recorded.should eql [1, 2, 3, 4, 5]
+ ScratchPad.recorded.should.eql? [1, 2, 3, 4, 5]
end
it "defaults to an infinite limit with a step size of 1 for Integers" do
@@ -26,35 +26,35 @@ describe :numeric_step, shared: true do
describe "when self, stop and step are Integers" do
it "yields only Integers" do
- @step.call(1, 5, 1) { |x| x.should be_an_instance_of(Integer) }
+ @step.call(1, 5, 1) { |x| x.should.instance_of?(Integer) }
end
describe "with a positive step" do
it "yields while increasing self by step until stop is reached" do
@step.call(1, 5, 1, &@prc)
- ScratchPad.recorded.should eql [1, 2, 3, 4, 5]
+ ScratchPad.recorded.should.eql? [1, 2, 3, 4, 5]
end
it "yields once when self equals stop" do
@step.call(1, 1, 1, &@prc)
- ScratchPad.recorded.should eql [1]
+ ScratchPad.recorded.should.eql? [1]
end
it "does not yield when self is greater than stop" do
@step.call(2, 1, 1, &@prc)
- ScratchPad.recorded.should eql []
+ ScratchPad.recorded.should.eql? []
end
end
describe "with a negative step" do
it "yields while decreasing self by step until stop is reached" do
@step.call(5, 1, -1, &@prc)
- ScratchPad.recorded.should eql [5, 4, 3, 2, 1]
+ ScratchPad.recorded.should.eql? [5, 4, 3, 2, 1]
end
it "yields once when self equals stop" do
@step.call(5, 5, -1, &@prc)
- ScratchPad.recorded.should eql [5]
+ ScratchPad.recorded.should.eql? [5]
end
it "does not yield when self is less than stop" do
@@ -66,26 +66,26 @@ describe :numeric_step, shared: true do
describe "when at least one of self, stop or step is a Float" do
it "yields Floats even if only self is a Float" do
- @step.call(1.5, 5, 1) { |x| x.should be_an_instance_of(Float) }
+ @step.call(1.5, 5, 1) { |x| x.should.instance_of?(Float) }
end
it "yields Floats even if only stop is a Float" do
- @step.call(1, 5.0, 1) { |x| x.should be_an_instance_of(Float) }
+ @step.call(1, 5.0, 1) { |x| x.should.instance_of?(Float) }
end
it "yields Floats even if only step is a Float" do
- @step.call(1, 5, 1.0) { |x| x.should be_an_instance_of(Float) }
+ @step.call(1, 5, 1.0) { |x| x.should.instance_of?(Float) }
end
describe "with a positive step" do
it "yields while increasing self by step while < stop" do
@step.call(1.5, 5, 1, &@prc)
- ScratchPad.recorded.should eql [1.5, 2.5, 3.5, 4.5]
+ ScratchPad.recorded.should.eql? [1.5, 2.5, 3.5, 4.5]
end
it "yields once when self equals stop" do
@step.call(1.5, 1.5, 1, &@prc)
- ScratchPad.recorded.should eql [1.5]
+ ScratchPad.recorded.should.eql? [1.5]
end
it "does not yield when self is greater than stop" do
@@ -96,19 +96,19 @@ describe :numeric_step, shared: true do
it "is careful about not yielding a value greater than limit" do
# As 9*1.3+1.0 == 12.700000000000001 > 12.7, we test:
@step.call(1.0, 12.7, 1.3, &@prc)
- ScratchPad.recorded.should eql [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]
+ ScratchPad.recorded.should.eql? [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]
end
end
describe "with a negative step" do
it "yields while decreasing self by step while self > stop" do
@step.call(5, 1.5, -1, &@prc)
- ScratchPad.recorded.should eql [5.0, 4.0, 3.0, 2.0]
+ ScratchPad.recorded.should.eql? [5.0, 4.0, 3.0, 2.0]
end
it "yields once when self equals stop" do
@step.call(1.5, 1.5, -1, &@prc)
- ScratchPad.recorded.should eql [1.5]
+ ScratchPad.recorded.should.eql? [1.5]
end
it "does not yield when self is less than stop" do
@@ -119,24 +119,24 @@ describe :numeric_step, shared: true do
it "is careful about not yielding a value smaller than limit" do
# As -9*1.3-1.0 == -12.700000000000001 < -12.7, we test:
@step.call(-1.0, -12.7, -1.3, &@prc)
- ScratchPad.recorded.should eql [-1.0, -2.3, -3.6, -4.9, -6.2, -7.5, -8.8, -10.1, -11.4, -12.7]
+ ScratchPad.recorded.should.eql? [-1.0, -2.3, -3.6, -4.9, -6.2, -7.5, -8.8, -10.1, -11.4, -12.7]
end
end
describe "with a positive Infinity step" do
it "yields once if self < stop" do
@step.call(42, 100, infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when stop is Infinity" do
@step.call(42, infinity_value, infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self equals stop" do
@step.call(42, 42, infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self and stop are Infinity" do
@@ -159,17 +159,17 @@ describe :numeric_step, shared: true do
describe "with a negative Infinity step" do
it "yields once if self > stop" do
@step.call(42, 6, -infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once if stop is -Infinity" do
@step.call(42, -infinity_value, -infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self equals stop" do
@step.call(42, 42, -infinity_value, &@prc)
- ScratchPad.recorded.should eql [42.0]
+ ScratchPad.recorded.should.eql? [42.0]
end
it "yields once when self and stop are Infinity" do
@@ -226,60 +226,60 @@ describe :numeric_step, shared: true do
describe "when step is a String" do
describe "with self and stop as Integers" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1, 5, "1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "0.1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "1/3") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "0.1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "1/3") {} }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1, 5, "foo") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "foo") {} }.should.raise(ArgumentError)
end
end
describe "with self and stop as Floats" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1.1, 5.1, "1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "0.1") {} }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "1/3") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "0.1") {} }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1/3") {} }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1.1, 5.1, "foo") {} }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "foo") {} }.should.raise(ArgumentError)
end
end
end
it "does not rescue ArgumentError exceptions" do
- -> { @step.call(1, 2) { raise ArgumentError, "" }}.should raise_error(ArgumentError)
+ -> { @step.call(1, 2) { raise ArgumentError, "" }}.should.raise(ArgumentError)
end
it "does not rescue TypeError exceptions" do
- -> { @step.call(1, 2) { raise TypeError, "" } }.should raise_error(TypeError)
+ -> { @step.call(1, 2) { raise TypeError, "" } }.should.raise(TypeError)
end
describe "when no block is given" do
step_enum_class = Enumerator::ArithmeticSequence
it "returns an #{step_enum_class} when not passed a block and self > stop" do
- @step.call(1, 0, 2).should be_an_instance_of(step_enum_class)
+ @step.call(1, 0, 2).should.instance_of?(step_enum_class)
end
it "returns an #{step_enum_class} when not passed a block and self < stop" do
- @step.call(1, 2, 3).should be_an_instance_of(step_enum_class)
+ @step.call(1, 2, 3).should.instance_of?(step_enum_class)
end
it "returns an #{step_enum_class} that uses the given step" do
- @step.call(0, 5, 2).to_a.should eql [0, 2, 4]
+ @step.call(0, 5, 2).to_a.should.eql? [0, 2, 4]
end
describe "when step is a String" do
describe "with self and stop as Integers" do
it "returns an Enumerator" do
- @step.call(1, 5, "foo").should be_an_instance_of(Enumerator)
+ @step.call(1, 5, "foo").should.instance_of?(Enumerator)
end
end
describe "with self and stop as Floats" do
it "returns an Enumerator" do
- @step.call(1.1, 5.1, "foo").should be_an_instance_of(Enumerator)
+ @step.call(1.1, 5.1, "foo").should.instance_of?(Enumerator)
end
end
end
@@ -289,23 +289,23 @@ describe :numeric_step, shared: true do
describe "when step is a String" do
describe "with self and stop as Integers" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1, 5, "1").size }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "0.1").size }.should raise_error(ArgumentError)
- -> { @step.call(1, 5, "1/3").size }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "1").size }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "0.1").size }.should.raise(ArgumentError)
+ -> { @step.call(1, 5, "1/3").size }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1, 5, "foo").size }.should raise_error(ArgumentError)
+ -> { @step.call(1, 5, "foo").size }.should.raise(ArgumentError)
end
end
describe "with self and stop as Floats" do
it "raises an ArgumentError when step is a numeric representation" do
- -> { @step.call(1.1, 5.1, "1").size }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "0.1").size }.should raise_error(ArgumentError)
- -> { @step.call(1.1, 5.1, "1/3").size }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1").size }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "0.1").size }.should.raise(ArgumentError)
+ -> { @step.call(1.1, 5.1, "1/3").size }.should.raise(ArgumentError)
end
it "raises an ArgumentError with step as an alphanumeric string" do
- -> { @step.call(1.1, 5.1, "foo").size }.should raise_error(ArgumentError)
+ -> { @step.call(1.1, 5.1, "foo").size }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/numeric/singleton_method_added_spec.rb b/spec/ruby/core/numeric/singleton_method_added_spec.rb
index 2091398e5d..327bb5662a 100644
--- a/spec/ruby/core/numeric/singleton_method_added_spec.rb
+++ b/spec/ruby/core/numeric/singleton_method_added_spec.rb
@@ -21,21 +21,21 @@ describe "Numeric#singleton_method_added" do
-> do
a = NumericSpecs::Subclass.new
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
a = 1
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
a = 1.5
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
a = bignum_value
def a.test; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb
index 1705fb1b4e..6896009eb6 100644
--- a/spec/ruby/core/numeric/step_spec.rb
+++ b/spec/ruby/core/numeric/step_spec.rb
@@ -6,11 +6,11 @@ describe "Numeric#step" do
describe 'with positional args' do
it "raises an ArgumentError when step is 0" do
- -> { 1.step(5, 0) {} }.should raise_error(ArgumentError)
+ -> { 1.step(5, 0) {} }.should.raise(ArgumentError)
end
it "raises an ArgumentError when step is 0.0" do
- -> { 1.step(2, 0.0) {} }.should raise_error(ArgumentError)
+ -> { 1.step(2, 0.0) {} }.should.raise(ArgumentError)
end
before :all do
@@ -81,19 +81,19 @@ describe "Numeric#step" do
describe 'with mixed arguments' do
it " raises an ArgumentError when step is 0" do
- -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(5, by: 0) { break } }.should.raise(ArgumentError)
end
it "raises an ArgumentError when step is 0.0" do
- -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(2, by: 0.0) { break } }.should.raise(ArgumentError)
end
it "raises a ArgumentError when limit and to are defined" do
- -> { 1.step(5, 1, to: 5) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(5, 1, to: 5) { break } }.should.raise(ArgumentError)
end
it "raises a ArgumentError when step and by are defined" do
- -> { 1.step(5, 1, by: 5) { break } }.should raise_error(ArgumentError)
+ -> { 1.step(5, 1, by: 5) { break } }.should.raise(ArgumentError)
end
describe "when no block is given" do
diff --git a/spec/ruby/core/numeric/to_c_spec.rb b/spec/ruby/core/numeric/to_c_spec.rb
index 75245a612e..70b7a9dd0c 100644
--- a/spec/ruby/core/numeric/to_c_spec.rb
+++ b/spec/ruby/core/numeric/to_c_spec.rb
@@ -22,7 +22,7 @@ describe "Numeric#to_c" do
it "returns a Complex object" do
@numbers.each do |number|
- number.to_c.should be_an_instance_of(Complex)
+ number.to_c.should.instance_of?(Complex)
end
end
@@ -30,7 +30,7 @@ describe "Numeric#to_c" do
@numbers.each do |number|
real = number.to_c.real
if Float === number and number.nan?
- real.nan?.should be_true
+ real.nan?.should == true
else
real.should == number
end
diff --git a/spec/ruby/core/objectspace/_id2ref_spec.rb b/spec/ruby/core/objectspace/_id2ref_spec.rb
index c088ae2743..a9fd526b7d 100644
--- a/spec/ruby/core/objectspace/_id2ref_spec.rb
+++ b/spec/ruby/core/objectspace/_id2ref_spec.rb
@@ -1,52 +1,65 @@
require_relative '../../spec_helper'
-describe "ObjectSpace._id2ref" do
- it "converts an object id to a reference to the object" do
- s = "I am a string"
- r = ObjectSpace._id2ref(s.object_id)
- r.should == s
+ruby_version_is "4.0" do
+ describe "ObjectSpace._id2ref" do
+ it "is deprecated" do
+ id = nil.object_id
+ -> {
+ ObjectSpace._id2ref(id)
+ }.should complain(/warning: ObjectSpace\._id2ref is deprecated/)
+ end
end
+end
- it "retrieves true by object_id" do
- ObjectSpace._id2ref(true.object_id).should == true
- end
+ruby_version_is ""..."4.0" do
+ describe "ObjectSpace._id2ref" do
+ it "converts an object id to a reference to the object" do
+ s = "I am a string"
+ r = ObjectSpace._id2ref(s.object_id)
+ r.should == s
+ end
- it "retrieves false by object_id" do
- ObjectSpace._id2ref(false.object_id).should == false
- end
+ it "retrieves true by object_id" do
+ ObjectSpace._id2ref(true.object_id).should == true
+ end
- it "retrieves nil by object_id" do
- ObjectSpace._id2ref(nil.object_id).should == nil
- end
+ it "retrieves false by object_id" do
+ ObjectSpace._id2ref(false.object_id).should == false
+ end
- it "retrieves a small Integer by object_id" do
- ObjectSpace._id2ref(1.object_id).should == 1
- ObjectSpace._id2ref((-42).object_id).should == -42
- end
+ it "retrieves nil by object_id" do
+ ObjectSpace._id2ref(nil.object_id).should == nil
+ end
- it "retrieves a large Integer by object_id" do
- obj = 1 << 88
- ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
- end
+ it "retrieves a small Integer by object_id" do
+ ObjectSpace._id2ref(1.object_id).should == 1
+ ObjectSpace._id2ref((-42).object_id).should == -42
+ end
- it "retrieves a Symbol by object_id" do
- ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym)
- end
+ it "retrieves a large Integer by object_id" do
+ obj = 1 << 88
+ ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
+ end
- it "retrieves a String by object_id" do
- obj = "str"
- ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
- end
+ it "retrieves a Symbol by object_id" do
+ ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym)
+ end
- it "retrieves a frozen literal String by object_id" do
- ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze)
- end
+ it "retrieves a String by object_id" do
+ obj = "str"
+ ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
+ end
- it "retrieves an Encoding by object_id" do
- ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8)
- end
+ it "retrieves a frozen literal String by object_id" do
+ ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze)
+ end
+
+ it "retrieves an Encoding by object_id" do
+ ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8)
+ end
- it 'raises RangeError when an object could not be found' do
- proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError)
+ it 'raises RangeError when an object could not be found' do
+ proc { ObjectSpace._id2ref(1 << 60) }.should.raise(RangeError)
+ end
end
end
diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb
index 0f4b54c345..5441cb4a21 100644
--- a/spec/ruby/core/objectspace/define_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb
@@ -13,7 +13,7 @@ describe "ObjectSpace.define_finalizer" do
it "raises an ArgumentError if the action does not respond to call" do
-> {
ObjectSpace.define_finalizer(Object.new, mock("ObjectSpace.define_finalizer no #call"))
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "accepts an object and a proc" do
@@ -42,7 +42,7 @@ describe "ObjectSpace.define_finalizer" do
it "raises ArgumentError trying to define a finalizer on a non-reference" do
-> {
ObjectSpace.define_finalizer(:blah) { 1 }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
# see [ruby-core:24095]
@@ -57,7 +57,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("finalizer run\n")
+ ruby_exe(code, :args => "2>&1").should.include?("finalizer run\n")
end
it "warns if the finalizer has the object as the receiver" do
@@ -73,7 +73,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ ruby_exe(code, :args => "2>&1").should.include?("warning: finalizer references object to be finalized\n")
end
it "warns if the finalizer is a method bound to the receiver" do
@@ -90,7 +90,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ ruby_exe(code, :args => "2>&1").should.include?("warning: finalizer references object to be finalized\n")
end
it "warns if the finalizer was a block in the receiver" do
@@ -106,7 +106,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ ruby_exe(code, :args => "2>&1").should.include?("warning: finalizer references object to be finalized\n")
end
it "calls a finalizer at exit even if it is self-referencing" do
@@ -117,7 +117,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code).should include("finalizer run\n")
+ ruby_exe(code).should.include?("finalizer run\n")
end
it "calls a finalizer at exit even if it is indirectly self-referencing" do
@@ -136,7 +136,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("finalizer run\n")
+ ruby_exe(code, :args => "2>&1").should.include?("finalizer run\n")
end
it "calls a finalizer defined in a finalizer running at exit" do
@@ -152,7 +152,7 @@ describe "ObjectSpace.define_finalizer" do
exit 0
RUBY
- ruby_exe(code, :args => "2>&1").should include("finalizer 2 run\n")
+ ruby_exe(code, :args => "2>&1").should.include?("finalizer 2 run\n")
end
it "allows multiple finalizers with different 'callables' to be defined" do
@@ -199,7 +199,9 @@ describe "ObjectSpace.define_finalizer" do
ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
RUBY
- ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
+ out = ruby_exe(code, args: "2>&1")
+ out.should.include?("warning: Exception in finalizer")
+ out.should.include?("finalizing")
end
end
diff --git a/spec/ruby/core/objectspace/each_object_spec.rb b/spec/ruby/core/objectspace/each_object_spec.rb
index 09a582afaf..aee0fd629c 100644
--- a/spec/ruby/core/objectspace/each_object_spec.rb
+++ b/spec/ruby/core/objectspace/each_object_spec.rb
@@ -39,7 +39,7 @@ describe "ObjectSpace.each_object" do
new_obj = klass.new
counter = ObjectSpace.each_object(klass)
- counter.should be_an_instance_of(Enumerator)
+ counter.should.instance_of?(Enumerator)
counter.each{}.should == 1
# this is needed to prevent the new_obj from being GC'd too early
new_obj.should_not == nil
@@ -47,20 +47,20 @@ describe "ObjectSpace.each_object" do
it "finds an object stored in a global variable" do
$object_space_global_variable = ObjectSpaceFixtures::ObjectToBeFound.new(:global)
- ObjectSpaceFixtures.to_be_found_symbols.should include(:global)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:global)
end
it "finds an object stored in a top-level constant" do
- ObjectSpaceFixtures.to_be_found_symbols.should include(:top_level_constant)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:top_level_constant)
end
it "finds an object stored in a second-level constant" do
- ObjectSpaceFixtures.to_be_found_symbols.should include(:second_level_constant)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:second_level_constant)
end
it "finds an object stored in a local variable" do
local = ObjectSpaceFixtures::ObjectToBeFound.new(:local)
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local)
end
it "finds an object stored in a local variable captured in a block explicitly" do
@@ -69,7 +69,7 @@ describe "ObjectSpace.each_object" do
Proc.new { local_in_block }
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_block_explicit)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_block_explicit)
end
it "finds an object stored in a local variable captured in a block implicitly" do
@@ -78,11 +78,11 @@ describe "ObjectSpace.each_object" do
Proc.new { }
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_block_implicit)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_block_implicit)
end
it "finds an object stored in a local variable captured in by a method defined with a block" do
- ObjectSpaceFixtures.to_be_found_symbols.should include(:captured_by_define_method)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:captured_by_define_method)
end
it "finds an object stored in a local variable captured in a Proc#binding" do
@@ -91,7 +91,7 @@ describe "ObjectSpace.each_object" do
Proc.new { }.binding
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_proc_binding)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_proc_binding)
end
it "finds an object stored in a local variable captured in a Kernel#binding" do
@@ -100,45 +100,45 @@ describe "ObjectSpace.each_object" do
binding
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_kernel_binding)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_kernel_binding)
end
it "finds an object stored in a local variable set in a binding manually" do
b = binding
b.eval("local = ObjectSpaceFixtures::ObjectToBeFound.new(:local_in_manual_binding)")
- ObjectSpaceFixtures.to_be_found_symbols.should include(:local_in_manual_binding)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:local_in_manual_binding)
end
it "finds an object stored in an array" do
array = [ObjectSpaceFixtures::ObjectToBeFound.new(:array)]
- ObjectSpaceFixtures.to_be_found_symbols.should include(:array)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:array)
end
it "finds an object stored in a hash key" do
hash = {ObjectSpaceFixtures::ObjectToBeFound.new(:hash_key) => :value}
- ObjectSpaceFixtures.to_be_found_symbols.should include(:hash_key)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:hash_key)
end
it "finds an object stored in a hash value" do
hash = {a: ObjectSpaceFixtures::ObjectToBeFound.new(:hash_value)}
- ObjectSpaceFixtures.to_be_found_symbols.should include(:hash_value)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:hash_value)
end
it "finds an object stored in an instance variable" do
local = ObjectSpaceFixtures::ObjectWithInstanceVariable.new
- ObjectSpaceFixtures.to_be_found_symbols.should include(:instance_variable)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:instance_variable)
end
it "finds an object stored in a thread local" do
thread = Thread.new {}
thread.thread_variable_set(:object_space_thread_local, ObjectSpaceFixtures::ObjectToBeFound.new(:thread_local))
- ObjectSpaceFixtures.to_be_found_symbols.should include(:thread_local)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:thread_local)
thread.join
end
it "finds an object stored in a fiber local" do
Thread.current[:object_space_fiber_local] = ObjectSpaceFixtures::ObjectToBeFound.new(:fiber_local)
- ObjectSpaceFixtures.to_be_found_symbols.should include(:fiber_local)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:fiber_local)
end
it "finds an object captured in an at_exit handler" do
@@ -150,7 +150,7 @@ describe "ObjectSpace.each_object" do
end
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:at_exit)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:at_exit)
end
it "finds an object captured in finalizer" do
@@ -164,9 +164,9 @@ describe "ObjectSpace.each_object" do
})
}.call
- ObjectSpaceFixtures.to_be_found_symbols.should include(:finalizer)
+ ObjectSpaceFixtures.to_be_found_symbols.should.include?(:finalizer)
- alive.should_not be_nil
+ alive.should_not == nil
end
describe "on singleton classes" do
@@ -185,8 +185,8 @@ describe "ObjectSpace.each_object" do
end
it "walks singleton classes" do
- @sclass.should be_kind_of(@meta)
- ObjectSpace.each_object(@meta).to_a.should include(@sclass)
+ @sclass.should.is_a?(@meta)
+ ObjectSpace.each_object(@meta).to_a.should.include?(@sclass)
end
end
@@ -202,7 +202,7 @@ describe "ObjectSpace.each_object" do
expected = [ a, b, c, d ]
expected << c_sclass
- c_sclass.should be_kind_of(a.singleton_class)
+ c_sclass.should.is_a?(a.singleton_class)
b.extend Enumerable # included modules should not be walked
diff --git a/spec/ruby/core/objectspace/garbage_collect_spec.rb b/spec/ruby/core/objectspace/garbage_collect_spec.rb
index 521eaa8785..d2db22e0aa 100644
--- a/spec/ruby/core/objectspace/garbage_collect_spec.rb
+++ b/spec/ruby/core/objectspace/garbage_collect_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "ObjectSpace.garbage_collect" do
it "can be invoked without any exceptions" do
- -> { ObjectSpace.garbage_collect }.should_not raise_error
+ -> { ObjectSpace.garbage_collect }.should_not.raise
end
it "accepts keyword arguments" do
@@ -11,7 +11,7 @@ describe "ObjectSpace.garbage_collect" do
end
it "ignores the supplied block" do
- -> { ObjectSpace.garbage_collect {} }.should_not raise_error
+ -> { ObjectSpace.garbage_collect {} }.should_not.raise
end
it "always returns nil" do
diff --git a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb
index f57d5a7845..98ffc6a986 100644
--- a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb
@@ -28,6 +28,6 @@ describe "ObjectSpace.undefine_finalizer" do
it "should raise when removing finalizers for a frozen object" do
obj = Object.new
obj.freeze
- -> { ObjectSpace.undefine_finalizer(obj) }.should raise_error(FrozenError)
+ -> { ObjectSpace.undefine_finalizer(obj) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
index 8050e2c307..b1804ec9b0 100644
--- a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../../spec_helper'
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakKeyMap#clear" do
- it "removes all the entries" do
- m = ObjectSpace::WeakKeyMap.new
+describe "ObjectSpace::WeakKeyMap#clear" do
+ it "removes all the entries" do
+ m = ObjectSpace::WeakKeyMap.new
- key = Object.new
- value = Object.new
- m[key] = value
+ key = Object.new
+ value = Object.new
+ m[key] = value
- key2 = Object.new
- value2 = Object.new
- m[key2] = value2
+ key2 = Object.new
+ value2 = Object.new
+ m[key2] = value2
- m.clear
+ m.clear
- m.key?(key).should == false
- m.key?(key2).should == false
- end
+ m.key?(key).should == false
+ m.key?(key2).should == false
+ end
- it "returns self" do
- m = ObjectSpace::WeakKeyMap.new
- m.clear.should.equal?(m)
- end
+ it "returns self" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.clear.should.equal?(m)
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
index 3cd61355d6..ad32c2c75e 100644
--- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
@@ -1,51 +1,49 @@
require_relative '../../../spec_helper'
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakKeyMap#delete" do
- it "removes the entry and returns the deleted value" do
- m = ObjectSpace::WeakKeyMap.new
- key = Object.new
- value = Object.new
- m[key] = value
-
- m.delete(key).should == value
- m.key?(key).should == false
- end
+describe "ObjectSpace::WeakKeyMap#delete" do
+ it "removes the entry and returns the deleted value" do
+ m = ObjectSpace::WeakKeyMap.new
+ key = Object.new
+ value = Object.new
+ m[key] = value
+
+ m.delete(key).should == value
+ m.key?(key).should == false
+ end
- it "uses equality semantic" do
- m = ObjectSpace::WeakKeyMap.new
- key = "foo".upcase
- value = Object.new
- m[key] = value
+ it "uses equality semantic" do
+ m = ObjectSpace::WeakKeyMap.new
+ key = "foo".upcase
+ value = Object.new
+ m[key] = value
- m.delete("foo".upcase).should == value
- m.key?(key).should == false
- end
+ m.delete("foo".upcase).should == value
+ m.key?(key).should == false
+ end
- it "calls supplied block if the key is not found" do
- key = Object.new
- m = ObjectSpace::WeakKeyMap.new
- return_value = m.delete(key) do |yielded_key|
- yielded_key.should == key
- 5
- end
- return_value.should == 5
+ it "calls supplied block if the key is not found" do
+ key = Object.new
+ m = ObjectSpace::WeakKeyMap.new
+ return_value = m.delete(key) do |yielded_key|
+ yielded_key.should == key
+ 5
end
+ return_value.should == 5
+ end
- it "returns nil if the key is not found when no block is given" do
- m = ObjectSpace::WeakKeyMap.new
- m.delete(Object.new).should == nil
- end
+ it "returns nil if the key is not found when no block is given" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.delete(Object.new).should == nil
+ end
- it "returns nil when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.delete(1).should == nil
- map.delete(1.0).should == nil
- map.delete(:a).should == nil
- map.delete(true).should == nil
- map.delete(false).should == nil
- map.delete(nil).should == nil
- end
+ map.delete(1).should == nil
+ map.delete(1.0).should == nil
+ map.delete(:a).should == nil
+ map.delete(true).should == nil
+ map.delete(false).should == nil
+ map.delete(nil).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
index 51368e8d3b..53eff79c40 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
@@ -1,107 +1,105 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#[]" do
- it "is faithful to the map's content" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
- map[key1] = ref1
- map[key1].should == ref1
- map[key1] = ref1
- map[key1].should == ref1
- map[key2] = ref2
- map[key1].should == ref1
- map[key2].should == ref2
- end
-
- it "compares keys with #eql? semantics" do
- map = ObjectSpace::WeakKeyMap.new
- key = [1.0]
- map[key] = "x"
- map[[1]].should == nil
- map[[1.0]].should == "x"
- key.should == [1.0] # keep the key alive until here to keep the map entry
-
- map = ObjectSpace::WeakKeyMap.new
- key = [1]
- map[key] = "x"
- map[[1.0]].should == nil
- map[[1]].should == "x"
- key.should == [1] # keep the key alive until here to keep the map entry
-
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map[key2].should == ref
- end
-
- it "compares key via #hash first" do
- x = mock('0')
- x.should_receive(:hash).and_return(0)
-
- map = ObjectSpace::WeakKeyMap.new
- key = 'foo'
- map[key] = :bar
- map[x].should == nil
- end
-
- it "does not compare keys with different #hash values via #eql?" do
- x = mock('x')
- x.should_not_receive(:eql?)
- x.stub!(:hash).and_return(0)
-
- y = mock('y')
- y.should_not_receive(:eql?)
- y.stub!(:hash).and_return(1)
-
- map = ObjectSpace::WeakKeyMap.new
- map[y] = 1
- map[x].should == nil
- end
-
- it "compares keys with the same #hash value via #eql?" do
- x = mock('x')
- x.should_receive(:eql?).and_return(true)
- x.stub!(:hash).and_return(42)
-
- y = mock('y')
- y.should_not_receive(:eql?)
- y.stub!(:hash).and_return(42)
-
- map = ObjectSpace::WeakKeyMap.new
- map[y] = 1
- map[x].should == 1
- end
-
- it "finds a value via an identical key even when its #eql? isn't reflexive" do
- x = mock('x')
- x.should_receive(:hash).at_least(1).and_return(42)
- x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
-
- map = ObjectSpace::WeakKeyMap.new
- map[x] = :x
- map[x].should == :x
- end
-
- it "supports keys with private #hash method" do
- key = WeakKeyMapSpecs::KeyWithPrivateHash.new
- map = ObjectSpace::WeakKeyMap.new
- map[key] = 42
- map[key].should == 42
- end
-
- it "returns nil and does not raise error when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
-
- map[1].should == nil
- map[1.0].should == nil
- map[:a].should == nil
- map[true].should == nil
- map[false].should == nil
- map[nil].should == nil
- end
+describe "ObjectSpace::WeakKeyMap#[]" do
+ it "is faithful to the map's content" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+ map[key1] = ref1
+ map[key1].should == ref1
+ map[key1] = ref1
+ map[key1].should == ref1
+ map[key2] = ref2
+ map[key1].should == ref1
+ map[key2].should == ref2
+ end
+
+ it "compares keys with #eql? semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1.0]
+ map[key] = "x"
+ map[[1]].should == nil
+ map[[1.0]].should == "x"
+ key.should == [1.0] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1]
+ map[key] = "x"
+ map[[1.0]].should == nil
+ map[[1]].should == "x"
+ key.should == [1] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map[key2].should == ref
+ end
+
+ it "compares key via #hash first" do
+ x = mock('0')
+ x.should_receive(:hash).and_return(0)
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = 'foo'
+ map[key] = :bar
+ map[x].should == nil
+ end
+
+ it "does not compare keys with different #hash values via #eql?" do
+ x = mock('x')
+ x.should_not_receive(:eql?)
+ x.stub!(:hash).and_return(0)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(1)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == nil
+ end
+
+ it "compares keys with the same #hash value via #eql?" do
+ x = mock('x')
+ x.should_receive(:eql?).and_return(true)
+ x.stub!(:hash).and_return(42)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(42)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == 1
+ end
+
+ it "finds a value via an identical key even when its #eql? isn't reflexive" do
+ x = mock('x')
+ x.should_receive(:hash).at_least(1).and_return(42)
+ x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[x] = :x
+ map[x].should == :x
+ end
+
+ it "supports keys with private #hash method" do
+ key = WeakKeyMapSpecs::KeyWithPrivateHash.new
+ map = ObjectSpace::WeakKeyMap.new
+ map[key] = 42
+ map[key].should == 42
+ end
+
+ it "returns nil and does not raise error when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map[1].should == nil
+ map[1.0].should == nil
+ map[:a].should == nil
+ map[true].should == nil
+ map[false].should == nil
+ map[nil].should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
index 8db8d780c7..cf59aebc6f 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
@@ -1,82 +1,80 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#[]=" do
- def should_accept(map, key, value)
- (map[key] = value).should == value
- map.should.key?(key)
- map[key].should == value
- end
+describe "ObjectSpace::WeakKeyMap#[]=" do
+ def should_accept(map, key, value)
+ (map[key] = value).should == value
+ map.should.key?(key)
+ map[key].should == value
+ end
+
+ it "is correct" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+ should_accept(map, key1, ref1)
+ should_accept(map, key1, ref1)
+ should_accept(map, key2, ref2)
+ map[key1].should == ref1
+ end
+
+ it "requires the keys to implement #hash" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[BasicObject.new] = 1 }.should.raise(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
+ end
- it "is correct" do
+ it "accepts frozen keys or values" do
+ map = ObjectSpace::WeakKeyMap.new
+ x = Object.new
+ should_accept(map, x, true)
+ should_accept(map, x, false)
+ should_accept(map, x, 42)
+ should_accept(map, x, :foo)
+
+ y = Object.new.freeze
+ should_accept(map, x, y)
+ should_accept(map, y, x)
+ end
+
+ it "does not duplicate and freeze String keys (like Hash#[]= does)" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = +"a"
+ map[key] = 1
+
+ map.getkey("a").should.equal? key
+ map.getkey("a").should_not.frozen?
+
+ key.should == "a" # keep the key alive until here to keep the map entry
+ end
+
+ context "a key cannot be garbage collected" do
+ it "raises ArgumentError when Integer is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
- should_accept(map, key1, ref1)
- should_accept(map, key1, ref1)
- should_accept(map, key2, ref2)
- map[key1].should == ref1
+ -> { map[1] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "requires the keys to implement #hash" do
+ it "raises ArgumentError when Float is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
+ -> { map[1.0] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "accepts frozen keys or values" do
+ it "raises ArgumentError when Symbol is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- x = Object.new
- should_accept(map, x, true)
- should_accept(map, x, false)
- should_accept(map, x, 42)
- should_accept(map, x, :foo)
-
- y = Object.new.freeze
- should_accept(map, x, y)
- should_accept(map, y, x)
+ -> { map[:a] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "does not duplicate and freeze String keys (like Hash#[]= does)" do
+ it "raises ArgumentError when true is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- key = +"a"
- map[key] = 1
-
- map.getkey("a").should.equal? key
- map.getkey("a").should_not.frozen?
-
- key.should == "a" # keep the key alive until here to keep the map entry
+ -> { map[true] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- context "a key cannot be garbage collected" do
- it "raises ArgumentError when Integer is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when Float is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when Symbol is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when true is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when false is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
+ it "raises ArgumentError when false is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[false] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
- it "raises ArgumentError when nil is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
+ it "raises ArgumentError when nil is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[nil] = "x" }.should.raise(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
index 8a2dbf809d..798a2e2cda 100644
--- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
@@ -1,28 +1,26 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#getkey" do
- it "returns the existing equal key" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
+describe "ObjectSpace::WeakKeyMap#getkey" do
+ it "returns the existing equal key" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
- map[key1] = true
- map.getkey(key2).should equal(key1)
- map.getkey("X").should == nil
+ map[key1] = true
+ map.getkey(key2).should.equal?(key1)
+ map.getkey("X").should == nil
- key1.should == "A" # keep the key alive until here to keep the map entry
- key2.should == "A" # keep the key alive until here to keep the map entry
- end
+ key1.should == "A" # keep the key alive until here to keep the map entry
+ key2.should == "A" # keep the key alive until here to keep the map entry
+ end
- it "returns nil when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.getkey(1).should == nil
- map.getkey(1.0).should == nil
- map.getkey(:a).should == nil
- map.getkey(true).should == nil
- map.getkey(false).should == nil
- map.getkey(nil).should == nil
- end
+ map.getkey(1).should == nil
+ map.getkey(1.0).should == nil
+ map.getkey(:a).should == nil
+ map.getkey(true).should == nil
+ map.getkey(false).should == nil
+ map.getkey(nil).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
index 319f050970..b6bb469158 100644
--- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
@@ -1,21 +1,19 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#inspect" do
- it "only displays size in output" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2, key3 = "foo", "bar", "bar"
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/
- map[key1] = 1
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/
- map[key2] = 2
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
- map[key3] = 3
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
+describe "ObjectSpace::WeakKeyMap#inspect" do
+ it "only displays size in output" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2, key3 = "foo", "bar", "bar"
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/
+ map[key1] = 1
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/
+ map[key2] = 2
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
+ map[key3] = 3
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
- key1.should == "foo" # keep the key alive until here to keep the map entry
- key2.should == "bar" # keep the key alive until here to keep the map entry
- key3.should == "bar" # keep the key alive until here to keep the map entry
- end
+ key1.should == "foo" # keep the key alive until here to keep the map entry
+ key2.should == "bar" # keep the key alive until here to keep the map entry
+ key3.should == "bar" # keep the key alive until here to keep the map entry
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
index a9a2e12432..e0b6866671 100644
--- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
@@ -1,44 +1,42 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#key?" do
- it "recognizes keys in use" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
+describe "ObjectSpace::WeakKeyMap#key?" do
+ it "recognizes keys in use" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
- map[key1] = ref1
- map.key?(key1).should == true
- map[key1] = ref1
- map.key?(key1).should == true
- map[key2] = ref2
- map.key?(key2).should == true
- end
+ map[key1] = ref1
+ map.key?(key1).should == true
+ map[key1] = ref1
+ map.key?(key1).should == true
+ map[key2] = ref2
+ map.key?(key2).should == true
+ end
- it "matches using equality semantics" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map.key?(key2).should == true
- end
+ it "matches using equality semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map.key?(key2).should == true
+ end
- it "reports true if the pair exists and the value is nil" do
- map = ObjectSpace::WeakKeyMap.new
- key = Object.new
- map[key] = nil
- map.key?(key).should == true
- end
+ it "reports true if the pair exists and the value is nil" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = Object.new
+ map[key] = nil
+ map.key?(key).should == true
+ end
- it "returns false when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns false when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.key?(1).should == false
- map.key?(1.0).should == false
- map.key?(:a).should == false
- map.key?(true).should == false
- map.key?(false).should == false
- map.key?(nil).should == false
- end
+ map.key?(1).should == false
+ map.key?(1.0).should == false
+ map.key?(:a).should == false
+ map.key?(true).should == false
+ map.key?(false).should == false
+ map.key?(nil).should == false
end
end
diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
index 302de264fb..03beebbb83 100644
--- a/spec/ruby/core/objectspace/weakmap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
@@ -1,30 +1,28 @@
require_relative '../../../spec_helper'
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakMap#delete" do
- it "removes the entry and returns the deleted value" do
- m = ObjectSpace::WeakMap.new
- key = Object.new
- value = Object.new
- m[key] = value
+describe "ObjectSpace::WeakMap#delete" do
+ it "removes the entry and returns the deleted value" do
+ m = ObjectSpace::WeakMap.new
+ key = Object.new
+ value = Object.new
+ m[key] = value
- m.delete(key).should == value
- m.key?(key).should == false
- end
+ m.delete(key).should == value
+ m.key?(key).should == false
+ end
- it "calls supplied block if the key is not found" do
- key = Object.new
- m = ObjectSpace::WeakMap.new
- return_value = m.delete(key) do |yielded_key|
- yielded_key.should == key
- 5
- end
- return_value.should == 5
+ it "calls supplied block if the key is not found" do
+ key = Object.new
+ m = ObjectSpace::WeakMap.new
+ return_value = m.delete(key) do |yielded_key|
+ yielded_key.should == key
+ 5
end
+ return_value.should == 5
+ end
- it "returns nil if the key is not found when no block is given" do
- m = ObjectSpace::WeakMap.new
- m.delete(Object.new).should == nil
- end
+ it "returns nil if the key is not found when no block is given" do
+ m = ObjectSpace::WeakMap.new
+ m.delete(Object.new).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakmap/shared/each.rb b/spec/ruby/core/objectspace/weakmap/shared/each.rb
index 3d43a19347..771c416dde 100644
--- a/spec/ruby/core/objectspace/weakmap/shared/each.rb
+++ b/spec/ruby/core/objectspace/weakmap/shared/each.rb
@@ -5,6 +5,6 @@ describe :weakmap_each, shared: true do
ref = "x"
map.send(@method).should == map
map[key] = ref
- -> { map.send(@method) }.should raise_error(LocalJumpError)
+ -> { map.send(@method) }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/core/proc/allocate_spec.rb b/spec/ruby/core/proc/allocate_spec.rb
index 54e1b69df9..96c4eb9fa8 100644
--- a/spec/ruby/core/proc/allocate_spec.rb
+++ b/spec/ruby/core/proc/allocate_spec.rb
@@ -4,6 +4,6 @@ describe "Proc.allocate" do
it "raises a TypeError" do
-> {
Proc.allocate
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/proc/binding_spec.rb b/spec/ruby/core/proc/binding_spec.rb
index 86ab6bd400..d643cbf89c 100644
--- a/spec/ruby/core/proc/binding_spec.rb
+++ b/spec/ruby/core/proc/binding_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Proc#binding" do
it "returns a Binding instance" do
[Proc.new{}, -> {}, proc {}].each { |p|
- p.binding.should be_kind_of(Binding)
+ p.binding.should.is_a?(Binding)
}
end
diff --git a/spec/ruby/core/proc/block_pass_spec.rb b/spec/ruby/core/proc/block_pass_spec.rb
index 411c0bf3db..82c08db8a7 100644
--- a/spec/ruby/core/proc/block_pass_spec.rb
+++ b/spec/ruby/core/proc/block_pass_spec.rb
@@ -8,14 +8,14 @@ describe "Proc as a block pass argument" do
it "remains the same object if re-vivified by the target method" do
p = Proc.new {}
p2 = revivify(&p)
- p.should equal p2
+ p.should.equal? p2
p.should == p2
end
it "remains the same object if reconstructed with Proc.new" do
p = Proc.new {}
p2 = Proc.new(&p)
- p.should equal p2
+ p.should.equal? p2
p.should == p2
end
end
diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb
index 730dc421a8..aee4873e09 100644
--- a/spec/ruby/core/proc/clone_spec.rb
+++ b/spec/ruby/core/proc/clone_spec.rb
@@ -5,7 +5,7 @@ require_relative 'shared/dup'
describe "Proc#clone" do
it_behaves_like :proc_dup, :clone
- ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do
+ ruby_bug "cloning a frozen proc is broken on Ruby 3.3", ""..."3.4" do
it "preserves frozen status" do
proc = Proc.new { }
proc.freeze
@@ -14,17 +14,15 @@ describe "Proc#clone" do
end
end
- ruby_version_is "3.3" do
- it "calls #initialize_clone on subclass" do
- obj = ProcSpecs::MyProc2.new(:a, 2) { }
- dup = obj.clone
+ it "calls #initialize_clone on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.clone
- dup.should_not equal(obj)
- dup.class.should == ProcSpecs::MyProc2
+ dup.should_not.equal?(obj)
+ dup.class.should == ProcSpecs::MyProc2
- dup.first.should == :a
- dup.second.should == 2
- dup.initializer.should == :clone
- end
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :clone
end
end
diff --git a/spec/ruby/core/proc/curry_spec.rb b/spec/ruby/core/proc/curry_spec.rb
index 6daabe0ee1..de13983ca6 100644
--- a/spec/ruby/core/proc/curry_spec.rb
+++ b/spec/ruby/core/proc/curry_spec.rb
@@ -8,12 +8,12 @@ describe "Proc#curry" do
it "returns a Proc when called on a proc" do
p = proc { true }
- p.curry.should be_an_instance_of(Proc)
+ p.curry.should.instance_of?(Proc)
end
it "returns a Proc when called on a lambda" do
p = -> { true }
- p.curry.should be_an_instance_of(Proc)
+ p.curry.should.instance_of?(Proc)
end
it "calls the curried proc with the arguments if sufficient arguments have been given" do
@@ -23,11 +23,11 @@ describe "Proc#curry" do
it "returns a Proc that consumes the remainder of the arguments unless sufficient arguments have been given" do
proc2 = @proc_add.curry[1][2]
- proc2.should be_an_instance_of(Proc)
+ proc2.should.instance_of?(Proc)
proc2.call(3).should == 6
lambda2 = @lambda_add.curry[1][2]
- lambda2.should be_an_instance_of(Proc)
+ lambda2.should.instance_of?(Proc)
lambda2.call(3).should == 6
@proc_add.curry.call(1,2,3).should == 6
@@ -36,10 +36,10 @@ describe "Proc#curry" do
it "can be called multiple times on the same Proc" do
@proc_add.curry
- -> { @proc_add.curry }.should_not raise_error
+ -> { @proc_add.curry }.should_not.raise
@lambda_add.curry
- -> { @lambda_add.curry }.should_not raise_error
+ -> { @lambda_add.curry }.should_not.raise
end
it "can be passed superfluous arguments if created from a proc" do
@@ -49,8 +49,8 @@ describe "Proc#curry" do
end
it "raises an ArgumentError if passed superfluous arguments when created from a lambda" do
- -> { @lambda_add.curry[1,2,3,4] }.should raise_error(ArgumentError)
- -> { @lambda_add.curry[1,2].curry[3,4,5,6] }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry[1,2,3,4] }.should.raise(ArgumentError)
+ -> { @lambda_add.curry[1,2].curry[3,4,5,6] }.should.raise(ArgumentError)
end
it "returns Procs with arities of -1" do
@@ -63,7 +63,7 @@ describe "Proc#curry" do
it "produces Procs that raise ArgumentError for #binding" do
-> do
@proc_add.curry.binding
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "produces Procs that return [[:rest]] for #parameters" do
@@ -98,41 +98,41 @@ describe "Proc#curry with arity argument" do
end
it "accepts an optional Integer argument for the arity" do
- -> { @proc_add.curry(3) }.should_not raise_error
- -> { @lambda_add.curry(3) }.should_not raise_error
+ -> { @proc_add.curry(3) }.should_not.raise
+ -> { @lambda_add.curry(3) }.should_not.raise
end
it "returns a Proc when called on a proc" do
- @proc_add.curry(3).should be_an_instance_of(Proc)
+ @proc_add.curry(3).should.instance_of?(Proc)
end
it "returns a Proc when called on a lambda" do
- @lambda_add.curry(3).should be_an_instance_of(Proc)
+ @lambda_add.curry(3).should.instance_of?(Proc)
end
# [ruby-core:24127]
it "retains the lambda-ness of the Proc on which its called" do
- @lambda_add.curry(3).lambda?.should be_true
- @proc_add.curry(3).lambda?.should be_false
+ @lambda_add.curry(3).lambda?.should == true
+ @proc_add.curry(3).lambda?.should == false
end
it "raises an ArgumentError if called on a lambda that requires more than _arity_ arguments" do
- -> { @lambda_add.curry(2) }.should raise_error(ArgumentError)
- -> { -> x, y, z, *more{}.curry(2) }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry(2) }.should.raise(ArgumentError)
+ -> { -> x, y, z, *more{}.curry(2) }.should.raise(ArgumentError)
end
it 'returns a Proc if called on a lambda that requires fewer than _arity_ arguments but may take more' do
- -> a, b, c, d=nil, e=nil {}.curry(4).should be_an_instance_of(Proc)
- -> a, b, c, d=nil, *e {}.curry(4).should be_an_instance_of(Proc)
- -> a, b, c, *d {}.curry(4).should be_an_instance_of(Proc)
+ -> a, b, c, d=nil, e=nil {}.curry(4).should.instance_of?(Proc)
+ -> a, b, c, d=nil, *e {}.curry(4).should.instance_of?(Proc)
+ -> a, b, c, *d {}.curry(4).should.instance_of?(Proc)
end
it "raises an ArgumentError if called on a lambda that requires fewer than _arity_ arguments" do
- -> { @lambda_add.curry(4) }.should raise_error(ArgumentError)
- -> { -> { true }.curry(1) }.should raise_error(ArgumentError)
- -> { -> a, b=nil {}.curry(5) }.should raise_error(ArgumentError)
- -> { -> a, &b {}.curry(2) }.should raise_error(ArgumentError)
- -> { -> a, b=nil, &c {}.curry(3) }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry(4) }.should.raise(ArgumentError)
+ -> { -> { true }.curry(1) }.should.raise(ArgumentError)
+ -> { -> a, b=nil {}.curry(5) }.should.raise(ArgumentError)
+ -> { -> a, &b {}.curry(2) }.should.raise(ArgumentError)
+ -> { -> a, b=nil, &c {}.curry(3) }.should.raise(ArgumentError)
end
it "calls the curried proc with the arguments if _arity_ arguments have been given" do
@@ -142,20 +142,20 @@ describe "Proc#curry with arity argument" do
it "returns a Proc that consumes the remainder of the arguments when fewer than _arity_ arguments are given" do
proc2 = @proc_add.curry(3)[1][2]
- proc2.should be_an_instance_of(Proc)
+ proc2.should.instance_of?(Proc)
proc2.call(3).should == 6
lambda2 = @lambda_add.curry(3)[1][2]
- lambda2.should be_an_instance_of(Proc)
+ lambda2.should.instance_of?(Proc)
lambda2.call(3).should == 6
end
it "can be specified multiple times on the same Proc" do
@proc_add.curry(2)
- -> { @proc_add.curry(1) }.should_not raise_error
+ -> { @proc_add.curry(1) }.should_not.raise
@lambda_add.curry(3)
- -> { @lambda_add.curry(3) }.should_not raise_error
+ -> { @lambda_add.curry(3) }.should_not.raise
end
it "can be passed more than _arity_ arguments if created from a proc" do
@@ -165,8 +165,8 @@ describe "Proc#curry with arity argument" do
end
it "raises an ArgumentError if passed more than _arity_ arguments when created from a lambda" do
- -> { @lambda_add.curry(3)[1,2,3,4] }.should raise_error(ArgumentError)
- -> { @lambda_add.curry(3)[1,2].curry(3)[3,4,5,6] }.should raise_error(ArgumentError)
+ -> { @lambda_add.curry(3)[1,2,3,4] }.should.raise(ArgumentError)
+ -> { @lambda_add.curry(3)[1,2].curry(3)[3,4,5,6] }.should.raise(ArgumentError)
end
it "returns Procs with arities of -1 regardless of the value of _arity_" do
diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb
index 716357d1f0..8604389422 100644
--- a/spec/ruby/core/proc/dup_spec.rb
+++ b/spec/ruby/core/proc/dup_spec.rb
@@ -12,17 +12,15 @@ describe "Proc#dup" do
proc.dup.frozen?.should == false
end
- ruby_version_is "3.3" do
- it "calls #initialize_dup on subclass" do
- obj = ProcSpecs::MyProc2.new(:a, 2) { }
- dup = obj.dup
+ it "calls #initialize_dup on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.dup
- dup.should_not equal(obj)
- dup.class.should == ProcSpecs::MyProc2
+ dup.should_not.equal?(obj)
+ dup.class.should == ProcSpecs::MyProc2
- dup.first.should == :a
- dup.second.should == 2
- dup.initializer.should == :dup
- end
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :dup
end
end
diff --git a/spec/ruby/core/proc/element_reference_spec.rb b/spec/ruby/core/proc/element_reference_spec.rb
index 9077e44c34..ea3a915a11 100644
--- a/spec/ruby/core/proc/element_reference_spec.rb
+++ b/spec/ruby/core/proc/element_reference_spec.rb
@@ -17,11 +17,11 @@ describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do
it_behaves_like :proc_call_on_proc_or_lambda, :call
end
-describe "Proc#[] with frozen_string_literals" do
+describe "Proc#[] with frozen_string_literal: true/false" do
it "doesn't duplicate frozen strings" do
- ProcArefSpecs.aref.frozen?.should be_false
- ProcArefSpecs.aref_freeze.frozen?.should be_true
- ProcArefFrozenSpecs.aref.frozen?.should be_true
- ProcArefFrozenSpecs.aref_freeze.frozen?.should be_true
+ ProcArefSpecs.aref.frozen?.should == false
+ ProcArefSpecs.aref_freeze.frozen?.should == true
+ ProcArefFrozenSpecs.aref.frozen?.should == true
+ ProcArefFrozenSpecs.aref_freeze.frozen?.should == true
end
end
diff --git a/spec/ruby/core/proc/hash_spec.rb b/spec/ruby/core/proc/hash_spec.rb
index ebe0fde1a0..adcb1ccb78 100644
--- a/spec/ruby/core/proc/hash_spec.rb
+++ b/spec/ruby/core/proc/hash_spec.rb
@@ -2,12 +2,12 @@ require_relative '../../spec_helper'
describe "Proc#hash" do
it "is provided" do
- proc {}.respond_to?(:hash).should be_true
- -> {}.respond_to?(:hash).should be_true
+ proc {}.respond_to?(:hash).should == true
+ -> {}.respond_to?(:hash).should == true
end
it "returns an Integer" do
- proc { 1 + 489 }.hash.should be_kind_of(Integer)
+ proc { 1 + 489 }.hash.should.is_a?(Integer)
end
it "is stable" do
diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb
index 5c3c38fc2a..1ff6147319 100644
--- a/spec/ruby/core/proc/lambda_spec.rb
+++ b/spec/ruby/core/proc/lambda_spec.rb
@@ -3,60 +3,53 @@ require_relative 'fixtures/common'
describe "Proc#lambda?" do
it "returns true if the Proc was created from a block with the lambda keyword" do
- -> {}.lambda?.should be_true
+ -> {}.lambda?.should == true
end
it "returns false if the Proc was created from a block with the proc keyword" do
- proc {}.lambda?.should be_false
+ proc {}.lambda?.should == false
end
it "returns false if the Proc was created from a block with Proc.new" do
- Proc.new {}.lambda?.should be_false
- end
-
- ruby_version_is ""..."3.3" do
- it "is preserved when passing a Proc with & to the lambda keyword" do
- suppress_warning {lambda(&->{})}.lambda?.should be_true
- suppress_warning {lambda(&proc{})}.lambda?.should be_false
- end
+ Proc.new {}.lambda?.should == false
end
it "is preserved when passing a Proc with & to the proc keyword" do
- proc(&->{}).lambda?.should be_true
- proc(&proc{}).lambda?.should be_false
+ proc(&->{}).lambda?.should == true
+ proc(&proc{}).lambda?.should == false
end
it "is preserved when passing a Proc with & to Proc.new" do
- Proc.new(&->{}).lambda?.should be_true
- Proc.new(&proc{}).lambda?.should be_false
+ Proc.new(&->{}).lambda?.should == true
+ Proc.new(&proc{}).lambda?.should == false
end
it "returns false if the Proc was created from a block with &" do
- ProcSpecs.new_proc_from_amp{}.lambda?.should be_false
+ ProcSpecs.new_proc_from_amp{}.lambda?.should == false
end
it "is preserved when the Proc was passed using &" do
- ProcSpecs.new_proc_from_amp(&->{}).lambda?.should be_true
- ProcSpecs.new_proc_from_amp(&proc{}).lambda?.should be_false
- ProcSpecs.new_proc_from_amp(&Proc.new{}).lambda?.should be_false
+ ProcSpecs.new_proc_from_amp(&->{}).lambda?.should == true
+ ProcSpecs.new_proc_from_amp(&proc{}).lambda?.should == false
+ ProcSpecs.new_proc_from_amp(&Proc.new{}).lambda?.should == false
end
it "returns true for a Method converted to a Proc" do
m = :foo.method(:to_s)
- m.to_proc.lambda?.should be_true
- ProcSpecs.new_proc_from_amp(&m).lambda?.should be_true
+ m.to_proc.lambda?.should == true
+ ProcSpecs.new_proc_from_amp(&m).lambda?.should == true
end
# [ruby-core:24127]
it "is preserved when a Proc is curried" do
- ->{}.curry.lambda?.should be_true
- proc{}.curry.lambda?.should be_false
- Proc.new{}.curry.lambda?.should be_false
+ ->{}.curry.lambda?.should == true
+ proc{}.curry.lambda?.should == false
+ Proc.new{}.curry.lambda?.should == false
end
it "is preserved when a curried Proc is called without enough arguments" do
- -> x, y{}.curry.call(42).lambda?.should be_true
- proc{|x,y|}.curry.call(42).lambda?.should be_false
- Proc.new{|x,y|}.curry.call(42).lambda?.should be_false
+ -> x, y{}.curry.call(42).lambda?.should == true
+ proc{|x,y|}.curry.call(42).lambda?.should == false
+ Proc.new{|x,y|}.curry.call(42).lambda?.should == false
end
end
diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb
index b2b7387756..f0b817f0cb 100644
--- a/spec/ruby/core/proc/new_spec.rb
+++ b/spec/ruby/core/proc/new_spec.rb
@@ -71,7 +71,7 @@ describe "Proc.new with an associated block" do
end
res = some_method()
- -> { res.call }.should raise_error(LocalJumpError)
+ -> { res.call }.should.raise(LocalJumpError)
end
it "returns from within enclosing method when 'return' is used in the block" do
@@ -86,7 +86,7 @@ describe "Proc.new with an associated block" do
it "returns a subclass of Proc" do
obj = ProcSpecs::MyProc.new { }
- obj.should be_kind_of(ProcSpecs::MyProc)
+ obj.should.is_a?(ProcSpecs::MyProc)
end
it "calls initialize on the Proc object" do
@@ -101,7 +101,7 @@ describe "Proc.new with a block argument" do
passed_prc = Proc.new { "hello".size }
prc = Proc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -110,7 +110,7 @@ describe "Proc.new with a block argument" do
passed_prc = Proc.new(&method)
prc = Proc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -118,7 +118,7 @@ describe "Proc.new with a block argument" do
passed_prc = Proc.new(&:size)
prc = Proc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call("hello").should == 5
end
end
@@ -129,7 +129,7 @@ describe "Proc.new with a block argument called indirectly from a subclass" do
passed_prc.class.should == ProcSpecs::MyProc
prc = ProcSpecs::MyProc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -139,7 +139,7 @@ describe "Proc.new with a block argument called indirectly from a subclass" do
passed_prc.class.should == ProcSpecs::MyProc
prc = ProcSpecs::MyProc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call.should == 5
end
@@ -148,22 +148,22 @@ describe "Proc.new with a block argument called indirectly from a subclass" do
passed_prc.class.should == ProcSpecs::MyProc
prc = ProcSpecs::MyProc.new(&passed_prc)
- prc.should equal(passed_prc)
+ prc.should.equal?(passed_prc)
prc.call("hello").should == 5
end
end
describe "Proc.new without a block" do
it "raises an ArgumentError" do
- -> { Proc.new }.should raise_error(ArgumentError)
+ -> { Proc.new }.should.raise(ArgumentError)
end
it "raises an ArgumentError if invoked from within a method with no block" do
- -> { ProcSpecs.new_proc_in_method }.should raise_error(ArgumentError)
+ -> { ProcSpecs.new_proc_in_method }.should.raise(ArgumentError)
end
it "raises an ArgumentError if invoked on a subclass from within a method with no block" do
- -> { ProcSpecs.new_proc_subclass_in_method }.should raise_error(ArgumentError)
+ -> { ProcSpecs.new_proc_subclass_in_method }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed no block" do
@@ -171,8 +171,8 @@ describe "Proc.new without a block" do
Proc.new
end
- -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ -> { ProcSpecs.new_proc_in_method { "hello" } }.should.raise(ArgumentError, 'tried to create Proc object without a block')
+ -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should.raise(ArgumentError, 'tried to create Proc object without a block')
+ -> { some_method { "hello" } }.should.raise(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index 7a2723487d..ac8c6e3560 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -7,8 +7,8 @@ describe "Proc#parameters" do
it "returns an Array of Arrays for a proc expecting parameters" do
p = proc {|x| }
- p.parameters.should be_an_instance_of(Array)
- p.parameters.first.should be_an_instance_of(Array)
+ p.parameters.should.instance_of?(Array)
+ p.parameters.first.should.instance_of?(Array)
end
it "sets the first element of each sub-Array to :opt for optional arguments" do
@@ -20,29 +20,27 @@ describe "Proc#parameters" do
proc {|x| }.parameters.first.first.should == :opt
end
- ruby_version_is "3.2" do
- it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do
- proc {|x| }.parameters(lambda: true).first.first.should == :req
- proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
- end
+ it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do
+ proc {|x| }.parameters(lambda: true).first.first.should == :req
+ proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
+ end
- it "regards named parameters in procs as required if lambda keyword used" do
- proc {|x| }.parameters(lambda: true).first.first.should == :req
- end
+ it "regards named parameters in procs as required if lambda keyword used" do
+ proc {|x| }.parameters(lambda: true).first.first.should == :req
+ end
- it "regards named parameters in lambda as optional if lambda: false keyword used" do
- -> x { }.parameters(lambda: false).first.first.should == :opt
- end
+ it "regards named parameters in lambda as optional if lambda: false keyword used" do
+ -> x { }.parameters(lambda: false).first.first.should == :opt
+ end
- it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do
- proc {|x| }.parameters(lambda: 123).first.first.should == :req
- -> x { }.parameters(lambda: 123).first.first.should == :req
- end
+ it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do
+ proc {|x| }.parameters(lambda: 123).first.first.should == :req
+ -> x { }.parameters(lambda: 123).first.first.should == :req
+ end
- it "ignores the lambda keyword if it is nil" do
- proc {|x|}.parameters(lambda: nil).first.first.should == :opt
- -> x { }.parameters(lambda: nil).first.first.should == :req
- end
+ it "ignores the lambda keyword if it is nil" do
+ proc {|x|}.parameters(lambda: nil).first.first.should == :opt
+ -> x { }.parameters(lambda: nil).first.first.should == :req
end
it "regards optional keyword parameters in procs as optional" do
@@ -110,24 +108,12 @@ describe "Proc#parameters" do
-> x { }.parameters.should == [[:req, :x]]
end
- ruby_version_is '3.2' do
- it "adds rest arg with name * for \"star\" argument" do
- -> * {}.parameters.should == [[:rest, :*]]
- end
-
- it "adds keyrest arg with ** as a name for \"double star\" argument" do
- -> ** {}.parameters.should == [[:keyrest, :**]]
- end
+ it "adds rest arg with name * for \"star\" argument" do
+ -> * {}.parameters.should == [[:rest, :*]]
end
- ruby_version_is ''...'3.2' do
- it "adds nameless rest arg for \"star\" argument" do
- -> * {}.parameters.should == [[:rest]]
- end
-
- it "adds nameless keyrest arg for \"double star\" argument" do
- -> ** {}.parameters.should == [[:keyrest]]
- end
+ it "adds keyrest arg with ** as a name for \"double star\" argument" do
+ -> ** {}.parameters.should == [[:keyrest, :**]]
end
it "adds block arg with name & for anonymous block argument" do
@@ -172,4 +158,26 @@ describe "Proc#parameters" do
it "returns :nokey for **nil parameter" do
proc { |**nil| }.parameters.should == [[:nokey]]
end
+
+ ruby_version_is "3.4"..."4.0" do
+ it "handles the usage of `it` as a parameter" do
+ eval("proc { it }").parameters.should == [[:opt, nil]]
+ eval("lambda { it }").parameters.should == [[:req]]
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "handles the usage of `it` as a parameter" do
+ eval("proc { it }").parameters.should == [[:opt]]
+ eval("lambda { it }").parameters.should == [[:req]]
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "returns :noblock for &nil parameter" do
+ eval <<~RUBY
+ proc { |&nil| }.parameters.should == [[:noblock]]
+ RUBY
+ end
+ end
end
diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb
index ab67302231..e06fad8693 100644
--- a/spec/ruby/core/proc/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb
@@ -27,7 +27,7 @@ describe "Proc#ruby2_keywords" do
it "returns self" do
f = -> *a { }
- f.ruby2_keywords.should equal f
+ f.ruby2_keywords.should.equal? f
end
it "prints warning when a proc does not accept argument splat" do
@@ -39,7 +39,7 @@ describe "Proc#ruby2_keywords" do
end
it "prints warning when a proc accepts keywords" do
- f = -> a:, b: { }
+ f = -> *a, b: { }
-> {
f.ruby2_keywords
@@ -47,10 +47,20 @@ describe "Proc#ruby2_keywords" do
end
it "prints warning when a proc accepts keyword splat" do
- f = -> **a { }
+ f = -> *a, **b { }
-> {
f.ruby2_keywords
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
+
+ ruby_version_is "4.0" do
+ it "prints warning when a proc accepts post arguments" do
+ f = -> *a, b { }
+
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+ end
end
diff --git a/spec/ruby/core/proc/shared/call.rb b/spec/ruby/core/proc/shared/call.rb
index dbec34df4b..fae2331b68 100644
--- a/spec/ruby/core/proc/shared/call.rb
+++ b/spec/ruby/core/proc/shared/call.rb
@@ -70,21 +70,21 @@ describe :proc_call_on_proc_or_lambda, shared: true do
it "raises an ArgumentError on excess arguments when self is a lambda" do
-> {
-> x { x }.send(@method, 1, 2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
-> x { x }.send(@method, 1, 2, 3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError on missing arguments when self is a lambda" do
-> {
-> x { x }.send(@method)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
-> x, y { [x,y] }.send(@method, 1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "treats a single Array argument as a single argument when self is a lambda" do
diff --git a/spec/ruby/core/proc/shared/compose.rb b/spec/ruby/core/proc/shared/compose.rb
index 3d3f3b310d..c004cec7c9 100644
--- a/spec/ruby/core/proc/shared/compose.rb
+++ b/spec/ruby/core/proc/shared/compose.rb
@@ -5,7 +5,7 @@ describe :proc_compose, shared: true do
-> {
lhs.send(@method, not_callable)
- }.should raise_error(TypeError, "callable object is expected")
+ }.should.raise(TypeError, "callable object is expected")
end
@@ -17,6 +17,6 @@ describe :proc_compose, shared: true do
-> {
lhs.send(@method, succ)
- }.should raise_error(TypeError, "callable object is expected")
+ }.should.raise(TypeError, "callable object is expected")
end
end
diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb
index 818f5b858e..2821d2e00f 100644
--- a/spec/ruby/core/proc/shared/dup.rb
+++ b/spec/ruby/core/proc/shared/dup.rb
@@ -3,17 +3,15 @@ describe :proc_dup, shared: true do
a = -> { "hello" }
b = a.send(@method)
- a.should_not equal(b)
+ a.should_not.equal?(b)
a.call.should == b.call
end
- ruby_version_is "3.2" do
- it "returns an instance of subclass" do
- cl = Class.new(Proc)
+ it "returns an instance of subclass" do
+ cl = Class.new(Proc)
- cl.new{}.send(@method).class.should == cl
- end
+ cl.new{}.send(@method).class.should == cl
end
ruby_version_is "3.4" do
diff --git a/spec/ruby/core/proc/shared/equal.rb b/spec/ruby/core/proc/shared/equal.rb
index d0503fb064..4f6f6c41be 100644
--- a/spec/ruby/core/proc/shared/equal.rb
+++ b/spec/ruby/core/proc/shared/equal.rb
@@ -3,29 +3,29 @@ require_relative '../fixtures/common'
describe :proc_equal, shared: true do
it "is a public method" do
- Proc.should have_public_instance_method(@method, false)
+ Proc.public_instance_methods(false).should.include?(@method)
end
it "returns true if self and other are the same object" do
p = proc { :foo }
- p.send(@method, p).should be_true
+ p.send(@method, p).should == true
p = Proc.new { :foo }
- p.send(@method, p).should be_true
+ p.send(@method, p).should == true
p = -> { :foo }
- p.send(@method, p).should be_true
+ p.send(@method, p).should == true
end
it "returns true if other is a dup of the original" do
p = proc { :foo }
- p.send(@method, p.dup).should be_true
+ p.send(@method, p.dup).should == true
p = Proc.new { :foo }
- p.send(@method, p.dup).should be_true
+ p.send(@method, p.dup).should == true
p = -> { :foo }
- p.send(@method, p.dup).should be_true
+ p.send(@method, p.dup).should == true
end
# identical here means the same method invocation.
@@ -33,51 +33,51 @@ describe :proc_equal, shared: true do
a = ProcSpecs.proc_for_1
b = ProcSpecs.proc_for_1
- a.send(@method, b).should be_false
+ a.send(@method, b).should == false
end
it "returns false if procs are distinct but have the same body and environment" do
p = proc { :foo }
p2 = proc { :foo }
- p.send(@method, p2).should be_false
+ p.send(@method, p2).should == false
end
it "returns false if lambdas are distinct but have same body and environment" do
x = -> { :foo }
x2 = -> { :foo }
- x.send(@method, x2).should be_false
+ x.send(@method, x2).should == false
end
it "returns false if using comparing lambda to proc, even with the same body and env" do
p = -> { :foo }
p2 = proc { :foo }
- p.send(@method, p2).should be_false
+ p.send(@method, p2).should == false
x = proc { :bar }
x2 = -> { :bar }
- x.send(@method, x2).should be_false
+ x.send(@method, x2).should == false
end
it "returns false if other is not a Proc" do
p = proc { :foo }
- p.send(@method, []).should be_false
+ p.send(@method, []).should == false
p = Proc.new { :foo }
- p.send(@method, Object.new).should be_false
+ p.send(@method, Object.new).should == false
p = -> { :foo }
- p.send(@method, :foo).should be_false
+ p.send(@method, :foo).should == false
end
it "returns false if self and other are both procs but have different bodies" do
p = proc { :bar }
p2 = proc { :foo }
- p.send(@method, p2).should be_false
+ p.send(@method, p2).should == false
end
it "returns false if self and other are both lambdas but have different bodies" do
p = -> { :foo }
p2 = -> { :bar }
- p.send(@method, p2).should be_false
+ p.send(@method, p2).should == false
end
end
diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb
index 484466f577..d27ad0559e 100644
--- a/spec/ruby/core/proc/source_location_spec.rb
+++ b/spec/ruby/core/proc/source_location_spec.rb
@@ -10,71 +10,64 @@ describe "Proc#source_location" do
end
it "returns an Array" do
- @proc.source_location.should be_an_instance_of(Array)
- @proc_new.source_location.should be_an_instance_of(Array)
- @lambda.source_location.should be_an_instance_of(Array)
- @method.source_location.should be_an_instance_of(Array)
+ @proc.source_location.should.instance_of?(Array)
+ @proc_new.source_location.should.instance_of?(Array)
+ @lambda.source_location.should.instance_of?(Array)
+ @method.source_location.should.instance_of?(Array)
end
it "sets the first value to the path of the file in which the proc was defined" do
- file = @proc.source_location[0]
- file.should be_an_instance_of(String)
+ file = @proc.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @proc_new.source_location[0]
- file.should be_an_instance_of(String)
+ file = @proc_new.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @lambda.source_location[0]
- file.should be_an_instance_of(String)
+ file = @lambda.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @method.source_location[0]
- file.should be_an_instance_of(String)
+ file = @method.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
end
- it "sets the second value to an Integer representing the line on which the proc was defined" do
- line = @proc.source_location[1]
- line.should be_an_instance_of(Integer)
+ it "sets the last value to an Integer representing the line on which the proc was defined" do
+ line = @proc.source_location.last
+ line.should.instance_of?(Integer)
line.should == 4
- line = @proc_new.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @proc_new.source_location.last
+ line.should.instance_of?(Integer)
line.should == 12
- line = @lambda.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @lambda.source_location.last
+ line.should.instance_of?(Integer)
line.should == 8
- line = @method.source_location[1]
- line.should be_an_instance_of(Integer)
+ line = @method.source_location.last
+ line.should.instance_of?(Integer)
line.should == 15
end
it "works even if the proc was created on the same line" do
- ruby_version_is(""..."3.5") do
- proc { true }.source_location.should == [__FILE__, __LINE__]
- Proc.new { true }.source_location.should == [__FILE__, __LINE__]
- -> { true }.source_location.should == [__FILE__, __LINE__]
- end
- ruby_version_is("3.5") do
- proc { true }.source_location.should == [__FILE__, __LINE__, 11, __LINE__, 19]
- Proc.new { true }.source_location.should == [__FILE__, __LINE__, 15, __LINE__, 23]
- -> { true }.source_location.should == [__FILE__, __LINE__, 8, __LINE__, 17]
- end
+ proc { true }.source_location.should == [__FILE__, __LINE__]
+ Proc.new { true }.source_location.should == [__FILE__, __LINE__]
+ -> { true }.source_location.should == [__FILE__, __LINE__]
end
it "returns the first line of a multi-line proc (i.e. the line containing 'proc do')" do
- ProcSpecs::SourceLocation.my_multiline_proc.source_location[1].should == 20
- ProcSpecs::SourceLocation.my_multiline_proc_new.source_location[1].should == 34
- ProcSpecs::SourceLocation.my_multiline_lambda.source_location[1].should == 27
+ ProcSpecs::SourceLocation.my_multiline_proc.source_location.last.should == 20
+ ProcSpecs::SourceLocation.my_multiline_proc_new.source_location.last.should == 34
+ ProcSpecs::SourceLocation.my_multiline_lambda.source_location.last.should == 27
end
it "returns the location of the proc's body; not necessarily the proc itself" do
- ProcSpecs::SourceLocation.my_detached_proc.source_location[1].should == 41
- ProcSpecs::SourceLocation.my_detached_proc_new.source_location[1].should == 51
- ProcSpecs::SourceLocation.my_detached_lambda.source_location[1].should == 46
+ ProcSpecs::SourceLocation.my_detached_proc.source_location.last.should == 41
+ ProcSpecs::SourceLocation.my_detached_proc_new.source_location.last.should == 51
+ ProcSpecs::SourceLocation.my_detached_lambda.source_location.last.should == 46
end
it "returns the same value for a proc-ified method as the method reports" do
@@ -93,12 +86,6 @@ describe "Proc#source_location" do
it "works for eval with a given line" do
proc = eval('-> {}', nil, "foo", 100)
- location = proc.source_location
- ruby_version_is(""..."3.5") do
- location.should == ["foo", 100]
- end
- ruby_version_is("3.5") do
- location.should == ["foo", 100, 2, 100, 5]
- end
+ proc.source_location.should == ["foo", 100]
end
end
diff --git a/spec/ruby/core/proc/to_proc_spec.rb b/spec/ruby/core/proc/to_proc_spec.rb
index ffaa34929b..7f35a4f19b 100644
--- a/spec/ruby/core/proc/to_proc_spec.rb
+++ b/spec/ruby/core/proc/to_proc_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Proc#to_proc" do
it "returns self" do
[Proc.new {}, -> {}, proc {}].each { |p|
- p.to_proc.should equal(p)
+ p.to_proc.should.equal?(p)
}
end
end
diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb
index 8e907f54bb..620f243ce5 100644
--- a/spec/ruby/core/process/_fork_spec.rb
+++ b/spec/ruby/core/process/_fork_spec.rb
@@ -5,9 +5,11 @@ describe "Process._fork" do
Process.respond_to?(:_fork).should == Process.respond_to?(:fork)
end
+ # Using respond_to? in a guard here is OK because the correct semantics
+ # are that _fork is implemented if and only if fork is (see above).
guard_not -> { Process.respond_to?(:fork) } do
it "raises a NotImplementedError when called" do
- -> { Process._fork }.should raise_error(NotImplementedError)
+ -> { Process._fork }.should.raise(NotImplementedError)
end
end
@@ -16,7 +18,7 @@ describe "Process._fork" do
Process.should_receive(:_fork).once.and_return(42)
pid = Process.fork {}
- pid.should equal(42)
+ pid.should.equal?(42)
end
end
end
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
index f5aba719e9..4c7a2c9ecb 100644
--- a/spec/ruby/core/process/argv0_spec.rb
+++ b/spec/ruby/core/process/argv0_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.argv0" do
it "returns a String" do
- Process.argv0.should be_kind_of(String)
+ Process.argv0.should.is_a?(String)
end
it "is the path given as the main script and the same as __FILE__" do
@@ -13,10 +13,8 @@ describe "Process.argv0" do
end
end
- ruby_bug "#19597", ""..."3.3" do
- it "returns a frozen object" do
- Process.argv0.should.frozen?
- end
+ it "returns a frozen object" do
+ Process.argv0.should.frozen?
end
it "returns every time the same object" do
diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb
index 6c1a52f21e..88158904e1 100644
--- a/spec/ruby/core/process/clock_gettime_spec.rb
+++ b/spec/ruby/core/process/clock_gettime_spec.rb
@@ -4,31 +4,31 @@ require_relative 'fixtures/clocks'
describe "Process.clock_gettime" do
ProcessSpecs.clock_constants.each do |name, value|
it "can be called with Process::#{name}" do
- Process.clock_gettime(value).should be_an_instance_of(Float)
+ Process.clock_gettime(value).should.instance_of?(Float)
end
end
describe 'time units' do
it 'handles a fixed set of time units' do
[:nanosecond, :microsecond, :millisecond, :second].each do |unit|
- Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should be_kind_of(Integer)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should.is_a?(Integer)
end
[:float_microsecond, :float_millisecond, :float_second].each do |unit|
- Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should.instance_of?(Float)
end
end
it 'raises an ArgumentError for an invalid time unit' do
- -> { Process.clock_gettime(Process::CLOCK_MONOTONIC, :bad) }.should raise_error(ArgumentError)
+ -> { Process.clock_gettime(Process::CLOCK_MONOTONIC, :bad) }.should.raise(ArgumentError)
end
it 'defaults to :float_second' do
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
- t1.should be_an_instance_of(Float)
- t2.should be_an_instance_of(Float)
+ t1.should.instance_of?(Float)
+ t2.should.instance_of?(Float)
t2.should be_close(t1, TIME_TOLERANCE)
end
@@ -36,116 +36,116 @@ describe "Process.clock_gettime" do
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC, nil)
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
- t1.should be_an_instance_of(Float)
- t2.should be_an_instance_of(Float)
+ t1.should.instance_of?(Float)
+ t2.should.instance_of?(Float)
t2.should be_close(t1, TIME_TOLERANCE)
end
end
describe "supports the platform clocks mentioned in the documentation" do
it "CLOCK_REALTIME" do
- Process.clock_gettime(Process::CLOCK_REALTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME).should.instance_of?(Float)
end
it "CLOCK_MONOTONIC" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC).should.instance_of?(Float)
end
# These specs need macOS 10.12+ / darwin 16+
guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do
platform_is :linux, :openbsd, :darwin do
it "CLOCK_PROCESS_CPUTIME_ID" do
- Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should.instance_of?(Float)
end
end
platform_is :linux, :freebsd, :openbsd, :darwin do
it "CLOCK_THREAD_CPUTIME_ID" do
- Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID).should.instance_of?(Float)
end
end
platform_is :linux, :darwin do
it "CLOCK_MONOTONIC_RAW" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should.instance_of?(Float)
end
end
platform_is :darwin do
it "CLOCK_MONOTONIC_RAW_APPROX" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW_APPROX).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW_APPROX).should.instance_of?(Float)
end
it "CLOCK_UPTIME_RAW and CLOCK_UPTIME_RAW_APPROX" do
- Process.clock_gettime(Process::CLOCK_UPTIME_RAW).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should.instance_of?(Float)
end
end
end
platform_is :freebsd do
it "CLOCK_VIRTUAL" do
- Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_VIRTUAL).should.instance_of?(Float)
end
it "CLOCK_PROF" do
- Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_PROF).should.instance_of?(Float)
end
end
platform_is :freebsd, :openbsd do
it "CLOCK_UPTIME" do
- Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME).should.instance_of?(Float)
end
end
platform_is :freebsd do
it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should.instance_of?(Float)
end
it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should.instance_of?(Float)
end
it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should.instance_of?(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should.instance_of?(Float)
end
it "CLOCK_SECOND" do
- Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_SECOND).should.instance_of?(Float)
end
end
guard -> { platform_is :linux and kernel_version_is '2.6.32' } do
it "CLOCK_REALTIME_COARSE" do
- Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should.instance_of?(Float)
end
it "CLOCK_MONOTONIC_COARSE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should.instance_of?(Float)
end
end
guard -> { platform_is :linux and kernel_version_is '2.6.39' } do
it "CLOCK_BOOTTIME" do
skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME)
- Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME).should.instance_of?(Float)
end
end
guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do
it "CLOCK_REALTIME_ALARM" do
skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM)
- Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should.instance_of?(Float)
end
it "CLOCK_BOOTTIME_ALARM" do
skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM)
- Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should.instance_of?(Float)
end
end
end
diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb
index 57cacadef2..5a4c478e74 100644
--- a/spec/ruby/core/process/constants_spec.rb
+++ b/spec/ruby/core/process/constants_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process::Constants" do
platform_is :darwin, :netbsd, :freebsd do
- it "are all present on BSD-like systems" do
+ describe "on BSD-like systems" do
%i[
WNOHANG
WUNTRACED
@@ -20,27 +20,31 @@ describe "Process::Constants" do
RLIMIT_NPROC
RLIMIT_NOFILE
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :darwin do
- it "are all present on Darwin" do
+ describe "on Darwin" do
%i[
RLIM_SAVED_MAX
RLIM_SAVED_CUR
RLIMIT_AS
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :linux do
- it "are all present on Linux" do
+ describe "on Linux" do
%i[
WNOHANG
WUNTRACED
@@ -61,37 +65,43 @@ describe "Process::Constants" do
RLIM_SAVED_MAX
RLIM_SAVED_CUR
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :netbsd, :freebsd do
- it "are all present on NetBSD and FreeBSD" do
+ describe "on NetBSD and FreeBSD" do
%i[
RLIMIT_SBSIZE
RLIMIT_AS
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :freebsd do
- it "are all present on FreeBSD" do
+ describe "on FreeBSD" do
%i[
RLIMIT_NPTS
].each do |const|
- Process.const_defined?(const).should be_true
- Process.const_get(const).should be_an_instance_of(Integer)
+ it "defines #{const}" do
+ Process.const_defined?(const).should == true
+ Process.const_get(const).should.instance_of?(Integer)
+ end
end
end
end
platform_is :windows do
- it "does not define RLIMIT constants" do
+ describe "on Windows" do
%i[
RLIMIT_CPU
RLIMIT_FSIZE
@@ -107,7 +117,9 @@ describe "Process::Constants" do
RLIM_SAVED_MAX
RLIM_SAVED_CUR
].each do |const|
- Process.const_defined?(const).should be_false
+ it "does not define #{const}" do
+ Process.const_defined?(const).should == false
+ end
end
end
end
diff --git a/spec/ruby/core/process/daemon_spec.rb b/spec/ruby/core/process/daemon_spec.rb
index 20b0d743b9..9b7eba1411 100644
--- a/spec/ruby/core/process/daemon_spec.rb
+++ b/spec/ruby/core/process/daemon_spec.rb
@@ -112,7 +112,7 @@ platform_is :windows do
it "raises a NotImplementedError" do
-> {
Process.daemon
- }.should raise_error(NotImplementedError)
+ }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb
index f13bda1f5d..33c674394e 100644
--- a/spec/ruby/core/process/detach_spec.rb
+++ b/spec/ruby/core/process/detach_spec.rb
@@ -5,7 +5,7 @@ describe "Process.detach" do
it "returns a thread" do
pid = Process.fork { Process.exit! }
thr = Process.detach(pid)
- thr.should be_kind_of(Thread)
+ thr.should.is_a?(Thread)
thr.join
end
@@ -15,7 +15,7 @@ describe "Process.detach" do
thr.join
status = thr.value
- status.should be_kind_of(Process::Status)
+ status.should.is_a?(Process::Status)
status.pid.should == pid
end
@@ -23,7 +23,7 @@ describe "Process.detach" do
it "reaps the child process's status automatically" do
pid = Process.fork { Process.exit! }
Process.detach(pid).join
- -> { Process.waitpid(pid) }.should raise_error(Errno::ECHILD)
+ -> { Process.waitpid(pid) }.should.raise(Errno::ECHILD)
end
end
@@ -52,12 +52,12 @@ describe "Process.detach" do
# Command `kill 0 pid`:
# - returns "1" if a process exists and
# - raises Errno::ESRCH otherwise
- -> { Process.kill(0, pid_not_existing) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid_not_existing) }.should.raise(Errno::ESRCH)
thr = Process.detach(pid_not_existing)
thr.join
- thr.should be_kind_of(Thread)
+ thr.should.is_a?(Thread)
end
it "calls #to_int to implicitly convert non-Integer pid to Integer" do
@@ -68,14 +68,14 @@ describe "Process.detach" do
end
it "raises TypeError when pid argument does not have #to_int method" do
- -> { Process.detach(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ -> { Process.detach(Object.new) }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "raises TypeError when #to_int returns non-Integer value" do
pid = MockObject.new('mock-enumerable')
pid.should_receive(:to_int).and_return(:symbol)
- -> { Process.detach(pid) }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Symbol)")
+ -> { Process.detach(pid) }.should raise_consistent_error(TypeError, "can't convert MockObject into Integer (MockObject#to_int gives Symbol)")
end
end
end
diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb
index a67b623d5c..69c86bebe2 100644
--- a/spec/ruby/core/process/egid_spec.rb
+++ b/spec/ruby/core/process/egid_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.egid" do
it "returns the effective group ID for this process" do
- Process.egid.should be_kind_of(Integer)
+ Process.egid.should.is_a?(Integer)
end
it "also goes by Process::GID.eid" do
@@ -18,7 +18,7 @@ describe "Process.egid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer or String" do
- -> { Process.egid = Object.new }.should raise_error(TypeError)
+ -> { Process.egid = Object.new }.should.raise(TypeError)
end
it "sets the effective group id to its own gid if given the username corresponding to its own gid" do
@@ -33,12 +33,12 @@ describe "Process.egid=" do
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do
- -> { Process.egid = 0 }.should raise_error(Errno::EPERM)
+ -> { Process.egid = 0 }.should.raise(Errno::EPERM)
end
platform_is :linux do
it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do
- -> { Process.egid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.egid = "root" }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb
index c1ec4171d0..da76f06e59 100644
--- a/spec/ruby/core/process/euid_spec.rb
+++ b/spec/ruby/core/process/euid_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.euid" do
it "returns the effective user ID for this process" do
- Process.euid.should be_kind_of(Integer)
+ Process.euid.should.is_a?(Integer)
end
it "also goes by Process::UID.eid" do
@@ -18,7 +18,7 @@ describe "Process.euid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer" do
- -> { Process.euid = Object.new }.should raise_error(TypeError)
+ -> { Process.euid = Object.new }.should.raise(TypeError)
end
it "sets the effective user id to its own uid if given the username corresponding to its own uid" do
@@ -33,11 +33,11 @@ describe "Process.euid=" do
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do
- -> { Process.euid = 0 }.should raise_error(Errno::EPERM)
+ -> { Process.euid = 0 }.should.raise(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do
- -> { Process.euid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.euid = "root" }.should.raise(Errno::EPERM)
end
end
diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb
index 0f371b39c8..a48d461b02 100644
--- a/spec/ruby/core/process/exec_spec.rb
+++ b/spec/ruby/core/process/exec_spec.rb
@@ -2,35 +2,35 @@ require_relative '../../spec_helper'
describe "Process.exec" do
it "raises Errno::ENOENT for an empty string" do
- -> { Process.exec "" }.should raise_error(Errno::ENOENT)
+ -> { Process.exec "" }.should.raise(Errno::ENOENT)
end
it "raises Errno::ENOENT for a command which does not exist" do
- -> { Process.exec "bogus-noent-script.sh" }.should raise_error(Errno::ENOENT)
+ -> { Process.exec "bogus-noent-script.sh" }.should.raise(Errno::ENOENT)
end
it "raises an ArgumentError if the command includes a null byte" do
- -> { Process.exec "\000" }.should raise_error(ArgumentError)
+ -> { Process.exec "\000" }.should.raise(ArgumentError)
end
unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises Errno::EACCES when the file does not have execute permissions" do
- -> { Process.exec __FILE__ }.should raise_error(Errno::EACCES)
+ -> { Process.exec __FILE__ }.should.raise(Errno::EACCES)
end
end
platform_is :windows do
it "raises Errno::EACCES or Errno::ENOEXEC when the file is not an executable file" do
- -> { Process.exec __FILE__ }.should raise_error(SystemCallError) { |e|
- [Errno::EACCES, Errno::ENOEXEC].should include(e.class)
+ -> { Process.exec __FILE__ }.should.raise(SystemCallError) { |e|
+ [Errno::EACCES, Errno::ENOEXEC].should.include?(e.class)
}
end
end
end
it "raises Errno::EACCES when passed a directory" do
- -> { Process.exec __dir__ }.should raise_error(Errno::EACCES)
+ -> { Process.exec __dir__ }.should.raise(Errno::EACCES)
end
it "runs the specified command, replacing current process" do
@@ -171,9 +171,9 @@ describe "Process.exec" do
end
it "raises an ArgumentError if the Array does not have exactly two elements" do
- -> { Process.exec([]) }.should raise_error(ArgumentError)
- -> { Process.exec([:a]) }.should raise_error(ArgumentError)
- -> { Process.exec([:a, :b, :c]) }.should raise_error(ArgumentError)
+ -> { Process.exec([]) }.should.raise(ArgumentError)
+ -> { Process.exec([:a]) }.should.raise(ArgumentError)
+ -> { Process.exec([:a, :b, :c]) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/process/fixtures/clocks.rb b/spec/ruby/core/process/fixtures/clocks.rb
index f043f6ac1f..5757e280be 100644
--- a/spec/ruby/core/process/fixtures/clocks.rb
+++ b/spec/ruby/core/process/fixtures/clocks.rb
@@ -2,7 +2,7 @@ module ProcessSpecs
def self.clock_constants
clocks = []
- platform_is_not :windows, :solaris do
+ platform_is_not :windows do
clocks += Process.constants.select { |c| c.to_s.start_with?('CLOCK_') }
# These require CAP_WAKE_ALARM and are not documented in
diff --git a/spec/ruby/core/process/getpriority_spec.rb b/spec/ruby/core/process/getpriority_spec.rb
index a35e5956a5..53fe7bfe20 100644
--- a/spec/ruby/core/process/getpriority_spec.rb
+++ b/spec/ruby/core/process/getpriority_spec.rb
@@ -5,19 +5,19 @@ describe "Process.getpriority" do
it "coerces arguments to Integers" do
ret = Process.getpriority mock_int(Process::PRIO_PROCESS), mock_int(0)
- ret.should be_kind_of(Integer)
+ ret.should.is_a?(Integer)
end
it "gets the scheduling priority for a specified process" do
- Process.getpriority(Process::PRIO_PROCESS, 0).should be_kind_of(Integer)
+ Process.getpriority(Process::PRIO_PROCESS, 0).should.is_a?(Integer)
end
it "gets the scheduling priority for a specified process group" do
- Process.getpriority(Process::PRIO_PGRP, 0).should be_kind_of(Integer)
+ Process.getpriority(Process::PRIO_PGRP, 0).should.is_a?(Integer)
end
it "gets the scheduling priority for a specified user" do
- Process.getpriority(Process::PRIO_USER, 0).should be_kind_of(Integer)
+ Process.getpriority(Process::PRIO_USER, 0).should.is_a?(Integer)
end
end
end
diff --git a/spec/ruby/core/process/getrlimit_spec.rb b/spec/ruby/core/process/getrlimit_spec.rb
index 883b8fac48..d36d8c3335 100644
--- a/spec/ruby/core/process/getrlimit_spec.rb
+++ b/spec/ruby/core/process/getrlimit_spec.rb
@@ -16,8 +16,8 @@ describe "Process.getrlimit" do
it "returns a two-element Array of Integers" do
result = Process.getrlimit Process::RLIMIT_CORE
result.size.should == 2
- result.first.should be_kind_of(Integer)
- result.last.should be_kind_of(Integer)
+ result.first.should.is_a?(Integer)
+ result.last.should.is_a?(Integer)
end
context "when passed an Object" do
@@ -36,7 +36,7 @@ describe "Process.getrlimit" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.getrlimit(obj) }.should raise_error(TypeError)
+ -> { Process.getrlimit(obj) }.should.raise(TypeError)
end
end
@@ -49,7 +49,7 @@ describe "Process.getrlimit" do
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.getrlimit(:FOO) }.should raise_error(ArgumentError)
+ -> { Process.getrlimit(:FOO) }.should.raise(ArgumentError)
end
end
@@ -62,7 +62,7 @@ describe "Process.getrlimit" do
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.getrlimit("FOO") }.should raise_error(ArgumentError)
+ -> { Process.getrlimit("FOO") }.should.raise(ArgumentError)
end
end
@@ -91,10 +91,10 @@ describe "Process.getrlimit" do
platform_is :windows do
it "is not implemented" do
- Process.respond_to?(:getrlimit).should be_false
+ Process.respond_to?(:getrlimit).should == false
-> do
Process.getrlimit(nil)
- end.should raise_error NotImplementedError
+ end.should.raise NotImplementedError
end
end
end
diff --git a/spec/ruby/core/process/groups_spec.rb b/spec/ruby/core/process/groups_spec.rb
index 33e0f9d7b3..fa916671a4 100644
--- a/spec/ruby/core/process/groups_spec.rb
+++ b/spec/ruby/core/process/groups_spec.rb
@@ -50,7 +50,7 @@ describe "Process.groups=" do
Process.groups.should == [ Process.gid ]
supplementary = groups - [ Process.gid ]
if supplementary.length > 0
- -> { Process.groups = supplementary }.should raise_error(Errno::EPERM)
+ -> { Process.groups = supplementary }.should.raise(Errno::EPERM)
end
end
end
@@ -59,7 +59,7 @@ describe "Process.groups=" do
it "raises Errno::EPERM" do
-> {
Process.groups = [0]
- }.should raise_error(Errno::EPERM)
+ }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/process/initgroups_spec.rb b/spec/ruby/core/process/initgroups_spec.rb
index ffc7f282b6..d9f31936cb 100644
--- a/spec/ruby/core/process/initgroups_spec.rb
+++ b/spec/ruby/core/process/initgroups_spec.rb
@@ -14,7 +14,7 @@ describe "Process.initgroups" do
Process.groups.sort.should == augmented_groups.sort
Process.groups = groups
else
- -> { Process.initgroups(name, gid) }.should raise_error(Errno::EPERM)
+ -> { Process.initgroups(name, gid) }.should.raise(Errno::EPERM)
end
end
end
diff --git a/spec/ruby/core/process/kill_spec.rb b/spec/ruby/core/process/kill_spec.rb
index af9c9e6deb..885c2bf2b7 100644
--- a/spec/ruby/core/process/kill_spec.rb
+++ b/spec/ruby/core/process/kill_spec.rb
@@ -9,18 +9,18 @@ describe "Process.kill" do
end
it "raises an ArgumentError for unknown signals" do
- -> { Process.kill("FOO", @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill("FOO", @pid) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed a lowercase signal name" do
- -> { Process.kill("term", @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill("term", @pid) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if signal is not an Integer or String" do
signal = mock("process kill signal")
signal.should_not_receive(:to_int)
- -> { Process.kill(signal, @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill(signal, @pid) }.should.raise(ArgumentError)
end
it "raises Errno::ESRCH if the process does not exist" do
@@ -29,7 +29,7 @@ describe "Process.kill" do
Process.wait(pid)
-> {
Process.kill("SIGKILL", pid)
- }.should raise_error(Errno::ESRCH)
+ }.should.raise(Errno::ESRCH)
end
it "checks for existence and permissions to signal a process, but does not actually signal it, when using signal 0" do
diff --git a/spec/ruby/core/process/last_status_spec.rb b/spec/ruby/core/process/last_status_spec.rb
index 2372f2aae3..1bd8adf798 100644
--- a/spec/ruby/core/process/last_status_spec.rb
+++ b/spec/ruby/core/process/last_status_spec.rb
@@ -13,6 +13,6 @@ describe 'Process#last_status' do
end
it 'raises an ArgumentError if any arguments are provided' do
- -> { Process.last_status(1) }.should raise_error(ArgumentError)
+ -> { Process.last_status(1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/process/maxgroups_spec.rb b/spec/ruby/core/process/maxgroups_spec.rb
index 2549a7a971..895b384bd0 100644
--- a/spec/ruby/core/process/maxgroups_spec.rb
+++ b/spec/ruby/core/process/maxgroups_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
platform_is_not :windows do
describe "Process.maxgroups" do
it "returns the maximum number of gids allowed in the supplemental group access list" do
- Process.maxgroups.should be_kind_of(Integer)
+ Process.maxgroups.should.is_a?(Integer)
end
it "sets the maximum number of gids allowed in the supplemental group access list" do
diff --git a/spec/ruby/core/process/pid_spec.rb b/spec/ruby/core/process/pid_spec.rb
index 2d008bc4b7..42b0b918b9 100644
--- a/spec/ruby/core/process/pid_spec.rb
+++ b/spec/ruby/core/process/pid_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Process.pid" do
it "returns the process id of this process" do
pid = Process.pid
- pid.should be_kind_of(Integer)
+ pid.should.is_a?(Integer)
Process.pid.should == pid
end
end
diff --git a/spec/ruby/core/process/set_proctitle_spec.rb b/spec/ruby/core/process/set_proctitle_spec.rb
index d022f2021c..28a0fa6cee 100644
--- a/spec/ruby/core/process/set_proctitle_spec.rb
+++ b/spec/ruby/core/process/set_proctitle_spec.rb
@@ -17,7 +17,7 @@ describe 'Process.setproctitle' do
title = 'rubyspec-proctitle-test'
Process.setproctitle(title).should == title
- `ps -ocommand= -p#{$$}`.should include(title)
+ `ps -ocommand= -p#{$$}`.should.include?(title)
end
end
end
diff --git a/spec/ruby/core/process/setrlimit_spec.rb b/spec/ruby/core/process/setrlimit_spec.rb
index b92f98fd40..f02ab46fca 100644
--- a/spec/ruby/core/process/setrlimit_spec.rb
+++ b/spec/ruby/core/process/setrlimit_spec.rb
@@ -9,200 +9,196 @@ describe "Process.setrlimit" do
end
it "calls #to_int to convert resource to an Integer" do
- Process.setrlimit(mock_int(@resource), @limit, @max).should be_nil
+ Process.setrlimit(mock_int(@resource), @limit, @max).should == nil
end
it "raises a TypeError if #to_int for resource does not return an Integer" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.setrlimit(obj, @limit, @max) }.should raise_error(TypeError)
+ -> { Process.setrlimit(obj, @limit, @max) }.should.raise(TypeError)
end
it "calls #to_int to convert the soft limit to an Integer" do
- Process.setrlimit(@resource, mock_int(@limit), @max).should be_nil
+ Process.setrlimit(@resource, mock_int(@limit), @max).should == nil
end
it "raises a TypeError if #to_int for resource does not return an Integer" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.setrlimit(@resource, obj, @max) }.should raise_error(TypeError)
+ -> { Process.setrlimit(@resource, obj, @max) }.should.raise(TypeError)
end
it "calls #to_int to convert the hard limit to an Integer" do
- Process.setrlimit(@resource, @limit, mock_int(@max)).should be_nil
+ Process.setrlimit(@resource, @limit, mock_int(@max)).should == nil
end
it "raises a TypeError if #to_int for resource does not return an Integer" do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- -> { Process.setrlimit(@resource, @limit, obj) }.should raise_error(TypeError)
+ -> { Process.setrlimit(@resource, @limit, obj) }.should.raise(TypeError)
end
end
context "when passed a Symbol" do
platform_is_not :openbsd do
it "coerces :AS into RLIMIT_AS" do
- Process.setrlimit(:AS, *Process.getrlimit(Process::RLIMIT_AS)).should be_nil
+ Process.setrlimit(:AS, *Process.getrlimit(Process::RLIMIT_AS)).should == nil
end
end
it "coerces :CORE into RLIMIT_CORE" do
- Process.setrlimit(:CORE, *Process.getrlimit(Process::RLIMIT_CORE)).should be_nil
+ Process.setrlimit(:CORE, *Process.getrlimit(Process::RLIMIT_CORE)).should == nil
end
it "coerces :CPU into RLIMIT_CPU" do
- Process.setrlimit(:CPU, *Process.getrlimit(Process::RLIMIT_CPU)).should be_nil
+ Process.setrlimit(:CPU, *Process.getrlimit(Process::RLIMIT_CPU)).should == nil
end
it "coerces :DATA into RLIMIT_DATA" do
- Process.setrlimit(:DATA, *Process.getrlimit(Process::RLIMIT_DATA)).should be_nil
+ Process.setrlimit(:DATA, *Process.getrlimit(Process::RLIMIT_DATA)).should == nil
end
it "coerces :FSIZE into RLIMIT_FSIZE" do
- Process.setrlimit(:FSIZE, *Process.getrlimit(Process::RLIMIT_FSIZE)).should be_nil
+ Process.setrlimit(:FSIZE, *Process.getrlimit(Process::RLIMIT_FSIZE)).should == nil
end
it "coerces :NOFILE into RLIMIT_NOFILE" do
- Process.setrlimit(:NOFILE, *Process.getrlimit(Process::RLIMIT_NOFILE)).should be_nil
+ Process.setrlimit(:NOFILE, *Process.getrlimit(Process::RLIMIT_NOFILE)).should == nil
end
it "coerces :STACK into RLIMIT_STACK" do
- Process.setrlimit(:STACK, *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
+ Process.setrlimit(:STACK, *Process.getrlimit(Process::RLIMIT_STACK)).should == nil
end
- platform_is_not :solaris, :aix do
+ platform_is_not :aix do
it "coerces :MEMLOCK into RLIMIT_MEMLOCK" do
- Process.setrlimit(:MEMLOCK, *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
+ Process.setrlimit(:MEMLOCK, *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should == nil
end
end
- platform_is_not :solaris do
- it "coerces :NPROC into RLIMIT_NPROC" do
- Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
- end
+ it "coerces :NPROC into RLIMIT_NPROC" do
+ Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should == nil
+ end
- it "coerces :RSS into RLIMIT_RSS" do
- Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
- end
+ it "coerces :RSS into RLIMIT_RSS" do
+ Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should == nil
end
platform_is :netbsd, :freebsd do
it "coerces :SBSIZE into RLIMIT_SBSIZE" do
- Process.setrlimit(:SBSIZE, *Process.getrlimit(Process::RLIMIT_SBSIZE)).should be_nil
+ Process.setrlimit(:SBSIZE, *Process.getrlimit(Process::RLIMIT_SBSIZE)).should == nil
end
end
platform_is :linux do
it "coerces :RTPRIO into RLIMIT_RTPRIO" do
- Process.setrlimit(:RTPRIO, *Process.getrlimit(Process::RLIMIT_RTPRIO)).should be_nil
+ Process.setrlimit(:RTPRIO, *Process.getrlimit(Process::RLIMIT_RTPRIO)).should == nil
end
guard -> { defined?(Process::RLIMIT_RTTIME) } do
it "coerces :RTTIME into RLIMIT_RTTIME" do
- Process.setrlimit(:RTTIME, *Process.getrlimit(Process::RLIMIT_RTTIME)).should be_nil
+ Process.setrlimit(:RTTIME, *Process.getrlimit(Process::RLIMIT_RTTIME)).should == nil
end
end
it "coerces :SIGPENDING into RLIMIT_SIGPENDING" do
- Process.setrlimit(:SIGPENDING, *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should be_nil
+ Process.setrlimit(:SIGPENDING, *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should == nil
end
it "coerces :MSGQUEUE into RLIMIT_MSGQUEUE" do
- Process.setrlimit(:MSGQUEUE, *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should be_nil
+ Process.setrlimit(:MSGQUEUE, *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should == nil
end
it "coerces :NICE into RLIMIT_NICE" do
- Process.setrlimit(:NICE, *Process.getrlimit(Process::RLIMIT_NICE)).should be_nil
+ Process.setrlimit(:NICE, *Process.getrlimit(Process::RLIMIT_NICE)).should == nil
end
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.setrlimit(:FOO, 1, 1) }.should raise_error(ArgumentError)
+ -> { Process.setrlimit(:FOO, 1, 1) }.should.raise(ArgumentError)
end
end
context "when passed a String" do
platform_is_not :openbsd do
it "coerces 'AS' into RLIMIT_AS" do
- Process.setrlimit("AS", *Process.getrlimit(Process::RLIMIT_AS)).should be_nil
+ Process.setrlimit("AS", *Process.getrlimit(Process::RLIMIT_AS)).should == nil
end
end
it "coerces 'CORE' into RLIMIT_CORE" do
- Process.setrlimit("CORE", *Process.getrlimit(Process::RLIMIT_CORE)).should be_nil
+ Process.setrlimit("CORE", *Process.getrlimit(Process::RLIMIT_CORE)).should == nil
end
it "coerces 'CPU' into RLIMIT_CPU" do
- Process.setrlimit("CPU", *Process.getrlimit(Process::RLIMIT_CPU)).should be_nil
+ Process.setrlimit("CPU", *Process.getrlimit(Process::RLIMIT_CPU)).should == nil
end
it "coerces 'DATA' into RLIMIT_DATA" do
- Process.setrlimit("DATA", *Process.getrlimit(Process::RLIMIT_DATA)).should be_nil
+ Process.setrlimit("DATA", *Process.getrlimit(Process::RLIMIT_DATA)).should == nil
end
it "coerces 'FSIZE' into RLIMIT_FSIZE" do
- Process.setrlimit("FSIZE", *Process.getrlimit(Process::RLIMIT_FSIZE)).should be_nil
+ Process.setrlimit("FSIZE", *Process.getrlimit(Process::RLIMIT_FSIZE)).should == nil
end
it "coerces 'NOFILE' into RLIMIT_NOFILE" do
- Process.setrlimit("NOFILE", *Process.getrlimit(Process::RLIMIT_NOFILE)).should be_nil
+ Process.setrlimit("NOFILE", *Process.getrlimit(Process::RLIMIT_NOFILE)).should == nil
end
it "coerces 'STACK' into RLIMIT_STACK" do
- Process.setrlimit("STACK", *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
+ Process.setrlimit("STACK", *Process.getrlimit(Process::RLIMIT_STACK)).should == nil
end
- platform_is_not :solaris, :aix do
+ platform_is_not :aix do
it "coerces 'MEMLOCK' into RLIMIT_MEMLOCK" do
- Process.setrlimit("MEMLOCK", *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
+ Process.setrlimit("MEMLOCK", *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should == nil
end
end
- platform_is_not :solaris do
- it "coerces 'NPROC' into RLIMIT_NPROC" do
- Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
- end
+ it "coerces 'NPROC' into RLIMIT_NPROC" do
+ Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should == nil
+ end
- it "coerces 'RSS' into RLIMIT_RSS" do
- Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
- end
+ it "coerces 'RSS' into RLIMIT_RSS" do
+ Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should == nil
end
platform_is :netbsd, :freebsd do
it "coerces 'SBSIZE' into RLIMIT_SBSIZE" do
- Process.setrlimit("SBSIZE", *Process.getrlimit(Process::RLIMIT_SBSIZE)).should be_nil
+ Process.setrlimit("SBSIZE", *Process.getrlimit(Process::RLIMIT_SBSIZE)).should == nil
end
end
platform_is :linux do
it "coerces 'RTPRIO' into RLIMIT_RTPRIO" do
- Process.setrlimit("RTPRIO", *Process.getrlimit(Process::RLIMIT_RTPRIO)).should be_nil
+ Process.setrlimit("RTPRIO", *Process.getrlimit(Process::RLIMIT_RTPRIO)).should == nil
end
guard -> { defined?(Process::RLIMIT_RTTIME) } do
it "coerces 'RTTIME' into RLIMIT_RTTIME" do
- Process.setrlimit("RTTIME", *Process.getrlimit(Process::RLIMIT_RTTIME)).should be_nil
+ Process.setrlimit("RTTIME", *Process.getrlimit(Process::RLIMIT_RTTIME)).should == nil
end
end
it "coerces 'SIGPENDING' into RLIMIT_SIGPENDING" do
- Process.setrlimit("SIGPENDING", *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should be_nil
+ Process.setrlimit("SIGPENDING", *Process.getrlimit(Process::RLIMIT_SIGPENDING)).should == nil
end
it "coerces 'MSGQUEUE' into RLIMIT_MSGQUEUE" do
- Process.setrlimit("MSGQUEUE", *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should be_nil
+ Process.setrlimit("MSGQUEUE", *Process.getrlimit(Process::RLIMIT_MSGQUEUE)).should == nil
end
it "coerces 'NICE' into RLIMIT_NICE" do
- Process.setrlimit("NICE", *Process.getrlimit(Process::RLIMIT_NICE)).should be_nil
+ Process.setrlimit("NICE", *Process.getrlimit(Process::RLIMIT_NICE)).should == nil
end
end
it "raises ArgumentError when passed an unknown resource" do
- -> { Process.setrlimit("FOO", 1, 1) }.should raise_error(ArgumentError)
+ -> { Process.setrlimit("FOO", 1, 1) }.should.raise(ArgumentError)
end
end
@@ -217,7 +213,7 @@ describe "Process.setrlimit" do
obj.should_receive(:to_str).and_return("CORE")
obj.should_not_receive(:to_int)
- Process.setrlimit(obj, @limit, @max).should be_nil
+ Process.setrlimit(obj, @limit, @max).should == nil
end
it "calls #to_int if #to_str does not return a String" do
@@ -225,17 +221,17 @@ describe "Process.setrlimit" do
obj.should_receive(:to_str).and_return(nil)
obj.should_receive(:to_int).and_return(@resource)
- Process.setrlimit(obj, @limit, @max).should be_nil
+ Process.setrlimit(obj, @limit, @max).should == nil
end
end
end
platform_is :windows do
it "is not implemented" do
- Process.respond_to?(:setrlimit).should be_false
+ Process.respond_to?(:setrlimit).should == false
-> do
Process.setrlimit(nil, nil)
- end.should raise_error NotImplementedError
+ end.should.raise NotImplementedError
end
end
end
diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb
index 283a7f033d..fb619dce42 100644
--- a/spec/ruby/core/process/spawn_spec.rb
+++ b/spec/ruby/core/process/spawn_spec.rb
@@ -51,7 +51,7 @@ describe "Process.spawn" do
it "returns the process ID of the new process as an Integer" do
pid = Process.spawn(*ruby_exe, "-e", "exit")
Process.wait pid
- pid.should be_an_instance_of(Integer)
+ pid.should.instance_of?(Integer)
end
it "returns immediately" do
@@ -93,11 +93,11 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if the command includes a null byte" do
- -> { Process.spawn "\000" }.should raise_error(ArgumentError)
+ -> { Process.spawn "\000" }.should.raise(ArgumentError)
end
it "raises a TypeError if the argument does not respond to #to_str" do
- -> { Process.spawn :echo }.should raise_error(TypeError)
+ -> { Process.spawn :echo }.should.raise(TypeError)
end
end
@@ -122,11 +122,11 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if an argument includes a null byte" do
- -> { Process.spawn "echo", "\000" }.should raise_error(ArgumentError)
+ -> { Process.spawn "echo", "\000" }.should.raise(ArgumentError)
end
it "raises a TypeError if an argument does not respond to #to_str" do
- -> { Process.spawn "echo", :foo }.should raise_error(TypeError)
+ -> { Process.spawn "echo", :foo }.should.raise(TypeError)
end
end
@@ -178,19 +178,19 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if the Array does not have exactly two elements" do
- -> { Process.spawn([]) }.should raise_error(ArgumentError)
- -> { Process.spawn([:a]) }.should raise_error(ArgumentError)
- -> { Process.spawn([:a, :b, :c]) }.should raise_error(ArgumentError)
+ -> { Process.spawn([]) }.should.raise(ArgumentError)
+ -> { Process.spawn([:a]) }.should.raise(ArgumentError)
+ -> { Process.spawn([:a, :b, :c]) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the Strings in the Array include a null byte" do
- -> { Process.spawn ["\000", "echo"] }.should raise_error(ArgumentError)
- -> { Process.spawn ["echo", "\000"] }.should raise_error(ArgumentError)
+ -> { Process.spawn ["\000", "echo"] }.should.raise(ArgumentError)
+ -> { Process.spawn ["echo", "\000"] }.should.raise(ArgumentError)
end
it "raises a TypeError if an element in the Array does not respond to #to_str" do
- -> { Process.spawn ["echo", :echo] }.should raise_error(TypeError)
- -> { Process.spawn [:echo, "echo"] }.should raise_error(TypeError)
+ -> { Process.spawn ["echo", :echo] }.should.raise(TypeError)
+ -> { Process.spawn [:echo, "echo"] }.should.raise(TypeError)
end
end
@@ -256,19 +256,19 @@ describe "Process.spawn" do
it "raises an ArgumentError if an environment key includes an equals sign" do
-> do
Process.spawn({"FOO=" => "BAR"}, "echo #{@var}>#{@name}")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError if an environment key includes a null byte" do
-> do
Process.spawn({"\000" => "BAR"}, "echo #{@var}>#{@name}")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError if an environment value includes a null byte" do
-> do
Process.spawn({"FOO" => "\000"}, "echo #{@var}>#{@name}")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
# :unsetenv_others
@@ -285,7 +285,7 @@ describe "Process.spawn" do
it "unsets other environment variables when given a true :unsetenv_others option" do
ENV["FOO"] = "BAR"
Process.wait Process.spawn(*@common_env_spawn_args, unsetenv_others: true)
- $?.success?.should be_true
+ $?.success?.should == true
File.read(@name).should == "\n"
end
end
@@ -293,7 +293,7 @@ describe "Process.spawn" do
it "does not unset other environment variables when given a false :unsetenv_others option" do
ENV["FOO"] = "BAR"
Process.wait Process.spawn(*@common_env_spawn_args, unsetenv_others: false)
- $?.success?.should be_true
+ $?.success?.should == true
File.read(@name).should == "BAR\n"
end
@@ -301,7 +301,7 @@ describe "Process.spawn" do
it "does not unset environment variables included in the environment hash" do
env = @minimal_env.merge({"FOO" => "BAR"})
Process.wait Process.spawn(env, "echo #{@var}>#{@name}", unsetenv_others: true)
- $?.success?.should be_true
+ $?.success?.should == true
File.read(@name).should == "BAR\n"
end
end
@@ -363,17 +363,17 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if given a negative :pgroup option" do
- -> { Process.spawn("echo", pgroup: -1) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", pgroup: -1) }.should.raise(ArgumentError)
end
it "raises a TypeError if given a symbol as :pgroup option" do
- -> { Process.spawn("echo", pgroup: :true) }.should raise_error(TypeError)
+ -> { Process.spawn("echo", pgroup: :true) }.should.raise(TypeError)
end
end
platform_is :windows do
it "raises an ArgumentError if given :pgroup option" do
- -> { Process.spawn("echo", pgroup: false) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", pgroup: false) }.should.raise(ArgumentError)
end
end
@@ -452,7 +452,7 @@ describe "Process.spawn" do
children.each do |child|
-> do
Process.kill("TERM", child)
- end.should raise_error(Errno::ESRCH)
+ end.should.raise(Errno::ESRCH)
end
end
end
@@ -678,53 +678,93 @@ describe "Process.spawn" do
# error handling
it "raises an ArgumentError if passed no command arguments" do
- -> { Process.spawn }.should raise_error(ArgumentError)
+ -> { Process.spawn }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed env or options but no command arguments" do
- -> { Process.spawn({}) }.should raise_error(ArgumentError)
+ -> { Process.spawn({}) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed env and options but no command arguments" do
- -> { Process.spawn({}, {}) }.should raise_error(ArgumentError)
+ -> { Process.spawn({}, {}) }.should.raise(ArgumentError)
end
it "raises an Errno::ENOENT for an empty string" do
- -> { Process.spawn "" }.should raise_error(Errno::ENOENT)
+ -> { Process.spawn "" }.should.raise(Errno::ENOENT)
end
it "raises an Errno::ENOENT if the command does not exist" do
- -> { Process.spawn "nonesuch" }.should raise_error(Errno::ENOENT)
+ -> { Process.spawn "nonesuch" }.should.raise(Errno::ENOENT, "No such file or directory - nonesuch")
+ end
+
+ it "sets $? to exit status 127 when the command does not exist" do
+ Process.spawn("nonesuch") rescue nil
+ $?.exitstatus.should == 127
+ end
+
+ it "raises an Errno::ENOENT if the file does not exist" do
+ -> { Process.spawn "./nonesuch" }.should.raise(Errno::ENOENT, "No such file or directory - ./nonesuch")
+ end
+
+ it "sets $? to exit status 127 when the file does not exist" do
+ Process.spawn("./nonesuch") rescue nil
+ $?.exitstatus.should == 127
+ end
+
+ platform_is_not :windows do
+ it "raises an Errno::EACCES when the path is a directory" do
+ -> { Process.spawn "./" }.should.raise(Errno::EACCES, "Permission denied - ./")
+ end
end
unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises an Errno::EACCES when the file does not have execute permissions" do
- -> { Process.spawn __FILE__ }.should raise_error(Errno::EACCES)
+ -> { Process.spawn __FILE__ }.should.raise(Errno::EACCES, "Permission denied - #{__FILE__}")
+ end
+
+ it "sets $? to exit status 127 when the file does not have execute permissions" do
+ Process.spawn(__FILE__) rescue nil
+ $?.exitstatus.should == 127
+ end
+
+ it "raises an Errno::ENOENT when a non-executable file is found in PATH" do
+ dir = tmp("spawn_path_non_executable_dir")
+ mkdir_p dir
+ begin
+ exe = 'process-spawn-non-executable-in-path'
+ File.write("#{dir}/#{exe}", "#!/bin/sh\necho hi")
+ File.chmod(0644, "#{dir}/#{exe}")
+ env = { "PATH" => "#{dir}#{File::PATH_SEPARATOR}#{ENV['PATH']}" }
+ -> { Process.spawn(env, exe) }.should.raise(Errno::ENOENT, "No such file or directory - #{exe}")
+ $?.exitstatus.should == 127
+ ensure
+ rm_r dir
+ end
end
end
platform_is :windows do
it "raises Errno::EACCES or Errno::ENOEXEC when the file is not an executable file" do
- -> { Process.spawn __FILE__ }.should raise_error(SystemCallError) { |e|
- [Errno::EACCES, Errno::ENOEXEC].should include(e.class)
+ -> { Process.spawn __FILE__ }.should.raise(SystemCallError) { |e|
+ [Errno::EACCES, Errno::ENOEXEC].should.include?(e.class)
}
end
end
end
it "raises an Errno::EACCES or Errno::EISDIR when passed a directory" do
- -> { Process.spawn __dir__ }.should raise_error(SystemCallError) { |e|
- [Errno::EACCES, Errno::EISDIR].should include(e.class)
+ -> { Process.spawn __dir__ }.should.raise(SystemCallError) { |e|
+ [Errno::EACCES, Errno::EISDIR].should.include?(e.class)
}
end
it "raises an ArgumentError when passed a string key in options" do
- -> { Process.spawn("echo", "chdir" => Dir.pwd) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", "chdir" => Dir.pwd) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed an unknown option key" do
- -> { Process.spawn("echo", nonesuch: :foo) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", nonesuch: :foo) }.should.raise(ArgumentError)
end
platform_is_not :windows, :aix do
diff --git a/spec/ruby/core/process/status/bit_and_spec.rb b/spec/ruby/core/process/status/bit_and_spec.rb
index 0e0edb0afa..a5b1123e90 100644
--- a/spec/ruby/core/process/status/bit_and_spec.rb
+++ b/spec/ruby/core/process/status/bit_and_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
describe "Process::Status#&" do
it "returns a bitwise and of the integer status of an exited child" do
@@ -17,13 +17,13 @@ ruby_version_is ""..."3.5" do
end
end
- ruby_version_is "3.3"..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises an ArgumentError if mask is negative" do
suppress_warning do
ruby_exe("exit(0)")
-> {
$? & -1
- }.should raise_error(ArgumentError, 'negative mask value: -1')
+ }.should.raise(ArgumentError, 'negative mask value: -1')
end
end
diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb
index a61292b146..ad14b35000 100644
--- a/spec/ruby/core/process/status/exited_spec.rb
+++ b/spec/ruby/core/process/status/exited_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#exited?" do
end
it "returns true" do
- $?.exited?.should be_true
+ $?.exited?.should == true
end
end
@@ -19,13 +19,13 @@ describe "Process::Status#exited?" do
platform_is_not :windows do
it "returns false" do
- $?.exited?.should be_false
+ $?.exited?.should == false
end
end
platform_is :windows do
it "always returns true" do
- $?.exited?.should be_true
+ $?.exited?.should == true
end
end
end
diff --git a/spec/ruby/core/process/status/right_shift_spec.rb b/spec/ruby/core/process/status/right_shift_spec.rb
index a1ab75141a..5689526f54 100644
--- a/spec/ruby/core/process/status/right_shift_spec.rb
+++ b/spec/ruby/core/process/status/right_shift_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
describe "Process::Status#>>" do
it "returns a right shift of the integer status of an exited child" do
@@ -16,13 +16,13 @@ ruby_version_is ""..."3.5" do
end
end
- ruby_version_is "3.3"..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises an ArgumentError if shift value is negative" do
suppress_warning do
ruby_exe("exit(0)")
-> {
$? >> -1
- }.should raise_error(ArgumentError, 'negative shift value: -1')
+ }.should.raise(ArgumentError, 'negative shift value: -1')
end
end
diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb
index c0de7b8006..8cf409bb42 100644
--- a/spec/ruby/core/process/status/signaled_spec.rb
+++ b/spec/ruby/core/process/status/signaled_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#signaled?" do
end
it "returns false" do
- $?.signaled?.should be_false
+ $?.signaled?.should == false
end
end
@@ -18,13 +18,13 @@ describe "Process::Status#signaled?" do
platform_is_not :windows do
it "returns true" do
- $?.signaled?.should be_true
+ $?.signaled?.should == true
end
end
platform_is :windows do
it "always returns false" do
- $?.signaled?.should be_false
+ $?.signaled?.should == false
end
end
end
diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb
index 3589cc611f..f61243c667 100644
--- a/spec/ruby/core/process/status/success_spec.rb
+++ b/spec/ruby/core/process/status/success_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#success?" do
end
it "returns true" do
- $?.success?.should be_true
+ $?.success?.should == true
end
end
@@ -17,7 +17,7 @@ describe "Process::Status#success?" do
end
it "returns false" do
- $?.success?.should be_false
+ $?.success?.should == false
end
end
@@ -28,13 +28,13 @@ describe "Process::Status#success?" do
platform_is_not :windows do
it "returns nil" do
- $?.success?.should be_nil
+ $?.success?.should == nil
end
end
platform_is :windows do
it "always returns true" do
- $?.success?.should be_true
+ $?.success?.should == true
end
end
end
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 9a22dbea71..1d57724d12 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#termsig" do
end
it "returns nil" do
- $?.termsig.should be_nil
+ $?.termsig.should == nil
end
end
@@ -36,7 +36,7 @@ describe "Process::Status#termsig" do
platform_is :windows do
it "always returns nil" do
- $?.termsig.should be_nil
+ $?.termsig.should == nil
end
end
end
diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb
index 39f8e2d84c..0bfb883d23 100644
--- a/spec/ruby/core/process/status/to_i_spec.rb
+++ b/spec/ruby/core/process/status/to_i_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../../spec_helper'
describe "Process::Status#to_i" do
it "returns an integer when the child exits" do
ruby_exe('exit 48', exit_status: 48)
- $?.to_i.should be_an_instance_of(Integer)
+ $?.to_i.should.instance_of?(Integer)
end
it "returns an integer when the child is signaled" do
ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM)
- $?.to_i.should be_an_instance_of(Integer)
+ $?.to_i.should.instance_of?(Integer)
end
end
diff --git a/spec/ruby/core/process/status/wait_spec.rb b/spec/ruby/core/process/status/wait_spec.rb
index 57d56209a9..18ecc14f6f 100644
--- a/spec/ruby/core/process/status/wait_spec.rb
+++ b/spec/ruby/core/process/status/wait_spec.rb
@@ -21,14 +21,14 @@ describe "Process::Status.wait" do
it "returns a status with its child pid" do
pid = Process.spawn(ruby_cmd('exit'))
status = Process::Status.wait
- status.should be_an_instance_of(Process::Status)
+ status.should.instance_of?(Process::Status)
status.pid.should == pid
end
it "should not set $? to the Process::Status" do
pid = Process.spawn(ruby_cmd('exit'))
status = Process::Status.wait
- $?.should_not equal(status)
+ $?.should_not.equal?(status)
end
it "should not change the value of $?" do
@@ -36,13 +36,13 @@ describe "Process::Status.wait" do
Process.wait
status = $?
Process::Status.wait
- status.should equal($?)
+ status.should.equal?($?)
end
it "waits for any child process if no pid is given" do
pid = Process.spawn(ruby_cmd('exit'))
Process::Status.wait.pid.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
it "waits for a specific child if a pid is given" do
@@ -50,14 +50,14 @@ describe "Process::Status.wait" do
pid2 = Process.spawn(ruby_cmd('exit'))
Process::Status.wait(pid2).pid.should == pid2
Process::Status.wait(pid1).pid.should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should.raise(Errno::ESRCH)
end
it "coerces the pid to an Integer" do
pid1 = Process.spawn(ruby_cmd('exit'))
Process::Status.wait(mock_int(pid1)).pid.should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
end
# This spec is probably system-dependent.
@@ -80,7 +80,7 @@ describe "Process::Status.wait" do
sleep
end
- Process::Status.wait(pid, Process::WNOHANG).should be_nil
+ Process::Status.wait(pid, Process::WNOHANG).should == nil
# wait for the child to setup its TERM handler
write.close
@@ -94,7 +94,7 @@ describe "Process::Status.wait" do
it "always accepts flags=0" do
pid = Process.spawn(ruby_cmd('exit'))
Process::Status.wait(-1, 0).pid.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
end
end
diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb
index d3bff2cda9..a7ffbb79e5 100644
--- a/spec/ruby/core/process/times_spec.rb
+++ b/spec/ruby/core/process/times_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Process.times" do
it "returns a Process::Tms" do
- Process.times.should be_kind_of(Process::Tms)
+ Process.times.should.is_a?(Process::Tms)
end
# TODO: Intel C Compiler does not work this example
diff --git a/spec/ruby/core/process/uid_spec.rb b/spec/ruby/core/process/uid_spec.rb
index a068b1a2c1..1e218ef4fe 100644
--- a/spec/ruby/core/process/uid_spec.rb
+++ b/spec/ruby/core/process/uid_spec.rb
@@ -20,16 +20,16 @@ end
describe "Process.uid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer" do
- -> { Process.uid = Object.new }.should raise_error(TypeError)
+ -> { Process.uid = Object.new }.should.raise(TypeError)
end
as_user do
it "raises Errno::ERPERM if run by a non privileged user trying to set the superuser id" do
- -> { (Process.uid = 0)}.should raise_error(Errno::EPERM)
+ -> { (Process.uid = 0)}.should.raise(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non privileged user trying to set the superuser id from username" do
- -> { Process.uid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.uid = "root" }.should.raise(Errno::EPERM)
end
end
diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb
index 8ba429dc96..5c57dd40fb 100644
--- a/spec/ruby/core/process/wait2_spec.rb
+++ b/spec/ruby/core/process/wait2_spec.rb
@@ -12,7 +12,7 @@ describe "Process.wait2" do
leaked = Process.waitall
$stderr.puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
# Ruby-space should not see PIDs used by rjit
- leaked.should be_empty
+ leaked.should.empty?
rescue Errno::ECHILD # No child processes
rescue NotImplementedError
end
@@ -30,15 +30,15 @@ describe "Process.wait2" do
end
it "raises a StandardError if no child processes exist" do
- -> { Process.wait2 }.should raise_error(Errno::ECHILD)
- -> { Process.wait2 }.should raise_error(StandardError)
+ -> { Process.wait2 }.should.raise(Errno::ECHILD)
+ -> { Process.wait2 }.should.raise(StandardError)
end
it "returns nil if the child process is still running when given the WNOHANG flag" do
IO.popen(ruby_cmd('STDIN.getbyte'), "w") do |io|
pid, status = Process.wait2(io.pid, Process::WNOHANG)
- pid.should be_nil
- status.should be_nil
+ pid.should == nil
+ status.should == nil
io.write('a')
end
end
diff --git a/spec/ruby/core/process/wait_spec.rb b/spec/ruby/core/process/wait_spec.rb
index 385acc9928..0b2e715f65 100644
--- a/spec/ruby/core/process/wait_spec.rb
+++ b/spec/ruby/core/process/wait_spec.rb
@@ -14,7 +14,7 @@ describe "Process.wait" do
end
it "raises an Errno::ECHILD if there are no child processes" do
- -> { Process.wait }.should raise_error(Errno::ECHILD)
+ -> { Process.wait }.should.raise(Errno::ECHILD)
end
platform_is_not :windows do
@@ -26,14 +26,14 @@ describe "Process.wait" do
it "sets $? to a Process::Status" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait
- $?.should be_kind_of(Process::Status)
+ $?.should.is_a?(Process::Status)
$?.pid.should == pid
end
it "waits for any child process if no pid is given" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
it "waits for a specific child if a pid is given" do
@@ -41,14 +41,14 @@ describe "Process.wait" do
pid2 = Process.spawn(ruby_cmd('exit'))
Process.wait(pid2).should == pid2
Process.wait(pid1).should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should.raise(Errno::ESRCH)
end
it "coerces the pid to an Integer" do
pid1 = Process.spawn(ruby_cmd('exit'))
Process.wait(mock_int(pid1)).should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should.raise(Errno::ESRCH)
end
# This spec is probably system-dependent.
@@ -71,7 +71,7 @@ describe "Process.wait" do
sleep
end
- Process.wait(pid, Process::WNOHANG).should be_nil
+ Process.wait(pid, Process::WNOHANG).should == nil
# wait for the child to setup its TERM handler
write.close
@@ -85,7 +85,7 @@ describe "Process.wait" do
it "always accepts flags=0" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait(-1, 0).should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
end
end
end
diff --git a/spec/ruby/core/process/waitall_spec.rb b/spec/ruby/core/process/waitall_spec.rb
index 6cf4e32bc9..a77873f553 100644
--- a/spec/ruby/core/process/waitall_spec.rb
+++ b/spec/ruby/core/process/waitall_spec.rb
@@ -13,7 +13,7 @@ describe "Process.waitall" do
end
it "takes no arguments" do
- -> { Process.waitall(0) }.should raise_error(ArgumentError)
+ -> { Process.waitall(0) }.should.raise(ArgumentError)
end
platform_is_not :windows do
@@ -24,7 +24,7 @@ describe "Process.waitall" do
pids << Process.fork { Process.exit! 0 }
Process.waitall
pids.each { |pid|
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should.raise(Errno::ESRCH)
}
end
@@ -34,14 +34,14 @@ describe "Process.waitall" do
pids << Process.fork { Process.exit! 1 }
pids << Process.fork { Process.exit! 0 }
a = Process.waitall
- a.should be_kind_of(Array)
+ a.should.is_a?(Array)
a.size.should == 3
pids.each { |pid|
pid_status = a.assoc(pid)
- pid_status.should be_kind_of(Array)
+ pid_status.should.is_a?(Array)
pid_status.size.should == 2
pid_status.first.should == pid
- pid_status.last.should be_kind_of(Process::Status)
+ pid_status.last.should.is_a?(Process::Status)
}
end
end
diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb
index b562d52d22..4530ae222c 100644
--- a/spec/ruby/core/process/warmup_spec.rb
+++ b/spec/ruby/core/process/warmup_spec.rb
@@ -1,11 +1,9 @@
require_relative '../../spec_helper'
describe "Process.warmup" do
- ruby_version_is "3.3" do
- # The behavior is entirely implementation specific.
- # Other implementations are free to just make it a noop
- it "is implemented" do
- Process.warmup.should == true
- end
+ # The behavior is entirely implementation specific.
+ # Other implementations are free to just make it a noop
+ it "is implemented" do
+ Process.warmup.should == true
end
end
diff --git a/spec/ruby/core/queue/deq_spec.rb b/spec/ruby/core/queue/deq_spec.rb
index f84d4220ea..a2784e6a63 100644
--- a/spec/ruby/core/queue/deq_spec.rb
+++ b/spec/ruby/core/queue/deq_spec.rb
@@ -7,7 +7,5 @@ describe "Queue#deq" do
end
describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index 592fbe2487..080e4d0abd 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -35,26 +35,26 @@ describe "Queue#initialize" do
end
it "raises a TypeError if the given argument can't be converted to an Array" do
- -> { Queue.new(42) }.should raise_error(TypeError)
- -> { Queue.new(:abc) }.should raise_error(TypeError)
+ -> { Queue.new(42) }.should.raise(TypeError)
+ -> { Queue.new(:abc) }.should.raise(TypeError)
end
it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
enumerable = MockObject.new('mock-enumerable')
enumerable.should_receive(:to_a).and_raise(NoMethodError)
- -> { Queue.new(enumerable) }.should raise_error(NoMethodError)
+ -> { Queue.new(enumerable) }.should.raise(NoMethodError)
end
end
it "raises TypeError if the provided Enumerable does not respond to #to_a" do
enumerable = MockObject.new('mock-enumerable')
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array")
+ -> { Queue.new(enumerable) }.should.raise(TypeError, "can't convert MockObject into Array")
end
it "raises TypeError if #to_a does not return Array" do
enumerable = MockObject.new('mock-enumerable')
enumerable.should_receive(:to_a).and_return("string")
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)")
+ -> { Queue.new(enumerable) }.should raise_consistent_error(TypeError, "can't convert MockObject into Array (MockObject#to_a gives String)")
end
end
diff --git a/spec/ruby/core/queue/pop_spec.rb b/spec/ruby/core/queue/pop_spec.rb
index d344740834..3dff7db242 100644
--- a/spec/ruby/core/queue/pop_spec.rb
+++ b/spec/ruby/core/queue/pop_spec.rb
@@ -7,7 +7,5 @@ describe "Queue#pop" do
end
describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) }
end
diff --git a/spec/ruby/core/queue/shift_spec.rb b/spec/ruby/core/queue/shift_spec.rb
index 64165e0b61..c105da74b2 100644
--- a/spec/ruby/core/queue/shift_spec.rb
+++ b/spec/ruby/core/queue/shift_spec.rb
@@ -7,7 +7,5 @@ describe "Queue#shift" do
end
describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
end
diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb
index b42dc61234..c9be07cd3f 100644
--- a/spec/ruby/core/random/bytes_spec.rb
+++ b/spec/ruby/core/random/bytes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/bytes'
diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb
index 01d7430df8..9e4845986d 100644
--- a/spec/ruby/core/random/default_spec.rb
+++ b/spec/ruby/core/random/default_spec.rb
@@ -1,35 +1,7 @@
require_relative '../../spec_helper'
describe "Random::DEFAULT" do
- ruby_version_is ''...'3.2' do
- it "returns a random number generator" do
- suppress_warning do
- Random::DEFAULT.should respond_to(:rand)
- end
- end
-
- it "changes seed on reboot" do
- seed1 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems')
- seed2 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems')
- seed1.should != seed2
- end
-
- it "refers to the Random class" do
- suppress_warning do
- Random::DEFAULT.should.equal?(Random)
- end
- end
-
- it "is deprecated" do
- -> {
- Random::DEFAULT.should.equal?(Random)
- }.should complain(/constant Random::DEFAULT is deprecated/)
- end
- end
-
- ruby_version_is '3.2' do
- it "is no longer defined" do
- Random.should_not.const_defined?(:DEFAULT)
- end
+ it "is no longer defined" do
+ Random.should_not.const_defined?(:DEFAULT)
end
end
diff --git a/spec/ruby/core/random/new_seed_spec.rb b/spec/ruby/core/random/new_seed_spec.rb
index 7a93da99aa..b2741aaa31 100644
--- a/spec/ruby/core/random/new_seed_spec.rb
+++ b/spec/ruby/core/random/new_seed_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Random.new_seed" do
it "returns an Integer" do
- Random.new_seed.should be_an_instance_of(Integer)
+ Random.new_seed.should.instance_of?(Integer)
end
it "returns an arbitrary seed value each time" do
diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb
index 90e2a9d6f2..e20d487137 100644
--- a/spec/ruby/core/random/new_spec.rb
+++ b/spec/ruby/core/random/new_spec.rb
@@ -1,17 +1,17 @@
require_relative "../../spec_helper"
describe "Random.new" do
it "returns a new instance of Random" do
- Random.new.should be_an_instance_of(Random)
+ Random.new.should.instance_of?(Random)
end
it "uses a random seed value if none is supplied" do
- Random.new.seed.should be_an_instance_of(Integer)
+ Random.new.seed.should.instance_of?(Integer)
end
it "returns Random instances initialized with different seeds" do
first = Random.new
second = Random.new
- (0..20).map { first.rand } .should_not == (0..20).map { second.rand }
+ (0..20).map { first.rand }.should_not == (0..20).map { second.rand }
end
it "accepts an Integer seed value as an argument" do
@@ -33,6 +33,6 @@ describe "Random.new" do
it "raises a RangeError if passed a Complex (with imaginary part) seed value as an argument" do
-> do
Random.new(Complex(20,2))
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/random/rand_spec.rb b/spec/ruby/core/random/rand_spec.rb
index 9244177ab5..c882db6381 100644
--- a/spec/ruby/core/random/rand_spec.rb
+++ b/spec/ruby/core/random/rand_spec.rb
@@ -45,13 +45,13 @@ describe "Random.rand" do
it "coerces arguments to Integers with #to_int" do
obj = mock_numeric('int')
obj.should_receive(:to_int).and_return(99)
- Random.rand(obj).should be_kind_of(Integer)
+ Random.rand(obj).should.is_a?(Integer)
end
end
describe "Random#rand with Fixnum" do
it "returns an Integer" do
- Random.new.rand(20).should be_an_instance_of(Integer)
+ Random.new.rand(20).should.instance_of?(Integer)
end
it "returns a Fixnum greater than or equal to 0" do
@@ -82,20 +82,20 @@ describe "Random#rand with Fixnum" do
it "raises an ArgumentError when the argument is 0" do
-> do
Random.new.rand(0)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError when the argument is negative" do
-> do
Random.new.rand(-12)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Random#rand with Bignum" do
it "typically returns a Bignum" do
rnd = Random.new(1)
- 10.times.map{ rnd.rand(bignum_value*2) }.max.should be_an_instance_of(Integer)
+ 10.times.map{ rnd.rand(bignum_value*2) }.max.should.instance_of?(Integer)
end
it "returns a Bignum greater than or equal to 0" do
@@ -121,13 +121,13 @@ describe "Random#rand with Bignum" do
it "raises an ArgumentError when the argument is negative" do
-> do
Random.new.rand(-bignum_value)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Random#rand with Float" do
it "returns a Float" do
- Random.new.rand(20.43).should be_an_instance_of(Float)
+ Random.new.rand(20.43).should.instance_of?(Float)
end
it "returns a Float greater than or equal to 0.0" do
@@ -153,25 +153,25 @@ describe "Random#rand with Float" do
it "raises an ArgumentError when the argument is negative" do
-> do
Random.new.rand(-1.234567)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
describe "Random#rand with Range" do
it "returns an element from the Range" do
- Random.new.rand(20..43).should be_an_instance_of(Integer)
+ Random.new.rand(20..43).should.instance_of?(Integer)
end
it "supports custom object types" do
- rand(RandomSpecs::CustomRangeInteger.new(1)..RandomSpecs::CustomRangeInteger.new(42)).should be_an_instance_of(RandomSpecs::CustomRangeInteger)
- rand(RandomSpecs::CustomRangeFloat.new(1.0)..RandomSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(RandomSpecs::CustomRangeFloat)
- rand(Time.now..Time.now).should be_an_instance_of(Time)
+ rand(RandomSpecs::CustomRangeInteger.new(1)..RandomSpecs::CustomRangeInteger.new(42)).should.instance_of?(RandomSpecs::CustomRangeInteger)
+ rand(RandomSpecs::CustomRangeFloat.new(1.0)..RandomSpecs::CustomRangeFloat.new(42.0)).should.instance_of?(RandomSpecs::CustomRangeFloat)
+ rand(Time.now..Time.now).should.instance_of?(Time)
end
it "returns an object that is a member of the Range" do
prng = Random.new
r = 20..30
- 20.times { r.member?(prng.rand(r)).should be_true }
+ 20.times { r.member?(prng.rand(r)).should == true }
end
it "works with inclusive ranges" do
@@ -201,8 +201,8 @@ describe "Random#rand with Range" do
end
it "considers Integers as Floats if one end point is a float" do
- Random.new(42).rand(0.0..1).should be_kind_of(Float)
- Random.new(42).rand(0..1.0).should be_kind_of(Float)
+ Random.new(42).rand(0.0..1).should.is_a?(Float)
+ Random.new(42).rand(0..1.0).should.is_a?(Float)
end
it "returns a float within a given float range" do
@@ -213,12 +213,12 @@ describe "Random#rand with Range" do
it "raises an ArgumentError when the startpoint lacks #+ and #- methods" do
-> do
Random.new.rand(Object.new..67)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises an ArgumentError when the endpoint lacks #+ and #- methods" do
-> do
Random.new.rand(68..Object.new)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/random/seed_spec.rb b/spec/ruby/core/random/seed_spec.rb
index bf4524fdd9..6529b2c873 100644
--- a/spec/ruby/core/random/seed_spec.rb
+++ b/spec/ruby/core/random/seed_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Random#seed" do
it "returns an Integer" do
- Random.new.seed.should be_kind_of(Integer)
+ Random.new.seed.should.is_a?(Integer)
end
it "returns an arbitrary seed if the constructor was called without arguments" do
diff --git a/spec/ruby/core/random/shared/bytes.rb b/spec/ruby/core/random/shared/bytes.rb
index 9afad3b7f8..86c64d5696 100644
--- a/spec/ruby/core/random/shared/bytes.rb
+++ b/spec/ruby/core/random/shared/bytes.rb
@@ -1,6 +1,6 @@
describe :random_bytes, shared: true do
it "returns a String" do
- @object.send(@method, 1).should be_an_instance_of(String)
+ @object.send(@method, 1).should.instance_of?(String)
end
it "returns a String of the length given as argument" do
diff --git a/spec/ruby/core/random/shared/rand.rb b/spec/ruby/core/random/shared/rand.rb
index d3b24b8851..655c75c9f1 100644
--- a/spec/ruby/core/random/shared/rand.rb
+++ b/spec/ruby/core/random/shared/rand.rb
@@ -1,9 +1,9 @@
describe :random_number, shared: true do
it "returns a Float if no max argument is passed" do
- @object.send(@method).should be_kind_of(Float)
+ @object.send(@method).should.is_a?(Float)
end
it "returns an Integer if an Integer argument is passed" do
- @object.send(@method, 20).should be_kind_of(Integer)
+ @object.send(@method, 20).should.is_a?(Integer)
end
end
diff --git a/spec/ruby/core/random/urandom_spec.rb b/spec/ruby/core/random/urandom_spec.rb
index 6f180e54ac..94e9423a06 100644
--- a/spec/ruby/core/random/urandom_spec.rb
+++ b/spec/ruby/core/random/urandom_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Random.urandom" do
it "returns a String" do
- Random.urandom(1).should be_an_instance_of(String)
+ Random.urandom(1).should.instance_of?(String)
end
it "returns a String of the length given as argument" do
@@ -12,7 +12,7 @@ describe "Random.urandom" do
it "raises an ArgumentError on a negative size" do
-> {
Random.urandom(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns a binary String" do
diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb
index 5254ab756c..151a1798cf 100644
--- a/spec/ruby/core/range/bsearch_spec.rb
+++ b/spec/ruby/core/range/bsearch_spec.rb
@@ -3,46 +3,46 @@ require_relative '../enumerable/shared/enumeratorized'
describe "Range#bsearch" do
it "returns an Enumerator when not passed a block" do
- (0..1).bsearch.should be_an_instance_of(Enumerator)
+ (0..1).bsearch.should.instance_of?(Enumerator)
end
it_behaves_like :enumeratorized_with_unknown_size, :bsearch, (1..3)
it "raises a TypeError if the block returns an Object" do
- -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError, "wrong argument type Object (must be numeric, true, false or nil)")
+ -> { (0..1).bsearch { Object.new } }.should.raise(TypeError, "wrong argument type Object (must be numeric, true, false or nil)")
end
it "raises a TypeError if the block returns a String and boundaries are Integer values" do
- -> { (0..1).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
+ -> { (0..1).bsearch { "1" } }.should.raise(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
end
it "raises a TypeError if the block returns a String and boundaries are Float values" do
- -> { (0.0..1.0).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
+ -> { (0.0..1.0).bsearch { "1" } }.should.raise(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
end
it "raises a TypeError if the Range has Object values" do
value = mock("range bsearch")
r = Range.new value, value
- -> { r.bsearch { true } }.should raise_error(TypeError, "can't do binary search for MockObject")
+ -> { r.bsearch { true } }.should.raise(TypeError, "can't do binary search for MockObject")
end
it "raises a TypeError if the Range has String values" do
- -> { ("a".."e").bsearch { true } }.should raise_error(TypeError, "can't do binary search for String")
+ -> { ("a".."e").bsearch { true } }.should.raise(TypeError, "can't do binary search for String")
end
it "raises TypeError when non-Numeric begin/end and block not passed" do
- -> { ("a".."e").bsearch }.should raise_error(TypeError, "can't do binary search for String")
+ -> { ("a".."e").bsearch }.should.raise(TypeError, "can't do binary search for String")
end
context "with Integer values" do
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- (0...3).bsearch { |x| x > 3 }.should be_nil
+ (0...3).bsearch { |x| x > 3 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- (0..3).bsearch { |x| nil }.should be_nil
+ (0..3).bsearch { |x| nil }.should == nil
end
it "returns minimum element if the block returns true for every element" do
@@ -62,21 +62,21 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- (0..3).bsearch { |x| x <=> 5 }.should be_nil
+ (0..3).bsearch { |x| x <=> 5 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- (0..3).bsearch { |x| x <=> -1 }.should be_nil
+ (0..3).bsearch { |x| x <=> -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (0..3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ (0..3).bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- (0..4).bsearch { |x| Float::INFINITY }.should be_nil
- (0..4).bsearch { |x| -Float::INFINITY }.should be_nil
+ (0..4).bsearch { |x| Float::INFINITY }.should == nil
+ (0..4).bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -86,7 +86,7 @@ describe "Range#bsearch" do
it "returns an element at an index for which block returns 0" do
result = (0..4).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2].should include(result)
+ [1, 2].should.include?(result)
end
end
@@ -111,11 +111,11 @@ describe "Range#bsearch" do
context "with Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- (0.1...2.3).bsearch { |x| x > 3 }.should be_nil
+ (0.1...2.3).bsearch { |x| x > 3 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- (-0.0..2.3).bsearch { |x| nil }.should be_nil
+ (-0.0..2.3).bsearch { |x| nil }.should == nil
end
it "returns minimum element if the block returns true for every element" do
@@ -163,20 +163,20 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- (-2.0..3.2).bsearch { |x| x <=> 5 }.should be_nil
+ (-2.0..3.2).bsearch { |x| x <=> 5 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- (0.3..3.0).bsearch { |x| x <=> -1 }.should be_nil
+ (0.3..3.0).bsearch { |x| x <=> -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (0.2..2.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ (0.2..2.3).bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- (0.1..4.5).bsearch { |x| Float::INFINITY }.should be_nil
- (-5.0..4.0).bsearch { |x| -Float::INFINITY }.should be_nil
+ (0.1..4.5).bsearch { |x| Float::INFINITY }.should == nil
+ (-5.0..4.0).bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -244,15 +244,15 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- eval("(0..)").bsearch { |x| -1 }.should be_nil
+ eval("(0..)").bsearch { |x| -1 }.should == nil
end
it "returns nil if the block never returns zero" do
- eval("(0..)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
+ eval("(0..)").bsearch { |x| x > 5 ? -1 : 1 }.should == nil
end
it "accepts -Float::INFINITY from the block" do
- eval("(0..)").bsearch { |x| -Float::INFINITY }.should be_nil
+ eval("(0..)").bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -262,7 +262,7 @@ describe "Range#bsearch" do
it "returns an element at an index for which block returns 0" do
result = eval("(0..)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2, 3].should include(result)
+ [1, 2, 3].should.include?(result)
end
end
@@ -274,13 +274,13 @@ describe "Range#bsearch" do
context "with endless ranges and Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns false for every element" do
- eval("(0.1..)").bsearch { |x| x < 0.0 }.should be_nil
- eval("(0.1...)").bsearch { |x| x < 0.0 }.should be_nil
+ eval("(0.1..)").bsearch { |x| x < 0.0 }.should == nil
+ eval("(0.1...)").bsearch { |x| x < 0.0 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- eval("(-0.0..)").bsearch { |x| nil }.should be_nil
- eval("(-0.0...)").bsearch { |x| nil }.should be_nil
+ eval("(-0.0..)").bsearch { |x| nil }.should == nil
+ eval("(-0.0...)").bsearch { |x| nil }.should == nil
end
it "returns minimum element if the block returns true for every element" do
@@ -304,22 +304,22 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- eval("(-2.0..)").bsearch { |x| -1 }.should be_nil
- eval("(-2.0...)").bsearch { |x| -1 }.should be_nil
+ eval("(-2.0..)").bsearch { |x| -1 }.should == nil
+ eval("(-2.0...)").bsearch { |x| -1 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- eval("(0.3..)").bsearch { |x| 1 }.should be_nil
- eval("(0.3...)").bsearch { |x| 1 }.should be_nil
+ eval("(0.3..)").bsearch { |x| 1 }.should == nil
+ eval("(0.3...)").bsearch { |x| 1 }.should == nil
end
it "returns nil if the block never returns zero" do
- eval("(0.2..)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ eval("(0.2..)").bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- eval("(0.1..)").bsearch { |x| Float::INFINITY }.should be_nil
- eval("(-5.0..)").bsearch { |x| -Float::INFINITY }.should be_nil
+ eval("(0.1..)").bsearch { |x| Float::INFINITY }.should == nil
+ eval("(-5.0..)").bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -362,15 +362,15 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns greater than zero for every element" do
- (..0).bsearch { |x| 1 }.should be_nil
+ (..0).bsearch { |x| 1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (..0).bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
+ (..0).bsearch { |x| x > 5 ? -1 : 1 }.should == nil
end
it "accepts Float::INFINITY from the block" do
- (..0).bsearch { |x| Float::INFINITY }.should be_nil
+ (..0).bsearch { |x| Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
@@ -380,7 +380,7 @@ describe "Range#bsearch" do
it "returns an element at an index for which block returns 0" do
result = (...10).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2, 3].should include(result)
+ [1, 2, 3].should.include?(result)
end
end
@@ -392,13 +392,13 @@ describe "Range#bsearch" do
context "with beginless ranges and Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns true for every element" do
- (..-0.1).bsearch { |x| x > 0.0 }.should be_nil
- (...-0.1).bsearch { |x| x > 0.0 }.should be_nil
+ (..-0.1).bsearch { |x| x > 0.0 }.should == nil
+ (...-0.1).bsearch { |x| x > 0.0 }.should == nil
end
it "returns nil if the block returns nil for every element" do
- (..-0.1).bsearch { |x| nil }.should be_nil
- (...-0.1).bsearch { |x| nil }.should be_nil
+ (..-0.1).bsearch { |x| nil }.should == nil
+ (...-0.1).bsearch { |x| nil }.should == nil
end
it "returns the smallest element for which block returns true" do
@@ -417,22 +417,22 @@ describe "Range#bsearch" do
context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
- (..5.0).bsearch { |x| -1 }.should be_nil
- (...5.0).bsearch { |x| -1 }.should be_nil
+ (..5.0).bsearch { |x| -1 }.should == nil
+ (...5.0).bsearch { |x| -1 }.should == nil
end
it "returns nil if the block returns greater than zero for every element" do
- (..1.1).bsearch { |x| 1 }.should be_nil
- (...1.1).bsearch { |x| 1 }.should be_nil
+ (..1.1).bsearch { |x| 1 }.should == nil
+ (...1.1).bsearch { |x| 1 }.should == nil
end
it "returns nil if the block never returns zero" do
- (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should == nil
end
it "accepts (+/-)Float::INFINITY from the block" do
- (..5.0).bsearch { |x| Float::INFINITY }.should be_nil
- (..7.0).bsearch { |x| -Float::INFINITY }.should be_nil
+ (..5.0).bsearch { |x| Float::INFINITY }.should == nil
+ (..7.0).bsearch { |x| -Float::INFINITY }.should == nil
end
it "returns an element at an index for which block returns 0.0" do
diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb
index 65878aaabe..7a76487d68 100644
--- a/spec/ruby/core/range/case_compare_spec.rb
+++ b/spec/ruby/core/range/case_compare_spec.rb
@@ -11,9 +11,7 @@ describe "Range#===" do
it_behaves_like :range_cover_and_include, :===
it_behaves_like :range_cover, :===
- ruby_bug "#19533", "3.2"..."3.3" do
- it "returns true on any value if begin and end are both nil" do
- (nil..nil).should === 1
- end
+ it "returns true on any value if begin and end are both nil" do
+ (nil..nil).should === 1
end
end
diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb
index eb7cddc967..eb8d5453bf 100644
--- a/spec/ruby/core/range/cover_spec.rb
+++ b/spec/ruby/core/range/cover_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/cover_and_include'
require_relative 'shared/cover'
@@ -9,6 +9,6 @@ describe "Range#cover?" do
it_behaves_like :range_cover_subrange, :cover?
it "covers U+9995 in the range U+0999..U+9999" do
- ("\u{999}".."\u{9999}").cover?("\u{9995}").should be_true
+ ("\u{999}".."\u{9999}").cover?("\u{9995}").should == true
end
end
diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb
index f10330d61d..b4389f864d 100644
--- a/spec/ruby/core/range/each_spec.rb
+++ b/spec/ruby/core/range/each_spec.rb
@@ -59,26 +59,26 @@ describe "Range#each" do
end
it "raises a TypeError beginless ranges" do
- -> { (..2).each { |x| x } }.should raise_error(TypeError)
+ -> { (..2).each { |x| x } }.should.raise(TypeError)
end
it "raises a TypeError if the first element does not respond to #succ" do
- -> { (0.5..2.4).each { |i| i } }.should raise_error(TypeError)
+ -> { (0.5..2.4).each { |i| i } }.should.raise(TypeError)
b = mock('x')
(a = mock('1')).should_receive(:<=>).with(b).and_return(1)
- -> { (a..b).each { |i| i } }.should raise_error(TypeError)
+ -> { (a..b).each { |i| i } }.should.raise(TypeError)
end
it "returns self" do
range = 1..10
- range.each{}.should equal(range)
+ range.each{}.should.equal?(range)
end
it "returns an enumerator when no block given" do
enum = (1..3).each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [1, 2, 3]
end
diff --git a/spec/ruby/core/range/eql_spec.rb b/spec/ruby/core/range/eql_spec.rb
index fa6c71840e..cdc19c9331 100644
--- a/spec/ruby/core/range/eql_spec.rb
+++ b/spec/ruby/core/range/eql_spec.rb
@@ -5,6 +5,6 @@ describe "Range#eql?" do
it_behaves_like :range_eql, :eql?
it "returns false if the endpoints are not eql?" do
- (0..1).should_not eql(0..1.0)
+ (0..1).should_not.eql?(0..1.0)
end
end
diff --git a/spec/ruby/core/range/first_spec.rb b/spec/ruby/core/range/first_spec.rb
index 2af935f439..54bd73a4e8 100644
--- a/spec/ruby/core/range/first_spec.rb
+++ b/spec/ruby/core/range/first_spec.rb
@@ -21,7 +21,7 @@ describe "Range#first" do
end
it "raises an ArgumentError when count is negative" do
- -> { (0..2).first(-1) }.should raise_error(ArgumentError)
+ -> { (0..2).first(-1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the argument" do
@@ -32,7 +32,7 @@ describe "Range#first" do
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("1")
- -> { (2..3).first(obj) }.should raise_error(TypeError)
+ -> { (2..3).first(obj) }.should.raise(TypeError)
end
it "truncates the value when passed a Float" do
@@ -40,14 +40,14 @@ describe "Range#first" do
end
it "raises a TypeError when passed nil" do
- -> { (2..3).first(nil) }.should raise_error(TypeError)
+ -> { (2..3).first(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { (2..3).first("1") }.should raise_error(TypeError)
+ -> { (2..3).first("1") }.should.raise(TypeError)
end
it "raises a RangeError when called on an beginless range" do
- -> { (..1).first }.should raise_error(RangeError)
+ -> { (..1).first }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/hash_spec.rb b/spec/ruby/core/range/hash_spec.rb
index 4f2681e86e..087f5d6de8 100644
--- a/spec/ruby/core/range/hash_spec.rb
+++ b/spec/ruby/core/range/hash_spec.rb
@@ -15,10 +15,10 @@ describe "Range#hash" do
end
it "generates an Integer for the hash value" do
- (0..0).hash.should be_an_instance_of(Integer)
- (0..1).hash.should be_an_instance_of(Integer)
- (0...10).hash.should be_an_instance_of(Integer)
- (0..10).hash.should be_an_instance_of(Integer)
+ (0..0).hash.should.instance_of?(Integer)
+ (0..1).hash.should.instance_of?(Integer)
+ (0...10).hash.should.instance_of?(Integer)
+ (0..10).hash.should.instance_of?(Integer)
end
end
diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb
index 277de205d1..66a049a90d 100644
--- a/spec/ruby/core/range/include_spec.rb
+++ b/spec/ruby/core/range/include_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/cover_and_include'
require_relative 'shared/include'
@@ -9,6 +9,6 @@ describe "Range#include?" do
it_behaves_like :range_include, :include?
it "does not include U+9995 in the range U+0999..U+9999" do
- ("\u{999}".."\u{9999}").include?("\u{9995}").should be_false
+ ("\u{999}".."\u{9999}").include?("\u{9995}").should == false
end
end
diff --git a/spec/ruby/core/range/initialize_spec.rb b/spec/ruby/core/range/initialize_spec.rb
index c653caf0c6..b1a0565ab2 100644
--- a/spec/ruby/core/range/initialize_spec.rb
+++ b/spec/ruby/core/range/initialize_spec.rb
@@ -6,36 +6,36 @@ describe "Range#initialize" do
end
it "is private" do
- Range.should have_private_instance_method("initialize")
+ Range.private_instance_methods(false).should.include?(:initialize)
end
it "initializes correctly the Range object when given 2 arguments" do
- -> { @range.send(:initialize, 0, 1) }.should_not raise_error
+ -> { @range.send(:initialize, 0, 1) }.should_not.raise
end
it "initializes correctly the Range object when given 3 arguments" do
- -> { @range.send(:initialize, 0, 1, true) }.should_not raise_error
+ -> { @range.send(:initialize, 0, 1, true) }.should_not.raise
end
it "raises an ArgumentError if passed without or with only one argument" do
- -> { @range.send(:initialize) }.should raise_error(ArgumentError)
- -> { @range.send(:initialize, 1) }.should raise_error(ArgumentError)
+ -> { @range.send(:initialize) }.should.raise(ArgumentError)
+ -> { @range.send(:initialize, 1) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed with four or more arguments" do
- -> { @range.send(:initialize, 1, 3, 5, 7) }.should raise_error(ArgumentError)
- -> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should raise_error(ArgumentError)
+ -> { @range.send(:initialize, 1, 3, 5, 7) }.should.raise(ArgumentError)
+ -> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should.raise(ArgumentError)
end
it "raises a FrozenError if called on an already initialized Range" do
- -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError)
- -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError)
+ -> { (0..1).send(:initialize, 1, 3) }.should.raise(FrozenError)
+ -> { (0..1).send(:initialize, 1, 3, true) }.should.raise(FrozenError)
end
it "raises an ArgumentError if arguments don't respond to <=>" do
o1 = Object.new
o2 = Object.new
- -> { @range.send(:initialize, o1, o2) }.should raise_error(ArgumentError)
+ -> { @range.send(:initialize, o1, o2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/range/last_spec.rb b/spec/ruby/core/range/last_spec.rb
index 6698686dd5..a7db7f85a7 100644
--- a/spec/ruby/core/range/last_spec.rb
+++ b/spec/ruby/core/range/last_spec.rb
@@ -8,10 +8,8 @@ describe "Range#last" do
(1..5).last(3).should == [3, 4, 5]
end
- ruby_bug '#18994', '2.7'...'3.2' do
- it "returns the specified number if elements for single element inclusive range" do
- (1..1).last(1).should == [1]
- end
+ it "returns the specified number if elements for single element inclusive range" do
+ (1..1).last(1).should == [1]
end
it "returns an empty array for an empty Range" do
@@ -27,7 +25,7 @@ describe "Range#last" do
end
it "raises an ArgumentError when count is negative" do
- -> { (0..2).last(-1) }.should raise_error(ArgumentError)
+ -> { (0..2).last(-1) }.should.raise(ArgumentError)
end
it "calls #to_int to convert the argument" do
@@ -38,7 +36,7 @@ describe "Range#last" do
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return("1")
- -> { (2..3).last(obj) }.should raise_error(TypeError)
+ -> { (2..3).last(obj) }.should.raise(TypeError)
end
it "truncates the value when passed a Float" do
@@ -46,14 +44,14 @@ describe "Range#last" do
end
it "raises a TypeError when passed nil" do
- -> { (2..3).last(nil) }.should raise_error(TypeError)
+ -> { (2..3).last(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { (2..3).last("1") }.should raise_error(TypeError)
+ -> { (2..3).last("1") }.should.raise(TypeError)
end
it "raises a RangeError when called on an endless range" do
- -> { eval("(1..)").last }.should raise_error(RangeError)
+ -> { eval("(1..)").last }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb
index 8b83f69a5a..57714967ce 100644
--- a/spec/ruby/core/range/max_spec.rb
+++ b/spec/ruby/core/range/max_spec.rb
@@ -14,40 +14,40 @@ describe "Range#max" do
end
it "raises TypeError when called on an exclusive range and a non Integer value" do
- -> { (303.20...908.1111).max }.should raise_error(TypeError)
+ -> { (303.20...908.1111).max }.should.raise(TypeError)
end
it "returns nil when the endpoint is less than the start point" do
- (100..10).max.should be_nil
- ('z'..'l').max.should be_nil
+ (100..10).max.should == nil
+ ('z'..'l').max.should == nil
end
it "returns nil when the endpoint equals the start point and the range is exclusive" do
- (5...5).max.should be_nil
+ (5...5).max.should == nil
end
it "returns the endpoint when the endpoint equals the start point and the range is inclusive" do
- (5..5).max.should equal(5)
+ (5..5).max.should.equal?(5)
end
it "returns nil when the endpoint is less than the start point in a Float range" do
- (3003.20..908.1111).max.should be_nil
+ (3003.20..908.1111).max.should == nil
end
it "returns end point when the range is Time..Time(included end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- (time_start..time_end).max.should equal(time_end)
+ (time_start..time_end).max.should.equal?(time_end)
end
it "raises TypeError when called on a Time...Time(excluded end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- -> { (time_start...time_end).max }.should raise_error(TypeError)
+ -> { (time_start...time_end).max }.should.raise(TypeError)
end
it "raises RangeError when called on an endless range" do
- -> { eval("(1..)").max }.should raise_error(RangeError)
+ -> { eval("(1..)").max }.should.raise(RangeError)
end
it "returns the end point for beginless ranges" do
@@ -55,15 +55,15 @@ describe "Range#max" do
(..1.0).max.should == 1.0
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "raises for an exclusive beginless Integer range" do
-> {
(...1).max
- }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
+ }.should.raise(TypeError, 'cannot exclude end value with non Integer begin value')
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "returns the end point for exclusive beginless Integer ranges" do
(...1).max.should == 0
end
@@ -72,7 +72,7 @@ describe "Range#max" do
it "raises for an exclusive beginless non Integer range" do
-> {
(...1.0).max
- }.should raise_error(TypeError, 'cannot exclude non Integer end value')
+ }.should.raise(TypeError, 'cannot exclude non Integer end value')
end
end
@@ -82,7 +82,7 @@ describe "Range#max given a block" do
(1..10).max {|a,b| acc << [a,b]; a }
acc.flatten!
(1..10).each do |value|
- acc.include?(value).should be_true
+ acc.include?(value).should == true
end
end
@@ -104,12 +104,12 @@ describe "Range#max given a block" do
end
it "returns nil when the endpoint is less than the start point" do
- (100..10).max {|x,y| x <=> y}.should be_nil
- ('z'..'l').max {|x,y| x <=> y}.should be_nil
- (5...5).max {|x,y| x <=> y}.should be_nil
+ (100..10).max {|x,y| x <=> y}.should == nil
+ ('z'..'l').max {|x,y| x <=> y}.should == nil
+ (5...5).max {|x,y| x <=> y}.should == nil
end
it "raises RangeError when called with custom comparison method on an beginless range" do
- -> { (..1).max {|a, b| a} }.should raise_error(RangeError)
+ -> { (..1).max {|a, b| a} }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/member_spec.rb b/spec/ruby/core/range/member_spec.rb
index ab61f92951..78299ae9e5 100644
--- a/spec/ruby/core/range/member_spec.rb
+++ b/spec/ruby/core/range/member_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/cover_and_include'
require_relative 'shared/include'
diff --git a/spec/ruby/core/range/min_spec.rb b/spec/ruby/core/range/min_spec.rb
index 89310ee589..9c83d3deca 100644
--- a/spec/ruby/core/range/min_spec.rb
+++ b/spec/ruby/core/range/min_spec.rb
@@ -11,32 +11,32 @@ describe "Range#min" do
end
it "returns nil when the start point is greater than the endpoint" do
- (100..10).min.should be_nil
- ('z'..'l').min.should be_nil
+ (100..10).min.should == nil
+ ('z'..'l').min.should == nil
end
it "returns nil when the endpoint equals the start point and the range is exclusive" do
- (7...7).min.should be_nil
+ (7...7).min.should == nil
end
it "returns the start point when the endpoint equals the start point and the range is inclusive" do
- (7..7).min.should equal(7)
+ (7..7).min.should.equal?(7)
end
it "returns nil when the start point is greater than the endpoint in a Float range" do
- (3003.20..908.1111).min.should be_nil
+ (3003.20..908.1111).min.should == nil
end
it "returns start point when the range is Time..Time(included end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- (time_start..time_end).min.should equal(time_start)
+ (time_start..time_end).min.should.equal?(time_start)
end
it "returns start point when the range is Time...Time(excluded end point)" do
time_start = Time.now
time_end = Time.now + 1.0
- (time_start...time_end).min.should equal(time_start)
+ (time_start...time_end).min.should.equal?(time_start)
end
it "returns the start point for endless ranges" do
@@ -45,7 +45,7 @@ describe "Range#min" do
end
it "raises RangeError when called on an beginless range" do
- -> { (..1).min }.should raise_error(RangeError)
+ -> { (..1).min }.should.raise(RangeError)
end
end
@@ -55,7 +55,7 @@ describe "Range#min given a block" do
(1..10).min {|a,b| acc << [a,b]; a }
acc.flatten!
(1..10).each do |value|
- acc.include?(value).should be_true
+ acc.include?(value).should == true
end
end
@@ -77,12 +77,12 @@ describe "Range#min given a block" do
end
it "returns nil when the start point is greater than the endpoint" do
- (100..10).min {|x,y| x <=> y}.should be_nil
- ('z'..'l').min {|x,y| x <=> y}.should be_nil
- (7...7).min {|x,y| x <=> y}.should be_nil
+ (100..10).min {|x,y| x <=> y}.should == nil
+ ('z'..'l').min {|x,y| x <=> y}.should == nil
+ (7...7).min {|x,y| x <=> y}.should == nil
end
it "raises RangeError when called with custom comparison method on an endless range" do
- -> { eval("(1..)").min {|a, b| a} }.should raise_error(RangeError)
+ -> { eval("(1..)").min {|a, b| a} }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb
index 6651ae3726..16c7626ea3 100644
--- a/spec/ruby/core/range/minmax_spec.rb
+++ b/spec/ruby/core/range/minmax_spec.rb
@@ -17,19 +17,19 @@ describe 'Range#minmax' do
range = (@x..)
- -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
+ -> { range.minmax }.should.raise(RangeError, 'cannot get the maximum of endless range')
end
it 'raises RangeError or ArgumentError on a beginless range' do
range = (..@x)
- -> { range.minmax }.should raise_error(StandardError) { |e|
+ -> { range.minmax }.should.raise(StandardError) { |e|
if RangeError === e
# error from #min
- -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range')
+ -> { raise e }.should.raise(RangeError, 'cannot get the minimum of beginless range')
else
# error from #max
- -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed')
+ -> { raise e }.should.raise(ArgumentError, 'comparison of NilClass with MockObject failed')
end
}
end
@@ -76,13 +76,13 @@ describe 'Range#minmax' do
@x.should_not_receive(:succ)
range = (@x...)
- -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
+ -> { range.minmax }.should.raise(RangeError, 'cannot get the maximum of endless range')
end
it 'should raise RangeError on a beginless range' do
range = (...@x)
- -> { range.minmax }.should raise_error(RangeError,
+ -> { range.minmax }.should.raise(RangeError,
/cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/)
end
@@ -118,7 +118,7 @@ describe 'Range#minmax' do
it 'raises TypeError if the end value is not an integer' do
range = (0...Float::INFINITY)
- -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value')
+ -> { range.minmax }.should.raise(TypeError, 'cannot exclude non Integer end value')
end
it 'should return the minimum and maximum values according to the provided block by iterating the range' do
diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb
index 3cab887799..9a35f28c7e 100644
--- a/spec/ruby/core/range/new_spec.rb
+++ b/spec/ruby/core/range/new_spec.rb
@@ -25,12 +25,12 @@ describe "Range.new" do
end
it "raises an ArgumentError when the given start and end can't be compared by using #<=>" do
- -> { Range.new(1, mock('x')) }.should raise_error(ArgumentError)
- -> { Range.new(mock('x'), mock('y')) }.should raise_error(ArgumentError)
+ -> { Range.new(1, mock('x')) }.should.raise(ArgumentError)
+ -> { Range.new(mock('x'), mock('y')) }.should.raise(ArgumentError)
b = mock('x')
(a = mock('nil')).should_receive(:<=>).with(b).and_return(nil)
- -> { Range.new(a, b) }.should raise_error(ArgumentError)
+ -> { Range.new(a, b) }.should.raise(ArgumentError)
end
it "does not rescue exception raised in #<=> when compares the given start and end" do
@@ -38,7 +38,7 @@ describe "Range.new" do
a = mock('b')
a.should_receive(:<=>).with(b).and_raise(RangeSpecs::ComparisonError)
- -> { Range.new(a, b) }.should raise_error(RangeSpecs::ComparisonError)
+ -> { Range.new(a, b) }.should.raise(RangeSpecs::ComparisonError)
end
describe "beginless/endless range" do
diff --git a/spec/ruby/core/range/overlap_spec.rb b/spec/ruby/core/range/overlap_spec.rb
index 9b6fc13493..201cd2b1ff 100644
--- a/spec/ruby/core/range/overlap_spec.rb
+++ b/spec/ruby/core/range/overlap_spec.rb
@@ -1,89 +1,87 @@
require_relative '../../spec_helper'
-ruby_version_is '3.3' do
- describe "Range#overlap?" do
- it "returns true if other Range overlaps self" do
- (0..2).overlap?(1..3).should == true
- (1..3).overlap?(0..2).should == true
- (0..2).overlap?(0..2).should == true
- (0..3).overlap?(1..2).should == true
- (1..2).overlap?(0..3).should == true
-
- ('a'..'c').overlap?('b'..'d').should == true
- end
-
- it "returns false if other Range does not overlap self" do
- (0..2).overlap?(3..4).should == false
- (0..2).overlap?(-4..-1).should == false
-
- ('a'..'c').overlap?('d'..'f').should == false
- end
-
- it "raises TypeError when called with non-Range argument" do
- -> {
- (0..2).overlap?(1)
- }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
- end
-
- it "returns true when beginningless and endless Ranges overlap" do
- (0..2).overlap?(..3).should == true
- (0..2).overlap?(..1).should == true
- (0..2).overlap?(..0).should == true
-
- (..3).overlap?(0..2).should == true
- (..1).overlap?(0..2).should == true
- (..0).overlap?(0..2).should == true
-
- (0..2).overlap?(-1..).should == true
- (0..2).overlap?(1..).should == true
- (0..2).overlap?(2..).should == true
-
- (-1..).overlap?(0..2).should == true
- (1..).overlap?(0..2).should == true
- (2..).overlap?(0..2).should == true
-
- (0..).overlap?(2..).should == true
- (..0).overlap?(..2).should == true
- end
-
- it "returns false when beginningless and endless Ranges do not overlap" do
- (0..2).overlap?(..-1).should == false
- (0..2).overlap?(3..).should == false
-
- (..-1).overlap?(0..2).should == false
- (3..).overlap?(0..2).should == false
- end
-
- it "returns false when Ranges are not compatible" do
- (0..2).overlap?('a'..'d').should == false
- end
-
- it "return false when self is empty" do
- (2..0).overlap?(1..3).should == false
- (2...2).overlap?(1..3).should == false
- (1...1).overlap?(1...1).should == false
- (2..0).overlap?(2..0).should == false
-
- ('c'..'a').overlap?('b'..'d').should == false
- ('a'...'a').overlap?('b'..'d').should == false
- ('b'...'b').overlap?('b'...'b').should == false
- ('c'...'a').overlap?('c'...'a').should == false
- end
-
- it "return false when other Range is empty" do
- (1..3).overlap?(2..0).should == false
- (1..3).overlap?(2...2).should == false
-
- ('b'..'d').overlap?('c'..'a').should == false
- ('b'..'d').overlap?('c'...'c').should == false
- end
-
- it "takes into account exclusive end" do
- (0...2).overlap?(2..4).should == false
- (2..4).overlap?(0...2).should == false
-
- ('a'...'c').overlap?('c'..'e').should == false
- ('c'..'e').overlap?('a'...'c').should == false
- end
+describe "Range#overlap?" do
+ it "returns true if other Range overlaps self" do
+ (0..2).overlap?(1..3).should == true
+ (1..3).overlap?(0..2).should == true
+ (0..2).overlap?(0..2).should == true
+ (0..3).overlap?(1..2).should == true
+ (1..2).overlap?(0..3).should == true
+
+ ('a'..'c').overlap?('b'..'d').should == true
+ end
+
+ it "returns false if other Range does not overlap self" do
+ (0..2).overlap?(3..4).should == false
+ (0..2).overlap?(-4..-1).should == false
+
+ ('a'..'c').overlap?('d'..'f').should == false
+ end
+
+ it "raises TypeError when called with non-Range argument" do
+ -> {
+ (0..2).overlap?(1)
+ }.should.raise(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "returns true when beginningless and endless Ranges overlap" do
+ (0..2).overlap?(..3).should == true
+ (0..2).overlap?(..1).should == true
+ (0..2).overlap?(..0).should == true
+
+ (..3).overlap?(0..2).should == true
+ (..1).overlap?(0..2).should == true
+ (..0).overlap?(0..2).should == true
+
+ (0..2).overlap?(-1..).should == true
+ (0..2).overlap?(1..).should == true
+ (0..2).overlap?(2..).should == true
+
+ (-1..).overlap?(0..2).should == true
+ (1..).overlap?(0..2).should == true
+ (2..).overlap?(0..2).should == true
+
+ (0..).overlap?(2..).should == true
+ (..0).overlap?(..2).should == true
+ end
+
+ it "returns false when beginningless and endless Ranges do not overlap" do
+ (0..2).overlap?(..-1).should == false
+ (0..2).overlap?(3..).should == false
+
+ (..-1).overlap?(0..2).should == false
+ (3..).overlap?(0..2).should == false
+ end
+
+ it "returns false when Ranges are not compatible" do
+ (0..2).overlap?('a'..'d').should == false
+ end
+
+ it "return false when self is empty" do
+ (2..0).overlap?(1..3).should == false
+ (2...2).overlap?(1..3).should == false
+ (1...1).overlap?(1...1).should == false
+ (2..0).overlap?(2..0).should == false
+
+ ('c'..'a').overlap?('b'..'d').should == false
+ ('a'...'a').overlap?('b'..'d').should == false
+ ('b'...'b').overlap?('b'...'b').should == false
+ ('c'...'a').overlap?('c'...'a').should == false
+ end
+
+ it "return false when other Range is empty" do
+ (1..3).overlap?(2..0).should == false
+ (1..3).overlap?(2...2).should == false
+
+ ('b'..'d').overlap?('c'..'a').should == false
+ ('b'..'d').overlap?('c'...'c').should == false
+ end
+
+ it "takes into account exclusive end" do
+ (0...2).overlap?(2..4).should == false
+ (2..4).overlap?(0...2).should == false
+
+ ('a'...'c').overlap?('c'..'e').should == false
+ ('c'..'e').overlap?('a'...'c').should == false
end
end
diff --git a/spec/ruby/core/range/reverse_each_spec.rb b/spec/ruby/core/range/reverse_each_spec.rb
index b51e04c3ff..49790e8b0a 100644
--- a/spec/ruby/core/range/reverse_each_spec.rb
+++ b/spec/ruby/core/range/reverse_each_spec.rb
@@ -1,102 +1,124 @@
require_relative '../../spec_helper'
-ruby_version_is "3.3" do
- describe "Range#reverse_each" do
- it "traverses the Range in reverse order and passes each element to block" do
- a = []
- (1..3).reverse_each { |i| a << i }
- a.should == [3, 2, 1]
+describe "Range#reverse_each" do
+ it "traverses the Range in reverse order and passes each element to block" do
+ a = []
+ (1..3).reverse_each { |i| a << i }
+ a.should == [3, 2, 1]
+
+ a = []
+ (1...3).reverse_each { |i| a << i }
+ a.should == [2, 1]
+ end
- a = []
- (1...3).reverse_each { |i| a << i }
- a.should == [2, 1]
- end
+ it "returns self" do
+ r = (1..3)
+ r.reverse_each { |x| }.should.equal?(r)
+ end
- it "returns self" do
- r = (1..3)
- r.reverse_each { |x| }.should equal(r)
- end
+ it "returns an Enumerator if no block given" do
+ enum = (1..3).reverse_each
+ enum.should.instance_of?(Enumerator)
+ enum.to_a.should == [3, 2, 1]
+ end
- it "returns an Enumerator if no block given" do
- enum = (1..3).reverse_each
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [3, 2, 1]
- end
+ it "raises a TypeError for endless Ranges of Integers" do
+ -> {
+ (1..).reverse_each.take(3)
+ }.should.raise(TypeError, "can't iterate from NilClass")
+ end
- it "raises a TypeError for endless Ranges of Integers" do
- -> {
- (1..).reverse_each.take(3)
- }.should raise_error(TypeError, "can't iterate from NilClass")
- end
+ it "raises a TypeError for endless Ranges of non-Integers" do
+ -> {
+ ("a"..).reverse_each.take(3)
+ }.should.raise(TypeError, "can't iterate from NilClass")
+ end
- it "raises a TypeError for endless Ranges of non-Integers" do
- -> {
- ("a"..).reverse_each.take(3)
- }.should raise_error(TypeError, "can't iterate from NilClass")
+ context "Integer boundaries" do
+ it "supports beginningless Ranges" do
+ (..5).reverse_each.take(3).should == [5, 4, 3]
end
+ end
- context "Integer boundaries" do
- it "supports beginningless Ranges" do
- (..5).reverse_each.take(3).should == [5, 4, 3]
- end
+ context "non-Integer boundaries" do
+ it "uses #succ to iterate a Range of non-Integer elements" do
+ y = mock('y')
+ x = mock('x')
+
+ x.should_receive(:succ).any_number_of_times.and_return(y)
+ x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1)
+ x.should_receive(:<=>).with(x).any_number_of_times.and_return(0)
+ y.should_receive(:<=>).with(x).any_number_of_times.and_return(1)
+ y.should_receive(:<=>).with(y).any_number_of_times.and_return(0)
+
+ a = []
+ (x..y).each { |i| a << i }
+ a.should == [x, y]
end
- context "non-Integer boundaries" do
- it "uses #succ to iterate a Range of non-Integer elements" do
- y = mock('y')
- x = mock('x')
+ it "uses #succ to iterate a Range of Strings" do
+ a = []
+ ('A'..'D').reverse_each { |i| a << i }
+ a.should == ['D','C','B','A']
+ end
- x.should_receive(:succ).any_number_of_times.and_return(y)
- x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1)
- x.should_receive(:<=>).with(x).any_number_of_times.and_return(0)
- y.should_receive(:<=>).with(x).any_number_of_times.and_return(1)
- y.should_receive(:<=>).with(y).any_number_of_times.and_return(0)
+ it "uses #succ to iterate a Range of Symbols" do
+ a = []
+ (:A..:D).reverse_each { |i| a << i }
+ a.should == [:D, :C, :B, :A]
+ end
- a = []
- (x..y).each { |i| a << i }
- a.should == [x, y]
- end
+ it "raises a TypeError when `begin` value does not respond to #succ" do
+ -> { (Time.now..Time.now).reverse_each { |x| x } }.should.raise(TypeError, /can't iterate from Time/)
+ -> { (//..//).reverse_each { |x| x } }.should.raise(TypeError, /can't iterate from Regexp/)
+ -> { ([]..[]).reverse_each { |x| x } }.should.raise(TypeError, /can't iterate from Array/)
+ end
- it "uses #succ to iterate a Range of Strings" do
- a = []
- ('A'..'D').reverse_each { |i| a << i }
- a.should == ['D','C','B','A']
- end
+ it "does not support beginningless Ranges" do
+ -> {
+ (..'a').reverse_each { |x| x }
+ }.should.raise(TypeError, /can't iterate from NilClass/)
+ end
+ end
- it "uses #succ to iterate a Range of Symbols" do
- a = []
- (:A..:D).reverse_each { |i| a << i }
- a.should == [:D, :C, :B, :A]
- end
+ context "when no block is given" do
+ describe "returned Enumerator size" do
+ it "returns the Range size when Range size is finite" do
+ (1..3).reverse_each.size.should == 3
+ (1...3).reverse_each.size.should == 2
- it "raises a TypeError when `begin` value does not respond to #succ" do
- -> { (Time.now..Time.now).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Time/)
- -> { (//..//).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Regexp/)
- -> { ([]..[]).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Array/)
+ (1..3.3).reverse_each.size.should == 3
+ (1...3.3).reverse_each.size.should == 3
end
- it "does not support beginningless Ranges" do
- -> {
- (..'a').reverse_each { |x| x }
- }.should raise_error(TypeError, /can't iterate from NilClass/)
+ ruby_version_is ""..."3.4" do
+ it "returns a size when it is not iterable" do
+ (1.1..3).reverse_each.size.should == 2
+ (1.1..3.3).reverse_each.size.should == 3
+ (1.1..nil).reverse_each.size.should == Float::INFINITY
+ (nil..3.3).reverse_each.size.should == Float::INFINITY
+ (nil..nil).reverse_each.size.should == nil
+ end
end
- end
- context "when no block is given" do
- describe "returned Enumerator size" do
- it "returns the Range size when Range size is finite" do
- (1..3).reverse_each.size.should == 3
+ ruby_version_is "3.4" do
+ it "raises TypeError when the range is not iterable" do
+ -> { (1.1..3).reverse_each.size }.should.raise(TypeError, /can't iterate from Integer/)
+ -> { (1.1..3.3).reverse_each.size }.should.raise(TypeError, /can't iterate from Float/)
+ -> { (1.1..nil).reverse_each.size }.should.raise(TypeError, /can't iterate from NilClass/)
+ -> { (nil..3.3).reverse_each.size }.should.raise(TypeError, /can't iterate from Float/)
+ -> { (nil..nil).reverse_each.size }.should.raise(TypeError, /can't iterate from NilClass/)
end
+ end
- ruby_bug "#20936", "3.4"..."3.5" do
- it "returns Infinity when Range size is infinite" do
- (..3).reverse_each.size.should == Float::INFINITY
- end
+ ruby_bug "#20936", "3.4"..."4.0" do
+ it "returns Infinity when Range size is infinite" do
+ (..3).reverse_each.size.should == Float::INFINITY
end
+ end
- it "returns nil when Range size is unknown" do
- ('a'..'z').reverse_each.size.should == nil
- end
+ it "returns nil when Range size is unknown" do
+ ('a'..'z').reverse_each.size.should == nil
end
end
end
diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb
index 0b41a26455..189f3da4bf 100644
--- a/spec/ruby/core/range/shared/cover.rb
+++ b/spec/ruby/core/range/shared/cover.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
@@ -6,26 +6,26 @@ describe :range_cover, shared: true do
it "uses the range element's <=> to make the comparison" do
a = mock('a')
a.should_receive(:<=>).twice.and_return(-1,-1)
- (a..'z').send(@method, 'b').should be_true
+ (a..'z').send(@method, 'b').should == true
end
it "uses a continuous inclusion test" do
- ('a'..'f').send(@method, 'aa').should be_true
- ('a'..'f').send(@method, 'babe').should be_true
- ('a'..'f').send(@method, 'baby').should be_true
- ('a'..'f').send(@method, 'ga').should be_false
- (-10..-2).send(@method, -2.5).should be_true
+ ('a'..'f').send(@method, 'aa').should == true
+ ('a'..'f').send(@method, 'babe').should == true
+ ('a'..'f').send(@method, 'baby').should == true
+ ('a'..'f').send(@method, 'ga').should == false
+ (-10..-2).send(@method, -2.5).should == true
end
describe "on string elements" do
it "returns true if other is matched by element.succ" do
- ('a'..'c').send(@method, 'b').should be_true
- ('a'...'c').send(@method, 'b').should be_true
+ ('a'..'c').send(@method, 'b').should == true
+ ('a'...'c').send(@method, 'b').should == true
end
it "returns true if other is not matched by element.succ" do
- ('a'..'c').send(@method, 'bc').should be_true
- ('a'...'c').send(@method, 'bc').should be_true
+ ('a'..'c').send(@method, 'bc').should == true
+ ('a'...'c').send(@method, 'bc').should == true
end
end
@@ -36,27 +36,27 @@ describe :range_cover, shared: true do
end
it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should == false
end
it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should == true
end
it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should == true
end
it "returns true if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should == true
end
it "returns true if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should == true
end
it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should == false
end
end
@@ -66,27 +66,27 @@ describe :range_cover, shared: true do
end
it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should == false
end
it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should == true
end
it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should == true
end
it "returns true if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should == true
end
it "returns false if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should == false
end
it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should == false
end
end
end
@@ -95,99 +95,99 @@ end
describe :range_cover_subrange, shared: true do
context "range argument" do
it "accepts range argument" do
- (0..10).send(@method, (3..7)).should be_true
- (0..10).send(@method, (3..15)).should be_false
- (0..10).send(@method, (-2..7)).should be_false
+ (0..10).send(@method, (3..7)).should == true
+ (0..10).send(@method, (3..15)).should == false
+ (0..10).send(@method, (-2..7)).should == false
- (1.1..7.9).send(@method, (2.5..6.5)).should be_true
- (1.1..7.9).send(@method, (2.5..8.5)).should be_false
- (1.1..7.9).send(@method, (0.5..6.5)).should be_false
+ (1.1..7.9).send(@method, (2.5..6.5)).should == true
+ (1.1..7.9).send(@method, (2.5..8.5)).should == false
+ (1.1..7.9).send(@method, (0.5..6.5)).should == false
- ('c'..'i').send(@method, ('d'..'f')).should be_true
- ('c'..'i').send(@method, ('d'..'z')).should be_false
- ('c'..'i').send(@method, ('a'..'f')).should be_false
+ ('c'..'i').send(@method, ('d'..'f')).should == true
+ ('c'..'i').send(@method, ('d'..'z')).should == false
+ ('c'..'i').send(@method, ('a'..'f')).should == false
range_10_100 = RangeSpecs::TenfoldSucc.new(10)..RangeSpecs::TenfoldSucc.new(100)
range_20_90 = RangeSpecs::TenfoldSucc.new(20)..RangeSpecs::TenfoldSucc.new(90)
range_20_110 = RangeSpecs::TenfoldSucc.new(20)..RangeSpecs::TenfoldSucc.new(110)
range_0_90 = RangeSpecs::TenfoldSucc.new(0)..RangeSpecs::TenfoldSucc.new(90)
- range_10_100.send(@method, range_20_90).should be_true
- range_10_100.send(@method, range_20_110).should be_false
- range_10_100.send(@method, range_0_90).should be_false
+ range_10_100.send(@method, range_20_90).should == true
+ range_10_100.send(@method, range_20_110).should == false
+ range_10_100.send(@method, range_0_90).should == false
end
it "supports boundaries of different comparable types" do
- (0..10).send(@method, (3.1..7.9)).should be_true
- (0..10).send(@method, (3.1..15.9)).should be_false
- (0..10).send(@method, (-2.1..7.9)).should be_false
+ (0..10).send(@method, (3.1..7.9)).should == true
+ (0..10).send(@method, (3.1..15.9)).should == false
+ (0..10).send(@method, (-2.1..7.9)).should == false
end
it "returns false if types are not comparable" do
- (0..10).send(@method, ('a'..'z')).should be_false
- (0..10).send(@method, (RangeSpecs::TenfoldSucc.new(0)..RangeSpecs::TenfoldSucc.new(100))).should be_false
+ (0..10).send(@method, ('a'..'z')).should == false
+ (0..10).send(@method, (RangeSpecs::TenfoldSucc.new(0)..RangeSpecs::TenfoldSucc.new(100))).should == false
end
it "honors exclusion of right boundary (:exclude_end option)" do
# Integer
- (0..10).send(@method, (0..10)).should be_true
- (0...10).send(@method, (0...10)).should be_true
+ (0..10).send(@method, (0..10)).should == true
+ (0...10).send(@method, (0...10)).should == true
- (0..10).send(@method, (0...10)).should be_true
- (0...10).send(@method, (0..10)).should be_false
+ (0..10).send(@method, (0...10)).should == true
+ (0...10).send(@method, (0..10)).should == false
- (0...11).send(@method, (0..10)).should be_true
- (0..10).send(@method, (0...11)).should be_true
+ (0...11).send(@method, (0..10)).should == true
+ (0..10).send(@method, (0...11)).should == true
# Float
- (0..10.1).send(@method, (0..10.1)).should be_true
- (0...10.1).send(@method, (0...10.1)).should be_true
+ (0..10.1).send(@method, (0..10.1)).should == true
+ (0...10.1).send(@method, (0...10.1)).should == true
- (0..10.1).send(@method, (0...10.1)).should be_true
- (0...10.1).send(@method, (0..10.1)).should be_false
+ (0..10.1).send(@method, (0...10.1)).should == true
+ (0...10.1).send(@method, (0..10.1)).should == false
- (0...11.1).send(@method, (0..10.1)).should be_true
- (0..10.1).send(@method, (0...11.1)).should be_false
+ (0...11.1).send(@method, (0..10.1)).should == true
+ (0..10.1).send(@method, (0...11.1)).should == false
end
end
it "allows self to be a beginless range" do
- (...10).send(@method, (3..7)).should be_true
- (...10).send(@method, (3..15)).should be_false
+ (...10).send(@method, (3..7)).should == true
+ (...10).send(@method, (3..15)).should == false
- (..7.9).send(@method, (2.5..6.5)).should be_true
- (..7.9).send(@method, (2.5..8.5)).should be_false
+ (..7.9).send(@method, (2.5..6.5)).should == true
+ (..7.9).send(@method, (2.5..8.5)).should == false
- (..'i').send(@method, ('d'..'f')).should be_true
- (..'i').send(@method, ('d'..'z')).should be_false
+ (..'i').send(@method, ('d'..'f')).should == true
+ (..'i').send(@method, ('d'..'z')).should == false
end
it "allows self to be a endless range" do
- eval("(0...)").send(@method, (3..7)).should be_true
- eval("(5...)").send(@method, (3..15)).should be_false
+ eval("(0...)").send(@method, (3..7)).should == true
+ eval("(5...)").send(@method, (3..15)).should == false
- eval("(1.1..)").send(@method, (2.5..6.5)).should be_true
- eval("(3.3..)").send(@method, (2.5..8.5)).should be_false
+ eval("(1.1..)").send(@method, (2.5..6.5)).should == true
+ eval("(3.3..)").send(@method, (2.5..8.5)).should == false
- eval("('a'..)").send(@method, ('d'..'f')).should be_true
- eval("('p'..)").send(@method, ('d'..'z')).should be_false
+ eval("('a'..)").send(@method, ('d'..'f')).should == true
+ eval("('p'..)").send(@method, ('d'..'z')).should == false
end
it "accepts beginless range argument" do
- (..10).send(@method, (...10)).should be_true
- (0..10).send(@method, (...10)).should be_false
+ (..10).send(@method, (...10)).should == true
+ (0..10).send(@method, (...10)).should == false
- (1.1..7.9).send(@method, (...10.5)).should be_false
+ (1.1..7.9).send(@method, (...10.5)).should == false
- ('c'..'i').send(@method, (..'i')).should be_false
+ ('c'..'i').send(@method, (..'i')).should == false
end
it "accepts endless range argument" do
- eval("(0..)").send(@method, eval("(0...)")).should be_true
- (0..10).send(@method, eval("(0...)")).should be_false
+ eval("(0..)").send(@method, eval("(0...)")).should == true
+ (0..10).send(@method, eval("(0...)")).should == false
- (1.1..7.9).send(@method, eval("(0.8...)")).should be_false
+ (1.1..7.9).send(@method, eval("(0.8...)")).should == false
- ('c'..'i').send(@method, eval("('a'..)")).should be_false
+ ('c'..'i').send(@method, eval("('a'..)")).should == false
end
end
diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb
index cd2b3621bb..97721a7307 100644
--- a/spec/ruby/core/range/shared/cover_and_include.rb
+++ b/spec/ruby/core/range/shared/cover_and_include.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe :range_cover_and_include, shared: true do
@@ -46,41 +46,41 @@ describe :range_cover_and_include, shared: true do
m.should_receive(:coerce).and_return([1, 2])
m.should_receive(:<=>).and_return(1)
- rng.send(@method, m).should be_false
+ rng.send(@method, m).should == false
end
it "raises an ArgumentError without exactly one argument" do
- ->{ (1..2).send(@method) }.should raise_error(ArgumentError)
- ->{ (1..2).send(@method, 1, 2) }.should raise_error(ArgumentError)
+ ->{ (1..2).send(@method) }.should.raise(ArgumentError)
+ ->{ (1..2).send(@method, 1, 2) }.should.raise(ArgumentError)
end
it "returns true if argument is equal to the first value of the range" do
- (0..5).send(@method, 0).should be_true
- ('f'..'s').send(@method, 'f').should be_true
+ (0..5).send(@method, 0).should == true
+ ('f'..'s').send(@method, 'f').should == true
end
it "returns true if argument is equal to the last value of the range" do
- (0..5).send(@method, 5).should be_true
- (0...5).send(@method, 4).should be_true
- ('f'..'s').send(@method, 's').should be_true
+ (0..5).send(@method, 5).should == true
+ (0...5).send(@method, 4).should == true
+ ('f'..'s').send(@method, 's').should == true
end
it "returns true if argument is less than the last value of the range and greater than the first value" do
- (20..30).send(@method, 28).should be_true
- ('e'..'h').send(@method, 'g').should be_true
+ (20..30).send(@method, 28).should == true
+ ('e'..'h').send(@method, 'g').should == true
end
it "returns true if argument is sole element in the range" do
- (30..30).send(@method, 30).should be_true
+ (30..30).send(@method, 30).should == true
end
it "returns false if range is empty" do
- (30...30).send(@method, 30).should be_false
- (30...30).send(@method, nil).should be_false
+ (30...30).send(@method, 30).should == false
+ (30...30).send(@method, nil).should == false
end
it "returns false if the range does not contain the argument" do
- ('A'..'C').send(@method, 20.9).should be_false
- ('A'...'C').send(@method, 'C').should be_false
+ ('A'..'C').send(@method, 20.9).should == false
+ ('A'...'C').send(@method, 'C').should == false
end
end
diff --git a/spec/ruby/core/range/shared/include.rb b/spec/ruby/core/range/shared/include.rb
index c6c5c2becf..5f0db48008 100644
--- a/spec/ruby/core/range/shared/include.rb
+++ b/spec/ruby/core/range/shared/include.rb
@@ -1,17 +1,17 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :range_include, shared: true do
describe "on string elements" do
it "returns true if other is matched by element.succ" do
- ('a'..'c').send(@method, 'b').should be_true
- ('a'...'c').send(@method, 'b').should be_true
+ ('a'..'c').send(@method, 'b').should == true
+ ('a'...'c').send(@method, 'b').should == true
end
it "returns false if other is not matched by element.succ" do
- ('a'..'c').send(@method, 'bc').should be_false
- ('a'...'c').send(@method, 'bc').should be_false
+ ('a'..'c').send(@method, 'bc').should == false
+ ('a'...'c').send(@method, 'bc').should == false
end
end
@@ -22,27 +22,27 @@ describe :range_include, shared: true do
end
it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should == false
end
it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should == true
end
it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should == true
end
it "returns false if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should == false
end
it "returns false if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should == false
end
it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should == false
end
end
@@ -52,27 +52,27 @@ describe :range_include, shared: true do
end
it "returns false if other is less than first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(0)).should == false
end
it "returns true if other is equal as first element" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(1)).should == true
end
it "returns true if other is matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should be_true
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(10)).should == true
end
it "returns false if other is not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(2)).should == false
end
it "returns false if other is equal as last element but not matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(99)).should == false
end
it "returns false if other is greater than last element but matched by element.succ" do
- @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should be_false
+ @range.send(@method, RangeSpecs::TenfoldSucc.new(100)).should == false
end
end
end
diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb
index a1fe3ce17d..3a8843b99d 100644
--- a/spec/ruby/core/range/size_spec.rb
+++ b/spec/ruby/core/range/size_spec.rb
@@ -22,16 +22,7 @@ describe "Range#size" do
eval("('z'..)").size.should == nil
end
- ruby_version_is ""..."3.2" do
- it 'returns Float::INFINITY for all beginless ranges' do
- (..1).size.should == Float::INFINITY
- (...0.5).size.should == Float::INFINITY
- (..nil).size.should == Float::INFINITY
- (...'o').size.should == Float::INFINITY
- end
- end
-
- ruby_version_is "3.2"..."3.4" do
+ ruby_version_is ""..."3.4" do
it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do
(..1).size.should == Float::INFINITY
(...0.5).size.should == Float::INFINITY
@@ -76,26 +67,26 @@ describe "Range#size" do
ruby_version_is "3.4" do
it 'raises TypeError if a range is not iterable' do
- -> { (1.0..16.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.0...16.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.0..15.9).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.1..16.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.1..15.9).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (16.0..0.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (-Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (-Float::INFINITY..Float::INFINITY).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (..1).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (...0.5).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (..nil).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (...'o').size }.should raise_error(TypeError, /can't iterate from/)
- -> { eval("(0.5...)").size }.should raise_error(TypeError, /can't iterate from/)
- -> { eval("([]...)").size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (1.0..16.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.0...16.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.0..15.9).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.1..16.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (1.1..15.9).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (16.0..0.0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (Float::INFINITY..0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (-Float::INFINITY..0).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (-Float::INFINITY..Float::INFINITY).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (..1).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (...0.5).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (..nil).size }.should.raise(TypeError, /can't iterate from/)
+ -> { (...'o').size }.should.raise(TypeError, /can't iterate from/)
+ -> { eval("(0.5...)").size }.should.raise(TypeError, /can't iterate from/)
+ -> { eval("([]...)").size }.should.raise(TypeError, /can't iterate from/)
end
end
it "returns nil if first and last are not Numeric" do
- (:a..:z).size.should be_nil
- ('a'..'z').size.should be_nil
+ (:a..:z).size.should == nil
+ ('a'..'z').size.should == nil
end
end
diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb
index 0d0caf746d..faab95d88d 100644
--- a/spec/ruby/core/range/step_spec.rb
+++ b/spec/ruby/core/range/step_spec.rb
@@ -7,7 +7,7 @@ describe "Range#step" do
it "returns self" do
r = 1..2
- r.step { }.should equal(r)
+ r.step { }.should.equal?(r)
end
ruby_version_is ""..."3.4" do
@@ -16,27 +16,27 @@ describe "Range#step" do
obj.should_receive(:to_int).and_return(1)
(1..2).step(obj) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 2])
+ ScratchPad.recorded.should.eql?([1, 2])
end
it "raises a TypeError if step does not respond to #to_int" do
obj = mock("Range#step non-integer")
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
+ -> { (1..2).step(obj) { } }.should.raise(TypeError)
end
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock("Range#step non-integer")
obj.should_receive(:to_int).and_return("1")
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
+ -> { (1..2).step(obj) { } }.should.raise(TypeError)
end
it "raises a TypeError if the first element does not respond to #succ" do
obj = mock("Range#step non-comparable")
obj.should_receive(:<=>).with(obj).and_return(1)
- -> { (obj..obj).step { |x| x } }.should raise_error(TypeError)
+ -> { (obj..obj).step { |x| x } }.should.raise(TypeError)
end
end
@@ -46,34 +46,40 @@ describe "Range#step" do
obj.should_receive(:coerce).at_least(:once).and_return([1, 2])
(1..3).step(obj) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 3])
+ ScratchPad.recorded.should.eql?([1, 3])
end
it "raises a TypeError if step does not respond to #coerce" do
obj = mock("Range#step non-coercible")
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
+ -> { (1..2).step(obj) { } }.should.raise(TypeError)
end
end
it "raises an ArgumentError if step is 0" do
- -> { (-1..1).step(0) { |x| x } }.should raise_error(ArgumentError)
+ -> { (-1..1).step(0) { |x| x } }.should.raise(ArgumentError)
end
it "raises an ArgumentError if step is 0.0" do
- -> { (-1..1).step(0.0) { |x| x } }.should raise_error(ArgumentError)
+ -> { (-1..1).step(0.0) { |x| x } }.should.raise(ArgumentError)
end
ruby_version_is "3.4" do
- it "does not raise an ArgumentError if step is 0 for non-numeric ranges" do
+ it "does not iterate if step is 0 for bounded non-numeric ranges" do
t = Time.utc(2023, 2, 24)
- -> { (t..t+1).step(0) { break } }.should_not raise_error(ArgumentError)
+ (t..t + 1).step(0) { |x| ScratchPad << x }
+ ScratchPad.recorded.should == []
+ end
+
+ it "raises an ArgumentError when iterating a beginless range" do
+ -> { (..10).step(1) { break } }.should.raise(ArgumentError,
+ "#step iteration for beginless ranges is meaningless")
end
end
ruby_version_is ""..."3.4" do
it "raises an ArgumentError if step is negative" do
- -> { (-1..1).step(-2) { |x| x } }.should raise_error(ArgumentError)
+ -> { (-1..1).step(-2) { |x| x } }.should.raise(ArgumentError)
end
end
@@ -81,28 +87,28 @@ describe "Range#step" do
describe "and Integer values" do
it "yields Integer values incremented by 1 and less than or equal to end when not passed a step" do
(-2..2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1, 2])
end
it "yields Integer values incremented by an Integer step" do
(-5..5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3, 5])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3, 5])
end
it "yields Float values incremented by a Float step" do
(-2..2).step(1.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
end
ruby_version_is "3.4" do
it "does not iterate if step is negative for forward range" do
(-1..1).step(-1) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([])
+ ScratchPad.recorded.should.eql?([])
end
it "iterates backward if step is negative for backward range" do
(1..-1).step(-1) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 0, -1])
+ ScratchPad.recorded.should.eql?([1, 0, -1])
end
end
end
@@ -110,67 +116,79 @@ describe "Range#step" do
describe "and Float values" do
it "yields Float values incremented by 1 and less than or equal to end when not passed a step" do
(-2.0..2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0, 2.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0, 2.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0..5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
end
it "yields Float values incremented by a Float step" do
(-1.0..1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5, 1.0])
end
it "returns Float values of 'step * n + begin <= end'" do
(1.0..6.4).step(1.8) { |x| ScratchPad << x }
(1.0..12.7).step(1.3) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 2.8, 4.6, 6.4, 1.0, 2.3, 3.6,
+ ScratchPad.recorded.should.eql?([1.0, 2.8, 4.6, 6.4, 1.0, 2.3, 3.6,
4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7])
end
it "handles infinite values at either end" do
(-Float::INFINITY..0.0).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
(0.0..Float::INFINITY).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([0.0, 2.0, 4.0])
+ ScratchPad.recorded.should.eql?([0.0, 2.0, 4.0])
+ end
+
+ ruby_version_is "3.4" do
+ it "does not iterate if step is negative for forward range" do
+ (-1.0..1.0).step(-0.5) { |x| ScratchPad << x }
+ ScratchPad.recorded.should.eql?([])
+ end
+
+ it "iterates backward if step is negative for backward range" do
+ (1.0..-1.0).step(-0.5) { |x| ScratchPad << x }
+ ScratchPad.recorded.should.eql?([1.0, 0.5, 0.0, -0.5, -1.0])
+ end
end
end
describe "and Integer, Float values" do
it "yields Float values incremented by 1 and less than or equal to end when not passed a step" do
(-2..2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0, 2.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0, 2.0])
end
it "yields Float values incremented by an Integer step" do
(-5..5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
end
it "yields Float values incremented by a Float step" do
(-1..1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5, 1.0])
end
end
describe "and Float, Integer values" do
it "yields Float values incremented by 1 and less than or equal to end when not passed a step" do
(-2.0..2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0, 2.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0, 2.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0..5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0, 5.0])
end
it "yields Float values incremented by a Float step" do
(-1.0..1).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5, 1.0])
end
end
@@ -186,7 +204,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed a Float step" do
- -> { ("A".."G").step(2.0) { } }.should raise_error(TypeError)
+ -> { ("A".."G").step(2.0) { } }.should.raise(TypeError)
end
ruby_version_is ""..."3.4" do
@@ -207,7 +225,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed an incompatible type step" do
- -> { ("A".."G").step([]) { } }.should raise_error(TypeError)
+ -> { ("A".."G").step([]) { } }.should.raise(TypeError)
end
it "calls #+ on begin and each element returned by #+" do
@@ -287,89 +305,96 @@ describe "Range#step" do
describe "and Integer values" do
it "yields Integer values incremented by 1 and less than end when not passed a step" do
(-2...2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1])
end
it "yields Integer values incremented by an Integer step" do
(-5...5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3])
end
it "yields Float values incremented by a Float step" do
(-2...2).step(1.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
end
end
describe "and Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2.0...2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0...5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
(-1.0...1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
end
it "returns Float values of 'step * n + begin < end'" do
(1.0...6.4).step(1.8) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 2.8, 4.6])
+ ScratchPad.recorded.should.eql?([1.0, 2.8, 4.6])
end
it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612
(1.0...55.6).step(18.2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994])
+ ScratchPad.recorded.should.eql?([1.0, 19.2, 37.4, 55.599999999999994])
(1.0...55.6).step(18.2).size.should == 4
end
it "handles infinite values at either end" do
(-Float::INFINITY...0.0).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
(0.0...Float::INFINITY).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([0.0, 2.0, 4.0])
+ ScratchPad.recorded.should.eql?([0.0, 2.0, 4.0])
+ end
+
+ ruby_version_is "3.4" do
+ it "iterates backward with exclusive end if step is negative" do
+ (1.0...-1.0).step(-0.5) { |x| ScratchPad << x }
+ ScratchPad.recorded.should.eql?([1.0, 0.5, 0.0, -0.5])
+ end
end
end
describe "and Integer, Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2...2.0).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5...5.0).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields an Float and then Float values incremented by a Float step" do
(-1...1.0).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
end
end
describe "and Float, Integer values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2.0...2).step { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0...5).step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
(-1.0...1).step(0.5) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
end
end
@@ -386,7 +411,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed a Float step" do
- -> { ("A"..."G").step(2.0) { } }.should raise_error(TypeError)
+ -> { ("A"..."G").step(2.0) { } }.should.raise(TypeError)
end
end
@@ -397,7 +422,7 @@ describe "Range#step" do
end
it "raises a TypeError when passed an incompatible type step" do
- -> { ("A".."G").step([]) { } }.should raise_error(TypeError)
+ -> { ("A".."G").step([]) { } }.should.raise(TypeError)
end
end
end
@@ -407,67 +432,74 @@ describe "Range#step" do
describe "and Integer values" do
it "yield Integer values incremented by 1 when not passed a step" do
(-2..).step { |x| break if x > 2; ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1, 2])
ScratchPad.record []
(-2...).step { |x| break if x > 2; ScratchPad << x }
- ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
+ ScratchPad.recorded.should.eql?([-2, -1, 0, 1, 2])
end
it "yields Integer values incremented by an Integer step" do
(-5..).step(2) { |x| break if x > 3; ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3])
ScratchPad.record []
(-5...).step(2) { |x| break if x > 3; ScratchPad << x }
- ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
+ ScratchPad.recorded.should.eql?([-5, -3, -1, 1, 3])
end
it "yields Float values incremented by a Float step" do
(-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
ScratchPad.record []
(-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -0.5, 1.0])
end
end
describe "and Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
(-2.0..).step { |x| break if x > 1.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
ScratchPad.record []
(-2.0...).step { |x| break if x > 1.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
+ ScratchPad.recorded.should.eql?([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
(-5.0..).step(2) { |x| break if x > 3.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
ScratchPad.record []
(-5.0...).step(2) { |x| break if x > 3.5; ScratchPad << x }
- ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
+ ScratchPad.recorded.should.eql?([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
(-1.0..).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
ScratchPad.record []
(-1.0...).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
- ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
+ ScratchPad.recorded.should.eql?([-1.0, -0.5, 0.0, 0.5])
+ end
+
+ it "computes each value independently to avoid accumulating floating-point errors" do
+ result = []
+ (0.0..).step(0.1) { |x| result << x; break if result.size == 20 }
+ expected = 20.times.map { |i| i * 0.1 + 0.0 }
+ result.should.eql?(expected)
end
it "handles infinite values at the start" do
(-Float::INFINITY..).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
(-Float::INFINITY...).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
- ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
+ ScratchPad.recorded.should.eql?([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
end
end
@@ -491,8 +523,8 @@ describe "Range#step" do
end
it "raises a TypeError when passed a Float step" do
- -> { ('A'..).step(2.0) { } }.should raise_error(TypeError)
- -> { ('A'...).step(2.0) { } }.should raise_error(TypeError)
+ -> { ('A'..).step(2.0) { } }.should.raise(TypeError)
+ -> { ('A'...).step(2.0) { } }.should.raise(TypeError)
end
ruby_version_is "3.4" do
@@ -506,8 +538,8 @@ describe "Range#step" do
end
it "raises a TypeError when passed an incompatible type step" do
- -> { ('A'..).step([]) { } }.should raise_error(TypeError)
- -> { ('A'...).step([]) { } }.should raise_error(TypeError)
+ -> { ('A'..).step([]) { } }.should.raise(TypeError)
+ -> { ('A'...).step([]) { } }.should.raise(TypeError)
end
end
end
@@ -515,7 +547,7 @@ describe "Range#step" do
describe "when no block is given" do
it "raises an ArgumentError if step is 0" do
- -> { (-1..1).step(0) }.should raise_error(ArgumentError)
+ -> { (-1..1).step(0) }.should.raise(ArgumentError)
end
describe "returned Enumerator" do
@@ -523,20 +555,20 @@ describe "Range#step" do
ruby_version_is ""..."3.4" do
it "raises a TypeError if step does not respond to #to_int" do
obj = mock("Range#step non-integer")
- -> { (1..2).step(obj) }.should raise_error(TypeError)
+ -> { (1..2).step(obj) }.should.raise(TypeError)
end
it "raises a TypeError if #to_int does not return an Integer" do
obj = mock("Range#step non-integer")
obj.should_receive(:to_int).and_return("1")
- -> { (1..2).step(obj) }.should raise_error(TypeError)
+ -> { (1..2).step(obj) }.should.raise(TypeError)
end
end
ruby_version_is "3.4" do
it "does not raise if step is incompatible" do
obj = mock("Range#step non-integer")
- -> { (1..2).step(obj) }.should_not raise_error
+ -> { (1..2).step(obj) }.should_not.raise
end
end
@@ -589,7 +621,7 @@ describe "Range#step" do
obj = mock("Range#step non-comparable")
obj.should_receive(:<=>).with(obj).and_return(1)
enum = (obj..obj).step
- -> { enum.size }.should_not raise_error
+ -> { enum.size }.should_not.raise
enum.size.should == nil
end
end
@@ -604,7 +636,7 @@ describe "Range#step" do
obj = mock("Range#step non-comparable")
obj.should_receive(:<=>).with(obj).and_return(1)
enum = (obj..obj).step(obj)
- -> { enum.size }.should_not raise_error
+ -> { enum.size }.should_not.raise
enum.size.should == nil
end
end
@@ -657,7 +689,17 @@ describe "Range#step" do
ruby_version_is "3.4" do
it "raises an ArgumentError" do
- -> { Range.new(nil, nil).step(1) }.should raise_error(ArgumentError)
+ -> { Range.new(nil, nil).step(1) }.should.raise(ArgumentError,
+ "#step for non-numeric beginless ranges is meaningless")
+ end
+ end
+ end
+
+ context "when range is beginless and finite" do
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if step is non-numeric" do
+ -> { (..10).step("a") }.should.raise(ArgumentError,
+ "#step for non-numeric beginless ranges is meaningless")
end
end
end
diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb
index b1d3de32db..6221ae5f71 100644
--- a/spec/ruby/core/range/to_a_spec.rb
+++ b/spec/ruby/core/range/to_a_spec.rb
@@ -6,7 +6,7 @@ describe "Range#to_a" do
('A'..'D').to_a.should == ['A','B','C','D']
('A'...'D').to_a.should == ['A','B','C']
(0xfffd...0xffff).to_a.should == [0xfffd,0xfffe]
- -> { (0.5..2.4).to_a }.should raise_error(TypeError)
+ -> { (0.5..2.4).to_a }.should.raise(TypeError)
end
it "returns empty array for descending-ordered" do
@@ -30,10 +30,10 @@ describe "Range#to_a" do
end
it "throws an exception for endless ranges" do
- -> { eval("(1..)").to_a }.should raise_error(RangeError)
+ -> { eval("(1..)").to_a }.should.raise(RangeError)
end
it "throws an exception for beginless ranges" do
- -> { (..1).to_a }.should raise_error(TypeError)
+ -> { (..1).to_a }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb
new file mode 100644
index 0000000000..ac81d2cc4b
--- /dev/null
+++ b/spec/ruby/core/range/to_set_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../spec_helper'
+require_relative '../enumerable/fixtures/classes'
+
+describe "Range#to_set" do
+ it "returns a new Set created from self" do
+ (1..4).to_set.should == Set[1, 2, 3, 4]
+ (1...4).to_set.should == Set[1, 2, 3]
+ end
+
+ it "passes down passed blocks" do
+ (1..3).to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+
+ it "raises a TypeError for a beginningless range" do
+ -> {
+ (..0).to_set
+ }.should.raise(TypeError, "can't iterate from NilClass")
+ end
+
+ ruby_version_is "4.0" do
+ it "raises a RangeError if the range is endless" do
+ -> { (1..).to_set }.should.raise(RangeError, "cannot convert endless range to a set")
+ -> { (1...).to_set }.should.raise(RangeError, "cannot convert endless range to a set")
+ end
+ end
+
+ context "given positional arguments" do
+ ruby_version_is ""..."4.0" do
+ it "instantiates an object of provided as the first argument set class" do
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ end
+ end
+
+ ruby_version_is "4.0"..."4.1" do
+ it "instantiates an object of provided as the first argument set class and warns" do
+ -> {
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ set.should.is_a?(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ }.should complain(/warning: passing arguments to Enumerable#to_set is deprecated/)
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "does not accept any positional argument" do
+ -> {
+ (1..3).to_set(EnumerableSpecs::SetSubclass)
+ }.should.raise(ArgumentError, "wrong number of arguments (given 1, expected 0)")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
index d5bdadf3b6..0464eab101 100644
--- a/spec/ruby/core/rational/ceil_spec.rb
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -1,45 +1,48 @@
require_relative "../../spec_helper"
+require_relative "../integer/shared/integer_ceil_precision"
describe "Rational#ceil" do
+ context "with values equal to integers" do
+ it_behaves_like :integer_ceil_precision, :Rational
+ end
+
before do
@rational = Rational(2200, 7)
end
describe "with no arguments (precision = 0)" do
- it "returns an Integer" do
- @rational.ceil.should be_kind_of(Integer)
- end
+ it "returns the Integer value rounded toward positive infinity" do
+ @rational.ceil.should.eql? 315
- it "returns the truncated value toward positive infinity" do
- @rational.ceil.should == 315
- Rational(1, 2).ceil.should == 1
- Rational(-1, 2).ceil.should == 0
+ Rational(1, 2).ceil.should.eql? 1
+ Rational(-1, 2).ceil.should.eql? 0
+ Rational(1, 1).ceil.should.eql? 1
end
end
describe "with a precision < 0" do
- it "returns an Integer" do
- @rational.ceil(-2).should be_kind_of(Integer)
- @rational.ceil(-1).should be_kind_of(Integer)
- end
+ it "moves the rounding point n decimal places left, returning an Integer" do
+ @rational.ceil(-3).should.eql? 1000
+ @rational.ceil(-2).should.eql? 400
+ @rational.ceil(-1).should.eql? 320
- it "moves the truncation point n decimal places left" do
- @rational.ceil(-3).should == 1000
- @rational.ceil(-2).should == 400
- @rational.ceil(-1).should == 320
+ Rational(100, 2).ceil(-1).should.eql? 50
+ Rational(100, 2).ceil(-2).should.eql? 100
+ Rational(-100, 2).ceil(-1).should.eql?(-50)
+ Rational(-100, 2).ceil(-2).should.eql?(0)
end
end
describe "with precision > 0" do
- it "returns a Rational" do
- @rational.ceil(1).should be_kind_of(Rational)
- @rational.ceil(2).should be_kind_of(Rational)
- end
+ it "moves the rounding point n decimal places right, returning a Rational" do
+ @rational.ceil(1).should.eql? Rational(3143, 10)
+ @rational.ceil(2).should.eql? Rational(31429, 100)
+ @rational.ceil(3).should.eql? Rational(157143, 500)
- it "moves the truncation point n decimal places right" do
- @rational.ceil(1).should == Rational(3143, 10)
- @rational.ceil(2).should == Rational(31429, 100)
- @rational.ceil(3).should == Rational(157143, 500)
+ Rational(100, 2).ceil(1).should.eql? Rational(50, 1)
+ Rational(100, 2).ceil(2).should.eql? Rational(50, 1)
+ Rational(-100, 2).ceil(1).should.eql? Rational(-50, 1)
+ Rational(-100, 2).ceil(2).should.eql? Rational(-50, 1)
end
end
end
diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb
index c9db60d5c7..482e904989 100644
--- a/spec/ruby/core/rational/comparison_spec.rb
+++ b/spec/ruby/core/rational/comparison_spec.rb
@@ -3,54 +3,54 @@ require_relative 'fixtures/rational'
describe "Rational#<=> when passed a Rational object" do
it "returns 1 when self is greater than the passed argument" do
- (Rational(4, 4) <=> Rational(3, 4)).should equal(1)
- (Rational(-3, 4) <=> Rational(-4, 4)).should equal(1)
+ (Rational(4, 4) <=> Rational(3, 4)).should.equal?(1)
+ (Rational(-3, 4) <=> Rational(-4, 4)).should.equal?(1)
end
it "returns 0 when self is equal to the passed argument" do
- (Rational(4, 4) <=> Rational(4, 4)).should equal(0)
- (Rational(-3, 4) <=> Rational(-3, 4)).should equal(0)
+ (Rational(4, 4) <=> Rational(4, 4)).should.equal?(0)
+ (Rational(-3, 4) <=> Rational(-3, 4)).should.equal?(0)
end
it "returns -1 when self is less than the passed argument" do
- (Rational(3, 4) <=> Rational(4, 4)).should equal(-1)
- (Rational(-4, 4) <=> Rational(-3, 4)).should equal(-1)
+ (Rational(3, 4) <=> Rational(4, 4)).should.equal?(-1)
+ (Rational(-4, 4) <=> Rational(-3, 4)).should.equal?(-1)
end
end
describe "Rational#<=> when passed an Integer object" do
it "returns 1 when self is greater than the passed argument" do
- (Rational(4, 4) <=> 0).should equal(1)
- (Rational(4, 4) <=> -10).should equal(1)
- (Rational(-3, 4) <=> -1).should equal(1)
+ (Rational(4, 4) <=> 0).should.equal?(1)
+ (Rational(4, 4) <=> -10).should.equal?(1)
+ (Rational(-3, 4) <=> -1).should.equal?(1)
end
it "returns 0 when self is equal to the passed argument" do
- (Rational(4, 4) <=> 1).should equal(0)
- (Rational(-8, 4) <=> -2).should equal(0)
+ (Rational(4, 4) <=> 1).should.equal?(0)
+ (Rational(-8, 4) <=> -2).should.equal?(0)
end
it "returns -1 when self is less than the passed argument" do
- (Rational(3, 4) <=> 1).should equal(-1)
- (Rational(-4, 4) <=> 0).should equal(-1)
+ (Rational(3, 4) <=> 1).should.equal?(-1)
+ (Rational(-4, 4) <=> 0).should.equal?(-1)
end
end
describe "Rational#<=> when passed a Float object" do
it "returns 1 when self is greater than the passed argument" do
- (Rational(4, 4) <=> 0.5).should equal(1)
- (Rational(4, 4) <=> -1.5).should equal(1)
- (Rational(-3, 4) <=> -0.8).should equal(1)
+ (Rational(4, 4) <=> 0.5).should.equal?(1)
+ (Rational(4, 4) <=> -1.5).should.equal?(1)
+ (Rational(-3, 4) <=> -0.8).should.equal?(1)
end
it "returns 0 when self is equal to the passed argument" do
- (Rational(4, 4) <=> 1.0).should equal(0)
- (Rational(-6, 4) <=> -1.5).should equal(0)
+ (Rational(4, 4) <=> 1.0).should.equal?(0)
+ (Rational(-6, 4) <=> -1.5).should.equal?(0)
end
it "returns -1 when self is less than the passed argument" do
- (Rational(3, 4) <=> 1.2).should equal(-1)
- (Rational(-4, 4) <=> 0.5).should equal(-1)
+ (Rational(3, 4) <=> 1.2).should.equal?(-1)
+ (Rational(-4, 4) <=> 0.5).should.equal?(-1)
end
end
@@ -82,12 +82,12 @@ describe "Rational#<=> when passed an Object that responds to #coerce" do
b = mock("numeric with failed #coerce")
b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
- -> { Rational(3, 4) <=> b }.should raise_error(RationalSpecs::CoerceError)
+ -> { Rational(3, 4) <=> b }.should.raise(RationalSpecs::CoerceError)
end
end
describe "Rational#<=> when passed a non-Numeric Object that doesn't respond to #coerce" do
it "returns nil" do
- (Rational <=> mock("Object")).should be_nil
+ (Rational <=> mock("Object")).should == nil
end
end
diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb
index 4687244893..ba6e936d60 100644
--- a/spec/ruby/core/rational/denominator_spec.rb
+++ b/spec/ruby/core/rational/denominator_spec.rb
@@ -2,8 +2,8 @@ require_relative "../../spec_helper"
describe "Rational#denominator" do
it "returns the denominator" do
- Rational(3, 4).denominator.should equal(4)
- Rational(3, -4).denominator.should equal(4)
+ Rational(3, 4).denominator.should.equal?(4)
+ Rational(3, -4).denominator.should.equal?(4)
Rational(1, bignum_value).denominator.should == bignum_value
end
diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb
index d3adb9b536..a679663543 100644
--- a/spec/ruby/core/rational/div_spec.rb
+++ b/spec/ruby/core/rational/div_spec.rb
@@ -2,16 +2,16 @@ require_relative "../../spec_helper"
describe "Rational#div" do
it "returns an Integer" do
- Rational(229, 21).div(82).should be_kind_of(Integer)
+ Rational(229, 21).div(82).should.is_a?(Integer)
end
it "raises an ArgumentError if passed more than one argument" do
- -> { Rational(3, 4).div(2,3) }.should raise_error(ArgumentError)
+ -> { Rational(3, 4).div(2,3) }.should.raise(ArgumentError)
end
# See http://redmine.ruby-lang.org/issues/show/1648
it "raises a TypeError if passed a non-numeric argument" do
- -> { Rational(3, 4).div([]) }.should raise_error(TypeError)
+ -> { Rational(3, 4).div([]) }.should.raise(TypeError)
end
end
@@ -22,11 +22,11 @@ describe "Rational#div passed a Rational" do
end
it "raises a ZeroDivisionError when the argument has a numerator of 0" do
- -> { Rational(3, 4).div(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(Rational(0, 3)) }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the argument has a numerator of 0.0" do
- -> { Rational(3, 4).div(Rational(0.0, 3)) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(Rational(0.0, 3)) }.should.raise(ZeroDivisionError)
end
end
@@ -37,7 +37,7 @@ describe "Rational#div passed an Integer" do
end
it "raises a ZeroDivisionError when the argument is 0" do
- -> { Rational(3, 4).div(0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(0) }.should.raise(ZeroDivisionError)
end
end
@@ -49,6 +49,6 @@ describe "Rational#div passed a Float" do
end
it "raises a ZeroDivisionError when the argument is 0.0" do
- -> { Rational(3, 4).div(0.0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4).div(0.0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb
index 8f5ca1fdec..c45d1fca2f 100644
--- a/spec/ruby/core/rational/divide_spec.rb
+++ b/spec/ruby/core/rational/divide_spec.rb
@@ -29,46 +29,46 @@ end
describe "Rational#/ when passed an Integer" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) / 2).should eql(Rational(3, 8))
- (Rational(2, 4) / 2).should eql(Rational(1, 4))
- (Rational(6, 7) / -2).should eql(Rational(-3, 7))
+ (Rational(3, 4) / 2).should.eql?(Rational(3, 8))
+ (Rational(2, 4) / 2).should.eql?(Rational(1, 4))
+ (Rational(6, 7) / -2).should.eql?(Rational(-3, 7))
end
it "raises a ZeroDivisionError when passed 0" do
- -> { Rational(3, 4) / 0 }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4) / 0 }.should.raise(ZeroDivisionError)
end
end
describe "Rational#/ when passed a Rational" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) / Rational(3, 4)).should eql(Rational(1, 1))
- (Rational(2, 4) / Rational(1, 4)).should eql(Rational(2, 1))
+ (Rational(3, 4) / Rational(3, 4)).should.eql?(Rational(1, 1))
+ (Rational(2, 4) / Rational(1, 4)).should.eql?(Rational(2, 1))
(Rational(2, 4) / 2).should == Rational(1, 4)
(Rational(6, 7) / -2).should == Rational(-3, 7)
end
it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
- -> { Rational(3, 4) / Rational(0, 1) }.should raise_error(ZeroDivisionError)
+ -> { Rational(3, 4) / Rational(0, 1) }.should.raise(ZeroDivisionError)
end
end
describe "Rational#/ when passed a Float" do
it "returns self divided by other as a Float" do
- (Rational(3, 4) / 0.75).should eql(1.0)
- (Rational(3, 4) / 0.25).should eql(3.0)
- (Rational(3, 4) / 0.3).should eql(2.5)
+ (Rational(3, 4) / 0.75).should.eql?(1.0)
+ (Rational(3, 4) / 0.25).should.eql?(3.0)
+ (Rational(3, 4) / 0.3).should.eql?(2.5)
- (Rational(-3, 4) / 0.3).should eql(-2.5)
- (Rational(3, -4) / 0.3).should eql(-2.5)
- (Rational(3, 4) / -0.3).should eql(-2.5)
+ (Rational(-3, 4) / 0.3).should.eql?(-2.5)
+ (Rational(3, -4) / 0.3).should.eql?(-2.5)
+ (Rational(3, 4) / -0.3).should.eql?(-2.5)
end
it "returns infinity when passed 0" do
- (Rational(3, 4) / 0.0).infinite?.should eql(1)
- (Rational(-3, -4) / 0.0).infinite?.should eql(1)
+ (Rational(3, 4) / 0.0).infinite?.should.eql?(1)
+ (Rational(-3, -4) / 0.0).infinite?.should.eql?(1)
- (Rational(-3, 4) / 0.0).infinite?.should eql(-1)
- (Rational(3, -4) / 0.0).infinite?.should eql(-1)
+ (Rational(-3, 4) / 0.0).infinite?.should.eql?(-1)
+ (Rational(3, -4) / 0.0).infinite?.should.eql?(-1)
end
end
diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb
index f0555294a3..68f8ecfd2d 100644
--- a/spec/ruby/core/rational/divmod_spec.rb
+++ b/spec/ruby/core/rational/divmod_spec.rb
@@ -2,41 +2,41 @@ require_relative "../../spec_helper"
describe "Rational#divmod when passed a Rational" do
it "returns the quotient as Integer and the remainder as Rational" do
- Rational(7, 4).divmod(Rational(1, 2)).should eql([3, Rational(1, 4)])
- Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)])
- Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)])
+ Rational(7, 4).divmod(Rational(1, 2)).should.eql?([3, Rational(1, 4)])
+ Rational(7, 4).divmod(Rational(-1, 2)).should.eql?([-4, Rational(-1, 4)])
+ Rational(0, 4).divmod(Rational(4, 3)).should.eql?([0, Rational(0, 1)])
- Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([3458764513820540928, Rational(0, 1)])
+ Rational(bignum_value, 4).divmod(Rational(4, 3)).should.eql?([3458764513820540928, Rational(0, 1)])
end
it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
- -> { Rational(7, 4).divmod(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ -> { Rational(7, 4).divmod(Rational(0, 3)) }.should.raise(ZeroDivisionError)
end
end
describe "Rational#divmod when passed an Integer" do
it "returns the quotient as Integer and the remainder as Rational" do
- Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)])
- Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)])
+ Rational(7, 4).divmod(2).should.eql?([0, Rational(7, 4)])
+ Rational(7, 4).divmod(-2).should.eql?([-1, Rational(-1, 4)])
- Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)])
+ Rational(bignum_value, 4).divmod(3).should.eql?([1537228672809129301, Rational(1, 1)])
end
it "raises a ZeroDivisionError when passed 0" do
- -> { Rational(7, 4).divmod(0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(7, 4).divmod(0) }.should.raise(ZeroDivisionError)
end
end
describe "Rational#divmod when passed a Float" do
it "returns the quotient as Integer and the remainder as Float" do
- Rational(7, 4).divmod(0.5).should eql([3, 0.25])
+ Rational(7, 4).divmod(0.5).should.eql?([3, 0.25])
end
it "returns the quotient as Integer and the remainder as Float" do
- Rational(7, 4).divmod(-0.5).should eql([-4, -0.25])
+ Rational(7, 4).divmod(-0.5).should.eql?([-4, -0.25])
end
it "raises a ZeroDivisionError when passed 0" do
- -> { Rational(7, 4).divmod(0.0) }.should raise_error(ZeroDivisionError)
+ -> { Rational(7, 4).divmod(0.0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb
index ba40d29c3b..1dd077ea41 100644
--- a/spec/ruby/core/rational/equal_value_spec.rb
+++ b/spec/ruby/core/rational/equal_value_spec.rb
@@ -5,35 +5,35 @@ describe "Rational#==" do
obj = mock("Object")
obj.should_receive(:==).and_return(:result)
- (Rational(3, 4) == obj).should_not be_false
+ (Rational(3, 4) == obj).should_not == false
end
end
describe "Rational#== when passed a Rational" do
it "returns true if self has the same numerator and denominator as the passed argument" do
- (Rational(3, 4) == Rational(3, 4)).should be_true
- (Rational(-3, -4) == Rational(3, 4)).should be_true
- (Rational(-4, 5) == Rational(4, -5)).should be_true
+ (Rational(3, 4) == Rational(3, 4)).should == true
+ (Rational(-3, -4) == Rational(3, 4)).should == true
+ (Rational(-4, 5) == Rational(4, -5)).should == true
- (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should be_true
- (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should be_true
+ (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should == true
+ (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should == true
end
end
describe "Rational#== when passed a Float" do
it "converts self to a Float and compares it with the passed argument" do
- (Rational(3, 4) == 0.75).should be_true
- (Rational(4, 2) == 2.0).should be_true
- (Rational(-4, 2) == -2.0).should be_true
- (Rational(4, -2) == -2.0).should be_true
+ (Rational(3, 4) == 0.75).should == true
+ (Rational(4, 2) == 2.0).should == true
+ (Rational(-4, 2) == -2.0).should == true
+ (Rational(4, -2) == -2.0).should == true
end
end
describe "Rational#== when passed an Integer" do
it "returns true if self has the passed argument as numerator and a denominator of 1" do
# Rational(x, y) reduces x and y automatically
- (Rational(4, 2) == 2).should be_true
- (Rational(-4, 2) == -2).should be_true
- (Rational(4, -2) == -2).should be_true
+ (Rational(4, 2) == 2).should == true
+ (Rational(-4, 2) == -2).should == true
+ (Rational(4, -2) == -2).should == true
end
end
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
index f9fdbcb33e..88b4a43796 100644
--- a/spec/ruby/core/rational/exponent_spec.rb
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -5,20 +5,20 @@ describe "Rational#**" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns Rational(1) if the exponent is Rational(0)" do
- (Rational(0) ** Rational(0)).should eql(Rational(1))
- (Rational(1) ** Rational(0)).should eql(Rational(1))
- (Rational(3, 4) ** Rational(0)).should eql(Rational(1))
- (Rational(-1) ** Rational(0)).should eql(Rational(1))
- (Rational(-3, 4) ** Rational(0)).should eql(Rational(1))
- (Rational(bignum_value) ** Rational(0)).should eql(Rational(1))
- (Rational(-bignum_value) ** Rational(0)).should eql(Rational(1))
+ (Rational(0) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(1) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(3, 4) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(-1) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(-3, 4) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(bignum_value) ** Rational(0)).should.eql?(Rational(1))
+ (Rational(-bignum_value) ** Rational(0)).should.eql?(Rational(1))
end
it "returns self raised to the argument as a Rational if the exponent's denominator is 1" do
- (Rational(3, 4) ** Rational(1, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) ** Rational(2, 1)).should eql(Rational(9, 16))
- (Rational(3, 4) ** Rational(-1, 1)).should eql(Rational(4, 3))
- (Rational(3, 4) ** Rational(-2, 1)).should eql(Rational(16, 9))
+ (Rational(3, 4) ** Rational(1, 1)).should.eql?(Rational(3, 4))
+ (Rational(3, 4) ** Rational(2, 1)).should.eql?(Rational(9, 16))
+ (Rational(3, 4) ** Rational(-1, 1)).should.eql?(Rational(4, 3))
+ (Rational(3, 4) ** Rational(-2, 1)).should.eql?(Rational(16, 9))
end
it "returns self raised to the argument as a Float if the exponent's denominator is not 1" do
@@ -49,12 +49,12 @@ describe "Rational#**" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns Rational(1, 1) when the passed argument is 0" do
- (Rational(3, 4) ** 0).should eql(Rational(1, 1))
- (Rational(-3, 4) ** 0).should eql(Rational(1, 1))
- (Rational(3, -4) ** 0).should eql(Rational(1, 1))
+ (Rational(3, 4) ** 0).should.eql?(Rational(1, 1))
+ (Rational(-3, 4) ** 0).should.eql?(Rational(1, 1))
+ (Rational(3, -4) ** 0).should.eql?(Rational(1, 1))
- (Rational(bignum_value, 4) ** 0).should eql(Rational(1, 1))
- (Rational(3, -bignum_value) ** 0).should eql(Rational(1, 1))
+ (Rational(bignum_value, 4) ** 0).should.eql?(Rational(1, 1))
+ (Rational(3, -bignum_value) ** 0).should.eql?(Rational(1, 1))
end
end
end
@@ -62,26 +62,26 @@ describe "Rational#**" do
describe "when passed Bignum" do
# #5713
it "returns Rational(0) when self is Rational(0) and the exponent is positive" do
- (Rational(0) ** bignum_value).should eql(Rational(0))
+ (Rational(0) ** bignum_value).should.eql?(Rational(0))
end
it "raises ZeroDivisionError when self is Rational(0) and the exponent is negative" do
- -> { Rational(0) ** -bignum_value }.should raise_error(ZeroDivisionError)
+ -> { Rational(0) ** -bignum_value }.should.raise(ZeroDivisionError)
end
it "returns Rational(1) when self is Rational(1)" do
- (Rational(1) ** bignum_value).should eql(Rational(1))
- (Rational(1) ** -bignum_value).should eql(Rational(1))
+ (Rational(1) ** bignum_value).should.eql?(Rational(1))
+ (Rational(1) ** -bignum_value).should.eql?(Rational(1))
end
it "returns Rational(1) when self is Rational(-1) and the exponent is positive and even" do
- (Rational(-1) ** bignum_value(0)).should eql(Rational(1))
- (Rational(-1) ** bignum_value(2)).should eql(Rational(1))
+ (Rational(-1) ** bignum_value(0)).should.eql?(Rational(1))
+ (Rational(-1) ** bignum_value(2)).should.eql?(Rational(1))
end
it "returns Rational(-1) when self is Rational(-1) and the exponent is positive and odd" do
- (Rational(-1) ** bignum_value(1)).should eql(Rational(-1))
- (Rational(-1) ** bignum_value(3)).should eql(Rational(-1))
+ (Rational(-1) ** bignum_value(1)).should.eql?(Rational(-1))
+ (Rational(-1) ** bignum_value(3)).should.eql?(Rational(-1))
end
ruby_version_is ""..."3.4" do
@@ -96,10 +96,10 @@ describe "Rational#**" do
it "returns 0.0 when self is > 1 and the exponent is negative" do
-> {
- (Rational(2) ** -bignum_value).should eql(0.0)
+ (Rational(2) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
-> {
- (Rational(fixnum_max) ** -bignum_value).should eql(0.0)
+ (Rational(fixnum_max) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
end
end
@@ -108,37 +108,37 @@ describe "Rational#**" do
it "raises an ArgumentError when self is > 1" do
-> {
(Rational(2) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_max) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is > 1 and the exponent is negative" do
-> {
(Rational(2) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_max) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is < -1" do
-> {
(Rational(-2) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_min) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is < -1 and the exponent is negative" do
-> {
(Rational(-2) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_min) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError, "exponent is too large")
end
end
@@ -159,10 +159,10 @@ describe "Rational#**" do
it "returns 0.0 when self is < -1 and the exponent is negative" do
-> {
- (Rational(-2) ** -bignum_value).should eql(0.0)
+ (Rational(-2) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
-> {
- (Rational(fixnum_min) ** -bignum_value).should eql(0.0)
+ (Rational(fixnum_min) ** -bignum_value).should.eql?(0.0)
}.should complain(/warning: in a\*\*b, b may be too big/)
end
end
@@ -171,7 +171,7 @@ describe "Rational#**" do
describe "when passed Float" do
it "returns self converted to Float and raised to the passed argument" do
- (Rational(3, 1) ** 3.0).should eql(27.0)
+ (Rational(3, 1) ** 3.0).should.eql?(27.0)
(Rational(3, 1) ** 1.5).should be_close(5.19615242270663, TOLERANCE)
(Rational(3, 1) ** -1.5).should be_close(0.192450089729875, TOLERANCE)
end
@@ -213,26 +213,24 @@ describe "Rational#**" do
it "raises ZeroDivisionError for Rational(0, 1) passed a negative Integer" do
[-1, -4, -9999].each do |exponent|
- -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(0, 1) ** exponent }.should.raise(ZeroDivisionError, "divided by 0")
end
end
it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational with denominator 1" do
[Rational(-1, 1), Rational(-3, 1)].each do |exponent|
- -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(0, 1) ** exponent }.should.raise(ZeroDivisionError, "divided by 0")
end
end
# #7513
it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational" do
- -> { Rational(0, 1) ** Rational(-3, 2) }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(0, 1) ** Rational(-3, 2) }.should.raise(ZeroDivisionError, "divided by 0")
end
- platform_is_not :solaris do # See https://github.com/ruby/spec/issues/134
- it "returns Infinity for Rational(0, 1) passed a negative Float" do
- [-1.0, -3.0, -3.14].each do |exponent|
- (Rational(0, 1) ** exponent).infinite?.should == 1
- end
+ it "returns Infinity for Rational(0, 1) passed a negative Float" do
+ [-1.0, -3.0, -3.14].each do |exponent|
+ (Rational(0, 1) ** exponent).infinite?.should == 1
end
end
end
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
index 8068aaf119..6d4cee79a9 100644
--- a/spec/ruby/core/rational/floor_spec.rb
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -1,45 +1,49 @@
require_relative "../../spec_helper"
+require_relative "../integer/shared/integer_floor_precision"
describe "Rational#floor" do
+ context "with values equal to integers" do
+ it_behaves_like :integer_floor_precision, :Rational
+ end
+
before do
@rational = Rational(2200, 7)
end
describe "with no arguments (precision = 0)" do
- it "returns an integer" do
- @rational.floor.should be_kind_of(Integer)
- end
- it "returns the truncated value toward negative infinity" do
- @rational.floor.should == 314
- Rational(1, 2).floor.should == 0
- Rational(-1, 2).floor.should == -1
+ it "returns the Integer value rounded toward negative infinity" do
+ @rational.floor.should.eql? 314
+
+ Rational(1, 2).floor.should.eql? 0
+ Rational(-1, 2).floor.should.eql?(-1)
+ Rational(1, 1).floor.should.eql? 1
end
end
describe "with a precision < 0" do
- it "returns an integer" do
- @rational.floor(-2).should be_kind_of(Integer)
- @rational.floor(-1).should be_kind_of(Integer)
- end
+ it "moves the rounding point n decimal places left, returning an Integer" do
+ @rational.floor(-3).should.eql? 0
+ @rational.floor(-2).should.eql? 300
+ @rational.floor(-1).should.eql? 310
- it "moves the truncation point n decimal places left" do
- @rational.floor(-3).should == 0
- @rational.floor(-2).should == 300
- @rational.floor(-1).should == 310
+ Rational(100, 2).floor(-1).should.eql? 50
+ Rational(100, 2).floor(-2).should.eql? 0
+ Rational(-100, 2).floor(-1).should.eql?(-50)
+ Rational(-100, 2).floor(-2).should.eql?(-100)
end
end
describe "with a precision > 0" do
- it "returns a Rational" do
- @rational.floor(1).should be_kind_of(Rational)
- @rational.floor(2).should be_kind_of(Rational)
- end
+ it "moves the rounding point n decimal places right, returning a Rational" do
+ @rational.floor(1).should.eql? Rational(1571, 5)
+ @rational.floor(2).should.eql? Rational(7857, 25)
+ @rational.floor(3).should.eql? Rational(62857, 200)
- it "moves the truncation point n decimal places right" do
- @rational.floor(1).should == Rational(1571, 5)
- @rational.floor(2).should == Rational(7857, 25)
- @rational.floor(3).should == Rational(62857, 200)
+ Rational(100, 2).floor(1).should.eql? Rational(50, 1)
+ Rational(100, 2).floor(2).should.eql? Rational(50, 1)
+ Rational(-100, 2).floor(1).should.eql? Rational(-50, 1)
+ Rational(-100, 2).floor(2).should.eql? Rational(-50, 1)
end
end
end
diff --git a/spec/ruby/core/rational/integer_spec.rb b/spec/ruby/core/rational/integer_spec.rb
index be7476a9dd..cd7fa97fcf 100644
--- a/spec/ruby/core/rational/integer_spec.rb
+++ b/spec/ruby/core/rational/integer_spec.rb
@@ -3,11 +3,11 @@ describe "Rational#integer?" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns false for a rational with a numerator and no denominator" do
- Rational(20).integer?.should be_false
+ Rational(20).integer?.should == false
end
end
it "returns false for a rational with a numerator and a denominator" do
- Rational(20,3).integer?.should be_false
+ Rational(20,3).integer?.should == false
end
end
diff --git a/spec/ruby/core/rational/marshal_dump_spec.rb b/spec/ruby/core/rational/marshal_dump_spec.rb
index 17a6107cd5..06bf36f166 100644
--- a/spec/ruby/core/rational/marshal_dump_spec.rb
+++ b/spec/ruby/core/rational/marshal_dump_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Rational#marshal_dump" do
it "is a private method" do
- Rational.should have_private_instance_method(:marshal_dump, false)
+ Rational.private_instance_methods(false).should.include?(:marshal_dump)
end
it "dumps numerator and denominator" do
diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb
index 8aee85f9dd..4e10e118b9 100644
--- a/spec/ruby/core/rational/minus_spec.rb
+++ b/spec/ruby/core/rational/minus_spec.rb
@@ -29,23 +29,23 @@ end
describe "Rational#- passed a Rational" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
+ (Rational(3, 4) - Rational(0, 1)).should.eql?(Rational(3, 4))
+ (Rational(3, 4) - Rational(1, 4)).should.eql?(Rational(1, 2))
- (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
+ (Rational(3, 4) - Rational(2, 1)).should.eql?(Rational(-5, 4))
end
end
describe "Rational#- passed a Float" do
it "returns the result of subtracting other from self as a Float" do
- (Rational(3, 4) - 0.2).should eql(0.55)
- (Rational(3, 4) - 2.5).should eql(-1.75)
+ (Rational(3, 4) - 0.2).should.eql?(0.55)
+ (Rational(3, 4) - 2.5).should.eql?(-1.75)
end
end
describe "Rational#- passed an Integer" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - 1).should eql(Rational(-1, 4))
- (Rational(3, 4) - 2).should eql(Rational(-5, 4))
+ (Rational(3, 4) - 1).should.eql?(Rational(-1, 4))
+ (Rational(3, 4) - 2).should.eql?(Rational(-5, 4))
end
end
diff --git a/spec/ruby/core/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb
index 23ed93e118..6241077f68 100644
--- a/spec/ruby/core/rational/modulo_spec.rb
+++ b/spec/ruby/core/rational/modulo_spec.rb
@@ -16,7 +16,7 @@ describe "Rational#%" do
end
it "returns a Float value when the argument is Float" do
- (Rational(7, 4) % 1.0).should be_kind_of(Float)
+ (Rational(7, 4) % 1.0).should.is_a?(Float)
(Rational(7, 4) % 1.0).should == 0.75
(Rational(7, 4) % 0.26).should be_close(0.19, 0.0001)
end
@@ -24,20 +24,20 @@ describe "Rational#%" do
it "raises ZeroDivisionError on zero denominator" do
-> {
Rational(3, 5) % Rational(0, 1)
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
-> {
Rational(0, 1) % Rational(0, 1)
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
-> {
Rational(3, 5) % 0
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
end
it "raises a ZeroDivisionError when the argument is 0.0" do
-> {
Rational(3, 5) % 0.0
- }.should raise_error(ZeroDivisionError)
+ }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb
index 87fb4de2b4..3e059cbc1c 100644
--- a/spec/ruby/core/rational/multiply_spec.rb
+++ b/spec/ruby/core/rational/multiply_spec.rb
@@ -29,37 +29,37 @@ end
describe "Rational#* passed a Rational" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) * Rational(3, 4)).should eql(Rational(9, 16))
- (Rational(2, 4) * Rational(1, 4)).should eql(Rational(1, 8))
+ (Rational(3, 4) * Rational(3, 4)).should.eql?(Rational(9, 16))
+ (Rational(2, 4) * Rational(1, 4)).should.eql?(Rational(1, 8))
- (Rational(3, 4) * Rational(0, 1)).should eql(Rational(0, 4))
+ (Rational(3, 4) * Rational(0, 1)).should.eql?(Rational(0, 4))
end
end
describe "Rational#* passed a Float" do
it "returns self divided by other as a Float" do
- (Rational(3, 4) * 0.75).should eql(0.5625)
- (Rational(3, 4) * 0.25).should eql(0.1875)
+ (Rational(3, 4) * 0.75).should.eql?(0.5625)
+ (Rational(3, 4) * 0.25).should.eql?(0.1875)
(Rational(3, 4) * 0.3).should be_close(0.225, TOLERANCE)
(Rational(-3, 4) * 0.3).should be_close(-0.225, TOLERANCE)
(Rational(3, -4) * 0.3).should be_close(-0.225, TOLERANCE)
(Rational(3, 4) * -0.3).should be_close(-0.225, TOLERANCE)
- (Rational(3, 4) * 0.0).should eql(0.0)
- (Rational(-3, -4) * 0.0).should eql(0.0)
+ (Rational(3, 4) * 0.0).should.eql?(0.0)
+ (Rational(-3, -4) * 0.0).should.eql?(0.0)
- (Rational(-3, 4) * 0.0).should eql(0.0)
- (Rational(3, -4) * 0.0).should eql(0.0)
+ (Rational(-3, 4) * 0.0).should.eql?(0.0)
+ (Rational(3, -4) * 0.0).should.eql?(0.0)
end
end
describe "Rational#* passed an Integer" do
it "returns self divided by other as a Rational" do
- (Rational(3, 4) * 2).should eql(Rational(3, 2))
- (Rational(2, 4) * 2).should eql(Rational(1, 1))
- (Rational(6, 7) * -2).should eql(Rational(-12, 7))
+ (Rational(3, 4) * 2).should.eql?(Rational(3, 2))
+ (Rational(2, 4) * 2).should.eql?(Rational(1, 1))
+ (Rational(6, 7) * -2).should.eql?(Rational(-12, 7))
- (Rational(3, 4) * 0).should eql(Rational(0, 4))
+ (Rational(3, 4) * 0).should.eql?(Rational(0, 4))
end
end
diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb
index 2b9fe2ff5c..631bb4703c 100644
--- a/spec/ruby/core/rational/numerator_spec.rb
+++ b/spec/ruby/core/rational/numerator_spec.rb
@@ -2,8 +2,8 @@ require_relative "../../spec_helper"
describe "Rational#numerator" do
it "returns the numerator" do
- Rational(3, 4).numerator.should equal(3)
- Rational(3, -4).numerator.should equal(-3)
+ Rational(3, 4).numerator.should.equal?(3)
+ Rational(3, -4).numerator.should.equal?(-3)
Rational(bignum_value, 1).numerator.should == bignum_value
end
diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb
index 01df5f6719..92f830a105 100644
--- a/spec/ruby/core/rational/plus_spec.rb
+++ b/spec/ruby/core/rational/plus_spec.rb
@@ -29,22 +29,22 @@ end
describe "Rational#+ with a Rational" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) + Rational(0, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) + Rational(1, 4)).should eql(Rational(1, 1))
+ (Rational(3, 4) + Rational(0, 1)).should.eql?(Rational(3, 4))
+ (Rational(3, 4) + Rational(1, 4)).should.eql?(Rational(1, 1))
- (Rational(3, 4) + Rational(2, 1)).should eql(Rational(11, 4))
+ (Rational(3, 4) + Rational(2, 1)).should.eql?(Rational(11, 4))
end
end
describe "Rational#+ with a Float" do
it "returns the result of subtracting other from self as a Float" do
- (Rational(3, 4) + 0.2).should eql(0.95)
- (Rational(3, 4) + 2.5).should eql(3.25)
+ (Rational(3, 4) + 0.2).should.eql?(0.95)
+ (Rational(3, 4) + 2.5).should.eql?(3.25)
end
end
describe "Rational#+ with an Integer" do
it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) + 1).should eql(Rational(7, 4))
- (Rational(3, 4) + 2).should eql(Rational(11, 4))
+ (Rational(3, 4) + 1).should.eql?(Rational(7, 4))
+ (Rational(3, 4) + 2).should.eql?(Rational(11, 4))
end
end
diff --git a/spec/ruby/core/rational/rational_spec.rb b/spec/ruby/core/rational/rational_spec.rb
index 482deab38d..278c4116a4 100644
--- a/spec/ruby/core/rational/rational_spec.rb
+++ b/spec/ruby/core/rational/rational_spec.rb
@@ -6,6 +6,6 @@ describe "Rational" do
end
it "does not respond to new" do
- -> { Rational.new(1) }.should raise_error(NoMethodError)
+ -> { Rational.new(1) }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/rational/rationalize_spec.rb b/spec/ruby/core/rational/rationalize_spec.rb
index 3db027d446..9c86824ddd 100644
--- a/spec/ruby/core/rational/rationalize_spec.rb
+++ b/spec/ruby/core/rational/rationalize_spec.rb
@@ -30,7 +30,7 @@ describe "Rational#rationalize" do
end
it "raises ArgumentError when passed more than one argument" do
- -> { Rational(1,1).rationalize(0.1, 0.1) }.should raise_error(ArgumentError)
- -> { Rational(1,1).rationalize(0.1, 0.1, 2) }.should raise_error(ArgumentError)
+ -> { Rational(1,1).rationalize(0.1, 0.1) }.should.raise(ArgumentError)
+ -> { Rational(1,1).rationalize(0.1, 0.1, 2) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/rational/round_spec.rb b/spec/ruby/core/rational/round_spec.rb
index ac3dcafe7b..dd6f66f408 100644
--- a/spec/ruby/core/rational/round_spec.rb
+++ b/spec/ruby/core/rational/round_spec.rb
@@ -7,9 +7,9 @@ describe "Rational#round" do
describe "with no arguments (precision = 0)" do
it "returns an integer" do
- @rational.round.should be_kind_of(Integer)
- Rational(0, 1).round(0).should be_kind_of(Integer)
- Rational(124, 1).round(0).should be_kind_of(Integer)
+ @rational.round.should.is_a?(Integer)
+ Rational(0, 1).round(0).should.is_a?(Integer)
+ Rational(124, 1).round(0).should.is_a?(Integer)
end
it "returns the truncated value toward the nearest integer" do
@@ -30,10 +30,10 @@ describe "Rational#round" do
describe "with a precision < 0" do
it "returns an integer" do
- @rational.round(-2).should be_kind_of(Integer)
- @rational.round(-1).should be_kind_of(Integer)
- Rational(0, 1).round(-1).should be_kind_of(Integer)
- Rational(2, 1).round(-1).should be_kind_of(Integer)
+ @rational.round(-2).should.is_a?(Integer)
+ @rational.round(-1).should.is_a?(Integer)
+ Rational(0, 1).round(-1).should.is_a?(Integer)
+ Rational(2, 1).round(-1).should.is_a?(Integer)
end
it "moves the truncation point n decimal places left" do
@@ -45,12 +45,12 @@ describe "Rational#round" do
describe "with a precision > 0" do
it "returns a Rational" do
- @rational.round(1).should be_kind_of(Rational)
- @rational.round(2).should be_kind_of(Rational)
+ @rational.round(1).should.is_a?(Rational)
+ @rational.round(2).should.is_a?(Rational)
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
- Rational(0, 1).round(1).should be_kind_of(Rational)
- Rational(2, 1).round(1).should be_kind_of(Rational)
+ Rational(0, 1).round(1).should.is_a?(Rational)
+ Rational(2, 1).round(1).should.is_a?(Rational)
end
end
@@ -100,7 +100,7 @@ describe "Rational#round" do
end
it "raise for a non-existent round mode" do
- -> { Rational(10, 4).round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
+ -> { Rational(10, 4).round(half: :nonsense) }.should.raise(ArgumentError, "invalid rounding mode: nonsense")
end
end
end
diff --git a/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
index f4cf70d147..e15169c912 100644
--- a/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
+++ b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
@@ -6,6 +6,6 @@ describe :rational_arithmetic_exception_in_coerce, shared: true do
b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
# e.g. Rational(3, 4) + b
- -> { Rational(3, 4).send(@method, b) }.should raise_error(RationalSpecs::CoerceError)
+ -> { Rational(3, 4).send(@method, b) }.should.raise(RationalSpecs::CoerceError)
end
end
diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb
index d0da49d377..40e3f11c0c 100644
--- a/spec/ruby/core/rational/to_f_spec.rb
+++ b/spec/ruby/core/rational/to_f_spec.rb
@@ -2,10 +2,10 @@ require_relative "../../spec_helper"
describe "Rational#to_f" do
it "returns self converted to a Float" do
- Rational(3, 4).to_f.should eql(0.75)
- Rational(3, -4).to_f.should eql(-0.75)
- Rational(-1, 4).to_f.should eql(-0.25)
- Rational(-1, -4).to_f.should eql(0.25)
+ Rational(3, 4).to_f.should.eql?(0.75)
+ Rational(3, -4).to_f.should.eql?(-0.75)
+ Rational(-1, 4).to_f.should.eql?(-0.25)
+ Rational(-1, -4).to_f.should.eql?(0.25)
end
it "converts to a Float for large numerator and denominator" do
diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb
index 520a380b2a..e61b1b6c3b 100644
--- a/spec/ruby/core/rational/to_i_spec.rb
+++ b/spec/ruby/core/rational/to_i_spec.rb
@@ -2,11 +2,11 @@ require_relative "../../spec_helper"
describe "Rational#to_i" do
it "converts self to an Integer by truncation" do
- Rational(7, 4).to_i.should eql(1)
- Rational(11, 4).to_i.should eql(2)
+ Rational(7, 4).to_i.should.eql?(1)
+ Rational(11, 4).to_i.should.eql?(2)
end
it "converts self to an Integer by truncation" do
- Rational(-7, 4).to_i.should eql(-1)
+ Rational(-7, 4).to_i.should.eql?(-1)
end
end
diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb
index 34f16d7890..eb6097f595 100644
--- a/spec/ruby/core/rational/to_r_spec.rb
+++ b/spec/ruby/core/rational/to_r_spec.rb
@@ -3,15 +3,15 @@ require_relative "../../spec_helper"
describe "Rational#to_r" do
it "returns self" do
a = Rational(3, 4)
- a.to_r.should equal(a)
+ a.to_r.should.equal?(a)
a = Rational(bignum_value, 4)
- a.to_r.should equal(a)
+ a.to_r.should.equal?(a)
end
it "raises TypeError trying to convert BasicObject" do
obj = BasicObject.new
- -> { Rational(obj) }.should raise_error(TypeError)
+ -> { Rational(obj) }.should.raise(TypeError)
end
it "works when a BasicObject has to_r" do
@@ -21,6 +21,6 @@ describe "Rational#to_r" do
it "fails when a BasicObject's to_r does not return a Rational" do
obj = BasicObject.new; def obj.to_r; 1 end
- -> { Rational(obj) }.should raise_error(TypeError)
+ -> { Rational(obj) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb
index 728fca34ea..3614431a7f 100644
--- a/spec/ruby/core/rational/truncate_spec.rb
+++ b/spec/ruby/core/rational/truncate_spec.rb
@@ -7,7 +7,7 @@ describe "Rational#truncate" do
describe "with no arguments (precision = 0)" do
it "returns an integer" do
- @rational.truncate.should be_kind_of(Integer)
+ @rational.truncate.should.is_a?(Integer)
end
it "returns the truncated value toward 0" do
@@ -19,7 +19,7 @@ describe "Rational#truncate" do
describe "with an explicit precision = 0" do
it "returns an integer" do
- @rational.truncate(0).should be_kind_of(Integer)
+ @rational.truncate(0).should.is_a?(Integer)
end
it "returns the truncated value toward 0" do
@@ -31,8 +31,8 @@ describe "Rational#truncate" do
describe "with a precision < 0" do
it "returns an integer" do
- @rational.truncate(-2).should be_kind_of(Integer)
- @rational.truncate(-1).should be_kind_of(Integer)
+ @rational.truncate(-2).should.is_a?(Integer)
+ @rational.truncate(-1).should.is_a?(Integer)
end
it "moves the truncation point n decimal places left" do
@@ -44,8 +44,8 @@ describe "Rational#truncate" do
describe "with a precision > 0" do
it "returns a Rational" do
- @rational.truncate(1).should be_kind_of(Rational)
- @rational.truncate(2).should be_kind_of(Rational)
+ @rational.truncate(1).should.is_a?(Rational)
+ @rational.truncate(2).should.is_a?(Rational)
end
it "moves the truncation point n decimal places right" do
@@ -57,15 +57,15 @@ describe "Rational#truncate" do
describe "with an invalid value for precision" do
it "raises a TypeError" do
- -> { @rational.truncate(nil) }.should raise_error(TypeError, "not an integer")
- -> { @rational.truncate(1.0) }.should raise_error(TypeError, "not an integer")
- -> { @rational.truncate('') }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(nil) }.should.raise(TypeError, "not an integer")
+ -> { @rational.truncate(1.0) }.should.raise(TypeError, "not an integer")
+ -> { @rational.truncate('') }.should.raise(TypeError, "not an integer")
end
it "does not call to_int on the argument" do
object = Object.new
object.should_not_receive(:to_int)
- -> { @rational.truncate(object) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(object) }.should.raise(TypeError, "not an integer")
end
end
end
diff --git a/spec/ruby/core/rational/zero_spec.rb b/spec/ruby/core/rational/zero_spec.rb
index af7fb391ac..2e4f783d5c 100644
--- a/spec/ruby/core/rational/zero_spec.rb
+++ b/spec/ruby/core/rational/zero_spec.rb
@@ -1,14 +1,14 @@
require_relative "../../spec_helper"
describe "Rational#zero?" do
it "returns true if the numerator is 0" do
- Rational(0,26).zero?.should be_true
+ Rational(0,26).zero?.should == true
end
it "returns true if the numerator is 0.0" do
- Rational(0.0,26).zero?.should be_true
+ Rational(0.0,26).zero?.should == true
end
it "returns false if the numerator isn't 0" do
- Rational(26).zero?.should be_false
+ Rational(26).zero?.should == false
end
end
diff --git a/spec/ruby/core/refinement/append_features_spec.rb b/spec/ruby/core/refinement/append_features_spec.rb
index fb84f245bd..cffc9ed308 100644
--- a/spec/ruby/core/refinement/append_features_spec.rb
+++ b/spec/ruby/core/refinement/append_features_spec.rb
@@ -1,20 +1,18 @@
require_relative '../../spec_helper'
describe "Refinement#append_features" do
- ruby_version_is "3.2" do
- it "is not defined" do
- Refinement.should_not have_private_instance_method(:append_features)
- end
+ it "is not defined" do
+ Refinement.private_instance_methods(true).should_not.include?(:append_features)
+ end
- it "is not called by Module#include" do
- c = Class.new
- Module.new do
- refine c do
- called = false
- define_method(:append_features){called = true}
- proc{c.include(self)}.should raise_error(TypeError)
- called.should == false
- end
+ it "is not called by Module#include" do
+ c = Class.new
+ Module.new do
+ refine c do
+ called = false
+ define_method(:append_features){called = true}
+ proc{c.include(self)}.should.raise(TypeError)
+ called.should == false
end
end
end
diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb
index 6c2a0af4f3..f6fe2a60ea 100644
--- a/spec/ruby/core/refinement/extend_object_spec.rb
+++ b/spec/ruby/core/refinement/extend_object_spec.rb
@@ -1,22 +1,20 @@
require_relative '../../spec_helper'
describe "Refinement#extend_object" do
- ruby_version_is "3.2" do
- it "is not defined" do
- Refinement.should_not have_private_instance_method(:extend_object)
- end
+ it "is not defined" do
+ Refinement.private_instance_methods(true).should_not.include?(:extend_object)
+ end
- it "is not called by Object#extend" do
- c = Class.new
- Module.new do
- refine c do
- called = false
- define_method(:extend_object) { called = true }
- -> {
- c.extend(self)
- }.should raise_error(TypeError)
- called.should == false
- end
+ it "is not called by Object#extend" do
+ c = Class.new
+ Module.new do
+ refine c do
+ called = false
+ define_method(:extend_object) { called = true }
+ -> {
+ c.extend(self)
+ }.should.raise(TypeError)
+ called.should == false
end
end
end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
index 13c0b1004c..bcb5e9b066 100644
--- a/spec/ruby/core/refinement/import_methods_spec.rb
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -23,7 +23,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods Integer
- }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
+ }.should.raise(TypeError, "wrong argument type Class (expected Module)")
end
end
end
@@ -82,7 +82,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods str_utils, Kernel
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -127,7 +127,7 @@ describe "Refinement#import_methods" do
using self
-> {
"foo".indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
+ }.should.raise(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
end
end
@@ -142,7 +142,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods str_utils, Integer
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -150,7 +150,7 @@ describe "Refinement#import_methods" do
using string_refined
-> {
"foo".indent(3)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
end
@@ -213,7 +213,7 @@ describe "Refinement#import_methods" do
using self
-> {
String.indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
+ }.should.raise(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
end
end
@@ -242,13 +242,33 @@ describe "Refinement#import_methods" do
end
end
+ it "correctly sets owner as the refinement module" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ refinement = Module.new do
+ refine String do
+ import_methods str_utils
+ end
+ end
+
+ Module.new do
+ using refinement
+
+ String.instance_method(:indent).owner.should == refinement.refinements.first
+ end
+ end
+
context "when methods are not defined in Ruby code" do
it "raises ArgumentError" do
Module.new do
refine String do
-> {
import_methods Kernel
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
@@ -259,7 +279,7 @@ describe "Refinement#import_methods" do
refine String do
-> {
import_methods Zlib
- }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
+ }.should.raise(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
end
end
end
diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb
index d20ab47e33..55ac89ffb5 100644
--- a/spec/ruby/core/refinement/include_spec.rb
+++ b/spec/ruby/core/refinement/include_spec.rb
@@ -1,26 +1,12 @@
require_relative '../../spec_helper'
describe "Refinement#include" do
- ruby_version_is ""..."3.2" do
- it "warns about deprecation" do
- Module.new do
- refine String do
- -> {
- include Module.new
- }.should complain(/warning: Refinement#include is deprecated and will be removed in Ruby 3.2/)
- end
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError" do
- Module.new do
- refine String do
- -> {
- include Module.new
- }.should raise_error(TypeError, "Refinement#include has been removed")
- end
+ it "raises a TypeError" do
+ Module.new do
+ refine String do
+ -> {
+ include Module.new
+ }.should.raise(TypeError, "Refinement#include has been removed")
end
end
end
diff --git a/spec/ruby/core/refinement/prepend_features_spec.rb b/spec/ruby/core/refinement/prepend_features_spec.rb
index 9fdea199a2..9dc5838f1f 100644
--- a/spec/ruby/core/refinement/prepend_features_spec.rb
+++ b/spec/ruby/core/refinement/prepend_features_spec.rb
@@ -1,20 +1,18 @@
require_relative '../../spec_helper'
describe "Refinement#prepend_features" do
- ruby_version_is "3.2" do
- it "is not defined" do
- Refinement.should_not have_private_instance_method(:prepend_features)
- end
+ it "is not defined" do
+ Refinement.private_instance_methods(true).should_not.include?(:prepend_features)
+ end
- it "is not called by Module#prepend" do
- c = Class.new
- Module.new do
- refine c do
- called = false
- define_method(:prepend_features){called = true}
- proc{c.prepend(self)}.should raise_error(TypeError)
- called.should == false
- end
+ it "is not called by Module#prepend" do
+ c = Class.new
+ Module.new do
+ refine c do
+ called = false
+ define_method(:prepend_features){called = true}
+ proc{c.prepend(self)}.should.raise(TypeError)
+ called.should == false
end
end
end
diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb
index 5d66766689..fd70dd6f97 100644
--- a/spec/ruby/core/refinement/prepend_spec.rb
+++ b/spec/ruby/core/refinement/prepend_spec.rb
@@ -1,26 +1,12 @@
require_relative '../../spec_helper'
describe "Refinement#prepend" do
- ruby_version_is ""..."3.2" do
- it "warns about deprecation" do
- Module.new do
- refine String do
- -> {
- prepend Module.new
- }.should complain(/warning: Refinement#prepend is deprecated and will be removed in Ruby 3.2/)
- end
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError" do
- Module.new do
- refine String do
- -> {
- prepend Module.new
- }.should raise_error(TypeError, "Refinement#prepend has been removed")
- end
+ it "raises a TypeError" do
+ Module.new do
+ refine String do
+ -> {
+ prepend Module.new
+ }.should.raise(TypeError, "Refinement#prepend has been removed")
end
end
end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
index acc6e2cb2b..b532d9a773 100644
--- a/spec/ruby/core/refinement/refined_class_spec.rb
+++ b/spec/ruby/core/refinement/refined_class_spec.rb
@@ -2,11 +2,7 @@ require_relative "../../spec_helper"
require_relative 'shared/target'
describe "Refinement#refined_class" do
- ruby_version_is "3.2"..."3.3" do
- it_behaves_like :refinement_target, :refined_class
- end
-
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "has been deprecated in favour of Refinement#target" do
refinement_int = nil
diff --git a/spec/ruby/core/refinement/target_spec.rb b/spec/ruby/core/refinement/target_spec.rb
index fee9588a96..8bd816aea6 100644
--- a/spec/ruby/core/refinement/target_spec.rb
+++ b/spec/ruby/core/refinement/target_spec.rb
@@ -2,7 +2,5 @@ require_relative "../../spec_helper"
require_relative 'shared/target'
describe "Refinement#target" do
- ruby_version_is "3.3" do
- it_behaves_like :refinement_target, :target
- end
+ it_behaves_like :refinement_target, :target
end
diff --git a/spec/ruby/core/regexp/case_compare_spec.rb b/spec/ruby/core/regexp/case_compare_spec.rb
index 5ae8b56c6a..29aada70bc 100644
--- a/spec/ruby/core/regexp/case_compare_spec.rb
+++ b/spec/ruby/core/regexp/case_compare_spec.rb
@@ -2,25 +2,25 @@ require_relative '../../spec_helper'
describe "Regexp#===" do
it "is true if there is a match" do
- (/abc/ === "aabcc").should be_true
+ (/abc/ === "aabcc").should == true
end
it "is false if there is no match" do
- (/abc/ === "xyz").should be_false
+ (/abc/ === "xyz").should == false
end
it "returns true if it matches a Symbol" do
- (/a/ === :a).should be_true
+ (/a/ === :a).should == true
end
it "returns false if it does not match a Symbol" do
- (/a/ === :b).should be_false
+ (/a/ === :b).should == false
end
# mirroring https://github.com/ruby/ruby/blob/master/test/ruby/test_regexp.rb
it "returns false if the other value cannot be coerced to a string" do
- (/abc/ === nil).should be_false
- (/abc/ === /abc/).should be_false
+ (/abc/ === nil).should == false
+ (/abc/ === /abc/).should == false
end
it "uses #to_str on string-like objects" do
@@ -30,6 +30,6 @@ describe "Regexp#===" do
end
end.new
- (/abc/ === stringlike).should be_true
+ (/abc/ === stringlike).should == true
end
end
diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb
index c41399cfbb..887c8d77dc 100644
--- a/spec/ruby/core/regexp/compile_spec.rb
+++ b/spec/ruby/core/regexp/compile_spec.rb
@@ -14,6 +14,6 @@ describe "Regexp.compile given a Regexp" do
it_behaves_like :regexp_new_regexp, :compile
end
-describe "Regexp.new given a non-String/Regexp" do
+describe "Regexp.compile given a non-String/Regexp" do
it_behaves_like :regexp_new_non_string_or_regexp, :compile
end
diff --git a/spec/ruby/core/regexp/encoding_spec.rb b/spec/ruby/core/regexp/encoding_spec.rb
index dfc835b4e4..fb4fdba064 100644
--- a/spec/ruby/core/regexp/encoding_spec.rb
+++ b/spec/ruby/core/regexp/encoding_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Regexp#encoding" do
it "returns an Encoding object" do
- /glar/.encoding.should be_an_instance_of(Encoding)
+ /glar/.encoding.should.instance_of?(Encoding)
end
it "defaults to US-ASCII if the Regexp contains only US-ASCII character" do
diff --git a/spec/ruby/core/regexp/fixed_encoding_spec.rb b/spec/ruby/core/regexp/fixed_encoding_spec.rb
index 29d0a22c53..5d8b1c2860 100644
--- a/spec/ruby/core/regexp/fixed_encoding_spec.rb
+++ b/spec/ruby/core/regexp/fixed_encoding_spec.rb
@@ -3,34 +3,34 @@ require_relative '../../spec_helper'
describe "Regexp#fixed_encoding?" do
it "returns false by default" do
- /needle/.fixed_encoding?.should be_false
+ /needle/.fixed_encoding?.should == false
end
it "returns false if the 'n' modifier was supplied to the Regexp" do
- /needle/n.fixed_encoding?.should be_false
+ /needle/n.fixed_encoding?.should == false
end
it "returns true if the 'u' modifier was supplied to the Regexp" do
- /needle/u.fixed_encoding?.should be_true
+ /needle/u.fixed_encoding?.should == true
end
it "returns true if the 's' modifier was supplied to the Regexp" do
- /needle/s.fixed_encoding?.should be_true
+ /needle/s.fixed_encoding?.should == true
end
it "returns true if the 'e' modifier was supplied to the Regexp" do
- /needle/e.fixed_encoding?.should be_true
+ /needle/e.fixed_encoding?.should == true
end
it "returns true if the Regexp contains a \\u escape" do
- /needle \u{8768}/.fixed_encoding?.should be_true
+ /needle \u{8768}/.fixed_encoding?.should == true
end
it "returns true if the Regexp contains a UTF-8 literal" do
- /文字化け/.fixed_encoding?.should be_true
+ /文字化け/.fixed_encoding?.should == true
end
it "returns true if the Regexp was created with the Regexp::FIXEDENCODING option" do
- Regexp.new("", Regexp::FIXEDENCODING).fixed_encoding?.should be_true
+ Regexp.new("", Regexp::FIXEDENCODING).fixed_encoding?.should == true
end
end
diff --git a/spec/ruby/core/regexp/initialize_spec.rb b/spec/ruby/core/regexp/initialize_spec.rb
index dd57292242..1c0133acae 100644
--- a/spec/ruby/core/regexp/initialize_spec.rb
+++ b/spec/ruby/core/regexp/initialize_spec.rb
@@ -2,14 +2,28 @@ require_relative '../../spec_helper'
describe "Regexp#initialize" do
it "is a private method" do
- Regexp.should have_private_instance_method(:initialize)
+ Regexp.private_instance_methods(false).should.include?(:initialize)
end
it "raises a FrozenError on a Regexp literal" do
- -> { //.send(:initialize, "") }.should raise_error(FrozenError)
+ -> { //.send(:initialize, "") }.should.raise(FrozenError)
end
- it "raises a TypeError on an initialized non-literal Regexp" do
- -> { Regexp.new("").send(:initialize, "") }.should raise_error(TypeError)
+ ruby_version_is "4.1" do
+ it "raises a FrozenError on an initialized non-literal Regexp" do
+ regexp = Regexp.new("")
+ -> { regexp.send(:initialize, "") }.should.raise(FrozenError)
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "raises a TypeError on an initialized non-literal Regexp" do
+ -> { Regexp.new("").send(:initialize, "") }.should.raise(TypeError)
+ end
+ end
+
+ it "raises a TypeError on an initialized non-literal Regexp subclass" do
+ r = Class.new(Regexp).new("")
+ -> { r.send(:initialize, "") }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/regexp/last_match_spec.rb b/spec/ruby/core/regexp/last_match_spec.rb
index 0bfed32051..6c256cc1cf 100644
--- a/spec/ruby/core/regexp/last_match_spec.rb
+++ b/spec/ruby/core/regexp/last_match_spec.rb
@@ -4,7 +4,7 @@ describe "Regexp.last_match" do
it "returns MatchData instance when not passed arguments" do
/c(.)t/ =~ 'cat'
- Regexp.last_match.should be_kind_of(MatchData)
+ Regexp.last_match.should.is_a?(MatchData)
end
it "returns the nth field in this MatchData when passed an Integer" do
@@ -28,7 +28,7 @@ describe "Regexp.last_match" do
it "raises an IndexError when given a missing name" do
/(?<test>[A-Z]+.*)/ =~ "TEST123"
- -> { Regexp.last_match(:missing) }.should raise_error(IndexError)
+ -> { Regexp.last_match(:missing) }.should.raise(IndexError)
end
end
@@ -50,7 +50,7 @@ describe "Regexp.last_match" do
it "raises a TypeError when unable to coerce" do
obj = Object.new
/(?<test>[A-Z]+.*)/ =~ "TEST123"
- -> { Regexp.last_match(obj) }.should raise_error(TypeError)
+ -> { Regexp.last_match(obj) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
index 4dc436264f..f70021dfed 100644
--- a/spec/ruby/core/regexp/linear_time_spec.rb
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -1,25 +1,80 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Regexp.linear_time?" do
- it "returns true if matching can be done in linear time" do
- Regexp.linear_time?(/a/).should == true
- Regexp.linear_time?('a').should == true
+describe "Regexp.linear_time?" do
+ it "returns true if matching can be done in linear time" do
+ Regexp.linear_time?(/a/).should == true
+ Regexp.linear_time?('a').should == true
+ end
+
+ it "returns true if matching can be done in linear time for a binary Regexp" do
+ Regexp.linear_time?(/[\x80-\xff]/n).should == true
+ end
+
+ it "return false if matching can't be done in linear time" do
+ Regexp.linear_time?(/(a)\1/).should == false
+ Regexp.linear_time?("(a)\\1").should == false
+ end
+
+ it "accepts flags for string argument" do
+ Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
+ end
+
+ it "warns about flags being ignored for regexp arguments" do
+ -> {
+ Regexp.linear_time?(/a/, Regexp::IGNORECASE)
+ }.should complain(/warning: flags ignored/)
+ end
+
+ it "returns true for positive lookahead" do
+ Regexp.linear_time?(/a*(?:(?=a*)a)*b/).should == true
+ end
+
+ it "returns true for positive lookbehind" do
+ Regexp.linear_time?(/a*(?:(?<=a)a*)*b/).should == true
+ end
+
+ it "returns true for negative lookbehind" do
+ Regexp.linear_time?(/a*(?:(?<!a)a*)*b/).should == true
+ end
+
+ # There are two known ways to make Regexp linear:
+ # * Using a DFA (deterministic finite-state automaton) Regexp engine, which always matches in linear time (e.g. TruffleRuby with TRegex)
+ # * Caching position and state to avoid catastrophic backtracking (e.g. CRuby: https://bugs.ruby-lang.org/issues/19104)
+ #
+ # Both approach should be allowed and given that DFA Regexp engines
+ # are much faster there should be no specs preventing using them.
+ uses_regexp_caching = RUBY_ENGINE == 'ruby'
+ uses_dfa_regexp_engine = !uses_regexp_caching
+
+ # The following specs should not be relied upon,
+ # they are here only to illustrate differences between Regexp engines.
+ guard -> { uses_regexp_caching } do
+ it "returns true for negative lookahead" do
+ Regexp.linear_time?(/a*(?:(?!a*)a*)*b/).should == true
end
- it "return false if matching can't be done in linear time" do
- Regexp.linear_time?(/(a)\1/).should == false
- Regexp.linear_time?("(a)\\1").should == false
+ it "returns true for atomic groups" do
+ Regexp.linear_time?(/a*(?:(?>a)a*)*b/).should == true
end
- it "accepts flags for string argument" do
- Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
+ it "returns true for possessive quantifiers" do
+ Regexp.linear_time?(/a*(?:(?:a)?+a*)*b/).should == true
+ end
+
+ it "returns true for positive lookbehind with capture group" do
+ Regexp.linear_time?(/.(?<=(a))/).should == true
+ end
+ end
+
+ # The following specs should not be relied upon,
+ # they are here only to illustrate differences between Regexp engines.
+ guard -> { uses_dfa_regexp_engine } do
+ it "returns true for non-recursive subexpression call" do
+ Regexp.linear_time?(/(?<a>a){0}\g<a>/).should == true
end
- it "warns about flags being ignored for regexp arguments" do
- -> {
- Regexp.linear_time?(/a/, Regexp::IGNORECASE)
- }.should complain(/warning: flags ignored/)
+ it "returns true for positive lookahead with capture group" do
+ Regexp.linear_time?(/x+(?=(a))/).should == true
end
end
end
diff --git a/spec/ruby/core/regexp/match_spec.rb b/spec/ruby/core/regexp/match_spec.rb
index 80dbfb4c10..276cecc8e4 100644
--- a/spec/ruby/core/regexp/match_spec.rb
+++ b/spec/ruby/core/regexp/match_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe :regexp_match, shared: true do
it "returns nil if there is no match" do
- /xyz/.send(@method,"abxyc").should be_nil
+ /xyz/.send(@method,"abxyc").should == nil
end
it "returns nil if the object is nil" do
- /\w+/.send(@method, nil).should be_nil
+ /\w+/.send(@method, nil).should == nil
end
end
@@ -27,19 +27,19 @@ describe "Regexp#match" do
it_behaves_like :regexp_match, :match
it "returns a MatchData object" do
- /(.)(.)(.)/.match("abc").should be_kind_of(MatchData)
+ /(.)(.)(.)/.match("abc").should.is_a?(MatchData)
end
it "returns a MatchData object, when argument is a Symbol" do
- /(.)(.)(.)/.match(:abc).should be_kind_of(MatchData)
+ /(.)(.)(.)/.match(:abc).should.is_a?(MatchData)
end
it "raises a TypeError on an uninitialized Regexp" do
- -> { Regexp.allocate.match('foo') }.should raise_error(TypeError)
+ -> { Regexp.allocate.match('foo') }.should.raise(TypeError)
end
it "raises TypeError on an uninitialized Regexp" do
- -> { Regexp.allocate.match('foo'.encode("UTF-16LE")) }.should raise_error(TypeError)
+ -> { Regexp.allocate.match('foo'.encode("UTF-16LE")) }.should.raise(TypeError)
end
describe "with [string, position]" do
@@ -54,7 +54,7 @@ describe "Regexp#match" do
it "raises an ArgumentError for an invalid encoding" do
x96 = ([150].pack('C')).force_encoding('utf-8')
- -> { /(.).(.)/.match("Hello, #{x96} world!", 1) }.should raise_error(ArgumentError)
+ -> { /(.).(.)/.match("Hello, #{x96} world!", 1) }.should.raise(ArgumentError)
end
end
@@ -69,14 +69,14 @@ describe "Regexp#match" do
it "raises an ArgumentError for an invalid encoding" do
x96 = ([150].pack('C')).force_encoding('utf-8')
- -> { /(.).(.)/.match("Hello, #{x96} world!", -1) }.should raise_error(ArgumentError)
+ -> { /(.).(.)/.match("Hello, #{x96} world!", -1) }.should.raise(ArgumentError)
end
end
describe "when passed a block" do
it "yields the MatchData" do
/./.match("abc") {|m| ScratchPad.record m }
- ScratchPad.recorded.should be_kind_of(MatchData)
+ ScratchPad.recorded.should.is_a?(MatchData)
end
it "returns the block result" do
@@ -94,20 +94,20 @@ describe "Regexp#match" do
it "resets $~ if passed nil" do
# set $~
/./.match("a")
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
/1/.match(nil)
- $~.should be_nil
+ $~.should == nil
end
it "raises TypeError when the given argument cannot be coerced to String" do
f = 1
- -> { /foo/.match(f)[0] }.should raise_error(TypeError)
+ -> { /foo/.match(f)[0] }.should.raise(TypeError)
end
it "raises TypeError when the given argument is an Exception" do
f = Exception.new("foo")
- -> { /foo/.match(f)[0] }.should raise_error(TypeError)
+ -> { /foo/.match(f)[0] }.should.raise(TypeError)
end
end
@@ -119,22 +119,22 @@ describe "Regexp#match?" do
context "when matches the given value" do
it "returns true but does not set Regexp.last_match" do
- /string/i.match?('string').should be_true
- Regexp.last_match.should be_nil
+ /string/i.match?('string').should == true
+ Regexp.last_match.should == nil
end
end
it "returns false when does not match the given value" do
- /STRING/.match?('string').should be_false
+ /STRING/.match?('string').should == false
end
it "takes matching position as the 2nd argument" do
- /str/i.match?('string', 0).should be_true
- /str/i.match?('string', 1).should be_false
+ /str/i.match?('string', 0).should == true
+ /str/i.match?('string', 1).should == false
end
it "returns false when given nil" do
- /./.match?(nil).should be_false
+ /./.match?(nil).should == false
end
end
diff --git a/spec/ruby/core/regexp/named_captures_spec.rb b/spec/ruby/core/regexp/named_captures_spec.rb
index 1a68d7877b..4d3fdd23ab 100644
--- a/spec/ruby/core/regexp/named_captures_spec.rb
+++ b/spec/ruby/core/regexp/named_captures_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Regexp#named_captures" do
it "returns a Hash" do
- /foo/.named_captures.should be_an_instance_of(Hash)
+ /foo/.named_captures.should.instance_of?(Hash)
end
it "returns an empty Hash when there are no capture groups" do
@@ -17,7 +17,7 @@ describe "Regexp#named_captures" do
it "sets the values of the Hash to Arrays" do
rex = /this (?<is>is) [aA] (?<pat>pate?rn)/
rex.named_captures.values.each do |value|
- value.should be_an_instance_of(Array)
+ value.should.instance_of?(Array)
end
end
diff --git a/spec/ruby/core/regexp/names_spec.rb b/spec/ruby/core/regexp/names_spec.rb
index 099768fd26..9013f41e20 100644
--- a/spec/ruby/core/regexp/names_spec.rb
+++ b/spec/ruby/core/regexp/names_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Regexp#names" do
it "returns an Array" do
- /foo/.names.should be_an_instance_of(Array)
+ /foo/.names.should.instance_of?(Array)
end
it "returns an empty Array if there are no named captures" do
@@ -11,7 +11,7 @@ describe "Regexp#names" do
it "returns each named capture as a String" do
/n(?<cap>ee)d(?<ture>le)/.names.each do |name|
- name.should be_an_instance_of(String)
+ name.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb
index 65f612df55..79210e9a23 100644
--- a/spec/ruby/core/regexp/new_spec.rb
+++ b/spec/ruby/core/regexp/new_spec.rb
@@ -7,11 +7,11 @@ end
describe "Regexp.new given a String" do
it_behaves_like :regexp_new_string, :new
+ it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given a Regexp" do
it_behaves_like :regexp_new_regexp, :new
- it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given a non-String/Regexp" do
diff --git a/spec/ruby/core/regexp/options_spec.rb b/spec/ruby/core/regexp/options_spec.rb
index 527b51a3b2..c3401cee6e 100644
--- a/spec/ruby/core/regexp/options_spec.rb
+++ b/spec/ruby/core/regexp/options_spec.rb
@@ -2,9 +2,9 @@ require_relative '../../spec_helper'
describe "Regexp#options" do
it "returns an Integer bitvector of regexp options for the Regexp object" do
- /cat/.options.should be_kind_of(Integer)
+ /cat/.options.should.is_a?(Integer)
not_supported_on :opal do
- /cat/ix.options.should be_kind_of(Integer)
+ /cat/ix.options.should.is_a?(Integer)
end
end
@@ -29,7 +29,7 @@ describe "Regexp#options" do
end
it "raises a TypeError on an uninitialized Regexp" do
- -> { Regexp.allocate.options }.should raise_error(TypeError)
+ -> { Regexp.allocate.options }.should.raise(TypeError)
end
it "includes Regexp::FIXEDENCODING for a Regexp literal with the 'u' option" do
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 3ca50d5a47..affdaf855c 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -1,10 +1,16 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :regexp_new, shared: true do
it "requires one argument and creates a new regular expression object" do
Regexp.send(@method, '').is_a?(Regexp).should == true
end
+ ruby_version_is "4.1" do
+ it "is frozen" do
+ Regexp.send(@method, '').should.frozen?
+ end
+ end
+
it "works by default for subclasses with overridden #initialize" do
class RegexpSpecsSubclass < Regexp
def initialize(*args)
@@ -17,10 +23,10 @@ describe :regexp_new, shared: true do
class RegexpSpecsSubclassTwo < Regexp; end
- RegexpSpecsSubclass.send(@method, "hi").should be_kind_of(RegexpSpecsSubclass)
+ RegexpSpecsSubclass.send(@method, "hi").should.is_a?(RegexpSpecsSubclass)
RegexpSpecsSubclass.send(@method, "hi").args.first.should == "hi"
- RegexpSpecsSubclassTwo.send(@method, "hi").should be_kind_of(RegexpSpecsSubclassTwo)
+ RegexpSpecsSubclassTwo.send(@method, "hi").should.is_a?(RegexpSpecsSubclassTwo)
end
end
@@ -34,19 +40,19 @@ describe :regexp_new_non_string_or_regexp, shared: true do
it "raises TypeError if there is no #to_str method for non-String/Regexp argument" do
obj = Object.new
- -> { Regexp.send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ -> { Regexp.send(@method, obj) }.should.raise(TypeError, "no implicit conversion of Object into String")
- -> { Regexp.send(@method, 1) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
- -> { Regexp.send(@method, 1.0) }.should raise_error(TypeError, "no implicit conversion of Float into String")
- -> { Regexp.send(@method, :symbol) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
- -> { Regexp.send(@method, []) }.should raise_error(TypeError, "no implicit conversion of Array into String")
+ -> { Regexp.send(@method, 1) }.should.raise(TypeError, "no implicit conversion of Integer into String")
+ -> { Regexp.send(@method, 1.0) }.should.raise(TypeError, "no implicit conversion of Float into String")
+ -> { Regexp.send(@method, :symbol) }.should.raise(TypeError, "no implicit conversion of Symbol into String")
+ -> { Regexp.send(@method, []) }.should.raise(TypeError, "no implicit conversion of Array into String")
end
it "raises TypeError if #to_str returns non-String value" do
obj = Object.new
def obj.to_str() [] end
- -> { Regexp.send(@method, obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ -> { Regexp.send(@method, obj) }.should raise_consistent_error(TypeError, /can't convert Object into String/)
end
end
@@ -56,7 +62,7 @@ describe :regexp_new_string, shared: true do
end
it "raises a RegexpError when passed an incorrect regexp" do
- -> { Regexp.send(@method, "^[$", 0) }.should raise_error(RegexpError, Regexp.new(Regexp.escape("premature end of char-class: /^[$/")))
+ -> { Regexp.send(@method, "^[$", 0) }.should.raise(RegexpError, Regexp.new(Regexp.escape("premature end of char-class: /^[$/")))
end
it "does not set Regexp options if only given one argument" do
@@ -123,349 +129,100 @@ describe :regexp_new_string, shared: true do
(r.options & Regexp::EXTENDED).should_not == 0
end
- ruby_version_is ""..."3.2" do
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
+ it "does not try to convert the second argument to Integer with #to_int method call" do
+ ScratchPad.clear
+ obj = Object.new
+ def obj.to_int() ScratchPad.record(:called) end
+ -> {
Regexp.send(@method, "Hi", obj)
+ }.should complain(/expected true or false as ignorecase/, {verbose: true})
- ScratchPad.recorded.should == nil
- end
- end
-
- ruby_version_is "3.2" do
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
-
- -> {
- Regexp.send(@method, "Hi", obj)
- }.should complain(/expected true or false as ignorecase/, {verbose: true})
-
- ScratchPad.recorded.should == nil
- end
+ ScratchPad.recorded.should == nil
end
- ruby_version_is ""..."3.2" do
- it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do
+ it "warns any non-Integer, non-nil, non-false second argument" do
+ r = nil
+ -> {
r = Regexp.send(@method, 'Hi', Object.new)
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "warns any non-Integer, non-nil, non-false second argument" do
- r = nil
- -> {
- r = Regexp.send(@method, 'Hi', Object.new)
- }.should complain(/expected true or false as ignorecase/, {verbose: true})
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
- end
-
- it "accepts a String of supported flags as the second argument" do
- r = Regexp.send(@method, 'Hi', 'i')
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
-
- r = Regexp.send(@method, 'Hi', 'imx')
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should_not == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should_not == 0
- end
-
- r = Regexp.send(@method, 'Hi', 'mimi')
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should_not == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
-
- r = Regexp.send(@method, 'Hi', '')
- (r.options & Regexp::IGNORECASE).should == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
- end
-
- it "raises an Argument error if the second argument contains unsupported chars" do
- -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e")
- -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n")
- -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s")
- -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u")
- -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j")
- -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/)
+ }.should complain(/expected true or false as ignorecase/, {verbose: true})
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
end
- ruby_version_is ""..."3.2" do
- it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
+ it "accepts a String of supported flags as the second argument" do
+ r = Regexp.send(@method, 'Hi', 'i')
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
- it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
+ r = Regexp.send(@method, 'Hi', 'imx')
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should_not == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should_not == 0
end
- it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
+ r = Regexp.send(@method, 'Hi', 'mimi')
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should_not == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
- it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do
- Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII
+ r = Regexp.send(@method, 'Hi', '')
+ (r.options & Regexp::IGNORECASE).should == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
+ end
- it "uses ASCII_8BIT encoding if third argument is 'n' or 'none' (case insensitive) and non-ascii characters" do
- a = "(?:[\x8E\xA1-\xFE])"
- str = "\A(?:#{a}|x*)\z"
-
- Regexp.send(@method, str, nil, 'N').encoding.should == Encoding::BINARY
- Regexp.send(@method, str, nil, 'n').encoding.should == Encoding::BINARY
- Regexp.send(@method, str, nil, 'none').encoding.should == Encoding::BINARY
- Regexp.send(@method, str, nil, 'NONE').encoding.should == Encoding::BINARY
- end
+ it "raises an Argument error if the second argument contains unsupported chars" do
+ -> { Regexp.send(@method, 'Hi', 'e') }.should.raise(ArgumentError, "unknown regexp option: e")
+ -> { Regexp.send(@method, 'Hi', 'n') }.should.raise(ArgumentError, "unknown regexp option: n")
+ -> { Regexp.send(@method, 'Hi', 's') }.should.raise(ArgumentError, "unknown regexp option: s")
+ -> { Regexp.send(@method, 'Hi', 'u') }.should.raise(ArgumentError, "unknown regexp option: u")
+ -> { Regexp.send(@method, 'Hi', 'j') }.should.raise(ArgumentError, "unknown regexp option: j")
+ -> { Regexp.send(@method, 'Hi', 'mjx') }.should.raise(ArgumentError, /unknown regexp option: mjx\b/)
end
describe "with escaped characters" do
it "raises a Regexp error if there is a trailing backslash" do
- -> { Regexp.send(@method, "\\") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("too short escape sequence: /\\/")))
+ -> { Regexp.send(@method, "\\") }.should.raise(RegexpError, Regexp.new(Regexp.escape("too short escape sequence: /\\/")))
end
it "does not raise a Regexp error if there is an escaped trailing backslash" do
- -> { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError)
+ -> { Regexp.send(@method, "\\\\") }.should_not.raise(RegexpError)
end
- it "accepts a backspace followed by a character" do
+ it "accepts a backspace followed by a non-special character" do
Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/
end
- it "accepts a one-digit octal value" do
- Regexp.send(@method, "\0").should == /#{"\x00"}/
- end
-
- it "accepts a two-digit octal value" do
- Regexp.send(@method, "\11").should == /#{"\x09"}/
- end
-
- it "accepts a one-digit hexadecimal value" do
- Regexp.send(@method, "\x9n").should == /#{"\x09n"}/
- end
-
- it "accepts a two-digit hexadecimal value" do
- Regexp.send(@method, "\x23").should == /#{"\x23"}/
- end
-
- it "interprets a digit following a two-digit hexadecimal value as a character" do
- Regexp.send(@method, "\x420").should == /#{"\x420"}/
- end
-
it "raises a RegexpError if \\x is not followed by any hexadecimal digits" do
- -> { Regexp.send(@method, "\\" + "xn") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid hex escape: /\\xn/")))
- end
-
- it "accepts an escaped string interpolation" do
- Regexp.send(@method, "\#{abc}").should == /#{"\#{abc}"}/
- end
-
- it "accepts '\\n'" do
- Regexp.send(@method, "\n").should == /#{"\x0a"}/
- end
-
- it "accepts '\\t'" do
- Regexp.send(@method, "\t").should == /#{"\x09"}/
- end
-
- it "accepts '\\r'" do
- Regexp.send(@method, "\r").should == /#{"\x0d"}/
- end
-
- it "accepts '\\f'" do
- Regexp.send(@method, "\f").should == /#{"\x0c"}/
- end
-
- it "accepts '\\v'" do
- Regexp.send(@method, "\v").should == /#{"\x0b"}/
- end
-
- it "accepts '\\a'" do
- Regexp.send(@method, "\a").should == /#{"\x07"}/
- end
-
- it "accepts '\\e'" do
- Regexp.send(@method, "\e").should == /#{"\x1b"}/
- end
-
- it "accepts '\\C-\\n'" do
- Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/
- end
-
- it "accepts '\\C-\\t'" do
- Regexp.send(@method, "\C-\t").should == /#{"\x09"}/
- end
-
- it "accepts '\\C-\\r'" do
- Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/
- end
-
- it "accepts '\\C-\\f'" do
- Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/
- end
-
- it "accepts '\\C-\\v'" do
- Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/
- end
-
- it "accepts '\\C-\\a'" do
- Regexp.send(@method, "\C-\a").should == /#{"\x07"}/
- end
-
- it "accepts '\\C-\\e'" do
- Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
- end
-
- it "accepts multiple consecutive '\\' characters" do
- Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/
- end
-
- it "accepts characters and escaped octal digits" do
- Regexp.send(@method, "abc\076").should == /#{"abc\x3e"}/
- end
-
- it "accepts escaped octal digits and characters" do
- Regexp.send(@method, "\076abc").should == /#{"\x3eabc"}/
- end
-
- it "accepts characters and escaped hexadecimal digits" do
- Regexp.send(@method, "abc\x42").should == /#{"abc\x42"}/
- end
-
- it "accepts escaped hexadecimal digits and characters" do
- Regexp.send(@method, "\x3eabc").should == /#{"\x3eabc"}/
- end
-
- it "accepts escaped hexadecimal and octal digits" do
- Regexp.send(@method, "\061\x42").should == /#{"\x31\x42"}/
- end
-
- it "accepts \\u{H} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{f}").should == /#{"\x0f"}/
- end
-
- it "accepts \\u{HH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{7f}").should == /#{"\x7f"}/
- end
-
- it "accepts \\u{HHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{07f}").should == /#{"\x7f"}/
- end
-
- it "accepts \\u{HHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{0000}").should == /#{"\x00"}/
- end
-
- it "accepts \\u{HHHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{00001}").should == /#{"\x01"}/
- end
-
- it "accepts \\u{HHHHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{000000}").should == /#{"\x00"}/
- end
-
- it "accepts characters followed by \\u{HHHH}" do
- Regexp.send(@method, "abc\u{3042}").should == /#{"abc\u3042"}/
- end
-
- it "accepts \\u{HHHH} followed by characters" do
- Regexp.send(@method, "\u{3042}abc").should == /#{"\u3042abc"}/
- end
-
- it "accepts escaped hexadecimal digits followed by \\u{HHHH}" do
- Regexp.send(@method, "\x42\u{3042}").should == /#{"\x42\u3042"}/
- end
-
- it "accepts escaped octal digits followed by \\u{HHHH}" do
- Regexp.send(@method, "\056\u{3042}").should == /#{"\x2e\u3042"}/
- end
-
- it "accepts a combination of escaped octal and hexadecimal digits and \\u{HHHH}" do
- Regexp.send(@method, "\056\x42\u{3042}\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
- end
-
- it "accepts \\uHHHH for a single Unicode codepoint" do
- Regexp.send(@method, "\u3042").should == /#{"\u3042"}/
- end
-
- it "accepts characters followed by \\uHHHH" do
- Regexp.send(@method, "abc\u3042").should == /#{"abc\u3042"}/
- end
-
- it "accepts \\uHHHH followed by characters" do
- Regexp.send(@method, "\u3042abc").should == /#{"\u3042abc"}/
- end
-
- it "accepts escaped hexadecimal digits followed by \\uHHHH" do
- Regexp.send(@method, "\x42\u3042").should == /#{"\x42\u3042"}/
- end
-
- it "accepts escaped octal digits followed by \\uHHHH" do
- Regexp.send(@method, "\056\u3042").should == /#{"\x2e\u3042"}/
- end
-
- it "accepts a combination of escaped octal and hexadecimal digits and \\uHHHH" do
- Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
- end
-
- it "accepts a multiple byte character which need not be escaped" do
- Regexp.send(@method, "\").should == /#{""}/
+ -> { Regexp.send(@method, "\\" + "xn") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid hex escape: /\\xn/")))
end
it "raises a RegexpError if less than four digits are given for \\uHHHH" do
- -> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode escape: /\\u304/")))
+ -> { Regexp.send(@method, "\\" + "u304") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid Unicode escape: /\\u304/")))
end
it "raises a RegexpError if the \\u{} escape is empty" do
- -> { Regexp.send(@method, "\\" + "u{}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{}/")))
+ -> { Regexp.send(@method, "\\" + "u{}") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{}/")))
end
it "raises a RegexpError if the \\u{} escape contains non hexadecimal digits" do
- -> { Regexp.send(@method, "\\" + "u{abcX}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{abcX}/")))
+ -> { Regexp.send(@method, "\\" + "u{abcX}") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{abcX}/")))
end
it "raises a RegexpError if more than six hexadecimal digits are given" do
- -> { Regexp.send(@method, "\\" + "u{0ffffff}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode range: /\\u{0ffffff}/")))
+ -> { Regexp.send(@method, "\\" + "u{0ffffff}") }.should.raise(RegexpError, Regexp.new(Regexp.escape("invalid Unicode range: /\\u{0ffffff}/")))
end
it "returns a Regexp with US-ASCII encoding if only 7-bit ASCII characters are present regardless of the input String's encoding" do
@@ -506,69 +263,6 @@ end
describe :regexp_new_string_binary, shared: true do
describe "with escaped characters" do
- it "accepts a three-digit octal value" do
- Regexp.send(@method, "\315").should == /#{"\xcd"}/
- end
-
- it "interprets a digit following a three-digit octal value as a character" do
- Regexp.send(@method, "\3762").should == /#{"\xfe2"}/
- end
-
- it "accepts '\\M-\\n'" do
- Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
- end
-
- it "accepts '\\M-\\t'" do
- Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
- end
-
- it "accepts '\\M-\\r'" do
- Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
- end
-
- it "accepts '\\M-\\f'" do
- Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
- end
-
- it "accepts '\\M-\\v'" do
- Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
- end
-
- it "accepts '\\M-\\a'" do
- Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
- end
-
- it "accepts '\\M-\\e'" do
- Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
- end
-
- it "accepts '\\M-\\C-\\n'" do
- Regexp.send(@method, "\M-\C-\n").should == /#{"\x8a"}/
- end
-
- it "accepts '\\M-\\C-\\t'" do
- Regexp.send(@method, "\M-\C-\t").should == /#{"\x89"}/
- end
-
- it "accepts '\\M-\\C-\\r'" do
- Regexp.send(@method, "\M-\C-\r").should == /#{"\x8d"}/
- end
-
- it "accepts '\\M-\\C-\\f'" do
- Regexp.send(@method, "\M-\C-\f").should == /#{"\x8c"}/
- end
-
- it "accepts '\\M-\\C-\\v'" do
- Regexp.send(@method, "\M-\C-\v").should == /#{"\x8b"}/
- end
-
- it "accepts '\\M-\\C-\\a'" do
- Regexp.send(@method, "\M-\C-\a").should == /#{"\x87"}/
- end
-
- it "accepts '\\M-\\C-\\e'" do
- Regexp.send(@method, "\M-\C-\e").should == /#{"\x9b"}/
- end
end
end
@@ -623,11 +317,5 @@ describe :regexp_new_regexp, shared: true do
it "sets the encoding to US-ASCII if the Regexp literal has the 'n' option and the source String is ASCII only" do
Regexp.send(@method, /Hi/n).encoding.should == Encoding::US_ASCII
end
-
- ruby_version_is ''...'3.2' do
- it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do
- Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::BINARY
- end
- end
end
end
diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb
index 48179444f0..083f12d78c 100644
--- a/spec/ruby/core/regexp/shared/quote.rb
+++ b/spec/ruby/core/regexp/shared/quote.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :regexp_quote, shared: true do
it "escapes any characters with special meaning in a regular expression" do
@@ -29,13 +29,13 @@ describe :regexp_quote, shared: true do
it "sets the encoding of the result to the encoding of the String if any non-US-ASCII characters are present in an input String with valid encoding" do
str = "ありがとう".dup.force_encoding("utf-8")
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
Regexp.send(@method, str).encoding.should == Encoding::UTF_8
end
it "sets the encoding of the result to BINARY if any non-US-ASCII characters are present in an input String with invalid encoding" do
str = "\xff".dup.force_encoding "us-ascii"
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
Regexp.send(@method, "\xff").encoding.should == Encoding::BINARY
end
end
diff --git a/spec/ruby/core/regexp/source_spec.rb b/spec/ruby/core/regexp/source_spec.rb
index 5f253da9ea..4eebf280f0 100644
--- a/spec/ruby/core/regexp/source_spec.rb
+++ b/spec/ruby/core/regexp/source_spec.rb
@@ -34,14 +34,14 @@ describe "Regexp#source" do
not_supported_on :opal do
it "has US-ASCII encoding when created from an ASCII-only \\u{} literal" do
re = /[\u{20}-\u{7E}]/
- re.source.encoding.should equal(Encoding::US_ASCII)
+ re.source.encoding.should.equal?(Encoding::US_ASCII)
end
end
not_supported_on :opal do
it "has UTF-8 encoding when created from a non-ASCII-only \\u{} literal" do
re = /[\u{20}-\u{7EE}]/
- re.source.encoding.should equal(Encoding::UTF_8)
+ re.source.encoding.should.equal?(Encoding::UTF_8)
end
end
end
diff --git a/spec/ruby/core/regexp/timeout_spec.rb b/spec/ruby/core/regexp/timeout_spec.rb
index 6fce261814..a1ec475ef3 100644
--- a/spec/ruby/core/regexp/timeout_spec.rb
+++ b/spec/ruby/core/regexp/timeout_spec.rb
@@ -1,35 +1,33 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Regexp.timeout" do
- after :each do
- Regexp.timeout = nil
- end
+describe "Regexp.timeout" do
+ after :each do
+ Regexp.timeout = nil
+ end
- it "returns global timeout" do
- Regexp.timeout = 3
- Regexp.timeout.should == 3
- end
+ it "returns global timeout" do
+ Regexp.timeout = 3
+ Regexp.timeout.should == 3
+ end
- it "raises Regexp::TimeoutError after global timeout elapsed" do
- Regexp.timeout = 0.001
- Regexp.timeout.should == 0.001
+ it "raises Regexp::TimeoutError after global timeout elapsed" do
+ Regexp.timeout = 0.001
+ Regexp.timeout.should == 0.001
- -> {
- # A typical ReDoS case
- /^(a*)*$/ =~ "a" * 1000000 + "x"
- }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
- end
+ -> {
+ # A typical ReDoS case
+ /^(a*)*$/ =~ "a" * 1000000 + "x"
+ }.should.raise(Regexp::TimeoutError, "regexp match timeout")
+ end
- it "raises Regexp::TimeoutError after timeout keyword value elapsed" do
- Regexp.timeout = 3 # This should be ignored
- Regexp.timeout.should == 3
+ it "raises Regexp::TimeoutError after timeout keyword value elapsed" do
+ Regexp.timeout = 3 # This should be ignored
+ Regexp.timeout.should == 3
- re = Regexp.new("^a*b?a*$", timeout: 0.001)
+ re = Regexp.new("^a*b?a*$", timeout: 0.001)
- -> {
- re =~ "a" * 1000000 + "x"
- }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
- end
+ -> {
+ re =~ "a" * 1000000 + "x"
+ }.should.raise(Regexp::TimeoutError, "regexp match timeout")
end
end
diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb
index e775dbe971..da5e10adce 100644
--- a/spec/ruby/core/regexp/try_convert_spec.rb
+++ b/spec/ruby/core/regexp/try_convert_spec.rb
@@ -9,7 +9,7 @@ describe "Regexp.try_convert" do
it "returns nil if given an argument that can't be converted to a Regexp" do
['', 'glark', [], Object.new, :pat].each do |arg|
- Regexp.try_convert(arg).should be_nil
+ Regexp.try_convert(arg).should == nil
end
end
@@ -22,6 +22,6 @@ describe "Regexp.try_convert" do
it "raises a TypeError if the object does not return an Regexp from #to_regexp" do
obj = mock("regexp")
obj.should_receive(:to_regexp).and_return("string")
- -> { Regexp.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to Regexp (MockObject#to_regexp gives String)")
+ -> { Regexp.try_convert(obj) }.should raise_consistent_error(TypeError, "can't convert MockObject into Regexp (MockObject#to_regexp gives String)")
end
end
diff --git a/spec/ruby/core/regexp/union_spec.rb b/spec/ruby/core/regexp/union_spec.rb
index ea5a5053f7..c0a9d12fed 100644
--- a/spec/ruby/core/regexp/union_spec.rb
+++ b/spec/ruby/core/regexp/union_spec.rb
@@ -75,83 +75,83 @@ describe "Regexp.union" do
it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Strings" do
-> {
Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-16BE"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
end
it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Regexps" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")),
Regexp.new("b".encode("UTF-16BE")))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
end
it "raises ArgumentError if the arguments include conflicting fixed encoding Regexps" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING),
Regexp.new("b".encode("US-ASCII"), Regexp::FIXEDENCODING))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and US-ASCII')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-8 and US-ASCII')
end
it "raises ArgumentError if the arguments include a fixed encoding Regexp and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING),
"\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and ISO-8859-1')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-8 and ISO-8859-1')
end
it "raises ArgumentError if the arguments include a String containing non-ASCII-compatible characters and a fixed encoding Regexp in a different encoding" do
-> {
Regexp.union("\u00A9".encode("ISO-8859-1"),
Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING))
- }.should raise_error(ArgumentError, 'incompatible encodings: ISO-8859-1 and UTF-8')
+ }.should.raise(ArgumentError, 'incompatible encodings: ISO-8859-1 and UTF-8')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only String" do
-> {
Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-8"))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should.raise(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only String" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), "b".encode("UTF-8"))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should.raise(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only Regexp" do
-> {
Regexp.union("a".encode("UTF-16LE"), Regexp.new("b".encode("UTF-8")))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should.raise(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only Regexp" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("b".encode("UTF-8")))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should.raise(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union("a".encode("UTF-16LE"), "\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), "\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and a Regexp containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union("a".encode("UTF-16LE"), Regexp.new("\u00A9".encode("ISO-8859-1")))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a Regexp containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("\u00A9".encode("ISO-8859-1")))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should.raise(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "uses to_str to convert arguments (if not Regexp)" do
@@ -177,6 +177,6 @@ describe "Regexp.union" do
end
-> {
Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])
- }.should raise_error(TypeError, 'no implicit conversion of Array into String')
+ }.should.raise(TypeError, 'no implicit conversion of Array into String')
end
end
diff --git a/spec/ruby/core/set/add_spec.rb b/spec/ruby/core/set/add_spec.rb
new file mode 100644
index 0000000000..1ce03b1eab
--- /dev/null
+++ b/spec/ruby/core/set/add_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../spec_helper'
+require_relative 'shared/add'
+
+describe "Set#add" do
+ it_behaves_like :set_add, :add
+end
+
+describe "Set#add?" do
+ before :each do
+ @set = Set.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.add?("cat")
+ @set.should.include?("cat")
+ end
+
+ it "returns self when the Object has not yet been added to self" do
+ @set.add?("cat").should.equal?(@set)
+ end
+
+ it "returns nil when the Object has already been added to self" do
+ @set.add?("cat")
+ @set.add?("cat").should == nil
+ end
+
+ it "raises RuntimeError when called during iteration" do
+ set = Set[:a, :b, :c, :d, :e, :f]
+ set.each do |_m|
+ -> { set << 1 }.should.raise(RuntimeError, /iteration/)
+ end
+ set.should == Set[:a, :b, :c, :d, :e, :f]
+ end
+end
diff --git a/spec/ruby/core/set/append_spec.rb b/spec/ruby/core/set/append_spec.rb
new file mode 100644
index 0000000000..82d34d9130
--- /dev/null
+++ b/spec/ruby/core/set/append_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/add'
+
+describe "Set#<<" do
+ it_behaves_like :set_add, :<<
+end
diff --git a/spec/ruby/core/set/case_compare_spec.rb b/spec/ruby/core/set/case_compare_spec.rb
new file mode 100644
index 0000000000..3781b1b963
--- /dev/null
+++ b/spec/ruby/core/set/case_compare_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#===" do
+ it_behaves_like :set_include, :===
+
+ it "is an alias for include?" do
+ set = Set.new
+ set.method(:===).should == set.method(:include?)
+ end
+end
diff --git a/spec/ruby/core/set/case_equality_spec.rb b/spec/ruby/core/set/case_equality_spec.rb
new file mode 100644
index 0000000000..19c1fb6b9c
--- /dev/null
+++ b/spec/ruby/core/set/case_equality_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#===" do
+ it_behaves_like :set_include, :===
+end
diff --git a/spec/ruby/core/set/classify_spec.rb b/spec/ruby/core/set/classify_spec.rb
new file mode 100644
index 0000000000..a225ab7cbb
--- /dev/null
+++ b/spec/ruby/core/set/classify_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Set#classify" do
+ before :each do
+ @set = Set["one", "two", "three", "four"]
+ end
+
+ it "yields each Object in self" do
+ res = []
+ @set.classify { |x| res << x }
+ res.sort.should == ["one", "two", "three", "four"].sort
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.classify
+ enum.should.instance_of?(Enumerator)
+
+ classified = enum.each { |x| x.length }
+ classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
+ end
+
+ it "classifies the Objects in self based on the block's return value" do
+ classified = @set.classify { |x| x.length }
+ classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
+ end
+end
diff --git a/spec/ruby/core/set/clear_spec.rb b/spec/ruby/core/set/clear_spec.rb
new file mode 100644
index 0000000000..c61a0d78f2
--- /dev/null
+++ b/spec/ruby/core/set/clear_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+
+describe "Set#clear" do
+ before :each do
+ @set = Set["one", "two", "three", "four"]
+ end
+
+ it "removes all elements from self" do
+ @set.clear
+ @set.should.empty?
+ end
+
+ it "returns self" do
+ @set.clear.should.equal?(@set)
+ end
+end
diff --git a/spec/ruby/core/set/collect_spec.rb b/spec/ruby/core/set/collect_spec.rb
new file mode 100644
index 0000000000..d186f1a0d9
--- /dev/null
+++ b/spec/ruby/core/set/collect_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/collect'
+
+describe "Set#collect!" do
+ it_behaves_like :set_collect_bang, :collect!
+end
diff --git a/spec/ruby/core/set/compare_by_identity_spec.rb b/spec/ruby/core/set/compare_by_identity_spec.rb
new file mode 100644
index 0000000000..458e760da0
--- /dev/null
+++ b/spec/ruby/core/set/compare_by_identity_spec.rb
@@ -0,0 +1,153 @@
+require_relative '../../spec_helper'
+
+describe "Set#compare_by_identity" do
+ it "compares its members by identity" do
+ a = "a"
+ b1 = "b"
+ b2 = b1.dup
+
+ set = Set.new
+ set.compare_by_identity
+ set.merge([a, a, b1, b2])
+ set.to_a.sort.should == [a, b1, b2].sort
+ end
+
+ it "causes future comparisons on the receiver to be made by identity" do
+ elt = [1]
+ set = Set.new
+ set << elt
+ set.member?(elt.dup).should == true
+ set.compare_by_identity
+ set.member?(elt.dup).should == false
+ end
+
+ it "rehashes internally so that old members can be looked up" do
+ set = Set.new
+ (1..10).each { |k| set << k }
+ o = Object.new
+ def o.hash; 123; end
+ set << o
+ set.compare_by_identity
+ set.member?(o).should == true
+ end
+
+ it "returns self" do
+ set = Set.new
+ result = set.compare_by_identity
+ result.should.equal?(set)
+ end
+
+ it "is idempotent and has no effect on an already compare_by_identity set" do
+ set = Set.new.compare_by_identity
+ set << :foo
+ set.compare_by_identity.should.equal?(set)
+ set.should.compare_by_identity?
+ set.to_a.should == [:foo]
+ end
+
+ it "uses the semantics of BasicObject#equal? to determine members identity" do
+ :a.equal?(:a).should == true
+ Set.new.compare_by_identity.merge([:a, :a]).to_a.should == [:a]
+
+ ary1 = [1]
+ ary2 = [1]
+ ary1.equal?(ary2).should == false
+ Set.new.compare_by_identity.merge([ary1, ary2]).to_a.sort.should == [ary1, ary2].sort
+ end
+
+ it "uses #equal? semantics, but doesn't actually call #equal? to determine identity" do
+ set = Set.new.compare_by_identity
+ obj = mock("equal")
+ obj.should_not_receive(:equal?)
+ set << :foo
+ set << obj
+ set.to_a.should == [:foo, obj]
+ end
+
+ it "does not call #hash on members" do
+ elt = mock("element")
+ elt.should_not_receive(:hash)
+ set = Set.new.compare_by_identity
+ set << elt
+ set.member?(elt).should == true
+ end
+
+ it "regards #dup'd objects as having different identities" do
+ a1 = "a"
+ a2 = a1.dup
+
+ set = Set.new.compare_by_identity
+ set.merge([a1, a2])
+ set.to_a.sort.should == [a1, a2].sort
+ end
+
+ it "regards #clone'd objects as having different identities" do
+ a1 = "a"
+ a2 = a1.clone
+
+ set = Set.new.compare_by_identity
+ set.merge([a1, a2])
+ set.to_a.sort.should == [a1, a2].sort
+ end
+
+ ruby_version_is "4.0" do
+ it "raises a FrozenError on frozen sets" do
+ set = Set.new.freeze
+ -> {
+ set.compare_by_identity
+ }.should.raise(FrozenError, /can't modify frozen Set: (#<)?Set(\[|: {)[\]}]>?/)
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "raises a FrozenError on frozen sets" do
+ set = Set.new.freeze
+ -> {
+ set.compare_by_identity
+ }.should.raise(FrozenError, /frozen Hash/)
+ end
+ end
+
+ it "persists over #dups" do
+ set = Set.new.compare_by_identity
+ set << :a
+ set_dup = set.dup
+ set_dup.should == set
+ set_dup << :a
+ set_dup.to_a.should == [:a]
+ end
+
+ it "persists over #clones" do
+ set = Set.new.compare_by_identity
+ set << :a
+ set_clone = set.clone
+ set_clone.should == set
+ set_clone << :a
+ set_clone.to_a.should == [:a]
+ end
+
+ it "is not equal to set what does not compare by identity" do
+ Set.new([1, 2]).should == Set.new([1, 2])
+ Set.new([1, 2]).should_not == Set.new([1, 2]).compare_by_identity
+ end
+end
+
+describe "Set#compare_by_identity?" do
+ it "returns false by default" do
+ Set.new.should_not.compare_by_identity?
+ end
+
+ it "returns true once #compare_by_identity has been invoked on self" do
+ set = Set.new
+ set.compare_by_identity
+ set.should.compare_by_identity?
+ end
+
+ it "returns true when called multiple times on the same set" do
+ set = Set.new
+ set.compare_by_identity
+ set.should.compare_by_identity?
+ set.should.compare_by_identity?
+ set.should.compare_by_identity?
+ end
+end
diff --git a/spec/ruby/core/set/comparison_spec.rb b/spec/ruby/core/set/comparison_spec.rb
new file mode 100644
index 0000000000..eb18a198e5
--- /dev/null
+++ b/spec/ruby/core/set/comparison_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Set#<=>" do
+ it "returns 0 if the sets are equal" do
+ (Set[] <=> Set[]).should == 0
+ (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
+ end
+
+ it "returns -1 if the set is a proper subset of the other set" do
+ (Set[] <=> Set[1]).should == -1
+ (Set[1, 2] <=> Set[1, 2, 3]).should == -1
+ end
+
+ it "returns +1 if the set is a proper superset of other set" do
+ (Set[1] <=> Set[]).should == +1
+ (Set[1, 2, 3] <=> Set[1, 2]).should == +1
+ end
+
+ it "returns nil if the set has unique elements" do
+ (Set[1, 2, 3] <=> Set[:a, :b, :c]).should == nil
+ end
+
+ it "returns nil when the argument is not set-like" do
+ (Set[] <=> false).should == nil
+ end
+end
diff --git a/spec/ruby/core/set/constructor_spec.rb b/spec/ruby/core/set/constructor_spec.rb
new file mode 100644
index 0000000000..11138f3a5b
--- /dev/null
+++ b/spec/ruby/core/set/constructor_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "Set[]" do
+ it "returns a new Set populated with the passed Objects" do
+ set = Set[1, 2, 3]
+
+ set.instance_of?(Set).should == true
+ set.size.should.eql?(3)
+
+ set.should.include?(1)
+ set.should.include?(2)
+ set.should.include?(3)
+ end
+end
diff --git a/spec/ruby/core/set/delete_if_spec.rb b/spec/ruby/core/set/delete_if_spec.rb
new file mode 100644
index 0000000000..b231dff50d
--- /dev/null
+++ b/spec/ruby/core/set/delete_if_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+
+describe "Set#delete_if" do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.delete_if { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "deletes every element from self for which the passed block returns true" do
+ @set.delete_if { |x| x.size == 3 }
+ @set.size.should.eql?(1)
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+
+ it "returns self" do
+ @set.delete_if { |x| x }.should.equal?(@set)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.delete_if
+ enum.should.instance_of?(Enumerator)
+
+ enum.each { |x| x.size == 3 }
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+end
diff --git a/spec/ruby/core/set/delete_spec.rb b/spec/ruby/core/set/delete_spec.rb
new file mode 100644
index 0000000000..cdc6dd7b36
--- /dev/null
+++ b/spec/ruby/core/set/delete_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../spec_helper'
+
+describe "Set#delete" do
+ before :each do
+ @set = Set["a", "b", "c"]
+ end
+
+ it "deletes the passed Object from self" do
+ @set.delete("a")
+ @set.should_not.include?("a")
+ end
+
+ it "returns self" do
+ @set.delete("a").should.equal?(@set)
+ @set.delete("x").should.equal?(@set)
+ end
+end
+
+describe "Set#delete?" do
+ before :each do
+ @set = Set["a", "b", "c"]
+ end
+
+ it "deletes the passed Object from self" do
+ @set.delete?("a")
+ @set.should_not.include?("a")
+ end
+
+ it "returns self when the passed Object is in self" do
+ @set.delete?("a").should.equal?(@set)
+ end
+
+ it "returns nil when the passed Object is not in self" do
+ @set.delete?("x").should == nil
+ end
+end
diff --git a/spec/ruby/core/set/difference_spec.rb b/spec/ruby/core/set/difference_spec.rb
new file mode 100644
index 0000000000..149f946592
--- /dev/null
+++ b/spec/ruby/core/set/difference_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/difference'
+
+describe "Set#difference" do
+ it_behaves_like :set_difference, :difference
+end
diff --git a/spec/ruby/core/set/disjoint_spec.rb b/spec/ruby/core/set/disjoint_spec.rb
new file mode 100644
index 0000000000..d415c21045
--- /dev/null
+++ b/spec/ruby/core/set/disjoint_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#disjoint?" do
+ it "returns false when two Sets have at least one element in common" do
+ Set[1, 2].disjoint?(Set[2, 3]).should == false
+ end
+
+ it "returns true when two Sets have no element in common" do
+ Set[1, 2].disjoint?(Set[3, 4]).should == true
+ end
+
+ context "when comparing to a Set-like object" do
+ it "returns false when a Set has at least one element in common with a Set-like object" do
+ Set[1, 2].disjoint?(SetSpecs::SetLike.new([2, 3])).should == false
+ end
+
+ it "returns true when a Set has no element in common with a Set-like object" do
+ Set[1, 2].disjoint?(SetSpecs::SetLike.new([3, 4])).should == true
+ end
+ end
+end
diff --git a/spec/ruby/core/set/divide_spec.rb b/spec/ruby/core/set/divide_spec.rb
new file mode 100644
index 0000000000..409a22df75
--- /dev/null
+++ b/spec/ruby/core/set/divide_spec.rb
@@ -0,0 +1,68 @@
+require_relative '../../spec_helper'
+
+describe "Set#divide" do
+ it "divides self into a set of subsets based on the blocks return values" do
+ set = Set["one", "two", "three", "four", "five"].divide { |x| x.length }
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+
+ it "yields each Object to the block" do
+ ret = []
+ Set["one", "two", "three", "four", "five"].divide { |x| ret << x }
+ ret.sort.should == ["five", "four", "one", "three", "two"]
+ end
+
+ it "returns an enumerator when not passed a block" do
+ ret = Set[1, 2, 3, 4].divide
+ ret.should.is_a?(Enumerator)
+ ret.each(&:even?).should == Set[Set[1, 3], Set[2, 4]]
+ end
+end
+
+describe "Set#divide when passed a block with an arity of 2" do
+ it "divides self into a set of subsets based on the blocks return values" do
+ set = Set[1, 3, 4, 6, 9, 10, 11].divide { |x, y| (x - y).abs == 1 }
+ set.map{ |x| x.to_a.sort }.sort.should == [[1], [3, 4], [6], [9, 10, 11]]
+ end
+
+ ruby_version_is "4.0" do
+ it "yields each two Object to the block" do
+ ret = []
+ Set[1, 2].divide { |x, y| ret << [x, y] }
+ ret.sort.should == [[1, 2], [2, 1]]
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "yields each two Object to the block" do
+ ret = []
+ Set[1, 2].divide { |x, y| ret << [x, y] }
+ ret.sort.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
+ end
+ end
+
+ it "returns an enumerator when not passed a block" do
+ ret = Set[1, 2, 3, 4].divide
+ ret.should.is_a?(Enumerator)
+ ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]]
+ end
+end
+
+describe "Set#divide when passed a block with an arity of > 2" do
+ it "only uses the first element if the arity > 2" do
+ set = Set["one", "two", "three", "four", "five"].divide do |x, y, z|
+ y.should == nil
+ z.should == nil
+ x.length
+ end
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+
+ it "only uses the first element if the arity = -1" do
+ set = Set["one", "two", "three", "four", "five"].divide do |*xs|
+ xs.size.should == 1
+ xs.first.length
+ end
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+end
diff --git a/spec/ruby/core/set/each_spec.rb b/spec/ruby/core/set/each_spec.rb
new file mode 100644
index 0000000000..bdafc99571
--- /dev/null
+++ b/spec/ruby/core/set/each_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Set#each" do
+ before :each do
+ @set = Set[1, 2, 3]
+ end
+
+ it "yields each Object in self" do
+ ret = []
+ @set.each { |x| ret << x }
+ ret.sort.should == [1, 2, 3]
+ end
+
+ it "returns self" do
+ @set.each { |x| x }.should.equal?(@set)
+ end
+
+ it "returns an Enumerator when not passed a block" do
+ enum = @set.each
+ enum.should.instance_of?(Enumerator)
+
+ ret = []
+ enum.each { |x| ret << x }
+ ret.sort.should == [1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/empty_spec.rb b/spec/ruby/core/set/empty_spec.rb
new file mode 100644
index 0000000000..c71f2ce18d
--- /dev/null
+++ b/spec/ruby/core/set/empty_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../spec_helper'
+
+describe "Set#empty?" do
+ it "returns true if self is empty" do
+ Set[].empty?.should == true
+ Set[1].empty?.should == false
+ Set[1,2,3].empty?.should == false
+ end
+end
diff --git a/spec/ruby/core/set/enumerable/to_set_spec.rb b/spec/ruby/core/set/enumerable/to_set_spec.rb
new file mode 100644
index 0000000000..f139e1c025
--- /dev/null
+++ b/spec/ruby/core/set/enumerable/to_set_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+
+describe "Enumerable#to_set" do
+ it "returns a new Set created from self" do
+ [1, 2, 3].to_set.should == Set[1, 2, 3]
+ {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
+ end
+
+ it "passes down passed blocks" do
+ [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+end
diff --git a/spec/ruby/core/set/eql_spec.rb b/spec/ruby/core/set/eql_spec.rb
new file mode 100644
index 0000000000..6862ed4eda
--- /dev/null
+++ b/spec/ruby/core/set/eql_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "Set#eql?" do
+ it "returns true when the passed argument is a Set and contains the same elements" do
+ Set[].should.eql?(Set[])
+ Set[1, 2, 3].should.eql?(Set[1, 2, 3])
+ Set[1, 2, 3].should.eql?(Set[3, 2, 1])
+ Set["a", :b, ?c].should.eql?(Set[?c, :b, "a"])
+
+ Set[1, 2, 3].should_not.eql?(Set[1.0, 2, 3])
+ Set[1, 2, 3].should_not.eql?(Set[2, 3])
+ Set[1, 2, 3].should_not.eql?(Set[])
+ end
+end
diff --git a/spec/ruby/core/set/equal_value_spec.rb b/spec/ruby/core/set/equal_value_spec.rb
new file mode 100644
index 0000000000..721a79a3f1
--- /dev/null
+++ b/spec/ruby/core/set/equal_value_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#==" do
+ it "returns true when the passed Object is a Set and self and the Object contain the same elements" do
+ Set[].should == Set[]
+ Set[1, 2, 3].should == Set[1, 2, 3]
+ Set["1", "2", "3"].should == Set["1", "2", "3"]
+
+ Set[1, 2, 3].should_not == Set[1.0, 2, 3]
+ Set[1, 2, 3].should_not == [1, 2, 3]
+ end
+
+ it "does not depend on the order of the elements" do
+ Set[1, 2, 3].should == Set[3, 2, 1]
+ Set[:a, "b", ?c].should == Set[?c, "b", :a]
+ end
+
+ it "does not depend on the order of nested Sets" do
+ Set[Set[1], Set[2], Set[3]].should == Set[Set[3], Set[2], Set[1]]
+
+ set1 = Set[Set["a", "b"], Set["c", "d"], Set["e", "f"]]
+ set2 = Set[Set["c", "d"], Set["a", "b"], Set["e", "f"]]
+ set1.should == set2
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true when a Set and a Set-like object contain the same elements" do
+ Set[1, 2, 3].should == SetSpecs::SetLike.new([1, 2, 3])
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/exclusion_spec.rb b/spec/ruby/core/set/exclusion_spec.rb
new file mode 100644
index 0000000000..52ee34fe78
--- /dev/null
+++ b/spec/ruby/core/set/exclusion_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../spec_helper'
+
+describe "Set#^" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns a new Set containing elements that are not in both self and the passed Enumerable" do
+ (@set ^ Set[3, 4, 5]).should == Set[1, 2, 5]
+ (@set ^ [3, 4, 5]).should == Set[1, 2, 5]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set ^ 3 }.should.raise(ArgumentError)
+ -> { @set ^ Object.new }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/set/filter_spec.rb b/spec/ruby/core/set/filter_spec.rb
index 779254ad68..779254ad68 100644
--- a/spec/ruby/library/set/filter_spec.rb
+++ b/spec/ruby/core/set/filter_spec.rb
diff --git a/spec/ruby/core/set/fixtures/set_like.rb b/spec/ruby/core/set/fixtures/set_like.rb
new file mode 100644
index 0000000000..86dec2ed52
--- /dev/null
+++ b/spec/ruby/core/set/fixtures/set_like.rb
@@ -0,0 +1,30 @@
+
+module SetSpecs
+ # This class is used to test the interaction of "Set-like" objects with real Sets
+ #
+ # These "Set-like" objects reply to is_a?(Set) with true and thus real Set objects are able to transparently
+ # interoperate with them in a duck-typing manner.
+ class SetLike
+ include Enumerable
+
+ def is_a?(klass)
+ super || klass == ::Set
+ end
+
+ def initialize(entries)
+ @entries = entries
+ end
+
+ def each(&block)
+ @entries.each(&block)
+ end
+
+ def inspect
+ "#<#{self.class}: {#{map(&:inspect).join(", ")}}>"
+ end
+
+ def size
+ @entries.size
+ end
+ end
+end
diff --git a/spec/ruby/core/set/flatten_merge_spec.rb b/spec/ruby/core/set/flatten_merge_spec.rb
new file mode 100644
index 0000000000..3904d969ae
--- /dev/null
+++ b/spec/ruby/core/set/flatten_merge_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+
+describe "Set#flatten_merge" do
+ ruby_version_is ""..."4.0" do
+ it "is protected" do
+ Set.protected_instance_methods(false).should.include?(:flatten_merge)
+ end
+
+ it "flattens the passed Set and merges it into self" do
+ set1 = Set[1, 2]
+ set2 = Set[3, 4, Set[5, 6]]
+
+ set1.send(:flatten_merge, set2).should == Set[1, 2, 3, 4, 5, 6]
+ end
+
+ it "raises an ArgumentError when trying to flatten a recursive Set" do
+ set1 = Set[1, 2, 3]
+ set2 = Set[5, 6, 7]
+ set2 << set2
+
+ -> { set1.send(:flatten_merge, set2) }.should.raise(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/core/set/flatten_spec.rb b/spec/ruby/core/set/flatten_spec.rb
new file mode 100644
index 0000000000..ca6323fac8
--- /dev/null
+++ b/spec/ruby/core/set/flatten_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
+
+describe "Set#flatten" do
+ it "returns a copy of self with each included Set flattened" do
+ set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
+ flattened_set = set.flatten
+
+ flattened_set.should_not.equal?(set)
+ flattened_set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ end
+
+ it "raises an ArgumentError when self is recursive" do
+ (set = Set[]) << set
+ -> { set.flatten }.should.raise(ArgumentError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when Set contains a Set-like object" do
+ it "returns a copy of self with each included Set-like object flattened" do
+ Set[SetSpecs::SetLike.new([1])].flatten.should == Set[1]
+ end
+ end
+ end
+end
+
+describe "Set#flatten!" do
+ it "flattens self" do
+ set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
+ set.flatten!
+ set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ end
+
+ it "returns self when self was modified" do
+ set = Set[1, 2, Set[3, 4]]
+ set.flatten!.should.equal?(set)
+ end
+
+ it "returns nil when self was not modified" do
+ set = Set[1, 2, 3, 4]
+ set.flatten!.should == nil
+ end
+
+ it "raises an ArgumentError when self is recursive" do
+ (set = Set[]) << set
+ -> { set.flatten! }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/hash_spec.rb b/spec/ruby/core/set/hash_spec.rb
new file mode 100644
index 0000000000..63a0aa66a5
--- /dev/null
+++ b/spec/ruby/core/set/hash_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../spec_helper'
+
+describe "Set#hash" do
+ it "is static" do
+ Set[].hash.should == Set[].hash
+ Set[1, 2, 3].hash.should == Set[1, 2, 3].hash
+ Set[:a, "b", ?c].hash.should == Set[?c, "b", :a].hash
+
+ Set[].hash.should_not == Set[1, 2, 3].hash
+ Set[1, 2, 3].hash.should_not == Set[:a, "b", ?c].hash
+ end
+
+ ruby_version_is ""..."4.0" do
+ # see https://github.com/jruby/jruby/issues/8393
+ it "is equal to nil.hash for an uninitialized Set" do
+ Set.allocate.hash.should == nil.hash
+ end
+ end
+end
diff --git a/spec/ruby/core/set/include_spec.rb b/spec/ruby/core/set/include_spec.rb
new file mode 100644
index 0000000000..dd33bbc3bd
--- /dev/null
+++ b/spec/ruby/core/set/include_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#include?" do
+ it_behaves_like :set_include, :include?
+end
diff --git a/spec/ruby/core/set/initialize_clone_spec.rb b/spec/ruby/core/set/initialize_clone_spec.rb
new file mode 100644
index 0000000000..13abb7ee4e
--- /dev/null
+++ b/spec/ruby/core/set/initialize_clone_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+describe "Set#initialize_clone" do
+ # See https://bugs.ruby-lang.org/issues/14266
+ it "does not freeze the new Set when called from clone(freeze: false)" do
+ set1 = Set[1, 2]
+ set1.freeze
+ set2 = set1.clone(freeze: false)
+ set1.frozen?.should == true
+ set2.frozen?.should == false
+ set2.add 3
+ set1.should == Set[1, 2]
+ set2.should == Set[1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/initialize_spec.rb b/spec/ruby/core/set/initialize_spec.rb
new file mode 100644
index 0000000000..45538b38fb
--- /dev/null
+++ b/spec/ruby/core/set/initialize_spec.rb
@@ -0,0 +1,88 @@
+require_relative '../../spec_helper'
+
+describe "Set#initialize" do
+ it "is private" do
+ Set.private_instance_methods(false).should.include?(:initialize)
+ end
+
+ it "adds all elements of the passed Enumerable to self" do
+ s = Set.new([1, 2, 3])
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(2)
+ s.should.include?(3)
+ end
+
+ it "uses #each_entry on the provided Enumerable" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:each_entry).and_yield(1).and_yield(2).and_yield(3)
+ s = Set.new(enumerable)
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(2)
+ s.should.include?(3)
+ end
+
+ it "uses #each on the provided Enumerable if it does not respond to #each_entry" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
+ s = Set.new(enumerable)
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(2)
+ s.should.include?(3)
+ end
+
+ it "raises if the provided Enumerable does not respond to #each_entry or #each" do
+ enumerable = MockObject.new('mock-enumerable')
+ -> { Set.new(enumerable) }.should.raise(ArgumentError, "value must be enumerable")
+ end
+
+ it "should initialize with empty array and set" do
+ s = Set.new([])
+ s.size.should.eql?(0)
+
+ s = Set.new({})
+ s.size.should.eql?(0)
+ end
+
+ it "preprocesses all elements by a passed block before adding to self" do
+ s = Set.new([1, 2, 3]) { |x| x * x }
+ s.size.should.eql?(3)
+ s.should.include?(1)
+ s.should.include?(4)
+ s.should.include?(9)
+ end
+
+ it "should initialize with empty array and block" do
+ s = Set.new([]) { |x| x * x }
+ s.size.should.eql?(0)
+ end
+
+ it "should initialize with empty set and block" do
+ s = Set.new(Set.new) { |x| x * x }
+ s.size.should.eql?(0)
+ end
+
+ it "should initialize with set" do
+ o = Set.new([1, 2])
+ s = Set.new(o)
+ s.size.should.eql?(2)
+ s.should.include?(1)
+ s.should.include?(2)
+ end
+
+ it "should initialize with set and block" do
+ o = Set.new([1, 2])
+ s = Set.new(o) { |e| e + 2 }
+ s.size.should.eql?(2)
+ s.should.include?(3)
+ s.should.include?(4)
+ end
+
+ it "should initialize with just block" do
+ s = Set.new { |x| x * x }
+ s.size.should.eql?(0)
+ s.should.eql?(Set.new)
+ end
+end
diff --git a/spec/ruby/core/set/inspect_spec.rb b/spec/ruby/core/set/inspect_spec.rb
new file mode 100644
index 0000000000..0dcce83eb6
--- /dev/null
+++ b/spec/ruby/core/set/inspect_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/inspect'
+
+describe "Set#inspect" do
+ it_behaves_like :set_inspect, :inspect
+end
diff --git a/spec/ruby/core/set/intersect_spec.rb b/spec/ruby/core/set/intersect_spec.rb
new file mode 100644
index 0000000000..d04a1af441
--- /dev/null
+++ b/spec/ruby/core/set/intersect_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#intersect?" do
+ it "returns true when two Sets have at least one element in common" do
+ Set[1, 2].intersect?(Set[2, 3]).should == true
+ end
+
+ it "returns false when two Sets have no element in common" do
+ Set[1, 2].intersect?(Set[3, 4]).should == false
+ end
+
+ context "when comparing to a Set-like object" do
+ it "returns true when a Set has at least one element in common with a Set-like object" do
+ Set[1, 2].intersect?(SetSpecs::SetLike.new([2, 3])).should == true
+ end
+
+ it "returns false when a Set has no element in common with a Set-like object" do
+ Set[1, 2].intersect?(SetSpecs::SetLike.new([3, 4])).should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/set/intersection_spec.rb b/spec/ruby/core/set/intersection_spec.rb
new file mode 100644
index 0000000000..136b886775
--- /dev/null
+++ b/spec/ruby/core/set/intersection_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require_relative 'shared/intersection'
+
+describe "Set#intersection" do
+ it_behaves_like :set_intersection, :intersection
+end
+
+describe "Set#&" do
+ it_behaves_like :set_intersection, :&
+end
diff --git a/spec/ruby/core/set/join_spec.rb b/spec/ruby/core/set/join_spec.rb
new file mode 100644
index 0000000000..1c1e8a8af8
--- /dev/null
+++ b/spec/ruby/core/set/join_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../spec_helper'
+
+describe "Set#join" do
+ it "returns an empty string if the Set is empty" do
+ Set[].join.should == ''
+ end
+
+ it "returns a new string formed by joining elements after conversion" do
+ set = Set[:a, :b, :c]
+ set.join.should == "abc"
+ end
+
+ it "does not separate elements when the passed separator is nil" do
+ set = Set[:a, :b, :c]
+ set.join(nil).should == "abc"
+ end
+
+ it "returns a string formed by concatenating each element separated by the separator" do
+ set = Set[:a, :b, :c]
+ set.join(' | ').should == "a | b | c"
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "calls #to_a to convert the Set in to an Array" do
+ set = Set[:a, :b, :c]
+ set.should_receive(:to_a).and_return([:a, :b, :c])
+ set.join.should == "abc"
+ end
+ end
+end
diff --git a/spec/ruby/core/set/keep_if_spec.rb b/spec/ruby/core/set/keep_if_spec.rb
new file mode 100644
index 0000000000..7ca5d0cd43
--- /dev/null
+++ b/spec/ruby/core/set/keep_if_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+
+describe "Set#keep_if" do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.keep_if { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.keep_if { |x| x.size != 3 }
+ @set.size.should.eql?(1)
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+
+ it "returns self" do
+ @set.keep_if {}.should.equal?(@set)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.keep_if
+ enum.should.instance_of?(Enumerator)
+
+ enum.each { |x| x.size != 3 }
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+end
diff --git a/spec/ruby/core/set/length_spec.rb b/spec/ruby/core/set/length_spec.rb
new file mode 100644
index 0000000000..6bb697b4ca
--- /dev/null
+++ b/spec/ruby/core/set/length_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/length'
+
+describe "Set#length" do
+ it_behaves_like :set_length, :length
+end
diff --git a/spec/ruby/core/set/map_spec.rb b/spec/ruby/core/set/map_spec.rb
new file mode 100644
index 0000000000..996191b0a8
--- /dev/null
+++ b/spec/ruby/core/set/map_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/collect'
+
+describe "Set#map!" do
+ it_behaves_like :set_collect_bang, :map!
+end
diff --git a/spec/ruby/core/set/member_spec.rb b/spec/ruby/core/set/member_spec.rb
new file mode 100644
index 0000000000..5c82e8f826
--- /dev/null
+++ b/spec/ruby/core/set/member_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#member?" do
+ it_behaves_like :set_include, :member?
+end
diff --git a/spec/ruby/core/set/merge_spec.rb b/spec/ruby/core/set/merge_spec.rb
new file mode 100644
index 0000000000..a2c1a7e706
--- /dev/null
+++ b/spec/ruby/core/set/merge_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../spec_helper'
+
+describe "Set#merge" do
+ it "adds the elements of the passed Enumerable to self" do
+ Set[:a, :b].merge(Set[:b, :c, :d]).should == Set[:a, :b, :c, :d]
+ Set[1, 2].merge([3, 4]).should == Set[1, 2, 3, 4]
+ end
+
+ it "returns self" do
+ set = Set[1, 2]
+ set.merge([3, 4]).should.equal?(set)
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { Set[1, 2].merge(1) }.should.raise(ArgumentError)
+ -> { Set[1, 2].merge(Object.new) }.should.raise(ArgumentError)
+ end
+
+ it "raises RuntimeError when called during iteration" do
+ set = Set[:a, :b]
+ set.each do |_m|
+ -> { set.merge([1, 2]) }.should.raise(RuntimeError, /iteration/)
+ end
+ end
+
+ it "accepts multiple arguments" do
+ Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
+ end
+end
diff --git a/spec/ruby/core/set/minus_spec.rb b/spec/ruby/core/set/minus_spec.rb
new file mode 100644
index 0000000000..72f98f985e
--- /dev/null
+++ b/spec/ruby/core/set/minus_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/difference'
+
+describe "Set#-" do
+ it_behaves_like :set_difference, :-
+end
diff --git a/spec/ruby/core/set/plus_spec.rb b/spec/ruby/core/set/plus_spec.rb
new file mode 100644
index 0000000000..7e44ff0b7e
--- /dev/null
+++ b/spec/ruby/core/set/plus_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/union'
+
+describe "Set#+" do
+ it_behaves_like :set_union, :+
+end
diff --git a/spec/ruby/core/set/pretty_print_cycle_spec.rb b/spec/ruby/core/set/pretty_print_cycle_spec.rb
new file mode 100644
index 0000000000..7e6017c112
--- /dev/null
+++ b/spec/ruby/core/set/pretty_print_cycle_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "Set#pretty_print_cycle" do
+ it "passes the 'pretty print' representation of a self-referencing Set to the pretty print writer" do
+ pp = mock("PrettyPrint")
+ ruby_version_is(""..."4.0") do
+ pp.should_receive(:text).with("#<Set: {...}>")
+ end
+ ruby_version_is("4.0") do
+ pp.should_receive(:text).with("Set[...]")
+ end
+ Set[1, 2, 3].pretty_print_cycle(pp)
+ end
+end
diff --git a/spec/ruby/core/set/proper_subset_spec.rb b/spec/ruby/core/set/proper_subset_spec.rb
new file mode 100644
index 0000000000..3fd27da131
--- /dev/null
+++ b/spec/ruby/core/set/proper_subset_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
+
+describe "Set#proper_subset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that self is a proper subset of" do
+ Set[].proper_subset?(@set).should == true
+ Set[].proper_subset?(Set[1, 2, 3]).should == true
+ Set[].proper_subset?(Set["a", :b, ?c]).should == true
+
+ Set[1, 2, 3].proper_subset?(@set).should == true
+ Set[1, 3].proper_subset?(@set).should == true
+ Set[1, 2].proper_subset?(@set).should == true
+ Set[1].proper_subset?(@set).should == true
+
+ Set[5].proper_subset?(@set).should == false
+ Set[1, 5].proper_subset?(@set).should == false
+ Set[nil].proper_subset?(@set).should == false
+ Set["test"].proper_subset?(@set).should == false
+
+ @set.proper_subset?(@set).should == false
+ Set[].proper_subset?(Set[]).should == false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].proper_subset?([]) }.should.raise(ArgumentError)
+ -> { Set[].proper_subset?(1) }.should.raise(ArgumentError)
+ -> { Set[].proper_subset?("test") }.should.raise(ArgumentError)
+ -> { Set[].proper_subset?(Object.new) }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/proper_superset_spec.rb b/spec/ruby/core/set/proper_superset_spec.rb
new file mode 100644
index 0000000000..e95c67ef0e
--- /dev/null
+++ b/spec/ruby/core/set/proper_superset_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#proper_superset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that self is a proper superset of" do
+ @set.proper_superset?(Set[]).should == true
+ Set[1, 2, 3].proper_superset?(Set[]).should == true
+ Set["a", :b, ?c].proper_superset?(Set[]).should == true
+
+ @set.proper_superset?(Set[1, 2, 3]).should == true
+ @set.proper_superset?(Set[1, 3]).should == true
+ @set.proper_superset?(Set[1, 2]).should == true
+ @set.proper_superset?(Set[1]).should == true
+
+ @set.proper_superset?(Set[5]).should == false
+ @set.proper_superset?(Set[1, 5]).should == false
+ @set.proper_superset?(Set[nil]).should == false
+ @set.proper_superset?(Set["test"]).should == false
+
+ @set.proper_superset?(@set).should == false
+ Set[].proper_superset?(Set[]).should == false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].proper_superset?([]) }.should.raise(ArgumentError)
+ -> { Set[].proper_superset?(1) }.should.raise(ArgumentError)
+ -> { Set[].proper_superset?("test") }.should.raise(ArgumentError)
+ -> { Set[].proper_superset?(Object.new) }.should.raise(ArgumentError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a proper superset of" do
+ Set[1, 2, 3, 4].proper_superset?(SetSpecs::SetLike.new([1, 2, 3])).should == true
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/reject_spec.rb b/spec/ruby/core/set/reject_spec.rb
new file mode 100644
index 0000000000..b00a36812b
--- /dev/null
+++ b/spec/ruby/core/set/reject_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../spec_helper'
+
+describe "Set#reject!" do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.reject! { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "deletes every element from self for which the passed block returns true" do
+ @set.reject! { |x| x.size == 3 }
+ @set.size.should.eql?(1)
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+
+ it "returns self when self was modified" do
+ @set.reject! { |x| true }.should.equal?(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.reject! { |x| false }.should == nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.reject!
+ enum.should.instance_of?(Enumerator)
+
+ enum.each { |x| x.size == 3 }
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+end
diff --git a/spec/ruby/core/set/replace_spec.rb b/spec/ruby/core/set/replace_spec.rb
new file mode 100644
index 0000000000..2a51a024dc
--- /dev/null
+++ b/spec/ruby/core/set/replace_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+
+describe "Set#replace" do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "replaces the contents with other and returns self" do
+ @set.replace(Set[1, 2, 3]).should == @set
+ @set.should == Set[1, 2, 3]
+ end
+
+ it "raises RuntimeError when called during iteration" do
+ set = Set[:a, :b, :c, :d, :e, :f]
+ set.each do |_m|
+ -> { set.replace(Set[1, 2, 3]) }.should.raise(RuntimeError, /iteration/)
+ end
+ set.should == Set[:a, :b, :c, :d, :e, :f]
+ end
+
+ it "accepts any enumerable as other" do
+ @set.replace([1, 2, 3]).should == Set[1, 2, 3]
+ end
+end
diff --git a/spec/ruby/library/set/select_spec.rb b/spec/ruby/core/set/select_spec.rb
index b458ffacaa..b458ffacaa 100644
--- a/spec/ruby/library/set/select_spec.rb
+++ b/spec/ruby/core/set/select_spec.rb
diff --git a/spec/ruby/core/set/set_spec.rb b/spec/ruby/core/set/set_spec.rb
new file mode 100644
index 0000000000..fd1d2072e3
--- /dev/null
+++ b/spec/ruby/core/set/set_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+
+describe 'Set' do
+ it 'is available without explicit requiring' do
+ output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
+ puts Set.new([1, 2, 3]).to_a.inspect
+ RUBY
+ output.chomp.should == "[1, 2, 3]"
+ end
+end
diff --git a/spec/ruby/core/set/shared/add.rb b/spec/ruby/core/set/shared/add.rb
new file mode 100644
index 0000000000..8d6d83434f
--- /dev/null
+++ b/spec/ruby/core/set/shared/add.rb
@@ -0,0 +1,14 @@
+describe :set_add, shared: true do
+ before :each do
+ @set = Set.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.send(@method, "dog")
+ @set.should.include?("dog")
+ end
+
+ it "returns self" do
+ @set.send(@method, "dog").should.equal?(@set)
+ end
+end
diff --git a/spec/ruby/core/set/shared/collect.rb b/spec/ruby/core/set/shared/collect.rb
new file mode 100644
index 0000000000..ad5c5afa59
--- /dev/null
+++ b/spec/ruby/core/set/shared/collect.rb
@@ -0,0 +1,20 @@
+describe :set_collect_bang, shared: true do
+ before :each do
+ @set = Set[1, 2, 3, 4, 5]
+ end
+
+ it "yields each Object in self" do
+ res = []
+ @set.send(@method) { |x| res << x }
+ res.sort.should == [1, 2, 3, 4, 5].sort
+ end
+
+ it "returns self" do
+ @set.send(@method) { |x| x }.should.equal?(@set)
+ end
+
+ it "replaces self with the return values of the block" do
+ @set.send(@method) { |x| x * 2 }
+ @set.should == Set[2, 4, 6, 8, 10]
+ end
+end
diff --git a/spec/ruby/core/set/shared/difference.rb b/spec/ruby/core/set/shared/difference.rb
new file mode 100644
index 0000000000..8a17056a82
--- /dev/null
+++ b/spec/ruby/core/set/shared/difference.rb
@@ -0,0 +1,15 @@
+describe :set_difference, shared: true do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing self's elements excluding the elements in the passed Enumerable" do
+ @set.send(@method, Set[:a, :b]).should == Set[:c]
+ @set.send(@method, [:b, :c]).should == Set[:a]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should.raise(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/shared/include.rb b/spec/ruby/core/set/shared/include.rb
new file mode 100644
index 0000000000..82755ccf59
--- /dev/null
+++ b/spec/ruby/core/set/shared/include.rb
@@ -0,0 +1,29 @@
+describe :set_include, shared: true do
+ it "returns true when self contains the passed Object" do
+ set = Set[:a, :b, :c]
+ set.send(@method, :a).should == true
+ set.send(@method, :e).should == false
+ end
+
+ describe "member equality" do
+ it "is checked using both #hash and #eql?" do
+ obj = Object.new
+ obj_another = Object.new
+
+ def obj.hash; 42 end
+ def obj_another.hash; 42 end
+ def obj_another.eql?(o) hash == o.hash end
+
+ set = Set["a", "b", "c", obj]
+ set.send(@method, obj_another).should == true
+ end
+
+ it "is not checked using #==" do
+ obj = Object.new
+ set = Set["a", "b", "c"]
+
+ obj.should_not_receive(:==)
+ set.send(@method, obj)
+ end
+ end
+end
diff --git a/spec/ruby/core/set/shared/inspect.rb b/spec/ruby/core/set/shared/inspect.rb
new file mode 100644
index 0000000000..31bd8accfd
--- /dev/null
+++ b/spec/ruby/core/set/shared/inspect.rb
@@ -0,0 +1,45 @@
+describe :set_inspect, shared: true do
+ it "returns a String representation of self" do
+ Set[].send(@method).should.is_a?(String)
+ Set[nil, false, true].send(@method).should.is_a?(String)
+ Set[1, 2, 3].send(@method).should.is_a?(String)
+ Set["1", "2", "3"].send(@method).should.is_a?(String)
+ Set[:a, "b", Set[?c]].send(@method).should.is_a?(String)
+ end
+
+ ruby_version_is "4.0" do
+ it "does include the elements of the set" do
+ Set["1"].send(@method).should == 'Set["1"]'
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "does include the elements of the set" do
+ Set["1"].send(@method).should == '#<Set: {"1"}>'
+ end
+ end
+
+ it "puts spaces between the elements" do
+ Set["1", "2"].send(@method).should.include?('", "')
+ end
+
+ ruby_version_is "4.0" do
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.send(@method).should.is_a?(String)
+ set1.send(@method).should.include?("Set[...]")
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.send(@method).should.is_a?(String)
+ set1.send(@method).should.include?("#<Set: {...}>")
+ end
+ end
+end
diff --git a/spec/ruby/core/set/shared/intersection.rb b/spec/ruby/core/set/shared/intersection.rb
new file mode 100644
index 0000000000..978a4924ef
--- /dev/null
+++ b/spec/ruby/core/set/shared/intersection.rb
@@ -0,0 +1,15 @@
+describe :set_intersection, shared: true do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing only elements shared by self and the passed Enumerable" do
+ @set.send(@method, Set[:b, :c, :d, :e]).should == Set[:b, :c]
+ @set.send(@method, [:b, :c, :d]).should == Set[:b, :c]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should.raise(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/set/shared/length.rb b/spec/ruby/core/set/shared/length.rb
index a8fcee9f39..a8fcee9f39 100644
--- a/spec/ruby/library/set/shared/length.rb
+++ b/spec/ruby/core/set/shared/length.rb
diff --git a/spec/ruby/core/set/shared/select.rb b/spec/ruby/core/set/shared/select.rb
new file mode 100644
index 0000000000..0d4a53fffd
--- /dev/null
+++ b/spec/ruby/core/set/shared/select.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+
+describe :set_select_bang, shared: true do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.send(@method) { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.send(@method) { |x| x.size != 3 }
+ @set.size.should.eql?(1)
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+
+ it "returns self when self was modified" do
+ @set.send(@method) { false }.should.equal?(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.send(@method) { true }.should == nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.send(@method)
+ enum.should.instance_of?(Enumerator)
+
+ enum.each { |x| x.size != 3 }
+
+ @set.should_not.include?("one")
+ @set.should_not.include?("two")
+ @set.should.include?("three")
+ end
+end
diff --git a/spec/ruby/core/set/shared/union.rb b/spec/ruby/core/set/shared/union.rb
new file mode 100644
index 0000000000..dddf1716e5
--- /dev/null
+++ b/spec/ruby/core/set/shared/union.rb
@@ -0,0 +1,15 @@
+describe :set_union, shared: true do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing all elements of self and the passed Enumerable" do
+ @set.send(@method, Set[:b, :d, :e]).should == Set[:a, :b, :c, :d, :e]
+ @set.send(@method, [:b, :e]).should == Set[:a, :b, :c, :e]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should.raise(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/size_spec.rb b/spec/ruby/core/set/size_spec.rb
new file mode 100644
index 0000000000..4ae22c5f0a
--- /dev/null
+++ b/spec/ruby/core/set/size_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/length'
+
+describe "Set#size" do
+ it_behaves_like :set_length, :size
+end
diff --git a/spec/ruby/core/set/sortedset/sortedset_spec.rb b/spec/ruby/core/set/sortedset/sortedset_spec.rb
new file mode 100644
index 0000000000..c8f65f0851
--- /dev/null
+++ b/spec/ruby/core/set/sortedset/sortedset_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+describe "SortedSet" do
+ ruby_version_is ""..."4.0" do
+ it "raises error including message that it has been extracted from the set stdlib" do
+ -> {
+ SortedSet
+ }.should.raise(RuntimeError) { |e|
+ e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
+ }
+ end
+ end
+end
diff --git a/spec/ruby/core/set/subset_spec.rb b/spec/ruby/core/set/subset_spec.rb
new file mode 100644
index 0000000000..81869d4993
--- /dev/null
+++ b/spec/ruby/core/set/subset_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
+
+describe "Set#subset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that is equal to self or self is a subset of" do
+ @set.subset?(@set).should == true
+ Set[].subset?(Set[]).should == true
+
+ Set[].subset?(@set).should == true
+ Set[].subset?(Set[1, 2, 3]).should == true
+ Set[].subset?(Set["a", :b, ?c]).should == true
+
+ Set[1, 2, 3].subset?(@set).should == true
+ Set[1, 3].subset?(@set).should == true
+ Set[1, 2].subset?(@set).should == true
+ Set[1].subset?(@set).should == true
+
+ Set[5].subset?(@set).should == false
+ Set[1, 5].subset?(@set).should == false
+ Set[nil].subset?(@set).should == false
+ Set["test"].subset?(@set).should == false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].subset?([]) }.should.raise(ArgumentError)
+ -> { Set[].subset?(1) }.should.raise(ArgumentError)
+ -> { Set[].subset?("test") }.should.raise(ArgumentError)
+ -> { Set[].subset?(Object.new) }.should.raise(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/subtract_spec.rb b/spec/ruby/core/set/subtract_spec.rb
new file mode 100644
index 0000000000..ae4bc73d41
--- /dev/null
+++ b/spec/ruby/core/set/subtract_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+
+describe "Set#subtract" do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "deletes any elements contained in other and returns self" do
+ @set.subtract(Set[:b, :c]).should == @set
+ @set.should == Set[:a]
+ end
+
+ it "accepts any enumerable as other" do
+ @set.subtract([:c]).should == Set[:a, :b]
+ end
+end
diff --git a/spec/ruby/core/set/superset_spec.rb b/spec/ruby/core/set/superset_spec.rb
new file mode 100644
index 0000000000..7e7db2b179
--- /dev/null
+++ b/spec/ruby/core/set/superset_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#superset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that equals self or self is a proper superset of" do
+ @set.superset?(@set).should == true
+ Set[].superset?(Set[]).should == true
+
+ @set.superset?(Set[]).should == true
+ Set[1, 2, 3].superset?(Set[]).should == true
+ Set["a", :b, ?c].superset?(Set[]).should == true
+
+ @set.superset?(Set[1, 2, 3]).should == true
+ @set.superset?(Set[1, 3]).should == true
+ @set.superset?(Set[1, 2]).should == true
+ @set.superset?(Set[1]).should == true
+
+ @set.superset?(Set[5]).should == false
+ @set.superset?(Set[1, 5]).should == false
+ @set.superset?(Set[nil]).should == false
+ @set.superset?(Set["test"]).should == false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].superset?([]) }.should.raise(ArgumentError)
+ -> { Set[].superset?(1) }.should.raise(ArgumentError)
+ -> { Set[].superset?("test") }.should.raise(ArgumentError)
+ -> { Set[].superset?(Object.new) }.should.raise(ArgumentError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a superset of" do
+ Set[1, 2, 3, 4].superset?(SetSpecs::SetLike.new([1, 2, 3])).should == true
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/to_a_spec.rb b/spec/ruby/core/set/to_a_spec.rb
new file mode 100644
index 0000000000..1e9800167a
--- /dev/null
+++ b/spec/ruby/core/set/to_a_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Set#to_a" do
+ it "returns an array containing elements of self" do
+ Set[1, 2, 3].to_a.sort.should == [1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/to_s_spec.rb b/spec/ruby/core/set/to_s_spec.rb
new file mode 100644
index 0000000000..55b8bfd9b2
--- /dev/null
+++ b/spec/ruby/core/set/to_s_spec.rb
@@ -0,0 +1,11 @@
+require_relative "../../spec_helper"
+require_relative 'shared/inspect'
+
+describe "Set#to_s" do
+ it_behaves_like :set_inspect, :to_s
+
+ it "is an alias of inspect" do
+ set = Set.new
+ set.method(:to_s).should == set.method(:inspect)
+ end
+end
diff --git a/spec/ruby/core/set/union_spec.rb b/spec/ruby/core/set/union_spec.rb
new file mode 100644
index 0000000000..3e77022d4b
--- /dev/null
+++ b/spec/ruby/core/set/union_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require_relative 'shared/union'
+
+describe "Set#union" do
+ it_behaves_like :set_union, :union
+end
+
+describe "Set#|" do
+ it_behaves_like :set_union, :|
+end
diff --git a/spec/ruby/core/signal/signame_spec.rb b/spec/ruby/core/signal/signame_spec.rb
index adfe895d97..82f040a6f9 100644
--- a/spec/ruby/core/signal/signame_spec.rb
+++ b/spec/ruby/core/signal/signame_spec.rb
@@ -16,13 +16,13 @@ describe "Signal.signame" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { Signal.signame("hello") }.should raise_error(TypeError)
+ -> { Signal.signame("hello") }.should.raise(TypeError)
end
it "raises a TypeError when the passed argument responds to #to_int but does not return an Integer" do
obj = mock('signal')
obj.should_receive(:to_int).and_return('not an int')
- -> { Signal.signame(obj) }.should raise_error(TypeError)
+ -> { Signal.signame(obj) }.should.raise(TypeError)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb
index 6d654a99be..5d3105fee8 100644
--- a/spec/ruby/core/signal/trap_spec.rb
+++ b/spec/ruby/core/signal/trap_spec.rb
@@ -14,7 +14,7 @@ describe "Signal.trap" do
end
it "returns the previous handler" do
- Signal.trap(:HUP, @saved_trap).should equal(@proc)
+ Signal.trap(:HUP, @saved_trap).should.equal?(@proc)
end
it "accepts a block" do
@@ -97,7 +97,7 @@ describe "Signal.trap" do
-> {
Process.kill :HUP, Process.pid
loop { Thread.pass }
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "accepts a non-callable that becomes callable when used" do
@@ -134,7 +134,7 @@ describe "Signal.trap" do
Process.kill :HUP, Process.pid
Thread.pass until done
- ScratchPad.recorded.should be_true
+ ScratchPad.recorded.should == true
end
it "registers an handler doing nothing with :IGNORE" do
@@ -158,7 +158,7 @@ describe "Signal.trap" do
it "ignores the signal when passed nil" do
Signal.trap :HUP, nil
- Signal.trap(:HUP, @saved_trap).should be_nil
+ Signal.trap(:HUP, @saved_trap).should == nil
end
it "accepts :DEFAULT in place of a proc" do
@@ -203,53 +203,53 @@ describe "Signal.trap" do
it "accepts long names as Strings" do
Signal.trap "SIGHUP", @proc
- Signal.trap("SIGHUP", @saved_trap).should equal(@proc)
+ Signal.trap("SIGHUP", @saved_trap).should.equal?(@proc)
end
it "accepts short names as Strings" do
Signal.trap "HUP", @proc
- Signal.trap("HUP", @saved_trap).should equal(@proc)
+ Signal.trap("HUP", @saved_trap).should.equal?(@proc)
end
it "accepts long names as Symbols" do
Signal.trap :SIGHUP, @proc
- Signal.trap(:SIGHUP, @saved_trap).should equal(@proc)
+ Signal.trap(:SIGHUP, @saved_trap).should.equal?(@proc)
end
it "accepts short names as Symbols" do
Signal.trap :HUP, @proc
- Signal.trap(:HUP, @saved_trap).should equal(@proc)
+ Signal.trap(:HUP, @saved_trap).should.equal?(@proc)
end
it "calls #to_str on an object to convert to a String" do
obj = mock("signal")
obj.should_receive(:to_str).exactly(2).times.and_return("HUP")
Signal.trap obj, @proc
- Signal.trap(obj, @saved_trap).should equal(@proc)
+ Signal.trap(obj, @saved_trap).should.equal?(@proc)
end
it "accepts Integer values" do
hup = Signal.list["HUP"]
Signal.trap hup, @proc
- Signal.trap(hup, @saved_trap).should equal(@proc)
+ Signal.trap(hup, @saved_trap).should.equal?(@proc)
end
it "does not call #to_int on an object to convert to an Integer" do
obj = mock("signal")
obj.should_not_receive(:to_int)
- -> { Signal.trap obj, @proc }.should raise_error(ArgumentError, /bad signal type/)
+ -> { Signal.trap obj, @proc }.should.raise(ArgumentError, /bad signal type/)
end
it "raises ArgumentError when passed unknown signal" do
- -> { Signal.trap(300) { } }.should raise_error(ArgumentError, "invalid signal number (300)")
- -> { Signal.trap("USR10") { } }.should raise_error(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
- -> { Signal.trap("SIGUSR10") { } }.should raise_error(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
+ -> { Signal.trap(300) { } }.should.raise(ArgumentError, "invalid signal number (300)")
+ -> { Signal.trap("USR10") { } }.should.raise(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
+ -> { Signal.trap("SIGUSR10") { } }.should.raise(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
end
it "raises ArgumentError when passed signal is not Integer, String or Symbol" do
- -> { Signal.trap(nil) { } }.should raise_error(ArgumentError, "bad signal type NilClass")
- -> { Signal.trap(100.0) { } }.should raise_error(ArgumentError, "bad signal type Float")
- -> { Signal.trap(Rational(100)) { } }.should raise_error(ArgumentError, "bad signal type Rational")
+ -> { Signal.trap(nil) { } }.should.raise(ArgumentError, "bad signal type NilClass")
+ -> { Signal.trap(100.0) { } }.should.raise(ArgumentError, "bad signal type Float")
+ -> { Signal.trap(Rational(100)) { } }.should.raise(ArgumentError, "bad signal type Rational")
end
# See man 2 signal
@@ -257,8 +257,8 @@ describe "Signal.trap" do
it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do
-> {
Signal.trap(signal, -> {})
- }.should raise_error(StandardError) { |e|
- [ArgumentError, Errno::EINVAL].should include(e.class)
+ }.should.raise(StandardError) { |e|
+ [ArgumentError, Errno::EINVAL].should.include?(e.class)
e.message.should =~ /Invalid argument|Signal already used by VM or OS/
}
end
@@ -268,7 +268,7 @@ describe "Signal.trap" do
it "raises ArgumentError for SIG#{signal} which is reserved by Ruby" do
-> {
Signal.trap(signal, -> {})
- }.should raise_error(ArgumentError, "can't trap reserved signal: SIG#{signal}")
+ }.should.raise(ArgumentError, "can't trap reserved signal: SIG#{signal}")
end
end
diff --git a/spec/ruby/core/sizedqueue/append_spec.rb b/spec/ruby/core/sizedqueue/append_spec.rb
index 6fffe2f272..c52baa3802 100644
--- a/spec/ruby/core/sizedqueue/append_spec.rb
+++ b/spec/ruby/core/sizedqueue/append_spec.rb
@@ -12,7 +12,5 @@ describe "SizedQueue#<<" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/deq_spec.rb b/spec/ruby/core/sizedqueue/deq_spec.rb
index 985d654bb3..2aeb52f8a6 100644
--- a/spec/ruby/core/sizedqueue/deq_spec.rb
+++ b/spec/ruby/core/sizedqueue/deq_spec.rb
@@ -7,7 +7,5 @@ describe "SizedQueue#deq" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/enq_spec.rb b/spec/ruby/core/sizedqueue/enq_spec.rb
index 619373e46b..b955909475 100644
--- a/spec/ruby/core/sizedqueue/enq_spec.rb
+++ b/spec/ruby/core/sizedqueue/enq_spec.rb
@@ -12,7 +12,5 @@ describe "SizedQueue#enq" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/pop_spec.rb b/spec/ruby/core/sizedqueue/pop_spec.rb
index 5e7cfea8fb..6338ddbaa0 100644
--- a/spec/ruby/core/sizedqueue/pop_spec.rb
+++ b/spec/ruby/core/sizedqueue/pop_spec.rb
@@ -7,7 +7,5 @@ describe "SizedQueue#pop" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/push_spec.rb b/spec/ruby/core/sizedqueue/push_spec.rb
index ce61e89b53..9eaa6beca0 100644
--- a/spec/ruby/core/sizedqueue/push_spec.rb
+++ b/spec/ruby/core/sizedqueue/push_spec.rb
@@ -12,7 +12,5 @@ describe "SizedQueue#push" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/shift_spec.rb b/spec/ruby/core/sizedqueue/shift_spec.rb
index 3220801f3a..52974c1d99 100644
--- a/spec/ruby/core/sizedqueue/shift_spec.rb
+++ b/spec/ruby/core/sizedqueue/shift_spec.rb
@@ -7,7 +7,5 @@ describe "SizedQueue#shift" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
end
diff --git a/spec/ruby/core/string/allocate_spec.rb b/spec/ruby/core/string/allocate_spec.rb
index 30d5f60594..00dadaf076 100644
--- a/spec/ruby/core/string/allocate_spec.rb
+++ b/spec/ruby/core/string/allocate_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "String.allocate" do
it "returns an instance of String" do
str = String.allocate
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
end
it "returns a fully-formed String" do
diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb
index b1703e5f89..feead64615 100644
--- a/spec/ruby/core/string/append_as_bytes_spec.rb
+++ b/spec/ruby/core/string/append_as_bytes_spec.rb
@@ -4,17 +4,19 @@ describe "String#append_bytes" do
ruby_version_is "3.4" do
it "doesn't allow to mutate frozen strings" do
str = "hello".freeze
- -> { str.append_as_bytes("\xE2\x82") }.should raise_error(FrozenError)
+ -> { str.append_as_bytes("\xE2\x82") }.should.raise(FrozenError)
end
- it "allows creating broken strings" do
+ it "allows creating broken strings in UTF8" do
str = +"hello"
str.append_as_bytes("\xE2\x82")
str.valid_encoding?.should == false
str.append_as_bytes("\xAC")
str.valid_encoding?.should == true
+ end
+ it "allows creating broken strings in UTF_32" do
str = "abc".encode(Encoding::UTF_32LE)
str.append_as_bytes("def")
str.encoding.should == Encoding::UTF_32LE
@@ -52,7 +54,7 @@ describe "String#append_bytes" do
to_str.should_not_receive(:to_int)
str = +"hello"
- -> { str.append_as_bytes(to_str) }.should raise_error(TypeError, "wrong argument type MockObject (expected String or Integer)")
+ -> { str.append_as_bytes(to_str) }.should.raise(TypeError, "wrong argument type MockObject (expected String or Integer)")
end
end
end
diff --git a/spec/ruby/core/string/append_spec.rb b/spec/ruby/core/string/append_spec.rb
index 8497ce8262..e0f71b7c97 100644
--- a/spec/ruby/core/string/append_spec.rb
+++ b/spec/ruby/core/string/append_spec.rb
@@ -8,7 +8,7 @@ describe "String#<<" do
it_behaves_like :string_concat_type_coercion, :<<
it "raises an ArgumentError when given the incorrect number of arguments" do
- -> { "hello".send(:<<) }.should raise_error(ArgumentError)
- -> { "hello".send(:<<, "one", "two") }.should raise_error(ArgumentError)
+ -> { "hello".send(:<<) }.should.raise(ArgumentError)
+ -> { "hello".send(:<<, "one", "two") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/ascii_only_spec.rb b/spec/ruby/core/string/ascii_only_spec.rb
index 88a0559cfd..9af663beb8 100644
--- a/spec/ruby/core/string/ascii_only_spec.rb
+++ b/spec/ruby/core/string/ascii_only_spec.rb
@@ -12,13 +12,13 @@ describe "String#ascii_only?" do
end
it "returns true if the encoding is US-ASCII" do
- "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
- "hello".encode(Encoding::US_ASCII).ascii_only?.should be_true
+ "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should == true
+ "hello".encode(Encoding::US_ASCII).ascii_only?.should == true
end
it "returns true for all single-character UTF-8 Strings" do
0.upto(127) do |n|
- n.chr.ascii_only?.should be_true
+ n.chr.ascii_only?.should == true
end
end
end
@@ -27,7 +27,7 @@ describe "String#ascii_only?" do
it "returns false if the encoding is BINARY" do
chr = 128.chr
chr.encoding.should == Encoding::BINARY
- chr.ascii_only?.should be_false
+ chr.ascii_only?.should == false
end
it "returns false if the String contains any non-ASCII characters" do
@@ -46,37 +46,37 @@ describe "String#ascii_only?" do
end
it "returns true for the empty String with an ASCII-compatible encoding" do
- "".ascii_only?.should be_true
- "".encode('UTF-8').ascii_only?.should be_true
+ "".ascii_only?.should == true
+ "".encode('UTF-8').ascii_only?.should == true
end
it "returns false for the empty String with a non-ASCII-compatible encoding" do
- "".dup.force_encoding('UTF-16LE').ascii_only?.should be_false
- "".encode('UTF-16BE').ascii_only?.should be_false
+ "".dup.force_encoding('UTF-16LE').ascii_only?.should == false
+ "".encode('UTF-16BE').ascii_only?.should == false
end
it "returns false for a non-empty String with non-ASCII-compatible encoding" do
- "\x78\x00".dup.force_encoding("UTF-16LE").ascii_only?.should be_false
+ "\x78\x00".dup.force_encoding("UTF-16LE").ascii_only?.should == false
end
it "returns false when interpolating non ascii strings" do
base = "EU currency is".dup.force_encoding(Encoding::US_ASCII)
euro = "\u20AC"
interp = "#{base} #{euro}"
- euro.ascii_only?.should be_false
- base.ascii_only?.should be_true
- interp.ascii_only?.should be_false
+ euro.ascii_only?.should == false
+ base.ascii_only?.should == true
+ interp.ascii_only?.should == false
end
it "returns false after appending non ASCII characters to an empty String" do
- ("".dup << "λ").ascii_only?.should be_false
+ ("".dup << "λ").ascii_only?.should == false
end
it "returns false when concatenating an ASCII and non-ASCII String" do
- "".dup.concat("λ").ascii_only?.should be_false
+ "".dup.concat("λ").ascii_only?.should == false
end
it "returns false when replacing an ASCII String with a non-ASCII String" do
- "".dup.replace("λ").ascii_only?.should be_false
+ "".dup.replace("λ").ascii_only?.should == false
end
end
diff --git a/spec/ruby/core/string/b_spec.rb b/spec/ruby/core/string/b_spec.rb
index 4b1fafff11..d181447709 100644
--- a/spec/ruby/core/string/b_spec.rb
+++ b/spec/ruby/core/string/b_spec.rb
@@ -10,7 +10,7 @@ describe "String#b" do
it "returns new string without modifying self" do
str = "こんちには"
- str.b.should_not equal(str)
+ str.b.should_not.equal?(str)
str.should == "こんちには"
end
end
diff --git a/spec/ruby/core/string/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb
index 47c7be1029..f4c6408790 100644
--- a/spec/ruby/core/string/byteindex_spec.rb
+++ b/spec/ruby/core/string/byteindex_spec.rb
@@ -4,301 +4,295 @@ require_relative 'fixtures/classes'
require_relative 'shared/byte_index_common.rb'
describe "String#byteindex" do
- ruby_version_is "3.2" do
- it "calls #to_str to convert the first argument" do
- char = mock("string index char")
- char.should_receive(:to_str).and_return("b")
- "abc".byteindex(char).should == 1
- end
-
- it "calls #to_int to convert the second argument" do
- offset = mock("string index offset")
- offset.should_receive(:to_int).and_return(1)
- "abc".byteindex("c", offset).should == 2
- end
+ it "calls #to_str to convert the first argument" do
+ char = mock("string index char")
+ char.should_receive(:to_str).and_return("b")
+ "abc".byteindex(char).should == 1
+ end
- it "does not raise IndexError when byte offset is correct or on string boundary" do
- "わ".byteindex("").should == 0
- "わ".byteindex("", 0).should == 0
- "わ".byteindex("", 3).should == 3
- end
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(1)
+ "abc".byteindex("c", offset).should == 2
+ end
- it_behaves_like :byte_index_common, :byteindex
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "わ".byteindex("").should == 0
+ "わ".byteindex("", 0).should == 0
+ "わ".byteindex("", 3).should == 3
end
+
+ it_behaves_like :byte_index_common, :byteindex
end
describe "String#byteindex with String" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byteindex(char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0]
- str.byteindex(str).should == str.byteindex(chr)
+ it "behaves the same as String#byteindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byteindex(str).should == str.byteindex(chr)
- 0.upto(str.size + 1) do |start|
- str.byteindex(str, start).should == str.byteindex(chr, start)
- end
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
+ end
- (-str.size - 1).upto(-1) do |start|
- str.byteindex(str, start).should == str.byteindex(chr, start)
- end
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
end
end
+ end
- it "returns the byteindex of the first occurrence of the given substring" do
- "blablabla".byteindex("").should == 0
- "blablabla".byteindex("b").should == 0
- "blablabla".byteindex("bla").should == 0
- "blablabla".byteindex("blabla").should == 0
- "blablabla".byteindex("blablabla").should == 0
-
- "blablabla".byteindex("l").should == 1
- "blablabla".byteindex("la").should == 1
- "blablabla".byteindex("labla").should == 1
- "blablabla".byteindex("lablabla").should == 1
-
- "blablabla".byteindex("a").should == 2
- "blablabla".byteindex("abla").should == 2
- "blablabla".byteindex("ablabla").should == 2
- end
+ it "returns the byteindex of the first occurrence of the given substring" do
+ "blablabla".byteindex("").should == 0
+ "blablabla".byteindex("b").should == 0
+ "blablabla".byteindex("bla").should == 0
+ "blablabla".byteindex("blabla").should == 0
+ "blablabla".byteindex("blablabla").should == 0
+
+ "blablabla".byteindex("l").should == 1
+ "blablabla".byteindex("la").should == 1
+ "blablabla".byteindex("labla").should == 1
+ "blablabla".byteindex("lablabla").should == 1
+
+ "blablabla".byteindex("a").should == 2
+ "blablabla".byteindex("abla").should == 2
+ "blablabla".byteindex("ablabla").should == 2
+ end
- it "treats the offset as a byteindex" do
- "aaaaa".byteindex("a", 0).should == 0
- "aaaaa".byteindex("a", 2).should == 2
- "aaaaa".byteindex("a", 4).should == 4
- end
+ it "treats the offset as a byteindex" do
+ "aaaaa".byteindex("a", 0).should == 0
+ "aaaaa".byteindex("a", 2).should == 2
+ "aaaaa".byteindex("a", 4).should == 4
+ end
- it "ignores string subclasses" do
- "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
- StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
- StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
- end
+ it "ignores string subclasses" do
+ "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
+ StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
+ StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
+ end
- it "starts the search at the given offset" do
- "blablabla".byteindex("bl", 0).should == 0
- "blablabla".byteindex("bl", 1).should == 3
- "blablabla".byteindex("bl", 2).should == 3
- "blablabla".byteindex("bl", 3).should == 3
-
- "blablabla".byteindex("bla", 0).should == 0
- "blablabla".byteindex("bla", 1).should == 3
- "blablabla".byteindex("bla", 2).should == 3
- "blablabla".byteindex("bla", 3).should == 3
-
- "blablabla".byteindex("blab", 0).should == 0
- "blablabla".byteindex("blab", 1).should == 3
- "blablabla".byteindex("blab", 2).should == 3
- "blablabla".byteindex("blab", 3).should == 3
-
- "blablabla".byteindex("la", 1).should == 1
- "blablabla".byteindex("la", 2).should == 4
- "blablabla".byteindex("la", 3).should == 4
- "blablabla".byteindex("la", 4).should == 4
-
- "blablabla".byteindex("lab", 1).should == 1
- "blablabla".byteindex("lab", 2).should == 4
- "blablabla".byteindex("lab", 3).should == 4
- "blablabla".byteindex("lab", 4).should == 4
-
- "blablabla".byteindex("ab", 2).should == 2
- "blablabla".byteindex("ab", 3).should == 5
- "blablabla".byteindex("ab", 4).should == 5
- "blablabla".byteindex("ab", 5).should == 5
-
- "blablabla".byteindex("", 0).should == 0
- "blablabla".byteindex("", 1).should == 1
- "blablabla".byteindex("", 2).should == 2
- "blablabla".byteindex("", 7).should == 7
- "blablabla".byteindex("", 8).should == 8
- "blablabla".byteindex("", 9).should == 9
- end
+ it "starts the search at the given offset" do
+ "blablabla".byteindex("bl", 0).should == 0
+ "blablabla".byteindex("bl", 1).should == 3
+ "blablabla".byteindex("bl", 2).should == 3
+ "blablabla".byteindex("bl", 3).should == 3
+
+ "blablabla".byteindex("bla", 0).should == 0
+ "blablabla".byteindex("bla", 1).should == 3
+ "blablabla".byteindex("bla", 2).should == 3
+ "blablabla".byteindex("bla", 3).should == 3
+
+ "blablabla".byteindex("blab", 0).should == 0
+ "blablabla".byteindex("blab", 1).should == 3
+ "blablabla".byteindex("blab", 2).should == 3
+ "blablabla".byteindex("blab", 3).should == 3
+
+ "blablabla".byteindex("la", 1).should == 1
+ "blablabla".byteindex("la", 2).should == 4
+ "blablabla".byteindex("la", 3).should == 4
+ "blablabla".byteindex("la", 4).should == 4
+
+ "blablabla".byteindex("lab", 1).should == 1
+ "blablabla".byteindex("lab", 2).should == 4
+ "blablabla".byteindex("lab", 3).should == 4
+ "blablabla".byteindex("lab", 4).should == 4
+
+ "blablabla".byteindex("ab", 2).should == 2
+ "blablabla".byteindex("ab", 3).should == 5
+ "blablabla".byteindex("ab", 4).should == 5
+ "blablabla".byteindex("ab", 5).should == 5
+
+ "blablabla".byteindex("", 0).should == 0
+ "blablabla".byteindex("", 1).should == 1
+ "blablabla".byteindex("", 2).should == 2
+ "blablabla".byteindex("", 7).should == 7
+ "blablabla".byteindex("", 8).should == 8
+ "blablabla".byteindex("", 9).should == 9
+ end
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byteindex(needle, offset).should ==
- str.byteindex(needle, offset + str.length)
- end
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
end
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byteindex("B").should == nil
- "blablabla".byteindex("z").should == nil
- "blablabla".byteindex("BLA").should == nil
- "blablabla".byteindex("blablablabla").should == nil
- "blablabla".byteindex("", 10).should == nil
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex("B").should == nil
+ "blablabla".byteindex("z").should == nil
+ "blablabla".byteindex("BLA").should == nil
+ "blablabla".byteindex("blablablabla").should == nil
+ "blablabla".byteindex("", 10).should == nil
- "hello".byteindex("he", 1).should == nil
- "hello".byteindex("he", 2).should == nil
- "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
- end
+ "hello".byteindex("he", 1).should == nil
+ "hello".byteindex("he", 2).should == nil
+ "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
+ end
- it "returns the character byteindex of a multibyte character" do
- "ありがとう".byteindex("が").should == 6
- end
+ it "returns the character byteindex of a multibyte character" do
+ "ありがとう".byteindex("が").should == 6
+ end
- it "returns the character byteindex after offset" do
- "われわれ".byteindex("わ", 3).should == 6
- "ありがとうありがとう".byteindex("が", 9).should == 21
- end
+ it "returns the character byteindex after offset" do
+ "われわれ".byteindex("わ", 3).should == 6
+ "ありがとうありがとう".byteindex("が", 9).should == 21
+ end
- it "returns the character byteindex after a partial first match" do
- "</</h".byteindex("</h").should == 2
- end
+ it "returns the character byteindex after a partial first match" do
+ "</</h".byteindex("</h").should == 2
+ end
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- char = "れ".encode Encoding::EUC_JP
- -> do
- "あれ".byteindex(char)
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ char = "れ".encode Encoding::EUC_JP
+ -> do
+ "あれ".byteindex(char)
+ end.should.raise(Encoding::CompatibilityError)
+ end
- it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil
- end
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil
+ end
- it "handles a substring in a subset encoding" do
- 'été'.byteindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
- end
+ it "handles a substring in a subset encoding" do
+ 'été'.byteindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
end
end
describe "String#byteindex with Regexp" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byteindex(string) for escaped string regexps" do
- ["blablabla", "hello cruel world...!"].each do |str|
- ["", "b", "bla", "lab", "o c", "d."].each do |needle|
- regexp = Regexp.new(Regexp.escape(needle))
- str.byteindex(regexp).should == str.byteindex(needle)
-
- 0.upto(str.size + 1) do |start|
- str.byteindex(regexp, start).should == str.byteindex(needle, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byteindex(regexp, start).should == str.byteindex(needle, start)
- end
+ it "behaves the same as String#byteindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byteindex(regexp).should == str.byteindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
end
end
end
+ end
- it "returns the byteindex of the first match of regexp" do
- "blablabla".byteindex(/bla/).should == 0
- "blablabla".byteindex(/BLA/i).should == 0
+ it "returns the byteindex of the first match of regexp" do
+ "blablabla".byteindex(/bla/).should == 0
+ "blablabla".byteindex(/BLA/i).should == 0
- "blablabla".byteindex(/.{0}/).should == 0
- "blablabla".byteindex(/.{6}/).should == 0
- "blablabla".byteindex(/.{9}/).should == 0
+ "blablabla".byteindex(/.{0}/).should == 0
+ "blablabla".byteindex(/.{6}/).should == 0
+ "blablabla".byteindex(/.{9}/).should == 0
- "blablabla".byteindex(/.*/).should == 0
- "blablabla".byteindex(/.+/).should == 0
+ "blablabla".byteindex(/.*/).should == 0
+ "blablabla".byteindex(/.+/).should == 0
- "blablabla".byteindex(/lab|b/).should == 0
+ "blablabla".byteindex(/lab|b/).should == 0
- not_supported_on :opal do
- "blablabla".byteindex(/\A/).should == 0
- "blablabla".byteindex(/\Z/).should == 9
- "blablabla".byteindex(/\z/).should == 9
- "blablabla\n".byteindex(/\Z/).should == 9
- "blablabla\n".byteindex(/\z/).should == 10
- end
+ not_supported_on :opal do
+ "blablabla".byteindex(/\A/).should == 0
+ "blablabla".byteindex(/\Z/).should == 9
+ "blablabla".byteindex(/\z/).should == 9
+ "blablabla\n".byteindex(/\Z/).should == 9
+ "blablabla\n".byteindex(/\z/).should == 10
+ end
- "blablabla".byteindex(/^/).should == 0
- "\nblablabla".byteindex(/^/).should == 0
- "b\nablabla".byteindex(/$/).should == 1
- "bl\nablabla".byteindex(/$/).should == 2
+ "blablabla".byteindex(/^/).should == 0
+ "\nblablabla".byteindex(/^/).should == 0
+ "b\nablabla".byteindex(/$/).should == 1
+ "bl\nablabla".byteindex(/$/).should == 2
- "blablabla".byteindex(/.l./).should == 0
- end
+ "blablabla".byteindex(/.l./).should == 0
+ end
- it "starts the search at the given offset" do
- "blablabla".byteindex(/.{0}/, 5).should == 5
- "blablabla".byteindex(/.{1}/, 5).should == 5
- "blablabla".byteindex(/.{2}/, 5).should == 5
- "blablabla".byteindex(/.{3}/, 5).should == 5
- "blablabla".byteindex(/.{4}/, 5).should == 5
-
- "blablabla".byteindex(/.{0}/, 3).should == 3
- "blablabla".byteindex(/.{1}/, 3).should == 3
- "blablabla".byteindex(/.{2}/, 3).should == 3
- "blablabla".byteindex(/.{5}/, 3).should == 3
- "blablabla".byteindex(/.{6}/, 3).should == 3
-
- "blablabla".byteindex(/.l./, 0).should == 0
- "blablabla".byteindex(/.l./, 1).should == 3
- "blablabla".byteindex(/.l./, 2).should == 3
- "blablabla".byteindex(/.l./, 3).should == 3
-
- "xblaxbla".byteindex(/x./, 0).should == 0
- "xblaxbla".byteindex(/x./, 1).should == 4
- "xblaxbla".byteindex(/x./, 2).should == 4
-
- not_supported_on :opal do
- "blablabla\n".byteindex(/\Z/, 9).should == 9
- end
+ it "starts the search at the given offset" do
+ "blablabla".byteindex(/.{0}/, 5).should == 5
+ "blablabla".byteindex(/.{1}/, 5).should == 5
+ "blablabla".byteindex(/.{2}/, 5).should == 5
+ "blablabla".byteindex(/.{3}/, 5).should == 5
+ "blablabla".byteindex(/.{4}/, 5).should == 5
+
+ "blablabla".byteindex(/.{0}/, 3).should == 3
+ "blablabla".byteindex(/.{1}/, 3).should == 3
+ "blablabla".byteindex(/.{2}/, 3).should == 3
+ "blablabla".byteindex(/.{5}/, 3).should == 3
+ "blablabla".byteindex(/.{6}/, 3).should == 3
+
+ "blablabla".byteindex(/.l./, 0).should == 0
+ "blablabla".byteindex(/.l./, 1).should == 3
+ "blablabla".byteindex(/.l./, 2).should == 3
+ "blablabla".byteindex(/.l./, 3).should == 3
+
+ "xblaxbla".byteindex(/x./, 0).should == 0
+ "xblaxbla".byteindex(/x./, 1).should == 4
+ "xblaxbla".byteindex(/x./, 2).should == 4
+
+ not_supported_on :opal do
+ "blablabla\n".byteindex(/\Z/, 9).should == 9
end
+ end
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byteindex(needle, offset).should ==
- str.byteindex(needle, offset + str.length)
- end
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
end
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byteindex(/BLA/).should == nil
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex(/BLA/).should == nil
- "blablabla".byteindex(/.{10}/).should == nil
- "blaxbla".byteindex(/.x/, 3).should == nil
- "blaxbla".byteindex(/..x/, 2).should == nil
- end
+ "blablabla".byteindex(/.{10}/).should == nil
+ "blaxbla".byteindex(/.x/, 3).should == nil
+ "blaxbla".byteindex(/..x/, 2).should == nil
+ end
- it "returns nil if the Regexp matches the empty string and the offset is out of range" do
- "ruby".byteindex(//, 12).should be_nil
- end
+ it "returns nil if the Regexp matches the empty string and the offset is out of range" do
+ "ruby".byteindex(//, 12).should == nil
+ end
- it "supports \\G which matches at the given start offset" do
- "helloYOU.".byteindex(/\GYOU/, 5).should == 5
- "helloYOU.".byteindex(/\GYOU/).should == nil
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byteindex(/\GYOU/, 5).should == 5
+ "helloYOU.".byteindex(/\GYOU/).should == nil
- re = /\G.+YOU/
- # The # marks where \G will match.
- [
- ["#hi!YOUall.", 0],
- ["h#i!YOUall.", 1],
- ["hi#!YOUall.", 2],
- ["hi!#YOUall.", nil]
- ].each do |spec|
+ re = /\G.+YOU/
+ # The # marks where \G will match.
+ [
+ ["#hi!YOUall.", 0],
+ ["h#i!YOUall.", 1],
+ ["hi#!YOUall.", 2],
+ ["hi!#YOUall.", nil]
+ ].each do |spec|
- start = spec[0].byteindex("#")
- str = spec[0].delete("#")
+ start = spec[0].byteindex("#")
+ str = spec[0].delete("#")
- str.byteindex(re, start).should == spec[1]
- end
+ str.byteindex(re, start).should == spec[1]
end
+ end
- it "converts start_offset to an integer via to_int" do
- obj = mock('1')
- obj.should_receive(:to_int).and_return(1)
- "RWOARW".byteindex(/R./, obj).should == 4
- end
+ it "converts start_offset to an integer via to_int" do
+ obj = mock('1')
+ obj.should_receive(:to_int).and_return(1)
+ "RWOARW".byteindex(/R./, obj).should == 4
+ end
- it "returns the character byteindex of a multibyte character" do
- "ありがとう".byteindex(/が/).should == 6
- end
+ it "returns the character byteindex of a multibyte character" do
+ "ありがとう".byteindex(/が/).should == 6
+ end
- it "returns the character byteindex after offset" do
- "われわれ".byteindex(/わ/, 3).should == 6
- end
+ it "returns the character byteindex after offset" do
+ "われわれ".byteindex(/わ/, 3).should == 6
+ end
- it "treats the offset as a byteindex" do
- "われわわれ".byteindex(/わ/, 6).should == 6
- end
+ it "treats the offset as a byteindex" do
+ "われわわれ".byteindex(/わ/, 6).should == 6
end
end
diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb
index 34ecbfbd21..569820463d 100644
--- a/spec/ruby/core/string/byterindex_spec.rb
+++ b/spec/ruby/core/string/byterindex_spec.rb
@@ -4,356 +4,350 @@ require_relative 'fixtures/classes'
require_relative 'shared/byte_index_common.rb'
describe "String#byterindex with object" do
- ruby_version_is "3.2" do
- it "tries to convert obj to a string via to_str" do
- obj = mock('lo')
- def obj.to_str() "lo" end
- "hello".byterindex(obj).should == "hello".byterindex("lo")
-
- obj = mock('o')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args) "o" end
- "hello".byterindex(obj).should == "hello".byterindex("o")
- end
-
- it "calls #to_int to convert the second argument" do
- offset = mock("string index offset")
- offset.should_receive(:to_int).and_return(3)
- "abc".byterindex("c", offset).should == 2
- end
+ it "tries to convert obj to a string via to_str" do
+ obj = mock('lo')
+ def obj.to_str() "lo" end
+ "hello".byterindex(obj).should == "hello".byterindex("lo")
+
+ obj = mock('o')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) "o" end
+ "hello".byterindex(obj).should == "hello".byterindex("o")
+ end
- it "does not raise IndexError when byte offset is correct or on string boundary" do
- "わ".byterindex("", 0).should == 0
- "わ".byterindex("", 3).should == 3
- "わ".byterindex("").should == 3
- end
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(3)
+ "abc".byterindex("c", offset).should == 2
+ end
- it_behaves_like :byte_index_common, :byterindex
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "わ".byterindex("", 0).should == 0
+ "わ".byterindex("", 3).should == 3
+ "わ".byterindex("").should == 3
end
+
+ it_behaves_like :byte_index_common, :byterindex
end
describe "String#byterindex with String" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byterindex(char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0]
- str.byterindex(str).should == str.byterindex(chr)
+ it "behaves the same as String#byterindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byterindex(str).should == str.byterindex(chr)
- 0.upto(str.size + 1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
end
end
+ end
- it "behaves the same as String#byterindex(?char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
- str.byterindex(str).should == str.byterindex(chr)
+ it "behaves the same as String#byterindex(?char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
+ str.byterindex(str).should == str.byterindex(chr)
- 0.upto(str.size + 1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
end
end
+ end
- it "returns the index of the last occurrence of the given substring" do
- "blablabla".byterindex("").should == 9
- "blablabla".byterindex("a").should == 8
- "blablabla".byterindex("la").should == 7
- "blablabla".byterindex("bla").should == 6
- "blablabla".byterindex("abla").should == 5
- "blablabla".byterindex("labla").should == 4
- "blablabla".byterindex("blabla").should == 3
- "blablabla".byterindex("ablabla").should == 2
- "blablabla".byterindex("lablabla").should == 1
- "blablabla".byterindex("blablabla").should == 0
-
- "blablabla".byterindex("l").should == 7
- "blablabla".byterindex("bl").should == 6
- "blablabla".byterindex("abl").should == 5
- "blablabla".byterindex("labl").should == 4
- "blablabla".byterindex("blabl").should == 3
- "blablabla".byterindex("ablabl").should == 2
- "blablabla".byterindex("lablabl").should == 1
- "blablabla".byterindex("blablabl").should == 0
-
- "blablabla".byterindex("b").should == 6
- "blablabla".byterindex("ab").should == 5
- "blablabla".byterindex("lab").should == 4
- "blablabla".byterindex("blab").should == 3
- "blablabla".byterindex("ablab").should == 2
- "blablabla".byterindex("lablab").should == 1
- "blablabla".byterindex("blablab").should == 0
- end
+ it "returns the index of the last occurrence of the given substring" do
+ "blablabla".byterindex("").should == 9
+ "blablabla".byterindex("a").should == 8
+ "blablabla".byterindex("la").should == 7
+ "blablabla".byterindex("bla").should == 6
+ "blablabla".byterindex("abla").should == 5
+ "blablabla".byterindex("labla").should == 4
+ "blablabla".byterindex("blabla").should == 3
+ "blablabla".byterindex("ablabla").should == 2
+ "blablabla".byterindex("lablabla").should == 1
+ "blablabla".byterindex("blablabla").should == 0
+
+ "blablabla".byterindex("l").should == 7
+ "blablabla".byterindex("bl").should == 6
+ "blablabla".byterindex("abl").should == 5
+ "blablabla".byterindex("labl").should == 4
+ "blablabla".byterindex("blabl").should == 3
+ "blablabla".byterindex("ablabl").should == 2
+ "blablabla".byterindex("lablabl").should == 1
+ "blablabla".byterindex("blablabl").should == 0
+
+ "blablabla".byterindex("b").should == 6
+ "blablabla".byterindex("ab").should == 5
+ "blablabla".byterindex("lab").should == 4
+ "blablabla".byterindex("blab").should == 3
+ "blablabla".byterindex("ablab").should == 2
+ "blablabla".byterindex("lablab").should == 1
+ "blablabla".byterindex("blablab").should == 0
+ end
- it "ignores string subclasses" do
- "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
- StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
- StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
- end
+ it "ignores string subclasses" do
+ "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
+ StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
+ StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
+ end
- it "starts the search at the given offset" do
- "blablabla".byterindex("bl", 0).should == 0
- "blablabla".byterindex("bl", 1).should == 0
- "blablabla".byterindex("bl", 2).should == 0
- "blablabla".byterindex("bl", 3).should == 3
-
- "blablabla".byterindex("bla", 0).should == 0
- "blablabla".byterindex("bla", 1).should == 0
- "blablabla".byterindex("bla", 2).should == 0
- "blablabla".byterindex("bla", 3).should == 3
-
- "blablabla".byterindex("blab", 0).should == 0
- "blablabla".byterindex("blab", 1).should == 0
- "blablabla".byterindex("blab", 2).should == 0
- "blablabla".byterindex("blab", 3).should == 3
- "blablabla".byterindex("blab", 6).should == 3
- "blablablax".byterindex("blab", 6).should == 3
-
- "blablabla".byterindex("la", 1).should == 1
- "blablabla".byterindex("la", 2).should == 1
- "blablabla".byterindex("la", 3).should == 1
- "blablabla".byterindex("la", 4).should == 4
-
- "blablabla".byterindex("lab", 1).should == 1
- "blablabla".byterindex("lab", 2).should == 1
- "blablabla".byterindex("lab", 3).should == 1
- "blablabla".byterindex("lab", 4).should == 4
-
- "blablabla".byterindex("ab", 2).should == 2
- "blablabla".byterindex("ab", 3).should == 2
- "blablabla".byterindex("ab", 4).should == 2
- "blablabla".byterindex("ab", 5).should == 5
-
- "blablabla".byterindex("", 0).should == 0
- "blablabla".byterindex("", 1).should == 1
- "blablabla".byterindex("", 2).should == 2
- "blablabla".byterindex("", 7).should == 7
- "blablabla".byterindex("", 8).should == 8
- "blablabla".byterindex("", 9).should == 9
- "blablabla".byterindex("", 10).should == 9
- end
+ it "starts the search at the given offset" do
+ "blablabla".byterindex("bl", 0).should == 0
+ "blablabla".byterindex("bl", 1).should == 0
+ "blablabla".byterindex("bl", 2).should == 0
+ "blablabla".byterindex("bl", 3).should == 3
+
+ "blablabla".byterindex("bla", 0).should == 0
+ "blablabla".byterindex("bla", 1).should == 0
+ "blablabla".byterindex("bla", 2).should == 0
+ "blablabla".byterindex("bla", 3).should == 3
+
+ "blablabla".byterindex("blab", 0).should == 0
+ "blablabla".byterindex("blab", 1).should == 0
+ "blablabla".byterindex("blab", 2).should == 0
+ "blablabla".byterindex("blab", 3).should == 3
+ "blablabla".byterindex("blab", 6).should == 3
+ "blablablax".byterindex("blab", 6).should == 3
+
+ "blablabla".byterindex("la", 1).should == 1
+ "blablabla".byterindex("la", 2).should == 1
+ "blablabla".byterindex("la", 3).should == 1
+ "blablabla".byterindex("la", 4).should == 4
+
+ "blablabla".byterindex("lab", 1).should == 1
+ "blablabla".byterindex("lab", 2).should == 1
+ "blablabla".byterindex("lab", 3).should == 1
+ "blablabla".byterindex("lab", 4).should == 4
+
+ "blablabla".byterindex("ab", 2).should == 2
+ "blablabla".byterindex("ab", 3).should == 2
+ "blablabla".byterindex("ab", 4).should == 2
+ "blablabla".byterindex("ab", 5).should == 5
+
+ "blablabla".byterindex("", 0).should == 0
+ "blablabla".byterindex("", 1).should == 1
+ "blablabla".byterindex("", 2).should == 2
+ "blablabla".byterindex("", 7).should == 7
+ "blablabla".byterindex("", 8).should == 8
+ "blablabla".byterindex("", 9).should == 9
+ "blablabla".byterindex("", 10).should == 9
+ end
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byterindex(needle, offset).should ==
- str.byterindex(needle, offset + str.length)
- end
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
end
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byterindex("B").should == nil
- "blablabla".byterindex("z").should == nil
- "blablabla".byterindex("BLA").should == nil
- "blablabla".byterindex("blablablabla").should == nil
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex("B").should == nil
+ "blablabla".byterindex("z").should == nil
+ "blablabla".byterindex("BLA").should == nil
+ "blablabla".byterindex("blablablabla").should == nil
- "hello".byterindex("lo", 0).should == nil
- "hello".byterindex("lo", 1).should == nil
- "hello".byterindex("lo", 2).should == nil
+ "hello".byterindex("lo", 0).should == nil
+ "hello".byterindex("lo", 1).should == nil
+ "hello".byterindex("lo", 2).should == nil
- "hello".byterindex("llo", 0).should == nil
- "hello".byterindex("llo", 1).should == nil
+ "hello".byterindex("llo", 0).should == nil
+ "hello".byterindex("llo", 1).should == nil
- "hello".byterindex("el", 0).should == nil
- "hello".byterindex("ello", 0).should == nil
+ "hello".byterindex("el", 0).should == nil
+ "hello".byterindex("ello", 0).should == nil
- "hello".byterindex("", -6).should == nil
- "hello".byterindex("", -7).should == nil
+ "hello".byterindex("", -6).should == nil
+ "hello".byterindex("", -7).should == nil
- "hello".byterindex("h", -6).should == nil
- end
+ "hello".byterindex("h", -6).should == nil
+ end
- it "tries to convert start_offset to an integer via to_int" do
- obj = mock('5')
- def obj.to_int() 5 end
- "str".byterindex("st", obj).should == 0
+ it "tries to convert start_offset to an integer via to_int" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex("st", obj).should == 0
- obj = mock('5')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args) 5 end
- "str".byterindex("st", obj).should == 0
- end
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) 5 end
+ "str".byterindex("st", obj).should == 0
+ end
- it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
- end
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex("st", nil) }.should.raise(TypeError)
+ end
- it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil
- end
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil
+ end
- it "handles a substring in a subset encoding" do
- 'été'.byterindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
- end
+ it "handles a substring in a subset encoding" do
+ 'été'.byterindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
end
end
describe "String#byterindex with Regexp" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byterindex(string) for escaped string regexps" do
- ["blablabla", "hello cruel world...!"].each do |str|
- ["", "b", "bla", "lab", "o c", "d."].each do |needle|
- regexp = Regexp.new(Regexp.escape(needle))
- str.byterindex(regexp).should == str.byterindex(needle)
-
- 0.upto(str.size + 1) do |start|
- str.byterindex(regexp, start).should == str.byterindex(needle, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(regexp, start).should == str.byterindex(needle, start)
- end
+ it "behaves the same as String#byterindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byterindex(regexp).should == str.byterindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
end
end
end
+ end
- it "returns the index of the first match from the end of string of regexp" do
- "blablabla".byterindex(/bla/).should == 6
- "blablabla".byterindex(/BLA/i).should == 6
-
- "blablabla".byterindex(/.{0}/).should == 9
- "blablabla".byterindex(/.{1}/).should == 8
- "blablabla".byterindex(/.{2}/).should == 7
- "blablabla".byterindex(/.{6}/).should == 3
- "blablabla".byterindex(/.{9}/).should == 0
+ it "returns the index of the first match from the end of string of regexp" do
+ "blablabla".byterindex(/bla/).should == 6
+ "blablabla".byterindex(/BLA/i).should == 6
- "blablabla".byterindex(/.*/).should == 9
- "blablabla".byterindex(/.+/).should == 8
+ "blablabla".byterindex(/.{0}/).should == 9
+ "blablabla".byterindex(/.{1}/).should == 8
+ "blablabla".byterindex(/.{2}/).should == 7
+ "blablabla".byterindex(/.{6}/).should == 3
+ "blablabla".byterindex(/.{9}/).should == 0
- "blablabla".byterindex(/bla|a/).should == 8
+ "blablabla".byterindex(/.*/).should == 9
+ "blablabla".byterindex(/.+/).should == 8
- not_supported_on :opal do
- "blablabla".byterindex(/\A/).should == 0
- "blablabla".byterindex(/\Z/).should == 9
- "blablabla".byterindex(/\z/).should == 9
- "blablabla\n".byterindex(/\Z/).should == 10
- "blablabla\n".byterindex(/\z/).should == 10
- end
+ "blablabla".byterindex(/bla|a/).should == 8
- "blablabla".byterindex(/^/).should == 0
- not_supported_on :opal do
- "\nblablabla".byterindex(/^/).should == 1
- "b\nlablabla".byterindex(/^/).should == 2
- end
- "blablabla".byterindex(/$/).should == 9
-
- "blablabla".byterindex(/.l./).should == 6
+ not_supported_on :opal do
+ "blablabla".byterindex(/\A/).should == 0
+ "blablabla".byterindex(/\Z/).should == 9
+ "blablabla".byterindex(/\z/).should == 9
+ "blablabla\n".byterindex(/\Z/).should == 10
+ "blablabla\n".byterindex(/\z/).should == 10
end
- it "starts the search at the given offset" do
- "blablabla".byterindex(/.{0}/, 5).should == 5
- "blablabla".byterindex(/.{1}/, 5).should == 5
- "blablabla".byterindex(/.{2}/, 5).should == 5
- "blablabla".byterindex(/.{3}/, 5).should == 5
- "blablabla".byterindex(/.{4}/, 5).should == 5
-
- "blablabla".byterindex(/.{0}/, 3).should == 3
- "blablabla".byterindex(/.{1}/, 3).should == 3
- "blablabla".byterindex(/.{2}/, 3).should == 3
- "blablabla".byterindex(/.{5}/, 3).should == 3
- "blablabla".byterindex(/.{6}/, 3).should == 3
-
- "blablabla".byterindex(/.l./, 0).should == 0
- "blablabla".byterindex(/.l./, 1).should == 0
- "blablabla".byterindex(/.l./, 2).should == 0
- "blablabla".byterindex(/.l./, 3).should == 3
-
- "blablablax".byterindex(/.x/, 10).should == 8
- "blablablax".byterindex(/.x/, 9).should == 8
- "blablablax".byterindex(/.x/, 8).should == 8
-
- "blablablax".byterindex(/..x/, 10).should == 7
- "blablablax".byterindex(/..x/, 9).should == 7
- "blablablax".byterindex(/..x/, 8).should == 7
- "blablablax".byterindex(/..x/, 7).should == 7
-
- not_supported_on :opal do
- "blablabla\n".byterindex(/\Z/, 9).should == 9
- end
+ "blablabla".byterindex(/^/).should == 0
+ not_supported_on :opal do
+ "\nblablabla".byterindex(/^/).should == 1
+ "b\nlablabla".byterindex(/^/).should == 2
end
+ "blablabla".byterindex(/$/).should == 9
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ "blablabla".byterindex(/.l./).should == 6
+ end
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byterindex(needle, offset).should ==
- str.byterindex(needle, offset + str.length)
- end
- end
+ it "starts the search at the given offset" do
+ "blablabla".byterindex(/.{0}/, 5).should == 5
+ "blablabla".byterindex(/.{1}/, 5).should == 5
+ "blablabla".byterindex(/.{2}/, 5).should == 5
+ "blablabla".byterindex(/.{3}/, 5).should == 5
+ "blablabla".byterindex(/.{4}/, 5).should == 5
+
+ "blablabla".byterindex(/.{0}/, 3).should == 3
+ "blablabla".byterindex(/.{1}/, 3).should == 3
+ "blablabla".byterindex(/.{2}/, 3).should == 3
+ "blablabla".byterindex(/.{5}/, 3).should == 3
+ "blablabla".byterindex(/.{6}/, 3).should == 3
+
+ "blablabla".byterindex(/.l./, 0).should == 0
+ "blablabla".byterindex(/.l./, 1).should == 0
+ "blablabla".byterindex(/.l./, 2).should == 0
+ "blablabla".byterindex(/.l./, 3).should == 3
+
+ "blablablax".byterindex(/.x/, 10).should == 8
+ "blablablax".byterindex(/.x/, 9).should == 8
+ "blablablax".byterindex(/.x/, 8).should == 8
+
+ "blablablax".byterindex(/..x/, 10).should == 7
+ "blablablax".byterindex(/..x/, 9).should == 7
+ "blablablax".byterindex(/..x/, 8).should == 7
+ "blablablax".byterindex(/..x/, 7).should == 7
+
+ not_supported_on :opal do
+ "blablabla\n".byterindex(/\Z/, 9).should == 9
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byterindex(/BLA/).should == nil
- "blablabla".byterindex(/.{10}/).should == nil
- "blablablax".byterindex(/.x/, 7).should == nil
- "blablablax".byterindex(/..x/, 6).should == nil
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- not_supported_on :opal do
- "blablabla".byterindex(/\Z/, 5).should == nil
- "blablabla".byterindex(/\z/, 5).should == nil
- "blablabla\n".byterindex(/\z/, 9).should == nil
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
end
end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex(/BLA/).should == nil
+ "blablabla".byterindex(/.{10}/).should == nil
+ "blablablax".byterindex(/.x/, 7).should == nil
+ "blablablax".byterindex(/..x/, 6).should == nil
not_supported_on :opal do
- it "supports \\G which matches at the given start offset" do
- "helloYOU.".byterindex(/YOU\G/, 8).should == 5
- "helloYOU.".byterindex(/YOU\G/).should == nil
-
- idx = "helloYOUall!".index("YOU")
- re = /YOU.+\G.+/
- # The # marks where \G will match.
- [
- ["helloYOU#all.", nil],
- ["helloYOUa#ll.", idx],
- ["helloYOUal#l.", idx],
- ["helloYOUall#.", idx],
- ["helloYOUall.#", nil]
- ].each do |i|
- start = i[0].index("#")
- str = i[0].delete("#")
-
- str.byterindex(re, start).should == i[1]
- end
+ "blablabla".byterindex(/\Z/, 5).should == nil
+ "blablabla".byterindex(/\z/, 5).should == nil
+ "blablabla\n".byterindex(/\z/, 9).should == nil
+ end
+ end
+
+ not_supported_on :opal do
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byterindex(/YOU\G/, 8).should == 5
+ "helloYOU.".byterindex(/YOU\G/).should == nil
+
+ idx = "helloYOUall!".index("YOU")
+ re = /YOU.+\G.+/
+ # The # marks where \G will match.
+ [
+ ["helloYOU#all.", nil],
+ ["helloYOUa#ll.", idx],
+ ["helloYOUal#l.", idx],
+ ["helloYOUall#.", idx],
+ ["helloYOUall.#", nil]
+ ].each do |i|
+ start = i[0].index("#")
+ str = i[0].delete("#")
+
+ str.byterindex(re, start).should == i[1]
end
end
+ end
- it "tries to convert start_offset to an integer" do
- obj = mock('5')
- def obj.to_int() 5 end
- "str".byterindex(/../, obj).should == 1
+ it "tries to convert start_offset to an integer" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex(/../, obj).should == 1
- obj = mock('5')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args); 5; end
- "str".byterindex(/../, obj).should == 1
- end
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args); 5; end
+ "str".byterindex(/../, obj).should == 1
+ end
- it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
- end
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex(/../, nil) }.should.raise(TypeError)
+ end
- it "returns the reverse byte index of a multibyte character" do
- "ありがりがとう".byterindex("が").should == 12
- "ありがりがとう".byterindex(/が/).should == 12
- end
+ it "returns the reverse byte index of a multibyte character" do
+ "ありがりがとう".byterindex("が").should == 12
+ "ありがりがとう".byterindex(/が/).should == 12
+ end
- it "returns the character index before the finish" do
- "ありがりがとう".byterindex("が", 9).should == 6
- "ありがりがとう".byterindex(/が/, 9).should == 6
- end
+ it "returns the character index before the finish" do
+ "ありがりがとう".byterindex("が", 9).should == 6
+ "ありがりがとう".byterindex(/が/, 9).should == 6
end
end
diff --git a/spec/ruby/core/string/bytes_spec.rb b/spec/ruby/core/string/bytes_spec.rb
index 02151eebbc..e6019fb987 100644
--- a/spec/ruby/core/string/bytes_spec.rb
+++ b/spec/ruby/core/string/bytes_spec.rb
@@ -9,7 +9,7 @@ describe "String#bytes" do
end
it "returns an Array when no block is given" do
- @utf8.bytes.should be_an_instance_of(Array)
+ @utf8.bytes.should.instance_of?(Array)
end
it "yields each byte to a block if one is given, returning self" do
@@ -23,8 +23,8 @@ describe "String#bytes" do
end
it "returns bytes as Integers" do
- @ascii.bytes.to_a.each {|b| b.should be_an_instance_of(Integer)}
- @utf8_ascii.bytes { |b| b.should be_an_instance_of(Integer) }
+ @ascii.bytes.to_a.each {|b| b.should.instance_of?(Integer)}
+ @utf8_ascii.bytes { |b| b.should.instance_of?(Integer) }
end
it "agrees with #unpack('C*')" do
diff --git a/spec/ruby/core/string/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb
index 9fe504aeb1..4ad9e8d8f1 100644
--- a/spec/ruby/core/string/byteslice_spec.rb
+++ b/spec/ruby/core/string/byteslice_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/slice'
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
index 5cb3b2c158..3e5e6fe1ee 100644
--- a/spec/ruby/core/string/bytesplice_spec.rb
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -3,296 +3,288 @@
require_relative '../../spec_helper'
describe "String#bytesplice" do
- ruby_version_is "3.2" do
- it "raises IndexError when index is less than -bytesize" do
- -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
- end
-
- it "raises IndexError when index is greater than bytesize" do
- -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
- end
-
- it "raises IndexError for negative length" do
- -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
- end
-
- it "replaces with integer indices" do
- "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
- "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
- "hello".bytesplice(0, 1, "xxx").should == "xxxello"
- "hello".bytesplice(0, 5, "xxx").should == "xxx"
- "hello".bytesplice(0, 6, "xxx").should == "xxx"
- end
-
- it "raises RangeError when range left boundary is less than -bytesize" do
- -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
- end
-
- it "replaces with ranges" do
- "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
- "hello".bytesplice(0...0, "xxx").should == "xxxhello"
- "hello".bytesplice(0..0, "xxx").should == "xxxello"
- "hello".bytesplice(0...1, "xxx").should == "xxxello"
- "hello".bytesplice(0..1, "xxx").should == "xxxllo"
- "hello".bytesplice(0..-1, "xxx").should == "xxx"
- "hello".bytesplice(0...5, "xxx").should == "xxx"
- "hello".bytesplice(0...6, "xxx").should == "xxx"
- end
-
- it "raises TypeError when integer index is provided without length argument" do
- -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
- end
-
- it "replaces on an empty string" do
- "".bytesplice(0, 0, "").should == ""
- "".bytesplice(0, 0, "xxx").should == "xxx"
- end
-
- it "mutates self" do
- s = "hello"
- s.bytesplice(2, 1, "xxx").should.equal?(s)
- end
-
- it "raises when string is frozen" do
- s = "hello".freeze
- -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
- end
-
- ruby_version_is "3.3" do
- it "raises IndexError when str_index is less than -bytesize" do
- -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string")
- end
-
- it "raises IndexError when str_index is greater than bytesize" do
- -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string")
- end
-
- it "raises IndexError for negative str length" do
- -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2")
- end
-
- it "replaces with integer str indices" do
- "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
- end
-
- it "raises RangeError when str range left boundary is less than -bytesize" do
- -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range")
- end
-
- it "replaces with str ranges" do
- "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
- "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
- "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
- "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
- "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
- "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
- "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
- "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
- end
-
- it "raises ArgumentError when integer str index is provided without str length argument" do
- -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
- end
-
- it "replaces on an empty string with str index/length" do
- "".bytesplice(0, 0, "", 0, 0).should == ""
- "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
- end
-
- it "mutates self with substring and str index/length" do
- s = "hello"
- s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
- s.should.eql?("hexxlo")
- end
-
- it "raises when string is frozen and str index/length" do
- s = "hello".freeze
- -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
-
- it "replaces on an empty string with str range" do
- "".bytesplice(0..0, "", 0..0).should == ""
- "".bytesplice(0..0, "xyz", 0..1).should == "xy"
- end
-
- it "mutates self with substring and str range" do
- s = "hello"
- s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
- s.should.eql?("heyzlo")
- end
-
- it "raises when string is frozen and str range" do
- s = "hello".freeze
- -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
+ it "raises IndexError when index is less than -bytesize" do
+ -> { "hello".bytesplice(-6, 0, "xxx") }.should.raise(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when index is greater than bytesize" do
+ -> { "hello".bytesplice(6, 0, "xxx") }.should.raise(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative length" do
+ -> { "abc".bytesplice(0, -2, "") }.should.raise(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer indices" do
+ "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 1, "xxx").should == "xxxello"
+ "hello".bytesplice(0, 5, "xxx").should == "xxx"
+ "hello".bytesplice(0, 6, "xxx").should == "xxx"
+ end
+
+ it "raises RangeError when range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(-6...-6, "xxx") }.should.raise(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with ranges" do
+ "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
+ "hello".bytesplice(0...0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0..0, "xxx").should == "xxxello"
+ "hello".bytesplice(0...1, "xxx").should == "xxxello"
+ "hello".bytesplice(0..1, "xxx").should == "xxxllo"
+ "hello".bytesplice(0..-1, "xxx").should == "xxx"
+ "hello".bytesplice(0...5, "xxx").should == "xxx"
+ "hello".bytesplice(0...6, "xxx").should == "xxx"
+ end
+
+ it "raises TypeError when integer index is provided without length argument" do
+ -> { "hello".bytesplice(0, "xxx") }.should.raise(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "replaces on an empty string" do
+ "".bytesplice(0, 0, "").should == ""
+ "".bytesplice(0, 0, "xxx").should == "xxx"
+ end
+
+ it "mutates self" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx").should.equal?(s)
+ end
+
+ it "raises when string is frozen" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx") }.should.raise(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ it "raises IndexError when str_index is less than -bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should.raise(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when str_index is greater than bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should.raise(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative str length" do
+ -> { "abc".bytesplice(0, 1, "", 0, -2) }.should.raise(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer str indices" do
+ "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
+ end
+
+ it "raises RangeError when str range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should.raise(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with str ranges" do
+ "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
+ "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
+ end
+
+ it "raises ArgumentError when integer str index is provided without str length argument" do
+ -> { "hello".bytesplice(0, 1, "xxx", 0) }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
+ end
+
+ it "replaces on an empty string with str index/length" do
+ "".bytesplice(0, 0, "", 0, 0).should == ""
+ "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
+ end
+
+ it "mutates self with substring and str index/length" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
+ s.should.eql?("hexxlo")
+ end
+
+ it "raises when string is frozen and str index/length" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should.raise(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ it "replaces on an empty string with str range" do
+ "".bytesplice(0..0, "", 0..0).should == ""
+ "".bytesplice(0..0, "xyz", 0..1).should == "xy"
+ end
+
+ it "mutates self with substring and str range" do
+ s = "hello"
+ s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
+ s.should.eql?("heyzlo")
+ end
+
+ it "raises when string is frozen and str range" do
+ s = "hello".freeze
+ -> { s.bytesplice(2..2, "yzx", 0..1) }.should.raise(FrozenError, "can't modify frozen String: \"hello\"")
end
end
describe "String#bytesplice with multibyte characters" do
- ruby_version_is "3.2" do
- it "raises IndexError when index is out of byte size boundary" do
- -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
- end
-
- it "raises IndexError when index is not on a codepoint boundary" do
- -> { "こんにちは".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
-
- it "raises IndexError when length is not matching the codepoint boundary" do
- -> { "こんにちは".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "こんにちは".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- end
-
- it "replaces with integer indices" do
- "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは"
- "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは"
- "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは"
- "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは"
- "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx"
- end
-
- it "replaces with range" do
- "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは"
- "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは"
- "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは"
- "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは"
- "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは"
- "こんにちは".bytesplice(0..-1, "xxx").should == "xxx"
- "こんにちは".bytesplice(0...15, "xxx").should == "xxx"
- "こんにちは".bytesplice(0...18, "xxx").should == "xxx"
- end
-
- it "treats negative length for range as 0" do
- "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは"
- "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは"
- "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは"
- end
-
- it "raises when ranges not match codepoint boundaries" do
- -> { "こんにちは".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "こんにちは".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- # Begin is incorrect
- -> { "こんにちは".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
- -> { "こんにちは".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
- # End is incorrect
- -> { "こんにちは".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
- -> { "こんにちは".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
- end
-
- it "deals with a different encoded argument" do
- s = "こんにちは"
- s.encoding.should == Encoding::UTF_8
- sub = "xxxxxx"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(0, 3, sub)
- result.should == "xxxxxxんにちは"
- result.encoding.should == Encoding::UTF_8
-
- s = "xxxxxx"
- s.force_encoding(Encoding::US_ASCII)
- sub = "こんにちは"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(0, 3, sub)
- result.should == "こんにちはxxx"
- result.encoding.should == Encoding::UTF_8
- end
- end
-
- ruby_version_is "3.3" do
- it "raises IndexError when str_index is out of byte size boundary" do
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string")
- end
-
- it "raises IndexError when str_index is not on a codepoint boundary" do
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
-
- it "raises IndexError when str_length is not matching the codepoint boundary" do
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- end
-
- it "replaces with integer str indices" do
- "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは"
- "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは"
- "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは"
- "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは"
- "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは"
- end
-
- it "replaces with str range" do
- "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは"
- end
-
- it "treats negative length for str range as 0" do
- "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは"
- end
-
- it "raises when ranges not match codepoint boundaries in str" do
- -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- # Begin is incorrect
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary")
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary")
- # End is incorrect
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary")
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary")
- end
-
- it "deals with a different encoded argument with str index/length" do
- s = "こんにちは"
- s.encoding.should == Encoding::UTF_8
- sub = "goodbye"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(3, 3, sub, 0, 3)
- result.should == "こgooにちは"
- result.encoding.should == Encoding::UTF_8
-
- s = "hello"
- s.force_encoding(Encoding::US_ASCII)
- sub = "こんにちは"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(1, 2, sub, 3, 3)
- result.should == "hんlo"
- result.encoding.should == Encoding::UTF_8
- end
-
- it "deals with a different encoded argument with str range" do
- s = "こんにちは"
- s.encoding.should == Encoding::UTF_8
- sub = "goodbye"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(3..5, sub, 0..2)
- result.should == "こgooにちは"
- result.encoding.should == Encoding::UTF_8
-
- s = "hello"
- s.force_encoding(Encoding::US_ASCII)
- sub = "こんにちは"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(1..2, sub, 3..5)
- result.should == "hんlo"
- result.encoding.should == Encoding::UTF_8
- end
+ it "raises IndexError when index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should.raise(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(1, 0, "xxx") }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(0, 1, "xxx") }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0, 2, "xxx") }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer indices" do
+ "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは"
+ "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx"
+ end
+
+ it "replaces with range" do
+ "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは"
+ "こんにちは".bytesplice(0..-1, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...15, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...18, "xxx").should == "xxx"
+ end
+
+ it "treats negative length for range as 0" do
+ "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは"
+ "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries" do
+ -> { "こんにちは".bytesplice(0..0, "x") }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0..1, "x") }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(-4..-1, "x") }.should.raise(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-5..-1, "x") }.should.raise(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(-3..-2, "x") }.should.raise(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-3..-3, "x") }.should.raise(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "xxxxxx"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "xxxxxxんにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "xxxxxx"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "こんにちはxxx"
+ result.encoding.should == Encoding::UTF_8
+ end
+
+ it "raises IndexError when str_index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should.raise(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when str_index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when str_length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer str indices" do
+ "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは"
+ "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは"
+ end
+
+ it "replaces with str range" do
+ "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは"
+ end
+
+ it "treats negative length for str range as 0" do
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries in str" do
+ -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should.raise(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should.raise(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should.raise(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should.raise(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument with str index/length" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3, 3, sub, 0, 3)
+ result.should == "こgooにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1, 2, sub, 3, 3)
+ result.should == "hんlo"
+ result.encoding.should == Encoding::UTF_8
+ end
+
+ it "deals with a different encoded argument with str range" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3..5, sub, 0..2)
+ result.should == "こgooにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1..2, sub, 3..5)
+ result.should == "hんlo"
+ result.encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index 5e59b656c5..12b1675c2e 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -28,7 +28,7 @@ describe "String#capitalize" do
capitalized.should == "Sset"
capitalized.size.should == 4
capitalized.bytesize.should == 4
- capitalized.ascii_only?.should be_true
+ capitalized.ascii_only?.should == true
end
end
@@ -52,7 +52,7 @@ describe "String#capitalize" do
end
it "does not allow any other additional option" do
- -> { "iSa".capitalize(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "iSa".capitalize(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -66,21 +66,21 @@ describe "String#capitalize" do
end
it "does not allow any other additional option" do
- -> { "iß".capitalize(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "iß".capitalize(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { "abc".capitalize(:fold) }.should raise_error(ArgumentError)
+ -> { "abc".capitalize(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "abc".capitalize(:invalid_option) }.should.raise(ArgumentError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String)
- StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").capitalize.should.instance_of?(String)
+ StringSpecs::MyString.new("Hello").capitalize.should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -91,7 +91,7 @@ end
describe "String#capitalize!" do
it "capitalizes self in place" do
a = +"hello"
- a.capitalize!.should equal(a)
+ a.capitalize!.should.equal?(a)
a.should == "Hello"
end
@@ -127,7 +127,7 @@ describe "String#capitalize!" do
capitalized.should == "Sset"
capitalized.size.should == 4
capitalized.bytesize.should == 4
- capitalized.ascii_only?.should be_true
+ capitalized.ascii_only?.should == true
end
end
@@ -159,7 +159,7 @@ describe "String#capitalize!" do
end
it "does not allow any other additional option" do
- -> { a = "iSa"; a.capitalize!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "iSa"; a.capitalize!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -177,16 +177,16 @@ describe "String#capitalize!" do
end
it "does not allow any other additional option" do
- -> { a = "iß"; a.capitalize!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "iß"; a.capitalize!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { a = "abc"; a.capitalize!(:fold) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.capitalize!(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { a = "abc"; a.capitalize!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.capitalize!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil when no changes are made" do
@@ -201,7 +201,7 @@ describe "String#capitalize!" do
it "raises a FrozenError when self is frozen" do
["", "Hello", "hello"].each do |a|
a.freeze
- -> { a.capitalize! }.should raise_error(FrozenError)
+ -> { a.capitalize! }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb
index 81ebea557c..90577aaac0 100644
--- a/spec/ruby/core/string/casecmp_spec.rb
+++ b/spec/ruby/core/string/casecmp_spec.rb
@@ -26,11 +26,11 @@ describe "String#casecmp independent of case" do
end
it "returns nil if other can't be converted to a string" do
- "abc".casecmp(mock('abc')).should be_nil
+ "abc".casecmp(mock('abc')).should == nil
end
it "returns nil if incompatible encodings" do
- "あれ".casecmp("れ".encode(Encoding::EUC_JP)).should be_nil
+ "あれ".casecmp("れ".encode(Encoding::EUC_JP)).should == nil
end
describe "in UTF-8 mode" do
@@ -143,7 +143,7 @@ describe 'String#casecmp? independent of case' do
end
it "returns nil if incompatible encodings" do
- "あれ".casecmp?("れ".encode(Encoding::EUC_JP)).should be_nil
+ "あれ".casecmp?("れ".encode(Encoding::EUC_JP)).should == nil
end
describe 'for UNICODE characters' do
@@ -190,11 +190,11 @@ describe 'String#casecmp? independent of case' do
end
it "case folds" do
- "ß".casecmp?("ss").should be_true
+ "ß".casecmp?("ss").should == true
end
it "returns nil if other can't be converted to a string" do
- "abc".casecmp?(mock('abc')).should be_nil
+ "abc".casecmp?(mock('abc')).should == nil
end
it "returns true for empty strings in different encodings" do
diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb
index 1667b59327..ac5b8a2ff3 100644
--- a/spec/ruby/core/string/center_spec.rb
+++ b/spec/ruby/core/string/center_spec.rb
@@ -57,10 +57,10 @@ describe "String#center with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- -> { "hello".center("x") }.should raise_error(TypeError)
- -> { "hello".center("x", "y") }.should raise_error(TypeError)
- -> { "hello".center([]) }.should raise_error(TypeError)
- -> { "hello".center(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".center("x") }.should.raise(TypeError)
+ -> { "hello".center("x", "y") }.should.raise(TypeError)
+ -> { "hello".center([]) }.should.raise(TypeError)
+ -> { "hello".center(mock('x')) }.should.raise(TypeError)
end
it "calls #to_str to convert padstr to a String" do
@@ -71,23 +71,23 @@ describe "String#center with length, padding" do
end
it "raises a TypeError when padstr can't be converted to a string" do
- -> { "hello".center(20, 100) }.should raise_error(TypeError)
- -> { "hello".center(20, []) }.should raise_error(TypeError)
- -> { "hello".center(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".center(20, 100) }.should.raise(TypeError)
+ -> { "hello".center(20, []) }.should.raise(TypeError)
+ -> { "hello".center(20, mock('x')) }.should.raise(TypeError)
end
it "raises an ArgumentError if padstr is empty" do
- -> { "hello".center(10, "") }.should raise_error(ArgumentError)
- -> { "hello".center(0, "") }.should raise_error(ArgumentError)
+ -> { "hello".center(10, "") }.should.raise(ArgumentError)
+ -> { "hello".center(0, "") }.should.raise(ArgumentError)
end
it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").center(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").center(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").center(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
- "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "".center(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
+ "foo".center(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
end
describe "with width" do
@@ -95,7 +95,7 @@ describe "String#center with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.center 6
result.should == " abc "
- result.encoding.should equal(Encoding::IBM437)
+ result.encoding.should.equal?(Encoding::IBM437)
end
end
@@ -104,14 +104,14 @@ describe "String#center with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.center 6, "あ"
result.should == "あabcああ"
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ア".encode Encoding::EUC_JP
-> do
"あれ".center 5, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
index 968e4ec1f0..6a5e846db2 100644
--- a/spec/ruby/core/string/chilled_string_spec.rb
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -47,6 +47,14 @@ describe "chilled String" do
input.should == "chilled-mutated"
end
+ it "emits a warning for concatenated strings" do
+ input = "still" "+chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "still+chilled-mutated"
+ end
+
it "emits a warning on singleton_class creation" do
-> {
"chilled".singleton_class
@@ -65,7 +73,7 @@ describe "chilled String" do
-> {
-> {
input << "mutated"
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
}.should_not complain(/literal string will be frozen in the future/)
end
end
@@ -134,7 +142,7 @@ describe "chilled String" do
-> {
-> {
input << "mutated"
- }.should raise_error(FrozenError)
+ }.should.raise(FrozenError)
}.should_not complain(/string returned by :chilled\.to_s will be frozen in the future/)
end
end
diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb
index d27c84c6f6..3a8550892f 100644
--- a/spec/ruby/core/string/chomp_spec.rb
+++ b/spec/ruby/core/string/chomp_spec.rb
@@ -22,7 +22,7 @@ describe "String#chomp" do
it "returns a copy of the String when it is not modified" do
str = "abc"
- str.chomp.should_not equal(str)
+ str.chomp.should_not.equal?(str)
end
it "removes one trailing newline" do
@@ -47,7 +47,7 @@ describe "String#chomp" do
it "returns String instances when called on a subclass" do
str = StringSpecs::MyString.new("hello\n").chomp
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
end
it "removes trailing characters that match $/ when it has been assigned a value" do
@@ -67,7 +67,7 @@ describe "String#chomp" do
it "returns a copy of the String" do
str = "abc"
- str.chomp(nil).should_not equal(str)
+ str.chomp(nil).should_not.equal?(str)
end
it "returns an empty String when self is empty" do
@@ -133,7 +133,7 @@ describe "String#chomp" do
it "raises a TypeError if #to_str does not return a String" do
arg = mock("string chomp")
arg.should_receive(:to_str).and_return(1)
- -> { "abc".chomp(arg) }.should raise_error(TypeError)
+ -> { "abc".chomp(arg) }.should.raise(TypeError)
end
end
@@ -171,11 +171,11 @@ describe "String#chomp!" do
it "modifies self" do
str = "abc\n"
- str.chomp!.should equal(str)
+ str.chomp!.should.equal?(str)
end
it "returns nil if self is not modified" do
- "abc".chomp!.should be_nil
+ "abc".chomp!.should == nil
end
it "removes one trailing newline" do
@@ -191,12 +191,12 @@ describe "String#chomp!" do
end
it "returns nil when self is empty" do
- "".chomp!.should be_nil
+ "".chomp!.should == nil
end
it "returns subclass instances when called on a subclass" do
str = StringSpecs::MyString.new("hello\n").chomp!
- str.should be_an_instance_of(StringSpecs::MyString)
+ str.should.instance_of?(StringSpecs::MyString)
end
it "removes trailing characters that match $/ when it has been assigned a value" do
@@ -207,11 +207,11 @@ describe "String#chomp!" do
describe "when passed nil" do
it "returns nil" do
- "abc\r\n".chomp!(nil).should be_nil
+ "abc\r\n".chomp!(nil).should == nil
end
it "returns nil when self is empty" do
- "".chomp!(nil).should be_nil
+ "".chomp!(nil).should == nil
end
end
@@ -225,7 +225,7 @@ describe "String#chomp!" do
end
it "does not remove a final carriage return" do
- "abc\r".chomp!("").should be_nil
+ "abc\r".chomp!("").should == nil
end
it "removes more than one trailing newlines" do
@@ -237,7 +237,7 @@ describe "String#chomp!" do
end
it "returns nil when self is empty" do
- "".chomp!("").should be_nil
+ "".chomp!("").should == nil
end
end
@@ -255,7 +255,7 @@ describe "String#chomp!" do
end
it "returns nil when self is empty" do
- "".chomp!("\n").should be_nil
+ "".chomp!("\n").should == nil
end
end
@@ -269,7 +269,7 @@ describe "String#chomp!" do
it "raises a TypeError if #to_str does not return a String" do
arg = mock("string chomp")
arg.should_receive(:to_str).and_return(1)
- -> { "abc".chomp!(arg) }.should raise_error(TypeError)
+ -> { "abc".chomp!(arg) }.should.raise(TypeError)
end
end
@@ -279,11 +279,11 @@ describe "String#chomp!" do
end
it "returns nil if the argument does not match the trailing characters" do
- "abc".chomp!("def").should be_nil
+ "abc".chomp!("def").should == nil
end
it "returns nil when self is empty" do
- "".chomp!("abc").should be_nil
+ "".chomp!("abc").should == nil
end
end
@@ -291,15 +291,15 @@ describe "String#chomp!" do
a = "string\n\r"
a.freeze
- -> { a.chomp! }.should raise_error(FrozenError)
+ -> { a.chomp! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance when it would not be modified" do
a = "string\n\r"
a.freeze
- -> { a.chomp!(nil) }.should raise_error(FrozenError)
- -> { a.chomp!("x") }.should raise_error(FrozenError)
+ -> { a.chomp!(nil) }.should.raise(FrozenError)
+ -> { a.chomp!("x") }.should.raise(FrozenError)
end
end
@@ -346,7 +346,7 @@ describe "String#chomp!" do
end
it "returns nil when the String is not modified" do
- "あれ".chomp!.should be_nil
+ "あれ".chomp!.should == nil
end
it "removes the final carriage return, newline from a multibyte String" do
diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb
index 99c2c82190..2113da543b 100644
--- a/spec/ruby/core/string/chop_spec.rb
+++ b/spec/ruby/core/string/chop_spec.rb
@@ -47,11 +47,11 @@ describe "String#chop" do
it "returns a new string when applied to an empty string" do
s = ""
- s.chop.should_not equal(s)
+ s.chop.should_not.equal?(s)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello\n").chop.should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -99,21 +99,21 @@ describe "String#chop!" do
it "returns self if modifications were made" do
str = "hello"
- str.chop!.should equal(str)
+ str.chop!.should.equal?(str)
end
it "returns nil when called on an empty string" do
- "".chop!.should be_nil
+ "".chop!.should == nil
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "string\n\r".freeze.chop! }.should raise_error(FrozenError)
+ -> { "string\n\r".freeze.chop! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance that would not be modified" do
a = ""
a.freeze
- -> { a.chop! }.should raise_error(FrozenError)
+ -> { a.chop! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/chr_spec.rb b/spec/ruby/core/string/chr_spec.rb
index 9ed29542e6..26c7d51202 100644
--- a/spec/ruby/core/string/chr_spec.rb
+++ b/spec/ruby/core/string/chr_spec.rb
@@ -3,11 +3,11 @@ require_relative '../../spec_helper'
describe "String#chr" do
it "returns a copy of self" do
s = 'e'
- s.should_not equal s.chr
+ s.should_not.equal? s.chr
end
it "returns a String" do
- 'glark'.chr.should be_an_instance_of(String)
+ 'glark'.chr.should.instance_of?(String)
end
it "returns an empty String if self is an empty String" do
diff --git a/spec/ruby/core/string/clear_spec.rb b/spec/ruby/core/string/clear_spec.rb
index 152986fd0f..d4688d3689 100644
--- a/spec/ruby/core/string/clear_spec.rb
+++ b/spec/ruby/core/string/clear_spec.rb
@@ -14,7 +14,7 @@ describe "String#clear" do
it "returns self after emptying it" do
cleared = @s.clear
cleared.should == ""
- cleared.should equal @s
+ cleared.should.equal? @s
end
it "preserves its encoding" do
@@ -32,7 +32,7 @@ describe "String#clear" do
it "raises a FrozenError if self is frozen" do
@s.freeze
- -> { @s.clear }.should raise_error(FrozenError)
- -> { "".freeze.clear }.should raise_error(FrozenError)
+ -> { @s.clear }.should.raise(FrozenError)
+ -> { "".freeze.clear }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/clone_spec.rb b/spec/ruby/core/string/clone_spec.rb
index a2ba2f9877..2cb289d2c1 100644
--- a/spec/ruby/core/string/clone_spec.rb
+++ b/spec/ruby/core/string/clone_spec.rb
@@ -43,8 +43,8 @@ describe "String#clone" do
end
it "copies frozen state" do
- @obj.freeze.clone.frozen?.should be_true
- "".freeze.clone.frozen?.should be_true
+ @obj.freeze.clone.frozen?.should == true
+ "".freeze.clone.frozen?.should == true
end
it "does not modify the original string when changing cloned string" do
diff --git a/spec/ruby/core/string/codepoints_spec.rb b/spec/ruby/core/string/codepoints_spec.rb
index b276d0baa8..51bd57d127 100644
--- a/spec/ruby/core/string/codepoints_spec.rb
+++ b/spec/ruby/core/string/codepoints_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/codepoints'
require_relative 'shared/each_codepoint_without_block'
@@ -12,7 +12,7 @@ describe "String#codepoints" do
it "raises an ArgumentError when no block is given if self has an invalid encoding" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.codepoints }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.codepoints }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb
index 9db0cff5ee..0737c131bb 100644
--- a/spec/ruby/core/string/comparison_spec.rb
+++ b/spec/ruby/core/string/comparison_spec.rb
@@ -85,7 +85,7 @@ end
# just using it as an indicator.
describe "String#<=>" do
it "returns nil if its argument provides neither #to_str nor #<=>" do
- ("abc" <=> mock('x')).should be_nil
+ ("abc" <=> mock('x')).should == nil
end
it "uses the result of calling #to_str for comparison when #to_str is defined" do
@@ -107,6 +107,6 @@ describe "String#<=>" do
def obj.<=>(other); other <=> self; end
obj.should_receive(:<=>).once
- ("abc" <=> obj).should be_nil
+ ("abc" <=> obj).should == nil
end
end
diff --git a/spec/ruby/core/string/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb
index cbd7df54e2..0194a357a0 100644
--- a/spec/ruby/core/string/concat_spec.rb
+++ b/spec/ruby/core/string/concat_spec.rb
@@ -21,7 +21,7 @@ describe "String#concat" do
it "returns self when given no arguments" do
str = +"hello"
- str.concat.should equal(str)
+ str.concat.should.equal?(str)
str.should == "hello"
end
end
diff --git a/spec/ruby/core/string/count_spec.rb b/spec/ruby/core/string/count_spec.rb
index 06ba5a4f0e..fd127c6ff2 100644
--- a/spec/ruby/core/string/count_spec.rb
+++ b/spec/ruby/core/string/count_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -23,7 +23,7 @@ describe "String#count" do
end
it "raises an ArgumentError when given no arguments" do
- -> { "hell yeah".count }.should raise_error(ArgumentError)
+ -> { "hell yeah".count }.should.raise(ArgumentError)
end
it "negates sets starting with ^" do
@@ -76,8 +76,8 @@ describe "String#count" do
it "raises if the given sequences are invalid" do
s = "hel-[()]-lo012^"
- -> { s.count("h-e") }.should raise_error(ArgumentError)
- -> { s.count("^h-e") }.should raise_error(ArgumentError)
+ -> { s.count("h-e") }.should.raise(ArgumentError)
+ -> { s.count("^h-e") }.should.raise(ArgumentError)
end
it 'returns the number of occurrences of a multi-byte character' do
@@ -98,8 +98,8 @@ describe "String#count" do
end
it "raises a TypeError when a set arg can't be converted to a string" do
- -> { "hello world".count(100) }.should raise_error(TypeError)
- -> { "hello world".count([]) }.should raise_error(TypeError)
- -> { "hello world".count(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".count(100) }.should.raise(TypeError)
+ -> { "hello world".count([]) }.should.raise(TypeError)
+ -> { "hello world".count(mock('x')) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb
index 06f84c70a4..924b4d48cf 100644
--- a/spec/ruby/core/string/crypt_spec.rb
+++ b/spec/ruby/core/string/crypt_spec.rb
@@ -15,7 +15,7 @@ describe "String#crypt" do
end
it "raises Errno::EINVAL when the salt is shorter than 29 characters" do
- -> { "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHW") }.should raise_error(Errno::EINVAL)
+ -> { "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHW") }.should.raise(Errno::EINVAL)
end
it "calls #to_str to converts the salt arg to a String" do
@@ -26,9 +26,9 @@ describe "String#crypt" do
end
it "doesn't return subclass instances" do
- StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should be_an_instance_of(String)
- "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
- StringSpecs::MyString.new("mypassword").crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should.instance_of?(String)
+ "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should.instance_of?(String)
+ StringSpecs::MyString.new("mypassword").crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should.instance_of?(String)
end
end
@@ -60,7 +60,7 @@ describe "String#crypt" do
end
it "raises an ArgumentError when the string contains NUL character" do
- -> { "poison\0null".crypt("aa") }.should raise_error(ArgumentError)
+ -> { "poison\0null".crypt("aa") }.should.raise(ArgumentError)
end
it "calls #to_str to converts the salt arg to a String" do
@@ -71,22 +71,22 @@ describe "String#crypt" do
end
it "doesn't return subclass instances" do
- StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String)
- "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
- StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").crypt("aa").should.instance_of?(String)
+ "hello".crypt(StringSpecs::MyString.new("aa")).should.instance_of?(String)
+ StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should.instance_of?(String)
end
it "raises an ArgumentError when the salt is shorter than two characters" do
- -> { "hello".crypt("") }.should raise_error(ArgumentError)
- -> { "hello".crypt("f") }.should raise_error(ArgumentError)
- -> { "hello".crypt("\x00\x00") }.should raise_error(ArgumentError)
- -> { "hello".crypt("\x00a") }.should raise_error(ArgumentError)
- -> { "hello".crypt("a\x00") }.should raise_error(ArgumentError)
+ -> { "hello".crypt("") }.should.raise(ArgumentError)
+ -> { "hello".crypt("f") }.should.raise(ArgumentError)
+ -> { "hello".crypt("\x00\x00") }.should.raise(ArgumentError)
+ -> { "hello".crypt("\x00a") }.should.raise(ArgumentError)
+ -> { "hello".crypt("a\x00") }.should.raise(ArgumentError)
end
end
it "raises a type error when the salt arg can't be converted to a string" do
- -> { "".crypt(5) }.should raise_error(TypeError)
- -> { "".crypt(mock('x')) }.should raise_error(TypeError)
+ -> { "".crypt(5) }.should.raise(TypeError)
+ -> { "".crypt(mock('x')) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
index 57d2be2cfd..2b31d80708 100644
--- a/spec/ruby/core/string/dedup_spec.rb
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -2,7 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/dedup'
describe 'String#dedup' do
- ruby_version_is '3.2' do
- it_behaves_like :string_dedup, :dedup
- end
+ it_behaves_like :string_dedup, :dedup
end
diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb
index ee7f044905..fc69adcbad 100644
--- a/spec/ruby/core/string/delete_prefix_spec.rb
+++ b/spec/ruby/core/string/delete_prefix_spec.rb
@@ -12,13 +12,13 @@ describe "String#delete_prefix" do
it "returns a copy of the string, when the prefix isn't found" do
s = 'hello'
r = s.delete_prefix('hello!')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_prefix('ell')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_prefix('')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
end
@@ -41,7 +41,7 @@ describe "String#delete_prefix" do
it "returns a String instance when called on a subclass instance" do
s = StringSpecs::MyString.new('hello')
- s.delete_prefix('hell').should be_an_instance_of(String)
+ s.delete_prefix('hell').should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -52,7 +52,7 @@ end
describe "String#delete_prefix!" do
it "removes the found prefix" do
s = 'hello'
- s.delete_prefix!('hell').should equal(s)
+ s.delete_prefix!('hell').should.equal?(s)
s.should == 'o'
end
@@ -76,8 +76,8 @@ describe "String#delete_prefix!" do
end
it "raises a FrozenError when self is frozen" do
- -> { 'hello'.freeze.delete_prefix!('hell') }.should raise_error(FrozenError)
- -> { 'hello'.freeze.delete_prefix!('') }.should raise_error(FrozenError)
- -> { ''.freeze.delete_prefix!('') }.should raise_error(FrozenError)
+ -> { 'hello'.freeze.delete_prefix!('hell') }.should.raise(FrozenError)
+ -> { 'hello'.freeze.delete_prefix!('') }.should.raise(FrozenError)
+ -> { ''.freeze.delete_prefix!('') }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb
index 6d359776e4..adb5150cff 100644
--- a/spec/ruby/core/string/delete_spec.rb
+++ b/spec/ruby/core/string/delete_spec.rb
@@ -15,7 +15,7 @@ describe "String#delete" do
end
it "raises an ArgumentError when given no arguments" do
- -> { "hell yeah".delete }.should raise_error(ArgumentError)
+ -> { "hell yeah".delete }.should.raise(ArgumentError)
end
it "negates sets starting with ^" do
@@ -63,10 +63,10 @@ describe "String#delete" do
not_supported_on :opal do
xFF = [0xFF].pack('C')
range = "\x00 - #{xFF}".force_encoding('utf-8')
- -> { "hello".delete(range).should == "" }.should raise_error(ArgumentError)
+ -> { "hello".delete(range).should == "" }.should.raise(ArgumentError)
end
- -> { "hello".delete("h-e") }.should raise_error(ArgumentError)
- -> { "hello".delete("^h-e") }.should raise_error(ArgumentError)
+ -> { "hello".delete("h-e") }.should.raise(ArgumentError)
+ -> { "hello".delete("^h-e") }.should.raise(ArgumentError)
end
it "tries to convert each set arg to a string using to_str" do
@@ -80,13 +80,13 @@ describe "String#delete" do
end
it "raises a TypeError when one set arg can't be converted to a string" do
- -> { "hello world".delete(100) }.should raise_error(TypeError)
- -> { "hello world".delete([]) }.should raise_error(TypeError)
- -> { "hello world".delete(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".delete(100) }.should.raise(TypeError)
+ -> { "hello world".delete([]) }.should.raise(TypeError)
+ -> { "hello world".delete(mock('x')) }.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
+ StringSpecs::MyString.new("oh no!!!").delete("!").should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -97,7 +97,7 @@ end
describe "String#delete!" do
it "modifies self in place and returns self" do
a = "hello"
- a.delete!("aeiou", "^e").should equal(a)
+ a.delete!("aeiou", "^e").should.equal?(a)
a.should == "hell"
end
@@ -111,7 +111,7 @@ describe "String#delete!" do
a = "hello"
a.freeze
- -> { a.delete!("") }.should raise_error(FrozenError)
- -> { a.delete!("aeiou", "^e") }.should raise_error(FrozenError)
+ -> { a.delete!("") }.should.raise(FrozenError)
+ -> { a.delete!("aeiou", "^e") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb
index 1842d75aa5..11d8fbbac1 100644
--- a/spec/ruby/core/string/delete_suffix_spec.rb
+++ b/spec/ruby/core/string/delete_suffix_spec.rb
@@ -12,13 +12,13 @@ describe "String#delete_suffix" do
it "returns a copy of the string, when the suffix isn't found" do
s = 'hello'
r = s.delete_suffix('!hello')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_suffix('ell')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
r = s.delete_suffix('')
- r.should_not equal s
+ r.should_not.equal? s
r.should == s
end
@@ -41,7 +41,7 @@ describe "String#delete_suffix" do
it "returns a String instance when called on a subclass instance" do
s = StringSpecs::MyString.new('hello')
- s.delete_suffix('ello').should be_an_instance_of(String)
+ s.delete_suffix('ello').should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -52,7 +52,7 @@ end
describe "String#delete_suffix!" do
it "removes the found prefix" do
s = 'hello'
- s.delete_suffix!('ello').should equal(s)
+ s.delete_suffix!('ello').should.equal?(s)
s.should == 'h'
end
@@ -76,8 +76,8 @@ describe "String#delete_suffix!" do
end
it "raises a FrozenError when self is frozen" do
- -> { 'hello'.freeze.delete_suffix!('ello') }.should raise_error(FrozenError)
- -> { 'hello'.freeze.delete_suffix!('') }.should raise_error(FrozenError)
- -> { ''.freeze.delete_suffix!('') }.should raise_error(FrozenError)
+ -> { 'hello'.freeze.delete_suffix!('ello') }.should.raise(FrozenError)
+ -> { 'hello'.freeze.delete_suffix!('') }.should.raise(FrozenError)
+ -> { ''.freeze.delete_suffix!('') }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb
index 2d260f23f1..4f7f44e5d4 100644
--- a/spec/ruby/core/string/downcase_spec.rb
+++ b/spec/ruby/core/string/downcase_spec.rb
@@ -24,7 +24,7 @@ describe "String#downcase" do
downcased.should == "king"
downcased.size.should == 4
downcased.bytesize.should == 4
- downcased.ascii_only?.should be_true
+ downcased.ascii_only?.should == true
end
end
@@ -48,7 +48,7 @@ describe "String#downcase" do
end
it "does not allow any other additional option" do
- -> { "İ".downcase(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "İ".downcase(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -62,7 +62,7 @@ describe "String#downcase" do
end
it "does not allow any other additional option" do
- -> { "İS".downcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "İS".downcase(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
@@ -74,18 +74,18 @@ describe "String#downcase" do
end
it "does not allow invalid options" do
- -> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "ABC".downcase(:invalid_option) }.should.raise(ArgumentError)
end
it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("FOObar").downcase.should.instance_of?(String)
end
end
describe "String#downcase!" do
it "modifies self in place" do
a = "HeLlO"
- a.downcase!.should equal(a)
+ a.downcase!.should.equal?(a)
a.should == "hello"
end
@@ -109,7 +109,7 @@ describe "String#downcase!" do
downcased.should == "king"
downcased.size.should == 4
downcased.bytesize.should == 4
- downcased.ascii_only?.should be_true
+ downcased.ascii_only?.should == true
end
end
@@ -141,7 +141,7 @@ describe "String#downcase!" do
end
it "does not allow any other additional option" do
- -> { a = "İ"; a.downcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "İ"; a.downcase!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -159,7 +159,7 @@ describe "String#downcase!" do
end
it "does not allow any other additional option" do
- -> { a = "İS"; a.downcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "İS"; a.downcase!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
@@ -175,7 +175,7 @@ describe "String#downcase!" do
end
it "does not allow invalid options" do
- -> { a = "ABC"; a.downcase!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "ABC"; a.downcase!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -185,11 +185,11 @@ describe "String#downcase!" do
end
it "raises a FrozenError when self is frozen" do
- -> { "HeLlo".freeze.downcase! }.should raise_error(FrozenError)
- -> { "hello".freeze.downcase! }.should raise_error(FrozenError)
+ -> { "HeLlo".freeze.downcase! }.should.raise(FrozenError)
+ -> { "hello".freeze.downcase! }.should.raise(FrozenError)
end
it "sets the result String encoding to the source String encoding" do
- "ABC".downcase.encoding.should equal(Encoding::UTF_8)
+ "ABC".downcase.encoding.should.equal?(Encoding::UTF_8)
end
end
diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb
index cab8beff5a..176be79db2 100644
--- a/spec/ruby/core/string/dump_spec.rb
+++ b/spec/ruby/core/string/dump_spec.rb
@@ -8,7 +8,7 @@ describe "String#dump" do
end
it "returns a String instance" do
- StringSpecs::MyString.new.dump.should be_an_instance_of(String)
+ StringSpecs::MyString.new.dump.should.instance_of?(String)
end
it "wraps string with \"" do
diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb
index 073802d84b..e367f7a311 100644
--- a/spec/ruby/core/string/dup_spec.rb
+++ b/spec/ruby/core/string/dup_spec.rb
@@ -21,7 +21,7 @@ describe "String#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- -> { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should.raise(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -30,7 +30,7 @@ describe "String#dup" do
end
dup = @obj.dup
- -> { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should.raise(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -39,7 +39,7 @@ describe "String#dup" do
end
dup = @obj.dup
- -> { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should.raise(NameError)
end
it "does not modify the original string when changing dupped string" do
diff --git a/spec/ruby/core/string/each_byte_spec.rb b/spec/ruby/core/string/each_byte_spec.rb
index 7b3db265ac..1884df416b 100644
--- a/spec/ruby/core/string/each_byte_spec.rb
+++ b/spec/ruby/core/string/each_byte_spec.rb
@@ -35,13 +35,13 @@ describe "String#each_byte" do
it "returns self" do
s = "hello"
- (s.each_byte {}).should equal(s)
+ (s.each_byte {}).should.equal?(s)
end
describe "when no block is given" do
it "returns an enumerator" do
enum = "hello".each_byte
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [104, 101, 108, 108, 111]
end
diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb
index e7599f832c..2abc5117aa 100644
--- a/spec/ruby/core/string/element_set_spec.rb
+++ b/spec/ruby/core/string/element_set_spec.rb
@@ -18,13 +18,13 @@ describe "String#[]= with Integer index" do
it "raises an IndexError without changing self if idx is outside of self" do
str = "hello"
- -> { str[20] = "bam" }.should raise_error(IndexError)
+ -> { str[20] = "bam" }.should.raise(IndexError)
str.should == "hello"
- -> { str[-20] = "bam" }.should raise_error(IndexError)
+ -> { str[-20] = "bam" }.should.raise(IndexError)
str.should == "hello"
- -> { ""[-1] = "bam" }.should raise_error(IndexError)
+ -> { ""[-1] = "bam" }.should.raise(IndexError)
end
# Behaviour is verified by matz in
@@ -37,7 +37,7 @@ describe "String#[]= with Integer index" do
it "raises IndexError if the string index doesn't match a position in the string" do
str = "hello"
- -> { str['y'] = "bam" }.should raise_error(IndexError)
+ -> { str['y'] = "bam" }.should.raise(IndexError)
str.should == "hello"
end
@@ -45,7 +45,7 @@ describe "String#[]= with Integer index" do
a = "hello"
a.freeze
- -> { a[0] = "bam" }.should raise_error(FrozenError)
+ -> { a[0] = "bam" }.should.raise(FrozenError)
end
it "calls to_int on index" do
@@ -69,17 +69,17 @@ describe "String#[]= with Integer index" do
end
it "raises a TypeError if other_str can't be converted to a String" do
- -> { "test"[1] = [] }.should raise_error(TypeError)
- -> { "test"[1] = mock('x') }.should raise_error(TypeError)
- -> { "test"[1] = nil }.should raise_error(TypeError)
+ -> { "test"[1] = [] }.should.raise(TypeError)
+ -> { "test"[1] = mock('x') }.should.raise(TypeError)
+ -> { "test"[1] = nil }.should.raise(TypeError)
end
it "raises a TypeError if passed an Integer replacement" do
- -> { "abc"[1] = 65 }.should raise_error(TypeError)
+ -> { "abc"[1] = 65 }.should.raise(TypeError)
end
it "raises an IndexError if the index is greater than character size" do
- -> { "あれ"[4] = "a" }.should raise_error(IndexError)
+ -> { "あれ"[4] = "a" }.should.raise(IndexError)
end
it "calls #to_int to convert the index" do
@@ -95,14 +95,14 @@ describe "String#[]= with Integer index" do
index = mock("string element set")
index.should_receive(:to_int).and_return('1')
- -> { "abc"[index] = "d" }.should raise_error(TypeError)
+ -> { "abc"[index] = "d" }.should.raise(TypeError)
end
it "raises an IndexError if #to_int returns a value out of range" do
index = mock("string element set")
index.should_receive(:to_int).and_return(4)
- -> { "ab"[index] = "c" }.should raise_error(IndexError)
+ -> { "ab"[index] = "c" }.should.raise(IndexError)
end
it "replaces a character with a multibyte character" do
@@ -127,7 +127,7 @@ describe "String#[]= with Integer index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[0] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "updates the string to a compatible encoding" do
@@ -139,7 +139,7 @@ describe "String#[]= with Integer index" do
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "あれ"
rep = "が".encode Encoding::EUC_JP
- -> { str[0] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[0] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -164,7 +164,7 @@ describe "String#[]= with String index" do
it "raises an IndexError if the search String is not found" do
str = "abcde"
- -> { str["g"] = "h" }.should raise_error(IndexError)
+ -> { str["g"] = "h" }.should.raise(IndexError)
end
it "replaces characters with a multibyte character" do
@@ -189,13 +189,13 @@ describe "String#[]= with String index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[" "] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "あれ"
rep = "が".encode Encoding::EUC_JP
- -> { str["れ"] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str["れ"] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -208,7 +208,7 @@ describe "String#[]= with a Regexp index" do
it "raises IndexError if the regexp index doesn't match a position in the string" do
str = "hello"
- -> { str[/y/] = "bam" }.should raise_error(IndexError)
+ -> { str[/y/] = "bam" }.should.raise(IndexError)
str.should == "hello"
end
@@ -225,7 +225,7 @@ describe "String#[]= with a Regexp index" do
rep = mock("string element set regexp")
rep.should_not_receive(:to_str)
- -> { "abc"[/def/] = rep }.should raise_error(IndexError)
+ -> { "abc"[/def/] = rep }.should.raise(IndexError)
end
describe "with 3 arguments" do
@@ -242,7 +242,7 @@ describe "String#[]= with a Regexp index" do
ref = mock("string element set regexp ref")
ref.should_receive(:to_int).and_return(nil)
- -> { "abc"[/a(b)/, ref] = "x" }.should raise_error(TypeError)
+ -> { "abc"[/a(b)/, ref] = "x" }.should.raise(TypeError)
end
it "uses the 2nd of 3 arguments as which capture should be replaced" do
@@ -261,20 +261,20 @@ describe "String#[]= with a Regexp index" do
rep = mock("string element set regexp")
rep.should_not_receive(:to_str)
- -> { "abc"[/a(b)/, 2] = rep }.should raise_error(IndexError)
+ -> { "abc"[/a(b)/, 2] = rep }.should.raise(IndexError)
end
it "raises IndexError if the specified capture isn't available" do
str = "aaa bbb ccc"
- -> { str[/a (bbb) c/, 2] = "ddd" }.should raise_error(IndexError)
- -> { str[/a (bbb) c/, -2] = "ddd" }.should raise_error(IndexError)
+ -> { str[/a (bbb) c/, 2] = "ddd" }.should.raise(IndexError)
+ -> { str[/a (bbb) c/, -2] = "ddd" }.should.raise(IndexError)
end
describe "when the optional capture does not match" do
it "raises an IndexError before setting the replacement" do
str1 = "a b c"
str2 = str1.dup
- -> { str2[/a (b) (Z)?/, 2] = "d" }.should raise_error(IndexError)
+ -> { str2[/a (b) (Z)?/, 2] = "d" }.should.raise(IndexError)
str2.should == str1
end
end
@@ -302,13 +302,13 @@ describe "String#[]= with a Regexp index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[/ /] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "あれ"
rep = "が".encode Encoding::EUC_JP
- -> { str[/れ/] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[/れ/] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -358,11 +358,11 @@ describe "String#[]= with a Range index" do
end
it "raises a RangeError if negative Range begin is out of range" do
- -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError, "-4..-2 out of range")
+ -> { "abc"[-4..-2] = "x" }.should.raise(RangeError, "-4..-2 out of range")
end
it "raises a RangeError if positive Range begin is greater than String size" do
- -> { "abc"[4..2] = "x" }.should raise_error(RangeError, "4..2 out of range")
+ -> { "abc"[4..2] = "x" }.should.raise(RangeError, "4..2 out of range")
end
it "uses the Range end as an index rather than a count" do
@@ -423,13 +423,13 @@ describe "String#[]= with a Range index" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[0..1] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "あれ"
rep = "が".encode Encoding::EUC_JP
- -> { str[0..1] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[0..1] = rep }.should.raise(Encoding::CompatibilityError)
end
end
@@ -498,14 +498,14 @@ describe "String#[]= with Integer index, count" do
index = mock("string element set index")
index.should_receive(:to_int).and_return("1")
- -> { "abc"[index, 2] = "xyz" }.should raise_error(TypeError)
+ -> { "abc"[index, 2] = "xyz" }.should.raise(TypeError)
end
it "raises a TypeError if #to_int for count does not return an Integer" do
count = mock("string element set count")
count.should_receive(:to_int).and_return("1")
- -> { "abc"[1, count] = "xyz" }.should raise_error(TypeError)
+ -> { "abc"[1, count] = "xyz" }.should.raise(TypeError)
end
it "calls #to_str to convert the replacement object" do
@@ -521,23 +521,23 @@ describe "String#[]= with Integer index, count" do
r = mock("string element set replacement")
r.should_receive(:to_str).and_return(nil)
- -> { "abc"[1, 1] = r }.should raise_error(TypeError)
+ -> { "abc"[1, 1] = r }.should.raise(TypeError)
end
it "raises an IndexError if |idx| is greater than the length of the string" do
- -> { "hello"[6, 0] = "bob" }.should raise_error(IndexError)
- -> { "hello"[-6, 0] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[6, 0] = "bob" }.should.raise(IndexError)
+ -> { "hello"[-6, 0] = "bob" }.should.raise(IndexError)
end
it "raises an IndexError if count < 0" do
- -> { "hello"[0, -1] = "bob" }.should raise_error(IndexError)
- -> { "hello"[1, -1] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[0, -1] = "bob" }.should.raise(IndexError)
+ -> { "hello"[1, -1] = "bob" }.should.raise(IndexError)
end
it "raises a TypeError if other_str is a type other than String" do
- -> { "hello"[0, 2] = nil }.should raise_error(TypeError)
- -> { "hello"[0, 2] = [] }.should raise_error(TypeError)
- -> { "hello"[0, 2] = 33 }.should raise_error(TypeError)
+ -> { "hello"[0, 2] = nil }.should.raise(TypeError)
+ -> { "hello"[0, 2] = [] }.should.raise(TypeError)
+ -> { "hello"[0, 2] = 33 }.should.raise(TypeError)
end
it "replaces characters with a multibyte character" do
@@ -571,19 +571,19 @@ describe "String#[]= with Integer index, count" do
end
it "raises an IndexError if the character index is out of range of a multibyte String" do
- -> { "あれ"[3, 0] = "り" }.should raise_error(IndexError)
+ -> { "あれ"[3, 0] = "り" }.should.raise(IndexError)
end
it "encodes the String in an encoding compatible with the replacement" do
str = " ".force_encoding Encoding::US_ASCII
rep = [160].pack('C').force_encoding Encoding::BINARY
str[0, 1] = rep
- str.encoding.should equal(Encoding::BINARY)
+ str.encoding.should.equal?(Encoding::BINARY)
end
it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
str = "あれ"
rep = "が".encode Encoding::EUC_JP
- -> { str[0, 1] = rep }.should raise_error(Encoding::CompatibilityError)
+ -> { str[0, 1] = rep }.should.raise(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/encode_spec.rb b/spec/ruby/core/string/encode_spec.rb
index cd449498a3..ab096f4041 100644
--- a/spec/ruby/core/string/encode_spec.rb
+++ b/spec/ruby/core/string/encode_spec.rb
@@ -20,7 +20,7 @@ describe "String#encode" do
Encoding.default_internal = nil
str = "あ"
encoded = str.encode
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -28,7 +28,7 @@ describe "String#encode" do
Encoding.default_internal = nil
str = "abc"
encoded = str.encode
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -36,7 +36,7 @@ describe "String#encode" do
x82 = [0x82].pack('C')
str = "#{x82}foo".dup.force_encoding("binary")[1..-1].encode("utf-8")
str.should == "foo".dup.force_encoding("utf-8")
- str.encoding.should equal(Encoding::UTF_8)
+ str.encoding.should.equal?(Encoding::UTF_8)
end
end
@@ -44,7 +44,7 @@ describe "String#encode" do
it "returns a copy when passed the same encoding as the String" do
str = "あ"
encoded = str.encode(Encoding::UTF_8)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -58,7 +58,7 @@ describe "String#encode" do
it "returns a copy when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = "あ"
- str.encode(invalid: :replace).should_not equal(str)
+ str.encode(invalid: :replace).should_not.equal?(str)
end
it "normalizes newlines with cr_newline option" do
@@ -137,7 +137,7 @@ describe "String#encode" do
str = "あ".dup.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8")
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str.force_encoding("utf-8")
encoded.encoding.should == Encoding::UTF_8
end
@@ -152,7 +152,7 @@ describe "String#encode" do
it "returns a copy when the destination encoding is the same as the String encoding" do
str = "あ"
encoded = str.encode(Encoding::UTF_8, undef: :replace)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
end
@@ -161,7 +161,7 @@ describe "String#encode" do
it "returns a copy when both encodings are the same" do
str = "あ"
encoded = str.encode("utf-8", "utf-8", invalid: :replace)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str
end
@@ -169,7 +169,7 @@ describe "String#encode" do
str = "あ".dup.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8", invalid: :replace)
- encoded.should_not equal(str)
+ encoded.should_not.equal?(str)
encoded.should == str.force_encoding("utf-8")
encoded.encoding.should == Encoding::UTF_8
end
@@ -190,25 +190,25 @@ describe "String#encode!" do
it_behaves_like :string_encode, :encode!
it "raises a FrozenError when called on a frozen String" do
- -> { "foo".freeze.encode!("euc-jp") }.should raise_error(FrozenError)
+ -> { "foo".freeze.encode!("euc-jp") }.should.raise(FrozenError)
end
# http://redmine.ruby-lang.org/issues/show/1836
it "raises a FrozenError when called on a frozen String when it's a no-op" do
- -> { "foo".freeze.encode!("utf-8") }.should raise_error(FrozenError)
+ -> { "foo".freeze.encode!("utf-8") }.should.raise(FrozenError)
end
describe "when passed no options" do
it "returns self when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = +"あ"
- str.encode!.should equal(str)
+ str.encode!.should.equal?(str)
end
it "returns self for a ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = +"abc"
- str.encode!.should equal(str)
+ str.encode!.should.equal?(str)
end
end
@@ -216,7 +216,7 @@ describe "String#encode!" do
it "returns self for ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
str = +"abc"
- str.encode!(invalid: :replace).should equal(str)
+ str.encode!(invalid: :replace).should.equal?(str)
end
end
@@ -224,8 +224,8 @@ describe "String#encode!" do
it "returns self" do
str = +"abc"
result = str.encode!(Encoding::BINARY)
- result.encoding.should equal(Encoding::BINARY)
- result.should equal(str)
+ result.encoding.should.equal?(Encoding::BINARY)
+ result.should.equal?(str)
end
end
@@ -233,8 +233,8 @@ describe "String#encode!" do
it "returns self" do
str = +"ああ"
result = str.encode!("euc-jp", "utf-8")
- result.encoding.should equal(Encoding::EUC_JP)
- result.should equal(str)
+ result.encoding.should.equal?(Encoding::EUC_JP)
+ result.should.equal?(str)
end
end
end
diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb
index f6e8fd3470..aa0e4765ed 100644
--- a/spec/ruby/core/string/encoding_spec.rb
+++ b/spec/ruby/core/string/encoding_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/iso-8859-9-encoding'
describe "String#encoding" do
it "returns an Encoding object" do
- String.new.encoding.should be_an_instance_of(Encoding)
+ String.new.encoding.should.instance_of?(Encoding)
end
it "is equal to the source encoding by default" do
@@ -70,13 +70,13 @@ describe "String#encoding for Strings with \\u escapes" do
it "returns US-ASCII if self is US-ASCII only" do
s = "\u{40}"
- s.ascii_only?.should be_true
+ s.ascii_only?.should == true
s.encoding.should == Encoding::US_ASCII
end
it "returns UTF-8 if self isn't US-ASCII only" do
s = "\u{4076}\u{619}"
- s.ascii_only?.should be_false
+ s.ascii_only?.should == false
s.encoding.should == Encoding::UTF_8
end
@@ -122,7 +122,7 @@ describe "String#encoding for Strings with \\x escapes" do
it "returns US-ASCII if self is US-ASCII only" do
s = "\x61"
- s.ascii_only?.should be_true
+ s.ascii_only?.should == true
s.encoding.should == Encoding::US_ASCII
end
@@ -131,7 +131,7 @@ describe "String#encoding for Strings with \\x escapes" do
str = " "
str.encoding.should == Encoding::US_ASCII
str += [0xDF].pack('C')
- str.ascii_only?.should be_false
+ str.ascii_only?.should == false
str.encoding.should == Encoding::BINARY
end
@@ -140,7 +140,7 @@ describe "String#encoding for Strings with \\x escapes" do
it "returns the source encoding when an escape creates a byte with the 8th bit set if the source encoding isn't US-ASCII" do
fixture = StringSpecs::ISO88599Encoding.new
fixture.source_encoding.should == Encoding::ISO8859_9
- fixture.x_escape.ascii_only?.should be_false
+ fixture.x_escape.ascii_only?.should == false
fixture.x_escape.encoding.should == Encoding::ISO8859_9
end
diff --git a/spec/ruby/core/string/eql_spec.rb b/spec/ruby/core/string/eql_spec.rb
index 397974d9fb..46ebeda509 100644
--- a/spec/ruby/core/string/eql_spec.rb
+++ b/spec/ruby/core/string/eql_spec.rb
@@ -6,16 +6,16 @@ describe "String#eql?" do
describe "when given a non-String" do
it "returns false" do
- 'hello'.should_not eql(5)
+ 'hello'.should_not.eql?(5)
not_supported_on :opal do
- 'hello'.should_not eql(:hello)
+ 'hello'.should_not.eql?(:hello)
end
- 'hello'.should_not eql(mock('x'))
+ 'hello'.should_not.eql?(mock('x'))
end
it "does not try to call #to_str on the given argument" do
(obj = mock('x')).should_not_receive(:to_str)
- 'hello'.should_not eql(obj)
+ 'hello'.should_not.eql?(obj)
end
end
end
diff --git a/spec/ruby/core/string/force_encoding_spec.rb b/spec/ruby/core/string/force_encoding_spec.rb
index 2259dcf3cf..fc6914213f 100644
--- a/spec/ruby/core/string/force_encoding_spec.rb
+++ b/spec/ruby/core/string/force_encoding_spec.rb
@@ -41,23 +41,23 @@ describe "String#force_encoding" do
obj = mock("force_encoding")
obj.should_receive(:to_str).and_return(1)
- -> { "abc".force_encoding(obj) }.should raise_error(TypeError)
+ -> { "abc".force_encoding(obj) }.should.raise(TypeError)
end
it "raises a TypeError if passed nil" do
- -> { "abc".force_encoding(nil) }.should raise_error(TypeError)
+ -> { "abc".force_encoding(nil) }.should.raise(TypeError)
end
it "returns self" do
str = "abc"
- str.force_encoding('utf-8').should equal(str)
+ str.force_encoding('utf-8').should.equal?(str)
end
it "sets the encoding even if the String contents are invalid in that encoding" do
str = "\u{9765}"
str.force_encoding('euc-jp')
str.encoding.should == Encoding::EUC_JP
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
end
it "does not transcode self" do
@@ -67,6 +67,6 @@ describe "String#force_encoding" do
it "raises a FrozenError if self is frozen" do
str = "abcd".freeze
- -> { str.force_encoding(str.encoding) }.should raise_error(FrozenError)
+ -> { str.force_encoding(str.encoding) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/freeze_spec.rb b/spec/ruby/core/string/freeze_spec.rb
index 2e8e70386d..8485e8de21 100644
--- a/spec/ruby/core/string/freeze_spec.rb
+++ b/spec/ruby/core/string/freeze_spec.rb
@@ -4,11 +4,11 @@ require_relative '../../spec_helper'
describe "String#freeze" do
it "produces the same object whenever called on an instance of a literal in the source" do
- "abc".freeze.should equal "abc".freeze
+ "abc".freeze.should.equal? "abc".freeze
end
it "doesn't produce the same object for different instances of literals in the source" do
- "abc".should_not equal "abc"
+ "abc".should_not.equal? "abc"
end
it "being a special form doesn't change the value of defined?" do
diff --git a/spec/ruby/core/string/getbyte_spec.rb b/spec/ruby/core/string/getbyte_spec.rb
index 27b7d826ea..d4619dca61 100644
--- a/spec/ruby/core/string/getbyte_spec.rb
+++ b/spec/ruby/core/string/getbyte_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "String#getbyte" do
it "returns an Integer if given a valid index" do
- "a".getbyte(0).should be_kind_of(Integer)
+ "a".getbyte(0).should.is_a?(Integer)
end
it "starts indexing at 0" do
@@ -51,19 +51,19 @@ describe "String#getbyte" do
end
it "returns nil for out-of-bound indexes" do
- "g".getbyte(1).should be_nil
+ "g".getbyte(1).should == nil
end
it "regards the empty String as containing no bytes" do
- "".getbyte(0).should be_nil
+ "".getbyte(0).should == nil
end
it "raises an ArgumentError unless given one argument" do
- -> { "glark".getbyte }.should raise_error(ArgumentError)
- -> { "food".getbyte(0,0) }.should raise_error(ArgumentError)
+ -> { "glark".getbyte }.should.raise(ArgumentError)
+ -> { "food".getbyte(0,0) }.should.raise(ArgumentError)
end
it "raises a TypeError unless its argument can be coerced into an Integer" do
- -> { "a".getbyte('a') }.should raise_error(TypeError)
+ -> { "a".getbyte('a') }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb
index 0d9f32eca2..d0e1c30bd2 100644
--- a/spec/ruby/core/string/gsub_spec.rb
+++ b/spec/ruby/core/string/gsub_spec.rb
@@ -175,9 +175,9 @@ describe "String#gsub with pattern and replacement" do
end
it "raises a TypeError when pattern can't be converted to a string" do
- -> { "hello".gsub([], "x") }.should raise_error(TypeError)
- -> { "hello".gsub(Object.new, "x") }.should raise_error(TypeError)
- -> { "hello".gsub(nil, "x") }.should raise_error(TypeError)
+ -> { "hello".gsub([], "x") }.should.raise(TypeError)
+ -> { "hello".gsub(Object.new, "x") }.should.raise(TypeError)
+ -> { "hello".gsub(nil, "x") }.should.raise(TypeError)
end
it "tries to convert replacement to a string using to_str" do
@@ -188,16 +188,16 @@ describe "String#gsub with pattern and replacement" do
end
it "raises a TypeError when replacement can't be converted to a string" do
- -> { "hello".gsub(/[aeiou]/, []) }.should raise_error(TypeError)
- -> { "hello".gsub(/[aeiou]/, Object.new) }.should raise_error(TypeError)
- -> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
+ -> { "hello".gsub(/[aeiou]/, []) }.should.raise(TypeError)
+ -> { "hello".gsub(/[aeiou]/, Object.new) }.should.raise(TypeError)
+ -> { "hello".gsub(/[aeiou]/, nil) }.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").gsub(//, "").should.instance_of?(String)
+ StringSpecs::MyString.new("").gsub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").gsub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").gsub("foo", "").should.instance_of?(String)
end
it "sets $~ to MatchData of last match and nil when there's none" do
@@ -450,8 +450,8 @@ describe "String#gsub with pattern and block" do
s = "hllëllo"
s2 = "hellö"
- -> { s.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
- -> { s2.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
+ -> { s2.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
end
it "replaces the incompatible part properly even if the encodings are not compatible" do
@@ -463,7 +463,7 @@ describe "String#gsub with pattern and block" do
not_supported_on :opal do
it "raises an ArgumentError if encoding is not valid" do
x92 = [0x92].pack('C').force_encoding('utf-8')
- -> { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
+ -> { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should.raise(ArgumentError)
end
end
end
@@ -471,7 +471,7 @@ end
describe "String#gsub with pattern and without replacement and block" do
it "returns an enumerator" do
enum = "abca".gsub(/a/)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ["a", "a"]
end
@@ -495,13 +495,13 @@ end
describe "String#gsub! with pattern and replacement" do
it "modifies self in place and returns self" do
a = "hello"
- a.gsub!(/[aeiou]/, '*').should equal(a)
+ a.gsub!(/[aeiou]/, '*').should.equal?(a)
a.should == "h*ll*"
end
it "modifies self in place with multi-byte characters and returns self" do
a = "¿por qué?"
- a.gsub!(/([a-z\d]*)/, "*").should equal(a)
+ a.gsub!(/([a-z\d]*)/, "*").should.equal?(a)
a.should == "*¿** **é*?*"
end
@@ -517,9 +517,9 @@ describe "String#gsub! with pattern and replacement" do
s = "hello"
s.freeze
- -> { s.gsub!(/ROAR/, "x") }.should raise_error(FrozenError)
- -> { s.gsub!(/e/, "e") }.should raise_error(FrozenError)
- -> { s.gsub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
+ -> { s.gsub!(/ROAR/, "x") }.should.raise(FrozenError)
+ -> { s.gsub!(/e/, "e") }.should.raise(FrozenError)
+ -> { s.gsub!(/[aeiou]/, '*') }.should.raise(FrozenError)
end
it "handles a pattern in a superset encoding" do
@@ -547,7 +547,7 @@ end
describe "String#gsub! with pattern and block" do
it "modifies self in place and returns self" do
a = "hello"
- a.gsub!(/[aeiou]/) { '*' }.should equal(a)
+ a.gsub!(/[aeiou]/) { '*' }.should.equal?(a)
a.should == "h*ll*"
end
@@ -563,9 +563,9 @@ describe "String#gsub! with pattern and block" do
s = "hello"
s.freeze
- -> { s.gsub!(/ROAR/) { "x" } }.should raise_error(FrozenError)
- -> { s.gsub!(/e/) { "e" } }.should raise_error(FrozenError)
- -> { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(FrozenError)
+ -> { s.gsub!(/ROAR/) { "x" } }.should.raise(FrozenError)
+ -> { s.gsub!(/e/) { "e" } }.should.raise(FrozenError)
+ -> { s.gsub!(/[aeiou]/) { '*' } }.should.raise(FrozenError)
end
it "uses the compatible encoding if they are compatible" do
@@ -580,8 +580,8 @@ describe "String#gsub! with pattern and block" do
s = "hllëllo"
s2 = "hellö"
- -> { s.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
- -> { s2.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
+ -> { s2.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should.raise(Encoding::CompatibilityError)
end
it "replaces the incompatible part properly even if the encodings are not compatible" do
@@ -593,7 +593,7 @@ describe "String#gsub! with pattern and block" do
not_supported_on :opal do
it "raises an ArgumentError if encoding is not valid" do
x92 = [0x92].pack('C').force_encoding('utf-8')
- -> { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
+ -> { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should.raise(ArgumentError)
end
end
end
@@ -601,7 +601,7 @@ end
describe "String#gsub! with pattern and without replacement and block" do
it "returns an enumerator" do
enum = "abca".gsub!(/a/)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ["a", "a"]
end
diff --git a/spec/ruby/core/string/include_spec.rb b/spec/ruby/core/string/include_spec.rb
index 9781140a55..d943430335 100644
--- a/spec/ruby/core/string/include_spec.rb
+++ b/spec/ruby/core/string/include_spec.rb
@@ -35,15 +35,15 @@ describe "String#include? with String" do
end
it "raises a TypeError if other can't be converted to string" do
- -> { "hello".include?([]) }.should raise_error(TypeError)
- -> { "hello".include?('h'.ord) }.should raise_error(TypeError)
- -> { "hello".include?(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".include?([]) }.should.raise(TypeError)
+ -> { "hello".include?('h'.ord) }.should.raise(TypeError)
+ -> { "hello".include?(mock('x')) }.should.raise(TypeError)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ア".encode Encoding::EUC_JP
-> do
"あれ".include?(pat)
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index 835263a2cd..3f82181b98 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -4,15 +4,15 @@ require_relative 'fixtures/classes'
describe "String#index" do
it "raises a TypeError if passed nil" do
- -> { "abc".index nil }.should raise_error(TypeError)
+ -> { "abc".index nil }.should.raise(TypeError)
end
it "raises a TypeError if passed a boolean" do
- -> { "abc".index true }.should raise_error(TypeError)
+ -> { "abc".index true }.should.raise(TypeError)
end
it "raises a TypeError if passed a Symbol" do
- -> { "abc".index :a }.should raise_error(TypeError)
+ -> { "abc".index :a }.should.raise(TypeError)
end
it "calls #to_str to convert the first argument" do
@@ -28,7 +28,7 @@ describe "String#index" do
end
it "raises a TypeError if passed an Integer" do
- -> { "abc".index 97 }.should raise_error(TypeError)
+ -> { "abc".index 97 }.should.raise(TypeError)
end
end
@@ -157,7 +157,7 @@ describe "String#index with String" do
char = "れ".encode Encoding::EUC_JP
-> do
"あれ".index char
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "handles a substring in a superset encoding" do
@@ -172,7 +172,7 @@ describe "String#index with String" do
str = 'abc'.dup.force_encoding("ISO-2022-JP")
pattern = 'b'.dup.force_encoding("EUC-JP")
- -> { str.index(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
+ -> { str.index(pattern) }.should.raise(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
end
end
@@ -231,15 +231,13 @@ describe "String#index with Regexp" do
$~.should == nil
end
- ruby_bug "#20421", ""..."3.3" do
- it "always clear $~" do
- "a".index(/a/)
- $~.should_not == nil
+ it "always clear $~" do
+ "a".index(/a/)
+ $~.should_not == nil
- string = "blablabla"
- string.index(/bla/, string.length + 1)
- $~.should == nil
- end
+ string = "blablabla"
+ string.index(/bla/, string.length + 1)
+ $~.should == nil
end
it "starts the search at the given offset" do
@@ -289,7 +287,7 @@ describe "String#index with Regexp" do
end
it "returns nil if the Regexp matches the empty string and the offset is out of range" do
- "ruby".index(//,12).should be_nil
+ "ruby".index(//,12).should == nil
end
it "supports \\G which matches at the given start offset" do
@@ -330,21 +328,10 @@ describe "String#index with Regexp" do
"われわわれ".index(/わ/, 3).should == 3
end
- ruby_bug "#19763", ""..."3.3.0" do
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- re = Regexp.new "れ".encode(Encoding::EUC_JP)
- -> do
- "あれ".index re
- end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
- end
- end
-
- # The exception message was incorrectly "incompatible character encodings: UTF-8 and EUC-JP" before 3.3.0
- # Still test that the right exception class is used before that.
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
"あれ".index re
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/initialize_spec.rb b/spec/ruby/core/string/initialize_spec.rb
index 08734cc916..b0c1e2e573 100644
--- a/spec/ruby/core/string/initialize_spec.rb
+++ b/spec/ruby/core/string/initialize_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/replace'
describe "String#initialize" do
it "is a private method" do
- String.should have_private_instance_method(:initialize)
+ String.private_instance_methods(false).should.include?(:initialize)
end
describe "with no arguments" do
@@ -16,7 +16,7 @@ describe "String#initialize" do
it "does not raise an exception when frozen" do
a = "hello".freeze
- a.send(:initialize).should equal(a)
+ a.send(:initialize).should.equal?(a)
end
end
diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb
index 483f3c9367..c89793a8ca 100644
--- a/spec/ruby/core/string/insert_spec.rb
+++ b/spec/ruby/core/string/insert_spec.rb
@@ -23,8 +23,8 @@ describe "String#insert with index, other" do
end
it "raises an IndexError if the index is beyond string" do
- -> { "abcd".insert(5, 'X') }.should raise_error(IndexError)
- -> { "abcd".insert(-6, 'X') }.should raise_error(IndexError)
+ -> { "abcd".insert(5, 'X') }.should.raise(IndexError)
+ -> { "abcd".insert(-6, 'X') }.should.raise(IndexError)
end
it "converts index to an integer using to_int" do
@@ -42,15 +42,15 @@ describe "String#insert with index, other" do
end
it "raises a TypeError if other can't be converted to string" do
- -> { "abcd".insert(-6, Object.new)}.should raise_error(TypeError)
- -> { "abcd".insert(-6, []) }.should raise_error(TypeError)
- -> { "abcd".insert(-6, mock('x')) }.should raise_error(TypeError)
+ -> { "abcd".insert(-6, Object.new)}.should.raise(TypeError)
+ -> { "abcd".insert(-6, []) }.should.raise(TypeError)
+ -> { "abcd".insert(-6, mock('x')) }.should.raise(TypeError)
end
it "raises a FrozenError if self is frozen" do
str = "abcd".freeze
- -> { str.insert(4, '') }.should raise_error(FrozenError)
- -> { str.insert(4, 'X') }.should raise_error(FrozenError)
+ -> { str.insert(4, '') }.should.raise(FrozenError)
+ -> { str.insert(4, 'X') }.should.raise(FrozenError)
end
it "inserts a character into a multibyte encoded string" do
@@ -67,7 +67,7 @@ describe "String#insert with index, other" do
pat = "ア".encode Encoding::EUC_JP
-> do
"あれ".insert 0, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "should not call subclassed string methods" do
diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb
index 15db06c7f5..8b91ce2f84 100644
--- a/spec/ruby/core/string/inspect_spec.rb
+++ b/spec/ruby/core/string/inspect_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "String#inspect" do
it "does not return a subclass instance" do
- StringSpecs::MyString.new.inspect.should be_an_instance_of(String)
+ StringSpecs::MyString.new.inspect.should.instance_of?(String)
end
it "returns a string with special characters replaced with \\<char> notation" do
diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb
index 47324c59d2..0b2aab2638 100644
--- a/spec/ruby/core/string/ljust_spec.rb
+++ b/spec/ruby/core/string/ljust_spec.rb
@@ -41,10 +41,10 @@ describe "String#ljust with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- -> { "hello".ljust("x") }.should raise_error(TypeError)
- -> { "hello".ljust("x", "y") }.should raise_error(TypeError)
- -> { "hello".ljust([]) }.should raise_error(TypeError)
- -> { "hello".ljust(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".ljust("x") }.should.raise(TypeError)
+ -> { "hello".ljust("x", "y") }.should.raise(TypeError)
+ -> { "hello".ljust([]) }.should.raise(TypeError)
+ -> { "hello".ljust(mock('x')) }.should.raise(TypeError)
end
it "tries to convert padstr to a string using to_str" do
@@ -55,22 +55,22 @@ describe "String#ljust with length, padding" do
end
it "raises a TypeError when padstr can't be converted" do
- -> { "hello".ljust(20, []) }.should raise_error(TypeError)
- -> { "hello".ljust(20, Object.new)}.should raise_error(TypeError)
- -> { "hello".ljust(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".ljust(20, []) }.should.raise(TypeError)
+ -> { "hello".ljust(20, Object.new)}.should.raise(TypeError)
+ -> { "hello".ljust(20, mock('x')) }.should.raise(TypeError)
end
it "raises an ArgumentError when padstr is empty" do
- -> { "hello".ljust(10, '') }.should raise_error(ArgumentError)
+ -> { "hello".ljust(10, '') }.should.raise(ArgumentError)
end
it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").ljust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").ljust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
- "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "".ljust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
+ "foo".ljust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
end
describe "with width" do
@@ -78,7 +78,7 @@ describe "String#ljust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.ljust 5
result.should == "abc "
- result.encoding.should equal(Encoding::IBM437)
+ result.encoding.should.equal?(Encoding::IBM437)
end
end
@@ -87,14 +87,14 @@ describe "String#ljust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.ljust 5, "あ"
result.should == "abcああ"
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ア".encode Encoding::EUC_JP
-> do
"あれ".ljust 5, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index c83650207e..5896f8d7da 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -30,7 +30,7 @@ end
describe "String#lstrip!" do
it "modifies self in place and returns self" do
a = " hello "
- a.lstrip!.should equal(a)
+ a.lstrip!.should.equal?(a)
a.should == "hello "
end
@@ -53,22 +53,22 @@ describe "String#lstrip!" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { " hello ".freeze.lstrip! }.should raise_error(FrozenError)
+ -> { " hello ".freeze.lstrip! }.should.raise(FrozenError)
end
# see [ruby-core:23657]
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "hello".freeze.lstrip! }.should raise_error(FrozenError)
- -> { "".freeze.lstrip! }.should raise_error(FrozenError)
+ -> { "hello".freeze.lstrip! }.should.raise(FrozenError)
+ -> { "".freeze.lstrip! }.should.raise(FrozenError)
end
it "raises an ArgumentError if the first non-space codepoint is invalid" do
s = "\xDFabc".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.lstrip! }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.lstrip! }.should.raise(ArgumentError)
s = " \xDFabc".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.lstrip! }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.lstrip! }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/match_spec.rb b/spec/ruby/core/string/match_spec.rb
index 5e988f34ca..3ea8d90aa8 100644
--- a/spec/ruby/core/string/match_spec.rb
+++ b/spec/ruby/core/string/match_spec.rb
@@ -19,8 +19,8 @@ describe "String#=~" do
end
it "raises a TypeError if a obj is a string" do
- -> { "some string" =~ "another string" }.should raise_error(TypeError)
- -> { "a" =~ StringSpecs::MyString.new("b") }.should raise_error(TypeError)
+ -> { "some string" =~ "another string" }.should.raise(TypeError)
+ -> { "a" =~ StringSpecs::MyString.new("b") }.should.raise(TypeError)
end
it "invokes obj.=~ with self if obj is neither a string nor regexp" do
@@ -81,7 +81,7 @@ describe "String#match" do
describe "when passed a block" do
it "yields the MatchData" do
"abc".match(/./) {|m| ScratchPad.record m }
- ScratchPad.recorded.should be_kind_of(MatchData)
+ ScratchPad.recorded.should.is_a?(MatchData)
end
it "returns the block result" do
@@ -107,9 +107,9 @@ describe "String#match" do
end
it "raises a TypeError if pattern is not a regexp or a string" do
- -> { 'hello'.match(10) }.should raise_error(TypeError)
+ -> { 'hello'.match(10) }.should.raise(TypeError)
not_supported_on :opal do
- -> { 'hello'.match(:ell) }.should raise_error(TypeError)
+ -> { 'hello'.match(:ell) }.should.raise(TypeError)
end
end
@@ -137,9 +137,17 @@ describe "String#match" do
end
it "calls match on the regular expression" do
- regexp = /./.dup
- regexp.should_receive(:match).and_return(:foo)
- 'hello'.match(regexp).should == :foo
+ # Can't use regexp.should_receive(:match).and_return(:foo) since regexps are frozen
+ ScratchPad.clear
+ regexp = Class.new(Regexp) {
+ def match(*args)
+ ScratchPad.record [:match, *args]
+ super(*args)
+ end
+ }.new('.')
+
+ 'hello'.match(regexp)
+ ScratchPad.recorded.should == [:match, 'hello']
end
end
@@ -151,17 +159,17 @@ describe "String#match?" do
context "when matches the given regex" do
it "returns true but does not set Regexp.last_match" do
- 'string'.match?(/string/i).should be_true
- Regexp.last_match.should be_nil
+ 'string'.match?(/string/i).should == true
+ Regexp.last_match.should == nil
end
end
it "returns false when does not match the given regex" do
- 'string'.match?(/STRING/).should be_false
+ 'string'.match?(/STRING/).should == false
end
it "takes matching position as the 2nd argument" do
- 'string'.match?(/str/i, 0).should be_true
- 'string'.match?(/str/i, 1).should be_false
+ 'string'.match?(/str/i, 0).should == true
+ 'string'.match?(/str/i, 1).should == false
end
end
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index 33c2141812..f93ec4bcf8 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -46,13 +46,13 @@ describe "String#%" do
end
it "raises if a compatible encoding can't be found" do
- -> { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
+ -> { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should.raise(Encoding::CompatibilityError)
end
end
it "raises an error if single % appears at the end" do
- -> { ("%" % []) }.should raise_error(ArgumentError)
- -> { ("foo%" % [])}.should raise_error(ArgumentError)
+ -> { ("%" % []) }.should.raise(ArgumentError)
+ -> { ("foo%" % [])}.should.raise(ArgumentError)
end
ruby_version_is ""..."3.4" do
@@ -69,18 +69,18 @@ describe "String#%" do
end
it "raises an error if single % appears anywhere else" do
- -> { (" % " % []) }.should raise_error(ArgumentError)
- -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
+ -> { (" % " % []) }.should.raise(ArgumentError)
+ -> { ("foo%quux" % []) }.should.raise(ArgumentError)
end
it "raises an error if NULL or \\n appear anywhere else in the format string" do
begin
old_debug, $DEBUG = $DEBUG, false
- -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.\n3f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should.raise(ArgumentError)
ensure
$DEBUG = old_debug
end
@@ -89,14 +89,14 @@ describe "String#%" do
ruby_version_is "3.4" do
it "raises an ArgumentError if % is not followed by a conversion specifier" do
- -> { "%" % [] }.should raise_error(ArgumentError)
- -> { "%\n" % [] }.should raise_error(ArgumentError)
- -> { "%\0" % [] }.should raise_error(ArgumentError)
- -> { " % " % [] }.should raise_error(ArgumentError)
- -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%" % [] }.should.raise(ArgumentError)
+ -> { "%\n" % [] }.should.raise(ArgumentError)
+ -> { "%\0" % [] }.should.raise(ArgumentError)
+ -> { " % " % [] }.should.raise(ArgumentError)
+ -> { "%.\n3f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should.raise(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should.raise(ArgumentError)
end
end
@@ -119,8 +119,8 @@ describe "String#%" do
s = $stderr
$stderr = IOStub.new
- -> { "" % [1, 2, 3] }.should raise_error(ArgumentError)
- -> { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "" % [1, 2, 3] }.should.raise(ArgumentError)
+ -> { "%s" % [1, 2, 3] }.should.raise(ArgumentError)
ensure
$DEBUG = old_debug
$stderr = s
@@ -148,26 +148,26 @@ describe "String#%" do
ruby_version_is "3.4" do
it "raises an ArgumentError if absolute argument specifier is followed by a conversion specifier" do
- -> { "hello %1$" % "foo" }.should raise_error(ArgumentError)
+ -> { "hello %1$" % "foo" }.should.raise(ArgumentError)
end
end
it "raises an ArgumentError when given invalid argument specifiers" do
- -> { "%1" % [] }.should raise_error(ArgumentError)
- -> { "%+" % [] }.should raise_error(ArgumentError)
- -> { "%-" % [] }.should raise_error(ArgumentError)
- -> { "%#" % [] }.should raise_error(ArgumentError)
- -> { "%0" % [] }.should raise_error(ArgumentError)
- -> { "%*" % [] }.should raise_error(ArgumentError)
- -> { "%." % [] }.should raise_error(ArgumentError)
- -> { "%_" % [] }.should raise_error(ArgumentError)
- -> { "%0$s" % "x" }.should raise_error(ArgumentError)
- -> { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError)
- -> { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "%1" % [] }.should.raise(ArgumentError)
+ -> { "%+" % [] }.should.raise(ArgumentError)
+ -> { "%-" % [] }.should.raise(ArgumentError)
+ -> { "%#" % [] }.should.raise(ArgumentError)
+ -> { "%0" % [] }.should.raise(ArgumentError)
+ -> { "%*" % [] }.should.raise(ArgumentError)
+ -> { "%." % [] }.should.raise(ArgumentError)
+ -> { "%_" % [] }.should.raise(ArgumentError)
+ -> { "%0$s" % "x" }.should.raise(ArgumentError)
+ -> { "%*0$s" % [5, "x"] }.should.raise(ArgumentError)
+ -> { "%*1$.*0$1$s" % [1, 2, 3] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when multiple positional argument tokens are given for one format specifier" do
- -> { "%1$1$s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%1$1$s" % "foo" }.should.raise(ArgumentError)
end
it "respects positional arguments and precision tokens given for one format specifier" do
@@ -183,36 +183,36 @@ describe "String#%" do
end
it "raises an ArgumentError when multiple width star tokens are given for one format specifier" do
- -> { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%**s" % [5, 5, 5] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when a width star token is seen after a width token" do
- -> { "%5*s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%5*s" % [5, 5] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when multiple precision tokens are given" do
- -> { "%.5.5s" % 5 }.should raise_error(ArgumentError)
- -> { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError)
- -> { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%.5.5s" % 5 }.should.raise(ArgumentError)
+ -> { "%.5.*s" % [5, 5] }.should.raise(ArgumentError)
+ -> { "%.*.5s" % [5, 5] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when there are less arguments than format specifiers" do
("foo" % []).should == "foo"
- -> { "%s" % [] }.should raise_error(ArgumentError)
- -> { "%s %s" % [1] }.should raise_error(ArgumentError)
+ -> { "%s" % [] }.should.raise(ArgumentError)
+ -> { "%s %s" % [1] }.should.raise(ArgumentError)
end
it "raises an ArgumentError when absolute and relative argument numbers are mixed" do
- -> { "%s %1$s" % "foo" }.should raise_error(ArgumentError)
- -> { "%1$s %s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%s %1$s" % "foo" }.should.raise(ArgumentError)
+ -> { "%1$s %s" % "foo" }.should.raise(ArgumentError)
- -> { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
- -> { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError)
+ -> { "%s %2$s" % ["foo", "bar"] }.should.raise(ArgumentError)
+ -> { "%2$s %s" % ["foo", "bar"] }.should.raise(ArgumentError)
- -> { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- -> { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
+ -> { "%*2$.*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should.raise(ArgumentError)
end
it "allows reuse of the one argument multiple via absolute argument numbers" do
@@ -221,13 +221,13 @@ describe "String#%" do
end
it "always interprets an array argument as a list of argument parameters" do
- -> { "%p" % [] }.should raise_error(ArgumentError)
+ -> { "%p" % [] }.should.raise(ArgumentError)
("%p" % [1]).should == "1"
("%p %p" % [1, 2]).should == "1 2"
end
it "always interprets an array subclass argument as a list of argument parameters" do
- -> { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError)
+ -> { "%p" % StringSpecs::MyArray[] }.should.raise(ArgumentError)
("%p" % StringSpecs::MyArray[1]).should == "1"
("%p %p" % StringSpecs::MyArray[1, 2]).should == "1 2"
end
@@ -298,7 +298,7 @@ describe "String#%" do
x = mock("string modulo to_ary")
x.should_receive(:to_ary).and_return("x")
- -> { "%s" % x }.should raise_error(TypeError)
+ -> { "%s" % x }.should.raise(TypeError)
end
it "tries to convert the argument to Array by calling #to_ary" do
@@ -321,7 +321,7 @@ describe "String#%" do
"%f", "%g", "%G", "%i", "%o", "%p",
"%s", "%u", "%x", "%X"
].each do |format|
- (StringSpecs::MyString.new(format) % universal).should be_an_instance_of(String)
+ (StringSpecs::MyString.new(format) % universal).should.instance_of?(String)
end
end
@@ -384,23 +384,15 @@ describe "String#%" do
("%*c" % [10, 3]).should == " \003"
("%c" % 42).should == "*"
- -> { "%c" % Object }.should raise_error(TypeError)
+ -> { "%c" % Object }.should.raise(TypeError)
end
it "supports single character strings as argument for %c" do
("%c" % 'A').should == "A"
end
- ruby_version_is ""..."3.2" do
- it "raises an exception for multiple character strings as argument for %c" do
- -> { "%c" % 'AA' }.should raise_error(ArgumentError)
- end
- end
-
- ruby_version_is "3.2" do
- it "supports only the first character as argument for %c" do
- ("%c" % 'AA').should == "A"
- end
+ it "supports only the first character as argument for %c" do
+ ("%c" % 'AA').should == "A"
end
it "calls to_str on argument for %c formats" do
@@ -618,7 +610,7 @@ describe "String#%" do
# See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d
it "raises an ArgumentError for huge precisions for %s" do
block = -> { "%.25555555555555555555555555555555555555s" % "hello world" }
- block.should raise_error(ArgumentError)
+ block.should.raise(ArgumentError)
end
# Note: %u has been changed to an alias for %d in 1.9.
@@ -713,16 +705,16 @@ describe "String#%" do
-> {
# see [ruby-core:14139] for more details
(format % "0777").should == (format % Kernel.Integer("0777"))
- }.should_not raise_error(ArgumentError)
+ }.should_not.raise(ArgumentError)
- -> { format % "0__7_7_7" }.should raise_error(ArgumentError)
+ -> { format % "0__7_7_7" }.should.raise(ArgumentError)
- -> { format % "" }.should raise_error(ArgumentError)
- -> { format % "x" }.should raise_error(ArgumentError)
- -> { format % "5x" }.should raise_error(ArgumentError)
- -> { format % "08" }.should raise_error(ArgumentError)
- -> { format % "0b2" }.should raise_error(ArgumentError)
- -> { format % "123__456" }.should raise_error(ArgumentError)
+ -> { format % "" }.should.raise(ArgumentError)
+ -> { format % "x" }.should.raise(ArgumentError)
+ -> { format % "5x" }.should.raise(ArgumentError)
+ -> { format % "08" }.should.raise(ArgumentError)
+ -> { format % "0b2" }.should.raise(ArgumentError)
+ -> { format % "123__456" }.should.raise(ArgumentError)
obj = mock('5')
obj.should_receive(:to_i).and_return(5)
@@ -760,14 +752,14 @@ describe "String#%" do
(format % "0777").should == (format % 777)
- -> { format % "" }.should raise_error(ArgumentError)
- -> { format % "x" }.should raise_error(ArgumentError)
- -> { format % "." }.should raise_error(ArgumentError)
- -> { format % "5x" }.should raise_error(ArgumentError)
- -> { format % "0b1" }.should raise_error(ArgumentError)
- -> { format % "10e10.5" }.should raise_error(ArgumentError)
- -> { format % "10__10" }.should raise_error(ArgumentError)
- -> { format % "10.10__10" }.should raise_error(ArgumentError)
+ -> { format % "" }.should.raise(ArgumentError)
+ -> { format % "x" }.should.raise(ArgumentError)
+ -> { format % "." }.should.raise(ArgumentError)
+ -> { format % "5x" }.should.raise(ArgumentError)
+ -> { format % "0b1" }.should.raise(ArgumentError)
+ -> { format % "10e10.5" }.should.raise(ArgumentError)
+ -> { format % "10__10" }.should.raise(ArgumentError)
+ -> { format % "10.10__10" }.should.raise(ArgumentError)
obj = mock('5.0')
obj.should_receive(:to_f).and_return(5.0)
@@ -785,7 +777,7 @@ describe "String#%" do
end
it "should raise ArgumentError if no hash given" do
- -> {"%{foo}" % []}.should raise_error(ArgumentError)
+ -> {"%{foo}" % []}.should.raise(ArgumentError)
end
end
@@ -795,11 +787,11 @@ describe "String#%" do
end
it "raises KeyError if key is missing from passed-in hash" do
- -> {"%<foo>d" % {}}.should raise_error(KeyError)
+ -> {"%<foo>d" % {}}.should.raise(KeyError)
end
it "should raise ArgumentError if no hash given" do
- -> {"%<foo>" % []}.should raise_error(ArgumentError)
+ -> {"%<foo>" % []}.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/new_spec.rb b/spec/ruby/core/string/new_spec.rb
index ca678f5323..aadf1e0e46 100644
--- a/spec/ruby/core/string/new_spec.rb
+++ b/spec/ruby/core/string/new_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "String.new" do
it "returns an instance of String" do
str = String.new
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
end
it "accepts an encoding argument" do
@@ -28,7 +28,7 @@ describe "String.new" do
it "returns a new string given a string argument" do
str1 = "test"
str = String.new(str1)
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
str.should == str1
str << "more"
str.should == "testmore"
@@ -36,7 +36,7 @@ describe "String.new" do
it "returns an instance of a subclass" do
a = StringSpecs::MyString.new("blah")
- a.should be_an_instance_of(StringSpecs::MyString)
+ a.should.instance_of?(StringSpecs::MyString)
a.should == "blah"
end
@@ -51,8 +51,8 @@ describe "String.new" do
end
it "raises TypeError on inconvertible object" do
- -> { String.new 5 }.should raise_error(TypeError)
- -> { String.new nil }.should raise_error(TypeError)
+ -> { String.new 5 }.should.raise(TypeError)
+ -> { String.new nil }.should.raise(TypeError)
end
it "returns a binary String" do
diff --git a/spec/ruby/core/string/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb
index 35af3b5458..5a17fc1d87 100644
--- a/spec/ruby/core/string/ord_spec.rb
+++ b/spec/ruby/core/string/ord_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "String#ord" do
it "returns an Integer" do
- 'a'.ord.should be_an_instance_of(Integer)
+ 'a'.ord.should.instance_of?(Integer)
end
it "returns the codepoint of the first character in the String" do
@@ -23,11 +23,11 @@ describe "String#ord" do
end
it "raises an ArgumentError if called on an empty String" do
- -> { ''.ord }.should raise_error(ArgumentError)
+ -> { ''.ord }.should.raise(ArgumentError)
end
it "raises ArgumentError if the character is broken" do
s = "©".dup.force_encoding("US-ASCII")
- -> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII")
+ -> { s.ord }.should.raise(ArgumentError, "invalid byte sequence in US-ASCII")
end
end
diff --git a/spec/ruby/core/string/partition_spec.rb b/spec/ruby/core/string/partition_spec.rb
index d5370dcc73..29fe910b39 100644
--- a/spec/ruby/core/string/partition_spec.rb
+++ b/spec/ruby/core/string/partition_spec.rb
@@ -31,8 +31,8 @@ describe "String#partition with String" do
end
it "raises an error if not convertible to string" do
- ->{ "hello".partition(5) }.should raise_error(TypeError)
- ->{ "hello".partition(nil) }.should raise_error(TypeError)
+ ->{ "hello".partition(5) }.should.raise(TypeError)
+ ->{ "hello".partition(nil) }.should.raise(TypeError)
end
it "takes precedence over a given block" do
diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb
index 9da17451c6..0464141c37 100644
--- a/spec/ruby/core/string/plus_spec.rb
+++ b/spec/ruby/core/string/plus_spec.rb
@@ -21,17 +21,17 @@ describe "String#+" do
end
it "raises a TypeError when given any object that fails #to_str" do
- -> { "" + Object.new }.should raise_error(TypeError)
- -> { "" + 65 }.should raise_error(TypeError)
+ -> { "" + Object.new }.should.raise(TypeError)
+ -> { "" + 65 }.should.raise(TypeError)
end
it "doesn't return subclass instances" do
- (StringSpecs::MyString.new("hello") + "").should be_an_instance_of(String)
- (StringSpecs::MyString.new("hello") + "foo").should be_an_instance_of(String)
- (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
- (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("")).should be_an_instance_of(String)
- (StringSpecs::MyString.new("") + StringSpecs::MyString.new("")).should be_an_instance_of(String)
- ("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
- ("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String)
+ (StringSpecs::MyString.new("hello") + "").should.instance_of?(String)
+ (StringSpecs::MyString.new("hello") + "foo").should.instance_of?(String)
+ (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("foo")).should.instance_of?(String)
+ (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("")).should.instance_of?(String)
+ (StringSpecs::MyString.new("") + StringSpecs::MyString.new("")).should.instance_of?(String)
+ ("hello" + StringSpecs::MyString.new("foo")).should.instance_of?(String)
+ ("hello" + StringSpecs::MyString.new("")).should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/prepend_spec.rb b/spec/ruby/core/string/prepend_spec.rb
index 5248ea8056..a8da4e62cb 100644
--- a/spec/ruby/core/string/prepend_spec.rb
+++ b/spec/ruby/core/string/prepend_spec.rb
@@ -5,7 +5,7 @@ require_relative 'fixtures/classes'
describe "String#prepend" do
it "prepends the given argument to self and returns self" do
str = "world"
- str.prepend("hello ").should equal(str)
+ str.prepend("hello ").should.equal?(str)
str.should == "hello world"
end
@@ -17,16 +17,16 @@ describe "String#prepend" do
end
it "raises a TypeError if the given argument can't be converted to a String" do
- -> { "hello ".prepend [] }.should raise_error(TypeError)
- -> { 'hello '.prepend mock('x') }.should raise_error(TypeError)
+ -> { "hello ".prepend [] }.should.raise(TypeError)
+ -> { 'hello '.prepend mock('x') }.should.raise(TypeError)
end
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- -> { a.prepend "" }.should raise_error(FrozenError)
- -> { a.prepend "test" }.should raise_error(FrozenError)
+ -> { a.prepend "" }.should.raise(FrozenError)
+ -> { a.prepend "test" }.should.raise(FrozenError)
end
it "works when given a subclass instance" do
@@ -49,7 +49,7 @@ describe "String#prepend" do
it "returns self when given no arguments" do
str = "hello"
- str.prepend.should equal(str)
+ str.prepend.should.equal?(str)
str.should == "hello"
end
end
diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb
index aa6abe6036..e37c1125db 100644
--- a/spec/ruby/core/string/reverse_spec.rb
+++ b/spec/ruby/core/string/reverse_spec.rb
@@ -12,9 +12,9 @@ describe "String#reverse" do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String)
- StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String)
- StringSpecs::MyString.new("").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("stressed").reverse.should.instance_of?(String)
+ StringSpecs::MyString.new("m").reverse.should.instance_of?(String)
+ StringSpecs::MyString.new("").reverse.should.instance_of?(String)
end
it "reverses a string with multi byte characters" do
@@ -24,7 +24,7 @@ describe "String#reverse" do
it "works with a broken string" do
str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str.reverse.should == "體黑正\xDE\xDF軟微"
end
@@ -37,20 +37,20 @@ end
describe "String#reverse!" do
it "reverses self in place and always returns self" do
a = "stressed"
- a.reverse!.should equal(a)
+ a.reverse!.should.equal?(a)
a.should == "desserts"
"".reverse!.should == ""
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "anna".freeze.reverse! }.should raise_error(FrozenError)
- -> { "hello".freeze.reverse! }.should raise_error(FrozenError)
+ -> { "anna".freeze.reverse! }.should.raise(FrozenError)
+ -> { "hello".freeze.reverse! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "".freeze.reverse! }.should raise_error(FrozenError)
+ -> { "".freeze.reverse! }.should.raise(FrozenError)
end
it "reverses a string with multi byte characters" do
@@ -62,7 +62,7 @@ describe "String#reverse!" do
it "works with a broken string" do
str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str.reverse!
str.should == "體黑正\xDE\xDF軟微"
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 0863a9c3be..acecec224f 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -5,19 +5,19 @@ require_relative 'fixtures/classes'
describe "String#rindex with object" do
it "raises a TypeError if obj isn't a String or Regexp" do
not_supported_on :opal do
- -> { "hello".rindex(:sym) }.should raise_error(TypeError)
+ -> { "hello".rindex(:sym) }.should.raise(TypeError)
end
- -> { "hello".rindex(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rindex(mock('x')) }.should.raise(TypeError)
end
it "raises a TypeError if obj is an Integer" do
- -> { "hello".rindex(42) }.should raise_error(TypeError)
+ -> { "hello".rindex(42) }.should.raise(TypeError)
end
it "doesn't try to convert obj to an integer via to_int" do
obj = mock('x')
obj.should_not_receive(:to_int)
- -> { "hello".rindex(obj) }.should raise_error(TypeError)
+ -> { "hello".rindex(obj) }.should.raise(TypeError)
end
it "tries to convert obj to a string via to_str" do
@@ -193,7 +193,7 @@ describe "String#rindex with String" do
end
it "raises a TypeError when given offset is nil" do
- -> { "str".rindex("st", nil) }.should raise_error(TypeError)
+ -> { "str".rindex("st", nil) }.should.raise(TypeError)
end
it "handles a substring in a superset encoding" do
@@ -208,7 +208,7 @@ describe "String#rindex with String" do
str = 'abc'.dup.force_encoding("ISO-2022-JP")
pattern = 'b'.dup.force_encoding("EUC-JP")
- -> { str.rindex(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
+ -> { str.rindex(pattern) }.should.raise(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
end
end
@@ -362,7 +362,7 @@ describe "String#rindex with Regexp" do
end
it "raises a TypeError when given offset is nil" do
- -> { "str".rindex(/../, nil) }.should raise_error(TypeError)
+ -> { "str".rindex(/../, nil) }.should.raise(TypeError)
end
it "returns the reverse character index of a multibyte character" do
@@ -379,6 +379,6 @@ describe "String#rindex with Regexp" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
"あれ".rindex re
- end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
+ end.should.raise(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb
index 4ad3e54aea..9f9c369745 100644
--- a/spec/ruby/core/string/rjust_spec.rb
+++ b/spec/ruby/core/string/rjust_spec.rb
@@ -41,10 +41,10 @@ describe "String#rjust with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- -> { "hello".rjust("x") }.should raise_error(TypeError)
- -> { "hello".rjust("x", "y") }.should raise_error(TypeError)
- -> { "hello".rjust([]) }.should raise_error(TypeError)
- -> { "hello".rjust(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rjust("x") }.should.raise(TypeError)
+ -> { "hello".rjust("x", "y") }.should.raise(TypeError)
+ -> { "hello".rjust([]) }.should.raise(TypeError)
+ -> { "hello".rjust(mock('x')) }.should.raise(TypeError)
end
it "tries to convert padstr to a string using to_str" do
@@ -55,22 +55,22 @@ describe "String#rjust with length, padding" do
end
it "raises a TypeError when padstr can't be converted" do
- -> { "hello".rjust(20, []) }.should raise_error(TypeError)
- -> { "hello".rjust(20, Object.new)}.should raise_error(TypeError)
- -> { "hello".rjust(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rjust(20, []) }.should.raise(TypeError)
+ -> { "hello".rjust(20, Object.new)}.should.raise(TypeError)
+ -> { "hello".rjust(20, mock('x')) }.should.raise(TypeError)
end
it "raises an ArgumentError when padstr is empty" do
- -> { "hello".rjust(10, '') }.should raise_error(ArgumentError)
+ -> { "hello".rjust(10, '') }.should.raise(ArgumentError)
end
it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").rjust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").rjust(10).should.instance_of?(String)
+ StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
- "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "".rjust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
+ "foo".rjust(10, StringSpecs::MyString.new("x")).should.instance_of?(String)
end
describe "with width" do
@@ -78,7 +78,7 @@ describe "String#rjust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.rjust 5
result.should == " abc"
- result.encoding.should equal(Encoding::IBM437)
+ result.encoding.should.equal?(Encoding::IBM437)
end
end
@@ -87,14 +87,14 @@ describe "String#rjust with length, padding" do
str = "abc".dup.force_encoding Encoding::IBM437
result = str.rjust 5, "あ"
result.should == "ああabc"
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ア".encode Encoding::EUC_JP
-> do
"あれ".rjust 5, pat
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb
index cef0384c73..a7dd7430b7 100644
--- a/spec/ruby/core/string/rpartition_spec.rb
+++ b/spec/ruby/core/string/rpartition_spec.rb
@@ -43,8 +43,8 @@ describe "String#rpartition with String" do
end
it "raises an error if not convertible to string" do
- ->{ "hello".rpartition(5) }.should raise_error(TypeError)
- ->{ "hello".rpartition(nil) }.should raise_error(TypeError)
+ ->{ "hello".rpartition(5) }.should.raise(TypeError)
+ ->{ "hello".rpartition(nil) }.should.raise(TypeError)
end
it "handles a pattern in a superset encoding" do
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index 6d46eb590e..1638ea375d 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -30,7 +30,7 @@ end
describe "String#rstrip!" do
it "modifies self in place and returns self" do
a = " hello "
- a.rstrip!.should equal(a)
+ a.rstrip!.should.equal?(a)
a.should == " hello"
end
@@ -59,36 +59,22 @@ describe "String#rstrip!" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { " hello ".freeze.rstrip! }.should raise_error(FrozenError)
+ -> { " hello ".freeze.rstrip! }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "hello".freeze.rstrip! }.should raise_error(FrozenError)
- -> { "".freeze.rstrip! }.should raise_error(FrozenError)
+ -> { "hello".freeze.rstrip! }.should.raise(FrozenError)
+ -> { "".freeze.rstrip! }.should.raise(FrozenError)
end
- ruby_version_is "3.2" do
- it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
- s = "abc\xDF".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+ it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
+ s = "abc\xDF".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should == false
+ -> { s.rstrip! }.should.raise(Encoding::CompatibilityError)
- s = "abc\xDF ".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
- end
- end
-
- ruby_version_is ""..."3.2" do
- it "raises an ArgumentError if the last non-space codepoint is invalid" do
- s = "abc\xDF".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(ArgumentError)
-
- s = "abc\xDF ".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(ArgumentError)
- end
+ s = "abc\xDF ".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should == false
+ -> { s.rstrip! }.should.raise(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb
index bbe843b591..47fa7214c2 100644
--- a/spec/ruby/core/string/scan_spec.rb
+++ b/spec/ruby/core/string/scan_spec.rb
@@ -58,11 +58,11 @@ describe "String#scan" do
end
it "raises a TypeError if pattern isn't a Regexp and can't be converted to a String" do
- -> { "cruel world".scan(5) }.should raise_error(TypeError)
+ -> { "cruel world".scan(5) }.should.raise(TypeError)
not_supported_on :opal do
- -> { "cruel world".scan(:test) }.should raise_error(TypeError)
+ -> { "cruel world".scan(:test) }.should.raise(TypeError)
end
- -> { "cruel world".scan(mock('x')) }.should raise_error(TypeError)
+ -> { "cruel world".scan(mock('x')) }.should.raise(TypeError)
end
# jruby/jruby#5513
@@ -80,8 +80,8 @@ end
describe "String#scan with pattern and block" do
it "returns self" do
s = "foo"
- s.scan(/./) {}.should equal(s)
- s.scan(/roar/) {}.should equal(s)
+ s.scan(/./) {}.should.equal?(s)
+ s.scan(/roar/) {}.should.equal?(s)
end
it "passes each match to the block as one argument: an array" do
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index b9ef0f1a16..9dc55dbef7 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -38,9 +38,9 @@ describe "String#scrub with a default replacement" do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").scrub.should.instance_of?(String)
input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
+ StringSpecs::MyString.new(input).scrub.should.instance_of?(String)
end
end
@@ -75,7 +75,7 @@ describe "String#scrub with a custom replacement" do
xE4 = [0xE4].pack('C').force_encoding('utf-8')
block = -> { "foo#{x81}".scrub(xE4) }
- block.should raise_error(ArgumentError)
+ block.should.raise(ArgumentError)
end
it "returns a String in the same encoding as self" do
@@ -87,13 +87,13 @@ describe "String#scrub with a custom replacement" do
x81 = [0x81].pack('C').force_encoding('utf-8')
block = -> { "foo#{x81}".scrub(1) }
- block.should raise_error(TypeError)
+ block.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").scrub("*").should.instance_of?(String)
input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
+ StringSpecs::MyString.new(input).scrub("*").should.instance_of?(String)
end
end
@@ -121,9 +121,9 @@ describe "String#scrub with a block" do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").scrub { |b| "*" }.should.instance_of?(String)
input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String)
+ StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should.instance_of?(String)
end
end
@@ -146,7 +146,7 @@ describe "String#scrub!" do
input = "a"
input.freeze
input.scrub!
- input.frozen?.should be_true
+ input.frozen?.should == true
end
it "preserves the instance variables of already valid strings" do
diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb
index 85403ca62c..d9fcc279c0 100644
--- a/spec/ruby/core/string/setbyte_spec.rb
+++ b/spec/ruby/core/string/setbyte_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../spec_helper'
describe "String#setbyte" do
it "returns an Integer" do
- "a".setbyte(0,1).should be_kind_of(Integer)
+ "a".setbyte(0,1).should.is_a?(Integer)
end
it "modifies the receiver" do
@@ -34,9 +34,9 @@ describe "String#setbyte" do
it "can invalidate a String's encoding" do
str = "glark"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
str.setbyte(2,253)
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str = "ABC"
str.setbyte(0, 0x20) # ' '
@@ -58,11 +58,11 @@ describe "String#setbyte" do
end
it "raises an IndexError if the index is greater than the String bytesize" do
- -> { "?".setbyte(1, 97) }.should raise_error(IndexError)
+ -> { "?".setbyte(1, 97) }.should.raise(IndexError)
end
it "raises an IndexError if the negative index is greater magnitude than the String bytesize" do
- -> { "???".setbyte(-5, 97) }.should raise_error(IndexError)
+ -> { "???".setbyte(-5, 97) }.should.raise(IndexError)
end
it "sets a byte at an index greater than String size" do
@@ -84,12 +84,12 @@ describe "String#setbyte" do
it "raises a FrozenError if self is frozen" do
str = "cold".freeze
- str.frozen?.should be_true
- -> { str.setbyte(3,96) }.should raise_error(FrozenError)
+ str.frozen?.should == true
+ -> { str.setbyte(3,96) }.should.raise(FrozenError)
end
it "raises a TypeError unless the second argument is an Integer" do
- -> { "a".setbyte(0,'a') }.should raise_error(TypeError)
+ -> { "a".setbyte(0,'a') }.should.raise(TypeError)
end
it "calls #to_int to convert the index" do
diff --git a/spec/ruby/core/string/shared/byte_index_common.rb b/spec/ruby/core/string/shared/byte_index_common.rb
index 3de1453f4f..bae6cff49f 100644
--- a/spec/ruby/core/string/shared/byte_index_common.rb
+++ b/spec/ruby/core/string/shared/byte_index_common.rb
@@ -4,43 +4,43 @@ require_relative '../../../spec_helper'
describe :byte_index_common, shared: true do
describe "raises on type errors" do
it "raises a TypeError if passed nil" do
- -> { "abc".send(@method, nil) }.should raise_error(TypeError, "no implicit conversion of nil into String")
+ -> { "abc".send(@method, nil) }.should.raise(TypeError, "no implicit conversion of nil into String")
end
it "raises a TypeError if passed a boolean" do
- -> { "abc".send(@method, true) }.should raise_error(TypeError, "no implicit conversion of true into String")
+ -> { "abc".send(@method, true) }.should.raise(TypeError, "no implicit conversion of true into String")
end
it "raises a TypeError if passed a Symbol" do
not_supported_on :opal do
- -> { "abc".send(@method, :a) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
+ -> { "abc".send(@method, :a) }.should.raise(TypeError, "no implicit conversion of Symbol into String")
end
end
it "raises a TypeError if passed a Symbol" do
obj = mock('x')
obj.should_not_receive(:to_int)
- -> { "hello".send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
+ -> { "hello".send(@method, obj) }.should.raise(TypeError, "no implicit conversion of MockObject into String")
end
it "raises a TypeError if passed an Integer" do
- -> { "abc".send(@method, 97) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
+ -> { "abc".send(@method, 97) }.should.raise(TypeError, "no implicit conversion of Integer into String")
end
end
describe "with multibyte codepoints" do
it "raises an IndexError when byte offset lands in the middle of a multibyte character" do
- -> { "わ".send(@method, "", 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "わ".send(@method, "", 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- -> { "わ".send(@method, "", -1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- -> { "わ".send(@method, "", -2) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "わ".send(@method, "", 1) }.should.raise(IndexError, "offset 1 does not land on character boundary")
+ -> { "わ".send(@method, "", 2) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ -> { "わ".send(@method, "", -1) }.should.raise(IndexError, "offset 2 does not land on character boundary")
+ -> { "わ".send(@method, "", -2) }.should.raise(IndexError, "offset 1 does not land on character boundary")
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
"あれ".send(@method, re)
- end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
+ end.should.raise(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index c730643cf4..826d403589 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -11,10 +11,9 @@ describe :string_chars, shared: true do
it "returns self" do
s = StringSpecs::MyString.new "hello"
- s.send(@method){}.should equal(s)
+ s.send(@method){}.should.equal?(s)
end
-
it "is unicode aware" do
"\303\207\342\210\202\303\251\306\222g".send(@method).to_a.should ==
["\303\207", "\342\210\202", "\303\251", "\306\222", "g"]
@@ -34,7 +33,7 @@ describe :string_chars, shared: true do
it "works if the String's contents is invalid for its encoding" do
xA4 = [0xA4].pack('C')
xA4.force_encoding('UTF-8')
- xA4.valid_encoding?.should be_false
+ xA4.valid_encoding?.should == false
xA4.send(@method).to_a.should == [xA4.force_encoding("UTF-8")]
end
@@ -63,4 +62,25 @@ describe :string_chars, shared: true do
[0xA2].pack('C').force_encoding('SJIS')
]
end
+
+ it "returns individual chars for dummy encodings" do
+ "ab".dup.force_encoding(Encoding::UTF_7).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_7),
+ "\x62".dup.force_encoding(Encoding::UTF_7)
+ ]
+
+ "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_16),
+ "\x62".dup.force_encoding(Encoding::UTF_16),
+ "\x63".dup.force_encoding(Encoding::UTF_16),
+ "\x64".dup.force_encoding(Encoding::UTF_16)
+ ]
+
+ "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_32),
+ "\x62".dup.force_encoding(Encoding::UTF_32),
+ "\x63".dup.force_encoding(Encoding::UTF_32),
+ "\x64".dup.force_encoding(Encoding::UTF_32)
+ ]
+ end
end
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index f71263054a..b6abf6a3ff 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -1,15 +1,15 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_codepoints, shared: true do
it "returns self" do
s = "foo"
result = s.send(@method) {}
- result.should equal s
+ result.should.equal? s
end
it "raises an ArgumentError when self has an invalid encoding and a method is called on the returned Enumerator" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.send(@method).to_a }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.send(@method).to_a }.should.raise(ArgumentError)
end
it "yields each codepoint to the block if one is given" do
@@ -22,13 +22,13 @@ describe :string_codepoints, shared: true do
it "raises an ArgumentError if self's encoding is invalid and a block is given" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.send(@method) { } }.should raise_error(ArgumentError)
+ s.valid_encoding?.should == false
+ -> { s.send(@method) { } }.should.raise(ArgumentError)
end
it "yields codepoints as Integers" do
"glark\u{20}".send(@method).to_a.each do |codepoint|
- codepoint.should be_an_instance_of(Integer)
+ codepoint.should.instance_of?(Integer)
end
end
@@ -56,7 +56,12 @@ describe :string_codepoints, shared: true do
it "is synonymous with #bytes for Strings which are single-byte optimizable" do
s = "(){}".encode('ascii')
- s.ascii_only?.should be_true
+ s.ascii_only?.should == true
s.send(@method).to_a.should == s.bytes.to_a
end
+
+ it "returns individual bytes for dummy encodings UTF-16 and UTF-32" do
+ "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [97, 98, 99, 100]
+ "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [97, 98, 99, 100]
+ end
end
diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb
index dded9a69e7..60cd0e12d4 100644
--- a/spec/ruby/core/string/shared/concat.rb
+++ b/spec/ruby/core/string/shared/concat.rb
@@ -2,7 +2,7 @@
describe :string_concat, shared: true do
it "concatenates the given argument to self and returns self" do
str = 'hello '
- str.send(@method, 'world').should equal(str)
+ str.send(@method, 'world').should.equal?(str)
str.should == "hello world"
end
@@ -10,22 +10,22 @@ describe :string_concat, shared: true do
a = "hello"
a.freeze
- -> { a.send(@method, "") }.should raise_error(FrozenError)
- -> { a.send(@method, "test") }.should raise_error(FrozenError)
+ -> { a.send(@method, "") }.should.raise(FrozenError)
+ -> { a.send(@method, "test") }.should.raise(FrozenError)
end
it "returns a String when given a subclass instance" do
a = "hello"
a.send(@method, StringSpecs::MyString.new(" world"))
a.should == "hello world"
- a.should be_an_instance_of(String)
+ a.should.instance_of?(String)
end
it "returns an instance of same class when called on a subclass" do
str = StringSpecs::MyString.new("hello")
str.send(@method, " world")
str.should == "hello world"
- str.should be_an_instance_of(StringSpecs::MyString)
+ str.should.instance_of?(StringSpecs::MyString)
end
describe "with Integer" do
@@ -50,28 +50,28 @@ describe :string_concat, shared: true do
end
it "raises RangeError if the argument is an invalid codepoint for self's encoding" do
- -> { "".encode(Encoding::US_ASCII).send(@method, 256) }.should raise_error(RangeError)
- -> { "".encode(Encoding::EUC_JP).send(@method, 0x81) }.should raise_error(RangeError)
+ -> { "".encode(Encoding::US_ASCII).send(@method, 256) }.should.raise(RangeError)
+ -> { "".encode(Encoding::EUC_JP).send(@method, 0x81) }.should.raise(RangeError)
end
it "raises RangeError if the argument is negative" do
- -> { "".send(@method, -200) }.should raise_error(RangeError)
- -> { "".send(@method, -bignum_value) }.should raise_error(RangeError)
+ -> { "".send(@method, -200) }.should.raise(RangeError)
+ -> { "".send(@method, -bignum_value) }.should.raise(RangeError)
end
it "doesn't call to_int on its argument" do
x = mock('x')
x.should_not_receive(:to_int)
- -> { "".send(@method, x) }.should raise_error(TypeError)
+ -> { "".send(@method, x) }.should.raise(TypeError)
end
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- -> { a.send(@method, 0) }.should raise_error(FrozenError)
- -> { a.send(@method, 33) }.should raise_error(FrozenError)
+ -> { a.send(@method, 0) }.should.raise(FrozenError)
+ -> { a.send(@method, 33) }.should.raise(FrozenError)
end
end
end
@@ -91,7 +91,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are empty" do
- -> { "x".encode("UTF-16LE").send(@method, "y".encode("UTF-8")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "x".encode("UTF-16LE").send(@method, "y".encode("UTF-8")) }.should.raise(Encoding::CompatibilityError)
end
end
@@ -109,7 +109,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are empty" do
- -> { "x".encode("UTF-8").send(@method, "y".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "x".encode("UTF-8").send(@method, "y".encode("UTF-16LE")) }.should.raise(Encoding::CompatibilityError)
end
end
@@ -127,7 +127,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are ASCII-only" do
- -> { "\u00E9".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "\u00E9".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")) }.should.raise(Encoding::CompatibilityError)
end
end
@@ -147,13 +147,13 @@ describe :string_concat_type_coercion, shared: true do
end
it "raises a TypeError if the given argument can't be converted to a String" do
- -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
- -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
+ -> { 'hello '.send(@method, []) }.should.raise(TypeError)
+ -> { 'hello '.send(@method, mock('x')) }.should.raise(TypeError)
end
it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
obj = mock('world!')
obj.should_receive(:to_str).and_raise(NoMethodError)
- -> { 'hello '.send(@method, obj) }.should raise_error(NoMethodError)
+ -> { 'hello '.send(@method, obj) }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb
index 1ffd6aa0fd..59506c2901 100644
--- a/spec/ruby/core/string/shared/dedup.rb
+++ b/spec/ruby/core/string/shared/dedup.rb
@@ -4,7 +4,7 @@ describe :string_dedup, shared: true do
input = 'foo'.freeze
output = input.send(@method)
- output.should equal(input)
+ output.should.equal?(input)
output.should.frozen?
end
@@ -13,7 +13,7 @@ describe :string_dedup, shared: true do
output = input.send(@method)
output.should.frozen?
- output.should_not equal(input)
+ output.should_not.equal?(input)
output.should == 'foo'
end
@@ -21,22 +21,22 @@ describe :string_dedup, shared: true do
origin = "this is a string"
dynamic = %w(this is a string).join(' ')
- origin.should_not equal(dynamic)
- origin.send(@method).should equal(dynamic.send(@method))
+ origin.should_not.equal?(dynamic)
+ origin.send(@method).should.equal?(dynamic.send(@method))
end
it "returns the same object when it's called on the same String literal" do
- "unfrozen string".send(@method).should equal("unfrozen string".send(@method))
- "unfrozen string".send(@method).should_not equal("another unfrozen string".send(@method))
+ "unfrozen string".send(@method).should.equal?("unfrozen string".send(@method))
+ "unfrozen string".send(@method).should_not.equal?("another unfrozen string".send(@method))
end
it "deduplicates frozen strings" do
dynamic = %w(this string is frozen).join(' ').freeze
- dynamic.should_not equal("this string is frozen".freeze)
+ dynamic.should_not.equal?("this string is frozen".freeze)
- dynamic.send(@method).should equal("this string is frozen".freeze)
- dynamic.send(@method).should equal("this string is frozen".send(@method).freeze)
+ dynamic.send(@method).should.equal?("this string is frozen".freeze)
+ dynamic.send(@method).should.equal?("this string is frozen".send(@method).freeze)
end
it "does not deduplicate a frozen string when it has instance variables" do
@@ -44,8 +44,8 @@ describe :string_dedup, shared: true do
dynamic.instance_variable_set(:@a, 1)
dynamic.freeze
- dynamic.send(@method).should_not equal("this string is frozen".freeze)
- dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze)
- dynamic.send(@method).should equal(dynamic)
+ dynamic.send(@method).should_not.equal?("this string is frozen".freeze)
+ dynamic.send(@method).should_not.equal?("this string is frozen".send(@method).freeze)
+ dynamic.send(@method).should.equal?(dynamic)
end
end
diff --git a/spec/ruby/core/string/shared/each_char_without_block.rb b/spec/ruby/core/string/shared/each_char_without_block.rb
index 397100ce0e..3c32bae42b 100644
--- a/spec/ruby/core/string/shared/each_char_without_block.rb
+++ b/spec/ruby/core/string/shared/each_char_without_block.rb
@@ -6,7 +6,7 @@ describe :string_each_char_without_block, shared: true do
describe "when no block is given" do
it "returns an enumerator" do
enum = "hello".send(@method)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ['h', 'e', 'l', 'l', 'o']
end
diff --git a/spec/ruby/core/string/shared/each_codepoint_without_block.rb b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
index 31b4c02c9c..60d603954c 100644
--- a/spec/ruby/core/string/shared/each_codepoint_without_block.rb
+++ b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
@@ -1,14 +1,14 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_each_codepoint_without_block, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
- "".send(@method).should be_an_instance_of(Enumerator)
+ "".send(@method).should.instance_of?(Enumerator)
end
it "returns an Enumerator even when self has an invalid encoding" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- s.send(@method).should be_an_instance_of(Enumerator)
+ s.valid_encoding?.should == false
+ s.send(@method).should.instance_of?(Enumerator)
end
describe "returned Enumerator" do
@@ -24,7 +24,7 @@ describe :string_each_codepoint_without_block, shared: true do
it "should return the size of the string even when the string has an invalid encoding" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
+ s.valid_encoding?.should == false
s.send(@method).size.should == 1
end
end
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index 231a6d9d4f..127db876ad 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -46,14 +46,36 @@ describe :string_each_line, shared: true do
a.should == ["one\ntwo\r\nthree"]
end
- it "yields paragraphs (broken by 2 or more successive newlines) when passed '' and replaces multiple newlines with only two ones" do
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n", "and\nuniverse\n\n"]
+ context "when passed '' (paragraph mode, broken by 2 or more successive newlines)" do
+ it "replaces multiple newlines with only two ones" do
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\n\n", "and\nuniverse\n\n"]
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n", "and\nuniverse\n\n", "dog"]
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\n\n", "and\nuniverse\n\n", "dog"]
+ end
+
+ it 'handles \r\n-style newlines' do
+ a = []
+ "hello\nworld\r\n\r\n\nand\nuniverse\n\r\n\n\n\n".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\r\n\r\n", "and\nuniverse\n\r\n"]
+
+ a = []
+ "hello\r\nworld\n\n\nand\nuniverse\n\n\n\r\n\r\ndog".send(@method, '') { |s| a << s }
+ a.should == ["hello\r\nworld\n\n", "and\nuniverse\n\n", "dog"]
+ end
+
+ it "removes trailing newlines with `chomp: true`" do
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '', chomp: true) { |s| a << s }
+ a.should == ["hello\nworld", "and\nuniverse"]
+
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '', chomp: true) { |s| a << s }
+ a.should == ["hello\nworld", "and\nuniverse", "dog"]
+ end
end
describe "uses $/" do
@@ -93,7 +115,7 @@ describe :string_each_line, shared: true do
it "returns self" do
s = "hello\nworld"
- (s.send(@method) {}).should equal(s)
+ (s.send(@method) {}).should.equal?(s)
end
it "tries to convert the separator to a string using to_str" do
@@ -119,8 +141,8 @@ describe :string_each_line, shared: true do
end
it "raises a TypeError when the separator can't be converted to a string" do
- -> { "hello world".send(@method, false) {} }.should raise_error(TypeError)
- -> { "hello world".send(@method, mock('x')) {} }.should raise_error(TypeError)
+ -> { "hello world".send(@method, false) {} }.should.raise(TypeError)
+ -> { "hello world".send(@method, mock('x')) {} }.should.raise(TypeError)
end
it "accepts a string separator" do
@@ -128,7 +150,7 @@ describe :string_each_line, shared: true do
end
it "raises a TypeError when the separator is a symbol" do
- -> { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
+ -> { "hello world".send(@method, :o).to_a }.should.raise(TypeError)
end
context "when `chomp` keyword argument is passed" do
@@ -159,4 +181,18 @@ describe :string_each_line, shared: true do
a.should == ["hello\r\n", "world\r\n"]
end
end
+
+ it "does not split lines for dummy UTF-16" do
+ "a\nb".encode(Encoding::UTF_16).lines.should == [
+ "\xFE\xFF\x00\x61\x00\n\x00\x62".dup.force_encoding(Encoding::UTF_16)
+ ]
+
+ str = "\x00\n\n\x00".dup.force_encoding(Encoding::UTF_16)
+ str.lines.should == [str]
+ end
+
+ it "raises Encoding::ConverterNotFoundError for dummy UTF-7" do
+ str = "a\nb".dup.force_encoding(Encoding::UTF_7)
+ -> { str.lines }.should.raise(Encoding::ConverterNotFoundError)
+ end
end
diff --git a/spec/ruby/core/string/shared/each_line_without_block.rb b/spec/ruby/core/string/shared/each_line_without_block.rb
index 8e08b0390c..af0ab69c00 100644
--- a/spec/ruby/core/string/shared/each_line_without_block.rb
+++ b/spec/ruby/core/string/shared/each_line_without_block.rb
@@ -2,7 +2,7 @@ describe :string_each_line_without_block, shared: true do
describe "when no block is given" do
it "returns an enumerator" do
enum = "hello world".send(@method, ' ')
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == ["hello ", "world"]
end
diff --git a/spec/ruby/core/string/shared/encode.rb b/spec/ruby/core/string/shared/encode.rb
index 9466308886..7f644c26d9 100644
--- a/spec/ruby/core/string/shared/encode.rb
+++ b/spec/ruby/core/string/shared/encode.rb
@@ -11,7 +11,7 @@ describe :string_encode, shared: true do
it "transcodes a 7-bit String despite no generic converting being available" do
-> do
Encoding::Converter.new Encoding::Emacs_Mule, Encoding::BINARY
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
Encoding.default_internal = Encoding::Emacs_Mule
str = "\x79".force_encoding Encoding::BINARY
@@ -22,7 +22,7 @@ describe :string_encode, shared: true do
it "raises an Encoding::ConverterNotFoundError when no conversion is possible" do
Encoding.default_internal = Encoding::Emacs_Mule
str = [0x80].pack('C').force_encoding Encoding::BINARY
- -> { str.send(@method) }.should raise_error(Encoding::ConverterNotFoundError)
+ -> { str.send(@method) }.should.raise(Encoding::ConverterNotFoundError)
end
end
@@ -54,7 +54,7 @@ describe :string_encode, shared: true do
it "transcodes a 7-bit String despite no generic converting being available" do
-> do
Encoding::Converter.new Encoding::Emacs_Mule, Encoding::BINARY
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
str = "\x79".force_encoding Encoding::BINARY
str.send(@method, Encoding::Emacs_Mule).should == "y".force_encoding(Encoding::BINARY)
@@ -64,13 +64,21 @@ describe :string_encode, shared: true do
str = [0x80].pack('C').force_encoding Encoding::BINARY
-> do
str.send(@method, Encoding::Emacs_Mule)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
it "raises an Encoding::ConverterNotFoundError for an invalid encoding" do
-> do
"abc".send(@method, "xyz")
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
+ end
+
+ it "raises an Encoding::UndefinedConversionError when a character cannot be represented in the destination encoding" do
+ # U+0100 (Ā) is valid UTF-8 but not representable in windows-1252
+ str = "test\u0100".force_encoding('utf-8')
+ -> {
+ str.send(@method, Encoding::Windows_1252)
+ }.should.raise(Encoding::UndefinedConversionError)
end
end
@@ -99,7 +107,7 @@ describe :string_encode, shared: true do
str = [0x80].pack('C').force_encoding Encoding::BINARY
-> do
str.send(@method, invalid: :replace, undef: :replace)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ end.should.raise(Encoding::ConverterNotFoundError)
end
it "replaces invalid characters when replacing Emacs-Mule encoded strings" do
@@ -142,6 +150,14 @@ describe :string_encode, shared: true do
"ab#{xFF}c".send(@method, Encoding::ISO_8859_1, invalid: :replace).should == "ab?c"
end
+ it "raises UndefinedConversionError for characters not representable in destination encoding with only invalid: :replace" do
+ # U+0100 (Ā) is valid UTF-8 but not representable in windows-1252
+ str = "test\u0100".force_encoding('utf-8')
+ -> {
+ str.send(@method, Encoding::Windows_1252, invalid: :replace, replace: "")
+ }.should.raise(Encoding::UndefinedConversionError)
+ end
+
it "calls #to_hash to convert the options object" do
options = mock("string encode options")
options.should_receive(:to_hash).and_return({ undef: :replace })
@@ -213,19 +229,19 @@ describe :string_encode, shared: true do
obj.should_not_receive(:to_s)
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => obj })
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises an error if the key is not present in the hash" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: { "foo" => "bar" })
- }.should raise_error(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
+ }.should.raise(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
end
it "raises an error if the value is itself invalid" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => "\uffee" })
- }.should raise_error(ArgumentError, "too big fallback string")
+ }.should.raise(ArgumentError, "too big fallback string")
end
it "uses the hash's default value if set" do
@@ -278,7 +294,7 @@ describe :string_encode, shared: true do
it "raises an error" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: @non_hash_like)
- }.should raise_error(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
+ }.should.raise(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
end
end
@@ -300,13 +316,13 @@ describe :string_encode, shared: true do
obj.should_not_receive(:to_s)
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| obj })
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises an error if the returned value is itself invalid" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { "\uffee" })
- }.should raise_error(ArgumentError, "too big fallback string")
+ }.should.raise(ArgumentError, "too big fallback string")
end
end
@@ -328,13 +344,13 @@ describe :string_encode, shared: true do
obj.should_not_receive(:to_s)
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { obj })
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises an error if the returned value is itself invalid" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { "\uffee" })
- }.should raise_error(ArgumentError, "too big fallback string")
+ }.should.raise(ArgumentError, "too big fallback string")
end
end
@@ -367,13 +383,13 @@ describe :string_encode, shared: true do
it "does not call to_s on the returned value" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_to_s))
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises an error if the returned value is itself invalid" do
-> {
"B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_bad))
- }.should raise_error(ArgumentError, "too big fallback string")
+ }.should.raise(ArgumentError, "too big fallback string")
end
end
end
@@ -427,6 +443,6 @@ describe :string_encode, shared: true do
end
it "raises ArgumentError if the value of the :xml option is not :text or :attr" do
- -> { ''.send(@method, "UTF-8", xml: :other) }.should raise_error(ArgumentError)
+ -> { ''.send(@method, "UTF-8", xml: :other) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb
index 845b0a3e15..0e356c69e8 100644
--- a/spec/ruby/core/string/shared/eql.rb
+++ b/spec/ruby/core/string/shared/eql.rb
@@ -1,35 +1,35 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :string_eql_value, shared: true do
it "returns true if self <=> string returns 0" do
- 'hello'.send(@method, 'hello').should be_true
+ 'hello'.send(@method, 'hello').should == true
end
it "returns false if self <=> string does not return 0" do
- "more".send(@method, "MORE").should be_false
- "less".send(@method, "greater").should be_false
+ "more".send(@method, "MORE").should == false
+ "less".send(@method, "greater").should == false
end
it "ignores encoding difference of compatible string" do
- "hello".dup.force_encoding("utf-8").send(@method, "hello".dup.force_encoding("iso-8859-1")).should be_true
+ "hello".dup.force_encoding("utf-8").send(@method, "hello".dup.force_encoding("iso-8859-1")).should == true
end
it "considers encoding difference of incompatible string" do
- "\xff".dup.force_encoding("utf-8").send(@method, "\xff".dup.force_encoding("iso-8859-1")).should be_false
+ "\xff".dup.force_encoding("utf-8").send(@method, "\xff".dup.force_encoding("iso-8859-1")).should == false
end
it "considers encoding compatibility" do
- "abcd".dup.force_encoding("utf-8").send(@method, "abcd".dup.force_encoding("utf-32le")).should be_false
+ "abcd".dup.force_encoding("utf-8").send(@method, "abcd".dup.force_encoding("utf-32le")).should == false
end
it "ignores subclass differences" do
a = "hello"
b = StringSpecs::MyString.new("hello")
- a.send(@method, b).should be_true
- b.send(@method, a).should be_true
+ a.send(@method, b).should == true
+ b.send(@method, a).should == true
end
it "returns true when comparing 2 empty strings but one is not ASCII-compatible" do
diff --git a/spec/ruby/core/string/shared/equal_value.rb b/spec/ruby/core/string/shared/equal_value.rb
index fccafb5821..dfc5c7cd29 100644
--- a/spec/ruby/core/string/shared/equal_value.rb
+++ b/spec/ruby/core/string/shared/equal_value.rb
@@ -3,11 +3,11 @@ require_relative '../fixtures/classes'
describe :string_equal_value, shared: true do
it "returns false if obj does not respond to to_str" do
- 'hello'.send(@method, 5).should be_false
+ 'hello'.send(@method, 5).should == false
not_supported_on :opal do
- 'hello'.send(@method, :hello).should be_false
+ 'hello'.send(@method, :hello).should == false
end
- 'hello'.send(@method, mock('x')).should be_false
+ 'hello'.send(@method, mock('x')).should == false
end
it "returns obj == self if obj responds to to_str" do
@@ -20,10 +20,10 @@ describe :string_equal_value, shared: true do
# Don't use @method for :== in `obj.should_receive(:==)`
obj.should_receive(:==).and_return(true)
- 'hello'.send(@method, obj).should be_true
+ 'hello'.send(@method, obj).should == true
end
it "is not fooled by NUL characters" do
- "abc\0def".send(@method, "abc\0xyz").should be_false
+ "abc\0def".send(@method, "abc\0xyz").should == false
end
end
diff --git a/spec/ruby/core/string/shared/grapheme_clusters.rb b/spec/ruby/core/string/shared/grapheme_clusters.rb
index 8b666868b1..dd8c7ed5fe 100644
--- a/spec/ruby/core/string/shared/grapheme_clusters.rb
+++ b/spec/ruby/core/string/shared/grapheme_clusters.rb
@@ -9,8 +9,17 @@ describe :string_grapheme_clusters, shared: true do
a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
end
+ it "returns grapheme clusters for various UTF encodings" do
+ [Encoding::UTF_16LE, Encoding::UTF_16BE, Encoding::UTF_32LE, Encoding::UTF_32BE].each do |enc|
+ a = []
+ # test string: abc[rainbow flag emoji][paw prints]
+ "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}".encode(enc).send(@method) { |c| a << c }
+ a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"].map { |s| s.encode(enc) }
+ end
+ end
+
it "returns self" do
s = StringSpecs::MyString.new "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
- s.send(@method) {}.should equal(s)
+ s.send(@method) {}.should.equal?(s)
end
end
diff --git a/spec/ruby/core/string/shared/partition.rb b/spec/ruby/core/string/shared/partition.rb
index 4cac149ce5..3f7e606eb3 100644
--- a/spec/ruby/core/string/shared/partition.rb
+++ b/spec/ruby/core/string/shared/partition.rb
@@ -4,15 +4,15 @@ require_relative '../fixtures/classes'
describe :string_partition, shared: true do
it "returns String instances when called on a subclass" do
StringSpecs::MyString.new("hello").send(@method, "l").each do |item|
- item.should be_an_instance_of(String)
+ item.should.instance_of?(String)
end
StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
- item.should be_an_instance_of(String)
+ item.should.instance_of?(String)
end
StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
- item.should be_an_instance_of(String)
+ item.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb
index 24dac0eb27..73b26351f1 100644
--- a/spec/ruby/core/string/shared/replace.rb
+++ b/spec/ruby/core/string/shared/replace.rb
@@ -2,7 +2,7 @@
describe :string_replace, shared: true do
it "returns self" do
a = "a"
- a.send(@method, "b").should equal(a)
+ a.send(@method, "b").should.equal?(a)
end
it "replaces the content of self with other" do
@@ -20,7 +20,7 @@ describe :string_replace, shared: true do
it "carries over the encoding invalidity" do
a = "\u{8765}".force_encoding('ascii')
- "".send(@method, a).valid_encoding?.should be_false
+ "".send(@method, a).valid_encoding?.should == false
end
it "tries to convert other to string using to_str" do
@@ -30,19 +30,19 @@ describe :string_replace, shared: true do
end
it "raises a TypeError if other can't be converted to string" do
- -> { "hello".send(@method, 123) }.should raise_error(TypeError)
- -> { "hello".send(@method, []) }.should raise_error(TypeError)
- -> { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 123) }.should.raise(TypeError)
+ -> { "hello".send(@method, []) }.should.raise(TypeError)
+ -> { "hello".send(@method, mock('x')) }.should.raise(TypeError)
end
it "raises a FrozenError on a frozen instance that is modified" do
a = "hello".freeze
- -> { a.send(@method, "world") }.should raise_error(FrozenError)
+ -> { a.send(@method, "world") }.should.raise(FrozenError)
end
# see [ruby-core:23666]
it "raises a FrozenError on a frozen instance when self-replacing" do
a = "hello".freeze
- -> { a.send(@method, a) }.should raise_error(FrozenError)
+ -> { a.send(@method, a) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 7b9b9f6a14..d296ab6680 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -21,17 +21,17 @@ describe :string_slice, shared: true do
end
it "raises a TypeError if the given index is nil" do
- -> { "hello".send(@method, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError if the given index can't be converted to an Integer" do
- -> { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
- -> { "hello".send(@method, {}) }.should raise_error(TypeError)
- -> { "hello".send(@method, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x')) }.should.raise(TypeError)
+ -> { "hello".send(@method, {}) }.should.raise(TypeError)
+ -> { "hello".send(@method, []) }.should.raise(TypeError)
end
it "raises a RangeError if the index is too big" do
- -> { "hello".send(@method, bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value) }.should.raise(RangeError)
end
end
@@ -145,35 +145,35 @@ describe :string_slice_index_length, shared: true do
end
it "raises a TypeError when idx or length can't be converted to an integer" do
- -> { "hello".send(@method, mock('x'), 0) }.should raise_error(TypeError)
- -> { "hello".send(@method, 0, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x'), 0) }.should.raise(TypeError)
+ -> { "hello".send(@method, 0, mock('x')) }.should.raise(TypeError)
# I'm deliberately including this here.
# It means that str.send(@method, other, idx) isn't supported.
- -> { "hello".send(@method, "", 0) }.should raise_error(TypeError)
+ -> { "hello".send(@method, "", 0) }.should.raise(TypeError)
end
it "raises a TypeError when the given index or the given length is nil" do
- -> { "hello".send(@method, 1, nil) }.should raise_error(TypeError)
- -> { "hello".send(@method, nil, 1) }.should raise_error(TypeError)
- -> { "hello".send(@method, nil, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 1, nil) }.should.raise(TypeError)
+ -> { "hello".send(@method, nil, 1) }.should.raise(TypeError)
+ -> { "hello".send(@method, nil, nil) }.should.raise(TypeError)
end
it "raises a RangeError if the index or length is too big" do
- -> { "hello".send(@method, bignum_value, 1) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value, 1) }.should.raise(RangeError)
+ -> { "hello".send(@method, 0, bignum_value) }.should.raise(RangeError)
end
it "raises a RangeError if the index or length is too small" do
- -> { "hello".send(@method, -bignum_value, 1) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0, -bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, -bignum_value, 1) }.should.raise(RangeError)
+ -> { "hello".send(@method, 0, -bignum_value) }.should.raise(RangeError)
end
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, 0,0).should be_an_instance_of(String)
- s.send(@method, 0,4).should be_an_instance_of(String)
- s.send(@method, 1,4).should be_an_instance_of(String)
+ s.send(@method, 0,0).should.instance_of?(String)
+ s.send(@method, 0,4).should.instance_of?(String)
+ s.send(@method, 1,4).should.instance_of?(String)
end
it "handles repeated application" do
@@ -250,9 +250,9 @@ describe :string_slice_range, shared: true do
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, 0...0).should be_an_instance_of(String)
- s.send(@method, 0..4).should be_an_instance_of(String)
- s.send(@method, 1..4).should be_an_instance_of(String)
+ s.send(@method, 0...0).should.instance_of?(String)
+ s.send(@method, 0..4).should.instance_of?(String)
+ s.send(@method, 1..4).should.instance_of?(String)
end
it "calls to_int on range arguments" do
@@ -293,12 +293,12 @@ describe :string_slice_range, shared: true do
end
it "raises a type error if a range is passed with a length" do
- ->{ "hello".send(@method, 1..2, 1) }.should raise_error(TypeError)
+ ->{ "hello".send(@method, 1..2, 1) }.should.raise(TypeError)
end
it "raises a RangeError if one of the bound is too big" do
- -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
- -> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should.raise(RangeError)
+ -> { "hello".send(@method, 0..bignum_value) }.should.raise(RangeError)
end
it "works with endless ranges" do
@@ -333,8 +333,8 @@ describe :string_slice_regexp, shared: true do
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, //).should be_an_instance_of(String)
- s.send(@method, /../).should be_an_instance_of(String)
+ s.send(@method, //).should.instance_of?(String)
+ s.send(@method, /../).should.instance_of?(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -394,19 +394,19 @@ describe :string_slice_regexp_index, shared: true do
end
it "raises a TypeError when the given index can't be converted to Integer" do
- -> { "hello".send(@method, /(.)(.)(.)/, mock('x')) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(.)(.)(.)/, {}) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(.)(.)(.)/, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, mock('x')) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, {}) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, []) }.should.raise(TypeError)
end
it "raises a TypeError when the given index is nil" do
- -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should.raise(TypeError)
end
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String)
- s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String)
+ s.send(@method, /(.)(.)/, 0).should.instance_of?(String)
+ s.send(@method, /(.)(.)/, 1).should.instance_of?(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -442,14 +442,14 @@ describe :string_slice_string, shared: true do
o = mock('x')
o.should_not_receive(:to_str)
- -> { "hello".send(@method, o) }.should raise_error(TypeError)
+ -> { "hello".send(@method, o) }.should.raise(TypeError)
end
it "returns a String instance when given a subclass instance" do
s = StringSpecs::MyString.new("el")
r = "hello".send(@method, s)
r.should == "el"
- r.should be_an_instance_of(String)
+ r.should.instance_of?(String)
end
end
@@ -476,28 +476,28 @@ describe :string_slice_regexp_group, shared: true do
end
it "returns nil if there is no match" do
- "hello there".send(@method, /(?<whut>what?)/, 'whut').should be_nil
+ "hello there".send(@method, /(?<whut>what?)/, 'whut').should == nil
end
it "raises an IndexError if there is no capture for the given name" do
-> do
"hello there".send(@method, /[aeiou](.)\1/, 'non')
- end.should raise_error(IndexError)
+ end.should.raise(IndexError)
end
it "raises a TypeError when the given name is not a String" do
- -> { "hello".send(@method, /(?<q>.)/, mock('x')) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(?<q>.)/, {}) }.should raise_error(TypeError)
- -> { "hello".send(@method, /(?<q>.)/, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, mock('x')) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, {}) }.should.raise(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, []) }.should.raise(TypeError)
end
it "raises an IndexError when given the empty String as a group name" do
- -> { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
+ -> { "hello".send(@method, /(?<q>)/, '') }.should.raise(IndexError)
end
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
+ s.send(@method, /(?<q>.)/, 'q').should.instance_of?(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -505,13 +505,13 @@ describe :string_slice_regexp_group, shared: true do
$~[0].should == 'he'
'hello'.send(@method, /(?<non>not)/, 'non')
- $~.should be_nil
+ $~.should == nil
end
end
end
describe :string_slice_symbol, shared: true do
it "raises TypeError" do
- -> { 'hello'.send(@method, :hello) }.should raise_error(TypeError)
+ -> { 'hello'.send(@method, :hello) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/string/shared/strip.rb b/spec/ruby/core/string/shared/strip.rb
index 3af77b50fe..39c7232ff9 100644
--- a/spec/ruby/core/string/shared/strip.rb
+++ b/spec/ruby/core/string/shared/strip.rb
@@ -7,8 +7,8 @@ describe :string_strip, shared: true do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new(" hello ").send(@method).should.instance_of?(String)
+ StringSpecs::MyString.new(" ").send(@method).should.instance_of?(String)
+ StringSpecs::MyString.new("").send(@method).should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb
index b69a394875..8f1d327741 100644
--- a/spec/ruby/core/string/shared/succ.rb
+++ b/spec/ruby/core/string/shared/succ.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_succ, shared: true do
it "returns an empty string for empty strings" do
"".send(@method).should == ""
@@ -60,9 +60,9 @@ describe :string_succ, shared: true do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").send(@method).should.instance_of?(String)
+ StringSpecs::MyString.new("a").send(@method).should.instance_of?(String)
+ StringSpecs::MyString.new("z").send(@method).should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
@@ -75,13 +75,13 @@ describe :string_succ_bang, shared: true do
["", "abcd", "THX1138"].each do |s|
s = +s
r = s.dup.send(@method)
- s.send(@method).should equal(s)
+ s.send(@method).should.equal?(s)
s.should == r
end
end
it "raises a FrozenError if self is frozen" do
- -> { "".freeze.send(@method) }.should raise_error(FrozenError)
- -> { "abcd".freeze.send(@method) }.should raise_error(FrozenError)
+ -> { "".freeze.send(@method) }.should.raise(FrozenError)
+ -> { "abcd".freeze.send(@method) }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/shared/to_s.rb b/spec/ruby/core/string/shared/to_s.rb
index 4b87a6cbe1..96c59470d6 100644
--- a/spec/ruby/core/string/shared/to_s.rb
+++ b/spec/ruby/core/string/shared/to_s.rb
@@ -1,13 +1,13 @@
describe :string_to_s, shared: true do
it "returns self when self.class == String" do
a = "a string"
- a.should equal(a.send(@method))
+ a.should.equal?(a.send(@method))
end
it "returns a new instance of String when called on a subclass" do
a = StringSpecs::MyString.new("a string")
s = a.send(@method)
s.should == "a string"
- s.should be_an_instance_of(String)
+ s.should.instance_of?(String)
end
end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
index 833eae100e..2a8a2e3182 100644
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ b/spec/ruby/core/string/shared/to_sym.rb
@@ -1,42 +1,42 @@
describe :string_to_sym, shared: true do
it "returns the symbol corresponding to self" do
- "Koala".send(@method).should equal :Koala
- 'cat'.send(@method).should equal :cat
- '@cat'.send(@method).should equal :@cat
- 'cat and dog'.send(@method).should equal :"cat and dog"
- "abc=".send(@method).should equal :abc=
+ "Koala".send(@method).should.equal? :Koala
+ 'cat'.send(@method).should.equal? :cat
+ '@cat'.send(@method).should.equal? :@cat
+ 'cat and dog'.send(@method).should.equal? :"cat and dog"
+ "abc=".send(@method).should.equal? :abc=
end
it "does not special case +(binary) and -(binary)" do
- "+(binary)".send(@method).should equal :"+(binary)"
- "-(binary)".send(@method).should equal :"-(binary)"
+ "+(binary)".send(@method).should.equal? :"+(binary)"
+ "-(binary)".send(@method).should.equal? :"-(binary)"
end
it "does not special case certain operators" do
- "!@".send(@method).should equal :"!@"
- "~@".send(@method).should equal :"~@"
- "!(unary)".send(@method).should equal :"!(unary)"
- "~(unary)".send(@method).should equal :"~(unary)"
- "+(unary)".send(@method).should equal :"+(unary)"
- "-(unary)".send(@method).should equal :"-(unary)"
+ "!@".send(@method).should.equal? :"!@"
+ "~@".send(@method).should.equal? :"~@"
+ "!(unary)".send(@method).should.equal? :"!(unary)"
+ "~(unary)".send(@method).should.equal? :"~(unary)"
+ "+(unary)".send(@method).should.equal? :"+(unary)"
+ "-(unary)".send(@method).should.equal? :"-(unary)"
end
it "returns a US-ASCII Symbol for a UTF-8 String containing only US-ASCII characters" do
sym = "foobar".send(@method)
sym.encoding.should == Encoding::US_ASCII
- sym.should equal :"foobar"
+ sym.should.equal? :"foobar"
end
it "returns a US-ASCII Symbol for a binary String containing only US-ASCII characters" do
sym = "foobar".b.send(@method)
sym.encoding.should == Encoding::US_ASCII
- sym.should equal :"foobar"
+ sym.should.equal? :"foobar"
end
it "returns a UTF-8 Symbol for a UTF-8 String containing non US-ASCII characters" do
sym = "il était une fois".send(@method)
sym.encoding.should == Encoding::UTF_8
- sym.should equal :"il était une #{'fois'}"
+ sym.should.equal? :"il était une #{'fois'}"
end
it "returns a UTF-16LE Symbol for a UTF-16LE String containing non US-ASCII characters" do
@@ -67,6 +67,6 @@ describe :string_to_sym, shared: true do
invalid_utf8.should_not.valid_encoding?
-> {
invalid_utf8.send(@method)
- }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
+ }.should.raise(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
end
end
diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb
index 5aba2d3be0..14e2251b3f 100644
--- a/spec/ruby/core/string/slice_spec.rb
+++ b/spec/ruby/core/string/slice_spec.rb
@@ -54,9 +54,9 @@ describe "String#slice! with index" do
end
it "raises a FrozenError if self is frozen" do
- -> { "hello".freeze.slice!(1) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(10) }.should raise_error(FrozenError)
- -> { "".freeze.slice!(0) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(1) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(10) }.should.raise(FrozenError)
+ -> { "".freeze.slice!(0) }.should.raise(FrozenError)
end
it "calls to_int on index" do
@@ -110,13 +110,13 @@ describe "String#slice! with index, length" do
end
it "raises a FrozenError if self is frozen" do
- -> { "hello".freeze.slice!(1, 2) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(10, 3) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(-10, 3)}.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(4, -3) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(10, 3) }.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(-10, 3)}.should raise_error(FrozenError)
- -> { "hello".freeze.slice!(4, -3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(1, 2) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(10, 3) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(-10, 3)}.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(4, -3) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(10, 3) }.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(-10, 3)}.should.raise(FrozenError)
+ -> { "hello".freeze.slice!(4, -3) }.should.raise(FrozenError)
end
it "calls to_int on idx and length" do
@@ -134,8 +134,8 @@ describe "String#slice! with index, length" do
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(0, 0).should be_an_instance_of(String)
- s.slice!(0, 4).should be_an_instance_of(String)
+ s.slice!(0, 0).should.instance_of?(String)
+ s.slice!(0, 4).should.instance_of?(String)
end
it "returns the substring given by the character offsets" do
@@ -177,8 +177,8 @@ describe "String#slice! Range" do
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(0...0).should be_an_instance_of(String)
- s.slice!(0..4).should be_an_instance_of(String)
+ s.slice!(0...0).should.instance_of?(String)
+ s.slice!(0..4).should.instance_of?(String)
end
it "calls to_int on range arguments" do
@@ -228,12 +228,12 @@ describe "String#slice! Range" do
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "hello".freeze.slice!(1..3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(1..3) }.should.raise(FrozenError)
end
# see redmine #1551
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "hello".freeze.slice!(10..20)}.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(10..20)}.should.raise(FrozenError)
end
end
@@ -256,8 +256,8 @@ describe "String#slice! with Regexp" do
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(//).should be_an_instance_of(String)
- s.slice!(/../).should be_an_instance_of(String)
+ s.slice!(//).should.instance_of?(String)
+ s.slice!(/../).should.instance_of?(String)
end
it "returns the matching portion of self with a multi byte character" do
@@ -274,11 +274,11 @@ describe "String#slice! with Regexp" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/s.*t/) }.should.raise(FrozenError)
end
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> { "this is a string".freeze.slice!(/zzz/) }.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/zzz/) }.should.raise(FrozenError)
end
end
@@ -316,8 +316,8 @@ describe "String#slice! with Regexp, index" do
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(/(.)(.)/, 0).should be_an_instance_of(String)
- s.slice!(/(.)(.)/, 1).should be_an_instance_of(String)
+ s.slice!(/(.)(.)/, 0).should.instance_of?(String)
+ s.slice!(/(.)(.)/, 1).should.instance_of?(String)
end
it "returns the encoding aware capture for the given index" do
@@ -342,9 +342,9 @@ describe "String#slice! with Regexp, index" do
end
it "raises a FrozenError if self is frozen" do
- -> { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!(/zzz/, 0)}.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!(/(.)/, 2)}.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/s.*t/) }.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!(/zzz/, 0)}.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!(/(.)/, 2)}.should.raise(FrozenError)
end
end
@@ -372,19 +372,19 @@ describe "String#slice! with String" do
o = mock('x')
o.should_not_receive(:to_str)
- -> { "hello".slice!(o) }.should raise_error(TypeError)
+ -> { "hello".slice!(o) }.should.raise(TypeError)
end
it "returns a subclass instance when given a subclass instance" do
s = StringSpecs::MyString.new("el")
r = "hello".slice!(s)
r.should == "el"
- r.should be_an_instance_of(String)
+ r.should.instance_of?(String)
end
it "raises a FrozenError if self is frozen" do
- -> { "hello hello".freeze.slice!('llo') }.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!('zzz')}.should raise_error(FrozenError)
- -> { "this is a string".freeze.slice!('zzz')}.should raise_error(FrozenError)
+ -> { "hello hello".freeze.slice!('llo') }.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!('zzz')}.should.raise(FrozenError)
+ -> { "this is a string".freeze.slice!('zzz')}.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 3c6d1864d1..6e8c1c6219 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -6,15 +6,15 @@ describe "String#split with String" do
it "throws an ArgumentError if the string is not a valid" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- -> { s.split }.should raise_error(ArgumentError)
- -> { s.split(':') }.should raise_error(ArgumentError)
+ -> { s.split }.should.raise(ArgumentError)
+ -> { s.split(':') }.should.raise(ArgumentError)
end
it "throws an ArgumentError if the pattern is not a valid string" do
str = 'проверка'
broken_str = "\xDF".dup.force_encoding(Encoding::UTF_8)
- -> { str.split(broken_str) }.should raise_error(ArgumentError)
+ -> { str.split(broken_str) }.should.raise(ArgumentError)
end
it "splits on multibyte characters" do
@@ -94,7 +94,7 @@ describe "String#split with String" do
end
it "raises a RangeError when the limit is larger than int" do
- -> { "a,b".split(" ", 2147483649) }.should raise_error(RangeError)
+ -> { "a,b".split(" ", 2147483649) }.should.raise(RangeError)
end
it "defaults to $; when string isn't given or nil" do
@@ -119,21 +119,21 @@ describe "String#split with String" do
$; = old_fs
end
end
+ end
- context "when $; is not nil" do
- before do
- suppress_warning do
- @old_value, $; = $;, 'foobar'
- end
+ context "when $; is not nil" do
+ before do
+ suppress_warning do
+ @old_value, $; = $;, 'foobar'
end
+ end
- after do
- $; = @old_value
- end
+ after do
+ $; = @old_value
+ end
- it "warns" do
- -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
- end
+ it "warns" do
+ -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
end
end
@@ -197,11 +197,11 @@ describe "String#split with String" do
["", ".", " "].each do |pat|
[-1, 0, 1, 2].each do |limit|
StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(String)
+ x.should.instance_of?(String)
end
str.split(StringSpecs::MyString.new(pat), limit).each do |x|
- x.should be_an_instance_of(String)
+ x.should.instance_of?(String)
end
end
end
@@ -231,7 +231,7 @@ describe "String#split with Regexp" do
it "throws an ArgumentError if the string is not a valid" do
s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- -> { s.split(/./) }.should raise_error(ArgumentError)
+ -> { s.split(/./) }.should.raise(ArgumentError)
end
it "divides self on regexp matches" do
@@ -367,8 +367,8 @@ describe "String#split with Regexp" do
end
it "returns a type error if limit can't be converted to an integer" do
- -> {"1.2.3.4".split(".", "three")}.should raise_error(TypeError)
- -> {"1.2.3.4".split(".", nil) }.should raise_error(TypeError)
+ -> {"1.2.3.4".split(".", "three")}.should.raise(TypeError)
+ -> {"1.2.3.4".split(".", nil) }.should.raise(TypeError)
end
it "doesn't set $~" do
@@ -391,7 +391,7 @@ describe "String#split with Regexp" do
[//, /:/, /\s+/].each do |pat|
[-1, 0, 1, 2].each do |limit|
StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(String)
+ x.should.instance_of?(String)
end
end
end
@@ -413,7 +413,7 @@ describe "String#split with Regexp" do
broken_str.force_encoding('binary')
broken_str.chop!
broken_str.force_encoding('utf-8')
- ->{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError)
+ ->{ broken_str.split(/\r\n|\r|\n/) }.should.raise(ArgumentError)
end
# See https://bugs.ruby-lang.org/issues/12689 and https://github.com/jruby/jruby/issues/4868
@@ -522,19 +522,19 @@ describe "String#split with Regexp" do
StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
first, last = a
- first.should be_an_instance_of(String)
+ first.should.instance_of?(String)
first.should == "a"
- last.should be_an_instance_of(String)
+ last.should.instance_of?(String)
last.should == "b"
end
end
it "raises a TypeError when not called with nil, String, or Regexp" do
- -> { "hello".split(42) }.should raise_error(TypeError)
- -> { "hello".split(:ll) }.should raise_error(TypeError)
- -> { "hello".split(false) }.should raise_error(TypeError)
- -> { "hello".split(Object.new) }.should raise_error(TypeError)
+ -> { "hello".split(42) }.should.raise(TypeError)
+ -> { "hello".split(:ll) }.should.raise(TypeError)
+ -> { "hello".split(false) }.should.raise(TypeError)
+ -> { "hello".split(Object.new) }.should.raise(TypeError)
end
it "returns Strings in the same encoding as self" do
diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb
index 4ea238e6b5..52b6e1eed4 100644
--- a/spec/ruby/core/string/squeeze_spec.rb
+++ b/spec/ruby/core/string/squeeze_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -51,8 +51,8 @@ describe "String#squeeze" do
it "raises an ArgumentError when the parameter is out of sequence" do
s = "--subbookkeeper--"
- -> { s.squeeze("e-b") }.should raise_error(ArgumentError)
- -> { s.squeeze("^e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze("e-b") }.should.raise(ArgumentError)
+ -> { s.squeeze("^e-b") }.should.raise(ArgumentError)
end
it "tries to convert each set arg to a string using to_str" do
@@ -71,20 +71,20 @@ describe "String#squeeze" do
end
it "raises a TypeError when one set arg can't be converted to a string" do
- -> { "hello world".squeeze([]) }.should raise_error(TypeError)
- -> { "hello world".squeeze(Object.new)}.should raise_error(TypeError)
- -> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".squeeze([]) }.should.raise(TypeError)
+ -> { "hello world".squeeze(Object.new)}.should.raise(TypeError)
+ -> { "hello world".squeeze(mock('x')) }.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
+ StringSpecs::MyString.new("oh no!!!").squeeze("!").should.instance_of?(String)
end
end
describe "String#squeeze!" do
it "modifies self in place and returns self" do
a = "yellow moon"
- a.squeeze!.should equal(a)
+ a.squeeze!.should.equal?(a)
a.should == "yelow mon"
end
@@ -97,15 +97,15 @@ describe "String#squeeze!" do
it "raises an ArgumentError when the parameter is out of sequence" do
s = "--subbookkeeper--"
- -> { s.squeeze!("e-b") }.should raise_error(ArgumentError)
- -> { s.squeeze!("^e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze!("e-b") }.should.raise(ArgumentError)
+ -> { s.squeeze!("^e-b") }.should.raise(ArgumentError)
end
it "raises a FrozenError when self is frozen" do
a = "yellow moon"
a.freeze
- -> { a.squeeze!("") }.should raise_error(FrozenError)
- -> { a.squeeze! }.should raise_error(FrozenError)
+ -> { a.squeeze!("") }.should.raise(FrozenError)
+ -> { a.squeeze! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb
index 35e33b46a6..8b0ba6b5a7 100644
--- a/spec/ruby/core/string/start_with_spec.rb
+++ b/spec/ruby/core/string/start_with_spec.rb
@@ -11,17 +11,8 @@ describe "String#start_with?" do
"\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8
end
- ruby_version_is ""..."3.3" do
- it "does not check we are matching only part of a character" do
- "\xe3\x81\x82".size.should == 1
- "\xe3\x81\x82".should.start_with?("\xe3")
- end
- end
-
- ruby_version_is "3.3" do # #19784
- it "checks we are matching only part of a character" do
- "\xe3\x81\x82".size.should == 1
- "\xe3\x81\x82".should_not.start_with?("\xe3")
- end
+ it "checks we are matching only part of a character" do
+ "\xe3\x81\x82".size.should == 1
+ "\xe3\x81\x82".should_not.start_with?("\xe3")
end
end
diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb
index edb6ea3b44..81994a7f2e 100644
--- a/spec/ruby/core/string/strip_spec.rb
+++ b/spec/ruby/core/string/strip_spec.rb
@@ -20,7 +20,7 @@ end
describe "String#strip!" do
it "modifies self in place and returns self" do
a = " hello "
- a.strip!.should equal(a)
+ a.strip!.should.equal?(a)
a.should == "hello"
a = "\tgoodbye\r\v\n"
@@ -47,12 +47,12 @@ describe "String#strip!" do
end
it "raises a FrozenError on a frozen instance that is modified" do
- -> { " hello ".freeze.strip! }.should raise_error(FrozenError)
+ -> { " hello ".freeze.strip! }.should.raise(FrozenError)
end
# see #1552
it "raises a FrozenError on a frozen instance that would not be modified" do
- -> {"hello".freeze.strip! }.should raise_error(FrozenError)
- -> {"".freeze.strip! }.should raise_error(FrozenError)
+ -> {"hello".freeze.strip! }.should.raise(FrozenError)
+ -> {"".freeze.strip! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb
index 6ff28ec851..f0082fba59 100644
--- a/spec/ruby/core/string/sub_spec.rb
+++ b/spec/ruby/core/string/sub_spec.rb
@@ -7,7 +7,7 @@ describe "String#sub with pattern, replacement" do
a = "hello"
b = a.sub(/w.*$/, "*")
- b.should_not equal(a)
+ b.should_not.equal?(a)
b.should == "hello"
end
@@ -147,16 +147,16 @@ describe "String#sub with pattern, replacement" do
not_supported_on :opal do
it "raises a TypeError when pattern is a Symbol" do
- -> { "hello".sub(:woot, "x") }.should raise_error(TypeError)
+ -> { "hello".sub(:woot, "x") }.should.raise(TypeError)
end
end
it "raises a TypeError when pattern is an Array" do
- -> { "hello".sub([], "x") }.should raise_error(TypeError)
+ -> { "hello".sub([], "x") }.should.raise(TypeError)
end
it "raises a TypeError when pattern can't be converted to a string" do
- -> { "hello".sub(Object.new, nil) }.should raise_error(TypeError)
+ -> { "hello".sub(Object.new, nil) }.should.raise(TypeError)
end
it "tries to convert replacement to a string using to_str" do
@@ -167,15 +167,15 @@ describe "String#sub with pattern, replacement" do
end
it "raises a TypeError when replacement can't be converted to a string" do
- -> { "hello".sub(/[aeiou]/, []) }.should raise_error(TypeError)
- -> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError)
+ -> { "hello".sub(/[aeiou]/, []) }.should.raise(TypeError)
+ -> { "hello".sub(/[aeiou]/, 99) }.should.raise(TypeError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").sub(//, "").should.instance_of?(String)
+ StringSpecs::MyString.new("").sub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").sub(/foo/, "").should.instance_of?(String)
+ StringSpecs::MyString.new("foo").sub("foo", "").should.instance_of?(String)
end
it "sets $~ to MatchData of match and nil when there's none" do
@@ -281,7 +281,7 @@ end
describe "String#sub! with pattern, replacement" do
it "modifies self in place and returns self" do
a = "hello"
- a.sub!(/[aeiou]/, '*').should equal(a)
+ a.sub!(/[aeiou]/, '*').should.equal?(a)
a.should == "h*llo"
end
@@ -296,9 +296,9 @@ describe "String#sub! with pattern, replacement" do
s = "hello"
s.freeze
- -> { s.sub!(/ROAR/, "x") }.should raise_error(FrozenError)
- -> { s.sub!(/e/, "e") }.should raise_error(FrozenError)
- -> { s.sub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
+ -> { s.sub!(/ROAR/, "x") }.should.raise(FrozenError)
+ -> { s.sub!(/e/, "e") }.should.raise(FrozenError)
+ -> { s.sub!(/[aeiou]/, '*') }.should.raise(FrozenError)
end
it "handles a pattern in a superset encoding" do
@@ -326,7 +326,7 @@ end
describe "String#sub! with pattern and block" do
it "modifies self in place and returns self" do
a = "hello"
- a.sub!(/[aeiou]/) { '*' }.should equal(a)
+ a.sub!(/[aeiou]/) { '*' }.should.equal?(a)
a.should == "h*llo"
end
@@ -357,16 +357,16 @@ describe "String#sub! with pattern and block" do
it "raises a RuntimeError if the string is modified while substituting" do
str = "hello"
- -> { str.sub!(//) { str << 'x' } }.should raise_error(RuntimeError)
+ -> { str.sub!(//) { str << 'x' } }.should.raise(RuntimeError)
end
it "raises a FrozenError when self is frozen" do
s = "hello"
s.freeze
- -> { s.sub!(/ROAR/) { "x" } }.should raise_error(FrozenError)
- -> { s.sub!(/e/) { "e" } }.should raise_error(FrozenError)
- -> { s.sub!(/[aeiou]/) { '*' } }.should raise_error(FrozenError)
+ -> { s.sub!(/ROAR/) { "x" } }.should.raise(FrozenError)
+ -> { s.sub!(/e/) { "e" } }.should.raise(FrozenError)
+ -> { s.sub!(/[aeiou]/) { '*' } }.should.raise(FrozenError)
end
end
@@ -501,12 +501,12 @@ end
describe "String#sub with pattern and without replacement and block" do
it "raises a ArgumentError" do
- -> { "abca".sub(/a/) }.should raise_error(ArgumentError)
+ -> { "abca".sub(/a/) }.should.raise(ArgumentError)
end
end
describe "String#sub! with pattern and without replacement and block" do
it "raises a ArgumentError" do
- -> { "abca".sub!(/a/) }.should raise_error(ArgumentError)
+ -> { "abca".sub!(/a/) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index 011a213501..f0e6e0182c 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -25,7 +25,7 @@ describe "String#swapcase" do
swapcased.should == "aSSET"
swapcased.size.should == 5
swapcased.bytesize.should == 5
- swapcased.ascii_only?.should be_true
+ swapcased.ascii_only?.should == true
end
end
@@ -49,7 +49,7 @@ describe "String#swapcase" do
end
it "does not allow any other additional option" do
- -> { "aiS".swapcase(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "aiS".swapcase(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -63,28 +63,28 @@ describe "String#swapcase" do
end
it "does not allow any other additional option" do
- -> { "aiS".swapcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "aiS".swapcase(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { "abc".swapcase(:fold) }.should raise_error(ArgumentError)
+ -> { "abc".swapcase(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "abc".swapcase(:invalid_option) }.should.raise(ArgumentError)
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String)
- StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("").swapcase.should.instance_of?(String)
+ StringSpecs::MyString.new("hello").swapcase.should.instance_of?(String)
end
end
describe "String#swapcase!" do
it "modifies self in place" do
a = "cYbEr_PuNk11"
- a.swapcase!.should equal(a)
+ a.swapcase!.should.equal?(a)
a.should == "CyBeR_pUnK11"
end
@@ -114,7 +114,7 @@ describe "String#swapcase!" do
swapcased.should == "aSSET"
swapcased.size.should == 5
swapcased.bytesize.should == 5
- swapcased.ascii_only?.should be_true
+ swapcased.ascii_only?.should == true
end
end
@@ -146,7 +146,7 @@ describe "String#swapcase!" do
end
it "does not allow any other additional option" do
- -> { a = "aiS"; a.swapcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "aiS"; a.swapcase!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -164,16 +164,16 @@ describe "String#swapcase!" do
end
it "does not allow any other additional option" do
- -> { a = "aiS"; a.swapcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "aiS"; a.swapcase!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { a = "abc"; a.swapcase!(:fold) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.swapcase!(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { a = "abc"; a.swapcase!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.swapcase!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -187,7 +187,7 @@ describe "String#swapcase!" do
it "raises a FrozenError when self is frozen" do
["", "hello"].each do |a|
a.freeze
- -> { a.swapcase! }.should raise_error(FrozenError)
+ -> { a.swapcase! }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index 4864a98e39..9cd0ed4401 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -13,9 +13,7 @@ describe "String#to_c" do
it "ignores trailing garbage" do
'79+4iruby'.to_c.should == Complex(79, 4)
- ruby_bug "[Bug #19087]", ""..."3.2" do
- '7__9+4__0i'.to_c.should == Complex(7, 0)
- end
+ '7__9+4__0i'.to_c.should == Complex(7, 0)
end
context "it treats special float value strings as characters" do
@@ -40,18 +38,16 @@ describe "String#to_c" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
-> {
'79+4i'.encode("UTF-16").to_c
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
- ruby_version_is "3.2" do
- it "treats a sequence of underscores as an end of Complex string" do
- "5+3_1i".to_c.should == Complex(5, 31)
- "5+3__1i".to_c.should == Complex(5)
- "5+3___1i".to_c.should == Complex(5)
+ it "treats a sequence of underscores as an end of Complex string" do
+ "5+3_1i".to_c.should == Complex(5, 31)
+ "5+3__1i".to_c.should == Complex(5)
+ "5+3___1i".to_c.should == Complex(5)
- "12_3".to_c.should == Complex(123)
- "12__3".to_c.should == Complex(12)
- "12___3".to_c.should == Complex(12)
- end
+ "12_3".to_c.should == Complex(123)
+ "12__3".to_c.should == Complex(12)
+ "12___3".to_c.should == Complex(12)
end
end
diff --git a/spec/ruby/core/string/to_f_spec.rb b/spec/ruby/core/string/to_f_spec.rb
index 72e2a90b13..bb09e4f2f3 100644
--- a/spec/ruby/core/string/to_f_spec.rb
+++ b/spec/ruby/core/string/to_f_spec.rb
@@ -120,11 +120,21 @@ describe "String#to_f" do
"\3771.2".b.to_f.should == 0
end
- ruby_version_is "3.2" do
- it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
- -> {
- '1.2'.encode("UTF-16").to_f
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '1.2'.encode("UTF-16").to_f
+ }.should.raise(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "allows String representation without a fractional part" do
+ "1.".to_f.should == 1.0
+ "+1.".to_f.should == 1.0
+ "-1.".to_f.should == -1.0
+ "1.e+0".to_f.should == 1.0
+ "1.e+0".to_f.should == 1.0
+
+ ruby_bug "#20705", ""..."3.4" do
+ "1.e-2".to_f.should be_close(0.01, TOLERANCE)
end
end
end
diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb
index 39f69acda3..629750bd73 100644
--- a/spec/ruby/core/string/to_i_spec.rb
+++ b/spec/ruby/core/string/to_i_spec.rb
@@ -138,31 +138,31 @@ describe "String#to_i" do
end
it "raises an ArgumentError for illegal bases (1, < 0 or > 36)" do
- -> { "".to_i(1) }.should raise_error(ArgumentError)
- -> { "".to_i(-1) }.should raise_error(ArgumentError)
- -> { "".to_i(37) }.should raise_error(ArgumentError)
+ -> { "".to_i(1) }.should.raise(ArgumentError)
+ -> { "".to_i(-1) }.should.raise(ArgumentError)
+ -> { "".to_i(37) }.should.raise(ArgumentError)
end
it "returns an Integer for long strings with trailing spaces" do
"0 ".to_i.should == 0
- "0 ".to_i.should be_an_instance_of(Integer)
+ "0 ".to_i.should.instance_of?(Integer)
"10 ".to_i.should == 10
- "10 ".to_i.should be_an_instance_of(Integer)
+ "10 ".to_i.should.instance_of?(Integer)
"-10 ".to_i.should == -10
- "-10 ".to_i.should be_an_instance_of(Integer)
+ "-10 ".to_i.should.instance_of?(Integer)
end
it "returns an Integer for long strings with leading spaces" do
" 0".to_i.should == 0
- " 0".to_i.should be_an_instance_of(Integer)
+ " 0".to_i.should.instance_of?(Integer)
" 10".to_i.should == 10
- " 10".to_i.should be_an_instance_of(Integer)
+ " 10".to_i.should.instance_of?(Integer)
" -10".to_i.should == -10
- " -10".to_i.should be_an_instance_of(Integer)
+ " -10".to_i.should.instance_of?(Integer)
end
it "returns the correct Integer for long strings" do
diff --git a/spec/ruby/core/string/to_r_spec.rb b/spec/ruby/core/string/to_r_spec.rb
index 4ffbb10d98..fb7c9d108e 100644
--- a/spec/ruby/core/string/to_r_spec.rb
+++ b/spec/ruby/core/string/to_r_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "String#to_r" do
it "returns a Rational object" do
- String.new.to_r.should be_an_instance_of(Rational)
+ String.new.to_r.should.instance_of?(Rational)
end
it "returns (0/1) for the empty String" do
diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb
index dd72da440c..22a193ec4b 100644
--- a/spec/ruby/core/string/tr_s_spec.rb
+++ b/spec/ruby/core/string/tr_s_spec.rb
@@ -18,13 +18,11 @@ describe "String#tr_s" do
"hello ^--^".tr_s("---", "_").should == "hello ^_^"
end
- ruby_bug "#19769", ""..."3.3" do
- it "accepts c1-c1 notation to denote range of one character" do
- "hello".tr_s('e-e', 'x').should == "hxllo"
- "123456789".tr_s("2-23","xy").should == "1xy456789"
- "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^"
- "hello ^-^".tr_s("---o", "_a").should == "hella ^_^"
- end
+ it "accepts c1-c1 notation to denote range of one character" do
+ "hello".tr_s('e-e', 'x').should == "hxllo"
+ "123456789".tr_s("2-23","xy").should == "1xy456789"
+ "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^"
+ "hello ^-^".tr_s("---o", "_a").should == "hella ^_^"
end
it "pads to_str with its last char if it is shorter than from_string" do
@@ -56,7 +54,7 @@ describe "String#tr_s" do
end
it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").tr_s("e", "a").should.instance_of?(String)
end
# http://redmine.ruby-lang.org/issues/show/1839
@@ -126,8 +124,8 @@ describe "String#tr_s!" do
it "raises a FrozenError if self is frozen" do
s = "hello".freeze
- -> { s.tr_s!("el", "ar") }.should raise_error(FrozenError)
- -> { s.tr_s!("l", "r") }.should raise_error(FrozenError)
- -> { s.tr_s!("", "") }.should raise_error(FrozenError)
+ -> { s.tr_s!("el", "ar") }.should.raise(FrozenError)
+ -> { s.tr_s!("l", "r") }.should.raise(FrozenError)
+ -> { s.tr_s!("", "") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb
index 75841a974f..cb57c3851e 100644
--- a/spec/ruby/core/string/tr_spec.rb
+++ b/spec/ruby/core/string/tr_spec.rb
@@ -17,13 +17,11 @@ describe "String#tr" do
"hello ^-^".tr("---", "_").should == "hello ^_^"
end
- ruby_bug "#19769", ""..."3.3" do
- it "accepts c1-c1 notation to denote range of one character" do
- "hello".tr('e-e', 'x').should == "hxllo"
- "123456789".tr("2-23","xy").should == "1xy456789"
- "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^"
- "hello ^-^".tr("---o", "_a").should == "hella ^_^"
- end
+ it "accepts c1-c1 notation to denote range of one character" do
+ "hello".tr('e-e', 'x').should == "hxllo"
+ "123456789".tr("2-23","xy").should == "1xy456789"
+ "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^"
+ "hello ^-^".tr("---o", "_a").should == "hella ^_^"
end
it "pads to_str with its last char if it is shorter than from_string" do
@@ -32,11 +30,11 @@ describe "String#tr" do
end
it "raises an ArgumentError a descending range in the replacement as containing just the start character" do
- -> { "hello".tr("a-y", "z-b") }.should raise_error(ArgumentError)
+ -> { "hello".tr("a-y", "z-b") }.should.raise(ArgumentError)
end
it "raises an ArgumentError a descending range in the source as empty" do
- -> { "hello".tr("l-a", "z") }.should raise_error(ArgumentError)
+ -> { "hello".tr("l-a", "z") }.should.raise(ArgumentError)
end
it "translates chars not in from_string when it starts with a ^" do
@@ -68,7 +66,7 @@ describe "String#tr" do
end
it "returns Stringinstances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").tr("e", "a").should.instance_of?(String)
end
# http://redmine.ruby-lang.org/issues/show/1839
@@ -121,8 +119,8 @@ describe "String#tr!" do
it "raises a FrozenError if self is frozen" do
s = "abcdefghijklmnopqR".freeze
- -> { s.tr!("cdefg", "12") }.should raise_error(FrozenError)
- -> { s.tr!("R", "S") }.should raise_error(FrozenError)
- -> { s.tr!("", "") }.should raise_error(FrozenError)
+ -> { s.tr!("cdefg", "12") }.should.raise(FrozenError)
+ -> { s.tr!("R", "S") }.should.raise(FrozenError)
+ -> { s.tr!("", "") }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index 72ce5dd8b2..0c0219cd2e 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -4,47 +4,47 @@ require_relative 'fixtures/classes'
describe "String.try_convert" do
it "returns the argument if it's a String" do
x = String.new
- String.try_convert(x).should equal(x)
+ String.try_convert(x).should.equal?(x)
end
it "returns the argument if it's a kind of String" do
x = StringSpecs::MyString.new
- String.try_convert(x).should equal(x)
+ String.try_convert(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_str" do
- String.try_convert(Object.new).should be_nil
+ String.try_convert(Object.new).should == nil
end
it "sends #to_str to the argument and returns the result if it's nil" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(nil)
- String.try_convert(obj).should be_nil
+ String.try_convert(obj).should == nil
end
it "sends #to_str to the argument and returns the result if it's a String" do
x = String.new
obj = mock("to_str")
obj.should_receive(:to_str).and_return(x)
- String.try_convert(obj).should equal(x)
+ String.try_convert(obj).should.equal?(x)
end
it "sends #to_str to the argument and returns the result if it's a kind of String" do
x = StringSpecs::MyString.new
obj = mock("to_str")
obj.should_receive(:to_str).and_return(x)
- String.try_convert(obj).should equal(x)
+ String.try_convert(obj).should.equal?(x)
end
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)")
+ -> { String.try_convert obj }.should raise_consistent_error(TypeError, "can't convert MockObject into String (MockObject#to_str gives Object)")
end
it "does not rescue exceptions raised by #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_raise(RuntimeError)
- -> { String.try_convert obj }.should raise_error(RuntimeError)
+ -> { String.try_convert obj }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb
index 6ff220161c..8516e24b3b 100644
--- a/spec/ruby/core/string/undump_spec.rb
+++ b/spec/ruby/core/string/undump_spec.rb
@@ -8,7 +8,7 @@ describe "String#undump" do
end
it "always returns String instance" do
- StringSpecs::MyString.new('"foo"').undump.should be_an_instance_of(String)
+ StringSpecs::MyString.new('"foo"').undump.should.instance_of?(String)
end
it "strips outer \"" do
@@ -396,46 +396,46 @@ describe "String#undump" do
describe "Limitations" do
it "cannot undump non ASCII-compatible string" do
- -> { '"foo"'.encode('utf-16le').undump }.should raise_error(Encoding::CompatibilityError)
+ -> { '"foo"'.encode('utf-16le').undump }.should.raise(Encoding::CompatibilityError)
end
end
describe "invalid dump" do
it "raises RuntimeError exception if wrapping \" are missing" do
- -> { 'foo'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
- -> { '"foo'.undump }.should raise_error(RuntimeError, /unterminated dumped string/)
- -> { 'foo"'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
- -> { "'foo'".undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { 'foo'.undump }.should.raise(RuntimeError, /invalid dumped string/)
+ -> { '"foo'.undump }.should.raise(RuntimeError, /unterminated dumped string/)
+ -> { 'foo"'.undump }.should.raise(RuntimeError, /invalid dumped string/)
+ -> { "'foo'".undump }.should.raise(RuntimeError, /invalid dumped string/)
end
it "raises RuntimeError if there is incorrect \\x sequence" do
- -> { '"\x"'.undump }.should raise_error(RuntimeError, /invalid hex escape/)
- -> { '"\\x3y"'.undump }.should raise_error(RuntimeError, /invalid hex escape/)
+ -> { '"\x"'.undump }.should.raise(RuntimeError, /invalid hex escape/)
+ -> { '"\\x3y"'.undump }.should.raise(RuntimeError, /invalid hex escape/)
end
it "raises RuntimeError in there is incorrect \\u sequence" do
- -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
- -> { '"\\u{"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
- -> { '"\\u{3042"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
- -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u{"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u{3042"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u"'.undump }.should.raise(RuntimeError, /invalid Unicode escape/)
end
it "raises RuntimeError if there is malformed dump of non ASCII-compatible string" do
- -> { '"".force_encoding("BINARY"'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
- -> { '"".force_encoding("Unknown")'.undump }.should raise_error(RuntimeError, /dumped string has unknown encoding name/)
- -> { '"".force_encoding()'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { '"".force_encoding("BINARY"'.undump }.should.raise(RuntimeError, /invalid dumped string/)
+ -> { '"".force_encoding("Unknown")'.undump }.should.raise(RuntimeError, /dumped string has unknown encoding name/)
+ -> { '"".force_encoding()'.undump }.should.raise(RuntimeError, /invalid dumped string/)
end
it "raises RuntimeError if string contains \0 character" do
- -> { "\"foo\0\"".undump }.should raise_error(RuntimeError, /string contains null byte/)
+ -> { "\"foo\0\"".undump }.should.raise(RuntimeError, /string contains null byte/)
end
it "raises RuntimeError if string contains non ASCII character" do
- -> { "\"\u3042\"".undump }.should raise_error(RuntimeError, /non-ASCII character detected/)
+ -> { "\"\u3042\"".undump }.should.raise(RuntimeError, /non-ASCII character detected/)
end
it "raises RuntimeError if there are some excessive \"" do
- -> { '" "" "'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { '" "" "'.undump }.should.raise(RuntimeError, /invalid dumped string/)
end
end
end
diff --git a/spec/ruby/core/string/unicode_normalize_spec.rb b/spec/ruby/core/string/unicode_normalize_spec.rb
index 2e7d22394a..92b3a46b43 100644
--- a/spec/ruby/core/string/unicode_normalize_spec.rb
+++ b/spec/ruby/core/string/unicode_normalize_spec.rb
@@ -51,13 +51,13 @@ describe "String#unicode_normalize" do
it "raises an Encoding::CompatibilityError if string is not in an unicode encoding" do
-> do
[0xE0].pack('C').force_encoding("ISO-8859-1").unicode_normalize(:nfd)
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
-> {
@angstrom.unicode_normalize(:invalid_form)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -104,13 +104,13 @@ describe "String#unicode_normalize!" do
it "raises an Encoding::CompatibilityError if the string is not in an unicode encoding" do
-> {
[0xE0].pack('C').force_encoding("ISO-8859-1").unicode_normalize!
- }.should raise_error(Encoding::CompatibilityError)
+ }.should.raise(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
ohm = "\u2126"
-> {
ohm.unicode_normalize!(:invalid_form)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unicode_normalized_spec.rb b/spec/ruby/core/string/unicode_normalized_spec.rb
index 91cf2086b2..3ca27d35dd 100644
--- a/spec/ruby/core/string/unicode_normalized_spec.rb
+++ b/spec/ruby/core/string/unicode_normalized_spec.rb
@@ -38,38 +38,38 @@ describe "String#unicode_normalized?" do
end
it "raises an Encoding::CompatibilityError if the string is not in an unicode encoding" do
- -> { @nfc_normalized_str.force_encoding("ISO-8859-1").unicode_normalized? }.should raise_error(Encoding::CompatibilityError)
+ -> { @nfc_normalized_str.force_encoding("ISO-8859-1").unicode_normalized? }.should.raise(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
- -> { @nfc_normalized_str.unicode_normalized?(:invalid_form) }.should raise_error(ArgumentError)
+ -> { @nfc_normalized_str.unicode_normalized?(:invalid_form) }.should.raise(ArgumentError)
end
it "returns true if str is in Unicode normalization form (nfc)" do
str = "a\u0300"
- str.unicode_normalized?(:nfc).should be_false
+ str.unicode_normalized?(:nfc).should == false
str.unicode_normalize!(:nfc)
- str.unicode_normalized?(:nfc).should be_true
+ str.unicode_normalized?(:nfc).should == true
end
it "returns true if str is in Unicode normalization form (nfd)" do
str = "a\u00E0"
- str.unicode_normalized?(:nfd).should be_false
+ str.unicode_normalized?(:nfd).should == false
str.unicode_normalize!(:nfd)
- str.unicode_normalized?(:nfd).should be_true
+ str.unicode_normalized?(:nfd).should == true
end
it "returns true if str is in Unicode normalization form (nfkc)" do
str = "a\u0300"
- str.unicode_normalized?(:nfkc).should be_false
+ str.unicode_normalized?(:nfkc).should == false
str.unicode_normalize!(:nfkc)
- str.unicode_normalized?(:nfkc).should be_true
+ str.unicode_normalized?(:nfkc).should == true
end
it "returns true if str is in Unicode normalization form (nfkd)" do
str = "a\u00E0"
- str.unicode_normalized?(:nfkd).should be_false
+ str.unicode_normalized?(:nfkd).should == false
str.unicode_normalize!(:nfkd)
- str.unicode_normalized?(:nfkd).should be_true
+ str.unicode_normalized?(:nfkd).should == true
end
end
diff --git a/spec/ruby/core/string/unpack/a_spec.rb b/spec/ruby/core/string/unpack/a_spec.rb
index 4002ece697..a68e842e15 100644
--- a/spec/ruby/core/string/unpack/a_spec.rb
+++ b/spec/ruby/core/string/unpack/a_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/at_spec.rb b/spec/ruby/core/string/unpack/at_spec.rb
index 70b2389d69..f4999f5922 100644
--- a/spec/ruby/core/string/unpack/at_spec.rb
+++ b/spec/ruby/core/string/unpack/at_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -24,6 +24,6 @@ describe "String#unpack with format '@'" do
end
it "raises an ArgumentError if the count exceeds the size of the String" do
- -> { "\x01\x02\x03\x04".unpack("C2@5C") }.should raise_error(ArgumentError)
+ -> { "\x01\x02\x03\x04".unpack("C2@5C") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index 23d93a8aea..fac6ef5151 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -86,20 +86,10 @@ describe "String#unpack with format 'B'" do
].should be_computed_by(:unpack, "BBB")
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x80\x00".unpack("B\x00B").should == ["1", "0"]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x80\x00".unpack("B\x00B")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x80\x00".unpack("B\x00B")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -194,20 +184,10 @@ describe "String#unpack with format 'b'" do
].should be_computed_by(:unpack, "bbb")
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x00".unpack("b\x00b").should == ["1", "0"]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x00".unpack("b\x00b")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x00".unpack("b\x00b")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index c2bf813954..d881015b5e 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -35,20 +35,10 @@ describe :string_unpack_8bit, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "abc".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abc".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/carret_spec.rb b/spec/ruby/core/string/unpack/carret_spec.rb
new file mode 100644
index 0000000000..815df0c718
--- /dev/null
+++ b/spec/ruby/core/string/unpack/carret_spec.rb
@@ -0,0 +1,43 @@
+# encoding: binary
+ruby_version_is "4.1" do
+ require_relative '../../../spec_helper'
+ require_relative '../fixtures/classes'
+ require_relative 'shared/basic'
+
+ describe "String#unpack with format '^'" do
+ it_behaves_like :string_unpack_basic, '^'
+ it_behaves_like :string_unpack_no_platform, '^'
+
+ it "returns the current offset that start from 0" do
+ "".unpack("^").should == [0]
+ end
+
+ it "returns the current offset after the last decode ended" do
+ "a".unpack("CC^").should == [97, nil, 1]
+ end
+
+ it "returns the current offset that start from the given offset" do
+ "abc".unpack("^", offset: 1).should == [1]
+ end
+
+ it "returns the offset moved by 'X'" do
+ "\x01\x02\x03\x04".unpack("C3X2^").should == [1, 2, 3, 1]
+ end
+
+ it "returns the offset moved by 'x'" do
+ "\x01\x02\x03\x04".unpack("Cx2^").should == [1, 3]
+ end
+
+ it "returns the offset to the position the previous decode ended" do
+ "foo".unpack("A4^").should == ["foo", 3]
+ "foo".unpack("a4^").should == ["foo", 3]
+ "foo".unpack("Z5^").should == ["foo", 3]
+ end
+
+ it "returns the offset including truncated part" do
+ "foo ".unpack("A*^").should == ["foo", 6]
+ "foo\0".unpack("Z*^").should == ["foo", 4]
+ "foo\0\0\0".unpack("Z5^").should == ["foo", 5]
+ end
+ end
+end
diff --git a/spec/ruby/core/string/unpack/comment_spec.rb b/spec/ruby/core/string/unpack/comment_spec.rb
index e18a53df3c..050d2b7fc0 100644
--- a/spec/ruby/core/string/unpack/comment_spec.rb
+++ b/spec/ruby/core/string/unpack/comment_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index 19c4d63664..0cf8d943a7 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -56,20 +56,10 @@ describe "String#unpack with format 'H'" do
].should be_computed_by(:unpack, "HHH")
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x10".unpack("H\x00H").should == ["0", "1"]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x10".unpack("H\x00H")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("H\x00H")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -133,20 +123,10 @@ describe "String#unpack with format 'h'" do
].should be_computed_by(:unpack, "hhh")
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x10".unpack("h\x00h").should == ["1", "0"]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x10".unpack("h\x00h")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("h\x00h")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb
index c551c755d1..c1c1eea629 100644
--- a/spec/ruby/core/string/unpack/m_spec.rb
+++ b/spec/ruby/core/string/unpack/m_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -186,7 +186,7 @@ describe "String#unpack with format 'm'" do
end
it "raises an ArgumentError for an invalid base64 character" do
- -> { "dGV%zdA==".unpack("m0") }.should raise_error(ArgumentError)
+ -> { "dGV%zdA==".unpack("m0") }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/unpack/p_spec.rb b/spec/ruby/core/string/unpack/p_spec.rb
index cd48c0523d..4103730269 100644
--- a/spec/ruby/core/string/unpack/p_spec.rb
+++ b/spec/ruby/core/string/unpack/p_spec.rb
@@ -15,7 +15,7 @@ describe "String#unpack with format 'P'" do
packed = ["hello"].pack("P")
packed.unpack("P5").should == ["hello"]
packed.dup.unpack("P5").should == ["hello"]
- -> { packed.to_sym.to_s.unpack("P5") }.should raise_error(ArgumentError, /no associated pointer/)
+ -> { packed.to_sym.to_s.unpack("P5") }.should.raise(ArgumentError, /no associated pointer/)
end
it "reads as many characters as specified" do
@@ -39,6 +39,6 @@ describe "String#unpack with format 'p'" do
packed = ["hello"].pack("p")
packed.unpack("p").should == ["hello"]
packed.dup.unpack("p").should == ["hello"]
- -> { packed.to_sym.to_s.unpack("p") }.should raise_error(ArgumentError, /no associated pointer/)
+ -> { packed.to_sym.to_s.unpack("p") }.should.raise(ArgumentError, /no associated pointer/)
end
end
diff --git a/spec/ruby/core/string/unpack/percent_spec.rb b/spec/ruby/core/string/unpack/percent_spec.rb
index 0e27663195..7142bbf241 100644
--- a/spec/ruby/core/string/unpack/percent_spec.rb
+++ b/spec/ruby/core/string/unpack/percent_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../../spec_helper'
describe "String#unpack with format '%'" do
it "raises an Argument Error" do
- -> { "abc".unpack("%") }.should raise_error(ArgumentError)
+ -> { "abc".unpack("%") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/r_spec.rb b/spec/ruby/core/string/unpack/r_spec.rb
new file mode 100644
index 0000000000..a385951aa8
--- /dev/null
+++ b/spec/ruby/core/string/unpack/r_spec.rb
@@ -0,0 +1,85 @@
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+
+ruby_version_is "4.1" do
+ describe "String#unpack with format 'R'" do
+ it_behaves_like :string_unpack_basic, 'R'
+ it_behaves_like :string_unpack_no_platform, 'R'
+
+ it "decodes a ULEB128 integer" do
+ [ ["\x00", [0]],
+ ["\x01", [1]],
+ ["\x7f", [127]],
+ ["\x80\x01", [128]],
+ ["\xff\x7f", [0x3fff]],
+ ["\x80\x80\x01", [0x4000]],
+ ["\xff\xff\xff\xff\x0f", [0xffffffff]],
+ ["\x80\x80\x80\x80\x10", [0x100000000]],
+ ["\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", [0xffff_ffff_ffff_ffff]],
+ ].should be_computed_by(:unpack, "R")
+ end
+
+ it "decodes multiple values with '*' modifier" do
+ "\x01\x02".unpack("R*").should == [1, 2]
+ "\x7f\x80\x01".unpack("R*").should == [127, 128]
+ end
+
+ it "returns nil for incomplete data" do
+ "\xFF".unpack("R").should == [nil]
+ "\xFF".unpack1("R").should == nil
+ end
+
+ it "returns nil for remaining incomplete values after a valid one" do
+ bytes = [256].pack("R")
+ (bytes + "\xFF").unpack("RRRR").should == [256, nil, nil, nil]
+ end
+
+ it "skips incomplete values with '*' modifier" do
+ "\xFF".unpack("R*").should == []
+ end
+ end
+
+ describe "String#unpack with format 'r'" do
+ it_behaves_like :string_unpack_basic, 'r'
+ it_behaves_like :string_unpack_no_platform, 'r'
+
+ it "decodes a SLEB128 integer" do
+ [ ["\x00", [0]],
+ ["\x01", [1]],
+ ["\x7f", [-1]],
+ ["\x7e", [-2]],
+ ["\xff\x00", [127]],
+ ["\x80\x01", [128]],
+ ["\x81\x7f", [-127]],
+ ["\x80\x7f", [-128]],
+ ].should be_computed_by(:unpack, "r")
+ end
+
+ it "decodes larger numbers" do
+ "\xff\xff\x00".unpack("r").should == [0x3fff]
+ "\x80\x80\x01".unpack("r").should == [0x4000]
+ "\x81\x80\x7f".unpack("r").should == [-0x3fff]
+ "\x80\x80\x7f".unpack("r").should == [-0x4000]
+ end
+
+ it "decodes multiple values with '*' modifier" do
+ "\x00\x01\x7f".unpack("r*").should == [0, 1, -1]
+ end
+
+ it "returns nil for incomplete data" do
+ "\xFF".unpack("r").should == [nil]
+ "\xFF".unpack1("r").should == nil
+ end
+
+ it "returns nil for remaining incomplete values after a valid one" do
+ bytes = [256].pack("r")
+ (bytes + "\xFF").unpack("rrrr").should == [256, nil, nil, nil]
+ end
+
+ it "skips incomplete values with '*' modifier" do
+ "\xFF".unpack("r*").should == []
+ end
+ end
+end
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb
index b37a447683..2ee2d6899a 100644
--- a/spec/ruby/core/string/unpack/shared/basic.rb
+++ b/spec/ruby/core/string/unpack/shared/basic.rb
@@ -1,30 +1,27 @@
describe :string_unpack_basic, shared: true do
it "ignores whitespace in the format string" do
- "abc".unpack("a \t\n\v\f\r"+unpack_format).should be_an_instance_of(Array)
+ "abc".unpack("a \t\n\v\f\r"+unpack_format).should.instance_of?(Array)
end
it "calls #to_str to coerce the directives string" do
d = mock("unpack directive")
d.should_receive(:to_str).and_return("a"+unpack_format)
- "abc".unpack(d).should be_an_instance_of(Array)
+ "abc".unpack(d).should.instance_of?(Array)
end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- it 'raise ArgumentError when a directive is unknown' do
- -> { "abcdefgh".unpack("a R" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive 'R'/)
- -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive '0'/)
- -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive ':'/)
- end
+ it "raises ArgumentError when a directive is unknown" do
+ -> { "abcdefgh".unpack("a K" + unpack_format) }.should.raise(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'")
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should.raise(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'")
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should.raise(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'")
end
end
describe :string_unpack_no_platform, shared: true do
it "raises an ArgumentError when the format modifier is '_'" do
- -> { "abcdefgh".unpack(unpack_format("_")) }.should raise_error(ArgumentError)
+ -> { "abcdefgh".unpack(unpack_format("_")) }.should.raise(ArgumentError)
end
it "raises an ArgumentError when the format modifier is '!'" do
- -> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError)
+ -> { "abcdefgh".unpack(unpack_format("!")) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index 93282bf4c9..5525c3fe73 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_unpack_float_le, shared: true do
it "decodes one float for a single format character" do
@@ -53,24 +53,13 @@ describe :string_unpack_float_le, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -132,24 +121,13 @@ describe :string_unpack_float_be, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
- end
-
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
- end
- end
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -214,23 +192,13 @@ describe :string_unpack_double_le, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -294,23 +262,13 @@ describe :string_unpack_double_be, shared: true do
it "decodes NaN" do
# mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884
- [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
- end
-
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
- end
- end
+ [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should == true
end
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index d71a2cf00d..c66156536b 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_unpack_16bit_le, shared: true do
it "decodes one short for a single format character" do
@@ -32,20 +32,10 @@ describe :string_unpack_16bit_le, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "abcd".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcd".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -97,20 +87,10 @@ describe :string_unpack_16bit_be, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "badc".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -163,20 +143,10 @@ describe :string_unpack_32bit_le, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "abcdefgh".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcdefgh".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -229,20 +199,10 @@ describe :string_unpack_32bit_be, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "dcbahgfe".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "dcbahgfe".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -291,21 +251,10 @@ describe :string_unpack_64bit_le, shared: true do
"abc".unpack(unpack_format('*')).should == []
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "badc".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -365,21 +314,10 @@ describe :string_unpack_64bit_be, shared: true do
"abc".unpack(unpack_format('*')).should == []
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index 9fe07f53ae..9b4e0c09de 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -50,20 +50,10 @@ describe :string_unpack_unicode, shared: true do
"\xc2\x80".unpack("UUUU").should == [0x80]
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x02".unpack("U\x00U").should == [1, 2]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x02".unpack("U\x00U")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02".unpack("U\x00U")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/u_spec.rb b/spec/ruby/core/string/unpack/u_spec.rb
index 456abee784..720c1b8583 100644
--- a/spec/ruby/core/string/unpack/u_spec.rb
+++ b/spec/ruby/core/string/unpack/u_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -12,11 +12,11 @@ describe "String#unpack with format 'U'" do
it_behaves_like :string_unpack_taint, 'U'
it "raises ArgumentError on a malformed byte sequence" do
- -> { "\xE3".unpack('U') }.should raise_error(ArgumentError)
+ -> { "\xE3".unpack('U') }.should.raise(ArgumentError)
end
it "raises ArgumentError on a malformed byte sequence and doesn't continue when used with the * modifier" do
- -> { "\xE3".unpack('U*') }.should raise_error(ArgumentError)
+ -> { "\xE3".unpack('U*') }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index 6a1cff1965..cc9aecac9c 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -15,20 +15,10 @@ describe "String#unpack with directive 'w'" do
].should be_computed_by(:unpack, "w")
end
- ruby_version_is ""..."3.3" do
- it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
- end
- end
- end
-
- ruby_version_is "3.3" do
- it "raise ArgumentError for NULL bytes between directives" do
- -> {
- "\x01\x02\x03".unpack("w\x00w")
- }.should raise_error(ArgumentError, /unknown unpack directive/)
- end
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02\x03".unpack("w\x00w")
+ }.should.raise(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/x_spec.rb b/spec/ruby/core/string/unpack/x_spec.rb
index 5e248de77e..fb2e79fc1f 100644
--- a/spec/ruby/core/string/unpack/x_spec.rb
+++ b/spec/ruby/core/string/unpack/x_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -24,11 +24,11 @@ describe "String#unpack with format 'X'" do
end
it "raises an ArgumentError when passed the '*' modifier if the remaining bytes exceed the bytes from the index to the start of the String" do
- -> { "abcd".unpack("CX*C") }.should raise_error(ArgumentError)
+ -> { "abcd".unpack("CX*C") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the count exceeds the bytes from current index to the start of the String" do
- -> { "\x01\x02\x03\x04".unpack("C3X4C") }.should raise_error(ArgumentError)
+ -> { "\x01\x02\x03\x04".unpack("C3X4C") }.should.raise(ArgumentError)
end
end
@@ -57,6 +57,6 @@ describe "String#unpack with format 'x'" do
end
it "raises an ArgumentError if the count exceeds the size of the String" do
- -> { "\x01\x02\x03\x04".unpack("C2x3C") }.should raise_error(ArgumentError)
+ -> { "\x01\x02\x03\x04".unpack("C2x3C") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb
index ce8da4b29e..1030390550 100644
--- a/spec/ruby/core/string/unpack/z_spec.rb
+++ b/spec/ruby/core/string/unpack/z_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb
index 3b3b879f75..ee10042eb8 100644
--- a/spec/ruby/core/string/unpack1_spec.rb
+++ b/spec/ruby/core/string/unpack1_spec.rb
@@ -20,8 +20,22 @@ describe "String#unpack1" do
"؈".unpack1("C", offset: 1).should == 136
end
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ describe "when the offset is negative" do
+ ruby_version_is "4.1" do
+ it "starts unpacking from the end" do
+ "abc".unpack1("C", offset: -2).should == 98
+ end
+
+ it "raises an ArgumentError if it is less than -length" do
+ -> { "a".unpack1("C", offset: -2) }.should.raise(ArgumentError, "offset outside of string")
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "raises an ArgumentError" do
+ -> { "a".unpack1("C", offset: -1) }.should.raise(ArgumentError, "offset can't be negative")
+ end
+ end
end
it "returns nil if the offset is at the end of the string" do
@@ -29,6 +43,19 @@ describe "String#unpack1" do
end
it "raises an ArgumentError when the offset is larger than the string bytesize" do
- -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ -> { "a".unpack1("C", offset: 2) }.should.raise(ArgumentError, "offset outside of string")
+ end
+
+ context "with format 'm0'" do
+ # unpack1("m0") takes a special code path that calls Pack.unpackBase46Strict instead of Pack.unpack_m,
+ # which is why we repeat the tests for unpack("m0") here.
+
+ it "decodes base64" do
+ "dGVzdA==".unpack1("m0").should == "test"
+ end
+
+ it "raises an ArgumentError for an invalid base64 character" do
+ -> { "dGV%zdA==".unpack1("m0") }.should.raise(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb
index 083484ebe9..eb4710ce14 100644
--- a/spec/ruby/core/string/unpack_spec.rb
+++ b/spec/ruby/core/string/unpack_spec.rb
@@ -2,11 +2,11 @@ require_relative '../../spec_helper'
describe "String#unpack" do
it "raises a TypeError when passed nil" do
- -> { "abc".unpack(nil) }.should raise_error(TypeError)
+ -> { "abc".unpack(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { "abc".unpack(1) }.should raise_error(TypeError)
+ -> { "abc".unpack(1) }.should.raise(TypeError)
end
it "starts unpacking from the given offset" do
@@ -18,15 +18,29 @@ describe "String#unpack" do
"؈".unpack("CC", offset: 1).should == [136, nil]
end
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ describe "when the offset is negative" do
+ ruby_version_is "4.1" do
+ it "starts unpacking from the end" do
+ "abc".unpack("CC", offset: -2).should == [98, 99]
+ end
+
+ it "raises an ArgumentError if it is less than -length" do
+ -> { "a".unpack("C", offset: -2) }.should.raise(ArgumentError, "offset outside of string")
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "raises an ArgumentError" do
+ -> { "a".unpack("C", offset: -1) }.should.raise(ArgumentError, "offset can't be negative")
+ end
+ end
end
it "returns nil if the offset is at the end of the string" do
"a".unpack("C", offset: 1).should == [nil]
end
- it "raises an ArgumentError when the offset is larget than the string" do
- -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ it "raises an ArgumentError when the offset is larger than the string" do
+ -> { "a".unpack("C", offset: 2) }.should.raise(ArgumentError, "offset outside of string")
end
end
diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb
index 652de5c2ef..a6e1869267 100644
--- a/spec/ruby/core/string/upcase_spec.rb
+++ b/spec/ruby/core/string/upcase_spec.rb
@@ -24,7 +24,7 @@ describe "String#upcase" do
upcased.should == "ASSET"
upcased.size.should == 5
upcased.bytesize.should == 5
- upcased.ascii_only?.should be_true
+ upcased.ascii_only?.should == true
end
end
@@ -48,7 +48,7 @@ describe "String#upcase" do
end
it "does not allow any other additional option" do
- -> { "i".upcase(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { "i".upcase(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -62,27 +62,27 @@ describe "String#upcase" do
end
it "does not allow any other additional option" do
- -> { "iß".upcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { "iß".upcase(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { "abc".upcase(:fold) }.should raise_error(ArgumentError)
+ -> { "abc".upcase(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError)
+ -> { "abc".upcase(:invalid_option) }.should.raise(ArgumentError)
end
it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("fooBAR").upcase.should.instance_of?(String)
end
end
describe "String#upcase!" do
it "modifies self in place" do
a = "HeLlO"
- a.upcase!.should equal(a)
+ a.upcase!.should.equal?(a)
a.should == "HELLO"
end
@@ -112,7 +112,7 @@ describe "String#upcase!" do
upcased.should == "ASSET"
upcased.size.should == 5
upcased.bytesize.should == 5
- upcased.ascii_only?.should be_true
+ upcased.ascii_only?.should == true
end
end
@@ -144,7 +144,7 @@ describe "String#upcase!" do
end
it "does not allow any other additional option" do
- -> { a = "i"; a.upcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "i"; a.upcase!(:turkic, :ascii) }.should.raise(ArgumentError)
end
end
@@ -162,16 +162,16 @@ describe "String#upcase!" do
end
it "does not allow any other additional option" do
- -> { a = "iß"; a.upcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ -> { a = "iß"; a.upcase!(:lithuanian, :ascii) }.should.raise(ArgumentError)
end
end
it "does not allow the :fold option for upcasing" do
- -> { a = "abc"; a.upcase!(:fold) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.upcase!(:fold) }.should.raise(ArgumentError)
end
it "does not allow invalid options" do
- -> { a = "abc"; a.upcase!(:invalid_option) }.should raise_error(ArgumentError)
+ -> { a = "abc"; a.upcase!(:invalid_option) }.should.raise(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -181,7 +181,7 @@ describe "String#upcase!" do
end
it "raises a FrozenError when self is frozen" do
- -> { "HeLlo".freeze.upcase! }.should raise_error(FrozenError)
- -> { "HELLO".freeze.upcase! }.should raise_error(FrozenError)
+ -> { "HeLlo".freeze.upcase! }.should.raise(FrozenError)
+ -> { "HELLO".freeze.upcase! }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb
index c0b0c49ede..20767bcc01 100644
--- a/spec/ruby/core/string/uplus_spec.rb
+++ b/spec/ruby/core/string/uplus_spec.rb
@@ -13,14 +13,48 @@ describe 'String#+@' do
output.should == 'foobar'
end
- it 'returns self if the String is not frozen' do
- input = 'foo'
+ it 'returns a mutable String itself' do
+ input = String.new("foo")
output = +input
- output.equal?(input).should == true
+ output.should.equal?(input)
+
+ input << "bar"
+ output.should == "foobar"
+ end
+
+ context 'if file has "frozen_string_literal: true" magic comment' do
+ it 'returns mutable copy of a literal' do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ end
end
- it 'returns mutable copy despite freeze-magic-comment in file' do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ context 'if file has "frozen_string_literal: false" magic comment' do
+ it 'returns literal string itself' do
+ input = 'foo'
+ output = +input
+
+ output.equal?(input).should == true
+ end
+ end
+
+ context 'if file has no frozen_string_literal magic comment' do
+ ruby_version_is ''...'3.4' do
+ it 'returns literal string itself' do
+ eval(<<~RUBY).should == true
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
+
+ ruby_version_is '3.4' do
+ it 'returns mutable copy of a literal' do
+ eval(<<~RUBY).should == false
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
end
end
diff --git a/spec/ruby/core/string/upto_spec.rb b/spec/ruby/core/string/upto_spec.rb
index 8bc847d5ac..2eea06fd01 100644
--- a/spec/ruby/core/string/upto_spec.rb
+++ b/spec/ruby/core/string/upto_spec.rb
@@ -53,13 +53,13 @@ describe "String#upto" do
end
it "raises a TypeError if other can't be converted to a string" do
- -> { "abc".upto(123) { } }.should raise_error(TypeError)
- -> { "abc".upto(mock('x')){ } }.should raise_error(TypeError)
+ -> { "abc".upto(123) { } }.should.raise(TypeError)
+ -> { "abc".upto(mock('x')){ } }.should.raise(TypeError)
end
it "does not work with symbols" do
- -> { "a".upto(:c).to_a }.should raise_error(TypeError)
+ -> { "a".upto(:c).to_a }.should.raise(TypeError)
end
it "returns non-alphabetic characters in the ASCII range for single letters" do
@@ -83,7 +83,7 @@ describe "String#upto" do
it "raises Encoding::CompatibilityError when incompatible characters are given" do
char1 = 'a'.dup.force_encoding("EUC-JP")
char2 = 'b'.dup.force_encoding("ISO-2022-JP")
- -> { char1.upto(char2) {} }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP")
+ -> { char1.upto(char2) {} }.should.raise(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP")
end
describe "on sequence of numbers" do
@@ -95,7 +95,7 @@ describe "String#upto" do
describe "when no block is given" do
it "returns an enumerator" do
enum = "aaa".upto("baa", true)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.count.should == 26**2
end
diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb
index 375035cd94..f29220fc99 100644
--- a/spec/ruby/core/string/valid_encoding_spec.rb
+++ b/spec/ruby/core/string/valid_encoding_spec.rb
@@ -2,132 +2,132 @@ require_relative '../../spec_helper'
describe "String#valid_encoding?" do
it "returns true if the String's encoding is valid" do
- "a".valid_encoding?.should be_true
- "\u{8365}\u{221}".valid_encoding?.should be_true
+ "a".valid_encoding?.should == true
+ "\u{8365}\u{221}".valid_encoding?.should == true
end
it "returns true if self is valid in the current encoding and other encodings" do
str = +"\x77"
- str.force_encoding('utf-8').valid_encoding?.should be_true
- str.force_encoding('binary').valid_encoding?.should be_true
+ str.force_encoding('utf-8').valid_encoding?.should == true
+ str.force_encoding('binary').valid_encoding?.should == true
end
it "returns true for all encodings self is valid in" do
str = +"\xE6\x9D\x94"
- str.force_encoding('BINARY').valid_encoding?.should be_true
- str.force_encoding('UTF-8').valid_encoding?.should be_true
- str.force_encoding('US-ASCII').valid_encoding?.should be_false
- str.force_encoding('Big5').valid_encoding?.should be_false
- str.force_encoding('CP949').valid_encoding?.should be_false
- str.force_encoding('Emacs-Mule').valid_encoding?.should be_false
- str.force_encoding('EUC-JP').valid_encoding?.should be_false
- str.force_encoding('EUC-KR').valid_encoding?.should be_false
- str.force_encoding('EUC-TW').valid_encoding?.should be_false
- str.force_encoding('GB18030').valid_encoding?.should be_false
- str.force_encoding('GBK').valid_encoding?.should be_false
- str.force_encoding('ISO-8859-1').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-2').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-3').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-4').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-5').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-6').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-7').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-8').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-9').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-10').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-11').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-13').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-14').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-15').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-16').valid_encoding?.should be_true
- str.force_encoding('KOI8-R').valid_encoding?.should be_true
- str.force_encoding('KOI8-U').valid_encoding?.should be_true
- str.force_encoding('Shift_JIS').valid_encoding?.should be_false
- "\xD8\x00".dup.force_encoding('UTF-16BE').valid_encoding?.should be_false
- "\x00\xD8".dup.force_encoding('UTF-16LE').valid_encoding?.should be_false
- "\x04\x03\x02\x01".dup.force_encoding('UTF-32BE').valid_encoding?.should be_false
- "\x01\x02\x03\x04".dup.force_encoding('UTF-32LE').valid_encoding?.should be_false
- str.force_encoding('Windows-1251').valid_encoding?.should be_true
- str.force_encoding('IBM437').valid_encoding?.should be_true
- str.force_encoding('IBM737').valid_encoding?.should be_true
- str.force_encoding('IBM775').valid_encoding?.should be_true
- str.force_encoding('CP850').valid_encoding?.should be_true
- str.force_encoding('IBM852').valid_encoding?.should be_true
- str.force_encoding('CP852').valid_encoding?.should be_true
- str.force_encoding('IBM855').valid_encoding?.should be_true
- str.force_encoding('CP855').valid_encoding?.should be_true
- str.force_encoding('IBM857').valid_encoding?.should be_true
- str.force_encoding('IBM860').valid_encoding?.should be_true
- str.force_encoding('IBM861').valid_encoding?.should be_true
- str.force_encoding('IBM862').valid_encoding?.should be_true
- str.force_encoding('IBM863').valid_encoding?.should be_true
- str.force_encoding('IBM864').valid_encoding?.should be_true
- str.force_encoding('IBM865').valid_encoding?.should be_true
- str.force_encoding('IBM866').valid_encoding?.should be_true
- str.force_encoding('IBM869').valid_encoding?.should be_true
- str.force_encoding('Windows-1258').valid_encoding?.should be_true
- str.force_encoding('GB1988').valid_encoding?.should be_true
- str.force_encoding('macCentEuro').valid_encoding?.should be_true
- str.force_encoding('macCroatian').valid_encoding?.should be_true
- str.force_encoding('macCyrillic').valid_encoding?.should be_true
- str.force_encoding('macGreek').valid_encoding?.should be_true
- str.force_encoding('macIceland').valid_encoding?.should be_true
- str.force_encoding('macRoman').valid_encoding?.should be_true
- str.force_encoding('macRomania').valid_encoding?.should be_true
- str.force_encoding('macThai').valid_encoding?.should be_true
- str.force_encoding('macTurkish').valid_encoding?.should be_true
- str.force_encoding('macUkraine').valid_encoding?.should be_true
- str.force_encoding('stateless-ISO-2022-JP').valid_encoding?.should be_false
- str.force_encoding('eucJP-ms').valid_encoding?.should be_false
- str.force_encoding('CP51932').valid_encoding?.should be_false
- str.force_encoding('GB2312').valid_encoding?.should be_false
- str.force_encoding('GB12345').valid_encoding?.should be_false
- str.force_encoding('ISO-2022-JP').valid_encoding?.should be_true
- str.force_encoding('ISO-2022-JP-2').valid_encoding?.should be_true
- str.force_encoding('CP50221').valid_encoding?.should be_true
- str.force_encoding('Windows-1252').valid_encoding?.should be_true
- str.force_encoding('Windows-1250').valid_encoding?.should be_true
- str.force_encoding('Windows-1256').valid_encoding?.should be_true
- str.force_encoding('Windows-1253').valid_encoding?.should be_true
- str.force_encoding('Windows-1255').valid_encoding?.should be_true
- str.force_encoding('Windows-1254').valid_encoding?.should be_true
- str.force_encoding('TIS-620').valid_encoding?.should be_true
- str.force_encoding('Windows-874').valid_encoding?.should be_true
- str.force_encoding('Windows-1257').valid_encoding?.should be_true
- str.force_encoding('Windows-31J').valid_encoding?.should be_false
- str.force_encoding('MacJapanese').valid_encoding?.should be_false
- str.force_encoding('UTF-7').valid_encoding?.should be_true
- str.force_encoding('UTF8-MAC').valid_encoding?.should be_true
+ str.force_encoding('BINARY').valid_encoding?.should == true
+ str.force_encoding('UTF-8').valid_encoding?.should == true
+ str.force_encoding('US-ASCII').valid_encoding?.should == false
+ str.force_encoding('Big5').valid_encoding?.should == false
+ str.force_encoding('CP949').valid_encoding?.should == false
+ str.force_encoding('Emacs-Mule').valid_encoding?.should == false
+ str.force_encoding('EUC-JP').valid_encoding?.should == false
+ str.force_encoding('EUC-KR').valid_encoding?.should == false
+ str.force_encoding('EUC-TW').valid_encoding?.should == false
+ str.force_encoding('GB18030').valid_encoding?.should == false
+ str.force_encoding('GBK').valid_encoding?.should == false
+ str.force_encoding('ISO-8859-1').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-2').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-3').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-4').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-5').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-6').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-7').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-8').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-9').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-10').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-11').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-13').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-14').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-15').valid_encoding?.should == true
+ str.force_encoding('ISO-8859-16').valid_encoding?.should == true
+ str.force_encoding('KOI8-R').valid_encoding?.should == true
+ str.force_encoding('KOI8-U').valid_encoding?.should == true
+ str.force_encoding('Shift_JIS').valid_encoding?.should == false
+ "\xD8\x00".dup.force_encoding('UTF-16BE').valid_encoding?.should == false
+ "\x00\xD8".dup.force_encoding('UTF-16LE').valid_encoding?.should == false
+ "\x04\x03\x02\x01".dup.force_encoding('UTF-32BE').valid_encoding?.should == false
+ "\x01\x02\x03\x04".dup.force_encoding('UTF-32LE').valid_encoding?.should == false
+ str.force_encoding('Windows-1251').valid_encoding?.should == true
+ str.force_encoding('IBM437').valid_encoding?.should == true
+ str.force_encoding('IBM737').valid_encoding?.should == true
+ str.force_encoding('IBM775').valid_encoding?.should == true
+ str.force_encoding('CP850').valid_encoding?.should == true
+ str.force_encoding('IBM852').valid_encoding?.should == true
+ str.force_encoding('CP852').valid_encoding?.should == true
+ str.force_encoding('IBM855').valid_encoding?.should == true
+ str.force_encoding('CP855').valid_encoding?.should == true
+ str.force_encoding('IBM857').valid_encoding?.should == true
+ str.force_encoding('IBM860').valid_encoding?.should == true
+ str.force_encoding('IBM861').valid_encoding?.should == true
+ str.force_encoding('IBM862').valid_encoding?.should == true
+ str.force_encoding('IBM863').valid_encoding?.should == true
+ str.force_encoding('IBM864').valid_encoding?.should == true
+ str.force_encoding('IBM865').valid_encoding?.should == true
+ str.force_encoding('IBM866').valid_encoding?.should == true
+ str.force_encoding('IBM869').valid_encoding?.should == true
+ str.force_encoding('Windows-1258').valid_encoding?.should == true
+ str.force_encoding('GB1988').valid_encoding?.should == true
+ str.force_encoding('macCentEuro').valid_encoding?.should == true
+ str.force_encoding('macCroatian').valid_encoding?.should == true
+ str.force_encoding('macCyrillic').valid_encoding?.should == true
+ str.force_encoding('macGreek').valid_encoding?.should == true
+ str.force_encoding('macIceland').valid_encoding?.should == true
+ str.force_encoding('macRoman').valid_encoding?.should == true
+ str.force_encoding('macRomania').valid_encoding?.should == true
+ str.force_encoding('macThai').valid_encoding?.should == true
+ str.force_encoding('macTurkish').valid_encoding?.should == true
+ str.force_encoding('macUkraine').valid_encoding?.should == true
+ str.force_encoding('stateless-ISO-2022-JP').valid_encoding?.should == false
+ str.force_encoding('eucJP-ms').valid_encoding?.should == false
+ str.force_encoding('CP51932').valid_encoding?.should == false
+ str.force_encoding('GB2312').valid_encoding?.should == false
+ str.force_encoding('GB12345').valid_encoding?.should == false
+ str.force_encoding('ISO-2022-JP').valid_encoding?.should == true
+ str.force_encoding('ISO-2022-JP-2').valid_encoding?.should == true
+ str.force_encoding('CP50221').valid_encoding?.should == true
+ str.force_encoding('Windows-1252').valid_encoding?.should == true
+ str.force_encoding('Windows-1250').valid_encoding?.should == true
+ str.force_encoding('Windows-1256').valid_encoding?.should == true
+ str.force_encoding('Windows-1253').valid_encoding?.should == true
+ str.force_encoding('Windows-1255').valid_encoding?.should == true
+ str.force_encoding('Windows-1254').valid_encoding?.should == true
+ str.force_encoding('TIS-620').valid_encoding?.should == true
+ str.force_encoding('Windows-874').valid_encoding?.should == true
+ str.force_encoding('Windows-1257').valid_encoding?.should == true
+ str.force_encoding('Windows-31J').valid_encoding?.should == false
+ str.force_encoding('MacJapanese').valid_encoding?.should == false
+ str.force_encoding('UTF-7').valid_encoding?.should == true
+ str.force_encoding('UTF8-MAC').valid_encoding?.should == true
end
it "returns true for IBM720 encoding self is valid in" do
str = +"\xE6\x9D\x94"
- str.force_encoding('IBM720').valid_encoding?.should be_true
- str.force_encoding('CP720').valid_encoding?.should be_true
+ str.force_encoding('IBM720').valid_encoding?.should == true
+ str.force_encoding('CP720').valid_encoding?.should == true
end
it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do
str = +"\u{8765}"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
str.force_encoding('ascii')
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
end
it "returns false if self contains a character invalid in the associated encoding" do
- "abc#{[0x80].pack('C')}".dup.force_encoding('ascii').valid_encoding?.should be_false
+ "abc#{[0x80].pack('C')}".dup.force_encoding('ascii').valid_encoding?.should == false
end
it "returns false if a valid String had an invalid character appended to it" do
str = +"a"
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
str << [0xDD].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
end
it "returns true if an invalid string is appended another invalid one but both make a valid string" do
str = [0xD0].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_false
+ str.valid_encoding?.should == false
str << [0xBF].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_true
+ str.valid_encoding?.should == true
end
end
diff --git a/spec/ruby/core/struct/constants_spec.rb b/spec/ruby/core/struct/constants_spec.rb
index fa61a4b912..7e8af1a211 100644
--- a/spec/ruby/core/struct/constants_spec.rb
+++ b/spec/ruby/core/struct/constants_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Struct::Group" do
- it "is no longer defined" do
- Struct.should_not.const_defined?(:Group)
- end
+describe "Struct::Group" do
+ it "is no longer defined" do
+ Struct.should_not.const_defined?(:Group)
end
+end
- describe "Struct::Passwd" do
- it "is no longer defined" do
- Struct.should_not.const_defined?(:Passwd)
- end
+describe "Struct::Passwd" do
+ it "is no longer defined" do
+ Struct.should_not.const_defined?(:Passwd)
end
end
diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb
index cd05aee056..590e1ab40b 100644
--- a/spec/ruby/core/struct/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb
@@ -14,7 +14,7 @@ describe "Struct#deconstruct_keys" do
-> {
obj.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ }.should.raise(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
end
it "returns only specified keys" do
@@ -43,6 +43,13 @@ describe "Struct#deconstruct_keys" do
s.deconstruct_keys([-1] ).should == {-1 => 30}
end
+ it "ignores incorrect position numbers" do
+ struct = Struct.new(:x, :y, :z)
+ s = struct.new(10, 20, 30)
+
+ s.deconstruct_keys([0, 3]).should == {0 => 10}
+ end
+
it "support mixing attribute names and argument position numbers" do
struct = Struct.new(:x, :y)
s = struct.new(1, 2)
@@ -80,22 +87,44 @@ describe "Struct#deconstruct_keys" do
obj.deconstruct_keys(nil).should == {x: 1, y: 2}
end
- it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
+ it "tries to convert a key with #to_int if index is not a String nor a Symbol, but responds to #to_int" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ key = mock("to_int")
+ key.should_receive(:to_int).and_return(1)
+
+ s.deconstruct_keys([key]).should == { key => 2 }
+ end
+
+ it "raises a TypeError if the conversion with #to_int does not return an Integer" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ key = mock("to_int")
+ key.should_receive(:to_int).and_return("not an Integer")
+
+ -> {
+ s.deconstruct_keys([key])
+ }.should raise_consistent_error(TypeError, /can't convert MockObject into Integer/)
+ end
+
+ it "raises TypeError if index is not a String, a Symbol and not convertible to Integer" do
struct = Struct.new(:x, :y)
s = struct.new(1, 2)
-> {
s.deconstruct_keys([0, []])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
end
it "raise TypeError if passed anything except nil or array" do
struct = Struct.new(:x, :y)
s = struct.new(1, 2)
- -> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys('x') }.should.raise(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys(1) }.should.raise(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys(:x) }.should.raise(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys({}) }.should.raise(TypeError, /expected Array or nil/)
end
end
diff --git a/spec/ruby/core/struct/dig_spec.rb b/spec/ruby/core/struct/dig_spec.rb
index 93a52dbbe1..52e4d1dd9a 100644
--- a/spec/ruby/core/struct/dig_spec.rb
+++ b/spec/ruby/core/struct/dig_spec.rb
@@ -32,11 +32,11 @@ describe "Struct#dig" do
instance = @klass.new(1)
-> {
instance.dig(:a, 3)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises an ArgumentError if no arguments provided" do
- -> { @instance.dig }.should raise_error(ArgumentError)
+ -> { @instance.dig }.should.raise(ArgumentError)
end
it "calls #dig on any intermediate step with the rest of the sequence as arguments" do
diff --git a/spec/ruby/core/struct/each_pair_spec.rb b/spec/ruby/core/struct/each_pair_spec.rb
index 1230ca9026..db146c81e9 100644
--- a/spec/ruby/core/struct/each_pair_spec.rb
+++ b/spec/ruby/core/struct/each_pair_spec.rb
@@ -21,11 +21,11 @@ describe "Struct#each_pair" do
end
it "returns self if passed a block" do
- @car.each_pair {}.should equal(@car)
+ @car.each_pair {}.should.equal?(@car)
end
it "returns an Enumerator if not passed a block" do
- @car.each_pair.should be_an_instance_of(Enumerator)
+ @car.each_pair.should.instance_of?(Enumerator)
end
it_behaves_like :struct_accessor, :each_pair
diff --git a/spec/ruby/core/struct/each_spec.rb b/spec/ruby/core/struct/each_spec.rb
index 41c0fbd4d0..4fbdfee02a 100644
--- a/spec/ruby/core/struct/each_spec.rb
+++ b/spec/ruby/core/struct/each_spec.rb
@@ -19,7 +19,7 @@ describe "Struct#each" do
it "returns an Enumerator if not passed a block" do
car = StructClasses::Car.new('Ford', 'Ranger')
- car.each.should be_an_instance_of(Enumerator)
+ car.each.should.instance_of?(Enumerator)
end
it_behaves_like :struct_accessor, :each
diff --git a/spec/ruby/core/struct/element_reference_spec.rb b/spec/ruby/core/struct/element_reference_spec.rb
index 0f6d547f66..b94f3aae8c 100644
--- a/spec/ruby/core/struct/element_reference_spec.rb
+++ b/spec/ruby/core/struct/element_reference_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "Struct[]" do
it "is a synonym for new" do
- StructClasses::Ruby['2.0', 'i686'].should be_kind_of(StructClasses::Ruby)
+ StructClasses::Ruby['2.0', 'i686'].should.is_a?(StructClasses::Ruby)
end
end
@@ -26,20 +26,20 @@ describe "Struct#[]" do
it "fails when it does not know about the requested attribute" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[3] }.should raise_error(IndexError)
- -> { car[-4] }.should raise_error(IndexError)
- -> { car[:body] }.should raise_error(NameError)
- -> { car['wheels'] }.should raise_error(NameError)
+ -> { car[3] }.should.raise(IndexError)
+ -> { car[-4] }.should.raise(IndexError)
+ -> { car[:body] }.should.raise(NameError)
+ -> { car['wheels'] }.should.raise(NameError)
end
it "fails if passed too many arguments" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[:make, :model] }.should raise_error(ArgumentError)
+ -> { car[:make, :model] }.should.raise(ArgumentError)
end
it "fails if not passed a string, symbol, or integer" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[Object.new] }.should raise_error(TypeError)
+ -> { car[Object.new] }.should.raise(TypeError)
end
it "returns attribute names that contain hyphens" do
diff --git a/spec/ruby/core/struct/element_set_spec.rb b/spec/ruby/core/struct/element_set_spec.rb
index 6ba7b081a9..e5438ca09a 100644
--- a/spec/ruby/core/struct/element_set_spec.rb
+++ b/spec/ruby/core/struct/element_set_spec.rb
@@ -21,9 +21,16 @@ describe "Struct#[]=" do
it "fails when trying to assign attributes which don't exist" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car[:something] = true }.should raise_error(NameError)
- -> { car[3] = true }.should raise_error(IndexError)
- -> { car[-4] = true }.should raise_error(IndexError)
- -> { car[Object.new] = true }.should raise_error(TypeError)
+ -> { car[:something] = true }.should.raise(NameError)
+ -> { car[3] = true }.should.raise(IndexError)
+ -> { car[-4] = true }.should.raise(IndexError)
+ -> { car[Object.new] = true }.should.raise(TypeError)
+ end
+
+ it "raises a FrozenError on a frozen struct" do
+ car = StructClasses::Car.new('Ford', 'Ranger')
+ car.freeze
+
+ -> { car[:model] = 'Escape' }.should.raise(FrozenError)
end
end
diff --git a/spec/ruby/core/struct/eql_spec.rb b/spec/ruby/core/struct/eql_spec.rb
index c864b2b943..327c927278 100644
--- a/spec/ruby/core/struct/eql_spec.rb
+++ b/spec/ruby/core/struct/eql_spec.rb
@@ -8,6 +8,6 @@ describe "Struct#eql?" do
it "returns false if any corresponding elements are not #eql?" do
car = StructClasses::Car.new("Honda", "Accord", 1998)
similar_car = StructClasses::Car.new("Honda", "Accord", 1998.0)
- car.should_not eql(similar_car)
+ car.should_not.eql?(similar_car)
end
end
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index 7b80b814ef..675d403abd 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -3,6 +3,7 @@ module StructClasses
class Apple < Struct; end
Ruby = Struct.new(:version, :platform)
+ Single = Struct.new(:value)
Car = Struct.new(:make, :model, :year)
diff --git a/spec/ruby/core/struct/hash_spec.rb b/spec/ruby/core/struct/hash_spec.rb
index 53361eb7a9..750387b326 100644
--- a/spec/ruby/core/struct/hash_spec.rb
+++ b/spec/ruby/core/struct/hash_spec.rb
@@ -8,14 +8,14 @@ describe "Struct#hash" do
[StructClasses::Ruby.new("1.8.6", "PPC"),
StructClasses::Car.new("Hugo", "Foo", "1972")].each do |stc|
stc.hash.should == stc.dup.hash
- stc.hash.should be_kind_of(Integer)
+ stc.hash.should.is_a?(Integer)
end
end
it "returns the same value if structs are #eql?" do
car = StructClasses::Car.new("Honda", "Accord", "1998")
similar_car = StructClasses::Car.new("Honda", "Accord", "1998")
- car.should eql(similar_car)
+ car.should.eql?(similar_car)
car.hash.should == similar_car.hash
end
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index 1861bcafb0..c824f52e13 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Struct#initialize" do
it "is private" do
- StructClasses::Car.should have_private_instance_method(:initialize)
+ StructClasses::Car.private_instance_methods(true).should.include?(:initialize)
end
it 'allows valid Ruby method names for members' do
@@ -41,21 +41,34 @@ describe "Struct#initialize" do
StructClasses::SubclassX.new(:y).new.key.should == :value
end
- ruby_version_is ""..."3.2" do
- it "warns about passing only keyword arguments" do
- -> {
- StructClasses::Ruby.new(version: "3.1", platform: "OS")
- }.should complain(/warning: Passing only keyword arguments/)
- end
+ it "can be initialized with keyword arguments" do
+ positional_args = StructClasses::Ruby.new("3.2", "OS")
+ keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS")
+
+ positional_args.version.should == keyword_args.version
+ positional_args.platform.should == keyword_args.platform
end
- ruby_version_is "3.2" do
- it "can be initialized with keyword arguments" do
- positional_args = StructClasses::Ruby.new("3.2", "OS")
- keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS")
+ it "accepts positional arguments with empty keyword arguments" do
+ data = StructClasses::Single.new(42, **{})
+
+ data.value.should == 42
+
+ data = StructClasses::Ruby.new("3.2", "OS", **{})
- positional_args.version.should == keyword_args.version
- positional_args.platform.should == keyword_args.platform
+ data.version.should == "3.2"
+ data.platform.should == "OS"
+ end
+
+ it "can be called via delegated ... from a prepended module" do
+ wrapper = Module.new do
+ def initialize(...)
+ super(...)
+ end
end
+
+ klass = Class.new(Struct.new(:a)) { prepend wrapper }
+ s = klass.new("x")
+ s.a.should == "x"
end
end
diff --git a/spec/ruby/core/struct/instance_variable_get_spec.rb b/spec/ruby/core/struct/instance_variable_get_spec.rb
index e4a3ea87dc..e3555cd246 100644
--- a/spec/ruby/core/struct/instance_variable_get_spec.rb
+++ b/spec/ruby/core/struct/instance_variable_get_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "Struct#instance_variable_get" do
it "returns nil for attributes" do
car = StructClasses::Car.new("Hugo", "Foo", "1972")
- car.instance_variable_get(:@make).should be_nil
+ car.instance_variable_get(:@make).should == nil
end
it "returns a user value for variables with the same name as attributes" do
diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb
index 536b82041a..42fcd3cc29 100644
--- a/spec/ruby/core/struct/keyword_init_spec.rb
+++ b/spec/ruby/core/struct/keyword_init_spec.rb
@@ -5,36 +5,36 @@ require_relative 'fixtures/classes'
describe "StructClass#keyword_init?" do
it "returns true for a struct that accepts keyword arguments to initialize" do
struct = Struct.new(:arg, keyword_init: true)
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
end
it "returns false for a struct that does not accept keyword arguments to initialize" do
struct = Struct.new(:arg, keyword_init: false)
- struct.keyword_init?.should be_false
+ struct.keyword_init?.should == false
end
it "returns nil for a struct that did not explicitly specify keyword_init" do
struct = Struct.new(:arg)
- struct.keyword_init?.should be_nil
+ struct.keyword_init?.should == nil
end
it "returns nil for a struct that does specify keyword_init to be nil" do
struct = Struct.new(:arg, keyword_init: nil)
- struct.keyword_init?.should be_nil
+ struct.keyword_init?.should == nil
end
it "returns true for any truthy value, not just for true" do
struct = Struct.new(:arg, keyword_init: 1)
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
struct = Struct.new(:arg, keyword_init: "")
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
struct = Struct.new(:arg, keyword_init: [])
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
struct = Struct.new(:arg, keyword_init: {})
- struct.keyword_init?.should be_true
+ struct.keyword_init?.should == true
end
context "class inheriting Struct" do
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index 73e88a81c1..b3ece2efed 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -38,19 +38,19 @@ describe "Struct.new" do
it "creates a new anonymous class with nil first argument" do
struct = Struct.new(nil, :foo)
struct.new("bar").foo.should == "bar"
- struct.should be_kind_of(Class)
- struct.name.should be_nil
+ struct.should.is_a?(Class)
+ struct.name.should == nil
end
it "creates a new anonymous class with symbol arguments" do
struct = Struct.new(:make, :model)
- struct.should be_kind_of(Class)
+ struct.should.is_a?(Class)
struct.name.should == nil
end
it "does not create a constant with symbol as first argument" do
Struct.new(:Animal2, :name, :legs, :eyeballs)
- Struct.const_defined?("Animal2").should be_false
+ Struct.const_defined?("Animal2").should == false
end
it "allows non-ASCII member name" do
@@ -60,62 +60,42 @@ describe "Struct.new" do
end
it "fails with invalid constant name as first argument" do
- -> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError)
+ -> { Struct.new('animal', :name, :legs, :eyeballs) }.should.raise(NameError)
end
it "raises a TypeError if object doesn't respond to to_sym" do
- -> { Struct.new(:animal, mock('giraffe')) }.should raise_error(TypeError)
- -> { Struct.new(:animal, 1.0) }.should raise_error(TypeError)
- -> { Struct.new(:animal, Time.now) }.should raise_error(TypeError)
- -> { Struct.new(:animal, Class) }.should raise_error(TypeError)
- -> { Struct.new(:animal, nil) }.should raise_error(TypeError)
- -> { Struct.new(:animal, true) }.should raise_error(TypeError)
- -> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError)
- end
-
- ruby_version_is ""..."3.2" do
- it "raises a TypeError or ArgumentError if passed a Hash with an unknown key" do
- # CRuby < 3.2 raises ArgumentError: unknown keyword: :name, but that seems a bug:
- # https://bugs.ruby-lang.org/issues/18632
- -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(StandardError) { |e|
- [ArgumentError, TypeError].should.include?(e.class)
- }
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError if passed a Hash with an unknown key" do
- -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
- end
+ -> { Struct.new(:animal, mock('giraffe')) }.should.raise(TypeError)
+ -> { Struct.new(:animal, 1.0) }.should.raise(TypeError)
+ -> { Struct.new(:animal, Time.now) }.should.raise(TypeError)
+ -> { Struct.new(:animal, Class) }.should.raise(TypeError)
+ -> { Struct.new(:animal, nil) }.should.raise(TypeError)
+ -> { Struct.new(:animal, true) }.should.raise(TypeError)
+ -> { Struct.new(:animal, ['chris', 'evan']) }.should.raise(TypeError)
end
- ruby_version_is ""..."3.3" do
- it "raises ArgumentError if not provided any arguments" do
- -> { Struct.new }.should raise_error(ArgumentError)
- end
+ it "raises a TypeError if passed a Hash with an unknown key" do
+ -> { Struct.new(:animal, { name: 'chris' }) }.should.raise(TypeError)
end
- ruby_version_is "3.3" do
- it "works when not provided any arguments" do
- c = Struct.new
- c.should be_kind_of(Class)
- c.superclass.should == Struct
- end
+ it "works when not provided any arguments" do
+ c = Struct.new
+ c.should.is_a?(Class)
+ c.superclass.should == Struct
end
it "raises ArgumentError when there is a duplicate member" do
- -> { Struct.new(:foo, :foo) }.should raise_error(ArgumentError, "duplicate member: foo")
+ -> { Struct.new(:foo, :foo) }.should.raise(ArgumentError, "duplicate member: foo")
end
it "raises a TypeError if object is not a Symbol" do
obj = mock(':ruby')
def obj.to_sym() :ruby end
- -> { Struct.new(:animal, obj) }.should raise_error(TypeError)
+ -> { Struct.new(:animal, obj) }.should.raise(TypeError)
end
it "processes passed block with instance_eval" do
klass = Struct.new(:something) { @something_else = 'something else entirely!' }
- klass.instance_variables.should include(:@something_else)
+ klass.instance_variables.should.include?(:@something_else)
end
context "with a block" do
@@ -136,7 +116,7 @@ describe "Struct.new" do
klass = Struct.new(:attr) do |block_parameter|
given = block_parameter
end
- klass.should equal(given)
+ klass.should.equal?(given)
end
end
@@ -153,29 +133,56 @@ describe "Struct.new" do
end
it "creates reader methods" do
- StructClasses::Ruby.new.should have_method(:version)
- StructClasses::Ruby.new.should have_method(:platform)
+ StructClasses::Ruby.new.should.respond_to?(:version)
+ StructClasses::Ruby.new.should.respond_to?(:platform)
end
it "creates writer methods" do
- StructClasses::Ruby.new.should have_method(:version=)
- StructClasses::Ruby.new.should have_method(:platform=)
+ StructClasses::Ruby.new.should.respond_to?(:version=)
+ StructClasses::Ruby.new.should.respond_to?(:platform=)
end
it "fails with too many arguments" do
- -> { StructClasses::Ruby.new('2.0', 'i686', true) }.should raise_error(ArgumentError)
+ -> { StructClasses::Ruby.new('2.0', 'i686', true) }.should.raise(ArgumentError)
end
- ruby_version_is '3.2' do
- it "accepts keyword arguments to initialize" do
- type = Struct.new(:args)
+ it "accepts keyword arguments to initialize" do
+ type = Struct.new(:args)
+
+ obj = type.new(args: 42)
+ obj2 = type.new(42)
- obj = type.new(args: 42)
- obj2 = type.new(42)
+ obj.should == obj2
+ obj.args.should == 42
+ obj2.args.should == 42
+ end
+
+ context "given positional and keyword arguments" do
+ it "treats keyword arguments as a positional parameter" do
+ type = Struct.new(:a, :b)
+ s = type.new("a", b: "b")
+ s.a.should == "a"
+ s.b.should == {b: "b"}
+
+ type = Struct.new(:a, :b, :c)
+ s = type.new("a", b: "b", c: "c")
+ s.a.should == "a"
+ s.b.should == {b: "b", c: "c"}
+ s.c.should == nil
+ end
+
+ it "ignores empty keyword arguments" do
+ type = Struct.new(:a, :b)
+ h = {}
+ s = type.new("a", **h)
+
+ s.a.should == "a"
+ s.b.should == nil
+ end
- obj.should == obj2
- obj.args.should == 42
- obj2.args.should == 42
+ it "raises ArgumentError when all struct attribute values are specified" do
+ type = Struct.new(:a, :b)
+ -> { type.new("a", "b", c: "c") }.should.raise(ArgumentError, "struct size differs")
end
end
end
@@ -192,7 +199,7 @@ describe "Struct.new" do
end
it "raises when there is a duplicate member" do
- -> { Struct.new(:foo, :foo, keyword_init: true) }.should raise_error(ArgumentError, "duplicate member: foo")
+ -> { Struct.new(:foo, :foo, keyword_init: true) }.should.raise(ArgumentError, "duplicate member: foo")
end
describe "new class instantiation" do
@@ -205,31 +212,31 @@ describe "Struct.new" do
it "allows missing arguments" do
obj = @struct_with_kwa.new(name: "elefant")
obj.name.should == "elefant"
- obj.legs.should be_nil
+ obj.legs.should == nil
end
it "allows no arguments" do
obj = @struct_with_kwa.new
- obj.name.should be_nil
- obj.legs.should be_nil
+ obj.name.should == nil
+ obj.legs.should == nil
end
it "raises ArgumentError when passed not declared keyword argument" do
-> {
@struct_with_kwa.new(name: "elefant", legs: 4, foo: "bar")
- }.should raise_error(ArgumentError, /unknown keywords: foo/)
+ }.should.raise(ArgumentError, /unknown keywords: foo/)
end
it "raises ArgumentError when passed a list of arguments" do
-> {
@struct_with_kwa.new("elefant", 4)
- }.should raise_error(ArgumentError, /wrong number of arguments/)
+ }.should.raise(ArgumentError, /wrong number of arguments/)
end
it "raises ArgumentError when passed a single non-hash argument" do
-> {
@struct_with_kwa.new("elefant")
- }.should raise_error(ArgumentError, /wrong number of arguments/)
+ }.should.raise(ArgumentError, /wrong number of arguments/)
end
end
end
diff --git a/spec/ruby/core/struct/shared/select.rb b/spec/ruby/core/struct/shared/select.rb
index 35abee461b..dfa1a809fe 100644
--- a/spec/ruby/core/struct/shared/select.rb
+++ b/spec/ruby/core/struct/shared/select.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe :struct_select, shared: true do
it "raises an ArgumentError if given any non-block arguments" do
struct = StructClasses::Car.new
- -> { struct.send(@method, 1) { } }.should raise_error(ArgumentError)
+ -> { struct.send(@method, 1) { } }.should.raise(ArgumentError)
end
it "returns a new array of elements for which block is true" do
@@ -14,13 +14,13 @@ describe :struct_select, shared: true do
it "returns an instance of Array" do
struct = StructClasses::Car.new("Ford", "Escort", "1995")
- struct.send(@method) { true }.should be_an_instance_of(Array)
+ struct.send(@method) { true }.should.instance_of?(Array)
end
describe "without block" do
it "returns an instance of Enumerator" do
struct = Struct.new(:foo).new
- struct.send(@method).should be_an_instance_of(Enumerator)
+ struct.send(@method).should.instance_of?(Enumerator)
end
end
end
diff --git a/spec/ruby/core/struct/struct_spec.rb b/spec/ruby/core/struct/struct_spec.rb
index 8817dc1a58..9fab9c0629 100644
--- a/spec/ruby/core/struct/struct_spec.rb
+++ b/spec/ruby/core/struct/struct_spec.rb
@@ -21,7 +21,7 @@ describe "Struct anonymous class instance methods" do
it "reader method should not interfere with undefined methods" do
car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car.something_weird }.should raise_error(NoMethodError)
+ -> { car.something_weird }.should.raise(NoMethodError)
end
it "writer method be a synonym for []=" do
@@ -33,6 +33,13 @@ describe "Struct anonymous class instance methods" do
car['model'].should == 'F150'
car[1].should == 'F150'
end
+
+ it "writer methods raise a FrozenError on a frozen struct" do
+ car = StructClasses::Car.new('Ford', 'Ranger')
+ car.freeze
+
+ -> { car.model = 'Escape' }.should.raise(FrozenError)
+ end
end
describe "Struct subclasses" do
diff --git a/spec/ruby/core/struct/to_h_spec.rb b/spec/ruby/core/struct/to_h_spec.rb
index 861ce3f49d..e0846ef268 100644
--- a/spec/ruby/core/struct/to_h_spec.rb
+++ b/spec/ruby/core/struct/to_h_spec.rb
@@ -36,17 +36,17 @@ describe "Struct#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
StructClasses::Car.new.to_h { |k, v| [k.to_s, "#{v}".downcase, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
StructClasses::Car.new.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
StructClasses::Car.new.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -62,7 +62,7 @@ describe "Struct#to_h" do
-> do
StructClasses::Car.new.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/struct/values_at_spec.rb b/spec/ruby/core/struct/values_at_spec.rb
index 5e5a496600..6aac5d96b3 100644
--- a/spec/ruby/core/struct/values_at_spec.rb
+++ b/spec/ruby/core/struct/values_at_spec.rb
@@ -14,8 +14,8 @@ describe "Struct#values_at" do
end
it "raises IndexError if any of integers is out of range" do
- -> { @movie.values_at(3) }.should raise_error(IndexError, "offset 3 too large for struct(size:3)")
- -> { @movie.values_at(-4) }.should raise_error(IndexError, "offset -4 too small for struct(size:3)")
+ -> { @movie.values_at(3) }.should.raise(IndexError, "offset 3 too large for struct(size:3)")
+ -> { @movie.values_at(-4) }.should.raise(IndexError, "offset -4 too small for struct(size:3)")
end
end
@@ -29,7 +29,7 @@ describe "Struct#values_at" do
end
it "raises RangeError if any element of the range is negative and out of range" do
- -> { @movie.values_at(-4..3) }.should raise_error(RangeError, "-4..3 out of range")
+ -> { @movie.values_at(-4..3) }.should.raise(RangeError, "-4..3 out of range")
end
it "supports endless Range" do
@@ -54,6 +54,6 @@ describe "Struct#values_at" do
end
it "fails when passed unsupported types" do
- -> { @movie.values_at('make') }.should raise_error(TypeError, "no implicit conversion of String into Integer")
+ -> { @movie.values_at('make') }.should.raise(TypeError, "no implicit conversion of String into Integer")
end
end
diff --git a/spec/ruby/core/symbol/all_symbols_spec.rb b/spec/ruby/core/symbol/all_symbols_spec.rb
index 1e21809093..689f6211de 100644
--- a/spec/ruby/core/symbol/all_symbols_spec.rb
+++ b/spec/ruby/core/symbol/all_symbols_spec.rb
@@ -3,17 +3,17 @@ require_relative '../../spec_helper'
describe "Symbol.all_symbols" do
it "returns an array of Symbols" do
all_symbols = Symbol.all_symbols
- all_symbols.should be_an_instance_of(Array)
- all_symbols.each { |s| s.should be_an_instance_of(Symbol) }
+ all_symbols.should.instance_of?(Array)
+ all_symbols.each { |s| s.should.instance_of?(Symbol) }
end
it "includes symbols that are strongly referenced" do
symbol = "symbol_specs_#{rand(5_000_000)}".to_sym
- Symbol.all_symbols.should include(symbol)
+ Symbol.all_symbols.should.include?(symbol)
end
it "includes symbols that are referenced in source code but not yet executed" do
- Symbol.all_symbols.any? { |s| s.to_s == 'symbol_specs_referenced_in_source_code' }.should be_true
+ Symbol.all_symbols.any? { |s| s.to_s == 'symbol_specs_referenced_in_source_code' }.should == true
:symbol_specs_referenced_in_source_code
end
end
diff --git a/spec/ruby/core/symbol/capitalize_spec.rb b/spec/ruby/core/symbol/capitalize_spec.rb
index a84bcf280a..a93d951e6a 100644
--- a/spec/ruby/core/symbol/capitalize_spec.rb
+++ b/spec/ruby/core/symbol/capitalize_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#capitalize" do
it "returns a Symbol" do
- :glark.capitalize.should be_an_instance_of(Symbol)
+ :glark.capitalize.should.instance_of?(Symbol)
end
it "converts the first character to uppercase if it is ASCII" do
diff --git a/spec/ruby/core/symbol/casecmp_spec.rb b/spec/ruby/core/symbol/casecmp_spec.rb
index 662a29a284..dcb77a8350 100644
--- a/spec/ruby/core/symbol/casecmp_spec.rb
+++ b/spec/ruby/core/symbol/casecmp_spec.rb
@@ -64,16 +64,16 @@ end
describe "Symbol#casecmp" do
it "returns nil if other is a String" do
- :abc.casecmp("abc").should be_nil
+ :abc.casecmp("abc").should == nil
end
it "returns nil if other is an Integer" do
- :abc.casecmp(1).should be_nil
+ :abc.casecmp(1).should == nil
end
it "returns nil if other is an object" do
obj = mock("string <=>")
- :abc.casecmp(obj).should be_nil
+ :abc.casecmp(obj).should == nil
end
end
diff --git a/spec/ruby/core/symbol/comparison_spec.rb b/spec/ruby/core/symbol/comparison_spec.rb
index 613177be05..6d56176e97 100644
--- a/spec/ruby/core/symbol/comparison_spec.rb
+++ b/spec/ruby/core/symbol/comparison_spec.rb
@@ -37,15 +37,15 @@ end
describe "Symbol#<=>" do
it "returns nil if other is a String" do
- (:abc <=> "abc").should be_nil
+ (:abc <=> "abc").should == nil
end
it "returns nil if other is an Integer" do
- (:abc <=> 1).should be_nil
+ (:abc <=> 1).should == nil
end
it "returns nil if other is an object" do
obj = mock("string <=>")
- (:abc <=> obj).should be_nil
+ (:abc <=> obj).should == nil
end
end
diff --git a/spec/ruby/core/symbol/downcase_spec.rb b/spec/ruby/core/symbol/downcase_spec.rb
index 7e94c669cc..76418aa9da 100644
--- a/spec/ruby/core/symbol/downcase_spec.rb
+++ b/spec/ruby/core/symbol/downcase_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#downcase" do
it "returns a Symbol" do
- :glark.downcase.should be_an_instance_of(Symbol)
+ :glark.downcase.should.instance_of?(Symbol)
end
it "converts uppercase ASCII characters to their lowercase equivalents" do
diff --git a/spec/ruby/core/symbol/dup_spec.rb b/spec/ruby/core/symbol/dup_spec.rb
index 8b35917c27..eef3078030 100644
--- a/spec/ruby/core/symbol/dup_spec.rb
+++ b/spec/ruby/core/symbol/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "Symbol#dup" do
it "returns self" do
- :a_symbol.dup.should equal(:a_symbol)
+ :a_symbol.dup.should.equal?(:a_symbol)
end
end
diff --git a/spec/ruby/core/symbol/empty_spec.rb b/spec/ruby/core/symbol/empty_spec.rb
index 19c23cfe5f..1d90a59a5b 100644
--- a/spec/ruby/core/symbol/empty_spec.rb
+++ b/spec/ruby/core/symbol/empty_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Symbol#empty?" do
it "returns true if self is empty" do
- :"".empty?.should be_true
+ :"".empty?.should == true
end
it "returns false if self is non-empty" do
- :"a".empty?.should be_false
+ :"a".empty?.should == false
end
end
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index 6dbb36c2ad..f2269996af 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -6,7 +6,7 @@ describe "Symbol#inspect" do
:fred? => ":fred?",
:fred! => ":fred!",
:BAD! => ":BAD!",
- :_BAD! => ":_BAD!",
+ :_BAD! => ":_BAD!",
:$ruby => ":$ruby",
:@ruby => ":@ruby",
:@@ruby => ":@@ruby",
@@ -66,9 +66,9 @@ describe "Symbol#inspect" do
:~ => ":~",
:| => ":|",
- :"!" => [":\"!\"", ":!" ],
- :"!=" => [":\"!=\"", ":!="],
- :"!~" => [":\"!~\"", ":!~"],
+ :"!" => ":!",
+ :"!=" => ":!=",
+ :"!~" => ":!~",
:"\$" => ":\"$\"", # for justice!
:"&&" => ":\"&&\"",
:"'" => ":\"\'\"",
@@ -96,12 +96,36 @@ describe "Symbol#inspect" do
:"foo " => ":\"foo \"",
:" foo" => ":\" foo\"",
:" " => ":\" \"",
+
+ :"ê" => [":ê", ":\"\\u00EA\""],
+ :"测" => [":测", ":\"\\u6D4B\""],
+ :"🦊" => [":🦊", ":\"\\u{1F98A}\""],
}
+ expected_by_encoding = Encoding::default_external == Encoding::UTF_8 ? 0 : 1
symbols.each do |input, expected|
- expected = expected[1] if expected.is_a?(Array)
+ expected = expected[expected_by_encoding] if expected.is_a?(Array)
it "returns self as a symbol literal for #{expected}" do
input.inspect.should == expected
end
end
+
+ it "quotes BINARY symbols" do
+ sym = "foo\xA4".b.to_sym
+ sym.inspect.should == ':"foo\xA4"'
+ end
+
+ it "quotes symbols in non-ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |encoding|
+ sym = "foo".encode(encoding).to_sym
+ sym.inspect.should == ':"foo"'
+ end
+ end
+
+ it "quotes and escapes symbols in dummy encodings" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ sym = "abcd".dup.force_encoding(encoding).to_sym
+ sym.inspect.should == ':"\x61\x62\x63\x64"'
+ end
+ end
end
diff --git a/spec/ruby/core/symbol/intern_spec.rb b/spec/ruby/core/symbol/intern_spec.rb
index ea04b87e8a..9d0914c7fb 100644
--- a/spec/ruby/core/symbol/intern_spec.rb
+++ b/spec/ruby/core/symbol/intern_spec.rb
@@ -6,6 +6,6 @@ describe "Symbol#intern" do
end
it "returns a Symbol" do
- :foo.intern.should be_kind_of(Symbol)
+ :foo.intern.should.is_a?(Symbol)
end
end
diff --git a/spec/ruby/core/symbol/match_spec.rb b/spec/ruby/core/symbol/match_spec.rb
index 41e058f977..7b165218c6 100644
--- a/spec/ruby/core/symbol/match_spec.rb
+++ b/spec/ruby/core/symbol/match_spec.rb
@@ -6,7 +6,7 @@ describe :symbol_match, shared: true do
end
it "returns nil if there is no match" do
- :a.send(@method, /b/).should be_nil
+ :a.send(@method, /b/).should == nil
end
it "sets the last match pseudo-variables" do
@@ -22,12 +22,12 @@ end
describe "Symbol#match" do
it "returns the MatchData" do
result = :abc.match(/b/)
- result.should be_kind_of(MatchData)
+ result.should.is_a?(MatchData)
result[0].should == 'b'
end
it "returns nil if there is no match" do
- :a.match(/b/).should be_nil
+ :a.match(/b/).should == nil
end
it "sets the last match pseudo-variables" do
@@ -38,7 +38,7 @@ describe "Symbol#match" do
describe "when passed a block" do
it "yields the MatchData" do
:abc.match(/./) {|m| ScratchPad.record m }
- ScratchPad.recorded.should be_kind_of(MatchData)
+ ScratchPad.recorded.should.is_a?(MatchData)
end
it "returns the block result" do
@@ -61,17 +61,17 @@ describe "Symbol#match?" do
context "when matches the given regex" do
it "returns true but does not set Regexp.last_match" do
- :string.match?(/string/i).should be_true
- Regexp.last_match.should be_nil
+ :string.match?(/string/i).should == true
+ Regexp.last_match.should == nil
end
end
it "returns false when does not match the given regex" do
- :string.match?(/STRING/).should be_false
+ :string.match?(/STRING/).should == false
end
it "takes matching position as the 2nd argument" do
- :string.match?(/str/i, 0).should be_true
- :string.match?(/str/i, 1).should be_false
+ :string.match?(/str/i, 0).should == true
+ :string.match?(/str/i, 1).should == false
end
end
diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb
index d012b7634e..00a9c7d7dc 100644
--- a/spec/ruby/core/symbol/shared/id2name.rb
+++ b/spec/ruby/core/symbol/shared/id2name.rb
@@ -13,4 +13,18 @@ describe :symbol_id2name, shared: true do
symbol.send(@method).encoding.should == Encoding::US_ASCII
end
+
+ ruby_version_is "3.4" do
+ it "warns about mutating returned string" do
+ -> { :bad!.send(@method).upcase! }.should complain(/warning: string returned by :bad!.to_s will be frozen in the future/)
+ end
+
+ it "does not warn about mutation when Warning[:deprecated] is false" do
+ deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ -> { :bad!.send(@method).upcase! }.should_not complain
+ ensure
+ Warning[:deprecated] = deprecated
+ end
+ end
end
diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb
index d3d4aad617..4e3a35240c 100644
--- a/spec/ruby/core/symbol/shared/slice.rb
+++ b/spec/ruby/core/symbol/shared/slice.rb
@@ -7,11 +7,11 @@ describe :symbol_slice, shared: true do
end
it "returns nil if the index starts from the end and is greater than the length" do
- :symbol.send(@method, -10).should be_nil
+ :symbol.send(@method, -10).should == nil
end
it "returns nil if the index is greater than the length" do
- :symbol.send(@method, 42).should be_nil
+ :symbol.send(@method, 42).should == nil
end
end
@@ -31,14 +31,14 @@ describe :symbol_slice, shared: true do
end
it "returns nil if the index is greater than the length" do
- :symbol.send(@method, 10,1).should be_nil
+ :symbol.send(@method, 10,1).should == nil
end
end
describe "and a positive index and negative length" do
it "returns nil" do
- :symbol.send(@method, 0,-1).should be_nil
- :symbol.send(@method, 1,-1).should be_nil
+ :symbol.send(@method, 0,-1).should == nil
+ :symbol.send(@method, 1,-1).should == nil
end
end
@@ -56,13 +56,13 @@ describe :symbol_slice, shared: true do
end
it "returns nil if the index is past the start" do
- :symbol.send(@method, -10,1).should be_nil
+ :symbol.send(@method, -10,1).should == nil
end
end
describe "and a negative index and negative length" do
it "returns nil" do
- :symbol.send(@method, -1,-1).should be_nil
+ :symbol.send(@method, -1,-1).should == nil
end
end
@@ -74,21 +74,21 @@ describe :symbol_slice, shared: true do
describe "and a nil length" do
it "raises a TypeError" do
- -> { :symbol.send(@method, 1,nil) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, 1,nil) }.should.raise(TypeError)
end
end
describe "and a length that cannot be converted into an Integer" do
it "raises a TypeError when given an Array" do
- -> { :symbol.send(@method, 1,Array.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, 1,Array.new) }.should.raise(TypeError)
end
it "raises a TypeError when given an Hash" do
- -> { :symbol.send(@method, 1,Hash.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, 1,Hash.new) }.should.raise(TypeError)
end
it "raises a TypeError when given an Object" do
- -> { :symbol.send(@method, 1,Object.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, 1,Object.new) }.should.raise(TypeError)
end
end
end
@@ -101,21 +101,21 @@ describe :symbol_slice, shared: true do
describe "with a nil index" do
it "raises a TypeError" do
- -> { :symbol.send(@method, nil) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, nil) }.should.raise(TypeError)
end
end
describe "with an index that cannot be converted into an Integer" do
it "raises a TypeError when given an Array" do
- -> { :symbol.send(@method, Array.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, Array.new) }.should.raise(TypeError)
end
it "raises a TypeError when given an Hash" do
- -> { :symbol.send(@method, Hash.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, Hash.new) }.should.raise(TypeError)
end
it "raises a TypeError when given an Object" do
- -> { :symbol.send(@method, Object.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, Object.new) }.should.raise(TypeError)
end
end
@@ -136,7 +136,7 @@ describe :symbol_slice, shared: true do
describe "that is out of bounds" do
it "returns nil if the first range value begins past the end" do
- :symbol.send(@method, 10..12).should be_nil
+ :symbol.send(@method, 10..12).should == nil
end
it "returns a blank string if the first range value is within bounds and the last range value is not" do
@@ -145,11 +145,11 @@ describe :symbol_slice, shared: true do
end
it "returns nil if the first range value starts from the end and is within bounds and the last value starts from the end and is greater than the length" do
- :symbol.send(@method, -10..-12).should be_nil
+ :symbol.send(@method, -10..-12).should == nil
end
it "returns nil if the first range value starts from the end and is out of bounds and the last value starts from the end and is less than the length" do
- :symbol.send(@method, -10..-2).should be_nil
+ :symbol.send(@method, -10..-2).should == nil
end
end
@@ -178,7 +178,7 @@ describe :symbol_slice, shared: true do
end
it "returns nil if the expression does not match" do
- :symbol.send(@method, /0-9/).should be_nil
+ :symbol.send(@method, /0-9/).should == nil
end
it "sets $~ to the MatchData if there is a match" do
@@ -188,7 +188,7 @@ describe :symbol_slice, shared: true do
it "does not set $~ if there if there is not a match" do
:symbol.send(@method, /[0-9]+/)
- $~.should be_nil
+ $~.should == nil
end
end
@@ -203,8 +203,8 @@ describe :symbol_slice, shared: true do
end
it "returns nil if there is no capture for the index" do
- :symbol.send(@method, /(sy)(mb)(ol)/, 4).should be_nil
- :symbol.send(@method, /(sy)(mb)(ol)/, -4).should be_nil
+ :symbol.send(@method, /(sy)(mb)(ol)/, 4).should == nil
+ :symbol.send(@method, /(sy)(mb)(ol)/, -4).should == nil
end
it "converts the index to an Integer" do
@@ -213,20 +213,20 @@ describe :symbol_slice, shared: true do
describe "and an index that cannot be converted to an Integer" do
it "raises a TypeError when given an Hash" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, Hash.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, /(sy)(mb)(ol)/, Hash.new) }.should.raise(TypeError)
end
it "raises a TypeError when given an Array" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, Array.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, /(sy)(mb)(ol)/, Array.new) }.should.raise(TypeError)
end
it "raises a TypeError when given an Object" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, Object.new) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, /(sy)(mb)(ol)/, Object.new) }.should.raise(TypeError)
end
end
it "raises a TypeError if the index is nil" do
- -> { :symbol.send(@method, /(sy)(mb)(ol)/, nil) }.should raise_error(TypeError)
+ -> { :symbol.send(@method, /(sy)(mb)(ol)/, nil) }.should.raise(TypeError)
end
it "sets $~ to the MatchData if there is a match" do
@@ -239,7 +239,7 @@ describe :symbol_slice, shared: true do
it "does not set $~ to the MatchData if there is not a match" do
:symbol.send(@method, /0-9/, 0)
- $~.should be_nil
+ $~.should == nil
end
end
end
@@ -248,7 +248,7 @@ describe :symbol_slice, shared: true do
it "does not set $~" do
$~ = nil
:symbol.send(@method, "sym")
- $~.should be_nil
+ $~.should == nil
end
it "returns a string if there is match" do
@@ -256,7 +256,7 @@ describe :symbol_slice, shared: true do
end
it "returns nil if there is not a match" do
- :symbol.send(@method, "foo").should be_nil
+ :symbol.send(@method, "foo").should == nil
end
end
end
diff --git a/spec/ruby/core/symbol/swapcase_spec.rb b/spec/ruby/core/symbol/swapcase_spec.rb
index 24709cac30..95fc29e32b 100644
--- a/spec/ruby/core/symbol/swapcase_spec.rb
+++ b/spec/ruby/core/symbol/swapcase_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#swapcase" do
it "returns a Symbol" do
- :glark.swapcase.should be_an_instance_of(Symbol)
+ :glark.swapcase.should.instance_of?(Symbol)
end
it "converts lowercase ASCII characters to their uppercase equivalents" do
diff --git a/spec/ruby/core/symbol/symbol_spec.rb b/spec/ruby/core/symbol/symbol_spec.rb
index cefe70bc99..3534686a08 100644
--- a/spec/ruby/core/symbol/symbol_spec.rb
+++ b/spec/ruby/core/symbol/symbol_spec.rb
@@ -8,12 +8,12 @@ describe "Symbol" do
it ".allocate raises a TypeError" do
-> do
Symbol.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
Symbol.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/symbol/to_proc_spec.rb b/spec/ruby/core/symbol/to_proc_spec.rb
index 54eccdba11..93ed1e9e9b 100644
--- a/spec/ruby/core/symbol/to_proc_spec.rb
+++ b/spec/ruby/core/symbol/to_proc_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#to_proc" do
it "returns a new Proc" do
proc = :to_s.to_proc
- proc.should be_kind_of(Proc)
+ proc.should.is_a?(Proc)
end
it "sends self to arguments passed when calling #call on the Proc" do
@@ -27,37 +27,35 @@ describe "Symbol#to_proc" do
pr.parameters.should == [[:req], [:rest]]
end
- ruby_version_is "3.2" do
- it "only calls public methods" do
- body = proc do
- public def pub; @a << :pub end
- protected def pro; @a << :pro end
- private def pri; @a << :pri end
- attr_reader :a
- end
+ it "only calls public methods" do
+ body = proc do
+ public def pub; @a << :pub end
+ protected def pro; @a << :pro end
+ private def pri; @a << :pri end
+ attr_reader :a
+ end
- @a = []
- singleton_class.class_eval(&body)
- tap(&:pub)
- proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
- proc{tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
- @a.should == [:pub]
+ @a = []
+ singleton_class.class_eval(&body)
+ tap(&:pub)
+ proc{tap(&:pro)}.should.raise(NoMethodError, /protected method [`']pro' called/)
+ proc{tap(&:pri)}.should.raise(NoMethodError, /private method [`']pri' called/)
+ @a.should == [:pub]
- @a = []
- c = Class.new(&body)
- o = c.new
- o.instance_variable_set(:@a, [])
- o.tap(&:pub)
- proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
- proc{o.tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
- o.a.should == [:pub]
- end
+ @a = []
+ c = Class.new(&body)
+ o = c.new
+ o.instance_variable_set(:@a, [])
+ o.tap(&:pub)
+ proc{tap(&:pro)}.should.raise(NoMethodError, /protected method [`']pro' called/)
+ proc{o.tap(&:pri)}.should.raise(NoMethodError, /private method [`']pri' called/)
+ o.a.should == [:pub]
end
it "raises an ArgumentError when calling #call on the Proc without receiver" do
-> {
:object_id.to_proc.call
- }.should raise_error(ArgumentError, /no receiver given|wrong number of arguments \(given 0, expected 1\+\)/)
+ }.should.raise(ArgumentError, /no receiver given|wrong number of arguments \(given 0, expected 1\+\)/)
end
it "passes along the block passed to Proc#call" do
diff --git a/spec/ruby/core/symbol/upcase_spec.rb b/spec/ruby/core/symbol/upcase_spec.rb
index f704bdcbf3..3895d95efb 100644
--- a/spec/ruby/core/symbol/upcase_spec.rb
+++ b/spec/ruby/core/symbol/upcase_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
describe "Symbol#upcase" do
it "returns a Symbol" do
- :glark.upcase.should be_an_instance_of(Symbol)
+ :glark.upcase.should.instance_of?(Symbol)
end
it "converts lowercase ASCII characters to their uppercase equivalents" do
diff --git a/spec/ruby/core/thread/abort_on_exception_spec.rb b/spec/ruby/core/thread/abort_on_exception_spec.rb
index 49be84ea9f..aeca50e5c1 100644
--- a/spec/ruby/core/thread/abort_on_exception_spec.rb
+++ b/spec/ruby/core/thread/abort_on_exception_spec.rb
@@ -13,12 +13,12 @@ describe "Thread#abort_on_exception" do
end
it "is false by default" do
- @thread.abort_on_exception.should be_false
+ @thread.abort_on_exception.should == false
end
it "returns true when #abort_on_exception= is passed true" do
@thread.abort_on_exception = true
- @thread.abort_on_exception.should be_true
+ @thread.abort_on_exception.should == true
end
end
@@ -39,7 +39,7 @@ describe :thread_abort_on_exception, shared: true do
ThreadSpecs.state = :run
# Wait for the main thread to be interrupted
sleep
- end.should raise_error(RuntimeError, "Thread#abort_on_exception= specs")
+ end.should.raise(RuntimeError, "Thread#abort_on_exception= specs")
ScratchPad << :after
rescue Exception => e
@@ -81,7 +81,7 @@ describe "Thread.abort_on_exception" do
it "returns true when .abort_on_exception= is passed true" do
Thread.abort_on_exception = true
- Thread.abort_on_exception.should be_true
+ Thread.abort_on_exception.should == true
end
end
diff --git a/spec/ruby/core/thread/allocate_spec.rb b/spec/ruby/core/thread/allocate_spec.rb
index cfd556812f..0b4e4f1b1f 100644
--- a/spec/ruby/core/thread/allocate_spec.rb
+++ b/spec/ruby/core/thread/allocate_spec.rb
@@ -4,6 +4,6 @@ describe "Thread.allocate" do
it "raises a TypeError" do
-> {
Thread.allocate
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
index 68a69049d9..6d9482f2ae 100644
--- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
@@ -42,7 +42,7 @@ describe 'Thread::Backtrace::Location#absolute_path' do
locations = ScratchPad.recorded
locations[0].absolute_path.should == path
# Make sure it's from the class body, not from the file top-level
- locations[0].label.should include 'MethodAddedAbsolutePath'
+ locations[0].label.should.include? 'MethodAddedAbsolutePath'
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
index e903c3e450..103c36b3a0 100644
--- a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
+++ b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
@@ -1,10 +1,26 @@
+# These are top-level def on purpose to test those cases
+
+def label_top_method = ThreadBacktraceLocationSpecs::LABEL.call
+
+def self.label_sdef_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call
+
+class << self
+ def label_sclass_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call
+end
+
module ThreadBacktraceLocationSpecs
MODULE_LOCATION = caller_locations(0) rescue nil
+ INSTANCE = Object.new.extend(self)
+ LABEL = -> { caller_locations(1, 1)[0].label }
def self.locations
caller_locations
end
+ def instance_method_location
+ caller_locations(0)
+ end
+
def self.method_location
caller_locations(0)
end
@@ -15,6 +31,12 @@ module ThreadBacktraceLocationSpecs
end
end
+ def instance_block_location
+ 1.times do
+ return caller_locations(0)
+ end
+ end
+
def self.locations_inside_nested_blocks
first_level_location = nil
second_level_location = nil
@@ -32,4 +54,86 @@ module ThreadBacktraceLocationSpecs
[first_level_location, second_level_location, third_level_location]
end
+
+ def instance_locations_inside_nested_block
+ loc = nil
+ 1.times do
+ 1.times do
+ loc = caller_locations(0)
+ end
+ end
+ loc
+ end
+
+ def original_method = LABEL.call
+ alias_method :aliased_method, :original_method
+
+ module M
+ class C
+ def regular_instance_method = LABEL.call
+
+ def self.sdef_class_method = LABEL.call
+
+ class << self
+ def sclass_method = LABEL.call
+
+ def block_in_sclass_method
+ -> {
+ -> { LABEL.call }.call
+ }.call
+ end
+ end
+ block_in_sclass_method
+ end
+ end
+
+ class M::D
+ def scoped_method = LABEL.call
+
+ def self.sdef_scoped_method = LABEL.call
+
+ class << self
+ def sclass_scoped_method = LABEL.call
+ end
+
+ module ::ThreadBacktraceLocationSpecs
+ def top = LABEL.call
+ end
+
+ class ::ThreadBacktraceLocationSpecs::Nested
+ def top_nested = LABEL.call
+
+ class C
+ def top_nested_c = LABEL.call
+ end
+ end
+ end
+
+ SOME_OBJECT = Object.new
+ SOME_OBJECT.instance_exec do
+ def unknown_def_singleton_method = LABEL.call
+
+ def self.unknown_sdef_singleton_method = LABEL.call
+ end
+
+ M.module_eval do
+ def module_eval_method = LABEL.call
+
+ def self.sdef_module_eval_method = LABEL.call
+ end
+
+ def ThreadBacktraceLocationSpecs.string_class_method = LABEL.call
+
+ module M
+ def ThreadBacktraceLocationSpecs.nested_class_method = LABEL.call
+ end
+
+ module M
+ module_function def mod_function = LABEL.call
+ end
+
+ expr = self
+ def expr.sdef_expression = LABEL.call
+
+ def expr.block_in_sdef_expression = -> { LABEL.call }.call
end
diff --git a/spec/ruby/core/thread/backtrace/location/inspect_spec.rb b/spec/ruby/core/thread/backtrace/location/inspect_spec.rb
index 20e477a5a6..4df88a2f33 100644
--- a/spec/ruby/core/thread/backtrace/location/inspect_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/inspect_spec.rb
@@ -8,6 +8,6 @@ describe 'Thread::Backtrace::Location#inspect' do
end
it 'converts the call frame to a String' do
- @frame.inspect.should include("#{__FILE__}:#{@line}:in ")
+ @frame.inspect.should.include?("#{__FILE__}:#{@line}:in ")
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/label_spec.rb b/spec/ruby/core/thread/backtrace/location/label_spec.rb
index 85ddccc8e3..5f6a7b73df 100644
--- a/spec/ruby/core/thread/backtrace/location/label_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/label_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe 'Thread::Backtrace::Location#label' do
it 'returns the base label of the call frame' do
- ThreadBacktraceLocationSpecs.locations[0].label.should include('<top (required)>')
+ ThreadBacktraceLocationSpecs.locations[0].label.should.include?('<top (required)>')
end
it 'returns the method name for a method location' do
@@ -15,7 +15,7 @@ describe 'Thread::Backtrace::Location#label' do
end
it 'returns the module name for a module location' do
- ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should include "ThreadBacktraceLocationSpecs"
+ ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should == "<module:ThreadBacktraceLocationSpecs>"
end
it 'includes the nesting level of a block as part of the location label' do
@@ -34,4 +34,194 @@ describe 'Thread::Backtrace::Location#label' do
main_label.should == "block in <main>\n"
required_label.should == "block in <top (required)>\n"
end
+
+ it "return the same name as the caller for eval" do
+ this = caller_locations(0)[0].label
+ eval("caller_locations(0)[0]").label.should == this
+
+ b = binding
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var1, 1)
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var2, 2)
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var2, 2)
+ eval("caller_locations(0)[0]", b).label.should == this
+ end
+
+ ruby_version_is "3.4" do
+ describe "is Module#method for" do
+ it "a core method defined natively" do
+ BasicObject.instance_method(:instance_exec).should_not.source_location
+ loc = nil
+ loc = instance_exec { caller_locations(1, 1)[0] }
+ loc.label.should == "BasicObject#instance_exec"
+ end
+
+ it "a core method defined in Ruby" do
+ Kernel.instance_method(:tap).should.source_location
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ end
+
+ it "an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_method_location[0].label.should == "ThreadBacktraceLocationSpecs#instance_method_location"
+ end
+
+ it "a block in an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_block_location[0].label.should == "block in ThreadBacktraceLocationSpecs#instance_block_location"
+ end
+
+ it "a nested block in an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_locations_inside_nested_block[0].label.should == "block (2 levels) in ThreadBacktraceLocationSpecs#instance_locations_inside_nested_block"
+ end
+
+ it "a method defined via module_exec" do
+ ThreadBacktraceLocationSpecs.module_exec do
+ def in_module_exec
+ caller_locations(0)
+ end
+ end
+ ThreadBacktraceLocationSpecs::INSTANCE.in_module_exec[0].label.should == "ThreadBacktraceLocationSpecs#in_module_exec"
+ end
+
+ it "a method defined via module_eval" do
+ ThreadBacktraceLocationSpecs.module_eval <<~RUBY
+ def in_module_eval
+ caller_locations(0)
+ end
+ RUBY
+ ThreadBacktraceLocationSpecs::INSTANCE.in_module_eval[0].label.should == "ThreadBacktraceLocationSpecs#in_module_eval"
+ end
+ end
+
+ describe "is Module.method for" do
+ it "a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.method_location[0].label.should == "ThreadBacktraceLocationSpecs.method_location"
+ end
+
+ it "a block in a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.block_location[0].label.should == "block in ThreadBacktraceLocationSpecs.block_location"
+ end
+
+ it "a nested block in a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.locations_inside_nested_blocks[2].label.should == "block (3 levels) in ThreadBacktraceLocationSpecs.locations_inside_nested_blocks"
+ end
+
+ it "a singleton method defined via def Const.method" do
+ def ThreadBacktraceLocationSpecs.def_singleton
+ caller_locations(0)
+ end
+ ThreadBacktraceLocationSpecs.def_singleton[0].label.should == "ThreadBacktraceLocationSpecs.def_singleton"
+ end
+ end
+
+ it "shows the original method name for an aliased method" do
+ ThreadBacktraceLocationSpecs::INSTANCE.aliased_method.should == "ThreadBacktraceLocationSpecs#original_method"
+ end
+
+ # A wide variety of cases.
+ # These show interesting cases when trying to determine the name statically/at parse time
+ describe "is correct for" do
+ base = ThreadBacktraceLocationSpecs
+
+ it "M::C#regular_instance_method" do
+ base::M::C.new.regular_instance_method.should == "#{base}::M::C#regular_instance_method"
+ end
+
+ it "M::C.sdef_class_method" do
+ base::M::C.sdef_class_method.should == "#{base}::M::C.sdef_class_method"
+ end
+
+ it "M::C.sclass_method" do
+ base::M::C.sclass_method.should == "#{base}::M::C.sclass_method"
+ end
+
+ it "M::C.block_in_sclass_method" do
+ base::M::C.block_in_sclass_method.should == "block (2 levels) in #{base}::M::C.block_in_sclass_method"
+ end
+
+ it "M::D#scoped_method" do
+ base::M::D.new.scoped_method.should == "#{base}::M::D#scoped_method"
+ end
+
+ it "M::D.sdef_scoped_method" do
+ base::M::D.sdef_scoped_method.should == "#{base}::M::D.sdef_scoped_method"
+ end
+
+ it "M::D.sclass_scoped_method" do
+ base::M::D.sclass_scoped_method.should == "#{base}::M::D.sclass_scoped_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs#top" do
+ ThreadBacktraceLocationSpecs::INSTANCE.top.should == "ThreadBacktraceLocationSpecs#top"
+ end
+
+ it "ThreadBacktraceLocationSpecs::Nested#top_nested" do
+ ThreadBacktraceLocationSpecs::Nested.new.top_nested.should == "ThreadBacktraceLocationSpecs::Nested#top_nested"
+ end
+
+ it "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c" do
+ ThreadBacktraceLocationSpecs::Nested::C.new.top_nested_c.should == "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c"
+ end
+
+ it "Object#label_top_method" do
+ label_top_method.should == "Object#label_top_method"
+ end
+
+ it "main.label_sdef_method_of_main" do
+ main = TOPLEVEL_BINDING.receiver
+ main.label_sdef_method_of_main.should == "label_sdef_method_of_main"
+ end
+
+ it "main.label_sclass_method_of_main" do
+ main = TOPLEVEL_BINDING.receiver
+ main.label_sclass_method_of_main.should == "label_sclass_method_of_main"
+ end
+
+ it "unknown_def_singleton_method" do
+ base::SOME_OBJECT.unknown_def_singleton_method.should == "unknown_def_singleton_method"
+ end
+
+ it "unknown_sdef_singleton_method" do
+ base::SOME_OBJECT.unknown_sdef_singleton_method.should == "unknown_sdef_singleton_method"
+ end
+
+ it "M#module_eval_method" do
+ Object.new.extend(base::M).module_eval_method.should == "#{base}::M#module_eval_method"
+ end
+
+ it "M.sdef_module_eval_method" do
+ base::M.sdef_module_eval_method.should == "#{base}::M.sdef_module_eval_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs.string_class_method" do
+ ThreadBacktraceLocationSpecs.string_class_method.should == "ThreadBacktraceLocationSpecs.string_class_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs.nested_class_method" do
+ ThreadBacktraceLocationSpecs.nested_class_method.should == "ThreadBacktraceLocationSpecs.nested_class_method"
+ end
+
+ it "M#mod_function" do
+ Object.new.extend(base::M).send(:mod_function).should == "#{base}::M#mod_function"
+ end
+
+ it "M.mod_function" do
+ base::M.mod_function.should == "#{base}::M.mod_function"
+ end
+
+ it "sdef_expression" do
+ base.sdef_expression.should == "#{base}.sdef_expression"
+ end
+
+ it "block_in_sdef_expression" do
+ base.block_in_sdef_expression.should == "block in #{base}.block_in_sdef_expression"
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/thread/backtrace/location/to_s_spec.rb b/spec/ruby/core/thread/backtrace/location/to_s_spec.rb
index 5911cdced0..983ce4c3f8 100644
--- a/spec/ruby/core/thread/backtrace/location/to_s_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/to_s_spec.rb
@@ -8,6 +8,6 @@ describe 'Thread::Backtrace::Location#to_s' do
end
it 'converts the call frame to a String' do
- @frame.to_s.should include("#{__FILE__}:#{@line}:in ")
+ @frame.to_s.should.include?("#{__FILE__}:#{@line}:in ")
end
end
diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb
index 09fe622e0d..28a488f311 100644
--- a/spec/ruby/core/thread/backtrace_locations_spec.rb
+++ b/spec/ruby/core/thread/backtrace_locations_spec.rb
@@ -3,20 +3,20 @@ require_relative '../../spec_helper'
describe "Thread#backtrace_locations" do
it "returns an Array" do
locations = Thread.current.backtrace_locations
- locations.should be_an_instance_of(Array)
- locations.should_not be_empty
+ locations.should.instance_of?(Array)
+ locations.should_not.empty?
end
it "sets each element to a Thread::Backtrace::Location" do
locations = Thread.current.backtrace_locations
- locations.each { |loc| loc.should be_an_instance_of(Thread::Backtrace::Location) }
+ locations.each { |loc| loc.should.instance_of?(Thread::Backtrace::Location) }
end
it "can be called on any Thread" do
locations = Thread.new { Thread.current.backtrace_locations }.value
- locations.should be_an_instance_of(Array)
- locations.should_not be_empty
- locations.each { |loc| loc.should be_an_instance_of(Thread::Backtrace::Location) }
+ locations.should.instance_of?(Array)
+ locations.should_not.empty?
+ locations.each { |loc| loc.should.instance_of?(Thread::Backtrace::Location) }
end
it "can be called with a number of locations to omit" do
diff --git a/spec/ruby/core/thread/backtrace_spec.rb b/spec/ruby/core/thread/backtrace_spec.rb
index 15bb29a349..770c300f06 100644
--- a/spec/ruby/core/thread/backtrace_spec.rb
+++ b/spec/ruby/core/thread/backtrace_spec.rb
@@ -12,7 +12,7 @@ describe "Thread#backtrace" do
Thread.pass while t.status && t.status != 'sleep'
backtrace = t.backtrace
- backtrace.should be_kind_of(Array)
+ backtrace.should.is_a?(Array)
backtrace.first.should =~ /[`'](?:Kernel#)?sleep'/
t.raise 'finish the thread'
@@ -30,7 +30,7 @@ describe "Thread#backtrace" do
backtrace = t.backtrace
t.kill
t.join
- backtrace.should be_kind_of(Array)
+ backtrace.should.is_a?(Array)
end
it "can be called with a number of locations to omit" do
diff --git a/spec/ruby/core/thread/current_spec.rb b/spec/ruby/core/thread/current_spec.rb
index f5ed1d95cd..f893f078ba 100644
--- a/spec/ruby/core/thread/current_spec.rb
+++ b/spec/ruby/core/thread/current_spec.rb
@@ -4,13 +4,13 @@ require_relative 'fixtures/classes'
describe "Thread.current" do
it "returns a thread" do
current = Thread.current
- current.should be_kind_of(Thread)
+ current.should.is_a?(Thread)
end
it "returns the current thread" do
t = Thread.new { Thread.current }
- t.value.should equal(t)
- Thread.current.should_not equal(t.value)
+ t.value.should.equal?(t)
+ Thread.current.should_not.equal?(t.value)
end
it "returns the correct thread in a Fiber" do
@@ -22,10 +22,10 @@ describe "Thread.current" do
cur = Thread.current
Fiber.new {
Thread.current
- }.resume.should equal cur
+ }.resume.should.equal? cur
cur
}
- t.value.should equal t
+ t.value.should.equal? t
end
end
end
diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb
index 29c271789b..15fda1a37b 100644
--- a/spec/ruby/core/thread/each_caller_location_spec.rb
+++ b/spec/ruby/core/thread/each_caller_location_spec.rb
@@ -1,49 +1,47 @@
require_relative '../../spec_helper'
describe "Thread.each_caller_location" do
- ruby_version_is "3.2" do
- it "iterates through the current execution stack and matches caller_locations content and type" do
- ScratchPad.record []
- Thread.each_caller_location { |l| ScratchPad << l; }
+ it "iterates through the current execution stack and matches caller_locations content and type" do
+ ScratchPad.record []
+ Thread.each_caller_location { |l| ScratchPad << l; }
- ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s)
- ScratchPad.recorded[0].should be_kind_of(Thread::Backtrace::Location)
- end
+ ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s)
+ ScratchPad.recorded[0].should.is_a?(Thread::Backtrace::Location)
+ end
- it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
- ar = []
- ecl = Thread.each_caller_location { |x| ar << x }
+ it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
+ ar = []
+ ecl = Thread.each_caller_location { |x| ar << x }
- (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty?
- end
+ (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty?
+ end
- it "stops the backtrace iteration if 'break' occurs" do
- i = 0
- ar = []
- ecl = Thread.each_caller_location do |x|
- ar << x
- i += 1
- break x if i == 2
- end
-
- ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
- ecl.should be_kind_of(Thread::Backtrace::Location)
+ it "stops the backtrace iteration if 'break' occurs" do
+ i = 0
+ ar = []
+ ecl = Thread.each_caller_location do |x|
+ ar << x
+ i += 1
+ break x if i == 2
end
- it "returns nil" do
- Thread.each_caller_location {}.should == nil
- end
+ ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
+ ecl.should.is_a?(Thread::Backtrace::Location)
+ end
- it "raises LocalJumpError when called without a block" do
- -> {
- Thread.each_caller_location
- }.should raise_error(LocalJumpError, "no block given")
- end
+ it "returns nil" do
+ Thread.each_caller_location {}.should == nil
+ end
- it "doesn't accept keyword arguments" do
- -> {
- Thread.each_caller_location(12, foo: 10) {}
- }.should raise_error(ArgumentError);
- end
+ it "raises LocalJumpError when called without a block" do
+ -> {
+ Thread.each_caller_location
+ }.should.raise(LocalJumpError, "no block given")
+ end
+
+ it "doesn't accept keyword arguments" do
+ -> {
+ Thread.each_caller_location(12, foo: 10) {}
+ }.should.raise(ArgumentError);
end
end
diff --git a/spec/ruby/core/thread/element_reference_spec.rb b/spec/ruby/core/thread/element_reference_spec.rb
index fde9d1f440..72892f6c50 100644
--- a/spec/ruby/core/thread/element_reference_spec.rb
+++ b/spec/ruby/core/thread/element_reference_spec.rb
@@ -49,7 +49,7 @@ describe "Thread#[]" do
end
it "raises exceptions on the wrong type of keys" do
- -> { Thread.current[nil] }.should raise_error(TypeError)
- -> { Thread.current[5] }.should raise_error(TypeError)
+ -> { Thread.current[nil] }.should.raise(TypeError)
+ -> { Thread.current[5] }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/thread/element_set_spec.rb b/spec/ruby/core/thread/element_set_spec.rb
index f205177304..97d6c23980 100644
--- a/spec/ruby/core/thread/element_set_spec.rb
+++ b/spec/ruby/core/thread/element_set_spec.rb
@@ -12,7 +12,7 @@ describe "Thread#[]=" do
th.freeze
-> {
th[:foo] = "bar"
- }.should raise_error(FrozenError, "can't modify frozen thread locals")
+ }.should.raise(FrozenError, "can't modify frozen thread locals")
end.join
end
@@ -40,8 +40,8 @@ describe "Thread#[]=" do
end
it "raises exceptions on the wrong type of keys" do
- -> { Thread.current[nil] = true }.should raise_error(TypeError)
- -> { Thread.current[5] = true }.should raise_error(TypeError)
+ -> { Thread.current[nil] = true }.should.raise(TypeError)
+ -> { Thread.current[5] = true }.should.raise(TypeError)
end
it "is not shared across fibers" do
@@ -51,7 +51,7 @@ describe "Thread#[]=" do
Thread.current[:value].should == 1
end
fib.resume
- Thread.current[:value].should be_nil
+ Thread.current[:value].should == nil
Thread.current[:value] = 2
fib.resume
Thread.current[:value] = 2
diff --git a/spec/ruby/core/thread/exit_spec.rb b/spec/ruby/core/thread/exit_spec.rb
index c3f710920e..b2e923c680 100644
--- a/spec/ruby/core/thread/exit_spec.rb
+++ b/spec/ruby/core/thread/exit_spec.rb
@@ -10,6 +10,6 @@ describe "Thread.exit" do
it "causes the current thread to exit" do
thread = Thread.new { Thread.exit; sleep }
thread.join
- thread.status.should be_false
+ thread.status.should == false
end
end
diff --git a/spec/ruby/core/thread/fetch_spec.rb b/spec/ruby/core/thread/fetch_spec.rb
index 85ffb71874..fe27dec4a2 100644
--- a/spec/ruby/core/thread/fetch_spec.rb
+++ b/spec/ruby/core/thread/fetch_spec.rb
@@ -19,7 +19,7 @@ describe 'Thread#fetch' do
it 'raises a KeyError when the Thread does not have a fiber-local variable of the same name' do
th = Thread.new {}
th.join
- -> { th.fetch(:cat) }.should raise_error(KeyError)
+ -> { th.fetch(:cat) }.should.raise(KeyError)
end
it 'returns the value of the fiber-local variable if value has been assigned' do
@@ -60,7 +60,7 @@ describe 'Thread#fetch' do
end
it 'raises an ArgumentError when not passed one or two arguments' do
- -> { Thread.current.fetch() }.should raise_error(ArgumentError)
- -> { Thread.current.fetch(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { Thread.current.fetch() }.should.raise(ArgumentError)
+ -> { Thread.current.fetch(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/thread/fixtures/classes.rb b/spec/ruby/core/thread/fixtures/classes.rb
index 23a090feb0..14d5d2f7bf 100644
--- a/spec/ruby/core/thread/fixtures/classes.rb
+++ b/spec/ruby/core/thread/fixtures/classes.rb
@@ -6,6 +6,31 @@ module ThreadSpecs
end
end
+ class NewThreadToRaise
+ def self.raise(*args, **kwargs, &block)
+ thread = Thread.new do
+ Thread.current.report_on_exception = false
+
+ if block_given?
+ block.call do
+ sleep
+ end
+ else
+ sleep
+ end
+ end
+
+ Thread.pass until thread.stop?
+
+ thread.raise(*args, **kwargs)
+
+ thread.join
+ ensure
+ thread.kill if thread.alive?
+ Thread.pass while thread.alive? # Thread#kill may not terminate a thread immediately so it may be detected as a leaked one
+ end
+ end
+
class Status
attr_reader :thread, :inspect, :status, :to_s
def initialize(thread)
@@ -182,7 +207,7 @@ module ThreadSpecs
def self.join_dying_thread_with_outer_ensure(kill_method_name=:kill)
t = dying_thread_with_outer_ensure(kill_method_name) { yield }
- -> { t.join }.should raise_error(RuntimeError, "In dying thread")
+ -> { t.join }.should.raise(RuntimeError, "In dying thread")
return t
end
diff --git a/spec/ruby/core/thread/handle_interrupt_spec.rb b/spec/ruby/core/thread/handle_interrupt_spec.rb
index ea7e81cb98..aa03d4c66d 100644
--- a/spec/ruby/core/thread/handle_interrupt_spec.rb
+++ b/spec/ruby/core/thread/handle_interrupt_spec.rb
@@ -75,7 +75,7 @@ describe "Thread.handle_interrupt" do
Thread.handle_interrupt(RuntimeError => :immediate) {
flunk "not reached"
}
- }.should raise_error(RuntimeError, "interrupt immediate")
+ }.should.raise(RuntimeError, "interrupt immediate")
Thread.pending_interrupt?.should == false
end
end
@@ -95,7 +95,7 @@ describe "Thread.handle_interrupt" do
Thread.handle_interrupt(RuntimeError => :immediate) {
flunk "not reached"
}
- }.should raise_error(RuntimeError, "interrupt with fibers")
+ }.should.raise(RuntimeError, "interrupt with fibers")
Thread.pending_interrupt?.should == false
end
@@ -115,7 +115,7 @@ describe "Thread.handle_interrupt" do
executed = true
raise "regular exception"
end
- }.should raise_error(RuntimeError, "interrupt exception")
+ }.should.raise(RuntimeError, "interrupt exception")
executed.should == true
end
diff --git a/spec/ruby/core/thread/initialize_spec.rb b/spec/ruby/core/thread/initialize_spec.rb
index 4fca900cd8..b9a94560ee 100644
--- a/spec/ruby/core/thread/initialize_spec.rb
+++ b/spec/ruby/core/thread/initialize_spec.rb
@@ -19,7 +19,7 @@ describe "Thread#initialize" do
@t.instance_eval do
initialize {}
end
- }.should raise_error(ThreadError)
+ }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/thread/join_spec.rb b/spec/ruby/core/thread/join_spec.rb
index 213fe2e505..f4332167f1 100644
--- a/spec/ruby/core/thread/join_spec.rb
+++ b/spec/ruby/core/thread/join_spec.rb
@@ -4,28 +4,28 @@ require_relative 'fixtures/classes'
describe "Thread#join" do
it "returns the thread when it is finished" do
t = Thread.new {}
- t.join.should equal(t)
+ t.join.should.equal?(t)
end
it "returns the thread when it is finished when given a timeout" do
t = Thread.new {}
t.join
- t.join(0).should equal(t)
+ t.join(0).should.equal?(t)
end
it "coerces timeout to a Float if it is not nil" do
t = Thread.new {}
t.join
- t.join(0).should equal(t)
- t.join(0.0).should equal(t)
- t.join(nil).should equal(t)
+ t.join(0).should.equal?(t)
+ t.join(0.0).should.equal?(t)
+ t.join(nil).should.equal?(t)
end
it "raises TypeError if the argument is not a valid timeout" do
t = Thread.new { }
t.join
- -> { t.join(:foo) }.should raise_error TypeError
- -> { t.join("bar") }.should raise_error TypeError
+ -> { t.join(:foo) }.should.raise TypeError
+ -> { t.join("bar") }.should.raise TypeError
end
it "returns nil if it is not finished when given a timeout" do
@@ -55,16 +55,16 @@ describe "Thread#join" do
Thread.current.report_on_exception = false
raise NotImplementedError.new("Just kidding")
}
- -> { t.join }.should raise_error(NotImplementedError)
+ -> { t.join }.should.raise(NotImplementedError)
end
it "returns the dead thread" do
t = Thread.new { Thread.current.kill }
- t.join.should equal(t)
+ t.join.should.equal?(t)
end
it "raises any uncaught exception encountered in ensure block" do
t = ThreadSpecs.dying_thread_ensures { raise NotImplementedError.new("Just kidding") }
- -> { t.join }.should raise_error(NotImplementedError)
+ -> { t.join }.should.raise(NotImplementedError)
end
end
diff --git a/spec/ruby/core/thread/key_spec.rb b/spec/ruby/core/thread/key_spec.rb
index 339fa98f53..a14aeb8d31 100644
--- a/spec/ruby/core/thread/key_spec.rb
+++ b/spec/ruby/core/thread/key_spec.rb
@@ -24,30 +24,30 @@ describe "Thread#key?" do
end
it "raises exceptions on the wrong type of keys" do
- -> { Thread.current.key? nil }.should raise_error(TypeError)
- -> { Thread.current.key? 5 }.should raise_error(TypeError)
+ -> { Thread.current.key? nil }.should.raise(TypeError)
+ -> { Thread.current.key? 5 }.should.raise(TypeError)
end
it "is not shared across fibers" do
fib = Fiber.new do
Thread.current[:val1] = 1
Fiber.yield
- Thread.current.key?(:val1).should be_true
- Thread.current.key?(:val2).should be_false
+ Thread.current.key?(:val1).should == true
+ Thread.current.key?(:val2).should == false
end
- Thread.current.key?(:val1).should_not be_true
+ Thread.current.key?(:val1).should_not == true
fib.resume
Thread.current[:val2] = 2
fib.resume
- Thread.current.key?(:val1).should be_false
- Thread.current.key?(:val2).should be_true
+ Thread.current.key?(:val1).should == false
+ Thread.current.key?(:val2).should == true
end
it "stores a local in another thread when in a fiber" do
fib = Fiber.new do
t = Thread.new do
sleep
- Thread.current.key?(:value).should be_true
+ Thread.current.key?(:value).should == true
end
Thread.pass while t.status and t.status != "sleep"
diff --git a/spec/ruby/core/thread/keys_spec.rb b/spec/ruby/core/thread/keys_spec.rb
index 15efda51d6..3a2edd2456 100644
--- a/spec/ruby/core/thread/keys_spec.rb
+++ b/spec/ruby/core/thread/keys_spec.rb
@@ -16,22 +16,22 @@ describe "Thread#keys" do
fib = Fiber.new do
Thread.current[:val1] = 1
Fiber.yield
- Thread.current.keys.should include(:val1)
- Thread.current.keys.should_not include(:val2)
+ Thread.current.keys.should.include?(:val1)
+ Thread.current.keys.should_not.include?(:val2)
end
- Thread.current.keys.should_not include(:val1)
+ Thread.current.keys.should_not.include?(:val1)
fib.resume
Thread.current[:val2] = 2
fib.resume
- Thread.current.keys.should include(:val2)
- Thread.current.keys.should_not include(:val1)
+ Thread.current.keys.should.include?(:val2)
+ Thread.current.keys.should_not.include?(:val1)
end
it "stores a local in another thread when in a fiber" do
fib = Fiber.new do
t = Thread.new do
sleep
- Thread.current.keys.should include(:value)
+ Thread.current.keys.should.include?(:value)
end
Thread.pass while t.status and t.status != "sleep"
diff --git a/spec/ruby/core/thread/kill_spec.rb b/spec/ruby/core/thread/kill_spec.rb
index 4b62c686c7..f9f1f46744 100644
--- a/spec/ruby/core/thread/kill_spec.rb
+++ b/spec/ruby/core/thread/kill_spec.rb
@@ -15,7 +15,7 @@ platform_is_not :mingw do
Thread.pass while thread.status and thread.status != "sleep"
Thread.kill(thread).should == thread
thread.join
- thread.status.should be_false
+ thread.status.should == false
end
end
end
diff --git a/spec/ruby/core/thread/list_spec.rb b/spec/ruby/core/thread/list_spec.rb
index 3c6f70c13e..5036841d58 100644
--- a/spec/ruby/core/thread/list_spec.rb
+++ b/spec/ruby/core/thread/list_spec.rb
@@ -3,15 +3,15 @@ require_relative 'fixtures/classes'
describe "Thread.list" do
it "includes the current and main thread" do
- Thread.list.should include(Thread.current)
- Thread.list.should include(Thread.main)
+ Thread.list.should.include?(Thread.current)
+ Thread.list.should.include?(Thread.main)
end
it "includes threads of non-default thread groups" do
t = Thread.new { sleep }
begin
ThreadGroup.new.add(t)
- Thread.list.should include(t)
+ Thread.list.should.include?(t)
ensure
t.kill
t.join
@@ -21,7 +21,7 @@ describe "Thread.list" do
it "does not include deceased threads" do
t = Thread.new { 1; }
t.join
- Thread.list.should_not include(t)
+ Thread.list.should_not.include?(t)
end
it "includes waiting threads" do
@@ -29,7 +29,7 @@ describe "Thread.list" do
t = Thread.new { q.pop }
begin
Thread.pass while t.status and t.status != 'sleep'
- Thread.list.should include(t)
+ Thread.list.should.include?(t)
ensure
q << nil
t.join
@@ -45,7 +45,7 @@ describe "Thread.list" do
begin
Thread.list.each { |th|
- th.should be_kind_of(Thread)
+ th.should.is_a?(Thread)
}
end while spawner.alive?
diff --git a/spec/ruby/core/thread/name_spec.rb b/spec/ruby/core/thread/name_spec.rb
index 9b3d2f4b09..47d807be4d 100644
--- a/spec/ruby/core/thread/name_spec.rb
+++ b/spec/ruby/core/thread/name_spec.rb
@@ -36,7 +36,7 @@ describe "Thread#name=" do
it "raises an ArgumentError if the name includes a null byte" do
-> {
@thread.name = "new thread\0name"
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "can be reset to nil" do
diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb
index 374cc59279..cc72e0b853 100644
--- a/spec/ruby/core/thread/native_thread_id_spec.rb
+++ b/spec/ruby/core/thread/native_thread_id_spec.rb
@@ -3,7 +3,7 @@ require_relative '../../spec_helper'
platform_is :linux, :darwin, :windows, :freebsd do
describe "Thread#native_thread_id" do
it "returns an integer when the thread is alive" do
- Thread.current.native_thread_id.should be_kind_of(Integer)
+ Thread.current.native_thread_id.should.is_a?(Integer)
end
it "returns nil when the thread is not running" do
@@ -18,12 +18,8 @@ platform_is :linux, :darwin, :windows, :freebsd do
main_thread_id = Thread.current.native_thread_id
t_thread_id = t.native_thread_id
- if ruby_version_is "3.3"
- # native_thread_id can be nil on a M:N scheduler
- t_thread_id.should be_kind_of(Integer) if t_thread_id != nil
- else
- t_thread_id.should be_kind_of(Integer)
- end
+ # native_thread_id can be nil on a M:N scheduler
+ t_thread_id.should.is_a?(Integer) if t_thread_id != nil
main_thread_id.should_not == t_thread_id
diff --git a/spec/ruby/core/thread/new_spec.rb b/spec/ruby/core/thread/new_spec.rb
index 47a836201c..acb6cd4e30 100644
--- a/spec/ruby/core/thread/new_spec.rb
+++ b/spec/ruby/core/thread/new_spec.rb
@@ -18,7 +18,7 @@ describe "Thread.new" do
end
it "raises an exception when not given a block" do
- -> { Thread.new }.should raise_error(ThreadError)
+ -> { Thread.new }.should.raise(ThreadError)
end
it "creates a subclass of thread calls super with a block in initialize" do
@@ -36,7 +36,7 @@ describe "Thread.new" do
-> {
c.new
- }.should raise_error(ThreadError)
+ }.should.raise(ThreadError)
end
it "calls and respects #initialize for the block to use" do
diff --git a/spec/ruby/core/thread/pending_interrupt_spec.rb b/spec/ruby/core/thread/pending_interrupt_spec.rb
index cd565d92a4..5fbe7422a9 100644
--- a/spec/ruby/core/thread/pending_interrupt_spec.rb
+++ b/spec/ruby/core/thread/pending_interrupt_spec.rb
@@ -19,7 +19,7 @@ describe "Thread.pending_interrupt?" do
Thread.pending_interrupt?.should == true
executed = true
end
- }.should raise_error(RuntimeError, "interrupt")
+ }.should.raise(RuntimeError, "interrupt")
executed.should == true
Thread.pending_interrupt?.should == false
end
diff --git a/spec/ruby/core/thread/priority_spec.rb b/spec/ruby/core/thread/priority_spec.rb
index e13ad478b5..970f7f9971 100644
--- a/spec/ruby/core/thread/priority_spec.rb
+++ b/spec/ruby/core/thread/priority_spec.rb
@@ -15,19 +15,19 @@ describe "Thread#priority" do
end
it "inherits the priority of the current thread while running" do
- @thread.alive?.should be_true
+ @thread.alive?.should == true
@thread.priority.should == @current_priority
end
it "maintain the priority of the current thread after death" do
ThreadSpecs.state = :exit
@thread.join
- @thread.alive?.should be_false
+ @thread.alive?.should == false
@thread.priority.should == @current_priority
end
it "returns an integer" do
- @thread.priority.should be_kind_of(Integer)
+ @thread.priority.should.is_a?(Integer)
end
end
@@ -59,7 +59,7 @@ describe "Thread#priority=" do
describe "when set with a non-integer" do
it "raises a type error" do
- ->{ @thread.priority = Object.new }.should raise_error(TypeError)
+ ->{ @thread.priority = Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 49323cf270..efc09d4a35 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -3,6 +3,16 @@ require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
describe "Thread#raise" do
+ it "is a public method" do
+ Thread.public_instance_methods.should.include?(:raise)
+ end
+
+ it_behaves_like :kernel_raise, :raise, ThreadSpecs::NewThreadToRaise
+ it_behaves_like :kernel_raise_across_contexts, :raise, ThreadSpecs::NewThreadToRaise
+ ruby_version_is "4.0" do
+ it_behaves_like :kernel_raise_with_cause, :raise, ThreadSpecs::NewThreadToRaise
+ end
+
it "ignores dead threads and returns nil" do
t = Thread.new { :dead }
Thread.pass while t.alive?
@@ -26,27 +36,27 @@ describe "Thread#raise on a sleeping thread" do
it "raises a RuntimeError if no exception class is given" do
@thr.raise
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(RuntimeError)
+ ScratchPad.recorded.should.is_a?(RuntimeError)
end
it "raises the given exception" do
@thr.raise Exception
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
end
it "raises the given exception with the given message" do
@thr.raise Exception, "get to work"
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
ScratchPad.recorded.message.should == "get to work"
end
it "raises the given exception and the backtrace is the one of the interrupted thread" do
@thr.raise Exception
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
- ScratchPad.recorded.backtrace[0].should include("sleep")
+ ScratchPad.recorded.should.is_a?(Exception)
+ ScratchPad.recorded.backtrace[0].should.include?("sleep")
end
it "is captured and raised by Thread#value" do
@@ -58,7 +68,7 @@ describe "Thread#raise on a sleeping thread" do
ThreadSpecs.spin_until_sleeping(t)
t.raise
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
it "raises a RuntimeError when called with no arguments inside rescue" do
@@ -76,7 +86,7 @@ describe "Thread#raise on a sleeping thread" do
ThreadSpecs.spin_until_sleeping(t)
t.raise
end
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
it "re-raises a previously rescued exception without overwriting the backtrace" do
@@ -98,8 +108,8 @@ describe "Thread#raise on a sleeping thread" do
raise_again_line = __LINE__; t.raise raised
raised_again = t.value
- raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:")
- raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
+ raised_again.backtrace.first.should.include?("#{__FILE__}:#{initial_raise_line}:")
+ raised_again.backtrace.first.should_not.include?("#{__FILE__}:#{raise_again_line}:")
end
end
@@ -126,6 +136,31 @@ describe "Thread#raise on a sleeping thread" do
[ScratchPad.recorded, @thr, []]
]
end
+
+ it "calls #set_backtrace only in the caller thread" do
+ cls = Class.new(Exception) do
+ attr_accessor :log
+ def initialize(*args)
+ @log = [] # This is shared because the super #exception uses a shallow clone
+ super
+ end
+
+ def set_backtrace(backtrace)
+ @log << [Thread.current, backtrace]
+ super
+ end
+ end
+ exc = cls.new
+
+ backtrace = ["a.rb:1"]
+
+ @thr.raise exc, "Thread#raise #set_backtrace spec", backtrace
+ @thr.join
+ ScratchPad.recorded.should.is_a?(cls)
+ exc.log.should == [
+ [Thread.current, backtrace]
+ ]
+ end
end
describe "Thread#raise on a running thread" do
@@ -145,19 +180,19 @@ describe "Thread#raise on a running thread" do
it "raises a RuntimeError if no exception class is given" do
@thr.raise
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(RuntimeError)
+ ScratchPad.recorded.should.is_a?(RuntimeError)
end
it "raises the given exception" do
@thr.raise Exception
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
end
it "raises the given exception with the given message" do
@thr.raise Exception, "get to work"
Thread.pass while @thr.status
- ScratchPad.recorded.should be_kind_of(Exception)
+ ScratchPad.recorded.should.is_a?(Exception)
ScratchPad.recorded.message.should == "get to work"
end
@@ -171,7 +206,7 @@ describe "Thread#raise on a running thread" do
q.pop # wait for `report_on_exception = false`.
t.raise
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
it "raises the given argument even when there is an active exception" do
@@ -190,7 +225,7 @@ describe "Thread#raise on a running thread" do
rescue
Thread.pass until raised
t.raise RangeError
- -> { t.value }.should raise_error(RangeError)
+ -> { t.value }.should.raise(RangeError)
end
end
@@ -211,7 +246,7 @@ describe "Thread#raise on a running thread" do
Thread.pass until raised
t.raise
end
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should.raise(RuntimeError)
end
end
@@ -227,6 +262,6 @@ describe "Thread#raise on same thread" do
Thread.current.raise
end
end
- -> { t.value }.should raise_error(RuntimeError, '')
+ -> { t.value }.should.raise(RuntimeError, '')
end
end
diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb
index d9daa041cd..9cf5260808 100644
--- a/spec/ruby/core/thread/report_on_exception_spec.rb
+++ b/spec/ruby/core/thread/report_on_exception_spec.rb
@@ -58,7 +58,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
end
it "prints a backtrace on $stderr in the regular backtrace order" do
@@ -86,7 +86,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs backtrace order")
end
it "prints the backtrace even if the thread was killed just after Thread#raise" do
@@ -107,7 +107,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception before kill spec")
+ }.should.raise(RuntimeError, "Thread#report_on_exception before kill spec")
end
end
@@ -124,7 +124,7 @@ describe "Thread#report_on_exception=" do
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
end
end
@@ -144,12 +144,12 @@ describe "Thread#report_on_exception=" do
-> {
mutex.sleep(5)
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
}.should output("", /Thread.+terminated with exception.+Thread#report_on_exception specs/m)
-> {
t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should.raise(RuntimeError, "Thread#report_on_exception specs")
end
end
end
diff --git a/spec/ruby/core/thread/shared/exit.rb b/spec/ruby/core/thread/shared/exit.rb
index 13e8832684..a294c3a4d6 100644
--- a/spec/ruby/core/thread/shared/exit.rb
+++ b/spec/ruby/core/thread/shared/exit.rb
@@ -56,8 +56,8 @@ describe :thread_exit, shared: true do
Thread.pass while @inner.status and @inner.status != "sleep"
@outer.send(@method)
@outer.join
- ScratchPad.recorded.should include(:inner_ensure_clause)
- ScratchPad.recorded.should include(:outer_ensure_clause)
+ ScratchPad.recorded.should.include?(:inner_ensure_clause)
+ ScratchPad.recorded.should.include?(:outer_ensure_clause)
end
it "does not set $!" do
@@ -155,7 +155,7 @@ describe :thread_exit, shared: true do
it "propagates inner exception to Thread.join if there is an outer ensure clause" do
thread = ThreadSpecs.dying_thread_with_outer_ensure(@method) { }
- -> { thread.join }.should raise_error(RuntimeError, "In dying thread")
+ -> { thread.join }.should.raise(RuntimeError, "In dying thread")
end
it "runs all outer ensure clauses even if inner ensure clause raises exception" do
diff --git a/spec/ruby/core/thread/shared/start.rb b/spec/ruby/core/thread/shared/start.rb
index 2ba926bf00..c5d62ab098 100644
--- a/spec/ruby/core/thread/shared/start.rb
+++ b/spec/ruby/core/thread/shared/start.rb
@@ -6,22 +6,22 @@ describe :thread_start, shared: true do
it "raises an ArgumentError if not passed a block" do
-> {
Thread.send(@method)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "spawns a new Thread running the block" do
run = false
t = Thread.send(@method) { run = true }
- t.should be_kind_of(Thread)
+ t.should.is_a?(Thread)
t.join
- run.should be_true
+ run.should == true
end
it "respects Thread subclasses" do
c = Class.new(Thread)
t = c.send(@method) { }
- t.should be_kind_of(c)
+ t.should.is_a?(c)
t.join
end
diff --git a/spec/ruby/core/thread/shared/to_s.rb b/spec/ruby/core/thread/shared/to_s.rb
index 43640deb33..27e53ba4b8 100644
--- a/spec/ruby/core/thread/shared/to_s.rb
+++ b/spec/ruby/core/thread/shared/to_s.rb
@@ -12,42 +12,42 @@ describe :thread_to_s, shared: true do
end
it "can check it's own status" do
- ThreadSpecs.status_of_current_thread.send(@method).should include('run')
+ ThreadSpecs.status_of_current_thread.send(@method).should.include?('run')
end
it "describes a running thread" do
- ThreadSpecs.status_of_running_thread.send(@method).should include('run')
+ ThreadSpecs.status_of_running_thread.send(@method).should.include?('run')
end
it "describes a sleeping thread" do
- ThreadSpecs.status_of_sleeping_thread.send(@method).should include('sleep')
+ ThreadSpecs.status_of_sleeping_thread.send(@method).should.include?('sleep')
end
it "describes a blocked thread" do
- ThreadSpecs.status_of_blocked_thread.send(@method).should include('sleep')
+ ThreadSpecs.status_of_blocked_thread.send(@method).should.include?('sleep')
end
it "describes a completed thread" do
- ThreadSpecs.status_of_completed_thread.send(@method).should include('dead')
+ ThreadSpecs.status_of_completed_thread.send(@method).should.include?('dead')
end
it "describes a killed thread" do
- ThreadSpecs.status_of_killed_thread.send(@method).should include('dead')
+ ThreadSpecs.status_of_killed_thread.send(@method).should.include?('dead')
end
it "describes a thread with an uncaught exception" do
- ThreadSpecs.status_of_thread_with_uncaught_exception.send(@method).should include('dead')
+ ThreadSpecs.status_of_thread_with_uncaught_exception.send(@method).should.include?('dead')
end
it "describes a dying sleeping thread" do
- ThreadSpecs.status_of_dying_sleeping_thread.send(@method).should include('sleep')
+ ThreadSpecs.status_of_dying_sleeping_thread.send(@method).should.include?('sleep')
end
it "reports aborting on a killed thread" do
- ThreadSpecs.status_of_dying_running_thread.send(@method).should include('aborting')
+ ThreadSpecs.status_of_dying_running_thread.send(@method).should.include?('aborting')
end
it "reports aborting on a killed thread after sleep" do
- ThreadSpecs.status_of_dying_thread_after_sleep.send(@method).should include('aborting')
+ ThreadSpecs.status_of_dying_thread_after_sleep.send(@method).should.include?('aborting')
end
end
diff --git a/spec/ruby/core/thread/shared/wakeup.rb b/spec/ruby/core/thread/shared/wakeup.rb
index 6f010fea25..c89235ba60 100644
--- a/spec/ruby/core/thread/shared/wakeup.rb
+++ b/spec/ruby/core/thread/shared/wakeup.rb
@@ -57,6 +57,6 @@ describe :thread_wakeup, shared: true do
it "raises a ThreadError when trying to wake up a dead thread" do
t = Thread.new { 1 }
t.join
- -> { t.send @method }.should raise_error(ThreadError)
+ -> { t.send @method }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/thread/thread_variable_get_spec.rb b/spec/ruby/core/thread/thread_variable_get_spec.rb
index 1ea34cf2b3..3d92cd5479 100644
--- a/spec/ruby/core/thread/thread_variable_get_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_get_spec.rb
@@ -10,7 +10,7 @@ describe "Thread#thread_variable_get" do
end
it "returns nil if the variable is not set" do
- @t.thread_variable_get(:a).should be_nil
+ @t.thread_variable_get(:a).should == nil
end
it "returns the value previously set by #thread_variable_set" do
@@ -20,7 +20,7 @@ describe "Thread#thread_variable_get" do
it "returns a value private to self" do
@t.thread_variable_set(:thread_variable_get_spec, 82)
- Thread.current.thread_variable_get(:thread_variable_get_spec).should be_nil
+ Thread.current.thread_variable_get(:thread_variable_get_spec).should == nil
end
it "accepts String and Symbol keys interchangeably" do
@@ -38,23 +38,23 @@ describe "Thread#thread_variable_get" do
it "does not raise FrozenError if the thread is frozen" do
@t.freeze
- @t.thread_variable_get(:a).should be_nil
+ @t.thread_variable_get(:a).should == nil
end
it "raises a TypeError if the key is neither Symbol nor String when thread variables are already set" do
@t.thread_variable_set(:a, 49)
- -> { @t.thread_variable_get(123) }.should raise_error(TypeError, /123 is not a symbol/)
+ -> { @t.thread_variable_get(123) }.should.raise(TypeError, /123 is not a symbol/)
end
ruby_version_is '3.4' do
it "raises a TypeError if the key is neither Symbol nor String when no thread variables are set" do
- -> { @t.thread_variable_get(123) }.should raise_error(TypeError, /123 is not a symbol/)
+ -> { @t.thread_variable_get(123) }.should.raise(TypeError, /123 is not a symbol/)
end
it "raises a TypeError if the key is neither Symbol nor String without calling #to_sym" do
key = mock('key')
key.should_not_receive(:to_sym)
- -> { @t.thread_variable_get(key) }.should raise_error(TypeError, /#{Regexp.escape(key.inspect)} is not a symbol/)
+ -> { @t.thread_variable_get(key) }.should.raise(TypeError, /#{Regexp.escape(key.inspect)} is not a symbol/)
end
end
end
diff --git a/spec/ruby/core/thread/thread_variable_set_spec.rb b/spec/ruby/core/thread/thread_variable_set_spec.rb
index eadee76afb..f8d25364ae 100644
--- a/spec/ruby/core/thread/thread_variable_set_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_set_spec.rb
@@ -21,7 +21,7 @@ describe "Thread#thread_variable_set" do
it "sets a value private to self" do
@t.thread_variable_set(:thread_variable_get_spec, 82)
@t.thread_variable_get(:thread_variable_get_spec).should == 82
- Thread.current.thread_variable_get(:thread_variable_get_spec).should be_nil
+ Thread.current.thread_variable_get(:thread_variable_get_spec).should == nil
end
it "accepts String and Symbol keys interchangeably" do
@@ -42,21 +42,21 @@ describe "Thread#thread_variable_set" do
it "removes a key if the value is nil" do
@t.thread_variable_set(:a, 52)
@t.thread_variable_set(:a, nil)
- @t.thread_variable?(:a).should be_false
+ @t.thread_variable?(:a).should == false
end
it "raises a FrozenError if the thread is frozen" do
@t.freeze
- -> { @t.thread_variable_set(:a, 1) }.should raise_error(FrozenError, "can't modify frozen thread locals")
+ -> { @t.thread_variable_set(:a, 1) }.should.raise(FrozenError, "can't modify frozen thread locals")
end
it "raises a TypeError if the key is neither Symbol nor String, nor responds to #to_str" do
- -> { @t.thread_variable_set(123, 1) }.should raise_error(TypeError, /123 is not a symbol/)
+ -> { @t.thread_variable_set(123, 1) }.should.raise(TypeError, /123 is not a symbol/)
end
it "does not try to convert the key with #to_sym" do
key = mock('key')
key.should_not_receive(:to_sym)
- -> { @t.thread_variable_set(key, 42) }.should raise_error(TypeError, /#{Regexp.quote(key.inspect)} is not a symbol/)
+ -> { @t.thread_variable_set(key, 42) }.should.raise(TypeError, /#{Regexp.quote(key.inspect)} is not a symbol/)
end
end
diff --git a/spec/ruby/core/thread/thread_variable_spec.rb b/spec/ruby/core/thread/thread_variable_spec.rb
index 1b021e9404..ebafd4f3eb 100644
--- a/spec/ruby/core/thread/thread_variable_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_spec.rb
@@ -11,50 +11,50 @@ describe "Thread#thread_variable?" do
it "returns false if the thread variables do not contain 'key'" do
@t.thread_variable_set(:a, 2)
- @t.thread_variable?(:b).should be_false
+ @t.thread_variable?(:b).should == false
end
it "returns true if the thread variables contain 'key'" do
@t.thread_variable_set(:a, 2)
- @t.thread_variable?(:a).should be_true
+ @t.thread_variable?(:a).should == true
end
it "accepts String and Symbol keys interchangeably" do
- @t.thread_variable?('a').should be_false
- @t.thread_variable?(:a).should be_false
+ @t.thread_variable?('a').should == false
+ @t.thread_variable?(:a).should == false
@t.thread_variable_set(:a, 49)
- @t.thread_variable?('a').should be_true
- @t.thread_variable?(:a).should be_true
+ @t.thread_variable?('a').should == true
+ @t.thread_variable?(:a).should == true
end
it "converts a key that is neither String nor Symbol with #to_str" do
key = mock('key')
key.should_receive(:to_str).and_return('a')
@t.thread_variable_set(:a, 49)
- @t.thread_variable?(key).should be_true
+ @t.thread_variable?(key).should == true
end
it "does not raise FrozenError if the thread is frozen" do
@t.freeze
- @t.thread_variable?(:a).should be_false
+ @t.thread_variable?(:a).should == false
end
it "raises a TypeError if the key is neither Symbol nor String when thread variables are already set" do
@t.thread_variable_set(:a, 49)
- -> { @t.thread_variable?(123) }.should raise_error(TypeError, /123 is not a symbol/)
+ -> { @t.thread_variable?(123) }.should.raise(TypeError, /123 is not a symbol/)
end
ruby_version_is '3.4' do
it "raises a TypeError if the key is neither Symbol nor String when no thread variables are set" do
- -> { @t.thread_variable?(123) }.should raise_error(TypeError, /123 is not a symbol/)
+ -> { @t.thread_variable?(123) }.should.raise(TypeError, /123 is not a symbol/)
end
it "raises a TypeError if the key is neither Symbol nor String without calling #to_sym" do
key = mock('key')
key.should_not_receive(:to_sym)
- -> { @t.thread_variable?(key) }.should raise_error(TypeError, /#{Regexp.escape(key.inspect)} is not a symbol/)
+ -> { @t.thread_variable?(key) }.should.raise(TypeError, /#{Regexp.escape(key.inspect)} is not a symbol/)
end
end
end
diff --git a/spec/ruby/core/thread/thread_variables_spec.rb b/spec/ruby/core/thread/thread_variables_spec.rb
index 51ceef3376..f15c681a8f 100644
--- a/spec/ruby/core/thread/thread_variables_spec.rb
+++ b/spec/ruby/core/thread/thread_variables_spec.rb
@@ -19,7 +19,8 @@ describe "Thread#thread_variables" do
it "returns the keys private to self" do
@t.thread_variable_set(:a, 82)
@t.thread_variable_set(:b, 82)
- Thread.current.thread_variables.should_not include(:a, :b)
+ Thread.current.thread_variables.should_not.include?(:a)
+ Thread.current.thread_variables.should_not.include?(:b)
end
it "only contains user thread variables and is empty initially" do
diff --git a/spec/ruby/core/thread/value_spec.rb b/spec/ruby/core/thread/value_spec.rb
index 30e43abd1a..50c823171d 100644
--- a/spec/ruby/core/thread/value_spec.rb
+++ b/spec/ruby/core/thread/value_spec.rb
@@ -11,7 +11,7 @@ describe "Thread#value" do
Thread.current.report_on_exception = false
raise "Hello"
}
- -> { t.value }.should raise_error(RuntimeError, "Hello")
+ -> { t.value }.should.raise(RuntimeError, "Hello")
end
it "is nil for a killed thread" do
diff --git a/spec/ruby/core/threadgroup/default_spec.rb b/spec/ruby/core/threadgroup/default_spec.rb
index d7d4726cc2..4f57508abf 100644
--- a/spec/ruby/core/threadgroup/default_spec.rb
+++ b/spec/ruby/core/threadgroup/default_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "ThreadGroup::Default" do
it "is a ThreadGroup instance" do
- ThreadGroup::Default.should be_kind_of(ThreadGroup)
+ ThreadGroup::Default.should.is_a?(ThreadGroup)
end
it "is the ThreadGroup of the main thread" do
diff --git a/spec/ruby/core/threadgroup/enclose_spec.rb b/spec/ruby/core/threadgroup/enclose_spec.rb
index dd9a7a362d..6f703d4ce2 100644
--- a/spec/ruby/core/threadgroup/enclose_spec.rb
+++ b/spec/ruby/core/threadgroup/enclose_spec.rb
@@ -19,6 +19,6 @@ describe "ThreadGroup#enclose" do
thread_group.enclose
-> do
default_group.add(@thread)
- end.should raise_error(ThreadError)
+ end.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/core/threadgroup/enclosed_spec.rb b/spec/ruby/core/threadgroup/enclosed_spec.rb
index a734256a64..cf8a5bb4c6 100644
--- a/spec/ruby/core/threadgroup/enclosed_spec.rb
+++ b/spec/ruby/core/threadgroup/enclosed_spec.rb
@@ -3,12 +3,12 @@ require_relative '../../spec_helper'
describe "ThreadGroup#enclosed?" do
it "returns false when a ThreadGroup has not been enclosed (default state)" do
thread_group = ThreadGroup.new
- thread_group.enclosed?.should be_false
+ thread_group.enclosed?.should == false
end
it "returns true when a ThreadGroup is enclosed" do
thread_group = ThreadGroup.new
thread_group.enclose
- thread_group.enclosed?.should be_true
+ thread_group.enclosed?.should == true
end
end
diff --git a/spec/ruby/core/threadgroup/list_spec.rb b/spec/ruby/core/threadgroup/list_spec.rb
index b2ac64324a..ef601d75ea 100644
--- a/spec/ruby/core/threadgroup/list_spec.rb
+++ b/spec/ruby/core/threadgroup/list_spec.rb
@@ -7,13 +7,13 @@ describe "ThreadGroup#list" do
q.pop.should == :go
tg = ThreadGroup.new
tg.add(th1)
- tg.list.should include(th1)
+ tg.list.should.include?(th1)
th2 = Thread.new { q << :go; sleep }
q.pop.should == :go
tg.add(th2)
- (tg.list & [th1, th2]).should include(th1, th2)
+ (tg.list & [th1, th2]).to_set.should == Set[th1, th2]
Thread.pass while th1.status and th1.status != 'sleep'
Thread.pass while th2.status and th2.status != 'sleep'
diff --git a/spec/ruby/core/time/_dump_spec.rb b/spec/ruby/core/time/_dump_spec.rb
index 4dc1c43cd2..21f0806327 100644
--- a/spec/ruby/core/time/_dump_spec.rb
+++ b/spec/ruby/core/time/_dump_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
describe "Time#_dump" do
@@ -10,7 +10,7 @@ describe "Time#_dump" do
end
it "is a private method" do
- Time.should have_private_instance_method(:_dump, false)
+ Time.private_instance_methods(false).should.include?(:_dump)
end
# http://redmine.ruby-lang.org/issues/show/627
@@ -25,7 +25,7 @@ describe "Time#_dump" do
end
it "dumps a Time object to a bytestring" do
- @s.should be_an_instance_of(String)
+ @s.should.instance_of?(String)
@s.should == [3222863947, 2235564032].pack("VV")
end
diff --git a/spec/ruby/core/time/_load_spec.rb b/spec/ruby/core/time/_load_spec.rb
index bb0d705bbc..a74e3dc129 100644
--- a/spec/ruby/core/time/_load_spec.rb
+++ b/spec/ruby/core/time/_load_spec.rb
@@ -1,9 +1,9 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
describe "Time._load" do
it "is a private method" do
- Time.should have_private_method(:_load, false)
+ Time.private_methods(false).should.include?(:_load)
end
# http://redmine.ruby-lang.org/issues/show/627
diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb
index 97906b8c8c..10d4d36a68 100644
--- a/spec/ruby/core/time/at_spec.rb
+++ b/spec/ruby/core/time/at_spec.rb
@@ -20,7 +20,7 @@ describe "Time.at" do
it "returns a subclass instance on a Time subclass" do
c = Class.new(Time)
t = c.at(0)
- t.should be_an_instance_of(c)
+ t.should.instance_of?(c)
end
it "roundtrips a Rational produced by #to_r" do
@@ -56,7 +56,7 @@ describe "Time.at" do
it "creates a dup time object with the value given by time" do
t1 = Time.new
t2 = Time.at(t1)
- t1.should_not equal t2
+ t1.should_not.equal? t2
end
it "returns a UTC time if the argument is UTC" do
@@ -72,17 +72,17 @@ describe "Time.at" do
it "returns a subclass instance" do
c = Class.new(Time)
t = c.at(Time.now)
- t.should be_an_instance_of(c)
+ t.should.instance_of?(c)
end
end
describe "passed non-Time, non-Numeric" do
it "raises a TypeError with a String argument" do
- -> { Time.at("0") }.should raise_error(TypeError)
+ -> { Time.at("0") }.should.raise(TypeError)
end
it "raises a TypeError with a nil argument" do
- -> { Time.at(nil) }.should raise_error(TypeError)
+ -> { Time.at(nil) }.should.raise(TypeError)
end
describe "with an argument that responds to #to_int" do
@@ -103,7 +103,7 @@ describe "Time.at" do
it "needs for the argument to respond to #to_int too" do
o = mock('rational-but-no-to_int')
def o.to_r; Rational(5, 2) end
- -> { Time.at(o) }.should raise_error(TypeError, "can't convert MockObject into an exact number")
+ -> { Time.at(o) }.should.raise(TypeError, "can't convert MockObject into an exact number")
end
end
end
@@ -140,20 +140,20 @@ describe "Time.at" do
describe "passed [Integer, nil]" do
it "raises a TypeError" do
- -> { Time.at(0, nil) }.should raise_error(TypeError)
+ -> { Time.at(0, nil) }.should.raise(TypeError)
end
end
describe "passed [Integer, String]" do
it "raises a TypeError" do
- -> { Time.at(0, "0") }.should raise_error(TypeError)
+ -> { Time.at(0, "0") }.should.raise(TypeError)
end
end
describe "passed [Time, Integer]" do
# #8173
it "raises a TypeError" do
- -> { Time.at(Time.now, 500000) }.should raise_error(TypeError)
+ -> { Time.at(Time.now, 500000) }.should.raise(TypeError)
end
end
@@ -190,15 +190,15 @@ describe "Time.at" do
context "not supported format" do
it "raises ArgumentError" do
- -> { Time.at(0, 123456, 2) }.should raise_error(ArgumentError)
- -> { Time.at(0, 123456, nil) }.should raise_error(ArgumentError)
- -> { Time.at(0, 123456, :invalid) }.should raise_error(ArgumentError)
+ -> { Time.at(0, 123456, 2) }.should.raise(ArgumentError)
+ -> { Time.at(0, 123456, nil) }.should.raise(ArgumentError)
+ -> { Time.at(0, 123456, :invalid) }.should.raise(ArgumentError)
end
it "does not try to convert format to Symbol with #to_sym" do
format = +"usec"
format.should_not_receive(:to_sym)
- -> { Time.at(0, 123456, format) }.should raise_error(ArgumentError)
+ -> { Time.at(0, 123456, format) }.should.raise(ArgumentError)
end
end
@@ -283,33 +283,33 @@ describe "Time.at" do
end
it "raises ArgumentError if format is invalid" do
- -> { Time.at(@epoch_time, in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.at(@epoch_time, in: "ABC") }.should raise_error(ArgumentError)
+ -> { Time.at(@epoch_time, in: "+09:99") }.should.raise(ArgumentError)
+ -> { Time.at(@epoch_time, in: "ABC") }.should.raise(ArgumentError)
end
it "raises ArgumentError if hours greater than 23" do # TODO
- -> { Time.at(@epoch_time, in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.at(@epoch_time, in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.at(@epoch_time, in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.at(@epoch_time, in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if minutes greater than 59" do # TODO
- -> { Time.at(@epoch_time, in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.at(@epoch_time, in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.at(@epoch_time, in: "+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.at(@epoch_time, in: "+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.at(@epoch_time, in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.at(@epoch_time, in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.at(@epoch_time, in: "+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.at(@epoch_time, in: "+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if seconds greater than 59" do
- -> { Time.at(@epoch_time, in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.at(@epoch_time, in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.at(@epoch_time, in: "+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.at(@epoch_time, in: "+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.at(@epoch_time, in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.at(@epoch_time, in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.at(@epoch_time, in: "+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.at(@epoch_time, in: "+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
end
diff --git a/spec/ruby/core/time/ceil_spec.rb b/spec/ruby/core/time/ceil_spec.rb
index 9d624a1ed0..18e26f9994 100644
--- a/spec/ruby/core/time/ceil_spec.rb
+++ b/spec/ruby/core/time/ceil_spec.rb
@@ -28,8 +28,8 @@ describe "Time#ceil" do
it "returns an instance of Time, even if #ceil is called on a subclass" do
subclass = Class.new(Time)
instance = subclass.at(0)
- instance.class.should equal subclass
- instance.ceil.should be_an_instance_of(Time)
+ instance.class.should.equal? subclass
+ instance.ceil.should.instance_of?(Time)
end
it "copies own timezone to the returning value" do
diff --git a/spec/ruby/core/time/comparison_spec.rb b/spec/ruby/core/time/comparison_spec.rb
index 866fbea72e..0790088f9e 100644
--- a/spec/ruby/core/time/comparison_spec.rb
+++ b/spec/ruby/core/time/comparison_spec.rb
@@ -124,7 +124,7 @@ describe "Time#<=>" do
def r.<=>(other); other <=> self; end
r.should_receive(:<=>).once
- (t <=> r).should be_nil
+ (t <=> r).should == nil
end
end
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
index ee17e7dbd4..9918728c1d 100644
--- a/spec/ruby/core/time/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/time/deconstruct_keys_spec.rb
@@ -1,45 +1,43 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Time#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = Time.utc(2022, 10, 5, 13, 30)
- res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
- min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" }
- d.deconstruct_keys(nil).should == res
- end
-
- it "returns only specified keys" do
- d = Time.utc(2022, 10, 5, 13, 39)
- d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 }
- end
-
- it "requires one argument" do
- -> {
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = Time.new(2022, 10, 5, 13, 30)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys and processes keys after the first non-existing one" do
- d = Time.utc(2022, 10, 5, 13, 30)
- d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 }
- end
+describe "Time#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = Time.utc(2022, 10, 5, 13, 30)
+ res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
+ min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" }
+ d.deconstruct_keys(nil).should == res
+ end
+
+ it "returns only specified keys" do
+ d = Time.utc(2022, 10, 5, 13, 39)
+ d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 }
+ end
+
+ it "requires one argument" do
+ -> {
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys
+ }.should.raise(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = Time.new(2022, 10, 5, 13, 30)
+
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys and processes keys after the first non-existing one" do
+ d = Time.utc(2022, 10, 5, 13, 30)
+ d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 }
end
end
diff --git a/spec/ruby/core/time/dup_spec.rb b/spec/ruby/core/time/dup_spec.rb
index 5d6621beaa..33aa1304ef 100644
--- a/spec/ruby/core/time/dup_spec.rb
+++ b/spec/ruby/core/time/dup_spec.rb
@@ -22,25 +22,25 @@ describe "Time#dup" do
c = Class.new(Time)
t = c.now
- t.should be_an_instance_of(c)
- t.dup.should be_an_instance_of(c)
+ t.should.instance_of?(c)
+ t.dup.should.instance_of?(c)
end
it "returns a clone of Time instance" do
c = Time.dup
t = c.now
- t.should be_an_instance_of(c)
- t.should_not be_an_instance_of(Time)
+ t.should.instance_of?(c)
+ t.should_not.instance_of?(Time)
- t.dup.should be_an_instance_of(c)
- t.dup.should_not be_an_instance_of(Time)
+ t.dup.should.instance_of?(c)
+ t.dup.should_not.instance_of?(Time)
end
it "does not copy frozen status from the original" do
t = Time.now
t.freeze
t2 = t.dup
- t2.frozen?.should be_false
+ t2.frozen?.should == false
end
end
diff --git a/spec/ruby/core/time/eql_spec.rb b/spec/ruby/core/time/eql_spec.rb
index 2ffb4eec96..b7505969dd 100644
--- a/spec/ruby/core/time/eql_spec.rb
+++ b/spec/ruby/core/time/eql_spec.rb
@@ -2,28 +2,28 @@ require_relative '../../spec_helper'
describe "Time#eql?" do
it "returns true if self and other have the same whole number of seconds" do
- Time.at(100).should eql(Time.at(100))
+ Time.at(100).should.eql?(Time.at(100))
end
it "returns false if self and other have differing whole numbers of seconds" do
- Time.at(100).should_not eql(Time.at(99))
+ Time.at(100).should_not.eql?(Time.at(99))
end
it "returns true if self and other have the same number of microseconds" do
- Time.at(100, 100).should eql(Time.at(100, 100))
+ Time.at(100, 100).should.eql?(Time.at(100, 100))
end
it "returns false if self and other have differing numbers of microseconds" do
- Time.at(100, 100).should_not eql(Time.at(100, 99))
+ Time.at(100, 100).should_not.eql?(Time.at(100, 99))
end
it "returns false if self and other have differing fractional microseconds" do
- Time.at(100, Rational(100,1000)).should_not eql(Time.at(100, Rational(99,1000)))
+ Time.at(100, Rational(100,1000)).should_not.eql?(Time.at(100, Rational(99,1000)))
end
it "returns false when given a non-time value" do
- Time.at(100, 100).should_not eql("100")
- Time.at(100, 100).should_not eql(100)
- Time.at(100, 100).should_not eql(100.1)
+ Time.at(100, 100).should_not.eql?("100")
+ Time.at(100, 100).should_not.eql?(100)
+ Time.at(100, 100).should_not.eql?(100.1)
end
end
diff --git a/spec/ruby/core/time/floor_spec.rb b/spec/ruby/core/time/floor_spec.rb
index b0003469c9..41e5142b19 100644
--- a/spec/ruby/core/time/floor_spec.rb
+++ b/spec/ruby/core/time/floor_spec.rb
@@ -20,8 +20,8 @@ describe "Time#floor" do
it "returns an instance of Time, even if #floor is called on a subclass" do
subclass = Class.new(Time)
instance = subclass.at(0)
- instance.class.should equal subclass
- instance.floor.should be_an_instance_of(Time)
+ instance.class.should.equal? subclass
+ instance.floor.should.instance_of?(Time)
end
it "copies own timezone to the returning value" do
diff --git a/spec/ruby/core/time/getlocal_spec.rb b/spec/ruby/core/time/getlocal_spec.rb
index 398596f400..7e5334c303 100644
--- a/spec/ruby/core/time/getlocal_spec.rb
+++ b/spec/ruby/core/time/getlocal_spec.rb
@@ -14,7 +14,7 @@ describe "Time#getlocal" do
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(3630)
t.should == Time.new(2007, 1, 9, 13, 0, 30, 3630)
t.utc_offset.should == 3630
- t.zone.should be_nil
+ t.zone.should == nil
end
platform_is_not :windows do
@@ -41,7 +41,7 @@ describe "Time#getlocal" do
it "returns a Time with a UTC offset of the specified number of Rational seconds" do
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(Rational(7201, 2))
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
describe "with an argument that responds to #to_r" do
@@ -50,7 +50,7 @@ describe "Time#getlocal" do
o.should_receive(:to_r).and_return(Rational(7201, 2))
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(o)
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
end
@@ -90,49 +90,49 @@ describe "Time#getlocal" do
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
t = Time.now
- -> { t.getlocal("3600") }.should raise_error(ArgumentError)
+ -> { t.getlocal("3600") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
t = Time.now
- -> { t.getlocal("-01:00".encode("UTF-16LE")) }.should raise_error(ArgumentError)
+ -> { t.getlocal("-01:00".encode("UTF-16LE")) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
t = Time.new
t.getlocal(-86400 + 1).utc_offset.should == (-86400 + 1)
- -> { t.getlocal(-86400) }.should raise_error(ArgumentError)
+ -> { t.getlocal(-86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds" do
t = Time.new
t.getlocal(86400 - 1).utc_offset.should == (86400 - 1)
- -> { t.getlocal(86400) }.should raise_error(ArgumentError)
+ -> { t.getlocal(86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if String argument and hours greater than 23" do
- -> { Time.now.getlocal("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.getlocal("+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.now.getlocal("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.getlocal("+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if String argument and minutes greater than 59" do
- -> { Time.now.getlocal("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.now.getlocal("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.now.getlocal("+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now.getlocal("+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.now.getlocal("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.now.getlocal("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.now.getlocal("+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now.getlocal("+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if String argument and seconds greater than 59" do
- -> { Time.now.getlocal("+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.now.getlocal("+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.now.getlocal("+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now.getlocal("+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.now.getlocal("+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.now.getlocal("+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.now.getlocal("+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now.getlocal("+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
@@ -155,8 +155,8 @@ describe "Time#getlocal" do
end
-> {
- Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should be_kind_of(Time)
- }.should_not raise_error
+ Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should.is_a?(Time)
+ }.should_not.raise
end
it "raises TypeError if timezone does not implement #utc_to_local method" do
@@ -167,7 +167,7 @@ describe "Time#getlocal" do
-> {
Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should.raise(TypeError, /can't convert \w+ into an exact number/)
end
it "does not raise exception if timezone does not implement #local_to_utc method" do
@@ -177,18 +177,18 @@ describe "Time#getlocal" do
end
-> {
- Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should be_kind_of(Time)
- }.should_not raise_error
+ Time.utc(2000, 1, 1, 12, 0, 0).getlocal(zone).should.is_a?(Time)
+ }.should_not.raise
end
context "subject's class implements .find_timezone method" do
it "calls .find_timezone to build a time object if passed zone name as a timezone argument" do
time = TimeSpecs::TimeWithFindTimezone.utc(2000, 1, 1, 12, 0, 0).getlocal("Asia/Colombo")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "Asia/Colombo"
time = TimeSpecs::TimeWithFindTimezone.utc(2000, 1, 1, 12, 0, 0).getlocal("some invalid zone name")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "some invalid zone name"
end
@@ -198,7 +198,7 @@ describe "Time#getlocal" do
-> {
time.getlocal(zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should.raise(TypeError, /can't convert \w+ into an exact number/)
end
end
end
diff --git a/spec/ruby/core/time/hash_spec.rb b/spec/ruby/core/time/hash_spec.rb
index 4f4d11a2cd..1cfc56eab0 100644
--- a/spec/ruby/core/time/hash_spec.rb
+++ b/spec/ruby/core/time/hash_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Time#hash" do
it "returns an Integer" do
- Time.at(100).hash.should be_an_instance_of(Integer)
+ Time.at(100).hash.should.instance_of?(Integer)
end
it "is stable" do
diff --git a/spec/ruby/core/time/localtime_spec.rb b/spec/ruby/core/time/localtime_spec.rb
index 71c0dfebde..1c0b11b7a6 100644
--- a/spec/ruby/core/time/localtime_spec.rb
+++ b/spec/ruby/core/time/localtime_spec.rb
@@ -12,7 +12,7 @@ describe "Time#localtime" do
it "returns self" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
- t.localtime.should equal(t)
+ t.localtime.should.equal?(t)
end
it "converts time to the UTC offset specified as an Integer number of seconds" do
@@ -26,13 +26,13 @@ describe "Time#localtime" do
it "does not raise an error if already in the right time zone" do
time = Time.now
time.freeze
- time.localtime.should equal(time)
+ time.localtime.should.equal?(time)
end
it "raises a FrozenError if the time has a different time zone" do
time = Time.gm(2007, 1, 9, 12, 0, 0)
time.freeze
- -> { time.localtime }.should raise_error(FrozenError)
+ -> { time.localtime }.should.raise(FrozenError)
end
end
@@ -51,7 +51,7 @@ describe "Time#localtime" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
t.localtime(Rational(7201, 2))
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
describe "with an argument that responds to #to_r" do
@@ -61,7 +61,7 @@ describe "Time#localtime" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
t.localtime(o)
t.should == Time.new(2007, 1, 9, 13, 0, Rational(1, 2), Rational(7201, 2))
- t.utc_offset.should eql(Rational(7201, 2))
+ t.utc_offset.should.eql?(Rational(7201, 2))
end
end
@@ -106,28 +106,28 @@ describe "Time#localtime" do
end
it "raises ArgumentError if String argument and hours greater than 23" do
- -> { Time.now.localtime("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.localtime("+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.now.localtime("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now.localtime("+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if String argument and minutes greater than 59" do
- -> { Time.now.localtime("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.now.localtime("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.now.localtime("+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now.localtime("+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.now.localtime("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.now.localtime("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.now.localtime("+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now.localtime("+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if String argument and seconds greater than 59" do
- -> { Time.now.localtime("+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.now.localtime("+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.now.localtime("+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now.localtime("+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.now.localtime("+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.now.localtime("+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.now.localtime("+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now.localtime("+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
@@ -181,23 +181,23 @@ describe "Time#localtime" do
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
t = Time.now
- -> { t.localtime("3600") }.should raise_error(ArgumentError)
+ -> { t.localtime("3600") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
t = Time.now
- -> { t.localtime("-01:00".encode("UTF-16LE")) }.should raise_error(ArgumentError)
+ -> { t.localtime("-01:00".encode("UTF-16LE")) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
t = Time.new
t.localtime(-86400 + 1).utc_offset.should == (-86400 + 1)
- -> { t.localtime(-86400) }.should raise_error(ArgumentError)
+ -> { t.localtime(-86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds" do
t = Time.new
t.localtime(86400 - 1).utc_offset.should == (86400 - 1)
- -> { t.localtime(86400) }.should raise_error(ArgumentError)
+ -> { t.localtime(86400) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/core/time/minus_spec.rb b/spec/ruby/core/time/minus_spec.rb
index 8449778465..ee3d8acda8 100644
--- a/spec/ruby/core/time/minus_spec.rb
+++ b/spec/ruby/core/time/minus_spec.rb
@@ -20,18 +20,18 @@ describe "Time#-" do
end
it "raises a TypeError if given argument is a coercible String" do
- -> { Time.now - "1" }.should raise_error(TypeError)
- -> { Time.now - "0.1" }.should raise_error(TypeError)
- -> { Time.now - "1/3" }.should raise_error(TypeError)
+ -> { Time.now - "1" }.should.raise(TypeError)
+ -> { Time.now - "0.1" }.should.raise(TypeError)
+ -> { Time.now - "1/3" }.should.raise(TypeError)
end
it "raises TypeError on argument that can't be coerced" do
- -> { Time.now - Object.new }.should raise_error(TypeError)
- -> { Time.now - "stuff" }.should raise_error(TypeError)
+ -> { Time.now - Object.new }.should.raise(TypeError)
+ -> { Time.now - "stuff" }.should.raise(TypeError)
end
it "raises TypeError on nil argument" do
- -> { Time.now - nil }.should raise_error(TypeError)
+ -> { Time.now - nil }.should.raise(TypeError)
end
it "tracks microseconds" do
@@ -109,8 +109,8 @@ describe "Time#-" do
it "does not return a subclass instance" do
c = Class.new(Time)
- x = c.now + 1
- x.should be_an_instance_of(Time)
+ x = c.now - 1
+ x.should.instance_of?(Time)
end
it "returns a time with nanoseconds precision between two time objects" do
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index 0fd48640d4..91ce4b2e3a 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -31,14 +31,14 @@ describe "Time.new with a utc_offset argument" do
end
it "returns a Time with a UTC offset of the specified number of Rational seconds" do
- Time.new(2000, 1, 1, 0, 0, 0, Rational(5, 2)).utc_offset.should eql(Rational(5, 2))
+ Time.new(2000, 1, 1, 0, 0, 0, Rational(5, 2)).utc_offset.should.eql?(Rational(5, 2))
end
describe "with an argument that responds to #to_r" do
it "coerces using #to_r" do
o = mock_numeric('rational')
o.should_receive(:to_r).and_return(Rational(5, 2))
- Time.new(2000, 1, 1, 0, 0, 0, o).utc_offset.should eql(Rational(5, 2))
+ Time.new(2000, 1, 1, 0, 0, 0, o).utc_offset.should.eql?(Rational(5, 2))
end
end
@@ -129,7 +129,7 @@ describe "Time.new with a utc_offset argument" do
it "raises ArgumentError if the string argument is J" do
message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J'
- -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should.raise(ArgumentError, message)
end
it "returns a local Time if the argument is nil" do
@@ -144,18 +144,18 @@ describe "Time.new with a utc_offset argument" do
it "disallows a value for minutes greater than 59" do
-> {
Time.new(2000, 1, 1, 0, 0, 0, "+01:60")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
Time.new(2000, 1, 1, 0, 0, 0, "+01:99")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, "3600") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "3600") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the hour value is greater than 23" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, "+24:00") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "+24:00") }.should.raise(ArgumentError)
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
@@ -164,21 +164,21 @@ describe "Time.new with a utc_offset argument" do
# - '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset'
-> {
Time.new(2000, 1, 1, 0, 0, 0, "-04:10".encode("UTF-16LE"))
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
Time.new(2000, 1, 1, 0, 0, 0, -86400 + 1).utc_offset.should == (-86400 + 1)
- -> { Time.new(2000, 1, 1, 0, 0, 0, -86400) }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, -86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds" do
Time.new(2000, 1, 1, 0, 0, 0, 86400 - 1).utc_offset.should == (86400 - 1)
- -> { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the utc_offset argument is greater than or equal to 10e9" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should.raise(ArgumentError)
end
end
@@ -203,7 +203,7 @@ describe "Time.new with a timezone argument" do
time
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
end
it "raises TypeError if timezone does not implement #local_to_utc method" do
@@ -214,7 +214,7 @@ describe "Time.new with a timezone argument" do
-> {
Time.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(TypeError, /can't convert Object into an exact number/)
+ }.should.raise(TypeError, /can't convert Object into an exact number/)
end
it "does not raise exception if timezone does not implement #utc_to_local method" do
@@ -223,7 +223,7 @@ describe "Time.new with a timezone argument" do
time
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
end
# The result also should be a Time or Time-like object (not necessary to be the same class)
@@ -236,7 +236,7 @@ describe "Time.new with a timezone argument" do
time - 60 * 60 # - 1 hour
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
@@ -248,7 +248,7 @@ describe "Time.new with a timezone argument" do
Class.new(Time).utc(time.year, time.mon, time.day, time.hour, t.min, t.sec)
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
@@ -260,7 +260,7 @@ describe "Time.new with a timezone argument" do
obj
end
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should.is_a?(Time)
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
@@ -294,7 +294,7 @@ describe "Time.new with a timezone argument" do
-> {
Time.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(ArgumentError, "utc_offset out of range")
+ }.should.raise(ArgumentError, "utc_offset out of range")
end
end
@@ -348,7 +348,7 @@ describe "Time.new with a timezone argument" do
-> {
Marshal.dump(time)
- }.should raise_error(NoMethodError, /undefined method [`']name' for/)
+ }.should.raise(NoMethodError, /undefined method [`']name' for/)
end
end
@@ -369,18 +369,18 @@ describe "Time.new with a timezone argument" do
time = TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, zone)
time_loaded = Marshal.load(Marshal.dump(time))
- time_loaded.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time_loaded.zone.should.is_a? TimeSpecs::TimezoneWithName
time_loaded.zone.name.should == "Asia/Colombo"
time_loaded.utc_offset.should == 5*3600+30*60
end
it "calls .find_timezone to build a time object if passed zone name as a timezone argument" do
time = TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, "Asia/Colombo")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "Asia/Colombo"
time = TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, "some invalid zone name")
- time.zone.should be_kind_of TimeSpecs::TimezoneWithName
+ time.zone.should.is_a? TimeSpecs::TimezoneWithName
time.zone.name.should == "some invalid zone name"
end
@@ -388,7 +388,7 @@ describe "Time.new with a timezone argument" do
[Object.new, [], {}, :"some zone"].each do |zone|
-> {
TimeSpecs::TimeWithFindTimezone.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should.raise(TypeError, /can't convert \w+ into an exact number/)
end
end
end
@@ -456,270 +456,284 @@ describe "Time.new with a timezone argument" do
end
it "raises ArgumentError if format is invalid" do
- -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should.raise(ArgumentError)
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should.raise(ArgumentError)
end
it "raises ArgumentError if two offset arguments are given" do
-> {
Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00")
- }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments")
+ }.should.raise(ArgumentError, "timezone argument given as positional and keyword arguments")
end
end
- ruby_version_is "3.2" do
- describe "Time.new with a String argument" do
- it "parses an ISO-8601 like format" do
- t = Time.utc(2020, 12, 24, 15, 56, 17)
+ describe "Time.new with a String argument" do
+ it "parses an ISO-8601 like format" do
+ t = Time.utc(2020, 12, 24, 15, 56, 17)
- Time.new("2020-12-24T15:56:17Z").should == t
- Time.new("2020-12-25 00:56:17 +09:00").should == t
- Time.new("2020-12-25 00:57:47 +09:01:30").should == t
- Time.new("2020-12-25 00:56:17 +0900").should == t
- Time.new("2020-12-25 00:57:47 +090130").should == t
- Time.new("2020-12-25T00:56:17+09:00").should == t
+ Time.new("2020-12-24T15:56:17Z").should == t
+ Time.new("2020-12-25 00:56:17 +09:00").should == t
+ Time.new("2020-12-25 00:57:47 +09:01:30").should == t
+ Time.new("2020-12-25 00:56:17 +0900").should == t
+ Time.new("2020-12-25 00:57:47 +090130").should == t
+ Time.new("2020-12-25T00:56:17+09:00").should == t
- Time.new("2020-12-25T00:56:17.123456+09:00").should == Time.utc(2020, 12, 24, 15, 56, 17, 123456)
- end
-
- it "accepts precision keyword argument and truncates specified digits of sub-second part" do
- Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
- Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
- end
+ Time.new("2020-12-25T00:56:17.123456+09:00").should == Time.utc(2020, 12, 24, 15, 56, 17, 123456)
+ end
- it "returns Time in local timezone if not provided in the String argument" do
- Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
- Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
- end
+ it "accepts precision keyword argument and truncates specified digits of sub-second part" do
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
+ Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
+ end
- it "returns Time in timezone specified in the String argument" do
- Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
- end
+ it "returns Time in local timezone if not provided in the String argument" do
+ Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
+ Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
+ end
- it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
- Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
- end
+ it "returns Time in timezone specified in the String argument" do
+ Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
+ end
- it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
- Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
- end
+ it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
+ Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
+ end
- it "returns Time of Jan 1 for string with just year" do
- Time.new("2021").should == Time.new(2021, 1, 1)
- Time.new("2021").zone.should == Time.new(2021, 1, 1).zone
- Time.new("2021").utc_offset.should == Time.new(2021, 1, 1).utc_offset
- end
+ it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
+ Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
+ end
- it "returns Time of Jan 1 for string with just year in timezone specified with in keyword argument" do
- Time.new("2021", in: "+17:00").to_s.should == "2021-01-01 00:00:00 +1700"
- end
+ it "returns Time of Jan 1 for string with just year" do
+ Time.new("2021").should == Time.new(2021, 1, 1)
+ Time.new("2021").zone.should == Time.new(2021, 1, 1).zone
+ Time.new("2021").utc_offset.should == Time.new(2021, 1, 1).utc_offset
+ end
- it "converts precision keyword argument into Integer if is not nil" do
- obj = Object.new
- def obj.to_int; 3; end
+ it "returns Time of Jan 1 for string with just year in timezone specified with in keyword argument" do
+ Time.new("2021", in: "+17:00").to_s.should == "2021-01-01 00:00:00 +1700"
+ end
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
- end
+ it "converts precision keyword argument into Integer if is not nil" do
+ obj = Object.new
+ def obj.to_int; 3; end
- ruby_version_is ""..."3.3" do
- it "raise TypeError is can't convert precision keyword argument into Integer" do
- -> {
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
- }.should raise_error(TypeError, "no implicit conversion from string")
- end
- end
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
+ end
- ruby_version_is "3.3" do
- it "raise TypeError is can't convert precision keyword argument into Integer" do
- -> {
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
- }.should raise_error(TypeError, "no implicit conversion of String into Integer")
- end
- end
+ it "returns Time with correct subseconds when given seconds fraction is shorted than 6 digits" do
+ Time.new("2020-12-25T00:56:17.123 +09:00").nsec.should == 123000000
+ Time.new("2020-12-25T00:56:17.123 +09:00").usec.should == 123000
+ Time.new("2020-12-25T00:56:17.123 +09:00").subsec.should == 0.123
+ end
- it "raises ArgumentError if part of time string is missing" do
- -> {
- Time.new("2020-12-25 00:56 +09:00")
- }.should raise_error(ArgumentError, /missing sec part: 00:56 |can't parse:/)
+ it "returns Time with correct subseconds when given seconds fraction is milliseconds" do
+ Time.new("2020-12-25T00:56:17.123456 +09:00").nsec.should == 123456000
+ Time.new("2020-12-25T00:56:17.123456 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.123456 +09:00").subsec.should == 0.123456
+ end
- -> {
- Time.new("2020-12-25 00 +09:00")
- }.should raise_error(ArgumentError, /missing min part: 00 |can't parse:/)
- end
+ it "returns Time with correct subseconds when given seconds fraction is longer that 6 digits but shorted than 9 digits" do
+ Time.new("2020-12-25T00:56:17.12345678 +09:00").nsec.should == 123456780
+ Time.new("2020-12-25T00:56:17.12345678 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.12345678 +09:00").subsec.should == 0.12345678
+ end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError if the time part is missing" do
- -> {
- Time.new("2020-12-25")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
-
- it "raises ArgumentError if day is missing" do
- -> {
- Time.new("2020-12")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
- end
+ it "returns Time with correct subseconds when given seconds fraction is nanoseconds" do
+ Time.new("2020-12-25T00:56:17.123456789 +09:00").nsec.should == 123456789
+ Time.new("2020-12-25T00:56:17.123456789 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.123456789 +09:00").subsec.should == 0.123456789
+ end
- it "raises ArgumentError if subsecond is missing after dot" do
- -> {
- Time.new("2020-12-25 00:56:17. +0900")
- }.should raise_error(ArgumentError, /subsecond expected after dot: 00:56:17. |can't parse:/)
- end
+ it "returns Time with correct subseconds when given seconds fraction is longer than 9 digits" do
+ Time.new("2020-12-25T00:56:17.123456789876 +09:00").nsec.should == 123456789
+ Time.new("2020-12-25T00:56:17.123456789876 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.123456789876 +09:00").subsec.should == 0.123456789
+ end
- it "raises ArgumentError if String argument is not in the supported format" do
- -> {
- Time.new("021-12-25 00:00:00.123456 +09:00")
- }.should raise_error(ArgumentError, /year must be 4 or more digits: 021|can't parse:/)
+ it "raise TypeError is can't convert precision keyword argument into Integer" do
+ -> {
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
+ }.should.raise(TypeError, "no implicit conversion of String into Integer")
+ end
- -> {
- Time.new("2020-012-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/)
+ it "raises ArgumentError if part of time string is missing" do
+ -> {
+ Time.new("2020-12-25 00:56 +09:00")
+ }.should.raise(ArgumentError, /missing sec part: 00:56 |can't parse:/)
- -> {
- Time.new("2020-2-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/)
+ -> {
+ Time.new("2020-12-25 00 +09:00")
+ }.should.raise(ArgumentError, /missing min part: 00 |can't parse:/)
+ end
- -> {
- Time.new("2020-12-215 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/)
+ it "raises ArgumentError if the time part is missing" do
+ -> {
+ Time.new("2020-12-25")
+ }.should.raise(ArgumentError, /no time information|can't parse:/)
+ end
- -> {
- Time.new("2020-12-25 000:56:17 +0900")
- }.should raise_error(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/)
+ it "raises ArgumentError if day is missing" do
+ -> {
+ Time.new("2020-12")
+ }.should.raise(ArgumentError, /no time information|can't parse:/)
+ end
- -> {
- Time.new("2020-12-25 0:56:17 +0900")
- }.should raise_error(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/)
+ it "raises ArgumentError if subsecond is missing after dot" do
+ -> {
+ Time.new("2020-12-25 00:56:17. +0900")
+ }.should.raise(ArgumentError, /subsecond expected after dot: 00:56:17. |can't parse:/)
+ end
- -> {
- Time.new("2020-12-25 00:516:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/)
+ it "raises ArgumentError if String argument is not in the supported format" do
+ -> {
+ Time.new("021-12-25 00:00:00.123456 +09:00")
+ }.should.raise(ArgumentError, /year must be 4 or more digits: 021|can't parse:/)
- -> {
- Time.new("2020-12-25 00:6:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/)
+ -> {
+ Time.new("2020-012-25 00:56:17 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56:137 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/)
+ -> {
+ Time.new("2020-2-25 00:56:17 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56:7 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/)
+ -> {
+ Time.new("2020-12-215 00:56:17 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56. +0900")
- }.should raise_error(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/)
+ -> {
+ Time.new("2020-12-25 000:56:17 +0900")
+ }.should.raise(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/)
- -> {
- Time.new("2020-12-25 00. +0900")
- }.should raise_error(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/)
- end
+ -> {
+ Time.new("2020-12-25 0:56:17 +0900")
+ }.should.raise(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/)
- it "raises ArgumentError if date/time parts values are not valid" do
- -> {
- Time.new("2020-13-25 00:56:17 +09:00")
- }.should raise_error(ArgumentError, /(mon|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:516:17 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/)
- -> {
- Time.new("2020-12-32 00:56:17 +09:00")
- }.should raise_error(ArgumentError, /(mday|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:6:17 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/)
- -> {
- Time.new("2020-12-25 25:56:17 +09:00")
- }.should raise_error(ArgumentError, /(hour|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:56:137 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:61:17 +09:00")
- }.should raise_error(ArgumentError, /(min|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:56:7 +0900")
+ }.should.raise(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56:61 +09:00")
- }.should raise_error(ArgumentError, /(sec|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:56. +0900")
+ }.should.raise(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56:17 +23:59:60")
- }.should raise_error(ArgumentError, /utc_offset|argument out of range/)
+ -> {
+ Time.new("2020-12-25 00. +0900")
+ }.should.raise(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/)
+ end
- -> {
- Time.new("2020-12-25 00:56:17 +24:00")
- }.should raise_error(ArgumentError, /(utc_offset|argument) out of range/)
+ it "raises ArgumentError if date/time parts values are not valid" do
+ -> {
+ Time.new("2020-13-25 00:56:17 +09:00")
+ }.should.raise(ArgumentError, /(mon|argument) out of range/)
- -> {
- Time.new("2020-12-25 00:56:17 +23:61")
- }.should raise_error(ArgumentError, /utc_offset/)
-
- ruby_bug '#20797', ''...'3.4' do
- -> {
- Time.new("2020-12-25 00:56:17 +00:23:61")
- }.should raise_error(ArgumentError, /utc_offset/)
- end
- end
+ -> {
+ Time.new("2020-12-32 00:56:17 +09:00")
+ }.should.raise(ArgumentError, /(mday|argument) out of range/)
- it "raises ArgumentError if utc offset parts are not valid" do
- -> { Time.new("2020-12-25 00:56:17 +24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.new("2020-12-25 00:56:17 +2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> {
+ Time.new("2020-12-25 25:56:17 +09:00")
+ }.should.raise(ArgumentError, /(hour|argument) out of range/)
- -> { Time.new("2020-12-25 00:56:17 +99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.new("2020-12-25 00:56:17 +9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> {
+ Time.new("2020-12-25 00:61:17 +09:00")
+ }.should.raise(ArgumentError, /(min|argument) out of range/)
- -> { Time.new("2020-12-25 00:56:17 +00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.new("2020-12-25 00:56:17 +0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> {
+ Time.new("2020-12-25 00:56:61 +09:00")
+ }.should.raise(ArgumentError, /(sec|argument) out of range/)
- -> { Time.new("2020-12-25 00:56:17 +00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.new("2020-12-25 00:56:17 +0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:59:60")
+ }.should.raise(ArgumentError, /utc_offset|argument out of range/)
- ruby_bug '#20797', ''...'3.4' do
- -> { Time.new("2020-12-25 00:56:17 +00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.new("2020-12-25 00:56:17 +000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> {
+ Time.new("2020-12-25 00:56:17 +24:00")
+ }.should.raise(ArgumentError, /(utc_offset|argument) out of range/)
- -> { Time.new("2020-12-25 00:56:17 +00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.new("2020-12-25 00:56:17 +000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
- end
- end
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:61")
+ }.should.raise(ArgumentError, /utc_offset/)
- it "raises ArgumentError if string has not ascii-compatible encoding" do
+ ruby_bug '#20797', ''...'3.4' do
-> {
- Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
- }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding")
+ Time.new("2020-12-25 00:56:17 +00:23:61")
+ }.should.raise(ArgumentError, /utc_offset/)
end
+ end
- it "raises ArgumentError if string doesn't start with year" do
- -> {
- Time.new("a\nb")
- }.should raise_error(ArgumentError, "can't parse: \"a\\nb\"")
- end
+ it "raises ArgumentError if utc offset parts are not valid" do
+ -> { Time.new("2020-12-25 00:56:17 +24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +2400") }.should.raise(ArgumentError, "utc_offset out of range")
- it "raises ArgumentError if string has extra characters after offset" do
- -> {
- Time.new("2021-11-31 00:00:59 +09:00 abc")
- }.should raise_error(ArgumentError, /can't parse.+ abc/)
- end
+ -> { Time.new("2020-12-25 00:56:17 +99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +9900") }.should.raise(ArgumentError, "utc_offset out of range")
+
+ -> { Time.new("2020-12-25 00:56:17 +00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.new("2020-12-25 00:56:17 +0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+
+ -> { Time.new("2020-12-25 00:56:17 +00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.new("2020-12-25 00:56:17 +0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+
+ ruby_bug '#20797', ''...'3.4' do
+ -> { Time.new("2020-12-25 00:56:17 +00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.new("2020-12-25 00:56:17 +000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- ruby_version_is "3.2.3" do
- it "raises ArgumentError when there are leading space characters" do
- -> { Time.new(" 2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\t2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\n2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\v2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\f2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\r2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- end
-
- it "raises ArgumentError when there are trailing whitespaces" do
- -> { Time.new("2020-12-02 00:00:00 ") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\t") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\n") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\v") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\f") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\r") }.should raise_error(ArgumentError, /can't parse/)
- end
+ -> { Time.new("2020-12-25 00:56:17 +00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.new("2020-12-25 00:56:17 +000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
+
+ it "raises ArgumentError if string has not ascii-compatible encoding" do
+ -> {
+ Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
+ }.should.raise(ArgumentError, "time string should have ASCII compatible encoding")
+ end
+
+ it "raises ArgumentError if string doesn't start with year" do
+ -> {
+ Time.new("a\nb")
+ }.should.raise(ArgumentError, "can't parse: \"a\\nb\"")
+ end
+
+ it "raises ArgumentError if string has extra characters after offset" do
+ -> {
+ Time.new("2021-11-31 00:00:59 +09:00 abc")
+ }.should.raise(ArgumentError, /can't parse.+ abc/)
+ end
+
+ it "raises ArgumentError when there are leading space characters" do
+ -> { Time.new(" 2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\t2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\n2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\v2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\f2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("\r2020-12-02 00:00:00") }.should.raise(ArgumentError, /can't parse/)
+ end
+
+ it "raises ArgumentError when there are trailing whitespaces" do
+ -> { Time.new("2020-12-02 00:00:00 ") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\t") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\n") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\v") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\f") }.should.raise(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\r") }.should.raise(ArgumentError, /can't parse/)
+ end
end
end
diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb
index f19e015461..533cf68380 100644
--- a/spec/ruby/core/time/now_spec.rb
+++ b/spec/ruby/core/time/now_spec.rb
@@ -53,130 +53,128 @@ describe "Time.now" do
end
it "raises ArgumentError if format is invalid" do
- -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
+ -> { Time.now(in: "+09:99") }.should.raise(ArgumentError)
+ -> { Time.now(in: "ABC") }.should.raise(ArgumentError)
end
it "raises ArgumentError if String argument and hours greater than 23" do
- -> { Time.now(in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now(in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+24:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+2400") }.should.raise(ArgumentError, "utc_offset out of range")
- -> { Time.now(in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
- -> { Time.now(in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+99:00") }.should.raise(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+9900") }.should.raise(ArgumentError, "utc_offset out of range")
end
it "raises ArgumentError if String argument and minutes greater than 59" do
- -> { Time.now(in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
- -> { Time.now(in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+ -> { Time.now(in: "+00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now(in: "+0060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
- -> { Time.now(in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
- -> { Time.now(in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ -> { Time.now(in: "+00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now(in: "+0099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
end
ruby_bug '#20797', ''...'3.4' do
it "raises ArgumentError if String argument and seconds greater than 59" do
- -> { Time.now(in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
- -> { Time.now(in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+ -> { Time.now(in: "+00:00:60") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now(in: "+000060") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
- -> { Time.now(in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
- -> { Time.now(in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ -> { Time.now(in: "+00:00:99") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now(in: "+000099") }.should.raise(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
end
end
- ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
- describe "Timezone object" do
- it "raises TypeError if timezone does not implement #utc_to_local method" do
+ describe "Timezone object" do # https://bugs.ruby-lang.org/issues/17485
+ it "raises TypeError if timezone does not implement #utc_to_local method" do
+ zone = Object.new
+ def zone.local_to_utc(time)
+ time
+ end
+
+ -> {
+ Time.now(in: zone)
+ }.should.raise(TypeError, /can't convert Object into an exact number/)
+ end
+
+ it "does not raise exception if timezone does not implement #local_to_utc method" do
+ zone = Object.new
+ def zone.utc_to_local(time)
+ time
+ end
+
+ Time.now(in: zone).should.is_a?(Time)
+ end
+
+ # The result also should be a Time or Time-like object (not necessary to be the same class)
+ # or Integer. The zone of the result is just ignored.
+ describe "returned value by #utc_to_local and #local_to_utc methods" do
+ it "could be Time instance" do
zone = Object.new
- def zone.local_to_utc(time)
- time
+ def zone.utc_to_local(t)
+ time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
+ time + 60 * 60 # + 1 hour
end
- -> {
- Time.now(in: zone)
- }.should raise_error(TypeError, /can't convert Object into an exact number/)
+ Time.now(in: zone).should.is_a?(Time)
+ Time.now(in: zone).utc_offset.should == 3600
end
- it "does not raise exception if timezone does not implement #local_to_utc method" do
+ it "could be Time subclass instance" do
zone = Object.new
- def zone.utc_to_local(time)
- time
+ def zone.utc_to_local(t)
+ time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
+ time += 60 * 60 # + 1 hour
+
+ Class.new(Time).new(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
end
- Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).should.is_a?(Time)
+ Time.now(in: zone).utc_offset.should == 3600
end
- # The result also should be a Time or Time-like object (not necessary to be the same class)
- # or Integer. The zone of the result is just ignored.
- describe "returned value by #utc_to_local and #local_to_utc methods" do
- it "could be Time instance" do
- zone = Object.new
- def zone.utc_to_local(t)
- time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
- time + 60 * 60 # + 1 hour
- end
-
- Time.now(in: zone).should be_kind_of(Time)
- Time.now(in: zone).utc_offset.should == 3600
+ it "could be Integer" do
+ zone = Object.new
+ def zone.utc_to_local(time)
+ time.to_i + 60*60
end
- it "could be Time subclass instance" do
- zone = Object.new
- def zone.utc_to_local(t)
- time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
- time += 60 * 60 # + 1 hour
-
- Class.new(Time).new(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
- end
+ Time.now(in: zone).should.is_a?(Time)
+ Time.now(in: zone).utc_offset.should == 60*60
+ end
- Time.now(in: zone).should be_kind_of(Time)
- Time.now(in: zone).utc_offset.should == 3600
+ it "could have any #zone and #utc_offset because they are ignored" do
+ zone = Object.new
+ def zone.utc_to_local(t)
+ Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride
+ .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'America/New_York', -5*60*60)
end
+ Time.now(in: zone).utc_offset.should == 0
- it "could be Integer" do
- zone = Object.new
- def zone.utc_to_local(time)
- time.to_i + 60*60
- end
-
- Time.now(in: zone).should be_kind_of(Time)
- Time.now(in: zone).utc_offset.should == 60*60
+ zone = Object.new
+ def zone.utc_to_local(t)
+ Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride
+ .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'Asia/Tokyo', 9*60*60)
end
+ Time.now(in: zone).utc_offset.should == 0
- it "could have any #zone and #utc_offset because they are ignored" do
- zone = Object.new
- def zone.utc_to_local(t)
- Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride
- .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'America/New_York', -5*60*60)
- end
- Time.now(in: zone).utc_offset.should == 0
-
- zone = Object.new
- def zone.utc_to_local(t)
- Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride
- .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'Asia/Tokyo', 9*60*60)
- end
- Time.now(in: zone).utc_offset.should == 0
-
- zone = Object.new
- def zone.utc_to_local(t)
- Time.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, 9*60*60)
- end
- Time.now(in: zone).utc_offset.should == 0
+ zone = Object.new
+ def zone.utc_to_local(t)
+ Time.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, 9*60*60)
end
+ Time.now(in: zone).utc_offset.should == 0
+ end
- it "raises ArgumentError if difference between argument and result is too large" do
- zone = Object.new
- def zone.utc_to_local(t)
- time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
- time -= 24 * 60 * 60 # - 1 day
- Time.utc(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
- end
-
- -> {
- Time.now(in: zone)
- }.should raise_error(ArgumentError, "utc_offset out of range")
+ it "raises ArgumentError if difference between argument and result is too large" do
+ zone = Object.new
+ def zone.utc_to_local(t)
+ time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
+ time -= 24 * 60 * 60 # - 1 day
+ Time.utc(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
end
+
+ -> {
+ Time.now(in: zone)
+ }.should.raise(ArgumentError, "utc_offset out of range")
end
end
end
diff --git a/spec/ruby/core/time/plus_spec.rb b/spec/ruby/core/time/plus_spec.rb
index 642393b615..6bd01bcdf3 100644
--- a/spec/ruby/core/time/plus_spec.rb
+++ b/spec/ruby/core/time/plus_spec.rb
@@ -17,9 +17,9 @@ describe "Time#+" do
end
it "raises a TypeError if given argument is a coercible String" do
- -> { Time.now + "1" }.should raise_error(TypeError)
- -> { Time.now + "0.1" }.should raise_error(TypeError)
- -> { Time.now + "1/3" }.should raise_error(TypeError)
+ -> { Time.now + "1" }.should.raise(TypeError)
+ -> { Time.now + "0.1" }.should.raise(TypeError)
+ -> { Time.now + "1/3" }.should.raise(TypeError)
end
it "increments the time by the specified amount as rational numbers" do
@@ -32,8 +32,8 @@ describe "Time#+" do
end
it "raises TypeError on argument that can't be coerced into Rational" do
- -> { Time.now + Object.new }.should raise_error(TypeError)
- -> { Time.now + "stuff" }.should raise_error(TypeError)
+ -> { Time.now + Object.new }.should.raise(TypeError)
+ -> { Time.now + "stuff" }.should.raise(TypeError)
end
it "returns a UTC time if self is UTC" do
@@ -68,15 +68,15 @@ describe "Time#+" do
it "does not return a subclass instance" do
c = Class.new(Time)
x = c.now + 1
- x.should be_an_instance_of(Time)
+ x.should.instance_of?(Time)
end
it "raises TypeError on Time argument" do
- -> { Time.now + Time.now }.should raise_error(TypeError)
+ -> { Time.now + Time.now }.should.raise(TypeError)
end
it "raises TypeError on nil argument" do
- -> { Time.now + nil }.should raise_error(TypeError)
+ -> { Time.now + nil }.should.raise(TypeError)
end
#see [ruby-dev:38446]
diff --git a/spec/ruby/core/time/round_spec.rb b/spec/ruby/core/time/round_spec.rb
index 0cbed04ade..a739cabfdf 100644
--- a/spec/ruby/core/time/round_spec.rb
+++ b/spec/ruby/core/time/round_spec.rb
@@ -20,8 +20,8 @@ describe "Time#round" do
it "returns an instance of Time, even if #round is called on a subclass" do
subclass = Class.new(Time)
instance = subclass.at(0)
- instance.class.should equal subclass
- instance.round.should be_an_instance_of(Time)
+ instance.class.should.equal? subclass
+ instance.round.should.instance_of?(Time)
end
it "copies own timezone to the returning value" do
diff --git a/spec/ruby/core/time/shared/gmtime.rb b/spec/ruby/core/time/shared/gmtime.rb
index 7b4f65f0b7..aa76b436cc 100644
--- a/spec/ruby/core/time/shared/gmtime.rb
+++ b/spec/ruby/core/time/shared/gmtime.rb
@@ -18,7 +18,7 @@ describe :time_gmtime, shared: true do
it "returns self" do
with_timezone("CST", -6) do
t = Time.local(2007, 1, 9, 12, 0, 0)
- t.send(@method).should equal(t)
+ t.send(@method).should.equal?(t)
end
end
@@ -26,14 +26,14 @@ describe :time_gmtime, shared: true do
it "does not raise an error if already in UTC" do
time = Time.gm(2007, 1, 9, 12, 0, 0)
time.freeze
- time.send(@method).should equal(time)
+ time.send(@method).should.equal?(time)
end
it "raises a FrozenError if the time is not UTC" do
with_timezone("CST", -6) do
time = Time.now
time.freeze
- -> { time.send(@method) }.should raise_error(FrozenError)
+ -> { time.send(@method) }.should.raise(FrozenError)
end
end
end
diff --git a/spec/ruby/core/time/shared/inspect.rb b/spec/ruby/core/time/shared/inspect.rb
index 4133671924..82f7f3c686 100644
--- a/spec/ruby/core/time/shared/inspect.rb
+++ b/spec/ruby/core/time/shared/inspect.rb
@@ -16,6 +16,6 @@ describe :inspect, shared: true do
end
it "returns a US-ASCII encoded string" do
- Time.now.send(@method).encoding.should equal(Encoding::US_ASCII)
+ Time.now.send(@method).encoding.should.equal?(Encoding::US_ASCII)
end
end
diff --git a/spec/ruby/core/time/shared/now.rb b/spec/ruby/core/time/shared/now.rb
index f4018d72f4..839cfdcd2a 100644
--- a/spec/ruby/core/time/shared/now.rb
+++ b/spec/ruby/core/time/shared/now.rb
@@ -2,8 +2,8 @@ require_relative '../fixtures/classes'
describe :time_now, shared: true do
it "creates a subclass instance if called on a subclass" do
- TimeSpecs::SubTime.send(@method).should be_an_instance_of(TimeSpecs::SubTime)
- TimeSpecs::MethodHolder.send(@method).should be_an_instance_of(Time)
+ TimeSpecs::SubTime.send(@method).should.instance_of?(TimeSpecs::SubTime)
+ TimeSpecs::MethodHolder.send(@method).should.instance_of?(Time)
end
it "sets the current time" do
diff --git a/spec/ruby/core/time/shared/time_params.rb b/spec/ruby/core/time/shared/time_params.rb
index b6a6c88c8e..f0de986b8e 100644
--- a/spec/ruby/core/time/shared/time_params.rb
+++ b/spec/ruby/core/time/shared/time_params.rb
@@ -30,7 +30,7 @@ describe :time_params, shared: true do
end
it "raises a TypeError if the year is nil" do
- -> { Time.send(@method, nil) }.should raise_error(TypeError)
+ -> { Time.send(@method, nil) }.should.raise(TypeError)
end
it "accepts nil month, day, hour, minute, and second" do
@@ -148,48 +148,52 @@ describe :time_params, shared: true do
# For some reason MRI uses a different message for month in 13-15 and month>=16
-> {
Time.send(@method, 2008, 16, 31, 23, 59, 59)
- }.should raise_error(ArgumentError, /(mon|argument) out of range/)
+ }.should.raise(ArgumentError, /(mon|argument) out of range/)
end
it "raises an ArgumentError for out of range day" do
-> {
Time.send(@method, 2008, 12, 32, 23, 59, 59)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError for out of range hour" do
-> {
Time.send(@method, 2008, 12, 31, 25, 59, 59)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError for out of range minute" do
-> {
Time.send(@method, 2008, 12, 31, 23, 61, 59)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError for out of range second" do
# For some reason MRI uses different messages for seconds 61-63 and seconds >= 64
-> {
Time.send(@method, 2008, 12, 31, 23, 59, 61)
- }.should raise_error(ArgumentError, /(sec|argument) out of range/)
+ }.should.raise(ArgumentError, /(sec|argument) out of range/)
-> {
Time.send(@method, 2008, 12, 31, 23, 59, -1)
- }.should raise_error(ArgumentError, "argument out of range")
+ }.should.raise(ArgumentError, "argument out of range")
+ end
+
+ it "raises ArgumentError when given 8 arguments" do
+ -> { Time.send(@method, *[0]*8) }.should.raise(ArgumentError)
end
it "raises ArgumentError when given 9 arguments" do
- -> { Time.send(@method, *[0]*9) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, *[0]*9) }.should.raise(ArgumentError)
end
it "raises ArgumentError when given 11 arguments" do
- -> { Time.send(@method, *[0]*11) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, *[0]*11) }.should.raise(ArgumentError)
end
it "returns subclass instances" do
c = Class.new(Time)
- c.send(@method, 2008, "12").should be_an_instance_of(c)
+ c.send(@method, 2008, "12").should.instance_of?(c)
end
end
@@ -209,23 +213,23 @@ describe :time_params_10_arg, shared: true do
it "raises an ArgumentError for out of range values" do
-> {
Time.send(@method, 61, 59, 23, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # sec
+ }.should.raise(ArgumentError) # sec
-> {
Time.send(@method, 59, 61, 23, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # min
+ }.should.raise(ArgumentError) # min
-> {
Time.send(@method, 59, 59, 25, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # hour
+ }.should.raise(ArgumentError) # hour
-> {
Time.send(@method, 59, 59, 23, 32, 12, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # day
+ }.should.raise(ArgumentError) # day
-> {
Time.send(@method, 59, 59, 23, 31, 13, 2008, :ignored, :ignored, :ignored, :ignored)
- }.should raise_error(ArgumentError) # month
+ }.should.raise(ArgumentError) # month
end
end
@@ -236,7 +240,7 @@ describe :time_params_microseconds, shared: true do
end
it "raises an ArgumentError for out of range microsecond" do
- -> { Time.send(@method, 2000, 1, 1, 20, 15, 1, 1000000) }.should raise_error(ArgumentError)
+ -> { Time.send(@method, 2000, 1, 1, 20, 15, 1, 1000000) }.should.raise(ArgumentError)
end
it "handles fractional microseconds as a Float" do
diff --git a/spec/ruby/core/time/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb
index fd233f3577..1528a668a1 100644
--- a/spec/ruby/core/time/strftime_spec.rb
+++ b/spec/ruby/core/time/strftime_spec.rb
@@ -25,7 +25,7 @@ describe "Time#strftime" do
# Differences with date
it "requires an argument" do
- -> { @time.strftime }.should raise_error(ArgumentError)
+ -> { @time.strftime }.should.raise(ArgumentError)
end
# %Z is zone name or empty for Time
diff --git a/spec/ruby/core/time/subsec_spec.rb b/spec/ruby/core/time/subsec_spec.rb
index 0f2c4eb856..3ed1bf5dd1 100644
--- a/spec/ruby/core/time/subsec_spec.rb
+++ b/spec/ruby/core/time/subsec_spec.rb
@@ -2,26 +2,26 @@ require_relative '../../spec_helper'
describe "Time#subsec" do
it "returns 0 as an Integer for a Time with a whole number of seconds" do
- Time.at(100).subsec.should eql(0)
+ Time.at(100).subsec.should.eql?(0)
end
it "returns the fractional seconds as a Rational for a Time constructed with a Rational number of seconds" do
- Time.at(Rational(3, 2)).subsec.should eql(Rational(1, 2))
+ Time.at(Rational(3, 2)).subsec.should.eql?(Rational(1, 2))
end
it "returns the fractional seconds as a Rational for a Time constructed with a Float number of seconds" do
- Time.at(10.75).subsec.should eql(Rational(3, 4))
+ Time.at(10.75).subsec.should.eql?(Rational(3, 4))
end
it "returns the fractional seconds as a Rational for a Time constructed with an Integer number of microseconds" do
- Time.at(0, 999999).subsec.should eql(Rational(999999, 1000000))
+ Time.at(0, 999999).subsec.should.eql?(Rational(999999, 1000000))
end
it "returns the fractional seconds as a Rational for a Time constructed with an Rational number of microseconds" do
- Time.at(0, Rational(9, 10)).subsec.should eql(Rational(9, 10000000))
+ Time.at(0, Rational(9, 10)).subsec.should.eql?(Rational(9, 10000000))
end
it "returns the fractional seconds as a Rational for a Time constructed with an Float number of microseconds" do
- Time.at(0, 0.75).subsec.should eql(Rational(3, 4000000))
+ Time.at(0, 0.75).subsec.should.eql?(Rational(3, 4000000))
end
end
diff --git a/spec/ruby/core/time/to_r_spec.rb b/spec/ruby/core/time/to_r_spec.rb
index 6af2d9b7ea..e30f5d8f94 100644
--- a/spec/ruby/core/time/to_r_spec.rb
+++ b/spec/ruby/core/time/to_r_spec.rb
@@ -2,10 +2,10 @@ require_relative '../../spec_helper'
describe "Time#to_r" do
it "returns the a Rational representing seconds and subseconds since the epoch" do
- Time.at(Rational(11, 10)).to_r.should eql(Rational(11, 10))
+ Time.at(Rational(11, 10)).to_r.should.eql?(Rational(11, 10))
end
it "returns a Rational even for a whole number of seconds" do
- Time.at(2).to_r.should eql(Rational(2))
+ Time.at(2).to_r.should.eql?(Rational(2))
end
end
diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb
index 3d36e13ccf..ab3c0df657 100644
--- a/spec/ruby/core/time/utc_spec.rb
+++ b/spec/ruby/core/time/utc_spec.rb
@@ -43,10 +43,14 @@ describe "Time#utc?" do
it "does not treat time with +00:00 offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, "+00:00").utc?.should == false
+ Time.now.localtime("+00:00").utc?.should == false
+ Time.at(Time.now, in: "+00:00").utc?.should == false
end
it "does not treat time with 0 offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, 0).utc?.should == false
+ Time.now.localtime(0).utc?.should == false
+ Time.at(Time.now, in: 0).utc?.should == false
end
end
diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb
index 9a15bd569b..2cb3c5e7bb 100644
--- a/spec/ruby/core/time/zone_spec.rb
+++ b/spec/ruby/core/time/zone_spec.rb
@@ -6,7 +6,7 @@ describe "Time#zone" do
with_timezone("America/New_York") do
Time.new(2001, 1, 1, 0, 0, 0).zone.should == "EST"
Time.new(2001, 7, 1, 0, 0, 0).zone.should == "EDT"
- %w[EST EDT].should include Time.now.zone
+ %w[EST EDT].should.include? Time.now.zone
end
end
end
@@ -29,7 +29,7 @@ describe "Time#zone" do
t = Time.new(2005, 2, 27, 22, 50, 0, -3600)
with_timezone("America/New_York") do
- t.getlocal("+05:00").zone.should be_nil
+ t.getlocal("+05:00").zone.should == nil
end
end
diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
index 75e9e859a9..475cca29a9 100644
--- a/spec/ruby/core/tracepoint/allow_reentry_spec.rb
+++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
@@ -25,6 +25,6 @@ describe 'TracePoint.allow_reentry' do
it 'raises RuntimeError when not called inside a TracePoint' do
-> {
TracePoint.allow_reentry{}
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/core/tracepoint/binding_spec.rb b/spec/ruby/core/tracepoint/binding_spec.rb
index 6a7ef5f85a..6de6e47d7d 100644
--- a/spec/ruby/core/tracepoint/binding_spec.rb
+++ b/spec/ruby/core/tracepoint/binding_spec.rb
@@ -15,7 +15,7 @@ describe 'TracePoint#binding' do
test
}
bindings.size.should == 1
- bindings[0].should be_kind_of(Binding)
+ bindings[0].should.is_a?(Binding)
bindings[0].local_variables.should == [:secret]
end
end
diff --git a/spec/ruby/core/tracepoint/defined_class_spec.rb b/spec/ruby/core/tracepoint/defined_class_spec.rb
index 4593db6d1f..53c86a8210 100644
--- a/spec/ruby/core/tracepoint/defined_class_spec.rb
+++ b/spec/ruby/core/tracepoint/defined_class_spec.rb
@@ -9,19 +9,19 @@ describe 'TracePoint#defined_class' do
last_class_name = tp.defined_class
end.enable do
TracePointSpec::B.new.foo
- last_class_name.should equal(TracePointSpec::B)
+ last_class_name.should.equal?(TracePointSpec::B)
TracePointSpec::B.new.bar
- last_class_name.should equal(TracePointSpec::A)
+ last_class_name.should.equal?(TracePointSpec::A)
c = TracePointSpec::C.new
- last_class_name.should equal(TracePointSpec::C)
+ last_class_name.should.equal?(TracePointSpec::C)
c.foo
- last_class_name.should equal(TracePointSpec::B)
+ last_class_name.should.equal?(TracePointSpec::B)
c.bar
- last_class_name.should equal(TracePointSpec::A)
+ last_class_name.should.equal?(TracePointSpec::A)
end
end
end
diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb
index 6cc8bb3897..bf61c35154 100644
--- a/spec/ruby/core/tracepoint/enable_spec.rb
+++ b/spec/ruby/core/tracepoint/enable_spec.rb
@@ -54,53 +54,28 @@ describe 'TracePoint#enable' do
TracePoint.new(:line) do |tp|
next unless TracePointSpec.target_thread?
event_name = tp.event
- end.enable { event_name.should equal(:line) }
+ end.enable { event_name.should.equal?(:line) }
end
- ruby_version_is '3.2' do
- it 'enables the trace object only for the current thread' do
- threads = []
- trace = TracePoint.new(:line) do |tp|
- # Runs on purpose on any Thread
- threads << Thread.current
- end
-
- thread = nil
- trace.enable do
- line_event = true
- thread = Thread.new do
- event_in_other_thread = true
- end
- thread.join
- end
-
- threads = threads.uniq
- threads.should.include?(Thread.current)
- threads.should_not.include?(thread)
+ it 'enables the trace object only for the current thread' do
+ threads = []
+ trace = TracePoint.new(:line) do |tp|
+ # Runs on purpose on any Thread
+ threads << Thread.current
end
- end
- ruby_version_is ''...'3.2' do
- it 'enables the trace object for any thread' do
- threads = []
- trace = TracePoint.new(:line) do |tp|
- # Runs on purpose on any Thread
- threads << Thread.current
- end
-
- thread = nil
- trace.enable do
- line_event = true
- thread = Thread.new do
- event_in_other_thread = true
- end
- thread.join
+ thread = nil
+ trace.enable do
+ line_event = true
+ thread = Thread.new do
+ event_in_other_thread = true
end
-
- threads = threads.uniq
- threads.should.include?(Thread.current)
- threads.should.include?(thread)
+ thread.join
end
+
+ threads = threads.uniq
+ threads.should.include?(Thread.current)
+ threads.should_not.include?(thread)
end
it 'can accept arguments within a block but it should not yield arguments' do
@@ -110,7 +85,7 @@ describe 'TracePoint#enable' do
event_name = tp.event
end
trace.enable do |*args|
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
args.should == []
end
trace.should_not.enabled?
@@ -326,7 +301,7 @@ describe 'TracePoint#enable' do
end
ScratchPad.recorded.should == [lineno]
- lineno.should be_kind_of(Integer)
+ lineno.should.is_a?(Integer)
end
end
@@ -342,7 +317,7 @@ describe 'TracePoint#enable' do
trace.enable(target: block) do
block.call # triggers :b_call and :b_return events
end
- }.should raise_error(ArgumentError, /can not enable any hooks/)
+ }.should.raise(ArgumentError, /can not enable any hooks/)
end
it "raises ArgumentError if passed not Method/UnboundMethod/Proc" do
@@ -351,7 +326,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target: Object.new) do
end
- }.should raise_error(ArgumentError, /specified target is not supported/)
+ }.should.raise(ArgumentError, /specified target is not supported/)
end
context "nested enabling and disabling" do
@@ -363,7 +338,7 @@ describe 'TracePoint#enable' do
trace.enable(target: -> {}) do
end
end
- }.should raise_error(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
+ }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
end
it "raises ArgumentError if trace point already enabled without target is re-enabled with target" do
@@ -374,7 +349,7 @@ describe 'TracePoint#enable' do
trace.enable(target: -> {}) do
end
end
- }.should raise_error(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
+ }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
end
it "raises ArgumentError if trace point already enabled with target is re-enabled without target" do
@@ -385,7 +360,7 @@ describe 'TracePoint#enable' do
trace.enable do
end
end
- }.should raise_error(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
+ }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/)
end
it "raises ArgumentError if trace point already enabled with target is disabled with block" do
@@ -396,7 +371,7 @@ describe 'TracePoint#enable' do
trace.disable do
end
end
- }.should raise_error(ArgumentError, /can't disable a targett?ing TracePoint in a block/)
+ }.should.raise(ArgumentError, /can't disable a targett?ing TracePoint in a block/)
end
it "traces events when trace point with target is enabled in another trace point enabled without target" do
@@ -499,7 +474,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: 67) do
end
- }.should raise_error(ArgumentError, /only target_line is specified/)
+ }.should.raise(ArgumentError, /only target_line is specified/)
end
it "raises ArgumentError if :line event isn't registered" do
@@ -516,7 +491,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: target_line, target: target) do
end
- }.should raise_error(ArgumentError, /target_line is specified, but line event is not specified/)
+ }.should.raise(ArgumentError, /target_line is specified, but line event is not specified/)
end
it "raises ArgumentError if :target_line value is out of target code lines range" do
@@ -525,7 +500,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: 1, target: -> { }) do
end
- }.should raise_error(ArgumentError, /can not enable any hooks/)
+ }.should.raise(ArgumentError, /can not enable any hooks/)
end
it "raises TypeError if :target_line value couldn't be coerced to Integer" do
@@ -534,7 +509,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: Object.new, target: -> { }) do
end
- }.should raise_error(TypeError, /no implicit conversion of \w+? into Integer/)
+ }.should.raise(TypeError, /no implicit conversion of \w+? into Integer/)
end
it "raises ArgumentError if :target_line value is negative" do
@@ -543,7 +518,7 @@ describe 'TracePoint#enable' do
-> {
trace.enable(target_line: -2, target: -> { }) do
end
- }.should raise_error(ArgumentError, /can not enable any hooks/)
+ }.should.raise(ArgumentError, /can not enable any hooks/)
end
it "accepts value that could be coerced to Integer" do
diff --git a/spec/ruby/core/tracepoint/event_spec.rb b/spec/ruby/core/tracepoint/event_spec.rb
index 9dea24d125..58017dc98d 100644
--- a/spec/ruby/core/tracepoint/event_spec.rb
+++ b/spec/ruby/core/tracepoint/event_spec.rb
@@ -9,13 +9,13 @@ describe 'TracePoint#event' do
event_name = tp.event
end.enable do
TracePointSpec.test
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
TracePointSpec::B.new.foo
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
class TracePointSpec::B; end
- event_name.should equal(:end)
+ event_name.should.equal?(:end)
end
end
diff --git a/spec/ruby/core/tracepoint/lineno_spec.rb b/spec/ruby/core/tracepoint/lineno_spec.rb
index 77b3ac8b54..7c46d5222b 100644
--- a/spec/ruby/core/tracepoint/lineno_spec.rb
+++ b/spec/ruby/core/tracepoint/lineno_spec.rb
@@ -15,6 +15,6 @@ describe 'TracePoint#lineno' do
it 'raises RuntimeError if accessed from outside' do
tp = TracePoint.new(:line) {}
- -> { tp.lineno }.should raise_error(RuntimeError, 'access from outside')
+ -> { tp.lineno }.should.raise(RuntimeError, 'access from outside')
end
end
diff --git a/spec/ruby/core/tracepoint/method_id_spec.rb b/spec/ruby/core/tracepoint/method_id_spec.rb
index 43e23248b7..67740f2d7d 100644
--- a/spec/ruby/core/tracepoint/method_id_spec.rb
+++ b/spec/ruby/core/tracepoint/method_id_spec.rb
@@ -9,7 +9,7 @@ describe 'TracePoint#method_id' do
method_name = tp.method_id
}.enable do
TracePointSpec.test
- method_name.should equal(:test)
+ method_name.should.equal?(:test)
end
end
end
diff --git a/spec/ruby/core/tracepoint/new_spec.rb b/spec/ruby/core/tracepoint/new_spec.rb
index e53c2b04a2..763b35292b 100644
--- a/spec/ruby/core/tracepoint/new_spec.rb
+++ b/spec/ruby/core/tracepoint/new_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe 'TracePoint.new' do
it 'returns a new TracePoint object, not enabled by default' do
- TracePoint.new(:line) {}.enabled?.should be_false
+ TracePoint.new(:line) {}.enabled?.should == false
end
it 'includes :line event when event is not specified' do
@@ -12,15 +12,15 @@ describe 'TracePoint.new' do
next unless TracePointSpec.target_thread?
event_name = tp.event
}.enable do
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
event_name = nil
TracePointSpec.test
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
event_name = nil
TracePointSpec::B.new.foo
- event_name.should equal(:line)
+ event_name.should.equal?(:line)
end
end
@@ -44,29 +44,29 @@ describe 'TracePoint.new' do
event_name = tp.event
end.enable do
TracePointSpec.test
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
TracePointSpec::B.new.foo
- event_name.should equal(:call)
+ event_name.should.equal?(:call)
class TracePointSpec::B; end
- event_name.should equal(:end)
+ event_name.should.equal?(:end)
end
end
it 'raises a TypeError when the given object is not a string/symbol' do
o = mock('123')
- -> { TracePoint.new(o) {} }.should raise_error(TypeError)
+ -> { TracePoint.new(o) {} }.should.raise(TypeError)
o.should_receive(:to_sym).and_return(123)
- -> { TracePoint.new(o) {} }.should raise_error(TypeError)
+ -> { TracePoint.new(o) {} }.should.raise(TypeError)
end
it 'expects to be called with a block' do
- -> { TracePoint.new(:line) }.should raise_error(ArgumentError, "must be called with a block")
+ -> { TracePoint.new(:line) }.should.raise(ArgumentError, "must be called with a block")
end
it "raises a Argument error when the given argument doesn't match an event name" do
- -> { TracePoint.new(:test) }.should raise_error(ArgumentError, "unknown event: test")
+ -> { TracePoint.new(:test) }.should.raise(ArgumentError, "unknown event: test")
end
end
diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb
index dc2ca840b8..aa6868ead2 100644
--- a/spec/ruby/core/tracepoint/path_spec.rb
+++ b/spec/ruby/core/tracepoint/path_spec.rb
@@ -13,29 +13,14 @@ describe 'TracePoint#path' do
path.should == "#{__FILE__}"
end
- ruby_version_is ""..."3.3" do
- it 'equals (eval) inside an eval for :end event' do
- path = nil
- TracePoint.new(:end) { |tp|
- next unless TracePointSpec.target_thread?
- path = tp.path
- }.enable do
- eval("module TracePointSpec; end")
- end
- path.should == '(eval)'
- end
- end
-
- ruby_version_is "3.3" do
- it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do
- path = nil
- TracePoint.new(:end) { |tp|
- next unless TracePointSpec.target_thread?
- path = tp.path
- }.enable do
- eval("module TracePointSpec; end")
- end
- path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})"
+ it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do
+ path = nil
+ TracePoint.new(:end) { |tp|
+ next unless TracePointSpec.target_thread?
+ path = tp.path
+ }.enable do
+ eval("module TracePointSpec; end")
end
+ path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})"
end
end
diff --git a/spec/ruby/core/tracepoint/raised_exception_spec.rb b/spec/ruby/core/tracepoint/raised_exception_spec.rb
index 5ac8531840..b1199902f2 100644
--- a/spec/ruby/core/tracepoint/raised_exception_spec.rb
+++ b/spec/ruby/core/tracepoint/raised_exception_spec.rb
@@ -14,25 +14,23 @@ describe 'TracePoint#raised_exception' do
rescue => e
error_result = e
end
- raised_exception.should equal(error_result)
+ raised_exception.should.equal?(error_result)
end
end
- ruby_version_is "3.3" do
- it 'returns value from exception rescued on the :rescue event' do
- raised_exception, error_result = nil
- trace = TracePoint.new(:rescue) { |tp|
- next unless TracePointSpec.target_thread?
- raised_exception = tp.raised_exception
- }
- trace.enable do
- begin
- raise StandardError
- rescue => e
- error_result = e
- end
- raised_exception.should equal(error_result)
+ it 'returns value from exception rescued on the :rescue event' do
+ raised_exception, error_result = nil
+ trace = TracePoint.new(:rescue) { |tp|
+ next unless TracePointSpec.target_thread?
+ raised_exception = tp.raised_exception
+ }
+ trace.enable do
+ begin
+ raise StandardError
+ rescue => e
+ error_result = e
end
+ raised_exception.should.equal?(error_result)
end
end
end
diff --git a/spec/ruby/core/tracepoint/self_spec.rb b/spec/ruby/core/tracepoint/self_spec.rb
index 2098860e59..bf9a2b6a45 100644
--- a/spec/ruby/core/tracepoint/self_spec.rb
+++ b/spec/ruby/core/tracepoint/self_spec.rb
@@ -8,7 +8,7 @@ describe 'TracePoint#self' do
next unless TracePointSpec.target_thread?
trace = tp.self
}.enable do
- trace.equal?(self).should be_true
+ trace.equal?(self).should == true
end
end
@@ -21,6 +21,6 @@ describe 'TracePoint#self' do
class TracePointSpec::C
end
end
- trace.should equal TracePointSpec::C
+ trace.should.equal? TracePointSpec::C
end
end
diff --git a/spec/ruby/core/true/dup_spec.rb b/spec/ruby/core/true/dup_spec.rb
index 351457ed22..2628f6d374 100644
--- a/spec/ruby/core/true/dup_spec.rb
+++ b/spec/ruby/core/true/dup_spec.rb
@@ -2,6 +2,6 @@ require_relative '../../spec_helper'
describe "TrueClass#dup" do
it "returns self" do
- true.dup.should equal(true)
+ true.dup.should.equal?(true)
end
end
diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb
index c06793850f..58689fb6e5 100644
--- a/spec/ruby/core/true/singleton_method_spec.rb
+++ b/spec/ruby/core/true/singleton_method_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../spec_helper'
describe "TrueClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether TrueClass defines the method" do
- -> { true.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (true).foo; end
- -> { true.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- TrueClass.send(:remove_method, :foo)
- end
+ it "raises regardless of whether TrueClass defines the method" do
+ -> { true.singleton_method(:foo) }.should.raise(NameError)
+ begin
+ def (true).foo; end
+ -> { true.singleton_method(:foo) }.should.raise(NameError)
+ ensure
+ TrueClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/true/to_s_spec.rb b/spec/ruby/core/true/to_s_spec.rb
index fa1b53a580..2c6f3889e9 100644
--- a/spec/ruby/core/true/to_s_spec.rb
+++ b/spec/ruby/core/true/to_s_spec.rb
@@ -10,6 +10,6 @@ describe "TrueClass#to_s" do
end
it "always returns the same string" do
- true.to_s.should equal(true.to_s)
+ true.to_s.should.equal?(true.to_s)
end
end
diff --git a/spec/ruby/core/true/trueclass_spec.rb b/spec/ruby/core/true/trueclass_spec.rb
index 02af649d09..1c1a0ddbe2 100644
--- a/spec/ruby/core/true/trueclass_spec.rb
+++ b/spec/ruby/core/true/trueclass_spec.rb
@@ -4,12 +4,12 @@ describe "TrueClass" do
it ".allocate raises a TypeError" do
-> do
TrueClass.allocate
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it ".new is undefined" do
-> do
TrueClass.new
- end.should raise_error(NoMethodError)
+ end.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb
index 80b2095d86..ee1dad9c9e 100644
--- a/spec/ruby/core/unboundmethod/bind_call_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb
@@ -12,7 +12,7 @@ describe "UnboundMethod#bind_call" do
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
- -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError)
+ -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should.raise(TypeError)
end
it "binds and calls the method if object is kind_of the Module the method defined in" do
@@ -47,7 +47,7 @@ describe "UnboundMethod#bind_call" do
end
end
um = p.method(:singleton_method).unbind
- ->{ um.bind_call(other) }.should raise_error(TypeError)
+ ->{ um.bind_call(other) }.should.raise(TypeError)
end
it "allows calling super for module methods bound to hierarchies that do not already have that module" do
diff --git a/spec/ruby/core/unboundmethod/bind_spec.rb b/spec/ruby/core/unboundmethod/bind_spec.rb
index 7658b664e5..087994ff57 100644
--- a/spec/ruby/core/unboundmethod/bind_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_spec.rb
@@ -12,15 +12,15 @@ describe "UnboundMethod#bind" do
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
- -> { @normal_um.bind(UnboundMethodSpecs::B.new) }.should raise_error(TypeError)
+ -> { @normal_um.bind(UnboundMethodSpecs::B.new) }.should.raise(TypeError)
end
it "returns Method for any object that is kind_of? the Module method was extracted from" do
- @normal_um.bind(UnboundMethodSpecs::Methods.new).should be_kind_of(Method)
+ @normal_um.bind(UnboundMethodSpecs::Methods.new).should.is_a?(Method)
end
it "returns Method on any object when UnboundMethod is unbound from a module" do
- UnboundMethodSpecs::Mod.instance_method(:from_mod).bind(Object.new).should be_kind_of(Method)
+ UnboundMethodSpecs::Mod.instance_method(:from_mod).bind(Object.new).should.is_a?(Method)
end
it "the returned Method is equal to the one directly returned by obj.method" do
@@ -29,9 +29,9 @@ describe "UnboundMethod#bind" do
end
it "returns Method for any object kind_of? the Module the method is defined in" do
- @parent_um.bind(UnboundMethodSpecs::Child1.new).should be_kind_of(Method)
- @child1_um.bind(UnboundMethodSpecs::Parent.new).should be_kind_of(Method)
- @child2_um.bind(UnboundMethodSpecs::Child1.new).should be_kind_of(Method)
+ @parent_um.bind(UnboundMethodSpecs::Child1.new).should.is_a?(Method)
+ @child1_um.bind(UnboundMethodSpecs::Parent.new).should.is_a?(Method)
+ @child2_um.bind(UnboundMethodSpecs::Child1.new).should.is_a?(Method)
end
it "allows binding a Kernel method retrieved from Object on BasicObject" do
@@ -45,7 +45,7 @@ describe "UnboundMethod#bind" do
it "binds a Parent's class method to any Child's class methods" do
m = UnboundMethodSpecs::Parent.method(:class_method).unbind.bind(UnboundMethodSpecs::Child1)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == "I am UnboundMethodSpecs::Child1"
end
@@ -58,7 +58,7 @@ describe "UnboundMethod#bind" do
end
end
um = p.method(:singleton_method).unbind
- ->{ um.bind(other) }.should raise_error(TypeError)
+ ->{ um.bind(other) }.should.raise(TypeError)
end
it "allows calling super for module methods bound to hierarchies that do not already have that module" do
diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb
index 036c6b7f8c..24d5233299 100644
--- a/spec/ruby/core/unboundmethod/equal_value_spec.rb
+++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
context "Creating UnboundMethods" do
specify "there is no difference between Method#unbind and Module#instance_method" do
- UnboundMethodSpecs::Methods.instance_method(:foo).should be_kind_of(UnboundMethod)
- UnboundMethodSpecs::Methods.new.method(:foo).unbind.should be_kind_of(UnboundMethod)
+ UnboundMethodSpecs::Methods.instance_method(:foo).should.is_a?(UnboundMethod)
+ UnboundMethodSpecs::Methods.new.method(:foo).unbind.should.is_a?(UnboundMethod)
end
end
@@ -35,6 +35,12 @@ describe "UnboundMethod#==" do
@method_one = UnboundMethodSpecs::Methods.instance_method(:one)
@method_two = UnboundMethodSpecs::Methods.instance_method(:two)
+
+ @mixin = UnboundMethodSpecs::Mixin.instance_method(:mixin_method)
+ @includer_base = UnboundMethodSpecs::IncluderBase.new.method(:mixin_method).unbind
+ @includer_child = UnboundMethodSpecs::IncluderChild.new.method(:mixin_method).unbind
+ @extender_base = UnboundMethodSpecs::ExtenderBase.method(:mixin_method).unbind
+ @extender_child = UnboundMethodSpecs::ExtenderChild.method(:mixin_method).unbind
end
it "returns true if objects refer to the same method" do
@@ -76,37 +82,42 @@ describe "UnboundMethod#==" do
(@identical_body == @original_body).should == false
end
- ruby_version_is ""..."3.2" do
- it "returns false if same method but one extracted from a subclass" do
- (@parent == @child1).should == false
- (@child1 == @parent).should == false
- end
+ it "returns true if same method but one extracted from a subclass" do
+ (@parent == @child1).should == true
+ (@child1 == @parent).should == true
+ end
- it "returns false if same method but extracted from two different subclasses" do
- (@child2 == @child1).should == false
- (@child1 == @child2).should == false
- end
+ it "returns true if same method but extracted from two different subclasses" do
+ (@child2 == @child1).should == true
+ (@child1 == @child2).should == true
+ end
- it "returns false if methods are the same but added from an included Module" do
- (@includee == @includer).should == false
- (@includer == @includee).should == false
- end
+ it "returns true if methods are the same but added from an included Module" do
+ (@includee == @includer).should == true
+ (@includer == @includee).should == true
end
- ruby_version_is "3.2" do
- it "returns true if same method but one extracted from a subclass" do
- (@parent == @child1).should == true
- (@child1 == @parent).should == true
- end
+ ruby_bug "#21873", ""..."4.1" do
+ it "returns true if same method is present in an object through module inclusion" do
+ (@mixin == @includer_base).should == true
+ (@includer_base == @mixin).should == true
+
+ (@mixin == @includer_child).should == true
+ (@includer_child == @mixin).should == true
- it "returns false if same method but extracted from two different subclasses" do
- (@child2 == @child1).should == true
- (@child1 == @child2).should == true
+ (@includer_base == @includer_child).should == true
+ (@includer_child == @includer_base).should == true
end
- it "returns true if methods are the same but added from an included Module" do
- (@includee == @includer).should == true
- (@includer == @includee).should == true
+ it "returns true if same method is present in an object through module extension" do
+ (@mixin == @extender_base).should == true
+ (@extender_base == @mixin).should == true
+
+ (@mixin == @extender_child).should == true
+ (@extender_child == @mixin).should == true
+
+ (@extender_base == @extender_child).should == true
+ (@extender_child == @extender_base).should == true
end
end
@@ -129,9 +140,6 @@ describe "UnboundMethod#==" do
c.method(:n).should == Class.instance_method(:new).bind(c)
end
- # On CRuby < 3.2, the 2 specs below pass due to method/instance_method skipping zsuper methods.
- # We are interested in the general pattern working, i.e. the combination of method/instance_method
- # and #== exposes the wanted behavior.
it "considers methods through visibility change equal" do
c = Class.new do
class << self
diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb
index 28d8e0a965..58120c2f88 100644
--- a/spec/ruby/core/unboundmethod/fixtures/classes.rb
+++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb
@@ -36,6 +36,7 @@ module UnboundMethodSpecs
alias bar foo
alias baz bar
+ alias qux baz
alias alias_1 foo
alias alias_2 foo
@@ -80,6 +81,22 @@ module UnboundMethodSpecs
end
end
+ module Mixin
+ def mixin_method; end
+ end
+
+ class IncluderBase
+ include Mixin
+ end
+
+ class IncluderChild < IncluderBase; end
+
+ class ExtenderBase
+ extend Mixin
+ end
+
+ class ExtenderChild < ExtenderBase; end
+
class A
def baz(a, b)
return [__FILE__, self.class]
diff --git a/spec/ruby/core/unboundmethod/inspect_spec.rb b/spec/ruby/core/unboundmethod/inspect_spec.rb
index cecf542fcd..3abed94f7f 100644
--- a/spec/ruby/core/unboundmethod/inspect_spec.rb
+++ b/spec/ruby/core/unboundmethod/inspect_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/to_s'
+require_relative '../method/shared/aliased_inspect'
describe "UnboundMethod#inspect" do
it_behaves_like :unboundmethod_to_s, :inspect
+ it_behaves_like :method_to_s_aliased, :inspect, -> meth { meth.unbind }
end
diff --git a/spec/ruby/core/unboundmethod/original_name_spec.rb b/spec/ruby/core/unboundmethod/original_name_spec.rb
index 7280dcb2b4..cd5f55805d 100644
--- a/spec/ruby/core/unboundmethod/original_name_spec.rb
+++ b/spec/ruby/core/unboundmethod/original_name_spec.rb
@@ -19,4 +19,41 @@ describe "UnboundMethod#original_name" do
obj.method(:baz).unbind.original_name.should == :foo
UnboundMethodSpecs::Methods.instance_method(:baz).original_name.should == :foo
end
+
+ it "returns the original name even when aliased thrice" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:qux).unbind.original_name.should == :foo
+ UnboundMethodSpecs::Methods.instance_method(:qux).original_name.should == :foo
+ end
+
+ it "returns the source UnboundMethod's name (not the name given to define_method)" do
+ klass = Class.new { define_method(:my_inspect, ::Kernel.instance_method(:inspect)) }
+ klass.instance_method(:my_inspect).original_name.should == :inspect
+ end
+
+ it "preserves the source method's name through define_method and alias" do
+ source = Class.new { def my_method; end }
+ klass = Class.new(source) do
+ define_method(:renamed, source.instance_method(:my_method))
+ alias aliased renamed
+ end
+ klass.instance_method(:renamed).original_name.should == :my_method
+ klass.instance_method(:aliased).original_name.should == :my_method
+ end
+
+ it "returns the source UnboundMethod's name for Kernel#is_a? and Kernel#kind_of?" do
+ klass = Class.new { define_method(:my_is_a?, ::Kernel.instance_method(:is_a?)) }
+ klass.instance_method(:my_is_a?).original_name.should == :is_a?
+
+ klass = Class.new { define_method(:my_kind_of?, ::Kernel.instance_method(:kind_of?)) }
+ klass.instance_method(:my_kind_of?).original_name.should == :kind_of?
+ end
+
+ it "preserves the source name when aliasing a define_method'd Kernel method" do
+ klass = Class.new do
+ define_method(:my_is_a?, ::Kernel.instance_method(:is_a?))
+ alias_method :renamed_is_a?, :my_is_a?
+ end
+ klass.instance_method(:renamed_is_a?).original_name.should == :is_a?
+ end
end
diff --git a/spec/ruby/core/unboundmethod/owner_spec.rb b/spec/ruby/core/unboundmethod/owner_spec.rb
index e8a734dac4..b099c56de1 100644
--- a/spec/ruby/core/unboundmethod/owner_spec.rb
+++ b/spec/ruby/core/unboundmethod/owner_spec.rb
@@ -25,9 +25,7 @@ describe "UnboundMethod#owner" do
child_singleton_class.instance_method(:another_class_method).owner.should == child_singleton_class
end
- ruby_version_is "3.2" do
- it "returns the class on which public was called for a private method in ancestor" do
- MethodSpecs::InheritedMethods::C.instance_method(:derp).owner.should == MethodSpecs::InheritedMethods::C
- end
+ it "returns the class on which public was called for a private method in ancestor" do
+ MethodSpecs::InheritedMethods::C.instance_method(:derp).owner.should == MethodSpecs::InheritedMethods::C
end
end
diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb
index 9a890db6fd..5a563939d1 100644
--- a/spec/ruby/core/unboundmethod/private_spec.rb
+++ b/spec/ruby/core/unboundmethod/private_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "UnboundMethod#private?" do
- ruby_version_is ""..."3.2" do
- it "returns false when the method is public" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.private?.should == false
- end
-
- it "returns false when the method is protected" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.private?.should == false
- end
-
- it "returns true when the method is private" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.private?.should == true
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
- end
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
end
end
diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb
index b79e2da63b..70622d658d 100644
--- a/spec/ruby/core/unboundmethod/protected_spec.rb
+++ b/spec/ruby/core/unboundmethod/protected_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "UnboundMethod#protected?" do
- ruby_version_is ""..."3.2" do
- it "returns false when the method is public" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.protected?.should == false
- end
-
- it "returns true when the method is protected" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.protected?.should == true
- end
-
- it "returns false when the method is private" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.protected?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
- end
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
end
end
diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb
index c2a2795a84..ae75e2601c 100644
--- a/spec/ruby/core/unboundmethod/public_spec.rb
+++ b/spec/ruby/core/unboundmethod/public_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "UnboundMethod#public?" do
- ruby_version_is ""..."3.2" do
- it "returns true when the method is public" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.public?.should == true
- end
-
- it "returns false when the method is protected" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.public?.should == false
- end
-
- it "returns false when the method is private" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.public?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
- end
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
end
end
diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb
index 194e2cc1a1..fd30f75c5b 100644
--- a/spec/ruby/core/unboundmethod/shared/dup.rb
+++ b/spec/ruby/core/unboundmethod/shared/dup.rb
@@ -4,7 +4,7 @@ describe :unboundmethod_dup, shared: true do
b = a.send(@method)
a.should == b
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
ruby_version_is "3.4" do
diff --git a/spec/ruby/core/unboundmethod/shared/to_s.rb b/spec/ruby/core/unboundmethod/shared/to_s.rb
index b92bb0b207..848c1eba2e 100644
--- a/spec/ruby/core/unboundmethod/shared/to_s.rb
+++ b/spec/ruby/core/unboundmethod/shared/to_s.rb
@@ -8,8 +8,8 @@ describe :unboundmethod_to_s, shared: true do
end
it "returns a String" do
- @from_module.send(@method).should be_kind_of(String)
- @from_method.send(@method).should be_kind_of(String)
+ @from_module.send(@method).should.is_a?(String)
+ @from_method.send(@method).should.is_a?(String)
end
it "the String reflects that this is an UnboundMethod object" do
@@ -20,22 +20,11 @@ describe :unboundmethod_to_s, shared: true do
it "the String shows the method name, Module defined in and Module extracted from" do
@from_module.send(@method).should =~ /\bfrom_mod\b/
@from_module.send(@method).should =~ /\bUnboundMethodSpecs::Mod\b/
-
- ruby_version_is ""..."3.2" do
- @from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\b/
- end
end
it "returns a String including all details" do
- ruby_version_is ""..."3.2" do
- @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod"
- @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod"
- end
-
- ruby_version_is "3.2" do
- @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
- @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
- end
+ @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
+ @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
end
it "does not show the defining module if it is the same as the origin" do
diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb
index 2391d07d99..927600bfcb 100644
--- a/spec/ruby/core/unboundmethod/source_location_spec.rb
+++ b/spec/ruby/core/unboundmethod/source_location_spec.rb
@@ -7,23 +7,23 @@ describe "UnboundMethod#source_location" do
end
it "sets the first value to the path of the file in which the method was defined" do
- file = @method.source_location[0]
- file.should be_an_instance_of(String)
+ file = @method.source_location.first
+ file.should.instance_of?(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end
- it "sets the second value to an Integer representing the line on which the method was defined" do
- line = @method.source_location[1]
- line.should be_an_instance_of(Integer)
+ it "sets the last value to an Integer representing the line on which the method was defined" do
+ line = @method.source_location.last
+ line.should.instance_of?(Integer)
line.should == 5
end
it "returns the last place the method was defined" do
- UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location[1].should == 13
+ UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location.last.should == 13
end
it "returns the location of the original method even if it was aliased" do
- UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location[1].should == 17
+ UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location.last.should == 17
end
it "works for define_method methods" do
@@ -54,12 +54,6 @@ describe "UnboundMethod#source_location" do
c = Class.new do
eval('def m; end', nil, "foo", 100)
end
- location = c.instance_method(:m).source_location
- ruby_version_is(""..."3.5") do
- location.should == ["foo", 100]
- end
- ruby_version_is("3.5") do
- location.should == ["foo", 100, 0, 100, 10]
- end
+ c.instance_method(:m).source_location.should == ["foo", 100]
end
end
diff --git a/spec/ruby/core/unboundmethod/to_s_spec.rb b/spec/ruby/core/unboundmethod/to_s_spec.rb
index a508229b49..615d88675b 100644
--- a/spec/ruby/core/unboundmethod/to_s_spec.rb
+++ b/spec/ruby/core/unboundmethod/to_s_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/to_s'
+require_relative '../method/shared/aliased_inspect'
describe "UnboundMethod#to_s" do
it_behaves_like :unboundmethod_to_s, :to_s
+ it_behaves_like :method_to_s_aliased, :to_s, -> meth { meth.unbind }
end
diff --git a/spec/ruby/core/warning/categories_spec.rb b/spec/ruby/core/warning/categories_spec.rb
new file mode 100644
index 0000000000..1e310ef38b
--- /dev/null
+++ b/spec/ruby/core/warning/categories_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "Warning.categories" do
+ # There might be more, but these are standard across Ruby implementations
+ it "returns the list of possible warning categories" do
+ Warning.categories.should.include? :deprecated
+ Warning.categories.should.include? :experimental
+ Warning.categories.should.include? :performance
+ end
+ end
+end
diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb
index c0ed37ef13..5f977759ec 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -10,20 +10,18 @@ describe "Warning.[]" do
ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]"
end
- ruby_version_is '3.3' do
- it "returns default values for :performance category" do
- ruby_exe('p Warning[:performance]').chomp.should == "false"
- ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false"
- end
+ it "returns default values for :performance category" do
+ ruby_exe('p Warning[:performance]').chomp.should == "false"
+ ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false"
end
it "raises for unknown category" do
- -> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/)
+ -> { Warning[:noop] }.should.raise(ArgumentError, /unknown category: noop/)
end
it "raises for non-Symbol category" do
- -> { Warning[42] }.should raise_error(TypeError)
- -> { Warning[false] }.should raise_error(TypeError)
- -> { Warning["noop"] }.should raise_error(TypeError)
+ -> { Warning[42] }.should.raise(TypeError)
+ -> { Warning[false] }.should.raise(TypeError)
+ -> { Warning["noop"] }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb
index d59a7d4c9e..3c8ceb721e 100644
--- a/spec/ruby/core/warning/element_set_spec.rb
+++ b/spec/ruby/core/warning/element_set_spec.rb
@@ -17,25 +17,23 @@ describe "Warning.[]=" do
end
end
- ruby_version_is '3.3' do
- it "enables or disables performance warnings" do
- original = Warning[:performance]
- begin
- Warning[:performance] = !original
- Warning[:performance].should == !original
- ensure
- Warning[:performance] = original
- end
+ it "enables or disables performance warnings" do
+ original = Warning[:performance]
+ begin
+ Warning[:performance] = !original
+ Warning[:performance].should == !original
+ ensure
+ Warning[:performance] = original
end
end
it "raises for unknown category" do
- -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/)
+ -> { Warning[:noop] = false }.should.raise(ArgumentError, /unknown category: noop/)
end
it "raises for non-Symbol category" do
- -> { Warning[42] = false }.should raise_error(TypeError)
- -> { Warning[false] = false }.should raise_error(TypeError)
- -> { Warning["noop"] = false }.should raise_error(TypeError)
+ -> { Warning[42] = false }.should.raise(TypeError)
+ -> { Warning[false] = false }.should.raise(TypeError)
+ -> { Warning["noop"] = false }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 572885c2b4..62f36e3454 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -16,7 +16,7 @@ describe "Warning.warn" do
end
it "extends itself" do
- Warning.singleton_class.ancestors.should include(Warning)
+ Warning.singleton_class.ancestors.should.include?(Warning)
end
it "has Warning as the method owner" do
@@ -97,6 +97,20 @@ describe "Warning.warn" do
end
end
+ ruby_version_is "3.4" do
+ it "warns when category is :strict_unused_block but Warning[:strict_unused_block] is false" do
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :strict_unused_block)
+ }.should complain("foo")
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+
it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do
warn_deprecated = Warning[:deprecated]
Warning[:deprecated] = false
@@ -121,6 +135,20 @@ describe "Warning.warn" do
end
end
+ ruby_version_is "3.4" do
+ it "doesn't print message when category is :strict_unused_block but Warning[:strict_unused_block] is false" do
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :strict_unused_block)
+ }.should_not complain
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+
ruby_bug '#20573', ''...'3.4' do
it "isn't called by Kernel.warn when category is :deprecated but Warning[:deprecated] is false" do
warn_deprecated = Warning[:deprecated]
diff --git a/spec/ruby/default.mspec b/spec/ruby/default.mspec
index 1e8f8893aa..c8b1215f56 100644
--- a/spec/ruby/default.mspec
+++ b/spec/ruby/default.mspec
@@ -20,8 +20,11 @@ class MSpecScript
# C extension API specs
set :capi, [ 'optional/capi' ]
+ # Thread safety specs
+ set :thread_safety, [ 'optional/thread_safety' ]
+
# A list of _all_ optional specs
- set :optional, get(:capi)
+ set :optional, get(:capi) + get(:thread_safety)
# An ordered list of the directories containing specs to run
set :files, get(:command_line) + get(:language) + get(:core) + get(:library) + get(:security) + get(:optional)
diff --git a/spec/ruby/language/BEGIN_spec.rb b/spec/ruby/language/BEGIN_spec.rb
index 5aef5a1d7c..25db32b96a 100644
--- a/spec/ruby/language/BEGIN_spec.rb
+++ b/spec/ruby/language/BEGIN_spec.rb
@@ -15,7 +15,7 @@ describe "The BEGIN keyword" do
end
it "must appear in a top-level context" do
- -> { eval "1.times { BEGIN { 1 } }" }.should raise_error(SyntaxError)
+ -> { eval "1.times { BEGIN { 1 } }" }.should.raise(SyntaxError)
end
it "uses top-level for self" do
diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb
index 61fddb0184..4b3d36d308 100644
--- a/spec/ruby/language/alias_spec.rb
+++ b/spec/ruby/language/alias_spec.rb
@@ -140,7 +140,7 @@ describe "The alias keyword" do
end
@obj.__value.should == 5
- -> { AliasObject.new.__value }.should raise_error(NoMethodError)
+ -> { AliasObject.new.__value }.should.raise(NoMethodError)
end
it "operates on the class/module metaclass when used in instance_eval" do
@@ -149,7 +149,7 @@ describe "The alias keyword" do
end
AliasObject.__klass_method.should == 7
- -> { Object.__klass_method }.should raise_error(NoMethodError)
+ -> { Object.__klass_method }.should.raise(NoMethodError)
end
it "operates on the class/module metaclass when used in instance_exec" do
@@ -158,7 +158,7 @@ describe "The alias keyword" do
end
AliasObject.__klass_method2.should == 7
- -> { Object.__klass_method2 }.should raise_error(NoMethodError)
+ -> { Object.__klass_method2 }.should.raise(NoMethodError)
end
it "operates on methods defined via attr, attr_reader, and attr_accessor" do
@@ -241,13 +241,13 @@ describe "The alias keyword" do
1.instance_eval do
alias :foo :to_s
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
-> do
:blah.instance_eval do
alias :foo :to_s
end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "on top level defines the alias on Object" do
@@ -256,7 +256,7 @@ describe "The alias keyword" do
end
it "raises a NameError when passed a missing name" do
- -> { @meta.class_eval { alias undef_method not_exist } }.should raise_error(NameError) { |e|
+ -> { @meta.class_eval { alias undef_method not_exist } }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -272,7 +272,7 @@ describe "The alias keyword" do
end
child.instance_method(:parent_method_alias).owner.should == child
- child.instance_methods(false).should include(:parent_method_alias)
+ child.instance_methods(false).should.include?(:parent_method_alias)
end
end
diff --git a/spec/ruby/language/and_spec.rb b/spec/ruby/language/and_spec.rb
index 55a2a3103a..c5c255989b 100644
--- a/spec/ruby/language/and_spec.rb
+++ b/spec/ruby/language/and_spec.rb
@@ -5,7 +5,7 @@ describe "The '&&' statement" do
it "short-circuits evaluation at the first condition to be false" do
x = nil
true && false && x = 1
- x.should be_nil
+ x.should == nil
end
it "evaluates to the first condition not to be true" do
@@ -33,9 +33,9 @@ describe "The '&&' statement" do
end
it "treats empty expressions as nil" do
- (() && true).should be_nil
- (true && ()).should be_nil
- (() && ()).should be_nil
+ (() && true).should == nil
+ (true && ()).should == nil
+ (() && ()).should == nil
end
end
@@ -44,7 +44,7 @@ describe "The 'and' statement" do
it "short-circuits evaluation at the first condition to be false" do
x = nil
true and false and x = 1
- x.should be_nil
+ x.should == nil
end
it "evaluates to the first condition not to be true" do
@@ -72,9 +72,9 @@ describe "The 'and' statement" do
end
it "treats empty expressions as nil" do
- (() and true).should be_nil
- (true and ()).should be_nil
- (() and ()).should be_nil
+ (() and true).should == nil
+ (true and ()).should == nil
+ (() and ()).should == nil
end
end
diff --git a/spec/ruby/language/array_spec.rb b/spec/ruby/language/array_spec.rb
index 2583cffbf7..78cf36c201 100644
--- a/spec/ruby/language/array_spec.rb
+++ b/spec/ruby/language/array_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/array'
describe "Array literals" do
it "[] should return a new array populated with the given elements" do
array = [1, 'a', nil]
- array.should be_kind_of(Array)
+ array.should.is_a?(Array)
array[0].should == 1
array[1].should == 'a'
array[2].should == nil
@@ -12,7 +12,7 @@ describe "Array literals" do
it "[] treats empty expressions as nil elements" do
array = [0, (), 2, (), 4]
- array.should be_kind_of(Array)
+ array.should.is_a?(Array)
array[0].should == 0
array[1].should == nil
array[2].should == 2
@@ -89,7 +89,7 @@ describe "The unpacking splat operator (*)" do
it "returns a new array containing the same values when applied to an array inside an empty array" do
splatted_array = [3, 4, 5]
[*splatted_array].should == splatted_array
- [*splatted_array].should_not equal(splatted_array)
+ [*splatted_array].should_not.equal?(splatted_array)
end
it "unpacks the start and count arguments in an array slice assignment" do
@@ -135,7 +135,7 @@ describe "The unpacking splat operator (*)" do
it "when applied to a non-Array value uses it unchanged if it does not respond_to?(:to_a)" do
obj = Object.new
- obj.should_not respond_to(:to_a)
+ obj.should_not.respond_to?(:to_a)
[1, *obj].should == [1, obj]
end
@@ -155,8 +155,12 @@ describe "The unpacking splat operator (*)" do
b = [1, 0]
[*a, 3, *a, *b].should == [1, 2, 3, 1, 2, 1, 0]
end
-end
-
-describe "The packing splat operator (*)" do
+ ruby_version_is "4.0" do
+ it "does not call #to_a on nil" do
+ e = nil
+ e.should_not_receive(:to_a)
+ [*e].should == []
+ end
+ end
end
diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb
index 222d8699c5..d621c9f0c6 100644
--- a/spec/ruby/language/assignments_spec.rb
+++ b/spec/ruby/language/assignments_spec.rb
@@ -23,25 +23,12 @@ describe 'Assignments' do
ScratchPad.recorded.should == [:receiver, :argument, :rhs]
end
- # similar tests for evaluation order are located in language/constants_spec.rb
- ruby_version_is ''...'3.2' do
- it 'evaluates expressions right to left when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
- ScratchPad.recorded.should == [:rhs, :module]
- end
- end
-
- ruby_version_is '3.2' do
- it 'evaluates expressions left to right when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
+ it 'evaluates expressions left to right when assignment with compounded constant' do
+ m = Module.new
+ ScratchPad.record []
- (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
- ScratchPad.recorded.should == [:module, :rhs]
- end
+ (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
+ ScratchPad.recorded.should == [:module, :rhs]
end
it 'raises TypeError after evaluation of right-hand-side when compounded constant module is not a module' do
@@ -49,11 +36,70 @@ describe 'Assignments' do
-> {
(:not_a_module)::A = (ScratchPad << :rhs; :value)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
ScratchPad.recorded.should == [:rhs]
end
end
+
+ context "given block argument" do
+ before do
+ @klass = Class.new do
+ def initialize(h) @h = h end
+ def [](k, &block) @h[k]; end
+ def []=(k, v, &block) @h[k] = v; end
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "accepts block argument" do
+ obj = @klass.new(a: 1)
+ block = proc {}
+
+ eval "obj[:a, &block] = 2"
+ eval("obj[:a, &block]").should == 2
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises SyntaxError" do
+ obj = @klass.new(a: 1)
+ block = proc {}
+
+ -> {
+ eval "obj[:a, &block] = 2"
+ }.should.raise(SyntaxError, /unexpected block arg given in index assignment|block arg given in index assignment/)
+ end
+ end
+ end
+
+ context "given keyword arguments" do
+ before do
+ @klass = Class.new do
+ attr_reader :x
+
+ def []=(*args, **kw)
+ @x = [args, kw]
+ end
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "supports keyword arguments in index assignments" do
+ a = @klass.new
+ eval "a[1, 2, 3, b: 4] = 5"
+ a.x.should == [[1, 2, 3, {b: 4}, 5], {}]
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises SyntaxError when given keyword arguments in index assignments" do
+ a = @klass.new
+ -> { eval "a[1, 2, 3, b: 4] = 5" }.should.raise(SyntaxError,
+ /keywords are not allowed in index assignment expressions|keyword arg given in index assignment/) # prism|parse.y
+ end
+ end
+ end
end
describe 'using +=' do
@@ -127,6 +173,69 @@ describe 'Assignments' do
a.public_method(:k, 2).should == 2
end
+ context "given block argument" do
+ before do
+ @klass = Class.new do
+ def initialize(h) @h = h end
+ def [](k, &block) @h[k]; end
+ def []=(k, v, &block) @h[k] = v; end
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "accepts block argument" do
+ obj = @klass.new(a: 1)
+ block = proc {}
+
+ eval "obj[:a, &block] += 2"
+ eval("obj[:a, &block]").should == 3
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises SyntaxError" do
+ obj = @klass.new(a: 1)
+ block = proc {}
+
+ -> {
+ eval "obj[:a, &block] += 2"
+ }.should.raise(SyntaxError, /unexpected block arg given in index assignment|block arg given in index assignment/)
+ end
+ end
+ end
+
+ context "given keyword arguments" do
+ before do
+ @klass = Class.new do
+ attr_reader :x
+
+ def [](*args)
+ 100
+ end
+
+ def []=(*args, **kw)
+ @x = [args, kw]
+ end
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "supports keyword arguments in index assignments" do
+ a = @klass.new
+ eval "a[1, 2, 3, b: 4] += 5"
+ a.x.should == [[1, 2, 3, 105], {b: 4}]
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises SyntaxError when given keyword arguments in index assignments" do
+ a = @klass.new
+ -> { eval "a[1, 2, 3, b: 4] += 5" }.should.raise(SyntaxError,
+ /keywords are not allowed in index assignment expressions|keyword arg given in index assignment/) # prism|parse.y
+ end
+ end
+ end
+
context 'splatted argument' do
it 'correctly handles it' do
@b[:m] = 10
@@ -345,45 +454,33 @@ describe 'Multiple assignments' do
ScratchPad.recorded.should == [:ra, :aa, :rb, :ab, :rc, :ac, :rd, :ad, :re, :ae, :rf, :af, :value]
end
- ruby_version_is ''...'3.2' do
- it 'evaluates expressions right to left when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
+ it 'evaluates expressions left to right when assignment with compounded constant' do
+ m = Module.new
+ ScratchPad.record []
- (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
- ScratchPad.recorded.should == [:c, :d, :a, :b]
- end
+ (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
+ ScratchPad.recorded.should == [:a, :b, :c, :d]
end
- ruby_version_is '3.2' do
- it 'evaluates expressions left to right when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
- ScratchPad.recorded.should == [:a, :b, :c, :d]
- end
-
- it 'evaluates expressions left to right when assignment with a nested compounded constant' do
- m = Module.new
- ScratchPad.record []
+ it 'evaluates expressions left to right when assignment with a nested compounded constant' do
+ m = Module.new
+ ScratchPad.record []
- ((ScratchPad << :a; m)::A, foo), bar = [(ScratchPad << :b; :b)]
- ScratchPad.recorded.should == [:a, :b]
- end
+ ((ScratchPad << :a; m)::A, foo), bar = [(ScratchPad << :b; :b)]
+ ScratchPad.recorded.should == [:a, :b]
+ end
- it 'evaluates expressions left to right when assignment with deeply nested compounded constants' do
- m = Module.new
- ScratchPad.record []
+ it 'evaluates expressions left to right when assignment with deeply nested compounded constants' do
+ m = Module.new
+ ScratchPad.record []
- (ScratchPad << :a; m)::A,
- ((ScratchPad << :b; m)::B,
- ((ScratchPad << :c; m)::C, (ScratchPad << :d; m)::D),
- (ScratchPad << :e; m)::E),
- (ScratchPad << :f; m)::F = (ScratchPad << :value; :value)
+ (ScratchPad << :a; m)::A,
+ ((ScratchPad << :b; m)::B,
+ ((ScratchPad << :c; m)::C, (ScratchPad << :d; m)::D),
+ (ScratchPad << :e; m)::E),
+ (ScratchPad << :f; m)::F = (ScratchPad << :value; :value)
- ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
- end
+ ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
end
end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index 1a73b415f2..5bdb993aea 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -13,7 +13,7 @@ describe "A block yielded a single" do
it "receives the identical Array object" do
ary = [1, 2]
- m(ary) { |a| a }.should equal(ary)
+ m(ary) { |a| a }.should.equal?(ary)
end
it "assigns the Array to a single rest argument" do
@@ -62,37 +62,18 @@ describe "A block yielded a single" do
m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [4], 5, 6]
end
- ruby_version_is "3.2" do
- it "does not autosplat single argument to required arguments when a keyword rest argument is present" do
- m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}]
- end
-
- it "does not autosplat single argument to required arguments when keyword arguments are present" do
- m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [[1, 2], :b, :c]
- end
-
- it "raises error when required keyword arguments are present" do
- -> {
- m([1, 2]) { |a, b:, c:| [a, b, c] }
- }.should raise_error(ArgumentError, "missing keywords: :b, :c")
- end
+ it "does not autosplat single argument to required arguments when a keyword rest argument is present" do
+ m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}]
end
- ruby_version_is ''..."3.2" do
- # https://bugs.ruby-lang.org/issues/18633
- it "autosplats single argument to required arguments when a keyword rest argument is present" do
- m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
- end
-
- it "autosplats single argument to required arguments when optional keyword arguments are present" do
- m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [1, :b, :c]
- end
+ it "does not autosplat single argument to required arguments when keyword arguments are present" do
+ m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [[1, 2], :b, :c]
+ end
- it "raises error when required keyword arguments are present" do
- -> {
- m([1, 2]) { |a, b:, c:| [a, b, c] }
- }.should raise_error(ArgumentError, "missing keywords: :b, :c")
- end
+ it "raises error when required keyword arguments are present" do
+ -> {
+ m([1, 2]) { |a, b:, c:| [a, b, c] }
+ }.should.raise(ArgumentError, "missing keywords: :b, :c")
end
it "assigns elements to mixed argument types" do
@@ -211,6 +192,22 @@ describe "A block yielded a single" do
m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
end
+ it "calls #respond_to? on a BasicObject to check if object has method #to_ary" do
+ ScratchPad.record []
+ obj = BasicObject.new
+ def obj.respond_to?(name, *)
+ ScratchPad << [:respond_to?, name]
+ name == :to_ary ? true : super
+ end
+ def obj.to_ary
+ ScratchPad << :to_ary
+ [1, 2]
+ end
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
+ ScratchPad.recorded.should == [[:respond_to?, :to_ary], :to_ary]
+ end
+
it "receives the object if it does not respond to #respond_to?" do
obj = BasicObject.new
@@ -237,14 +234,14 @@ describe "A block yielded a single" do
obj = mock("destructure block arguments")
obj.should_receive(:to_ary).and_return(1)
- -> { m(obj) { |a, b| } }.should raise_error(TypeError)
+ -> { m(obj) { |a, b| } }.should.raise(TypeError)
end
it "raises error transparently if #to_ary raises error on its own" do
obj = Object.new
def obj.to_ary; raise "Exception raised in #to_ary" end
- -> { m(obj) { |a, b| } }.should raise_error(RuntimeError, "Exception raised in #to_ary")
+ -> { m(obj) { |a, b| } }.should.raise(RuntimeError, "Exception raised in #to_ary")
end
end
end
@@ -314,7 +311,7 @@ describe "A block" do
describe "taking |a| arguments" do
it "assigns nil to the argument when no values are yielded" do
- @y.z { |a| a }.should be_nil
+ @y.z { |a| a }.should == nil
end
it "assigns the value yielded to the argument" do
@@ -325,7 +322,7 @@ describe "A block" do
obj = mock("block yield to_ary")
obj.should_not_receive(:to_ary)
- @y.s(obj) { |a| a }.should equal(obj)
+ @y.s(obj) { |a| a }.should.equal?(obj)
end
it "assigns the first value yielded to the argument" do
@@ -401,14 +398,14 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, b| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, b| } }.should.raise(TypeError)
end
it "raises the original exception if #to_ary raises an exception" do
obj = mock("block yield to_ary raising an exception")
obj.should_receive(:to_ary).and_raise(ZeroDivisionError)
- -> { @y.s(obj) { |a, b| } }.should raise_error(ZeroDivisionError)
+ -> { @y.s(obj) { |a, b| } }.should.raise(ZeroDivisionError)
end
end
@@ -464,7 +461,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, *b| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, *b| } }.should.raise(TypeError)
end
end
@@ -542,7 +539,7 @@ describe "A block" do
describe "taking |a, | arguments" do
it "assigns nil to the argument when no values are yielded" do
- @y.z { |a, | a }.should be_nil
+ @y.z { |a, | a }.should == nil
end
it "assigns the argument a single value yielded" do
@@ -558,7 +555,7 @@ describe "A block" do
end
it "assigns nil to the argument when passed an empty Array" do
- @y.s([]) { |a, | a }.should be_nil
+ @y.s([]) { |a, | a }.should == nil
end
it "assigns the argument the first element of the Array when passed a single Array" do
@@ -589,7 +586,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, | } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, | } }.should.raise(TypeError)
end
end
@@ -631,7 +628,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |(a, b)| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |(a, b)| } }.should.raise(TypeError)
end
end
@@ -672,7 +669,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |(a, b), c| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |(a, b), c| } }.should.raise(TypeError)
end
end
@@ -731,15 +728,15 @@ describe "A block" do
describe "taking identically-named arguments" do
it "raises a SyntaxError for standard arguments" do
- -> { eval "lambda { |x,x| }" }.should raise_error(SyntaxError)
- -> { eval "->(x,x) {}" }.should raise_error(SyntaxError)
- -> { eval "Proc.new { |x,x| }" }.should raise_error(SyntaxError)
+ -> { eval "lambda { |x,x| }" }.should.raise(SyntaxError)
+ -> { eval "->(x,x) {}" }.should.raise(SyntaxError)
+ -> { eval "Proc.new { |x,x| }" }.should.raise(SyntaxError)
end
it "accepts unnamed arguments" do
- lambda { |_,_| }.should be_an_instance_of(Proc) # rubocop:disable Style/Lambda
- -> _,_ {}.should be_an_instance_of(Proc)
- Proc.new { |_,_| }.should be_an_instance_of(Proc)
+ lambda { |_,_| }.should.instance_of?(Proc) # rubocop:disable Style/Lambda
+ -> _,_ {}.should.instance_of?(Proc)
+ Proc.new { |_,_| }.should.instance_of?(Proc)
end
end
@@ -790,29 +787,29 @@ describe "Block-local variables" do
end
it "can not have the same name as one of the standard parameters" do
- -> { eval "[1].each {|foo; foo| }" }.should raise_error(SyntaxError)
- -> { eval "[1].each {|foo, bar; glark, bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; foo| }" }.should.raise(SyntaxError)
+ -> { eval "[1].each {|foo, bar; glark, bar| }" }.should.raise(SyntaxError)
end
it "can not be prefixed with an asterisk" do
- -> { eval "[1].each {|foo; *bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; *bar| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, *fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "can not be prefixed with an ampersand" do
- -> { eval "[1].each {|foo; &bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; &bar| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, &fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "can not be assigned default values" do
- -> { eval "[1].each {|foo; bar=1| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; bar=1| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, fnord=:fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "need not be preceded by standard parameters" do
@@ -821,8 +818,8 @@ describe "Block-local variables" do
end
it "only allow a single semi-colon in the parameter list" do
- -> { eval "[1].each {|foo; bar; glark| }" }.should raise_error(SyntaxError)
- -> { eval "[1].each {|; bar; glark| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; bar; glark| }" }.should.raise(SyntaxError)
+ -> { eval "[1].each {|; bar; glark| }" }.should.raise(SyntaxError)
end
it "override shadowed variables from the outer scope" do
@@ -847,21 +844,21 @@ describe "Block-local variables" do
end
it "are not automatically instantiated in the outer scope" do
- defined?(glark).should be_nil
+ defined?(glark).should == nil
[1].each {|;glark| 1}
- defined?(glark).should be_nil
+ defined?(glark).should == nil
end
it "are automatically instantiated in the block" do
[1].each do |;glark|
- glark.should be_nil
+ glark.should == nil
end
end
it "are visible in deeper scopes before initialization" do
[1].each {|;glark|
[1].each {
- defined?(glark).should_not be_nil
+ defined?(glark).should_not == nil
glark = 1
}
glark.should == 1
@@ -889,7 +886,7 @@ describe "Post-args" do
-> *a, b do
[a, b]
end.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "are assigned to nil when not enough arguments are given to a proc" do
@@ -965,7 +962,7 @@ describe "Post-args" do
a = 1
-> {
eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -1009,7 +1006,7 @@ describe "Anonymous block forwarding" do
end
it "requires the anonymous block parameter to be declared if directly passing a block" do
- -> { eval "def a; b(&); end; def b; end" }.should raise_error(SyntaxError)
+ -> { eval "def a; b(&); end; def b; end" }.should.raise(SyntaxError)
end
it "works when it's the only declared parameter" do
@@ -1040,36 +1037,40 @@ describe "Anonymous block forwarding" do
no_kw(:a) { 1 }.should == 1
end
- ruby_version_is "3.2" do
- it "works alongside explicit keyword arguments" do
- eval <<-EOF
- def inner; yield end
- def rest_kw(*a, kwarg: 1, &); inner(&) end
- def kw(kwarg: 1, &); inner(&) end
- def pos_kw_kwrest(arg1, kwarg: 1, **kw, &); inner(&) end
- def pos_rkw(arg1, kwarg1:, &); inner(&) end
- def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &); inner(&) end
- def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &); inner(&) end
- EOF
-
- rest_kw { 1 }.should == 1
- kw { 1 }.should == 1
- pos_kw_kwrest(:a) { 1 }.should == 1
- pos_rkw(:a, kwarg1: 3) { 1 }.should == 1
- all(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
- all_kwrest(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
- end
+ it "works alongside explicit keyword arguments" do
+ eval <<-EOF
+ def inner; yield end
+ def rest_kw(*a, kwarg: 1, &); inner(&) end
+ def kw(kwarg: 1, &); inner(&) end
+ def pos_kw_kwrest(arg1, kwarg: 1, **kw, &); inner(&) end
+ def pos_rkw(arg1, kwarg1:, &); inner(&) end
+ def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &); inner(&) end
+ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &); inner(&) end
+ EOF
+
+ rest_kw { 1 }.should == 1
+ kw { 1 }.should == 1
+ pos_kw_kwrest(:a) { 1 }.should == 1
+ pos_rkw(:a, kwarg1: 3) { 1 }.should == 1
+ all(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
+ all_kwrest(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
end
end
-describe "`it` calls without arguments in a block with no ordinary parameters" do
- ruby_version_is "3.3"..."3.4" do
+describe "`it` calls without arguments in a block" do
+ ruby_version_is ""..."3.4" do
it "emits a deprecation warning" do
-> {
eval "proc { it }"
}.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
end
+ it "emits a deprecation warning if numbered parameters are used" do
+ -> {
+ eval "proc { it; _1 }"
+ }.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
+ end
+
it "does not emit a deprecation warning when a block has parameters" do
-> { eval "proc { |a, b| it }" }.should_not complain
-> { eval "proc { |*rest| it }" }.should_not complain
@@ -1079,14 +1080,69 @@ describe "`it` calls without arguments in a block with no ordinary parameters" d
-> { eval "proc { |**| it }" }.should_not complain
-> { eval "proc { |&block| it }" }.should_not complain
-> { eval "proc { |&| it }" }.should_not complain
+ -> { eval "proc { || it }" }.should_not complain
end
it "does not emit a deprecation warning when `it` calls with arguments" do
-> { eval "proc { it(42) }" }.should_not complain
+ -> { eval "proc { it 42 }" }.should_not complain
+ end
+
+ it "does not emit a deprecation warning when `it` calls with a block" do
+ -> { eval "proc { it {} }" }.should_not complain
+ end
+
+ it "does not emit a deprecation warning when a local variable inside the block named `it` exists" do
+ -> { eval "proc { it = 42; it }" }.should_not complain
end
it "does not emit a deprecation warning when `it` calls with explicit empty arguments list" do
-> { eval "proc { it() }" }.should_not complain
end
+
+ it "calls the method `it` if defined" do
+ o = Object.new
+ def o.it
+ 21
+ end
+ suppress_warning do
+ o.instance_eval("proc { it * 2 }").call(1).should == 42
+ end
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "works alongside disallowed block argument" do
+ no_block = eval <<-EOF
+ proc {|arg1, &nil| arg1}
+ EOF
+
+ no_block.call(:a).should == :a
+ -> { no_block.call(:a) {} }.should.raise(ArgumentError, 'no block accepted')
+ end
+ end
+end
+
+# Duplicates specs in language/it_parameter_spec.rb
+# Need them here to run on Ruby versions prior 3.4
+# TODO: remove when the minimal supported Ruby version is 3.4
+describe "if `it` is defined as a variable" do
+ it "treats `it` as a captured variable if defined outside of a block" do
+ it = 5
+ proc { it }.call(0).should == 5
+ end
+
+ it "treats `it` as a local variable if defined inside of a block" do
+ proc { it = 5; it }.call(0).should == 5
+ end
+end
+
+describe "Block-parameter destructuring" do
+ it "does not warn about unused inner names in verbose mode" do
+ -> {
+ eval <<~RUBY, binding, __FILE__, __LINE__ + 1
+ proc { |key, (val1, val2)| [key, val2] }
+ RUBY
+ }.should_not complain(verbose: true)
end
end
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index 7e5b6fb328..5c9b8060c3 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -52,29 +52,29 @@ describe "The break statement in a captured block" do
describe "when the invocation of the scope creating the block is still active" do
it "raises a LocalJumpError when invoking the block from the scope creating the block" do
- -> { @program.break_in_method }.should raise_error(LocalJumpError)
+ -> { @program.break_in_method }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :xa, :d, :b]
end
it "raises a LocalJumpError when invoking the block from a method" do
- -> { @program.break_in_nested_method }.should raise_error(LocalJumpError)
+ -> { @program.break_in_nested_method }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :xa, :cc, :aa, :b]
end
it "raises a LocalJumpError when yielding to the block" do
- -> { @program.break_in_yielding_method }.should raise_error(LocalJumpError)
+ -> { @program.break_in_yielding_method }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :xa, :cc, :aa, :b]
end
end
describe "from a scope that has returned" do
it "raises a LocalJumpError when calling the block from a method" do
- -> { @program.break_in_method_captured }.should raise_error(LocalJumpError)
+ -> { @program.break_in_method_captured }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :za, :xa, :zd, :zb]
end
it "raises a LocalJumpError when yielding to the block" do
- -> { @program.break_in_yield_captured }.should raise_error(LocalJumpError)
+ -> { @program.break_in_yield_captured }.should.raise(LocalJumpError)
ScratchPad.recorded.should == [:a, :za, :xa, :zd, :aa, :zb]
end
end
@@ -88,7 +88,7 @@ describe "The break statement in a captured block" do
e
end
end
- thread_with_break.value.should be_an_instance_of(LocalJumpError)
+ thread_with_break.value.should.instance_of?(LocalJumpError)
end
end
end
@@ -256,7 +256,7 @@ describe "The break statement in a method" do
it "is invalid and raises a SyntaxError" do
-> {
eval("def m; break; end")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -268,7 +268,7 @@ describe "The break statement in a module literal" do
end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError)
+ -> { eval(code) }.should.raise(SyntaxError)
end
end
@@ -388,7 +388,7 @@ describe "Executing break from within a block" do
-> do
cls2.new.foo.should == 1
- end.should_not raise_error
+ end.should_not.raise
end
it "raises LocalJumpError when converted into a proc during a super call" do
@@ -397,6 +397,6 @@ describe "Executing break from within a block" do
-> do
cls2.new.foo
- end.should raise_error(LocalJumpError)
+ end.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb
index 464d06e46a..41881bf20a 100644
--- a/spec/ruby/language/case_spec.rb
+++ b/spec/ruby/language/case_spec.rb
@@ -27,6 +27,41 @@ describe "The 'case'-construct" do
@calls.should == [:foo, :bar]
end
+ it "matches an Integer literal whose value does not fit in a 32-bit int" do
+ big = 10_000_000_000
+ case big
+ when 10_000_000_000; true
+ else false
+ end.should == true
+
+ case -3_000_000_000
+ when -3_000_000_000; true
+ else false
+ end.should == true
+ end
+
+ it "matches an arbitrary-precision Integer literal" do
+ huge = 1267650600228229401496703205376
+ case huge
+ when 1267650600228229401496703205376; true
+ else false
+ end.should == true
+ end
+
+ it "dispatches correctly with mixed small and large Integer literals" do
+ pick = -> x {
+ case x
+ when 1267650600228229401496703205376 then :beyond_long
+ when 10_000_000_000 then :beyond_int
+ when 1 then :fits_int
+ else :other
+ end
+ }
+
+ [1267650600228229401496703205376, 10_000_000_000, 1, :nope].map(&pick).should ==
+ [:beyond_long, :beyond_int, :fits_int, :other]
+ end
+
it "evaluates the body of the when clause whose range expression includes the case target expression" do
case 5
when 21..30; false
@@ -94,12 +129,12 @@ describe "The 'case'-construct" do
it "tests with matching regexps and sets $~ and captures" do
case "foo42"
when /oo(\d+)/
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "42"
else
flunk
end
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "42"
end
@@ -107,12 +142,12 @@ describe "The 'case'-construct" do
digits = '\d+'
case "foo44"
when /oo(#{digits})/
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "44"
else
flunk
end
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "44"
end
@@ -120,12 +155,12 @@ describe "The 'case'-construct" do
digits_regexp = /\d+/
case "foo43"
when /oo(#{digits_regexp})/
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "43"
else
flunk
end
- $~.should be_kind_of(MatchData)
+ $~.should.is_a?(MatchData)
$1.should == "43"
end
@@ -268,7 +303,7 @@ describe "The 'case'-construct" do
true
end
CODE
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "raises a SyntaxError when 'else' is used before a 'when' was given" do
@@ -280,7 +315,7 @@ describe "The 'case'-construct" do
when 4; false
end
CODE
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "supports nested case statements" do
diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb
index 0b770d69b5..7ea4857514 100644
--- a/spec/ruby/language/class_spec.rb
+++ b/spec/ruby/language/class_spec.rb
@@ -10,23 +10,23 @@ end
describe "The class keyword" do
it "creates a new class with semicolon" do
class ClassSpecsKeywordWithSemicolon; end
- ClassSpecsKeywordWithSemicolon.should be_an_instance_of(Class)
+ ClassSpecsKeywordWithSemicolon.should.instance_of?(Class)
end
it "does not raise a SyntaxError when opening a class without a semicolon" do
eval "class ClassSpecsKeywordWithoutSemicolon end"
- ClassSpecsKeywordWithoutSemicolon.should be_an_instance_of(Class)
+ ClassSpecsKeywordWithoutSemicolon.should.instance_of?(Class)
end
it "can redefine a class when called from a block" do
ClassSpecs::DEFINE_CLASS.call
- A.should be_an_instance_of(Class)
+ A.should.instance_of?(Class)
Object.send(:remove_const, :A)
- defined?(A).should be_nil
+ defined?(A).should == nil
ClassSpecs::DEFINE_CLASS.call
- A.should be_an_instance_of(Class)
+ A.should.instance_of?(Class)
ensure
Object.send(:remove_const, :A) if defined?(::A)
end
@@ -34,8 +34,8 @@ end
describe "A class definition" do
it "creates a new class" do
- ClassSpecs::A.should be_kind_of(Class)
- ClassSpecs::A.new.should be_kind_of(ClassSpecs::A)
+ ClassSpecs::A.should.is_a?(Class)
+ ClassSpecs::A.new.should.is_a?(ClassSpecs::A)
end
it "has no class variables" do
@@ -46,7 +46,14 @@ describe "A class definition" do
-> {
class ClassSpecsNumber
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError, /\AClassSpecsNumber is not a class/)
+ end
+
+ it "raises TypeError if constant given as class name exists and is a Module but not a Class" do
+ -> {
+ class ClassSpecs
+ end
+ }.should.raise(TypeError, /\AClassSpecs is not a class/)
end
# test case known to be detecting bugs (JRuby, MRI)
@@ -54,19 +61,19 @@ describe "A class definition" do
-> {
class nil::Foo
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if any constant qualifying the class is not a Module" do
-> {
class ClassSpecs::Number::MyClass
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
class ClassSpecsNumber::MyClass
end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "inherits from Object by default" do
@@ -80,7 +87,7 @@ describe "A class definition" do
-> {
class SuperclassResetToSubclass < M
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
end
end
@@ -93,7 +100,7 @@ describe "A class definition" do
-> {
class SuperclassReopenedBasicObject < BasicObject
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
SuperclassReopenedBasicObject.superclass.should == A
end
end
@@ -108,7 +115,7 @@ describe "A class definition" do
-> {
class SuperclassReopenedObject < Object
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
SuperclassReopenedObject.superclass.should == A
end
end
@@ -133,7 +140,7 @@ describe "A class definition" do
-> {
class NoSuperclassSet < String
end
- }.should raise_error(TypeError, /superclass mismatch/)
+ }.should.raise(TypeError, /superclass mismatch/)
end
end
@@ -142,7 +149,7 @@ describe "A class definition" do
-> {
class ShouldNotWork < self; end
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "first evaluates the superclass before checking if the class already exists" do
@@ -161,7 +168,7 @@ describe "A class definition" do
it "raises a TypeError if inheriting from a metaclass" do
obj = mock("metaclass super")
meta = obj.singleton_class
- -> { class ClassSpecs::MetaclassSuper < meta; end }.should raise_error(TypeError)
+ -> { class ClassSpecs::MetaclassSuper < meta; end }.should.raise(TypeError)
end
it "allows the declaration of class variables in the body" do
@@ -170,7 +177,7 @@ describe "A class definition" do
end
it "stores instance variables defined in the class body in the class object" do
- ClassSpecs.string_instance_variables(ClassSpecs::B).should include("@ivar")
+ ClassSpecs.string_instance_variables(ClassSpecs::B).should.include?("@ivar")
ClassSpecs::B.instance_variable_get(:@ivar).should == :ivar
end
@@ -182,9 +189,9 @@ describe "A class definition" do
end
it "allows the definition of class-level instance variables in a class method" do
- ClassSpecs.string_instance_variables(ClassSpecs::C).should_not include("@civ")
+ ClassSpecs.string_instance_variables(ClassSpecs::C).should_not.include?("@civ")
ClassSpecs::C.make_class_instance_variable
- ClassSpecs.string_instance_variables(ClassSpecs::C).should include("@civ")
+ ClassSpecs.string_instance_variables(ClassSpecs::C).should.include?("@civ")
ClassSpecs::C.remove_instance_variable :@civ
end
@@ -279,7 +286,8 @@ end
describe "An outer class definition" do
it "contains the inner classes" do
- ClassSpecs::Container.constants.should include(:A, :B)
+ ClassSpecs::Container.constants.should.include?(:A)
+ ClassSpecs::Container.constants.should.include?(:B)
end
end
@@ -297,23 +305,23 @@ describe "A class definition extending an object (sclass)" do
end
end
CODE
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError when trying to extend non-Class" do
error_msg = /superclass must be a.* Class/
- -> { class TestClass < ""; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < 1; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < :symbol; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < mock('o'); end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < Module.new; end }.should raise_error(TypeError, error_msg)
- -> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg)
+ -> { class TestClass < ""; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < 1; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < :symbol; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < mock('o'); end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < Module.new; end }.should.raise(TypeError, error_msg)
+ -> { class TestClass < BasicObject.new; end }.should.raise(TypeError, error_msg)
end
it "does not allow accessing the block of the original scope" do
-> {
ClassSpecs.sclass_with_block { 123 }
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "can use return to cause the enclosing method to return" do
@@ -333,11 +341,11 @@ describe "Reopening a class" do
end
it "raises a TypeError when superclasses mismatch" do
- -> { class ClassSpecs::A < Array; end }.should raise_error(TypeError)
+ -> { class ClassSpecs::A < Array; end }.should.raise(TypeError)
end
it "adds new methods to subclasses" do
- -> { ClassSpecs::M.m }.should raise_error(NoMethodError)
+ -> { ClassSpecs::M.m }.should.raise(NoMethodError)
class ClassSpecs::L
def self.m
1
@@ -346,6 +354,39 @@ describe "Reopening a class" do
ClassSpecs::M.m.should == 1
ClassSpecs::L.singleton_class.send(:remove_method, :m)
end
+
+ it "does not reopen a class included in Object" do
+ ruby_exe(<<~RUBY).should == "false"
+ module IncludedInObject
+ class IncludedClass
+ end
+ end
+ class Object
+ include IncludedInObject
+ end
+ class IncludedClass
+ end
+ print IncludedInObject::IncludedClass == Object::IncludedClass
+ RUBY
+ end
+
+ it "does not reopen a class included in non-Object modules" do
+ ruby_exe(<<~RUBY).should == "false/false"
+ module Included
+ module IncludedClass; end
+ end
+ module M
+ include Included
+ module IncludedClass; end
+ end
+ class C
+ include Included
+ module IncludedClass; end
+ end
+ print Included::IncludedClass == M::IncludedClass, "/",
+ Included::IncludedClass == C::IncludedClass
+ RUBY
+ end
end
describe "class provides hooks" do
diff --git a/spec/ruby/language/class_variable_spec.rb b/spec/ruby/language/class_variable_spec.rb
index a26a3fb8de..84a7684c6d 100644
--- a/spec/ruby/language/class_variable_spec.rb
+++ b/spec/ruby/language/class_variable_spec.rb
@@ -30,19 +30,19 @@ describe "A class variable defined in a module" do
end
it "is not defined in these classes" do
- ClassVariablesSpec::ClassC.cvar_defined?.should be_false
+ ClassVariablesSpec::ClassC.cvar_defined?.should == false
end
it "is only updated in the module a method defined in the module is used" do
ClassVariablesSpec::ClassC.cvar_m = "new value"
ClassVariablesSpec::ClassC.cvar_m.should == "new value"
- ClassVariablesSpec::ClassC.cvar_defined?.should be_false
+ ClassVariablesSpec::ClassC.cvar_defined?.should == false
end
it "is updated in the class when a Method defined in the class is used" do
ClassVariablesSpec::ClassC.cvar_c = "new value"
- ClassVariablesSpec::ClassC.cvar_defined?.should be_true
+ ClassVariablesSpec::ClassC.cvar_defined?.should == true
end
it "can be accessed inside the class using the module methods" do
@@ -55,11 +55,11 @@ describe "A class variable defined in a module" do
end
it "is defined in the extended module" do
- ClassVariablesSpec::ModuleN.class_variable_defined?(:@@cvar_n).should be_true
+ ClassVariablesSpec::ModuleN.class_variable_defined?(:@@cvar_n).should == true
end
it "is not defined in the extending module" do
- ClassVariablesSpec::ModuleO.class_variable_defined?(:@@cvar_n).should be_false
+ ClassVariablesSpec::ModuleO.class_variable_defined?(:@@cvar_n).should == false
end
end
@@ -70,14 +70,14 @@ describe 'A class variable definition' do
c = Class.new(b)
b.class_variable_set(:@@cv, :value)
- -> { a.class_variable_get(:@@cv) }.should raise_error(NameError)
+ -> { a.class_variable_get(:@@cv) }.should.raise(NameError)
b.class_variable_get(:@@cv).should == :value
c.class_variable_get(:@@cv).should == :value
# updates the same variable
c.class_variable_set(:@@cv, :next)
- -> { a.class_variable_get(:@@cv) }.should raise_error(NameError)
+ -> { a.class_variable_get(:@@cv) }.should.raise(NameError)
b.class_variable_get(:@@cv).should == :next
c.class_variable_get(:@@cv).should == :next
end
@@ -87,16 +87,16 @@ describe 'Accessing a class variable' do
it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do
-> {
eval "@@cvar_toplevel1"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ }.should.raise(RuntimeError, 'class variable access from toplevel')
-> {
eval "@@cvar_toplevel2 = 2"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ }.should.raise(RuntimeError, 'class variable access from toplevel')
end
it "does not raise an error when checking if defined from the toplevel scope" do
-> {
eval "defined?(@@cvar_toplevel1)"
- }.should_not raise_error
+ }.should_not.raise
end
it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
@@ -107,7 +107,7 @@ describe 'Accessing a class variable' do
-> {
subclass.class_variable_get(:@@cvar_overtaken)
- }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
+ }.should.raise(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
parent.class_variable_get(:@@cvar_overtaken).should == :parent
end
diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb
index 35913b9e30..0880230a36 100644
--- a/spec/ruby/language/constants_spec.rb
+++ b/spec/ruby/language/constants_spec.rb
@@ -51,8 +51,8 @@ describe "Literal (A::X) constant resolution" do
it "does not search the singleton class of the class or module" do
-> do
ConstantSpecs::ContainerA::ChildA::CS_CONST14
- end.should raise_error(NameError)
- -> { ConstantSpecs::CS_CONST14 }.should raise_error(NameError)
+ end.should.raise(NameError)
+ -> { ConstantSpecs::CS_CONST14 }.should.raise(NameError)
end
end
@@ -135,7 +135,7 @@ describe "Literal (A::X) constant resolution" do
-> do
ConstantSpecs::ContainerB::ChildB::CS_CONST108
- end.should raise_error(NameError)
+ end.should.raise(NameError)
module ConstantSpecs
class << self
@@ -143,7 +143,7 @@ describe "Literal (A::X) constant resolution" do
end
end
- -> { ConstantSpecs::CS_CONST108 }.should raise_error(NameError)
+ -> { ConstantSpecs::CS_CONST108 }.should.raise(NameError)
ensure
ConstantSpecs::ContainerB::ChildB.singleton_class.send(:remove_const, :CS_CONST108)
ConstantSpecs.singleton_class.send(:remove_const, :CS_CONST108)
@@ -161,39 +161,21 @@ describe "Literal (A::X) constant resolution" do
ConstantSpecs::ClassB.send(:remove_const, :CS_CONST109)
end
- ruby_version_is "3.2" do
- it "evaluates left-to-right" do
- mod = Module.new
+ it "evaluates left-to-right" do
+ mod = Module.new
- mod.module_eval <<-EOC
- order = []
- ConstantSpecsRHS = Module.new
- (order << :lhs; ConstantSpecsRHS)::B = (order << :rhs)
- EOC
+ mod.module_eval <<-EOC
+ order = []
+ ConstantSpecsRHS = Module.new
+ (order << :lhs; ConstantSpecsRHS)::B = (order << :rhs)
+ EOC
- mod::ConstantSpecsRHS::B.should == [:lhs, :rhs]
- end
- end
-
- ruby_version_is ""..."3.2" do
- it "evaluates the right hand side before evaluating a constant path" do
- mod = Module.new
-
- mod.module_eval <<-EOC
- ConstantSpecsRHS::B = begin
- module ConstantSpecsRHS; end
-
- "hello"
- end
- EOC
-
- mod::ConstantSpecsRHS::B.should == 'hello'
- end
+ mod::ConstantSpecsRHS::B.should == [:lhs, :rhs]
end
end
it "raises a NameError if no constant is defined in the search path" do
- -> { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError)
+ -> { ConstantSpecs::ParentA::CS_CONSTX }.should.raise(NameError)
end
it "uses the module or class #name to craft the error message" do
@@ -207,7 +189,7 @@ describe "Literal (A::X) constant resolution" do
end
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
+ -> { mod::DOES_NOT_EXIST }.should.raise(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
end
it "uses the module or class #inspect to craft the error message if they are anonymous" do
@@ -221,7 +203,7 @@ describe "Literal (A::X) constant resolution" do
end
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
+ -> { mod::DOES_NOT_EXIST }.should.raise(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
end
it "sends #const_missing to the original class or module scope" do
@@ -233,10 +215,10 @@ describe "Literal (A::X) constant resolution" do
end
it "raises a TypeError if a non-class or non-module qualifier is given" do
- -> { CS_CONST1::CS_CONST }.should raise_error(TypeError)
- -> { 1::CS_CONST }.should raise_error(TypeError)
- -> { "mod"::CS_CONST }.should raise_error(TypeError)
- -> { false::CS_CONST }.should raise_error(TypeError)
+ -> { CS_CONST1::CS_CONST }.should.raise(TypeError)
+ -> { 1::CS_CONST }.should.raise(TypeError)
+ -> { "mod"::CS_CONST }.should.raise(TypeError)
+ -> { false::CS_CONST }.should.raise(TypeError)
end
end
@@ -282,7 +264,7 @@ describe "Constant resolution within methods" do
end
it "does not search the lexical scope of the caller" do
- -> { ConstantSpecs::ClassA.const16 }.should raise_error(NameError)
+ -> { ConstantSpecs::ClassA.const16 }.should.raise(NameError)
end
it "searches the lexical scope of a block" do
@@ -297,7 +279,7 @@ describe "Constant resolution within methods" do
it "does not search the lexical scope of qualifying modules" do
-> do
ConstantSpecs::ContainerA::ChildA.const23
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
end
@@ -395,7 +377,7 @@ describe "Constant resolution within methods" do
it "does not search the lexical scope of the caller" do
ConstantSpecs::ClassB::CS_CONST209 = :const209
- -> { ConstantSpecs::ClassB.const209 }.should raise_error(NameError)
+ -> { ConstantSpecs::ClassB.const209 }.should.raise(NameError)
ensure
ConstantSpecs::ClassB.send(:remove_const, :CS_CONST209)
end
@@ -444,14 +426,14 @@ describe "Constant resolution within methods" do
-> do
ConstantSpecs::ContainerB::ChildB.const214
- end.should raise_error(NameError)
+ end.should.raise(NameError)
ensure
ConstantSpecs::ContainerB.send(:remove_const, :CS_CONST214)
end
end
it "raises a NameError if no constant is defined in the search path" do
- -> { ConstantSpecs::ParentA.constx }.should raise_error(NameError)
+ -> { ConstantSpecs::ParentA.constx }.should.raise(NameError)
end
it "sends #const_missing to the original class or module scope" do
@@ -474,7 +456,7 @@ describe "Constant resolution within a singleton class (class << obj)" do
it "uses its own namespace for nested modules" do
a = ConstantSpecs::CS_SINGLETON3[0].x
b = ConstantSpecs::CS_SINGLETON3[1].x
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
it "allows nested modules to have proper resolution" do
@@ -487,12 +469,12 @@ end
describe "top-level constant lookup" do
context "on a class" do
it "does not search Object after searching other scopes" do
- -> { String::Hash }.should raise_error(NameError)
+ -> { String::Hash }.should.raise(NameError)
end
end
it "searches Object unsuccessfully when searches on a module" do
- -> { Enumerable::Hash }.should raise_error(NameError)
+ -> { Enumerable::Hash }.should.raise(NameError)
end
end
@@ -506,7 +488,7 @@ describe "Module#private_constant marked constants" do
mod.const_set :Foo, false
}.should complain(/already initialized constant/)
- -> {mod::Foo}.should raise_error(NameError)
+ -> {mod::Foo}.should.raise(NameError)
end
it "sends #const_missing to the original class or module" do
@@ -524,19 +506,19 @@ describe "Module#private_constant marked constants" do
it "cannot be accessed from outside the module" do
-> do
ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a module from scope where constant would be private" do
-> do
module ConstantVisibility::ModuleContainer::PrivateModule; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a class from scope where constant would be private" do
-> do
class ConstantVisibility::ModuleContainer::PrivateClass; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "can be reopened as a module where constant is not private" do
@@ -572,7 +554,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from the module itself" do
- ConstantVisibility::PrivConstModule.private_constant_from_self.should be_true
+ ConstantVisibility::PrivConstModule.private_constant_from_self.should == true
end
it "is defined? from the module itself" do
@@ -580,7 +562,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from lexical scope" do
- ConstantVisibility::PrivConstModule::Nested.private_constant_from_scope.should be_true
+ ConstantVisibility::PrivConstModule::Nested.private_constant_from_scope.should == true
end
it "is defined? from lexical scope" do
@@ -588,20 +570,20 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from classes that include the module" do
- ConstantVisibility::ClassIncludingPrivConstModule.new.private_constant_from_include.should be_true
+ ConstantVisibility::ClassIncludingPrivConstModule.new.private_constant_from_include.should == true
end
it "can be accessed from modules that include the module" do
- ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_from_include.should be_true
+ ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_from_include.should == true
end
it "raises a NameError when accessed directly from modules that include the module" do
-> do
ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_self_from_include
- end.should raise_error(NameError)
+ end.should.raise(NameError)
-> do
ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_named_from_include
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is defined? from classes that include the module" do
@@ -613,19 +595,19 @@ describe "Module#private_constant marked constants" do
it "cannot be accessed from outside the class" do
-> do
ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a module" do
-> do
module ConstantVisibility::ClassContainer::PrivateModule; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "cannot be reopened as a class" do
-> do
class ConstantVisibility::ClassContainer::PrivateClass; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "can be reopened as a module where constant is not private" do
@@ -661,7 +643,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from the class itself" do
- ConstantVisibility::PrivConstClass.private_constant_from_self.should be_true
+ ConstantVisibility::PrivConstClass.private_constant_from_self.should == true
end
it "is defined? from the class itself" do
@@ -669,7 +651,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from lexical scope" do
- ConstantVisibility::PrivConstClass::Nested.private_constant_from_scope.should be_true
+ ConstantVisibility::PrivConstClass::Nested.private_constant_from_scope.should == true
end
it "is defined? from lexical scope" do
@@ -677,7 +659,7 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from subclasses" do
- ConstantVisibility::PrivConstClassChild.new.private_constant_from_subclass.should be_true
+ ConstantVisibility::PrivConstClassChild.new.private_constant_from_subclass.should == true
end
it "is defined? from subclasses" do
@@ -689,7 +671,7 @@ describe "Module#private_constant marked constants" do
it "cannot be accessed using ::Const form" do
-> do
::PRIVATE_CONSTANT_IN_OBJECT
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is not defined? using ::Const form" do
@@ -709,14 +691,14 @@ describe "Module#private_constant marked constants" do
it "has :receiver and :name attributes" do
-> do
ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstClass
e.name.should == :PRIVATE_CONSTANT_CLASS
}
-> do
ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstModule
e.name.should == :PRIVATE_CONSTANT_MODULE
}
@@ -725,14 +707,14 @@ describe "Module#private_constant marked constants" do
it "has the defined class as the :name attribute" do
-> do
ConstantVisibility::PrivConstClassChild::PRIVATE_CONSTANT_CLASS
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstClass
e.name.should == :PRIVATE_CONSTANT_CLASS
}
-> do
ConstantVisibility::ClassIncludingPrivConstModule::PRIVATE_CONSTANT_MODULE
- end.should raise_error(NameError) {|e|
+ end.should.raise(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstModule
e.name.should == :PRIVATE_CONSTANT_MODULE
}
@@ -801,7 +783,7 @@ describe 'Allowed characters' do
it 'does not allow not ASCII characters that cannot be upcased or lowercased at the beginning' do
-> do
Module.new.const_set("થBB", 1)
- end.should raise_error(NameError, /wrong constant name/)
+ end.should.raise(NameError, /wrong constant name/)
end
it 'allows not ASCII upcased characters at the beginning' do
@@ -821,7 +803,7 @@ describe 'Assignment' do
B = 1
end
CODE
- end.should raise_error(SyntaxError, /dynamic constant assignment/)
+ end.should.raise(SyntaxError, /dynamic constant assignment/)
end
end
end
diff --git a/spec/ruby/language/def_spec.rb b/spec/ruby/language/def_spec.rb
index eb44331bb5..82c89a0d08 100644
--- a/spec/ruby/language/def_spec.rb
+++ b/spec/ruby/language/def_spec.rb
@@ -14,11 +14,11 @@ end
describe "Defining a method at the top-level" do
it "defines it on Object with private visibility by default" do
- Object.should have_private_instance_method(:some_toplevel_method, false)
+ Object.private_instance_methods(false).should.include?(:some_toplevel_method)
end
it "defines it on Object with public visibility after calling public" do
- Object.should have_public_instance_method(:public_toplevel_method, false)
+ Object.public_instance_methods(false).should.include?(:public_toplevel_method)
end
end
@@ -28,7 +28,7 @@ describe "Defining an 'initialize' method" do
def initialize
end
end
- DefInitializeSpec.should have_private_instance_method(:initialize, false)
+ DefInitializeSpec.private_instance_methods(false).should.include?(:initialize)
end
end
@@ -38,7 +38,7 @@ describe "Defining an 'initialize_copy' method" do
def initialize_copy
end
end
- DefInitializeCopySpec.should have_private_instance_method(:initialize_copy, false)
+ DefInitializeCopySpec.private_instance_methods(false).should.include?(:initialize_copy)
end
end
@@ -48,7 +48,7 @@ describe "Defining an 'initialize_dup' method" do
def initialize_dup
end
end
- DefInitializeDupSpec.should have_private_instance_method(:initialize_dup, false)
+ DefInitializeDupSpec.private_instance_methods(false).should.include?(:initialize_dup)
end
end
@@ -58,7 +58,7 @@ describe "Defining an 'initialize_clone' method" do
def initialize_clone
end
end
- DefInitializeCloneSpec.should have_private_instance_method(:initialize_clone, false)
+ DefInitializeCloneSpec.private_instance_methods(false).should.include?(:initialize_clone)
end
end
@@ -68,7 +68,7 @@ describe "Defining a 'respond_to_missing?' method" do
def respond_to_missing?
end
end
- DefRespondToMissingPSpec.should have_private_instance_method(:respond_to_missing?, false)
+ DefRespondToMissingPSpec.private_instance_methods(false).should.include?(:respond_to_missing?)
end
end
@@ -82,12 +82,12 @@ end
describe "An instance method" do
it "raises an error with too few arguments" do
def foo(a, b); end
- -> { foo 1 }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 2)')
+ -> { foo 1 }.should.raise(ArgumentError, 'wrong number of arguments (given 1, expected 2)')
end
it "raises an error with too many arguments" do
def foo(a); end
- -> { foo 1, 2 }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ -> { foo 1, 2 }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
it "raises FrozenError with the correct class name" do
@@ -96,8 +96,9 @@ describe "An instance method" do
self.freeze
def foo; end
end
- }.should raise_error(FrozenError) { |e|
- e.message.should.start_with? "can't modify frozen module"
+ }.should.raise(FrozenError) { |e|
+ msg_class = ruby_version_is("4.0") ? "Module" : "module"
+ e.message.should == "can't modify frozen #{msg_class}: #{e.receiver}"
}
-> {
@@ -105,8 +106,9 @@ describe "An instance method" do
self.freeze
def foo; end
end
- }.should raise_error(FrozenError){ |e|
- e.message.should.start_with? "can't modify frozen class"
+ }.should.raise(FrozenError){ |e|
+ msg_class = ruby_version_is("4.0") ? "Class" : "class"
+ e.message.should == "can't modify frozen #{msg_class}: #{e.receiver}"
}
end
end
@@ -133,12 +135,12 @@ describe "An instance method definition with a splat" do
end
it "allows only a single * argument" do
- -> { eval 'def foo(a, *b, *c); end' }.should raise_error(SyntaxError)
+ -> { eval 'def foo(a, *b, *c); end' }.should.raise(SyntaxError)
end
it "requires the presence of any arguments that precede the *" do
def foo(a, b, *c); end
- -> { foo 1 }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 2+)')
+ -> { foo 1 }.should.raise(ArgumentError, 'wrong number of arguments (given 1, expected 2+)')
end
end
@@ -171,7 +173,7 @@ describe "An instance method with a default argument" do
def foo(a, b = 2)
[a,b]
end
- -> { foo }.should raise_error(ArgumentError, 'wrong number of arguments (given 0, expected 1..2)')
+ -> { foo }.should.raise(ArgumentError, 'wrong number of arguments (given 0, expected 1..2)')
foo(1).should == [1, 2]
end
@@ -179,7 +181,7 @@ describe "An instance method with a default argument" do
def foo(a, b = 2, *c)
[a,b,c]
end
- -> { foo }.should raise_error(ArgumentError, 'wrong number of arguments (given 0, expected 1+)')
+ -> { foo }.should.raise(ArgumentError, 'wrong number of arguments (given 0, expected 1+)')
foo(1).should == [1,2,[]]
end
@@ -203,7 +205,7 @@ describe "An instance method with a default argument" do
eval "def foo(bar = bar)
bar
end"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -277,26 +279,27 @@ describe "A singleton method definition" do
it "raises FrozenError if frozen" do
obj = Object.new
obj.freeze
- -> { def obj.foo; end }.should raise_error(FrozenError)
+ -> { def obj.foo; end }.should.raise(FrozenError)
end
it "raises FrozenError with the correct class name" do
obj = Object.new
obj.freeze
- -> { def obj.foo; end }.should raise_error(FrozenError){ |e|
- e.message.should.start_with? "can't modify frozen object"
- }
+ msg_class = ruby_version_is("4.0") ? "Object" : "object"
+ -> { def obj.foo; end }.should.raise(FrozenError, "can't modify frozen #{msg_class}: #{obj}")
+ obj = Object.new
c = obj.singleton_class
- -> { def c.foo; end }.should raise_error(FrozenError){ |e|
- e.message.should.start_with? "can't modify frozen Class"
- }
+ c.singleton_class.freeze
+ -> { def c.foo; end }.should.raise(FrozenError, "can't modify frozen Class: #{c}")
+
+ c = Class.new
+ c.freeze
+ -> { def c.foo; end }.should.raise(FrozenError, "can't modify frozen Class: #{c}")
m = Module.new
m.freeze
- -> { def m.foo; end }.should raise_error(FrozenError){ |e|
- e.message.should.start_with? "can't modify frozen Module"
- }
+ -> { def m.foo; end }.should.raise(FrozenError, "can't modify frozen Module: #{m}")
end
end
@@ -431,7 +434,7 @@ describe "A method definition inside a metaclass scope" do
end
DefSpecSingleton.a_class_method.should == DefSpecSingleton
- -> { Object.a_class_method }.should raise_error(NoMethodError)
+ -> { Object.a_class_method }.should.raise(NoMethodError)
end
it "can create a singleton method" do
@@ -441,7 +444,7 @@ describe "A method definition inside a metaclass scope" do
end
obj.a_singleton_method.should == obj
- -> { Object.new.a_singleton_method }.should raise_error(NoMethodError)
+ -> { Object.new.a_singleton_method }.should.raise(NoMethodError)
end
it "raises FrozenError if frozen" do
@@ -449,7 +452,7 @@ describe "A method definition inside a metaclass scope" do
obj.freeze
class << obj
- -> { def foo; end }.should raise_error(FrozenError)
+ -> { def foo; end }.should.raise(FrozenError)
end
end
end
@@ -470,7 +473,7 @@ describe "A nested method definition" do
other = DefSpecNested.new
other.an_instance_method.should == other
- DefSpecNested.should have_instance_method(:an_instance_method)
+ DefSpecNested.should.method_defined?(:an_instance_method, false)
end
it "creates a class method when evaluated in a class method" do
@@ -485,11 +488,11 @@ describe "A nested method definition" do
end
end
- -> { DefSpecNested.a_class_method }.should raise_error(NoMethodError)
+ -> { DefSpecNested.a_class_method }.should.raise(NoMethodError)
DefSpecNested.create_class_method.should == DefSpecNested
DefSpecNested.a_class_method.should == DefSpecNested
- -> { Object.a_class_method }.should raise_error(NoMethodError)
- -> { DefSpecNested.new.a_class_method }.should raise_error(NoMethodError)
+ -> { Object.a_class_method }.should.raise(NoMethodError)
+ -> { DefSpecNested.new.a_class_method }.should.raise(NoMethodError)
end
it "creates a singleton method when evaluated in the metaclass of an instance" do
@@ -507,7 +510,7 @@ describe "A nested method definition" do
obj.a_singleton_method.should == obj
other = DefSpecNested.new
- -> { other.a_singleton_method }.should raise_error(NoMethodError)
+ -> { other.a_singleton_method }.should.raise(NoMethodError)
end
it "creates a method in the surrounding context when evaluated in a def expr.method" do
@@ -519,8 +522,8 @@ describe "A nested method definition" do
end
DefSpecNested::TARGET.defs_method
- DefSpecNested.should have_instance_method :inherited_method
- DefSpecNested::TARGET.should_not have_method :inherited_method
+ DefSpecNested.should.method_defined?(:inherited_method, false)
+ DefSpecNested::TARGET.should_not.respond_to? :inherited_method
obj = DefSpecNested.new
obj.inherited_method.should == obj
@@ -542,11 +545,11 @@ describe "A nested method definition" do
obj = DefSpecNested::OBJ
obj.create_method_in_instance_eval
- obj.should have_method :arg_method
- obj.should have_method :body_method
+ obj.should.respond_to? :arg_method
+ obj.should.respond_to? :body_method
- DefSpecNested.should_not have_instance_method :arg_method
- DefSpecNested.should_not have_instance_method :body_method
+ DefSpecNested.should_not.method_defined? :arg_method
+ DefSpecNested.should_not.method_defined? :body_method
ensure
DefSpecNested.send(:remove_const, :OBJ)
end
@@ -566,7 +569,7 @@ describe "A nested method definition" do
cls.new.new_def.should == 1
- -> { Object.new.new_def }.should raise_error(NoMethodError)
+ -> { Object.new.new_def }.should.raise(NoMethodError)
end
end
@@ -582,18 +585,18 @@ describe "A method definition always resets the visibility to public for nested
end
obj = cls.new
- -> { obj.do_def }.should raise_error(NoMethodError, /private/)
+ -> { obj.do_def }.should.raise(NoMethodError, /private/)
obj.send :do_def
obj.new_def.should == 1
cls.new.new_def.should == 1
- -> { Object.new.new_def }.should raise_error(NoMethodError)
+ -> { Object.new.new_def }.should.raise(NoMethodError)
end
it "at the toplevel" do
obj = Object.new
- -> { obj.toplevel_define_other_method }.should raise_error(NoMethodError, /private/)
+ -> { obj.toplevel_define_other_method }.should.raise(NoMethodError, /private/)
toplevel_define_other_method
nested_method_in_toplevel_method.should == 42
@@ -610,7 +613,7 @@ describe "A method definition inside an instance_eval" do
obj.an_instance_eval_method.should == obj
other = Object.new
- -> { other.an_instance_eval_method }.should raise_error(NoMethodError)
+ -> { other.an_instance_eval_method }.should.raise(NoMethodError)
end
it "creates a singleton method when evaluated inside a metaclass" do
@@ -623,7 +626,7 @@ describe "A method definition inside an instance_eval" do
obj.a_metaclass_eval_method.should == obj
other = Object.new
- -> { other.a_metaclass_eval_method }.should raise_error(NoMethodError)
+ -> { other.a_metaclass_eval_method }.should.raise(NoMethodError)
end
it "creates a class method when the receiver is a class" do
@@ -632,7 +635,7 @@ describe "A method definition inside an instance_eval" do
end
DefSpecNested.an_instance_eval_class_method.should == DefSpecNested
- -> { Object.an_instance_eval_class_method }.should raise_error(NoMethodError)
+ -> { Object.an_instance_eval_class_method }.should.raise(NoMethodError)
end
it "creates a class method when the receiver is an anonymous class" do
@@ -644,7 +647,7 @@ describe "A method definition inside an instance_eval" do
end
m.klass_method.should == :test
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
it "creates a class method when instance_eval is within class" do
@@ -657,7 +660,7 @@ describe "A method definition inside an instance_eval" do
end
m.klass_method.should == :test
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
end
@@ -670,7 +673,7 @@ describe "A method definition inside an instance_exec" do
end
DefSpecNested.an_instance_exec_class_method.should == 1
- -> { Object.an_instance_exec_class_method }.should raise_error(NoMethodError)
+ -> { Object.an_instance_exec_class_method }.should.raise(NoMethodError)
end
it "creates a class method when the receiver is an anonymous class" do
@@ -684,7 +687,7 @@ describe "A method definition inside an instance_exec" do
end
m.klass_method.should == 1
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
it "creates a class method when instance_exec is within class" do
@@ -699,7 +702,7 @@ describe "A method definition inside an instance_exec" do
end
m.klass_method.should == 2
- -> { Object.klass_method }.should raise_error(NoMethodError)
+ -> { Object.klass_method }.should.raise(NoMethodError)
end
end
@@ -719,7 +722,7 @@ describe "A method definition in an eval" do
other = DefSpecNested.new
other.an_eval_instance_method.should == other
- -> { Object.new.an_eval_instance_method }.should raise_error(NoMethodError)
+ -> { Object.new.an_eval_instance_method }.should.raise(NoMethodError)
end
it "creates a class method" do
@@ -735,8 +738,8 @@ describe "A method definition in an eval" do
DefSpecNestedB.eval_class_method.should == DefSpecNestedB
DefSpecNestedB.an_eval_class_method.should == DefSpecNestedB
- -> { Object.an_eval_class_method }.should raise_error(NoMethodError)
- -> { DefSpecNestedB.new.an_eval_class_method}.should raise_error(NoMethodError)
+ -> { Object.an_eval_class_method }.should.raise(NoMethodError)
+ -> { DefSpecNestedB.new.an_eval_class_method}.should.raise(NoMethodError)
end
it "creates a singleton method" do
@@ -754,7 +757,7 @@ describe "A method definition in an eval" do
obj.an_eval_singleton_method.should == obj
other = DefSpecNested.new
- -> { other.an_eval_singleton_method }.should raise_error(NoMethodError)
+ -> { other.an_eval_singleton_method }.should.raise(NoMethodError)
end
end
@@ -765,8 +768,8 @@ describe "a method definition that sets more than one default parameter all to t
it "assigns them all the same object by default" do
foo.should == [{},{},{}]
a, b, c = foo
- a.should eql(b)
- a.should eql(c)
+ a.should.eql?(b)
+ a.should.eql?(c)
end
it "allows the first argument to be given, and sets the rest to null" do
@@ -776,11 +779,11 @@ describe "a method definition that sets more than one default parameter all to t
it "assigns the parameters different objects across different default calls" do
a, _b, _c = foo
d, _e, _f = foo
- a.should_not equal(d)
+ a.should_not.equal?(d)
end
it "only allows overriding the default value of the first such parameter in each set" do
- -> { foo(1,2) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 0..1)')
+ -> { foo(1,2) }.should.raise(ArgumentError, 'wrong number of arguments (given 2, expected 0..1)')
end
def bar(a=b=c=1,d=2)
@@ -791,7 +794,7 @@ describe "a method definition that sets more than one default parameter all to t
bar.should == [1,1,1,2]
bar(3).should == [3,nil,nil,2]
bar(3,4).should == [3,nil,nil,4]
- -> { bar(3,4,5) }.should raise_error(ArgumentError, 'wrong number of arguments (given 3, expected 0..2)')
+ -> { bar(3,4,5) }.should.raise(ArgumentError, 'wrong number of arguments (given 3, expected 0..2)')
end
end
@@ -806,7 +809,7 @@ describe "The def keyword" do
}.call
end
- DefSpecsLambdaVisibility.should have_private_instance_method("some_method")
+ DefSpecsLambdaVisibility.private_instance_methods(false).should.include?(:some_method)
end
end
end
diff --git a/spec/ruby/language/defined_spec.rb b/spec/ruby/language/defined_spec.rb
index 80ad1818b1..6846179a7c 100644
--- a/spec/ruby/language/defined_spec.rb
+++ b/spec/ruby/language/defined_spec.rb
@@ -70,7 +70,7 @@ describe "The defined? keyword when called with a method name" do
end
it "returns nil if the method is not defined" do
- defined?(defined_specs_undefined_method).should be_nil
+ defined?(defined_specs_undefined_method).should == nil
end
it "returns 'method' if the method is defined and private" do
@@ -90,23 +90,23 @@ describe "The defined? keyword when called with a method name" do
end
it "returns nil if the method is private" do
- defined?(Object.print).should be_nil
+ defined?(Object.print).should == nil
end
it "returns nil if the method is protected" do
- defined?(DefinedSpecs::Basic.new.protected_method).should be_nil
+ defined?(DefinedSpecs::Basic.new.protected_method).should == nil
end
it "returns nil if the method is not defined" do
- defined?(Kernel.defined_specs_undefined_method).should be_nil
+ defined?(Kernel.defined_specs_undefined_method).should == nil
end
it "returns nil if the class is not defined" do
- defined?(DefinedSpecsUndefined.puts).should be_nil
+ defined?(DefinedSpecsUndefined.puts).should == nil
end
it "returns nil if the subclass is not defined" do
- defined?(DefinedSpecs::Undefined.puts).should be_nil
+ defined?(DefinedSpecs::Undefined.puts).should == nil
end
end
@@ -123,11 +123,11 @@ describe "The defined? keyword when called with a method name" do
it "returns nil if the method is not defined" do
obj = DefinedSpecs::Basic.new
- defined?(obj.an_undefined_method).should be_nil
+ defined?(obj.an_undefined_method).should == nil
end
it "returns nil if the variable does not exist" do
- defined?(nonexistent_local_variable.some_method).should be_nil
+ defined?(nonexistent_local_variable.some_method).should == nil
end
it "calls #respond_to_missing?" do
@@ -145,11 +145,11 @@ describe "The defined? keyword when called with a method name" do
it "returns nil if the method is not defined" do
@defined_specs_obj = DefinedSpecs::Basic.new
- defined?(@defined_specs_obj.an_undefined_method).should be_nil
+ defined?(@defined_specs_obj.an_undefined_method).should == nil
end
it "returns nil if the variable does not exist" do
- defined?(@nonexistent_instance_variable.some_method).should be_nil
+ defined?(@nonexistent_instance_variable.some_method).should == nil
end
end
@@ -161,22 +161,22 @@ describe "The defined? keyword when called with a method name" do
it "returns nil if the method is not defined" do
$defined_specs_obj = DefinedSpecs::Basic.new
- defined?($defined_specs_obj.an_undefined_method).should be_nil
+ defined?($defined_specs_obj.an_undefined_method).should == nil
end
it "returns nil if the variable does not exist" do
- defined?($nonexistent_global_variable.some_method).should be_nil
+ defined?($nonexistent_global_variable.some_method).should == nil
end
end
describe "having a method call as a receiver" do
it "returns nil if evaluating the receiver raises an exception" do
- defined?(DefinedSpecs.exception_method / 2).should be_nil
+ defined?(DefinedSpecs.exception_method / 2).should == nil
ScratchPad.recorded.should == :defined_specs_exception
end
it "returns nil if the method is not defined on the object the receiver returns" do
- defined?(DefinedSpecs.side_effects / 2).should be_nil
+ defined?(DefinedSpecs.side_effects / 2).should == nil
ScratchPad.recorded.should == :defined_specs_side_effects
end
@@ -211,6 +211,22 @@ describe "The defined? keyword when called with a method name" do
}.should complain(/warning: possibly useless use of defined\? in void context/, verbose: true)
end
end
+
+ describe "for a protected method" do
+ it "returns 'method' when the receiver is a subclass instance" do
+ DefinedSpecs::ProtectedBase.new.defined_on(DefinedSpecs::ProtectedSubclass.new).should == "method"
+ end
+
+ it "returns 'method' when the receiver is the base class instance" do
+ DefinedSpecs::ProtectedSubclass.new.defined_on(DefinedSpecs::ProtectedBase.new).should == "method"
+ end
+
+ ruby_bug "#22076", ""..."4.1" do
+ it "returns 'method' when the receiver is a sibling class instance via a shared included module" do
+ DefinedSpecs::ProtectedIncluderA.new.defined_on(DefinedSpecs::ProtectedIncluderB.new).should == "method"
+ end
+ end
+ end
end
describe "The defined? keyword for an expression" do
@@ -403,15 +419,15 @@ describe "The defined? keyword for an expression" do
end
it "returns nil for an expression with == and an undefined method" do
- defined?(defined_specs_undefined_method == 2).should be_nil
+ defined?(defined_specs_undefined_method == 2).should == nil
end
it "returns nil for an expression with != and an undefined method" do
- defined?(defined_specs_undefined_method != 2).should be_nil
+ defined?(defined_specs_undefined_method != 2).should == nil
end
it "returns nil for an expression with !~ and an undefined method" do
- defined?(defined_specs_undefined_method !~ 2).should be_nil
+ defined?(defined_specs_undefined_method !~ 2).should == nil
end
it "returns 'method' for an expression with '=='" do
@@ -431,25 +447,25 @@ describe "The defined? keyword for an expression" do
describe "with logical connectives" do
it "returns nil for an expression with '!' and an undefined method" do
- defined?(!defined_specs_undefined_method).should be_nil
+ defined?(!defined_specs_undefined_method).should == nil
end
it "returns nil for an expression with '!' and an unset class variable" do
@result = eval("class singleton_class::A; defined?(!@@doesnt_exist) end", binding, __FILE__, __LINE__)
- @result.should be_nil
+ @result.should == nil
end
it "returns nil for an expression with 'not' and an undefined method" do
- defined?(not defined_specs_undefined_method).should be_nil
+ defined?(not defined_specs_undefined_method).should == nil
end
it "returns nil for an expression with 'not' and an unset class variable" do
@result = eval("class singleton_class::A; defined?(not @@doesnt_exist) end", binding, __FILE__, __LINE__)
- @result.should be_nil
+ @result.should == nil
end
it "does not propagate an exception raised by a method in a 'not' expression" do
- defined?(not DefinedSpecs.exception_method).should be_nil
+ defined?(not DefinedSpecs.exception_method).should == nil
ScratchPad.recorded.should == :defined_specs_exception
end
@@ -488,11 +504,11 @@ describe "The defined? keyword for an expression" do
end
it "returns nil for an expression with '!' and an unset global variable" do
- defined?(!$defined_specs_undefined_global_variable).should be_nil
+ defined?(!$defined_specs_undefined_global_variable).should == nil
end
it "returns nil for an expression with '!' and an unset instance variable" do
- defined?(!@defined_specs_undefined_instance_variable).should be_nil
+ defined?(!@defined_specs_undefined_instance_variable).should == nil
end
it "returns 'method' for a 'not' expression with a method" do
@@ -505,11 +521,11 @@ describe "The defined? keyword for an expression" do
end
it "returns nil for an expression with 'not' and an unset global variable" do
- defined?(not $defined_specs_undefined_global_variable).should be_nil
+ defined?(not $defined_specs_undefined_global_variable).should == nil
end
it "returns nil for an expression with 'not' and an unset instance variable" do
- defined?(not @defined_specs_undefined_instance_variable).should be_nil
+ defined?(not @defined_specs_undefined_instance_variable).should == nil
end
it "returns 'expression' for an expression with '&&/and' and an undefined method" do
@@ -524,12 +540,12 @@ describe "The defined? keyword for an expression" do
it "does not call a method in an '&&' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects && true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "does not call a method in an 'and' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects and true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "returns 'expression' for an expression with '||/or' and an undefined method" do
@@ -544,12 +560,12 @@ describe "The defined? keyword for an expression" do
it "does not call a method in an '||' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects || true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "does not call a method in an 'or' expression and returns 'expression'" do
defined?(DefinedSpecs.side_effects or true).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
@@ -572,7 +588,7 @@ describe "The defined? keyword for an expression" do
it "does not call the method in the String" do
defined?("garble #{DefinedSpecs.dynamic_string}").should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
@@ -591,7 +607,7 @@ describe "The defined? keyword for an expression" do
it "does not call the method in the Regexp" do
defined?(/garble #{DefinedSpecs.dynamic_string}/).should == "expression"
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
end
@@ -640,11 +656,11 @@ describe "The defined? keyword for variables" do
end
it "returns nil for an instance variable that has not been read" do
- DefinedSpecs::Basic.new.instance_variable_undefined.should be_nil
+ DefinedSpecs::Basic.new.instance_variable_undefined.should == nil
end
it "returns nil for an instance variable that has been read but not assigned to" do
- DefinedSpecs::Basic.new.instance_variable_read.should be_nil
+ DefinedSpecs::Basic.new.instance_variable_read.should == nil
end
it "returns 'instance-variable' for an instance variable that has been assigned" do
@@ -658,11 +674,11 @@ describe "The defined? keyword for variables" do
end
it "returns nil for a global variable that has not been read" do
- DefinedSpecs::Basic.new.global_variable_undefined.should be_nil
+ DefinedSpecs::Basic.new.global_variable_undefined.should == nil
end
it "returns nil for a global variable that has been read but not assigned to" do
- DefinedSpecs::Basic.new.global_variable_read.should be_nil
+ DefinedSpecs::Basic.new.global_variable_read.should == nil
end
it "returns 'global-variable' for a global variable that has been assigned nil" do
@@ -694,27 +710,27 @@ describe "The defined? keyword for variables" do
end
it "returns nil for $&" do
- defined?($&).should be_nil
+ defined?($&).should == nil
end
it "returns nil for $`" do
- defined?($`).should be_nil
+ defined?($`).should == nil
end
it "returns nil for $'" do
- defined?($').should be_nil
+ defined?($').should == nil
end
it "returns nil for $+" do
- defined?($+).should be_nil
+ defined?($+).should == nil
end
it "returns nil for any last match global" do
- defined?($1).should be_nil
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($1).should == nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
@@ -749,10 +765,10 @@ describe "The defined? keyword for variables" do
end
it "returns nil for non-captures" do
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
@@ -766,27 +782,27 @@ describe "The defined? keyword for variables" do
end
it "returns nil for $&" do
- defined?($&).should be_nil
+ defined?($&).should == nil
end
it "returns nil for $`" do
- defined?($`).should be_nil
+ defined?($`).should == nil
end
it "returns nil for $'" do
- defined?($').should be_nil
+ defined?($').should == nil
end
it "returns nil for $+" do
- defined?($+).should be_nil
+ defined?($+).should == nil
end
it "returns nil for any last match global" do
- defined?($1).should be_nil
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($1).should == nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
@@ -821,10 +837,10 @@ describe "The defined? keyword for variables" do
end
it "returns nil for non-captures" do
- defined?($4).should be_nil
- defined?($7).should be_nil
- defined?($10).should be_nil
- defined?($200).should be_nil
+ defined?($4).should == nil
+ defined?($7).should == nil
+ defined?($10).should == nil
+ defined?($200).should == nil
end
end
it "returns 'global-variable' for a global variable that has been assigned" do
@@ -832,7 +848,7 @@ describe "The defined? keyword for variables" do
end
it "returns nil for a class variable that has not been read" do
- DefinedSpecs::Basic.new.class_variable_undefined.should be_nil
+ DefinedSpecs::Basic.new.class_variable_undefined.should == nil
end
# There is no spec for a class variable that is read before being assigned
@@ -859,12 +875,12 @@ describe "The defined? keyword for a simple constant" do
end
it "returns nil when the constant is not defined" do
- defined?(DefinedSpecsUndefined).should be_nil
+ defined?(DefinedSpecsUndefined).should == nil
end
it "does not call Object.const_missing if the constant is not defined" do
Object.should_not_receive(:const_missing)
- defined?(DefinedSpecsUndefined).should be_nil
+ defined?(DefinedSpecsUndefined).should == nil
end
it "returns 'constant' for an included module" do
@@ -882,12 +898,12 @@ describe "The defined? keyword for a top-level constant" do
end
it "returns nil if the constant is not defined" do
- defined?(::DefinedSpecsUndefined).should be_nil
+ defined?(::DefinedSpecsUndefined).should == nil
end
it "does not call Object.const_missing if the constant is not defined" do
Object.should_not_receive(:const_missing)
- defined?(::DefinedSpecsUndefined).should be_nil
+ defined?(::DefinedSpecsUndefined).should == nil
end
end
@@ -897,37 +913,37 @@ describe "The defined? keyword for a scoped constant" do
end
it "returns nil when the scoped constant is not defined" do
- defined?(DefinedSpecs::Undefined).should be_nil
+ defined?(DefinedSpecs::Undefined).should == nil
end
it "returns nil when the constant is not defined and the outer module implements .const_missing" do
- defined?(DefinedSpecs::ModuleWithConstMissing::Undefined).should be_nil
+ defined?(DefinedSpecs::ModuleWithConstMissing::Undefined).should == nil
end
it "does not call .const_missing if the constant is not defined" do
DefinedSpecs.should_not_receive(:const_missing)
- defined?(DefinedSpecs::UnknownChild).should be_nil
+ defined?(DefinedSpecs::UnknownChild).should == nil
end
it "returns nil when an undefined constant is scoped to a defined constant" do
- defined?(DefinedSpecs::Child::Undefined).should be_nil
+ defined?(DefinedSpecs::Child::Undefined).should == nil
end
it "returns nil when a constant is scoped to an undefined constant" do
Object.should_not_receive(:const_missing)
- defined?(Undefined::Object).should be_nil
+ defined?(Undefined::Object).should == nil
end
it "returns nil when the undefined constant is scoped to an undefined constant" do
- defined?(DefinedSpecs::Undefined::Undefined).should be_nil
+ defined?(DefinedSpecs::Undefined::Undefined).should == nil
end
it "returns nil when a constant is defined on top-level but not on the module" do
- defined?(DefinedSpecs::String).should be_nil
+ defined?(DefinedSpecs::String).should == nil
end
it "returns nil when a constant is defined on top-level but not on the class" do
- defined?(DefinedSpecs::Basic::String).should be_nil
+ defined?(DefinedSpecs::Basic::String).should == nil
end
it "returns 'constant' if the scoped-scoped constant is defined" do
@@ -941,15 +957,15 @@ describe "The defined? keyword for a top-level scoped constant" do
end
it "returns nil when the scoped constant is not defined" do
- defined?(::DefinedSpecs::Undefined).should be_nil
+ defined?(::DefinedSpecs::Undefined).should == nil
end
it "returns nil when an undefined constant is scoped to a defined constant" do
- defined?(::DefinedSpecs::Child::Undefined).should be_nil
+ defined?(::DefinedSpecs::Child::Undefined).should == nil
end
it "returns nil when the undefined constant is scoped to an undefined constant" do
- defined?(::DefinedSpecs::Undefined::Undefined).should be_nil
+ defined?(::DefinedSpecs::Undefined::Undefined).should == nil
end
it "returns 'constant' if the scoped-scoped constant is defined" do
@@ -959,7 +975,7 @@ end
describe "The defined? keyword for a self-send method call scoped constant" do
it "returns nil if the constant is not defined in the scope of the method's value" do
- defined?(defined_specs_method::Undefined).should be_nil
+ defined?(defined_specs_method::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the method's value" do
@@ -967,11 +983,11 @@ describe "The defined? keyword for a self-send method call scoped constant" do
end
it "returns nil if the last constant is not defined in the scope chain" do
- defined?(defined_specs_method::Basic::Undefined).should be_nil
+ defined?(defined_specs_method::Basic::Undefined).should == nil
end
it "returns nil if the middle constant is not defined in the scope chain" do
- defined?(defined_specs_method::Undefined::Undefined).should be_nil
+ defined?(defined_specs_method::Undefined::Undefined).should == nil
end
it "returns 'constant' if all the constants in the scope chain are defined" do
@@ -981,7 +997,7 @@ end
describe "The defined? keyword for a receiver method call scoped constant" do
it "returns nil if the constant is not defined in the scope of the method's value" do
- defined?(defined_specs_receiver.defined_method::Undefined).should be_nil
+ defined?(defined_specs_receiver.defined_method::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the method's value" do
@@ -989,11 +1005,11 @@ describe "The defined? keyword for a receiver method call scoped constant" do
end
it "returns nil if the last constant is not defined in the scope chain" do
- defined?(defined_specs_receiver.defined_method::Basic::Undefined).should be_nil
+ defined?(defined_specs_receiver.defined_method::Basic::Undefined).should == nil
end
it "returns nil if the middle constant is not defined in the scope chain" do
- defined?(defined_specs_receiver.defined_method::Undefined::Undefined).should be_nil
+ defined?(defined_specs_receiver.defined_method::Undefined::Undefined).should == nil
end
it "returns 'constant' if all the constants in the scope chain are defined" do
@@ -1003,7 +1019,7 @@ end
describe "The defined? keyword for a module method call scoped constant" do
it "returns nil if the constant is not defined in the scope of the method's value" do
- defined?(DefinedSpecs.defined_method::Undefined).should be_nil
+ defined?(DefinedSpecs.defined_method::Undefined).should == nil
end
it "returns 'constant' if the constant scoped by the method's value is defined" do
@@ -1011,11 +1027,11 @@ describe "The defined? keyword for a module method call scoped constant" do
end
it "returns nil if the last constant in the scope chain is not defined" do
- defined?(DefinedSpecs.defined_method::Basic::Undefined).should be_nil
+ defined?(DefinedSpecs.defined_method::Basic::Undefined).should == nil
end
it "returns nil if the middle constant in the scope chain is not defined" do
- defined?(DefinedSpecs.defined_method::Undefined::Undefined).should be_nil
+ defined?(DefinedSpecs.defined_method::Undefined::Undefined).should == nil
end
it "returns 'constant' if all the constants in the scope chain are defined" do
@@ -1023,11 +1039,11 @@ describe "The defined? keyword for a module method call scoped constant" do
end
it "returns nil if the outer scope constant in the receiver is not defined" do
- defined?(Undefined::DefinedSpecs.defined_method::Basic).should be_nil
+ defined?(Undefined::DefinedSpecs.defined_method::Basic).should == nil
end
it "returns nil if the scoped constant in the receiver is not defined" do
- defined?(DefinedSpecs::Undefined.defined_method::Basic).should be_nil
+ defined?(DefinedSpecs::Undefined.defined_method::Basic).should == nil
end
it "returns 'constant' if all the constants in the receiver are defined" do
@@ -1048,7 +1064,7 @@ describe "The defined? keyword for a variable scoped constant" do
it "returns nil if the instance scoped constant is not defined" do
@defined_specs_obj = DefinedSpecs::Basic
- defined?(@defined_specs_obj::Undefined).should be_nil
+ defined?(@defined_specs_obj::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the instance variable" do
@@ -1058,7 +1074,7 @@ describe "The defined? keyword for a variable scoped constant" do
it "returns nil if the global scoped constant is not defined" do
$defined_specs_obj = DefinedSpecs::Basic
- defined?($defined_specs_obj::Undefined).should be_nil
+ defined?($defined_specs_obj::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the global variable" do
@@ -1070,7 +1086,7 @@ describe "The defined? keyword for a variable scoped constant" do
eval(<<-END, binding, __FILE__, __LINE__)
class singleton_class::A
@@defined_specs_obj = DefinedSpecs::Basic
- defined?(@@defined_specs_obj::Undefined).should be_nil
+ defined?(@@defined_specs_obj::Undefined).should == nil
end
END
end
@@ -1086,7 +1102,7 @@ describe "The defined? keyword for a variable scoped constant" do
it "returns nil if the local scoped constant is not defined" do
defined_specs_obj = DefinedSpecs::Basic
- defined?(defined_specs_obj::Undefined).should be_nil
+ defined?(defined_specs_obj::Undefined).should == nil
end
it "returns 'constant' if the constant is defined in the scope of the local variable" do
@@ -1107,11 +1123,11 @@ end
describe "The defined? keyword for yield" do
it "returns nil if no block is passed to a method not taking a block parameter" do
- DefinedSpecs::Basic.new.no_yield_block.should be_nil
+ DefinedSpecs::Basic.new.no_yield_block.should == nil
end
it "returns nil if no block is passed to a method taking a block parameter" do
- DefinedSpecs::Basic.new.no_yield_block_parameter.should be_nil
+ DefinedSpecs::Basic.new.no_yield_block_parameter.should == nil
end
it "returns 'yield' if a block is passed to a method not taking a block parameter" do
@@ -1139,24 +1155,24 @@ end
describe "The defined? keyword for super" do
it "returns nil when a superclass undef's the method" do
- DefinedSpecs::ClassWithoutMethod.new.test.should be_nil
+ DefinedSpecs::ClassWithoutMethod.new.test.should == nil
end
describe "for a method taking no arguments" do
it "returns nil when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_no_args.should == nil
end
it "returns nil from a block when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_block_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_block_no_args.should == nil
end
it "returns nil from a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_no_args.should == nil
end
it "returns nil from a block in a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_block_no_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_block_no_args.should == nil
end
it "returns 'super' when a superclass method exists" do
@@ -1184,19 +1200,19 @@ describe "The defined? keyword for super" do
describe "for a method taking arguments" do
it "returns nil when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_args.should == nil
end
it "returns nil from a block when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_method_block_args.should be_nil
+ DefinedSpecs::Super.new.no_super_method_block_args.should == nil
end
it "returns nil from a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_args.should == nil
end
it "returns nil from a block in a #define_method when no superclass method exists" do
- DefinedSpecs::Super.new.no_super_define_method_block_args.should be_nil
+ DefinedSpecs::Super.new.no_super_define_method_block_args.should == nil
end
it "returns 'super' when a superclass method exists" do
@@ -1231,7 +1247,7 @@ describe "The defined? keyword for instance variables" do
end
it "returns nil if not assigned" do
- defined?(@unassigned_ivar).should be_nil
+ defined?(@unassigned_ivar).should == nil
end
end
diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb
index 0fcd3e57bf..3d917993f5 100644
--- a/spec/ruby/language/delegation_spec.rb
+++ b/spec/ruby/language/delegation_spec.rb
@@ -37,6 +37,16 @@ describe "delegation with def(...)" do
a.new.delegate(1, b: 2, &block).should == [[1], {b: 2}, block]
end
+ it "delegates with additional arguments" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(...)
+ target(:first, :second, ...)
+ end
+ RUBY
+ a.new.delegate(1, b: 2).should == [[:first, :second, 1], {b: 2}, nil]
+ end
+
it "parses as open endless Range when brackets are omitted" do
a = Class.new(DelegationSpecs::Target)
suppress_warning do
@@ -87,52 +97,44 @@ describe "delegation with def(x, ...)" do
end
end
-ruby_version_is "3.2" do
- describe "delegation with def(*)" do
- it "delegates rest" do
- a = Class.new(DelegationSpecs::Target)
- a.class_eval(<<-RUBY)
- def delegate(*)
- target(*)
- end
- RUBY
-
- a.new.delegate(0, 1).should == [[0, 1], {}, nil]
+describe "delegation with def(*)" do
+ it "delegates rest" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(*)
+ target(*)
end
+ RUBY
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
- it "does not allow delegating rest" do
- -> {
- eval "def m(*); proc { |*| n(*) } end"
- }.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/)
- end
- end
+ a.new.delegate(0, 1).should == [[0, 1], {}, nil]
+ end
+
+ context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
+ it "does not allow delegating rest" do
+ -> {
+ eval "def m(*); proc { |*| n(*) } end"
+ }.should.raise(SyntaxError, /anonymous rest parameter is also used within block/)
end
end
end
-ruby_version_is "3.2" do
- describe "delegation with def(**)" do
- it "delegates kwargs" do
- a = Class.new(DelegationSpecs::Target)
- a.class_eval(<<-RUBY)
- def delegate(**)
- target(**)
- end
- RUBY
-
- a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}, nil]
+describe "delegation with def(**)" do
+ it "delegates kwargs" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(**)
+ target(**)
end
+ RUBY
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
- it "does not allow delegating kwargs" do
- -> {
- eval "def m(**); proc { |**| n(**) } end"
- }.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/)
- end
- end
+ a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}, nil]
+ end
+
+ context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
+ it "does not allow delegating kwargs" do
+ -> {
+ eval "def m(**); proc { |**| n(**) } end"
+ }.should.raise(SyntaxError, /anonymous keyword rest parameter is also used within block/)
end
end
end
@@ -150,13 +152,11 @@ describe "delegation with def(&)" do
a.new.delegate(&block).should == [[], {}, block]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous block within a method that accepts anonymous block" do
- it "does not allow delegating a block" do
- -> {
- eval "def m(&); proc { |&| n(&) } end"
- }.should raise_error(SyntaxError, /anonymous block parameter is also used within block/)
- end
+ context "within a block that accepts anonymous block within a method that accepts anonymous block" do
+ it "does not allow delegating a block" do
+ -> {
+ eval "def m(&); proc { |&| n(&) } end"
+ }.should.raise(SyntaxError, /anonymous block parameter is also used within block/)
end
end
end
diff --git a/spec/ruby/language/encoding_spec.rb b/spec/ruby/language/encoding_spec.rb
index e761a53cb6..116f53a77d 100644
--- a/spec/ruby/language/encoding_spec.rb
+++ b/spec/ruby/language/encoding_spec.rb
@@ -5,7 +5,7 @@ require_relative 'fixtures/coding_utf_8'
describe "The __ENCODING__ pseudo-variable" do
it "is an instance of Encoding" do
- __ENCODING__.should be_kind_of(Encoding)
+ __ENCODING__.should.is_a?(Encoding)
end
it "is US-ASCII by default" do
@@ -31,6 +31,6 @@ describe "The __ENCODING__ pseudo-variable" do
end
it "raises a SyntaxError if assigned to" do
- -> { eval("__ENCODING__ = 1") }.should raise_error(SyntaxError)
+ -> { eval("__ENCODING__ = 1") }.should.raise(SyntaxError)
end
end
diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb
index b76292c007..04ff0305ab 100644
--- a/spec/ruby/language/ensure_spec.rb
+++ b/spec/ruby/language/ensure_spec.rb
@@ -6,7 +6,7 @@ describe "An ensure block inside a begin block" do
ScratchPad.record []
end
- it "is executed when an exception is raised in it's corresponding begin block" do
+ it "is executed when an exception is raised in its corresponding begin block" do
-> {
begin
ScratchPad << :begin
@@ -14,12 +14,12 @@ describe "An ensure block inside a begin block" do
ensure
ScratchPad << :ensure
end
- }.should raise_error(EnsureSpec::Error)
+ }.should.raise(EnsureSpec::Error)
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ it "is executed when an exception is raised and rescued in its corresponding begin block" do
begin
ScratchPad << :begin
raise "An exception occurred!"
@@ -32,7 +32,7 @@ describe "An ensure block inside a begin block" do
ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ it "is executed even when a symbol is thrown in its corresponding begin block" do
catch(:symbol) do
begin
ScratchPad << :begin
@@ -47,7 +47,7 @@ describe "An ensure block inside a begin block" do
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ it "is executed when nothing is raised or thrown in its corresponding begin block" do
begin
ScratchPad << :begin
rescue
@@ -74,7 +74,7 @@ describe "An ensure block inside a begin block" do
ensure
raise "from ensure"
end
- }.should raise_error(RuntimeError, "from ensure") { |e|
+ }.should.raise(RuntimeError, "from ensure") { |e|
e.cause.message.should == "from block"
}
end
@@ -108,7 +108,7 @@ describe "An ensure block inside a method" do
end
it "is executed when an exception is raised in the method" do
- -> { @obj.raise_in_method_with_ensure }.should raise_error(EnsureSpec::Error)
+ -> { @obj.raise_in_method_with_ensure }.should.raise(EnsureSpec::Error)
@obj.executed.should == [:method, :ensure]
end
@@ -149,13 +149,13 @@ describe "An ensure block inside a method" do
it "overrides exception raised in rescue if raises exception itself" do
-> {
@obj.raise_in_rescue_and_raise_in_ensure
- }.should raise_error(RuntimeError, "raised in ensure")
+ }.should.raise(RuntimeError, "raised in ensure")
end
it "suppresses exception raised in method if raises exception itself" do
-> {
@obj.raise_in_method_and_raise_in_ensure
- }.should raise_error(RuntimeError, "raised in ensure")
+ }.should.raise(RuntimeError, "raised in ensure")
end
end
@@ -174,7 +174,7 @@ describe "An ensure block inside a class" do
ScratchPad << :ensure
end
ruby
- }.should raise_error(EnsureSpec::Error)
+ }.should.raise(EnsureSpec::Error)
ScratchPad.recorded.should == [:class, :ensure]
end
@@ -247,7 +247,7 @@ describe "An ensure block inside {} block" do
ensure
}
ruby
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -256,7 +256,7 @@ describe "An ensure block inside 'do end' block" do
ScratchPad.record []
end
- it "is executed when an exception is raised in it's corresponding begin block" do
+ it "is executed when an exception is raised in its corresponding begin block" do
-> {
eval(<<-ruby).call
lambda do
@@ -266,12 +266,12 @@ describe "An ensure block inside 'do end' block" do
ScratchPad << :ensure
end
ruby
- }.should raise_error(EnsureSpec::Error)
+ }.should.raise(EnsureSpec::Error)
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ it "is executed when an exception is raised and rescued in its corresponding begin block" do
eval(<<-ruby).call
lambda do
ScratchPad << :begin
@@ -286,7 +286,7 @@ describe "An ensure block inside 'do end' block" do
ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ it "is executed even when a symbol is thrown in its corresponding begin block" do
catch(:symbol) do
eval(<<-ruby).call
lambda do
@@ -303,7 +303,7 @@ describe "An ensure block inside 'do end' block" do
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ it "is executed when nothing is raised or thrown in its corresponding begin block" do
eval(<<-ruby).call
lambda do
ScratchPad << :begin
diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb
index 59563d9642..dd89ce2385 100644
--- a/spec/ruby/language/file_spec.rb
+++ b/spec/ruby/language/file_spec.rb
@@ -4,19 +4,11 @@ require_relative 'shared/__FILE__'
describe "The __FILE__ pseudo-variable" do
it "raises a SyntaxError if assigned to" do
- -> { eval("__FILE__ = 1") }.should raise_error(SyntaxError)
+ -> { eval("__FILE__ = 1") }.should.raise(SyntaxError)
end
- ruby_version_is ""..."3.3" do
- it "equals (eval) inside an eval" do
- eval("__FILE__").should == "(eval)"
- end
- end
-
- ruby_version_is "3.3" do
- it "equals (eval at __FILE__:__LINE__) inside an eval" do
- eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
- end
+ it "equals (eval at __FILE__:__LINE__) inside an eval" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
end
end
diff --git a/spec/ruby/language/fixtures/class_with_class_variable.rb b/spec/ruby/language/fixtures/class_with_class_variable.rb
new file mode 100644
index 0000000000..0b07f16d30
--- /dev/null
+++ b/spec/ruby/language/fixtures/class_with_class_variable.rb
@@ -0,0 +1,9 @@
+module StringSpecs
+ class ClassWithClassVariable
+ @@a = "xxx"
+
+ def foo
+ "#@@a"
+ end
+ end
+end
diff --git a/spec/ruby/language/fixtures/defined.rb b/spec/ruby/language/fixtures/defined.rb
index 3761cfa5bd..15bd7c50cf 100644
--- a/spec/ruby/language/fixtures/defined.rb
+++ b/spec/ruby/language/fixtures/defined.rb
@@ -299,6 +299,33 @@ module DefinedSpecs
super
end
end
+
+ class ProtectedBase
+ def m; end
+ protected :m
+ def defined_on(o)
+ defined?(o.m)
+ end
+ end
+
+ class ProtectedSubclass < ProtectedBase
+ end
+
+ module ProtectedInModule
+ def m; end
+ protected :m
+ def defined_on(o)
+ defined?(o.m)
+ end
+ end
+
+ class ProtectedIncluderA
+ include ProtectedInModule
+ end
+
+ class ProtectedIncluderB
+ include ProtectedInModule
+ end
end
class Object
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb b/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb
index 3aed2f29b6..f3ef666a3c 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_across_files.rb
@@ -2,4 +2,5 @@
require_relative 'freeze_magic_comment_required'
-p "abc".object_id == $second_literal_id
+p "abc".equal?($second_literal)
+$second_literal = nil
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb
index 53ef959970..e9ca35e7c8 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_diff_enc.rb
@@ -2,4 +2,5 @@
require_relative 'freeze_magic_comment_required_diff_enc'
-p "abc".object_id != $second_literal_id
+p !"abc".equal?($second_literal)
+$second_literal = nil
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb
index fc6cd5bf82..c9eaab46a2 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_across_files_no_comment.rb
@@ -2,4 +2,5 @@
require_relative 'freeze_magic_comment_required_no_comment'
-p "abc".object_id != $second_literal_id
+p !"abc".equal?($second_literal)
+$second_literal = nil
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb b/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb
index d35905b332..c175b2b7a2 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_one_literal.rb
@@ -1,4 +1,4 @@
# frozen_string_literal: true
-ids = Array.new(2) { "abc".object_id }
-p ids.first == ids.last
+objs = Array.new(2) { "abc" }
+p objs.first.equal?(objs.last)
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required.rb
index a4ff4459b1..f75acb2ce3 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required.rb
@@ -1,3 +1,3 @@
# frozen_string_literal: true
-$second_literal_id = "abc".object_id
+$second_literal = "abc"
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
index f72a32e879..739e96e99a 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
@@ -1,4 +1,4 @@
# encoding: euc-jp # built-in for old regexp option
# frozen_string_literal: true
-$second_literal_id = "abc".object_id
+$second_literal = "abc"
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb
index e09232a5f4..6fbe175b42 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required_no_comment.rb
@@ -1 +1 @@
-$second_literal_id = "abc".object_id
+$second_literal = "abc"
diff --git a/spec/ruby/language/fixtures/module.rb b/spec/ruby/language/fixtures/module.rb
index 33d323846e..75eee77791 100644
--- a/spec/ruby/language/fixtures/module.rb
+++ b/spec/ruby/language/fixtures/module.rb
@@ -12,13 +12,4 @@ module ModuleSpecs
module Anonymous
end
-
- module IncludedInObject
- module IncludedModuleSpecs
- end
- end
-end
-
-class Object
- include ModuleSpecs::IncludedInObject
end
diff --git a/spec/ruby/language/fixtures/send.rb b/spec/ruby/language/fixtures/send.rb
index 5d1d9da214..4787abee5c 100644
--- a/spec/ruby/language/fixtures/send.rb
+++ b/spec/ruby/language/fixtures/send.rb
@@ -81,6 +81,16 @@ module LangSendSpecs
end
end
+ class RawToProc
+ def initialize(to_proc)
+ @to_proc = to_proc
+ end
+
+ def to_proc
+ @to_proc
+ end
+ end
+
class ToAry
def initialize(obj)
@obj = obj
diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb
index c5bdcf0e40..b6d4218b03 100644
--- a/spec/ruby/language/fixtures/super.rb
+++ b/spec/ruby/language/fixtures/super.rb
@@ -266,7 +266,7 @@ module SuperSpecs
# Use this so that we can see collect all supers that we see.
# One bug that arises is that we call Alias2#name from Alias2#name
- # as it's superclass. In that case, either we get a runaway recursion
+ # as its superclass. In that case, either we get a runaway recursion
# super OR we get the return value being [:alias2, :alias2, :alias1]
# rather than [:alias2, :alias1].
#
diff --git a/spec/ruby/language/for_spec.rb b/spec/ruby/language/for_spec.rb
index b8ddfe5f0d..b0f3aef405 100644
--- a/spec/ruby/language/for_spec.rb
+++ b/spec/ruby/language/for_spec.rb
@@ -129,37 +129,34 @@ describe "The for expression" do
n.should == 3
end
- # Segfault in MRI 3.3 and lower: https://bugs.ruby-lang.org/issues/20468
- ruby_bug "#20468", ""..."3.4" do
- it "allows an attribute with safe navigation as an iterator name" do
- class OFor
- attr_accessor :target
- end
-
- ofor = OFor.new
- m = [1,2,3]
- n = 0
- eval <<~RUBY
- for ofor&.target in m
- n += 1
- end
- RUBY
- ofor.target.should == 3
- n.should == 3
+ it "allows an attribute with safe navigation as an iterator name" do
+ class OFor
+ attr_accessor :target
end
- it "allows an attribute with safe navigation on a nil base as an iterator name" do
- ofor = nil
- m = [1,2,3]
- n = 0
- eval <<~RUBY
- for ofor&.target in m
- n += 1
- end
- RUBY
- ofor.should be_nil
- n.should == 3
- end
+ ofor = OFor.new
+ m = [1,2,3]
+ n = 0
+ eval <<~RUBY
+ for ofor&.target in m
+ n += 1
+ end
+ RUBY
+ ofor.target.should == 3
+ n.should == 3
+ end
+
+ it "allows an attribute with safe navigation on a nil base as an iterator name" do
+ ofor = nil
+ m = [1,2,3]
+ n = 0
+ eval <<~RUBY
+ for ofor&.target in m
+ n += 1
+ end
+ RUBY
+ ofor.should == nil
+ n.should == 3
end
it "allows an array index writer as an iterator name" do
@@ -218,7 +215,15 @@ describe "The for expression" do
j.should == 6
end
- it "executes code in containing variable scope" do
+ it "declares iteration variables in the surrounding variable scope" do
+ for a, b in [[1,2]]
+ end
+
+ a.should == 1
+ b.should == 2
+ end
+
+ it "declares variables in the body in the surrounding variable scope" do
for i in 1..2
a = 123
end
@@ -226,7 +231,7 @@ describe "The for expression" do
a.should == 123
end
- it "executes code in containing variable scope with 'do'" do
+ it "declares variables in the body in the surrounding variable scope with 'do'" do
for i in 1..2 do
a = 123
end
@@ -234,6 +239,96 @@ describe "The for expression" do
a.should == 123
end
+ it "declares variables inside a block as normal" do
+ for i in 1..2 do
+ proc {
+ inside_proc = 42
+ }.call
+ end
+ local_variables.should == [:i]
+ end
+
+ it "declares variables inside a lambda as normal" do
+ for i in 1..2 do
+ -> {
+ inside_proc = 42
+ }.call
+ end
+ local_variables.should == [:i]
+ end
+
+ it "can be nested" do
+ for a in [6]
+ for b in [7]
+ c = a * b
+ end
+ end
+ local_variables.sort.should == [:a, :b, :c]
+ c.should == 42
+ end
+
+ it "can be nested with blocks in between" do
+ # This is an edge case spec for Ruby implementations which have
+ # their own runtime scope per for loop body (like YARV and TruffleRuby)
+ for a in [1]
+ a1 = a
+ a1.should == a
+ for b in [2]
+ b1 = b
+ a1.should == a
+ b1.should == b
+ proc {
+ inside_proc = 42
+
+ a1.should == a
+ b1.should == b
+ inside_proc.should == 42
+
+ for c in [3].map { |enum_var|
+ a1.should == a
+ b1.should == b
+ inside_proc.should == 42
+ enum_var
+ }
+ c1 = c
+
+ a1.should == a
+ b1.should == b
+ c1.should == c
+ inside_proc.should == 42
+
+ for d in [4]
+ d1 = d
+
+ a1.should == a
+ b1.should == b
+ c1.should == c
+ d1.should == d
+ inside_proc.should == 42
+ end
+ end
+ local_variables.sort.should == [:a, :a1, :b, :b1, :c, :c1, :d, :d1, :inside_proc]
+ }.call
+ end
+ end
+ local_variables.sort.should == [:a, :a1, :b, :b1]
+ end
+
+ it "can be nested with forward arguments" do
+ def bar(*args)
+ args
+ end
+
+ def foo(...)
+ for a in [1]
+ r = bar(...)
+ end
+ r
+ end
+
+ foo(2, 3).should == [2, 3]
+ end
+
it "does not try to access variables outside the method" do
ForSpecs::ForInClassMethod.foo.should == [:bar, :baz]
ForSpecs::ForInClassMethod::READER.call.should == :same_variable_set_outside
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index b119b6ca73..7a4a2e37c9 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -81,7 +81,7 @@ describe "Hash literal" do
end
it "with '==>' in the middle raises SyntaxError" do
- -> { eval("{:a ==> 1}") }.should raise_error(SyntaxError)
+ -> { eval("{:a ==> 1}") }.should.raise(SyntaxError)
end
it "recognizes '!' at the end of the key" do
@@ -93,7 +93,7 @@ describe "Hash literal" do
end
it "raises a SyntaxError if there is no space between `!` and `=>`" do
- -> { eval("{:a!=> 1}") }.should raise_error(SyntaxError)
+ -> { eval("{:a!=> 1}") }.should.raise(SyntaxError)
end
it "recognizes '?' at the end of the key" do
@@ -105,7 +105,7 @@ describe "Hash literal" do
end
it "raises a SyntaxError if there is no space between `?` and `=>`" do
- -> { eval("{:a?=> 1}") }.should raise_error(SyntaxError)
+ -> { eval("{:a?=> 1}") }.should.raise(SyntaxError)
end
it "constructs a new hash with the given elements" do
@@ -149,6 +149,37 @@ describe "Hash literal" do
{a: 1, **h, c: 4}.should == {a: 1, b: 2, c: 4}
end
+ ruby_version_is ""..."3.4" do
+ it "does not expand nil using ** into {} and raises TypeError" do
+ h = nil
+ -> { {a: 1, **h} }.should.raise(TypeError, "no implicit conversion of nil into Hash")
+
+ -> { {a: 1, **nil} }.should.raise(TypeError, "no implicit conversion of nil into Hash")
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "expands nil using ** into {}" do
+ h = nil
+ {**h}.should == {}
+ {a: 1, **h}.should == {a: 1}
+
+ {**nil}.should == {}
+ {a: 1, **nil}.should == {a: 1}
+ end
+
+ it "expands nil using ** into {} and provides a copy to the callable" do
+ ScratchPad.record []
+ insert = -> key, **kw do
+ kw[key] = 1
+ ScratchPad << kw
+ end
+ insert.call(:foo, **nil)
+ insert.call(:bar, **nil)
+ ScratchPad.recorded.should == [{ foo: 1 }, { bar: 1 }]
+ end
+ end
+
it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do
-> {
@h = eval "{a: 1, **{a: 2, b: 3, c: 1}, c: 3}"
@@ -192,13 +223,13 @@ describe "Hash literal" do
obj = mock("hash splat")
obj.should_receive(:to_hash).and_return(obj)
- -> { {**obj} }.should raise_error(TypeError)
+ -> { {**obj} }.should.raise(TypeError)
end
it "raises a TypeError if the object does not respond to #to_hash" do
obj = 42
- -> { {**obj} }.should raise_error(TypeError)
- -> { {a: 1, **obj} }.should raise_error(TypeError)
+ -> { {**obj} }.should.raise(TypeError)
+ -> { {a: 1, **obj} }.should.raise(TypeError)
end
it "does not change encoding of literal string keys during creation" do
@@ -218,7 +249,7 @@ describe "Hash literal" do
ScratchPad.record []
-> {
eval 'ScratchPad << 1; {:"\xC3" => 1}'
- }.should raise_error(SyntaxError, /invalid symbol/)
+ }.should.raise(SyntaxError, /invalid symbol/)
ScratchPad.recorded.should == []
end
@@ -226,7 +257,7 @@ describe "Hash literal" do
ScratchPad.record []
-> {
eval 'ScratchPad << 1; {"\xC3": 1}'
- }.should raise_error(SyntaxError, /invalid symbol/)
+ }.should.raise(SyntaxError, /invalid symbol/)
ScratchPad.recorded.should == []
end
end
@@ -244,17 +275,15 @@ describe "The ** operator" do
h.should == { one: 1, two: 2 }
end
- ruby_bug "#20012", ""..."3.3" do
- it "makes a copy when calling a method taking a positional Hash" do
- def m(h)
- h.delete(:one); h
- end
-
- h = { one: 1, two: 2 }
- m(**h).should == { two: 2 }
- m(**h).should_not.equal?(h)
- h.should == { one: 1, two: 2 }
+ it "makes a copy when calling a method taking a positional Hash" do
+ def m(h)
+ h.delete(:one); h
end
+
+ h = { one: 1, two: 2 }
+ m(**h).should == { two: 2 }
+ m(**h).should_not.equal?(h)
+ h.should == { one: 1, two: 2 }
end
describe "hash with omitted value" do
@@ -294,11 +323,11 @@ describe "The ** operator" do
end
it "raises a SyntaxError when the hash key ends with `!`" do
- -> { eval("{a!:}") }.should raise_error(SyntaxError, /identifier a! is not valid to get/)
+ -> { eval("{a!:}") }.should.raise(SyntaxError, /identifier a! is not valid to get/)
end
it "raises a SyntaxError when the hash key ends with `?`" do
- -> { eval("{a?:}") }.should raise_error(SyntaxError, /identifier a\? is not valid to get/)
+ -> { eval("{a?:}") }.should.raise(SyntaxError, /identifier a\? is not valid to get/)
end
end
end
diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb
index 47ee9c2c51..535f18cba8 100644
--- a/spec/ruby/language/heredoc_spec.rb
+++ b/spec/ruby/language/heredoc_spec.rb
@@ -62,7 +62,7 @@ HERE
it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do
-> {
eval %{<<"HERE\n"\nraises syntax error\nHERE}
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do
@@ -114,6 +114,6 @@ HERE
b
#{c}
HERE
- }.should raise_error(NameError) { |e| e.backtrace[0].should.start_with?("#{__FILE__}:#{__LINE__ - 2}") }
+ }.should.raise(NameError) { |e| e.backtrace[0].should.start_with?("#{__FILE__}:#{__LINE__ - 2}") }
end
end
diff --git a/spec/ruby/language/if_spec.rb b/spec/ruby/language/if_spec.rb
index 2d1a89f081..53fcb853d5 100644
--- a/spec/ruby/language/if_spec.rb
+++ b/spec/ruby/language/if_spec.rb
@@ -330,7 +330,7 @@ describe "The if expression" do
a
end
RUBY
- }.should raise_error(SyntaxError, /void value expression/)
+ }.should.raise(SyntaxError, /void value expression/)
end
it "does not raise SyntaxError if one branch returns a value" do
diff --git a/spec/ruby/language/it_parameter_spec.rb b/spec/ruby/language/it_parameter_spec.rb
new file mode 100644
index 0000000000..6ba67cbb4f
--- /dev/null
+++ b/spec/ruby/language/it_parameter_spec.rb
@@ -0,0 +1,108 @@
+require_relative '../spec_helper'
+
+ruby_version_is "3.4" do
+ eval <<-RUBY # use eval to avoid warnings on Ruby 3.3
+ describe "The `it` parameter" do
+ it "provides it in a block" do
+ -> { it }.call("a").should == "a"
+ proc { it }.call("a").should == "a"
+ lambda { it }.call("a").should == "a"
+ ["a"].map { it }.should == ["a"]
+ end
+
+ it "assigns nil to not passed parameters" do
+ proc { it }.call().should == nil
+ end
+
+ it "can be used in both outer and nested blocks at the same time" do
+ -> { it + -> { it * it }.call(2) }.call(3).should == 7
+ end
+
+ it "can be reassigned to act as a local variable" do
+ proc { tmp = it; it = tmp * 2; it }.call(21).should == 42
+ end
+
+ it "is a regular local variable if there is already a 'it' local variable" do
+ it = 0
+ proc { it }.call("a").should == 0
+ end
+
+ it "is a regular local variable if there is a method `it` defined" do
+ o = Object.new
+ def o.it
+ 21
+ end
+
+ o.instance_eval("proc { it * 2 }").call(1).should == 2
+ end
+
+ it "is not shadowed by an reassignment in a block" do
+ a = nil
+ proc { a = it; it = 42 }.call(0)
+ a.should == 0 # if `it` were shadowed its value would be nil
+ end
+
+ it "raises SyntaxError when block parameters are specified explicitly" do
+ -> { eval("-> () { it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> (x) { it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+
+ -> { eval("proc { || it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { |x| it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+
+ -> { eval("lambda { || it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { |x| it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+
+ -> { eval("['a'].map { || it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { |x| it }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ end
+
+ it "cannot be mixed with numbered parameters" do
+ -> {
+ eval("proc { it + _1 }")
+ }.should.raise(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/)
+
+ -> {
+ eval("proc { _1 + it }")
+ }.should.raise(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/)
+ end
+
+ it "affects block arity" do
+ -> {}.arity.should == 0
+ -> { it }.arity.should == 1
+ end
+
+ it "affects block parameters" do
+ -> { it }.parameters.should == [[:req]]
+
+ ruby_version_is ""..."4.0" do
+ proc { it }.parameters.should == [[:opt, nil]]
+ end
+ ruby_version_is "4.0" do
+ proc { it }.parameters.should == [[:opt]]
+ end
+ end
+
+ it "does not affect binding local variables" do
+ -> { it; binding.local_variables }.call("a").should == []
+ end
+
+ it "does not work in methods" do
+ obj = Object.new
+ def obj.foo; it; end
+
+ -> { obj.foo("a") }.should.raise(ArgumentError, /wrong number of arguments/)
+ end
+
+ context "given multiple arguments" do
+ it "provides it in a block and assigns the first argument for a block" do
+ proc { it }.call("a", "b").should == "a"
+ end
+
+ it "raises ArgumentError for a proc" do
+ -> { -> { it }.call("a", "b") }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ -> { lambda { it }.call("a", "b") }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+ end
+ end
+ RUBY
+end
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index 3f8ddfa40d..38edc24414 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -55,9 +55,9 @@ describe "Keyword arguments" do
end
m(kw: 1).should == []
- -> { m(kw: 1, kw2: 2) }.should raise_error(ArgumentError, 'unknown keyword: :kw2')
- -> { m(kw: 1, true => false) }.should raise_error(ArgumentError, 'unknown keyword: true')
- -> { m(kw: 1, a: 1, b: 2, c: 3) }.should raise_error(ArgumentError, 'unknown keywords: :a, :b, :c')
+ -> { m(kw: 1, kw2: 2) }.should.raise(ArgumentError, 'unknown keyword: :kw2')
+ -> { m(kw: 1, true => false) }.should.raise(ArgumentError, 'unknown keyword: true')
+ -> { m(kw: 1, a: 1, b: 2, c: 3) }.should.raise(ArgumentError, 'unknown keywords: :a, :b, :c')
end
it "raises ArgumentError exception when required keyword argument is not passed" do
@@ -65,8 +65,8 @@ describe "Keyword arguments" do
[a, b, c]
end
- -> { m(a: 1, b: 2) }.should raise_error(ArgumentError, /missing keyword: :c/)
- -> { m() }.should raise_error(ArgumentError, /missing keywords: :a, :b, :c/)
+ -> { m(a: 1, b: 2) }.should.raise(ArgumentError, /missing keyword: :c/)
+ -> { m() }.should.raise(ArgumentError, /missing keywords: :a, :b, :c/)
end
it "raises ArgumentError for missing keyword arguments even if there are extra ones" do
@@ -74,7 +74,7 @@ describe "Keyword arguments" do
a
end
- -> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/)
+ -> { m(b: 1) }.should.raise(ArgumentError, /missing keyword: :a/)
end
it "handle * and ** at the same call site" do
@@ -86,17 +86,29 @@ describe "Keyword arguments" do
m(*[], 42, **{}).should == [42]
end
- context "**" do
- ruby_version_is "3.3" do
- it "copies a non-empty Hash for a method taking (*args)" do
- def m(*args)
- args[0]
- end
+ context "marked as ruby2_keywords_hash" do
+ it "is not copied when passed as a positional argument" do
+ h = Hash.ruby2_keywords_hash(a:1)
+
+ def bar(a)
+ a
+ end
+
+ h2 = bar(h)
+ h2.should.equal?(h)
+ Hash.ruby2_keywords_hash?(h).should == true
+ end
+ end
- h = {a: 1}
- m(**h).should_not.equal?(h)
- h.should == {a: 1}
+ context "**" do
+ it "copies a non-empty Hash for a method taking (*args)" do
+ def m(*args)
+ args[0]
end
+
+ h = {a: 1}
+ m(**h).should_not.equal?(h)
+ h.should == {a: 1}
end
it "copies the given Hash for a method taking (**kwargs)" do
@@ -336,61 +348,23 @@ describe "Keyword arguments" do
end
end
- ruby_version_is "3.2" do
- it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do
- class << self
- def n(*args) # Note the missing ruby2_keywords here
- target(*args)
- end
-
- ruby2_keywords def m(*args)
- n(*args)
- end
+ it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do
+ class << self
+ def n(*args) # Note the missing ruby2_keywords here
+ target(*args)
end
- empty = {}
- m(**empty).should == [[], {}]
- m(empty).should == [[{}], {}]
-
- m(a: 1).should == [[{a: 1}], {}]
- m({a: 1}).should == [[{a: 1}], {}]
- end
- end
-
- ruby_version_is ""..."3.2" do
- # https://bugs.ruby-lang.org/issues/18625
- it "works with call(*ruby2_keyword_args) with missing ruby2_keywords in between due to CRuby bug #18625" do
- class << self
- def n(*args) # Note the missing ruby2_keywords here
- target(*args)
- end
-
- ruby2_keywords def m(*args)
- n(*args)
- end
+ ruby2_keywords def m(*args)
+ n(*args)
end
+ end
- empty = {}
- m(**empty).should == [[], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
- m(empty).should == [[{}], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
-
- m(a: 1).should == [[], {a: 1}]
- m({a: 1}).should == [[{a: 1}], {}]
-
- kw = {a: 1}
-
- m(**kw).should == [[], {a: 1}]
- m(**kw)[1].should == kw
- m(**kw)[1].should_not.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
- m(kw).should == [[{a: 1}], {}]
- m(kw)[0][0].should.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- end
+ m(a: 1).should == [[{a: 1}], {}]
+ m({a: 1}).should == [[{a: 1}], {}]
end
end
diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb
index ed5a1c69e8..c6239e32bb 100644
--- a/spec/ruby/language/lambda_spec.rb
+++ b/spec/ruby/language/lambda_spec.rb
@@ -11,23 +11,29 @@ describe "A lambda literal -> () { }" do
end
end
- klass.new.create_lambda.should be_an_instance_of(Proc)
+ klass.new.create_lambda.should.instance_of?(Proc)
+ end
+
+ it "is not just syntactic sugar for Kernel#lambda" do
+ should_not_receive(:lambda)
+
+ -> {}
end
it "does not execute the block" do
- -> { fail }.should be_an_instance_of(Proc)
+ -> { fail }.should.instance_of?(Proc)
end
it "returns a lambda" do
- -> { }.lambda?.should be_true
+ -> { }.lambda?.should == true
end
it "may include a rescue clause" do
- eval('-> do raise ArgumentError; rescue ArgumentError; 7; end').should be_an_instance_of(Proc)
+ eval('-> do raise ArgumentError; rescue ArgumentError; 7; end').should.instance_of?(Proc)
end
it "may include a ensure clause" do
- eval('-> do 1; ensure; 2; end').should be_an_instance_of(Proc)
+ eval('-> do 1; ensure; 2; end').should.instance_of?(Proc)
end
it "has its own scope for local variables" do
@@ -48,10 +54,10 @@ describe "A lambda literal -> () { }" do
@d = -> do end
ruby
- @a.().should be_nil
- @b.().should be_nil
- @c.().should be_nil
- @d.().should be_nil
+ @a.().should == nil
+ @b.().should == nil
+ @c.().should == nil
+ @d.().should == nil
end
end
@@ -91,9 +97,9 @@ describe "A lambda literal -> () { }" do
@a = -> (*) { }
ruby
- @a.().should be_nil
- @a.(1).should be_nil
- @a.(1, 2, 3).should be_nil
+ @a.().should == nil
+ @a.(1).should == nil
+ @a.(1, 2, 3).should == nil
end
evaluate <<-ruby do
@@ -109,7 +115,7 @@ describe "A lambda literal -> () { }" do
@a = -> (a:) { a }
ruby
- -> { @a.() }.should raise_error(ArgumentError)
+ -> { @a.() }.should.raise(ArgumentError)
@a.(a: 1).should == 1
end
@@ -125,9 +131,9 @@ describe "A lambda literal -> () { }" do
@a = -> (**) { }
ruby
- @a.().should be_nil
- @a.(a: 1, b: 2).should be_nil
- -> { @a.(1) }.should raise_error(ArgumentError)
+ @a.().should == nil
+ @a.(a: 1, b: 2).should == nil
+ -> { @a.(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -142,8 +148,8 @@ describe "A lambda literal -> () { }" do
@a = -> (&b) { b }
ruby
- @a.().should be_nil
- @a.() { }.should be_an_instance_of(Proc)
+ @a.().should == nil
+ @a.() { }.should.instance_of?(Proc)
end
evaluate <<-ruby do
@@ -151,8 +157,8 @@ describe "A lambda literal -> () { }" do
ruby
@a.(1, 2).should == [1, 2]
- -> { @a.() }.should raise_error(ArgumentError)
- -> { @a.(1) }.should raise_error(ArgumentError)
+ -> { @a.() }.should.raise(ArgumentError)
+ -> { @a.(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -193,9 +199,9 @@ describe "A lambda literal -> () { }" do
@a = -> (*, &b) { b }
ruby
- @a.().should be_nil
- @a.(1, 2, 3, 4).should be_nil
- @a.(&(l = ->{})).should equal(l)
+ @a.().should == nil
+ @a.(1, 2, 3, 4).should == nil
+ @a.(&(l = ->{})).should.equal?(l)
end
evaluate <<-ruby do
@@ -268,7 +274,7 @@ describe "A lambda literal -> () { }" do
a = 1
-> {
eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -286,6 +292,24 @@ describe "A lambda literal -> () { }" do
end
end
end
+
+ evaluate <<-ruby do
+ @a = -> (**nil) { :ok }
+ ruby
+
+ @a.call().should == :ok
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @a = -> (a, **nil) { a }
+ ruby
+
+ @a.call({a: 1}).should == {a: 1}
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
end
describe "A lambda expression 'lambda { ... }'" do
@@ -299,25 +323,25 @@ describe "A lambda expression 'lambda { ... }'" do
lambda { }
end
- obj.define.should equal(obj)
+ obj.define.should.equal?(obj)
end
it "does not execute the block" do
- lambda { fail }.should be_an_instance_of(Proc)
+ lambda { fail }.should.instance_of?(Proc)
end
it "returns a lambda" do
- lambda { }.lambda?.should be_true
+ lambda { }.lambda?.should == true
end
it "requires a block" do
suppress_warning do
- lambda { lambda }.should raise_error(ArgumentError)
+ lambda { lambda }.should.raise(ArgumentError)
end
end
it "may include a rescue clause" do
- eval('lambda do raise ArgumentError; rescue ArgumentError; 7; end').should be_an_instance_of(Proc)
+ eval('lambda do raise ArgumentError; rescue ArgumentError; 7; end').should.instance_of?(Proc)
end
context "with an implicit block" do
@@ -330,7 +354,7 @@ describe "A lambda expression 'lambda { ... }'" do
suppress_warning do
-> {
meth { 1 }
- }.should raise_error(ArgumentError, /tried to create Proc object without a block/)
+ }.should.raise(ArgumentError, /tried to create Proc object without a block/)
end
end
end
@@ -341,8 +365,8 @@ describe "A lambda expression 'lambda { ... }'" do
@b = lambda { || }
ruby
- @a.().should be_nil
- @b.().should be_nil
+ @a.().should == nil
+ @b.().should == nil
end
end
@@ -359,8 +383,8 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |a| a }
ruby
- lambda { m(&@a) }.should raise_error(ArgumentError)
- lambda { m(1, 2, &@a) }.should raise_error(ArgumentError)
+ lambda { m(&@a) }.should.raise(ArgumentError)
+ lambda { m(1, 2, &@a) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -370,8 +394,8 @@ describe "A lambda expression 'lambda { ... }'" do
@a.(1).should == 1
@a.([1, 2]).should == [1, 2]
- lambda { @a.() }.should raise_error(ArgumentError)
- lambda { @a.(1, 2) }.should raise_error(ArgumentError)
+ lambda { @a.() }.should.raise(ArgumentError)
+ lambda { @a.(1, 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -384,7 +408,7 @@ describe "A lambda expression 'lambda { ... }'" do
m(1, &@a).should == 1
m([1, 2], &@a).should == [1, 2]
- lambda { m2(&@a) }.should raise_error(ArgumentError)
+ lambda { m2(&@a) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -415,9 +439,9 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |*| }
ruby
- @a.().should be_nil
- @a.(1).should be_nil
- @a.(1, 2, 3).should be_nil
+ @a.().should == nil
+ @a.(1).should == nil
+ @a.(1, 2, 3).should == nil
end
evaluate <<-ruby do
@@ -433,7 +457,7 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |a:| a }
ruby
- lambda { @a.() }.should raise_error(ArgumentError)
+ lambda { @a.() }.should.raise(ArgumentError)
@a.(a: 1).should == 1
end
@@ -449,9 +473,9 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |**| }
ruby
- @a.().should be_nil
- @a.(a: 1, b: 2).should be_nil
- lambda { @a.(1) }.should raise_error(ArgumentError)
+ @a.().should == nil
+ @a.(a: 1, b: 2).should == nil
+ lambda { @a.(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -466,8 +490,8 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |&b| b }
ruby
- @a.().should be_nil
- @a.() { }.should be_an_instance_of(Proc)
+ @a.().should == nil
+ @a.() { }.should.instance_of?(Proc)
end
evaluate <<-ruby do
@@ -515,9 +539,9 @@ describe "A lambda expression 'lambda { ... }'" do
@a = lambda { |*, &b| b }
ruby
- @a.().should be_nil
- @a.(1, 2, 3, 4).should be_nil
- @a.(&(l = ->{})).should equal(l)
+ @a.().should == nil
+ @a.(1, 2, 3, 4).should == nil
+ @a.(&(l = ->{})).should.equal?(l)
end
evaluate <<-ruby do
@@ -583,5 +607,23 @@ describe "A lambda expression 'lambda { ... }'" do
result = @a.(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{}))
result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l]
end
+
+ evaluate <<-ruby do
+ @a = lambda { |**nil| :ok }
+ ruby
+
+ @a.call().should == :ok
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @a.call("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @a = lambda { |a, **nil| a }
+ ruby
+
+ @a.call({a: 1}).should == {a: 1}
+ -> { @a.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
end
end
diff --git a/spec/ruby/language/line_spec.rb b/spec/ruby/language/line_spec.rb
index fcadaa71d7..2864798079 100644
--- a/spec/ruby/language/line_spec.rb
+++ b/spec/ruby/language/line_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/__LINE__'
describe "The __LINE__ pseudo-variable" do
it "raises a SyntaxError if assigned to" do
- -> { eval("__LINE__ = 1") }.should raise_error(SyntaxError)
+ -> { eval("__LINE__ = 1") }.should.raise(SyntaxError)
end
before :each do
diff --git a/spec/ruby/language/loop_spec.rb b/spec/ruby/language/loop_spec.rb
index fd17b53910..9b12765a5f 100644
--- a/spec/ruby/language/loop_spec.rb
+++ b/spec/ruby/language/loop_spec.rb
@@ -15,7 +15,7 @@ describe "The loop expression" do
inner_loop = 123
break
end
- -> { inner_loop }.should raise_error(NameError)
+ -> { inner_loop }.should.raise(NameError)
end
it "returns the value passed to break if interrupted by break" do
diff --git a/spec/ruby/language/magic_comment_spec.rb b/spec/ruby/language/magic_comment_spec.rb
index f2bf3a08e5..af9c9dbfd0 100644
--- a/spec/ruby/language/magic_comment_spec.rb
+++ b/spec/ruby/language/magic_comment_spec.rb
@@ -45,7 +45,8 @@ end
describe "Magic comments" do
describe "in stdin" do
- it_behaves_like :magic_comments, :locale, -> file {
+ default = (platform_is :windows and ruby_version_is "4.0") ? :UTF8 : :locale
+ it_behaves_like :magic_comments, default, -> file {
print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb")
ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}")
}
diff --git a/spec/ruby/language/match_spec.rb b/spec/ruby/language/match_spec.rb
index ebf677cabc..096ebee022 100644
--- a/spec/ruby/language/match_spec.rb
+++ b/spec/ruby/language/match_spec.rb
@@ -46,6 +46,14 @@ describe "The =~ operator with named captures" do
matched.should == "foo"
unmatched.should == nil
end
+
+ it "sets existing local variables if declared in a higher scope" do
+ a = 42
+ 1.times do
+ /(?<a>foo)/ =~ @string
+ end
+ a.should == "foo"
+ end
end
describe "on syntax of 'string_literal' =~ /regexp/" do
diff --git a/spec/ruby/language/metaclass_spec.rb b/spec/ruby/language/metaclass_spec.rb
index fc83067977..3bee823a75 100644
--- a/spec/ruby/language/metaclass_spec.rb
+++ b/spec/ruby/language/metaclass_spec.rb
@@ -16,17 +16,17 @@ describe "self in a metaclass body (class << obj)" do
end
it "raises a TypeError for numbers" do
- -> { class << 1; self; end }.should raise_error(TypeError)
+ -> { class << 1; self; end }.should.raise(TypeError)
end
it "raises a TypeError for symbols" do
- -> { class << :symbol; self; end }.should raise_error(TypeError)
+ -> { class << :symbol; self; end }.should.raise(TypeError)
end
it "is a singleton Class instance" do
cls = class << mock('x'); self; end
cls.is_a?(Class).should == true
- cls.should_not equal(Object)
+ cls.should_not.equal?(Object)
end
end
@@ -57,20 +57,20 @@ describe "A constant on a metaclass" do
end
it "is not defined on the object's class" do
- @object.class.const_defined?(:CONST).should be_false
+ @object.class.const_defined?(:CONST).should == false
end
it "is not defined in the metaclass opener's scope" do
class << @object
CONST
end
- -> { CONST }.should raise_error(NameError)
+ -> { CONST }.should.raise(NameError)
end
it "cannot be accessed via object::CONST" do
-> do
@object::CONST
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a NameError for anonymous_module::CONST" do
@@ -81,16 +81,16 @@ describe "A constant on a metaclass" do
-> do
@object::CONST
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "appears in the metaclass constant list" do
constants = class << @object; constants; end
- constants.should include(:CONST)
+ constants.should.include?(:CONST)
end
it "does not appear in the object's class constant list" do
- @object.class.constants.should_not include(:CONST)
+ @object.class.constants.should_not.include?(:CONST)
end
it "is not preserved when the object is duped" do
@@ -98,14 +98,14 @@ describe "A constant on a metaclass" do
-> do
class << @object; CONST; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is preserved when the object is cloned" do
@object = @object.clone
class << @object
- CONST.should_not be_nil
+ CONST.should_not == nil
end
end
end
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index b0d7058dbe..324bd6cea5 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -19,7 +19,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_not_receive(:to_ary)
- m(*x).should equal(x)
+ m(*x).should.equal?(x)
end
it "calls #to_a" do
@@ -40,7 +40,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(*x) }.should raise_error(TypeError)
+ -> { m(*x) }.should.raise(TypeError)
end
end
@@ -74,7 +74,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(*x, 2, 3) }.should raise_error(TypeError)
+ -> { m(*x, 2, 3) }.should.raise(TypeError)
end
end
@@ -108,13 +108,13 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(1, *x, 2, 3) }.should raise_error(TypeError)
+ -> { m(1, *x, 2, 3) }.should.raise(TypeError)
end
it "copies the splatted array" do
args = [3, 4]
m(1, 2, *args, 4, 5).should == [1, 2, [3, 4], 4, 5]
- m(1, 2, *args, 4, 5)[2].should_not equal(args)
+ m(1, 2, *args, 4, 5)[2].should_not.equal?(args)
end
it "allows an array being splatted to be modified by another argument" do
@@ -153,7 +153,7 @@ describe "A method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { m(1, 2, *x) }.should raise_error(TypeError)
+ -> { m(1, 2, *x) }.should.raise(TypeError)
end
end
@@ -217,7 +217,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[*x] = 1 }.should raise_error(TypeError)
+ -> { @o[*x] = 1 }.should.raise(TypeError)
end
end
@@ -255,7 +255,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[*x, 2, 3] = 4 }.should raise_error(TypeError)
+ -> { @o[*x, 2, 3] = 4 }.should.raise(TypeError)
end
end
@@ -293,7 +293,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[1, 2, *x, 3] = 4 }.should raise_error(TypeError)
+ -> { @o[1, 2, *x, 3] = 4 }.should.raise(TypeError)
end
end
@@ -331,7 +331,7 @@ describe "An element assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o[1, 2, 3, *x] = 4 }.should raise_error(TypeError)
+ -> { @o[1, 2, 3, *x] = 4 }.should.raise(TypeError)
end
end
end
@@ -368,7 +368,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, *x, 1 }.should raise_error(TypeError)
+ -> { @o.send :m=, *x, 1 }.should.raise(TypeError)
end
end
@@ -403,7 +403,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, *x, 2, 3, 4 }.should raise_error(TypeError)
+ -> { @o.send :m=, *x, 2, 3, 4 }.should.raise(TypeError)
end
end
@@ -438,7 +438,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, 1, 2, *x, 3, 4 }.should raise_error(TypeError)
+ -> { @o.send :m=, 1, 2, *x, 3, 4 }.should.raise(TypeError)
end
end
@@ -473,7 +473,7 @@ describe "An attribute assignment method send" do
x = mock("splat argument")
x.should_receive(:to_a).and_return(1)
- -> { @o.send :m=, 1, 2, 3, *x, 4 }.should raise_error(TypeError)
+ -> { @o.send :m=, 1, 2, 3, *x, 4 }.should.raise(TypeError)
end
end
end
@@ -487,7 +487,7 @@ describe "A method" do
end
ruby
- m.should be_nil
+ m.should == nil
end
evaluate <<-ruby do
@@ -495,7 +495,7 @@ describe "A method" do
end
ruby
- m.should be_nil
+ m.should == nil
end
end
@@ -504,7 +504,7 @@ describe "A method" do
def m(a) a end
ruby
- m((args = 1, 2, 3)).should equal(args)
+ m((args = 1, 2, 3)).should.equal?(args)
end
evaluate <<-ruby do
@@ -535,18 +535,18 @@ describe "A method" do
def m() end
ruby
- m().should be_nil
- m(*[]).should be_nil
- m(**{}).should be_nil
+ m().should == nil
+ m(*[]).should == nil
+ m(**{}).should == nil
end
evaluate <<-ruby do
def m(*) end
ruby
- m().should be_nil
- m(1).should be_nil
- m(1, 2, 3).should be_nil
+ m().should == nil
+ m(1).should == nil
+ m(1, 2, 3).should == nil
end
evaluate <<-ruby do
@@ -564,10 +564,10 @@ describe "A method" do
def m(a:) a end
ruby
- -> { m() }.should raise_error(ArgumentError)
+ -> { m() }.should.raise(ArgumentError)
m(a: 1).should == 1
suppress_keyword_warning do
- -> { m("a" => 1, a: 1) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, a: 1) }.should.raise(ArgumentError)
end
end
@@ -575,7 +575,7 @@ describe "A method" do
def m(a:, **kw) [a, kw] end
ruby
- -> { m(b: 1) }.should raise_error(ArgumentError)
+ -> { m(b: 1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -590,9 +590,9 @@ describe "A method" do
def m(**) end
ruby
- m().should be_nil
- m(a: 1, b: 2).should be_nil
- -> { m(1) }.should raise_error(ArgumentError)
+ m().should == nil
+ m(a: 1, b: 2).should == nil
+ -> { m(1) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -606,7 +606,7 @@ describe "A method" do
suppress_warning {
eval "m(**{a: 1, b: 2}, **{a: 4, c: 7})"
}.should == { a: 4, b: 2, c: 7 }
- -> { m(2) }.should raise_error(ArgumentError)
+ -> { m(2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -620,7 +620,7 @@ describe "A method" do
def m(&b) b end
ruby
- m { }.should be_an_instance_of(Proc)
+ m { }.should.instance_of?(Proc)
end
evaluate <<-ruby do
@@ -650,9 +650,9 @@ describe "A method" do
def m((*), (*)) end
ruby
- m(2, 3).should be_nil
- m([2, 3, 4], [5, 6]).should be_nil
- -> { m a: 1 }.should raise_error(ArgumentError)
+ m(2, 3).should == nil
+ m([2, 3, 4], [5, 6]).should == nil
+ -> { m a: 1 }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -745,7 +745,7 @@ describe "A method" do
m(1, b: 2).should == [1, 2]
suppress_keyword_warning do
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
end
@@ -755,7 +755,7 @@ describe "A method" do
m(2).should == [2, 1]
m(1, b: 2).should == [1, 2]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -764,7 +764,7 @@ describe "A method" do
m(1).should == 1
m(1, a: 2, b: 3).should == 1
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -773,7 +773,7 @@ describe "A method" do
m(1).should == [1, {}]
m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -848,8 +848,8 @@ describe "A method" do
def m(a=1, (*b), (*c)) [a, b, c] end
ruby
- -> { m() }.should raise_error(ArgumentError)
- -> { m(2) }.should raise_error(ArgumentError)
+ -> { m() }.should.raise(ArgumentError)
+ -> { m(2) }.should.raise(ArgumentError)
m(2, 3).should == [1, [2], [3]]
m(2, [3, 4], [5, 6]).should == [2, [3, 4], [5, 6]]
end
@@ -890,7 +890,7 @@ describe "A method" do
m(b: 2).should == [1, 2]
m(2, b: 1).should == [2, 1]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -900,7 +900,7 @@ describe "A method" do
m().should == [1, 2]
m(2).should == [2, 2]
m(b: 3).should == [1, 3]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, b: 2) }.should.raise(ArgumentError)
end
evaluate <<-ruby do
@@ -953,9 +953,9 @@ describe "A method" do
def m(*, &b) b end
ruby
- m().should be_nil
- m(1, 2, 3, 4).should be_nil
- m(&(l = ->{})).should equal(l)
+ m().should == nil
+ m(1, 2, 3, 4).should == nil
+ m(&(l = ->{})).should.equal?(l)
end
evaluate <<-ruby do
@@ -973,7 +973,7 @@ describe "A method" do
m(a: 1, b: 2).should == [1, 2]
suppress_keyword_warning do
- -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, a: 1, b: 2) }.should.raise(ArgumentError)
end
end
@@ -984,7 +984,7 @@ describe "A method" do
m(a: 1).should == [1, 1]
m(a: 1, b: 2).should == [1, 2]
suppress_keyword_warning do
- -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError)
+ -> { m("a" => 1, a: 1, b: 2) }.should.raise(ArgumentError)
end
end
@@ -1101,15 +1101,25 @@ describe "A method" do
end
evaluate <<-ruby do
+ def m(**nil); :ok; end;
+ ruby
+
+ m().should == :ok
+ -> { m(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
def m(a, **nil); a end;
ruby
m({a: 1}).should == {a: 1}
m({"a" => 1}).should == {"a" => 1}
- -> { m(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
- -> { m(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
- -> { m("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { m(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { m("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
end
evaluate <<-ruby do
@@ -1127,6 +1137,18 @@ describe "A method" do
result = m(1, {foo: :bar})
result.should == [1, nil, nil, {foo: :bar}, nil, {}]
end
+
+ ruby_version_is "4.1" do
+ evaluate <<-ruby do
+ def m(a, &nil); a end;
+ ruby
+
+ m(1).should == 1
+
+ -> { m(1) {} }.should.raise(ArgumentError, 'no block accepted')
+ -> { m(1, &proc {}) }.should.raise(ArgumentError, 'no block accepted')
+ end
+ end
end
context 'when passing an empty keyword splat to a method that does not accept keywords' do
@@ -1147,7 +1169,7 @@ describe "A method" do
-> do
m(**h).should == {}
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
@@ -1159,7 +1181,7 @@ describe "A method" do
options = {a: 1}.freeze
-> do
m(options)
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
end
@@ -1175,6 +1197,31 @@ describe "A method" do
end
end
+context "when passing **nil into a method that accepts keyword arguments" do
+ ruby_version_is ""..."3.4" do
+ it "raises TypeError" do
+ def m(**kw) kw; end
+
+ h = nil
+ -> { m(a: 1, **h) }.should.raise(TypeError, "no implicit conversion of nil into Hash")
+ -> { m(a: 1, **nil) }.should.raise(TypeError, "no implicit conversion of nil into Hash")
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "expands nil using ** into {}" do
+ def m(**kw) kw; end
+
+ h = nil
+ m(**h).should == {}
+ m(a: 1, **h).should == {a: 1}
+
+ m(**nil).should == {}
+ m(a: 1, **nil).should == {a: 1}
+ end
+ end
+end
+
describe "A method call with a space between method name and parentheses" do
before(:each) do
def m(*args)
@@ -1209,10 +1256,8 @@ describe "A method call with a space between method name and parentheses" do
args.should == [true]
end
- ruby_version_is "3.3" do
- it "supports multiple statements" do
- eval("m (1; 2)").should == [2]
- end
+ it "supports multiple statements" do
+ eval("m (1; 2)").should == [2]
end
end
@@ -1232,11 +1277,11 @@ describe "A method call with a space between method name and parentheses" do
it "raises a syntax error" do
-> {
eval("m (1, 2)")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
-> {
eval("m (1, 2, 3)")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -1386,7 +1431,7 @@ describe "Keyword arguments are now separated from positional arguments" do
-> {
foo(1, 2, 3, { key: 42 })
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ }.should.raise(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
end
end
@@ -1399,7 +1444,7 @@ describe "Keyword arguments are now separated from positional arguments" do
-> {
foo(1, 2, 3, { key: 42 })
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ }.should.raise(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
end
end
@@ -1462,3 +1507,163 @@ describe "Inside 'endless' method definitions" do
greet("Homer").should == "Hi, Homer"
end
end
+
+describe "warning about not used block argument" do
+ ruby_version_is "3.4" do
+ it "warns when passing a block argument to a method that never uses it" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ -> {
+ m_that_does_not_use_block { }
+ }.should complain(
+ /#{__FILE__}:#{__LINE__ - 2}: warning: the block passed to 'm_that_does_not_use_block' defined at #{__FILE__}:#{__LINE__ - 7} may be ignored/,
+ verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that declares a block parameter" do
+ def m_with_block_parameter(&block)
+ 42
+ end
+
+ -> { m_with_block_parameter { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that declares an anonymous block parameter" do
+ def m_with_anonymous_block_parameter(&)
+ 42
+ end
+
+ -> { m_with_anonymous_block_parameter { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that yields an implicit block parameter" do
+ def m_with_yield
+ yield 42
+ end
+
+ -> { m_with_yield { } }.should_not complain(verbose: true)
+ end
+
+ it "warns when passing a block argument to a method that calls #block_given?" do
+ def m_with_block_given
+ block_given?
+ end
+
+ -> {
+ m_with_block_given { }
+ }.should complain(
+ /#{__FILE__}:#{__LINE__ - 2}: warning: the block passed to 'm_with_block_given' defined at #{__FILE__}:#{__LINE__ - 7} may be ignored/,
+ verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that calls super" do
+ parent = Class.new do
+ def m
+ end
+ end
+
+ child = Class.new(parent) do
+ def m
+ super
+ end
+ end
+
+ obj = child.new
+ -> { obj.m { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that calls super(...)" do
+ parent = Class.new do
+ def m(a)
+ end
+ end
+
+ child = Class.new(parent) do
+ def m(...)
+ super(...)
+ end
+ end
+
+ obj = child.new
+ -> { obj.m(42) { } }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when called #initialize()" do
+ klass = Class.new do
+ def initialize
+ end
+ end
+
+ -> { klass.new {} }.should_not complain(verbose: true)
+ end
+
+ it "does not warn when passing a block argument to a method that calls super()" do
+ parent = Class.new do
+ def m
+ end
+ end
+
+ child = Class.new(parent) do
+ def m
+ super()
+ end
+ end
+
+ obj = child.new
+ -> { obj.m { } }.should_not complain(verbose: true)
+ end
+
+ it "warns only once per call site" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ def call_m_that_does_not_use_block
+ m_that_does_not_use_block {}
+ end
+
+ -> {
+ m_that_does_not_use_block { }
+ }.should complain(/the block passed to 'm_that_does_not_use_block' defined at .+ may be ignored/, verbose: true)
+
+ -> {
+ m_that_does_not_use_block { }
+ }.should_not complain(verbose: true)
+ end
+
+ it "can be disabled with :strict_unused_block warning category" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ # ensure that warning is emitted
+ -> { m_that_does_not_use_block { } }.should complain(verbose: true)
+
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = false
+ begin
+ -> { m_that_does_not_use_block { } }.should_not complain(verbose: true)
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+
+ it "can be enabled with :strict_unused_block = true warning category in not verbose mode" do
+ def m_that_does_not_use_block
+ 42
+ end
+
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = true
+ begin
+ -> {
+ m_that_does_not_use_block { }
+ }.should complain(/the block passed to 'm_that_does_not_use_block' defined at .+ may be ignored/)
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb
index 0bfd148868..2f22e383d5 100644
--- a/spec/ruby/language/module_spec.rb
+++ b/spec/ruby/language/module_spec.rb
@@ -4,79 +4,94 @@ require_relative 'fixtures/module'
describe "The module keyword" do
it "creates a new module without semicolon" do
module ModuleSpecsKeywordWithoutSemicolon end
- ModuleSpecsKeywordWithoutSemicolon.should be_an_instance_of(Module)
+ ModuleSpecsKeywordWithoutSemicolon.should.instance_of?(Module)
end
it "creates a new module with a non-qualified constant name" do
module ModuleSpecsToplevel; end
- ModuleSpecsToplevel.should be_an_instance_of(Module)
+ ModuleSpecsToplevel.should.instance_of?(Module)
end
it "creates a new module with a qualified constant name" do
module ModuleSpecs::Nested; end
- ModuleSpecs::Nested.should be_an_instance_of(Module)
+ ModuleSpecs::Nested.should.instance_of?(Module)
end
it "creates a new module with a variable qualified constant name" do
m = Module.new
module m::N; end
- m::N.should be_an_instance_of(Module)
+ m::N.should.instance_of?(Module)
end
it "reopens an existing module" do
module ModuleSpecs; Reopened = true; end
- ModuleSpecs::Reopened.should be_true
+ ModuleSpecs::Reopened.should == true
ensure
ModuleSpecs.send(:remove_const, :Reopened)
end
- ruby_version_is '3.2' do
- it "does not reopen a module included in Object" do
- module IncludedModuleSpecs; Reopened = true; end
- ModuleSpecs::IncludedInObject::IncludedModuleSpecs.should_not == Object::IncludedModuleSpecs
- ensure
- IncludedModuleSpecs.send(:remove_const, :Reopened)
- end
- end
-
- ruby_version_is ''...'3.2' do
- it "reopens a module included in Object" do
- module IncludedModuleSpecs; Reopened = true; end
- ModuleSpecs::IncludedInObject::IncludedModuleSpecs::Reopened.should be_true
- end
+ it "does not reopen a module included in Object" do
+ ruby_exe(<<~RUBY).should == "false"
+ module IncludedInObject
+ module IncludedModule; end
+ end
+ class Object
+ include IncludedInObject
+ end
+ module IncludedModule; end
+ print IncludedInObject::IncludedModule == Object::IncludedModule
+ RUBY
+ end
+
+ it "does not reopen a module included in non-Object modules" do
+ ruby_exe(<<~RUBY).should == "false/false"
+ module Included
+ module IncludedModule; end
+ end
+ module M
+ include Included
+ module IncludedModule; end
+ end
+ class C
+ include Included
+ module IncludedModule; end
+ end
+ print Included::IncludedModule == M::IncludedModule, "/",
+ Included::IncludedModule == C::IncludedModule
+ RUBY
end
it "raises a TypeError if the constant is a Class" do
-> do
module ModuleSpecs::Modules::Klass; end
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if the constant is a String" do
- -> { module ModuleSpecs::Modules::A; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::A; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is an Integer" do
- -> { module ModuleSpecs::Modules::B; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::B; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is nil" do
- -> { module ModuleSpecs::Modules::C; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::C; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is true" do
- -> { module ModuleSpecs::Modules::D; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::D; end }.should.raise(TypeError)
end
it "raises a TypeError if the constant is false" do
- -> { module ModuleSpecs::Modules::D; end }.should raise_error(TypeError)
+ -> { module ModuleSpecs::Modules::D; end }.should.raise(TypeError)
end
end
describe "Assigning an anonymous module to a constant" do
it "sets the name of the module" do
mod = Module.new
- mod.name.should be_nil
+ mod.name.should == nil
::ModuleSpecs_CS1 = mod
mod.name.should == "ModuleSpecs_CS1"
diff --git a/spec/ruby/language/next_spec.rb b/spec/ruby/language/next_spec.rb
index 6fbfc4a54d..eac151eeb3 100644
--- a/spec/ruby/language/next_spec.rb
+++ b/spec/ruby/language/next_spec.rb
@@ -21,7 +21,7 @@ describe "The next statement from within the block" do
end
it "causes block to return nil if invoked with an empty expression" do
- -> { next (); 456 }.call.should be_nil
+ -> { next (); 456 }.call.should == nil
end
it "returns the argument passed" do
@@ -111,7 +111,7 @@ describe "The next statement" do
it "is invalid and raises a SyntaxError" do
-> {
eval("def m; next; end")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
end
diff --git a/spec/ruby/language/not_spec.rb b/spec/ruby/language/not_spec.rb
index 052af9b256..23411a8e1d 100644
--- a/spec/ruby/language/not_spec.rb
+++ b/spec/ruby/language/not_spec.rb
@@ -2,50 +2,50 @@ require_relative '../spec_helper'
describe "The not keyword" do
it "negates a `true' value" do
- (not true).should be_false
- (not 'true').should be_false
+ (not true).should == false
+ (not 'true').should == false
end
it "negates a `false' value" do
- (not false).should be_true
- (not nil).should be_true
+ (not false).should == true
+ (not nil).should == true
end
it "accepts an argument" do
- not(true).should be_false
+ not(true).should == false
end
it "returns false if the argument is true" do
- (not(true)).should be_false
+ (not(true)).should == false
end
it "returns true if the argument is false" do
- (not(false)).should be_true
+ (not(false)).should == true
end
it "returns true if the argument is nil" do
- (not(nil)).should be_true
+ (not(nil)).should == true
end
end
describe "The `!' keyword" do
it "negates a `true' value" do
- (!true).should be_false
- (!'true').should be_false
+ (!true).should == false
+ (!'true').should == false
end
it "negates a `false' value" do
- (!false).should be_true
- (!nil).should be_true
+ (!false).should == true
+ (!nil).should == true
end
it "doubled turns a truthful object into `true'" do
- (!!true).should be_true
- (!!'true').should be_true
+ (!!true).should == true
+ (!!'true').should == true
end
it "doubled turns a not truthful object into `false'" do
- (!!false).should be_false
- (!!nil).should be_false
+ (!!false).should == false
+ (!!nil).should == false
end
end
diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb
index 39ddd6fee8..23e89a14be 100644
--- a/spec/ruby/language/numbered_parameters_spec.rb
+++ b/spec/ruby/language/numbered_parameters_spec.rb
@@ -22,13 +22,13 @@ describe "Numbered parameters" do
it "does not support more than 9 parameters" do
-> {
proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- }.should raise_error(NameError, /undefined local variable or method [`']_10'/)
+ }.should.raise(NameError, /undefined local variable or method [`']_10'/)
end
it "can not be used in both outer and nested blocks at the same time" do
-> {
eval("-> { _1; -> { _2 } }")
- }.should raise_error(SyntaxError, /numbered parameter is already used in/m)
+ }.should.raise(SyntaxError, /numbered parameter is already used in/m)
end
it "cannot be overwritten with local variable" do
@@ -37,32 +37,32 @@ describe "Numbered parameters" do
_1 = 0
proc { _1 }.call("a").should == 0
CODE
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ }.should.raise(SyntaxError, /_1 is reserved for numbered parameter/)
end
it "errors when numbered parameter is overwritten with local variable" do
-> {
eval("_1 = 0")
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ }.should.raise(SyntaxError, /_1 is reserved for numbered parameter/)
end
it "raises SyntaxError when block parameters are specified explicitly" do
- -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> () { _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> (x) { _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
- -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { || _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { |x| _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
- -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { || _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { |x| _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
- -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { || _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { |x| _1 }") }.should.raise(SyntaxError, /ordinary parameter is defined/)
end
describe "assigning to a numbered parameter" do
it "raises SyntaxError" do
- -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ -> { eval("proc { _1 = 0 }") }.should.raise(SyntaxError, /_1 is reserved for numbered parameter/)
end
end
@@ -90,14 +90,14 @@ describe "Numbered parameters" do
proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]]
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "affects binding local variables" do
-> { _1; binding.local_variables }.call("a").should == [:_1]
-> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2]
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "does not affect binding local variables" do
-> { _1; binding.local_variables }.call("a").should == []
-> { _2; binding.local_variables }.call("a", "b").should == []
@@ -108,6 +108,6 @@ describe "Numbered parameters" do
obj = Object.new
def obj.foo; _1 end
- -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/)
+ -> { obj.foo("a") }.should.raise(ArgumentError, /wrong number of arguments/)
end
end
diff --git a/spec/ruby/language/numbers_spec.rb b/spec/ruby/language/numbers_spec.rb
index a8e023efb6..ed0e49c048 100644
--- a/spec/ruby/language/numbers_spec.rb
+++ b/spec/ruby/language/numbers_spec.rb
@@ -11,7 +11,7 @@ describe "A number literal" do
end
it "cannot have a leading underscore" do
- -> { eval("_4_2") }.should raise_error(NameError)
+ -> { eval("_4_2") }.should.raise(NameError)
end
it "can have a decimal point" do
@@ -20,8 +20,8 @@ describe "A number literal" do
it "must have a digit before the decimal point" do
0.75.should == 0.75
- -> { eval(".75") }.should raise_error(SyntaxError)
- -> { eval("-.75") }.should raise_error(SyntaxError)
+ -> { eval(".75") }.should.raise(SyntaxError)
+ -> { eval("-.75") }.should.raise(SyntaxError)
end
it "can have an exponent" do
diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb
index 5fe3e3671b..ebb5d36351 100644
--- a/spec/ruby/language/optional_assignments_spec.rb
+++ b/spec/ruby/language/optional_assignments_spec.rb
@@ -603,7 +603,7 @@ describe 'Optional variable assignments' do
end
it 'with &&= assignments will fail with non-existent constants' do
- -> { Object::A &&= 10 }.should raise_error(NameError)
+ -> { Object::A &&= 10 }.should.raise(NameError)
end
it 'with operator assignments' do
@@ -615,7 +615,7 @@ describe 'Optional variable assignments' do
end
it 'with operator assignments will fail with non-existent constants' do
- -> { Object::A += 10 }.should raise_error(NameError)
+ -> { Object::A += 10 }.should.raise(NameError)
end
end
end
@@ -623,7 +623,7 @@ end
describe 'Optional constant assignment' do
describe 'with ||=' do
it "assigns a scoped constant if previously undefined" do
- ConstantSpecs.should_not have_constant(:OpAssignUndefined)
+ ConstantSpecs.should_not.const_defined?(:OpAssignUndefined)
module ConstantSpecs
OpAssignUndefined ||= 42
end
@@ -679,7 +679,7 @@ describe 'Optional constant assignment' do
-> {
(x += 1; raise Exception; ConstantSpecs::ClassA)::OR_ASSIGNED_CONSTANT3 ||= (y += 1; :assigned)
- }.should raise_error(Exception)
+ }.should.raise(Exception)
x.should == 1
y.should == 0
@@ -693,7 +693,7 @@ describe 'Optional constant assignment' do
-> {
(x += 1; raise Exception; ConstantSpecs::ClassA)::NIL_OR_ASSIGNED_CONSTANT3 ||= (y += 1; :assigned)
- }.should raise_error(Exception)
+ }.should.raise(Exception)
x.should == 1
y.should == 0
diff --git a/spec/ruby/language/or_spec.rb b/spec/ruby/language/or_spec.rb
index fb75e788f1..8ae577a142 100644
--- a/spec/ruby/language/or_spec.rb
+++ b/spec/ruby/language/or_spec.rb
@@ -26,24 +26,24 @@ describe "The || operator" do
end
it "treats empty expressions as nil" do
- (() || true).should be_true
- (() || false).should be_false
- (true || ()).should be_true
- (false || ()).should be_nil
- (() || ()).should be_nil
+ (() || true).should == true
+ (() || false).should == false
+ (true || ()).should == true
+ (false || ()).should == nil
+ (() || ()).should == nil
end
it "has a higher precedence than 'break' in 'break true || false'" do
# see also 'break true or false' below
- -> { break false || true }.call.should be_true
+ -> { break false || true }.call.should == true
end
it "has a higher precedence than 'next' in 'next true || false'" do
- -> { next false || true }.call.should be_true
+ -> { next false || true }.call.should == true
end
it "has a higher precedence than 'return' in 'return true || false'" do
- -> { return false || true }.call.should be_true
+ -> { return false || true }.call.should == true
end
end
@@ -68,23 +68,23 @@ describe "The or operator" do
end
it "treats empty expressions as nil" do
- (() or true).should be_true
- (() or false).should be_false
- (true or ()).should be_true
- (false or ()).should be_nil
- (() or ()).should be_nil
+ (() or true).should == true
+ (() or false).should == false
+ (true or ()).should == true
+ (false or ()).should == nil
+ (() or ()).should == nil
end
it "has a lower precedence than 'break' in 'break true or false'" do
# see also 'break true || false' above
- -> { eval "break true or false" }.should raise_error(SyntaxError, /void value expression/)
+ -> { eval "break true or false" }.should.raise(SyntaxError, /void value expression/)
end
it "has a lower precedence than 'next' in 'next true or false'" do
- -> { eval "next true or false" }.should raise_error(SyntaxError, /void value expression/)
+ -> { eval "next true or false" }.should.raise(SyntaxError, /void value expression/)
end
it "has a lower precedence than 'return' in 'return true or false'" do
- -> { eval "return true or false" }.should raise_error(SyntaxError, /void value expression/)
+ -> { eval "return true or false" }.should.raise(SyntaxError, /void value expression/)
end
end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index cb4f5864d7..a24500c9fd 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -185,7 +185,7 @@ describe "Pattern matching" do
in []
end
RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in|unexpected 'in'/)
+ }.should.raise(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in|unexpected 'in'/)
-> {
eval <<~RUBY
@@ -194,7 +194,7 @@ describe "Pattern matching" do
when 1 == 1
end
RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when|unexpected 'when'/)
+ }.should.raise(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when|unexpected 'when'/)
end
it "checks patterns until the first matching" do
@@ -222,14 +222,14 @@ describe "Pattern matching" do
case [0, 1]
in [0]
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ }.should.raise(NoMatchingPatternError, /\[0, 1\]/)
error_pattern = ruby_version_is("3.4") ? /\{a: 0, b: 1\}/ : /\{:a=>0, :b=>1\}/
-> {
case {a: 0, b: 1}
in a: 1, b: 1
end
- }.should raise_error(NoMatchingPatternError, error_pattern)
+ }.should.raise(NoMatchingPatternError, error_pattern)
end
it "raises NoMatchingPatternError if no pattern matches and evaluates the expression only once" do
@@ -238,7 +238,7 @@ describe "Pattern matching" do
case (evals += 1; [0, 1])
in [0]
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ }.should.raise(NoMatchingPatternError, /\[0, 1\]/)
evals.should == 1
end
@@ -250,7 +250,7 @@ describe "Pattern matching" do
true
end
RUBY
- }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the patterns of an `in` clause/)
+ }.should.raise(SyntaxError, /unexpected|expected a delimiter after the patterns of an `in` clause/)
end
it "evaluates the case expression once for multiple patterns, caching the result" do
@@ -336,7 +336,7 @@ describe "Pattern matching" do
case [0, 1]
in [0, 1] if false
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ }.should.raise(NoMatchingPatternError, /\[0, 1\]/)
end
end
@@ -438,7 +438,7 @@ describe "Pattern matching" do
in [a, a]
end
RUBY
- }.should raise_error(SyntaxError, /duplicated variable name/)
+ }.should.raise(SyntaxError, /duplicated variable name/)
end
it "supports existing variables in a pattern specified with ^ operator" do
@@ -474,7 +474,7 @@ describe "Pattern matching" do
false
end
RUBY
- }.should raise_error(SyntaxError, /n: no such local variable/)
+ }.should.raise(SyntaxError, /n: no such local variable/)
end
end
@@ -493,7 +493,7 @@ describe "Pattern matching" do
in [0, 0] | [0, a]
end
RUBY
- }.should raise_error(SyntaxError, /illegal variable in alternative pattern/)
+ }.should.raise(SyntaxError)
end
it "support underscore prefixed variables in alternation" do
@@ -674,7 +674,7 @@ describe "Pattern matching" do
in Object[]
else
end
- }.should raise_error(TypeError, /deconstruct must return Array/)
+ }.should.raise(TypeError, /deconstruct must return Array/)
end
it "accepts a subclass of Array from #deconstruct" do
@@ -870,7 +870,7 @@ describe "Pattern matching" do
in {"a" => 1}
end
RUBY
- }.should raise_error(SyntaxError, /unexpected|expected a label as the key in the hash pattern/)
+ }.should.raise(SyntaxError, /unexpected|expected a label as the key in the hash pattern/)
end
it "does not support string interpolation in keys" do
@@ -880,7 +880,7 @@ describe "Pattern matching" do
in {"#{x}": 1}
end
RUBY
- }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed|expected a label as the key in the hash pattern/)
+ }.should.raise(SyntaxError, /symbol literal with interpolation is not allowed|expected a label as the key in the hash pattern/)
end
it "raise SyntaxError when keys duplicate in pattern" do
@@ -890,7 +890,7 @@ describe "Pattern matching" do
in {a: 1, b: 2, a: 3}
end
RUBY
- }.should raise_error(SyntaxError, /duplicated key name/)
+ }.should.raise(SyntaxError, /duplicated key name/)
end
it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do
@@ -969,7 +969,7 @@ describe "Pattern matching" do
case obj
in Object[a: 1]
end
- }.should raise_error(TypeError, /deconstruct_keys must return Hash/)
+ }.should.raise(TypeError, /deconstruct_keys must return Hash/)
end
it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
diff --git a/spec/ruby/language/precedence_spec.rb b/spec/ruby/language/precedence_spec.rb
index 5e606c16d8..edb990525e 100644
--- a/spec/ruby/language/precedence_spec.rb
+++ b/spec/ruby/language/precedence_spec.rb
@@ -251,12 +251,12 @@ describe "Operators" do
end
it "<=> == === != =~ !~ are non-associative" do
- -> { eval("1 <=> 2 <=> 3") }.should raise_error(SyntaxError)
- -> { eval("1 == 2 == 3") }.should raise_error(SyntaxError)
- -> { eval("1 === 2 === 3") }.should raise_error(SyntaxError)
- -> { eval("1 != 2 != 3") }.should raise_error(SyntaxError)
- -> { eval("1 =~ 2 =~ 3") }.should raise_error(SyntaxError)
- -> { eval("1 !~ 2 !~ 3") }.should raise_error(SyntaxError)
+ -> { eval("1 <=> 2 <=> 3") }.should.raise(SyntaxError)
+ -> { eval("1 == 2 == 3") }.should.raise(SyntaxError)
+ -> { eval("1 === 2 === 3") }.should.raise(SyntaxError)
+ -> { eval("1 != 2 != 3") }.should.raise(SyntaxError)
+ -> { eval("1 =~ 2 =~ 3") }.should.raise(SyntaxError)
+ -> { eval("1 !~ 2 !~ 3") }.should.raise(SyntaxError)
end
it "<=> == === != =~ !~ have higher precedence than &&" do
@@ -290,8 +290,8 @@ describe "Operators" do
end
it ".. ... are non-associative" do
- -> { eval("1..2..3") }.should raise_error(SyntaxError)
- -> { eval("1...2...3") }.should raise_error(SyntaxError)
+ -> { eval("1..2..3") }.should.raise(SyntaxError)
+ -> { eval("1...2...3") }.should.raise(SyntaxError)
end
it ".. ... have higher precedence than ? :" do
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index f8645493b8..d57b924bcf 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -1,4 +1,5 @@
require_relative '../spec_helper'
+require_relative '../core/exception/shared/set_backtrace'
require 'stringio'
# The following tables are excerpted from Programming Ruby: The Pragmatic Programmer's Guide'
@@ -39,12 +40,12 @@ require 'stringio'
describe "Predefined global $~" do
it "is set to contain the MatchData object of the last match if successful" do
md = /foo/.match 'foo'
- $~.should be_kind_of(MatchData)
- $~.should equal md
+ $~.should.is_a?(MatchData)
+ $~.should.equal? md
/bar/ =~ 'bar'
- $~.should be_kind_of(MatchData)
- $~.should_not equal md
+ $~.should.is_a?(MatchData)
+ $~.should_not.equal? md
end
it "is set to nil if the last match was unsuccessful" do
@@ -86,10 +87,10 @@ describe "Predefined global $~" do
$~ = nil
$~.should == nil
$~ = /foo/.match("foo")
- $~.should be_an_instance_of(MatchData)
+ $~.should.instance_of?(MatchData)
- -> { $~ = Object.new }.should raise_error(TypeError)
- -> { $~ = 1 }.should raise_error(TypeError)
+ -> { $~ = Object.new }.should.raise(TypeError, 'wrong argument type Object (expected MatchData)')
+ -> { $~ = 1 }.should.raise(TypeError, 'wrong argument type Integer (expected MatchData)')
end
it "changes the value of derived capture globals when assigned" do
@@ -134,7 +135,20 @@ describe "Predefined global $&" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
- $&.encoding.should equal(Encoding::EUC_JP)
+ $&.encoding.should.equal?(Encoding::EUC_JP)
+ end
+
+ it "is read-only" do
+ -> {
+ eval %q{$& = ""}
+ }.should.raise(SyntaxError, /Can't set variable \$&/)
+ end
+
+ it "is read-only when aliased" do
+ alias $predefined_spec_ampersand $&
+ -> {
+ $predefined_spec_ampersand = ""
+ }.should.raise(NameError, '$predefined_spec_ampersand is a read-only variable')
end
end
@@ -147,12 +161,25 @@ describe "Predefined global $`" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
- $`.encoding.should equal(Encoding::EUC_JP)
+ $`.encoding.should.equal?(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::ISO_8859_1) =~ /a/
- $`.encoding.should equal(Encoding::ISO_8859_1)
+ $`.encoding.should.equal?(Encoding::ISO_8859_1)
+ end
+
+ it "is read-only" do
+ -> {
+ eval %q{$` = ""}
+ }.should.raise(SyntaxError, /Can't set variable \$`/)
+ end
+
+ it "is read-only when aliased" do
+ alias $predefined_spec_backquote $`
+ -> {
+ $predefined_spec_backquote = ""
+ }.should.raise(NameError, '$predefined_spec_backquote is a read-only variable')
end
end
@@ -165,12 +192,25 @@ describe "Predefined global $'" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
- $'.encoding.should equal(Encoding::EUC_JP)
+ $'.encoding.should.equal?(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::ISO_8859_1) =~ /c/
- $'.encoding.should equal(Encoding::ISO_8859_1)
+ $'.encoding.should.equal?(Encoding::ISO_8859_1)
+ end
+
+ it "is read-only" do
+ -> {
+ eval %q{$' = ""}
+ }.should.raise(SyntaxError, /Can't set variable \$'/)
+ end
+
+ it "is read-only when aliased" do
+ alias $predefined_spec_single_quote $'
+ -> {
+ $predefined_spec_single_quote = ""
+ }.should.raise(NameError, '$predefined_spec_single_quote is a read-only variable')
end
end
@@ -188,7 +228,20 @@ describe "Predefined global $+" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
- $+.encoding.should equal(Encoding::EUC_JP)
+ $+.encoding.should.equal?(Encoding::EUC_JP)
+ end
+
+ it "is read-only" do
+ -> {
+ eval %q{$+ = ""}
+ }.should.raise(SyntaxError, /Can't set variable \$\+/)
+ end
+
+ it "is read-only when aliased" do
+ alias $predefined_spec_plus $+
+ -> {
+ $predefined_spec_plus = ""
+ }.should.raise(NameError, '$predefined_spec_plus is a read-only variable')
end
end
@@ -215,7 +268,7 @@ describe "Predefined globals $1..N" do
it "sets the encoding to the encoding of the source String" do
"abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
- $1.encoding.should equal(Encoding::EUC_JP)
+ $1.encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -229,16 +282,16 @@ describe "Predefined global $stdout" do
end
it "raises TypeError error if assigned to nil" do
- -> { $stdout = nil }.should raise_error(TypeError)
+ -> { $stdout = nil }.should.raise(TypeError, '$stdout must have write method, NilClass given')
end
it "raises TypeError error if assigned to object that doesn't respond to #write" do
obj = mock('object')
- -> { $stdout = obj }.should raise_error(TypeError)
+ -> { $stdout = obj }.should.raise(TypeError)
obj.stub!(:write)
$stdout = obj
- $stdout.should equal(obj)
+ $stdout.should.equal?(obj)
end
end
@@ -253,6 +306,12 @@ describe "Predefined global $!" do
$!.should == nil
end
+ it "is read-only" do
+ -> {
+ $! = []
+ }.should.raise(NameError, '$! is a read-only variable')
+ end
+
# See http://jira.codehaus.org/browse/JRUBY-5550
it "remains nil after a failed core class \"checked\" coercion against a class that defines method_missing" do
$!.should == nil
@@ -512,6 +571,75 @@ describe "Predefined global $!" do
end
end
+describe "Predefined global $@" do
+ it "is Fiber-local" do
+ Fiber.new do
+ raise "hi"
+ rescue
+ Fiber.yield
+ end.resume
+
+ $@.should == nil
+ end
+
+ it "is set to a backtrace of a rescued exception" do
+ begin
+ raise
+ rescue
+ $@.should.instance_of?(Array)
+ $@.should == $!.backtrace
+ end
+ end
+
+ it "is cleared when an exception is rescued" do
+ begin
+ raise
+ rescue
+ end
+
+ $@.should == nil
+ end
+
+ it "is not set when there is no current exception" do
+ $@.should == nil
+ end
+
+ it "is set to a backtrace of a rescued exception" do
+ begin
+ raise
+ rescue
+ $@.should.instance_of?(Array)
+ $@.should == $!.backtrace
+ end
+ end
+
+ it "is not read-only" do
+ begin
+ raise
+ rescue
+ $@ = []
+ $@.should == []
+ end
+ end
+
+ it_behaves_like :exception_set_backtrace, -> backtrace {
+ exception = nil
+ begin
+ raise
+ rescue
+ $@ = backtrace
+ exception = $!
+ end
+ exception
+ }
+
+ it "cannot be assigned when there is no a rescued exception" do
+ -> {
+ $@ = []
+ }.should.raise(ArgumentError, '$! not set')
+ end
+end
+
# Input/Output Variables
# ---------------------------------------------------------------------------------------------------
#
@@ -559,22 +687,22 @@ describe "Predefined global $/" do
$VERBOSE = @verbose
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "can be assigned a String" do
str = +"abc"
$/ = str
- $/.should equal(str)
+ $/.should.equal?(str)
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "makes a new frozen String from the assigned String" do
string_subclass = Class.new(String)
str = string_subclass.new("abc")
str.instance_variable_set(:@ivar, 1)
$/ = str
$/.should.frozen?
- $/.should be_an_instance_of(String)
+ $/.should.instance_of?(String)
$/.should_not.instance_variable_defined?(:@ivar)
$/.should == str
end
@@ -589,12 +717,13 @@ describe "Predefined global $/" do
it "assigns the given String if it's frozen and has no instance variables" do
str = "abc".freeze
$/ = str
- $/.should equal(str)
+ $/.should.equal?(str)
end
end
+
it "can be assigned nil" do
$/ = nil
- $/.should be_nil
+ $/.should == nil
end
it "returns the value assigned" do
@@ -603,22 +732,26 @@ describe "Predefined global $/" do
it "changes $-0" do
$/ = "xyz"
- $-0.should equal($/)
+ $-0.should.equal?($/)
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$/ value")
obj.should_not_receive(:to_str)
- -> { $/ = obj }.should raise_error(TypeError)
+ -> { $/ = obj }.should.raise(TypeError, 'value of $/ must be String')
end
it "raises a TypeError if assigned an Integer" do
- -> { $/ = 1 }.should raise_error(TypeError)
+ -> { $/ = 1 }.should.raise(TypeError, 'value of $/ must be String')
end
it "raises a TypeError if assigned a boolean" do
- -> { $/ = true }.should raise_error(TypeError)
+ -> { $/ = true }.should.raise(TypeError, 'value of $/ must be String')
+ end
+
+ it "warns if assigned non-nil" do
+ -> { $/ = "_" }.should complain(/warning: (?:non-nil )?[`']\$\/' is deprecated/)
end
end
@@ -635,22 +768,22 @@ describe "Predefined global $-0" do
$VERBOSE = @verbose
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "can be assigned a String" do
str = +"abc"
$-0 = str
- $-0.should equal(str)
+ $-0.should.equal?(str)
end
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "makes a new frozen String from the assigned String" do
string_subclass = Class.new(String)
str = string_subclass.new("abc")
str.instance_variable_set(:@ivar, 1)
$-0 = str
$-0.should.frozen?
- $-0.should be_an_instance_of(String)
+ $-0.should.instance_of?(String)
$-0.should_not.instance_variable_defined?(:@ivar)
$-0.should == str
end
@@ -665,13 +798,13 @@ describe "Predefined global $-0" do
it "assigns the given String if it's frozen and has no instance variables" do
str = "abc".freeze
$-0 = str
- $-0.should equal(str)
+ $-0.should.equal?(str)
end
end
it "can be assigned nil" do
$-0 = nil
- $-0.should be_nil
+ $-0.should == nil
end
it "returns the value assigned" do
@@ -680,22 +813,26 @@ describe "Predefined global $-0" do
it "changes $/" do
$-0 = "xyz"
- $/.should equal($-0)
+ $/.should.equal?($-0)
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$-0 value")
obj.should_not_receive(:to_str)
- -> { $-0 = obj }.should raise_error(TypeError)
+ -> { $-0 = obj }.should.raise(TypeError, 'value of $-0 must be String')
end
it "raises a TypeError if assigned an Integer" do
- -> { $-0 = 1 }.should raise_error(TypeError)
+ -> { $-0 = 1 }.should.raise(TypeError, 'value of $-0 must be String')
end
it "raises a TypeError if assigned a boolean" do
- -> { $-0 = true }.should raise_error(TypeError)
+ -> { $-0 = true }.should.raise(TypeError, 'value of $-0 must be String')
+ end
+
+ it "warns if assigned non-nil" do
+ -> { $-0 = "_" }.should complain(/warning: (?:non-nil )?[`']\$-0' is deprecated/)
end
end
@@ -713,12 +850,12 @@ describe "Predefined global $\\" do
it "can be assigned a String" do
str = "abc"
$\ = str
- $\.should equal(str)
+ $\.should.equal?(str)
end
it "can be assigned nil" do
$\ = nil
- $\.should be_nil
+ $\.should == nil
end
it "returns the value assigned" do
@@ -729,12 +866,16 @@ describe "Predefined global $\\" do
obj = mock("$\\ value")
obj.should_not_receive(:to_str)
- -> { $\ = obj }.should raise_error(TypeError)
+ -> { $\ = obj }.should.raise(TypeError, 'value of $\ must be String')
end
it "raises a TypeError if assigned not String" do
- -> { $\ = 1 }.should raise_error(TypeError)
- -> { $\ = true }.should raise_error(TypeError)
+ -> { $\ = 1 }.should.raise(TypeError, 'value of $\ must be String')
+ -> { $\ = true }.should.raise(TypeError, 'value of $\ must be String')
+ end
+
+ it "warns if assigned non-nil" do
+ -> { $\ = "_" }.should complain(/warning: (?:non-nil )?[`']\$\\' is deprecated/)
end
end
@@ -744,15 +885,15 @@ describe "Predefined global $," do
end
it "defaults to nil" do
- $,.should be_nil
+ $,.should == nil
end
it "raises TypeError if assigned a non-String" do
- -> { $, = Object.new }.should raise_error(TypeError)
+ -> { $, = Object.new }.should.raise(TypeError, 'value of $, must be String')
end
it "warns if assigned non-nil" do
- -> { $, = "_" }.should complain(/warning: [`']\$,' is deprecated/)
+ -> { $, = "_" }.should complain(/warning: (?:non-nil )?[`']\$,' is deprecated/)
end
end
@@ -779,7 +920,7 @@ describe "Predefined global $." do
obj = mock("bad-value")
obj.should_receive(:to_int).and_return('abc')
- -> { $. = obj }.should raise_error(TypeError)
+ -> { $. = obj }.should.raise(TypeError)
end
end
@@ -789,7 +930,7 @@ describe "Predefined global $;" do
end
it "warns if assigned non-nil" do
- -> { $; = "_" }.should complain(/warning: [`']\$;' is deprecated/)
+ -> { $; = "_" }.should complain(/warning: (?:non-nil )?[`']\$;' is deprecated/)
end
end
@@ -844,7 +985,7 @@ describe "Predefined global $_" do
end
Thread.pass until running
- $_.should be_nil
+ $_.should == nil
thr.join
end
@@ -915,7 +1056,7 @@ describe "Execution variable $:" do
end
it "does not include the current directory" do
- $:.should_not include(".")
+ $:.should_not.include?(".")
end
it "is the same object as $LOAD_PATH and $-I" do
@@ -925,7 +1066,7 @@ describe "Execution variable $:" do
it "can be changed via <<" do
$: << "foo"
- $:.should include("foo")
+ $:.should.include?("foo")
ensure
$:.delete("foo")
end
@@ -933,41 +1074,47 @@ describe "Execution variable $:" do
it "is read-only" do
-> {
$: = []
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$: is a read-only variable')
-> {
$LOAD_PATH = []
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$LOAD_PATH is a read-only variable')
-> {
$-I = []
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$-I is a read-only variable')
end
it "default $LOAD_PATH entries until sitelibdir included have @gem_prelude_index set" do
skip "no sense in ruby itself" if MSpecScript.instance_variable_defined?(:@testing_ruby)
- $:.should.include?(RbConfig::CONFIG['sitelibdir'])
- idx = $:.index(RbConfig::CONFIG['sitelibdir'])
+ if platform_is :windows
+ # See https://github.com/ruby/setup-ruby/pull/762#issuecomment-2917460440
+ $:.should.find { |e| File.realdirpath(e) == RbConfig::CONFIG['sitelibdir'] }
+ idx = $:.index { |e| File.realdirpath(e) == RbConfig::CONFIG['sitelibdir'] }
+ else
+ $:.should.include?(RbConfig::CONFIG['sitelibdir'])
+ idx = $:.index(RbConfig::CONFIG['sitelibdir'])
+ end
- $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
- $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
+ $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should == true
+ $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should == true
end
end
describe "Global variable $\"" do
it "is an alias for $LOADED_FEATURES" do
- $".should equal $LOADED_FEATURES
+ $".should.equal? $LOADED_FEATURES
end
it "is read-only" do
-> {
$" = []
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$" is a read-only variable')
-> {
$LOADED_FEATURES = []
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$LOADED_FEATURES is a read-only variable')
end
end
@@ -975,7 +1122,7 @@ describe "Global variable $<" do
it "is read-only" do
-> {
$< = nil
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$< is a read-only variable')
end
end
@@ -983,7 +1130,7 @@ describe "Global variable $FILENAME" do
it "is read-only" do
-> {
$FILENAME = "-"
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$FILENAME is a read-only variable')
end
end
@@ -991,30 +1138,30 @@ describe "Global variable $?" do
it "is read-only" do
-> {
$? = nil
- }.should raise_error(NameError)
+ }.should.raise(NameError, '$? is a read-only variable')
end
it "is thread-local" do
system(ruby_cmd('exit 0'))
- Thread.new { $?.should be_nil }.join
+ Thread.new { $?.should == nil }.join
end
end
describe "Global variable $-a" do
it "is read-only" do
- -> { $-a = true }.should raise_error(NameError)
+ -> { $-a = true }.should.raise(NameError, '$-a is a read-only variable')
end
end
describe "Global variable $-l" do
it "is read-only" do
- -> { $-l = true }.should raise_error(NameError)
+ -> { $-l = true }.should.raise(NameError, '$-l is a read-only variable')
end
end
describe "Global variable $-p" do
it "is read-only" do
- -> { $-p = true }.should raise_error(NameError)
+ -> { $-p = true }.should.raise(NameError, '$-p is a read-only variable')
end
end
@@ -1029,9 +1176,9 @@ describe "Global variable $-d" do
it "is an alias of $DEBUG" do
$DEBUG = true
- $-d.should be_true
+ $-d.should == true
$-d = false
- $DEBUG.should be_false
+ $DEBUG.should == false
end
end
@@ -1045,24 +1192,24 @@ describe "Global variable $VERBOSE" do
end
it "is false by default" do
- $VERBOSE.should be_false
+ $VERBOSE.should == false
end
it "converts truthy values to true" do
[true, 1, 0, [], ""].each do |true_value|
$VERBOSE = true_value
- $VERBOSE.should be_true
+ $VERBOSE.should == true
end
end
it "allows false" do
$VERBOSE = false
- $VERBOSE.should be_false
+ $VERBOSE.should == false
end
it "allows nil without coercing to false" do
$VERBOSE = nil
- $VERBOSE.should be_nil
+ $VERBOSE.should == nil
end
end
@@ -1077,9 +1224,9 @@ describe :verbose_global_alias, shared: true do
it "is an alias of $VERBOSE" do
$VERBOSE = true
- eval(@method).should be_true
+ eval(@method).should == true
eval("#{@method} = false")
- $VERBOSE.should be_false
+ $VERBOSE.should == false
end
end
@@ -1116,7 +1263,7 @@ describe "Global variable $0" do
it "actually sets the program name" do
title = "rubyspec-dollar0-test"
$0 = title
- `ps -ocommand= -p#{$$}`.should include(title)
+ `ps -ocommand= -p#{$$}`.should.include?(title)
end
end
@@ -1125,7 +1272,7 @@ describe "Global variable $0" do
end
it "raises a TypeError when not given an object that can be coerced to a String" do
- -> { $0 = nil }.should raise_error(TypeError)
+ -> { $0 = nil }.should.raise(TypeError)
end
end
@@ -1161,37 +1308,37 @@ end
describe "The predefined standard object nil" do
it "is an instance of NilClass" do
- nil.should be_kind_of(NilClass)
+ nil.should.is_a?(NilClass)
end
it "raises a SyntaxError if assigned to" do
- -> { eval("nil = true") }.should raise_error(SyntaxError)
+ -> { eval("nil = true") }.should.raise(SyntaxError, /Can't assign to nil/)
end
end
describe "The predefined standard object true" do
it "is an instance of TrueClass" do
- true.should be_kind_of(TrueClass)
+ true.should.is_a?(TrueClass)
end
it "raises a SyntaxError if assigned to" do
- -> { eval("true = false") }.should raise_error(SyntaxError)
+ -> { eval("true = false") }.should.raise(SyntaxError, /Can't assign to true/)
end
end
describe "The predefined standard object false" do
it "is an instance of FalseClass" do
- false.should be_kind_of(FalseClass)
+ false.should.is_a?(FalseClass)
end
it "raises a SyntaxError if assigned to" do
- -> { eval("false = nil") }.should raise_error(SyntaxError)
+ -> { eval("false = nil") }.should.raise(SyntaxError, /Can't assign to false/)
end
end
describe "The self pseudo-variable" do
it "raises a SyntaxError if assigned to" do
- -> { eval("self = 1") }.should raise_error(SyntaxError)
+ -> { eval("self = 1") }.should.raise(SyntaxError, /Can't change the value of self/)
end
end
@@ -1286,21 +1433,21 @@ describe "The predefined global constant" do
describe "STDIN" do
platform_is_not :windows do
it "has the same external encoding as Encoding.default_external" do
- STDIN.external_encoding.should equal(Encoding.default_external)
+ STDIN.external_encoding.should.equal?(Encoding.default_external)
end
it "has the same external encoding as Encoding.default_external when that encoding is changed" do
Encoding.default_external = Encoding::ISO_8859_16
- STDIN.external_encoding.should equal(Encoding::ISO_8859_16)
+ STDIN.external_encoding.should.equal?(Encoding::ISO_8859_16)
end
it "has nil for the internal encoding" do
- STDIN.internal_encoding.should be_nil
+ STDIN.internal_encoding.should == nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
- STDIN.internal_encoding.should be_nil
+ STDIN.internal_encoding.should == nil
end
end
@@ -1320,12 +1467,12 @@ describe "The predefined global constant" do
describe "STDOUT" do
it "has nil for the external encoding" do
- STDOUT.external_encoding.should be_nil
+ STDOUT.external_encoding.should == nil
end
it "has nil for the external encoding despite Encoding.default_external being changed" do
Encoding.default_external = Encoding::ISO_8859_1
- STDOUT.external_encoding.should be_nil
+ STDOUT.external_encoding.should == nil
end
it "has the encodings set by #set_encoding" do
@@ -1335,23 +1482,23 @@ describe "The predefined global constant" do
end
it "has nil for the internal encoding" do
- STDOUT.internal_encoding.should be_nil
+ STDOUT.internal_encoding.should == nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
- STDOUT.internal_encoding.should be_nil
+ STDOUT.internal_encoding.should == nil
end
end
describe "STDERR" do
it "has nil for the external encoding" do
- STDERR.external_encoding.should be_nil
+ STDERR.external_encoding.should == nil
end
it "has nil for the external encoding despite Encoding.default_external being changed" do
Encoding.default_external = Encoding::ISO_8859_1
- STDERR.external_encoding.should be_nil
+ STDERR.external_encoding.should == nil
end
it "has the encodings set by #set_encoding" do
@@ -1361,12 +1508,12 @@ describe "The predefined global constant" do
end
it "has nil for the internal encoding" do
- STDERR.internal_encoding.should be_nil
+ STDERR.internal_encoding.should == nil
end
it "has nil for the internal encoding despite Encoding.default_internal being changed" do
Encoding.default_internal = Encoding::IBM437
- STDERR.internal_encoding.should be_nil
+ STDERR.internal_encoding.should == nil
end
end
@@ -1382,9 +1529,9 @@ end
describe "$LOAD_PATH.resolve_feature_path" do
it "returns what will be loaded without actual loading, .rb file" do
- extension, path = $LOAD_PATH.resolve_feature_path('set')
+ extension, path = $LOAD_PATH.resolve_feature_path('pp')
extension.should == :rb
- path.should.end_with?('/set.rb')
+ path.should.end_with?('/pp.rb')
end
it "returns what will be loaded without actual loading, .so file" do
@@ -1397,7 +1544,7 @@ describe "$LOAD_PATH.resolve_feature_path" do
end
it "return nil if feature cannot be found" do
- $LOAD_PATH.resolve_feature_path('noop').should be_nil
+ $LOAD_PATH.resolve_feature_path('noop').should == nil
end
end
diff --git a/spec/ruby/language/private_spec.rb b/spec/ruby/language/private_spec.rb
index b04aa25c9e..94b56fee5b 100644
--- a/spec/ruby/language/private_spec.rb
+++ b/spec/ruby/language/private_spec.rb
@@ -4,12 +4,12 @@ require_relative 'fixtures/private'
describe "The private keyword" do
it "marks following methods as being private" do
a = Private::A.new
- a.methods.should_not include(:bar)
- -> { a.bar }.should raise_error(NoMethodError)
+ a.methods.should_not.include?(:bar)
+ -> { a.bar }.should.raise(NoMethodError)
b = Private::B.new
- b.methods.should_not include(:bar)
- -> { b.bar }.should raise_error(NoMethodError)
+ b.methods.should_not.include?(:bar)
+ -> { b.bar }.should.raise(NoMethodError)
end
# def expr.meth() methods are always public
@@ -19,15 +19,15 @@ describe "The private keyword" do
it "is overridden when a new class is opened" do
c = Private::B::C.new
- c.methods.should include(:baz)
+ c.methods.should.include?(:baz)
c.baz
Private::B.public_class_method1.should == 1
- -> { Private::B.private_class_method1 }.should raise_error(NoMethodError)
+ -> { Private::B.private_class_method1 }.should.raise(NoMethodError)
end
it "is no longer in effect when the class is closed" do
b = Private::B.new
- b.methods.should include(:foo)
+ b.methods.should.include?(:foo)
b.foo
end
@@ -42,7 +42,7 @@ describe "The private keyword" do
klass.class_eval do
private :foo
end
- -> { f.foo }.should raise_error(NoMethodError)
+ -> { f.foo }.should.raise(NoMethodError)
end
it "changes visibility of previously called methods with same send/call site" do
@@ -56,12 +56,12 @@ describe "The private keyword" do
end
end
end
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "changes the visibility of the existing method in the subclass" do
::Private::A.new.foo.should == 'foo'
- -> { ::Private::H.new.foo }.should raise_error(NoMethodError)
+ -> { ::Private::H.new.foo }.should.raise(NoMethodError)
::Private::H.new.send(:foo).should == 'foo'
end
end
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index ca9a13aa61..53a21d6b85 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -22,7 +22,7 @@ describe "A Proc" do
end
it "raises an ArgumentError if a value is passed" do
- lambda { @l.call(0) }.should raise_error(ArgumentError)
+ lambda { @l.call(0) }.should.raise(ArgumentError)
end
end
@@ -36,7 +36,7 @@ describe "A Proc" do
end
it "raises an ArgumentError if a value is passed" do
- lambda { @l.call(0) }.should raise_error(ArgumentError)
+ lambda { @l.call(0) }.should.raise(ArgumentError)
end
end
@@ -57,11 +57,11 @@ describe "A Proc" do
obj = mock("block yield to_ary")
obj.should_not_receive(:to_ary)
- @l.call(obj).should equal(obj)
+ @l.call(obj).should.equal?(obj)
end
it "raises an ArgumentError if no value is passed" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
end
@@ -71,11 +71,11 @@ describe "A Proc" do
end
it "raises an ArgumentError if passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "raises an ArgumentError if passed one value" do
- lambda { @l.call(0) }.should raise_error(ArgumentError)
+ lambda { @l.call(0) }.should.raise(ArgumentError)
end
it "assigns the values passed to the arguments" do
@@ -86,7 +86,7 @@ describe "A Proc" do
obj = mock("proc call to_ary")
obj.should_not_receive(:to_ary)
- lambda { @l.call(obj) }.should raise_error(ArgumentError)
+ lambda { @l.call(obj) }.should.raise(ArgumentError)
end
end
@@ -96,7 +96,7 @@ describe "A Proc" do
end
it "raises an ArgumentError if passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "does not destructure a single Array value yielded" do
@@ -179,11 +179,11 @@ describe "A Proc" do
end
it "raises an ArgumentError when passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "raises an ArgumentError when passed more than one value" do
- lambda { @l.call(1, 2) }.should raise_error(ArgumentError)
+ lambda { @l.call(1, 2) }.should.raise(ArgumentError)
end
it "assigns the argument the value passed" do
@@ -208,7 +208,7 @@ describe "A Proc" do
end
it "raises an ArgumentError when passed no values" do
- lambda { @l.call }.should raise_error(ArgumentError)
+ lambda { @l.call }.should.raise(ArgumentError)
end
it "destructures a single Array value yielded" do
@@ -226,7 +226,7 @@ describe "A Proc" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- lambda { @l.call(obj) }.should raise_error(TypeError)
+ lambda { @l.call(obj) }.should.raise(TypeError)
end
end
@@ -243,7 +243,25 @@ describe "A Proc" do
describe "taking |required keyword arguments, **kw| arguments" do
it "raises ArgumentError for missing required argument" do
p = proc { |a:, **kw| [a, kw] }
- -> { p.call() }.should raise_error(ArgumentError)
+ -> { p.call() }.should.raise(ArgumentError)
end
end
+
+ evaluate <<-ruby do
+ @p = proc { |**nil| :ok }
+ ruby
+
+ @p.call().should == :ok
+ -> { @p.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @p.call(**{a: 1}) }.should.raise(ArgumentError, 'no keywords accepted')
+ -> { @p.call("a" => 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @p = proc { |a, **nil| a }
+ ruby
+
+ @p.call({a: 1}).should == {a: 1}
+ -> { @p.call(a: 1) }.should.raise(ArgumentError, 'no keywords accepted')
+ end
end
diff --git a/spec/ruby/language/redo_spec.rb b/spec/ruby/language/redo_spec.rb
index 57532553b3..9b14c5add1 100644
--- a/spec/ruby/language/redo_spec.rb
+++ b/spec/ruby/language/redo_spec.rb
@@ -60,7 +60,7 @@ describe "The redo statement" do
it "is invalid and raises a SyntaxError" do
-> {
eval("def m; redo; end")
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
end
diff --git a/spec/ruby/language/regexp/anchors_spec.rb b/spec/ruby/language/regexp/anchors_spec.rb
index cdc06c0b4d..8e597b65e8 100644
--- a/spec/ruby/language/regexp/anchors_spec.rb
+++ b/spec/ruby/language/regexp/anchors_spec.rb
@@ -7,8 +7,8 @@ describe "Regexps with anchors" do
/^foo/.match("foo").to_a.should == ["foo"]
/^bar/.match("foo\nbar").to_a.should == ["bar"]
# Basic non-matching
- /^foo/.match(" foo").should be_nil
- /foo^/.match("foo\n\n\n").should be_nil
+ /^foo/.match(" foo").should == nil
+ /foo^/.match("foo\n\n\n").should == nil
# A bit advanced
/^^^foo/.match("foo").to_a.should == ["foo"]
@@ -16,8 +16,8 @@ describe "Regexps with anchors" do
(/($^)($^)/ =~ "foo\n\n").should == "foo\n".size and $~.to_a.should == ["", "", ""]
# Different start of line chars
- /^bar/.match("foo\rbar").should be_nil
- /^bar/.match("foo\0bar").should be_nil
+ /^bar/.match("foo\rbar").should == nil
+ /^bar/.match("foo\0bar").should == nil
# Trivial
/^/.match("foo").to_a.should == [""]
@@ -29,7 +29,7 @@ describe "Regexps with anchors" do
end
it "does not match ^ after trailing \\n" do
- /^(?!\A)/.match("foo\n").should be_nil # There is no (empty) line after a trailing \n
+ /^(?!\A)/.match("foo\n").should == nil # There is no (empty) line after a trailing \n
end
it "supports $ (line end anchor)" do
@@ -37,16 +37,16 @@ describe "Regexps with anchors" do
/foo$/.match("foo").to_a.should == ["foo"]
/foo$/.match("foo\nbar").to_a.should == ["foo"]
# Basic non-matching
- /foo$/.match("foo ").should be_nil
- /$foo/.match("\n\n\nfoo").should be_nil
+ /foo$/.match("foo ").should == nil
+ /$foo/.match("\n\n\nfoo").should == nil
# A bit advanced
/foo$$$/.match("foo").to_a.should == ["foo"]
(/[^o]$/ =~ "foo\n\n").should == ("foo\n".size - 1) and $~.to_a.should == ["\n"]
# Different end of line chars
- /foo$/.match("foo\r\nbar").should be_nil
- /foo$/.match("foo\0bar").should be_nil
+ /foo$/.match("foo\r\nbar").should == nil
+ /foo$/.match("foo\0bar").should == nil
# Trivial
(/$/ =~ "foo").should == "foo".size and $~.to_a.should == [""]
@@ -61,15 +61,15 @@ describe "Regexps with anchors" do
# Basic matching
/\Afoo/.match("foo").to_a.should == ["foo"]
# Basic non-matching
- /\Abar/.match("foo\nbar").should be_nil
- /\Afoo/.match(" foo").should be_nil
+ /\Abar/.match("foo\nbar").should == nil
+ /\Afoo/.match(" foo").should == nil
# A bit advanced
/\A\A\Afoo/.match("foo").to_a.should == ["foo"]
/(\A\Z)(\A\Z)/.match("").to_a.should == ["", "", ""]
# Different start of line chars
- /\Abar/.match("foo\0bar").should be_nil
+ /\Abar/.match("foo\0bar").should == nil
# Grouping
/(\Afoo)/.match("foo").to_a.should == ["foo", "foo"]
@@ -81,8 +81,8 @@ describe "Regexps with anchors" do
/foo\Z/.match("foo").to_a.should == ["foo"]
/foo\Z/.match("foo\n").to_a.should == ["foo"]
# Basic non-matching
- /foo\Z/.match("foo\nbar").should be_nil
- /foo\Z/.match("foo ").should be_nil
+ /foo\Z/.match("foo\nbar").should == nil
+ /foo\Z/.match("foo ").should == nil
# A bit advanced
/foo\Z\Z\Z/.match("foo\n").to_a.should == ["foo"]
@@ -90,8 +90,8 @@ describe "Regexps with anchors" do
(/(\z\Z)(\z\Z)/ =~ "foo\n").should == "foo\n".size and $~.to_a.should == ["", "", ""]
# Different end of line chars
- /foo\Z/.match("foo\0bar").should be_nil
- /foo\Z/.match("foo\r\n").should be_nil
+ /foo\Z/.match("foo\0bar").should == nil
+ /foo\Z/.match("foo\r\n").should == nil
# Grouping
/(foo\Z)/.match("foo").to_a.should == ["foo", "foo"]
@@ -102,17 +102,17 @@ describe "Regexps with anchors" do
# Basic matching
/foo\z/.match("foo").to_a.should == ["foo"]
# Basic non-matching
- /foo\z/.match("foo\nbar").should be_nil
- /foo\z/.match("foo\n").should be_nil
- /foo\z/.match("foo ").should be_nil
+ /foo\z/.match("foo\nbar").should == nil
+ /foo\z/.match("foo\n").should == nil
+ /foo\z/.match("foo ").should == nil
# A bit advanced
/foo\z\z\z/.match("foo").to_a.should == ["foo"]
(/($\z)($\z)/ =~ "foo").should == "foo".size and $~.to_a.should == ["", "", ""]
# Different end of line chars
- /foo\z/.match("foo\0bar").should be_nil
- /foo\z/.match("foo\r\nbar").should be_nil
+ /foo\z/.match("foo\0bar").should == nil
+ /foo\z/.match("foo\r\nbar").should == nil
# Grouping
/(foo\z)/.match("foo").to_a.should == ["foo", "foo"]
@@ -131,9 +131,9 @@ describe "Regexps with anchors" do
end
/foo\b/.match("foo\0").to_a.should == ["foo"]
# Basic non-matching
- /foo\b/.match("foobar").should be_nil
- /foo\b/.match("foo123").should be_nil
- /foo\b/.match("foo_").should be_nil
+ /foo\b/.match("foobar").should == nil
+ /foo\b/.match("foo123").should == nil
+ /foo\b/.match("foo_").should == nil
end
it "supports \\B (non-word-boundary)" do
@@ -142,15 +142,15 @@ describe "Regexps with anchors" do
/foo\B/.match("foo123").to_a.should == ["foo"]
/foo\B/.match("foo_").to_a.should == ["foo"]
# Basic non-matching
- /foo\B/.match("foo").should be_nil
- /foo\B/.match("foo\n").should be_nil
+ /foo\B/.match("foo").should == nil
+ /foo\B/.match("foo\n").should == nil
LanguageSpecs.white_spaces.scan(/./).each do |c|
- /foo\B/.match("foo" + c).should be_nil
+ /foo\B/.match("foo" + c).should == nil
end
LanguageSpecs.non_alphanum_non_space.scan(/./).each do |c|
- /foo\B/.match("foo" + c).should be_nil
+ /foo\B/.match("foo" + c).should == nil
end
- /foo\B/.match("foo\0").should be_nil
+ /foo\B/.match("foo\0").should == nil
end
it "supports (?= ) (positive lookahead)" do
diff --git a/spec/ruby/language/regexp/back-references_spec.rb b/spec/ruby/language/regexp/back-references_spec.rb
index 627c8daace..3b4c5656a2 100644
--- a/spec/ruby/language/regexp/back-references_spec.rb
+++ b/spec/ruby/language/regexp/back-references_spec.rb
@@ -49,7 +49,7 @@ describe "Regexps with back-references" do
it "supports \<n> (backreference to previous group match)" do
/(foo.)\1/.match("foo1foo1").to_a.should == ["foo1foo1", "foo1"]
- /(foo.)\1/.match("foo1foo2").should be_nil
+ /(foo.)\1/.match("foo1foo2").should == nil
end
it "resets nested \<n> backreference before match of outer subexpression" do
@@ -82,7 +82,7 @@ describe "Regexps with back-references" do
end
it "0 is not a valid backreference" do
- -> { Regexp.new("\\k<0>") }.should raise_error(RegexpError)
+ -> { Regexp.new("\\k<0>") }.should.raise(RegexpError)
end
it "allows numeric conditional backreferences" do
@@ -92,7 +92,7 @@ describe "Regexps with back-references" do
end
it "allows either <> or '' in named conditional backreferences" do
- -> { Regexp.new("(?<a>a)(?(a)a|b)") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<a>a)(?(a)a|b)") }.should.raise(RegexpError)
/(?<a>a)(?(<a>)a|b)/.match("aa").to_a.should == [ "aa", "a" ]
/(?<a>a)(?('a')a|b)/.match("aa").to_a.should == [ "aa", "a" ]
end
@@ -118,32 +118,32 @@ describe "Regexps with back-references" do
end
it "named capture groups invalidate numeric backreferences" do
- -> { Regexp.new("(?<a>a)\\1") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a>a)\\k<1>") }.should raise_error(RegexpError)
- -> { Regexp.new("(a)(?<a>a)\\1") }.should raise_error(RegexpError)
- -> { Regexp.new("(a)(?<a>a)\\k<1>") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<a>a)\\1") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a>a)\\k<1>") }.should.raise(RegexpError)
+ -> { Regexp.new("(a)(?<a>a)\\1") }.should.raise(RegexpError)
+ -> { Regexp.new("(a)(?<a>a)\\k<1>") }.should.raise(RegexpError)
end
it "treats + or - as the beginning of a level specifier in \\k<> backreferences and (?(...)...|...) conditional backreferences" do
- -> { Regexp.new("(?<a+>a)\\k<a+>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+b>a)\\k<a+b>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+1>a)\\k<a+1>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a->a)\\k<a->") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-b>a)\\k<a-b>") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-1>a)\\k<a-1>") }.should raise_error(RegexpError)
-
- -> { Regexp.new("(?<a+>a)(?(<a+>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+b>a)(?(<a+b>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+1>a)(?(<a+1>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a->a)(?(<a->)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-b>a)(?(<a-b>)a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-1>a)(?(<a-1>)a|b)") }.should raise_error(RegexpError)
-
- -> { Regexp.new("(?<a+>a)(?('a+')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+b>a)(?('a+b')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a+1>a)(?('a+1')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a->a)(?('a-')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-b>a)(?('a-b')a|b)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<a-1>a)(?('a-1')a|b)") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<a+>a)\\k<a+>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+b>a)\\k<a+b>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+1>a)\\k<a+1>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a->a)\\k<a->") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-b>a)\\k<a-b>") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-1>a)\\k<a-1>") }.should.raise(RegexpError)
+
+ -> { Regexp.new("(?<a+>a)(?(<a+>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+b>a)(?(<a+b>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+1>a)(?(<a+1>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a->a)(?(<a->)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-b>a)(?(<a-b>)a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-1>a)(?(<a-1>)a|b)") }.should.raise(RegexpError)
+
+ -> { Regexp.new("(?<a+>a)(?('a+')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+b>a)(?('a+b')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a+1>a)(?('a+1')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a->a)(?('a-')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-b>a)(?('a-b')a|b)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<a-1>a)(?('a-1')a|b)") }.should.raise(RegexpError)
end
end
diff --git a/spec/ruby/language/regexp/character_classes_spec.rb b/spec/ruby/language/regexp/character_classes_spec.rb
index 8e9a0b960b..c6ed92b78e 100644
--- a/spec/ruby/language/regexp/character_classes_spec.rb
+++ b/spec/ruby/language/regexp/character_classes_spec.rb
@@ -9,9 +9,9 @@ describe "Regexp with character classes" do
/\w/.match("_").to_a.should == ["_"]
# Non-matches
- /\w/.match(LanguageSpecs.white_spaces).should be_nil
- /\w/.match(LanguageSpecs.non_alphanum_non_space).should be_nil
- /\w/.match("\0").should be_nil
+ /\w/.match(LanguageSpecs.white_spaces).should == nil
+ /\w/.match(LanguageSpecs.non_alphanum_non_space).should == nil
+ /\w/.match("\0").should == nil
end
it "supports \\W (non-word character)" do
@@ -20,19 +20,19 @@ describe "Regexp with character classes" do
/\W/.match("\0").to_a.should == ["\0"]
# Non-matches
- /\W/.match("a").should be_nil
- /\W/.match("1").should be_nil
- /\W/.match("_").should be_nil
+ /\W/.match("a").should == nil
+ /\W/.match("1").should == nil
+ /\W/.match("_").should == nil
end
it "supports \\s (space character)" do
/\s+/.match(LanguageSpecs.white_spaces).to_a.should == [LanguageSpecs.white_spaces]
# Non-matches
- /\s/.match("a").should be_nil
- /\s/.match("1").should be_nil
- /\s/.match(LanguageSpecs.non_alphanum_non_space).should be_nil
- /\s/.match("\0").should be_nil
+ /\s/.match("a").should == nil
+ /\s/.match("1").should == nil
+ /\s/.match(LanguageSpecs.non_alphanum_non_space).should == nil
+ /\s/.match("\0").should == nil
end
it "supports \\S (non-space character)" do
@@ -42,17 +42,17 @@ describe "Regexp with character classes" do
/\S/.match("\0").to_a.should == ["\0"]
# Non-matches
- /\S/.match(LanguageSpecs.white_spaces).should be_nil
+ /\S/.match(LanguageSpecs.white_spaces).should == nil
end
it "supports \\d (numeric digit)" do
/\d/.match("1").to_a.should == ["1"]
# Non-matches
- /\d/.match("a").should be_nil
- /\d/.match(LanguageSpecs.white_spaces).should be_nil
- /\d/.match(LanguageSpecs.non_alphanum_non_space).should be_nil
- /\d/.match("\0").should be_nil
+ /\d/.match("a").should == nil
+ /\d/.match(LanguageSpecs.white_spaces).should == nil
+ /\d/.match(LanguageSpecs.non_alphanum_non_space).should == nil
+ /\d/.match("\0").should == nil
end
it "supports \\D (non-digit)" do
@@ -62,7 +62,7 @@ describe "Regexp with character classes" do
/\D/.match("\0").to_a.should == ["\0"]
# Non-matches
- /\D/.match("1").should be_nil
+ /\D/.match("1").should == nil
end
it "supports [] (character class)" do
@@ -89,7 +89,7 @@ describe "Regexp with character classes" do
/[^[:lower:]A-C]+/.match("abcABCDEF123def").to_a.should == ["DEF123"] # negated character class
/[:alnum:]+/.match("a:l:n:u:m").to_a.should == ["a:l:n:u:m"] # should behave like regular character class composed of the individual letters
/[\[:alnum:]+/.match("[:a:l:n:u:m").to_a.should == ["[:a:l:n:u:m"] # should behave like regular character class composed of the individual letters
- -> { eval('/[[:alpha:]-[:digit:]]/') }.should raise_error(SyntaxError) # can't use character class as a start value of range
+ -> { eval('/[[:alpha:]-[:digit:]]/') }.should.raise(SyntaxError) # can't use character class as a start value of range
end
it "matches ASCII characters with [[:ascii:]]" do
@@ -99,8 +99,8 @@ describe "Regexp with character classes" do
not_supported_on :opal do
it "doesn't match non-ASCII characters with [[:ascii:]]" do
- /[[:ascii:]]/.match("\u{80}").should be_nil
- /[[:ascii:]]/.match("\u{9898}").should be_nil
+ /[[:ascii:]]/.match("\u{80}").should == nil
+ /[[:ascii:]]/.match("\u{9898}").should == nil
end
end
@@ -113,7 +113,7 @@ describe "Regexp with character classes" do
end
it "doesn't matches Unicode marks with [[:alnum:]]" do
- "\u{36F}".match(/[[:alnum:]]/).should be_nil
+ "\u{3099}".match(/[[:alnum:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:alnum:]]" do
@@ -133,7 +133,7 @@ describe "Regexp with character classes" do
end
it "doesn't matches Unicode marks with [[:alpha:]]" do
- "\u{36F}".match(/[[:alpha:]]/).should be_nil
+ "\u{3099}".match(/[[:alpha:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:alpha:]]" do
@@ -149,39 +149,39 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode control characters with [[:blank:]]" do
- "\u{16}".match(/[[:blank:]]/).should be_nil
+ "\u{16}".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:blank:]]" do
- "\u{3F}".match(/[[:blank:]]/).should be_nil
+ "\u{3F}".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode letter characters with [[:blank:]]" do
- "à".match(/[[:blank:]]/).should be_nil
+ "à".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode digits with [[:blank:]]" do
- "\u{0660}".match(/[[:blank:]]/).should be_nil
+ "\u{0660}".match(/[[:blank:]]/).should == nil
end
it "doesn't match Unicode marks with [[:blank:]]" do
- "\u{36F}".match(/[[:blank:]]/).should be_nil
+ "\u{36F}".match(/[[:blank:]]/).should == nil
end
it "doesn't Unicode letter characters with [[:cntrl:]]" do
- "à".match(/[[:cntrl:]]/).should be_nil
+ "à".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode digits with [[:cntrl:]]" do
- "\u{0660}".match(/[[:cntrl:]]/).should be_nil
+ "\u{0660}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode marks with [[:cntrl:]]" do
- "\u{36F}".match(/[[:cntrl:]]/).should be_nil
+ "\u{36F}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:cntrl:]]" do
- "\u{3F}".match(/[[:cntrl:]]/).should be_nil
+ "\u{3F}".match(/[[:cntrl:]]/).should == nil
end
it "matches Unicode control characters with [[:cntrl:]]" do
@@ -189,15 +189,15 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode format characters with [[:cntrl:]]" do
- "\u{2060}".match(/[[:cntrl:]]/).should be_nil
+ "\u{2060}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:cntrl:]]" do
- "\u{E001}".match(/[[:cntrl:]]/).should be_nil
+ "\u{E001}".match(/[[:cntrl:]]/).should == nil
end
it "doesn't match Unicode letter characters with [[:digit:]]" do
- "à".match(/[[:digit:]]/).should be_nil
+ "à".match(/[[:digit:]]/).should == nil
end
it "matches Unicode digits with [[:digit:]]" do
@@ -206,23 +206,23 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode marks with [[:digit:]]" do
- "\u{36F}".match(/[[:digit:]]/).should be_nil
+ "\u{36F}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:digit:]]" do
- "\u{3F}".match(/[[:digit:]]/).should be_nil
+ "\u{3F}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:digit:]]" do
- "\u{16}".match(/[[:digit:]]/).should be_nil
+ "\u{16}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:digit:]]" do
- "\u{2060}".match(/[[:digit:]]/).should be_nil
+ "\u{2060}".match(/[[:digit:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:digit:]]" do
- "\u{E001}".match(/[[:digit:]]/).should be_nil
+ "\u{E001}".match(/[[:digit:]]/).should == nil
end
it "matches Unicode letter characters with [[:graph:]]" do
@@ -243,7 +243,7 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode control characters with [[:graph:]]" do
- "\u{16}".match(/[[:graph:]]/).should be_nil
+ "\u{16}".match(/[[:graph:]]/).should == nil
end
it "match Unicode format characters with [[:graph:]]" do
@@ -261,40 +261,40 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode uppercase letter characters with [[:lower:]]" do
- "\u{100}".match(/[[:lower:]]/).should be_nil
- "\u{130}".match(/[[:lower:]]/).should be_nil
- "\u{405}".match(/[[:lower:]]/).should be_nil
+ "\u{100}".match(/[[:lower:]]/).should == nil
+ "\u{130}".match(/[[:lower:]]/).should == nil
+ "\u{405}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode title-case characters with [[:lower:]]" do
- "\u{1F88}".match(/[[:lower:]]/).should be_nil
- "\u{1FAD}".match(/[[:lower:]]/).should be_nil
- "\u{01C5}".match(/[[:lower:]]/).should be_nil
+ "\u{1F88}".match(/[[:lower:]]/).should == nil
+ "\u{1FAD}".match(/[[:lower:]]/).should == nil
+ "\u{01C5}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode digits with [[:lower:]]" do
- "\u{0660}".match(/[[:lower:]]/).should be_nil
- "\u{FF12}".match(/[[:lower:]]/).should be_nil
+ "\u{0660}".match(/[[:lower:]]/).should == nil
+ "\u{FF12}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode marks with [[:lower:]]" do
- "\u{36F}".match(/[[:lower:]]/).should be_nil
+ "\u{36F}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:lower:]]" do
- "\u{3F}".match(/[[:lower:]]/).should be_nil
+ "\u{3F}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:lower:]]" do
- "\u{16}".match(/[[:lower:]]/).should be_nil
+ "\u{16}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:lower:]]" do
- "\u{2060}".match(/[[:lower:]]/).should be_nil
+ "\u{2060}".match(/[[:lower:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:lower:]]" do
- "\u{E001}".match(/[[:lower:]]/).should be_nil
+ "\u{E001}".match(/[[:lower:]]/).should == nil
end
it "matches Unicode lowercase letter characters with [[:print:]]" do
@@ -329,7 +329,7 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode control characters with [[:print:]]" do
- "\u{16}".match(/[[:print:]]/).should be_nil
+ "\u{16}".match(/[[:print:]]/).should == nil
end
it "match Unicode format characters with [[:print:]]" do
@@ -342,30 +342,30 @@ describe "Regexp with character classes" do
it "doesn't match Unicode lowercase letter characters with [[:punct:]]" do
- "\u{FF41}".match(/[[:punct:]]/).should be_nil
- "\u{1D484}".match(/[[:punct:]]/).should be_nil
- "\u{E8}".match(/[[:punct:]]/).should be_nil
+ "\u{FF41}".match(/[[:punct:]]/).should == nil
+ "\u{1D484}".match(/[[:punct:]]/).should == nil
+ "\u{E8}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode uppercase letter characters with [[:punct:]]" do
- "\u{100}".match(/[[:punct:]]/).should be_nil
- "\u{130}".match(/[[:punct:]]/).should be_nil
- "\u{405}".match(/[[:punct:]]/).should be_nil
+ "\u{100}".match(/[[:punct:]]/).should == nil
+ "\u{130}".match(/[[:punct:]]/).should == nil
+ "\u{405}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode title-case characters with [[:punct:]]" do
- "\u{1F88}".match(/[[:punct:]]/).should be_nil
- "\u{1FAD}".match(/[[:punct:]]/).should be_nil
- "\u{01C5}".match(/[[:punct:]]/).should be_nil
+ "\u{1F88}".match(/[[:punct:]]/).should == nil
+ "\u{1FAD}".match(/[[:punct:]]/).should == nil
+ "\u{01C5}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode digits with [[:punct:]]" do
- "\u{0660}".match(/[[:punct:]]/).should be_nil
- "\u{FF12}".match(/[[:punct:]]/).should be_nil
+ "\u{0660}".match(/[[:punct:]]/).should == nil
+ "\u{FF12}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode marks with [[:punct:]]" do
- "\u{36F}".match(/[[:punct:]]/).should be_nil
+ "\u{36F}".match(/[[:punct:]]/).should == nil
end
it "matches Unicode Pc characters with [[:punct:]]" do
@@ -398,38 +398,38 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode format characters with [[:punct:]]" do
- "\u{2060}".match(/[[:punct:]]/).should be_nil
+ "\u{2060}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:punct:]]" do
- "\u{E001}".match(/[[:punct:]]/).should be_nil
+ "\u{E001}".match(/[[:punct:]]/).should == nil
end
it "doesn't match Unicode lowercase letter characters with [[:space:]]" do
- "\u{FF41}".match(/[[:space:]]/).should be_nil
- "\u{1D484}".match(/[[:space:]]/).should be_nil
- "\u{E8}".match(/[[:space:]]/).should be_nil
+ "\u{FF41}".match(/[[:space:]]/).should == nil
+ "\u{1D484}".match(/[[:space:]]/).should == nil
+ "\u{E8}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode uppercase letter characters with [[:space:]]" do
- "\u{100}".match(/[[:space:]]/).should be_nil
- "\u{130}".match(/[[:space:]]/).should be_nil
- "\u{405}".match(/[[:space:]]/).should be_nil
+ "\u{100}".match(/[[:space:]]/).should == nil
+ "\u{130}".match(/[[:space:]]/).should == nil
+ "\u{405}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode title-case characters with [[:space:]]" do
- "\u{1F88}".match(/[[:space:]]/).should be_nil
- "\u{1FAD}".match(/[[:space:]]/).should be_nil
- "\u{01C5}".match(/[[:space:]]/).should be_nil
+ "\u{1F88}".match(/[[:space:]]/).should == nil
+ "\u{1FAD}".match(/[[:space:]]/).should == nil
+ "\u{01C5}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode digits with [[:space:]]" do
- "\u{0660}".match(/[[:space:]]/).should be_nil
- "\u{FF12}".match(/[[:space:]]/).should be_nil
+ "\u{0660}".match(/[[:space:]]/).should == nil
+ "\u{FF12}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode marks with [[:space:]]" do
- "\u{36F}".match(/[[:space:]]/).should be_nil
+ "\u{36F}".match(/[[:space:]]/).should == nil
end
it "matches Unicode Zs characters with [[:space:]]" do
@@ -445,17 +445,17 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode format characters with [[:space:]]" do
- "\u{2060}".match(/[[:space:]]/).should be_nil
+ "\u{2060}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:space:]]" do
- "\u{E001}".match(/[[:space:]]/).should be_nil
+ "\u{E001}".match(/[[:space:]]/).should == nil
end
it "doesn't match Unicode lowercase characters with [[:upper:]]" do
- "\u{FF41}".match(/[[:upper:]]/).should be_nil
- "\u{1D484}".match(/[[:upper:]]/).should be_nil
- "\u{E8}".match(/[[:upper:]]/).should be_nil
+ "\u{FF41}".match(/[[:upper:]]/).should == nil
+ "\u{1D484}".match(/[[:upper:]]/).should == nil
+ "\u{E8}".match(/[[:upper:]]/).should == nil
end
it "matches Unicode uppercase characters with [[:upper:]]" do
@@ -465,40 +465,40 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode title-case characters with [[:upper:]]" do
- "\u{1F88}".match(/[[:upper:]]/).should be_nil
- "\u{1FAD}".match(/[[:upper:]]/).should be_nil
- "\u{01C5}".match(/[[:upper:]]/).should be_nil
+ "\u{1F88}".match(/[[:upper:]]/).should == nil
+ "\u{1FAD}".match(/[[:upper:]]/).should == nil
+ "\u{01C5}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode digits with [[:upper:]]" do
- "\u{0660}".match(/[[:upper:]]/).should be_nil
- "\u{FF12}".match(/[[:upper:]]/).should be_nil
+ "\u{0660}".match(/[[:upper:]]/).should == nil
+ "\u{FF12}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode marks with [[:upper:]]" do
- "\u{36F}".match(/[[:upper:]]/).should be_nil
+ "\u{36F}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:upper:]]" do
- "\u{3F}".match(/[[:upper:]]/).should be_nil
+ "\u{3F}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:upper:]]" do
- "\u{16}".match(/[[:upper:]]/).should be_nil
+ "\u{16}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:upper:]]" do
- "\u{2060}".match(/[[:upper:]]/).should be_nil
+ "\u{2060}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:upper:]]" do
- "\u{E001}".match(/[[:upper:]]/).should be_nil
+ "\u{E001}".match(/[[:upper:]]/).should == nil
end
it "doesn't match Unicode letter characters [^a-fA-F] with [[:xdigit:]]" do
- "à".match(/[[:xdigit:]]/).should be_nil
- "g".match(/[[:xdigit:]]/).should be_nil
- "X".match(/[[:xdigit:]]/).should be_nil
+ "à".match(/[[:xdigit:]]/).should == nil
+ "g".match(/[[:xdigit:]]/).should == nil
+ "X".match(/[[:xdigit:]]/).should == nil
end
it "matches Unicode letter characters [a-fA-F] with [[:xdigit:]]" do
@@ -507,28 +507,28 @@ describe "Regexp with character classes" do
end
it "doesn't match Unicode digits [^0-9] with [[:xdigit:]]" do
- "\u{0660}".match(/[[:xdigit:]]/).should be_nil
- "\u{FF12}".match(/[[:xdigit:]]/).should be_nil
+ "\u{0660}".match(/[[:xdigit:]]/).should == nil
+ "\u{FF12}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode marks with [[:xdigit:]]" do
- "\u{36F}".match(/[[:xdigit:]]/).should be_nil
+ "\u{36F}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:xdigit:]]" do
- "\u{3F}".match(/[[:xdigit:]]/).should be_nil
+ "\u{3F}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:xdigit:]]" do
- "\u{16}".match(/[[:xdigit:]]/).should be_nil
+ "\u{16}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:xdigit:]]" do
- "\u{2060}".match(/[[:xdigit:]]/).should be_nil
+ "\u{2060}".match(/[[:xdigit:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:xdigit:]]" do
- "\u{E001}".match(/[[:xdigit:]]/).should be_nil
+ "\u{E001}".match(/[[:xdigit:]]/).should == nil
end
it "matches Unicode lowercase characters with [[:word:]]" do
@@ -562,23 +562,30 @@ describe "Regexp with character classes" do
"\u{16EE}".match(/[[:word:]]/).to_a.should == ["\u{16EE}"]
end
+ ruby_bug "#19417", ""..."3.4.6" do
+ it "matches Unicode join control characters with [[:word:]]" do
+ "\u{200C}".match(/[[:word:]]/).to_a.should == ["\u{200C}"]
+ "\u{200D}".match(/[[:word:]]/).to_a.should == ["\u{200D}"]
+ end
+ end
+
it "doesn't match Unicode No characters with [[:word:]]" do
- "\u{17F0}".match(/[[:word:]]/).should be_nil
+ "\u{17F0}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode punctuation characters with [[:word:]]" do
- "\u{3F}".match(/[[:word:]]/).should be_nil
+ "\u{3F}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode control characters with [[:word:]]" do
- "\u{16}".match(/[[:word:]]/).should be_nil
+ "\u{16}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode format characters with [[:word:]]" do
- "\u{2060}".match(/[[:word:]]/).should be_nil
+ "\u{2060}".match(/[[:word:]]/).should == nil
end
it "doesn't match Unicode private-use characters with [[:word:]]" do
- "\u{E001}".match(/[[:word:]]/).should be_nil
+ "\u{E001}".match(/[[:word:]]/).should == nil
end
it "matches unicode named character properties" do
@@ -610,12 +617,12 @@ describe "Regexp with character classes" do
end
it "supports negated property condition" do
- "a".match(eval("/\P{L}/")).should be_nil
- "1".match(eval("/\P{N}/")).should be_nil
+ "a".match(eval("/\P{L}/")).should == nil
+ "1".match(eval("/\P{N}/")).should == nil
end
it "raises a RegexpError for an unterminated unicode property" do
- -> { Regexp.new('\p{') }.should raise_error(RegexpError)
+ -> { Regexp.new('\p{') }.should.raise(RegexpError)
end
it "supports \\X (unicode 9.0 with UTR #51 workarounds)" do
diff --git a/spec/ruby/language/regexp/encoding_spec.rb b/spec/ruby/language/regexp/encoding_spec.rb
index 0571b2d3cf..81e845af0c 100644
--- a/spec/ruby/language/regexp/encoding_spec.rb
+++ b/spec/ruby/language/regexp/encoding_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative '../fixtures/classes'
@@ -39,7 +39,11 @@ describe "Regexps with encoding modifiers" do
end
it "warns when using /n with a match string with non-ASCII characters and an encoding other than ASCII-8BIT" do
- -> { /./n.match("\303\251".dup.force_encoding('utf-8')) }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
+ -> {
+ eval <<~RUBY
+ /./n.match("\303\251".dup.force_encoding('utf-8'))
+ RUBY
+ }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
end
it 'uses US-ASCII as /n encoding if all chars are 7-bit' do
@@ -110,28 +114,28 @@ describe "Regexps with encoding modifiers" do
end
it "raises Encoding::CompatibilityError when trying match against different encodings" do
- -> { /\A[[:space:]]*\z/.match(" ".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { /\A[[:space:]]*\z/.match(" ".encode("UTF-16LE")) }.should.raise(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when trying match? against different encodings" do
- -> { /\A[[:space:]]*\z/.match?(" ".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { /\A[[:space:]]*\z/.match?(" ".encode("UTF-16LE")) }.should.raise(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when trying =~ against different encodings" do
- -> { /\A[[:space:]]*\z/ =~ " ".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
+ -> { /\A[[:space:]]*\z/ =~ " ".encode("UTF-16LE") }.should.raise(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when the regexp has a fixed, non-ASCII-compatible encoding" do
- -> { Regexp.new("".dup.force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should raise_error(Encoding::CompatibilityError)
+ -> { Regexp.new("".dup.force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should.raise(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when the regexp has a fixed encoding and the match string has non-ASCII characters" do
- -> { Regexp.new("".dup.force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".dup.force_encoding('UTF-8') }.should raise_error(Encoding::CompatibilityError)
+ -> { Regexp.new("".dup.force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".dup.force_encoding('UTF-8') }.should.raise(Encoding::CompatibilityError)
end
it "raises ArgumentError when trying to match a broken String" do
s = "\x80".dup.force_encoding('UTF-8')
- -> { s =~ /./ }.should raise_error(ArgumentError, "invalid byte sequence in UTF-8")
+ -> { s =~ /./ }.should.raise(ArgumentError, "invalid byte sequence in UTF-8")
end
it "computes the Regexp Encoding for each interpolated Regexp instance" do
diff --git a/spec/ruby/language/regexp/escapes_spec.rb b/spec/ruby/language/regexp/escapes_spec.rb
index 16a4d8c23b..4a0e611540 100644
--- a/spec/ruby/language/regexp/escapes_spec.rb
+++ b/spec/ruby/language/regexp/escapes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative '../fixtures/classes'
@@ -116,11 +116,11 @@ describe "Regexps with escape characters" do
it "supports \\x (hex characters)" do
/\xA/.match("\nxyz").to_a.should == ["\n"]
/\x0A/.match("\n").to_a.should == ["\n"]
- /\xAA/.match("\nA").should be_nil
+ /\xAA/.match("\nA").should == nil
/\x0AA/.match("\nA").to_a.should == ["\nA"]
/\xAG/.match("\nG").to_a.should == ["\nG"]
# Non-matches
- -> { eval('/\xG/') }.should raise_error(SyntaxError)
+ -> { eval('/\xG/') }.should.raise(SyntaxError)
# \x{7HHHHHHH} wide hexadecimal char (character code point value)
end
@@ -136,14 +136,14 @@ describe "Regexps with escape characters" do
/\c,\cL\cl/.match("\f\f\f").to_a.should == ["\f\f\f"]
/\c-\cM\cm/.match("\r\r\r").to_a.should == ["\r\r\r"]
- /\cJ/.match("\r").should be_nil
+ /\cJ/.match("\r").should == nil
# Parsing precedence
/\cJ+/.match("\n\n").to_a.should == ["\n\n"] # Quantifiers apply to entire escape sequence
/\\cJ/.match("\\cJ").to_a.should == ["\\cJ"]
- -> { eval('/[abc\x]/') }.should raise_error(SyntaxError) # \x is treated as a escape sequence even inside a character class
+ -> { eval('/[abc\x]/') }.should.raise(SyntaxError) # \x is treated as a escape sequence even inside a character class
# Syntax error
- -> { eval('/\c/') }.should raise_error(SyntaxError)
+ -> { eval('/\c/') }.should.raise(SyntaxError)
# \cx control char (character code point value)
# \C-x control char (character code point value)
diff --git a/spec/ruby/language/regexp/grouping_spec.rb b/spec/ruby/language/regexp/grouping_spec.rb
index 313858f714..80ad7460da 100644
--- a/spec/ruby/language/regexp/grouping_spec.rb
+++ b/spec/ruby/language/regexp/grouping_spec.rb
@@ -12,7 +12,7 @@ describe "Regexps with grouping" do
end
it "raises a SyntaxError when parentheses aren't balanced" do
- -> { eval "/(hay(st)ack/" }.should raise_error(SyntaxError)
+ -> { eval "/(hay(st)ack/" }.should.raise(SyntaxError)
end
it "supports (?: ) (non-capturing group)" do
@@ -22,8 +22,8 @@ describe "Regexps with grouping" do
end
it "group names cannot start with digits or minus" do
- -> { Regexp.new("(?<1a>a)") }.should raise_error(RegexpError)
- -> { Regexp.new("(?<-a>a)") }.should raise_error(RegexpError)
+ -> { Regexp.new("(?<1a>a)") }.should.raise(RegexpError)
+ -> { Regexp.new("(?<-a>a)") }.should.raise(RegexpError)
end
it "ignore capture groups in line comments" do
diff --git a/spec/ruby/language/regexp/interpolation_spec.rb b/spec/ruby/language/regexp/interpolation_spec.rb
index 6951fd38ca..f771d0a395 100644
--- a/spec/ruby/language/regexp/interpolation_spec.rb
+++ b/spec/ruby/language/regexp/interpolation_spec.rb
@@ -36,14 +36,14 @@ describe "Regexps with interpolation" do
it "gives precedence to escape sequences over substitution" do
str = "J"
- /\c#{str}/.to_s.should include('{str}')
+ /\c#{str}/.to_s.should.include?('{str}')
end
it "throws RegexpError for malformed interpolation" do
s = ""
- -> { /(#{s}/ }.should raise_error(RegexpError)
+ -> { /(#{s}/ }.should.raise(RegexpError)
s = "("
- -> { /#{s}/ }.should raise_error(RegexpError)
+ -> { /#{s}/ }.should.raise(RegexpError)
end
it "allows interpolation in extended mode" do
diff --git a/spec/ruby/language/regexp/modifiers_spec.rb b/spec/ruby/language/regexp/modifiers_spec.rb
index 2f5522bc8a..c96fbfa983 100644
--- a/spec/ruby/language/regexp/modifiers_spec.rb
+++ b/spec/ruby/language/regexp/modifiers_spec.rb
@@ -8,7 +8,7 @@ describe "Regexps with modifiers" do
it "supports /m (multiline)" do
/foo.bar/m.match("foo\nbar").to_a.should == ["foo\nbar"]
- /foo.bar/.match("foo\nbar").should be_nil
+ /foo.bar/.match("foo\nbar").should == nil
end
it "supports /x (extended syntax)" do
@@ -36,7 +36,7 @@ describe "Regexps with modifiers" do
/foo/imox.match("foo").to_a.should == ["foo"]
/foo/imoximox.match("foo").to_a.should == ["foo"]
- -> { eval('/foo/a') }.should raise_error(SyntaxError)
+ -> { eval('/foo/a') }.should.raise(SyntaxError)
end
it "supports (?~) (absent operator)" do
@@ -46,57 +46,57 @@ describe "Regexps with modifiers" do
it "supports (?imx-imx) (inline modifiers)" do
/(?i)foo/.match("FOO").to_a.should == ["FOO"]
- /foo(?i)/.match("FOO").should be_nil
+ /foo(?i)/.match("FOO").should == nil
# Interaction with /i
- /(?-i)foo/i.match("FOO").should be_nil
+ /(?-i)foo/i.match("FOO").should == nil
/foo(?-i)/i.match("FOO").to_a.should == ["FOO"]
# Multiple uses
/foo (?i)bar (?-i)baz/.match("foo BAR baz").to_a.should == ["foo BAR baz"]
- /foo (?i)bar (?-i)baz/.match("foo BAR BAZ").should be_nil
+ /foo (?i)bar (?-i)baz/.match("foo BAR BAZ").should == nil
/(?m)./.match("\n").to_a.should == ["\n"]
- /.(?m)/.match("\n").should be_nil
+ /.(?m)/.match("\n").should == nil
# Interaction with /m
- /(?-m)./m.match("\n").should be_nil
+ /(?-m)./m.match("\n").should == nil
/.(?-m)/m.match("\n").to_a.should == ["\n"]
# Multiple uses
/. (?m). (?-m)./.match(". \n .").to_a.should == [". \n ."]
- /. (?m). (?-m)./.match(". \n \n").should be_nil
+ /. (?m). (?-m)./.match(". \n \n").should == nil
/(?x) foo /.match("foo").to_a.should == ["foo"]
- / foo (?x)/.match("foo").should be_nil
+ / foo (?x)/.match("foo").should == nil
# Interaction with /x
- /(?-x) foo /x.match("foo").should be_nil
+ /(?-x) foo /x.match("foo").should == nil
/ foo (?-x)/x.match("foo").to_a.should == ["foo"]
# Multiple uses
/( foo )(?x)( bar )(?-x)( baz )/.match(" foo bar baz ").to_a.should == [" foo bar baz ", " foo ", "bar", " baz "]
- /( foo )(?x)( bar )(?-x)( baz )/.match(" foo barbaz").should be_nil
+ /( foo )(?x)( bar )(?-x)( baz )/.match(" foo barbaz").should == nil
# Parsing
- /(?i-i)foo/.match("FOO").should be_nil
+ /(?i-i)foo/.match("FOO").should == nil
/(?ii)foo/.match("FOO").to_a.should == ["FOO"]
/(?-)foo/.match("foo").to_a.should == ["foo"]
- -> { eval('/(?o)/') }.should raise_error(SyntaxError)
+ -> { eval('/(?o)/') }.should.raise(SyntaxError)
end
it "supports (?imx-imx:expr) (scoped inline modifiers)" do
/foo (?i:bar) baz/.match("foo BAR baz").to_a.should == ["foo BAR baz"]
- /foo (?i:bar) baz/.match("foo BAR BAZ").should be_nil
- /foo (?-i:bar) baz/i.match("foo BAR BAZ").should be_nil
+ /foo (?i:bar) baz/.match("foo BAR BAZ").should == nil
+ /foo (?-i:bar) baz/i.match("foo BAR BAZ").should == nil
/. (?m:.) ./.match(". \n .").to_a.should == [". \n ."]
- /. (?m:.) ./.match(". \n \n").should be_nil
- /. (?-m:.) ./m.match("\n \n \n").should be_nil
+ /. (?m:.) ./.match(". \n \n").should == nil
+ /. (?-m:.) ./m.match("\n \n \n").should == nil
/( foo )(?x: bar )( baz )/.match(" foo bar baz ").to_a.should == [" foo bar baz ", " foo ", " baz "]
- /( foo )(?x: bar )( baz )/.match(" foo barbaz").should be_nil
+ /( foo )(?x: bar )( baz )/.match(" foo barbaz").should == nil
/( foo )(?-x: bar )( baz )/x.match("foo bar baz").to_a.should == ["foo bar baz", "foo", "baz"]
# Parsing
- /(?i-i:foo)/.match("FOO").should be_nil
+ /(?i-i:foo)/.match("FOO").should == nil
/(?ii:foo)/.match("FOO").to_a.should == ["FOO"]
/(?-:)foo/.match("foo").to_a.should == ["foo"]
- -> { eval('/(?o:)/') }.should raise_error(SyntaxError)
+ -> { eval('/(?o:)/') }.should.raise(SyntaxError)
end
it "supports . with /m" do
diff --git a/spec/ruby/language/regexp/repetition_spec.rb b/spec/ruby/language/regexp/repetition_spec.rb
index d76619688f..f24323de5c 100644
--- a/spec/ruby/language/regexp/repetition_spec.rb
+++ b/spec/ruby/language/regexp/repetition_spec.rb
@@ -15,7 +15,7 @@ describe "Regexps with repetition" do
it "supports + (1 or more of previous subexpression)" do
/a+/.match("aaa").to_a.should == ["aaa"]
- /a+/.match("bbb").should be_nil
+ /a+/.match("bbb").should == nil
/<.+>/.match("<a>foo</a>").to_a.should == ["<a>foo</a>"] # it is greedy
end
diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb
index 0cd9584549..1452b01935 100644
--- a/spec/ruby/language/regexp_spec.rb
+++ b/spec/ruby/language/regexp_spec.rb
@@ -15,7 +15,7 @@ describe "Literal Regexps" do
end
it "yields a Regexp" do
- /Hello/.should be_kind_of(Regexp)
+ /Hello/.should.is_a?(Regexp)
end
it "is frozen" do
@@ -27,11 +27,11 @@ describe "Literal Regexps" do
2.times do |i|
rs << /foo/
end
- rs[0].should equal(rs[1])
+ rs[0].should.equal?(rs[1])
end
it "throws SyntaxError for malformed literals" do
- -> { eval('/(/') }.should raise_error(SyntaxError)
+ -> { eval('/(/') }.should.raise(SyntaxError)
end
#############################################################################
@@ -58,7 +58,7 @@ describe "Literal Regexps" do
it "disallows first part of paired delimiters to be used as non-paired delimiters" do
LanguageSpecs.paired_delimiters.each do |p0, p1|
- -> { eval("%r#{p0} foo #{p0}") }.should raise_error(SyntaxError)
+ -> { eval("%r#{p0} foo #{p0}") }.should.raise(SyntaxError)
end
end
@@ -69,11 +69,11 @@ describe "Literal Regexps" do
end
it "disallows alphabets as non-paired delimiter with %r" do
- -> { eval('%ra foo a') }.should raise_error(SyntaxError)
+ -> { eval('%ra foo a') }.should.raise(SyntaxError)
end
it "disallows spaces after %r and delimiter" do
- -> { eval('%r !foo!') }.should raise_error(SyntaxError)
+ -> { eval('%r !foo!') }.should.raise(SyntaxError)
end
it "allows unescaped / to be used with %r" do
@@ -89,8 +89,8 @@ describe "Literal Regexps" do
# Basic matching
/./.match("foo").to_a.should == ["f"]
# Basic non-matching
- /./.match("").should be_nil
- /./.match("\n").should be_nil
+ /./.match("").should == nil
+ /./.match("\n").should == nil
/./.match("\0").to_a.should == ["\0"]
end
@@ -100,7 +100,7 @@ describe "Literal Regexps" do
it "supports (?> ) (embedded subexpression)" do
/(?>foo)(?>bar)/.match("foobar").to_a.should == ["foobar"]
- /(?>foo*)obar/.match("foooooooobar").should be_nil # it is possessive
+ /(?>foo*)obar/.match("foooooooobar").should == nil # it is possessive
end
it "supports (?# )" do
@@ -112,7 +112,7 @@ describe "Literal Regexps" do
/foo.(?<=\d)/.match("fooA foo1").to_a.should == ["foo1"]
end
- ruby_bug "#13671", ""..."3.6" do # https://bugs.ruby-lang.org/issues/13671
+ ruby_bug "#13671", ""..."4.0" do # https://bugs.ruby-lang.org/issues/13671
it "handles a lookbehind with ss characters" do
r = Regexp.new("(?<!dss)", Regexp::IGNORECASE)
r.should =~ "✨"
@@ -135,9 +135,9 @@ describe "Literal Regexps" do
it "supports possessive quantifiers" do
/fooA++bar/.match("fooAAAbar").to_a.should == ["fooAAAbar"]
- /fooA++Abar/.match("fooAAAbar").should be_nil
- /fooA?+Abar/.match("fooAAAbar").should be_nil
- /fooA*+Abar/.match("fooAAAbar").should be_nil
+ /fooA++Abar/.match("fooAAAbar").should == nil
+ /fooA?+Abar/.match("fooAAAbar").should == nil
+ /fooA*+Abar/.match("fooAAAbar").should == nil
end
it "supports conditional regular expressions with positional capture groups" do
diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb
index 79571d689f..cf16d8f6f8 100644
--- a/spec/ruby/language/rescue_spec.rb
+++ b/spec/ruby/language/rescue_spec.rb
@@ -59,7 +59,7 @@ describe "The rescue keyword" do
rescue SpecificExampleException => target&.captured_error
:caught
end.should == :caught
- target.should be_nil
+ target.should == nil
end
it 'using a setter method' do
@@ -136,10 +136,14 @@ describe "The rescue keyword" do
it 'captures successfully at the top-level' do
ScratchPad.record []
+ loaded_features = $".dup
+ begin
+ require_relative 'fixtures/rescue/top_level'
- require_relative 'fixtures/rescue/top_level'
-
- ScratchPad.recorded.should == ["message"]
+ ScratchPad.recorded.should == ["message"]
+ ensure
+ $".replace loaded_features
+ end
end
end
@@ -182,7 +186,7 @@ describe "The rescue keyword" do
rescue *exception_list
caught_it = true
end
- caught_it.should be_true
+ caught_it.should == true
caught = []
[->{raise ArbitraryException}, ->{raise SpecificExampleException}].each do |block|
begin
@@ -193,7 +197,7 @@ describe "The rescue keyword" do
end
caught.size.should == 2
exception_list.each do |exception_class|
- caught.map{|e| e.class}.should include(exception_class)
+ caught.map{|e| e.class}.should.include?(exception_class)
end
end
@@ -206,7 +210,7 @@ describe "The rescue keyword" do
rescue *exceptions
caught_it = true
end
- caught_it.should be_true
+ caught_it.should == true
end
it "can combine a splatted list of exceptions with a literal list of exceptions" do
@@ -216,7 +220,7 @@ describe "The rescue keyword" do
rescue ArbitraryException, *exception_list
caught_it = true
end
- caught_it.should be_true
+ caught_it.should == true
caught = []
[->{raise ArbitraryException}, ->{raise SpecificExampleException}].each do |block|
begin
@@ -227,7 +231,7 @@ describe "The rescue keyword" do
end
caught.size.should == 2
exception_list.each do |exception_class|
- caught.map{|e| e.class}.should include(exception_class)
+ caught.map{|e| e.class}.should.include?(exception_class)
end
end
@@ -237,7 +241,7 @@ describe "The rescue keyword" do
raise OtherCustomException, "not rescued!"
rescue *exception_list
end
- end.should raise_error(OtherCustomException)
+ end.should.raise(OtherCustomException)
end
it "can rescue different types of exceptions in different ways" do
@@ -341,7 +345,7 @@ describe "The rescue keyword" do
ScratchPad << :else
end
ruby
- }.should raise_error(SyntaxError, /else without rescue is useless/)
+ }.should.raise(SyntaxError, /else without rescue is useless/)
end
it "will not execute an else block if an exception was raised" do
@@ -409,7 +413,7 @@ describe "The rescue keyword" do
ScratchPad << :two
raise SpecificExampleException, "an error from else"
end
- end.should raise_error(SpecificExampleException)
+ end.should.raise(SpecificExampleException)
ScratchPad.recorded.should == [:one, :two]
end
@@ -441,7 +445,7 @@ describe "The rescue keyword" do
rescue
ScratchPad << :caught
end
- }.should raise_error(exception.class)
+ }.should.raise(exception.class)
end
ScratchPad.recorded.should == []
end
@@ -472,7 +476,7 @@ describe "The rescue keyword" do
raise "error"
rescue rescuer
end
- }.should raise_error(TypeError) { |e|
+ }.should.raise(TypeError) { |e|
e.message.should =~ /class or module required for rescue clause/
}
end
@@ -484,7 +488,7 @@ describe "The rescue keyword" do
raise "error"
rescue *rescuer
end
- }.should raise_error(TypeError) { |e|
+ }.should.raise(TypeError) { |e|
e.message.should =~ /class or module required for rescue clause/
}
end
@@ -504,7 +508,7 @@ describe "The rescue keyword" do
raise "from block"
rescue (raise "from rescue expression")
end
- }.should raise_error(RuntimeError, "from rescue expression") { |e|
+ }.should.raise(RuntimeError, "from rescue expression") { |e|
e.cause.message.should == "from block"
}
end
@@ -538,7 +542,7 @@ describe "The rescue keyword" do
:caught
}
ruby
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "allows rescue in 'do end' block" do
@@ -559,7 +563,7 @@ describe "The rescue keyword" do
end
it "requires the 'rescue' in method arguments to be wrapped in parens" do
- -> { eval '1.+(1 rescue 1)' }.should raise_error(SyntaxError)
+ -> { eval '1.+(1 rescue 1)' }.should.raise(SyntaxError)
eval('1.+((1 rescue 1))').should == 2
end
@@ -589,7 +593,7 @@ describe "The rescue keyword" do
eval <<-ruby
a = 1 rescue RuntimeError 2
ruby
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "rescues only StandardError and its subclasses" do
@@ -598,7 +602,7 @@ describe "The rescue keyword" do
-> {
a = raise(Exception) rescue 1
- }.should raise_error(Exception)
+ }.should.raise(Exception)
end
it "rescues with multiple assignment" do
diff --git a/spec/ruby/language/reserved_keywords.rb b/spec/ruby/language/reserved_keywords.rb
new file mode 100644
index 0000000000..bd1a55feec
--- /dev/null
+++ b/spec/ruby/language/reserved_keywords.rb
@@ -0,0 +1,149 @@
+require_relative '../spec_helper'
+
+describe "Ruby's reserved keywords" do
+ # Copied from https://github.com/ruby/ruby/blob/master/defs/keywords
+ keywords = %w[
+ alias
+ and
+ begin
+ BEGIN
+ break
+ case
+ class
+ def
+ defined?
+ do
+ else
+ elsif
+ end
+ END
+ ensure
+ false
+ for
+ if
+ in
+ module
+ next
+ nil
+ not
+ or
+ redo
+ rescue
+ retry
+ return
+ self
+ super
+ then
+ true
+ undef
+ unless
+ until
+ when
+ while
+ yield
+ __ENCODING__
+ __FILE__
+ __LINE__
+ ]
+
+ keywords.each do |name|
+ describe "keyword '#{name}'" do
+ it "can't be used as local variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ #{name} = :local_variable
+ RUBY
+ end
+
+ if name == "defined?"
+ it "can't be used as an instance variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ @#{name} = :instance_variable
+ RUBY
+ end
+
+ it "can't be used as a class variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ class C
+ @@#{name} = :class_variable
+ end
+ RUBY
+ end
+
+ it "can't be used as a global variable name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ $#{name} = :global_variable
+ RUBY
+ end
+ else
+ it "can be used as an instance variable name" do
+ result = eval <<~RUBY
+ @#{name} = :instance_variable
+ @#{name}
+ RUBY
+
+ result.should == :instance_variable
+ end
+
+ it "can be used as a class variable name" do
+ result = eval <<~RUBY
+ class C
+ @@#{name} = :class_variable
+ @@#{name}
+ end
+ RUBY
+
+ result.should == :class_variable
+ end
+
+ it "can be used as a global variable name" do
+ result = eval <<~RUBY
+ $#{name} = :global_variable
+ $#{name}
+ RUBY
+
+ result.should == :global_variable
+ end
+ end
+
+ it "can't be used as a positional parameter name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ def x(#{name}); end
+ RUBY
+ end
+
+ invalid_kw_param_names = ["BEGIN","END","defined?"]
+
+ if invalid_kw_param_names.include?(name)
+ it "can't be used a keyword parameter name" do
+ -> { eval(<<~RUBY) }.should.raise(SyntaxError)
+ def m(#{name}:); end
+ RUBY
+ end
+ else
+ it "can be used a keyword parameter name" do
+ result = instance_eval <<~RUBY
+ def m(#{name}:)
+ binding.local_variable_get(:#{name})
+ end
+
+ m(#{name}: :argument)
+ RUBY
+
+ result.should == :argument
+ end
+ end
+
+ it "can be used as a method name" do
+ result = instance_eval <<~RUBY
+ def #{name}
+ :method_return_value
+ end
+
+ send(:#{name})
+ RUBY
+
+ result.should == :method_return_value
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/retry_spec.rb b/spec/ruby/language/retry_spec.rb
index 669d5f0ff5..39e58b7b5d 100644
--- a/spec/ruby/language/retry_spec.rb
+++ b/spec/ruby/language/retry_spec.rb
@@ -32,10 +32,10 @@ describe "The retry statement" do
end
it "raises a SyntaxError when used outside of a rescue statement" do
- -> { eval 'retry' }.should raise_error(SyntaxError)
- -> { eval 'begin; retry; end' }.should raise_error(SyntaxError)
- -> { eval 'def m; retry; end' }.should raise_error(SyntaxError)
- -> { eval 'module RetrySpecs; retry; end' }.should raise_error(SyntaxError)
+ -> { eval 'retry' }.should.raise(SyntaxError)
+ -> { eval 'begin; retry; end' }.should.raise(SyntaxError)
+ -> { eval 'def m; retry; end' }.should.raise(SyntaxError)
+ -> { eval 'module RetrySpecs; retry; end' }.should.raise(SyntaxError)
end
end
diff --git a/spec/ruby/language/return_spec.rb b/spec/ruby/language/return_spec.rb
index a62ed1242d..36a3cba4d7 100644
--- a/spec/ruby/language/return_spec.rb
+++ b/spec/ruby/language/return_spec.rb
@@ -19,7 +19,7 @@ describe "The return keyword" do
it "returns nil by default" do
def r; return; end
- r().should be_nil
+ r().should == nil
end
describe "in a Thread" do
@@ -31,7 +31,7 @@ describe "The return keyword" do
e
end
}
- t.value.should be_an_instance_of(LocalJumpError)
+ t.value.should.instance_of?(LocalJumpError)
end
end
@@ -176,11 +176,11 @@ describe "The return keyword" do
end
it "causes lambda to return nil if invoked without any arguments" do
- -> { return; 456 }.call.should be_nil
+ -> { return; 456 }.call.should == nil
end
it "causes lambda to return nil if invoked with an empty expression" do
- -> { return (); 456 }.call.should be_nil
+ -> { return (); 456 }.call.should == nil
end
it "causes lambda to return the value passed to return" do
@@ -229,7 +229,7 @@ describe "The return keyword" do
def f
1.times { 1.times {return true}; false}; false
end
- f.should be_true
+ f.should == true
end
end
@@ -417,7 +417,7 @@ describe "The return keyword" do
end
END_OF_CODE
- -> { load @filename }.should raise_error(SyntaxError)
+ -> { load @filename }.should.raise(SyntaxError)
end
end
@@ -431,7 +431,7 @@ describe "The return keyword" do
end
END_OF_CODE
- -> { load @filename }.should raise_error(LocalJumpError)
+ -> { load @filename }.should.raise(LocalJumpError)
end
end
diff --git a/spec/ruby/language/safe_navigator_spec.rb b/spec/ruby/language/safe_navigator_spec.rb
index b1e28c3963..e8b429631d 100644
--- a/spec/ruby/language/safe_navigator_spec.rb
+++ b/spec/ruby/language/safe_navigator_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
describe "Safe navigator" do
it "requires a method name to be provided" do
- -> { eval("obj&. {}") }.should raise_error(SyntaxError)
+ -> { eval("obj&. {}") }.should.raise(SyntaxError)
end
context "when context is nil" do
@@ -26,7 +26,7 @@ describe "Safe navigator" do
it "calls the method" do
false&.to_s.should == "false"
- -> { false&.unknown }.should raise_error(NoMethodError)
+ -> { false&.unknown }.should.raise(NoMethodError)
end
end
@@ -34,7 +34,7 @@ describe "Safe navigator" do
it "calls the method" do
1&.to_s.should == "1"
- -> { 1&.unknown }.should raise_error(NoMethodError)
+ -> { 1&.unknown }.should.raise(NoMethodError)
end
end
@@ -140,7 +140,7 @@ describe "Safe navigator" do
-> {
obj&.foo += 3
- }.should raise_error(NoMethodError) { |e|
+ }.should.raise(NoMethodError) { |e|
e.name.should == :+
}
end
diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb
index aaccdf0998..f56a77d529 100644
--- a/spec/ruby/language/send_spec.rb
+++ b/spec/ruby/language/send_spec.rb
@@ -22,7 +22,7 @@ describe "Invoking a method" do
it "raises ArgumentError if the method has a positive arity" do
-> {
specs.fooM1
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -38,7 +38,7 @@ describe "Invoking a method" do
it "raises ArgumentError if the methods arity doesn't match" do
-> {
specs.fooM1(1,2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -54,7 +54,7 @@ describe "Invoking a method" do
it "raises ArgumentError if extra arguments are passed" do
-> {
specs.fooM0O1(2,3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -66,13 +66,13 @@ describe "Invoking a method" do
it "raises an ArgumentError if there are no values for the mandatory args" do
-> {
specs.fooM1O1
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError if too many values are passed" do
-> {
specs.fooM1O1(1,2,3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -94,7 +94,7 @@ describe "Invoking a method" do
it "with a block converts the block to a Proc" do
prc = specs.makeproc { "hello" }
- prc.should be_kind_of(Proc)
+ prc.should.is_a?(Proc)
prc.call.should == "hello"
end
@@ -106,10 +106,28 @@ describe "Invoking a method" do
specs.yield_now(&o).should == :from_to_proc
end
+ ruby_version_is "4.0" do
+ it "raises TypeError if 'to_proc' doesn't return a Proc" do
+ o = LangSendSpecs::RawToProc.new(42)
+
+ -> {
+ specs.makeproc(&o)
+ }.should raise_consistent_error(TypeError, "can't convert LangSendSpecs::RawToProc into Proc (LangSendSpecs::RawToProc#to_proc gives Integer)")
+ end
+
+ it "raises TypeError if block object isn't a Proc and doesn't respond to `to_proc`" do
+ o = Object.new
+
+ -> {
+ specs.makeproc(&o)
+ }.should.raise(TypeError, "no implicit conversion of Object into Proc")
+ end
+ end
+
it "raises a SyntaxError with both a literal block and an object as block" do
-> {
eval "specs.oneb(10, &l){ 42 }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "with same names as existing variables is ok" do
@@ -194,21 +212,42 @@ describe "Invoking a method" do
o.args.should == [1,2]
end
- it "raises NameError if invoked as a vcall" do
- -> { no_such_method }.should raise_error NameError
+ describe "if invoked as a vcall" do
+ it "raises NameError" do
+ -> { no_such_method }.should.raise NameError
+ end
+
+ it "raises NameError with $! as a cause" do
+ begin
+ raise RuntimeError.new
+ rescue => cause
+ -> { no_such_method }.should.raise(NameError, cause:)
+ end
+ end
end
it "should omit the method_missing call from the backtrace for NameError" do
- -> { no_such_method }.should raise_error { |e| e.backtrace.first.should_not include("method_missing") }
+ -> { no_such_method }.should.raise { |e| e.backtrace.first.should_not.include?("method_missing") }
end
- it "raises NoMethodError if invoked as an unambiguous method call" do
- -> { no_such_method() }.should raise_error NoMethodError
- -> { no_such_method(1,2,3) }.should raise_error NoMethodError
+ describe "if invoked as an unambiguous method call" do
+ it "raises NoMethodError" do
+ -> { no_such_method() }.should.raise NoMethodError
+ -> { no_such_method(1,2,3) }.should.raise NoMethodError
+ end
+
+ it "raises NoMethodError with $! as a cause" do
+ begin
+ raise
+ rescue => cause
+ -> { no_such_method() }.should.raise(NoMethodError, cause:)
+ -> { no_such_method(1,2,3) }.should.raise(NoMethodError, cause:)
+ end
+ end
end
it "should omit the method_missing call from the backtrace for NoMethodError" do
- -> { no_such_method() }.should raise_error { |e| e.backtrace.first.should_not include("method_missing") }
+ -> { no_such_method() }.should.raise { |e| e.backtrace.first.should_not.include?("method_missing") }
end
end
@@ -337,7 +376,7 @@ describe "Invoking a method" do
it "with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_ary)" do
obj = Object.new
- obj.should_not respond_to(:to_a)
+ obj.should_not.respond_to?(:to_a)
specs.fooM0R(*obj).should == [obj]
specs.fooM1R(1,*obj).should == [1, [obj]]
diff --git a/spec/ruby/language/shared/__FILE__.rb b/spec/ruby/language/shared/__FILE__.rb
index 3e4f5c958d..7e2e871932 100644
--- a/spec/ruby/language/shared/__FILE__.rb
+++ b/spec/ruby/language/shared/__FILE__.rb
@@ -9,14 +9,14 @@ describe :language___FILE__, shared: true do
end
it "equals the absolute path of a file loaded by an absolute path" do
- @object.send(@method, @path).should be_true
+ @object.send(@method, @path).should == true
ScratchPad.recorded.should == [@path]
end
it "equals the absolute path of a file loaded by a relative path" do
$LOAD_PATH << "."
Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "file_fixture.rb").should be_true
+ @object.send(@method, "file_fixture.rb").should == true
end
ScratchPad.recorded.should == [@path]
end
diff --git a/spec/ruby/language/shared/__LINE__.rb b/spec/ruby/language/shared/__LINE__.rb
index 076b74b3ba..6bfc8c1c17 100644
--- a/spec/ruby/language/shared/__LINE__.rb
+++ b/spec/ruby/language/shared/__LINE__.rb
@@ -9,7 +9,7 @@ describe :language___LINE__, shared: true do
end
it "equals the line number of the text in a loaded file" do
- @object.send(@method, @path).should be_true
+ @object.send(@method, @path).should == true
ScratchPad.recorded.should == [1, 5]
end
end
diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb
index 45e1f7f3ad..20256a323c 100644
--- a/spec/ruby/language/singleton_class_spec.rb
+++ b/spec/ruby/language/singleton_class_spec.rb
@@ -15,39 +15,39 @@ describe "A singleton class" do
end
it "raises a TypeError for Integer's" do
- -> { 1.singleton_class }.should raise_error(TypeError)
+ -> { 1.singleton_class }.should.raise(TypeError)
end
it "raises a TypeError for symbols" do
- -> { :symbol.singleton_class }.should raise_error(TypeError)
+ -> { :symbol.singleton_class }.should.raise(TypeError)
end
it "is a singleton Class instance" do
o = mock('x')
- o.singleton_class.should be_kind_of(Class)
- o.singleton_class.should_not equal(Object)
- o.should be_kind_of(o.singleton_class)
+ o.singleton_class.should.is_a?(Class)
+ o.singleton_class.should_not.equal?(Object)
+ o.should.is_a?(o.singleton_class)
end
it "is a Class for classes" do
- ClassSpecs::A.singleton_class.should be_kind_of(Class)
+ ClassSpecs::A.singleton_class.should.is_a?(Class)
end
it "inherits from Class for classes" do
- Class.should be_ancestor_of(Object.singleton_class)
+ Object.singleton_class.ancestors.should.include?(Class)
end
it "is a subclass of Class's singleton class" do
ec = ClassSpecs::A.singleton_class
- ec.should be_kind_of(Class.singleton_class)
+ ec.should.is_a?(Class.singleton_class)
end
it "is a subclass of the same level of Class's singleton class" do
ecec = ClassSpecs::A.singleton_class.singleton_class
class_ec = Class.singleton_class
- ecec.should be_kind_of(class_ec.singleton_class)
- ecec.should be_kind_of(class_ec)
+ ecec.should.is_a?(class_ec.singleton_class)
+ ecec.should.is_a?(class_ec)
end
it "is a subclass of a superclass's singleton class" do
@@ -60,7 +60,7 @@ describe "A singleton class" do
ClassSpecs::H.singleton_class.singleton_class
end
- it "for BasicObject has Class as it's superclass" do
+ it "for BasicObject has Class as its superclass" do
BasicObject.singleton_class.superclass.should == Class
end
@@ -74,7 +74,7 @@ describe "A singleton class" do
end
it "doesn't have singleton class" do
- -> { bignum_value.singleton_class }.should raise_error(TypeError)
+ -> { bignum_value.singleton_class }.should.raise(TypeError)
end
end
@@ -105,20 +105,20 @@ describe "A constant on a singleton class" do
end
it "is not defined on the object's class" do
- @object.class.const_defined?(:CONST).should be_false
+ @object.class.const_defined?(:CONST).should == false
end
it "is not defined in the singleton class opener's scope" do
class << @object
CONST
end
- -> { CONST }.should raise_error(NameError)
+ -> { CONST }.should.raise(NameError)
end
it "cannot be accessed via object::CONST" do
-> do
@object::CONST
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a NameError for anonymous_module::CONST" do
@@ -129,15 +129,15 @@ describe "A constant on a singleton class" do
-> do
@object::CONST
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "appears in the singleton class constant list" do
- @object.singleton_class.should have_constant(:CONST)
+ @object.singleton_class.should.const_defined?(:CONST, false)
end
it "does not appear in the object's class constant list" do
- @object.class.should_not have_constant(:CONST)
+ @object.class.should_not.const_defined?(:CONST)
end
it "is not preserved when the object is duped" do
@@ -145,14 +145,14 @@ describe "A constant on a singleton class" do
-> do
class << @object; CONST; end
- end.should raise_error(NameError)
+ end.should.raise(NameError)
end
it "is preserved when the object is cloned" do
@object = @object.clone
class << @object
- CONST.should_not be_nil
+ CONST.should_not == nil
end
end
end
@@ -168,7 +168,7 @@ describe "Defining instance methods on a singleton class" do
end
it "defines public methods" do
- @k_sc.should have_public_instance_method(:singleton_method)
+ @k_sc.public_instance_methods(false).should.include?(:singleton_method)
end
end
@@ -181,46 +181,46 @@ describe "Instance methods of a singleton class" do
end
it "include ones of the object's class" do
- @k_sc.should have_instance_method(:example_instance_method)
+ @k_sc.should.method_defined?(:example_instance_method, true)
end
it "does not include class methods of the object's class" do
- @k_sc.should_not have_instance_method(:example_class_method)
+ @k_sc.should_not.method_defined?(:example_class_method)
end
it "include instance methods of Object" do
- @a_sc.should have_instance_method(:example_instance_method_of_object)
+ @a_sc.should.method_defined?(:example_instance_method_of_object, true)
end
it "does not include class methods of Object" do
- @a_sc.should_not have_instance_method(:example_class_method_of_object)
+ @a_sc.should_not.method_defined?(:example_class_method_of_object)
end
describe "for a class" do
it "include instance methods of Class" do
- @a_c_sc.should have_instance_method(:example_instance_method_of_class)
+ @a_c_sc.should.method_defined?(:example_instance_method_of_class, true)
end
it "does not include class methods of Class" do
- @a_c_sc.should_not have_instance_method(:example_class_method_of_class)
+ @a_c_sc.should_not.method_defined?(:example_class_method_of_class)
end
it "does not include instance methods of the singleton class of Class" do
- @a_c_sc.should_not have_instance_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.should_not.method_defined?(:example_instance_method_of_singleton_class)
end
it "does not include class methods of the singleton class of Class" do
- @a_c_sc.should_not have_instance_method(:example_class_method_of_singleton_class)
+ @a_c_sc.should_not.method_defined?(:example_class_method_of_singleton_class)
end
end
describe "for a singleton class" do
it "includes instance methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should have_instance_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.singleton_class.should.method_defined?(:example_instance_method_of_singleton_class, true)
end
it "does not include class methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should_not have_instance_method(:example_class_method_of_singleton_class)
+ @a_c_sc.singleton_class.should_not.method_defined?(:example_class_method_of_singleton_class)
end
end
end
@@ -234,46 +234,46 @@ describe "Class methods of a singleton class" do
end
it "include ones of the object's class" do
- @k_sc.should have_method(:example_class_method)
+ @k_sc.should.respond_to?(:example_class_method)
end
it "does not include instance methods of the object's class" do
- @k_sc.should_not have_method(:example_instance_method)
+ @k_sc.should_not.respond_to?(:example_instance_method)
end
it "include instance methods of Class" do
- @a_sc.should have_method(:example_instance_method_of_class)
+ @a_sc.should.respond_to?(:example_instance_method_of_class)
end
it "does not include class methods of Class" do
- @a_sc.should_not have_method(:example_class_method_of_class)
+ @a_sc.should_not.respond_to?(:example_class_method_of_class)
end
describe "for a class" do
it "include instance methods of Class" do
- @a_c_sc.should have_method(:example_instance_method_of_class)
+ @a_c_sc.should.respond_to?(:example_instance_method_of_class)
end
it "include class methods of Class" do
- @a_c_sc.should have_method(:example_class_method_of_class)
+ @a_c_sc.should.respond_to?(:example_class_method_of_class)
end
it "include instance methods of the singleton class of Class" do
- @a_c_sc.should have_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.should.respond_to?(:example_instance_method_of_singleton_class)
end
it "does not include class methods of the singleton class of Class" do
- @a_c_sc.should_not have_method(:example_class_method_of_singleton_class)
+ @a_c_sc.should_not.respond_to?(:example_class_method_of_singleton_class)
end
end
describe "for a singleton class" do
it "include instance methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should have_method(:example_instance_method_of_singleton_class)
+ @a_c_sc.singleton_class.should.respond_to?(:example_instance_method_of_singleton_class)
end
it "include class methods of the singleton class of Class" do
- @a_c_sc.singleton_class.should have_method(:example_class_method_of_singleton_class)
+ @a_c_sc.singleton_class.should.respond_to?(:example_class_method_of_singleton_class)
end
end
end
@@ -282,13 +282,13 @@ describe "Instantiating a singleton class" do
it "raises a TypeError when new is called" do
-> {
Object.new.singleton_class.new
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError when allocate is called" do
-> {
Object.new.singleton_class.allocate
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/language/source_encoding_spec.rb b/spec/ruby/language/source_encoding_spec.rb
index 7135bc0a70..5a243fa2c3 100644
--- a/spec/ruby/language/source_encoding_spec.rb
+++ b/spec/ruby/language/source_encoding_spec.rb
@@ -29,7 +29,7 @@ describe "Source files" do
touch(path, "wb") { |f| f.write source }
begin
- ruby_exe(path, args: "2>&1", exit_status: 1).should =~ /invalid multibyte char/
+ ruby_exe(path, args: "2>&1", exit_status: 1).b.should =~ /invalid multibyte char/
ensure
rm_r path
end
@@ -51,7 +51,7 @@ describe "Source files" do
touch(path, "wb") { |f| f.write source }
begin
- ruby_exe(path, args: "2>&1", exit_status: 1).should =~ /invalid multibyte char/
+ ruby_exe(path, args: "2>&1", exit_status: 1).b.should =~ /invalid multibyte char/
ensure
rm_r path
end
diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb
index 083a7f5db5..163063032f 100644
--- a/spec/ruby/language/string_spec.rb
+++ b/spec/ruby/language/string_spec.rb
@@ -1,6 +1,7 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../spec_helper'
+require_relative 'fixtures/class_with_class_variable'
# TODO: rewrite these horrid specs. it "are..." seriously?!
@@ -27,6 +28,11 @@ describe "Ruby character strings" do
"#$ip".should == 'xxx'
end
+ it "interpolate class variables just with the # character" do
+ object = StringSpecs::ClassWithClassVariable.new
+ object.foo.should == 'xxx'
+ end
+
it "allows underscore as part of a variable name in a simple interpolation" do
@my_ip = 'xxx'
"#@my_ip".should == 'xxx'
@@ -127,6 +133,12 @@ describe "Ruby character strings" do
"#{obj}".should == '42'
end
+ it "raise NoMethodError when #to_s is not defined for the object" do
+ obj = BasicObject.new
+
+ -> { "#{obj}" }.should.raise(NoMethodError)
+ end
+
it "uses an internal representation when #to_s doesn't return a String" do
obj = mock('to_s')
obj.stub!(:to_s).and_return(42)
@@ -137,7 +149,7 @@ describe "Ruby character strings" do
# is that if you interpolate an object that fails to return
# a String, you will still get a String and not raise an
# exception.
- "#{obj}".should be_an_instance_of(String)
+ "#{obj}".should.instance_of?(String)
end
it "allows a dynamic string to parse a nested do...end block as an argument to a call without parens, interpolated" do
@@ -275,20 +287,20 @@ describe "Ruby String interpolation" do
a = "\u3042"
b = "\xff".dup.force_encoding "binary"
- -> { "#{a} #{b}" }.should raise_error(Encoding::CompatibilityError)
+ -> { "#{a} #{b}" }.should.raise(Encoding::CompatibilityError)
end
it "creates a non-frozen String" do
code = <<~'RUBY'
- "a#{6*7}c"
+ "a#{6*7}c"
RUBY
eval(code).should_not.frozen?
end
it "creates a non-frozen String when # frozen-string-literal: true is used" do
code = <<~'RUBY'
- # frozen-string-literal: true
- "a#{6*7}c"
+ # frozen-string-literal: true
+ "a#{6*7}c"
RUBY
eval(code).should_not.frozen?
end
diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb
index 7d9e896d8b..f595d49395 100644
--- a/spec/ruby/language/super_spec.rb
+++ b/spec/ruby/language/super_spec.rb
@@ -83,8 +83,8 @@ describe "The super keyword" do
end
end
- -> {sub_normal.new.foo}.should raise_error(NoMethodError, /super/)
- -> {sub_zsuper.new.foo}.should raise_error(NoMethodError, /super/)
+ -> {sub_normal.new.foo}.should.raise(NoMethodError, /super/)
+ -> {sub_zsuper.new.foo}.should.raise(NoMethodError, /super/)
end
it "uses given block even if arguments are passed explicitly" do
@@ -130,7 +130,7 @@ describe "The super keyword" do
end
end
- c2.new.m('a') { raise }.should be_false
+ c2.new.m('a') { raise }.should == false
end
it "uses block argument given to method when used in a block" do
@@ -200,7 +200,7 @@ describe "The super keyword" do
end
end
- -> { klass.new.a(:a_called) }.should raise_error(RuntimeError)
+ -> { klass.new.a(:a_called) }.should.raise(RuntimeError)
end
it "is able to navigate to super, when a method is defined dynamically on the singleton class" do
@@ -461,4 +461,18 @@ describe "The super keyword" do
@all.foo('a', b: 'b').should == [['a'], {b: 'b'}]
end
end
+
+ it "works in method definitions using **nil" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+ end
+ child = Class.new(parent) do
+ def m(*args, **nil)
+ super
+ end
+ end
+ child.new.m(1, 2).should == [[1, 2], {}]
+ end
end
diff --git a/spec/ruby/language/symbol_spec.rb b/spec/ruby/language/symbol_spec.rb
index 0801d3223e..81fe06b50b 100644
--- a/spec/ruby/language/symbol_spec.rb
+++ b/spec/ruby/language/symbol_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
describe "A Symbol literal" do
it "is a ':' followed by any number of valid characters" do
a = :foo
- a.should be_kind_of(Symbol)
+ a.should.is_a?(Symbol)
a.inspect.should == ':foo'
end
@@ -21,7 +21,7 @@ describe "A Symbol literal" do
:_Foo,
:&,
:_9
- ].each { |s| s.should be_kind_of(Symbol) }
+ ].each { |s| s.should.is_a?(Symbol) }
end
it "is a ':' followed by a single- or double-quoted string that may contain otherwise invalid characters" do
@@ -31,7 +31,7 @@ describe "A Symbol literal" do
[:"foo #{1 + 1}", ':"foo 2"'],
[:"foo\nbar", ':"foo\nbar"'],
].each { |sym, str|
- sym.should be_kind_of(Symbol)
+ sym.should.is_a?(Symbol)
sym.inspect.should == str
}
end
@@ -42,22 +42,22 @@ describe "A Symbol literal" do
end
it "may contain '::' in the string" do
- :'Some::Class'.should be_kind_of(Symbol)
+ :'Some::Class'.should.is_a?(Symbol)
end
it "is converted to a literal, unquoted representation if the symbol contains only valid characters" do
a, b, c = :'foo', :'+', :'Foo__9'
- a.should be_kind_of(Symbol)
+ a.should.is_a?(Symbol)
a.inspect.should == ':foo'
- b.should be_kind_of(Symbol)
+ b.should.is_a?(Symbol)
b.inspect.should == ':+'
- c.should be_kind_of(Symbol)
+ c.should.is_a?(Symbol)
c.inspect.should == ':Foo__9'
end
it "can be created by the %s-delimited expression" do
a, b = :'foo bar', %s{foo bar}
- b.should be_kind_of(Symbol)
+ b.should.is_a?(Symbol)
b.inspect.should == ':"foo bar"'
b.should == a
end
@@ -68,7 +68,7 @@ describe "A Symbol literal" do
[:'a string', :'a string'],
[:"#{var}", :"#{var}"]
].each { |a, b|
- a.should equal(b)
+ a.should.equal?(b)
}
end
@@ -78,7 +78,7 @@ describe "A Symbol literal" do
it "can be an empty string" do
c = :''
- c.should be_kind_of(Symbol)
+ c.should.is_a?(Symbol)
c.inspect.should == ':""'
end
@@ -101,7 +101,7 @@ describe "A Symbol literal" do
ScratchPad.record []
-> {
eval 'ScratchPad << 1; :"\xC3"'
- }.should raise_error(SyntaxError, /invalid symbol/)
+ }.should.raise(SyntaxError, /invalid symbol/)
ScratchPad.recorded.should == []
end
end
diff --git a/spec/ruby/language/throw_spec.rb b/spec/ruby/language/throw_spec.rb
index d723843688..73f64de17d 100644
--- a/spec/ruby/language/throw_spec.rb
+++ b/spec/ruby/language/throw_spec.rb
@@ -35,7 +35,7 @@ describe "The throw keyword" do
throw :exit
end
end
- $!.should be_nil
+ $!.should == nil
end
it "allows any object as its argument" do
@@ -45,7 +45,7 @@ describe "The throw keyword" do
end
it "does not convert strings to a symbol" do
- -> { catch(:exit) { throw "exit" } }.should raise_error(ArgumentError)
+ -> { catch(:exit) { throw "exit" } }.should.raise(ArgumentError)
end
it "unwinds stack from within a method" do
@@ -64,8 +64,8 @@ describe "The throw keyword" do
end
it "raises an ArgumentError if outside of scope of a matching catch" do
- -> { throw :test, 5 }.should raise_error(ArgumentError)
- -> { catch(:different) { throw :test, 5 } }.should raise_error(ArgumentError)
+ -> { throw :test, 5 }.should.raise(ArgumentError)
+ -> { catch(:different) { throw :test, 5 } }.should.raise(ArgumentError)
end
it "raises an UncaughtThrowError if used to exit a thread" do
@@ -73,7 +73,7 @@ describe "The throw keyword" do
t = Thread.new {
-> {
throw :what
- }.should raise_error(UncaughtThrowError)
+ }.should.raise(UncaughtThrowError)
}
t.join
end
diff --git a/spec/ruby/language/undef_spec.rb b/spec/ruby/language/undef_spec.rb
index 268c0b84c3..98ecd99c21 100644
--- a/spec/ruby/language/undef_spec.rb
+++ b/spec/ruby/language/undef_spec.rb
@@ -14,42 +14,42 @@ describe "The undef keyword" do
@undef_class.class_eval do
undef meth
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with a simple symbol" do
@undef_class.class_eval do
undef :meth
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with a single quoted symbol" do
@undef_class.class_eval do
undef :'meth'
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with a double quoted symbol" do
@undef_class.class_eval do
undef :"meth"
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with an interpolated symbol" do
@undef_class.class_eval do
undef :"#{'meth'}"
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
it "with an interpolated symbol when interpolated expression is not a String literal" do
@undef_class.class_eval do
undef :"#{'meth'.to_sym}"
end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ -> { @obj.meth(5) }.should.raise(NoMethodError)
end
end
@@ -70,7 +70,7 @@ describe "The undef keyword" do
Class.new do
-> {
undef not_exist
- }.should raise_error(NameError) { |e|
+ }.should.raise(NameError) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb
index eb080eea55..e01e03f01e 100644
--- a/spec/ruby/language/variables_spec.rb
+++ b/spec/ruby/language/variables_spec.rb
@@ -91,7 +91,7 @@ describe "Multiple assignment" do
x = mock("multi-assign single RHS")
x.should_receive(:to_ary).and_return(1)
- -> { a, b, c = x }.should raise_error(TypeError)
+ -> { a, b, c = x }.should.raise(TypeError)
end
it "does not call #to_a to convert an Object RHS when assigning a simple MLHS" do
@@ -122,7 +122,7 @@ describe "Multiple assignment" do
ary = [1, 2]
x = (a, b = ary)
- x.should equal(ary)
+ x.should.equal?(ary)
end
it "returns the RHS when it is an Array subclass" do
@@ -130,7 +130,7 @@ describe "Multiple assignment" do
ary = cls.new [1, 2]
x = (a, b = ary)
- x.should equal(ary)
+ x.should.equal?(ary)
end
it "does not call #to_ary on an Array subclass instance" do
@@ -172,7 +172,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_ary).and_return(1)
- -> { *a = x }.should raise_error(TypeError)
+ -> { *a = x }.should.raise(TypeError)
end
it "does not call #to_ary on an Array subclass" do
@@ -189,8 +189,8 @@ describe "Multiple assignment" do
ary = cls.new [1, 2]
x = (*a = ary)
- x.should equal(ary)
- a.should be_an_instance_of(Array)
+ x.should.equal?(ary)
+ a.should.instance_of?(Array)
end
it "calls #to_ary to convert an Object RHS with MLHS" do
@@ -205,7 +205,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_ary).and_return(1)
- -> { a, *b, c = x }.should raise_error(TypeError)
+ -> { a, *b, c = x }.should.raise(TypeError)
end
it "does not call #to_a to convert an Object RHS with a MLHS" do
@@ -301,7 +301,7 @@ describe "Multiple assignment" do
x = mock("multi-assign attributes")
x.should_receive(:m).and_return(y)
- -> { a, b = x.m }.should raise_error(TypeError)
+ -> { a, b = x.m }.should.raise(TypeError)
end
it "assigns values from a RHS method call with receiver and arguments" do
@@ -363,7 +363,7 @@ describe "Multiple assignment" do
a.should == []
end
- ruby_version_is "3.5" do
+ ruby_version_is "4.0" do
it "converts nil to empty array without calling a method" do
nil.should_not_receive(:to_a)
@@ -372,7 +372,7 @@ describe "Multiple assignment" do
end
end
- ruby_version_is ""..."3.5" do
+ ruby_version_is ""..."4.0" do
it "calls #to_a to convert nil to an empty Array" do
nil.should_receive(:to_a).and_return([])
@@ -393,7 +393,7 @@ describe "Multiple assignment" do
ary = [1, 2]
(a = *ary).should == [1, 2]
- a.should_not equal(ary)
+ a.should_not.equal?(ary)
end
it "does not call #to_a on an Array subclass" do
@@ -412,10 +412,10 @@ describe "Multiple assignment" do
x = (a = *ary)
x.should == [1, 2]
- x.should be_an_instance_of(Array)
+ x.should.instance_of?(Array)
a.should == [1, 2]
- a.should be_an_instance_of(Array)
+ a.should.instance_of?(Array)
end
it "unfreezes the array returned from calling 'to_a' on the splatted value" do
@@ -481,7 +481,7 @@ describe "Multiple assignment" do
x = mock("multi-assign RHS splat")
x.should_receive(:to_a).and_return(1)
- -> { *a = *x }.should raise_error(TypeError)
+ -> { *a = *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object RHS with a single splat LHS" do
@@ -527,7 +527,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_a).and_return(1)
- -> { a = *x }.should raise_error(TypeError)
+ -> { a = *x }.should.raise(TypeError)
end
it "calls #to_a to convert an Object splat RHS when assigned to a simple MLHS" do
@@ -542,7 +542,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_a).and_return(1)
- -> { a, b, c = *x }.should raise_error(TypeError)
+ -> { a, b, c = *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object splat RHS when assigned to a simple MLHS" do
@@ -565,7 +565,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat")
x.should_receive(:to_a).and_return(1)
- -> { a, *b, c = *x }.should raise_error(TypeError)
+ -> { a, *b, c = *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object RHS with a MLHS" do
@@ -645,7 +645,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat MRHS")
x.should_receive(:to_a).and_return(1)
- -> { a, *b = 1, *x }.should raise_error(TypeError)
+ -> { a, *b = 1, *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert a splatted Object as part of a MRHS with a splat MRHS" do
@@ -668,7 +668,7 @@ describe "Multiple assignment" do
x = mock("multi-assign splat MRHS")
x.should_receive(:to_a).and_return(1)
- -> { a, *b = *x, 1 }.should raise_error(TypeError)
+ -> { a, *b = *x, 1 }.should.raise(TypeError)
end
it "does not call #to_ary to convert a splatted Object with a splat MRHS" do
@@ -717,7 +717,7 @@ describe "Multiple assignment" do
x = mock("multi-assign mixed RHS")
x.should_receive(:to_ary).and_return(x)
- -> { a, (b, c), d = 1, x, 3, 4 }.should raise_error(TypeError)
+ -> { a, (b, c), d = 1, x, 3, 4 }.should.raise(TypeError)
end
it "calls #to_a to convert a splatted Object value in a MRHS" do
@@ -741,7 +741,7 @@ describe "Multiple assignment" do
x = mock("multi-assign mixed splatted RHS")
x.should_receive(:to_ary).and_return(x)
- -> { a, *b, (c, d) = 1, 2, 3, *x }.should raise_error(TypeError)
+ -> { a, *b, (c, d) = 1, 2, 3, *x }.should.raise(TypeError)
end
it "does not call #to_ary to convert an Object when the position receiving the value is a simple variable" do
@@ -889,7 +889,7 @@ describe 'Allowed characters' do
ἍBB = 1
end
CODE
- end.should raise_error(SyntaxError, /dynamic constant assignment/)
+ end.should.raise(SyntaxError, /dynamic constant assignment/)
end
end
diff --git a/spec/ruby/language/while_spec.rb b/spec/ruby/language/while_spec.rb
index e172453ca6..b9bf32047d 100644
--- a/spec/ruby/language/while_spec.rb
+++ b/spec/ruby/language/while_spec.rb
@@ -88,7 +88,7 @@ describe "The while expression" do
break if c
c = false
)
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a begin ... end element op-assign-or value" do
@@ -99,7 +99,7 @@ describe "The while expression" do
break if c
c = false
end
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a parenthesized element op-assign value" do
@@ -111,7 +111,7 @@ describe "The while expression" do
break if c
c = false
)
- end.should be_nil
+ end.should == nil
a.should == [1, 2]
end
@@ -123,7 +123,7 @@ describe "The while expression" do
break if c
c = false
end
- end.should be_nil
+ end.should == nil
a.should == [1, 2]
end
@@ -139,7 +139,7 @@ describe "The while expression" do
break unless d
d = false
)
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break with unless in a begin ... end attribute op-assign-or value" do
@@ -153,7 +153,7 @@ describe "The while expression" do
break unless d
d = false
end
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a parenthesized attribute op-assign-or value" do
@@ -168,7 +168,7 @@ describe "The while expression" do
break if c
c = false
)
- end.should be_nil
+ end.should == nil
end
it "stops running body if interrupted by break in a begin ... end attribute op-assign-or value" do
@@ -182,7 +182,7 @@ describe "The while expression" do
break if c
c = false
end
- end.should be_nil
+ end.should == nil
end
it "returns value passed to break if interrupted by break" do
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index e125cf8e73..3173f41b0c 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -13,7 +13,7 @@ describe "The yield call" do
describe "taking no arguments" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.z }.should raise_error(LocalJumpError)
+ -> { @y.z }.should.raise(LocalJumpError)
end
it "ignores assignment to the explicit block argument and calls the passed block" do
@@ -28,7 +28,7 @@ describe "The yield call" do
describe "taking a single argument" do
describe "when no block is given" do
it "raises a LocalJumpError" do
- -> { @y.s(1) }.should raise_error(LocalJumpError)
+ -> { @y.s(1) }.should.raise(LocalJumpError)
end
end
@@ -48,6 +48,12 @@ describe "The yield call" do
it "passes a single, multi-value Array" do
@y.s([1, 2, 3]) { |*a| a }.should == [[1, 2, 3]]
end
+
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ @y.s([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
+ end
end
describe "yielding to a lambda" do
@@ -70,20 +76,20 @@ describe "The yield call" do
it "raises an ArgumentError if too few arguments are passed" do
-> {
@y.s(1, &-> a, b { [a,b] })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "should not destructure an Array into multiple arguments" do
-> {
@y.s([1, 2], &-> a, b { [a,b] })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
describe "taking multiple arguments" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.m(1, 2, 3) }.should raise_error(LocalJumpError)
+ -> { @y.m(1, 2, 3) }.should.raise(LocalJumpError)
end
it "passes the arguments to the block" do
@@ -97,19 +103,19 @@ describe "The yield call" do
it "raises an ArgumentError if too many arguments are passed to a lambda" do
-> {
@y.m(1, 2, 3, &-> a { })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an ArgumentError if too few arguments are passed to a lambda" do
-> {
@y.m(1, 2, 3, &-> a, b, c, d { })
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
describe "taking a single splatted argument" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.r(0) }.should raise_error(LocalJumpError)
+ -> { @y.r(0) }.should.raise(LocalJumpError)
end
it "passes a single value" do
@@ -141,7 +147,7 @@ describe "The yield call" do
describe "taking multiple arguments with a splat" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.rs(1, 2, [3, 4]) }.should raise_error(LocalJumpError)
+ -> { @y.rs(1, 2, [3, 4]) }.should.raise(LocalJumpError)
end
it "passes the arguments to the block" do
@@ -166,7 +172,7 @@ describe "The yield call" do
describe "taking matching arguments with splats and post args" do
it "raises a LocalJumpError when the method is not passed a block" do
- -> { @y.rs(1, 2, [3, 4]) }.should raise_error(LocalJumpError)
+ -> { @y.rs(1, 2, [3, 4]) }.should.raise(LocalJumpError)
end
it "passes the arguments to the block" do
@@ -193,7 +199,7 @@ describe "Using yield in a singleton class literal" do
end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should.raise(SyntaxError, /Invalid yield/)
end
end
@@ -203,7 +209,7 @@ describe "Using yield in non-lambda block" do
1.times { yield }
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should.raise(SyntaxError, /Invalid yield/)
end
end
@@ -215,6 +221,6 @@ describe "Using yield in a module literal" do
end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should.raise(SyntaxError, /Invalid yield/)
end
end
diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb
index 4d615d1e25..bdc3774608 100644
--- a/spec/ruby/library/English/English_spec.rb
+++ b/spec/ruby/library/English/English_spec.rb
@@ -7,26 +7,26 @@ describe "English" do
begin
raise "error"
rescue
- $ERROR_INFO.should_not be_nil
+ $ERROR_INFO.should_not == nil
$ERROR_INFO.should == $!
end
- $ERROR_INFO.should be_nil
+ $ERROR_INFO.should == nil
end
it "aliases $ERROR_POSITION to $@" do
begin
raise "error"
rescue
- $ERROR_POSITION.should_not be_nil
+ $ERROR_POSITION.should_not == nil
$ERROR_POSITION.should == $@
end
- $ERROR_POSITION.should be_nil
+ $ERROR_POSITION.should == nil
end
it "aliases $FS to $;" do
original = $;
suppress_warning {$; = ","}
- $FS.should_not be_nil
+ $FS.should_not == nil
$FS.should == $;
suppress_warning {$; = original}
end
@@ -34,7 +34,7 @@ describe "English" do
it "aliases $FIELD_SEPARATOR to $;" do
original = $;
suppress_warning {$; = ","}
- $FIELD_SEPARATOR.should_not be_nil
+ $FIELD_SEPARATOR.should_not == nil
$FIELD_SEPARATOR.should == $;
suppress_warning {$; = original}
end
@@ -42,7 +42,7 @@ describe "English" do
it "aliases $OFS to $," do
original = $,
suppress_warning {$, = "|"}
- $OFS.should_not be_nil
+ $OFS.should_not == nil
$OFS.should == $,
suppress_warning {$, = original}
end
@@ -50,25 +50,25 @@ describe "English" do
it "aliases $OUTPUT_FIELD_SEPARATOR to $," do
original = $,
suppress_warning {$, = "|"}
- $OUTPUT_FIELD_SEPARATOR.should_not be_nil
+ $OUTPUT_FIELD_SEPARATOR.should_not == nil
$OUTPUT_FIELD_SEPARATOR.should == $,
suppress_warning {$, = original}
end
it "aliases $RS to $/" do
- $RS.should_not be_nil
+ $RS.should_not == nil
$RS.should == $/
end
it "aliases $INPUT_RECORD_SEPARATOR to $/" do
- $INPUT_RECORD_SEPARATOR.should_not be_nil
+ $INPUT_RECORD_SEPARATOR.should_not == nil
$INPUT_RECORD_SEPARATOR.should == $/
end
it "aliases $ORS to $\\" do
original = $\
suppress_warning {$\ = "\t"}
- $ORS.should_not be_nil
+ $ORS.should_not == nil
$ORS.should == $\
suppress_warning {$\ = original}
end
@@ -76,98 +76,86 @@ describe "English" do
it "aliases $OUTPUT_RECORD_SEPARATOR to $\\" do
original = $\
suppress_warning {$\ = "\t"}
- $OUTPUT_RECORD_SEPARATOR.should_not be_nil
+ $OUTPUT_RECORD_SEPARATOR.should_not == nil
$OUTPUT_RECORD_SEPARATOR.should == $\
suppress_warning {$\ = original}
end
it "aliases $INPUT_LINE_NUMBER to $." do
- $INPUT_LINE_NUMBER.should_not be_nil
+ $INPUT_LINE_NUMBER.should_not == nil
$INPUT_LINE_NUMBER.should == $.
end
it "aliases $NR to $." do
- $NR.should_not be_nil
+ $NR.should_not == nil
$NR.should == $.
end
it "aliases $LAST_READ_LINE to $_ needs to be reviewed for spec completeness"
it "aliases $DEFAULT_OUTPUT to $>" do
- $DEFAULT_OUTPUT.should_not be_nil
+ $DEFAULT_OUTPUT.should_not == nil
$DEFAULT_OUTPUT.should == $>
end
it "aliases $DEFAULT_INPUT to $<" do
- $DEFAULT_INPUT.should_not be_nil
+ $DEFAULT_INPUT.should_not == nil
$DEFAULT_INPUT.should == $<
end
it "aliases $PID to $$" do
- $PID.should_not be_nil
+ $PID.should_not == nil
$PID.should == $$
end
it "aliases $PID to $$" do
- $PID.should_not be_nil
+ $PID.should_not == nil
$PID.should == $$
end
it "aliases $PROCESS_ID to $$" do
- $PROCESS_ID.should_not be_nil
+ $PROCESS_ID.should_not == nil
$PROCESS_ID.should == $$
end
it "aliases $CHILD_STATUS to $?" do
ruby_exe('exit 0')
- $CHILD_STATUS.should_not be_nil
+ $CHILD_STATUS.should_not == nil
$CHILD_STATUS.should == $?
end
it "aliases $LAST_MATCH_INFO to $~" do
/c(a)t/ =~ "cat"
- $LAST_MATCH_INFO.should_not be_nil
+ $LAST_MATCH_INFO.should_not == nil
$LAST_MATCH_INFO.should == $~
end
- ruby_version_is ""..."3.3" do
- it "aliases $IGNORECASE to $=" do
- $VERBOSE, verbose = nil, $VERBOSE
- begin
- $IGNORECASE.should_not be_nil
- $IGNORECASE.should == $=
- ensure
- $VERBOSE = verbose
- end
- end
- end
-
it "aliases $ARGV to $*" do
- $ARGV.should_not be_nil
+ $ARGV.should_not == nil
$ARGV.should == $*
end
it "aliases $MATCH to $&" do
/c(a)t/ =~ "cat"
- $MATCH.should_not be_nil
+ $MATCH.should_not == nil
$MATCH.should == $&
end
it "aliases $PREMATCH to $`" do
/c(a)t/ =~ "cat"
- $PREMATCH.should_not be_nil
+ $PREMATCH.should_not == nil
$PREMATCH.should == $`
end
it "aliases $POSTMATCH to $'" do
/c(a)t/ =~ "cat"
- $POSTMATCH.should_not be_nil
+ $POSTMATCH.should_not == nil
$POSTMATCH.should == $'
end
it "aliases $LAST_PAREN_MATCH to $+" do
/c(a)t/ =~ "cat"
- $LAST_PAREN_MATCH.should_not be_nil
+ $LAST_PAREN_MATCH.should_not == nil
$LAST_PAREN_MATCH.should == $+
end
end
diff --git a/spec/ruby/library/English/alias_spec.rb b/spec/ruby/library/English/alias_spec.rb
index 78ccfb4398..3ff92f964d 100644
--- a/spec/ruby/library/English/alias_spec.rb
+++ b/spec/ruby/library/English/alias_spec.rb
@@ -4,11 +4,11 @@ require 'English'
describe "English" do
it "aliases $! to $ERROR_INFO and $ERROR_INFO still returns an Exception with a backtrace" do
exception = (1 / 0 rescue $ERROR_INFO)
- exception.should be_kind_of(Exception)
- exception.backtrace.should be_kind_of(Array)
+ exception.should.is_a?(Exception)
+ exception.backtrace.should.is_a?(Array)
end
it "aliases $@ to $ERROR_POSITION and $ERROR_POSITION still returns a backtrace" do
- (1 / 0 rescue $ERROR_POSITION).should be_kind_of(Array)
+ (1 / 0 rescue $ERROR_POSITION).should.is_a?(Array)
end
end
diff --git a/spec/ruby/library/base64/strict_decode64_spec.rb b/spec/ruby/library/base64/strict_decode64_spec.rb
index d258223c82..7b52f0c922 100644
--- a/spec/ruby/library/base64/strict_decode64_spec.rb
+++ b/spec/ruby/library/base64/strict_decode64_spec.rb
@@ -14,25 +14,25 @@ describe "Base64#strict_decode64" do
it "raises ArgumentError when the given string contains CR" do
-> do
Base64.strict_decode64("U2VuZCByZWluZm9yY2VtZW50cw==\r")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when the given string contains LF" do
-> do
Base64.strict_decode64("U2VuZCByZWluZm9yY2VtZW50cw==\n")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when the given string has wrong padding" do
-> do
Base64.strict_decode64("=U2VuZCByZWluZm9yY2VtZW50cw==")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError when the given string contains an invalid character" do
-> do
Base64.strict_decode64("%3D")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns a binary encoded string" do
diff --git a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb
index 45f5ebffc7..6adebabe84 100644
--- a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb
+++ b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb
@@ -10,7 +10,7 @@ end
describe "Kernel#BigDecimal" do
it "creates a new object of class BigDecimal" do
- BigDecimal("3.14159").should be_kind_of(BigDecimal)
+ BigDecimal("3.14159").should.is_a?(BigDecimal)
(0..9).each {|i|
BigDecimal("1#{i}").should == 10 + i
BigDecimal("-1#{i}").should == -10 - i
@@ -31,16 +31,12 @@ describe "Kernel#BigDecimal" do
end
it "accepts significant digits >= given precision" do
- suppress_warning do
- BigDecimal("3.1415923", 10).precs[1].should >= 10
- end
+ BigDecimal("3.1415923", 10).should == BigDecimal("3.1415923")
end
it "determines precision from initial value" do
pi_string = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043"
- suppress_warning {
- BigDecimal(pi_string).precs[1]
- }.should >= pi_string.size-1
+ BigDecimal(pi_string).precision.should == pi_string.size-1
end
it "ignores leading and trailing whitespace" do
@@ -57,15 +53,15 @@ describe "Kernel#BigDecimal" do
end
it "does not ignores trailing garbage" do
- -> { BigDecimal("123E45ruby") }.should raise_error(ArgumentError)
- -> { BigDecimal("123x45") }.should raise_error(ArgumentError)
- -> { BigDecimal("123.4%E5") }.should raise_error(ArgumentError)
- -> { BigDecimal("1E2E3E4E5E") }.should raise_error(ArgumentError)
+ -> { BigDecimal("123E45ruby") }.should.raise(ArgumentError)
+ -> { BigDecimal("123x45") }.should.raise(ArgumentError)
+ -> { BigDecimal("123.4%E5") }.should.raise(ArgumentError)
+ -> { BigDecimal("1E2E3E4E5E") }.should.raise(ArgumentError)
end
it "raises ArgumentError for invalid strings" do
- -> { BigDecimal("ruby") }.should raise_error(ArgumentError)
- -> { BigDecimal(" \t\n \r-\t\t\tInfinity \n") }.should raise_error(ArgumentError)
+ -> { BigDecimal("ruby") }.should.raise(ArgumentError)
+ -> { BigDecimal(" \t\n \r-\t\t\tInfinity \n") }.should.raise(ArgumentError)
end
it "allows omitting the integer part" do
@@ -76,8 +72,8 @@ describe "Kernel#BigDecimal" do
reference = BigDecimal("12345.67E89")
BigDecimal("12_345.67E89").should == reference
- -> { BigDecimal("1_2_3_4_5_._6____7_E89") }.should raise_error(ArgumentError)
- -> { BigDecimal("12345_.67E_8__9_") }.should raise_error(ArgumentError)
+ -> { BigDecimal("1_2_3_4_5_._6____7_E89") }.should.raise(ArgumentError)
+ -> { BigDecimal("12345_.67E_8__9_") }.should.raise(ArgumentError)
end
it "accepts NaN and [+-]Infinity" do
@@ -95,13 +91,13 @@ describe "Kernel#BigDecimal" do
describe "with exception: false" do
it "returns nil for invalid strings" do
- BigDecimal("invalid", exception: false).should be_nil
- BigDecimal("0invalid", exception: false).should be_nil
- BigDecimal("invalid0", exception: false).should be_nil
+ BigDecimal("invalid", exception: false).should == nil
+ BigDecimal("0invalid", exception: false).should == nil
+ BigDecimal("invalid0", exception: false).should == nil
if BigDecimal::VERSION >= "3.1.9"
BigDecimal("0.", exception: false).to_i.should == 0
else
- BigDecimal("0.", exception: false).should be_nil
+ BigDecimal("0.", exception: false).should == nil
end
end
end
@@ -156,8 +152,10 @@ describe "Kernel#BigDecimal" do
BigDecimal("-12345.6E-1").should == -reference
end
- it "raises ArgumentError when Float is used without precision" do
- -> { BigDecimal(1.0) }.should raise_error(ArgumentError)
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "allows Float without precision" do
+ BigDecimal(1.2).should == BigDecimal("1.2")
+ end
end
it "returns appropriate BigDecimal zero for signed zero" do
@@ -206,14 +204,6 @@ describe "Kernel#BigDecimal" do
Float(@b).to_s.should == "166.66666666666666"
end
- it "has the expected precision on the LHS" do
- suppress_warning { @a.precs[0] }.should == 18
- end
-
- it "has the expected maximum precision on the LHS" do
- suppress_warning { @a.precs[1] }.should == 27
- end
-
it "produces the expected result when done via Float" do
(Float(@a) - Float(@b)).to_s.should == "-6.666596163995564e-10"
end
@@ -224,34 +214,10 @@ describe "Kernel#BigDecimal" do
# Check underlying methods work as we understand
- it "BigDecimal precision is the number of digits rounded up to a multiple of nine" do
- 1.upto(100) do |n|
- b = BigDecimal('4' * n)
- precs, _ = suppress_warning { b.precs }
- (precs >= 9).should be_true
- (precs >= n).should be_true
- (precs % 9).should == 0
- end
- suppress_warning { BigDecimal('NaN').precs[0] }.should == 9
- end
-
- it "BigDecimal maximum precision is nine more than precision except for abnormals" do
- 1.upto(100) do |n|
- b = BigDecimal('4' * n)
- precs, max = suppress_warning { b.precs }
- max.should == precs + 9
- end
- suppress_warning { BigDecimal('NaN').precs[1] }.should == 9
- end
-
it "BigDecimal(Rational, 18) produces the result we expect" do
BigDecimal(@b, 18).to_s.should == "0.166666666666666667e3"
end
- it "BigDecimal(Rational, BigDecimal.precs[0]) produces the result we expect" do
- BigDecimal(@b, suppress_warning { @a.precs[0] }).to_s.should == "0.166666666666666667e3"
- end
-
# Check the top-level expression works as we expect
it "produces a BigDecimal" do
@@ -259,8 +225,8 @@ describe "Kernel#BigDecimal" do
end
it "produces the expected result" do
- @c.should == BigDecimal("-0.666667e-9")
- @c.to_s.should == "-0.666667e-9"
+ @c.round(15).should == BigDecimal("-0.666667e-9")
+ @c.round(15).to_s.should == "-0.666667e-9"
end
it "produces the correct class for other arithmetic operators" do
diff --git a/spec/ruby/library/bigdecimal/add_spec.rb b/spec/ruby/library/bigdecimal/add_spec.rb
index 542713011d..a4237298f4 100644
--- a/spec/ruby/library/bigdecimal/add_spec.rb
+++ b/spec/ruby/library/bigdecimal/add_spec.rb
@@ -73,14 +73,6 @@ describe "BigDecimal#add" do
# BigDecimal("0.88").add(0.0, 1).should == BigDecimal("0.9")
# end
- describe "with Object" do
- it "tries to coerce the other operand to self" do
- object = mock("Object")
- object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4])
- @frac_3.add(object, 1).should == BigDecimal("0.1E16")
- end
- end
-
describe "with Rational" do
it "produces a BigDecimal" do
(@three + Rational(500, 2)).should == BigDecimal("0.253e3")
@@ -173,21 +165,21 @@ describe "BigDecimal#add" do
it "raises TypeError when adds nil" do
-> {
@one.add(nil, 10)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
@one.add(nil, 0)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError when precision parameter is nil" do
-> {
@one.add(@one, nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises ArgumentError when precision parameter is negative" do
-> {
@one.add(@one, -10)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/ceil_spec.rb b/spec/ruby/library/bigdecimal/ceil_spec.rb
index 60e71b12fb..3d94b8e578 100644
--- a/spec/ruby/library/bigdecimal/ceil_spec.rb
+++ b/spec/ruby/library/bigdecimal/ceil_spec.rb
@@ -48,9 +48,9 @@ describe "BigDecimal#ceil" do
end
it "raise exception, if self is special value" do
- -> { @infinity.ceil }.should raise_error(FloatDomainError)
- -> { @infinity_neg.ceil }.should raise_error(FloatDomainError)
- -> { @nan.ceil }.should raise_error(FloatDomainError)
+ -> { @infinity.ceil }.should.raise(FloatDomainError)
+ -> { @infinity_neg.ceil }.should.raise(FloatDomainError)
+ -> { @nan.ceil }.should.raise(FloatDomainError)
end
it "returns n digits right of the decimal point if given n > 0" do
diff --git a/spec/ruby/library/bigdecimal/constants_spec.rb b/spec/ruby/library/bigdecimal/constants_spec.rb
index 8d879c036a..f2cc42dfc9 100644
--- a/spec/ruby/library/bigdecimal/constants_spec.rb
+++ b/spec/ruby/library/bigdecimal/constants_spec.rb
@@ -3,17 +3,17 @@ require 'bigdecimal'
describe "BigDecimal constants" do
it "defines a VERSION value" do
- BigDecimal.const_defined?(:VERSION).should be_true
+ BigDecimal.const_defined?(:VERSION).should == true
end
it "has a BASE value" do
# The actual one is decided based on HAVE_INT64_T in MRI,
# which is hard to check here.
- [10000, 1000000000].should include(BigDecimal::BASE)
+ [10000, 1000000000].should.include?(BigDecimal::BASE)
end
it "has a NaN value" do
- BigDecimal::NAN.nan?.should be_true
+ BigDecimal::NAN.nan?.should == true
end
it "has an INFINITY value" do
diff --git a/spec/ruby/library/bigdecimal/core_spec.rb b/spec/ruby/library/bigdecimal/core_spec.rb
index acee4dcf56..8f64fdf388 100644
--- a/spec/ruby/library/bigdecimal/core_spec.rb
+++ b/spec/ruby/library/bigdecimal/core_spec.rb
@@ -20,9 +20,12 @@ describe "Core extension by bigdecimal" do
describe "BigDecimal#log" do
it "handles high-precision Rational arguments" do
- result = BigDecimal('0.22314354220170971436137296411949880462556361100856391620766259404746040597133837784E0')
+ # log(BigDecimal(r, 50), 50)
+ result1 = BigDecimal('0.22314354220170971436137296411949880462556361100856e0')
+ # log(BigDecimal(r, 1000), 50)
+ result2 = BigDecimal('0.22314354220170971436137296411949880462556361100853e0')
r = Rational(1_234_567_890, 987_654_321)
- BigMath.log(r, 50).should == result
+ [result1, result2].should.include?(BigMath.log(r, 50).mult(1, 50))
end
end
@@ -30,15 +33,15 @@ describe "Core extension by bigdecimal" do
it "returns the passed argument, self as Float, when given a Float" do
result = Rational(3, 4).coerce(1.0)
result.should == [1.0, 0.75]
- result.first.is_a?(Float).should be_true
- result.last.is_a?(Float).should be_true
+ result.first.is_a?(Float).should == true
+ result.last.is_a?(Float).should == true
end
it "returns the passed argument, self as Rational, when given an Integer" do
result = Rational(3, 4).coerce(10)
result.should == [Rational(10, 1), Rational(3, 4)]
- result.first.is_a?(Rational).should be_true
- result.last.is_a?(Rational).should be_true
+ result.first.is_a?(Rational).should == true
+ result.last.is_a?(Rational).should == true
end
it "coerces to Rational, when given a Complex" do
@@ -53,7 +56,7 @@ describe "Core extension by bigdecimal" do
it "raises an error when passed a BigDecimal" do
-> {
Rational(500, 3).coerce(BigDecimal('166.666666666'))
- }.should raise_error(TypeError, /BigDecimal can't be coerced into Rational/)
+ }.should.raise(TypeError, /BigDecimal can't be coerced into Rational/)
end
end
end
diff --git a/spec/ruby/library/bigdecimal/div_spec.rb b/spec/ruby/library/bigdecimal/div_spec.rb
index 53ad6d0418..967d8b5221 100644
--- a/spec/ruby/library/bigdecimal/div_spec.rb
+++ b/spec/ruby/library/bigdecimal/div_spec.rb
@@ -51,9 +51,9 @@ describe "BigDecimal#div" do
end
it "raises FloatDomainError if NaN is involved" do
- -> { @one.div(@nan) }.should raise_error(FloatDomainError)
- -> { @nan.div(@one) }.should raise_error(FloatDomainError)
- -> { @nan.div(@nan) }.should raise_error(FloatDomainError)
+ -> { @one.div(@nan) }.should.raise(FloatDomainError)
+ -> { @nan.div(@one) }.should.raise(FloatDomainError)
+ -> { @nan.div(@nan) }.should.raise(FloatDomainError)
end
it "returns 0 if divided by Infinity and no precision given" do
@@ -69,14 +69,14 @@ describe "BigDecimal#div" do
end
it "raises ZeroDivisionError if divided by zero and no precision given" do
- -> { @one.div(@zero) }.should raise_error(ZeroDivisionError)
- -> { @one.div(@zero_plus) }.should raise_error(ZeroDivisionError)
- -> { @one.div(@zero_minus) }.should raise_error(ZeroDivisionError)
-
- -> { @zero.div(@zero) }.should raise_error(ZeroDivisionError)
- -> { @zero_minus.div(@zero_plus) }.should raise_error(ZeroDivisionError)
- -> { @zero_minus.div(@zero_minus) }.should raise_error(ZeroDivisionError)
- -> { @zero_plus.div(@zero_minus) }.should raise_error(ZeroDivisionError)
+ -> { @one.div(@zero) }.should.raise(ZeroDivisionError)
+ -> { @one.div(@zero_plus) }.should.raise(ZeroDivisionError)
+ -> { @one.div(@zero_minus) }.should.raise(ZeroDivisionError)
+
+ -> { @zero.div(@zero) }.should.raise(ZeroDivisionError)
+ -> { @zero_minus.div(@zero_plus) }.should.raise(ZeroDivisionError)
+ -> { @zero_minus.div(@zero_minus) }.should.raise(ZeroDivisionError)
+ -> { @zero_plus.div(@zero_minus) }.should.raise(ZeroDivisionError)
end
it "returns NaN if zero is divided by zero" do
@@ -90,9 +90,9 @@ describe "BigDecimal#div" do
end
it "raises FloatDomainError if (+|-) Infinity divided by 1 and no precision given" do
- -> { @infinity_minus.div(@one) }.should raise_error(FloatDomainError)
- -> { @infinity.div(@one) }.should raise_error(FloatDomainError)
- -> { @infinity_minus.div(@one_minus) }.should raise_error(FloatDomainError)
+ -> { @infinity_minus.div(@one) }.should.raise(FloatDomainError)
+ -> { @infinity.div(@one) }.should.raise(FloatDomainError)
+ -> { @infinity_minus.div(@one_minus) }.should.raise(FloatDomainError)
end
it "returns (+|-)Infinity if (+|-)Infinity by 1 and precision given" do
diff --git a/spec/ruby/library/bigdecimal/divmod_spec.rb b/spec/ruby/library/bigdecimal/divmod_spec.rb
index 294f01cba0..d170c6f845 100644
--- a/spec/ruby/library/bigdecimal/divmod_spec.rb
+++ b/spec/ruby/library/bigdecimal/divmod_spec.rb
@@ -33,14 +33,16 @@ describe "BigDecimal#mod_part_of_divmod" do
end
end
- it_behaves_like :bigdecimal_modulo, :mod_part_of_divmod
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it_behaves_like :bigdecimal_modulo, :mod_part_of_divmod
+ end
it "raises ZeroDivisionError if other is zero" do
bd5667 = BigDecimal("5667.19")
-
- -> { bd5667.mod_part_of_divmod(0) }.should raise_error(ZeroDivisionError)
- -> { bd5667.mod_part_of_divmod(BigDecimal("0")) }.should raise_error(ZeroDivisionError)
- -> { @zero.mod_part_of_divmod(@zero) }.should raise_error(ZeroDivisionError)
+ zero = BigDecimal("0")
+ -> { bd5667.mod_part_of_divmod(0) }.should.raise(ZeroDivisionError)
+ -> { bd5667.mod_part_of_divmod(BigDecimal("0")) }.should.raise(ZeroDivisionError)
+ -> { zero.mod_part_of_divmod(zero) }.should.raise(ZeroDivisionError)
end
end
@@ -73,14 +75,25 @@ describe "BigDecimal#divmod" do
@zeroes = [@zero, @zero_pos, @zero_neg]
end
- it "divides value, returns an array" do
- res = @a.divmod(5)
- res.kind_of?(Array).should == true
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it "divides value, returns [BigDecimal, BigDecimal]" do
+ res = @a.divmod(5)
+ res.kind_of?(Array).should == true
+ DivmodSpecs.check_both_bigdecimal(res)
+ end
+ end
+
+ version_is BigDecimal::VERSION, "4.0.0" do
+ it "divides value, returns [Integer, BigDecimal]" do
+ res = @a.divmod(5)
+ res.kind_of?(Array).should == true
+ res[0].kind_of?(Integer).should == true
+ res[1].kind_of?(BigDecimal).should == true
+ end
end
it "array contains quotient and modulus as BigDecimal" do
res = @a.divmod(5)
- DivmodSpecs.check_both_bigdecimal(res)
res[0].should == BigDecimal('0.8E1')
res[1].should == BigDecimal('2.00000000000000000001')
@@ -123,43 +136,62 @@ describe "BigDecimal#divmod" do
values_and_zeroes.each do |val1|
values.each do |val2|
res = val1.divmod(val2)
- DivmodSpecs.check_both_bigdecimal(res)
res[0].should == ((val1/val2).floor)
res[1].should == (val1 - res[0] * val2)
end
end
end
- it "returns an array of two NaNs if NaN is involved" do
- (@special_vals + @regular_vals + @zeroes).each do |val|
- DivmodSpecs.check_both_nan(val.divmod(@nan))
- DivmodSpecs.check_both_nan(@nan.divmod(val))
+ version_is BigDecimal::VERSION, "4.0.0" do
+ it "raise FloatDomainError error if NaN is involved" do
+ (@special_vals + @regular_vals + @zeroes).each do |val|
+ -> { val.divmod(@nan) }.should.raise(FloatDomainError)
+ -> { @nan.divmod(val) }.should.raise(FloatDomainError)
+ end
+ end
+ end
+
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it "returns an array of two NaNs if NaN is involved" do
+ (@special_vals + @regular_vals + @zeroes).each do |val|
+ DivmodSpecs.check_both_nan(val.divmod(@nan))
+ DivmodSpecs.check_both_nan(@nan.divmod(val))
+ end
end
end
it "raises ZeroDivisionError if the divisor is zero" do
(@special_vals + @regular_vals + @zeroes - [@nan]).each do |val|
@zeroes.each do |zero|
- -> { val.divmod(zero) }.should raise_error(ZeroDivisionError)
+ -> { val.divmod(zero) }.should.raise(ZeroDivisionError)
end
end
end
- it "returns an array of Infinity and NaN if the dividend is Infinity" do
- @regular_vals.each do |val|
- array = @infinity.divmod(val)
- array.length.should == 2
- array[0].infinite?.should == (val > 0 ? 1 : -1)
- array[1].should.nan?
+ version_is BigDecimal::VERSION, ""..."4.0.0" do
+ it "returns an array of Infinity and NaN if the dividend is Infinity" do
+ @regular_vals.each do |val|
+ array = @infinity.divmod(val)
+ array.length.should == 2
+ array[0].infinite?.should == (val > 0 ? 1 : -1)
+ array[1].should.nan?
+ end
end
end
- it "returns an array of zero and the dividend if the divisor is Infinity" do
- @regular_vals.each do |val|
- array = val.divmod(@infinity)
- array.length.should == 2
- array[0].should == @zero
- array[1].should == val
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "returns an array of zero and the dividend or minus one and Infinity if the divisor is Infinity" do
+ @regular_vals.each do |val|
+ array = val.divmod(@infinity)
+ array.length.should == 2
+ if val >= 0
+ array[0].should == @zero
+ array[1].should == val
+ else
+ array[0].should == @one_minus
+ array[1].should == @infinity
+ end
+ end
end
end
@@ -174,7 +206,7 @@ describe "BigDecimal#divmod" do
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
-> {
@one.divmod('1')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/bigdecimal/fix_spec.rb b/spec/ruby/library/bigdecimal/fix_spec.rb
index 2c6276899e..dceb2ce867 100644
--- a/spec/ruby/library/bigdecimal/fix_spec.rb
+++ b/spec/ruby/library/bigdecimal/fix_spec.rb
@@ -51,7 +51,7 @@ describe "BigDecimal#fix" do
it "does not allow any arguments" do
-> {
@mixed.fix(10)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/floor_spec.rb b/spec/ruby/library/bigdecimal/floor_spec.rb
index a7dfec2c9a..c0666c668c 100644
--- a/spec/ruby/library/bigdecimal/floor_spec.rb
+++ b/spec/ruby/library/bigdecimal/floor_spec.rb
@@ -41,9 +41,9 @@ describe "BigDecimal#floor" do
end
it "raise exception, if self is special value" do
- -> { @infinity.floor }.should raise_error(FloatDomainError)
- -> { @infinity_neg.floor }.should raise_error(FloatDomainError)
- -> { @nan.floor }.should raise_error(FloatDomainError)
+ -> { @infinity.floor }.should.raise(FloatDomainError)
+ -> { @infinity_neg.floor }.should.raise(FloatDomainError)
+ -> { @nan.floor }.should.raise(FloatDomainError)
end
it "returns n digits right of the decimal point if given n > 0" do
diff --git a/spec/ruby/library/bigdecimal/gt_spec.rb b/spec/ruby/library/bigdecimal/gt_spec.rb
index 78547fb85f..e9c9a60e75 100644
--- a/spec/ruby/library/bigdecimal/gt_spec.rb
+++ b/spec/ruby/library/bigdecimal/gt_spec.rb
@@ -86,11 +86,11 @@ describe "BigDecimal#>" do
end
it "raises an ArgumentError if the argument can't be coerced into a BigDecimal" do
- -> {@zero > nil }.should raise_error(ArgumentError)
- -> {@infinity > nil }.should raise_error(ArgumentError)
- -> {@infinity_neg > nil }.should raise_error(ArgumentError)
- -> {@mixed > nil }.should raise_error(ArgumentError)
- -> {@pos_int > nil }.should raise_error(ArgumentError)
- -> {@neg_frac > nil }.should raise_error(ArgumentError)
+ -> {@zero > nil }.should.raise(ArgumentError)
+ -> {@infinity > nil }.should.raise(ArgumentError)
+ -> {@infinity_neg > nil }.should.raise(ArgumentError)
+ -> {@mixed > nil }.should.raise(ArgumentError)
+ -> {@pos_int > nil }.should.raise(ArgumentError)
+ -> {@neg_frac > nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/gte_spec.rb b/spec/ruby/library/bigdecimal/gte_spec.rb
index 2a5cc025ba..548f3efe4c 100644
--- a/spec/ruby/library/bigdecimal/gte_spec.rb
+++ b/spec/ruby/library/bigdecimal/gte_spec.rb
@@ -90,11 +90,11 @@ describe "BigDecimal#>=" do
end
it "returns nil if the argument is nil" do
- -> {@zero >= nil }.should raise_error(ArgumentError)
- -> {@infinity >= nil }.should raise_error(ArgumentError)
- -> {@infinity_neg >= nil }.should raise_error(ArgumentError)
- -> {@mixed >= nil }.should raise_error(ArgumentError)
- -> {@pos_int >= nil }.should raise_error(ArgumentError)
- -> {@neg_frac >= nil }.should raise_error(ArgumentError)
+ -> {@zero >= nil }.should.raise(ArgumentError)
+ -> {@infinity >= nil }.should.raise(ArgumentError)
+ -> {@infinity_neg >= nil }.should.raise(ArgumentError)
+ -> {@mixed >= nil }.should.raise(ArgumentError)
+ -> {@pos_int >= nil }.should.raise(ArgumentError)
+ -> {@neg_frac >= nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/lt_spec.rb b/spec/ruby/library/bigdecimal/lt_spec.rb
index 02390e76e3..c3f3573247 100644
--- a/spec/ruby/library/bigdecimal/lt_spec.rb
+++ b/spec/ruby/library/bigdecimal/lt_spec.rb
@@ -84,11 +84,11 @@ describe "BigDecimal#<" do
end
it "raises an ArgumentError if the argument can't be coerced into a BigDecimal" do
- -> {@zero < nil }.should raise_error(ArgumentError)
- -> {@infinity < nil }.should raise_error(ArgumentError)
- -> {@infinity_neg < nil }.should raise_error(ArgumentError)
- -> {@mixed < nil }.should raise_error(ArgumentError)
- -> {@pos_int < nil }.should raise_error(ArgumentError)
- -> {@neg_frac < nil }.should raise_error(ArgumentError)
+ -> {@zero < nil }.should.raise(ArgumentError)
+ -> {@infinity < nil }.should.raise(ArgumentError)
+ -> {@infinity_neg < nil }.should.raise(ArgumentError)
+ -> {@mixed < nil }.should.raise(ArgumentError)
+ -> {@pos_int < nil }.should.raise(ArgumentError)
+ -> {@neg_frac < nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/lte_spec.rb b/spec/ruby/library/bigdecimal/lte_spec.rb
index b92be04123..7918bde88b 100644
--- a/spec/ruby/library/bigdecimal/lte_spec.rb
+++ b/spec/ruby/library/bigdecimal/lte_spec.rb
@@ -90,11 +90,11 @@ describe "BigDecimal#<=" do
end
it "raises an ArgumentError if the argument can't be coerced into a BigDecimal" do
- -> {@zero <= nil }.should raise_error(ArgumentError)
- -> {@infinity <= nil }.should raise_error(ArgumentError)
- -> {@infinity_neg <= nil }.should raise_error(ArgumentError)
- -> {@mixed <= nil }.should raise_error(ArgumentError)
- -> {@pos_int <= nil }.should raise_error(ArgumentError)
- -> {@neg_frac <= nil }.should raise_error(ArgumentError)
+ -> {@zero <= nil }.should.raise(ArgumentError)
+ -> {@infinity <= nil }.should.raise(ArgumentError)
+ -> {@infinity_neg <= nil }.should.raise(ArgumentError)
+ -> {@mixed <= nil }.should.raise(ArgumentError)
+ -> {@pos_int <= nil }.should.raise(ArgumentError)
+ -> {@neg_frac <= nil }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/bigdecimal/mode_spec.rb b/spec/ruby/library/bigdecimal/mode_spec.rb
index 73fa1a118e..26e6d0ea75 100644
--- a/spec/ruby/library/bigdecimal/mode_spec.rb
+++ b/spec/ruby/library/bigdecimal/mode_spec.rb
@@ -24,13 +24,13 @@ describe "BigDecimal.mode" do
it "raise an exception if the flag is true" do
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true)
- -> { BigDecimal("NaN").add(BigDecimal("1"),0) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("NaN").add(BigDecimal("1"),0) }.should.raise(FloatDomainError)
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true)
- -> { BigDecimal("0").add(BigDecimal("Infinity"),0) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("0").add(BigDecimal("Infinity"),0) }.should.raise(FloatDomainError)
BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, true)
- -> { BigDecimal("1").quo(BigDecimal("0")) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("1").quo(BigDecimal("0")) }.should.raise(FloatDomainError)
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true)
- -> { BigDecimal("1E11111111111111111111") }.should raise_error(FloatDomainError)
- -> { (BigDecimal("1E1000000000000000000")**10) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("1E11111111111111111111") }.should.raise(FloatDomainError)
+ -> { (BigDecimal("1E1000000000000000000")**10) }.should.raise(FloatDomainError)
end
end
diff --git a/spec/ruby/library/bigdecimal/mult_spec.rb b/spec/ruby/library/bigdecimal/mult_spec.rb
index b7f8044b0b..2353df9cb8 100644
--- a/spec/ruby/library/bigdecimal/mult_spec.rb
+++ b/spec/ruby/library/bigdecimal/mult_spec.rb
@@ -21,12 +21,4 @@ describe "BigDecimal#mult" do
@e.mult(@one, 1).should be_close(@one, @tolerance)
@e3_minus.mult(@one, 1).should be_close(0, @tolerance2)
end
-
- describe "with Object" do
- it "tries to coerce the other operand to self" do
- object = mock("Object")
- object.should_receive(:coerce).with(@e3_minus).and_return([@e3_minus, @e3_plus])
- @e3_minus.mult(object, 1).should == BigDecimal("9")
- end
- end
end
diff --git a/spec/ruby/library/bigdecimal/nonzero_spec.rb b/spec/ruby/library/bigdecimal/nonzero_spec.rb
index f43c4393cd..31421ebdf4 100644
--- a/spec/ruby/library/bigdecimal/nonzero_spec.rb
+++ b/spec/ruby/library/bigdecimal/nonzero_spec.rb
@@ -10,11 +10,11 @@ describe "BigDecimal#nonzero?" do
infinity = BigDecimal("Infinity")
infinity_minus = BigDecimal("-Infinity")
nan = BigDecimal("NaN")
- infinity.nonzero?.should equal(infinity)
- infinity_minus.nonzero?.should equal(infinity_minus)
- nan.nonzero?.should equal(nan)
- e3_minus.nonzero?.should equal(e3_minus)
- e2_plus.nonzero?.should equal(e2_plus)
+ infinity.nonzero?.should.equal?(infinity)
+ infinity_minus.nonzero?.should.equal?(infinity_minus)
+ nan.nonzero?.should.equal?(nan)
+ e3_minus.nonzero?.should.equal?(e3_minus)
+ e2_plus.nonzero?.should.equal?(e2_plus)
end
it "returns nil otherwise" do
diff --git a/spec/ruby/library/bigdecimal/precs_spec.rb b/spec/ruby/library/bigdecimal/precs_spec.rb
deleted file mode 100644
index 5fda8d3087..0000000000
--- a/spec/ruby/library/bigdecimal/precs_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-require_relative '../../spec_helper'
-require 'bigdecimal'
-
-describe "BigDecimal#precs" do
- before :each do
- @infinity = BigDecimal("Infinity")
- @infinity_neg = BigDecimal("-Infinity")
- @nan = BigDecimal("NaN")
- @zero = BigDecimal("0")
- @zero_neg = BigDecimal("-0")
-
- @arr = [BigDecimal("2E40001"), BigDecimal("3E-20001"),\
- @infinity, @infinity_neg, @nan, @zero, @zero_neg]
- @precision = BigDecimal::BASE.to_s.length - 1
- end
-
- it "returns array of two values" do
- suppress_warning do
- @arr.each do |x|
- x.precs.kind_of?(Array).should == true
- x.precs.size.should == 2
- end
- end
- end
-
- it "returns Integers as array values" do
- suppress_warning do
- @arr.each do |x|
- x.precs[0].kind_of?(Integer).should == true
- x.precs[1].kind_of?(Integer).should == true
- end
- end
- end
-
- it "returns the current value of significant digits as the first value" do
- suppress_warning do
- BigDecimal("3.14159").precs[0].should >= 6
- BigDecimal('1').precs[0].should == BigDecimal('1' + '0' * 100).precs[0]
- [@infinity, @infinity_neg, @nan, @zero, @zero_neg].each do |value|
- value.precs[0].should <= @precision
- end
- end
- end
-
- it "returns the maximum number of significant digits as the second value" do
- suppress_warning do
- BigDecimal("3.14159").precs[1].should >= 6
- BigDecimal('1').precs[1].should >= 1
- BigDecimal('1' + '0' * 100).precs[1].should >= 101
- [@infinity, @infinity_neg, @nan, @zero, @zero_neg].each do |value|
- value.precs[1].should >= 1
- end
- end
- end
-end
diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb
index bac5f37ba9..27a2986570 100644
--- a/spec/ruby/library/bigdecimal/remainder_spec.rb
+++ b/spec/ruby/library/bigdecimal/remainder_spec.rb
@@ -37,9 +37,11 @@ describe "BigDecimal#remainder" do
@neg_int.remainder(@pos_frac).should == @neg_int - @pos_frac * (@neg_int / @pos_frac).truncate
end
- it "returns NaN used with zero" do
- @mixed.remainder(@zero).should.nan?
- @zero.remainder(@zero).should.nan?
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "raises ZeroDivisionError used with zero" do
+ -> { @mixed.remainder(@zero) }.should.raise(ZeroDivisionError)
+ -> { @zero.remainder(@zero) }.should.raise(ZeroDivisionError)
+ end
end
it "returns zero if used on zero" do
@@ -54,25 +56,6 @@ describe "BigDecimal#remainder" do
@nan.remainder(@infinity).should.nan?
end
- version_is BigDecimal::VERSION, ""..."3.1.4" do #ruby_version_is ""..."3.3" do
- it "returns NaN if Infinity is involved" do
- @infinity.remainder(@infinity).should.nan?
- @infinity.remainder(@one).should.nan?
- @infinity.remainder(@mixed).should.nan?
- @infinity.remainder(@one_minus).should.nan?
- @infinity.remainder(@frac_1).should.nan?
- @one.remainder(@infinity).should.nan?
-
- @infinity_minus.remainder(@infinity_minus).should.nan?
- @infinity_minus.remainder(@one).should.nan?
- @one.remainder(@infinity_minus).should.nan?
- @frac_2.remainder(@infinity_minus).should.nan?
-
- @infinity.remainder(@infinity_minus).should.nan?
- @infinity_minus.remainder(@infinity).should.nan?
- end
- end
-
it "coerces arguments to BigDecimal if possible" do
@three.remainder(2).should == @one
end
@@ -88,7 +71,7 @@ describe "BigDecimal#remainder" do
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
-> {
@one.remainder('2')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/bigdecimal/round_spec.rb b/spec/ruby/library/bigdecimal/round_spec.rb
index fba52df65d..622e129d93 100644
--- a/spec/ruby/library/bigdecimal/round_spec.rb
+++ b/spec/ruby/library/bigdecimal/round_spec.rb
@@ -217,26 +217,18 @@ describe "BigDecimal#round" do
end
it 'raise exception, if self is special value' do
- -> { BigDecimal('NaN').round }.should raise_error(FloatDomainError)
- -> { BigDecimal('Infinity').round }.should raise_error(FloatDomainError)
- -> { BigDecimal('-Infinity').round }.should raise_error(FloatDomainError)
+ -> { BigDecimal('NaN').round }.should.raise(FloatDomainError)
+ -> { BigDecimal('Infinity').round }.should.raise(FloatDomainError)
+ -> { BigDecimal('-Infinity').round }.should.raise(FloatDomainError)
end
it 'do not raise exception, if self is special value and precision is given' do
- -> { BigDecimal('NaN').round(2) }.should_not raise_error(FloatDomainError)
- -> { BigDecimal('Infinity').round(2) }.should_not raise_error(FloatDomainError)
- -> { BigDecimal('-Infinity').round(2) }.should_not raise_error(FloatDomainError)
+ -> { BigDecimal('NaN').round(2) }.should_not.raise(FloatDomainError)
+ -> { BigDecimal('Infinity').round(2) }.should_not.raise(FloatDomainError)
+ -> { BigDecimal('-Infinity').round(2) }.should_not.raise(FloatDomainError)
end
- version_is BigDecimal::VERSION, ''...'3.1.3' do #ruby_version_is ''...'3.2' do
- it 'raise for a non-existent round mode' do
- -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode")
- end
- end
-
- version_is BigDecimal::VERSION, '3.1.3' do #ruby_version_is '3.2' do
- it 'raise for a non-existent round mode' do
- -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode (nonsense)")
- end
+ it 'raise for a non-existent round mode' do
+ -> { @p1_50.round(0, :nonsense) }.should.raise(ArgumentError, "invalid rounding mode (nonsense)")
end
end
diff --git a/spec/ruby/library/bigdecimal/shared/clone.rb b/spec/ruby/library/bigdecimal/shared/clone.rb
index 935ef76e7e..03de6d0fc3 100644
--- a/spec/ruby/library/bigdecimal/shared/clone.rb
+++ b/spec/ruby/library/bigdecimal/shared/clone.rb
@@ -8,6 +8,6 @@ describe :bigdecimal_clone, shared: true do
it "returns self" do
copy = @obj.public_send(@method)
- copy.should equal(@obj)
+ copy.should.equal?(@obj)
end
end
diff --git a/spec/ruby/library/bigdecimal/shared/modulo.rb b/spec/ruby/library/bigdecimal/shared/modulo.rb
index aa5c5a640b..63470d0977 100644
--- a/spec/ruby/library/bigdecimal/shared/modulo.rb
+++ b/spec/ruby/library/bigdecimal/shared/modulo.rb
@@ -101,16 +101,22 @@ describe :bigdecimal_modulo, shared: true do
@infinity_minus.send(@method, @infinity).should.nan?
end
- it "returns the dividend if the divisor is Infinity" do
- @one.send(@method, @infinity).should == @one
- @one.send(@method, @infinity_minus).should == @one
- @frac_2.send(@method, @infinity_minus).should == @frac_2
+ version_is BigDecimal::VERSION, "3.3.0" do
+ it "returns the dividend if the divisor is Infinity and signs are same" do
+ @one.send(@method, @infinity).should == @one
+ (-@frac_2).send(@method, @infinity_minus).should == -@frac_2
+ end
+
+ it "returns the divisor if the divisor is Infinity and signs are different" do
+ (-@one).send(@method, @infinity).should == @infinity
+ @frac_2.send(@method, @infinity_minus).should == @infinity_minus
+ end
end
it "raises TypeError if the argument cannot be coerced to BigDecimal" do
-> {
@one.send(@method, '2')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -118,8 +124,8 @@ describe :bigdecimal_modulo_zerodivisionerror, shared: true do
it "raises ZeroDivisionError if other is zero" do
bd5667 = BigDecimal("5667.19")
- -> { bd5667.send(@method, 0) }.should raise_error(ZeroDivisionError)
- -> { bd5667.send(@method, BigDecimal("0")) }.should raise_error(ZeroDivisionError)
- -> { @zero.send(@method, @zero) }.should raise_error(ZeroDivisionError)
+ -> { bd5667.send(@method, 0) }.should.raise(ZeroDivisionError)
+ -> { bd5667.send(@method, BigDecimal("0")) }.should.raise(ZeroDivisionError)
+ -> { @zero.send(@method, @zero) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/bigdecimal/shared/power.rb b/spec/ruby/library/bigdecimal/shared/power.rb
index 568a08589b..6dafb638e2 100644
--- a/spec/ruby/library/bigdecimal/shared/power.rb
+++ b/spec/ruby/library/bigdecimal/shared/power.rb
@@ -10,8 +10,8 @@ describe :bigdecimal_power, shared: true do
e = BigDecimal("1.00000000000000000000123456789")
one = BigDecimal("1")
ten = BigDecimal("10")
- # The tolerance is dependent upon the size of BASE_FIG
- tolerance = BigDecimal("1E-70")
+ # Accuracy is at least ndigits(== 30) + DOUBLE_FIG(== 16)
+ tolerance = BigDecimal("1E-46")
ten_powers = BigDecimal("1E10000")
pi = BigDecimal("3.14159265358979")
e3_minus.send(@method, 2).should == e3_minus_power_2
diff --git a/spec/ruby/library/bigdecimal/shared/quo.rb b/spec/ruby/library/bigdecimal/shared/quo.rb
index 46e6d62bf4..18ff2fe9a5 100644
--- a/spec/ruby/library/bigdecimal/shared/quo.rb
+++ b/spec/ruby/library/bigdecimal/shared/quo.rb
@@ -31,6 +31,7 @@ describe :bigdecimal_quo, shared: true do
describe "with Object" do
it "tries to coerce the other operand to self" do
+ skip if @method == :div
object = mock("Object")
object.should_receive(:coerce).with(@one).and_return([@one, @two])
@one.send(@method, object, *@object).should == BigDecimal("0.5")
diff --git a/spec/ruby/library/bigdecimal/shared/to_int.rb b/spec/ruby/library/bigdecimal/shared/to_int.rb
index 44b6a3c7b2..3c9f3b4f97 100644
--- a/spec/ruby/library/bigdecimal/shared/to_int.rb
+++ b/spec/ruby/library/bigdecimal/shared/to_int.rb
@@ -2,8 +2,8 @@ require 'bigdecimal'
describe :bigdecimal_to_int, shared: true do
it "raises FloatDomainError if BigDecimal is infinity or NaN" do
- -> { BigDecimal("Infinity").send(@method) }.should raise_error(FloatDomainError)
- -> { BigDecimal("NaN").send(@method) }.should raise_error(FloatDomainError)
+ -> { BigDecimal("Infinity").send(@method) }.should.raise(FloatDomainError)
+ -> { BigDecimal("NaN").send(@method) }.should.raise(FloatDomainError)
end
it "returns Integer otherwise" do
diff --git a/spec/ruby/library/bigdecimal/sqrt_spec.rb b/spec/ruby/library/bigdecimal/sqrt_spec.rb
index 42cf4545cb..1f3ef9a8c3 100644
--- a/spec/ruby/library/bigdecimal/sqrt_spec.rb
+++ b/spec/ruby/library/bigdecimal/sqrt_spec.rb
@@ -45,37 +45,37 @@ describe "BigDecimal#sqrt" do
it "raises ArgumentError when no argument is given" do
-> {
@one.sqrt
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if a negative number is given" do
-> {
@one.sqrt(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises ArgumentError if 2 arguments are given" do
-> {
@one.sqrt(1, 1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises TypeError if nil is given" do
-> {
@one.sqrt(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if a string is given" do
-> {
@one.sqrt("stuff")
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises TypeError if a plain Object is given" do
-> {
@one.sqrt(Object.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "returns 1 if precision is 0 or 1" do
@@ -86,7 +86,7 @@ describe "BigDecimal#sqrt" do
it "raises FloatDomainError on negative values" do
-> {
BigDecimal('-1').sqrt(10)
- }.should raise_error(FloatDomainError)
+ }.should.raise(FloatDomainError)
end
it "returns positive infinity for infinity" do
@@ -96,13 +96,13 @@ describe "BigDecimal#sqrt" do
it "raises FloatDomainError for negative infinity" do
-> {
@infinity_minus.sqrt(1)
- }.should raise_error(FloatDomainError)
+ }.should.raise(FloatDomainError)
end
it "raises FloatDomainError for NaN" do
-> {
@nan.sqrt(1)
- }.should raise_error(FloatDomainError)
+ }.should.raise(FloatDomainError)
end
it "returns 0 for 0, +0.0 and -0.0" do
diff --git a/spec/ruby/library/bigdecimal/sub_spec.rb b/spec/ruby/library/bigdecimal/sub_spec.rb
index bddfec2186..3b62a0c794 100644
--- a/spec/ruby/library/bigdecimal/sub_spec.rb
+++ b/spec/ruby/library/bigdecimal/sub_spec.rb
@@ -35,14 +35,6 @@ describe "BigDecimal#sub" do
@frac_1.sub(@frac_1, 1000000).should == @zero
end
- describe "with Object" do
- it "tries to coerce the other operand to self" do
- object = mock("Object")
- object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4])
- @frac_3.sub(object, 1).should == BigDecimal("-0.9E15")
- end
- end
-
describe "with Rational" do
it "produces a BigDecimal" do
(@three - Rational(500, 2)).should == BigDecimal('-0.247e3')
diff --git a/spec/ruby/library/bigdecimal/to_f_spec.rb b/spec/ruby/library/bigdecimal/to_f_spec.rb
index 84d4d49de2..f5220d995a 100644
--- a/spec/ruby/library/bigdecimal/to_f_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_f_spec.rb
@@ -20,9 +20,9 @@ describe "BigDecimal#to_f" do
end
it "returns number of type float" do
- BigDecimal("3.14159").to_f.should be_kind_of(Float)
- @vals.each { |val| val.to_f.should be_kind_of(Float) }
- @spec_vals.each { |val| val.to_f.should be_kind_of(Float) }
+ BigDecimal("3.14159").to_f.should.is_a?(Float)
+ @vals.each { |val| val.to_f.should.is_a?(Float) }
+ @spec_vals.each { |val| val.to_f.should.is_a?(Float) }
end
it "rounds correctly to Float precision" do
diff --git a/spec/ruby/library/bigdecimal/to_r_spec.rb b/spec/ruby/library/bigdecimal/to_r_spec.rb
index c350beff08..a112c002ef 100644
--- a/spec/ruby/library/bigdecimal/to_r_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_r_spec.rb
@@ -4,25 +4,25 @@ require 'bigdecimal'
describe "BigDecimal#to_r" do
it "returns a Rational" do
- BigDecimal("3.14159").to_r.should be_kind_of(Rational)
+ BigDecimal("3.14159").to_r.should.is_a?(Rational)
end
it "returns a Rational with bignum values" do
r = BigDecimal("3.141592653589793238462643").to_r
- r.numerator.should eql(3141592653589793238462643)
- r.denominator.should eql(1000000000000000000000000)
+ r.numerator.should.eql?(3141592653589793238462643)
+ r.denominator.should.eql?(1000000000000000000000000)
end
it "returns a Rational from a BigDecimal with an exponent" do
r = BigDecimal("1E2").to_r
- r.numerator.should eql(100)
- r.denominator.should eql(1)
+ r.numerator.should.eql?(100)
+ r.denominator.should.eql?(1)
end
it "returns a Rational from a negative BigDecimal with an exponent" do
r = BigDecimal("-1E2").to_r
- r.numerator.should eql(-100)
- r.denominator.should eql(1)
+ r.numerator.should.eql?(-100)
+ r.denominator.should.eql?(1)
end
end
diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb
index ba9f960eb3..5ec54765b5 100644
--- a/spec/ruby/library/bigdecimal/to_s_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_s_spec.rb
@@ -31,7 +31,7 @@ describe "BigDecimal#to_s" do
end
it "takes an optional argument" do
- -> {@bigdec.to_s("F")}.should_not raise_error()
+ -> {@bigdec.to_s("F")}.should_not.raise()
end
it "starts with + if + is supplied and value is positive" do
@@ -52,10 +52,8 @@ describe "BigDecimal#to_s" do
BigDecimal("1.2345").to_s('0F').should == "1.2345"
end
- version_is BigDecimal::VERSION, "3.1.5" do #ruby_version_is '3.3' do
- it "inserts a space every n chars to integer part, if integer n is supplied" do
- BigDecimal('1000010').to_s('5F').should == "10 00010.0"
- end
+ it "inserts a space every n chars to integer part, if integer n is supplied" do
+ BigDecimal('1000010').to_s('5F').should == "10 00010.0"
end
it "can return a leading space for values > 0" do
@@ -90,11 +88,11 @@ describe "BigDecimal#to_s" do
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
+ BigDecimal('1.23').to_s.encoding.should.equal?(Encoding::US_ASCII)
end
it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
Encoding.default_internal = Encoding::IBM437
- BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
+ BigDecimal('1.23').to_s.encoding.should.equal?(Encoding::US_ASCII)
end
end
diff --git a/spec/ruby/library/bigdecimal/truncate_spec.rb b/spec/ruby/library/bigdecimal/truncate_spec.rb
index 0ae0421b30..cedc662aeb 100644
--- a/spec/ruby/library/bigdecimal/truncate_spec.rb
+++ b/spec/ruby/library/bigdecimal/truncate_spec.rb
@@ -74,8 +74,8 @@ describe "BigDecimal#truncate" do
end
it "returns the same value if self is special value" do
- -> { @nan.truncate }.should raise_error(FloatDomainError)
- -> { @infinity.truncate }.should raise_error(FloatDomainError)
- -> { @infinity_negative.truncate }.should raise_error(FloatDomainError)
+ -> { @nan.truncate }.should.raise(FloatDomainError)
+ -> { @infinity.truncate }.should.raise(FloatDomainError)
+ -> { @infinity_negative.truncate }.should.raise(FloatDomainError)
end
end
diff --git a/spec/ruby/library/bigdecimal/util_spec.rb b/spec/ruby/library/bigdecimal/util_spec.rb
index fc67fcf200..69663d4bd2 100644
--- a/spec/ruby/library/bigdecimal/util_spec.rb
+++ b/spec/ruby/library/bigdecimal/util_spec.rb
@@ -20,7 +20,7 @@ describe "BigDecimal's util method definitions" do
it "should define #to_d on BigDecimal" do
bd = BigDecimal("3.14")
- bd.to_d.should equal(bd)
+ bd.to_d.should.equal?(bd)
end
it "should define #to_d on Rational" do
diff --git a/spec/ruby/library/cgi/cookie/domain_spec.rb b/spec/ruby/library/cgi/cookie/domain_spec.rb
index 962609ebaf..c118ef6383 100644
--- a/spec/ruby/library/cgi/cookie/domain_spec.rb
+++ b/spec/ruby/library/cgi/cookie/domain_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#domain" do
- it "returns self's domain" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.domain.should be_nil
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- cookie = CGI::Cookie.new("name" => "test-cookie", "domain" => "example.com")
- cookie.domain.should == "example.com"
+ describe "CGI::Cookie#domain" do
+ it "returns self's domain" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.domain.should == nil
+
+ cookie = CGI::Cookie.new("name" => "test-cookie", "domain" => "example.com")
+ cookie.domain.should == "example.com"
+ end
end
-end
-describe "CGI::Cookie#domain=" do
- it "sets self's domain" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.domain = "test.com"
- cookie.domain.should == "test.com"
+ describe "CGI::Cookie#domain=" do
+ it "sets self's domain" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.domain = "test.com"
+ cookie.domain.should == "test.com"
- cookie.domain = "example.com"
- cookie.domain.should == "example.com"
+ cookie.domain = "example.com"
+ cookie.domain.should == "example.com"
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/expires_spec.rb b/spec/ruby/library/cgi/cookie/expires_spec.rb
index c8f26d01cd..b9cc7d5b65 100644
--- a/spec/ruby/library/cgi/cookie/expires_spec.rb
+++ b/spec/ruby/library/cgi/cookie/expires_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#expires" do
- it "returns self's expiration date" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.expires.should be_nil
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- cookie = CGI::Cookie.new("name" => "test-cookie", "expires" => Time.at(1196524602))
- cookie.expires.should == Time.at(1196524602)
+ describe "CGI::Cookie#expires" do
+ it "returns self's expiration date" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.expires.should == nil
+
+ cookie = CGI::Cookie.new("name" => "test-cookie", "expires" => Time.at(1196524602))
+ cookie.expires.should == Time.at(1196524602)
+ end
end
-end
-describe "CGI::Cookie#expires=" do
- it "sets self's expiration date" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.expires = Time.at(1196524602)
- cookie.expires.should == Time.at(1196524602)
+ describe "CGI::Cookie#expires=" do
+ it "sets self's expiration date" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.expires = Time.at(1196524602)
+ cookie.expires.should == Time.at(1196524602)
- cookie.expires = Time.at(1196525000)
- cookie.expires.should == Time.at(1196525000)
+ cookie.expires = Time.at(1196525000)
+ cookie.expires.should == Time.at(1196525000)
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/initialize_spec.rb b/spec/ruby/library/cgi/cookie/initialize_spec.rb
index 4b6e104b10..80bc2c2196 100644
--- a/spec/ruby/library/cgi/cookie/initialize_spec.rb
+++ b/spec/ruby/library/cgi/cookie/initialize_spec.rb
@@ -1,147 +1,150 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#initialize when passed String" do
- before :each do
- @cookie = CGI::Cookie.allocate
- end
-
- it "sets the self's name to the passed String" do
- @cookie.send(:initialize, "test-cookie")
- @cookie.name.should == "test-cookie"
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- it "sets the self's value to an empty Array" do
- @cookie.send(:initialize, "test-cookie")
- @cookie.value.should == []
- end
-
- it "sets self to a non-secure cookie" do
- @cookie.send(:initialize, "test")
- @cookie.secure.should be_false
- end
-
- it "does set self's path to an empty String when ENV[\"SCRIPT_NAME\"] is not set" do
- @cookie.send(:initialize, "test-cookie")
- @cookie.path.should == ""
- end
-
- it "does set self's path based on ENV[\"SCRIPT_NAME\"] when ENV[\"SCRIPT_NAME\"] is set" do
- old_script_name = ENV["SCRIPT_NAME"]
+ describe "CGI::Cookie#initialize when passed String" do
+ before :each do
+ @cookie = CGI::Cookie.allocate
+ end
- begin
- ENV["SCRIPT_NAME"] = "some/path/script.rb"
+ it "sets the self's name to the passed String" do
@cookie.send(:initialize, "test-cookie")
- @cookie.path.should == "some/path/"
+ @cookie.name.should == "test-cookie"
+ end
- ENV["SCRIPT_NAME"] = "script.rb"
+ it "sets the self's value to an empty Array" do
@cookie.send(:initialize, "test-cookie")
- @cookie.path.should == ""
+ @cookie.value.should == []
+ end
- ENV["SCRIPT_NAME"] = nil
+ it "sets self to a non-secure cookie" do
+ @cookie.send(:initialize, "test")
+ @cookie.secure.should == false
+ end
+
+ it "does set self's path to an empty String when ENV[\"SCRIPT_NAME\"] is not set" do
@cookie.send(:initialize, "test-cookie")
@cookie.path.should == ""
- ensure
- ENV["SCRIPT_NAME"] = old_script_name
end
- end
- it "does not set self's expiration date" do
- @cookie.expires.should be_nil
- end
+ it "does set self's path based on ENV[\"SCRIPT_NAME\"] when ENV[\"SCRIPT_NAME\"] is set" do
+ old_script_name = ENV["SCRIPT_NAME"]
- it "does not set self's domain" do
- @cookie.domain.should be_nil
- end
-end
+ begin
+ ENV["SCRIPT_NAME"] = "some/path/script.rb"
+ @cookie.send(:initialize, "test-cookie")
+ @cookie.path.should == "some/path/"
-describe "CGI::Cookie#initialize when passed Hash" do
- before :each do
- @cookie = CGI::Cookie.allocate
- end
+ ENV["SCRIPT_NAME"] = "script.rb"
+ @cookie.send(:initialize, "test-cookie")
+ @cookie.path.should == ""
+
+ ENV["SCRIPT_NAME"] = nil
+ @cookie.send(:initialize, "test-cookie")
+ @cookie.path.should == ""
+ ensure
+ ENV["SCRIPT_NAME"] = old_script_name
+ end
+ end
+
+ it "does not set self's expiration date" do
+ @cookie.expires.should == nil
+ end
- it "sets self's contents based on the passed Hash" do
- @cookie.send(:initialize,
- 'name' => 'test-cookie',
- 'value' => ["one", "two", "three"],
- 'path' => 'some/path/',
- 'domain' => 'example.com',
- 'expires' => Time.at(1196524602),
- 'secure' => true)
-
- @cookie.name.should == "test-cookie"
- @cookie.value.should == ["one", "two", "three"]
- @cookie.path.should == "some/path/"
- @cookie.domain.should == "example.com"
- @cookie.expires.should == Time.at(1196524602)
- @cookie.secure.should be_true
+ it "does not set self's domain" do
+ @cookie.domain.should == nil
+ end
end
- it "does set self's path based on ENV[\"SCRIPT_NAME\"] when the Hash has no 'path' entry" do
- old_script_name = ENV["SCRIPT_NAME"]
+ describe "CGI::Cookie#initialize when passed Hash" do
+ before :each do
+ @cookie = CGI::Cookie.allocate
+ end
- begin
- ENV["SCRIPT_NAME"] = "some/path/script.rb"
- @cookie.send(:initialize, 'name' => 'test-cookie')
+ it "sets self's contents based on the passed Hash" do
+ @cookie.send(:initialize,
+ 'name' => 'test-cookie',
+ 'value' => ["one", "two", "three"],
+ 'path' => 'some/path/',
+ 'domain' => 'example.com',
+ 'expires' => Time.at(1196524602),
+ 'secure' => true)
+
+ @cookie.name.should == "test-cookie"
+ @cookie.value.should == ["one", "two", "three"]
@cookie.path.should == "some/path/"
+ @cookie.domain.should == "example.com"
+ @cookie.expires.should == Time.at(1196524602)
+ @cookie.secure.should == true
+ end
- ENV["SCRIPT_NAME"] = "script.rb"
- @cookie.send(:initialize, 'name' => 'test-cookie')
- @cookie.path.should == ""
+ it "does set self's path based on ENV[\"SCRIPT_NAME\"] when the Hash has no 'path' entry" do
+ old_script_name = ENV["SCRIPT_NAME"]
- ENV["SCRIPT_NAME"] = nil
- @cookie.send(:initialize, 'name' => 'test-cookie')
- @cookie.path.should == ""
- ensure
- ENV["SCRIPT_NAME"] = old_script_name
+ begin
+ ENV["SCRIPT_NAME"] = "some/path/script.rb"
+ @cookie.send(:initialize, 'name' => 'test-cookie')
+ @cookie.path.should == "some/path/"
+
+ ENV["SCRIPT_NAME"] = "script.rb"
+ @cookie.send(:initialize, 'name' => 'test-cookie')
+ @cookie.path.should == ""
+
+ ENV["SCRIPT_NAME"] = nil
+ @cookie.send(:initialize, 'name' => 'test-cookie')
+ @cookie.path.should == ""
+ ensure
+ ENV["SCRIPT_NAME"] = old_script_name
+ end
end
- end
- it "tries to convert the Hash's 'value' to an Array using #Array" do
- obj = mock("Converted To Array")
- obj.should_receive(:to_ary).and_return(["1", "2", "3"])
- @cookie.send(:initialize,
- 'name' => 'test-cookie',
- 'value' => obj)
- @cookie.value.should == [ "1", "2", "3" ]
-
- obj = mock("Converted To Array")
- obj.should_receive(:to_a).and_return(["one", "two", "three"])
- @cookie.send(:initialize,
- 'name' => 'test-cookie',
- 'value' => obj)
- @cookie.value.should == [ "one", "two", "three" ]
-
- obj = mock("Put into an Array")
- @cookie.send(:initialize,
- 'name' => 'test-cookie',
- 'value' => obj)
- @cookie.value.should == [ obj ]
- end
+ it "tries to convert the Hash's 'value' to an Array using #Array" do
+ obj = mock("Converted To Array")
+ obj.should_receive(:to_ary).and_return(["1", "2", "3"])
+ @cookie.send(:initialize,
+ 'name' => 'test-cookie',
+ 'value' => obj)
+ @cookie.value.should == [ "1", "2", "3" ]
+
+ obj = mock("Converted To Array")
+ obj.should_receive(:to_a).and_return(["one", "two", "three"])
+ @cookie.send(:initialize,
+ 'name' => 'test-cookie',
+ 'value' => obj)
+ @cookie.value.should == [ "one", "two", "three" ]
+
+ obj = mock("Put into an Array")
+ @cookie.send(:initialize,
+ 'name' => 'test-cookie',
+ 'value' => obj)
+ @cookie.value.should == [ obj ]
+ end
- it "raises a ArgumentError when the passed Hash has no 'name' entry" do
- -> { @cookie.send(:initialize, {}) }.should raise_error(ArgumentError)
- -> { @cookie.send(:initialize, "value" => "test") }.should raise_error(ArgumentError)
+ it "raises a ArgumentError when the passed Hash has no 'name' entry" do
+ -> { @cookie.send(:initialize, {}) }.should.raise(ArgumentError)
+ -> { @cookie.send(:initialize, "value" => "test") }.should.raise(ArgumentError)
+ end
end
-end
-describe "CGI::Cookie#initialize when passed String, values ..." do
- before :each do
- @cookie = CGI::Cookie.allocate
- end
+ describe "CGI::Cookie#initialize when passed String, values ..." do
+ before :each do
+ @cookie = CGI::Cookie.allocate
+ end
- it "sets the self's name to the passed String" do
- @cookie.send(:initialize, "test-cookie", "one", "two", "three")
- @cookie.name.should == "test-cookie"
- end
+ it "sets the self's name to the passed String" do
+ @cookie.send(:initialize, "test-cookie", "one", "two", "three")
+ @cookie.name.should == "test-cookie"
+ end
- it "sets the self's value to an Array containing all passed values" do
- @cookie.send(:initialize, "test-cookie", "one", "two", "three")
- @cookie.value.should == ["one", "two", "three"]
- end
+ it "sets the self's value to an Array containing all passed values" do
+ @cookie.send(:initialize, "test-cookie", "one", "two", "three")
+ @cookie.value.should == ["one", "two", "three"]
+ end
- it "sets self to a non-secure cookie" do
- @cookie.send(:initialize, "test", "one", "two", "three")
- @cookie.secure.should be_false
+ it "sets self to a non-secure cookie" do
+ @cookie.send(:initialize, "test", "one", "two", "three")
+ @cookie.secure.should == false
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/name_spec.rb b/spec/ruby/library/cgi/cookie/name_spec.rb
index 326a43ade3..4908204e8a 100644
--- a/spec/ruby/library/cgi/cookie/name_spec.rb
+++ b/spec/ruby/library/cgi/cookie/name_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#name" do
- it "returns self's name" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.name.should == "test-cookie"
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- cookie = CGI::Cookie.new("name" => "another-cookie")
- cookie.name.should == "another-cookie"
+ describe "CGI::Cookie#name" do
+ it "returns self's name" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.name.should == "test-cookie"
+
+ cookie = CGI::Cookie.new("name" => "another-cookie")
+ cookie.name.should == "another-cookie"
+ end
end
-end
-describe "CGI::Cookie#name=" do
- it "sets self's expiration date" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.name = "another-name"
- cookie.name.should == "another-name"
+ describe "CGI::Cookie#name=" do
+ it "sets self's expiration date" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.name = "another-name"
+ cookie.name.should == "another-name"
- cookie.name = "and-one-more"
- cookie.name.should == "and-one-more"
+ cookie.name = "and-one-more"
+ cookie.name.should == "and-one-more"
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/parse_spec.rb b/spec/ruby/library/cgi/cookie/parse_spec.rb
index d484c7bad9..bc505c37ba 100644
--- a/spec/ruby/library/cgi/cookie/parse_spec.rb
+++ b/spec/ruby/library/cgi/cookie/parse_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie.parse" do
- it "parses a raw cookie string into a hash of Cookies" do
- expected = { "test-cookie" => ["one", "two", "three"] }
- CGI::Cookie.parse("test-cookie=one&two&three").should == expected
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- expected = { "second-cookie" => ["three", "four"], "first-cookie" => ["one", "two"] }
- CGI::Cookie.parse("first-cookie=one&two;second-cookie=three&four").should == expected
- end
+ describe "CGI::Cookie.parse" do
+ it "parses a raw cookie string into a hash of Cookies" do
+ expected = { "test-cookie" => ["one", "two", "three"] }
+ CGI::Cookie.parse("test-cookie=one&two&three").should == expected
- it "does not use , for cookie separators" do
- expected = {
- "first-cookie" => ["one", "two"],
- "second-cookie" => ["three", "four,third_cookie=five", "six"]
- }
- CGI::Cookie.parse("first-cookie=one&two;second-cookie=three&four,third_cookie=five&six").should == expected
- end
+ expected = { "second-cookie" => ["three", "four"], "first-cookie" => ["one", "two"] }
+ CGI::Cookie.parse("first-cookie=one&two;second-cookie=three&four").should == expected
+ end
+
+ it "does not use , for cookie separators" do
+ expected = {
+ "first-cookie" => ["one", "two"],
+ "second-cookie" => ["three", "four,third_cookie=five", "six"]
+ }
+ CGI::Cookie.parse("first-cookie=one&two;second-cookie=three&four,third_cookie=five&six").should == expected
+ end
- it "unescapes the Cookie values" do
- cookie = "test-cookie=+%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E"
- expected = { "test-cookie" => [ " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" ] }
- CGI::Cookie.parse(cookie).should == expected
+ it "unescapes the Cookie values" do
+ cookie = "test-cookie=+%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E"
+ expected = { "test-cookie" => [ " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" ] }
+ CGI::Cookie.parse(cookie).should == expected
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/path_spec.rb b/spec/ruby/library/cgi/cookie/path_spec.rb
index 8a2f05aa50..13ee5d726b 100644
--- a/spec/ruby/library/cgi/cookie/path_spec.rb
+++ b/spec/ruby/library/cgi/cookie/path_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#path" do
- it "returns self's path" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.path.should == ""
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- cookie = CGI::Cookie.new("name" => "test-cookie", "path" => "/some/path/")
- cookie.path.should == "/some/path/"
+ describe "CGI::Cookie#path" do
+ it "returns self's path" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.path.should == ""
+
+ cookie = CGI::Cookie.new("name" => "test-cookie", "path" => "/some/path/")
+ cookie.path.should == "/some/path/"
+ end
end
-end
-describe "CGI::Cookie#path=" do
- it "sets self's path" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.path = "/some/path/"
- cookie.path.should == "/some/path/"
+ describe "CGI::Cookie#path=" do
+ it "sets self's path" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.path = "/some/path/"
+ cookie.path.should == "/some/path/"
- cookie.path = "/another/path/"
- cookie.path.should == "/another/path/"
+ cookie.path = "/another/path/"
+ cookie.path.should == "/another/path/"
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/secure_spec.rb b/spec/ruby/library/cgi/cookie/secure_spec.rb
index 694bc2eeed..233881b173 100644
--- a/spec/ruby/library/cgi/cookie/secure_spec.rb
+++ b/spec/ruby/library/cgi/cookie/secure_spec.rb
@@ -1,70 +1,73 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#secure" do
- before :each do
- @cookie = CGI::Cookie.new("test-cookie")
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- it "returns whether self is a secure cookie or not" do
- @cookie.secure = true
- @cookie.secure.should be_true
+ describe "CGI::Cookie#secure" do
+ before :each do
+ @cookie = CGI::Cookie.new("test-cookie")
+ end
- @cookie.secure = false
- @cookie.secure.should be_false
- end
-end
+ it "returns whether self is a secure cookie or not" do
+ @cookie.secure = true
+ @cookie.secure.should == true
-describe "CGI::Cookie#secure= when passed true" do
- before :each do
- @cookie = CGI::Cookie.new("test-cookie")
+ @cookie.secure = false
+ @cookie.secure.should == false
+ end
end
- it "returns true" do
- (@cookie.secure = true).should be_true
- end
+ describe "CGI::Cookie#secure= when passed true" do
+ before :each do
+ @cookie = CGI::Cookie.new("test-cookie")
+ end
- it "sets self to a secure cookie" do
- @cookie.secure = true
- @cookie.secure.should be_true
- end
-end
+ it "returns true" do
+ (@cookie.secure = true).should == true
+ end
-describe "CGI::Cookie#secure= when passed false" do
- before :each do
- @cookie = CGI::Cookie.new("test-cookie")
+ it "sets self to a secure cookie" do
+ @cookie.secure = true
+ @cookie.secure.should == true
+ end
end
- it "returns false" do
- (@cookie.secure = false).should be_false
- end
+ describe "CGI::Cookie#secure= when passed false" do
+ before :each do
+ @cookie = CGI::Cookie.new("test-cookie")
+ end
- it "sets self to a non-secure cookie" do
- @cookie.secure = false
- @cookie.secure.should be_false
- end
-end
+ it "returns false" do
+ (@cookie.secure = false).should == false
+ end
-describe "CGI::Cookie#secure= when passed Object" do
- before :each do
- @cookie = CGI::Cookie.new("test-cookie")
+ it "sets self to a non-secure cookie" do
+ @cookie.secure = false
+ @cookie.secure.should == false
+ end
end
- it "does not change self's secure value" do
- @cookie.secure = false
+ describe "CGI::Cookie#secure= when passed Object" do
+ before :each do
+ @cookie = CGI::Cookie.new("test-cookie")
+ end
+
+ it "does not change self's secure value" do
+ @cookie.secure = false
- @cookie.secure = Object.new
- @cookie.secure.should be_false
+ @cookie.secure = Object.new
+ @cookie.secure.should == false
- @cookie.secure = "Test"
- @cookie.secure.should be_false
+ @cookie.secure = "Test"
+ @cookie.secure.should == false
- @cookie.secure = true
+ @cookie.secure = true
- @cookie.secure = Object.new
- @cookie.secure.should be_true
+ @cookie.secure = Object.new
+ @cookie.secure.should == true
- @cookie.secure = "Test"
- @cookie.secure.should be_true
+ @cookie.secure = "Test"
+ @cookie.secure.should == true
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/to_s_spec.rb b/spec/ruby/library/cgi/cookie/to_s_spec.rb
index da15e6ed2a..20d2579f8d 100644
--- a/spec/ruby/library/cgi/cookie/to_s_spec.rb
+++ b/spec/ruby/library/cgi/cookie/to_s_spec.rb
@@ -1,33 +1,36 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#to_s" do
- it "returns a String representation of self" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.to_s.should == "test-cookie=; path="
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- cookie = CGI::Cookie.new("test-cookie", "value")
- cookie.to_s.should == "test-cookie=value; path="
+ describe "CGI::Cookie#to_s" do
+ it "returns a String representation of self" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.to_s.should == "test-cookie=; path="
- cookie = CGI::Cookie.new("test-cookie", "one", "two", "three")
- cookie.to_s.should == "test-cookie=one&two&three; path="
+ cookie = CGI::Cookie.new("test-cookie", "value")
+ cookie.to_s.should == "test-cookie=value; path="
- cookie = CGI::Cookie.new(
- 'name' => 'test-cookie',
- 'value' => ["one", "two", "three"],
- 'path' => 'some/path/',
- 'domain' => 'example.com',
- 'expires' => Time.at(1196524602),
- 'secure' => true)
- cookie.to_s.should == "test-cookie=one&two&three; domain=example.com; path=some/path/; expires=Sat, 01 Dec 2007 15:56:42 GMT; secure"
- end
+ cookie = CGI::Cookie.new("test-cookie", "one", "two", "three")
+ cookie.to_s.should == "test-cookie=one&two&three; path="
- it "escapes the self's values" do
- cookie = CGI::Cookie.new("test-cookie", " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}")
- cookie.to_s.should == "test-cookie=+%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D; path="
- end
+ cookie = CGI::Cookie.new(
+ 'name' => 'test-cookie',
+ 'value' => ["one", "two", "three"],
+ 'path' => 'some/path/',
+ 'domain' => 'example.com',
+ 'expires' => Time.at(1196524602),
+ 'secure' => true)
+ cookie.to_s.should == "test-cookie=one&two&three; domain=example.com; path=some/path/; expires=Sat, 01 Dec 2007 15:56:42 GMT; secure"
+ end
+
+ it "escapes the self's values" do
+ cookie = CGI::Cookie.new("test-cookie", " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}")
+ cookie.to_s.should == "test-cookie=+%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D; path="
+ end
- it "does not escape tilde" do
- cookie = CGI::Cookie.new("test-cookie", "~").to_s.should == "test-cookie=~; path="
+ it "does not escape tilde" do
+ cookie = CGI::Cookie.new("test-cookie", "~").to_s.should == "test-cookie=~; path="
+ end
end
end
diff --git a/spec/ruby/library/cgi/cookie/value_spec.rb b/spec/ruby/library/cgi/cookie/value_spec.rb
index 1d5da3a3ac..45032edcbf 100644
--- a/spec/ruby/library/cgi/cookie/value_spec.rb
+++ b/spec/ruby/library/cgi/cookie/value_spec.rb
@@ -1,76 +1,79 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::Cookie#value" do
- it "returns self's value" do
- cookie = CGI::Cookie.new("test-cookie")
- cookie.value.should == []
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- cookie = CGI::Cookie.new("test-cookie", "one")
- cookie.value.should == ["one"]
+ describe "CGI::Cookie#value" do
+ it "returns self's value" do
+ cookie = CGI::Cookie.new("test-cookie")
+ cookie.value.should == []
- cookie = CGI::Cookie.new("test-cookie", "one", "two", "three")
- cookie.value.should == ["one", "two", "three"]
+ cookie = CGI::Cookie.new("test-cookie", "one")
+ cookie.value.should == ["one"]
- cookie = CGI::Cookie.new("name" => "test-cookie", "value" => ["one", "two", "three"])
- cookie.value.should == ["one", "two", "three"]
- end
+ cookie = CGI::Cookie.new("test-cookie", "one", "two", "three")
+ cookie.value.should == ["one", "two", "three"]
- it "is in synch with self" do
- fail = []
- [
- :pop,
- :shift,
- [:<<, "Hello"],
- [:push, "Hello"],
- [:unshift, "World"],
- [:replace, ["A", "B"]],
- [:[]=, 1, "Set"],
- [:delete, "first"],
- [:delete_at, 0],
- ].each do |method, *args|
- cookie1 = CGI::Cookie.new("test-cookie", "first", "second")
- cookie2 = CGI::Cookie.new("test-cookie", "first", "second")
- cookie1.send(method, *args)
- cookie2.value.send(method, *args)
- fail << method unless cookie1.value == cookie2.value
+ cookie = CGI::Cookie.new("name" => "test-cookie", "value" => ["one", "two", "three"])
+ cookie.value.should == ["one", "two", "three"]
end
- fail.should be_empty
- end
-end
-describe "CGI::Cookie#value=" do
- before :each do
- @cookie = CGI::Cookie.new("test-cookie")
+ it "is in synch with self" do
+ fail = []
+ [
+ :pop,
+ :shift,
+ [:<<, "Hello"],
+ [:push, "Hello"],
+ [:unshift, "World"],
+ [:replace, ["A", "B"]],
+ [:[]=, 1, "Set"],
+ [:delete, "first"],
+ [:delete_at, 0],
+ ].each do |method, *args|
+ cookie1 = CGI::Cookie.new("test-cookie", "first", "second")
+ cookie2 = CGI::Cookie.new("test-cookie", "first", "second")
+ cookie1.send(method, *args)
+ cookie2.value.send(method, *args)
+ fail << method unless cookie1.value == cookie2.value
+ end
+ fail.should.empty?
+ end
end
- it "sets self's value" do
- @cookie.value = ["one"]
- @cookie.value.should == ["one"]
+ describe "CGI::Cookie#value=" do
+ before :each do
+ @cookie = CGI::Cookie.new("test-cookie")
+ end
- @cookie.value = ["one", "two", "three"]
- @cookie.value.should == ["one", "two", "three"]
- end
+ it "sets self's value" do
+ @cookie.value = ["one"]
+ @cookie.value.should == ["one"]
- it "automatically converts the passed Object to an Array using #Array" do
- @cookie.value = "test"
- @cookie.value.should == ["test"]
+ @cookie.value = ["one", "two", "three"]
+ @cookie.value.should == ["one", "two", "three"]
+ end
- obj = mock("to_a")
- obj.should_receive(:to_a).and_return(["1", "2"])
- @cookie.value = obj
- @cookie.value.should == ["1", "2"]
+ it "automatically converts the passed Object to an Array using #Array" do
+ @cookie.value = "test"
+ @cookie.value.should == ["test"]
- obj = mock("to_ary")
- obj.should_receive(:to_ary).and_return(["1", "2"])
- @cookie.value = obj
- @cookie.value.should == ["1", "2"]
- end
+ obj = mock("to_a")
+ obj.should_receive(:to_a).and_return(["1", "2"])
+ @cookie.value = obj
+ @cookie.value.should == ["1", "2"]
- it "does keep self and the values in sync" do
- @cookie.value = ["one", "two", "three"]
- @cookie[0].should == "one"
- @cookie[1].should == "two"
- @cookie[2].should == "three"
+ obj = mock("to_ary")
+ obj.should_receive(:to_ary).and_return(["1", "2"])
+ @cookie.value = obj
+ @cookie.value.should == ["1", "2"]
+ end
+
+ it "does keep self and the values in sync" do
+ @cookie.value = ["one", "two", "three"]
+ @cookie[0].should == "one"
+ @cookie[1].should == "two"
+ @cookie[2].should == "three"
+ end
end
end
diff --git a/spec/ruby/library/cgi/escapeElement_spec.rb b/spec/ruby/library/cgi/escapeElement_spec.rb
index 148926c453..72c38d6028 100644
--- a/spec/ruby/library/cgi/escapeElement_spec.rb
+++ b/spec/ruby/library/cgi/escapeElement_spec.rb
@@ -1,5 +1,11 @@
require_relative '../../spec_helper'
-require 'cgi'
+
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+end
+ruby_version_is "4.0" do
+ require 'cgi/escape'
+end
describe "CGI.escapeElement when passed String, elements, ..." do
it "escapes only the tags of the passed elements in the passed String" do
diff --git a/spec/ruby/library/cgi/escapeHTML_spec.rb b/spec/ruby/library/cgi/escapeHTML_spec.rb
index 421aac5d4a..6e70e87ed7 100644
--- a/spec/ruby/library/cgi/escapeHTML_spec.rb
+++ b/spec/ruby/library/cgi/escapeHTML_spec.rb
@@ -1,5 +1,9 @@
require_relative '../../spec_helper'
-require 'cgi'
+begin
+ require 'cgi/escape'
+rescue LoadError
+ require 'cgi'
+end
describe "CGI.escapeHTML" do
it "escapes special HTML characters (&\"<>') in the passed argument" do
diff --git a/spec/ruby/library/cgi/escapeURIComponent_spec.rb b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
index f05795a2f5..98efa2e67e 100644
--- a/spec/ruby/library/cgi/escapeURIComponent_spec.rb
+++ b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
@@ -1,57 +1,78 @@
require_relative '../../spec_helper'
-require 'cgi'
+begin
+ require 'cgi/escape'
+rescue LoadError
+ require 'cgi'
+end
-ruby_version_is "3.2" do
- describe "CGI.escapeURIComponent" do
- it "escapes whitespace" do
- string = "&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93"
- CGI.escapeURIComponent(string).should == '%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93'
- end
+describe "CGI.escapeURIComponent" do
+ it "percent-encodes characters reserved according to RFC 3986" do
+ # https://www.rfc-editor.org/rfc/rfc3986#section-2.2
+ string = ":/?#[]@!$&'()*+,;="
+ CGI.escapeURIComponent(string).should == "%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D"
+ end
- it "does not escape with unreserved characters" do
- string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
- CGI.escapeURIComponent(string).should == "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
- end
+ it "does not percent-encode unreserved characters according to RFC 3986" do
+ string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
+ CGI.escapeURIComponent(string).should == "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
+ end
- it "supports String with invalid encoding" do
- string = "\xC0\<\<".dup.force_encoding("UTF-8")
- CGI.escapeURIComponent(string).should == "%C0%3C%3C"
- end
+ it "encodes % character as %25" do
+ CGI.escapeURIComponent("%").should == "%25"
+ end
- it "processes String bytes one by one, not characters" do
- CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2
- end
+ # Compare to .escape which uses "+".
+ it "percent-encodes single whitespace" do
+ CGI.escapeURIComponent(" ").should == "%20"
+ end
- it "raises a TypeError with nil" do
- -> {
- CGI.escapeURIComponent(nil)
- }.should raise_error(TypeError, 'no implicit conversion of nil into String')
- end
+ it "percent-encodes all non-reserved and non-unreserved ASCII characters" do
+ special_set = ":/?#[]@!$&'()*+,;=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
+ all_other = (0x00..0x7F).filter_map { |i| i.chr unless special_set.include?(i.chr) }.join
+ encoded = CGI.escapeURIComponent(all_other)
+ encoded.should.match?(/\A(?:%[0-9A-F]{2}){#{all_other.length}}\z/)
+ end
- it "encodes empty string" do
- CGI.escapeURIComponent("").should == ""
- end
+ it "percent-encodes non-ASCII bytes" do
+ bytes = (0x80..0xFF).map(&:chr).join
+ encoded = CGI.escapeURIComponent(bytes)
+ encoded.should.match?(/\A(?:%[0-9A-F]{2}){#{bytes.length}}\z/)
+ end
- it "encodes single whitespace" do
- CGI.escapeURIComponent(" ").should == "%20"
- end
+ it "processes multi-byte characters as separate bytes, percent-encoding each one" do
+ CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2
+ end
- it "encodes double whitespace" do
- CGI.escapeURIComponent(" ").should == "%20%20"
- end
+ it "produces a copy of an empty string" do
+ string = "".encode(Encoding::BINARY)
+ encoded = CGI.escapeURIComponent(string)
+ encoded.should == ""
+ encoded.encoding.should == Encoding::BINARY
+ string.should_not.equal?(encoded)
+ end
- it "preserves encoding" do
- string = "whatever".encode("ASCII-8BIT")
- CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT
- end
+ it "preserves string's encoding" do
+ string = "whatever".encode("ASCII-8BIT")
+ CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT
+ end
- it "uses implicit type conversion to String" do
- object = Object.new
- def object.to_str
- "a b"
- end
+ it "processes even strings with invalid encoding, percent-encoding octets as-is" do
+ string = "\xC0<<".dup.force_encoding("UTF-8")
+ CGI.escapeURIComponent(string).should == "%C0%3C%3C"
+ end
- CGI.escapeURIComponent(object).should == "a%20b"
+ it "raises a TypeError with nil" do
+ -> {
+ CGI.escapeURIComponent(nil)
+ }.should.raise(TypeError, "no implicit conversion of nil into String")
+ end
+
+ it "uses implicit type conversion to String" do
+ object = Object.new
+ def object.to_str
+ "a b"
end
+
+ CGI.escapeURIComponent(object).should == "a%20b"
end
end
diff --git a/spec/ruby/library/cgi/escape_spec.rb b/spec/ruby/library/cgi/escape_spec.rb
index c599a73cf0..55eb0b66c2 100644
--- a/spec/ruby/library/cgi/escape_spec.rb
+++ b/spec/ruby/library/cgi/escape_spec.rb
@@ -1,5 +1,9 @@
require_relative '../../spec_helper'
-require 'cgi'
+begin
+ require 'cgi/escape'
+rescue LoadError
+ require 'cgi'
+end
describe "CGI.escape" do
it "url-encodes the passed argument" do
diff --git a/spec/ruby/library/cgi/htmlextension/a_spec.rb b/spec/ruby/library/cgi/htmlextension/a_spec.rb
index 05b4c2d14c..78d3dec8fa 100644
--- a/spec/ruby/library/cgi/htmlextension/a_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/a_spec.rb
@@ -1,49 +1,52 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#a" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed a String" do
- it "returns an 'a'-element, using the passed String as the 'href'-attribute" do
- output = @html.a("http://www.example.com")
- output.should equal_element("A", "HREF" => "http://www.example.com")
+ describe "CGI::HtmlExtension#a" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "includes the passed block's return value when passed a block" do
- output = @html.a("http://www.example.com") { "Example" }
- output.should equal_element("A", { "HREF" => "http://www.example.com" }, "Example")
- end
- end
+ describe "when passed a String" do
+ it "returns an 'a'-element, using the passed String as the 'href'-attribute" do
+ output = @html.a("http://www.example.com")
+ output.should equal_element("A", "HREF" => "http://www.example.com")
+ end
- describe "when passed a Hash" do
- it "returns an 'a'-element, using the passed Hash for attributes" do
- attributes = {"HREF" => "http://www.example.com", "TARGET" => "_top"}
- @html.a(attributes).should equal_element("A", attributes)
+ it "includes the passed block's return value when passed a block" do
+ output = @html.a("http://www.example.com") { "Example" }
+ output.should equal_element("A", { "HREF" => "http://www.example.com" }, "Example")
+ end
end
- it "includes the passed block's return value when passed a block" do
- attributes = {"HREF" => "http://www.example.com", "TARGET" => "_top"}
- @html.a(attributes) { "Example" }.should equal_element("A", attributes, "Example")
- end
- end
+ describe "when passed a Hash" do
+ it "returns an 'a'-element, using the passed Hash for attributes" do
+ attributes = {"HREF" => "http://www.example.com", "TARGET" => "_top"}
+ @html.a(attributes).should equal_element("A", attributes)
+ end
- describe "when each HTML generation" do
- it "returns the doctype declaration for HTML3" do
- CGISpecs.cgi_new("html3").a.should == %(<A HREF=""></A>)
- CGISpecs.cgi_new("html3").a { "link text" }.should == %(<A HREF="">link text</A>)
+ it "includes the passed block's return value when passed a block" do
+ attributes = {"HREF" => "http://www.example.com", "TARGET" => "_top"}
+ @html.a(attributes) { "Example" }.should equal_element("A", attributes, "Example")
+ end
end
- it "returns the doctype declaration for HTML4" do
- CGISpecs.cgi_new("html4").a.should == %(<A HREF=""></A>)
- CGISpecs.cgi_new("html4").a { "link text" }.should == %(<A HREF="">link text</A>)
- end
- it "returns the doctype declaration for the Transitional version of HTML4" do
- CGISpecs.cgi_new("html4Tr").a.should == %(<A HREF=""></A>)
- CGISpecs.cgi_new("html4Tr").a { "link text" }.should == %(<A HREF="">link text</A>)
+ describe "when each HTML generation" do
+ it "returns the doctype declaration for HTML3" do
+ CGISpecs.cgi_new("html3").a.should == %(<A HREF=""></A>)
+ CGISpecs.cgi_new("html3").a { "link text" }.should == %(<A HREF="">link text</A>)
+ end
+
+ it "returns the doctype declaration for HTML4" do
+ CGISpecs.cgi_new("html4").a.should == %(<A HREF=""></A>)
+ CGISpecs.cgi_new("html4").a { "link text" }.should == %(<A HREF="">link text</A>)
+ end
+ it "returns the doctype declaration for the Transitional version of HTML4" do
+ CGISpecs.cgi_new("html4Tr").a.should == %(<A HREF=""></A>)
+ CGISpecs.cgi_new("html4Tr").a { "link text" }.should == %(<A HREF="">link text</A>)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/base_spec.rb b/spec/ruby/library/cgi/htmlextension/base_spec.rb
index 877ac321cd..1eedfdea54 100644
--- a/spec/ruby/library/cgi/htmlextension/base_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/base_spec.rb
@@ -1,33 +1,36 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#base" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when bassed a String" do
- it "returns a 'base'-element, using the passed String as the 'href'-attribute" do
- output = @html.base("http://www.example.com")
- output.should equal_element("BASE", {"HREF" => "http://www.example.com"}, nil, not_closed: true)
+ describe "CGI::HtmlExtension#base" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.base("http://www.example.com") { "Example" }
- output.should equal_element("BASE", {"HREF" => "http://www.example.com"}, nil, not_closed: true)
- end
- end
+ describe "when bassed a String" do
+ it "returns a 'base'-element, using the passed String as the 'href'-attribute" do
+ output = @html.base("http://www.example.com")
+ output.should equal_element("BASE", {"HREF" => "http://www.example.com"}, nil, not_closed: true)
+ end
- describe "when passed a Hash" do
- it "returns a 'base'-element, using the passed Hash for attributes" do
- output = @html.base("HREF" => "http://www.example.com", "ID" => "test")
- output.should equal_element("BASE", {"HREF" => "http://www.example.com", "ID" => "test"}, nil, not_closed: true)
+ it "ignores a passed block" do
+ output = @html.base("http://www.example.com") { "Example" }
+ output.should equal_element("BASE", {"HREF" => "http://www.example.com"}, nil, not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.base("HREF" => "http://www.example.com", "ID" => "test") { "Example" }
- output.should equal_element("BASE", {"HREF" => "http://www.example.com", "ID" => "test"}, nil, not_closed: true)
+ describe "when passed a Hash" do
+ it "returns a 'base'-element, using the passed Hash for attributes" do
+ output = @html.base("HREF" => "http://www.example.com", "ID" => "test")
+ output.should equal_element("BASE", {"HREF" => "http://www.example.com", "ID" => "test"}, nil, not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.base("HREF" => "http://www.example.com", "ID" => "test") { "Example" }
+ output.should equal_element("BASE", {"HREF" => "http://www.example.com", "ID" => "test"}, nil, not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb b/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb
index a7b833b1c5..883e36f78b 100644
--- a/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/blockquote_spec.rb
@@ -1,33 +1,36 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#blockquote" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed a String" do
- it "returns a 'blockquote'-element, using the passed String for the 'cite'-attribute" do
- output = @html.blockquote("http://www.example.com/quotes/foo.html")
- output.should equal_element("BLOCKQUOTE", "CITE" => "http://www.example.com/quotes/foo.html")
+ describe "CGI::HtmlExtension#blockquote" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "includes the passed block's return value when passed a block" do
- output = @html.blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
- output.should equal_element("BLOCKQUOTE", { "CITE" => "http://www.example.com/quotes/foo.html" }, "Foo!")
- end
- end
+ describe "when passed a String" do
+ it "returns a 'blockquote'-element, using the passed String for the 'cite'-attribute" do
+ output = @html.blockquote("http://www.example.com/quotes/foo.html")
+ output.should equal_element("BLOCKQUOTE", "CITE" => "http://www.example.com/quotes/foo.html")
+ end
- describe "when passed a Hash" do
- it "returns a 'blockquote'-element, using the passed Hash for attributes" do
- output = @html.blockquote("CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test")
- output.should equal_element("BLOCKQUOTE", "CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test")
+ it "includes the passed block's return value when passed a block" do
+ output = @html.blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
+ output.should equal_element("BLOCKQUOTE", { "CITE" => "http://www.example.com/quotes/foo.html" }, "Foo!")
+ end
end
- it "includes the passed block's return value when passed a block" do
- output = @html.blockquote("CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test") { "Foo!" }
- output.should equal_element("BLOCKQUOTE", {"CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test"}, "Foo!")
+ describe "when passed a Hash" do
+ it "returns a 'blockquote'-element, using the passed Hash for attributes" do
+ output = @html.blockquote("CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test")
+ output.should equal_element("BLOCKQUOTE", "CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test")
+ end
+
+ it "includes the passed block's return value when passed a block" do
+ output = @html.blockquote("CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test") { "Foo!" }
+ output.should equal_element("BLOCKQUOTE", {"CITE" => "http://www.example.com/quotes/foo.html", "ID" => "test"}, "Foo!")
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/br_spec.rb b/spec/ruby/library/cgi/htmlextension/br_spec.rb
index dfca121884..23c2cb4a48 100644
--- a/spec/ruby/library/cgi/htmlextension/br_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/br_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#br" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when each HTML generation" do
- it "returns the doctype declaration for HTML3" do
- CGISpecs.cgi_new("html3").br.should == "<BR>"
+ describe "CGI::HtmlExtension#br" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "returns the doctype declaration for HTML4" do
- CGISpecs.cgi_new("html4").br.should == "<BR>"
- end
- it "returns the doctype declaration for the Transitional version of HTML4" do
- CGISpecs.cgi_new("html4Tr").br.should == "<BR>"
+ describe "when each HTML generation" do
+ it "returns the doctype declaration for HTML3" do
+ CGISpecs.cgi_new("html3").br.should == "<BR>"
+ end
+
+ it "returns the doctype declaration for HTML4" do
+ CGISpecs.cgi_new("html4").br.should == "<BR>"
+ end
+ it "returns the doctype declaration for the Transitional version of HTML4" do
+ CGISpecs.cgi_new("html4Tr").br.should == "<BR>"
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/caption_spec.rb b/spec/ruby/library/cgi/htmlextension/caption_spec.rb
index 16615028b8..3d3e21ecaa 100644
--- a/spec/ruby/library/cgi/htmlextension/caption_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/caption_spec.rb
@@ -1,33 +1,36 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#caption" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed a String" do
- it "returns a 'caption'-element, using the passed String for the 'align'-attribute" do
- output = @html.caption("left")
- output.should equal_element("CAPTION", "ALIGN" => "left")
+ describe "CGI::HtmlExtension#caption" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "includes the passed block's return value when passed a block" do
- output = @html.caption("left") { "Capital Cities" }
- output.should equal_element("CAPTION", {"ALIGN" => "left"}, "Capital Cities")
- end
- end
+ describe "when passed a String" do
+ it "returns a 'caption'-element, using the passed String for the 'align'-attribute" do
+ output = @html.caption("left")
+ output.should equal_element("CAPTION", "ALIGN" => "left")
+ end
- describe "when passed a Hash" do
- it "returns a 'caption'-element, using the passed Hash for attributes" do
- output = @html.caption("ALIGN" => "left", "ID" => "test")
- output.should equal_element("CAPTION", "ALIGN" => "left", "ID" => "test")
+ it "includes the passed block's return value when passed a block" do
+ output = @html.caption("left") { "Capital Cities" }
+ output.should equal_element("CAPTION", {"ALIGN" => "left"}, "Capital Cities")
+ end
end
- it "includes the passed block's return value when passed a block" do
- output = @html.caption("ALIGN" => "left", "ID" => "test") { "Capital Cities" }
- output.should equal_element("CAPTION", {"ALIGN" => "left", "ID" => "test"}, "Capital Cities")
+ describe "when passed a Hash" do
+ it "returns a 'caption'-element, using the passed Hash for attributes" do
+ output = @html.caption("ALIGN" => "left", "ID" => "test")
+ output.should equal_element("CAPTION", "ALIGN" => "left", "ID" => "test")
+ end
+
+ it "includes the passed block's return value when passed a block" do
+ output = @html.caption("ALIGN" => "left", "ID" => "test") { "Capital Cities" }
+ output.should equal_element("CAPTION", {"ALIGN" => "left", "ID" => "test"}, "Capital Cities")
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb b/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb
index 64f852cc52..07163c010e 100644
--- a/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/checkbox_group_spec.rb
@@ -1,76 +1,79 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#checkbox_group" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed name, values ..." do
- it "returns a sequence of 'checkbox'-elements with the passed name and the passed values" do
- output = CGISpecs.split(@html.checkbox_group("test", "foo", "bar", "baz"))
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ describe "CGI::HtmlExtension#checkbox_group" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "allows passing a value inside an Array" do
- output = CGISpecs.split(@html.checkbox_group("test", ["foo"], "bar", ["baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
- end
+ describe "when passed name, values ..." do
+ it "returns a sequence of 'checkbox'-elements with the passed name and the passed values" do
+ output = CGISpecs.split(@html.checkbox_group("test", "foo", "bar", "baz"))
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
- it "allows passing a value as an Array containing the value and the checked state or a label" do
- output = CGISpecs.split(@html.checkbox_group("test", ["foo"], ["bar", true], ["baz", "label for baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "label for baz", not_closed: true)
- end
+ it "allows passing a value inside an Array" do
+ output = CGISpecs.split(@html.checkbox_group("test", ["foo"], "bar", ["baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
- it "allows passing a value as an Array containing the value, a label and the checked state" do
- output = CGISpecs.split(@html.checkbox_group("test", ["foo", "label for foo", true], ["bar", "label for bar", false], ["baz", "label for baz", true]))
- output[0].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "label for foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "label for bar", not_closed: true)
- output[2].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "label for baz", not_closed: true)
- end
+ it "allows passing a value as an Array containing the value and the checked state or a label" do
+ output = CGISpecs.split(@html.checkbox_group("test", ["foo"], ["bar", true], ["baz", "label for baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "label for baz", not_closed: true)
+ end
- it "returns an empty String when passed no values" do
- @html.checkbox_group("test").should == ""
- end
+ it "allows passing a value as an Array containing the value, a label and the checked state" do
+ output = CGISpecs.split(@html.checkbox_group("test", ["foo", "label for foo", true], ["bar", "label for bar", false], ["baz", "label for baz", true]))
+ output[0].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "label for foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "label for bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "label for baz", not_closed: true)
+ end
+
+ it "returns an empty String when passed no values" do
+ @html.checkbox_group("test").should == ""
+ end
- it "ignores a passed block" do
- output = CGISpecs.split(@html.checkbox_group("test", "foo", "bar", "baz") { "test" })
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ it "ignores a passed block" do
+ output = CGISpecs.split(@html.checkbox_group("test", "foo", "bar", "baz") { "test" })
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
end
- end
- describe "when passed Hash" do
- it "uses the passed Hash to generate the checkbox sequence" do
- output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ describe "when passed Hash" do
+ it "uses the passed Hash to generate the checkbox sequence" do
+ output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
- output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => [["foo"], ["bar", true], "baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => [["foo"], ["bar", true], "baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
- output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "1"}, "Foo", not_closed: true)
- output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "checkbox", "VALUE" => "2"}, "Bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "Baz"}, "Baz", not_closed: true)
- end
+ output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "1"}, "Foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "checkbox", "VALUE" => "2"}, "Bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "Baz"}, "Baz", not_closed: true)
+ end
- it "ignores a passed block" do
- output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]) { "test" })
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ it "ignores a passed block" do
+ output = CGISpecs.split(@html.checkbox_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]) { "test" })
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "checkbox", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb b/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb
index af76fa1da9..ad87b78061 100644
--- a/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/checkbox_spec.rb
@@ -1,77 +1,80 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#checkbox" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a checkbox-'input'-element without a name" do
- output = @html.checkbox
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "checkbox"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#checkbox" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.checkbox { "test" }
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "checkbox"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns a checkbox-'input'-element without a name" do
+ output = @html.checkbox
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "checkbox"}, "", not_closed: true)
+ end
- describe "when passed name" do
- it "returns a checkbox-'input'-element with the passed name" do
- output = @html.checkbox("test")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.checkbox { "test" }
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "checkbox"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.checkbox("test") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox"}, "", not_closed: true)
- end
- end
+ describe "when passed name" do
+ it "returns a checkbox-'input'-element with the passed name" do
+ output = @html.checkbox("test")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox"}, "", not_closed: true)
+ end
- describe "CGI::HtmlExtension#checkbox when passed name, value" do
- it "returns a checkbox-'input'-element with the passed name and value" do
- output = @html.checkbox("test", "test-value")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.checkbox("test") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.checkbox("test", "test-value") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#checkbox when passed name, value" do
+ it "returns a checkbox-'input'-element with the passed name and value" do
+ output = @html.checkbox("test", "test-value")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.checkbox("test", "test-value") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ end
end
- end
- describe "when passed name, value, checked" do
- it "returns a checked checkbox-'input'-element with the passed name and value when checked is true" do
- output = @html.checkbox("test", "test-value", true)
- output.should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ describe "when passed name, value, checked" do
+ it "returns a checked checkbox-'input'-element with the passed name and value when checked is true" do
+ output = @html.checkbox("test", "test-value", true)
+ output.should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
- output = @html.checkbox("test", "test-value", false)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ output = @html.checkbox("test", "test-value", false)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
- output = @html.checkbox("test", "test-value", nil)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
- end
+ output = @html.checkbox("test", "test-value", nil)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ end
- it "ignores a passed block" do
- output = @html.checkbox("test", "test-value", nil) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.checkbox("test", "test-value", nil) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "checkbox", "VALUE" => "test-value"}, "", not_closed: true)
+ end
end
- end
- describe "when passed Hash" do
- it "returns a checkbox-'input'-element using the passed Hash for attributes" do
- attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
- output = @html.checkbox(attributes)
- output.should equal_element("INPUT", attributes, "", not_closed: true)
- end
+ describe "when passed Hash" do
+ it "returns a checkbox-'input'-element using the passed Hash for attributes" do
+ attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
+ output = @html.checkbox(attributes)
+ output.should equal_element("INPUT", attributes, "", not_closed: true)
+ end
- it "ignores a passed block" do
- attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
- output = @html.checkbox(attributes) { "test" }
- output.should equal_element("INPUT", attributes, "", not_closed: true)
+ it "ignores a passed block" do
+ attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
+ output = @html.checkbox(attributes) { "test" }
+ output.should equal_element("INPUT", attributes, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/doctype_spec.rb b/spec/ruby/library/cgi/htmlextension/doctype_spec.rb
index 9a28a8883b..02af831855 100644
--- a/spec/ruby/library/cgi/htmlextension/doctype_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/doctype_spec.rb
@@ -1,27 +1,30 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#doctype" do
- describe "when each HTML generation" do
- it "returns the doctype declaration for HTML3" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'
- CGISpecs.cgi_new("html3").doctype.should == expect
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- it "returns the doctype declaration for HTML4" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
- CGISpecs.cgi_new("html4").doctype.should == expect
- end
+ describe "CGI::HtmlExtension#doctype" do
+ describe "when each HTML generation" do
+ it "returns the doctype declaration for HTML3" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'
+ CGISpecs.cgi_new("html3").doctype.should == expect
+ end
- it "returns the doctype declaration for the Frameset version of HTML4" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
- CGISpecs.cgi_new("html4Fr").doctype.should == expect
- end
+ it "returns the doctype declaration for HTML4" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
+ CGISpecs.cgi_new("html4").doctype.should == expect
+ end
+
+ it "returns the doctype declaration for the Frameset version of HTML4" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
+ CGISpecs.cgi_new("html4Fr").doctype.should == expect
+ end
- it "returns the doctype declaration for the Transitional version of HTML4" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
- CGISpecs.cgi_new("html4Tr").doctype.should == expect
+ it "returns the doctype declaration for the Transitional version of HTML4" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
+ CGISpecs.cgi_new("html4Tr").doctype.should == expect
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/file_field_spec.rb b/spec/ruby/library/cgi/htmlextension/file_field_spec.rb
index 2a0632fd58..eff077b9a2 100644
--- a/spec/ruby/library/cgi/htmlextension/file_field_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/file_field_spec.rb
@@ -1,72 +1,75 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#file_field" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a file-'input'-element without a name and a size of 20" do
- output = @html.file_field
- output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "", "TYPE" => "file"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#file_field" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.file_field { "test" }
- output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "", "TYPE" => "file"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns a file-'input'-element without a name and a size of 20" do
+ output = @html.file_field
+ output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "", "TYPE" => "file"}, "", not_closed: true)
+ end
- describe "when passed name" do
- it "returns a checkbox-'input'-element with the passed name" do
- output = @html.file_field("Example")
- output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.file_field { "test" }
+ output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "", "TYPE" => "file"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.file_field("Example") { "test" }
- output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
- end
- end
+ describe "when passed name" do
+ it "returns a checkbox-'input'-element with the passed name" do
+ output = @html.file_field("Example")
+ output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
+ end
- describe "when passed name, size" do
- it "returns a checkbox-'input'-element with the passed name and size" do
- output = @html.file_field("Example", 40)
- output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.file_field("Example") { "test" }
+ output.should equal_element("INPUT", {"SIZE" => 20, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.file_field("Example", 40) { "test" }
- output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
- end
- end
+ describe "when passed name, size" do
+ it "returns a checkbox-'input'-element with the passed name and size" do
+ output = @html.file_field("Example", 40)
+ output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
+ end
- describe "when passed name, size, maxlength" do
- it "returns a checkbox-'input'-element with the passed name, size and maxlength" do
- output = @html.file_field("Example", 40, 100)
- output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file", "MAXLENGTH" => 100}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.file_field("Example", 40) { "test" }
+ output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.file_field("Example", 40, 100) { "test" }
- output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file", "MAXLENGTH" => 100}, "", not_closed: true)
+ describe "when passed name, size, maxlength" do
+ it "returns a checkbox-'input'-element with the passed name, size and maxlength" do
+ output = @html.file_field("Example", 40, 100)
+ output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file", "MAXLENGTH" => 100}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.file_field("Example", 40, 100) { "test" }
+ output.should equal_element("INPUT", {"SIZE" => 40, "NAME" => "Example", "TYPE" => "file", "MAXLENGTH" => 100}, "", not_closed: true)
+ end
end
- end
- describe "when passed a Hash" do
- it "returns a file-'input'-element using the passed Hash for attributes" do
- output = @html.file_field("NAME" => "test", "SIZE" => 40)
- output.should equal_element("INPUT", {"NAME" => "test", "SIZE" => 40}, "", not_closed: true)
+ describe "when passed a Hash" do
+ it "returns a file-'input'-element using the passed Hash for attributes" do
+ output = @html.file_field("NAME" => "test", "SIZE" => 40)
+ output.should equal_element("INPUT", {"NAME" => "test", "SIZE" => 40}, "", not_closed: true)
- output = @html.file_field("NAME" => "test", "MAXLENGTH" => 100)
- output.should equal_element("INPUT", {"NAME" => "test", "MAXLENGTH" => 100}, "", not_closed: true)
- end
+ output = @html.file_field("NAME" => "test", "MAXLENGTH" => 100)
+ output.should equal_element("INPUT", {"NAME" => "test", "MAXLENGTH" => 100}, "", not_closed: true)
+ end
- it "ignores a passed block" do
- output = @html.file_field("NAME" => "test", "SIZE" => 40) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "SIZE" => 40}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.file_field("NAME" => "test", "SIZE" => 40) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "SIZE" => 40}, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/form_spec.rb b/spec/ruby/library/cgi/htmlextension/form_spec.rb
index 8c0ac97735..55ac63152b 100644
--- a/spec/ruby/library/cgi/htmlextension/form_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/form_spec.rb
@@ -1,58 +1,61 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#form" do
- before :each do
- @html = CGISpecs.cgi_new
- @html.stub!(:script_name).and_return("/path/to/some/script")
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a 'form'-element" do
- output = @html.form
- output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/path/to/some/script"}, "")
+ describe "CGI::HtmlExtension#form" do
+ before :each do
+ @html = CGISpecs.cgi_new
+ @html.stub!(:script_name).and_return("/path/to/some/script")
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.form { "test" }
- output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/path/to/some/script"}, "test")
- end
- end
+ describe "when passed no arguments" do
+ it "returns a 'form'-element" do
+ output = @html.form
+ output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/path/to/some/script"}, "")
+ end
- describe "when passed method" do
- it "returns a 'form'-element with the passed method" do
- output = @html.form("get")
- output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/path/to/some/script"}, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.form { "test" }
+ output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/path/to/some/script"}, "test")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.form("get") { "test" }
- output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/path/to/some/script"}, "test")
- end
- end
+ describe "when passed method" do
+ it "returns a 'form'-element with the passed method" do
+ output = @html.form("get")
+ output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/path/to/some/script"}, "")
+ end
- describe "when passed method, action" do
- it "returns a 'form'-element with the passed method and the passed action" do
- output = @html.form("get", "/some/other/script")
- output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/some/other/script"}, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.form("get") { "test" }
+ output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/path/to/some/script"}, "test")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.form("get", "/some/other/script") { "test" }
- output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/some/other/script"}, "test")
- end
- end
+ describe "when passed method, action" do
+ it "returns a 'form'-element with the passed method and the passed action" do
+ output = @html.form("get", "/some/other/script")
+ output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/some/other/script"}, "")
+ end
- describe "when passed method, action, enctype" do
- it "returns a 'form'-element with the passed method, action and enctype" do
- output = @html.form("get", "/some/other/script", "multipart/form-data")
- output.should equal_element("FORM", {"ENCTYPE" => "multipart/form-data", "METHOD" => "get", "ACTION" => "/some/other/script"}, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.form("get", "/some/other/script") { "test" }
+ output.should equal_element("FORM", {"ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ACTION" => "/some/other/script"}, "test")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.form("get", "/some/other/script", "multipart/form-data") { "test" }
- output.should equal_element("FORM", {"ENCTYPE" => "multipart/form-data", "METHOD" => "get", "ACTION" => "/some/other/script"}, "test")
+ describe "when passed method, action, enctype" do
+ it "returns a 'form'-element with the passed method, action and enctype" do
+ output = @html.form("get", "/some/other/script", "multipart/form-data")
+ output.should equal_element("FORM", {"ENCTYPE" => "multipart/form-data", "METHOD" => "get", "ACTION" => "/some/other/script"}, "")
+ end
+
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.form("get", "/some/other/script", "multipart/form-data") { "test" }
+ output.should equal_element("FORM", {"ENCTYPE" => "multipart/form-data", "METHOD" => "get", "ACTION" => "/some/other/script"}, "test")
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/frame_spec.rb b/spec/ruby/library/cgi/htmlextension/frame_spec.rb
index 2ddd4e1ef0..fef40849eb 100644
--- a/spec/ruby/library/cgi/htmlextension/frame_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/frame_spec.rb
@@ -1,14 +1,17 @@
require_relative '../../../spec_helper'
-require_relative 'fixtures/common'
-require 'cgi'
-describe "CGI::HtmlExtension#frame" do
- before :each do
- @html = CGISpecs.cgi_new("html4Fr")
- end
+ruby_version_is ""..."4.0" do
+ require_relative 'fixtures/common'
+ require 'cgi'
+
+ describe "CGI::HtmlExtension#frame" do
+ before :each do
+ @html = CGISpecs.cgi_new("html4Fr")
+ end
- it "initializes the HTML Generation methods for the Frameset version of HTML4" do
- @html.frameset.should == "<FRAMESET></FRAMESET>"
- @html.frameset { "link text" }.should == "<FRAMESET>link text</FRAMESET>"
+ it "initializes the HTML Generation methods for the Frameset version of HTML4" do
+ @html.frameset.should == "<FRAMESET></FRAMESET>"
+ @html.frameset { "link text" }.should == "<FRAMESET>link text</FRAMESET>"
+ end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/frameset_spec.rb b/spec/ruby/library/cgi/htmlextension/frameset_spec.rb
index baeb446593..3ad0a9c4d2 100644
--- a/spec/ruby/library/cgi/htmlextension/frameset_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/frameset_spec.rb
@@ -1,14 +1,17 @@
require_relative '../../../spec_helper'
-require_relative 'fixtures/common'
-require 'cgi'
-describe "CGI::HtmlExtension#frameset" do
- before :each do
- @html = CGISpecs.cgi_new("html4Fr")
- end
+ruby_version_is ""..."4.0" do
+ require_relative 'fixtures/common'
+ require 'cgi'
+
+ describe "CGI::HtmlExtension#frameset" do
+ before :each do
+ @html = CGISpecs.cgi_new("html4Fr")
+ end
- it "initializes the HTML Generation methods for the Frameset version of HTML4" do
- @html.frameset.should == "<FRAMESET></FRAMESET>"
- @html.frameset { "link text" }.should == "<FRAMESET>link text</FRAMESET>"
+ it "initializes the HTML Generation methods for the Frameset version of HTML4" do
+ @html.frameset.should == "<FRAMESET></FRAMESET>"
+ @html.frameset { "link text" }.should == "<FRAMESET>link text</FRAMESET>"
+ end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/hidden_spec.rb b/spec/ruby/library/cgi/htmlextension/hidden_spec.rb
index 52ebd8c261..b2323775f6 100644
--- a/spec/ruby/library/cgi/htmlextension/hidden_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/hidden_spec.rb
@@ -1,59 +1,62 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#hidden" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns an hidden-'input'-element without a name" do
- output = @html.hidden
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "hidden"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#hidden" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.hidden { "test" }
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "hidden"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns an hidden-'input'-element without a name" do
+ output = @html.hidden
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "hidden"}, "", not_closed: true)
+ end
- describe "when passed name" do
- it "returns an hidden-'input'-element with the passed name" do
- output = @html.hidden("test")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.hidden { "test" }
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "hidden"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.hidden("test") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden"}, "", not_closed: true)
- end
- end
+ describe "when passed name" do
+ it "returns an hidden-'input'-element with the passed name" do
+ output = @html.hidden("test")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden"}, "", not_closed: true)
+ end
- describe "when passed name, value" do
- it "returns an hidden-'input'-element with the passed name and value" do
- output = @html.hidden("test", "some value")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden", "VALUE" => "some value"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.hidden("test") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.hidden("test", "some value") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden", "VALUE" => "some value"}, "", not_closed: true)
- end
- end
+ describe "when passed name, value" do
+ it "returns an hidden-'input'-element with the passed name and value" do
+ output = @html.hidden("test", "some value")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden", "VALUE" => "some value"}, "", not_closed: true)
+ end
- describe "when passed Hash" do
- it "returns a checkbox-'input'-element using the passed Hash for attributes" do
- attributes = { "NAME" => "test", "VALUE" => "some value" }
- output = @html.hidden("test", "some value")
- output.should equal_element("INPUT", attributes, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.hidden("test", "some value") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "hidden", "VALUE" => "some value"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- attributes = { "NAME" => "test", "VALUE" => "some value" }
- output = @html.hidden("test", "some value") { "test" }
- output.should equal_element("INPUT", attributes, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns a checkbox-'input'-element using the passed Hash for attributes" do
+ attributes = { "NAME" => "test", "VALUE" => "some value" }
+ output = @html.hidden("test", "some value")
+ output.should equal_element("INPUT", attributes, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ attributes = { "NAME" => "test", "VALUE" => "some value" }
+ output = @html.hidden("test", "some value") { "test" }
+ output.should equal_element("INPUT", attributes, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/html_spec.rb b/spec/ruby/library/cgi/htmlextension/html_spec.rb
index 5d89c82086..60a10fb6b4 100644
--- a/spec/ruby/library/cgi/htmlextension/html_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/html_spec.rb
@@ -1,66 +1,69 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#html" do
- before :each do
- @html = CGISpecs.cgi_new
- @html.stub!(:doctype).and_return("<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE>")
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a self's doctype and an 'html'-element" do
- expected = '<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE><HTML>'
- @html.html.should == expected
+ describe "CGI::HtmlExtension#html" do
+ before :each do
+ @html = CGISpecs.cgi_new
+ @html.stub!(:doctype).and_return("<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE>")
end
- it "includes the passed block when passed a block" do
- expected = '<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE><HTML>test</HTML>'
- @html.html { "test" }.should == expected
- end
- end
+ describe "when passed no arguments" do
+ it "returns a self's doctype and an 'html'-element" do
+ expected = '<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE><HTML>'
+ @html.html.should == expected
+ end
- describe "when passed 'PRETTY'" do
- it "returns pretty output when the passed String is 'PRETTY" do
- expected = "<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE>\n<HTML>\n"
- @html.html("PRETTY").should == expected
+ it "includes the passed block when passed a block" do
+ expected = '<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE><HTML>test</HTML>'
+ @html.html { "test" }.should == expected
+ end
end
- it "includes the passed block when passed a block" do
- expected = "<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE>\n<HTML>\n test\n</HTML>\n"
- @html.html("PRETTY") { "test" }.should == expected
- end
- end
+ describe "when passed 'PRETTY'" do
+ it "returns pretty output when the passed String is 'PRETTY" do
+ expected = "<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE>\n<HTML>\n"
+ @html.html("PRETTY").should == expected
+ end
- describe "when passed a Hash" do
- it "returns an 'html'-element using the passed Hash for attributes" do
- expected = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML BLA="TEST">'
- @html.html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">', "BLA" => "TEST").should == expected
+ it "includes the passed block when passed a block" do
+ expected = "<!DOCTYPE SUPA-FUNKAY-RUBYSPEC-DOCTYPE>\n<HTML>\n test\n</HTML>\n"
+ @html.html("PRETTY") { "test" }.should == expected
+ end
end
- it "omits the doctype when the Hash contains a 'DOCTYPE' entry that's false or nil" do
- @html.html("DOCTYPE" => false).should == "<HTML>"
- @html.html("DOCTYPE" => nil).should == "<HTML>"
- end
- end
+ describe "when passed a Hash" do
+ it "returns an 'html'-element using the passed Hash for attributes" do
+ expected = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML BLA="TEST">'
+ @html.html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">', "BLA" => "TEST").should == expected
+ end
- describe "when each HTML generation" do
- it "returns the doctype declaration for HTML3" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'
- CGISpecs.cgi_new("html3").html.should == expect + "<HTML>"
- CGISpecs.cgi_new("html3").html { "html body" }.should == expect + "<HTML>html body</HTML>"
+ it "omits the doctype when the Hash contains a 'DOCTYPE' entry that's false or nil" do
+ @html.html("DOCTYPE" => false).should == "<HTML>"
+ @html.html("DOCTYPE" => nil).should == "<HTML>"
+ end
end
- it "returns the doctype declaration for HTML4" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
- CGISpecs.cgi_new("html4").html.should == expect + "<HTML>"
- CGISpecs.cgi_new("html4").html { "html body" }.should == expect + "<HTML>html body</HTML>"
- end
+ describe "when each HTML generation" do
+ it "returns the doctype declaration for HTML3" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'
+ CGISpecs.cgi_new("html3").html.should == expect + "<HTML>"
+ CGISpecs.cgi_new("html3").html { "html body" }.should == expect + "<HTML>html body</HTML>"
+ end
+
+ it "returns the doctype declaration for HTML4" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
+ CGISpecs.cgi_new("html4").html.should == expect + "<HTML>"
+ CGISpecs.cgi_new("html4").html { "html body" }.should == expect + "<HTML>html body</HTML>"
+ end
- it "returns the doctype declaration for the Transitional version of HTML4" do
- expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
- CGISpecs.cgi_new("html4Tr").html.should == expect + "<HTML>"
- CGISpecs.cgi_new("html4Tr").html { "html body" }.should == expect + "<HTML>html body</HTML>"
+ it "returns the doctype declaration for the Transitional version of HTML4" do
+ expect = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
+ CGISpecs.cgi_new("html4Tr").html.should == expect + "<HTML>"
+ CGISpecs.cgi_new("html4Tr").html { "html body" }.should == expect + "<HTML>html body</HTML>"
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/image_button_spec.rb b/spec/ruby/library/cgi/htmlextension/image_button_spec.rb
index d14bec9ca3..f8770119d4 100644
--- a/spec/ruby/library/cgi/htmlextension/image_button_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/image_button_spec.rb
@@ -1,69 +1,72 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#image_button" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns an image-'input'-element without a source image" do
- output = @html.image_button
- output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#image_button" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.image_button { "test" }
- output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns an image-'input'-element without a source image" do
+ output = @html.image_button
+ output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image"}, "", not_closed: true)
+ end
- describe "when passed src" do
- it "returns an image-'input'-element with the passed src" do
- output = @html.image_button("/path/to/image.png")
- output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.image_button { "test" }
+ output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.image_button("/path/to/image.png") { "test" }
- output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image"}, "", not_closed: true)
- end
- end
+ describe "when passed src" do
+ it "returns an image-'input'-element with the passed src" do
+ output = @html.image_button("/path/to/image.png")
+ output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image"}, "", not_closed: true)
+ end
- describe "when passed src, name" do
- it "returns an image-'input'-element with the passed src and name" do
- output = @html.image_button("/path/to/image.png", "test")
- output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.image_button("/path/to/image.png") { "test" }
+ output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.image_button("/path/to/image.png", "test") { "test" }
- output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test"}, "", not_closed: true)
- end
- end
+ describe "when passed src, name" do
+ it "returns an image-'input'-element with the passed src and name" do
+ output = @html.image_button("/path/to/image.png", "test")
+ output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test"}, "", not_closed: true)
+ end
- describe "when passed src, name, alt" do
- it "returns an image-'input'-element with the passed src, name and alt" do
- output = @html.image_button("/path/to/image.png", "test", "alternative")
- output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test", "ALT" => "alternative"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.image_button("/path/to/image.png", "test") { "test" }
+ output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.image_button("/path/to/image.png", "test", "alternative") { "test" }
- output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test", "ALT" => "alternative"}, "", not_closed: true)
- end
- end
+ describe "when passed src, name, alt" do
+ it "returns an image-'input'-element with the passed src, name and alt" do
+ output = @html.image_button("/path/to/image.png", "test", "alternative")
+ output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test", "ALT" => "alternative"}, "", not_closed: true)
+ end
- describe "when passed Hash" do
- it "returns a image-'input'-element using the passed Hash for attributes" do
- output = @html.image_button("NAME" => "test", "VALUE" => "test-value")
- output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image", "NAME" => "test", "VALUE" => "test-value"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.image_button("/path/to/image.png", "test", "alternative") { "test" }
+ output.should equal_element("INPUT", {"SRC" => "/path/to/image.png", "TYPE" => "image", "NAME" => "test", "ALT" => "alternative"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.image_button("NAME" => "test", "VALUE" => "test-value") { "test" }
- output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image", "NAME" => "test", "VALUE" => "test-value"}, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns a image-'input'-element using the passed Hash for attributes" do
+ output = @html.image_button("NAME" => "test", "VALUE" => "test-value")
+ output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image", "NAME" => "test", "VALUE" => "test-value"}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.image_button("NAME" => "test", "VALUE" => "test-value") { "test" }
+ output.should equal_element("INPUT", {"SRC" => "", "TYPE" => "image", "NAME" => "test", "VALUE" => "test-value"}, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/img_spec.rb b/spec/ruby/library/cgi/htmlextension/img_spec.rb
index 994ae7fedf..a05cfdea48 100644
--- a/spec/ruby/library/cgi/htmlextension/img_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/img_spec.rb
@@ -1,83 +1,86 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#img" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns an 'img'-element without an src-url or alt-text" do
- output = @html.img
- output.should equal_element("IMG", { "SRC" => "", "ALT" => "" }, "", not_closed: true)
+ describe "CGI::HtmlExtension#img" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.img { "test" }
- output.should equal_element("IMG", { "SRC" => "", "ALT" => "" }, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns an 'img'-element without an src-url or alt-text" do
+ output = @html.img
+ output.should equal_element("IMG", { "SRC" => "", "ALT" => "" }, "", not_closed: true)
+ end
- describe "when passed src" do
- it "returns an 'img'-element with the passed src-url" do
- output = @html.img("/path/to/some/image.png")
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "" }, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.img { "test" }
+ output.should equal_element("IMG", { "SRC" => "", "ALT" => "" }, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.img("/path/to/some/image.png")
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "" }, "", not_closed: true)
- end
- end
+ describe "when passed src" do
+ it "returns an 'img'-element with the passed src-url" do
+ output = @html.img("/path/to/some/image.png")
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "" }, "", not_closed: true)
+ end
- describe "when passed src, alt" do
- it "returns an 'img'-element with the passed src-url and the passed alt-text" do
- output = @html.img("/path/to/some/image.png", "Alternative")
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative" }, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.img("/path/to/some/image.png")
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "" }, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.img("/path/to/some/image.png", "Alternative") { "test" }
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative" }, "", not_closed: true)
- end
- end
+ describe "when passed src, alt" do
+ it "returns an 'img'-element with the passed src-url and the passed alt-text" do
+ output = @html.img("/path/to/some/image.png", "Alternative")
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative" }, "", not_closed: true)
+ end
- describe "when passed src, alt, width" do
- it "returns an 'img'-element with the passed src-url, the passed alt-text and the passed width" do
- output = @html.img("/path/to/some/image.png", "Alternative", 40)
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative", "WIDTH" => "40" }, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.img("/path/to/some/image.png", "Alternative") { "test" }
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative" }, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.img("/path/to/some/image.png", "Alternative", 40) { "test" }
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative", "WIDTH" => "40" }, "", not_closed: true)
- end
- end
+ describe "when passed src, alt, width" do
+ it "returns an 'img'-element with the passed src-url, the passed alt-text and the passed width" do
+ output = @html.img("/path/to/some/image.png", "Alternative", 40)
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative", "WIDTH" => "40" }, "", not_closed: true)
+ end
- describe "when passed src, alt, width, height" do
- it "returns an 'img'-element with the passed src-url, the passed alt-text, the passed width and the passed height" do
- output = @html.img("/path/to/some/image.png", "Alternative", 40, 60)
- output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative", "WIDTH" => "40", "HEIGHT" => "60" }, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.img("/path/to/some/image.png", "Alternative", 40) { "test" }
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative", "WIDTH" => "40" }, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.img { "test" }
- output.should equal_element("IMG", { "SRC" => "", "ALT" => "" }, "", not_closed: true)
- end
- end
+ describe "when passed src, alt, width, height" do
+ it "returns an 'img'-element with the passed src-url, the passed alt-text, the passed width and the passed height" do
+ output = @html.img("/path/to/some/image.png", "Alternative", 40, 60)
+ output.should equal_element("IMG", { "SRC" => "/path/to/some/image.png", "ALT" => "Alternative", "WIDTH" => "40", "HEIGHT" => "60" }, "", not_closed: true)
+ end
- describe "when passed Hash" do
- it "returns an 'img'-element with the passed Hash as attributes" do
- attributes = { "SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50 }
- output = @html.img(attributes)
- output.should equal_element("IMG", attributes, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.img { "test" }
+ output.should equal_element("IMG", { "SRC" => "", "ALT" => "" }, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- attributes = { "SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50 }
- output = @html.img(attributes) { "test" }
- output.should equal_element("IMG", attributes, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns an 'img'-element with the passed Hash as attributes" do
+ attributes = { "SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50 }
+ output = @html.img(attributes)
+ output.should equal_element("IMG", attributes, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ attributes = { "SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50 }
+ output = @html.img(attributes) { "test" }
+ output.should equal_element("IMG", attributes, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb b/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
index 0bf2042a33..4b56a7abfe 100644
--- a/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
@@ -1,64 +1,67 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#multipart_form" do
- before :each do
- @html = CGISpecs.cgi_new
- @html.stub!(:script_name).and_return("/path/to/some/script.rb")
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a 'form'-element with it's enctype set to multipart" do
- output = @html.multipart_form
- output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post" }, "")
+ describe "CGI::HtmlExtension#multipart_form" do
+ before :each do
+ @html = CGISpecs.cgi_new
+ @html.stub!(:script_name).and_return("/path/to/some/script.rb")
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.multipart_form { "test" }
- output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post" }, "test")
- end
- end
+ describe "when passed no arguments" do
+ it "returns a 'form'-element with its enctype set to multipart" do
+ output = @html.multipart_form
+ output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post" }, "")
+ end
- describe "when passed action" do
- it "returns a 'form'-element with the passed action" do
- output = @html.multipart_form("/some/other/script.rb")
- output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.multipart_form { "test" }
+ output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post" }, "test")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.multipart_form("/some/other/script.rb") { "test" }
- output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "test")
- end
- end
+ describe "when passed action" do
+ it "returns a 'form'-element with the passed action" do
+ output = @html.multipart_form("/some/other/script.rb")
+ output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "")
+ end
- describe "when passed action, enctype" do
- it "returns a 'form'-element with the passed action and enctype" do
- output = @html.multipart_form("/some/other/script.rb", "application/x-www-form-urlencoded")
- output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.multipart_form("/some/other/script.rb") { "test" }
+ output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "test")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.multipart_form("/some/other/script.rb", "application/x-www-form-urlencoded") { "test" }
- output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "test")
+ describe "when passed action, enctype" do
+ it "returns a 'form'-element with the passed action and enctype" do
+ output = @html.multipart_form("/some/other/script.rb", "application/x-www-form-urlencoded")
+ output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "")
+ end
+
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.multipart_form("/some/other/script.rb", "application/x-www-form-urlencoded") { "test" }
+ output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "post", "ACTION" => "/some/other/script.rb" }, "test")
+ end
end
- end
- describe "when passed Hash" do
- it "returns a 'form'-element with the passed Hash as attributes" do
- output = @html.multipart_form("ID" => "test")
- output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ID" => "test" }, "")
+ describe "when passed Hash" do
+ it "returns a 'form'-element with the passed Hash as attributes" do
+ output = @html.multipart_form("ID" => "test")
+ output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ID" => "test" }, "")
- output = @html.multipart_form("ID" => "test", "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get")
- output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ID" => "test" }, "")
- end
+ output = @html.multipart_form("ID" => "test", "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get")
+ output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ID" => "test" }, "")
+ end
- it "includes the return value of the passed block when passed a block" do
- output = @html.multipart_form("ID" => "test") { "test" }
- output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ID" => "test" }, "test")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.multipart_form("ID" => "test") { "test" }
+ output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post", "ID" => "test" }, "test")
- output = @html.multipart_form("ID" => "test", "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get") { "test" }
- output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ID" => "test" }, "test")
+ output = @html.multipart_form("ID" => "test", "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get") { "test" }
+ output.should equal_element("FORM", { "ENCTYPE" => "application/x-www-form-urlencoded", "METHOD" => "get", "ID" => "test" }, "test")
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/password_field_spec.rb b/spec/ruby/library/cgi/htmlextension/password_field_spec.rb
index 683bc428ba..0fefdd5c45 100644
--- a/spec/ruby/library/cgi/htmlextension/password_field_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/password_field_spec.rb
@@ -1,84 +1,87 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#password_field" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns an password-'input'-element without a name" do
- output = @html.password_field
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#password_field" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.password_field { "test" }
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns an password-'input'-element without a name" do
+ output = @html.password_field
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
+ end
- describe "when passed name" do
- it "returns an password-'input'-element with the passed name" do
- output = @html.password_field("test")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.password_field { "test" }
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.password_field("test") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
- end
- end
+ describe "when passed name" do
+ it "returns an password-'input'-element with the passed name" do
+ output = @html.password_field("test")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
+ end
- describe "when passed name, value" do
- it "returns an password-'input'-element with the passed name and value" do
- output = @html.password_field("test", "some value")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.password_field("test") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "SIZE" => "40"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.password_field("test", "some value") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
- end
- end
+ describe "when passed name, value" do
+ it "returns an password-'input'-element with the passed name and value" do
+ output = @html.password_field("test", "some value")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
+ end
- describe "when passed name, value, size" do
- it "returns an password-'input'-element with the passed name, value and size" do
- output = @html.password_field("test", "some value", 60)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.password_field("test", "some value") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.password_field("test", "some value", 60) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
- end
- end
+ describe "when passed name, value, size" do
+ it "returns an password-'input'-element with the passed name, value and size" do
+ output = @html.password_field("test", "some value", 60)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
+ end
- describe "when passed name, value, size, maxlength" do
- it "returns an password-'input'-element with the passed name, value, size and maxlength" do
- output = @html.password_field("test", "some value", 60, 12)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.password_field("test", "some value", 60) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.password_field("test", "some value", 60, 12) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ describe "when passed name, value, size, maxlength" do
+ it "returns an password-'input'-element with the passed name, value, size and maxlength" do
+ output = @html.password_field("test", "some value", 60, 12)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.password_field("test", "some value", 60, 12) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "password", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ end
end
- end
- describe "when passed Hash" do
- it "returns a checkbox-'input'-element using the passed Hash for attributes" do
- output = @html.password_field("NAME" => "test", "VALUE" => "some value")
- output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "password" }, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns a checkbox-'input'-element using the passed Hash for attributes" do
+ output = @html.password_field("NAME" => "test", "VALUE" => "some value")
+ output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "password" }, "", not_closed: true)
- output = @html.password_field("TYPE" => "hidden")
- output.should equal_element("INPUT", {"TYPE" => "password"}, "", not_closed: true)
- end
+ output = @html.password_field("TYPE" => "hidden")
+ output.should equal_element("INPUT", {"TYPE" => "password"}, "", not_closed: true)
+ end
- it "ignores a passed block" do
- output = @html.password_field("NAME" => "test", "VALUE" => "some value") { "test" }
- output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "password" }, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.password_field("NAME" => "test", "VALUE" => "some value") { "test" }
+ output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "password" }, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb b/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb
index 3462be09b0..7452d15317 100644
--- a/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/popup_menu_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-require_relative 'shared/popup_menu'
-describe "CGI::HtmlExtension#popup_menu" do
- it_behaves_like :cgi_htmlextension_popup_menu, :popup_menu
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
+ require_relative 'shared/popup_menu'
+
+ describe "CGI::HtmlExtension#popup_menu" do
+ it_behaves_like :cgi_htmlextension_popup_menu, :popup_menu
+ end
end
diff --git a/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb b/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb
index 3dc3c879b5..8458685cdc 100644
--- a/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/radio_button_spec.rb
@@ -1,77 +1,80 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#radio_button" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a radio-'input'-element without a name" do
- output = @html.radio_button
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "radio"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#radio_button" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.radio_button { "test" }
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "radio"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns a radio-'input'-element without a name" do
+ output = @html.radio_button
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "radio"}, "", not_closed: true)
+ end
- describe "when passed name" do
- it "returns a radio-'input'-element with the passed name" do
- output = @html.radio_button("test")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.radio_button { "test" }
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "radio"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.radio_button("test") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio"}, "", not_closed: true)
- end
- end
+ describe "when passed name" do
+ it "returns a radio-'input'-element with the passed name" do
+ output = @html.radio_button("test")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio"}, "", not_closed: true)
+ end
- describe "CGI::HtmlExtension#checkbox when passed name, value" do
- it "returns a radio-'input'-element with the passed name and value" do
- output = @html.radio_button("test", "test-value")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.radio_button("test") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.radio_button("test", "test-value") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#checkbox when passed name, value" do
+ it "returns a radio-'input'-element with the passed name and value" do
+ output = @html.radio_button("test", "test-value")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.radio_button("test", "test-value") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ end
end
- end
- describe "when passed name, value, checked" do
- it "returns a checked radio-'input'-element with the passed name and value when checked is true" do
- output = @html.radio_button("test", "test-value", true)
- output.should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ describe "when passed name, value, checked" do
+ it "returns a checked radio-'input'-element with the passed name and value when checked is true" do
+ output = @html.radio_button("test", "test-value", true)
+ output.should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
- output = @html.radio_button("test", "test-value", false)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ output = @html.radio_button("test", "test-value", false)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
- output = @html.radio_button("test", "test-value", nil)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
- end
+ output = @html.radio_button("test", "test-value", nil)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ end
- it "ignores a passed block" do
- output = @html.radio_button("test", "test-value", nil) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.radio_button("test", "test-value", nil) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "test-value"}, "", not_closed: true)
+ end
end
- end
- describe "when passed Hash" do
- it "returns a radio-'input'-element using the passed Hash for attributes" do
- attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
- output = @html.radio_button(attributes)
- output.should equal_element("INPUT", attributes, "", not_closed: true)
- end
+ describe "when passed Hash" do
+ it "returns a radio-'input'-element using the passed Hash for attributes" do
+ attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
+ output = @html.radio_button(attributes)
+ output.should equal_element("INPUT", attributes, "", not_closed: true)
+ end
- it "ignores a passed block" do
- attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
- output = @html.radio_button(attributes) { "test" }
- output.should equal_element("INPUT", attributes, "", not_closed: true)
+ it "ignores a passed block" do
+ attributes = {"NAME" => "test", "VALUE" => "test-value", "CHECKED" => true}
+ output = @html.radio_button(attributes) { "test" }
+ output.should equal_element("INPUT", attributes, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb b/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb
index 1bfd43449d..fd925a5165 100644
--- a/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/radio_group_spec.rb
@@ -1,77 +1,80 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#radio_group" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed name, values ..." do
- it "returns a sequence of 'radio'-elements with the passed name and the passed values" do
- output = CGISpecs.split(@html.radio_group("test", "foo", "bar", "baz"))
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ describe "CGI::HtmlExtension#radio_group" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "allows passing a value inside an Array" do
- output = CGISpecs.split(@html.radio_group("test", ["foo"], "bar", ["baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
- end
+ describe "when passed name, values ..." do
+ it "returns a sequence of 'radio'-elements with the passed name and the passed values" do
+ output = CGISpecs.split(@html.radio_group("test", "foo", "bar", "baz"))
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
- it "allows passing a value as an Array containing the value and the checked state or a label" do
- output = CGISpecs.split(@html.radio_group("test", ["foo"], ["bar", true], ["baz", "label for baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "label for baz", not_closed: true)
- end
+ it "allows passing a value inside an Array" do
+ output = CGISpecs.split(@html.radio_group("test", ["foo"], "bar", ["baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
- # TODO: CGI does not like passing false instead of true.
- it "allows passing a value as an Array containing the value, a label and the checked state" do
- output = CGISpecs.split(@html.radio_group("test", ["foo", "label for foo", true], ["bar", "label for bar", false], ["baz", "label for baz", true]))
- output[0].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "label for foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "label for bar", not_closed: true)
- output[2].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "label for baz", not_closed: true)
- end
+ it "allows passing a value as an Array containing the value and the checked state or a label" do
+ output = CGISpecs.split(@html.radio_group("test", ["foo"], ["bar", true], ["baz", "label for baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "label for baz", not_closed: true)
+ end
- it "returns an empty String when passed no values" do
- @html.radio_group("test").should == ""
- end
+ # TODO: CGI does not like passing false instead of true.
+ it "allows passing a value as an Array containing the value, a label and the checked state" do
+ output = CGISpecs.split(@html.radio_group("test", ["foo", "label for foo", true], ["bar", "label for bar", false], ["baz", "label for baz", true]))
+ output[0].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "label for foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "label for bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "label for baz", not_closed: true)
+ end
+
+ it "returns an empty String when passed no values" do
+ @html.radio_group("test").should == ""
+ end
- it "ignores a passed block" do
- output = CGISpecs.split(@html.radio_group("test", "foo", "bar", "baz") { "test" })
- output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ it "ignores a passed block" do
+ output = CGISpecs.split(@html.radio_group("test", "foo", "bar", "baz") { "test" })
+ output[0].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "test", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
end
- end
- describe "when passed Hash" do
- it "uses the passed Hash to generate the radio sequence" do
- output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ describe "when passed Hash" do
+ it "uses the passed Hash to generate the radio sequence" do
+ output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
- output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => [["foo"], ["bar", true], "baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => [["foo"], ["bar", true], "baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
- output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]))
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "1"}, "Foo", not_closed: true)
- output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "radio", "VALUE" => "2"}, "Bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "Baz"}, "Baz", not_closed: true)
- end
+ output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"]))
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "1"}, "Foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"CHECKED" => true, "NAME" => "name", "TYPE" => "radio", "VALUE" => "2"}, "Bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "Baz"}, "Baz", not_closed: true)
+ end
- it "ignores a passed block" do
- output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]) { "test" })
- output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
- output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
- output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ it "ignores a passed block" do
+ output = CGISpecs.split(@html.radio_group("NAME" => "name", "VALUES" => ["foo", "bar", "baz"]) { "test" })
+ output[0].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "foo"}, "foo", not_closed: true)
+ output[1].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "bar"}, "bar", not_closed: true)
+ output[2].should equal_element("INPUT", {"NAME" => "name", "TYPE" => "radio", "VALUE" => "baz"}, "baz", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/reset_spec.rb b/spec/ruby/library/cgi/htmlextension/reset_spec.rb
index 86fa25fc8a..80e4441b16 100644
--- a/spec/ruby/library/cgi/htmlextension/reset_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/reset_spec.rb
@@ -1,57 +1,60 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#reset" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a reset-'input'-element" do
- output = @html.reset
- output.should equal_element("INPUT", {"TYPE" => "reset"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#reset" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.reset { "test" }
- output.should equal_element("INPUT", {"TYPE" => "reset"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns a reset-'input'-element" do
+ output = @html.reset
+ output.should equal_element("INPUT", {"TYPE" => "reset"}, "", not_closed: true)
+ end
- describe "when passed value" do
- it "returns a reset-'input'-element with the passed value" do
- output = @html.reset("Example")
- output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.reset { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "reset"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.reset("Example") { "test" }
- output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
- end
- end
+ describe "when passed value" do
+ it "returns a reset-'input'-element with the passed value" do
+ output = @html.reset("Example")
+ output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ end
- describe "when passed value, name" do
- it "returns a reset-'input'-element with the passed value and the passed name" do
- output = @html.reset("Example", "test-name")
- output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.reset("Example") { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.reset("Example", "test-name") { "test" }
- output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
- end
- end
+ describe "when passed value, name" do
+ it "returns a reset-'input'-element with the passed value and the passed name" do
+ output = @html.reset("Example", "test-name")
+ output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
+ end
- describe "when passed Hash" do
- it "returns a reset-'input'-element with the passed value" do
- output = @html.reset("Example")
- output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.reset("Example", "test-name") { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.reset("Example") { "test" }
- output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns a reset-'input'-element with the passed value" do
+ output = @html.reset("Example")
+ output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.reset("Example") { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "reset", "VALUE" => "Example"}, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb b/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb
index 4eb0c86c1a..b565444679 100644
--- a/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/scrolling_list_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../../spec_helper'
-require_relative 'fixtures/common'
-require 'cgi'
-require_relative 'shared/popup_menu'
-describe "CGI::HtmlExtension#scrolling_list" do
- it_behaves_like :cgi_htmlextension_popup_menu, :scrolling_list
+ruby_version_is ""..."4.0" do
+ require_relative 'fixtures/common'
+ require 'cgi'
+ require_relative 'shared/popup_menu'
+
+ describe "CGI::HtmlExtension#scrolling_list" do
+ it_behaves_like :cgi_htmlextension_popup_menu, :scrolling_list
+ end
end
diff --git a/spec/ruby/library/cgi/htmlextension/submit_spec.rb b/spec/ruby/library/cgi/htmlextension/submit_spec.rb
index 063891b959..bb6e079c4e 100644
--- a/spec/ruby/library/cgi/htmlextension/submit_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/submit_spec.rb
@@ -1,57 +1,60 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#submit" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns a submit-'input'-element" do
- output = @html.submit
- output.should equal_element("INPUT", {"TYPE" => "submit"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#submit" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.submit { "test" }
- output.should equal_element("INPUT", {"TYPE" => "submit"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns a submit-'input'-element" do
+ output = @html.submit
+ output.should equal_element("INPUT", {"TYPE" => "submit"}, "", not_closed: true)
+ end
- describe "when passed value" do
- it "returns a submit-'input'-element with the passed value" do
- output = @html.submit("Example")
- output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.submit { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "submit"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.submit("Example") { "test" }
- output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
- end
- end
+ describe "when passed value" do
+ it "returns a submit-'input'-element with the passed value" do
+ output = @html.submit("Example")
+ output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ end
- describe "when passed value, name" do
- it "returns a submit-'input'-element with the passed value and the passed name" do
- output = @html.submit("Example", "test-name")
- output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.submit("Example") { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.submit("Example", "test-name") { "test" }
- output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
- end
- end
+ describe "when passed value, name" do
+ it "returns a submit-'input'-element with the passed value and the passed name" do
+ output = @html.submit("Example", "test-name")
+ output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
+ end
- describe "when passed Hash" do
- it "returns a submit-'input'-element with the passed value" do
- output = @html.submit("Example")
- output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.submit("Example", "test-name") { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example", "NAME" => "test-name"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.submit("Example") { "test" }
- output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns a submit-'input'-element with the passed value" do
+ output = @html.submit("Example")
+ output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.submit("Example") { "test" }
+ output.should equal_element("INPUT", {"TYPE" => "submit", "VALUE" => "Example"}, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/text_field_spec.rb b/spec/ruby/library/cgi/htmlextension/text_field_spec.rb
index 44b5a5e69f..37e13e3746 100644
--- a/spec/ruby/library/cgi/htmlextension/text_field_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/text_field_spec.rb
@@ -1,84 +1,87 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#text_field" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns an text-'input'-element without a name" do
- output = @html.text_field
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
+ describe "CGI::HtmlExtension#text_field" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "ignores a passed block" do
- output = @html.text_field { "test" }
- output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
- end
- end
+ describe "when passed no arguments" do
+ it "returns an text-'input'-element without a name" do
+ output = @html.text_field
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
+ end
- describe "when passed name" do
- it "returns an text-'input'-element with the passed name" do
- output = @html.text_field("test")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.text_field { "test" }
+ output.should equal_element("INPUT", {"NAME" => "", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.text_field("test") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
- end
- end
+ describe "when passed name" do
+ it "returns an text-'input'-element with the passed name" do
+ output = @html.text_field("test")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
+ end
- describe "when passed name, value" do
- it "returns an text-'input'-element with the passed name and value" do
- output = @html.text_field("test", "some value")
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.text_field("test") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "SIZE" => "40"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.text_field("test", "some value") { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
- end
- end
+ describe "when passed name, value" do
+ it "returns an text-'input'-element with the passed name and value" do
+ output = @html.text_field("test", "some value")
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
+ end
- describe "when passed name, value, size" do
- it "returns an text-'input'-element with the passed name, value and size" do
- output = @html.text_field("test", "some value", 60)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.text_field("test", "some value") { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "40"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.text_field("test", "some value", 60) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
- end
- end
+ describe "when passed name, value, size" do
+ it "returns an text-'input'-element with the passed name, value and size" do
+ output = @html.text_field("test", "some value", 60)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
+ end
- describe "when passed name, value, size, maxlength" do
- it "returns an text-'input'-element with the passed name, value, size and maxlength" do
- output = @html.text_field("test", "some value", 60, 12)
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.text_field("test", "some value", 60) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60"}, "", not_closed: true)
+ end
end
- it "ignores a passed block" do
- output = @html.text_field("test", "some value", 60, 12) { "test" }
- output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ describe "when passed name, value, size, maxlength" do
+ it "returns an text-'input'-element with the passed name, value, size and maxlength" do
+ output = @html.text_field("test", "some value", 60, 12)
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ end
+
+ it "ignores a passed block" do
+ output = @html.text_field("test", "some value", 60, 12) { "test" }
+ output.should equal_element("INPUT", {"NAME" => "test", "TYPE" => "text", "VALUE" => "some value", "SIZE" => "60", "MAXLENGTH" => 12}, "", not_closed: true)
+ end
end
- end
- describe "when passed Hash" do
- it "returns a checkbox-'input'-element using the passed Hash for attributes" do
- output = @html.text_field("NAME" => "test", "VALUE" => "some value")
- output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "text" }, "", not_closed: true)
+ describe "when passed Hash" do
+ it "returns a checkbox-'input'-element using the passed Hash for attributes" do
+ output = @html.text_field("NAME" => "test", "VALUE" => "some value")
+ output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "text" }, "", not_closed: true)
- output = @html.text_field("TYPE" => "hidden")
- output.should equal_element("INPUT", {"TYPE" => "text"}, "", not_closed: true)
- end
+ output = @html.text_field("TYPE" => "hidden")
+ output.should equal_element("INPUT", {"TYPE" => "text"}, "", not_closed: true)
+ end
- it "ignores a passed block" do
- output = @html.text_field("NAME" => "test", "VALUE" => "some value") { "test" }
- output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "text" }, "", not_closed: true)
+ it "ignores a passed block" do
+ output = @html.text_field("NAME" => "test", "VALUE" => "some value") { "test" }
+ output.should equal_element("INPUT", { "NAME" => "test", "VALUE" => "some value", "TYPE" => "text" }, "", not_closed: true)
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/htmlextension/textarea_spec.rb b/spec/ruby/library/cgi/htmlextension/textarea_spec.rb
index db84a973d2..99c6d3dd2d 100644
--- a/spec/ruby/library/cgi/htmlextension/textarea_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/textarea_spec.rb
@@ -1,73 +1,76 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'fixtures/common'
-describe "CGI::HtmlExtension#textarea" do
- before :each do
- @html = CGISpecs.cgi_new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'fixtures/common'
- describe "when passed no arguments" do
- it "returns an 'textarea'-element without a name" do
- output = @html.textarea
- output.should equal_element("TEXTAREA", {"NAME" => "", "COLS" => "70", "ROWS" => "10"}, "")
+ describe "CGI::HtmlExtension#textarea" do
+ before :each do
+ @html = CGISpecs.cgi_new
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.textarea { "Example" }
- output.should equal_element("TEXTAREA", {"NAME" => "", "COLS" => "70", "ROWS" => "10"}, "Example")
- end
- end
+ describe "when passed no arguments" do
+ it "returns an 'textarea'-element without a name" do
+ output = @html.textarea
+ output.should equal_element("TEXTAREA", {"NAME" => "", "COLS" => "70", "ROWS" => "10"}, "")
+ end
- describe "when passed name" do
- it "returns an 'textarea'-element with the passed name" do
- output = @html.textarea("test")
- output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "70", "ROWS" => "10"}, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.textarea { "Example" }
+ output.should equal_element("TEXTAREA", {"NAME" => "", "COLS" => "70", "ROWS" => "10"}, "Example")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.textarea("test") { "Example" }
- output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "70", "ROWS" => "10"}, "Example")
- end
- end
+ describe "when passed name" do
+ it "returns an 'textarea'-element with the passed name" do
+ output = @html.textarea("test")
+ output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "70", "ROWS" => "10"}, "")
+ end
- describe "when passed name, cols" do
- it "returns an 'textarea'-element with the passed name and the passed amount of columns" do
- output = @html.textarea("test", 40)
- output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "10"}, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.textarea("test") { "Example" }
+ output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "70", "ROWS" => "10"}, "Example")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.textarea("test", 40) { "Example" }
- output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "10"}, "Example")
- end
- end
+ describe "when passed name, cols" do
+ it "returns an 'textarea'-element with the passed name and the passed amount of columns" do
+ output = @html.textarea("test", 40)
+ output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "10"}, "")
+ end
- describe "when passed name, cols, rows" do
- it "returns an 'textarea'-element with the passed name, the passed amount of columns and the passed number of rows" do
- output = @html.textarea("test", 40, 5)
- output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "5"}, "")
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.textarea("test", 40) { "Example" }
+ output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "10"}, "Example")
+ end
end
- it "includes the return value of the passed block when passed a block" do
- output = @html.textarea("test", 40, 5) { "Example" }
- output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "5"}, "Example")
+ describe "when passed name, cols, rows" do
+ it "returns an 'textarea'-element with the passed name, the passed amount of columns and the passed number of rows" do
+ output = @html.textarea("test", 40, 5)
+ output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "5"}, "")
+ end
+
+ it "includes the return value of the passed block when passed a block" do
+ output = @html.textarea("test", 40, 5) { "Example" }
+ output.should equal_element("TEXTAREA", {"NAME" => "test", "COLS" => "40", "ROWS" => "5"}, "Example")
+ end
end
- end
- describe "when passed Hash" do
- it "uses the passed Hash as attributes" do
- @html.textarea("ID" => "test").should == '<TEXTAREA ID="test"></TEXTAREA>'
+ describe "when passed Hash" do
+ it "uses the passed Hash as attributes" do
+ @html.textarea("ID" => "test").should == '<TEXTAREA ID="test"></TEXTAREA>'
- attributes = {"ID" => "test-id", "NAME" => "test-name"}
- output = @html.textarea(attributes)
- output.should equal_element("TEXTAREA", attributes, "")
- end
+ attributes = {"ID" => "test-id", "NAME" => "test-name"}
+ output = @html.textarea(attributes)
+ output.should equal_element("TEXTAREA", attributes, "")
+ end
- it "includes the return value of the passed block when passed a block" do
- attributes = {"ID" => "test-id", "NAME" => "test-name"}
- output = @html.textarea(attributes) { "test" }
- output.should equal_element("TEXTAREA", attributes, "test")
+ it "includes the return value of the passed block when passed a block" do
+ attributes = {"ID" => "test-id", "NAME" => "test-name"}
+ output = @html.textarea(attributes) { "test" }
+ output.should equal_element("TEXTAREA", attributes, "test")
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/http_header_spec.rb b/spec/ruby/library/cgi/http_header_spec.rb
index 4094bebed3..8d9f3fe9b8 100644
--- a/spec/ruby/library/cgi/http_header_spec.rb
+++ b/spec/ruby/library/cgi/http_header_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require 'cgi'
-require_relative 'shared/http_header'
+ruby_version_is ""..."4.0" do
+ require 'cgi'
-describe "CGI#http_header" do
- it_behaves_like :cgi_http_header, :http_header
+ require_relative 'shared/http_header'
+
+ describe "CGI#http_header" do
+ it_behaves_like :cgi_http_header, :http_header
+ end
end
diff --git a/spec/ruby/library/cgi/initialize_spec.rb b/spec/ruby/library/cgi/initialize_spec.rb
index 61bc971d49..6135522c54 100644
--- a/spec/ruby/library/cgi/initialize_spec.rb
+++ b/spec/ruby/library/cgi/initialize_spec.rb
@@ -1,133 +1,136 @@
require_relative '../../spec_helper'
-require 'cgi'
-describe "CGI#initialize" do
- it "is private" do
- CGI.should have_private_instance_method(:initialize)
- end
-end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
-describe "CGI#initialize when passed no arguments" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.allocate
- end
-
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
-
- it "extends self with CGI::QueryExtension" do
- @cgi.send(:initialize)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ describe "CGI#initialize" do
+ it "is private" do
+ CGI.private_instance_methods(false).should.include?(:initialize)
+ end
end
- it "does not extend self with CGI::HtmlExtension" do
- @cgi.send(:initialize)
- @cgi.should_not be_kind_of(CGI::HtmlExtension)
- end
+ describe "CGI#initialize when passed no arguments" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.allocate
+ end
- it "does not extend self with any of the other HTML modules" do
- @cgi.send(:initialize)
- @cgi.should_not be_kind_of(CGI::HtmlExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4)
- @cgi.should_not be_kind_of(CGI::Html4Tr)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
- end
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "sets #cookies based on ENV['HTTP_COOKIE']" do
- begin
- old_env, ENV["HTTP_COOKIE"] = ENV["HTTP_COOKIE"], "test=test yay"
+ it "extends self with CGI::QueryExtension" do
@cgi.send(:initialize)
- @cgi.cookies.should == { "test"=>[ "test yay" ] }
- ensure
- ENV["HTTP_COOKIE"] = old_env
+ @cgi.should.is_a?(CGI::QueryExtension)
end
- end
- it "sets #params based on ENV['QUERY_STRING'] when ENV['REQUEST_METHOD'] is GET" do
- begin
- old_env_query, ENV["QUERY_STRING"] = ENV["QUERY_STRING"], "?test=a&test2=b"
- old_env_method, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], "GET"
+ it "does not extend self with CGI::HtmlExtension" do
@cgi.send(:initialize)
- @cgi.params.should == { "test2" => ["b"], "?test" => ["a"] }
- ensure
- ENV["QUERY_STRING"] = old_env_query
- ENV["REQUEST_METHOD"] = old_env_method
+ @cgi.should_not.is_a?(CGI::HtmlExtension)
end
- end
- it "sets #params based on ENV['QUERY_STRING'] when ENV['REQUEST_METHOD'] is HEAD" do
- begin
- old_env_query, ENV["QUERY_STRING"] = ENV["QUERY_STRING"], "?test=a&test2=b"
- old_env_method, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], "HEAD"
+ it "does not extend self with any of the other HTML modules" do
@cgi.send(:initialize)
- @cgi.params.should == { "test2" => ["b"], "?test" => ["a"] }
- ensure
- ENV["QUERY_STRING"] = old_env_query
- ENV["REQUEST_METHOD"] = old_env_method
+ @cgi.should_not.is_a?(CGI::HtmlExtension)
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html4Tr)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
end
- end
-end
-describe "CGI#initialize when passed type" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.allocate
- end
+ it "sets #cookies based on ENV['HTTP_COOKIE']" do
+ begin
+ old_env, ENV["HTTP_COOKIE"] = ENV["HTTP_COOKIE"], "test=test yay"
+ @cgi.send(:initialize)
+ @cgi.cookies.should == { "test"=>[ "test yay" ] }
+ ensure
+ ENV["HTTP_COOKIE"] = old_env
+ end
+ end
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
+ it "sets #params based on ENV['QUERY_STRING'] when ENV['REQUEST_METHOD'] is GET" do
+ begin
+ old_env_query, ENV["QUERY_STRING"] = ENV["QUERY_STRING"], "?test=a&test2=b"
+ old_env_method, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], "GET"
+ @cgi.send(:initialize)
+ @cgi.params.should == { "test2" => ["b"], "?test" => ["a"] }
+ ensure
+ ENV["QUERY_STRING"] = old_env_query
+ ENV["REQUEST_METHOD"] = old_env_method
+ end
+ end
+
+ it "sets #params based on ENV['QUERY_STRING'] when ENV['REQUEST_METHOD'] is HEAD" do
+ begin
+ old_env_query, ENV["QUERY_STRING"] = ENV["QUERY_STRING"], "?test=a&test2=b"
+ old_env_method, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], "HEAD"
+ @cgi.send(:initialize)
+ @cgi.params.should == { "test2" => ["b"], "?test" => ["a"] }
+ ensure
+ ENV["QUERY_STRING"] = old_env_query
+ ENV["REQUEST_METHOD"] = old_env_method
+ end
+ end
end
+ describe "CGI#initialize when passed type" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.allocate
+ end
- it "extends self with CGI::QueryExtension" do
- @cgi.send(:initialize, "test")
- @cgi.should be_kind_of(CGI::QueryExtension)
- end
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "extends self with CGI::QueryExtension, CGI::Html3 and CGI::HtmlExtension when the passed type is 'html3'" do
- @cgi.send(:initialize, "html3")
- @cgi.should be_kind_of(CGI::Html3)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html4)
- @cgi.should_not be_kind_of(CGI::Html4Tr)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
- end
+ it "extends self with CGI::QueryExtension" do
+ @cgi.send(:initialize, "test")
+ @cgi.should.is_a?(CGI::QueryExtension)
+ end
- it "extends self with CGI::QueryExtension, CGI::Html4 and CGI::HtmlExtension when the passed type is 'html4'" do
- @cgi.send(:initialize, "html4")
- @cgi.should be_kind_of(CGI::Html4)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ it "extends self with CGI::QueryExtension, CGI::Html3 and CGI::HtmlExtension when the passed type is 'html3'" do
+ @cgi.send(:initialize, "html3")
+ @cgi.should.is_a?(CGI::Html3)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4Tr)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
- end
+ @cgi.should_not.is_a?(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html4Tr)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
+ end
- it "extends self with CGI::QueryExtension, CGI::Html4Tr and CGI::HtmlExtension when the passed type is 'html4Tr'" do
- @cgi.send(:initialize, "html4Tr")
- @cgi.should be_kind_of(CGI::Html4Tr)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ it "extends self with CGI::QueryExtension, CGI::Html4 and CGI::HtmlExtension when the passed type is 'html4'" do
+ @cgi.send(:initialize, "html4")
+ @cgi.should.is_a?(CGI::Html4)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4)
- @cgi.should_not be_kind_of(CGI::Html4Fr)
- end
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4Tr)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
+ end
- it "extends self with CGI::QueryExtension, CGI::Html4Tr, CGI::Html4Fr and CGI::HtmlExtension when the passed type is 'html4Fr'" do
- @cgi.send(:initialize, "html4Fr")
- @cgi.should be_kind_of(CGI::Html4Tr)
- @cgi.should be_kind_of(CGI::Html4Fr)
- @cgi.should be_kind_of(CGI::HtmlExtension)
- @cgi.should be_kind_of(CGI::QueryExtension)
+ it "extends self with CGI::QueryExtension, CGI::Html4Tr and CGI::HtmlExtension when the passed type is 'html4Tr'" do
+ @cgi.send(:initialize, "html4Tr")
+ @cgi.should.is_a?(CGI::Html4Tr)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
- @cgi.should_not be_kind_of(CGI::Html3)
- @cgi.should_not be_kind_of(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4)
+ @cgi.should_not.is_a?(CGI::Html4Fr)
+ end
+
+ it "extends self with CGI::QueryExtension, CGI::Html4Tr, CGI::Html4Fr and CGI::HtmlExtension when the passed type is 'html4Fr'" do
+ @cgi.send(:initialize, "html4Fr")
+ @cgi.should.is_a?(CGI::Html4Tr)
+ @cgi.should.is_a?(CGI::Html4Fr)
+ @cgi.should.is_a?(CGI::HtmlExtension)
+ @cgi.should.is_a?(CGI::QueryExtension)
+
+ @cgi.should_not.is_a?(CGI::Html3)
+ @cgi.should_not.is_a?(CGI::Html4)
+ end
end
end
diff --git a/spec/ruby/library/cgi/out_spec.rb b/spec/ruby/library/cgi/out_spec.rb
index bc09f5bcbb..e9eaf5e151 100644
--- a/spec/ruby/library/cgi/out_spec.rb
+++ b/spec/ruby/library/cgi/out_spec.rb
@@ -1,51 +1,54 @@
require_relative '../../spec_helper'
-require 'cgi'
-describe "CGI#out" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- $stdout, @old_stdout = IOStub.new, $stdout
- end
-
- after :each do
- $stdout = @old_stdout
- ENV['REQUEST_METHOD'] = @old_request_method
- end
-
- it "it writes a HTMl header based on the passed argument to $stdout" do
- @cgi.out { "" }
- $stdout.should == "Content-Type: text/html\r\nContent-Length: 0\r\n\r\n"
- end
-
- it "appends the block's return value to the HTML header" do
- @cgi.out { "test!" }
- $stdout.should == "Content-Type: text/html\r\nContent-Length: 5\r\n\r\ntest!"
- end
-
- it "automatically sets the Content-Length Header based on the block's return value" do
- @cgi.out { "0123456789" }
- $stdout.should == "Content-Type: text/html\r\nContent-Length: 10\r\n\r\n0123456789"
- end
-
- it "includes Cookies in the @output_cookies field" do
- @cgi.instance_variable_set(:@output_cookies, ["multiple", "cookies"])
- @cgi.out { "" }
- $stdout.should == "Content-Type: text/html\r\nContent-Length: 0\r\nSet-Cookie: multiple\r\nSet-Cookie: cookies\r\n\r\n"
- end
-end
-
-describe "CGI#out when passed no block" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
-
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
-
- it "raises a LocalJumpError" do
- -> { @cgi.out }.should raise_error(LocalJumpError)
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+
+ describe "CGI#out" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ $stdout, @old_stdout = IOStub.new, $stdout
+ end
+
+ after :each do
+ $stdout = @old_stdout
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
+
+ it "it writes a HTMl header based on the passed argument to $stdout" do
+ @cgi.out { "" }
+ $stdout.should == "Content-Type: text/html\r\nContent-Length: 0\r\n\r\n"
+ end
+
+ it "appends the block's return value to the HTML header" do
+ @cgi.out { "test!" }
+ $stdout.should == "Content-Type: text/html\r\nContent-Length: 5\r\n\r\ntest!"
+ end
+
+ it "automatically sets the Content-Length Header based on the block's return value" do
+ @cgi.out { "0123456789" }
+ $stdout.should == "Content-Type: text/html\r\nContent-Length: 10\r\n\r\n0123456789"
+ end
+
+ it "includes Cookies in the @output_cookies field" do
+ @cgi.instance_variable_set(:@output_cookies, ["multiple", "cookies"])
+ @cgi.out { "" }
+ $stdout.should == "Content-Type: text/html\r\nContent-Length: 0\r\nSet-Cookie: multiple\r\nSet-Cookie: cookies\r\n\r\n"
+ end
+ end
+
+ describe "CGI#out when passed no block" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
+
+ it "raises a LocalJumpError" do
+ -> { @cgi.out }.should.raise(LocalJumpError)
+ end
end
end
diff --git a/spec/ruby/library/cgi/parse_spec.rb b/spec/ruby/library/cgi/parse_spec.rb
index 04539b1226..f09270c195 100644
--- a/spec/ruby/library/cgi/parse_spec.rb
+++ b/spec/ruby/library/cgi/parse_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require 'cgi'
-describe "CGI.parse when passed String" do
- it "parses a HTTP Query String into a Hash" do
- CGI.parse("test=test&a=b").should == { "a" => ["b"], "test" => ["test"] }
- CGI.parse("test=1,2,3").should == { "test" => ["1,2,3"] }
- CGI.parse("test=a&a=&b=").should == { "test" => ["a"], "a" => [""], "b" => [""] }
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- it "parses query strings with semicolons in place of ampersands" do
- CGI.parse("test=test;a=b").should == { "a" => ["b"], "test" => ["test"] }
- CGI.parse("test=a;a=;b=").should == { "test" => ["a"], "a" => [""], "b" => [""] }
- end
+ describe "CGI.parse when passed String" do
+ it "parses a HTTP Query String into a Hash" do
+ CGI.parse("test=test&a=b").should == { "a" => ["b"], "test" => ["test"] }
+ CGI.parse("test=1,2,3").should == { "test" => ["1,2,3"] }
+ CGI.parse("test=a&a=&b=").should == { "test" => ["a"], "a" => [""], "b" => [""] }
+ end
- it "allows passing multiple values for one key" do
- CGI.parse("test=1&test=2&test=3").should == { "test" => ["1", "2", "3"] }
- CGI.parse("test[]=1&test[]=2&test[]=3").should == { "test[]" => [ "1", "2", "3" ] }
- end
+ it "parses query strings with semicolons in place of ampersands" do
+ CGI.parse("test=test;a=b").should == { "a" => ["b"], "test" => ["test"] }
+ CGI.parse("test=a;a=;b=").should == { "test" => ["a"], "a" => [""], "b" => [""] }
+ end
+
+ it "allows passing multiple values for one key" do
+ CGI.parse("test=1&test=2&test=3").should == { "test" => ["1", "2", "3"] }
+ CGI.parse("test[]=1&test[]=2&test[]=3").should == { "test[]" => [ "1", "2", "3" ] }
+ end
- it "unescapes keys and values" do
- CGI.parse("hello%3F=hello%21").should == { "hello?" => ["hello!"] }
+ it "unescapes keys and values" do
+ CGI.parse("hello%3F=hello%21").should == { "hello?" => ["hello!"] }
+ end
end
end
diff --git a/spec/ruby/library/cgi/pretty_spec.rb b/spec/ruby/library/cgi/pretty_spec.rb
index a7b7505c15..9df1611037 100644
--- a/spec/ruby/library/cgi/pretty_spec.rb
+++ b/spec/ruby/library/cgi/pretty_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require 'cgi'
-describe "CGI.pretty when passed html" do
- it "indents the passed html String with two spaces" do
- CGI.pretty("<HTML><BODY></BODY></HTML>").should == <<-EOS
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+
+ describe "CGI.pretty when passed html" do
+ it "indents the passed html String with two spaces" do
+ CGI.pretty("<HTML><BODY></BODY></HTML>").should == <<-EOS
<HTML>
<BODY>
</BODY>
</HTML>
EOS
+ end
end
-end
-describe "CGI.pretty when passed html, indentation_unit" do
- it "indents the passed html String with the passed indentation_unit" do
- CGI.pretty("<HTML><BODY></BODY></HTML>", "\t").should == <<-EOS
+ describe "CGI.pretty when passed html, indentation_unit" do
+ it "indents the passed html String with the passed indentation_unit" do
+ CGI.pretty("<HTML><BODY></BODY></HTML>", "\t").should == <<-EOS
<HTML>
\t<BODY>
\t</BODY>
</HTML>
EOS
+ end
end
end
diff --git a/spec/ruby/library/cgi/print_spec.rb b/spec/ruby/library/cgi/print_spec.rb
index 18ab8d673b..f4f461c5c0 100644
--- a/spec/ruby/library/cgi/print_spec.rb
+++ b/spec/ruby/library/cgi/print_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../spec_helper'
-require 'cgi'
-describe "CGI#print" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI#print" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
- it "passes all arguments to $stdout.print" do
- $stdout.should_receive(:print).with("test")
- @cgi.print("test")
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- $stdout.should_receive(:print).with("one", "two", "three", ["four", "five"])
- @cgi.print("one", "two", "three", ["four", "five"])
- end
+ it "passes all arguments to $stdout.print" do
+ $stdout.should_receive(:print).with("test")
+ @cgi.print("test")
+
+ $stdout.should_receive(:print).with("one", "two", "three", ["four", "five"])
+ @cgi.print("one", "two", "three", ["four", "five"])
+ end
- it "returns the result of calling $stdout.print" do
- $stdout.should_receive(:print).with("test").and_return(:expected)
- @cgi.print("test").should == :expected
+ it "returns the result of calling $stdout.print" do
+ $stdout.should_receive(:print).with("test").and_return(:expected)
+ @cgi.print("test").should == :expected
+ end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb b/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb
index 0487569b9c..be05f0c175 100644
--- a/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_charset_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#accept_charset" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#accept_charset" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_ACCEPT_CHARSET']" do
- old_value, ENV['HTTP_ACCEPT_CHARSET'] = ENV['HTTP_ACCEPT_CHARSET'], "ISO-8859-1,utf-8;q=0.7,*;q=0.7"
- begin
- @cgi.accept_charset.should == "ISO-8859-1,utf-8;q=0.7,*;q=0.7"
- ensure
- ENV['HTTP_ACCEPT_CHARSET'] = old_value
+ it "returns ENV['HTTP_ACCEPT_CHARSET']" do
+ old_value, ENV['HTTP_ACCEPT_CHARSET'] = ENV['HTTP_ACCEPT_CHARSET'], "ISO-8859-1,utf-8;q=0.7,*;q=0.7"
+ begin
+ @cgi.accept_charset.should == "ISO-8859-1,utf-8;q=0.7,*;q=0.7"
+ ensure
+ ENV['HTTP_ACCEPT_CHARSET'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb b/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb
index 35ff3c2b30..42eb4a49b5 100644
--- a/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_encoding_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#accept_encoding" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#accept_encoding" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_ACCEPT_ENCODING']" do
- old_value, ENV['HTTP_ACCEPT_ENCODING'] = ENV['HTTP_ACCEPT_ENCODING'], "gzip,deflate"
- begin
- @cgi.accept_encoding.should == "gzip,deflate"
- ensure
- ENV['HTTP_ACCEPT_ENCODING'] = old_value
+ it "returns ENV['HTTP_ACCEPT_ENCODING']" do
+ old_value, ENV['HTTP_ACCEPT_ENCODING'] = ENV['HTTP_ACCEPT_ENCODING'], "gzip,deflate"
+ begin
+ @cgi.accept_encoding.should == "gzip,deflate"
+ ensure
+ ENV['HTTP_ACCEPT_ENCODING'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/accept_language_spec.rb b/spec/ruby/library/cgi/queryextension/accept_language_spec.rb
index 4a15d58914..19f29c6345 100644
--- a/spec/ruby/library/cgi/queryextension/accept_language_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_language_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#accept_language" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#accept_language" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_ACCEPT_LANGUAGE']" do
- old_value, ENV['HTTP_ACCEPT_LANGUAGE'] = ENV['HTTP_ACCEPT_LANGUAGE'], "en-us,en;q=0.5"
- begin
- @cgi.accept_language.should == "en-us,en;q=0.5"
- ensure
- ENV['HTTP_ACCEPT_LANGUAGE'] = old_value
+ it "returns ENV['HTTP_ACCEPT_LANGUAGE']" do
+ old_value, ENV['HTTP_ACCEPT_LANGUAGE'] = ENV['HTTP_ACCEPT_LANGUAGE'], "en-us,en;q=0.5"
+ begin
+ @cgi.accept_language.should == "en-us,en;q=0.5"
+ ensure
+ ENV['HTTP_ACCEPT_LANGUAGE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/accept_spec.rb b/spec/ruby/library/cgi/queryextension/accept_spec.rb
index af5209ffbe..dcae39a736 100644
--- a/spec/ruby/library/cgi/queryextension/accept_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/accept_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#accept" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#accept" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_ACCEPT']" do
- old_value, ENV['HTTP_ACCEPT'] = ENV['HTTP_ACCEPT'], "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
- begin
- @cgi.accept.should == "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
- ensure
- ENV['HTTP_ACCEPT'] = old_value
+ it "returns ENV['HTTP_ACCEPT']" do
+ old_value, ENV['HTTP_ACCEPT'] = ENV['HTTP_ACCEPT'], "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
+ begin
+ @cgi.accept.should == "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
+ ensure
+ ENV['HTTP_ACCEPT'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/auth_type_spec.rb b/spec/ruby/library/cgi/queryextension/auth_type_spec.rb
index 25318269b1..75e9cdb27a 100644
--- a/spec/ruby/library/cgi/queryextension/auth_type_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/auth_type_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#auth_type" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#auth_type" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['AUTH_TYPE']" do
- old_value, ENV['AUTH_TYPE'] = ENV['AUTH_TYPE'], "Basic"
- begin
- @cgi.auth_type.should == "Basic"
- ensure
- ENV['AUTH_TYPE'] = old_value
+ it "returns ENV['AUTH_TYPE']" do
+ old_value, ENV['AUTH_TYPE'] = ENV['AUTH_TYPE'], "Basic"
+ begin
+ @cgi.auth_type.should == "Basic"
+ ensure
+ ENV['AUTH_TYPE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/cache_control_spec.rb b/spec/ruby/library/cgi/queryextension/cache_control_spec.rb
index 0471307c22..c4b727e671 100644
--- a/spec/ruby/library/cgi/queryextension/cache_control_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/cache_control_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#cache_control" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#cache_control" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_CACHE_CONTROL']" do
- old_value, ENV['HTTP_CACHE_CONTROL'] = ENV['HTTP_CACHE_CONTROL'], "no-cache"
- begin
- @cgi.cache_control.should == "no-cache"
- ensure
- ENV['HTTP_CACHE_CONTROL'] = old_value
+ it "returns ENV['HTTP_CACHE_CONTROL']" do
+ old_value, ENV['HTTP_CACHE_CONTROL'] = ENV['HTTP_CACHE_CONTROL'], "no-cache"
+ begin
+ @cgi.cache_control.should == "no-cache"
+ ensure
+ ENV['HTTP_CACHE_CONTROL'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/content_length_spec.rb b/spec/ruby/library/cgi/queryextension/content_length_spec.rb
index de823f7119..bd02f3d8da 100644
--- a/spec/ruby/library/cgi/queryextension/content_length_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/content_length_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#content_length" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#content_length" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['CONTENT_LENGTH'] as Integer" do
- old_value = ENV['CONTENT_LENGTH']
- begin
- ENV['CONTENT_LENGTH'] = nil
- @cgi.content_length.should be_nil
+ it "returns ENV['CONTENT_LENGTH'] as Integer" do
+ old_value = ENV['CONTENT_LENGTH']
+ begin
+ ENV['CONTENT_LENGTH'] = nil
+ @cgi.content_length.should == nil
- ENV['CONTENT_LENGTH'] = "100"
- @cgi.content_length.should eql(100)
- ensure
- ENV['CONTENT_LENGTH'] = old_value
+ ENV['CONTENT_LENGTH'] = "100"
+ @cgi.content_length.should.eql?(100)
+ ensure
+ ENV['CONTENT_LENGTH'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/content_type_spec.rb b/spec/ruby/library/cgi/queryextension/content_type_spec.rb
index 49b8389c87..d3cbdf0b14 100644
--- a/spec/ruby/library/cgi/queryextension/content_type_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/content_type_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#content_type" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#content_type" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['CONTENT_TYPE']" do
- old_value, ENV['CONTENT_TYPE'] = ENV['CONTENT_TYPE'], "text/html"
- begin
- @cgi.content_type.should == "text/html"
- ensure
- ENV['CONTENT_TYPE'] = old_value
+ it "returns ENV['CONTENT_TYPE']" do
+ old_value, ENV['CONTENT_TYPE'] = ENV['CONTENT_TYPE'], "text/html"
+ begin
+ @cgi.content_type.should == "text/html"
+ ensure
+ ENV['CONTENT_TYPE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/cookies_spec.rb b/spec/ruby/library/cgi/queryextension/cookies_spec.rb
index 4befd61ab7..266fe0c721 100644
--- a/spec/ruby/library/cgi/queryextension/cookies_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/cookies_spec.rb
@@ -1,10 +1,13 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#cookies" do
- it "needs to be reviewed for spec completeness"
-end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+
+ describe "CGI::QueryExtension#cookies" do
+ it "needs to be reviewed for spec completeness"
+ end
-describe "CGI::QueryExtension#cookies=" do
- it "needs to be reviewed for spec completeness"
+ describe "CGI::QueryExtension#cookies=" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/cgi/queryextension/element_reference_spec.rb b/spec/ruby/library/cgi/queryextension/element_reference_spec.rb
index 6ac5b46407..c835f385f0 100644
--- a/spec/ruby/library/cgi/queryextension/element_reference_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/element_reference_spec.rb
@@ -1,27 +1,30 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#[]" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- ENV['QUERY_STRING'], @old_query_string = "one=a&two=b&two=c", ENV['QUERY_STRING']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- ENV['QUERY_STRING'] = @old_query_string
- end
+ describe "CGI::QueryExtension#[]" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ ENV['QUERY_STRING'], @old_query_string = "one=a&two=b&two=c", ENV['QUERY_STRING']
+ @cgi = CGI.new
+ end
- it "it returns the value for the parameter with the given key" do
- @cgi["one"].should == "a"
- end
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ ENV['QUERY_STRING'] = @old_query_string
+ end
- it "only returns the first value for parameters with multiple values" do
- @cgi["two"].should == "b"
- end
+ it "it returns the value for the parameter with the given key" do
+ @cgi["one"].should == "a"
+ end
+
+ it "only returns the first value for parameters with multiple values" do
+ @cgi["two"].should == "b"
+ end
- it "returns a String" do
- @cgi["one"].should be_kind_of(String)
+ it "returns a String" do
+ @cgi["one"].should.is_a?(String)
+ end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/from_spec.rb b/spec/ruby/library/cgi/queryextension/from_spec.rb
index 04a992cfc7..b341e0be10 100644
--- a/spec/ruby/library/cgi/queryextension/from_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/from_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#from" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#from" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_FROM']" do
- old_value, ENV['HTTP_FROM'] = ENV['HTTP_FROM'], "googlebot(at)googlebot.com"
- begin
- @cgi.from.should == "googlebot(at)googlebot.com"
- ensure
- ENV['HTTP_FROM'] = old_value
+ it "returns ENV['HTTP_FROM']" do
+ old_value, ENV['HTTP_FROM'] = ENV['HTTP_FROM'], "googlebot(at)googlebot.com"
+ begin
+ @cgi.from.should == "googlebot(at)googlebot.com"
+ ensure
+ ENV['HTTP_FROM'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb b/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb
index 3ead5bd8bf..c82522326b 100644
--- a/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/gateway_interface_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#gateway_interface" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#gateway_interface" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['GATEWAY_INTERFACE']" do
- old_value, ENV['GATEWAY_INTERFACE'] = ENV['GATEWAY_INTERFACE'], "CGI/1.1"
- begin
- @cgi.gateway_interface.should == "CGI/1.1"
- ensure
- ENV['GATEWAY_INTERFACE'] = old_value
+ it "returns ENV['GATEWAY_INTERFACE']" do
+ old_value, ENV['GATEWAY_INTERFACE'] = ENV['GATEWAY_INTERFACE'], "CGI/1.1"
+ begin
+ @cgi.gateway_interface.should == "CGI/1.1"
+ ensure
+ ENV['GATEWAY_INTERFACE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/has_key_spec.rb b/spec/ruby/library/cgi/queryextension/has_key_spec.rb
index 525b45b507..43f7aae1b2 100644
--- a/spec/ruby/library/cgi/queryextension/has_key_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/has_key_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'shared/has_key'
-describe "CGI::QueryExtension#has_key?" do
- it_behaves_like :cgi_query_extension_has_key_p, :has_key?
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'shared/has_key'
+
+ describe "CGI::QueryExtension#has_key?" do
+ it_behaves_like :cgi_query_extension_has_key_p, :has_key?
+ end
end
diff --git a/spec/ruby/library/cgi/queryextension/host_spec.rb b/spec/ruby/library/cgi/queryextension/host_spec.rb
index e820e0afc3..e1047c942b 100644
--- a/spec/ruby/library/cgi/queryextension/host_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/host_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#host" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#host" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_HOST']" do
- old_value, ENV['HTTP_HOST'] = ENV['HTTP_HOST'], "localhost"
- begin
- @cgi.host.should == "localhost"
- ensure
- ENV['HTTP_HOST'] = old_value
+ it "returns ENV['HTTP_HOST']" do
+ old_value, ENV['HTTP_HOST'] = ENV['HTTP_HOST'], "localhost"
+ begin
+ @cgi.host.should == "localhost"
+ ensure
+ ENV['HTTP_HOST'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/include_spec.rb b/spec/ruby/library/cgi/queryextension/include_spec.rb
index 12365ea284..7275c309f9 100644
--- a/spec/ruby/library/cgi/queryextension/include_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/include_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'shared/has_key'
-describe "CGI::QueryExtension#include?" do
- it_behaves_like :cgi_query_extension_has_key_p, :include?
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'shared/has_key'
+
+ describe "CGI::QueryExtension#include?" do
+ it_behaves_like :cgi_query_extension_has_key_p, :include?
+ end
end
diff --git a/spec/ruby/library/cgi/queryextension/key_spec.rb b/spec/ruby/library/cgi/queryextension/key_spec.rb
index d0f1e4cee2..dc2f52fbe0 100644
--- a/spec/ruby/library/cgi/queryextension/key_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/key_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require_relative 'shared/has_key'
-describe "CGI::QueryExtension#key?" do
- it_behaves_like :cgi_query_extension_has_key_p, :key?
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require_relative 'shared/has_key'
+
+ describe "CGI::QueryExtension#key?" do
+ it_behaves_like :cgi_query_extension_has_key_p, :key?
+ end
end
diff --git a/spec/ruby/library/cgi/queryextension/keys_spec.rb b/spec/ruby/library/cgi/queryextension/keys_spec.rb
index 14d77180fa..bb16914065 100644
--- a/spec/ruby/library/cgi/queryextension/keys_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/keys_spec.rb
@@ -1,20 +1,23 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#keys" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- ENV['QUERY_STRING'], @old_query_string = "one=a&two=b", ENV['QUERY_STRING']
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- @cgi = CGI.new
- end
+ describe "CGI::QueryExtension#keys" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ ENV['QUERY_STRING'], @old_query_string = "one=a&two=b", ENV['QUERY_STRING']
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- ENV['QUERY_STRING'] = @old_query_string
- end
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ ENV['QUERY_STRING'] = @old_query_string
+ end
- it "returns all parameter keys as an Array" do
- @cgi.keys.sort.should == ["one", "two"]
+ it "returns all parameter keys as an Array" do
+ @cgi.keys.sort.should == ["one", "two"]
+ end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/multipart_spec.rb b/spec/ruby/library/cgi/queryextension/multipart_spec.rb
index ced4cb05a1..1fa771ca1c 100644
--- a/spec/ruby/library/cgi/queryextension/multipart_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/multipart_spec.rb
@@ -1,20 +1,22 @@
require_relative '../../../spec_helper'
-require 'cgi'
-require "stringio"
-describe "CGI::QueryExtension#multipart?" do
- before :each do
- @old_stdin = $stdin
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+ require "stringio"
- @old_request_method = ENV['REQUEST_METHOD']
- @old_content_type = ENV['CONTENT_TYPE']
- @old_content_length = ENV['CONTENT_LENGTH']
+ describe "CGI::QueryExtension#multipart?" do
+ before :each do
+ @old_stdin = $stdin
- ENV['REQUEST_METHOD'] = "POST"
- ENV["CONTENT_TYPE"] = "multipart/form-data; boundary=---------------------------1137522503144128232716531729"
- ENV["CONTENT_LENGTH"] = "222"
+ @old_request_method = ENV['REQUEST_METHOD']
+ @old_content_type = ENV['CONTENT_TYPE']
+ @old_content_length = ENV['CONTENT_LENGTH']
- $stdin = StringIO.new <<-EOS
+ ENV['REQUEST_METHOD'] = "POST"
+ ENV["CONTENT_TYPE"] = "multipart/form-data; boundary=---------------------------1137522503144128232716531729"
+ ENV["CONTENT_LENGTH"] = "222"
+
+ $stdin = StringIO.new <<-EOS
-----------------------------1137522503144128232716531729\r
Content-Disposition: form-data; name="file"; filename=""\r
Content-Type: application/octet-stream\r
@@ -23,18 +25,19 @@ Content-Type: application/octet-stream\r
-----------------------------1137522503144128232716531729--\r
EOS
- @cgi = CGI.new
- end
+ @cgi = CGI.new
+ end
- after :each do
- $stdin = @old_stdin
+ after :each do
+ $stdin = @old_stdin
- ENV['REQUEST_METHOD'] = @old_request_method
- ENV['CONTENT_TYPE'] = @old_content_type
- ENV['CONTENT_LENGTH'] = @old_content_length
- end
+ ENV['REQUEST_METHOD'] = @old_request_method
+ ENV['CONTENT_TYPE'] = @old_content_type
+ ENV['CONTENT_LENGTH'] = @old_content_length
+ end
- it "returns true if the current Request is a multipart request" do
- @cgi.multipart?.should be_true
+ it "returns true if the current Request is a multipart request" do
+ @cgi.multipart?.should == true
+ end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/negotiate_spec.rb b/spec/ruby/library/cgi/queryextension/negotiate_spec.rb
index b6fe036042..4083e6a8cd 100644
--- a/spec/ruby/library/cgi/queryextension/negotiate_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/negotiate_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#negotiate" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#negotiate" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_NEGOTIATE']" do
- old_value, ENV['HTTP_NEGOTIATE'] = ENV['HTTP_NEGOTIATE'], "trans"
- begin
- @cgi.negotiate.should == "trans"
- ensure
- ENV['HTTP_NEGOTIATE'] = old_value
+ it "returns ENV['HTTP_NEGOTIATE']" do
+ old_value, ENV['HTTP_NEGOTIATE'] = ENV['HTTP_NEGOTIATE'], "trans"
+ begin
+ @cgi.negotiate.should == "trans"
+ ensure
+ ENV['HTTP_NEGOTIATE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/params_spec.rb b/spec/ruby/library/cgi/queryextension/params_spec.rb
index f4449e3c8a..938028ea14 100644
--- a/spec/ruby/library/cgi/queryextension/params_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/params_spec.rb
@@ -1,37 +1,40 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#params" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- ENV['QUERY_STRING'], @old_query_string = "one=a&two=b&two=c&three", ENV['QUERY_STRING']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['QUERY_STRING'] = @old_query_string
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#params" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ ENV['QUERY_STRING'], @old_query_string = "one=a&two=b&two=c&three", ENV['QUERY_STRING']
+ @cgi = CGI.new
+ end
- it "returns the parsed HTTP Query Params" do
- @cgi.params.should == {"three"=>[], "two"=>["b", "c"], "one"=>["a"]}
- end
-end
+ after :each do
+ ENV['QUERY_STRING'] = @old_query_string
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
-describe "CGI::QueryExtension#params=" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
+ it "returns the parsed HTTP Query Params" do
+ @cgi.params.should == {"three"=>[], "two"=>["b", "c"], "one"=>["a"]}
+ end
end
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#params=" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "sets the HTTP Query Params to the passed argument" do
- @cgi.params.should == {}
+ it "sets the HTTP Query Params to the passed argument" do
+ @cgi.params.should == {}
- @cgi.params = {"one"=>["a"], "two"=>["b", "c"]}
- @cgi.params.should == {"one"=>["a"], "two"=>["b", "c"]}
+ @cgi.params = {"one"=>["a"], "two"=>["b", "c"]}
+ @cgi.params.should == {"one"=>["a"], "two"=>["b", "c"]}
+ end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/path_info_spec.rb b/spec/ruby/library/cgi/queryextension/path_info_spec.rb
index 9785df85f1..9b7834c514 100644
--- a/spec/ruby/library/cgi/queryextension/path_info_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/path_info_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#path_info" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#path_info" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['PATH_INFO']" do
- old_value, ENV['PATH_INFO'] = ENV['PATH_INFO'], "/test/path"
- begin
- @cgi.path_info.should == "/test/path"
- ensure
- ENV['PATH_INFO'] = old_value
+ it "returns ENV['PATH_INFO']" do
+ old_value, ENV['PATH_INFO'] = ENV['PATH_INFO'], "/test/path"
+ begin
+ @cgi.path_info.should == "/test/path"
+ ensure
+ ENV['PATH_INFO'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/path_translated_spec.rb b/spec/ruby/library/cgi/queryextension/path_translated_spec.rb
index 417a749341..a773aaafdb 100644
--- a/spec/ruby/library/cgi/queryextension/path_translated_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/path_translated_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#path_translated" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#path_translated" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['PATH_TRANSLATED']" do
- old_value, ENV['PATH_TRANSLATED'] = ENV['PATH_TRANSLATED'], "/full/path/to/dir"
- begin
- @cgi.path_translated.should == "/full/path/to/dir"
- ensure
- ENV['PATH_TRANSLATED'] = old_value
+ it "returns ENV['PATH_TRANSLATED']" do
+ old_value, ENV['PATH_TRANSLATED'] = ENV['PATH_TRANSLATED'], "/full/path/to/dir"
+ begin
+ @cgi.path_translated.should == "/full/path/to/dir"
+ ensure
+ ENV['PATH_TRANSLATED'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/pragma_spec.rb b/spec/ruby/library/cgi/queryextension/pragma_spec.rb
index 02d5c91221..be384182a5 100644
--- a/spec/ruby/library/cgi/queryextension/pragma_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/pragma_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#pragma" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#pragma" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_PRAGMA']" do
- old_value, ENV['HTTP_PRAGMA'] = ENV['HTTP_PRAGMA'], "no-cache"
- begin
- @cgi.pragma.should == "no-cache"
- ensure
- ENV['HTTP_PRAGMA'] = old_value
+ it "returns ENV['HTTP_PRAGMA']" do
+ old_value, ENV['HTTP_PRAGMA'] = ENV['HTTP_PRAGMA'], "no-cache"
+ begin
+ @cgi.pragma.should == "no-cache"
+ ensure
+ ENV['HTTP_PRAGMA'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/query_string_spec.rb b/spec/ruby/library/cgi/queryextension/query_string_spec.rb
index a6b454a7eb..64fbeaea10 100644
--- a/spec/ruby/library/cgi/queryextension/query_string_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/query_string_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#query_string" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#query_string" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['QUERY_STRING']" do
- old_value, ENV['QUERY_STRING'] = ENV['QUERY_STRING'], "one=a&two=b"
- begin
- @cgi.query_string.should == "one=a&two=b"
- ensure
- ENV['QUERY_STRING'] = old_value
+ it "returns ENV['QUERY_STRING']" do
+ old_value, ENV['QUERY_STRING'] = ENV['QUERY_STRING'], "one=a&two=b"
+ begin
+ @cgi.query_string.should == "one=a&two=b"
+ ensure
+ ENV['QUERY_STRING'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb b/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb
index 3d7072e346..30d314aca1 100644
--- a/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/raw_cookie2_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#raw_cookie2" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#raw_cookie2" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_COOKIE2']" do
- old_value, ENV['HTTP_COOKIE2'] = ENV['HTTP_COOKIE2'], "some_cookie=data"
- begin
- @cgi.raw_cookie2.should == "some_cookie=data"
- ensure
- ENV['HTTP_COOKIE2'] = old_value
+ it "returns ENV['HTTP_COOKIE2']" do
+ old_value, ENV['HTTP_COOKIE2'] = ENV['HTTP_COOKIE2'], "some_cookie=data"
+ begin
+ @cgi.raw_cookie2.should == "some_cookie=data"
+ ensure
+ ENV['HTTP_COOKIE2'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb b/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb
index ede7b9ff87..affa504b39 100644
--- a/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/raw_cookie_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#raw_cookie" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#raw_cookie" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_COOKIE']" do
- old_value, ENV['HTTP_COOKIE'] = ENV['HTTP_COOKIE'], "some_cookie=data"
- begin
- @cgi.raw_cookie.should == "some_cookie=data"
- ensure
- ENV['HTTP_COOKIE'] = old_value
+ it "returns ENV['HTTP_COOKIE']" do
+ old_value, ENV['HTTP_COOKIE'] = ENV['HTTP_COOKIE'], "some_cookie=data"
+ begin
+ @cgi.raw_cookie.should == "some_cookie=data"
+ ensure
+ ENV['HTTP_COOKIE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/referer_spec.rb b/spec/ruby/library/cgi/queryextension/referer_spec.rb
index 6cd5dc96f8..53fc19ddd0 100644
--- a/spec/ruby/library/cgi/queryextension/referer_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/referer_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#referer" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#referer" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_REFERER']" do
- old_value, ENV['HTTP_REFERER'] = ENV['HTTP_REFERER'], "example.com"
- begin
- @cgi.referer.should == "example.com"
- ensure
- ENV['HTTP_REFERER'] = old_value
+ it "returns ENV['HTTP_REFERER']" do
+ old_value, ENV['HTTP_REFERER'] = ENV['HTTP_REFERER'], "example.com"
+ begin
+ @cgi.referer.should == "example.com"
+ ensure
+ ENV['HTTP_REFERER'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb b/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb
index 0259402b23..7b5addc2d5 100644
--- a/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_addr_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#remote_addr" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#remote_addr" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['REMOTE_ADDR']" do
- old_value, ENV['REMOTE_ADDR'] = ENV['REMOTE_ADDR'], "127.0.0.1"
- begin
- @cgi.remote_addr.should == "127.0.0.1"
- ensure
- ENV['REMOTE_ADDR'] = old_value
+ it "returns ENV['REMOTE_ADDR']" do
+ old_value, ENV['REMOTE_ADDR'] = ENV['REMOTE_ADDR'], "127.0.0.1"
+ begin
+ @cgi.remote_addr.should == "127.0.0.1"
+ ensure
+ ENV['REMOTE_ADDR'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/remote_host_spec.rb b/spec/ruby/library/cgi/queryextension/remote_host_spec.rb
index cf77e0031b..2dfe59ca38 100644
--- a/spec/ruby/library/cgi/queryextension/remote_host_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_host_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#remote_host" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#remote_host" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['REMOTE_HOST']" do
- old_value, ENV['REMOTE_HOST'] = ENV['REMOTE_HOST'], "test.host"
- begin
- @cgi.remote_host.should == "test.host"
- ensure
- ENV['REMOTE_HOST'] = old_value
+ it "returns ENV['REMOTE_HOST']" do
+ old_value, ENV['REMOTE_HOST'] = ENV['REMOTE_HOST'], "test.host"
+ begin
+ @cgi.remote_host.should == "test.host"
+ ensure
+ ENV['REMOTE_HOST'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb b/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb
index 5b51d6b8ee..bb05fc7942 100644
--- a/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_ident_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#remote_ident" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#remote_ident" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['REMOTE_IDENT']" do
- old_value, ENV['REMOTE_IDENT'] = ENV['REMOTE_IDENT'], "no-idea-what-this-is-for"
- begin
- @cgi.remote_ident.should == "no-idea-what-this-is-for"
- ensure
- ENV['REMOTE_IDENT'] = old_value
+ it "returns ENV['REMOTE_IDENT']" do
+ old_value, ENV['REMOTE_IDENT'] = ENV['REMOTE_IDENT'], "no-idea-what-this-is-for"
+ begin
+ @cgi.remote_ident.should == "no-idea-what-this-is-for"
+ ensure
+ ENV['REMOTE_IDENT'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/remote_user_spec.rb b/spec/ruby/library/cgi/queryextension/remote_user_spec.rb
index 1a93bb6561..29856302ab 100644
--- a/spec/ruby/library/cgi/queryextension/remote_user_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/remote_user_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#remote_user" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#remote_user" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['REMOTE_USER']" do
- old_value, ENV['REMOTE_USER'] = ENV['REMOTE_USER'], "username"
- begin
- @cgi.remote_user.should == "username"
- ensure
- ENV['REMOTE_USER'] = old_value
+ it "returns ENV['REMOTE_USER']" do
+ old_value, ENV['REMOTE_USER'] = ENV['REMOTE_USER'], "username"
+ begin
+ @cgi.remote_user.should == "username"
+ ensure
+ ENV['REMOTE_USER'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/request_method_spec.rb b/spec/ruby/library/cgi/queryextension/request_method_spec.rb
index eabdd6998b..7331b134d2 100644
--- a/spec/ruby/library/cgi/queryextension/request_method_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/request_method_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#request_method" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#request_method" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['REQUEST_METHOD']" do
- old_value, ENV['REQUEST_METHOD'] = ENV['REQUEST_METHOD'], "GET"
- begin
- @cgi.request_method.should == "GET"
- ensure
- ENV['REQUEST_METHOD'] = old_value
+ it "returns ENV['REQUEST_METHOD']" do
+ old_value, ENV['REQUEST_METHOD'] = ENV['REQUEST_METHOD'], "GET"
+ begin
+ @cgi.request_method.should == "GET"
+ ensure
+ ENV['REQUEST_METHOD'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/script_name_spec.rb b/spec/ruby/library/cgi/queryextension/script_name_spec.rb
index 341b7b6fea..4b359a545f 100644
--- a/spec/ruby/library/cgi/queryextension/script_name_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/script_name_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#script_name" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#script_name" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['SCRIPT_NAME']" do
- old_value, ENV['SCRIPT_NAME'] = ENV['SCRIPT_NAME'], "/path/to/script.rb"
- begin
- @cgi.script_name.should == "/path/to/script.rb"
- ensure
- ENV['SCRIPT_NAME'] = old_value
+ it "returns ENV['SCRIPT_NAME']" do
+ old_value, ENV['SCRIPT_NAME'] = ENV['SCRIPT_NAME'], "/path/to/script.rb"
+ begin
+ @cgi.script_name.should == "/path/to/script.rb"
+ ensure
+ ENV['SCRIPT_NAME'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/server_name_spec.rb b/spec/ruby/library/cgi/queryextension/server_name_spec.rb
index b12aaf8c5c..c1f7fb4c54 100644
--- a/spec/ruby/library/cgi/queryextension/server_name_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_name_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#server_name" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#server_name" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['SERVER_NAME']" do
- old_value, ENV['SERVER_NAME'] = ENV['SERVER_NAME'], "localhost"
- begin
- @cgi.server_name.should == "localhost"
- ensure
- ENV['SERVER_NAME'] = old_value
+ it "returns ENV['SERVER_NAME']" do
+ old_value, ENV['SERVER_NAME'] = ENV['SERVER_NAME'], "localhost"
+ begin
+ @cgi.server_name.should == "localhost"
+ ensure
+ ENV['SERVER_NAME'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/server_port_spec.rb b/spec/ruby/library/cgi/queryextension/server_port_spec.rb
index 0e688a99bf..1c88d3225d 100644
--- a/spec/ruby/library/cgi/queryextension/server_port_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_port_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#server_port" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#server_port" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['SERVER_PORT'] as Integer" do
- old_value = ENV['SERVER_PORT']
- begin
- ENV['SERVER_PORT'] = nil
- @cgi.server_port.should be_nil
+ it "returns ENV['SERVER_PORT'] as Integer" do
+ old_value = ENV['SERVER_PORT']
+ begin
+ ENV['SERVER_PORT'] = nil
+ @cgi.server_port.should == nil
- ENV['SERVER_PORT'] = "3000"
- @cgi.server_port.should eql(3000)
- ensure
- ENV['SERVER_PORT'] = old_value
+ ENV['SERVER_PORT'] = "3000"
+ @cgi.server_port.should.eql?(3000)
+ ensure
+ ENV['SERVER_PORT'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb b/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb
index f9dcf3c5b8..fdbcc2108f 100644
--- a/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_protocol_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#server_protocol" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#server_protocol" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['SERVER_PROTOCOL']" do
- old_value, ENV['SERVER_PROTOCOL'] = ENV['SERVER_PROTOCOL'], "HTTP/1.1"
- begin
- @cgi.server_protocol.should == "HTTP/1.1"
- ensure
- ENV['SERVER_PROTOCOL'] = old_value
+ it "returns ENV['SERVER_PROTOCOL']" do
+ old_value, ENV['SERVER_PROTOCOL'] = ENV['SERVER_PROTOCOL'], "HTTP/1.1"
+ begin
+ @cgi.server_protocol.should == "HTTP/1.1"
+ ensure
+ ENV['SERVER_PROTOCOL'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/server_software_spec.rb b/spec/ruby/library/cgi/queryextension/server_software_spec.rb
index df349cdf2e..c5811a2268 100644
--- a/spec/ruby/library/cgi/queryextension/server_software_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/server_software_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#server_software" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#server_software" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['SERVER_SOFTWARE']" do
- old_value, ENV['SERVER_SOFTWARE'] = ENV['SERVER_SOFTWARE'], "Server/1.0.0"
- begin
- @cgi.server_software.should == "Server/1.0.0"
- ensure
- ENV['SERVER_SOFTWARE'] = old_value
+ it "returns ENV['SERVER_SOFTWARE']" do
+ old_value, ENV['SERVER_SOFTWARE'] = ENV['SERVER_SOFTWARE'], "Server/1.0.0"
+ begin
+ @cgi.server_software.should == "Server/1.0.0"
+ ensure
+ ENV['SERVER_SOFTWARE'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/queryextension/shared/has_key.rb b/spec/ruby/library/cgi/queryextension/shared/has_key.rb
index cfac5865fa..6231cb548e 100644
--- a/spec/ruby/library/cgi/queryextension/shared/has_key.rb
+++ b/spec/ruby/library/cgi/queryextension/shared/has_key.rb
@@ -12,8 +12,8 @@ describe :cgi_query_extension_has_key_p, shared: true do
end
it "returns true when the passed key exists in the HTTP Query" do
- @cgi.send(@method, "one").should be_true
- @cgi.send(@method, "two").should be_true
- @cgi.send(@method, "three").should be_false
+ @cgi.send(@method, "one").should == true
+ @cgi.send(@method, "two").should == true
+ @cgi.send(@method, "three").should == false
end
end
diff --git a/spec/ruby/library/cgi/queryextension/user_agent_spec.rb b/spec/ruby/library/cgi/queryextension/user_agent_spec.rb
index ec5ef187dd..3240352ef6 100644
--- a/spec/ruby/library/cgi/queryextension/user_agent_spec.rb
+++ b/spec/ruby/library/cgi/queryextension/user_agent_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'cgi'
-describe "CGI::QueryExtension#user_agent" do
- before :each do
- ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
- @cgi = CGI.new
- end
+ruby_version_is ""..."4.0" do
+ require 'cgi'
- after :each do
- ENV['REQUEST_METHOD'] = @old_request_method
- end
+ describe "CGI::QueryExtension#user_agent" do
+ before :each do
+ ENV['REQUEST_METHOD'], @old_request_method = "GET", ENV['REQUEST_METHOD']
+ @cgi = CGI.new
+ end
+
+ after :each do
+ ENV['REQUEST_METHOD'] = @old_request_method
+ end
- it "returns ENV['HTTP_USER_AGENT']" do
- old_value, ENV['HTTP_USER_AGENT'] = ENV['HTTP_USER_AGENT'], "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; de-de) AppleWebKit/527+ (KHTML, like Gecko) Version/3.1 Safari/525.13"
- begin
- @cgi.user_agent.should == "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; de-de) AppleWebKit/527+ (KHTML, like Gecko) Version/3.1 Safari/525.13"
- ensure
- ENV['HTTP_USER_AGENT'] = old_value
+ it "returns ENV['HTTP_USER_AGENT']" do
+ old_value, ENV['HTTP_USER_AGENT'] = ENV['HTTP_USER_AGENT'], "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; de-de) AppleWebKit/527+ (KHTML, like Gecko) Version/3.1 Safari/525.13"
+ begin
+ @cgi.user_agent.should == "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; de-de) AppleWebKit/527+ (KHTML, like Gecko) Version/3.1 Safari/525.13"
+ ensure
+ ENV['HTTP_USER_AGENT'] = old_value
+ end
end
end
end
diff --git a/spec/ruby/library/cgi/rfc1123_date_spec.rb b/spec/ruby/library/cgi/rfc1123_date_spec.rb
index 6904eeabaa..636185f22c 100644
--- a/spec/ruby/library/cgi/rfc1123_date_spec.rb
+++ b/spec/ruby/library/cgi/rfc1123_date_spec.rb
@@ -1,10 +1,13 @@
require_relative '../../spec_helper'
-require 'cgi'
-describe "CGI.rfc1123_date when passed Time" do
- it "returns the passed Time formatted in RFC1123 ('Sat, 01 Dec 2007 15:56:42 GMT')" do
- input = Time.at(1196524602)
- expected = 'Sat, 01 Dec 2007 15:56:42 GMT'
- CGI.rfc1123_date(input).should == expected
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+
+ describe "CGI.rfc1123_date when passed Time" do
+ it "returns the passed Time formatted in RFC1123 ('Sat, 01 Dec 2007 15:56:42 GMT')" do
+ input = Time.at(1196524602)
+ expected = 'Sat, 01 Dec 2007 15:56:42 GMT'
+ CGI.rfc1123_date(input).should == expected
+ end
end
end
diff --git a/spec/ruby/library/cgi/shared/http_header.rb b/spec/ruby/library/cgi/shared/http_header.rb
index b225b5925e..e739fed538 100644
--- a/spec/ruby/library/cgi/shared/http_header.rb
+++ b/spec/ruby/library/cgi/shared/http_header.rb
@@ -63,11 +63,11 @@ describe :cgi_http_header, shared: true do
header.should == "Content-Type: text/plain; charset=UTF-8\r\n\r\n"
header = @cgi.send(@method, "nph" => true)
- header.should include("HTTP/1.0 200 OK\r\n")
- header.should include("Date: ")
- header.should include("Server: ")
- header.should include("Connection: close\r\n")
- header.should include("Content-Type: text/html\r\n")
+ header.should.include?("HTTP/1.0 200 OK\r\n")
+ header.should.include?("Date: ")
+ header.should.include?("Server: ")
+ header.should.include?("Connection: close\r\n")
+ header.should.include?("Content-Type: text/html\r\n")
header = @cgi.send(@method, "status" => "OK")
header.should == "Status: 200 OK\r\nContent-Type: text/html\r\n\r\n"
diff --git a/spec/ruby/library/cgi/unescapeElement_spec.rb b/spec/ruby/library/cgi/unescapeElement_spec.rb
index ae4d50b076..db83f0d2fb 100644
--- a/spec/ruby/library/cgi/unescapeElement_spec.rb
+++ b/spec/ruby/library/cgi/unescapeElement_spec.rb
@@ -1,5 +1,11 @@
require_relative '../../spec_helper'
-require 'cgi'
+
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+end
+ruby_version_is "4.0" do
+ require 'cgi/escape'
+end
describe "CGI.unescapeElement when passed String, elements, ..." do
it "unescapes only the tags of the passed elements in the passed String" do
diff --git a/spec/ruby/library/cgi/unescapeHTML_spec.rb b/spec/ruby/library/cgi/unescapeHTML_spec.rb
index 84b30c6aa6..e43dcc83e5 100644
--- a/spec/ruby/library/cgi/unescapeHTML_spec.rb
+++ b/spec/ruby/library/cgi/unescapeHTML_spec.rb
@@ -1,5 +1,9 @@
require_relative '../../spec_helper'
-require 'cgi'
+begin
+ require 'cgi/escape'
+rescue LoadError
+ require 'cgi'
+end
describe "CGI.unescapeHTML" do
it "unescapes '&amp; &lt; &gt; &quot;' to '& < > \"'" do
diff --git a/spec/ruby/library/cgi/unescapeURIComponent_spec.rb b/spec/ruby/library/cgi/unescapeURIComponent_spec.rb
new file mode 100644
index 0000000000..e0bf4b70e0
--- /dev/null
+++ b/spec/ruby/library/cgi/unescapeURIComponent_spec.rb
@@ -0,0 +1,128 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+end
+ruby_version_is "4.0" do
+ require 'cgi/escape'
+end
+
+describe "CGI.unescapeURIComponent" do
+ it "decodes any percent-encoded octets to their corresponding bytes according to RFC 3986" do
+ string = (0x00..0xff).map { |i| "%%%02x" % i }.join
+ expected = (0x00..0xff).map { |i| i.chr }.join.force_encoding(Encoding::UTF_8)
+ CGI.unescapeURIComponent(string).should == expected
+ end
+
+ it "disregards case of characters in a percent-encoding triplet" do
+ CGI.unescapeURIComponent("%CE%B2abc").should == "βabc"
+ CGI.unescapeURIComponent("%ce%b2ABC").should == "βABC"
+ end
+
+ it "leaves any non-percent-encoded characters as-is" do
+ string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ:/?#[]@!$&'()*+,;=\t\x0D\xFFβᛉ▒90%"
+ decoded = CGI.unescapeURIComponent(string)
+ decoded.should == string
+ string.should_not.equal?(decoded)
+ end
+
+ it "leaves sequences which can't be a percent-encoded octet as-is" do
+ string = "%AZ%B"
+ decoded = CGI.unescapeURIComponent(string)
+ decoded.should == string
+ string.should_not.equal?(decoded)
+ end
+
+ it "creates a String with the specified target Encoding" do
+ string = CGI.unescapeURIComponent("%D2%3C%3CABC", Encoding::ISO_8859_1)
+ string.encoding.should == Encoding::ISO_8859_1
+ string.should == "Ò<<ABC".encode("ISO-8859-1")
+ end
+
+ it "accepts a string name of an Encoding" do
+ CGI.unescapeURIComponent("%D2%3C%3CABC", "ISO-8859-1").should == "Ò<<ABC".encode("ISO-8859-1")
+ end
+
+ it "raises ArgumentError if specified encoding is unknown" do
+ -> { CGI.unescapeURIComponent("ABC", "ISO-JOKE-1") }.should.raise(ArgumentError, "unknown encoding name - ISO-JOKE-1")
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "uses CGI.accept_charset as the default target encoding" do
+ original_charset = CGI.accept_charset
+ CGI.accept_charset = "ISO-8859-1"
+ decoded = CGI.unescapeURIComponent("%D2%3C%3CABC")
+ decoded.should == "Ò<<ABC".encode("ISO-8859-1")
+ decoded.encoding.should == Encoding::ISO_8859_1
+ ensure
+ CGI.accept_charset = original_charset
+ end
+
+ it "has CGI.accept_charset as UTF-8 by default" do
+ decoded = CGI.unescapeURIComponent("%CE%B2ABC")
+ decoded.should == "βABC"
+ decoded.encoding.should == Encoding::UTF_8
+ end
+ end
+
+ ruby_version_is "4.0" do
+ # "cgi/escape" does not have methods to access @@accept_charset.
+ # Full "cgi" gem provides them, allowing to possibly change it.
+ it "uses CGI's @@accept_charset as the default target encoding" do
+ original_charset = CGI.class_variable_get(:@@accept_charset)
+ CGI.class_variable_set(:@@accept_charset, "ISO-8859-1")
+ decoded = CGI.unescapeURIComponent("%D2%3C%3CABC")
+ decoded.should == "Ò<<ABC".encode("ISO-8859-1")
+ decoded.encoding.should == Encoding::ISO_8859_1
+ ensure
+ CGI.class_variable_set(:@@accept_charset, original_charset)
+ end
+
+ it "has CGI's @@accept_charset as UTF-8 by default" do
+ decoded = CGI.unescapeURIComponent("%CE%B2ABC")
+ decoded.should == "βABC"
+ decoded.encoding.should == Encoding::UTF_8
+ end
+ end
+
+ context "when source string specifies octets invalid in target encoding" do
+ it "uses source string's encoding" do
+ string = "%A2%A6%A3".encode(Encoding::SHIFT_JIS)
+ decoded = CGI.unescapeURIComponent(string, Encoding::US_ASCII)
+ decoded.encoding.should == Encoding::SHIFT_JIS
+ decoded.should == "「ヲ」".encode(Encoding::SHIFT_JIS)
+ decoded.valid_encoding?.should == true
+ end
+
+ it "uses source string's encoding even if it's also invalid" do
+ string = "%FF".encode(Encoding::US_ASCII)
+ decoded = CGI.unescapeURIComponent(string, Encoding::SHIFT_JIS)
+ decoded.encoding.should == Encoding::US_ASCII
+ decoded.should == "\xFF".dup.force_encoding(Encoding::US_ASCII)
+ decoded.valid_encoding?.should == false
+ end
+ end
+
+ it "decodes an empty string as an empty string with target encoding" do
+ string = "".encode(Encoding::BINARY)
+ decoded = CGI.unescapeURIComponent(string, "UTF-8")
+ decoded.should == ""
+ decoded.encoding.should == Encoding::UTF_8
+ string.should_not.equal?(decoded)
+ end
+
+ it "raises a TypeError with nil" do
+ -> {
+ CGI.unescapeURIComponent(nil)
+ }.should.raise(TypeError, "no implicit conversion of nil into String")
+ end
+
+ it "uses implicit type conversion to String" do
+ object = Object.new
+ def object.to_str
+ "a%20b"
+ end
+
+ CGI.unescapeURIComponent(object).should == "a b"
+ end
+end
diff --git a/spec/ruby/library/cgi/unescape_spec.rb b/spec/ruby/library/cgi/unescape_spec.rb
index c593e24b4a..aa731b9367 100644
--- a/spec/ruby/library/cgi/unescape_spec.rb
+++ b/spec/ruby/library/cgi/unescape_spec.rb
@@ -1,6 +1,12 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-require 'cgi'
+
+ruby_version_is ""..."4.0" do
+ require 'cgi'
+end
+ruby_version_is "4.0" do
+ require 'cgi/escape'
+end
describe "CGI.unescape" do
it "url-decodes the passed argument" do
diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb
index bc999a5369..2e7d598bb8 100644
--- a/spec/ruby/library/coverage/result_spec.rb
+++ b/spec/ruby/library/coverage/result_spec.rb
@@ -34,39 +34,37 @@ describe 'Coverage.result' do
}
end
- ruby_version_is "3.2" do
- it 'returns results for each mode separately when enabled :all modes' do
- Coverage.start(:all)
- require @class_file.chomp('.rb')
- result = Coverage.result
-
- result.should == {
- @class_file => {
+ it 'returns results for each mode separately when enabled :all modes' do
+ Coverage.start(:all)
+ require @class_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @class_file => {
+ lines: [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ],
+ branches: {},
+ methods: {
+ [SomeClass, :some_method, 6, 2, 11, 5] => 0
+ }
+ }
+ }
+ end
+
+ it 'returns results for each mode separately when enabled any mode explicitly' do
+ Coverage.start(lines: true)
+ require @class_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @class_file =>
+ {
lines: [
nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ],
- branches: {},
- methods: {
- [SomeClass, :some_method, 6, 2, 11, 5] => 0
- }
+ ]
}
- }
- end
-
- it 'returns results for each mode separately when enabled any mode explicitly' do
- Coverage.start(lines: true)
- require @class_file.chomp('.rb')
- result = Coverage.result
-
- result.should == {
- @class_file =>
- {
- lines: [
- nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
- }
- end
+ }
end
it 'no requires/loads should give empty hash' do
@@ -82,7 +80,7 @@ describe 'Coverage.result' do
Coverage.result
-> {
Coverage.result
- }.should raise_error(RuntimeError, 'coverage measurement is not enabled')
+ }.should.raise(RuntimeError, 'coverage measurement is not enabled')
end
it 'second run should give same result' do
@@ -110,51 +108,35 @@ describe 'Coverage.result' do
it 'does not include the file starting coverage since it is not tracked' do
require @config_file.chomp('.rb')
- Coverage.result.should_not include(@config_file)
+ Coverage.result.should_not.include?(@config_file)
end
- ruby_version_is '3.1'...'3.2' do
- it 'returns the correct results when eval is used' do
- Coverage.start
- require @eval_code_file.chomp('.rb')
- result = Coverage.result
-
- result.should == {
- @eval_code_file => [
- 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
- ]
- }
- end
- end
+ it 'returns the correct results when eval coverage is enabled' do
+ Coverage.supported?(:eval).should == true
- ruby_version_is '3.2' do
- it 'returns the correct results when eval coverage is enabled' do
- Coverage.supported?(:eval).should == true
-
- Coverage.start(lines: true, eval: true)
- require @eval_code_file.chomp('.rb')
- result = Coverage.result
+ Coverage.start(lines: true, eval: true)
+ require @eval_code_file.chomp('.rb')
+ result = Coverage.result
- result.should == {
- @eval_code_file => {
- lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
- }
+ result.should == {
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
}
- end
+ }
+ end
- it 'returns the correct results when eval coverage is disabled' do
- Coverage.supported?(:eval).should == true
+ it 'returns the correct results when eval coverage is disabled' do
+ Coverage.supported?(:eval).should == true
- Coverage.start(lines: true, eval: false)
- require @eval_code_file.chomp('.rb')
- result = Coverage.result
+ Coverage.start(lines: true, eval: false)
+ require @eval_code_file.chomp('.rb')
+ result = Coverage.result
- result.should == {
- @eval_code_file => {
- lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
- }
+ result.should == {
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
}
- end
+ }
end
it "disables coverage measurement when stop option is not specified" do
diff --git a/spec/ruby/library/coverage/start_spec.rb b/spec/ruby/library/coverage/start_spec.rb
index 757837a462..11777347a2 100644
--- a/spec/ruby/library/coverage/start_spec.rb
+++ b/spec/ruby/library/coverage/start_spec.rb
@@ -24,66 +24,64 @@ describe 'Coverage.start' do
-> {
Coverage.start
- }.should raise_error(RuntimeError, 'coverage measurement is already setup')
- end
-
- ruby_version_is '3.2' do
- it "accepts :all optional argument" do
- Coverage.start(:all)
- Coverage.should.running?
- end
-
- it "accepts lines: optional keyword argument" do
- Coverage.start(lines: true)
- Coverage.should.running?
- end
-
- it "accepts branches: optional keyword argument" do
- Coverage.start(branches: true)
- Coverage.should.running?
- end
-
- it "accepts methods: optional keyword argument" do
- Coverage.start(methods: true)
- Coverage.should.running?
- end
-
- it "accepts eval: optional keyword argument" do
- Coverage.start(eval: true)
- Coverage.should.running?
- end
-
- it "accepts oneshot_lines: optional keyword argument" do
- Coverage.start(oneshot_lines: true)
- Coverage.should.running?
- end
-
- it "ignores unknown keyword arguments" do
- Coverage.start(foo: true)
- Coverage.should.running?
- end
-
- it "expects a Hash if not passed :all" do
- -> {
- Coverage.start(42)
- }.should raise_error(TypeError, "no implicit conversion of Integer into Hash")
- end
-
- it "does not accept both lines: and oneshot_lines: keyword arguments" do
- -> {
- Coverage.start(lines: true, oneshot_lines: true)
- }.should raise_error(RuntimeError, "cannot enable lines and oneshot_lines simultaneously")
- end
-
- it "enables the coverage measurement if passed options with `false` value" do
- Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false)
- Coverage.should.running?
- end
-
- it "measures coverage within eval" do
- Coverage.start(lines: true, eval: true)
- eval("Object.new\n"*3, binding, "test.rb", 1)
- Coverage.result["test.rb"].should == {lines: [1, 1, 1]}
- end
+ }.should.raise(RuntimeError, 'coverage measurement is already setup')
+ end
+
+ it "accepts :all optional argument" do
+ Coverage.start(:all)
+ Coverage.should.running?
+ end
+
+ it "accepts lines: optional keyword argument" do
+ Coverage.start(lines: true)
+ Coverage.should.running?
+ end
+
+ it "accepts branches: optional keyword argument" do
+ Coverage.start(branches: true)
+ Coverage.should.running?
+ end
+
+ it "accepts methods: optional keyword argument" do
+ Coverage.start(methods: true)
+ Coverage.should.running?
+ end
+
+ it "accepts eval: optional keyword argument" do
+ Coverage.start(eval: true)
+ Coverage.should.running?
+ end
+
+ it "accepts oneshot_lines: optional keyword argument" do
+ Coverage.start(oneshot_lines: true)
+ Coverage.should.running?
+ end
+
+ it "ignores unknown keyword arguments" do
+ Coverage.start(foo: true)
+ Coverage.should.running?
+ end
+
+ it "expects a Hash if not passed :all" do
+ -> {
+ Coverage.start(42)
+ }.should.raise(TypeError, "no implicit conversion of Integer into Hash")
+ end
+
+ it "does not accept both lines: and oneshot_lines: keyword arguments" do
+ -> {
+ Coverage.start(lines: true, oneshot_lines: true)
+ }.should.raise(RuntimeError, "cannot enable lines and oneshot_lines simultaneously")
+ end
+
+ it "enables the coverage measurement if passed options with `false` value" do
+ Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false)
+ Coverage.should.running?
+ end
+
+ it "measures coverage within eval" do
+ Coverage.start(lines: true, eval: true)
+ eval("Object.new\n"*3, binding, "test.rb", 1)
+ Coverage.result["test.rb"].should == {lines: [1, 1, 1]}
end
end
diff --git a/spec/ruby/library/coverage/supported_spec.rb b/spec/ruby/library/coverage/supported_spec.rb
index 78b3784ee0..fcf8a76d79 100644
--- a/spec/ruby/library/coverage/supported_spec.rb
+++ b/spec/ruby/library/coverage/supported_spec.rb
@@ -2,31 +2,29 @@ require_relative '../../spec_helper'
require 'coverage'
describe "Coverage.supported?" do
- ruby_version_is "3.2" do
- it "returns true or false if coverage measurement is supported for the given mode" do
- [true, false].should.include?(Coverage.supported?(:lines))
- [true, false].should.include?(Coverage.supported?(:branches))
- [true, false].should.include?(Coverage.supported?(:methods))
- [true, false].should.include?(Coverage.supported?(:eval))
- end
+ it "returns true or false if coverage measurement is supported for the given mode" do
+ [true, false].should.include?(Coverage.supported?(:lines))
+ [true, false].should.include?(Coverage.supported?(:branches))
+ [true, false].should.include?(Coverage.supported?(:methods))
+ [true, false].should.include?(Coverage.supported?(:eval))
+ end
- it "returns false for not existing modes" do
- Coverage.supported?(:foo).should == false
- Coverage.supported?(:bar).should == false
- end
+ it "returns false for not existing modes" do
+ Coverage.supported?(:foo).should == false
+ Coverage.supported?(:bar).should == false
+ end
- it "raise TypeError if argument is not Symbol" do
- -> {
- Coverage.supported?("lines")
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+ it "raise TypeError if argument is not Symbol" do
+ -> {
+ Coverage.supported?("lines")
+ }.should.raise(TypeError, "wrong argument type String (expected Symbol)")
- -> {
- Coverage.supported?([])
- }.should raise_error(TypeError, "wrong argument type Array (expected Symbol)")
+ -> {
+ Coverage.supported?([])
+ }.should.raise(TypeError, "wrong argument type Array (expected Symbol)")
- -> {
- Coverage.supported?(1)
- }.should raise_error(TypeError, "wrong argument type Integer (expected Symbol)")
- end
+ -> {
+ Coverage.supported?(1)
+ }.should.raise(TypeError, "wrong argument type Integer (expected Symbol)")
end
end
diff --git a/spec/ruby/library/csv/generate_spec.rb b/spec/ruby/library/csv/generate_spec.rb
index b45e2eb95b..62e19aa6e4 100644
--- a/spec/ruby/library/csv/generate_spec.rb
+++ b/spec/ruby/library/csv/generate_spec.rb
@@ -26,7 +26,7 @@ describe "CSV.generate" do
csv.add_row [1, 2, 3]
csv << [4, 5, 6]
end
- csv_str.should equal str
+ csv_str.should.equal? str
str.should == "1,2,3\n4,5,6\n"
end
end
diff --git a/spec/ruby/library/csv/parse_spec.rb b/spec/ruby/library/csv/parse_spec.rb
index ef5d4ea3ca..7000f03cda 100644
--- a/spec/ruby/library/csv/parse_spec.rb
+++ b/spec/ruby/library/csv/parse_spec.rb
@@ -5,7 +5,7 @@ describe "CSV.parse" do
it "parses '' into []" do
result = CSV.parse ''
- result.should be_kind_of(Array)
+ result.should.is_a?(Array)
result.should == []
end
@@ -82,7 +82,7 @@ describe "CSV.parse" do
it "raises CSV::MalformedCSVError exception if input is illegal" do
-> {
CSV.parse('"quoted" field')
- }.should raise_error(CSV::MalformedCSVError)
+ }.should.raise(CSV::MalformedCSVError)
end
it "handles illegal input with the liberal_parsing option" do
diff --git a/spec/ruby/library/csv/readlines_spec.rb b/spec/ruby/library/csv/readlines_spec.rb
index 14dea34381..624f906489 100644
--- a/spec/ruby/library/csv/readlines_spec.rb
+++ b/spec/ruby/library/csv/readlines_spec.rb
@@ -23,7 +23,7 @@ describe "CSV#readlines" do
it "raises CSV::MalformedCSVError exception if input is illegal" do
csv = CSV.new('"quoted" field')
- -> { csv.readlines }.should raise_error(CSV::MalformedCSVError)
+ -> { csv.readlines }.should.raise(CSV::MalformedCSVError)
end
it "handles illegal input with the liberal_parsing option" do
diff --git a/spec/ruby/library/date/add_month_spec.rb b/spec/ruby/library/date/add_month_spec.rb
index 40833f6487..ab802ea97a 100644
--- a/spec/ruby/library/date/add_month_spec.rb
+++ b/spec/ruby/library/date/add_month_spec.rb
@@ -21,18 +21,18 @@ describe "Date#>>" do
end
it "raise a TypeError when passed a Symbol" do
- -> { Date.civil(2007,2,27) >> :hello }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> :hello }.should.raise(TypeError)
end
it "raise a TypeError when passed a String" do
- -> { Date.civil(2007,2,27) >> "hello" }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> "hello" }.should.raise(TypeError)
end
it "raise a TypeError when passed a Date" do
- -> { Date.civil(2007,2,27) >> Date.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> Date.new }.should.raise(TypeError)
end
it "raise a TypeError when passed an Object" do
- -> { Date.civil(2007,2,27) >> Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) >> Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/add_spec.rb b/spec/ruby/library/date/add_spec.rb
index 2b9cc62023..5e368decdc 100644
--- a/spec/ruby/library/date/add_spec.rb
+++ b/spec/ruby/library/date/add_spec.rb
@@ -13,18 +13,18 @@ describe "Date#+" do
end
it "raises a TypeError when passed a Symbol" do
- -> { Date.civil(2007,2,27) + :hello }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + :hello }.should.raise(TypeError)
end
it "raises a TypeError when passed a String" do
- -> { Date.civil(2007,2,27) + "hello" }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + "hello" }.should.raise(TypeError)
end
it "raises a TypeError when passed a Date" do
- -> { Date.civil(2007,2,27) + Date.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + Date.new }.should.raise(TypeError)
end
it "raises a TypeError when passed an Object" do
- -> { Date.civil(2007,2,27) + Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) + Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/constants_spec.rb b/spec/ruby/library/date/constants_spec.rb
index 1d18dd1b0c..3494b0c296 100644
--- a/spec/ruby/library/date/constants_spec.rb
+++ b/spec/ruby/library/date/constants_spec.rb
@@ -36,11 +36,11 @@ describe "Date constants" do
[Date::MONTHNAMES, Date::DAYNAMES, Date::ABBR_MONTHNAMES, Date::ABBR_DAYNAMES].each do |ary|
-> {
ary << "Unknown"
- }.should raise_error(FrozenError, /frozen/)
+ }.should.raise(FrozenError, /frozen/)
ary.compact.each do |name|
-> {
name << "modified"
- }.should raise_error(FrozenError, /frozen/)
+ }.should.raise(FrozenError, /frozen/)
end
end
end
diff --git a/spec/ruby/library/date/deconstruct_keys_spec.rb b/spec/ruby/library/date/deconstruct_keys_spec.rb
index 92579e35c7..1fa1e70250 100644
--- a/spec/ruby/library/date/deconstruct_keys_spec.rb
+++ b/spec/ruby/library/date/deconstruct_keys_spec.rb
@@ -2,43 +2,41 @@ require_relative '../../spec_helper'
require 'date'
date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
-version_is date_version, "3.3" do #ruby_version_is "3.2" do
- describe "Date#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = Date.new(2022, 10, 5)
- d.deconstruct_keys(nil).should == { year: 2022, month: 10, day: 5, yday: 278, wday: 3 }
- end
-
- it "returns only specified keys" do
- d = Date.new(2022, 10, 5)
- d.deconstruct_keys([:year, :month]).should == { year: 2022, month: 10 }
- end
-
- it "requires one argument" do
- -> {
- Date.new(2022, 10, 5).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = Date.new(2022, 10, 5)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- Date.new(2022, 10, 5).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- Date.new(2022, 10, 5).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys" do
- Date.new(2022, 10, 5).deconstruct_keys([:year, :a]).should == { year: 2022 }
- end
+describe "Date#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = Date.new(2022, 10, 5)
+ d.deconstruct_keys(nil).should == { year: 2022, month: 10, day: 5, yday: 278, wday: 3 }
+ end
+
+ it "returns only specified keys" do
+ d = Date.new(2022, 10, 5)
+ d.deconstruct_keys([:year, :month]).should == { year: 2022, month: 10 }
+ end
+
+ it "requires one argument" do
+ -> {
+ Date.new(2022, 10, 5).deconstruct_keys
+ }.should.raise(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = Date.new(2022, 10, 5)
+
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ Date.new(2022, 10, 5).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ Date.new(2022, 10, 5).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ Date.new(2022, 10, 5).deconstruct_keys([:year, :a]).should == { year: 2022 }
end
end
diff --git a/spec/ruby/library/date/eql_spec.rb b/spec/ruby/library/date/eql_spec.rb
index a1819cae3a..79fabc47f4 100644
--- a/spec/ruby/library/date/eql_spec.rb
+++ b/spec/ruby/library/date/eql_spec.rb
@@ -3,10 +3,10 @@ require 'date'
describe "Date#eql?" do
it "returns true if self is equal to another date" do
- Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 11)).should be_true
+ Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 11)).should == true
end
it "returns false if self is not equal to another date" do
- Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 12)).should be_false
+ Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 12)).should == false
end
end
diff --git a/spec/ruby/library/date/friday_spec.rb b/spec/ruby/library/date/friday_spec.rb
index 3dc040fabe..62f050346e 100644
--- a/spec/ruby/library/date/friday_spec.rb
+++ b/spec/ruby/library/date/friday_spec.rb
@@ -3,10 +3,10 @@ require 'date'
describe "Date#friday?" do
it "should be friday" do
- Date.new(2000, 1, 7).friday?.should be_true
+ Date.new(2000, 1, 7).friday?.should == true
end
it "should not be friday" do
- Date.new(2000, 1, 8).friday?.should be_false
+ Date.new(2000, 1, 8).friday?.should == false
end
end
diff --git a/spec/ruby/library/date/gregorian_leap_spec.rb b/spec/ruby/library/date/gregorian_leap_spec.rb
index c3d25cf90f..c27890faf4 100644
--- a/spec/ruby/library/date/gregorian_leap_spec.rb
+++ b/spec/ruby/library/date/gregorian_leap_spec.rb
@@ -3,13 +3,13 @@ require 'date'
describe "Date#gregorian_leap?" do
it "returns true if a year is a leap year in the Gregorian calendar" do
- Date.gregorian_leap?(2000).should be_true
- Date.gregorian_leap?(2004).should be_true
+ Date.gregorian_leap?(2000).should == true
+ Date.gregorian_leap?(2004).should == true
end
it "returns false if a year is not a leap year in the Gregorian calendar" do
- Date.gregorian_leap?(1900).should be_false
- Date.gregorian_leap?(1999).should be_false
- Date.gregorian_leap?(2002).should be_false
+ Date.gregorian_leap?(1900).should == false
+ Date.gregorian_leap?(1999).should == false
+ Date.gregorian_leap?(2002).should == false
end
end
diff --git a/spec/ruby/library/date/gregorian_spec.rb b/spec/ruby/library/date/gregorian_spec.rb
index ea7ece2ade..bbda13af08 100644
--- a/spec/ruby/library/date/gregorian_spec.rb
+++ b/spec/ruby/library/date/gregorian_spec.rb
@@ -4,13 +4,13 @@ require 'date'
describe "Date#gregorian?" do
it "marks a day before the calendar reform as Julian" do
- Date.civil(1007, 2, 27).gregorian?.should be_false
- Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).gregorian?.should be_false
+ Date.civil(1007, 2, 27).gregorian?.should == false
+ Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).gregorian?.should == false
end
it "marks a day after the calendar reform as Julian" do
Date.civil(2007, 2, 27).should.gregorian?
- Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).gregorian?.should be_true
+ Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).gregorian?.should == true
end
end
diff --git a/spec/ruby/library/date/iso8601_spec.rb b/spec/ruby/library/date/iso8601_spec.rb
index af66845a6b..26815bd76c 100644
--- a/spec/ruby/library/date/iso8601_spec.rb
+++ b/spec/ruby/library/date/iso8601_spec.rb
@@ -25,17 +25,17 @@ describe "Date.iso8601" do
it "raises a Date::Error if the argument is a invalid Date" do
-> {
Date.iso8601('invalid')
- }.should raise_error(Date::Error, "invalid date")
+ }.should.raise(Date::Error, "invalid date")
end
it "raises a Date::Error when passed a nil" do
-> {
Date.iso8601(nil)
- }.should raise_error(Date::Error, "invalid date")
+ }.should.raise(Date::Error, "invalid date")
end
it "raises a TypeError when passed an Object" do
- -> { Date.iso8601(Object.new) }.should raise_error(TypeError)
+ -> { Date.iso8601(Object.new) }.should.raise(TypeError)
end
end
@@ -51,6 +51,6 @@ describe "Date._iso8601" do
end
it "raises a TypeError when passed an Object" do
- -> { Date._iso8601(Object.new) }.should raise_error(TypeError)
+ -> { Date._iso8601(Object.new) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/julian_leap_spec.rb b/spec/ruby/library/date/julian_leap_spec.rb
index 2ef2d65d81..42231e012f 100644
--- a/spec/ruby/library/date/julian_leap_spec.rb
+++ b/spec/ruby/library/date/julian_leap_spec.rb
@@ -3,13 +3,13 @@ require 'date'
describe "Date.julian_leap?" do
it "determines whether a year is a leap year in the Julian calendar" do
- Date.julian_leap?(1900).should be_true
- Date.julian_leap?(2000).should be_true
- Date.julian_leap?(2004).should be_true
+ Date.julian_leap?(1900).should == true
+ Date.julian_leap?(2000).should == true
+ Date.julian_leap?(2004).should == true
end
it "determines whether a year is not a leap year in the Julian calendar" do
- Date.julian_leap?(1999).should be_false
- Date.julian_leap?(2002).should be_false
+ Date.julian_leap?(1999).should == false
+ Date.julian_leap?(2002).should == false
end
end
diff --git a/spec/ruby/library/date/julian_spec.rb b/spec/ruby/library/date/julian_spec.rb
index db2629d1e7..9f8a670899 100644
--- a/spec/ruby/library/date/julian_spec.rb
+++ b/spec/ruby/library/date/julian_spec.rb
@@ -5,12 +5,12 @@ describe "Date#julian?" do
it "marks a day before the calendar reform as Julian" do
Date.civil(1007, 2, 27).should.julian?
- Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).julian?.should be_true
+ Date.civil(1907, 2, 27, Date.civil(1930, 1, 1).jd).julian?.should == true
end
it "marks a day after the calendar reform as Julian" do
Date.civil(2007, 2, 27).should_not.julian?
- Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).julian?.should be_false
+ Date.civil(1607, 2, 27, Date.civil(1582, 1, 1).jd).julian?.should == false
end
end
diff --git a/spec/ruby/library/date/minus_month_spec.rb b/spec/ruby/library/date/minus_month_spec.rb
index 470c4d8a76..d56e19dc31 100644
--- a/spec/ruby/library/date/minus_month_spec.rb
+++ b/spec/ruby/library/date/minus_month_spec.rb
@@ -14,10 +14,10 @@ describe "Date#<<" do
end
it "raises an error on non numeric parameters" do
- -> { Date.civil(2007,2,27) << :hello }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) << "hello" }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) << Date.new }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) << Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) << :hello }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) << "hello" }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) << Date.new }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) << Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/minus_spec.rb b/spec/ruby/library/date/minus_spec.rb
index 5a2a29e04a..c2a08fa5b0 100644
--- a/spec/ruby/library/date/minus_spec.rb
+++ b/spec/ruby/library/date/minus_spec.rb
@@ -22,9 +22,9 @@ describe "Date#-" do
end
it "raises an error for non Numeric arguments" do
- -> { Date.civil(2007,2,27) - :hello }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) - "hello" }.should raise_error(TypeError)
- -> { Date.civil(2007,2,27) - Object.new }.should raise_error(TypeError)
+ -> { Date.civil(2007,2,27) - :hello }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) - "hello" }.should.raise(TypeError)
+ -> { Date.civil(2007,2,27) - Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/monday_spec.rb b/spec/ruby/library/date/monday_spec.rb
index 14a117b73c..61d728f3c5 100644
--- a/spec/ruby/library/date/monday_spec.rb
+++ b/spec/ruby/library/date/monday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#monday?" do
it "should be monday" do
- Date.new(2000, 1, 3).monday?.should be_true
+ Date.new(2000, 1, 3).monday?.should == true
end
end
diff --git a/spec/ruby/library/date/parse_spec.rb b/spec/ruby/library/date/parse_spec.rb
index 5ef4f6e9b5..4d655f516e 100644
--- a/spec/ruby/library/date/parse_spec.rb
+++ b/spec/ruby/library/date/parse_spec.rb
@@ -23,7 +23,7 @@ describe "Date#parse" do
# Specs using numbers
it "throws an argument error for a single digit" do
- ->{ Date.parse("1") }.should raise_error(ArgumentError)
+ ->{ Date.parse("1") }.should.raise(ArgumentError)
end
it "parses DD as month day number" do
@@ -66,8 +66,8 @@ describe "Date#parse" do
end
it "raises a TypeError trying to parse non-String-like object" do
- -> { Date.parse(1) }.should raise_error(TypeError)
- -> { Date.parse([]) }.should raise_error(TypeError)
+ -> { Date.parse(1) }.should.raise(TypeError)
+ -> { Date.parse([]) }.should.raise(TypeError)
end
it "coerces using to_str" do
diff --git a/spec/ruby/library/date/plus_spec.rb b/spec/ruby/library/date/plus_spec.rb
index 0cb99fd4ca..6179370fca 100644
--- a/spec/ruby/library/date/plus_spec.rb
+++ b/spec/ruby/library/date/plus_spec.rb
@@ -15,6 +15,6 @@ describe "Date#+" do
end
it "raises TypeError if argument is not Numeric" do
- -> { Date.today + Date.today }.should raise_error(TypeError)
+ -> { Date.today + Date.today }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/date/saturday_spec.rb b/spec/ruby/library/date/saturday_spec.rb
index 1527b71d00..29f8267a2b 100644
--- a/spec/ruby/library/date/saturday_spec.rb
+++ b/spec/ruby/library/date/saturday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#saturday?" do
it "should be saturday" do
- Date.new(2000, 1, 1).saturday?.should be_true
+ Date.new(2000, 1, 1).saturday?.should == true
end
end
diff --git a/spec/ruby/library/date/shared/civil.rb b/spec/ruby/library/date/shared/civil.rb
index bbed4a8866..4499cdf8e9 100644
--- a/spec/ruby/library/date/shared/civil.rb
+++ b/spec/ruby/library/date/shared/civil.rb
@@ -36,14 +36,14 @@ describe :date_civil, shared: true do
end
it "doesn't create dates for invalid arguments" do
- -> { Date.send(@method, 2000, 13, 31) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2000, 12, 32) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2000, 2, 30) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 1900, 2, 29) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2000, 2, 29) }.should_not raise_error(ArgumentError)
-
- -> { Date.send(@method, 1582, 10, 14) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 1582, 10, 15) }.should_not raise_error(ArgumentError)
+ -> { Date.send(@method, 2000, 13, 31) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2000, 12, 32) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2000, 2, 30) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 1900, 2, 29) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2000, 2, 29) }.should_not.raise(ArgumentError)
+
+ -> { Date.send(@method, 1582, 10, 14) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 1582, 10, 15) }.should_not.raise(ArgumentError)
end
diff --git a/spec/ruby/library/date/shared/commercial.rb b/spec/ruby/library/date/shared/commercial.rb
index 39c9af47b6..f53d83235a 100644
--- a/spec/ruby/library/date/shared/commercial.rb
+++ b/spec/ruby/library/date/shared/commercial.rb
@@ -25,15 +25,15 @@ describe :date_commercial, shared: true do
end
it "creates only Date objects for valid weeks" do
- -> { Date.send(@method, 2004, 53, 1) }.should_not raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 53, 0) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 53, 8) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 54, 1) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2004, 0, 1) }.should raise_error(ArgumentError)
+ -> { Date.send(@method, 2004, 53, 1) }.should_not.raise(ArgumentError)
+ -> { Date.send(@method, 2004, 53, 0) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2004, 53, 8) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2004, 54, 1) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2004, 0, 1) }.should.raise(ArgumentError)
- -> { Date.send(@method, 2003, 52, 1) }.should_not raise_error(ArgumentError)
- -> { Date.send(@method, 2003, 53, 1) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2003, 52, 0) }.should raise_error(ArgumentError)
- -> { Date.send(@method, 2003, 52, 8) }.should raise_error(ArgumentError)
+ -> { Date.send(@method, 2003, 52, 1) }.should_not.raise(ArgumentError)
+ -> { Date.send(@method, 2003, 53, 1) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2003, 52, 0) }.should.raise(ArgumentError)
+ -> { Date.send(@method, 2003, 52, 8) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/date/shared/valid_civil.rb b/spec/ruby/library/date/shared/valid_civil.rb
index 545c207bbe..425fee4d2d 100644
--- a/spec/ruby/library/date/shared/valid_civil.rb
+++ b/spec/ruby/library/date/shared/valid_civil.rb
@@ -9,8 +9,8 @@ describe :date_valid_civil?, shared: true do
# 31
it "returns true if it is a valid civil date" do
- Date.send(@method, 1582, 10, 15).should be_true
- Date.send(@method, 1582, 10, 14, Date::ENGLAND).should be_true
+ Date.send(@method, 1582, 10, 15).should == true
+ Date.send(@method, 1582, 10, 14, Date::ENGLAND).should == true
end
it "returns false if it is not a valid civil date" do
@@ -24,13 +24,13 @@ describe :date_valid_civil?, shared: true do
# -15 -14 -13 -12 -11 -10 -9
# -8 -7 -6 -5 -4 -3 -2
# -1
- Date.send(@method, 1582, -3, -22).should be_false
- Date.send(@method, 1582, -3, -21).should be_true
- Date.send(@method, 1582, -3, -18).should be_true
- Date.send(@method, 1582, -3, -17).should be_true
+ Date.send(@method, 1582, -3, -22).should == false
+ Date.send(@method, 1582, -3, -21).should == true
+ Date.send(@method, 1582, -3, -18).should == true
+ Date.send(@method, 1582, -3, -17).should == true
- Date.send(@method, 2007, -11, -10).should be_true
- Date.send(@method, 2008, -11, -10).should be_true
+ Date.send(@method, 2007, -11, -10).should == true
+ Date.send(@method, 2008, -11, -10).should == true
end
end
diff --git a/spec/ruby/library/date/shared/valid_commercial.rb b/spec/ruby/library/date/shared/valid_commercial.rb
index 117dfe1d3d..573b851fdd 100644
--- a/spec/ruby/library/date/shared/valid_commercial.rb
+++ b/spec/ruby/library/date/shared/valid_commercial.rb
@@ -6,16 +6,16 @@ describe :date_valid_commercial?, shared: true do
# 39: 1 2 3 4 5 6 7
# 40: 1 2 3 4 5 6 7
# 41: 1 2 3 4 5 6 7
- Date.send(@method, 1582, 39, 4).should be_true
- Date.send(@method, 1582, 39, 5).should be_true
- Date.send(@method, 1582, 41, 4).should be_true
- Date.send(@method, 1582, 41, 5).should be_true
- Date.send(@method, 1582, 41, 4, Date::ENGLAND).should be_true
- Date.send(@method, 1752, 37, 4, Date::ENGLAND).should be_true
+ Date.send(@method, 1582, 39, 4).should == true
+ Date.send(@method, 1582, 39, 5).should == true
+ Date.send(@method, 1582, 41, 4).should == true
+ Date.send(@method, 1582, 41, 5).should == true
+ Date.send(@method, 1582, 41, 4, Date::ENGLAND).should == true
+ Date.send(@method, 1752, 37, 4, Date::ENGLAND).should == true
end
it "returns false it is not a valid commercial date" do
- Date.send(@method, 1999, 53, 1).should be_false
+ Date.send(@method, 1999, 53, 1).should == false
end
it "handles negative week and day numbers" do
@@ -24,11 +24,11 @@ describe :date_valid_commercial?, shared: true do
# -12: -7 -6 -5 -4 -3 -2 -1
# -11: -7 -6 -5 -4 -3 -2 -1
# -10: -7 -6 -5 -4 -3 -2 -1
- Date.send(@method, 1582, -12, -4).should be_true
- Date.send(@method, 1582, -12, -3).should be_true
- Date.send(@method, 2007, -44, -2).should be_true
- Date.send(@method, 2008, -44, -2).should be_true
- Date.send(@method, 1999, -53, -1).should be_false
+ Date.send(@method, 1582, -12, -4).should == true
+ Date.send(@method, 1582, -12, -3).should == true
+ Date.send(@method, 2007, -44, -2).should == true
+ Date.send(@method, 2008, -44, -2).should == true
+ Date.send(@method, 1999, -53, -1).should == false
end
end
diff --git a/spec/ruby/library/date/shared/valid_jd.rb b/spec/ruby/library/date/shared/valid_jd.rb
index e474dfb450..0c01710208 100644
--- a/spec/ruby/library/date/shared/valid_jd.rb
+++ b/spec/ruby/library/date/shared/valid_jd.rb
@@ -1,20 +1,20 @@
describe :date_valid_jd?, shared: true do
it "returns true if passed a number value" do
- Date.send(@method, -100).should be_true
- Date.send(@method, 100.0).should be_true
- Date.send(@method, 2**100).should be_true
- Date.send(@method, Rational(1,2)).should be_true
+ Date.send(@method, -100).should == true
+ Date.send(@method, 100.0).should == true
+ Date.send(@method, 2**100).should == true
+ Date.send(@method, Rational(1,2)).should == true
end
it "returns false if passed nil" do
- Date.send(@method, nil).should be_false
+ Date.send(@method, nil).should == false
end
it "returns false if passed symbol" do
- Date.send(@method, :number).should be_false
+ Date.send(@method, :number).should == false
end
it "returns false if passed false" do
- Date.send(@method, false).should be_false
+ Date.send(@method, false).should == false
end
end
diff --git a/spec/ruby/library/date/sunday_spec.rb b/spec/ruby/library/date/sunday_spec.rb
index c3a817fa86..548f36a4f0 100644
--- a/spec/ruby/library/date/sunday_spec.rb
+++ b/spec/ruby/library/date/sunday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#sunday?" do
it "should be sunday" do
- Date.new(2000, 1, 2).sunday?.should be_true
+ Date.new(2000, 1, 2).sunday?.should == true
end
end
diff --git a/spec/ruby/library/date/thursday_spec.rb b/spec/ruby/library/date/thursday_spec.rb
index 74b5f40365..4df3b9103a 100644
--- a/spec/ruby/library/date/thursday_spec.rb
+++ b/spec/ruby/library/date/thursday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#thursday?" do
it "should be thursday" do
- Date.new(2000, 1, 6).thursday?.should be_true
+ Date.new(2000, 1, 6).thursday?.should == true
end
end
diff --git a/spec/ruby/library/date/today_spec.rb b/spec/ruby/library/date/today_spec.rb
index 7c6ebc9cb4..4be8d8e931 100644
--- a/spec/ruby/library/date/today_spec.rb
+++ b/spec/ruby/library/date/today_spec.rb
@@ -3,7 +3,7 @@ require 'date'
describe "Date.today" do
it "returns a Date object" do
- Date.today.should be_kind_of Date
+ Date.today.should.is_a? Date
end
it "sets Date object to the current date" do
diff --git a/spec/ruby/library/date/tuesday_spec.rb b/spec/ruby/library/date/tuesday_spec.rb
index 052837b54e..db31387aed 100644
--- a/spec/ruby/library/date/tuesday_spec.rb
+++ b/spec/ruby/library/date/tuesday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#tuesday?" do
it "should be tuesday" do
- Date.new(2000, 1, 4).tuesday?.should be_true
+ Date.new(2000, 1, 4).tuesday?.should == true
end
end
diff --git a/spec/ruby/library/date/wednesday_spec.rb b/spec/ruby/library/date/wednesday_spec.rb
index e80ec23dd2..4bbeead5b8 100644
--- a/spec/ruby/library/date/wednesday_spec.rb
+++ b/spec/ruby/library/date/wednesday_spec.rb
@@ -3,6 +3,6 @@ require 'date'
describe "Date#wednesday?" do
it "should be wednesday" do
- Date.new(2000, 1, 5).wednesday?.should be_true
+ Date.new(2000, 1, 5).wednesday?.should == true
end
end
diff --git a/spec/ruby/library/datetime/deconstruct_keys_spec.rb b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
index 77ceaa51c4..07a7bda881 100644
--- a/spec/ruby/library/datetime/deconstruct_keys_spec.rb
+++ b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
@@ -2,45 +2,43 @@ require_relative '../../spec_helper'
require 'date'
date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
-version_is date_version, "3.3" do #ruby_version_is "3.2" do
- describe "DateTime#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = DateTime.new(2022, 10, 5, 13, 30)
- res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
- min: 30, sec: 0, sec_fraction: (0/1), zone: "+00:00" }
- d.deconstruct_keys(nil).should == res
- end
-
- it "returns only specified keys" do
- d = DateTime.new(2022, 10, 5, 13, 39)
- d.deconstruct_keys([:zone, :hour]).should == { zone: "+00:00", hour: 13 }
- end
-
- it "requires one argument" do
- -> {
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = DateTime.new(2022, 10, 5, 13, 30)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys" do
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
- end
+describe "DateTime#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = DateTime.new(2022, 10, 5, 13, 30)
+ res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
+ min: 30, sec: 0, sec_fraction: (0/1), zone: "+00:00" }
+ d.deconstruct_keys(nil).should == res
+ end
+
+ it "returns only specified keys" do
+ d = DateTime.new(2022, 10, 5, 13, 39)
+ d.deconstruct_keys([:zone, :hour]).should == { zone: "+00:00", hour: 13 }
+ end
+
+ it "requires one argument" do
+ -> {
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys
+ }.should.raise(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = DateTime.new(2022, 10, 5, 13, 30)
+
+ -> { d.deconstruct_keys(1) }.should.raise(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should.raise(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should.raise(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should.raise(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
end
end
diff --git a/spec/ruby/library/datetime/hour_spec.rb b/spec/ruby/library/datetime/hour_spec.rb
index 8efd5f92f0..383a85fe60 100644
--- a/spec/ruby/library/datetime/hour_spec.rb
+++ b/spec/ruby/library/datetime/hour_spec.rb
@@ -15,23 +15,23 @@ describe "DateTime#hour" do
end
it "raises an error for Rational" do
- -> { new_datetime(hour: 1 + Rational(1,2)) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 1 + Rational(1,2)) }.should.raise(ArgumentError)
end
it "raises an error for Float" do
- -> { new_datetime(hour: 1.5).hour }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 1.5).hour }.should.raise(ArgumentError)
end
it "raises an error for Rational" do
- -> { new_datetime(day: 1 + Rational(1,2)) }.should raise_error(ArgumentError)
+ -> { new_datetime(day: 1 + Rational(1,2)) }.should.raise(ArgumentError)
end
it "raises an error, when the hour is smaller than -24" do
- -> { new_datetime(hour: -25) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: -25) }.should.raise(ArgumentError)
end
it "raises an error, when the hour is larger than 24" do
- -> { new_datetime(hour: 25) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 25) }.should.raise(ArgumentError)
end
it "raises an error for hour fractions smaller than -24" do
diff --git a/spec/ruby/library/datetime/new_spec.rb b/spec/ruby/library/datetime/new_spec.rb
index 6a4dced384..2b3c3f156c 100644
--- a/spec/ruby/library/datetime/new_spec.rb
+++ b/spec/ruby/library/datetime/new_spec.rb
@@ -47,6 +47,6 @@ describe "DateTime.new" do
end
it "raises an error on invalid arguments" do
- -> { new_datetime(minute: 999) }.should raise_error(ArgumentError)
+ -> { new_datetime(minute: 999) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/datetime/now_spec.rb b/spec/ruby/library/datetime/now_spec.rb
index 9f22153c15..5c0411c2be 100644
--- a/spec/ruby/library/datetime/now_spec.rb
+++ b/spec/ruby/library/datetime/now_spec.rb
@@ -3,7 +3,7 @@ require 'date'
describe "DateTime.now" do
it "creates an instance of DateTime" do
- DateTime.now.should be_an_instance_of(DateTime)
+ DateTime.now.should.instance_of?(DateTime)
end
it "sets the current date" do
diff --git a/spec/ruby/library/datetime/parse_spec.rb b/spec/ruby/library/datetime/parse_spec.rb
index e9bf4e2ed1..0a965273a0 100644
--- a/spec/ruby/library/datetime/parse_spec.rb
+++ b/spec/ruby/library/datetime/parse_spec.rb
@@ -20,7 +20,7 @@ describe "DateTime.parse" do
# Specs using numbers
it "throws an argument error for a single digit" do
- ->{ DateTime.parse("1") }.should raise_error(ArgumentError)
+ ->{ DateTime.parse("1") }.should.raise(ArgumentError)
end
it "parses DD as month day number" do
@@ -54,23 +54,23 @@ describe "DateTime.parse" do
end
it "throws an argument error for invalid month values" do
- ->{DateTime.parse("2012-13-08T15:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-13-08T15:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid day values" do
- ->{DateTime.parse("2012-12-32T15:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-12-32T15:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid hour values" do
- ->{DateTime.parse("2012-12-31T25:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-12-31T25:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid minute values" do
- ->{DateTime.parse("2012-12-31T25:43:59")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-12-31T25:43:59")}.should.raise(ArgumentError)
end
it "throws an argument error for invalid second values" do
- ->{DateTime.parse("2012-11-08T15:43:61")}.should raise_error(ArgumentError)
+ ->{DateTime.parse("2012-11-08T15:43:61")}.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/datetime/rfc2822_spec.rb b/spec/ruby/library/datetime/rfc2822_spec.rb
index 83f7fa8d5b..11b79a1e84 100644
--- a/spec/ruby/library/datetime/rfc2822_spec.rb
+++ b/spec/ruby/library/datetime/rfc2822_spec.rb
@@ -5,6 +5,6 @@ describe "DateTime.rfc2822" do
it "needs to be reviewed for spec completeness"
it "raises DateError if passed nil" do
- -> { DateTime.rfc2822(nil) }.should raise_error(Date::Error, "invalid date")
+ -> { DateTime.rfc2822(nil) }.should.raise(Date::Error, "invalid date")
end
end
diff --git a/spec/ruby/library/datetime/shared/min.rb b/spec/ruby/library/datetime/shared/min.rb
index a35b839281..04e5f3457a 100644
--- a/spec/ruby/library/datetime/shared/min.rb
+++ b/spec/ruby/library/datetime/shared/min.rb
@@ -14,23 +14,23 @@ describe :datetime_min, shared: true do
end
it "raises an error for Rational" do
- -> { new_datetime minute: 5 + Rational(1,2) }.should raise_error(ArgumentError)
+ -> { new_datetime minute: 5 + Rational(1,2) }.should.raise(ArgumentError)
end
it "raises an error for Float" do
- -> { new_datetime minute: 5.5 }.should raise_error(ArgumentError)
+ -> { new_datetime minute: 5.5 }.should.raise(ArgumentError)
end
it "raises an error for Rational" do
- -> { new_datetime(hour: 2 + Rational(1,2)) }.should raise_error(ArgumentError)
+ -> { new_datetime(hour: 2 + Rational(1,2)) }.should.raise(ArgumentError)
end
it "raises an error, when the minute is smaller than -60" do
- -> { new_datetime(minute: -61) }.should raise_error(ArgumentError)
+ -> { new_datetime(minute: -61) }.should.raise(ArgumentError)
end
it "raises an error, when the minute is greater or equal than 60" do
- -> { new_datetime(minute: 60) }.should raise_error(ArgumentError)
+ -> { new_datetime(minute: 60) }.should.raise(ArgumentError)
end
it "raises an error for minute fractions smaller than -60" do
diff --git a/spec/ruby/library/datetime/shared/sec.rb b/spec/ruby/library/datetime/shared/sec.rb
index 60009213aa..5af5db4fb2 100644
--- a/spec/ruby/library/datetime/shared/sec.rb
+++ b/spec/ruby/library/datetime/shared/sec.rb
@@ -23,15 +23,15 @@ describe :datetime_sec, shared: true do
end
it "raises an error when minute is given as a rational" do
- -> { new_datetime(minute: 5 + Rational(1,2)) }.should raise_error(ArgumentError)
+ -> { new_datetime(minute: 5 + Rational(1,2)) }.should.raise(ArgumentError)
end
it "raises an error, when the second is smaller than -60" do
- -> { new_datetime(second: -61) }.should raise_error(ArgumentError)
+ -> { new_datetime(second: -61) }.should.raise(ArgumentError)
end
it "raises an error, when the second is greater or equal than 60" do
- -> { new_datetime(second: 60) }.should raise_error(ArgumentError)
+ -> { new_datetime(second: 60) }.should.raise(ArgumentError)
end
it "raises an error for second fractions smaller than -60" do
diff --git a/spec/ruby/library/datetime/time/to_datetime_spec.rb b/spec/ruby/library/datetime/time/to_datetime_spec.rb
index 1125dbe851..5589725238 100644
--- a/spec/ruby/library/datetime/time/to_datetime_spec.rb
+++ b/spec/ruby/library/datetime/time/to_datetime_spec.rb
@@ -15,17 +15,15 @@ describe "Time#to_datetime" do
datetime.sec.should == 59
end
- version_is date_version, '3.2.3' do #ruby_version_is '3.2' do
- it "returns a DateTime representing the same instant before Gregorian" do
- time = Time.utc(1582, 10, 14, 23, 58, 59)
- datetime = time.to_datetime
- datetime.year.should == 1582
- datetime.month.should == 10
- datetime.day.should == 4
- datetime.hour.should == 23
- datetime.min.should == 58
- datetime.sec.should == 59
- end
+ it "returns a DateTime representing the same instant before Gregorian" do
+ time = Time.utc(1582, 10, 14, 23, 58, 59)
+ datetime = time.to_datetime
+ datetime.year.should == 1582
+ datetime.month.should == 10
+ datetime.day.should == 4
+ datetime.hour.should == 23
+ datetime.min.should == 58
+ datetime.sec.should == 59
end
it "roundtrips" do
diff --git a/spec/ruby/library/datetime/to_date_spec.rb b/spec/ruby/library/datetime/to_date_spec.rb
index 48c05e7fed..31ccf5ae98 100644
--- a/spec/ruby/library/datetime/to_date_spec.rb
+++ b/spec/ruby/library/datetime/to_date_spec.rb
@@ -4,7 +4,7 @@ require 'date'
describe "DateTime#to_date" do
it "returns an instance of Date" do
dt = DateTime.new(2012, 12, 24, 12, 23, 00, '+05:00')
- dt.to_date.should be_kind_of(Date)
+ dt.to_date.should.is_a?(Date)
end
it "maintains the same year" do
diff --git a/spec/ruby/library/datetime/to_s_spec.rb b/spec/ruby/library/datetime/to_s_spec.rb
index 175fb807f4..ed0746f42b 100644
--- a/spec/ruby/library/datetime/to_s_spec.rb
+++ b/spec/ruby/library/datetime/to_s_spec.rb
@@ -4,7 +4,7 @@ require 'date'
describe "DateTime#to_s" do
it "returns a new String object" do
dt = DateTime.new(2012, 12, 24, 1, 2, 3, "+03:00")
- dt.to_s.should be_kind_of(String)
+ dt.to_s.should.is_a?(String)
end
it "maintains timezone regardless of local time" do
diff --git a/spec/ruby/library/datetime/to_time_spec.rb b/spec/ruby/library/datetime/to_time_spec.rb
index 09e6192e7f..a3ffc019fb 100644
--- a/spec/ruby/library/datetime/to_time_spec.rb
+++ b/spec/ruby/library/datetime/to_time_spec.rb
@@ -4,7 +4,7 @@ date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "DateTime#to_time" do
it "yields a new Time object" do
- DateTime.now.to_time.should be_kind_of(Time)
+ DateTime.now.to_time.should.is_a?(Time)
end
it "returns a Time representing the same instant" do
@@ -19,17 +19,15 @@ describe "DateTime#to_time" do
time.sec.should == 59
end
- version_is date_version, '3.2.3' do #ruby_version_is "3.2" do
- it "returns a Time representing the same instant before Gregorian" do
- datetime = DateTime.civil(1582, 10, 4, 23, 58, 59)
- time = datetime.to_time.utc
- time.year.should == 1582
- time.month.should == 10
- time.day.should == 14
- time.hour.should == 23
- time.min.should == 58
- time.sec.should == 59
- end
+ it "returns a Time representing the same instant before Gregorian" do
+ datetime = DateTime.civil(1582, 10, 4, 23, 58, 59)
+ time = datetime.to_time.utc
+ time.year.should == 1582
+ time.month.should == 10
+ time.day.should == 14
+ time.hour.should == 23
+ time.min.should == 58
+ time.sec.should == 59
end
it "preserves the same time regardless of local time or zone" do
diff --git a/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb b/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb
index 16bf8d734c..19ffc4cf85 100644
--- a/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/instance_method_spec.rb
@@ -9,44 +9,44 @@ describe "DelegateClass.instance_method" do
it "returns a method object for public instance methods of the delegated class" do
m = @klass.instance_method(:pub)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :foo
end
it "returns a method object for protected instance methods of the delegated class" do
m = @klass.instance_method(:prot)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :protected
end
it "raises a NameError for a private instance methods of the delegated class" do
-> {
@klass.instance_method(:priv)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns a method object for public instance methods of the DelegateClass class" do
m = @klass.instance_method(:extra)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :cheese
end
it "returns a method object for protected instance methods of the DelegateClass class" do
m = @klass.instance_method(:extra_protected)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :baz
end
it "returns a method object for private instance methods of the DelegateClass class" do
m = @klass.instance_method(:extra_private)
- m.should be_an_instance_of(UnboundMethod)
+ m.should.instance_of?(UnboundMethod)
m.bind(@obj).call.should == :bar
end
it "raises a NameError for an invalid method name" do
-> {
@klass.instance_method(:invalid_and_silly_method_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb
index 6012ff72de..586be56cae 100644
--- a/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/instance_methods_spec.rb
@@ -7,20 +7,20 @@ describe "DelegateClass.instance_methods" do
end
it "includes all public methods of the delegated class" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "includes all protected methods of the delegated class" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes instance methods of the DelegateClass class" do
- @methods.should include :extra
- @methods.should include :extra_protected
+ @methods.should.include? :extra
+ @methods.should.include? :extra_protected
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb
index 06b2115cc5..18ca2a4c88 100644
--- a/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/private_instance_methods_spec.rb
@@ -7,17 +7,17 @@ describe "DelegateClass.private_instance_methods" do
end
it "does not include any instance methods of the delegated class" do
- @methods.should_not include :pub
- @methods.should_not include :prot
- @methods.should_not include :priv # since these are not forwarded...
+ @methods.should_not.include? :pub
+ @methods.should_not.include? :prot
+ @methods.should_not.include? :priv # since these are not forwarded...
end
it "includes private instance methods of the DelegateClass class" do
- @methods.should include :extra_private
+ @methods.should.include? :extra_private
end
it "does not include public or protected instance methods of the DelegateClass class" do
- @methods.should_not include :extra
- @methods.should_not include :extra_protected
+ @methods.should_not.include? :extra
+ @methods.should_not.include? :extra_protected
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb
index ac6659ec1e..d540b45065 100644
--- a/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/protected_instance_methods_spec.rb
@@ -7,23 +7,23 @@ describe "DelegateClass.protected_instance_methods" do
end
it "does not include public methods of the delegated class" do
- @methods.should_not include :pub
+ @methods.should_not.include? :pub
end
it "includes the protected methods of the delegated class" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes protected instance methods of the DelegateClass class" do
- @methods.should include :extra_protected
+ @methods.should.include? :extra_protected
end
it "does not include public instance methods of the DelegateClass class" do
- @methods.should_not include :extra
+ @methods.should_not.include? :extra
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb b/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb
index 6c0d9bcab1..124b92de82 100644
--- a/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/public_instance_methods_spec.rb
@@ -7,19 +7,19 @@ describe "DelegateClass.public_instance_methods" do
end
it "includes all public methods of the delegated class" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "does not include the protected methods of the delegated class" do
- @methods.should_not include :prot
+ @methods.should_not.include? :prot
end
it "includes public instance methods of the DelegateClass class" do
- @methods.should include :extra
+ @methods.should.include? :extra
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegator/eql_spec.rb b/spec/ruby/library/delegate/delegator/eql_spec.rb
index 34f56f44c9..b302bb7016 100644
--- a/spec/ruby/library/delegate/delegator/eql_spec.rb
+++ b/spec/ruby/library/delegate/delegator/eql_spec.rb
@@ -6,14 +6,14 @@ describe "Delegator#eql?" do
base = mock('base')
delegator = DelegateSpecs::Delegator.new(base)
- delegator.eql?(delegator).should be_true
+ delegator.eql?(delegator).should == true
end
it "returns true when compared with the inner object" do
base = mock('base')
delegator = DelegateSpecs::Delegator.new(base)
- delegator.eql?(base).should be_true
+ delegator.eql?(base).should == true
end
it "returns false when compared with the delegator with other object" do
@@ -22,7 +22,7 @@ describe "Delegator#eql?" do
delegator0 = DelegateSpecs::Delegator.new(base)
delegator1 = DelegateSpecs::Delegator.new(other)
- delegator0.eql?(delegator1).should be_false
+ delegator0.eql?(delegator1).should == false
end
it "returns false when compared with the other object" do
@@ -30,6 +30,6 @@ describe "Delegator#eql?" do
other = mock('other')
delegator = DelegateSpecs::Delegator.new(base)
- delegator.eql?(other).should be_false
+ delegator.eql?(other).should == false
end
end
diff --git a/spec/ruby/library/delegate/delegator/equal_spec.rb b/spec/ruby/library/delegate/delegator/equal_spec.rb
index c8711c74b5..97aabebabe 100644
--- a/spec/ruby/library/delegate/delegator/equal_spec.rb
+++ b/spec/ruby/library/delegate/delegator/equal_spec.rb
@@ -6,8 +6,8 @@ describe "Delegator#equal?" do
obj = mock('base')
delegator = DelegateSpecs::Delegator.new(obj)
obj.should_not_receive(:equal?)
- delegator.equal?(obj).should be_false
- delegator.equal?(nil).should be_false
- delegator.equal?(delegator).should be_true
+ delegator.equal?(obj).should == false
+ delegator.equal?(nil).should == false
+ delegator.equal?(delegator).should == true
end
end
diff --git a/spec/ruby/library/delegate/delegator/equal_value_spec.rb b/spec/ruby/library/delegate/delegator/equal_value_spec.rb
index 0c967d5f94..d70aad1e03 100644
--- a/spec/ruby/library/delegate/delegator/equal_value_spec.rb
+++ b/spec/ruby/library/delegate/delegator/equal_value_spec.rb
@@ -9,16 +9,16 @@ describe "Delegator#==" do
it "is not delegated when passed self" do
@base.should_not_receive(:==)
- (@delegator == @delegator).should be_true
+ (@delegator == @delegator).should == true
end
it "is delegated when passed the delegated object" do
@base.should_receive(:==).and_return(false)
- (@delegator == @base).should be_false
+ (@delegator == @base).should == false
end
it "is delegated in general" do
@base.should_receive(:==).and_return(true)
- (@delegator == 42).should be_true
+ (@delegator == 42).should == true
end
end
diff --git a/spec/ruby/library/delegate/delegator/frozen_spec.rb b/spec/ruby/library/delegate/delegator/frozen_spec.rb
index b3145c54b1..ad87dc8bdf 100644
--- a/spec/ruby/library/delegate/delegator/frozen_spec.rb
+++ b/spec/ruby/library/delegate/delegator/frozen_spec.rb
@@ -10,30 +10,30 @@ describe "Delegator when frozen" do
it "is still readable" do
@delegate.should == [42, :hello]
- @delegate.include?("bar").should be_false
+ @delegate.include?("bar").should == false
end
it "is frozen" do
- @delegate.frozen?.should be_true
+ @delegate.frozen?.should == true
end
it "is not writable" do
- ->{ @delegate[0] += 2 }.should raise_error( RuntimeError )
+ ->{ @delegate[0] += 2 }.should.raise( RuntimeError )
end
it "creates a frozen clone" do
- @delegate.clone.frozen?.should be_true
+ @delegate.clone.frozen?.should == true
end
it "creates an unfrozen dup" do
- @delegate.dup.frozen?.should be_false
+ @delegate.dup.frozen?.should == false
end
it "causes mutative calls to raise RuntimeError" do
- ->{ @delegate.__setobj__("hola!") }.should raise_error( RuntimeError )
+ ->{ @delegate.__setobj__("hola!") }.should.raise( RuntimeError )
end
it "returns false if only the delegated object is frozen" do
- DelegateSpecs::Delegator.new([1,2,3].freeze).frozen?.should be_false
+ DelegateSpecs::Delegator.new([1,2,3].freeze).frozen?.should == false
end
end
diff --git a/spec/ruby/library/delegate/delegator/marshal_spec.rb b/spec/ruby/library/delegate/delegator/marshal_spec.rb
index 6c75c8f573..2817ac7e0b 100644
--- a/spec/ruby/library/delegate/delegator/marshal_spec.rb
+++ b/spec/ruby/library/delegate/delegator/marshal_spec.rb
@@ -10,7 +10,7 @@ describe "SimpleDelegator" do
it "can be marshalled" do
m = Marshal.load(Marshal.dump(@delegate))
m.class.should == SimpleDelegator
- (m == @obj).should be_true
+ (m == @obj).should == true
end
it "can be marshalled with its instance variables intact" do
diff --git a/spec/ruby/library/delegate/delegator/method_spec.rb b/spec/ruby/library/delegate/delegator/method_spec.rb
index 81c8eea710..e41d3b4a53 100644
--- a/spec/ruby/library/delegate/delegator/method_spec.rb
+++ b/spec/ruby/library/delegate/delegator/method_spec.rb
@@ -9,7 +9,7 @@ describe "Delegator#method" do
it "returns a method object for public methods of the delegate object" do
m = @delegate.method(:pub)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :foo
end
@@ -18,7 +18,7 @@ describe "Delegator#method" do
-> {
@delegate.method(:prot)
}.should complain(/delegator does not forward private method #prot/)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "raises a NameError for a private methods of the delegate object" do
@@ -26,36 +26,36 @@ describe "Delegator#method" do
-> {
@delegate.method(:priv)
}.should complain(/delegator does not forward private method #priv/)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns a method object for public methods of the Delegator class" do
m = @delegate.method(:extra)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :cheese
end
it "returns a method object for protected methods of the Delegator class" do
m = @delegate.method(:extra_protected)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :baz
end
it "returns a method object for private methods of the Delegator class" do
m = @delegate.method(:extra_private)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :bar
end
it "raises a NameError for an invalid method name" do
-> {
@delegate.method(:invalid_and_silly_method_name)
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "returns a method that respond_to_missing?" do
m = @delegate.method(:pub_too)
- m.should be_an_instance_of(Method)
+ m.should.instance_of?(Method)
m.call.should == :pub_too
end
@@ -64,6 +64,6 @@ describe "Delegator#method" do
@delegate.__setobj__([1,2,3])
-> {
m.call
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/delegate/delegator/methods_spec.rb b/spec/ruby/library/delegate/delegator/methods_spec.rb
index b9942bd230..928f63f21d 100644
--- a/spec/ruby/library/delegate/delegator/methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/methods_spec.rb
@@ -14,24 +14,24 @@ describe "Delegator#methods" do
end
it "returns singleton methods when passed false" do
- @delegate.methods(false).should include(:singleton_method)
+ @delegate.methods(false).should.include?(:singleton_method)
end
it "includes all public methods of the delegate object" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "includes all protected methods of the delegate object" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes instance methods of the Delegator class" do
- @methods.should include :extra
- @methods.should include :extra_protected
+ @methods.should.include? :extra
+ @methods.should.include? :extra_protected
end
it "does not include private methods" do
- @methods.should_not include :priv
- @methods.should_not include :extra_private
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegator/not_equal_spec.rb b/spec/ruby/library/delegate/delegator/not_equal_spec.rb
index 6f2df21715..7fd234a671 100644
--- a/spec/ruby/library/delegate/delegator/not_equal_spec.rb
+++ b/spec/ruby/library/delegate/delegator/not_equal_spec.rb
@@ -9,16 +9,16 @@ describe "Delegator#!=" do
it "is not delegated when passed self" do
@base.should_not_receive(:"!=")
- (@delegator != @delegator).should be_false
+ (@delegator != @delegator).should == false
end
it "is delegated when passed the delegated object" do
@base.should_receive(:"!=").and_return(true)
- (@delegator != @base).should be_true
+ (@delegator != @base).should == true
end
it "is delegated in general" do
@base.should_receive(:"!=").and_return(false)
- (@delegator != 42).should be_false
+ (@delegator != 42).should == false
end
end
diff --git a/spec/ruby/library/delegate/delegator/private_methods_spec.rb b/spec/ruby/library/delegate/delegator/private_methods_spec.rb
index 7724b8d413..5615ed0668 100644
--- a/spec/ruby/library/delegate/delegator/private_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/private_methods_spec.rb
@@ -9,12 +9,12 @@ describe "Delegator#private_methods" do
end
it "does not include any method of the delegate object" do # since delegates does not forward private calls
- @methods.should_not include :priv
- @methods.should_not include :prot
- @methods.should_not include :pub
+ @methods.should_not.include? :priv
+ @methods.should_not.include? :prot
+ @methods.should_not.include? :pub
end
it "includes all private instance methods of the Delegate class" do
- @methods.should include :extra_private
+ @methods.should.include? :extra_private
end
end
diff --git a/spec/ruby/library/delegate/delegator/protected_methods_spec.rb b/spec/ruby/library/delegate/delegator/protected_methods_spec.rb
index fd7874fb21..3ee999fdac 100644
--- a/spec/ruby/library/delegate/delegator/protected_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/protected_methods_spec.rb
@@ -9,10 +9,10 @@ describe "Delegator#protected_methods" do
end
it "includes protected methods of the delegate object" do
- @methods.should include :prot
+ @methods.should.include? :prot
end
it "includes protected instance methods of the Delegator class" do
- @methods.should include :extra_protected
+ @methods.should.include? :extra_protected
end
end
diff --git a/spec/ruby/library/delegate/delegator/public_methods_spec.rb b/spec/ruby/library/delegate/delegator/public_methods_spec.rb
index 18da16a613..8cf6621e2d 100644
--- a/spec/ruby/library/delegate/delegator/public_methods_spec.rb
+++ b/spec/ruby/library/delegate/delegator/public_methods_spec.rb
@@ -9,10 +9,10 @@ describe "Delegator#public_methods" do
end
it "includes public methods of the delegate object" do
- @methods.should include :pub
+ @methods.should.include? :pub
end
it "includes public instance methods of the Delegator class" do
- @methods.should include :extra
+ @methods.should.include? :extra
end
end
diff --git a/spec/ruby/library/delegate/delegator/send_spec.rb b/spec/ruby/library/delegate/delegator/send_spec.rb
index 3022c2ce91..cc18a2794b 100644
--- a/spec/ruby/library/delegate/delegator/send_spec.rb
+++ b/spec/ruby/library/delegate/delegator/send_spec.rb
@@ -12,15 +12,15 @@ describe "SimpleDelegator.new" do
end
it "forwards protected method calls" do
- ->{ @delegate.prot }.should raise_error( NoMethodError )
+ ->{ @delegate.prot }.should.raise( NoMethodError )
end
it "doesn't forward private method calls" do
- ->{ @delegate.priv }.should raise_error( NoMethodError )
+ ->{ @delegate.priv }.should.raise( NoMethodError )
end
it "doesn't forward private method calls even via send or __send__" do
- ->{ @delegate.send(:priv, 42) }.should raise_error( NoMethodError )
- ->{ @delegate.__send__(:priv, 42) }.should raise_error( NoMethodError )
+ ->{ @delegate.send(:priv, 42) }.should.raise( NoMethodError )
+ ->{ @delegate.__send__(:priv, 42) }.should.raise( NoMethodError )
end
end
diff --git a/spec/ruby/library/delegate/delegator/tap_spec.rb b/spec/ruby/library/delegate/delegator/tap_spec.rb
index 34a88fa1d5..916e4a37fe 100644
--- a/spec/ruby/library/delegate/delegator/tap_spec.rb
+++ b/spec/ruby/library/delegate/delegator/tap_spec.rb
@@ -11,6 +11,6 @@ describe "Delegator#tap" do
yielded << x
end
yielded.size.should == 1
- yielded[0].equal?(delegator).should be_true
+ yielded[0].equal?(delegator).should == true
end
end
diff --git a/spec/ruby/library/digest/bubblebabble_spec.rb b/spec/ruby/library/digest/bubblebabble_spec.rb
index bbc11ceec5..44a9bf0e26 100644
--- a/spec/ruby/library/digest/bubblebabble_spec.rb
+++ b/spec/ruby/library/digest/bubblebabble_spec.rb
@@ -3,7 +3,7 @@ require 'digest/bubblebabble'
describe "Digest.bubblebabble" do
it "returns a String" do
- Digest.bubblebabble('').should be_an_instance_of(String)
+ Digest.bubblebabble('').should.instance_of?(String)
end
it "returns a String in the Bubble Babble Binary Data Encoding format" do
@@ -20,10 +20,10 @@ describe "Digest.bubblebabble" do
end
it "raises a TypeError when passed nil" do
- -> { Digest.bubblebabble(nil) }.should raise_error(TypeError)
+ -> { Digest.bubblebabble(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { Digest.bubblebabble(9001) }.should raise_error(TypeError)
+ -> { Digest.bubblebabble(9001) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/hexencode_spec.rb b/spec/ruby/library/digest/hexencode_spec.rb
index 4b6db6eaff..3359303d15 100644
--- a/spec/ruby/library/digest/hexencode_spec.rb
+++ b/spec/ruby/library/digest/hexencode_spec.rb
@@ -22,10 +22,10 @@ describe "Digest.hexencode" do
end
it "raises a TypeError when passed nil" do
- -> { Digest.hexencode(nil) }.should raise_error(TypeError)
+ -> { Digest.hexencode(nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed an Integer" do
- -> { Digest.hexencode(9001) }.should raise_error(TypeError)
+ -> { Digest.hexencode(9001) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/instance/shared/update.rb b/spec/ruby/library/digest/instance/shared/update.rb
index 17779e54a4..e064a90087 100644
--- a/spec/ruby/library/digest/instance/shared/update.rb
+++ b/spec/ruby/library/digest/instance/shared/update.rb
@@ -3,6 +3,6 @@ describe :digest_instance_update, shared: true do
c = Class.new do
include Digest::Instance
end
- -> { c.new.send(@method, "test") }.should raise_error(RuntimeError)
+ -> { c.new.send(@method, "test") }.should.raise(RuntimeError)
end
end
diff --git a/spec/ruby/library/digest/md5/file_spec.rb b/spec/ruby/library/digest/md5/file_spec.rb
index 0c8d12cbc9..9a78a8c055 100644
--- a/spec/ruby/library/digest/md5/file_spec.rb
+++ b/spec/ruby/library/digest/md5/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::MD5.file" do
end
it "returns a Digest::MD5 object" do
- Digest::MD5.file(@file).should be_kind_of(Digest::MD5)
+ Digest::MD5.file(@file).should.is_a?(Digest::MD5)
end
it "returns a Digest::MD5 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::MD5.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::MD5.file(obj)
- result.should be_kind_of(Digest::MD5)
+ result.should.is_a?(Digest::MD5)
result.digest.should == MD5Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::MD5.file" do
it_behaves_like :file_read_directory, :file, Digest::MD5
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::MD5.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::MD5.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::MD5.file(nil) }.should raise_error(TypeError)
+ -> { Digest::MD5.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/md5/shared/constants.rb b/spec/ruby/library/digest/md5/shared/constants.rb
index e807b96f9f..664dd18e9c 100644
--- a/spec/ruby/library/digest/md5/shared/constants.rb
+++ b/spec/ruby/library/digest/md5/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require 'digest/md5'
module MD5Constants
diff --git a/spec/ruby/library/digest/sha1/file_spec.rb b/spec/ruby/library/digest/sha1/file_spec.rb
index 9c15f5b02f..d36e560e21 100644
--- a/spec/ruby/library/digest/sha1/file_spec.rb
+++ b/spec/ruby/library/digest/sha1/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA1.file" do
end
it "returns a Digest::SHA1 object" do
- Digest::SHA1.file(@file).should be_kind_of(Digest::SHA1)
+ Digest::SHA1.file(@file).should.is_a?(Digest::SHA1)
end
it "returns a Digest::SHA1 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::SHA1.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA1.file(obj)
- result.should be_kind_of(Digest::SHA1)
+ result.should.is_a?(Digest::SHA1)
result.digest.should == SHA1Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::SHA1.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA1
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA1.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA1.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA1.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA1.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha1/shared/constants.rb b/spec/ruby/library/digest/sha1/shared/constants.rb
index 169438747f..d77c05a968 100644
--- a/spec/ruby/library/digest/sha1/shared/constants.rb
+++ b/spec/ruby/library/digest/sha1/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require 'digest/sha1'
diff --git a/spec/ruby/library/digest/sha256/file_spec.rb b/spec/ruby/library/digest/sha256/file_spec.rb
index 8cbc5a2755..d67a9ebcd6 100644
--- a/spec/ruby/library/digest/sha256/file_spec.rb
+++ b/spec/ruby/library/digest/sha256/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA256.file" do
end
it "returns a Digest::SHA256 object" do
- Digest::SHA256.file(@file).should be_kind_of(Digest::SHA256)
+ Digest::SHA256.file(@file).should.is_a?(Digest::SHA256)
end
it "returns a Digest::SHA256 object with the correct digest" do
@@ -30,7 +30,7 @@ describe "Digest::SHA256.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA256.file(obj)
- result.should be_kind_of(Digest::SHA256)
+ result.should.is_a?(Digest::SHA256)
result.digest.should == SHA256Constants::Digest
end
end
@@ -38,10 +38,10 @@ describe "Digest::SHA256.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA256
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA256.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA256.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA256.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA256.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha256/shared/constants.rb b/spec/ruby/library/digest/sha256/shared/constants.rb
index 351679f344..afe8f11426 100644
--- a/spec/ruby/library/digest/sha256/shared/constants.rb
+++ b/spec/ruby/library/digest/sha256/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require 'digest/sha2'
diff --git a/spec/ruby/library/digest/sha384/file_spec.rb b/spec/ruby/library/digest/sha384/file_spec.rb
index 8556f10175..3726ad4423 100644
--- a/spec/ruby/library/digest/sha384/file_spec.rb
+++ b/spec/ruby/library/digest/sha384/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA384.file" do
end
it "returns a Digest::SHA384 object" do
- Digest::SHA384.file(@file).should be_kind_of(Digest::SHA384)
+ Digest::SHA384.file(@file).should.is_a?(Digest::SHA384)
end
it "returns a Digest::SHA384 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::SHA384.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA384.file(obj)
- result.should be_kind_of(Digest::SHA384)
+ result.should.is_a?(Digest::SHA384)
result.digest.should == SHA384Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::SHA384.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA384
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA384.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA384.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA384.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA384.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha384/shared/constants.rb b/spec/ruby/library/digest/sha384/shared/constants.rb
index 2050f03f2b..a78d571d26 100644
--- a/spec/ruby/library/digest/sha384/shared/constants.rb
+++ b/spec/ruby/library/digest/sha384/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require 'digest/sha2'
diff --git a/spec/ruby/library/digest/sha512/file_spec.rb b/spec/ruby/library/digest/sha512/file_spec.rb
index 781ec781e5..78d6d3d4f3 100644
--- a/spec/ruby/library/digest/sha512/file_spec.rb
+++ b/spec/ruby/library/digest/sha512/file_spec.rb
@@ -15,7 +15,7 @@ describe "Digest::SHA512.file" do
end
it "returns a Digest::SHA512 object" do
- Digest::SHA512.file(@file).should be_kind_of(Digest::SHA512)
+ Digest::SHA512.file(@file).should.is_a?(Digest::SHA512)
end
it "returns a Digest::SHA512 object with the correct digest" do
@@ -26,7 +26,7 @@ describe "Digest::SHA512.file" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(@file)
result = Digest::SHA512.file(obj)
- result.should be_kind_of(Digest::SHA512)
+ result.should.is_a?(Digest::SHA512)
result.digest.should == SHA512Constants::Digest
end
end
@@ -34,10 +34,10 @@ describe "Digest::SHA512.file" do
it_behaves_like :file_read_directory, :file, Digest::SHA512
it "raises a Errno::ENOENT when passed a path that does not exist" do
- -> { Digest::SHA512.file("") }.should raise_error(Errno::ENOENT)
+ -> { Digest::SHA512.file("") }.should.raise(Errno::ENOENT)
end
it "raises a TypeError when passed nil" do
- -> { Digest::SHA512.file(nil) }.should raise_error(TypeError)
+ -> { Digest::SHA512.file(nil) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/digest/sha512/shared/constants.rb b/spec/ruby/library/digest/sha512/shared/constants.rb
index 2765a1ec16..91787381ee 100644
--- a/spec/ruby/library/digest/sha512/shared/constants.rb
+++ b/spec/ruby/library/digest/sha512/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require 'digest/sha2'
diff --git a/spec/ruby/library/erb/filename_spec.rb b/spec/ruby/library/erb/filename_spec.rb
index 8ecaed7343..bbd2233bb3 100644
--- a/spec/ruby/library/erb/filename_spec.rb
+++ b/spec/ruby/library/erb/filename_spec.rb
@@ -13,7 +13,7 @@ describe "ERB#filename" do
@ex = e
raise e
end
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
expected = filename
@ex.message =~ /^(.*?):(\d+): /
@@ -30,7 +30,7 @@ describe "ERB#filename" do
@ex = e
raise e
end
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
expected = '(erb)'
@ex.message =~ /^(.*?):(\d+): /
diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb
index ec1be5c234..35ac0dfdfe 100644
--- a/spec/ruby/library/erb/new_spec.rb
+++ b/spec/ruby/library/erb/new_spec.rb
@@ -83,7 +83,7 @@ END
-> {
ERBSpecs.new_erb(input, trim_mode: '-').result
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
it "regards lines starting with '%' as '<% ... %>' when trim_mode is '%'" do
@@ -136,20 +136,22 @@ END
it "forget local variables defined previous one" do
ERB.new(@eruby_str).result
- ->{ ERB.new("<%= list %>").result }.should raise_error(NameError)
+ ->{ ERB.new("<%= list %>").result }.should.raise(NameError)
end
- describe "warning about arguments" do
- it "warns when passed safe_level and later arguments" do
- -> {
- ERB.new(@eruby_str, nil, '%')
- }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
- end
-
- it "does not warn when passed arguments as keyword argument" do
- -> {
- ERB.new(@eruby_str, trim_mode: '%')
- }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ version_is ERB.const_get(:VERSION, false), ""..."6.0.0" do
+ describe "warning about arguments" do
+ it "warns when passed safe_level and later arguments" do
+ -> {
+ ERB.new(@eruby_str, nil, '%')
+ }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ end
+
+ it "does not warn when passed arguments as keyword argument" do
+ -> {
+ ERB.new(@eruby_str, trim_mode: '%')
+ }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ end
end
end
end
diff --git a/spec/ruby/library/erb/result_spec.rb b/spec/ruby/library/erb/result_spec.rb
index a29c1ccedb..84333031ec 100644
--- a/spec/ruby/library/erb/result_spec.rb
+++ b/spec/ruby/library/erb/result_spec.rb
@@ -43,7 +43,7 @@ END
input = "<%=h '<>' %>"
-> {
ERB.new(input).result()
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
@@ -81,6 +81,6 @@ END
-> {
myerb2.new.main2()
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/erb/run_spec.rb b/spec/ruby/library/erb/run_spec.rb
index 602e53ab38..d81d534087 100644
--- a/spec/ruby/library/erb/run_spec.rb
+++ b/spec/ruby/library/erb/run_spec.rb
@@ -54,7 +54,7 @@ END
input = "<%=h '<>' %>"
-> {
_steal_stdout { ERB.new(input).run() }
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
it "is able to h() or u() if ERB::Util is included" do
@@ -91,6 +91,6 @@ END
-> {
_steal_stdout { myerb2.new.main2() }
- }.should raise_error(NameError)
+ }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/etc/confstr_spec.rb b/spec/ruby/library/etc/confstr_spec.rb
index 5b43461150..786cb16407 100644
--- a/spec/ruby/library/etc/confstr_spec.rb
+++ b/spec/ruby/library/etc/confstr_spec.rb
@@ -4,11 +4,11 @@ require 'etc'
platform_is_not :windows, :android do
describe "Etc.confstr" do
it "returns a String for Etc::CS_PATH" do
- Etc.confstr(Etc::CS_PATH).should be_an_instance_of(String)
+ Etc.confstr(Etc::CS_PATH).should.instance_of?(String)
end
it "raises Errno::EINVAL for unknown configuration variables" do
- -> { Etc.confstr(-1) }.should raise_error(Errno::EINVAL)
+ -> { Etc.confstr(-1) }.should.raise(Errno::EINVAL)
end
end
end
diff --git a/spec/ruby/library/etc/getgrgid_spec.rb b/spec/ruby/library/etc/getgrgid_spec.rb
index 14da5e041d..472d4c82c8 100644
--- a/spec/ruby/library/etc/getgrgid_spec.rb
+++ b/spec/ruby/library/etc/getgrgid_spec.rb
@@ -34,7 +34,7 @@ platform_is_not :windows do
it "returns the Etc::Group for a given gid if it exists" do
grp = Etc.getgrgid(@gid)
- grp.should be_kind_of(Etc::Group)
+ grp.should.is_a?(Etc::Group)
grp.gid.should == @gid
grp.name.should == @name
end
@@ -47,12 +47,12 @@ platform_is_not :windows do
end
it "raises if the group does not exist" do
- -> { Etc.getgrgid(9876)}.should raise_error(ArgumentError)
+ -> { Etc.getgrgid(9876)}.should.raise(ArgumentError)
end
it "raises a TypeError if not passed an Integer" do
- -> { Etc.getgrgid("foo") }.should raise_error(TypeError)
- -> { Etc.getgrgid(nil) }.should raise_error(TypeError)
+ -> { Etc.getgrgid("foo") }.should.raise(TypeError)
+ -> { Etc.getgrgid(nil) }.should.raise(TypeError)
end
it "can be called safely by multiple threads" do
diff --git a/spec/ruby/library/etc/getgrnam_spec.rb b/spec/ruby/library/etc/getgrnam_spec.rb
index fa49f15349..325ea7b297 100644
--- a/spec/ruby/library/etc/getgrnam_spec.rb
+++ b/spec/ruby/library/etc/getgrnam_spec.rb
@@ -24,7 +24,7 @@ platform_is_not :windows, :android do
-> {
Etc.getgrnam(123)
Etc.getgrnam(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/etc/getlogin_spec.rb b/spec/ruby/library/etc/getlogin_spec.rb
index 7a4fd79ae2..2bc598c0af 100644
--- a/spec/ruby/library/etc/getlogin_spec.rb
+++ b/spec/ruby/library/etc/getlogin_spec.rb
@@ -14,7 +14,7 @@ describe "Etc.getlogin" do
if ENV['TRAVIS'] and platform_is(:darwin)
# See https://travis-ci.org/ruby/spec/jobs/285967744
# and https://travis-ci.org/ruby/spec/jobs/285999602
- Etc.getlogin.should be_an_instance_of(String)
+ Etc.getlogin.should.instance_of?(String)
else
# Etc.getlogin returns the same result of logname(2)
# if it returns non NULL
@@ -28,7 +28,7 @@ describe "Etc.getlogin" do
else
# Etc.getlogin may return nil if the login name is not set
# because of chroot or sudo or something.
- Etc.getlogin.should be_nil
+ Etc.getlogin.should == nil
getlogin_null = true
end
ensure
diff --git a/spec/ruby/library/etc/getpwnam_spec.rb b/spec/ruby/library/etc/getpwnam_spec.rb
index 3f4416aa9d..a0b3c9e1fe 100644
--- a/spec/ruby/library/etc/getpwnam_spec.rb
+++ b/spec/ruby/library/etc/getpwnam_spec.rb
@@ -22,7 +22,7 @@ platform_is_not :windows do
-> {
Etc.getpwnam(123)
Etc.getpwnam(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/etc/getpwuid_spec.rb b/spec/ruby/library/etc/getpwuid_spec.rb
index 5b98f0f8d9..3e35dfe6d5 100644
--- a/spec/ruby/library/etc/getpwuid_spec.rb
+++ b/spec/ruby/library/etc/getpwuid_spec.rb
@@ -30,7 +30,7 @@ platform_is_not :windows do
-> {
Etc.getpwuid("foo")
Etc.getpwuid(nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/etc/group_spec.rb b/spec/ruby/library/etc/group_spec.rb
index fda808eec9..d7addbbec1 100644
--- a/spec/ruby/library/etc/group_spec.rb
+++ b/spec/ruby/library/etc/group_spec.rb
@@ -9,7 +9,7 @@ describe "Etc.group" do
it "returns a Etc::Group struct" do
group = Etc.group
begin
- group.should be_an_instance_of(Etc::Group)
+ group.should.instance_of?(Etc::Group)
ensure
Etc.endgrent
end
@@ -21,7 +21,7 @@ describe "Etc.group" do
Etc.group do | group2 |
end
end
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
end
diff --git a/spec/ruby/library/etc/nprocessors_spec.rb b/spec/ruby/library/etc/nprocessors_spec.rb
index ec7ffc81da..482719dde0 100644
--- a/spec/ruby/library/etc/nprocessors_spec.rb
+++ b/spec/ruby/library/etc/nprocessors_spec.rb
@@ -3,7 +3,7 @@ require 'etc'
describe "Etc.nprocessors" do
it "returns the number of online processors" do
- Etc.nprocessors.should be_kind_of(Integer)
+ Etc.nprocessors.should.is_a?(Integer)
Etc.nprocessors.should >= 1
end
end
diff --git a/spec/ruby/library/etc/passwd_spec.rb b/spec/ruby/library/etc/passwd_spec.rb
index 7157fd3f2e..0602b7e10b 100644
--- a/spec/ruby/library/etc/passwd_spec.rb
+++ b/spec/ruby/library/etc/passwd_spec.rb
@@ -6,7 +6,7 @@ platform_is_not :windows do
it "returns a Etc::Passwd struct" do
passwd = Etc.passwd
begin
- passwd.should be_an_instance_of(Etc::Passwd)
+ passwd.should.instance_of?(Etc::Passwd)
ensure
Etc.endpwent
end
diff --git a/spec/ruby/library/etc/sysconf_spec.rb b/spec/ruby/library/etc/sysconf_spec.rb
index 1f2c7a770f..81ce1ca258 100644
--- a/spec/ruby/library/etc/sysconf_spec.rb
+++ b/spec/ruby/library/etc/sysconf_spec.rb
@@ -14,7 +14,7 @@ platform_is_not :windows do
if value.nil?
value.should == nil
else
- value.should be_kind_of(Integer)
+ value.should.is_a?(Integer)
end
end
end
diff --git a/spec/ruby/library/etc/sysconfdir_spec.rb b/spec/ruby/library/etc/sysconfdir_spec.rb
index 8538faa65b..eb2d6b649a 100644
--- a/spec/ruby/library/etc/sysconfdir_spec.rb
+++ b/spec/ruby/library/etc/sysconfdir_spec.rb
@@ -3,6 +3,6 @@ require 'etc'
describe "Etc.sysconfdir" do
it "returns a String" do
- Etc.sysconfdir.should be_an_instance_of(String)
+ Etc.sysconfdir.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/etc/systmpdir_spec.rb b/spec/ruby/library/etc/systmpdir_spec.rb
index 5b007aa9f9..ed34cb43fc 100644
--- a/spec/ruby/library/etc/systmpdir_spec.rb
+++ b/spec/ruby/library/etc/systmpdir_spec.rb
@@ -3,6 +3,6 @@ require 'etc'
describe "Etc.systmpdir" do
it "returns a String" do
- Etc.systmpdir.should be_an_instance_of(String)
+ Etc.systmpdir.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/etc/uname_spec.rb b/spec/ruby/library/etc/uname_spec.rb
index a42558f593..1c5fe2a741 100644
--- a/spec/ruby/library/etc/uname_spec.rb
+++ b/spec/ruby/library/etc/uname_spec.rb
@@ -4,7 +4,7 @@ require 'etc'
describe "Etc.uname" do
it "returns a Hash with the documented keys" do
uname = Etc.uname
- uname.should be_kind_of(Hash)
+ uname.should.is_a?(Hash)
uname.should.key?(:sysname)
uname.should.key?(:nodename)
uname.should.key?(:release)
diff --git a/spec/ruby/library/expect/expect_spec.rb b/spec/ruby/library/expect/expect_spec.rb
index 76ea3d5451..ba705c5535 100644
--- a/spec/ruby/library/expect/expect_spec.rb
+++ b/spec/ruby/library/expect/expect_spec.rb
@@ -40,14 +40,14 @@ platform_is_not :windows do
-> {
@read.expect("hello")
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "returns nil if eof is hit" do
@write << "pro"
@write.close
- @read.expect("prompt").should be_nil
+ @read.expect("prompt").should == nil
end
it "yields the result if a block is given" do
diff --git a/spec/ruby/library/fiddle/handle/initialize_spec.rb b/spec/ruby/library/fiddle/handle/initialize_spec.rb
index 51c2470efd..84c809a727 100644
--- a/spec/ruby/library/fiddle/handle/initialize_spec.rb
+++ b/spec/ruby/library/fiddle/handle/initialize_spec.rb
@@ -5,6 +5,6 @@ describe "Fiddle::Handle#initialize" do
it "raises Fiddle::DLError if the library cannot be found" do
-> {
Fiddle::Handle.new("doesnotexist.doesnotexist")
- }.should raise_error(Fiddle::DLError)
+ }.should.raise(Fiddle::DLError)
end
end
diff --git a/spec/ruby/library/find/find_spec.rb b/spec/ruby/library/find/find_spec.rb
index 7cd76fa01b..c4ccfa76fd 100644
--- a/spec/ruby/library/find/find_spec.rb
+++ b/spec/ruby/library/find/find_spec.rb
@@ -13,7 +13,7 @@ describe "Find.find" do
describe "when called without a block" do
it "returns an Enumerator" do
- Find.find(FindDirSpecs.mock_dir).should be_an_instance_of(Enumerator)
+ Find.find(FindDirSpecs.mock_dir).should.instance_of?(Enumerator)
Find.find(FindDirSpecs.mock_dir).to_a.sort.should == FindDirSpecs.expected_paths
end
end
diff --git a/spec/ruby/library/getoptlong/error_message_spec.rb b/spec/ruby/library/getoptlong/error_message_spec.rb
index 1ed9419f6c..10435b1350 100644
--- a/spec/ruby/library/getoptlong/error_message_spec.rb
+++ b/spec/ruby/library/getoptlong/error_message_spec.rb
@@ -14,7 +14,7 @@ describe "GetoptLong#error_message" do
opts.get
-> {
opts.ordering = GetoptLong::PERMUTE
- }.should raise_error(ArgumentError) { |e|
+ }.should.raise(ArgumentError) { |e|
e.message.should == "argument error"
opts.error_message.should == "argument error"
}
diff --git a/spec/ruby/library/getoptlong/ordering_spec.rb b/spec/ruby/library/getoptlong/ordering_spec.rb
index 695d1cafa7..60ce73afaa 100644
--- a/spec/ruby/library/getoptlong/ordering_spec.rb
+++ b/spec/ruby/library/getoptlong/ordering_spec.rb
@@ -11,7 +11,7 @@ describe "GetoptLong#ordering=" do
-> {
opts.ordering = GetoptLong::PERMUTE
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -20,7 +20,7 @@ describe "GetoptLong#ordering=" do
-> {
opts.ordering = 12345
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not allow changing ordering to PERMUTE if ENV['POSIXLY_CORRECT'] is set" do
diff --git a/spec/ruby/library/getoptlong/set_options_spec.rb b/spec/ruby/library/getoptlong/set_options_spec.rb
index 36b9c579c4..f60dcc87a3 100644
--- a/spec/ruby/library/getoptlong/set_options_spec.rb
+++ b/spec/ruby/library/getoptlong/set_options_spec.rb
@@ -41,7 +41,7 @@ describe "GetoptLong#set_options" do
argv [] do
-> {
@opts.set_options(["--size", GetoptLong::NO_ARGUMENT, GetoptLong::REQUIRED_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -50,7 +50,7 @@ describe "GetoptLong#set_options" do
@opts.get
-> {
@opts.set_options()
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
end
@@ -58,7 +58,7 @@ describe "GetoptLong#set_options" do
argv [] do
-> {
@opts.set_options(["--size"])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -68,7 +68,7 @@ describe "GetoptLong#set_options" do
@opts.set_options(
["--size", GetoptLong::REQUIRED_ARGUMENT],
"test")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -78,13 +78,13 @@ describe "GetoptLong#set_options" do
@opts.set_options(
["--size", GetoptLong::NO_ARGUMENT],
["--size", GetoptLong::OPTIONAL_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@opts.set_options(
["--size", GetoptLong::NO_ARGUMENT],
["-s", "--size", GetoptLong::OPTIONAL_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -92,7 +92,7 @@ describe "GetoptLong#set_options" do
argv [] do
-> {
@opts.set_options(["-size", GetoptLong::NO_ARGUMENT])
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/getoptlong/shared/get.rb b/spec/ruby/library/getoptlong/shared/get.rb
index f44cf583d2..8d24c4c255 100644
--- a/spec/ruby/library/getoptlong/shared/get.rb
+++ b/spec/ruby/library/getoptlong/shared/get.rb
@@ -49,7 +49,7 @@ describe :getoptlong_get, shared: true do
it "raises a if an argument was required, but none given" do
argv [ "--size" ] do
- -> { @opts.send(@method) }.should raise_error(GetoptLong::MissingArgument)
+ -> { @opts.send(@method) }.should.raise(GetoptLong::MissingArgument)
end
end
diff --git a/spec/ruby/library/io-wait/wait_readable_spec.rb b/spec/ruby/library/io-wait/wait_readable_spec.rb
index df25fdb931..d7473f029f 100644
--- a/spec/ruby/library/io-wait/wait_readable_spec.rb
+++ b/spec/ruby/library/io-wait/wait_readable_spec.rb
@@ -1,9 +1,5 @@
require_relative '../../spec_helper'
-ruby_version_is ''...'3.2' do
- require 'io/wait'
-end
-
describe "IO#wait_readable" do
before :each do
@io = File.new(__FILE__ )
diff --git a/spec/ruby/library/io-wait/wait_spec.rb b/spec/ruby/library/io-wait/wait_spec.rb
index 6ab41e9f08..1d784e7aa4 100644
--- a/spec/ruby/library/io-wait/wait_spec.rb
+++ b/spec/ruby/library/io-wait/wait_spec.rb
@@ -1,10 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../fixtures/io'
-ruby_version_is ''...'3.2' do
- require 'io/wait'
-end
-
describe "IO#wait" do
before :each do
@io = File.new(__FILE__ )
@@ -25,26 +21,13 @@ describe "IO#wait" do
end
context "[events, timeout] passed" do
- ruby_version_is ""..."3.2" do
- it "returns self when the READABLE event is ready during the timeout" do
- @w.write('data to read')
- @r.wait(IO::READABLE, 2).should.equal?(@r)
- end
-
- it "returns self when the WRITABLE event is ready during the timeout" do
- @w.wait(IO::WRITABLE, 0).should.equal?(@w)
- end
+ it "returns events mask when the READABLE event is ready during the timeout" do
+ @w.write('data to read')
+ @r.wait(IO::READABLE, 2).should == IO::READABLE
end
- ruby_version_is "3.2" do
- it "returns events mask when the READABLE event is ready during the timeout" do
- @w.write('data to read')
- @r.wait(IO::READABLE, 2).should == IO::READABLE
- end
-
- it "returns events mask when the WRITABLE event is ready during the timeout" do
- @w.wait(IO::WRITABLE, 0).should == IO::WRITABLE
- end
+ it "returns events mask when the WRITABLE event is ready during the timeout" do
+ @w.wait(IO::WRITABLE, 0).should == IO::WRITABLE
end
it "waits for the READABLE event to be ready" do
@@ -73,14 +56,12 @@ describe "IO#wait" do
it "raises IOError when io is closed (closed stream (IOError))" do
@io.close
- -> { @io.wait(IO::READABLE, 0) }.should raise_error(IOError, "closed stream")
+ -> { @io.wait(IO::READABLE, 0) }.should.raise(IOError, "closed stream")
end
- ruby_version_is "3.2" do
- it "raises ArgumentError when events is not positive" do
- -> { @w.wait(0, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
- -> { @w.wait(-1, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
- end
+ it "raises ArgumentError when events is not positive" do
+ -> { @w.wait(0, 0) }.should.raise(ArgumentError, "Events must be positive integer!")
+ -> { @w.wait(-1, 0) }.should.raise(ArgumentError, "Events must be positive integer!")
end
it "changes thread status to 'sleep' when waits for READABLE event" do
@@ -159,31 +140,23 @@ describe "IO#wait" do
@io.wait(0, :r, :w, :rw).should == @io
end
- # It works at least since 2.7 but by some reason may fail on 3.1
- ruby_version_is "3.2" do
- it "accepts timeout and mode in any order" do
- @io.wait(0, :r).should == @io
- @io.wait(:r, 0).should == @io
- @io.wait(:r, 0, :w).should == @io
- end
+ it "accepts timeout and mode in any order" do
+ @io.wait(0, :r).should == @io
+ @io.wait(:r, 0).should == @io
+ @io.wait(:r, 0, :w).should == @io
end
it "raises ArgumentError when passed wrong Symbol value as mode argument" do
- -> { @io.wait(0, :wrong) }.should raise_error(ArgumentError, "unsupported mode: wrong")
+ -> { @io.wait(0, :wrong) }.should.raise(ArgumentError, "unsupported mode: wrong")
end
- # It works since 3.0 but by some reason may fail on 3.1
- ruby_version_is "3.2" do
- it "raises ArgumentError when several Integer arguments passed" do
- -> { @w.wait(0, 10, :r) }.should raise_error(ArgumentError, "timeout given more than once")
- end
+ it "raises ArgumentError when several Integer arguments passed" do
+ -> { @w.wait(0, 10, :r) }.should.raise(ArgumentError, "timeout given more than once")
end
- ruby_version_is "3.2" do
- it "raises IOError when io is closed (closed stream (IOError))" do
- @io.close
- -> { @io.wait(0, :r) }.should raise_error(IOError, "closed stream")
- end
+ it "raises IOError when io is closed (closed stream (IOError))" do
+ @io.close
+ -> { @io.wait(0, :r) }.should.raise(IOError, "closed stream")
end
end
end
diff --git a/spec/ruby/library/io-wait/wait_writable_spec.rb b/spec/ruby/library/io-wait/wait_writable_spec.rb
index 8639dd717b..2017817caa 100644
--- a/spec/ruby/library/io-wait/wait_writable_spec.rb
+++ b/spec/ruby/library/io-wait/wait_writable_spec.rb
@@ -1,10 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../fixtures/io'
-ruby_version_is ''...'3.2' do
- require 'io/wait'
-end
-
describe "IO#wait_writable" do
it "waits for the IO to become writable with no timeout" do
STDOUT.wait_writable.should == STDOUT
diff --git a/spec/ruby/library/ipaddr/new_spec.rb b/spec/ruby/library/ipaddr/new_spec.rb
index 2c0f44acf2..7fba2b372e 100644
--- a/spec/ruby/library/ipaddr/new_spec.rb
+++ b/spec/ruby/library/ipaddr/new_spec.rb
@@ -3,9 +3,9 @@ require 'ipaddr'
describe "IPAddr#new" do
it "initializes IPAddr" do
- ->{ IPAddr.new("3FFE:505:ffff::/48") }.should_not raise_error
- ->{ IPAddr.new("0:0:0:1::") }.should_not raise_error
- ->{ IPAddr.new("2001:200:300::/48") }.should_not raise_error
+ ->{ IPAddr.new("3FFE:505:ffff::/48") }.should_not.raise
+ ->{ IPAddr.new("0:0:0:1::") }.should_not.raise
+ ->{ IPAddr.new("2001:200:300::/48") }.should_not.raise
end
it "initializes IPAddr ipv6 address with short notation" do
@@ -86,7 +86,7 @@ describe "IPAddr#new" do
].each { |args|
->{
IPAddr.new(*args)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
}
end
end
diff --git a/spec/ruby/library/ipaddr/operator_spec.rb b/spec/ruby/library/ipaddr/operator_spec.rb
index f90c56009c..3337d22300 100644
--- a/spec/ruby/library/ipaddr/operator_spec.rb
+++ b/spec/ruby/library/ipaddr/operator_spec.rb
@@ -66,17 +66,17 @@ describe "IPAddr Operator" do
end
it "checks whether an address is included in a range" do
- @a.should include(IPAddr.new("3ffe:505:2::"))
- @a.should include(IPAddr.new("3ffe:505:2::1"))
- @a.should_not include(IPAddr.new("3ffe:505:3::"))
+ @a.should.include?(IPAddr.new("3ffe:505:2::"))
+ @a.should.include?(IPAddr.new("3ffe:505:2::1"))
+ @a.should_not.include?(IPAddr.new("3ffe:505:3::"))
net1 = IPAddr.new("192.168.2.0/24")
- net1.should include(IPAddr.new("192.168.2.0"))
- net1.should include(IPAddr.new("192.168.2.255"))
- net1.should_not include(IPAddr.new("192.168.3.0"))
+ net1.should.include?(IPAddr.new("192.168.2.0"))
+ net1.should.include?(IPAddr.new("192.168.2.255"))
+ net1.should_not.include?(IPAddr.new("192.168.3.0"))
# test with integer parameter
int = (192 << 24) + (168 << 16) + (2 << 8) + 13
- net1.should include(int)
- net1.should_not include(int+255)
+ net1.should.include?(int)
+ net1.should_not.include?(int+255)
end
end
diff --git a/spec/ruby/library/ipaddr/reverse_spec.rb b/spec/ruby/library/ipaddr/reverse_spec.rb
index 6ebb343269..9bda60ca70 100644
--- a/spec/ruby/library/ipaddr/reverse_spec.rb
+++ b/spec/ruby/library/ipaddr/reverse_spec.rb
@@ -13,7 +13,7 @@ describe "IPAddr#ip6_arpa" do
IPAddr.new("3ffe:505:2::f").ip6_arpa.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa"
->{
IPAddr.new("192.168.2.1").ip6_arpa
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -22,6 +22,6 @@ describe "IPAddr#ip6_int" do
IPAddr.new("3ffe:505:2::f").ip6_int.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int"
->{
IPAddr.new("192.168.2.1").ip6_int
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/logger/device/new_spec.rb b/spec/ruby/library/logger/device/new_spec.rb
index 26a38c2b8c..c943e7fbe2 100644
--- a/spec/ruby/library/logger/device/new_spec.rb
+++ b/spec/ruby/library/logger/device/new_spec.rb
@@ -14,11 +14,11 @@ describe "Logger::LogDevice#new" do
it "creates a new log device" do
l = Logger::LogDevice.new(@log_file)
- l.dev.should be_kind_of(File)
+ l.dev.should.is_a?(File)
end
it "receives an IO object to log there as first argument" do
- @log_file.should be_kind_of(IO)
+ @log_file.should.is_a?(IO)
l = Logger::LogDevice.new(@log_file)
l.write("foo")
@log_file.rewind
@@ -33,7 +33,7 @@ describe "Logger::LogDevice#new" do
File.should.exist?(path)
File.open(path) do |f|
- f.readlines.should_not be_empty
+ f.readlines.should_not.empty?
end
rm_r path
@@ -42,6 +42,6 @@ describe "Logger::LogDevice#new" do
it "receives options via a hash as second argument" do
-> {
Logger::LogDevice.new(STDERR, shift_age: 8, shift_size: 10)
- }.should_not raise_error
+ }.should_not.raise
end
end
diff --git a/spec/ruby/library/logger/logger/add_spec.rb b/spec/ruby/library/logger/logger/add_spec.rb
index 3f709e18ba..98ac88f64f 100644
--- a/spec/ruby/library/logger/logger/add_spec.rb
+++ b/spec/ruby/library/logger/logger/add_spec.rb
@@ -56,7 +56,7 @@ describe "Logger#add" do
@logger.log(nil, "test", "TestApp") do
1+1
end
- }.should_not raise_error
+ }.should_not.raise
end
it "calls the block if message is nil" do
@@ -65,7 +65,7 @@ describe "Logger#add" do
@logger.log(nil, nil, "TestApp") do
temp = 1+1
end
- }.should_not raise_error
+ }.should_not.raise
temp.should == 2
end
@@ -75,7 +75,7 @@ describe "Logger#add" do
@logger.log(nil, "not nil", "TestApp") do
temp = 1+1
end
- }.should_not raise_error
+ }.should_not.raise
temp.should == 0
end
end
diff --git a/spec/ruby/library/logger/logger/datetime_format_spec.rb b/spec/ruby/library/logger/logger/datetime_format_spec.rb
index 582b34bfda..75a7f6cc03 100644
--- a/spec/ruby/library/logger/logger/datetime_format_spec.rb
+++ b/spec/ruby/library/logger/logger/datetime_format_spec.rb
@@ -49,7 +49,7 @@ describe "Logger#datetime_format=" do
end
it "follows the Time#strftime format" do
- -> { @logger.datetime_format = "%Y-%m" }.should_not raise_error
+ -> { @logger.datetime_format = "%Y-%m" }.should_not.raise
regex = /\d{4}-\d{2}-\d{2}oo-\w+ar/
@logger.datetime_format = "%Foo-%Bar"
diff --git a/spec/ruby/library/logger/logger/new_spec.rb b/spec/ruby/library/logger/logger/new_spec.rb
index 3db20e7432..b311c96132 100644
--- a/spec/ruby/library/logger/logger/new_spec.rb
+++ b/spec/ruby/library/logger/logger/new_spec.rb
@@ -28,13 +28,13 @@ describe "Logger#new" do
end
it "receives a frequency rotation as second argument" do
- -> { Logger.new(@log_file, "daily") }.should_not raise_error
- -> { Logger.new(@log_file, "weekly") }.should_not raise_error
- -> { Logger.new(@log_file, "monthly") }.should_not raise_error
+ -> { Logger.new(@log_file, "daily") }.should_not.raise
+ -> { Logger.new(@log_file, "weekly") }.should_not.raise
+ -> { Logger.new(@log_file, "monthly") }.should_not.raise
end
it "also receives a number of log files to keep as second argument" do
- -> { Logger.new(@log_file, 1).close }.should_not raise_error
+ -> { Logger.new(@log_file, 1).close }.should_not.raise
end
it "receives a maximum logfile size as third argument" do
@@ -94,7 +94,7 @@ describe "Logger#new" do
logger.formatter.should == formatter
end
- it "receives shift_period_suffix " do
+ it "receives shift_period_suffix" do
shift_period_suffix = "%Y-%m-%d"
path = tmp("shift_period_suffix_test.log")
now = Time.now
diff --git a/spec/ruby/library/logger/logger/unknown_spec.rb b/spec/ruby/library/logger/logger/unknown_spec.rb
index b174b8b2c9..4d37c9797e 100644
--- a/spec/ruby/library/logger/logger/unknown_spec.rb
+++ b/spec/ruby/library/logger/logger/unknown_spec.rb
@@ -29,7 +29,7 @@ describe "Logger#unknown" do
end
it "receives empty messages" do
- -> { @logger.unknown("") }.should_not raise_error
+ -> { @logger.unknown("") }.should_not.raise
@log_file.rewind
LoggerSpecs.strip_date(@log_file.readlines.first).should == "ANY -- : \n"
end
diff --git a/spec/ruby/library/matrix/antisymmetric_spec.rb b/spec/ruby/library/matrix/antisymmetric_spec.rb
index 200df703cb..b4b8858f32 100644
--- a/spec/ruby/library/matrix/antisymmetric_spec.rb
+++ b/spec/ruby/library/matrix/antisymmetric_spec.rb
@@ -4,11 +4,11 @@ require 'matrix'
describe "Matrix#antisymmetric?" do
it "returns true for an antisymmetric Matrix" do
- Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should be_true
+ Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should == true
end
it "returns true for a 0x0 empty matrix" do
- Matrix.empty.antisymmetric?.should be_true
+ Matrix.empty.antisymmetric?.should == true
end
it "returns false for non-antisymmetric matrices" do
@@ -17,7 +17,7 @@ describe "Matrix#antisymmetric?" do
Matrix[[1, -2, 3], [2, 0, 6], [-3, -6, 0]], # wrong diagonal element
Matrix[[0, 2, -3], [2, 0, 6], [-3, 6, 0]] # only signs wrong
].each do |matrix|
- matrix.antisymmetric?.should be_false
+ matrix.antisymmetric?.should == false
end
end
@@ -30,7 +30,7 @@ describe "Matrix#antisymmetric?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.antisymmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/build_spec.rb b/spec/ruby/library/matrix/build_spec.rb
index 6d8017a3df..49eb2e69a5 100644
--- a/spec/ruby/library/matrix/build_spec.rb
+++ b/spec/ruby/library/matrix/build_spec.rb
@@ -6,7 +6,7 @@ describe "Matrix.build" do
it "returns a Matrix object of the given size" do
m = Matrix.build(3, 4){1}
- m.should be_an_instance_of(Matrix)
+ m.should.instance_of?(Matrix)
m.row_size.should == 3
m.column_size.should == 4
end
@@ -24,32 +24,32 @@ describe "Matrix.build" do
it "returns an Enumerator is no block is given" do
enum = Matrix.build(2, 1)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.each{1}.should == Matrix[[1], [1]]
end
it "requires integers as parameters" do
- -> { Matrix.build("1", "2"){1} }.should raise_error(TypeError)
- -> { Matrix.build(nil, nil){1} }.should raise_error(TypeError)
- -> { Matrix.build(1..2){1} }.should raise_error(TypeError)
+ -> { Matrix.build("1", "2"){1} }.should.raise(TypeError)
+ -> { Matrix.build(nil, nil){1} }.should.raise(TypeError)
+ -> { Matrix.build(1..2){1} }.should.raise(TypeError)
end
it "requires non-negative integers" do
- -> { Matrix.build(-1, 1){1} }.should raise_error(ArgumentError)
- -> { Matrix.build(+1,-1){1} }.should raise_error(ArgumentError)
+ -> { Matrix.build(-1, 1){1} }.should.raise(ArgumentError)
+ -> { Matrix.build(+1,-1){1} }.should.raise(ArgumentError)
end
it "returns empty Matrix if one argument is zero" do
m = Matrix.build(0, 3){
raise "Should not yield"
}
- m.should be_empty
+ m.should.empty?
m.column_size.should == 3
m = Matrix.build(3, 0){
raise "Should not yield"
}
- m.should be_empty
+ m.should.empty?
m.row_size.should == 3
end
@@ -68,6 +68,6 @@ end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.build(3){1}.should be_an_instance_of(MatrixSub)
+ MatrixSub.build(3){1}.should.instance_of?(MatrixSub)
end
end
diff --git a/spec/ruby/library/matrix/clone_spec.rb b/spec/ruby/library/matrix/clone_spec.rb
index 74e5bf157e..51aefc6010 100644
--- a/spec/ruby/library/matrix/clone_spec.rb
+++ b/spec/ruby/library/matrix/clone_spec.rb
@@ -9,17 +9,17 @@ describe "Matrix#clone" do
it "returns a shallow copy of the matrix" do
b = @a.clone
- @a.should_not equal(b)
- b.should be_kind_of(Matrix)
+ @a.should_not.equal?(b)
+ b.should.is_a?(Matrix)
b.should == @a
0.upto(@a.row_size - 1) do |i|
- @a.row(i).should_not equal(b.row(i))
+ @a.row(i).should_not.equal?(b.row(i))
end
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.clone.should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.clone.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/coerce_spec.rb b/spec/ruby/library/matrix/coerce_spec.rb
index 4022f00236..6032dd2f62 100644
--- a/spec/ruby/library/matrix/coerce_spec.rb
+++ b/spec/ruby/library/matrix/coerce_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require 'matrix'
describe "Matrix#coerce" do
- it "allows the division of integer by a Matrix " do
+ it "allows the division of integer by a Matrix" do
(1/Matrix[[0,1],[-1,0]]).should == Matrix[[0,-1],[1,0]]
end
end
diff --git a/spec/ruby/library/matrix/column_spec.rb b/spec/ruby/library/matrix/column_spec.rb
index 1f3c80964a..d5d8c80c1a 100644
--- a/spec/ruby/library/matrix/column_spec.rb
+++ b/spec/ruby/library/matrix/column_spec.rb
@@ -21,7 +21,7 @@ describe "Matrix#column" do
end
it "returns self when called with a block" do
- @m.column(0) { |x| x }.should equal(@m)
+ @m.column(0) { |x| x }.should.equal?(@m)
end
it "returns nil when out of bounds" do
@@ -29,7 +29,7 @@ describe "Matrix#column" do
end
it "never yields when out of bounds" do
- -> { @m.column(3){ raise } }.should_not raise_error
- -> { @m.column(-4){ raise } }.should_not raise_error
+ -> { @m.column(3){ raise } }.should_not.raise
+ -> { @m.column(-4){ raise } }.should_not.raise
end
end
diff --git a/spec/ruby/library/matrix/column_vector_spec.rb b/spec/ruby/library/matrix/column_vector_spec.rb
index 47e866a8d5..d86c3f9e42 100644
--- a/spec/ruby/library/matrix/column_vector_spec.rb
+++ b/spec/ruby/library/matrix/column_vector_spec.rb
@@ -6,20 +6,20 @@ describe "Matrix.column_vector" do
it "returns a single column Matrix when called with an Array" do
m = Matrix.column_vector([4,5,6])
- m.should be_an_instance_of(Matrix)
+ m.should.instance_of?(Matrix)
m.should == Matrix[ [4],[5],[6] ]
end
it "returns an empty Matrix when called with an empty Array" do
m = Matrix.column_vector([])
- m.should be_an_instance_of(Matrix)
+ m.should.instance_of?(Matrix)
m.row_size.should == 0
m.column_size.should == 1
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.column_vector([4,5,6]).should be_an_instance_of(MatrixSub)
+ MatrixSub.column_vector([4,5,6]).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/column_vectors_spec.rb b/spec/ruby/library/matrix/column_vectors_spec.rb
index b0cb6f914c..7ac6871e7f 100644
--- a/spec/ruby/library/matrix/column_vectors_spec.rb
+++ b/spec/ruby/library/matrix/column_vectors_spec.rb
@@ -8,11 +8,11 @@ describe "Matrix#column_vectors" do
end
it "returns an Array" do
- Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array)
+ Matrix[ [1,2], [3,4] ].column_vectors.should.instance_of?(Array)
end
it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ @vectors.all? {|v| v.should.instance_of?(Vector)}
end
it "returns each column as a Vector" do
diff --git a/spec/ruby/library/matrix/columns_spec.rb b/spec/ruby/library/matrix/columns_spec.rb
index 3095fdd7af..ac9587899d 100644
--- a/spec/ruby/library/matrix/columns_spec.rb
+++ b/spec/ruby/library/matrix/columns_spec.rb
@@ -10,7 +10,7 @@ describe "Matrix.columns" do
end
it "creates a Matrix from argument columns" do
- @m.should be_an_instance_of(Matrix)
+ @m.should.instance_of?(Matrix)
@m.column(0).to_a.should == @a
@m.column(1).to_a.should == @b
end
@@ -36,7 +36,7 @@ describe "Matrix.columns" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub)
+ MatrixSub.columns([[1]]).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/constructor_spec.rb b/spec/ruby/library/matrix/constructor_spec.rb
index 70d77babbb..026525f36d 100644
--- a/spec/ruby/library/matrix/constructor_spec.rb
+++ b/spec/ruby/library/matrix/constructor_spec.rb
@@ -5,10 +5,10 @@ require 'matrix'
describe "Matrix.[]" do
it "requires arrays as parameters" do
- -> { Matrix[5] }.should raise_error(TypeError)
- -> { Matrix[nil] }.should raise_error(TypeError)
- -> { Matrix[1..2] }.should raise_error(TypeError)
- -> { Matrix[[1, 2], 3] }.should raise_error(TypeError)
+ -> { Matrix[5] }.should.raise(TypeError)
+ -> { Matrix[nil] }.should.raise(TypeError)
+ -> { Matrix[1..2] }.should.raise(TypeError)
+ -> { Matrix[[1, 2], 3] }.should.raise(TypeError)
end
it "creates an empty Matrix with no arguments" do
@@ -18,15 +18,13 @@ describe "Matrix.[]" do
end
it "raises for non-rectangular matrices" do
- ->{ Matrix[ [0], [0,1] ] }.should \
- raise_error(Matrix::ErrDimensionMismatch)
- ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should \
- raise_error(Matrix::ErrDimensionMismatch)
+ ->{ Matrix[ [0], [0,1] ] }.should.raise(Matrix::ErrDimensionMismatch)
+ ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should.raise(Matrix::ErrDimensionMismatch)
end
it "accepts vector arguments" do
a = Matrix[Vector[1, 2], Vector[3, 4]]
- a.should be_an_instance_of(Matrix)
+ a.should.instance_of?(Matrix)
a.should == Matrix[ [1, 2], [3, 4] ]
end
@@ -38,7 +36,7 @@ describe "Matrix.[]" do
it "returns a Matrix object" do
- Matrix[ [1] ].should be_an_instance_of(Matrix)
+ Matrix[ [1] ].should.instance_of?(Matrix)
end
it "can create an nxn Matrix" do
@@ -59,7 +57,7 @@ describe "Matrix.[]" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub[ [20,30], [40.5, 9] ].should be_an_instance_of(MatrixSub)
+ MatrixSub[ [20,30], [40.5, 9] ].should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/diagonal_spec.rb b/spec/ruby/library/matrix/diagonal_spec.rb
index ef9738e73e..ee84ac8c28 100644
--- a/spec/ruby/library/matrix/diagonal_spec.rb
+++ b/spec/ruby/library/matrix/diagonal_spec.rb
@@ -8,7 +8,7 @@ describe "Matrix.diagonal" do
end
it "returns an object of type Matrix" do
- @m.should be_kind_of(Matrix)
+ @m.should.is_a?(Matrix)
end
it "returns a square Matrix of the right size" do
@@ -34,27 +34,27 @@ describe "Matrix.diagonal" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub)
+ MatrixSub.diagonal(1).should.instance_of?(MatrixSub)
end
end
end
describe "Matrix.diagonal?" do
it "returns true for a diagonal Matrix" do
- Matrix.diagonal([1, 2, 3]).diagonal?.should be_true
+ Matrix.diagonal([1, 2, 3]).diagonal?.should == true
end
it "returns true for a zero square Matrix" do
- Matrix.zero(3).diagonal?.should be_true
+ Matrix.zero(3).diagonal?.should == true
end
it "returns false for a non diagonal square Matrix" do
- Matrix[[0, 1], [0, 0]].diagonal?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should be_false
+ Matrix[[0, 1], [0, 0]].diagonal?.should == false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should == false
end
it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).diagonal?.should be_true
+ Matrix.empty(0,0).diagonal?.should == true
end
it "raises an error for rectangular matrices" do
@@ -66,7 +66,7 @@ describe "Matrix.diagonal?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.diagonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/divide_spec.rb b/spec/ruby/library/matrix/divide_spec.rb
index 2e3bb85bf6..711a5189e4 100644
--- a/spec/ruby/library/matrix/divide_spec.rb
+++ b/spec/ruby/library/matrix/divide_spec.rb
@@ -30,25 +30,25 @@ describe "Matrix#/" do
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a / Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
end
it "returns an instance of Matrix" do
- (@a / @b).should be_kind_of(Matrix)
+ (@a / @b).should.is_a?(Matrix)
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
m = MatrixSub.ins
- (m/m).should be_an_instance_of(MatrixSub)
- (m/1).should be_an_instance_of(MatrixSub)
+ (m/m).should.instance_of?(MatrixSub)
+ (m/1).should.instance_of?(MatrixSub)
end
end
it "raises a TypeError if other is of wrong type" do
- -> { @a / nil }.should raise_error(TypeError)
- -> { @a / "a" }.should raise_error(TypeError)
- -> { @a / [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a / Object.new }.should raise_error(TypeError)
+ -> { @a / nil }.should.raise(TypeError)
+ -> { @a / "a" }.should.raise(TypeError)
+ -> { @a / [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a / Object.new }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/matrix/each_spec.rb b/spec/ruby/library/matrix/each_spec.rb
index f3b0f01867..b4bfd3c76f 100644
--- a/spec/ruby/library/matrix/each_spec.rb
+++ b/spec/ruby/library/matrix/each_spec.rb
@@ -9,12 +9,12 @@ describe "Matrix#each" do
it "returns an Enumerator when called without a block" do
enum = @m.each
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == @result
end
it "returns self" do
- @m.each{}.should equal(@m)
+ @m.each{}.should.equal?(@m)
end
it "yields the elements starting with the those of the first row" do
@@ -33,13 +33,13 @@ describe "Matrix#each with an argument" do
it "raises an ArgumentError for unrecognized argument" do
-> {
@m.each("all"){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each(nil){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each(:left){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "yields the rights elements when passed :diagonal" do
diff --git a/spec/ruby/library/matrix/each_with_index_spec.rb b/spec/ruby/library/matrix/each_with_index_spec.rb
index a005b88621..17e3f3f44c 100644
--- a/spec/ruby/library/matrix/each_with_index_spec.rb
+++ b/spec/ruby/library/matrix/each_with_index_spec.rb
@@ -16,12 +16,12 @@ describe "Matrix#each_with_index" do
it "returns an Enumerator when called without a block" do
enum = @m.each_with_index
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == @result
end
it "returns self" do
- @m.each_with_index{}.should equal(@m)
+ @m.each_with_index{}.should.equal?(@m)
end
it "yields the elements starting with the those of the first row" do
@@ -40,13 +40,13 @@ describe "Matrix#each_with_index with an argument" do
it "raises an ArgumentError for unrecognized argument" do
-> {
@m.each_with_index("all"){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each_with_index(nil){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.each_with_index(:left){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "yields the rights elements when passed :diagonal" do
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
index 8438f63133..cbda82a16a 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
@@ -5,16 +5,16 @@ describe "Matrix::EigenvalueDecomposition#initialize" do
it "raises an error if argument is not a matrix" do
-> {
Matrix::EigenvalueDecomposition.new([[]])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Matrix::EigenvalueDecomposition.new(42)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises an error if matrix is not square" do
-> {
Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]])
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
it "never hangs" do
diff --git a/spec/ruby/library/matrix/element_reference_spec.rb b/spec/ruby/library/matrix/element_reference_spec.rb
index b950d1c391..c6804b3846 100644
--- a/spec/ruby/library/matrix/element_reference_spec.rb
+++ b/spec/ruby/library/matrix/element_reference_spec.rb
@@ -16,8 +16,8 @@ describe "Matrix#[]" do
end
it "returns nil for an invalid index pair" do
- @m[8,1].should be_nil
- @m[1,8].should be_nil
+ @m[8,1].should == nil
+ @m[1,8].should == nil
end
end
diff --git a/spec/ruby/library/matrix/empty_spec.rb b/spec/ruby/library/matrix/empty_spec.rb
index 5f294711db..7b0f0af9eb 100644
--- a/spec/ruby/library/matrix/empty_spec.rb
+++ b/spec/ruby/library/matrix/empty_spec.rb
@@ -4,20 +4,20 @@ require 'matrix'
describe "Matrix#empty?" do
it "returns true when the Matrix is empty" do
- Matrix[ ].empty?.should be_true
- Matrix[ [], [], [] ].empty?.should be_true
- Matrix[ [], [], [] ].transpose.empty?.should be_true
+ Matrix[ ].empty?.should == true
+ Matrix[ [], [], [] ].empty?.should == true
+ Matrix[ [], [], [] ].transpose.empty?.should == true
end
it "returns false when the Matrix has elements" do
- Matrix[ [1, 2] ].empty?.should be_false
- Matrix[ [1], [2] ].empty?.should be_false
+ Matrix[ [1, 2] ].empty?.should == false
+ Matrix[ [1], [2] ].empty?.should == false
end
it "doesn't accept any parameter" do
->{
Matrix[ [1, 2] ].empty?(42)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -40,29 +40,29 @@ describe "Matrix.empty" do
it "does not accept more than two parameters" do
->{
Matrix.empty(1, 2, 3)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if both dimensions are > 0" do
->{
Matrix.empty(1, 2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if any dimension is < 0" do
->{
Matrix.empty(-2, 0)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
->{
Matrix.empty(0, -2)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.empty(0, 1).should be_an_instance_of(MatrixSub)
+ MatrixSub.empty(0, 1).should.instance_of?(MatrixSub)
end
end
diff --git a/spec/ruby/library/matrix/eql_spec.rb b/spec/ruby/library/matrix/eql_spec.rb
index ea26c3320d..cda122f4d8 100644
--- a/spec/ruby/library/matrix/eql_spec.rb
+++ b/spec/ruby/library/matrix/eql_spec.rb
@@ -6,6 +6,6 @@ describe "Matrix#eql?" do
it_behaves_like :equal, :eql?
it "returns false if some elements are == but not eql?" do
- Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should be_false
+ Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should == false
end
end
diff --git a/spec/ruby/library/matrix/exponent_spec.rb b/spec/ruby/library/matrix/exponent_spec.rb
index 38cdfa9276..4cbe63587d 100644
--- a/spec/ruby/library/matrix/exponent_spec.rb
+++ b/spec/ruby/library/matrix/exponent_spec.rb
@@ -17,8 +17,8 @@ describe "Matrix#**" do
it "raises a ErrDimensionMismatch for non square matrices" do
m = Matrix[ [1, 1], [1, 2], [2, 3]]
- -> { m ** 3 }.should raise_error(Matrix::ErrDimensionMismatch)
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { m ** 3 }.should.raise(Matrix::ErrDimensionMismatch)
+ -> { m ** 0 }.should.raise(Matrix::ErrDimensionMismatch)
end
describe "that is < 0" do
@@ -30,7 +30,7 @@ describe "Matrix#**" do
it "raises a ErrNotRegular for irregular matrices" do
m = Matrix[ [1, 1], [1, 1] ]
- -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular)
+ -> { m ** -2 }.should.raise(Matrix::ErrNotRegular)
end
end
@@ -42,7 +42,7 @@ describe "Matrix#**" do
it "raises an ErrDimensionMismatch for non-square matrices" do
m = Matrix[ [1, 1] ]
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { m ** 0 }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
@@ -56,7 +56,7 @@ describe "Matrix#**" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub)
+ (MatrixSub.ins ** 1).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/find_index_spec.rb b/spec/ruby/library/matrix/find_index_spec.rb
index c2bfa6d61a..c7278fd449 100644
--- a/spec/ruby/library/matrix/find_index_spec.rb
+++ b/spec/ruby/library/matrix/find_index_spec.rb
@@ -8,12 +8,12 @@ describe "Matrix#find_index without any argument" do
it "returns an Enumerator when called without a block" do
enum = @m.find_index
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [1, 2, 3, 4, 5, 6, 7, 8]
end
it "returns nil if the block is always false" do
- @m.find_index{false}.should be_nil
+ @m.find_index{false}.should == nil
end
it "returns the first index for which the block is true" do
@@ -48,7 +48,7 @@ describe "Matrix#find_index with a subselection argument" do
it "returns an Enumerator when called without a block" do
@tests.each do |matrix, h|
h.each do |selector, result|
- matrix.find_index(selector).should be_an_instance_of(Enumerator)
+ matrix.find_index(selector).should.instance_of?(Enumerator)
end
end
end
@@ -116,7 +116,7 @@ describe "Matrix#find_index with only a generic argument" do
end
it "returns nil if the value is not found" do
- @m.find_index(42).should be_nil
+ @m.find_index(42).should == nil
end
it "returns the first index for of the requested value" do
@@ -132,15 +132,15 @@ describe "Matrix#find_index with two arguments" do
it "raises an ArgumentError for an unrecognized last argument" do
-> {
@m.find_index(1, "all"){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.find_index(1, nil){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.find_index(1, :left){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@m.find_index(:diagonal, 1){}
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/matrix/hash_spec.rb b/spec/ruby/library/matrix/hash_spec.rb
index 7dabcd3737..27bf7b9751 100644
--- a/spec/ruby/library/matrix/hash_spec.rb
+++ b/spec/ruby/library/matrix/hash_spec.rb
@@ -4,7 +4,7 @@ require 'matrix'
describe "Matrix#hash" do
it "returns an Integer" do
- Matrix[ [1,2] ].hash.should be_an_instance_of(Integer)
+ Matrix[ [1,2] ].hash.should.instance_of?(Integer)
end
it "returns the same value for the same matrix" do
diff --git a/spec/ruby/library/matrix/hermitian_spec.rb b/spec/ruby/library/matrix/hermitian_spec.rb
index 177ca64d83..94d0dbe6b6 100644
--- a/spec/ruby/library/matrix/hermitian_spec.rb
+++ b/spec/ruby/library/matrix/hermitian_spec.rb
@@ -3,15 +3,15 @@ require 'matrix'
describe "Matrix.hermitian?" do
it "returns true for a hermitian Matrix" do
- Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should be_true
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should == true
end
it "returns true for a 0x0 empty matrix" do
- Matrix.empty.hermitian?.should be_true
+ Matrix.empty.hermitian?.should == true
end
it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].hermitian?.should be_false
+ Matrix[[1, 2],[-2, 1]].hermitian?.should == false
end
it "raises an error for rectangular matrices" do
@@ -23,12 +23,12 @@ describe "Matrix.hermitian?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.hermitian?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
it "returns false for a matrix with complex values on the diagonal" do
- Matrix[[Complex(1,1)]].hermitian?.should be_false
- Matrix[[Complex(1,0)]].hermitian?.should be_true
+ Matrix[[Complex(1,1)]].hermitian?.should == false
+ Matrix[[Complex(1,0)]].hermitian?.should == true
end
end
diff --git a/spec/ruby/library/matrix/lower_triangular_spec.rb b/spec/ruby/library/matrix/lower_triangular_spec.rb
index f3aa4501f4..7e8688fd9b 100644
--- a/spec/ruby/library/matrix/lower_triangular_spec.rb
+++ b/spec/ruby/library/matrix/lower_triangular_spec.rb
@@ -3,22 +3,22 @@ require 'matrix'
describe "Matrix.lower_triangular?" do
it "returns true for a square lower triangular Matrix" do
- Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should be_true
- Matrix.diagonal([1, 2, 3]).lower_triangular?.should be_true
- Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should be_true
- Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should be_true
+ Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should == true
+ Matrix.diagonal([1, 2, 3]).lower_triangular?.should == true
+ Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should == true
+ Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should == true
end
it "returns true for an empty Matrix" do
- Matrix.empty(3, 0).lower_triangular?.should be_true
- Matrix.empty(0, 3).lower_triangular?.should be_true
- Matrix.empty(0, 0).lower_triangular?.should be_true
+ Matrix.empty(3, 0).lower_triangular?.should == true
+ Matrix.empty(0, 3).lower_triangular?.should == true
+ Matrix.empty(0, 0).lower_triangular?.should == true
end
it "returns false for a non lower triangular square Matrix" do
- Matrix[[0, 1], [0, 0]].lower_triangular?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should be_false
- Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should be_false
- Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should be_false
+ Matrix[[0, 1], [0, 0]].lower_triangular?.should == false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should == false
+ Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should == false
+ Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should == false
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
index 9d733066c1..98ac5c71a3 100644
--- a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
@@ -15,7 +15,7 @@ describe "Matrix::LUPDecomposition#determinant" do
lup = m.lup
-> {
lup.determinant
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
index 36afb349e6..b813757525 100644
--- a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
@@ -5,9 +5,9 @@ describe "Matrix::LUPDecomposition#initialize" do
it "raises an error if argument is not a matrix" do
-> {
Matrix::LUPDecomposition.new([[]])
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
-> {
Matrix::LUPDecomposition.new(42)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
index 9514ab5d06..0a6797cc85 100644
--- a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
@@ -13,6 +13,6 @@ describe "Matrix::LUPDecomposition#l" do
end
it "returns a lower triangular matrix" do
- @l.lower_triangular?.should be_true
+ @l.lower_triangular?.should == true
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
index c7b5e9196e..2c44399b79 100644
--- a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
@@ -13,6 +13,6 @@ describe "Matrix::LUPDecomposition#p" do
end
it "returns a permutation matrix" do
- @p.permutation?.should be_true
+ @p.permutation?.should == true
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
index 66242627e9..9927e96727 100644
--- a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
@@ -8,7 +8,7 @@ describe "Matrix::LUPDecomposition#solve" do
lu = Matrix::LUPDecomposition.new(a)
-> {
lu.solve(a)
- }.should raise_error(Matrix::ErrNotRegular)
+ }.should.raise(Matrix::ErrNotRegular)
end
describe "for non singular matrices" do
@@ -33,7 +33,7 @@ describe "Matrix::LUPDecomposition#solve" do
values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]]
-> {
@lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
it "returns the right vector when given a vector of the appropriate size" do
@@ -46,7 +46,7 @@ describe "Matrix::LUPDecomposition#solve" do
values = Vector[14, 55]
-> {
@lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
index 9b1dccbbac..ab59677dd9 100644
--- a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
@@ -10,9 +10,9 @@ describe "Matrix::LUPDecomposition#to_a" do
end
it "returns an array of three matrices" do
- @to_a.should be_kind_of(Array)
+ @to_a.should.is_a?(Array)
@to_a.length.should == 3
- @to_a.each{|m| m.should be_kind_of(Matrix)}
+ @to_a.each{|m| m.should.is_a?(Matrix)}
end
it "returns [l, u, p] such that l*u == a*p" do
diff --git a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
index ca3dfc1f00..967bc669dc 100644
--- a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
@@ -13,6 +13,6 @@ describe "Matrix::LUPDecomposition#u" do
end
it "returns an upper triangular matrix" do
- @u.upper_triangular?.should be_true
+ @u.upper_triangular?.should == true
end
end
diff --git a/spec/ruby/library/matrix/minor_spec.rb b/spec/ruby/library/matrix/minor_spec.rb
index 009826c3d6..6b29db568b 100644
--- a/spec/ruby/library/matrix/minor_spec.rb
+++ b/spec/ruby/library/matrix/minor_spec.rb
@@ -79,7 +79,7 @@ describe "Matrix#minor" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.minor(0, 1, 0, 1).should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.minor(0, 1, 0, 1).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/minus_spec.rb b/spec/ruby/library/matrix/minus_spec.rb
index 95cf4a6072..7426aa2d2c 100644
--- a/spec/ruby/library/matrix/minus_spec.rb
+++ b/spec/ruby/library/matrix/minus_spec.rb
@@ -13,30 +13,30 @@ describe "Matrix#-" do
end
it "returns an instance of Matrix" do
- (@a - @b).should be_kind_of(Matrix)
+ (@a - @b).should.is_a?(Matrix)
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a - Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
end
it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
- -> { @a - 2 }.should raise_error(Matrix::ErrOperationNotDefined)
- -> { @a - 1.2 }.should raise_error(Matrix::ErrOperationNotDefined)
- -> { @a - bignum_value }.should raise_error(Matrix::ErrOperationNotDefined)
+ -> { @a - 2 }.should.raise(Matrix::ErrOperationNotDefined)
+ -> { @a - 1.2 }.should.raise(Matrix::ErrOperationNotDefined)
+ -> { @a - bignum_value }.should.raise(Matrix::ErrOperationNotDefined)
end
it "raises a TypeError if other is of wrong type" do
- -> { @a - nil }.should raise_error(TypeError)
- -> { @a - "a" }.should raise_error(TypeError)
- -> { @a - [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a - Object.new }.should raise_error(TypeError)
+ -> { @a - nil }.should.raise(TypeError)
+ -> { @a - "a" }.should.raise(TypeError)
+ -> { @a - [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a - Object.new }.should.raise(TypeError)
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
m = MatrixSub.ins
- (m-m).should be_an_instance_of(MatrixSub)
+ (m-m).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/multiply_spec.rb b/spec/ruby/library/matrix/multiply_spec.rb
index 206868af92..6c495c5521 100644
--- a/spec/ruby/library/matrix/multiply_spec.rb
+++ b/spec/ruby/library/matrix/multiply_spec.rb
@@ -33,7 +33,7 @@ describe "Matrix#*" do
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a * Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
end
it "returns a zero matrix if (nx0) * (0xn)" do
@@ -53,17 +53,17 @@ describe "Matrix#*" do
end
it "raises a TypeError if other is of wrong type" do
- -> { @a * nil }.should raise_error(TypeError)
- -> { @a * "a" }.should raise_error(TypeError)
- -> { @a * [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a * Object.new }.should raise_error(TypeError)
+ -> { @a * nil }.should.raise(TypeError)
+ -> { @a * "a" }.should.raise(TypeError)
+ -> { @a * [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a * Object.new }.should.raise(TypeError)
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
m = MatrixSub.ins
- (m*m).should be_an_instance_of(MatrixSub)
- (m*1).should be_an_instance_of(MatrixSub)
+ (m*m).should.instance_of?(MatrixSub)
+ (m*1).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/new_spec.rb b/spec/ruby/library/matrix/new_spec.rb
index 3005066846..bde9d9f4c8 100644
--- a/spec/ruby/library/matrix/new_spec.rb
+++ b/spec/ruby/library/matrix/new_spec.rb
@@ -3,6 +3,6 @@ require 'matrix'
describe "Matrix.new" do
it "is private" do
- Matrix.should have_private_method(:new)
+ Matrix.private_methods(false).should.include?(:new)
end
end
diff --git a/spec/ruby/library/matrix/normal_spec.rb b/spec/ruby/library/matrix/normal_spec.rb
index a9e6c645fa..420d4b011f 100644
--- a/spec/ruby/library/matrix/normal_spec.rb
+++ b/spec/ruby/library/matrix/normal_spec.rb
@@ -20,7 +20,7 @@ describe "Matrix.normal?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.normal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/orthogonal_spec.rb b/spec/ruby/library/matrix/orthogonal_spec.rb
index 26afe89ff0..71ac831fe8 100644
--- a/spec/ruby/library/matrix/orthogonal_spec.rb
+++ b/spec/ruby/library/matrix/orthogonal_spec.rb
@@ -20,7 +20,7 @@ describe "Matrix.orthogonal?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.orthogonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/permutation_spec.rb b/spec/ruby/library/matrix/permutation_spec.rb
index 825a9d982c..43727edea1 100644
--- a/spec/ruby/library/matrix/permutation_spec.rb
+++ b/spec/ruby/library/matrix/permutation_spec.rb
@@ -3,18 +3,18 @@ require 'matrix'
describe "Matrix#permutation?" do
it "returns true for a permutation Matrix" do
- Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should be_true
+ Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should == true
end
it "returns false for a non permutation square Matrix" do
- Matrix[[0, 1], [0, 0]].permutation?.should be_false
- Matrix[[-1, 0], [0, -1]].permutation?.should be_false
- Matrix[[1, 0], [1, 0]].permutation?.should be_false
- Matrix[[1, 0], [1, 1]].permutation?.should be_false
+ Matrix[[0, 1], [0, 0]].permutation?.should == false
+ Matrix[[-1, 0], [0, -1]].permutation?.should == false
+ Matrix[[1, 0], [1, 0]].permutation?.should == false
+ Matrix[[1, 0], [1, 1]].permutation?.should == false
end
it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).permutation?.should be_true
+ Matrix.empty(0,0).permutation?.should == true
end
it "raises an error for rectangular matrices" do
@@ -26,7 +26,7 @@ describe "Matrix#permutation?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.permutation?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/plus_spec.rb b/spec/ruby/library/matrix/plus_spec.rb
index 2706bad060..72a9ba8f8f 100644
--- a/spec/ruby/library/matrix/plus_spec.rb
+++ b/spec/ruby/library/matrix/plus_spec.rb
@@ -13,30 +13,30 @@ describe "Matrix#+" do
end
it "returns an instance of Matrix" do
- (@a + @b).should be_kind_of(Matrix)
+ (@a + @b).should.is_a?(Matrix)
end
it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { @a + Matrix[ [1] ] }.should.raise(Matrix::ErrDimensionMismatch)
end
it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
- -> { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- -> { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- -> { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + 2 }.should.raise(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + 1.2 }.should.raise(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + bignum_value }.should.raise(ExceptionForMatrix::ErrOperationNotDefined)
end
it "raises a TypeError if other is of wrong type" do
- -> { @a + nil }.should raise_error(TypeError)
- -> { @a + "a" }.should raise_error(TypeError)
- -> { @a + [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a + Object.new }.should raise_error(TypeError)
+ -> { @a + nil }.should.raise(TypeError)
+ -> { @a + "a" }.should.raise(TypeError)
+ -> { @a + [ [1, 2] ] }.should.raise(TypeError)
+ -> { @a + Object.new }.should.raise(TypeError)
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
m = MatrixSub.ins
- (m+m).should be_an_instance_of(MatrixSub)
+ (m+m).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/real_spec.rb b/spec/ruby/library/matrix/real_spec.rb
index 38033c63c8..4589dc22a5 100644
--- a/spec/ruby/library/matrix/real_spec.rb
+++ b/spec/ruby/library/matrix/real_spec.rb
@@ -4,22 +4,22 @@ require 'matrix'
describe "Matrix#real?" do
it "returns true for matrices with all real entries" do
- Matrix[ [1, 2], [3, 4] ].real?.should be_true
- Matrix[ [1.9, 2], [3, 4] ].real?.should be_true
+ Matrix[ [1, 2], [3, 4] ].real?.should == true
+ Matrix[ [1.9, 2], [3, 4] ].real?.should == true
end
it "returns true for empty matrices" do
- Matrix.empty.real?.should be_true
+ Matrix.empty.real?.should == true
end
it "returns false if one element is a Complex" do
- Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false
+ Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should == false
end
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
it "returns false if one element is a Complex whose imaginary part is 0" do
- Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should be_false
+ Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should == false
end
end
end
@@ -37,7 +37,7 @@ describe "Matrix#real" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.real.should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.real.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/regular_spec.rb b/spec/ruby/library/matrix/regular_spec.rb
index 3699d0ef8b..4cb00819ac 100644
--- a/spec/ruby/library/matrix/regular_spec.rb
+++ b/spec/ruby/library/matrix/regular_spec.rb
@@ -5,27 +5,27 @@ describe "Matrix#regular?" do
it "returns false for singular matrices" do
m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.regular?.should be_false
+ m.regular?.should == false
m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.regular?.should be_false
+ m.regular?.should == false
end
it "returns true if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].regular?.should be_true
+ Matrix[ [0,1], [1,0] ].regular?.should == true
end
it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).regular?.should be_true
+ Matrix.empty(0,0).regular?.should == true
end
it "raises an error for rectangular matrices" do
-> {
Matrix[[1], [2], [3]].regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
-> {
Matrix.empty(3,0).regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/round_spec.rb b/spec/ruby/library/matrix/round_spec.rb
index 1dc29df890..cdec646fa1 100644
--- a/spec/ruby/library/matrix/round_spec.rb
+++ b/spec/ruby/library/matrix/round_spec.rb
@@ -15,7 +15,7 @@ describe "Matrix#round" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.round.should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.round.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/row_spec.rb b/spec/ruby/library/matrix/row_spec.rb
index 00b1f02a8e..8a7662fdf2 100644
--- a/spec/ruby/library/matrix/row_spec.rb
+++ b/spec/ruby/library/matrix/row_spec.rb
@@ -21,7 +21,7 @@ describe "Matrix#row" do
end
it "returns self when called with a block" do
- @m.row(0) { |x| x }.should equal(@m)
+ @m.row(0) { |x| x }.should.equal?(@m)
end
it "returns nil when out of bounds" do
@@ -30,7 +30,7 @@ describe "Matrix#row" do
end
it "never yields when out of bounds" do
- -> { @m.row(3){ raise } }.should_not raise_error
- -> { @m.row(-4){ raise } }.should_not raise_error
+ -> { @m.row(3){ raise } }.should_not.raise
+ -> { @m.row(-4){ raise } }.should_not.raise
end
end
diff --git a/spec/ruby/library/matrix/row_vector_spec.rb b/spec/ruby/library/matrix/row_vector_spec.rb
index 341437ee05..f3919fb7d8 100644
--- a/spec/ruby/library/matrix/row_vector_spec.rb
+++ b/spec/ruby/library/matrix/row_vector_spec.rb
@@ -5,7 +5,7 @@ require 'matrix'
describe "Matrix.row_vector" do
it "returns a Matrix" do
- Matrix.row_vector([]).should be_an_instance_of(Matrix)
+ Matrix.row_vector([]).should.instance_of?(Matrix)
end
it "returns a single-row Matrix with the specified values" do
@@ -18,7 +18,7 @@ describe "Matrix.row_vector" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.row_vector([1]).should be_an_instance_of(MatrixSub)
+ MatrixSub.row_vector([1]).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/row_vectors_spec.rb b/spec/ruby/library/matrix/row_vectors_spec.rb
index 6f99c439a6..4a0db67527 100644
--- a/spec/ruby/library/matrix/row_vectors_spec.rb
+++ b/spec/ruby/library/matrix/row_vectors_spec.rb
@@ -8,11 +8,11 @@ describe "Matrix#row_vectors" do
end
it "returns an Array" do
- Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array)
+ Matrix[ [1,2], [3,4] ].row_vectors.should.instance_of?(Array)
end
it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ @vectors.all? {|v| v.should.instance_of?(Vector)}
end
it "returns each row as a Vector" do
diff --git a/spec/ruby/library/matrix/rows_spec.rb b/spec/ruby/library/matrix/rows_spec.rb
index 41ba635775..9c248cd8a4 100644
--- a/spec/ruby/library/matrix/rows_spec.rb
+++ b/spec/ruby/library/matrix/rows_spec.rb
@@ -10,7 +10,7 @@ describe "Matrix.rows" do
end
it "returns a Matrix" do
- @m.should be_kind_of(Matrix)
+ @m.should.is_a?(Matrix)
end
it "creates a matrix from argument rows" do
@@ -21,8 +21,8 @@ describe "Matrix.rows" do
it "copies the original rows by default" do
@a << 3
@b << 6
- @m.row(0).should_not equal(@a)
- @m.row(1).should_not equal(@b)
+ @m.row(0).should_not.equal?(@a)
+ @m.row(1).should_not.equal?(@b)
end
it "references the original rows if copy is false" do
@@ -35,7 +35,7 @@ describe "Matrix.rows" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.rows([[0, 1], [0, 1]]).should be_an_instance_of(MatrixSub)
+ MatrixSub.rows([[0, 1], [0, 1]]).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/scalar_spec.rb b/spec/ruby/library/matrix/scalar_spec.rb
index 7fdd64c9d9..5b93b60533 100644
--- a/spec/ruby/library/matrix/scalar_spec.rb
+++ b/spec/ruby/library/matrix/scalar_spec.rb
@@ -10,7 +10,7 @@ describe "Matrix.scalar" do
end
it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
+ @a.should.is_a?(Matrix)
end
it "returns a n x n matrix" do
@@ -41,7 +41,7 @@ describe "Matrix.scalar" do
end
it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
+ @a.should.is_a?(Matrix)
end
it "returns a square matrix, where the first argument specifies the side of the square" do
diff --git a/spec/ruby/library/matrix/shared/collect.rb b/spec/ruby/library/matrix/shared/collect.rb
index 852f7fd6cf..3a4dbe3a36 100644
--- a/spec/ruby/library/matrix/shared/collect.rb
+++ b/spec/ruby/library/matrix/shared/collect.rb
@@ -7,7 +7,7 @@ describe :collect, shared: true do
end
it "returns an instance of Matrix" do
- @m.send(@method){|n| n * 2 }.should be_kind_of(Matrix)
+ @m.send(@method){|n| n * 2 }.should.is_a?(Matrix)
end
it "returns a Matrix where each element is the result of the block" do
@@ -15,12 +15,12 @@ describe :collect, shared: true do
end
it "returns an enumerator if no block is given" do
- @m.send(@method).should be_an_instance_of(Enumerator)
+ @m.send(@method).should.instance_of?(Enumerator)
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method){1}.should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.send(@method){1}.should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/shared/conjugate.rb b/spec/ruby/library/matrix/shared/conjugate.rb
index d87658f855..ffdf5ebca1 100644
--- a/spec/ruby/library/matrix/shared/conjugate.rb
+++ b/spec/ruby/library/matrix/shared/conjugate.rb
@@ -14,7 +14,7 @@ describe :matrix_conjugate, shared: true do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.send(@method).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/shared/determinant.rb b/spec/ruby/library/matrix/shared/determinant.rb
index 9e0528c24b..b7c86393ba 100644
--- a/spec/ruby/library/matrix/shared/determinant.rb
+++ b/spec/ruby/library/matrix/shared/determinant.rb
@@ -29,10 +29,10 @@ describe :determinant, shared: true do
it "raises an error for rectangular matrices" do
-> {
Matrix[[1], [2], [3]].send(@method)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
-> {
Matrix.empty(3,0).send(@method)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/shared/equal_value.rb b/spec/ruby/library/matrix/shared/equal_value.rb
index 2b2311d49e..9bc6ed908b 100644
--- a/spec/ruby/library/matrix/shared/equal_value.rb
+++ b/spec/ruby/library/matrix/shared/equal_value.rb
@@ -7,27 +7,27 @@ describe :equal, shared: true do
end
it "returns true for self" do
- @matrix.send(@method, @matrix).should be_true
+ @matrix.send(@method, @matrix).should == true
end
it "returns true for equal matrices" do
- @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should be_true
+ @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should == true
end
it "returns false for different matrices" do
- @matrix.send(@method, Matrix[ [42, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should be_false
- @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7] ]).should be_false
- @matrix.send(@method, Matrix[ [1, 2, 3], [2, 3, 4] ]).should be_false
+ @matrix.send(@method, Matrix[ [42, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should == false
+ @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7] ]).should == false
+ @matrix.send(@method, Matrix[ [1, 2, 3], [2, 3, 4] ]).should == false
end
it "returns false for different empty matrices" do
- Matrix.empty(42, 0).send(@method, Matrix.empty(6, 0)).should be_false
- Matrix.empty(0, 42).send(@method, Matrix.empty(0, 6)).should be_false
- Matrix.empty(0, 0).send(@method, Matrix.empty(6, 0)).should be_false
- Matrix.empty(0, 0).send(@method, Matrix.empty(0, 6)).should be_false
+ Matrix.empty(42, 0).send(@method, Matrix.empty(6, 0)).should == false
+ Matrix.empty(0, 42).send(@method, Matrix.empty(0, 6)).should == false
+ Matrix.empty(0, 0).send(@method, Matrix.empty(6, 0)).should == false
+ Matrix.empty(0, 0).send(@method, Matrix.empty(0, 6)).should == false
end
it "doesn't distinguish on subclasses" do
- MatrixSub.ins.send(@method, Matrix.I(2)).should be_true
+ MatrixSub.ins.send(@method, Matrix.I(2)).should == true
end
end
diff --git a/spec/ruby/library/matrix/shared/identity.rb b/spec/ruby/library/matrix/shared/identity.rb
index 114f86e7b0..df957b5a75 100644
--- a/spec/ruby/library/matrix/shared/identity.rb
+++ b/spec/ruby/library/matrix/shared/identity.rb
@@ -3,7 +3,7 @@ require 'matrix'
describe :matrix_identity, shared: true do
it "returns a Matrix" do
- Matrix.send(@method, 2).should be_kind_of(Matrix)
+ Matrix.send(@method, 2).should.is_a?(Matrix)
end
it "returns a n x n identity matrix" do
@@ -13,7 +13,7 @@ describe :matrix_identity, shared: true do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.send(@method, 2).should be_an_instance_of(MatrixSub)
+ MatrixSub.send(@method, 2).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/shared/imaginary.rb b/spec/ruby/library/matrix/shared/imaginary.rb
index d28ecc69f1..16615213a2 100644
--- a/spec/ruby/library/matrix/shared/imaginary.rb
+++ b/spec/ruby/library/matrix/shared/imaginary.rb
@@ -14,7 +14,7 @@ describe :matrix_imaginary, shared: true do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.send(@method).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/shared/inverse.rb b/spec/ruby/library/matrix/shared/inverse.rb
index c8a6b90da5..ac463cf680 100644
--- a/spec/ruby/library/matrix/shared/inverse.rb
+++ b/spec/ruby/library/matrix/shared/inverse.rb
@@ -4,7 +4,7 @@ require 'matrix'
describe :inverse, shared: true do
it "returns a Matrix" do
- Matrix[ [1,2], [2,1] ].send(@method).should be_an_instance_of(Matrix)
+ Matrix[ [1,2], [2,1] ].send(@method).should.instance_of?(Matrix)
end
it "returns the inverse of the Matrix" do
@@ -27,12 +27,12 @@ describe :inverse, shared: true do
it "raises a ErrDimensionMismatch if the Matrix is not square" do
->{
Matrix[ [1,2,3], [1,2,3] ].send(@method)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.send(@method).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/shared/rectangular.rb b/spec/ruby/library/matrix/shared/rectangular.rb
index 3d9a0dfe8a..0229e614c6 100644
--- a/spec/ruby/library/matrix/shared/rectangular.rb
+++ b/spec/ruby/library/matrix/shared/rectangular.rb
@@ -12,7 +12,7 @@ describe :matrix_rectangular, shared: true do
describe "for a subclass of Matrix" do
it "returns instances of that subclass" do
- MatrixSub.ins.send(@method).each{|m| m.should be_an_instance_of(MatrixSub) }
+ MatrixSub.ins.send(@method).each{|m| m.should.instance_of?(MatrixSub) }
end
end
end
diff --git a/spec/ruby/library/matrix/shared/trace.rb b/spec/ruby/library/matrix/shared/trace.rb
index 57b89863f8..c4a5491b22 100644
--- a/spec/ruby/library/matrix/shared/trace.rb
+++ b/spec/ruby/library/matrix/shared/trace.rb
@@ -6,7 +6,7 @@ describe :trace, shared: true do
end
it "returns the sum of diagonal elements in a rectangular Matrix" do
- ->{ Matrix[[1,2,3], [4,5,6]].trace}.should raise_error(Matrix::ErrDimensionMismatch)
+ ->{ Matrix[[1,2,3], [4,5,6]].trace}.should.raise(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/shared/transpose.rb b/spec/ruby/library/matrix/shared/transpose.rb
index 89b1d025be..a0b495359b 100644
--- a/spec/ruby/library/matrix/shared/transpose.rb
+++ b/spec/ruby/library/matrix/shared/transpose.rb
@@ -13,7 +13,7 @@ describe :matrix_transpose, shared: true do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub)
+ MatrixSub.ins.send(@method).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/singular_spec.rb b/spec/ruby/library/matrix/singular_spec.rb
index 7bba36a54a..00b93af495 100644
--- a/spec/ruby/library/matrix/singular_spec.rb
+++ b/spec/ruby/library/matrix/singular_spec.rb
@@ -4,28 +4,28 @@ require 'matrix'
describe "Matrix#singular?" do
it "returns true for singular matrices" do
m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.singular?.should be_true
+ m.singular?.should == true
m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.singular?.should be_true
+ m.singular?.should == true
end
it "returns false if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].singular?.should be_false
+ Matrix[ [0,1], [1,0] ].singular?.should == false
end
it "returns false for an empty 0x0 matrix" do
- Matrix.empty(0,0).singular?.should be_false
+ Matrix.empty(0,0).singular?.should == false
end
it "raises an error for rectangular matrices" do
-> {
Matrix[[1], [2], [3]].singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
-> {
Matrix.empty(3,0).singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/square_spec.rb b/spec/ruby/library/matrix/square_spec.rb
index 25d2d1ad9c..b8cf4acf44 100644
--- a/spec/ruby/library/matrix/square_spec.rb
+++ b/spec/ruby/library/matrix/square_spec.rb
@@ -4,25 +4,25 @@ require 'matrix'
describe "Matrix#square?" do
it "returns true when the Matrix is square" do
- Matrix[ [1,2], [2,4] ].square?.should be_true
- Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should be_true
+ Matrix[ [1,2], [2,4] ].square?.should == true
+ Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should == true
end
it "returns true when the Matrix has only one element" do
- Matrix[ [9] ].square?.should be_true
+ Matrix[ [9] ].square?.should == true
end
it "returns false when the Matrix is rectangular" do
- Matrix[ [1, 2] ].square?.should be_false
+ Matrix[ [1, 2] ].square?.should == false
end
it "returns false when the Matrix is rectangular" do
- Matrix[ [1], [2] ].square?.should be_false
+ Matrix[ [1], [2] ].square?.should == false
end
it "returns handles empty matrices" do
- Matrix[].square?.should be_true
- Matrix[[]].square?.should be_false
- Matrix.columns([[]]).square?.should be_false
+ Matrix[].square?.should == true
+ Matrix[[]].square?.should == false
+ Matrix.columns([[]]).square?.should == false
end
end
diff --git a/spec/ruby/library/matrix/symmetric_spec.rb b/spec/ruby/library/matrix/symmetric_spec.rb
index 6f2a99276a..4b86c19503 100644
--- a/spec/ruby/library/matrix/symmetric_spec.rb
+++ b/spec/ruby/library/matrix/symmetric_spec.rb
@@ -3,15 +3,15 @@ require 'matrix'
describe "Matrix.symmetric?" do
it "returns true for a symmetric Matrix" do
- Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should be_true
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should == true
end
it "returns true for a 0x0 empty matrix" do
- Matrix.empty.symmetric?.should be_true
+ Matrix.empty.symmetric?.should == true
end
it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].symmetric?.should be_false
+ Matrix[[1, 2],[-2, 1]].symmetric?.should == false
end
it "raises an error for rectangular matrices" do
@@ -23,7 +23,7 @@ describe "Matrix.symmetric?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.symmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/unitary_spec.rb b/spec/ruby/library/matrix/unitary_spec.rb
index c214ee9b2f..4490e8f8d4 100644
--- a/spec/ruby/library/matrix/unitary_spec.rb
+++ b/spec/ruby/library/matrix/unitary_spec.rb
@@ -26,7 +26,7 @@ describe "Matrix.unitary?" do
].each do |rectangular_matrix|
-> {
rectangular_matrix.unitary?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ }.should.raise(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/upper_triangular_spec.rb b/spec/ruby/library/matrix/upper_triangular_spec.rb
index 2514294a80..0e2bf611e2 100644
--- a/spec/ruby/library/matrix/upper_triangular_spec.rb
+++ b/spec/ruby/library/matrix/upper_triangular_spec.rb
@@ -3,22 +3,22 @@ require 'matrix'
describe "Matrix.upper_triangular?" do
it "returns true for an upper triangular Matrix" do
- Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should be_true
- Matrix.diagonal([1, 2, 3]).upper_triangular?.should be_true
- Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should be_true
- Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should be_true
+ Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should == true
+ Matrix.diagonal([1, 2, 3]).upper_triangular?.should == true
+ Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should == true
+ Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should == true
end
it "returns false for a non upper triangular square Matrix" do
- Matrix[[0, 0], [1, 0]].upper_triangular?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should be_false
- Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should be_false
- Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should be_false
+ Matrix[[0, 0], [1, 0]].upper_triangular?.should == false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should == false
+ Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should == false
+ Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should == false
end
it "returns true for an empty matrix" do
- Matrix.empty(3,0).upper_triangular?.should be_true
- Matrix.empty(0,3).upper_triangular?.should be_true
- Matrix.empty(0,0).upper_triangular?.should be_true
+ Matrix.empty(3,0).upper_triangular?.should == true
+ Matrix.empty(0,3).upper_triangular?.should == true
+ Matrix.empty(0,0).upper_triangular?.should == true
end
end
diff --git a/spec/ruby/library/matrix/vector/cross_product_spec.rb b/spec/ruby/library/matrix/vector/cross_product_spec.rb
index c2698ade4c..96a462c067 100644
--- a/spec/ruby/library/matrix/vector/cross_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/cross_product_spec.rb
@@ -9,6 +9,6 @@ describe "Vector#cross_product" do
it "raises an error unless both vectors have dimension 3" do
-> {
Vector[1, 2, 3].cross_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
+ }.should.raise(Vector::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/vector/each2_spec.rb b/spec/ruby/library/matrix/vector/each2_spec.rb
index 10d2fc404d..86e7ed75aa 100644
--- a/spec/ruby/library/matrix/vector/each2_spec.rb
+++ b/spec/ruby/library/matrix/vector/each2_spec.rb
@@ -8,8 +8,8 @@ describe "Vector.each2" do
end
it "requires one argument" do
- -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError)
- -> { @v.each2(){} }.should raise_error(ArgumentError)
+ -> { @v.each2(@v2, @v2){} }.should.raise(ArgumentError)
+ -> { @v.each2(){} }.should.raise(ArgumentError)
end
describe "given one argument" do
@@ -20,8 +20,8 @@ describe "Vector.each2" do
end
it "raises a DimensionMismatch error if the Vector size is different" do
- -> { @v.each2(Vector[1,2]){} }.should raise_error(Vector::ErrDimensionMismatch)
- -> { @v.each2(Vector[1,2,3,4]){} }.should raise_error(Vector::ErrDimensionMismatch)
+ -> { @v.each2(Vector[1,2]){} }.should.raise(Vector::ErrDimensionMismatch)
+ -> { @v.each2(Vector[1,2,3,4]){} }.should.raise(Vector::ErrDimensionMismatch)
end
it "yields arguments in sequence" do
@@ -37,12 +37,12 @@ describe "Vector.each2" do
end
it "returns self when given a block" do
- @v.each2(@v2){}.should equal(@v)
+ @v.each2(@v2){}.should.equal?(@v)
end
it "returns an enumerator if no block given" do
enum = @v.each2(@v2)
- enum.should be_an_instance_of(Enumerator)
+ enum.should.instance_of?(Enumerator)
enum.to_a.should == [[1, 4], [2, 5], [3, 6]]
end
end
diff --git a/spec/ruby/library/matrix/vector/eql_spec.rb b/spec/ruby/library/matrix/vector/eql_spec.rb
index eb2451b550..6e2cd47b8e 100644
--- a/spec/ruby/library/matrix/vector/eql_spec.rb
+++ b/spec/ruby/library/matrix/vector/eql_spec.rb
@@ -7,10 +7,10 @@ describe "Vector#eql?" do
end
it "returns true for self" do
- @vector.eql?(@vector).should be_true
+ @vector.eql?(@vector).should == true
end
it "returns false when there are a pair corresponding elements which are not equal in the sense of Kernel#eql?" do
- @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should be_false
+ @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should == false
end
end
diff --git a/spec/ruby/library/matrix/vector/inner_product_spec.rb b/spec/ruby/library/matrix/vector/inner_product_spec.rb
index 1cf8771e04..79dee10833 100644
--- a/spec/ruby/library/matrix/vector/inner_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/inner_product_spec.rb
@@ -13,7 +13,7 @@ describe "Vector#inner_product" do
it "raises an error for mismatched vectors" do
-> {
Vector[1, 2, 3].inner_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
+ }.should.raise(Vector::ErrDimensionMismatch)
end
it "uses the conjugate of its argument" do
diff --git a/spec/ruby/library/matrix/vector/normalize_spec.rb b/spec/ruby/library/matrix/vector/normalize_spec.rb
index 527c9260de..bb1f046786 100644
--- a/spec/ruby/library/matrix/vector/normalize_spec.rb
+++ b/spec/ruby/library/matrix/vector/normalize_spec.rb
@@ -10,9 +10,9 @@ describe "Vector#normalize" do
it "raises an error for zero vectors" do
-> {
Vector[].normalize
- }.should raise_error(Vector::ZeroVectorError)
+ }.should.raise(Vector::ZeroVectorError)
-> {
Vector[0, 0, 0].normalize
- }.should raise_error(Vector::ZeroVectorError)
+ }.should.raise(Vector::ZeroVectorError)
end
end
diff --git a/spec/ruby/library/matrix/zero_spec.rb b/spec/ruby/library/matrix/zero_spec.rb
index 68e8567c26..406bcad6ed 100644
--- a/spec/ruby/library/matrix/zero_spec.rb
+++ b/spec/ruby/library/matrix/zero_spec.rb
@@ -4,7 +4,7 @@ require 'matrix'
describe "Matrix.zero" do
it "returns an object of type Matrix" do
- Matrix.zero(3).should be_kind_of(Matrix)
+ Matrix.zero(3).should.is_a?(Matrix)
end
it "creates a n x n matrix" do
@@ -30,7 +30,7 @@ describe "Matrix.zero" do
describe "for a subclass of Matrix" do
it "returns an instance of that subclass" do
- MatrixSub.zero(3).should be_an_instance_of(MatrixSub)
+ MatrixSub.zero(3).should.instance_of?(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/monitor/exit_spec.rb b/spec/ruby/library/monitor/exit_spec.rb
index 952ad9525d..0748a523ac 100644
--- a/spec/ruby/library/monitor/exit_spec.rb
+++ b/spec/ruby/library/monitor/exit_spec.rb
@@ -5,6 +5,6 @@ describe "Monitor#exit" do
it "raises ThreadError when monitor is not entered" do
m = Monitor.new
- -> { m.exit }.should raise_error(ThreadError)
+ -> { m.exit }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/library/monitor/mon_initialize_spec.rb b/spec/ruby/library/monitor/mon_initialize_spec.rb
index e0fe6c2d97..092aee929c 100644
--- a/spec/ruby/library/monitor/mon_initialize_spec.rb
+++ b/spec/ruby/library/monitor/mon_initialize_spec.rb
@@ -26,6 +26,6 @@ describe "MonitorMixin#mon_initialize" do
instance = cls.new(1, 2, 3)
copy = instance.dup
- copy.should_not equal(instance)
+ copy.should_not.equal?(instance)
end
end
diff --git a/spec/ruby/library/monitor/synchronize_spec.rb b/spec/ruby/library/monitor/synchronize_spec.rb
index d78393eb3a..27cc1258b4 100644
--- a/spec/ruby/library/monitor/synchronize_spec.rb
+++ b/spec/ruby/library/monitor/synchronize_spec.rb
@@ -31,11 +31,11 @@ describe "Monitor#synchronize" do
end
it "raises a LocalJumpError if not passed a block" do
- -> { Monitor.new.synchronize }.should raise_error(LocalJumpError)
+ -> { Monitor.new.synchronize }.should.raise(LocalJumpError)
end
it "raises a thread error if the monitor is not owned on exiting the block" do
monitor = Monitor.new
- -> { monitor.synchronize { monitor.exit } }.should raise_error(ThreadError)
+ -> { monitor.synchronize { monitor.exit } }.should.raise(ThreadError)
end
end
diff --git a/spec/ruby/library/net-ftp/FTPError_spec.rb b/spec/ruby/library/net-ftp/FTPError_spec.rb
index 0c31b65dcc..b447e50546 100644
--- a/spec/ruby/library/net-ftp/FTPError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPError_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPError" do
- it "is an Exception" do
- Net::FTPError.should < Exception
+ruby_version_is ""..."4.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPError" do
+ it "is an Exception" do
+ Net::FTPError.should < Exception
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPPermError_spec.rb b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
index b43e12c503..b9a2d93aef 100644
--- a/spec/ruby/library/net-ftp/FTPPermError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPPermError" do
- it "is an Exception" do
- Net::FTPPermError.should < Exception
- end
+ruby_version_is ""..."4.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPPermError" do
+ it "is an Exception" do
+ Net::FTPPermError.should < Exception
+ end
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
index e7abbc0dd8..a1d9e44d63 100644
--- a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPProtoError" do
- it "is an Exception" do
- Net::FTPProtoError.should < Exception
- end
+ruby_version_is ""..."4.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPProtoError" do
+ it "is an Exception" do
+ Net::FTPProtoError.should < Exception
+ end
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
index fcc7501fc1..c9e6468323 100644
--- a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPReplyError" do
- it "is an Exception" do
- Net::FTPReplyError.should < Exception
- end
+ruby_version_is ""..."4.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPReplyError" do
+ it "is an Exception" do
+ Net::FTPReplyError.should < Exception
+ end
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/FTPTempError_spec.rb b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
index f4b045dfb5..c0953cb0f2 100644
--- a/spec/ruby/library/net-ftp/FTPTempError_spec.rb
+++ b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
@@ -1,12 +1,15 @@
require_relative '../../spec_helper'
-require 'net/ftp'
-describe "Net::FTPTempError" do
- it "is an Exception" do
- Net::FTPTempError.should < Exception
- end
+ruby_version_is ""..."4.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPTempError" do
+ it "is an Exception" do
+ Net::FTPTempError.should < Exception
+ end
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/abort_spec.rb b/spec/ruby/library/net-ftp/abort_spec.rb
index 335d056512..9e8be53c68 100644
--- a/spec/ruby/library/net-ftp/abort_spec.rb
+++ b/spec/ruby/library/net-ftp/abort_spec.rb
@@ -1,62 +1,65 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#abort" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#abort" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the ABOR command to the server" do
- -> { @ftp.abort }.should_not raise_error
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "ignores the response" do
- @ftp.abort
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- end
+ it "sends the ABOR command to the server" do
+ -> { @ftp.abort }.should_not.raise
+ end
- it "returns the full response" do
- @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
- end
+ it "ignores the response" do
+ @ftp.abort
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
+ end
- it "does not raise any error when the response code is 225" do
- @server.should_receive(:abor).and_respond("225 Data connection open; no transfer in progress.")
- -> { @ftp.abort }.should_not raise_error
- end
+ it "returns the full response" do
+ @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
+ end
- it "does not raise any error when the response code is 226" do
- @server.should_receive(:abor).and_respond("226 Closing data connection.")
- -> { @ftp.abort }.should_not raise_error
- end
+ it "does not raise any error when the response code is 225" do
+ @server.should_receive(:abor).and_respond("225 Data connection open; no transfer in progress.")
+ -> { @ftp.abort }.should_not.raise
+ end
- it "raises a Net::FTPProtoError when the response code is 500" do
- @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
+ it "does not raise any error when the response code is 226" do
+ @server.should_receive(:abor).and_respond("226 Closing data connection.")
+ -> { @ftp.abort }.should_not.raise
+ end
- it "raises a Net::FTPProtoError when the response code is 501" do
- @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
+ it "raises a Net::FTPProtoError when the response code is 500" do
+ @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.abort }.should.raise(Net::FTPProtoError)
+ end
- it "raises a Net::FTPProtoError when the response code is 502" do
- @server.should_receive(:abor).and_respond("502 Command not implemented.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
+ it "raises a Net::FTPProtoError when the response code is 501" do
+ @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.abort }.should.raise(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 502" do
+ @server.should_receive(:abor).and_respond("502 Command not implemented.")
+ -> { @ftp.abort }.should.raise(Net::FTPProtoError)
+ end
- it "raises a Net::FTPProtoError when the response code is 421" do
- @server.should_receive(:abor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ it "raises a Net::FTPProtoError when the response code is 421" do
+ @server.should_receive(:abor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.abort }.should.raise(Net::FTPProtoError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/acct_spec.rb b/spec/ruby/library/net-ftp/acct_spec.rb
index ab093448a2..a64a0f48a8 100644
--- a/spec/ruby/library/net-ftp/acct_spec.rb
+++ b/spec/ruby/library/net-ftp/acct_spec.rb
@@ -1,58 +1,61 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#acct" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "writes the ACCT command to the server" do
- @ftp.acct("my_account")
- @ftp.last_response.should == "230 User 'my_account' logged in, proceed. (ACCT)\n"
- end
-
- it "returns nil" do
- @ftp.acct("my_account").should == nil
- end
-
- it "does not raise any error when the response code is 230" do
- @server.should_receive(:acct).and_respond("230 User logged in, proceed.")
- -> { @ftp.acct("my_account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:acct).and_respond("530 Not logged in.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 503" do
- @server.should_receive(:acct).and_respond("503 Bad sequence of commands.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPTempError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#acct" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "writes the ACCT command to the server" do
+ @ftp.acct("my_account")
+ @ftp.last_response.should == "230 User 'my_account' logged in, proceed. (ACCT)\n"
+ end
+
+ it "returns nil" do
+ @ftp.acct("my_account").should == nil
+ end
+
+ it "does not raise any error when the response code is 230" do
+ @server.should_receive(:acct).and_respond("230 User logged in, proceed.")
+ -> { @ftp.acct("my_account") }.should_not.raise
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:acct).and_respond("530 Not logged in.")
+ -> { @ftp.acct("my_account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.acct("my_account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.acct("my_account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 503" do
+ @server.should_receive(:acct).and_respond("503 Bad sequence of commands.")
+ -> { @ftp.acct("my_account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.acct("my_account") }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/binary_spec.rb b/spec/ruby/library/net-ftp/binary_spec.rb
index 1e0585b795..de8d0ac103 100644
--- a/spec/ruby/library/net-ftp/binary_spec.rb
+++ b/spec/ruby/library/net-ftp/binary_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#binary" do
- it "returns true when self is in binary mode" do
- ftp = Net::FTP.new
- ftp.binary.should be_true
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.binary = false
- ftp.binary.should be_false
+ describe "Net::FTP#binary" do
+ it "returns true when self is in binary mode" do
+ ftp = Net::FTP.new
+ ftp.binary.should == true
+
+ ftp.binary = false
+ ftp.binary.should == false
+ end
end
-end
-describe "Net::FTP#binary=" do
- it "sets self to binary mode when passed true" do
- ftp = Net::FTP.new
+ describe "Net::FTP#binary=" do
+ it "sets self to binary mode when passed true" do
+ ftp = Net::FTP.new
- ftp.binary = true
- ftp.binary.should be_true
+ ftp.binary = true
+ ftp.binary.should == true
- ftp.binary = false
- ftp.binary.should be_false
+ ftp.binary = false
+ ftp.binary.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/chdir_spec.rb b/spec/ruby/library/net-ftp/chdir_spec.rb
index cc129b5e42..f8f352158c 100644
--- a/spec/ruby/library/net-ftp/chdir_spec.rb
+++ b/spec/ruby/library/net-ftp/chdir_spec.rb
@@ -1,99 +1,102 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#chdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#chdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when switching to the parent directory" do
+ it "sends the 'CDUP' command to the server" do
+ @ftp.chdir("..")
+ @ftp.last_response.should == "200 Command okay. (CDUP)\n"
+ end
+
+ it "returns nil" do
+ @ftp.chdir("..").should == nil
+ end
+
+ it "does not raise a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:cdup).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.chdir("..") }.should_not.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:cdup).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("..") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:cdup).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("..") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:cdup).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("..") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:cdup).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("..") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:cdup).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("..") }.should.raise(Net::FTPPermError)
+ end
+ end
- describe "when switching to the parent directory" do
- it "sends the 'CDUP' command to the server" do
- @ftp.chdir("..")
- @ftp.last_response.should == "200 Command okay. (CDUP)\n"
+ it "writes the 'CWD' command with the passed directory to the socket" do
+ @ftp.chdir("test")
+ @ftp.last_response.should == "200 Command okay. (CWD test)\n"
end
it "returns nil" do
- @ftp.chdir("..").should be_nil
+ @ftp.chdir("test").should == nil
end
- it "does not raise a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:cdup).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.chdir("..") }.should_not raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:cwd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.chdir("test") }.should.raise(Net::FTPPermError)
end
it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:cdup).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("test") }.should.raise(Net::FTPPermError)
end
it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:cdup).and_respond("502 Command not implemented.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:cwd).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("test") }.should.raise(Net::FTPPermError)
end
it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:cdup).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPTempError)
+ @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("test") }.should.raise(Net::FTPTempError)
end
it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:cdup).and_respond("530 Not logged in.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:cwd).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("test") }.should.raise(Net::FTPPermError)
end
it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:cdup).and_respond("550 Requested action not taken.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("test") }.should.raise(Net::FTPPermError)
end
end
-
- it "writes the 'CWD' command with the passed directory to the socket" do
- @ftp.chdir("test")
- @ftp.last_response.should == "200 Command okay. (CWD test)\n"
- end
-
- it "returns nil" do
- @ftp.chdir("test").should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:cwd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:cwd).and_respond("502 Command not implemented.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:cwd).and_respond("530 Not logged in.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
end
diff --git a/spec/ruby/library/net-ftp/close_spec.rb b/spec/ruby/library/net-ftp/close_spec.rb
index 183f14a84b..9d5d4c638a 100644
--- a/spec/ruby/library/net-ftp/close_spec.rb
+++ b/spec/ruby/library/net-ftp/close_spec.rb
@@ -1,30 +1,33 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#close" do
- before :each do
- @socket = mock("Socket")
- @socket.stub!(:closed?).and_return(false)
- @socket.stub!(:read_timeout).and_return(60)
- @socket.stub!(:read_timeout=).and_return(3)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
+ describe "Net::FTP#close" do
+ before :each do
+ @socket = mock("Socket")
+ @socket.stub!(:closed?).and_return(false)
+ @socket.stub!(:read_timeout).and_return(60)
+ @socket.stub!(:read_timeout=).and_return(3)
- it "closes the socket" do
- @socket.should_receive(:close)
- @ftp.close.should be_nil
- end
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ end
- it "does not try to close the socket if it has already been closed" do
- @socket.should_receive(:closed?).and_return(true)
- @socket.should_not_receive(:close)
- @ftp.close.should be_nil
- end
+ it "closes the socket" do
+ @socket.should_receive(:close)
+ @ftp.close.should == nil
+ end
+
+ it "does not try to close the socket if it has already been closed" do
+ @socket.should_receive(:closed?).and_return(true)
+ @socket.should_not_receive(:close)
+ @ftp.close.should == nil
+ end
- it "does not try to close the socket if it is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.close.should be_nil
+ it "does not try to close the socket if it is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.close.should == nil
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/closed_spec.rb b/spec/ruby/library/net-ftp/closed_spec.rb
index 84001cdc0f..1c8693932e 100644
--- a/spec/ruby/library/net-ftp/closed_spec.rb
+++ b/spec/ruby/library/net-ftp/closed_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#closed?" do
- before :each do
- @socket = mock("Socket")
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
+ describe "Net::FTP#closed?" do
+ before :each do
+ @socket = mock("Socket")
- it "returns true when the socket is closed" do
- @socket.should_receive(:closed?).and_return(true)
- @ftp.closed?.should be_true
- end
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ end
+
+ it "returns true when the socket is closed" do
+ @socket.should_receive(:closed?).and_return(true)
+ @ftp.closed?.should == true
+ end
- it "returns true when the socket is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.closed?.should be_true
+ it "returns true when the socket is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.closed?.should == true
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/connect_spec.rb b/spec/ruby/library/net-ftp/connect_spec.rb
index e606b11e2a..597381f67c 100644
--- a/spec/ruby/library/net-ftp/connect_spec.rb
+++ b/spec/ruby/library/net-ftp/connect_spec.rb
@@ -1,43 +1,46 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-# TODO: Add specs for using the SOCKSSocket
-describe "Net::FTP#connect" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- end
-
- after :each do
- @server.connect_message = nil
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "tries to connect to the FTP Server on the given host and port" do
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
- end
-
- it "returns nil" do
- @ftp.connect(@server.hostname, @server.server_port).should be_nil
- end
-
- it "does not raise any error when the response code is 220" do
- @server.connect_message = "220 Dummy FTP Server ready!"
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
- end
-
- it "raises a Net::FTPReplyError when the response code is 120" do
- @server.connect_message = "120 Service ready in nnn minutes."
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.connect_message = "421 Service not available, closing control connection."
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPTempError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ # TODO: Add specs for using the SOCKSSocket
+ describe "Net::FTP#connect" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ end
+
+ after :each do
+ @server.connect_message = nil
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "tries to connect to the FTP Server on the given host and port" do
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not.raise
+ end
+
+ it "returns nil" do
+ @ftp.connect(@server.hostname, @server.server_port).should == nil
+ end
+
+ it "does not raise any error when the response code is 220" do
+ @server.connect_message = "220 Dummy FTP Server ready!"
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not.raise
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 120" do
+ @server.connect_message = "120 Service ready in nnn minutes."
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should.raise(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.connect_message = "421 Service not available, closing control connection."
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/debug_mode_spec.rb b/spec/ruby/library/net-ftp/debug_mode_spec.rb
index f2ef53c089..28765b9d1c 100644
--- a/spec/ruby/library/net-ftp/debug_mode_spec.rb
+++ b/spec/ruby/library/net-ftp/debug_mode_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#debug_mode" do
- it "returns true when self is in debug mode" do
- ftp = Net::FTP.new
- ftp.debug_mode.should be_false
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
+ describe "Net::FTP#debug_mode" do
+ it "returns true when self is in debug mode" do
+ ftp = Net::FTP.new
+ ftp.debug_mode.should == false
+
+ ftp.debug_mode = true
+ ftp.debug_mode.should == true
+ end
end
-end
-describe "Net::FTP#debug_mode=" do
- it "sets self into debug mode when passed true" do
- ftp = Net::FTP.new
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
+ describe "Net::FTP#debug_mode=" do
+ it "sets self into debug mode when passed true" do
+ ftp = Net::FTP.new
+ ftp.debug_mode = true
+ ftp.debug_mode.should == true
- ftp.debug_mode = false
- ftp.debug_mode.should be_false
+ ftp.debug_mode = false
+ ftp.debug_mode.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/default_passive_spec.rb b/spec/ruby/library/net-ftp/default_passive_spec.rb
index 3f14f6187e..b47b4e9782 100644
--- a/spec/ruby/library/net-ftp/default_passive_spec.rb
+++ b/spec/ruby/library/net-ftp/default_passive_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#default_passive" do
- it "is true by default" do
- ruby_exe(fixture(__FILE__, "default_passive.rb")).should == "true\ntrue\n"
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#default_passive" do
+ it "is true by default" do
+ ruby_exe(fixture(__FILE__, "default_passive.rb")).should == "true\ntrue\n"
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/delete_spec.rb b/spec/ruby/library/net-ftp/delete_spec.rb
index bfb7da1ffe..40cd8f1d99 100644
--- a/spec/ruby/library/net-ftp/delete_spec.rb
+++ b/spec/ruby/library/net-ftp/delete_spec.rb
@@ -1,59 +1,62 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#delete" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the DELE command with the passed filename to the server" do
- @ftp.delete("test.file")
- @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:dele).and_respond("550 Requested action not taken.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:dele).and_respond("502 Command not implemented.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:dele).and_respond("530 Not logged in.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#delete" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the DELE command with the passed filename to the server" do
+ @ftp.delete("test.file")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:dele).and_respond("550 Requested action not taken.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:dele).and_respond("502 Command not implemented.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:dele).and_respond("530 Not logged in.")
+ -> { @ftp.delete("test.file") }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/dir_spec.rb b/spec/ruby/library/net-ftp/dir_spec.rb
index 894f03dd7b..af38724fad 100644
--- a/spec/ruby/library/net-ftp/dir_spec.rb
+++ b/spec/ruby/library/net-ftp/dir_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/list'
-describe "Net::FTP#dir" do
- it_behaves_like :net_ftp_list, :dir
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/list'
+
+ describe "Net::FTP#dir" do
+ it_behaves_like :net_ftp_list, :dir
+ end
end
diff --git a/spec/ruby/library/net-ftp/fixtures/server.rb b/spec/ruby/library/net-ftp/fixtures/server.rb
index 8b34d3f8bd..9fc2beb57b 100644
--- a/spec/ruby/library/net-ftp/fixtures/server.rb
+++ b/spec/ruby/library/net-ftp/fixtures/server.rb
@@ -1,277 +1,279 @@
-module NetFTPSpecs
- class DummyFTP
- attr_accessor :connect_message
- attr_reader :login_user, :login_pass, :login_acct
-
- # hostname or IP address
- attr_reader :hostname
- # port number
- attr_reader :server_port
-
- def initialize
- @hostname = "127.0.0.1"
- @server = TCPServer.new(@hostname, 0)
- @server_port = @server.addr[1]
-
- @handlers = {}
- @commands = []
- @connect_message = nil
- end
+ruby_version_is ""..."4.1" do
+ module NetFTPSpecs
+ class DummyFTP
+ attr_accessor :connect_message
+ attr_reader :login_user, :login_pass, :login_acct
+
+ # hostname or IP address
+ attr_reader :hostname
+ # port number
+ attr_reader :server_port
+
+ def initialize
+ @hostname = "127.0.0.1"
+ @server = TCPServer.new(@hostname, 0)
+ @server_port = @server.addr[1]
+
+ @handlers = {}
+ @commands = []
+ @connect_message = nil
+ end
- def serve_once
- @thread = Thread.new do
- @socket = @server.accept
- @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
- begin
- handle_request
- ensure
- @socket.close
+ def serve_once
+ @thread = Thread.new do
+ @socket = @server.accept
+ @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
+ begin
+ handle_request
+ ensure
+ @socket.close
+ end
end
end
- end
-
- def handle_request
- # Send out the welcome message.
- response @connect_message || "220 Dummy FTP Server ready!"
- begin
- while command = @socket.gets
- command, argument = command.chomp.split(" ", 2)
+ def handle_request
+ # Send out the welcome message.
+ response @connect_message || "220 Dummy FTP Server ready!"
- if command == "QUIT"
- self.response("221 OK, bye")
- break
- elsif proc_handler = @handlers[command.downcase.to_sym]
- if argument.nil?
- proc_handler.call(self)
- else
- proc_handler.call(self, argument)
- end
- else
- if argument.nil?
- self.send(command.downcase.to_sym)
+ begin
+ while command = @socket.gets
+ command, argument = command.chomp.split(" ", 2)
+
+ if command == "QUIT"
+ self.response("221 OK, bye")
+ break
+ elsif proc_handler = @handlers[command.downcase.to_sym]
+ if argument.nil?
+ proc_handler.call(self)
+ else
+ proc_handler.call(self, argument)
+ end
else
- self.send(command.downcase.to_sym, argument)
+ if argument.nil?
+ self.send(command.downcase.to_sym)
+ else
+ self.send(command.downcase.to_sym, argument)
+ end
end
end
+ rescue => e
+ self.error_response("Exception: #{e} #{e.backtrace.inspect}")
end
- rescue => e
- self.error_response("Exception: #{e} #{e.backtrace.inspect}")
end
- end
- def error_response(text)
- self.response("451 #{text}")
- end
+ def error_response(text)
+ self.response("451 #{text}")
+ end
- def response(text)
- @socket.puts(text) unless @socket.closed?
- end
+ def response(text)
+ @socket.puts(text) unless @socket.closed?
+ end
- def stop
- @datasocket.close unless @datasocket.nil? || @datasocket.closed?
- @server.close
- @thread.join
- end
+ def stop
+ @datasocket.close unless @datasocket.nil? || @datasocket.closed?
+ @server.close
+ @thread.join
+ end
- ##
- def handle(sym, &block)
- @handlers[sym] = block
- end
+ ##
+ def handle(sym, &block)
+ @handlers[sym] = block
+ end
- def should_receive(method)
- @handler_for = method
- self
- end
+ def should_receive(method)
+ @handler_for = method
+ self
+ end
- def and_respond(text)
- @handlers[@handler_for] = -> s, *args { s.response(text) }
- end
+ def and_respond(text)
+ @handlers[@handler_for] = -> s, *args { s.response(text) }
+ end
- ##
- # FTP methods
- ##
+ ##
+ # FTP methods
+ ##
- def abor
- self.response("226 Closing data connection. (ABOR)")
- end
+ def abor
+ self.response("226 Closing data connection. (ABOR)")
+ end
- def acct(account)
- @login_acct = account
- self.response("230 User '#{account}' logged in, proceed. (ACCT)")
- end
+ def acct(account)
+ @login_acct = account
+ self.response("230 User '#{account}' logged in, proceed. (ACCT)")
+ end
- def cdup
- self.response("200 Command okay. (CDUP)")
- end
+ def cdup
+ self.response("200 Command okay. (CDUP)")
+ end
- def cwd(dir)
- self.response("200 Command okay. (CWD #{dir})")
- end
+ def cwd(dir)
+ self.response("200 Command okay. (CWD #{dir})")
+ end
- def dele(file)
- self.response("250 Requested file action okay, completed. (DELE #{file})")
- end
+ def dele(file)
+ self.response("250 Requested file action okay, completed. (DELE #{file})")
+ end
- def eprt(arg)
- _, _, host, port = arg.split("|")
+ def eprt(arg)
+ _, _, host, port = arg.split("|")
- @datasocket = TCPSocket.new(host, port)
- self.response("200 port opened")
- end
+ @datasocket = TCPSocket.new(host, port)
+ self.response("200 port opened")
+ end
- def help(param = :default)
- if param == :default
- self.response("211 System status, or system help reply. (HELP)")
- else
- self.response("211 System status, or system help reply. (HELP #{param})")
+ def help(param = :default)
+ if param == :default
+ self.response("211 System status, or system help reply. (HELP)")
+ else
+ self.response("211 System status, or system help reply. (HELP #{param})")
+ end
end
- end
- def list(folder)
- self.response("150 opening ASCII connection for file list")
- @datasocket.puts("-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb")
- @datasocket.puts("-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb")
- @datasocket.puts("-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb")
- @datasocket.close()
- self.response("226 transfer complete (LIST #{folder})")
- end
+ def list(folder)
+ self.response("150 opening ASCII connection for file list")
+ @datasocket.puts("-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb")
+ @datasocket.puts("-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb")
+ @datasocket.puts("-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb")
+ @datasocket.close()
+ self.response("226 transfer complete (LIST #{folder})")
+ end
- def mdtm(filename)
- self.response("213 19980705132316")
- end
+ def mdtm(filename)
+ self.response("213 19980705132316")
+ end
- def mkd(foldername)
- self.response(%Q{257 "#{foldername.gsub('"', '""')}" created.})
- end
+ def mkd(foldername)
+ self.response(%Q{257 "#{foldername.gsub('"', '""')}" created.})
+ end
- def nlst(folder = nil)
- self.response("150 opening ASCII connection for file list")
- @datasocket.puts("last_response_code.rb")
- @datasocket.puts("list.rb")
- @datasocket.puts("pwd.rb")
- @datasocket.close()
- self.response("226 transfer complete (NLST#{folder ? " #{folder}" : ""})")
- end
+ def nlst(folder = nil)
+ self.response("150 opening ASCII connection for file list")
+ @datasocket.puts("last_response_code.rb")
+ @datasocket.puts("list.rb")
+ @datasocket.puts("pwd.rb")
+ @datasocket.close()
+ self.response("226 transfer complete (NLST#{folder ? " #{folder}" : ""})")
+ end
- def noop
- self.response("200 Command okay. (NOOP)")
- end
+ def noop
+ self.response("200 Command okay. (NOOP)")
+ end
- def pass(password)
- @login_pass = password
- self.response("230 User logged in, proceed. (PASS #{password})")
- end
+ def pass(password)
+ @login_pass = password
+ self.response("230 User logged in, proceed. (PASS #{password})")
+ end
- def port(arg)
- nums = arg.split(",")
+ def port(arg)
+ nums = arg.split(",")
+
+ if nums[0] == "::1"
+ # IPv6
+ port = nums[1].to_i * 256 + nums[2].to_i
+ host = nums[0]
+ else
+ # IPv4
+ port = nums[4].to_i * 256 + nums[5].to_i
+ host = nums[0..3].join(".")
+ end
- if nums[0] == "::1"
- # IPv6
- port = nums[1].to_i * 256 + nums[2].to_i
- host = nums[0]
- else
- # IPv4
- port = nums[4].to_i * 256 + nums[5].to_i
- host = nums[0..3].join(".")
+ @datasocket = TCPSocket.new(host, port)
+ self.response("200 port opened")
end
- @datasocket = TCPSocket.new(host, port)
- self.response("200 port opened")
- end
-
- def pwd
- self.response('257 "/some/dir/" - current directory')
- end
+ def pwd
+ self.response('257 "/some/dir/" - current directory')
+ end
- def retr(file)
- self.response("125 Data transfer starting")
- if @restart_at && @restart_at == 20
- @datasocket.puts("of the file named '#{file}'.")
- @restart_at = nil
- else
- @datasocket.puts("This is the content")
- @datasocket.puts("of the file named '#{file}'.")
- end
- @datasocket.close()
- self.response("226 Closing data connection. (RETR #{file})")
- end
+ def retr(file)
+ self.response("125 Data transfer starting")
+ if @restart_at && @restart_at == 20
+ @datasocket.puts("of the file named '#{file}'.")
+ @restart_at = nil
+ else
+ @datasocket.puts("This is the content")
+ @datasocket.puts("of the file named '#{file}'.")
+ end
+ @datasocket.close()
+ self.response("226 Closing data connection. (RETR #{file})")
+ end
- def rest(at_bytes)
- @restart_at = at_bytes.to_i
- self.response("350 Requested file action pending further information. (REST)")
- end
+ def rest(at_bytes)
+ @restart_at = at_bytes.to_i
+ self.response("350 Requested file action pending further information. (REST)")
+ end
- def rmd(folder)
- self.response("250 Requested file action okay, completed. (RMD #{folder})")
- end
+ def rmd(folder)
+ self.response("250 Requested file action okay, completed. (RMD #{folder})")
+ end
- def rnfr(from)
- @rename_from = from
- self.response("350 Requested file action pending further information.")
- end
+ def rnfr(from)
+ @rename_from = from
+ self.response("350 Requested file action pending further information.")
+ end
- def rnto(to)
- self.response("250 Requested file action okay, completed. (Renamed #{@rename_from} to #{to})")
- @rename_from = nil
- end
+ def rnto(to)
+ self.response("250 Requested file action okay, completed. (Renamed #{@rename_from} to #{to})")
+ @rename_from = nil
+ end
- def site(param)
- self.response("200 Command okay. (SITE #{param})")
- end
+ def site(param)
+ self.response("200 Command okay. (SITE #{param})")
+ end
- def size(filename)
- if filename == "binary"
- self.response("213 24")
- else
- self.response("213 1024")
+ def size(filename)
+ if filename == "binary"
+ self.response("213 24")
+ else
+ self.response("213 1024")
+ end
end
- end
- def stat(param = :default)
- if param == :default
- self.response("211 System status, or system help reply. (STAT)")
- else
- self.response("211 System status, or system help reply. (STAT #{param})")
+ def stat(param = :default)
+ if param == :default
+ self.response("211 System status, or system help reply. (STAT)")
+ else
+ self.response("211 System status, or system help reply. (STAT #{param})")
+ end
end
- end
- def stor(file)
- tmp_file = tmp("#{file}file", false)
+ def stor(file)
+ tmp_file = tmp("#{file}file", false)
- self.response("125 Data transfer starting.")
+ self.response("125 Data transfer starting.")
- mode = @restart_at ? "a" : "w"
+ mode = @restart_at ? "a" : "w"
- File.open(tmp_file, mode + "b") do |f|
- loop do
- data = @datasocket.recv(1024)
- break if !data || data.empty?
- f << data
+ File.open(tmp_file, mode + "b") do |f|
+ loop do
+ data = @datasocket.recv(1024)
+ break if !data || data.empty?
+ f << data
+ end
end
- end
- @datasocket.close()
- self.response("200 OK, Data received. (STOR #{file})")
- end
+ @datasocket.close()
+ self.response("200 OK, Data received. (STOR #{file})")
+ end
- def appe(file)
- @restart_at = true
- stor(file)
- end
+ def appe(file)
+ @restart_at = true
+ stor(file)
+ end
- def syst
- self.response("215 FTP Dummy Server (SYST)")
- end
+ def syst
+ self.response("215 FTP Dummy Server (SYST)")
+ end
- def type(type)
- self.response("200 TYPE switched to #{type}")
- end
+ def type(type)
+ self.response("200 TYPE switched to #{type}")
+ end
- def user(name)
- @login_user = name
- self.response("230 User logged in, proceed. (USER #{name})")
+ def user(name)
+ @login_user = name
+ self.response("230 User logged in, proceed. (USER #{name})")
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/get_spec.rb b/spec/ruby/library/net-ftp/get_spec.rb
index 1bc1bd744b..6a8aa3e206 100644
--- a/spec/ruby/library/net-ftp/get_spec.rb
+++ b/spec/ruby/library/net-ftp/get_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/gettextfile'
-require_relative 'shared/getbinaryfile'
-describe "Net::FTP#get (binary mode)" do
- before :each do
- @binary_mode = true
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/gettextfile'
+ require_relative 'shared/getbinaryfile'
- it_behaves_like :net_ftp_getbinaryfile, :get
-end
+ describe "Net::FTP#get (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
-describe "Net::FTP#get (text mode)" do
- before :each do
- @binary_mode = false
+ it_behaves_like :net_ftp_getbinaryfile, :get
end
- it_behaves_like :net_ftp_gettextfile, :get
+ describe "Net::FTP#get (text mode)" do
+ before :each do
+ @binary_mode = false
+ end
+
+ it_behaves_like :net_ftp_gettextfile, :get
+ end
end
diff --git a/spec/ruby/library/net-ftp/getbinaryfile_spec.rb b/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
index e9898fccc7..6b2d38edf5 100644
--- a/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
+++ b/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/getbinaryfile'
-describe "Net::FTP#getbinaryfile" do
- it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/getbinaryfile'
+
+ describe "Net::FTP#getbinaryfile" do
+ it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
+ end
end
diff --git a/spec/ruby/library/net-ftp/getdir_spec.rb b/spec/ruby/library/net-ftp/getdir_spec.rb
index 756d6a23af..2ff62d399d 100644
--- a/spec/ruby/library/net-ftp/getdir_spec.rb
+++ b/spec/ruby/library/net-ftp/getdir_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/pwd'
-describe "Net::FTP#getdir" do
- it_behaves_like :net_ftp_pwd, :getdir
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/pwd'
+
+ describe "Net::FTP#getdir" do
+ it_behaves_like :net_ftp_pwd, :getdir
+ end
end
diff --git a/spec/ruby/library/net-ftp/gettextfile_spec.rb b/spec/ruby/library/net-ftp/gettextfile_spec.rb
index cdd1b4c797..3bb037663b 100644
--- a/spec/ruby/library/net-ftp/gettextfile_spec.rb
+++ b/spec/ruby/library/net-ftp/gettextfile_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/gettextfile'
-describe "Net::FTP#gettextfile" do
- it_behaves_like :net_ftp_gettextfile, :gettextfile
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/gettextfile'
+
+ describe "Net::FTP#gettextfile" do
+ it_behaves_like :net_ftp_gettextfile, :gettextfile
+ end
end
diff --git a/spec/ruby/library/net-ftp/help_spec.rb b/spec/ruby/library/net-ftp/help_spec.rb
index c562be50b2..bb52fb9e69 100644
--- a/spec/ruby/library/net-ftp/help_spec.rb
+++ b/spec/ruby/library/net-ftp/help_spec.rb
@@ -1,66 +1,69 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#help" do
- def with_connection
- yield
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ describe "Net::FTP#help" do
+ def with_connection
+ yield
+ end
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "writes the HELP command to the server" do
- @ftp.help
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the server's response" do
- @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
- end
+ it "writes the HELP command to the server" do
+ @ftp.help
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
- it "writes the HELP command with an optional parameter to the socket" do
- @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
- end
+ it "returns the server's response" do
+ @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
+ end
- it "does not raise any error when the response code is 211" do
- @server.should_receive(:help).and_respond("211 System status, or system help reply.")
- -> { @ftp.help }.should_not raise_error
- end
+ it "writes the HELP command with an optional parameter to the socket" do
+ @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
+ end
- it "does not raise any error when the response code is 214" do
- @server.should_receive(:help).and_respond("214 Help message.")
- -> { @ftp.help }.should_not raise_error
- end
+ it "does not raise any error when the response code is 211" do
+ @server.should_receive(:help).and_respond("211 System status, or system help reply.")
+ -> { @ftp.help }.should_not.raise
+ end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
+ it "does not raise any error when the response code is 214" do
+ @server.should_receive(:help).and_respond("214 Help message.")
+ -> { @ftp.help }.should_not.raise
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.help }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:help).and_respond("502 Command not implemented.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.help }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:help).and_respond("502 Command not implemented.")
+ -> { @ftp.help }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.help }.should raise_error(Net::FTPTempError)
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.help }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/initialize_spec.rb b/spec/ruby/library/net-ftp/initialize_spec.rb
index 4d775e8dc1..9079ad6b79 100644
--- a/spec/ruby/library/net-ftp/initialize_spec.rb
+++ b/spec/ruby/library/net-ftp/initialize_spec.rb
@@ -1,402 +1,405 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#initialize" do
- before :each do
- @ftp = Net::FTP.allocate
- @ftp.stub!(:connect)
- @port_args = []
- @port_args << 21
- end
- it "is private" do
- Net::FTP.should have_private_instance_method(:initialize)
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- it "sets self into binary mode" do
- @ftp.binary.should be_nil
- @ftp.send(:initialize)
- @ftp.binary.should be_true
- end
-
- it "sets self into active mode" do
- @ftp.passive.should be_nil
- @ftp.send(:initialize)
- @ftp.passive.should be_false
- end
+ describe "Net::FTP#initialize" do
+ before :each do
+ @ftp = Net::FTP.allocate
+ @ftp.stub!(:connect)
+ @port_args = []
+ @port_args << 21
+ end
- it "sets self into non-debug mode" do
- @ftp.debug_mode.should be_nil
- @ftp.send(:initialize)
- @ftp.debug_mode.should be_false
- end
+ it "is private" do
+ Net::FTP.private_instance_methods(false).should.include?(:initialize)
+ end
- it "sets self to not resume file uploads/downloads" do
- @ftp.resume.should be_nil
- @ftp.send(:initialize)
- @ftp.resume.should be_false
- end
+ it "sets self into binary mode" do
+ @ftp.binary.should == nil
+ @ftp.send(:initialize)
+ @ftp.binary.should == true
+ end
- describe "when passed no arguments" do
- it "does not try to connect" do
- @ftp.should_not_receive(:connect)
+ it "sets self into active mode" do
+ @ftp.passive.should == nil
@ftp.send(:initialize)
+ @ftp.passive.should == false
end
- end
- describe "when passed host" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
+ it "sets self into non-debug mode" do
+ @ftp.debug_mode.should == nil
+ @ftp.send(:initialize)
+ @ftp.debug_mode.should == false
end
- end
- describe "when passed host, user" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
+ it "sets self to not resume file uploads/downloads" do
+ @ftp.resume.should == nil
+ @ftp.send(:initialize)
+ @ftp.resume.should == false
end
- it "tries to login with the passed username" do
- @ftp.should_receive(:login).with("rubyspec", nil, nil)
- @ftp.send(:initialize, "localhost", "rubyspec")
+ describe "when passed no arguments" do
+ it "does not try to connect" do
+ @ftp.should_not_receive(:connect)
+ @ftp.send(:initialize)
+ end
end
- end
- describe "when passed host, user, password" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
+ describe "when passed host" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
end
- it "tries to login with the passed username and password" do
- @ftp.should_receive(:login).with("rubyspec", "rocks", nil)
- @ftp.send(:initialize, "localhost", "rubyspec", "rocks")
+ describe "when passed host, user" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username" do
+ @ftp.should_receive(:login).with("rubyspec", nil, nil)
+ @ftp.send(:initialize, "localhost", "rubyspec")
+ end
end
- end
- describe "when passed host, user" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
+ describe "when passed host, user, password" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username and password" do
+ @ftp.should_receive(:login).with("rubyspec", "rocks", nil)
+ @ftp.send(:initialize, "localhost", "rubyspec", "rocks")
+ end
end
- it "tries to login with the passed username, password and account" do
- @ftp.should_receive(:login).with("rubyspec", "rocks", "account")
- @ftp.send(:initialize, "localhost", "rubyspec", "rocks", "account")
+ describe "when passed host, user" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username, password and account" do
+ @ftp.should_receive(:login).with("rubyspec", "rocks", "account")
+ @ftp.send(:initialize, "localhost", "rubyspec", "rocks", "account")
+ end
end
- end
- before :each do
- @ftp.stub!(:login)
- end
+ before :each do
+ @ftp.stub!(:login)
+ end
- describe 'when the host' do
- describe 'is set' do
- describe 'and port option' do
- describe 'is set' do
- it 'tries to connect to the host on the specified port' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ port: 8080 })
- @ftp.should_receive(:connect).with('localhost', 8080)
+ describe 'when the host' do
+ describe 'is set' do
+ describe 'and port option' do
+ describe 'is set' do
+ it 'tries to connect to the host on the specified port' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ port: 8080 })
+ @ftp.should_receive(:connect).with('localhost', 8080)
- @ftp.send(:initialize, 'localhost', options)
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
- end
- describe 'is not set' do
- it 'tries to connect to the host without a port' do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
+ describe 'is not set' do
+ it 'tries to connect to the host without a port' do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, 'localhost')
+ @ftp.send(:initialize, 'localhost')
+ end
end
end
- end
- describe 'when the username option' do
- describe 'is set' do
- describe 'and the password option' do
- describe 'is set' do
- describe 'and the account option' do
- describe 'is set' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret', account: 'b' })
- @ftp.should_receive(:login).with('a', 'topsecret', 'b')
-
- @ftp.send(:initialize, 'localhost', options)
+ describe 'when the username option' do
+ describe 'is set' do
+ describe 'and the password option' do
+ describe 'is set' do
+ describe 'and the account option' do
+ describe 'is set' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret', account: 'b' })
+ @ftp.should_receive(:login).with('a', 'topsecret', 'b')
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
- end
- describe 'is unset' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret' })
- @ftp.should_receive(:login).with('a', 'topsecret', nil)
+ describe 'is unset' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret' })
+ @ftp.should_receive(:login).with('a', 'topsecret', nil)
- @ftp.send(:initialize, 'localhost', options)
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
end
end
- end
- describe 'is unset' do
- describe 'and the account option' do
- describe 'is set' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', account: 'b' })
- @ftp.should_receive(:login).with('a', nil, 'b')
+ describe 'is unset' do
+ describe 'and the account option' do
+ describe 'is set' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', account: 'b' })
+ @ftp.should_receive(:login).with('a', nil, 'b')
- @ftp.send(:initialize, 'localhost', options)
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
- end
- describe 'is unset' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a'})
- @ftp.should_receive(:login).with('a', nil, nil)
+ describe 'is unset' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a'})
+ @ftp.should_receive(:login).with('a', nil, nil)
- @ftp.send(:initialize, 'localhost', options)
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
end
end
end
end
- end
- describe 'is not set' do
- it 'does not try to log in' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
- @ftp.should_not_receive(:login)
+ describe 'is not set' do
+ it 'does not try to log in' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+ @ftp.should_not_receive(:login)
- @ftp.send(:initialize, 'localhost', options)
+ @ftp.send(:initialize, 'localhost', options)
+ end
end
end
end
- end
- describe 'is unset' do
- it 'does not try to connect' do
- @ftp.should_not_receive(:connect)
+ describe 'is unset' do
+ it 'does not try to connect' do
+ @ftp.should_not_receive(:connect)
- @ftp.send(:initialize)
- end
+ @ftp.send(:initialize)
+ end
- it 'does not try to log in' do
- @ftp.should_not_receive(:login)
+ it 'does not try to log in' do
+ @ftp.should_not_receive(:login)
- @ftp.send(:initialize)
+ @ftp.send(:initialize)
+ end
end
end
- end
- describe 'when the passive option' do
- describe 'is set' do
- describe 'to true' do
- it 'sets passive to true' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ passive: true })
+ describe 'when the passive option' do
+ describe 'is set' do
+ describe 'to true' do
+ it 'sets passive to true' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ passive: true })
- @ftp.send(:initialize, nil, options)
- @ftp.passive.should == true
+ @ftp.send(:initialize, nil, options)
+ @ftp.passive.should == true
+ end
+ end
+
+ describe 'to false' do
+ it 'sets passive to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ passive: false })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.passive.should == false
+ end
end
end
- describe 'to false' do
+ describe 'is unset' do
it 'sets passive to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ passive: false })
-
- @ftp.send(:initialize, nil, options)
+ @ftp.send(:initialize)
@ftp.passive.should == false
end
end
end
- describe 'is unset' do
- it 'sets passive to false' do
- @ftp.send(:initialize)
- @ftp.passive.should == false
- end
- end
- end
+ describe 'when the debug_mode option' do
+ describe 'is set' do
+ describe 'to true' do
+ it 'sets debug_mode to true' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ debug_mode: true })
- describe 'when the debug_mode option' do
- describe 'is set' do
- describe 'to true' do
- it 'sets debug_mode to true' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ debug_mode: true })
+ @ftp.send(:initialize, nil, options)
+ @ftp.debug_mode.should == true
+ end
+ end
- @ftp.send(:initialize, nil, options)
- @ftp.debug_mode.should == true
+ describe 'to false' do
+ it 'sets debug_mode to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ debug_mode: false })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.debug_mode.should == false
+ end
end
end
- describe 'to false' do
+ describe 'is unset' do
it 'sets debug_mode to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ debug_mode: false })
-
- @ftp.send(:initialize, nil, options)
+ @ftp.send(:initialize)
@ftp.debug_mode.should == false
end
end
end
- describe 'is unset' do
- it 'sets debug_mode to false' do
- @ftp.send(:initialize)
- @ftp.debug_mode.should == false
- end
- end
- end
-
- describe 'when the open_timeout option' do
- describe 'is set' do
- it 'sets open_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ open_timeout: 42 })
+ describe 'when the open_timeout option' do
+ describe 'is set' do
+ it 'sets open_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ open_timeout: 42 })
- @ftp.send(:initialize, nil, options)
- @ftp.open_timeout.should == 42
+ @ftp.send(:initialize, nil, options)
+ @ftp.open_timeout.should == 42
+ end
end
- end
- describe 'is not set' do
- it 'sets open_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.open_timeout.should == nil
+ describe 'is not set' do
+ it 'sets open_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.open_timeout.should == nil
+ end
end
end
- end
- describe 'when the read_timeout option' do
- describe 'is set' do
- it 'sets read_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ read_timeout: 100 })
+ describe 'when the read_timeout option' do
+ describe 'is set' do
+ it 'sets read_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ read_timeout: 100 })
- @ftp.send(:initialize, nil, options)
- @ftp.read_timeout.should == 100
+ @ftp.send(:initialize, nil, options)
+ @ftp.read_timeout.should == 100
+ end
end
- end
- describe 'is not set' do
- it 'sets read_timeout to the default value' do
- @ftp.send(:initialize)
- @ftp.read_timeout.should == 60
+ describe 'is not set' do
+ it 'sets read_timeout to the default value' do
+ @ftp.send(:initialize)
+ @ftp.read_timeout.should == 60
+ end
end
end
- end
- describe 'when the ssl_handshake_timeout option' do
- describe 'is set' do
- it 'sets ssl_handshake_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl_handshake_timeout: 23 })
+ describe 'when the ssl_handshake_timeout option' do
+ describe 'is set' do
+ it 'sets ssl_handshake_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl_handshake_timeout: 23 })
- @ftp.send(:initialize, nil, options)
- @ftp.ssl_handshake_timeout.should == 23
+ @ftp.send(:initialize, nil, options)
+ @ftp.ssl_handshake_timeout.should == 23
+ end
end
- end
- describe 'is not set' do
- it 'sets ssl_handshake_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.ssl_handshake_timeout.should == nil
+ describe 'is not set' do
+ it 'sets ssl_handshake_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.ssl_handshake_timeout.should == nil
+ end
end
end
- end
- describe 'when the ssl option' do
- describe 'is set' do
- describe "and the ssl option's value is true" do
- it 'initializes ssl_context to a blank SSLContext object' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true })
+ describe 'when the ssl option' do
+ describe 'is set' do
+ describe "and the ssl option's value is true" do
+ it 'initializes ssl_context to a blank SSLContext object' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true })
- ssl_context = OpenSSL::SSL::SSLContext.allocate
- ssl_context.stub!(:set_params)
+ ssl_context = OpenSSL::SSL::SSLContext.allocate
+ ssl_context.stub!(:set_params)
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
- ssl_context.should_receive(:set_params).with({})
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
+ ssl_context.should_receive(:set_params).with({})
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
end
- end
- describe "and the ssl option's value is a hash" do
- it 'initializes ssl_context to a configured SSLContext object' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: {key: 'value'} })
+ describe "and the ssl option's value is a hash" do
+ it 'initializes ssl_context to a configured SSLContext object' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: {key: 'value'} })
- ssl_context = OpenSSL::SSL::SSLContext.allocate
- ssl_context.stub!(:set_params)
+ ssl_context = OpenSSL::SSL::SSLContext.allocate
+ ssl_context.stub!(:set_params)
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
- ssl_context.should_receive(:set_params).with({key: 'value'})
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
+ ssl_context.should_receive(:set_params).with({key: 'value'})
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
end
- end
- describe 'and private_data_connection' do
- describe 'is set' do
- it 'sets private_data_connection to that value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true, private_data_connection: 'true' })
+ describe 'and private_data_connection' do
+ describe 'is set' do
+ it 'sets private_data_connection to that value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true, private_data_connection: 'true' })
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == 'true'
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == 'true'
+ end
end
- end
- describe 'is not set' do
- it 'sets private_data_connection to nil' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true })
+ describe 'is not set' do
+ it 'sets private_data_connection to nil' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true })
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == true
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == true
+ end
end
end
end
- end
- describe 'is not set' do
- it 'sets ssl_context to nil' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
+ describe 'is not set' do
+ it 'sets ssl_context to nil' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == nil
- end
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == nil
+ end
- describe 'private_data_connection' do
- describe 'is set' do
- it 'raises an ArgumentError' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ private_data_connection: true })
+ describe 'private_data_connection' do
+ describe 'is set' do
+ it 'raises an ArgumentError' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ private_data_connection: true })
- -> {
- @ftp.send(:initialize, nil, options)
- }.should raise_error(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
+ -> {
+ @ftp.send(:initialize, nil, options)
+ }.should.raise(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
+ end
end
- end
- describe 'is not set' do
- it 'sets private_data_connection to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
+ describe 'is not set' do
+ it 'sets private_data_connection to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == false
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == false
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/last_response_code_spec.rb b/spec/ruby/library/net-ftp/last_response_code_spec.rb
index c17c28f0f8..03329758b5 100644
--- a/spec/ruby/library/net-ftp/last_response_code_spec.rb
+++ b/spec/ruby/library/net-ftp/last_response_code_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/last_response_code'
-require_relative 'fixtures/server'
-describe "Net::FTP#last_response_code" do
- it_behaves_like :net_ftp_last_response_code, :last_response_code
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/last_response_code'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#last_response_code" do
+ it_behaves_like :net_ftp_last_response_code, :last_response_code
+ end
end
diff --git a/spec/ruby/library/net-ftp/last_response_spec.rb b/spec/ruby/library/net-ftp/last_response_spec.rb
index c9d9d70f35..7cda9fa7a4 100644
--- a/spec/ruby/library/net-ftp/last_response_spec.rb
+++ b/spec/ruby/library/net-ftp/last_response_spec.rb
@@ -1,25 +1,28 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#last_response" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#last_response" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the last response" do
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- @ftp.help
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ it "returns the last response" do
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
+ @ftp.help
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/lastresp_spec.rb b/spec/ruby/library/net-ftp/lastresp_spec.rb
index e0c1b862a0..c373670ec4 100644
--- a/spec/ruby/library/net-ftp/lastresp_spec.rb
+++ b/spec/ruby/library/net-ftp/lastresp_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/last_response_code'
-require_relative 'fixtures/server'
-describe "Net::FTP#lastresp" do
- it_behaves_like :net_ftp_last_response_code, :lastresp
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/last_response_code'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#lastresp" do
+ it_behaves_like :net_ftp_last_response_code, :lastresp
+ end
end
diff --git a/spec/ruby/library/net-ftp/list_spec.rb b/spec/ruby/library/net-ftp/list_spec.rb
index 6cb1bbc4b8..297d100dd9 100644
--- a/spec/ruby/library/net-ftp/list_spec.rb
+++ b/spec/ruby/library/net-ftp/list_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/list'
-describe "Net::FTP#list" do
- it_behaves_like :net_ftp_list, :list
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/list'
+
+ describe "Net::FTP#list" do
+ it_behaves_like :net_ftp_list, :list
+ end
end
diff --git a/spec/ruby/library/net-ftp/login_spec.rb b/spec/ruby/library/net-ftp/login_spec.rb
index 0de2f5cc63..05bb6b7f81 100644
--- a/spec/ruby/library/net-ftp/login_spec.rb
+++ b/spec/ruby/library/net-ftp/login_spec.rb
@@ -1,195 +1,198 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#login" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed no arguments" do
- it "sends the USER command with 'anonymous' as name to the server" do
- @ftp.login
- @server.login_user.should == "anonymous"
- end
-
- it "sends 'anonymous@' as a password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login
- @server.login_pass.should == "anonymous@"
- end
-
- it "raises a Net::FTPReplyError when the server requests an account" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec")
- @server.login_user.should == "rubyspec"
- end
-
- it "raises a Net::FTPReplyError when the server requests a password, but none was given" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPReplyError when the server requests an account, but none was given" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name, password" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec", "rocks")
- @server.login_user.should == "rubyspec"
- end
-
- it "sends the passed password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login("rubyspec", "rocks")
- @server.login_pass.should == "rocks"
- end
-
- it "raises a Net::FTPReplyError when the server requests an account" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login("rubyspec", "rocks") }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name, password, account" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_user.should == "rubyspec"
- end
-
- it "sends the passed password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_pass.should == "rocks"
- end
-
- it "sends the passed account when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_acct.should == "account"
- end
- end
-
- describe "when the USER command fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:user).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:user).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:user).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:user).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:user).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the PASS command fails" do
+ describe "Net::FTP#login" do
before :each do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- end
-
- it "does not raise an Error when the response code is 202" do
- @server.should_receive(:pass).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:pass).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:pass).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:pass).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:pass).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:pass).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the ACCT command fails" do
- before :each do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- end
-
- it "does not raise an Error when the response code is 202" do
- @server.should_receive(:acct).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:acct).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:acct).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed no arguments" do
+ it "sends the USER command with 'anonymous' as name to the server" do
+ @ftp.login
+ @server.login_user.should == "anonymous"
+ end
+
+ it "sends 'anonymous@' as a password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login
+ @server.login_pass.should == "anonymous@"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login }.should.raise(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests a password, but none was given" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ -> { @ftp.login("rubyspec") }.should.raise(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account, but none was given" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login("rubyspec") }.should.raise(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name, password" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec", "rocks")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "sends the passed password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login("rubyspec", "rocks")
+ @server.login_pass.should == "rocks"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login("rubyspec", "rocks") }.should.raise(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name, password, account" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "sends the passed password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_pass.should == "rocks"
+ end
+
+ it "sends the passed account when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_acct.should == "account"
+ end
+ end
+
+ describe "when the USER command fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:user).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:user).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:user).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:user).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:user).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+ end
+
+ describe "when the PASS command fails" do
+ before :each do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ end
+
+ it "does not raise an Error when the response code is 202" do
+ @server.should_receive(:pass).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should_not.raise
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:pass).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:pass).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:pass).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:pass).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:pass).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+ end
+
+ describe "when the ACCT command fails" do
+ before :each do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ end
+
+ it "does not raise an Error when the response code is 202" do
+ @server.should_receive(:acct).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should_not.raise
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:acct).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:acct).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/ls_spec.rb b/spec/ruby/library/net-ftp/ls_spec.rb
index acd7e9e523..f8fdb10e8f 100644
--- a/spec/ruby/library/net-ftp/ls_spec.rb
+++ b/spec/ruby/library/net-ftp/ls_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/list'
-describe "Net::FTP#ls" do
- it_behaves_like :net_ftp_list, :ls
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/list'
+
+ describe "Net::FTP#ls" do
+ it_behaves_like :net_ftp_list, :ls
+ end
end
diff --git a/spec/ruby/library/net-ftp/mdtm_spec.rb b/spec/ruby/library/net-ftp/mdtm_spec.rb
index a504507c84..effd22a6e4 100644
--- a/spec/ruby/library/net-ftp/mdtm_spec.rb
+++ b/spec/ruby/library/net-ftp/mdtm_spec.rb
@@ -1,38 +1,41 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#mdtm" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#mdtm" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the MDTM with the passed filename command to the server" do
- @ftp.mdtm("test.file")
- @ftp.last_response.should == "213 19980705132316\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the last modification time of the passed file" do
- @ftp.mdtm("test.file").should == "19980705132316"
- end
+ it "sends the MDTM with the passed filename command to the server" do
+ @ftp.mdtm("test.file")
+ @ftp.last_response.should == "213 19980705132316\n"
+ end
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
- -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPPermError)
- end
+ it "returns the last modification time of the passed file" do
+ @ftp.mdtm("test.file").should == "19980705132316"
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
+ -> { @ftp.mdtm("test.file") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPTempError)
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mdtm("test.file") }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/mkdir_spec.rb b/spec/ruby/library/net-ftp/mkdir_spec.rb
index 8cc6ae785e..6daeb7c022 100644
--- a/spec/ruby/library/net-ftp/mkdir_spec.rb
+++ b/spec/ruby/library/net-ftp/mkdir_spec.rb
@@ -1,61 +1,64 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#mkdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#mkdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the MKD command with the passed pathname to the server" do
- @ftp.mkdir("test.folder")
- @ftp.last_response.should == %{257 "test.folder" created.\n}
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the path to the newly created directory" do
- @ftp.mkdir("test.folder").should == "test.folder"
- @ftp.mkdir("/absolute/path/to/test.folder").should == "/absolute/path/to/test.folder"
- @ftp.mkdir("relative/path/to/test.folder").should == "relative/path/to/test.folder"
- @ftp.mkdir('/usr/dm/foo"bar').should == '/usr/dm/foo"bar'
- end
+ it "sends the MKD command with the passed pathname to the server" do
+ @ftp.mkdir("test.folder")
+ @ftp.last_response.should == %{257 "test.folder" created.\n}
+ end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
+ it "returns the path to the newly created directory" do
+ @ftp.mkdir("test.folder").should == "test.folder"
+ @ftp.mkdir("/absolute/path/to/test.folder").should == "/absolute/path/to/test.folder"
+ @ftp.mkdir("relative/path/to/test.folder").should == "relative/path/to/test.folder"
+ @ftp.mkdir('/usr/dm/foo"bar').should == '/usr/dm/foo"bar'
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:mkd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:mkd).and_respond("502 Command not implemented.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:mkd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mkd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPTempError)
- end
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:mkd).and_respond("502 Command not implemented.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:mkd).and_respond("530 Not logged in.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mkd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:mkd).and_respond("530 Not logged in.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mkd).and_respond("550 Requested action not taken.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mkd).and_respond("550 Requested action not taken.")
+ -> { @ftp.mkdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/mtime_spec.rb b/spec/ruby/library/net-ftp/mtime_spec.rb
index 9dde1278a8..694036a296 100644
--- a/spec/ruby/library/net-ftp/mtime_spec.rb
+++ b/spec/ruby/library/net-ftp/mtime_spec.rb
@@ -1,50 +1,53 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#mtime" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#mtime" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the MDTM with the passed filename command to the server" do
- @ftp.mtime("test.file")
- @ftp.last_response.should == "213 19980705132316\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- describe "when passed filename" do
- it "returns the last modification time of the passed file as a Time object in the local time" do
- @ftp.mtime("test.file").should == Time.gm("1998", "07", "05", "13", "23", "16")
+ it "sends the MDTM with the passed filename command to the server" do
+ @ftp.mtime("test.file")
+ @ftp.last_response.should == "213 19980705132316\n"
end
- end
- describe "when passed filename, local_time" do
- it "returns the last modification time as a Time object in UTC when local_time is true" do
- @ftp.mtime("test.file", true).should == Time.local("1998", "07", "05", "13", "23", "16")
+ describe "when passed filename" do
+ it "returns the last modification time of the passed file as a Time object in the local time" do
+ @ftp.mtime("test.file").should == Time.gm("1998", "07", "05", "13", "23", "16")
+ end
end
- it "returns the last modification time as a Time object in the local time when local_time is false" do
- @ftp.mtime("test.file", false).should == Time.gm("1998", "07", "05", "13", "23", "16")
+ describe "when passed filename, local_time" do
+ it "returns the last modification time as a Time object in UTC when local_time is true" do
+ @ftp.mtime("test.file", true).should == Time.local("1998", "07", "05", "13", "23", "16")
+ end
+
+ it "returns the last modification time as a Time object in the local time when local_time is false" do
+ @ftp.mtime("test.file", false).should == Time.gm("1998", "07", "05", "13", "23", "16")
+ end
end
- end
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
- -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
+ -> { @ftp.mtime("test.file") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPTempError)
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mtime("test.file") }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/nlst_spec.rb b/spec/ruby/library/net-ftp/nlst_spec.rb
index 2f22543af6..87b80b43fd 100644
--- a/spec/ruby/library/net-ftp/nlst_spec.rb
+++ b/spec/ruby/library/net-ftp/nlst_spec.rb
@@ -1,92 +1,95 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#nlst" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.passive = false
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ describe "Net::FTP#nlst" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- describe "when passed no arguments" do
- it "returns an Array containing a list of files in the current dir" do
- @ftp.nlst.should == ["last_response_code.rb", "list.rb", "pwd.rb"]
- @ftp.last_response.should == "226 transfer complete (NLST)\n"
+ @ftp = Net::FTP.new
+ @ftp.passive = false
+ @ftp.connect(@server.hostname, @server.server_port)
end
- end
- describe "when passed dir" do
- it "returns an Array containing a list of files in the passed dir" do
- @ftp.nlst("test.folder").should == ["last_response_code.rb", "list.rb", "pwd.rb"]
- @ftp.last_response.should == "226 transfer complete (NLST test.folder)\n"
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
end
- end
- describe "when the NLST command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:nlst).and_respond("450 Requested file action not taken..")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ describe "when passed no arguments" do
+ it "returns an Array containing a list of files in the current dir" do
+ @ftp.nlst.should == ["last_response_code.rb", "list.rb", "pwd.rb"]
+ @ftp.last_response.should == "226 transfer complete (NLST)\n"
+ end
end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ describe "when passed dir" do
+ it "returns an Array containing a list of files in the passed dir" do
+ @ftp.nlst("test.folder").should == ["last_response_code.rb", "list.rb", "pwd.rb"]
+ @ftp.last_response.should == "226 transfer complete (NLST test.folder)\n"
+ end
end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
+ describe "when the NLST command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:nlst).and_respond("450 Requested file action not taken..")
+ -> { @ftp.nlst }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:nlst).and_respond("502 Command not implemented.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:nlst).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:nlst).and_respond("530 Not logged in.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
- end
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:nlst).and_respond("502 Command not implemented.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:nlst).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.nlst }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:nlst).and_respond("530 Not logged in.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.nlst }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.nlst }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/noop_spec.rb b/spec/ruby/library/net-ftp/noop_spec.rb
index 4743a39ef6..43c48e355a 100644
--- a/spec/ruby/library/net-ftp/noop_spec.rb
+++ b/spec/ruby/library/net-ftp/noop_spec.rb
@@ -1,38 +1,41 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#noop" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#noop" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the NOOP command to the server" do
- @ftp.noop
- @ftp.last_response.should == "200 Command okay. (NOOP)\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns nil" do
- @ftp.noop.should be_nil
- end
+ it "sends the NOOP command to the server" do
+ @ftp.noop
+ @ftp.last_response.should == "200 Command okay. (NOOP)\n"
+ end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:noop).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.noop }.should raise_error(Net::FTPPermError)
- end
+ it "returns nil" do
+ @ftp.noop.should == nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:noop).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.noop }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:noop).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.noop }.should raise_error(Net::FTPTempError)
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:noop).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.noop }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/open_spec.rb b/spec/ruby/library/net-ftp/open_spec.rb
index e59496dc3c..2d6477ec4d 100644
--- a/spec/ruby/library/net-ftp/open_spec.rb
+++ b/spec/ruby/library/net-ftp/open_spec.rb
@@ -1,55 +1,58 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP.open" do
- before :each do
- @ftp = mock("Net::FTP instance")
- Net::FTP.stub!(:new).and_return(@ftp)
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- describe "when passed no block" do
- it "returns a new Net::FTP instance" do
- Net::FTP.open("localhost").should equal(@ftp)
+ describe "Net::FTP.open" do
+ before :each do
+ @ftp = mock("Net::FTP instance")
+ Net::FTP.stub!(:new).and_return(@ftp)
end
- it "passes the passed arguments down to Net::FTP.new" do
- Net::FTP.should_receive(:new).with("localhost", "user", "password", "account")
- Net::FTP.open("localhost", "user", "password", "account")
- end
- end
+ describe "when passed no block" do
+ it "returns a new Net::FTP instance" do
+ Net::FTP.open("localhost").should.equal?(@ftp)
+ end
- describe "when passed a block" do
- before :each do
- @ftp.stub!(:close)
+ it "passes the passed arguments down to Net::FTP.new" do
+ Net::FTP.should_receive(:new).with("localhost", "user", "password", "account")
+ Net::FTP.open("localhost", "user", "password", "account")
+ end
end
- it "yields a new Net::FTP instance to the passed block" do
- yielded = false
- Net::FTP.open("localhost") do |ftp|
- yielded = true
- ftp.should equal(@ftp)
+ describe "when passed a block" do
+ before :each do
+ @ftp.stub!(:close)
end
- yielded.should be_true
- end
- it "closes the Net::FTP instance after yielding" do
- Net::FTP.open("localhost") do |ftp|
- ftp.should_receive(:close)
+ it "yields a new Net::FTP instance to the passed block" do
+ yielded = false
+ Net::FTP.open("localhost") do |ftp|
+ yielded = true
+ ftp.should.equal?(@ftp)
+ end
+ yielded.should == true
end
- end
- it "closes the Net::FTP instance even if an exception is raised while yielding" do
- begin
+ it "closes the Net::FTP instance after yielding" do
Net::FTP.open("localhost") do |ftp|
ftp.should_receive(:close)
- raise ArgumentError, "some exception"
end
- rescue ArgumentError
end
- end
- it "returns the block's return value" do
- Net::FTP.open("localhost") { :test }.should == :test
+ it "closes the Net::FTP instance even if an exception is raised while yielding" do
+ begin
+ Net::FTP.open("localhost") do |ftp|
+ ftp.should_receive(:close)
+ raise ArgumentError, "some exception"
+ end
+ rescue ArgumentError
+ end
+ end
+
+ it "returns the block's return value" do
+ Net::FTP.open("localhost") { :test }.should == :test
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/passive_spec.rb b/spec/ruby/library/net-ftp/passive_spec.rb
index 97659f1b68..6acabd3f98 100644
--- a/spec/ruby/library/net-ftp/passive_spec.rb
+++ b/spec/ruby/library/net-ftp/passive_spec.rb
@@ -1,28 +1,31 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#passive" do
- it "returns true when self is in passive mode" do
- ftp = Net::FTP.new
- ftp.passive.should be_false
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.passive = true
- ftp.passive.should be_true
- end
+ describe "Net::FTP#passive" do
+ it "returns true when self is in passive mode" do
+ ftp = Net::FTP.new
+ ftp.passive.should == false
+
+ ftp.passive = true
+ ftp.passive.should == true
+ end
- it "is the value of Net::FTP.default_value by default" do
- ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
+ it "is the value of Net::FTP.default_value by default" do
+ ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
+ end
end
-end
-describe "Net::FTP#passive=" do
- it "sets self to passive mode when passed true" do
- ftp = Net::FTP.new
+ describe "Net::FTP#passive=" do
+ it "sets self to passive mode when passed true" do
+ ftp = Net::FTP.new
- ftp.passive = true
- ftp.passive.should be_true
+ ftp.passive = true
+ ftp.passive.should == true
- ftp.passive = false
- ftp.passive.should be_false
+ ftp.passive = false
+ ftp.passive.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/put_spec.rb b/spec/ruby/library/net-ftp/put_spec.rb
index 6d40d3d5b9..603409e283 100644
--- a/spec/ruby/library/net-ftp/put_spec.rb
+++ b/spec/ruby/library/net-ftp/put_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/puttextfile'
-require_relative 'shared/putbinaryfile'
-describe "Net::FTP#put (binary mode)" do
- before :each do
- @binary_mode = true
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/puttextfile'
+ require_relative 'shared/putbinaryfile'
- it_behaves_like :net_ftp_putbinaryfile, :put
-end
+ describe "Net::FTP#put (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
-describe "Net::FTP#put (text mode)" do
- before :each do
- @binary_mode = false
+ it_behaves_like :net_ftp_putbinaryfile, :put
end
- it_behaves_like :net_ftp_puttextfile, :put
+ describe "Net::FTP#put (text mode)" do
+ before :each do
+ @binary_mode = false
+ end
+
+ it_behaves_like :net_ftp_puttextfile, :put
+ end
end
diff --git a/spec/ruby/library/net-ftp/putbinaryfile_spec.rb b/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
index d0398229e5..ce8a6f0473 100644
--- a/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
+++ b/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/putbinaryfile'
-describe "Net::FTP#putbinaryfile" do
- it_behaves_like :net_ftp_putbinaryfile, :putbinaryfile
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/putbinaryfile'
+
+ describe "Net::FTP#putbinaryfile" do
+ it_behaves_like :net_ftp_putbinaryfile, :putbinaryfile
+ end
end
diff --git a/spec/ruby/library/net-ftp/puttextfile_spec.rb b/spec/ruby/library/net-ftp/puttextfile_spec.rb
index b8bcac33df..b4ab86aab1 100644
--- a/spec/ruby/library/net-ftp/puttextfile_spec.rb
+++ b/spec/ruby/library/net-ftp/puttextfile_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/puttextfile'
-describe "Net::FTP#puttextfile" do
- it_behaves_like :net_ftp_puttextfile, :puttextfile
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/puttextfile'
+
+ describe "Net::FTP#puttextfile" do
+ it_behaves_like :net_ftp_puttextfile, :puttextfile
+ end
end
diff --git a/spec/ruby/library/net-ftp/pwd_spec.rb b/spec/ruby/library/net-ftp/pwd_spec.rb
index 992e2c4ed2..53692b553f 100644
--- a/spec/ruby/library/net-ftp/pwd_spec.rb
+++ b/spec/ruby/library/net-ftp/pwd_spec.rb
@@ -1,53 +1,56 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#pwd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the PWD command to the server" do
- @ftp.pwd
- @ftp.last_response.should == "257 \"/some/dir/\" - current directory\n"
- end
-
- it "returns the current directory" do
- @ftp.pwd.should == "/some/dir/"
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:pwd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:pwd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:pwd).and_respond("502 Command not implemented.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:pwd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.pwd }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:pwd).and_respond("550 Requested action not taken.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#pwd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the PWD command to the server" do
+ @ftp.pwd
+ @ftp.last_response.should == "257 \"/some/dir/\" - current directory\n"
+ end
+
+ it "returns the current directory" do
+ @ftp.pwd.should == "/some/dir/"
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:pwd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.pwd }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:pwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.pwd }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:pwd).and_respond("502 Command not implemented.")
+ -> { @ftp.pwd }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:pwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.pwd }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:pwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.pwd }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/quit_spec.rb b/spec/ruby/library/net-ftp/quit_spec.rb
index c5352ceada..1af0107d34 100644
--- a/spec/ruby/library/net-ftp/quit_spec.rb
+++ b/spec/ruby/library/net-ftp/quit_spec.rb
@@ -1,33 +1,36 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#quit" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#quit" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the QUIT command to the server" do
- @ftp.quit
- @ftp.last_response.should == "221 OK, bye\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "does not close the socket automatically" do
- @ftp.quit
- @ftp.closed?.should be_false
- end
+ it "sends the QUIT command to the server" do
+ @ftp.quit
+ @ftp.last_response.should == "221 OK, bye\n"
+ end
+
+ it "does not close the socket automatically" do
+ @ftp.quit
+ @ftp.closed?.should == false
+ end
- it "returns nil" do
- @ftp.quit.should be_nil
+ it "returns nil" do
+ @ftp.quit.should == nil
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/rename_spec.rb b/spec/ruby/library/net-ftp/rename_spec.rb
index 48f81b7deb..6541fe5301 100644
--- a/spec/ruby/library/net-ftp/rename_spec.rb
+++ b/spec/ruby/library/net-ftp/rename_spec.rb
@@ -1,94 +1,97 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#rename" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed from_name, to_name" do
- it "sends the RNFR command with the passed from_name and the RNTO command with the passed to_name to the server" do
- @ftp.rename("from.file", "to.file")
- @ftp.last_response.should == "250 Requested file action okay, completed. (Renamed from.file to to.file)\n"
- end
-
- it "returns something" do
- @ftp.rename("from.file", "to.file").should be_nil
- end
- end
-
- describe "when the RNFR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:rnfr).and_respond("450 Requested file action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:rnfr).and_respond("550 Requested action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rnfr).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
+ describe "Net::FTP#rename" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rnfr).and_respond("502 Command not implemented.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rnfr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rnfr).and_respond("530 Not logged in.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the RNTO command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:rnfr).and_respond("532 Need account for storing files.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:rnto).and_respond("553 Requested action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rnto).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
+ describe "when passed from_name, to_name" do
+ it "sends the RNFR command with the passed from_name and the RNTO command with the passed to_name to the server" do
+ @ftp.rename("from.file", "to.file")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (Renamed from.file to to.file)\n"
+ end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rnto).and_respond("502 Command not implemented.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ it "returns something" do
+ @ftp.rename("from.file", "to.file").should == nil
+ end
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rnto).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ describe "when the RNFR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:rnfr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:rnfr).and_respond("550 Requested action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rnfr).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rnfr).and_respond("502 Command not implemented.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rnfr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rnfr).and_respond("530 Not logged in.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rnto).and_respond("530 Not logged in.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ describe "when the RNTO command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:rnfr).and_respond("532 Need account for storing files.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:rnto).and_respond("553 Requested action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rnto).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rnto).and_respond("502 Command not implemented.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rnto).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rnto).and_respond("530 Not logged in.")
+ -> { @ftp.rename("from.file", "to.file") }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/resume_spec.rb b/spec/ruby/library/net-ftp/resume_spec.rb
index 6592fc5bb0..5ec565d155 100644
--- a/spec/ruby/library/net-ftp/resume_spec.rb
+++ b/spec/ruby/library/net-ftp/resume_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#resume" do
- it "returns true when self is set to resume uploads/downloads" do
- ftp = Net::FTP.new
- ftp.resume.should be_false
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- ftp.resume = true
- ftp.resume.should be_true
+ describe "Net::FTP#resume" do
+ it "returns true when self is set to resume uploads/downloads" do
+ ftp = Net::FTP.new
+ ftp.resume.should == false
+
+ ftp.resume = true
+ ftp.resume.should == true
+ end
end
-end
-describe "Net::FTP#resume=" do
- it "sets self to resume uploads/downloads when set to true" do
- ftp = Net::FTP.new
- ftp.resume = true
- ftp.resume.should be_true
+ describe "Net::FTP#resume=" do
+ it "sets self to resume uploads/downloads when set to true" do
+ ftp = Net::FTP.new
+ ftp.resume = true
+ ftp.resume.should == true
- ftp.resume = false
- ftp.resume.should be_false
+ ftp.resume = false
+ ftp.resume.should == false
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/retrbinary_spec.rb b/spec/ruby/library/net-ftp/retrbinary_spec.rb
index de024208aa..ff8c8098a4 100644
--- a/spec/ruby/library/net-ftp/retrbinary_spec.rb
+++ b/spec/ruby/library/net-ftp/retrbinary_spec.rb
@@ -1,30 +1,33 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#retrbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#retrbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the passed command to the server" do
- @ftp.retrbinary("RETR test", 4096) {}
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @ftp.retrbinary("RETR test", 4096) {}
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
- it "yields the received content as binary blocks of the passed size" do
- res = []
- @ftp.retrbinary("RETR test", 10) { |bin| res << bin }
- res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ it "yields the received content as binary blocks of the passed size" do
+ res = []
+ @ftp.retrbinary("RETR test", 10) { |bin| res << bin }
+ res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/retrlines_spec.rb b/spec/ruby/library/net-ftp/retrlines_spec.rb
index 866ecb5f40..2963da14f7 100644
--- a/spec/ruby/library/net-ftp/retrlines_spec.rb
+++ b/spec/ruby/library/net-ftp/retrlines_spec.rb
@@ -1,34 +1,37 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#retrlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#retrlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the passed command over the socket" do
- @ftp.retrlines("LIST test.dir") {}
- @ftp.last_response.should == "226 transfer complete (LIST test.dir)\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command over the socket" do
+ @ftp.retrlines("LIST test.dir") {}
+ @ftp.last_response.should == "226 transfer complete (LIST test.dir)\n"
+ end
- it "yields each received line to the passed block" do
- res = []
- @ftp.retrlines("LIST test.dir") { |x| res << x }
- res.should == [
- "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
- "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
- "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
- ]
+ it "yields each received line to the passed block" do
+ res = []
+ @ftp.retrlines("LIST test.dir") { |x| res << x }
+ res.should == [
+ "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
+ "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
+ "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
+ ]
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/return_code_spec.rb b/spec/ruby/library/net-ftp/return_code_spec.rb
index 35a6232f7e..fcf5a32aa7 100644
--- a/spec/ruby/library/net-ftp/return_code_spec.rb
+++ b/spec/ruby/library/net-ftp/return_code_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#return_code" do
- before :each do
- @ftp = Net::FTP.new
- end
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
- it "outputs a warning and returns a newline" do
- -> do
- @ftp.return_code.should == "\n"
- end.should complain(/warning: Net::FTP#return_code is obsolete and do nothing/)
- end
-end
+ describe "Net::FTP#return_code" do
+ before :each do
+ @ftp = Net::FTP.new
+ end
-describe "Net::FTP#return_code=" do
- before :each do
- @ftp = Net::FTP.new
+ it "outputs a warning and returns a newline" do
+ -> do
+ @ftp.return_code.should == "\n"
+ end.should complain(/warning: Net::FTP#return_code is obsolete and do nothing/)
+ end
end
- it "outputs a warning" do
- -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
+ describe "Net::FTP#return_code=" do
+ before :each do
+ @ftp = Net::FTP.new
+ end
+
+ it "outputs a warning" do
+ -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/rmdir_spec.rb b/spec/ruby/library/net-ftp/rmdir_spec.rb
index 400874d60d..23650ebcc8 100644
--- a/spec/ruby/library/net-ftp/rmdir_spec.rb
+++ b/spec/ruby/library/net-ftp/rmdir_spec.rb
@@ -1,58 +1,61 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#rmdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the RMD command with the passed pathname to the server" do
- @ftp.rmdir("test.folder")
- @ftp.last_response.should == "250 Requested file action okay, completed. (RMD test.folder)\n"
- end
-
- it "returns nil" do
- @ftp.rmdir("test.folder").should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:rmd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rmd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rmd).and_respond("502 Command not implemented.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rmd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rmd).and_respond("530 Not logged in.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:rmd).and_respond("550 Requested action not taken.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#rmdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the RMD command with the passed pathname to the server" do
+ @ftp.rmdir("test.folder")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (RMD test.folder)\n"
+ end
+
+ it "returns nil" do
+ @ftp.rmdir("test.folder").should == nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:rmd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.rmdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rmd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rmdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rmd).and_respond("502 Command not implemented.")
+ -> { @ftp.rmdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rmd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rmdir("test.folder") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rmd).and_respond("530 Not logged in.")
+ -> { @ftp.rmdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:rmd).and_respond("550 Requested action not taken.")
+ -> { @ftp.rmdir("test.folder") }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/sendcmd_spec.rb b/spec/ruby/library/net-ftp/sendcmd_spec.rb
index c50b373869..67dbd3bdb8 100644
--- a/spec/ruby/library/net-ftp/sendcmd_spec.rb
+++ b/spec/ruby/library/net-ftp/sendcmd_spec.rb
@@ -1,54 +1,57 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#sendcmd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @ftp.sendcmd("HELP")
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "returns the server's response" do
- @ftp.sendcmd("HELP").should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "raises no error when the response code is 1xx, 2xx or 3xx" do
- @server.should_receive(:help).and_respond("120 Service ready in nnn minutes.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
-
- @server.should_receive(:help).and_respond("200 Command okay.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
-
- @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
- end
-
- it "raises a Net::FTPTempError when the response code is 4xx" do
- @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 5xx" do
- @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPProtoError when the response code is not between 1xx-5xx" do
- @server.should_receive(:help).and_respond("999 Invalid response.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPProtoError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#sendcmd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @ftp.sendcmd("HELP")
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "returns the server's response" do
+ @ftp.sendcmd("HELP").should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "raises no error when the response code is 1xx, 2xx or 3xx" do
+ @server.should_receive(:help).and_respond("120 Service ready in nnn minutes.")
+ -> { @ftp.sendcmd("HELP") }.should_not.raise
+
+ @server.should_receive(:help).and_respond("200 Command okay.")
+ -> { @ftp.sendcmd("HELP") }.should_not.raise
+
+ @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
+ -> { @ftp.sendcmd("HELP") }.should_not.raise
+ end
+
+ it "raises a Net::FTPTempError when the response code is 4xx" do
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.sendcmd("HELP") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 5xx" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.sendcmd("HELP") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is not between 1xx-5xx" do
+ @server.should_receive(:help).and_respond("999 Invalid response.")
+ -> { @ftp.sendcmd("HELP") }.should.raise(Net::FTPProtoError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/set_socket_spec.rb b/spec/ruby/library/net-ftp/set_socket_spec.rb
index 8182dd8b33..ad83dfcc4f 100644
--- a/spec/ruby/library/net-ftp/set_socket_spec.rb
+++ b/spec/ruby/library/net-ftp/set_socket_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-describe "Net::FTP#set_socket" do
- # TODO: I won't spec this method, as it is not used
- # anywhere and it should be private anyway.
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#set_socket" do
+ # TODO: I won't spec this method, as it is not used
+ # anywhere and it should be private anyway.
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/net-ftp/shared/getbinaryfile.rb b/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
index ceec8e7cd5..4fc4731c45 100644
--- a/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
+++ b/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
@@ -1,150 +1,152 @@
-describe :net_ftp_getbinaryfile, shared: true do
- before :each do
- @fixture_file = __dir__ + "/../fixtures/getbinaryfile"
- @tmp_file = tmp("getbinaryfile")
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_getbinaryfile, shared: true do
+ before :each do
+ @fixture_file = __dir__ + "/../fixtures/getbinaryfile"
+ @tmp_file = tmp("getbinaryfile")
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- rm_r @tmp_file
- end
+ rm_r @tmp_file
+ end
- it "sends the RETR command to the server" do
- @ftp.send(@method, "test", @tmp_file)
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
+ it "sends the RETR command to the server" do
+ @ftp.send(@method, "test", @tmp_file)
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
- it "returns nil" do
- @ftp.send(@method, "test", @tmp_file).should be_nil
- end
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should == nil
+ end
- it "saves the contents of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
+ it "saves the contents of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
- describe "when passed a block" do
- it "yields the received content as binary blocks of the passed size" do
- res = []
- @ftp.send(@method, "test", @tmp_file, 10) { |bin| res << bin }
- res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ describe "when passed a block" do
+ it "yields the received content as binary blocks of the passed size" do
+ res = []
+ @ftp.send(@method, "test", @tmp_file, 10) { |bin| res << bin }
+ res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ end
end
- end
- describe "when resuming an existing file" do
- before :each do
- @tmp_file = tmp("getbinaryfile_resume")
+ describe "when resuming an existing file" do
+ before :each do
+ @tmp_file = tmp("getbinaryfile_resume")
- File.open(@tmp_file, "wb") do |f|
- f << "This is the content\n"
+ File.open(@tmp_file, "wb") do |f|
+ f << "This is the content\n"
+ end
+
+ @ftp.resume = true
end
- @ftp.resume = true
- end
+ it "saves the remaining content of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
- it "saves the remaining content of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ describe "and the REST command fails" do
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:rest).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:rest).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rest).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rest).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rest).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rest).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+ end
end
- describe "and the REST command fails" do
+ describe "when the RETR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
+ end
+
it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:rest).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPProtoError)
end
it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:rest).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
end
it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rest).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rest).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
end
it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rest).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
end
it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rest).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
end
end
- end
-
- describe "when the RETR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:retr).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:retr).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/gettextfile.rb b/spec/ruby/library/net-ftp/shared/gettextfile.rb
index 7fe14f7dfb..562c7a3047 100644
--- a/spec/ruby/library/net-ftp/shared/gettextfile.rb
+++ b/spec/ruby/library/net-ftp/shared/gettextfile.rb
@@ -1,100 +1,102 @@
-describe :net_ftp_gettextfile, shared: true do
- before :each do
- @tmp_file = tmp("gettextfile")
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_gettextfile, shared: true do
+ before :each do
+ @tmp_file = tmp("gettextfile")
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the RETR command to the server" do
- @ftp.send(@method, "test", @tmp_file)
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "returns nil" do
- @ftp.send(@method, "test", @tmp_file).should be_nil
- end
-
- it "saves the contents of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "when passed a block" do
- it "yields each line of the retrieved file to the passed block" do
- res = []
- @ftp.send(@method, "test", @tmp_file) { |line| res << line }
- res.should == [ "This is the content", "of the file named 'test'."]
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
end
- end
- describe "when the RETR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:retr).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ rm_r @tmp_file
end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ it "sends the RETR command to the server" do
+ @ftp.send(@method, "test", @tmp_file)
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should == nil
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:retr).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ it "saves the contents of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ describe "when passed a block" do
+ it "yields each line of the retrieved file to the passed block" do
+ res = []
+ @ftp.send(@method, "test", @tmp_file) { |line| res << line }
+ res.should == [ "This is the content", "of the file named 'test'."]
+ end
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ describe "when the RETR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/last_response_code.rb b/spec/ruby/library/net-ftp/shared/last_response_code.rb
index 4fe53677db..9d36e37f0c 100644
--- a/spec/ruby/library/net-ftp/shared/last_response_code.rb
+++ b/spec/ruby/library/net-ftp/shared/last_response_code.rb
@@ -1,25 +1,27 @@
-describe :net_ftp_last_response_code, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_last_response_code, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the response code for the last response" do
- @server.should_receive(:help).and_respond("200 Command okay.")
- @ftp.help
- @ftp.send(@method).should == "200"
+ it "returns the response code for the last response" do
+ @server.should_receive(:help).and_respond("200 Command okay.")
+ @ftp.help
+ @ftp.send(@method).should == "200"
- @server.should_receive(:help).and_respond("212 Directory status.")
- @ftp.help
- @ftp.send(@method).should == "212"
+ @server.should_receive(:help).and_respond("212 Directory status.")
+ @ftp.help
+ @ftp.send(@method).should == "212"
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/list.rb b/spec/ruby/library/net-ftp/shared/list.rb
index adc3fa59c1..ec372447e8 100644
--- a/spec/ruby/library/net-ftp/shared/list.rb
+++ b/spec/ruby/library/net-ftp/shared/list.rb
@@ -1,104 +1,106 @@
-describe :net_ftp_list, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.passive = false
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed a block" do
- it "yields each file in the list of files in the passed dir" do
- expected = [
- "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
- "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
- "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
- ]
-
- res = []
- @ftp.send(@method, "test.folder") { |line| res << line}
- res.should == expected
-
- @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_list, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.passive = false
+ @ftp.connect(@server.hostname, @server.server_port)
end
- end
-
- describe "when passed no block" do
- it "returns an Array containing a list of files in the passed dir" do
- expected = [
- "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
- "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
- "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
- ]
- @ftp.send(@method, "test.folder").should == expected
-
- @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
end
- end
- describe "when the LIST command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:list).and_respond("450 Requested file action not taken..")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPTempError)
- end
+ describe "when passed a block" do
+ it "yields each file in the list of files in the passed dir" do
+ expected = [
+ "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
+ "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
+ "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
+ ]
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:list).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
- end
+ res = []
+ @ftp.send(@method, "test.folder") { |line| res << line}
+ res.should == expected
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:list).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
+ @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ end
end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:list).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:list).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPTempError)
- end
+ describe "when passed no block" do
+ it "returns an Array containing a list of files in the passed dir" do
+ expected = [
+ "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
+ "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
+ "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
+ ]
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:list).and_respond("530 Not logged in.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
- end
+ @ftp.send(@method, "test.folder").should == expected
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
+ @ftp.last_response.should == "226 transfer complete (LIST test.folder)\n"
+ end
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPTempError)
+ describe "when the LIST command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:list).and_respond("450 Requested file action not taken..")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:list).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:list).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:list).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:list).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:list).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method) }.should raise_error(Net::FTPPermError)
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method) }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
index 45f53adc2a..afbe3c61f8 100644
--- a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
+++ b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
@@ -1,167 +1,169 @@
-describe :net_ftp_putbinaryfile, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_putbinaryfile, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @local_fixture_file = __dir__ + "/../fixtures/putbinaryfile"
- @remote_tmp_file = tmp("binaryfile", false)
+ @local_fixture_file = __dir__ + "/../fixtures/putbinaryfile"
+ @remote_tmp_file = tmp("binaryfile", false)
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- rm_r @remote_tmp_file
- end
-
- it "sends the STOR command to the server" do
- @ftp.send(@method, @local_fixture_file, "binary")
- @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
- end
+ rm_r @remote_tmp_file
+ end
- it "sends the contents of the passed local_file, without modifications" do
- @ftp.send(@method, @local_fixture_file, "binary")
+ it "sends the STOR command to the server" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
- remote_lines = File.readlines(@remote_tmp_file)
- local_lines = File.readlines(@local_fixture_file)
+ it "sends the contents of the passed local_file, without modifications" do
+ @ftp.send(@method, @local_fixture_file, "binary")
- remote_lines.should == local_lines
- end
+ remote_lines = File.readlines(@remote_tmp_file)
+ local_lines = File.readlines(@local_fixture_file)
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "binary").should be_nil
- end
+ remote_lines.should == local_lines
+ end
- describe "when passed a block" do
- it "yields the transmitted content as binary blocks of the passed size" do
- res = []
- @ftp.send(@method, @local_fixture_file, "binary", 10) { |x| res << x }
- res.should == [
- "This is an", " example f",
- "ile\nwhich ", "is going t",
- "o be trans", "mitted\nusi",
- "ng #putbin", "aryfile.\n"
- ]
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "binary").should == nil
end
- end
- describe "when resuming an existing file" do
- before :each do
- File.open(@remote_tmp_file, "w") do |f|
- f << "This is an example file\n"
+ describe "when passed a block" do
+ it "yields the transmitted content as binary blocks of the passed size" do
+ res = []
+ @ftp.send(@method, @local_fixture_file, "binary", 10) { |x| res << x }
+ res.should == [
+ "This is an", " example f",
+ "ile\nwhich ", "is going t",
+ "o be trans", "mitted\nusi",
+ "ng #putbin", "aryfile.\n"
+ ]
end
-
- @ftp.resume = true
end
- it "sends the remaining content of the passed local_file to the passed remote_file" do
- @ftp.send(@method, @local_fixture_file, "binary")
- File.read(@remote_tmp_file).should == File.read(@local_fixture_file)
- end
+ describe "when resuming an existing file" do
+ before :each do
+ File.open(@remote_tmp_file, "w") do |f|
+ f << "This is an example file\n"
+ end
- describe "and the APPE command fails" do
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:appe).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPProtoError)
+ @ftp.resume = true
end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:appe).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ it "sends the remaining content of the passed local_file to the passed remote_file" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+ File.read(@remote_tmp_file).should == File.read(@local_fixture_file)
end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:appe).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ describe "and the APPE command fails" do
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:appe).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:appe).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:appe).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:appe).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:appe).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:appe).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
end
+ end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:appe).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ describe "when the STOR command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:stor).and_respond("532 Need account for storing files.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:appe).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPTempError)
end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:appe).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPTempError when the response code is 452" do
+ @server.should_receive(:stor).and_respond("452 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPTempError)
end
- end
- end
-
- describe "when the STOR command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:stor).and_respond("532 Need account for storing files.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPTempError when the response code is 452" do
- @server.should_receive(:stor).and_respond("452 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:stor).and_respond("553 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stor).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stor).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
end
- end
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/puttextfile.rb b/spec/ruby/library/net-ftp/shared/puttextfile.rb
index e2c0453352..3650cad230 100644
--- a/spec/ruby/library/net-ftp/shared/puttextfile.rb
+++ b/spec/ruby/library/net-ftp/shared/puttextfile.rb
@@ -1,128 +1,130 @@
-describe :net_ftp_puttextfile, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = __dir__ + "/../fixtures/puttextfile"
- @remote_tmp_file = tmp("textfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @remote_tmp_file
- end
-
- it "sends the STOR command to the server" do
- @ftp.send(@method, @local_fixture_file, "text")
- @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
- end
-
- it "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
- @ftp.send(@method, @local_fixture_file, "text")
-
- remote_lines = File.binread(@remote_tmp_file)
- local_lines = File.binread(@local_fixture_file)
-
- remote_lines.should_not == local_lines
- remote_lines.should == local_lines.gsub("\n", "\r\n")
- end
-
- guard -> { Net::FTP::VERSION < '0.3.6' } do
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "text").should be_nil
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_puttextfile, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = __dir__ + "/../fixtures/puttextfile"
+ @remote_tmp_file = tmp("textfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
end
- end
- guard -> { Net::FTP::VERSION >= '0.3.6' } do
- it "returns the response" do
- @ftp.send(@method, @local_fixture_file, "text").should == @ftp.last_response
- end
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- describe "when passed a block" do
- it "yields each transmitted line" do
- res = []
- @ftp.send(@method, @local_fixture_file, "text") { |x| res << x }
- res.should == [
- "This is an example file\r\n",
- "which is going to be transmitted\r\n",
- "using #puttextfile.\r\n"
- ]
+ rm_r @remote_tmp_file
end
- end
- describe "when the STOR command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:stor).and_respond("532 Need account for storing files.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ it "sends the STOR command to the server" do
+ @ftp.send(@method, @local_fixture_file, "text")
+ @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
end
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
+ it "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
+ @ftp.send(@method, @local_fixture_file, "text")
- it "raises a Net::FTPTempError when the response code is 452" do
- @server.should_receive(:stor).and_respond("452 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
+ remote_lines = File.binread(@remote_tmp_file)
+ local_lines = File.binread(@local_fixture_file)
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:stor).and_respond("553 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ remote_lines.should_not == local_lines
+ remote_lines.should == local_lines.gsub("\n", "\r\n")
end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ guard -> { Net::FTP::VERSION < '0.3.6' } do
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "text").should == nil
+ end
end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stor).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ guard -> { Net::FTP::VERSION >= '0.3.6' } do
+ it "returns the response" do
+ @ftp.send(@method, @local_fixture_file, "text").should == @ftp.last_response
+ end
end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ describe "when passed a block" do
+ it "yields each transmitted line" do
+ res = []
+ @ftp.send(@method, @local_fixture_file, "text") { |x| res << x }
+ res.should == [
+ "This is an example file\r\n",
+ "which is going to be transmitted\r\n",
+ "using #puttextfile.\r\n"
+ ]
+ end
end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ describe "when the STOR command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:stor).and_respond("532 Need account for storing files.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 452" do
+ @server.should_receive(:stor).and_respond("452 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stor).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should.raise(Net::FTPPermError)
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/shared/pwd.rb b/spec/ruby/library/net-ftp/shared/pwd.rb
index 951d020f2d..db3e587464 100644
--- a/spec/ruby/library/net-ftp/shared/pwd.rb
+++ b/spec/ruby/library/net-ftp/shared/pwd.rb
@@ -1,3 +1,5 @@
-describe :net_ftp_pwd, shared: true do
+ruby_version_is ""..."4.1" do
+ describe :net_ftp_pwd, shared: true do
+ end
end
diff --git a/spec/ruby/library/net-ftp/site_spec.rb b/spec/ruby/library/net-ftp/site_spec.rb
index c3e589a920..adc7dfafdf 100644
--- a/spec/ruby/library/net-ftp/site_spec.rb
+++ b/spec/ruby/library/net-ftp/site_spec.rb
@@ -1,53 +1,56 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#site" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SITE command with the passed argument to the server" do
- @ftp.site("param")
- @ftp.last_response.should == "200 Command okay. (SITE param)\n"
- end
-
- it "returns nil" do
- @ftp.site("param").should be_nil
- end
-
- it "does not raise an error when the response code is 202" do
- @server.should_receive(:site).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.site("param") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:site).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:site).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:site).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:site).and_respond("530 Requested action not taken.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#site" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SITE command with the passed argument to the server" do
+ @ftp.site("param")
+ @ftp.last_response.should == "200 Command okay. (SITE param)\n"
+ end
+
+ it "returns nil" do
+ @ftp.site("param").should == nil
+ end
+
+ it "does not raise an error when the response code is 202" do
+ @server.should_receive(:site).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.site("param") }.should_not.raise
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:site).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.site("param") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:site).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.site("param") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:site).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.site("param") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:site).and_respond("530 Requested action not taken.")
+ -> { @ftp.site("param") }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/size_spec.rb b/spec/ruby/library/net-ftp/size_spec.rb
index 0cf2e24477..dd84e5a449 100644
--- a/spec/ruby/library/net-ftp/size_spec.rb
+++ b/spec/ruby/library/net-ftp/size_spec.rb
@@ -1,48 +1,51 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#size" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SIZE command to the server" do
- @ftp.size("test.file")
- @ftp.last_response.should == "213 1024\n"
- end
-
- it "returns the size of the passed file as Integer" do
- @ftp.size("test.file").should eql(1024)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:size).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:size).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:size).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:size).and_respond("550 Requested action not taken.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#size" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SIZE command to the server" do
+ @ftp.size("test.file")
+ @ftp.last_response.should == "213 1024\n"
+ end
+
+ it "returns the size of the passed file as Integer" do
+ @ftp.size("test.file").should.eql?(1024)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:size).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.size("test.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:size).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.size("test.file") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:size).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.size("test.file") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:size).and_respond("550 Requested action not taken.")
+ -> { @ftp.size("test.file") }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/spec_helper.rb b/spec/ruby/library/net-ftp/spec_helper.rb
index c87d16218b..7689b4fb0c 100644
--- a/spec/ruby/library/net-ftp/spec_helper.rb
+++ b/spec/ruby/library/net-ftp/spec_helper.rb
@@ -1,5 +1,7 @@
-require "net/ftp"
+ruby_version_is ""..."4.1" do
+ require "net/ftp"
-if defined?(Net::FTP.default_passive)
- Net::FTP.default_passive = false
+ if defined?(Net::FTP.default_passive)
+ Net::FTP.default_passive = false
+ end
end
diff --git a/spec/ruby/library/net-ftp/status_spec.rb b/spec/ruby/library/net-ftp/status_spec.rb
index 9d9f86c381..ce29e215d4 100644
--- a/spec/ruby/library/net-ftp/status_spec.rb
+++ b/spec/ruby/library/net-ftp/status_spec.rb
@@ -1,67 +1,70 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#status" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#status" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- it "sends the STAT command to the server" do
- @ftp.status
- @ftp.last_response.should == "211 System status, or system help reply. (STAT)\n"
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "sends the STAT command with an optional parameter to the server" do
- @ftp.status("/pub").should == "211 System status, or system help reply. (STAT /pub)\n"
- end
+ it "sends the STAT command to the server" do
+ @ftp.status
+ @ftp.last_response.should == "211 System status, or system help reply. (STAT)\n"
+ end
- it "returns the received information" do
- @ftp.status.should == "211 System status, or system help reply. (STAT)\n"
- end
+ it "sends the STAT command with an optional parameter to the server" do
+ @ftp.status("/pub").should == "211 System status, or system help reply. (STAT /pub)\n"
+ end
- it "does not raise an error when the response code is 212" do
- @server.should_receive(:stat).and_respond("212 Directory status.")
- -> { @ftp.status }.should_not raise_error
- end
+ it "returns the received information" do
+ @ftp.status.should == "211 System status, or system help reply. (STAT)\n"
+ end
- it "does not raise an error when the response code is 213" do
- @server.should_receive(:stat).and_respond("213 File status.")
- -> { @ftp.status }.should_not raise_error
- end
+ it "does not raise an error when the response code is 212" do
+ @server.should_receive(:stat).and_respond("212 Directory status.")
+ -> { @ftp.status }.should_not.raise
+ end
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
+ it "does not raise an error when the response code is 213" do
+ @server.should_receive(:stat).and_respond("213 File status.")
+ -> { @ftp.status }.should_not.raise
+ end
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stat).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.status }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:stat).and_respond("502 Command not implemented.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stat).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.status }.should.raise(Net::FTPPermError)
+ end
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stat).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.status }.should raise_error(Net::FTPTempError)
- end
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:stat).and_respond("502 Command not implemented.")
+ -> { @ftp.status }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stat).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.status }.should.raise(Net::FTPTempError)
+ end
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stat).and_respond("530 Requested action not taken.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stat).and_respond("530 Requested action not taken.")
+ -> { @ftp.status }.should.raise(Net::FTPPermError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/storbinary_spec.rb b/spec/ruby/library/net-ftp/storbinary_spec.rb
index aa4c51f2e8..a2f81fc669 100644
--- a/spec/ruby/library/net-ftp/storbinary_spec.rb
+++ b/spec/ruby/library/net-ftp/storbinary_spec.rb
@@ -1,49 +1,52 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
+ruby_version_is ""..."4.1" do
-describe "Net::FTP#storbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @local_fixture_file = __dir__ + "/fixtures/putbinaryfile"
- @tmp_file = tmp("binaryfile", false)
+ describe "Net::FTP#storbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ @local_fixture_file = __dir__ + "/fixtures/putbinaryfile"
+ @tmp_file = tmp("binaryfile", false)
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- rm_r @tmp_file
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- it "sends the passed command and the passed File object's content to the server" do
- File.open(@local_fixture_file) do |f|
- f.binmode
+ rm_r @tmp_file
+ end
+
+ it "sends the passed command and the passed File object's content to the server" do
+ File.open(@local_fixture_file) do |f|
+ f.binmode
- @ftp.storbinary("STOR binary", f, 4096) {}
- @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ @ftp.storbinary("STOR binary", f, 4096) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
end
- end
- it "yields the transmitted content as binary blocks of the passed size" do
- File.open(@local_fixture_file) do |f|
- f.binmode
-
- res = []
- @ftp.storbinary("STOR binary", f, 10) { |x| res << x }
- res.should == [
- "This is an", " example f",
- "ile\nwhich ", "is going t",
- "o be trans", "mitted\nusi",
- "ng #putbin", "aryfile.\n"
- ]
+ it "yields the transmitted content as binary blocks of the passed size" do
+ File.open(@local_fixture_file) do |f|
+ f.binmode
+
+ res = []
+ @ftp.storbinary("STOR binary", f, 10) { |x| res << x }
+ res.should == [
+ "This is an", " example f",
+ "ile\nwhich ", "is going t",
+ "o be trans", "mitted\nusi",
+ "ng #putbin", "aryfile.\n"
+ ]
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/storlines_spec.rb b/spec/ruby/library/net-ftp/storlines_spec.rb
index dc6830da7b..09340bafe9 100644
--- a/spec/ruby/library/net-ftp/storlines_spec.rb
+++ b/spec/ruby/library/net-ftp/storlines_spec.rb
@@ -1,44 +1,47 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
+ruby_version_is ""..."4.1" do
-describe "Net::FTP#storlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @local_fixture_file = __dir__ + "/fixtures/puttextfile"
- @tmp_file = tmp("textfile", false)
+ describe "Net::FTP#storlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ @local_fixture_file = __dir__ + "/fixtures/puttextfile"
+ @tmp_file = tmp("textfile", false)
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
- rm_r @tmp_file
- end
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
- it "sends the passed command and the passed File object's content to the server" do
- File.open(@local_fixture_file) do |f|
- @ftp.storlines("STOR text", f) {}
- @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
+ rm_r @tmp_file
+ end
+
+ it "sends the passed command and the passed File object's content to the server" do
+ File.open(@local_fixture_file) do |f|
+ @ftp.storlines("STOR text", f) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
+ end
end
- end
- it "yields each line of the transmitted content" do
- File.open(@local_fixture_file) do |f|
- res = []
- @ftp.storlines("STOR text", f) { |x| res << x }
- res.should == [
- "This is an example file\r\n",
- "which is going to be transmitted\r\n",
- "using #puttextfile.\r\n"
- ]
+ it "yields each line of the transmitted content" do
+ File.open(@local_fixture_file) do |f|
+ res = []
+ @ftp.storlines("STOR text", f) { |x| res << x }
+ res.should == [
+ "This is an example file\r\n",
+ "which is going to be transmitted\r\n",
+ "using #puttextfile.\r\n"
+ ]
+ end
end
end
end
diff --git a/spec/ruby/library/net-ftp/system_spec.rb b/spec/ruby/library/net-ftp/system_spec.rb
index 2b7f0d2560..fa61776282 100644
--- a/spec/ruby/library/net-ftp/system_spec.rb
+++ b/spec/ruby/library/net-ftp/system_spec.rb
@@ -1,48 +1,51 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#system" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SYST command to the server" do
- @ftp.system
- @ftp.last_response.should =~ /\A215 FTP Dummy Server \(SYST\)\Z/
- end
-
- it "returns the received information" do
- @ftp.system.should =~ /\AFTP Dummy Server \(SYST\)\Z/
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:syst).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:syst).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:syst).and_respond("502 Command not implemented.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:syst).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.system }.should raise_error(Net::FTPTempError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#system" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SYST command to the server" do
+ @ftp.system
+ @ftp.last_response.should =~ /\A215 FTP Dummy Server \(SYST\)\Z/
+ end
+
+ it "returns the received information" do
+ @ftp.system.should =~ /\AFTP Dummy Server \(SYST\)\Z/
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:syst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.system }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:syst).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.system }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:syst).and_respond("502 Command not implemented.")
+ -> { @ftp.system }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:syst).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.system }.should.raise(Net::FTPTempError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/voidcmd_spec.rb b/spec/ruby/library/net-ftp/voidcmd_spec.rb
index f2536fe697..4f74da7a70 100644
--- a/spec/ruby/library/net-ftp/voidcmd_spec.rb
+++ b/spec/ruby/library/net-ftp/voidcmd_spec.rb
@@ -1,54 +1,57 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#voidcmd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @server.should_receive(:help).and_respond("2xx Does not raise.")
- -> { @ftp.voidcmd("HELP") }.should_not raise_error
- end
-
- it "returns nil" do
- @server.should_receive(:help).and_respond("2xx Does not raise.")
- @ftp.voidcmd("HELP").should be_nil
- end
-
- it "raises a Net::FTPReplyError when the response code is 1xx" do
- @server.should_receive(:help).and_respond("1xx Does raise a Net::FTPReplyError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPReplyError when the response code is 3xx" do
- @server.should_receive(:help).and_respond("3xx Does raise a Net::FTPReplyError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPTempError when the response code is 4xx" do
- @server.should_receive(:help).and_respond("4xx Does raise a Net::FTPTempError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 5xx" do
- @server.should_receive(:help).and_respond("5xx Does raise a Net::FTPPermError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPProtoError when the response code is not valid" do
- @server.should_receive(:help).and_respond("999 Does raise a Net::FTPProtoError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPProtoError)
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#voidcmd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ -> { @ftp.voidcmd("HELP") }.should_not.raise
+ end
+
+ it "returns nil" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ @ftp.voidcmd("HELP").should == nil
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 1xx" do
+ @server.should_receive(:help).and_respond("1xx Does raise a Net::FTPReplyError.")
+ -> { @ftp.voidcmd("HELP") }.should.raise(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 3xx" do
+ @server.should_receive(:help).and_respond("3xx Does raise a Net::FTPReplyError.")
+ -> { @ftp.voidcmd("HELP") }.should.raise(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 4xx" do
+ @server.should_receive(:help).and_respond("4xx Does raise a Net::FTPTempError.")
+ -> { @ftp.voidcmd("HELP") }.should.raise(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 5xx" do
+ @server.should_receive(:help).and_respond("5xx Does raise a Net::FTPPermError.")
+ -> { @ftp.voidcmd("HELP") }.should.raise(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is not valid" do
+ @server.should_receive(:help).and_respond("999 Does raise a Net::FTPProtoError.")
+ -> { @ftp.voidcmd("HELP") }.should.raise(Net::FTPProtoError)
+ end
end
end
diff --git a/spec/ruby/library/net-ftp/welcome_spec.rb b/spec/ruby/library/net-ftp/welcome_spec.rb
index 4279127ce3..761a0f9a3e 100644
--- a/spec/ruby/library/net-ftp/welcome_spec.rb
+++ b/spec/ruby/library/net-ftp/welcome_spec.rb
@@ -1,25 +1,28 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-describe "Net::FTP#welcome" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
+ruby_version_is ""..."4.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
+ describe "Net::FTP#welcome" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
- it "returns the server's welcome message" do
- @ftp.welcome.should be_nil
- @ftp.login
- @ftp.welcome.should == "230 User logged in, proceed. (USER anonymous)\n"
+ it "returns the server's welcome message" do
+ @ftp.welcome.should == nil
+ @ftp.login
+ @ftp.welcome.should == "230 User logged in, proceed. (USER anonymous)\n"
+ end
end
end
diff --git a/spec/ruby/library/net-http/HTTPServerException_spec.rb b/spec/ruby/library/net-http/HTTPServerException_spec.rb
index 5e0a833fee..020d3cce85 100644
--- a/spec/ruby/library/net-http/HTTPServerException_spec.rb
+++ b/spec/ruby/library/net-http/HTTPServerException_spec.rb
@@ -3,10 +3,10 @@ require 'net/http'
describe "Net::HTTPServerException" do
it "is a subclass of Net::ProtoServerError and is warned as deprecated" do
- -> { Net::HTTPServerException.should < Net::ProtoServerError }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
+ -> { eval("Net::HTTPServerException").should < Net::ProtoServerError }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
end
it "includes the Net::HTTPExceptions module and is warned as deprecated" do
- -> { Net::HTTPServerException.should < Net::HTTPExceptions }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
+ -> { eval("Net::HTTPServerException").should < Net::HTTPExceptions }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
end
end
diff --git a/spec/ruby/library/net-http/http/Proxy_spec.rb b/spec/ruby/library/net-http/http/Proxy_spec.rb
index a1a04fa00b..7753ce5e30 100644
--- a/spec/ruby/library/net-http/http/Proxy_spec.rb
+++ b/spec/ruby/library/net-http/http/Proxy_spec.rb
@@ -13,7 +13,7 @@ describe "Net::HTTP.Proxy" do
it "sets the returned subclasses' proxy options based on the passed arguments" do
http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
http_with_proxy.proxy_address.should == "localhost"
- http_with_proxy.proxy_port.should eql(1234)
+ http_with_proxy.proxy_port.should.eql?(1234)
http_with_proxy.proxy_user.should == "rspec"
http_with_proxy.proxy_pass.should == "rocks"
end
@@ -22,14 +22,14 @@ end
describe "Net::HTTP#proxy?" do
describe "when self is no proxy class instance" do
it "returns false" do
- Net::HTTP.new("localhost", 3333).proxy?.should be_false
+ Net::HTTP.new("localhost", 3333).proxy?.should == false
end
end
describe "when self is a proxy class instance" do
it "returns false" do
http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy?.should be_true
+ http_with_proxy.new("localhost", 3333).proxy?.should == true
end
end
end
diff --git a/spec/ruby/library/net-http/http/copy_spec.rb b/spec/ruby/library/net-http/http/copy_spec.rb
index fba96c0f11..1f3e25009f 100644
--- a/spec/ruby/library/net-http/http/copy_spec.rb
+++ b/spec/ruby/library/net-http/http/copy_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#copy" do
it "sends a COPY request to the passed path and returns the response" do
response = @http.copy("/request")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
response.body.should == "Request type: COPY"
end
end
diff --git a/spec/ruby/library/net-http/http/default_port_spec.rb b/spec/ruby/library/net-http/http/default_port_spec.rb
index 95b7316a0c..20407d0b12 100644
--- a/spec/ruby/library/net-http/http/default_port_spec.rb
+++ b/spec/ruby/library/net-http/http/default_port_spec.rb
@@ -3,6 +3,6 @@ require 'net/http'
describe "Net::HTTP.default_port" do
it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
+ Net::HTTP.http_default_port.should.eql?(80)
end
end
diff --git a/spec/ruby/library/net-http/http/delete_spec.rb b/spec/ruby/library/net-http/http/delete_spec.rb
index d73aa5b375..09ddd74000 100644
--- a/spec/ruby/library/net-http/http/delete_spec.rb
+++ b/spec/ruby/library/net-http/http/delete_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#delete" do
it "sends a DELETE request to the passed path and returns the response" do
response = @http.delete("/request")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
response.body.should == "Request type: DELETE"
end
end
diff --git a/spec/ruby/library/net-http/http/finish_spec.rb b/spec/ruby/library/net-http/http/finish_spec.rb
index d4aa00dffe..0d466675f3 100644
--- a/spec/ruby/library/net-http/http/finish_spec.rb
+++ b/spec/ruby/library/net-http/http/finish_spec.rb
@@ -17,13 +17,13 @@ describe "Net::HTTP#finish" do
it "closes the tcp connection" do
@http.start
@http.finish
- @http.started?.should be_false
+ @http.started?.should == false
end
end
describe "when self has not been started yet" do
it "raises an IOError" do
- -> { @http.finish }.should raise_error(IOError)
+ -> { @http.finish }.should.raise(IOError)
end
end
end
diff --git a/spec/ruby/library/net-http/http/get_spec.rb b/spec/ruby/library/net-http/http/get_spec.rb
index e64a61c52c..9be726dc3b 100644
--- a/spec/ruby/library/net-http/http/get_spec.rb
+++ b/spec/ruby/library/net-http/http/get_spec.rb
@@ -74,7 +74,7 @@ describe "Net::HTTP.get" do
socket, client_thread = start_threads
begin
client_thread.raise my_exception, "my exception"
- -> { client_thread.value }.should raise_error(my_exception)
+ -> { client_thread.value }.should.raise(my_exception)
ensure
socket.close
end
diff --git a/spec/ruby/library/net-http/http/head_spec.rb b/spec/ruby/library/net-http/http/head_spec.rb
index 64621fa87b..4824d22534 100644
--- a/spec/ruby/library/net-http/http/head_spec.rb
+++ b/spec/ruby/library/net-http/http/head_spec.rb
@@ -16,10 +16,10 @@ describe "Net::HTTP#head" do
it "sends a HEAD request to the passed path and returns the response" do
response = @http.head("/request")
# HEAD requests have no responses
- response.body.should be_nil
+ response.body.should == nil
end
it "returns a Net::HTTPResponse" do
- @http.head("/request").should be_kind_of(Net::HTTPResponse)
+ @http.head("/request").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/http_default_port_spec.rb b/spec/ruby/library/net-http/http/http_default_port_spec.rb
index 3b17bcd0a5..82c88e58a8 100644
--- a/spec/ruby/library/net-http/http/http_default_port_spec.rb
+++ b/spec/ruby/library/net-http/http/http_default_port_spec.rb
@@ -3,6 +3,6 @@ require 'net/http'
describe "Net::HTTP.http_default_port" do
it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
+ Net::HTTP.http_default_port.should.eql?(80)
end
end
diff --git a/spec/ruby/library/net-http/http/https_default_port_spec.rb b/spec/ruby/library/net-http/http/https_default_port_spec.rb
index 8c24e1d97c..24b9c3b462 100644
--- a/spec/ruby/library/net-http/http/https_default_port_spec.rb
+++ b/spec/ruby/library/net-http/http/https_default_port_spec.rb
@@ -3,6 +3,6 @@ require 'net/http'
describe "Net::HTTP.https_default_port" do
it "returns 443" do
- Net::HTTP.https_default_port.should eql(443)
+ Net::HTTP.https_default_port.should.eql?(443)
end
end
diff --git a/spec/ruby/library/net-http/http/initialize_spec.rb b/spec/ruby/library/net-http/http/initialize_spec.rb
index 78aa01e1aa..907314cb25 100644
--- a/spec/ruby/library/net-http/http/initialize_spec.rb
+++ b/spec/ruby/library/net-http/http/initialize_spec.rb
@@ -3,7 +3,7 @@ require 'net/http'
describe "Net::HTTP#initialize" do
it "is private" do
- Net::HTTP.should have_private_instance_method(:initialize)
+ Net::HTTP.private_instance_methods(false).should.include?(:initialize)
end
describe "when passed address" do
@@ -17,11 +17,11 @@ describe "Net::HTTP#initialize" do
end
it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
+ @net.port.should.eql?(Net::HTTP.default_port)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == false
end
end
@@ -36,11 +36,11 @@ describe "Net::HTTP#initialize" do
end
it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
+ @net.port.should.eql?(3333)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == false
end
end
end
diff --git a/spec/ruby/library/net-http/http/inspect_spec.rb b/spec/ruby/library/net-http/http/inspect_spec.rb
index b8f650809e..fd4e6116c7 100644
--- a/spec/ruby/library/net-http/http/inspect_spec.rb
+++ b/spec/ruby/library/net-http/http/inspect_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#inspect" do
end
it "returns a String representation of self" do
- @http.inspect.should be_kind_of(String)
+ @http.inspect.should.is_a?(String)
@http.inspect.should == "#<Net::HTTP localhost:#{@port} open=false>"
@http.start
diff --git a/spec/ruby/library/net-http/http/lock_spec.rb b/spec/ruby/library/net-http/http/lock_spec.rb
index aa1f944196..12df138ad0 100644
--- a/spec/ruby/library/net-http/http/lock_spec.rb
+++ b/spec/ruby/library/net-http/http/lock_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#lock" do
it "sends a LOCK request to the passed path and returns the response" do
response = @http.lock("/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
response.body.should == "Request type: LOCK"
end
end
diff --git a/spec/ruby/library/net-http/http/mkcol_spec.rb b/spec/ruby/library/net-http/http/mkcol_spec.rb
index f8009f9059..b1a5055982 100644
--- a/spec/ruby/library/net-http/http/mkcol_spec.rb
+++ b/spec/ruby/library/net-http/http/mkcol_spec.rb
@@ -15,7 +15,7 @@ describe "Net::HTTP#mkcol" do
it "sends a MKCOL request to the passed path and returns the response" do
response = @http.mkcol("/request")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
response.body.should == "Request type: MKCOL"
end
end
diff --git a/spec/ruby/library/net-http/http/move_spec.rb b/spec/ruby/library/net-http/http/move_spec.rb
index ae43016a2c..a57c2a0f49 100644
--- a/spec/ruby/library/net-http/http/move_spec.rb
+++ b/spec/ruby/library/net-http/http/move_spec.rb
@@ -20,6 +20,6 @@ describe "Net::HTTP#head" do
end
it "returns a Net::HTTPResponse" do
- @http.move("/request").should be_kind_of(Net::HTTPResponse)
+ @http.move("/request").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/new_spec.rb b/spec/ruby/library/net-http/http/new_spec.rb
index 1ec6bbd0c0..8feb3d1351 100644
--- a/spec/ruby/library/net-http/http/new_spec.rb
+++ b/spec/ruby/library/net-http/http/new_spec.rb
@@ -8,8 +8,8 @@ describe "Net::HTTP.new" do
end
it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
+ @http.proxy?.should == false
+ @http.instance_of?(Net::HTTP).should == true
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -17,11 +17,11 @@ describe "Net::HTTP.new" do
end
it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @http.port.should eql(Net::HTTP.default_port)
+ @http.port.should.eql?(Net::HTTP.default_port)
end
it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
+ @http.started?.should == false
end
end
@@ -31,8 +31,8 @@ describe "Net::HTTP.new" do
end
it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
+ @http.proxy?.should == false
+ @http.instance_of?(Net::HTTP).should == true
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -40,44 +40,44 @@ describe "Net::HTTP.new" do
end
it "sets the new Net::HTTP instance's port to the passed port" do
- @http.port.should eql(3333)
+ @http.port.should.eql?(3333)
end
it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
+ @http.started?.should == false
end
end
describe "when passed address, port, *proxy_options" do
it "returns a Net::HTTP instance" do
http = Net::HTTP.new("localhost", 3333, "localhost")
- http.proxy?.should be_true
- http.instance_of?(Net::HTTP).should be_true
- http.should be_kind_of(Net::HTTP)
+ http.proxy?.should == true
+ http.instance_of?(Net::HTTP).should == true
+ http.should.is_a?(Net::HTTP)
end
it "correctly sets the passed Proxy options" do
http = Net::HTTP.new("localhost", 3333, "localhost")
http.proxy_address.should == "localhost"
- http.proxy_port.should eql(80)
- http.proxy_user.should be_nil
- http.proxy_pass.should be_nil
+ http.proxy_port.should.eql?(80)
+ http.proxy_user.should == nil
+ http.proxy_pass.should == nil
http = Net::HTTP.new("localhost", 3333, "localhost", 1234)
http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should be_nil
- http.proxy_pass.should be_nil
+ http.proxy_port.should.eql?(1234)
+ http.proxy_user.should == nil
+ http.proxy_pass.should == nil
http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec")
http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
+ http.proxy_port.should.eql?(1234)
http.proxy_user.should == "rubyspec"
- http.proxy_pass.should be_nil
+ http.proxy_pass.should == nil
http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec", "rocks")
http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
+ http.proxy_port.should.eql?(1234)
http.proxy_user.should == "rubyspec"
http.proxy_pass.should == "rocks"
end
diff --git a/spec/ruby/library/net-http/http/newobj_spec.rb b/spec/ruby/library/net-http/http/newobj_spec.rb
index e19b30fca9..d398fb7d9a 100644
--- a/spec/ruby/library/net-http/http/newobj_spec.rb
+++ b/spec/ruby/library/net-http/http/newobj_spec.rb
@@ -8,7 +8,7 @@ describe "Net::HTTP.newobj" do
describe "when passed address" do
it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
+ @net.should.is_a?(Net::HTTP)
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -16,11 +16,11 @@ describe "Net::HTTP.newobj" do
end
it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
+ @net.port.should.eql?(Net::HTTP.default_port)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == false
end
end
@@ -30,7 +30,7 @@ describe "Net::HTTP.newobj" do
end
it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
+ @net.should.is_a?(Net::HTTP)
end
it "sets the new Net::HTTP instance's address to the passed address" do
@@ -38,11 +38,11 @@ describe "Net::HTTP.newobj" do
end
it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
+ @net.port.should.eql?(3333)
end
it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
+ @net.started?.should == false
end
end
end
diff --git a/spec/ruby/library/net-http/http/open_timeout_spec.rb b/spec/ruby/library/net-http/http/open_timeout_spec.rb
index 0d93752271..d00f844b38 100644
--- a/spec/ruby/library/net-http/http/open_timeout_spec.rb
+++ b/spec/ruby/library/net-http/http/open_timeout_spec.rb
@@ -4,9 +4,9 @@ require 'net/http'
describe "Net::HTTP#open_timeout" do
it "returns the seconds to wait till the connection is open" do
net = Net::HTTP.new("localhost")
- net.open_timeout.should eql(60)
+ net.open_timeout.should.eql?(60)
net.open_timeout = 10
- net.open_timeout.should eql(10)
+ net.open_timeout.should.eql?(10)
end
end
@@ -14,11 +14,11 @@ describe "Net::HTTP#open_timeout=" do
it "sets the seconds to wait till the connection is open" do
net = Net::HTTP.new("localhost")
net.open_timeout = 10
- net.open_timeout.should eql(10)
+ net.open_timeout.should.eql?(10)
end
it "returns the newly set value" do
net = Net::HTTP.new("localhost")
- (net.open_timeout = 10).should eql(10)
+ (net.open_timeout = 10).should.eql?(10)
end
end
diff --git a/spec/ruby/library/net-http/http/options_spec.rb b/spec/ruby/library/net-http/http/options_spec.rb
index 3d9887a557..3b90573cfa 100644
--- a/spec/ruby/library/net-http/http/options_spec.rb
+++ b/spec/ruby/library/net-http/http/options_spec.rb
@@ -20,6 +20,6 @@ describe "Net::HTTP#options" do
end
it "returns a Net::HTTPResponse" do
- @http.options("/request").should be_kind_of(Net::HTTPResponse)
+ @http.options("/request").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/port_spec.rb b/spec/ruby/library/net-http/http/port_spec.rb
index 0984d5e6ce..edb689f9ca 100644
--- a/spec/ruby/library/net-http/http/port_spec.rb
+++ b/spec/ruby/library/net-http/http/port_spec.rb
@@ -4,6 +4,6 @@ require 'net/http'
describe "Net::HTTP#port" do
it "returns the current port number" do
net = Net::HTTP.new("localhost", 3333)
- net.port.should eql(3333)
+ net.port.should.eql?(3333)
end
end
diff --git a/spec/ruby/library/net-http/http/post_spec.rb b/spec/ruby/library/net-http/http/post_spec.rb
index ac020bd6be..f294411197 100644
--- a/spec/ruby/library/net-http/http/post_spec.rb
+++ b/spec/ruby/library/net-http/http/post_spec.rb
@@ -22,12 +22,14 @@ describe "Net::HTTP.post" do
it "returns a Net::HTTPResponse" do
response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request"), "test=test")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
- it "sends Content-Type: application/x-www-form-urlencoded by default" do
- response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
- response.body.should include({ "Content-Type" => "application/x-www-form-urlencoded" }.inspect.delete("{}"))
+ ruby_version_is ""..."4.0" do
+ it "sends Content-Type: application/x-www-form-urlencoded by default" do
+ response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
+ response.body.should.include?({ "Content-Type" => "application/x-www-form-urlencoded" }.inspect.delete("{}"))
+ end
end
it "does not support HTTP Basic Auth" do
@@ -55,7 +57,7 @@ describe "Net::HTTP#post" do
end
it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.post("/request", "test=test").should.is_a?(Net::HTTPResponse)
end
describe "when passed a block" do
@@ -68,7 +70,7 @@ describe "Net::HTTP#post" do
end
it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test") {}.should be_kind_of(Net::HTTPResponse)
+ @http.post("/request", "test=test") {}.should.is_a?(Net::HTTPResponse)
end
end
end
diff --git a/spec/ruby/library/net-http/http/propfind_spec.rb b/spec/ruby/library/net-http/http/propfind_spec.rb
index f3742d1b1a..6a1be0392a 100644
--- a/spec/ruby/library/net-http/http/propfind_spec.rb
+++ b/spec/ruby/library/net-http/http/propfind_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#propfind" do
end
it "returns a Net::HTTPResponse" do
- @http.propfind("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.propfind("/request", "test=test").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/proppatch_spec.rb b/spec/ruby/library/net-http/http/proppatch_spec.rb
index 0163d24d46..074dfafaef 100644
--- a/spec/ruby/library/net-http/http/proppatch_spec.rb
+++ b/spec/ruby/library/net-http/http/proppatch_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#proppatch" do
end
it "returns a Net::HTTPResponse" do
- @http.proppatch("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.proppatch("/request", "test=test").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/proxy_address_spec.rb b/spec/ruby/library/net-http/http/proxy_address_spec.rb
index 5b5efb7ac0..ba040336ad 100644
--- a/spec/ruby/library/net-http/http/proxy_address_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_address_spec.rb
@@ -4,7 +4,7 @@ require 'net/http'
describe "Net::HTTP.proxy_address" do
describe "when self is no proxy class" do
it "returns nil" do
- Net::HTTP.proxy_address.should be_nil
+ Net::HTTP.proxy_address.should == nil
end
end
@@ -18,7 +18,7 @@ end
describe "Net::HTTP#proxy_address" do
describe "when self is no proxy class instance" do
it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_address.should be_nil
+ Net::HTTP.new("localhost", 3333).proxy_address.should == nil
end
end
diff --git a/spec/ruby/library/net-http/http/proxy_class_spec.rb b/spec/ruby/library/net-http/http/proxy_class_spec.rb
index 00975aef4e..eda027c893 100644
--- a/spec/ruby/library/net-http/http/proxy_class_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_class_spec.rb
@@ -3,7 +3,7 @@ require 'net/http'
describe "Net::HTTP.proxy_class?" do
it "returns true if self is a class created with Net::HTTP.Proxy" do
- Net::HTTP.proxy_class?.should be_false
- Net::HTTP.Proxy("localhost").proxy_class?.should be_true
+ Net::HTTP.proxy_class?.should == false
+ Net::HTTP.Proxy("localhost").proxy_class?.should == true
end
end
diff --git a/spec/ruby/library/net-http/http/proxy_pass_spec.rb b/spec/ruby/library/net-http/http/proxy_pass_spec.rb
index 4e393a53ff..ad02d896c0 100644
--- a/spec/ruby/library/net-http/http/proxy_pass_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_pass_spec.rb
@@ -4,13 +4,13 @@ require 'net/http'
describe "Net::HTTP.proxy_pass" do
describe "when self is no proxy class" do
it "returns nil" do
- Net::HTTP.proxy_pass.should be_nil
+ Net::HTTP.proxy_pass.should == nil
end
end
describe "when self is a proxy class" do
it "returns nil if no password was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_pass.should be_nil
+ Net::HTTP.Proxy("localhost").proxy_pass.should == nil
end
it "returns the password for self's proxy connection" do
@@ -22,13 +22,13 @@ end
describe "Net::HTTP#proxy_pass" do
describe "when self is no proxy class instance" do
it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_pass.should be_nil
+ Net::HTTP.new("localhost", 3333).proxy_pass.should == nil
end
end
describe "when self is a proxy class instance" do
it "returns nil if no password was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should be_nil
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should == nil
end
it "returns the password for self's proxy connection" do
diff --git a/spec/ruby/library/net-http/http/proxy_port_spec.rb b/spec/ruby/library/net-http/http/proxy_port_spec.rb
index d7d37f3927..21c1e4180e 100644
--- a/spec/ruby/library/net-http/http/proxy_port_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_port_spec.rb
@@ -4,17 +4,17 @@ require 'net/http'
describe "Net::HTTP.proxy_port" do
describe "when self is no proxy class" do
it "returns nil" do
- Net::HTTP.proxy_port.should be_nil
+ Net::HTTP.proxy_port.should == nil
end
end
describe "when self is a proxy class" do
it "returns 80 if no port was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_port.should eql(80)
+ Net::HTTP.Proxy("localhost").proxy_port.should.eql?(80)
end
it "returns the port for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should eql(1234)
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should.eql?(1234)
end
end
end
@@ -22,18 +22,18 @@ end
describe "Net::HTTP#proxy_port" do
describe "when self is no proxy class instance" do
it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_port.should be_nil
+ Net::HTTP.new("localhost", 3333).proxy_port.should == nil
end
end
describe "when self is a proxy class instance" do
it "returns 80 if no port was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_port.should eql(80)
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_port.should.eql?(80)
end
it "returns the port for self's proxy connection" do
http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_port.should eql(1234)
+ http_with_proxy.new("localhost", 3333).proxy_port.should.eql?(1234)
end
end
end
diff --git a/spec/ruby/library/net-http/http/proxy_user_spec.rb b/spec/ruby/library/net-http/http/proxy_user_spec.rb
index ef7654425d..492ea2e8ee 100644
--- a/spec/ruby/library/net-http/http/proxy_user_spec.rb
+++ b/spec/ruby/library/net-http/http/proxy_user_spec.rb
@@ -4,13 +4,13 @@ require 'net/http'
describe "Net::HTTP.proxy_user" do
describe "when self is no proxy class" do
it "returns nil" do
- Net::HTTP.proxy_user.should be_nil
+ Net::HTTP.proxy_user.should == nil
end
end
describe "when self is a proxy class" do
it "returns nil if no username was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_user.should be_nil
+ Net::HTTP.Proxy("localhost").proxy_user.should == nil
end
it "returns the username for self's proxy connection" do
@@ -22,13 +22,13 @@ end
describe "Net::HTTP#proxy_user" do
describe "when self is no proxy class instance" do
it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_user.should be_nil
+ Net::HTTP.new("localhost", 3333).proxy_user.should == nil
end
end
describe "when self is a proxy class instance" do
it "returns nil if no username was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should be_nil
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should == nil
end
it "returns the username for self's proxy connection" do
diff --git a/spec/ruby/library/net-http/http/put_spec.rb b/spec/ruby/library/net-http/http/put_spec.rb
index 75f3c243d4..7ef9219f63 100644
--- a/spec/ruby/library/net-http/http/put_spec.rb
+++ b/spec/ruby/library/net-http/http/put_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#put" do
end
it "returns a Net::HTTPResponse" do
- @http.put("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.put("/request", "test=test").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/read_timeout_spec.rb b/spec/ruby/library/net-http/http/read_timeout_spec.rb
index 7a0d2f1d72..81e71337bb 100644
--- a/spec/ruby/library/net-http/http/read_timeout_spec.rb
+++ b/spec/ruby/library/net-http/http/read_timeout_spec.rb
@@ -4,9 +4,9 @@ require 'net/http'
describe "Net::HTTP#read_timeout" do
it "returns the seconds to wait until reading one block" do
net = Net::HTTP.new("localhost")
- net.read_timeout.should eql(60)
+ net.read_timeout.should.eql?(60)
net.read_timeout = 10
- net.read_timeout.should eql(10)
+ net.read_timeout.should.eql?(10)
end
end
@@ -14,11 +14,11 @@ describe "Net::HTTP#read_timeout=" do
it "sets the seconds to wait till the connection is open" do
net = Net::HTTP.new("localhost")
net.read_timeout = 10
- net.read_timeout.should eql(10)
+ net.read_timeout.should.eql?(10)
end
it "returns the newly set value" do
net = Net::HTTP.new("localhost")
- (net.read_timeout = 10).should eql(10)
+ (net.read_timeout = 10).should.eql?(10)
end
end
diff --git a/spec/ruby/library/net-http/http/request_spec.rb b/spec/ruby/library/net-http/http/request_spec.rb
index 356e605b3b..e05ee96b55 100644
--- a/spec/ruby/library/net-http/http/request_spec.rb
+++ b/spec/ruby/library/net-http/http/request_spec.rb
@@ -19,7 +19,7 @@ describe "Net::HTTP#request" do
response.body.should == "Request type: GET"
response = @http.request(Net::HTTP::Head.new("/request"), "test=test")
- response.body.should be_nil
+ response.body.should == nil
response = @http.request(Net::HTTP::Post.new("/request"), "test=test")
response.body.should == "Request type: POST"
@@ -38,7 +38,7 @@ describe "Net::HTTP#request" do
# TODO: Does not work?
#response = @http.request(Net::HTTP::Options.new("/request"), "test=test")
- #response.body.should be_nil
+ #response.body.should == nil
response = @http.request(Net::HTTP::Propfind.new("/request"), "test=test")
response.body.should == "Request type: PROPFIND"
@@ -66,7 +66,7 @@ describe "Net::HTTP#request" do
response.body.should == "test=test"
response = @http.request(Net::HTTP::Head.new("/request/body"), "test=test")
- response.body.should be_nil
+ response.body.should == nil
response = @http.request(Net::HTTP::Post.new("/request/body"), "test=test")
response.body.should == "test=test"
@@ -85,7 +85,7 @@ describe "Net::HTTP#request" do
# TODO: Does not work?
#response = @http.request(Net::HTTP::Options.new("/request/body"), "test=test")
- #response.body.should be_nil
+ #response.body.should == nil
response = @http.request(Net::HTTP::Propfind.new("/request/body"), "test=test")
response.body.should == "test=test"
diff --git a/spec/ruby/library/net-http/http/request_types_spec.rb b/spec/ruby/library/net-http/http/request_types_spec.rb
index 53aef1ee58..0adc625979 100644
--- a/spec/ruby/library/net-http/http/request_types_spec.rb
+++ b/spec/ruby/library/net-http/http/request_types_spec.rb
@@ -11,11 +11,11 @@ describe "Net::HTTP::Get" do
end
it "has no Request Body" do
- Net::HTTP::Get::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Get::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Get::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Get::RESPONSE_HAS_BODY.should == true
end
end
@@ -29,11 +29,11 @@ describe "Net::HTTP::Head" do
end
it "has no Request Body" do
- Net::HTTP::Head::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Head::REQUEST_HAS_BODY.should == false
end
it "has no Response Body" do
- Net::HTTP::Head::RESPONSE_HAS_BODY.should be_false
+ Net::HTTP::Head::RESPONSE_HAS_BODY.should == false
end
end
@@ -47,11 +47,11 @@ describe "Net::HTTP::Post" do
end
it "has a Request Body" do
- Net::HTTP::Post::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Post::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Post::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Post::RESPONSE_HAS_BODY.should == true
end
end
@@ -65,11 +65,11 @@ describe "Net::HTTP::Put" do
end
it "has a Request Body" do
- Net::HTTP::Put::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Put::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Put::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Put::RESPONSE_HAS_BODY.should == true
end
end
@@ -83,11 +83,11 @@ describe "Net::HTTP::Delete" do
end
it "has no Request Body" do
- Net::HTTP::Delete::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Delete::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Delete::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Delete::RESPONSE_HAS_BODY.should == true
end
end
@@ -101,11 +101,11 @@ describe "Net::HTTP::Options" do
end
it "has no Request Body" do
- Net::HTTP::Options::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Options::REQUEST_HAS_BODY.should == false
end
it "has no Response Body" do
- Net::HTTP::Options::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Options::RESPONSE_HAS_BODY.should == true
end
end
@@ -119,11 +119,11 @@ describe "Net::HTTP::Trace" do
end
it "has no Request Body" do
- Net::HTTP::Trace::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Trace::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Trace::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Trace::RESPONSE_HAS_BODY.should == true
end
end
@@ -137,11 +137,11 @@ describe "Net::HTTP::Propfind" do
end
it "has a Request Body" do
- Net::HTTP::Propfind::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Propfind::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Propfind::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Propfind::RESPONSE_HAS_BODY.should == true
end
end
@@ -155,11 +155,11 @@ describe "Net::HTTP::Proppatch" do
end
it "has a Request Body" do
- Net::HTTP::Proppatch::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Proppatch::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should == true
end
end
@@ -173,11 +173,11 @@ describe "Net::HTTP::Mkcol" do
end
it "has a Request Body" do
- Net::HTTP::Mkcol::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Mkcol::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should == true
end
end
@@ -191,11 +191,11 @@ describe "Net::HTTP::Copy" do
end
it "has no Request Body" do
- Net::HTTP::Copy::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Copy::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Copy::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Copy::RESPONSE_HAS_BODY.should == true
end
end
@@ -209,11 +209,11 @@ describe "Net::HTTP::Move" do
end
it "has no Request Body" do
- Net::HTTP::Move::REQUEST_HAS_BODY.should be_false
+ Net::HTTP::Move::REQUEST_HAS_BODY.should == false
end
it "has a Response Body" do
- Net::HTTP::Move::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Move::RESPONSE_HAS_BODY.should == true
end
end
@@ -227,11 +227,11 @@ describe "Net::HTTP::Lock" do
end
it "has a Request Body" do
- Net::HTTP::Lock::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Lock::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Lock::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Lock::RESPONSE_HAS_BODY.should == true
end
end
@@ -245,10 +245,10 @@ describe "Net::HTTP::Unlock" do
end
it "has a Request Body" do
- Net::HTTP::Unlock::REQUEST_HAS_BODY.should be_true
+ Net::HTTP::Unlock::REQUEST_HAS_BODY.should == true
end
it "has a Response Body" do
- Net::HTTP::Unlock::RESPONSE_HAS_BODY.should be_true
+ Net::HTTP::Unlock::RESPONSE_HAS_BODY.should == true
end
end
diff --git a/spec/ruby/library/net-http/http/send_request_spec.rb b/spec/ruby/library/net-http/http/send_request_spec.rb
index af35c068ce..e2dfc505b6 100644
--- a/spec/ruby/library/net-http/http/send_request_spec.rb
+++ b/spec/ruby/library/net-http/http/send_request_spec.rb
@@ -24,7 +24,7 @@ describe "Net::HTTP#send_request" do
describe "when passed type, path" do
it "sends a HTTP Request of the passed type to the passed path" do
response = @http.send_request("HEAD", "/request")
- response.body.should be_nil
+ response.body.should == nil
(@methods - %w[POST PUT]).each do |method|
response = @http.send_request(method, "/request")
@@ -36,7 +36,7 @@ describe "Net::HTTP#send_request" do
describe "when passed type, path, body" do
it "sends a HTTP Request with the passed body" do
response = @http.send_request("HEAD", "/request/body", "test=test")
- response.body.should be_nil
+ response.body.should == nil
@methods.each do |method|
response = @http.send_request(method, "/request/body", "test=test")
@@ -50,11 +50,11 @@ describe "Net::HTTP#send_request" do
referer = 'https://www.ruby-lang.org/'.freeze
response = @http.send_request("HEAD", "/request/header", "test=test", "referer" => referer)
- response.body.should be_nil
+ response.body.should == nil
@methods.each do |method|
response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
- response.body.should include({ "Referer" => referer }.inspect.delete("{}"))
+ response.body.should.include?({ "Referer" => referer }.inspect.delete("{}"))
end
end
end
diff --git a/spec/ruby/library/net-http/http/set_debug_output_spec.rb b/spec/ruby/library/net-http/http/set_debug_output_spec.rb
index 5ceecb39fb..491ac38b5d 100644
--- a/spec/ruby/library/net-http/http/set_debug_output_spec.rb
+++ b/spec/ruby/library/net-http/http/set_debug_output_spec.rb
@@ -19,7 +19,7 @@ describe "Net::HTTP#set_debug_output when passed io" do
@http.set_debug_output(io)
@http.start
- io.string.should_not be_empty
+ io.string.should_not.empty?
size = io.string.size
@http.get("/")
diff --git a/spec/ruby/library/net-http/http/shared/request_get.rb b/spec/ruby/library/net-http/http/shared/request_get.rb
index d25f32049b..4f2f152ea4 100644
--- a/spec/ruby/library/net-http/http/shared/request_get.rb
+++ b/spec/ruby/library/net-http/http/shared/request_get.rb
@@ -17,7 +17,7 @@ describe :net_http_request_get, shared: true do
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
@@ -35,7 +35,7 @@ describe :net_http_request_get, shared: true do
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request") {}
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
end
diff --git a/spec/ruby/library/net-http/http/shared/request_head.rb b/spec/ruby/library/net-http/http/shared/request_head.rb
index 78b555884b..a5fe787d32 100644
--- a/spec/ruby/library/net-http/http/shared/request_head.rb
+++ b/spec/ruby/library/net-http/http/shared/request_head.rb
@@ -12,30 +12,30 @@ describe :net_http_request_head, shared: true do
describe "when passed no block" do
it "sends a head request to the passed path and returns the response" do
response = @http.send(@method, "/request")
- response.body.should be_nil
+ response.body.should == nil
end
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
describe "when passed a block" do
it "sends a head request to the passed path and returns the response" do
response = @http.send(@method, "/request") {}
- response.body.should be_nil
+ response.body.should == nil
end
it "yields the response to the passed block" do
@http.send(@method, "/request") do |response|
- response.body.should be_nil
+ response.body.should == nil
end
end
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request") {}
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
end
diff --git a/spec/ruby/library/net-http/http/shared/request_post.rb b/spec/ruby/library/net-http/http/shared/request_post.rb
index e832411c48..73cfd577cf 100644
--- a/spec/ruby/library/net-http/http/shared/request_post.rb
+++ b/spec/ruby/library/net-http/http/shared/request_post.rb
@@ -17,7 +17,7 @@ describe :net_http_request_post, shared: true do
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
@@ -35,7 +35,7 @@ describe :net_http_request_post, shared: true do
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request", "test=test") {}
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
end
diff --git a/spec/ruby/library/net-http/http/shared/request_put.rb b/spec/ruby/library/net-http/http/shared/request_put.rb
index 3b902f4957..3b64d7e055 100644
--- a/spec/ruby/library/net-http/http/shared/request_put.rb
+++ b/spec/ruby/library/net-http/http/shared/request_put.rb
@@ -17,7 +17,7 @@ describe :net_http_request_put, shared: true do
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
@@ -35,7 +35,7 @@ describe :net_http_request_put, shared: true do
it "returns a Net::HTTPResponse object" do
response = @http.send(@method, "/request", "test=test") {}
- response.should be_kind_of(Net::HTTPResponse)
+ response.should.is_a?(Net::HTTPResponse)
end
end
end
diff --git a/spec/ruby/library/net-http/http/shared/started.rb b/spec/ruby/library/net-http/http/shared/started.rb
index 9ff6272c31..0ab18a4e83 100644
--- a/spec/ruby/library/net-http/http/shared/started.rb
+++ b/spec/ruby/library/net-http/http/shared/started.rb
@@ -11,16 +11,16 @@ describe :net_http_started_p, shared: true do
it "returns true when self has been started" do
@http.start
- @http.send(@method).should be_true
+ @http.send(@method).should == true
end
it "returns false when self has not been started yet" do
- @http.send(@method).should be_false
+ @http.send(@method).should == false
end
it "returns false when self has been stopped again" do
@http.start
@http.finish
- @http.send(@method).should be_false
+ @http.send(@method).should == false
end
end
diff --git a/spec/ruby/library/net-http/http/shared/version_1_1.rb b/spec/ruby/library/net-http/http/shared/version_1_1.rb
index db3d6a986d..84e7264eab 100644
--- a/spec/ruby/library/net-http/http/shared/version_1_1.rb
+++ b/spec/ruby/library/net-http/http/shared/version_1_1.rb
@@ -1,6 +1,6 @@
describe :net_http_version_1_1_p, shared: true do
it "returns the state of net/http 1.1 features" do
Net::HTTP.version_1_2
- Net::HTTP.send(@method).should be_false
+ Net::HTTP.send(@method).should == false
end
end
diff --git a/spec/ruby/library/net-http/http/shared/version_1_2.rb b/spec/ruby/library/net-http/http/shared/version_1_2.rb
index b044182c60..dcf5419704 100644
--- a/spec/ruby/library/net-http/http/shared/version_1_2.rb
+++ b/spec/ruby/library/net-http/http/shared/version_1_2.rb
@@ -1,6 +1,6 @@
describe :net_http_version_1_2_p, shared: true do
it "returns the state of net/http 1.2 features" do
Net::HTTP.version_1_2
- Net::HTTP.send(@method).should be_true
+ Net::HTTP.send(@method).should == true
end
end
diff --git a/spec/ruby/library/net-http/http/start_spec.rb b/spec/ruby/library/net-http/http/start_spec.rb
index 0ce3e79269..1aebc16f4d 100644
--- a/spec/ruby/library/net-http/http/start_spec.rb
+++ b/spec/ruby/library/net-http/http/start_spec.rb
@@ -22,13 +22,13 @@ describe "Net::HTTP.start" do
end
it "returns a new Net::HTTP object for the passed address and port" do
- @http.should be_kind_of(Net::HTTP)
+ @http.should.is_a?(Net::HTTP)
@http.address.should == "localhost"
@http.port.should == @port
end
it "opens the tcp connection" do
- @http.started?.should be_true
+ @http.started?.should == true
end
end
@@ -41,19 +41,19 @@ describe "Net::HTTP.start" do
yielded = false
Net::HTTP.start("localhost", @port) do |net|
yielded = true
- net.should be_kind_of(Net::HTTP)
+ net.should.is_a?(Net::HTTP)
end
- yielded.should be_true
+ yielded.should == true
end
it "opens the tcp connection before yielding" do
- Net::HTTP.start("localhost", @port) { |http| http.started?.should be_true }
+ Net::HTTP.start("localhost", @port) { |http| http.started?.should == true }
end
it "closes the tcp connection after yielding" do
net = nil
Net::HTTP.start("localhost", @port) { |x| net = x }
- net.started?.should be_false
+ net.started?.should == false
end
end
end
@@ -70,18 +70,18 @@ describe "Net::HTTP#start" do
end
it "returns self" do
- @http.start.should equal(@http)
+ @http.start.should.equal?(@http)
end
it "opens the tcp connection" do
@http.start
- @http.started?.should be_true
+ @http.started?.should == true
end
describe "when self has already been started" do
it "raises an IOError" do
@http.start
- -> { @http.start }.should raise_error(IOError)
+ -> { @http.start }.should.raise(IOError)
end
end
@@ -94,18 +94,18 @@ describe "Net::HTTP#start" do
yielded = false
@http.start do |http|
yielded = true
- http.should equal(@http)
+ http.should.equal?(@http)
end
- yielded.should be_true
+ yielded.should == true
end
it "opens the tcp connection before yielding" do
- @http.start { |http| http.started?.should be_true }
+ @http.start { |http| http.started?.should == true }
end
it "closes the tcp connection after yielding" do
@http.start { }
- @http.started?.should be_false
+ @http.started?.should == false
end
end
end
diff --git a/spec/ruby/library/net-http/http/trace_spec.rb b/spec/ruby/library/net-http/http/trace_spec.rb
index 9809d537c5..e0ff741b04 100644
--- a/spec/ruby/library/net-http/http/trace_spec.rb
+++ b/spec/ruby/library/net-http/http/trace_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#trace" do
end
it "returns a Net::HTTPResponse" do
- @http.trace("/request").should be_kind_of(Net::HTTPResponse)
+ @http.trace("/request").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/unlock_spec.rb b/spec/ruby/library/net-http/http/unlock_spec.rb
index adf0b49f65..cbfc803f09 100644
--- a/spec/ruby/library/net-http/http/unlock_spec.rb
+++ b/spec/ruby/library/net-http/http/unlock_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTP#unlock" do
end
it "returns a Net::HTTPResponse" do
- @http.unlock("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ @http.unlock("/request", "test=test").should.is_a?(Net::HTTPResponse)
end
end
diff --git a/spec/ruby/library/net-http/http/use_ssl_spec.rb b/spec/ruby/library/net-http/http/use_ssl_spec.rb
index 912a62a8ba..b283655359 100644
--- a/spec/ruby/library/net-http/http/use_ssl_spec.rb
+++ b/spec/ruby/library/net-http/http/use_ssl_spec.rb
@@ -4,6 +4,6 @@ require 'net/http'
describe "Net::HTTP#use_ssl?" do
it "returns false" do
http = Net::HTTP.new("localhost")
- http.use_ssl?.should be_false
+ http.use_ssl?.should == false
end
end
diff --git a/spec/ruby/library/net-http/http/version_1_2_spec.rb b/spec/ruby/library/net-http/http/version_1_2_spec.rb
index e994511aea..4918597234 100644
--- a/spec/ruby/library/net-http/http/version_1_2_spec.rb
+++ b/spec/ruby/library/net-http/http/version_1_2_spec.rb
@@ -6,12 +6,12 @@ describe "Net::HTTP.version_1_2" do
it "turns on net/http 1.2 features" do
Net::HTTP.version_1_2
- Net::HTTP.version_1_2?.should be_true
- Net::HTTP.version_1_1?.should be_false
+ Net::HTTP.version_1_2?.should == true
+ Net::HTTP.version_1_1?.should == false
end
it "returns true" do
- Net::HTTP.version_1_2.should be_true
+ Net::HTTP.version_1_2.should == true
end
end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
index 6c886499ca..96a761929e 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
@@ -4,10 +4,10 @@ require 'net/http'
describe "Net::HTTPGenericRequest#body_exist?" do
it "returns true when the response is expected to have a body" do
request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body_exist?.should be_true
+ request.body_exist?.should == true
request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.body_exist?.should be_false
+ request.body_exist?.should == false
end
describe "when $VERBOSE is true" do
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
index 5f7315f303..63cda994e5 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
@@ -5,7 +5,7 @@ require "stringio"
describe "Net::HTTPGenericRequest#body" do
it "returns self's request body" do
request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body.should be_nil
+ request.body.should == nil
request.body = "Some Content"
request.body.should == "Some Content"
@@ -25,6 +25,6 @@ describe "Net::HTTPGenericRequest#body=" do
it "sets self's body stream to nil" do
@request.body_stream = StringIO.new("")
@request.body = "Some Content"
- @request.body_stream.should be_nil
+ @request.body_stream.should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
index dea1c8c883..3237dbb861 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
@@ -5,11 +5,11 @@ require "stringio"
describe "Net::HTTPGenericRequest#body_stream" do
it "returns self's body stream Object" do
request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body_stream.should be_nil
+ request.body_stream.should == nil
stream = StringIO.new("test")
request.body_stream = stream
- request.body_stream.should equal(stream)
+ request.body_stream.should.equal?(stream)
end
end
@@ -21,12 +21,12 @@ describe "Net::HTTPGenericRequest#body_stream=" do
it "sets self's body stream to the passed Object" do
@request.body_stream = @stream
- @request.body_stream.should equal(@stream)
+ @request.body_stream.should.equal?(@stream)
end
it "sets self's body to nil" do
@request.body = "Some Content"
@request.body_stream = @stream
- @request.body.should be_nil
+ @request.body.should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
index 7de03d7da0..0ccf80e3b6 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
@@ -31,18 +31,20 @@ describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
end
describe "when a request body is set" do
- it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body = "Some Content"
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
- str.should =~ %r[Content-Length: 12\r\n]
- str[-16..-1].should == "\r\n\r\nSome Content"
+ ruby_version_is ""..."4.0" do
+ it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body = "Some Content"
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
+ str.should =~ %r[Content-Length: 12\r\n]
+ str[-16..-1].should == "\r\n\r\nSome Content"
+ end
end
it "correctly sets the 'Content-Length' header and includes the body" do
@@ -62,19 +64,21 @@ describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
end
describe "when a body stream is set" do
- it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Length" => "10")
- request.body_stream = StringIO.new("a" * 20)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
- str.should =~ %r[Content-Length: 10\r\n]
- str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
+ ruby_version_is ""..."4.0" do
+ it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Length" => "10")
+ request.body_stream = StringIO.new("a" * 20)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
+ str.should =~ %r[Content-Length: 10\r\n]
+ str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
+ end
end
it "sends the whole stream, regardless of the 'Content-Length' header" do
@@ -125,7 +129,7 @@ describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
"Content-Type" => "text/html")
request.body_stream = StringIO.new("Some Content")
- -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should raise_error(ArgumentError)
+ -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
index 1713b59baf..ba836e8130 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
@@ -4,9 +4,9 @@ require 'net/http'
describe "Net::HTTPGenericRequest#request_body_permitted?" do
it "returns true when the request is expected to have a body" do
request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.request_body_permitted?.should be_true
+ request.request_body_permitted?.should == true
request = Net::HTTPGenericRequest.new("POST", false, true, "/some/path")
- request.request_body_permitted?.should be_false
+ request.request_body_permitted?.should == false
end
end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
index 2f0751c344..067500f60d 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
@@ -4,9 +4,9 @@ require 'net/http'
describe "Net::HTTPGenericRequest#response_body_permitted?" do
it "returns true when the response is expected to have a body" do
request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.response_body_permitted?.should be_true
+ request.response_body_permitted?.should == true
request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.response_body_permitted?.should be_false
+ request.response_body_permitted?.should == false
end
end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
index 358aa6cde3..f241d8d698 100644
--- a/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
+++ b/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
@@ -13,9 +13,9 @@ describe "Net::HTTPGenericRequest#set_body_internal when passed string" do
it "raises an ArgumentError when the body or body_stream of self have already been set" do
@request.body = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+ -> { @request.set_body_internal("Some other Content") }.should.raise(ArgumentError)
@request.body_stream = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+ -> { @request.set_body_internal("Some other Content") }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/chunked_spec.rb b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
index b32a0aab38..4da218ae25 100644
--- a/spec/ruby/library/net-http/httpheader/chunked_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
@@ -8,15 +8,15 @@ describe "Net::HTTPHeader#chunked?" do
end
it "returns true if the 'Transfer-Encoding' header entry is set to chunked" do
- @headers.chunked?.should be_false
+ @headers.chunked?.should == false
@headers["Transfer-Encoding"] = "bla"
- @headers.chunked?.should be_false
+ @headers.chunked?.should == false
@headers["Transfer-Encoding"] = "blachunkedbla"
- @headers.chunked?.should be_false
+ @headers.chunked?.should == false
@headers["Transfer-Encoding"] = "chunked"
- @headers.chunked?.should be_true
+ @headers.chunked?.should == true
end
end
diff --git a/spec/ruby/library/net-http/httpheader/content_length_spec.rb b/spec/ruby/library/net-http/httpheader/content_length_spec.rb
index f05c5f8d8b..c66d5673c1 100644
--- a/spec/ruby/library/net-http/httpheader/content_length_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/content_length_spec.rb
@@ -8,23 +8,23 @@ describe "Net::HTTPHeader#content_length" do
end
it "returns nil if no 'Content-Length' header entry is set" do
- @headers.content_length.should be_nil
+ @headers.content_length.should == nil
end
it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Length' header entry has an invalid format" do
@headers["Content-Length"] = "invalid"
- -> { @headers.content_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.content_length }.should.raise(Net::HTTPHeaderSyntaxError)
end
it "returns the value of the 'Content-Length' header entry as an Integer" do
@headers["Content-Length"] = "123"
- @headers.content_length.should eql(123)
+ @headers.content_length.should.eql?(123)
@headers["Content-Length"] = "123valid"
- @headers.content_length.should eql(123)
+ @headers.content_length.should.eql?(123)
@headers["Content-Length"] = "valid123"
- @headers.content_length.should eql(123)
+ @headers.content_length.should.eql?(123)
end
end
@@ -36,7 +36,7 @@ describe "Net::HTTPHeader#content_length=" do
it "removes the 'Content-Length' entry if passed false or nil" do
@headers["Content-Length"] = "123"
@headers.content_length = nil
- @headers["Content-Length"].should be_nil
+ @headers["Content-Length"].should == nil
end
it "sets the 'Content-Length' entry to the passed value" do
diff --git a/spec/ruby/library/net-http/httpheader/content_range_spec.rb b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
index 09737141a5..3635fb3f1b 100644
--- a/spec/ruby/library/net-http/httpheader/content_range_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
@@ -16,17 +16,17 @@ describe "Net::HTTPHeader#content_range" do
end
it "returns nil when there is no 'Content-Range' header entry" do
- @headers.content_range.should be_nil
+ @headers.content_range.should == nil
end
it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
@headers["Content-Range"] = "invalid"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.content_range }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.content_range }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes abc-123"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.content_range }.should.raise(Net::HTTPHeaderSyntaxError)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/content_type_spec.rb b/spec/ruby/library/net-http/httpheader/content_type_spec.rb
index a6e1ae1093..c9c936ba0f 100644
--- a/spec/ruby/library/net-http/httpheader/content_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/content_type_spec.rb
@@ -17,7 +17,7 @@ describe "Net::HTTPHeader#content_type" do
end
it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.content_type.should be_nil
+ @headers.content_type.should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpheader/delete_spec.rb b/spec/ruby/library/net-http/httpheader/delete_spec.rb
index 8d929dbd86..09bae65a13 100644
--- a/spec/ruby/library/net-http/httpheader/delete_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/delete_spec.rb
@@ -11,8 +11,8 @@ describe "Net::HTTPHeader#delete when passed key" do
@headers["My-Header"] = "test"
@headers.delete("My-Header")
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
+ @headers["My-Header"].should == nil
+ @headers.size.should.eql?(0)
end
it "returns the removed values" do
@@ -24,7 +24,7 @@ describe "Net::HTTPHeader#delete when passed key" do
@headers["My-Header"] = "test"
@headers.delete("my-header")
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
+ @headers["My-Header"].should == nil
+ @headers.size.should.eql?(0)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb b/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
index 27713577f9..54874c0535 100644
--- a/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
@@ -23,7 +23,7 @@ describe "Net::HTTPHeader#each_capitalized_name" do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.each_capitalized_name
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |key|
diff --git a/spec/ruby/library/net-http/httpheader/each_value_spec.rb b/spec/ruby/library/net-http/httpheader/each_value_spec.rb
index b71df58c65..55ba4c1ef8 100644
--- a/spec/ruby/library/net-http/httpheader/each_value_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/each_value_spec.rb
@@ -23,7 +23,7 @@ describe "Net::HTTPHeader#each_value" do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.each_value
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |key|
diff --git a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
index 1003c41af9..f12f8494db 100644
--- a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
@@ -33,7 +33,7 @@ describe "Net::HTTPHeader#[] when passed key" do
end
it "returns nil for non-existing entries" do
- @headers["My-Header"].should be_nil
- @headers["My-Other-Header"].should be_nil
+ @headers["My-Header"].should == nil
+ @headers["My-Other-Header"].should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpheader/element_set_spec.rb b/spec/ruby/library/net-http/httpheader/element_set_spec.rb
index 376df2f977..633fe18b2e 100644
--- a/spec/ruby/library/net-http/httpheader/element_set_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/element_set_spec.rb
@@ -26,16 +26,16 @@ describe "Net::HTTPHeader#[]= when passed key, value" do
@headers['MY-HEADER'] = "last one"
@headers["My-Header"].should == "last one"
- @headers.size.should eql(1)
+ @headers.size.should.eql?(1)
end
it "removes the header entry with the passed key when the value is false or nil" do
@headers['My-Header'] = "test"
@headers['My-Header'] = nil
- @headers['My-Header'].should be_nil
+ @headers['My-Header'].should == nil
@headers['My-Header'] = "test"
@headers['My-Header'] = false
- @headers['My-Header'].should be_nil
+ @headers['My-Header'].should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpheader/fetch_spec.rb b/spec/ruby/library/net-http/httpheader/fetch_spec.rb
index 58c69c0377..d1c273dada 100644
--- a/spec/ruby/library/net-http/httpheader/fetch_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/fetch_spec.rb
@@ -25,7 +25,7 @@ describe "Net::HTTPHeader#fetch" do
end
it "returns nil when there is no entry for the passed key" do
- -> { @headers.fetch("my-header") }.should raise_error(IndexError)
+ -> { @headers.fetch("my-header") }.should.raise(IndexError)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/get_fields_spec.rb b/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
index 0278bcede2..76da63bc31 100644
--- a/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
@@ -26,8 +26,8 @@ describe "Net::HTTPHeader#get_fields when passed key" do
end
it "returns nil for non-existing header entries" do
- @headers.get_fields("My-Header").should be_nil
- @headers.get_fields("My-Other-header").should be_nil
+ @headers.get_fields("My-Header").should == nil
+ @headers.get_fields("My-Other-header").should == nil
end
it "is case-insensitive" do
diff --git a/spec/ruby/library/net-http/httpheader/key_spec.rb b/spec/ruby/library/net-http/httpheader/key_spec.rb
index 2b7aeb9c2a..65662591eb 100644
--- a/spec/ruby/library/net-http/httpheader/key_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/key_spec.rb
@@ -8,14 +8,14 @@ describe "Net::HTTPHeader#key? when passed key" do
end
it "returns true if the header entry with the passed key exists" do
- @headers.key?("My-Header").should be_false
+ @headers.key?("My-Header").should == false
@headers["My-Header"] = "test"
- @headers.key?("My-Header").should be_true
+ @headers.key?("My-Header").should == true
end
it "is case-insensitive" do
@headers["My-Header"] = "test"
- @headers.key?("my-header").should be_true
- @headers.key?("MY-HEADER").should be_true
+ @headers.key?("my-header").should == true
+ @headers.key?("MY-HEADER").should == true
end
end
diff --git a/spec/ruby/library/net-http/httpheader/main_type_spec.rb b/spec/ruby/library/net-http/httpheader/main_type_spec.rb
index 4dd551d8f4..af7d3e05a3 100644
--- a/spec/ruby/library/net-http/httpheader/main_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/main_type_spec.rb
@@ -19,6 +19,6 @@ describe "Net::HTTPHeader#main_type" do
end
it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.main_type.should be_nil
+ @headers.main_type.should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpheader/range_length_spec.rb b/spec/ruby/library/net-http/httpheader/range_length_spec.rb
index 77323ac872..34db7e6126 100644
--- a/spec/ruby/library/net-http/httpheader/range_length_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/range_length_spec.rb
@@ -9,24 +9,24 @@ describe "Net::HTTPHeader#range_length" do
it "returns the length of the Range represented by the 'Content-Range' header entry" do
@headers["Content-Range"] = "bytes 0-499/1234"
- @headers.range_length.should eql(500)
+ @headers.range_length.should.eql?(500)
@headers["Content-Range"] = "bytes 500-1233/1234"
- @headers.range_length.should eql(734)
+ @headers.range_length.should.eql?(734)
end
it "returns nil when there is no 'Content-Range' header entry" do
- @headers.range_length.should be_nil
+ @headers.range_length.should == nil
end
it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
@headers["Content-Range"] = "invalid"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range_length }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range_length }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Content-Range"] = "bytes abc-123"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range_length }.should.raise(Net::HTTPHeaderSyntaxError)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/range_spec.rb b/spec/ruby/library/net-http/httpheader/range_spec.rb
index 2de80a825e..0fc0feb5c9 100644
--- a/spec/ruby/library/net-http/httpheader/range_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/range_spec.rb
@@ -23,23 +23,23 @@ describe "Net::HTTPHeader#range" do
end
it "returns nil when there is no 'Range' header entry" do
- @headers.range.should be_nil
+ @headers.range.should == nil
end
it "raises a Net::HTTPHeaderSyntaxError when the 'Range' has an invalid format" do
@headers["Range"] = "invalid"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Range"] = "bytes 123-abc"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range }.should.raise(Net::HTTPHeaderSyntaxError)
@headers["Range"] = "bytes abc-123"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range }.should.raise(Net::HTTPHeaderSyntaxError)
end
it "raises a Net::HTTPHeaderSyntaxError when the 'Range' was not specified" do
@headers["Range"] = "bytes=-"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.range }.should.raise(Net::HTTPHeaderSyntaxError)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb b/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
index 3bac409876..c12df62787 100644
--- a/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
@@ -19,7 +19,7 @@ describe :net_httpheader_each_capitalized, shared: true do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.send(@method)
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |*key|
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_header.rb b/spec/ruby/library/net-http/httpheader/shared/each_header.rb
index 6bf3a6ddfe..5913665a4d 100644
--- a/spec/ruby/library/net-http/httpheader/shared/each_header.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/each_header.rb
@@ -19,7 +19,7 @@ describe :net_httpheader_each_header, shared: true do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.send(@method)
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |*key|
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_name.rb b/spec/ruby/library/net-http/httpheader/shared/each_name.rb
index efc6a09dfd..29c9400fef 100644
--- a/spec/ruby/library/net-http/httpheader/shared/each_name.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/each_name.rb
@@ -19,7 +19,7 @@ describe :net_httpheader_each_name, shared: true do
describe "when passed no block" do
it "returns an Enumerator" do
enumerator = @headers.send(@method)
- enumerator.should be_an_instance_of(Enumerator)
+ enumerator.should.instance_of?(Enumerator)
res = []
enumerator.each do |key|
diff --git a/spec/ruby/library/net-http/httpheader/shared/set_range.rb b/spec/ruby/library/net-http/httpheader/shared/set_range.rb
index 87f51d46f3..9ab50a075e 100644
--- a/spec/ruby/library/net-http/httpheader/shared/set_range.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/set_range.rb
@@ -5,13 +5,13 @@ describe :net_httpheader_set_range, shared: true do
describe "when passed nil" do
it "returns nil" do
- @headers.send(@method, nil).should be_nil
+ @headers.send(@method, nil).should == nil
end
it "deletes the 'Range' header entry" do
@headers["Range"] = "bytes 0-499/1234"
@headers.send(@method, nil)
- @headers["Range"].should be_nil
+ @headers["Range"].should == nil
end
end
@@ -50,15 +50,15 @@ describe :net_httpheader_set_range, shared: true do
end
it "raises a Net::HTTPHeaderSyntaxError when the first Range element is negative" do
- -> { @headers.send(@method, -10..5) }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.send(@method, -10..5) }.should.raise(Net::HTTPHeaderSyntaxError)
end
it "raises a Net::HTTPHeaderSyntaxError when the last Range element is negative" do
- -> { @headers.send(@method, 10..-5) }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.send(@method, 10..-5) }.should.raise(Net::HTTPHeaderSyntaxError)
end
it "raises a Net::HTTPHeaderSyntaxError when the last Range element is smaller than the first" do
- -> { @headers.send(@method, 10..5) }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.send(@method, 10..5) }.should.raise(Net::HTTPHeaderSyntaxError)
end
end
@@ -75,15 +75,15 @@ describe :net_httpheader_set_range, shared: true do
end
it "raises a Net::HTTPHeaderSyntaxError when start is negative" do
- -> { @headers.send(@method, -10, 5) }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.send(@method, -10, 5) }.should.raise(Net::HTTPHeaderSyntaxError)
end
it "raises a Net::HTTPHeaderSyntaxError when start + length is negative" do
- -> { @headers.send(@method, 10, -15) }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.send(@method, 10, -15) }.should.raise(Net::HTTPHeaderSyntaxError)
end
it "raises a Net::HTTPHeaderSyntaxError when length is negative" do
- -> { @headers.send(@method, 10, -4) }.should raise_error(Net::HTTPHeaderSyntaxError)
+ -> { @headers.send(@method, 10, -4) }.should.raise(Net::HTTPHeaderSyntaxError)
end
end
end
diff --git a/spec/ruby/library/net-http/httpheader/shared/size.rb b/spec/ruby/library/net-http/httpheader/shared/size.rb
index e2b1e4c22b..b38310a940 100644
--- a/spec/ruby/library/net-http/httpheader/shared/size.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/size.rb
@@ -4,15 +4,15 @@ describe :net_httpheader_size, shared: true do
end
it "returns the number of header entries in self" do
- @headers.send(@method).should eql(0)
+ @headers.send(@method).should.eql?(0)
@headers["a"] = "b"
- @headers.send(@method).should eql(1)
+ @headers.send(@method).should.eql?(1)
@headers["b"] = "b"
- @headers.send(@method).should eql(2)
+ @headers.send(@method).should.eql?(2)
@headers["c"] = "c"
- @headers.send(@method).should eql(3)
+ @headers.send(@method).should.eql?(3)
end
end
diff --git a/spec/ruby/library/net-http/httpheader/sub_type_spec.rb b/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
index b39b57fe8d..9e7d2a5368 100644
--- a/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
@@ -20,13 +20,13 @@ describe "Net::HTTPHeader#sub_type" do
it "returns nil if no 'sub-content-type' is set" do
@headers["Content-Type"] = "text"
- @headers.sub_type.should be_nil
+ @headers.sub_type.should == nil
@headers["Content-Type"] = "text;charset=utf-8"
- @headers.sub_type.should be_nil
+ @headers.sub_type.should == nil
end
it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.sub_type.should be_nil
+ @headers.sub_type.should == nil
end
end
diff --git a/spec/ruby/library/net-http/httpheader/to_hash_spec.rb b/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
index 3cebc519a6..e245c20d4c 100644
--- a/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
+++ b/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
@@ -20,6 +20,6 @@ describe "Net::HTTPHeader#to_hash" do
it "does not allow modifying the headers from the returned hash" do
@headers.to_hash["my-header"] = ["test"]
@headers.to_hash.should == {}
- @headers.key?("my-header").should be_false
+ @headers.key?("my-header").should == false
end
end
diff --git a/spec/ruby/library/net-http/httprequest/initialize_spec.rb b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
index d009a00ed2..1229986bef 100644
--- a/spec/ruby/library/net-http/httprequest/initialize_spec.rb
+++ b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
@@ -21,12 +21,12 @@ describe "Net::HTTPRequest#initialize" do
it "uses the REQUEST_HAS_BODY to set whether the Request has a body or not" do
@req.send(:initialize, "/some/path")
- @req.request_body_permitted?.should be_false
+ @req.request_body_permitted?.should == false
end
it "uses the RESPONSE_HAS_BODY to set whether the Response can have a body or not" do
@req.send(:initialize, "/some/path")
- @req.response_body_permitted?.should be_true
+ @req.response_body_permitted?.should == true
end
describe "when passed path" do
diff --git a/spec/ruby/library/net-http/httpresponse/error_spec.rb b/spec/ruby/library/net-http/httpresponse/error_spec.rb
index 6ced90fa23..e194df95af 100644
--- a/spec/ruby/library/net-http/httpresponse/error_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/error_spec.rb
@@ -4,21 +4,21 @@ require 'net/http'
describe "Net::HTTPResponse#error!" do
it "raises self's class 'EXCEPTION_TYPE' Exception" do
res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
+ -> { res.error! }.should.raise(Net::HTTPError)
res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
+ -> { res.error! }.should.raise(Net::HTTPError)
res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
+ -> { res.error! }.should.raise(Net::HTTPError)
res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPRetriableError)
+ -> { res.error! }.should.raise(Net::HTTPRetriableError)
res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPClientException)
+ -> { res.error! }.should.raise(Net::HTTPClientException)
res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPFatalError)
+ -> { res.error! }.should.raise(Net::HTTPFatalError)
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/header_spec.rb b/spec/ruby/library/net-http/httpresponse/header_spec.rb
index a403dbd2c3..3ddadfb8e4 100644
--- a/spec/ruby/library/net-http/httpresponse/header_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/header_spec.rb
@@ -4,6 +4,6 @@ require 'net/http'
describe "Net::HTTPResponse#header" do
it "returns self" do
res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
+ res.response.should.equal?(res)
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/read_body_spec.rb b/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
index 4530a26bfc..d8b2418624 100644
--- a/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
@@ -17,7 +17,7 @@ describe "Net::HTTPResponse#read_body" do
it "returns the previously read body if called a second time" do
@res.reading_body(@socket, true) do
- @res.read_body.should equal(@res.read_body)
+ @res.read_body.should.equal?(@res.read_body)
end
end
end
@@ -34,14 +34,14 @@ describe "Net::HTTPResponse#read_body" do
it "returns the passed buffer" do
@res.reading_body(@socket, true) do
buffer = +""
- @res.read_body(buffer).should equal(buffer)
+ @res.read_body(buffer).should.equal?(buffer)
end
end
it "raises an IOError if called a second time" do
@res.reading_body(@socket, true) do
@res.read_body(+"")
- -> { @res.read_body(+"") }.should raise_error(IOError)
+ -> { @res.read_body(+"") }.should.raise(IOError)
end
end
end
@@ -57,21 +57,21 @@ describe "Net::HTTPResponse#read_body" do
buffer << body
end
- yielded.should be_true
+ yielded.should == true
buffer.should == "test body"
end
end
it "returns the ReadAdapter" do
@res.reading_body(@socket, true) do
- @res.read_body { nil }.should be_kind_of(Net::ReadAdapter)
+ @res.read_body { nil }.should.is_a?(Net::ReadAdapter)
end
end
it "raises an IOError if called a second time" do
@res.reading_body(@socket, true) do
@res.read_body {}
- -> { @res.read_body {} }.should raise_error(IOError)
+ -> { @res.read_body {} }.should.raise(IOError)
end
end
end
@@ -79,7 +79,7 @@ describe "Net::HTTPResponse#read_body" do
describe "when passed buffer and block" do
it "raises an ArgumentError" do
@res.reading_body(@socket, true) do
- -> { @res.read_body(+"") {} }.should raise_error(ArgumentError)
+ -> { @res.read_body(+"") {} }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/read_header_spec.rb b/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
index 3ea4ee834b..70ce988502 100644
--- a/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
@@ -4,6 +4,6 @@ require 'net/http'
describe "Net::HTTPResponse#read_header" do
it "returns self" do
res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
+ res.response.should.equal?(res)
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/read_new_spec.rb b/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
index 82f7a47ce8..3795e29d83 100644
--- a/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
@@ -12,7 +12,7 @@ test-body
EOS
response = Net::HTTPResponse.read_new(socket)
- response.should be_kind_of(Net::HTTPOK)
+ response.should.is_a?(Net::HTTPOK)
response.code.should == "200"
response["Content-Type"].should == "text/html; charset=utf-8"
diff --git a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
index 637a2806f8..a3671d6eb5 100644
--- a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
@@ -22,7 +22,7 @@ describe "Net::HTTPResponse#reading_body" do
yielded = true
end
- yielded.should be_true
+ yielded.should == true
end
describe "but the response type is not allowed to have a body" do
@@ -31,28 +31,28 @@ describe "Net::HTTPResponse#reading_body" do
end
it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
+ @res.reading_body(@socket, false) {}.should == nil
+ @res.body.should == nil
end
it "yields the passed block" do
yielded = false
@res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
+ yielded.should == true
end
end
end
describe "when body_allowed is false" do
it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
+ @res.reading_body(@socket, false) {}.should == nil
+ @res.body.should == nil
end
it "yields the passed block" do
yielded = false
@res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
+ yielded.should == true
end
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/response_spec.rb b/spec/ruby/library/net-http/httpresponse/response_spec.rb
index caa0ca2d19..440c33c168 100644
--- a/spec/ruby/library/net-http/httpresponse/response_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/response_spec.rb
@@ -4,6 +4,6 @@ require 'net/http'
describe "Net::HTTPResponse#response" do
it "returns self" do
res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
+ res.response.should.equal?(res)
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/shared/body.rb b/spec/ruby/library/net-http/httpresponse/shared/body.rb
index 618e3936fb..368774fb52 100644
--- a/spec/ruby/library/net-http/httpresponse/shared/body.rb
+++ b/spec/ruby/library/net-http/httpresponse/shared/body.rb
@@ -14,7 +14,7 @@ describe :net_httpresponse_body, shared: true do
it "returns the previously read body if called a second time" do
@res.reading_body(@socket, true) do
- @res.send(@method).should equal(@res.send(@method))
+ @res.send(@method).should.equal?(@res.send(@method))
end
end
end
diff --git a/spec/ruby/library/net-http/httpresponse/value_spec.rb b/spec/ruby/library/net-http/httpresponse/value_spec.rb
index 2df8beaa10..e32d37500a 100644
--- a/spec/ruby/library/net-http/httpresponse/value_spec.rb
+++ b/spec/ruby/library/net-http/httpresponse/value_spec.rb
@@ -4,21 +4,21 @@ require 'net/http'
describe "Net::HTTPResponse#value" do
it "raises an HTTP error for non 2xx HTTP Responses" do
res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
+ -> { res.value }.should.raise(Net::HTTPError)
res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
+ -> { res.value }.should.raise(Net::HTTPError)
res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.value }.should_not raise_error(Net::HTTPError)
+ -> { res.value }.should_not.raise(Net::HTTPError)
res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPRetriableError)
+ -> { res.value }.should.raise(Net::HTTPRetriableError)
res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPClientException)
+ -> { res.value }.should.raise(Net::HTTPClientException)
res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPFatalError)
+ -> { res.value }.should.raise(Net::HTTPFatalError)
end
end
diff --git a/spec/ruby/library/objectspace/dump_all_spec.rb b/spec/ruby/library/objectspace/dump_all_spec.rb
index e9b449a905..c92812ebd5 100644
--- a/spec/ruby/library/objectspace/dump_all_spec.rb
+++ b/spec/ruby/library/objectspace/dump_all_spec.rb
@@ -82,7 +82,7 @@ describe "ObjectSpace.dump_all" do
ObjectSpace.dump_all(output: :stdout)
RUBY
- stdout.should include('"value":"abc"')
+ stdout.should.include?('"value":"abc"')
end
it "dumps Ruby heap to provided IO when passed output: IO" do
@@ -107,6 +107,6 @@ describe "ObjectSpace.dump_all" do
end
it "raises ArgumentError when passed not supported :output value" do
- -> { ObjectSpace.dump_all(output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
+ -> { ObjectSpace.dump_all(output: Object.new) }.should.raise(ArgumentError, /wrong output option/)
end
end
diff --git a/spec/ruby/library/objectspace/dump_spec.rb b/spec/ruby/library/objectspace/dump_spec.rb
index e22ee3df1e..4b5e0da198 100644
--- a/spec/ruby/library/objectspace/dump_spec.rb
+++ b/spec/ruby/library/objectspace/dump_spec.rb
@@ -13,23 +13,23 @@ describe "ObjectSpace.dump" do
it "dumps to string when passed output: :string" do
string = ObjectSpace.dump("abc", output: :string)
- string.should be_kind_of(String)
- string.should include('"value":"abc"')
+ string.should.is_a?(String)
+ string.should.include?('"value":"abc"')
end
it "dumps to string when :output not specified" do
string = ObjectSpace.dump("abc")
- string.should be_kind_of(String)
- string.should include('"value":"abc"')
+ string.should.is_a?(String)
+ string.should.include?('"value":"abc"')
end
it "dumps to a temporary file when passed output: :file" do
file = ObjectSpace.dump("abc", output: :file)
- file.should be_kind_of(File)
+ file.should.is_a?(File)
file.rewind
content = file.read
- content.should include('"value":"abc"')
+ content.should.include?('"value":"abc"')
ensure
file.close
File.unlink file.path
@@ -37,10 +37,10 @@ describe "ObjectSpace.dump" do
it "dumps to a temporary file when passed output: :nil" do
file = ObjectSpace.dump("abc", output: nil)
- file.should be_kind_of(File)
+ file.should.is_a?(File)
file.rewind
- file.read.should include('"value":"abc"')
+ file.read.should.include?('"value":"abc"')
ensure
file.close
File.unlink file.path
@@ -48,7 +48,7 @@ describe "ObjectSpace.dump" do
it "dumps to stdout when passed output: :stdout" do
stdout = ruby_exe('ObjectSpace.dump("abc", output: :stdout)', options: "-robjspace").chomp
- stdout.should include('"value":"abc"')
+ stdout.should.include?('"value":"abc"')
end
it "dumps to provided IO when passed output: IO" do
@@ -58,13 +58,13 @@ describe "ObjectSpace.dump" do
result.should.equal? io
io.rewind
- io.read.should include('"value":"abc"')
+ io.read.should.include?('"value":"abc"')
ensure
io.close
rm_r filename
end
it "raises ArgumentError when passed not supported :output value" do
- -> { ObjectSpace.dump("abc", output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
+ -> { ObjectSpace.dump("abc", output: Object.new) }.should.raise(ArgumentError, /wrong output option/)
end
end
diff --git a/spec/ruby/library/objectspace/memsize_of_all_spec.rb b/spec/ruby/library/objectspace/memsize_of_all_spec.rb
index c5a48165ce..9fc6e8be9d 100644
--- a/spec/ruby/library/objectspace/memsize_of_all_spec.rb
+++ b/spec/ruby/library/objectspace/memsize_of_all_spec.rb
@@ -3,12 +3,12 @@ require 'objspace'
describe "ObjectSpace.memsize_of_all" do
it "returns a non-zero Integer for all objects" do
- ObjectSpace.memsize_of_all.should be_kind_of(Integer)
+ ObjectSpace.memsize_of_all.should.is_a?(Integer)
ObjectSpace.memsize_of_all.should > 0
end
it "returns a non-zero Integer for Class" do
- ObjectSpace.memsize_of_all(Class).should be_kind_of(Integer)
+ ObjectSpace.memsize_of_all(Class).should.is_a?(Integer)
ObjectSpace.memsize_of_all(Class).should > 0
end
diff --git a/spec/ruby/library/objectspace/memsize_of_spec.rb b/spec/ruby/library/objectspace/memsize_of_spec.rb
index cbb5a07d54..9c8aea4e84 100644
--- a/spec/ruby/library/objectspace/memsize_of_spec.rb
+++ b/spec/ruby/library/objectspace/memsize_of_spec.rb
@@ -18,7 +18,7 @@ describe "ObjectSpace.memsize_of" do
it "returns a positive Integer for an Object" do
obj = Object.new
- ObjectSpace.memsize_of(obj).should be_kind_of(Integer)
+ ObjectSpace.memsize_of(obj).should.is_a?(Integer)
ObjectSpace.memsize_of(obj).should > 0
end
diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
index dee5961663..4620bdec31 100644
--- a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
+++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
@@ -16,7 +16,7 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "enumerates objects directly reachable from a given object" do
- ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c')
+ ObjectSpace.reachable_objects_from(['a', 'b', 'c']).to_set.should >= Set[Array, 'a', 'b', 'c']
ObjectSpace.reachable_objects_from(Object.new).should == [Object]
end
@@ -24,7 +24,7 @@ describe "ObjectSpace.reachable_objects_from" do
obj = Object.new
ary = [obj]
reachable = ObjectSpace.reachable_objects_from(ary)
- reachable.should include(obj)
+ reachable.should.include?(obj)
end
it "finds an object stored in a copy-on-write Array" do
@@ -33,8 +33,8 @@ describe "ObjectSpace.reachable_objects_from" do
ary = [removed, obj]
ary.shift
reachable = ObjectSpace.reachable_objects_from(ary)
- reachable.should include(obj)
- reachable.should_not include(removed)
+ reachable.should.include?(obj)
+ reachable.should_not.include?(removed)
end
it "finds an object stored in a Queue" do
@@ -44,7 +44,7 @@ describe "ObjectSpace.reachable_objects_from" do
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
- reachable.should include(o)
+ reachable.should.include?(o)
end
it "finds an object stored in a SizedQueue" do
@@ -54,6 +54,6 @@ describe "ObjectSpace.reachable_objects_from" do
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
- reachable.should include(o)
+ reachable.should.include?(o)
end
end
diff --git a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
index 612430e067..0bb6efbfa5 100644
--- a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
+++ b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
@@ -2,6 +2,20 @@ require_relative '../../spec_helper'
require 'objspace'
describe "ObjectSpace.trace_object_allocations" do
+ def has_class_frame?
+ Class.new {
+ attr_reader :c
+
+ def initialize
+ @c = caller_locations.first.label =~ /new/
+ end
+ }.new.c
+ end
+
+ def obj_class_path
+ has_class_frame? ? "Class" : nil
+ end
+
it "runs a block" do
ScratchPad.clear
ObjectSpace.trace_object_allocations do
@@ -13,7 +27,7 @@ describe "ObjectSpace.trace_object_allocations" do
it "records info for allocation_class_path" do
ObjectSpace.trace_object_allocations do
o = Object.new
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
a = [1, 2, 3]
ObjectSpace.allocation_class_path(a).should == nil
end
@@ -31,7 +45,7 @@ describe "ObjectSpace.trace_object_allocations" do
it "records info for allocation_method_id" do
ObjectSpace.trace_object_allocations do
o = Object.new
- ObjectSpace.allocation_method_id(o).should == :new
+ ObjectSpace.allocation_method_id(o).should == (has_class_frame? ? :new : nil)
a = [1, 2, 3]
ObjectSpace.allocation_method_id(a).should == nil
end
@@ -58,9 +72,9 @@ describe "ObjectSpace.trace_object_allocations" do
it "can be cleared using trace_object_allocations_clear" do
ObjectSpace.trace_object_allocations do
o = Object.new
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
ObjectSpace.trace_object_allocations_clear
- ObjectSpace.allocation_class_path(o).should be_nil
+ ObjectSpace.allocation_class_path(o).should == nil
end
end
@@ -69,14 +83,14 @@ describe "ObjectSpace.trace_object_allocations" do
ObjectSpace.trace_object_allocations do
o = Object.new
end
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
end
it "can be used without a block using trace_object_allocations_start and _stop" do
ObjectSpace.trace_object_allocations_start
begin
o = Object.new
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
a = [1, 2, 3]
ObjectSpace.allocation_class_path(a).should == nil
ensure
@@ -91,14 +105,14 @@ describe "ObjectSpace.trace_object_allocations" do
ensure
ObjectSpace.trace_object_allocations_stop
end
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
end
it "can be nested" do
ObjectSpace.trace_object_allocations do
ObjectSpace.trace_object_allocations do
o = Object.new
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
end
end
end
@@ -109,7 +123,7 @@ describe "ObjectSpace.trace_object_allocations" do
ObjectSpace.trace_object_allocations_start
begin
o = Object.new
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
ensure
ObjectSpace.trace_object_allocations_stop
end
@@ -122,7 +136,7 @@ describe "ObjectSpace.trace_object_allocations" do
ObjectSpace.trace_object_allocations_start
begin
o = Object.new
- ObjectSpace.allocation_class_path(o).should == "Class"
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
ObjectSpace.trace_object_allocations_stop
ensure
ObjectSpace.trace_object_allocations_stop
diff --git a/spec/ruby/library/observer/notify_observers_spec.rb b/spec/ruby/library/observer/notify_observers_spec.rb
index 31f82e9266..6f3f984637 100644
--- a/spec/ruby/library/observer/notify_observers_spec.rb
+++ b/spec/ruby/library/observer/notify_observers_spec.rb
@@ -18,7 +18,7 @@ describe "Observer#notify_observers" do
it "verifies observer responds to update" do
-> {
@observable.add_observer(@observable)
- }.should raise_error(NoMethodError)
+ }.should.raise(NoMethodError)
end
it "receives the callback" do
diff --git a/spec/ruby/library/open3/popen3_spec.rb b/spec/ruby/library/open3/popen3_spec.rb
index d3103ad3cb..3651bd516c 100644
--- a/spec/ruby/library/open3/popen3_spec.rb
+++ b/spec/ruby/library/open3/popen3_spec.rb
@@ -5,10 +5,10 @@ describe "Open3.popen3" do
it "returns in, out, err and a thread waiting the process" do
stdin, out, err, waiter = Open3.popen3(ruby_cmd("print :foo"))
begin
- stdin.should be_kind_of IO
- out.should be_kind_of IO
- err.should be_kind_of IO
- waiter.should be_kind_of Thread
+ stdin.should.is_a? IO
+ out.should.is_a? IO
+ err.should.is_a? IO
+ waiter.should.is_a? Thread
out.read.should == "foo"
ensure
diff --git a/spec/ruby/library/openssl/cipher_spec.rb b/spec/ruby/library/openssl/cipher_spec.rb
index f66f25f9c6..91da1c592c 100644
--- a/spec/ruby/library/openssl/cipher_spec.rb
+++ b/spec/ruby/library/openssl/cipher_spec.rb
@@ -4,6 +4,6 @@ require 'openssl'
describe "OpenSSL::Cipher's CipherError" do
it "exists under OpenSSL::Cipher namespace" do
- OpenSSL::Cipher.should have_constant :CipherError
+ OpenSSL::Cipher.should.const_defined?(:CipherError, false)
end
end
diff --git a/spec/ruby/library/openssl/digest/initialize_spec.rb b/spec/ruby/library/openssl/digest/initialize_spec.rb
index 1cd0409c4d..e24ab51d14 100644
--- a/spec/ruby/library/openssl/digest/initialize_spec.rb
+++ b/spec/ruby/library/openssl/digest/initialize_spec.rb
@@ -23,18 +23,14 @@ describe "OpenSSL::Digest#initialize" do
OpenSSL::Digest.new("sha512").name.should == "SHA512"
end
- it "throws an error when called with an unknown digest" do
- -> { OpenSSL::Digest.new("wd40") }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
+ version_is OpenSSL::VERSION, "4.0.0" do
+ it "throws an error when called with an unknown digest" do
+ -> { OpenSSL::Digest.new("wd40") }.should.raise(OpenSSL::Digest::DigestError, /wd40/)
+ end
end
it "cannot be called with a symbol" do
- -> { OpenSSL::Digest.new(:SHA1) }.should raise_error(TypeError, /wrong argument type Symbol/)
- end
-
- it "does not call #to_str on the argument" do
- name = mock("digest name")
- name.should_not_receive(:to_str)
- -> { OpenSSL::Digest.new(name) }.should raise_error(TypeError, /wrong argument type/)
+ -> { OpenSSL::Digest.new(:SHA1) }.should.raise(TypeError)
end
end
@@ -62,7 +58,7 @@ describe "OpenSSL::Digest#initialize" do
end
it "cannot be called with a digest class" do
- -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should raise_error(TypeError, /wrong argument type Class/)
+ -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should.raise(TypeError)
end
context "when called without an initial String argument" do
diff --git a/spec/ruby/library/openssl/digest/shared/update.rb b/spec/ruby/library/openssl/digest/shared/update.rb
index e5ff9dcb16..37277c945d 100644
--- a/spec/ruby/library/openssl/digest/shared/update.rb
+++ b/spec/ruby/library/openssl/digest/shared/update.rb
@@ -96,28 +96,28 @@ describe :openssl_digest_update, shared: true do
digest = OpenSSL::Digest.new('sha1')
-> {
digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
it "raises a TypeError with SHA256" do
digest = OpenSSL::Digest.new('sha256')
-> {
digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
it "raises a TypeError with SHA384" do
digest = OpenSSL::Digest.new('sha384')
-> {
digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
it "raises a TypeError with SHA512" do
digest = OpenSSL::Digest.new('sha512')
-> {
digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
end
end
diff --git a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
index 5a2ca168b5..cc638e1f0d 100644
--- a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
+++ b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
@@ -5,13 +5,13 @@ describe "OpenSSL.fixed_length_secure_compare" do
it "returns true for two strings with the same content" do
input1 = "the quick brown fox jumps over the lazy dog"
input2 = "the quick brown fox jumps over the lazy dog"
- OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
+ OpenSSL.fixed_length_secure_compare(input1, input2).should == true
end
it "returns false for two strings of equal size with different content" do
input1 = "the quick brown fox jumps over the lazy dog"
input2 = "the lazy dog jumps over the quick brown fox"
- OpenSSL.fixed_length_secure_compare(input1, input2).should be_false
+ OpenSSL.fixed_length_secure_compare(input1, input2).should == false
end
it "converts both arguments to strings using #to_str" do
@@ -19,17 +19,17 @@ describe "OpenSSL.fixed_length_secure_compare" do
input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
input2 = mock("input2")
input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
- OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
+ OpenSSL.fixed_length_secure_compare(input1, input2).should == true
end
it "does not accept arguments that are not string and cannot be coerced into strings" do
-> {
OpenSSL.fixed_length_secure_compare("input1", :input2)
- }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
+ }.should.raise(TypeError, 'no implicit conversion of Symbol into String')
-> {
OpenSSL.fixed_length_secure_compare(Object.new, "input2")
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
it "raises an ArgumentError for two strings of different size" do
@@ -37,6 +37,6 @@ describe "OpenSSL.fixed_length_secure_compare" do
input2 = "the quick brown fox"
-> {
OpenSSL.fixed_length_secure_compare(input1, input2)
- }.should raise_error(ArgumentError, 'inputs must be of equal length')
+ }.should.raise(ArgumentError, 'inputs must be of equal length')
end
end
diff --git a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
index 40f8597275..2558dbb9ec 100644
--- a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
+++ b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
@@ -83,86 +83,80 @@ describe "OpenSSL::KDF.pbkdf2_hmac" do
it "raises a TypeError when password is not a String and does not respond to #to_str" do
-> {
OpenSSL::KDF.pbkdf2_hmac(Object.new, **@defaults)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises a TypeError when salt is not a String and does not respond to #to_str" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises a TypeError when iterations is not an Integer and does not respond to #to_int" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: Object.new)
- }.should raise_error(TypeError, "wrong argument type Object (expected OpenSSL/Digest)")
+ }.should.raise(TypeError)
end
- it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest, it does not try to call #to_str" do
- hash = mock("hash")
- hash.should_not_receive(:to_str)
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
- }.should raise_error(TypeError, "wrong argument type MockObject (expected OpenSSL/Digest)")
- end
-
- it "raises a RuntimeError for unknown digest algorithms" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
- }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
+ version_is OpenSSL::VERSION, "4.0.0" do
+ it "raises a OpenSSL::Digest::DigestError for unknown digest algorithms" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
+ }.should.raise(OpenSSL::Digest::DigestError, /wd40/)
+ end
end
it "treats salt as a required keyword" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:salt))
- }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ }.should.raise(ArgumentError, 'missing keyword: :salt')
end
it "treats iterations as a required keyword" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:iterations))
- }.should raise_error(ArgumentError, 'missing keyword: :iterations')
+ }.should.raise(ArgumentError, 'missing keyword: :iterations')
end
it "treats length as a required keyword" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:length))
- }.should raise_error(ArgumentError, 'missing keyword: :length')
+ }.should.raise(ArgumentError, 'missing keyword: :length')
end
it "treats hash as a required keyword" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:hash))
- }.should raise_error(ArgumentError, 'missing keyword: :hash')
+ }.should.raise(ArgumentError, 'missing keyword: :hash')
end
it "treats all keywords as required" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret")
- }.should raise_error(ArgumentError, 'missing keywords: :salt, :iterations, :length, :hash')
+ }.should.raise(ArgumentError, 'missing keywords: :salt, :iterations, :length, :hash')
end
guard -> { OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 } do
it "raises an OpenSSL::KDF::KDFError for 0 or less iterations" do
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, "PKCS5_PBKDF2_HMAC: invalid iteration count")
+ }.should.raise(OpenSSL::KDF::KDFError, "PKCS5_PBKDF2_HMAC: invalid iteration count")
-> {
OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /PKCS5_PBKDF2_HMAC/)
+ }.should.raise(OpenSSL::KDF::KDFError, /PKCS5_PBKDF2_HMAC/)
end
end
end
diff --git a/spec/ruby/library/openssl/kdf/scrypt_spec.rb b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
index 5dc9f2f281..c00f91bb5b 100644
--- a/spec/ruby/library/openssl/kdf/scrypt_spec.rb
+++ b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../../spec_helper'
require 'openssl'
-guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do
+# LibreSSL seems not to support scrypt
+guard -> { OpenSSL::OPENSSL_VERSION.start_with?('OpenSSL') and OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000 } do
describe "OpenSSL::KDF.scrypt" do
before :each do
@defaults = {
@@ -88,79 +89,79 @@ guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do
it "raises a TypeError when password is not a String and does not respond to #to_str" do
-> {
OpenSSL::KDF.scrypt(Object.new, **@defaults)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises a TypeError when salt is not a String and does not respond to #to_str" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, salt: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ }.should.raise(TypeError, "no implicit conversion of Object into String")
end
it "raises a TypeError when N is not an Integer and does not respond to #to_int" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "raises a TypeError when r is not an Integer and does not respond to #to_int" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, r: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "raises a TypeError when p is not an Integer and does not respond to #to_int" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, p: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, length: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Object into Integer")
end
it "treats salt as a required keyword" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults.except(:salt))
- }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ }.should.raise(ArgumentError, 'missing keyword: :salt')
end
it "treats N as a required keyword" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults.except(:N))
- }.should raise_error(ArgumentError, 'missing keyword: :N')
+ }.should.raise(ArgumentError, 'missing keyword: :N')
end
it "treats r as a required keyword" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults.except(:r))
- }.should raise_error(ArgumentError, 'missing keyword: :r')
+ }.should.raise(ArgumentError, 'missing keyword: :r')
end
it "treats p as a required keyword" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults.except(:p))
- }.should raise_error(ArgumentError, 'missing keyword: :p')
+ }.should.raise(ArgumentError, 'missing keyword: :p')
end
it "treats length as a required keyword" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults.except(:length))
- }.should raise_error(ArgumentError, 'missing keyword: :length')
+ }.should.raise(ArgumentError, 'missing keyword: :length')
end
it "treats all keywords as required" do
-> {
OpenSSL::KDF.scrypt("secret")
- }.should raise_error(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length')
+ }.should.raise(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length')
end
it "requires N to be a power of 2" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: 2**14 - 1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
end
it "requires N to be at least 2" do
@@ -169,41 +170,41 @@ guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: 1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, N: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
end
it "requires r to be positive" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, r: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, r: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
end
it "requires p to be positive" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, p: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, p: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ }.should.raise(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
end
it "requires length to be not negative" do
-> {
OpenSSL::KDF.scrypt("secret", **@defaults, length: -1)
- }.should raise_error(ArgumentError, "negative string size (or size too big)")
+ }.should.raise(ArgumentError, "negative string size (or size too big)")
end
end
end
diff --git a/spec/ruby/library/openssl/random/shared/random_bytes.rb b/spec/ruby/library/openssl/random/shared/random_bytes.rb
index f97ccd9974..4d1751e57e 100644
--- a/spec/ruby/library/openssl/random/shared/random_bytes.rb
+++ b/spec/ruby/library/openssl/random/shared/random_bytes.rb
@@ -5,7 +5,7 @@ describe :openssl_random_bytes, shared: true do
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = OpenSSL::Random.send(@method, idx)
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == idx
end
end
@@ -24,6 +24,6 @@ describe :openssl_random_bytes, shared: true do
it "raises ArgumentError on negative arguments" do
-> {
OpenSSL::Random.send(@method, -1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/openssl/secure_compare_spec.rb b/spec/ruby/library/openssl/secure_compare_spec.rb
index cec48e01e7..ce2a4a0d43 100644
--- a/spec/ruby/library/openssl/secure_compare_spec.rb
+++ b/spec/ruby/library/openssl/secure_compare_spec.rb
@@ -5,13 +5,13 @@ describe "OpenSSL.secure_compare" do
it "returns true for two strings with the same content" do
input1 = "the quick brown fox jumps over the lazy dog"
input2 = "the quick brown fox jumps over the lazy dog"
- OpenSSL.secure_compare(input1, input2).should be_true
+ OpenSSL.secure_compare(input1, input2).should == true
end
it "returns false for two strings with different content" do
input1 = "the quick brown fox jumps over the lazy dog"
input2 = "the lazy dog jumps over the quick brown fox"
- OpenSSL.secure_compare(input1, input2).should be_false
+ OpenSSL.secure_compare(input1, input2).should == false
end
it "converts both arguments to strings using #to_str, but adds equality check for the original objects" do
@@ -19,20 +19,20 @@ describe "OpenSSL.secure_compare" do
input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
input2 = mock("input2")
input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
- OpenSSL.secure_compare(input1, input2).should be_false
+ OpenSSL.secure_compare(input1, input2).should == false
input = mock("input")
input.should_receive(:to_str).twice.and_return("the quick brown fox jumps over the lazy dog")
- OpenSSL.secure_compare(input, input).should be_true
+ OpenSSL.secure_compare(input, input).should == true
end
it "does not accept arguments that are not string and cannot be coerced into strings" do
-> {
OpenSSL.secure_compare("input1", :input2)
- }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
+ }.should.raise(TypeError, 'no implicit conversion of Symbol into String')
-> {
OpenSSL.secure_compare(Object.new, "input2")
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ }.should.raise(TypeError, 'no implicit conversion of Object into String')
end
end
diff --git a/spec/ruby/library/openssl/shared/constants.rb b/spec/ruby/library/openssl/shared/constants.rb
index 0bed4156a1..836f75011b 100644
--- a/spec/ruby/library/openssl/shared/constants.rb
+++ b/spec/ruby/library/openssl/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
module HMACConstants
Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
diff --git a/spec/ruby/library/openssl/x509/name/parse_spec.rb b/spec/ruby/library/openssl/x509/name/parse_spec.rb
index 6624161d83..84e3d442f6 100644
--- a/spec/ruby/library/openssl/x509/name/parse_spec.rb
+++ b/spec/ruby/library/openssl/x509/name/parse_spec.rb
@@ -37,12 +37,12 @@ describe "OpenSSL::X509::Name.parse" do
it "raises TypeError if the given string contains no key/value pairs" do
-> do
OpenSSL::X509::Name.parse("hello")
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises OpenSSL::X509::NameError if the given string contains invalid keys" do
-> do
OpenSSL::X509::Name.parse("hello=goodbye")
- end.should raise_error(OpenSSL::X509::NameError)
+ end.should.raise(OpenSSL::X509::NameError)
end
end
diff --git a/spec/ruby/library/openstruct/delete_field_spec.rb b/spec/ruby/library/openstruct/delete_field_spec.rb
index 9ac80196cc..12fed6c90d 100644
--- a/spec/ruby/library/openstruct/delete_field_spec.rb
+++ b/spec/ruby/library/openstruct/delete_field_spec.rb
@@ -8,12 +8,12 @@ describe "OpenStruct#delete_field" do
it "removes the named field from self's method/value table" do
@os.delete_field(:name)
- @os[:name].should be_nil
+ @os[:name].should == nil
end
it "does remove the accessor methods" do
@os.delete_field(:name)
- @os.respond_to?(:name).should be_false
- @os.respond_to?(:name=).should be_false
+ @os.respond_to?(:name).should == false
+ @os.respond_to?(:name=).should == false
end
end
diff --git a/spec/ruby/library/openstruct/equal_value_spec.rb b/spec/ruby/library/openstruct/equal_value_spec.rb
index 103ac13588..c72c09ce14 100644
--- a/spec/ruby/library/openstruct/equal_value_spec.rb
+++ b/spec/ruby/library/openstruct/equal_value_spec.rb
@@ -8,21 +8,21 @@ describe "OpenStruct#==" do
end
it "returns false when the passed argument is no OpenStruct" do
- (@os == Object.new).should be_false
- (@os == "Test").should be_false
- (@os == 10).should be_false
- (@os == :sym).should be_false
+ (@os == Object.new).should == false
+ (@os == "Test").should == false
+ (@os == 10).should == false
+ (@os == :sym).should == false
end
it "returns true when self and other are equal method/value wise" do
- (@os == @os).should be_true
- (@os == OpenStruct.new(name: "John")).should be_true
- (@os == OpenStructSpecs::OpenStructSub.new(name: "John")).should be_true
+ (@os == @os).should == true
+ (@os == OpenStruct.new(name: "John")).should == true
+ (@os == OpenStructSpecs::OpenStructSub.new(name: "John")).should == true
- (@os == OpenStruct.new(name: "Jonny")).should be_false
- (@os == OpenStructSpecs::OpenStructSub.new(name: "Jonny")).should be_false
+ (@os == OpenStruct.new(name: "Jonny")).should == false
+ (@os == OpenStructSpecs::OpenStructSub.new(name: "Jonny")).should == false
- (@os == OpenStruct.new(name: "John", age: 20)).should be_false
- (@os == OpenStructSpecs::OpenStructSub.new(name: "John", age: 20)).should be_false
+ (@os == OpenStruct.new(name: "John", age: 20)).should == false
+ (@os == OpenStructSpecs::OpenStructSub.new(name: "John", age: 20)).should == false
end
end
diff --git a/spec/ruby/library/openstruct/frozen_spec.rb b/spec/ruby/library/openstruct/frozen_spec.rb
index c14a4bac55..c37fd18c8c 100644
--- a/spec/ruby/library/openstruct/frozen_spec.rb
+++ b/spec/ruby/library/openstruct/frozen_spec.rb
@@ -9,25 +9,25 @@ describe "OpenStruct.new when frozen" do
# method_missing case handled in method_missing_spec.rb
#
it "is still readable" do
- @os.age.should eql(70)
- @os.pension.should eql(300)
+ @os.age.should.eql?(70)
+ @os.pension.should.eql?(300)
@os.name.should == "John Smith"
end
it "is not writable" do
- ->{ @os.age = 42 }.should raise_error( RuntimeError )
+ ->{ @os.age = 42 }.should.raise( RuntimeError )
end
it "cannot create new fields" do
- ->{ @os.state = :new }.should raise_error( RuntimeError )
+ ->{ @os.state = :new }.should.raise( RuntimeError )
end
it "creates a frozen clone" do
f = @os.clone
f.frozen?.should == true
f.age.should == 70
- ->{ f.age = 0 }.should raise_error( RuntimeError )
- ->{ f.state = :newer }.should raise_error( RuntimeError )
+ ->{ f.age = 0 }.should.raise( RuntimeError )
+ ->{ f.state = :newer }.should.raise( RuntimeError )
end
it "creates an unfrozen dup" do
diff --git a/spec/ruby/library/openstruct/initialize_spec.rb b/spec/ruby/library/openstruct/initialize_spec.rb
index dee5de48c6..52304cf780 100644
--- a/spec/ruby/library/openstruct/initialize_spec.rb
+++ b/spec/ruby/library/openstruct/initialize_spec.rb
@@ -3,6 +3,6 @@ require 'ostruct'
describe "OpenStruct#initialize" do
it "is private" do
- OpenStruct.should have_private_instance_method(:initialize)
+ OpenStruct.private_instance_methods(false).should.include?(:initialize)
end
end
diff --git a/spec/ruby/library/openstruct/marshal_load_spec.rb b/spec/ruby/library/openstruct/marshal_load_spec.rb
index 342e5e68cd..a8cdda3b43 100644
--- a/spec/ruby/library/openstruct/marshal_load_spec.rb
+++ b/spec/ruby/library/openstruct/marshal_load_spec.rb
@@ -6,7 +6,7 @@ describe "OpenStruct#marshal_load when passed [Hash]" do
os = OpenStruct.new
os.send :marshal_load, age: 20, name: "John"
- os.age.should eql(20)
+ os.age.should.eql?(20)
os.name.should == "John"
end
end
diff --git a/spec/ruby/library/openstruct/method_missing_spec.rb b/spec/ruby/library/openstruct/method_missing_spec.rb
index 89f83d07b3..cf6734d629 100644
--- a/spec/ruby/library/openstruct/method_missing_spec.rb
+++ b/spec/ruby/library/openstruct/method_missing_spec.rb
@@ -7,18 +7,18 @@ describe "OpenStruct#method_missing when called with a method name ending in '='
end
it "raises an ArgumentError when not passed any additional arguments" do
- -> { @os.send(:test=) }.should raise_error(ArgumentError)
+ -> { @os.send(:test=) }.should.raise(ArgumentError)
end
end
describe "OpenStruct#method_missing when passed additional arguments" do
it "raises a NoMethodError when the key does not exist" do
os = OpenStruct.new
- -> { os.test(1, 2, 3) }.should raise_error(NoMethodError)
+ -> { os.test(1, 2, 3) }.should.raise(NoMethodError)
end
it "raises an ArgumentError when the key exists" do
os = OpenStruct.new(test: 20)
- -> { os.test(1, 2, 3) }.should raise_error(ArgumentError)
+ -> { os.test(1, 2, 3) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/openstruct/new_spec.rb b/spec/ruby/library/openstruct/new_spec.rb
index 5d2cacea40..9e53948c82 100644
--- a/spec/ruby/library/openstruct/new_spec.rb
+++ b/spec/ruby/library/openstruct/new_spec.rb
@@ -7,8 +7,8 @@ describe "OpenStruct.new when passed [Hash]" do
end
it "creates an attribute for each key of the passed Hash" do
- @os.age.should eql(70)
- @os.pension.should eql(300)
+ @os.age.should.eql?(70)
+ @os.pension.should.eql?(300)
@os.name.should == "John Smith"
end
end
diff --git a/spec/ruby/library/openstruct/shared/inspect.rb b/spec/ruby/library/openstruct/shared/inspect.rb
index ffcd690e1f..d5fffa0e2e 100644
--- a/spec/ruby/library/openstruct/shared/inspect.rb
+++ b/spec/ruby/library/openstruct/shared/inspect.rb
@@ -4,7 +4,7 @@ describe :ostruct_inspect, shared: true do
os.send(@method).should == "#<OpenStruct name=\"John Smith\">"
os = OpenStruct.new(age: 20, name: "John Smith")
- os.send(@method).should be_kind_of(String)
+ os.send(@method).should.is_a?(String)
end
it "correctly handles self-referential OpenStructs" do
diff --git a/spec/ruby/library/openstruct/to_h_spec.rb b/spec/ruby/library/openstruct/to_h_spec.rb
index 6c272bcc71..7d9c7db5dc 100644
--- a/spec/ruby/library/openstruct/to_h_spec.rb
+++ b/spec/ruby/library/openstruct/to_h_spec.rb
@@ -19,7 +19,7 @@ describe "OpenStruct#to_h" do
end
it "does not return the hash used as initializer" do
- @to_h.should_not equal(@h)
+ @to_h.should_not.equal?(@h)
end
it "returns a Hash that is independent from the struct" do
@@ -36,17 +36,17 @@ describe "OpenStruct#to_h" do
it "raises ArgumentError if block returns longer or shorter array" do
-> do
@os.to_h { |k, v| [k.to_s, v*2, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
-> do
@os.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ end.should.raise(ArgumentError, /element has wrong array length/)
end
it "raises TypeError if block returns something other than Array" do
-> do
@os.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
+ end.should.raise(TypeError, /wrong element type String/)
end
it "coerces returned pair to Array with #to_ary" do
@@ -62,7 +62,7 @@ describe "OpenStruct#to_h" do
-> do
@os.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
+ end.should.raise(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/library/pathname/birthtime_spec.rb b/spec/ruby/library/pathname/birthtime_spec.rb
index 109c112303..387f0aa54d 100644
--- a/spec/ruby/library/pathname/birthtime_spec.rb
+++ b/spec/ruby/library/pathname/birthtime_spec.rb
@@ -4,13 +4,13 @@ require 'pathname'
describe "Pathname#birthtime" do
platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birth time for self" do
- Pathname.new(__FILE__).birthtime.should be_kind_of(Time)
+ Pathname.new(__FILE__).birthtime.should.is_a?(Time)
end
end
platform_is :openbsd do
it "raises an NotImplementedError" do
- -> { Pathname.new(__FILE__).birthtime }.should raise_error(NotImplementedError)
+ -> { Pathname.new(__FILE__).birthtime }.should.raise(NotImplementedError)
end
end
end
diff --git a/spec/ruby/library/pathname/empty_spec.rb b/spec/ruby/library/pathname/empty_spec.rb
index 4deade5b64..9f0305a0f0 100644
--- a/spec/ruby/library/pathname/empty_spec.rb
+++ b/spec/ruby/library/pathname/empty_spec.rb
@@ -15,18 +15,18 @@ describe 'Pathname#empty?' do
end
it 'returns true when file is not empty' do
- Pathname.new(__FILE__).empty?.should be_false
+ Pathname.new(__FILE__).empty?.should == false
end
it 'returns false when the directory is not empty' do
- Pathname.new(__dir__).empty?.should be_false
+ Pathname.new(__dir__).empty?.should == false
end
it 'return true when file is empty' do
- Pathname.new(@file).empty?.should be_true
+ Pathname.new(@file).empty?.should == true
end
it 'returns true when directory is empty' do
- Pathname.new(@dir).empty?.should be_true
+ Pathname.new(@dir).empty?.should == true
end
end
diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb
index de322bab47..e20e6f8f85 100644
--- a/spec/ruby/library/pathname/glob_spec.rb
+++ b/spec/ruby/library/pathname/glob_spec.rb
@@ -41,7 +41,7 @@ describe 'Pathname.glob' do
it "raises an ArgumentError when supplied a keyword argument other than :base" do
-> {
Pathname.glob('*i*.rb', foo: @dir + 'lib')
- }.should raise_error(ArgumentError, /unknown keyword: :?foo/)
+ }.should.raise(ArgumentError, "unknown keyword: :foo")
end
it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do
@@ -81,7 +81,7 @@ describe 'Pathname#glob' do
it 'yields matching file paths to block' do
ary = []
- Pathname.new(@dir).glob('lib/*i*.rb') { |p| ary << p }.should be_nil
+ Pathname.new(@dir).glob('lib/*i*.rb') { |p| ary << p }.should == nil
ary.sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort
end
diff --git a/spec/ruby/library/pathname/inspect_spec.rb b/spec/ruby/library/pathname/inspect_spec.rb
index 304746fbe5..3abba6cbb5 100644
--- a/spec/ruby/library/pathname/inspect_spec.rb
+++ b/spec/ruby/library/pathname/inspect_spec.rb
@@ -4,7 +4,7 @@ require 'pathname'
describe "Pathname#inspect" do
it "returns a consistent String" do
result = Pathname.new('/tmp').inspect
- result.should be_an_instance_of(String)
+ result.should.instance_of?(String)
result.should == "#<Pathname:/tmp>"
end
end
diff --git a/spec/ruby/library/pathname/new_spec.rb b/spec/ruby/library/pathname/new_spec.rb
index 36226ed515..3ef9d9b76d 100644
--- a/spec/ruby/library/pathname/new_spec.rb
+++ b/spec/ruby/library/pathname/new_spec.rb
@@ -3,18 +3,18 @@ require 'pathname'
describe "Pathname.new" do
it "returns a new Pathname Object with 1 argument" do
- Pathname.new('').should be_kind_of(Pathname)
+ Pathname.new('').should.is_a?(Pathname)
end
it "raises an ArgumentError when called with \0" do
- -> { Pathname.new("\0")}.should raise_error(ArgumentError)
+ -> { Pathname.new("\0")}.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { Pathname.new(nil) }.should raise_error(TypeError)
- -> { Pathname.new(0) }.should raise_error(TypeError)
- -> { Pathname.new(true) }.should raise_error(TypeError)
- -> { Pathname.new(false) }.should raise_error(TypeError)
+ -> { Pathname.new(nil) }.should.raise(TypeError)
+ -> { Pathname.new(0) }.should.raise(TypeError)
+ -> { Pathname.new(true) }.should.raise(TypeError)
+ -> { Pathname.new(false) }.should.raise(TypeError)
end
it "initializes with an object with to_path" do
diff --git a/spec/ruby/library/pathname/pathname_spec.rb b/spec/ruby/library/pathname/pathname_spec.rb
index 0fb2881468..6fa6fd2bcb 100644
--- a/spec/ruby/library/pathname/pathname_spec.rb
+++ b/spec/ruby/library/pathname/pathname_spec.rb
@@ -3,11 +3,11 @@ require 'pathname'
describe "Kernel#Pathname" do
it "is a private instance method" do
- Kernel.should have_private_instance_method(:Pathname)
+ Kernel.private_instance_methods(false).should.include?(:Pathname)
end
it "is also a public method" do
- Kernel.should have_method(:Pathname)
+ Kernel.should.respond_to?(:Pathname)
end
it "returns same argument when called with a pathname argument" do
diff --git a/spec/ruby/library/pathname/realdirpath_spec.rb b/spec/ruby/library/pathname/realdirpath_spec.rb
index a9e44e354e..e50741a737 100644
--- a/spec/ruby/library/pathname/realdirpath_spec.rb
+++ b/spec/ruby/library/pathname/realdirpath_spec.rb
@@ -4,7 +4,7 @@ require 'pathname'
describe "Pathname#realdirpath" do
it "returns a Pathname" do
- Pathname.pwd.realdirpath.should be_an_instance_of(Pathname)
+ Pathname.pwd.realdirpath.should.instance_of?(Pathname)
end
end
diff --git a/spec/ruby/library/pathname/realpath_spec.rb b/spec/ruby/library/pathname/realpath_spec.rb
index f2c654308e..d8b87f57d0 100644
--- a/spec/ruby/library/pathname/realpath_spec.rb
+++ b/spec/ruby/library/pathname/realpath_spec.rb
@@ -4,7 +4,7 @@ require 'pathname'
describe "Pathname#realpath" do
it "returns a Pathname" do
- Pathname.pwd.realpath.should be_an_instance_of(Pathname)
+ Pathname.pwd.realpath.should.instance_of?(Pathname)
end
end
diff --git a/spec/ruby/library/pathname/relative_path_from_spec.rb b/spec/ruby/library/pathname/relative_path_from_spec.rb
index 133a149849..7cbd22c3d6 100644
--- a/spec/ruby/library/pathname/relative_path_from_spec.rb
+++ b/spec/ruby/library/pathname/relative_path_from_spec.rb
@@ -7,11 +7,11 @@ describe "Pathname#relative_path_from" do
end
it "raises an error when the two paths do not share a common prefix" do
- -> { relative_path_str('/usr', 'foo') }.should raise_error(ArgumentError)
+ -> { relative_path_str('/usr', 'foo') }.should.raise(ArgumentError)
end
it "raises an error when the base directory has .." do
- -> { relative_path_str('a', '..') }.should raise_error(ArgumentError)
+ -> { relative_path_str('a', '..') }.should.raise(ArgumentError)
end
it "returns a path relative from root" do
diff --git a/spec/ruby/library/prime/each_spec.rb b/spec/ruby/library/prime/each_spec.rb
index b99cf7cf0e..d81e952a88 100644
--- a/spec/ruby/library/prime/each_spec.rb
+++ b/spec/ruby/library/prime/each_spec.rb
@@ -32,11 +32,11 @@ describe :prime_each, shared: true do
all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
end
- all_prime.should be_true
+ all_prime.should == true
end
it "returns the last evaluated expression in the passed block" do
- @object.each { break :value }.should equal(:value)
+ @object.each { break :value }.should.equal?(:value)
end
describe "when not passed a block" do
@@ -45,23 +45,23 @@ describe :prime_each, shared: true do
end
it "returns an object that is Enumerable" do
- @prime_enum.each.should be_kind_of(Enumerable)
+ @prime_enum.each.should.is_a?(Enumerable)
end
it "returns an object that responds to #with_index" do
- @prime_enum.should respond_to(:with_index)
+ @prime_enum.should.respond_to?(:with_index)
end
it "returns an object that responds to #with_object" do
- @prime_enum.should respond_to(:with_object)
+ @prime_enum.should.respond_to?(:with_object)
end
it "returns an object that responds to #next" do
- @prime_enum.should respond_to(:next)
+ @prime_enum.should.respond_to?(:next)
end
it "returns an object that responds to #rewind" do
- @prime_enum.should respond_to(:rewind)
+ @prime_enum.should.respond_to?(:rewind)
end
it "yields primes starting at 2 independent of prior enumerators" do
@@ -106,13 +106,13 @@ describe :prime_each_with_arguments, shared: true do
ScratchPad.recorded.all? do |prime|
(2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
- end.should be_true
+ end.should == true
- ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
+ ScratchPad.recorded.all? { |prime| prime <= bound }.should == true
end
it "returns nil when no prime is generated" do
- @object.each(1) { :value }.should be_nil
+ @object.each(1) { :value }.should == nil
end
it "yields primes starting at 2 independent of prior enumeration" do
@@ -132,7 +132,7 @@ describe :prime_each_with_arguments, shared: true do
describe "when not passed a block" do
it "returns an object that returns primes less than or equal to the bound" do
bound = 100
- @object.each(bound).all? { |prime| prime <= bound }.should be_true
+ @object.each(bound).all? { |prime| prime <= bound }.should == true
end
end
end
diff --git a/spec/ruby/library/prime/instance_spec.rb b/spec/ruby/library/prime/instance_spec.rb
index 5183f36901..680895eb64 100644
--- a/spec/ruby/library/prime/instance_spec.rb
+++ b/spec/ruby/library/prime/instance_spec.rb
@@ -3,12 +3,12 @@ require 'prime'
describe "Prime.instance" do
it "returns a object representing the set of prime numbers" do
- Prime.instance.should be_kind_of(Prime)
+ Prime.instance.should.is_a?(Prime)
end
it "returns a object with no obsolete features" do
- Prime.instance.should_not respond_to(:succ)
- Prime.instance.should_not respond_to(:next)
+ Prime.instance.should_not.respond_to?(:succ)
+ Prime.instance.should_not.respond_to?(:next)
end
it "does not complain anything" do
@@ -16,6 +16,6 @@ describe "Prime.instance" do
end
it "raises a ArgumentError when is called with some arguments" do
- -> { Prime.instance(1) }.should raise_error(ArgumentError)
+ -> { Prime.instance(1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/prime/integer/prime_division_spec.rb b/spec/ruby/library/prime/integer/prime_division_spec.rb
index be03438a6f..5631b22d0a 100644
--- a/spec/ruby/library/prime/integer/prime_division_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_division_spec.rb
@@ -14,6 +14,6 @@ describe "Integer#prime_division" do
-1.prime_division.should == [[-1, 1]]
end
it "raises ZeroDivisionError for 0" do
- -> { 0.prime_division }.should raise_error(ZeroDivisionError)
+ -> { 0.prime_division }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/prime/integer/prime_spec.rb b/spec/ruby/library/prime/integer/prime_spec.rb
index 53de76d5ab..d24f883b19 100644
--- a/spec/ruby/library/prime/integer/prime_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_spec.rb
@@ -3,15 +3,15 @@ require 'prime'
describe "Integer#prime?" do
it "returns a true value for prime numbers" do
- 2.prime?.should be_true
- 3.prime?.should be_true
- (2**31-1).prime?.should be_true # 8th Mersenne prime (M8)
+ 2.prime?.should == true
+ 3.prime?.should == true
+ (2**31-1).prime?.should == true # 8th Mersenne prime (M8)
end
it "returns a false value for composite numbers" do
- 4.prime?.should be_false
- 15.prime?.should be_false
- (2**32-1).prime?.should be_false
- ( (2**17-1)*(2**19-1) ).prime?.should be_false # M6*M7
+ 4.prime?.should == false
+ 15.prime?.should == false
+ (2**32-1).prime?.should == false
+ ( (2**17-1)*(2**19-1) ).prime?.should == false # M6*M7
end
end
diff --git a/spec/ruby/library/prime/prime_division_spec.rb b/spec/ruby/library/prime/prime_division_spec.rb
index 6293478f59..cc39969a56 100644
--- a/spec/ruby/library/prime/prime_division_spec.rb
+++ b/spec/ruby/library/prime/prime_division_spec.rb
@@ -16,10 +16,10 @@ describe "Prime.prime_division" do
end
it "includes [[-1, 1]] in the divisors of a negative number" do
- Prime.prime_division(-10).should include([-1, 1])
+ Prime.prime_division(-10).should.include?([-1, 1])
end
it "raises ZeroDivisionError for 0" do
- -> { Prime.prime_division(0) }.should raise_error(ZeroDivisionError)
+ -> { Prime.prime_division(0) }.should.raise(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/prime/prime_spec.rb b/spec/ruby/library/prime/prime_spec.rb
index 0896c7f0f3..207c763aed 100644
--- a/spec/ruby/library/prime/prime_spec.rb
+++ b/spec/ruby/library/prime/prime_spec.rb
@@ -3,15 +3,15 @@ require 'prime'
describe "Prime#prime?" do
it "returns a true value for prime numbers" do
- Prime.prime?(2).should be_true
- Prime.prime?(3).should be_true
- Prime.prime?(2**31-1).should be_true # 8th Mersenne prime (M8)
+ Prime.prime?(2).should == true
+ Prime.prime?(3).should == true
+ Prime.prime?(2**31-1).should == true # 8th Mersenne prime (M8)
end
it "returns a false value for composite numbers" do
- Prime.prime?(4).should be_false
- Prime.prime?(15).should be_false
- Prime.prime?(2**32-1).should be_false
- Prime.prime?( (2**17-1)*(2**19-1) ).should be_false # M6*M7
+ Prime.prime?(4).should == false
+ Prime.prime?(15).should == false
+ Prime.prime?(2**32-1).should == false
+ Prime.prime?( (2**17-1)*(2**19-1) ).should == false # M6*M7
end
end
diff --git a/spec/ruby/library/random/formatter/alphanumeric_spec.rb b/spec/ruby/library/random/formatter/alphanumeric_spec.rb
index 9bd325e1d0..62a4698d0d 100644
--- a/spec/ruby/library/random/formatter/alphanumeric_spec.rb
+++ b/spec/ruby/library/random/formatter/alphanumeric_spec.rb
@@ -30,7 +30,7 @@ describe "Random::Formatter#alphanumeric" do
it "raises an ArgumentError if the size is not numeric" do
-> {
@object.alphanumeric("10")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "does not coerce the size argument with #to_int" do
@@ -38,19 +38,17 @@ describe "Random::Formatter#alphanumeric" do
size.should_not_receive(:to_int)
-> {
@object.alphanumeric(size)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
- ruby_version_is "3.3" do
- it "accepts a 'chars' argument with the output alphabet" do
- @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/
- end
+ it "accepts a 'chars' argument with the output alphabet" do
+ @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/
+ end
- it "converts the elements of chars using #to_s" do
- to_s = mock("to_s")
- to_s.should_receive(:to_s).and_return("[mock to_s]")
- # Using 1 value in chars results in an infinite loop
- @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]"
- end
+ it "converts the elements of chars using #to_s" do
+ to_s = mock("to_s")
+ to_s.should_receive(:to_s).and_return("[mock to_s]")
+ # Using 1 value in chars results in an infinite loop
+ @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]"
end
end
diff --git a/spec/ruby/library/rbconfig/rbconfig_spec.rb b/spec/ruby/library/rbconfig/rbconfig_spec.rb
index b9a4588bf0..4195128a05 100644
--- a/spec/ruby/library/rbconfig/rbconfig_spec.rb
+++ b/spec/ruby/library/rbconfig/rbconfig_spec.rb
@@ -4,8 +4,8 @@ require 'rbconfig'
describe 'RbConfig::CONFIG' do
it 'values are all strings' do
RbConfig::CONFIG.each do |k, v|
- k.should be_kind_of String
- v.should be_kind_of String
+ k.should.is_a? String
+ v.should.is_a? String
end
end
@@ -32,7 +32,7 @@ describe 'RbConfig::CONFIG' do
it "['sitelibdir'] is set and is part of $LOAD_PATH" do
sitelibdir = RbConfig::CONFIG['sitelibdir']
- sitelibdir.should be_kind_of String
+ sitelibdir.should.is_a? String
$LOAD_PATH.map{|path| File.realpath(path) rescue path }.should.include? sitelibdir
end
end
@@ -80,7 +80,7 @@ describe 'RbConfig::CONFIG' do
ar = RbConfig::CONFIG.fetch('AR')
out = `#{ar} --version`
$?.should.success?
- out.should_not be_empty
+ out.should_not.empty?
end
it "['STRIP'] exists and can be executed" do
diff --git a/spec/ruby/library/rbconfig/sizeof/limits_spec.rb b/spec/ruby/library/rbconfig/sizeof/limits_spec.rb
index 776099da27..08b1185965 100644
--- a/spec/ruby/library/rbconfig/sizeof/limits_spec.rb
+++ b/spec/ruby/library/rbconfig/sizeof/limits_spec.rb
@@ -3,13 +3,13 @@ require 'rbconfig/sizeof'
describe "RbConfig::LIMITS" do
it "is a Hash" do
- RbConfig::LIMITS.should be_kind_of(Hash)
+ RbConfig::LIMITS.should.is_a?(Hash)
end
it "has string keys and numeric values" do
RbConfig::LIMITS.each do |key, value|
- key.should be_kind_of String
- value.should be_kind_of Numeric
+ key.should.is_a? String
+ value.should.is_a? Numeric
end
end
diff --git a/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb b/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb
index f2582dc4fd..b74dae5166 100644
--- a/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb
+++ b/spec/ruby/library/rbconfig/sizeof/sizeof_spec.rb
@@ -3,13 +3,13 @@ require 'rbconfig/sizeof'
describe "RbConfig::SIZEOF" do
it "is a Hash" do
- RbConfig::SIZEOF.should be_kind_of(Hash)
+ RbConfig::SIZEOF.should.is_a?(Hash)
end
it "has string keys and integer values" do
RbConfig::SIZEOF.each do |key, value|
- key.should be_kind_of String
- value.should be_kind_of Integer
+ key.should.is_a? String
+ value.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
index 27220f4983..521a750bf7 100644
--- a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
+++ b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
@@ -2,22 +2,16 @@ require_relative '../../spec_helper'
require 'rbconfig'
describe "RbConfig::CONFIG['UNICODE_EMOJI_VERSION']" do
- ruby_version_is ""..."3.2" do
- it "is 13.1" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "13.1"
- end
- end
-
- ruby_version_is "3.2"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "is 15.0" do
RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "15.0"
end
end
# Caution: ruby_version_is means is_or_later
- ruby_version_is "3.5" do
- it "is 15.1" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "15.1"
+ ruby_version_is "4.0" do
+ it "is 17.0" do
+ RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "17.0"
end
end
end
diff --git a/spec/ruby/library/rbconfig/unicode_version_spec.rb b/spec/ruby/library/rbconfig/unicode_version_spec.rb
index bcb67a5076..5cdde74f79 100644
--- a/spec/ruby/library/rbconfig/unicode_version_spec.rb
+++ b/spec/ruby/library/rbconfig/unicode_version_spec.rb
@@ -2,22 +2,16 @@ require_relative '../../spec_helper'
require 'rbconfig'
describe "RbConfig::CONFIG['UNICODE_VERSION']" do
- ruby_version_is ""..."3.2" do
- it "is 13.0.0" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "13.0.0"
- end
- end
-
- ruby_version_is "3.2"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "is 15.0.0" do
RbConfig::CONFIG['UNICODE_VERSION'].should == "15.0.0"
end
end
# Caution: ruby_version_is means is_or_later
- ruby_version_is "3.5" do
- it "is 15.1.0" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "15.1.0"
+ ruby_version_is "4.0" do
+ it "is 17.0.0" do
+ RbConfig::CONFIG['UNICODE_VERSION'].should == "17.0.0"
end
end
end
diff --git a/spec/ruby/library/readline/basic_quote_characters_spec.rb b/spec/ruby/library/readline/basic_quote_characters_spec.rb
index 216899d875..f6467c8be4 100644
--- a/spec/ruby/library/readline/basic_quote_characters_spec.rb
+++ b/spec/ruby/library/readline/basic_quote_characters_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.basic_quote_characters" do
it "returns not nil" do
- Readline.basic_quote_characters.should_not be_nil
+ Readline.basic_quote_characters.should_not == nil
end
end
diff --git a/spec/ruby/library/readline/basic_word_break_characters_spec.rb b/spec/ruby/library/readline/basic_word_break_characters_spec.rb
index daa0e1cb76..ef05d6560b 100644
--- a/spec/ruby/library/readline/basic_word_break_characters_spec.rb
+++ b/spec/ruby/library/readline/basic_word_break_characters_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.basic_word_break_characters" do
it "returns not nil" do
- Readline.basic_word_break_characters.should_not be_nil
+ Readline.basic_word_break_characters.should_not == nil
end
end
diff --git a/spec/ruby/library/readline/completer_quote_characters_spec.rb b/spec/ruby/library/readline/completer_quote_characters_spec.rb
index 86c58f3cf6..1109ea1f03 100644
--- a/spec/ruby/library/readline/completer_quote_characters_spec.rb
+++ b/spec/ruby/library/readline/completer_quote_characters_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completer_quote_characters" do
it "returns nil" do
- Readline.completer_quote_characters.should be_nil
+ Readline.completer_quote_characters.should == nil
end
end
diff --git a/spec/ruby/library/readline/completer_word_break_characters_spec.rb b/spec/ruby/library/readline/completer_word_break_characters_spec.rb
index c72f1135c4..91a002b9de 100644
--- a/spec/ruby/library/readline/completer_word_break_characters_spec.rb
+++ b/spec/ruby/library/readline/completer_word_break_characters_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completer_word_break_characters" do
it "returns nil" do
- Readline.completer_word_break_characters.should be_nil
+ Readline.completer_word_break_characters.should == nil
end
end
diff --git a/spec/ruby/library/readline/completion_append_character_spec.rb b/spec/ruby/library/readline/completion_append_character_spec.rb
index 615b523f4e..2a14d5d30e 100644
--- a/spec/ruby/library/readline/completion_append_character_spec.rb
+++ b/spec/ruby/library/readline/completion_append_character_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completion_append_character" do
it "returns not nil" do
- Readline.completion_append_character.should_not be_nil
+ Readline.completion_append_character.should_not == nil
end
end
diff --git a/spec/ruby/library/readline/completion_case_fold_spec.rb b/spec/ruby/library/readline/completion_case_fold_spec.rb
index 966f5d6c79..b6a4aab101 100644
--- a/spec/ruby/library/readline/completion_case_fold_spec.rb
+++ b/spec/ruby/library/readline/completion_case_fold_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completion_case_fold" do
it "returns nil" do
- Readline.completion_case_fold.should be_nil
+ Readline.completion_case_fold.should == nil
end
end
diff --git a/spec/ruby/library/readline/completion_proc_spec.rb b/spec/ruby/library/readline/completion_proc_spec.rb
index 2d7a353ec5..037fc6de21 100644
--- a/spec/ruby/library/readline/completion_proc_spec.rb
+++ b/spec/ruby/library/readline/completion_proc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
with_feature :readline do
describe "Readline.completion_proc" do
it "returns nil" do
- Readline.completion_proc.should be_nil
+ Readline.completion_proc.should == nil
end
end
@@ -16,7 +16,7 @@ with_feature :readline do
end
it "returns an ArgumentError if not given an Proc or #call" do
- -> { Readline.completion_proc = "test" }.should raise_error(ArgumentError)
+ -> { Readline.completion_proc = "test" }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/readline/constants_spec.rb b/spec/ruby/library/readline/constants_spec.rb
index 8fee274866..91536ce1cc 100644
--- a/spec/ruby/library/readline/constants_spec.rb
+++ b/spec/ruby/library/readline/constants_spec.rb
@@ -11,8 +11,8 @@ with_feature :readline do
describe "Readline::VERSION" do
it "is defined and is a non-empty String" do
Readline.const_defined?(:VERSION).should == true
- Readline::VERSION.should be_kind_of(String)
- Readline::VERSION.should_not be_empty
+ Readline::VERSION.should.is_a?(String)
+ Readline::VERSION.should_not.empty?
end
end
end
diff --git a/spec/ruby/library/readline/emacs_editing_mode_spec.rb b/spec/ruby/library/readline/emacs_editing_mode_spec.rb
index f7e8eda982..93ded3d023 100644
--- a/spec/ruby/library/readline/emacs_editing_mode_spec.rb
+++ b/spec/ruby/library/readline/emacs_editing_mode_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.emacs_editing_mode" do
it "returns nil" do
- Readline.emacs_editing_mode.should be_nil
+ Readline.emacs_editing_mode.should == nil
end
end
end
diff --git a/spec/ruby/library/readline/filename_quote_characters_spec.rb b/spec/ruby/library/readline/filename_quote_characters_spec.rb
index de8ce700a8..6bcb04fc79 100644
--- a/spec/ruby/library/readline/filename_quote_characters_spec.rb
+++ b/spec/ruby/library/readline/filename_quote_characters_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.filename_quote_characters" do
it "returns nil" do
- Readline.filename_quote_characters.should be_nil
+ Readline.filename_quote_characters.should == nil
end
end
diff --git a/spec/ruby/library/readline/history/append_spec.rb b/spec/ruby/library/readline/history/append_spec.rb
index 5383271374..be0e515b84 100644
--- a/spec/ruby/library/readline/history/append_spec.rb
+++ b/spec/ruby/library/readline/history/append_spec.rb
@@ -22,7 +22,7 @@ with_feature :readline do
end
it "raises a TypeError when the passed Object can't be converted to a String" do
- -> { Readline::HISTORY << mock("Object") }.should raise_error(TypeError)
+ -> { Readline::HISTORY << mock("Object") }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/readline/history/delete_at_spec.rb b/spec/ruby/library/readline/history/delete_at_spec.rb
index 3bd577e75c..4383ff7e83 100644
--- a/spec/ruby/library/readline/history/delete_at_spec.rb
+++ b/spec/ruby/library/readline/history/delete_at_spec.rb
@@ -31,8 +31,8 @@ with_feature :readline do
end
it "raises an IndexError when the given index is greater than the history size" do
- -> { Readline::HISTORY.delete_at(10) }.should raise_error(IndexError)
- -> { Readline::HISTORY.delete_at(-10) }.should raise_error(IndexError)
+ -> { Readline::HISTORY.delete_at(10) }.should.raise(IndexError)
+ -> { Readline::HISTORY.delete_at(-10) }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/readline/history/element_reference_spec.rb b/spec/ruby/library/readline/history/element_reference_spec.rb
index 0a74f3d62d..1f1642626f 100644
--- a/spec/ruby/library/readline/history/element_reference_spec.rb
+++ b/spec/ruby/library/readline/history/element_reference_spec.rb
@@ -23,13 +23,13 @@ with_feature :readline do
end
it "raises an IndexError when there is no item at the passed index" do
- -> { Readline::HISTORY[-10] }.should raise_error(IndexError)
- -> { Readline::HISTORY[-9] }.should raise_error(IndexError)
- -> { Readline::HISTORY[-8] }.should raise_error(IndexError)
+ -> { Readline::HISTORY[-10] }.should.raise(IndexError)
+ -> { Readline::HISTORY[-9] }.should.raise(IndexError)
+ -> { Readline::HISTORY[-8] }.should.raise(IndexError)
- -> { Readline::HISTORY[8] }.should raise_error(IndexError)
- -> { Readline::HISTORY[9] }.should raise_error(IndexError)
- -> { Readline::HISTORY[10] }.should raise_error(IndexError)
+ -> { Readline::HISTORY[8] }.should.raise(IndexError)
+ -> { Readline::HISTORY[9] }.should.raise(IndexError)
+ -> { Readline::HISTORY[10] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/readline/history/element_set_spec.rb b/spec/ruby/library/readline/history/element_set_spec.rb
index 776adaacd1..0787b6343d 100644
--- a/spec/ruby/library/readline/history/element_set_spec.rb
+++ b/spec/ruby/library/readline/history/element_set_spec.rb
@@ -17,7 +17,7 @@ with_feature :readline do
end
it "raises an IndexError when there is no item at the passed positive index" do
- -> { Readline::HISTORY[10] = "test" }.should raise_error(IndexError)
+ -> { Readline::HISTORY[10] = "test" }.should.raise(IndexError)
end
it "sets the item at the given index" do
@@ -29,7 +29,7 @@ with_feature :readline do
end
it "raises an IndexError when there is no item at the passed negative index" do
- -> { Readline::HISTORY[10] = "test" }.should raise_error(IndexError)
+ -> { Readline::HISTORY[10] = "test" }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/readline/history/empty_spec.rb b/spec/ruby/library/readline/history/empty_spec.rb
index 31d01d9601..5b722dccd3 100644
--- a/spec/ruby/library/readline/history/empty_spec.rb
+++ b/spec/ruby/library/readline/history/empty_spec.rb
@@ -3,11 +3,11 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY.empty?" do
it "returns true when the history is empty" do
- Readline::HISTORY.should be_empty
+ Readline::HISTORY.should.empty?
Readline::HISTORY.push("test")
- Readline::HISTORY.should_not be_empty
+ Readline::HISTORY.should_not.empty?
Readline::HISTORY.pop
- Readline::HISTORY.should be_empty
+ Readline::HISTORY.should.empty?
end
end
end
diff --git a/spec/ruby/library/readline/history/history_spec.rb b/spec/ruby/library/readline/history/history_spec.rb
index 927dd52ebf..3233071033 100644
--- a/spec/ruby/library/readline/history/history_spec.rb
+++ b/spec/ruby/library/readline/history/history_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY" do
it "is extended with the Enumerable module" do
- Readline::HISTORY.should be_kind_of(Enumerable)
+ Readline::HISTORY.should.is_a?(Enumerable)
end
end
end
diff --git a/spec/ruby/library/readline/history/pop_spec.rb b/spec/ruby/library/readline/history/pop_spec.rb
index 156a8a06f8..0b780a38cc 100644
--- a/spec/ruby/library/readline/history/pop_spec.rb
+++ b/spec/ruby/library/readline/history/pop_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY.pop" do
it "returns nil when the history is empty" do
- Readline::HISTORY.pop.should be_nil
+ Readline::HISTORY.pop.should == nil
end
it "returns and removes the last item from the history" do
diff --git a/spec/ruby/library/readline/history/push_spec.rb b/spec/ruby/library/readline/history/push_spec.rb
index 53505ccba6..4bbf1763a1 100644
--- a/spec/ruby/library/readline/history/push_spec.rb
+++ b/spec/ruby/library/readline/history/push_spec.rb
@@ -20,7 +20,7 @@ with_feature :readline do
end
it "raises a TypeError when the passed Object can't be converted to a String" do
- -> { Readline::HISTORY.push(mock("Object")) }.should raise_error(TypeError)
+ -> { Readline::HISTORY.push(mock("Object")) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/readline/history/shift_spec.rb b/spec/ruby/library/readline/history/shift_spec.rb
index 9aad7d5399..d852480a2a 100644
--- a/spec/ruby/library/readline/history/shift_spec.rb
+++ b/spec/ruby/library/readline/history/shift_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
with_feature :readline do
describe "Readline::HISTORY.shift" do
it "returns nil when the history is empty" do
- Readline::HISTORY.shift.should be_nil
+ Readline::HISTORY.shift.should == nil
end
it "returns and removes the first item from the history" do
diff --git a/spec/ruby/library/readline/vi_editing_mode_spec.rb b/spec/ruby/library/readline/vi_editing_mode_spec.rb
index 6622962ceb..3ce4f5a7e6 100644
--- a/spec/ruby/library/readline/vi_editing_mode_spec.rb
+++ b/spec/ruby/library/readline/vi_editing_mode_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :darwin do
with_feature :readline do
describe "Readline.vi_editing_mode" do
it "returns nil" do
- Readline.vi_editing_mode.should be_nil
+ Readline.vi_editing_mode.should == nil
end
end
end
diff --git a/spec/ruby/library/resolv/get_address_spec.rb b/spec/ruby/library/resolv/get_address_spec.rb
index ecc2cdf7de..9caa94643a 100644
--- a/spec/ruby/library/resolv/get_address_spec.rb
+++ b/spec/ruby/library/resolv/get_address_spec.rb
@@ -14,6 +14,6 @@ describe "Resolv#getaddress" do
res = Resolv.new([])
-> {
res.getaddress("should.raise.error.")
- }.should raise_error(Resolv::ResolvError)
+ }.should.raise(Resolv::ResolvError)
end
end
diff --git a/spec/ruby/library/resolv/get_name_spec.rb b/spec/ruby/library/resolv/get_name_spec.rb
index 3ef97a2cea..81e0cda28d 100644
--- a/spec/ruby/library/resolv/get_name_spec.rb
+++ b/spec/ruby/library/resolv/get_name_spec.rb
@@ -13,6 +13,6 @@ describe "Resolv#getname" do
res = Resolv.new([])
-> {
res.getname("should.raise.error")
- }.should raise_error(Resolv::ResolvError)
+ }.should.raise(Resolv::ResolvError)
end
end
diff --git a/spec/ruby/library/ripper/lex_spec.rb b/spec/ruby/library/ripper/lex_spec.rb
index 97cfb06904..0255480579 100644
--- a/spec/ruby/library/ripper/lex_spec.rb
+++ b/spec/ruby/library/ripper/lex_spec.rb
@@ -10,14 +10,14 @@ describe "Ripper.lex" do
[[1, 5], :on_lparen, "(", 'BEG|LABEL'],
[[1, 6], :on_ident, "a", 'ARG'],
[[1, 7], :on_rparen, ")", 'ENDFN'],
- [[1, 8], :on_sp, " ", 'BEG'],
+ [[1, 8], :on_semicolon, ";", 'BEG'],
[[1, 9], :on_kw, "nil", 'END'],
[[1, 12], :on_sp, " ", 'END'],
[[1, 13], :on_kw, "end", 'END']
]
- lexed = Ripper.lex("def m(a) nil end")
+ lexed = Ripper.lex("def m(a);nil end")
lexed.map { |e|
- e[0...-1] + [e[-1].to_s.split('|').map { |s| s.sub(/^EXPR_/, '') }.join('|')]
+ e[0...-1] + [e[-1].to_s]
}.should == expected
end
end
diff --git a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
index 9b37eaa43c..693c72a29e 100644
--- a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
+++ b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
@@ -4,7 +4,7 @@ require 'rubygems'
describe "Gem.load_path_insert_index" do
guard -> { RbConfig::TOPDIR } do
it "is set for an installed Ruby" do
- Gem.load_path_insert_index.should be_kind_of Integer
+ Gem.load_path_insert_index.should.is_a? Integer
end
end
end
diff --git a/spec/ruby/library/securerandom/base64_spec.rb b/spec/ruby/library/securerandom/base64_spec.rb
index 34cd419ce2..49d4b8a029 100644
--- a/spec/ruby/library/securerandom/base64_spec.rb
+++ b/spec/ruby/library/securerandom/base64_spec.rb
@@ -6,13 +6,13 @@ describe "SecureRandom.base64" do
it "generates a random base64 string out of specified number of random bytes" do
(16..128).each do |idx|
base64 = SecureRandom.base64(idx)
- base64.should be_kind_of(String)
+ base64.should.is_a?(String)
base64.length.should < 2 * idx
base64.should =~ /^[A-Za-z0-9\+\/]+={0,2}$/
end
base64 = SecureRandom.base64(16.5)
- base64.should be_kind_of(String)
+ base64.should.is_a?(String)
base64.length.should < 2 * 16
end
@@ -32,19 +32,19 @@ describe "SecureRandom.base64" do
end
it "generates a random base64 string out of 32 random bytes" do
- SecureRandom.base64.should be_kind_of(String)
+ SecureRandom.base64.should.is_a?(String)
SecureRandom.base64.length.should < 32 * 2
end
it "treats nil argument as default one and generates a random base64 string" do
- SecureRandom.base64(nil).should be_kind_of(String)
+ SecureRandom.base64(nil).should.is_a?(String)
SecureRandom.base64(nil).length.should < 32 * 2
end
it "raises ArgumentError on negative arguments" do
-> {
SecureRandom.base64(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "tries to convert the passed argument to an Integer using #to_int" do
diff --git a/spec/ruby/library/securerandom/hex_spec.rb b/spec/ruby/library/securerandom/hex_spec.rb
index bdb920b217..ec33aca1ee 100644
--- a/spec/ruby/library/securerandom/hex_spec.rb
+++ b/spec/ruby/library/securerandom/hex_spec.rb
@@ -6,13 +6,13 @@ describe "SecureRandom.hex" do
it "generates a random hex string of length twice the specified argument" do
(1..64).each do |idx|
hex = SecureRandom.hex(idx)
- hex.should be_kind_of(String)
+ hex.should.is_a?(String)
hex.length.should == 2 * idx
end
base64 = SecureRandom.hex(5.5)
- base64.should be_kind_of(String)
- base64.length.should eql(10)
+ base64.should.is_a?(String)
+ base64.length.should.eql?(10)
end
it "returns an empty string when argument is 0" do
@@ -31,24 +31,24 @@ describe "SecureRandom.hex" do
end
it "generates a random hex string of length 32 if no argument is provided" do
- SecureRandom.hex.should be_kind_of(String)
+ SecureRandom.hex.should.is_a?(String)
SecureRandom.hex.length.should == 32
end
it "treats nil argument as default one and generates a random hex string of length 32" do
- SecureRandom.hex(nil).should be_kind_of(String)
+ SecureRandom.hex(nil).should.is_a?(String)
SecureRandom.hex(nil).length.should == 32
end
it "raises ArgumentError on negative arguments" do
-> {
SecureRandom.hex(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "tries to convert the passed argument to an Integer using #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(5)
- SecureRandom.hex(obj).size.should eql(10)
+ SecureRandom.hex(obj).size.should.eql?(10)
end
end
diff --git a/spec/ruby/library/securerandom/random_bytes_spec.rb b/spec/ruby/library/securerandom/random_bytes_spec.rb
index ed3a02255c..4e30a53163 100644
--- a/spec/ruby/library/securerandom/random_bytes_spec.rb
+++ b/spec/ruby/library/securerandom/random_bytes_spec.rb
@@ -8,24 +8,24 @@ describe "SecureRandom.random_bytes" do
it "generates a random binary string of length 16 if no argument is provided" do
bytes = SecureRandom.random_bytes
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == 16
end
it "generates a random binary string of length 16 if argument is nil" do
bytes = SecureRandom.random_bytes(nil)
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == 16
end
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = SecureRandom.random_bytes(idx)
- bytes.should be_kind_of(String)
+ bytes.should.is_a?(String)
bytes.length.should == idx
end
- SecureRandom.random_bytes(2.2).length.should eql(2)
+ SecureRandom.random_bytes(2.2).length.should.eql?(2)
end
it "generates different binary strings with subsequent invocations" do
@@ -42,12 +42,12 @@ describe "SecureRandom.random_bytes" do
it "raises ArgumentError on negative arguments" do
-> {
SecureRandom.random_bytes(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "tries to convert the passed argument to an Integer using #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(5)
- SecureRandom.random_bytes(obj).size.should eql(5)
+ SecureRandom.random_bytes(obj).size.should.eql?(5)
end
end
diff --git a/spec/ruby/library/securerandom/random_number_spec.rb b/spec/ruby/library/securerandom/random_number_spec.rb
index bb25bc496e..97cd66f7bc 100644
--- a/spec/ruby/library/securerandom/random_number_spec.rb
+++ b/spec/ruby/library/securerandom/random_number_spec.rb
@@ -10,7 +10,7 @@ describe "SecureRandom.random_number" do
it "generates a random positive number smaller then the positive integer argument" do
(1..64).each do |idx|
num = SecureRandom.random_number(idx)
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
0.should <= num
num.should < idx
end
@@ -20,7 +20,7 @@ describe "SecureRandom.random_number" do
max = 12345678901234567890
11.times do
num = SecureRandom.random_number max
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
0.should <= num
num.should < max
end
@@ -29,7 +29,7 @@ describe "SecureRandom.random_number" do
it "generates a random float number between 0.0 and 1.0 if no argument provided" do
64.times do
num = SecureRandom.random_number
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.0.should <= num
num.should < 1.0
end
@@ -38,7 +38,7 @@ describe "SecureRandom.random_number" do
it "generates a random value in given (integer) range limits" do
64.times do
num = SecureRandom.random_number 11...13
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
11.should <= num
num.should < 13
end
@@ -49,7 +49,7 @@ describe "SecureRandom.random_number" do
upper = 12345678901234567890 + 5
32.times do
num = SecureRandom.random_number lower..upper
- num.should be_kind_of(Integer)
+ num.should.is_a?(Integer)
lower.should <= num
num.should <= upper
end
@@ -58,7 +58,7 @@ describe "SecureRandom.random_number" do
it "generates a random value in given (float) range limits" do
64.times do
num = SecureRandom.random_number 0.6..0.9
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.6.should <= num
num.should <= 0.9
end
@@ -66,14 +66,14 @@ describe "SecureRandom.random_number" do
it "generates a random float number between 0.0 and 1.0 if argument is negative" do
num = SecureRandom.random_number(-10)
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.0.should <= num
num.should < 1.0
end
it "generates a random float number between 0.0 and 1.0 if argument is negative float" do
num = SecureRandom.random_number(-11.1)
- num.should be_kind_of(Float)
+ num.should.is_a?(Float)
0.0.should <= num
num.should < 1.0
end
@@ -84,7 +84,7 @@ describe "SecureRandom.random_number" do
256.times do
val = SecureRandom.random_number
# make sure the random values are not repeating
- values.should_not include(val)
+ values.should_not.include?(val)
values << val
end
end
@@ -92,6 +92,6 @@ describe "SecureRandom.random_number" do
it "raises ArgumentError if the argument is non-numeric" do
-> {
SecureRandom.random_number(Object.new)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/set/add_spec.rb b/spec/ruby/library/set/add_spec.rb
deleted file mode 100644
index 68356cc111..0000000000
--- a/spec/ruby/library/set/add_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-require_relative 'shared/add'
-
-describe "Set#add" do
- it_behaves_like :set_add, :add
-end
-
-describe "Set#add?" do
- before :each do
- @set = Set.new
- end
-
- it "adds the passed Object to self" do
- @set.add?("cat")
- @set.should include("cat")
- end
-
- it "returns self when the Object has not yet been added to self" do
- @set.add?("cat").should equal(@set)
- end
-
- it "returns nil when the Object has already been added to self" do
- @set.add?("cat")
- @set.add?("cat").should be_nil
- end
-end
diff --git a/spec/ruby/library/set/append_spec.rb b/spec/ruby/library/set/append_spec.rb
deleted file mode 100644
index 8b3498b779..0000000000
--- a/spec/ruby/library/set/append_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-require_relative 'shared/add'
-
-describe "Set#<<" do
- it_behaves_like :set_add, :<<
-end
diff --git a/spec/ruby/library/set/case_compare_spec.rb b/spec/ruby/library/set/case_compare_spec.rb
deleted file mode 100644
index 70d392a27d..0000000000
--- a/spec/ruby/library/set/case_compare_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/include'
-require 'set'
-
-describe "Set#===" do
- it_behaves_like :set_include, :===
-
- it "is an alias for include?" do
- set = Set.new
- set.method(:===).should == set.method(:include?)
- end
-end
diff --git a/spec/ruby/library/set/case_equality_spec.rb b/spec/ruby/library/set/case_equality_spec.rb
deleted file mode 100644
index 10cbfd380a..0000000000
--- a/spec/ruby/library/set/case_equality_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/include'
-require 'set'
-
-describe "Set#===" do
- it_behaves_like :set_include, :===
-end
diff --git a/spec/ruby/library/set/classify_spec.rb b/spec/ruby/library/set/classify_spec.rb
deleted file mode 100644
index ec600c91d6..0000000000
--- a/spec/ruby/library/set/classify_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#classify" do
- before :each do
- @set = Set["one", "two", "three", "four"]
- end
-
- it "yields each Object in self" do
- res = []
- @set.classify { |x| res << x }
- res.sort.should == ["one", "two", "three", "four"].sort
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.classify
- enum.should be_an_instance_of(Enumerator)
-
- classified = enum.each { |x| x.length }
- classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
- end
-
- it "classifies the Objects in self based on the block's return value" do
- classified = @set.classify { |x| x.length }
- classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
- end
-end
diff --git a/spec/ruby/library/set/clear_spec.rb b/spec/ruby/library/set/clear_spec.rb
deleted file mode 100644
index 2b1c9c5b5a..0000000000
--- a/spec/ruby/library/set/clear_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#clear" do
- before :each do
- @set = Set["one", "two", "three", "four"]
- end
-
- it "removes all elements from self" do
- @set.clear
- @set.should be_empty
- end
-
- it "returns self" do
- @set.clear.should equal(@set)
- end
-end
diff --git a/spec/ruby/library/set/collect_spec.rb b/spec/ruby/library/set/collect_spec.rb
deleted file mode 100644
index f8813a9331..0000000000
--- a/spec/ruby/library/set/collect_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-require_relative 'shared/collect'
-
-describe "Set#collect!" do
- it_behaves_like :set_collect_bang, :collect!
-end
diff --git a/spec/ruby/library/set/compare_by_identity_spec.rb b/spec/ruby/library/set/compare_by_identity_spec.rb
deleted file mode 100644
index 602d1e758e..0000000000
--- a/spec/ruby/library/set/compare_by_identity_spec.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#compare_by_identity" do
- it "compares its members by identity" do
- a = "a"
- b1 = "b"
- b2 = b1.dup
-
- set = Set.new
- set.compare_by_identity
- set.merge([a, a, b1, b2])
- set.to_a.sort.should == [a, b1, b2].sort
- end
-
- it "causes future comparisons on the receiver to be made by identity" do
- elt = [1]
- set = Set.new
- set << elt
- set.member?(elt.dup).should be_true
- set.compare_by_identity
- set.member?(elt.dup).should be_false
- end
-
- it "rehashes internally so that old members can be looked up" do
- set = Set.new
- (1..10).each { |k| set << k }
- o = Object.new
- def o.hash; 123; end
- set << o
- set.compare_by_identity
- set.member?(o).should be_true
- end
-
- it "returns self" do
- set = Set.new
- result = set.compare_by_identity
- result.should equal(set)
- end
-
- it "is idempotent and has no effect on an already compare_by_identity set" do
- set = Set.new.compare_by_identity
- set << :foo
- set.compare_by_identity.should equal(set)
- set.should.compare_by_identity?
- set.to_a.should == [:foo]
- end
-
- it "uses the semantics of BasicObject#equal? to determine members identity" do
- :a.equal?(:a).should == true
- Set.new.compare_by_identity.merge([:a, :a]).to_a.should == [:a]
-
- ary1 = [1]
- ary2 = [1]
- ary1.equal?(ary2).should == false
- Set.new.compare_by_identity.merge([ary1, ary2]).to_a.sort.should == [ary1, ary2].sort
- end
-
- it "uses #equal? semantics, but doesn't actually call #equal? to determine identity" do
- set = Set.new.compare_by_identity
- obj = mock("equal")
- obj.should_not_receive(:equal?)
- set << :foo
- set << obj
- set.to_a.should == [:foo, obj]
- end
-
- it "does not call #hash on members" do
- elt = mock("element")
- elt.should_not_receive(:hash)
- set = Set.new.compare_by_identity
- set << elt
- set.member?(elt).should be_true
- end
-
- it "regards #dup'd objects as having different identities" do
- a1 = "a"
- a2 = a1.dup
-
- set = Set.new.compare_by_identity
- set.merge([a1, a2])
- set.to_a.sort.should == [a1, a2].sort
- end
-
- it "regards #clone'd objects as having different identities" do
- a1 = "a"
- a2 = a1.clone
-
- set = Set.new.compare_by_identity
- set.merge([a1, a2])
- set.to_a.sort.should == [a1, a2].sort
- end
-
- it "raises a FrozenError on frozen sets" do
- set = Set.new.freeze
- -> {
- set.compare_by_identity
- }.should raise_error(FrozenError, /frozen Hash/)
- end
-
- it "persists over #dups" do
- set = Set.new.compare_by_identity
- set << :a
- set_dup = set.dup
- set_dup.should == set
- set_dup << :a
- set_dup.to_a.should == [:a]
- end
-
- it "persists over #clones" do
- set = Set.new.compare_by_identity
- set << :a
- set_clone = set.clone
- set_clone.should == set
- set_clone << :a
- set_clone.to_a.should == [:a]
- end
-
- it "is not equal to set what does not compare by identity" do
- Set.new([1, 2]).should == Set.new([1, 2])
- Set.new([1, 2]).should_not == Set.new([1, 2]).compare_by_identity
- end
-end
-
-describe "Set#compare_by_identity?" do
- it "returns false by default" do
- Set.new.should_not.compare_by_identity?
- end
-
- it "returns true once #compare_by_identity has been invoked on self" do
- set = Set.new
- set.compare_by_identity
- set.should.compare_by_identity?
- end
-
- it "returns true when called multiple times on the same set" do
- set = Set.new
- set.compare_by_identity
- set.should.compare_by_identity?
- set.should.compare_by_identity?
- set.should.compare_by_identity?
- end
-end
diff --git a/spec/ruby/library/set/comparison_spec.rb b/spec/ruby/library/set/comparison_spec.rb
deleted file mode 100644
index ddcfbae0af..0000000000
--- a/spec/ruby/library/set/comparison_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#<=>" do
- it "returns 0 if the sets are equal" do
- (Set[] <=> Set[]).should == 0
- (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
- end
-
- it "returns -1 if the set is a proper subset of the other set" do
- (Set[] <=> Set[1]).should == -1
- (Set[1, 2] <=> Set[1, 2, 3]).should == -1
- end
-
- it "returns +1 if the set is a proper superset of other set" do
- (Set[1] <=> Set[]).should == +1
- (Set[1, 2, 3] <=> Set[1, 2]).should == +1
- end
-
- it "returns nil if the set has unique elements" do
- (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
- end
-
- it "returns nil when the argument is not set-like" do
- (Set[] <=> false).should be_nil
- end
-end
diff --git a/spec/ruby/library/set/constructor_spec.rb b/spec/ruby/library/set/constructor_spec.rb
deleted file mode 100644
index bb84861514..0000000000
--- a/spec/ruby/library/set/constructor_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set[]" do
- it "returns a new Set populated with the passed Objects" do
- set = Set[1, 2, 3]
-
- set.instance_of?(Set).should be_true
- set.size.should eql(3)
-
- set.should include(1)
- set.should include(2)
- set.should include(3)
- end
-end
diff --git a/spec/ruby/library/set/delete_if_spec.rb b/spec/ruby/library/set/delete_if_spec.rb
deleted file mode 100644
index 33caeeaab7..0000000000
--- a/spec/ruby/library/set/delete_if_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#delete_if" do
- before :each do
- @set = Set["one", "two", "three"]
- end
-
- it "yields every element of self" do
- ret = []
- @set.delete_if { |x| ret << x }
- ret.sort.should == ["one", "two", "three"].sort
- end
-
- it "deletes every element from self for which the passed block returns true" do
- @set.delete_if { |x| x.size == 3 }
- @set.size.should eql(1)
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-
- it "returns self" do
- @set.delete_if { |x| x }.should equal(@set)
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.delete_if
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size == 3 }
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-end
diff --git a/spec/ruby/library/set/delete_spec.rb b/spec/ruby/library/set/delete_spec.rb
deleted file mode 100644
index b12524384a..0000000000
--- a/spec/ruby/library/set/delete_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#delete" do
- before :each do
- @set = Set["a", "b", "c"]
- end
-
- it "deletes the passed Object from self" do
- @set.delete("a")
- @set.should_not include("a")
- end
-
- it "returns self" do
- @set.delete("a").should equal(@set)
- @set.delete("x").should equal(@set)
- end
-end
-
-describe "Set#delete?" do
- before :each do
- @set = Set["a", "b", "c"]
- end
-
- it "deletes the passed Object from self" do
- @set.delete?("a")
- @set.should_not include("a")
- end
-
- it "returns self when the passed Object is in self" do
- @set.delete?("a").should equal(@set)
- end
-
- it "returns nil when the passed Object is not in self" do
- @set.delete?("x").should be_nil
- end
-end
diff --git a/spec/ruby/library/set/difference_spec.rb b/spec/ruby/library/set/difference_spec.rb
deleted file mode 100644
index 422f2ed3c7..0000000000
--- a/spec/ruby/library/set/difference_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-require_relative 'shared/difference'
-
-describe "Set#difference" do
- it_behaves_like :set_difference, :difference
-end
diff --git a/spec/ruby/library/set/disjoint_spec.rb b/spec/ruby/library/set/disjoint_spec.rb
deleted file mode 100644
index ea3b141455..0000000000
--- a/spec/ruby/library/set/disjoint_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-
-describe "Set#disjoint?" do
- it "returns false when two Sets have at least one element in common" do
- Set[1, 2].disjoint?(Set[2, 3]).should == false
- end
-
- it "returns true when two Sets have no element in common" do
- Set[1, 2].disjoint?(Set[3, 4]).should == true
- end
-
- context "when comparing to a Set-like object" do
- it "returns false when a Set has at least one element in common with a Set-like object" do
- Set[1, 2].disjoint?(SetSpecs::SetLike.new([2, 3])).should be_false
- end
-
- it "returns true when a Set has no element in common with a Set-like object" do
- Set[1, 2].disjoint?(SetSpecs::SetLike.new([3, 4])).should be_true
- end
- end
-end
diff --git a/spec/ruby/library/set/divide_spec.rb b/spec/ruby/library/set/divide_spec.rb
deleted file mode 100644
index 998a1b292c..0000000000
--- a/spec/ruby/library/set/divide_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#divide" do
- it "divides self into a set of subsets based on the blocks return values" do
- set = Set["one", "two", "three", "four", "five"].divide { |x| x.length }
- set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
- end
-
- it "yields each Object to the block" do
- ret = []
- Set["one", "two", "three", "four", "five"].divide { |x| ret << x }
- ret.sort.should == ["five", "four", "one", "three", "two"]
- end
-
- it "returns an enumerator when not passed a block" do
- ret = Set[1, 2, 3, 4].divide
- ret.should be_kind_of(Enumerator)
- ret.each(&:even?).should == Set[Set[1, 3], Set[2, 4]]
- end
-end
-
-describe "Set#divide when passed a block with an arity of 2" do
- it "divides self into a set of subsets based on the blocks return values" do
- set = Set[1, 3, 4, 6, 9, 10, 11].divide { |x, y| (x - y).abs == 1 }
- set.map{ |x| x.to_a.sort }.sort.should == [[1], [3, 4], [6], [9, 10, 11]]
- end
-
- it "yields each two Object to the block" do
- ret = []
- Set[1, 2].divide { |x, y| ret << [x, y] }
- ret.sort.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
- end
-
- it "returns an enumerator when not passed a block" do
- ret = Set[1, 2, 3, 4].divide
- ret.should be_kind_of(Enumerator)
- ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]]
- end
-end
-
-describe "Set#divide when passed a block with an arity of > 2" do
- it "only uses the first element if the arity > 2" do
- set = Set["one", "two", "three", "four", "five"].divide do |x, y, z|
- y.should be_nil
- z.should be_nil
- x.length
- end
- set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
- end
-
- it "only uses the first element if the arity = -1" do
- set = Set["one", "two", "three", "four", "five"].divide do |*xs|
- xs.size.should == 1
- xs.first.length
- end
- set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
- end
-end
diff --git a/spec/ruby/library/set/each_spec.rb b/spec/ruby/library/set/each_spec.rb
deleted file mode 100644
index 44e185a4da..0000000000
--- a/spec/ruby/library/set/each_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#each" do
- before :each do
- @set = Set[1, 2, 3]
- end
-
- it "yields each Object in self" do
- ret = []
- @set.each { |x| ret << x }
- ret.sort.should == [1, 2, 3]
- end
-
- it "returns self" do
- @set.each { |x| x }.should equal(@set)
- end
-
- it "returns an Enumerator when not passed a block" do
- enum = @set.each
- enum.should be_an_instance_of(Enumerator)
-
- ret = []
- enum.each { |x| ret << x }
- ret.sort.should == [1, 2, 3]
- end
-end
diff --git a/spec/ruby/library/set/empty_spec.rb b/spec/ruby/library/set/empty_spec.rb
deleted file mode 100644
index 1789a664c7..0000000000
--- a/spec/ruby/library/set/empty_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#empty?" do
- it "returns true if self is empty" do
- Set[].empty?.should be_true
- Set[1].empty?.should be_false
- Set[1,2,3].empty?.should be_false
- end
-end
diff --git a/spec/ruby/library/set/enumerable/to_set_spec.rb b/spec/ruby/library/set/enumerable/to_set_spec.rb
deleted file mode 100644
index b2d850515b..0000000000
--- a/spec/ruby/library/set/enumerable/to_set_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-require 'set'
-
-describe "Enumerable#to_set" do
- it "returns a new Set created from self" do
- [1, 2, 3].to_set.should == Set[1, 2, 3]
- {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
- end
-
- it "passes down passed blocks" do
- [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
- end
-end
diff --git a/spec/ruby/library/set/eql_spec.rb b/spec/ruby/library/set/eql_spec.rb
deleted file mode 100644
index dd8e633775..0000000000
--- a/spec/ruby/library/set/eql_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#eql?" do
- it "returns true when the passed argument is a Set and contains the same elements" do
- Set[].should eql(Set[])
- Set[1, 2, 3].should eql(Set[1, 2, 3])
- Set[1, 2, 3].should eql(Set[3, 2, 1])
- Set["a", :b, ?c].should eql(Set[?c, :b, "a"])
-
- Set[1, 2, 3].should_not eql(Set[1.0, 2, 3])
- Set[1, 2, 3].should_not eql(Set[2, 3])
- Set[1, 2, 3].should_not eql(Set[])
- end
-end
diff --git a/spec/ruby/library/set/equal_value_spec.rb b/spec/ruby/library/set/equal_value_spec.rb
deleted file mode 100644
index f5b5f790c0..0000000000
--- a/spec/ruby/library/set/equal_value_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-
-describe "Set#==" do
- it "returns true when the passed Object is a Set and self and the Object contain the same elements" do
- Set[].should == Set[]
- Set[1, 2, 3].should == Set[1, 2, 3]
- Set["1", "2", "3"].should == Set["1", "2", "3"]
-
- Set[1, 2, 3].should_not == Set[1.0, 2, 3]
- Set[1, 2, 3].should_not == [1, 2, 3]
- end
-
- it "does not depend on the order of the elements" do
- Set[1, 2, 3].should == Set[3, 2, 1]
- Set[:a, "b", ?c].should == Set[?c, "b", :a]
- end
-
- it "does not depend on the order of nested Sets" do
- Set[Set[1], Set[2], Set[3]].should == Set[Set[3], Set[2], Set[1]]
-
- set1 = Set[Set["a", "b"], Set["c", "d"], Set["e", "f"]]
- set2 = Set[Set["c", "d"], Set["a", "b"], Set["e", "f"]]
- set1.should == set2
- end
-
- context "when comparing to a Set-like object" do
- it "returns true when a Set and a Set-like object contain the same elements" do
- Set[1, 2, 3].should == SetSpecs::SetLike.new([1, 2, 3])
- end
- end
-end
diff --git a/spec/ruby/library/set/exclusion_spec.rb b/spec/ruby/library/set/exclusion_spec.rb
deleted file mode 100644
index 5bc4b5a2bf..0000000000
--- a/spec/ruby/library/set/exclusion_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#^" do
- before :each do
- @set = Set[1, 2, 3, 4]
- end
-
- it "returns a new Set containing elements that are not in both self and the passed Enumerable" do
- (@set ^ Set[3, 4, 5]).should == Set[1, 2, 5]
- (@set ^ [3, 4, 5]).should == Set[1, 2, 5]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set ^ 3 }.should raise_error(ArgumentError)
- -> { @set ^ Object.new }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/fixtures/set_like.rb b/spec/ruby/library/set/fixtures/set_like.rb
deleted file mode 100644
index 46f61a451e..0000000000
--- a/spec/ruby/library/set/fixtures/set_like.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require 'set'
-
-module SetSpecs
- # This class is used to test the interaction of "Set-like" objects with real Sets
- #
- # These "Set-like" objects reply to is_a?(Set) with true and thus real Set objects are able to transparently
- # interoperate with them in a duck-typing manner.
- class SetLike
- include Enumerable
-
- def is_a?(klass)
- super || klass == ::Set
- end
-
- def initialize(entries)
- @entries = entries
- end
-
- def each(&block)
- @entries.each(&block)
- end
-
- def inspect
- "#<#{self.class}: {#{map(&:inspect).join(", ")}}>"
- end
-
- def size
- @entries.size
- end
- end
-end
diff --git a/spec/ruby/library/set/flatten_merge_spec.rb b/spec/ruby/library/set/flatten_merge_spec.rb
deleted file mode 100644
index f2c99a9481..0000000000
--- a/spec/ruby/library/set/flatten_merge_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#flatten_merge" do
- it "is protected" do
- Set.should have_protected_instance_method("flatten_merge")
- end
-
- it "flattens the passed Set and merges it into self" do
- set1 = Set[1, 2]
- set2 = Set[3, 4, Set[5, 6]]
-
- set1.send(:flatten_merge, set2).should == Set[1, 2, 3, 4, 5, 6]
- end
-
- it "raises an ArgumentError when trying to flatten a recursive Set" do
- set1 = Set[1, 2, 3]
- set2 = Set[5, 6, 7]
- set2 << set2
-
- -> { set1.send(:flatten_merge, set2) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/flatten_spec.rb b/spec/ruby/library/set/flatten_spec.rb
deleted file mode 100644
index 51b58d6439..0000000000
--- a/spec/ruby/library/set/flatten_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
-
-describe "Set#flatten" do
- it "returns a copy of self with each included Set flattened" do
- set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
- flattened_set = set.flatten
-
- flattened_set.should_not equal(set)
- flattened_set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- end
-
- it "raises an ArgumentError when self is recursive" do
- (set = Set[]) << set
- -> { set.flatten }.should raise_error(ArgumentError)
- end
-
- context "when Set contains a Set-like object" do
- it "returns a copy of self with each included Set-like object flattened" do
- Set[SetSpecs::SetLike.new([1])].flatten.should == Set[1]
- end
- end
-end
-
-describe "Set#flatten!" do
- it "flattens self" do
- set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
- set.flatten!
- set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- end
-
- it "returns self when self was modified" do
- set = Set[1, 2, Set[3, 4]]
- set.flatten!.should equal(set)
- end
-
- it "returns nil when self was not modified" do
- set = Set[1, 2, 3, 4]
- set.flatten!.should be_nil
- end
-
- it "raises an ArgumentError when self is recursive" do
- (set = Set[]) << set
- -> { set.flatten! }.should raise_error(ArgumentError)
- end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- context "when Set contains a Set-like object" do
- it "flattens self, including Set-like objects" do
- Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1]
- end
- end
- end
-end
diff --git a/spec/ruby/library/set/hash_spec.rb b/spec/ruby/library/set/hash_spec.rb
deleted file mode 100644
index c5bab73931..0000000000
--- a/spec/ruby/library/set/hash_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#hash" do
- it "is static" do
- Set[].hash.should == Set[].hash
- Set[1, 2, 3].hash.should == Set[1, 2, 3].hash
- Set[:a, "b", ?c].hash.should == Set[?c, "b", :a].hash
-
- Set[].hash.should_not == Set[1, 2, 3].hash
- Set[1, 2, 3].hash.should_not == Set[:a, "b", ?c].hash
- end
-
- # see https://github.com/jruby/jruby/issues/8393
- it "is equal to nil.hash for an uninitialized Set" do
- Set.allocate.hash.should == nil.hash
- end
-end
diff --git a/spec/ruby/library/set/include_spec.rb b/spec/ruby/library/set/include_spec.rb
deleted file mode 100644
index 68532d9a04..0000000000
--- a/spec/ruby/library/set/include_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/include'
-require 'set'
-
-describe "Set#include?" do
- it_behaves_like :set_include, :include?
-end
diff --git a/spec/ruby/library/set/initialize_clone_spec.rb b/spec/ruby/library/set/initialize_clone_spec.rb
deleted file mode 100644
index bda42cd6e8..0000000000
--- a/spec/ruby/library/set/initialize_clone_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#initialize_clone" do
- # See https://bugs.ruby-lang.org/issues/14266
- it "does not freeze the new Set when called from clone(freeze: false)" do
- set1 = Set[1, 2]
- set1.freeze
- set2 = set1.clone(freeze: false)
- set1.frozen?.should == true
- set2.frozen?.should == false
- set2.add 3
- set1.should == Set[1, 2]
- set2.should == Set[1, 2, 3]
- end
-end
diff --git a/spec/ruby/library/set/initialize_spec.rb b/spec/ruby/library/set/initialize_spec.rb
deleted file mode 100644
index 76ebc0a20a..0000000000
--- a/spec/ruby/library/set/initialize_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#initialize" do
- it "is private" do
- Set.should have_private_instance_method(:initialize)
- end
-
- it "adds all elements of the passed Enumerable to self" do
- s = Set.new([1, 2, 3])
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
- end
-
- it "uses #each_entry on the provided Enumerable" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:each_entry).and_yield(1).and_yield(2).and_yield(3)
- s = Set.new(enumerable)
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
- end
-
- it "uses #each on the provided Enumerable if it does not respond to #each_entry" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
- s = Set.new(enumerable)
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
- end
-
- it "raises if the provided Enumerable does not respond to #each_entry or #each" do
- enumerable = MockObject.new('mock-enumerable')
- -> { Set.new(enumerable) }.should raise_error(ArgumentError, "value must be enumerable")
- end
-
- it "should initialize with empty array and set" do
- s = Set.new([])
- s.size.should eql(0)
-
- s = Set.new({})
- s.size.should eql(0)
- end
-
- it "preprocesses all elements by a passed block before adding to self" do
- s = Set.new([1, 2, 3]) { |x| x * x }
- s.size.should eql(3)
- s.should include(1)
- s.should include(4)
- s.should include(9)
- end
-
- it "should initialize with empty array and block" do
- s = Set.new([]) { |x| x * x }
- s.size.should eql(0)
- end
-
- it "should initialize with empty set and block" do
- s = Set.new(Set.new) { |x| x * x }
- s.size.should eql(0)
- end
-
- it "should initialize with just block" do
- s = Set.new { |x| x * x }
- s.size.should eql(0)
- s.should eql(Set.new)
- end
-end
diff --git a/spec/ruby/library/set/inspect_spec.rb b/spec/ruby/library/set/inspect_spec.rb
deleted file mode 100644
index 4060c63b95..0000000000
--- a/spec/ruby/library/set/inspect_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/inspect'
-require 'set'
-
-describe "Set#inspect" do
- it_behaves_like :set_inspect, :inspect
-end
diff --git a/spec/ruby/library/set/intersect_spec.rb b/spec/ruby/library/set/intersect_spec.rb
deleted file mode 100644
index e60f06db94..0000000000
--- a/spec/ruby/library/set/intersect_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-
-describe "Set#intersect?" do
- it "returns true when two Sets have at least one element in common" do
- Set[1, 2].intersect?(Set[2, 3]).should == true
- end
-
- it "returns false when two Sets have no element in common" do
- Set[1, 2].intersect?(Set[3, 4]).should == false
- end
-
- context "when comparing to a Set-like object" do
- it "returns true when a Set has at least one element in common with a Set-like object" do
- Set[1, 2].intersect?(SetSpecs::SetLike.new([2, 3])).should be_true
- end
-
- it "returns false when a Set has no element in common with a Set-like object" do
- Set[1, 2].intersect?(SetSpecs::SetLike.new([3, 4])).should be_false
- end
- end
-end
diff --git a/spec/ruby/library/set/intersection_spec.rb b/spec/ruby/library/set/intersection_spec.rb
deleted file mode 100644
index 792c2d8f07..0000000000
--- a/spec/ruby/library/set/intersection_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/intersection'
-require 'set'
-
-describe "Set#intersection" do
- it_behaves_like :set_intersection, :intersection
-end
-
-describe "Set#&" do
- it_behaves_like :set_intersection, :&
-end
diff --git a/spec/ruby/library/set/join_spec.rb b/spec/ruby/library/set/join_spec.rb
deleted file mode 100644
index 3f511a84e4..0000000000
--- a/spec/ruby/library/set/join_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#join" do
- it "returns an empty string if the Set is empty" do
- Set[].join.should == ''
- end
-
- it "returns a new string formed by joining elements after conversion" do
- set = Set[:a, :b, :c]
- set.join.should == "abc"
- end
-
- it "does not separate elements when the passed separator is nil" do
- set = Set[:a, :b, :c]
- set.join(nil).should == "abc"
- end
-
- it "returns a string formed by concatenating each element separated by the separator" do
- set = Set[:a, :b, :c]
- set.join(' | ').should == "a | b | c"
- end
-
- it "calls #to_a to convert the Set in to an Array" do
- set = Set[:a, :b, :c]
- set.should_receive(:to_a).and_return([:a, :b, :c])
- set.join.should == "abc"
- end
-end
diff --git a/spec/ruby/library/set/keep_if_spec.rb b/spec/ruby/library/set/keep_if_spec.rb
deleted file mode 100644
index 7edc80769f..0000000000
--- a/spec/ruby/library/set/keep_if_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#keep_if" do
- before :each do
- @set = Set["one", "two", "three"]
- end
-
- it "yields every element of self" do
- ret = []
- @set.keep_if { |x| ret << x }
- ret.sort.should == ["one", "two", "three"].sort
- end
-
- it "keeps every element from self for which the passed block returns true" do
- @set.keep_if { |x| x.size != 3 }
- @set.size.should eql(1)
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-
- it "returns self" do
- @set.keep_if {}.should equal(@set)
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.keep_if
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size != 3 }
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-end
diff --git a/spec/ruby/library/set/length_spec.rb b/spec/ruby/library/set/length_spec.rb
deleted file mode 100644
index fef63d25a7..0000000000
--- a/spec/ruby/library/set/length_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/length'
-require 'set'
-
-describe "Set#length" do
- it_behaves_like :set_length, :length
-end
diff --git a/spec/ruby/library/set/map_spec.rb b/spec/ruby/library/set/map_spec.rb
deleted file mode 100644
index e60e98b179..0000000000
--- a/spec/ruby/library/set/map_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-require_relative 'shared/collect'
-
-describe "Set#map!" do
- it_behaves_like :set_collect_bang, :map!
-end
diff --git a/spec/ruby/library/set/member_spec.rb b/spec/ruby/library/set/member_spec.rb
deleted file mode 100644
index 5b56a38ab9..0000000000
--- a/spec/ruby/library/set/member_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/include'
-require 'set'
-
-describe "Set#member?" do
- it_behaves_like :set_include, :member?
-end
diff --git a/spec/ruby/library/set/merge_spec.rb b/spec/ruby/library/set/merge_spec.rb
deleted file mode 100644
index 3ae0da827c..0000000000
--- a/spec/ruby/library/set/merge_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#merge" do
- it "adds the elements of the passed Enumerable to self" do
- Set[:a, :b].merge(Set[:b, :c, :d]).should == Set[:a, :b, :c, :d]
- Set[1, 2].merge([3, 4]).should == Set[1, 2, 3, 4]
- end
-
- it "returns self" do
- set = Set[1, 2]
- set.merge([3, 4]).should equal(set)
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { Set[1, 2].merge(1) }.should raise_error(ArgumentError)
- -> { Set[1, 2].merge(Object.new) }.should raise_error(ArgumentError)
- end
-
- ruby_version_is ""..."3.3" do
- it "accepts only a single argument" do
- -> { Set[].merge([], []) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
- end
- end
-
- ruby_version_is "3.3" do
- it "accepts multiple arguments" do
- Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
- end
- end
-end
diff --git a/spec/ruby/library/set/minus_spec.rb b/spec/ruby/library/set/minus_spec.rb
deleted file mode 100644
index 3fe0b6a2cc..0000000000
--- a/spec/ruby/library/set/minus_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-require_relative 'shared/difference'
-
-describe "Set#-" do
- it_behaves_like :set_difference, :-
-end
diff --git a/spec/ruby/library/set/plus_spec.rb b/spec/ruby/library/set/plus_spec.rb
deleted file mode 100644
index 3e70d3269d..0000000000
--- a/spec/ruby/library/set/plus_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/union'
-require 'set'
-
-describe "Set#+" do
- it_behaves_like :set_union, :+
-end
diff --git a/spec/ruby/library/set/pretty_print_cycle_spec.rb b/spec/ruby/library/set/pretty_print_cycle_spec.rb
deleted file mode 100644
index 4f440353e5..0000000000
--- a/spec/ruby/library/set/pretty_print_cycle_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#pretty_print_cycle" do
- it "passes the 'pretty print' representation of a self-referencing Set to the pretty print writer" do
- pp = mock("PrettyPrint")
- pp.should_receive(:text).with("#<Set: {...}>")
- Set[1, 2, 3].pretty_print_cycle(pp)
- end
-end
diff --git a/spec/ruby/library/set/proper_subset_spec.rb b/spec/ruby/library/set/proper_subset_spec.rb
deleted file mode 100644
index 6b51dedc9f..0000000000
--- a/spec/ruby/library/set/proper_subset_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
-
-describe "Set#proper_subset?" do
- before :each do
- @set = Set[1, 2, 3, 4]
- end
-
- it "returns true if passed a Set that self is a proper subset of" do
- Set[].proper_subset?(@set).should be_true
- Set[].proper_subset?(Set[1, 2, 3]).should be_true
- Set[].proper_subset?(Set["a", :b, ?c]).should be_true
-
- Set[1, 2, 3].proper_subset?(@set).should be_true
- Set[1, 3].proper_subset?(@set).should be_true
- Set[1, 2].proper_subset?(@set).should be_true
- Set[1].proper_subset?(@set).should be_true
-
- Set[5].proper_subset?(@set).should be_false
- Set[1, 5].proper_subset?(@set).should be_false
- Set[nil].proper_subset?(@set).should be_false
- Set["test"].proper_subset?(@set).should be_false
-
- @set.proper_subset?(@set).should be_false
- Set[].proper_subset?(Set[]).should be_false
- end
-
- it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].proper_subset?([]) }.should raise_error(ArgumentError)
- -> { Set[].proper_subset?(1) }.should raise_error(ArgumentError)
- -> { Set[].proper_subset?("test") }.should raise_error(ArgumentError)
- -> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
- end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a proper subset of" do
- Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
- end
- end
- end
-end
diff --git a/spec/ruby/library/set/proper_superset_spec.rb b/spec/ruby/library/set/proper_superset_spec.rb
deleted file mode 100644
index a386c8c097..0000000000
--- a/spec/ruby/library/set/proper_superset_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-
-describe "Set#proper_superset?" do
- before :each do
- @set = Set[1, 2, 3, 4]
- end
-
- it "returns true if passed a Set that self is a proper superset of" do
- @set.proper_superset?(Set[]).should be_true
- Set[1, 2, 3].proper_superset?(Set[]).should be_true
- Set["a", :b, ?c].proper_superset?(Set[]).should be_true
-
- @set.proper_superset?(Set[1, 2, 3]).should be_true
- @set.proper_superset?(Set[1, 3]).should be_true
- @set.proper_superset?(Set[1, 2]).should be_true
- @set.proper_superset?(Set[1]).should be_true
-
- @set.proper_superset?(Set[5]).should be_false
- @set.proper_superset?(Set[1, 5]).should be_false
- @set.proper_superset?(Set[nil]).should be_false
- @set.proper_superset?(Set["test"]).should be_false
-
- @set.proper_superset?(@set).should be_false
- Set[].proper_superset?(Set[]).should be_false
- end
-
- it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].proper_superset?([]) }.should raise_error(ArgumentError)
- -> { Set[].proper_superset?(1) }.should raise_error(ArgumentError)
- -> { Set[].proper_superset?("test") }.should raise_error(ArgumentError)
- -> { Set[].proper_superset?(Object.new) }.should raise_error(ArgumentError)
- end
-
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a proper superset of" do
- Set[1, 2, 3, 4].proper_superset?(SetSpecs::SetLike.new([1, 2, 3])).should be_true
- end
- end
-end
diff --git a/spec/ruby/library/set/reject_spec.rb b/spec/ruby/library/set/reject_spec.rb
deleted file mode 100644
index 9131f960ad..0000000000
--- a/spec/ruby/library/set/reject_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#reject!" do
- before :each do
- @set = Set["one", "two", "three"]
- end
-
- it "yields every element of self" do
- ret = []
- @set.reject! { |x| ret << x }
- ret.sort.should == ["one", "two", "three"].sort
- end
-
- it "deletes every element from self for which the passed block returns true" do
- @set.reject! { |x| x.size == 3 }
- @set.size.should eql(1)
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-
- it "returns self when self was modified" do
- @set.reject! { |x| true }.should equal(@set)
- end
-
- it "returns nil when self was not modified" do
- @set.reject! { |x| false }.should be_nil
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.reject!
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size == 3 }
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-end
diff --git a/spec/ruby/library/set/replace_spec.rb b/spec/ruby/library/set/replace_spec.rb
deleted file mode 100644
index 7511066c9c..0000000000
--- a/spec/ruby/library/set/replace_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#replace" do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "replaces the contents with other and returns self" do
- @set.replace(Set[1, 2, 3]).should == @set
- @set.should == Set[1, 2, 3]
- end
-
- it "accepts any enumerable as other" do
- @set.replace([1, 2, 3]).should == Set[1, 2, 3]
- end
-end
diff --git a/spec/ruby/library/set/set_spec.rb b/spec/ruby/library/set/set_spec.rb
deleted file mode 100644
index 2a4edc6dfc..0000000000
--- a/spec/ruby/library/set/set_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-
-describe 'Set' do
- ruby_version_is '3.2' do
- it 'is available without explicit requiring' do
- output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
- puts Set.new([1, 2, 3])
- RUBY
- output.chomp.should == "#<Set: {1, 2, 3}>"
- end
- end
-end
diff --git a/spec/ruby/library/set/shared/add.rb b/spec/ruby/library/set/shared/add.rb
deleted file mode 100644
index 9e797f5df9..0000000000
--- a/spec/ruby/library/set/shared/add.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :set_add, shared: true do
- before :each do
- @set = Set.new
- end
-
- it "adds the passed Object to self" do
- @set.send(@method, "dog")
- @set.should include("dog")
- end
-
- it "returns self" do
- @set.send(@method, "dog").should equal(@set)
- end
-end
diff --git a/spec/ruby/library/set/shared/collect.rb b/spec/ruby/library/set/shared/collect.rb
deleted file mode 100644
index bc58c231be..0000000000
--- a/spec/ruby/library/set/shared/collect.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-describe :set_collect_bang, shared: true do
- before :each do
- @set = Set[1, 2, 3, 4, 5]
- end
-
- it "yields each Object in self" do
- res = []
- @set.send(@method) { |x| res << x }
- res.sort.should == [1, 2, 3, 4, 5].sort
- end
-
- it "returns self" do
- @set.send(@method) { |x| x }.should equal(@set)
- end
-
- it "replaces self with the return values of the block" do
- @set.send(@method) { |x| x * 2 }
- @set.should == Set[2, 4, 6, 8, 10]
- end
-end
diff --git a/spec/ruby/library/set/shared/difference.rb b/spec/ruby/library/set/shared/difference.rb
deleted file mode 100644
index f88987ed2a..0000000000
--- a/spec/ruby/library/set/shared/difference.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :set_difference, shared: true do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "returns a new Set containing self's elements excluding the elements in the passed Enumerable" do
- @set.send(@method, Set[:a, :b]).should == Set[:c]
- @set.send(@method, [:b, :c]).should == Set[:a]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
- -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/shared/include.rb b/spec/ruby/library/set/shared/include.rb
deleted file mode 100644
index b4d95cde24..0000000000
--- a/spec/ruby/library/set/shared/include.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-describe :set_include, shared: true do
- it "returns true when self contains the passed Object" do
- set = Set[:a, :b, :c]
- set.send(@method, :a).should be_true
- set.send(@method, :e).should be_false
- end
-
- describe "member equality" do
- it "is checked using both #hash and #eql?" do
- obj = Object.new
- obj_another = Object.new
-
- def obj.hash; 42 end
- def obj_another.hash; 42 end
- def obj_another.eql?(o) hash == o.hash end
-
- set = Set["a", "b", "c", obj]
- set.send(@method, obj_another).should == true
- end
-
- it "is not checked using #==" do
- obj = Object.new
- set = Set["a", "b", "c"]
-
- obj.should_not_receive(:==)
- set.send(@method, obj)
- end
- end
-end
diff --git a/spec/ruby/library/set/shared/inspect.rb b/spec/ruby/library/set/shared/inspect.rb
deleted file mode 100644
index adb6ddb4c9..0000000000
--- a/spec/ruby/library/set/shared/inspect.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-describe :set_inspect, shared: true do
- it "returns a String representation of self" do
- Set[].send(@method).should be_kind_of(String)
- Set[nil, false, true].send(@method).should be_kind_of(String)
- Set[1, 2, 3].send(@method).should be_kind_of(String)
- Set["1", "2", "3"].send(@method).should be_kind_of(String)
- Set[:a, "b", Set[?c]].send(@method).should be_kind_of(String)
- end
-
- it "does include the elements of the set" do
- Set["1"].send(@method).should == '#<Set: {"1"}>'
- end
-
- it "puts spaces between the elements" do
- Set["1", "2"].send(@method).should include('", "')
- end
-
- it "correctly handles cyclic-references" do
- set1 = Set[]
- set2 = Set[set1]
- set1 << set2
- set1.send(@method).should be_kind_of(String)
- set1.send(@method).should include("#<Set: {...}>")
- end
-end
diff --git a/spec/ruby/library/set/shared/intersection.rb b/spec/ruby/library/set/shared/intersection.rb
deleted file mode 100644
index 5ae4199c94..0000000000
--- a/spec/ruby/library/set/shared/intersection.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :set_intersection, shared: true do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "returns a new Set containing only elements shared by self and the passed Enumerable" do
- @set.send(@method, Set[:b, :c, :d, :e]).should == Set[:b, :c]
- @set.send(@method, [:b, :c, :d]).should == Set[:b, :c]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
- -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/shared/select.rb b/spec/ruby/library/set/shared/select.rb
deleted file mode 100644
index 2108d398b4..0000000000
--- a/spec/ruby/library/set/shared/select.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../../spec_helper'
-require 'set'
-
-describe :set_select_bang, shared: true do
- before :each do
- @set = Set["one", "two", "three"]
- end
-
- it "yields every element of self" do
- ret = []
- @set.send(@method) { |x| ret << x }
- ret.sort.should == ["one", "two", "three"].sort
- end
-
- it "keeps every element from self for which the passed block returns true" do
- @set.send(@method) { |x| x.size != 3 }
- @set.size.should eql(1)
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-
- it "returns self when self was modified" do
- @set.send(@method) { false }.should equal(@set)
- end
-
- it "returns nil when self was not modified" do
- @set.send(@method) { true }.should be_nil
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size != 3 }
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-end
diff --git a/spec/ruby/library/set/shared/union.rb b/spec/ruby/library/set/shared/union.rb
deleted file mode 100644
index 314f0e852d..0000000000
--- a/spec/ruby/library/set/shared/union.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :set_union, shared: true do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "returns a new Set containing all elements of self and the passed Enumerable" do
- @set.send(@method, Set[:b, :d, :e]).should == Set[:a, :b, :c, :d, :e]
- @set.send(@method, [:b, :e]).should == Set[:a, :b, :c, :e]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
- -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/size_spec.rb b/spec/ruby/library/set/size_spec.rb
deleted file mode 100644
index 3c8cb38517..0000000000
--- a/spec/ruby/library/set/size_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/length'
-require 'set'
-
-describe "Set#size" do
- it_behaves_like :set_length, :size
-end
diff --git a/spec/ruby/library/set/sortedset/sortedset_spec.rb b/spec/ruby/library/set/sortedset/sortedset_spec.rb
deleted file mode 100644
index 67993dee29..0000000000
--- a/spec/ruby/library/set/sortedset/sortedset_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'set'
-
-describe "SortedSet" do
- it "raises error including message that it has been extracted from the set stdlib" do
- -> {
- SortedSet
- }.should raise_error(RuntimeError) { |e|
- e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
- }
- end
-end
diff --git a/spec/ruby/library/set/subset_spec.rb b/spec/ruby/library/set/subset_spec.rb
deleted file mode 100644
index 85666d633f..0000000000
--- a/spec/ruby/library/set/subset_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
-
-describe "Set#subset?" do
- before :each do
- @set = Set[1, 2, 3, 4]
- end
-
- it "returns true if passed a Set that is equal to self or self is a subset of" do
- @set.subset?(@set).should be_true
- Set[].subset?(Set[]).should be_true
-
- Set[].subset?(@set).should be_true
- Set[].subset?(Set[1, 2, 3]).should be_true
- Set[].subset?(Set["a", :b, ?c]).should be_true
-
- Set[1, 2, 3].subset?(@set).should be_true
- Set[1, 3].subset?(@set).should be_true
- Set[1, 2].subset?(@set).should be_true
- Set[1].subset?(@set).should be_true
-
- Set[5].subset?(@set).should be_false
- Set[1, 5].subset?(@set).should be_false
- Set[nil].subset?(@set).should be_false
- Set["test"].subset?(@set).should be_false
- end
-
- it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].subset?([]) }.should raise_error(ArgumentError)
- -> { Set[].subset?(1) }.should raise_error(ArgumentError)
- -> { Set[].subset?("test") }.should raise_error(ArgumentError)
- -> { Set[].subset?(Object.new) }.should raise_error(ArgumentError)
- end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a subset of" do
- Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
- end
- end
- end
-end
diff --git a/spec/ruby/library/set/subtract_spec.rb b/spec/ruby/library/set/subtract_spec.rb
deleted file mode 100644
index 56713de8b3..0000000000
--- a/spec/ruby/library/set/subtract_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#subtract" do
- before :each do
- @set = Set[:a, :b, :c]
- end
-
- it "deletes any elements contained in other and returns self" do
- @set.subtract(Set[:b, :c]).should == @set
- @set.should == Set[:a]
- end
-
- it "accepts any enumerable as other" do
- @set.subtract([:c]).should == Set[:a, :b]
- end
-end
diff --git a/spec/ruby/library/set/superset_spec.rb b/spec/ruby/library/set/superset_spec.rb
deleted file mode 100644
index bd9d2f3eee..0000000000
--- a/spec/ruby/library/set/superset_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/set_like'
-require 'set'
-
-describe "Set#superset?" do
- before :each do
- @set = Set[1, 2, 3, 4]
- end
-
- it "returns true if passed a Set that equals self or self is a proper superset of" do
- @set.superset?(@set).should be_true
- Set[].superset?(Set[]).should be_true
-
- @set.superset?(Set[]).should be_true
- Set[1, 2, 3].superset?(Set[]).should be_true
- Set["a", :b, ?c].superset?(Set[]).should be_true
-
- @set.superset?(Set[1, 2, 3]).should be_true
- @set.superset?(Set[1, 3]).should be_true
- @set.superset?(Set[1, 2]).should be_true
- @set.superset?(Set[1]).should be_true
-
- @set.superset?(Set[5]).should be_false
- @set.superset?(Set[1, 5]).should be_false
- @set.superset?(Set[nil]).should be_false
- @set.superset?(Set["test"]).should be_false
- end
-
- it "raises an ArgumentError when passed a non-Set" do
- -> { Set[].superset?([]) }.should raise_error(ArgumentError)
- -> { Set[].superset?(1) }.should raise_error(ArgumentError)
- -> { Set[].superset?("test") }.should raise_error(ArgumentError)
- -> { Set[].superset?(Object.new) }.should raise_error(ArgumentError)
- end
-
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a superset of" do
- Set[1, 2, 3, 4].superset?(SetSpecs::SetLike.new([1, 2, 3])).should be_true
- end
- end
-end
diff --git a/spec/ruby/library/set/to_a_spec.rb b/spec/ruby/library/set/to_a_spec.rb
deleted file mode 100644
index 689e44f38a..0000000000
--- a/spec/ruby/library/set/to_a_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#to_a" do
- it "returns an array containing elements of self" do
- Set[1, 2, 3].to_a.sort.should == [1, 2, 3]
- end
-end
diff --git a/spec/ruby/library/set/to_s_spec.rb b/spec/ruby/library/set/to_s_spec.rb
deleted file mode 100644
index 3c26ae9346..0000000000
--- a/spec/ruby/library/set/to_s_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative "../../spec_helper"
-require_relative 'shared/inspect'
-require 'set'
-
-describe "Set#to_s" do
- it_behaves_like :set_inspect, :to_s
-
- it "is an alias of inspect" do
- set = Set.new
- set.method(:to_s).should == set.method(:inspect)
- end
-end
diff --git a/spec/ruby/library/set/union_spec.rb b/spec/ruby/library/set/union_spec.rb
deleted file mode 100644
index 20fe0ddca3..0000000000
--- a/spec/ruby/library/set/union_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/union'
-require 'set'
-
-describe "Set#union" do
- it_behaves_like :set_union, :union
-end
-
-describe "Set#|" do
- it_behaves_like :set_union, :|
-end
diff --git a/spec/ruby/library/shellwords/shellwords_spec.rb b/spec/ruby/library/shellwords/shellwords_spec.rb
index fe86b6faab..d1b61e0a6e 100644
--- a/spec/ruby/library/shellwords/shellwords_spec.rb
+++ b/spec/ruby/library/shellwords/shellwords_spec.rb
@@ -19,11 +19,11 @@ describe "Shellwords#shellwords" do
end
it "raises ArgumentError when double quoted strings are misquoted" do
- -> { Shellwords.shellwords('a "b c d e') }.should raise_error(ArgumentError)
+ -> { Shellwords.shellwords('a "b c d e') }.should.raise(ArgumentError)
end
it "raises ArgumentError when single quoted strings are misquoted" do
- -> { Shellwords.shellwords("a 'b c d e") }.should raise_error(ArgumentError)
+ -> { Shellwords.shellwords("a 'b c d e") }.should.raise(ArgumentError)
end
# https://bugs.ruby-lang.org/issues/10055
diff --git a/spec/ruby/library/singleton/allocate_spec.rb b/spec/ruby/library/singleton/allocate_spec.rb
index 6a1512d53b..a0094fb32a 100644
--- a/spec/ruby/library/singleton/allocate_spec.rb
+++ b/spec/ruby/library/singleton/allocate_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton.allocate" do
it "is a private method" do
- -> { SingletonSpecs::MyClass.allocate }.should raise_error(NoMethodError)
+ -> { SingletonSpecs::MyClass.allocate }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/singleton/clone_spec.rb b/spec/ruby/library/singleton/clone_spec.rb
index 3635bcd594..a7b7b731f5 100644
--- a/spec/ruby/library/singleton/clone_spec.rb
+++ b/spec/ruby/library/singleton/clone_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton#clone" do
it "is prevented" do
- -> { SingletonSpecs::MyClass.instance.clone }.should raise_error(TypeError)
+ -> { SingletonSpecs::MyClass.instance.clone }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/singleton/dup_spec.rb b/spec/ruby/library/singleton/dup_spec.rb
index 13d5a213e9..a0455f37b7 100644
--- a/spec/ruby/library/singleton/dup_spec.rb
+++ b/spec/ruby/library/singleton/dup_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton#dup" do
it "is prevented" do
- -> { SingletonSpecs::MyClass.instance.dup }.should raise_error(TypeError)
+ -> { SingletonSpecs::MyClass.instance.dup }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/singleton/instance_spec.rb b/spec/ruby/library/singleton/instance_spec.rb
index 1679728d4c..20cac602b5 100644
--- a/spec/ruby/library/singleton/instance_spec.rb
+++ b/spec/ruby/library/singleton/instance_spec.rb
@@ -3,28 +3,28 @@ require_relative 'fixtures/classes'
describe "Singleton.instance" do
it "returns an instance of the singleton class" do
- SingletonSpecs::MyClass.instance.should be_kind_of(SingletonSpecs::MyClass)
+ SingletonSpecs::MyClass.instance.should.is_a?(SingletonSpecs::MyClass)
end
it "returns the same instance for multiple calls to instance" do
- SingletonSpecs::MyClass.instance.should equal(SingletonSpecs::MyClass.instance)
+ SingletonSpecs::MyClass.instance.should.equal?(SingletonSpecs::MyClass.instance)
end
it "returns an instance of the singleton's subclasses" do
- SingletonSpecs::MyClassChild.instance.should be_kind_of(SingletonSpecs::MyClassChild)
+ SingletonSpecs::MyClassChild.instance.should.is_a?(SingletonSpecs::MyClassChild)
end
it "returns the same instance for multiple class to instance on subclasses" do
- SingletonSpecs::MyClassChild.instance.should equal(SingletonSpecs::MyClassChild.instance)
+ SingletonSpecs::MyClassChild.instance.should.equal?(SingletonSpecs::MyClassChild.instance)
end
it "returns an instance of the singleton's clone" do
klone = SingletonSpecs::MyClassChild.clone
- klone.instance.should be_kind_of(klone)
+ klone.instance.should.is_a?(klone)
end
it "returns the same instance for multiple class to instance on clones" do
klone = SingletonSpecs::MyClassChild.clone
- klone.instance.should equal(klone.instance)
+ klone.instance.should.equal?(klone.instance)
end
end
diff --git a/spec/ruby/library/singleton/load_spec.rb b/spec/ruby/library/singleton/load_spec.rb
index 4c753f9e7a..ab95d14640 100644
--- a/spec/ruby/library/singleton/load_spec.rb
+++ b/spec/ruby/library/singleton/load_spec.rb
@@ -1,21 +1,20 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-# TODO: change to a.should be_equal(b)
# TODO: write spec for cloning classes and calling private methods
# TODO: write spec for private_methods not showing up via extended
describe "Singleton._load" do
it "returns the singleton instance for anything passed in" do
klass = SingletonSpecs::MyClass
- klass._load("").should equal(klass.instance)
- klass._load("42").should equal(klass.instance)
- klass._load(42).should equal(klass.instance)
+ klass._load("").should.equal?(klass.instance)
+ klass._load("42").should.equal?(klass.instance)
+ klass._load(42).should.equal?(klass.instance)
end
it "returns the singleton instance for anything passed in to subclass" do
subklass = SingletonSpecs::MyClassChild
- subklass._load("").should equal(subklass.instance)
- subklass._load("42").should equal(subklass.instance)
- subklass._load(42).should equal(subklass.instance)
+ subklass._load("").should.equal?(subklass.instance)
+ subklass._load("42").should.equal?(subklass.instance)
+ subklass._load(42).should.equal?(subklass.instance)
end
end
diff --git a/spec/ruby/library/singleton/new_spec.rb b/spec/ruby/library/singleton/new_spec.rb
index 2f45db819c..6167231a29 100644
--- a/spec/ruby/library/singleton/new_spec.rb
+++ b/spec/ruby/library/singleton/new_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "Singleton.new" do
it "is a private method" do
- -> { SingletonSpecs::NewSpec.new }.should raise_error(NoMethodError)
+ -> { SingletonSpecs::NewSpec.new }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/afamily_spec.rb b/spec/ruby/library/socket/addrinfo/afamily_spec.rb
index 7229dab9de..5d075be057 100644
--- a/spec/ruby/library/socket/addrinfo/afamily_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/afamily_spec.rb
@@ -23,15 +23,13 @@ describe "Addrinfo#afamily" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
-
- it "returns Socket::AF_UNIX" do
- @addrinfo.afamily.should == Socket::AF_UNIX
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
+
+ it "returns Socket::AF_UNIX" do
+ @addrinfo.afamily.should == Socket::AF_UNIX
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/bind_spec.rb b/spec/ruby/library/socket/addrinfo/bind_spec.rb
index 6f78890a4d..cdd187771f 100644
--- a/spec/ruby/library/socket/addrinfo/bind_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/bind_spec.rb
@@ -13,16 +13,16 @@ describe "Addrinfo#bind" do
it "returns a bound socket when no block is given" do
@socket = @addrinfo.bind
- @socket.should be_kind_of(Socket)
- @socket.closed?.should be_false
+ @socket.should.is_a?(Socket)
+ @socket.closed?.should == false
end
it "yields the socket if a block is given" do
@addrinfo.bind do |sock|
@socket = sock
- sock.should be_kind_of(Socket)
+ sock.should.is_a?(Socket)
end
- @socket.closed?.should be_true
+ @socket.closed?.should == true
end
end
diff --git a/spec/ruby/library/socket/addrinfo/canonname_spec.rb b/spec/ruby/library/socket/addrinfo/canonname_spec.rb
index a1cc8b3980..efd3147125 100644
--- a/spec/ruby/library/socket/addrinfo/canonname_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/canonname_spec.rb
@@ -10,7 +10,7 @@ describe "Addrinfo#canonname" do
it "returns the canonical name for a host" do
canonname = @addrinfos.map { |a| a.canonname }.find { |name| name and name.include?("localhost") }
if canonname
- canonname.should include("localhost")
+ canonname.should.include?("localhost")
else
canonname.should == nil
end
@@ -20,7 +20,7 @@ describe "Addrinfo#canonname" do
it 'returns nil' do
addr = Addrinfo.new(Socket.sockaddr_in(0, '127.0.0.1'))
- addr.canonname.should be_nil
+ addr.canonname.should == nil
end
end
diff --git a/spec/ruby/library/socket/addrinfo/connect_from_spec.rb b/spec/ruby/library/socket/addrinfo/connect_from_spec.rb
index 55fce2e159..b1f6caa174 100644
--- a/spec/ruby/library/socket/addrinfo/connect_from_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/connect_from_spec.rb
@@ -17,18 +17,18 @@ describe 'Addrinfo#connect_from' do
describe 'using separate arguments' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_from(ip_address, 0)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_from(ip_address, 0) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_from(ip_address, 0, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the socket to the local address' do
@@ -48,18 +48,18 @@ describe 'Addrinfo#connect_from' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_from(@from_addr)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_from(@from_addr) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_from(@from_addr, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the socket to the local address' do
diff --git a/spec/ruby/library/socket/addrinfo/connect_spec.rb b/spec/ruby/library/socket/addrinfo/connect_spec.rb
index 1c2dc609ca..a8494b5501 100644
--- a/spec/ruby/library/socket/addrinfo/connect_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/connect_spec.rb
@@ -16,20 +16,20 @@ describe 'Addrinfo#connect' do
it 'returns a Socket when no block is given' do
addr = Addrinfo.tcp(ip_address, @port)
@socket = addr.connect
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields a Socket when a block is given' do
addr = Addrinfo.tcp(ip_address, @port)
addr.connect do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'accepts a Hash of options' do
addr = Addrinfo.tcp(ip_address, @port)
@socket = addr.connect(timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/connect_to_spec.rb b/spec/ruby/library/socket/addrinfo/connect_to_spec.rb
index 69666da19b..2bf49a38e8 100644
--- a/spec/ruby/library/socket/addrinfo/connect_to_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/connect_to_spec.rb
@@ -17,18 +17,18 @@ describe 'Addrinfo#connect_to' do
describe 'using separate arguments' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_to(ip_address, @port)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_to(ip_address, @port) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_to(ip_address, @port, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the Addrinfo to the local address' do
@@ -48,18 +48,18 @@ describe 'Addrinfo#connect_to' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_to(@to_addr)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_to(@to_addr) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_to(@to_addr, timeout: 2)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'binds the socket to the local address' do
diff --git a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb
index 2bc3b6a2e3..38834ade91 100644
--- a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb
@@ -4,7 +4,7 @@ describe 'Addrinfo#family_addrinfo' do
it 'raises ArgumentError if no arguments are given' do
addr = Addrinfo.tcp('127.0.0.1', 0)
- -> { addr.family_addrinfo }.should raise_error(ArgumentError)
+ -> { addr.family_addrinfo }.should.raise(ArgumentError)
end
describe 'using multiple arguments' do
@@ -14,17 +14,17 @@ describe 'Addrinfo#family_addrinfo' do
end
it 'raises ArgumentError if only 1 argument is given' do
- -> { @source.family_addrinfo('127.0.0.1') }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo('127.0.0.1') }.should.raise(ArgumentError)
end
it 'raises ArgumentError if more than 2 arguments are given' do
- -> { @source.family_addrinfo('127.0.0.1', 0, 666) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo('127.0.0.1', 0, 666) }.should.raise(ArgumentError)
end
it 'returns an Addrinfo when a host and port are given' do
addr = @source.family_addrinfo('127.0.0.1', 0)
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
@@ -50,38 +50,36 @@ describe 'Addrinfo#family_addrinfo' do
end
end
- with_feature :unix_socket do
- describe 'with a UNIX Addrinfo' do
- before do
- @source = Addrinfo.unix('cats')
- end
+ describe 'with a UNIX Addrinfo' do
+ before do
+ @source = Addrinfo.unix('cats')
+ end
- it 'raises ArgumentError if more than 1 argument is given' do
- -> { @source.family_addrinfo('foo', 'bar') }.should raise_error(ArgumentError)
- end
+ it 'raises ArgumentError if more than 1 argument is given' do
+ -> { @source.family_addrinfo('foo', 'bar') }.should.raise(ArgumentError)
+ end
- it 'returns an Addrinfo when a UNIX socket path is given' do
- addr = @source.family_addrinfo('dogs')
+ it 'returns an Addrinfo when a UNIX socket path is given' do
+ addr = @source.family_addrinfo('dogs')
- addr.should be_an_instance_of(Addrinfo)
- end
+ addr.should.instance_of?(Addrinfo)
+ end
- describe 'the returned Addrinfo' do
- before do
- @addr = @source.family_addrinfo('dogs')
- end
+ describe 'the returned Addrinfo' do
+ before do
+ @addr = @source.family_addrinfo('dogs')
+ end
- it 'uses AF_UNIX as the address family' do
- @addr.afamily.should == Socket::AF_UNIX
- end
+ it 'uses AF_UNIX as the address family' do
+ @addr.afamily.should == Socket::AF_UNIX
+ end
- it 'uses PF_UNIX as the protocol family' do
- @addr.pfamily.should == Socket::PF_UNIX
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @addr.pfamily.should == Socket::PF_UNIX
+ end
- it 'uses the given socket path' do
- @addr.unix_path.should == 'dogs'
- end
+ it 'uses the given socket path' do
+ @addr.unix_path.should == 'dogs'
end
end
end
@@ -99,17 +97,17 @@ describe 'Addrinfo#family_addrinfo' do
it 'raises ArgumentError if more than 1 argument is given' do
input = Addrinfo.tcp('127.0.0.2', 0)
- -> { @source.family_addrinfo(input, 666) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo(input, 666) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the protocol families don't match" do
input = Addrinfo.tcp('::1', 0)
- -> { @source.family_addrinfo(input) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo(input) }.should.raise(ArgumentError)
end
it "raises ArgumentError if the socket types don't match" do
input = Addrinfo.udp('127.0.0.1', 0)
- -> { @source.family_addrinfo(input) }.should raise_error(ArgumentError)
+ -> { @source.family_addrinfo(input) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/foreach_spec.rb b/spec/ruby/library/socket/addrinfo/foreach_spec.rb
index 6ec8fab905..8cbbddb8f0 100644
--- a/spec/ruby/library/socket/addrinfo/foreach_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/foreach_spec.rb
@@ -3,7 +3,7 @@ require_relative '../spec_helper'
describe 'Addrinfo.foreach' do
it 'yields Addrinfo instances to the supplied block' do
Addrinfo.foreach('127.0.0.1', 80) do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb
index 67fad73815..47393ee167 100644
--- a/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb
@@ -5,8 +5,8 @@ describe 'Addrinfo.getaddrinfo' do
it 'returns an Array of Addrinfo instances' do
array = Addrinfo.getaddrinfo('127.0.0.1', 80)
- array.should be_an_instance_of(Array)
- array[0].should be_an_instance_of(Addrinfo)
+ array.should.instance_of?(Array)
+ array[0].should.instance_of?(Addrinfo)
end
SocketSpecs.each_ip_protocol do |family, ip_address|
@@ -54,7 +54,7 @@ describe 'Addrinfo.getaddrinfo' do
array = Addrinfo.getaddrinfo('127.0.0.1', 80)
possible = [Socket::SOCK_STREAM, Socket::SOCK_DGRAM]
- possible.should include(array[0].socktype)
+ possible.should.include?(array[0].socktype)
end
end
@@ -69,23 +69,19 @@ describe 'Addrinfo.getaddrinfo' do
array = Addrinfo.getaddrinfo('127.0.0.1', 80)
possible = [Socket::IPPROTO_TCP, Socket::IPPROTO_UDP]
- possible.should include(array[0].protocol)
+ possible.should.include?(array[0].protocol)
end
end
- platform_is_not :'solaris2.10' do # i386-solaris
- it 'sets a custom socket protocol of the Addrinfo instances' do
- array = Addrinfo.getaddrinfo('127.0.0.1', 80, nil, nil, Socket::IPPROTO_UDP)
+ it 'sets a custom socket protocol of the Addrinfo instances' do
+ array = Addrinfo.getaddrinfo('127.0.0.1', 80, nil, nil, Socket::IPPROTO_UDP)
- array[0].protocol.should == Socket::IPPROTO_UDP
- end
+ array[0].protocol.should == Socket::IPPROTO_UDP
end
- platform_is_not :solaris do
- it 'sets the canonical name when AI_CANONNAME is given as a flag' do
- array = Addrinfo.getaddrinfo('localhost', 80, nil, nil, nil, Socket::AI_CANONNAME)
+ it 'sets the canonical name when AI_CANONNAME is given as a flag' do
+ array = Addrinfo.getaddrinfo('localhost', 80, nil, nil, nil, Socket::AI_CANONNAME)
- array[0].canonname.should be_an_instance_of(String)
- end
+ array[0].canonname.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb
index 76579de74c..43b5a2000a 100644
--- a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb
@@ -22,19 +22,17 @@ describe 'Addrinfo#getnameinfo' do
platform_is :linux do
platform_is_not :android do
- with_feature :unix_socket do
- describe 'using a UNIX Addrinfo' do
- before do
- @addr = Addrinfo.unix('cats')
- @host = Socket.gethostname
- end
+ describe 'using a UNIX Addrinfo' do
+ before do
+ @addr = Addrinfo.unix('cats')
+ @host = Socket.gethostname
+ end
- it 'returns the hostname and UNIX socket path' do
- host, path = @addr.getnameinfo
+ it 'returns the hostname and UNIX socket path' do
+ host, path = @addr.getnameinfo
- host.should == @host
- path.should == 'cats'
- end
+ host.should == @host
+ path.should == 'cats'
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
index d8885c5d62..f33255e38b 100644
--- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
@@ -17,7 +17,7 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the UNSPEC pfamily" do
@addrinfo.pfamily.should == Socket::PF_UNSPEC
end
@@ -53,11 +53,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -83,11 +83,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -113,11 +113,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 25
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -147,11 +147,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::PF_INET pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -200,7 +200,7 @@ describe "Addrinfo#initialize" do
it 'raises SocketError' do
block = -> { Addrinfo.new(['AF_INET6', 80, 'hostname', '127.0.0.1']) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
@@ -217,11 +217,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -247,11 +247,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -294,7 +294,7 @@ describe "Addrinfo#initialize" do
value = Socket::SOCK_RDM
block = -> { Addrinfo.new(sockaddr, nil, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
@@ -311,11 +311,11 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102
end
- it "returns the Socket::UNSPEC pfamily" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET6 afamily" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -340,7 +340,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(constant)
-> {
Addrinfo.new(@sockaddr, value)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
end
@@ -362,13 +362,13 @@ describe "Addrinfo#initialize" do
end
end
- platform_is_not :windows, :aix, :solaris do
+ platform_is_not :windows, :aix do
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, nil, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -390,13 +390,13 @@ describe "Addrinfo#initialize" do
end
end
- platform_is_not :windows, :aix, :solaris do
+ platform_is_not :windows, :aix do
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -413,7 +413,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -444,7 +444,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -472,7 +472,7 @@ describe "Addrinfo#initialize" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -495,13 +495,13 @@ describe "Addrinfo#initialize" do
end
end
- platform_is_not :windows, :aix, :solaris do
+ platform_is_not :windows, :aix do
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = -> { Addrinfo.new(@sockaddr, nil, @socktype, value) }
- block.should raise_error(SocketError)
+ block.should.raise(SocketError)
end
end
end
@@ -514,13 +514,13 @@ describe "Addrinfo#initialize" do
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with :PF_INET family' do
+ it 'returns an Addrinfo with the specified pfamily for :PF_INET' do
addr = Addrinfo.new(@sockaddr, :PF_INET)
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with :INET family' do
+ it 'returns an Addrinfo with the specified pfamily for :INET' do
addr = Addrinfo.new(@sockaddr, :INET)
addr.pfamily.should == Socket::PF_INET
@@ -544,13 +544,13 @@ describe "Addrinfo#initialize" do
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with "PF_INET" family' do
+ it 'returns an Addrinfo with the specified pfamily for PF_INET' do
addr = Addrinfo.new(@sockaddr, 'PF_INET')
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with "INET" family' do
+ it 'returns an Addrinfo with the specified pfamily for INET' do
addr = Addrinfo.new(@sockaddr, 'INET')
addr.pfamily.should == Socket::PF_INET
@@ -569,23 +569,21 @@ describe "Addrinfo#initialize" do
end
end
- with_feature :unix_socket do
- describe 'using separate arguments for a Unix socket' do
- before do
- @sockaddr = Socket.pack_sockaddr_un('socket')
- end
+ describe 'using separate arguments for a Unix socket' do
+ before do
+ @sockaddr = Socket.pack_sockaddr_un('socket')
+ end
- it 'returns an Addrinfo with the correct unix path' do
- Addrinfo.new(@sockaddr).unix_path.should == 'socket'
- end
+ it 'returns an Addrinfo with the correct unix path' do
+ Addrinfo.new(@sockaddr).unix_path.should == 'socket'
+ end
- it 'returns an Addrinfo with the correct protocol family' do
- Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC
- end
+ it 'returns an Addrinfo with the correct protocol family' do
+ Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC
+ end
- it 'returns an Addrinfo with the correct address family' do
- Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX
- end
+ it 'returns an Addrinfo with the correct address family' do
+ Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb
index 70ca4dd4d7..6b18c79469 100644
--- a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb
@@ -32,19 +32,17 @@ describe 'Addrinfo#inspect_sockaddr' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX path' do
- it 'returns a String containing the UNIX path' do
- addr = Addrinfo.unix('/foo/bar')
+ describe 'using a UNIX path' do
+ it 'returns a String containing the UNIX path' do
+ addr = Addrinfo.unix('/foo/bar')
- addr.inspect_sockaddr.should == '/foo/bar'
- end
+ addr.inspect_sockaddr.should == '/foo/bar'
+ end
- it 'returns a String containing the UNIX path when using a relative path' do
- addr = Addrinfo.unix('foo')
+ it 'returns a String containing the UNIX path when using a relative path' do
+ addr = Addrinfo.unix('foo')
- addr.inspect_sockaddr.should == 'UNIX foo'
- end
+ addr.inspect_sockaddr.should == 'UNIX foo'
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/inspect_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_spec.rb
index 98e1e83ffa..1442af6162 100644
--- a/spec/ruby/library/socket/addrinfo/inspect_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/inspect_spec.rb
@@ -41,25 +41,23 @@ describe 'Addrinfo#inspect' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX Addrinfo' do
- it 'returns a String' do
- addr = Addrinfo.unix('/foo')
+ describe 'using a UNIX Addrinfo' do
+ it 'returns a String' do
+ addr = Addrinfo.unix('/foo')
- addr.inspect.should == '#<Addrinfo: /foo SOCK_STREAM>'
- end
+ addr.inspect.should == '#<Addrinfo: /foo SOCK_STREAM>'
+ end
- it 'returns a String when using a relative UNIX path' do
- addr = Addrinfo.unix('foo')
+ it 'returns a String when using a relative UNIX path' do
+ addr = Addrinfo.unix('foo')
- addr.inspect.should == '#<Addrinfo: UNIX foo SOCK_STREAM>'
- end
+ addr.inspect.should == '#<Addrinfo: UNIX foo SOCK_STREAM>'
+ end
- it 'returns a String when using a DGRAM socket' do
- addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM)
+ it 'returns a String when using a DGRAM socket' do
+ addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM)
- addr.inspect.should == '#<Addrinfo: /foo SOCK_DGRAM>'
- end
+ addr.inspect.should == '#<Addrinfo: /foo SOCK_DGRAM>'
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb
index 4522cf5cfd..9a0ede4eeb 100644
--- a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb
@@ -21,15 +21,13 @@ describe "Addrinfo#ip_address" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "raises an exception" do
- -> { @addrinfo.ip_address }.should raise_error(SocketError)
- end
+ it "raises an exception" do
+ -> { @addrinfo.ip_address }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb
index 4118607db0..00f74cdd46 100644
--- a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb
@@ -21,15 +21,13 @@ describe "Addrinfo#ip_port" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "raises an exception" do
- -> { @addrinfo.ip_port }.should raise_error(SocketError)
- end
+ it "raises an exception" do
+ -> { @addrinfo.ip_port }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ip_spec.rb b/spec/ruby/library/socket/addrinfo/ip_spec.rb
index 80e7a62df7..2237eca263 100644
--- a/spec/ruby/library/socket/addrinfo/ip_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_spec.rb
@@ -8,7 +8,7 @@ describe "Addrinfo#ip?" do
end
it "returns true" do
- @addrinfo.ip?.should be_true
+ @addrinfo.ip?.should == true
end
end
@@ -18,19 +18,17 @@ describe "Addrinfo#ip?" do
end
it "returns true" do
- @addrinfo.ip?.should be_true
+ @addrinfo.ip?.should == true
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ip?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ip?.should == false
end
end
end
@@ -38,7 +36,7 @@ end
describe 'Addrinfo.ip' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
- Addrinfo.ip(ip_address).should be_an_instance_of(Addrinfo)
+ Addrinfo.ip(ip_address).should.instance_of?(Addrinfo)
end
it 'sets the IP address' do
diff --git a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb
index 6c81c48d1c..b48ca062ee 100644
--- a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb
@@ -21,15 +21,13 @@ describe "Addrinfo#ip_unpack" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "raises an exception" do
- -> { @addrinfo.ip_unpack }.should raise_error(SocketError)
- end
+ it "raises an exception" do
+ -> { @addrinfo.ip_unpack }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb
index 10ad084fc9..266281ce7a 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb
@@ -10,7 +10,7 @@ describe "Addrinfo#ipv4_loopback?" do
end
it "returns false for another address" do
- Addrinfo.ip('255.255.255.0').ipv4_loopback?.should be_false
+ Addrinfo.ip('255.255.255.0').ipv4_loopback?.should == false
end
end
@@ -21,23 +21,21 @@ describe "Addrinfo#ipv4_loopback?" do
end
it "returns false for the loopback address" do
- @loopback.ipv4_loopback?.should be_false
+ @loopback.ipv4_loopback?.should == false
end
it "returns false for another address" do
- @other.ipv4_loopback?.should be_false
+ @other.ipv4_loopback?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4_loopback?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4_loopback?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb
index f7fead8640..bc8a31dfa8 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb
@@ -15,15 +15,13 @@ describe "Addrinfo#ipv4_multicast?" do
Addrinfo.ip('::1').should_not.ipv4_multicast?
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4_multicast?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4_multicast?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb
index e5a33b4953..8cfbf0a25e 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb
@@ -19,7 +19,7 @@ describe "Addrinfo#ipv4_private?" do
end
it "returns false for a public address" do
- @other.ipv4_private?.should be_false
+ @other.ipv4_private?.should == false
end
end
@@ -29,19 +29,17 @@ describe "Addrinfo#ipv4_private?" do
end
it "returns false" do
- @other.ipv4_private?.should be_false
+ @other.ipv4_private?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4_private?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4_private?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb
index 7cba8209b6..8fef94a8e8 100644
--- a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb
@@ -7,7 +7,7 @@ describe "Addrinfo#ipv4?" do
end
it "returns true" do
- @addrinfo.ipv4?.should be_true
+ @addrinfo.ipv4?.should == true
end
end
@@ -17,19 +17,17 @@ describe "Addrinfo#ipv4?" do
end
it "returns false" do
- @addrinfo.ipv4?.should be_false
+ @addrinfo.ipv4?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv4?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv4?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb
index 9ff8f107bf..2e8241e336 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb
@@ -8,11 +8,11 @@ describe "Addrinfo#ipv6_loopback?" do
end
it "returns false for the loopback address" do
- @loopback.ipv6_loopback?.should be_false
+ @loopback.ipv6_loopback?.should == false
end
it "returns false for another address" do
- @other.ipv6_loopback?.should be_false
+ @other.ipv6_loopback?.should == false
end
end
@@ -23,23 +23,21 @@ describe "Addrinfo#ipv6_loopback?" do
end
it "returns true for the loopback address" do
- @loopback.ipv6_loopback?.should be_true
+ @loopback.ipv6_loopback?.should == true
end
it "returns false for another address" do
- @other.ipv6_loopback?.should be_false
+ @other.ipv6_loopback?.should == false
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv6_loopback?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv6_loopback?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb
index 2c987b5921..52787e5e53 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb
@@ -8,11 +8,11 @@ describe "Addrinfo#ipv6_multicast?" do
end
it "returns true for a multicast address" do
- @multicast.ipv6_multicast?.should be_false
+ @multicast.ipv6_multicast?.should == false
end
it "returns false for another address" do
- @other.ipv6_multicast?.should be_false
+ @other.ipv6_multicast?.should == false
end
end
@@ -34,15 +34,13 @@ describe "Addrinfo#ipv6_multicast?" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv6_multicast?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv6_multicast?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb
index 131e38849c..9fa8e9bd0c 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb
@@ -7,7 +7,7 @@ describe "Addrinfo#ipv6?" do
end
it "returns true" do
- @addrinfo.ipv6?.should be_false
+ @addrinfo.ipv6?.should == false
end
end
@@ -17,19 +17,17 @@ describe "Addrinfo#ipv6?" do
end
it "returns false" do
- @addrinfo.ipv6?.should be_true
+ @addrinfo.ipv6?.should == true
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns false" do
- @addrinfo.ipv6?.should be_false
- end
+ it "returns false" do
+ @addrinfo.ipv6?.should == false
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb
index 6dfaf531ae..d1436d4527 100644
--- a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb
@@ -6,7 +6,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::192.168.1.1' do
addr = Addrinfo.ip('::192.168.1.1').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '192.168.1.1'
@@ -16,7 +16,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::0.0.1.1' do
addr = Addrinfo.ip('::0.0.1.1').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.0.1.1'
@@ -25,7 +25,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::0.0.1.0' do
addr = Addrinfo.ip('::0.0.1.0').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.0.1.0'
@@ -34,7 +34,7 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::0.1.0.0' do
addr = Addrinfo.ip('::0.1.0.0').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.1.0.0'
@@ -44,27 +44,27 @@ guard -> { SocketSpecs.ipv6_available? } do
it 'returns an Addrinfo for ::ffff:192.168.1.1' do
addr = Addrinfo.ip('::ffff:192.168.1.1').ipv6_to_ipv4
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '192.168.1.1'
end
it 'returns nil for ::0.0.0.1' do
- Addrinfo.ip('::0.0.0.1').ipv6_to_ipv4.should be_nil
+ Addrinfo.ip('::0.0.0.1').ipv6_to_ipv4.should == nil
end
it 'returns nil for a pure IPv6 Addrinfo' do
- Addrinfo.ip('::1').ipv6_to_ipv4.should be_nil
+ Addrinfo.ip('::1').ipv6_to_ipv4.should == nil
end
it 'returns nil for an IPv4 Addrinfo' do
- Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should be_nil
+ Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should == nil
end
- with_feature :unix_socket do
+ describe 'for a unix socket' do
it 'returns nil for a UNIX Addrinfo' do
- Addrinfo.unix('foo').ipv6_to_ipv4.should be_nil
+ Addrinfo.unix('foo').ipv6_to_ipv4.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/listen_spec.rb b/spec/ruby/library/socket/addrinfo/listen_spec.rb
index 931093f732..80bcdc7f83 100644
--- a/spec/ruby/library/socket/addrinfo/listen_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/listen_spec.rb
@@ -13,12 +13,12 @@ describe 'Addrinfo#listen' do
it 'returns a Socket when no block is given' do
@socket = @addr.listen
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'yields the Socket if a block is given' do
@addr.listen do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
diff --git a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb
index c4220a6f3e..438b04a99c 100644
--- a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb
@@ -8,7 +8,7 @@ describe 'Addrinfo#marshal_dump' do
end
it 'returns an Array' do
- @addr.marshal_dump.should be_an_instance_of(Array)
+ @addr.marshal_dump.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -32,10 +32,8 @@ describe 'Addrinfo#marshal_dump' do
@array[3].should == 'SOCK_STREAM'
end
- platform_is_not :'solaris2.10' do # i386-solaris
- it 'includes the protocol as the 5th value' do
- @array[4].should == 'IPPROTO_TCP'
- end
+ it 'includes the protocol as the 5th value' do
+ @array[4].should == 'IPPROTO_TCP'
end
it 'includes the canonical name as the 6th value' do
@@ -44,40 +42,38 @@ describe 'Addrinfo#marshal_dump' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX Addrinfo' do
+ describe 'using a UNIX Addrinfo' do
+ before do
+ @addr = Addrinfo.unix('foo')
+ end
+
+ it 'returns an Array' do
+ @addr.marshal_dump.should.instance_of?(Array)
+ end
+
+ describe 'the returned Array' do
before do
- @addr = Addrinfo.unix('foo')
+ @array = @addr.marshal_dump
end
- it 'returns an Array' do
- @addr.marshal_dump.should be_an_instance_of(Array)
+ it 'includes the address family as the 1st value' do
+ @array[0].should == 'AF_UNIX'
end
- describe 'the returned Array' do
- before do
- @array = @addr.marshal_dump
- end
-
- it 'includes the address family as the 1st value' do
- @array[0].should == 'AF_UNIX'
- end
-
- it 'includes the UNIX path as the 2nd value' do
- @array[1].should == @addr.unix_path
- end
+ it 'includes the UNIX path as the 2nd value' do
+ @array[1].should == @addr.unix_path
+ end
- it 'includes the protocol family as the 3rd value' do
- @array[2].should == 'PF_UNIX'
- end
+ it 'includes the protocol family as the 3rd value' do
+ @array[2].should == 'PF_UNIX'
+ end
- it 'includes the socket type as the 4th value' do
- @array[3].should == 'SOCK_STREAM'
- end
+ it 'includes the socket type as the 4th value' do
+ @array[3].should == 'SOCK_STREAM'
+ end
- it 'includes the protocol as the 5th value' do
- @array[4].should == 0
- end
+ it 'includes the protocol as the 5th value' do
+ @array[4].should == 0
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb
index aa20865224..02cef90115 100644
--- a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb
@@ -18,18 +18,16 @@ describe 'Addrinfo#marshal_load' do
end
end
- with_feature :unix_socket do
- describe 'using a UNIX socket' do
- it 'returns a new Addrinfo' do
- source = Addrinfo.unix('foo')
- addr = Marshal.load(Marshal.dump(source))
+ describe 'using a UNIX socket' do
+ it 'returns a new Addrinfo' do
+ source = Addrinfo.unix('foo')
+ addr = Marshal.load(Marshal.dump(source))
- addr.afamily.should == source.afamily
- addr.pfamily.should == source.pfamily
- addr.socktype.should == source.socktype
- addr.protocol.should == source.protocol
- addr.unix_path.should == source.unix_path
- end
+ addr.afamily.should == source.afamily
+ addr.pfamily.should == source.pfamily
+ addr.socktype.should == source.socktype
+ addr.protocol.should == source.protocol
+ addr.unix_path.should == source.unix_path
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb
index 984744a964..da530b7fdc 100644
--- a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb
@@ -29,15 +29,13 @@ describe "Addrinfo#pfamily" do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
-
- it "returns Socket::PF_UNIX" do
- @addrinfo.pfamily.should == Socket::PF_UNIX
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
+
+ it "returns Socket::PF_UNIX" do
+ @addrinfo.pfamily.should == Socket::PF_UNIX
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/protocol_spec.rb b/spec/ruby/library/socket/addrinfo/protocol_spec.rb
index ea143fc4a8..f6ffc9acf9 100644
--- a/spec/ruby/library/socket/addrinfo/protocol_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/protocol_spec.rb
@@ -10,15 +10,13 @@ describe "Addrinfo#protocol" do
Addrinfo.tcp('::1', 80).protocol.should == Socket::IPPROTO_TCP
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns 0" do
- @addrinfo.protocol.should == 0
- end
+ it "returns 0" do
+ @addrinfo.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
index 4f7cf439a0..70d6bfbbfe 100644
--- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
+++ b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
@@ -19,15 +19,13 @@ describe :socket_addrinfo_to_sockaddr, shared: true do
end
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
-
- it "returns a sockaddr packed structure" do
- @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock')
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
+
+ it "returns a sockaddr packed structure" do
+ @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock')
end
end
diff --git a/spec/ruby/library/socket/addrinfo/socktype_spec.rb b/spec/ruby/library/socket/addrinfo/socktype_spec.rb
index b994bea140..e5f02cd759 100644
--- a/spec/ruby/library/socket/addrinfo/socktype_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/socktype_spec.rb
@@ -9,15 +9,13 @@ describe "Addrinfo#socktype" do
Addrinfo.tcp('127.0.0.1', 80).socktype.should == Socket::SOCK_STREAM
end
- with_feature :unix_socket do
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns Socket::SOCK_STREAM" do
- @addrinfo.socktype.should == Socket::SOCK_STREAM
- end
+ it "returns Socket::SOCK_STREAM" do
+ @addrinfo.socktype.should == Socket::SOCK_STREAM
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/tcp_spec.rb b/spec/ruby/library/socket/addrinfo/tcp_spec.rb
index c74c9c21c2..0669de16a6 100644
--- a/spec/ruby/library/socket/addrinfo/tcp_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/tcp_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe 'Addrinfo.tcp' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
- Addrinfo.tcp(ip_address, 80).should be_an_instance_of(Addrinfo)
+ Addrinfo.tcp(ip_address, 80).should.instance_of?(Addrinfo)
end
it 'sets the IP address' do
diff --git a/spec/ruby/library/socket/addrinfo/udp_spec.rb b/spec/ruby/library/socket/addrinfo/udp_spec.rb
index b05cbf9b0b..51d7f5588e 100644
--- a/spec/ruby/library/socket/addrinfo/udp_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/udp_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe 'Addrinfo.udp' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
- Addrinfo.udp(ip_address, 80).should be_an_instance_of(Addrinfo)
+ Addrinfo.udp(ip_address, 80).should.instance_of?(Addrinfo)
end
it 'sets the IP address' do
@@ -27,10 +27,8 @@ describe 'Addrinfo.udp' do
Addrinfo.udp(ip_address, 80).socktype.should == Socket::SOCK_DGRAM
end
- platform_is_not :solaris do
- it 'sets the socket protocol' do
- Addrinfo.udp(ip_address, 80).protocol.should == Socket::IPPROTO_UDP
- end
+ it 'sets the socket protocol' do
+ Addrinfo.udp(ip_address, 80).protocol.should == Socket::IPPROTO_UDP
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb
index 6bfb56a4ac..c15075bce3 100644
--- a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb
@@ -1,37 +1,35 @@
require_relative '../spec_helper'
-with_feature :unix_socket do
- describe "Addrinfo#unix_path" do
- describe "for an ipv4 socket" do
+describe "Addrinfo#unix_path" do
+ describe "for an ipv4 socket" do
- before :each do
- @addrinfo = Addrinfo.tcp("127.0.0.1", 80)
- end
-
- it "raises an exception" do
- -> { @addrinfo.unix_path }.should raise_error(SocketError)
- end
+ before :each do
+ @addrinfo = Addrinfo.tcp("127.0.0.1", 80)
+ end
+ it "raises an exception" do
+ -> { @addrinfo.unix_path }.should.raise(SocketError)
end
- describe "for an ipv6 socket" do
- before :each do
- @addrinfo = Addrinfo.tcp("::1", 80)
- end
+ end
- it "raises an exception" do
- -> { @addrinfo.unix_path }.should raise_error(SocketError)
- end
+ describe "for an ipv6 socket" do
+ before :each do
+ @addrinfo = Addrinfo.tcp("::1", 80)
end
- describe "for a unix socket" do
- before :each do
- @addrinfo = Addrinfo.unix("/tmp/sock")
- end
+ it "raises an exception" do
+ -> { @addrinfo.unix_path }.should.raise(SocketError)
+ end
+ end
+
+ describe "for a unix socket" do
+ before :each do
+ @addrinfo = Addrinfo.unix("/tmp/sock")
+ end
- it "returns the socket path" do
- @addrinfo.unix_path.should == "/tmp/sock"
- end
+ it "returns the socket path" do
+ @addrinfo.unix_path.should == "/tmp/sock"
end
end
end
diff --git a/spec/ruby/library/socket/addrinfo/unix_spec.rb b/spec/ruby/library/socket/addrinfo/unix_spec.rb
index 4596ece17e..da65e13efb 100644
--- a/spec/ruby/library/socket/addrinfo/unix_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/unix_spec.rb
@@ -1,36 +1,34 @@
require_relative '../spec_helper'
-with_feature :unix_socket do
- describe 'Addrinfo.unix' do
- it 'returns an Addrinfo instance' do
- Addrinfo.unix('socket').should be_an_instance_of(Addrinfo)
- end
+describe 'Addrinfo.unix' do
+ it 'returns an Addrinfo instance' do
+ Addrinfo.unix('socket').should.instance_of?(Addrinfo)
+ end
- it 'sets the IP address' do
- Addrinfo.unix('socket').unix_path.should == 'socket'
- end
+ it 'sets the IP address' do
+ Addrinfo.unix('socket').unix_path.should == 'socket'
+ end
- it 'sets the address family' do
- Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX
- end
+ it 'sets the address family' do
+ Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX
+ end
- it 'sets the protocol family' do
- Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX
- end
+ it 'sets the protocol family' do
+ Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX
+ end
- it 'sets the socket type' do
- Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM
- end
+ it 'sets the socket type' do
+ Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM
+ end
- it 'sets a custom socket type' do
- addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM)
+ it 'sets a custom socket type' do
+ addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM)
- addr.socktype.should == Socket::SOCK_DGRAM
- end
+ addr.socktype.should == Socket::SOCK_DGRAM
+ end
- it 'sets the socket protocol to 0' do
- Addrinfo.unix('socket').protocol.should == 0
- end
+ it 'sets the socket protocol to 0' do
+ Addrinfo.unix('socket').protocol.should == 0
end
end
@@ -42,7 +40,7 @@ describe "Addrinfo#unix?" do
end
it "returns false" do
- @addrinfo.unix?.should be_false
+ @addrinfo.unix?.should == false
end
end
@@ -53,7 +51,7 @@ describe "Addrinfo#unix?" do
end
it "returns false" do
- @addrinfo.unix?.should be_false
+ @addrinfo.unix?.should == false
end
end
@@ -64,7 +62,7 @@ describe "Addrinfo#unix?" do
end
it "returns true" do
- @addrinfo.unix?.should be_true
+ @addrinfo.unix?.should == true
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb b/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb
index c54ee29825..c77f3bdbae 100644
--- a/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb
@@ -26,7 +26,7 @@ with_feature :ancillary_data do
end
it 'raises SocketError when comparing with :IPV6 and :RIGHTS' do
- -> { @data.cmsg_is?(:IPV6, :RIGHTS) }.should raise_error(SocketError)
+ -> { @data.cmsg_is?(:IPV6, :RIGHTS) }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/initialize_spec.rb b/spec/ruby/library/socket/ancillarydata/initialize_spec.rb
index 344d1485c5..60f5ac7a90 100644
--- a/spec/ruby/library/socket/ancillarydata/initialize_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/initialize_spec.rb
@@ -106,7 +106,7 @@ with_feature :ancillary_data do
Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS
end
- platform_is_not :"solaris2.10", :aix do
+ platform_is_not :aix do
it 'sets the type to SCM_TIMESTAMP when using :TIMESTAMP as the type argument' do
Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '').type.should == Socket::SCM_TIMESTAMP
end
@@ -115,25 +115,25 @@ with_feature :ancillary_data do
it 'raises TypeError when using a numeric string as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IGMP, Socket::SCM_RIGHTS.to_s, '')
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it 'raises SocketError when using :RECVTTL as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :SOCKET, :RECVTTL, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :SOCKET, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :IP_RECVTTL as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :SOCKET, :IP_RECVTTL, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -157,13 +157,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IP, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IP, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -181,13 +181,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IPV6, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :IPV6, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -207,13 +207,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :TCP, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :TCP, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -227,13 +227,13 @@ with_feature :ancillary_data do
it 'raises SocketError when using :RIGHTS as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :UDP, :RIGHTS, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
-> {
Socket::AncillaryData.new(:INET, :UDP, :MOO, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -245,7 +245,7 @@ with_feature :ancillary_data do
it 'raises SocketError when using :CORK sa the type argument' do
-> {
Socket::AncillaryData.new(:UNIX, :SOCKET, :CORK, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -253,7 +253,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :IP, :RECVTTL, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -261,7 +261,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :IPV6, :NEXTHOP, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -269,7 +269,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :TCP, :CORK, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -277,7 +277,7 @@ with_feature :ancillary_data do
it 'raises SocketError' do
-> {
Socket::AncillaryData.new(:UNIX, :UDP, :CORK, '')
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/int_spec.rb b/spec/ruby/library/socket/ancillarydata/int_spec.rb
index fe41a30a1a..10c5dea436 100644
--- a/spec/ruby/library/socket/ancillarydata/int_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/int_spec.rb
@@ -7,7 +7,7 @@ with_feature :ancillary_data do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -37,7 +37,7 @@ with_feature :ancillary_data do
it 'raises when the data is not an Integer' do
data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, 'ugh')
- -> { data.int }.should raise_error(TypeError)
+ -> { data.int }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb b/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb
index 84910a038a..065bcf1f39 100644
--- a/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb
@@ -8,7 +8,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -32,7 +32,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -58,7 +58,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'returns an Array' do
- @data.ip_pktinfo.should be_an_instance_of(Array)
+ @data.ip_pktinfo.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -67,15 +67,15 @@ with_feature :ancillary_data, :pktinfo do
end
it 'stores an Addrinfo at index 0' do
- @info[0].should be_an_instance_of(Addrinfo)
+ @info[0].should.instance_of?(Addrinfo)
end
it 'stores the ifindex at index 1' do
- @info[1].should be_kind_of(Integer)
+ @info[1].should.is_a?(Integer)
end
it 'stores an Addrinfo at index 2' do
- @info[2].should be_an_instance_of(Addrinfo)
+ @info[2].should.instance_of?(Addrinfo)
end
end
@@ -89,7 +89,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'is not the same object as the input Addrinfo' do
- @addr.should_not equal @source
+ @addr.should_not.equal? @source
end
end
@@ -109,7 +109,7 @@ with_feature :ancillary_data, :pktinfo do
end
it 'is not the same object as the input Addrinfo' do
- @addr.should_not equal @dest
+ @addr.should_not.equal? @dest
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb
index f70fe27d6a..7c630218d1 100644
--- a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb
@@ -5,7 +5,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
it 'returns an Addrinfo' do
data = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip('::1'), 4)
- data.ipv6_pktinfo_addr.should be_an_instance_of(Addrinfo)
+ data.ipv6_pktinfo_addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb
index 0fffc720dc..b5b779c36e 100644
--- a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb
@@ -7,7 +7,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'returns a Socket::AncillaryData' do
- @data.should be_an_instance_of(Socket::AncillaryData)
+ @data.should.instance_of?(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@@ -31,7 +31,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'returns an Array' do
- @data.ipv6_pktinfo.should be_an_instance_of(Array)
+ @data.ipv6_pktinfo.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -40,11 +40,11 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'stores an Addrinfo at index 0' do
- @info[0].should be_an_instance_of(Addrinfo)
+ @info[0].should.instance_of?(Addrinfo)
end
it 'stores the ifindex at index 1' do
- @info[1].should be_kind_of(Integer)
+ @info[1].should.is_a?(Integer)
end
end
@@ -58,7 +58,7 @@ with_feature :ancillary_data, :ipv6_pktinfo do
end
it 'is not the same object as the input Addrinfo' do
- @addr.should_not equal @source
+ @addr.should_not.equal? @source
end
end
diff --git a/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb b/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb
index 65ffcb01af..6dd144ba5a 100644
--- a/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb
+++ b/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb
@@ -26,7 +26,7 @@ with_feature :ancillary_data do
describe 'using non IO objects' do
it 'raises TypeError' do
- -> { Socket::AncillaryData.unix_rights(10) }.should raise_error(TypeError)
+ -> { Socket::AncillaryData.unix_rights(10) }.should.raise(TypeError)
end
end
end
@@ -41,20 +41,20 @@ with_feature :ancillary_data do
it 'returns nil when the data is not a list of file descriptors' do
data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, '')
- data.unix_rights.should be_nil
+ data.unix_rights.should == nil
end
it 'raises TypeError when the level is not SOL_SOCKET' do
data = Socket::AncillaryData.new(:INET, :IP, :RECVTTL, '')
- -> { data.unix_rights }.should raise_error(TypeError)
+ -> { data.unix_rights }.should.raise(TypeError)
end
- platform_is_not :"solaris2.10", :aix do
+ platform_is_not :aix do
it 'raises TypeError when the type is not SCM_RIGHTS' do
data = Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '')
- -> { data.unix_rights }.should raise_error(TypeError)
+ -> { data.unix_rights }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/close_read_spec.rb b/spec/ruby/library/socket/basicsocket/close_read_spec.rb
index f317b34955..35bec203d7 100644
--- a/spec/ruby/library/socket/basicsocket/close_read_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/close_read_spec.rb
@@ -12,32 +12,32 @@ describe "Socket::BasicSocket#close_read" do
it "closes the reading end of the socket" do
@server.close_read
- -> { @server.read }.should raise_error(IOError)
+ -> { @server.read }.should.raise(IOError)
end
it 'does not raise when called on a socket already closed for reading' do
@server.close_read
@server.close_read
- -> { @server.read }.should raise_error(IOError)
+ -> { @server.read }.should.raise(IOError)
end
it 'does not fully close the socket' do
@server.close_read
- @server.closed?.should be_false
+ @server.closed?.should == false
end
it "fully closes the socket if it was already closed for writing" do
@server.close_write
@server.close_read
- @server.closed?.should be_true
+ @server.closed?.should == true
end
it 'raises IOError when called on a fully closed socket' do
@server.close
- -> { @server.close_read }.should raise_error(IOError)
+ -> { @server.close_read }.should.raise(IOError)
end
it "returns nil" do
- @server.close_read.should be_nil
+ @server.close_read.should == nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/close_write_spec.rb b/spec/ruby/library/socket/basicsocket/close_write_spec.rb
index 232cfbb7c6..c1b6d9e9ef 100644
--- a/spec/ruby/library/socket/basicsocket/close_write_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/close_write_spec.rb
@@ -12,18 +12,18 @@ describe "Socket::BasicSocket#close_write" do
it "closes the writing end of the socket" do
@server.close_write
- -> { @server.write("foo") }.should raise_error(IOError)
+ -> { @server.write("foo") }.should.raise(IOError)
end
it 'does not raise when called on a socket already closed for writing' do
@server.close_write
@server.close_write
- -> { @server.write("foo") }.should raise_error(IOError)
+ -> { @server.write("foo") }.should.raise(IOError)
end
it 'does not fully close the socket' do
@server.close_write
- @server.closed?.should be_false
+ @server.closed?.should == false
end
it "does not prevent reading" do
@@ -34,15 +34,15 @@ describe "Socket::BasicSocket#close_write" do
it "fully closes the socket if it was already closed for reading" do
@server.close_read
@server.close_write
- @server.closed?.should be_true
+ @server.closed?.should == true
end
it 'raises IOError when called on a fully closed socket' do
@server.close
- -> { @server.close_write }.should raise_error(IOError)
+ -> { @server.close_write }.should.raise(IOError)
end
it "returns nil" do
- @server.close_write.should be_nil
+ @server.close_write.should == nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb
index 1a1c9982d9..e330b6e1be 100644
--- a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket#connect_address' do
it 'raises SocketError' do
@sock = Socket.new(:INET, :STREAM)
- -> { @sock.connect_address }.should raise_error(SocketError)
+ -> { @sock.connect_address }.should.raise(SocketError)
end
end
@@ -25,7 +25,7 @@ describe 'Socket#connect_address' do
end
it 'returns an Addrinfo' do
- @sock.connect_address.should be_an_instance_of(Addrinfo)
+ @sock.connect_address.should.instance_of?(Addrinfo)
end
it 'uses 127.0.0.1 as the IP address' do
@@ -65,7 +65,7 @@ describe 'Socket#connect_address' do
end
it 'returns an Addrinfo' do
- @sock.connect_address.should be_an_instance_of(Addrinfo)
+ @sock.connect_address.should.instance_of?(Addrinfo)
end
it 'uses ::1 as the IP address' do
@@ -94,61 +94,59 @@ describe 'Socket#connect_address' do
end
end
- with_feature :unix_socket do
- platform_is_not :aix do
- describe 'using an unbound UNIX socket' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @client = UNIXSocket.new(@path)
- end
-
- after do
- @client.close
- @server.close
- rm_r(@path)
- end
-
- it 'raises SocketError' do
- -> { @client.connect_address }.should raise_error(SocketError)
- end
- end
- end
-
- describe 'using a bound UNIX socket' do
+ platform_is_not :aix do
+ describe 'using an unbound UNIX socket' do
before do
@path = SocketSpecs.socket_path
- @sock = UNIXServer.new(@path)
+ @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @sock.close
+ @client.close
+ @server.close
rm_r(@path)
end
- it 'returns an Addrinfo' do
- @sock.connect_address.should be_an_instance_of(Addrinfo)
+ it 'raises SocketError' do
+ -> { @client.connect_address }.should.raise(SocketError)
end
+ end
+ end
- it 'uses the correct socket path' do
- @sock.connect_address.unix_path.should == @path
- end
+ describe 'using a bound UNIX socket' do
+ before do
+ @path = SocketSpecs.socket_path
+ @sock = UNIXServer.new(@path)
+ end
- it 'uses AF_UNIX as the address family' do
- @sock.connect_address.afamily.should == Socket::AF_UNIX
- end
+ after do
+ @sock.close
+ rm_r(@path)
+ end
- it 'uses PF_UNIX as the protocol family' do
- @sock.connect_address.pfamily.should == Socket::PF_UNIX
- end
+ it 'returns an Addrinfo' do
+ @sock.connect_address.should.instance_of?(Addrinfo)
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @sock.connect_address.socktype.should == Socket::SOCK_STREAM
- end
+ it 'uses the correct socket path' do
+ @sock.connect_address.unix_path.should == @path
+ end
- it 'uses 0 as the protocol' do
- @sock.connect_address.protocol.should == 0
- end
+ it 'uses AF_UNIX as the address family' do
+ @sock.connect_address.afamily.should == Socket::AF_UNIX
+ end
+
+ it 'uses PF_UNIX as the protocol family' do
+ @sock.connect_address.pfamily.should == Socket::PF_UNIX
+ end
+
+ it 'uses SOCK_STREAM as the socket type' do
+ @sock.connect_address.socktype.should == Socket::SOCK_STREAM
+ end
+
+ it 'uses 0 as the protocol' do
+ @sock.connect_address.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb
index a8800a8493..36338bfd59 100644
--- a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb
@@ -16,7 +16,7 @@ describe "BasicSocket.do_not_reverse_lookup" do
end
it "defaults to true" do
- BasicSocket.do_not_reverse_lookup.should be_true
+ BasicSocket.do_not_reverse_lookup.should == true
end
it "causes 'peeraddr' to avoid name lookups" do
diff --git a/spec/ruby/library/socket/basicsocket/for_fd_spec.rb b/spec/ruby/library/socket/basicsocket/for_fd_spec.rb
index 9c9e6a8b55..8d5b71cfa9 100644
--- a/spec/ruby/library/socket/basicsocket/for_fd_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/for_fd_spec.rb
@@ -15,7 +15,7 @@ describe "BasicSocket.for_fd" do
it "return a Socket instance wrapped around the descriptor" do
@s2 = TCPServer.for_fd(@server.fileno)
@s2.autoclose = false
- @s2.should be_kind_of(TCPServer)
+ @s2.should.is_a?(TCPServer)
@s2.fileno.should == @server.fileno
end
@@ -24,7 +24,7 @@ describe "BasicSocket.for_fd" do
socket2 = Socket.for_fd(@socket1.fileno)
socket2.autoclose = false
- socket2.should be_an_instance_of(Socket)
+ socket2.should.instance_of?(Socket)
socket2.fileno.should == @socket1.fileno
end
@@ -33,6 +33,6 @@ describe "BasicSocket.for_fd" do
socket2 = Socket.for_fd(@socket1.fileno)
socket2.autoclose = false
- socket2.binmode?.should be_true
+ socket2.binmode?.should == true
end
end
diff --git a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb
index 6179211d96..b9851bae15 100644
--- a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#getpeereid' do
- with_feature :unix_socket do
+ platform_is_not :windows do
describe 'using a UNIXSocket' do
before do
@path = SocketSpecs.socket_path
@@ -30,7 +30,7 @@ describe 'BasicSocket#getpeereid' do
it 'raises NoMethodError' do
@sock = TCPServer.new('127.0.0.1', 0)
- -> { @sock.getpeereid }.should raise_error(NoMethodError)
+ -> { @sock.getpeereid }.should.raise(NoMethodError)
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/getpeername_spec.rb b/spec/ruby/library/socket/basicsocket/getpeername_spec.rb
index 0b93f02eef..7e2f6f2e7b 100644
--- a/spec/ruby/library/socket/basicsocket/getpeername_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getpeername_spec.rb
@@ -20,6 +20,6 @@ describe "Socket::BasicSocket#getpeername" do
end
it 'raises Errno::ENOTCONN for a disconnected socket' do
- -> { @server.getpeername }.should raise_error(Errno::ENOTCONN)
+ -> { @server.getpeername }.should.raise(Errno::ENOTCONN)
end
end
diff --git a/spec/ruby/library/socket/basicsocket/getsockname_spec.rb b/spec/ruby/library/socket/basicsocket/getsockname_spec.rb
index b33db088b6..a54626647e 100644
--- a/spec/ruby/library/socket/basicsocket/getsockname_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getsockname_spec.rb
@@ -3,7 +3,7 @@ require_relative '../fixtures/classes'
describe "Socket::BasicSocket#getsockname" do
after :each do
- @socket.closed?.should be_false
+ @socket.closed?.should == false
@socket.close
end
@@ -16,7 +16,7 @@ describe "Socket::BasicSocket#getsockname" do
it "works on sockets listening in ipaddr_any" do
@socket = TCPServer.new(0)
sockaddr = Socket.unpack_sockaddr_in(@socket.getsockname)
- ["::", "0.0.0.0", "::ffff:0.0.0.0"].include?(sockaddr[1]).should be_true
+ ["::", "0.0.0.0", "::ffff:0.0.0.0"].include?(sockaddr[1]).should == true
sockaddr[0].should == @socket.addr[1]
end
diff --git a/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb
index ce65d6c92b..744297ad02 100644
--- a/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb
@@ -7,7 +7,7 @@ describe "BasicSocket#getsockopt" do
end
after :each do
- @sock.closed?.should be_false
+ @sock.closed?.should == false
@sock.close
end
@@ -41,13 +41,13 @@ describe "BasicSocket#getsockopt" do
end
it "raises a SystemCallError with an invalid socket option" do
- -> { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should raise_error(Errno::ENOPROTOOPT)
+ -> { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should.raise(Errno::ENOPROTOOPT)
end
it 'returns a Socket::Option using a constant' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
end
it 'returns a Socket::Option for a boolean option' do
@@ -59,7 +59,7 @@ describe "BasicSocket#getsockopt" do
it 'returns a Socket::Option for a numeric option' do
opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
- opt.int.should be_kind_of(Integer)
+ opt.int.should.is_a?(Integer)
end
it 'returns a Socket::Option for a struct option' do
@@ -69,7 +69,7 @@ describe "BasicSocket#getsockopt" do
end
it 'raises Errno::ENOPROTOOPT when requesting an invalid option' do
- -> { @sock.getsockopt(Socket::SOL_SOCKET, -1) }.should raise_error(Errno::ENOPROTOOPT)
+ -> { @sock.getsockopt(Socket::SOL_SOCKET, -1) }.should.raise(Errno::ENOPROTOOPT)
end
describe 'using Symbols as arguments' do
@@ -171,7 +171,7 @@ describe "BasicSocket#getsockopt" do
opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL).to_s
array = opt.unpack('i')
- array[0].should be_kind_of(Integer)
+ array[0].should.is_a?(Integer)
array[0].should > 0
end
diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
index f2a6682f12..8aca7d0332 100644
--- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
@@ -16,7 +16,7 @@ describe "Socket::BasicSocket#recv_nonblock" do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises an exception extending IO::WaitReadable' do
- -> { @s1.recv_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @s1.recv_nonblock(1) }.should.raise(IO::WaitReadable)
end
end
end
@@ -25,12 +25,12 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s1.bind(Socket.pack_sockaddr_in(0, ip_address))
-> {
@s1.recv_nonblock(5)
- }.should raise_error(IO::WaitReadable) { |e|
+ }.should.raise(IO::WaitReadable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
@@ -74,7 +74,7 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s1.recv_nonblock(1).should == "a"
-> {
@s1.recv_nonblock(5)
- }.should raise_error(IO::WaitReadable)
+ }.should.raise(IO::WaitReadable)
end
end
@@ -89,10 +89,10 @@ describe "Socket::BasicSocket#recv_nonblock" do
end
it "raises Errno::ENOTCONN" do
- -> { @server.recv_nonblock(1) }.should raise_error { |e|
+ -> { @server.recv_nonblock(1) }.should.raise { |e|
[Errno::ENOTCONN, Errno::EINVAL].should.include?(e.class)
}
- -> { @server.recv_nonblock(1, exception: false) }.should raise_error { |e|
+ -> { @server.recv_nonblock(1, exception: false) }.should.raise { |e|
[Errno::ENOTCONN, Errno::EINVAL].should.include?(e.class)
}
end
@@ -112,60 +112,30 @@ describe "Socket::BasicSocket#recv_nonblock" do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client = @server.accept
-
- Thread.pass while !ready
- begin
- client.recv_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ it "returns nil on a closed stream socket" do
+ ready = false
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
+ t = Thread.new do
+ client = @server.accept
- t.value.should == ""
- end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client = @server.accept
-
- Thread.pass while !ready
- begin
- client.recv_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recv_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
+ ensure
+ client.close if client
+ end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+ ready = true
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb
index e20c571922..5c393218bc 100644
--- a/spec/ruby/library/socket/basicsocket/recv_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../spec_helper'
require_relative '../fixtures/classes'
@@ -22,7 +22,7 @@ describe "BasicSocket#recv" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
socket = TCPSocket.new('127.0.0.1', @port)
socket.send('hello', 0)
@@ -32,28 +32,26 @@ describe "BasicSocket#recv" do
ScratchPad.recorded.should == 'hello'
end
- platform_is_not :solaris do
- it "accepts flags to specify unusual receiving behaviour" do
- t = Thread.new do
- client = @server.accept
+ it "accepts flags to specify unusual receiving behaviour" do
+ t = Thread.new do
+ client = @server.accept
- # in-band data (TCP), doesn't receive the flag.
- ScratchPad.record client.recv(10)
+ # in-band data (TCP), doesn't receive the flag.
+ ScratchPad.record client.recv(10)
- # this recv is important (TODO: explain)
- client.recv(10)
- client.close
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.send('helloU', Socket::MSG_OOB)
- socket.shutdown(1)
- t.join
- socket.close
- ScratchPad.recorded.should == 'hello'
+ # this recv is important (TODO: explain)
+ client.recv(10)
+ client.close
end
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
+
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.send('helloU', Socket::MSG_OOB)
+ socket.shutdown(1)
+ t.join
+ socket.close
+ ScratchPad.recorded.should == 'hello'
end
it "gets lines delimited with a custom separator" do
@@ -66,7 +64,7 @@ describe "BasicSocket#recv" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
socket = TCPSocket.new('127.0.0.1', @port)
socket.write("firstline\377secondline\377")
@@ -186,42 +184,21 @@ describe "BasicSocket#recv" do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recv(10)
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
-
- t.value.should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ client.recv(10)
+ ensure
+ client.close if client
end
- end
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recv(10)
- ensure
- client.close if client
- end
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
-
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
index b5fdd7c93b..9d77f5df6b 100644
--- a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
@@ -17,7 +17,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises an exception extending IO::WaitReadable' do
- -> { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.recvmsg_nonblock }.should.raise(IO::WaitReadable)
end
end
end
@@ -29,7 +29,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
describe 'without any data available' do
it 'raises an exception extending IO::WaitReadable' do
- -> { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.recvmsg_nonblock }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable with exception: false' do
@@ -47,7 +47,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @server.recvmsg_nonblock.should be_an_instance_of(Array)
+ @server.recvmsg_nonblock.should.instance_of?(Array)
end
describe 'without a maximum message length' do
@@ -74,12 +74,12 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
platform_is_not :windows do
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
end
@@ -124,8 +124,8 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it "raises Errno::ENOTCONN" do
- -> { @server.recvmsg_nonblock }.should raise_error(Errno::ENOTCONN)
- -> { @server.recvmsg_nonblock(exception: false) }.should raise_error(Errno::ENOTCONN)
+ -> { @server.recvmsg_nonblock }.should.raise(Errno::ENOTCONN)
+ -> { @server.recvmsg_nonblock(exception: false) }.should.raise(Errno::ENOTCONN)
end
end
@@ -154,7 +154,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
ensure
socket.close
end
- }.should raise_error(IO::WaitReadable)
+ }.should.raise(IO::WaitReadable)
end
end
@@ -171,7 +171,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @socket.recvmsg_nonblock.should be_an_instance_of(Array)
+ @socket.recvmsg_nonblock.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -184,11 +184,11 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
describe 'the returned Addrinfo' do
@@ -197,7 +197,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'raises when receiving the ip_address message' do
- -> { @addr.ip_address }.should raise_error(SocketError)
+ -> { @addr.ip_address }.should.raise(SocketError)
end
it 'uses the correct address family' do
@@ -213,7 +213,7 @@ describe 'BasicSocket#recvmsg_nonblock' do
end
it 'raises when receiving the ip_port message' do
- -> { @addr.ip_port }.should raise_error(SocketError)
+ -> { @addr.ip_port }.should.raise(SocketError)
end
end
end
@@ -235,64 +235,31 @@ describe 'BasicSocket#recvmsg_nonblock' do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- platform_is_not :windows do # #recvmsg_nonblock() raises 'Errno::EINVAL: Invalid argument - recvmsg(2)'
- it "returns an empty String as received data on a closed stream socket" do
- ready = false
+ platform_is_not :windows do
+ it "returns nil on a closed stream socket" do
+ ready = false
- t = Thread.new do
- client = @server.accept
+ t = Thread.new do
+ client = @server.accept
- Thread.pass while !ready
- begin
- client.recvmsg_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recvmsg_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ ensure
+ client.close if client
end
- end
- end
- ruby_version_is "3.3" do
- platform_is_not :windows do
- it "returns nil on a closed stream socket" do
- ready = false
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- t = Thread.new do
- client = @server.accept
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+ ready = true
- Thread.pass while !ready
- begin
- client.recvmsg_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
-
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
index 04ba1d74c7..eabfb9dd18 100644
--- a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
@@ -41,7 +41,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @server.recvmsg.should be_an_instance_of(Array)
+ @server.recvmsg.should.instance_of?(Array)
end
describe 'without a maximum message length' do
@@ -66,12 +66,12 @@ describe 'BasicSocket#recvmsg' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
platform_is_not :windows do
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
end
@@ -144,7 +144,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
- @socket.recvmsg.should be_an_instance_of(Array)
+ @socket.recvmsg.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -157,11 +157,11 @@ describe 'BasicSocket#recvmsg' do
end
it 'stores an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
it 'stores the flags at index 2' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
describe 'the returned Addrinfo' do
@@ -170,7 +170,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'raises when receiving the ip_address message' do
- -> { @addr.ip_address }.should raise_error(SocketError)
+ -> { @addr.ip_address }.should.raise(SocketError)
end
it 'uses the correct address family' do
@@ -186,7 +186,7 @@ describe 'BasicSocket#recvmsg' do
end
it 'raises when receiving the ip_port message' do
- -> { @addr.ip_port }.should raise_error(SocketError)
+ -> { @addr.ip_port }.should.raise(SocketError)
end
end
end
@@ -208,46 +208,22 @@ describe 'BasicSocket#recvmsg' do
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- platform_is_not :windows do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recvmsg(10)
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ platform_is_not :windows do
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ client.recvmsg(10)
+ ensure
+ client.close if client
end
- end
- end
-
- ruby_version_is "3.3" do
- platform_is_not :windows do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recvmsg(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb
index 36da125279..a2c2ee8de9 100644
--- a/spec/ruby/library/socket/basicsocket/send_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/send_spec.rb
@@ -9,8 +9,8 @@ describe "BasicSocket#send" do
end
after :each do
- @server.closed?.should be_false
- @socket.closed?.should be_false
+ @server.closed?.should == false
+ @socket.closed?.should == false
@server.close
@socket.close
@@ -28,7 +28,7 @@ describe "BasicSocket#send" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
@socket.send('hello', 0).should == 5
@socket.shutdown(1) # indicate, that we are done sending
@@ -38,7 +38,7 @@ describe "BasicSocket#send" do
data.should == 'hello'
end
- platform_is_not :solaris, :windows do
+ platform_is_not :windows do
it "accepts flags to specify unusual sending behaviour" do
data = nil
peek_data = nil
@@ -50,7 +50,7 @@ describe "BasicSocket#send" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
@socket.send('helloU', Socket::MSG_PEEK | Socket::MSG_OOB).should == 6
@socket.shutdown # indicate, that we are done sending
@@ -73,7 +73,7 @@ describe "BasicSocket#send" do
client.close
end
Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ t.status.should_not == nil
sockaddr = Socket.pack_sockaddr_in(@port, "127.0.0.1")
@socket.send('hello', 0, sockaddr).should == 5
@@ -109,7 +109,7 @@ describe 'BasicSocket#send' do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
@@ -121,7 +121,7 @@ describe 'BasicSocket#send' do
it 'does not persist the connection after writing to the socket' do
@client.send('hello', 0, @server.getsockname)
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
diff --git a/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb
index 7acfc659bd..4cd6e8bdca 100644
--- a/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb
@@ -20,10 +20,10 @@ describe 'BasicSocket#sendmsg_nonblock' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
-> {
@client.sendmsg_nonblock('hello')
- }.should raise_error(SocketSpecs.dest_addr_req_error)
+ }.should.raise(SocketSpecs.dest_addr_req_error)
-> {
@client.sendmsg_nonblock('hello', exception: false)
- }.should raise_error(SocketSpecs.dest_addr_req_error)
+ }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
@@ -101,7 +101,7 @@ describe 'BasicSocket#sendmsg_nonblock' do
it 'raises IO::WaitWritable when the underlying buffer is full' do
-> {
10.times { @client.sendmsg_nonblock('hello' * 1_000_000) }
- }.should raise_error(IO::WaitWritable)
+ }.should.raise(IO::WaitWritable)
end
it 'returns :wait_writable when the underlying buffer is full with exception: false' do
diff --git a/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb b/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb
index 7ff336c0b7..dc999b32df 100644
--- a/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb
@@ -19,7 +19,7 @@ describe 'BasicSocket#sendmsg' do
platform_is_not :windows do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
- -> { @client.sendmsg('hello') }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.sendmsg('hello') }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb
index 1e8d84e1c9..e306581aa3 100644
--- a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb
@@ -40,7 +40,7 @@ describe "BasicSocket#setsockopt" do
it "raises EINVAL if passed wrong linger value" do
-> do
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, 0)
- end.should raise_error(Errno::EINVAL)
+ end.should.raise(Errno::EINVAL)
end
end
@@ -72,7 +72,7 @@ describe "BasicSocket#setsockopt" do
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "blah").should == 0
@@ -82,7 +82,7 @@ describe "BasicSocket#setsockopt" do
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "0")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "\x00\x00\x00\x00").should == 0
@@ -92,13 +92,13 @@ describe "BasicSocket#setsockopt" do
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "1")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
platform_is_not :windows do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, "\x00\x00\x00")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
end
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, [1].pack('i')).should == 0
@@ -127,7 +127,7 @@ describe "BasicSocket#setsockopt" do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, nil).should == 0
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, 1).should == 0
n = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF).to_s
@@ -139,23 +139,23 @@ describe "BasicSocket#setsockopt" do
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "bla")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "0")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "1")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
-> {
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "\x00\x00\x00")
- }.should raise_error(SystemCallError)
+ }.should.raise(SystemCallError)
@sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF, "\x00\x00\x01\x00").should == 0
n = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF).to_s
@@ -207,7 +207,7 @@ describe "BasicSocket#setsockopt" do
onoff, seconds = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER).linger
seconds.should == 10
# Both results can be produced depending on the OS and value of Socket::SO_LINGER
- [true, Socket::SO_LINGER].should include(onoff)
+ [true, Socket::SO_LINGER].should.include?(onoff)
end
end
end
@@ -224,7 +224,7 @@ describe 'BasicSocket#setsockopt' do
describe 'using separate arguments with Symbols' do
it 'raises TypeError when the first argument is nil' do
- -> { @socket.setsockopt(nil, :REUSEADDR, true) }.should raise_error(TypeError)
+ -> { @socket.setsockopt(nil, :REUSEADDR, true) }.should.raise(TypeError)
end
it 'sets a boolean option' do
@@ -251,7 +251,7 @@ describe 'BasicSocket#setsockopt' do
platform_is_not :windows do
it 'raises Errno::EINVAL when setting an invalid option value' do
- -> { @socket.setsockopt(:SOCKET, :OOBINLINE, 'bla') }.should raise_error(Errno::EINVAL)
+ -> { @socket.setsockopt(:SOCKET, :OOBINLINE, 'bla') }.should.raise(Errno::EINVAL)
end
end
end
@@ -305,32 +305,30 @@ describe 'BasicSocket#setsockopt' do
it 'raises ArgumentError when passing 2 arguments' do
option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)
- -> { @socket.setsockopt(option, :REUSEADDR) }.should raise_error(ArgumentError)
+ -> { @socket.setsockopt(option, :REUSEADDR) }.should.raise(ArgumentError)
end
it 'raises TypeError when passing 3 arguments' do
option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)
- -> { @socket.setsockopt(option, :REUSEADDR, true) }.should raise_error(TypeError)
+ -> { @socket.setsockopt(option, :REUSEADDR, true) }.should.raise(TypeError)
end
end
end
- with_feature :unix_socket do
- describe 'using a UNIX socket' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- end
+ describe 'using a UNIX socket' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
- after do
- @server.close
- rm_r @path
- end
+ after do
+ @server.close
+ rm_r @path
+ end
- it 'sets a boolean option' do
- @server.setsockopt(:SOCKET, :REUSEADDR, true)
- @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
- end
+ it 'sets a boolean option' do
+ @server.setsockopt(:SOCKET, :REUSEADDR, true)
+ @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
index c78b32de38..c96c62abe1 100644
--- a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
@@ -23,25 +23,25 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading' do
@client.shutdown(Socket::SHUT_RD)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for writing' do
@client.shutdown(Socket::SHUT_WR)
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for reading and writing' do
@client.shutdown(Socket::SHUT_RDWR)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
- -> { @server.shutdown(666) }.should raise_error(ArgumentError)
+ -> { @server.shutdown(666) }.should.raise(ArgumentError)
end
end
@@ -49,37 +49,37 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading using :RD' do
@client.shutdown(:RD)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for reading using :SHUT_RD' do
@client.shutdown(:SHUT_RD)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for writing using :WR' do
@client.shutdown(:WR)
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for writing using :SHUT_WR' do
@client.shutdown(:SHUT_WR)
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for reading and writing' do
@client.shutdown(:RDWR)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
- -> { @server.shutdown(:Nope) }.should raise_error(SocketError)
+ -> { @server.shutdown(:Nope) }.should.raise(SocketError)
end
end
@@ -87,29 +87,29 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading using "RD"' do
@client.shutdown('RD')
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@client.shutdown('SHUT_RD')
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for writing using "WR"' do
@client.shutdown('WR')
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'shuts down a socket for writing using "SHUT_WR"' do
@client.shutdown('SHUT_WR')
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
- -> { @server.shutdown('Nope') }.should raise_error(SocketError)
+ -> { @server.shutdown('Nope') }.should.raise(SocketError)
end
end
@@ -123,7 +123,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@@ -131,7 +131,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
end
it 'shuts down a socket for reading and writing' do
@@ -139,15 +139,15 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).to_s.should.empty?
- -> { @client.write('hello') }.should raise_error(Errno::EPIPE)
+ -> { @client.write('hello') }.should.raise(Errno::EPIPE)
end
end
describe 'using an object that does not respond to #to_str' do
it 'raises TypeError' do
- -> { @server.shutdown(mock(:dummy)) }.should raise_error(TypeError)
+ -> { @server.shutdown(mock(:dummy)) }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/constants/constants_spec.rb b/spec/ruby/library/socket/constants/constants_spec.rb
index 637bc6740a..a936473bb6 100644
--- a/spec/ruby/library/socket/constants/constants_spec.rb
+++ b/spec/ruby/library/socket/constants/constants_spec.rb
@@ -5,47 +5,47 @@ describe "Socket::Constants" do
it "defines socket types" do
consts = ["SOCK_DGRAM", "SOCK_RAW", "SOCK_RDM", "SOCK_SEQPACKET", "SOCK_STREAM"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
it "defines protocol families" do
consts = ["PF_INET6", "PF_INET", "PF_UNIX", "PF_UNSPEC"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
platform_is_not :aix do
it "defines PF_IPX protocol" do
- Socket::Constants.should have_constant("PF_IPX")
+ Socket::Constants.should.const_defined?("PF_IPX", false)
end
end
it "defines address families" do
consts = ["AF_INET6", "AF_INET", "AF_UNIX", "AF_UNSPEC"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
platform_is_not :aix do
it "defines AF_IPX address" do
- Socket::Constants.should have_constant("AF_IPX")
+ Socket::Constants.should.const_defined?("AF_IPX", false)
end
end
it "defines send/receive options" do
consts = ["MSG_DONTROUTE", "MSG_OOB", "MSG_PEEK"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
it "defines socket level options" do
consts = ["SOL_SOCKET"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
@@ -53,7 +53,7 @@ describe "Socket::Constants" do
consts = ["SO_BROADCAST", "SO_DEBUG", "SO_DONTROUTE", "SO_ERROR", "SO_KEEPALIVE", "SO_LINGER",
"SO_OOBINLINE", "SO_RCVBUF", "SO_REUSEADDR", "SO_SNDBUF", "SO_TYPE"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
@@ -64,15 +64,15 @@ describe "Socket::Constants" do
consts += ["IP_DEFAULT_MULTICAST_LOOP", "IP_DEFAULT_MULTICAST_TTL"]
end
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
- platform_is_not :solaris, :windows, :aix, :android do
+ platform_is_not :windows, :aix, :android do
it "defines multicast options" do
consts = ["IP_MAX_MEMBERSHIPS"]
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
end
@@ -83,13 +83,13 @@ describe "Socket::Constants" do
consts << "TCP_MAXSEG"
end
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
platform_is_not :windows do
it 'defines SCM options' do
- Socket::Constants.should have_constant('SCM_RIGHTS')
+ Socket::Constants.should.const_defined?('SCM_RIGHTS', false)
end
it 'defines error options' do
@@ -101,7 +101,7 @@ describe "Socket::Constants" do
end
consts.each do |c|
- Socket::Constants.should have_constant(c)
+ Socket::Constants.should.const_defined?(c, false)
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/addr_spec.rb b/spec/ruby/library/socket/ipsocket/addr_spec.rb
index 199eb85ab7..eb16a8efdf 100644
--- a/spec/ruby/library/socket/ipsocket/addr_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/addr_spec.rb
@@ -17,7 +17,7 @@ describe "Socket::IPSocket#addr" do
BasicSocket.do_not_reverse_lookup = false
addrinfo = @socket.addr
addrinfo[0].should == "AF_INET"
- addrinfo[1].should be_kind_of(Integer)
+ addrinfo[1].should.is_a?(Integer)
addrinfo[2].should == SocketSpecs.hostname
addrinfo[3].should == "127.0.0.1"
end
@@ -27,7 +27,7 @@ describe "Socket::IPSocket#addr" do
BasicSocket.do_not_reverse_lookup = true
addrinfo = @socket.addr
addrinfo[0].should == "AF_INET"
- addrinfo[1].should be_kind_of(Integer)
+ addrinfo[1].should.is_a?(Integer)
addrinfo[2].should == "127.0.0.1"
addrinfo[3].should == "127.0.0.1"
end
@@ -35,7 +35,7 @@ describe "Socket::IPSocket#addr" do
it "returns an address in the array if passed false" do
addrinfo = @socket.addr(false)
addrinfo[0].should == "AF_INET"
- addrinfo[1].should be_kind_of(Integer)
+ addrinfo[1].should.is_a?(Integer)
addrinfo[2].should == "127.0.0.1"
addrinfo[3].should == "127.0.0.1"
end
@@ -81,7 +81,7 @@ describe 'Socket::IPSocket#addr' do
describe 'using :cats as the argument' do
it 'raises ArgumentError' do
- -> { @server.addr(:cats) }.should raise_error(ArgumentError)
+ -> { @server.addr(:cats) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
index 329f8267d3..d302cd6a8a 100644
--- a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
@@ -23,6 +23,6 @@ describe "Socket::IPSocket#getaddress" do
it "raises an error on unknown hostnames" do
-> {
IPSocket.getaddress("rubyspecdoesntexist.ruby-lang.org")
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/ipsocket/inspect_spec.rb b/spec/ruby/library/socket/ipsocket/inspect_spec.rb
new file mode 100644
index 0000000000..85780a16f6
--- /dev/null
+++ b/spec/ruby/library/socket/ipsocket/inspect_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../spec_helper'
+
+describe 'IPSocket#inspect' do
+ it "returns a String with the fd, family, address and port for TCPSocket" do
+ @server = TCPServer.new("127.0.0.1", 0)
+ @socket = TCPSocket.new("127.0.0.1", @server.addr[1])
+ port = @socket.addr[1]
+
+ @socket.inspect.should == "#<TCPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>"
+ ensure
+ @socket&.close
+ @server&.close
+ end
+
+ it 'returns a String with the fd, family, address and port for UDPSocket' do
+ @socket = UDPSocket.new
+ @socket.bind('127.0.0.1', 0)
+ port = @socket.addr[1]
+
+ @socket.inspect.should == "#<UDPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>"
+ ensure
+ @socket&.close
+ end
+end
diff --git a/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb b/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb
index 702650940b..b79222000a 100644
--- a/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb
@@ -18,7 +18,7 @@ describe "Socket::IPSocket#peeraddr" do
it "raises error if socket is not connected" do
-> {
@server.peeraddr
- }.should raise_error(Errno::ENOTCONN)
+ }.should.raise(Errno::ENOTCONN)
end
it "returns an array of information on the peer" do
@@ -92,7 +92,7 @@ describe 'Socket::IPSocket#peeraddr' do
describe 'using :cats as the argument' do
it 'raises ArgumentError' do
- -> { @client.peeraddr(:cats) }.should raise_error(ArgumentError)
+ -> { @client.peeraddr(:cats) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
index b58903df23..7af0078be1 100644
--- a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
@@ -83,43 +83,21 @@ describe "Socket::IPSocket#recvfrom" do
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- message = client.recvfrom(10)
- message
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ message = client.recvfrom(10)
+ message
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- message = client.recvfrom(10)
- message
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- @client.close
+ @client.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
diff --git a/spec/ruby/library/socket/option/bool_spec.rb b/spec/ruby/library/socket/option/bool_spec.rb
index 144a78043d..9992e842b3 100644
--- a/spec/ruby/library/socket/option/bool_spec.rb
+++ b/spec/ruby/library/socket/option/bool_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe "Socket::Option.bool" do
it "creates a new Socket::Option" do
so = Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true)
- so.should be_an_instance_of(Socket::Option)
+ so.should.instance_of?(Socket::Option)
so.family.should == Socket::AF_INET
so.level.should == Socket::SOL_SOCKET
so.optname.should == Socket::SO_KEEPALIVE
@@ -21,7 +21,7 @@ describe "Socket::Option#bool" do
platform_is_not :windows do
it 'raises TypeError when called on a non boolean option' do
opt = Socket::Option.linger(1, 4)
- -> { opt.bool }.should raise_error(TypeError)
+ -> { opt.bool }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/option/initialize_spec.rb b/spec/ruby/library/socket/option/initialize_spec.rb
index 8071ad7ef0..5af274f332 100644
--- a/spec/ruby/library/socket/option/initialize_spec.rb
+++ b/spec/ruby/library/socket/option/initialize_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket::Option#initialize' do
opt = Socket::Option
.new(Socket::AF_INET, Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, @bool)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::SOL_SOCKET
@@ -23,7 +23,7 @@ describe 'Socket::Option#initialize' do
it 'returns a Socket::Option' do
opt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, @bool)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::SOL_SOCKET
@@ -34,19 +34,19 @@ describe 'Socket::Option#initialize' do
it 'raises when using an invalid address family' do
-> {
Socket::Option.new(:INET2, :SOCKET, :KEEPALIVE, @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid level' do
-> {
Socket::Option.new(:INET, :CATS, :KEEPALIVE, @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid option name' do
-> {
Socket::Option.new(:INET, :SOCKET, :CATS, @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -54,7 +54,7 @@ describe 'Socket::Option#initialize' do
it 'returns a Socket::Option' do
opt = Socket::Option.new('INET', 'SOCKET', 'KEEPALIVE', @bool)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::SOL_SOCKET
@@ -65,19 +65,19 @@ describe 'Socket::Option#initialize' do
it 'raises when using an invalid address family' do
-> {
Socket::Option.new('INET2', 'SOCKET', 'KEEPALIVE', @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid level' do
-> {
Socket::Option.new('INET', 'CATS', 'KEEPALIVE', @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
it 'raises when using an invalid option name' do
-> {
Socket::Option.new('INET', 'SOCKET', 'CATS', @bool)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/option/int_spec.rb b/spec/ruby/library/socket/option/int_spec.rb
index 8c69ef6cbd..0cd341f88a 100644
--- a/spec/ruby/library/socket/option/int_spec.rb
+++ b/spec/ruby/library/socket/option/int_spec.rb
@@ -4,7 +4,7 @@ require_relative '../fixtures/classes'
describe "Socket::Option.int" do
it "creates a new Socket::Option" do
so = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 5)
- so.should be_an_instance_of(Socket::Option)
+ so.should.instance_of?(Socket::Option)
so.family.should == Socket::Constants::AF_INET
so.level.should == Socket::Constants::SOL_SOCKET
so.optname.should == Socket::Constants::SO_KEEPALIVE
@@ -14,7 +14,7 @@ describe "Socket::Option.int" do
it 'returns a Socket::Option' do
opt = Socket::Option.int(:INET, :IP, :TTL, 4)
- opt.should be_an_instance_of(Socket::Option)
+ opt.should.instance_of?(Socket::Option)
opt.family.should == Socket::AF_INET
opt.level.should == Socket::IPPROTO_IP
@@ -37,7 +37,7 @@ describe "Socket::Option#int" do
platform_is_not :windows do
it 'raises TypeError when called on a non integer option' do
opt = Socket::Option.linger(1, 4)
- -> { opt.int }.should raise_error(TypeError)
+ -> { opt.int }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/option/linger_spec.rb b/spec/ruby/library/socket/option/linger_spec.rb
index ee987db85b..87c5e0982e 100644
--- a/spec/ruby/library/socket/option/linger_spec.rb
+++ b/spec/ruby/library/socket/option/linger_spec.rb
@@ -9,7 +9,7 @@ end
describe "Socket::Option.linger" do
it "creates a new Socket::Option for SO_LINGER" do
so = Socket::Option.linger(1, 10)
- so.should be_an_instance_of(Socket::Option)
+ so.should.instance_of?(Socket::Option)
so.family.should == Socket::Constants::AF_UNSPEC
so.level.should == Socket::Constants::SOL_SOCKET
@@ -31,46 +31,46 @@ describe "Socket::Option#linger" do
it "returns linger option" do
so = Socket::Option.linger(0, 5)
ary = so.linger
- ary[0].should be_false
+ ary[0].should == false
ary[1].should == 5
so = Socket::Option.linger(false, 4)
ary = so.linger
- ary[0].should be_false
+ ary[0].should == false
ary[1].should == 4
so = Socket::Option.linger(1, 10)
ary = so.linger
- ary[0].should be_true
+ ary[0].should == true
ary[1].should == 10
so = Socket::Option.linger(true, 9)
ary = so.linger
- ary[0].should be_true
+ ary[0].should == true
ary[1].should == 9
end
it "raises TypeError if not a SO_LINGER" do
so = Socket::Option.int(:AF_UNSPEC, :SOL_SOCKET, :KEEPALIVE, 1)
- -> { so.linger }.should raise_error(TypeError)
+ -> { so.linger }.should.raise(TypeError)
end
it 'raises TypeError when called on a non SOL_SOCKET/SO_LINGER option' do
opt = Socket::Option.int(:INET, :IP, :TTL, 4)
- -> { opt.linger }.should raise_error(TypeError)
+ -> { opt.linger }.should.raise(TypeError)
end
platform_is_not :windows do
it "raises TypeError if option has not good size" do
so = Socket::Option.int(:AF_UNSPEC, :SOL_SOCKET, :LINGER, 1)
- -> { so.linger }.should raise_error(TypeError)
+ -> { so.linger }.should.raise(TypeError)
end
end
it 'raises TypeError when called on a non linger option' do
opt = Socket::Option.new(:INET, :SOCKET, :LINGER, '')
- -> { opt.linger }.should raise_error(TypeError)
+ -> { opt.linger }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/socket/option/new_spec.rb b/spec/ruby/library/socket/option/new_spec.rb
index a9e6f09097..3721d63ee5 100644
--- a/spec/ruby/library/socket/option/new_spec.rb
+++ b/spec/ruby/library/socket/option/new_spec.rb
@@ -22,14 +22,14 @@ describe "Socket::Option.new" do
end
it "should raise error on unknown family" do
- -> { Socket::Option.new(:INET4, :SOCKET, :KEEPALIVE, [0].pack('i')) }.should raise_error(SocketError)
+ -> { Socket::Option.new(:INET4, :SOCKET, :KEEPALIVE, [0].pack('i')) }.should.raise(SocketError)
end
it "should raise error on unknown level" do
- -> { Socket::Option.new(:INET, :ROCKET, :KEEPALIVE, [0].pack('i')) }.should raise_error(SocketError)
+ -> { Socket::Option.new(:INET, :ROCKET, :KEEPALIVE, [0].pack('i')) }.should.raise(SocketError)
end
it "should raise error on unknown option name" do
- -> { Socket::Option.new(:INET, :SOCKET, :ALIVE, [0].pack('i')) }.should raise_error(SocketError)
+ -> { Socket::Option.new(:INET, :SOCKET, :ALIVE, [0].pack('i')) }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/shared/address.rb b/spec/ruby/library/socket/shared/address.rb
index f3be9cfb99..c64602df2f 100644
--- a/spec/ruby/library/socket/shared/address.rb
+++ b/spec/ruby/library/socket/shared/address.rb
@@ -46,7 +46,7 @@ describe :socket_local_remote_address, shared: true do
end
it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
+ @addr.should.instance_of?(Addrinfo)
end
it 'uses 0 as the protocol' do
@@ -110,7 +110,7 @@ describe :socket_local_remote_address, shared: true do
end
it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
+ @addr.should.instance_of?(Addrinfo)
end
it 'uses 0 as the protocol' do
@@ -129,41 +129,51 @@ describe :socket_local_remote_address, shared: true do
end
end
- with_feature :unix_socket do
- describe 'using UNIXSocket' do
- before :each do
- @path = SocketSpecs.socket_path
- @s = UNIXServer.new(@path)
- @a = UNIXSocket.new(@path)
- @b = @s.accept
- @addr = @object.call(@a)
- end
+ describe 'using UNIXSocket' do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @s = UNIXServer.new(@path)
+ @a = UNIXSocket.new(@path)
+ @b = @s.accept
+ @addr = @object.call(@a)
+ end
- after :each do
- [@b, @a, @s].each(&:close)
- rm_r(@path)
- end
+ after :each do
+ [@b, @a, @s].each(&:close)
+ rm_r(@path)
+ end
- it 'uses AF_UNIX as the address family' do
- @addr.afamily.should == Socket::AF_UNIX
- end
+ it 'uses AF_UNIX as the address family' do
+ @addr.afamily.should == Socket::AF_UNIX
+ end
- it 'uses PF_UNIX as the protocol family' do
- @addr.pfamily.should == Socket::PF_UNIX
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @addr.pfamily.should == Socket::PF_UNIX
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @addr.socktype.should == Socket::SOCK_STREAM
+ it 'uses SOCK_STREAM as the socket type' do
+ @addr.socktype.should == Socket::SOCK_STREAM
+ end
+
+ it 'uses the correct socket path' do
+ if @method == :local_address
+ @addr.unix_path.should == ""
+ else
+ @addr.unix_path.should == @path
end
+ end
- it 'uses the correct socket path' do
+ platform_is_not :windows do
+ it 'equals address of peer socket' do
if @method == :local_address
- @addr.unix_path.should == ""
+ @addr.to_s.should == @b.remote_address.to_s
else
- @addr.unix_path.should == @path
+ @addr.to_s.should == @b.local_address.to_s
end
end
+ end
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
it 'equals address of peer socket' do
if @method == :local_address
@addr.to_s.should == @b.remote_address.to_s
@@ -171,23 +181,23 @@ describe :socket_local_remote_address, shared: true do
@addr.to_s.should == @b.local_address.to_s
end
end
+ end
- it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
- end
+ it 'returns an Addrinfo' do
+ @addr.should.instance_of?(Addrinfo)
+ end
- it 'uses 0 as the protocol' do
- @addr.protocol.should == 0
- end
+ it 'uses 0 as the protocol' do
+ @addr.protocol.should == 0
+ end
- it 'can be used to connect to the server' do
- skip if @method == :local_address
- b = @addr.connect
- begin
- b.remote_address.to_s.should == @addr.to_s
- ensure
- b.close
- end
+ it 'can be used to connect to the server' do
+ skip if @method == :local_address
+ b = @addr.connect
+ begin
+ b.remote_address.to_s.should == @addr.to_s
+ ensure
+ b.close
end
end
end
@@ -230,7 +240,7 @@ describe :socket_local_remote_address, shared: true do
end
it 'returns an Addrinfo' do
- @addr.should be_an_instance_of(Addrinfo)
+ @addr.should.instance_of?(Addrinfo)
end
it 'uses 0 as the protocol' do
diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb
index 26fdf682b1..db6f39612d 100644
--- a/spec/ruby/library/socket/shared/pack_sockaddr.rb
+++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb
@@ -22,70 +22,53 @@ describe :socket_pack_sockaddr_in, shared: true do
Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '0.0.0.0']
end
- platform_is_not :solaris do
- it 'resolves the service name to a port' do
- sockaddr_in = Socket.public_send(@method, 'http', '127.0.0.1')
- Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
- end
+ it 'resolves the service name to a port' do
+ sockaddr_in = Socket.public_send(@method, 'http', '127.0.0.1')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
end
describe 'using an IPv4 address' do
it 'returns a String of 16 bytes' do
str = Socket.public_send(@method, 80, '127.0.0.1')
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
str.bytesize.should == 16
end
end
- platform_is_not :solaris do
- describe 'using an IPv6 address' do
- it 'returns a String of 28 bytes' do
- str = Socket.public_send(@method, 80, '::1')
-
- str.should be_an_instance_of(String)
- str.bytesize.should == 28
- end
- end
- end
-
- platform_is :solaris do
- describe 'using an IPv6 address' do
- it 'returns a String of 32 bytes' do
- str = Socket.public_send(@method, 80, '::1')
+ describe 'using an IPv6 address' do
+ it 'returns a String of 28 bytes' do
+ str = Socket.public_send(@method, 80, '::1')
- str.should be_an_instance_of(String)
- str.bytesize.should == 32
- end
+ str.should.instance_of?(String)
+ str.bytesize.should == 28
end
end
end
describe :socket_pack_sockaddr_un, shared: true do
- with_feature :unix_socket do
- it 'should be idempotent' do
- bytes = Socket.public_send(@method, '/tmp/foo').bytes
- bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111]
- bytes[10..-1].all?(&:zero?).should == true
- end
+ it 'should be idempotent' do
+ bytes = Socket.public_send(@method, '/tmp/foo').bytes
+ bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111]
+ bytes[10..-1].all?(&:zero?).should == true
+ end
- it "packs and unpacks" do
- sockaddr_un = Socket.public_send(@method, '/tmp/s')
- Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s'
- end
+ it "packs and unpacks" do
+ sockaddr_un = Socket.public_send(@method, '/tmp/s')
+ Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s'
+ end
- it "handles correctly paths with multibyte chars" do
- sockaddr_un = Socket.public_send(@method, '/home/вася/sock')
- path = Socket.unpack_sockaddr_un(sockaddr_un).encode('UTF-8', 'UTF-8')
- path.should == '/home/вася/sock'
- end
+ it "handles correctly paths with multibyte chars" do
+ sockaddr_un = Socket.public_send(@method, '/home/вася/sock')
+ path = Socket.unpack_sockaddr_un(sockaddr_un).encode('UTF-8', 'UTF-8')
+ path.should == '/home/вася/sock'
end
platform_is :linux do
it 'returns a String of 110 bytes' do
str = Socket.public_send(@method, '/tmp/test.sock')
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
str.bytesize.should == 110
end
end
@@ -94,16 +77,16 @@ describe :socket_pack_sockaddr_un, shared: true do
it 'returns a String of 106 bytes' do
str = Socket.public_send(@method, '/tmp/test.sock')
- str.should be_an_instance_of(String)
+ str.should.instance_of?(String)
str.bytesize.should == 106
end
end
- platform_is_not :windows, :aix do
+ platform_is_not :aix do
it "raises ArgumentError for paths that are too long" do
# AIX doesn't raise error
long_path = 'a' * 110
- -> { Socket.public_send(@method, long_path) }.should raise_error(ArgumentError)
+ -> { Socket.public_send(@method, long_path) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/library/socket/shared/socketpair.rb b/spec/ruby/library/socket/shared/socketpair.rb
index 25146cfff6..7fcd4d6b46 100644
--- a/spec/ruby/library/socket/shared/socketpair.rb
+++ b/spec/ruby/library/socket/shared/socketpair.rb
@@ -12,8 +12,8 @@ describe :socket_socketpair, shared: true do
begin
s1, s2 = Socket.public_send(@method, :UNIX, :STREAM)
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
ensure
s1.close
s2.close
@@ -24,8 +24,8 @@ describe :socket_socketpair, shared: true do
it 'returns two Socket objects' do
s1, s2 = Socket.public_send(@method, Socket::AF_UNIX, Socket::SOCK_STREAM)
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
s1.close
s2.close
end
@@ -35,18 +35,18 @@ describe :socket_socketpair, shared: true do
it 'returns two Socket objects' do
s1, s2 = Socket.public_send(@method, :UNIX, :STREAM)
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
s1.close
s2.close
end
it 'raises SocketError for an unknown address family' do
- -> { Socket.public_send(@method, :CATS, :STREAM) }.should raise_error(SocketError)
+ -> { Socket.public_send(@method, :CATS, :STREAM) }.should.raise(SocketError)
end
it 'raises SocketError for an unknown socket type' do
- -> { Socket.public_send(@method, :UNIX, :CATS) }.should raise_error(SocketError)
+ -> { Socket.public_send(@method, :UNIX, :CATS) }.should.raise(SocketError)
end
end
@@ -54,18 +54,18 @@ describe :socket_socketpair, shared: true do
it 'returns two Socket objects' do
s1, s2 = Socket.public_send(@method, 'UNIX', 'STREAM')
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
s1.close
s2.close
end
it 'raises SocketError for an unknown address family' do
- -> { Socket.public_send(@method, 'CATS', 'STREAM') }.should raise_error(SocketError)
+ -> { Socket.public_send(@method, 'CATS', 'STREAM') }.should.raise(SocketError)
end
it 'raises SocketError for an unknown socket type' do
- -> { Socket.public_send(@method, 'UNIX', 'CATS') }.should raise_error(SocketError)
+ -> { Socket.public_send(@method, 'UNIX', 'CATS') }.should.raise(SocketError)
end
end
@@ -79,8 +79,8 @@ describe :socket_socketpair, shared: true do
s1, s2 = Socket.public_send(@method, family, type)
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
s1.close
s2.close
end
@@ -92,7 +92,7 @@ describe :socket_socketpair, shared: true do
family.stub!(:to_str).and_return(Socket::AF_UNIX)
type.stub!(:to_str).and_return(Socket::SOCK_STREAM)
- -> { Socket.public_send(@method, family, type) }.should raise_error(TypeError)
+ -> { Socket.public_send(@method, family, type) }.should.raise(TypeError)
end
it 'raises SocketError for an unknown address family' do
@@ -102,7 +102,7 @@ describe :socket_socketpair, shared: true do
family.stub!(:to_str).and_return('CATS')
type.stub!(:to_str).and_return('STREAM')
- -> { Socket.public_send(@method, family, type) }.should raise_error(SocketError)
+ -> { Socket.public_send(@method, family, type) }.should.raise(SocketError)
end
it 'raises SocketError for an unknown socket type' do
@@ -112,14 +112,14 @@ describe :socket_socketpair, shared: true do
family.stub!(:to_str).and_return('UNIX')
type.stub!(:to_str).and_return('CATS')
- -> { Socket.public_send(@method, family, type) }.should raise_error(SocketError)
+ -> { Socket.public_send(@method, family, type) }.should.raise(SocketError)
end
end
it 'accepts a custom protocol as an Integer as the 3rd argument' do
s1, s2 = Socket.public_send(@method, :UNIX, :STREAM, Socket::IPPROTO_IP)
- s1.should be_an_instance_of(Socket)
- s2.should be_an_instance_of(Socket)
+ s1.should.instance_of?(Socket)
+ s2.should.instance_of?(Socket)
s1.close
s2.close
end
diff --git a/spec/ruby/library/socket/socket/accept_loop_spec.rb b/spec/ruby/library/socket/socket/accept_loop_spec.rb
index 78e8c3fa4a..6c65b192ed 100644
--- a/spec/ruby/library/socket/socket/accept_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/accept_loop_spec.rb
@@ -41,8 +41,8 @@ describe 'Socket.accept_loop' do
end
begin
- conn.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
+ conn.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
ensure
conn.close
end
@@ -73,8 +73,8 @@ describe 'Socket.accept_loop' do
end
begin
- conn.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
+ conn.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
ensure
conn.close
end
diff --git a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
index 011622988c..09cdbaa7b4 100644
--- a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
@@ -17,12 +17,12 @@ describe "Socket#accept_nonblock" do
it "raises IO::WaitReadable if the connection is not accepted yet" do
-> {
@socket.accept_nonblock
- }.should raise_error(IO::WaitReadable) { |e|
+ }.should.raise(IO::WaitReadable) { |e|
platform_is_not :windows do
- e.should be_kind_of(Errno::EAGAIN)
+ e.should.is_a?(Errno::EAGAIN)
end
platform_is :windows do
- e.should be_kind_of(Errno::EWOULDBLOCK)
+ e.should.is_a?(Errno::EWOULDBLOCK)
end
}
end
@@ -45,8 +45,8 @@ describe 'Socket#accept_nonblock' do
describe 'using an unbound socket' do
it 'raises Errno::EINVAL' do
- -> { @server.accept_nonblock }.should raise_error(Errno::EINVAL)
- -> { @server.accept_nonblock(exception: false) }.should raise_error(Errno::EINVAL)
+ -> { @server.accept_nonblock }.should.raise(Errno::EINVAL)
+ -> { @server.accept_nonblock(exception: false) }.should.raise(Errno::EINVAL)
end
end
@@ -56,8 +56,8 @@ describe 'Socket#accept_nonblock' do
end
it 'raises Errno::EINVAL' do
- -> { @server.accept_nonblock }.should raise_error(Errno::EINVAL)
- -> { @server.accept_nonblock(exception: false) }.should raise_error(Errno::EINVAL)
+ -> { @server.accept_nonblock }.should.raise(Errno::EINVAL)
+ -> { @server.accept_nonblock(exception: false) }.should.raise(Errno::EINVAL)
end
end
@@ -65,8 +65,8 @@ describe 'Socket#accept_nonblock' do
it 'raises IOError' do
@server.close
- -> { @server.accept_nonblock }.should raise_error(IOError)
- -> { @server.accept_nonblock(exception: false) }.should raise_error(IOError)
+ -> { @server.accept_nonblock }.should.raise(IOError)
+ -> { @server.accept_nonblock(exception: false) }.should.raise(IOError)
end
end
@@ -78,7 +78,7 @@ describe 'Socket#accept_nonblock' do
describe 'without a connected client' do
it 'raises IO::WaitReadable' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
end
@@ -100,8 +100,8 @@ describe 'Socket#accept_nonblock' do
IO.select([@server])
@socket, addrinfo = @server.accept_nonblock
- @socket.should be_an_instance_of(Socket)
- addrinfo.should be_an_instance_of(Addrinfo)
+ @socket.should.instance_of?(Socket)
+ addrinfo.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/accept_spec.rb b/spec/ruby/library/socket/socket/accept_spec.rb
index 417f996c55..fca727ab08 100644
--- a/spec/ruby/library/socket/socket/accept_spec.rb
+++ b/spec/ruby/library/socket/socket/accept_spec.rb
@@ -15,7 +15,7 @@ describe 'Socket#accept' do
platform_is :linux do # hangs on other platforms
describe 'using an unbound socket' do
it 'raises Errno::EINVAL' do
- -> { @server.accept }.should raise_error(Errno::EINVAL)
+ -> { @server.accept }.should.raise(Errno::EINVAL)
end
end
@@ -25,7 +25,7 @@ describe 'Socket#accept' do
end
it 'raises Errno::EINVAL' do
- -> { @server.accept }.should raise_error(Errno::EINVAL)
+ -> { @server.accept }.should.raise(Errno::EINVAL)
end
end
end
@@ -34,7 +34,7 @@ describe 'Socket#accept' do
it 'raises IOError' do
@server.close
- -> { @server.accept }.should raise_error(IOError)
+ -> { @server.accept }.should.raise(IOError)
end
end
@@ -58,7 +58,7 @@ describe 'Socket#accept' do
value = thread.value
begin
- value.should be_an_instance_of(Array)
+ value.should.instance_of?(Array)
ensure
client.close
value[0].close
@@ -82,8 +82,8 @@ describe 'Socket#accept' do
it 'returns an Array containing a Socket and an Addrinfo' do
@socket, addrinfo = @server.accept
- @socket.should be_an_instance_of(Socket)
- addrinfo.should be_an_instance_of(Addrinfo)
+ @socket.should.instance_of?(Socket)
+ addrinfo.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/bind_spec.rb b/spec/ruby/library/socket/socket/bind_spec.rb
index e76336eafa..164df92205 100644
--- a/spec/ruby/library/socket/socket/bind_spec.rb
+++ b/spec/ruby/library/socket/socket/bind_spec.rb
@@ -8,12 +8,12 @@ describe "Socket#bind on SOCK_DGRAM socket" do
end
after :each do
- @sock.closed?.should be_false
+ @sock.closed?.should == false
@sock.close
end
it "binds to a port" do
- -> { @sock.bind(@sockaddr) }.should_not raise_error
+ -> { @sock.bind(@sockaddr) }.should_not.raise
end
it "returns 0 if successful" do
@@ -23,12 +23,12 @@ describe "Socket#bind on SOCK_DGRAM socket" do
it "raises Errno::EINVAL when already bound" do
@sock.bind(@sockaddr)
- -> { @sock.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
+ -> { @sock.bind(@sockaddr) }.should.raise(Errno::EINVAL)
end
it "raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available from the local machine" do
sockaddr1 = Socket.pack_sockaddr_in(0, "4.3.2.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EADDRNOTAVAIL)
end
platform_is_not :windows, :cygwin do
@@ -36,7 +36,7 @@ describe "Socket#bind on SOCK_DGRAM socket" do
break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil
it "raises Errno::EACCES when the current user does not have permission to bind" do
sockaddr1 = Socket.pack_sockaddr_in(1, "127.0.0.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EACCES)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EACCES)
end
end
end
@@ -50,12 +50,12 @@ describe "Socket#bind on SOCK_STREAM socket" do
end
after :each do
- @sock.closed?.should be_false
+ @sock.closed?.should == false
@sock.close
end
it "binds to a port" do
- -> { @sock.bind(@sockaddr) }.should_not raise_error
+ -> { @sock.bind(@sockaddr) }.should_not.raise
end
it "returns 0 if successful" do
@@ -65,12 +65,12 @@ describe "Socket#bind on SOCK_STREAM socket" do
it "raises Errno::EINVAL when already bound" do
@sock.bind(@sockaddr)
- -> { @sock.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
+ -> { @sock.bind(@sockaddr) }.should.raise(Errno::EINVAL)
end
it "raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available from the local machine" do
sockaddr1 = Socket.pack_sockaddr_in(0, "4.3.2.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EADDRNOTAVAIL)
end
platform_is_not :windows, :cygwin do
@@ -78,7 +78,7 @@ describe "Socket#bind on SOCK_STREAM socket" do
break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil
it "raises Errno::EACCES when the current user does not have permission to bind" do
sockaddr1 = Socket.pack_sockaddr_in(1, "127.0.0.1")
- -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EACCES)
+ -> { @sock.bind(sockaddr1) }.should.raise(Errno::EACCES)
end
end
end
@@ -103,14 +103,14 @@ describe 'Socket#bind' do
it 'raises Errno::EINVAL when binding to an already bound port' do
@socket.bind(@sockaddr)
- -> { @socket.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
+ -> { @socket.bind(@sockaddr) }.should.raise(Errno::EINVAL)
end
it 'raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available' do
ip = family == Socket::AF_INET ? '4.3.2.1' : '::2'
sockaddr1 = Socket.sockaddr_in(0, ip)
- -> { @socket.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { @socket.bind(sockaddr1) }.should.raise(Errno::EADDRNOTAVAIL)
end
platform_is_not :windows do
@@ -120,7 +120,7 @@ describe 'Socket#bind' do
it 'raises Errno::EACCES when the user is not allowed to bind to the port' do
sockaddr1 = Socket.pack_sockaddr_in(1, ip_address)
- -> { @socket.bind(sockaddr1) }.should raise_error(Errno::EACCES)
+ -> { @socket.bind(sockaddr1) }.should.raise(Errno::EACCES)
end
end
end
@@ -138,7 +138,7 @@ describe 'Socket#bind' do
it 'binds to an Addrinfo' do
@socket.bind(@addr).should == 0
- @socket.local_address.should be_an_instance_of(Addrinfo)
+ @socket.local_address.should.instance_of?(Addrinfo)
end
it 'uses a new Addrinfo for the local address' do
diff --git a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
index 3cf667fc4a..dac24e3e5b 100644
--- a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
@@ -16,52 +16,50 @@ describe "Socket#connect_nonblock" do
@thread.join if @thread
end
- platform_is_not :solaris do
- it "connects the socket to the remote side" do
- port = nil
- accept = false
- @thread = Thread.new do
- server = TCPServer.new(@hostname, 0)
- port = server.addr[1]
- Thread.pass until accept
- conn = server.accept
- conn << "hello!"
- conn.close
- server.close
- end
-
- Thread.pass until port
+ it "connects the socket to the remote side" do
+ port = nil
+ accept = false
+ @thread = Thread.new do
+ server = TCPServer.new(@hostname, 0)
+ port = server.addr[1]
+ Thread.pass until accept
+ conn = server.accept
+ conn << "hello!"
+ conn.close
+ server.close
+ end
- addr = Socket.sockaddr_in(port, @hostname)
- begin
- @socket.connect_nonblock(addr)
- rescue Errno::EINPROGRESS
- end
+ Thread.pass until port
- accept = true
- IO.select nil, [@socket]
+ addr = Socket.sockaddr_in(port, @hostname)
+ begin
+ @socket.connect_nonblock(addr)
+ rescue Errno::EINPROGRESS
+ end
- begin
- @socket.connect_nonblock(addr)
- rescue Errno::EISCONN
- # Not all OS's use this errno, so we trap and ignore it
- end
+ accept = true
+ IO.select nil, [@socket]
- @socket.read(6).should == "hello!"
+ begin
+ @socket.connect_nonblock(addr)
+ rescue Errno::EISCONN
+ # Not all OS's use this errno, so we trap and ignore it
end
+
+ @socket.read(6).should == "hello!"
end
- platform_is_not :freebsd, :solaris, :aix do
+ platform_is_not :freebsd, :aix do
it "raises Errno::EINPROGRESS when the connect would block" do
-> do
@socket.connect_nonblock(@addr)
- end.should raise_error(Errno::EINPROGRESS)
+ end.should.raise(Errno::EINPROGRESS)
end
it "raises Errno::EINPROGRESS with IO::WaitWritable mixed in when the connect would block" do
-> do
@socket.connect_nonblock(@addr)
- end.should raise_error(IO::WaitWritable)
+ end.should.raise(IO::WaitWritable)
end
it "returns :wait_writable in exceptionless mode when the connect would block" do
@@ -95,7 +93,7 @@ describe 'Socket#connect_nonblock' do
end
it 'raises TypeError when passed an Integer' do
- -> { @client.connect_nonblock(666) }.should raise_error(TypeError)
+ -> { @client.connect_nonblock(666) }.should.raise(TypeError)
end
end
@@ -124,7 +122,7 @@ describe 'Socket#connect_nonblock' do
# as it's too implementation-dependent and checking for connect()
# errors is futile anyways because of TOCTOU
@client.connect_nonblock(@server.connect_address)
- }.should raise_error(Errno::EISCONN)
+ }.should.raise(Errno::EISCONN)
end
it 'returns 0 when already connected in exceptionless mode' do
@@ -135,13 +133,13 @@ describe 'Socket#connect_nonblock' do
end
end
- platform_is_not :freebsd, :solaris do
+ platform_is_not :freebsd do
it 'raises IO:EINPROGRESSWaitWritable when the connection would block' do
@server.bind(@sockaddr)
-> {
@client.connect_nonblock(@server.connect_address)
- }.should raise_error(IO::EINPROGRESSWaitWritable)
+ }.should.raise(IO::EINPROGRESSWaitWritable)
end
end
end
diff --git a/spec/ruby/library/socket/socket/connect_spec.rb b/spec/ruby/library/socket/socket/connect_spec.rb
index 130379ce2b..c928b66c53 100644
--- a/spec/ruby/library/socket/socket/connect_spec.rb
+++ b/spec/ruby/library/socket/socket/connect_spec.rb
@@ -40,7 +40,7 @@ describe 'Socket#connect' do
# as it's too implementation-dependent and checking for connect()
# errors is futile anyways because of TOCTOU
@client.connect(@server.getsockname)
- }.should raise_error(Errno::EISCONN)
+ }.should.raise(Errno::EISCONN)
end
platform_is_not :darwin do
@@ -70,7 +70,7 @@ describe 'Socket#connect' do
rescue Errno::ENETUNREACH
skip "Off line"
end
- }.should raise_error(IO::TimeoutError)
+ }.should.raise(IO::TimeoutError)
ensure
client.close
end
diff --git a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
index e0eff3cef4..7e5bdc9b25 100644
--- a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
@@ -11,7 +11,7 @@ describe "Socket.getaddrinfo" do
BasicSocket.do_not_reverse_lookup = @do_not_reverse_lookup
end
- platform_is_not :solaris, :windows do
+ platform_is_not :windows do
it "gets the address information" do
expected = []
# The check for AP_INET6's class is needed because ipaddr.rb adds
@@ -43,7 +43,7 @@ describe "Socket.getaddrinfo" do
addrinfo.each do |a|
case a.last
when Socket::IPPROTO_UDP, Socket::IPPROTO_TCP
- expected.should include(a)
+ expected.should.include?(a)
else
# don't check this. It's some weird protocol we don't know about
# so we can't spec it.
@@ -90,7 +90,7 @@ describe "Socket.getaddrinfo" do
["AF_INET6", 9, "::", "::", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP],
["AF_INET6", 9, "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0:0", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP]
]
- res.each { |a| expected.should include(a) }
+ res.each { |a| expected.should.include?(a) }
end
it "accepts empty addresses for IPv6 non-passive sockets" do
@@ -104,7 +104,15 @@ describe "Socket.getaddrinfo" do
["AF_INET6", 9, "::1", "::1", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP],
["AF_INET6", 9, "0:0:0:0:0:0:0:1", "0:0:0:0:0:0:0:1", Socket::AF_INET6, Socket::SOCK_STREAM, Socket::IPPROTO_TCP]
]
- res.each { |a| expected.should include(a) }
+ res.each { |a| expected.should.include?(a) }
+ end
+
+ it "raises ResolutionError when fails to resolve address" do
+ -> {
+ Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX")
+ }.should.raise(Socket::ResolutionError) { |e|
+ [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
+ }
end
end
end
@@ -112,7 +120,7 @@ end
describe 'Socket.getaddrinfo' do
describe 'without global reverse lookups' do
it 'returns an Array' do
- Socket.getaddrinfo(nil, 'ftp').should be_an_instance_of(Array)
+ Socket.getaddrinfo(nil, 'ftp').should.instance_of?(Array)
end
it 'accepts an Integer as the address family' do
@@ -123,8 +131,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an Integer as the address family using IPv6' do
@@ -135,8 +143,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '::1'
array[3].should == '::1'
array[4].should == Socket::AF_INET6
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a Symbol as the address family' do
@@ -147,8 +155,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a Symbol as the address family using IPv6' do
@@ -159,8 +167,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '::1'
array[3].should == '::1'
array[4].should == Socket::AF_INET6
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a String as the address family' do
@@ -171,8 +179,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts a String as the address family using IPv6' do
@@ -183,8 +191,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '::1'
array[3].should == '::1'
array[4].should == Socket::AF_INET6
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an object responding to #to_str as the host' do
@@ -199,8 +207,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an object responding to #to_str as the address family' do
@@ -215,8 +223,8 @@ describe 'Socket.getaddrinfo' do
array[2].should == '127.0.0.1'
array[3].should == '127.0.0.1'
array[4].should == Socket::AF_INET
- array[5].should be_kind_of(Integer)
- array[6].should be_kind_of(Integer)
+ array[5].should.is_a?(Integer)
+ array[6].should.is_a?(Integer)
end
it 'accepts an Integer as the socket type' do
@@ -229,7 +237,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'accepts a Symbol as the socket type' do
@@ -242,7 +250,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'accepts a String as the socket type' do
@@ -255,7 +263,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'accepts an object responding to #to_str as the socket type' do
@@ -272,7 +280,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
platform_is_not :windows do
@@ -286,7 +294,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_DGRAM,
]
- [0, Socket::IPPROTO_UDP].should include(proto)
+ [0, Socket::IPPROTO_UDP].should.include?(proto)
end
end
@@ -301,7 +309,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
it 'performs a reverse lookup when the reverse_lookup argument is true' do
@@ -311,7 +319,7 @@ describe 'Socket.getaddrinfo' do
addr[0].should == 'AF_INET'
addr[1].should == 21
- addr[2].should be_an_instance_of(String)
+ addr[2].should.instance_of?(String)
addr[2].should_not == addr[3]
addr[3].should == '127.0.0.1'
@@ -324,7 +332,7 @@ describe 'Socket.getaddrinfo' do
addr[0].should == 'AF_INET'
addr[1].should == 21
- addr[2].should be_an_instance_of(String)
+ addr[2].should.instance_of?(String)
addr[2].should_not == addr[3]
addr[3].should == '127.0.0.1'
@@ -341,7 +349,7 @@ describe 'Socket.getaddrinfo' do
Socket::AF_INET,
Socket::SOCK_STREAM,
]
- [0, Socket::IPPROTO_TCP].should include(proto)
+ [0, Socket::IPPROTO_TCP].should.include?(proto)
end
end
@@ -364,7 +372,7 @@ describe 'Socket.getaddrinfo' do
# We don't have control over this value and there's no way to test this
# without relying on Socket.getaddrinfo()'s own behaviour (meaning this
# test would faily any way of the method was not implemented correctly).
- addr[2].should be_an_instance_of(String)
+ addr[2].should.instance_of?(String)
addr[2].should_not == addr[3]
addr[3].should == '127.0.0.1'
diff --git a/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb b/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb
index a4c8355520..bf6d63dbe9 100644
--- a/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb
+++ b/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket.gethostbyaddr' do
describe 'without an explicit address family' do
it 'returns an Array' do
- suppress_warning { Socket.gethostbyaddr(@addr) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr) }.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -18,18 +18,15 @@ describe 'Socket.gethostbyaddr' do
@array = suppress_warning { Socket.gethostbyaddr(@addr) }
end
- # RubyCI Solaris 11x defines 127.0.0.1 as unstable11x
- platform_is_not :"solaris2.11" do
- it 'includes the hostname as the first value' do
- @array[0].should == SocketSpecs.hostname_reverse_lookup
- end
+ it 'includes the hostname as the first value' do
+ @array[0].should == SocketSpecs.hostname_reverse_lookup
end
it 'includes the aliases as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
@array[1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
@@ -41,7 +38,7 @@ describe 'Socket.gethostbyaddr' do
@array[3].should == @addr
@array[4..-1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
end
@@ -49,15 +46,15 @@ describe 'Socket.gethostbyaddr' do
describe 'with an explicit address family' do
it 'returns an Array when using an Integer as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET) }.should.instance_of?(Array)
end
it 'returns an Array when using a Symbol as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, :INET) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, :INET) }.should.instance_of?(Array)
end
it 'raises SocketError when the address is not supported by the family' do
- -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET6) } }.should raise_error(SocketError)
+ -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET6) } }.should.raise(SocketError)
end
end
end
@@ -70,7 +67,7 @@ describe 'Socket.gethostbyaddr' do
describe 'without an explicit address family' do
it 'returns an Array' do
- suppress_warning { Socket.gethostbyaddr(@addr) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr) }.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -83,10 +80,10 @@ describe 'Socket.gethostbyaddr' do
end
it 'includes the aliases as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
@array[1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
@@ -95,10 +92,10 @@ describe 'Socket.gethostbyaddr' do
end
it 'includes all address strings as the remaining values' do
- @array[3].should be_an_instance_of(String)
+ @array[3].should.instance_of?(String)
@array[4..-1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
end
@@ -106,16 +103,16 @@ describe 'Socket.gethostbyaddr' do
describe 'with an explicit address family' do
it 'returns an Array when using an Integer as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET6) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, Socket::AF_INET6) }.should.instance_of?(Array)
end
it 'returns an Array when using a Symbol as the address family' do
- suppress_warning { Socket.gethostbyaddr(@addr, :INET6) }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyaddr(@addr, :INET6) }.should.instance_of?(Array)
end
platform_is_not :windows, :wsl do
it 'raises SocketError when the address is not supported by the family' do
- -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET) } }.should raise_error(SocketError)
+ -> { suppress_warning { Socket.gethostbyaddr(@addr, :INET) } }.should.raise(SocketError)
end
end
end
diff --git a/spec/ruby/library/socket/socket/gethostbyname_spec.rb b/spec/ruby/library/socket/socket/gethostbyname_spec.rb
index 0858e255e4..326fe26094 100644
--- a/spec/ruby/library/socket/socket/gethostbyname_spec.rb
+++ b/spec/ruby/library/socket/socket/gethostbyname_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../spec_helper'
require_relative '../fixtures/classes'
@@ -16,7 +16,7 @@ end
describe 'Socket.gethostbyname' do
it 'returns an Array' do
- suppress_warning { Socket.gethostbyname('127.0.0.1') }.should be_an_instance_of(Array)
+ suppress_warning { Socket.gethostbyname('127.0.0.1') }.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -29,10 +29,10 @@ describe 'Socket.gethostbyname' do
end
it 'includes the aliases as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
@array[1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
@@ -43,10 +43,10 @@ describe 'Socket.gethostbyname' do
end
it 'includes the address strings as the remaining values' do
- @array[3].should be_an_instance_of(String)
+ @array[3].should.instance_of?(String)
@array[4..-1].each do |val|
- val.should be_an_instance_of(String)
+ val.should.instance_of?(String)
end
end
end
diff --git a/spec/ruby/library/socket/socket/getifaddrs_spec.rb b/spec/ruby/library/socket/socket/getifaddrs_spec.rb
index 7df542abe6..1b326605c8 100644
--- a/spec/ruby/library/socket/socket/getifaddrs_spec.rb
+++ b/spec/ruby/library/socket/socket/getifaddrs_spec.rb
@@ -1,23 +1,23 @@
require_relative '../spec_helper'
-platform_is_not :aix, :"solaris2.10" do
+platform_is_not :aix do
describe 'Socket.getifaddrs' do
before do
@ifaddrs = Socket.getifaddrs
end
it 'returns an Array' do
- @ifaddrs.should be_an_instance_of(Array)
+ @ifaddrs.should.instance_of?(Array)
end
describe 'the returned Array' do
it 'should not be empty' do
- @ifaddrs.should_not be_empty
+ @ifaddrs.should_not.empty?
end
it 'contains instances of Socket::Ifaddr' do
@ifaddrs.each do |ifaddr|
- ifaddr.should be_an_instance_of(Socket::Ifaddr)
+ ifaddr.should.instance_of?(Socket::Ifaddr)
end
end
end
@@ -25,19 +25,19 @@ describe 'Socket.getifaddrs' do
describe 'each returned Socket::Ifaddr' do
it 'has an interface index' do
@ifaddrs.each do |ifaddr|
- ifaddr.ifindex.should be_kind_of(Integer)
+ ifaddr.ifindex.should.is_a?(Integer)
end
end
it 'has an interface name' do
@ifaddrs.each do |ifaddr|
- ifaddr.name.should be_an_instance_of(String)
+ ifaddr.name.should.instance_of?(String)
end
end
it 'has a set of flags' do
@ifaddrs.each do |ifaddr|
- ifaddr.flags.should be_kind_of(Integer)
+ ifaddr.flags.should.is_a?(Integer)
end
end
end
@@ -49,17 +49,17 @@ describe 'Socket.getifaddrs' do
it 'is an Addrinfo' do
@addrs.all? do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
true
- end.should be_true
+ end.should == true
end
it 'has an address family' do
@addrs.all? do |addr|
- addr.afamily.should be_kind_of(Integer)
+ addr.afamily.should.is_a?(Integer)
addr.afamily.should_not == Socket::AF_UNSPEC
true
- end.should be_true
+ end.should == true
end
end
@@ -71,17 +71,17 @@ describe 'Socket.getifaddrs' do
it 'is an Addrinfo' do
@addrs.all? do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
true
- end.should be_true
+ end.should == true
end
it 'has an address family' do
@addrs.all? do |addr|
- addr.afamily.should be_kind_of(Integer)
+ addr.afamily.should.is_a?(Integer)
addr.afamily.should_not == Socket::AF_UNSPEC
true
- end.should be_true
+ end.should == true
end
end
@@ -92,24 +92,24 @@ describe 'Socket.getifaddrs' do
it 'is an Addrinfo' do
@addrs.all? do |addr|
- addr.should be_an_instance_of(Addrinfo)
+ addr.should.instance_of?(Addrinfo)
true
- end.should be_true
+ end.should == true
end
it 'has an address family' do
@addrs.all? do |addr|
- addr.afamily.should be_kind_of(Integer)
+ addr.afamily.should.is_a?(Integer)
addr.afamily.should_not == Socket::AF_UNSPEC
true
- end.should be_true
+ end.should == true
end
it 'has an IP address' do
@addrs.all? do |addr|
- addr.ip_address.should be_an_instance_of(String)
+ addr.ip_address.should.instance_of?(String)
true
- end.should be_true
+ end.should == true
end
end
end
diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
index 4f13bf484d..d0b77004de 100644
--- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
@@ -60,6 +60,14 @@ describe "Socket.getnameinfo" do
name_info = Socket.getnameinfo ["AF_INET", 9, 'foo', '127.0.0.1']
name_info[1].should == 'discard'
end
+
+ it "raises ResolutionError when fails to resolve address" do
+ -> {
+ Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"])
+ }.should.raise(Socket::ResolutionError) { |e|
+ [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
+ }
+ end
end
describe 'Socket.getnameinfo' do
@@ -69,7 +77,7 @@ describe 'Socket.getnameinfo' do
end
it 'raises SocketError or TypeError when using an invalid String' do
- -> { Socket.getnameinfo('cats') }.should raise_error(Exception) { |e|
+ -> { Socket.getnameinfo('cats') }.should.raise(Exception) { |e|
(e.is_a?(SocketError) || e.is_a?(TypeError)).should == true
}
end
@@ -102,7 +110,7 @@ describe 'Socket.getnameinfo' do
end
it 'raises ArgumentError when using an invalid Array' do
- -> { Socket.getnameinfo([family_name]) }.should raise_error(ArgumentError)
+ -> { Socket.getnameinfo([family_name]) }.should.raise(ArgumentError)
end
platform_is_not :windows do
@@ -122,7 +130,7 @@ describe 'Socket.getnameinfo' do
describe 'without custom flags' do
it 'returns an Array containing the hostname and service name' do
array = Socket.getnameinfo(@addr)
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array[0].should == @hostname
array[1].should == 'ftp'
end
@@ -131,7 +139,7 @@ describe 'Socket.getnameinfo' do
addr = [family_name, 21, ip_address, nil]
array = Socket.getnameinfo(addr)
- array.should be_an_instance_of(Array)
+ array.should.instance_of?(Array)
array[0].should == @hostname
array[1].should == 'ftp'
end
diff --git a/spec/ruby/library/socket/socket/getservbyname_spec.rb b/spec/ruby/library/socket/socket/getservbyname_spec.rb
index d361e619f2..4a88444fff 100644
--- a/spec/ruby/library/socket/socket/getservbyname_spec.rb
+++ b/spec/ruby/library/socket/socket/getservbyname_spec.rb
@@ -27,6 +27,6 @@ describe "Socket#getservbyname" do
end
it "raises a SocketError when the service or port is invalid" do
- -> { Socket.getservbyname('invalid') }.should raise_error(SocketError)
+ -> { Socket.getservbyname('invalid') }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/socket/getservbyport_spec.rb b/spec/ruby/library/socket/socket/getservbyport_spec.rb
index 563c592b54..7e4b75fa52 100644
--- a/spec/ruby/library/socket/socket/getservbyport_spec.rb
+++ b/spec/ruby/library/socket/socket/getservbyport_spec.rb
@@ -18,6 +18,6 @@ describe 'Socket.getservbyport' do
end
it 'raises SocketError for an unknown port number' do
- -> { Socket.getservbyport(0) }.should raise_error(SocketError)
+ -> { Socket.getservbyport(0) }.should.raise(SocketError)
end
end
diff --git a/spec/ruby/library/socket/socket/initialize_spec.rb b/spec/ruby/library/socket/socket/initialize_spec.rb
index f8337bcaa5..a8fb1c61fa 100644
--- a/spec/ruby/library/socket/socket/initialize_spec.rb
+++ b/spec/ruby/library/socket/socket/initialize_spec.rb
@@ -13,7 +13,7 @@ describe 'Socket#initialize' do
it 'returns a Socket' do
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
@@ -21,7 +21,7 @@ describe 'Socket#initialize' do
it 'returns a Socket' do
@socket = Socket.new(:INET, :STREAM)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
@@ -29,7 +29,7 @@ describe 'Socket#initialize' do
it 'returns a Socket' do
@socket = Socket.new('INET', 'STREAM')
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
end
@@ -43,7 +43,7 @@ describe 'Socket#initialize' do
@socket = Socket.new(family, type)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'raises TypeError when the #to_str method does not return a String' do
@@ -53,7 +53,7 @@ describe 'Socket#initialize' do
family.stub!(:to_str).and_return(Socket::AF_INET)
type.stub!(:to_str).and_return(Socket::SOCK_STREAM)
- -> { Socket.new(family, type) }.should raise_error(TypeError)
+ -> { Socket.new(family, type) }.should.raise(TypeError)
end
end
@@ -61,11 +61,11 @@ describe 'Socket#initialize' do
it 'returns a Socket when using an Integer' do
@socket = Socket.new(:INET, :STREAM, Socket::IPPROTO_TCP)
- @socket.should be_an_instance_of(Socket)
+ @socket.should.instance_of?(Socket)
end
it 'raises TypeError when using a Symbol' do
- -> { Socket.new(:INET, :STREAM, :TCP) }.should raise_error(TypeError)
+ -> { Socket.new(:INET, :STREAM, :TCP) }.should.raise(TypeError)
end
end
@@ -82,6 +82,6 @@ describe 'Socket#initialize' do
it "sets the socket to binary mode" do
@socket = Socket.new(:INET, :STREAM)
- @socket.binmode?.should be_true
+ @socket.binmode?.should == true
end
end
diff --git a/spec/ruby/library/socket/socket/ip_address_list_spec.rb b/spec/ruby/library/socket/socket/ip_address_list_spec.rb
index f97c2d7f85..2c4e008af1 100644
--- a/spec/ruby/library/socket/socket/ip_address_list_spec.rb
+++ b/spec/ruby/library/socket/socket/ip_address_list_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
describe 'Socket.ip_address_list' do
it 'returns an Array' do
- Socket.ip_address_list.should be_an_instance_of(Array)
+ Socket.ip_address_list.should.instance_of?(Array)
end
describe 'the returned Array' do
@@ -11,12 +11,12 @@ describe 'Socket.ip_address_list' do
end
it 'is not empty' do
- @array.should_not be_empty
+ @array.should_not.empty?
end
it 'contains Addrinfo objects' do
@array.each do |klass|
- klass.should be_an_instance_of(Addrinfo)
+ klass.should.instance_of?(Addrinfo)
end
end
end
@@ -28,8 +28,8 @@ describe 'Socket.ip_address_list' do
it 'has a non-empty IP address' do
@array.each do |addr|
- addr.ip_address.should be_an_instance_of(String)
- addr.ip_address.should_not be_empty
+ addr.ip_address.should.instance_of?(String)
+ addr.ip_address.should_not.empty?
end
end
diff --git a/spec/ruby/library/socket/socket/listen_spec.rb b/spec/ruby/library/socket/socket/listen_spec.rb
index 4d2aedab19..7986a0225c 100644
--- a/spec/ruby/library/socket/socket/listen_spec.rb
+++ b/spec/ruby/library/socket/socket/listen_spec.rb
@@ -7,7 +7,7 @@ describe "Socket#listen" do
end
after :each do
- @socket.closed?.should be_false
+ @socket.closed?.should == false
@socket.close
end
@@ -35,7 +35,7 @@ describe 'Socket#listen' do
end
it 'raises Errno::EOPNOTSUPP or Errno::EACCES' do
- -> { @server.listen(1) }.should raise_error { |e|
+ -> { @server.listen(1) }.should.raise { |e|
[Errno::EOPNOTSUPP, Errno::EACCES].should.include?(e.class)
}
end
@@ -59,7 +59,7 @@ describe 'Socket#listen' do
end
it "raises when the given argument can't be coerced to an Integer" do
- -> { @server.listen('cats') }.should raise_error(TypeError)
+ -> { @server.listen('cats') }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/socket/local_address_spec.rb b/spec/ruby/library/socket/socket/local_address_spec.rb
index 3687f93a0c..86b053fc3e 100644
--- a/spec/ruby/library/socket/socket/local_address_spec.rb
+++ b/spec/ruby/library/socket/socket/local_address_spec.rb
@@ -10,7 +10,7 @@ describe 'Socket#local_address' do
end
it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
+ @sock.local_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
index 01b42bcc52..ab29435a1d 100644
--- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
@@ -16,7 +16,7 @@ describe 'Socket#recvfrom_nonblock' do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
end
end
@@ -29,7 +29,7 @@ describe 'Socket#recvfrom_nonblock' do
describe 'without any data available' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable with exception: false' do
@@ -47,7 +47,7 @@ describe 'Socket#recvfrom_nonblock' do
IO.select([@server])
ret = @server.recvfrom_nonblock(1)
- ret.should be_an_instance_of(Array)
+ ret.should.instance_of?(Array)
ret.length.should == 2
end
end
@@ -98,7 +98,7 @@ describe 'Socket#recvfrom_nonblock' do
end
it 'contains an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
end
@@ -158,61 +158,30 @@ describe 'Socket#recvfrom_nonblock' do
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- ready = false
+ it "returns nil on a closed stream socket" do
+ ready = false
- t = Thread.new do
- client, _ = @server.accept
+ t = Thread.new do
+ client, _ = @server.accept
- Thread.pass while !ready
- begin
- client.recvfrom_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recvfrom_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
- ready = true
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ ensure
+ client.close if client
end
- end
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- ready = false
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- t = Thread.new do
- client, _ = @server.accept
+ @client.connect(@server_addr)
+ @client.close
+ ready = true
- Thread.pass while !ready
- begin
- client.recvfrom_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
- ready = true
-
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_spec.rb b/spec/ruby/library/socket/socket/recvfrom_spec.rb
index 6ba39ffcaf..0f319fc47c 100644
--- a/spec/ruby/library/socket/socket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_spec.rb
@@ -39,7 +39,7 @@ describe 'Socket#recvfrom' do
it 'returns an Array containing the data and an Addrinfo' do
ret = @server.recvfrom(1)
- ret.should be_an_instance_of(Array)
+ ret.should.instance_of?(Array)
ret.length.should == 2
end
@@ -53,7 +53,7 @@ describe 'Socket#recvfrom' do
end
it 'contains an Addrinfo at index 1' do
- @array[1].should be_an_instance_of(Addrinfo)
+ @array[1].should.instance_of?(Addrinfo)
end
end
@@ -111,43 +111,21 @@ describe 'Socket#recvfrom' do
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client, _ = @server.accept
- client.recvfrom(10)
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client, _ = @server.accept
+ client.recvfrom(10)
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client, _ = @server.accept
- client.recvfrom(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not == nil
- @client.connect(@server_addr)
- @client.close
+ @client.connect(@server_addr)
+ @client.close
- t.value.should be_nil
- end
+ t.value.should == nil
end
end
diff --git a/spec/ruby/library/socket/socket/remote_address_spec.rb b/spec/ruby/library/socket/socket/remote_address_spec.rb
index 24d60d7f58..f72ec50ed7 100644
--- a/spec/ruby/library/socket/socket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/socket/remote_address_spec.rb
@@ -22,7 +22,7 @@ describe 'Socket#remote_address' do
end
it 'returns an Addrinfo' do
- @client.remote_address.should be_an_instance_of(Addrinfo)
+ @client.remote_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/socket/sysaccept_spec.rb b/spec/ruby/library/socket/socket/sysaccept_spec.rb
index 92ac21124e..3e7078f745 100644
--- a/spec/ruby/library/socket/socket/sysaccept_spec.rb
+++ b/spec/ruby/library/socket/socket/sysaccept_spec.rb
@@ -15,7 +15,7 @@ describe 'Socket#sysaccept' do
platform_is :linux do # hangs on other platforms
describe 'using an unbound socket' do
it 'raises Errno::EINVAL' do
- -> { @server.sysaccept }.should raise_error(Errno::EINVAL)
+ -> { @server.sysaccept }.should.raise(Errno::EINVAL)
end
end
@@ -25,7 +25,7 @@ describe 'Socket#sysaccept' do
end
it 'raises Errno::EINVAL' do
- -> { @server.sysaccept }.should raise_error(Errno::EINVAL)
+ -> { @server.sysaccept }.should.raise(Errno::EINVAL)
end
end
end
@@ -59,7 +59,7 @@ describe 'Socket#sysaccept' do
@client.connect(@server_addr)
- thread.value.should be_an_instance_of(Array)
+ thread.value.should.instance_of?(Array)
end
end
@@ -76,8 +76,8 @@ describe 'Socket#sysaccept' do
it 'returns an Array containing an Integer and an Addrinfo' do
@fd, addrinfo = @server.sysaccept
- @fd.should be_kind_of(Integer)
- addrinfo.should be_an_instance_of(Addrinfo)
+ @fd.should.is_a?(Integer)
+ addrinfo.should.instance_of?(Addrinfo)
end
it 'returns a new file descriptor' do
diff --git a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb
index a46c6df5c6..4e39d01d72 100644
--- a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb
@@ -47,8 +47,8 @@ describe 'Socket.tcp_server_loop' do
# complete.
thread.join
- @sock.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
+ @sock.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb b/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb
index bd496d3015..b6cdb3c583 100644
--- a/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb
+++ b/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb
@@ -13,16 +13,16 @@ describe 'Socket.tcp_server_sockets' do
it 'returns an Array of Socket objects' do
@sockets = Socket.tcp_server_sockets(0)
- @sockets.should be_an_instance_of(Array)
- @sockets[0].should be_an_instance_of(Socket)
+ @sockets.should.instance_of?(Array)
+ @sockets[0].should.instance_of?(Socket)
end
end
describe 'with a block' do
it 'yields the sockets to the supplied block' do
Socket.tcp_server_sockets(0) do |sockets|
- sockets.should be_an_instance_of(Array)
- sockets[0].should be_an_instance_of(Socket)
+ sockets.should.instance_of?(Array)
+ sockets[0].should.instance_of?(Socket)
end
end
diff --git a/spec/ruby/library/socket/socket/tcp_spec.rb b/spec/ruby/library/socket/socket/tcp_spec.rb
index faf020b1ea..cc3c9381c7 100644
--- a/spec/ruby/library/socket/socket/tcp_spec.rb
+++ b/spec/ruby/library/socket/socket/tcp_spec.rb
@@ -22,12 +22,12 @@ describe 'Socket.tcp' do
it 'returns a Socket when no block is given' do
@client = Socket.tcp(@host, @port)
- @client.should be_an_instance_of(Socket)
+ @client.should.instance_of?(Socket)
end
it 'yields the Socket when a block is given' do
Socket.tcp(@host, @port) do |socket|
- socket.should be_an_instance_of(Socket)
+ socket.should.instance_of?(Socket)
end
end
@@ -51,20 +51,38 @@ describe 'Socket.tcp' do
it 'raises ArgumentError when 6 arguments are provided' do
-> {
Socket.tcp(@host, @port, @host, 0, {:connect_timeout => 1}, 10)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it 'connects to the server' do
@client = Socket.tcp(@host, @port)
-
@client.write('hello')
-
connection, _ = @server.accept
-
begin
connection.recv(5).should == 'hello'
ensure
connection.close
end
end
+
+ ruby_version_is "4.0" do
+ it 'connects to the server when passed open_timeout argument' do
+ @client = Socket.tcp(@host, @port, open_timeout: 60)
+ @client.write('open_timeout')
+ connection, _ = @server.accept
+ begin
+ connection.recv(12).should == 'open_timeout'
+ ensure
+ connection.close
+ end
+ end
+
+ it 'raises Errno::ETIMEDOUT with :open_timeout when no server is listening on the given address' do
+ -> {
+ Socket.tcp("192.0.2.1", 80, open_timeout: 0)
+ }.should.raise(Errno::ETIMEDOUT)
+ rescue Errno::ENETUNREACH
+ skip "all network interfaces down"
+ end
+ end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb
index cb8c5c5587..9197509f1f 100644
--- a/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb
@@ -41,7 +41,7 @@ describe 'Socket.udp_server_loop_on' do
end
msg.should == 'hello'
- src.should be_an_instance_of(Socket::UDPSource)
+ src.should.instance_of?(Socket::UDPSource)
end
end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb
index fc030e75b9..d44d522c20 100644
--- a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb
@@ -50,10 +50,10 @@ describe 'Socket.udp_server_loop' do
end
end
- msg.should == 'hello'
- src.should be_an_instance_of(Socket::UDPSource)
-
thread.join
+
+ msg.should == 'hello'
+ src.should.instance_of?(Socket::UDPSource)
end
end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_recv_spec.rb b/spec/ruby/library/socket/socket/udp_server_recv_spec.rb
index 47ed74bc03..34e2280558 100644
--- a/spec/ruby/library/socket/socket/udp_server_recv_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_recv_spec.rb
@@ -30,6 +30,6 @@ describe 'Socket.udp_server_recv' do
end
msg.should == 'hello'
- src.should be_an_instance_of(Socket::UDPSource)
+ src.should.instance_of?(Socket::UDPSource)
end
end
diff --git a/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb b/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb
index f8be672612..cb357977d6 100644
--- a/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb
+++ b/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb
@@ -13,16 +13,16 @@ describe 'Socket.udp_server_sockets' do
it 'returns an Array of Socket objects' do
@sockets = Socket.udp_server_sockets(0)
- @sockets.should be_an_instance_of(Array)
- @sockets[0].should be_an_instance_of(Socket)
+ @sockets.should.instance_of?(Array)
+ @sockets[0].should.instance_of?(Socket)
end
end
describe 'with a block' do
it 'yields the sockets to the supplied block' do
Socket.udp_server_sockets(0) do |sockets|
- sockets.should be_an_instance_of(Array)
- sockets[0].should be_an_instance_of(Socket)
+ sockets.should.instance_of?(Array)
+ sockets[0].should.instance_of?(Socket)
end
end
diff --git a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb
index 0f34d4a50b..9d35a995bc 100644
--- a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb
+++ b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb
@@ -1,58 +1,56 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unix_server_loop' do
- before do
- @path = SocketSpecs.socket_path
- end
+describe 'Socket.unix_server_loop' do
+ before do
+ @path = SocketSpecs.socket_path
+ end
- after do
- rm_r(@path) if File.file?(@path)
- end
+ after do
+ rm_r(@path) if File.file?(@path)
+ end
- describe 'when no connections are available' do
- it 'blocks the caller' do
- -> { Socket.unix_server_loop(@path) }.should block_caller
- end
+ describe 'when no connections are available' do
+ it 'blocks the caller' do
+ -> { Socket.unix_server_loop(@path) }.should block_caller
end
+ end
- describe 'when a connection is available' do
- before do
- @client = nil
- end
+ describe 'when a connection is available' do
+ before do
+ @client = nil
+ end
- after do
- @sock.close if @sock
- @client.close if @client
- end
+ after do
+ @sock.close if @sock
+ @client.close if @client
+ end
- it 'yields a Socket and an Addrinfo' do
- @sock, addr = nil
+ it 'yields a Socket and an Addrinfo' do
+ @sock, addr = nil
- thread = Thread.new do
- Socket.unix_server_loop(@path) do |socket, addrinfo|
- @sock = socket
- addr = addrinfo
+ thread = Thread.new do
+ Socket.unix_server_loop(@path) do |socket, addrinfo|
+ @sock = socket
+ addr = addrinfo
- break
- end
+ break
end
+ end
- SocketSpecs.loop_with_timeout do
- begin
- @client = Socket.unix(@path)
- rescue SystemCallError
- sleep 0.01
- :retry
- end
+ SocketSpecs.loop_with_timeout do
+ begin
+ @client = Socket.unix(@path)
+ rescue SystemCallError
+ sleep 0.01
+ :retry
end
+ end
- thread.join
+ thread.join
- @sock.should be_an_instance_of(Socket)
- addr.should be_an_instance_of(Addrinfo)
- end
+ @sock.should.instance_of?(Socket)
+ addr.should.instance_of?(Addrinfo)
end
end
end
diff --git a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb
index fc357740fa..da9671bf8c 100644
--- a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb
+++ b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb
@@ -1,48 +1,46 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unix_server_socket' do
+describe 'Socket.unix_server_socket' do
+ before do
+ @path = SocketSpecs.socket_path
+ end
+
+ after do
+ rm_r(@path)
+ end
+
+ describe 'when no block is given' do
before do
- @path = SocketSpecs.socket_path
+ @socket = nil
end
after do
- rm_r(@path)
+ @socket.close
end
- describe 'when no block is given' do
- before do
- @socket = nil
- end
-
- after do
- @socket.close
- end
+ it 'returns a Socket' do
+ @socket = Socket.unix_server_socket(@path)
- it 'returns a Socket' do
- @socket = Socket.unix_server_socket(@path)
-
- @socket.should be_an_instance_of(Socket)
- end
+ @socket.should.instance_of?(Socket)
end
+ end
- describe 'when a block is given' do
- it 'yields a Socket' do
- Socket.unix_server_socket(@path) do |sock|
- sock.should be_an_instance_of(Socket)
- end
+ describe 'when a block is given' do
+ it 'yields a Socket' do
+ Socket.unix_server_socket(@path) do |sock|
+ sock.should.instance_of?(Socket)
end
+ end
- it 'closes the Socket when the block returns' do
- socket = nil
-
- Socket.unix_server_socket(@path) do |sock|
- socket = sock
- end
+ it 'closes the Socket when the block returns' do
+ socket = nil
- socket.should be_an_instance_of(Socket)
+ Socket.unix_server_socket(@path) do |sock|
+ socket = sock
end
+
+ socket.should.instance_of?(Socket)
end
end
end
diff --git a/spec/ruby/library/socket/socket/unix_spec.rb b/spec/ruby/library/socket/socket/unix_spec.rb
index 4bff59bd4b..87f4938871 100644
--- a/spec/ruby/library/socket/socket/unix_spec.rb
+++ b/spec/ruby/library/socket/socket/unix_spec.rb
@@ -1,45 +1,43 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unix' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @socket = nil
- end
+describe 'Socket.unix' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @socket = nil
+ end
- after do
- @server.close
- @socket.close if @socket
+ after do
+ @server.close
+ @socket.close if @socket
- rm_r(@path)
- end
+ rm_r(@path)
+ end
- describe 'when no block is given' do
- it 'returns a Socket' do
- @socket = Socket.unix(@path)
+ describe 'when no block is given' do
+ it 'returns a Socket' do
+ @socket = Socket.unix(@path)
- @socket.should be_an_instance_of(Socket)
- end
+ @socket.should.instance_of?(Socket)
end
+ end
- describe 'when a block is given' do
- it 'yields a Socket' do
- Socket.unix(@path) do |sock|
- sock.should be_an_instance_of(Socket)
- end
+ describe 'when a block is given' do
+ it 'yields a Socket' do
+ Socket.unix(@path) do |sock|
+ sock.should.instance_of?(Socket)
end
+ end
- it 'closes the Socket when the block returns' do
- socket = nil
-
- Socket.unix(@path) do |sock|
- socket = sock
- end
+ it 'closes the Socket when the block returns' do
+ socket = nil
- socket.should.closed?
+ Socket.unix(@path) do |sock|
+ socket = sock
end
+
+ socket.should.closed?
end
end
end
diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb
index 79ec68cd18..35d46b0fd0 100644
--- a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb
@@ -32,15 +32,13 @@ describe "Socket.unpack_sockaddr_in" do
end
end
- with_feature :unix_socket do
- it "raises an ArgumentError when the sin_family is not AF_INET" do
- sockaddr = Socket.sockaddr_un '/tmp/x'
- -> { Socket.unpack_sockaddr_in sockaddr }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when the sin_family is not AF_INET" do
+ sockaddr = Socket.sockaddr_un '/tmp/x'
+ -> { Socket.unpack_sockaddr_in sockaddr }.should.raise(ArgumentError)
+ end
- it "raises an ArgumentError when passed addrinfo is not AF_INET/AF_INET6" do
- addrinfo = Addrinfo.unix('/tmp/sock')
- -> { Socket.unpack_sockaddr_in(addrinfo) }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when passed addrinfo is not AF_INET/AF_INET6" do
+ addrinfo = Addrinfo.unix('/tmp/sock')
+ -> { Socket.unpack_sockaddr_in(addrinfo) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb
index 12f970f89b..85a941cfc2 100644
--- a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb
+++ b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb
@@ -1,26 +1,24 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'Socket.unpack_sockaddr_un' do
- it 'decodes sockaddr to unix path' do
- sockaddr = Socket.sockaddr_un('/tmp/sock')
- Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock'
- end
+describe 'Socket.unpack_sockaddr_un' do
+ it 'decodes sockaddr to unix path' do
+ sockaddr = Socket.sockaddr_un('/tmp/sock')
+ Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock'
+ end
- it 'returns unix path from a passed Addrinfo' do
- addrinfo = Addrinfo.unix('/tmp/sock')
- Socket.unpack_sockaddr_un(addrinfo).should == '/tmp/sock'
- end
+ it 'returns unix path from a passed Addrinfo' do
+ addrinfo = Addrinfo.unix('/tmp/sock')
+ Socket.unpack_sockaddr_un(addrinfo).should == '/tmp/sock'
+ end
- it 'raises an ArgumentError when the sa_family is not AF_UNIX' do
- sockaddr = Socket.sockaddr_in(0, '127.0.0.1')
- -> { Socket.unpack_sockaddr_un(sockaddr) }.should raise_error(ArgumentError)
- end
+ it 'raises an ArgumentError when the sa_family is not AF_UNIX' do
+ sockaddr = Socket.sockaddr_in(0, '127.0.0.1')
+ -> { Socket.unpack_sockaddr_un(sockaddr) }.should.raise(ArgumentError)
+ end
- it 'raises an ArgumentError when passed addrinfo is not AF_UNIX' do
- addrinfo = Addrinfo.tcp('127.0.0.1', 0)
- -> { Socket.unpack_sockaddr_un(addrinfo) }.should raise_error(ArgumentError)
- end
+ it 'raises an ArgumentError when passed addrinfo is not AF_UNIX' do
+ addrinfo = Addrinfo.tcp('127.0.0.1', 0)
+ -> { Socket.unpack_sockaddr_un(addrinfo) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/socket/spec_helper.rb b/spec/ruby/library/socket/spec_helper.rb
index 1121542dd5..86f3a61086 100644
--- a/spec/ruby/library/socket/spec_helper.rb
+++ b/spec/ruby/library/socket/spec_helper.rb
@@ -1,13 +1,14 @@
require_relative '../../spec_helper'
require 'socket'
-MSpec.enable_feature :sock_packet if Socket.const_defined?(:SOCK_PACKET)
-MSpec.enable_feature :unix_socket unless PlatformGuard.windows?
-MSpec.enable_feature :udp_cork if Socket.const_defined?(:UDP_CORK)
-MSpec.enable_feature :tcp_cork if Socket.const_defined?(:TCP_CORK)
-MSpec.enable_feature :pktinfo if Socket.const_defined?(:IP_PKTINFO)
-MSpec.enable_feature :ipv6_pktinfo if Socket.const_defined?(:IPV6_PKTINFO)
-MSpec.enable_feature :ip_mtu if Socket.const_defined?(:IP_MTU)
-MSpec.enable_feature :ipv6_nexthop if Socket.const_defined?(:IPV6_NEXTHOP)
-MSpec.enable_feature :tcp_info if Socket.const_defined?(:TCP_INFO)
-MSpec.enable_feature :ancillary_data if Socket.const_defined?(:AncillaryData)
+# We force enable all features on Linux because anyway Linux implements all these features,
+# and we want a constant number of spec examples across Ruby implementations, even if they don't define these constants.
+MSpec.enable_feature :sock_packet if platform_is(:linux) || Socket.const_defined?(:SOCK_PACKET)
+MSpec.enable_feature :udp_cork if platform_is(:linux) || Socket.const_defined?(:UDP_CORK)
+MSpec.enable_feature :tcp_cork if platform_is(:linux) || Socket.const_defined?(:TCP_CORK)
+MSpec.enable_feature :pktinfo if platform_is(:linux) || Socket.const_defined?(:IP_PKTINFO)
+MSpec.enable_feature :ipv6_pktinfo if platform_is(:linux) || Socket.const_defined?(:IPV6_PKTINFO)
+MSpec.enable_feature :ip_mtu if platform_is(:linux) || Socket.const_defined?(:IP_MTU)
+MSpec.enable_feature :ipv6_nexthop if platform_is(:linux) || Socket.const_defined?(:IPV6_NEXTHOP)
+MSpec.enable_feature :tcp_info if platform_is(:linux) || Socket.const_defined?(:TCP_INFO)
+MSpec.enable_feature :ancillary_data if platform_is(:linux) || Socket.const_defined?(:AncillaryData)
diff --git a/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb
index 91f6a327f0..ac08fe37c6 100644
--- a/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb
@@ -15,7 +15,7 @@ describe "Socket::TCPServer.accept_nonblock" do
@server.listen(5)
-> {
@server.accept_nonblock
- }.should raise_error(IO::WaitReadable)
+ }.should.raise(IO::WaitReadable)
c = TCPSocket.new("127.0.0.1", @port)
IO.select([@server])
@@ -25,7 +25,7 @@ describe "Socket::TCPServer.accept_nonblock" do
port.should == @port
address.should == "127.0.0.1"
- s.should be_kind_of(TCPSocket)
+ s.should.is_a?(TCPSocket)
c.close
s.close
@@ -33,12 +33,12 @@ describe "Socket::TCPServer.accept_nonblock" do
it "raises an IOError if the socket is closed" do
@server.close
- -> { @server.accept }.should raise_error(IOError)
+ -> { @server.accept }.should.raise(IOError)
end
describe 'without a connected client' do
it 'raises error' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable in exceptionless mode' do
@@ -59,7 +59,7 @@ describe 'TCPServer#accept_nonblock' do
describe 'without a connected client' do
it 'raises IO::WaitReadable' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
end
@@ -77,7 +77,7 @@ describe 'TCPServer#accept_nonblock' do
it 'returns a TCPSocket' do
IO.select([@server])
@socket = @server.accept_nonblock
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
end
end
diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb
index d8892cd5f0..f2aa0bf8e1 100644
--- a/spec/ruby/library/socket/tcpserver/accept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb
@@ -15,7 +15,7 @@ describe "TCPServer#accept" do
data = nil
t = Thread.new do
client = @server.accept
- client.should be_kind_of(TCPSocket)
+ client.should.is_a?(TCPSocket)
data = client.read(5)
client << "goodbye"
client.close
@@ -50,7 +50,7 @@ describe "TCPServer#accept" do
t = Thread.new {
-> {
@server.accept
- }.should raise_error(Exception, "interrupted")
+ }.should.raise(Exception, "interrupted")
}
Thread.pass while t.status and t.status != "sleep"
@@ -80,7 +80,7 @@ describe "TCPServer#accept" do
it "raises an IOError if the socket is closed" do
@server.close
- -> { @server.accept }.should raise_error(IOError)
+ -> { @server.accept }.should.raise(IOError)
end
end
@@ -112,7 +112,7 @@ describe 'TCPServer#accept' do
it 'returns a TCPSocket' do
@socket = @server.accept
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
platform_is_not :windows do
diff --git a/spec/ruby/library/socket/tcpserver/gets_spec.rb b/spec/ruby/library/socket/tcpserver/gets_spec.rb
index 417976d737..72a72fa2dc 100644
--- a/spec/ruby/library/socket/tcpserver/gets_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/gets_spec.rb
@@ -11,6 +11,6 @@ describe "TCPServer#gets" do
end
it "raises Errno::ENOTCONN on gets" do
- -> { @server.gets }.should raise_error(Errno::ENOTCONN)
+ -> { @server.gets }.should.raise(Errno::ENOTCONN)
end
end
diff --git a/spec/ruby/library/socket/tcpserver/initialize_spec.rb b/spec/ruby/library/socket/tcpserver/initialize_spec.rb
index 4ddd1f465f..517b014edc 100644
--- a/spec/ruby/library/socket/tcpserver/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/initialize_spec.rb
@@ -12,7 +12,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
@@ -24,7 +24,7 @@ describe 'TCPServer#initialize' do
end
it "sets the socket to binmode" do
- @server.binmode?.should be_true
+ @server.binmode?.should == true
end
end
@@ -38,7 +38,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
@@ -52,7 +52,7 @@ describe 'TCPServer#initialize' do
describe 'with a single String argument containing a non numeric value' do
it 'raises SocketError' do
- -> { TCPServer.new('cats') }.should raise_error(SocketError)
+ -> { TCPServer.new('cats') }.should.raise(SocketError)
end
end
@@ -67,7 +67,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given port argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
@@ -90,7 +90,7 @@ describe 'TCPServer#initialize' do
end
it 'sets the port to the given port argument' do
- @server.local_address.ip_port.should be_kind_of(Integer)
+ @server.local_address.ip_port.should.is_a?(Integer)
@server.local_address.ip_port.should > 0
end
diff --git a/spec/ruby/library/socket/tcpserver/listen_spec.rb b/spec/ruby/library/socket/tcpserver/listen_spec.rb
index c877fdced6..5b046ef6f7 100644
--- a/spec/ruby/library/socket/tcpserver/listen_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/listen_spec.rb
@@ -16,7 +16,7 @@ describe 'TCPServer#listen' do
end
it "raises when the given argument can't be coerced to an Integer" do
- -> { @server.listen('cats') }.should raise_error(TypeError)
+ -> { @server.listen('cats') }.should.raise(TypeError)
end
end
end
diff --git a/spec/ruby/library/socket/tcpserver/new_spec.rb b/spec/ruby/library/socket/tcpserver/new_spec.rb
index dd1ba676bd..70b8d4352e 100644
--- a/spec/ruby/library/socket/tcpserver/new_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/new_spec.rb
@@ -10,7 +10,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('127.0.0.1', 0)
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
# on some platforms (Mac), MRI
# returns comma at the end.
addr[2].should =~ /^#{SocketSpecs.hostname}\b/
@@ -20,7 +20,7 @@ describe "TCPServer.new" do
it "binds to localhost and a port with either IPv4 or IPv6" do
@server = TCPServer.new(SocketSpecs.hostname, 0)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
if addr[0] == 'AF_INET'
addr[2].should =~ /^#{SocketSpecs.hostname}\b/
addr[3].should == '127.0.0.1'
@@ -34,7 +34,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('', 0)
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
@@ -43,7 +43,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('', '0')
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
@@ -52,7 +52,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('', nil)
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
@@ -61,20 +61,20 @@ describe "TCPServer.new" do
@server = TCPServer.new('', '')
addr = @server.addr
addr[0].should == 'AF_INET'
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
addr[2].should == '0.0.0.0'
addr[3].should == '0.0.0.0'
end
it "coerces port to string, then determines port from that number or service name" do
- -> { TCPServer.new(SocketSpecs.hostname, Object.new) }.should raise_error(TypeError)
+ -> { TCPServer.new(SocketSpecs.hostname, Object.new) }.should.raise(TypeError)
port = Object.new
port.should_receive(:to_str).and_return("0")
@server = TCPServer.new(SocketSpecs.hostname, port)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
# TODO: This should also accept strings like 'https', but I don't know how to
# pick such a service port that will be able to reliably bind...
@@ -83,18 +83,18 @@ describe "TCPServer.new" do
it "has a single argument form and treats it as a port number" do
@server = TCPServer.new(0)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
end
it "coerces port to a string when it is the only argument" do
- -> { TCPServer.new(Object.new) }.should raise_error(TypeError)
+ -> { TCPServer.new(Object.new) }.should.raise(TypeError)
port = Object.new
port.should_receive(:to_str).and_return("0")
@server = TCPServer.new(port)
addr = @server.addr
- addr[1].should be_kind_of(Integer)
+ addr[1].should.is_a?(Integer)
end
it "does not use the given block and warns to use TCPServer::open" do
@@ -104,7 +104,7 @@ describe "TCPServer.new" do
end
it "raises Errno::EADDRNOTAVAIL when the address is unknown" do
- -> { TCPServer.new("1.2.3.4", 0) }.should raise_error(Errno::EADDRNOTAVAIL)
+ -> { TCPServer.new("1.2.3.4", 0) }.should.raise(Errno::EADDRNOTAVAIL)
end
# There is no way to make this fail-proof on all machines, because
@@ -114,7 +114,7 @@ describe "TCPServer.new" do
it "raises a SocketError when the host is unknown" do
-> {
TCPServer.new("--notavalidname", 0)
- }.should raise_error(SocketError)
+ }.should.raise(SocketError)
end
end
@@ -122,7 +122,7 @@ describe "TCPServer.new" do
@server = TCPServer.new('127.0.0.1', 0)
-> {
@server = TCPServer.new('127.0.0.1', @server.addr[1])
- }.should raise_error(Errno::EADDRINUSE)
+ }.should.raise(Errno::EADDRINUSE)
end
platform_is_not :windows, :aix do
diff --git a/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb b/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb
index bd7d33faf4..ed23bced23 100644
--- a/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb
@@ -21,7 +21,7 @@ describe "TCPServer#sysaccept" do
fd = @server.sysaccept
- fd.should be_kind_of(Integer)
+ fd.should.is_a?(Integer)
ensure
sock.close if sock && !sock.closed?
IO.for_fd(fd).close if fd
@@ -58,7 +58,7 @@ describe 'TCPServer#sysaccept' do
it 'returns a new file descriptor as an Integer' do
@fd = @server.sysaccept
- @fd.should be_kind_of(Integer)
+ @fd.should.is_a?(Integer)
@fd.should_not == @client.fileno
end
end
diff --git a/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb b/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb
index f0e98778f5..c6fe007827 100644
--- a/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
# TODO: verify these for windows
-describe "TCPSocket#gethostbyname" do
+describe "TCPSocket.gethostbyname" do
before :each do
suppress_warning do
@host_info = TCPSocket.gethostbyname(SocketSpecs.hostname)
@@ -10,7 +10,7 @@ describe "TCPSocket#gethostbyname" do
end
it "returns an array elements of information on the hostname" do
- @host_info.should be_kind_of(Array)
+ @host_info.should.is_a?(Array)
end
platform_is_not :windows do
@@ -20,12 +20,12 @@ describe "TCPSocket#gethostbyname" do
it "returns the address type as the third value" do
address_type = @host_info[2]
- [Socket::AF_INET, Socket::AF_INET6].include?(address_type).should be_true
+ [Socket::AF_INET, Socket::AF_INET6].include?(address_type).should == true
end
it "returns the IP address as the fourth value" do
ip = @host_info[3]
- ["127.0.0.1", "::1"].include?(ip).should be_true
+ ["127.0.0.1", "::1"].include?(ip).should == true
end
end
@@ -48,14 +48,14 @@ describe "TCPSocket#gethostbyname" do
end
it "returns any aliases to the address as second value" do
- @host_info[1].should be_kind_of(Array)
+ @host_info[1].should.is_a?(Array)
end
end
-describe 'TCPSocket#gethostbyname' do
+describe 'TCPSocket.gethostbyname' do
it 'returns an Array' do
suppress_warning do
- TCPSocket.gethostbyname('127.0.0.1').should be_an_instance_of(Array)
+ TCPSocket.gethostbyname('127.0.0.1').should.instance_of?(Array)
end
end
@@ -72,11 +72,11 @@ describe 'TCPSocket#gethostbyname' do
end
it 'includes an array of alternative hostnames as the 2nd value' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
end
it 'includes the address family as the 3rd value' do
- @array[2].should be_kind_of(Integer)
+ @array[2].should.is_a?(Integer)
end
it 'includes the IP addresses as all the remaining values' do
diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
index d7feb9751b..a33d0b16ba 100644
--- a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
@@ -31,7 +31,7 @@ describe 'TCPSocket#initialize' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'when no server is listening on the given address' do
it 'raises Errno::ECONNREFUSED' do
- -> { TCPSocket.new(ip_address, 666) }.should raise_error(Errno::ECONNREFUSED)
+ -> { TCPSocket.new(ip_address, 666) }.should.raise(Errno::ECONNREFUSED)
end
end
@@ -48,21 +48,21 @@ describe 'TCPSocket#initialize' do
it 'returns a TCPSocket when using an Integer as the port' do
@client = TCPSocket.new(ip_address, @port)
- @client.should be_an_instance_of(TCPSocket)
+ @client.should.instance_of?(TCPSocket)
end
it 'returns a TCPSocket when using a String as the port' do
@client = TCPSocket.new(ip_address, @port.to_s)
- @client.should be_an_instance_of(TCPSocket)
+ @client.should.instance_of?(TCPSocket)
end
it 'raises SocketError when the port number is a non numeric String' do
- -> { TCPSocket.new(ip_address, 'cats') }.should raise_error(SocketError)
+ -> { TCPSocket.new(ip_address, 'cats') }.should.raise(SocketError)
end
it 'set the socket to binmode' do
@client = TCPSocket.new(ip_address, @port)
- @client.binmode?.should be_true
+ @client.binmode?.should == true
end
it 'connects to the right address' do
diff --git a/spec/ruby/library/socket/tcpsocket/local_address_spec.rb b/spec/ruby/library/socket/tcpsocket/local_address_spec.rb
index ce66d5ff8f..5dcf741f29 100644
--- a/spec/ruby/library/socket/tcpsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/local_address_spec.rb
@@ -23,7 +23,7 @@ describe 'TCPSocket#local_address' do
end
it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
+ @sock.local_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb b/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb
index eb9dabc075..085d57b3f9 100644
--- a/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb
@@ -23,7 +23,7 @@ describe 'TCPSocket#remote_address' do
end
it 'returns an Addrinfo' do
- @sock.remote_address.should be_an_instance_of(Addrinfo)
+ @sock.remote_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb
index 90f8d7e6a2..9c15dced4f 100644
--- a/spec/ruby/library/socket/tcpsocket/shared/new.rb
+++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb
@@ -3,36 +3,32 @@ require_relative '../../fixtures/classes'
describe :tcpsocket_new, shared: true do
it "requires a hostname and a port as arguments" do
- -> { TCPSocket.send(@method) }.should raise_error(ArgumentError)
+ -> { TCPSocket.send(@method) }.should.raise(ArgumentError)
end
it "refuses the connection when there is no server to connect to" do
-> do
TCPSocket.send(@method, SocketSpecs.hostname, SocketSpecs.reserved_unused_port)
- end.should raise_error(SystemCallError) {|e|
- [Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL].should include(e.class)
+ end.should.raise(SystemCallError) {|e|
+ [Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL].should.include?(e.class)
}
end
- ruby_version_is ""..."3.2" do
- it 'raises Errno::ETIMEDOUT with :connect_timeout when no server is listening on the given address' do
- -> {
- TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
- }.should raise_error(Errno::ETIMEDOUT)
- rescue Errno::ENETUNREACH
- # In the case all network interfaces down.
- # raise_error cannot deal with multiple expected exceptions
- end
+ it 'raises IO::TimeoutError with :connect_timeout when no server is listening on the given address' do
+ -> {
+ TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
+ }.should.raise(IO::TimeoutError)
+ rescue Errno::ENETUNREACH
+ skip "all network interfaces down"
end
- ruby_version_is "3.2" do
- it 'raises IO::TimeoutError with :connect_timeout when no server is listening on the given address' do
+ ruby_version_is "4.0" do
+ it 'raises IO::TimeoutError with :open_timeout when no server is listening on the given address' do
-> {
- TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
- }.should raise_error(IO::TimeoutError)
+ TCPSocket.send(@method, "192.0.2.1", 80, open_timeout: 0)
+ }.should.raise(IO::TimeoutError)
rescue Errno::ENETUNREACH
- # In the case all network interfaces down.
- # raise_error cannot deal with multiple expected exceptions
+ skip "all network interfaces down"
end
end
@@ -52,34 +48,43 @@ describe :tcpsocket_new, shared: true do
it "silently ignores 'nil' as the third parameter" do
@socket = TCPSocket.send(@method, @hostname, @server.port, nil)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "connects to a listening server with host and port" do
@socket = TCPSocket.send(@method, @hostname, @server.port)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "connects to a server when passed local_host argument" do
@socket = TCPSocket.send(@method, @hostname, @server.port, @hostname)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "connects to a server when passed local_host and local_port arguments" do
- server = TCPServer.new(SocketSpecs.hostname, 0)
+ retries = 0
+ max_retries = 3
+
begin
- available_port = server.addr[1]
- ensure
- server.close
+ retries += 1
+ server = TCPServer.new(SocketSpecs.hostname, 0)
+ begin
+ available_port = server.addr[1]
+ ensure
+ server.close
+ end
+ @socket = TCPSocket.send(@method, @hostname, @server.port,
+ @hostname, available_port)
+ rescue Errno::EADDRINUSE
+ raise if retries >= max_retries
+ retry
end
- @socket = TCPSocket.send(@method, @hostname, @server.port,
- @hostname, available_port)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
end
it "has an address once it has connected to a listening server" do
@socket = TCPSocket.send(@method, @hostname, @server.port)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
# TODO: Figure out how to abstract this. You can get AF_INET
# from 'Socket.getaddrinfo(hostname, nil)[0][3]' but socket.addr
@@ -94,13 +99,20 @@ describe :tcpsocket_new, shared: true do
@socket.addr[3].should == SocketSpecs.addr(:ipv6)
end
- @socket.addr[1].should be_kind_of(Integer)
+ @socket.addr[1].should.is_a?(Integer)
@socket.addr[2].should =~ /^#{@hostname}/
end
it "connects to a server when passed connect_timeout argument" do
@socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1)
- @socket.should be_an_instance_of(TCPSocket)
+ @socket.should.instance_of?(TCPSocket)
+ end
+
+ ruby_version_is "4.0" do
+ it "connects to a server when passed open_timeout argument" do
+ @socket = TCPSocket.send(@method, @hostname, @server.port, open_timeout: 1)
+ @socket.should.instance_of?(TCPSocket)
+ end
end
end
end
diff --git a/spec/ruby/library/socket/udpsocket/bind_spec.rb b/spec/ruby/library/socket/udpsocket/bind_spec.rb
index 08b386e941..974e701e71 100644
--- a/spec/ruby/library/socket/udpsocket/bind_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/bind_spec.rb
@@ -12,7 +12,7 @@ describe "UDPSocket#bind" do
it "binds the socket to a port" do
@socket.bind(SocketSpecs.hostname, 0)
- @socket.addr[1].should be_kind_of(Integer)
+ @socket.addr[1].should.is_a?(Integer)
end
it "raises Errno::EINVAL when already bound" do
@@ -20,7 +20,7 @@ describe "UDPSocket#bind" do
-> {
@socket.bind(SocketSpecs.hostname, @socket.addr[1])
- }.should raise_error(Errno::EINVAL)
+ }.should.raise(Errno::EINVAL)
end
it "receives a hostname and a port" do
diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
index ecf0043c10..c040187400 100644
--- a/spec/ruby/library/socket/udpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
@@ -7,27 +7,27 @@ describe 'UDPSocket#initialize' do
it 'initializes a new UDPSocket' do
@socket = UDPSocket.new
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'initializes a new UDPSocket using an Integer' do
@socket = UDPSocket.new(Socket::AF_INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'initializes a new UDPSocket using a Symbol' do
@socket = UDPSocket.new(:INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'initializes a new UDPSocket using a String' do
@socket = UDPSocket.new('INET')
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'sets the socket to binmode' do
@socket = UDPSocket.new(:INET)
- @socket.binmode?.should be_true
+ @socket.binmode?.should == true
end
platform_is_not :windows do
@@ -46,8 +46,8 @@ describe 'UDPSocket#initialize' do
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do
-> {
UDPSocket.new(666)
- }.should raise_error(SystemCallError) { |e|
- [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class)
+ }.should.raise(SystemCallError) { |e|
+ [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should.include?(e.class)
}
end
end
diff --git a/spec/ruby/library/socket/udpsocket/inspect_spec.rb b/spec/ruby/library/socket/udpsocket/inspect_spec.rb
deleted file mode 100644
index e212120b14..0000000000
--- a/spec/ruby/library/socket/udpsocket/inspect_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../spec_helper'
-
-describe 'UDPSocket#inspect' do
- before do
- @socket = UDPSocket.new
- @socket.bind('127.0.0.1', 0)
- end
-
- after do
- @socket.close
- end
-
- it 'returns a String with the fd, family, address and port' do
- port = @socket.addr[1]
- @socket.inspect.should == "#<UDPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>"
- end
-end
diff --git a/spec/ruby/library/socket/udpsocket/local_address_spec.rb b/spec/ruby/library/socket/udpsocket/local_address_spec.rb
index 92e4cc10c7..868d2f537e 100644
--- a/spec/ruby/library/socket/udpsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/local_address_spec.rb
@@ -28,7 +28,7 @@ describe 'UDPSocket#local_address' do
end
it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
+ @sock.local_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb
index 79bfcb624d..aff111927c 100644
--- a/spec/ruby/library/socket/udpsocket/new_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/new_spec.rb
@@ -8,22 +8,22 @@ describe 'UDPSocket.new' do
it 'without arguments' do
@socket = UDPSocket.new
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'using Integer argument' do
@socket = UDPSocket.new(Socket::AF_INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'using Symbol argument' do
@socket = UDPSocket.new(:INET)
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it 'using String argument' do
@socket = UDPSocket.new('INET')
- @socket.should be_an_instance_of(UDPSocket)
+ @socket.should.instance_of?(UDPSocket)
end
it "does not use the given block and warns to use UDPSocket::open" do
@@ -33,8 +33,8 @@ describe 'UDPSocket.new' do
end
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT if unsupported family passed' do
- -> { UDPSocket.new(-1) }.should raise_error(SystemCallError) { |e|
- [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class)
+ -> { UDPSocket.new(-1) }.should.raise(SystemCallError) { |e|
+ [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should.include?(e.class)
}
end
end
diff --git a/spec/ruby/library/socket/udpsocket/open_spec.rb b/spec/ruby/library/socket/udpsocket/open_spec.rb
index e4dbb2ee2a..7c77855372 100644
--- a/spec/ruby/library/socket/udpsocket/open_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/open_spec.rb
@@ -8,6 +8,6 @@ describe "UDPSocket.open" do
it "allows calls to open without arguments" do
@socket = UDPSocket.open
- @socket.should be_kind_of(UDPSocket)
+ @socket.should.is_a?(UDPSocket)
end
end
diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
index b804099589..460cf2c9a2 100644
--- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
@@ -16,7 +16,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
end
end
@@ -32,7 +32,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
describe 'without any data available' do
it 'raises IO::WaitReadable' do
- -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable)
+ -> { @server.recvfrom_nonblock(1) }.should.raise(IO::WaitReadable)
end
it 'returns :wait_readable with exception: false' do
@@ -48,7 +48,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
it 'returns an Array containing the data and an Array' do
IO.select([@server])
- @server.recvfrom_nonblock(1).should be_an_instance_of(Array)
+ @server.recvfrom_nonblock(1).should.instance_of?(Array)
end
it 'writes the data to the buffer when one is present' do
@@ -78,7 +78,7 @@ describe 'UDPSocket#recvfrom_nonblock' do
end
it 'contains an Array at index 1' do
- @array[1].should be_an_instance_of(Array)
+ @array[1].should.instance_of?(Array)
end
end
diff --git a/spec/ruby/library/socket/udpsocket/remote_address_spec.rb b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb
index 94889ce560..d1310200fc 100644
--- a/spec/ruby/library/socket/udpsocket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb
@@ -28,7 +28,7 @@ describe 'UDPSocket#remote_address' do
end
it 'returns an Addrinfo' do
- @sock.remote_address.should be_an_instance_of(Addrinfo)
+ @sock.remote_address.should.instance_of?(Addrinfo)
end
describe 'the returned Addrinfo' do
diff --git a/spec/ruby/library/socket/udpsocket/send_spec.rb b/spec/ruby/library/socket/udpsocket/send_spec.rb
index 6dd5f67bea..63f5b0dcc6 100644
--- a/spec/ruby/library/socket/udpsocket/send_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/send_spec.rb
@@ -34,7 +34,7 @@ describe "UDPSocket#send" do
@msg[0].should == "ad hoc"
@msg[1][0].should == "AF_INET"
- @msg[1][1].should be_kind_of(Integer)
+ @msg[1][1].should.is_a?(Integer)
@msg[1][3].should == "127.0.0.1"
end
@@ -46,7 +46,7 @@ describe "UDPSocket#send" do
@msg[0].should == "ad hoc"
@msg[1][0].should == "AF_INET"
- @msg[1][1].should be_kind_of(Integer)
+ @msg[1][1].should.is_a?(Integer)
@msg[1][3].should == "127.0.0.1"
end
@@ -59,7 +59,7 @@ describe "UDPSocket#send" do
@msg[0].should == "connection-based"
@msg[1][0].should == "AF_INET"
- @msg[1][1].should be_kind_of(Integer)
+ @msg[1][1].should.is_a?(Integer)
@msg[1][3].should == "127.0.0.1"
end
@@ -68,7 +68,7 @@ describe "UDPSocket#send" do
begin
-> do
@socket.send('1' * 100_000, 0, SocketSpecs.hostname, @port.to_s)
- end.should raise_error(Errno::EMSGSIZE)
+ end.should.raise(Errno::EMSGSIZE)
ensure
@socket.send("ad hoc", 0, SocketSpecs.hostname, @port)
@socket.close
@@ -96,7 +96,7 @@ describe 'UDPSocket#send' do
describe 'using a disconnected socket' do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
@@ -108,7 +108,7 @@ describe 'UDPSocket#send' do
it 'does not persist the connection after sending data' do
@client.send('hello', 0, @addr.ip_address, @addr.ip_port)
- -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
+ -> { @client.send('hello', 0) }.should.raise(SocketSpecs.dest_addr_req_error)
end
end
diff --git a/spec/ruby/library/socket/udpsocket/write_spec.rb b/spec/ruby/library/socket/udpsocket/write_spec.rb
index c971f29b62..d41ee078d8 100644
--- a/spec/ruby/library/socket/udpsocket/write_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/write_spec.rb
@@ -12,7 +12,7 @@ describe "UDPSocket#write" do
-> do
s2.write('1' * 100_000)
- end.should raise_error(Errno::EMSGSIZE)
+ end.should.raise(Errno::EMSGSIZE)
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
index dba3de7359..531d851658 100644
--- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
@@ -1,87 +1,85 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer#accept_nonblock" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
+describe "UNIXServer#accept_nonblock" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
- @socket = @server.accept_nonblock
- @client.send("foobar", 0)
- end
+ @socket = @server.accept_nonblock
+ @client.send("foobar", 0)
+ end
- after :each do
- @socket.close
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @socket.close
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "accepts a connection in a non-blocking way" do
- data = @socket.recvfrom(6).first
- data.should == "foobar"
- end
+ it "accepts a connection in a non-blocking way" do
+ data = @socket.recvfrom(6).first
+ data.should == "foobar"
+ end
- it "returns a UNIXSocket" do
- @socket.should be_kind_of(UNIXSocket)
- end
+ it "returns a UNIXSocket" do
+ @socket.should.is_a?(UNIXSocket)
+ end
+
+ it 'returns :wait_readable in exceptionless mode' do
+ @server.accept_nonblock(exception: false).should == :wait_readable
+ end
+end
- it 'returns :wait_readable in exceptionless mode' do
- @server.accept_nonblock(exception: false).should == :wait_readable
+describe 'UNIXServer#accept_nonblock' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
+
+ after do
+ @server.close
+ rm_r(@path)
+ end
+
+ describe 'without a client' do
+ it 'raises IO::WaitReadable' do
+ -> { @server.accept_nonblock }.should.raise(IO::WaitReadable)
end
end
- describe 'UNIXServer#accept_nonblock' do
+ describe 'with a client' do
before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @server.close
- rm_r(@path)
+ @client.close
+ @socket.close if @socket
end
- describe 'without a client' do
- it 'raises IO::WaitReadable' do
- -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
+ describe 'without any data' do
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept_nonblock
+ @socket.should.instance_of?(UNIXSocket)
end
end
- describe 'with a client' do
+ describe 'with data available' do
before do
- @client = UNIXSocket.new(@path)
- end
-
- after do
- @client.close
- @socket.close if @socket
+ @client.write('hello')
end
- describe 'without any data' do
- it 'returns a UNIXSocket' do
- @socket = @server.accept_nonblock
- @socket.should be_an_instance_of(UNIXSocket)
- end
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept_nonblock
+ @socket.should.instance_of?(UNIXSocket)
end
- describe 'with data available' do
- before do
- @client.write('hello')
- end
-
- it 'returns a UNIXSocket' do
+ describe 'the returned UNIXSocket' do
+ it 'can read the data written' do
@socket = @server.accept_nonblock
- @socket.should be_an_instance_of(UNIXSocket)
- end
-
- describe 'the returned UNIXSocket' do
- it 'can read the data written' do
- @socket = @server.accept_nonblock
- @socket.recv(5).should == 'hello'
- end
+ @socket.recv(5).should == 'hello'
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb
index 1305bc6220..8f3ea50966 100644
--- a/spec/ruby/library/socket/unixserver/accept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_spec.rb
@@ -1,126 +1,124 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer#accept" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- end
+describe "UNIXServer#accept" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ end
- after :each do
- @server.close if @server
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close if @server
+ SocketSpecs.rm_socket @path
+ end
- it "accepts what is written by the client" do
- client = UNIXSocket.open(@path)
+ it "accepts what is written by the client" do
+ client = UNIXSocket.open(@path)
- client.send('hello', 0)
+ client.send('hello', 0)
- sock = @server.accept
- begin
- data, info = sock.recvfrom(5)
+ sock = @server.accept
+ begin
+ data, info = sock.recvfrom(5)
- data.should == 'hello'
- info.should_not be_empty
- ensure
- sock.close
- client.close
- end
+ data.should == 'hello'
+ info.should_not.empty?
+ ensure
+ sock.close
+ client.close
end
+ end
- it "can be interrupted by Thread#kill" do
- t = Thread.new {
- @server.accept
- }
- Thread.pass while t.status and t.status != "sleep"
-
- # kill thread, ensure it dies in a reasonable amount of time
- t.kill
- a = 0
- while t.alive? and a < 5000
- sleep 0.001
- a += 1
- end
- a.should < 5000
+ it "can be interrupted by Thread#kill" do
+ t = Thread.new {
+ @server.accept
+ }
+ Thread.pass while t.status and t.status != "sleep"
+
+ # kill thread, ensure it dies in a reasonable amount of time
+ t.kill
+ a = 0
+ while t.alive? and a < 5000
+ sleep 0.001
+ a += 1
end
+ a.should < 5000
+ end
- it "can be interrupted by Thread#raise" do
- t = Thread.new {
- -> {
- @server.accept
- }.should raise_error(Exception, "interrupted")
- }
+ it "can be interrupted by Thread#raise" do
+ t = Thread.new {
+ -> {
+ @server.accept
+ }.should.raise(Exception, "interrupted")
+ }
- Thread.pass while t.status and t.status != "sleep"
- t.raise Exception, "interrupted"
- t.join
- end
+ Thread.pass while t.status and t.status != "sleep"
+ t.raise Exception, "interrupted"
+ t.join
end
end
-with_feature :unix_socket do
- describe 'UNIXServer#accept' do
+describe 'UNIXServer#accept' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
+
+ after do
+ @server.close
+ rm_r(@path)
+ end
+
+ describe 'without a client' do
+ it 'blocks the calling thread' do
+ -> { @server.accept }.should block_caller
+ end
+ end
+
+ describe 'with a client' do
before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @server.close
- rm_r(@path)
+ @client.close
+ @socket.close if @socket
end
- describe 'without a client' do
- it 'blocks the calling thread' do
- -> { @server.accept }.should block_caller
+ describe 'without any data' do
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept
+ @socket.should.instance_of?(UNIXSocket)
end
end
- describe 'with a client' do
+ describe 'with data available' do
before do
- @client = UNIXSocket.new(@path)
- end
-
- after do
- @client.close
- @socket.close if @socket
+ @client.write('hello')
end
- describe 'without any data' do
- it 'returns a UNIXSocket' do
- @socket = @server.accept
- @socket.should be_an_instance_of(UNIXSocket)
- end
+ it 'returns a UNIXSocket' do
+ @socket = @server.accept
+ @socket.should.instance_of?(UNIXSocket)
end
- describe 'with data available' do
- before do
- @client.write('hello')
- end
-
- it 'returns a UNIXSocket' do
+ describe 'the returned UNIXSocket' do
+ it 'can read the data written' do
@socket = @server.accept
- @socket.should be_an_instance_of(UNIXSocket)
+ @socket.recv(5).should == 'hello'
end
- describe 'the returned UNIXSocket' do
- it 'can read the data written' do
- @socket = @server.accept
- @socket.recv(5).should == 'hello'
- end
-
+ platform_is_not :windows do
it "is set to nonblocking" do
require 'io/nonblock'
@socket = @server.accept
@socket.should.nonblock?
end
+ end
- it "is set to close on exec" do
- @socket = @server.accept
- @socket.should.close_on_exec?
- end
+ it "is set to close on exec" do
+ @socket = @server.accept
+ @socket.should.close_on_exec?
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/for_fd_spec.rb b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
index 8cc55ef391..be1c2df4d7 100644
--- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb
+++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
@@ -1,23 +1,21 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer.for_fd" do
- before :each do
- @unix_path = SocketSpecs.socket_path
- @unix = UNIXServer.new(@unix_path)
- end
+describe "UNIXServer.for_fd" do
+ before :each do
+ @unix_path = SocketSpecs.socket_path
+ @unix = UNIXServer.new(@unix_path)
+ end
- after :each do
- @unix.close if @unix
- SocketSpecs.rm_socket @unix_path
- end
+ after :each do
+ @unix.close if @unix
+ SocketSpecs.rm_socket @unix_path
+ end
- it "can calculate the path" do
- b = UNIXServer.for_fd(@unix.fileno)
- b.autoclose = false
+ it "can calculate the path" do
+ b = UNIXServer.for_fd(@unix.fileno)
+ b.autoclose = false
- b.path.should == @unix_path
- end
+ b.path.should == @unix_path
end
end
diff --git a/spec/ruby/library/socket/unixserver/initialize_spec.rb b/spec/ruby/library/socket/unixserver/initialize_spec.rb
index 0cc49ef1eb..ca1dd301f0 100644
--- a/spec/ruby/library/socket/unixserver/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixserver/initialize_spec.rb
@@ -1,28 +1,26 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXServer#initialize' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- end
+describe 'UNIXServer#initialize' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
- after do
- @server.close if @server
- rm_r @path
- end
+ after do
+ @server.close if @server
+ rm_r @path
+ end
- it 'returns a new UNIXServer' do
- @server.should be_an_instance_of(UNIXServer)
- end
+ it 'returns a new UNIXServer' do
+ @server.should.instance_of?(UNIXServer)
+ end
- it 'sets the socket to binmode' do
- @server.binmode?.should be_true
- end
+ it 'sets the socket to binmode' do
+ @server.binmode?.should == true
+ end
- it 'raises Errno::EADDRINUSE when the socket is already in use' do
- -> { UNIXServer.new(@path) }.should raise_error(Errno::EADDRINUSE)
- end
+ it 'raises Errno::EADDRINUSE when the socket is already in use' do
+ -> { UNIXServer.new(@path) }.should.raise(Errno::EADDRINUSE)
end
end
diff --git a/spec/ruby/library/socket/unixserver/listen_spec.rb b/spec/ruby/library/socket/unixserver/listen_spec.rb
index b90b3bbb09..7938d648c4 100644
--- a/spec/ruby/library/socket/unixserver/listen_spec.rb
+++ b/spec/ruby/library/socket/unixserver/listen_spec.rb
@@ -1,21 +1,19 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXServer#listen' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- end
+describe 'UNIXServer#listen' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
- after do
- @server.close
+ after do
+ @server.close
- rm_r(@path)
- end
+ rm_r(@path)
+ end
- it 'returns 0' do
- @server.listen(1).should == 0
- end
+ it 'returns 0' do
+ @server.listen(1).should == 0
end
end
diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb
index a160e3ce5c..7d0c7bf76e 100644
--- a/spec/ruby/library/socket/unixserver/new_spec.rb
+++ b/spec/ruby/library/socket/unixserver/new_spec.rb
@@ -1,14 +1,12 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXServer.new" do
- it_behaves_like :unixserver_new, :new
+describe "UNIXServer.new" do
+ it_behaves_like :unixserver_new, :new
- it "does not use the given block and warns to use UNIXServer::open" do
- -> {
- @server = UNIXServer.new(@path) { raise }
- }.should complain(/warning: UNIXServer::new\(\) does not take block; use UNIXServer::open\(\) instead/)
- end
+ it "does not use the given block and warns to use UNIXServer::open" do
+ -> {
+ @server = UNIXServer.new(@path) { raise }
+ }.should complain(/warning: UNIXServer::new\(\) does not take block; use UNIXServer::open\(\) instead/)
end
end
diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb
index 16453dd3bd..c49df802d0 100644
--- a/spec/ruby/library/socket/unixserver/open_spec.rb
+++ b/spec/ruby/library/socket/unixserver/open_spec.rb
@@ -2,25 +2,23 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXServer.open" do
- it_behaves_like :unixserver_new, :open
+describe "UNIXServer.open" do
+ it_behaves_like :unixserver_new, :open
- before :each do
- @path = SocketSpecs.socket_path
- end
+ before :each do
+ @path = SocketSpecs.socket_path
+ end
- after :each do
- @server.close if @server
- @server = nil
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close if @server
+ @server = nil
+ SocketSpecs.rm_socket @path
+ end
- it "yields the new UNIXServer object to the block, if given" do
- UNIXServer.open(@path) do |unix|
- unix.path.should == @path
- unix.addr.should == ["AF_UNIX", @path]
- end
+ it "yields the new UNIXServer object to the block, if given" do
+ UNIXServer.open(@path) do |unix|
+ unix.path.should == @path
+ unix.addr.should == ["AF_UNIX", @path]
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb
index e59731878a..5970c01114 100644
--- a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb
@@ -1,51 +1,49 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXServer#sysaccept' do
+describe 'UNIXServer#sysaccept' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ end
+
+ after do
+ @server.close
+
+ rm_r(@path)
+ end
+
+ describe 'without a client' do
+ it 'blocks the calling thread' do
+ -> { @server.sysaccept }.should block_caller
+ end
+ end
+
+ describe 'with a client' do
before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
end
after do
- @server.close
-
- rm_r(@path)
+ Socket.for_fd(@fd).close if @fd
+ @client.close
end
- describe 'without a client' do
- it 'blocks the calling thread' do
- -> { @server.sysaccept }.should block_caller
+ describe 'without any data' do
+ it 'returns an Integer' do
+ @fd = @server.sysaccept
+ @fd.should.is_a?(Integer)
end
end
- describe 'with a client' do
+ describe 'with data available' do
before do
- @client = UNIXSocket.new(@path)
- end
-
- after do
- Socket.for_fd(@fd).close if @fd
- @client.close
+ @client.write('hello')
end
- describe 'without any data' do
- it 'returns an Integer' do
- @fd = @server.sysaccept
- @fd.should be_kind_of(Integer)
- end
- end
-
- describe 'with data available' do
- before do
- @client.write('hello')
- end
-
- it 'returns an Integer' do
- @fd = @server.sysaccept
- @fd.should be_kind_of(Integer)
- end
+ it 'returns an Integer' do
+ @fd = @server.sysaccept
+ @fd.should.is_a?(Integer)
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/addr_spec.rb b/spec/ruby/library/socket/unixsocket/addr_spec.rb
index d93e061312..b3ae2af5d8 100644
--- a/spec/ruby/library/socket/unixsocket/addr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb
@@ -1,35 +1,33 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#addr" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
- end
+describe "UNIXSocket#addr" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "returns an array" do
- @client.addr.should be_kind_of(Array)
- end
+ it "returns an array" do
+ @client.addr.should.is_a?(Array)
+ end
- it "returns the address family of this socket in an array" do
- @client.addr[0].should == "AF_UNIX"
- @server.addr[0].should == "AF_UNIX"
- end
+ it "returns the address family of this socket in an array" do
+ @client.addr[0].should == "AF_UNIX"
+ @server.addr[0].should == "AF_UNIX"
+ end
- it "returns the path of the socket in an array if it's a server" do
- @server.addr[1].should == @path
- end
+ it "returns the path of the socket in an array if it's a server" do
+ @server.addr[1].should == @path
+ end
- it "returns an empty string for path if it's a client" do
- @client.addr[1].should == ""
- end
+ it "returns an empty string for path if it's a client" do
+ @client.addr[1].should == ""
end
end
diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
index bf7896ab0e..ac30b93de0 100644
--- a/spec/ruby/library/socket/unixsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
@@ -1,48 +1,56 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXSocket#initialize' do
- describe 'using a non existing path' do
+describe 'UNIXSocket#initialize' do
+ describe 'using a non existing path' do
+ platform_is_not :windows do
it 'raises Errno::ENOENT' do
- -> { UNIXSocket.new(SocketSpecs.socket_path) }.should raise_error(Errno::ENOENT)
+ -> { UNIXSocket.new(SocketSpecs.socket_path) }.should.raise(Errno::ENOENT)
end
end
- describe 'using an existing socket path' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @socket = UNIXSocket.new(@path)
+ platform_is :windows do
+ # Why, Windows, why?
+ it 'raises Errno::ECONNREFUSED' do
+ -> { UNIXSocket.new(SocketSpecs.socket_path) }.should.raise(Errno::ECONNREFUSED)
end
+ end
+ end
- after do
- @socket.close
- @server.close
- rm_r(@path)
- end
+ describe 'using an existing socket path' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @socket = UNIXSocket.new(@path)
+ end
- it 'returns a new UNIXSocket' do
- @socket.should be_an_instance_of(UNIXSocket)
- end
+ after do
+ @socket.close
+ @server.close
+ rm_r(@path)
+ end
- it 'sets the socket path to an empty String' do
- @socket.path.should == ''
- end
+ it 'returns a new UNIXSocket' do
+ @socket.should.instance_of?(UNIXSocket)
+ end
- it 'sets the socket to binmode' do
- @socket.binmode?.should be_true
- end
+ it 'sets the socket path to an empty String' do
+ @socket.path.should == ''
+ end
+
+ it 'sets the socket to binmode' do
+ @socket.binmode?.should == true
+ end
+ platform_is_not :windows do
it 'sets the socket to nonblock' do
require 'io/nonblock'
@socket.should.nonblock?
end
+ end
- it 'sets the socket to close on exec' do
- @socket.should.close_on_exec?
- end
-
+ it 'sets the socket to close on exec' do
+ @socket.should.close_on_exec?
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/inspect_spec.rb b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
index a542ba6db5..77bb521069 100644
--- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
@@ -1,17 +1,15 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#inspect" do
- it "returns sockets fd for unnamed sockets" do
- begin
- s1, s2 = UNIXSocket.socketpair
- s1.inspect.should == "#<UNIXSocket:fd #{s1.fileno}>"
- s2.inspect.should == "#<UNIXSocket:fd #{s2.fileno}>"
- ensure
- s1.close
- s2.close
- end
+describe "UNIXSocket#inspect" do
+ it "returns sockets fd for unnamed sockets" do
+ begin
+ s1, s2 = UNIXSocket.socketpair
+ s1.inspect.should == "#<UNIXSocket:fd #{s1.fileno}>"
+ s2.inspect.should == "#<UNIXSocket:fd #{s2.fileno}>"
+ ensure
+ s1.close
+ s2.close
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
index 734253e7f5..fc504698c3 100644
--- a/spec/ruby/library/socket/unixsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
@@ -1,94 +1,92 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXSocket#local_address' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @client = UNIXSocket.new(@path)
- end
+describe 'UNIXSocket#local_address' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
+ end
- after do
- @client.close
- @server.close
+ after do
+ @client.close
+ @server.close
- rm_r(@path)
- end
-
- it 'returns an Addrinfo' do
- @client.local_address.should be_an_instance_of(Addrinfo)
- end
+ rm_r(@path)
+ end
- describe 'the returned Addrinfo' do
- platform_is_not :aix do
- it 'uses AF_UNIX as the address family' do
- @client.local_address.afamily.should == Socket::AF_UNIX
- end
+ it 'returns an Addrinfo' do
+ @client.local_address.should.instance_of?(Addrinfo)
+ end
- it 'uses PF_UNIX as the protocol family' do
- @client.local_address.pfamily.should == Socket::PF_UNIX
- end
+ describe 'the returned Addrinfo' do
+ platform_is_not :aix do
+ it 'uses AF_UNIX as the address family' do
+ @client.local_address.afamily.should == Socket::AF_UNIX
end
- it 'uses SOCK_STREAM as the socket type' do
- @client.local_address.socktype.should == Socket::SOCK_STREAM
+ it 'uses PF_UNIX as the protocol family' do
+ @client.local_address.pfamily.should == Socket::PF_UNIX
end
+ end
- platform_is_not :aix do
- it 'uses an empty socket path' do
- @client.local_address.unix_path.should == ''
- end
- end
+ it 'uses SOCK_STREAM as the socket type' do
+ @client.local_address.socktype.should == Socket::SOCK_STREAM
+ end
- it 'uses 0 as the protocol' do
- @client.local_address.protocol.should == 0
+ platform_is_not :aix do
+ it 'uses an empty socket path' do
+ @client.local_address.unix_path.should == ''
end
end
- end
- describe 'UNIXSocket#local_address with a UNIX socket pair' do
- before :each do
- @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
+ it 'uses 0 as the protocol' do
+ @client.local_address.protocol.should == 0
end
+ end
+end
- after :each do
- @sock.close
- @sock2.close
- end
+describe 'UNIXSocket#local_address with a UNIX socket pair' do
+ before :each do
+ @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
+ end
- it 'returns an Addrinfo' do
- @sock.local_address.should be_an_instance_of(Addrinfo)
- end
+ after :each do
+ @sock.close
+ @sock2.close
+ end
- describe 'the returned Addrinfo' do
- it 'uses AF_UNIX as the address family' do
- @sock.local_address.afamily.should == Socket::AF_UNIX
- end
+ it 'returns an Addrinfo' do
+ @sock.local_address.should.instance_of?(Addrinfo)
+ end
- it 'uses PF_UNIX as the protocol family' do
- @sock.local_address.pfamily.should == Socket::PF_UNIX
- end
+ describe 'the returned Addrinfo' do
+ it 'uses AF_UNIX as the address family' do
+ @sock.local_address.afamily.should == Socket::AF_UNIX
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @sock.local_address.socktype.should == Socket::SOCK_STREAM
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @sock.local_address.pfamily.should == Socket::PF_UNIX
+ end
- it 'raises SocketError for #ip_address' do
- -> {
- @sock.local_address.ip_address
- }.should raise_error(SocketError, "need IPv4 or IPv6 address")
- end
+ it 'uses SOCK_STREAM as the socket type' do
+ @sock.local_address.socktype.should == Socket::SOCK_STREAM
+ end
- it 'raises SocketError for #ip_port' do
- -> {
- @sock.local_address.ip_port
- }.should raise_error(SocketError, "need IPv4 or IPv6 address")
- end
+ it 'raises SocketError for #ip_address' do
+ -> {
+ @sock.local_address.ip_address
+ }.should.raise(SocketError, "need IPv4 or IPv6 address")
+ end
- it 'uses 0 as the protocol' do
- @sock.local_address.protocol.should == 0
- end
+ it 'raises SocketError for #ip_port' do
+ -> {
+ @sock.local_address.ip_port
+ }.should.raise(SocketError, "need IPv4 or IPv6 address")
+ end
+
+ it 'uses 0 as the protocol' do
+ @sock.local_address.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb
index 6d8ea6dcfe..fea2c1e2b7 100644
--- a/spec/ruby/library/socket/unixsocket/new_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/new_spec.rb
@@ -1,14 +1,12 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXSocket.new" do
- it_behaves_like :unixsocket_new, :new
+describe "UNIXSocket.new" do
+ it_behaves_like :unixsocket_new, :new
- it "does not use the given block and warns to use UNIXSocket::open" do
- -> {
- @client = UNIXSocket.new(@path) { raise }
- }.should complain(/warning: UNIXSocket::new\(\) does not take block; use UNIXSocket::open\(\) instead/)
- end
+ it "does not use the given block and warns to use UNIXSocket::open" do
+ -> {
+ @client = UNIXSocket.new(@path) { raise }
+ }.should complain(/warning: UNIXSocket::new\(\) does not take block; use UNIXSocket::open\(\) instead/)
end
end
diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb
index 61def30abb..b5e8c6c23a 100644
--- a/spec/ruby/library/socket/unixsocket/open_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/open_spec.rb
@@ -2,27 +2,25 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXSocket.open" do
- it_behaves_like :unixsocket_new, :open
- end
+describe "UNIXSocket.open" do
+ it_behaves_like :unixsocket_new, :open
+end
- describe "UNIXSocket.open" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- end
+describe "UNIXSocket.open" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ end
- after :each do
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "opens a unix socket on the specified file and yields it to the block" do
- UNIXSocket.open(@path) do |client|
- client.addr[0].should == "AF_UNIX"
- client.should_not.closed?
- end
+ it "opens a unix socket on the specified file and yields it to the block" do
+ UNIXSocket.open(@path) do |client|
+ client.addr[0].should == "AF_UNIX"
+ client.should_not.closed?
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb
index b0a3b2af99..9690142668 100644
--- a/spec/ruby/library/socket/unixsocket/pair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb
@@ -3,18 +3,16 @@ require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
require_relative 'shared/pair'
-with_feature :unix_socket do
- describe "UNIXSocket.pair" do
- it_should_behave_like :unixsocket_pair
- it_should_behave_like :partially_closable_sockets
+describe "UNIXSocket.pair" do
+ it_should_behave_like :unixsocket_pair
+ it_should_behave_like :partially_closable_sockets
- before :each do
- @s1, @s2 = UNIXSocket.pair
- end
+ before :each do
+ @s1, @s2 = UNIXSocket.pair
+ end
- after :each do
- @s1.close
- @s2.close
- end
+ after :each do
+ @s1.close
+ @s2.close
end
end
diff --git a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
index ef7d0f0b2a..108a6c3063 100644
--- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
@@ -2,22 +2,20 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
-with_feature :unix_socket do
- describe "UNIXSocket partial closability" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @s1 = UNIXSocket.new(@path)
- @s2 = @server.accept
- end
-
- after :each do
- @server.close
- @s1.close
- @s2.close
- SocketSpecs.rm_socket @path
- end
+describe "UNIXSocket partial closability" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @s1 = UNIXSocket.new(@path)
+ @s2 = @server.accept
+ end
- it_should_behave_like :partially_closable_sockets
+ after :each do
+ @server.close
+ @s1.close
+ @s2.close
+ SocketSpecs.rm_socket @path
end
+
+ it_should_behave_like :partially_closable_sockets
end
diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb
index a608378e4f..ffe7e4bea2 100644
--- a/spec/ruby/library/socket/unixsocket/path_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/path_spec.rb
@@ -1,26 +1,24 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#path" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
- end
+describe "UNIXSocket#path" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "returns the path of the socket if it's a server" do
- @server.path.should == @path
- end
+ it "returns the path of the socket if it's a server" do
+ @server.path.should == @path
+ end
- it "returns an empty string for path if it's a client" do
- @client.path.should == ""
- end
+ it "returns an empty string for path if it's a client" do
+ @client.path.should == ""
end
end
diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
index 72bc96b1fe..b586b1fcbb 100644
--- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
@@ -1,28 +1,26 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#peeraddr" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
- end
+describe "UNIXSocket#peeraddr" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "returns the address family and path of the server end of the connection" do
- @client.peeraddr.should == ["AF_UNIX", @path]
- end
+ it "returns the address family and path of the server end of the connection" do
+ @client.peeraddr.should == ["AF_UNIX", @path]
+ end
- it "raises an error in server sockets" do
- -> {
- @server.peeraddr
- }.should raise_error(Errno::ENOTCONN)
- end
+ it "raises an error in server sockets" do
+ -> {
+ @server.peeraddr
+ }.should.raise(Errno::ENOTCONN)
end
end
diff --git a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
index 1dbc4538e3..ac9d892375 100644
--- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
+platform_is_not :windows do
describe "UNIXSocket#recv_io" do
before :each do
@path = SocketSpecs.socket_path
@@ -37,7 +37,7 @@ with_feature :unix_socket do
@socket = @server.accept
@io = @socket.recv_io(File)
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
end
@@ -59,7 +59,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
end
@@ -68,7 +68,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io(File)
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
end
@@ -77,7 +77,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io(File, File::WRONLY)
- @io.should be_an_instance_of(File)
+ @io.should.instance_of?(File)
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
index d849fdc302..9ae3777961 100644
--- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
@@ -1,59 +1,105 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#recvfrom" do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- @client = UNIXSocket.open(@path)
+describe "UNIXSocket#recvfrom" do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ @client = UNIXSocket.open(@path)
+ end
+
+ after :each do
+ @client.close
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
+
+ it "receives len bytes from sock, returning an array containing sent data as first element" do
+ @client.send("foobar", 0)
+ sock = @server.accept
+ sock.recvfrom(6).first.should == "foobar"
+ sock.close
+ end
+
+ context "when called on a server's socket" do
+ platform_is_not :windows do
+ it "returns an array containing basic information on the client as second element" do
+ @client.send("foobar", 0)
+ sock = @server.accept
+ data = sock.recvfrom(6)
+ data.last.should == ["AF_UNIX", ""]
+ sock.close
+ end
end
- after :each do
- @client.close
- @server.close
- SocketSpecs.rm_socket @path
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
+ it "returns an array containing basic information on the client as second element" do
+ @client.send("foobar", 0)
+ sock = @server.accept
+ data = sock.recvfrom(6)
+ data.last.should == ["AF_UNIX", ""]
+ sock.close
+ end
end
+ end
- it "receives len bytes from sock" do
- @client.send("foobar", 0)
- sock = @server.accept
- sock.recvfrom(6).first.should == "foobar"
- sock.close
+ context "when called on a client's socket" do
+ platform_is :linux do
+ it "returns an array containing server's address as second element" do
+ @client.send("", 0)
+ sock = @server.accept
+ sock.send("barfoo", 0)
+ @client.recvfrom(6).last.should == ["AF_UNIX", @server.local_address.unix_path]
+ sock.close
+ end
end
- it "returns an array with data and information on the sender" do
- @client.send("foobar", 0)
- sock = @server.accept
- data = sock.recvfrom(6)
- data.first.should == "foobar"
- data.last.should == ["AF_UNIX", ""]
- sock.close
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
+ it "returns an array containing server's address as second element" do
+ @client.send("", 0)
+ sock = @server.accept
+ sock.send("barfoo", 0)
+ # This may not be correct, depends on what underlying recvfrom actually returns.
+ @client.recvfrom(6).last.should == ["AF_UNIX", @server.local_address.unix_path]
+ sock.close
+ end
end
- it "allows an output buffer as third argument" do
- buffer = +''
+ platform_is :darwin do
+ it "returns an array containing basic information on the server as second element" do
+ @client.send("", 0)
+ sock = @server.accept
+ sock.send("barfoo", 0)
+ @client.recvfrom(6).last.should == ["AF_UNIX", ""]
+ sock.close
+ end
+ end
+ end
- @client.send("foobar", 0)
- sock = @server.accept
- message, = sock.recvfrom(6, 0, buffer)
- sock.close
+ it "allows an output buffer as third argument" do
+ buffer = +''
- message.should.equal?(buffer)
- buffer.should == "foobar"
- end
+ @client.send("foobar", 0)
+ sock = @server.accept
+ message, = sock.recvfrom(6, 0, buffer)
+ sock.close
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
+ message.should.equal?(buffer)
+ buffer.should == "foobar"
+ end
- @client.send("foobar", 0)
- sock = @server.accept
- sock.recvfrom(6, 0, buffer)
- sock.close
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
- buffer.encoding.should == Encoding::ISO_8859_1
- end
+ @client.send("foobar", 0)
+ sock = @server.accept
+ sock.recvfrom(6, 0, buffer)
+ sock.close
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
+ platform_is_not :windows do
it "uses different message options" do
@client.send("foobar", Socket::MSG_PEEK)
sock = @server.accept
@@ -65,24 +111,34 @@ with_feature :unix_socket do
sock.close
end
end
+end
- describe 'UNIXSocket#recvfrom' do
- describe 'using a socket pair' do
- before do
- @client, @server = UNIXSocket.socketpair
- @client.write('hello')
- end
+describe 'UNIXSocket#recvfrom' do
+ describe 'using a socket pair' do
+ before do
+ @client, @server = UNIXSocket.socketpair
+ @client.write('hello')
+ end
- after do
- @client.close
- @server.close
+ after do
+ @client.close
+ @server.close
+ end
+
+ platform_is_not :windows do
+ it 'returns an Array containing the data and address information' do
+ @server.recvfrom(5).should == ['hello', ['AF_UNIX', '']]
end
+ end
+ guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do
it 'returns an Array containing the data and address information' do
@server.recvfrom(5).should == ['hello', ['AF_UNIX', '']]
end
end
+ end
+ platform_is_not :windows do
# These specs are taken from the rdoc examples on UNIXSocket#recvfrom.
describe 'using a UNIX socket constructed using UNIXSocket.for_fd' do
before do
diff --git a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb
index 0b416254d0..d2303a6587 100644
--- a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb
@@ -1,45 +1,43 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe 'UNIXSocket#remote_address' do
- before do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.new(@path)
- @client = UNIXSocket.new(@path)
- end
+describe 'UNIXSocket#remote_address' do
+ before do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.new(@path)
+ @client = UNIXSocket.new(@path)
+ end
- after do
- @client.close
- @server.close
+ after do
+ @client.close
+ @server.close
- rm_r(@path)
- end
+ rm_r(@path)
+ end
- it 'returns an Addrinfo' do
- @client.remote_address.should be_an_instance_of(Addrinfo)
- end
+ it 'returns an Addrinfo' do
+ @client.remote_address.should.instance_of?(Addrinfo)
+ end
- describe 'the returned Addrinfo' do
- it 'uses AF_UNIX as the address family' do
- @client.remote_address.afamily.should == Socket::AF_UNIX
- end
+ describe 'the returned Addrinfo' do
+ it 'uses AF_UNIX as the address family' do
+ @client.remote_address.afamily.should == Socket::AF_UNIX
+ end
- it 'uses PF_UNIX as the protocol family' do
- @client.remote_address.pfamily.should == Socket::PF_UNIX
- end
+ it 'uses PF_UNIX as the protocol family' do
+ @client.remote_address.pfamily.should == Socket::PF_UNIX
+ end
- it 'uses SOCK_STREAM as the socket type' do
- @client.remote_address.socktype.should == Socket::SOCK_STREAM
- end
+ it 'uses SOCK_STREAM as the socket type' do
+ @client.remote_address.socktype.should == Socket::SOCK_STREAM
+ end
- it 'uses the correct socket path' do
- @client.remote_address.unix_path.should == @path
- end
+ it 'uses the correct socket path' do
+ @client.remote_address.unix_path.should == @path
+ end
- it 'uses 0 as the protocol' do
- @client.remote_address.protocol.should == 0
- end
+ it 'uses 0 as the protocol' do
+ @client.remote_address.protocol.should == 0
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
index 80f3550c6d..0063fc7d3f 100644
--- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
+platform_is_not :windows do
describe "UNIXSocket#send_io" do
before :each do
@path = SocketSpecs.socket_path
@@ -49,7 +49,7 @@ with_feature :unix_socket do
@client.send_io(@file)
@io = @server.recv_io
- @io.should be_an_instance_of(IO)
+ @io.should.instance_of?(IO)
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/shared/pair.rb b/spec/ruby/library/socket/unixsocket/shared/pair.rb
index ade7fc9852..49b6a6a413 100644
--- a/spec/ruby/library/socket/unixsocket/shared/pair.rb
+++ b/spec/ruby/library/socket/unixsocket/shared/pair.rb
@@ -3,8 +3,8 @@ require_relative '../../fixtures/classes'
describe :unixsocket_pair, shared: true do
it "returns two UNIXSockets" do
- @s1.should be_an_instance_of(UNIXSocket)
- @s2.should be_an_instance_of(UNIXSocket)
+ @s1.should.instance_of?(UNIXSocket)
+ @s2.should.instance_of?(UNIXSocket)
end
it "returns a pair of connected sockets" do
@@ -12,18 +12,36 @@ describe :unixsocket_pair, shared: true do
@s2.gets.should == "foo\n"
end
- it "sets the socket paths to empty Strings" do
- @s1.path.should == ""
- @s2.path.should == ""
- end
+ platform_is_not :windows do
+ it "sets the socket paths to empty Strings" do
+ @s1.path.should == ""
+ @s2.path.should == ""
+ end
+
+ it "sets the socket addresses to empty Strings" do
+ @s1.addr.should == ["AF_UNIX", ""]
+ @s2.addr.should == ["AF_UNIX", ""]
+ end
- it "sets the socket addresses to empty Strings" do
- @s1.addr.should == ["AF_UNIX", ""]
- @s2.addr.should == ["AF_UNIX", ""]
+ it "sets the socket peer addresses to empty Strings" do
+ @s1.peeraddr.should == ["AF_UNIX", ""]
+ @s2.peeraddr.should == ["AF_UNIX", ""]
+ end
end
- it "sets the socket peer addresses to empty Strings" do
- @s1.peeraddr.should == ["AF_UNIX", ""]
- @s2.peeraddr.should == ["AF_UNIX", ""]
+ platform_is :windows do
+ it "emulates unnamed sockets with a temporary file with a path" do
+ @s1.addr.should == ["AF_UNIX", @s1.path]
+ @s2.peeraddr.should == ["AF_UNIX", @s1.path]
+ end
+
+ it "sets the peer address of first socket to an empty string" do
+ @s1.peeraddr.should == ["AF_UNIX", ""]
+ end
+
+ it "sets the address and path of second socket to an empty string" do
+ @s2.addr.should == ["AF_UNIX", ""]
+ @s2.path.should == ""
+ end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
index 5f34008df3..c61fc00be4 100644
--- a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
@@ -3,18 +3,16 @@ require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
require_relative 'shared/pair'
-with_feature :unix_socket do
- describe "UNIXSocket.socketpair" do
- it_should_behave_like :unixsocket_pair
- it_should_behave_like :partially_closable_sockets
+describe "UNIXSocket.socketpair" do
+ it_should_behave_like :unixsocket_pair
+ it_should_behave_like :partially_closable_sockets
- before :each do
- @s1, @s2 = UNIXSocket.socketpair
- end
+ before :each do
+ @s1, @s2 = UNIXSocket.socketpair
+ end
- after :each do
- @s1.close
- @s2.close
- end
+ after :each do
+ @s1.close
+ @s2.close
end
end
diff --git a/spec/ruby/library/stringio/append_spec.rb b/spec/ruby/library/stringio/append_spec.rb
index cb50d73d1b..c21ba00508 100644
--- a/spec/ruby/library/stringio/append_spec.rb
+++ b/spec/ruby/library/stringio/append_spec.rb
@@ -7,7 +7,7 @@ describe "StringIO#<< when passed [Object]" do
end
it "returns self" do
- (@io << "just testing").should equal(@io)
+ (@io << "just testing").should.equal?(@io)
end
it "writes the passed argument onto self" do
@@ -31,7 +31,7 @@ describe "StringIO#<< when passed [Object]" do
it "updates self's position" do
@io << "test"
- @io.pos.should eql(4)
+ @io.pos.should.eql?(4)
end
it "tries to convert the passed argument to a String using #to_s" do
@@ -45,11 +45,11 @@ end
describe "StringIO#<< when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io << "test" }.should raise_error(IOError)
+ -> { io << "test" }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io << "test" }.should raise_error(IOError)
+ -> { io << "test" }.should.raise(IOError)
end
end
@@ -69,6 +69,6 @@ describe "StringIO#<< when in append mode" do
it "correctly updates self's position" do
@io << ", testing"
- @io.pos.should eql(16)
+ @io.pos.should.eql?(16)
end
end
diff --git a/spec/ruby/library/stringio/binmode_spec.rb b/spec/ruby/library/stringio/binmode_spec.rb
index 9e92c63814..bc7ccda0a2 100644
--- a/spec/ruby/library/stringio/binmode_spec.rb
+++ b/spec/ruby/library/stringio/binmode_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "StringIO#binmode" do
it "returns self" do
io = StringIO.new(+"example")
- io.binmode.should equal(io)
+ io.binmode.should.equal?(io)
end
it "changes external encoding to BINARY" do
diff --git a/spec/ruby/library/stringio/close_read_spec.rb b/spec/ruby/library/stringio/close_read_spec.rb
index 0f08e1ff2e..dd46a927be 100644
--- a/spec/ruby/library/stringio/close_read_spec.rb
+++ b/spec/ruby/library/stringio/close_read_spec.rb
@@ -7,12 +7,12 @@ describe "StringIO#close_read" do
end
it "returns nil" do
- @io.close_read.should be_nil
+ @io.close_read.should == nil
end
it "prevents further reading" do
@io.close_read
- -> { @io.read(1) }.should raise_error(IOError)
+ -> { @io.read(1) }.should.raise(IOError)
end
it "allows further writing" do
@@ -22,7 +22,7 @@ describe "StringIO#close_read" do
it "raises an IOError when in write-only mode" do
io = StringIO.new(+"example", "w")
- -> { io.close_read }.should raise_error(IOError)
+ -> { io.close_read }.should.raise(IOError)
io = StringIO.new("example")
io.close_read
diff --git a/spec/ruby/library/stringio/close_spec.rb b/spec/ruby/library/stringio/close_spec.rb
index 520a8de782..6febd14a26 100644
--- a/spec/ruby/library/stringio/close_spec.rb
+++ b/spec/ruby/library/stringio/close_spec.rb
@@ -7,17 +7,17 @@ describe "StringIO#close" do
end
it "returns nil" do
- @io.close.should be_nil
+ @io.close.should == nil
end
it "prevents further reading and/or writing" do
@io.close
- -> { @io.read(1) }.should raise_error(IOError)
- -> { @io.write('x') }.should raise_error(IOError)
+ -> { @io.read(1) }.should.raise(IOError)
+ -> { @io.write('x') }.should.raise(IOError)
end
it "does not raise anything when self was already closed" do
@io.close
- -> { @io.close }.should_not raise_error(IOError)
+ -> { @io.close }.should_not.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/close_write_spec.rb b/spec/ruby/library/stringio/close_write_spec.rb
index c86c3f9826..b74b996166 100644
--- a/spec/ruby/library/stringio/close_write_spec.rb
+++ b/spec/ruby/library/stringio/close_write_spec.rb
@@ -7,12 +7,12 @@ describe "StringIO#close_write" do
end
it "returns nil" do
- @io.close_write.should be_nil
+ @io.close_write.should == nil
end
it "prevents further writing" do
@io.close_write
- -> { @io.write('x') }.should raise_error(IOError)
+ -> { @io.write('x') }.should.raise(IOError)
end
it "allows further reading" do
@@ -22,7 +22,7 @@ describe "StringIO#close_write" do
it "raises an IOError when in read-only mode" do
io = StringIO.new(+"example", "r")
- -> { io.close_write }.should raise_error(IOError)
+ -> { io.close_write }.should.raise(IOError)
io = StringIO.new(+"example")
io.close_write
diff --git a/spec/ruby/library/stringio/closed_read_spec.rb b/spec/ruby/library/stringio/closed_read_spec.rb
index b4dcadc3a4..2e3813b1bc 100644
--- a/spec/ruby/library/stringio/closed_read_spec.rb
+++ b/spec/ruby/library/stringio/closed_read_spec.rb
@@ -5,8 +5,8 @@ describe "StringIO#closed_read?" do
it "returns true if self is not readable" do
io = StringIO.new(+"example", "r+")
io.close_write
- io.closed_read?.should be_false
+ io.closed_read?.should == false
io.close_read
- io.closed_read?.should be_true
+ io.closed_read?.should == true
end
end
diff --git a/spec/ruby/library/stringio/closed_spec.rb b/spec/ruby/library/stringio/closed_spec.rb
index bf7ba63184..647fe445da 100644
--- a/spec/ruby/library/stringio/closed_spec.rb
+++ b/spec/ruby/library/stringio/closed_spec.rb
@@ -5,12 +5,12 @@ describe "StringIO#closed?" do
it "returns true if self is completely closed" do
io = StringIO.new(+"example", "r+")
io.close_read
- io.closed?.should be_false
+ io.closed?.should == false
io.close_write
- io.closed?.should be_true
+ io.closed?.should == true
io = StringIO.new(+"example", "r+")
io.close
- io.closed?.should be_true
+ io.closed?.should == true
end
end
diff --git a/spec/ruby/library/stringio/closed_write_spec.rb b/spec/ruby/library/stringio/closed_write_spec.rb
index 2bd3e6fa8b..339691cd82 100644
--- a/spec/ruby/library/stringio/closed_write_spec.rb
+++ b/spec/ruby/library/stringio/closed_write_spec.rb
@@ -5,8 +5,8 @@ describe "StringIO#closed_write?" do
it "returns true if self is not writable" do
io = StringIO.new(+"example", "r+")
io.close_read
- io.closed_write?.should be_false
+ io.closed_write?.should == false
io.close_write
- io.closed_write?.should be_true
+ io.closed_write?.should == true
end
end
diff --git a/spec/ruby/library/stringio/each_line_spec.rb b/spec/ruby/library/stringio/each_line_spec.rb
index c68f7dae82..4ac0db7c45 100644
--- a/spec/ruby/library/stringio/each_line_spec.rb
+++ b/spec/ruby/library/stringio/each_line_spec.rb
@@ -21,3 +21,7 @@ end
describe "StringIO#each_line when passed limit" do
it_behaves_like :stringio_each_limit, :each_line
end
+
+describe "StringIO#each when passed separator and limit" do
+ it_behaves_like :stringio_each_separator_and_limit, :each_line
+end
diff --git a/spec/ruby/library/stringio/each_spec.rb b/spec/ruby/library/stringio/each_spec.rb
index 2c30ed5cda..7eb322f3ff 100644
--- a/spec/ruby/library/stringio/each_spec.rb
+++ b/spec/ruby/library/stringio/each_spec.rb
@@ -25,3 +25,7 @@ end
describe "StringIO#each when passed limit" do
it_behaves_like :stringio_each_limit, :each
end
+
+describe "StringIO#each when passed separator and limit" do
+ it_behaves_like :stringio_each_separator_and_limit, :each
+end
diff --git a/spec/ruby/library/stringio/fcntl_spec.rb b/spec/ruby/library/stringio/fcntl_spec.rb
index a78004d868..6108130db7 100644
--- a/spec/ruby/library/stringio/fcntl_spec.rb
+++ b/spec/ruby/library/stringio/fcntl_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#fcntl" do
it "raises a NotImplementedError" do
- -> { StringIO.new("boom").fcntl }.should raise_error(NotImplementedError)
+ -> { StringIO.new("boom").fcntl }.should.raise(NotImplementedError)
end
end
diff --git a/spec/ruby/library/stringio/fileno_spec.rb b/spec/ruby/library/stringio/fileno_spec.rb
index eea03a5af3..f5d1e83776 100644
--- a/spec/ruby/library/stringio/fileno_spec.rb
+++ b/spec/ruby/library/stringio/fileno_spec.rb
@@ -1,9 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/each'
+require 'stringio'
describe "StringIO#fileno" do
it "returns nil" do
- StringIO.new("nuffin").fileno.should be_nil
+ StringIO.new("nuffin").fileno.should == nil
end
end
diff --git a/spec/ruby/library/stringio/flush_spec.rb b/spec/ruby/library/stringio/flush_spec.rb
index 4dc58b1d48..48be44773c 100644
--- a/spec/ruby/library/stringio/flush_spec.rb
+++ b/spec/ruby/library/stringio/flush_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "StringIO#flush" do
it "returns self" do
io = StringIO.new(+"flush")
- io.flush.should equal(io)
+ io.flush.should.equal?(io)
end
end
diff --git a/spec/ruby/library/stringio/fsync_spec.rb b/spec/ruby/library/stringio/fsync_spec.rb
index 85053cb2e5..30fae15c8e 100644
--- a/spec/ruby/library/stringio/fsync_spec.rb
+++ b/spec/ruby/library/stringio/fsync_spec.rb
@@ -4,6 +4,6 @@ require_relative 'fixtures/classes'
describe "StringIO#fsync" do
it "returns zero" do
io = StringIO.new(+"fsync")
- io.fsync.should eql(0)
+ io.fsync.should.eql?(0)
end
end
diff --git a/spec/ruby/library/stringio/gets_spec.rb b/spec/ruby/library/stringio/gets_spec.rb
index 4af7704a41..5dc572fba5 100644
--- a/spec/ruby/library/stringio/gets_spec.rb
+++ b/spec/ruby/library/stringio/gets_spec.rb
@@ -1,250 +1,61 @@
require_relative '../../spec_helper'
require "stringio"
+require_relative "shared/gets"
-describe "StringIO#gets when passed [separator]" do
- before :each do
- @io = StringIO.new("this>is>an>example")
- end
-
- it "returns the data read till the next occurrence of the passed separator" do
- @io.gets(">").should == "this>"
- @io.gets(">").should == "is>"
- @io.gets(">").should == "an>"
- @io.gets(">").should == "example"
- end
-
- it "sets $_ to the read content" do
- @io.gets(">")
- $_.should == "this>"
- @io.gets(">")
- $_.should == "is>"
- @io.gets(">")
- $_.should == "an>"
- @io.gets(">")
- $_.should == "example"
- @io.gets(">")
- $_.should be_nil
- end
-
- it "accepts string as separator" do
- @io.gets("is>")
- $_.should == "this>"
- @io.gets("an>")
- $_.should == "is>an>"
- @io.gets("example")
- $_.should == "example"
- @io.gets("ple")
- $_.should be_nil
- end
-
- it "updates self's lineno by one" do
- @io.gets(">")
- @io.lineno.should eql(1)
-
- @io.gets(">")
- @io.lineno.should eql(2)
-
- @io.gets(">")
- @io.lineno.should eql(3)
- end
-
- it "returns the next paragraph when the passed separator is an empty String" do
- io = StringIO.new("this is\n\nan example")
- io.gets("").should == "this is\n\n"
- io.gets("").should == "an example"
- end
-
- it "returns the remaining content starting at the current position when passed nil" do
- io = StringIO.new("this is\n\nan example")
- io.pos = 5
- io.gets(nil).should == "is\n\nan example"
- end
+describe "StringIO#gets" do
+ describe "when passed [separator]" do
+ it_behaves_like :stringio_gets_separator, :gets
- it "tries to convert the passed separator to a String using #to_str" do
- obj = mock('to_str')
- obj.should_receive(:to_str).and_return(">")
- @io.gets(obj).should == "this>"
- end
-end
-
-describe "StringIO#gets when passed no argument" do
- before :each do
- @io = StringIO.new("this is\nan example\nfor StringIO#gets")
- end
+ it "returns nil if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- it "returns the data read till the next occurrence of $/ or till eof" do
- @io.gets.should == "this is\n"
-
- begin
- old_sep = $/
- suppress_warning {$/ = " "}
- @io.gets.should == "an "
- @io.gets.should == "example\nfor "
- @io.gets.should == "StringIO#gets"
- ensure
- suppress_warning {$/ = old_sep}
+ @io.pos = 36
+ @io.gets(">").should == nil
+ @io.gets(">").should == nil
end
end
- it "sets $_ to the read content" do
- @io.gets
- $_.should == "this is\n"
- @io.gets
- $_.should == "an example\n"
- @io.gets
- $_.should == "for StringIO#gets"
- @io.gets
- $_.should be_nil
- end
-
- it "updates self's position" do
- @io.gets
- @io.pos.should eql(8)
-
- @io.gets
- @io.pos.should eql(19)
-
- @io.gets
- @io.pos.should eql(36)
- end
-
- it "updates self's lineno" do
- @io.gets
- @io.lineno.should eql(1)
-
- @io.gets
- @io.lineno.should eql(2)
-
- @io.gets
- @io.lineno.should eql(3)
- end
-
- it "returns nil if self is at the end" do
- @io.pos = 36
- @io.gets.should be_nil
- @io.gets.should be_nil
- end
-end
-
-describe "StringIO#gets when passed [limit]" do
- before :each do
- @io = StringIO.new("this>is>an>example")
- end
-
- it "returns the data read until the limit is met" do
- @io.gets(4).should == "this"
- @io.gets(3).should == ">is"
- @io.gets(5).should == ">an>e"
- @io.gets(6).should == "xample"
- end
-
- it "sets $_ to the read content" do
- @io.gets(4)
- $_.should == "this"
- @io.gets(3)
- $_.should == ">is"
- @io.gets(5)
- $_.should == ">an>e"
- @io.gets(6)
- $_.should == "xample"
- @io.gets(3)
- $_.should be_nil
- end
-
- it "updates self's lineno by one" do
- @io.gets(3)
- @io.lineno.should eql(1)
-
- @io.gets(3)
- @io.lineno.should eql(2)
-
- @io.gets(3)
- @io.lineno.should eql(3)
- end
-
- it "tries to convert the passed limit to an Integer using #to_int" do
- obj = mock('to_int')
- obj.should_receive(:to_int).and_return(4)
- @io.gets(obj).should == "this"
- end
-
- it "returns a blank string when passed a limit of 0" do
- @io.gets(0).should == ""
- end
-
- it "ignores it when passed a negative limit" do
- @io.gets(-4).should == "this>is>an>example"
- end
-end
+ describe "when passed [limit]" do
+ it_behaves_like :stringio_gets_limit, :gets
-describe "StringIO#gets when passed [separator] and [limit]" do
- before :each do
- @io = StringIO.new("this>is>an>example")
- end
-
- it "returns the data read until the limit is consumed or the separator is met" do
- @io.gets('>', 8).should == "this>"
- @io.gets('>', 2).should == "is"
- @io.gets('>', 10).should == ">"
- @io.gets('>', 6).should == "an>"
- @io.gets('>', 5).should == "examp"
- end
+ it "returns nil if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- it "sets $_ to the read content" do
- @io.gets('>', 8)
- $_.should == "this>"
- @io.gets('>', 2)
- $_.should == "is"
- @io.gets('>', 10)
- $_.should == ">"
- @io.gets('>', 6)
- $_.should == "an>"
- @io.gets('>', 5)
- $_.should == "examp"
+ @io.pos = 36
+ @io.gets(3).should == nil
+ @io.gets(3).should == nil
+ end
end
- it "updates self's lineno by one" do
- @io.gets('>', 3)
- @io.lineno.should eql(1)
+ describe "when passed [separator] and [limit]" do
+ it_behaves_like :stringio_gets_separator_and_limit, :gets
- @io.gets('>', 3)
- @io.lineno.should eql(2)
+ it "returns nil if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- @io.gets('>', 3)
- @io.lineno.should eql(3)
+ @io.pos = 36
+ @io.gets(">", 3).should == nil
+ @io.gets(">", 3).should == nil
+ end
end
- it "tries to convert the passed separator to a String using #to_str" do
- obj = mock('to_str')
- obj.should_receive(:to_str).and_return('>')
- @io.gets(obj, 5).should == "this>"
- end
+ describe "when passed no argument" do
+ it_behaves_like :stringio_gets_no_argument, :gets
- it "does not raise TypeError if passed separator is nil" do
- @io.gets(nil, 5).should == "this>"
- end
+ it "returns nil if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- it "tries to convert the passed limit to an Integer using #to_int" do
- obj = mock('to_int')
- obj.should_receive(:to_int).and_return(5)
- @io.gets('>', obj).should == "this>"
+ @io.pos = 36
+ @io.gets.should == nil
+ @io.gets.should == nil
+ end
end
-end
-
-describe "StringIO#gets when in write-only mode" do
- it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
- -> { io.gets }.should raise_error(IOError)
- io = StringIO.new("xyz")
- io.close_read
- -> { io.gets }.should raise_error(IOError)
+ describe "when passed [chomp]" do
+ it_behaves_like :stringio_gets_chomp, :gets
end
-end
-describe "StringIO#gets when passed [chomp]" do
- it "returns the data read without a trailing newline character" do
- io = StringIO.new("this>is>an>example\n")
- io.gets(chomp: true).should == "this>is>an>example"
+ describe "when in write-only mode" do
+ it_behaves_like :stringio_gets_write_only, :gets
end
end
diff --git a/spec/ruby/library/stringio/initialize_spec.rb b/spec/ruby/library/stringio/initialize_spec.rb
index 6f4d2e456c..413e0aacc0 100644
--- a/spec/ruby/library/stringio/initialize_spec.rb
+++ b/spec/ruby/library/stringio/initialize_spec.rb
@@ -8,111 +8,111 @@ describe "StringIO#initialize when passed [Object, mode]" do
it "uses the passed Object as the StringIO backend" do
@io.send(:initialize, str = "example", "r")
- @io.string.should equal(str)
+ @io.string.should.equal?(str)
end
it "sets the mode based on the passed mode" do
io = StringIO.allocate
io.send(:initialize, +"example", "r")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.allocate
io.send(:initialize, +"example", "rb")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.allocate
io.send(:initialize, +"example", "r+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "rb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "w")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "wb")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "w+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "wb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "a")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "ab")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "a+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", "ab+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "allows passing the mode as an Integer" do
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDONLY)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDWR)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::WRONLY)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::WRONLY | IO::TRUNC)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDWR | IO::TRUNC)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::WRONLY | IO::APPEND)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.allocate
io.send(:initialize, +"example", IO::RDWR | IO::APPEND)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "raises a FrozenError when passed a frozen String in truncate mode as StringIO backend" do
io = StringIO.allocate
- -> { io.send(:initialize, "example".freeze, IO::TRUNC) }.should raise_error(FrozenError)
+ -> { io.send(:initialize, "example".freeze, IO::TRUNC) }.should.raise(FrozenError)
end
it "tries to convert the passed mode to a String using #to_str" do
@@ -120,15 +120,15 @@ describe "StringIO#initialize when passed [Object, mode]" do
obj.should_receive(:to_str).and_return("r")
@io.send(:initialize, +"example", obj)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
end
it "raises an Errno::EACCES error when passed a frozen string with a write-mode" do
(str = "example").freeze
- -> { @io.send(:initialize, str, "r+") }.should raise_error(Errno::EACCES)
- -> { @io.send(:initialize, str, "w") }.should raise_error(Errno::EACCES)
- -> { @io.send(:initialize, str, "a") }.should raise_error(Errno::EACCES)
+ -> { @io.send(:initialize, str, "r+") }.should.raise(Errno::EACCES)
+ -> { @io.send(:initialize, str, "w") }.should.raise(Errno::EACCES)
+ -> { @io.send(:initialize, str, "a") }.should.raise(Errno::EACCES)
end
it "truncates all the content if passed w mode" do
@@ -159,19 +159,19 @@ describe "StringIO#initialize when passed [Object]" do
it "uses the passed Object as the StringIO backend" do
@io.send(:initialize, str = "example")
- @io.string.should equal(str)
+ @io.string.should.equal?(str)
end
it "sets the mode to read-write if the string is mutable" do
@io.send(:initialize, +"example")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
end
it "sets the mode to read if the string is frozen" do
@io.send(:initialize, -"example")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
end
it "tries to convert the passed Object to a String using #to_str" do
@@ -184,8 +184,8 @@ describe "StringIO#initialize when passed [Object]" do
it "automatically sets the mode to read-only when passed a frozen string" do
(str = "example").freeze
@io.send(:initialize, str)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
end
end
@@ -193,8 +193,8 @@ end
describe "StringIO#initialize when passed keyword arguments" do
it "sets the mode based on the passed :mode option" do
io = StringIO.new("example", mode: "r")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
end
it "accepts a mode argument set to nil with a valid :mode option" do
@@ -223,54 +223,54 @@ describe "StringIO#initialize when passed keyword arguments and error happens" d
it "raises an error if passed encodings two ways" do
-> {
@io = StringIO.new(+'', 'w:ISO-8859-1', encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed matching binary/text mode two ways" do
-> {
@io = StringIO.new(+'', "wb", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wb", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error if passed conflicting binary/text mode two ways" do
-> {
@io = StringIO.new(+'', "wb", binmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", textmode: false)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wb", textmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', "wt", binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "raises an error when trying to set both binmode and textmode" do
-> {
@io = StringIO.new(+'', "w", textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
-> {
@io = StringIO.new(+'', File::Constants::WRONLY, textmode: true, binmode: true)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -280,13 +280,13 @@ describe "StringIO#initialize when passed no arguments" do
end
it "is private" do
- StringIO.should have_private_instance_method(:initialize)
+ StringIO.private_instance_methods(false).should.include?(:initialize)
end
it "sets the mode to read-write" do
@io.send(:initialize)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
end
it "uses an empty String as the StringIO backend" do
diff --git a/spec/ruby/library/stringio/inspect_spec.rb b/spec/ruby/library/stringio/inspect_spec.rb
index 7c02f8d360..962d858e48 100644
--- a/spec/ruby/library/stringio/inspect_spec.rb
+++ b/spec/ruby/library/stringio/inspect_spec.rb
@@ -9,7 +9,7 @@ describe "StringIO#inspect" do
it "does not include the contents" do
io = StringIO.new("contents")
- io.inspect.should_not include("contents")
+ io.inspect.should_not.include?("contents")
end
it "uses the regular Object#inspect without any instance variable" do
diff --git a/spec/ruby/library/stringio/lineno_spec.rb b/spec/ruby/library/stringio/lineno_spec.rb
index c620a1a686..a96dc05927 100644
--- a/spec/ruby/library/stringio/lineno_spec.rb
+++ b/spec/ruby/library/stringio/lineno_spec.rb
@@ -10,7 +10,7 @@ describe "StringIO#lineno" do
@io.gets
@io.gets
@io.gets
- @io.lineno.should eql(3)
+ @io.lineno.should.eql?(3)
end
end
@@ -21,10 +21,10 @@ describe "StringIO#lineno=" do
it "sets the current line number, but has no impact on the position" do
@io.lineno = 3
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
@io.gets.should == "this\n"
- @io.lineno.should eql(4)
- @io.pos.should eql(5)
+ @io.lineno.should.eql?(4)
+ @io.pos.should.eql?(5)
end
end
diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb
index b7c90661f9..23c7b34e09 100644
--- a/spec/ruby/library/stringio/open_spec.rb
+++ b/spec/ruby/library/stringio/open_spec.rb
@@ -4,24 +4,24 @@ require 'stringio'
describe "StringIO.open when passed [Object, mode]" do
it "uses the passed Object as the StringIO backend" do
io = StringIO.open(str = "example", "r")
- io.string.should equal(str)
+ io.string.should.equal?(str)
end
it "returns the blocks return value when yielding" do
ret = StringIO.open(+"example", "r") { :test }
- ret.should equal(:test)
+ ret.should.equal?(:test)
end
it "yields self to the passed block" do
io = nil
StringIO.open(+"example", "r") { |strio| io = strio }
- io.should be_kind_of(StringIO)
+ io.should.is_a?(StringIO)
end
it "closes self after yielding" do
io = nil
StringIO.open(+"example", "r") { |strio| io = strio }
- io.closed?.should be_true
+ io.closed?.should == true
end
it "even closes self when an exception is raised while yielding" do
@@ -33,13 +33,13 @@ describe "StringIO.open when passed [Object, mode]" do
end
rescue
end
- io.closed?.should be_true
+ io.closed?.should == true
end
it "sets self's string to nil after yielding" do
io = nil
StringIO.open(+"example", "r") { |strio| io = strio }
- io.string.should be_nil
+ io.string.should == nil
end
it "even sets self's string to nil when an exception is raised while yielding" do
@@ -51,91 +51,91 @@ describe "StringIO.open when passed [Object, mode]" do
end
rescue
end
- io.string.should be_nil
+ io.string.should == nil
end
it "sets the mode based on the passed mode" do
io = StringIO.open(+"example", "r")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.open(+"example", "rb")
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.open(+"example", "r+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "rb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "w")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "wb")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "w+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "wb+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "a")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "ab")
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", "a+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", "ab+")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "allows passing the mode as an Integer" do
io = StringIO.open(+"example", IO::RDONLY)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
io = StringIO.open(+"example", IO::RDWR)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::WRONLY)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::WRONLY | IO::TRUNC)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::RDWR | IO::TRUNC)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::WRONLY | IO::APPEND)
- io.closed_read?.should be_true
- io.closed_write?.should be_false
+ io.closed_read?.should == true
+ io.closed_write?.should == false
io = StringIO.open(+"example", IO::RDWR | IO::APPEND)
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
end
it "raises a FrozenError when passed a frozen String in truncate mode as StringIO backend" do
- -> { StringIO.open("example".freeze, IO::TRUNC) }.should raise_error(FrozenError)
+ -> { StringIO.open("example".freeze, IO::TRUNC) }.should.raise(FrozenError)
end
it "tries to convert the passed mode to a String using #to_str" do
@@ -143,34 +143,34 @@ describe "StringIO.open when passed [Object, mode]" do
obj.should_receive(:to_str).and_return("r")
io = StringIO.open(+"example", obj)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
end
it "raises an Errno::EACCES error when passed a frozen string with a write-mode" do
(str = "example").freeze
- -> { StringIO.open(str, "r+") }.should raise_error(Errno::EACCES)
- -> { StringIO.open(str, "w") }.should raise_error(Errno::EACCES)
- -> { StringIO.open(str, "a") }.should raise_error(Errno::EACCES)
+ -> { StringIO.open(str, "r+") }.should.raise(Errno::EACCES)
+ -> { StringIO.open(str, "w") }.should.raise(Errno::EACCES)
+ -> { StringIO.open(str, "a") }.should.raise(Errno::EACCES)
end
end
describe "StringIO.open when passed [Object]" do
it "uses the passed Object as the StringIO backend" do
io = StringIO.open(str = "example")
- io.string.should equal(str)
+ io.string.should.equal?(str)
end
it "yields self to the passed block" do
io = nil
ret = StringIO.open(+"example") { |strio| io = strio }
- io.should equal(ret)
+ io.should.equal?(ret)
end
it "sets the mode to read-write (r+)" do
io = StringIO.open(+"example")
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.new(+"example")
io.printf("%d", 123)
@@ -187,8 +187,8 @@ describe "StringIO.open when passed [Object]" do
it "automatically sets the mode to read-only when passed a frozen string" do
(str = "example").freeze
io = StringIO.open(str)
- io.closed_read?.should be_false
- io.closed_write?.should be_true
+ io.closed_read?.should == false
+ io.closed_write?.should == true
end
end
@@ -196,13 +196,13 @@ describe "StringIO.open when passed no arguments" do
it "yields self to the passed block" do
io = nil
ret = StringIO.open { |strio| io = strio }
- io.should equal(ret)
+ io.should.equal?(ret)
end
it "sets the mode to read-write (r+)" do
io = StringIO.open
- io.closed_read?.should be_false
- io.closed_write?.should be_false
+ io.closed_read?.should == false
+ io.closed_write?.should == false
io = StringIO.new(+"example")
io.printf("%d", 123)
diff --git a/spec/ruby/library/stringio/path_spec.rb b/spec/ruby/library/stringio/path_spec.rb
index 1184ca523f..dcb77b1df8 100644
--- a/spec/ruby/library/stringio/path_spec.rb
+++ b/spec/ruby/library/stringio/path_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#path" do
it "is not defined" do
- -> { StringIO.new("path").path }.should raise_error(NoMethodError)
+ -> { StringIO.new("path").path }.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/stringio/pid_spec.rb b/spec/ruby/library/stringio/pid_spec.rb
index 08f2d7ab1a..7a729fbe41 100644
--- a/spec/ruby/library/stringio/pid_spec.rb
+++ b/spec/ruby/library/stringio/pid_spec.rb
@@ -3,6 +3,6 @@ require_relative 'fixtures/classes'
describe "StringIO#pid" do
it "returns nil" do
- StringIO.new("pid").pid.should be_nil
+ StringIO.new("pid").pid.should == nil
end
end
diff --git a/spec/ruby/library/stringio/pos_spec.rb b/spec/ruby/library/stringio/pos_spec.rb
index 81be5f01a5..ba640f8c18 100644
--- a/spec/ruby/library/stringio/pos_spec.rb
+++ b/spec/ruby/library/stringio/pos_spec.rb
@@ -17,7 +17,7 @@ describe "StringIO#pos=" do
end
it "raises an EINVAL if given a negative argument" do
- -> { @io.pos = -10 }.should raise_error(Errno::EINVAL)
+ -> { @io.pos = -10 }.should.raise(Errno::EINVAL)
end
it "updates the current byte offset after reaching EOF" do
diff --git a/spec/ruby/library/stringio/print_spec.rb b/spec/ruby/library/stringio/print_spec.rb
index 00c33367dc..48728e5f14 100644
--- a/spec/ruby/library/stringio/print_spec.rb
+++ b/spec/ruby/library/stringio/print_spec.rb
@@ -29,7 +29,7 @@ describe "StringIO#print" do
end
it "returns nil" do
- @io.print(1, 2, 3).should be_nil
+ @io.print(1, 2, 3).should == nil
end
it "pads self with \\000 when the current position is after the end" do
@@ -52,10 +52,10 @@ describe "StringIO#print" do
it "updates the current position" do
@io.print(1, 2, 3)
- @io.pos.should eql(3)
+ @io.pos.should.eql?(3)
@io.print(1, 2, 3)
- @io.pos.should eql(6)
+ @io.pos.should.eql?(6)
end
it "correctly updates the current position when honoring the output record separator global" do
@@ -64,7 +64,7 @@ describe "StringIO#print" do
begin
@io.print(5, 6, 7, 8)
- @io.pos.should eql(5)
+ @io.pos.should.eql?(5)
ensure
suppress_warning {$\ = old_rs}
end
@@ -86,17 +86,17 @@ describe "StringIO#print when in append mode" do
it "correctly updates self's position" do
@io.print(", testing")
- @io.pos.should eql(16)
+ @io.pos.should.eql?(16)
end
end
describe "StringIO#print when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io.print("test") }.should raise_error(IOError)
+ -> { io.print("test") }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io.print("test") }.should raise_error(IOError)
+ -> { io.print("test") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb
index ca82e84757..ae7e0af729 100644
--- a/spec/ruby/library/stringio/printf_spec.rb
+++ b/spec/ruby/library/stringio/printf_spec.rb
@@ -8,7 +8,7 @@ describe "StringIO#printf" do
end
it "returns nil" do
- @io.printf("%d %04x", 123, 123).should be_nil
+ @io.printf("%d %04x", 123, 123).should == nil
end
it "pads self with \\000 when the current position is after the end" do
@@ -24,10 +24,10 @@ describe "StringIO#printf" do
it "updates the current position" do
@io.printf("%d %04x", 123, 123)
- @io.pos.should eql(8)
+ @io.pos.should.eql?(8)
@io.printf("%d %04x", 123, 123)
- @io.pos.should eql(16)
+ @io.pos.should.eql?(16)
end
describe "formatting" do
@@ -56,7 +56,7 @@ describe "StringIO#printf when in read-write mode" do
it "correctly updates self's position" do
@io.printf("%s", "abc")
- @io.pos.should eql(3)
+ @io.pos.should.eql?(3)
end
end
@@ -75,17 +75,17 @@ describe "StringIO#printf when in append mode" do
it "correctly updates self's position" do
@io.printf("%d %04x", 123, 123)
- @io.pos.should eql(15)
+ @io.pos.should.eql?(15)
end
end
describe "StringIO#printf when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io.printf("test") }.should raise_error(IOError)
+ -> { io.printf("test") }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io.printf("test") }.should raise_error(IOError)
+ -> { io.printf("test") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb
index 9f1ac8ffb2..742f8623eb 100644
--- a/spec/ruby/library/stringio/putc_spec.rb
+++ b/spec/ruby/library/stringio/putc_spec.rb
@@ -22,7 +22,7 @@ describe "StringIO#putc when passed [String]" do
it "returns the passed String" do
str = "test"
- @io.putc(str).should equal(str)
+ @io.putc(str).should.equal?(str)
end
it "correctly updates the current position" do
@@ -79,7 +79,7 @@ describe "StringIO#putc when passed [Object]" do
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { @io.putc(Object.new) }.should raise_error(TypeError)
+ -> { @io.putc(Object.new) }.should.raise(TypeError)
end
end
@@ -94,10 +94,10 @@ end
describe "StringIO#putc when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io.putc(?a) }.should raise_error(IOError)
+ -> { io.putc(?a) }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io.putc("t") }.should raise_error(IOError)
+ -> { io.putc("t") }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb
index 054ec8227f..ebe74d4a45 100644
--- a/spec/ruby/library/stringio/puts_spec.rb
+++ b/spec/ruby/library/stringio/puts_spec.rb
@@ -123,7 +123,7 @@ describe "StringIO#puts when passed no arguments" do
end
it "returns nil" do
- @io.puts.should be_nil
+ @io.puts.should == nil
end
it "prints a newline" do
@@ -158,18 +158,18 @@ describe "StringIO#puts when in append mode" do
it "correctly updates self's position" do
@io.puts(", testing")
- @io.pos.should eql(17)
+ @io.pos.should.eql?(17)
end
end
describe "StringIO#puts when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io.puts }.should raise_error(IOError)
+ -> { io.puts }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io.puts }.should raise_error(IOError)
+ -> { io.puts }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb
index 74736f7792..38ae7541ca 100644
--- a/spec/ruby/library/stringio/read_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/read_nonblock_spec.rb
@@ -45,7 +45,7 @@ describe "StringIO#read_nonblock" do
stringio.rewind
stringio.read_nonblock(5).should == "hello"
- stringio.read_nonblock(5, exception: false).should be_nil
+ stringio.read_nonblock(5, exception: false).should == nil
end
end
end
diff --git a/spec/ruby/library/stringio/read_spec.rb b/spec/ruby/library/stringio/read_spec.rb
index e49f262127..9a2086a682 100644
--- a/spec/ruby/library/stringio/read_spec.rb
+++ b/spec/ruby/library/stringio/read_spec.rb
@@ -39,7 +39,7 @@ describe "StringIO#read when passed [length]" do
it "returns nil when self's position is at the end" do
@io.pos = 7
- @io.read(10).should be_nil
+ @io.read(10).should == nil
end
it "returns an empty String when length is 0" do
@@ -57,6 +57,6 @@ describe "StringIO#read when passed length and a buffer" do
result = @io.read(10, buf)
buf.should == "abcdefghij"
- result.should equal(buf)
+ result.should.equal?(buf)
end
end
diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb
index b16a16e23f..3f026080e2 100644
--- a/spec/ruby/library/stringio/readline_spec.rb
+++ b/spec/ruby/library/stringio/readline_spec.rb
@@ -1,150 +1,58 @@
require_relative '../../spec_helper'
+require "stringio"
require_relative 'fixtures/classes'
+require_relative "shared/gets"
+describe "StringIO#readline" do
+ describe "when passed [separator]" do
+ it_behaves_like :stringio_gets_separator, :readline
-describe "StringIO#readline when passed [separator]" do
- before :each do
- @io = StringIO.new("this>is>an>example")
- end
-
- it "returns the data read till the next occurrence of the passed separator" do
- @io.readline(">").should == "this>"
- @io.readline(">").should == "is>"
- @io.readline(">").should == "an>"
- @io.readline(">").should == "example"
- end
-
- it "sets $_ to the read content" do
- @io.readline(">")
- $_.should == "this>"
- @io.readline(">")
- $_.should == "is>"
- @io.readline(">")
- $_.should == "an>"
- @io.readline(">")
- $_.should == "example"
- end
-
- it "updates self's lineno by one" do
- @io.readline(">")
- @io.lineno.should eql(1)
-
- @io.readline(">")
- @io.lineno.should eql(2)
-
- @io.readline(">")
- @io.lineno.should eql(3)
- end
-
- it "returns the next paragraph when the passed separator is an empty String" do
- io = StringIO.new("this is\n\nan example")
- io.readline("").should == "this is\n\n"
- io.readline("").should == "an example"
- end
-
- it "returns the remaining content starting at the current position when passed nil" do
- io = StringIO.new("this is\n\nan example")
- io.pos = 5
- io.readline(nil).should == "is\n\nan example"
- end
-
- it "tries to convert the passed separator to a String using #to_str" do
- obj = mock('to_str')
- obj.should_receive(:to_str).and_return(">")
- @io.readline(obj).should == "this>"
- end
-end
-
-describe "StringIO#readline when passed no argument" do
- before :each do
- @io = StringIO.new("this is\nan example\nfor StringIO#readline")
- end
-
- it "returns the data read till the next occurrence of $/ or till eof" do
- @io.readline.should == "this is\n"
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- begin
- old_sep = $/
- suppress_warning {$/ = " "}
- @io.readline.should == "an "
- @io.readline.should == "example\nfor "
- @io.readline.should == "StringIO#readline"
- ensure
- suppress_warning {$/ = old_sep}
+ @io.pos = 36
+ -> { @io.readline(">") }.should.raise(IOError)
end
end
- it "sets $_ to the read content" do
- @io.readline
- $_.should == "this is\n"
- @io.readline
- $_.should == "an example\n"
- @io.readline
- $_.should == "for StringIO#readline"
- end
+ describe "when passed [limit]" do
+ it_behaves_like :stringio_gets_limit, :readline
- it "updates self's position" do
- @io.readline
- @io.pos.should eql(8)
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- @io.readline
- @io.pos.should eql(19)
-
- @io.readline
- @io.pos.should eql(40)
+ @io.pos = 36
+ -> { @io.readline(3) }.should.raise(IOError)
+ end
end
- it "updates self's lineno" do
- @io.readline
- @io.lineno.should eql(1)
+ describe "when passed [separator] and [limit]" do
+ it_behaves_like :stringio_gets_separator_and_limit, :readline
- @io.readline
- @io.lineno.should eql(2)
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- @io.readline
- @io.lineno.should eql(3)
- end
-
- it "raises an IOError if self is at the end" do
- @io.pos = 40
- -> { @io.readline }.should raise_error(IOError)
- end
-end
-
-describe "StringIO#readline when in write-only mode" do
- it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
- -> { io.readline }.should raise_error(IOError)
-
- io = StringIO.new("xyz")
- io.close_read
- -> { io.readline }.should raise_error(IOError)
+ @io.pos = 36
+ -> { @io.readline(">", 3) }.should.raise(IOError)
+ end
end
-end
-describe "StringIO#readline when passed [chomp]" do
- it "returns the data read without a trailing newline character" do
- io = StringIO.new("this>is>an>example\n")
- io.readline(chomp: true).should == "this>is>an>example"
- end
-end
+ describe "when passed no argument" do
+ it_behaves_like :stringio_gets_no_argument, :readline
-describe "StringIO#readline when passed [limit]" do
- before :each do
- @io = StringIO.new("this>is>an>example")
- end
+ it "raises an IOError if self is at the end" do
+ @io = StringIO.new("this>is>an>example")
- it "returns the data read until the limit is met" do
- io = StringIO.new("this>is>an>example\n")
- io.readline(3).should == "thi"
+ @io.pos = 36
+ -> { @io.readline }.should.raise(IOError)
+ end
end
- it "returns a blank string when passed a limit of 0" do
- @io.readline(0).should == ""
+ describe "when passed [chomp]" do
+ it_behaves_like :stringio_gets_chomp, :readline
end
- it "ignores it when the limit is negative" do
- seen = []
- @io.readline(-4).should == "this>is>an>example"
+ describe "when in write-only mode" do
+ it_behaves_like :stringio_gets_write_only, :readline
end
end
diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb
index ed7cc22b3d..821a8169e7 100644
--- a/spec/ruby/library/stringio/readlines_spec.rb
+++ b/spec/ruby/library/stringio/readlines_spec.rb
@@ -12,12 +12,12 @@ describe "StringIO#readlines when passed [separator]" do
it "updates self's position based on the number of read bytes" do
@io.readlines(">")
- @io.pos.should eql(18)
+ @io.pos.should.eql?(18)
end
it "updates self's lineno based on the number of read lines" do
@io.readlines(">")
- @io.lineno.should eql(4)
+ @io.lineno.should.eql?(4)
end
it "does not change $_" do
@@ -61,12 +61,12 @@ describe "StringIO#readlines when passed no argument" do
it "updates self's position based on the number of read bytes" do
@io.readlines
- @io.pos.should eql(41)
+ @io.pos.should.eql?(41)
end
it "updates self's lineno based on the number of read lines" do
@io.readlines
- @io.lineno.should eql(3)
+ @io.lineno.should.eql?(3)
end
it "does not change $_" do
@@ -84,11 +84,11 @@ end
describe "StringIO#readlines when in write-only mode" do
it "raises an IOError" do
io = StringIO.new(+"xyz", "w")
- -> { io.readlines }.should raise_error(IOError)
+ -> { io.readlines }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.readlines }.should raise_error(IOError)
+ -> { io.readlines }.should.raise(IOError)
end
end
@@ -109,7 +109,7 @@ describe "StringIO#readlines when passed [limit]" do
end
it "raises ArgumentError when limit is 0" do
- -> { @io.readlines(0) }.should raise_error(ArgumentError)
+ -> { @io.readlines(0) }.should.raise(ArgumentError)
end
it "ignores it when the limit is negative" do
diff --git a/spec/ruby/library/stringio/readpartial_spec.rb b/spec/ruby/library/stringio/readpartial_spec.rb
index f25cef4014..e05d9bded4 100644
--- a/spec/ruby/library/stringio/readpartial_spec.rb
+++ b/spec/ruby/library/stringio/readpartial_spec.rb
@@ -10,13 +10,7 @@ describe "StringIO#readpartial" do
@string.close unless @string.closed?
end
- it "raises IOError on closed stream" do
- @string.close
- -> { @string.readpartial(10) }.should raise_error(IOError)
- end
-
it "reads at most the specified number of bytes" do
-
# buffered read
@string.read(1).should == 'S'
# return only specified number, not the whole buffer
@@ -30,6 +24,14 @@ describe "StringIO#readpartial" do
@string.readpartial(3).should == ", l"
end
+ it "reads after ungetc with multibyte characters in the buffer" do
+ @string = StringIO.new(+"∂φ/∂x = gaîté")
+ c = @string.getc
+ @string.ungetc(c)
+ @string.readpartial(3).should == "\xE2\x88\x82".b
+ @string.readpartial(3).should == "\xCF\x86/".b
+ end
+
it "reads after ungetc without data in the buffer" do
@string = StringIO.new
@string.write("f").should == 1
@@ -55,26 +57,46 @@ describe "StringIO#readpartial" do
it "raises EOFError on EOF" do
@string.readpartial(18).should == 'Stop, look, listen'
- -> { @string.readpartial(10) }.should raise_error(EOFError)
+ -> { @string.readpartial(10) }.should.raise(EOFError)
end
it "discards the existing buffer content upon error" do
buffer = +'hello'
@string.readpartial(100)
- -> { @string.readpartial(1, buffer) }.should raise_error(EOFError)
- buffer.should be_empty
+ -> { @string.readpartial(1, buffer) }.should.raise(EOFError)
+ buffer.should.empty?
end
it "raises IOError if the stream is closed" do
@string.close
- -> { @string.readpartial(1) }.should raise_error(IOError)
+ -> { @string.readpartial(1) }.should.raise(IOError, "not opened for reading")
end
it "raises ArgumentError if the negative argument is provided" do
- -> { @string.readpartial(-1) }.should raise_error(ArgumentError)
+ -> { @string.readpartial(-1) }.should.raise(ArgumentError, "negative length -1 given")
end
it "immediately returns an empty string if the length argument is 0" do
@string.readpartial(0).should == ""
end
+
+ it "raises IOError if the stream is closed and the length argument is 0" do
+ @string.close
+ -> { @string.readpartial(0) }.should.raise(IOError, "not opened for reading")
+ end
+
+ it "clears and returns the given buffer if the length argument is 0" do
+ buffer = +"existing content"
+ @string.readpartial(0, buffer).should == buffer
+ buffer.should == ""
+ end
+
+ version_is StringIO::VERSION, "3.1.2" do # ruby_version_is "3.4"
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @string.readpartial(10, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+ end
end
diff --git a/spec/ruby/library/stringio/reopen_spec.rb b/spec/ruby/library/stringio/reopen_spec.rb
index 7021ff17e5..3d4ae3a698 100644
--- a/spec/ruby/library/stringio/reopen_spec.rb
+++ b/spec/ruby/library/stringio/reopen_spec.rb
@@ -8,18 +8,18 @@ describe "StringIO#reopen when passed [Object, Integer]" do
it "reopens self with the passed Object in the passed mode" do
@io.reopen("reopened", IO::RDONLY)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
@io.string.should == "reopened"
@io.reopen(+"reopened, twice", IO::WRONLY)
- @io.closed_read?.should be_true
- @io.closed_write?.should be_false
+ @io.closed_read?.should == true
+ @io.closed_write?.should == false
@io.string.should == "reopened, twice"
@io.reopen(+"reopened, another time", IO::RDWR)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == "reopened, another time"
end
@@ -31,16 +31,16 @@ describe "StringIO#reopen when passed [Object, Integer]" do
end
it "raises a TypeError when the passed Object can't be converted to a String" do
- -> { @io.reopen(Object.new, IO::RDWR) }.should raise_error(TypeError)
+ -> { @io.reopen(Object.new, IO::RDWR) }.should.raise(TypeError)
end
it "raises an Errno::EACCES when trying to reopen self with a frozen String in write-mode" do
- -> { @io.reopen("burn".freeze, IO::WRONLY) }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, IO::WRONLY | IO::APPEND) }.should raise_error(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, IO::WRONLY) }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, IO::WRONLY | IO::APPEND) }.should.raise(Errno::EACCES)
end
it "raises a FrozenError when trying to reopen self with a frozen String in truncate-mode" do
- -> { @io.reopen("burn".freeze, IO::RDONLY | IO::TRUNC) }.should raise_error(FrozenError)
+ -> { @io.reopen("burn".freeze, IO::RDONLY | IO::TRUNC) }.should.raise(FrozenError)
end
it "does not raise IOError when passed a frozen String in read-mode" do
@@ -56,23 +56,23 @@ describe "StringIO#reopen when passed [Object, Object]" do
it "reopens self with the passed Object in the passed mode" do
@io.reopen("reopened", "r")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
@io.string.should == "reopened"
@io.reopen(+"reopened, twice", "r+")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == "reopened, twice"
@io.reopen(+"reopened, another", "w+")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == ""
@io.reopen(+"reopened, another time", "r+")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
@io.string.should == "reopened, another time"
end
@@ -89,35 +89,35 @@ describe "StringIO#reopen when passed [Object, Object]" do
end
it "raises a TypeError when the passed Object can't be converted to a String using #to_str" do
- -> { @io.reopen(Object.new, "r") }.should raise_error(TypeError)
+ -> { @io.reopen(Object.new, "r") }.should.raise(TypeError)
end
it "resets self's position to 0" do
@io.read(5)
@io.reopen(+"reopened")
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
end
it "resets self's line number to 0" do
@io.gets
@io.reopen(+"reopened")
- @io.lineno.should eql(0)
+ @io.lineno.should.eql?(0)
end
it "tries to convert the passed mode Object to an Integer using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return("r")
@io.reopen("reopened", obj)
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
+ @io.closed_read?.should == false
+ @io.closed_write?.should == true
@io.string.should == "reopened"
end
it "raises an Errno::EACCES error when trying to reopen self with a frozen String in write-mode" do
- -> { @io.reopen("burn".freeze, 'w') }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, 'w+') }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, 'a') }.should raise_error(Errno::EACCES)
- -> { @io.reopen("burn".freeze, "r+") }.should raise_error(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, 'w') }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, 'w+') }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, 'a') }.should.raise(Errno::EACCES)
+ -> { @io.reopen("burn".freeze, "r+") }.should.raise(Errno::EACCES)
end
it "does not raise IOError if a frozen string is passed in read mode" do
@@ -136,8 +136,8 @@ describe "StringIO#reopen when passed [String]" do
@io.reopen(+"reopened")
- @io.closed_write?.should be_false
- @io.closed_read?.should be_false
+ @io.closed_write?.should == false
+ @io.closed_read?.should == false
@io.string.should == "reopened"
end
@@ -145,13 +145,13 @@ describe "StringIO#reopen when passed [String]" do
it "resets self's position to 0" do
@io.read(5)
@io.reopen(+"reopened")
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
end
it "resets self's line number to 0" do
@io.gets
@io.reopen(+"reopened")
- @io.lineno.should eql(0)
+ @io.lineno.should.eql?(0)
end
end
@@ -161,13 +161,13 @@ describe "StringIO#reopen when passed [Object]" do
end
it "raises a TypeError when passed an Object that can't be converted to a StringIO" do
- -> { @io.reopen(Object.new) }.should raise_error(TypeError)
+ -> { @io.reopen(Object.new) }.should.raise(TypeError)
end
it "does not try to convert the passed Object to a String using #to_str" do
obj = mock("not to_str")
obj.should_not_receive(:to_str)
- -> { @io.reopen(obj) }.should raise_error(TypeError)
+ -> { @io.reopen(obj) }.should.raise(TypeError)
end
it "tries to convert the passed Object to a StringIO using #to_strio" do
@@ -186,20 +186,20 @@ describe "StringIO#reopen when passed no arguments" do
it "resets self's mode to read-write" do
@io.close
@io.reopen
- @io.closed_read?.should be_false
- @io.closed_write?.should be_false
+ @io.closed_read?.should == false
+ @io.closed_write?.should == false
end
it "resets self's position to 0" do
@io.read(5)
@io.reopen
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
end
it "resets self's line number to 0" do
@io.gets
@io.reopen
- @io.lineno.should eql(0)
+ @io.lineno.should.eql?(0)
end
end
diff --git a/spec/ruby/library/stringio/rewind_spec.rb b/spec/ruby/library/stringio/rewind_spec.rb
index 5f885ecf81..8c48709d89 100644
--- a/spec/ruby/library/stringio/rewind_spec.rb
+++ b/spec/ruby/library/stringio/rewind_spec.rb
@@ -9,7 +9,7 @@ describe "StringIO#rewind" do
end
it "returns 0" do
- @io.rewind.should eql(0)
+ @io.rewind.should.eql?(0)
end
it "resets the position" do
diff --git a/spec/ruby/library/stringio/seek_spec.rb b/spec/ruby/library/stringio/seek_spec.rb
index 253b5027a9..9043e0338f 100644
--- a/spec/ruby/library/stringio/seek_spec.rb
+++ b/spec/ruby/library/stringio/seek_spec.rb
@@ -9,18 +9,18 @@ describe "StringIO#seek" do
it "seeks from the current position when whence is IO::SEEK_CUR" do
@io.pos = 1
@io.seek(1, IO::SEEK_CUR)
- @io.pos.should eql(2)
+ @io.pos.should.eql?(2)
@io.seek(-1, IO::SEEK_CUR)
- @io.pos.should eql(1)
+ @io.pos.should.eql?(1)
end
it "seeks from the end of self when whence is IO::SEEK_END" do
@io.seek(3, IO::SEEK_END)
- @io.pos.should eql(11) # Outside of the StringIO's content
+ @io.pos.should.eql?(11) # Outside of the StringIO's content
@io.seek(-2, IO::SEEK_END)
- @io.pos.should eql(6)
+ @io.pos.should.eql?(6)
end
it "seeks to an absolute position when whence is IO::SEEK_SET" do
@@ -33,25 +33,25 @@ describe "StringIO#seek" do
end
it "raises an Errno::EINVAL error on negative amounts when whence is IO::SEEK_SET" do
- -> { @io.seek(-5, IO::SEEK_SET) }.should raise_error(Errno::EINVAL)
+ -> { @io.seek(-5, IO::SEEK_SET) }.should.raise(Errno::EINVAL)
end
it "raises an Errno::EINVAL error on incorrect whence argument" do
- -> { @io.seek(0, 3) }.should raise_error(Errno::EINVAL)
- -> { @io.seek(0, -1) }.should raise_error(Errno::EINVAL)
- -> { @io.seek(0, 2**16) }.should raise_error(Errno::EINVAL)
- -> { @io.seek(0, -2**16) }.should raise_error(Errno::EINVAL)
+ -> { @io.seek(0, 3) }.should.raise(Errno::EINVAL)
+ -> { @io.seek(0, -1) }.should.raise(Errno::EINVAL)
+ -> { @io.seek(0, 2**16) }.should.raise(Errno::EINVAL)
+ -> { @io.seek(0, -2**16) }.should.raise(Errno::EINVAL)
end
it "tries to convert the passed Object to a String using #to_int" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(2)
@io.seek(obj)
- @io.pos.should eql(2)
+ @io.pos.should.eql?(2)
end
it "raises a TypeError when the passed Object can't be converted to an Integer" do
- -> { @io.seek(Object.new) }.should raise_error(TypeError)
+ -> { @io.seek(Object.new) }.should.raise(TypeError)
end
end
@@ -62,6 +62,6 @@ describe "StringIO#seek when self is closed" do
end
it "raises an IOError" do
- -> { @io.seek(5) }.should raise_error(IOError)
+ -> { @io.seek(5) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb
index 1030aad042..b4583a7ad7 100644
--- a/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb
+++ b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb
@@ -6,7 +6,7 @@ describe "StringIO#set_encoding_by_bom" do
it "returns nil if not readable" do
io = StringIO.new("".b, "wb")
- io.set_encoding_by_bom.should be_nil
+ io.set_encoding_by_bom.should == nil
io.external_encoding.should == Encoding::ASCII_8BIT
end
@@ -82,7 +82,7 @@ describe "StringIO#set_encoding_by_bom" do
it "returns nil if io is empty" do
io = StringIO.new("".b, "rb")
- io.set_encoding_by_bom.should be_nil
+ io.set_encoding_by_bom.should == nil
io.external_encoding.should == Encoding::ASCII_8BIT
end
@@ -227,7 +227,7 @@ describe "StringIO#set_encoding_by_bom" do
it "raises FrozenError when io is frozen" do
io = StringIO.new()
io.freeze
- -> { io.set_encoding_by_bom }.should raise_error(FrozenError)
+ -> { io.set_encoding_by_bom }.should.raise(FrozenError)
end
it "does not raise FrozenError when initial string is frozen" do
diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb
index 25333bb0fd..e35a02ccb4 100644
--- a/spec/ruby/library/stringio/shared/codepoints.rb
+++ b/spec/ruby/library/stringio/shared/codepoints.rb
@@ -6,7 +6,7 @@ describe :stringio_codepoints, shared: true do
end
it "returns an Enumerator" do
- @enum.should be_an_instance_of(Enumerator)
+ @enum.should.instance_of?(Enumerator)
end
it "yields each codepoint code in turn" do
@@ -20,15 +20,15 @@ describe :stringio_codepoints, shared: true do
it "raises an error if reading invalid sequence" do
@io.pos = 1 # inside of a multibyte sequence
- -> { @enum.first }.should raise_error(ArgumentError)
+ -> { @enum.first }.should.raise(ArgumentError)
end
it "raises an IOError if not readable" do
@io.close_read
- -> { @enum.to_a }.should raise_error(IOError)
+ -> { @enum.to_a }.should.raise(IOError)
io = StringIO.new(+"xyz", "w")
- -> { io.send(@method).to_a }.should raise_error(IOError)
+ -> { io.send(@method).to_a }.should.raise(IOError)
end
@@ -39,7 +39,7 @@ describe :stringio_codepoints, shared: true do
end
it "returns self" do
- @io.send(@method) {|l| l }.should equal(@io)
+ @io.send(@method) {|l| l }.should.equal?(@io)
end
end
diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb
index e0dd3f9b8f..04e40b6b2a 100644
--- a/spec/ruby/library/stringio/shared/each.rb
+++ b/spec/ruby/library/stringio/shared/each.rb
@@ -16,7 +16,7 @@ describe :stringio_each_separator, shared: true do
end
it "returns self" do
- @io.send(@method) {|l| l }.should equal(@io)
+ @io.send(@method) {|l| l }.should.equal?(@io)
end
it "tries to convert the passed separator to a String using #to_str" do
@@ -36,22 +36,11 @@ describe :stringio_each_separator, shared: true do
seen.should == ["2 1 2 1 2"]
end
- version_is StringIO::VERSION, ""..."3.0.4" do #ruby_version_is ""..."3.2" do
- it "yields each paragraph with two separation characters when passed an empty String as separator" do
- seen = []
- io = StringIO.new("para1\n\npara2\n\n\npara3")
- io.send(@method, "") {|s| seen << s}
- seen.should == ["para1\n\n", "para2\n\n", "para3"]
- end
- end
-
- version_is StringIO::VERSION, "3.0.4" do #ruby_version_is "3.2" do
- it "yields each paragraph with all separation characters when passed an empty String as separator" do
- seen = []
- io = StringIO.new("para1\n\npara2\n\n\npara3")
- io.send(@method, "") {|s| seen << s}
- seen.should == ["para1\n\n", "para2\n\n\n", "para3"]
- end
+ it "yields each paragraph with all separation characters when passed an empty String as separator" do
+ seen = []
+ io = StringIO.new("para1\n\npara2\n\n\npara3")
+ io.send(@method, "") {|s| seen << s}
+ seen.should == ["para1\n\n", "para2\n\n\n", "para3"]
end
end
@@ -85,19 +74,19 @@ describe :stringio_each_no_arguments, shared: true do
old_rs = $/
suppress_warning {$/ = " "}
@io.send(@method) {|s| seen << s }
- seen.should eql(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"])
+ seen.should.eql?(["a ", "b ", "c ", "d ", "e\n1 ", "2 ", "3 ", "4 ", "5"])
ensure
suppress_warning {$/ = old_rs}
end
end
it "returns self" do
- @io.send(@method) {|l| l }.should equal(@io)
+ @io.send(@method) {|l| l }.should.equal?(@io)
end
it "returns an Enumerator when passed no block" do
enum = @io.send(@method)
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
seen = []
enum.each { |b| seen << b }
@@ -108,11 +97,11 @@ end
describe :stringio_each_not_readable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"a b c d e", "w")
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
io = StringIO.new("a b c d e")
io.close_read
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
end
end
@@ -161,3 +150,60 @@ describe :stringio_each_limit, shared: true do
seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
end
end
+
+describe :stringio_each_separator_and_limit, shared: true do
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read until the limit is consumed or the separator is met" do
+ @io.send(@method, '>', 8) { |s| break s }.should == "this>"
+ @io.send(@method, '>', 2) { |s| break s }.should == "is"
+ @io.send(@method, '>', 10) { |s| break s }.should == ">"
+ @io.send(@method, '>', 6) { |s| break s }.should == "an>"
+ @io.send(@method, '>', 5) { |s| break s }.should == "examp"
+ end
+
+ it "truncates the multi-character separator at the end to meet the limit" do
+ @io.send(@method, "is>an", 7) { |s| break s }.should == "this>is"
+ end
+
+ it "does not change $_" do
+ $_ = "test"
+ @io.send(@method, '>', 8) { |s| s }
+ $_.should == "test"
+ end
+
+ it "updates self's lineno by one" do
+ @io.send(@method, '>', 3) { |s| break s }
+ @io.lineno.should.eql?(1)
+
+ @io.send(@method, '>', 3) { |s| break s }
+ @io.lineno.should.eql?(2)
+
+ @io.send(@method, '>', 3) { |s| break s }
+ @io.lineno.should.eql?(3)
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do # TODO
+ obj = mock('to_str')
+ obj.should_receive(:to_str).and_return('>')
+
+ seen = []
+ @io.send(@method, obj, 5) { |s| seen << s }
+ seen.should == ["this>", "is>", "an>", "examp", "le"]
+ end
+
+ it "does not raise TypeError if passed separator is nil" do
+ @io.send(@method, nil, 5) { |s| break s }.should == "this>"
+ end
+
+ it "tries to convert the passed limit to an Integer using #to_int" do # TODO
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(5)
+
+ seen = []
+ @io.send(@method, '>', obj) { |s| seen << s }
+ seen.should == ["this>", "is>", "an>", "examp", "le"]
+ end
+end
diff --git a/spec/ruby/library/stringio/shared/each_byte.rb b/spec/ruby/library/stringio/shared/each_byte.rb
index b51fa38f2f..b3939c26de 100644
--- a/spec/ruby/library/stringio/shared/each_byte.rb
+++ b/spec/ruby/library/stringio/shared/each_byte.rb
@@ -19,16 +19,16 @@ describe :stringio_each_byte, shared: true do
@io.pos = 1000
seen = nil
@io.send(@method) { |b| seen = b }
- seen.should be_nil
+ seen.should == nil
end
it "returns self" do
- @io.send(@method) {}.should equal(@io)
+ @io.send(@method) {}.should.equal?(@io)
end
it "returns an Enumerator when passed no block" do
enum = @io.send(@method)
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
seen = []
enum.each { |b| seen << b }
@@ -39,10 +39,10 @@ end
describe :stringio_each_byte_not_readable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"xyz", "w")
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb
index 197237c1c8..4215a9952b 100644
--- a/spec/ruby/library/stringio/shared/each_char.rb
+++ b/spec/ruby/library/stringio/shared/each_char.rb
@@ -11,12 +11,12 @@ describe :stringio_each_char, shared: true do
end
it "returns self" do
- @io.send(@method) {}.should equal(@io)
+ @io.send(@method) {}.should.equal?(@io)
end
it "returns an Enumerator when passed no block" do
enum = @io.send(@method)
- enum.instance_of?(Enumerator).should be_true
+ enum.instance_of?(Enumerator).should == true
seen = []
enum.each { |c| seen << c }
@@ -27,10 +27,10 @@ end
describe :stringio_each_char_not_readable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"xyz", "w")
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.send(@method) { |b| b } }.should raise_error(IOError)
+ -> { io.send(@method) { |b| b } }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/eof.rb b/spec/ruby/library/stringio/shared/eof.rb
index e0368a2892..a9489581fc 100644
--- a/spec/ruby/library/stringio/shared/eof.rb
+++ b/spec/ruby/library/stringio/shared/eof.rb
@@ -5,20 +5,20 @@ describe :stringio_eof, shared: true do
it "returns true when self's position is greater than or equal to self's size" do
@io.pos = 3
- @io.send(@method).should be_true
+ @io.send(@method).should == true
@io.pos = 6
- @io.send(@method).should be_true
+ @io.send(@method).should == true
end
it "returns false when self's position is less than self's size" do
@io.pos = 0
- @io.send(@method).should be_false
+ @io.send(@method).should == false
@io.pos = 1
- @io.send(@method).should be_false
+ @io.send(@method).should == false
@io.pos = 2
- @io.send(@method).should be_false
+ @io.send(@method).should == false
end
end
diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb
index ba65040bce..a146b2d4cf 100644
--- a/spec/ruby/library/stringio/shared/getc.rb
+++ b/spec/ruby/library/stringio/shared/getc.rb
@@ -5,39 +5,39 @@ describe :stringio_getc, shared: true do
it "increases self's position by one" do
@io.send(@method)
- @io.pos.should eql(1)
+ @io.pos.should.eql?(1)
@io.send(@method)
- @io.pos.should eql(2)
+ @io.pos.should.eql?(2)
@io.send(@method)
- @io.pos.should eql(3)
+ @io.pos.should.eql?(3)
end
it "returns nil when called at the end of self" do
@io.pos = 7
- @io.send(@method).should be_nil
- @io.send(@method).should be_nil
- @io.send(@method).should be_nil
+ @io.send(@method).should == nil
+ @io.send(@method).should == nil
+ @io.send(@method).should == nil
end
it "does not increase self's position when called at the end of file" do
@io.pos = 7
@io.send(@method)
- @io.pos.should eql(7)
+ @io.pos.should.eql?(7)
@io.send(@method)
- @io.pos.should eql(7)
+ @io.pos.should.eql?(7)
end
end
describe :stringio_getc_not_readable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"xyz", "w")
- -> { io.send(@method) }.should raise_error(IOError)
+ -> { io.send(@method) }.should.raise(IOError)
io = StringIO.new("xyz")
io.close_read
- -> { io.send(@method) }.should raise_error(IOError)
+ -> { io.send(@method) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/gets.rb b/spec/ruby/library/stringio/shared/gets.rb
new file mode 100644
index 0000000000..16039b18ef
--- /dev/null
+++ b/spec/ruby/library/stringio/shared/gets.rb
@@ -0,0 +1,249 @@
+describe :stringio_gets_separator, shared: true do
+ describe "when passed [separator]" do
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read till the next occurrence of the passed separator" do
+ @io.send(@method, ">").should == "this>"
+ @io.send(@method, ">").should == "is>"
+ @io.send(@method, ">").should == "an>"
+ @io.send(@method, ">").should == "example"
+ end
+
+ it "sets $_ to the read content" do
+ @io.send(@method, ">")
+ $_.should == "this>"
+ @io.send(@method, ">")
+ $_.should == "is>"
+ @io.send(@method, ">")
+ $_.should == "an>"
+ @io.send(@method, ">")
+ $_.should == "example"
+ end
+
+ it "accepts string as separator" do
+ @io.send(@method, "is>")
+ $_.should == "this>"
+ @io.send(@method, "an>")
+ $_.should == "is>an>"
+ @io.send(@method, "example")
+ $_.should == "example"
+ end
+
+ it "updates self's lineno by one" do
+ @io.send(@method, ">")
+ @io.lineno.should.eql?(1)
+
+ @io.send(@method, ">")
+ @io.lineno.should.eql?(2)
+
+ @io.send(@method, ">")
+ @io.lineno.should.eql?(3)
+ end
+
+ it "returns the next paragraph when the passed separator is an empty String" do
+ io = StringIO.new("this is\n\nan example")
+ io.send(@method, "").should == "this is\n\n"
+ io.send(@method, "").should == "an example"
+ end
+
+ it "returns the remaining content starting at the current position when passed nil" do
+ io = StringIO.new("this is\n\nan example")
+ io.pos = 5
+ io.send(@method, nil).should == "is\n\nan example"
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do
+ obj = mock('to_str')
+ obj.should_receive(:to_str).and_return(">")
+ @io.send(@method, obj).should == "this>"
+ end
+ end
+end
+
+describe :stringio_gets_limit, shared: true do
+ describe "when passed [limit]" do
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read until the limit is met" do
+ @io.send(@method, 4).should == "this"
+ @io.send(@method, 3).should == ">is"
+ @io.send(@method, 5).should == ">an>e"
+ @io.send(@method, 6).should == "xample"
+ end
+
+ it "sets $_ to the read content" do
+ @io.send(@method, 4)
+ $_.should == "this"
+ @io.send(@method, 3)
+ $_.should == ">is"
+ @io.send(@method, 5)
+ $_.should == ">an>e"
+ @io.send(@method, 6)
+ $_.should == "xample"
+ end
+
+ it "updates self's lineno by one" do
+ @io.send(@method, 3)
+ @io.lineno.should.eql?(1)
+
+ @io.send(@method, 3)
+ @io.lineno.should.eql?(2)
+
+ @io.send(@method, 3)
+ @io.lineno.should.eql?(3)
+ end
+
+ it "tries to convert the passed limit to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(4)
+ @io.send(@method, obj).should == "this"
+ end
+
+ it "returns a blank string when passed a limit of 0" do
+ @io.send(@method, 0).should == ""
+ end
+
+ it "ignores it when passed a negative limit" do
+ @io.send(@method, -4).should == "this>is>an>example"
+ end
+ end
+end
+
+describe :stringio_gets_separator_and_limit, shared: true do
+ describe "when passed [separator] and [limit]" do
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read until the limit is consumed or the separator is met" do
+ @io.send(@method, '>', 8).should == "this>"
+ @io.send(@method, '>', 2).should == "is"
+ @io.send(@method, '>', 10).should == ">"
+ @io.send(@method, '>', 6).should == "an>"
+ @io.send(@method, '>', 5).should == "examp"
+ end
+
+ it "truncates the multi-character separator at the end to meet the limit" do
+ @io.send(@method, "is>an", 7).should == "this>is"
+ end
+
+ it "sets $_ to the read content" do
+ @io.send(@method, '>', 8)
+ $_.should == "this>"
+ @io.send(@method, '>', 2)
+ $_.should == "is"
+ @io.send(@method, '>', 10)
+ $_.should == ">"
+ @io.send(@method, '>', 6)
+ $_.should == "an>"
+ @io.send(@method, '>', 5)
+ $_.should == "examp"
+ end
+
+ it "updates self's lineno by one" do
+ @io.send(@method, '>', 3)
+ @io.lineno.should.eql?(1)
+
+ @io.send(@method, '>', 3)
+ @io.lineno.should.eql?(2)
+
+ @io.send(@method, '>', 3)
+ @io.lineno.should.eql?(3)
+ end
+
+ it "tries to convert the passed separator to a String using #to_str" do
+ obj = mock('to_str')
+ obj.should_receive(:to_str).and_return('>')
+ @io.send(@method, obj, 5).should == "this>"
+ end
+
+ it "does not raise TypeError if passed separator is nil" do
+ @io.send(@method, nil, 5).should == "this>"
+ end
+
+ it "tries to convert the passed limit to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(5)
+ @io.send(@method, '>', obj).should == "this>"
+ end
+ end
+end
+
+describe :stringio_gets_no_argument, shared: true do
+ describe "when passed no argument" do
+ before :each do
+ @io = StringIO.new("this is\nan example\nfor StringIO#gets")
+ end
+
+ it "returns the data read till the next occurrence of $/ or till eof" do
+ @io.send(@method).should == "this is\n"
+
+ begin
+ old_sep = $/
+ suppress_warning {$/ = " "}
+ @io.send(@method).should == "an "
+ @io.send(@method).should == "example\nfor "
+ @io.send(@method).should == "StringIO#gets"
+ ensure
+ suppress_warning {$/ = old_sep}
+ end
+ end
+
+ it "sets $_ to the read content" do
+ @io.send(@method)
+ $_.should == "this is\n"
+ @io.send(@method)
+ $_.should == "an example\n"
+ @io.send(@method)
+ $_.should == "for StringIO#gets"
+ end
+
+ it "updates self's position" do
+ @io.send(@method)
+ @io.pos.should.eql?(8)
+
+ @io.send(@method)
+ @io.pos.should.eql?(19)
+
+ @io.send(@method)
+ @io.pos.should.eql?(36)
+ end
+
+ it "updates self's lineno" do
+ @io.send(@method)
+ @io.lineno.should.eql?(1)
+
+ @io.send(@method)
+ @io.lineno.should.eql?(2)
+
+ @io.send(@method)
+ @io.lineno.should.eql?(3)
+ end
+ end
+end
+
+describe :stringio_gets_chomp, shared: true do
+ describe "when passed [chomp]" do
+ it "returns the data read without a trailing newline character" do
+ io = StringIO.new("this>is>an>example\n")
+ io.send(@method, chomp: true).should == "this>is>an>example"
+ end
+ end
+end
+
+describe :stringio_gets_write_only, shared: true do
+ describe "when in write-only mode" do
+ it "raises an IOError" do
+ io = StringIO.new(+"xyz", "w")
+ -> { io.send(@method) }.should.raise(IOError)
+
+ io = StringIO.new("xyz")
+ io.close_read
+ -> { io.send(@method) }.should.raise(IOError)
+ end
+ end
+end
diff --git a/spec/ruby/library/stringio/shared/isatty.rb b/spec/ruby/library/stringio/shared/isatty.rb
index c9e7ee7321..2b92e8d656 100644
--- a/spec/ruby/library/stringio/shared/isatty.rb
+++ b/spec/ruby/library/stringio/shared/isatty.rb
@@ -1,5 +1,5 @@
describe :stringio_isatty, shared: true do
it "returns false" do
- StringIO.new("tty").send(@method).should be_false
+ StringIO.new("tty").send(@method).should == false
end
end
diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb
index 22f76b0fb0..6e04e75dba 100644
--- a/spec/ruby/library/stringio/shared/read.rb
+++ b/spec/ruby/library/stringio/shared/read.rb
@@ -5,9 +5,9 @@ describe :stringio_read, shared: true do
it "returns the passed buffer String" do
# Note: Rubinius bug:
- # @io.send(@method, 7, buffer = +"").should equal(buffer)
+ # @io.send(@method, 7, buffer = +"").should.equal?(buffer)
ret = @io.send(@method, 7, buffer = +"")
- ret.should equal(buffer)
+ ret.should.equal?(buffer)
end
it "reads length bytes and writes them to the buffer String" do
@@ -42,11 +42,11 @@ describe :stringio_read, shared: true do
end
it "raises a TypeError when the passed buffer Object can't be converted to a String" do
- -> { @io.send(@method, 7, Object.new) }.should raise_error(TypeError)
+ -> { @io.send(@method, 7, Object.new) }.should.raise(TypeError)
end
it "raises a FrozenError error when passed a frozen String as buffer" do
- -> { @io.send(@method, 7, "".freeze) }.should raise_error(FrozenError)
+ -> { @io.send(@method, 7, "".freeze) }.should.raise(FrozenError)
end
end
@@ -66,10 +66,10 @@ describe :stringio_read_length, shared: true do
it "correctly updates the position" do
@io.send(@method, 3)
- @io.pos.should eql(3)
+ @io.pos.should.eql?(3)
@io.send(@method, 999)
- @io.pos.should eql(7)
+ @io.pos.should.eql?(7)
end
it "tries to convert the passed length to an Integer using #to_int" do
@@ -79,11 +79,11 @@ describe :stringio_read_length, shared: true do
end
it "raises a TypeError when the passed length can't be converted to an Integer" do
- -> { @io.send(@method, Object.new) }.should raise_error(TypeError)
+ -> { @io.send(@method, Object.new) }.should.raise(TypeError)
end
it "raises a TypeError when the passed length is negative" do
- -> { @io.send(@method, -2) }.should raise_error(ArgumentError)
+ -> { @io.send(@method, -2) }.should.raise(ArgumentError)
end
it "returns a binary String" do
@@ -105,13 +105,13 @@ describe :stringio_read_no_arguments, shared: true do
it "correctly updates the current position" do
@io.send(@method)
- @io.pos.should eql(7)
+ @io.pos.should.eql?(7)
end
it "correctly update the current position in bytes when multi-byte characters are used" do
@io.print("example\u03A3") # Overwrite the original string with 8 characters containing 9 bytes.
@io.send(@method)
- @io.pos.should eql(9)
+ @io.pos.should.eql?(9)
end
end
@@ -129,17 +129,17 @@ describe :stringio_read_nil, shared: true do
it "updates the current position" do
@io.send(@method, nil)
- @io.pos.should eql(7)
+ @io.pos.should.eql?(7)
end
end
describe :stringio_read_not_readable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"test", "w")
- -> { io.send(@method) }.should raise_error(IOError)
+ -> { io.send(@method) }.should.raise(IOError)
io = StringIO.new("test")
io.close_read
- -> { io.send(@method) }.should raise_error(IOError)
+ -> { io.send(@method) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/readchar.rb b/spec/ruby/library/stringio/shared/readchar.rb
index 72d7446c36..5ac28e0743 100644
--- a/spec/ruby/library/stringio/shared/readchar.rb
+++ b/spec/ruby/library/stringio/shared/readchar.rb
@@ -13,17 +13,17 @@ describe :stringio_readchar, shared: true do
it "raises an EOFError when self is at the end" do
@io.pos = 7
- -> { @io.send(@method) }.should raise_error(EOFError)
+ -> { @io.send(@method) }.should.raise(EOFError)
end
end
describe :stringio_readchar_not_readable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"a b c d e", "w")
- -> { io.send(@method) }.should raise_error(IOError)
+ -> { io.send(@method) }.should.raise(IOError)
io = StringIO.new("a b c d e")
io.close_read
- -> { io.send(@method) }.should raise_error(IOError)
+ -> { io.send(@method) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb
index 3e23fbc233..bc448d3379 100644
--- a/spec/ruby/library/stringio/shared/sysread.rb
+++ b/spec/ruby/library/stringio/shared/sysread.rb
@@ -10,6 +10,6 @@ describe :stringio_sysread_length, shared: true do
it "raises an EOFError when passed length > 0 and no data remains" do
@io.read.should == "example"
- -> { @io.send(@method, 1) }.should raise_error(EOFError)
+ -> { @io.send(@method, 1) }.should.raise(EOFError)
end
end
diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb
index 4661658baf..b6bffe7f12 100644
--- a/spec/ruby/library/stringio/shared/write.rb
+++ b/spec/ruby/library/stringio/shared/write.rb
@@ -42,7 +42,7 @@ describe :stringio_write_string, shared: true do
it "updates self's position" do
@io.send(@method, 'test')
- @io.pos.should eql(4)
+ @io.pos.should.eql?(4)
end
it "handles concurrent writes correctly" do
@@ -107,11 +107,11 @@ end
describe :stringio_write_not_writable, shared: true do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io.send(@method, "test") }.should raise_error(IOError)
+ -> { io.send(@method, "test") }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io.send(@method, "test") }.should raise_error(IOError)
+ -> { io.send(@method, "test") }.should.raise(IOError)
end
end
@@ -130,6 +130,6 @@ describe :stringio_write_append, shared: true do
it "correctly updates self's position" do
@io.send(@method, ", testing")
- @io.pos.should eql(16)
+ @io.pos.should.eql?(16)
end
end
diff --git a/spec/ruby/library/stringio/string_spec.rb b/spec/ruby/library/stringio/string_spec.rb
index 1ed5233ba6..3b27243da9 100644
--- a/spec/ruby/library/stringio/string_spec.rb
+++ b/spec/ruby/library/stringio/string_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "StringIO#string" do
it "returns the underlying string" do
io = StringIO.new(str = "hello")
- io.string.should equal(str)
+ io.string.should.equal?(str)
end
end
@@ -15,25 +15,25 @@ describe "StringIO#string=" do
it "returns the passed String" do
str = "test"
- (@io.string = str).should equal(str)
+ (@io.string = str).should.equal?(str)
end
it "changes the underlying string" do
str = "hello"
@io.string = str
- @io.string.should equal(str)
+ @io.string.should.equal?(str)
end
it "resets the position" do
@io.pos = 1
@io.string = "other"
- @io.pos.should eql(0)
+ @io.pos.should.eql?(0)
end
it "resets the line number" do
@io.lineno = 1
@io.string = "other"
- @io.lineno.should eql(0)
+ @io.lineno.should.eql?(0)
end
it "tries to convert the passed Object to a String using #to_str" do
@@ -45,6 +45,6 @@ describe "StringIO#string=" do
end
it "raises a TypeError when the passed Object can't be converted to an Integer" do
- -> { @io.seek(Object.new) }.should raise_error(TypeError)
+ -> { @io.seek(Object.new) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/stringio/stringio_spec.rb b/spec/ruby/library/stringio/stringio_spec.rb
index 5ef42b3390..dee0364ab0 100644
--- a/spec/ruby/library/stringio/stringio_spec.rb
+++ b/spec/ruby/library/stringio/stringio_spec.rb
@@ -3,6 +3,6 @@ require "stringio"
describe "StringIO" do
it "includes the Enumerable module" do
- StringIO.should include(Enumerable)
+ StringIO.should.include?(Enumerable)
end
end
diff --git a/spec/ruby/library/stringio/sync_spec.rb b/spec/ruby/library/stringio/sync_spec.rb
index e717a5697b..d7d1209047 100644
--- a/spec/ruby/library/stringio/sync_spec.rb
+++ b/spec/ruby/library/stringio/sync_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#sync" do
it "returns true" do
- StringIO.new('').sync.should be_true
+ StringIO.new('').sync.should == true
end
end
@@ -14,6 +14,6 @@ describe "StringIO#sync=" do
it "does not change 'sync' status" do
@io.sync = false
- @io.sync.should be_true
+ @io.sync.should == true
end
end
diff --git a/spec/ruby/library/stringio/sysread_spec.rb b/spec/ruby/library/stringio/sysread_spec.rb
index fabb06dd9a..1403dab5cb 100644
--- a/spec/ruby/library/stringio/sysread_spec.rb
+++ b/spec/ruby/library/stringio/sysread_spec.rb
@@ -44,7 +44,7 @@ describe "StringIO#sysread when passed [length]" do
it "raises an EOFError when self's position is at the end" do
@io.pos = 7
- -> { @io.sysread(10) }.should raise_error(EOFError)
+ -> { @io.sysread(10) }.should.raise(EOFError)
end
it "returns an empty String when length is 0" do
diff --git a/spec/ruby/library/stringio/truncate_spec.rb b/spec/ruby/library/stringio/truncate_spec.rb
index 592ca5a6e1..7205261141 100644
--- a/spec/ruby/library/stringio/truncate_spec.rb
+++ b/spec/ruby/library/stringio/truncate_spec.rb
@@ -7,7 +7,7 @@ describe "StringIO#truncate when passed [length]" do
end
it "returns an Integer" do
- @io.truncate(4).should be_kind_of(Integer)
+ @io.truncate(4).should.is_a?(Integer)
end
it "truncated the underlying string down to the passed length" do
@@ -18,13 +18,13 @@ describe "StringIO#truncate when passed [length]" do
it "does not create a copy of the underlying string" do
io = StringIO.new(str = +"123456789")
io.truncate(4)
- io.string.should equal(str)
+ io.string.should.equal?(str)
end
it "does not change the position" do
@io.pos = 7
@io.truncate(4)
- @io.pos.should eql(7)
+ @io.pos.should.eql?(7)
end
it "can grow a string to a larger size, padding it with \\000" do
@@ -33,8 +33,8 @@ describe "StringIO#truncate when passed [length]" do
end
it "raises an Errno::EINVAL when the passed length is negative" do
- -> { @io.truncate(-1) }.should raise_error(Errno::EINVAL)
- -> { @io.truncate(-10) }.should raise_error(Errno::EINVAL)
+ -> { @io.truncate(-1) }.should.raise(Errno::EINVAL)
+ -> { @io.truncate(-10) }.should.raise(Errno::EINVAL)
end
it "tries to convert the passed length to an Integer using #to_int" do
@@ -46,17 +46,17 @@ describe "StringIO#truncate when passed [length]" do
end
it "raises a TypeError when the passed length can't be converted to an Integer" do
- -> { @io.truncate(Object.new) }.should raise_error(TypeError)
+ -> { @io.truncate(Object.new) }.should.raise(TypeError)
end
end
describe "StringIO#truncate when self is not writable" do
it "raises an IOError" do
io = StringIO.new(+"test", "r")
- -> { io.truncate(2) }.should raise_error(IOError)
+ -> { io.truncate(2) }.should.raise(IOError)
io = StringIO.new(+"test")
io.close_write
- -> { io.truncate(2) }.should raise_error(IOError)
+ -> { io.truncate(2) }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/stringio/ungetc_spec.rb b/spec/ruby/library/stringio/ungetc_spec.rb
index bceafa79ff..8753ac9666 100644
--- a/spec/ruby/library/stringio/ungetc_spec.rb
+++ b/spec/ruby/library/stringio/ungetc_spec.rb
@@ -14,13 +14,13 @@ describe "StringIO#ungetc when passed [char]" do
it "returns nil" do
@io.pos = 1
- @io.ungetc(?A).should be_nil
+ @io.ungetc(?A).should == nil
end
it "decreases the current position by one" do
@io.pos = 2
@io.ungetc(?A)
- @io.pos.should eql(1)
+ @io.pos.should.eql?(1)
end
it "pads with \\000 when the current position is after the end" do
@@ -39,7 +39,7 @@ describe "StringIO#ungetc when passed [char]" do
end
it "raises a TypeError when the passed length can't be converted to an Integer or String" do
- -> { @io.ungetc(Object.new) }.should raise_error(TypeError)
+ -> { @io.ungetc(Object.new) }.should.raise(TypeError)
end
end
@@ -47,12 +47,12 @@ describe "StringIO#ungetc when self is not readable" do
it "raises an IOError" do
io = StringIO.new(+"test", "w")
io.pos = 1
- -> { io.ungetc(?A) }.should raise_error(IOError)
+ -> { io.ungetc(?A) }.should.raise(IOError)
io = StringIO.new(+"test")
io.pos = 1
io.close_read
- -> { io.ungetc(?A) }.should raise_error(IOError)
+ -> { io.ungetc(?A) }.should.raise(IOError)
end
end
@@ -62,11 +62,11 @@ end
# it "raises an IOError" do
# io = StringIO.new(+"test", "r")
# io.pos = 1
-# lambda { io.ungetc(?A) }.should raise_error(IOError)
+# lambda { io.ungetc(?A) }.should.raise(IOError)
#
# io = StringIO.new(+"test")
# io.pos = 1
# io.close_write
-# lambda { io.ungetc(?A) }.should raise_error(IOError)
+# lambda { io.ungetc(?A) }.should.raise(IOError)
# end
# end
diff --git a/spec/ruby/library/stringscanner/check_spec.rb b/spec/ruby/library/stringscanner/check_spec.rb
index 235f2f22e9..232158b09e 100644
--- a/spec/ruby/library/stringscanner/check_spec.rb
+++ b/spec/ruby/library/stringscanner/check_spec.rb
@@ -33,33 +33,31 @@ describe "StringScanner#check" do
it "returns nil when matching failed" do
@s.check(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
context "when #check was called with a String pattern" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil when matching succeeded" do
@s.check("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "raises IndexError when matching succeeded" do
@s.check("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
it "returns nil when matching failed" do
@s.check("2008")
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
it "returns a matching substring when given Integer index" do
@@ -68,7 +66,6 @@ describe "StringScanner#check" do
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -77,10 +74,9 @@ describe "StringScanner#check" do
@s.check("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -89,7 +85,7 @@ describe "StringScanner#check" do
@s.check("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/check_until_spec.rb b/spec/ruby/library/stringscanner/check_until_spec.rb
index 701a703ebe..b4ef35d9f7 100644
--- a/spec/ruby/library/stringscanner/check_until_spec.rb
+++ b/spec/ruby/library/stringscanner/check_until_spec.rb
@@ -24,7 +24,7 @@ describe "StringScanner#check_until" do
it "raises TypeError if given a String" do
-> {
@s.check_until('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
+ }.should.raise(TypeError, 'wrong argument type String (expected Regexp)')
end
end
@@ -35,7 +35,6 @@ describe "StringScanner#check_until" do
end
# https://github.com/ruby/strscan/issues/131
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.1"
it "sets the last match result if given a String" do
@s.check_until("a")
@@ -45,7 +44,6 @@ describe "StringScanner#check_until" do
@s.post_match.should == " test"
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "sets the last match result if given a String" do
@@ -69,34 +67,32 @@ describe "StringScanner#check_until" do
it "returns nil when matching failed" do
@s.check_until(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
context "when #check_until was called with a String pattern" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil when matching succeeded" do
@s.check_until("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError when matching succeeded" do
@s.check_until("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
it "returns nil when matching failed" do
@s.check_until("2008")
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
it "returns a matching substring when given Integer index" do
@@ -105,7 +101,6 @@ describe "StringScanner#check_until" do
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -114,10 +109,9 @@ describe "StringScanner#check_until" do
@s.check_until("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -126,7 +120,7 @@ describe "StringScanner#check_until" do
@s.check_until("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/clear_spec.rb b/spec/ruby/library/stringscanner/clear_spec.rb
deleted file mode 100644
index 7ae089704a..0000000000
--- a/spec/ruby/library/stringscanner/clear_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/terminate'
-require 'strscan'
-
-describe "StringScanner#clear" do
- it_behaves_like :strscan_terminate, :clear
-
- it "warns in verbose mode that the method is obsolete" do
- s = StringScanner.new("abc")
- -> {
- s.clear
- }.should complain(/clear.*obsolete.*terminate/, verbose: true)
-
- -> {
- s.clear
- }.should_not complain(verbose: false)
- end
-end
diff --git a/spec/ruby/library/stringscanner/dup_spec.rb b/spec/ruby/library/stringscanner/dup_spec.rb
index 0fc52a1477..0118964526 100644
--- a/spec/ruby/library/stringscanner/dup_spec.rb
+++ b/spec/ruby/library/stringscanner/dup_spec.rb
@@ -15,7 +15,7 @@ describe "StringScanner#dup" do
it "copies the passed StringScanner's position to self" do
@orig_s.pos = 5
s = @orig_s.dup
- s.pos.should eql(5)
+ s.pos.should.eql?(5)
end
it "copies previous match state" do
@@ -34,6 +34,6 @@ describe "StringScanner#dup" do
it "copies the passed StringScanner scan pointer to self" do
@orig_s.terminate
s = @orig_s.dup
- s.eos?.should be_true
+ s.eos?.should == true
end
end
diff --git a/spec/ruby/library/stringscanner/element_reference_spec.rb b/spec/ruby/library/stringscanner/element_reference_spec.rb
index 91b6d86dc7..bcd48ede61 100644
--- a/spec/ruby/library/stringscanner/element_reference_spec.rb
+++ b/spec/ruby/library/stringscanner/element_reference_spec.rb
@@ -7,8 +7,8 @@ describe "StringScanner#[]" do
end
it "returns nil if there is no current match" do
- @s[0].should be_nil
- @s[:wday].should be_nil
+ @s[0].should == nil
+ @s[:wday].should == nil
end
it "returns the n-th subgroup in the most recent match" do
@@ -35,24 +35,24 @@ describe "StringScanner#[]" do
it "raises a TypeError if the given index is nil" do
@s.scan(/(\w+) (\w+) (\d+) /)
- -> { @s[nil]}.should raise_error(TypeError)
+ -> { @s[nil]}.should.raise(TypeError)
end
it "raises a TypeError when a Range is as argument" do
@s.scan(/(\w+) (\w+) (\d+) /)
- -> { @s[0..2]}.should raise_error(TypeError)
+ -> { @s[0..2]}.should.raise(TypeError)
end
it "raises a IndexError when there's no any named capture group in the regexp" do
@s.scan(/(\w+) (\w+) (\d+) /)
- -> { @s["wday"]}.should raise_error(IndexError)
- -> { @s[:wday]}.should raise_error(IndexError)
+ -> { @s["wday"]}.should.raise(IndexError)
+ -> { @s[:wday]}.should.raise(IndexError)
end
it "raises a IndexError when given a not existing capture group name" do
@s.scan(/(?<a>\w+) (?<b>\w+) (?<c>\d+) /)
- -> { @s["wday"]}.should raise_error(IndexError)
- -> { @s[:wday]}.should raise_error(IndexError)
+ -> { @s["wday"]}.should.raise(IndexError)
+ -> { @s[:wday]}.should.raise(IndexError)
end
it "returns named capture" do
diff --git a/spec/ruby/library/stringscanner/empty_spec.rb b/spec/ruby/library/stringscanner/empty_spec.rb
deleted file mode 100644
index d9449bea6e..0000000000
--- a/spec/ruby/library/stringscanner/empty_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/eos'
-require 'strscan'
-
-describe "StringScanner#empty?" do
- it_behaves_like :strscan_eos, :empty?
-
- it "warns in verbose mode that the method is obsolete" do
- s = StringScanner.new("abc")
- -> {
- s.empty?
- }.should complain(/empty?.*obsolete.*eos?/, verbose: true)
-
- -> {
- s.empty?
- }.should_not complain(verbose: false)
- end
-end
diff --git a/spec/ruby/library/stringscanner/eos_spec.rb b/spec/ruby/library/stringscanner/eos_spec.rb
index b58ee1e473..03c2804e5b 100644
--- a/spec/ruby/library/stringscanner/eos_spec.rb
+++ b/spec/ruby/library/stringscanner/eos_spec.rb
@@ -1,7 +1,20 @@
require_relative '../../spec_helper'
-require_relative 'shared/eos'
require 'strscan'
describe "StringScanner#eos?" do
- it_behaves_like :strscan_eos, :eos?
+ before :each do
+ @s = StringScanner.new("This is a test")
+ end
+
+ it "returns true if the scan pointer is at the end of the string" do
+ @s.terminate
+ @s.should.eos?
+
+ s = StringScanner.new('')
+ s.should.eos?
+ end
+
+ it "returns false if the scan pointer is not at the end of the string" do
+ @s.should_not.eos?
+ end
end
diff --git a/spec/ruby/library/stringscanner/exist_spec.rb b/spec/ruby/library/stringscanner/exist_spec.rb
index 3f40c7a5a5..2207622366 100644
--- a/spec/ruby/library/stringscanner/exist_spec.rb
+++ b/spec/ruby/library/stringscanner/exist_spec.rb
@@ -32,7 +32,7 @@ describe "StringScanner#exist?" do
it "raises TypeError if given a String" do
-> {
@s.exist?('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
+ }.should.raise(TypeError, 'wrong argument type String (expected Regexp)')
end
end
@@ -57,34 +57,32 @@ describe "StringScanner#exist?" do
it "returns nil when matching failed" do
@s.exist?(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
context "when #exist? was called with a String pattern" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil when matching succeeded" do
@s.exist?("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError when matching succeeded" do
@s.exist?("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
it "returns nil when matching failed" do
@s.exist?("2008")
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
it "returns a matching substring when given Integer index" do
@@ -93,7 +91,6 @@ describe "StringScanner#exist?" do
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -102,10 +99,9 @@ describe "StringScanner#exist?" do
@s.exist?("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -114,7 +110,7 @@ describe "StringScanner#exist?" do
@s.exist?("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/get_byte_spec.rb b/spec/ruby/library/stringscanner/get_byte_spec.rb
index 29e2f557de..b989b73883 100644
--- a/spec/ruby/library/stringscanner/get_byte_spec.rb
+++ b/spec/ruby/library/stringscanner/get_byte_spec.rb
@@ -1,7 +1,84 @@
+# encoding: binary
require_relative '../../spec_helper'
-require_relative 'shared/get_byte'
require 'strscan'
describe "StringScanner#get_byte" do
- it_behaves_like :strscan_get_byte, :get_byte
+ it "scans one byte and returns it" do
+ s = StringScanner.new('abc5.')
+ s.get_byte.should == 'a'
+ s.get_byte.should == 'b'
+ s.get_byte.should == 'c'
+ s.get_byte.should == '5'
+ s.get_byte.should == '.'
+ end
+
+ it "is not multi-byte character sensitive" do
+ s = StringScanner.new("\244\242")
+ s.get_byte.should == "\244"
+ s.get_byte.should == "\242"
+ end
+
+ it "returns nil at the end of the string" do
+ # empty string case
+ s = StringScanner.new('')
+ s.get_byte.should == nil
+ s.get_byte.should == nil
+
+ # non-empty string case
+ s = StringScanner.new('a')
+ s.get_byte # skip one
+ s.get_byte.should == nil
+ end
+
+ describe "#[] successive call with a capture group name" do
+ # https://github.com/ruby/strscan/issues/139
+ version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
+ it "returns nil" do
+ s = StringScanner.new("This is a test")
+ s.get_byte
+ s.should.matched?
+ s[:a].should == nil
+ end
+ end
+ version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
+ it "raises IndexError" do
+ s = StringScanner.new("This is a test")
+ s.get_byte
+ s.should.matched?
+ -> { s[:a] }.should.raise(IndexError)
+ end
+ end
+
+ it "returns a matching character when given Integer index" do
+ s = StringScanner.new("This is a test")
+ s.get_byte
+ s[0].should == "T"
+ end
+
+ # https://github.com/ruby/strscan/issues/135
+ version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
+ it "ignores the previous matching with Regexp" do
+ s = StringScanner.new("This is a test")
+ s.exist?(/(?<a>This)/)
+ s.should.matched?
+ s[:a].should == "This"
+
+ s.get_byte
+ s.should.matched?
+ s[:a].should == nil
+ end
+ end
+ version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
+ it "ignores the previous matching with Regexp" do
+ s = StringScanner.new("This is a test")
+ s.exist?(/(?<a>This)/)
+ s.should.matched?
+ s[:a].should == "This"
+
+ s.get_byte
+ s.should.matched?
+ -> { s[:a] }.should.raise(IndexError)
+ end
+ end
+ end
end
diff --git a/spec/ruby/library/stringscanner/getbyte_spec.rb b/spec/ruby/library/stringscanner/getbyte_spec.rb
deleted file mode 100644
index e0659a5829..0000000000
--- a/spec/ruby/library/stringscanner/getbyte_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/get_byte'
-require_relative 'shared/extract_range'
-require 'strscan'
-
-describe "StringScanner#getbyte" do
- it_behaves_like :strscan_get_byte, :getbyte
-
- it "warns in verbose mode that the method is obsolete" do
- s = StringScanner.new("abc")
- -> {
- s.getbyte
- }.should complain(/getbyte.*obsolete.*get_byte/, verbose: true)
-
- -> {
- s.getbyte
- }.should_not complain(verbose: false)
- end
-
- it_behaves_like :extract_range, :getbyte
-end
diff --git a/spec/ruby/library/stringscanner/getch_spec.rb b/spec/ruby/library/stringscanner/getch_spec.rb
index ac43cf449d..cd41b4336a 100644
--- a/spec/ruby/library/stringscanner/getch_spec.rb
+++ b/spec/ruby/library/stringscanner/getch_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/extract_range'
require 'strscan'
@@ -11,6 +11,13 @@ describe "StringScanner#getch" do
s.getch.should == "c"
end
+ it "scans newlines too" do
+ s = StringScanner.new("a\nc")
+ s.getch.should == "a"
+ s.getch.should == "\n"
+ s.getch.should == "c"
+ end
+
it "is multi-byte character sensitive" do
# Japanese hiragana "A" in EUC-JP
src = "\244\242".dup.force_encoding("euc-jp")
@@ -33,22 +40,20 @@ describe "StringScanner#getch" do
describe "#[] successive call with a capture group name" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil" do
s = StringScanner.new("This is a test")
s.getch
s.should.matched?
- s[:a].should be_nil
+ s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError" do
s = StringScanner.new("This is a test")
s.getch
s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
+ -> { s[:a] }.should.raise(IndexError)
end
end
@@ -59,7 +64,6 @@ describe "StringScanner#getch" do
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
s = StringScanner.new("This is a test")
@@ -70,10 +74,9 @@ describe "StringScanner#getch" do
s.getch
s.should.matched?
- s[:a].should be_nil
+ s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
s = StringScanner.new("This is a test")
@@ -84,7 +87,7 @@ describe "StringScanner#getch" do
s.getch
s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
+ -> { s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/initialize_spec.rb b/spec/ruby/library/stringscanner/initialize_spec.rb
index 77f6084c1b..fdab4d381c 100644
--- a/spec/ruby/library/stringscanner/initialize_spec.rb
+++ b/spec/ruby/library/stringscanner/initialize_spec.rb
@@ -7,12 +7,12 @@ describe "StringScanner#initialize" do
end
it "is a private method" do
- StringScanner.should have_private_instance_method(:initialize)
+ StringScanner.private_instance_methods(false).should.include?(:initialize)
end
it "returns an instance of StringScanner" do
- @s.should be_kind_of(StringScanner)
- @s.eos?.should be_false
+ @s.should.is_a?(StringScanner)
+ @s.eos?.should == false
end
it "converts the argument into a string using #to_str" do
diff --git a/spec/ruby/library/stringscanner/inspect_spec.rb b/spec/ruby/library/stringscanner/inspect_spec.rb
index ff6b97eb91..570d0b7b10 100644
--- a/spec/ruby/library/stringscanner/inspect_spec.rb
+++ b/spec/ruby/library/stringscanner/inspect_spec.rb
@@ -7,7 +7,7 @@ describe "StringScanner#inspect" do
end
it "returns a String object" do
- @s.inspect.should be_kind_of(String)
+ @s.inspect.should.is_a?(String)
end
it "returns a string that represents the StringScanner object" do
diff --git a/spec/ruby/library/stringscanner/match_spec.rb b/spec/ruby/library/stringscanner/match_spec.rb
index a27bb51d72..c2bc49324b 100644
--- a/spec/ruby/library/stringscanner/match_spec.rb
+++ b/spec/ruby/library/stringscanner/match_spec.rb
@@ -45,7 +45,7 @@ describe "StringScanner#match?" do
it "returns nil when matching failed" do
@s.match?(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
end
diff --git a/spec/ruby/library/stringscanner/matched_spec.rb b/spec/ruby/library/stringscanner/matched_spec.rb
index c020bd3eae..95b57574c5 100644
--- a/spec/ruby/library/stringscanner/matched_spec.rb
+++ b/spec/ruby/library/stringscanner/matched_spec.rb
@@ -31,11 +31,11 @@ describe "StringScanner#matched?" do
it "returns true if the last match was successful" do
@s.match?(/\w+/)
- @s.matched?.should be_true
+ @s.matched?.should == true
end
it "returns false if there's no match" do
@s.match?(/\d+/)
- @s.matched?.should be_false
+ @s.matched?.should == false
end
end
diff --git a/spec/ruby/library/stringscanner/named_captures_spec.rb b/spec/ruby/library/stringscanner/named_captures_spec.rb
index f35051b8cb..927784a6c4 100644
--- a/spec/ruby/library/stringscanner/named_captures_spec.rb
+++ b/spec/ruby/library/stringscanner/named_captures_spec.rb
@@ -1,32 +1,28 @@
require_relative '../../spec_helper'
require 'strscan'
-version_is StringScanner::Version, "3.0.5" do # ruby_version_is "3.2"
- describe "StringScanner#named_captures" do
- before do
- @s = StringScanner.new('Fri Dec 12 1975 14:39')
- end
+describe "StringScanner#named_captures" do
+ before do
+ @s = StringScanner.new('Fri Dec 12 1975 14:39')
+ end
- it "returns a hash of names and matched substrings for named capturing groups in a regular expression of the most recent matching" do
- @s.exist?(/(?<wday>\w+) (?<month>\w+) (?<day>\d+)/)
- @s.named_captures.should == {"wday" => "Fri", "month" => "Dec", "day" => "12"}
- end
+ it "returns a hash of names and matched substrings for named capturing groups in a regular expression of the most recent matching" do
+ @s.exist?(/(?<wday>\w+) (?<month>\w+) (?<day>\d+)/)
+ @s.named_captures.should == {"wday" => "Fri", "month" => "Dec", "day" => "12"}
+ end
- it "returns {} if there are no named capturing groups" do
- @s.exist?(/(\w+) (\w+) (\d+)/)
- @s.named_captures.should == {}
- end
+ it "returns {} if there are no named capturing groups" do
+ @s.exist?(/(\w+) (\w+) (\d+)/)
+ @s.named_captures.should == {}
+ end
- # https://github.com/ruby/strscan/issues/132
- ruby_bug "", "3.2"..."3.3" do # fixed in strscan v3.0.7
- it "returns {} if there is no any matching done" do
- @s.named_captures.should == {}
- end
- end
+ # https://github.com/ruby/strscan/issues/132 fixed in strscan v3.0.7
+ it "returns {} if there is no any matching done" do
+ @s.named_captures.should == {}
+ end
- it "returns nil for an optional named capturing group if it doesn't match" do
- @s.exist?(/(?<wday>\w+) (?<month>\w+) (?<day>\s+)?/)
- @s.named_captures.should == {"wday" => "Fri", "month" => "Dec", "day" => nil}
- end
+ it "returns nil for an optional named capturing group if it doesn't match" do
+ @s.exist?(/(?<wday>\w+) (?<month>\w+) (?<day>\s+)?/)
+ @s.named_captures.should == {"wday" => "Fri", "month" => "Dec", "day" => nil}
end
end
diff --git a/spec/ruby/library/stringscanner/peek_spec.rb b/spec/ruby/library/stringscanner/peek_spec.rb
index cbb5630ff9..5b54c6be0b 100644
--- a/spec/ruby/library/stringscanner/peek_spec.rb
+++ b/spec/ruby/library/stringscanner/peek_spec.rb
@@ -1,7 +1,42 @@
require_relative '../../spec_helper'
-require_relative 'shared/peek'
require 'strscan'
describe "StringScanner#peek" do
- it_behaves_like :strscan_peek, :peek
+ before :each do
+ @s = StringScanner.new('This is a test')
+ end
+
+ it "returns at most the specified number of bytes from the current position" do
+ @s.peek(4).should == "This"
+ @s.pos.should == 0
+ @s.pos = 5
+ @s.peek(2).should == "is"
+ @s.peek(1000).should == "is a test"
+
+ s = StringScanner.new("été")
+ s.peek(2).should == "é"
+ end
+
+ it "returns an empty string when the passed argument is zero" do
+ @s.peek(0).should == ""
+ end
+
+ it "raises a ArgumentError when the passed argument is negative" do
+ -> { @s.peek(-2) }.should.raise(ArgumentError)
+ end
+
+ it "raises a RangeError when the passed argument is a Bignum" do
+ -> { @s.peek(bignum_value) }.should.raise(RangeError)
+ end
+
+ it "returns an instance of String when passed a String subclass" do
+ cls = Class.new(String)
+ sub = cls.new("abc")
+
+ s = StringScanner.new(sub)
+
+ ch = s.peek(1)
+ ch.should_not.is_a?(cls)
+ ch.should.instance_of?(String)
+ end
end
diff --git a/spec/ruby/library/stringscanner/peep_spec.rb b/spec/ruby/library/stringscanner/peep_spec.rb
deleted file mode 100644
index bf6d579325..0000000000
--- a/spec/ruby/library/stringscanner/peep_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/peek'
-require 'strscan'
-
-describe "StringScanner#peep" do
- it_behaves_like :strscan_peek, :peep
-
- it "warns in verbose mode that the method is obsolete" do
- s = StringScanner.new("abc")
- -> {
- s.peep(1)
- }.should complain(/peep.*obsolete.*peek/, verbose: true)
-
- -> {
- s.peep(1)
- }.should_not complain(verbose: false)
- end
-end
diff --git a/spec/ruby/library/stringscanner/rest_size_spec.rb b/spec/ruby/library/stringscanner/rest_size_spec.rb
index e62e3a8f8c..65d3b50e08 100644
--- a/spec/ruby/library/stringscanner/rest_size_spec.rb
+++ b/spec/ruby/library/stringscanner/rest_size_spec.rb
@@ -1,7 +1,30 @@
require_relative '../../spec_helper'
-require_relative 'shared/rest_size'
require 'strscan'
describe "StringScanner#rest_size" do
- it_behaves_like :strscan_rest_size, :rest_size
+ before :each do
+ @s = StringScanner.new('This is a test')
+ end
+
+ it "returns the length of the rest of the string" do
+ @s.rest_size.should == 14
+ @s.scan(/This/)
+ @s.rest_size.should == 10
+ @s.terminate
+ @s.rest_size.should == 0
+ end
+
+ it "is equivalent to rest.bytesize" do
+ @s.scan(/This/)
+ @s.rest_size.should == @s.rest.bytesize
+
+ s = StringScanner.new('été')
+ s.rest_size.should == 5
+ s.scan(/./)
+ s.rest_size.should == 3
+ s.scan(/./)
+ s.rest_size.should == 2
+ s.scan(/./)
+ s.rest_size.should == 0
+ end
end
diff --git a/spec/ruby/library/stringscanner/rest_spec.rb b/spec/ruby/library/stringscanner/rest_spec.rb
index 67072f880d..40f073058c 100644
--- a/spec/ruby/library/stringscanner/rest_spec.rb
+++ b/spec/ruby/library/stringscanner/rest_spec.rb
@@ -32,14 +32,14 @@ describe "StringScanner#rest?" do
end
it "returns true if there is more data in the string" do
- @s.rest?.should be_true
+ @s.rest?.should == true
@s.scan(/This/)
- @s.rest?.should be_true
+ @s.rest?.should == true
end
it "returns false if there is no more data in the string" do
@s.terminate
- @s.rest?.should be_false
+ @s.rest?.should == false
end
it "is the opposite of eos?" do
diff --git a/spec/ruby/library/stringscanner/restsize_spec.rb b/spec/ruby/library/stringscanner/restsize_spec.rb
deleted file mode 100644
index 710520afae..0000000000
--- a/spec/ruby/library/stringscanner/restsize_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/rest_size'
-require 'strscan'
-
-describe "StringScanner#restsize" do
- it_behaves_like :strscan_rest_size, :restsize
-
- it "warns in verbose mode that the method is obsolete" do
- s = StringScanner.new("abc")
- -> {
- s.restsize
- }.should complain(/restsize.*obsolete.*rest_size/, verbose: true)
-
- -> {
- s.restsize
- }.should_not complain(verbose: false)
- end
-end
diff --git a/spec/ruby/library/stringscanner/scan_byte_spec.rb b/spec/ruby/library/stringscanner/scan_byte_spec.rb
index c60e22be4f..8fd77270e4 100644
--- a/spec/ruby/library/stringscanner/scan_byte_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_byte_spec.rb
@@ -43,22 +43,20 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
describe "#[] successive call with a capture group name" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil" do
s = StringScanner.new("abc")
s.scan_byte
s.should.matched?
- s[:a].should be_nil
+ s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError" do
s = StringScanner.new("abc")
s.scan_byte
s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
+ -> { s[:a] }.should.raise(IndexError)
end
end
@@ -69,7 +67,6 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
s = StringScanner.new("abc")
@@ -83,7 +80,6 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
s = StringScanner.new("abc")
@@ -94,7 +90,7 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
s.scan_byte
s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
+ -> { s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/scan_full_spec.rb b/spec/ruby/library/stringscanner/scan_full_spec.rb
index 967313f5ca..7633c17860 100644
--- a/spec/ruby/library/stringscanner/scan_full_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_full_spec.rb
@@ -38,7 +38,7 @@ describe "StringScanner#scan_full" do
it "returns nil when matching failed" do
@s.scan_full(/(?<a>2008)/, false, false)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
end
diff --git a/spec/ruby/library/stringscanner/scan_integer_spec.rb b/spec/ruby/library/stringscanner/scan_integer_spec.rb
index a0b3685bae..d83149344a 100644
--- a/spec/ruby/library/stringscanner/scan_integer_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_integer_spec.rb
@@ -25,7 +25,7 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
end
# https://github.com/ruby/strscan/issues/130
- ruby_bug "", "3.4"..."3.5" do # introduced in strscan v3.1.1
+ ruby_bug "", "3.4"..."4.0" do # introduced in strscan v3.1.1
it "sets the last match result" do
s = StringScanner.new("42abc")
s.scan_integer
@@ -44,7 +44,7 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
-> {
s.scan_integer
- }.should raise_error(Encoding::CompatibilityError, 'ASCII incompatible encoding: UTF-16BE')
+ }.should.raise(Encoding::CompatibilityError, /ASCII incompatible encoding: UTF-16BE|incompatible encoding regexp match/)
end
context "given base" do
@@ -65,10 +65,9 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
it "raises ArgumentError when passed not supported base" do
-> {
StringScanner.new("42").scan_integer(base: 5)
- }.should raise_error(ArgumentError, "Unsupported integer base: 5, expected 10 or 16")
+ }.should.raise(ArgumentError, "Unsupported integer base: 5, expected 10 or 16")
end
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "does not match '0x' prefix on its own" do
StringScanner.new("0x").scan_integer(base: 16).should == nil
@@ -76,7 +75,6 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
StringScanner.new("+0x").scan_integer(base: 16).should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "matches '0' in a '0x' that is followed by non-hex characters" do
@@ -96,7 +94,6 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
describe "#[] successive call with a capture group name" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil substring when matching succeeded" do
s = StringScanner.new("42")
@@ -105,13 +102,12 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError when matching succeeded" do
s = StringScanner.new("42")
s.scan_integer
s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
+ -> { s[:a] }.should.raise(IndexError)
end
end
@@ -119,7 +115,7 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
s = StringScanner.new("a42")
s.scan_integer
s.should_not.matched?
- s[:a].should be_nil
+ s[:a].should == nil
end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
@@ -131,7 +127,6 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "does not ignore the previous matching with Regexp" do
s = StringScanner.new("42")
@@ -145,7 +140,6 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
s[:a].should == "42"
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "ignores the previous matching with Regexp" do
s = StringScanner.new("42")
@@ -156,7 +150,7 @@ version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
s.scan_integer
s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
+ -> { s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/scan_spec.rb b/spec/ruby/library/stringscanner/scan_spec.rb
index 088c3419fb..ee8a9eb103 100644
--- a/spec/ruby/library/stringscanner/scan_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_spec.rb
@@ -15,7 +15,7 @@ describe "StringScanner#scan" do
it "treats ^ as matching from the beginning of the current position" do
@s.scan(/\w+/).should == "This"
- @s.scan(/^\d/).should be_nil
+ @s.scan(/^\d/).should == nil
@s.scan(/^\s/).should == " "
end
@@ -26,7 +26,7 @@ describe "StringScanner#scan" do
it "treats \\A as matching from the beginning of the current position" do
@s.scan(/\w+/).should == "This"
- @s.scan(/\A\d/).should be_nil
+ @s.scan(/\A\d/).should == nil
@s.scan(/\A\s/).should == " "
end
@@ -41,24 +41,24 @@ describe "StringScanner#scan" do
it "returns nil when there is no more to scan" do
@s.scan(/[\w\s]+/).should == "This is a test"
- @s.scan(/\w+/).should be_nil
+ @s.scan(/\w+/).should == nil
end
it "returns an empty string when the pattern matches empty" do
@s.scan(/.*/).should == "This is a test"
@s.scan(/.*/).should == ""
- @s.scan(/./).should be_nil
+ @s.scan(/./).should == nil
end
it "treats String as the pattern itself" do
- @s.scan("this").should be_nil
+ @s.scan("this").should == nil
@s.scan("This").should == "This"
end
it "raises a TypeError if pattern isn't a Regexp nor String" do
- -> { @s.scan(5) }.should raise_error(TypeError)
- -> { @s.scan(:test) }.should raise_error(TypeError)
- -> { @s.scan(mock('x')) }.should raise_error(TypeError)
+ -> { @s.scan(5) }.should.raise(TypeError)
+ -> { @s.scan(:test) }.should.raise(TypeError)
+ -> { @s.scan(mock('x')) }.should.raise(TypeError)
end
describe "#[] successive call with a capture group name" do
@@ -71,7 +71,7 @@ describe "StringScanner#scan" do
it "returns nil when matching failed" do
@s.scan(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
end
@@ -91,11 +91,11 @@ describe "StringScanner#scan with fixed_anchor: true" do
it "treats ^ as matching from the beginning of line" do
@s.scan(/\w+\n/).should == "This\n"
@s.scan(/^\w/).should == "i"
- @s.scan(/^\w/).should be_nil
+ @s.scan(/^\w/).should == nil
end
it "treats \\A as matching from the beginning of string" do
@s.scan(/\A\w/).should == "T"
- @s.scan(/\A\w/).should be_nil
+ @s.scan(/\A\w/).should == nil
end
end
diff --git a/spec/ruby/library/stringscanner/scan_until_spec.rb b/spec/ruby/library/stringscanner/scan_until_spec.rb
index 737d83a14c..df83f3916a 100644
--- a/spec/ruby/library/stringscanner/scan_until_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_until_spec.rb
@@ -31,7 +31,7 @@ describe "StringScanner#scan_until" do
it "raises TypeError if given a String" do
-> {
@s.scan_until('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
+ }.should.raise(TypeError, 'wrong argument type String (expected Regexp)')
end
end
@@ -41,7 +41,6 @@ describe "StringScanner#scan_until" do
end
# https://github.com/ruby/strscan/issues/131
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.1"
it "sets the last match result if given a String" do
@s.scan_until("a")
@@ -51,7 +50,6 @@ describe "StringScanner#scan_until" do
@s.post_match.should == " test"
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "sets the last match result if given a String" do
@@ -75,34 +73,32 @@ describe "StringScanner#scan_until" do
it "returns nil when matching failed" do
@s.scan_until(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
context "when #scan_until was called with a String pattern" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil when matching succeeded" do
@s.scan_until("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError when matching succeeded" do
@s.scan_until("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
it "returns nil when matching failed" do
@s.scan_until("2008")
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
it "returns a matching substring when given Integer index" do
@@ -111,7 +107,6 @@ describe "StringScanner#scan_until" do
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -120,10 +115,9 @@ describe "StringScanner#scan_until" do
@s.scan_until("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -132,7 +126,7 @@ describe "StringScanner#scan_until" do
@s.scan_until("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/search_full_spec.rb b/spec/ruby/library/stringscanner/search_full_spec.rb
index a089da2043..656884f46b 100644
--- a/spec/ruby/library/stringscanner/search_full_spec.rb
+++ b/spec/ruby/library/stringscanner/search_full_spec.rb
@@ -40,7 +40,7 @@ describe "StringScanner#search_full" do
it "raises TypeError if given a String" do
-> {
@s.search_full('T', true, true)
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
+ }.should.raise(TypeError, 'wrong argument type String (expected Regexp)')
end
end
@@ -50,7 +50,6 @@ describe "StringScanner#search_full" do
end
# https://github.com/ruby/strscan/issues/131
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.1"
it "sets the last match result if given a String" do
@s.search_full("is a", false, false)
@@ -60,7 +59,6 @@ describe "StringScanner#search_full" do
@s.post_match.should == " test"
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "sets the last match result if given a String" do
@@ -84,34 +82,32 @@ describe "StringScanner#search_full" do
it "returns nil when matching failed" do
@s.search_full(/(?<a>2008)/, false, false)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
context "when #search_full was called with a String pattern" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil when matching succeeded" do
@s.search_full("This", false, false)
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError when matching succeeded" do
@s.search_full("This", false, false)
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
it "returns nil when matching failed" do
@s.search_full("2008", false, false)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
it "returns a matching substring when given Integer index" do
@@ -128,7 +124,7 @@ describe "StringScanner#search_full" do
@s.search_full("This", false, false)
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/shared/bol.rb b/spec/ruby/library/stringscanner/shared/bol.rb
index ebcdd7938f..ec5c2051b5 100644
--- a/spec/ruby/library/stringscanner/shared/bol.rb
+++ b/spec/ruby/library/stringscanner/shared/bol.rb
@@ -1,25 +1,25 @@
describe :strscan_bol, shared: true do
it "returns true if the scan pointer is at the beginning of the line, false otherwise" do
s = StringScanner.new("This is a test")
- s.send(@method).should be_true
+ s.send(@method).should == true
s.scan(/This/)
- s.send(@method).should be_false
+ s.send(@method).should == false
s.terminate
- s.send(@method).should be_false
+ s.send(@method).should == false
s = StringScanner.new("hello\nworld")
- s.bol?.should be_true
+ s.bol?.should == true
s.scan(/\w+/)
- s.bol?.should be_false
+ s.bol?.should == false
s.scan(/\n/)
- s.bol?.should be_true
+ s.bol?.should == true
s.unscan
- s.bol?.should be_false
+ s.bol?.should == false
end
it "returns true if the scan pointer is at the end of the line of an empty string." do
s = StringScanner.new('')
s.terminate
- s.send(@method).should be_true
+ s.send(@method).should == true
end
end
diff --git a/spec/ruby/library/stringscanner/shared/concat.rb b/spec/ruby/library/stringscanner/shared/concat.rb
index 1dbae11f7c..8138b0f8dc 100644
--- a/spec/ruby/library/stringscanner/shared/concat.rb
+++ b/spec/ruby/library/stringscanner/shared/concat.rb
@@ -3,28 +3,28 @@ describe :strscan_concat, shared: true do
s = StringScanner.new(+"hello ")
s.send(@method, 'world').should == s
s.string.should == "hello world"
- s.eos?.should be_false
+ s.eos?.should == false
end
it "raises a TypeError if the given argument can't be converted to a String" do
- -> { StringScanner.new('hello').send(@method, :world) }.should raise_error(TypeError)
- -> { StringScanner.new('hello').send(@method, mock('x')) }.should raise_error(TypeError)
+ -> { StringScanner.new('hello').send(@method, :world) }.should.raise(TypeError)
+ -> { StringScanner.new('hello').send(@method, mock('x')) }.should.raise(TypeError)
end
end
describe :strscan_concat_fixnum, shared: true do
it "raises a TypeError" do
a = StringScanner.new("hello world")
- -> { a.send(@method, 333) }.should raise_error(TypeError)
+ -> { a.send(@method, 333) }.should.raise(TypeError)
b = StringScanner.new("")
- -> { b.send(@method, (256 * 3 + 64)) }.should raise_error(TypeError)
- -> { b.send(@method, -200) }.should raise_error(TypeError)
+ -> { b.send(@method, (256 * 3 + 64)) }.should.raise(TypeError)
+ -> { b.send(@method, -200) }.should.raise(TypeError)
end
it "doesn't call to_int on the argument" do
x = mock('x')
x.should_not_receive(:to_int)
- -> { StringScanner.new("").send(@method, x) }.should raise_error(TypeError)
+ -> { StringScanner.new("").send(@method, x) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/stringscanner/shared/eos.rb b/spec/ruby/library/stringscanner/shared/eos.rb
deleted file mode 100644
index ea04c764a2..0000000000
--- a/spec/ruby/library/stringscanner/shared/eos.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-describe :strscan_eos, shared: true do
- before :each do
- @s = StringScanner.new("This is a test")
- end
-
- it "returns true if the scan pointer is at the end of the string" do
- @s.terminate
- @s.send(@method).should be_true
-
- s = StringScanner.new('')
- s.send(@method).should be_true
- end
-
- it "returns false if the scan pointer is not at the end of the string" do
- @s.send(@method).should be_false
- end
-end
diff --git a/spec/ruby/library/stringscanner/shared/extract_range.rb b/spec/ruby/library/stringscanner/shared/extract_range.rb
index e7404fd0cb..c64cc41fa7 100644
--- a/spec/ruby/library/stringscanner/shared/extract_range.rb
+++ b/spec/ruby/library/stringscanner/shared/extract_range.rb
@@ -5,7 +5,7 @@ describe :extract_range, shared: true do
s = StringScanner.new(sub)
ch = s.send(@method)
- ch.should_not be_kind_of(cls)
- ch.should be_an_instance_of(String)
+ ch.should_not.is_a?(cls)
+ ch.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/stringscanner/shared/extract_range_matched.rb b/spec/ruby/library/stringscanner/shared/extract_range_matched.rb
index 070a132812..8a6349bec1 100644
--- a/spec/ruby/library/stringscanner/shared/extract_range_matched.rb
+++ b/spec/ruby/library/stringscanner/shared/extract_range_matched.rb
@@ -7,7 +7,7 @@ describe :extract_range_matched, shared: true do
s.scan(/\w{1}/)
ch = s.send(@method)
- ch.should_not be_kind_of(cls)
- ch.should be_an_instance_of(String)
+ ch.should_not.is_a?(cls)
+ ch.should.instance_of?(String)
end
end
diff --git a/spec/ruby/library/stringscanner/shared/get_byte.rb b/spec/ruby/library/stringscanner/shared/get_byte.rb
deleted file mode 100644
index f1b016905f..0000000000
--- a/spec/ruby/library/stringscanner/shared/get_byte.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-# -*- encoding: binary -*-
-require 'strscan'
-
-describe :strscan_get_byte, shared: true do
- it "scans one byte and returns it" do
- s = StringScanner.new('abc5.')
- s.send(@method).should == 'a'
- s.send(@method).should == 'b'
- s.send(@method).should == 'c'
- s.send(@method).should == '5'
- s.send(@method).should == '.'
- end
-
- it "is not multi-byte character sensitive" do
- s = StringScanner.new("\244\242")
- s.send(@method).should == "\244"
- s.send(@method).should == "\242"
- end
-
- it "returns nil at the end of the string" do
- # empty string case
- s = StringScanner.new('')
- s.send(@method).should == nil
- s.send(@method).should == nil
-
- # non-empty string case
- s = StringScanner.new('a')
- s.send(@method) # skip one
- s.send(@method).should == nil
- end
-
- describe "#[] successive call with a capture group name" do
- # https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
- version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
- it "returns nil" do
- s = StringScanner.new("This is a test")
- s.send(@method)
- s.should.matched?
- s[:a].should be_nil
- end
- end
- end
- version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
- it "raises IndexError" do
- s = StringScanner.new("This is a test")
- s.send(@method)
- s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
- end
- end
-
- it "returns a matching character when given Integer index" do
- s = StringScanner.new("This is a test")
- s.send(@method)
- s[0].should == "T"
- end
-
- # https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
- version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
- it "ignores the previous matching with Regexp" do
- s = StringScanner.new("This is a test")
- s.exist?(/(?<a>This)/)
- s.should.matched?
- s[:a].should == "This"
-
- s.send(@method)
- s.should.matched?
- s[:a].should be_nil
- end
- end
- end
- version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
- it "ignores the previous matching with Regexp" do
- s = StringScanner.new("This is a test")
- s.exist?(/(?<a>This)/)
- s.should.matched?
- s[:a].should == "This"
-
- s.send(@method)
- s.should.matched?
- -> { s[:a] }.should raise_error(IndexError)
- end
- end
- end
-end
diff --git a/spec/ruby/library/stringscanner/shared/peek.rb b/spec/ruby/library/stringscanner/shared/peek.rb
deleted file mode 100644
index 4c757866c1..0000000000
--- a/spec/ruby/library/stringscanner/shared/peek.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-describe :strscan_peek, shared: true do
- before :each do
- @s = StringScanner.new('This is a test')
- end
-
- it "returns at most the specified number of bytes from the current position" do
- @s.send(@method, 4).should == "This"
- @s.pos.should == 0
- @s.pos = 5
- @s.send(@method, 2).should == "is"
- @s.send(@method, 1000).should == "is a test"
-
- s = StringScanner.new("été")
- s.send(@method, 2).should == "é"
- end
-
- it "returns an empty string when the passed argument is zero" do
- @s.send(@method, 0).should == ""
- end
-
- it "raises a ArgumentError when the passed argument is negative" do
- -> { @s.send(@method, -2) }.should raise_error(ArgumentError)
- end
-
- it "raises a RangeError when the passed argument is a Bignum" do
- -> { @s.send(@method, bignum_value) }.should raise_error(RangeError)
- end
-
- it "returns an instance of String when passed a String subclass" do
- cls = Class.new(String)
- sub = cls.new("abc")
-
- s = StringScanner.new(sub)
-
- ch = s.send(@method, 1)
- ch.should_not be_kind_of(cls)
- ch.should be_an_instance_of(String)
- end
-end
diff --git a/spec/ruby/library/stringscanner/shared/pos.rb b/spec/ruby/library/stringscanner/shared/pos.rb
index 6d540881f2..91f80fdf08 100644
--- a/spec/ruby/library/stringscanner/shared/pos.rb
+++ b/spec/ruby/library/stringscanner/shared/pos.rb
@@ -22,6 +22,13 @@ describe :strscan_pos, shared: true do
@s.terminate
@s.send(@method).should == @s.string.length
end
+
+ it "is not multi-byte character sensitive" do
+ s = StringScanner.new("abcädeföghi")
+
+ s.scan_until(/ö/)
+ s.pos.should == 10
+ end
end
describe :strscan_pos_set, shared: true do
@@ -43,10 +50,10 @@ describe :strscan_pos_set, shared: true do
it "raises a RangeError if position too far backward" do
-> {
@s.send(@method, -20)
- }.should raise_error(RangeError)
+ }.should.raise(RangeError)
end
it "raises a RangeError when the passed argument is out of range" do
- -> { @s.send(@method, 20) }.should raise_error(RangeError)
+ -> { @s.send(@method, 20) }.should.raise(RangeError)
end
end
diff --git a/spec/ruby/library/stringscanner/shared/rest_size.rb b/spec/ruby/library/stringscanner/shared/rest_size.rb
deleted file mode 100644
index 4c4f49e45c..0000000000
--- a/spec/ruby/library/stringscanner/shared/rest_size.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-describe :strscan_rest_size, shared: true do
- before :each do
- @s = StringScanner.new('This is a test')
- end
-
- it "returns the length of the rest of the string" do
- @s.send(@method).should == 14
- @s.scan(/This/)
- @s.send(@method).should == 10
- @s.terminate
- @s.send(@method).should == 0
- end
-
- it "is equivalent to rest.size" do
- @s.scan(/This/)
- @s.send(@method).should == @s.rest.size
- end
-end
diff --git a/spec/ruby/library/stringscanner/shared/terminate.rb b/spec/ruby/library/stringscanner/shared/terminate.rb
deleted file mode 100644
index bf41d097e2..0000000000
--- a/spec/ruby/library/stringscanner/shared/terminate.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-describe :strscan_terminate, shared: true do
- it "set the scan pointer to the end of the string and clear matching data." do
- s = StringScanner.new('This is a test')
- s.send(@method)
- s.bol?.should be_false
- s.eos?.should be_true
- end
-end
diff --git a/spec/ruby/library/stringscanner/skip_spec.rb b/spec/ruby/library/stringscanner/skip_spec.rb
index 12f5b7781c..2b955b3172 100644
--- a/spec/ruby/library/stringscanner/skip_spec.rb
+++ b/spec/ruby/library/stringscanner/skip_spec.rb
@@ -26,7 +26,7 @@ describe "StringScanner#skip" do
it "returns nil when matching failed" do
@s.skip(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
end
diff --git a/spec/ruby/library/stringscanner/skip_until_spec.rb b/spec/ruby/library/stringscanner/skip_until_spec.rb
index f5be4b5ceb..508db285ba 100644
--- a/spec/ruby/library/stringscanner/skip_until_spec.rb
+++ b/spec/ruby/library/stringscanner/skip_until_spec.rb
@@ -27,7 +27,7 @@ describe "StringScanner#skip_until" do
it "raises TypeError if given a String" do
-> {
@s.skip_until('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
+ }.should.raise(TypeError, 'wrong argument type String (expected Regexp)')
end
end
@@ -38,7 +38,6 @@ describe "StringScanner#skip_until" do
end
# https://github.com/ruby/strscan/issues/131
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.1"
it "sets the last match result if given a String" do
@s.skip_until("a")
@@ -48,7 +47,6 @@ describe "StringScanner#skip_until" do
@s.post_match.should == " test"
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "sets the last match result if given a String" do
@@ -72,34 +70,32 @@ describe "StringScanner#skip_until" do
it "returns nil when matching failed" do
@s.skip_until(/(?<a>2008)/)
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
version_is StringScanner::Version, "3.1.1" do # ruby_version_is "3.4"
context "when #skip_until was called with a String pattern" do
# https://github.com/ruby/strscan/issues/139
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "returns nil when matching succeeded" do
@s.skip_until("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4.3"
it "raises IndexError when matching succeeded" do
@s.skip_until("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
it "returns nil when matching failed" do
@s.skip_until("2008")
@s.should_not.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
it "returns a matching substring when given Integer index" do
@@ -108,7 +104,6 @@ describe "StringScanner#skip_until" do
end
# https://github.com/ruby/strscan/issues/135
- ruby_version_is ""..."3.5" do # Don't run on 3.5.0dev that already contains not released fixes
version_is StringScanner::Version, "3.1.1"..."3.1.3" do # ruby_version_is "3.4.0"..."3.4.3"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -117,10 +112,9 @@ describe "StringScanner#skip_until" do
@s.skip_until("This")
@s.should.matched?
- @s[:a].should be_nil
+ @s[:a].should == nil
end
end
- end
version_is StringScanner::Version, "3.1.3" do # ruby_version_is "3.4"
it "ignores the previous matching with Regexp" do
@s.exist?(/(?<a>This)/)
@@ -129,7 +123,7 @@ describe "StringScanner#skip_until" do
@s.skip_until("This")
@s.should.matched?
- -> { @s[:a] }.should raise_error(IndexError)
+ -> { @s[:a] }.should.raise(IndexError)
end
end
end
diff --git a/spec/ruby/library/stringscanner/string_spec.rb b/spec/ruby/library/stringscanner/string_spec.rb
index cba6bd51dd..6cbbff4822 100644
--- a/spec/ruby/library/stringscanner/string_spec.rb
+++ b/spec/ruby/library/stringscanner/string_spec.rb
@@ -14,7 +14,7 @@ describe "StringScanner#string" do
end
it "returns the identical object passed in" do
- @s.string.equal?(@string).should be_true
+ @s.string.equal?(@string).should == true
end
end
diff --git a/spec/ruby/library/stringscanner/terminate_spec.rb b/spec/ruby/library/stringscanner/terminate_spec.rb
index 7943efe0f9..3cff5c010c 100644
--- a/spec/ruby/library/stringscanner/terminate_spec.rb
+++ b/spec/ruby/library/stringscanner/terminate_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../spec_helper'
-require_relative 'shared/terminate'
require 'strscan'
describe "StringScanner#terminate" do
- it_behaves_like :strscan_terminate, :terminate
+ it "set the scan pointer to the end of the string and clear matching data." do
+ s = StringScanner.new('This is a test')
+ s.terminate
+ s.should_not.bol?
+ s.should.eos?
+ end
end
diff --git a/spec/ruby/library/stringscanner/unscan_spec.rb b/spec/ruby/library/stringscanner/unscan_spec.rb
index df0ea43367..f738778273 100644
--- a/spec/ruby/library/stringscanner/unscan_spec.rb
+++ b/spec/ruby/library/stringscanner/unscan_spec.rb
@@ -21,8 +21,8 @@ describe "StringScanner#unscan" do
@s.pos.should == pos
end
- it "raises a ScanError when the previous match had failed" do
- -> { @s.unscan }.should raise_error(ScanError)
- -> { @s.scan(/\d/); @s.unscan }.should raise_error(ScanError)
+ it "raises a StringScanner::Error when the previous match had failed" do
+ -> { @s.unscan }.should.raise(StringScanner::Error)
+ -> { @s.scan(/\d/); @s.unscan }.should.raise(StringScanner::Error)
end
end
diff --git a/spec/ruby/library/stringscanner/values_at_spec.rb b/spec/ruby/library/stringscanner/values_at_spec.rb
index 14d4a5f6a7..b00cce0ffa 100644
--- a/spec/ruby/library/stringscanner/values_at_spec.rb
+++ b/spec/ruby/library/stringscanner/values_at_spec.rb
@@ -35,7 +35,7 @@ describe "StringScanner#captures" do
-> {
@s.values_at("foo")
- }.should raise_error(IndexError, "undefined group name reference: foo")
+ }.should.raise(IndexError, "undefined group name reference: foo")
end
end
@@ -54,7 +54,7 @@ describe "StringScanner#captures" do
-> {
@s.values_at([])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ }.should.raise(TypeError, "no implicit conversion of Array into Integer")
end
it "returns nil if the most recent matching fails" do
diff --git a/spec/ruby/library/syslog/close_spec.rb b/spec/ruby/library/syslog/close_spec.rb
index 8c3b67c05b..713ef701d2 100644
--- a/spec/ruby/library/syslog/close_spec.rb
+++ b/spec/ruby/library/syslog/close_spec.rb
@@ -7,29 +7,29 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "closes the log" do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
Syslog.open
- Syslog.opened?.should be_true
+ Syslog.opened?.should == true
Syslog.close
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "raises a RuntimeError if the log's already closed" do
- -> { Syslog.close }.should raise_error(RuntimeError)
+ -> { Syslog.close }.should.raise(RuntimeError)
end
it "it does not work inside blocks" do
-> {
Syslog.open { |s| s.close }
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
Syslog.should_not.opened?
end
@@ -37,7 +37,7 @@ platform_is_not :windows do
Syslog.open("rubyspec")
Syslog.ident.should == "rubyspec"
Syslog.close
- Syslog.ident.should be_nil
+ Syslog.ident.should == nil
end
it "sets the options to nil" do
diff --git a/spec/ruby/library/syslog/constants_spec.rb b/spec/ruby/library/syslog/constants_spec.rb
index 2b9524c53d..a6ac355ddd 100644
--- a/spec/ruby/library/syslog/constants_spec.rb
+++ b/spec/ruby/library/syslog/constants_spec.rb
@@ -4,7 +4,7 @@ platform_is_not :windows do
require 'syslog'
describe "Syslog::Constants" do
- platform_is_not :windows, :solaris, :aix do
+ platform_is_not :windows, :aix do
before :all do
@constants = %w(LOG_AUTHPRIV LOG_USER LOG_LOCAL2 LOG_NOTICE LOG_NDELAY
LOG_SYSLOG LOG_ALERT LOG_FTP LOG_LOCAL5 LOG_ERR LOG_AUTH
@@ -17,7 +17,7 @@ platform_is_not :windows do
it "includes the Syslog constants" do
@constants.each do |c|
- Syslog::Constants.should have_constant(c)
+ Syslog::Constants.should.const_defined?(c, true)
end
end
end
diff --git a/spec/ruby/library/syslog/facility_spec.rb b/spec/ruby/library/syslog/facility_spec.rb
index 550ca70b11..79a685c201 100644
--- a/spec/ruby/library/syslog/facility_spec.rb
+++ b/spec/ruby/library/syslog/facility_spec.rb
@@ -7,11 +7,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns the logging facility" do
@@ -21,7 +21,7 @@ platform_is_not :windows do
end
it "returns nil if the log is closed" do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
Syslog.facility.should == nil
end
diff --git a/spec/ruby/library/syslog/ident_spec.rb b/spec/ruby/library/syslog/ident_spec.rb
index 3b08327140..80302a42b8 100644
--- a/spec/ruby/library/syslog/ident_spec.rb
+++ b/spec/ruby/library/syslog/ident_spec.rb
@@ -7,11 +7,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns the logging identity" do
diff --git a/spec/ruby/library/syslog/inspect_spec.rb b/spec/ruby/library/syslog/inspect_spec.rb
index f45231f8e3..6407423fd3 100644
--- a/spec/ruby/library/syslog/inspect_spec.rb
+++ b/spec/ruby/library/syslog/inspect_spec.rb
@@ -7,11 +7,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns a string a closed log" do
diff --git a/spec/ruby/library/syslog/log_spec.rb b/spec/ruby/library/syslog/log_spec.rb
index 8589fb1f73..1650283371 100644
--- a/spec/ruby/library/syslog/log_spec.rb
+++ b/spec/ruby/library/syslog/log_spec.rb
@@ -4,14 +4,14 @@ platform_is_not :windows do
require 'syslog'
describe "Syslog.log" do
- platform_is_not :windows, :darwin, :solaris, :aix, :android do
+ platform_is_not :windows, :darwin, :aix, :android do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "receives a priority as first argument" do
@@ -34,14 +34,14 @@ platform_is_not :windows do
it "fails with TypeError on nil log messages" do
Syslog.open do |s|
- -> { s.log(1, nil) }.should raise_error(TypeError)
+ -> { s.log(1, nil) }.should.raise(TypeError)
end
end
it "fails if the log is closed" do
-> {
Syslog.log(Syslog::LOG_ALERT, "test")
- }.should raise_error(RuntimeError)
+ }.should.raise(RuntimeError)
end
it "accepts printf parameters" do
diff --git a/spec/ruby/library/syslog/mask_spec.rb b/spec/ruby/library/syslog/mask_spec.rb
index b3f1250b24..23cca6fa8d 100644
--- a/spec/ruby/library/syslog/mask_spec.rb
+++ b/spec/ruby/library/syslog/mask_spec.rb
@@ -7,11 +7,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
# make sure we return the mask to the default value
Syslog.open { |s| s.mask = 255 }
end
@@ -74,11 +74,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
# make sure we return the mask to the default value
Syslog.open { |s| s.mask = 255 }
end
@@ -91,7 +91,7 @@ platform_is_not :windows do
end
it "raises an error if the log is closed" do
- -> { Syslog.mask = 1337 }.should raise_error(RuntimeError)
+ -> { Syslog.mask = 1337 }.should.raise(RuntimeError)
end
it "only accepts numbers" do
@@ -103,8 +103,8 @@ platform_is_not :windows do
Syslog.mask = 3.1416
Syslog.mask.should == 3
- -> { Syslog.mask = "oh hai" }.should raise_error(TypeError)
- -> { Syslog.mask = "43" }.should raise_error(TypeError)
+ -> { Syslog.mask = "oh hai" }.should.raise(TypeError)
+ -> { Syslog.mask = "43" }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/library/syslog/open_spec.rb b/spec/ruby/library/syslog/open_spec.rb
index 543f5d418b..73e3780d78 100644
--- a/spec/ruby/library/syslog/open_spec.rb
+++ b/spec/ruby/library/syslog/open_spec.rb
@@ -8,11 +8,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns the module" do
@@ -69,18 +69,18 @@ platform_is_not :windows do
it "closes the log if after it receives a block" do
Syslog.open{ }
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "raises an error if the log is opened" do
Syslog.open
-> {
Syslog.open
- }.should raise_error(RuntimeError, /syslog already open/)
+ }.should.raise(RuntimeError, /syslog already open/)
-> {
Syslog.close
Syslog.open
- }.should_not raise_error
+ }.should_not.raise
Syslog.close
end
end
diff --git a/spec/ruby/library/syslog/opened_spec.rb b/spec/ruby/library/syslog/opened_spec.rb
index 94432e65a4..ad4311d15a 100644
--- a/spec/ruby/library/syslog/opened_spec.rb
+++ b/spec/ruby/library/syslog/opened_spec.rb
@@ -7,32 +7,32 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns true if the log is opened" do
Syslog.open
- Syslog.opened?.should be_true
+ Syslog.opened?.should == true
Syslog.close
end
it "returns false otherwise" do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
Syslog.open
Syslog.close
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "works inside a block" do
Syslog.open do |s|
- s.opened?.should be_true
- Syslog.opened?.should be_true
+ s.opened?.should == true
+ Syslog.opened?.should == true
end
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
end
end
diff --git a/spec/ruby/library/syslog/options_spec.rb b/spec/ruby/library/syslog/options_spec.rb
index 83ba43503e..2035272f70 100644
--- a/spec/ruby/library/syslog/options_spec.rb
+++ b/spec/ruby/library/syslog/options_spec.rb
@@ -7,11 +7,11 @@ platform_is_not :windows do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns the logging options" do
@@ -21,7 +21,7 @@ platform_is_not :windows do
end
it "returns nil when the log is closed" do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
Syslog.options.should == nil
end
diff --git a/spec/ruby/library/syslog/shared/log.rb b/spec/ruby/library/syslog/shared/log.rb
index 12e4ea8366..98ce4f54b2 100644
--- a/spec/ruby/library/syslog/shared/log.rb
+++ b/spec/ruby/library/syslog/shared/log.rb
@@ -1,11 +1,11 @@
describe :syslog_log, shared: true do
- platform_is_not :windows, :darwin, :solaris, :aix, :android do
+ platform_is_not :windows, :darwin, :aix, :android do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "logs a message" do
diff --git a/spec/ruby/library/syslog/shared/reopen.rb b/spec/ruby/library/syslog/shared/reopen.rb
index 621437a01d..f04408e807 100644
--- a/spec/ruby/library/syslog/shared/reopen.rb
+++ b/spec/ruby/library/syslog/shared/reopen.rb
@@ -1,22 +1,22 @@
describe :syslog_reopen, shared: true do
platform_is_not :windows do
before :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
after :each do
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "reopens the log" do
Syslog.open
- -> { Syslog.send(@method)}.should_not raise_error
- Syslog.opened?.should be_true
+ -> { Syslog.send(@method)}.should_not.raise
+ Syslog.opened?.should == true
Syslog.close
end
it "fails with RuntimeError if the log is closed" do
- -> { Syslog.send(@method)}.should raise_error(RuntimeError)
+ -> { Syslog.send(@method)}.should.raise(RuntimeError)
end
it "receives the same parameters as Syslog.open" do
@@ -26,9 +26,9 @@ describe :syslog_reopen, shared: true do
s.ident.should == "rubyspec"
s.options.should == 3
s.facility.should == Syslog::LOG_USER
- s.opened?.should be_true
+ s.opened?.should == true
end
- Syslog.opened?.should be_false
+ Syslog.opened?.should == false
end
it "returns the module" do
diff --git a/spec/ruby/library/tempfile/_close_spec.rb b/spec/ruby/library/tempfile/_close_spec.rb
index c08f425b6f..344b08dc17 100644
--- a/spec/ruby/library/tempfile/_close_spec.rb
+++ b/spec/ruby/library/tempfile/_close_spec.rb
@@ -11,11 +11,11 @@ describe "Tempfile#_close" do
end
it "is protected" do
- Tempfile.should have_protected_instance_method(:_close)
+ Tempfile.protected_instance_methods(false).should.include?(:_close)
end
it "closes self" do
@tempfile.send(:_close)
- @tempfile.closed?.should be_true
+ @tempfile.closed?.should == true
end
end
diff --git a/spec/ruby/library/tempfile/callback_spec.rb b/spec/ruby/library/tempfile/callback_spec.rb
deleted file mode 100644
index c0b1518326..0000000000
--- a/spec/ruby/library/tempfile/callback_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../spec_helper'
-require 'tempfile'
-
-describe "Tempfile.callback" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/library/tempfile/close_spec.rb b/spec/ruby/library/tempfile/close_spec.rb
index db0eae3fa5..7e95ae1d7e 100644
--- a/spec/ruby/library/tempfile/close_spec.rb
+++ b/spec/ruby/library/tempfile/close_spec.rb
@@ -12,7 +12,7 @@ describe "Tempfile#close when passed no argument or [false]" do
it "closes self" do
@tempfile.close
- @tempfile.closed?.should be_true
+ @tempfile.closed?.should == true
end
it "does not unlink self" do
@@ -29,7 +29,7 @@ describe "Tempfile#close when passed [true]" do
it "closes self" do
@tempfile.close(true)
- @tempfile.closed?.should be_true
+ @tempfile.closed?.should == true
end
it "unlinks self" do
@@ -46,7 +46,7 @@ describe "Tempfile#close!" do
it "closes self" do
@tempfile.close!
- @tempfile.closed?.should be_true
+ @tempfile.closed?.should == true
end
it "unlinks self" do
diff --git a/spec/ruby/library/tempfile/create_spec.rb b/spec/ruby/library/tempfile/create_spec.rb
new file mode 100644
index 0000000000..be6d21e218
--- /dev/null
+++ b/spec/ruby/library/tempfile/create_spec.rb
@@ -0,0 +1,176 @@
+require_relative '../../spec_helper'
+require 'tempfile'
+
+describe "Tempfile.create" do
+ after :each do
+ if @tempfile
+ @tempfile.close
+ File.unlink(@tempfile.path) if File.file?(@tempfile.path)
+ end
+ end
+
+ it "returns a new, open regular File instance placed in tmpdir" do
+ @tempfile = Tempfile.create
+ # Unlike Tempfile.open this returns a true File,
+ # but `.should.instance_of?(File)` would be true either way.
+ @tempfile.instance_of?(File).should == true
+
+ @tempfile.should_not.closed?
+ File.file?(@tempfile.path).should == true
+
+ @tempfile.path.should.start_with?(Dir.tmpdir)
+ @tempfile.path.should_not == "#{Dir.tmpdir}/"
+ end
+
+ it "returns file in w+ mode" do
+ @tempfile = Tempfile.create
+ @tempfile << "Test!\nMore test!"
+ @tempfile.rewind
+ @tempfile.read.should == "Test!\nMore test!"
+
+ # Not "a+" mode, which would write at the end of the file.
+ @tempfile.rewind
+ @tempfile.print "Trust"
+ @tempfile.rewind
+ @tempfile.read.should == "Trust\nMore test!"
+ end
+
+ platform_is_not :windows do
+ it "returns a private, readable and writable file" do
+ @tempfile = Tempfile.create
+ stat = @tempfile.stat
+ stat.should.readable?
+ stat.should.writable?
+ stat.should_not.executable?
+ stat.should_not.world_readable?
+ stat.should_not.world_writable?
+ end
+ end
+
+ platform_is :windows do
+ it "returns a public, readable and writable file" do
+ @tempfile = Tempfile.create
+ stat = @tempfile.stat
+ stat.should.readable?
+ stat.should.writable?
+ stat.should_not.executable?
+ stat.should.world_readable?
+ stat.should.world_writable?
+ end
+ end
+
+ context "when called with a block" do
+ it "returns the value of the block" do
+ value = Tempfile.create do |tempfile|
+ tempfile << "Test!"
+ "return"
+ end
+ value.should == "return"
+ end
+
+ it "closes and unlinks file after block execution" do
+ Tempfile.create do |tempfile|
+ @tempfile = tempfile
+ @tempfile.should_not.closed?
+ File.exist?(@tempfile.path).should == true
+ end
+
+ @tempfile.should.closed?
+ File.exist?(@tempfile.path).should == false
+ end
+ end
+
+ context "when called with a single positional argument" do
+ it "uses a String as a prefix for the filename" do
+ @tempfile = Tempfile.create("create_spec")
+ @tempfile.path.should.start_with?("#{Dir.tmpdir}/create_spec")
+ @tempfile.path.should_not == "#{Dir.tmpdir}/create_spec"
+ end
+
+ it "uses an array of one String as a prefix for the filename" do
+ @tempfile = Tempfile.create(["create_spec"])
+ @tempfile.path.should.start_with?("#{Dir.tmpdir}/create_spec")
+ @tempfile.path.should_not == "#{Dir.tmpdir}/create_spec"
+ end
+
+ it "uses an array of two Strings as a prefix and suffix for the filename" do
+ @tempfile = Tempfile.create(["create_spec", ".temp"])
+ @tempfile.path.should.start_with?("#{Dir.tmpdir}/create_spec")
+ @tempfile.path.should.end_with?(".temp")
+ end
+
+ it "ignores excessive array elements after the first two" do
+ @tempfile = Tempfile.create(["create_spec", ".temp", :".txt"])
+ @tempfile.path.should.start_with?("#{Dir.tmpdir}/create_spec")
+ @tempfile.path.should.end_with?(".temp")
+ end
+
+ it "raises ArgumentError if passed something else than a String or an array of Strings" do
+ -> { Tempfile.create(:create_spec) }.should.raise(ArgumentError, "unexpected prefix: :create_spec")
+ -> { Tempfile.create([:create_spec]) }.should.raise(ArgumentError, "unexpected prefix: :create_spec")
+ -> { Tempfile.create(["create_spec", :temp]) }.should.raise(ArgumentError, "unexpected suffix: :temp")
+ end
+ end
+
+ context "when called with a second positional argument" do
+ it "uses it as a directory for the tempfile" do
+ @tempfile = Tempfile.create("create_spec", "./")
+ @tempfile.path.should.start_with?("./create_spec")
+ end
+
+ it "raises TypeError if argument can not be converted to a String" do
+ -> { Tempfile.create("create_spec", :temp) }.should.raise(TypeError, "no implicit conversion of Symbol into String")
+ end
+ end
+
+ context "when called with a mode option" do
+ it "ORs it with the default mode, forcing it to be readable and writable" do
+ @tempfile = Tempfile.create(mode: File::RDONLY)
+ @tempfile.puts "test"
+ @tempfile.rewind
+ @tempfile.read.should == "test\n"
+ end
+
+ it "raises NoMethodError if passed a String mode" do
+ -> { Tempfile.create(mode: "wb") }.should.raise(NoMethodError, /undefined method ['`]|' for .+String/)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ context "when called with anonymous: true" do
+ it "returns an already unlinked File without a proper path" do
+ @tempfile = Tempfile.create(anonymous: true)
+ @tempfile.should_not.closed?
+ @tempfile.path.should == "#{Dir.tmpdir}/"
+ File.file?(@tempfile.path).should == false
+ end
+
+ it "unlinks file before calling the block" do
+ Tempfile.create(anonymous: true) do |tempfile|
+ @tempfile = tempfile
+ @tempfile.should_not.closed?
+ @tempfile.path.should == "#{Dir.tmpdir}/"
+ File.file?(@tempfile.path).should == false
+ end
+ @tempfile.should.closed?
+ end
+ end
+
+ context "when called with anonymous: false" do
+ it "returns a usual File with a path" do
+ @tempfile = Tempfile.create(anonymous: false)
+ @tempfile.should_not.closed?
+ @tempfile.path.should.start_with?(Dir.tmpdir)
+ File.file?(@tempfile.path).should == true
+ end
+ end
+ end
+
+ context "when called with other options" do
+ it "passes them along to File.open" do
+ @tempfile = Tempfile.create(encoding: "IBM037:IBM037", binmode: true)
+ @tempfile.external_encoding.should == Encoding.find("IBM037")
+ @tempfile.binmode?.should == true
+ end
+ end
+end
diff --git a/spec/ruby/library/tempfile/initialize_spec.rb b/spec/ruby/library/tempfile/initialize_spec.rb
index f2e786d7d8..0e882a3f0c 100644
--- a/spec/ruby/library/tempfile/initialize_spec.rb
+++ b/spec/ruby/library/tempfile/initialize_spec.rb
@@ -24,7 +24,7 @@ describe "Tempfile#initialize" do
end
path[0, tmpdir.length].should == tmpdir
- path.should include("basename")
+ path.should.include?("basename")
end
platform_is_not :windows do
diff --git a/spec/ruby/library/tempfile/open_spec.rb b/spec/ruby/library/tempfile/open_spec.rb
index ef2c95376f..0993a2c5ee 100644
--- a/spec/ruby/library/tempfile/open_spec.rb
+++ b/spec/ruby/library/tempfile/open_spec.rb
@@ -14,7 +14,7 @@ describe "Tempfile#open" do
it "reopens self" do
@tempfile.close
@tempfile.open
- @tempfile.closed?.should be_false
+ @tempfile.closed?.should == false
end
it "reopens self in read and write mode and does not truncate" do
@@ -33,8 +33,8 @@ describe "Tempfile.open" do
it "returns a new, open Tempfile instance" do
@tempfile = Tempfile.open("specs")
- # Delegation messes up .should be_an_instance_of(Tempfile)
- @tempfile.instance_of?(Tempfile).should be_true
+ # Delegation messes up .should.instance_of?(Tempfile)
+ @tempfile.instance_of?(Tempfile).should == true
end
it "is passed an array [base, suffix] as first argument" do
@@ -46,14 +46,14 @@ describe "Tempfile.open" do
Tempfile.open("specs", Dir.tmpdir, encoding: "IBM037:IBM037", binmode: true) do |tempfile|
@tempfile = tempfile
tempfile.external_encoding.should == Encoding.find("IBM037")
- tempfile.binmode?.should be_true
+ tempfile.binmode?.should == true
end
end
it "uses a blank string for basename when passed no arguments" do
Tempfile.open() do |tempfile|
@tempfile = tempfile
- tempfile.closed?.should be_false
+ tempfile.closed?.should == false
end
@tempfile.should_not == nil
end
@@ -74,9 +74,9 @@ describe "Tempfile.open when passed a block" do
@tempfile = tempfile
ScratchPad.record :yielded
- # Delegation messes up .should be_an_instance_of(Tempfile)
- tempfile.instance_of?(Tempfile).should be_true
- tempfile.closed?.should be_false
+ # Delegation messes up .should.instance_of?(Tempfile)
+ tempfile.instance_of?(Tempfile).should == true
+ tempfile.closed?.should == false
end
ScratchPad.recorded.should == :yielded
@@ -92,6 +92,6 @@ describe "Tempfile.open when passed a block" do
it "closes the yielded Tempfile after the block" do
Tempfile.open("specs") { |tempfile| @tempfile = tempfile }
- @tempfile.closed?.should be_true
+ @tempfile.closed?.should == true
end
end
diff --git a/spec/ruby/library/tempfile/path_spec.rb b/spec/ruby/library/tempfile/path_spec.rb
index 07f75b3e10..be56bd87c8 100644
--- a/spec/ruby/library/tempfile/path_spec.rb
+++ b/spec/ruby/library/tempfile/path_spec.rb
@@ -21,6 +21,6 @@ describe "Tempfile#path" do
end
path[0, tmpdir.length].should == tmpdir
- path.should include("specs")
+ path.should.include?("specs")
end
end
diff --git a/spec/ruby/library/tempfile/shared/length.rb b/spec/ruby/library/tempfile/shared/length.rb
index 4d18d1f385..1a89ff7b4d 100644
--- a/spec/ruby/library/tempfile/shared/length.rb
+++ b/spec/ruby/library/tempfile/shared/length.rb
@@ -8,14 +8,14 @@ describe :tempfile_length, shared: true do
end
it "returns the size of self" do
- @tempfile.send(@method).should eql(0)
+ @tempfile.send(@method).should.eql?(0)
@tempfile.print("Test!")
- @tempfile.send(@method).should eql(5)
+ @tempfile.send(@method).should.eql?(5)
end
it "returns the size of self even if self is closed" do
@tempfile.print("Test!")
@tempfile.close
- @tempfile.send(@method).should eql(5)
+ @tempfile.send(@method).should.eql?(5)
end
end
diff --git a/spec/ruby/library/thread/queue_spec.rb b/spec/ruby/library/thread/queue_spec.rb
index c7e2bb1b50..b6c4fef08f 100644
--- a/spec/ruby/library/thread/queue_spec.rb
+++ b/spec/ruby/library/thread/queue_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Thread::Queue" do
it "is the same class as ::Queue" do
- Thread.should have_constant(:Queue)
- Thread::Queue.should equal ::Queue
+ Thread.should.const_defined?(:Queue, false)
+ Thread::Queue.should.equal? ::Queue
end
end
diff --git a/spec/ruby/library/thread/sizedqueue_spec.rb b/spec/ruby/library/thread/sizedqueue_spec.rb
index 6151ff437c..ffa66bcd35 100644
--- a/spec/ruby/library/thread/sizedqueue_spec.rb
+++ b/spec/ruby/library/thread/sizedqueue_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "Thread::SizedQueue" do
it "is the same class as ::SizedQueue" do
- Thread.should have_constant(:SizedQueue)
- Thread::SizedQueue.should equal ::SizedQueue
+ Thread.should.const_defined?(:SizedQueue, false)
+ Thread::SizedQueue.should.equal? ::SizedQueue
end
end
diff --git a/spec/ruby/library/time/shared/rfc2822.rb b/spec/ruby/library/time/shared/rfc2822.rb
index e460d655a6..49ef76db47 100644
--- a/spec/ruby/library/time/shared/rfc2822.rb
+++ b/spec/ruby/library/time/shared/rfc2822.rb
@@ -60,6 +60,6 @@ describe :time_rfc2822, shared: true do
-> {
# inner comment is not supported.
Time.send(@method, "Fri, 21 Nov 1997 09(comment): 55 : 06 -0600")
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/time/to_time_spec.rb b/spec/ruby/library/time/to_time_spec.rb
index 7e6c75a003..d2b89cb112 100644
--- a/spec/ruby/library/time/to_time_spec.rb
+++ b/spec/ruby/library/time/to_time_spec.rb
@@ -6,10 +6,10 @@ describe "Time#to_time" do
time = Time.new(2012, 2, 21, 10, 11, 12)
with_timezone("America/Regina") do
- time.to_time.should equal time
+ time.to_time.should.equal? time
end
time2 = Time.utc(2012, 2, 21, 10, 11, 12)
- time2.to_time.should equal time2
+ time2.to_time.should.equal? time2
end
end
diff --git a/spec/ruby/library/timeout/error_spec.rb b/spec/ruby/library/timeout/error_spec.rb
index 6c236e5128..2c28236e29 100644
--- a/spec/ruby/library/timeout/error_spec.rb
+++ b/spec/ruby/library/timeout/error_spec.rb
@@ -3,6 +3,6 @@ require 'timeout'
describe "Timeout::Error" do
it "is a subclass of RuntimeError" do
- RuntimeError.should be_ancestor_of(Timeout::Error)
+ Timeout::Error.ancestors.should.include?(RuntimeError)
end
end
diff --git a/spec/ruby/library/timeout/timeout_spec.rb b/spec/ruby/library/timeout/timeout_spec.rb
index 584b38d8ec..9ae70bf600 100644
--- a/spec/ruby/library/timeout/timeout_spec.rb
+++ b/spec/ruby/library/timeout/timeout_spec.rb
@@ -7,7 +7,7 @@ describe "Timeout.timeout" do
Timeout.timeout(1) do
sleep
end
- }.should raise_error(Timeout::Error)
+ }.should.raise(Timeout::Error)
end
it "raises specified error type when it times out" do
@@ -15,7 +15,7 @@ describe "Timeout.timeout" do
Timeout.timeout(1, StandardError) do
sleep
end
- end.should raise_error(StandardError)
+ end.should.raise(StandardError)
end
it "raises specified error type with specified message when it times out" do
@@ -23,7 +23,7 @@ describe "Timeout.timeout" do
Timeout.timeout(1, StandardError, "foobar") do
sleep
end
- end.should raise_error(StandardError, "foobar")
+ end.should.raise(StandardError, "foobar")
end
it "raises specified error type with a default message when it times out if message is nil" do
@@ -31,7 +31,7 @@ describe "Timeout.timeout" do
Timeout.timeout(1, StandardError, nil) do
sleep
end
- end.should raise_error(StandardError, "execution expired")
+ end.should.raise(StandardError, "execution expired")
end
it "returns back the last value in the block" do
@@ -39,4 +39,12 @@ describe "Timeout.timeout" do
42
end.should == 42
end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError when provided with a negative duration" do
+ -> {
+ Timeout.timeout(-1)
+ }.should.raise(ArgumentError, "Timeout sec must be a non-negative number")
+ end
+ end
end
diff --git a/spec/ruby/library/tmpdir/dir/mktmpdir_spec.rb b/spec/ruby/library/tmpdir/dir/mktmpdir_spec.rb
index 8165c2d8a8..edc4795efb 100644
--- a/spec/ruby/library/tmpdir/dir/mktmpdir_spec.rb
+++ b/spec/ruby/library/tmpdir/dir/mktmpdir_spec.rb
@@ -16,8 +16,8 @@ describe "Dir.mktmpdir when passed no arguments" do
it "creates a new writable directory in the path provided by Dir.tmpdir" do
Dir.should_receive(:tmpdir).and_return(tmp(""))
@tmpdir = Dir.mktmpdir
- File.directory?(@tmpdir).should be_true
- File.writable?(@tmpdir).should be_true
+ File.directory?(@tmpdir).should == true
+ File.writable?(@tmpdir).should == true
end
end
@@ -41,15 +41,15 @@ describe "Dir.mktmpdir when passed a block" do
called = true
path.should.start_with?(@real_tmp_root)
end
- called.should be_true
+ called.should == true
end
it "creates the tmp-dir before yielding" do
Dir.should_receive(:tmpdir).and_return(tmp(""))
Dir.mktmpdir do |path|
@tmpdir = path
- File.directory?(path).should be_true
- File.writable?(path).should be_true
+ File.directory?(path).should == true
+ File.writable?(path).should == true
end
end
@@ -67,7 +67,7 @@ describe "Dir.mktmpdir when passed a block" do
@tmpdir = path
:test
end
- result.should equal(:test)
+ result.should.equal?(:test)
end
end
@@ -110,8 +110,8 @@ end
describe "Dir.mktmpdir when passed [Object]" do
it "raises an ArgumentError" do
- -> { Dir.mktmpdir(Object.new) }.should raise_error(ArgumentError)
- -> { Dir.mktmpdir(:symbol) }.should raise_error(ArgumentError)
- -> { Dir.mktmpdir(10) }.should raise_error(ArgumentError)
+ -> { Dir.mktmpdir(Object.new) }.should.raise(ArgumentError)
+ -> { Dir.mktmpdir(:symbol) }.should.raise(ArgumentError)
+ -> { Dir.mktmpdir(10) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/tmpdir/dir/tmpdir_spec.rb b/spec/ruby/library/tmpdir/dir/tmpdir_spec.rb
index f4ab5e40b8..330f04458f 100644
--- a/spec/ruby/library/tmpdir/dir/tmpdir_spec.rb
+++ b/spec/ruby/library/tmpdir/dir/tmpdir_spec.rb
@@ -4,7 +4,7 @@ require "tmpdir"
describe "Dir.tmpdir" do
it "returns the path to a writable and readable directory" do
dir = Dir.tmpdir
- File.directory?(dir).should be_true
- File.writable?(dir).should be_true
+ File.directory?(dir).should == true
+ File.writable?(dir).should == true
end
end
diff --git a/spec/ruby/library/uri/generic/host_spec.rb b/spec/ruby/library/uri/generic/host_spec.rb
index 210124ef66..4a5a162512 100644
--- a/spec/ruby/library/uri/generic/host_spec.rb
+++ b/spec/ruby/library/uri/generic/host_spec.rb
@@ -2,11 +2,9 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#host" do
- version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do
- # https://hackerone.com/reports/156615
- it "returns empty string when host is empty" do
- URI.parse('http:////foo.com').host.should == ''
- end
+ # https://hackerone.com/reports/156615
+ it "returns empty string when host is empty" do
+ URI.parse('http:////foo.com').host.should == ''
end
end
diff --git a/spec/ruby/library/uri/generic/to_s_spec.rb b/spec/ruby/library/uri/generic/to_s_spec.rb
index 8cebd374a1..c436ee3c03 100644
--- a/spec/ruby/library/uri/generic/to_s_spec.rb
+++ b/spec/ruby/library/uri/generic/to_s_spec.rb
@@ -2,10 +2,8 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#to_s" do
- version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do
- # https://hackerone.com/reports/156615
- it "preserves / characters when host is empty" do
- URI('http:///foo.com').to_s.should == 'http:///foo.com'
- end
+ # https://hackerone.com/reports/156615
+ it "preserves / characters when host is empty" do
+ URI('http:///foo.com').to_s.should == 'http:///foo.com'
end
end
diff --git a/spec/ruby/library/uri/join_spec.rb b/spec/ruby/library/uri/join_spec.rb
index 796f74134f..1777303360 100644
--- a/spec/ruby/library/uri/join_spec.rb
+++ b/spec/ruby/library/uri/join_spec.rb
@@ -23,7 +23,7 @@ describe "URI.join" do
it "raises an error if given no argument" do
-> {
URI.join
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "doesn't create redundant '/'s" do
diff --git a/spec/ruby/library/uri/mailto/build_spec.rb b/spec/ruby/library/uri/mailto/build_spec.rb
index 2c011626ab..081707b1cf 100644
--- a/spec/ruby/library/uri/mailto/build_spec.rb
+++ b/spec/ruby/library/uri/mailto/build_spec.rb
@@ -84,7 +84,7 @@ describe "URI::Mailto.build" do
end
bad.each do |x|
- -> { URI::MailTo.build(x) }.should raise_error(URI::InvalidComponentError)
+ -> { URI::MailTo.build(x) }.should.raise(URI::InvalidComponentError)
end
ok.flatten.join("\0").should == ok_all
diff --git a/spec/ruby/library/uri/parse_spec.rb b/spec/ruby/library/uri/parse_spec.rb
index e9ec59b490..f0373fbf5e 100644
--- a/spec/ruby/library/uri/parse_spec.rb
+++ b/spec/ruby/library/uri/parse_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "URI.parse" do
it "returns a URI::HTTP object when parsing an HTTP URI" do
- URI.parse("http://www.example.com/").should be_kind_of(URI::HTTP)
+ URI.parse("http://www.example.com/").should.is_a?(URI::HTTP)
end
it "populates the components of a parsed URI::HTTP, setting the port to 80 by default" do
@@ -47,7 +47,7 @@ describe "URI.parse" do
end
it "returns a URI::HTTPS object when parsing an HTTPS URI" do
- URI.parse("https://important-intern-net.net").should be_kind_of(URI::HTTPS)
+ URI.parse("https://important-intern-net.net").should.is_a?(URI::HTTPS)
end
it "sets the port of a parsed https URI to 443 by default" do
@@ -57,7 +57,7 @@ describe "URI.parse" do
it "populates the components of a parsed URI::FTP object" do
# generic, empty password.
url = URI.parse("ftp://anonymous@ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.bz2;type=i")
- url.should be_kind_of(URI::FTP)
+ url.should.is_a?(URI::FTP)
URISpec.components(url).should == {
scheme: "ftp",
userinfo: "anonymous",
@@ -69,7 +69,7 @@ describe "URI.parse" do
# multidomain, no user or password
url = URI.parse('ftp://ftp.is.co.za/rfc/rfc1808.txt')
- url.should be_kind_of(URI::FTP)
+ url.should.is_a?(URI::FTP)
URISpec.components(url).should == {
scheme: "ftp",
userinfo: nil,
@@ -81,7 +81,7 @@ describe "URI.parse" do
# empty user
url = URI.parse('ftp://:pass@localhost/')
- url.should be_kind_of(URI::FTP)
+ url.should.is_a?(URI::FTP)
URISpec.components(url).should == {
scheme: "ftp",
userinfo: ":pass",
@@ -97,7 +97,7 @@ describe "URI.parse" do
#taken from http://www.faqs.org/rfcs/rfc2255.html 'cause I don't really know what an LDAP url looks like
ldap_uris = %w{ ldap:///o=University%20of%20Michigan,c=US ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen) ldap://ldap.itd.umich.edu/c=GB?objectClass?one ldap://ldap.question.com/o=Question%3f,c=US?mail ldap://ldap.netscape.com/o=Babsco,c=US??(int=%5c00%5c00%5c00%5c04) ldap:///??sub??bindname=cn=Manager%2co=Foo ldap:///??sub??!bindname=cn=Manager%2co=Foo }
ldap_uris.each do |ldap_uri|
- URI.parse(ldap_uri).should be_kind_of(URI::LDAP)
+ URI.parse(ldap_uri).should.is_a?(URI::LDAP)
end
end
@@ -115,7 +115,7 @@ describe "URI.parse" do
end
it "returns a URI::MailTo object when passed a mailto URI" do
- URI.parse("mailto:spam@mailinator.com").should be_kind_of(URI::MailTo)
+ URI.parse("mailto:spam@mailinator.com").should.is_a?(URI::MailTo)
end
it "populates the components of a parsed URI::MailTo object" do
@@ -145,7 +145,7 @@ describe "URI.parse" do
# gopher
gopher = URI.parse('gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles')
- gopher.should be_kind_of(URI::Generic)
+ gopher.should.is_a?(URI::Generic)
URISpec.components(gopher).should == {
scheme: "gopher",
@@ -161,7 +161,7 @@ describe "URI.parse" do
# news
news = URI.parse('news:comp.infosystems.www.servers.unix')
- news.should be_kind_of(URI::Generic)
+ news.should.is_a?(URI::Generic)
URISpec.components(news).should == {
scheme: "news",
userinfo: nil,
@@ -176,7 +176,7 @@ describe "URI.parse" do
# telnet
telnet = URI.parse('telnet://melvyl.ucop.edu/')
- telnet.should be_kind_of(URI::Generic)
+ telnet.should.is_a?(URI::Generic)
URISpec.components(telnet).should == {
scheme: "telnet",
userinfo: nil,
@@ -191,9 +191,9 @@ describe "URI.parse" do
# files
file_l = URI.parse('file:///foo/bar.txt')
- file_l.should be_kind_of(URI::Generic)
+ file_l.should.is_a?(URI::Generic)
file = URI.parse('file:/foo/bar.txt')
- file.should be_kind_of(URI::Generic)
+ file.should.is_a?(URI::Generic)
end
it "doesn't raise errors on URIs which has underscore in reg_name" do
diff --git a/spec/ruby/library/uri/plus_spec.rb b/spec/ruby/library/uri/plus_spec.rb
index b84b0767c1..51fb5e3750 100644
--- a/spec/ruby/library/uri/plus_spec.rb
+++ b/spec/ruby/library/uri/plus_spec.rb
@@ -36,7 +36,7 @@ describe "URI#+" do
end
it "raises a URI::BadURIError when adding two relative URIs" do
- -> {URI.parse('a/b/c') + "d"}.should raise_error(URI::BadURIError)
+ -> {URI.parse('a/b/c') + "d"}.should.raise(URI::BadURIError)
end
#Todo: make more BDD?
@@ -47,403 +47,403 @@ describe "URI#+" do
# http://a/b/c/d;p?q
# g:h = g:h
url = @base_url.merge('g:h')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g:h'
url = @base_url.route_to('g:h')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g:h'
# http://a/b/c/d;p?q
# g = http://a/b/c/g
url = @base_url.merge('g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g'
url = @base_url.route_to('http://a/b/c/g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g'
# http://a/b/c/d;p?q
# ./g = http://a/b/c/g
url = @base_url.merge('./g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g'
url = @base_url.route_to('http://a/b/c/g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == './g' # ok
url.to_s.should == 'g'
# http://a/b/c/d;p?q
# g/ = http://a/b/c/g/
url = @base_url.merge('g/')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g/'
url = @base_url.route_to('http://a/b/c/g/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g/'
# http://a/b/c/d;p?q
# /g = http://a/g
url = @base_url.merge('/g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/g'
url = @base_url.route_to('http://a/g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == '/g' # ok
url.to_s.should == '../../g'
# http://a/b/c/d;p?q
# //g = http://g
url = @base_url.merge('//g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://g'
url = @base_url.route_to('http://g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '//g'
# http://a/b/c/d;p?q
# ?y = http://a/b/c/?y
url = @base_url.merge('?y')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/d;p?y'
url = @base_url.route_to('http://a/b/c/?y')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '?y'
# http://a/b/c/d;p?q
# g?y = http://a/b/c/g?y
url = @base_url.merge('g?y')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g?y'
url = @base_url.route_to('http://a/b/c/g?y')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g?y'
# http://a/b/c/d;p?q
# #s = (current document)#s
url = @base_url.merge('#s')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == @base_url.to_s + '#s'
url = @base_url.route_to(@base_url.to_s + '#s')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '#s'
# http://a/b/c/d;p?q
# g#s = http://a/b/c/g#s
url = @base_url.merge('g#s')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g#s'
url = @base_url.route_to('http://a/b/c/g#s')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g#s'
# http://a/b/c/d;p?q
# g?y#s = http://a/b/c/g?y#s
url = @base_url.merge('g?y#s')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g?y#s'
url = @base_url.route_to('http://a/b/c/g?y#s')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g?y#s'
# http://a/b/c/d;p?q
# ;x = http://a/b/c/;x
url = @base_url.merge(';x')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/;x'
url = @base_url.route_to('http://a/b/c/;x')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == ';x'
# http://a/b/c/d;p?q
# g;x = http://a/b/c/g;x
url = @base_url.merge('g;x')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g;x'
url = @base_url.route_to('http://a/b/c/g;x')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g;x'
# http://a/b/c/d;p?q
# g;x?y#s = http://a/b/c/g;x?y#s
url = @base_url.merge('g;x?y#s')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g;x?y#s'
url = @base_url.route_to('http://a/b/c/g;x?y#s')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g;x?y#s'
# http://a/b/c/d;p?q
# . = http://a/b/c/
url = @base_url.merge('.')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/'
url = @base_url.route_to('http://a/b/c/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == '.' # ok
url.to_s.should == './'
# http://a/b/c/d;p?q
# ./ = http://a/b/c/
url = @base_url.merge('./')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/'
url = @base_url.route_to('http://a/b/c/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == './'
# http://a/b/c/d;p?q
# .. = http://a/b/
url = @base_url.merge('..')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/'
url = @base_url.route_to('http://a/b/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == '..' # ok
url.to_s.should == '../'
# http://a/b/c/d;p?q
# ../ = http://a/b/
url = @base_url.merge('../')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/'
url = @base_url.route_to('http://a/b/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '../'
# http://a/b/c/d;p?q
# ../g = http://a/b/g
url = @base_url.merge('../g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/g'
url = @base_url.route_to('http://a/b/g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '../g'
# http://a/b/c/d;p?q
# ../.. = http://a/
url = @base_url.merge('../..')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/'
url = @base_url.route_to('http://a/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == '../..' # ok
url.to_s.should == '../../'
# http://a/b/c/d;p?q
# ../../ = http://a/
url = @base_url.merge('../../')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/'
url = @base_url.route_to('http://a/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '../../'
# http://a/b/c/d;p?q
# ../../g = http://a/g
url = @base_url.merge('../../g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/g'
url = @base_url.route_to('http://a/g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '../../g'
# http://a/b/c/d;p?q
# <> = (current document)
url = @base_url.merge('')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/d;p?q'
url = @base_url.route_to('http://a/b/c/d;p?q')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == ''
# http://a/b/c/d;p?q
# /./g = http://a/./g
url = @base_url.merge('/./g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/g'
url = @base_url.route_to('http://a/./g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '/./g'
# http://a/b/c/d;p?q
# /../g = http://a/../g
url = @base_url.merge('/../g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/g'
url = @base_url.route_to('http://a/../g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '/../g'
# http://a/b/c/d;p?q
# g. = http://a/b/c/g.
url = @base_url.merge('g.')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g.'
url = @base_url.route_to('http://a/b/c/g.')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g.'
# http://a/b/c/d;p?q
# .g = http://a/b/c/.g
url = @base_url.merge('.g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/.g'
url = @base_url.route_to('http://a/b/c/.g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '.g'
# http://a/b/c/d;p?q
# g.. = http://a/b/c/g..
url = @base_url.merge('g..')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g..'
url = @base_url.route_to('http://a/b/c/g..')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g..'
# http://a/b/c/d;p?q
# ..g = http://a/b/c/..g
url = @base_url.merge('..g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/..g'
url = @base_url.route_to('http://a/b/c/..g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == '..g'
# http://a/b/c/d;p?q
# ../../../g = http://a/../g
url = @base_url.merge('../../../g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/g'
url = @base_url.route_to('http://a/../g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == '../../../g' # ok? yes, it confuses you
url.to_s.should == '/../g' # and it is clearly
# http://a/b/c/d;p?q
# ../../../../g = http://a/../../g
url = @base_url.merge('../../../../g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/g'
url = @base_url.route_to('http://a/../../g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == '../../../../g' # ok? yes, it confuses you
url.to_s.should == '/../../g' # and it is clearly
# http://a/b/c/d;p?q
# ./../g = http://a/b/g
url = @base_url.merge('./../g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/g'
url = @base_url.route_to('http://a/b/g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == './../g' # ok
url.to_s.should == '../g'
# http://a/b/c/d;p?q
# ./g/. = http://a/b/c/g/
url = @base_url.merge('./g/.')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g/'
url = @base_url.route_to('http://a/b/c/g/')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == './g/.' # ok
url.to_s.should == 'g/'
# http://a/b/c/d;p?q
# g/./h = http://a/b/c/g/h
url = @base_url.merge('g/./h')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g/h'
url = @base_url.route_to('http://a/b/c/g/h')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == 'g/./h' # ok
url.to_s.should == 'g/h'
# http://a/b/c/d;p?q
# g/../h = http://a/b/c/h
url = @base_url.merge('g/../h')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/h'
url = @base_url.route_to('http://a/b/c/h')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == 'g/../h' # ok
url.to_s.should == 'h'
# http://a/b/c/d;p?q
# g;x=1/./y = http://a/b/c/g;x=1/y
url = @base_url.merge('g;x=1/./y')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g;x=1/y'
url = @base_url.route_to('http://a/b/c/g;x=1/y')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == 'g;x=1/./y' # ok
url.to_s.should == 'g;x=1/y'
# http://a/b/c/d;p?q
# g;x=1/../y = http://a/b/c/y
url = @base_url.merge('g;x=1/../y')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/y'
url = @base_url.route_to('http://a/b/c/y')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should_not == 'g;x=1/../y' # ok
url.to_s.should == 'y'
# http://a/b/c/d;p?q
# g?y/./x = http://a/b/c/g?y/./x
url = @base_url.merge('g?y/./x')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g?y/./x'
url = @base_url.route_to('http://a/b/c/g?y/./x')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g?y/./x'
# http://a/b/c/d;p?q
# g?y/../x = http://a/b/c/g?y/../x
url = @base_url.merge('g?y/../x')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g?y/../x'
url = @base_url.route_to('http://a/b/c/g?y/../x')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g?y/../x'
# http://a/b/c/d;p?q
# g#s/./x = http://a/b/c/g#s/./x
url = @base_url.merge('g#s/./x')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g#s/./x'
url = @base_url.route_to('http://a/b/c/g#s/./x')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g#s/./x'
# http://a/b/c/d;p?q
# g#s/../x = http://a/b/c/g#s/../x
url = @base_url.merge('g#s/../x')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http://a/b/c/g#s/../x'
url = @base_url.route_to('http://a/b/c/g#s/../x')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'g#s/../x'
# http://a/b/c/d;p?q
# http:g = http:g ; for validating parsers
# | http://a/b/c/g ; for backwards compatibility
url = @base_url.merge('http:g')
- url.should be_kind_of(URI::HTTP)
+ url.should.is_a?(URI::HTTP)
url.to_s.should == 'http:g'
url = @base_url.route_to('http:g')
- url.should be_kind_of(URI::Generic)
+ url.should.is_a?(URI::Generic)
url.to_s.should == 'http:g'
end
end
diff --git a/spec/ruby/library/uri/select_spec.rb b/spec/ruby/library/uri/select_spec.rb
index 839b68b3a1..27591f69f2 100644
--- a/spec/ruby/library/uri/select_spec.rb
+++ b/spec/ruby/library/uri/select_spec.rb
@@ -15,13 +15,13 @@ describe "URI#select" do
end
it "raises an ArgumentError if a component is requested that isn't valid under the given scheme" do
- -> { URI("mailto:spam@mailinator.com").select(:path) }.should raise_error(ArgumentError)
- -> { URI("http://blog.blag.web").select(:typecode) }.should raise_error(ArgumentError)
+ -> { URI("mailto:spam@mailinator.com").select(:path) }.should.raise(ArgumentError)
+ -> { URI("http://blog.blag.web").select(:typecode) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if given strings rather than symbols" do
-> {
URI("http://host:8080/path/").select("scheme","host","port",'path')
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/library/uri/set_component_spec.rb b/spec/ruby/library/uri/set_component_spec.rb
index 642a5d6fcf..15f1ed1f87 100644
--- a/spec/ruby/library/uri/set_component_spec.rb
+++ b/spec/ruby/library/uri/set_component_spec.rb
@@ -6,40 +6,42 @@ describe "URI#select" do
it "conforms to the MatzRuby tests" do
uri = URI.parse('http://foo:bar@baz')
(uri.user = 'oof').should == 'oof'
- uri.to_s.should == 'http://oof:bar@baz'
- (uri.password = 'rab').should == 'rab'
- uri.to_s.should == 'http://oof:rab@baz'
- (uri.userinfo = 'foo').should == 'foo'
- uri.to_s.should == 'http://foo:rab@baz'
- (uri.userinfo = ['foo', 'bar']).should == ['foo', 'bar']
- uri.to_s.should == 'http://foo:bar@baz'
- (uri.userinfo = ['foo']).should == ['foo']
- uri.to_s.should == 'http://foo:bar@baz'
- (uri.host = 'zab').should == 'zab'
- uri.to_s.should == 'http://foo:bar@zab'
- (uri.port = 8080).should == 8080
- uri.to_s.should == 'http://foo:bar@zab:8080'
- (uri.path = '/').should == '/'
- uri.to_s.should == 'http://foo:bar@zab:8080/'
- (uri.query = 'a=1').should == 'a=1'
- uri.to_s.should == 'http://foo:bar@zab:8080/?a=1'
- (uri.fragment = 'b123').should == 'b123'
- uri.to_s.should == 'http://foo:bar@zab:8080/?a=1#b123'
+ version_is(URI::VERSION, "1.0.4") do
+ uri.to_s.should == 'http://oof@baz'
+ (uri.password = 'rab').should == 'rab'
+ uri.to_s.should == 'http://oof:rab@baz'
+ (uri.userinfo = 'foo').should == 'foo'
+ uri.to_s.should == 'http://foo@baz'
+ (uri.userinfo = ['foo', 'bar']).should == ['foo', 'bar']
+ uri.to_s.should == 'http://foo:bar@baz'
+ (uri.userinfo = ['foo']).should == ['foo']
+ uri.to_s.should == 'http://foo@baz'
+ (uri.host = 'zab').should == 'zab'
+ uri.to_s.should == 'http://zab'
+ (uri.port = 8080).should == 8080
+ uri.to_s.should == 'http://zab:8080'
+ (uri.path = '/').should == '/'
+ uri.to_s.should == 'http://zab:8080/'
+ (uri.query = 'a=1').should == 'a=1'
+ uri.to_s.should == 'http://zab:8080/?a=1'
+ (uri.fragment = 'b123').should == 'b123'
+ uri.to_s.should == 'http://zab:8080/?a=1#b123'
+ end
uri = URI.parse('http://example.com')
- -> { uri.password = 'bar' }.should raise_error(URI::InvalidURIError)
+ -> { uri.password = 'bar' }.should.raise(URI::InvalidURIError)
uri.userinfo = 'foo:bar'
uri.to_s.should == 'http://foo:bar@example.com'
- -> { uri.registry = 'bar' }.should raise_error(URI::InvalidURIError)
- -> { uri.opaque = 'bar' }.should raise_error(URI::InvalidURIError)
+ -> { uri.registry = 'bar' }.should.raise(URI::InvalidURIError)
+ -> { uri.opaque = 'bar' }.should.raise(URI::InvalidURIError)
uri = URI.parse('mailto:foo@example.com')
- -> { uri.user = 'bar' }.should raise_error(URI::InvalidURIError)
- -> { uri.password = 'bar' }.should raise_error(URI::InvalidURIError)
- -> { uri.userinfo = ['bar', 'baz'] }.should raise_error(URI::InvalidURIError)
- -> { uri.host = 'bar' }.should raise_error(URI::InvalidURIError)
- -> { uri.port = 'bar' }.should raise_error(URI::InvalidURIError)
- -> { uri.path = 'bar' }.should raise_error(URI::InvalidURIError)
- -> { uri.query = 'bar' }.should raise_error(URI::InvalidURIError)
+ -> { uri.user = 'bar' }.should.raise(URI::InvalidURIError)
+ -> { uri.password = 'bar' }.should.raise(URI::InvalidURIError)
+ -> { uri.userinfo = ['bar', 'baz'] }.should.raise(URI::InvalidURIError)
+ -> { uri.host = 'bar' }.should.raise(URI::InvalidURIError)
+ -> { uri.port = 'bar' }.should.raise(URI::InvalidURIError)
+ -> { uri.path = 'bar' }.should.raise(URI::InvalidURIError)
+ -> { uri.query = 'bar' }.should.raise(URI::InvalidURIError)
end
end
diff --git a/spec/ruby/library/uri/shared/eql.rb b/spec/ruby/library/uri/shared/eql.rb
index 2cc960d39a..978c4aae05 100644
--- a/spec/ruby/library/uri/shared/eql.rb
+++ b/spec/ruby/library/uri/shared/eql.rb
@@ -3,7 +3,7 @@ describe :uri_eql, shared: true do
URISpec::NORMALIZED_FORMS.each do |form|
normal_uri = URI(form[:normalized])
form[:different].each do |other|
- URI(other).send(@method, normal_uri).should be_false
+ URI(other).send(@method, normal_uri).should == false
end
end
end
@@ -11,7 +11,7 @@ end
describe :uri_eql_against_other_types, shared: true do
it "returns false for when compared to non-uri objects" do
- URI("http://example.com/").send(@method, "http://example.com/").should be_false
- URI("http://example.com/").send(@method, nil).should be_false
+ URI("http://example.com/").send(@method, "http://example.com/").should == false
+ URI("http://example.com/").send(@method, nil).should == false
end
end
diff --git a/spec/ruby/library/uri/shared/join.rb b/spec/ruby/library/uri/shared/join.rb
index 4df0782b37..b1f5f1c72b 100644
--- a/spec/ruby/library/uri/shared/join.rb
+++ b/spec/ruby/library/uri/shared/join.rb
@@ -20,7 +20,7 @@ describe :uri_join, shared: true do
it "raises an error if given no argument" do
-> {
@object.join
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "doesn't create redundant '/'s" do
diff --git a/spec/ruby/library/uri/shared/parse.rb b/spec/ruby/library/uri/shared/parse.rb
index c5057b6c4b..7ec7179526 100644
--- a/spec/ruby/library/uri/shared/parse.rb
+++ b/spec/ruby/library/uri/shared/parse.rb
@@ -1,6 +1,6 @@
describe :uri_parse, shared: true do
it "returns a URI::HTTP object when parsing an HTTP URI" do
- @object.parse("http://www.example.com/").should be_kind_of(URI::HTTP)
+ @object.parse("http://www.example.com/").should.is_a?(URI::HTTP)
end
it "populates the components of a parsed URI::HTTP, setting the port to 80 by default" do
@@ -43,7 +43,7 @@ describe :uri_parse, shared: true do
end
it "returns a URI::HTTPS object when parsing an HTTPS URI" do
- @object.parse("https://important-intern-net.net").should be_kind_of(URI::HTTPS)
+ @object.parse("https://important-intern-net.net").should.is_a?(URI::HTTPS)
end
it "sets the port of a parsed https URI to 443 by default" do
@@ -53,7 +53,7 @@ describe :uri_parse, shared: true do
it "populates the components of a parsed URI::FTP object" do
# generic, empty password.
url = @object.parse("ftp://anonymous@ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.bz2;type=i")
- url.should be_kind_of(URI::FTP)
+ url.should.is_a?(URI::FTP)
URISpec.components(url).should == {
scheme: "ftp",
userinfo: "anonymous",
@@ -65,7 +65,7 @@ describe :uri_parse, shared: true do
# multidomain, no user or password
url = @object.parse('ftp://ftp.is.co.za/rfc/rfc1808.txt')
- url.should be_kind_of(URI::FTP)
+ url.should.is_a?(URI::FTP)
URISpec.components(url).should == {
scheme: "ftp",
userinfo: nil,
@@ -77,7 +77,7 @@ describe :uri_parse, shared: true do
# empty user
url = @object.parse('ftp://:pass@localhost/')
- url.should be_kind_of(URI::FTP)
+ url.should.is_a?(URI::FTP)
URISpec.components(url).should == {
scheme: "ftp",
userinfo: ":pass",
@@ -93,7 +93,7 @@ describe :uri_parse, shared: true do
#taken from http://www.faqs.org/rfcs/rfc2255.html 'cause I don't really know what an LDAP url looks like
ldap_uris = %w{ ldap:///o=University%20of%20Michigan,c=US ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen) ldap://ldap.itd.umich.edu/c=GB?objectClass?one ldap://ldap.question.com/o=Question%3f,c=US?mail ldap://ldap.netscape.com/o=Babsco,c=US??(int=%5c00%5c00%5c00%5c04) ldap:///??sub??bindname=cn=Manager%2co=Foo ldap:///??sub??!bindname=cn=Manager%2co=Foo }
ldap_uris.each do |ldap_uri|
- @object.parse(ldap_uri).should be_kind_of(URI::LDAP)
+ @object.parse(ldap_uri).should.is_a?(URI::LDAP)
end
end
@@ -111,7 +111,7 @@ describe :uri_parse, shared: true do
end
it "returns a URI::MailTo object when passed a mailto URI" do
- @object.parse("mailto:spam@mailinator.com").should be_kind_of(URI::MailTo)
+ @object.parse("mailto:spam@mailinator.com").should.is_a?(URI::MailTo)
end
it "populates the components of a parsed URI::MailTo object" do
@@ -141,7 +141,7 @@ describe :uri_parse, shared: true do
# gopher
gopher = @object.parse('gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles')
- gopher.should be_kind_of(URI::Generic)
+ gopher.should.is_a?(URI::Generic)
URISpec.components(gopher).should == {
scheme: "gopher",
@@ -157,7 +157,7 @@ describe :uri_parse, shared: true do
# news
news = @object.parse('news:comp.infosystems.www.servers.unix')
- news.should be_kind_of(URI::Generic)
+ news.should.is_a?(URI::Generic)
URISpec.components(news).should == {
scheme: "news",
userinfo: nil,
@@ -172,7 +172,7 @@ describe :uri_parse, shared: true do
# telnet
telnet = @object.parse('telnet://melvyl.ucop.edu/')
- telnet.should be_kind_of(URI::Generic)
+ telnet.should.is_a?(URI::Generic)
URISpec.components(telnet).should == {
scheme: "telnet",
userinfo: nil,
@@ -187,20 +187,20 @@ describe :uri_parse, shared: true do
# files
file_l = @object.parse('file:///foo/bar.txt')
- file_l.should be_kind_of(URI::Generic)
+ file_l.should.is_a?(URI::Generic)
file = @object.parse('file:/foo/bar.txt')
- file.should be_kind_of(URI::Generic)
+ file.should.is_a?(URI::Generic)
end
if URI::DEFAULT_PARSER == URI::RFC2396_Parser
it "raises errors on malformed URIs" do
- -> { @object.parse('http://a_b:80/') }.should raise_error(URI::InvalidURIError)
- -> { @object.parse('http://a_b/') }.should raise_error(URI::InvalidURIError)
+ -> { @object.parse('http://a_b:80/') }.should.raise(URI::InvalidURIError)
+ -> { @object.parse('http://a_b/') }.should.raise(URI::InvalidURIError)
end
elsif URI::DEFAULT_PARSER == URI::RFC3986_Parser
it "does not raise errors on URIs contained underscore" do
- -> { @object.parse('http://a_b:80/') }.should_not raise_error(URI::InvalidURIError)
- -> { @object.parse('http://a_b/') }.should_not raise_error(URI::InvalidURIError)
+ -> { @object.parse('http://a_b:80/') }.should_not.raise(URI::InvalidURIError)
+ -> { @object.parse('http://a_b/') }.should_not.raise(URI::InvalidURIError)
end
end
end
diff --git a/spec/ruby/library/uri/uri_spec.rb b/spec/ruby/library/uri/uri_spec.rb
index 45a7502052..eab4e7176c 100644
--- a/spec/ruby/library/uri/uri_spec.rb
+++ b/spec/ruby/library/uri/uri_spec.rb
@@ -19,11 +19,11 @@ describe "the URI method" do
it "returns the argument if it is a URI object" do
result = URI.parse("http://ruby-lang.org")
- URI(result).should equal(result)
+ URI(result).should.equal?(result)
end
#apparently this was a concern? imported from MRI tests
it "does not add a URI method to Object instances" do
- -> {Object.new.URI("http://ruby-lang.org/")}.should raise_error(NoMethodError)
+ -> {Object.new.URI("http://ruby-lang.org/")}.should.raise(NoMethodError)
end
end
diff --git a/spec/ruby/library/weakref/__getobj___spec.rb b/spec/ruby/library/weakref/__getobj___spec.rb
index 79b06f5c96..fa507384c2 100644
--- a/spec/ruby/library/weakref/__getobj___spec.rb
+++ b/spec/ruby/library/weakref/__getobj___spec.rb
@@ -5,13 +5,13 @@ describe "WeakRef#__getobj__" do
it "returns the object if it is reachable" do
obj = Object.new
ref = WeakRef.new(obj)
- ref.__getobj__.should equal(obj)
+ ref.__getobj__.should.equal?(obj)
end
it "raises WeakRef::RefError if the object is no longer reachable" do
ref = WeakRefSpec.make_dead_weakref
-> {
ref.__getobj__
- }.should raise_error(WeakRef::RefError)
+ }.should.raise(WeakRef::RefError)
end
end
diff --git a/spec/ruby/library/weakref/allocate_spec.rb b/spec/ruby/library/weakref/allocate_spec.rb
index e734cfd23d..0438d093c4 100644
--- a/spec/ruby/library/weakref/allocate_spec.rb
+++ b/spec/ruby/library/weakref/allocate_spec.rb
@@ -3,6 +3,6 @@ require 'weakref'
describe "WeakRef#allocate" do
it "assigns nil as the reference" do
- -> { WeakRef.allocate.__getobj__ }.should raise_error(WeakRef::RefError)
+ -> { WeakRef.allocate.__getobj__ }.should.raise(WeakRef::RefError)
end
end
diff --git a/spec/ruby/library/weakref/send_spec.rb b/spec/ruby/library/weakref/send_spec.rb
index 9591657e01..da8660066f 100644
--- a/spec/ruby/library/weakref/send_spec.rb
+++ b/spec/ruby/library/weakref/send_spec.rb
@@ -27,11 +27,11 @@ describe "WeakRef#__send__" do
it "delegates to protected methods of the weakly-referenced object" do
wr = WeakRef.new(WeakRefSpecs)
- -> { wr.protected_method }.should raise_error(NameError)
+ -> { wr.protected_method }.should.raise(NameError)
end
it "does not delegate to private methods of the weakly-referenced object" do
wr = WeakRef.new(WeakRefSpecs)
- -> { wr.private_method }.should raise_error(NameError)
+ -> { wr.private_method }.should.raise(NameError)
end
end
diff --git a/spec/ruby/library/weakref/weakref_alive_spec.rb b/spec/ruby/library/weakref/weakref_alive_spec.rb
index 1ebf9c1ee3..1b12ffbbec 100644
--- a/spec/ruby/library/weakref/weakref_alive_spec.rb
+++ b/spec/ruby/library/weakref/weakref_alive_spec.rb
@@ -5,11 +5,11 @@ describe "WeakRef#weakref_alive?" do
it "returns true if the object is reachable" do
obj = Object.new
ref = WeakRef.new(obj)
- ref.weakref_alive?.should be_true
+ ref.weakref_alive?.should == true
end
it "returns a falsy value if the object is no longer reachable" do
ref = WeakRefSpec.make_dead_weakref
- [false, nil].should include(ref.weakref_alive?)
+ [false, nil].should.include?(ref.weakref_alive?)
end
end
diff --git a/spec/ruby/library/win32ole/fixtures/classes.rb b/spec/ruby/library/win32ole/fixtures/classes.rb
index f61cf6ba69..5a16fcca45 100644
--- a/spec/ruby/library/win32ole/fixtures/classes.rb
+++ b/spec/ruby/library/win32ole/fixtures/classes.rb
@@ -1,14 +1,25 @@
require 'win32ole'
+# win32ole deprecated constants like WIN32OLE_TYPELIB in Ruby 3.4
+# but only added the replacements like WIN32OLE::TypeLib in Ruby 3.4.
+# So we use the new-style constants in specs to avoid deprecation warnings
+# and we define the new-style constants as the old ones if they don't exist yet.
+WIN32OLE::TypeLib ||= WIN32OLE_TYPELIB
+WIN32OLE::RuntimeError ||= WIN32OLERuntimeError
+WIN32OLE::Method ||= WIN32OLE_METHOD
+WIN32OLE::Type ||= WIN32OLE_TYPE
+WIN32OLE::Event ||= WIN32OLE_EVENT
+WIN32OLE::Param ||= WIN32OLE_PARAM
+
module WIN32OLESpecs
- MSXML_AVAILABLE = WIN32OLE_TYPELIB.typelibs.any? { |t| t.name.start_with?('Microsoft XML') }
- SYSTEM_MONITOR_CONTROL_AVAILABLE = WIN32OLE_TYPELIB.typelibs.any? { |t| t.name.start_with?('System Monitor Control') }
+ MSXML_AVAILABLE = WIN32OLE::TypeLib.typelibs.any? { |t| t.name.start_with?('Microsoft XML') }
+ SYSTEM_MONITOR_CONTROL_AVAILABLE = WIN32OLE::TypeLib.typelibs.any? { |t| t.name.start_with?('System Monitor Control') }
def self.new_ole(name)
tries = 0
begin
WIN32OLE.new(name)
- rescue WIN32OLERuntimeError => e
+ rescue WIN32OLE::RuntimeError => e
if tries < 3
tries += 1
$stderr.puts "WIN32OLESpecs#new_ole retry (#{tries}): #{e.class}: #{e.message}"
diff --git a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
index 994c2e6d36..747121aeba 100644
--- a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
@@ -8,9 +8,9 @@ platform_is :windows do
end
it "raises ArgumentError if insufficient number of arguments are given" do
- -> { @shell._invoke() }.should raise_error ArgumentError
- -> { @shell._invoke(0) }.should raise_error ArgumentError
- -> { @shell._invoke(0, []) }.should raise_error ArgumentError
+ -> { @shell._invoke() }.should.raise ArgumentError
+ -> { @shell._invoke(0) }.should.raise ArgumentError
+ -> { @shell._invoke(0, []) }.should.raise ArgumentError
end
it "dispatches the method bound to a specific ID" do
diff --git a/spec/ruby/library/win32ole/win32ole/connect_spec.rb b/spec/ruby/library/win32ole/win32ole/connect_spec.rb
index ac0976ddc1..3a1caf85d3 100644
--- a/spec/ruby/library/win32ole/win32ole/connect_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/connect_spec.rb
@@ -5,11 +5,11 @@ platform_is :windows do
describe "WIN32OLE.connect" do
it "creates WIN32OLE object given valid argument" do
obj = WIN32OLE.connect("winmgmts:")
- obj.should be_kind_of WIN32OLE
+ obj.should.is_a? WIN32OLE
end
it "raises TypeError when given invalid argument" do
- -> { WIN32OLE.connect 1 }.should raise_error TypeError
+ -> { WIN32OLE.connect 1 }.should.raise TypeError
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
index 2099c4aa66..b0ba023536 100644
--- a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
@@ -8,9 +8,9 @@ platform_is :windows do
end
it "loads constant SsfWINDOWS into WIN32OLE namespace" do
- WIN32OLE.const_defined?(:SsfWINDOWS).should be_false
+ WIN32OLE.const_defined?(:SsfWINDOWS).should == false
WIN32OLE.const_load @win32ole
- WIN32OLE.const_defined?(:SsfWINDOWS).should be_true
+ WIN32OLE.const_defined?(:SsfWINDOWS).should == true
end
end
@@ -23,9 +23,9 @@ platform_is :windows do
it "loads constants into given namespace" do
module WIN32OLE_RUBYSPEC; end
- WIN32OLE_RUBYSPEC.const_defined?(:SsfWINDOWS).should be_false
+ WIN32OLE_RUBYSPEC.const_defined?(:SsfWINDOWS).should == false
WIN32OLE.const_load @win32ole, WIN32OLE_RUBYSPEC
- WIN32OLE_RUBYSPEC.const_defined?(:SsfWINDOWS).should be_true
+ WIN32OLE_RUBYSPEC.const_defined?(:SsfWINDOWS).should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/locale_spec.rb b/spec/ruby/library/win32ole/win32ole/locale_spec.rb
index 78ede4375a..390c41d1a2 100644
--- a/spec/ruby/library/win32ole/win32ole/locale_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/locale_spec.rb
@@ -13,14 +13,14 @@ platform_is :windows do
begin
begin
WIN32OLE.locale = 1041
- rescue WIN32OLERuntimeError
+ rescue WIN32OLE::RuntimeError
STDERR.puts("\n#{__FILE__}:#{__LINE__}:#{self.class.name}.test_s_locale_set is skipped(Japanese locale is not installed)")
return
end
WIN32OLE.locale.should == 1041
WIN32OLE.locale = WIN32OLE::LOCALE_SYSTEM_DEFAULT
- -> { WIN32OLE.locale = 111 }.should raise_error WIN32OLERuntimeError
+ -> { WIN32OLE.locale = 111 }.should.raise WIN32OLE::RuntimeError
WIN32OLE.locale.should == WIN32OLE::LOCALE_SYSTEM_DEFAULT
ensure
WIN32OLE.locale.should == WIN32OLE::LOCALE_SYSTEM_DEFAULT
diff --git a/spec/ruby/library/win32ole/win32ole/new_spec.rb b/spec/ruby/library/win32ole/win32ole/new_spec.rb
index 7e91c2d3ea..4f54c724d9 100644
--- a/spec/ruby/library/win32ole/win32ole/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/new_spec.rb
@@ -5,20 +5,20 @@ platform_is :windows do
describe "WIN32OLESpecs.new_ole" do
it "creates a WIN32OLE object from OLE server name" do
shell = WIN32OLESpecs.new_ole 'Shell.Application'
- shell.should be_kind_of WIN32OLE
+ shell.should.is_a? WIN32OLE
end
it "creates a WIN32OLE object from valid CLSID" do
shell = WIN32OLESpecs.new_ole("{13709620-C279-11CE-A49E-444553540000}")
- shell.should be_kind_of WIN32OLE
+ shell.should.is_a? WIN32OLE
end
it "raises TypeError if argument cannot be converted to String" do
- -> { WIN32OLESpecs.new_ole(42) }.should raise_error( TypeError )
+ -> { WIN32OLESpecs.new_ole(42) }.should.raise( TypeError )
end
- it "raises WIN32OLERuntimeError if invalid string is given" do
- -> { WIN32OLE.new('foo') }.should raise_error( WIN32OLERuntimeError )
+ it "raises WIN32OLE::RuntimeError if invalid string is given" do
+ -> { WIN32OLE.new('foo') }.should.raise( WIN32OLE::RuntimeError )
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
index 2bbe8c27d4..33e3e23b1b 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
@@ -8,15 +8,15 @@ platform_is :windows do
end
it "raises ArgumentError if argument is given" do
- -> { @dict.ole_func_methods(1) }.should raise_error ArgumentError
+ -> { @dict.ole_func_methods(1) }.should.raise ArgumentError
end
- it "returns an array of WIN32OLE_METHODs" do
- @dict.ole_func_methods.all? { |m| m.kind_of? WIN32OLE_METHOD }.should be_true
+ it "returns an array of WIN32OLE::Methods" do
+ @dict.ole_func_methods.all? { |m| m.kind_of? WIN32OLE::Method }.should == true
end
it "contains a 'AddRef' method for Scripting Dictionary" do
- @dict.ole_func_methods.map { |m| m.name }.include?('AddRef').should be_true
+ @dict.ole_func_methods.map { |m| m.name }.include?('AddRef').should == true
end
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
index c1d1970214..168a225d58 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
@@ -8,8 +8,8 @@ platform_is :windows do
@win32ole = WIN32OLESpecs.new_ole('Shell.Application')
end
- it "returns an array of WIN32OLE_METHOD objects" do
- @win32ole.ole_get_methods.all? {|m| m.kind_of? WIN32OLE_METHOD}.should be_true
+ it "returns an array of WIN32OLE::Method objects" do
+ @win32ole.ole_get_methods.all? {|m| m.kind_of? WIN32OLE::Method}.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
index fe161ce9f0..5152deeaf4 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
@@ -8,15 +8,15 @@ platform_is :windows do
end
it "raises ArgumentError if argument is given" do
- -> { @dict.ole_methods(1) }.should raise_error ArgumentError
+ -> { @dict.ole_methods(1) }.should.raise ArgumentError
end
- it "returns an array of WIN32OLE_METHODs" do
- @dict.ole_methods.all? { |m| m.kind_of? WIN32OLE_METHOD }.should be_true
+ it "returns an array of WIN32OLE::Methods" do
+ @dict.ole_methods.all? { |m| m.kind_of? WIN32OLE::Method }.should == true
end
it "contains a 'AddRef' method for Scripting Dictionary" do
- @dict.ole_methods.map { |m| m.name }.include?('AddRef').should be_true
+ @dict.ole_methods.map { |m| m.name }.include?('AddRef').should == true
end
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
index afcf16a051..1478804b55 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
@@ -9,11 +9,11 @@ platform_is :windows do
end
it "raises ArgumentError if argument is given" do
- -> { @dict.ole_obj_help(1) }.should raise_error ArgumentError
+ -> { @dict.ole_obj_help(1) }.should.raise ArgumentError
end
- it "returns an instance of WIN32OLE_TYPE" do
- @dict.ole_obj_help.kind_of?(WIN32OLE_TYPE).should be_true
+ it "returns an instance of WIN32OLE::Type" do
+ @dict.ole_obj_help.kind_of?(WIN32OLE::Type).should == true
end
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
index c091c83c95..b03a5d4b06 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
@@ -8,15 +8,15 @@ platform_is :windows do
end
it "raises ArgumentError if argument is given" do
- -> { @dict.ole_put_methods(1) }.should raise_error ArgumentError
+ -> { @dict.ole_put_methods(1) }.should.raise ArgumentError
end
- it "returns an array of WIN32OLE_METHODs" do
- @dict.ole_put_methods.all? { |m| m.kind_of? WIN32OLE_METHOD }.should be_true
+ it "returns an array of WIN32OLE::Methods" do
+ @dict.ole_put_methods.all? { |m| m.kind_of? WIN32OLE::Method }.should == true
end
it "contains a 'Key' method for Scripting Dictionary" do
- @dict.ole_put_methods.map { |m| m.name }.include?('Key').should be_true
+ @dict.ole_put_methods.map { |m| m.name }.include?('Key').should == true
end
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/shared/ole_method.rb b/spec/ruby/library/win32ole/win32ole/shared/ole_method.rb
index f1fd8713a4..9e4b7e7c20 100644
--- a/spec/ruby/library/win32ole/win32ole/shared/ole_method.rb
+++ b/spec/ruby/library/win32ole/win32ole/shared/ole_method.rb
@@ -7,12 +7,12 @@ platform_is :windows do
end
it "raises ArgumentError if no argument is given" do
- -> { @dict.send(@method) }.should raise_error ArgumentError
+ -> { @dict.send(@method) }.should.raise ArgumentError
end
- it "returns the WIN32OLE_METHOD 'Add' if given 'Add'" do
+ it "returns the WIN32OLE::Method 'Add' if given 'Add'" do
result = @dict.send(@method, "Add")
- result.kind_of?(WIN32OLE_METHOD).should be_true
+ result.kind_of?(WIN32OLE::Method).should == true
result.name.should == 'Add'
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/shared/setproperty.rb b/spec/ruby/library/win32ole/win32ole/shared/setproperty.rb
index b9267aef71..de3ad7b286 100644
--- a/spec/ruby/library/win32ole/win32ole/shared/setproperty.rb
+++ b/spec/ruby/library/win32ole/win32ole/shared/setproperty.rb
@@ -7,7 +7,7 @@ platform_is :windows do
end
it "raises ArgumentError if no argument is given" do
- -> { @dict.send(@method) }.should raise_error ArgumentError
+ -> { @dict.send(@method) }.should.raise ArgumentError
end
it "sets key to newkey and returns nil" do
diff --git a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
index 94fabb1e3b..d09c38b78d 100644
--- a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
@@ -3,7 +3,7 @@ platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::MSXML_AVAILABLE } do
- describe "WIN32OLE_EVENT.new" do
+ describe "WIN32OLE::Event.new" do
before :all do
@xml_dom = WIN32OLESpecs.new_ole('MSXML.DOMDocument')
end
@@ -13,21 +13,21 @@ platform_is :windows do
end
it "raises TypeError given invalid argument" do
- -> { WIN32OLE_EVENT.new "A" }.should raise_error TypeError
+ -> { WIN32OLE::Event.new "A" }.should.raise TypeError
end
it "raises RuntimeError if event does not exist" do
- -> { WIN32OLE_EVENT.new(@xml_dom, 'A') }.should raise_error RuntimeError
+ -> { WIN32OLE::Event.new(@xml_dom, 'A') }.should.raise RuntimeError
end
it "raises RuntimeError if OLE object has no events" do
dict = WIN32OLESpecs.new_ole('Scripting.Dictionary')
- -> { WIN32OLE_EVENT.new(dict) }.should raise_error RuntimeError
+ -> { WIN32OLE::Event.new(dict) }.should.raise RuntimeError
end
- it "creates WIN32OLE_EVENT object" do
- ev = WIN32OLE_EVENT.new(@xml_dom)
- ev.should be_kind_of WIN32OLE_EVENT
+ it "creates WIN32OLE::Event object" do
+ ev = WIN32OLE::Event.new(@xml_dom)
+ ev.should.is_a? WIN32OLE::Event
end
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
index 0957bdd2d4..acc7d2d6b6 100644
--- a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
@@ -15,7 +15,7 @@ platform_is :windows do
@event_spec_alt = "spec_alt"
end
- describe "WIN32OLE_EVENT#on_event" do
+ describe "WIN32OLE::Event#on_event" do
before :all do
@fn_xml = File.absolute_path "../fixtures/event.xml", __dir__
end
@@ -23,7 +23,7 @@ platform_is :windows do
before :each do
@xml_dom = WIN32OLESpecs.new_ole 'MSXML.DOMDocument'
@xml_dom.async = true
- @ev = WIN32OLE_EVENT.new @xml_dom
+ @ev = WIN32OLE::Event.new @xml_dom
@event_global = ''
@event_specific = ''
@event_spec_alt = ''
@@ -37,21 +37,21 @@ platform_is :windows do
it "sets global event handler properly, and the handler is invoked by event loop" do
@ev.on_event { |*args| handler_global(*args) }
@xml_dom.loadXML "<program><name>Ruby</name><version>trunk</version></program>"
- WIN32OLE_EVENT.message_loop
+ WIN32OLE::Event.message_loop
@event_global.should =~ /onreadystatechange/
end
it "accepts a String argument and the handler is invoked by event loop" do
@ev.on_event("onreadystatechange") { |*args| @event = 'foo' }
@xml_dom.loadXML "<program><name>Ruby</name><version>trunk</version></program>"
- WIN32OLE_EVENT.message_loop
+ WIN32OLE::Event.message_loop
@event.should =~ /foo/
end
it "accepts a Symbol argument and the handler is invoked by event loop" do
@ev.on_event(:onreadystatechange) { |*args| @event = 'bar' }
@xml_dom.loadXML "<program><name>Ruby</name><version>trunk</version></program>"
- WIN32OLE_EVENT.message_loop
+ WIN32OLE::Event.message_loop
@event.should =~ /bar/
end
@@ -60,7 +60,7 @@ platform_is :windows do
@ev.on_event("onreadystatechange") { |*args| handler_specific(*args) }
@ev.on_event("onreadystatechange") { |*args| handler_spec_alt(*args) }
@xml_dom.load @fn_xml
- WIN32OLE_EVENT.message_loop
+ WIN32OLE::Event.message_loop
@event_global.should == 'ondataavailable'
@event_global.should_not =~ /onreadystatechange/
@event_specific.should == ''
diff --git a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
index ece71df0d4..43084eb943 100644
--- a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#dispid" do
+ describe "WIN32OLE::Method#dispid" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m = WIN32OLE_METHOD.new(ole_type, "namespace")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m = WIN32OLE::Method.new(ole_type, "namespace")
end
it "raises ArgumentError if argument is given" do
- -> { @m.dispid(0) }.should raise_error ArgumentError
+ -> { @m.dispid(0) }.should.raise ArgumentError
end
it "returns expected dispatch ID for Shell's 'namespace' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
index 78634d2fde..1d00fb9696 100644
--- a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
@@ -3,16 +3,16 @@ platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do
- describe "WIN32OLE_METHOD#event_interface" do
+ describe "WIN32OLE::Method#event_interface" do
before :each do
- ole_type = WIN32OLE_TYPE.new("System Monitor Control", "SystemMonitor")
- @on_dbl_click_method = WIN32OLE_METHOD.new(ole_type, "OnDblClick")
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @namespace_method = WIN32OLE_METHOD.new(ole_type, "namespace")
+ ole_type = WIN32OLE::Type.new("System Monitor Control", "SystemMonitor")
+ @on_dbl_click_method = WIN32OLE::Method.new(ole_type, "OnDblClick")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @namespace_method = WIN32OLE::Method.new(ole_type, "namespace")
end
it "raises ArgumentError if argument is given" do
- -> { @on_dbl_click_method.event_interface(1) }.should raise_error ArgumentError
+ -> { @on_dbl_click_method.event_interface(1) }.should.raise ArgumentError
end
it "returns expected string for System Monitor Control's 'OnDblClick' method" do
@@ -20,7 +20,7 @@ platform_is :windows do
end
it "returns nil if method has no event interface" do
- @namespace_method.event_interface.should be_nil
+ @namespace_method.event_interface.should == nil
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
index 9b642a010c..fd611519cb 100644
--- a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
@@ -3,18 +3,18 @@ platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do
- describe "WIN32OLE_METHOD#event?" do
+ describe "WIN32OLE::Method#event?" do
before :each do
- ole_type = WIN32OLE_TYPE.new("System Monitor Control", "SystemMonitor")
- @on_dbl_click_method = WIN32OLE_METHOD.new(ole_type, "OnDblClick")
+ ole_type = WIN32OLE::Type.new("System Monitor Control", "SystemMonitor")
+ @on_dbl_click_method = WIN32OLE::Method.new(ole_type, "OnDblClick")
end
it "raises ArgumentError if argument is given" do
- -> { @on_dbl_click_method.event?(1) }.should raise_error ArgumentError
+ -> { @on_dbl_click_method.event?(1) }.should.raise ArgumentError
end
it "returns true for System Monitor Control's 'OnDblClick' method" do
- @on_dbl_click_method.event?.should be_true
+ @on_dbl_click_method.event?.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
index d1c5ee3be2..88164bcd1f 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
@@ -2,16 +2,16 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#helpcontext" do
+ describe "WIN32OLE::Method#helpcontext" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- @get_file_version = WIN32OLE_METHOD.new(ole_type, "GetFileVersion")
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ @get_file_version = WIN32OLE::Method.new(ole_type, "GetFileVersion")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @get_file_version.helpcontext(1) }.should raise_error ArgumentError
+ -> { @get_file_version.helpcontext(1) }.should.raise ArgumentError
end
it "returns expected value for FileSystemObject's 'GetFileVersion' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
index 59dad9244c..314f58c062 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#helpfile" do
+ describe "WIN32OLE::Method#helpfile" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.helpfile(1) }.should raise_error ArgumentError
+ -> { @m_file_name.helpfile(1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'File' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
index b2f24ba151..2a93acdb37 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#helpstring" do
+ describe "WIN32OLE::Method#helpstring" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.helpstring(1) }.should raise_error ArgumentError
+ -> { @m_file_name.helpstring(1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'File' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
index d7fedf0d36..16e5412a36 100644
--- a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#invkind" do
+ describe "WIN32OLE::Method#invkind" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.invkind(1) }.should raise_error ArgumentError
+ -> { @m_file_name.invkind(1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'name' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
index d5536fd17b..312860a9c5 100644
--- a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#invoke_kind" do
+ describe "WIN32OLE::Method#invoke_kind" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.invoke_kind(1) }.should raise_error ArgumentError
+ -> { @m_file_name.invoke_kind(1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'name' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
index 477b820f4d..6e2e233a62 100644
--- a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/name'
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#name" do
+ describe "WIN32OLE::Method#name" do
it_behaves_like :win32ole_method_name, :name
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
index 4e427421b9..d805d80128 100644
--- a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
@@ -2,31 +2,31 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD.new" do
+ describe "WIN32OLE::Method.new" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
it "raises TypeError when given non-strings" do
- -> { WIN32OLE_METHOD.new(1, 2) }.should raise_error TypeError
+ -> { WIN32OLE::Method.new(1, 2) }.should.raise TypeError
end
it "raises ArgumentError if only 1 argument is given" do
- -> { WIN32OLE_METHOD.new("hello") }.should raise_error ArgumentError
- -> { WIN32OLE_METHOD.new(@ole_type) }.should raise_error ArgumentError
+ -> { WIN32OLE::Method.new("hello") }.should.raise ArgumentError
+ -> { WIN32OLE::Method.new(@ole_type) }.should.raise ArgumentError
end
- it "returns a valid WIN32OLE_METHOD object" do
- WIN32OLE_METHOD.new(@ole_type, "Open").should be_kind_of WIN32OLE_METHOD
- WIN32OLE_METHOD.new(@ole_type, "open").should be_kind_of WIN32OLE_METHOD
+ it "returns a valid WIN32OLE::Method object" do
+ WIN32OLE::Method.new(@ole_type, "Open").should.is_a? WIN32OLE::Method
+ WIN32OLE::Method.new(@ole_type, "open").should.is_a? WIN32OLE::Method
end
- it "raises WIN32OLERuntimeError if the method does not exist" do
- -> { WIN32OLE_METHOD.new(@ole_type, "NonexistentMethod") }.should raise_error WIN32OLERuntimeError
+ it "raises WIN32OLE::RuntimeError if the method does not exist" do
+ -> { WIN32OLE::Method.new(@ole_type, "NonexistentMethod") }.should.raise WIN32OLE::RuntimeError
end
it "raises TypeError if second argument is not a String" do
- -> { WIN32OLE_METHOD.new(@ole_type, 5) }.should raise_error TypeError
+ -> { WIN32OLE::Method.new(@ole_type, 5) }.should.raise TypeError
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
index b3da9a8303..7c7e49ff3a 100644
--- a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#offset_vtbl" do
+ describe "WIN32OLE::Method#offset_vtbl" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.offset_vtbl(1) }.should raise_error ArgumentError
+ -> { @m_file_name.offset_vtbl(1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'name' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
index 09fb0eb5ac..40a543fa55 100644
--- a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
@@ -2,25 +2,25 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#params" do
+ describe "WIN32OLE::Method#params" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.params(1) }.should raise_error ArgumentError
+ -> { @m_file_name.params(1) }.should.raise ArgumentError
end
it "returns empty array for Scripting Runtime's 'name' method" do
- @m_file_name.params.should be_kind_of Array
- @m_file_name.params.should be_empty
+ @m_file_name.params.should.is_a? Array
+ @m_file_name.params.should.empty?
end
- it "returns 4-element array of WIN32OLE_PARAM for Shell's 'BrowseForFolder' method" do
- @m_browse_for_folder.params.all? { |p| p.kind_of? WIN32OLE_PARAM }.should be_true
+ it "returns 4-element array of WIN32OLE::Param for Shell's 'BrowseForFolder' method" do
+ @m_browse_for_folder.params.all? { |p| p.kind_of? WIN32OLE::Param }.should == true
@m_browse_for_folder.params.size == 4
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
index 582a5951d5..6d46c705c6 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
@@ -2,18 +2,18 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#return_type_detail" do
+ describe "WIN32OLE::Method#return_type_detail" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
end
it "raises ArgumentError if argument is given" do
- -> { @m_browse_for_folder.return_type_detail(1) }.should raise_error ArgumentError
+ -> { @m_browse_for_folder.return_type_detail(1) }.should.raise ArgumentError
end
it "returns expected value for Shell Control's 'BrowseForFolder' method" do
- @m_browse_for_folder.return_type_detail.should be_kind_of Array
+ @m_browse_for_folder.return_type_detail.should.is_a? Array
@m_browse_for_folder.return_type_detail.should == ['PTR', 'USERDEFINED', 'Folder']
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
index dd8add402d..5afaf202f2 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#return_type" do
+ describe "WIN32OLE::Method#return_type" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.return_type(1) }.should raise_error ArgumentError
+ -> { @m_file_name.return_type(1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'name' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
index 3fca3d54ed..882b5eaf43 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#return_vtype" do
+ describe "WIN32OLE::Method#return_vtype" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
end
it "raises ArgumentError if argument is given" do
- -> { @m_browse_for_folder.return_vtype(1) }.should raise_error ArgumentError
+ -> { @m_browse_for_folder.return_vtype(1) }.should.raise ArgumentError
end
it "returns expected value for Shell Control's 'BrowseForFolder' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/shared/name.rb b/spec/ruby/library/win32ole/win32ole_method/shared/name.rb
index ddaff4011b..ef63999836 100644
--- a/spec/ruby/library/win32ole/win32ole_method/shared/name.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/shared/name.rb
@@ -3,12 +3,12 @@ platform_is :windows do
describe :win32ole_method_name, shared: true do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "File")
- @m_file_name = WIN32OLE_METHOD.new(ole_type, "name")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "File")
+ @m_file_name = WIN32OLE::Method.new(ole_type, "name")
end
it "raises ArgumentError if argument is given" do
- -> { @m_file_name.send(@method, 1) }.should raise_error ArgumentError
+ -> { @m_file_name.send(@method, 1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'name' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
index fe9facb53a..e03a97c6c0 100644
--- a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#size_opt_params" do
+ describe "WIN32OLE::Method#size_opt_params" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
end
it "raises ArgumentError if argument is given" do
- -> { @m_browse_for_folder.size_opt_params(1) }.should raise_error ArgumentError
+ -> { @m_browse_for_folder.size_opt_params(1) }.should.raise ArgumentError
end
it "returns expected value for Shell Control's 'BrowseForFolder' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
index 8ea6e61e7d..f64f77af46 100644
--- a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
@@ -2,14 +2,14 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#size_params" do
+ describe "WIN32OLE::Method#size_params" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
end
it "raises ArgumentError if argument is given" do
- -> { @m_browse_for_folder.size_params(1) }.should raise_error ArgumentError
+ -> { @m_browse_for_folder.size_params(1) }.should.raise ArgumentError
end
it "returns expected value for Shell Control's 'BrowseForFolder' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
index 11107a77fc..cdcc4525b1 100644
--- a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/name'
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#name" do
+ describe "WIN32OLE::Method#name" do
it_behaves_like :win32ole_method_name, :to_s
end
diff --git a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
index d1a50523fc..a04ac6570b 100644
--- a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
@@ -2,18 +2,18 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_METHOD#visible?" do
+ describe "WIN32OLE::Method#visible?" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- @m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ @m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
end
it "raises ArgumentError if argument is given" do
- -> { @m_browse_for_folder.visible?(1) }.should raise_error ArgumentError
+ -> { @m_browse_for_folder.visible?(1) }.should.raise ArgumentError
end
it "returns true for Shell Control's 'BrowseForFolder' method" do
- @m_browse_for_folder.visible?.should be_true
+ @m_browse_for_folder.visible?.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
index 44bd3d7fd3..dded6833d4 100644
--- a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
@@ -2,24 +2,24 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#default" do
+ describe "WIN32OLE::Param#default" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- m_browse_for_folder = WIN32OLE_METHOD.new(ole_type, "BrowseForFolder")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ m_browse_for_folder = WIN32OLE::Method.new(ole_type, "BrowseForFolder")
@params = m_browse_for_folder.params
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type, "CopyFile")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @params[0].default(1) }.should raise_error ArgumentError
+ -> { @params[0].default(1) }.should.raise ArgumentError
end
- it "returns nil for each of WIN32OLE_PARAM for Shell's 'BrowseForFolder' method" do
+ it "returns nil for each of WIN32OLE::Param for Shell's 'BrowseForFolder' method" do
@params.each do |p|
- p.default.should be_nil
+ p.default.should == nil
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
index e9134b1df8..46dc305d2b 100644
--- a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
@@ -2,15 +2,15 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#input?" do
+ describe "WIN32OLE::Param#input?" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type, "CopyFile")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @param_overwritefiles.input?(1) }.should raise_error ArgumentError
+ -> { @param_overwritefiles.input?(1) }.should.raise ArgumentError
end
it "returns true for 3rd parameter of FileSystemObject's 'CopyFile' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
index 67a8955ba4..2c3474ffb3 100644
--- a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/name'
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#name" do
+ describe "WIN32OLE::Param#name" do
it_behaves_like :win32ole_param_name, :name
end
diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
index f05455e3f1..bd25ec325a 100644
--- a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
@@ -2,15 +2,15 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#ole_type_detail" do
+ describe "WIN32OLE::Param#ole_type_detail" do
before :each do
- ole_type_detail = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type_detail, "CopyFile")
+ ole_type_detail = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type_detail, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @param_overwritefiles.ole_type_detail(1) }.should raise_error ArgumentError
+ -> { @param_overwritefiles.ole_type_detail(1) }.should.raise ArgumentError
end
it "returns ['BOOL'] for 3rd parameter of FileSystemObject's 'CopyFile' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
index 1467130e03..3f0c279316 100644
--- a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
@@ -2,15 +2,15 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#ole_type" do
+ describe "WIN32OLE::Param#ole_type" do
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type, "CopyFile")
+ ole_type = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @param_overwritefiles.ole_type(1) }.should raise_error ArgumentError
+ -> { @param_overwritefiles.ole_type(1) }.should.raise ArgumentError
end
it "returns 'BOOL' for 3rd parameter of FileSystemObject's 'CopyFile' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
index b39ee41179..ca676e0950 100644
--- a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
@@ -2,19 +2,19 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#optional?" do
+ describe "WIN32OLE::Param#optional?" do
before :each do
- ole_type_detail = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type_detail, "CopyFile")
+ ole_type_detail = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type_detail, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @param_overwritefiles.optional?(1) }.should raise_error ArgumentError
+ -> { @param_overwritefiles.optional?(1) }.should.raise ArgumentError
end
it "returns true for 3rd parameter of FileSystemObject's 'CopyFile' method" do
- @param_overwritefiles.optional?.should be_true
+ @param_overwritefiles.optional?.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
index dd613dd29a..f25b1e7e14 100644
--- a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
@@ -2,19 +2,19 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#retval?" do
+ describe "WIN32OLE::Param#retval?" do
before :each do
- ole_type_detail = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type_detail, "CopyFile")
+ ole_type_detail = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type_detail, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @param_overwritefiles.retval?(1) }.should raise_error ArgumentError
+ -> { @param_overwritefiles.retval?(1) }.should.raise ArgumentError
end
it "returns false for 3rd parameter of FileSystemObject's 'CopyFile' method" do
- @param_overwritefiles.retval?.should be_false
+ @param_overwritefiles.retval?.should == false
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_param/shared/name.rb b/spec/ruby/library/win32ole/win32ole_param/shared/name.rb
index 043bc32856..1f6cbea7a0 100644
--- a/spec/ruby/library/win32ole/win32ole_param/shared/name.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/shared/name.rb
@@ -3,13 +3,13 @@ platform_is :windows do
describe :win32ole_param_name, shared: true do
before :each do
- ole_type_detail = WIN32OLE_TYPE.new("Microsoft Scripting Runtime", "FileSystemObject")
- m_copyfile = WIN32OLE_METHOD.new(ole_type_detail, "CopyFile")
+ ole_type_detail = WIN32OLE::Type.new("Microsoft Scripting Runtime", "FileSystemObject")
+ m_copyfile = WIN32OLE::Method.new(ole_type_detail, "CopyFile")
@param_overwritefiles = m_copyfile.params[2]
end
it "raises ArgumentError if argument is given" do
- -> { @param_overwritefiles.send(@method, 1) }.should raise_error ArgumentError
+ -> { @param_overwritefiles.send(@method, 1) }.should.raise ArgumentError
end
it "returns expected value for Scripting Runtime's 'name' method" do
diff --git a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
index e9153a2eb2..c59f426692 100644
--- a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/name'
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_PARAM#to_s" do
+ describe "WIN32OLE::Param#to_s" do
it_behaves_like :win32ole_param_name, :to_s
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
index abdf8d34b9..e574a945ad 100644
--- a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#guid for Shell Controls" do
+ describe "WIN32OLE::Type#guid for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
index eee23abc56..7b605a038b 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#helpcontext for Shell Controls" do
+ describe "WIN32OLE::Type#helpcontext for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns an Integer" do
- @ole_type.helpcontext.should be_kind_of Integer
+ @ole_type.helpcontext.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
index 3a0a9ead94..43a979882a 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#helpfile for Shell Controls" do
+ describe "WIN32OLE::Type#helpfile for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns an empty string" do
- @ole_type.helpfile.should be_empty
+ @ole_type.helpfile.should.empty?
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
index 9ab0004668..940475b25e 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#helpstring for Shell Controls" do
+ describe "WIN32OLE::Type#helpstring for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
diff --git a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
index 7d2731f778..66fdbc9ab0 100644
--- a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#major_version for Shell Controls" do
+ describe "WIN32OLE::Type#major_version for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns an Integer" do
- @ole_type.major_version.should be_kind_of Integer
+ @ole_type.major_version.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
index 3904e78d42..afb5086565 100644
--- a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#minor_version for Shell Controls" do
+ describe "WIN32OLE::Type#minor_version for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns an Integer" do
- @ole_type.minor_version.should be_kind_of Integer
+ @ole_type.minor_version.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
index d76998d7dc..4cc3426872 100644
--- a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/name'
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#name" do
+ describe "WIN32OLE::Type#name" do
it_behaves_like :win32ole_type_name, :name
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
index cc691ffa67..9d92177a4b 100644
--- a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
@@ -2,39 +2,39 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE.new" do
+ describe "WIN32OLE::Type.new" do
it "raises ArgumentError with no argument" do
- -> { WIN32OLE_TYPE.new }.should raise_error ArgumentError
+ -> { WIN32OLE::Type.new }.should.raise ArgumentError
end
it "raises ArgumentError with invalid string" do
- -> { WIN32OLE_TYPE.new("foo") }.should raise_error ArgumentError
+ -> { WIN32OLE::Type.new("foo") }.should.raise ArgumentError
end
it "raises TypeError if second argument is not a String" do
- -> { WIN32OLE_TYPE.new(1,2) }.should raise_error TypeError
+ -> { WIN32OLE::Type.new(1,2) }.should.raise TypeError
-> {
- WIN32OLE_TYPE.new('Microsoft Shell Controls And Automation',2)
- }.should raise_error TypeError
+ WIN32OLE::Type.new('Microsoft Shell Controls And Automation',2)
+ }.should.raise TypeError
end
- it "raise WIN32OLERuntimeError if OLE object specified is not found" do
+ it "raise WIN32OLE::RuntimeError if OLE object specified is not found" do
-> {
- WIN32OLE_TYPE.new('Microsoft Shell Controls And Automation','foo')
- }.should raise_error WIN32OLERuntimeError
+ WIN32OLE::Type.new('Microsoft Shell Controls And Automation','foo')
+ }.should.raise WIN32OLE::RuntimeError
-> {
- WIN32OLE_TYPE.new('Microsoft Shell Controls And Automation','Application')
- }.should raise_error WIN32OLERuntimeError
+ WIN32OLE::Type.new('Microsoft Shell Controls And Automation','Application')
+ }.should.raise WIN32OLE::RuntimeError
end
- it "creates WIN32OLE_TYPE object from name and valid type" do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
- ole_type.should be_kind_of WIN32OLE_TYPE
+ it "creates WIN32OLE::Type object from name and valid type" do
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
+ ole_type.should.is_a? WIN32OLE::Type
end
- it "creates WIN32OLE_TYPE object from CLSID and valid type" do
- ole_type2 = WIN32OLE_TYPE.new("{13709620-C279-11CE-A49E-444553540000}", "Shell")
- ole_type2.should be_kind_of WIN32OLE_TYPE
+ it "creates WIN32OLE::Type object from CLSID and valid type" do
+ ole_type2 = WIN32OLE::Type.new("{13709620-C279-11CE-A49E-444553540000}", "Shell")
+ ole_type2.should.is_a? WIN32OLE::Type
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
index a3a1d4ac58..7db08dc900 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE.ole_classes for Shell Controls" do
+ describe "WIN32OLE::Type.ole_classes for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns array of WIN32OLE_TYPEs" do
- WIN32OLE_TYPE.ole_classes("Microsoft Shell Controls And Automation").all? {|e| e.kind_of? WIN32OLE_TYPE }.should be_true
+ WIN32OLE::Type.ole_classes("Microsoft Shell Controls And Automation").all? {|e| e.kind_of? WIN32OLE::Type }.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
index 3b99b97a61..bdf668e53b 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#ole_methods for Shell Controls" do
+ describe "WIN32OLE::Type#ole_methods for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns an Integer" do
- @ole_type.ole_methods.all? { |m| m.kind_of? WIN32OLE_METHOD }.should be_true
+ @ole_type.ole_methods.all? { |m| m.kind_of? WIN32OLE::Method }.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
index 24292b1c4f..49c1902f8c 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#ole_type for Shell Controls" do
+ describe "WIN32OLE::Type#ole_type for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
diff --git a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
index 340fdb34e8..9a700426d9 100644
--- a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#progid for Shell Controls" do
+ describe "WIN32OLE::Type#progid for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
diff --git a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
index 793535b48d..cbb9247da1 100644
--- a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
@@ -2,13 +2,13 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE.progids" do
+ describe "WIN32OLE::Type.progids" do
it "raises ArgumentError if an argument is given" do
- -> { WIN32OLE_TYPE.progids(1) }.should raise_error ArgumentError
+ -> { WIN32OLE::Type.progids(1) }.should.raise ArgumentError
end
it "returns an array containing 'Shell.Explorer'" do
- WIN32OLE_TYPE.progids().include?('Shell.Explorer').should be_true
+ WIN32OLE::Type.progids().include?('Shell.Explorer').should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/shared/name.rb b/spec/ruby/library/win32ole/win32ole_type/shared/name.rb
index 6f37446b23..707149a5bb 100644
--- a/spec/ruby/library/win32ole/win32ole_type/shared/name.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/shared/name.rb
@@ -3,11 +3,11 @@ platform_is :windows do
describe :win32ole_type_name, shared: true do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
end
it "raises ArgumentError if argument is given" do
- -> { @ole_type.send(@method, 1) }.should raise_error ArgumentError
+ -> { @ole_type.send(@method, 1) }.should.raise ArgumentError
end
it "returns a String" do
diff --git a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
index 3f89fe702a..9f0893b750 100644
--- a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#src_type for Shell Controls" do
+ describe "WIN32OLE::Type#src_type for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns nil" do
- @ole_type.src_type.should be_nil
+ @ole_type.src_type.should == nil
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
index 9f086a5a35..03a0344fdb 100644
--- a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
@@ -4,7 +4,7 @@ require_relative 'shared/name'
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#to_s" do
+ describe "WIN32OLE::Type#to_s" do
it_behaves_like :win32ole_type_name, :to_s
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
index 391d505e01..1051627025 100644
--- a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#typekind for Shell Controls" do
+ describe "WIN32OLE::Type#typekind for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns an Integer" do
- @ole_type.typekind.should be_kind_of Integer
+ @ole_type.typekind.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
index a487208caa..36400d75f2 100644
--- a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE.typelibs for Shell Controls" do
+ describe "WIN32OLE::Type.typelibs for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,11 +12,11 @@ platform_is :windows do
end
it "raises ArgumentError if any argument is give" do
- -> { WIN32OLE_TYPE.typelibs(1) }.should raise_error ArgumentError
+ -> { WIN32OLE::Type.typelibs(1) }.should.raise ArgumentError
end
it "returns array of type libraries" do
- WIN32OLE_TYPE.typelibs().include?("Microsoft Shell Controls And Automation").should be_true
+ WIN32OLE::Type.typelibs().include?("Microsoft Shell Controls And Automation").should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
index 7f61b8af95..b1a407523c 100644
--- a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#variables for Shell Controls" do
+ describe "WIN32OLE::Type#variables for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
diff --git a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
index 99e34edcdd..bca9159d53 100644
--- a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
@@ -2,9 +2,9 @@ require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
- describe "WIN32OLE_TYPE#visible? for Shell Controls" do
+ describe "WIN32OLE::Type#visible? for Shell Controls" do
before :each do
- @ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "Shell")
+ @ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "Shell")
end
after :each do
@@ -12,7 +12,7 @@ platform_is :windows do
end
it "returns true" do
- @ole_type.visible?.should be_true
+ @ole_type.visible?.should == true
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
index 7a9c791494..a9232d2b28 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
@@ -6,13 +6,13 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns a nonempty Array" do
- @var.ole_type_detail.should be_kind_of Array
- @var.ole_type_detail.should_not be_empty
+ @var.ole_type_detail.should.is_a? Array
+ @var.ole_type_detail.should_not.empty?
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
index 03a9aa4c74..f28cbfd37a 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
@@ -6,12 +6,12 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns a String" do
- @var.ole_type.should be_kind_of String
+ @var.ole_type.should.is_a? String
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/shared/name.rb b/spec/ruby/library/win32ole/win32ole_variable/shared/name.rb
index 033e830fac..d079066616 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/shared/name.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/shared/name.rb
@@ -5,12 +5,12 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns a String" do
- @var.send(@method).should be_kind_of String
+ @var.send(@method).should.is_a? String
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
index b7849793c5..33066e40ef 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
@@ -6,13 +6,13 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns an Integer" do
# according to doc, this could return nil
- @var.value.should be_kind_of Integer
+ @var.value.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
index 7a79d32ddc..2cf1d7f1f2 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
@@ -6,12 +6,12 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns a String" do
- @var.variable_kind.should be_kind_of String
+ @var.variable_kind.should.is_a? String
@var.variable_kind.should == 'CONSTANT'
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
index 9d7b8238c8..04ccb8d46f 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
@@ -7,12 +7,12 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns an Integer" do
- @var.varkind.should be_kind_of Integer
+ @var.varkind.should.is_a? Integer
end
end
diff --git a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
index 60252e8139..939468122c 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
@@ -6,12 +6,12 @@ platform_is :windows do
# not sure how WIN32OLE_VARIABLE objects are supposed to be generated
# WIN32OLE_VARIABLE.new even seg faults in some cases
before :each do
- ole_type = WIN32OLE_TYPE.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
+ ole_type = WIN32OLE::Type.new("Microsoft Shell Controls And Automation", "ShellSpecialFolderConstants")
@var = ole_type.variables[0]
end
it "returns a String" do
- @var.visible?.should be_true
+ @var.visible?.should == true
end
end
diff --git a/spec/ruby/library/yaml/parse_file_spec.rb b/spec/ruby/library/yaml/parse_file_spec.rb
index 7bffcdc62f..a29377f163 100644
--- a/spec/ruby/library/yaml/parse_file_spec.rb
+++ b/spec/ruby/library/yaml/parse_file_spec.rb
@@ -5,6 +5,6 @@ require 'yaml'
describe "YAML.parse_file" do
it "returns a YAML::Syck::Map object after parsing a YAML file" do
test_parse_file = fixture __FILE__, "test_yaml.yml"
- YAML.parse_file(test_parse_file).should be_kind_of(Psych::Nodes::Document)
+ YAML.parse_file(test_parse_file).should.is_a?(Psych::Nodes::Document)
end
end
diff --git a/spec/ruby/library/yaml/parse_spec.rb b/spec/ruby/library/yaml/parse_spec.rb
index 37e2b7fa0a..832cd99d03 100644
--- a/spec/ruby/library/yaml/parse_spec.rb
+++ b/spec/ruby/library/yaml/parse_spec.rb
@@ -4,7 +4,7 @@ require 'yaml'
describe "YAML.parse with an empty string" do
it "returns false" do
- YAML.parse('').should be_false
+ YAML.parse('').should == false
end
end
diff --git a/spec/ruby/library/yaml/shared/load.rb b/spec/ruby/library/yaml/shared/load.rb
index b8bb605b0a..7e5669f2d0 100644
--- a/spec/ruby/library/yaml/shared/load.rb
+++ b/spec/ruby/library/yaml/shared/load.rb
@@ -60,7 +60,7 @@ describe :yaml_load_safe, shared: true do
else
error = ArgumentError
end
- -> { YAML.send(@method, "key1: value\ninvalid_key") }.should raise_error(error)
+ -> { YAML.send(@method, "key1: value\ninvalid_key") }.should.raise(error)
end
it "accepts symbols" do
@@ -117,7 +117,7 @@ describe :yaml_load_unsafe, shared: true do
].should be_computed_by(:usec)
end
- it "rounds values smaller than 1 usec to 0 " do
+ it "rounds values smaller than 1 usec to 0" do
YAML.send(@method, "2011-03-22t23:32:11.000000342222+01:00").usec.should == 0
end
end
@@ -137,6 +137,6 @@ describe :yaml_load_unsafe, shared: true do
loaded = YAML.send(@method, "--- !ruby/object:File {}\n")
-> {
loaded.read(1)
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
end
diff --git a/spec/ruby/library/yaml/to_yaml_spec.rb b/spec/ruby/library/yaml/to_yaml_spec.rb
index 08c5451416..328ab25552 100644
--- a/spec/ruby/library/yaml/to_yaml_spec.rb
+++ b/spec/ruby/library/yaml/to_yaml_spec.rb
@@ -32,25 +32,25 @@ describe "Object#to_yaml" do
it "returns the YAML representation of a FalseClass" do
false_klass = false
- false_klass.should be_kind_of(FalseClass)
+ false_klass.should.is_a?(FalseClass)
false_klass.to_yaml.should match_yaml("--- false\n")
end
it "returns the YAML representation of a Float object" do
float = 1.2
- float.should be_kind_of(Float)
+ float.should.is_a?(Float)
float.to_yaml.should match_yaml("--- 1.2\n")
end
it "returns the YAML representation of an Integer object" do
int = 20
- int.should be_kind_of(Integer)
+ int.should.is_a?(Integer)
int.to_yaml.should match_yaml("--- 20\n")
end
it "returns the YAML representation of a NilClass object" do
nil_klass = nil
- nil_klass.should be_kind_of(NilClass)
+ nil_klass.should.is_a?(NilClass)
nil_klass.to_yaml.should match_yaml("--- \n")
end
@@ -84,7 +84,7 @@ describe "Object#to_yaml" do
it "returns the YAML representation of a TrueClass" do
true_klass = true
- true_klass.should be_kind_of(TrueClass)
+ true_klass.should.is_a?(TrueClass)
true_klass.to_yaml.should match_yaml("--- true\n")
end
@@ -94,10 +94,10 @@ describe "Object#to_yaml" do
it "returns the YAML representation for Range objects" do
yaml = Range.new(1,3).to_yaml
- yaml.include?("!ruby/range").should be_true
- yaml.include?("begin: 1").should be_true
- yaml.include?("end: 3").should be_true
- yaml.include?("excl: false").should be_true
+ yaml.include?("!ruby/range").should == true
+ yaml.include?("begin: 1").should == true
+ yaml.include?("end: 3").should == true
+ yaml.include?("excl: false").should == true
end
it "returns the YAML representation of numeric constants" do
diff --git a/spec/ruby/library/zlib/adler32_spec.rb b/spec/ruby/library/zlib/adler32_spec.rb
index 226aa18522..887c22d059 100644
--- a/spec/ruby/library/zlib/adler32_spec.rb
+++ b/spec/ruby/library/zlib/adler32_spec.rb
@@ -19,7 +19,7 @@ describe "Zlib.adler32" do
Zlib.adler32(test_string, 1).should == 66391324
Zlib.adler32(test_string, 2**8).should == 701435419
Zlib.adler32(test_string, 2**16).should == 63966491
- -> { Zlib.adler32(test_string, 2**128) }.should raise_error(RangeError)
+ -> { Zlib.adler32(test_string, 2**128) }.should.raise(RangeError)
end
it "calculates the Adler checksum for string and initial Adler value for Integers" do
diff --git a/spec/ruby/library/zlib/crc32_spec.rb b/spec/ruby/library/zlib/crc32_spec.rb
index d5f5c199cc..b94b5c627c 100644
--- a/spec/ruby/library/zlib/crc32_spec.rb
+++ b/spec/ruby/library/zlib/crc32_spec.rb
@@ -26,7 +26,7 @@ describe "Zlib.crc32" do
Zlib.crc32(test_string, 2**16).should == 1932511220
Zlib.crc32("p", ~305419896).should == 4046865307
Zlib.crc32("p", -305419897).should == 4046865307
- -> { Zlib.crc32(test_string, 2**128) }.should raise_error(RangeError)
+ -> { Zlib.crc32(test_string, 2**128) }.should.raise(RangeError)
end
it "calculates the CRC checksum for string and initial CRC value for Integers" do
diff --git a/spec/ruby/library/zlib/gzipfile/close_spec.rb b/spec/ruby/library/zlib/gzipfile/close_spec.rb
index 964b5ffb4d..07bafac961 100644
--- a/spec/ruby/library/zlib/gzipfile/close_spec.rb
+++ b/spec/ruby/library/zlib/gzipfile/close_spec.rb
@@ -10,10 +10,8 @@ describe "Zlib::GzipFile#close" do
gzio.should.closed?
- -> { gzio.orig_name }.should \
- raise_error(Zlib::GzipFile::Error, 'closed gzip stream')
- -> { gzio.comment }.should \
- raise_error(Zlib::GzipFile::Error, 'closed gzip stream')
+ -> { gzio.orig_name }.should.raise(Zlib::GzipFile::Error, 'closed gzip stream')
+ -> { gzio.comment }.should.raise(Zlib::GzipFile::Error, 'closed gzip stream')
end
io.string[10..-1].should == ([3] + Array.new(9,0)).pack('C*')
diff --git a/spec/ruby/library/zlib/gzipfile/comment_spec.rb b/spec/ruby/library/zlib/gzipfile/comment_spec.rb
index 70d97ecaf6..845224df98 100644
--- a/spec/ruby/library/zlib/gzipfile/comment_spec.rb
+++ b/spec/ruby/library/zlib/gzipfile/comment_spec.rb
@@ -19,8 +19,7 @@ describe "Zlib::GzipFile#comment" do
Zlib::GzipWriter.wrap @io do |gzio|
gzio.close
- -> { gzio.comment }.should \
- raise_error(Zlib::GzipFile::Error, 'closed gzip stream')
+ -> { gzio.comment }.should.raise(Zlib::GzipFile::Error, 'closed gzip stream')
end
end
end
diff --git a/spec/ruby/library/zlib/gzipfile/orig_name_spec.rb b/spec/ruby/library/zlib/gzipfile/orig_name_spec.rb
index ebfd3692af..1da375390b 100644
--- a/spec/ruby/library/zlib/gzipfile/orig_name_spec.rb
+++ b/spec/ruby/library/zlib/gzipfile/orig_name_spec.rb
@@ -19,8 +19,7 @@ describe "Zlib::GzipFile#orig_name" do
Zlib::GzipWriter.wrap @io do |gzio|
gzio.close
- -> { gzio.orig_name }.should \
- raise_error(Zlib::GzipFile::Error, 'closed gzip stream')
+ -> { gzio.orig_name }.should.raise(Zlib::GzipFile::Error, 'closed gzip stream')
end
end
end
diff --git a/spec/ruby/library/zlib/gzipreader/eof_spec.rb b/spec/ruby/library/zlib/gzipreader/eof_spec.rb
index 673220fdfd..a38e144c72 100644
--- a/spec/ruby/library/zlib/gzipreader/eof_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/eof_spec.rb
@@ -12,31 +12,31 @@ describe "Zlib::GzipReader#eof?" do
it "returns true when at EOF" do
gz = Zlib::GzipReader.new @io
- gz.eof?.should be_false
+ gz.eof?.should == false
gz.read
- gz.eof?.should be_true
+ gz.eof?.should == true
end
it "returns true when at EOF with the exact length of uncompressed data" do
gz = Zlib::GzipReader.new @io
- gz.eof?.should be_false
+ gz.eof?.should == false
gz.read(10)
- gz.eof?.should be_true
+ gz.eof?.should == true
end
it "returns true when at EOF with a length greater than the size of uncompressed data" do
gz = Zlib::GzipReader.new @io
- gz.eof?.should be_false
+ gz.eof?.should == false
gz.read(11)
- gz.eof?.should be_true
+ gz.eof?.should == true
end
it "returns false when at EOF when there's data left in the buffer to read" do
gz = Zlib::GzipReader.new @io
gz.read(9)
- gz.eof?.should be_false
+ gz.eof?.should == false
gz.read
- gz.eof?.should be_true
+ gz.eof?.should == true
end
# This is especially important for JRuby, since eof? there
@@ -44,11 +44,11 @@ describe "Zlib::GzipReader#eof?" do
it "does not affect the reading data" do
gz = Zlib::GzipReader.new @io
0.upto(9) do |i|
- gz.eof?.should be_false
+ gz.eof?.should == false
gz.read(1).should == @data[i, 1]
end
- gz.eof?.should be_true
+ gz.eof?.should == true
gz.read.should == ""
- gz.eof?.should be_true
+ gz.eof?.should == true
end
end
diff --git a/spec/ruby/library/zlib/gzipreader/getc_spec.rb b/spec/ruby/library/zlib/gzipreader/getc_spec.rb
index e567231940..be13592189 100644
--- a/spec/ruby/library/zlib/gzipreader/getc_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/getc_spec.rb
@@ -33,7 +33,7 @@ describe "Zlib::GzipReader#getc" do
gz = Zlib::GzipReader.new @io
gz.read
pos = gz.pos
- gz.getc.should be_nil
+ gz.getc.should == nil
gz.pos.should == pos
end
end
diff --git a/spec/ruby/library/zlib/gzipreader/gets_spec.rb b/spec/ruby/library/zlib/gzipreader/gets_spec.rb
index d3a2e7d263..5d0809f833 100644
--- a/spec/ruby/library/zlib/gzipreader/gets_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/gets_spec.rb
@@ -16,7 +16,7 @@ describe 'Zlib::GzipReader#gets' do
gz.gets('').should == "123\n45\n\n"
gz.gets('').should == "abc\nde\n\n"
- gz.eof?.should be_true
+ gz.eof?.should == true
end
end
end
diff --git a/spec/ruby/library/zlib/gzipreader/read_spec.rb b/spec/ruby/library/zlib/gzipreader/read_spec.rb
index b81954b5ce..b07d433bdd 100644
--- a/spec/ruby/library/zlib/gzipreader/read_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/read_spec.rb
@@ -30,7 +30,7 @@ describe "Zlib::GzipReader#read" do
gz = Zlib::GzipReader.new @io
-> {
gz.read(-1)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "returns an empty string if a 0 length is given" do
@@ -59,8 +59,8 @@ describe "Zlib::GzipReader#read" do
it "returns nil if length parameter is positive" do
gz = Zlib::GzipReader.new @io
gz.read # read till the end
- gz.read(1).should be_nil
- gz.read(2**16).should be_nil
+ gz.read(1).should == nil
+ gz.read(2**16).should == nil
end
end
end
diff --git a/spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb b/spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb
index 7fa0608f9f..53870b9177 100644
--- a/spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/ungetbyte_spec.rb
@@ -94,7 +94,7 @@ describe "Zlib::GzipReader#ungetbyte" do
it 'makes eof? false' do
@gz.ungetbyte 0x21
- @gz.eof?.should be_false
+ @gz.eof?.should == false
end
end
@@ -112,7 +112,7 @@ describe "Zlib::GzipReader#ungetbyte" do
it 'does not make eof? false' do
@gz.ungetbyte nil
- @gz.eof?.should be_true
+ @gz.eof?.should == true
end
end
end
diff --git a/spec/ruby/library/zlib/gzipreader/ungetc_spec.rb b/spec/ruby/library/zlib/gzipreader/ungetc_spec.rb
index 34f2a1a2ca..46dcfde989 100644
--- a/spec/ruby/library/zlib/gzipreader/ungetc_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/ungetc_spec.rb
@@ -190,7 +190,7 @@ describe "Zlib::GzipReader#ungetc" do
it 'makes eof? false' do
@gz.ungetc 'x'
- @gz.eof?.should be_false
+ @gz.eof?.should == false
end
end
@@ -207,7 +207,7 @@ describe "Zlib::GzipReader#ungetc" do
it 'makes eof? false' do
@gz.ungetc 'ŷ'
- @gz.eof?.should be_false
+ @gz.eof?.should == false
end
end
@@ -224,7 +224,7 @@ describe "Zlib::GzipReader#ungetc" do
it 'makes eof? false' do
@gz.ungetc 'xŷž'
- @gz.eof?.should be_false
+ @gz.eof?.should == false
end
end
@@ -241,7 +241,7 @@ describe "Zlib::GzipReader#ungetc" do
it 'makes eof? false' do
@gz.ungetc 0x21
- @gz.eof?.should be_false
+ @gz.eof?.should == false
end
end
@@ -258,7 +258,7 @@ describe "Zlib::GzipReader#ungetc" do
it 'does not make eof? false' do
@gz.ungetc ''
- @gz.eof?.should be_true
+ @gz.eof?.should == true
end
end
@@ -276,7 +276,7 @@ describe "Zlib::GzipReader#ungetc" do
it 'does not make eof? false' do
@gz.ungetc nil
- @gz.eof?.should be_true
+ @gz.eof?.should == true
end
end
end
diff --git a/spec/ruby/library/zlib/gzipwriter/append_spec.rb b/spec/ruby/library/zlib/gzipwriter/append_spec.rb
index 6aa2824180..ef9e3d3a6b 100644
--- a/spec/ruby/library/zlib/gzipwriter/append_spec.rb
+++ b/spec/ruby/library/zlib/gzipwriter/append_spec.rb
@@ -9,7 +9,7 @@ describe "Zlib::GzipWriter#<<" do
it "returns self" do
Zlib::GzipWriter.wrap @io do |gzio|
- (gzio << "test").should equal(gzio)
+ (gzio << "test").should.equal?(gzio)
end
end
end
diff --git a/spec/ruby/library/zlib/gzipwriter/mtime_spec.rb b/spec/ruby/library/zlib/gzipwriter/mtime_spec.rb
index 621b602dc7..a70fa68069 100644
--- a/spec/ruby/library/zlib/gzipwriter/mtime_spec.rb
+++ b/spec/ruby/library/zlib/gzipwriter/mtime_spec.rb
@@ -31,8 +31,7 @@ describe "Zlib::GzipWriter#mtime=" do
Zlib::GzipWriter.wrap @io do |gzio|
gzio.write ''
- -> { gzio.mtime = nil }.should \
- raise_error(Zlib::GzipFile::Error, 'header is already written')
+ -> { gzio.mtime = nil }.should.raise(Zlib::GzipFile::Error, 'header is already written')
end
end
end
diff --git a/spec/ruby/library/zlib/inflate/append_spec.rb b/spec/ruby/library/zlib/inflate/append_spec.rb
index f121e66566..a4c791e31e 100644
--- a/spec/ruby/library/zlib/inflate/append_spec.rb
+++ b/spec/ruby/library/zlib/inflate/append_spec.rb
@@ -41,7 +41,7 @@ describe "Zlib::Inflate#<<" do
it "properly handles incomplete data" do
# add bytes, one by one
@foo_deflated[0, 5].each_byte { |d| @z << d.chr}
- -> { @z.finish }.should raise_error(Zlib::BufError)
+ -> { @z.finish }.should.raise(Zlib::BufError)
end
it "properly handles excessive data, byte-by-byte" do
diff --git a/spec/ruby/library/zlib/inflate/finish_spec.rb b/spec/ruby/library/zlib/inflate/finish_spec.rb
index 3e0663e265..b7494e419c 100644
--- a/spec/ruby/library/zlib/inflate/finish_spec.rb
+++ b/spec/ruby/library/zlib/inflate/finish_spec.rb
@@ -23,7 +23,7 @@ describe "Zlib::Inflate#finish" do
end
it "each chunk should have the same prefix" do
- @chunks.all? { |chunk| chunk =~ /\A0+\z/ }.should be_true
+ @chunks.all? { |chunk| chunk =~ /\A0+\z/ }.should == true
end
end
diff --git a/spec/ruby/library/zlib/inflate/inflate_spec.rb b/spec/ruby/library/zlib/inflate/inflate_spec.rb
index b308a4ba67..92e52363db 100644
--- a/spec/ruby/library/zlib/inflate/inflate_spec.rb
+++ b/spec/ruby/library/zlib/inflate/inflate_spec.rb
@@ -84,7 +84,7 @@ describe "Zlib::Inflate.inflate" do
# add bytes, one by one, but not all
result = +""
data.each_byte { |d| result << z.inflate(d.chr)}
- -> { result << z.finish }.should raise_error(Zlib::BufError)
+ -> { result << z.finish }.should.raise(Zlib::BufError)
end
it "properly handles excessive data, byte-by-byte" do
@@ -138,7 +138,7 @@ describe "Zlib::Inflate#inflate" do
end
it "properly handles chunked data" do
- @chunks.all? { |chunk| chunk =~ /\A0+\z/ }.should be_true
+ @chunks.all? { |chunk| chunk =~ /\A0+\z/ }.should == true
end
end
diff --git a/spec/ruby/library/zlib/inflate/set_dictionary_spec.rb b/spec/ruby/library/zlib/inflate/set_dictionary_spec.rb
index 251cec44bb..375ee3c765 100644
--- a/spec/ruby/library/zlib/inflate/set_dictionary_spec.rb
+++ b/spec/ruby/library/zlib/inflate/set_dictionary_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require 'zlib'
diff --git a/spec/ruby/library/zlib/zlib_version_spec.rb b/spec/ruby/library/zlib/zlib_version_spec.rb
index f83dfae66d..7edc76cdd5 100644
--- a/spec/ruby/library/zlib/zlib_version_spec.rb
+++ b/spec/ruby/library/zlib/zlib_version_spec.rb
@@ -3,6 +3,6 @@ require 'zlib'
describe "Zlib.zlib_version" do
it "returns the version of the libz library" do
- Zlib.zlib_version.should be_an_instance_of(String)
+ Zlib.zlib_version.should.instance_of?(String)
end
end
diff --git a/spec/ruby/optional/capi/array_spec.rb b/spec/ruby/optional/capi/array_spec.rb
index 9c35017e21..0b997f774c 100644
--- a/spec/ruby/optional/capi/array_spec.rb
+++ b/spec/ruby/optional/capi/array_spec.rb
@@ -8,7 +8,7 @@ describe :rb_ary_new2, shared: true do
end
it "raises an ArgumentError when the given argument is negative" do
- -> { @s.send(@method, -1) }.should raise_error(ArgumentError)
+ -> { @s.send(@method, -1) }.should.raise(ArgumentError)
end
end
@@ -84,7 +84,7 @@ describe "C-API Array function" do
end
it "raises a FrozenError if the array is frozen" do
- -> { @s.rb_ary_cat([].freeze, 1) }.should raise_error(FrozenError)
+ -> { @s.rb_ary_cat([].freeze, 1) }.should.raise(FrozenError)
end
end
@@ -120,7 +120,7 @@ describe "C-API Array function" do
it "returns the original array" do
a = [1,2,3]
- @s.rb_ary_reverse(a).should equal(a)
+ @s.rb_ary_reverse(a).should.equal?(a)
end
end
@@ -131,7 +131,7 @@ describe "C-API Array function" do
end
it "raises a FrozenError if the array is frozen" do
- -> { @s.rb_ary_rotate([].freeze, 1) }.should raise_error(FrozenError)
+ -> { @s.rb_ary_rotate([].freeze, 1) }.should.raise(FrozenError)
end
end
@@ -166,7 +166,7 @@ describe "C-API Array function" do
b = @s.rb_ary_dup(a)
b.should == a
- b.should_not equal(a)
+ b.should_not.equal?(a)
end
end
@@ -221,7 +221,7 @@ describe "C-API Array function" do
it "raises an IndexError if the negative index is greater than the length" do
a = [1, 2, 3]
- -> { @s.rb_ary_store(a, -10, 5) }.should raise_error(IndexError)
+ -> { @s.rb_ary_store(a, -10, 5) }.should.raise(IndexError)
end
it "enlarges the array as needed" do
@@ -232,7 +232,7 @@ describe "C-API Array function" do
it "raises a FrozenError if the array is frozen" do
a = [1, 2, 3].freeze
- -> { @s.rb_ary_store(a, 1, 5) }.should raise_error(FrozenError)
+ -> { @s.rb_ary_store(a, 1, 5) }.should.raise(FrozenError)
end
end
@@ -307,11 +307,11 @@ describe "C-API Array function" do
describe "rb_ary_includes" do
it "returns true if the array includes the element" do
- @s.rb_ary_includes([1, 2, 3], 2).should be_true
+ @s.rb_ary_includes([1, 2, 3], 2).should == true
end
it "returns false if the array does not include the element" do
- @s.rb_ary_includes([1, 2, 3], 4).should be_false
+ @s.rb_ary_includes([1, 2, 3], 4).should == false
end
end
@@ -322,7 +322,7 @@ describe "C-API Array function" do
end
it "returns nil for an out of range index" do
- @s.rb_ary_aref([1, 2, 3], 6).should be_nil
+ @s.rb_ary_aref([1, 2, 3], 6).should == nil
end
it "returns a new array where the first argument is the index and the second is the length" do
@@ -335,7 +335,7 @@ describe "C-API Array function" do
end
it "returns nil when the start of a range is out of bounds" do
- @s.rb_ary_aref([1, 2, 3, 4], 6..10).should be_nil
+ @s.rb_ary_aref([1, 2, 3, 4], 6..10).should == nil
end
it "returns an empty array when the start of a range equals the last element" do
@@ -343,37 +343,39 @@ describe "C-API Array function" do
end
end
- describe "rb_iterate" do
- it "calls an callback function as a block passed to an method" do
- s = [1,2,3,4]
- s2 = @s.rb_iterate(s)
+ ruby_version_is ""..."4.0" do
+ describe "rb_iterate" do
+ it "calls an callback function as a block passed to an method" do
+ s = [1,2,3,4]
+ s2 = @s.rb_iterate(s)
- s2.should == s
+ s2.should == s
- # Make sure they're different objects
- s2.equal?(s).should be_false
- end
+ # Make sure they're different objects
+ s2.equal?(s).should == false
+ end
- it "calls a function with the other function available as a block" do
- h = {a: 1, b: 2}
+ it "calls a function with the other function available as a block" do
+ h = {a: 1, b: 2}
- @s.rb_iterate_each_pair(h).sort.should == [1,2]
- end
+ @s.rb_iterate_each_pair(h).sort.should == [1,2]
+ end
- it "calls a function which can yield into the original block" do
- s2 = []
+ it "calls a function which can yield into the original block" do
+ s2 = []
- o = Object.new
- def o.each
- yield 1
- yield 2
- yield 3
- yield 4
- end
+ o = Object.new
+ def o.each
+ yield 1
+ yield 2
+ yield 3
+ yield 4
+ end
- @s.rb_iterate_then_yield(o) { |x| s2 << x }
+ @s.rb_iterate_then_yield(o) { |x| s2 << x }
- s2.should == [1,2,3,4]
+ s2.should == [1,2,3,4]
+ end
end
end
@@ -385,7 +387,7 @@ describe "C-API Array function" do
s2.should == s
# Make sure they're different objects
- s2.equal?(s).should be_false
+ s2.equal?(s).should == false
end
it "calls a function with the other function available as a block" do
@@ -420,7 +422,7 @@ describe "C-API Array function" do
it "returns nil if the element is not in the array" do
ary = [1, 2, 3, 4]
- @s.rb_ary_delete(ary, 5).should be_nil
+ @s.rb_ary_delete(ary, 5).should == nil
ary.should == [1, 2, 3, 4]
end
end
@@ -435,7 +437,7 @@ describe "C-API Array function" do
it "freezes the object exactly like Kernel#freeze" do
ary = [1,2]
@s.rb_ary_freeze(ary)
- ary.frozen?.should be_true
+ ary.frozen?.should == true
end
end
@@ -455,12 +457,12 @@ describe "C-API Array function" do
end
it "returns nil if the index is out of bounds" do
- @s.rb_ary_delete_at(@array, 4).should be_nil
+ @s.rb_ary_delete_at(@array, 4).should == nil
@array.should == [1, 2, 3, 4]
end
it "returns nil if the negative index is out of bounds" do
- @s.rb_ary_delete_at(@array, -5).should be_nil
+ @s.rb_ary_delete_at(@array, -5).should == nil
@array.should == [1, 2, 3, 4]
end
end
@@ -471,7 +473,7 @@ describe "C-API Array function" do
it "returns the given array" do
array = [1, 2, 3]
- @s.rb_ary_to_ary(array).should equal(array)
+ @s.rb_ary_to_ary(array).should.equal?(array)
end
end
@@ -517,7 +519,7 @@ describe "C-API Array function" do
end
it "returns nil if the begin index is out of bound" do
- @s.rb_ary_subseq([1, 2, 3, 4, 5], 6, 3).should be_nil
+ @s.rb_ary_subseq([1, 2, 3, 4, 5], 6, 3).should == nil
end
it "returns the existing subsequence of the length is out of bounds" do
@@ -525,7 +527,7 @@ describe "C-API Array function" do
end
it "returns nil if the size is negative" do
- @s.rb_ary_subseq([1, 2, 3, 4, 5], 1, -1).should be_nil
+ @s.rb_ary_subseq([1, 2, 3, 4, 5], 1, -1).should == nil
end
end
end
diff --git a/spec/ruby/optional/capi/bignum_spec.rb b/spec/ruby/optional/capi/bignum_spec.rb
index 179f053eec..ae7552b3f5 100644
--- a/spec/ruby/optional/capi/bignum_spec.rb
+++ b/spec/ruby/optional/capi/bignum_spec.rb
@@ -35,8 +35,8 @@ describe "CApiBignumSpecs" do
end
it "raises RangeError if passed Bignum overflow long" do
- -> { @s.rb_big2long(ensure_bignum(@max_long + 1)) }.should raise_error(RangeError)
- -> { @s.rb_big2long(ensure_bignum(@min_long - 1)) }.should raise_error(RangeError)
+ -> { @s.rb_big2long(ensure_bignum(@max_long + 1)) }.should.raise(RangeError)
+ -> { @s.rb_big2long(ensure_bignum(@min_long - 1)) }.should.raise(RangeError)
end
end
@@ -49,8 +49,8 @@ describe "CApiBignumSpecs" do
end
it "raises RangeError if passed Bignum overflow long" do
- -> { @s.rb_big2ll(ensure_bignum(@max_long << 40)) }.should raise_error(RangeError)
- -> { @s.rb_big2ll(ensure_bignum(@min_long << 40)) }.should raise_error(RangeError)
+ -> { @s.rb_big2ll(ensure_bignum(@max_long << 40)) }.should.raise(RangeError)
+ -> { @s.rb_big2ll(ensure_bignum(@min_long << 40)) }.should.raise(RangeError)
end
end
@@ -67,8 +67,8 @@ describe "CApiBignumSpecs" do
end
it "raises RangeError if passed Bignum overflow long" do
- -> { @s.rb_big2ulong(ensure_bignum(@max_ulong + 1)) }.should raise_error(RangeError)
- -> { @s.rb_big2ulong(ensure_bignum(@min_long - 1)) }.should raise_error(RangeError)
+ -> { @s.rb_big2ulong(ensure_bignum(@max_ulong + 1)) }.should.raise(RangeError)
+ -> { @s.rb_big2ulong(ensure_bignum(@min_long - 1)) }.should.raise(RangeError)
end
end
@@ -214,13 +214,13 @@ describe "CApiBignumSpecs" do
it "raises FloatDomainError for Infinity values" do
inf = 1.0 / 0
- -> { @s.rb_dbl2big(inf) }.should raise_error(FloatDomainError)
+ -> { @s.rb_dbl2big(inf) }.should.raise(FloatDomainError)
end
it "raises FloatDomainError for NaN values" do
nan = 0.0 / 0
- -> { @s.rb_dbl2big(nan) }.should raise_error(FloatDomainError)
+ -> { @s.rb_dbl2big(nan) }.should.raise(FloatDomainError)
end
end
end
diff --git a/spec/ruby/optional/capi/binding_spec.rb b/spec/ruby/optional/capi/binding_spec.rb
index 2165705457..1edd20b8f3 100644
--- a/spec/ruby/optional/capi/binding_spec.rb
+++ b/spec/ruby/optional/capi/binding_spec.rb
@@ -8,21 +8,9 @@ describe "CApiBindingSpecs" do
end
describe "Kernel#binding" do
- ruby_version_is '3.2' do
- it "raises when called from C" do
- foo = 14
- -> { @b.get_binding }.should raise_error(RuntimeError)
- end
- end
-
- ruby_version_is ''...'3.2' do
- it "gives the top-most Ruby binding when called from C" do
- foo = 14
- b = @b.get_binding
- b.local_variable_get(:foo).should == 14
- b.local_variable_set :foo, 12
- foo.should == 12
- end
+ it "raises when called from C" do
+ foo = 14
+ -> { @b.get_binding }.should.raise(RuntimeError)
end
end
end
diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb
index 21a887f047..07e9e42ad1 100644
--- a/spec/ruby/optional/capi/class_spec.rb
+++ b/spec/ruby/optional/capi/class_spec.rb
@@ -11,8 +11,8 @@ autoload :ClassIdUnderAutoload, "#{object_path}/class_id_under_autoload_spec"
describe :rb_path_to_class, shared: true do
it "returns a class or module from a scoped String" do
- @s.send(@method, "CApiClassSpecs::A::B").should equal(CApiClassSpecs::A::B)
- @s.send(@method, "CApiClassSpecs::A::M").should equal(CApiClassSpecs::A::M)
+ @s.send(@method, "CApiClassSpecs::A::B").should.equal?(CApiClassSpecs::A::B)
+ @s.send(@method, "CApiClassSpecs::A::M").should.equal?(CApiClassSpecs::A::M)
end
it "resolves autoload constants" do
@@ -20,21 +20,21 @@ describe :rb_path_to_class, shared: true do
end
it "raises an ArgumentError if a constant in the path does not exist" do
- -> { @s.send(@method, "CApiClassSpecs::NotDefined::B") }.should raise_error(ArgumentError)
+ -> { @s.send(@method, "CApiClassSpecs::NotDefined::B") }.should.raise(ArgumentError)
end
it "raises an ArgumentError if the final constant does not exist" do
- -> { @s.send(@method, "CApiClassSpecs::NotDefined") }.should raise_error(ArgumentError)
+ -> { @s.send(@method, "CApiClassSpecs::NotDefined") }.should.raise(ArgumentError)
end
it "raises a TypeError if the constant is not a class or module" do
-> {
@s.send(@method, "CApiClassSpecs::A::C")
- }.should raise_error(TypeError, 'CApiClassSpecs::A::C does not refer to class/module')
+ }.should.raise(TypeError, 'CApiClassSpecs::A::C does not refer to class/module')
end
it "raises an ArgumentError even if a constant in the path exists on toplevel" do
- -> { @s.send(@method, "CApiClassSpecs::Object") }.should raise_error(ArgumentError)
+ -> { @s.send(@method, "CApiClassSpecs::Object") }.should.raise(ArgumentError)
end
end
@@ -46,29 +46,31 @@ describe "C-API Class function" do
describe "rb_class_instance_methods" do
it "returns the public and protected methods of self and its ancestors" do
methods = @s.rb_class_instance_methods(ModuleSpecs::Basic)
- methods.should include(:protected_module, :public_module)
+ methods.should.include?(:protected_module)
+ methods.should.include?(:public_module)
methods = @s.rb_class_instance_methods(ModuleSpecs::Basic, true)
- methods.should include(:protected_module, :public_module)
+ methods.should.include?(:protected_module)
+ methods.should.include?(:public_module)
end
it "when passed false as a parameter, returns the instance methods of the class" do
methods = @s.rb_class_instance_methods(ModuleSpecs::Child, false)
- methods.should include(:protected_child, :public_child)
+ methods.to_set.should >= Set[:protected_child, :public_child]
end
end
describe "rb_class_public_instance_methods" do
it "returns a list of public methods in module and its ancestors" do
methods = @s.rb_class_public_instance_methods(ModuleSpecs::CountsChild)
- methods.should include(:public_3)
- methods.should include(:public_2)
- methods.should include(:public_1)
+ methods.should.include?(:public_3)
+ methods.should.include?(:public_2)
+ methods.should.include?(:public_1)
methods = @s.rb_class_public_instance_methods(ModuleSpecs::CountsChild, true)
- methods.should include(:public_3)
- methods.should include(:public_2)
- methods.should include(:public_1)
+ methods.should.include?(:public_3)
+ methods.should.include?(:public_2)
+ methods.should.include?(:public_1)
end
it "when passed false as a parameter, should return only methods defined in that module" do
@@ -79,14 +81,14 @@ describe "C-API Class function" do
describe "rb_class_protected_instance_methods" do
it "returns a list of protected methods in module and its ancestors" do
methods = @s.rb_class_protected_instance_methods(ModuleSpecs::CountsChild)
- methods.should include(:protected_3)
- methods.should include(:protected_2)
- methods.should include(:protected_1)
+ methods.should.include?(:protected_3)
+ methods.should.include?(:protected_2)
+ methods.should.include?(:protected_1)
methods = @s.rb_class_protected_instance_methods(ModuleSpecs::CountsChild, true)
- methods.should include(:protected_3)
- methods.should include(:protected_2)
- methods.should include(:protected_1)
+ methods.should.include?(:protected_3)
+ methods.should.include?(:protected_2)
+ methods.should.include?(:protected_1)
end
it "when passed false as a parameter, should return only methods defined in that module" do
@@ -110,7 +112,7 @@ describe "C-API Class function" do
it "allocates and initializes a new object" do
o = @s.rb_class_new_instance([], CApiClassSpecs::Alloc)
o.class.should == CApiClassSpecs::Alloc
- o.initialized.should be_true
+ o.initialized.should == true
end
it "passes arguments to the #initialize method" do
@@ -133,7 +135,7 @@ describe "C-API Class function" do
it "raises TypeError if the last argument is not a Hash" do
-> {
@s.rb_class_new_instance_kw([42], CApiClassSpecs::KeywordAlloc)
- }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ }.should.raise(TypeError, 'no implicit conversion of Integer into Hash')
end
end
@@ -141,9 +143,9 @@ describe "C-API Class function" do
it "includes a module into a class" do
c = Class.new
o = c.new
- -> { o.included? }.should raise_error(NameError)
+ -> { o.included? }.should.raise(NameError)
@s.rb_include_module(c, CApiClassSpecs::M)
- o.included?.should be_true
+ o.included?.should == true
end
end
@@ -155,12 +157,12 @@ describe "C-API Class function" do
it "defines an attr_reader when passed true, false" do
@s.rb_define_attr(CApiClassSpecs::Attr, :foo, true, false)
@a.foo.should == 1
- -> { @a.foo = 5 }.should raise_error(NameError)
+ -> { @a.foo = 5 }.should.raise(NameError)
end
it "defines an attr_writer when passed false, true" do
@s.rb_define_attr(CApiClassSpecs::Attr, :bar, false, true)
- -> { @a.bar }.should raise_error(NameError)
+ -> { @a.bar }.should.raise(NameError)
@a.bar = 5
@a.instance_variable_get(:@bar).should == 5
end
@@ -183,7 +185,7 @@ describe "C-API Class function" do
it "calls the method in the superclass with the correct self" do
@s.define_call_super_method CApiClassSpecs::SubSelf, "call_super_method"
obj = CApiClassSpecs::SubSelf.new
- obj.call_super_method.should equal obj
+ obj.call_super_method.should.equal? obj
end
it "calls the method in the superclass through two native levels" do
@@ -200,7 +202,7 @@ describe "C-API Class function" do
end
it "returns a string for an anonymous class" do
- @s.rb_class2name(Class.new).should be_kind_of(String)
+ @s.rb_class2name(Class.new).should.is_a?(String)
end
it "returns a string beginning with # for an anonymous class" do
@@ -224,7 +226,7 @@ describe "C-API Class function" do
end
it "returns a string for an anonymous class" do
- @s.rb_class_name(Class.new).should be_kind_of(String)
+ @s.rb_class_name(Class.new).should.is_a?(String)
end
end
@@ -238,22 +240,22 @@ describe "C-API Class function" do
describe "rb_cvar_defined" do
it "returns false when the class variable is not defined" do
- @s.rb_cvar_defined(CApiClassSpecs::CVars, "@@nocvar").should be_false
+ @s.rb_cvar_defined(CApiClassSpecs::CVars, "@@nocvar").should == false
end
it "returns true when the class variable is defined" do
- @s.rb_cvar_defined(CApiClassSpecs::CVars, "@@cvar").should be_true
+ @s.rb_cvar_defined(CApiClassSpecs::CVars, "@@cvar").should == true
end
it "returns true if the class instance variable is defined" do
- @s.rb_cvar_defined(CApiClassSpecs::CVars, "@c_ivar").should be_true
+ @s.rb_cvar_defined(CApiClassSpecs::CVars, "@c_ivar").should == true
end
end
describe "rb_cv_set" do
it "sets a class variable" do
o = CApiClassSpecs::CVars.new
- o.new_cv.should be_nil
+ o.new_cv.should == nil
@s.rb_cv_set(CApiClassSpecs::CVars, "@@new_cv", 1)
o.new_cv.should == 1
CApiClassSpecs::CVars.remove_class_variable :@@new_cv
@@ -268,14 +270,14 @@ describe "C-API Class function" do
it "raises a NameError if the class variable is not defined" do
-> {
@s.rb_cv_get(CApiClassSpecs::CVars, "@@no_cvar")
- }.should raise_error(NameError, /class variable @@no_cvar/)
+ }.should.raise(NameError, /class variable @@no_cvar/)
end
end
describe "rb_cvar_set" do
it "sets a class variable" do
o = CApiClassSpecs::CVars.new
- o.new_cvar.should be_nil
+ o.new_cvar.should == nil
@s.rb_cvar_set(CApiClassSpecs::CVars, "@@new_cvar", 1)
o.new_cvar.should == 1
CApiClassSpecs::CVars.remove_class_variable :@@new_cvar
@@ -289,8 +291,8 @@ describe "C-API Class function" do
end
it "creates a subclass of the superclass" do
- @cls.should be_kind_of(Class)
- ClassSpecDefineClass.should equal(@cls)
+ @cls.should.is_a?(Class)
+ ClassSpecDefineClass.should.equal?(@cls)
@cls.superclass.should == CApiClassSpecs::Super
end
@@ -307,19 +309,19 @@ describe "C-API Class function" do
it "raises a TypeError when given a non class object to superclass" do
-> {
@s.rb_define_class("ClassSpecDefineClass3", Module.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError when given a mismatched class to superclass" do
-> {
@s.rb_define_class("ClassSpecDefineClass", Object)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a ArgumentError when given NULL as superclass" do
-> {
@s.rb_define_class("ClassSpecDefineClass4", nil)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "allows arbitrary names, including constant names not valid in Ruby" do
@@ -328,7 +330,7 @@ describe "C-API Class function" do
-> {
Object.const_get(cls.name)
- }.should raise_error(NameError, /wrong constant name/)
+ }.should.raise(NameError, /wrong constant name/)
end
end
@@ -337,8 +339,8 @@ describe "C-API Class function" do
cls = @s.rb_define_class_under(CApiClassSpecs,
"ClassUnder1",
CApiClassSpecs::Super)
- cls.should be_kind_of(Class)
- CApiClassSpecs::Super.should be_ancestor_of(CApiClassSpecs::ClassUnder1)
+ cls.should.is_a?(Class)
+ CApiClassSpecs::ClassUnder1.ancestors.should.include?(CApiClassSpecs::Super)
end
it "sets the class name" do
@@ -356,7 +358,7 @@ describe "C-API Class function" do
-> { @s.rb_define_class_under(CApiClassSpecs,
"ClassUnder5",
Module.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
it "raises a TypeError when given a mismatched class to superclass" do
@@ -364,7 +366,7 @@ describe "C-API Class function" do
-> { @s.rb_define_class_under(CApiClassSpecs,
"ClassUnder6",
Class.new)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
ensure
CApiClassSpecs.send(:remove_const, :ClassUnder6)
end
@@ -374,7 +376,7 @@ describe "C-API Class function" do
end
it "raises a TypeError if class is defined and its superclass mismatches the given one" do
- -> { @s.rb_define_class_under(CApiClassSpecs, "Sub", Object) }.should raise_error(TypeError)
+ -> { @s.rb_define_class_under(CApiClassSpecs, "Sub", Object) }.should.raise(TypeError)
end
it "allows arbitrary names, including constant names not valid in Ruby" do
@@ -383,26 +385,15 @@ describe "C-API Class function" do
-> {
CApiClassSpecs.const_get(cls.name)
- }.should raise_error(NameError, /wrong constant name/)
- end
-
- ruby_version_is "3.5" do
- it "calls .inherited before .const_added" do
- ScratchPad.record([])
- @s.rb_define_class_id_under(CApiClassSpecs::Callbacks, :Subclass, CApiClassSpecs::Callbacks)
- ScratchPad.recorded.should == [
- [:inherited, "CApiClassSpecs::Callbacks::Subclass", :location],
- [:const_added, :Subclass, :location],
- ]
- end
+ }.should.raise(NameError, /wrong constant name/)
end
end
describe "rb_define_class_id_under" do
it "creates a subclass of the superclass contained in a module" do
cls = @s.rb_define_class_id_under(CApiClassSpecs, :ClassIdUnder1, CApiClassSpecs::Super)
- cls.should be_kind_of(Class)
- CApiClassSpecs::Super.should be_ancestor_of(CApiClassSpecs::ClassIdUnder1)
+ cls.should.is_a?(Class)
+ CApiClassSpecs::ClassIdUnder1.ancestors.should.include?(CApiClassSpecs::Super)
end
it "sets the class name" do
@@ -421,7 +412,7 @@ describe "C-API Class function" do
end
it "raises a TypeError if class is defined and its superclass mismatches the given one" do
- -> { @s.rb_define_class_id_under(CApiClassSpecs, :Sub, Object) }.should raise_error(TypeError)
+ -> { @s.rb_define_class_id_under(CApiClassSpecs, :Sub, Object) }.should.raise(TypeError)
end
it "allows arbitrary names, including constant names not valid in Ruby" do
@@ -430,14 +421,14 @@ describe "C-API Class function" do
-> {
CApiClassSpecs.const_get(cls.name)
- }.should raise_error(NameError, /wrong constant name/)
+ }.should.raise(NameError, /wrong constant name/)
end
end
describe "rb_define_class_variable" do
it "sets a class variable" do
o = CApiClassSpecs::CVars.new
- o.rbdcv_cvar.should be_nil
+ o.rbdcv_cvar.should == nil
@s.rb_define_class_variable(CApiClassSpecs::CVars, "@@rbdcv_cvar", 1)
o.rbdcv_cvar.should == 1
CApiClassSpecs::CVars.remove_class_variable :@@rbdcv_cvar
@@ -452,23 +443,23 @@ describe "C-API Class function" do
it "raises a NameError if the class variable is not defined" do
-> {
@s.rb_cvar_get(CApiClassSpecs::CVars, "@@no_cvar")
- }.should raise_error(NameError, /class variable @@no_cvar/)
+ }.should.raise(NameError, /class variable @@no_cvar/)
end
end
describe "rb_class_new" do
it "returns a new subclass of the superclass" do
subclass = @s.rb_class_new(CApiClassSpecs::NewClass)
- CApiClassSpecs::NewClass.should be_ancestor_of(subclass)
+ subclass.ancestors.should.include?(CApiClassSpecs::NewClass)
end
it "raises a TypeError if passed Class as the superclass" do
- -> { @s.rb_class_new(Class) }.should raise_error(TypeError)
+ -> { @s.rb_class_new(Class) }.should.raise(TypeError)
end
it "raises a TypeError if passed a singleton class as the superclass" do
metaclass = Object.new.singleton_class
- -> { @s.rb_class_new(metaclass) }.should raise_error(TypeError)
+ -> { @s.rb_class_new(metaclass) }.should.raise(TypeError)
end
end
@@ -479,7 +470,7 @@ describe "C-API Class function" do
end
it "returns nil if the class has no superclass" do
- @s.rb_class_superclass(BasicObject).should be_nil
+ @s.rb_class_superclass(BasicObject).should == nil
end
end
diff --git a/spec/ruby/optional/capi/constants_spec.rb b/spec/ruby/optional/capi/constants_spec.rb
index 172d10a788..74584690ad 100644
--- a/spec/ruby/optional/capi/constants_spec.rb
+++ b/spec/ruby/optional/capi/constants_spec.rb
@@ -199,7 +199,7 @@ describe "C-API exception constant" do
specify "rb_eFatal references the fatal class" do
fatal = @s.rb_eFatal
- fatal.should be_kind_of(Class)
+ fatal.should.is_a?(Class)
fatal.should < Exception
end
diff --git a/spec/ruby/optional/capi/data_spec.rb b/spec/ruby/optional/capi/data_spec.rb
index d000eba6e3..af1da10f48 100644
--- a/spec/ruby/optional/capi/data_spec.rb
+++ b/spec/ruby/optional/capi/data_spec.rb
@@ -32,7 +32,7 @@ ruby_version_is ""..."3.4" do
end
it "raises a TypeError if the object does not wrap a struct" do
- -> { @s.get_struct(Object.new) }.should raise_error(TypeError)
+ -> { @s.get_struct(Object.new) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/optional/capi/debug_spec.rb b/spec/ruby/optional/capi/debug_spec.rb
index 14ba25609c..547b24cfcc 100644
--- a/spec/ruby/optional/capi/debug_spec.rb
+++ b/spec/ruby/optional/capi/debug_spec.rb
@@ -9,7 +9,7 @@ describe "C-API Debug function" do
describe "rb_debug_inspector_open" do
it "creates a debug context and calls the given callback" do
- @o.rb_debug_inspector_open(42).should be_kind_of(Array)
+ @o.rb_debug_inspector_open(42).should.is_a?(Array)
@o.debug_spec_callback_data.should == 42
end
end
@@ -31,7 +31,7 @@ describe "C-API Debug function" do
it "returns the current binding" do
a = "test"
b = @o.rb_debug_inspector_frame_binding_get(1)
- b.should be_an_instance_of(Binding)
+ b.should.instance_of?(Binding)
b.local_variable_get(:a).should == "test"
end
@@ -55,7 +55,7 @@ describe "C-API Debug function" do
describe "rb_debug_inspector_frame_iseq_get" do
it "returns an InstructionSequence" do
if defined?(RubyVM::InstructionSequence)
- @o.rb_debug_inspector_frame_iseq_get(1).should be_an_instance_of(RubyVM::InstructionSequence)
+ @o.rb_debug_inspector_frame_iseq_get(1).should.instance_of?(RubyVM::InstructionSequence)
else
@o.rb_debug_inspector_frame_iseq_get(1).should == nil
end
@@ -66,9 +66,9 @@ describe "C-API Debug function" do
it "returns an array of Thread::Backtrace::Location" do
bts = @o.rb_debug_inspector_backtrace_locations
bts.should_not.empty?
- bts.each { |bt| bt.should be_kind_of(Thread::Backtrace::Location) }
+ bts.each { |bt| bt.should.is_a?(Thread::Backtrace::Location) }
location = "#{__FILE__}:#{__LINE__ - 3}"
- bts[1].to_s.should include(location)
+ bts[1].to_s.should.include?(location)
end
end
end
diff --git a/spec/ruby/optional/capi/digest_spec.rb b/spec/ruby/optional/capi/digest_spec.rb
new file mode 100644
index 0000000000..65c5ecebb1
--- /dev/null
+++ b/spec/ruby/optional/capi/digest_spec.rb
@@ -0,0 +1,103 @@
+require_relative 'spec_helper'
+
+begin
+ require 'fiddle'
+rescue LoadError
+ return
+end
+
+load_extension('digest')
+
+describe "C-API Digest functions" do
+ before :each do
+ @s = CApiDigestSpecs.new
+ end
+
+ describe "rb_digest_make_metadata" do
+ before :each do
+ @metadata = @s.rb_digest_make_metadata
+ end
+
+ it "should store the block length" do
+ @s.block_length(@metadata).should == 40
+ end
+
+ it "should store the digest length" do
+ @s.digest_length(@metadata).should == 20
+ end
+
+ it "should store the context size" do
+ @s.context_size(@metadata).should == 129
+ end
+ end
+
+ describe "digest plugin" do
+ before :each do
+ @s = CApiDigestSpecs.new
+ @digest = Digest::TestDigest.new
+
+ # A pointer to the CTX type defined in the extension for this spec. Digest does not make the context directly
+ # accessible as part of its API. However, to ensure we are properly loading the plugin, it's useful to have
+ # direct access to the context pointer to verify its contents.
+ @context = Fiddle::Pointer.new(@s.context(@digest))
+ end
+
+ it "should report the block length" do
+ @digest.block_length.should == 40
+ end
+
+ it "should report the digest length" do
+ @digest.digest_length.should == 20
+ end
+
+ it "should initialize the context" do
+ # Our test plugin always writes the string "Initialized\n" when its init function is called.
+ verify_context("Initialized\n")
+ end
+
+ it "should update the digest" do
+ @digest.update("hello world")
+
+ # Our test plugin always writes the string "Updated: <data>\n" when its update function is called.
+ current = "Initialized\nUpdated: hello world"
+ verify_context(current)
+
+ @digest << "blah"
+
+ current = "Initialized\nUpdated: hello worldUpdated: blah"
+ verify_context(current)
+ end
+
+ it "should finalize the digest" do
+ @digest.update("")
+
+ finish_string = @digest.instance_eval { finish }
+
+ # We expect the plugin to write out the last `@digest.digest_length` bytes, followed by the string "Finished\n".
+ #
+ finish_string.should == "d\nUpdated: Finished\n"
+ finish_string.encoding.should == Encoding::ASCII_8BIT
+ end
+
+ it "should reset the context" do
+ @digest.update("foo")
+ verify_context("Initialized\nUpdated: foo")
+
+ @digest.reset
+
+ # The context will be recreated as a result of the `reset` so we must fetch the latest context pointer.
+ @context = Fiddle::Pointer.new(@s.context(@digest))
+
+ verify_context("Initialized\n")
+ end
+
+ def verify_context(current_body)
+ # In the CTX type, the length of the current context contents is stored in the first byte.
+ byte_count = @context[0]
+ byte_count.should == current_body.bytesize
+
+ # After the size byte follows a string.
+ @context[1, byte_count].should == current_body
+ end
+ end
+end
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index db693f041b..b77a967b1e 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -36,7 +36,7 @@ describe :rb_enc_set_index, shared: true do
obj = Object.new
-> {
result = @s.send(@method, obj, 1)
- }.should raise_error(ArgumentError, "cannot set encoding on non-encoding capable object")
+ }.should.raise(ArgumentError, "cannot set encoding on non-encoding capable object")
end
end
@@ -165,7 +165,7 @@ describe "C-API Encoding function" do
describe "rb_enc_from_index" do
it "returns an Encoding" do
- @s.rb_enc_from_index(0).should be_an_instance_of(String)
+ @s.rb_enc_from_index(0).should.instance_of?(String)
end
end
@@ -298,7 +298,7 @@ describe "C-API Encoding function" do
it "returns a String in US-ASCII encoding when high bits are set" do
xEE = [0xEE].pack('C').force_encoding('utf-8')
result = @s.rb_enc_str_new(xEE, 1, Encoding::US_ASCII)
- result.encoding.should equal(Encoding::US_ASCII)
+ result.encoding.should.equal?(Encoding::US_ASCII)
end
end
@@ -389,12 +389,12 @@ describe "C-API Encoding function" do
it "returns true if the object encoding is only ASCII" do
str = "abc".force_encoding("us-ascii")
str.valid_encoding? # make sure to set the coderange
- @s.ENC_CODERANGE_ASCIIONLY(str).should be_true
+ @s.ENC_CODERANGE_ASCIIONLY(str).should == true
end
it "returns false if the object encoding is not ASCII only" do
str = "ありがとう".force_encoding("utf-8")
- @s.ENC_CODERANGE_ASCIIONLY(str).should be_false
+ @s.ENC_CODERANGE_ASCIIONLY(str).should == false
end
end
@@ -421,7 +421,7 @@ describe "C-API Encoding function" do
describe "when the rb_encoding struct is stored in native memory" do
it "can still read the name of the encoding" do
address = @s.rb_to_encoding_native_store(Encoding::UTF_8)
- address.should be_kind_of(Integer)
+ address.should.is_a?(Integer)
@s.rb_to_encoding_native_name(address).should == "UTF-8"
end
end
@@ -452,7 +452,7 @@ describe "C-API Encoding function" do
describe "rb_enc_compatible" do
it "returns 0 if the encodings of the Strings are not compatible" do
a = [0xff].pack('C').force_encoding "binary"
- b = "\u3042".encode("utf-8")
+ b = "あ"
@s.rb_enc_compatible(a, b).should == 0
end
@@ -461,11 +461,25 @@ describe "C-API Encoding function" do
# Encoding.compatible?
it "returns the same value as Encoding.compatible? if the Strings have a compatible encoding" do
a = "abc".force_encoding("us-ascii")
- b = "\u3042".encode("utf-8")
+ b = "あ"
@s.rb_enc_compatible(a, b).should == Encoding.compatible?(a, b)
end
end
+ describe "rb_enc_check" do
+ it "returns the compatible encoding of the two Strings" do
+ a = "abc".force_encoding("us-ascii")
+ b = "あ"
+ @s.rb_enc_check(a, b).should == Encoding::UTF_8
+ end
+
+ it "raises Encoding::CompatibilityError if the encodings are not compatible" do
+ a = [0xff].pack('C').b
+ b = "あ"
+ -> { @s.rb_enc_check(a, b) }.should.raise(Encoding::CompatibilityError)
+ end
+ end
+
describe "rb_enc_copy" do
before :each do
@obj = "rb_enc_copy".encode(Encoding::US_ASCII)
@@ -475,12 +489,20 @@ describe "C-API Encoding function" do
@s.rb_enc_copy("string", @obj).encoding.should == Encoding::US_ASCII
end
- it "raises a RuntimeError if the second argument is a Symbol" do
- -> { @s.rb_enc_copy(:symbol, @obj) }.should raise_error(RuntimeError)
+ it "raises a RuntimeError if the first argument is a Symbol" do
+ -> { @s.rb_enc_copy(:symbol, @obj) }.should.raise(RuntimeError)
end
- it "sets the encoding of a Regexp to that of the second argument" do
- @s.rb_enc_copy(/regexp/.dup, @obj).encoding.should == Encoding::US_ASCII
+ ruby_version_is "4.1" do
+ it "raises a FrozenError if the first argument is a Regexp" do
+ -> { @s.rb_enc_copy(/regexp/.dup, @obj) }.should.raise(FrozenError)
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "sets the encoding of a Regexp to that of the second argument" do
+ @s.rb_enc_copy(/regexp/.dup, @obj).encoding.should == Encoding::US_ASCII
+ end
end
end
@@ -495,7 +517,7 @@ describe "C-API Encoding function" do
it "returns 0 if Encoding.default_internal is nil" do
Encoding.default_internal = nil
- @s.rb_default_internal_encoding.should be_nil
+ @s.rb_default_internal_encoding.should == nil
end
it "returns the encoding for Encoding.default_internal" do
@@ -527,11 +549,19 @@ describe "C-API Encoding function" do
end
it "raises a RuntimeError if the argument is Symbol" do
- -> { @s.rb_enc_associate(:symbol, "US-ASCII") }.should raise_error(RuntimeError)
+ -> { @s.rb_enc_associate(:symbol, "US-ASCII") }.should.raise(RuntimeError)
+ end
+
+ ruby_version_is "4.1" do
+ it "raises a FrozenError if the argument is a Regexp" do
+ -> { @s.rb_enc_associate(/regexp/.dup, "BINARY") }.should.raise(FrozenError)
+ end
end
- it "sets the encoding of a Regexp to the encoding" do
- @s.rb_enc_associate(/regexp/.dup, "BINARY").encoding.should == Encoding::BINARY
+ ruby_version_is ""..."4.1" do
+ it "sets the encoding of a Regexp to the encoding" do
+ @s.rb_enc_associate(/regexp/.dup, "BINARY").encoding.should == Encoding::BINARY
+ end
end
it "sets the encoding of a String to a default when the encoding is NULL" do
@@ -546,15 +576,24 @@ describe "C-API Encoding function" do
enc.should == Encoding::BINARY
end
- it "sets the encoding of a Regexp to the encoding" do
- index = @s.rb_enc_find_index("UTF-8")
- enc = @s.rb_enc_associate_index(/regexp/.dup, index).encoding
- enc.should == Encoding::UTF_8
+ ruby_version_is "4.1" do
+ it "raises a FrozenError if the argument is a Regexp" do
+ index = @s.rb_enc_find_index("UTF-8")
+ -> { @s.rb_enc_associate_index(/regexp/.dup, index) }.should.raise(FrozenError)
+ end
+ end
+
+ ruby_version_is ""..."4.1" do
+ it "sets the encoding of a Regexp to the encoding" do
+ index = @s.rb_enc_find_index("UTF-8")
+ enc = @s.rb_enc_associate_index(/regexp/.dup, index).encoding
+ enc.should == Encoding::UTF_8
+ end
end
it "sets the encoding of a Symbol to the encoding" do
index = @s.rb_enc_find_index("UTF-8")
- -> { @s.rb_enc_associate_index(:symbol, index) }.should raise_error(RuntimeError)
+ -> { @s.rb_enc_associate_index(:symbol, index) }.should.raise(RuntimeError)
end
end
@@ -610,13 +649,13 @@ describe "C-API Encoding function" do
it "raises ArgumentError if an empty string is given" do
-> do
@s.rb_enc_codepoint_len("")
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "raises ArgumentError if an invalid byte sequence is given" do
-> do
@s.rb_enc_codepoint_len([0xa0, 0xa1].pack('CC').force_encoding('utf-8')) # Invalid sequence identifier
- end.should raise_error(ArgumentError)
+ end.should.raise(ArgumentError)
end
it "returns codepoint 0x24 and length 1 for character '$'" do
@@ -650,11 +689,11 @@ describe "C-API Encoding function" do
describe "rb_enc_str_asciionly_p" do
it "returns true for an ASCII string" do
- @s.rb_enc_str_asciionly_p("hello").should be_true
+ @s.rb_enc_str_asciionly_p("hello").should == true
end
it "returns false for a non-ASCII string" do
- @s.rb_enc_str_asciionly_p("hüllo").should be_false
+ @s.rb_enc_str_asciionly_p("hüllo").should == false
end
end
@@ -664,7 +703,7 @@ describe "C-API Encoding function" do
-> {
@s.rb_enc_raise(Encoding::UTF_8, RuntimeError, utf_8_incompatible_string)
- }.should raise_error { |e|
+ }.should.raise { |e|
e.message.encoding.should == Encoding::UTF_8
e.message.valid_encoding?.should == false
e.message.bytes.should == utf_8_incompatible_string.bytes
@@ -724,25 +763,55 @@ describe "C-API Encoding function" do
end
describe "rb_define_dummy_encoding" do
+ run = 0
+
it "defines the dummy encoding" do
- @s.rb_define_dummy_encoding("FOO")
- enc = Encoding.find("FOO")
+ @s.rb_define_dummy_encoding("FOO#{run += 1}")
+ enc = Encoding.find("FOO#{run}")
enc.should.dummy?
end
it "returns the index of the dummy encoding" do
- index = @s.rb_define_dummy_encoding("BAR")
+ index = @s.rb_define_dummy_encoding("BAR#{run += 1}")
index.should == Encoding.list.size - 1
end
- ruby_version_is "3.2" do
- it "raises EncodingError if too many encodings" do
- code = <<-RUBY
- require #{extension_path.dump}
- 1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding("R_\#{i}") }
- RUBY
- ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
+ it "raises EncodingError if too many encodings" do
+ code = <<-RUBY
+ require #{extension_path.dump}
+ 1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding("R_\#{i}") }
+ RUBY
+ ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
+ end
+ end
+
+ describe "ONIGENC_IS_UNICODE" do
+ it "is true only for select UTF-related encodings" do
+ unicode = [
+ Encoding::UTF_8,
+ Encoding::UTF8_DOCOMO,
+ Encoding::UTF8_KDDI,
+ Encoding::UTF8_MAC,
+ Encoding::UTF8_SOFTBANK,
+ Encoding::CESU_8,
+ Encoding::UTF_16LE,
+ Encoding::UTF_16BE,
+ Encoding::UTF_32LE,
+ Encoding::UTF_32BE
+ ]
+ unicode.each do |enc|
+ @s.should.ONIGENC_IS_UNICODE(enc)
end
+
+ (Encoding.list - unicode).each { |enc|
+ @s.should_not.ONIGENC_IS_UNICODE(enc)
+ }
+ end
+
+ # Redundant with the above but more explicit
+ it "is false for the dummy UTF-16 and UTF-32 encodings" do
+ @s.should_not.ONIGENC_IS_UNICODE(Encoding::UTF_16)
+ @s.should_not.ONIGENC_IS_UNICODE(Encoding::UTF_32)
end
end
end
diff --git a/spec/ruby/optional/capi/exception_spec.rb b/spec/ruby/optional/capi/exception_spec.rb
index 5bb60608b2..429da093d1 100644
--- a/spec/ruby/optional/capi/exception_spec.rb
+++ b/spec/ruby/optional/capi/exception_spec.rb
@@ -28,13 +28,13 @@ describe "C-API Exception function" do
describe "rb_exc_raise" do
it "raises passed exception" do
runtime_error = RuntimeError.new '42'
- -> { @s.rb_exc_raise(runtime_error) }.should raise_error(RuntimeError, '42')
+ -> { @s.rb_exc_raise(runtime_error) }.should.raise(RuntimeError, '42')
end
it "raises an exception with an empty backtrace" do
runtime_error = RuntimeError.new '42'
runtime_error.set_backtrace []
- -> { @s.rb_exc_raise(runtime_error) }.should raise_error(RuntimeError, '42')
+ -> { @s.rb_exc_raise(runtime_error) }.should.raise(RuntimeError, '42')
end
it "sets $! to the raised exception when not rescuing from an another exception" do
@@ -88,15 +88,35 @@ describe "C-API Exception function" do
end
it "accepts nil" do
- @s.rb_set_errinfo(nil).should be_nil
+ @s.rb_set_errinfo(nil).should == nil
end
it "accepts an Exception instance" do
- @s.rb_set_errinfo(Exception.new).should be_nil
+ @s.rb_set_errinfo(Exception.new).should == nil
end
it "raises a TypeError if the object is not nil or an Exception instance" do
- -> { @s.rb_set_errinfo("error") }.should raise_error(TypeError)
+ -> { @s.rb_set_errinfo("error") }.should.raise(TypeError)
+ end
+ end
+
+ describe "rb_error_frozen_object" do
+ it "raises a FrozenError regardless of the object's frozen state" do
+ # The type of the argument we supply doesn't matter. The choice here is arbitrary and we only change the type
+ # of the argument to ensure the exception messages are set correctly.
+ -> { @s.rb_error_frozen_object(Array.new) }.should.raise(FrozenError, "can't modify frozen Array: []")
+ -> { @s.rb_error_frozen_object(Array.new.freeze) }.should.raise(FrozenError, "can't modify frozen Array: []")
+ end
+
+ it "properly handles recursive rb_error_frozen_object calls" do
+ klass = Class.new(Object)
+ object = klass.new
+ s = @s
+ klass.define_method :inspect do
+ s.rb_error_frozen_object(object)
+ end
+
+ -> { @s.rb_error_frozen_object(object) }.should.raise(FrozenError, "can't modify frozen #{klass}: ...")
end
end
@@ -104,14 +124,14 @@ describe "C-API Exception function" do
it "returns system error with default message when passed message is NULL" do
exception = @s.rb_syserr_new(Errno::ENOENT::Errno, nil)
exception.class.should == Errno::ENOENT
- exception.message.should include("No such file or directory")
+ exception.message.should.include?("No such file or directory")
exception.should.is_a?(SystemCallError)
end
it "returns system error with custom message" do
exception = @s.rb_syserr_new(Errno::ENOENT::Errno, "custom message")
- exception.message.should include("custom message")
+ exception.message.should.include?("custom message")
exception.class.should == Errno::ENOENT
exception.should.is_a?(SystemCallError)
end
@@ -121,14 +141,14 @@ describe "C-API Exception function" do
it "returns system error with default message when passed message is nil" do
exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, nil)
- exception.message.should include("No such file or directory")
+ exception.message.should.include?("No such file or directory")
exception.class.should == Errno::ENOENT
exception.should.is_a?(SystemCallError)
end
it "returns system error with custom message" do
exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, "custom message")
- exception.message.should include("custom message")
+ exception.message.should.include?("custom message")
exception.class.should == Errno::ENOENT
exception.should.is_a?(SystemCallError)
end
@@ -161,17 +181,17 @@ describe "C-API Exception function" do
end
it "raises a TypeError for incorrect types" do
- -> { @s.rb_make_exception([nil]) }.should raise_error(TypeError)
- -> { @s.rb_make_exception([Object.new]) }.should raise_error(TypeError)
+ -> { @s.rb_make_exception([nil]) }.should.raise(TypeError)
+ -> { @s.rb_make_exception([Object.new]) }.should.raise(TypeError)
obj = Object.new
def obj.exception
"not exception type"
end
- -> { @s.rb_make_exception([obj]) }.should raise_error(TypeError)
+ -> { @s.rb_make_exception([obj]) }.should.raise(TypeError)
end
it "raises an ArgumentError for too many arguments" do
- -> { @s.rb_make_exception([Exception, "Message", ["backtrace 1"], "extra"]) }.should raise_error(ArgumentError)
+ -> { @s.rb_make_exception([Exception, "Message", ["backtrace 1"], "extra"]) }.should.raise(ArgumentError)
end
it "returns nil for empty arguments" do
diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c
index 2347798bb4..628c4df9d7 100644
--- a/spec/ruby/optional/capi/ext/array_spec.c
+++ b/spec/ruby/optional/capi/ext/array_spec.c
@@ -196,6 +196,7 @@ static VALUE copy_ary(RB_BLOCK_CALL_FUNC_ARGLIST(el, new_ary)) {
return rb_ary_push(new_ary, el);
}
+#ifndef RUBY_VERSION_IS_4_0
static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) {
VALUE new_ary = rb_ary_new();
@@ -203,6 +204,7 @@ static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) {
return new_ary;
}
+#endif
static VALUE array_spec_rb_block_call(VALUE self, VALUE ary) {
VALUE new_ary = rb_ary_new();
@@ -216,6 +218,7 @@ static VALUE sub_pair(RB_BLOCK_CALL_FUNC_ARGLIST(el, holder)) {
return rb_ary_push(holder, rb_ary_entry(el, 1));
}
+#ifndef RUBY_VERSION_IS_4_0
static VALUE each_pair(VALUE obj) {
return rb_funcall(obj, rb_intern("each_pair"), 0);
}
@@ -227,6 +230,7 @@ static VALUE array_spec_rb_iterate_each_pair(VALUE self, VALUE obj) {
return new_ary;
}
+#endif
static VALUE array_spec_rb_block_call_each_pair(VALUE self, VALUE obj) {
VALUE new_ary = rb_ary_new();
@@ -241,10 +245,12 @@ static VALUE iter_yield(RB_BLOCK_CALL_FUNC_ARGLIST(el, ary)) {
return Qnil;
}
+#ifndef RUBY_VERSION_IS_4_0
static VALUE array_spec_rb_iterate_then_yield(VALUE self, VALUE obj) {
rb_iterate(rb_each, obj, iter_yield, obj);
return Qnil;
}
+#endif
static VALUE array_spec_rb_block_call_then_yield(VALUE self, VALUE obj) {
rb_block_call(obj, rb_intern("each"), 0, 0, iter_yield, obj);
@@ -308,9 +314,11 @@ void Init_array_spec(void) {
rb_define_method(cls, "rb_ary_plus", array_spec_rb_ary_plus, 2);
rb_define_method(cls, "rb_ary_unshift", array_spec_rb_ary_unshift, 2);
rb_define_method(cls, "rb_assoc_new", array_spec_rb_assoc_new, 2);
+#ifndef RUBY_VERSION_IS_4_0
rb_define_method(cls, "rb_iterate", array_spec_rb_iterate, 1);
rb_define_method(cls, "rb_iterate_each_pair", array_spec_rb_iterate_each_pair, 1);
rb_define_method(cls, "rb_iterate_then_yield", array_spec_rb_iterate_then_yield, 1);
+#endif
rb_define_method(cls, "rb_block_call", array_spec_rb_block_call, 1);
rb_define_method(cls, "rb_block_call_each_pair", array_spec_rb_block_call_each_pair, 1);
rb_define_method(cls, "rb_block_call_then_yield", array_spec_rb_block_call_then_yield, 1);
diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c
index c13f02ecf2..8ac0e7a93f 100644
--- a/spec/ruby/optional/capi/ext/class_spec.c
+++ b/spec/ruby/optional/capi/ext/class_spec.c
@@ -65,11 +65,9 @@ static VALUE class_spec_rb_class_new_instance(VALUE self, VALUE args, VALUE klas
return rb_class_new_instance(RARRAY_LENINT(args), RARRAY_PTR(args), klass);
}
-#ifdef RUBY_VERSION_IS_3_0
static VALUE class_spec_rb_class_new_instance_kw(VALUE self, VALUE args, VALUE klass) {
return rb_class_new_instance_kw(RARRAY_LENINT(args), RARRAY_PTR(args), klass, RB_PASS_KEYWORDS);
}
-#endif
static VALUE class_spec_rb_class_real(VALUE self, VALUE object) {
if (rb_type_p(object, T_FIXNUM)) {
@@ -160,9 +158,7 @@ void Init_class_spec(void) {
rb_define_method(cls, "rb_class_private_instance_methods", class_spec_rb_class_private_instance_methods, -1);
rb_define_method(cls, "rb_class_new", class_spec_rb_class_new, 1);
rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 2);
-#ifdef RUBY_VERSION_IS_3_0
rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2);
-#endif
rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1);
rb_define_method(cls, "rb_class_get_superclass", class_spec_rb_class_get_superclass, 1);
rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1);
diff --git a/spec/ruby/optional/capi/ext/constants_spec.c b/spec/ruby/optional/capi/ext/constants_spec.c
index 9aee8db37f..05819ea476 100644
--- a/spec/ruby/optional/capi/ext/constants_spec.c
+++ b/spec/ruby/optional/capi/ext/constants_spec.c
@@ -14,9 +14,6 @@ defconstfunc(rb_cBinding)
defconstfunc(rb_cClass)
defconstfunc(rb_cComplex)
defconstfunc(rb_mComparable)
-#ifndef RUBY_VERSION_IS_3_0
-defconstfunc(rb_cData)
-#endif
defconstfunc(rb_cDir)
defconstfunc(rb_cEncoding)
defconstfunc(rb_mEnumerable)
@@ -97,9 +94,6 @@ void Init_constants_spec(void) {
rb_define_method(cls, "rb_cClass", constants_spec_rb_cClass, 0);
rb_define_method(cls, "rb_cComplex", constants_spec_rb_cComplex, 0);
rb_define_method(cls, "rb_mComparable", constants_spec_rb_mComparable, 0);
- #ifndef RUBY_VERSION_IS_3_0
- rb_define_method(cls, "rb_cData", constants_spec_rb_cData, 0);
- #endif
rb_define_method(cls, "rb_cDir", constants_spec_rb_cDir, 0);
rb_define_method(cls, "rb_cEncoding", constants_spec_rb_cEncoding, 0);
rb_define_method(cls, "rb_mEnumerable", constants_spec_rb_mEnumerable, 0);
diff --git a/spec/ruby/optional/capi/ext/digest_spec.c b/spec/ruby/optional/capi/ext/digest_spec.c
new file mode 100644
index 0000000000..65c8defa20
--- /dev/null
+++ b/spec/ruby/optional/capi/ext/digest_spec.c
@@ -0,0 +1,168 @@
+#include "ruby.h"
+#include "rubyspec.h"
+
+#include "ruby/digest.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DIGEST_LENGTH 20
+#define BLOCK_LENGTH 40
+
+const char *init_string = "Initialized\n";
+const char *update_string = "Updated: ";
+const char *finish_string = "Finished\n";
+
+#define PAYLOAD_SIZE 128
+
+typedef struct CTX {
+ uint8_t pos;
+ char payload[PAYLOAD_SIZE];
+} CTX;
+
+void* context = NULL;
+
+int digest_spec_plugin_init(void *raw_ctx) {
+ // Make the context accessible to tests. This isn't safe, but there's no way to access the context otherwise.
+ context = raw_ctx;
+
+ struct CTX *ctx = (struct CTX *)raw_ctx;
+ size_t len = strlen(init_string);
+
+ // Clear the payload since this init function will be invoked as part of the `reset` operation.
+ memset(ctx->payload, 0, PAYLOAD_SIZE);
+
+ // Write a simple value we can verify in tests.
+ // This is not what a real digest would do, but we're using a dummy digest plugin to test interactions.
+ memcpy(ctx->payload, init_string, len);
+ ctx->pos = (uint8_t) len;
+
+ return 1;
+}
+
+void digest_spec_plugin_update(void *raw_ctx, unsigned char *ptr, size_t size) {
+ struct CTX *ctx = (struct CTX *)raw_ctx;
+ size_t update_str_len = strlen(update_string);
+
+ if (ctx->pos + update_str_len + size >= PAYLOAD_SIZE) {
+ rb_raise(rb_eRuntimeError, "update size too large; reset the digest and write fewer updates");
+ }
+
+ // Write the supplied value to the payload so it can be easily verified in test.
+ // This is not what a real digest would do, but we're using a dummy digest plugin to test interactions.
+ memcpy(ctx->payload + ctx->pos, update_string, update_str_len);
+ ctx->pos += update_str_len;
+
+ memcpy(ctx->payload + ctx->pos, ptr, size);
+ ctx->pos += size;
+
+ return;
+}
+
+int digest_spec_plugin_finish(void *raw_ctx, unsigned char *ptr) {
+ struct CTX *ctx = (struct CTX *)raw_ctx;
+ size_t finish_string_len = strlen(finish_string);
+
+ // We're always going to write DIGEST_LENGTH bytes. In a real plugin, this would be the digest value. Here we
+ // write out a text string in order to make validation in tests easier.
+ //
+ // In order to delineate the output more clearly from an `Digest#update` call, we always write out the
+ // `finish_string` message. That leaves `DIGEST_LENGTH - finish_string_len` bytes to read out of the context.
+ size_t context_bytes = DIGEST_LENGTH - finish_string_len;
+
+ memcpy(ptr, ctx->payload + (ctx->pos - context_bytes), context_bytes);
+ memcpy(ptr + context_bytes, finish_string, finish_string_len);
+
+ return 1;
+}
+
+static const rb_digest_metadata_t metadata = {
+ // The RUBY_DIGEST_API_VERSION value comes from ruby/digest.h and may vary based on the Ruby being tested. Since
+ // it isn't publicly exposed in the digest gem, we ignore for these tests. Either the test hard-codes an expected
+ // value and is subject to breaking depending on the Ruby being run or we publicly expose `RUBY_DIGEST_API_VERSION`,
+ // in which case the test would pass trivially.
+ RUBY_DIGEST_API_VERSION,
+ DIGEST_LENGTH,
+ BLOCK_LENGTH,
+ sizeof(CTX),
+ (rb_digest_hash_init_func_t) digest_spec_plugin_init,
+ (rb_digest_hash_update_func_t) digest_spec_plugin_update,
+ (rb_digest_hash_finish_func_t) digest_spec_plugin_finish,
+};
+
+// The `get_metadata_ptr` function is not publicly available in the digest gem. However, we need to use
+// to extract the `rb_digest_metadata_t*` value set up by the plugin so we reproduce and adjust the
+// definition here.
+//
+// Taken and adapted from https://github.com/ruby/digest/blob/v3.2.0/ext/digest/digest.c#L558-L568
+static rb_digest_metadata_t * get_metadata_ptr(VALUE obj) {
+ rb_digest_metadata_t *algo;
+
+#ifdef DIGEST_USE_RB_EXT_RESOLVE_SYMBOL
+ // In the digest gem there is an additional data type check performed before reading the value out.
+ // Since the type definition isn't public, we can't use it as part of a type check here so we omit it.
+ // This is safe to do because this code is intended to only load digest plugins written as part of this test suite.
+ algo = (rb_digest_metadata_t *) RTYPEDDATA_DATA(obj);
+#else
+# undef RUBY_UNTYPED_DATA_WARNING
+# define RUBY_UNTYPED_DATA_WARNING 0
+ Data_Get_Struct(obj, rb_digest_metadata_t, algo);
+#endif
+
+ return algo;
+}
+
+VALUE digest_spec_rb_digest_make_metadata(VALUE self) {
+ return rb_digest_make_metadata(&metadata);
+}
+
+VALUE digest_spec_block_length(VALUE self, VALUE meta) {
+ rb_digest_metadata_t* algo = get_metadata_ptr(meta);
+
+ return SIZET2NUM(algo->block_len);
+}
+
+VALUE digest_spec_digest_length(VALUE self, VALUE meta) {
+ rb_digest_metadata_t* algo = get_metadata_ptr(meta);
+
+ return SIZET2NUM(algo->digest_len);
+}
+
+VALUE digest_spec_context_size(VALUE self, VALUE meta) {
+ rb_digest_metadata_t* algo = get_metadata_ptr(meta);
+
+ return SIZET2NUM(algo->ctx_size);
+}
+
+#ifndef PTR2NUM
+#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
+#endif
+
+VALUE digest_spec_context(VALUE self, VALUE digest) {
+ return PTR2NUM(context);
+}
+
+void Init_digest_spec(void) {
+ VALUE cls;
+
+ cls = rb_define_class("CApiDigestSpecs", rb_cObject);
+ rb_define_method(cls, "rb_digest_make_metadata", digest_spec_rb_digest_make_metadata, 0);
+ rb_define_method(cls, "block_length", digest_spec_block_length, 1);
+ rb_define_method(cls, "digest_length", digest_spec_digest_length, 1);
+ rb_define_method(cls, "context_size", digest_spec_context_size, 1);
+ rb_define_method(cls, "context", digest_spec_context, 1);
+
+ VALUE mDigest, cDigest_Base, cDigest;
+
+ mDigest = rb_define_module("Digest");
+ mDigest = rb_digest_namespace();
+ cDigest_Base = rb_const_get(mDigest, rb_intern_const("Base"));
+
+ cDigest = rb_define_class_under(mDigest, "TestDigest", cDigest_Base);
+ rb_iv_set(cDigest, "metadata", rb_digest_make_metadata(&metadata));
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c
index aa8662cfbd..2038a5d4a8 100644
--- a/spec/ruby/optional/capi/ext/encoding_spec.c
+++ b/spec/ruby/optional/capi/ext/encoding_spec.c
@@ -91,6 +91,11 @@ static VALUE encoding_spec_rb_enc_compatible(VALUE self, VALUE a, VALUE b) {
return rb_enc_from_encoding(enc);
}
+static VALUE encoding_spec_rb_enc_check(VALUE self, VALUE a, VALUE b) {
+ rb_encoding* enc = rb_enc_check(a, b);
+ return rb_enc_from_encoding(enc);
+}
+
static VALUE encoding_spec_rb_enc_copy(VALUE self, VALUE dest, VALUE src) {
rb_enc_copy(dest, src);
return dest;
@@ -324,6 +329,10 @@ static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
}
+static VALUE encoding_spec_ONIGENC_IS_UNICODE(VALUE self, VALUE encoding) {
+ return ONIGENC_IS_UNICODE(rb_to_encoding(encoding)) ? Qtrue : Qfalse;
+}
+
void Init_encoding_spec(void) {
VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@@ -349,6 +358,7 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2);
rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2);
rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2);
+ rb_define_method(cls, "rb_enc_check", encoding_spec_rb_enc_check, 2);
rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2);
rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2);
rb_define_method(cls, "rb_enc_strlen", encoding_spec_rb_enc_strlen, 3);
@@ -384,6 +394,7 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2);
rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
+ rb_define_method(cls, "ONIGENC_IS_UNICODE", encoding_spec_ONIGENC_IS_UNICODE, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c
index 0e8347ab0d..c3b94d7bcd 100644
--- a/spec/ruby/optional/capi/ext/exception_spec.c
+++ b/spec/ruby/optional/capi/ext/exception_spec.c
@@ -36,6 +36,13 @@ VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) {
return Qnil;
}
+NORETURN(VALUE exception_spec_rb_error_frozen_object(VALUE self, VALUE object));
+
+VALUE exception_spec_rb_error_frozen_object(VALUE self, VALUE object) {
+ rb_error_frozen_object(object);
+ UNREACHABLE_RETURN(Qnil);
+}
+
VALUE exception_spec_rb_syserr_new(VALUE self, VALUE num, VALUE msg) {
int n = NUM2INT(num);
char *cstr = NULL;
@@ -66,6 +73,7 @@ void Init_exception_spec(void) {
rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1);
rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1);
rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1);
+ rb_define_method(cls, "rb_error_frozen_object", exception_spec_rb_error_frozen_object, 1);
rb_define_method(cls, "rb_syserr_new", exception_spec_rb_syserr_new, 2);
rb_define_method(cls, "rb_syserr_new_str", exception_spec_rb_syserr_new_str, 2);
rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1);
diff --git a/spec/ruby/optional/capi/ext/fiber_spec.c b/spec/ruby/optional/capi/ext/fiber_spec.c
index f06a54494e..db54f7ad8c 100644
--- a/spec/ruby/optional/capi/ext/fiber_spec.c
+++ b/spec/ruby/optional/capi/ext/fiber_spec.c
@@ -44,12 +44,10 @@ VALUE fiber_spec_rb_fiber_new(VALUE self) {
return rb_fiber_new(fiber_spec_rb_fiber_new_function, Qnil);
}
-#ifdef RUBY_VERSION_IS_3_1
VALUE fiber_spec_rb_fiber_raise(int argc, VALUE *argv, VALUE self) {
VALUE fiber = argv[0];
return rb_fiber_raise(fiber, argc-1, argv+1);
}
-#endif
void Init_fiber_spec(void) {
VALUE cls = rb_define_class("CApiFiberSpecs", rb_cObject);
@@ -58,10 +56,7 @@ void Init_fiber_spec(void) {
rb_define_method(cls, "rb_fiber_resume", fiber_spec_rb_fiber_resume, 2);
rb_define_method(cls, "rb_fiber_yield", fiber_spec_rb_fiber_yield, 1);
rb_define_method(cls, "rb_fiber_new", fiber_spec_rb_fiber_new, 0);
-
-#ifdef RUBY_VERSION_IS_3_1
rb_define_method(cls, "rb_fiber_raise", fiber_spec_rb_fiber_raise, -1);
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c
index 2637ad27ac..0baa114d7b 100644
--- a/spec/ruby/optional/capi/ext/gc_spec.c
+++ b/spec/ruby/optional/capi/ext/gc_spec.c
@@ -18,6 +18,32 @@ VALUE rb_gc_register_address_outside_init;
VALUE rb_gc_register_mark_object_not_referenced_float;
+static VALUE spec_RB_GC_GUARD_keep_alive(VALUE self, VALUE array_with_string) {
+ VALUE string = rb_ary_entry(array_with_string, 0);
+ char* ptr = RSTRING_PTR(string);
+ // Without the RB_GC_GUARD(string) below, string could be GC'd, and ptr become invalid
+ rb_gc();
+ char copy[4];
+ copy[0] = ptr[0];
+ copy[1] = ptr[1];
+ copy[2] = ptr[2];
+ copy[3] = '\0';
+ RB_GC_GUARD(string);
+ return rb_str_new_cstr(copy);
+}
+
+static VALUE spec_RB_GC_GUARD(VALUE self, VALUE object) {
+ RB_GC_GUARD(object);
+ return object;
+}
+
+static VALUE spec_RB_GC_GUARD_raw(VALUE self, VALUE number) {
+ long l = NUM2LONG(number);
+ VALUE value = (VALUE) l;
+ RB_GC_GUARD(value);
+ return Qnil;
+}
+
static VALUE registered_tagged_address(VALUE self) {
return registered_tagged_value;
}
@@ -124,6 +150,9 @@ void Init_gc_spec(void) {
rb_gc_register_mark_object_not_referenced_float = DBL2NUM(1.61);
rb_gc_register_mark_object(rb_gc_register_mark_object_not_referenced_float);
+ rb_define_method(cls, "RB_GC_GUARD_keep_alive", spec_RB_GC_GUARD_keep_alive, 1);
+ rb_define_method(cls, "RB_GC_GUARD", spec_RB_GC_GUARD, 1);
+ rb_define_method(cls, "RB_GC_GUARD_raw", spec_RB_GC_GUARD_raw, 1);
rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0);
rb_define_method(cls, "registered_reference_address", registered_reference_address, 0);
rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0);
diff --git a/spec/ruby/optional/capi/ext/hash_spec.c b/spec/ruby/optional/capi/ext/hash_spec.c
index 0e5b3d1c0a..653917f2c4 100644
--- a/spec/ruby/optional/capi/ext/hash_spec.c
+++ b/spec/ruby/optional/capi/ext/hash_spec.c
@@ -105,11 +105,9 @@ VALUE hash_spec_rb_hash_new(VALUE self) {
return rb_hash_new();
}
-#ifdef RUBY_VERSION_IS_3_2
VALUE hash_spec_rb_hash_new_capa(VALUE self, VALUE capacity) {
return rb_hash_new_capa(NUM2LONG(capacity));
}
-#endif
VALUE rb_ident_hash_new(void); /* internal.h, used in ripper */
@@ -169,9 +167,7 @@ void Init_hash_spec(void) {
rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3);
rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2);
rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0);
-#ifdef RUBY_VERSION_IS_3_2
rb_define_method(cls, "rb_hash_new_capa", hash_spec_rb_hash_new_capa, 1);
-#endif
rb_define_method(cls, "rb_ident_hash_new", hash_spec_rb_ident_hash_new, 0);
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index cc440e6b07..fe31cffb49 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -28,13 +28,7 @@ static int set_non_blocking(int fd) {
}
static int io_spec_get_fd(VALUE io) {
-#ifdef RUBY_VERSION_IS_3_1
return rb_io_descriptor(io);
-#else
- rb_io_t* fp;
- GetOpenFile(io, fp);
- return fp->fd;
-#endif
}
VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) {
@@ -143,11 +137,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
errno = saved_errno;
}
-#ifdef RUBY_VERSION_IS_3_1
ret = rb_io_maybe_wait_readable(errno, io, Qnil);
-#else
- ret = rb_io_wait_readable(fd);
-#endif
if (RTEST(read_p)) {
ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
@@ -166,22 +156,15 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
}
VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) {
-#ifdef RUBY_VERSION_IS_3_1
int ret = rb_io_maybe_wait_writable(errno, io, Qnil);
-#else
- int ret = rb_io_wait_writable(io_spec_get_fd(io));
-#endif
return ret ? Qtrue : Qfalse;
}
-#ifdef RUBY_VERSION_IS_3_1
VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) {
int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout);
return INT2NUM(ret);
}
-#endif
-#ifdef RUBY_VERSION_IS_3_1
#ifdef SET_NON_BLOCKING_FAILS_ALWAYS
NORETURN(VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p));
#endif
@@ -224,13 +207,10 @@ VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE
UNREACHABLE_RETURN(Qnil);
#endif
}
-#endif
-#ifdef RUBY_VERSION_IS_3_1
VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) {
return rb_io_maybe_wait(NUM2INT(error), io, events, timeout);
}
-#endif
VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) {
rb_thread_wait_fd(io_spec_get_fd(io));
@@ -238,7 +218,6 @@ VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) {
}
VALUE io_spec_rb_wait_for_single_fd(VALUE self, VALUE io, VALUE events, VALUE secs, VALUE usecs) {
-#ifdef RUBY_VERSION_IS_3_0
VALUE timeout = Qnil;
if (!NIL_P(secs)) {
timeout = rb_float_new((double)FIX2INT(secs) + (0.000001 * FIX2INT(usecs)));
@@ -246,15 +225,6 @@ VALUE io_spec_rb_wait_for_single_fd(VALUE self, VALUE io, VALUE events, VALUE se
VALUE result = rb_io_wait(io, events, timeout);
if (result == Qfalse) return INT2FIX(0);
else return result;
-#else
- struct timeval tv;
- if (!NIL_P(secs)) {
- tv.tv_sec = FIX2INT(secs);
- tv.tv_usec = FIX2INT(usecs);
- }
- int fd = io_spec_get_fd(io);
- return INT2FIX(rb_wait_for_single_fd(fd, FIX2INT(events), NIL_P(secs) ? NULL : &tv));
-#endif
}
VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) {
@@ -317,6 +287,18 @@ VALUE io_spec_rb_cloexec_open(VALUE self, VALUE path, VALUE flags, VALUE mode) {
return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(fd));
}
+VALUE io_spec_rb_cloexec_dup(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+ int new_fd = rb_cloexec_dup(fd);
+ return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd));
+}
+
+VALUE io_spec_rb_cloexec_fcntl_dupfd(VALUE self, VALUE io, VALUE minfd) {
+ int fd = io_spec_get_fd(io);
+ int new_fd = rb_cloexec_fcntl_dupfd(fd, FIX2INT(minfd));
+ return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd));
+}
+
VALUE io_spec_rb_io_close(VALUE self, VALUE io) {
return rb_io_close(io);
}
@@ -349,13 +331,7 @@ static VALUE io_spec_errno_set(VALUE self, VALUE val) {
VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
int mode;
-#ifdef RUBY_VERSION_IS_3_3
mode = rb_io_mode(io);
-#else
- rb_io_t *fp;
- GetOpenFile(io, fp);
- mode = fp->mode;
-#endif
if (mode & FMODE_SYNC) {
return Qtrue;
} else {
@@ -363,7 +339,6 @@ VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
}
}
-#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) {
return INT2FIX(rb_io_mode(io));
}
@@ -390,7 +365,6 @@ static VALUE io_spec_rb_io_open_descriptor(VALUE self, VALUE klass, VALUE descri
static VALUE io_spec_rb_io_open_descriptor_without_encoding(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout) {
return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, NULL);
}
-#endif
void Init_io_spec(void) {
VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject);
@@ -409,11 +383,9 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1);
rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2);
rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1);
-#ifdef RUBY_VERSION_IS_3_1
rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3);
rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4);
rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4);
-#endif
rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1);
rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1);
rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1);
@@ -423,9 +395,10 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1);
rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1);
rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3);
+ rb_define_method(cls, "rb_cloexec_dup", io_spec_rb_cloexec_dup, 1);
+ rb_define_method(cls, "rb_cloexec_fcntl_dupfd", io_spec_rb_cloexec_fcntl_dupfd, 2);
rb_define_method(cls, "errno=", io_spec_errno_set, 1);
rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1);
-#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
rb_define_method(cls, "rb_io_closed_p", io_spec_rb_io_closed_p, 1);
@@ -436,7 +409,6 @@ void Init_io_spec(void) {
rb_define_const(cls, "FMODE_BINMODE", INT2FIX(FMODE_BINMODE));
rb_define_const(cls, "FMODE_TEXTMODE", INT2FIX(FMODE_TEXTMODE));
rb_define_const(cls, "ECONV_UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR));
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c
index abd8d20ff4..eee324052d 100644
--- a/spec/ruby/optional/capi/ext/kernel_spec.c
+++ b/spec/ruby/optional/capi/ext/kernel_spec.c
@@ -1,4 +1,5 @@
#include "ruby.h"
+#include "ruby/vm.h"
#include "rubyspec.h"
#include <errno.h>
@@ -117,9 +118,11 @@ VALUE kernel_spec_rb_eval_string(VALUE self, VALUE str) {
return rb_eval_string(RSTRING_PTR(str));
}
+#ifndef RUBY_VERSION_IS_4_0
VALUE kernel_spec_rb_eval_cmd_kw(VALUE self, VALUE cmd, VALUE args, VALUE kw_splat) {
return rb_eval_cmd_kw(cmd, args, NUM2INT(kw_splat));
}
+#endif
VALUE kernel_spec_rb_raise(VALUE self, VALUE hash) {
rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("before")));
@@ -335,6 +338,15 @@ static VALUE kernel_spec_rb_set_end_proc(VALUE self, VALUE io) {
return Qnil;
}
+static void at_exit_hook(ruby_vm_t *vm) {
+ puts("ruby_vm_at_exit hook ran");
+}
+
+static VALUE kernel_spec_ruby_vm_at_exit(VALUE self) {
+ ruby_vm_at_exit(at_exit_hook);
+ return self;
+}
+
static VALUE kernel_spec_rb_f_sprintf(VALUE self, VALUE ary) {
return rb_f_sprintf((int)RARRAY_LEN(ary), RARRAY_PTR(ary));
}
@@ -351,7 +363,6 @@ static VALUE kernel_spec_rb_funcallv(VALUE self, VALUE obj, VALUE method, VALUE
return rb_funcallv(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args));
}
-#ifdef RUBY_VERSION_IS_3_0
static VALUE kernel_spec_rb_funcallv_kw(VALUE self, VALUE obj, VALUE method, VALUE args) {
return rb_funcallv_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), RB_PASS_KEYWORDS);
}
@@ -359,7 +370,6 @@ static VALUE kernel_spec_rb_funcallv_kw(VALUE self, VALUE obj, VALUE method, VAL
static VALUE kernel_spec_rb_keyword_given_p(int argc, VALUE *args, VALUE self) {
return rb_keyword_given_p() ? Qtrue : Qfalse;
}
-#endif
static VALUE kernel_spec_rb_funcallv_public(VALUE self, VALUE obj, VALUE method) {
return rb_funcallv_public(obj, SYM2ID(method), 0, NULL);
@@ -405,7 +415,9 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_category_warn_deprecated_with_integer_extra_value", kernel_spec_rb_category_warn_deprecated_with_integer_extra_value, 1);
rb_define_method(cls, "rb_ensure", kernel_spec_rb_ensure, 4);
rb_define_method(cls, "rb_eval_string", kernel_spec_rb_eval_string, 1);
+#ifndef RUBY_VERSION_IS_4_0
rb_define_method(cls, "rb_eval_cmd_kw", kernel_spec_rb_eval_cmd_kw, 3);
+#endif
rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1);
rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1);
rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2);
@@ -432,14 +444,13 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_yield_splat", kernel_spec_rb_yield_splat, 1);
rb_define_method(cls, "rb_exec_recursive", kernel_spec_rb_exec_recursive, 1);
rb_define_method(cls, "rb_set_end_proc", kernel_spec_rb_set_end_proc, 1);
+ rb_define_method(cls, "ruby_vm_at_exit", kernel_spec_ruby_vm_at_exit, 0);
rb_define_method(cls, "rb_f_sprintf", kernel_spec_rb_f_sprintf, 1);
rb_define_method(cls, "rb_str_format", kernel_spec_rb_str_format, 3);
rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0);
rb_define_method(cls, "rb_funcallv", kernel_spec_rb_funcallv, 3);
-#ifdef RUBY_VERSION_IS_3_0
rb_define_method(cls, "rb_funcallv_kw", kernel_spec_rb_funcallv_kw, 3);
rb_define_method(cls, "rb_keyword_given_p", kernel_spec_rb_keyword_given_p, -1);
-#endif
rb_define_method(cls, "rb_funcallv_public", kernel_spec_rb_funcallv_public, 2);
rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2);
rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 4);
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index aa60662e1e..995bc38fcf 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -15,11 +15,6 @@ static VALUE object_spec_FL_ABLE(VALUE self, VALUE obj) {
static int object_spec_FL_TEST_flag(VALUE flag_string) {
char *flag_cstr = StringValueCStr(flag_string);
-#ifndef RUBY_VERSION_IS_3_1
- if (strcmp(flag_cstr, "FL_TAINT") == 0) {
- return FL_TAINT;
- }
-#endif
if (strcmp(flag_cstr, "FL_FREEZE") == 0) {
return FL_FREEZE;
}
@@ -30,22 +25,6 @@ static VALUE object_spec_FL_TEST(VALUE self, VALUE obj, VALUE flag) {
return INT2FIX(FL_TEST(obj, object_spec_FL_TEST_flag(flag)));
}
-#ifndef RUBY_VERSION_IS_3_1
-static VALUE object_spec_OBJ_TAINT(VALUE self, VALUE obj) {
- OBJ_TAINT(obj);
- return Qnil;
-}
-
-static VALUE object_spec_OBJ_TAINTED(VALUE self, VALUE obj) {
- return OBJ_TAINTED(obj) ? Qtrue : Qfalse;
-}
-
-static VALUE object_spec_OBJ_INFECT(VALUE self, VALUE host, VALUE source) {
- OBJ_INFECT(host, source);
- return Qnil;
-}
-#endif
-
static VALUE object_spec_rb_any_to_s(VALUE self, VALUE obj) {
return rb_any_to_s(obj);
}
@@ -154,12 +133,6 @@ static VALUE object_specs_rb_obj_method(VALUE self, VALUE obj, VALUE method) {
return rb_obj_method(obj, method);
}
-#ifndef RUBY_VERSION_IS_3_2
-static VALUE object_spec_rb_obj_taint(VALUE self, VALUE obj) {
- return rb_obj_taint(obj);
-}
-#endif
-
static VALUE so_require(VALUE self) {
rb_require("fixtures/foo");
return Qnil;
@@ -410,15 +383,20 @@ static VALUE object_spec_custom_alloc_func_p(VALUE self, VALUE klass) {
return allocator ? Qtrue : Qfalse;
}
+static VALUE object_spec_redefine_frozen(VALUE self) {
+ // The purpose of this spec is to verify that `frozen?`
+ // and `RB_OBJ_FROZEN` do not mutually recurse infinitely.
+ if (RB_OBJ_FROZEN(self)) {
+ return Qtrue;
+ }
+
+ return Qfalse;
+}
+
void Init_object_spec(void) {
VALUE cls = rb_define_class("CApiObjectSpecs", rb_cObject);
rb_define_method(cls, "FL_ABLE", object_spec_FL_ABLE, 1);
rb_define_method(cls, "FL_TEST", object_spec_FL_TEST, 2);
-#ifndef RUBY_VERSION_IS_3_1
- rb_define_method(cls, "OBJ_TAINT", object_spec_OBJ_TAINT, 1);
- rb_define_method(cls, "OBJ_TAINTED", object_spec_OBJ_TAINTED, 1);
- rb_define_method(cls, "OBJ_INFECT", object_spec_OBJ_INFECT, 2);
-#endif
rb_define_method(cls, "rb_any_to_s", object_spec_rb_any_to_s, 1);
rb_define_method(cls, "rb_attr_get", so_attr_get, 2);
rb_define_method(cls, "rb_obj_instance_variables", object_spec_rb_obj_instance_variables, 1);
@@ -443,15 +421,11 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_obj_is_kind_of", so_kind_of, 2);
rb_define_method(cls, "rb_obj_method_arity", object_specs_rb_obj_method_arity, 2);
rb_define_method(cls, "rb_obj_method", object_specs_rb_obj_method, 2);
-#ifndef RUBY_VERSION_IS_3_2
- rb_define_method(cls, "rb_obj_taint", object_spec_rb_obj_taint, 1);
-#endif
rb_define_method(cls, "rb_require", so_require, 0);
rb_define_method(cls, "rb_respond_to", so_respond_to, 2);
rb_define_method(cls, "rb_method_boundp", object_spec_rb_method_boundp, 3);
rb_define_method(cls, "rb_obj_respond_to", so_obj_respond_to, 3);
rb_define_method(cls, "rb_special_const_p", object_spec_rb_special_const_p, 1);
-
rb_define_method(cls, "rb_to_id", so_to_id, 1);
rb_define_method(cls, "RTEST", object_spec_RTEST, 1);
rb_define_method(cls, "rb_check_type", so_check_type, 2);
@@ -491,6 +465,9 @@ void Init_object_spec(void) {
rb_define_method(cls, "custom_alloc_func?", object_spec_custom_alloc_func_p, 1);
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
+
+ cls = rb_define_class("CApiObjectRedefinitionSpecs", rb_cObject);
+ rb_define_method(cls, "frozen?", object_spec_redefine_frozen, 0);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/range_spec.c b/spec/ruby/optional/capi/ext/range_spec.c
index b0cf1a8662..9faed3e5ee 100644
--- a/spec/ruby/optional/capi/ext/range_spec.c
+++ b/spec/ruby/optional/capi/ext/range_spec.c
@@ -25,9 +25,9 @@ VALUE range_spec_rb_range_values(VALUE self, VALUE range) {
return ary;
}
-VALUE range_spec_rb_range_beg_len(VALUE self, VALUE range, VALUE begpv, VALUE lenpv, VALUE lenv, VALUE errv) {
- long begp = FIX2LONG(begpv);
- long lenp = FIX2LONG(lenpv);
+VALUE range_spec_rb_range_beg_len(VALUE self, VALUE range, VALUE lenv, VALUE errv) {
+ long begp = 0;
+ long lenp = 0;
long len = FIX2LONG(lenv);
int err = FIX2INT(errv);
VALUE ary = rb_ary_new();
@@ -38,11 +38,51 @@ VALUE range_spec_rb_range_beg_len(VALUE self, VALUE range, VALUE begpv, VALUE le
return ary;
}
+VALUE range_spec_rb_arithmetic_sequence_extract(VALUE self, VALUE object) {
+ VALUE ary = rb_ary_new();
+ rb_arithmetic_sequence_components_t components;
+
+ int status = rb_arithmetic_sequence_extract(object, &components);
+
+ if (!status) {
+ rb_ary_store(ary, 0, LONG2FIX(status));
+ return ary;
+ }
+
+ rb_ary_store(ary, 0, LONG2FIX(status));
+ rb_ary_store(ary, 1, components.begin);
+ rb_ary_store(ary, 2, components.end);
+ rb_ary_store(ary, 3, components.step);
+ rb_ary_store(ary, 4, components.exclude_end ? Qtrue : Qfalse);
+ return ary;
+}
+
+VALUE range_spec_rb_arithmetic_sequence_beg_len_step(VALUE self, VALUE aseq, VALUE lenv, VALUE errv) {
+ long begp = 0;
+ long lenp = 0;
+ long stepp = 0;
+
+ long len = FIX2LONG(lenv);
+ int err = FIX2INT(errv);
+
+ VALUE success = rb_arithmetic_sequence_beg_len_step(aseq, &begp, &lenp, &stepp, len, err);
+
+ VALUE ary = rb_ary_new();
+ rb_ary_store(ary, 0, success);
+ rb_ary_store(ary, 1, LONG2FIX(begp));
+ rb_ary_store(ary, 2, LONG2FIX(lenp));
+ rb_ary_store(ary, 3, LONG2FIX(stepp));
+
+ return ary;
+}
+
void Init_range_spec(void) {
VALUE cls = rb_define_class("CApiRangeSpecs", rb_cObject);
rb_define_method(cls, "rb_range_new", range_spec_rb_range_new, -1);
rb_define_method(cls, "rb_range_values", range_spec_rb_range_values, 1);
- rb_define_method(cls, "rb_range_beg_len", range_spec_rb_range_beg_len, 5);
+ rb_define_method(cls, "rb_range_beg_len", range_spec_rb_range_beg_len, 3);
+ rb_define_method(cls, "rb_arithmetic_sequence_extract", range_spec_rb_arithmetic_sequence_extract, 1);
+ rb_define_method(cls, "rb_arithmetic_sequence_beg_len_step", range_spec_rb_arithmetic_sequence_beg_len_step, 3);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/rbasic_spec.c b/spec/ruby/optional/capi/ext/rbasic_spec.c
index 26be2fed6d..5a95b92804 100644
--- a/spec/ruby/optional/capi/ext/rbasic_spec.c
+++ b/spec/ruby/optional/capi/ext/rbasic_spec.c
@@ -31,13 +31,6 @@ static const VALUE DATA_VISIBLE_BITS = FL_FREEZE | ~(FL_USER0 - 1);
#error "unsupported"
#endif
-
-#ifndef RUBY_VERSION_IS_3_1
-VALUE rbasic_spec_taint_flag(VALUE self) {
- return VALUE2NUM(RUBY_FL_TAINT);
-}
-#endif
-
VALUE rbasic_spec_freeze_flag(VALUE self) {
return VALUE2NUM(RUBY_FL_FREEZE);
}
@@ -93,9 +86,6 @@ static VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) {
void Init_rbasic_spec(void) {
VALUE cls = rb_define_class("CApiRBasicSpecs", rb_cObject);
-#ifndef RUBY_VERSION_IS_3_1
- rb_define_method(cls, "taint_flag", rbasic_spec_taint_flag, 0);
-#endif
rb_define_method(cls, "freeze_flag", rbasic_spec_freeze_flag, 0);
rb_define_method(cls, "get_flags", rbasic_spec_get_flags, 1);
rb_define_method(cls, "set_flags", rbasic_spec_set_flags, 2);
diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h
index 90073ab82e..5a92645785 100644
--- a/spec/ruby/optional/capi/ext/rubyspec.h
+++ b/spec/ruby/optional/capi/ext/rubyspec.h
@@ -35,24 +35,16 @@
(RUBY_API_VERSION_MAJOR == (major) && RUBY_API_VERSION_MINOR < (minor)))
#define RUBY_VERSION_SINCE(major,minor) (!RUBY_VERSION_BEFORE(major, minor))
-#if RUBY_VERSION_SINCE(3, 4)
-#define RUBY_VERSION_IS_3_4
-#endif
-
-#if RUBY_VERSION_SINCE(3, 3)
-#define RUBY_VERSION_IS_3_3
+#if RUBY_VERSION_SINCE(4, 1)
+#define RUBY_VERSION_IS_4_1
#endif
-#if RUBY_VERSION_SINCE(3, 2)
-#define RUBY_VERSION_IS_3_2
+#if RUBY_VERSION_SINCE(4, 0)
+#define RUBY_VERSION_IS_4_0
#endif
-#if RUBY_VERSION_SINCE(3, 1)
-#define RUBY_VERSION_IS_3_1
-#endif
-
-#if RUBY_VERSION_SINCE(3, 0)
-#define RUBY_VERSION_IS_3_0
+#if RUBY_VERSION_SINCE(3, 4)
+#define RUBY_VERSION_IS_3_4
#endif
#endif
diff --git a/spec/ruby/optional/capi/ext/set_spec.c b/spec/ruby/optional/capi/ext/set_spec.c
new file mode 100644
index 0000000000..11a271b361
--- /dev/null
+++ b/spec/ruby/optional/capi/ext/set_spec.c
@@ -0,0 +1,65 @@
+#include "ruby.h"
+#include "rubyspec.h"
+
+#ifdef RUBY_VERSION_IS_4_0
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RBOOL(x) ((x) ? Qtrue : Qfalse)
+
+int yield_element_and_arg(VALUE element, VALUE arg) {
+ return RTEST(rb_yield_values(2, element, arg)) ? ST_CONTINUE : ST_STOP;
+}
+
+VALUE set_spec_rb_set_foreach(VALUE self, VALUE set, VALUE arg) {
+ rb_set_foreach(set, yield_element_and_arg, arg);
+ return Qnil;
+}
+
+VALUE set_spec_rb_set_new(VALUE self) {
+ return rb_set_new();
+}
+
+VALUE set_spec_rb_set_new_capa(VALUE self, VALUE capa) {
+ return rb_set_new_capa(NUM2INT(capa));
+}
+
+VALUE set_spec_rb_set_lookup(VALUE self, VALUE set, VALUE element) {
+ return RBOOL(rb_set_lookup(set, element));
+}
+
+VALUE set_spec_rb_set_add(VALUE self, VALUE set, VALUE element) {
+ return RBOOL(rb_set_add(set, element));
+}
+
+VALUE set_spec_rb_set_clear(VALUE self, VALUE set) {
+ return rb_set_clear(set);
+}
+
+VALUE set_spec_rb_set_delete(VALUE self, VALUE set, VALUE element) {
+ return RBOOL(rb_set_delete(set, element));
+}
+
+VALUE set_spec_rb_set_size(VALUE self, VALUE set) {
+ return SIZET2NUM(rb_set_size(set));
+}
+
+void Init_set_spec(void) {
+ VALUE cls = rb_define_class("CApiSetSpecs", rb_cObject);
+
+ rb_define_method(cls, "rb_set_foreach", set_spec_rb_set_foreach, 2);
+ rb_define_method(cls, "rb_set_new", set_spec_rb_set_new, 0);
+ rb_define_method(cls, "rb_set_new_capa", set_spec_rb_set_new_capa, 1);
+ rb_define_method(cls, "rb_set_lookup", set_spec_rb_set_lookup, 2);
+ rb_define_method(cls, "rb_set_add", set_spec_rb_set_add, 2);
+ rb_define_method(cls, "rb_set_clear", set_spec_rb_set_clear, 1);
+ rb_define_method(cls, "rb_set_delete", set_spec_rb_set_delete, 2);
+ rb_define_method(cls, "rb_set_size", set_spec_rb_set_size, 1);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index a140c86347..8291b73ea4 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -12,6 +12,13 @@
extern "C" {
#endif
+#ifdef PTR2NUM
+#elif SIZEOF_VOIDP <= SIZEOF_LONG
+# define PTR2NUM(x) (LONG2NUM((long)(x)))
+#elif SIZEOF_VOIDP <= SIZEOF_LONG_LONG
+# define PTR2NUM(x) (LL2NUM((LONG_LONG)(x)))
+#endif
+
/* Make sure the RSTRING_PTR and the bytes are in native memory.
* On TruffleRuby RSTRING_PTR and the bytes remain in managed memory
* until they must be written to native memory.
@@ -252,16 +259,6 @@ VALUE string_spec_rb_str_new5(VALUE self, VALUE str, VALUE ptr, VALUE len) {
return rb_str_new5(str, RSTRING_PTR(ptr), FIX2INT(len));
}
-#ifndef RUBY_VERSION_IS_3_2
-VALUE string_spec_rb_tainted_str_new(VALUE self, VALUE str, VALUE len) {
- return rb_tainted_str_new(RSTRING_PTR(str), FIX2INT(len));
-}
-
-VALUE string_spec_rb_tainted_str_new2(VALUE self, VALUE str) {
- return rb_tainted_str_new2(RSTRING_PTR(str));
-}
-#endif
-
VALUE string_spec_rb_str_plus(VALUE self, VALUE str1, VALUE str2) {
return rb_str_plus(str1, str2);
}
@@ -306,6 +303,26 @@ VALUE string_spec_rb_str_substr(VALUE self, VALUE str, VALUE beg, VALUE len) {
return rb_str_substr(str, FIX2INT(beg), FIX2INT(len));
}
+VALUE string_spec_rb_str_subpos(VALUE self, VALUE str, VALUE beg) {
+ char* original = RSTRING_PTR(str);
+ char* end = RSTRING_END(str);
+ long len = rb_str_strlen(str);
+ char *p = rb_str_subpos(str, FIX2LONG(beg), &len);
+ if (p == NULL) {
+ return Qnil;
+ }
+
+ if (p >= original && p <= end) {
+ return rb_ary_new_from_args(2, LONG2FIX(p - RSTRING_PTR(str)), LONG2FIX(len));
+ } else {
+ rb_raise(rb_eRuntimeError, "the returned pointer is not inside the original string buffer");
+ }
+}
+
+VALUE string_spec_rb_str_sublen(VALUE self, VALUE str, VALUE pos) {
+ return LONG2FIX(rb_str_sublen(str, FIX2LONG(pos)));
+}
+
VALUE string_spec_rb_str_to_str(VALUE self, VALUE arg) {
return rb_str_to_str(arg);
}
@@ -318,6 +335,11 @@ VALUE string_spec_RSTRING_LENINT(VALUE self, VALUE str) {
return INT2FIX(RSTRING_LENINT(str));
}
+VALUE string_spec_RSTRING_PTR(VALUE self, VALUE str) {
+ char* ptr = RSTRING_PTR(str);
+ return PTR2NUM(ptr);
+}
+
VALUE string_spec_RSTRING_PTR_iterate(VALUE self, VALUE str) {
int i;
char* ptr;
@@ -403,6 +425,7 @@ VALUE string_spec_RSTRING_PTR_read(VALUE self, VALUE str, VALUE path) {
if (read(fd, buffer, 30) < 0) {
rb_syserr_fail(errno, "read");
}
+ rb_str_set_len(str, 30);
rb_str_modify_expand(str, 53);
rb_ary_push(capacities, SIZET2NUM(rb_str_capacity(str)));
@@ -450,6 +473,7 @@ static VALUE string_spec_rb_str_free(VALUE self, VALUE str) {
static VALUE string_spec_rb_sprintf1(VALUE self, VALUE str, VALUE repl) {
return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl));
}
+
static VALUE string_spec_rb_sprintf2(VALUE self, VALUE str, VALUE repl1, VALUE repl2) {
return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl1), RSTRING_PTR(repl2));
}
@@ -540,7 +564,10 @@ static VALUE string_spec_rb_str_modify(VALUE self, VALUE str) {
}
static VALUE string_spec_rb_utf8_str_new_static(VALUE self) {
- return rb_utf8_str_new_static("nokogiri", 8);
+ const char* literal = "nokogiri";
+ return rb_ary_new_from_args(2,
+ rb_utf8_str_new_static("nokogiri", 8),
+ PTR2NUM(literal));
}
static VALUE string_spec_rb_utf8_str_new(VALUE self) {
@@ -590,6 +617,14 @@ static VALUE string_spec_rb_str_to_interned_str(VALUE self, VALUE str) {
return rb_str_to_interned_str(str);
}
+static VALUE string_spec_rb_interned_str(VALUE self, VALUE str, VALUE len) {
+ return rb_interned_str(RSTRING_PTR(str), FIX2LONG(len));
+}
+
+static VALUE string_spec_rb_interned_str_cstr(VALUE self, VALUE str) {
+ return rb_interned_str_cstr(RSTRING_PTR(str));
+}
+
void Init_string_spec(void) {
VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject);
rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2);
@@ -635,10 +670,6 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_str_new3", string_spec_rb_str_new3, 1);
rb_define_method(cls, "rb_str_new4", string_spec_rb_str_new4, 1);
rb_define_method(cls, "rb_str_new5", string_spec_rb_str_new5, 3);
-#ifndef RUBY_VERSION_IS_3_2
- rb_define_method(cls, "rb_tainted_str_new", string_spec_rb_tainted_str_new, 2);
- rb_define_method(cls, "rb_tainted_str_new2", string_spec_rb_tainted_str_new2, 1);
-#endif
rb_define_method(cls, "rb_str_plus", string_spec_rb_str_plus, 2);
rb_define_method(cls, "rb_str_times", string_spec_rb_str_times, 2);
rb_define_method(cls, "rb_str_modify_expand", string_spec_rb_str_modify_expand, 2);
@@ -650,9 +681,12 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_str_split", string_spec_rb_str_split, 1);
rb_define_method(cls, "rb_str_subseq", string_spec_rb_str_subseq, 3);
rb_define_method(cls, "rb_str_substr", string_spec_rb_str_substr, 3);
+ rb_define_method(cls, "rb_str_subpos", string_spec_rb_str_subpos, 2);
+ rb_define_method(cls, "rb_str_sublen", string_spec_rb_str_sublen, 2);
rb_define_method(cls, "rb_str_to_str", string_spec_rb_str_to_str, 1);
rb_define_method(cls, "RSTRING_LEN", string_spec_RSTRING_LEN, 1);
rb_define_method(cls, "RSTRING_LENINT", string_spec_RSTRING_LENINT, 1);
+ rb_define_method(cls, "RSTRING_PTR", string_spec_RSTRING_PTR, 1);
rb_define_method(cls, "RSTRING_PTR_iterate", string_spec_RSTRING_PTR_iterate, 1);
rb_define_method(cls, "RSTRING_PTR_iterate_uint32", string_spec_RSTRING_PTR_iterate_uint32, 1);
rb_define_method(cls, "RSTRING_PTR_short_memcpy", string_spec_RSTRING_PTR_short_memcpy, 1);
@@ -694,6 +728,8 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2);
rb_define_method(cls, "rb_enc_interned_str", string_spec_rb_enc_interned_str, 3);
rb_define_method(cls, "rb_str_to_interned_str", string_spec_rb_str_to_interned_str, 1);
+ rb_define_method(cls, "rb_interned_str", string_spec_rb_interned_str, 2);
+ rb_define_method(cls, "rb_interned_str_cstr", string_spec_rb_interned_str_cstr, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c
index 413249e828..1c669d153e 100644
--- a/spec/ruby/optional/capi/ext/struct_spec.c
+++ b/spec/ruby/optional/capi/ext/struct_spec.c
@@ -62,7 +62,10 @@ static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) {
return rb_struct_size(st);
}
-#if defined(RUBY_VERSION_IS_3_3)
+static VALUE struct_spec_rb_struct_initialize(VALUE self, VALUE st, VALUE values) {
+ return rb_struct_initialize(st, values);
+}
+
/* Only allow setting three attributes, should be sufficient for testing. */
static VALUE struct_spec_rb_data_define(VALUE self, VALUE superclass,
VALUE attr1, VALUE attr2, VALUE attr3) {
@@ -77,7 +80,6 @@ static VALUE struct_spec_rb_data_define(VALUE self, VALUE superclass,
return rb_data_define(superclass, a1, a2, a3, NULL);
}
-#endif
void Init_struct_spec(void) {
VALUE cls = rb_define_class("CApiStructSpecs", rb_cObject);
@@ -90,9 +92,8 @@ void Init_struct_spec(void) {
rb_define_method(cls, "rb_struct_define_under", struct_spec_rb_struct_define_under, 5);
rb_define_method(cls, "rb_struct_new", struct_spec_rb_struct_new, 4);
rb_define_method(cls, "rb_struct_size", struct_spec_rb_struct_size, 1);
-#if defined(RUBY_VERSION_IS_3_3)
+ rb_define_method(cls, "rb_struct_initialize", struct_spec_rb_struct_initialize, 2);
rb_define_method(cls, "rb_data_define", struct_spec_rb_data_define, 4);
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c
index 3511c2fbcf..ac77e4e813 100644
--- a/spec/ruby/optional/capi/ext/thread_spec.c
+++ b/spec/ruby/optional/capi/ext/thread_spec.c
@@ -118,7 +118,6 @@ static VALUE thread_spec_rb_thread_wait_for(VALUE self, VALUE s, VALUE ms) {
return Qnil;
}
-
VALUE thread_spec_call_proc(void *arg_ptr) {
VALUE arg_array = (VALUE)arg_ptr;
VALUE arg = rb_ary_pop(arg_array);
@@ -167,6 +166,12 @@ static VALUE thread_spec_ruby_native_thread_p_new_thread(VALUE self) {
#endif
}
+#ifdef RUBY_VERSION_IS_4_0
+static VALUE thread_spec_ruby_thread_has_gvl_p(VALUE self) {
+ return ruby_thread_has_gvl_p() ? Qtrue : Qfalse;
+}
+#endif
+
void Init_thread_spec(void) {
VALUE cls = rb_define_class("CApiThreadSpecs", rb_cObject);
rb_define_method(cls, "rb_thread_alone", thread_spec_rb_thread_alone, 0);
@@ -180,6 +185,9 @@ void Init_thread_spec(void) {
rb_define_method(cls, "rb_thread_create", thread_spec_rb_thread_create, 2);
rb_define_method(cls, "ruby_native_thread_p", thread_spec_ruby_native_thread_p, 0);
rb_define_method(cls, "ruby_native_thread_p_new_thread", thread_spec_ruby_native_thread_p_new_thread, 0);
+#ifdef RUBY_VERSION_IS_4_0
+ rb_define_method(cls, "ruby_thread_has_gvl_p", thread_spec_ruby_thread_has_gvl_p, 0);
+#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c
index 221f1c8ac4..c6fcfa3bc8 100644
--- a/spec/ruby/optional/capi/ext/typed_data_spec.c
+++ b/spec/ruby/optional/capi/ext/typed_data_spec.c
@@ -106,6 +106,7 @@ VALUE sws_typed_wrap_struct(VALUE self, VALUE val) {
return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar);
}
+#ifndef RUBY_VERSION_IS_4_1
#undef RUBY_UNTYPED_DATA_WARNING
#define RUBY_UNTYPED_DATA_WARNING 0
VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) {
@@ -113,6 +114,7 @@ VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) {
*data = FIX2INT(val);
return Data_Wrap_Struct(rb_cObject, NULL, free, data);
}
+#endif
VALUE sws_typed_get_struct(VALUE self, VALUE obj) {
struct sample_typed_wrapped_struct* bar;
@@ -173,9 +175,11 @@ VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}
+#ifndef RUBY_VERSION_IS_4_1
VALUE sws_typed_RTYPEDDATA_P(VALUE self, VALUE obj) {
return RTYPEDDATA_P(obj) ? Qtrue : Qfalse;
}
+#endif
void Init_typed_data_spec(void) {
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
@@ -183,7 +187,9 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "typed_wrapped_data", sdaf_typed_get_struct, 0);
cls = rb_define_class("CApiWrappedTypedStructSpecs", rb_cObject);
rb_define_method(cls, "typed_wrap_struct", sws_typed_wrap_struct, 1);
+#ifndef RUBY_VERSION_IS_4_1
rb_define_method(cls, "untyped_wrap_struct", sws_untyped_wrap_struct, 1);
+#endif
rb_define_method(cls, "typed_get_struct", sws_typed_get_struct, 1);
rb_define_method(cls, "typed_get_struct_other", sws_typed_get_struct_different_type, 1);
rb_define_method(cls, "typed_get_struct_parent", sws_typed_get_struct_parent_type, 1);
@@ -194,10 +200,11 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
+#ifndef RUBY_VERSION_IS_4_1
rb_define_method(cls, "RTYPEDDATA_P", sws_typed_RTYPEDDATA_P, 1);
+#endif
}
#ifdef __cplusplus
}
#endif
-
diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c
index b5bde420d2..043da99ace 100644
--- a/spec/ruby/optional/capi/ext/util_spec.c
+++ b/spec/ruby/optional/capi/ext/util_spec.c
@@ -20,15 +20,11 @@ VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected,
a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1);
-#ifdef RB_SCAN_ARGS_KEYWORDS
if (*RSTRING_PTR(fmt) == 'k') {
result = rb_scan_args_kw(RB_SCAN_ARGS_KEYWORDS, argc, args, RSTRING_PTR(fmt)+1, &a1, &a2, &a3, &a4, &a5, &a6);
} else {
-#endif
result = rb_scan_args(argc, args, RSTRING_PTR(fmt), &a1, &a2, &a3, &a4, &a5, &a6);
-#ifdef RB_SCAN_ARGS_KEYWORDS
}
-#endif
switch(NUM2INT(expected)) {
case 6:
diff --git a/spec/ruby/optional/capi/fiber_spec.rb b/spec/ruby/optional/capi/fiber_spec.rb
index 05d867498c..c820ba17c2 100644
--- a/spec/ruby/optional/capi/fiber_spec.rb
+++ b/spec/ruby/optional/capi/fiber_spec.rb
@@ -10,7 +10,7 @@ describe "C-API Fiber function" do
describe "rb_fiber_current" do
it "returns the current fiber" do
result = @s.rb_fiber_current()
- result.should be_an_instance_of(Fiber)
+ result.should.instance_of?(Fiber)
result.should == Fiber.current
end
end
@@ -19,9 +19,9 @@ describe "C-API Fiber function" do
it "returns the fibers alive status" do
fiber = Fiber.new { Fiber.yield }
fiber.resume
- @s.rb_fiber_alive_p(fiber).should be_true
+ @s.rb_fiber_alive_p(fiber).should == true
fiber.resume
- @s.rb_fiber_alive_p(fiber).should be_false
+ @s.rb_fiber_alive_p(fiber).should == false
end
end
@@ -43,7 +43,7 @@ describe "C-API Fiber function" do
describe "rb_fiber_new" do
it "returns a new fiber" do
fiber = @s.rb_fiber_new
- fiber.should be_an_instance_of(Fiber)
+ fiber.should.instance_of?(Fiber)
fiber.resume(42).should == "42"
end
end
@@ -61,7 +61,7 @@ describe "C-API Fiber function" do
fiber.resume
result = @s.rb_fiber_raise(fiber, "Boom!")
- result.should be_an_instance_of(RuntimeError)
+ result.should.instance_of?(RuntimeError)
result.message.should == "Boom!"
end
@@ -79,7 +79,7 @@ describe "C-API Fiber function" do
fiber.transfer
result = @s.rb_fiber_raise(fiber, "Boom!")
- result.should be_an_instance_of(RuntimeError)
+ result.should.instance_of?(RuntimeError)
result.message.should == "Boom!"
end
end
diff --git a/spec/ruby/optional/capi/file_spec.rb b/spec/ruby/optional/capi/file_spec.rb
index 12449b4e34..fd63aed316 100644
--- a/spec/ruby/optional/capi/file_spec.rb
+++ b/spec/ruby/optional/capi/file_spec.rb
@@ -5,13 +5,13 @@ load_extension('file')
describe :rb_file_open, shared: true do
it "raises an ArgumentError if passed an empty mode string" do
touch @name
- -> { @s.rb_file_open(@name, "") }.should raise_error(ArgumentError)
+ -> { @s.rb_file_open(@name, "") }.should.raise(ArgumentError)
end
it "opens a file in read-only mode with 'r'" do
touch(@name) { |f| f.puts "readable" }
@file = @s.send(@method, @name, "r")
- @file.should be_an_instance_of(File)
+ @file.should.instance_of?(File)
@file.read.chomp.should == "readable"
end
@@ -65,13 +65,13 @@ describe "C-API File function" do
describe "FilePathValue" do
it "returns a String argument unchanged" do
obj = "path"
- @s.FilePathValue(obj).should eql(obj)
+ @s.FilePathValue(obj).should.eql?(obj)
end
it "does not call #to_str on a String" do
obj = +"path"
obj.should_not_receive(:to_str)
- @s.FilePathValue(obj).should eql(obj)
+ @s.FilePathValue(obj).should.eql?(obj)
end
it "calls #to_path to convert an object to a String" do
diff --git a/spec/ruby/optional/capi/fixnum_spec.rb b/spec/ruby/optional/capi/fixnum_spec.rb
index e691aa3893..73751c4895 100644
--- a/spec/ruby/optional/capi/fixnum_spec.rb
+++ b/spec/ruby/optional/capi/fixnum_spec.rb
@@ -27,7 +27,7 @@ describe "CApiFixnumSpecs" do
platform_is c_long_size: 64 do # sizeof(long) > sizeof(int)
it "raises a TypeError if passed nil" do
- -> { @s.FIX2INT(nil) }.should raise_error(TypeError)
+ -> { @s.FIX2INT(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -39,16 +39,16 @@ describe "CApiFixnumSpecs" do
end
it "raises a RangeError if the value does not fit a native int" do
- -> { @s.FIX2INT(0x7fff_ffff+1) }.should raise_error(RangeError)
- -> { @s.FIX2INT(-(1 << 31) - 1) }.should raise_error(RangeError)
+ -> { @s.FIX2INT(0x7fff_ffff+1) }.should.raise(RangeError)
+ -> { @s.FIX2INT(-(1 << 31) - 1) }.should.raise(RangeError)
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.FIX2INT(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.FIX2INT(0xffff_ffff+1) }.should.raise(RangeError)
end
it "raises a RangeError if the value is more than 64bits" do
- -> { @s.FIX2INT(0xffff_ffff_ffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.FIX2INT(0xffff_ffff_ffff_ffff+1) }.should.raise(RangeError)
end
it "calls #to_int to coerce the value" do
@@ -76,7 +76,7 @@ describe "CApiFixnumSpecs" do
platform_is c_long_size: 64 do # sizeof(long) > sizeof(int)
it "raises a TypeError if passed nil" do
- -> { @s.FIX2UINT(nil) }.should raise_error(TypeError)
+ -> { @s.FIX2UINT(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -85,16 +85,16 @@ describe "CApiFixnumSpecs" do
it "raises a RangeError if the value does not fit a native uint" do
# Interestingly, on MRI FIX2UINT(-1) is allowed
- -> { @s.FIX2UINT(0xffff_ffff+1) }.should raise_error(RangeError)
- -> { @s.FIX2UINT(-(1 << 31) - 1) }.should raise_error(RangeError)
+ -> { @s.FIX2UINT(0xffff_ffff+1) }.should.raise(RangeError)
+ -> { @s.FIX2UINT(-(1 << 31) - 1) }.should.raise(RangeError)
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.FIX2UINT(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.FIX2UINT(0xffff_ffff+1) }.should.raise(RangeError)
end
it "raises a RangeError if the value is more than 64bits" do
- -> { @s.FIX2UINT(0xffff_ffff_ffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.FIX2UINT(0xffff_ffff_ffff_ffff+1) }.should.raise(RangeError)
end
end
end
diff --git a/spec/ruby/optional/capi/fixtures/class.rb b/spec/ruby/optional/capi/fixtures/class.rb
index 2560fef17d..b463e3b4c3 100644
--- a/spec/ruby/optional/capi/fixtures/class.rb
+++ b/spec/ruby/optional/capi/fixtures/class.rb
@@ -101,14 +101,4 @@ class CApiClassSpecs
module M
end
end
-
- class Callbacks
- def self.inherited(child)
- ScratchPad << [:inherited, child.name, Object.const_source_location(child.name) ? :location : :unknown_location]
- end
-
- def self.const_added(const_name)
- ScratchPad << [:const_added, const_name, const_source_location(const_name) ? :location : :unknown_location]
- end
- end
end
diff --git a/spec/ruby/optional/capi/float_spec.rb b/spec/ruby/optional/capi/float_spec.rb
index 4b98902b59..5b02483b28 100644
--- a/spec/ruby/optional/capi/float_spec.rb
+++ b/spec/ruby/optional/capi/float_spec.rb
@@ -23,8 +23,8 @@ describe "CApiFloatSpecs" do
describe "rb_Float" do
it "creates a new Float from a String" do
f = @f.rb_Float("101.99")
- f.should be_kind_of(Float)
- f.should eql(101.99)
+ f.should.is_a?(Float)
+ f.should.eql?(101.99)
end
end
diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb
index d9661328ab..8b70ea4758 100644
--- a/spec/ruby/optional/capi/gc_spec.rb
+++ b/spec/ruby/optional/capi/gc_spec.rb
@@ -7,12 +7,30 @@ describe "CApiGCSpecs" do
@f = CApiGCSpecs.new
end
+ describe "RB_GC_GUARD" do
+ it "forces an object to on stack so it cannot be GC'd early" do
+ @f.RB_GC_GUARD_keep_alive([%w[ab cd ef].join]).should == "abc"
+ end
+
+ it "can be used with any Ruby object" do
+ @f.RB_GC_GUARD(true).should == true
+ @f.RB_GC_GUARD(42).should == 42
+ @f.RB_GC_GUARD(self).should == self
+ end
+
+ it "tolerates being passed invalid pointers" do
+ (0...256).each do |address|
+ @f.RB_GC_GUARD_raw(address).should == nil
+ end
+ end
+ end
+
describe "rb_gc_register_address" do
it "correctly gets the value from a registered address" do
@f.registered_tagged_address.should == 10
- @f.registered_tagged_address.should equal(@f.registered_tagged_address)
+ @f.registered_tagged_address.should.equal?(@f.registered_tagged_address)
@f.registered_reference_address.should == "Globally registered data"
- @f.registered_reference_address.should equal(@f.registered_reference_address)
+ @f.registered_reference_address.should.equal?(@f.registered_reference_address)
end
it "keeps the value alive even if the value is assigned after rb_gc_register_address() is called" do
@@ -67,22 +85,22 @@ describe "CApiGCSpecs" do
it "enables GC when disabled" do
GC.disable
- @f.rb_gc_enable.should be_true
+ @f.rb_gc_enable.should == true
end
it "GC stays enabled when enabled" do
GC.enable
- @f.rb_gc_enable.should be_false
+ @f.rb_gc_enable.should == false
end
it "disables GC when enabled" do
GC.enable
- @f.rb_gc_disable.should be_false
+ @f.rb_gc_disable.should == false
end
it "GC stays disabled when disabled" do
GC.disable
- @f.rb_gc_disable.should be_true
+ @f.rb_gc_disable.should == true
end
end
@@ -100,13 +118,13 @@ describe "CApiGCSpecs" do
-> {
@f.rb_gc_adjust_memory_usage(8)
@f.rb_gc_adjust_memory_usage(-8)
- }.should_not raise_error
+ }.should_not.raise
end
end
describe "rb_gc_register_mark_object" do
it "can be called with an object" do
- @f.rb_gc_register_mark_object(Object.new).should be_nil
+ @f.rb_gc_register_mark_object(Object.new).should == nil
end
it "keeps the value alive even if the value is not referenced by any Ruby object" do
@@ -116,11 +134,11 @@ describe "CApiGCSpecs" do
describe "rb_gc_latest_gc_info" do
it "raises a TypeError when hash or symbol not given" do
- -> { @f.rb_gc_latest_gc_info("foo") }.should raise_error(TypeError)
+ -> { @f.rb_gc_latest_gc_info("foo") }.should.raise(TypeError)
end
it "raises an ArgumentError when unknown symbol given" do
- -> { @f.rb_gc_latest_gc_info(:unknown) }.should raise_error(ArgumentError)
+ -> { @f.rb_gc_latest_gc_info(:unknown) }.should.raise(ArgumentError)
end
it "returns the populated hash when a hash is given" do
@@ -130,7 +148,7 @@ describe "CApiGCSpecs" do
end
it "returns a value when symbol is given" do
- @f.rb_gc_latest_gc_info(:state).should be_kind_of(Symbol)
+ @f.rb_gc_latest_gc_info(:state).should.is_a?(Symbol)
end
end
end
diff --git a/spec/ruby/optional/capi/globals_spec.rb b/spec/ruby/optional/capi/globals_spec.rb
index 48677620bc..03316c256c 100644
--- a/spec/ruby/optional/capi/globals_spec.rb
+++ b/spec/ruby/optional/capi/globals_spec.rb
@@ -41,14 +41,19 @@ describe "CApiGlobalSpecs" do
@f.sb_get_global_value.should == "XYZ"
end
+ run = 0
+
it "rb_define_readonly_variable should define a new readonly global variable" do
+ name = "ro_gvar#{run += 1}"
+ eval <<~RUBY
# Check the gvar doesn't exist and ensure rb_gv_get doesn't implicitly declare the gvar,
# otherwise the rb_define_readonly_variable call will conflict.
- suppress_warning { @f.sb_gv_get("ro_gvar") } .should == nil
+ suppress_warning { @f.sb_gv_get("#{name}") }.should == nil
- @f.rb_define_readonly_variable("ro_gvar", 15)
- $ro_gvar.should == 15
- -> { $ro_gvar = 10 }.should raise_error(NameError)
+ @f.rb_define_readonly_variable("#{name}", 15)
+ $#{name}.should == 15
+ -> { $#{name} = 10 }.should.raise(NameError)
+ RUBY
end
it "rb_define_hooked_variable should define a C hooked global variable" do
@@ -75,7 +80,7 @@ describe "CApiGlobalSpecs" do
end
it "is read-only" do
- -> { $virtual_variable_default_accessors = 10 }.should raise_error(NameError, /read-only/)
+ -> { $virtual_variable_default_accessors = 10 }.should.raise(NameError, /read-only/)
end
it "returns false with the default getter" do
@@ -159,7 +164,7 @@ describe "CApiGlobalSpecs" do
it "returns $stdin" do
$stdin = @stream
- @f.rb_stdin.should equal($stdin)
+ @f.rb_stdin.should.equal?($stdin)
end
end
@@ -170,7 +175,7 @@ describe "CApiGlobalSpecs" do
it "returns $stdout" do
$stdout = @stream
- @f.rb_stdout.should equal($stdout)
+ @f.rb_stdout.should.equal?($stdout)
end
end
@@ -181,7 +186,7 @@ describe "CApiGlobalSpecs" do
it "returns $stderr" do
$stderr = @stream
- @f.rb_stderr.should equal($stderr)
+ @f.rb_stderr.should.equal?($stderr)
end
end
@@ -192,7 +197,7 @@ describe "CApiGlobalSpecs" do
it "is an alias of rb_stdout" do
$stdout = @stream
- @f.rb_defout.should equal($stdout)
+ @f.rb_defout.should.equal?($stdout)
end
end
end
@@ -213,7 +218,7 @@ describe "CApiGlobalSpecs" do
end
it "returns nil by default" do
- @f.rb_output_rs.should be_nil
+ @f.rb_output_rs.should == nil
end
it "returns the value of $\\" do
@@ -232,7 +237,7 @@ describe "CApiGlobalSpecs" do
end
it "returns nil by default" do
- @f.rb_output_fs.should be_nil
+ @f.rb_output_fs.should == nil
end
it "returns the value of $\\" do
@@ -258,7 +263,7 @@ describe "CApiGlobalSpecs" do
end
Thread.pass while thr.status and !running
- $_.should be_nil
+ $_.should == nil
thr.join
end
@@ -285,7 +290,7 @@ describe "CApiGlobalSpecs" do
end
Thread.pass while thr.status and !running
- $_.should be_nil
+ $_.should == nil
thr.join
end
diff --git a/spec/ruby/optional/capi/hash_spec.rb b/spec/ruby/optional/capi/hash_spec.rb
index 08e03fcb26..842bc82b97 100644
--- a/spec/ruby/optional/capi/hash_spec.rb
+++ b/spec/ruby/optional/capi/hash_spec.rb
@@ -36,7 +36,7 @@ describe "C-API Hash function" do
obj = mock("rb_hash no to_int")
obj.should_receive(:hash).and_return(nil)
- -> { @s.rb_hash(obj) }.should raise_error(TypeError)
+ -> { @s.rb_hash(obj) }.should.raise(TypeError)
end
end
@@ -46,23 +46,21 @@ describe "C-API Hash function" do
end
it "creates a hash with no default proc" do
- @s.rb_hash_new {}.default_proc.should be_nil
+ @s.rb_hash_new {}.default_proc.should == nil
end
end
- ruby_version_is '3.2' do
- describe "rb_hash_new_capa" do
- it "returns a new hash" do
- @s.rb_hash_new_capa(3).should == {}
- end
+ describe "rb_hash_new_capa" do
+ it "returns a new hash" do
+ @s.rb_hash_new_capa(3).should == {}
+ end
- it "creates a hash with no default proc" do
- @s.rb_hash_new_capa(3) {}.default_proc.should be_nil
- end
+ it "creates a hash with no default proc" do
+ @s.rb_hash_new_capa(3) {}.default_proc.should == nil
+ end
- it "raises RuntimeError when negative index is provided" do
- -> { @s.rb_hash_new_capa(-1) }.should raise_error(RuntimeError, "st_table too big")
- end
+ it "raises RuntimeError when negative index is provided" do
+ -> { @s.rb_hash_new_capa(-1) }.should.raise(RuntimeError, "st_table too big")
end
end
@@ -79,13 +77,13 @@ describe "C-API Hash function" do
hsh = {}
dup = @s.rb_hash_dup(hsh)
dup.should == hsh
- dup.should_not equal(hsh)
+ dup.should_not.equal?(hsh)
end
end
describe "rb_hash_freeze" do
it "freezes the hash" do
- @s.rb_hash_freeze({}).frozen?.should be_true
+ @s.rb_hash_freeze({}).frozen?.should == true
end
end
@@ -98,13 +96,13 @@ describe "C-API Hash function" do
it "returns the default value if it exists" do
hsh = Hash.new(0)
@s.rb_hash_aref(hsh, :chunky).should == 0
- @s.rb_hash_aref_nil(hsh, :chunky).should be_false
+ @s.rb_hash_aref_nil(hsh, :chunky).should == false
end
it "returns nil if the key does not exist" do
hsh = { }
- @s.rb_hash_aref(hsh, :chunky).should be_nil
- @s.rb_hash_aref_nil(hsh, :chunky).should be_true
+ @s.rb_hash_aref(hsh, :chunky).should == nil
+ @s.rb_hash_aref_nil(hsh, :chunky).should == true
end
end
@@ -119,7 +117,7 @@ describe "C-API Hash function" do
describe "rb_hash_clear" do
it "returns self that cleared keys and values" do
hsh = { :key => 'value' }
- @s.rb_hash_clear(hsh).should equal(hsh)
+ @s.rb_hash_clear(hsh).should.equal?(hsh)
hsh.should == {}
end
end
@@ -140,7 +138,7 @@ describe "C-API Hash function" do
end
it "returns an Enumerator when no block is passed" do
- @s.rb_hash_delete_if({a: 1}).should be_an_instance_of(Enumerator)
+ @s.rb_hash_delete_if({a: 1}).should.instance_of?(Enumerator)
end
end
@@ -155,11 +153,11 @@ describe "C-API Hash function" do
it "raises a KeyError if the key is not found and default is set" do
@hsh.default = :d
- -> { @s.rb_hash_fetch(@hsh, :c) }.should raise_error(KeyError)
+ -> { @s.rb_hash_fetch(@hsh, :c) }.should.raise(KeyError)
end
it "raises a KeyError if the key is not found and no default is set" do
- -> { @s.rb_hash_fetch(@hsh, :c) }.should raise_error(KeyError)
+ -> { @s.rb_hash_fetch(@hsh, :c) }.should.raise(KeyError)
end
context "when key is not found" do
@@ -268,14 +266,14 @@ describe "C-API Hash function" do
it "does not return the default value if it exists" do
hsh = Hash.new(0)
- @s.rb_hash_lookup(hsh, :chunky).should be_nil
- @s.rb_hash_lookup_nil(hsh, :chunky).should be_true
+ @s.rb_hash_lookup(hsh, :chunky).should == nil
+ @s.rb_hash_lookup_nil(hsh, :chunky).should == true
end
it "returns nil if the key does not exist" do
hsh = { }
- @s.rb_hash_lookup(hsh, :chunky).should be_nil
- @s.rb_hash_lookup_nil(hsh, :chunky).should be_true
+ @s.rb_hash_lookup(hsh, :chunky).should == nil
+ @s.rb_hash_lookup_nil(hsh, :chunky).should == true
end
describe "rb_hash_lookup2" do
@@ -293,7 +291,7 @@ describe "C-API Hash function" do
it "returns undefined if that is the default value specified" do
hsh = Hash.new(0)
- @s.rb_hash_lookup2_default_undef(hsh, :chunky).should be_true
+ @s.rb_hash_lookup2_default_undef(hsh, :chunky).should == true
end
end
end
@@ -324,20 +322,20 @@ describe "C-API Hash function" do
end
it "raises a TypeError if the argument does not respond to #to_hash" do
- -> { @s.rb_Hash(42) }.should raise_error(TypeError)
+ -> { @s.rb_Hash(42) }.should.raise(TypeError)
end
it "raises a TypeError if #to_hash does not return a hash" do
h = BasicObject.new
def h.to_hash; 42; end
- -> { @s.rb_Hash(h) }.should raise_error(TypeError)
+ -> { @s.rb_Hash(h) }.should.raise(TypeError)
end
end
describe "hash code functions" do
it "computes a deterministic number" do
hash_code = @s.compute_a_hash_code(53)
- hash_code.should be_an_instance_of(Integer)
+ hash_code.should.instance_of?(Integer)
hash_code.should == @s.compute_a_hash_code(53)
@s.compute_a_hash_code(90).should == @s.compute_a_hash_code(90)
end
diff --git a/spec/ruby/optional/capi/integer_spec.rb b/spec/ruby/optional/capi/integer_spec.rb
index 089872381c..f177374569 100644
--- a/spec/ruby/optional/capi/integer_spec.rb
+++ b/spec/ruby/optional/capi/integer_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative 'spec_helper'
load_extension("integer")
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index ab7a7fc8f6..35bd856e00 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -15,7 +15,7 @@ describe "C-API IO function" do
end
after :each do
- @io.close unless @io.closed?
+ @io.close
rm_r @name
end
@@ -34,7 +34,7 @@ describe "C-API IO function" do
end
it "returns the io" do
- @o.rb_io_addstr(@io, "rb_io_addstr data").should eql(@io)
+ @o.rb_io_addstr(@io, "rb_io_addstr data").should.eql?(@io)
end
end
@@ -118,15 +118,15 @@ describe "C-API IO function" do
end
after :each do
- @io.close unless @io.closed?
+ @io.close
rm_r @name
end
describe "rb_io_close" do
it "closes an IO object" do
- @io.closed?.should be_false
+ @io.closed?.should == false
@o.rb_io_close(@io)
- @io.closed?.should be_true
+ @io.closed?.should == true
end
end
@@ -136,19 +136,19 @@ describe "C-API IO function" do
end
it "returns nil for non IO objects" do
- @o.rb_io_check_io({}).should be_nil
+ @o.rb_io_check_io({}).should == nil
end
end
describe "rb_io_check_closed" do
it "does not raise an exception if the IO is not closed" do
# The MRI function is void, so we use should_not raise_error
- -> { @o.rb_io_check_closed(@io) }.should_not raise_error
+ -> { @o.rb_io_check_closed(@io) }.should_not.raise
end
it "raises an error if the IO is closed" do
@io.close
- -> { @o.rb_io_check_closed(@io) }.should raise_error(IOError)
+ -> { @o.rb_io_check_closed(@io) }.should.raise(IOError)
end
end
@@ -157,7 +157,7 @@ describe "C-API IO function" do
it "returns true when nonblock flag is set" do
require 'io/nonblock'
@o.rb_io_set_nonblock(@io)
- @io.nonblock?.should be_true
+ @io.nonblock?.should == true
end
end
end
@@ -166,13 +166,13 @@ describe "C-API IO function" do
# object is frozen, *not* if it's tainted.
describe "rb_io_taint_check" do
it "does not raise an exception if the IO is not frozen" do
- -> { @o.rb_io_taint_check(@io) }.should_not raise_error
+ -> { @o.rb_io_taint_check(@io) }.should_not.raise
end
it "raises an exception if the IO is frozen" do
@io.freeze
- -> { @o.rb_io_taint_check(@io) }.should raise_error(RuntimeError)
+ -> { @o.rb_io_taint_check(@io) }.should.raise(RuntimeError)
end
end
@@ -186,7 +186,7 @@ describe "C-API IO function" do
it "raises IOError if the IO is closed" do
@io.close
- -> { @o.GetOpenFile_fd(@io) }.should raise_error(IOError, "closed stream")
+ -> { @o.GetOpenFile_fd(@io) }.should.raise(IOError, "closed stream")
end
end
@@ -197,7 +197,7 @@ describe "C-API IO function" do
it "sets binmode" do
@o.rb_io_binmode(@io)
- @io.binmode?.should be_true
+ @io.binmode?.should == true
end
end
end
@@ -213,24 +213,24 @@ describe "C-API IO function" do
end
after :each do
- @r_io.close unless @r_io.closed?
- @w_io.close unless @w_io.closed?
- @rw_io.close unless @rw_io.closed?
+ @r_io.close
+ @w_io.close
+ @rw_io.close
rm_r @name
end
describe "rb_io_check_readable" do
it "does not raise an exception if the IO is opened for reading" do
# The MRI function is void, so we use should_not raise_error
- -> { @o.rb_io_check_readable(@r_io) }.should_not raise_error
+ -> { @o.rb_io_check_readable(@r_io) }.should_not.raise
end
it "does not raise an exception if the IO is opened for read and write" do
- -> { @o.rb_io_check_readable(@rw_io) }.should_not raise_error
+ -> { @o.rb_io_check_readable(@rw_io) }.should_not.raise
end
it "raises an IOError if the IO is not opened for reading" do
- -> { @o.rb_io_check_readable(@w_io) }.should raise_error(IOError)
+ -> { @o.rb_io_check_readable(@w_io) }.should.raise(IOError)
end
end
@@ -238,27 +238,27 @@ describe "C-API IO function" do
describe "rb_io_check_writable" do
it "does not raise an exception if the IO is opened for writing" do
# The MRI function is void, so we use should_not raise_error
- -> { @o.rb_io_check_writable(@w_io) }.should_not raise_error
+ -> { @o.rb_io_check_writable(@w_io) }.should_not.raise
end
it "does not raise an exception if the IO is opened for read and write" do
- -> { @o.rb_io_check_writable(@rw_io) }.should_not raise_error
+ -> { @o.rb_io_check_writable(@rw_io) }.should_not.raise
end
it "raises an IOError if the IO is not opened for reading" do
- -> { @o.rb_io_check_writable(@r_io) }.should raise_error(IOError)
+ -> { @o.rb_io_check_writable(@r_io) }.should.raise(IOError)
end
end
describe "rb_io_wait_writable" do
it "returns false if there is no error condition" do
@o.errno = 0
- @o.rb_io_wait_writable(@w_io).should be_false
+ @o.rb_io_wait_writable(@w_io).should == false
end
it "raises an IOError if the IO is closed" do
@w_io.close
- -> { @o.rb_io_wait_writable(@w_io) }.should raise_error(IOError)
+ -> { @o.rb_io_wait_writable(@w_io) }.should.raise(IOError)
end
end
@@ -273,11 +273,11 @@ describe "C-API IO function" do
it "raises an IOError if the IO is closed" do
@w_io.close
- -> { @o.rb_io_maybe_wait_writable(0, @w_io, nil) }.should raise_error(IOError, "closed stream")
+ -> { @o.rb_io_maybe_wait_writable(0, @w_io, nil) }.should.raise(IOError, "closed stream")
end
it "raises an IOError if the IO is not initialized" do
- -> { @o.rb_io_maybe_wait_writable(0, IO.allocate, nil) }.should raise_error(IOError, "uninitialized stream")
+ -> { @o.rb_io_maybe_wait_writable(0, IO.allocate, nil) }.should.raise(IOError, "uninitialized stream")
end
it "can be interrupted" do
@@ -299,7 +299,7 @@ describe "C-API IO function" do
describe "rb_thread_fd_writable" do
it "waits til an fd is ready for writing" do
- @o.rb_thread_fd_writable(@w_io).should be_nil
+ @o.rb_thread_fd_writable(@w_io).should == nil
end
end
@@ -322,14 +322,14 @@ describe "C-API IO function" do
describe "rb_io_wait_readable" do
it "returns false if there is no error condition" do
@o.errno = 0
- @o.rb_io_wait_readable(@r_io, false).should be_false
+ @o.rb_io_wait_readable(@r_io, false).should == false
end
it "raises and IOError if passed a closed stream" do
@r_io.close
-> {
@o.rb_io_wait_readable(@r_io, false)
- }.should raise_error(IOError)
+ }.should.raise(IOError)
end
it "blocks until the io is readable and returns true" do
@@ -340,7 +340,7 @@ describe "C-API IO function" do
end
@o.errno = Errno::EAGAIN.new.errno
- @o.rb_io_wait_readable(@r_io, true).should be_true
+ @o.rb_io_wait_readable(@r_io, true).should == true
@o.instance_variable_get(:@read_data).should == "rb_io_wait_re"
thr.join
@@ -386,11 +386,11 @@ describe "C-API IO function" do
it "raises an IOError if the IO is closed" do
@r_io.close
- -> { @o.rb_io_maybe_wait_readable(0, @r_io, nil, false) }.should raise_error(IOError, "closed stream")
+ -> { @o.rb_io_maybe_wait_readable(0, @r_io, nil, false) }.should.raise(IOError, "closed stream")
end
it "raises an IOError if the IO is not initialized" do
- -> { @o.rb_io_maybe_wait_readable(0, IO.allocate, nil, false) }.should raise_error(IOError, "uninitialized stream")
+ -> { @o.rb_io_maybe_wait_readable(0, IO.allocate, nil, false) }.should.raise(IOError, "uninitialized stream")
end
end
end
@@ -406,7 +406,7 @@ describe "C-API IO function" do
Thread.pass until start
- @o.rb_thread_wait_fd(@r_io).should be_nil
+ @o.rb_thread_wait_fd(@r_io).should == nil
thr.join
end
@@ -455,11 +455,11 @@ describe "C-API IO function" do
it "raises an IOError if the IO is closed" do
@w_io.close
- -> { @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil) }.should raise_error(IOError, "closed stream")
+ -> { @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil) }.should.raise(IOError, "closed stream")
end
it "raises an IOError if the IO is not initialized" do
- -> { @o.rb_io_maybe_wait(0, IO.allocate, IO::WRITABLE, nil) }.should raise_error(IOError, "uninitialized stream")
+ -> { @o.rb_io_maybe_wait(0, IO.allocate, IO::WRITABLE, nil) }.should.raise(IOError, "uninitialized stream")
end
it "can be interrupted when waiting for READABLE event" do
@@ -494,166 +494,164 @@ describe "C-API IO function" do
end
end
- ruby_version_is "3.3" do
- describe "rb_io_mode" do
- it "returns the mode" do
- (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
- (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
- (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
- end
+ describe "rb_io_mode" do
+ it "returns the mode" do
+ (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
+ (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
+ (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
end
+ end
- describe "rb_io_path" do
- it "returns the IO#path" do
- @o.rb_io_path(@r_io).should == @r_io.path
- @o.rb_io_path(@rw_io).should == @rw_io.path
- @o.rb_io_path(@rw_io).should == @name
- end
+ describe "rb_io_path" do
+ it "returns the IO#path" do
+ @o.rb_io_path(@r_io).should == @r_io.path
+ @o.rb_io_path(@rw_io).should == @rw_io.path
+ @o.rb_io_path(@rw_io).should == @name
end
+ end
- describe "rb_io_closed_p" do
- it "returns false when io is not closed" do
- @o.rb_io_closed_p(@r_io).should == false
- @r_io.closed?.should == false
- end
+ describe "rb_io_closed_p" do
+ it "returns false when io is not closed" do
+ @o.rb_io_closed_p(@r_io).should == false
+ @r_io.closed?.should == false
+ end
- it "returns true when io is closed" do
- @r_io.close
+ it "returns true when io is closed" do
+ @r_io.close
- @o.rb_io_closed_p(@r_io).should == true
- @r_io.closed?.should == true
- end
+ @o.rb_io_closed_p(@r_io).should == true
+ @r_io.closed?.should == true
end
+ end
- quarantine! do # "Errno::EBADF: Bad file descriptor" at closing @r_io, @rw_io etc in the after :each hook
- describe "rb_io_open_descriptor" do
- it "creates a new IO instance" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should.is_a?(IO)
- end
-
- it "return an instance of the specified class" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.class.should == File
+ quarantine! do # "Errno::EBADF: Bad file descriptor" at closing @r_io, @rw_io etc in the after :each hook
+ describe "rb_io_open_descriptor" do
+ it "creates a new IO instance" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should.is_a?(IO)
+ end
- io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.class.should == IO
- end
+ it "return an instance of the specified class" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.class.should == File
- it "sets the specified file descriptor" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.fileno.should == @r_io.fileno
- end
+ io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.class.should == IO
+ end
- it "sets the specified path" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should == "a.txt"
- end
+ it "sets the specified file descriptor" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.fileno.should == @r_io.fileno
+ end
- it "sets the specified mode" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_BINMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should.binmode?
+ it "sets the specified path" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.path.should == "a.txt"
+ end
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_TEXTMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should_not.binmode?
- end
+ it "sets the specified mode" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_BINMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should.binmode?
- it "sets the specified timeout" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.timeout.should == 60
- end
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_TEXTMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should_not.binmode?
+ end
- it "sets the specified internal encoding" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.internal_encoding.should == Encoding::US_ASCII
- end
+ it "sets the specified timeout" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.timeout.should == 60
+ end
- it "sets the specified external encoding" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.external_encoding.should == Encoding::UTF_8
- end
+ it "sets the specified internal encoding" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.internal_encoding.should == Encoding::US_ASCII
+ end
- it "does not apply the specified encoding flags" do
- name = tmp("rb_io_open_descriptor_specs")
- File.write(name, "123\r\n456\n89")
- file = File.open(name, "r")
+ it "sets the specified external encoding" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.external_encoding.should == Encoding::UTF_8
+ end
- io = @o.rb_io_open_descriptor(File, file.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", CApiIOSpecs::ECONV_UNIVERSAL_NEWLINE_DECORATOR, {})
- io.read_nonblock(20).should == "123\r\n456\n89"
- ensure
- file.close
- rm_r name
- end
+ it "does not apply the specified encoding flags" do
+ name = tmp("rb_io_open_descriptor_specs")
+ File.write(name, "123\r\n456\n89")
+ file = File.open(name, "r")
- it "ignores the IO open options" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"})
- io.external_encoding.should == Encoding::UTF_8
+ io = @o.rb_io_open_descriptor(File, file.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", CApiIOSpecs::ECONV_UNIVERSAL_NEWLINE_DECORATOR, {})
+ io.read_nonblock(20).should == "123\r\n456\n89"
+ ensure
+ file.close
+ rm_r name
+ end
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"})
- io.internal_encoding.should == Encoding::US_ASCII
+ it "ignores the IO open options" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"})
+ io.external_encoding.should == Encoding::UTF_8
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"})
- io.external_encoding.should == Encoding::UTF_8
- io.internal_encoding.should == Encoding::US_ASCII
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"})
+ io.internal_encoding.should == Encoding::US_ASCII
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false})
- io.should_not.binmode?
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"})
+ io.external_encoding.should == Encoding::UTF_8
+ io.internal_encoding.should == Encoding::US_ASCII
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true})
- io.should_not.binmode?
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false})
+ io.should_not.binmode?
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false})
- io.should.autoclose?
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true})
+ io.should_not.binmode?
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"})
- io.path.should == "a.txt"
- end
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false})
+ io.should.autoclose?
- it "ignores the IO encoding options" do
- io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_WRITABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {crlf_newline: true})
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"})
+ io.path.should == "a.txt"
+ end
- io.write("123\r\n456\n89")
- io.flush
+ it "ignores the IO encoding options" do
+ io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_WRITABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {crlf_newline: true})
- @r_io.read_nonblock(20).should == "123\r\n456\n89"
- end
+ io.write("123\r\n456\n89")
+ io.flush
- it "allows wrong mode" do
- io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should.is_a?(File)
+ @r_io.read_nonblock(20).should == "123\r\n456\n89"
+ end
- platform_is_not :windows do
- -> { io.read_nonblock(1) }.should raise_error(Errno::EBADF)
- end
+ it "allows wrong mode" do
+ io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should.is_a?(File)
- platform_is :windows do
- -> { io.read_nonblock(1) }.should raise_error(IO::EWOULDBLOCKWaitReadable)
- end
+ platform_is_not :windows do
+ -> { io.read_nonblock(1) }.should.raise(Errno::EBADF)
end
- it "tolerates NULL as rb_io_encoding *encoding parameter" do
- io = @o.rb_io_open_descriptor_without_encoding(File, @r_io.fileno, 0, "a.txt", 60)
- io.should.is_a?(File)
+ platform_is :windows do
+ -> { io.read_nonblock(1) }.should.raise(IO::EWOULDBLOCKWaitReadable)
end
+ end
+
+ it "tolerates NULL as rb_io_encoding *encoding parameter" do
+ io = @o.rb_io_open_descriptor_without_encoding(File, @r_io.fileno, 0, "a.txt", 60)
+ io.should.is_a?(File)
+ end
- it "deduplicates path String" do
- path = "a.txt".dup
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should_not equal(path)
+ it "deduplicates path String" do
+ path = "a.txt".dup
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
+ io.path.should_not.equal?(path)
- path = "a.txt".freeze
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should_not equal(path)
- end
+ path = "a.txt".freeze
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
+ io.path.should_not.equal?(path)
+ end
- it "calls #to_str to convert a path to a String" do
- path = Object.new
- def path.to_str; "a.txt"; end
+ it "calls #to_str to convert a path to a String" do
+ path = Object.new
+ def path.to_str; "a.txt"; end
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should == "a.txt"
- end
+ io.path.should == "a.txt"
end
end
end
@@ -680,13 +678,13 @@ describe "rb_fd_fix_cloexec" do
end
after :each do
- @io.close unless @io.closed?
+ @io.close
rm_r @name
end
it "sets close_on_exec on the IO" do
@o.rb_fd_fix_cloexec(@io)
- @io.close_on_exec?.should be_true
+ @io.close_on_exec?.should == true
end
end
@@ -701,13 +699,65 @@ describe "rb_cloexec_open" do
end
after :each do
- @io.close unless @io.nil? || @io.closed?
+ @io.close if @io
rm_r @name
end
it "sets close_on_exec on the newly-opened IO" do
@io = @o.rb_cloexec_open(@name, 0, 0)
- @io.close_on_exec?.should be_true
+ @io.close_on_exec?.should == true
+ end
+end
+
+describe "rb_cloexec_dup" do
+ before :each do
+ @o = CApiIOSpecs.new
+ @name = tmp("c_api_rb_io_specs")
+ touch @name
+
+ @io = new_io @name, "r"
+ @dup = nil
+ end
+
+ after :each do
+ @dup.close if @dup
+ @io.close
+ rm_r @name
+ end
+
+ it "duplicates a file descriptor and sets close_on_exec" do
+ @dup = @o.rb_cloexec_dup(@io)
+ @dup.should.close_on_exec?
+ @dup.fileno.should_not == @io.fileno
+ end
+end
+
+describe "rb_cloexec_fcntl_dupfd" do
+ before :each do
+ @o = CApiIOSpecs.new
+ @name = tmp("c_api_rb_io_specs")
+ touch @name
+
+ @io = new_io @name, "r"
+ @dup = nil
+ end
+
+ after :each do
+ @dup.close if @dup
+ @io.close
+ rm_r @name
+ end
+
+ it "duplicates a file descriptor and sets close_on_exec" do
+ @dup = @o.rb_cloexec_fcntl_dupfd(@io, 3)
+ @dup.close_on_exec?.should == true
+ @dup.fileno.should_not == @io.fileno
+ end
+
+ it "returns a file descriptor greater than or equal to minfd" do
+ @dup = @o.rb_cloexec_fcntl_dupfd(@io, 100)
+ @dup.fileno.should >= 100
+ @dup.close_on_exec?.should == true
end
end
diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb
index ba301ec172..62eb21448b 100644
--- a/spec/ruby/optional/capi/kernel_spec.rb
+++ b/spec/ruby/optional/capi/kernel_spec.rb
@@ -28,7 +28,7 @@ describe "C-API Kernel function" do
describe "rb_need_block" do
it "raises a LocalJumpError if no block is given" do
- -> { @s.rb_need_block }.should raise_error(LocalJumpError)
+ -> { @s.rb_need_block }.should.raise(LocalJumpError)
end
it "does not raise a LocalJumpError if a block is given" do
@@ -53,7 +53,7 @@ describe "C-API Kernel function" do
it "calls the method with no function callback and no block" do
ary = [1, 3, 5]
- @s.rb_block_call_no_func(ary).should be_kind_of(Enumerator)
+ @s.rb_block_call_no_func(ary).should.is_a?(Enumerator)
end
it "calls the method with no function callback and a block" do
@@ -65,7 +65,7 @@ describe "C-API Kernel function" do
it "can pass extra data to the function" do
ary = [3]
- @s.rb_block_call_extra_data(ary).should equal(ary)
+ @s.rb_block_call_extra_data(ary).should.equal?(ary)
end
end
@@ -78,12 +78,12 @@ describe "C-API Kernel function" do
describe "rb_raise" do
it "raises an exception" do
- -> { @s.rb_raise({}) }.should raise_error(TypeError)
+ -> { @s.rb_raise({}) }.should.raise(TypeError)
end
it "terminates the function at the point it was called" do
h = {}
- -> { @s.rb_raise(h) }.should raise_error(TypeError)
+ -> { @s.rb_raise(h) }.should.raise(TypeError)
h[:stage].should == :before
end
@@ -100,7 +100,7 @@ describe "C-API Kernel function" do
# should raise StandardError "aaa"
raise
end
- end.should raise_error(StandardError, "aaa")
+ end.should.raise(StandardError, "aaa")
end
end
@@ -125,7 +125,7 @@ describe "C-API Kernel function" do
end
it "raises an ArgumentError if there is no catch block for the symbol" do
- -> { @s.rb_throw(nil) }.should raise_error(ArgumentError)
+ -> { @s.rb_throw(nil) }.should.raise(ArgumentError)
end
end
@@ -151,7 +151,7 @@ describe "C-API Kernel function" do
end
it "raises an ArgumentError if there is no catch block for the symbol" do
- -> { @s.rb_throw(nil) }.should raise_error(ArgumentError)
+ -> { @s.rb_throw(nil) }.should.raise(ArgumentError)
end
end
@@ -173,13 +173,13 @@ describe "C-API Kernel function" do
it "raises an exception from the value of errno" do
-> do
@s.rb_sys_fail("additional info")
- end.should raise_error(SystemCallError, /additional info/)
+ end.should.raise(SystemCallError, /additional info/)
end
it "can take a NULL message" do
-> do
@s.rb_sys_fail(nil)
- end.should raise_error(Errno::EPERM)
+ end.should.raise(Errno::EPERM)
end
end
@@ -187,17 +187,17 @@ describe "C-API Kernel function" do
it "raises an exception from the given error" do
-> do
@s.rb_syserr_fail(Errno::EINVAL::Errno, "additional info")
- end.should raise_error(Errno::EINVAL, "Invalid argument - additional info")
+ end.should.raise(Errno::EINVAL, "Invalid argument - additional info")
end
it "can take a NULL message" do
-> do
@s.rb_syserr_fail(Errno::EINVAL::Errno, nil)
- end.should raise_error(Errno::EINVAL, "Invalid argument")
+ end.should.raise(Errno::EINVAL, "Invalid argument")
end
it "uses some kind of string as message when errno is unknown" do
- -> { @s.rb_syserr_fail(-10, nil) }.should raise_error(SystemCallError, /[[:graph:]]+/)
+ -> { @s.rb_syserr_fail(-10, nil) }.should.raise(SystemCallError, /[[:graph:]]+/)
end
end
@@ -205,17 +205,17 @@ describe "C-API Kernel function" do
it "raises an exception from the given error" do
-> do
@s.rb_syserr_fail_str(Errno::EINVAL::Errno, "additional info")
- end.should raise_error(Errno::EINVAL, "Invalid argument - additional info")
+ end.should.raise(Errno::EINVAL, "Invalid argument - additional info")
end
it "can take nil as a message" do
-> do
@s.rb_syserr_fail_str(Errno::EINVAL::Errno, nil)
- end.should raise_error(Errno::EINVAL, "Invalid argument")
+ end.should.raise(Errno::EINVAL, "Invalid argument")
end
it "uses some kind of string as message when errno is unknown" do
- -> { @s.rb_syserr_fail_str(-10, nil) }.should raise_error(SystemCallError, /[[:graph:]]+/)
+ -> { @s.rb_syserr_fail_str(-10, nil) }.should.raise(SystemCallError, /[[:graph:]]+/)
end
end
@@ -231,7 +231,7 @@ describe "C-API Kernel function" do
end
it "raises LocalJumpError when no block is given" do
- -> { @s.rb_yield(1) }.should raise_error(LocalJumpError)
+ -> { @s.rb_yield(1) }.should.raise(LocalJumpError)
end
it "rb_yield to a block that breaks does not raise an error" do
@@ -242,10 +242,8 @@ describe "C-API Kernel function" do
@s.rb_yield(1) { break 73 }.should == 73
end
- platform_is_not :"solaris2.10" do # NOTE: i386-pc-solaris2.10
- it "rb_yield through a callback to a block that breaks with a value returns the value" do
- @s.rb_yield_indirected(1) { break 73 }.should == 73
- end
+ it "rb_yield through a callback to a block that breaks with a value returns the value" do
+ @s.rb_yield_indirected(1) { break 73 }.should == 73
end
it "rb_yield to block passed to enumerator" do
@@ -271,7 +269,7 @@ describe "C-API Kernel function" do
end
it "raises LocalJumpError when no block is given" do
- -> { @s.rb_yield_splat([1, 2]) }.should raise_error(LocalJumpError)
+ -> { @s.rb_yield_splat([1, 2]) }.should.raise(LocalJumpError)
end
end
@@ -303,7 +301,7 @@ describe "C-API Kernel function" do
end
it "raises LocalJumpError when no block is given" do
- -> { @s.rb_yield_splat([1, 2]) }.should raise_error(LocalJumpError)
+ -> { @s.rb_yield_splat([1, 2]) }.should.raise(LocalJumpError)
end
end
@@ -332,7 +330,7 @@ describe "C-API Kernel function" do
proof = [] # Hold proof of work performed after the yield.
-> do
@s.rb_protect_yield(77, proof) { |x| raise NameError }
- end.should raise_error(NameError)
+ end.should.raise(NameError)
proof[0].should == 23
end
@@ -340,7 +338,7 @@ describe "C-API Kernel function" do
proof = [] # Hold proof of work performed after the yield.
-> do
@s.rb_protect_yield(77, proof) { |x| raise NameError }
- end.should raise_error(NameError)
+ end.should.raise(NameError)
proof[0].should == 23
proof[1].should == nil
end
@@ -377,7 +375,7 @@ describe "C-API Kernel function" do
proof = []
-> do
@s.rb_eval_string_protect('raise RuntimeError', proof)
- end.should raise_error(RuntimeError)
+ end.should.raise(RuntimeError)
proof.should == [23, nil]
end
end
@@ -418,11 +416,11 @@ describe "C-API Kernel function" do
end
it "raises an exception if passed function raises an exception other than StandardError" do
- -> { @s.rb_rescue(@exc_error_proc, nil, @rescue_proc_returns_arg, nil) }.should raise_error(Exception)
+ -> { @s.rb_rescue(@exc_error_proc, nil, @rescue_proc_returns_arg, nil) }.should.raise(Exception)
end
it "raises an exception if any exception is raised inside the 'rescue function'" do
- -> { @s.rb_rescue(@std_error_proc, nil, @std_error_proc, nil) }.should raise_error(StandardError)
+ -> { @s.rb_rescue(@std_error_proc, nil, @std_error_proc, nil) }.should.raise(StandardError)
end
it "sets $! and rb_errinfo() during the 'rescue function' execution" do
@@ -465,13 +463,13 @@ describe "C-API Kernel function" do
@s.rb_rescue2(run_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc
-> {
@s.rb_rescue2(type_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError)
- }.should raise_error(Exception, 'custom error')
+ }.should.raise(Exception, 'custom error')
end
it "raises TypeError if one of the passed exceptions is not a Module" do
-> {
@s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42)
- }.should raise_error(TypeError, /class or module required/)
+ }.should.raise(TypeError, /class or module required/)
end
it "sets $! and rb_errinfo() during the 'rescue function' execution" do
@@ -507,12 +505,12 @@ describe "C-API Kernel function" do
throw :thrown_value
ScratchPad << :after_throw
end
- @s.rb_catch("thrown_value", proc).should be_nil
+ @s.rb_catch("thrown_value", proc).should == nil
ScratchPad.recorded.should == [:before_throw]
end
it "raises an ArgumentError if the throw symbol isn't caught" do
- -> { @s.rb_catch("foo", -> { throw :bar }) }.should raise_error(ArgumentError)
+ -> { @s.rb_catch("foo", -> { throw :bar }) }.should.raise(ArgumentError)
end
end
@@ -533,12 +531,12 @@ describe "C-API Kernel function" do
throw @tag
ScratchPad << :after_throw
end
- @s.rb_catch_obj(@tag, proc).should be_nil
+ @s.rb_catch_obj(@tag, proc).should == nil
ScratchPad.recorded.should == [:before_throw]
end
it "raises an ArgumentError if the throw symbol isn't caught" do
- -> { @s.rb_catch("foo", -> { throw :bar }) }.should raise_error(ArgumentError)
+ -> { @s.rb_catch("foo", -> { throw :bar }) }.should.raise(ArgumentError)
end
end
@@ -596,7 +594,7 @@ describe "C-API Kernel function" do
ensure_proc = -> x { foo = x }
-> {
@s.rb_ensure(raise_proc, nil, ensure_proc, :foo)
- }.should raise_error(exception_class)
+ }.should.raise(exception_class)
foo.should == :foo
end
@@ -606,14 +604,14 @@ describe "C-API Kernel function" do
$!.should.is_a?(exception_class)
@s.rb_errinfo.should.is_a?(exception_class)
}, nil)
- }.should raise_error(exception_class)
+ }.should.raise(exception_class)
-> {
@s.rb_ensure(-> _ { @s.rb_raise({}) }, nil, -> _ {
$!.should.is_a?(TypeError)
@s.rb_errinfo.should.is_a?(TypeError)
}, nil)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
$!.should == nil
@s.rb_errinfo.should == nil
@@ -622,7 +620,7 @@ describe "C-API Kernel function" do
it "raises the same exception raised inside passed function" do
raise_proc = -> *_ { raise RuntimeError, 'foo' }
proc = -> *_ { }
- -> { @s.rb_ensure(raise_proc, nil, proc, nil) }.should raise_error(RuntimeError, 'foo')
+ -> { @s.rb_ensure(raise_proc, nil, proc, nil) }.should.raise(RuntimeError, 'foo')
end
end
@@ -637,29 +635,31 @@ describe "C-API Kernel function" do
end
end
- describe "rb_eval_cmd_kw" do
- it "evaluates a string of ruby code" do
- @s.rb_eval_cmd_kw("1+1", [], 0).should == 2
- end
+ ruby_version_is ""..."4.0" do
+ describe "rb_eval_cmd_kw" do
+ it "evaluates a string of ruby code" do
+ @s.rb_eval_cmd_kw("1+1", [], 0).should == 2
+ end
- it "calls a proc with the supplied arguments" do
- @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8]
- end
+ it "calls a proc with the supplied arguments" do
+ @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8]
+ end
- it "calls a proc with keyword arguments if kw_splat is non zero" do
- a_proc = -> *x, **y {
- res = x.map { |i| i + 1 }
- y.each { |k, v| res << k; res << v }
- res
- }
- @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3]
+ it "calls a proc with keyword arguments if kw_splat is non zero" do
+ a_proc = -> *x, **y {
+ res = x.map { |i| i + 1 }
+ y.each { |k, v| res << k; res << v }
+ res
+ }
+ @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3]
+ end
end
end
describe "rb_block_proc" do
it "converts the implicit block into a proc" do
proc = @s.rb_block_proc { 1+1 }
- proc.should be_kind_of(Proc)
+ proc.should.is_a?(Proc)
proc.call.should == 2
proc.should_not.lambda?
end
@@ -667,7 +667,7 @@ describe "C-API Kernel function" do
it "passes through an existing lambda and does not convert to a proc" do
b = -> { 1+1 }
proc = @s.rb_block_proc(&b)
- proc.should equal(b)
+ proc.should.equal?(b)
proc.call.should == 2
proc.should.lambda?
end
@@ -676,7 +676,7 @@ describe "C-API Kernel function" do
describe "rb_block_lambda" do
it "converts the implicit block into a lambda" do
proc = @s.rb_block_lambda { 1+1 }
- proc.should be_kind_of(Proc)
+ proc.should.is_a?(Proc)
proc.call.should == 2
proc.should.lambda?
end
@@ -684,7 +684,7 @@ describe "C-API Kernel function" do
it "passes through an existing Proc and does not convert to a lambda" do
b = proc { 1+1 }
proc = @s.rb_block_lambda(&b)
- proc.should equal(b)
+ proc.should.equal?(b)
proc.call.should == 2
proc.should_not.lambda?
end
@@ -703,6 +703,12 @@ describe "C-API Kernel function" do
end
end
+ describe "ruby_vm_at_exit" do
+ it "runs a C function after the VM is terminated" do
+ ruby_exe("require #{kernel_path.inspect}; CApiKernelSpecs.new.ruby_vm_at_exit").should == "ruby_vm_at_exit hook ran\n"
+ end
+ end
+
describe "rb_f_sprintf" do
it "returns a string according to format and arguments" do
@s.rb_f_sprintf(["%d %f %s", 10, 2.5, "test"]).should == "10 2.500000 test"
@@ -713,7 +719,7 @@ describe "C-API Kernel function" do
it "returns a caller backtrace" do
backtrace = @s.rb_make_backtrace
lines = backtrace.select {|l| l =~ /#{__FILE__}/ }
- lines.should_not be_empty
+ lines.should_not.empty?
end
end
@@ -771,7 +777,7 @@ describe "C-API Kernel function" do
-> {
@s.rb_funcallv_kw(self, :m, [42])
- }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ }.should.raise(TypeError, 'no implicit conversion of Integer into Hash')
end
end
@@ -807,7 +813,7 @@ describe "C-API Kernel function" do
end
it "does not call a private method" do
- -> { @s.rb_funcallv_public(@obj, :method_private) }.should raise_error(NoMethodError, /private/)
+ -> { @s.rb_funcallv_public(@obj, :method_private) }.should.raise(NoMethodError, /private/)
end
end
@@ -841,7 +847,7 @@ describe "C-API Kernel function" do
-> {
@s.rb_funcall_with_block(object, :private_method, [], proc { })
- }.should raise_error(NoMethodError, /private/)
+ }.should.raise(NoMethodError, /private/)
end
it "does not call a protected method" do
@@ -849,7 +855,7 @@ describe "C-API Kernel function" do
-> {
@s.rb_funcall_with_block(object, :protected_method, [], proc { })
- }.should raise_error(NoMethodError, /protected/)
+ }.should.raise(NoMethodError, /protected/)
end
end
@@ -868,7 +874,7 @@ describe "C-API Kernel function" do
-> {
@s.rb_funcall_with_block_kw(object, :private_method, [{}], proc { })
- }.should raise_error(NoMethodError, /private/)
+ }.should.raise(NoMethodError, /private/)
end
it "does not call a protected method" do
@@ -876,7 +882,7 @@ describe "C-API Kernel function" do
-> {
@s.rb_funcall_with_block_kw(object, :protected_method, [{}], proc { })
- }.should raise_error(NoMethodError, /protected/)
+ }.should.raise(NoMethodError, /protected/)
end
end
diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb
index b7684e566b..b9c36f569f 100644
--- a/spec/ruby/optional/capi/module_spec.rb
+++ b/spec/ruby/optional/capi/module_spec.rb
@@ -36,15 +36,15 @@ describe "CApiModule" do
it "allows arbitrary names, including constant names not valid in Ruby" do
-> {
CApiModuleSpecs::C.const_set(:_INVALID, 1)
- }.should raise_error(NameError, /wrong constant name/)
+ }.should.raise(NameError, /wrong constant name/)
- @m.rb_const_set(CApiModuleSpecs::C, :_INVALID, 2)
+ suppress_warning { @m.rb_const_set(CApiModuleSpecs::C, :_INVALID, 2) }
@m.rb_const_get(CApiModuleSpecs::C, :_INVALID).should == 2
# Ruby-level should still not allow access
-> {
CApiModuleSpecs::C.const_get(:_INVALID)
- }.should raise_error(NameError, /wrong constant name/)
+ }.should.raise(NameError, /wrong constant name/)
end
end
@@ -56,15 +56,15 @@ describe "CApiModule" do
it "raises a TypeError if the constant is not a module" do
::CApiModuleSpecsGlobalConst = 7
- -> { @m.rb_define_module("CApiModuleSpecsGlobalConst") }.should raise_error(TypeError)
+ -> { @m.rb_define_module("CApiModuleSpecsGlobalConst") }.should.raise(TypeError)
Object.send :remove_const, :CApiModuleSpecsGlobalConst
end
it "defines a new module at toplevel" do
mod = @m.rb_define_module("CApiModuleSpecsModuleB")
- mod.should be_kind_of(Module)
+ mod.should.is_a?(Module)
mod.name.should == "CApiModuleSpecsModuleB"
- ::CApiModuleSpecsModuleB.should be_kind_of(Module)
+ ::CApiModuleSpecsModuleB.should.is_a?(Module)
Object.send :remove_const, :CApiModuleSpecsModuleB
end
end
@@ -72,7 +72,7 @@ describe "CApiModule" do
describe "rb_define_module_under" do
it "creates a new module inside the inner class" do
mod = @m.rb_define_module_under(CApiModuleSpecs, "ModuleSpecsModuleUnder1")
- mod.should be_kind_of(Module)
+ mod.should.is_a?(Module)
end
it "sets the module name" do
@@ -110,26 +110,26 @@ describe "CApiModule" do
describe "rb_const_defined" do
# The fixture converts C boolean test to Ruby 'true' / 'false'
it "returns C non-zero if a constant is defined" do
- @m.rb_const_defined(CApiModuleSpecs::A, :X).should be_true
+ @m.rb_const_defined(CApiModuleSpecs::A, :X).should == true
end
it "returns C non-zero if a constant is defined in Object" do
- @m.rb_const_defined(CApiModuleSpecs::A, :Module).should be_true
+ @m.rb_const_defined(CApiModuleSpecs::A, :Module).should == true
end
end
describe "rb_const_defined_at" do
# The fixture converts C boolean test to Ruby 'true' / 'false'
it "returns C non-zero if a constant is defined" do
- @m.rb_const_defined_at(CApiModuleSpecs::A, :X).should be_true
+ @m.rb_const_defined_at(CApiModuleSpecs::A, :X).should == true
end
it "does not search in ancestors for the constant" do
- @m.rb_const_defined_at(CApiModuleSpecs::B, :X).should be_false
+ @m.rb_const_defined_at(CApiModuleSpecs::B, :X).should == false
end
it "does not search in Object" do
- @m.rb_const_defined_at(CApiModuleSpecs::A, :Module).should be_false
+ @m.rb_const_defined_at(CApiModuleSpecs::A, :Module).should == false
end
end
@@ -166,11 +166,11 @@ describe "CApiModule" do
it "allows arbitrary names, including constant names not valid in Ruby" do
-> {
CApiModuleSpecs::A.const_get(:_INVALID)
- }.should raise_error(NameError, /wrong constant name/)
+ }.should.raise(NameError, /wrong constant name/)
-> {
@m.rb_const_get(CApiModuleSpecs::A, :_INVALID)
- }.should raise_error(NameError, /uninitialized constant/)
+ }.should.raise(NameError, /uninitialized constant/)
end
end
@@ -237,7 +237,7 @@ describe "CApiModule" do
describe "rb_define_global_function" do
it "defines a method on Kernel" do
@m.rb_define_global_function("module_specs_global_function")
- Kernel.should have_method(:module_specs_global_function)
+ Kernel.should.respond_to?(:module_specs_global_function)
module_specs_global_function.should == :test_method
end
end
@@ -246,7 +246,7 @@ describe "CApiModule" do
it "defines a method on a class" do
cls = Class.new
@m.rb_define_method(cls, "test_method")
- cls.should have_instance_method(:test_method)
+ cls.should.method_defined?(:test_method, false)
cls.new.test_method.should == :test_method
end
@@ -285,7 +285,7 @@ describe "CApiModule" do
it "defines a method on a module" do
mod = Module.new
@m.rb_define_method(mod, "test_method")
- mod.should have_instance_method(:test_method)
+ mod.should.method_defined?(:test_method, false)
end
it "returns the correct arity of the method in module" do
@@ -313,7 +313,7 @@ describe "CApiModule" do
cls = Class.new
cls.include(@mod)
- cls.should have_private_instance_method(:test_module_function)
+ cls.private_instance_methods(true).should.include?(:test_module_function)
end
it "returns the correct arity for private instance method" do
@@ -328,14 +328,14 @@ describe "CApiModule" do
it "defines a private method on a class" do
cls = Class.new
@m.rb_define_private_method(cls, "test_method")
- cls.should have_private_instance_method(:test_method)
+ cls.private_instance_methods(false).should.include?(:test_method)
cls.new.send(:test_method).should == :test_method
end
it "defines a private method on a module" do
mod = Module.new
@m.rb_define_private_method(mod, "test_method")
- mod.should have_private_instance_method(:test_method)
+ mod.private_instance_methods(false).should.include?(:test_method)
end
end
@@ -343,14 +343,14 @@ describe "CApiModule" do
it "defines a protected method on a class" do
cls = Class.new
@m.rb_define_protected_method(cls, "test_method")
- cls.should have_protected_instance_method(:test_method)
+ cls.protected_instance_methods(false).should.include?(:test_method)
cls.new.send(:test_method).should == :test_method
end
it "defines a protected method on a module" do
mod = Module.new
@m.rb_define_protected_method(mod, "test_method")
- mod.should have_protected_instance_method(:test_method)
+ mod.protected_instance_methods(false).should.include?(:test_method)
end
end
@@ -360,7 +360,7 @@ describe "CApiModule" do
a = cls.new
@m.rb_define_singleton_method a, "module_specs_singleton_method"
a.module_specs_singleton_method.should == :test_method
- -> { cls.new.module_specs_singleton_method }.should raise_error(NoMethodError)
+ -> { cls.new.module_specs_singleton_method }.should.raise(NoMethodError)
end
end
@@ -376,16 +376,16 @@ describe "CApiModule" do
it "undef'ines a method on a class" do
@class.new.ruby_test_method.should == :ruby_test_method
@m.rb_undef_method @class, "ruby_test_method"
- @class.should_not have_instance_method(:ruby_test_method)
+ @class.should_not.method_defined?(:ruby_test_method)
end
it "undefines private methods also" do
@m.rb_undef_method @class, "initialize_copy"
- -> { @class.new.dup }.should raise_error(NoMethodError)
+ -> { @class.new.dup }.should.raise(NoMethodError)
end
it "does not raise exceptions when passed a missing name" do
- -> { @m.rb_undef_method @class, "not_exist" }.should_not raise_error
+ -> { @m.rb_undef_method @class, "not_exist" }.should_not.raise
end
describe "when given a frozen Class" do
@@ -394,11 +394,11 @@ describe "CApiModule" do
end
it "raises a FrozenError when passed a name" do
- -> { @m.rb_undef_method @frozen, "ruby_test_method" }.should raise_error(FrozenError)
+ -> { @m.rb_undef_method @frozen, "ruby_test_method" }.should.raise(FrozenError)
end
it "raises a FrozenError when passed a missing name" do
- -> { @m.rb_undef_method @frozen, "not_exist" }.should raise_error(FrozenError)
+ -> { @m.rb_undef_method @frozen, "not_exist" }.should.raise(FrozenError)
end
end
end
@@ -413,7 +413,7 @@ describe "CApiModule" do
cls.new.ruby_test_method.should == :ruby_test_method
@m.rb_undef cls, :ruby_test_method
- cls.should_not have_instance_method(:ruby_test_method)
+ cls.should_not.method_defined?(:ruby_test_method)
end
end
diff --git a/spec/ruby/optional/capi/mutex_spec.rb b/spec/ruby/optional/capi/mutex_spec.rb
index 71a2212e36..fad9b4d1a2 100644
--- a/spec/ruby/optional/capi/mutex_spec.rb
+++ b/spec/ruby/optional/capi/mutex_spec.rb
@@ -10,64 +10,64 @@ describe "C-API Mutex functions" do
describe "rb_mutex_new" do
it "creates a new mutex" do
- @s.rb_mutex_new.should be_an_instance_of(Mutex)
+ @s.rb_mutex_new.should.instance_of?(Mutex)
end
end
describe "rb_mutex_locked_p" do
it "returns false if the mutex is not locked" do
- @s.rb_mutex_locked_p(@m).should be_false
+ @s.rb_mutex_locked_p(@m).should == false
end
it "returns true if the mutex is locked" do
@m.lock
- @s.rb_mutex_locked_p(@m).should be_true
+ @s.rb_mutex_locked_p(@m).should == true
end
end
describe "rb_mutex_trylock" do
it "locks the mutex if not locked" do
- @s.rb_mutex_trylock(@m).should be_true
- @m.locked?.should be_true
+ @s.rb_mutex_trylock(@m).should == true
+ @m.locked?.should == true
end
it "returns false if the mutex is already locked" do
@m.lock
- @s.rb_mutex_trylock(@m).should be_false
- @m.locked?.should be_true
+ @s.rb_mutex_trylock(@m).should == false
+ @m.locked?.should == true
end
end
describe "rb_mutex_lock" do
it "returns when the mutex isn't locked" do
@s.rb_mutex_lock(@m).should == @m
- @m.locked?.should be_true
+ @m.locked?.should == true
end
it "throws an exception when already locked in the same thread" do
@m.lock
- -> { @s.rb_mutex_lock(@m) }.should raise_error(ThreadError)
- @m.locked?.should be_true
+ -> { @s.rb_mutex_lock(@m) }.should.raise(ThreadError)
+ @m.locked?.should == true
end
end
describe "rb_mutex_unlock" do
it "raises an exception when not locked" do
- -> { @s.rb_mutex_unlock(@m) }.should raise_error(ThreadError)
- @m.locked?.should be_false
+ -> { @s.rb_mutex_unlock(@m) }.should.raise(ThreadError)
+ @m.locked?.should == false
end
it "unlocks the mutex when locked" do
@m.lock
@s.rb_mutex_unlock(@m).should == @m
- @m.locked?.should be_false
+ @m.locked?.should == false
end
end
describe "rb_mutex_sleep" do
it "throws an exception when the mutex is not locked" do
- -> { @s.rb_mutex_sleep(@m, 0.1) }.should raise_error(ThreadError)
- @m.locked?.should be_false
+ -> { @s.rb_mutex_sleep(@m, 0.1) }.should.raise(ThreadError)
+ @m.locked?.should == false
end
it "sleeps when the mutex is locked" do
@@ -76,13 +76,13 @@ describe "C-API Mutex functions" do
@s.rb_mutex_sleep(@m, 0.001)
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
(t2 - t1).should >= 0
- @m.locked?.should be_true
+ @m.locked?.should == true
end
end
describe "rb_mutex_synchronize" do
it "calls the function while the mutex is locked" do
- callback = -> { @m.locked?.should be_true }
+ callback = -> { @m.locked?.should == true }
@s.rb_mutex_synchronize(@m, callback)
end
diff --git a/spec/ruby/optional/capi/numeric_spec.rb b/spec/ruby/optional/capi/numeric_spec.rb
index e9667da5ba..abfed13503 100644
--- a/spec/ruby/optional/capi/numeric_spec.rb
+++ b/spec/ruby/optional/capi/numeric_spec.rb
@@ -9,7 +9,7 @@ describe "CApiNumericSpecs" do
describe "NUM2INT" do
it "raises a TypeError if passed nil" do
- -> { @s.NUM2INT(nil) }.should raise_error(TypeError)
+ -> { @s.NUM2INT(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -33,7 +33,7 @@ describe "CApiNumericSpecs" do
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.NUM2INT(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.NUM2INT(0xffff_ffff+1) }.should.raise(RangeError)
end
it "calls #to_int to coerce the value" do
@@ -45,7 +45,7 @@ describe "CApiNumericSpecs" do
describe "NUM2UINT" do
it "raises a TypeError if passed nil" do
- -> { @s.NUM2UINT(nil) }.should raise_error(TypeError)
+ -> { @s.NUM2UINT(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -69,17 +69,17 @@ describe "CApiNumericSpecs" do
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.NUM2UINT(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.NUM2UINT(0xffff_ffff+1) }.should.raise(RangeError)
end
it "raises a RangeError if the value is less than 32bits negative" do
- -> { @s.NUM2UINT(-0x8000_0000-1) }.should raise_error(RangeError)
+ -> { @s.NUM2UINT(-0x8000_0000-1) }.should.raise(RangeError)
end
it "raises a RangeError if the value is more than 64bits" do
-> do
@s.NUM2UINT(0xffff_ffff_ffff_ffff+1)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
it "calls #to_int to coerce the value" do
@@ -91,7 +91,7 @@ describe "CApiNumericSpecs" do
describe "NUM2LONG" do
it "raises a TypeError if passed nil" do
- -> { @s.NUM2LONG(nil) }.should raise_error(TypeError)
+ -> { @s.NUM2LONG(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -116,7 +116,7 @@ describe "CApiNumericSpecs" do
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.NUM2LONG(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.NUM2LONG(0xffff_ffff+1) }.should.raise(RangeError)
end
end
@@ -132,7 +132,7 @@ describe "CApiNumericSpecs" do
it "raises a RangeError if the value is more than 64bits" do
-> do
@s.NUM2LONG(0xffff_ffff_ffff_ffff+1)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
end
@@ -145,7 +145,7 @@ describe "CApiNumericSpecs" do
describe "NUM2SHORT" do
it "raises a TypeError if passed nil" do
- -> { @s.NUM2SHORT(nil) }.should raise_error(TypeError)
+ -> { @s.NUM2SHORT(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -161,7 +161,7 @@ describe "CApiNumericSpecs" do
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.NUM2SHORT(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.NUM2SHORT(0xffff_ffff+1) }.should.raise(RangeError)
end
it "calls #to_int to coerce the value" do
@@ -173,7 +173,7 @@ describe "CApiNumericSpecs" do
describe "INT2NUM" do
it "raises a TypeError if passed nil" do
- -> { @s.INT2NUM(nil) }.should raise_error(TypeError)
+ -> { @s.INT2NUM(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -181,7 +181,7 @@ describe "CApiNumericSpecs" do
end
it "raises a RangeError when passed a Bignum" do
- -> { @s.INT2NUM(bignum_value) }.should raise_error(RangeError)
+ -> { @s.INT2NUM(bignum_value) }.should.raise(RangeError)
end
it "converts a Fixnum" do
@@ -195,7 +195,7 @@ describe "CApiNumericSpecs" do
describe "NUM2ULONG" do
it "raises a TypeError if passed nil" do
- -> { @s.NUM2ULONG(nil) }.should raise_error(TypeError)
+ -> { @s.NUM2ULONG(nil) }.should.raise(TypeError)
end
it "converts a Float" do
@@ -227,7 +227,7 @@ describe "CApiNumericSpecs" do
end
it "raises a RangeError if the value is more than 32bits" do
- -> { @s.NUM2ULONG(0xffff_ffff+1) }.should raise_error(RangeError)
+ -> { @s.NUM2ULONG(0xffff_ffff+1) }.should.raise(RangeError)
end
end
@@ -250,7 +250,7 @@ describe "CApiNumericSpecs" do
it "raises a RangeError if the value is more than 64bits" do
-> do
@s.NUM2ULONG(0xffff_ffff_ffff_ffff+1)
- end.should raise_error(RangeError)
+ end.should.raise(RangeError)
end
end
@@ -308,11 +308,11 @@ describe "CApiNumericSpecs" do
describe "NUM2DBL" do
it "raises a TypeError if passed nil" do
- -> { @s.NUM2DBL(nil) }.should raise_error(TypeError)
+ -> { @s.NUM2DBL(nil) }.should.raise(TypeError)
end
it "raises a TypeError if passed a String" do
- -> { @s.NUM2DBL("1.2") }.should raise_error(TypeError)
+ -> { @s.NUM2DBL("1.2") }.should.raise(TypeError)
end
it "converts a Float" do
@@ -348,13 +348,13 @@ describe "CApiNumericSpecs" do
end
it "raises a TypeError when passed an empty String" do
- -> { @s.NUM2CHR("") }.should raise_error(TypeError)
+ -> { @s.NUM2CHR("") }.should.raise(TypeError)
end
end
describe "rb_num_zerodiv" do
it "raises a RuntimeError" do
- -> { @s.rb_num_zerodiv() }.should raise_error(ZeroDivisionError, 'divided by 0')
+ -> { @s.rb_num_zerodiv() }.should.raise(ZeroDivisionError, 'divided by 0')
end
end
@@ -386,7 +386,7 @@ describe "CApiNumericSpecs" do
it "raises an ArgumentError when passed nil" do
-> {
@s.rb_cmpint(nil, 4)
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
end
@@ -410,7 +410,7 @@ describe "CApiNumericSpecs" do
obj = mock("rb_num_coerce_bin")
obj.should_receive(:coerce).with(2).and_return(nil)
- -> { @s.rb_num_coerce_bin(2, obj, :+) }.should raise_error(TypeError)
+ -> { @s.rb_num_coerce_bin(2, obj, :+) }.should.raise(TypeError)
end
end
@@ -435,14 +435,14 @@ describe "CApiNumericSpecs" do
obj.should_receive(:coerce).with(2).and_raise(RuntimeError.new("my error"))
-> {
@s.rb_num_coerce_cmp(2, obj, :<=>)
- }.should raise_error(RuntimeError, "my error")
+ }.should.raise(RuntimeError, "my error")
end
it "returns nil if #coerce does not return an Array" do
obj = mock("rb_num_coerce_cmp")
obj.should_receive(:coerce).with(2).and_return(nil)
- @s.rb_num_coerce_cmp(2, obj, :<=>).should be_nil
+ @s.rb_num_coerce_cmp(2, obj, :<=>).should == nil
end
end
@@ -451,7 +451,7 @@ describe "CApiNumericSpecs" do
obj = mock("rb_num_coerce_relop")
obj.should_receive(:coerce).with(2).and_return([1, 2])
- @s.rb_num_coerce_relop(2, obj, :<).should be_true
+ @s.rb_num_coerce_relop(2, obj, :<).should == true
end
it "calls the specified method on the first argument returned by #coerce" do
@@ -459,7 +459,7 @@ describe "CApiNumericSpecs" do
obj.should_receive(:coerce).with(2).and_return([obj, 2])
obj.should_receive(:<).with(2).and_return(false)
- @s.rb_num_coerce_relop(2, obj, :<).should be_false
+ @s.rb_num_coerce_relop(2, obj, :<).should == false
end
it "raises an ArgumentError if #<op> returns nil" do
@@ -467,14 +467,14 @@ describe "CApiNumericSpecs" do
obj.should_receive(:coerce).with(2).and_return([obj, 2])
obj.should_receive(:<).with(2).and_return(nil)
- -> { @s.rb_num_coerce_relop(2, obj, :<) }.should raise_error(ArgumentError)
+ -> { @s.rb_num_coerce_relop(2, obj, :<) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if #coerce does not return an Array" do
obj = mock("rb_num_coerce_relop")
obj.should_receive(:coerce).with(2).and_return(nil)
- -> { @s.rb_num_coerce_relop(2, obj, :<) }.should raise_error(ArgumentError)
+ -> { @s.rb_num_coerce_relop(2, obj, :<) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb
index 7bc7bd992a..8e907a5a8c 100644
--- a/spec/ruby/optional/capi/object_spec.rb
+++ b/spec/ruby/optional/capi/object_spec.rb
@@ -64,7 +64,7 @@ describe "CApiObject" do
it "allocates a new uninitialized object" do
o = @o.rb_obj_alloc(CApiObjectSpecs::Alloc)
o.class.should == CApiObjectSpecs::Alloc
- o.initialized.should be_nil
+ o.initialized.should == nil
end
end
@@ -77,17 +77,17 @@ describe "CApiObject" do
obj2.foo.should == obj1.foo
- obj2.should_not equal(obj1)
+ obj2.should_not.equal?(obj1)
end
end
describe "rb_obj_call_init" do
it "sends #initialize" do
o = @o.rb_obj_alloc(CApiObjectSpecs::Alloc)
- o.initialized.should be_nil
+ o.initialized.should == nil
@o.rb_obj_call_init(o, 2, [:one, :two])
- o.initialized.should be_true
+ o.initialized.should == true
o.arguments.should == [:one, :two]
end
@@ -235,7 +235,7 @@ describe "CApiObject" do
describe "rb_obj_instance_variables" do
it "returns an array with instance variable names as symbols" do
o = ObjectTest.new
- @o.rb_obj_instance_variables(o).should include(:@foo)
+ @o.rb_obj_instance_variables(o).should.include?(:@foo)
end
end
@@ -244,21 +244,21 @@ describe "CApiObject" do
ary = [1, 2]
ary.should_not_receive(:to_ary)
- @o.rb_check_convert_type(ary, "Array", "to_ary").should equal(ary)
+ @o.rb_check_convert_type(ary, "Array", "to_ary").should.equal?(ary)
end
it "returns the passed object and does not call the converting method if the object is a subclass of the specified type" do
obj = CApiObjectSpecs::SubArray.new
obj.should_not_receive(:to_array)
- @o.rb_check_convert_type(obj, "Array", "to_array").should equal(obj)
+ @o.rb_check_convert_type(obj, "Array", "to_array").should.equal?(obj)
end
it "returns nil if the converting method returns nil" do
obj = mock("rb_check_convert_type")
obj.should_receive(:to_array).and_return(nil)
- @o.rb_check_convert_type(obj, "Array", "to_array").should be_nil
+ @o.rb_check_convert_type(obj, "Array", "to_array").should == nil
end
it "raises a TypeError if the converting method returns an object that is not the specified type" do
@@ -267,7 +267,7 @@ describe "CApiObject" do
-> do
@o.rb_check_convert_type(obj, "Array", "to_array")
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
@@ -276,14 +276,14 @@ describe "CApiObject" do
ary = [1, 2]
ary.should_not_receive(:to_ary)
- @o.rb_convert_type(ary, "Array", "to_ary").should equal(ary)
+ @o.rb_convert_type(ary, "Array", "to_ary").should.equal?(ary)
end
it "returns the passed object and does not call the converting method if the object is a subclass of the specified type" do
obj = CApiObjectSpecs::SubArray.new
obj.should_not_receive(:to_array)
- @o.rb_convert_type(obj, "Array", "to_array").should equal(obj)
+ @o.rb_convert_type(obj, "Array", "to_array").should.equal?(obj)
end
it "raises a TypeError if the converting method returns nil" do
@@ -292,7 +292,7 @@ describe "CApiObject" do
-> do
@o.rb_convert_type(obj, "Array", "to_array")
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
it "raises a TypeError if the converting method returns an object that is not the specified type" do
@@ -301,109 +301,109 @@ describe "CApiObject" do
-> do
@o.rb_convert_type(obj, "Array", "to_array")
- end.should raise_error(TypeError)
+ end.should.raise(TypeError)
end
end
describe "rb_check_array_type" do
it "returns the argument if it's an Array" do
x = Array.new
- @o.rb_check_array_type(x).should equal(x)
+ @o.rb_check_array_type(x).should.equal?(x)
end
it "returns the argument if it's a kind of Array" do
x = AryChild.new
- @o.rb_check_array_type(x).should equal(x)
+ @o.rb_check_array_type(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_ary" do
- @o.rb_check_array_type(Object.new).should be_nil
+ @o.rb_check_array_type(Object.new).should == nil
end
it "sends #to_ary to the argument and returns the result if it's nil" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(nil)
- @o.rb_check_array_type(obj).should be_nil
+ @o.rb_check_array_type(obj).should == nil
end
it "sends #to_ary to the argument and returns the result if it's an Array" do
x = Array.new
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(x)
- @o.rb_check_array_type(obj).should equal(x)
+ @o.rb_check_array_type(obj).should.equal?(x)
end
it "sends #to_ary to the argument and returns the result if it's a kind of Array" do
x = AryChild.new
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(x)
- @o.rb_check_array_type(obj).should equal(x)
+ @o.rb_check_array_type(obj).should.equal?(x)
end
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { @o.rb_check_array_type obj }.should raise_error(TypeError)
+ -> { @o.rb_check_array_type obj }.should.raise(TypeError)
end
it "does not rescue exceptions raised by #to_ary" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_raise(FrozenError)
- -> { @o.rb_check_array_type obj }.should raise_error(FrozenError)
+ -> { @o.rb_check_array_type obj }.should.raise(FrozenError)
end
end
describe "rb_check_string_type" do
it "returns the argument if it's a String" do
x = String.new
- @o.rb_check_string_type(x).should equal(x)
+ @o.rb_check_string_type(x).should.equal?(x)
end
it "returns the argument if it's a kind of String" do
x = StrChild.new
- @o.rb_check_string_type(x).should equal(x)
+ @o.rb_check_string_type(x).should.equal?(x)
end
it "returns nil when the argument does not respond to #to_str" do
- @o.rb_check_string_type(Object.new).should be_nil
+ @o.rb_check_string_type(Object.new).should == nil
end
it "sends #to_str to the argument and returns the result if it's nil" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(nil)
- @o.rb_check_string_type(obj).should be_nil
+ @o.rb_check_string_type(obj).should == nil
end
it "sends #to_str to the argument and returns the result if it's a String" do
x = String.new
obj = mock("to_str")
obj.should_receive(:to_str).and_return(x)
- @o.rb_check_string_type(obj).should equal(x)
+ @o.rb_check_string_type(obj).should.equal?(x)
end
it "sends #to_str to the argument and returns the result if it's a kind of String" do
x = StrChild.new
obj = mock("to_str")
obj.should_receive(:to_str).and_return(x)
- @o.rb_check_string_type(obj).should equal(x)
+ @o.rb_check_string_type(obj).should.equal?(x)
end
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- -> { @o.rb_check_string_type obj }.should raise_error(TypeError)
+ -> { @o.rb_check_string_type obj }.should.raise(TypeError)
end
it "does not rescue exceptions raised by #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_raise(RuntimeError)
- -> { @o.rb_check_string_type obj }.should raise_error(RuntimeError)
+ -> { @o.rb_check_string_type obj }.should.raise(RuntimeError)
end
end
describe "rb_check_to_integer" do
it "returns the object when passed a Fixnum" do
- @o.rb_check_to_integer(5, "to_int").should equal(5)
+ @o.rb_check_to_integer(5, "to_int").should.equal?(5)
end
it "returns the object when passed a Bignum" do
@@ -414,7 +414,7 @@ describe "CApiObject" do
obj = mock("rb_check_to_integer")
obj.should_receive(:to_integer).and_return(10)
- @o.rb_check_to_integer(obj, "to_integer").should equal(10)
+ @o.rb_check_to_integer(obj, "to_integer").should.equal?(10)
end
it "calls the converting method and returns a Bignum value" do
@@ -428,23 +428,23 @@ describe "CApiObject" do
obj = mock("rb_check_to_integer")
obj.should_receive(:to_integer).and_return(nil)
- @o.rb_check_to_integer(obj, "to_integer").should be_nil
+ @o.rb_check_to_integer(obj, "to_integer").should == nil
end
it "returns nil when the converting method does not return an Integer" do
obj = mock("rb_check_to_integer")
obj.should_receive(:to_integer).and_return("string")
- @o.rb_check_to_integer(obj, "to_integer").should be_nil
+ @o.rb_check_to_integer(obj, "to_integer").should == nil
end
end
describe "FL_ABLE" do
it "returns correct boolean for type" do
- @o.FL_ABLE(Object.new).should be_true
- @o.FL_ABLE(true).should be_false
- @o.FL_ABLE(nil).should be_false
- @o.FL_ABLE(1).should be_false
+ @o.FL_ABLE(Object.new).should == true
+ @o.FL_ABLE(true).should == false
+ @o.FL_ABLE(nil).should == false
+ @o.FL_ABLE(1).should == false
end
end
@@ -476,9 +476,9 @@ describe "CApiObject" do
it "returns the singleton class if it exists" do
o = ObjectTest.new
- @o.rb_class_of(o).should equal ObjectTest
+ @o.rb_class_of(o).should.equal? ObjectTest
s = o.singleton_class
- @o.rb_class_of(o).should equal s
+ @o.rb_class_of(o).should.equal? s
end
end
@@ -493,7 +493,7 @@ describe "CApiObject" do
it "does not return the singleton class if it exists" do
o = ObjectTest.new
o.singleton_class
- @o.rb_obj_class(o).should equal ObjectTest
+ @o.rb_obj_class(o).should.equal? ObjectTest
end
end
@@ -553,15 +553,15 @@ describe "CApiObject" do
it "raises an exception if the object is not of the expected type" do
-> {
@o.rb_check_type([], Object.new)
- }.should raise_error(TypeError, 'wrong argument type Array (expected Object)')
+ }.should.raise(TypeError, 'wrong argument type Array (expected Object)')
-> {
@o.rb_check_type(ObjectTest, Module.new)
- }.should raise_error(TypeError, 'wrong argument type Class (expected Module)')
+ }.should.raise(TypeError, 'wrong argument type Class (expected Module)')
-> {
@o.rb_check_type(nil, "string")
- }.should raise_error(TypeError, 'wrong argument type nil (expected String)')
+ }.should.raise(TypeError, 'wrong argument type nil (expected String)')
end
end
@@ -592,49 +592,49 @@ describe "CApiObject" do
describe "RTEST" do
it "returns C false if passed Qfalse" do
- @o.RTEST(false).should be_false
+ @o.RTEST(false).should == false
end
it "returns C false if passed Qnil" do
- @o.RTEST(nil).should be_false
+ @o.RTEST(nil).should == false
end
it "returns C true if passed Qtrue" do
- @o.RTEST(true).should be_true
+ @o.RTEST(true).should == true
end
it "returns C true if passed a Symbol" do
- @o.RTEST(:test).should be_true
+ @o.RTEST(:test).should == true
end
it "returns C true if passed an Object" do
- @o.RTEST(Object.new).should be_true
+ @o.RTEST(Object.new).should == true
end
end
describe "rb_special_const_p" do
it "returns true if passed Qfalse" do
- @o.rb_special_const_p(false).should be_true
+ @o.rb_special_const_p(false).should == true
end
it "returns true if passed Qtrue" do
- @o.rb_special_const_p(true).should be_true
+ @o.rb_special_const_p(true).should == true
end
it "returns true if passed Qnil" do
- @o.rb_special_const_p(nil).should be_true
+ @o.rb_special_const_p(nil).should == true
end
it "returns true if passed a Symbol" do
- @o.rb_special_const_p(:test).should be_true
+ @o.rb_special_const_p(:test).should == true
end
it "returns true if passed a Fixnum" do
- @o.rb_special_const_p(10).should be_true
+ @o.rb_special_const_p(10).should == true
end
it "returns false if passed an Object" do
- @o.rb_special_const_p(Object.new).should be_false
+ @o.rb_special_const_p(Object.new).should == false
end
end
@@ -665,7 +665,7 @@ describe "CApiObject" do
it "freezes the object passed to it" do
obj = ""
@o.rb_obj_freeze(obj).should == obj
- obj.frozen?.should be_true
+ obj.frozen?.should == true
end
end
@@ -674,7 +674,7 @@ describe "CApiObject" do
obj = ObjectTest
-> do
@o.rb_obj_instance_eval(obj) { include Kernel }
- end.should_not raise_error(NoMethodError)
+ end.should_not.raise(NoMethodError)
end
end
@@ -691,17 +691,27 @@ describe "CApiObject" do
end
end
+ describe "redefining frozen? works" do
+ it "allows an object to override frozen?" do
+ obj = CApiObjectRedefinitionSpecs.new
+
+ obj.frozen?.should == false
+ obj.freeze
+ obj.frozen?.should == true
+ end
+ end
+
describe "rb_obj_taint" do
end
describe "rb_check_frozen" do
it "raises a FrozenError if the obj is frozen" do
- -> { @o.rb_check_frozen("".freeze) }.should raise_error(FrozenError)
+ -> { @o.rb_check_frozen("".freeze) }.should.raise(FrozenError)
end
it "does nothing when object isn't frozen" do
obj = +""
- -> { @o.rb_check_frozen(obj) }.should_not raise_error(TypeError)
+ -> { @o.rb_check_frozen(obj) }.should_not.raise(TypeError)
end
end
@@ -709,13 +719,13 @@ describe "CApiObject" do
it "converts an Integer to string" do
obj = 1
i = @o.rb_any_to_s(obj)
- i.should be_kind_of(String)
+ i.should.is_a?(String)
end
it "converts an Object to string" do
obj = Object.new
i = @o.rb_any_to_s(obj)
- i.should be_kind_of(String)
+ i.should.is_a?(String)
end
end
@@ -741,61 +751,61 @@ describe "CApiObject" do
it "raises a TypeError if #to_int does not return an Integer" do
x = mock("to_int")
x.should_receive(:to_int).and_return("5")
- -> { @o.rb_to_int(x) }.should raise_error(TypeError)
+ -> { @o.rb_to_int(x) }.should.raise(TypeError)
end
it "raises a TypeError if called with nil" do
- -> { @o.rb_to_int(nil) }.should raise_error(TypeError)
+ -> { @o.rb_to_int(nil) }.should.raise(TypeError)
end
it "raises a TypeError if called with true" do
- -> { @o.rb_to_int(true) }.should raise_error(TypeError)
+ -> { @o.rb_to_int(true) }.should.raise(TypeError)
end
it "raises a TypeError if called with false" do
- -> { @o.rb_to_int(false) }.should raise_error(TypeError)
+ -> { @o.rb_to_int(false) }.should.raise(TypeError)
end
it "raises a TypeError if called with a String" do
- -> { @o.rb_to_int("1") }.should raise_error(TypeError)
+ -> { @o.rb_to_int("1") }.should.raise(TypeError)
end
end
describe "rb_equal" do
it "returns true if the arguments are the same exact object" do
s = "hello"
- @o.rb_equal(s, s).should be_true
+ @o.rb_equal(s, s).should == true
end
it "calls == to check equality and coerces to true/false" do
m = mock("string")
m.should_receive(:==).and_return(8)
- @o.rb_equal(m, "hello").should be_true
+ @o.rb_equal(m, "hello").should == true
m2 = mock("string")
m2.should_receive(:==).and_return(nil)
- @o.rb_equal(m2, "hello").should be_false
+ @o.rb_equal(m2, "hello").should == false
end
end
describe "rb_class_inherited_p" do
it "returns true if mod equals arg" do
- @o.rb_class_inherited_p(Array, Array).should be_true
+ @o.rb_class_inherited_p(Array, Array).should == true
end
it "returns true if mod is a subclass of arg" do
- @o.rb_class_inherited_p(Array, Object).should be_true
+ @o.rb_class_inherited_p(Array, Object).should == true
end
it "returns nil if mod is not a subclass of arg" do
- @o.rb_class_inherited_p(Array, Hash).should be_nil
+ @o.rb_class_inherited_p(Array, Hash).should == nil
end
it "raises a TypeError if arg is no class or module" do
->{
@o.rb_class_inherited_p(1, 2)
- }.should raise_error(TypeError)
+ }.should.raise(TypeError)
end
end
@@ -888,7 +898,7 @@ describe "CApiObject" do
end
end
- # The `generic_iv_tbl` table and `*_generic_ivar` functions are for mutable
+ # The `generic_fields_tbl` table and `*_generic_ivar` functions are for mutable
# objects which do not store ivars directly in MRI such as RString, because
# there is no member iv_index_tbl (ivar table) such as in RObject and RClass.
@@ -919,7 +929,7 @@ describe "CApiObject" do
@o.rb_define_alloc_func(klass)
obj = klass.allocate
obj.class.should.equal?(klass)
- obj.should have_instance_variable(:@from_custom_allocator)
+ obj.should.instance_variable_defined?(:@from_custom_allocator)
end
it "sets up the allocator for a subclass of String" do
@@ -927,7 +937,7 @@ describe "CApiObject" do
@o.rb_define_alloc_func(klass)
obj = klass.allocate
obj.class.should.equal?(klass)
- obj.should have_instance_variable(:@from_custom_allocator)
+ obj.should.instance_variable_defined?(:@from_custom_allocator)
obj.should == ""
end
@@ -936,7 +946,7 @@ describe "CApiObject" do
@o.rb_define_alloc_func(klass)
obj = klass.allocate
obj.class.should.equal?(klass)
- obj.should have_instance_variable(:@from_custom_allocator)
+ obj.should.instance_variable_defined?(:@from_custom_allocator)
obj.should == []
end
end
@@ -994,7 +1004,6 @@ describe "CApiObject" do
it "calls the callback function for each cvar and ivar on a class" do
exp = [:@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz]
- exp.unshift(:__classpath__, 'CApiObjectSpecs::CVars') if RUBY_VERSION < "3.3"
ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars)
ary.should == exp
@@ -1002,7 +1011,6 @@ describe "CApiObject" do
it "calls the callback function for each cvar and ivar on a module" do
exp = [:@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz]
- exp.unshift(:__classpath__, 'CApiObjectSpecs::MVars') if RUBY_VERSION < "3.3"
ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars)
ary.should == exp
diff --git a/spec/ruby/optional/capi/proc_spec.rb b/spec/ruby/optional/capi/proc_spec.rb
index 8b94432f3e..1c250fee76 100644
--- a/spec/ruby/optional/capi/proc_spec.rb
+++ b/spec/ruby/optional/capi/proc_spec.rb
@@ -36,7 +36,7 @@ describe "C-API Proc function" do
it "calls the C function with arguments in argv" do
@prc2.call(1, :foo).should == :foo
@prc2.call(2, :foo, :bar).should == :bar
- -> { @prc2.call(3, :foo, :bar) }.should raise_error(ArgumentError)
+ -> { @prc2.call(3, :foo, :bar) }.should.raise(ArgumentError)
end
it "calls the C function with the block passed in blockarg" do
@@ -95,7 +95,7 @@ describe "C-API Proc function" do
it "raises TypeError if the last argument is not a Hash" do
-> {
@p.rb_proc_call_kw(proc {}, [42])
- }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ }.should.raise(TypeError, 'no implicit conversion of Integer into Hash')
end
end
@@ -125,7 +125,7 @@ describe "C-API Proc function" do
it "raises TypeError if the last argument is not a Hash" do
-> {
@p.rb_proc_call_with_block_kw(proc {}, [42], proc {})
- }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ }.should.raise(TypeError, 'no implicit conversion of Integer into Hash')
end
it "passes keyword arguments to the proc when a block is nil" do
@@ -138,19 +138,19 @@ describe "C-API Proc function" do
describe "rb_obj_is_proc" do
it "returns true for Proc" do
prc = Proc.new {|a,b| a * b }
- @p.rb_obj_is_proc(prc).should be_true
+ @p.rb_obj_is_proc(prc).should == true
end
it "returns true for subclass of Proc" do
prc = Class.new(Proc).new {}
- @p.rb_obj_is_proc(prc).should be_true
+ @p.rb_obj_is_proc(prc).should == true
end
it "returns false for non Proc instances" do
- @p.rb_obj_is_proc("aoeui").should be_false
- @p.rb_obj_is_proc(123).should be_false
- @p.rb_obj_is_proc(true).should be_false
- @p.rb_obj_is_proc([]).should be_false
+ @p.rb_obj_is_proc("aoeui").should == false
+ @p.rb_obj_is_proc(123).should == false
+ @p.rb_obj_is_proc(true).should == false
+ @p.rb_obj_is_proc([]).should == false
end
end
end
@@ -172,17 +172,17 @@ describe "C-API when calling Proc.new from a C function" do
it "raises an ArgumentError when the C function calls a Ruby method that calls Proc.new" do
-> {
@p.rb_Proc_new(2) { :called }
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
# Ruby -> C -> Ruby -> C -> rb_funcall(Proc.new)
it "raises an ArgumentError when the C function calls a Ruby method and that method calls a C function that calls Proc.new" do
def @p.redispatch() rb_Proc_new(0) end
- -> { @p.rb_Proc_new(3) { :called } }.should raise_error(ArgumentError)
+ -> { @p.rb_Proc_new(3) { :called } }.should.raise(ArgumentError)
end
# Ruby -> C -> Ruby -> block_given?
it "returns false from block_given? in a Ruby method called by the C function" do
- @p.rb_Proc_new(6).should be_false
+ @p.rb_Proc_new(6).should == false
end
end
diff --git a/spec/ruby/optional/capi/range_spec.rb b/spec/ruby/optional/capi/range_spec.rb
index 7a52dc7ff8..9213862aa4 100644
--- a/spec/ruby/optional/capi/range_spec.rb
+++ b/spec/ruby/optional/capi/range_spec.rb
@@ -31,8 +31,8 @@ describe "C-API Range function" do
end
it "raises an ArgumentError when the given start and end can't be compared by using #<=>" do
- -> { @s.rb_range_new(1, mock('x')) }.should raise_error(ArgumentError)
- -> { @s.rb_range_new(mock('x'), mock('y')) }.should raise_error(ArgumentError)
+ -> { @s.rb_range_new(1, mock('x')) }.should.raise(ArgumentError)
+ -> { @s.rb_range_new(mock('x'), mock('y')) }.should.raise(ArgumentError)
end
end
@@ -41,7 +41,7 @@ describe "C-API Range function" do
beg, fin, excl = @s.rb_range_values(10..20)
beg.should == 10
fin.should == 20
- excl.should be_false
+ excl.should == false
end
it "stores the range properties of non-Range object" do
@@ -62,34 +62,170 @@ describe "C-API Range function" do
beg, fin, excl = @s.rb_range_values(range_like)
beg.should == 10
fin.should == 20
- excl.should be_false
+ excl.should == false
end
end
describe "rb_range_beg_len" do
it "returns correct begin, length and result" do
r = 2..5
- begp, lenp, result = @s.rb_range_beg_len(r, 0, 0, 10, 0)
- result.should be_true
+ begp, lenp, result = @s.rb_range_beg_len(r, 10, 0)
+ result.should == true
begp.should == 2
lenp.should == 4
end
it "returns nil when not in range" do
r = 2..5
- begp, lenp, result = @s.rb_range_beg_len(r, 0, 0, 1, 0)
- result.should be_nil
+ begp, lenp, result = @s.rb_range_beg_len(r, 1, 0)
+ result.should == nil
end
it "raises a RangeError when not in range and err is 1" do
r = -5..-1
- -> { @s.rb_range_beg_len(r, 0, 0, 1, 1) }.should raise_error(RangeError)
+ -> { @s.rb_range_beg_len(r, 1, 1) }.should.raise(RangeError)
end
it "returns nil when not in range and err is 0" do
r = -5..-1
- begp, lenp, result = @s.rb_range_beg_len(r, 0, 0, 1, 0)
- result.should be_nil
+ begp, lenp, result = @s.rb_range_beg_len(r, 1, 0)
+ result.should == nil
+ end
+ end
+
+ describe "rb_arithmetic_sequence_extract" do
+ it "returns begin, end, step, exclude end of an instance of an Enumerator::ArithmeticSequence" do
+ enum = (10..20).step(5)
+ enum.should.kind_of?(Enumerator::ArithmeticSequence)
+
+ @s.rb_arithmetic_sequence_extract(enum).should == [1, 10, 20, 5, false]
+ end
+
+ it "returns begin, end, step, exclude end of an instance of a Range" do
+ range = (10..20)
+ @s.rb_arithmetic_sequence_extract(range).should == [1, 10, 20, 1, false]
+ end
+
+ it "returns begin, end, step, exclude end of a non-Range object with Range properties" do
+ object = Object.new
+ def object.begin
+ 10
+ end
+ def object.end
+ 20
+ end
+ def object.exclude_end?
+ false
+ end
+
+ @s.rb_arithmetic_sequence_extract(object).should == [1, 10, 20, 1, false]
+ end
+
+ it "returns failed status if given object is not Enumerator::ArithmeticSequence or Range or Range-like object" do
+ object = Object.new
+ @s.rb_arithmetic_sequence_extract(object).should == [0]
+ end
+ end
+
+ describe "rb_arithmetic_sequence_beg_len_step" do
+ it "returns correct begin, length, step and result" do
+ as = (2..5).step(5)
+ error_code = 0
+
+ success, beg, len, step = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
+ success.should == true
+
+ beg.should == 2
+ len.should == 4
+ step.should == 5
+ end
+
+ it "takes into account excluded end boundary" do
+ as = (2...5).step(1)
+ error_code = 0
+
+ success, _, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
+ success.should == true
+ len.should == 3
+ end
+
+ it "adds length to negative begin boundary" do
+ as = (-2..5).step(1)
+ error_code = 0
+
+ success, beg, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
+ success.should == true
+
+ beg.should == 4
+ len.should == 2
+ end
+
+ it "adds length to negative end boundary" do
+ as = (2..-1).step(1)
+ error_code = 0
+
+ success, beg, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
+ success.should == true
+
+ beg.should == 2
+ len.should == 4
+ end
+
+ it "truncates arithmetic sequence length if end boundary greater than specified length value" do
+ as = (2..10).step(1)
+ error_code = 0
+
+ success, _, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
+ success.should == true
+ len.should == 4
+ end
+
+ it "returns inverted begin and end boundaries when step is negative" do
+ as = (2..5).step(-2)
+ error_code = 0
+
+ success, beg, len, step = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
+ success.should == true
+
+ beg.should == 5
+ len.should == 0
+ step.should == -2
+ end
+
+ it "returns nil when not in range and error code = 0" do
+ as = (2..5).step(1)
+ error_code = 0
+
+ success, = @s.rb_arithmetic_sequence_beg_len_step(as, 1, error_code)
+ success.should == nil
+ end
+
+ it "returns nil when not in range, negative boundaries and error code = 0" do
+ as = (-5..-1).step(1)
+ error_code = 0
+
+ success, = @s.rb_arithmetic_sequence_beg_len_step(as, 1, 0)
+ success.should == nil
+ end
+
+ it "returns begin, length and step and doesn't raise a RangeError when not in range and error code = 1" do
+ as = (2..5).step(1)
+ error_code = 1
+
+ success, beg, len, step = @s.rb_arithmetic_sequence_beg_len_step(as, 1, error_code)
+ success.should == true
+
+ beg.should == 2
+ len.should == 4
+ step.should == 1
+ end
+
+ it "returns nil and doesn't raise a RangeError when not in range, negative boundaries and error code = 1" do
+ as = (-5..-1).step(1)
+ error_code = 1
+
+ success, = @s.rb_arithmetic_sequence_beg_len_step(as, 1, error_code)
+ success.should == nil
end
end
end
diff --git a/spec/ruby/optional/capi/regexp_spec.rb b/spec/ruby/optional/capi/regexp_spec.rb
index 4b130ff66a..f233b5e3b3 100644
--- a/spec/ruby/optional/capi/regexp_spec.rb
+++ b/spec/ruby/optional/capi/regexp_spec.rb
@@ -104,13 +104,13 @@ describe "C-API Regexp function" do
end
Thread.pass while thr.status and !running
- $~.should be_nil
+ $~.should == nil
thr.join
end
end
- describe "rb_memicmp" do
+ describe "rb_memcicmp" do
it "returns 0 for identical strings" do
@p.rb_memcicmp('Hello', 'Hello').should == 0
end
diff --git a/spec/ruby/optional/capi/set_spec.rb b/spec/ruby/optional/capi/set_spec.rb
new file mode 100644
index 0000000000..21a9756236
--- /dev/null
+++ b/spec/ruby/optional/capi/set_spec.rb
@@ -0,0 +1,96 @@
+require_relative 'spec_helper'
+
+ruby_version_is "4.0" do
+ load_extension("set")
+
+ describe "C-API Set function" do
+ before :each do
+ @s = CApiSetSpecs.new
+ end
+
+ describe "rb_set_foreach" do
+ it "calls function with each element and arg" do
+ a = []
+ @s.rb_set_foreach(Set[1, 2], 3) {|*args| a.concat(args) }
+ a.should == [1, 3, 2, 3]
+ end
+
+ it "respects function return value" do
+ a = []
+ @s.rb_set_foreach(Set[1, 2], 3) do |*args|
+ a.concat(args)
+ false
+ end
+ a.should == [1, 3]
+ end
+ end
+
+ describe "rb_set_new" do
+ it "returns a new set" do
+ @s.rb_set_new.should == Set[]
+ end
+ end
+
+ describe "rb_set_new_capa" do
+ it "returns a new set" do
+ @s.rb_set_new_capa(3).should == Set[]
+ end
+ end
+
+ describe "rb_set_lookup" do
+ it "returns whether the element is in the set" do
+ set = Set[1]
+ @s.rb_set_lookup(set, 1).should == true
+ @s.rb_set_lookup(set, 2).should == false
+ end
+ end
+
+ describe "rb_set_add" do
+ it "adds element to set" do
+ set = Set[]
+ @s.rb_set_add(set, 1).should == true
+ set.should == Set[1]
+ @s.rb_set_add(set, 2).should == true
+ set.should == Set[1, 2]
+ end
+
+ it "returns false if element is already in set" do
+ set = Set[1]
+ @s.rb_set_add(set, 1).should == false
+ set.should == Set[1]
+ end
+ end
+
+ describe "rb_set_clear" do
+ it "empties and returns self" do
+ set = Set[1]
+ @s.rb_set_clear(set).should.equal?(set)
+ set.should == Set[]
+ end
+ end
+
+ describe "rb_set_delete" do
+ it "removes element from set" do
+ set = Set[1, 2]
+ @s.rb_set_delete(set, 1).should == true
+ set.should == Set[2]
+ @s.rb_set_delete(set, 2).should == true
+ set.should == Set[]
+ end
+
+ it "returns false if element is not already in set" do
+ set = Set[2]
+ @s.rb_set_delete(set, 1).should == false
+ set.should == Set[2]
+ end
+ end
+
+ describe "rb_set_size" do
+ it "returns number of elements in set" do
+ @s.rb_set_size(Set[]).should == 0
+ @s.rb_set_size(Set[1]).should == 1
+ @s.rb_set_size(Set[1,2]).should == 2
+ end
+ end
+ end
+end
diff --git a/spec/ruby/optional/capi/shared/rbasic.rb b/spec/ruby/optional/capi/shared/rbasic.rb
index 9d80a93e1d..e3485d4b7b 100644
--- a/spec/ruby/optional/capi/shared/rbasic.rb
+++ b/spec/ruby/optional/capi/shared/rbasic.rb
@@ -1,7 +1,6 @@
describe :rbasic, shared: true do
before :all do
specs = CApiRBasicSpecs.new
- @taint = ruby_version_is(''...'3.1') ? specs.taint_flag : 0
@freeze = specs.freeze_flag
end
diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb
index 2691aa1332..49ce23d874 100644
--- a/spec/ruby/optional/capi/spec_helper.rb
+++ b/spec/ruby/optional/capi/spec_helper.rb
@@ -59,7 +59,11 @@ def compile_extension(name)
tmpdir = tmp("cext_#{name}")
Dir.mkdir(tmpdir)
begin
- ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"].each do |file|
+ files = ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"]
+ if spec_ext_dir != core_ext_dir
+ files += Dir.glob("#{spec_ext_dir}/*.h")
+ end
+ files.each do |file|
if cxx and file.end_with?('.c')
cp file, "#{tmpdir}/#{File.basename(file, '.c')}.cpp"
else
@@ -74,12 +78,25 @@ def compile_extension(name)
init_mkmf unless required
create_makefile(ext, tmpdir)
else
+ # Workaround for digest C-API specs to find the ruby/digest.h header
+ # when run in the CRuby repository via make test-spec
+ if MSpecScript.instance_variable_defined?(:@testing_ruby)
+ ruby_repository_extra_include_dir = "-I#{RbConfig::CONFIG.fetch("prefix")}/#{RbConfig::CONFIG.fetch("EXTOUT")}/include"
+ end
+
File.write("extconf.rb", <<-RUBY)
require 'mkmf'
$ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ')
# MRI magic to consider building non-bundled extensions
$extout = nil
+ if RbConfig::CONFIG.key?("buildlibdir") # The top directory where the libruby is built.
+ # Prepend the dummy macro to bypass the conversion in `with_destdir` on DOSISH
+ # platforms, where the drive letter is replaced with `$(DESTDIR)`. `DESTDIR` is
+ # overridden by the command line argument bellow.
+ RbConfig::MAKEFILE_CONFIG["buildlibdir"] = "$(empty)" + RbConfig::CONFIG["buildlibdir"]
+ end
append_cflags '-Wno-declaration-after-statement'
+ #{"append_cflags #{ruby_repository_extra_include_dir.inspect}" if ruby_repository_extra_include_dir}
create_makefile(#{ext.inspect})
RUBY
output = ruby_exe("extconf.rb")
@@ -89,7 +106,7 @@ def compile_extension(name)
# Do not capture stderr as we want to show compiler warnings
make, opts = setup_make
- output = IO.popen([make, "V=1", "DESTDIR=", opts], &:read)
+ output = IO.popen([*make, "V=1", "DESTDIR=", opts], &:read)
raise "#{make} failed:\n#{output}" unless $?.success?
$stderr.puts output if debug
@@ -106,26 +123,34 @@ end
def setup_make
make = ENV['MAKE']
make ||= (RbConfig::CONFIG['host_os'].include?("mswin") ? "nmake" : "make")
- make_flags = ENV["MAKEFLAGS"] || ''
+ env = %w[MFLAGS MAKEFLAGS GNUMAKEFLAGS].to_h {|var| [var, ENV[var]]}
+ make_flags = env["MAKEFLAGS"] || ''
# suppress logo of nmake.exe to stderr
if File.basename(make, ".*").downcase == "nmake" and !make_flags.include?("l")
- ENV["MAKEFLAGS"] = "l#{make_flags}"
+ env["MAKEFLAGS"] = "l#{make_flags}"
end
opts = {}
if /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ make_flags
- begin
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- rescue Errno::EBADF
- else
- opts[r] = r
- opts[w] = w
+ [$1, $2].each do |fd|
+ fd = IO.for_fd(fd.to_i(10), autoclose: false)
+ opts[fd] = fd
+ rescue
+ # Jobserver is not usable, maybe no `+` flag or on Windows.
+ job_options = /\A\s*(?:-j\d+\s*|-\S+\Kj\d+)|(?:\G|\s)\K--jobserver-(?:auth|fds)=\S+\s*/
+ env["MAKEFLAGS"] = make_flags.gsub(job_options, '')
+ %w[GNUMAKEFLAGS MFLAGS].each do |var|
+ if flags = env[var]
+ env[var] = flags.gsub(job_options, '')
+ end
+ end
+ opts.clear
+ break
end
end
- [make, opts]
+ [[env, make], opts]
end
def load_extension(name)
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 18eaeda8e0..569fc8891a 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -191,11 +191,19 @@ describe "C-API String function" do
end
it "returns a new String object filled with \\0 bytes" do
- s = @s.rb_str_tmp_new(4)
- s.encoding.should == Encoding::BINARY
- s.bytesize.should == 4
- s.size.should == 4
- s.should == "\x00\x00\x00\x00"
+ lens = [4]
+
+ ruby_version_is "4.0" do
+ lens << 100
+ end
+
+ lens.each do |len|
+ s = @s.rb_str_tmp_new(len)
+ s.encoding.should == Encoding::BINARY
+ s.bytesize.should == len
+ s.size.should == len
+ s.should == "\x00" * len
+ end
end
end
@@ -278,13 +286,13 @@ describe "C-API String function" do
it "returns a dup of the original String" do
a = "abc"
b = @s.rb_str_encode("abc", "us-ascii", 0, nil)
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
it "returns a duplicate of the original when the encoding doesn't change" do
a = "abc"
b = @s.rb_str_encode("abc", Encoding::UTF_8, 0, nil)
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
it "accepts encoding flags" do
@@ -312,7 +320,7 @@ describe "C-API String function" do
str1 = "hi"
str2 = @s.rb_str_new3 str1
str1.should == str2
- str1.should_not equal str2
+ str1.should_not.equal? str2
end
end
@@ -322,7 +330,7 @@ describe "C-API String function" do
str1.freeze
str2 = @s.rb_str_new4 str1
str1.should == str2
- str1.should equal(str2)
+ str1.should.equal?(str2)
str1.should.frozen?
str2.should.frozen?
end
@@ -331,7 +339,7 @@ describe "C-API String function" do
str1 = "hi"
str2 = @s.rb_str_new4 str1
str1.should == str2
- str1.should_not equal(str2)
+ str1.should_not.equal?(str2)
str2.should.frozen?
end
end
@@ -341,7 +349,7 @@ describe "C-API String function" do
str1 = "hi"
str2 = @s.rb_str_dup str1
str1.should == str2
- str1.should_not equal str2
+ str1.should_not.equal? str2
end
end
@@ -362,7 +370,7 @@ describe "C-API String function" do
end
it "raises a TypeError trying to append non-String-like object" do
- -> { @s.rb_str_append("Hello", 32323)}.should raise_error(TypeError)
+ -> { @s.rb_str_append("Hello", 32323)}.should.raise(TypeError)
end
it "changes Encoding if a string is appended to an empty string" do
@@ -491,7 +499,7 @@ describe "C-API String function" do
end
it "converts a C string to a Fixnum strictly if base is 0" do
- -> { @s.rb_cstr2inum("1234a", 0) }.should raise_error(ArgumentError)
+ -> { @s.rb_cstr2inum("1234a", 0) }.should.raise(ArgumentError)
end
end
@@ -509,7 +517,7 @@ describe "C-API String function" do
end
it "converts a C string to a Fixnum strictly" do
- -> { @s.rb_cstr_to_inum("1234a", 10, true) }.should raise_error(ArgumentError)
+ -> { @s.rb_cstr_to_inum("1234a", 10, true) }.should.raise(ArgumentError)
end
end
@@ -528,6 +536,61 @@ describe "C-API String function" do
end
end
+ describe "rb_str_sublen" do
+ it "returns the character length for a given byte offset in an ASCII string" do
+ @s.rb_str_sublen("hello", 3).should == 3
+ end
+
+ it "returns the character length for a given byte offset in a multibyte string" do
+ # "hëllo" where 'ë' is 2 bytes in UTF-8, total 6 bytes
+ str = "hëllo"
+ @s.rb_str_sublen(str, 3).should == 2
+ end
+
+ it "returns 0 for byte offset 0" do
+ @s.rb_str_sublen("hello", 0).should == 0
+ end
+
+ it "returns the full character length for the total byte length" do
+ str = "hëllo"
+ @s.rb_str_sublen(str, str.bytesize).should == str.length
+ end
+ end
+
+ describe "rb_str_subpos" do
+ it "returns [byte_offset, byte_length] for a valid character offset in an ASCII string" do
+ @s.rb_str_subpos("hello", 1).should == [1, 4]
+ end
+
+ it "returns [byte_offset, byte_length] for a valid character offset in a multibyte string" do
+ # "hëllo" where 'ë' is 2 bytes in UTF-8
+ str = "hëllo"
+ @s.rb_str_subpos(str, 0).should == [0, 6]
+ @s.rb_str_subpos(str, 1).should == [1, 5]
+ @s.rb_str_subpos(str, 2).should == [3, 3]
+ end
+
+ it "returns [0, byte_length] for offset 0" do
+ @s.rb_str_subpos("hello", 0).should == [0, 5]
+ end
+
+ it "returns nil for a negative offset that is out of range" do
+ @s.rb_str_subpos("hello", -6).should == nil
+ end
+
+ it "returns the correct position for a negative offset" do
+ @s.rb_str_subpos("hello", -2).should == [3, 2]
+ end
+
+ it "returns [byte_length, 0] when offset equals string length" do
+ @s.rb_str_subpos("hello", 5).should == [5, 0]
+ end
+
+ it "returns nil when offset is beyond string length" do
+ @s.rb_str_subpos("hello", 6).should == nil
+ end
+ end
+
describe "rb_str_to_str" do
it "calls #to_str to coerce the value to a String" do
@s.rb_str_to_str("foo").should == "foo"
@@ -535,8 +598,8 @@ describe "C-API String function" do
end
it "raises a TypeError if coercion fails" do
- -> { @s.rb_str_to_str(0) }.should raise_error(TypeError)
- -> { @s.rb_str_to_str(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
+ -> { @s.rb_str_to_str(0) }.should.raise(TypeError)
+ -> { @s.rb_str_to_str(CApiStringSpecs::InvalidTostrTest.new) }.should.raise(TypeError)
end
end
@@ -660,7 +723,7 @@ describe "C-API String function" do
it "does not call #to_s on non-String objects" do
str = mock("fake")
str.should_not_receive(:to_s)
- -> { @s.send(@method, str) }.should raise_error(TypeError)
+ -> { @s.send(@method, str) }.should.raise(TypeError)
end
end
@@ -673,7 +736,7 @@ describe "C-API String function" do
describe "rb_str_modify" do
it "raises an error if the string is frozen" do
- -> { @s.rb_str_modify("frozen".freeze) }.should raise_error(FrozenError)
+ -> { @s.rb_str_modify("frozen".freeze) }.should.raise(FrozenError)
end
end
@@ -704,7 +767,7 @@ describe "C-API String function" do
end
it "raises an error if the string is frozen" do
- -> { @s.rb_str_modify_expand("frozen".freeze, 10) }.should raise_error(FrozenError)
+ -> { @s.rb_str_modify_expand("frozen".freeze, 10) }.should.raise(FrozenError)
end
end
@@ -760,14 +823,14 @@ describe "C-API String function" do
it "freezes the string" do
s = ""
@s.rb_str_freeze(s).should == s
- s.frozen?.should be_true
+ s.frozen?.should == true
end
end
describe "rb_str_hash" do
it "hashes the string into a number" do
s = "hello"
- @s.rb_str_hash(s).should be_kind_of(Integer)
+ @s.rb_str_hash(s).should.is_a?(Integer)
end
end
@@ -783,7 +846,7 @@ describe "rb_str_free" do
# is available. There is no guarantee this even does
# anything at all
it "indicates data for a string might be freed" do
- @s.rb_str_free("xyz").should be_nil
+ @s.rb_str_free("xyz").should == nil
end
end
@@ -825,12 +888,12 @@ describe "C-API String function" do
describe "rb_str_equal" do
it "compares two same strings" do
s = "hello"
- @s.rb_str_equal(s, "hello").should be_true
+ @s.rb_str_equal(s, "hello").should == true
end
it "compares two different strings" do
s = "hello"
- @s.rb_str_equal(s, "hella").should be_false
+ @s.rb_str_equal(s, "hella").should == false
end
end
@@ -865,7 +928,7 @@ describe "C-API String function" do
# - s.should == "\xA4\xA2\xA4\xEC".dup.force_encoding("euc-jp")
# + x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4')#.force_encoding('binary')
# + s.should == x
-# s.encoding.should equal(Encoding::EUC_JP)
+# s.encoding.should.equal?(Encoding::EUC_JP)
# end
it "transcodes a String to Encoding.default_internal if it is set" do
@@ -875,7 +938,7 @@ describe "C-API String function" do
s = @s.rb_external_str_new_with_enc(a, a.bytesize, Encoding::UTF_8)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('euc-jp')
s.should == x
- s.encoding.should equal(Encoding::EUC_JP)
+ s.encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -883,7 +946,7 @@ describe "C-API String function" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new("abc", 3)
s.should == "abc".dup.force_encoding(Encoding.find("locale"))
- s.encoding.should equal(Encoding.find("locale"))
+ s.encoding.should.equal?(Encoding.find("locale"))
end
end
@@ -891,14 +954,14 @@ describe "C-API String function" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new_cstr("abc")
s.should == "abc".dup.force_encoding(Encoding.find("locale"))
- s.encoding.should equal(Encoding.find("locale"))
+ s.encoding.should.equal?(Encoding.find("locale"))
end
end
describe "rb_str_conv_enc" do
it "returns the original String when to encoding is not specified" do
a = "abc".dup.force_encoding("us-ascii")
- @s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should.equal?(a)
end
it "returns the original String if a transcoding error occurs" do
@@ -921,17 +984,17 @@ describe "C-API String function" do
describe "when the String encoding is equal to the destination encoding" do
it "returns the original String" do
a = "abc".dup.force_encoding("us-ascii")
- @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should.equal?(a)
end
it "returns the original String if the destination encoding is ASCII compatible and the String has no high bits set" do
a = "abc".encode("us-ascii")
- @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::US_ASCII).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::US_ASCII).should.equal?(a)
end
it "returns the origin String if the destination encoding is BINARY" do
a = "abc".dup.force_encoding("binary")
- @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::BINARY).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::BINARY).should.equal?(a)
end
end
end
@@ -939,13 +1002,13 @@ describe "C-API String function" do
describe "rb_str_conv_enc_opts" do
it "returns the original String when to encoding is not specified" do
a = "abc".dup.force_encoding("us-ascii")
- @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should equal(a)
+ @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should.equal?(a)
end
it "returns the original String if a transcoding error occurs" do
a = [0xEE].pack('C').force_encoding("utf-8")
@s.rb_str_conv_enc_opts(a, Encoding::UTF_8,
- Encoding::EUC_JP, 0, nil).should equal(a)
+ Encoding::EUC_JP, 0, nil).should.equal?(a)
end
it "returns a transcoded String" do
@@ -953,26 +1016,26 @@ describe "C-API String function" do
result = @s.rb_str_conv_enc_opts(a, Encoding::UTF_8, Encoding::EUC_JP, 0, nil)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8')
result.should == x.force_encoding("euc-jp")
- result.encoding.should equal(Encoding::EUC_JP)
+ result.encoding.should.equal?(Encoding::EUC_JP)
end
describe "when the String encoding is equal to the destination encoding" do
it "returns the original String" do
a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
- Encoding::US_ASCII, 0, nil).should equal(a)
+ Encoding::US_ASCII, 0, nil).should.equal?(a)
end
it "returns the original String if the destination encoding is ASCII compatible and the String has no high bits set" do
a = "abc".encode("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::UTF_8,
- Encoding::US_ASCII, 0, nil).should equal(a)
+ Encoding::US_ASCII, 0, nil).should.equal?(a)
end
it "returns the origin String if the destination encoding is BINARY" do
a = "abc".dup.force_encoding("binary")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
- Encoding::BINARY, 0, nil).should equal(a)
+ Encoding::BINARY, 0, nil).should.equal?(a)
end
end
end
@@ -981,7 +1044,7 @@ describe "C-API String function" do
it "returns the original String with the external encoding" do
Encoding.default_external = Encoding::ISO_8859_1
s = @s.rb_str_export("Hëllo")
- s.encoding.should equal(Encoding::ISO_8859_1)
+ s.encoding.should.equal?(Encoding::ISO_8859_1)
end
end
@@ -989,7 +1052,7 @@ describe "C-API String function" do
it "returns the original String with the locale encoding" do
s = @s.rb_str_export_locale("abc")
s.should == "abc".dup.force_encoding(Encoding.find("locale"))
- s.encoding.should equal(Encoding.find("locale"))
+ s.encoding.should.equal?(Encoding.find("locale"))
end
end
@@ -1004,7 +1067,7 @@ describe "C-API String function" do
it "returns the source string if it can not be converted" do
source = ["00ff"].pack("H*");
result = @s.rb_str_export_to_enc(source, Encoding::UTF_8)
- result.should equal(source)
+ result.should.equal?(source)
end
it "does not alter the source string if it can not be converted" do
@@ -1040,11 +1103,19 @@ describe "C-API String function" do
@s.rb_sprintf3(true.class).should == s
end
- ruby_bug "#19167", ""..."3.2" do
- it "formats a TrueClass VALUE as 'true' if sign specified in format" do
- s = 'Result: TrueClass.'
- @s.rb_sprintf4(true.class).should == s
- end
+ it "formats a TrueClass VALUE as 'true' if sign specified in format" do
+ s = 'Result: TrueClass.'
+ @s.rb_sprintf4(true.class).should == s
+ end
+
+ it "formats nil using to_s if sign not specified in format" do
+ s = 'Result: .'
+ @s.rb_sprintf3(nil).should == s
+ end
+
+ it "formats nil using inspect if sign specified in format" do
+ s = 'Result: nil.'
+ @s.rb_sprintf4(nil).should == s
end
it "truncates a string to a supplied precision if that is shorter than the string" do
@@ -1078,7 +1149,7 @@ describe "C-API String function" do
end
it "can format a nil VALUE as a pointer and gives the same output as sprintf in C" do
- res = @s.rb_sprintf7("%p", nil);
+ res = @s.rb_sprintf7("%p", nil)
res[0].should == res[1]
end
@@ -1088,14 +1159,14 @@ describe "C-API String function" do
end
it "can format a raw number a pointer and gives the same output as sprintf in C" do
- res = @s.rb_sprintf7("%p", 0x223643);
+ res = @s.rb_sprintf7("%p", 0x223643)
res[0].should == res[1]
end
end
describe "rb_vsprintf" do
it "returns a formatted String from a variable number of arguments" do
- s = @s.rb_vsprintf("%s, %d, %.2f", "abc", 42, 2.7);
+ s = @s.rb_vsprintf("%s, %d, %.2f", "abc", 42, 2.7)
s.should == "abc, 42, 2.70"
end
end
@@ -1110,7 +1181,7 @@ describe "C-API String function" do
end
it "raises a TypeError if #to_str does not return a string" do
- -> { @s.rb_String(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
+ -> { @s.rb_String(CApiStringSpecs::InvalidTostrTest.new) }.should.raise(TypeError)
end
it "tries to convert the passed argument to a string by calling #to_s" do
@@ -1128,11 +1199,11 @@ describe "C-API String function" do
end
it "raises an error if a string contains a null" do
- -> { @s.rb_string_value_cstr("Hello\0 with a null.") }.should raise_error(ArgumentError)
+ -> { @s.rb_string_value_cstr("Hello\0 with a null.") }.should.raise(ArgumentError)
end
it "raises an error if a UTF-16 string contains a null" do
- -> { @s.rb_string_value_cstr("Hello\0 with a null.".encode('UTF-16BE')) }.should raise_error(ArgumentError)
+ -> { @s.rb_string_value_cstr("Hello\0 with a null.".encode('UTF-16BE')) }.should.raise(ArgumentError)
end
end
@@ -1159,9 +1230,11 @@ describe "C-API String function" do
describe "rb_utf8_str_new_static" do
it "returns a UTF-8 string of the correct characters and length" do
- str = @s.rb_utf8_str_new_static
+ str, ptr = @s.rb_utf8_str_new_static
str.should == "nokogiri"
str.encoding.should == Encoding::UTF_8
+
+ @s.RSTRING_PTR(str).should == ptr
end
end
@@ -1203,28 +1276,50 @@ describe "C-API String function" do
describe "rb_str_locktmp" do
it "raises an error when trying to lock an already locked string" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str).should == str
- -> { @s.rb_str_locktmp(str) }.should raise_error(RuntimeError, 'temporal locking already locked string')
+ -> { @s.rb_str_locktmp(str) }.should.raise(RuntimeError, 'temporal locking already locked string')
end
it "locks a string so that modifications would raise an error" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str).should == str
- -> { str.upcase! }.should raise_error(RuntimeError, 'can\'t modify string; temporarily locked')
+ -> { str.upcase! }.should.raise(RuntimeError, 'can\'t modify string; temporarily locked')
+ end
+
+ ruby_version_is "4.0" do
+ it "raises FrozenError if string is frozen" do
+ str = -"rb_str_locktmp"
+ -> { @s.rb_str_locktmp(str) }.should.raise(FrozenError)
+
+ str = +"rb_str_locktmp"
+ str.freeze
+ -> { @s.rb_str_locktmp(str) }.should.raise(FrozenError)
+ end
end
end
describe "rb_str_unlocktmp" do
it "unlocks a locked string" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str)
@s.rb_str_unlocktmp(str).should == str
str.upcase!.should == "TEST"
end
it "raises an error when trying to unlock an already unlocked string" do
- -> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
+ -> { @s.rb_str_unlocktmp(+"test") }.should.raise(RuntimeError, 'temporal unlocking already unlocked string')
+ end
+
+ ruby_version_is "4.0" do
+ it "raises FrozenError if string is frozen" do
+ str = -"rb_str_locktmp"
+ -> { @s.rb_str_unlocktmp(str) }.should.raise(FrozenError)
+
+ str = +"rb_str_locktmp"
+ str.freeze
+ -> { @s.rb_str_unlocktmp(str) }.should.raise(FrozenError)
+ end
end
end
@@ -1331,8 +1426,133 @@ describe "C-API String function" do
result1.should_not.equal?(result2)
end
+ it "preserves the encoding of the original string" do
+ result1 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::US_ASCII))
+ result2 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::UTF_8))
+ result1.encoding.should == Encoding::US_ASCII
+ result2.encoding.should == Encoding::UTF_8
+ end
+
it "returns the same string as String#-@" do
@s.rb_str_to_interned_str("hello").should.equal?(-"hello")
end
end
+
+ describe "rb_interned_str" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_interned_str(str, str.bytesize)
+ result.should.is_a?(String)
+ result.should.frozen?
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_interned_str(str, str.bytesize)
+ result2 = @s.rb_interned_str(str, str.bytesize)
+ result1.should.equal?(result2)
+ end
+
+ it "supports strings with embedded null bytes" do
+ str = "foo\x00bar\x00baz".b
+ result = @s.rb_interned_str(str, str.bytesize)
+ result.should == str
+ end
+
+ it "return US_ASCII encoding for an empty string" do
+ result = @s.rb_interned_str("", 0)
+ result.should == ""
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US_ASCII encoding for strings of only 7 bit ASCII" do
+ 0x00.upto(0x7f).each do |char|
+ result = @s.rb_interned_str(char.chr, 1)
+ result.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns BINARY encoding for strings that use the 8th bit" do
+ 0x80.upto(0xff) do |char|
+ result = @s.rb_interned_str(char.chr, 1)
+ result.encoding.should == Encoding::BINARY
+ end
+ end
+ end
+
+ it 'returns the same string when using non-ascii characters' do
+ str = 'こんにちは'
+ result1 = @s.rb_interned_str(str, str.bytesize)
+ result2 = @s.rb_interned_str(str, str.bytesize)
+ result1.should.equal?(result2)
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns the same string as String#-@" do
+ str = "hello".dup.force_encoding(Encoding::US_ASCII)
+ @s.rb_interned_str(str, str.bytesize).should.equal?(-str)
+ end
+ end
+ end
+
+ describe "rb_interned_str_cstr" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_interned_str_cstr(str)
+ result.should.is_a?(String)
+ result.should.frozen?
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_interned_str_cstr(str)
+ result2 = @s.rb_interned_str_cstr(str)
+ result1.should.equal?(result2)
+ end
+
+ it "does not support strings with embedded null bytes" do
+ str = "foo\x00bar\x00baz".b
+ result = @s.rb_interned_str_cstr(str)
+ result.should == "foo"
+ end
+
+ it "return US_ASCII encoding for an empty string" do
+ result = @s.rb_interned_str_cstr("")
+ result.should == ""
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US_ASCII encoding for strings of only 7 bit ASCII" do
+ 0x01.upto(0x7f).each do |char|
+ result = @s.rb_interned_str_cstr(char.chr)
+ result.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns BINARY encoding for strings that use the 8th bit" do
+ 0x80.upto(0xff) do |char|
+ result = @s.rb_interned_str_cstr(char.chr)
+ result.encoding.should == Encoding::BINARY
+ end
+ end
+ end
+
+ it 'returns the same string when using non-ascii characters' do
+ str = 'こんにちは'
+ result1 = @s.rb_interned_str_cstr(str)
+ result2 = @s.rb_interned_str_cstr(str)
+ result1.should.equal?(result2)
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns the same string as String#-@" do
+ str = "hello".dup.force_encoding(Encoding::US_ASCII)
+ @s.rb_interned_str_cstr(str).should.equal?(-str)
+ end
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/struct_spec.rb b/spec/ruby/optional/capi/struct_spec.rb
index 474c397956..843387bc19 100644
--- a/spec/ruby/optional/capi/struct_spec.rb
+++ b/spec/ruby/optional/capi/struct_spec.rb
@@ -25,11 +25,11 @@ describe "C-API Struct function" do
it "has a value of nil for the member of a newly created instance" do
# Verify that attributes are on an instance basis
- Struct::CAPIStruct.new.b.should be_nil
+ Struct::CAPIStruct.new.b.should == nil
end
it "creates a constant scoped under Struct for the named Struct" do
- Struct.should have_constant(:CAPIStruct)
+ Struct.should.const_defined?(:CAPIStruct, false)
end
it "returns the member names as Symbols" do
@@ -80,15 +80,15 @@ describe "C-API Struct function" do
it "has a value of nil for the member of a newly created instance" do
# Verify that attributes are on an instance basis
- CApiStructSpecs::CAPIStructUnder.new.b.should be_nil
+ CApiStructSpecs::CAPIStructUnder.new.b.should == nil
end
it "does not create a constant scoped under Struct for the named Struct" do
- Struct.should_not have_constant(:CAPIStructUnder)
+ Struct.should_not.const_defined?(:CAPIStructUnder)
end
it "creates a constant scoped under the namespace of the given class" do
- CApiStructSpecs.should have_constant(:CAPIStructUnder)
+ CApiStructSpecs.should.const_defined?(:CAPIStructUnder, false)
end
it "returns the member names as Symbols" do
@@ -106,11 +106,11 @@ describe "C-API Struct function" do
describe "rb_struct_define" do
it "raises an ArgumentError if arguments contain duplicate member name" do
- -> { @s.rb_struct_define(nil, "a", "b", "a") }.should raise_error(ArgumentError)
+ -> { @s.rb_struct_define(nil, "a", "b", "a") }.should.raise(ArgumentError)
end
it "raises a NameError if an invalid constant name is given" do
- -> { @s.rb_struct_define("foo", "a", "b", "c") }.should raise_error(NameError)
+ -> { @s.rb_struct_define("foo", "a", "b", "c") }.should.raise(NameError)
end
end
@@ -131,12 +131,12 @@ describe "C-API Struct function" do
end
it "raises a NameError if the struct member does not exist" do
- -> { @s.rb_struct_aref(@struct, :d) }.should raise_error(NameError)
+ -> { @s.rb_struct_aref(@struct, :d) }.should.raise(NameError)
end
it "raises an IndexError if the given index is out of range" do
- -> { @s.rb_struct_aref(@struct, -4) }.should raise_error(IndexError)
- -> { @s.rb_struct_aref(@struct, 3) }.should raise_error(IndexError)
+ -> { @s.rb_struct_aref(@struct, -4) }.should.raise(IndexError)
+ -> { @s.rb_struct_aref(@struct, 3) }.should.raise(IndexError)
end
end
@@ -147,7 +147,7 @@ describe "C-API Struct function" do
end
it "raises a NameError if the struct member does not exist" do
- -> { @s.rb_struct_getmember(@struct, :d) }.should raise_error(NameError)
+ -> { @s.rb_struct_getmember(@struct, :d) }.should.raise(NameError)
end
end
@@ -180,17 +180,17 @@ describe "C-API Struct function" do
end
it "raises a NameError if the struct member does not exist" do
- -> { @s.rb_struct_aset(@struct, :d, 1) }.should raise_error(NameError)
+ -> { @s.rb_struct_aset(@struct, :d, 1) }.should.raise(NameError)
end
it "raises an IndexError if the given index is out of range" do
- -> { @s.rb_struct_aset(@struct, -4, 1) }.should raise_error(IndexError)
- -> { @s.rb_struct_aset(@struct, 3, 1) }.should raise_error(IndexError)
+ -> { @s.rb_struct_aset(@struct, -4, 1) }.should.raise(IndexError)
+ -> { @s.rb_struct_aset(@struct, 3, 1) }.should.raise(IndexError)
end
it "raises a FrozenError if the struct is frozen" do
@struct.freeze
- -> { @s.rb_struct_aset(@struct, :a, 1) }.should raise_error(FrozenError)
+ -> { @s.rb_struct_aset(@struct, :a, 1) }.should.raise(FrozenError)
end
end
@@ -208,53 +208,107 @@ describe "C-API Struct function" do
@s.rb_struct_size(@struct).should == 3
end
end
+
+ describe "rb_struct_initialize" do
+ it "sets all members" do
+ @s.rb_struct_initialize(@struct, [1, 2, 3]).should == nil
+ @struct.a.should == 1
+ @struct.b.should == 2
+ @struct.c.should == 3
+ end
+
+ it "does not freeze the Struct instance" do
+ @s.rb_struct_initialize(@struct, [1, 2, 3]).should == nil
+ @struct.should_not.frozen?
+ @s.rb_struct_initialize(@struct, [4, 5, 6]).should == nil
+ @struct.a.should == 4
+ @struct.b.should == 5
+ @struct.c.should == 6
+ end
+
+ it "raises ArgumentError if too many values" do
+ -> { @s.rb_struct_initialize(@struct, [1, 2, 3, 4]) }.should.raise(ArgumentError, "struct size differs")
+ end
+
+ it "treats missing values as nil" do
+ @s.rb_struct_initialize(@struct, [1, 2]).should == nil
+ @struct.a.should == 1
+ @struct.b.should == 2
+ @struct.c.should == nil
+ end
+ end
end
-ruby_version_is "3.3" do
- describe "C-API Data function" do
- before :each do
- @s = CApiStructSpecs.new
+describe "C-API Data function" do
+ before :all do
+ @s = CApiStructSpecs.new
+ @klass = @s.rb_data_define(nil, "a", "b", "c")
+ end
+
+ describe "rb_data_define" do
+ it "returns a subclass of Data class when passed nil as the first argument" do
+ @klass.should.is_a? Class
+ @klass.superclass.should == Data
end
- describe "rb_data_define" do
- it "returns a subclass of Data class when passed nil as the first argument" do
- klass = @s.rb_data_define(nil, "a", "b", "c")
+ it "returns a subclass of a class when passed as the first argument" do
+ superclass = Class.new(Data)
+ klass = @s.rb_data_define(superclass, "a", "b", "c")
- klass.should.is_a? Class
- klass.superclass.should == Data
- end
+ klass.should.is_a? Class
+ klass.superclass.should == superclass
+ end
- it "returns a subclass of a class when passed as the first argument" do
- superclass = Class.new(Data)
- klass = @s.rb_data_define(superclass, "a", "b", "c")
+ it "creates readers for the members" do
+ obj = @klass.new(1, 2, 3)
- klass.should.is_a? Class
- klass.superclass.should == superclass
- end
+ obj.a.should == 1
+ obj.b.should == 2
+ obj.c.should == 3
+ end
- it "creates readers for the members" do
- klass = @s.rb_data_define(nil, "a", "b", "c")
- obj = klass.new(1, 2, 3)
+ it "returns the member names as Symbols" do
+ obj = @klass.new(0, 0, 0)
- obj.a.should == 1
- obj.b.should == 2
- obj.c.should == 3
- end
+ obj.members.should == [:a, :b, :c]
+ end
- it "returns the member names as Symbols" do
- klass = @s.rb_data_define(nil, "a", "b", "c")
- obj = klass.new(0, 0, 0)
+ it "raises an ArgumentError if arguments contain duplicate member name" do
+ -> { @s.rb_data_define(nil, "a", "b", "a") }.should.raise(ArgumentError)
+ end
- obj.members.should == [:a, :b, :c]
- end
+ it "raises when first argument is not a class" do
+ -> { @s.rb_data_define([], "a", "b", "c") }.should.raise(TypeError, "wrong argument type Array (expected Class)")
+ end
+ end
+
+ describe "rb_struct_initialize" do
+ it "sets all members for a Data instance" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
+ data.a.should == 1
+ data.b.should == 2
+ data.c.should == 3
+ end
- it "raises an ArgumentError if arguments contain duplicate member name" do
- -> { @s.rb_data_define(nil, "a", "b", "a") }.should raise_error(ArgumentError)
- end
+ it "freezes the Data instance" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
+ data.should.frozen?
+ -> { @s.rb_struct_initialize(data, [1, 2, 3]) }.should.raise(FrozenError)
+ end
+
+ it "raises ArgumentError if too many values" do
+ data = @klass.allocate
+ -> { @s.rb_struct_initialize(data, [1, 2, 3, 4]) }.should.raise(ArgumentError, "struct size differs")
+ end
- it "raises when first argument is not a class" do
- -> { @s.rb_data_define([], "a", "b", "c") }.should raise_error(TypeError, "wrong argument type Array (expected Class)")
- end
+ it "treats missing values as nil" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2]).should == nil
+ data.a.should == 1
+ data.b.should == 2
+ data.c.should == nil
end
end
end
diff --git a/spec/ruby/optional/capi/thread_spec.rb b/spec/ruby/optional/capi/thread_spec.rb
index af641f0564..75e0b94fdf 100644
--- a/spec/ruby/optional/capi/thread_spec.rb
+++ b/spec/ruby/optional/capi/thread_spec.rb
@@ -50,7 +50,7 @@ describe "C-API Thread function" do
end
it "returns nil if the value has not been set" do
- @t.rb_thread_local_aref(Thread.current, :thread_capi_specs_undefined).should be_nil
+ @t.rb_thread_local_aref(Thread.current, :thread_capi_specs_undefined).should == nil
end
end
@@ -72,7 +72,7 @@ describe "C-API Thread function" do
obj = Object.new
proc = -> x { ScratchPad.record x }
thr = @t.rb_thread_create(proc, obj)
- thr.should be_kind_of(Thread)
+ thr.should.is_a?(Thread)
thr.join
ScratchPad.recorded.should == obj
end
@@ -83,18 +83,18 @@ describe "C-API Thread function" do
raise "my error"
}
thr = @t.rb_thread_create(prc, nil)
- thr.should be_kind_of(Thread)
+ thr.should.is_a?(Thread)
-> {
thr.join
- }.should raise_error(RuntimeError, "my error")
+ }.should.raise(RuntimeError, "my error")
end
it "sets the thread's group" do
thr = @t.rb_thread_create(-> x { }, nil)
begin
thread_group = thr.group
- thread_group.should be_an_instance_of(ThreadGroup)
+ thread_group.should.instance_of?(ThreadGroup)
ensure
thr.join
end
@@ -103,11 +103,11 @@ describe "C-API Thread function" do
describe "ruby_native_thread_p" do
it "returns non-zero for a ruby thread" do
- @t.ruby_native_thread_p.should be_true
+ @t.ruby_native_thread_p.should == true
end
it "returns zero for a non ruby thread" do
- @t.ruby_native_thread_p_new_thread.should be_false
+ @t.ruby_native_thread_p_new_thread.should == false
end
end
@@ -128,7 +128,7 @@ describe "C-API Thread function" do
thr.wakeup
# Make sure it stopped and we got a proper value
- thr.value.should be_true
+ thr.value.should == true
end
platform_is_not :windows do
@@ -159,7 +159,7 @@ describe "C-API Thread function" do
going_to_block = true
# Make sure it stopped and we got a proper value
- @t.rb_thread_call_without_gvl.should be_true
+ @t.rb_thread_call_without_gvl.should == true
interrupter.join
end
@@ -181,7 +181,15 @@ describe "C-API Thread function" do
thr.wakeup
# Make sure it stopped and we got a proper value
- thr.value.should be_true
+ thr.value.should == true
+ end
+ end
+
+ ruby_version_is "4.0" do
+ describe "ruby_thread_has_gvl_p" do
+ it "returns true if the current thread has the GVL" do
+ @t.ruby_thread_has_gvl_p.should == true
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/time_spec.rb b/spec/ruby/optional/capi/time_spec.rb
index ca5fc5952a..dc0b09376e 100644
--- a/spec/ruby/optional/capi/time_spec.rb
+++ b/spec/ruby/optional/capi/time_spec.rb
@@ -16,7 +16,7 @@ describe "CApiTimeSpecs" do
describe "TIMET2NUM" do
it "returns an Integer" do
- @s.TIMET2NUM.should be_kind_of(Integer)
+ @s.TIMET2NUM.should.is_a?(Integer)
end
end
@@ -32,7 +32,7 @@ describe "CApiTimeSpecs" do
it "creates a Time in the local zone with only a timestamp" do
with_timezone("Europe/Amsterdam") do
time = @s.rb_time_num_new(1232141421, nil)
- time.should be_an_instance_of(Time)
+ time.should.instance_of?(Time)
time.to_i.should == 1232141421
platform_is_not :windows do
time.gmt_offset.should == 3600
@@ -43,7 +43,7 @@ describe "CApiTimeSpecs" do
it "creates a Time with the given offset" do
with_timezone("Europe/Amsterdam") do
time = @s.rb_time_num_new(1232141421, 7200)
- time.should be_an_instance_of(Time)
+ time.should.instance_of?(Time)
time.to_i.should == 1232141421
time.gmt_offset.should == 7200
end
@@ -52,7 +52,7 @@ describe "CApiTimeSpecs" do
it "creates a Time with a Float timestamp" do
with_timezone("Europe/Amsterdam") do
time = @s.rb_time_num_new(1.5, 7200)
- time.should be_an_instance_of(Time)
+ time.should.instance_of?(Time)
time.to_i.should == 1
time.nsec.should == 500000000
time.gmt_offset.should == 7200
@@ -62,7 +62,7 @@ describe "CApiTimeSpecs" do
it "creates a Time with a Rational timestamp" do
with_timezone("Europe/Amsterdam") do
time = @s.rb_time_num_new(Rational(3, 2), 7200)
- time.should be_an_instance_of(Time)
+ time.should.instance_of?(Time)
time.to_i.should == 1
time.nsec.should == 500000000
time.gmt_offset.should == 7200
@@ -73,32 +73,32 @@ describe "CApiTimeSpecs" do
describe "rb_time_interval" do
it "creates a timeval interval for a Fixnum" do
sec, usec = @s.rb_time_interval(1232141421)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1232141421
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 0
end
it "creates a timeval interval for a Float" do
sec, usec = @s.rb_time_interval(1.5)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "creates a timeval interval for a Rational" do
sec, usec = @s.rb_time_interval(Rational(3, 2))
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "throws an argument error for a negative value" do
- -> { @s.rb_time_interval(-1232141421) }.should raise_error(ArgumentError)
- -> { @s.rb_time_interval(Rational(-3, 2)) }.should raise_error(ArgumentError)
- -> { @s.rb_time_interval(-1.5) }.should raise_error(ArgumentError)
+ -> { @s.rb_time_interval(-1232141421) }.should.raise(ArgumentError)
+ -> { @s.rb_time_interval(Rational(-3, 2)) }.should.raise(ArgumentError)
+ -> { @s.rb_time_interval(-1.5) }.should.raise(ArgumentError)
end
end
@@ -106,36 +106,36 @@ describe "CApiTimeSpecs" do
describe "rb_time_interval" do
it "creates a timeval interval for a Fixnum" do
sec, usec = @s.rb_time_interval(1232141421)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1232141421
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 0
end
it "creates a timeval interval for a Float" do
sec, usec = @s.rb_time_interval(1.5)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "creates a timeval interval for a Rational" do
sec, usec = @s.rb_time_interval(Rational(3, 2))
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "throws an argument error for a negative value" do
- -> { @s.rb_time_interval(-1232141421) }.should raise_error(ArgumentError)
- -> { @s.rb_time_interval(Rational(-3, 2)) }.should raise_error(ArgumentError)
- -> { @s.rb_time_interval(-1.5) }.should raise_error(ArgumentError)
+ -> { @s.rb_time_interval(-1232141421) }.should.raise(ArgumentError)
+ -> { @s.rb_time_interval(Rational(-3, 2)) }.should.raise(ArgumentError)
+ -> { @s.rb_time_interval(-1.5) }.should.raise(ArgumentError)
end
it "throws an argument error when given a Time instance" do
- -> { @s.rb_time_interval(Time.now) }.should raise_error(TypeError)
+ -> { @s.rb_time_interval(Time.now) }.should.raise(TypeError)
end
end
@@ -143,49 +143,49 @@ describe "CApiTimeSpecs" do
describe "rb_time_timeval" do
it "creates a timeval for a Fixnum" do
sec, usec = @s.rb_time_timeval(1232141421)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1232141421
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 0
end
it "creates a timeval for a Float" do
sec, usec = @s.rb_time_timeval(1.5)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "creates a timeval for a Rational" do
sec, usec = @s.rb_time_timeval(Rational(3, 2))
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "creates a timeval for a negative Fixnum" do
sec, usec = @s.rb_time_timeval(-1232141421)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == -1232141421
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 0
end
it "creates a timeval for a negative Float" do
sec, usec = @s.rb_time_timeval(-1.5)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == -2
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
it "creates a timeval for a negative Rational" do
sec, usec = @s.rb_time_timeval(Rational(-3, 2))
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == -2
- usec.should be_kind_of(Integer)
+ usec.should.is_a?(Integer)
usec.should == 500000
end
@@ -200,49 +200,49 @@ describe "CApiTimeSpecs" do
describe "rb_time_timespec" do
it "creates a timespec for a Fixnum" do
sec, nsec = @s.rb_time_timespec(1232141421)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1232141421
- nsec.should be_kind_of(Integer)
+ nsec.should.is_a?(Integer)
nsec.should == 0
end
it "creates a timespec for a Float" do
sec, nsec = @s.rb_time_timespec(1.5)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- nsec.should be_kind_of(Integer)
+ nsec.should.is_a?(Integer)
nsec.should == 500000000
end
it "creates a timespec for a Rational" do
sec, nsec = @s.rb_time_timespec(Rational(3, 2))
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == 1
- nsec.should be_kind_of(Integer)
+ nsec.should.is_a?(Integer)
nsec.should == 500000000
end
it "creates a timespec for a negative Fixnum" do
sec, nsec = @s.rb_time_timespec(-1232141421)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == -1232141421
- nsec.should be_kind_of(Integer)
+ nsec.should.is_a?(Integer)
nsec.should == 0
end
it "creates a timespec for a negative Float" do
sec, nsec = @s.rb_time_timespec(-1.5)
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == -2
- nsec.should be_kind_of(Integer)
+ nsec.should.is_a?(Integer)
nsec.should == 500000000
end
it "creates a timespec for a negative Rational" do
sec, nsec = @s.rb_time_timespec(Rational(-3, 2))
- sec.should be_kind_of(Integer)
+ sec.should.is_a?(Integer)
sec.should == -2
- nsec.should be_kind_of(Integer)
+ nsec.should.is_a?(Integer)
nsec.should == 500000000
end
@@ -261,7 +261,7 @@ describe "CApiTimeSpecs" do
describe "when offset given is within range of -86400 and 86400 (exclusive)" do
it "sets time's is_gmt to false" do
- @s.rb_time_timespec_new(1447087832, 476451125, 0).gmt?.should be_false
+ @s.rb_time_timespec_new(1447087832, 476451125, 0).gmt?.should == false
end
it "sets time's offset to the offset given" do
@@ -270,7 +270,7 @@ describe "CApiTimeSpecs" do
end
it "returns time object in UTC if offset given equals INT_MAX - 1" do
- @s.rb_time_timespec_new(1447087832, 476451125, 0x7ffffffe).utc?.should be_true
+ @s.rb_time_timespec_new(1447087832, 476451125, 0x7ffffffe).utc?.should == true
end
it "returns time object in localtime if offset given equals INT_MAX" do
@@ -280,13 +280,13 @@ describe "CApiTimeSpecs" do
end
it "raises an ArgumentError if offset passed is not within range of -86400 and 86400 (exclusive)" do
- -> { @s.rb_time_timespec_new(1447087832, 476451125, 86400) }.should raise_error(ArgumentError)
- -> { @s.rb_time_timespec_new(1447087832, 476451125, -86400) }.should raise_error(ArgumentError)
+ -> { @s.rb_time_timespec_new(1447087832, 476451125, 86400) }.should.raise(ArgumentError)
+ -> { @s.rb_time_timespec_new(1447087832, 476451125, -86400) }.should.raise(ArgumentError)
end
it "doesn't call Time.at directly" do
Time.should_not_receive(:at)
- @s.rb_time_timespec_new(1447087832, 476451125, 32400).should be_kind_of(Time)
+ @s.rb_time_timespec_new(1447087832, 476451125, 32400).should.is_a?(Time)
end
end
@@ -294,7 +294,7 @@ describe "CApiTimeSpecs" do
it "fills a struct timespec with the current time" do
now = Time.now
time = @s.rb_time_from_timespec(now.utc_offset)
- time.should be_an_instance_of(Time)
+ time.should.instance_of?(Time)
(time - now).should be_close(0, TIME_TOLERANCE)
end
end
diff --git a/spec/ruby/optional/capi/tracepoint_spec.rb b/spec/ruby/optional/capi/tracepoint_spec.rb
index 2043b7c941..8775715e04 100644
--- a/spec/ruby/optional/capi/tracepoint_spec.rb
+++ b/spec/ruby/optional/capi/tracepoint_spec.rb
@@ -14,7 +14,7 @@ describe "CApiTracePointSpecs" do
describe "rb_tracepoint_new" do
it "returns a tracepoint object" do
@trace = @s.rb_tracepoint_new(7)
- @trace.should be_an_instance_of(TracePoint)
+ @trace.should.instance_of?(TracePoint)
@trace.should_not.enabled?
end
diff --git a/spec/ruby/optional/capi/typed_data_spec.rb b/spec/ruby/optional/capi/typed_data_spec.rb
index 6d1398a1a0..376cfe417f 100644
--- a/spec/ruby/optional/capi/typed_data_spec.rb
+++ b/spec/ruby/optional/capi/typed_data_spec.rb
@@ -30,7 +30,7 @@ describe "CApiWrappedTypedStruct" do
it "throws an exception for a wrong type" do
a = @s.typed_wrap_struct(1024)
- -> { @s.typed_get_struct_other(a) }.should raise_error(TypeError)
+ -> { @s.typed_get_struct_other(a) }.should.raise(TypeError)
end
it "unwraps data for a parent type" do
@@ -63,7 +63,7 @@ describe "CApiWrappedTypedStruct" do
-> {
a = @s.typed_wrap_struct(1024)
@s.rb_check_type(a, a)
- }.should raise_error(TypeError) { |e|
+ }.should.raise(TypeError) { |e|
e.message.should == 'wrong argument type Object (expected Data)'
}
end
@@ -82,19 +82,21 @@ describe "CApiWrappedTypedStruct" do
it "raises an error for different types" do
a = @s.typed_wrap_struct(1024)
- -> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError)
+ -> { @s.rb_check_typeddata_different_type(a) }.should.raise(TypeError)
end
end
- describe "RTYPEDDATA_P" do
- it "returns true for a typed data" do
- a = @s.typed_wrap_struct(1024)
- @s.RTYPEDDATA_P(a).should == true
- end
+ ruby_version_is ""..."4.1" do
+ describe "RTYPEDDATA_P" do
+ it "returns true for a typed data" do
+ a = @s.typed_wrap_struct(1024)
+ @s.RTYPEDDATA_P(a).should == true
+ end
- it "returns false for an untyped data object" do
- a = @s.untyped_wrap_struct(1024)
- @s.RTYPEDDATA_P(a).should == false
+ it "returns false for an untyped data object" do
+ a = @s.untyped_wrap_struct(1024)
+ @s.RTYPEDDATA_P(a).should == false
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb
index 6cf064bf97..dd3cbb6549 100644
--- a/spec/ruby/optional/capi/util_spec.rb
+++ b/spec/ruby/optional/capi/util_spec.rb
@@ -21,11 +21,11 @@ describe "C-API Util function" do
end
it "raises an ArgumentError if there are insufficient arguments" do
- -> { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should raise_error(ArgumentError)
+ -> { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 3)")
end
it "raises an ArgumentError if there are too many arguments" do
- -> { @o.rb_scan_args([1, 2, 3, 4], "3", 0, @acc) }.should raise_error(ArgumentError)
+ -> { @o.rb_scan_args([1, 2, 3, 4], "3", 0, @acc) }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 3)")
end
it "assigns the required and optional arguments scanned" do
@@ -117,8 +117,15 @@ describe "C-API Util function" do
it "rejects the use of nil as a hash" do
-> {
- @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1
- }.should raise_error(ArgumentError)
+ @o.rb_scan_args([1, nil], "1:", 2, @acc)
+ }.should.raise(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ ScratchPad.recorded.should == []
+ end
+
+ it "rejects the use of of a non-Hash as keywords" do
+ -> {
+ @o.rb_scan_args([42], ":", 1, @acc)
+ }.should.raise(ArgumentError, "wrong number of arguments (given 1, expected 0)")
ScratchPad.recorded.should == []
end
@@ -186,7 +193,7 @@ describe "C-API Util function" do
it "raises an error if a required argument is not in the hash" do
h = { :a => 7, :c => 12, :b => 5 }
- -> { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should raise_error(ArgumentError, /missing keyword: :?d/)
+ -> { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should.raise(ArgumentError, "missing keyword: :d")
h.should == {:a => 7, :c => 12}
end
@@ -198,7 +205,7 @@ describe "C-API Util function" do
it "raises an error if there are additional arguments and optional is positive" do
h = { :a => 7, :c => 12, :b => 5 }
- -> { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should raise_error(ArgumentError, /unknown keyword: :?c/)
+ -> { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should.raise(ArgumentError, "unknown keyword: :c")
h.should == {:c => 12}
end
@@ -212,7 +219,7 @@ describe "C-API Util function" do
platform_is c_long_size: 64 do
describe "rb_long2int" do
it "raises a RangeError if the value is outside the range of a C int" do
- -> { @o.rb_long2int(0xffff_ffff_ffff) }.should raise_error(RangeError)
+ -> { @o.rb_long2int(0xffff_ffff_ffff) }.should.raise(RangeError)
end
end
@@ -258,7 +265,7 @@ describe "C-API Util function" do
describe "rb_sourceline" do
it "returns the current ruby file" do
- @o.rb_sourceline.should be_kind_of(Integer)
+ @o.rb_sourceline.should.is_a?(Integer)
end
end
diff --git a/spec/ruby/optional/thread_safety/fixtures/classes.rb b/spec/ruby/optional/thread_safety/fixtures/classes.rb
new file mode 100644
index 0000000000..4f0ad030e5
--- /dev/null
+++ b/spec/ruby/optional/thread_safety/fixtures/classes.rb
@@ -0,0 +1,39 @@
+module ThreadSafetySpecs
+ # Returns the number of processors, rounded up so it's always a multiple of 2
+ def self.processors
+ require 'etc'
+ n = Etc.nprocessors
+ raise "expected at least 1 processor" if n < 1
+ n += 1 if n.odd? # ensure it's a multiple of 2
+ n
+ end
+
+ class Counter
+ def initialize
+ @value = 0
+ @mutex = Mutex.new
+ end
+
+ def get
+ @mutex.synchronize { @value }
+ end
+
+ def increment
+ @mutex.synchronize do
+ @value += 1
+ end
+ end
+ end
+
+ class Barrier
+ def initialize(parties)
+ @parties = parties
+ @counter = Counter.new
+ end
+
+ def wait
+ @counter.increment
+ Thread.pass until @counter.get == @parties
+ end
+ end
+end
diff --git a/spec/ruby/optional/thread_safety/hash_spec.rb b/spec/ruby/optional/thread_safety/hash_spec.rb
new file mode 100644
index 0000000000..53127fc973
--- /dev/null
+++ b/spec/ruby/optional/thread_safety/hash_spec.rb
@@ -0,0 +1,210 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Hash thread safety" do
+ it "supports concurrent #[]=" do
+ n_threads = ThreadSafetySpecs.processors
+
+ n = 1_000
+ operations = n * n_threads
+
+ h = {}
+ barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1)
+
+ threads = n_threads.times.map { |t|
+ Thread.new {
+ barrier.wait
+ base = t * n
+ n.times do |j|
+ h[base+j] = t
+ end
+ }
+ }
+
+ barrier.wait
+ threads.each(&:join)
+
+ h.size.should == operations
+ h.each_pair { |key, value|
+ (key / n).should == value
+ }
+ end
+
+ # can't add a new key into hash during iteration (RuntimeError) on CRuby.
+ # Yet it's good to test this for implementations that support it.
+ guard_not -> { PlatformGuard.standard? } do
+ it "supports concurrent #[]= and #delete and iteration" do
+ n_threads = ThreadSafetySpecs.processors
+
+ n = 1_000
+ operations = n * n_threads / 2
+
+ h = {}
+ barrier1 = ThreadSafetySpecs::Barrier.new(n_threads + 2)
+ barrier2 = ThreadSafetySpecs::Barrier.new(n_threads + 1)
+
+ threads = n_threads.times.map { |t|
+ Thread.new {
+ barrier1.wait
+ base = t * n
+ n.times do |j|
+ h[base+j] = t
+ end
+
+ barrier2.wait
+ n.times do |j|
+ # delete only even keys
+ h.delete(base+j).should == t if (base+j).even?
+ end
+ }
+ }
+
+ read = true
+ reader = Thread.new {
+ barrier1.wait
+ while read
+ h.each_pair { |k,v|
+ k.should.is_a?(Integer)
+ v.should.is_a?(Integer)
+ (k / n).should == v
+ }
+ end
+ }
+
+ barrier1.wait
+ barrier2.wait
+ threads.each(&:join)
+ read = false
+ reader.join
+
+ # odd keys are left
+ h.size.should == operations
+ h.each_pair { |key, value|
+ key.should.odd?
+ (key / n).should == value
+ }
+ end
+ end
+
+ it "supports concurrent #[]= and #[]" do
+ n_threads = ThreadSafetySpecs.processors
+
+ n = 1_000
+ operations = n * n_threads / 2
+
+ h = {}
+ barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1)
+
+ threads = n_threads.times.map { |t|
+ Thread.new {
+ barrier.wait
+ base = (t / 2) * n
+
+ if t.even?
+ n.times do |j|
+ k = base + j
+ h[k] = k
+ end
+ else
+ n.times do |j|
+ k = base + j
+ Thread.pass until v = h[k]
+ v.should == k
+ end
+ end
+ }
+ }
+
+ barrier.wait
+ threads.each(&:join)
+
+ h.size.should == operations
+ h.each_pair { |key, value|
+ key.should == value
+ }
+ end
+
+ it "supports concurrent #[]= and #[] with change to #compare_by_identity in the middle" do
+ n_threads = ThreadSafetySpecs.processors
+
+ n = 1_000
+ operations = n * n_threads / 2
+
+ h = {}
+ barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1)
+
+ threads = n_threads.times.map { |t|
+ Thread.new {
+ barrier.wait
+ base = (t / 2) * n
+
+ if t.even?
+ n.times do |j|
+ k = base + j
+ h[k] = k
+ end
+ else
+ n.times do |j|
+ k = base + j
+ Thread.pass until v = h[k]
+ v.should == k
+ end
+ end
+ }
+ }
+
+ changer = Thread.new {
+ Thread.pass until h.size >= operations / 2
+ h.should_not.compare_by_identity?
+ h.compare_by_identity
+ h.should.compare_by_identity?
+ }
+
+ barrier.wait
+ threads.each(&:join)
+ changer.join
+
+ h.size.should == operations
+ h.each_pair { |key, value|
+ key.should == value
+ }
+ end
+
+ it "supports repeated concurrent #[]= and #delete and always returns a #size >= 0" do
+ n_threads = ThreadSafetySpecs.processors
+
+ n = 1_000
+ operations = n * n_threads / 2
+
+ h = {}
+ barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1)
+ deleted = ThreadSafetySpecs::Counter.new
+
+ threads = n_threads.times.map { |t|
+ Thread.new {
+ barrier.wait
+ key = t / 2
+
+ if t.even?
+ n.times {
+ Thread.pass until h.delete(key)
+ h.size.should >= 0
+ deleted.increment
+ }
+ else
+ n.times {
+ h[key] = key
+ Thread.pass while h.key?(key)
+ }
+ end
+ }
+ }
+
+ barrier.wait
+ threads.each(&:join)
+
+ deleted.get.should == operations
+ h.size.should == 0
+ h.should.empty?
+ end
+end
diff --git a/spec/ruby/security/cve_2010_1330_spec.rb b/spec/ruby/security/cve_2010_1330_spec.rb
index 2594439550..8867fb7135 100644
--- a/spec/ruby/security/cve_2010_1330_spec.rb
+++ b/spec/ruby/security/cve_2010_1330_spec.rb
@@ -14,6 +14,6 @@ describe "String#gsub" do
str.force_encoding Encoding::UTF_8
-> {
str.gsub(/</, "&lt;")
- }.should raise_error(ArgumentError, /invalid byte sequence in UTF-8/)
+ }.should.raise(ArgumentError, /invalid byte sequence in UTF-8/)
end
end
diff --git a/spec/ruby/security/cve_2018_8778_spec.rb b/spec/ruby/security/cve_2018_8778_spec.rb
index 62057faa53..bbdaac734c 100644
--- a/spec/ruby/security/cve_2018_8778_spec.rb
+++ b/spec/ruby/security/cve_2018_8778_spec.rb
@@ -5,6 +5,6 @@ describe "String#unpack" do
pos = (1 << PlatformGuard::POINTER_SIZE) - 99
-> {
"0123456789".unpack("@#{pos}C10")
- }.should raise_error(RangeError, /pack length too big/)
+ }.should.raise(RangeError, /pack length too big/)
end
end
diff --git a/spec/ruby/security/cve_2018_8779_spec.rb b/spec/ruby/security/cve_2018_8779_spec.rb
index 603dcf497b..6d573ea7fd 100644
--- a/spec/ruby/security/cve_2018_8779_spec.rb
+++ b/spec/ruby/security/cve_2018_8779_spec.rb
@@ -18,13 +18,13 @@ platform_is_not :windows do
it "UNIXServer.open by raising an exception when there is a NUL byte" do
-> {
UNIXServer.open(@path+"\0")
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
it "UNIXSocket.open by raising an exception when there is a NUL byte" do
-> {
UNIXSocket.open(@path+"\0")
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
end
end
diff --git a/spec/ruby/security/cve_2018_8780_spec.rb b/spec/ruby/security/cve_2018_8780_spec.rb
index 9942e07ee2..dc8c6bcc9b 100644
--- a/spec/ruby/security/cve_2018_8780_spec.rb
+++ b/spec/ruby/security/cve_2018_8780_spec.rb
@@ -8,36 +8,36 @@ describe "CVE-2018-8780 is resisted by" do
it "Dir.glob by raising an exception when there is a NUL byte" do
-> {
Dir.glob([[@root, File.join(@root, "*")].join("\0")])
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
it "Dir.entries by raising an exception when there is a NUL byte" do
-> {
Dir.entries(@root+"\0")
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
it "Dir.foreach by raising an exception when there is a NUL byte" do
-> {
Dir.foreach(@root+"\0").to_a
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
it "Dir.empty? by raising an exception when there is a NUL byte" do
-> {
Dir.empty?(@root+"\0")
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
it "Dir.children by raising an exception when there is a NUL byte" do
-> {
Dir.children(@root+"\0")
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
it "Dir.each_child by raising an exception when there is a NUL byte" do
-> {
Dir.each_child(@root+"\0").to_a
- }.should raise_error(ArgumentError, /(path name|string) contains null byte/)
+ }.should.raise(ArgumentError, /(path name|string) contains null byte/)
end
end
diff --git a/spec/ruby/security/cve_2019_8322_spec.rb b/spec/ruby/security/cve_2019_8322_spec.rb
index b70d78c033..dbc273f313 100644
--- a/spec/ruby/security/cve_2019_8322_spec.rb
+++ b/spec/ruby/security/cve_2019_8322_spec.rb
@@ -1,21 +1,24 @@
require_relative '../spec_helper'
-require 'yaml'
-require 'rubygems'
-require 'rubygems/safe_yaml'
-require 'rubygems/commands/owner_command'
+ruby_version_is ""..."4.0" do
-describe "CVE-2019-8322 is resisted by" do
- it "sanitising owner names" do
- command = Gem::Commands::OwnerCommand.new
- def command.rubygems_api_request(*args)
- Struct.new(:body).new("---\n- email: \"\e]2;nyan\a\"\n handle: handle\n id: id\n")
- end
- def command.with_response(response)
- yield response
+ require 'yaml'
+ require 'rubygems'
+ require 'rubygems/safe_yaml'
+ require 'rubygems/commands/owner_command'
+
+ describe "CVE-2019-8322 is resisted by" do
+ it "sanitising owner names" do
+ command = Gem::Commands::OwnerCommand.new
+ def command.rubygems_api_request(*args)
+ Struct.new(:body).new("---\n- email: \"\e]2;nyan\a\"\n handle: handle\n id: id\n")
+ end
+ def command.with_response(response)
+ yield response
+ end
+ command.should_receive(:say).with("Owners for gem: name")
+ command.should_receive(:say).with("- .]2;nyan.")
+ command.show_owners "name"
end
- command.should_receive(:say).with("Owners for gem: name")
- command.should_receive(:say).with("- .]2;nyan.")
- command.show_owners "name"
end
end
diff --git a/spec/ruby/security/cve_2020_10663_spec.rb b/spec/ruby/security/cve_2020_10663_spec.rb
index 80e860348b..7f42c40742 100644
--- a/spec/ruby/security/cve_2020_10663_spec.rb
+++ b/spec/ruby/security/cve_2020_10663_spec.rb
@@ -1,6 +1,6 @@
require_relative '../spec_helper'
-ruby_version_is ""..."3.5" do
+ruby_version_is ""..."4.0" do
require 'json'
module JSONSpecs
@@ -21,7 +21,7 @@ ruby_version_is ""..."3.5" do
guard -> {
JSON.const_defined?(:Pure) or
- version_is(JSON::VERSION, '2.3.0')
+ version_is(JSON::VERSION, '2.3.0'...'2.11.0')
} do
describe "CVE-2020-10663 is resisted by" do
it "only creating custom objects if passed create_additions: true or using JSON.load" do
diff --git a/spec/ruby/security/cve_2024_49761_spec.rb b/spec/ruby/security/cve_2024_49761_spec.rb
index 54ede39032..c66b438eef 100644
--- a/spec/ruby/security/cve_2024_49761_spec.rb
+++ b/spec/ruby/security/cve_2024_49761_spec.rb
@@ -1,9 +1,7 @@
require_relative '../spec_helper'
-ruby_version_is "3.2" do
- describe "CVE-2024-49761 is resisted by" do
- it "the Regexp implementation handling that regular expression in linear time" do
- Regexp.linear_time?(/&#0*((?:\d+)|(?:x[a-fA-F0-9]+));/).should == true
- end
+describe "CVE-2024-49761 is resisted by" do
+ it "the Regexp implementation handling that regular expression in linear time" do
+ Regexp.linear_time?(/&#0*((?:\d+)|(?:x[a-fA-F0-9]+));/).should == true
end
end
diff --git a/spec/ruby/shared/basicobject/method_missing.rb b/spec/ruby/shared/basicobject/method_missing.rb
index 4871603dce..330f6a4922 100644
--- a/spec/ruby/shared/basicobject/method_missing.rb
+++ b/spec/ruby/shared/basicobject/method_missing.rb
@@ -24,15 +24,15 @@ end
describe :method_missing_module, shared: true do
describe "for a Module" do
it "raises a NoMethodError when an undefined method is called" do
- -> { @object.no_such_method }.should raise_error(NoMethodError)
+ -> { @object.no_such_method }.should.raise(NoMethodError)
end
it "raises a NoMethodError when a protected method is called" do
- -> { @object.method_protected }.should raise_error(NoMethodError)
+ -> { @object.method_protected }.should.raise(NoMethodError)
end
it "raises a NoMethodError when a private method is called" do
- -> { @object.method_private }.should raise_error(NoMethodError)
+ -> { @object.method_private }.should.raise(NoMethodError)
end
end
end
@@ -60,15 +60,15 @@ end
describe :method_missing_class, shared: true do
describe "for a Class" do
it "raises a NoMethodError when an undefined method is called" do
- -> { @object.no_such_method }.should raise_error(NoMethodError)
+ -> { @object.no_such_method }.should.raise(NoMethodError)
end
it "raises a NoMethodError when a protected method is called" do
- -> { @object.method_protected }.should raise_error(NoMethodError)
+ -> { @object.method_protected }.should.raise(NoMethodError)
end
it "raises a NoMethodError when a private method is called" do
- -> { @object.method_private }.should raise_error(NoMethodError)
+ -> { @object.method_private }.should.raise(NoMethodError)
end
end
end
@@ -100,15 +100,15 @@ end
describe :method_missing_instance, shared: true do
describe "for an instance" do
it "raises a NoMethodError when an undefined method is called" do
- -> { @object.new.no_such_method }.should raise_error(NoMethodError)
+ -> { @object.new.no_such_method }.should.raise(NoMethodError)
end
it "raises a NoMethodError when a protected method is called" do
- -> { @object.new.method_protected }.should raise_error(NoMethodError)
+ -> { @object.new.method_protected }.should.raise(NoMethodError)
end
it "raises a NoMethodError when a private method is called" do
- -> { @object.new.method_private }.should raise_error(NoMethodError)
+ -> { @object.new.method_private }.should.raise(NoMethodError)
end
it 'sets the receiver of the raised NoMethodError' do
diff --git a/spec/ruby/shared/basicobject/send.rb b/spec/ruby/shared/basicobject/send.rb
index 625aaa2917..d38aea975e 100644
--- a/spec/ruby/shared/basicobject/send.rb
+++ b/spec/ruby/shared/basicobject/send.rb
@@ -30,10 +30,10 @@ describe :basicobject_send, shared: true do
end
it "raises a TypeError if the method name is not a string or symbol" do
- -> { SendSpecs.send(@method, nil) }.should raise_error(TypeError, /not a symbol nor a string/)
- -> { SendSpecs.send(@method, 42) }.should raise_error(TypeError, /not a symbol nor a string/)
- -> { SendSpecs.send(@method, 3.14) }.should raise_error(TypeError, /not a symbol nor a string/)
- -> { SendSpecs.send(@method, true) }.should raise_error(TypeError, /not a symbol nor a string/)
+ -> { SendSpecs.send(@method, nil) }.should.raise(TypeError, /not a symbol nor a string/)
+ -> { SendSpecs.send(@method, 42) }.should.raise(TypeError, /not a symbol nor a string/)
+ -> { SendSpecs.send(@method, 3.14) }.should.raise(TypeError, /not a symbol nor a string/)
+ -> { SendSpecs.send(@method, true) }.should.raise(TypeError, /not a symbol nor a string/)
end
it "raises a NameError if the corresponding method can't be found" do
@@ -42,7 +42,7 @@ describe :basicobject_send, shared: true do
'done'
end
end
- -> { SendSpecs::Foo.new.send(@method, :syegsywhwua) }.should raise_error(NameError)
+ -> { SendSpecs::Foo.new.send(@method, :syegsywhwua) }.should.raise(NameError)
end
it "raises a NameError if the corresponding singleton method can't be found" do
@@ -51,12 +51,12 @@ describe :basicobject_send, shared: true do
'done'
end
end
- -> { SendSpecs::Foo.send(@method, :baz) }.should raise_error(NameError)
+ -> { SendSpecs::Foo.send(@method, :baz) }.should.raise(NameError)
end
it "raises an ArgumentError if no arguments are given" do
class SendSpecs::Foo; end
- -> { SendSpecs::Foo.new.send @method }.should raise_error(ArgumentError)
+ -> { SendSpecs::Foo.new.send @method }.should.raise(ArgumentError)
end
it "raises an ArgumentError if called with more arguments than available parameters" do
@@ -64,7 +64,7 @@ describe :basicobject_send, shared: true do
def bar; end
end
- -> { SendSpecs::Foo.new.send(@method, :bar, :arg) }.should raise_error(ArgumentError)
+ -> { SendSpecs::Foo.new.send(@method, :bar, :arg) }.should.raise(ArgumentError)
end
it "raises an ArgumentError if called with fewer arguments than required parameters" do
@@ -72,7 +72,7 @@ describe :basicobject_send, shared: true do
def foo(arg); end
end
- -> { SendSpecs::Foo.new.send(@method, :foo) }.should raise_error(ArgumentError)
+ -> { SendSpecs::Foo.new.send(@method, :foo) }.should.raise(ArgumentError)
end
it "succeeds if passed an arbitrary number of arguments as a splat parameter" do
diff --git a/spec/ruby/shared/enumerable/minmax.rb b/spec/ruby/shared/enumerable/minmax.rb
index 8af2626d2a..db95ef9c78 100644
--- a/spec/ruby/shared/enumerable/minmax.rb
+++ b/spec/ruby/shared/enumerable/minmax.rb
@@ -14,11 +14,11 @@ describe :enumerable_minmax, shared: true do
end
it "raises a NoMethodError for elements without #<=>" do
- -> { @incomparable_enum.minmax }.should raise_error(NoMethodError)
+ -> { @incomparable_enum.minmax }.should.raise(NoMethodError)
end
it "raises an ArgumentError when elements are incompatible" do
- -> { @incompatible_enum.minmax }.should raise_error(ArgumentError)
- -> { @enum.minmax{ |a, b| nil } }.should raise_error(ArgumentError)
+ -> { @incompatible_enum.minmax }.should.raise(ArgumentError)
+ -> { @enum.minmax{ |a, b| nil } }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/shared/file/directory.rb b/spec/ruby/shared/file/directory.rb
index 8ba933a601..84f8f1a958 100644
--- a/spec/ruby/shared/file/directory.rb
+++ b/spec/ruby/shared/file/directory.rb
@@ -12,24 +12,24 @@ describe :file_directory, shared: true do
end
it "returns true if the argument is a directory" do
- @object.send(@method, @dir).should be_true
+ @object.send(@method, @dir).should == true
end
it "returns false if the argument is not a directory" do
- @object.send(@method, @file).should be_false
+ @object.send(@method, @file).should == false
end
it "accepts an object that has a #to_path method" do
- @object.send(@method, mock_to_path(@dir)).should be_true
+ @object.send(@method, mock_to_path(@dir)).should == true
end
it "raises a TypeError when passed an Integer" do
- -> { @object.send(@method, 1) }.should raise_error(TypeError)
- -> { @object.send(@method, bignum_value) }.should raise_error(TypeError)
+ -> { @object.send(@method, 1) }.should.raise(TypeError)
+ -> { @object.send(@method, bignum_value) }.should.raise(TypeError)
end
it "raises a TypeError when passed nil" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
end
end
@@ -47,13 +47,13 @@ describe :file_directory_io, shared: true do
end
it "returns false if the argument is an IO that's not a directory" do
- @object.send(@method, STDIN).should be_false
+ @object.send(@method, STDIN).should == false
end
platform_is_not :windows do
it "returns true if the argument is an IO that is a directory" do
File.open(@dir, "r") do |f|
- @object.send(@method, f).should be_true
+ @object.send(@method, f).should == true
end
end
end
@@ -61,6 +61,6 @@ describe :file_directory_io, shared: true do
it "calls #to_io to convert a non-IO object" do
io = mock('FileDirectoryIO')
io.should_receive(:to_io).and_return(STDIN)
- @object.send(@method, io).should be_false
+ @object.send(@method, io).should == false
end
end
diff --git a/spec/ruby/shared/file/executable.rb b/spec/ruby/shared/file/executable.rb
index baa156de98..0fc65cf866 100644
--- a/spec/ruby/shared/file/executable.rb
+++ b/spec/ruby/shared/file/executable.rb
@@ -31,13 +31,13 @@ describe :file_executable, shared: true do
end
it "raises an ArgumentError if not passed one argument" do
- -> { @object.send(@method) }.should raise_error(ArgumentError)
+ -> { @object.send(@method) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { @object.send(@method, 1) }.should raise_error(TypeError)
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
- -> { @object.send(@method, false) }.should raise_error(TypeError)
+ -> { @object.send(@method, 1) }.should.raise(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
+ -> { @object.send(@method, false) }.should.raise(TypeError)
end
platform_is_not :windows do
diff --git a/spec/ruby/shared/file/executable_real.rb b/spec/ruby/shared/file/executable_real.rb
index bf2734ea07..90b7a41ba7 100644
--- a/spec/ruby/shared/file/executable_real.rb
+++ b/spec/ruby/shared/file/executable_real.rb
@@ -29,13 +29,13 @@ describe :file_executable_real, shared: true do
end
it "raises an ArgumentError if not passed one argument" do
- -> { @object.send(@method) }.should raise_error(ArgumentError)
+ -> { @object.send(@method) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { @object.send(@method, 1) }.should raise_error(TypeError)
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
- -> { @object.send(@method, false) }.should raise_error(TypeError)
+ -> { @object.send(@method, 1) }.should.raise(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
+ -> { @object.send(@method, false) }.should.raise(TypeError)
end
platform_is_not :windows do
diff --git a/spec/ruby/shared/file/exist.rb b/spec/ruby/shared/file/exist.rb
index 67424146c5..5075fa74b9 100644
--- a/spec/ruby/shared/file/exist.rb
+++ b/spec/ruby/shared/file/exist.rb
@@ -5,12 +5,12 @@ describe :file_exist, shared: true do
end
it "raises an ArgumentError if not passed one argument" do
- -> { @object.send(@method) }.should raise_error(ArgumentError)
- -> { @object.send(@method, __FILE__, __FILE__) }.should raise_error(ArgumentError)
+ -> { @object.send(@method) }.should.raise(ArgumentError)
+ -> { @object.send(@method, __FILE__, __FILE__) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
end
it "accepts an object that has a #to_path method" do
diff --git a/spec/ruby/shared/file/file.rb b/spec/ruby/shared/file/file.rb
index c1748a88b3..18477cff55 100644
--- a/spec/ruby/shared/file/file.rb
+++ b/spec/ruby/shared/file/file.rb
@@ -34,12 +34,12 @@ describe :file_file, shared: true do
end
it "raises an ArgumentError if not passed one argument" do
- -> { @object.send(@method) }.should raise_error(ArgumentError)
- -> { @object.send(@method, @null, @file) }.should raise_error(ArgumentError)
+ -> { @object.send(@method) }.should.raise(ArgumentError)
+ -> { @object.send(@method, @null, @file) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
- -> { @object.send(@method, 1) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
+ -> { @object.send(@method, 1) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/shared/file/grpowned.rb b/spec/ruby/shared/file/grpowned.rb
index 24e84c28e3..07a5a69e1a 100644
--- a/spec/ruby/shared/file/grpowned.rb
+++ b/spec/ruby/shared/file/grpowned.rb
@@ -11,11 +11,11 @@ describe :file_grpowned, shared: true do
platform_is_not :windows do
it "returns true if the file exist" do
- @object.send(@method, @file).should be_true
+ @object.send(@method, @file).should == true
end
it "accepts an object that has a #to_path method" do
- @object.send(@method, mock_to_path(@file)).should be_true
+ @object.send(@method, mock_to_path(@file)).should == true
end
it 'takes non primary groups into account' do
@@ -33,7 +33,7 @@ describe :file_grpowned, shared: true do
platform_is :windows do
it "returns false if the file exist" do
- @object.send(@method, @file).should be_false
+ @object.send(@method, @file).should == false
end
end
end
diff --git a/spec/ruby/shared/file/identical.rb b/spec/ruby/shared/file/identical.rb
index b7a2904839..628abd4f48 100644
--- a/spec/ruby/shared/file/identical.rb
+++ b/spec/ruby/shared/file/identical.rb
@@ -25,9 +25,9 @@ describe :file_identical, shared: true do
end
it "returns false if any of the files doesn't exist" do
- @object.send(@method, @file1, @non_exist).should be_false
- @object.send(@method, @non_exist, @file1).should be_false
- @object.send(@method, @non_exist, @non_exist).should be_false
+ @object.send(@method, @file1, @non_exist).should == false
+ @object.send(@method, @non_exist, @file1).should == false
+ @object.send(@method, @non_exist, @non_exist).should == false
end
it "accepts an object that has a #to_path method" do
@@ -35,17 +35,17 @@ describe :file_identical, shared: true do
end
it "raises an ArgumentError if not passed two arguments" do
- -> { @object.send(@method, @file1, @file2, @link) }.should raise_error(ArgumentError)
- -> { @object.send(@method, @file1) }.should raise_error(ArgumentError)
+ -> { @object.send(@method, @file1, @file2, @link) }.should.raise(ArgumentError)
+ -> { @object.send(@method, @file1) }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed String types" do
- -> { @object.send(@method, 1,1) }.should raise_error(TypeError)
+ -> { @object.send(@method, 1,1) }.should.raise(TypeError)
end
it "returns true if both named files are identical" do
- @object.send(@method, @file1, @file1).should be_true
- @object.send(@method, @link, @link).should be_true
- @object.send(@method, @file1, @file2).should be_false
+ @object.send(@method, @file1, @file1).should == true
+ @object.send(@method, @link, @link).should == true
+ @object.send(@method, @file1, @file2).should == false
end
end
diff --git a/spec/ruby/shared/file/size.rb b/spec/ruby/shared/file/size.rb
index cba99fe6a5..fa198ed232 100644
--- a/spec/ruby/shared/file/size.rb
+++ b/spec/ruby/shared/file/size.rb
@@ -56,7 +56,7 @@ describe :file_size_raise_when_missing, shared: true do
end
it "raises an error if file_name doesn't exist" do
- -> {@object.send(@method, @missing)}.should raise_error(Errno::ENOENT)
+ -> {@object.send(@method, @missing)}.should.raise(Errno::ENOENT)
end
end
diff --git a/spec/ruby/shared/file/socket.rb b/spec/ruby/shared/file/socket.rb
index 55a1cfd284..ef6c482d1c 100644
--- a/spec/ruby/shared/file/socket.rb
+++ b/spec/ruby/shared/file/socket.rb
@@ -1,3 +1,33 @@
describe :file_socket, shared: true do
- it "accepts an object that has a #to_path method"
+ it "returns false if the file is not a socket" do
+ filename = tmp("i_exist")
+ touch(filename)
+
+ @object.send(@method, filename).should == false
+
+ rm_r filename
+ end
+
+ it "returns true if the file is a socket" do
+ require 'socket'
+
+ # We need a really short name here.
+ # On Linux the path length is limited to 107, see unix(7).
+ name = tmp("s")
+ server = UNIXServer.new(name)
+
+ @object.send(@method, name).should == true
+
+ server.close
+ rm_r name
+ end
+
+ it "accepts an object that has a #to_path method" do
+ obj = Object.new
+ def obj.to_path
+ __FILE__
+ end
+
+ @object.send(@method, obj).should == false
+ end
end
diff --git a/spec/ruby/shared/file/sticky.rb b/spec/ruby/shared/file/sticky.rb
index 38bb6ed26b..e07fa22fd7 100644
--- a/spec/ruby/shared/file/sticky.rb
+++ b/spec/ruby/shared/file/sticky.rb
@@ -8,7 +8,7 @@ describe :file_sticky, shared: true do
Dir.rmdir(@dir) if File.exist?(@dir)
end
- platform_is_not :windows, :darwin, :freebsd, :netbsd, :openbsd, :solaris, :aix do
+ platform_is_not :windows, :darwin, :freebsd, :netbsd, :openbsd, :aix do
it "returns true if the named file has the sticky bit, otherwise false" do
Dir.mkdir @dir, 01755
diff --git a/spec/ruby/shared/file/world_readable.rb b/spec/ruby/shared/file/world_readable.rb
index 1dce7a580f..c8946366ad 100644
--- a/spec/ruby/shared/file/world_readable.rb
+++ b/spec/ruby/shared/file/world_readable.rb
@@ -14,24 +14,24 @@ describe :file_world_readable, shared: true do
platform_is_not :windows do
it "returns nil if the file is chmod 600" do
File.chmod(0600, @file)
- @object.world_readable?(@file).should be_nil
+ @object.world_readable?(@file).should == nil
end
it "returns nil if the file is chmod 000" do
File.chmod(0000, @file)
- @object.world_readable?(@file).should be_nil
+ @object.world_readable?(@file).should == nil
end
it "returns nil if the file is chmod 700" do
File.chmod(0700, @file)
- @object.world_readable?(@file).should be_nil
+ @object.world_readable?(@file).should == nil
end
end
# We don't specify what the Integer is because it's system dependent
it "returns an Integer if the file is chmod 644" do
File.chmod(0644, @file)
- @object.world_readable?(@file).should be_an_instance_of(Integer)
+ @object.world_readable?(@file).should.instance_of?(Integer)
end
it "returns an Integer if the file is a directory and chmod 644" do
@@ -39,7 +39,7 @@ describe :file_world_readable, shared: true do
Dir.mkdir(dir)
Dir.should.exist?(dir)
File.chmod(0644, dir)
- @object.world_readable?(dir).should be_an_instance_of(Integer)
+ @object.world_readable?(dir).should.instance_of?(Integer)
Dir.rmdir(dir)
end
diff --git a/spec/ruby/shared/file/world_writable.rb b/spec/ruby/shared/file/world_writable.rb
index 7ed252dcf3..fcff09636e 100644
--- a/spec/ruby/shared/file/world_writable.rb
+++ b/spec/ruby/shared/file/world_writable.rb
@@ -14,23 +14,23 @@ describe :file_world_writable, shared: true do
platform_is_not :windows do
it "returns nil if the file is chmod 600" do
File.chmod(0600, @file)
- @object.world_writable?(@file).should be_nil
+ @object.world_writable?(@file).should == nil
end
it "returns nil if the file is chmod 000" do
File.chmod(0000, @file)
- @object.world_writable?(@file).should be_nil
+ @object.world_writable?(@file).should == nil
end
it "returns nil if the file is chmod 700" do
File.chmod(0700, @file)
- @object.world_writable?(@file).should be_nil
+ @object.world_writable?(@file).should == nil
end
# We don't specify what the Integer is because it's system dependent
it "returns an Integer if the file is chmod 777" do
File.chmod(0777, @file)
- @object.world_writable?(@file).should be_an_instance_of(Integer)
+ @object.world_writable?(@file).should.instance_of?(Integer)
end
it "returns an Integer if the file is a directory and chmod 777" do
@@ -38,7 +38,7 @@ describe :file_world_writable, shared: true do
Dir.mkdir(dir)
Dir.should.exist?(dir)
File.chmod(0777, dir)
- @object.world_writable?(dir).should be_an_instance_of(Integer)
+ @object.world_writable?(dir).should.instance_of?(Integer)
Dir.rmdir(dir)
end
end
diff --git a/spec/ruby/shared/file/writable_real.rb b/spec/ruby/shared/file/writable_real.rb
index b4a0a58c6e..4602996187 100644
--- a/spec/ruby/shared/file/writable_real.rb
+++ b/spec/ruby/shared/file/writable_real.rb
@@ -16,13 +16,13 @@ describe :file_writable_real, shared: true do
end
it "raises an ArgumentError if not passed one argument" do
- -> { File.writable_real? }.should raise_error(ArgumentError)
+ -> { File.writable_real? }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { @object.send(@method, 1) }.should raise_error(TypeError)
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
- -> { @object.send(@method, false) }.should raise_error(TypeError)
+ -> { @object.send(@method, 1) }.should.raise(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
+ -> { @object.send(@method, false) }.should.raise(TypeError)
end
platform_is_not :windows do
diff --git a/spec/ruby/shared/file/zero.rb b/spec/ruby/shared/file/zero.rb
index 6a9399a021..94285c14c5 100644
--- a/spec/ruby/shared/file/zero.rb
+++ b/spec/ruby/shared/file/zero.rb
@@ -40,13 +40,13 @@ describe :file_zero, shared: true do
end
it "raises an ArgumentError if not passed one argument" do
- -> { File.zero? }.should raise_error(ArgumentError)
+ -> { File.zero? }.should.raise(ArgumentError)
end
it "raises a TypeError if not passed a String type" do
- -> { @object.send(@method, nil) }.should raise_error(TypeError)
- -> { @object.send(@method, true) }.should raise_error(TypeError)
- -> { @object.send(@method, false) }.should raise_error(TypeError)
+ -> { @object.send(@method, nil) }.should.raise(TypeError)
+ -> { @object.send(@method, true) }.should.raise(TypeError)
+ -> { @object.send(@method, false) }.should.raise(TypeError)
end
it "returns true inside a block opening a file if it is empty" do
@@ -57,7 +57,7 @@ describe :file_zero, shared: true do
# See https://bugs.ruby-lang.org/issues/449 for background
it "returns true or false for a directory" do
- @object.send(@method, @dir).should be_true_or_false
+ [true, false].should.include? @object.send(@method, @dir)
end
end
diff --git a/spec/ruby/shared/hash/key_error.rb b/spec/ruby/shared/hash/key_error.rb
index 54dcb89e91..0044cd5de2 100644
--- a/spec/ruby/shared/hash/key_error.rb
+++ b/spec/ruby/shared/hash/key_error.rb
@@ -2,21 +2,21 @@ describe :key_error, shared: true do
it "raises a KeyError" do
-> {
@method.call(@object, 'foo')
- }.should raise_error(KeyError)
+ }.should.raise(KeyError)
end
it "sets the Hash as the receiver of KeyError" do
-> {
@method.call(@object, 'foo')
- }.should raise_error(KeyError) { |err|
- err.receiver.should equal(@object)
+ }.should.raise(KeyError) { |err|
+ err.receiver.should.equal?(@object)
}
end
it "sets the unmatched key as the key of KeyError" do
-> {
@method.call(@object, 'foo')
- }.should raise_error(KeyError) { |err|
+ }.should.raise(KeyError) { |err|
err.key.to_s.should == 'foo'
}
end
diff --git a/spec/ruby/shared/io/putc.rb b/spec/ruby/shared/io/putc.rb
index e6012c0098..56902ccad5 100644
--- a/spec/ruby/shared/io/putc.rb
+++ b/spec/ruby/shared/io/putc.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :io_putc, shared: true do
after :each do
@io.close if @io && !@io.closed?
@@ -40,18 +40,18 @@ describe :io_putc, shared: true do
it "raises IOError on a closed stream" do
@io.close
- -> { @io_object.send(@method, "a") }.should raise_error(IOError)
+ -> { @io_object.send(@method, "a") }.should.raise(IOError)
end
it "raises a TypeError when passed nil" do
- -> { @io_object.send(@method, nil) }.should raise_error(TypeError)
+ -> { @io_object.send(@method, nil) }.should.raise(TypeError)
end
it "raises a TypeError when passed false" do
- -> { @io_object.send(@method, false) }.should raise_error(TypeError)
+ -> { @io_object.send(@method, false) }.should.raise(TypeError)
end
it "raises a TypeError when passed true" do
- -> { @io_object.send(@method, true) }.should raise_error(TypeError)
+ -> { @io_object.send(@method, true) }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb
index 29db79bb39..a868ed1e0e 100644
--- a/spec/ruby/shared/kernel/at_exit.rb
+++ b/spec/ruby/shared/kernel/at_exit.rb
@@ -60,10 +60,7 @@ describe :kernel_at_exit, shared: true do
result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
$?.should_not.success?
result.should.include?("handler ran\n")
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- result.should include_any_of("syntax error", "SyntaxError")
+ result.should.include?("SyntaxError")
end
it "calls the nested handler right after the outer one if a handler is nested into another handler" do
diff --git a/spec/ruby/shared/kernel/complex.rb b/spec/ruby/shared/kernel/complex.rb
index 98ee0b2b3f..6e0764dd3d 100644
--- a/spec/ruby/shared/kernel/complex.rb
+++ b/spec/ruby/shared/kernel/complex.rb
@@ -2,7 +2,7 @@
describe :kernel_complex, shared: true do
it "returns a Complex object" do
- @object.send(@method, '9').should be_an_instance_of(Complex)
+ @object.send(@method, '9').should.instance_of?(Complex)
end
it "understands integers" do
diff --git a/spec/ruby/shared/kernel/equal.rb b/spec/ruby/shared/kernel/equal.rb
index 0a70aec639..3b74232922 100644
--- a/spec/ruby/shared/kernel/equal.rb
+++ b/spec/ruby/shared/kernel/equal.rb
@@ -2,13 +2,13 @@
describe :object_equal, shared: true do
it "returns true if other is identical to self" do
obj = Object.new
- obj.__send__(@method, obj).should be_true
+ obj.__send__(@method, obj).should == true
end
it "returns false if other is not identical to self" do
a = Object.new
b = Object.new
- a.__send__(@method, b).should be_false
+ a.__send__(@method, b).should == false
end
it "returns true only if self and other are the same object" do
diff --git a/spec/ruby/shared/kernel/object_id.rb b/spec/ruby/shared/kernel/object_id.rb
index 099df8ff94..6469e49903 100644
--- a/spec/ruby/shared/kernel/object_id.rb
+++ b/spec/ruby/shared/kernel/object_id.rb
@@ -2,7 +2,7 @@
describe :object_id, shared: true do
it "returns an integer" do
o1 = @object.new
- o1.__send__(@method).should be_kind_of(Integer)
+ o1.__send__(@method).should.is_a?(Integer)
end
it "returns the same value on all calls to id for a given object" do
diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb
index 1917a4c923..8459166906 100644
--- a/spec/ruby/shared/kernel/raise.rb
+++ b/spec/ruby/shared/kernel/raise.rb
@@ -7,9 +7,9 @@ describe :kernel_raise, shared: true do
-> do
@object.raise Exception, "abort"
ScratchPad.record :no_abort
- end.should raise_error(Exception, "abort")
+ end.should.raise(Exception, "abort")
- ScratchPad.recorded.should be_nil
+ ScratchPad.recorded.should == nil
end
it "accepts an exception that implements to_hash" do
@@ -19,7 +19,7 @@ describe :kernel_raise, shared: true do
end
end
error = custom_error.new
- -> { @object.raise(error) }.should raise_error(custom_error)
+ -> { @object.raise(error) }.should.raise(custom_error)
end
it "allows the message parameter to be a hash" do
@@ -30,7 +30,7 @@ describe :kernel_raise, shared: true do
end
end
- -> { @object.raise(data_error, {data: 42}) }.should raise_error(data_error) do |ex|
+ -> { @object.raise(data_error, {data: 42}) }.should.raise(data_error) do |ex|
ex.data.should == {data: 42}
end
end
@@ -44,37 +44,22 @@ describe :kernel_raise, shared: true do
end
end
- -> { @object.raise(data_error, data: 42) }.should raise_error(data_error) do |ex|
+ -> { @object.raise(data_error, data: 42) }.should.raise(data_error) do |ex|
ex.data.should == {data: 42}
end
end
- it "does not allow message and extra keyword arguments" do
- data_error = Class.new(StandardError) do
- attr_reader :data
- def initialize(data)
- @data = data
- end
- end
-
- -> { @object.raise(data_error, {a: 1}, b: 2) }.should raise_error(StandardError) do |e|
- [TypeError, ArgumentError].should.include?(e.class)
- end
-
- -> { @object.raise(data_error, {a: 1}, [], b: 2) }.should raise_error(ArgumentError)
- end
-
it "raises RuntimeError if no exception class is given" do
- -> { @object.raise }.should raise_error(RuntimeError, "")
+ -> { @object.raise }.should.raise(RuntimeError, "")
end
it "raises a given Exception instance" do
error = RuntimeError.new
- -> { @object.raise(error) }.should raise_error(error)
+ -> { @object.raise(error) }.should.raise(error)
end
it "raises a RuntimeError if string given" do
- -> { @object.raise("a bad thing") }.should raise_error(RuntimeError)
+ -> { @object.raise("a bad thing") }.should.raise(RuntimeError, "a bad thing")
end
it "passes no arguments to the constructor when given only an exception class" do
@@ -82,69 +67,67 @@ describe :kernel_raise, shared: true do
def initialize
end
end
- -> { @object.raise(klass) }.should raise_error(klass) { |e| e.message.should == klass.to_s }
+ -> { @object.raise(klass) }.should.raise(klass) { |e| e.message.should == klass.to_s }
end
it "raises a TypeError when passed a non-Exception object" do
- -> { @object.raise(Object.new) }.should raise_error(TypeError)
+ -> { @object.raise(Object.new) }.should.raise(TypeError, "exception class/object expected")
+ -> { @object.raise(Object.new, "message") }.should.raise(TypeError, "exception class/object expected")
+ -> { @object.raise(Object.new, "message", []) }.should.raise(TypeError, "exception class/object expected")
end
it "raises a TypeError when passed true" do
- -> { @object.raise(true) }.should raise_error(TypeError)
+ -> { @object.raise(true) }.should.raise(TypeError, "exception class/object expected")
end
it "raises a TypeError when passed false" do
- -> { @object.raise(false) }.should raise_error(TypeError)
+ -> { @object.raise(false) }.should.raise(TypeError, "exception class/object expected")
end
it "raises a TypeError when passed nil" do
- -> { @object.raise(nil) }.should raise_error(TypeError)
+ -> { @object.raise(nil) }.should.raise(TypeError, "exception class/object expected")
+ end
+
+ it "raises a TypeError when passed a message and an extra argument" do
+ -> { @object.raise("message", {cause: RuntimeError.new()}) }.should.raise(TypeError, "exception class/object expected")
+ end
+
+ it "raises TypeError when passed a non-Exception object but it responds to #exception method that doesn't return an instance of Exception class" do
+ e = Object.new
+ def e.exception
+ Array
+ end
+
+ -> {
+ @object.raise e
+ }.should.raise(TypeError, "exception object expected")
end
it "re-raises a previously rescued exception without overwriting the backtrace" do
- # This spec is written using #backtrace and matching the line number
- # from the string, as backtrace_locations is a more advanced
- # method that is not always supported by implementations.
- #
- initial_raise_line = nil
- raise_again_line = nil
- raised_again = nil
-
- if defined?(FiberSpecs::NewFiberToRaise) and @object == FiberSpecs::NewFiberToRaise
- fiber = Fiber.new do
- begin
- initial_raise_line = __LINE__; Fiber.yield
- rescue => raised
- begin
- raise_again_line = __LINE__; Fiber.yield raised
- rescue => raised_again
- raised_again
- end
- end
- end
- fiber.resume
- raised = fiber.raise 'raised'
- raised_again = fiber.raise raised
- else
- begin
- initial_raise_line = __LINE__; @object.raise 'raised'
- rescue => raised
- begin
- raise_again_line = __LINE__; @object.raise raised
- rescue => raised_again
- raised_again
- end
- end
+ exception = nil
+
+ begin
+ raise "raised"
+ rescue => exception
+ # Ignore.
end
- raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:")
- raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
+ backtrace = exception.backtrace
+
+ begin
+ raised_exception = @object.raise(exception)
+ rescue => raised_exception
+ # Ignore.
+ end
+
+ raised_exception.backtrace.should == backtrace
+ raised_exception.should == exception
end
it "allows Exception, message, and backtrace parameters" do
-> do
@object.raise(ArgumentError, "message", caller)
- end.should raise_error(ArgumentError, "message")
+ end.should.raise(ArgumentError, "message")
end
ruby_version_is "3.4" do
@@ -152,9 +135,258 @@ describe :kernel_raise, shared: true do
it "allows Exception, message, and backtrace_locations parameters" do
-> do
@object.raise(ArgumentError, "message", locations)
- end.should raise_error(ArgumentError, "message") { |error|
+ end.should.raise(ArgumentError, "message") { |error|
error.backtrace_locations.map(&:to_s).should == locations.map(&:to_s)
}
end
end
end
+
+describe :kernel_raise_with_cause, shared: true do
+ context "without cause keyword argument" do
+ it "sets cause to nil when there is no previous exception" do
+ -> do
+ @object.raise("error without a cause")
+ end.should.raise(RuntimeError, "error without a cause", cause: nil)
+ end
+
+ it "supports automatic cause chaining from a previous exception" do
+ begin
+ raise StandardError, "first error"
+ rescue => cause
+ -> { @object.raise("second error") }.should.raise(RuntimeError, "second error", cause:)
+ end
+ end
+ end
+
+ context "with cause keyword argument" do
+ it "allows setting exception's cause" do
+ cause = StandardError.new("original error")
+
+ -> do
+ @object.raise("new error", cause:)
+ end.should.raise(RuntimeError, "new error", cause:)
+ end
+
+ it "allows setting cause to nil" do
+ -> do
+ @object.raise("error without a cause", cause: nil)
+ end.should.raise(RuntimeError, "error without a cause") do |error|
+ error.cause.should == nil
+ end
+ end
+
+ it "raises an ArgumentError when only cause is given" do
+ cause = StandardError.new("cause")
+ -> do
+ @object.raise(cause:)
+ end.should.raise(ArgumentError, "only cause is given with no arguments")
+ end
+
+ it "raises an ArgumentError when only cause is given and is nil" do
+ -> do
+ @object.raise(cause: nil)
+ end.should.raise(ArgumentError, "only cause is given with no arguments")
+ end
+
+ it "raises a TypeError when given cause is not an instance of Exception or nil" do
+ cause = Object.new
+ -> do
+ @object.raise("message", cause:)
+ end.should.raise(TypeError, "exception object expected")
+ end
+
+ it "doesn't set given cause when it equals the raised exception" do
+ cause = StandardError.new("cause")
+
+ -> do
+ @object.raise(cause, cause:)
+ end.should.raise(StandardError, "cause", cause: nil)
+ end
+
+ it "raises ArgumentError when cause creates a circular reference" do
+ -> {
+ begin
+ raise "Error 1"
+ rescue => error1
+ begin
+ raise "Error 2"
+ rescue => error2
+ begin
+ raise "Error 3"
+ rescue => error3
+ @object.raise(error1, cause: error3)
+ end
+ end
+ end
+ }.should.raise(ArgumentError, "circular causes")
+ end
+
+ it "supports exception class with message and cause" do
+ cause = StandardError.new("cause message")
+
+ -> do
+ @object.raise(ArgumentError, "argument error message", cause:)
+ end.should.raise(ArgumentError, "argument error message", cause:)
+ end
+
+ it "supports exception class with message, backtrace and cause" do
+ cause = StandardError.new("cause message")
+ backtrace = ["line1", "line2"]
+
+ -> do
+ @object.raise(ArgumentError, "argument error message", backtrace, cause:)
+ end.should.raise(ArgumentError, "argument error message", cause:) do |error|
+ error.backtrace.should == backtrace
+ end
+ end
+
+ it "supports cause: exception, overriding previous exception" do
+ custom_error = StandardError.new("custom error")
+ -> do
+ begin
+ raise "first error"
+ rescue
+ @object.raise("second error", cause: custom_error)
+ end
+ end.should.raise(RuntimeError, "second error", cause: custom_error)
+ end
+
+ it "supports cause: nil, discarding previous exception" do
+ -> do
+ begin
+ raise "first error"
+ rescue
+ # Explicit nil prevents chaining:
+ @object.raise("second error", cause: nil)
+ end
+ end.should.raise(RuntimeError, "second error", cause: nil)
+ end
+ end
+end
+
+describe :kernel_raise_across_contexts, shared: true do
+ ruby_version_is "4.0" do
+ describe "with cause keyword argument" do
+ it "uses the cause from the calling context" do
+ original_cause = nil
+ result = nil
+
+ # We have no cause ($!) and we don't specify one explicitly either:
+ @object.raise("second error") do |&block|
+ begin
+ begin
+ raise "first error"
+ rescue => original_cause
+ # We have a cause here ($!) but we should ignore it:
+ block.call
+ end
+ rescue => result
+ # Ignore.
+ end
+ end
+
+ result.should.is_a?(RuntimeError)
+ result.message.should == "second error"
+ result.cause.should == nil
+ end
+
+ it "accepts a cause keyword argument that overrides the last exception" do
+ original_cause = nil
+ override_cause = StandardError.new("override cause")
+ result = nil
+
+ begin
+ raise "outer error"
+ rescue
+ # We have an existing cause, but we want to override it:
+ @object.raise("second error", cause: override_cause) do |&block|
+ begin
+ begin
+ raise "first error"
+ rescue => original_cause
+ # We also have an existing cause here:
+ block.call
+ end
+ rescue => result
+ # Ignore.
+ end
+ end
+ end
+
+ result.should.is_a?(RuntimeError)
+ result.message.should == "second error"
+ result.cause.should == override_cause
+ end
+
+ it "supports automatic cause chaining from calling context" do
+ result = nil
+
+ @object.raise("new error") do |&block|
+ begin
+ begin
+ raise "original error"
+ rescue
+ block.call # Let the context yield/sleep
+ end
+ rescue => result
+ # Ignore.
+ end
+ end
+
+ result.should.is_a?(RuntimeError)
+ result.message.should == "new error"
+ # Calling context has no current exception:
+ result.cause.should == nil
+ end
+
+ it "supports explicit cause: nil to prevent cause chaining" do
+ result = nil
+
+ begin
+ raise "calling context error"
+ rescue
+ @object.raise("new error", cause: nil) do |&block|
+ begin
+ begin
+ raise "target context error"
+ rescue
+ block.call # Let the context yield/sleep
+ end
+ rescue => result
+ # Ignore.
+ end
+ end
+
+ result.should.is_a?(RuntimeError)
+ result.message.should == "new error"
+ result.cause.should == nil
+ end
+ end
+
+ it "raises TypeError when cause is not an Exception" do
+ -> {
+ @object.raise("error", cause: "not an exception") do |&block|
+ begin
+ block.call # Let the context yield/sleep
+ rescue
+ # Ignore - we expect the TypeError to be raised in the calling context
+ end
+ end
+ }.should.raise(TypeError, "exception object expected")
+ end
+
+ it "raises ArgumentError when only cause is given with no arguments" do
+ -> {
+ @object.raise(cause: StandardError.new("cause")) do |&block|
+ begin
+ block.call # Let the context yield/sleep
+ rescue
+ # Ignore - we expect the ArgumentError to be raised in the calling context
+ end
+ end
+ }.should.raise(ArgumentError, "only cause is given with no arguments")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/shared/process/abort.rb b/spec/ruby/shared/process/abort.rb
index 935637e1c2..19f9f1e6a5 100644
--- a/spec/ruby/shared/process/abort.rb
+++ b/spec/ruby/shared/process/abort.rb
@@ -8,29 +8,29 @@ describe :process_abort, shared: true do
end
it "raises a SystemExit exception" do
- -> { @object.abort }.should raise_error(SystemExit)
+ -> { @object.abort }.should.raise(SystemExit)
end
it "sets the exception message to the given message" do
- -> { @object.abort "message" }.should raise_error { |e| e.message.should == "message" }
+ -> { @object.abort "message" }.should.raise { |e| e.message.should == "message" }
end
it "sets the exception status code of 1" do
- -> { @object.abort }.should raise_error { |e| e.status.should == 1 }
+ -> { @object.abort }.should.raise { |e| e.status.should == 1 }
end
it "prints the specified message to STDERR" do
- -> { @object.abort "a message" }.should raise_error(SystemExit)
+ -> { @object.abort "a message" }.should.raise(SystemExit)
$stderr.should =~ /a message/
end
it "coerces the argument with #to_str" do
str = mock('to_str')
str.should_receive(:to_str).any_number_of_times.and_return("message")
- -> { @object.abort str }.should raise_error(SystemExit, "message")
+ -> { @object.abort str }.should.raise(SystemExit, "message")
end
it "raises TypeError when given a non-String object" do
- -> { @object.abort 123 }.should raise_error(TypeError)
+ -> { @object.abort 123 }.should.raise(TypeError)
end
end
diff --git a/spec/ruby/shared/process/exit.rb b/spec/ruby/shared/process/exit.rb
index 1e073614a3..cacf2f8774 100644
--- a/spec/ruby/shared/process/exit.rb
+++ b/spec/ruby/shared/process/exit.rb
@@ -1,13 +1,13 @@
describe :process_exit, shared: true do
it "raises a SystemExit with status 0" do
- -> { @object.exit }.should raise_error(SystemExit) { |e|
+ -> { @object.exit }.should.raise(SystemExit) { |e|
e.status.should == 0
}
end
it "raises a SystemExit with the specified status" do
[-2**16, -2**8, -8, -1, 0, 1 , 8, 2**8, 2**16].each do |value|
- -> { @object.exit(value) }.should raise_error(SystemExit) { |e|
+ -> { @object.exit(value) }.should.raise(SystemExit) { |e|
e.status.should == value
}
end
@@ -15,14 +15,14 @@ describe :process_exit, shared: true do
it "raises a SystemExit with the specified boolean status" do
{ true => 0, false => 1 }.each do |value, status|
- -> { @object.exit(value) }.should raise_error(SystemExit) { |e|
+ -> { @object.exit(value) }.should.raise(SystemExit) { |e|
e.status.should == status
}
end
end
it "raises a SystemExit with message 'exit'" do
- -> { @object.exit }.should raise_error(SystemExit) { |e|
+ -> { @object.exit }.should.raise(SystemExit) { |e|
e.message.should == "exit"
}
end
@@ -30,24 +30,24 @@ describe :process_exit, shared: true do
it "tries to convert the passed argument to an Integer using #to_int" do
obj = mock('5')
obj.should_receive(:to_int).and_return(5)
- -> { @object.exit(obj) }.should raise_error(SystemExit) { |e|
+ -> { @object.exit(obj) }.should.raise(SystemExit) { |e|
e.status.should == 5
}
end
it "converts the passed Float argument to an Integer" do
{ -2.2 => -2, -0.1 => 0, 5.5 => 5, 827.999 => 827 }.each do |value, status|
- -> { @object.exit(value) }.should raise_error(SystemExit) { |e|
+ -> { @object.exit(value) }.should.raise(SystemExit) { |e|
e.status.should == status
}
end
end
it "raises TypeError if can't convert the argument to an Integer" do
- -> { @object.exit(Object.new) }.should raise_error(TypeError)
- -> { @object.exit('0') }.should raise_error(TypeError)
- -> { @object.exit([0]) }.should raise_error(TypeError)
- -> { @object.exit(nil) }.should raise_error(TypeError)
+ -> { @object.exit(Object.new) }.should.raise(TypeError)
+ -> { @object.exit('0') }.should.raise(TypeError)
+ -> { @object.exit([0]) }.should.raise(TypeError)
+ -> { @object.exit(nil) }.should.raise(TypeError)
end
it "raises the SystemExit in the main thread if it reaches the top-level handler of another thread" do
@@ -75,7 +75,7 @@ describe :process_exit, shared: true do
ScratchPad.recorded.should == [:in_thread, :in_main]
# the thread also keeps the exception as its value
- -> { t.value }.should raise_error(SystemExit)
+ -> { t.value }.should.raise(SystemExit)
end
end
diff --git a/spec/ruby/shared/process/fork.rb b/spec/ruby/shared/process/fork.rb
index 8dbb3d0da4..dd595cd93e 100644
--- a/spec/ruby/shared/process/fork.rb
+++ b/spec/ruby/shared/process/fork.rb
@@ -3,12 +3,12 @@ describe :process_fork, shared: true do
it "returns false from #respond_to?" do
# Workaround for Kernel::Method being public and losing the "non-respond_to? magic"
mod = @object.class.name == "KernelSpecs::Method" ? Object.new : @object
- mod.respond_to?(:fork).should be_false
- mod.respond_to?(:fork, true).should be_false
+ mod.respond_to?(:fork).should == false
+ mod.respond_to?(:fork, true).should == false
end
it "raises a NotImplementedError when called" do
- -> { @object.fork }.should raise_error(NotImplementedError)
+ -> { @object.fork }.should.raise(NotImplementedError)
end
end
@@ -74,16 +74,19 @@ describe :process_fork, shared: true do
it "marks threads from the parent as killed" do
t = Thread.new { sleep }
- pid = @object.fork {
- touch(@file) do |f|
- f.write Thread.current.alive?
- f.write t.alive?
- end
- Process.exit!
- }
- Process.waitpid(pid)
- t.kill
- t.join
+ begin
+ pid = @object.fork {
+ touch(@file) do |f|
+ f.write Thread.current.alive?
+ f.write t.alive?
+ end
+ Process.exit!
+ }
+ Process.waitpid(pid)
+ ensure
+ t.kill
+ t.join
+ end
File.read(@file).should == "truefalse"
end
end
diff --git a/spec/ruby/shared/queue/clear.rb b/spec/ruby/shared/queue/clear.rb
index 5db5a5b497..742468a859 100644
--- a/spec/ruby/shared/queue/clear.rb
+++ b/spec/ruby/shared/queue/clear.rb
@@ -3,9 +3,9 @@ describe :queue_clear, shared: true do
queue = @object.call
queue << Object.new
queue << 1
- queue.empty?.should be_false
+ queue.empty?.should == false
queue.clear
- queue.empty?.should be_true
+ queue.empty?.should == true
end
# TODO: test for atomicity of Queue#clear
diff --git a/spec/ruby/shared/queue/close.rb b/spec/ruby/shared/queue/close.rb
index 0e7c69acba..1b0908c27c 100644
--- a/spec/ruby/shared/queue/close.rb
+++ b/spec/ruby/shared/queue/close.rb
@@ -2,9 +2,9 @@ describe :queue_close, shared: true do
it "may be called multiple times" do
q = @object.call
q.close
- q.closed?.should be_true
+ q.closed?.should == true
q.close # no effect
- q.closed?.should be_true
+ q.closed?.should == true
end
it "returns self" do
diff --git a/spec/ruby/shared/queue/closed.rb b/spec/ruby/shared/queue/closed.rb
index b3cea0c524..8a7d65055f 100644
--- a/spec/ruby/shared/queue/closed.rb
+++ b/spec/ruby/shared/queue/closed.rb
@@ -1,12 +1,12 @@
describe :queue_closed?, shared: true do
it "returns false initially" do
queue = @object.call
- queue.closed?.should be_false
+ queue.closed?.should == false
end
it "returns true when the queue is closed" do
queue = @object.call
queue.close
- queue.closed?.should be_true
+ queue.closed?.should == true
end
end
diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb
index 0abba5301e..45cbc4a995 100644
--- a/spec/ruby/shared/queue/deque.rb
+++ b/spec/ruby/shared/queue/deque.rb
@@ -65,66 +65,64 @@ describe :queue_deq, shared: true do
end
describe "with a timeout" do
- ruby_version_is "3.2" do
- it "returns an item if one is available in time" do
- q = @object.call
-
- t = Thread.new {
- q.send(@method, timeout: TIME_TOLERANCE).should == 1
- }
- Thread.pass until t.status == "sleep" && q.num_waiting == 1
- q << 1
- t.join
- end
-
- it "returns nil if no item is available in time" do
- q = @object.call
-
- Thread.new {
- q.send(@method, timeout: 0.001).should == nil
- }.join
- end
-
- it "does nothing if the timeout is nil" do
- q = @object.call
- t = Thread.new {
- q.send(@method, timeout: nil).should == 1
- }
- Thread.pass until t.status == "sleep" && q.num_waiting == 1
- q << 1
- t.join
- end
-
- it "immediately returns nil if no item is available and the timeout is 0" do
- q = @object.call
- q << 1
- q.send(@method, timeout: 0).should == 1
- q.send(@method, timeout: 0).should == nil
- end
-
- it "raise TypeError if timeout is not a valid numeric" do
- q = @object.call
- -> {
- q.send(@method, timeout: "1")
- }.should raise_error(TypeError, "no implicit conversion to float from string")
-
- -> {
- q.send(@method, timeout: false)
- }.should raise_error(TypeError, "no implicit conversion to float from false")
- end
-
- it "raise ArgumentError if non_block = true is passed too" do
- q = @object.call
- -> {
- q.send(@method, true, timeout: 1)
- }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled")
- end
-
- it "returns nil for a closed empty queue" do
- q = @object.call
- q.close
- q.send(@method, timeout: 0).should == nil
- end
+ it "returns an item if one is available in time" do
+ q = @object.call
+
+ t = Thread.new {
+ q.send(@method, timeout: TIME_TOLERANCE).should == 1
+ }
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
+ q << 1
+ t.join
+ end
+
+ it "returns nil if no item is available in time" do
+ q = @object.call
+
+ Thread.new {
+ q.send(@method, timeout: 0.001).should == nil
+ }.join
+ end
+
+ it "does nothing if the timeout is nil" do
+ q = @object.call
+ t = Thread.new {
+ q.send(@method, timeout: nil).should == 1
+ }
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
+ q << 1
+ t.join
+ end
+
+ it "immediately returns nil if no item is available and the timeout is 0" do
+ q = @object.call
+ q << 1
+ q.send(@method, timeout: 0).should == 1
+ q.send(@method, timeout: 0).should == nil
+ end
+
+ it "raise TypeError if timeout is not a valid numeric" do
+ q = @object.call
+ -> {
+ q.send(@method, timeout: "1")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of String into Float")
+
+ -> {
+ q.send(@method, timeout: false)
+ }.should raise_consistent_error(TypeError, "no implicit conversion of false into Float")
+ end
+
+ it "raise ArgumentError if non_block = true is passed too" do
+ q = @object.call
+ -> {
+ q.send(@method, true, timeout: 1)
+ }.should.raise(ArgumentError, "can't set a timeout if non_block is enabled")
+ end
+
+ it "returns nil for a closed empty queue" do
+ q = @object.call
+ q.close
+ q.send(@method, timeout: 0).should == nil
end
end
@@ -139,7 +137,7 @@ describe :queue_deq, shared: true do
it "raises a ThreadError if the queue is empty" do
q = @object.call
- -> { q.send(@method, true) }.should raise_error(ThreadError)
+ -> { q.send(@method, true) }.should.raise(ThreadError)
end
it "removes an item from a closed queue" do
@@ -152,15 +150,15 @@ describe :queue_deq, shared: true do
it "raises a ThreadError for a closed empty queue" do
q = @object.call
q.close
- -> { q.send(@method, true) }.should raise_error(ThreadError)
+ -> { q.send(@method, true) }.should.raise(ThreadError)
end
it "converts true-ish non_blocking argument to true" do
q = @object.call
- -> { q.send(@method, true) }.should raise_error(ThreadError)
- -> { q.send(@method, 1) }.should raise_error(ThreadError)
- -> { q.send(@method, "") }.should raise_error(ThreadError)
+ -> { q.send(@method, true) }.should.raise(ThreadError)
+ -> { q.send(@method, 1) }.should.raise(ThreadError)
+ -> { q.send(@method, "") }.should.raise(ThreadError)
end
end
end
diff --git a/spec/ruby/shared/queue/empty.rb b/spec/ruby/shared/queue/empty.rb
index 4acd831d48..052ce6ac23 100644
--- a/spec/ruby/shared/queue/empty.rb
+++ b/spec/ruby/shared/queue/empty.rb
@@ -1,12 +1,12 @@
describe :queue_empty?, shared: true do
it "returns true on an empty Queue" do
queue = @object.call
- queue.empty?.should be_true
+ queue.empty?.should == true
end
it "returns false when Queue is not empty" do
queue = @object.call
queue << Object.new
- queue.empty?.should be_false
+ queue.empty?.should == false
end
end
diff --git a/spec/ruby/shared/queue/enque.rb b/spec/ruby/shared/queue/enque.rb
index 8aba02e544..61d962b788 100644
--- a/spec/ruby/shared/queue/enque.rb
+++ b/spec/ruby/shared/queue/enque.rb
@@ -13,6 +13,6 @@ describe :queue_enq, shared: true do
q.close
-> {
q.send @method, Object.new
- }.should raise_error(ClosedQueueError)
+ }.should.raise(ClosedQueueError)
end
end
diff --git a/spec/ruby/shared/queue/freeze.rb b/spec/ruby/shared/queue/freeze.rb
index 4c506a4235..7f1f72fd7e 100644
--- a/spec/ruby/shared/queue/freeze.rb
+++ b/spec/ruby/shared/queue/freeze.rb
@@ -1,18 +1,8 @@
describe :queue_freeze, shared: true do
- ruby_version_is ""..."3.3" do
- it "can be frozen" do
- queue = @object.call
+ it "raises an exception when freezing" do
+ queue = @object.call
+ -> {
queue.freeze
- queue.should.frozen?
- end
- end
-
- ruby_version_is "3.3" do
- it "raises an exception when freezing" do
- queue = @object.call
- -> {
- queue.freeze
- }.should raise_error(TypeError, "cannot freeze #{queue}")
- end
+ }.should.raise(TypeError, "cannot freeze #{queue}")
end
end
diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb
index 2f25517675..014056acda 100644
--- a/spec/ruby/shared/sizedqueue/enque.rb
+++ b/spec/ruby/shared/sizedqueue/enque.rb
@@ -29,7 +29,7 @@ describe :sizedqueue_enq, shared: true do
q.size.should == 1
add_to_queue.call
q.size.should == 2
- add_to_queue.should raise_error(ThreadError)
+ add_to_queue.should.raise(ThreadError)
end
it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do
@@ -37,7 +37,7 @@ describe :sizedqueue_enq, shared: true do
q << 1
t = Thread.new {
- -> { q.send(@method, 2) }.should raise_error(ClosedQueueError, "queue closed")
+ -> { q.send(@method, 2) }.should.raise(ClosedQueueError, "queue closed")
}
Thread.pass until q.num_waiting == 1
@@ -49,83 +49,81 @@ describe :sizedqueue_enq, shared: true do
end
describe "with a timeout" do
- ruby_version_is "3.2" do
- it "returns self if the item was pushed in time" do
- q = @object.call(1)
- q << 1
-
- t = Thread.new {
- q.send(@method, 2, timeout: TIME_TOLERANCE).should == q
- }
- Thread.pass until t.status == "sleep" && q.num_waiting == 1
- q.pop
- t.join
- end
-
- it "does nothing if the timeout is nil" do
- q = @object.call(1)
- q << 1
- t = Thread.new {
- q.send(@method, 2, timeout: nil).should == q
- }
- t.join(0.2).should == nil
- q.pop
- t.join
- end
-
- it "returns nil if no space is available and timeout is 0" do
- q = @object.call(1)
- q.send(@method, 1, timeout: 0).should == q
- q.send(@method, 2, timeout: 0).should == nil
- end
-
- it "returns nil if no space is available in time" do
- q = @object.call(1)
- q << 1
- Thread.new {
- q.send(@method, 2, timeout: 0.001).should == nil
- }.join
- end
-
- it "raise TypeError if timeout is not a valid numeric" do
- q = @object.call(1)
- -> {
- q.send(@method, 2, timeout: "1")
- }.should raise_error(TypeError, "no implicit conversion to float from string")
-
- -> {
- q.send(@method, 2, timeout: false)
- }.should raise_error(TypeError, "no implicit conversion to float from false")
- end
-
- it "raise ArgumentError if non_block = true is passed too" do
- q = @object.call(1)
- -> {
- q.send(@method, 2, true, timeout: 1)
- }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled")
- end
-
- it "raise ClosedQueueError when closed before enqueued" do
- q = @object.call(1)
- q.close
- -> { q.send(@method, 2, timeout: 1) }.should raise_error(ClosedQueueError, "queue closed")
- end
-
- it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do
- q = @object.call(1)
- q << 1
-
- t = Thread.new {
- -> { q.send(@method, 1, timeout: TIME_TOLERANCE) }.should raise_error(ClosedQueueError, "queue closed")
- }
-
- Thread.pass until q.num_waiting == 1
-
- q.close
-
- t.join
- q.pop.should == 1
- end
+ it "returns self if the item was pushed in time" do
+ q = @object.call(1)
+ q << 1
+
+ t = Thread.new {
+ q.send(@method, 2, timeout: TIME_TOLERANCE).should == q
+ }
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
+ q.pop
+ t.join
+ end
+
+ it "does nothing if the timeout is nil" do
+ q = @object.call(1)
+ q << 1
+ t = Thread.new {
+ q.send(@method, 2, timeout: nil).should == q
+ }
+ t.join(0.2).should == nil
+ q.pop
+ t.join
+ end
+
+ it "returns nil if no space is available and timeout is 0" do
+ q = @object.call(1)
+ q.send(@method, 1, timeout: 0).should == q
+ q.send(@method, 2, timeout: 0).should == nil
+ end
+
+ it "returns nil if no space is available in time" do
+ q = @object.call(1)
+ q << 1
+ Thread.new {
+ q.send(@method, 2, timeout: 0.001).should == nil
+ }.join
+ end
+
+ it "raise TypeError if timeout is not a valid numeric" do
+ q = @object.call(1)
+ -> {
+ q.send(@method, 2, timeout: "1")
+ }.should raise_consistent_error(TypeError, "no implicit conversion of String into Float")
+
+ -> {
+ q.send(@method, 2, timeout: false)
+ }.should raise_consistent_error(TypeError, "no implicit conversion of false into Float")
+ end
+
+ it "raise ArgumentError if non_block = true is passed too" do
+ q = @object.call(1)
+ -> {
+ q.send(@method, 2, true, timeout: 1)
+ }.should.raise(ArgumentError, "can't set a timeout if non_block is enabled")
+ end
+
+ it "raise ClosedQueueError when closed before enqueued" do
+ q = @object.call(1)
+ q.close
+ -> { q.send(@method, 2, timeout: 1) }.should.raise(ClosedQueueError, "queue closed")
+ end
+
+ it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do
+ q = @object.call(1)
+ q << 1
+
+ t = Thread.new {
+ -> { q.send(@method, 1, timeout: TIME_TOLERANCE) }.should.raise(ClosedQueueError, "queue closed")
+ }
+
+ Thread.pass until q.num_waiting == 1
+
+ q.close
+
+ t.join
+ q.pop.should == 1
end
end
end
diff --git a/spec/ruby/shared/sizedqueue/max.rb b/spec/ruby/shared/sizedqueue/max.rb
index ea10d24be0..167f669275 100644
--- a/spec/ruby/shared/sizedqueue/max.rb
+++ b/spec/ruby/shared/sizedqueue/max.rb
@@ -19,7 +19,7 @@ describe :sizedqueue_max=, shared: true do
q.enq 2
q.enq 3
q.max = 2
- (q.size > q.max).should be_true
+ (q.size > q.max).should == true
q.deq.should == 1
q.deq.should == 2
q.deq.should == 3
@@ -27,21 +27,21 @@ describe :sizedqueue_max=, shared: true do
it "raises a TypeError when given a non-numeric value" do
q = @object.call(5)
- -> { q.max = "foo" }.should raise_error(TypeError)
- -> { q.max = Object.new }.should raise_error(TypeError)
+ -> { q.max = "foo" }.should.raise(TypeError)
+ -> { q.max = Object.new }.should.raise(TypeError)
end
it "raises an argument error when set to zero" do
q = @object.call(5)
q.max.should == 5
- -> { q.max = 0 }.should raise_error(ArgumentError)
+ -> { q.max = 0 }.should.raise(ArgumentError)
q.max.should == 5
end
it "raises an argument error when set to a negative number" do
q = @object.call(5)
q.max.should == 5
- -> { q.max = -1 }.should raise_error(ArgumentError)
+ -> { q.max = -1 }.should.raise(ArgumentError)
q.max.should == 5
end
end
diff --git a/spec/ruby/shared/sizedqueue/new.rb b/spec/ruby/shared/sizedqueue/new.rb
index 2573194efb..2904422a45 100644
--- a/spec/ruby/shared/sizedqueue/new.rb
+++ b/spec/ruby/shared/sizedqueue/new.rb
@@ -1,7 +1,7 @@
describe :sizedqueue_new, shared: true do
it "raises a TypeError when the given argument doesn't respond to #to_int" do
- -> { @object.call("12") }.should raise_error(TypeError)
- -> { @object.call(Object.new) }.should raise_error(TypeError)
+ -> { @object.call("12") }.should.raise(TypeError)
+ -> { @object.call(Object.new) }.should.raise(TypeError)
@object.call(12.9).max.should == 12
object = Object.new
@@ -10,14 +10,14 @@ describe :sizedqueue_new, shared: true do
end
it "raises an argument error when no argument is given" do
- -> { @object.call }.should raise_error(ArgumentError)
+ -> { @object.call }.should.raise(ArgumentError)
end
it "raises an argument error when the given argument is zero" do
- -> { @object.call(0) }.should raise_error(ArgumentError)
+ -> { @object.call(0) }.should.raise(ArgumentError)
end
it "raises an argument error when the given argument is negative" do
- -> { @object.call(-1) }.should raise_error(ArgumentError)
+ -> { @object.call(-1) }.should.raise(ArgumentError)
end
end
diff --git a/spec/ruby/shared/string/end_with.rb b/spec/ruby/shared/string/end_with.rb
index 08f43c1bce..8eb9693395 100644
--- a/spec/ruby/shared/string/end_with.rb
+++ b/spec/ruby/shared/string/end_with.rb
@@ -30,9 +30,9 @@ describe :end_with, shared: true do
it "ignores arguments not convertible to string" do
"hello".send(@method).should_not.end_with?()
- -> { "hello".send(@method).end_with?(1) }.should raise_error(TypeError)
- -> { "hello".send(@method).end_with?(["o"]) }.should raise_error(TypeError)
- -> { "hello".send(@method).end_with?(1, nil, "o") }.should raise_error(TypeError)
+ -> { "hello".send(@method).end_with?(1) }.should.raise(TypeError)
+ -> { "hello".send(@method).end_with?(["o"]) }.should.raise(TypeError)
+ -> { "hello".send(@method).end_with?(1, nil, "o") }.should.raise(TypeError)
end
it "uses only the needed arguments" do
@@ -49,7 +49,7 @@ describe :end_with, shared: true do
pat = "ア".encode Encoding::EUC_JP
-> do
"あれ".send(@method).end_with?(pat)
- end.should raise_error(Encoding::CompatibilityError)
+ end.should.raise(Encoding::CompatibilityError)
end
it "checks that we are starting to match at the head of a character" do
diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb
index 4b947a3bbf..fe12e28969 100644
--- a/spec/ruby/shared/string/start_with.rb
+++ b/spec/ruby/shared/string/start_with.rb
@@ -26,9 +26,9 @@ describe :start_with, shared: true do
it "ignores arguments not convertible to string" do
"hello".send(@method).should_not.start_with?()
- -> { "hello".send(@method).start_with?(1) }.should raise_error(TypeError)
- -> { "hello".send(@method).start_with?(["h"]) }.should raise_error(TypeError)
- -> { "hello".send(@method).start_with?(1, nil, "h") }.should raise_error(TypeError)
+ -> { "hello".send(@method).start_with?(1) }.should.raise(TypeError)
+ -> { "hello".send(@method).start_with?(["h"]) }.should.raise(TypeError)
+ -> { "hello".send(@method).start_with?(1, nil, "h") }.should.raise(TypeError)
end
it "uses only the needed arguments" do
@@ -60,25 +60,17 @@ describe :start_with, shared: true do
it "sets Regexp.last_match if it returns true" do
regexp = /test-(\d+)/
- "test-1337".send(@method).start_with?(regexp).should be_true
- Regexp.last_match.should_not be_nil
+ "test-1337".send(@method).start_with?(regexp).should == true
+ Regexp.last_match.should_not == nil
Regexp.last_match[1].should == "1337"
$1.should == "1337"
- "test-asdf".send(@method).start_with?(regexp).should be_false
- Regexp.last_match.should be_nil
- $1.should be_nil
+ "test-asdf".send(@method).start_with?(regexp).should == false
+ Regexp.last_match.should == nil
+ $1.should == nil
end
- ruby_version_is ""..."3.3" do
- it "does not check that we are not matching part of a character" do
- "\xC3\xA9".send(@method).should.start_with?("\xC3")
- end
- end
-
- ruby_version_is "3.3" do # #19784
- it "checks that we are not matching part of a character" do
- "\xC3\xA9".send(@method).should_not.start_with?("\xC3")
- end
+ it "checks that we are not matching part of a character" do
+ "\xC3\xA9".send(@method).should_not.start_with?("\xC3")
end
end
diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb
index 4814f894cf..0a16ba8b82 100644
--- a/spec/ruby/shared/string/times.rb
+++ b/spec/ruby/shared/string/times.rb
@@ -18,14 +18,14 @@ describe :string_times, shared: true do
end
it "raises an ArgumentError when given integer is negative" do
- -> { @object.call("cool", -3) }.should raise_error(ArgumentError)
- -> { @object.call("cool", -3.14) }.should raise_error(ArgumentError)
- -> { @object.call("cool", min_long) }.should raise_error(ArgumentError)
+ -> { @object.call("cool", -3) }.should.raise(ArgumentError)
+ -> { @object.call("cool", -3.14) }.should.raise(ArgumentError)
+ -> { @object.call("cool", min_long) }.should.raise(ArgumentError)
end
it "raises a RangeError when given integer is a Bignum" do
- -> { @object.call("cool", 999999999999999999999) }.should raise_error(RangeError)
- -> { @object.call("", 999999999999999999999) }.should raise_error(RangeError)
+ -> { @object.call("cool", 999999999999999999999) }.should.raise(RangeError)
+ -> { @object.call("", 999999999999999999999) }.should.raise(RangeError)
end
it "works with huge long values when string is empty" do
@@ -33,26 +33,26 @@ describe :string_times, shared: true do
end
it "returns String instances" do
- @object.call(MyString.new("cool"), 0).should be_an_instance_of(String)
- @object.call(MyString.new("cool"), 1).should be_an_instance_of(String)
- @object.call(MyString.new("cool"), 2).should be_an_instance_of(String)
+ @object.call(MyString.new("cool"), 0).should.instance_of?(String)
+ @object.call(MyString.new("cool"), 1).should.instance_of?(String)
+ @object.call(MyString.new("cool"), 2).should.instance_of?(String)
end
it "returns a String in the same encoding as self" do
str = "\xE3\x81\x82".dup.force_encoding Encoding::UTF_8
result = @object.call(str, 2)
- result.encoding.should equal(Encoding::UTF_8)
+ result.encoding.should.equal?(Encoding::UTF_8)
end
platform_is c_long_size: 32 do
it "raises an ArgumentError if the length of the resulting string doesn't fit into a long" do
- -> { @object.call("abc", (2 ** 31) - 1) }.should raise_error(ArgumentError)
+ -> { @object.call("abc", (2 ** 31) - 1) }.should.raise(ArgumentError)
end
end
platform_is c_long_size: 64 do
it "raises an ArgumentError if the length of the resulting string doesn't fit into a long" do
- -> { @object.call("abc", (2 ** 63) - 1) }.should raise_error(ArgumentError)
+ -> { @object.call("abc", (2 ** 63) - 1) }.should.raise(ArgumentError)
end
end
end
diff --git a/spec/ruby/shared/types/rb_num2dbl_fails.rb b/spec/ruby/shared/types/rb_num2dbl_fails.rb
index ec7cc11986..4d4856fa6c 100644
--- a/spec/ruby/shared/types/rb_num2dbl_fails.rb
+++ b/spec/ruby/shared/types/rb_num2dbl_fails.rb
@@ -7,11 +7,11 @@
describe :rb_num2dbl_fails, shared: true do
it "fails if string is provided" do
- -> { @object.call("123") }.should raise_error(TypeError, "no implicit conversion to float from string")
+ -> { @object.call("123") }.should raise_consistent_error(TypeError, "no implicit conversion of String into Float")
end
it "fails if boolean is provided" do
- -> { @object.call(true) }.should raise_error(TypeError, "no implicit conversion to float from true")
- -> { @object.call(false) }.should raise_error(TypeError, "no implicit conversion to float from false")
+ -> { @object.call(true) }.should raise_consistent_error(TypeError, "no implicit conversion of true into Float")
+ -> { @object.call(false) }.should raise_consistent_error(TypeError, "no implicit conversion of false into Float")
end
end
diff --git a/spec/syntax_suggest/integration/ruby_command_line_spec.rb b/spec/syntax_suggest/integration/ruby_command_line_spec.rb
index c1ec4be54e..02354ceff0 100644
--- a/spec/syntax_suggest/integration/ruby_command_line_spec.rb
+++ b/spec/syntax_suggest/integration/ruby_command_line_spec.rb
@@ -94,8 +94,6 @@ module SyntaxSuggest
end
it "gem can be tested when executing on Ruby with default gem included" do
- skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
-
out = `#{ruby} -I#{lib_dir} -rsyntax_suggest -e "puts SyntaxError.instance_method(:detailed_message).source_location" 2>&1`
expect($?.success?).to be_truthy
@@ -103,8 +101,6 @@ module SyntaxSuggest
end
it "annotates a syntax error in Ruby 3.2+ when require is not used" do
- skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
-
Dir.mktmpdir do |dir|
tmpdir = Pathname(dir)
script = tmpdir.join("script.rb")
diff --git a/spec/syntax_suggest/integration/syntax_suggest_spec.rb b/spec/syntax_suggest/integration/syntax_suggest_spec.rb
index 015d088c92..de9bc5d38e 100644
--- a/spec/syntax_suggest/integration/syntax_suggest_spec.rb
+++ b/spec/syntax_suggest/integration/syntax_suggest_spec.rb
@@ -4,10 +4,6 @@ require_relative "../spec_helper"
module SyntaxSuggest
RSpec.describe "Integration tests that don't spawn a process (like using the cli)" do
- before(:each) do
- skip "Benchmark is not available" unless defined?(::Benchmark)
- end
-
it "does not timeout on massive files" do
next unless ENV["SYNTAX_SUGGEST_TIMEOUT"]
@@ -17,7 +13,7 @@ module SyntaxSuggest
io = StringIO.new
- benchmark = Benchmark.measure do
+ benchmark_measure do
debug_perf do
SyntaxSuggest.call(
io: io,
@@ -28,7 +24,6 @@ module SyntaxSuggest
end
debug_display(io.string)
- debug_display(benchmark)
expect(io.string).to include(<<~EOM)
6 class SyntaxTree < Ripper
@@ -46,7 +41,7 @@ module SyntaxSuggest
io = StringIO.new
debug_perf do
- benchmark = Benchmark.measure do
+ benchmark_measure do
SyntaxSuggest.call(
io: io,
source: file.read,
@@ -54,7 +49,6 @@ module SyntaxSuggest
)
end
debug_display(io.string)
- debug_display(benchmark)
end
expect(io.string).to_not include("def ruby_install_binstub_path")
@@ -209,6 +203,29 @@ module SyntaxSuggest
EOM
end
+ it "multi-line chain with missing paren" do
+ source = <<~EOM
+ class Dog
+ def bark
+ User
+ .where(name: "schneems"
+ .first
+ end
+ end
+ EOM
+ io = StringIO.new
+ SyntaxSuggest.call(
+ io: io,
+ source: source
+ )
+ out = io.string
+ expect(out).to include(<<~EOM)
+ > 3 User
+ > 4 .where(name: "schneems"
+ > 5 .first
+ EOM
+ end
+
it "empty else" do
source = <<~EOM
class Foo
diff --git a/spec/syntax_suggest/spec_helper.rb b/spec/syntax_suggest/spec_helper.rb
index b5d2924e69..c0aaf0f4f7 100644
--- a/spec/syntax_suggest/spec_helper.rb
+++ b/spec/syntax_suggest/spec_helper.rb
@@ -85,6 +85,16 @@ def debug_perf
end
end
+def benchmark_measure
+ raise "No block given" unless block_given?
+
+ if defined?(::Benchmark)
+ debug_display(Benchmark.measure { yield })
+ else
+ yield
+ end
+end
+
def run!(cmd, raise_on_nonzero_exit: true)
out = `#{cmd} 2>&1`
raise "Command: #{cmd} failed: #{out}" if !$?.success? && raise_on_nonzero_exit
diff --git a/spec/syntax_suggest/unit/api_spec.rb b/spec/syntax_suggest/unit/api_spec.rb
index e900b9e10b..9299a17bee 100644
--- a/spec/syntax_suggest/unit/api_spec.rb
+++ b/spec/syntax_suggest/unit/api_spec.rb
@@ -8,12 +8,6 @@ end
module SyntaxSuggest
RSpec.describe "Top level SyntaxSuggest api" do
- it "doesn't load prism if env var is set" do
- skip("SYNTAX_SUGGEST_DISABLE_PRISM not set") unless ENV["SYNTAX_SUGGEST_DISABLE_PRISM"]
-
- expect(SyntaxSuggest.use_prism_parser?).to be_falsey
- end
-
it "has a `handle_error` interface" do
fake_error = Object.new
def fake_error.message
@@ -69,8 +63,6 @@ module SyntaxSuggest
end
it "respects highlight API" do
- skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
-
core_ext_file = lib_dir.join("syntax_suggest").join("core_ext.rb")
require_relative core_ext_file
@@ -91,8 +83,6 @@ module SyntaxSuggest
end
it "can be disabled via falsey kwarg" do
- skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
-
core_ext_file = lib_dir.join("syntax_suggest").join("core_ext.rb")
require_relative core_ext_file
diff --git a/spec/syntax_suggest/unit/clean_document_spec.rb b/spec/syntax_suggest/unit/clean_document_spec.rb
index 5b5ca04cfd..3d83bd13c0 100644
--- a/spec/syntax_suggest/unit/clean_document_spec.rb
+++ b/spec/syntax_suggest/unit/clean_document_spec.rb
@@ -113,7 +113,7 @@ module SyntaxSuggest
lines = CleanDocument.new(source: source).lines
expect(lines[0].to_s).to eq($/)
expect(lines[1].to_s).to eq('puts "what"' + $/)
- expect(lines[2].to_s).to eq($/)
+ expect(lines[2].to_s).to eq(" " + $/)
end
it "trailing slash: does not join trailing do" do
diff --git a/spec/syntax_suggest/unit/code_block_spec.rb b/spec/syntax_suggest/unit/code_block_spec.rb
index 3ab2751b27..dfea307668 100644
--- a/spec/syntax_suggest/unit/code_block_spec.rb
+++ b/spec/syntax_suggest/unit/code_block_spec.rb
@@ -33,7 +33,7 @@ module SyntaxSuggest
array = [block_2, block_1, block_0].sort
expect(array.last).to eq(block_2)
- block = CodeBlock.new(lines: CodeLine.new(line: " " * 8 + "foo", index: 4, lex: []))
+ block = CodeBlock.new(lines: CodeLine.new(line: " " * 8 + "foo", index: 4, tokens: [], consecutive: false))
array.prepend(block)
expect(array.max).to eq(block)
end
diff --git a/spec/syntax_suggest/unit/code_line_spec.rb b/spec/syntax_suggest/unit/code_line_spec.rb
index 5b62cc2757..309d3d1c1e 100644
--- a/spec/syntax_suggest/unit/code_line_spec.rb
+++ b/spec/syntax_suggest/unit/code_line_spec.rb
@@ -17,8 +17,6 @@ module SyntaxSuggest
end
it "supports endless method definitions" do
- skip("Unsupported ruby version") unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3")
-
line = CodeLine.from_source(<<~EOM).first
def square(x) = x * x
EOM
@@ -46,7 +44,7 @@ module SyntaxSuggest
EOM
# Indicates line 1 can join 2, 2 can join 3, but 3 won't join it's next line
- expect(code_lines.map(&:ignore_newline_not_beg?)).to eq([true, true, false, false])
+ expect(code_lines.map(&:consecutive?)).to eq([true, true, false, false])
end
it "trailing if" do
@@ -131,14 +129,15 @@ module SyntaxSuggest
it "knows empty lines" do
code_lines = CodeLine.from_source(<<~EOM)
- # Not empty
+ # Comment only
+ foo # Inline comment
- # Not empty
+ bar
EOM
- expect(code_lines.map(&:empty?)).to eq([false, true, false])
- expect(code_lines.map(&:not_empty?)).to eq([true, false, true])
- expect(code_lines.map { |l| SyntaxSuggest.valid?(l) }).to eq([true, true, true])
+ expect(code_lines.map(&:empty?)).to eq([true, false, true, false])
+ expect(code_lines.map(&:not_empty?)).to eq([false, true, false, true])
+ expect(code_lines.map { |l| SyntaxSuggest.valid?(l) }).to eq([true, true, true, true])
end
it "counts indentations" do
diff --git a/spec/syntax_suggest/unit/core_ext_spec.rb b/spec/syntax_suggest/unit/core_ext_spec.rb
index 499c38a240..d579cc8dc4 100644
--- a/spec/syntax_suggest/unit/core_ext_spec.rb
+++ b/spec/syntax_suggest/unit/core_ext_spec.rb
@@ -3,8 +3,6 @@ require_relative "../spec_helper"
module SyntaxSuggest
RSpec.describe "Core extension" do
it "SyntaxError monkepatch ensures there is a newline to the end of the file" do
- skip if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2")
-
Dir.mktmpdir do |dir|
tmpdir = Pathname(dir)
file = tmpdir.join("file.rb")
diff --git a/spec/syntax_suggest/unit/explain_syntax_spec.rb b/spec/syntax_suggest/unit/explain_syntax_spec.rb
index c62a42b925..7ddb32b8ea 100644
--- a/spec/syntax_suggest/unit/explain_syntax_spec.rb
+++ b/spec/syntax_suggest/unit/explain_syntax_spec.rb
@@ -17,9 +17,23 @@ module SyntaxSuggest
expect(explain.errors.join.strip).to_not be_empty
end
- it "handles %w[]" do
+ %w[w W i I].each do |type|
+ it "handles %#{type}-style array" do
+ source = <<~EOM
+ node.is_a?(Op) && %#{type}[| ||].include?(node.value) &&
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+ end
+ end
+
+ it "handles %r-style regexp" do
source = <<~EOM
- node.is_a?(Op) && %w[| ||].include?(node.value) &&
+ node.is_a?(Op) && %r{| ||}.include?(node.value) &&
EOM
explain = ExplainSyntax.new(
@@ -29,6 +43,20 @@ module SyntaxSuggest
expect(explain.missing).to eq([])
end
+ ["", "q", "Q"].each do |type|
+ it "handles %#{type}-style string" do
+ source = <<~EOM
+ node.is_a?(Op) && %#{type}(| ||).include?(node.value) &&
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+ end
+ end
+
it "doesn't falsely identify strings or symbols as critical chars" do
source = <<~EOM
a = ['(', '{', '[', '|']
diff --git a/spec/syntax_suggest/unit/lex_all_spec.rb b/spec/syntax_suggest/unit/lex_all_spec.rb
deleted file mode 100644
index 9621c9ecec..0000000000
--- a/spec/syntax_suggest/unit/lex_all_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../spec_helper"
-
-module SyntaxSuggest
- RSpec.describe "EndBlockParse" do
- it "finds blocks based on `end` keyword" do
- source = <<~EOM
- describe "cat" # 1
- Cat.call do # 2
- end # 3
- end # 4
- # 5
- it "dog" do # 6
- Dog.call do # 7
- end # 8
- end # 9
- EOM
-
- lex = LexAll.new(source: source)
- expect(lex.map(&:token).to_s).to include("dog")
- expect(lex.first.line).to eq(1)
- expect(lex.last.line).to eq(9)
- end
- end
-end
diff --git a/spec/syntax_suggest/unit/visitor_spec.rb b/spec/syntax_suggest/unit/visitor_spec.rb
new file mode 100644
index 0000000000..94eefd1e95
--- /dev/null
+++ b/spec/syntax_suggest/unit/visitor_spec.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require_relative "../spec_helper"
+
+module SyntaxSuggest
+ RSpec.describe Visitor do
+ def visit(source)
+ ast, _tokens = Prism.parse_lex(source).value
+ visitor = Visitor.new
+ visitor.visit(ast)
+ visitor
+ end
+
+ describe "#consecutive_lines" do
+ it "detects dot-leading multi-line chains" do
+ visitor = visit(<<~RUBY)
+ User
+ .where(name: "Earlopain")
+ .first
+ RUBY
+
+ expect(visitor.consecutive_lines).to eq(Set[1, 2])
+ end
+
+ it "detects dot-trailing multi-line chains" do
+ visitor = visit(<<~RUBY)
+ User.
+ where(name: "Earlopain").
+ first
+ RUBY
+
+ expect(visitor.consecutive_lines).to eq(Set[1, 2])
+ end
+
+ it "handles chains separated by comments" do
+ visitor = visit(<<~RUBY)
+ User.
+ # comment
+ where(name: "Earlopain").
+ # another comment
+ first
+ RUBY
+
+ # The AST sees through comments — every line except
+ # the last is consecutive regardless of interleaved comments.
+ expect(visitor.consecutive_lines).to eq(Set[1, 2, 3, 4])
+ end
+
+ it "returns empty for single-line calls" do
+ visitor = visit(<<~RUBY)
+ User.where(name: "Earlopain").first
+ RUBY
+
+ expect(visitor.consecutive_lines).to be_empty
+ end
+
+ it "returns empty when there is no method chain" do
+ visitor = visit(<<~RUBY)
+ puts "hello"
+ puts "world"
+ RUBY
+
+ expect(visitor.consecutive_lines).to be_empty
+ end
+
+ it "handles deeply nested chains" do
+ visitor = visit(<<~RUBY)
+ User
+ .where(name: "Earlopain")
+ .order(:created_at)
+ .limit(10)
+ .first
+ RUBY
+
+ expect(visitor.consecutive_lines).to eq(Set[1, 2, 3, 4])
+ end
+ end
+
+ describe "#endless_def_keyword_offsets" do
+ it "records the def location for endless methods" do
+ visitor = visit(<<~RUBY)
+ def square(x) = x * x
+ RUBY
+
+ expect(visitor.endless_def_keyword_offsets).to eq(Set[0])
+ end
+
+ it "does not record regular method definitions" do
+ visitor = visit(<<~RUBY)
+ def square(x)
+ x * x
+ end
+ RUBY
+
+ expect(visitor.endless_def_keyword_offsets).to be_empty
+ end
+
+ it "records multiple endless methods" do
+ visitor = visit(<<~RUBY)
+ def square(x) = x * x
+ def double(x) = x * 2
+ RUBY
+
+ expect(visitor.endless_def_keyword_offsets).to eq(Set[0, 22])
+ end
+
+ it "distinguishes endless from regular in the same source" do
+ visitor = visit(<<~RUBY)
+ def square(x) = x * x
+ def cube(x)
+ x * x * x
+ end
+ RUBY
+
+ expect(visitor.endless_def_keyword_offsets).to eq(Set[0])
+ end
+ end
+ end
+end
diff --git a/sprintf.c b/sprintf.c
index cb266a9841..234aff76f5 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -440,8 +440,8 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
{
VALUE val = GETARG();
VALUE tmp;
- unsigned int c;
- int n;
+ unsigned int c = 0;
+ int n, encidx = 0;
tmp = rb_check_string_type(val);
if (!NIL_P(tmp)) {
@@ -451,11 +451,13 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
goto format_s1;
}
n = NUM2INT(val);
- if (n >= 0) n = rb_enc_codelen((c = n), enc);
+ if (n >= 0) {
+ n = rb_enc_codelen((c = n), enc);
+ encidx = rb_ascii8bit_appendable_encoding_index(enc, c);
+ }
if (n <= 0) {
rb_raise(rb_eArgError, "invalid character");
}
- int encidx = rb_ascii8bit_appendable_encoding_index(enc, c);
if (encidx >= 0 && encidx != rb_enc_to_index(enc)) {
/* special case */
rb_enc_associate_index(result, encidx);
diff --git a/st.c b/st.c
index f41120ecaf..6bf83c94cd 100644
--- a/st.c
+++ b/st.c
@@ -107,8 +107,10 @@
#elif defined RUBY_EXPORT
#include "internal.h"
#include "internal/bits.h"
+#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/sanitizers.h"
+#include "internal/set_table.h"
#include "internal/st.h"
#include "ruby_assert.h"
#endif
@@ -172,7 +174,14 @@ static const struct st_hash_type type_strcasehash = {
#define malloc ruby_xmalloc
#define calloc ruby_xcalloc
#define realloc ruby_xrealloc
+#define sized_realloc ruby_xrealloc_sized
#define free ruby_xfree
+#define sized_free ruby_xfree_sized
+#define free_fixed_ptr(v) ruby_xfree_sized((v), sizeof(*(v)))
+#else
+#define sized_realloc(ptr, new_size, old_size) realloc(ptr, new_size)
+#define sized_free(v, s) free(v)
+#define free_fixed_ptr(v) free(v)
#endif
#define EQUAL(tab,x,y) ((x) == (y) || (*(tab)->type->compare)((x),(y)) == 0)
@@ -389,7 +398,7 @@ set_bin(st_index_t *bins, int s, st_index_t n, st_index_t v)
/* Mark I-th bin of table TAB as empty, in other words not
corresponding to any entry. */
-#define MARK_BIN_EMPTY(tab, i) (set_bin((tab)->bins, get_size_ind(tab), i, EMPTY_BIN))
+#define MARK_BIN_EMPTY(tab, i) (set_bin(st_bins_ptr(tab), get_size_ind(tab), i, EMPTY_BIN))
/* Values used for not found entry and bin with given
characteristics. */
@@ -406,7 +415,7 @@ set_bin(st_index_t *bins, int s, st_index_t n, st_index_t v)
corresponding to deleted entries. */
#define MARK_BIN_DELETED(tab, i) \
do { \
- set_bin((tab)->bins, get_size_ind(tab), i, DELETED_BIN); \
+ set_bin(st_bins_ptr(tab), get_size_ind(tab), i, DELETED_BIN); \
} while (0)
/* Macros to check that value B is used empty bins and bins
@@ -417,15 +426,22 @@ set_bin(st_index_t *bins, int s, st_index_t n, st_index_t v)
/* Macros to check empty bins and bins corresponding to deleted
entries. Bins are given by their index I in table TAB. */
-#define IND_EMPTY_BIN_P(tab, i) (EMPTY_BIN_P(get_bin((tab)->bins, get_size_ind(tab), i)))
-#define IND_DELETED_BIN_P(tab, i) (DELETED_BIN_P(get_bin((tab)->bins, get_size_ind(tab), i)))
-#define IND_EMPTY_OR_DELETED_BIN_P(tab, i) (EMPTY_OR_DELETED_BIN_P(get_bin((tab)->bins, get_size_ind(tab), i)))
+#define IND_EMPTY_BIN_P(tab, i) (EMPTY_BIN_P(get_bin(st_bins_ptr(tab), get_size_ind(tab), i)))
+#define IND_DELETED_BIN_P(tab, i) (DELETED_BIN_P(get_bin(st_bins_ptr(tab), get_size_ind(tab), i)))
+#define IND_EMPTY_OR_DELETED_BIN_P(tab, i) (EMPTY_OR_DELETED_BIN_P(get_bin(st_bins_ptr(tab), get_size_ind(tab), i)))
/* Macros for marking and checking deleted entries given by their
pointer E_PTR. */
#define MARK_ENTRY_DELETED(e_ptr) ((e_ptr)->hash = RESERVED_HASH_VAL)
#define DELETED_ENTRY_P(e_ptr) ((e_ptr)->hash == RESERVED_HASH_VAL)
+/* Return the number of allocated entries of table TAB. */
+static inline st_index_t
+get_allocated_entries(const st_table *tab)
+{
+ return ((st_index_t) 1)<<tab->entry_power;
+}
+
/* Return bin size index of table TAB. */
static inline unsigned int
get_size_ind(const st_table *tab)
@@ -447,6 +463,28 @@ bins_mask(const st_table *tab)
return get_bins_num(tab) - 1;
}
+static inline bool
+st_has_bins(const st_table *tab)
+{
+ return tab->entry_power > MAX_POWER2_FOR_TABLES_WITHOUT_BINS;
+}
+
+static inline size_t
+st_allocated_entries_size(const st_table *tab)
+{
+ return get_allocated_entries(tab) * sizeof(st_table_entry);
+}
+
+static inline st_index_t *
+st_bins_ptr(const st_table *tab)
+{
+ if (st_has_bins(tab)) {
+ return (st_index_t *)(((char *)tab->entries) + st_allocated_entries_size(tab));
+ }
+
+ return NULL;
+}
+
/* Return the index of table TAB bin corresponding to
HASH_VALUE. */
static inline st_index_t
@@ -455,25 +493,21 @@ hash_bin(st_hash_t hash_value, st_table *tab)
return hash_value & bins_mask(tab);
}
-/* Return the number of allocated entries of table TAB. */
-static inline st_index_t
-get_allocated_entries(const st_table *tab)
-{
- return ((st_index_t) 1)<<tab->entry_power;
-}
-
/* Return size of the allocated bins of table TAB. */
static inline st_index_t
bins_size(const st_table *tab)
{
- return features[tab->entry_power].bins_words * sizeof (st_index_t);
+ if (st_has_bins(tab)) {
+ return features[tab->entry_power].bins_words * sizeof (st_index_t);
+ }
+ return 0;
}
/* Mark all bins of table TAB as empty. */
static void
initialize_bins(st_table *tab)
{
- memset(tab->bins, 0, bins_size(tab));
+ memset(st_bins_ptr(tab), 0, bins_size(tab));
}
/* Make table TAB empty. */
@@ -482,7 +516,7 @@ make_tab_empty(st_table *tab)
{
tab->num_entries = 0;
tab->entries_start = tab->entries_bound = 0;
- if (tab->bins != NULL)
+ if (st_bins_ptr(tab) != NULL)
initialize_bins(tab);
}
@@ -544,19 +578,12 @@ st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type,
tab->entry_power = n;
tab->bin_power = features[n].bin_power;
tab->size_ind = features[n].size_ind;
- if (n <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
- tab->bins = NULL;
- else {
- tab->bins = (st_index_t *) malloc(bins_size(tab));
-#ifndef RUBY
- if (tab->bins == NULL) {
- free(tab);
- return NULL;
- }
-#endif
+
+ size_t memsize = get_allocated_entries(tab) * sizeof(st_table_entry);
+ if (tab->entry_power > MAX_POWER2_FOR_TABLES_WITHOUT_BINS) {
+ memsize += bins_size(tab);
}
- tab->entries = (st_table_entry *) malloc(get_allocated_entries(tab)
- * sizeof(st_table_entry));
+ tab->entries = (st_table_entry *)malloc(memsize);
#ifndef RUBY
if (tab->entries == NULL) {
st_free_table(tab);
@@ -568,6 +595,12 @@ st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type,
return tab;
}
+st_table *
+st_init_existing_numtable_with_size(st_table *tab, st_index_t size)
+{
+ return st_init_existing_table_with_size(tab, &type_numhash, size);
+}
+
/* Create and return table with TYPE which can hold at least SIZE
entries. The real number of entries which the table can hold is
the nearest power of two for SIZE. */
@@ -584,7 +617,7 @@ st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
st_init_existing_table_with_size(tab, type, size);
#else
if (st_init_existing_table_with_size(tab, type, size) == NULL) {
- free(tab);
+ free_fixed_ptr(tab);
return NULL;
}
#endif
@@ -636,6 +669,13 @@ st_init_strtable_with_size(st_index_t size)
return st_init_table_with_size(&type_strhash, size);
}
+st_table *
+st_init_existing_strtable_with_size(st_table *tab, st_index_t size)
+{
+ return st_init_existing_table_with_size(tab, &type_strhash, size);
+}
+
+
/* Create and return table which can hold a minimal number of strings
whose character case is ignored. */
st_table *
@@ -660,22 +700,40 @@ st_clear(st_table *tab)
tab->rebuilds_num++;
}
+static inline size_t
+st_entries_memsize(const st_table *tab)
+{
+ return get_allocated_entries(tab) * sizeof(st_table_entry);
+}
+
+static inline void
+st_free_entries(const st_table *tab)
+{
+ sized_free(tab->entries, st_entries_memsize(tab) + bins_size(tab));
+}
+
+void
+st_free_embedded_table(st_table *tab)
+{
+ st_free_entries(tab);
+}
+
/* Free table TAB space. */
void
st_free_table(st_table *tab)
{
- free(tab->bins);
- free(tab->entries);
- free(tab);
+ st_free_embedded_table(tab);
+ free_fixed_ptr(tab);
}
/* Return byte size of memory allocated for table TAB. */
size_t
st_memsize(const st_table *tab)
{
+ RUBY_ASSERT(tab != NULL);
return(sizeof(st_table)
- + (tab->bins == NULL ? 0 : bins_size(tab))
- + get_allocated_entries(tab) * sizeof(st_table_entry));
+ + bins_size(tab)
+ + st_entries_memsize(tab));
}
static st_index_t
@@ -740,14 +798,14 @@ rebuild_table(st_table *tab)
|| tab->num_entries < (1 << MINIMAL_POWER2)) {
/* Compaction: */
tab->num_entries = 0;
- if (tab->bins != NULL)
+ if (st_has_bins(tab))
initialize_bins(tab);
rebuild_table_with(tab, tab);
}
else {
st_table *new_tab;
/* This allocation could trigger GC and compaction. If tab is the
- * gen_iv_tbl, then tab could have changed in size due to objects being
+ * gen_fields_tbl, then tab could have changed in size due to objects being
* freed and/or moved. Do not store attributes of tab before this line. */
new_tab = st_init_table_with_size(tab->type,
2 * tab->num_entries - 1);
@@ -770,7 +828,7 @@ rebuild_table_with(st_table *const new_tab, st_table *const tab)
new_entries = new_tab->entries;
ni = 0;
- bins = new_tab->bins;
+ bins = st_bins_ptr(new_tab);
size_ind = get_size_ind(new_tab);
st_index_t bound = tab->entries_bound;
st_table_entry *entries = tab->entries;
@@ -797,14 +855,12 @@ rebuild_table_with(st_table *const new_tab, st_table *const tab)
static void
rebuild_move_table(st_table *const new_tab, st_table *const tab)
{
+ st_free_entries(tab);
tab->entry_power = new_tab->entry_power;
tab->bin_power = new_tab->bin_power;
tab->size_ind = new_tab->size_ind;
- free(tab->bins);
- tab->bins = new_tab->bins;
- free(tab->entries);
tab->entries = new_tab->entries;
- free(new_tab);
+ free_fixed_ptr(new_tab);
}
static void
@@ -887,7 +943,7 @@ find_table_entry_ind(st_table *tab, st_hash_t hash_value, st_data_t key)
#endif
FOUND_BIN;
for (;;) {
- bin = get_bin(tab->bins, get_size_ind(tab), ind);
+ bin = get_bin(st_bins_ptr(tab), get_size_ind(tab), ind);
if (! EMPTY_OR_DELETED_BIN_P(bin)) {
DO_PTR_EQUAL_CHECK(tab, &entries[bin - ENTRY_BASE], hash_value, key, eq_p, rebuilt_p);
if (EXPECT(rebuilt_p, 0))
@@ -933,7 +989,7 @@ find_table_bin_ind(st_table *tab, st_hash_t hash_value, st_data_t key)
#endif
FOUND_BIN;
for (;;) {
- bin = get_bin(tab->bins, get_size_ind(tab), ind);
+ bin = get_bin(st_bins_ptr(tab), get_size_ind(tab), ind);
if (! EMPTY_OR_DELETED_BIN_P(bin)) {
DO_PTR_EQUAL_CHECK(tab, &entries[bin - ENTRY_BASE], hash_value, key, eq_p, rebuilt_p);
if (EXPECT(rebuilt_p, 0))
@@ -976,7 +1032,7 @@ find_table_bin_ind_direct(st_table *tab, st_hash_t hash_value, st_data_t key)
#endif
FOUND_BIN;
for (;;) {
- bin = get_bin(tab->bins, get_size_ind(tab), ind);
+ bin = get_bin(st_bins_ptr(tab), get_size_ind(tab), ind);
if (EMPTY_OR_DELETED_BIN_P(bin))
return ind;
#ifdef QUADRATIC_PROBE
@@ -1024,7 +1080,7 @@ find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
first_deleted_bin_ind = UNDEFINED_BIN_IND;
entries = tab->entries;
for (;;) {
- entry_index = get_bin(tab->bins, get_size_ind(tab), ind);
+ entry_index = get_bin(st_bins_ptr(tab), get_size_ind(tab), ind);
if (EMPTY_BIN_P(entry_index)) {
tab->num_entries++;
entry_index = UNDEFINED_ENTRY_IND;
@@ -1065,7 +1121,7 @@ st_lookup(st_table *tab, st_data_t key, st_data_t *value)
st_hash_t hash = do_hash(key, tab);
retry:
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, hash, key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
goto retry;
@@ -1094,7 +1150,7 @@ st_get_key(st_table *tab, st_data_t key, st_data_t *result)
st_hash_t hash = do_hash(key, tab);
retry:
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, hash, key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
goto retry;
@@ -1140,7 +1196,7 @@ st_insert(st_table *tab, st_data_t key, st_data_t value)
hash_value = do_hash(key, tab);
retry:
rebuild_table_if_necessary(tab);
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, hash_value, key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
goto retry;
@@ -1164,7 +1220,7 @@ st_insert(st_table *tab, st_data_t key, st_data_t value)
entry->key = key;
entry->record = value;
if (bin_ind != UNDEFINED_BIN_IND)
- set_bin(tab->bins, get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
+ set_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
return 0;
}
tab->entries[bin].record = value;
@@ -1190,9 +1246,9 @@ st_add_direct_with_hash(st_table *tab,
entry->key = key;
entry->record = value;
tab->num_entries++;
- if (tab->bins != NULL) {
+ if (st_has_bins(tab)) {
bin_ind = find_table_bin_ind_direct(tab, hash, key);
- set_bin(tab->bins, get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
+ set_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
}
}
@@ -1231,7 +1287,7 @@ st_insert2(st_table *tab, st_data_t key, st_data_t value,
hash_value = do_hash(key, tab);
retry:
rebuild_table_if_necessary (tab);
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, hash_value, key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
goto retry;
@@ -1256,7 +1312,7 @@ st_insert2(st_table *tab, st_data_t key, st_data_t value,
entry->key = key;
entry->record = value;
if (bin_ind != UNDEFINED_BIN_IND)
- set_bin(tab->bins, get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
+ set_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
return 0;
}
tab->entries[bin].record = value;
@@ -1268,27 +1324,15 @@ st_table *
st_replace(st_table *new_tab, st_table *old_tab)
{
*new_tab = *old_tab;
- if (old_tab->bins == NULL)
- new_tab->bins = NULL;
- else {
- new_tab->bins = (st_index_t *) malloc(bins_size(old_tab));
-#ifndef RUBY
- if (new_tab->bins == NULL) {
- return NULL;
- }
-#endif
- }
- new_tab->entries = (st_table_entry *) malloc(get_allocated_entries(old_tab)
- * sizeof(st_table_entry));
+ size_t memsize = get_allocated_entries(old_tab) * sizeof(st_table_entry);
+ memsize += bins_size(old_tab);
+ new_tab->entries = (st_table_entry *) malloc(memsize);
#ifndef RUBY
if (new_tab->entries == NULL) {
return NULL;
}
#endif
- MEMCPY(new_tab->entries, old_tab->entries, st_table_entry,
- get_allocated_entries(old_tab));
- if (old_tab->bins != NULL)
- MEMCPY(new_tab->bins, old_tab->bins, char, bins_size(old_tab));
+ MEMCPY(new_tab->entries, old_tab->entries, char, memsize);
return new_tab;
}
@@ -1343,7 +1387,7 @@ st_general_delete(st_table *tab, st_data_t *key, st_data_t *value)
hash = do_hash(*key, tab);
retry:
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, hash, *key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
goto retry;
@@ -1360,7 +1404,7 @@ st_general_delete(st_table *tab, st_data_t *key, st_data_t *value)
if (value != 0) *value = 0;
return 0;
}
- bin = get_bin(tab->bins, get_size_ind(tab), bin_ind) - ENTRY_BASE;
+ bin = get_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind) - ENTRY_BASE;
MARK_BIN_DELETED(tab, bin_ind);
}
entry = &tab->entries[bin];
@@ -1413,7 +1457,7 @@ st_shift(st_table *tab, st_data_t *key, st_data_t *value)
if (value != 0) *value = curr_entry_ptr->record;
*key = entry_key;
retry:
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, entry_hash, entry_key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0)) {
entries = tab->entries;
@@ -1427,7 +1471,7 @@ st_shift(st_table *tab, st_data_t *key, st_data_t *value)
entries = tab->entries;
goto retry;
}
- curr_entry_ptr = &entries[get_bin(tab->bins, get_size_ind(tab), bin_ind)
+ curr_entry_ptr = &entries[get_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind)
- ENTRY_BASE];
MARK_BIN_DELETED(tab, bin_ind);
}
@@ -1471,7 +1515,7 @@ st_update(st_table *tab, st_data_t key,
retry:
entries = tab->entries;
- if (tab->bins == NULL) {
+ if (!st_has_bins(tab)) {
bin = find_entry(tab, hash, key);
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
goto retry;
@@ -1485,7 +1529,7 @@ st_update(st_table *tab, st_data_t key,
goto retry;
existing = bin_ind != UNDEFINED_BIN_IND;
if (existing) {
- bin = get_bin(tab->bins, get_size_ind(tab), bin_ind) - ENTRY_BASE;
+ bin = get_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind) - ENTRY_BASE;
entry = &entries[bin];
}
}
@@ -1494,7 +1538,16 @@ st_update(st_table *tab, st_data_t key,
value = entry->record;
}
old_key = key;
+
+ unsigned int rebuilds_num = tab->rebuilds_num;
+
retval = (*func)(&key, &value, arg, existing);
+
+ // We need to make sure that the callback didn't cause a table rebuild
+ // Ideally we would make sure no operations happened
+ assert(rebuilds_num == tab->rebuilds_num);
+ (void)rebuilds_num;
+
switch (retval) {
case ST_CONTINUE:
if (! existing) {
@@ -1538,7 +1591,7 @@ st_general_foreach(st_table *tab, st_foreach_check_callback_func *func, st_updat
st_index_t i, rebuilds_num;
st_hash_t hash;
st_data_t key;
- int error_p, packed_p = tab->bins == NULL;
+ int error_p, packed_p = !st_has_bins(tab);
entries = tab->entries;
/* The bound can change inside the loop even without rebuilding
@@ -1563,7 +1616,7 @@ st_general_foreach(st_table *tab, st_foreach_check_callback_func *func, st_updat
if (rebuilds_num != tab->rebuilds_num) {
retry:
entries = tab->entries;
- packed_p = tab->bins == NULL;
+ packed_p = !st_has_bins(tab);
if (packed_p) {
i = find_entry(tab, hash, key);
if (EXPECT(i == REBUILT_TABLE_ENTRY_IND, 0))
@@ -1611,7 +1664,7 @@ st_general_foreach(st_table *tab, st_foreach_check_callback_func *func, st_updat
goto again;
if (bin_ind == UNDEFINED_BIN_IND)
break;
- bin = get_bin(tab->bins, get_size_ind(tab), bin_ind) - ENTRY_BASE;
+ bin = get_bin(st_bins_ptr(tab), get_size_ind(tab), bin_ind) - ENTRY_BASE;
MARK_BIN_DELETED(tab, bin_ind);
}
curr_entry_ptr = &entries[bin];
@@ -2124,16 +2177,14 @@ st_expand_table(st_table *tab, st_index_t siz)
tmp = st_init_table_with_size(tab->type, siz);
n = get_allocated_entries(tab);
MEMCPY(tmp->entries, tab->entries, st_table_entry, n);
- free(tab->entries);
- free(tab->bins);
- free(tmp->bins);
+ st_free_entries(tab);
+
tab->entry_power = tmp->entry_power;
tab->bin_power = tmp->bin_power;
tab->size_ind = tmp->size_ind;
tab->entries = tmp->entries;
- tab->bins = NULL;
tab->rebuilds_num++;
- free(tmp);
+ free_fixed_ptr(tmp);
}
/* Rehash using linear search. Return TRUE if we found that the table
@@ -2145,9 +2196,6 @@ st_rehash_linear(st_table *tab)
st_index_t i, j;
st_table_entry *p, *q;
- free(tab->bins);
- tab->bins = NULL;
-
for (i = tab->entries_start; i < tab->entries_bound; i++) {
p = &tab->entries[i];
if (DELETED_ENTRY_P(p))
@@ -2177,10 +2225,8 @@ st_rehash_indexed(st_table *tab)
{
int eq_p, rebuilt_p;
st_index_t i;
- st_index_t const n = bins_size(tab);
+
unsigned int const size_ind = get_size_ind(tab);
- st_index_t *bins = realloc(tab->bins, n);
- tab->bins = bins;
initialize_bins(tab);
for (i = tab->entries_start; i < tab->entries_bound; i++) {
st_table_entry *p = &tab->entries[i];
@@ -2196,10 +2242,10 @@ st_rehash_indexed(st_table *tab)
ind = hash_bin(p->hash, tab);
for (;;) {
- st_index_t bin = get_bin(bins, size_ind, ind);
+ st_index_t bin = get_bin(st_bins_ptr(tab), size_ind, ind);
if (EMPTY_OR_DELETED_BIN_P(bin)) {
/* ok, new room */
- set_bin(bins, size_ind, ind, i + ENTRY_BASE);
+ set_bin(st_bins_ptr(tab), size_ind, ind, i + ENTRY_BASE);
break;
}
else {
@@ -2239,7 +2285,7 @@ st_rehash(st_table *tab)
int rebuilt_p;
do {
- if (tab->bin_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
+ if (tab->entry_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
rebuilt_p = st_rehash_linear(tab);
else
rebuilt_p = st_rehash_indexed(tab);
@@ -2313,7 +2359,7 @@ rb_hash_bulk_insert_into_st_table(long argc, const VALUE *argv, VALUE hash)
st_insert_generic(tab, argc, argv, hash);
else if (argc <= 2)
st_insert_single(tab, hash, argv[0], argv[1]);
- else if (tab->bin_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
+ else if (tab->entry_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
st_insert_linear(tab, argc, argv, hash);
else
st_insert_generic(tab, argc, argv, hash);
@@ -2332,4 +2378,901 @@ rb_st_compact_table(st_table *tab)
}
}
+/*
+ * set_table related code
+ */
+
+struct set_table_entry {
+ st_hash_t hash;
+ st_data_t key;
+};
+
+/* Return hash value of KEY for table TAB. */
+static inline st_hash_t
+set_do_hash(st_data_t key, set_table *tab)
+{
+ st_hash_t hash = (st_hash_t)(tab->type->hash)(key);
+ return normalize_hash_value(hash);
+}
+
+/* Return bin size index of table TAB. */
+static inline unsigned int
+set_get_size_ind(const set_table *tab)
+{
+ return tab->size_ind;
+}
+
+/* Return the number of allocated bins of table TAB. */
+static inline st_index_t
+set_get_bins_num(const set_table *tab)
+{
+ return ((st_index_t) 1)<<tab->bin_power;
+}
+
+/* Return mask for a bin index in table TAB. */
+static inline st_index_t
+set_bins_mask(const set_table *tab)
+{
+ return set_get_bins_num(tab) - 1;
+}
+
+/* Return the index of table TAB bin corresponding to
+ HASH_VALUE. */
+static inline st_index_t
+set_hash_bin(st_hash_t hash_value, set_table *tab)
+{
+ return hash_value & set_bins_mask(tab);
+}
+
+/* Return the number of allocated entries of table TAB. */
+static inline st_index_t
+set_get_allocated_entries(const set_table *tab)
+{
+ return ((st_index_t) 1)<<tab->entry_power;
+}
+
+static inline size_t
+set_allocated_entries_size(const set_table *tab)
+{
+ return set_get_allocated_entries(tab) * sizeof(set_table_entry);
+}
+
+static inline bool
+set_has_bins(const set_table *tab)
+{
+ return tab->entry_power > MAX_POWER2_FOR_TABLES_WITHOUT_BINS;
+}
+
+/* Return size of the allocated bins of table TAB. */
+static inline st_index_t
+set_bins_size(const set_table *tab)
+{
+ if (set_has_bins(tab)) {
+ return features[tab->entry_power].bins_words * sizeof (st_index_t);
+ }
+
+ return 0;
+}
+
+static inline st_index_t *
+set_bins_ptr(const set_table *tab)
+{
+ if (set_has_bins(tab)) {
+ return (st_index_t *)(((char *)tab->entries) + set_allocated_entries_size(tab));
+ }
+
+ return NULL;
+}
+
+/* Mark all bins of table TAB as empty. */
+static void
+set_initialize_bins(set_table *tab)
+{
+ memset(set_bins_ptr(tab), 0, set_bins_size(tab));
+}
+
+/* Make table TAB empty. */
+static void
+set_make_tab_empty(set_table *tab)
+{
+ tab->num_entries = 0;
+ tab->entries_start = tab->entries_bound = 0;
+ if (set_bins_ptr(tab) != NULL)
+ set_initialize_bins(tab);
+}
+
+static inline size_t
+set_entries_memsize(set_table *tab)
+{
+ size_t memsize = set_get_allocated_entries(tab) * sizeof(set_table_entry);
+ if (set_has_bins(tab)) {
+ memsize += set_bins_size(tab);
+ }
+ return memsize;
+}
+
+static set_table *
+set_init_existing_table_with_size(set_table *tab, const struct st_hash_type *type, st_index_t size)
+{
+ int n;
+
+#ifdef HASH_LOG
+#if HASH_LOG+0 < 0
+ {
+ const char *e = getenv("ST_HASH_LOG");
+ if (!e || !*e) init_st = 1;
+ }
+#endif
+ if (init_st == 0) {
+ init_st = 1;
+ atexit(stat_col);
+ }
+#endif
+
+ n = get_power2(size);
+
+ tab->type = type;
+ tab->entry_power = n;
+ tab->bin_power = features[n].bin_power;
+ tab->size_ind = features[n].size_ind;
+
+ tab->entries = (set_table_entry *)malloc(set_entries_memsize(tab));
+ set_make_tab_empty(tab);
+ tab->rebuilds_num = 0;
+ return tab;
+}
+
+/* Create and return table with TYPE which can hold at least SIZE
+ entries. The real number of entries which the table can hold is
+ the nearest power of two for SIZE. */
+set_table *
+set_init_table_with_size(set_table *tab, const struct st_hash_type *type, st_index_t size)
+{
+ if (tab == NULL) tab = malloc(sizeof(set_table));
+
+ set_init_existing_table_with_size(tab, type, size);
+
+ return tab;
+}
+
+set_table *
+set_init_numtable(void)
+{
+ return set_init_table_with_size(NULL, &type_numhash, 0);
+}
+
+set_table *
+set_init_numtable_with_size(st_index_t size)
+{
+ return set_init_table_with_size(NULL, &type_numhash, size);
+}
+
+set_table *
+set_init_embedded_numtable_with_size(set_table *tab, st_index_t size)
+{
+ return set_init_existing_table_with_size(tab, &type_numhash, size);
+}
+
+size_t
+set_table_size(const struct set_table *tbl)
+{
+ return tbl->num_entries;
+}
+
+/* Make table TAB empty. */
+void
+set_table_clear(set_table *tab)
+{
+ set_make_tab_empty(tab);
+ tab->rebuilds_num++;
+}
+
+void
+set_free_embedded_table(set_table *tab)
+{
+ sized_free(tab->entries, set_entries_memsize(tab));
+}
+
+/* Free table TAB space. This should only be used if you passed NULL to
+ set_init_table_with_size/set_copy when creating the table. */
+void
+set_free_table(set_table *tab)
+{
+ set_free_embedded_table(tab);
+ free_fixed_ptr(tab);
+}
+
+/* Return byte size of memory allocated for table TAB. */
+size_t
+set_memsize(const set_table *tab)
+{
+ return(sizeof(set_table)
+ + (tab->entry_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS ? 0 : set_bins_size(tab))
+ + set_get_allocated_entries(tab) * sizeof(set_table_entry));
+}
+
+static st_index_t
+set_find_table_entry_ind(set_table *tab, st_hash_t hash_value, st_data_t key);
+
+static st_index_t
+set_find_table_bin_ind(set_table *tab, st_hash_t hash_value, st_data_t key);
+
+static st_index_t
+set_find_table_bin_ind_direct(set_table *table, st_hash_t hash_value, st_data_t key);
+
+static st_index_t
+set_find_table_bin_ptr_and_reserve(set_table *tab, st_hash_t *hash_value,
+ st_data_t key, st_index_t *bin_ind);
+
+static void set_rebuild_table_with(set_table *const new_tab, set_table *const tab);
+static void set_rebuild_move_table(set_table *const new_tab, set_table *const tab);
+static void set_rebuild_cleanup(set_table *const tab);
+
+/* Rebuild table TAB. Rebuilding removes all deleted bins and entries
+ and can change size of the table entries and bins arrays.
+ Rebuilding is implemented by creation of a new table or by
+ compaction of the existing one. */
+static void
+set_rebuild_table(set_table *tab)
+{
+ if ((2 * tab->num_entries <= set_get_allocated_entries(tab)
+ && REBUILD_THRESHOLD * tab->num_entries > set_get_allocated_entries(tab))
+ || tab->num_entries < (1 << MINIMAL_POWER2)) {
+ /* Compaction: */
+ tab->num_entries = 0;
+ if (set_has_bins(tab))
+ set_initialize_bins(tab);
+ set_rebuild_table_with(tab, tab);
+ }
+ else {
+ set_table *new_tab;
+ /* This allocation could trigger GC and compaction. If tab is the
+ * gen_fields_tbl, then tab could have changed in size due to objects being
+ * freed and/or moved. Do not store attributes of tab before this line. */
+ new_tab = set_init_table_with_size(NULL, tab->type,
+ 2 * tab->num_entries - 1);
+ set_rebuild_table_with(new_tab, tab);
+ set_rebuild_move_table(new_tab, tab);
+ }
+ set_rebuild_cleanup(tab);
+}
+
+static void
+set_rebuild_table_with(set_table *const new_tab, set_table *const tab)
+{
+ st_index_t i, ni;
+ unsigned int size_ind;
+ set_table_entry *new_entries;
+ set_table_entry *curr_entry_ptr;
+ st_index_t *bins;
+ st_index_t bin_ind;
+
+ new_entries = new_tab->entries;
+
+ ni = 0;
+ bins = set_bins_ptr(new_tab);
+ size_ind = set_get_size_ind(new_tab);
+ st_index_t bound = tab->entries_bound;
+ set_table_entry *entries = tab->entries;
+
+ for (i = tab->entries_start; i < bound; i++) {
+ curr_entry_ptr = &entries[i];
+ PREFETCH(entries + i + 1, 0);
+ if (EXPECT(DELETED_ENTRY_P(curr_entry_ptr), 0))
+ continue;
+ if (&new_entries[ni] != curr_entry_ptr)
+ new_entries[ni] = *curr_entry_ptr;
+ if (EXPECT(bins != NULL, 1)) {
+ bin_ind = set_find_table_bin_ind_direct(new_tab, curr_entry_ptr->hash,
+ curr_entry_ptr->key);
+ set_bin(bins, size_ind, bin_ind, ni + ENTRY_BASE);
+ }
+ new_tab->num_entries++;
+ ni++;
+ }
+
+ assert(new_tab->num_entries == tab->num_entries);
+}
+
+static void
+set_rebuild_move_table(set_table *const new_tab, set_table *const tab)
+{
+ sized_free(tab->entries, set_entries_memsize(tab));
+ tab->entries = new_tab->entries;
+
+ tab->entry_power = new_tab->entry_power;
+ tab->bin_power = new_tab->bin_power;
+ tab->size_ind = new_tab->size_ind;
+
+ free_fixed_ptr(new_tab);
+}
+
+static void
+set_rebuild_cleanup(set_table *const tab)
+{
+ tab->entries_start = 0;
+ tab->entries_bound = tab->num_entries;
+ tab->rebuilds_num++;
+}
+
+/* Return the next secondary hash index for table TAB using previous
+ index IND and PERTURB. Finally modulo of the function becomes a
+ full *cycle linear congruential generator*, in other words it
+ guarantees traversing all table bins in extreme case.
+
+ According the Hull-Dobell theorem a generator
+ "Xnext = (a*Xprev + c) mod m" is a full cycle generator if and only if
+ o m and c are relatively prime
+ o a-1 is divisible by all prime factors of m
+ o a-1 is divisible by 4 if m is divisible by 4.
+
+ For our case a is 5, c is 1, and m is a power of two. */
+static inline st_index_t
+set_secondary_hash(st_index_t ind, set_table *tab, st_index_t *perturb)
+{
+ *perturb >>= 11;
+ ind = (ind << 2) + ind + *perturb + 1;
+ return set_hash_bin(ind, tab);
+}
+
+/* Find an entry with HASH_VALUE and KEY in TABLE using a linear
+ search. Return the index of the found entry in array `entries`.
+ If it is not found, return UNDEFINED_ENTRY_IND. If the table was
+ rebuilt during the search, return REBUILT_TABLE_ENTRY_IND. */
+static inline st_index_t
+set_find_entry(set_table *tab, st_hash_t hash_value, st_data_t key)
+{
+ int eq_p, rebuilt_p;
+ st_index_t i, bound;
+ set_table_entry *entries;
+
+ bound = tab->entries_bound;
+ entries = tab->entries;
+ for (i = tab->entries_start; i < bound; i++) {
+ DO_PTR_EQUAL_CHECK(tab, &entries[i], hash_value, key, eq_p, rebuilt_p);
+ if (EXPECT(rebuilt_p, 0))
+ return REBUILT_TABLE_ENTRY_IND;
+ if (eq_p)
+ return i;
+ }
+ return UNDEFINED_ENTRY_IND;
+}
+
+/* Use the quadratic probing. The method has a better data locality
+ but more collisions than the current approach. In average it
+ results in a bit slower search. */
+/*#define QUADRATIC_PROBE*/
+
+/* Return index of entry with HASH_VALUE and KEY in table TAB. If
+ there is no such entry, return UNDEFINED_ENTRY_IND. If the table
+ was rebuilt during the search, return REBUILT_TABLE_ENTRY_IND. */
+static st_index_t
+set_find_table_entry_ind(set_table *tab, st_hash_t hash_value, st_data_t key)
+{
+ int eq_p, rebuilt_p;
+ st_index_t ind;
+#ifdef QUADRATIC_PROBE
+ st_index_t d;
+#else
+ st_index_t perturb;
+#endif
+ st_index_t bin;
+ set_table_entry *entries = tab->entries;
+
+ ind = set_hash_bin(hash_value, tab);
+#ifdef QUADRATIC_PROBE
+ d = 1;
+#else
+ perturb = hash_value;
+#endif
+ for (;;) {
+ bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
+ if (! EMPTY_OR_DELETED_BIN_P(bin)) {
+ DO_PTR_EQUAL_CHECK(tab, &entries[bin - ENTRY_BASE], hash_value, key, eq_p, rebuilt_p);
+ if (EXPECT(rebuilt_p, 0))
+ return REBUILT_TABLE_ENTRY_IND;
+ if (eq_p)
+ break;
+ }
+ else if (EMPTY_BIN_P(bin))
+ return UNDEFINED_ENTRY_IND;
+#ifdef QUADRATIC_PROBE
+ ind = set_hash_bin(ind + d, tab);
+ d++;
+#else
+ ind = set_secondary_hash(ind, tab, &perturb);
+#endif
+ }
+ return bin;
+}
+
+/* Find and return index of table TAB bin corresponding to an entry
+ with HASH_VALUE and KEY. If there is no such bin, return
+ UNDEFINED_BIN_IND. If the table was rebuilt during the search,
+ return REBUILT_TABLE_BIN_IND. */
+static st_index_t
+set_find_table_bin_ind(set_table *tab, st_hash_t hash_value, st_data_t key)
+{
+ int eq_p, rebuilt_p;
+ st_index_t ind;
+#ifdef QUADRATIC_PROBE
+ st_index_t d;
+#else
+ st_index_t perturb;
+#endif
+ st_index_t bin;
+ set_table_entry *entries = tab->entries;
+
+ ind = set_hash_bin(hash_value, tab);
+#ifdef QUADRATIC_PROBE
+ d = 1;
+#else
+ perturb = hash_value;
+#endif
+ for (;;) {
+ bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
+ if (! EMPTY_OR_DELETED_BIN_P(bin)) {
+ DO_PTR_EQUAL_CHECK(tab, &entries[bin - ENTRY_BASE], hash_value, key, eq_p, rebuilt_p);
+ if (EXPECT(rebuilt_p, 0))
+ return REBUILT_TABLE_BIN_IND;
+ if (eq_p)
+ break;
+ }
+ else if (EMPTY_BIN_P(bin))
+ return UNDEFINED_BIN_IND;
+#ifdef QUADRATIC_PROBE
+ ind = set_hash_bin(ind + d, tab);
+ d++;
+#else
+ ind = set_secondary_hash(ind, tab, &perturb);
+#endif
+ }
+ return ind;
+}
+
+/* Find and return index of table TAB bin corresponding to an entry
+ with HASH_VALUE and KEY. The entry should be in the table
+ already. */
+static st_index_t
+set_find_table_bin_ind_direct(set_table *tab, st_hash_t hash_value, st_data_t key)
+{
+ st_index_t ind;
+#ifdef QUADRATIC_PROBE
+ st_index_t d;
+#else
+ st_index_t perturb;
+#endif
+ st_index_t bin;
+
+ ind = set_hash_bin(hash_value, tab);
+#ifdef QUADRATIC_PROBE
+ d = 1;
+#else
+ perturb = hash_value;
+#endif
+ for (;;) {
+ bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
+ if (EMPTY_OR_DELETED_BIN_P(bin))
+ return ind;
+#ifdef QUADRATIC_PROBE
+ ind = set_hash_bin(ind + d, tab);
+ d++;
+#else
+ ind = set_secondary_hash(ind, tab, &perturb);
+#endif
+ }
+}
+
+/* Mark I-th bin of table TAB as empty, in other words not
+ corresponding to any entry. */
+#define MARK_SET_BIN_EMPTY(tab, i) (set_bin(set_bins_ptr(tab), set_get_size_ind(tab), i, EMPTY_BIN))
+
+/* Return index of table TAB bin for HASH_VALUE and KEY through
+ BIN_IND and the pointed value as the function result. Reserve the
+ bin for inclusion of the corresponding entry into the table if it
+ is not there yet. We always find such bin as bins array length is
+ bigger entries array. Although we can reuse a deleted bin, the
+ result bin value is always empty if the table has no entry with
+ KEY. Return the entries array index of the found entry or
+ UNDEFINED_ENTRY_IND if it is not found. If the table was rebuilt
+ during the search, return REBUILT_TABLE_ENTRY_IND. */
+static st_index_t
+set_find_table_bin_ptr_and_reserve(set_table *tab, st_hash_t *hash_value,
+ st_data_t key, st_index_t *bin_ind)
+{
+ int eq_p, rebuilt_p;
+ st_index_t ind;
+ st_hash_t curr_hash_value = *hash_value;
+#ifdef QUADRATIC_PROBE
+ st_index_t d;
+#else
+ st_index_t perturb;
+#endif
+ st_index_t entry_index;
+ st_index_t firset_deleted_bin_ind;
+ set_table_entry *entries;
+
+ ind = set_hash_bin(curr_hash_value, tab);
+#ifdef QUADRATIC_PROBE
+ d = 1;
+#else
+ perturb = curr_hash_value;
+#endif
+ firset_deleted_bin_ind = UNDEFINED_BIN_IND;
+ entries = tab->entries;
+ for (;;) {
+ entry_index = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
+ if (EMPTY_BIN_P(entry_index)) {
+ tab->num_entries++;
+ entry_index = UNDEFINED_ENTRY_IND;
+ if (firset_deleted_bin_ind != UNDEFINED_BIN_IND) {
+ /* We can reuse bin of a deleted entry. */
+ ind = firset_deleted_bin_ind;
+ MARK_SET_BIN_EMPTY(tab, ind);
+ }
+ break;
+ }
+ else if (! DELETED_BIN_P(entry_index)) {
+ DO_PTR_EQUAL_CHECK(tab, &entries[entry_index - ENTRY_BASE], curr_hash_value, key, eq_p, rebuilt_p);
+ if (EXPECT(rebuilt_p, 0))
+ return REBUILT_TABLE_ENTRY_IND;
+ if (eq_p)
+ break;
+ }
+ else if (firset_deleted_bin_ind == UNDEFINED_BIN_IND)
+ firset_deleted_bin_ind = ind;
+#ifdef QUADRATIC_PROBE
+ ind = set_hash_bin(ind + d, tab);
+ d++;
+#else
+ ind = set_secondary_hash(ind, tab, &perturb);
+#endif
+ }
+ *bin_ind = ind;
+ return entry_index;
+}
+
+/* Find an entry with KEY in table TAB. Return non-zero if we found
+ it. */
+int
+set_table_lookup(set_table *tab, st_data_t key)
+{
+ st_index_t bin;
+ st_hash_t hash = set_do_hash(key, tab);
+
+ retry:
+ if (!set_has_bins(tab)) {
+ bin = set_find_entry(tab, hash, key);
+ if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ if (bin == UNDEFINED_ENTRY_IND)
+ return 0;
+ }
+ else {
+ bin = set_find_table_entry_ind(tab, hash, key);
+ if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ if (bin == UNDEFINED_ENTRY_IND)
+ return 0;
+ bin -= ENTRY_BASE;
+ }
+ return 1;
+}
+
+/* Check the table and rebuild it if it is necessary. */
+static inline void
+set_rebuild_table_if_necessary (set_table *tab)
+{
+ st_index_t bound = tab->entries_bound;
+
+ if (bound == set_get_allocated_entries(tab))
+ set_rebuild_table(tab);
+}
+
+/* Insert KEY into table TAB and return zero. If there is
+ already entry with KEY in the table, return nonzero and update
+ the value of the found entry. */
+int
+set_insert(set_table *tab, st_data_t key)
+{
+ set_table_entry *entry;
+ st_index_t bin;
+ st_index_t ind;
+ st_hash_t hash_value;
+ st_index_t bin_ind;
+ int new_p;
+
+ hash_value = set_do_hash(key, tab);
+ retry:
+ set_rebuild_table_if_necessary(tab);
+ if (!set_has_bins(tab)) {
+ bin = set_find_entry(tab, hash_value, key);
+ if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ new_p = bin == UNDEFINED_ENTRY_IND;
+ if (new_p)
+ tab->num_entries++;
+ bin_ind = UNDEFINED_BIN_IND;
+ }
+ else {
+ bin = set_find_table_bin_ptr_and_reserve(tab, &hash_value,
+ key, &bin_ind);
+ if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ new_p = bin == UNDEFINED_ENTRY_IND;
+ bin -= ENTRY_BASE;
+ }
+ if (new_p) {
+ ind = tab->entries_bound++;
+ entry = &tab->entries[ind];
+ entry->hash = hash_value;
+ entry->key = key;
+ if (bin_ind != UNDEFINED_BIN_IND)
+ set_bin(set_bins_ptr(tab), set_get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
+ return 0;
+ }
+ return 1;
+}
+
+/* Create a copy of old_tab into new_tab. */
+static set_table *
+set_replace(set_table *new_tab, set_table *old_tab)
+{
+ *new_tab = *old_tab;
+ size_t memsize = set_allocated_entries_size(old_tab) + set_bins_size(old_tab);
+ new_tab->entries = (set_table_entry *)malloc(memsize);
+ MEMCPY(new_tab->entries, old_tab->entries, char, memsize);
+ return new_tab;
+}
+
+/* Create and return a copy of table OLD_TAB. */
+set_table *
+set_copy(set_table *new_tab, set_table *old_tab)
+{
+ if (new_tab == NULL) new_tab = (set_table *) malloc(sizeof(set_table));
+
+ if (set_replace(new_tab, old_tab) == NULL) {
+ set_free_table(new_tab);
+ return NULL;
+ }
+
+ return new_tab;
+}
+
+/* Update the entries start of table TAB after removing an entry
+ with index N in the array entries. */
+static inline void
+set_update_range_for_deleted(set_table *tab, st_index_t n)
+{
+ /* Do not update entries_bound here. Otherwise, we can fill all
+ bins by deleted entry value before rebuilding the table. */
+ if (tab->entries_start == n) {
+ st_index_t start = n + 1;
+ st_index_t bound = tab->entries_bound;
+ set_table_entry *entries = tab->entries;
+ while (start < bound && DELETED_ENTRY_P(&entries[start])) start++;
+ tab->entries_start = start;
+ }
+}
+
+/* Mark I-th bin of table TAB as corresponding to a deleted table
+ entry. Update number of entries in the table and number of bins
+ corresponding to deleted entries. */
+#define MARK_SET_BIN_DELETED(tab, i) \
+ do { \
+ set_bin(set_bins_ptr(tab), set_get_size_ind(tab), i, DELETED_BIN); \
+ } while (0)
+
+/* Delete entry with KEY from table TAB, and return non-zero. If
+ there is no entry with KEY in the table, return zero. */
+int
+set_table_delete(set_table *tab, st_data_t *key)
+{
+ set_table_entry *entry;
+ st_index_t bin;
+ st_index_t bin_ind;
+ st_hash_t hash;
+
+ hash = set_do_hash(*key, tab);
+ retry:
+ if (!set_has_bins(tab)) {
+ bin = set_find_entry(tab, hash, *key);
+ if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ if (bin == UNDEFINED_ENTRY_IND) {
+ return 0;
+ }
+ }
+ else {
+ bin_ind = set_find_table_bin_ind(tab, hash, *key);
+ if (EXPECT(bin_ind == REBUILT_TABLE_BIN_IND, 0))
+ goto retry;
+ if (bin_ind == UNDEFINED_BIN_IND) {
+ return 0;
+ }
+ bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), bin_ind) - ENTRY_BASE;
+ MARK_SET_BIN_DELETED(tab, bin_ind);
+ }
+ entry = &tab->entries[bin];
+ *key = entry->key;
+ MARK_ENTRY_DELETED(entry);
+ tab->num_entries--;
+ set_update_range_for_deleted(tab, bin);
+ return 1;
+}
+
+/* Traverse all entries in table TAB calling FUNC with current entry
+ key and zero. If the call returns ST_STOP, stop
+ traversing. If the call returns ST_DELETE, delete the current
+ entry from the table. In case of ST_CHECK or ST_CONTINUE, continue
+ traversing. The function returns zero unless an error is found.
+ CHECK_P is flag of set_foreach_check call. The behavior is a bit
+ different for ST_CHECK and when the current element is removed
+ during traversing. */
+static inline int
+set_general_foreach(set_table *tab, set_foreach_check_callback_func *func,
+ set_update_callback_func *replace, st_data_t arg,
+ int check_p)
+{
+ st_index_t bin;
+ st_index_t bin_ind;
+ set_table_entry *entries, *curr_entry_ptr;
+ enum st_retval retval;
+ st_index_t i, rebuilds_num;
+ st_hash_t hash;
+ st_data_t key;
+ int error_p, packed_p = !set_has_bins(tab);
+
+ entries = tab->entries;
+ /* The bound can change inside the loop even without rebuilding
+ the table, e.g. by an entry insertion. */
+ for (i = tab->entries_start; i < tab->entries_bound; i++) {
+ curr_entry_ptr = &entries[i];
+ if (EXPECT(DELETED_ENTRY_P(curr_entry_ptr), 0))
+ continue;
+ key = curr_entry_ptr->key;
+ rebuilds_num = tab->rebuilds_num;
+ hash = curr_entry_ptr->hash;
+ retval = (*func)(key, arg, 0);
+
+ if (retval == ST_REPLACE && replace) {
+ retval = (*replace)(&key, arg, TRUE);
+ curr_entry_ptr->key = key;
+ }
+
+ if (rebuilds_num != tab->rebuilds_num) {
+ retry:
+ entries = tab->entries;
+ packed_p = !set_has_bins(tab);
+ if (packed_p) {
+ i = set_find_entry(tab, hash, key);
+ if (EXPECT(i == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ error_p = i == UNDEFINED_ENTRY_IND;
+ }
+ else {
+ i = set_find_table_entry_ind(tab, hash, key);
+ if (EXPECT(i == REBUILT_TABLE_ENTRY_IND, 0))
+ goto retry;
+ error_p = i == UNDEFINED_ENTRY_IND;
+ i -= ENTRY_BASE;
+ }
+ if (error_p && check_p) {
+ /* call func with error notice */
+ retval = (*func)(0, arg, 1);
+ return 1;
+ }
+ curr_entry_ptr = &entries[i];
+ }
+ switch (retval) {
+ case ST_REPLACE:
+ break;
+ case ST_CONTINUE:
+ break;
+ case ST_CHECK:
+ if (check_p)
+ break;
+ case ST_STOP:
+ return 0;
+ case ST_DELETE: {
+ st_data_t key = curr_entry_ptr->key;
+
+ again:
+ if (packed_p) {
+ bin = set_find_entry(tab, hash, key);
+ if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
+ goto again;
+ if (bin == UNDEFINED_ENTRY_IND)
+ break;
+ }
+ else {
+ bin_ind = set_find_table_bin_ind(tab, hash, key);
+ if (EXPECT(bin_ind == REBUILT_TABLE_BIN_IND, 0))
+ goto again;
+ if (bin_ind == UNDEFINED_BIN_IND)
+ break;
+ bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), bin_ind) - ENTRY_BASE;
+ MARK_SET_BIN_DELETED(tab, bin_ind);
+ }
+ curr_entry_ptr = &entries[bin];
+ MARK_ENTRY_DELETED(curr_entry_ptr);
+ tab->num_entries--;
+ set_update_range_for_deleted(tab, bin);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int
+set_foreach_with_replace(set_table *tab, set_foreach_check_callback_func *func, set_update_callback_func *replace, st_data_t arg)
+{
+ return set_general_foreach(tab, func, replace, arg, TRUE);
+}
+
+struct set_functor {
+ set_foreach_callback_func *func;
+ st_data_t arg;
+};
+
+static int
+set_apply_functor(st_data_t k, st_data_t d, int _)
+{
+ const struct set_functor *f = (void *)d;
+ return f->func(k, f->arg);
+}
+
+int
+set_table_foreach(set_table *tab, set_foreach_callback_func *func, st_data_t arg)
+{
+ const struct set_functor f = { func, arg };
+ return set_general_foreach(tab, set_apply_functor, NULL, (st_data_t)&f, FALSE);
+}
+
+/* See comments for function set_delete_safe. */
+int
+set_foreach_check(set_table *tab, set_foreach_check_callback_func *func, st_data_t arg,
+ st_data_t never ATTRIBUTE_UNUSED)
+{
+ return set_general_foreach(tab, func, NULL, arg, TRUE);
+}
+
+/* Set up array KEYS by at most SIZE keys of head table TAB entries.
+ Return the number of keys set up in array KEYS. */
+inline st_index_t
+set_keys(set_table *tab, st_data_t *keys, st_index_t size)
+{
+ st_index_t i, bound;
+ st_data_t key, *keys_start, *keys_end;
+ set_table_entry *curr_entry_ptr, *entries = tab->entries;
+
+ bound = tab->entries_bound;
+ keys_start = keys;
+ keys_end = keys + size;
+ for (i = tab->entries_start; i < bound; i++) {
+ if (keys == keys_end)
+ break;
+ curr_entry_ptr = &entries[i];
+ key = curr_entry_ptr->key;
+ if (! DELETED_ENTRY_P(curr_entry_ptr))
+ *keys++ = key;
+ }
+
+ return keys - keys_start;
+}
+
+void
+set_compact_table(set_table *tab)
+{
+ st_index_t num = tab->num_entries;
+ if (REBUILD_THRESHOLD * num <= set_get_allocated_entries(tab)) {
+ /* Compaction: */
+ set_table *new_tab = set_init_table_with_size(NULL, tab->type, 2 * num);
+ set_rebuild_table_with(new_tab, tab);
+ set_rebuild_move_table(new_tab, tab);
+ set_rebuild_cleanup(tab);
+ }
+}
+
#endif
diff --git a/string.c b/string.c
index 857d1e1085..134e125431 100644
--- a/string.c
+++ b/string.c
@@ -28,6 +28,7 @@
#include "internal/array.h"
#include "internal/compar.h"
#include "internal/compilers.h"
+#include "internal/concurrent_set.h"
#include "internal/encoding.h"
#include "internal/error.h"
#include "internal/gc.h"
@@ -42,9 +43,13 @@
#include "probes.h"
#include "ruby/encoding.h"
#include "ruby/re.h"
+#include "ruby/thread.h"
#include "ruby/util.h"
+#include "ruby/ractor.h"
#include "ruby_assert.h"
+#include "shape.h"
#include "vm_sync.h"
+#include "ruby/internal/attr/nonstring.h"
#if defined HAVE_CRYPT_R
# if defined HAVE_CRYPT_H
@@ -55,9 +60,6 @@
# define HAVE_CRYPT_R 1
#endif
-#define BEG(no) (regs->beg[(no)])
-#define END(no) (regs->end[(no)])
-
#undef rb_str_new
#undef rb_usascii_str_new
#undef rb_utf8_str_new
@@ -141,27 +143,7 @@ VALUE rb_cSymbol;
RSTRING(str)->len = (n); \
} while (0)
-static inline bool
-str_encindex_fastpath(int encindex)
-{
- // The overwhelming majority of strings are in one of these 3 encodings.
- switch (encindex) {
- case ENCINDEX_ASCII_8BIT:
- case ENCINDEX_UTF_8:
- case ENCINDEX_US_ASCII:
- return true;
- default:
- return false;
- }
-}
-
-static inline bool
-str_enc_fastpath(VALUE str)
-{
- return str_encindex_fastpath(ENCODING_GET_INLINED(str));
-}
-
-#define TERM_LEN(str) (str_enc_fastpath(str) ? 1 : rb_enc_mbminlen(rb_enc_from_index(ENCODING_GET(str))))
+#define TERM_LEN(str) (rb_str_enc_fastpath(str) ? 1 : rb_enc_mbminlen(rb_enc_from_index(ENCODING_GET(str))))
#define TERM_FILL(ptr, termlen) do {\
char *const term_fill_ptr = (ptr);\
const int term_fill_len = (termlen);\
@@ -179,7 +161,7 @@ str_enc_fastpath(VALUE str)
if (str_embed_capa(str) < capacity + termlen) {\
char *const tmp = ALLOC_N(char, (size_t)(capacity) + (termlen));\
const long tlen = RSTRING_LEN(str);\
- memcpy(tmp, RSTRING_PTR(str), tlen);\
+ memcpy(tmp, RSTRING_PTR(str), str_embed_capa(str));\
RSTRING(str)->as.heap.ptr = tmp;\
RSTRING(str)->len = tlen;\
STR_SET_NOEMBED(str);\
@@ -200,6 +182,7 @@ str_enc_fastpath(VALUE str)
RUBY_ASSERT(RSTRING_PTR(str) <= RSTRING_PTR(shared_str) + RSTRING_LEN(shared_str)); \
RB_OBJ_WRITE((str), &RSTRING(str)->as.heap.aux.shared, (shared_str)); \
FL_SET((str), STR_SHARED); \
+ rb_gc_register_pinning_obj(str); \
FL_SET((shared_str), STR_SHARED_ROOT); \
if (RBASIC_CLASS((shared_str)) == 0) /* for CoW-friendliness */ \
FL_SET_RAW((shared_str), STR_BORROWED); \
@@ -212,15 +195,30 @@ str_enc_fastpath(VALUE str)
#define STR_ENC_GET(str) get_encoding(str)
+static inline bool
+zero_filled(const char *s, int n)
+{
+ for (; n > 0; --n) {
+ if (*s++) return false;
+ }
+ return true;
+}
+
#if !defined SHARABLE_MIDDLE_SUBSTRING
# define SHARABLE_MIDDLE_SUBSTRING 0
#endif
-#if !SHARABLE_MIDDLE_SUBSTRING
-#define SHARABLE_SUBSTRING_P(beg, len, end) ((beg) + (len) == (end))
+
+static inline bool
+SHARABLE_SUBSTRING_P(VALUE str, long beg, long len)
+{
+#if SHARABLE_MIDDLE_SUBSTRING
+ return true;
#else
-#define SHARABLE_SUBSTRING_P(beg, len, end) 1
+ long end = beg + len;
+ long source_len = RSTRING_LEN(str);
+ return end == source_len || zero_filled(RSTRING_PTR(str) + end, TERM_LEN(str));
#endif
-
+}
static inline long
str_embed_capa(VALUE str)
@@ -235,9 +233,11 @@ rb_str_reembeddable_p(VALUE str)
}
static inline size_t
-rb_str_embed_size(long capa)
+rb_str_embed_size(long capa, long termlen)
{
- return offsetof(struct RString, as.embed.ary) + capa;
+ size_t size = offsetof(struct RString, as.embed.ary) + capa + termlen;
+ if (size < sizeof(struct RString)) size = sizeof(struct RString);
+ return size;
}
size_t
@@ -245,28 +245,30 @@ rb_str_size_as_embedded(VALUE str)
{
size_t real_size;
if (STR_EMBED_P(str)) {
- real_size = rb_str_embed_size(RSTRING(str)->len) + TERM_LEN(str);
+ size_t capa = RSTRING(str)->len;
+ if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) capa += sizeof(st_index_t);
+
+ real_size = rb_str_embed_size(capa, TERM_LEN(str));
}
/* if the string is not currently embedded, but it can be embedded, how
* much space would it require */
else if (rb_str_reembeddable_p(str)) {
- real_size = rb_str_embed_size(RSTRING(str)->as.heap.aux.capa) + TERM_LEN(str);
+ size_t capa = RSTRING(str)->as.heap.aux.capa;
+ if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) capa += sizeof(st_index_t);
+
+ real_size = rb_str_embed_size(capa, TERM_LEN(str));
}
else {
real_size = sizeof(struct RString);
}
- if (FL_TEST_RAW(str, STR_PRECOMPUTED_HASH)) {
- real_size += sizeof(st_index_t);
- }
-
return real_size;
}
static inline bool
STR_EMBEDDABLE_P(long len, long termlen)
{
- return rb_gc_size_allocatable_p(rb_str_embed_size(len + termlen));
+ return rb_gc_size_allocatable_p(rb_str_embed_size(len, termlen));
}
static VALUE str_replace_shared_without_enc(VALUE str2, VALUE str);
@@ -303,7 +305,9 @@ rb_str_make_embedded(VALUE str)
RUBY_ASSERT(rb_str_reembeddable_p(str));
RUBY_ASSERT(!STR_EMBED_P(str));
+ int termlen = TERM_LEN(str);
char *buf = RSTRING(str)->as.heap.ptr;
+ long old_capa = RSTRING(str)->as.heap.aux.capa + termlen;
long len = RSTRING(str)->len;
STR_SET_EMBED(str);
@@ -311,10 +315,10 @@ rb_str_make_embedded(VALUE str)
if (len > 0) {
memcpy(RSTRING_PTR(str), buf, len);
- ruby_xfree(buf);
+ SIZED_FREE_N(buf, old_capa);
}
- TERM_FILL(RSTRING(str)->as.embed.ary + len, TERM_LEN(str));
+ TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
}
void
@@ -353,8 +357,6 @@ mustnot_wchar(VALUE str)
}
}
-static int fstring_cmp(VALUE a, VALUE b);
-
static VALUE register_fstring(VALUE str, bool copy, bool force_precompute_hash);
#if SIZEOF_LONG == SIZEOF_VOIDP
@@ -362,32 +364,11 @@ static VALUE register_fstring(VALUE str, bool copy, bool force_precompute_hash);
#else
#endif
-#ifdef PRECOMPUTED_FAKESTR_HASH
-static st_index_t
-fstring_hash(VALUE str)
+static inline bool
+BARE_STRING_P(VALUE str)
{
- st_index_t h;
- if (FL_TEST_RAW(str, STR_FAKESTR)) {
- // register_fstring precomputes the hash and stores it in capa for fake strings
- h = (st_index_t)RSTRING(str)->as.heap.aux.capa;
- }
- else {
- h = rb_str_hash(str);
- }
- // rb_str_hash doesn't include the encoding for ascii only strings, so
- // we add it to avoid common collisions between `:sym.name` (ASCII) and `"sym"` (UTF-8)
- return rb_hash_end(rb_hash_uint32(h, (uint32_t)ENCODING_GET_INLINED(str)));
+ return RBASIC_CLASS(str) == rb_cString && !rb_obj_shape_has_ivars(str);
}
-#else
-#define fstring_hash rb_str_hash
-#endif
-
-const struct st_hash_type rb_fstring_hash_type = {
- fstring_cmp,
- fstring_hash,
-};
-
-#define BARE_STRING_P(str) (!FL_ANY_RAW(str, FL_EXIVAR) && RBASIC_CLASS(str) == rb_cString)
static inline st_index_t
str_do_hash(VALUE str)
@@ -419,93 +400,6 @@ str_store_precomputed_hash(VALUE str, st_index_t hash)
return str;
}
-struct fstr_update_arg {
- VALUE fstr;
- bool copy;
- bool force_precompute_hash;
-};
-
-static int
-fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int existing)
-{
- struct fstr_update_arg *arg = (struct fstr_update_arg *)data;
- VALUE str = (VALUE)*key;
-
- if (existing) {
- /* because of lazy sweep, str may be unmarked already and swept
- * at next time */
-
- if (rb_objspace_garbage_object_p(str)) {
- arg->fstr = Qundef;
- // When RSTRING_FSTR strings are swept, they call `st_delete`.
- // To avoid a race condition if an equivalent string was inserted
- // we must remove the flag immediately.
- FL_UNSET_RAW(str, RSTRING_FSTR);
- return ST_DELETE;
- }
-
- arg->fstr = str;
- return ST_STOP;
- }
- else {
- // Unless the string is empty or binary, its coderange has been precomputed.
- int coderange = ENC_CODERANGE(str);
-
- if (FL_TEST_RAW(str, STR_FAKESTR)) {
- if (arg->copy) {
- VALUE new_str;
- long len = RSTRING_LEN(str);
- long capa = len + sizeof(st_index_t);
- int term_len = TERM_LEN(str);
-
- if (arg->force_precompute_hash && STR_EMBEDDABLE_P(capa, term_len)) {
- new_str = str_alloc_embed(rb_cString, capa + term_len);
- memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str), len);
- STR_SET_LEN(new_str, RSTRING_LEN(str));
- TERM_FILL(RSTRING_END(new_str), TERM_LEN(str));
- rb_enc_copy(new_str, str);
- str_store_precomputed_hash(new_str, str_do_hash(str));
- }
- else {
- new_str = str_new(rb_cString, RSTRING(str)->as.heap.ptr, RSTRING(str)->len);
- rb_enc_copy(new_str, str);
-#ifdef PRECOMPUTED_FAKESTR_HASH
- if (rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len + sizeof(st_index_t)) {
- str_store_precomputed_hash(new_str, (st_index_t)RSTRING(str)->as.heap.aux.capa);
- }
-#endif
- }
- str = new_str;
- }
- else {
- str = str_new_static(rb_cString, RSTRING(str)->as.heap.ptr,
- RSTRING(str)->len,
- ENCODING_GET(str));
- }
- OBJ_FREEZE(str);
- }
- else {
- if (!OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
- str = str_new_frozen(rb_cString, str);
- }
- if (STR_SHARED_P(str)) { /* str should not be shared */
- /* shared substring */
- str_make_independent(str);
- RUBY_ASSERT(OBJ_FROZEN(str));
- }
- if (!BARE_STRING_P(str)) {
- str = str_new_frozen(rb_cString, str);
- }
- }
-
- ENC_CODERANGE_SET(str, coderange);
- RBASIC(str)->flags |= RSTRING_FSTR;
-
- *key = *value = arg->fstr = str;
- return ST_CONTINUE;
- }
-}
-
VALUE
rb_fstring(VALUE str)
{
@@ -543,10 +437,138 @@ rb_fstring(VALUE str)
return fstr;
}
+static VALUE fstring_table_obj;
+
+static VALUE
+fstring_concurrent_set_hash(VALUE str)
+{
+#ifdef PRECOMPUTED_FAKESTR_HASH
+ st_index_t h;
+ if (FL_TEST_RAW(str, STR_FAKESTR)) {
+ // register_fstring precomputes the hash and stores it in capa for fake strings
+ h = (st_index_t)RSTRING(str)->as.heap.aux.capa;
+ }
+ else {
+ h = rb_str_hash(str);
+ }
+ // rb_str_hash doesn't include the encoding for ascii only strings, so
+ // we add it to avoid common collisions between `:sym.name` (ASCII) and `"sym"` (UTF-8)
+ return (VALUE)rb_hash_end(rb_hash_uint32(h, (uint32_t)ENCODING_GET_INLINED(str)));
+#else
+ return (VALUE)rb_str_hash(str);
+#endif
+}
+
+static bool
+fstring_concurrent_set_cmp(VALUE a, VALUE b)
+{
+ long alen, blen;
+ const char *aptr, *bptr;
+
+ RUBY_ASSERT(RB_TYPE_P(a, T_STRING));
+ RUBY_ASSERT(RB_TYPE_P(b, T_STRING));
+
+ RSTRING_GETMEM(a, aptr, alen);
+ RSTRING_GETMEM(b, bptr, blen);
+ return (alen == blen &&
+ ENCODING_GET(a) == ENCODING_GET(b) &&
+ memcmp(aptr, bptr, alen) == 0);
+}
+
+struct fstr_create_arg {
+ bool copy;
+ bool force_precompute_hash;
+};
+
+static VALUE
+fstring_concurrent_set_create(VALUE str, void *data)
+{
+ struct fstr_create_arg *arg = data;
+
+ // Unless the string is empty or binary, its coderange has been precomputed.
+ int coderange = ENC_CODERANGE(str);
+
+ if (FL_TEST_RAW(str, STR_FAKESTR)) {
+ if (arg->copy) {
+ VALUE new_str;
+ long len = RSTRING_LEN(str);
+ long capa = len + sizeof(st_index_t);
+ int term_len = TERM_LEN(str);
+
+ if (arg->force_precompute_hash && STR_EMBEDDABLE_P(capa, term_len)) {
+ new_str = str_alloc_embed(rb_cString, capa + term_len);
+ memcpy(RSTRING_PTR(new_str), RSTRING_PTR(str), len);
+ STR_SET_LEN(new_str, RSTRING_LEN(str));
+ TERM_FILL(RSTRING_END(new_str), TERM_LEN(str));
+ rb_enc_copy(new_str, str);
+ str_store_precomputed_hash(new_str, str_do_hash(str));
+ }
+ else {
+ new_str = str_new(rb_cString, RSTRING(str)->as.heap.ptr, RSTRING(str)->len);
+ rb_enc_copy(new_str, str);
+#ifdef PRECOMPUTED_FAKESTR_HASH
+ if (rb_str_capacity(new_str) >= RSTRING_LEN(str) + term_len + sizeof(st_index_t)) {
+ str_store_precomputed_hash(new_str, (st_index_t)RSTRING(str)->as.heap.aux.capa);
+ }
+#endif
+ }
+ str = new_str;
+ }
+ else {
+ str = str_new_static(rb_cString, RSTRING(str)->as.heap.ptr,
+ RSTRING(str)->len,
+ ENCODING_GET(str));
+ }
+ OBJ_FREEZE(str);
+ }
+ else {
+ if (!OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
+ str = str_new_frozen(rb_cString, str);
+ }
+ if (STR_SHARED_P(str)) { /* str should not be shared */
+ /* shared substring */
+ str_make_independent(str);
+ RUBY_ASSERT(OBJ_FROZEN(str));
+ }
+ if (!BARE_STRING_P(str)) {
+ str = str_new_frozen(rb_cString, str);
+ }
+ }
+
+ ENC_CODERANGE_SET(str, coderange);
+ RBASIC(str)->flags |= RSTRING_FSTR;
+ if (!RB_OBJ_SHAREABLE_P(str)) {
+ RB_OBJ_SET_SHAREABLE(str);
+ }
+ RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
+ RUBY_ASSERT(RB_TYPE_P(str, T_STRING));
+ RUBY_ASSERT(OBJ_FROZEN(str));
+ RUBY_ASSERT(!FL_TEST_RAW(str, STR_FAKESTR));
+ RUBY_ASSERT(!rb_obj_shape_has_ivars(str));
+ RUBY_ASSERT(RBASIC_CLASS(str) == rb_cString);
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(str));
+
+ return str;
+}
+
+static const struct rb_concurrent_set_funcs fstring_concurrent_set_funcs = {
+ .hash = fstring_concurrent_set_hash,
+ .cmp = fstring_concurrent_set_cmp,
+ .create = fstring_concurrent_set_create,
+ .free = NULL,
+};
+
+void
+Init_fstring_table(void)
+{
+ fstring_table_obj = rb_concurrent_set_new(&fstring_concurrent_set_funcs, 8192);
+ rb_gc_register_address(&fstring_table_obj);
+}
+
static VALUE
register_fstring(VALUE str, bool copy, bool force_precompute_hash)
{
- struct fstr_update_arg args = {
+ struct fstr_create_arg args = {
.copy = copy,
.force_precompute_hash = force_precompute_hash
};
@@ -559,28 +581,56 @@ register_fstring(VALUE str, bool copy, bool force_precompute_hash)
}
#endif
- RB_VM_LOCK_ENTER();
- {
- st_table *frozen_strings = rb_vm_fstring_table();
- do {
- args.fstr = str;
- st_update(frozen_strings, (st_data_t)str, fstr_update_callback, (st_data_t)&args);
- } while (UNDEF_P(args.fstr));
- }
- RB_VM_LOCK_LEAVE();
+ VALUE result = rb_concurrent_set_find_or_insert(&fstring_table_obj, str, &args);
- RUBY_ASSERT(OBJ_FROZEN(args.fstr));
- RUBY_ASSERT(!FL_TEST_RAW(args.fstr, STR_FAKESTR));
- RUBY_ASSERT(!FL_TEST_RAW(args.fstr, FL_EXIVAR));
- RUBY_ASSERT(RBASIC_CLASS(args.fstr) == rb_cString);
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(result));
+ RUBY_ASSERT(RB_TYPE_P(result, T_STRING));
+ RUBY_ASSERT(OBJ_FROZEN(result));
+ RUBY_ASSERT(RB_OBJ_SHAREABLE_P(result));
+ RUBY_ASSERT((rb_gc_verify_shareable(result), 1));
+ RUBY_ASSERT(!FL_TEST_RAW(result, STR_FAKESTR));
+ RUBY_ASSERT(RBASIC_CLASS(result) == rb_cString);
- return args.fstr;
+ return result;
+}
+
+bool
+rb_obj_is_fstring_table(VALUE obj)
+{
+ ASSERT_vm_locking();
+
+ return obj == fstring_table_obj;
+}
+
+void
+rb_gc_free_fstring(VALUE obj)
+{
+ ASSERT_vm_locking_with_barrier();
+
+ RUBY_ASSERT(FL_TEST(obj, RSTRING_FSTR));
+ RUBY_ASSERT(OBJ_FROZEN(obj));
+ RUBY_ASSERT(!FL_TEST(obj, STR_SHARED));
+
+ rb_concurrent_set_delete_by_identity(fstring_table_obj, obj);
+
+ RB_DEBUG_COUNTER_INC(obj_str_fstr);
+
+ FL_UNSET(obj, RSTRING_FSTR);
+}
+
+void
+rb_fstring_foreach_with_replace(int (*callback)(VALUE *str, void *data), void *data)
+{
+ if (fstring_table_obj) {
+ rb_concurrent_set_foreach_with_replace(fstring_table_obj, callback, data);
+ }
}
static VALUE
setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx)
{
fake_str->basic.flags = T_STRING|RSTRING_NOEMBED|STR_NOFREE|STR_FAKESTR;
+ RBASIC_SET_SHAPE_ID((VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER);
if (!name) {
RUBY_ASSERT_ALWAYS(len == 0);
@@ -613,14 +663,14 @@ rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encod
VALUE
rb_fstring_new(const char *ptr, long len)
{
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
return register_fstring(setup_fake_str(&fake_str, ptr, len, ENCINDEX_US_ASCII), false, false);
}
VALUE
rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc)
{
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), false, false);
}
@@ -630,25 +680,6 @@ rb_fstring_cstr(const char *ptr)
return rb_fstring_new(ptr, strlen(ptr));
}
-static int
-fstring_set_class_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- RBASIC_SET_CLASS((VALUE)key, (VALUE)arg);
- return ST_CONTINUE;
-}
-
-static int
-fstring_cmp(VALUE a, VALUE b)
-{
- long alen, blen;
- const char *aptr, *bptr;
- RSTRING_GETMEM(a, aptr, alen);
- RSTRING_GETMEM(b, bptr, blen);
- return (alen != blen ||
- ENCODING_GET(a) != ENCODING_GET(b) ||
- memcmp(aptr, bptr, alen) != 0);
-}
-
static inline bool
single_byte_optimizable(VALUE str)
{
@@ -680,7 +711,11 @@ VALUE rb_fs;
static inline const char *
search_nonascii(const char *p, const char *e)
{
- const uintptr_t *s, *t;
+ const char *s, *t;
+
+ if (p < e && !ISASCII(*p)) {
+ return p;
+ }
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# if SIZEOF_UINTPTR_T == 8
@@ -724,17 +759,19 @@ search_nonascii(const char *p, const char *e)
#define aligned_ptr(value) \
__builtin_assume_aligned((value), sizeof(uintptr_t))
#else
-#define aligned_ptr(value) (uintptr_t *)(value)
+#define aligned_ptr(value) (value)
#endif
s = aligned_ptr(p);
- t = (uintptr_t *)(e - (SIZEOF_VOIDP-1));
+ t = (e - (SIZEOF_VOIDP-1));
#undef aligned_ptr
- for (;s < t; s++) {
- if (*s & NONASCII_MASK) {
+ for (;s < t; s += sizeof(uintptr_t)) {
+ uintptr_t word;
+ memcpy(&word, s, sizeof(word));
+ if (word & NONASCII_MASK) {
#ifdef WORDS_BIGENDIAN
- return (const char *)s + (nlz_intptr(*s&NONASCII_MASK)>>3);
+ return (const char *)s + (nlz_intptr(word&NONASCII_MASK)>>3);
#else
- return (const char *)s + (ntz_intptr(*s&NONASCII_MASK)>>3);
+ return (const char *)s + (ntz_intptr(word&NONASCII_MASK)>>3);
#endif
}
}
@@ -906,22 +943,31 @@ rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc)
}
int
+rbimpl_enc_str_coderange_scan(VALUE str)
+{
+ int cr = enc_coderange_scan(str, get_encoding(str));
+ ENC_CODERANGE_SET(str, cr);
+ return cr;
+}
+
+#undef rb_enc_str_coderange
+int
rb_enc_str_coderange(VALUE str)
{
int cr = ENC_CODERANGE(str);
if (cr == ENC_CODERANGE_UNKNOWN) {
- cr = enc_coderange_scan(str, get_encoding(str));
- ENC_CODERANGE_SET(str, cr);
+ cr = rbimpl_enc_str_coderange_scan(str);
}
return cr;
}
+#define rb_enc_str_coderange rb_enc_str_coderange_inline
static inline bool
rb_enc_str_asciicompat(VALUE str)
{
int encindex = ENCODING_GET_INLINED(str);
- return str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
+ return rb_str_encindex_fastpath(encindex) || rb_enc_asciicompat(rb_enc_get_from_index(encindex));
}
int
@@ -976,12 +1022,14 @@ must_not_null(const char *ptr)
static inline VALUE
str_alloc_embed(VALUE klass, size_t capa)
{
- size_t size = rb_str_embed_size(capa);
+ size_t size = rb_str_embed_size(capa, 0);
RUBY_ASSERT(size > 0);
RUBY_ASSERT(rb_gc_size_allocatable_p(size));
- NEWOBJ_OF(str, struct RString, klass,
- T_STRING | (RGENGC_WB_PROTECTED_STRING ? FL_WB_PROTECTED : 0), size, 0);
+ NEWOBJ_OF(str, struct RString, klass, T_STRING, size);
+
+ str->len = 0;
+ str->as.embed.ary[0] = 0;
return (VALUE)str;
}
@@ -989,8 +1037,11 @@ str_alloc_embed(VALUE klass, size_t capa)
static inline VALUE
str_alloc_heap(VALUE klass)
{
- NEWOBJ_OF(str, struct RString, klass,
- T_STRING | STR_NOEMBED | (RGENGC_WB_PROTECTED_STRING ? FL_WB_PROTECTED : 0), sizeof(struct RString), 0);
+ NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString));
+
+ str->len = 0;
+ str->as.heap.aux.capa = 0;
+ str->as.heap.ptr = NULL;
return (VALUE)str;
}
@@ -1043,6 +1094,9 @@ str_enc_new(VALUE klass, const char *ptr, long len, rb_encoding *enc)
if (ptr) {
memcpy(RSTRING_PTR(str), ptr, len);
}
+ else {
+ memset(RSTRING_PTR(str), 0, len);
+ }
STR_SET_LEN(str, len);
TERM_FILL(RSTRING_PTR(str) + len, termlen);
@@ -1433,7 +1487,7 @@ str_replace_shared_without_enc(VALUE str2, VALUE str)
}
char *ptr2 = STR_HEAP_PTR(str2);
if (ptr2 != ptr) {
- ruby_sized_xfree(ptr2, STR_HEAP_SIZE(str2));
+ SIZED_FREE_N(ptr2, STR_HEAP_SIZE(str2));
}
}
FL_SET(str2, STR_NOEMBED);
@@ -1512,7 +1566,7 @@ rb_str_tmp_frozen_no_embed_acquire(VALUE orig)
* allocated. If the string is shared then the shared root must be
* embedded, so we want to create a copy. If the string is a shared root
* then it must be embedded, so we want to create a copy. */
- if (STR_EMBED_P(orig) || FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT)) {
+ if (STR_EMBED_P(orig) || FL_TEST_RAW(orig, STR_SHARED | STR_SHARED_ROOT | RSTRING_FSTR)) {
RSTRING(str)->as.heap.ptr = rb_xmalloc_mul_add_mul(sizeof(char), capa, sizeof(char), TERM_LEN(orig));
memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), capa);
}
@@ -1523,10 +1577,14 @@ rb_str_tmp_frozen_no_embed_acquire(VALUE orig)
RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
RBASIC(orig)->flags &= ~STR_NOFREE;
STR_SET_SHARED(orig, str);
+ if (RB_OBJ_SHAREABLE_P(orig)) {
+ RB_OBJ_SET_SHAREABLE(str);
+ RUBY_ASSERT((rb_gc_verify_shareable(str), 1));
+ }
}
RSTRING(str)->len = RSTRING(orig)->len;
- RSTRING(str)->as.heap.aux.capa = capa;
+ RSTRING(str)->as.heap.aux.capa = capa + (TERM_LEN(orig) - TERM_LEN(str));
return str;
}
@@ -1540,8 +1598,8 @@ rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
if (STR_EMBED_P(tmp)) {
RUBY_ASSERT(OBJ_FROZEN_RAW(tmp));
}
- else if (FL_TEST_RAW(orig, STR_SHARED) &&
- !FL_TEST_RAW(orig, STR_TMPLOCK|RUBY_FL_FREEZE)) {
+ else if (FL_TEST_RAW(orig, STR_SHARED | STR_TMPLOCK) == STR_TMPLOCK &&
+ !OBJ_FROZEN_RAW(orig)) {
VALUE shared = RSTRING(orig)->as.heap.aux.shared;
if (shared == tmp && !FL_TEST_RAW(tmp, STR_BORROWED)) {
@@ -1572,6 +1630,7 @@ heap_str_make_shared(VALUE klass, VALUE orig)
{
RUBY_ASSERT(!STR_EMBED_P(orig));
RUBY_ASSERT(!STR_SHARED_P(orig));
+ RUBY_ASSERT(!RB_OBJ_SHAREABLE_P(orig));
VALUE str = str_alloc_heap(klass);
STR_SET_LEN(str, RSTRING_LEN(orig));
@@ -1581,7 +1640,7 @@ heap_str_make_shared(VALUE klass, VALUE orig)
RBASIC(orig)->flags &= ~STR_NOFREE;
STR_SET_SHARED(orig, str);
if (klass == 0)
- FL_UNSET_RAW(str, STR_BORROWED);
+ FL_UNSET_RAW(str, STR_BORROWED);
return str;
}
@@ -1631,7 +1690,12 @@ str_new_frozen_buffer(VALUE klass, VALUE orig, int copy_encoding)
TERM_FILL(RSTRING_END(str), TERM_LEN(orig));
}
else {
- str = heap_str_make_shared(klass, orig);
+ if (RB_OBJ_SHAREABLE_P(orig)) {
+ str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig));
+ }
+ else {
+ str = heap_str_make_shared(klass, orig);
+ }
}
}
@@ -1702,7 +1766,7 @@ rb_str_free(VALUE str)
}
else {
RB_DEBUG_COUNTER_INC(obj_str_ptr);
- ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
+ SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
}
}
@@ -1833,12 +1897,13 @@ str_replace(VALUE str, VALUE str2)
static inline VALUE
ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t capa)
{
- size_t size = rb_str_embed_size(capa);
+ size_t size = rb_str_embed_size(capa, 0);
RUBY_ASSERT(size > 0);
RUBY_ASSERT(rb_gc_size_allocatable_p(size));
- NEWOBJ_OF(str, struct RString, klass,
- T_STRING | (RGENGC_WB_PROTECTED_STRING ? FL_WB_PROTECTED : 0), size, ec);
+ EC_NEWOBJ_OF(str, struct RString, klass, T_STRING, size, ec);
+
+ str->len = 0;
return (VALUE)str;
}
@@ -1846,8 +1911,10 @@ ec_str_alloc_embed(struct rb_execution_context_struct *ec, VALUE klass, size_t c
static inline VALUE
ec_str_alloc_heap(struct rb_execution_context_struct *ec, VALUE klass)
{
- NEWOBJ_OF(str, struct RString, klass,
- T_STRING | STR_NOEMBED | (RGENGC_WB_PROTECTED_STRING ? FL_WB_PROTECTED : 0), sizeof(struct RString), ec);
+ EC_NEWOBJ_OF(str, struct RString, klass, T_STRING | STR_NOEMBED, sizeof(struct RString), ec);
+
+ str->as.heap.aux.capa = 0;
+ str->as.heap.ptr = NULL;
return (VALUE)str;
}
@@ -1874,8 +1941,8 @@ str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup)
long len = RSTRING_LEN(str);
RUBY_ASSERT(STR_EMBED_P(dup));
- RUBY_ASSERT(str_embed_capa(dup) >= len + 1);
- MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + 1);
+ RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str));
+ MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str));
STR_SET_LEN(dup, RSTRING_LEN(str));
return str_duplicate_setup_encoding(str, dup, flags);
}
@@ -1888,7 +1955,7 @@ str_duplicate_setup_heap(VALUE klass, VALUE str, VALUE dup)
if (FL_TEST_RAW(str, STR_SHARED)) {
root = RSTRING(str)->as.heap.aux.shared;
}
- else if (UNLIKELY(!(flags & FL_FREEZE))) {
+ else if (UNLIKELY(!OBJ_FROZEN_RAW(str))) {
root = str = str_new_frozen(klass, str);
flags = FL_TEST_RAW(str, flag_mask);
}
@@ -1896,8 +1963,8 @@ str_duplicate_setup_heap(VALUE klass, VALUE str, VALUE dup)
RUBY_ASSERT(RB_OBJ_FROZEN_RAW(root));
RSTRING(dup)->as.heap.ptr = RSTRING_PTR(str);
- FL_SET(root, STR_SHARED_ROOT);
- RB_OBJ_WRITE(dup, &RSTRING(dup)->as.heap.aux.shared, root);
+ FL_SET_RAW(dup, RSTRING_NOEMBED);
+ STR_SET_SHARED(dup, root);
flags |= RSTRING_NOEMBED | STR_SHARED;
STR_SET_LEN(dup, RSTRING_LEN(str));
@@ -1940,7 +2007,7 @@ VALUE
rb_str_dup_m(VALUE str)
{
if (LIKELY(BARE_STRING_P(str))) {
- return str_duplicate(rb_obj_class(str), str);
+ return str_duplicate(rb_cString, str);
}
else {
return rb_obj_dup(str);
@@ -1985,9 +2052,14 @@ rb_str_with_debug_created_info(VALUE str, VALUE path, int line)
}
/*
+ * The documentation block below uses an include (instead of inline text)
+ * because the included text has non-ASCII characters (which are not allowed in a C file).
+ */
+
+/*
*
* call-seq:
- * String.new(string = '', **opts) -> new_string
+ * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string
*
* :include: doc/string/new.rdoc
*
@@ -2229,26 +2301,22 @@ enc_strlen(const char *p, const char *e, rb_encoding *enc, int cr)
c = 0;
if (ENC_CODERANGE_CLEAN_P(cr)) {
while (p < e) {
- if (ISASCII(*p)) {
- q = search_nonascii(p, e);
- if (!q)
- return c + (e - p);
- c += q - p;
- p = q;
- }
+ q = search_nonascii(p, e);
+ if (!q)
+ return c + (e - p);
+ c += q - p;
+ p = q;
p += rb_enc_fast_mbclen(p, e, enc);
c++;
}
}
else {
while (p < e) {
- if (ISASCII(*p)) {
- q = search_nonascii(p, e);
- if (!q)
- return c + (e - p);
- c += q - p;
- p = q;
- }
+ q = search_nonascii(p, e);
+ if (!q)
+ return c + (e - p);
+ c += q - p;
+ p = q;
p += rb_enc_mbclen(p, e, enc);
c++;
}
@@ -2286,15 +2354,13 @@ rb_enc_strlen_cr(const char *p, const char *e, rb_encoding *enc, int *cr)
else if (rb_enc_asciicompat(enc)) {
c = 0;
while (p < e) {
- if (ISASCII(*p)) {
- q = search_nonascii(p, e);
- if (!q) {
- if (!*cr) *cr = ENC_CODERANGE_7BIT;
- return c + (e - p);
- }
- c += q - p;
- p = q;
+ q = search_nonascii(p, e);
+ if (!q) {
+ if (!*cr) *cr = ENC_CODERANGE_7BIT;
+ return c + (e - p);
}
+ c += q - p;
+ p = q;
ret = rb_enc_precise_mbclen(p, e, enc);
if (MBCLEN_CHARFOUND_P(ret)) {
*cr |= ENC_CODERANGE_VALID;
@@ -2389,12 +2455,13 @@ rb_str_bytesize(VALUE str)
* call-seq:
* empty? -> true or false
*
- * Returns +true+ if the length of +self+ is zero, +false+ otherwise:
+ * Returns whether the length of +self+ is zero:
*
- * "hello".empty? # => false
- * " ".empty? # => false
- * "".empty? # => true
+ * 'hello'.empty? # => false
+ * ' '.empty? # => false
+ * ''.empty? # => true
*
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -2405,12 +2472,13 @@ rb_str_empty(VALUE str)
/*
* call-seq:
- * string + other_string -> new_string
+ * self + other_string -> new_string
*
- * Returns a new +String+ containing +other_string+ concatenated to +self+:
+ * Returns a new string containing +other_string+ concatenated to +self+:
*
- * "Hello from " + self.to_s # => "Hello from main"
+ * 'Hello from ' + self.to_s # => "Hello from main"
*
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
VALUE
@@ -2476,13 +2544,14 @@ rb_str_opt_plus(VALUE str1, VALUE str2)
/*
* call-seq:
- * string * integer -> new_string
+ * self * n -> new_string
*
- * Returns a new +String+ containing +integer+ copies of +self+:
+ * Returns a new string containing +n+ copies of +self+:
*
- * "Ho! " * 3 # => "Ho! Ho! Ho! "
- * "Ho! " * 0 # => ""
+ * 'Ho!' * 3 # => "Ho!Ho!Ho!"
+ * 'No!' * 0 # => ""
*
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
VALUE
@@ -2545,20 +2614,22 @@ rb_str_times(VALUE str, VALUE times)
/*
* call-seq:
- * string % object -> new_string
+ * self % object -> new_string
*
- * Returns the result of formatting +object+ into the format specification +self+
- * (see Kernel#sprintf for formatting details):
+ * Returns the result of formatting +object+ into the format specifications
+ * contained in +self+
+ * (see {Format Specifications}[rdoc-ref:language/format_specifications.rdoc]):
*
- * "%05d" % 123 # => "00123"
+ * '%05d' % 123 # => "00123"
*
- * If +self+ contains multiple substitutions, +object+ must be
- * an Array or Hash containing the values to be substituted:
+ * If +self+ contains multiple format specifications,
+ * +object+ must be an array or hash containing the objects to be formatted:
*
- * "%-5s: %016x" % [ "ID", self.object_id ] # => "ID : 00002b054ec93168"
- * "foo = %{foo}" % {foo: 'bar'} # => "foo = bar"
- * "foo = %{foo}, baz = %{baz}" % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
+ * '%-5s: %016x' % [ 'ID', self.object_id ] # => "ID : 00002b054ec93168"
+ * 'foo = %{foo}' % {foo: 'bar'} # => "foo = bar"
+ * 'foo = %{foo}, baz = %{baz}' % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
*
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@@ -2567,7 +2638,9 @@ rb_str_format_m(VALUE str, VALUE arg)
VALUE tmp = rb_check_array_type(arg);
if (!NIL_P(tmp)) {
- return rb_str_format(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str);
+ VALUE result = rb_str_format(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str);
+ RB_GC_GUARD(tmp);
+ return result;
}
return rb_str_format(1, &arg, str);
}
@@ -2586,6 +2659,8 @@ rb_check_lockedtmp(VALUE str)
static inline void
str_modifiable(VALUE str)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
if (RB_UNLIKELY(FL_ANY_RAW(str, STR_UNMODIFIABLE_MASK))) {
if (CHILLED_STRING_P(str)) {
CHILLED_STRING_MUTATED(str);
@@ -2612,6 +2687,8 @@ str_dependent_p(VALUE str)
static inline int
str_independent(VALUE str)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
if (RB_UNLIKELY(FL_ANY_RAW(str, STR_DEPENDANT_MASK))) {
str_modifiable(str);
return !str_dependent_p(str);
@@ -2622,6 +2699,8 @@ str_independent(VALUE str)
static void
str_make_independent_expand(VALUE str, long len, long expand, const int termlen)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
char *ptr;
char *oldptr;
long capa = len + expand;
@@ -2643,7 +2722,7 @@ str_make_independent_expand(VALUE str, long len, long expand, const int termlen)
memcpy(ptr, oldptr, len);
}
if (FL_TEST_RAW(str, STR_NOEMBED|STR_NOFREE|STR_SHARED) == STR_NOEMBED) {
- xfree(oldptr);
+ SIZED_FREE_N(oldptr, STR_HEAP_SIZE(str));
}
STR_SET_NOEMBED(str);
FL_UNSET(str, STR_SHARED|STR_NOFREE);
@@ -2664,6 +2743,8 @@ rb_str_modify(VALUE str)
void
rb_str_modify_expand(VALUE str, long expand)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
int termlen = TERM_LEN(str);
long len = RSTRING_LEN(str);
@@ -2699,7 +2780,7 @@ str_discard(VALUE str)
{
str_modifiable(str);
if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
- ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
+ SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
RSTRING(str)->as.heap.ptr = 0;
STR_SET_LEN(str, 0);
}
@@ -2714,7 +2795,7 @@ rb_must_asciicompat(VALUE str)
rb_raise(rb_eTypeError, "not encoding capable object");
}
- if (RB_LIKELY(str_encindex_fastpath(encindex))) {
+ if (RB_LIKELY(rb_str_encindex_fastpath(encindex))) {
return;
}
@@ -2727,6 +2808,8 @@ rb_must_asciicompat(VALUE str)
VALUE
rb_string_value(volatile VALUE *ptr)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
VALUE s = *ptr;
if (!RB_TYPE_P(s, T_STRING)) {
s = rb_str_to_str(s);
@@ -2742,15 +2825,6 @@ rb_string_value_ptr(volatile VALUE *ptr)
return RSTRING_PTR(str);
}
-static int
-zero_filled(const char *s, int n)
-{
- for (; n > 0; --n) {
- if (*s++) return 0;
- }
- return 1;
-}
-
static const char *
str_null_char(const char *s, long len, const int minlen, rb_encoding *enc)
{
@@ -2813,16 +2887,21 @@ str_null_check(VALUE str, int *w)
{
char *s = RSTRING_PTR(str);
long len = RSTRING_LEN(str);
- rb_encoding *enc = rb_enc_get(str);
- const int minlen = rb_enc_mbminlen(enc);
+ int minlen = 1;
+
+ if (RB_UNLIKELY(!rb_str_enc_fastpath(str))) {
+ rb_encoding *enc = rb_str_enc_get(str);
+ minlen = rb_enc_mbminlen(enc);
- if (minlen > 1) {
- *w = 1;
- if (str_null_char(s, len, minlen, enc)) {
- return NULL;
+ if (minlen > 1) {
+ *w = 1;
+ if (str_null_char(s, len, minlen, enc)) {
+ return NULL;
+ }
+ return str_fill_term(str, s, len, minlen);
}
- return str_fill_term(str, s, len, minlen);
}
+
*w = 0;
if (!s || memchr(s, 0, len)) {
return NULL;
@@ -2833,6 +2912,34 @@ str_null_check(VALUE str, int *w)
return s;
}
+const char *
+rb_str_null_check(VALUE str)
+{
+ RUBY_ASSERT(RB_TYPE_P(str, T_STRING));
+
+ char *s;
+ long len;
+ RSTRING_GETMEM(str, s, len);
+
+ if (RB_LIKELY(rb_str_enc_fastpath(str))) {
+ if (!s || memchr(s, 0, len)) {
+ rb_raise(rb_eArgError, "string contains null byte");
+ }
+ }
+ else {
+ int w;
+ const char *s = str_null_check(str, &w);
+ if (!s) {
+ if (w) {
+ rb_raise(rb_eArgError, "string contains null char");
+ }
+ rb_raise(rb_eArgError, "string contains null byte");
+ }
+ }
+
+ return s;
+}
+
char *
rb_str_to_cstr(VALUE str)
{
@@ -2874,14 +2981,16 @@ rb_check_string_type(VALUE str)
* call-seq:
* String.try_convert(object) -> object, new_string, or nil
*
- * If +object+ is a +String+ object, returns +object+.
+ * Attempts to convert the given +object+ to a string.
+ *
+ * If +object+ is already a string, returns +object+, unmodified.
*
* Otherwise if +object+ responds to <tt>:to_str</tt>,
* calls <tt>object.to_str</tt> and returns the result.
*
* Returns +nil+ if +object+ does not respond to <tt>:to_str</tt>.
*
- * Raises an exception unless <tt>object.to_str</tt> returns a +String+ object.
+ * Raises an exception unless <tt>object.to_str</tt> returns a string.
*/
static VALUE
rb_str_s_try_convert(VALUE dummy, VALUE str)
@@ -2909,16 +3018,14 @@ str_nth_len(const char *p, const char *e, long *nthp, rb_encoding *enc)
*nthp = nth;
return (char *)e;
}
- if (ISASCII(*p)) {
- p2 = search_nonascii(p, e2);
- if (!p2) {
- nth -= e2 - p;
- *nthp = nth;
- return (char *)e2;
- }
- nth -= p2 - p;
- p = p2;
+ p2 = search_nonascii(p, e2);
+ if (!p2) {
+ nth -= e2 - p;
+ *nthp = nth;
+ return (char *)e2;
}
+ nth -= p2 - p;
+ p = p2;
n = rb_enc_mbclen(p, e, enc);
p += n;
nth--;
@@ -3035,8 +3142,11 @@ str_subseq(VALUE str, long beg, long len)
RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
const int termlen = TERM_LEN(str);
- if (!SHARABLE_SUBSTRING_P(beg, len, RSTRING_LEN(str))) {
- str2 = rb_str_new(RSTRING_PTR(str) + beg, len);
+ if (!SHARABLE_SUBSTRING_P(str, beg, len)) {
+ str2 = rb_enc_str_new(RSTRING_PTR(str) + beg, len, rb_str_enc_get(str));
+ if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
+ ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT);
+ }
RB_GC_GUARD(str);
return str2;
}
@@ -3049,12 +3159,19 @@ str_subseq(VALUE str, long beg, long len)
TERM_FILL(ptr2+len, termlen);
STR_SET_LEN(str2, len);
+ if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
+ ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT);
+ }
+
RB_GC_GUARD(str);
}
else {
str_replace_shared(str2, str);
RUBY_ASSERT(!STR_EMBED_P(str2));
- ENC_CODERANGE_CLEAR(str2);
+ if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
+ ENC_CODERANGE_CLEAR(str2);
+ }
+
RSTRING(str2)->as.heap.ptr += beg;
if (RSTRING_LEN(str2) > len) {
STR_SET_LEN(str2, len);
@@ -3209,6 +3326,8 @@ rb_str_freeze(VALUE str)
* without warning issuance.
*
* Otherwise returns <tt>self.dup</tt>, which is not frozen.
+ *
+ * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
*/
static VALUE
str_uplus(VALUE str)
@@ -3223,24 +3342,37 @@ str_uplus(VALUE str)
/*
* call-seq:
- * -string -> frozen_string
- * dedup -> frozen_string
+ * -self -> frozen_string
+ *
+ * Returns a frozen string equal to +self+.
*
- * Returns a frozen, possibly pre-existing copy of the string.
+ * The returned string is +self+ if and only if all of the following are true:
*
- * The returned +String+ will be deduplicated as long as it does not have
- * any instance variables set on it and is not a String subclass.
+ * - +self+ is already frozen.
+ * - +self+ is an instance of \String (rather than of a subclass of \String)
+ * - +self+ has no instance variables set on it.
*
- * Note that <tt>-string</tt> variant is more convenient for defining
- * constants:
+ * Otherwise, the returned string is a frozen copy of +self+.
*
- * FILENAME = -'config/database.yml'
+ * Returning +self+, when possible, saves duplicating +self+;
+ * see {Data deduplication}[https://en.wikipedia.org/wiki/Data_deduplication].
*
- * while +dedup+ is better suitable for using the method in chains
- * of calculations:
+ * It may also save duplicating other, already-existing, strings:
*
- * @url_list.concat(urls.map(&:dedup))
+ * s0 = 'foo'
+ * s1 = 'foo'
+ * s0.object_id == s1.object_id # => false
+ * (-s0).object_id == (-s1).object_id # => true
*
+ * Note that method #-@ is convenient for defining a constant:
+ *
+ * FileName = -'config/database.yml'
+ *
+ * While its alias #dedup is better suited for chaining:
+ *
+ * 'foo'.dedup.gsub!('o')
+ *
+ * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing].
*/
static VALUE
str_uminus(VALUE str)
@@ -3257,6 +3389,7 @@ RUBY_ALIAS_FUNCTION(rb_str_dup_frozen(VALUE str), rb_str_new_frozen, (str))
VALUE
rb_str_locktmp(VALUE str)
{
+ rb_check_frozen(str);
if (FL_TEST(str, STR_TMPLOCK)) {
rb_raise(rb_eRuntimeError, "temporal locking already locked string");
}
@@ -3267,6 +3400,7 @@ rb_str_locktmp(VALUE str)
VALUE
rb_str_unlocktmp(VALUE str)
{
+ rb_check_frozen(str);
if (!FL_TEST(str, STR_TMPLOCK)) {
rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
}
@@ -3284,6 +3418,8 @@ rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg)
void
rb_str_set_len(VALUE str, long len)
{
+ RUBY_ASSERT(ruby_thread_has_gvl_p());
+
long capa;
const int termlen = TERM_LEN(str);
@@ -3356,13 +3492,16 @@ rb_str_resize(VALUE str, long len)
str_make_independent_expand(str, slen, len - slen, termlen);
}
else if (str_embed_capa(str) >= len + termlen) {
+ capa = RSTRING(str)->as.heap.aux.capa;
char *ptr = STR_HEAP_PTR(str);
STR_SET_EMBED(str);
if (slen > len) slen = len;
if (slen > 0) MEMCPY(RSTRING(str)->as.embed.ary, ptr, char, slen);
TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen);
STR_SET_LEN(str, len);
- if (independent) ruby_xfree(ptr);
+ if (independent) {
+ SIZED_FREE_N(ptr, capa + termlen);
+ }
return str;
}
else if (!independent) {
@@ -3660,7 +3799,7 @@ rb_str_buf_append(VALUE str, VALUE str2)
{
int str2_cr = rb_enc_str_coderange(str2);
- if (str_enc_fastpath(str)) {
+ if (rb_str_enc_fastpath(str)) {
switch (str2_cr) {
case ENC_CODERANGE_7BIT:
// If RHS is 7bit we can do simple concatenation
@@ -3727,19 +3866,7 @@ rb_str_concat_literals(size_t num, const VALUE *strary)
* call-seq:
* concat(*objects) -> string
*
- * Concatenates each object in +objects+ to +self+ and returns +self+:
- *
- * s = 'foo'
- * s.concat('bar', 'baz') # => "foobarbaz"
- * s # => "foobarbaz"
- *
- * For each given object +object+ that is an Integer,
- * the value is considered a codepoint and converted to a character before concatenation:
- *
- * s = 'foo'
- * s.concat(32, 'bar', 32, 'baz') # => "foo bar baz"
- *
- * Related: String#<<, which takes a single argument.
+ * :include: doc/string/concat.rdoc
*/
static VALUE
rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
@@ -3764,25 +3891,27 @@ rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * append_as_bytes(*objects) -> string
+ * append_as_bytes(*objects) -> self
*
- * Concatenates each object in +objects+ into +self+ without any encoding
- * validation or conversion and returns +self+:
+ * Concatenates each object in +objects+ into +self+; returns +self+;
+ * performs no encoding validation or conversion:
*
* s = 'foo'
- * s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
- * s.valid_encoding? # => false
+ * s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82"
+ * s.valid_encoding? # => false
* s.append_as_bytes("\xAC 12")
- * s.valid_encoding? # => true
+ * s.valid_encoding? # => true
*
- * For each given object +object+ that is an Integer,
- * the value is considered a Byte. If the Integer is bigger
- * than one byte, only the lower byte is considered, similar to String#setbyte:
+ * When a given object is an integer,
+ * the value is considered an 8-bit byte;
+ * if the integer occupies more than one byte (i.e,. is greater than 255),
+ * appends only the low-order byte (similar to String#setbyte):
*
* s = ""
- * s.append_as_bytes(0, 257) # => "\u0000\u0001"
+ * s.append_as_bytes(0, 257) # => "\u0000\u0001"
+ * s.bytesize # => 2
*
- * Related: String#<<, String#concat, which do an encoding aware concatenation.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
VALUE
@@ -3887,7 +4016,7 @@ rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
clear_cr:
// If no fast path was hit, we clear the coderange.
- // append_as_bytes is predominently meant to be used in
+ // append_as_bytes is predominantly meant to be used in
// buffering situation, hence it's likely the coderange
// will never be scanned, so it's not worth spending time
// precomputing the coderange except for simple and common
@@ -3899,22 +4028,34 @@ rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * string << object -> string
+ * self << object -> self
+ *
+ * Appends a string representation of +object+ to +self+;
+ * returns +self+.
*
- * Concatenates +object+ to +self+ and returns +self+:
+ * If +object+ is a string, appends it to +self+:
*
* s = 'foo'
* s << 'bar' # => "foobar"
* s # => "foobar"
*
- * If +object+ is an Integer,
- * the value is considered a codepoint and converted to a character before concatenation:
+ * If +object+ is an integer,
+ * its value is considered a codepoint;
+ * converts the value to a character before concatenating:
*
* s = 'foo'
* s << 33 # => "foo!"
*
- * If that codepoint is not representable in the encoding of
- * _string_, RangeError is raised.
+ * Additionally, if the codepoint is in range <tt>0..0xff</tt>
+ * and the encoding of +self+ is Encoding::US_ASCII,
+ * changes the encoding to Encoding::ASCII_8BIT:
+ *
+ * s = 'foo'.encode(Encoding::US_ASCII)
+ * s.encoding # => #<Encoding:US-ASCII>
+ * s << 0xff # => "foo\xFF"
+ * s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
+ *
+ * Raises RangeError if that codepoint is not representable in the encoding of +self+:
*
* s = 'foo'
* s.encoding # => <Encoding:UTF-8>
@@ -3922,14 +4063,7 @@ rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
* s = 'foo'.encode(Encoding::EUC_JP)
* s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError)
*
- * If the encoding is US-ASCII and the codepoint is 0..0xff, _string_
- * is automatically promoted to ASCII-8BIT.
- *
- * s = 'foo'.encode(Encoding::US_ASCII)
- * s << 0xff
- * s.encoding # => #<Encoding:BINARY (ASCII-8BIT)>
- *
- * Related: String#concat, which takes multiple arguments.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
VALUE
rb_str_concat(VALUE str1, VALUE str2)
@@ -4012,15 +4146,14 @@ rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code)
/*
* call-seq:
- * prepend(*other_strings) -> string
+ * prepend(*other_strings) -> new_string
*
- * Prepends each string in +other_strings+ to +self+ and returns +self+:
+ * Prefixes to +self+ the concatenation of the given +other_strings+; returns +self+:
*
- * s = 'foo'
- * s.prepend('bar', 'baz') # => "barbazfoo"
- * s # => "barbazfoo"
+ * 'baz'.prepend('foo', 'bar') # => "foobarbaz"
+ *
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*
- * Related: String#concat.
*/
static VALUE
@@ -4074,10 +4207,8 @@ rb_str_hash_cmp(VALUE str1, VALUE str2)
* call-seq:
* hash -> integer
*
- * Returns the integer hash value for +self+.
- * The value is based on the length, content and encoding of +self+.
+ * :include: doc/string/hash.rdoc
*
- * Related: Object#hash.
*/
static VALUE
@@ -4142,22 +4273,29 @@ rb_str_cmp(VALUE str1, VALUE str2)
/*
* call-seq:
- * string == object -> true or false
- * string === object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +object+ has the same length and content;
- * as +self+; +false+ otherwise:
+ * Returns whether +other+ is equal to +self+.
+ *
+ * When +other+ is a string, returns whether +other+ has the same length and content as +self+:
*
* s = 'foo'
- * s == 'foo' # => true
+ * s == 'foo' # => true
* s == 'food' # => false
- * s == 'FOO' # => false
+ * s == 'FOO' # => false
*
* Returns +false+ if the two strings' encodings are not compatible:
+ *
* "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false
*
- * If +object+ is not an instance of +String+ but responds to +to_str+, then the
- * two strings are compared using <code>object.==</code>.
+ * When +other+ is not a string:
+ *
+ * - If +other+ responds to method <tt>to_str</tt>,
+ * <tt>other == self</tt> is called and its return value is returned.
+ * - If +other+ does not respond to <tt>to_str</tt>,
+ * +false+ is returned.
+ *
+ * Related: {Comparing}[rdoc-ref:String@Comparing].
*/
VALUE
@@ -4177,17 +4315,7 @@ rb_str_equal(VALUE str1, VALUE str2)
* call-seq:
* eql?(object) -> true or false
*
- * Returns +true+ if +object+ has the same length and content;
- * as +self+; +false+ otherwise:
- *
- * s = 'foo'
- * s.eql?('foo') # => true
- * s.eql?('food') # => false
- * s.eql?('FOO') # => false
- *
- * Returns +false+ if the two strings' encodings are not compatible:
- *
- * "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1).eql?("\u{c4 d6 dc}") # => false
+ * :include: doc/string/eql_p.rdoc
*
*/
@@ -4201,24 +4329,31 @@ rb_str_eql(VALUE str1, VALUE str2)
/*
* call-seq:
- * string <=> other_string -> -1, 0, 1, or nil
+ * self <=> other -> -1, 0, 1, or nil
*
- * Compares +self+ and +other_string+, returning:
+ * Compares +self+ and +other+,
+ * evaluating their _contents_, not their _lengths_.
*
- * - -1 if +other_string+ is larger.
- * - 0 if the two are equal.
- * - 1 if +other_string+ is smaller.
- * - +nil+ if the two are incomparable.
+ * Returns:
+ *
+ * - +-1+, if +self+ is smaller.
+ * - +0+, if the two are equal.
+ * - +1+, if +self+ is larger.
+ * - +nil+, if the two are incomparable.
*
* Examples:
*
- * 'foo' <=> 'foo' # => 0
- * 'foo' <=> 'food' # => -1
- * 'food' <=> 'foo' # => 1
- * 'FOO' <=> 'foo' # => -1
- * 'foo' <=> 'FOO' # => 1
- * 'foo' <=> 1 # => nil
+ * 'a' <=> 'b' # => -1
+ * 'a' <=> 'ab' # => -1
+ * 'a' <=> 'a' # => 0
+ * 'b' <=> 'a' # => 1
+ * 'ab' <=> 'a' # => 1
+ * 'a' <=> :a # => nil
+ *
+ * \Class \String includes module Comparable,
+ * each of whose methods uses String#<=> for comparison.
*
+ * Related: see {Comparing}[rdoc-ref:String@Comparing].
*/
static VALUE
@@ -4240,29 +4375,29 @@ static VALUE str_casecmp_p(VALUE str1, VALUE str2);
* call-seq:
* casecmp(other_string) -> -1, 0, 1, or nil
*
- * Compares <tt>self.downcase</tt> and <tt>other_string.downcase</tt>; returns:
+ * Ignoring case, compares +self+ and +other_string+; returns:
*
- * - -1 if <tt>other_string.downcase</tt> is larger.
+ * - -1 if <tt>self.downcase</tt> is smaller than <tt>other_string.downcase</tt>.
* - 0 if the two are equal.
- * - 1 if <tt>other_string.downcase</tt> is smaller.
+ * - 1 if <tt>self.downcase</tt> is larger than <tt>other_string.downcase</tt>.
* - +nil+ if the two are incomparable.
*
+ * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
+ *
* Examples:
*
- * 'foo'.casecmp('foo') # => 0
+ * 'foo'.casecmp('goo') # => -1
+ * 'goo'.casecmp('foo') # => 1
* 'foo'.casecmp('food') # => -1
* 'food'.casecmp('foo') # => 1
- * 'FOO'.casecmp('foo') # => 0
- * 'foo'.casecmp('FOO') # => 0
- * 'foo'.casecmp(1) # => nil
- *
- * See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#casecmp?.
+ * 'FOO'.casecmp('foo') # => 0
+ * 'foo'.casecmp('FOO') # => 0
+ * 'foo'.casecmp(1) # => nil
*
+ * Related: see {Comparing}[rdoc-ref:String@Comparing].
*/
-static VALUE
+VALUE
rb_str_casecmp(VALUE str1, VALUE str2)
{
VALUE s = rb_check_string_type(str2);
@@ -4324,9 +4459,9 @@ str_casecmp(VALUE str1, VALUE str2)
p2 += l2;
}
}
- if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) return INT2FIX(0);
- if (RSTRING_LEN(str1) > RSTRING_LEN(str2)) return INT2FIX(1);
- return INT2FIX(-1);
+ if (p1 == p1end && p2 == p2end) return INT2FIX(0);
+ if (p1 == p1end) return INT2FIX(-1);
+ return INT2FIX(1);
}
/*
@@ -4334,22 +4469,21 @@ str_casecmp(VALUE str1, VALUE str2)
* casecmp?(other_string) -> true, false, or nil
*
* Returns +true+ if +self+ and +other_string+ are equal after
- * Unicode case folding, otherwise +false+:
- *
- * 'foo'.casecmp?('foo') # => true
- * 'foo'.casecmp?('food') # => false
- * 'food'.casecmp?('foo') # => false
- * 'FOO'.casecmp?('foo') # => true
- * 'foo'.casecmp?('FOO') # => true
- *
- * Returns +nil+ if the two values are incomparable:
- *
- * 'foo'.casecmp?(1) # => nil
+ * Unicode case folding, +false+ if unequal, +nil+ if incomparable.
*
* See {Case Mapping}[rdoc-ref:case_mapping.rdoc].
*
- * Related: String#casecmp.
+ * Examples:
+ *
+ * 'foo'.casecmp?('goo') # => false
+ * 'goo'.casecmp?('foo') # => false
+ * 'foo'.casecmp?('food') # => false
+ * 'food'.casecmp?('foo') # => false
+ * 'FOO'.casecmp?('foo') # => true
+ * 'foo'.casecmp?('FOO') # => true
+ * 'foo'.casecmp?(1) # => nil
*
+ * Related: see {Comparing}[rdoc-ref:String@Comparing].
*/
static VALUE
@@ -4445,8 +4579,7 @@ rb_strseq_index(VALUE str, VALUE sub, long offset, int in_byte)
/*
* call-seq:
- * index(substring, offset = 0) -> integer or nil
- * index(regexp, offset = 0) -> integer or nil
+ * index(pattern, offset = 0) -> integer or nil
*
* :include: doc/string/index.rdoc
*
@@ -4480,8 +4613,7 @@ rb_str_index_m(int argc, VALUE *argv, VALUE str)
if (rb_reg_search(sub, str, pos, 0) >= 0) {
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
- pos = rb_str_sublen(str, BEG(0));
+ pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
return LONG2NUM(pos);
}
}
@@ -4516,43 +4648,69 @@ str_ensure_byte_pos(VALUE str, long pos)
/*
* call-seq:
- * byteindex(substring, offset = 0) -> integer or nil
- * byteindex(regexp, offset = 0) -> integer or nil
+ * byteindex(object, offset = 0) -> integer or nil
+ *
+ * Returns the 0-based integer index of a substring of +self+
+ * specified by +object+ (a string or Regexp) and +offset+,
+ * or +nil+ if there is no such substring;
+ * the returned index is the count of _bytes_ (not characters).
+ *
+ * When +object+ is a string,
+ * returns the index of the first found substring equal to +object+:
*
- * Returns the Integer byte-based index of the first occurrence of the given +substring+,
- * or +nil+ if none found:
+ * s = 'foo' # => "foo"
+ * s.size # => 3 # Three 1-byte characters.
+ * s.bytesize # => 3 # Three bytes.
+ * s.byteindex('f') # => 0
+ * s.byteindex('o') # => 1
+ * s.byteindex('oo') # => 1
+ * s.byteindex('ooo') # => nil
*
- * 'foo'.byteindex('f') # => 0
- * 'foo'.byteindex('o') # => 1
- * 'foo'.byteindex('oo') # => 1
- * 'foo'.byteindex('ooo') # => nil
+ * When +object+ is a Regexp,
+ * returns the index of the first found substring matching +object+;
+ * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
*
- * Returns the Integer byte-based index of the first match for the given Regexp +regexp+,
- * or +nil+ if none found:
+ * s = 'foo'
+ * s.byteindex(/f/) # => 0
+ * $~ # => #<MatchData "f">
+ * s.byteindex(/o/) # => 1
+ * s.byteindex(/oo/) # => 1
+ * s.byteindex(/ooo/) # => nil
+ * $~ # => nil
*
- * 'foo'.byteindex(/f/) # => 0
- * 'foo'.byteindex(/o/) # => 1
- * 'foo'.byteindex(/oo/) # => 1
- * 'foo'.byteindex(/ooo/) # => nil
+ * \Integer argument +offset+, if given, specifies the 0-based index
+ * of the byte where searching is to begin.
*
- * Integer argument +offset+, if given, specifies the byte-based position in the
- * string to begin the search:
+ * When +offset+ is non-negative,
+ * searching begins at byte position +offset+:
*
- * 'foo'.byteindex('o', 1) # => 1
- * 'foo'.byteindex('o', 2) # => 2
- * 'foo'.byteindex('o', 3) # => nil
+ * s = 'foo'
+ * s.byteindex('o', 1) # => 1
+ * s.byteindex('o', 2) # => 2
+ * s.byteindex('o', 3) # => nil
*
- * If +offset+ is negative, counts backward from the end of +self+:
+ * When +offset+ is negative, counts backward from the end of +self+:
*
- * 'foo'.byteindex('o', -1) # => 2
- * 'foo'.byteindex('o', -2) # => 1
- * 'foo'.byteindex('o', -3) # => 1
- * 'foo'.byteindex('o', -4) # => nil
+ * s = 'foo'
+ * s.byteindex('o', -1) # => 2
+ * s.byteindex('o', -2) # => 1
+ * s.byteindex('o', -3) # => 1
+ * s.byteindex('o', -4) # => nil
*
- * If +offset+ does not land on character (codepoint) boundary, +IndexError+ is
- * raised.
+ * Raises IndexError if the byte at +offset+ is not the first byte of a character:
*
- * Related: String#index, String#byterindex.
+ * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
+ * s.size # => 2 # Two 3-byte characters.
+ * s.bytesize # => 6 # Six bytes.
+ * s.byteindex("\uFFFF") # => 0
+ * s.byteindex("\uFFFF", 1) # Raises IndexError
+ * s.byteindex("\uFFFF", 2) # Raises IndexError
+ * s.byteindex("\uFFFF", 3) # => 3
+ * s.byteindex("\uFFFF", 4) # Raises IndexError
+ * s.byteindex("\uFFFF", 5) # Raises IndexError
+ * s.byteindex("\uFFFF", 6) # => nil
+ *
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -4581,8 +4739,7 @@ rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
if (RB_TYPE_P(sub, T_REGEXP)) {
if (rb_reg_search(sub, str, pos, 0) >= 0) {
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
- pos = BEG(0);
+ pos = RMATCH_BEG(match, 0);
return LONG2NUM(pos);
}
}
@@ -4678,59 +4835,10 @@ rb_str_rindex(VALUE str, VALUE sub, long pos)
/*
* call-seq:
- * rindex(substring, offset = self.length) -> integer or nil
- * rindex(regexp, offset = self.length) -> integer or nil
- *
- * Returns the Integer index of the _last_ occurrence of the given +substring+,
- * or +nil+ if none found:
- *
- * 'foo'.rindex('f') # => 0
- * 'foo'.rindex('o') # => 2
- * 'foo'.rindex('oo') # => 1
- * 'foo'.rindex('ooo') # => nil
- *
- * Returns the Integer index of the _last_ match for the given Regexp +regexp+,
- * or +nil+ if none found:
- *
- * 'foo'.rindex(/f/) # => 0
- * 'foo'.rindex(/o/) # => 2
- * 'foo'.rindex(/oo/) # => 1
- * 'foo'.rindex(/ooo/) # => nil
- *
- * The _last_ match means starting at the possible last position, not
- * the last of longest matches.
- *
- * 'foo'.rindex(/o+/) # => 2
- * $~ #=> #<MatchData "o">
+ * rindex(pattern, offset = self.length) -> integer or nil
*
- * To get the last longest match, needs to combine with negative
- * lookbehind.
+ * :include:doc/string/rindex.rdoc
*
- * 'foo'.rindex(/(?<!o)o+/) # => 1
- * $~ #=> #<MatchData "oo">
- *
- * Or String#index with negative lookforward.
- *
- * 'foo'.index(/o+(?!.*o)/) # => 1
- * $~ #=> #<MatchData "oo">
- *
- * Integer argument +offset+, if given and non-negative, specifies the maximum starting position in the
- * string to _end_ the search:
- *
- * 'foo'.rindex('o', 0) # => nil
- * 'foo'.rindex('o', 1) # => 1
- * 'foo'.rindex('o', 2) # => 2
- * 'foo'.rindex('o', 3) # => 2
- *
- * If +offset+ is a negative Integer, the maximum starting position in the
- * string to _end_ the search is the sum of the string's length and +offset+:
- *
- * 'foo'.rindex('o', -1) # => 2
- * 'foo'.rindex('o', -2) # => 1
- * 'foo'.rindex('o', -3) # => nil
- * 'foo'.rindex('o', -4) # => nil
- *
- * Related: String#index.
*/
static VALUE
@@ -4762,8 +4870,7 @@ rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
if (rb_reg_search(sub, str, pos, 1) >= 0) {
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
- pos = rb_str_sublen(str, BEG(0));
+ pos = rb_str_sublen(str, RMATCH_BEG(match, 0));
return LONG2NUM(pos);
}
}
@@ -4808,65 +4915,90 @@ rb_str_byterindex(VALUE str, VALUE sub, long pos)
return str_rindex(str, sub, s, enc);
}
-
/*
* call-seq:
- * byterindex(substring, offset = self.bytesize) -> integer or nil
- * byterindex(regexp, offset = self.bytesize) -> integer or nil
+ * byterindex(object, offset = self.bytesize) -> integer or nil
*
- * Returns the Integer byte-based index of the _last_ occurrence of the given +substring+,
- * or +nil+ if none found:
+ * Returns the 0-based integer index of a substring of +self+
+ * that is the _last_ match for the given +object+ (a string or Regexp) and +offset+,
+ * or +nil+ if there is no such substring;
+ * the returned index is the count of _bytes_ (not characters).
*
- * 'foo'.byterindex('f') # => 0
- * 'foo'.byterindex('o') # => 2
- * 'foo'.byterindex('oo') # => 1
- * 'foo'.byterindex('ooo') # => nil
+ * When +object+ is a string,
+ * returns the index of the _last_ found substring equal to +object+:
*
- * Returns the Integer byte-based index of the _last_ match for the given Regexp +regexp+,
- * or +nil+ if none found:
+ * s = 'foo' # => "foo"
+ * s.size # => 3 # Three 1-byte characters.
+ * s.bytesize # => 3 # Three bytes.
+ * s.byterindex('f') # => 0
+ * s.byterindex('o') # => 2
+ * s.byterindex('oo') # => 1
+ * s.byterindex('ooo') # => nil
*
- * 'foo'.byterindex(/f/) # => 0
- * 'foo'.byterindex(/o/) # => 2
- * 'foo'.byterindex(/oo/) # => 1
- * 'foo'.byterindex(/ooo/) # => nil
+ * When +object+ is a Regexp,
+ * returns the index of the last found substring matching +object+;
+ * updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
*
- * The _last_ match means starting at the possible last position, not
- * the last of longest matches.
+ * s = 'foo'
+ * s.byterindex(/f/) # => 0
+ * $~ # => #<MatchData "f">
+ * s.byterindex(/o/) # => 2
+ * s.byterindex(/oo/) # => 1
+ * s.byterindex(/ooo/) # => nil
+ * $~ # => nil
*
- * 'foo'.byterindex(/o+/) # => 2
- * $~ #=> #<MatchData "o">
+ * The last match means starting at the possible last position,
+ * not the last of the longest matches:
*
- * To get the last longest match, needs to combine with negative
- * lookbehind.
+ * s = 'foo'
+ * s.byterindex(/o+/) # => 2
+ * $~ #=> #<MatchData "o">
*
- * 'foo'.byterindex(/(?<!o)o+/) # => 1
- * $~ #=> #<MatchData "oo">
+ * To get the last longest match, use a negative lookbehind:
*
- * Or String#byteindex with negative lookforward.
+ * s = 'foo'
+ * s.byterindex(/(?<!o)o+/) # => 1
+ * $~ # => #<MatchData "oo">
*
- * 'foo'.byteindex(/o+(?!.*o)/) # => 1
- * $~ #=> #<MatchData "oo">
+ * Or use method #byteindex with negative lookahead:
*
- * Integer argument +offset+, if given and non-negative, specifies the maximum starting byte-based position in the
- * string to _end_ the search:
+ * s = 'foo'
+ * s.byteindex(/o+(?!.*o)/) # => 1
+ * $~ #=> #<MatchData "oo">
+ *
+ * \Integer argument +offset+, if given, specifies the 0-based index
+ * of the byte where searching is to end.
+ *
+ * When +offset+ is non-negative,
+ * searching ends at byte position +offset+:
+ *
+ * s = 'foo'
+ * s.byterindex('o', 0) # => nil
+ * s.byterindex('o', 1) # => 1
+ * s.byterindex('o', 2) # => 2
+ * s.byterindex('o', 3) # => 2
*
- * 'foo'.byterindex('o', 0) # => nil
- * 'foo'.byterindex('o', 1) # => 1
- * 'foo'.byterindex('o', 2) # => 2
- * 'foo'.byterindex('o', 3) # => 2
+ * When +offset+ is negative, counts backward from the end of +self+:
*
- * If +offset+ is a negative Integer, the maximum starting position in the
- * string to _end_ the search is the sum of the string's length and +offset+:
+ * s = 'foo'
+ * s.byterindex('o', -1) # => 2
+ * s.byterindex('o', -2) # => 1
+ * s.byterindex('o', -3) # => nil
*
- * 'foo'.byterindex('o', -1) # => 2
- * 'foo'.byterindex('o', -2) # => 1
- * 'foo'.byterindex('o', -3) # => nil
- * 'foo'.byterindex('o', -4) # => nil
+ * Raises IndexError if the byte at +offset+ is not the first byte of a character:
*
- * If +offset+ does not land on character (codepoint) boundary, +IndexError+ is
- * raised.
+ * s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF"
+ * s.size # => 2 # Two 3-byte characters.
+ * s.bytesize # => 6 # Six bytes.
+ * s.byterindex("\uFFFF") # => 3
+ * s.byterindex("\uFFFF", 1) # Raises IndexError
+ * s.byterindex("\uFFFF", 2) # Raises IndexError
+ * s.byterindex("\uFFFF", 3) # => 3
+ * s.byterindex("\uFFFF", 4) # Raises IndexError
+ * s.byterindex("\uFFFF", 5) # Raises IndexError
+ * s.byterindex("\uFFFF", 6) # => nil
*
- * Related: String#byteindex.
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -4895,8 +5027,7 @@ rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
if (RB_TYPE_P(sub, T_REGEXP)) {
if (rb_reg_search(sub, str, pos, 1) >= 0) {
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
- pos = BEG(0);
+ pos = RMATCH_BEG(match, 0);
return LONG2NUM(pos);
}
}
@@ -4910,30 +5041,36 @@ rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * string =~ regexp -> integer or nil
- * string =~ object -> integer or nil
+ * self =~ other -> integer or nil
+ *
+ * When +other+ is a Regexp:
*
- * Returns the Integer index of the first substring that matches
- * the given +regexp+, or +nil+ if no match found:
+ * - Returns the integer index (in characters) of the first match
+ * for +self+ and +other+, or +nil+ if none;
+ * - Updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables].
+ *
+ * Examples:
*
* 'foo' =~ /f/ # => 0
+ * $~ # => #<MatchData "f">
* 'foo' =~ /o/ # => 1
+ * $~ # => #<MatchData "o">
* 'foo' =~ /x/ # => nil
- *
- * Note: also updates Regexp@Global+Variables.
- *
- * If the given +object+ is not a Regexp, returns the value
- * returned by <tt>object =~ self</tt>.
+ * $~ # => nil
*
* Note that <tt>string =~ regexp</tt> is different from <tt>regexp =~ string</tt>
* (see Regexp#=~):
*
- * number= nil
- * "no. 9" =~ /(?<number>\d+)/
- * number # => nil (not assigned)
- * /(?<number>\d+)/ =~ "no. 9"
- * number #=> "9"
+ * number = nil
+ * 'no. 9' =~ /(?<number>\d+)/ # => 4
+ * number # => nil # Not assigned.
+ * /(?<number>\d+)/ =~ 'no. 9' # => 4
+ * number # => "9" # Assigned.
+ *
+ * When +other+ is not a Regexp, returns the value
+ * returned by <tt>other =~ self</tt>.
*
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -4960,34 +5097,36 @@ static VALUE get_pat(VALUE);
* match(pattern, offset = 0) -> matchdata or nil
* match(pattern, offset = 0) {|matchdata| ... } -> object
*
- * Returns a MatchData object (or +nil+) based on +self+ and the given +pattern+.
- *
- * Note: also updates Regexp@Global+Variables.
+ * Creates a MatchData object based on +self+ and the given arguments;
+ * updates {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
*
* - Computes +regexp+ by converting +pattern+ (if not already a Regexp).
+ *
* regexp = Regexp.new(pattern)
+ *
* - Computes +matchdata+, which will be either a MatchData object or +nil+
* (see Regexp#match):
- * matchdata = regexp.match(self)
- *
- * With no block given, returns the computed +matchdata+:
*
- * 'foo'.match('f') # => #<MatchData "f">
- * 'foo'.match('o') # => #<MatchData "o">
- * 'foo'.match('x') # => nil
+ * matchdata = regexp.match(self[offset..])
*
- * If Integer argument +offset+ is given, the search begins at index +offset+:
+ * With no block given, returns the computed +matchdata+ or +nil+:
*
+ * 'foo'.match('f') # => #<MatchData "f">
+ * 'foo'.match('o') # => #<MatchData "o">
+ * 'foo'.match('x') # => nil
* 'foo'.match('f', 1) # => nil
* 'foo'.match('o', 1) # => #<MatchData "o">
*
- * With a block given, calls the block with the computed +matchdata+
- * and returns the block's return value:
+ * With a block given and computed +matchdata+ non-nil, calls the block with +matchdata+;
+ * returns the block's return value:
*
* 'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
- * 'foo'.match(/x/) {|matchdata| matchdata } # => nil
- * 'foo'.match(/f/, 1) {|matchdata| matchdata } # => nil
*
+ * With a block given and +nil+ +matchdata+, does not call the block:
+ *
+ * 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil
+ *
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -5009,24 +5148,23 @@ rb_str_match_m(int argc, VALUE *argv, VALUE str)
* call-seq:
* match?(pattern, offset = 0) -> true or false
*
- * Returns +true+ or +false+ based on whether a match is found for +self+ and +pattern+.
+ * Returns whether a match is found for +self+ and the given arguments;
+ * does not update {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
*
- * Note: does not update Regexp@Global+Variables.
+ * Computes +regexp+ by converting +pattern+ (if not already a Regexp):
*
- * Computes +regexp+ by converting +pattern+ (if not already a Regexp).
* regexp = Regexp.new(pattern)
*
- * Returns +true+ if <tt>self+.match(regexp)</tt> returns a MatchData object,
+ * Returns +true+ if <tt>self[offset..].match(regexp)</tt> returns a MatchData object,
* +false+ otherwise:
*
* 'foo'.match?(/o/) # => true
* 'foo'.match?('o') # => true
* 'foo'.match?(/x/) # => false
- *
- * If Integer argument +offset+ is given, the search begins at index +offset+:
* 'foo'.match?('f', 1) # => false
* 'foo'.match?('o', 1) # => true
*
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -5227,57 +5365,7 @@ static VALUE str_succ(VALUE str);
* call-seq:
* succ -> new_str
*
- * Returns the successor to +self+. The successor is calculated by
- * incrementing characters.
- *
- * The first character to be incremented is the rightmost alphanumeric:
- * or, if no alphanumerics, the rightmost character:
- *
- * 'THX1138'.succ # => "THX1139"
- * '<<koala>>'.succ # => "<<koalb>>"
- * '***'.succ # => '**+'
- *
- * The successor to a digit is another digit, "carrying" to the next-left
- * character for a "rollover" from 9 to 0, and prepending another digit
- * if necessary:
- *
- * '00'.succ # => "01"
- * '09'.succ # => "10"
- * '99'.succ # => "100"
- *
- * The successor to a letter is another letter of the same case,
- * carrying to the next-left character for a rollover,
- * and prepending another same-case letter if necessary:
- *
- * 'aa'.succ # => "ab"
- * 'az'.succ # => "ba"
- * 'zz'.succ # => "aaa"
- * 'AA'.succ # => "AB"
- * 'AZ'.succ # => "BA"
- * 'ZZ'.succ # => "AAA"
- *
- * The successor to a non-alphanumeric character is the next character
- * in the underlying character set's collating sequence,
- * carrying to the next-left character for a rollover,
- * and prepending another character if necessary:
- *
- * s = 0.chr * 3
- * s # => "\x00\x00\x00"
- * s.succ # => "\x00\x00\x01"
- * s = 255.chr * 3
- * s # => "\xFF\xFF\xFF"
- * s.succ # => "\x01\x00\x00\x00"
- *
- * Carrying can occur between and among mixtures of alphanumeric characters:
- *
- * s = 'zz99zz99'
- * s.succ # => "aaa00aa00"
- * s = '99zz99zz'
- * s.succ # => "100aa00aa"
- *
- * The successor to an empty +String+ is a new empty +String+:
- *
- * ''.succ # => ""
+ * :include: doc/string/succ.rdoc
*
*/
@@ -5382,7 +5470,9 @@ str_succ(VALUE str)
* call-seq:
* succ! -> self
*
- * Equivalent to String#succ, but modifies +self+ in place; returns +self+.
+ * Like String#succ, but modifies +self+ in place; returns +self+.
+ *
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -5415,33 +5505,7 @@ str_upto_i(VALUE str, VALUE arg)
* upto(other_string, exclusive = false) {|string| ... } -> self
* upto(other_string, exclusive = false) -> new_enumerator
*
- * With a block given, calls the block with each +String+ value
- * returned by successive calls to String#succ;
- * the first value is +self+, the next is <tt>self.succ</tt>, and so on;
- * the sequence terminates when value +other_string+ is reached;
- * returns +self+:
- *
- * 'a8'.upto('b6') {|s| print s, ' ' } # => "a8"
- * Output:
- *
- * a8 a9 b0 b1 b2 b3 b4 b5 b6
- *
- * If argument +exclusive+ is given as a truthy object, the last value is omitted:
- *
- * 'a8'.upto('b6', true) {|s| print s, ' ' } # => "a8"
- *
- * Output:
- *
- * a8 a9 b0 b1 b2 b3 b4 b5
- *
- * If +other_string+ would not be reached, does not call the block:
- *
- * '25'.upto('5') {|s| fail s }
- * 'aa'.upto('a') {|s| fail s }
- *
- * With no block given, returns a new Enumerator:
- *
- * 'a8'.upto('b6') # => #<Enumerator: "a8":upto("b6")>
+ * :include: doc/string/upto.rdoc
*
*/
@@ -5682,15 +5746,13 @@ rb_str_aref(VALUE str, VALUE indx)
/*
* call-seq:
- * string[index] -> new_string or nil
- * string[start, length] -> new_string or nil
- * string[range] -> new_string or nil
- * string[regexp, capture = 0] -> new_string or nil
- * string[substring] -> new_string or nil
- *
- * Returns the substring of +self+ specified by the arguments.
- * See examples at {String Slices}[rdoc-ref:String@String+Slices].
+ * self[offset] -> new_string or nil
+ * self[offset, size] -> new_string or nil
+ * self[range] -> new_string or nil
+ * self[regexp, capture = 0] -> new_string or nil
+ * self[substring] -> new_string or nil
*
+ * :include: doc/string/aref.rdoc
*
*/
@@ -5720,11 +5782,14 @@ rb_str_drop_bytes(VALUE str, long len)
nlen = olen - len;
if (str_embed_capa(str) >= nlen + TERM_LEN(str)) {
char *oldptr = ptr;
+ size_t old_capa = RSTRING(str)->as.heap.aux.capa + TERM_LEN(str);
int fl = (int)(RBASIC(str)->flags & (STR_NOEMBED|STR_SHARED|STR_NOFREE));
STR_SET_EMBED(str);
ptr = RSTRING(str)->as.embed.ary;
memmove(ptr, oldptr + len, nlen);
- if (fl == STR_NOEMBED) xfree(oldptr);
+ if (fl == STR_NOEMBED) {
+ SIZED_FREE_N(oldptr, old_capa);
+ }
}
else {
if (!STR_SHARED_P(str)) {
@@ -5839,26 +5904,25 @@ rb_str_subpat_set(VALUE str, VALUE re, VALUE backref, VALUE val)
VALUE match;
long start, end, len;
rb_encoding *enc;
- struct re_registers *regs;
if (rb_reg_search(re, str, 0, 0) < 0) {
rb_raise(rb_eIndexError, "regexp not matched");
}
match = rb_backref_get();
nth = rb_reg_backref_number(match, backref);
- regs = RMATCH_REGS(match);
- if ((nth >= regs->num_regs) || ((nth < 0) && (-nth >= regs->num_regs))) {
+ int num_regs = RMATCH_NREGS(match);
+ if ((nth >= num_regs) || ((nth < 0) && (-nth >= num_regs))) {
rb_raise(rb_eIndexError, "index %d out of regexp", nth);
}
if (nth < 0) {
- nth += regs->num_regs;
+ nth += num_regs;
}
- start = BEG(nth);
+ start = RMATCH_BEG(match, nth);
if (start == -1) {
rb_raise(rb_eIndexError, "regexp group %d not matched", nth);
}
- end = END(nth);
+ end = RMATCH_END(match, nth);
len = end - start;
StringValue(val);
enc = rb_enc_check_str(str, val);
@@ -5905,28 +5969,13 @@ rb_str_aset(VALUE str, VALUE indx, VALUE val)
/*
* call-seq:
- * string[index] = new_string
- * string[start, length] = new_string
- * string[range] = new_string
- * string[regexp, capture = 0] = new_string
- * string[substring] = new_string
- *
- * Replaces all, some, or none of the contents of +self+; returns +new_string+.
- * See {String Slices}[rdoc-ref:String@String+Slices].
- *
- * A few examples:
+ * self[index] = other_string -> new_string
+ * self[start, length] = other_string -> new_string
+ * self[range] = other_string -> new_string
+ * self[regexp, capture = 0] = other_string -> new_string
+ * self[substring] = other_string -> new_string
*
- * s = 'foo'
- * s[2] = 'rtune' # => "rtune"
- * s # => "fortune"
- * s[1, 5] = 'init' # => "init"
- * s # => "finite"
- * s[3..4] = 'al' # => "al"
- * s # => "finale"
- * s[/e$/] = 'ly' # => "ly"
- * s # => "finally"
- * s['lly'] = 'ncial' # => "ncial"
- * s # => "financial"
+ * :include: doc/string/aset.rdoc
*
*/
@@ -5948,19 +5997,9 @@ rb_str_aset_m(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * insert(index, other_string) -> self
- *
- * Inserts the given +other_string+ into +self+; returns +self+.
- *
- * If the Integer +index+ is positive, inserts +other_string+ at offset +index+:
- *
- * 'foo'.insert(1, 'bar') # => "fbaroo"
+ * insert(offset, other_string) -> self
*
- * If the Integer +index+ is negative, counts backward from the end of +self+
- * and inserts +other_string+ at offset <tt>index+1</tt>
- * (that is, _after_ <tt>self[index]</tt>):
- *
- * 'foo'.insert(-2, 'bar') # => "fobaro"
+ * :include: doc/string/insert.rdoc
*
*/
@@ -5988,18 +6027,20 @@ rb_str_insert(VALUE str, VALUE idx, VALUE str2)
* slice!(regexp, capture = 0) -> new_string or nil
* slice!(substring) -> new_string or nil
*
- * Removes and returns the substring of +self+ specified by the arguments.
- * See {String Slices}[rdoc-ref:String@String+Slices].
+ * Like String#[] (and its alias String#slice), except that:
+ *
+ * - Performs substitutions in +self+ (not in a copy of +self+).
+ * - Returns the removed substring if any modifications were made, +nil+ otherwise.
*
* A few examples:
*
- * string = "This is a string"
- * string.slice!(2) #=> "i"
- * string.slice!(3..6) #=> " is "
- * string.slice!(/s.*t/) #=> "sa st"
- * string.slice!("r") #=> "r"
- * string #=> "Thing"
+ * s = 'hello'
+ * s.slice!('e') # => "e"
+ * s # => "hllo"
+ * s.slice!('e') # => nil
+ * s # => "hllo"
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -6016,14 +6057,14 @@ rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
if (RB_TYPE_P(indx, T_REGEXP)) {
if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
+ int num_regs = RMATCH_NREGS(match);
int nth = 0;
if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
- if ((nth += regs->num_regs) <= 0) return Qnil;
+ if ((nth += num_regs) <= 0) return Qnil;
}
- else if (nth >= regs->num_regs) return Qnil;
- beg = BEG(nth);
- len = END(nth) - beg;
+ else if (nth >= num_regs) return Qnil;
+ beg = RMATCH_BEG(match, nth);
+ len = RMATCH_END(match, nth) - beg;
goto subseq;
}
else if (argc == 2) {
@@ -6173,13 +6214,12 @@ rb_pat_search(VALUE pat, VALUE str, long pos, int set_backref_str)
* sub!(pattern, replacement) -> self or nil
* sub!(pattern) {|match| ... } -> self or nil
*
- * Replaces the first occurrence (not all occurrences) of the given +pattern+
- * on +self+; returns +self+ if a replacement occurred, +nil+ otherwise.
- *
- * See {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
+ * Like String#sub, except that:
*
- * Related: String#sub, String#gsub, String#gsub!.
+ * - Changes are made to +self+, not to copy of +self+.
+ * - Returns +self+ if any changes are made, +nil+ otherwise.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -6197,9 +6237,11 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
}
else {
repl = argv[1];
- hash = rb_check_hash_type(argv[1]);
- if (NIL_P(hash)) {
- StringValue(repl);
+ if (!RB_TYPE_P(repl, T_STRING)) {
+ hash = rb_check_hash_type(repl);
+ if (NIL_P(hash)) {
+ StringValue(repl);
+ }
}
}
@@ -6212,20 +6254,18 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
int cr = ENC_CODERANGE(str);
long beg0, end0;
VALUE match, match0 = Qnil;
- struct re_registers *regs;
char *p, *rp;
long len, rlen;
match = rb_backref_get();
- regs = RMATCH_REGS(match);
if (RB_TYPE_P(pat, T_STRING)) {
beg0 = beg;
end0 = beg0 + RSTRING_LEN(pat);
match0 = pat;
}
else {
- beg0 = BEG(0);
- end0 = END(0);
+ beg0 = RMATCH_BEG(match, 0);
+ end0 = RMATCH_END(match, 0);
if (iter) match0 = rb_reg_nth_match(0, match);
}
@@ -6243,7 +6283,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
rb_check_frozen(str);
}
else {
- repl = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
+ repl = rb_reg_regsub_match(repl, str, match);
}
enc = rb_enc_compatible(str, repl);
@@ -6298,13 +6338,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
* sub(pattern, replacement) -> new_string
* sub(pattern) {|match| ... } -> new_string
*
- * Returns a copy of +self+ with only the first occurrence
- * (not all occurrences) of the given +pattern+ replaced.
- *
- * See {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
- *
- * Related: String#sub!, String#gsub, String#gsub!.
- *
+ * :include: doc/string/sub.rdoc
*/
static VALUE
@@ -6333,15 +6367,17 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
break;
case 2:
repl = argv[1];
- hash = rb_check_hash_type(argv[1]);
- if (NIL_P(hash)) {
- StringValue(repl);
- }
- else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
- mode = FAST_MAP;
- }
- else {
- mode = MAP;
+ if (!RB_TYPE_P(repl, T_STRING)) {
+ hash = rb_check_hash_type(repl);
+ if (NIL_P(hash)) {
+ StringValue(repl);
+ }
+ else if (rb_hash_default_unredefined(hash) && !FL_TEST_RAW(hash, RHASH_PROC_DEFAULT)) {
+ mode = FAST_MAP;
+ }
+ else {
+ mode = MAP;
+ }
}
break;
default:
@@ -6355,6 +6391,7 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
if (bang) return Qnil; /* no match, no substitution */
return str_duplicate(rb_cString, str);
}
+ if (bang) str_modify_keep_cr(str);
offset = 0;
blen = RSTRING_LEN(str) + 30; /* len + margin */
@@ -6367,15 +6404,14 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);
do {
- struct re_registers *regs = RMATCH_REGS(match);
if (RB_TYPE_P(pat, T_STRING)) {
beg0 = beg;
end0 = beg0 + RSTRING_LEN(pat);
match0 = pat;
}
else {
- beg0 = BEG(0);
- end0 = END(0);
+ beg0 = RMATCH_BEG(match, 0);
+ end0 = RMATCH_END(match, 0);
if (mode == ITER) match0 = rb_reg_nth_match(0, match);
}
@@ -6384,7 +6420,7 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
val = rb_obj_as_string(rb_yield(match0));
}
else {
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
VALUE key;
if (mode == FAST_MAP) {
// It is safe to use a fake_str here because we established that it won't escape,
@@ -6404,7 +6440,7 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
}
}
else if (need_backref_str) {
- val = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
+ val = rb_reg_regsub_match(repl, str, match);
if (need_backref_str < 0) {
need_backref_str = val != repl;
}
@@ -6465,21 +6501,18 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
* gsub!(pattern) {|match| ... } -> self or nil
* gsub!(pattern) -> an_enumerator
*
- * Performs the specified substring replacement(s) on +self+;
- * returns +self+ if any replacement occurred, +nil+ otherwise.
- *
- * See {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
- *
- * Returns an Enumerator if no +replacement+ and no block given.
+ * Like String#gsub, except that:
*
- * Related: String#sub, String#gsub, String#sub!.
+ * - Performs substitutions in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any characters are removed, +nil+ otherwise.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
{
- str_modify_keep_cr(str);
+ str_modifiable(str);
return str_gsub(argc, argv, str, 1);
}
@@ -6490,14 +6523,41 @@ rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
* gsub(pattern) {|match| ... } -> new_string
* gsub(pattern) -> enumerator
*
- * Returns a copy of +self+ with all occurrences of the given +pattern+ replaced.
+ * Returns a copy of +self+ with zero or more substrings replaced.
+ *
+ * Argument +pattern+ may be a string or a Regexp;
+ * argument +replacement+ may be a string or a Hash.
+ * Varying types for the argument values makes this method very versatile.
+ *
+ * Below are some simple examples;
+ * for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
+ *
+ * With arguments +pattern+ and string +replacement+ given,
+ * replaces each matching substring with the given +replacement+ string:
*
- * See {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
+ * s = 'abracadabra'
+ * s.gsub('ab', 'AB') # => "ABracadABra"
+ * s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
*
- * Returns an Enumerator if no +replacement+ and no block given.
+ * With arguments +pattern+ and hash +replacement+ given,
+ * replaces each matching substring with a value from the given +replacement+ hash,
+ * or removes it:
*
- * Related: String#sub, String#sub!, String#gsub!.
+ * h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
+ * s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
+ * s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
*
+ * With argument +pattern+ and a block given,
+ * calls the block with each matching substring;
+ * replaces that substring with the block's return value:
+ *
+ * s.gsub(/[a-d]/) {|substring| substring.upcase }
+ * # => "ABrACADABrA"
+ *
+ * With argument +pattern+ and no block given,
+ * returns a new Enumerator.
+ *
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@@ -6511,11 +6571,13 @@ rb_str_gsub(int argc, VALUE *argv, VALUE str)
* call-seq:
* replace(other_string) -> self
*
- * Replaces the contents of +self+ with the contents of +other_string+:
+ * Replaces the contents of +self+ with the contents of +other_string+;
+ * returns +self+:
*
* s = 'foo' # => "foo"
* s.replace('bar') # => "bar"
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
VALUE
@@ -6535,9 +6597,11 @@ rb_str_replace(VALUE str, VALUE str2)
*
* Removes the contents of +self+:
*
- * s = 'foo' # => "foo"
- * s.clear # => ""
+ * s = 'foo'
+ * s.clear # => ""
+ * s # => ""
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -6558,10 +6622,7 @@ rb_str_clear(VALUE str)
* call-seq:
* chr -> string
*
- * Returns a string containing the first character of +self+:
- *
- * s = 'foo' # => "foo"
- * s.chr # => "f"
+ * :include: doc/string/chr.rdoc
*
*/
@@ -6575,14 +6636,8 @@ rb_str_chr(VALUE str)
* call-seq:
* getbyte(index) -> integer or nil
*
- * Returns the byte at zero-based +index+ as an integer, or +nil+ if +index+ is out of range:
+ * :include: doc/string/getbyte.rdoc
*
- * s = 'abcde' # => "abcde"
- * s.getbyte(0) # => 97
- * s.getbyte(-1) # => 101
- * s.getbyte(5) # => nil
- *
- * Related: String#setbyte.
*/
VALUE
rb_str_getbyte(VALUE str, VALUE index)
@@ -6601,13 +6656,14 @@ rb_str_getbyte(VALUE str, VALUE index)
* call-seq:
* setbyte(index, integer) -> integer
*
- * Sets the byte at zero-based +index+ to +integer+; returns +integer+:
+ * Sets the byte at zero-based offset +index+ to the value of the given +integer+;
+ * returns +integer+:
*
- * s = 'abcde' # => "abcde"
- * s.setbyte(0, 98) # => 98
- * s # => "bbcde"
+ * s = 'xyzzy'
+ * s.setbyte(2, 129) # => 129
+ * s # => "xy\x81zy"
*
- * Related: String#getbyte.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
VALUE
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
@@ -6738,45 +6794,10 @@ str_byte_aref(VALUE str, VALUE indx)
/*
* call-seq:
- * byteslice(index, length = 1) -> string or nil
- * byteslice(range) -> string or nil
- *
- * Returns a substring of +self+, or +nil+ if the substring cannot be constructed.
- *
- * With integer arguments +index+ and +length+ given,
- * returns the substring beginning at the given +index+
- * of the given +length+ (if possible),
- * or +nil+ if +length+ is negative or +index+ falls outside of +self+:
- *
- * s = '0123456789' # => "0123456789"
- * s.byteslice(2) # => "2"
- * s.byteslice(200) # => nil
- * s.byteslice(4, 3) # => "456"
- * s.byteslice(4, 30) # => "456789"
- * s.byteslice(4, -1) # => nil
- * s.byteslice(40, 2) # => nil
- *
- * In either case above, counts backwards from the end of +self+
- * if +index+ is negative:
- *
- * s = '0123456789' # => "0123456789"
- * s.byteslice(-4) # => "6"
- * s.byteslice(-4, 3) # => "678"
- *
- * With Range argument +range+ given, returns
- * <tt>byteslice(range.begin, range.size)</tt>:
- *
- * s = '0123456789' # => "0123456789"
- * s.byteslice(4..6) # => "456"
- * s.byteslice(-6..-4) # => "456"
- * s.byteslice(5..2) # => "" # range.size is zero.
- * s.byteslice(40..42) # => nil
- *
- * In all cases, a returned string has the same encoding as +self+:
- *
- * s.encoding # => #<Encoding:UTF-8>
- * s.byteslice(4).encoding # => #<Encoding:UTF-8>
+ * byteslice(offset, length = 1) -> string or nil
+ * byteslice(range) -> string or nil
*
+ * :include: doc/string/byteslice.rdoc
*/
static VALUE
@@ -6816,23 +6837,12 @@ str_check_beg_len(VALUE str, long *beg, long *len)
/*
* call-seq:
- * bytesplice(index, length, str) -> string
- * bytesplice(index, length, str, str_index, str_length) -> string
- * bytesplice(range, str) -> string
- * bytesplice(range, str, str_range) -> string
+ * bytesplice(offset, length, str) -> self
+ * bytesplice(offset, length, str, str_offset, str_length) -> self
+ * bytesplice(range, str) -> self
+ * bytesplice(range, str, str_range) -> self
*
- * Replaces some or all of the content of +self+ with +str+, and returns +self+.
- * The portion of the string affected is determined using
- * the same criteria as String#byteslice, except that +length+ cannot be omitted.
- * If the replacement string is not the same length as the text it is replacing,
- * the string will be adjusted accordingly.
- *
- * If +str_index+ and +str_length+, or +str_range+ are given, the content of +self+ is replaced by str.byteslice(str_index, str_length) or str.byteslice(str_range); however the substring of +str+ is not allocated as a new string.
- *
- * The form that take an Integer will raise an IndexError if the value is out
- * of range; the Range form will raise a RangeError.
- * If the beginning or ending offset does not land on character (codepoint)
- * boundary, an IndexError will be raised.
+ * :include: doc/string/bytesplice.rdoc
*/
static VALUE
@@ -6899,12 +6909,16 @@ rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * reverse -> string
+ * reverse -> new_string
*
* Returns a new string with the characters from +self+ in reverse order.
*
- * 'stressed'.reverse # => "desserts"
+ * 'drawer'.reverse # => "reward"
+ * 'reviled'.reverse # => "deliver"
+ * 'stressed'.reverse # => "desserts"
+ * 'semordnilaps'.reverse # => "spalindromes"
*
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@@ -6964,10 +6978,12 @@ rb_str_reverse(VALUE str)
*
* Returns +self+ with its characters reversed:
*
- * s = 'stressed'
- * s.reverse! # => "desserts"
- * s # => "desserts"
+ * 'drawer'.reverse! # => "reward"
+ * 'reviled'.reverse! # => "deliver"
+ * 'stressed'.reverse! # => "desserts"
+ * 'semordnilaps'.reverse! # => "spalindromes"
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -7001,13 +7017,17 @@ rb_str_reverse_bang(VALUE str)
* call-seq:
* include?(other_string) -> true or false
*
- * Returns +true+ if +self+ contains +other_string+, +false+ otherwise:
+ * Returns whether +self+ contains +other_string+:
*
- * s = 'foo'
- * s.include?('f') # => true
- * s.include?('fo') # => true
- * s.include?('food') # => false
+ * s = 'bar'
+ * s.include?('ba') # => true
+ * s.include?('ar') # => true
+ * s.include?('bar') # => true
+ * s.include?('a') # => true
+ * s.include?('') # => true
+ * s.include?('foo') # => false
*
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
VALUE
@@ -7027,12 +7047,13 @@ rb_str_include(VALUE str, VALUE arg)
* to_i(base = 10) -> integer
*
* Returns the result of interpreting leading characters in +self+
- * as an integer in the given +base+ (which must be in (0, 2..36)):
+ * as an integer in the given +base+;
+ * +base+ must be either +0+ or in range <tt>(2..36)</tt>:
*
* '123456'.to_i # => 123456
* '123def'.to_i(16) # => 1195503
*
- * With +base+ zero, string +object+ may contain leading characters
+ * With +base+ zero given, string +object+ may contain leading characters
* to specify the actual base:
*
* '123def'.to_i(0) # => 123
@@ -7052,6 +7073,7 @@ rb_str_include(VALUE str, VALUE arg)
* 'abcdef'.to_i # => 0
* '2'.to_i(2) # => 0
*
+ * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
*/
static VALUE
@@ -7075,7 +7097,7 @@ rb_str_to_i(int argc, VALUE *argv, VALUE str)
* '3.14159'.to_f # => 3.14159
* '1.234e-2'.to_f # => 0.01234
*
- * Characters past a leading valid number (in the given +base+) are ignored:
+ * Characters past a leading valid number are ignored:
*
* '3.14 (pi to two places)'.to_f # => 3.14
*
@@ -7083,6 +7105,7 @@ rb_str_to_i(int argc, VALUE *argv, VALUE str)
*
* 'abcdef'.to_f # => 0.0
*
+ * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
*/
static VALUE
@@ -7094,10 +7117,12 @@ rb_str_to_f(VALUE str)
/*
* call-seq:
- * to_s -> self or string
+ * to_s -> self or new_string
*
* Returns +self+ if +self+ is a +String+,
* or +self+ converted to a +String+ if +self+ is a subclass of +String+.
+ *
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@@ -7230,12 +7255,7 @@ rb_str_escape(VALUE str)
* call-seq:
* inspect -> string
*
- * Returns a printable version of +self+, enclosed in double-quotes,
- * and with special characters escaped:
- *
- * s = "foo\tbar\tbaz\n"
- * s.inspect
- * # => "\"foo\\tbar\\tbaz\\n\""
+ * :include: doc/string/inspect.rdoc
*
*/
@@ -7340,16 +7360,9 @@ rb_str_inspect(VALUE str)
/*
* call-seq:
- * dump -> string
- *
- * Returns a printable version of +self+, enclosed in double-quotes,
- * with special characters escaped, and with non-printing characters
- * replaced by hexadecimal notation:
- *
- * "hello \n ''".dump # => "\"hello \\n ''\""
- * "\f\x00\xff\\\"".dump # => "\"\\f\\x00\\xFF\\\\\\\"\""
+ * dump -> new_string
*
- * Related: String#undump (inverse of String#dump).
+ * :include: doc/string/dump.rdoc
*
*/
@@ -7609,10 +7622,6 @@ undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_en
}
break;
case 'x':
- if (*utf8) {
- rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
- }
- *binary = true;
if (++s >= s_end) {
rb_raise(rb_eRuntimeError, "invalid hex escape");
}
@@ -7620,6 +7629,12 @@ undump_after_backslash(VALUE undumped, const char **ss, const char *s_end, rb_en
if (hexlen != 2) {
rb_raise(rb_eRuntimeError, "invalid hex escape");
}
+ if (!ISASCII(*buf)) {
+ if (*utf8) {
+ rb_raise(rb_eRuntimeError, "hex escape and Unicode escape are mixed");
+ }
+ *binary = true;
+ }
rb_str_cat(undumped, (char *)buf, 1);
s += hexlen;
break;
@@ -7635,17 +7650,11 @@ static VALUE rb_str_is_ascii_only_p(VALUE str);
/*
* call-seq:
- * undump -> string
- *
- * Returns an unescaped version of +self+:
- *
- * s_orig = "\f\x00\xff\\\"" # => "\f\u0000\xFF\\\""
- * s_dumped = s_orig.dump # => "\"\\f\\x00\\xFF\\\\\\\"\""
- * s_undumped = s_dumped.undump # => "\f\u0000\xFF\\\""
- * s_undumped == s_orig # => true
+ * undump -> new_string
*
- * Related: String#dump (inverse of String#undump).
+ * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone."
*
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@@ -7826,7 +7835,7 @@ mapping_buffer_free(void *p)
while (current_buffer) {
previous_buffer = current_buffer;
current_buffer = current_buffer->next;
- ruby_sized_xfree(previous_buffer, previous_buffer->capa);
+ ruby_xfree_sized(previous_buffer, offsetof(mapping_buffer, space) + previous_buffer->capa);
}
}
@@ -7970,21 +7979,14 @@ upcase_single(VALUE str)
/*
* call-seq:
- * upcase!(*options) -> self or nil
- *
- * Upcases the characters in +self+;
- * returns +self+ if any changes were made, +nil+ otherwise:
- *
- * s = 'Hello World!' # => "Hello World!"
- * s.upcase! # => "HELLO WORLD!"
- * s # => "HELLO WORLD!"
- * s.upcase! # => nil
+ * upcase!(mapping) -> self or nil
*
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
+ * Like String#upcase, except that:
*
- * Related: String#upcase, String#downcase, String#downcase!.
+ * - Changes character casings in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any changes are made, +nil+ otherwise.
*
+ * Related: See {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8012,18 +8014,9 @@ rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * upcase(*options) -> string
- *
- * Returns a string containing the upcased characters in +self+:
- *
- * s = 'Hello World!' # => "Hello World!"
- * s.upcase # => "HELLO WORLD!"
- *
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#upcase!, String#downcase, String#downcase!.
+ * upcase(mapping = :ascii) -> new_string
*
+ * :include: doc/string/upcase.rdoc
*/
static VALUE
@@ -8072,21 +8065,14 @@ downcase_single(VALUE str)
/*
* call-seq:
- * downcase!(*options) -> self or nil
- *
- * Downcases the characters in +self+;
- * returns +self+ if any changes were made, +nil+ otherwise:
+ * downcase!(mapping) -> self or nil
*
- * s = 'Hello World!' # => "Hello World!"
- * s.downcase! # => "hello world!"
- * s # => "hello world!"
- * s.downcase! # => nil
+ * Like String#downcase, except that:
*
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#downcase, String#upcase, String#upcase!.
+ * - Changes character casings in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any changes are made, +nil+ otherwise.
*
+ * Related: See {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8114,17 +8100,9 @@ rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * downcase(*options) -> string
- *
- * Returns a string containing the downcased characters in +self+:
- *
- * s = 'Hello World!' # => "Hello World!"
- * s.downcase # => "hello world!"
+ * downcase(mapping = :ascii) -> new_string
*
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#downcase!, String#upcase, String#upcase!.
+ * :include: doc/string/downcase.rdoc
*
*/
@@ -8156,22 +8134,14 @@ rb_str_downcase(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * capitalize!(*options) -> self or nil
- *
- * Upcases the first character in +self+;
- * downcases the remaining characters;
- * returns +self+ if any changes were made, +nil+ otherwise:
+ * capitalize!(mapping = :ascii) -> self or nil
*
- * s = 'hello World!' # => "hello World!"
- * s.capitalize! # => "Hello world!"
- * s # => "Hello world!"
- * s.capitalize! # => nil
+ * Like String#capitalize, except that:
*
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#capitalize.
+ * - Changes character casings in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any changes are made, +nil+ otherwise.
*
+ * Related: See {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8196,19 +8166,9 @@ rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * capitalize(*options) -> string
- *
- * Returns a string containing the characters in +self+;
- * the first character is upcased;
- * the remaining characters are downcased:
- *
- * s = 'hello World!' # => "hello World!"
- * s.capitalize # => "Hello world!"
+ * capitalize(mapping = :ascii) -> new_string
*
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#capitalize!.
+ * :include: doc/string/capitalize.rdoc
*
*/
@@ -8235,22 +8195,14 @@ rb_str_capitalize(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * swapcase!(*options) -> self or nil
- *
- * Upcases each lowercase character in +self+;
- * downcases uppercase character;
- * returns +self+ if any changes were made, +nil+ otherwise:
- *
- * s = 'Hello World!' # => "Hello World!"
- * s.swapcase! # => "hELLO wORLD!"
- * s # => "hELLO wORLD!"
- * ''.swapcase! # => nil
+ * swapcase!(mapping) -> self or nil
*
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
+ * Like String#swapcase, except that:
*
- * Related: String#swapcase.
+ * - Changes are made to +self+, not to copy of +self+.
+ * - Returns +self+ if any changes are made, +nil+ otherwise.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8274,19 +8226,9 @@ rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * swapcase(*options) -> string
+ * swapcase(mapping = :ascii) -> new_string
*
- * Returns a string containing the characters in +self+, with cases reversed;
- * each uppercase character is downcased;
- * each lowercase character is upcased:
- *
- * s = 'Hello World!' # => "Hello World!"
- * s.swapcase # => "hELLO wORLD!"
- *
- * The casing may be affected by the given +options+;
- * see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
- *
- * Related: String#swapcase!.
+ * :include: doc/string/swapcase.rdoc
*
*/
@@ -8483,7 +8425,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
if (!MBCLEN_CHARFOUND_P(r)) {
- xfree(buf);
+ SIZED_FREE_N(buf, max + termlen);
rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
}
clen = MBCLEN_CHARFOUND_LEN(r);
@@ -8535,7 +8477,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
t += tlen;
}
if (!STR_EMBED_P(str)) {
- ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
+ SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
}
TERM_FILL((char *)t, termlen);
RSTRING(str)->as.heap.ptr = (char *)buf;
@@ -8571,7 +8513,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
int r = rb_enc_precise_mbclen((char *)s, (char *)send, e1);
if (!MBCLEN_CHARFOUND_P(r)) {
- xfree(buf);
+ SIZED_FREE_N(buf, max + termlen);
rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(e1));
}
clen = MBCLEN_CHARFOUND_LEN(r);
@@ -8619,7 +8561,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
t += tlen;
}
if (!STR_EMBED_P(str)) {
- ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
+ SIZED_FREE_N(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
}
TERM_FILL((char *)t, termlen);
RSTRING(str)->as.heap.ptr = (char *)buf;
@@ -8642,9 +8584,12 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
* call-seq:
* tr!(selector, replacements) -> self or nil
*
- * Like String#tr, but modifies +self+ in place.
- * Returns +self+ if any changes were made, +nil+ otherwise.
+ * Like String#tr, except:
*
+ * - Performs substitutions in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any modifications were made, +nil+ otherwise.
+ *
+ * Related: {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8680,17 +8625,15 @@ rb_str_tr_bang(VALUE str, VALUE src, VALUE repl)
*
* Arguments +selector+ and +replacements+ must be valid character selectors
* (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
- * and may use any of its valid forms, including negation, ranges, and escaping:
+ * and may use any of its valid forms, including negation, ranges, and escapes:
*
- * # Negation.
- * 'hello'.tr('^aeiou', '-') # => "-e--o"
- * # Ranges.
- * 'ibm'.tr('b-z', 'a-z') # => "hal"
- * # Escapes.
+ * 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation.
+ * 'ibm'.tr('b-z', 'a-z') # => "hal" # Range.
* 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret.
* 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen.
* 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash.
*
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@@ -8793,9 +8736,10 @@ tr_find(unsigned int c, const char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
* call-seq:
* delete!(*selectors) -> self or nil
*
- * Like String#delete, but modifies +self+ in place.
- * Returns +self+ if any changes were made, +nil+ otherwise.
+ * Like String#delete, but modifies +self+ in place;
+ * returns +self+ if any characters were deleted, +nil+ otherwise.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8864,13 +8808,7 @@ rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
* call-seq:
* delete(*selectors) -> new_string
*
- * Returns a copy of +self+ with characters specified by +selectors+ removed
- * (see {Multiple Character Selectors}[rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors]):
- *
- * "hello".delete "l","lo" #=> "heo"
- * "hello".delete "lo" #=> "he"
- * "hello".delete "aeiou", "^e" #=> "hell"
- * "hello".delete "ej-m" #=> "ho"
+ * :include: doc/string/delete.rdoc
*
*/
@@ -8887,8 +8825,12 @@ rb_str_delete(int argc, VALUE *argv, VALUE str)
* call-seq:
* squeeze!(*selectors) -> self or nil
*
- * Like String#squeeze, but modifies +self+ in place.
- * Returns +self+ if any changes were made, +nil+ otherwise.
+ * Like String#squeeze, except that:
+ *
+ * - Characters are squeezed in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any changes are made, +nil+ otherwise.
+ *
+ * Related: See {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -8971,16 +8913,7 @@ rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
* call-seq:
* squeeze(*selectors) -> new_string
*
- * Returns a copy of +self+ with characters specified by +selectors+ "squeezed"
- * (see {Multiple Character Selectors}[rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors]):
- *
- * "Squeezed" means that each multiple-character run of a selected character
- * is squeezed down to a single character;
- * with no arguments given, squeezes all characters:
- *
- * "yellow moon".squeeze #=> "yelow mon"
- * " now is the".squeeze(" ") #=> " now is the"
- * "putters shoot balls".squeeze("m-z") #=> "puters shot balls"
+ * :include: doc/string/squeeze.rdoc
*
*/
@@ -8997,10 +8930,12 @@ rb_str_squeeze(int argc, VALUE *argv, VALUE str)
* call-seq:
* tr_s!(selector, replacements) -> self or nil
*
- * Like String#tr_s, but modifies +self+ in place.
- * Returns +self+ if any changes were made, +nil+ otherwise.
+ * Like String#tr_s, except:
+ *
+ * - Modifies +self+ in place (not a copy of +self+).
+ * - Returns +self+ if any changes were made, +nil+ otherwise.
*
- * Related: String#squeeze!.
+ * Related: {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -9012,16 +8947,21 @@ rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
/*
* call-seq:
- * tr_s(selector, replacements) -> string
+ * tr_s(selector, replacements) -> new_string
*
- * Like String#tr, but also squeezes the modified portions of the translated string;
- * returns a new string (translated and squeezed).
+ * Like String#tr, except:
+ *
+ * - Also squeezes the modified portions of the translated string;
+ * see String#squeeze.
+ * - Returns the translated and squeezed string.
+ *
+ * Examples:
*
* 'hello'.tr_s('l', 'r') #=> "hero"
* 'hello'.tr_s('el', '-') #=> "h-o"
* 'hello'.tr_s('el', 'hx') #=> "hhxo"
*
- * Related: String#squeeze.
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*
*/
@@ -9038,23 +8978,7 @@ rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
* call-seq:
* count(*selectors) -> integer
*
- * Returns the total number of characters in +self+
- * that are specified by the given +selectors+
- * (see {Multiple Character Selectors}[rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors]):
- *
- * a = "hello world"
- * a.count "lo" #=> 5
- * a.count "lo", "o" #=> 2
- * a.count "hello", "^l" #=> 4
- * a.count "ej-m" #=> 4
- *
- * "hello^world".count "\\^aeiou" #=> 4
- * "hello-world".count "a\\-eo" #=> 4
- *
- * c = "hello world\\r\\n"
- * c.count "\\" #=> 2
- * c.count "\\A" #=> 0
- * c.count "X-\\w" #=> 3
+ * :include: doc/string/count.rdoc
*/
static VALUE
@@ -9217,7 +9141,7 @@ literal_split_pattern(VALUE spat, split_type_t default_type)
/*
* call-seq:
- * split(field_sep = $;, limit = 0) -> array
+ * split(field_sep = $;, limit = 0) -> array_of_substrings
* split(field_sep = $;, limit = 0) {|substring| ... } -> self
*
* :include: doc/string/split.rdoc
@@ -9289,11 +9213,15 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str)
}
}
-#define SPLIT_STR(beg, len) (empty_count = split_string(result, str, beg, len, empty_count))
+#define SPLIT_STR(beg, len) ( \
+ empty_count = split_string(result, str, beg, len, empty_count), \
+ str_mod_check(str, str_start, str_len))
beg = 0;
char *ptr = RSTRING_PTR(str);
- char *eptr = RSTRING_END(str);
+ char *const str_start = ptr;
+ const long str_len = RSTRING_LEN(str);
+ char *const eptr = str_start + str_len;
if (split_type == SPLIT_TYPE_AWK) {
char *bptr = ptr;
int skip = 1;
@@ -9354,7 +9282,6 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str)
}
}
else if (split_type == SPLIT_TYPE_STRING) {
- char *str_start = ptr;
char *substr_start = ptr;
char *sptr = RSTRING_PTR(spat);
long slen = RSTRING_LEN(spat);
@@ -9371,6 +9298,7 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str)
continue;
}
SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
+ str_mod_check(spat, sptr, slen);
ptr += end + slen;
substr_start = ptr;
if (!NIL_P(limit) && lim <= ++i) break;
@@ -9378,7 +9306,6 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str)
beg = ptr - str_start;
}
else if (split_type == SPLIT_TYPE_CHARS) {
- char *str_start = ptr;
int n;
if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
@@ -9396,18 +9323,16 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str)
if (result) result = rb_ary_new();
long len = RSTRING_LEN(str);
long start = beg;
- long idx;
+ int idx;
int last_null = 0;
- struct re_registers *regs;
VALUE match = 0;
for (; rb_reg_search(spat, str, start, 0) >= 0;
(match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
match = rb_backref_get();
if (!result) rb_match_busy(match);
- regs = RMATCH_REGS(match);
- end = BEG(0);
- if (start == end && BEG(0) == END(0)) {
+ end = RMATCH_BEG(match, 0);
+ if (start == end && RMATCH_BEG(match, 0) == RMATCH_END(match, 0)) {
if (!ptr) {
SPLIT_STR(0, 0);
break;
@@ -9427,13 +9352,13 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str)
}
else {
SPLIT_STR(beg, end-beg);
- beg = start = END(0);
+ beg = start = RMATCH_END(match, 0);
}
last_null = 0;
- for (idx=1; idx < regs->num_regs; idx++) {
- if (BEG(idx) == -1) continue;
- SPLIT_STR(BEG(idx), END(idx)-BEG(idx));
+ for (idx = 1; idx < RMATCH_NREGS(match); idx++) {
+ if (RMATCH_BEG(match, idx) == -1) continue;
+ SPLIT_STR(RMATCH_BEG(match, idx), RMATCH_END(match, idx) - RMATCH_BEG(match, idx));
}
if (!NIL_P(limit) && lim <= ++i) break;
}
@@ -9643,8 +9568,8 @@ rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
/*
* call-seq:
- * each_line(line_sep = $/, chomp: false) {|substring| ... } -> self
- * each_line(line_sep = $/, chomp: false) -> enumerator
+ * each_line(record_separator = $/, chomp: false) {|substring| ... } -> self
+ * each_line(record_separator = $/, chomp: false) -> enumerator
*
* :include: doc/string/each_line.rdoc
*
@@ -9659,11 +9584,53 @@ rb_str_each_line(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * lines(Line_sep = $/, chomp: false) -> array_of_strings
+ * lines(record_separator = $/, chomp: false) -> array_of_strings
+ *
+ * Returns substrings ("lines") of +self+
+ * according to the given arguments:
+ *
+ * s = <<~EOT
+ * This is the first line.
+ * This is line two.
+ *
+ * This is line four.
+ * This is line five.
+ * EOT
+ *
+ * With the default argument values:
+ *
+ * $/ # => "\n"
+ * s.lines
+ * # =>
+ * ["This is the first line.\n",
+ * "This is line two.\n",
+ * "\n",
+ * "This is line four.\n",
+ * "This is line five.\n"]
*
- * Forms substrings ("lines") of +self+ according to the given arguments
- * (see String#each_line for details); returns the lines in an array.
+ * With a different +record_separator+:
*
+ * record_separator = ' is '
+ * s.lines(record_separator)
+ * # =>
+ * ["This is ",
+ * "the first line.\nThis is ",
+ * "line two.\n\nThis is ",
+ * "line four.\nThis is ",
+ * "line five.\n"]
+ *
+ * With keyword argument +chomp+ as +true+,
+ * removes the trailing newline from each line:
+ *
+ * s.lines(chomp: true)
+ * # =>
+ * ["This is the first line.",
+ * "This is line two.",
+ * "",
+ * "This is line four.",
+ * "This is line five."]
+ *
+ * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
*/
static VALUE
@@ -9764,7 +9731,7 @@ rb_str_enumerate_chars(VALUE str, VALUE ary)
/*
* call-seq:
- * each_char {|c| ... } -> self
+ * each_char {|char| ... } -> self
* each_char -> enumerator
*
* :include: doc/string/each_char.rdoc
@@ -9801,6 +9768,7 @@ rb_str_enumerate_codepoints(VALUE str, VALUE ary)
unsigned int c;
const char *ptr, *end;
rb_encoding *enc;
+ int enc_asciicompat;
if (single_byte_optimizable(str))
return rb_str_enumerate_bytes(str, ary);
@@ -9809,9 +9777,15 @@ rb_str_enumerate_codepoints(VALUE str, VALUE ary)
ptr = RSTRING_PTR(str);
end = RSTRING_END(str);
enc = STR_ENC_GET(str);
+ enc_asciicompat = rb_enc_asciicompat(enc);
while (ptr < end) {
- c = rb_enc_codepoint_len(ptr, end, &n, enc);
+ /* Fast path: ASCII byte in an ASCII-compatible encoding is its own codepoint;
+ * skip rb_enc_codepoint_len and return the byte directly.
+ */
+ n = 1;
+ c = (enc_asciicompat && ISASCII(*ptr)) ?
+ (unsigned char)*ptr : rb_enc_codepoint_len(ptr, end, &n, enc);
ENUM_ELEM(ary, UINT2NUM(c));
ptr += n;
}
@@ -9824,7 +9798,7 @@ rb_str_enumerate_codepoints(VALUE str, VALUE ary)
/*
* call-seq:
- * each_codepoint {|integer| ... } -> self
+ * each_codepoint {|codepoint| ... } -> self
* each_codepoint -> enumerator
*
* :include: doc/string/each_codepoint.rdoc
@@ -9994,7 +9968,7 @@ rb_str_enumerate_grapheme_clusters(VALUE str, VALUE ary)
/*
* call-seq:
- * each_grapheme_cluster {|gc| ... } -> self
+ * each_grapheme_cluster {|grapheme_cluster| ... } -> self
* each_grapheme_cluster -> enumerator
*
* :include: doc/string/each_grapheme_cluster.rdoc
@@ -10045,10 +10019,12 @@ chopped_length(VALUE str)
* call-seq:
* chop! -> self or nil
*
- * Like String#chop, but modifies +self+ in place;
- * returns +nil+ if +self+ is empty, +self+ otherwise.
+ * Like String#chop, except that:
+ *
+ * - Removes trailing characters from +self+ (not from a copy of +self+).
+ * - Returns +self+ if any characters are removed, +nil+ otherwise.
*
- * Related: String#chomp!.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -10225,9 +10201,12 @@ rb_str_chomp_string(VALUE str, VALUE rs)
* call-seq:
* chomp!(line_sep = $/) -> self or nil
*
- * Like String#chomp, but modifies +self+ in place;
- * returns +nil+ if no modification made, +self+ otherwise.
+ * Like String#chomp, except that:
*
+ * - Removes trailing characters from +self+ (not from a copy of +self+).
+ * - Returns +self+ if any characters are removed, +nil+ otherwise.
+ *
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -10258,6 +10237,22 @@ rb_str_chomp(int argc, VALUE *argv, VALUE str)
return rb_str_subseq(str, 0, chompped_length(str, rs));
}
+static void
+tr_setup_table_multi(char table[TR_TABLE_SIZE], VALUE *tablep, VALUE *ctablep,
+ VALUE str, int num_selectors, VALUE *selectors)
+{
+ int i;
+
+ for (i=0; i<num_selectors; i++) {
+ VALUE selector = selectors[i];
+ rb_encoding *enc;
+
+ StringValue(selector);
+ enc = rb_enc_check(str, selector);
+ tr_setup_table(selector, table, i==0, tablep, ctablep, enc);
+ }
+}
+
static long
lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
{
@@ -10281,18 +10276,39 @@ lstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
return s - start;
}
+static long
+lstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
+ char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
+{
+ const char *const start = s;
+
+ if (!s || s >= e) return 0;
+
+ /* remove leading characters in the table */
+ while (s < e) {
+ int n;
+ unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
+
+ if (!tr_find(cc, table, del, nodel)) break;
+ s += n;
+ }
+ return s - start;
+}
+
/*
* call-seq:
- * lstrip! -> self or nil
+ * lstrip!(*selectors) -> self or nil
+ *
+ * Like String#lstrip, except that:
*
- * Like String#lstrip, except that any modifications are made in +self+;
- * returns +self+ if any modification are made, +nil+ otherwise.
+ * - Performs stripping in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any characters are stripped, +nil+ otherwise.
*
- * Related: String#rstrip!, String#strip!.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
-rb_str_lstrip_bang(VALUE str)
+rb_str_lstrip_bang(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
char *start, *s;
@@ -10301,7 +10317,17 @@ rb_str_lstrip_bang(VALUE str)
str_modify_keep_cr(str);
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
- loffset = lstrip_offset(str, start, start+olen, enc);
+ if (argc > 0) {
+ char table[TR_TABLE_SIZE];
+ VALUE del = 0, nodel = 0;
+
+ tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
+ loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
+ }
+ else {
+ loffset = lstrip_offset(str, start, start+olen, enc);
+ }
+
if (loffset > 0) {
long len = olen-loffset;
s = start + loffset;
@@ -10316,26 +10342,48 @@ rb_str_lstrip_bang(VALUE str)
/*
* call-seq:
- * lstrip -> new_string
+ * lstrip(*selectors) -> new_string
*
* Returns a copy of +self+ with leading whitespace removed;
* see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
*
* whitespace = "\x00\t\n\v\f\r "
* s = whitespace + 'abc' + whitespace
- * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
- * s.lstrip # => "abc\u0000\t\n\v\f\r "
+ * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
+ * s.lstrip
+ * # => "abc\u0000\t\n\v\f\r "
*
- * Related: String#rstrip, String#strip.
+ * If +selectors+ are given, removes characters of +selectors+ from the beginning of +self+:
+ *
+ * s = "---abc+++"
+ * s.lstrip("-") # => "abc+++"
+ *
+ * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
+ * and may use any of its valid forms, including negation, ranges, and escapes:
+ *
+ * "01234abc56789".lstrip("0-9") # "abc56789"
+ * "01234abc56789".lstrip("0-9", "^4-6") # "4abc56789"
+ *
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
-rb_str_lstrip(VALUE str)
+rb_str_lstrip(int argc, VALUE *argv, VALUE str)
{
char *start;
long len, loffset;
+
RSTRING_GETMEM(str, start, len);
- loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
+ if (argc > 0) {
+ char table[TR_TABLE_SIZE];
+ VALUE del = 0, nodel = 0;
+
+ tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
+ loffset = lstrip_offset_table(str, start, start+len, STR_ENC_GET(str), table, del, nodel);
+ }
+ else {
+ loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
+ }
if (loffset <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, loffset, len - loffset);
}
@@ -10369,18 +10417,44 @@ rstrip_offset(VALUE str, const char *s, const char *e, rb_encoding *enc)
return e - t;
}
+static long
+rstrip_offset_table(VALUE str, const char *s, const char *e, rb_encoding *enc,
+ char table[TR_TABLE_SIZE], VALUE del, VALUE nodel)
+{
+ const char *t;
+ char *tp;
+
+ rb_str_check_dummy_enc(enc);
+ if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
+ rb_raise(rb_eEncCompatError, "invalid byte sequence in %s", rb_enc_name(enc));
+ }
+ if (!s || s >= e) return 0;
+ t = e;
+
+ /* remove trailing characters in the table */
+ while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) {
+ unsigned int c = rb_enc_codepoint(tp, e, enc);
+ if (!tr_find(c, table, del, nodel)) break;
+ t = tp;
+ }
+
+ return e - t;
+}
+
/*
* call-seq:
- * rstrip! -> self or nil
+ * rstrip!(*selectors) -> self or nil
+ *
+ * Like String#rstrip, except that:
*
- * Like String#rstrip, except that any modifications are made in +self+;
- * returns +self+ if any modification are made, +nil+ otherwise.
+ * - Performs stripping in +self+ (not in a copy of +self+).
+ * - Returns +self+ if any characters are stripped, +nil+ otherwise.
*
- * Related: String#lstrip!, String#strip!.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
-rb_str_rstrip_bang(VALUE str)
+rb_str_rstrip_bang(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
char *start;
@@ -10389,7 +10463,16 @@ rb_str_rstrip_bang(VALUE str)
str_modify_keep_cr(str);
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
- roffset = rstrip_offset(str, start, start+olen, enc);
+ if (argc > 0) {
+ char table[TR_TABLE_SIZE];
+ VALUE del = 0, nodel = 0;
+
+ tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
+ roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
+ }
+ else {
+ roffset = rstrip_offset(str, start, start+olen, enc);
+ }
if (roffset > 0) {
long len = olen - roffset;
@@ -10403,9 +10486,9 @@ rb_str_rstrip_bang(VALUE str)
/*
* call-seq:
- * rstrip -> new_string
+ * rstrip(*selectors) -> new_string
*
- * Returns a copy of the receiver with trailing whitespace removed;
+ * Returns a copy of +self+ with trailing whitespace removed;
* see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
*
* whitespace = "\x00\t\n\v\f\r "
@@ -10413,11 +10496,22 @@ rb_str_rstrip_bang(VALUE str)
* s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
* s.rstrip # => "\u0000\t\n\v\f\r abc"
*
- * Related: String#lstrip, String#strip.
+ * If +selectors+ are given, removes characters of +selectors+ from the end of +self+:
+ *
+ * s = "---abc+++"
+ * s.rstrip("+") # => "---abc"
+ *
+ * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
+ * and may use any of its valid forms, including negation, ranges, and escapes:
+ *
+ * "01234abc56789".rstrip("0-9") # "01234abc"
+ * "01234abc56789".rstrip("0-9", "^4-6") # "01234abc56"
+ *
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
-rb_str_rstrip(VALUE str)
+rb_str_rstrip(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
char *start;
@@ -10425,8 +10519,16 @@ rb_str_rstrip(VALUE str)
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
- roffset = rstrip_offset(str, start, start+olen, enc);
+ if (argc > 0) {
+ char table[TR_TABLE_SIZE];
+ VALUE del = 0, nodel = 0;
+ tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
+ roffset = rstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
+ }
+ else {
+ roffset = rstrip_offset(str, start, start+olen, enc);
+ }
if (roffset <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, 0, olen-roffset);
}
@@ -10434,16 +10536,18 @@ rb_str_rstrip(VALUE str)
/*
* call-seq:
- * strip! -> self or nil
+ * strip!(*selectors) -> self or nil
*
- * Like String#strip, except that any modifications are made in +self+;
- * returns +self+ if any modification are made, +nil+ otherwise.
+ * Like String#strip, except that:
*
- * Related: String#lstrip!, String#strip!.
+ * - Any modifications are made to +self+.
+ * - Returns +self+ if any modification are made, +nil+ otherwise.
+ *
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
-rb_str_strip_bang(VALUE str)
+rb_str_strip_bang(int argc, VALUE *argv, VALUE str)
{
char *start;
long olen, loffset, roffset;
@@ -10452,8 +10556,19 @@ rb_str_strip_bang(VALUE str)
str_modify_keep_cr(str);
enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
- loffset = lstrip_offset(str, start, start+olen, enc);
- roffset = rstrip_offset(str, start+loffset, start+olen, enc);
+
+ if (argc > 0) {
+ char table[TR_TABLE_SIZE];
+ VALUE del = 0, nodel = 0;
+
+ tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
+ loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
+ roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
+ }
+ else {
+ loffset = lstrip_offset(str, start, start+olen, enc);
+ roffset = rstrip_offset(str, start+loffset, start+olen, enc);
+ }
if (loffset > 0 || roffset > 0) {
long len = olen-roffset;
@@ -10471,29 +10586,52 @@ rb_str_strip_bang(VALUE str)
/*
* call-seq:
- * strip -> new_string
+ * strip(*selectors) -> new_string
*
- * Returns a copy of the receiver with leading and trailing whitespace removed;
+ * Returns a copy of +self+ with leading and trailing whitespace removed;
* see {Whitespace in Strings}[rdoc-ref:String@Whitespace+in+Strings]:
*
* whitespace = "\x00\t\n\v\f\r "
* s = whitespace + 'abc' + whitespace
- * s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
+ * # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
* s.strip # => "abc"
*
- * Related: String#lstrip, String#rstrip.
+ * If +selectors+ are given, removes characters of +selectors+ from both ends of +self+:
+ *
+ * s = "---abc+++"
+ * s.strip("-+") # => "abc"
+ * s.strip("+-") # => "abc"
+ *
+ * +selectors+ must be valid character selectors (see {Character Selectors}[rdoc-ref:character_selectors.rdoc]),
+ * and may use any of its valid forms, including negation, ranges, and escapes:
+ *
+ * "01234abc56789".strip("0-9") # "abc"
+ * "01234abc56789".strip("0-9", "^4-6") # "4abc56"
+ *
+ * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
-rb_str_strip(VALUE str)
+rb_str_strip(int argc, VALUE *argv, VALUE str)
{
char *start;
long olen, loffset, roffset;
rb_encoding *enc = STR_ENC_GET(str);
RSTRING_GETMEM(str, start, olen);
- loffset = lstrip_offset(str, start, start+olen, enc);
- roffset = rstrip_offset(str, start+loffset, start+olen, enc);
+
+ if (argc > 0) {
+ char table[TR_TABLE_SIZE];
+ VALUE del = 0, nodel = 0;
+
+ tr_setup_table_multi(table, &del, &nodel, str, argc, argv);
+ loffset = lstrip_offset_table(str, start, start+olen, enc, table, del, nodel);
+ roffset = rstrip_offset_table(str, start+loffset, start+olen, enc, table, del, nodel);
+ }
+ else {
+ loffset = lstrip_offset(str, start, start+olen, enc);
+ roffset = rstrip_offset(str, start+loffset, start+olen, enc);
+ }
if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
return rb_str_subseq(str, loffset, olen-loffset-roffset);
@@ -10505,17 +10643,14 @@ scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
VALUE result = Qnil;
long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
if (pos >= 0) {
- VALUE match;
- struct re_registers *regs;
+ VALUE match = Qnil;
if (BUILTIN_TYPE(pat) == T_STRING) {
- regs = NULL;
end = pos + RSTRING_LEN(pat);
}
else {
match = rb_backref_get();
- regs = RMATCH_REGS(match);
- pos = BEG(0);
- end = END(0);
+ pos = RMATCH_BEG(match, 0);
+ end = RMATCH_END(match, 0);
}
if (pos == end) {
@@ -10533,16 +10668,17 @@ scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
*start = end;
}
- if (!regs || regs->num_regs == 1) {
+ if (NIL_P(match) || RMATCH_NREGS(match) == 1) {
result = rb_str_subseq(str, pos, end - pos);
return result;
}
else {
- result = rb_ary_new2(regs->num_regs);
- for (int i = 1; i < regs->num_regs; i++) {
+ int num_regs = RMATCH_NREGS(match);
+ result = rb_ary_new2(num_regs);
+ for (int i = 1; i < num_regs; i++) {
VALUE s = Qnil;
- if (BEG(i) >= 0) {
- s = rb_str_subseq(str, BEG(i), END(i)-BEG(i));
+ if (RMATCH_BEG(match, i) >= 0) {
+ s = rb_str_subseq(str, RMATCH_BEG(match, i), RMATCH_END(match, i) - RMATCH_BEG(match, i));
}
rb_ary_push(result, s);
@@ -10558,40 +10694,10 @@ scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
/*
* call-seq:
- * scan(string_or_regexp) -> array
- * scan(string_or_regexp) {|matches| ... } -> self
- *
- * Matches a pattern against +self+; the pattern is:
- *
- * - +string_or_regexp+ itself, if it is a Regexp.
- * - <tt>Regexp.quote(string_or_regexp)</tt>, if +string_or_regexp+ is a string.
- *
- * Iterates through +self+, generating a collection of matching results:
- *
- * - If the pattern contains no groups, each result is the
- * matched string, <code>$&</code>.
- * - If the pattern contains groups, each result is an array
- * containing one entry per group.
- *
- * With no block given, returns an array of the results:
- *
- * s = 'cruel world'
- * s.scan(/\w+/) # => ["cruel", "world"]
- * s.scan(/.../) # => ["cru", "el ", "wor"]
- * s.scan(/(...)/) # => [["cru"], ["el "], ["wor"]]
- * s.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]]
+ * scan(pattern) -> array_of_results
+ * scan(pattern) {|result| ... } -> self
*
- * With a block given, calls the block with each result; returns +self+:
- *
- * s.scan(/\w+/) {|w| print "<<#{w}>> " }
- * print "\n"
- * s.scan(/(.)(.)/) {|x,y| print y, x }
- * print "\n"
- *
- * Output:
- *
- * <<cruel>> <<world>>
- * rceu lowlr
+ * :include: doc/string/scan.rdoc
*
*/
@@ -10633,18 +10739,46 @@ rb_str_scan(VALUE str, VALUE pat)
* call-seq:
* hex -> integer
*
- * Interprets the leading substring of +self+ as a string of hexadecimal digits
- * (with an optional sign and an optional <code>0x</code>) and returns the
- * corresponding number;
- * returns zero if there is no such leading substring:
+ * Interprets the leading substring of +self+ as hexadecimal, possibly signed;
+ * returns its value as an integer.
+ *
+ * The leading substring is interpreted as hexadecimal when it begins with:
+ *
+ * - One or more character representing hexadecimal digits
+ * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
+ * the string to be interpreted ends at the first character that does not represent a hexadecimal digit:
+ *
+ * 'f'.hex # => 15
+ * '11'.hex # => 17
+ * 'FFF'.hex # => 4095
+ * 'fffg'.hex # => 4095
+ * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not.
+ * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not.
+ * 'deadbeef'.hex # => 3735928559
+ *
+ * - <tt>'0x'</tt> or <tt>'0X'</tt>, followed by one or more hexadecimal digits:
+ *
+ * '0xfff'.hex # => 4095
+ * '0xfffg'.hex # => 4095
+ *
+ * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
+ *
+ * '-fff'.hex # => -4095
+ * '-0xFFF'.hex # => -4095
+ *
+ * For any substring not described above, returns zero:
*
- * '0x0a'.hex # => 10
- * '-1234'.hex # => -4660
- * '0'.hex # => 0
- * 'non-numeric'.hex # => 0
+ * 'xxx'.hex # => 0
+ * ''.hex # => 0
*
- * Related: String#oct.
+ * Note that, unlike #oct, this method interprets only hexadecimal,
+ * and not binary, octal, or decimal notations:
*
+ * '0b111'.hex # => 45329
+ * '0o777'.hex # => 0
+ * '0d999'.hex # => 55705
+ *
+ * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
*/
static VALUE
@@ -10658,20 +10792,79 @@ rb_str_hex(VALUE str)
* call-seq:
* oct -> integer
*
- * Interprets the leading substring of +self+ as a string of octal digits
- * (with an optional sign) and returns the corresponding number;
- * returns zero if there is no such leading substring:
+ * Interprets the leading substring of +self+ as octal, binary, decimal, or hexadecimal, possibly signed;
+ * returns their value as an integer.
+ *
+ * In brief:
+ *
+ * # Interpreted as octal.
+ * '777'.oct # => 511
+ * '777x'.oct # => 511
+ * '0777'.oct # => 511
+ * '0o777'.oct # => 511
+ * '-777'.oct # => -511
+ * # Not interpreted as octal.
+ * '0b111'.oct # => 7 # Interpreted as binary.
+ * '0d999'.oct # => 999 # Interpreted as decimal.
+ * '0xfff'.oct # => 4095 # Interpreted as hexadecimal.
+ *
+ * The leading substring is interpreted as octal when it begins with:
+ *
+ * - One or more character representing octal digits
+ * (each in the range <tt>'0'..'7'</tt>);
+ * the string to be interpreted ends at the first character that does not represent an octal digit:
+ *
+ * '7'.oct @ => 7
+ * '11'.oct # => 9
+ * '777'.oct # => 511
+ * '0777'.oct # => 511
+ * '7778'.oct # => 511
+ * '777x'.oct # => 511
+ *
+ * - <tt>'0o'</tt>, followed by one or more octal digits:
+ *
+ * '0o777'.oct # => 511
+ * '0o7778'.oct # => 511
+ *
+ * The leading substring is _not_ interpreted as octal when it begins with:
+ *
+ * - <tt>'0b'</tt>, followed by one or more characters representing binary digits
+ * (each in the range <tt>'0'..'1'</tt>);
+ * the string to be interpreted ends at the first character that does not represent a binary digit.
+ * the string is interpreted as binary digits (base 2):
*
- * '123'.oct # => 83
- * '-377'.oct # => -255
- * '0377non-numeric'.oct # => 255
- * 'non-numeric'.oct # => 0
+ * '0b111'.oct # => 7
+ * '0b1112'.oct # => 7
*
- * If +self+ starts with <tt>0</tt>, radix indicators are honored;
- * see Kernel#Integer.
+ * - <tt>'0d'</tt>, followed by one or more characters representing decimal digits
+ * (each in the range <tt>'0'..'9'</tt>);
+ * the string to be interpreted ends at the first character that does not represent a decimal digit.
+ * the string is interpreted as decimal digits (base 10):
*
- * Related: String#hex.
+ * '0d999'.oct # => 999
+ * '0d999x'.oct # => 999
*
+ * - <tt>'0x'</tt>, followed by one or more characters representing hexadecimal digits
+ * (each in one of the ranges <tt>'0'..'9'</tt>, <tt>'a'..'f'</tt>, or <tt>'A'..'F'</tt>);
+ * the string to be interpreted ends at the first character that does not represent a hexadecimal digit.
+ * the string is interpreted as hexadecimal digits (base 16):
+ *
+ * '0xfff'.oct # => 4095
+ * '0xfffg'.oct # => 4095
+ *
+ * Any of the above may prefixed with <tt>'-'</tt>, which negates the interpreted value:
+ *
+ * '-777'.oct # => -511
+ * '-0777'.oct # => -511
+ * '-0b111'.oct # => -7
+ * '-0xfff'.oct # => -4095
+ *
+ * For any substring not described above, returns zero:
+ *
+ * 'foo'.oct # => 0
+ * ''.oct # => 0
+ *
+ * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non-String].
*/
static VALUE
@@ -10687,11 +10880,6 @@ rb_str_oct(VALUE str)
static struct {
rb_nativethread_lock_t lock;
} crypt_mutex = {PTHREAD_MUTEX_INITIALIZER};
-
-static void
-crypt_mutex_initialize(void)
-{
-}
#endif
/*
@@ -10762,6 +10950,7 @@ rb_str_crypt(VALUE str, VALUE salt)
struct crypt_data *data;
# define CRYPT_END() ALLOCV_END(databuf)
#else
+ char *tmp_buf;
extern char *crypt(const char *, const char *);
# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
#endif
@@ -10796,7 +10985,6 @@ rb_str_crypt(VALUE str, VALUE salt)
# endif
res = crypt_r(s, saltp, data);
#else
- crypt_mutex_initialize();
rb_nativethread_lock_lock(&crypt_mutex.lock);
res = crypt(s, saltp);
#endif
@@ -10805,8 +10993,21 @@ rb_str_crypt(VALUE str, VALUE salt)
CRYPT_END();
rb_syserr_fail(err, "crypt");
}
+#ifdef HAVE_CRYPT_R
result = rb_str_new_cstr(res);
CRYPT_END();
+#else
+ // We need to copy this buffer because it's static and we need to unlock the mutex
+ // before allocating a new object (the string to be returned). If we allocate while
+ // holding the lock, we could run GC which fires the VM barrier and causes a deadlock
+ // if other ractors are waiting on this lock.
+ size_t res_size = strlen(res)+1;
+ tmp_buf = ALLOCA_N(char, res_size); // should be small enough to alloca
+ memcpy(tmp_buf, res, res_size);
+ res = tmp_buf;
+ CRYPT_END();
+ result = rb_str_new_cstr(res);
+#endif
return result;
}
@@ -10924,48 +11125,48 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
rlen = n - llen;
cr = ENC_CODERANGE(str);
if (flen > 1) {
- llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
- rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
+ llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
+ rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
}
size = RSTRING_LEN(str);
if ((len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
- (len *= flen) >= LONG_MAX - llen2 - rlen2 ||
- (len += llen2 + rlen2) >= LONG_MAX - size) {
- rb_raise(rb_eArgError, "argument too big");
+ (len *= flen) >= LONG_MAX - llen2 - rlen2 ||
+ (len += llen2 + rlen2) >= LONG_MAX - size) {
+ rb_raise(rb_eArgError, "argument too big");
}
len += size;
res = str_enc_new(rb_cString, 0, len, enc);
p = RSTRING_PTR(res);
if (flen <= 1) {
- memset(p, *f, llen);
- p += llen;
+ memset(p, *f, llen);
+ p += llen;
}
else {
- while (llen >= fclen) {
+ while (llen >= fclen) {
memcpy(p,f,flen);
p += flen;
llen -= fclen;
}
- if (llen > 0) {
- memcpy(p, f, llen2);
- p += llen2;
+ if (llen > 0) {
+ memcpy(p, f, llen2);
+ p += llen2;
}
}
memcpy(p, RSTRING_PTR(str), size);
p += size;
if (flen <= 1) {
- memset(p, *f, rlen);
- p += rlen;
+ memset(p, *f, rlen);
+ p += rlen;
}
else {
- while (rlen >= fclen) {
+ while (rlen >= fclen) {
memcpy(p,f,flen);
p += flen;
rlen -= fclen;
}
- if (rlen > 0) {
- memcpy(p, f, rlen2);
- p += rlen2;
+ if (rlen > 0) {
+ memcpy(p, f, rlen2);
+ p += rlen2;
}
}
TERM_FILL(p, termlen);
@@ -10983,12 +11184,10 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
/*
* call-seq:
- * ljust(size, pad_string = ' ') -> new_string
+ * ljust(width, pad_string = ' ') -> new_string
*
* :include: doc/string/ljust.rdoc
*
- * Related: String#rjust, String#center.
- *
*/
static VALUE
@@ -10999,12 +11198,10 @@ rb_str_ljust(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * rjust(size, pad_string = ' ') -> new_string
+ * rjust(width, pad_string = ' ') -> new_string
*
* :include: doc/string/rjust.rdoc
*
- * Related: String#ljust, String#center.
- *
*/
static VALUE
@@ -11020,8 +11217,6 @@ rb_str_rjust(int argc, VALUE *argv, VALUE str)
*
* :include: doc/string/center.rdoc
*
- * Related: String#ljust, String#rjust.
- *
*/
static VALUE
@@ -11032,7 +11227,7 @@ rb_str_center(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * partition(string_or_regexp) -> [head, match, tail]
+ * partition(pattern) -> [pre_match, first_match, post_match]
*
* :include: doc/string/partition.rdoc
*
@@ -11049,10 +11244,9 @@ rb_str_partition(VALUE str, VALUE sep)
goto failed;
}
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
- pos = BEG(0);
- sep = rb_str_subseq(str, pos, END(0) - pos);
+ pos = RMATCH_BEG(match, 0);
+ sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
}
else {
pos = rb_str_index(str, sep, 0);
@@ -11069,7 +11263,7 @@ rb_str_partition(VALUE str, VALUE sep)
/*
* call-seq:
- * rpartition(sep) -> [head, match, tail]
+ * rpartition(pattern) -> [pre_match, last_match, post_match]
*
* :include: doc/string/rpartition.rdoc
*
@@ -11086,10 +11280,9 @@ rb_str_rpartition(VALUE str, VALUE sep)
goto failed;
}
VALUE match = rb_backref_get();
- struct re_registers *regs = RMATCH_REGS(match);
- pos = BEG(0);
- sep = rb_str_subseq(str, pos, END(0) - pos);
+ pos = RMATCH_BEG(match, 0);
+ sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos);
}
else {
pos = rb_str_sublen(str, pos);
@@ -11109,7 +11302,7 @@ rb_str_rpartition(VALUE str, VALUE sep)
/*
* call-seq:
- * start_with?(*string_or_regexp) -> true or false
+ * start_with?(*patterns) -> true or false
*
* :include: doc/string/start_with_p.rdoc
*
@@ -11234,9 +11427,10 @@ deleted_prefix_length(VALUE str, VALUE prefix)
* call-seq:
* delete_prefix!(prefix) -> self or nil
*
- * Like String#delete_prefix, except that +self+ is modified in place.
- * Returns +self+ if the prefix is removed, +nil+ otherwise.
+ * Like String#delete_prefix, except that +self+ is modified in place;
+ * returns +self+ if the prefix is removed, +nil+ otherwise.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -11309,9 +11503,10 @@ deleted_suffix_length(VALUE str, VALUE suffix)
* call-seq:
* delete_suffix!(suffix) -> self or nil
*
- * Like String#delete_suffix, except that +self+ is modified in place.
- * Returns +self+ if the suffix is removed, +nil+ otherwise.
+ * Like String#delete_suffix, except that +self+ is modified in place;
+ * returns +self+ if the suffix is removed, +nil+ otherwise.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -11363,6 +11558,21 @@ rb_str_setter(VALUE val, ID id, VALUE *var)
}
static void
+nil_setter_warning(ID id)
+{
+ rb_warn_deprecated("non-nil '%"PRIsVALUE"'", NULL, rb_id2str(id));
+}
+
+void
+rb_deprecated_str_setter(VALUE val, ID id, VALUE *var)
+{
+ rb_str_setter(val, id, var);
+ if (!NIL_P(*var)) {
+ nil_setter_warning(id);
+ }
+}
+
+static void
rb_fs_setter(VALUE val, ID id, VALUE *var)
{
val = rb_fs_check(val);
@@ -11372,7 +11582,7 @@ rb_fs_setter(VALUE val, ID id, VALUE *var)
rb_id2str(id));
}
if (!NIL_P(val)) {
- rb_warn_deprecated("'$;'", NULL);
+ nil_setter_warning(id);
}
*var = val;
}
@@ -11413,7 +11623,7 @@ rb_str_force_encoding(VALUE str, VALUE enc)
/*
* call-seq:
- * b -> string
+ * b -> new_string
*
* :include: doc/string/b.rdoc
*
@@ -11456,11 +11666,8 @@ rb_str_b(VALUE str)
* call-seq:
* valid_encoding? -> true or false
*
- * Returns +true+ if +self+ is encoded correctly, +false+ otherwise:
+ * :include: doc/string/valid_encoding_p.rdoc
*
- * "\xc2\xa1".force_encoding(Encoding::UTF_8).valid_encoding? # => true
- * "\xc2".force_encoding(Encoding::UTF_8).valid_encoding? # => false
- * "\x80".force_encoding(Encoding::UTF_8).valid_encoding? # => false
*/
static VALUE
@@ -11475,12 +11682,12 @@ rb_str_valid_encoding_p(VALUE str)
* call-seq:
* ascii_only? -> true or false
*
- * Returns +true+ if +self+ contains only ASCII characters,
- * +false+ otherwise:
+ * Returns whether +self+ contains only ASCII characters:
*
* 'abc'.ascii_only? # => true
* "abc\u{6666}".ascii_only? # => false
*
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
@@ -11596,7 +11803,7 @@ enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
encidx = rb_enc_to_index(enc);
#define DEFAULT_REPLACE_CHAR(str) do { \
- static const char replace[sizeof(str)-1] = str; \
+ RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \
rep = replace; replen = (int)sizeof(replace); \
} while (0)
@@ -11639,6 +11846,12 @@ enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
else if (MBCLEN_CHARFOUND_P(ret)) {
cr = ENC_CODERANGE_VALID;
p += MBCLEN_CHARFOUND_LEN(ret);
+ /* After a multibyte character, fast-skip the following ASCII run. */
+ p = search_nonascii(p, e);
+ if (!p) {
+ p = e;
+ break;
+ }
}
else if (MBCLEN_INVALID_P(ret)) {
/*
@@ -11812,8 +12025,8 @@ enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr)
/*
* call-seq:
- * scrub(replacement_string = default_replacement) -> new_string
- * scrub{|bytes| ... } -> new_string
+ * scrub(replacement_string = default_replacement_string) -> new_string
+ * scrub{|sequence| ... } -> new_string
*
* :include: doc/string/scrub.rdoc
*
@@ -11828,11 +12041,15 @@ str_scrub(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * scrub! -> self
- * scrub!(replacement_string = default_replacement) -> self
- * scrub!{|bytes| ... } -> self
+ * scrub!(replacement_string = default_replacement_string) -> self
+ * scrub!{|sequence| ... } -> self
+ *
+ * Like String#scrub, except that:
+ *
+ * - Any replacements are made in +self+.
+ * - Returns +self+.
*
- * Like String#scrub, except that any replacements are made in +self+.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*
*/
static VALUE
@@ -11867,34 +12084,8 @@ unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id)
* call-seq:
* unicode_normalize(form = :nfc) -> string
*
- * Returns a copy of +self+ with
- * {Unicode normalization}[https://unicode.org/reports/tr15] applied.
+ * :include: doc/string/unicode_normalize.rdoc
*
- * Argument +form+ must be one of the following symbols
- * (see {Unicode normalization forms}[https://unicode.org/reports/tr15/#Norm_Forms]):
- *
- * - +:nfc+: Canonical decomposition, followed by canonical composition.
- * - +:nfd+: Canonical decomposition.
- * - +:nfkc+: Compatibility decomposition, followed by canonical composition.
- * - +:nfkd+: Compatibility decomposition.
- *
- * The encoding of +self+ must be one of:
- *
- * - Encoding::UTF_8
- * - Encoding::UTF_16BE
- * - Encoding::UTF_16LE
- * - Encoding::UTF_32BE
- * - Encoding::UTF_32LE
- * - Encoding::GB18030
- * - Encoding::UCS_2BE
- * - Encoding::UCS_4BE
- *
- * Examples:
- *
- * "a\u0300".unicode_normalize # => "a"
- * "\u00E0".unicode_normalize(:nfd) # => "a "
- *
- * Related: String#unicode_normalize!, String#unicode_normalized?.
*/
static VALUE
rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
@@ -11907,9 +12098,9 @@ rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
* unicode_normalize!(form = :nfc) -> self
*
* Like String#unicode_normalize, except that the normalization
- * is performed on +self+.
+ * is performed on +self+ (not on a copy of +self+).
*
- * Related String#unicode_normalized?.
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*
*/
static VALUE
@@ -11921,8 +12112,9 @@ rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
/* call-seq:
* unicode_normalized?(form = :nfc) -> true or false
*
- * Returns +true+ if +self+ is in the given +form+ of Unicode normalization,
- * +false+ otherwise.
+ * Returns whether +self+ is in the given +form+ of Unicode normalization;
+ * see String#unicode_normalize.
+ *
* The +form+ must be one of +:nfc+, +:nfd+, +:nfkc+, or +:nfkd+.
*
* Examples:
@@ -11936,10 +12128,9 @@ rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
* Raises an exception if +self+ is not in a Unicode encoding:
*
* s = "\xE0".force_encoding(Encoding::ISO_8859_1)
- * s.unicode_normalized? # Raises Encoding::CompatibilityError.
- *
- * Related: String#unicode_normalize, String#unicode_normalize!.
+ * s.unicode_normalized? # Raises Encoding::CompatibilityError
*
+ * Related: see {Querying}[rdoc-ref:String@Querying].
*/
static VALUE
rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
@@ -12011,8 +12202,8 @@ rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
*
* First, what's elsewhere. Class +Symbol+:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
*
* Here, class +Symbol+ provides methods that are useful for:
*
@@ -12071,9 +12262,9 @@ rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
/*
* call-seq:
- * symbol == object -> true or false
+ * self == other -> true or false
*
- * Returns +true+ if +object+ is the same object as +self+, +false+ otherwise.
+ * Returns whether +other+ is the same object as +self+.
*/
#define sym_equal rb_obj_equal
@@ -12231,18 +12422,24 @@ sym_succ(VALUE sym)
/*
* call-seq:
- * symbol <=> object -> -1, 0, +1, or nil
+ * self <=> other -> -1, 0, 1, or nil
+ *
+ * Compares +self+ and +other+, using String#<=>.
*
- * If +object+ is a symbol,
- * returns the equivalent of <tt>symbol.to_s <=> object.to_s</tt>:
+ * Returns:
*
- * :bar <=> :foo # => -1
- * :foo <=> :foo # => 0
- * :foo <=> :bar # => 1
+ * - <tt>self.to_s <=> other.to_s</tt>, if +other+ is a symbol.
+ * - +nil+, otherwise.
*
- * Otherwise, returns +nil+:
+ * Examples:
+ *
+ * :bar <=> :foo # => -1
+ * :foo <=> :foo # => 0
+ * :foo <=> :bar # => 1
+ * :foo <=> 'bar' # => nil
*
- * :foo <=> 'bar' # => nil
+ * \Class \Symbol includes module Comparable,
+ * each of whose methods uses Symbol#<=> for comparison.
*
* Related: String#<=>.
*/
@@ -12292,9 +12489,9 @@ sym_casecmp_p(VALUE sym, VALUE other)
/*
* call-seq:
- * symbol =~ object -> integer or nil
+ * self =~ other -> integer or nil
*
- * Equivalent to <tt>symbol.to_s =~ object</tt>,
+ * Equivalent to <tt>self.to_s =~ other</tt>,
* including possible updates to global variables;
* see String#=~.
*
@@ -12340,11 +12537,11 @@ sym_match_m_p(int argc, VALUE *argv, VALUE sym)
/*
* call-seq:
- * symbol[index] -> string or nil
- * symbol[start, length] -> string or nil
- * symbol[range] -> string or nil
- * symbol[regexp, capture = 0] -> string or nil
- * symbol[substring] -> string or nil
+ * self[offset] -> string or nil
+ * self[offset, size] -> string or nil
+ * self[range] -> string or nil
+ * self[regexp, capture = 0] -> string or nil
+ * self[substring] -> string or nil
*
* Equivalent to <tt>symbol.to_s[]</tt>; see String#[].
*
@@ -12385,7 +12582,7 @@ sym_empty(VALUE sym)
/*
* call-seq:
- * upcase(*options) -> symbol
+ * upcase(mapping) -> symbol
*
* Equivalent to <tt>sym.to_s.upcase.to_sym</tt>.
*
@@ -12401,7 +12598,7 @@ sym_upcase(int argc, VALUE *argv, VALUE sym)
/*
* call-seq:
- * downcase(*options) -> symbol
+ * downcase(mapping) -> symbol
*
* Equivalent to <tt>sym.to_s.downcase.to_sym</tt>.
*
@@ -12419,7 +12616,7 @@ sym_downcase(int argc, VALUE *argv, VALUE sym)
/*
* call-seq:
- * capitalize(*options) -> symbol
+ * capitalize(mapping) -> symbol
*
* Equivalent to <tt>sym.to_s.capitalize.to_sym</tt>.
*
@@ -12435,7 +12632,7 @@ sym_capitalize(int argc, VALUE *argv, VALUE sym)
/*
* call-seq:
- * swapcase(*options) -> symbol
+ * swapcase(mapping) -> symbol
*
* Equivalent to <tt>sym.to_s.swapcase.to_sym</tt>.
*
@@ -12552,8 +12749,16 @@ rb_str_to_interned_str(VALUE str)
VALUE
rb_interned_str(const char *ptr, long len)
{
- struct RString fake_str;
- return register_fstring(setup_fake_str(&fake_str, ptr, len, ENCINDEX_US_ASCII), true, false);
+ struct RString fake_str = {RBASIC_INIT};
+ int encidx = ENCINDEX_US_ASCII;
+ int coderange = ENC_CODERANGE_7BIT;
+ if (len > 0 && search_nonascii(ptr, ptr + len)) {
+ encidx = ENCINDEX_ASCII_8BIT;
+ coderange = ENC_CODERANGE_VALID;
+ }
+ VALUE str = setup_fake_str(&fake_str, ptr, len, encidx);
+ ENC_CODERANGE_SET(str, coderange);
+ return register_fstring(str, true, false);
}
VALUE
@@ -12569,7 +12774,7 @@ rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
rb_enc_autoload(enc);
}
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, false);
}
@@ -12580,8 +12785,10 @@ rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc)
rb_enc_autoload(enc);
}
- struct RString fake_str;
- return register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
+ struct RString fake_str = {RBASIC_INIT};
+ VALUE str = register_fstring(rb_setup_fake_str(&fake_str, ptr, len, enc), true, true);
+ RUBY_ASSERT(RB_OBJ_SHAREABLE_P(str) && (rb_gc_verify_shareable(str), 1));
+ return str;
}
VALUE
@@ -12590,9 +12797,9 @@ rb_enc_interned_str_cstr(const char *ptr, rb_encoding *enc)
return rb_enc_interned_str(ptr, strlen(ptr), enc);
}
-#if USE_YJIT
+#if USE_YJIT || USE_ZJIT
void
-rb_yjit_str_concat_codepoint(VALUE str, VALUE codepoint)
+rb_jit_str_concat_codepoint(VALUE str, VALUE codepoint)
{
if (RB_LIKELY(ENCODING_GET_INLINED(str) == rb_ascii8bit_encindex())) {
ssize_t code = RB_NUM2SSIZE(codepoint);
@@ -12607,17 +12814,27 @@ rb_yjit_str_concat_codepoint(VALUE str, VALUE codepoint)
}
#endif
+static int
+fstring_set_class_i(VALUE *str, void *data)
+{
+ RBASIC_SET_CLASS(*str, rb_cString);
+
+ return ST_CONTINUE;
+}
+
void
Init_String(void)
{
rb_cString = rb_define_class("String", rb_cObject);
- RUBY_ASSERT(rb_vm_fstring_table());
- st_foreach(rb_vm_fstring_table(), fstring_set_class_i, rb_cString);
+
+ rb_concurrent_set_foreach_with_replace(fstring_table_obj, fstring_set_class_i, NULL);
+
rb_include_module(rb_cString, rb_mComparable);
rb_define_alloc_func(rb_cString, empty_str_alloc);
rb_define_singleton_method(rb_cString, "new", rb_str_s_new, -1);
rb_define_singleton_method(rb_cString, "try_convert", rb_str_s_try_convert, 1);
rb_define_method(rb_cString, "initialize", rb_str_init, -1);
+ rb_define_method(rb_cString, "replace", rb_str_replace, 1);
rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1);
rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
rb_define_method(rb_cString, "==", rb_str_equal, 1);
@@ -12648,7 +12865,6 @@ Init_String(void)
rb_define_method(rb_cString, "byteindex", rb_str_byteindex_m, -1);
rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1);
rb_define_method(rb_cString, "byterindex", rb_str_byterindex_m, -1);
- rb_define_method(rb_cString, "replace", rb_str_replace, 1);
rb_define_method(rb_cString, "clear", rb_str_clear, 0);
rb_define_method(rb_cString, "chr", rb_str_chr, 0);
rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
@@ -12719,9 +12935,9 @@ Init_String(void)
rb_define_method(rb_cString, "gsub", rb_str_gsub, -1);
rb_define_method(rb_cString, "chop", rb_str_chop, 0);
rb_define_method(rb_cString, "chomp", rb_str_chomp, -1);
- rb_define_method(rb_cString, "strip", rb_str_strip, 0);
- rb_define_method(rb_cString, "lstrip", rb_str_lstrip, 0);
- rb_define_method(rb_cString, "rstrip", rb_str_rstrip, 0);
+ rb_define_method(rb_cString, "strip", rb_str_strip, -1);
+ rb_define_method(rb_cString, "lstrip", rb_str_lstrip, -1);
+ rb_define_method(rb_cString, "rstrip", rb_str_rstrip, -1);
rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1);
rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1);
@@ -12729,9 +12945,9 @@ Init_String(void)
rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1);
rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0);
rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1);
- rb_define_method(rb_cString, "strip!", rb_str_strip_bang, 0);
- rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, 0);
- rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, 0);
+ rb_define_method(rb_cString, "strip!", rb_str_strip_bang, -1);
+ rb_define_method(rb_cString, "lstrip!", rb_str_lstrip_bang, -1);
+ rb_define_method(rb_cString, "rstrip!", rb_str_rstrip_bang, -1);
rb_define_method(rb_cString, "delete_prefix!", rb_str_delete_prefix_bang, 1);
rb_define_method(rb_cString, "delete_suffix!", rb_str_delete_suffix_bang, 1);
@@ -12816,3 +13032,4 @@ Init_String(void)
rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
}
+
diff --git a/string.rb b/string.rb
deleted file mode 100644
index f925cc5833..0000000000
--- a/string.rb
+++ /dev/null
@@ -1,556 +0,0 @@
-# A +String+ object has an arbitrary sequence of bytes,
-# typically representing text or binary data.
-# A +String+ object may be created using String::new or as literals.
-#
-# String objects differ from Symbol objects in that Symbol objects are
-# designed to be used as identifiers, instead of text or data.
-#
-# You can create a +String+ object explicitly with:
-#
-# - A {string literal}[rdoc-ref:syntax/literals.rdoc@String+Literals].
-# - A {heredoc literal}[rdoc-ref:syntax/literals.rdoc@Here+Document+Literals].
-#
-# You can convert certain objects to Strings with:
-#
-# - Method #String.
-#
-# Some +String+ methods modify +self+.
-# Typically, a method whose name ends with <tt>!</tt> modifies +self+
-# and returns +self+;
-# often, a similarly named method (without the <tt>!</tt>)
-# returns a new string.
-#
-# In general, if both bang and non-bang versions of a method exist,
-# the bang method mutates and the non-bang method does not.
-# However, a method without a bang can also mutate, such as String#replace.
-#
-# == Substitution Methods
-#
-# These methods perform substitutions:
-#
-# - String#sub: One substitution (or none); returns a new string.
-# - String#sub!: One substitution (or none); returns +self+ if any changes,
-# +nil+ otherwise.
-# - String#gsub: Zero or more substitutions; returns a new string.
-# - String#gsub!: Zero or more substitutions; returns +self+ if any changes,
-# +nil+ otherwise.
-#
-# Each of these methods takes:
-#
-# - A first argument, +pattern+ (String or Regexp),
-# that specifies the substring(s) to be replaced.
-#
-# - Either of the following:
-#
-# - A second argument, +replacement+ (String or Hash),
-# that determines the replacing string.
-# - A block that will determine the replacing string.
-#
-# The examples in this section mostly use the String#sub and String#gsub methods;
-# the principles illustrated apply to all four substitution methods.
-#
-# <b>Argument +pattern+</b>
-#
-# Argument +pattern+ is commonly a regular expression:
-#
-# s = 'hello'
-# s.sub(/[aeiou]/, '*') # => "h*llo"
-# s.gsub(/[aeiou]/, '*') # => "h*ll*"
-# s.gsub(/[aeiou]/, '') # => "hll"
-# s.sub(/ell/, 'al') # => "halo"
-# s.gsub(/xyzzy/, '*') # => "hello"
-# 'THX1138'.gsub(/\d+/, '00') # => "THX00"
-#
-# When +pattern+ is a string, all its characters are treated
-# as ordinary characters (not as Regexp special characters):
-#
-# 'THX1138'.gsub('\d+', '00') # => "THX1138"
-#
-# <b>+String+ +replacement+</b>
-#
-# If +replacement+ is a string, that string determines
-# the replacing string that is substituted for the matched text.
-#
-# Each of the examples above uses a simple string as the replacing string.
-#
-# +String+ +replacement+ may contain back-references to the pattern's captures:
-#
-# - <tt>\n</tt> (_n_ is a non-negative integer) refers to <tt>$n</tt>.
-# - <tt>\k<name></tt> refers to the named capture +name+.
-#
-# See Regexp for details.
-#
-# Note that within the string +replacement+, a character combination
-# such as <tt>$&</tt> is treated as ordinary text, not as
-# a special match variable.
-# However, you may refer to some special match variables using these
-# combinations:
-#
-# - <tt>\&</tt> and <tt>\0</tt> correspond to <tt>$&</tt>,
-# which contains the complete matched text.
-# - <tt>\'</tt> corresponds to <tt>$'</tt>,
-# which contains the string after the match.
-# - <tt>\`</tt> corresponds to <tt>$`</tt>,
-# which contains the string before the match.
-# - <tt>\\+</tt> corresponds to <tt>$+</tt>,
-# which contains the last capture group.
-#
-# See Regexp for details.
-#
-# Note that <tt>\\\\</tt> is interpreted as an escape, i.e., a single backslash.
-#
-# Note also that a string literal consumes backslashes.
-# See {String Literals}[rdoc-ref:syntax/literals.rdoc@String+Literals] for details about string literals.
-#
-# A back-reference is typically preceded by an additional backslash.
-# For example, if you want to write a back-reference <tt>\&</tt> in
-# +replacement+ with a double-quoted string literal, you need to write
-# <tt>"..\\\\&.."</tt>.
-#
-# If you want to write a non-back-reference string <tt>\&</tt> in
-# +replacement+, you need to first escape the backslash to prevent
-# this method from interpreting it as a back-reference, and then you
-# need to escape the backslashes again to prevent a string literal from
-# consuming them: <tt>"..\\\\\\\\&.."</tt>.
-#
-# You may want to use the block form to avoid excessive backslashes.
-#
-# <b>\Hash +replacement+</b>
-#
-# If the argument +replacement+ is a hash, and +pattern+ matches one of its keys,
-# the replacing string is the value for that key:
-#
-# h = {'foo' => 'bar', 'baz' => 'bat'}
-# 'food'.sub('foo', h) # => "bard"
-#
-# Note that a symbol key does not match:
-#
-# h = {foo: 'bar', baz: 'bat'}
-# 'food'.sub('foo', h) # => "d"
-#
-# <b>Block</b>
-#
-# In the block form, the current match string is passed to the block;
-# the block's return value becomes the replacing string:
-#
-# s = '@'
-# '1234'.gsub(/\d/) { |match| s.succ! } # => "ABCD"
-#
-# Special match variables such as <tt>$1</tt>, <tt>$2</tt>, <tt>$`</tt>,
-# <tt>$&</tt>, and <tt>$'</tt> are set appropriately.
-#
-# == Whitespace in Strings
-#
-# In the class +String+, _whitespace_ is defined as a contiguous sequence of characters
-# consisting of any mixture of the following:
-#
-# - NL (null): <tt>"\x00"</tt>, <tt>"\u0000"</tt>.
-# - HT (horizontal tab): <tt>"\x09"</tt>, <tt>"\t"</tt>.
-# - LF (line feed): <tt>"\x0a"</tt>, <tt>"\n"</tt>.
-# - VT (vertical tab): <tt>"\x0b"</tt>, <tt>"\v"</tt>.
-# - FF (form feed): <tt>"\x0c"</tt>, <tt>"\f"</tt>.
-# - CR (carriage return): <tt>"\x0d"</tt>, <tt>"\r"</tt>.
-# - SP (space): <tt>"\x20"</tt>, <tt>" "</tt>.
-#
-#
-# Whitespace is relevant for the following methods:
-#
-# - #lstrip, #lstrip!: Strip leading whitespace.
-# - #rstrip, #rstrip!: Strip trailing whitespace.
-# - #strip, #strip!: Strip leading and trailing whitespace.
-#
-# == +String+ Slices
-#
-# A _slice_ of a string is a substring selected by certain criteria.
-#
-# These instance methods utilize slicing:
-#
-# - String#[] (aliased as String#slice): Returns a slice copied from +self+.
-# - String#[]=: Mutates +self+ with the slice replaced.
-# - String#slice!: Mutates +self+ with the slice removed and returns the removed slice.
-#
-# Each of the above methods takes arguments that determine the slice
-# to be copied or replaced.
-#
-# The arguments have several forms.
-# For a string +string+, the forms are:
-#
-# - <tt>string[index]</tt>
-# - <tt>string[start, length]</tt>
-# - <tt>string[range]</tt>
-# - <tt>string[regexp, capture = 0]</tt>
-# - <tt>string[substring]</tt>
-#
-# <b><tt>string[index]</tt></b>
-#
-# When a non-negative integer argument +index+ is given,
-# the slice is the 1-character substring found in +self+ at character offset +index+:
-#
-# 'bar'[0] # => "b"
-# 'bar'[2] # => "r"
-# 'bar'[20] # => nil
-# 'тест'[2] # => "с"
-# 'こんにちは'[4] # => "は"
-#
-# When a negative integer +index+ is given,
-# the slice begins at the offset given by counting backward from the end of +self+:
-#
-# 'bar'[-3] # => "b"
-# 'bar'[-1] # => "r"
-# 'bar'[-20] # => nil
-#
-# <b><tt>string[start, length]</tt></b>
-#
-# When non-negative integer arguments +start+ and +length+ are given,
-# the slice begins at character offset +start+, if it exists,
-# and continues for +length+ characters, if available:
-#
-# 'foo'[0, 2] # => "fo"
-# 'тест'[1, 2] # => "ес"
-# 'こんにちは'[2, 2] # => "にち"
-# # Zero length.
-# 'foo'[2, 0] # => ""
-# # Length not entirely available.
-# 'foo'[1, 200] # => "oo"
-# # Start out of range.
-# 'foo'[4, 2] # => nil
-#
-# Special case: if +start+ equals the length of +self+,
-# the slice is a new empty string:
-#
-# 'foo'[3, 2] # => ""
-# 'foo'[3, 200] # => ""
-#
-# When a negative +start+ and non-negative +length+ are given,
-# the slice begins by counting backward from the end of +self+,
-# and continues for +length+ characters, if available:
-#
-# 'foo'[-2, 2] # => "oo"
-# 'foo'[-2, 200] # => "oo"
-# # Start out of range.
-# 'foo'[-4, 2] # => nil
-#
-# When a negative +length+ is given, there is no slice:
-#
-# 'foo'[1, -1] # => nil
-# 'foo'[-2, -1] # => nil
-#
-# <b><tt>string[range]</tt></b>
-#
-# When a Range argument +range+ is given,
-# it creates a substring of +string+ using the indices in +range+.
-# The slice is then determined as above:
-#
-# 'foo'[0..1] # => "fo"
-# 'foo'[0, 2] # => "fo"
-#
-# 'foo'[2...2] # => ""
-# 'foo'[2, 0] # => ""
-#
-# 'foo'[1..200] # => "oo"
-# 'foo'[1, 200] # => "oo"
-#
-# 'foo'[4..5] # => nil
-# 'foo'[4, 2] # => nil
-#
-# 'foo'[-4..-3] # => nil
-# 'foo'[-4, 2] # => nil
-#
-# 'foo'[3..4] # => ""
-# 'foo'[3, 2] # => ""
-#
-# 'foo'[-2..-1] # => "oo"
-# 'foo'[-2, 2] # => "oo"
-#
-# 'foo'[-2..197] # => "oo"
-# 'foo'[-2, 200] # => "oo"
-#
-# <b><tt>string[regexp, capture = 0]</tt></b>
-#
-# When the Regexp argument +regexp+ is given,
-# and the +capture+ argument is <tt>0</tt>,
-# the slice is the first matching substring found in +self+:
-#
-# 'foo'[/o/] # => "o"
-# 'foo'[/x/] # => nil
-# s = 'hello there'
-# s[/[aeiou](.)\1/] # => "ell"
-# s[/[aeiou](.)\1/, 0] # => "ell"
-#
-# If the argument +capture+ is provided and not <tt>0</tt>,
-# it should be either a capture group index (integer)
-# or a capture group name (String or Symbol);
-# the slice is the specified capture (see Regexp@Groups and Captures):
-#
-# s = 'hello there'
-# s[/[aeiou](.)\1/, 1] # => "l"
-# s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] # => "l"
-# s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, :vowel] # => "e"
-#
-# If an invalid capture group index is given, there is no slice.
-# If an invalid capture group name is given, +IndexError+ is raised.
-#
-# <b><tt>string[substring]</tt></b>
-#
-# When the single +String+ argument +substring+ is given,
-# it returns the substring from +self+ if found, otherwise +nil+:
-#
-# 'foo'['oo'] # => "oo"
-# 'foo'['xx'] # => nil
-#
-# == What's Here
-#
-# First, what's elsewhere. Class +String+:
-#
-# - Inherits from the {Object class}[rdoc-ref:Object@What-27s+Here].
-# - Includes the {Comparable module}[rdoc-ref:Comparable@What-27s+Here].
-#
-# Here, class +String+ provides methods that are useful for:
-#
-# - {Creating a String}[rdoc-ref:String@Methods+for+Creating+a+String]
-# - {Frozen/Unfrozen Strings}[rdoc-ref:String@Methods+for+a+Frozen-2FUnfrozen+String]
-# - {Querying}[rdoc-ref:String@Methods+for+Querying]
-# - {Comparing}[rdoc-ref:String@Methods+for+Comparing]
-# - {Modifying a String}[rdoc-ref:String@Methods+for+Modifying+a+String]
-# - {Converting to New String}[rdoc-ref:String@Methods+for+Converting+to+New+String]
-# - {Converting to Non-String}[rdoc-ref:String@Methods+for+Converting+to+Non-String]
-# - {Iterating}[rdoc-ref:String@Methods+for+Iterating]
-#
-# === Methods for Creating a +String+
-#
-# - ::new: Returns a new string.
-# - ::try_convert: Returns a new string created from a given object.
-#
-# === Methods for a Frozen/Unfrozen String
-#
-# - #+@: Returns a string that is not frozen: +self+ if not frozen;
-# +self.dup+ otherwise.
-# - #-@ (aliased as #dedup): Returns a string that is frozen: +self+ if already frozen;
-# +self.freeze+ otherwise.
-# - #freeze: Freezes +self+ if not already frozen; returns +self+.
-#
-# === Methods for Querying
-#
-# _Counts_
-#
-# - #length (aliased as #size): Returns the count of characters (not bytes).
-# - #empty?: Returns +true+ if +self.length+ is zero; +false+ otherwise.
-# - #bytesize: Returns the count of bytes.
-# - #count: Returns the count of substrings matching given strings.
-#
-# _Substrings_
-#
-# - #=~: Returns the index of the first substring that matches a given
-# Regexp or other object; returns +nil+ if no match is found.
-# - #index: Returns the index of the _first_ occurrence of a given substring;
-# returns +nil+ if none found.
-# - #rindex: Returns the index of the _last_ occurrence of a given substring;
-# returns +nil+ if none found.
-# - #include?: Returns +true+ if the string contains a given substring; +false+ otherwise.
-# - #match: Returns a MatchData object if the string matches a given Regexp; +nil+ otherwise.
-# - #match?: Returns +true+ if the string matches a given Regexp; +false+ otherwise.
-# - #start_with?: Returns +true+ if the string begins with any of the given substrings.
-# - #end_with?: Returns +true+ if the string ends with any of the given substrings.
-#
-# _Encodings_
-#
-# - #encoding\: Returns the Encoding object that represents the encoding of the string.
-# - #unicode_normalized?: Returns +true+ if the string is in Unicode normalized form; +false+ otherwise.
-# - #valid_encoding?: Returns +true+ if the string contains only characters that are valid
-# for its encoding.
-# - #ascii_only?: Returns +true+ if the string has only ASCII characters; +false+ otherwise.
-#
-# _Other_
-#
-# - #sum: Returns a basic checksum for the string: the sum of each byte.
-# - #hash: Returns the integer hash code.
-#
-# === Methods for Comparing
-#
-# - #== (aliased as #===): Returns +true+ if a given other string has the same content as +self+.
-# - #eql?: Returns +true+ if the content is the same as the given other string.
-# - #<=>: Returns -1, 0, or 1 as a given other string is smaller than,
-# equal to, or larger than +self+.
-# - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
-# other string is smaller than, equal to, or larger than +self+.
-# - #casecmp?: Returns +true+ if the string is equal to a given string after Unicode case folding;
-# +false+ otherwise.
-#
-# === Methods for Modifying a +String+
-#
-# Each of these methods modifies +self+.
-#
-# _Insertion_
-#
-# - #insert: Returns +self+ with a given string inserted at a specified offset.
-# - #<<: Returns +self+ concatenated with a given string or integer.
-# - #append_as_bytes: Returns +self+ concatenated with strings without performing any
-# encoding validation or conversion.
-#
-# _Substitution_
-#
-# - #sub!: Replaces the first substring that matches a given pattern with a given replacement string;
-# returns +self+ if any changes, +nil+ otherwise.
-# - #gsub!: Replaces each substring that matches a given pattern with a given replacement string;
-# returns +self+ if any changes, +nil+ otherwise.
-# - #succ! (aliased as #next!): Returns +self+ modified to become its own successor.
-# - #initialize_copy (aliased as #replace): Returns +self+ with its entire content replaced by a given string.
-# - #reverse!: Returns +self+ with its characters in reverse order.
-# - #setbyte: Sets the byte at a given integer offset to a given value; returns the argument.
-# - #tr!: Replaces specified characters in +self+ with specified replacement characters;
-# returns +self+ if any changes, +nil+ otherwise.
-# - #tr_s!: Replaces specified characters in +self+ with specified replacement characters,
-# removing duplicates from the substrings that were modified;
-# returns +self+ if any changes, +nil+ otherwise.
-#
-# _Casing_
-#
-# - #capitalize!: Upcases the initial character and downcases all others;
-# returns +self+ if any changes, +nil+ otherwise.
-# - #downcase!: Downcases all characters; returns +self+ if any changes, +nil+ otherwise.
-# - #upcase!: Upcases all characters; returns +self+ if any changes, +nil+ otherwise.
-# - #swapcase!: Upcases each downcase character and downcases each upcase character;
-# returns +self+ if any changes, +nil+ otherwise.
-#
-# _Encoding_
-#
-# - #encode!: Returns +self+ with all characters transcoded from one encoding to another.
-# - #unicode_normalize!: Unicode-normalizes +self+; returns +self+.
-# - #scrub!: Replaces each invalid byte with a given character; returns +self+.
-# - #force_encoding: Changes the encoding to a given encoding; returns +self+.
-#
-# _Deletion_
-#
-# - #clear: Removes all content, so that +self+ is empty; returns +self+.
-# - #slice!, #[]=: Removes a substring determined by a given index, start/length, range, regexp, or substring.
-# - #squeeze!: Removes contiguous duplicate characters; returns +self+.
-# - #delete!: Removes characters as determined by the intersection of substring arguments.
-# - #lstrip!: Removes leading whitespace; returns +self+ if any changes, +nil+ otherwise.
-# - #rstrip!: Removes trailing whitespace; returns +self+ if any changes, +nil+ otherwise.
-# - #strip!: Removes leading and trailing whitespace; returns +self+ if any changes, +nil+ otherwise.
-# - #chomp!: Removes the trailing record separator, if found; returns +self+ if any changes, +nil+ otherwise.
-# - #chop!: Removes trailing newline characters if found; otherwise removes the last character;
-# returns +self+ if any changes, +nil+ otherwise.
-#
-# === Methods for Converting to New +String+
-#
-# Each of these methods returns a new +String+ based on +self+,
-# often just a modified copy of +self+.
-#
-# _Extension_
-#
-# - #*: Returns the concatenation of multiple copies of +self+.
-# - #+: Returns the concatenation of +self+ and a given other string.
-# - #center: Returns a copy of +self+ centered between pad substrings.
-# - #concat: Returns the concatenation of +self+ with given other strings.
-# - #prepend: Returns the concatenation of a given other string with +self+.
-# - #ljust: Returns a copy of +self+ of a given length, right-padded with a given other string.
-# - #rjust: Returns a copy of +self+ of a given length, left-padded with a given other string.
-#
-# _Encoding_
-#
-# - #b: Returns a copy of +self+ with ASCII-8BIT encoding.
-# - #scrub: Returns a copy of +self+ with each invalid byte replaced with a given character.
-# - #unicode_normalize: Returns a copy of +self+ with each character Unicode-normalized.
-# - #encode: Returns a copy of +self+ with all characters transcoded from one encoding to another.
-#
-# _Substitution_
-#
-# - #dump: Returns a copy of +self+ with all non-printing characters replaced by \xHH notation
-# and all special characters escaped.
-# - #undump: Returns a copy of +self+ with all <tt>\xNN</tt> notations replaced by <tt>\uNNNN</tt> notations
-# and all escaped characters unescaped.
-# - #sub: Returns a copy of +self+ with the first substring matching a given pattern
-# replaced with a given replacement string.
-# - #gsub: Returns a copy of +self+ with each substring that matches a given pattern
-# replaced with a given replacement string.
-# - #succ (aliased as #next): Returns the string that is the successor to +self+.
-# - #reverse: Returns a copy of +self+ with its characters in reverse order.
-# - #tr: Returns a copy of +self+ with specified characters replaced with specified replacement characters.
-# - #tr_s: Returns a copy of +self+ with specified characters replaced with
-# specified replacement characters,
-# removing duplicates from the substrings that were modified.
-# - #%: Returns the string resulting from formatting a given object into +self+.
-#
-# _Casing_
-#
-# - #capitalize: Returns a copy of +self+ with the first character upcased
-# and all other characters downcased.
-# - #downcase: Returns a copy of +self+ with all characters downcased.
-# - #upcase: Returns a copy of +self+ with all characters upcased.
-# - #swapcase: Returns a copy of +self+ with all upcase characters downcased
-# and all downcase characters upcased.
-#
-# _Deletion_
-#
-# - #delete: Returns a copy of +self+ with characters removed.
-# - #delete_prefix: Returns a copy of +self+ with a given prefix removed.
-# - #delete_suffix: Returns a copy of +self+ with a given suffix removed.
-# - #lstrip: Returns a copy of +self+ with leading whitespace removed.
-# - #rstrip: Returns a copy of +self+ with trailing whitespace removed.
-# - #strip: Returns a copy of +self+ with leading and trailing whitespace removed.
-# - #chomp: Returns a copy of +self+ with a trailing record separator removed, if found.
-# - #chop: Returns a copy of +self+ with trailing newline characters or the last character removed.
-# - #squeeze: Returns a copy of +self+ with contiguous duplicate characters removed.
-# - #[] (aliased as #slice): Returns a substring determined by a given index, start/length, range, regexp, or string.
-# - #byteslice: Returns a substring determined by a given index, start/length, or range.
-# - #chr: Returns the first character.
-#
-# _Duplication_
-#
-# - #to_s (aliased as #to_str): If +self+ is a subclass of +String+, returns +self+ copied into a +String+;
-# otherwise, returns +self+.
-#
-# === Methods for Converting to Non-+String+
-#
-# Each of these methods converts the contents of +self+ to a non-+String+.
-#
-# <em>Characters, Bytes, and Clusters</em>
-#
-# - #bytes: Returns an array of the bytes in +self+.
-# - #chars: Returns an array of the characters in +self+.
-# - #codepoints: Returns an array of the integer ordinals in +self+.
-# - #getbyte: Returns the integer byte at the given index in +self+.
-# - #grapheme_clusters: Returns an array of the grapheme clusters in +self+.
-#
-# _Splitting_
-#
-# - #lines: Returns an array of the lines in +self+, as determined by a given record separator.
-# - #partition: Returns a 3-element array determined by the first substring that matches
-# a given substring or regexp.
-# - #rpartition: Returns a 3-element array determined by the last substring that matches
-# a given substring or regexp.
-# - #split: Returns an array of substrings determined by a given delimiter -- regexp or string --
-# or, if a block is given, passes those substrings to the block.
-#
-# _Matching_
-#
-# - #scan: Returns an array of substrings matching a given regexp or string, or,
-# if a block is given, passes each matching substring to the block.
-# - #unpack: Returns an array of substrings extracted from +self+ according to a given format.
-# - #unpack1: Returns the first substring extracted from +self+ according to a given format.
-#
-# _Numerics_
-#
-# - #hex: Returns the integer value of the leading characters, interpreted as hexadecimal digits.
-# - #oct: Returns the integer value of the leading characters, interpreted as octal digits.
-# - #ord: Returns the integer ordinal of the first character in +self+.
-# - #to_i: Returns the integer value of leading characters, interpreted as an integer.
-# - #to_f: Returns the floating-point value of leading characters, interpreted as a floating-point number.
-#
-# <em>Strings and Symbols</em>
-#
-# - #inspect: Returns a copy of +self+, enclosed in double quotes, with special characters escaped.
-# - #intern (aliased as #to_sym): Returns the symbol corresponding to +self+.
-#
-# === Methods for Iterating
-#
-# - #each_byte: Calls the given block with each successive byte in +self+.
-# - #each_char: Calls the given block with each successive character in +self+.
-# - #each_codepoint: Calls the given block with each successive integer codepoint in +self+.
-# - #each_grapheme_cluster: Calls the given block with each successive grapheme cluster in +self+.
-# - #each_line: Calls the given block with each successive line in +self+,
-# as determined by a given record separator.
-# - #upto: Calls the given block with each string value returned by successive calls to #succ.
-
-class String; end
diff --git a/struct.c b/struct.c
index 7cfc1f2a16..7a592b42c5 100644
--- a/struct.c
+++ b/struct.c
@@ -52,7 +52,8 @@ struct_ivar_get(VALUE c, ID id)
RUBY_ASSERT(RB_TYPE_P(c, T_CLASS));
ivar = rb_attr_get(c, id);
if (!NIL_P(ivar)) {
- return rb_ivar_set(orig, id, ivar);
+ if (!OBJ_FROZEN(orig)) rb_ivar_set(orig, id, ivar);
+ return ivar;
}
}
}
@@ -82,9 +83,9 @@ rb_struct_members(VALUE s)
{
VALUE members = rb_struct_s_members(rb_obj_class(s));
- if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) {
+ if (RSTRUCT_LEN_RAW(s) != RARRAY_LEN(members)) {
rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
- RARRAY_LEN(members), RSTRUCT_LEN(s));
+ RARRAY_LEN(members), RSTRUCT_LEN_RAW(s));
}
return members;
}
@@ -160,10 +161,10 @@ struct_member_pos(VALUE s, VALUE name)
mask = RARRAY_LEN(back);
if (mask <= AREF_HASH_THRESHOLD) {
- if (UNLIKELY(RSTRUCT_LEN(s) != mask)) {
+ if (UNLIKELY(RSTRUCT_LEN_RAW(s) != mask)) {
rb_raise(rb_eTypeError,
"struct size differs (%ld required %ld given)",
- mask, RSTRUCT_LEN(s));
+ mask, RSTRUCT_LEN_RAW(s));
}
for (j = 0; j < mask; j++) {
if (RARRAY_AREF(back, j) == name)
@@ -172,9 +173,9 @@ struct_member_pos(VALUE s, VALUE name)
return -1;
}
- if (UNLIKELY(RSTRUCT_LEN(s) != FIX2INT(RARRAY_AREF(back, mask-1)))) {
+ if (UNLIKELY(RSTRUCT_LEN_RAW(s) != FIX2INT(RARRAY_AREF(back, mask-1)))) {
rb_raise(rb_eTypeError, "struct size differs (%d required %ld given)",
- FIX2INT(RARRAY_AREF(back, mask-1)), RSTRUCT_LEN(s));
+ FIX2INT(RARRAY_AREF(back, mask-1)), RSTRUCT_LEN_RAW(s));
}
mask -= 3;
@@ -234,7 +235,7 @@ rb_struct_getmember(VALUE obj, ID id)
VALUE slot = ID2SYM(id);
int i = struct_member_pos(obj, slot);
if (i != -1) {
- return RSTRUCT_GET(obj, i);
+ return RSTRUCT_GET_RAW(obj, i);
}
rb_name_err_raise("'%1$s' is not a struct member", obj, ID2SYM(id));
@@ -627,7 +628,7 @@ rb_struct_define_under(VALUE outer, const char *name, ...)
* PositionalOnly.new(0, 1)
* # => #<struct PositionalOnly foo=0, bar=1>
* PositionalOnly.new(bar: 1, foo: 0)
- * # => #<struct PositionalOnly foo={:foo=>1, :bar=>2}, bar=nil>
+ * # => #<struct PositionalOnly foo={foo: 1, bar: 2}, bar=nil>
* # Note that no error is raised, but arguments treated as one hash value
*
* # Same as not providing keyword_init:
@@ -715,15 +716,18 @@ num_members(VALUE klass)
struct struct_hash_set_arg {
VALUE self;
VALUE unknown_keywords;
+ VALUE missing_keywords;
+ long missing_count;
};
-static int rb_struct_pos(VALUE s, VALUE *name);
+static int rb_struct_pos(VALUE s, VALUE *name, bool name_only);
+static VALUE deconstruct_keys(VALUE s, VALUE keys, bool name_only);
+static int rb_struct_pos(VALUE s, VALUE *name, bool name_only);
static int
-struct_hash_set_i(VALUE key, VALUE val, VALUE arg)
+struct_hash_aset(VALUE key, VALUE val, struct struct_hash_set_arg *args, bool name_only)
{
- struct struct_hash_set_arg *args = (struct struct_hash_set_arg *)arg;
- int i = rb_struct_pos(args->self, &key);
+ int i = rb_struct_pos(args->self, &key, name_only);
if (i < 0) {
if (NIL_P(args->unknown_keywords)) {
args->unknown_keywords = rb_ary_new();
@@ -732,8 +736,16 @@ struct_hash_set_i(VALUE key, VALUE val, VALUE arg)
}
else {
rb_struct_modify(args->self);
- RSTRUCT_SET(args->self, i, val);
+ RSTRUCT_SET_RAW(args->self, i, val);
}
+ return i;
+}
+
+static int
+struct_hash_set_i(VALUE key, VALUE val, VALUE arg)
+{
+ struct struct_hash_set_arg *args = (struct struct_hash_set_arg *)arg;
+ struct_hash_aset(key, val, args, false);
return ST_CONTINUE;
}
@@ -766,12 +778,13 @@ rb_struct_initialize_m(int argc, const VALUE *argv, VALUE self)
break;
}
if (keyword_init) {
- struct struct_hash_set_arg arg;
+ struct struct_hash_set_arg arg = {
+ .self = self,
+ .unknown_keywords = Qnil,
+ };
rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), n);
- arg.self = self;
- arg.unknown_keywords = Qnil;
rb_hash_foreach(argv[0], struct_hash_set_i, (VALUE)&arg);
- if (arg.unknown_keywords != Qnil) {
+ if (UNLIKELY(!NIL_P(arg.unknown_keywords))) {
rb_raise(rb_eArgError, "unknown keywords: %s",
RSTRING_PTR(rb_ary_join(arg.unknown_keywords, rb_str_new2(", "))));
}
@@ -781,7 +794,7 @@ rb_struct_initialize_m(int argc, const VALUE *argv, VALUE self)
rb_raise(rb_eArgError, "struct size differs");
}
for (long i=0; i<argc; i++) {
- RSTRUCT_SET(self, i, argv[i]);
+ RSTRUCT_SET_RAW(self, i, argv[i]);
}
if (n > argc) {
rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self)+argc, n-argc);
@@ -810,19 +823,42 @@ struct_alloc(VALUE klass)
{
long n = num_members(klass);
size_t embedded_size = offsetof(struct RStruct, as.ary) + (sizeof(VALUE) * n);
- VALUE flags = T_STRUCT | (RGENGC_WB_PROTECTED_STRUCT ? FL_WB_PROTECTED : 0);
+ if (RCLASS_MAX_IV_COUNT(klass) > 0) {
+ embedded_size += sizeof(VALUE);
+ }
+
+ VALUE flags = T_STRUCT;
if (n > 0 && rb_gc_size_allocatable_p(embedded_size)) {
flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
+ if (RCLASS_MAX_IV_COUNT(klass) == 0) {
+ // We set the flag before calling `NEWOBJ_OF` in case a NEWOBJ tracepoint does
+ // attempt to write fields. We'll remove it later if no fields was written to.
+ flags |= RSTRUCT_GEN_FIELDS;
+ }
- NEWOBJ_OF(st, struct RStruct, klass, flags, embedded_size, 0);
+ NEWOBJ_OF(st, struct RStruct, klass, flags, embedded_size);
+ if (RCLASS_MAX_IV_COUNT(klass) == 0) {
+ if (!rb_obj_shape_has_fields((VALUE)st)
+ && embedded_size < rb_gc_obj_slot_size((VALUE)st)) {
+ FL_UNSET_RAW((VALUE)st, RSTRUCT_GEN_FIELDS);
+ RSTRUCT_SET_FIELDS_OBJ((VALUE)st, 0);
+ }
+ }
+ else {
+ RSTRUCT_SET_FIELDS_OBJ((VALUE)st, 0);
+ }
rb_mem_clear((VALUE *)st->as.ary, n);
return (VALUE)st;
}
else {
- NEWOBJ_OF(st, struct RStruct, klass, flags, sizeof(struct RStruct), 0);
+ NEWOBJ_OF(st, struct RStruct, klass, flags, sizeof(struct RStruct));
+
+ st->as.heap.ptr = NULL;
+ st->as.heap.fields_obj = 0;
+ st->as.heap.len = 0;
st->as.heap.ptr = struct_heap_alloc((VALUE)st, n);
rb_mem_clear((VALUE *)st->as.heap.ptr, n);
@@ -893,8 +929,8 @@ rb_struct_each(VALUE s)
long i;
RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
- for (i=0; i<RSTRUCT_LEN(s); i++) {
- rb_yield(RSTRUCT_GET(s, i));
+ for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
+ rb_yield(RSTRUCT_GET_RAW(s, i));
}
return s;
}
@@ -931,16 +967,16 @@ rb_struct_each_pair(VALUE s)
RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
members = rb_struct_members(s);
if (rb_block_pair_yield_optimizable()) {
- for (i=0; i<RSTRUCT_LEN(s); i++) {
+ for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
VALUE key = rb_ary_entry(members, i);
- VALUE value = RSTRUCT_GET(s, i);
+ VALUE value = RSTRUCT_GET_RAW(s, i);
rb_yield_values(2, key, value);
}
}
else {
- for (i=0; i<RSTRUCT_LEN(s); i++) {
+ for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
VALUE key = rb_ary_entry(members, i);
- VALUE value = RSTRUCT_GET(s, i);
+ VALUE value = RSTRUCT_GET_RAW(s, i);
rb_yield(rb_assoc_new(key, value));
}
}
@@ -957,6 +993,7 @@ inspect_struct(VALUE s, VALUE prefix, int recur)
char first = RSTRING_PTR(cname)[0];
if (recur || first != '#') {
+ rb_str_cat2(str, " ");
rb_str_append(str, cname);
}
if (recur) {
@@ -964,7 +1001,7 @@ inspect_struct(VALUE s, VALUE prefix, int recur)
}
members = rb_struct_members(s);
- len = RSTRUCT_LEN(s);
+ len = RSTRUCT_LEN_RAW(s);
for (i=0; i<len; i++) {
VALUE slot;
@@ -973,7 +1010,7 @@ inspect_struct(VALUE s, VALUE prefix, int recur)
if (i > 0) {
rb_str_cat2(str, ", ");
}
- else if (first != '#') {
+ else {
rb_str_cat2(str, " ");
}
slot = RARRAY_AREF(members, i);
@@ -985,7 +1022,7 @@ inspect_struct(VALUE s, VALUE prefix, int recur)
rb_str_append(str, rb_inspect(slot));
}
rb_str_cat2(str, "=");
- rb_str_append(str, rb_inspect(RSTRUCT_GET(s, i)));
+ rb_str_append(str, rb_inspect(RSTRUCT_GET_RAW(s, i)));
}
rb_str_cat2(str, ">");
@@ -1007,7 +1044,7 @@ inspect_struct(VALUE s, VALUE prefix, int recur)
static VALUE
rb_struct_inspect(VALUE s)
{
- return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<struct "));
+ return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<struct"));
}
/*
@@ -1026,7 +1063,7 @@ rb_struct_inspect(VALUE s)
static VALUE
rb_struct_to_a(VALUE s)
{
- return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
+ return rb_ary_new4(RSTRUCT_LEN_RAW(s), RSTRUCT_CONST_PTR(s));
}
/*
@@ -1039,14 +1076,14 @@ rb_struct_to_a(VALUE s)
* Customer = Struct.new(:name, :address, :zip)
* joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
* h = joe.to_h
- * h # => {:name=>"Joe Smith", :address=>"123 Maple, Anytown NC", :zip=>12345}
+ * h # => {name: "Joe Smith", address: "123 Maple, Anytown NC", zip: 12345}
*
* If a block is given, it is called with each name/value pair;
* the block should return a 2-element array whose elements will become
* a key/value pair in the returned hash:
*
* h = joe.to_h{|name, value| [name.upcase, value.to_s.upcase]}
- * h # => {:NAME=>"JOE SMITH", :ADDRESS=>"123 MAPLE, ANYTOWN NC", :ZIP=>"12345"}
+ * h # => {NAME: "JOE SMITH", ADDRESS: "123 MAPLE, ANYTOWN NC", ZIP: "12345"}
*
* Raises ArgumentError if the block returns an inappropriate value.
*
@@ -1055,13 +1092,13 @@ rb_struct_to_a(VALUE s)
static VALUE
rb_struct_to_h(VALUE s)
{
- VALUE h = rb_hash_new_with_size(RSTRUCT_LEN(s));
+ VALUE h = rb_hash_new_with_size(RSTRUCT_LEN_RAW(s));
VALUE members = rb_struct_members(s);
long i;
int block_given = rb_block_given_p();
- for (i=0; i<RSTRUCT_LEN(s); i++) {
- VALUE k = rb_ary_entry(members, i), v = RSTRUCT_GET(s, i);
+ for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
+ VALUE k = rb_ary_entry(members, i), v = RSTRUCT_GET_RAW(s, i);
if (block_given)
rb_hash_set_pair(h, rb_yield_values(2, k, v));
else
@@ -1079,17 +1116,23 @@ rb_struct_to_h(VALUE s)
* Customer = Struct.new(:name, :address, :zip)
* joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
* h = joe.deconstruct_keys([:zip, :address])
- * h # => {:zip=>12345, :address=>"123 Maple, Anytown NC"}
+ * h # => {zip: 12345, address: "123 Maple, Anytown NC"}
*
* Returns all names and values if +array_of_names+ is +nil+:
*
* h = joe.deconstruct_keys(nil)
- * h # => {:name=>"Joseph Smith, Jr.", :address=>"123 Maple, Anytown NC", :zip=>12345}
+ * h # => {name: "Joseph Smith, Jr.", address: "123 Maple, Anytown NC", zip: 12345}
*
*/
static VALUE
rb_struct_deconstruct_keys(VALUE s, VALUE keys)
{
+ return deconstruct_keys(s, keys, false);
+}
+
+static VALUE
+deconstruct_keys(VALUE s, VALUE keys, bool name_only)
+{
VALUE h;
long i;
@@ -1102,17 +1145,17 @@ rb_struct_deconstruct_keys(VALUE s, VALUE keys)
rb_obj_class(keys));
}
- if (RSTRUCT_LEN(s) < RARRAY_LEN(keys)) {
+ if (RSTRUCT_LEN_RAW(s) < RARRAY_LEN(keys)) {
return rb_hash_new_with_size(0);
}
h = rb_hash_new_with_size(RARRAY_LEN(keys));
for (i=0; i<RARRAY_LEN(keys); i++) {
VALUE key = RARRAY_AREF(keys, i);
- int i = rb_struct_pos(s, &key);
+ int i = rb_struct_pos(s, &key, name_only);
if (i < 0) {
return h;
}
- rb_hash_aset(h, key, RSTRUCT_GET(s, i));
+ rb_hash_aset(h, key, RSTRUCT_GET_RAW(s, i));
}
return h;
}
@@ -1124,19 +1167,19 @@ rb_struct_init_copy(VALUE copy, VALUE s)
long i, len;
if (!OBJ_INIT_COPY(copy, s)) return copy;
- if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) {
+ if (RSTRUCT_LEN_RAW(copy) != RSTRUCT_LEN_RAW(s)) {
rb_raise(rb_eTypeError, "struct size mismatch");
}
- for (i=0, len=RSTRUCT_LEN(copy); i<len; i++) {
- RSTRUCT_SET(copy, i, RSTRUCT_GET(s, i));
+ for (i=0, len=RSTRUCT_LEN_RAW(copy); i<len; i++) {
+ RSTRUCT_SET_RAW(copy, i, RSTRUCT_GET_RAW(s, i));
}
return copy;
}
static int
-rb_struct_pos(VALUE s, VALUE *name)
+rb_struct_pos(VALUE s, VALUE *name, bool name_only)
{
long i;
VALUE idx = *name;
@@ -1144,7 +1187,7 @@ rb_struct_pos(VALUE s, VALUE *name)
if (SYMBOL_P(idx)) {
return struct_member_pos(s, idx);
}
- else if (RB_TYPE_P(idx, T_STRING)) {
+ else if (name_only || RB_TYPE_P(idx, T_STRING)) {
idx = rb_check_symbol(name);
if (NIL_P(idx)) return -1;
return struct_member_pos(s, idx);
@@ -1152,7 +1195,7 @@ rb_struct_pos(VALUE s, VALUE *name)
else {
long len;
i = NUM2LONG(idx);
- len = RSTRUCT_LEN(s);
+ len = RSTRUCT_LEN_RAW(s);
if (i < 0) {
if (i + len < 0) {
*name = LONG2FIX(i);
@@ -1172,7 +1215,7 @@ static void
invalid_struct_pos(VALUE s, VALUE idx)
{
if (FIXNUM_P(idx)) {
- long i = FIX2INT(idx), len = RSTRUCT_LEN(s);
+ long i = FIX2INT(idx), len = RSTRUCT_LEN_RAW(s);
if (i < 0) {
rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)",
i, len);
@@ -1216,9 +1259,9 @@ invalid_struct_pos(VALUE s, VALUE idx)
VALUE
rb_struct_aref(VALUE s, VALUE idx)
{
- int i = rb_struct_pos(s, &idx);
+ int i = rb_struct_pos(s, &idx, false);
if (i < 0) invalid_struct_pos(s, idx);
- return RSTRUCT_GET(s, i);
+ return RSTRUCT_GET_RAW(s, i);
}
/*
@@ -1254,28 +1297,28 @@ rb_struct_aref(VALUE s, VALUE idx)
VALUE
rb_struct_aset(VALUE s, VALUE idx, VALUE val)
{
- int i = rb_struct_pos(s, &idx);
+ int i = rb_struct_pos(s, &idx, false);
if (i < 0) invalid_struct_pos(s, idx);
rb_struct_modify(s);
- RSTRUCT_SET(s, i, val);
+ RSTRUCT_SET_RAW(s, i, val);
return val;
}
FUNC_MINIMIZED(VALUE rb_struct_lookup(VALUE s, VALUE idx));
-NOINLINE(static VALUE rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound));
+NOINLINE(static VALUE rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound, bool name_only));
VALUE
rb_struct_lookup(VALUE s, VALUE idx)
{
- return rb_struct_lookup_default(s, idx, Qnil);
+ return rb_struct_lookup_default(s, idx, Qnil, false);
}
static VALUE
-rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound)
+rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound, bool name_only)
{
- int i = rb_struct_pos(s, &idx);
+ int i = rb_struct_pos(s, &idx, name_only);
if (i < 0) return notfound;
- return RSTRUCT_GET(s, i);
+ return RSTRUCT_GET_RAW(s, i);
}
static VALUE
@@ -1322,7 +1365,7 @@ struct_entry(VALUE s, long n)
static VALUE
rb_struct_values_at(int argc, VALUE *argv, VALUE s)
{
- return rb_get_values_at(s, RSTRUCT_LEN(s), argc, argv, struct_entry);
+ return rb_get_values_at(s, RSTRUCT_LEN_RAW(s), argc, argv, struct_entry);
}
/*
@@ -1352,9 +1395,9 @@ rb_struct_select(int argc, VALUE *argv, VALUE s)
rb_check_arity(argc, 0, 0);
RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
result = rb_ary_new();
- for (i = 0; i < RSTRUCT_LEN(s); i++) {
- if (RTEST(rb_yield(RSTRUCT_GET(s, i)))) {
- rb_ary_push(result, RSTRUCT_GET(s, i));
+ for (i = 0; i < RSTRUCT_LEN_RAW(s); i++) {
+ if (RTEST(rb_yield(RSTRUCT_GET_RAW(s, i)))) {
+ rb_ary_push(result, RSTRUCT_GET_RAW(s, i));
}
}
@@ -1367,9 +1410,9 @@ recursive_equal(VALUE s, VALUE s2, int recur)
long i, len;
if (recur) return Qtrue; /* Subtle! */
- len = RSTRUCT_LEN(s);
+ len = RSTRUCT_LEN_RAW(s);
for (i=0; i<len; i++) {
- if (!rb_equal(RSTRUCT_GET(s, i), RSTRUCT_GET(s2, i))) return Qfalse;
+ if (!rb_equal(RSTRUCT_GET_RAW(s, i), RSTRUCT_GET_RAW(s2, i))) return Qfalse;
}
return Qtrue;
}
@@ -1379,7 +1422,7 @@ recursive_equal(VALUE s, VALUE s2, int recur)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if and only if the following are true; otherwise returns +false+:
+ * Returns whether both the following are true:
*
* - <tt>other.class == self.class</tt>.
* - For each member name +name+, <tt>other.name == self.name</tt>.
@@ -1401,7 +1444,7 @@ rb_struct_equal(VALUE s, VALUE s2)
if (s == s2) return Qtrue;
if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
- if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
+ if (RSTRUCT_LEN_RAW(s) != RSTRUCT_LEN_RAW(s2)) {
rb_bug("inconsistent struct"); /* should never happen */
}
@@ -1435,9 +1478,9 @@ rb_struct_hash(VALUE s)
VALUE n;
h = rb_hash_start(rb_hash(rb_obj_class(s)));
- len = RSTRUCT_LEN(s);
+ len = RSTRUCT_LEN_RAW(s);
for (i = 0; i < len; i++) {
- n = rb_hash(RSTRUCT_GET(s, i));
+ n = rb_hash(RSTRUCT_GET_RAW(s, i));
h = rb_hash_uint(h, NUM2LONG(n));
}
h = rb_hash_end(h);
@@ -1450,9 +1493,9 @@ recursive_eql(VALUE s, VALUE s2, int recur)
long i, len;
if (recur) return Qtrue; /* Subtle! */
- len = RSTRUCT_LEN(s);
+ len = RSTRUCT_LEN_RAW(s);
for (i=0; i<len; i++) {
- if (!rb_eql(RSTRUCT_GET(s, i), RSTRUCT_GET(s2, i))) return Qfalse;
+ if (!rb_eql(RSTRUCT_GET_RAW(s, i), RSTRUCT_GET_RAW(s2, i))) return Qfalse;
}
return Qtrue;
}
@@ -1482,7 +1525,7 @@ rb_struct_eql(VALUE s, VALUE s2)
if (s == s2) return Qtrue;
if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
- if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
+ if (RSTRUCT_LEN_RAW(s) != RSTRUCT_LEN_RAW(s2)) {
rb_bug("inconsistent struct"); /* should never happen */
}
@@ -1504,7 +1547,7 @@ rb_struct_eql(VALUE s, VALUE s2)
VALUE
rb_struct_size(VALUE s)
{
- return LONG2FIX(RSTRUCT_LEN(s));
+ return LONG2FIX(RSTRUCT_LEN_RAW(s));
}
/*
@@ -1522,8 +1565,8 @@ rb_struct_size(VALUE s)
*
* Foo = Struct.new(:a)
* f = Foo.new(Foo.new({b: [1, 2, 3]}))
- * f.dig(:a) # => #<struct Foo a={:b=>[1, 2, 3]}>
- * f.dig(:a, :a) # => {:b=>[1, 2, 3]}
+ * f.dig(:a) # => #<struct Foo a={b: [1, 2, 3]}>
+ * f.dig(:a, :a) # => {b: [1, 2, 3]}
* f.dig(:a, :a, :b) # => [1, 2, 3]
* f.dig(:a, :a, :b, 0) # => 1
* f.dig(:b, 0) # => nil
@@ -1531,8 +1574,8 @@ rb_struct_size(VALUE s)
* Given integer argument +n+,
* returns the object that is specified by +n+ and +identifiers+:
*
- * f.dig(0) # => #<struct Foo a={:b=>[1, 2, 3]}>
- * f.dig(0, 0) # => {:b=>[1, 2, 3]}
+ * f.dig(0) # => #<struct Foo a={b: [1, 2, 3]}>
+ * f.dig(0, 0) # => {b: [1, 2, 3]}
* f.dig(0, 0, :b) # => [1, 2, 3]
* f.dig(0, 0, :b, 0) # => 1
* f.dig(:b, 0) # => nil
@@ -1709,6 +1752,21 @@ rb_data_define(VALUE super, ...)
return klass;
}
+static int
+data_hash_set_i(VALUE key, VALUE val, VALUE arg)
+{
+ struct struct_hash_set_arg *args = (struct struct_hash_set_arg *)arg;
+ int i = struct_hash_aset(key, val, args, true);
+ if (i >= 0 && args->missing_count > 0) {
+ VALUE k = RARRAY_AREF(args->missing_keywords, i);
+ if (!NIL_P(k)) {
+ RARRAY_ASET(args->missing_keywords, i, Qnil);
+ args->missing_count--;
+ }
+ }
+ return ST_CONTINUE;
+}
+
/*
* call-seq:
* DataClass::members -> array_of_symbols
@@ -1785,28 +1843,38 @@ rb_data_initialize_m(int argc, const VALUE *argv, VALUE self)
if (num_members > 0) {
rb_exc_raise(rb_keyword_error_new("missing", members));
}
+ OBJ_FREEZE(self);
return Qnil;
}
if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
rb_error_arity(argc, 0, 0);
}
- if (RHASH_SIZE(argv[0]) < num_members) {
- VALUE missing = rb_ary_diff(members, rb_hash_keys(argv[0]));
- rb_exc_raise(rb_keyword_error_new("missing", missing));
- }
-
- struct struct_hash_set_arg arg;
+ VALUE missing = rb_ary_dup(members);
+ RBASIC_CLEAR_CLASS(missing);
+ struct struct_hash_set_arg arg = {
+ .self = self,
+ .unknown_keywords = Qnil,
+ .missing_keywords = missing,
+ .missing_count = (long)num_members,
+ };
rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), num_members);
- arg.self = self;
- arg.unknown_keywords = Qnil;
- rb_hash_foreach(argv[0], struct_hash_set_i, (VALUE)&arg);
+ rb_hash_foreach(argv[0], data_hash_set_i, (VALUE)&arg);
// Freeze early before potentially raising, so that we don't leave an
// unfrozen copy on the heap, which could get exposed via ObjectSpace.
OBJ_FREEZE(self);
- if (arg.unknown_keywords != Qnil) {
- rb_exc_raise(rb_keyword_error_new("unknown", arg.unknown_keywords));
+ if (UNLIKELY(arg.missing_count > 0)) {
+ rb_ary_compact_bang(missing);
+ RUBY_ASSERT(RARRAY_LEN(missing) == arg.missing_count, "missing_count=%ld but %ld", arg.missing_count, RARRAY_LEN(missing));
+ RBASIC_SET_CLASS_RAW(missing, rb_cArray);
+ rb_exc_raise(rb_keyword_error_new("missing", missing));
+ }
+ VALUE unknown_keywords = arg.unknown_keywords;
+ if (UNLIKELY(!NIL_P(unknown_keywords))) {
+ RBASIC_SET_CLASS_RAW(unknown_keywords, rb_cArray);
+ rb_exc_raise(rb_keyword_error_new("unknown", unknown_keywords));
}
+
return Qnil;
}
@@ -1885,14 +1953,14 @@ rb_data_with(int argc, const VALUE *argv, VALUE self)
static VALUE
rb_data_inspect(VALUE s)
{
- return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<data "));
+ return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<data"));
}
/*
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if +other+ is the same class as +self+, and all members are
+ * Returns whether +other+ is the same class as +self+, and all members are
* equal.
*
* Examples:
@@ -1966,7 +2034,7 @@ rb_data_inspect(VALUE s)
* distance = Measure[10, 'km']
*
* distance.to_h
- * #=> {:amount=>10, :unit=>"km"}
+ * #=> {amount: 10, unit: "km"}
*
* Like Enumerable#to_h, if the block is provided, it is expected to
* produce key-value pairs to construct a hash:
@@ -2040,8 +2108,8 @@ rb_data_inspect(VALUE s)
* Measure = Data.define(:amount, :unit)
*
* distance = Measure[10, 'km']
- * distance.deconstruct_keys(nil) #=> {:amount=>10, :unit=>"km"}
- * distance.deconstruct_keys([:amount]) #=> {:amount=>10}
+ * distance.deconstruct_keys(nil) #=> {amount: 10, unit: "km"}
+ * distance.deconstruct_keys([:amount]) #=> {amount: 10}
*
* # usage
* case distance
@@ -2061,7 +2129,11 @@ rb_data_inspect(VALUE s)
* end
*/
-#define rb_data_deconstruct_keys rb_struct_deconstruct_keys
+static VALUE
+rb_data_deconstruct_keys(VALUE s, VALUE keys)
+{
+ return deconstruct_keys(s, keys, true);
+}
/*
* Document-class: Struct
@@ -2108,8 +2180,8 @@ rb_data_inspect(VALUE s)
*
* First, what's elsewhere. Class \Struct:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* See also Data, which is a somewhat similar, but stricter concept for defining immutable
diff --git a/symbol.c b/symbol.c
index 5f95769292..d26d668008 100644
--- a/symbol.c
+++ b/symbol.c
@@ -9,7 +9,9 @@
**********************************************************************/
+#include "darray.h"
#include "internal.h"
+#include "internal/concurrent_set.h"
#include "internal/error.h"
#include "internal/gc.h"
#include "internal/hash.h"
@@ -18,18 +20,13 @@
#include "internal/vm.h"
#include "probes.h"
#include "ruby/encoding.h"
+#include "ruby/ractor.h"
#include "ruby/st.h"
#include "symbol.h"
#include "vm_sync.h"
#include "builtin.h"
+#include "ruby/internal/attr/nonstring.h"
-#if defined(USE_SYMBOL_GC) && !(USE_SYMBOL_GC+0)
-# undef USE_SYMBOL_GC
-# define USE_SYMBOL_GC 0
-#else
-# undef USE_SYMBOL_GC
-# define USE_SYMBOL_GC 1
-#endif
#if defined(SYMBOL_DEBUG) && (SYMBOL_DEBUG+0)
# undef SYMBOL_DEBUG
# define SYMBOL_DEBUG 1
@@ -41,12 +38,14 @@
# define CHECK_ID_SERIAL SYMBOL_DEBUG
#endif
+#define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST))
+#define IDSET_ATTRSET_FOR_INTERN (~(~0U<<(1<<ID_SCOPE_SHIFT)) & ~(1U<<ID_ATTRSET))
+
#define SYMBOL_PINNED_P(sym) (RSYMBOL(sym)->id&~ID_SCOPE_MASK)
#define STATIC_SYM2ID(sym) RSHIFT((VALUE)(sym), RUBY_SPECIAL_SHIFT)
static ID register_static_symid(ID, const char *, long, rb_encoding *);
-static ID register_static_symid_str(ID, VALUE);
#define REGISTER_SYMID(id, name) register_static_symid((id), (name), strlen(name), enc)
#include "id.c"
@@ -56,6 +55,13 @@ static ID register_static_symid_str(ID, VALUE);
STATIC_ASSERT(op_tbl_name_size, sizeof(op_tbl[0].name) == 3);
#define op_tbl_len(i) (!op_tbl[i].name[1] ? 1 : !op_tbl[i].name[2] ? 2 : 3)
+
+#define GLOBAL_SYMBOLS_LOCKING(symbols) \
+ for (rb_symbols_t *symbols = &ruby_global_symbols, **locking = &symbols; \
+ locking; \
+ locking = NULL) \
+ RB_VM_LOCKING()
+
static void
Init_op_tbl(void)
{
@@ -75,29 +81,341 @@ Init_op_tbl(void)
static const int ID_ENTRY_UNIT = 512;
-enum id_entry_type {
- ID_ENTRY_STR,
- ID_ENTRY_SYM,
- ID_ENTRY_SIZE
+typedef struct {
+ rb_atomic_t next_id;
+ VALUE sym_set;
+
+ VALUE ids;
+} rb_symbols_t;
+
+rb_symbols_t ruby_global_symbols = {
+ .next_id = tNEXT_ID,
};
-rb_symbols_t ruby_global_symbols = {tNEXT_ID-1};
+struct sym_set_static_sym_entry {
+ VALUE sym;
+ VALUE str;
+};
+
+#define SYM_SET_SYM_STATIC_TAG 1
+
+static bool
+sym_set_sym_static_p(VALUE sym)
+{
+ return sym & SYM_SET_SYM_STATIC_TAG;
+}
+
+static VALUE
+sym_set_static_sym_tag(struct sym_set_static_sym_entry *sym)
+{
+ VALUE value = (VALUE)sym | SYM_SET_SYM_STATIC_TAG;
+ RUBY_ASSERT(IMMEDIATE_P(value));
+ RUBY_ASSERT(sym_set_sym_static_p(value));
+
+ return value;
+}
+
+static struct sym_set_static_sym_entry *
+sym_set_static_sym_untag(VALUE sym)
+{
+ RUBY_ASSERT(sym_set_sym_static_p(sym));
+
+ return (struct sym_set_static_sym_entry *)(sym & ~((VALUE)SYM_SET_SYM_STATIC_TAG));
+}
+
+static VALUE
+sym_set_sym_get_str(VALUE sym)
+{
+ VALUE str;
+ if (sym_set_sym_static_p(sym)) {
+ str = sym_set_static_sym_untag(sym)->str;
+ }
+ else {
+ RUBY_ASSERT(RB_TYPE_P(sym, T_SYMBOL));
+ str = RSYMBOL(sym)->fstr;
+ }
+
+ RUBY_ASSERT(RB_TYPE_P(str, T_STRING));
+
+ return str;
+}
+
+static VALUE
+sym_set_hash(VALUE sym)
+{
+ if (sym_set_sym_static_p(sym)) {
+ return (VALUE)rb_str_hash(sym_set_static_sym_untag(sym)->str);
+ }
+ else {
+ return (VALUE)RSYMBOL(sym)->hashval;
+ }
+}
+
+static bool
+sym_set_cmp(VALUE a, VALUE b)
+{
+ return rb_str_hash_cmp(sym_set_sym_get_str(a), sym_set_sym_get_str(b)) == false;
+}
+
+struct sym_id_entry {
+ VALUE sym;
+ VALUE str;
+};
+
+static void
+sym_id_entry_list_mark(void *ptr)
+{
+ rb_darray(struct sym_id_entry) ary = ptr;
+
+ struct sym_id_entry *entry;
+ rb_darray_foreach(ary, i, entry) {
+ // sym must be pinned because it may be used in places that don't
+ // support compaction
+ rb_gc_mark(entry->sym);
+ rb_gc_mark_movable(entry->str);
+ }
+}
+
+static void
+sym_id_entry_list_free(void *ptr)
+{
+ rb_darray_free_sized(ptr, struct sym_id_entry);
+}
+
+static size_t
+sym_id_entry_list_memsize(const void *ptr)
+{
+ const rb_darray(struct sym_id_entry) ary = ptr;
+
+ return rb_darray_memsize(ary);
+}
+
+static void
+sym_id_entry_list_compact(void *ptr)
+{
+ rb_darray(struct sym_id_entry) ary = ptr;
+
+ struct sym_id_entry *entry;
+ rb_darray_foreach(ary, i, entry) {
+ entry->str = rb_gc_location(entry->str);
+ }
+}
+
+static const rb_data_type_t sym_id_entry_list_type = {
+ "symbol_id_entry_list",
+ {
+ sym_id_entry_list_mark,
+ sym_id_entry_list_free,
+ sym_id_entry_list_memsize,
+ sym_id_entry_list_compact,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+};
+
+static int
+sym_check_asciionly(VALUE str, bool fake_str)
+{
+ if (!rb_enc_asciicompat(rb_enc_get(str))) return FALSE;
+ switch (rb_enc_str_coderange(str)) {
+ case ENC_CODERANGE_BROKEN:
+ if (fake_str) {
+ str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
+ }
+ rb_raise(rb_eEncodingError, "invalid symbol in encoding %s :%+"PRIsVALUE,
+ rb_enc_name(rb_enc_get(str)), str);
+ case ENC_CODERANGE_7BIT:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static VALUE
+dup_string_for_create(VALUE str)
+{
+ rb_encoding *enc = rb_enc_get(str);
+
+ str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), enc);
+
+ rb_encoding *ascii = rb_usascii_encoding();
+ if (enc != ascii && sym_check_asciionly(str, false)) {
+ rb_enc_associate(str, ascii);
+ }
+ OBJ_FREEZE(str);
+
+ str = rb_fstring(str);
+ return str;
+}
+
+static int
+rb_str_symname_type(VALUE name, unsigned int allowed_attrset)
+{
+ const char *ptr = StringValuePtr(name);
+ long len = RSTRING_LEN(name);
+ int type = rb_enc_symname_type(ptr, len, rb_enc_get(name), allowed_attrset);
+ RB_GC_GUARD(name);
+ return type;
+}
+
+static ID
+next_id_base(void)
+{
+ rb_atomic_t serial = RUBY_ATOMIC_FETCH_ADD(ruby_global_symbols.next_id, 1);
+
+ return (ID)serial << ID_SCOPE_SHIFT;
+}
+
+static void
+set_id_entry(rb_symbols_t *symbols, rb_id_serial_t num, VALUE str, VALUE sym)
+{
+ ASSERT_vm_locking();
+ RUBY_ASSERT_BUILTIN_TYPE(str, T_STRING);
+ RUBY_ASSERT_BUILTIN_TYPE(sym, T_SYMBOL);
+
+ size_t idx = num / ID_ENTRY_UNIT;
+
+ VALUE id_entry_list, ids = symbols->ids;
+ rb_darray(struct sym_id_entry) entries;
+ if (idx >= (size_t)RARRAY_LEN(ids) || NIL_P(id_entry_list = rb_ary_entry(ids, (long)idx))) {
+ rb_darray_make(&entries, ID_ENTRY_UNIT);
+ id_entry_list = TypedData_Wrap_Struct(0, &sym_id_entry_list_type, entries);
+ rb_ary_store(ids, (long)idx, id_entry_list);
+ }
+ else {
+ entries = RTYPEDDATA_GET_DATA(id_entry_list);
+ }
+
+ idx = num % ID_ENTRY_UNIT;
+ struct sym_id_entry *entry = rb_darray_ref(entries, idx);
+ RUBY_ASSERT(entry->str == 0);
+ RUBY_ASSERT(entry->sym == 0);
-static const struct st_hash_type symhash = {
- rb_str_hash_cmp,
- rb_str_hash,
+ RB_OBJ_WRITE(id_entry_list, &entry->str, str);
+ RB_OBJ_WRITE(id_entry_list, &entry->sym, sym);
+}
+
+static VALUE
+sym_set_create(VALUE sym, void *data)
+{
+ bool create_dynamic_symbol = (bool)data;
+
+ struct sym_set_static_sym_entry *static_sym_entry = sym_set_static_sym_untag(sym);
+
+ VALUE str = dup_string_for_create(static_sym_entry->str);
+
+ if (create_dynamic_symbol) {
+ NEWOBJ_OF(obj, struct RSymbol, rb_cSymbol, T_SYMBOL, sizeof(struct RSymbol));
+
+ rb_encoding *enc = rb_enc_get(str);
+ rb_enc_set_index((VALUE)obj, rb_enc_to_index(enc));
+ RB_OBJ_WRITE((VALUE)obj, &obj->fstr, str);
+ RB_OBJ_SET_FROZEN_SHAREABLE((VALUE)obj);
+
+ int id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
+ if (id < 0) id = ID_INTERNAL;
+ obj->id = id;
+
+ obj->hashval = rb_str_hash(str);
+ RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(obj->fstr));
+
+ return (VALUE)obj;
+ }
+ else {
+ struct sym_set_static_sym_entry *new_static_sym_entry = xmalloc(sizeof(struct sym_set_static_sym_entry));
+ new_static_sym_entry->str = str;
+
+ VALUE static_sym = static_sym_entry->sym;
+ if (static_sym == 0) {
+ ID id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
+ if (id == (ID)-1) id = ID_INTERNAL;
+
+ id |= next_id_base();
+ id |= ID_STATIC_SYM;
+
+ static_sym = STATIC_ID2SYM(id);
+ }
+ new_static_sym_entry->sym = static_sym;
+
+ RB_VM_LOCKING() {
+ set_id_entry(&ruby_global_symbols, rb_id_to_serial(STATIC_SYM2ID(static_sym)), str, static_sym);
+ }
+
+ return sym_set_static_sym_tag(new_static_sym_entry);
+ }
+}
+
+static void
+sym_set_free(VALUE sym)
+{
+ if (sym_set_sym_static_p(sym)) {
+ xfree(sym_set_static_sym_untag(sym));
+ }
+}
+
+static const struct rb_concurrent_set_funcs sym_set_funcs = {
+ .hash = sym_set_hash,
+ .cmp = sym_set_cmp,
+ .create = sym_set_create,
+ .free = sym_set_free,
};
+static VALUE
+sym_set_entry_to_sym(VALUE entry)
+{
+ if (sym_set_sym_static_p(entry)) {
+ RUBY_ASSERT(STATIC_SYM_P(sym_set_static_sym_untag(entry)->sym));
+
+ if (!STATIC_SYM_P(sym_set_static_sym_untag(entry)->sym)) rb_bug("not sym");
+
+ return sym_set_static_sym_untag(entry)->sym;
+ }
+ else {
+ RUBY_ASSERT(DYNAMIC_SYM_P(entry));
+ if (!DYNAMIC_SYM_P(entry)) rb_bug("not sym");
+
+ return entry;
+ }
+}
+
+static VALUE
+sym_find_or_insert_dynamic_symbol(rb_symbols_t *symbols, const VALUE str)
+{
+ struct sym_set_static_sym_entry static_sym = {
+ .str = str
+ };
+ return sym_set_entry_to_sym(
+ rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)true)
+ );
+}
+
+static VALUE
+sym_find_or_insert_static_symbol(rb_symbols_t *symbols, const VALUE str)
+{
+ struct sym_set_static_sym_entry static_sym = {
+ .str = str
+ };
+ return sym_set_entry_to_sym(
+ rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)false)
+ );
+}
+
+static VALUE
+sym_find_or_insert_static_symbol_id(rb_symbols_t *symbols, const VALUE str, ID id)
+{
+ struct sym_set_static_sym_entry static_sym = {
+ .sym = STATIC_ID2SYM(id),
+ .str = str,
+ };
+ return sym_set_entry_to_sym(
+ rb_concurrent_set_find_or_insert(&symbols->sym_set, sym_set_static_sym_tag(&static_sym), (void *)false)
+ );
+}
+
void
Init_sym(void)
{
rb_symbols_t *symbols = &ruby_global_symbols;
- VALUE dsym_fstrs = rb_ident_hash_new();
- symbols->dsymbol_fstr_hash = dsym_fstrs;
- rb_obj_hide(dsym_fstrs);
-
- symbols->str_sym = st_init_table_with_size(&symhash, 1000);
+ symbols->sym_set = rb_concurrent_set_new(&sym_set_funcs, 1024);
symbols->ids = rb_ary_hidden_new(0);
Init_op_tbl();
@@ -105,38 +423,34 @@ Init_sym(void)
}
void
-rb_sym_global_symbols_mark(void)
+rb_sym_global_symbols_mark_and_move(void)
{
rb_symbols_t *symbols = &ruby_global_symbols;
- rb_gc_mark_movable(symbols->ids);
- rb_gc_mark_movable(symbols->dsymbol_fstr_hash);
+ rb_gc_mark_and_move(&symbols->sym_set);
+ rb_gc_mark_and_move(&symbols->ids);
}
-void
-rb_sym_global_symbols_update_references(void)
+static int
+rb_free_global_symbol_table_i(VALUE *sym_ptr, void *data)
{
- rb_symbols_t *symbols = &ruby_global_symbols;
+ sym_set_free(*sym_ptr);
- symbols->ids = rb_gc_location(symbols->ids);
- symbols->dsymbol_fstr_hash = rb_gc_location(symbols->dsymbol_fstr_hash);
+ return ST_DELETE;
}
-WARN_UNUSED_RESULT(static VALUE dsymbol_alloc(rb_symbols_t *symbols, const VALUE klass, const VALUE str, rb_encoding *const enc, const ID type));
-WARN_UNUSED_RESULT(static VALUE dsymbol_check(rb_symbols_t *symbols, const VALUE sym));
-WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
-WARN_UNUSED_RESULT(static VALUE lookup_str_sym_with_lock(rb_symbols_t *symbols, const VALUE str));
-WARN_UNUSED_RESULT(static VALUE lookup_str_sym(const VALUE str));
-WARN_UNUSED_RESULT(static VALUE lookup_id_str(ID id));
-WARN_UNUSED_RESULT(static ID intern_str(VALUE str, int mutable));
+void
+rb_free_global_symbol_table(void)
+{
+ rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_free_global_symbol_table_i, NULL);
+}
-#define GLOBAL_SYMBOLS_ENTER(symbols) rb_symbols_t *symbols = &ruby_global_symbols; RB_VM_LOCK_ENTER()
-#define GLOBAL_SYMBOLS_LEAVE() RB_VM_LOCK_LEAVE()
+WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
+WARN_UNUSED_RESULT(static VALUE get_id_str(ID id));
ID
rb_id_attrset(ID id)
{
- VALUE str, sym;
int scope;
if (!is_notop_id(id)) {
@@ -151,13 +465,14 @@ rb_id_attrset(ID id)
scope = id_type(id);
switch (scope) {
case ID_LOCAL: case ID_INSTANCE: case ID_GLOBAL:
- case ID_CONST: case ID_CLASS: case ID_JUNK:
+ case ID_CONST: case ID_CLASS: case ID_INTERNAL:
break;
case ID_ATTRSET:
return id;
default:
{
- if ((str = lookup_id_str(id)) != 0) {
+ VALUE str = get_id_str(id);
+ if (str != 0) {
rb_name_error(id, "cannot make unknown type ID %d:%"PRIsVALUE" attrset",
scope, str);
}
@@ -169,9 +484,25 @@ rb_id_attrset(ID id)
}
}
+ bool error = false;
/* make new symbol and ID */
- if (!(str = lookup_id_str(id))) {
- static const char id_types[][8] = {
+ VALUE str = get_id_str(id);
+ if (str) {
+ str = rb_str_dup(str);
+ rb_str_cat(str, "=", 1);
+ if (sym_check_asciionly(str, false)) {
+ rb_enc_associate(str, rb_usascii_encoding());
+ }
+
+ VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
+ id = rb_sym2id(sym);
+ }
+ else {
+ error = true;
+ }
+
+ if (error) {
+ RBIMPL_ATTR_NONSTRING_ARRAY() static const char id_types[][8] = {
"local",
"instance",
"invalid",
@@ -179,15 +510,12 @@ rb_id_attrset(ID id)
"attrset",
"const",
"class",
- "junk",
+ "internal",
};
rb_name_error(id, "cannot make anonymous %.*s ID %"PRIxVALUE" attrset",
(int)sizeof(id_types[0]), id_types[scope], (VALUE)id);
}
- str = rb_str_dup(str);
- rb_str_cat(str, "=", 1);
- sym = lookup_str_sym(str);
- id = sym ? rb_sym2id(sym) : intern_str(str, 1);
+
return id;
}
@@ -265,9 +593,6 @@ rb_sym_constant_char_p(const char *name, long nlen, rb_encoding *enc)
return FALSE;
}
-#define IDSET_ATTRSET_FOR_SYNTAX ((1U<<ID_LOCAL)|(1U<<ID_CONST))
-#define IDSET_ATTRSET_FOR_INTERN (~(~0U<<(1<<ID_SCOPE_SHIFT)) & ~(1U<<ID_ATTRSET))
-
struct enc_synmane_type_leading_chars_tag {
const enum { invalid, stophere, needmore, } kind;
const enum ruby_id_types type;
@@ -311,66 +636,66 @@ enc_synmane_type_leading_chars(const char *name, long len, rb_encoding *enc, int
case '<':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 1, };
- case '<': return (t) { stophere, ID_JUNK, 2, };
+ default: return (t) { stophere, ID_INTERNAL, 1, };
+ case '<': return (t) { stophere, ID_INTERNAL, 2, };
case '=':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 2, };
- case '>': return (t) { stophere, ID_JUNK, 3, };
+ default: return (t) { stophere, ID_INTERNAL, 2, };
+ case '>': return (t) { stophere, ID_INTERNAL, 3, };
}
}
case '>':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 1, };
- case '>': case '=': return (t) { stophere, ID_JUNK, 2, };
+ default: return (t) { stophere, ID_INTERNAL, 1, };
+ case '>': case '=': return (t) { stophere, ID_INTERNAL, 2, };
}
case '=':
switch (*++m) {
- default: return (t) { invalid, 0, 1, };
- case '~': return (t) { stophere, ID_JUNK, 2, };
+ default: return (t) { invalid, 0, 1, };
+ case '~': return (t) { stophere, ID_INTERNAL, 2, };
case '=':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 2, };
- case '=': return (t) { stophere, ID_JUNK, 3, };
+ default: return (t) { stophere, ID_INTERNAL, 2, };
+ case '=': return (t) { stophere, ID_INTERNAL, 3, };
}
}
case '*':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 1, };
- case '*': return (t) { stophere, ID_JUNK, 2, };
+ default: return (t) { stophere, ID_INTERNAL, 1, };
+ case '*': return (t) { stophere, ID_INTERNAL, 2, };
}
case '+': case '-':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 1, };
- case '@': return (t) { stophere, ID_JUNK, 2, };
+ default: return (t) { stophere, ID_INTERNAL, 1, };
+ case '@': return (t) { stophere, ID_INTERNAL, 2, };
}
case '|': case '^': case '&': case '/': case '%': case '~': case '`':
- return (t) { stophere, ID_JUNK, 1, };
+ return (t) { stophere, ID_INTERNAL, 1, };
case '[':
switch (*++m) {
- default: return (t) { needmore, ID_JUNK, 0, };
+ default: return (t) { needmore, ID_INTERNAL, 0, };
case ']':
switch (*++m) {
- default: return (t) { stophere, ID_JUNK, 2, };
- case '=': return (t) { stophere, ID_JUNK, 3, };
+ default: return (t) { stophere, ID_INTERNAL, 2, };
+ case '=': return (t) { stophere, ID_INTERNAL, 3, };
}
}
case '!':
switch (*++m) {
- case '=': case '~': return (t) { stophere, ID_JUNK, 2, };
+ case '=': case '~': return (t) { stophere, ID_INTERNAL, 2, };
default:
- if (allowed_attrset & (1U << ID_JUNK)) {
- return (t) { needmore, ID_JUNK, 1, };
+ if (allowed_attrset & (1U << ID_INTERNAL)) {
+ return (t) { needmore, ID_INTERNAL, 1, };
}
else {
- return (t) { stophere, ID_JUNK, 1, };
+ return (t) { stophere, ID_INTERNAL, 1, };
}
}
@@ -411,7 +736,7 @@ rb_enc_symname_type(const char *name, long len, rb_encoding *enc, unsigned int a
switch (*m) {
case '!': case '?':
if (type == ID_GLOBAL || type == ID_CLASS || type == ID_INSTANCE) return -1;
- type = ID_JUNK;
+ type = ID_INTERNAL;
++m;
if (m + 1 < e || *m != '=') break;
/* fall through */
@@ -432,400 +757,131 @@ rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
return rb_enc_symname_type(name, len, enc, IDSET_ATTRSET_FOR_SYNTAX) != -1;
}
-static int
-rb_str_symname_type(VALUE name, unsigned int allowed_attrset)
+static struct sym_id_entry *
+get_id_serial_entry(rb_id_serial_t num)
{
- const char *ptr = StringValuePtr(name);
- long len = RSTRING_LEN(name);
- int type = rb_enc_symname_type(ptr, len, rb_enc_get(name), allowed_attrset);
- RB_GC_GUARD(name);
- return type;
-}
+ struct sym_id_entry *entry = NULL;
-static void
-set_id_entry(rb_symbols_t *symbols, rb_id_serial_t num, VALUE str, VALUE sym)
-{
- ASSERT_vm_locking();
- RUBY_ASSERT_BUILTIN_TYPE(str, T_STRING);
- RUBY_ASSERT_BUILTIN_TYPE(sym, T_SYMBOL);
-
- size_t idx = num / ID_ENTRY_UNIT;
-
- VALUE ary, ids = symbols->ids;
- if (idx >= (size_t)RARRAY_LEN(ids) || NIL_P(ary = rb_ary_entry(ids, (long)idx))) {
- ary = rb_ary_hidden_new(ID_ENTRY_UNIT * ID_ENTRY_SIZE);
- rb_ary_store(ids, (long)idx, ary);
- }
- idx = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE;
- rb_ary_store(ary, (long)idx + ID_ENTRY_STR, str);
- rb_ary_store(ary, (long)idx + ID_ENTRY_SYM, sym);
-}
-
-static VALUE
-get_id_serial_entry(rb_id_serial_t num, ID id, const enum id_entry_type t)
-{
- VALUE result = 0;
-
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- if (num && num <= symbols->last_id) {
+ GLOBAL_SYMBOLS_LOCKING(symbols) {
+ if (num && num < RUBY_ATOMIC_LOAD(symbols->next_id)) {
size_t idx = num / ID_ENTRY_UNIT;
VALUE ids = symbols->ids;
- VALUE ary;
- if (idx < (size_t)RARRAY_LEN(ids) && !NIL_P(ary = rb_ary_entry(ids, (long)idx))) {
- long pos = (long)(num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE;
- result = rb_ary_entry(ary, pos + t);
+ VALUE id_entry_list;
+ if (idx < (size_t)RARRAY_LEN(ids) && !NIL_P(id_entry_list = rb_ary_entry(ids, (long)idx))) {
+ rb_darray(struct sym_id_entry) entries = RTYPEDDATA_GET_DATA(id_entry_list);
- if (NIL_P(result)) {
- result = 0;
- }
- else if (CHECK_ID_SERIAL) {
- if (id) {
- VALUE sym = result;
- if (t != ID_ENTRY_SYM)
- sym = rb_ary_entry(ary, pos + ID_ENTRY_SYM);
- if (STATIC_SYM_P(sym)) {
- if (STATIC_SYM2ID(sym) != id) result = 0;
- }
- else {
- if (RSYMBOL(sym)->id != id) result = 0;
- }
- }
- }
+ size_t pos = (size_t)(num % ID_ENTRY_UNIT);
+ RUBY_ASSERT(pos < rb_darray_size(entries));
+ entry = rb_darray_ref(entries, pos);
}
}
}
- GLOBAL_SYMBOLS_LEAVE();
- if (result) {
- switch (t) {
- case ID_ENTRY_STR:
- RUBY_ASSERT_BUILTIN_TYPE(result, T_STRING);
- break;
- case ID_ENTRY_SYM:
- RUBY_ASSERT_BUILTIN_TYPE(result, T_SYMBOL);
- break;
- default:
- break;
- }
- }
+ return entry;
+}
- return result;
+static VALUE
+get_id_sym(ID id)
+{
+ struct sym_id_entry *entry = get_id_serial_entry(rb_id_to_serial(id));
+ return entry ? entry->sym : 0;
}
static VALUE
-get_id_entry(ID id, const enum id_entry_type t)
+get_id_str(ID id)
{
- return get_id_serial_entry(rb_id_to_serial(id), id, t);
+ struct sym_id_entry *entry = get_id_serial_entry(rb_id_to_serial(id));
+ return entry ? entry->str : 0;
}
int
rb_static_id_valid_p(ID id)
{
- return STATIC_ID2SYM(id) == get_id_entry(id, ID_ENTRY_SYM);
+ return STATIC_ID2SYM(id) == get_id_sym(id);
}
static inline ID
rb_id_serial_to_id(rb_id_serial_t num)
{
if (is_notop_id((ID)num)) {
- VALUE sym = get_id_serial_entry(num, 0, ID_ENTRY_SYM);
- if (sym) return SYM2ID(sym);
- return ((ID)num << ID_SCOPE_SHIFT) | ID_INTERNAL | ID_STATIC_SYM;
+ struct sym_id_entry *entry = get_id_serial_entry(num);
+ if (entry && entry->sym != 0) {
+ return SYM2ID(entry->sym);
+ }
+ else {
+ return ((ID)num << ID_SCOPE_SHIFT) | ID_INTERNAL | ID_STATIC_SYM;
+ }
}
else {
return (ID)num;
}
}
-static int
-register_sym_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
-{
- if (existing) {
- rb_fatal("symbol :% "PRIsVALUE" is already registered with %"PRIxVALUE,
- (VALUE)*key, (VALUE)*value);
- }
- *value = arg;
- return ST_CONTINUE;
-}
-
-static void
-register_sym(rb_symbols_t *symbols, VALUE str, VALUE sym)
-{
- ASSERT_vm_locking();
-
- if (SYMBOL_DEBUG) {
- st_update(symbols->str_sym, (st_data_t)str,
- register_sym_update_callback, (st_data_t)sym);
- }
- else {
- st_add_direct(symbols->str_sym, (st_data_t)str, (st_data_t)sym);
- }
-}
-
-void
-rb_free_static_symid_str(void)
-{
- GLOBAL_SYMBOLS_ENTER(symbols)
- {
- st_free_table(symbols->str_sym);
- }
- GLOBAL_SYMBOLS_LEAVE();
-}
-
-static void
-unregister_sym(rb_symbols_t *symbols, VALUE str, VALUE sym)
-{
- ASSERT_vm_locking();
-
- st_data_t str_data = (st_data_t)str;
- if (!st_delete(symbols->str_sym, &str_data, NULL)) {
- rb_bug("%p can't remove str from str_id (%s)", (void *)sym, RSTRING_PTR(str));
- }
-}
-
static ID
register_static_symid(ID id, const char *name, long len, rb_encoding *enc)
{
VALUE str = rb_enc_str_new(name, len, enc);
- return register_static_symid_str(id, str);
-}
-
-static ID
-register_static_symid_str(ID id, VALUE str)
-{
- rb_id_serial_t num = rb_id_to_serial(id);
- VALUE sym = STATIC_ID2SYM(id);
-
OBJ_FREEZE(str);
str = rb_fstring(str);
RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(str));
- GLOBAL_SYMBOLS_ENTER(symbols)
- {
- register_sym(symbols, str, sym);
- set_id_entry(symbols, num, str, sym);
- }
- GLOBAL_SYMBOLS_LEAVE();
+ sym_find_or_insert_static_symbol_id(&ruby_global_symbols, str, id);
return id;
}
-static int
-sym_check_asciionly(VALUE str, bool fake_str)
-{
- if (!rb_enc_asciicompat(rb_enc_get(str))) return FALSE;
- switch (rb_enc_str_coderange(str)) {
- case ENC_CODERANGE_BROKEN:
- if (fake_str) {
- str = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
- }
- rb_raise(rb_eEncodingError, "invalid symbol in encoding %s :%+"PRIsVALUE,
- rb_enc_name(rb_enc_get(str)), str);
- case ENC_CODERANGE_7BIT:
- return TRUE;
- }
- return FALSE;
-}
-
-#if 0
-/*
- * _str_ itself will be registered at the global symbol table. _str_
- * can be modified before the registration, since the encoding will be
- * set to ASCII-8BIT if it is a special global name.
- */
-
-static inline void
-must_be_dynamic_symbol(VALUE x)
-{
- if (UNLIKELY(!DYNAMIC_SYM_P(x))) {
- if (STATIC_SYM_P(x)) {
- VALUE str = lookup_id_str(RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT));
-
- if (str) {
- rb_bug("wrong argument: %s (inappropriate Symbol)", RSTRING_PTR(str));
- }
- else {
- rb_bug("wrong argument: inappropriate Symbol (%p)", (void *)x);
- }
- }
- else {
- rb_bug("wrong argument type %s (expected Symbol)", rb_builtin_class_name(x));
- }
- }
-}
-#endif
-
static VALUE
-dsymbol_alloc(rb_symbols_t *symbols, const VALUE klass, const VALUE str, rb_encoding * const enc, const ID type)
+sym_find(VALUE str)
{
- ASSERT_vm_locking();
-
- NEWOBJ_OF(obj, struct RSymbol, klass, T_SYMBOL | FL_WB_PROTECTED, sizeof(struct RSymbol), 0);
-
- long hashval;
-
- rb_enc_set_index((VALUE)obj, rb_enc_to_index(enc));
- OBJ_FREEZE((VALUE)obj);
- RB_OBJ_WRITE((VALUE)obj, &obj->fstr, str);
- obj->id = type;
-
- /* we want hashval to be in Fixnum range [ruby-core:15713] r15672 */
- hashval = (long)rb_str_hash(str);
- obj->hashval = RSHIFT((long)hashval, 1);
- register_sym(symbols, str, (VALUE)obj);
- rb_hash_aset(symbols->dsymbol_fstr_hash, str, Qtrue);
- RUBY_DTRACE_CREATE_HOOK(SYMBOL, RSTRING_PTR(obj->fstr));
+ VALUE sym;
- return (VALUE)obj;
-}
+ struct sym_set_static_sym_entry static_sym = {
+ .str = str
+ };
+ sym = rb_concurrent_set_find(&ruby_global_symbols.sym_set, sym_set_static_sym_tag(&static_sym));
-static inline VALUE
-dsymbol_check(rb_symbols_t *symbols, const VALUE sym)
-{
- ASSERT_vm_locking();
-
- if (UNLIKELY(rb_objspace_garbage_object_p(sym))) {
- const VALUE fstr = RSYMBOL(sym)->fstr;
- const ID type = RSYMBOL(sym)->id & ID_SCOPE_MASK;
- RSYMBOL(sym)->fstr = 0;
- unregister_sym(symbols, fstr, sym);
- return dsymbol_alloc(symbols, rb_cSymbol, fstr, rb_enc_get(fstr), type);
+ if (sym) {
+ return sym_set_entry_to_sym(sym);
}
else {
- return sym;
+ return 0;
}
}
static ID
lookup_str_id(VALUE str)
{
- st_data_t sym_data;
- int found;
+ VALUE sym = sym_find(str);
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- found = st_lookup(symbols->str_sym, (st_data_t)str, &sym_data);
+ if (sym == 0) {
+ return (ID)0;
}
- GLOBAL_SYMBOLS_LEAVE();
- if (found) {
- const VALUE sym = (VALUE)sym_data;
-
- if (STATIC_SYM_P(sym)) {
- return STATIC_SYM2ID(sym);
- }
- else if (DYNAMIC_SYM_P(sym)) {
- ID id = RSYMBOL(sym)->id;
- if (id & ~ID_SCOPE_MASK) return id;
- }
- else {
- rb_bug("non-symbol object %s:%"PRIxVALUE" for %"PRIsVALUE" in symbol table",
- rb_builtin_class_name(sym), sym, str);
- }
+ if (STATIC_SYM_P(sym)) {
+ return STATIC_SYM2ID(sym);
}
- return (ID)0;
-}
-
-static VALUE
-lookup_str_sym_with_lock(rb_symbols_t *symbols, const VALUE str)
-{
- st_data_t sym_data;
- if (st_lookup(symbols->str_sym, (st_data_t)str, &sym_data)) {
- VALUE sym = (VALUE)sym_data;
- if (DYNAMIC_SYM_P(sym)) {
- sym = dsymbol_check(symbols, sym);
- }
- return sym;
+ else if (DYNAMIC_SYM_P(sym)) {
+ ID id = RSYMBOL(sym)->id;
+ if (id & ~ID_SCOPE_MASK) return id;
}
else {
- return Qfalse;
- }
-}
-
-static VALUE
-lookup_str_sym(const VALUE str)
-{
- VALUE sym;
-
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- sym = lookup_str_sym_with_lock(symbols, str);
+ rb_bug("non-symbol object %s:%"PRIxVALUE" for %"PRIsVALUE" in symbol table",
+ rb_builtin_class_name(sym), sym, str);
}
- GLOBAL_SYMBOLS_LEAVE();
- return sym;
-}
-
-static VALUE
-lookup_id_str(ID id)
-{
- return get_id_entry(id, ID_ENTRY_STR);
+ return (ID)0;
}
ID
rb_intern3(const char *name, long len, rb_encoding *enc)
{
- VALUE sym;
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
VALUE str = rb_setup_fake_str(&fake_str, name, len, enc);
OBJ_FREEZE(str);
- sym = lookup_str_sym(str);
- if (sym) return rb_sym2id(sym);
- str = rb_enc_str_new(name, len, enc); /* make true string */
- return intern_str(str, 1);
-}
-
-static ID
-next_id_base_with_lock(rb_symbols_t *symbols)
-{
- ID id;
- rb_id_serial_t next_serial = symbols->last_id + 1;
-
- if (next_serial == 0) {
- id = (ID)-1;
- }
- else {
- const size_t num = ++symbols->last_id;
- id = num << ID_SCOPE_SHIFT;
- }
-
- return id;
-}
-
-static ID
-next_id_base(void)
-{
- ID id;
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- id = next_id_base_with_lock(symbols);
- }
- GLOBAL_SYMBOLS_LEAVE();
- return id;
-}
-static ID
-intern_str(VALUE str, int mutable)
-{
- ID id;
- ID nid;
-
- id = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
- if (id == (ID)-1) id = ID_JUNK;
- if (sym_check_asciionly(str, false)) {
- if (!mutable) str = rb_str_dup(str);
- rb_enc_associate(str, rb_usascii_encoding());
- }
- if ((nid = next_id_base()) == (ID)-1) {
- str = rb_str_ellipsize(str, 20);
- rb_raise(rb_eRuntimeError, "symbol table overflow (symbol %"PRIsVALUE")",
- str);
- }
- id |= nid;
- id |= ID_STATIC_SYM;
- return register_static_symid_str(id, str);
+ VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
+ return rb_sym2id(sym);
}
ID
@@ -844,13 +900,48 @@ rb_intern(const char *name)
ID
rb_intern_str(VALUE str)
{
- VALUE sym = lookup_str_sym(str);
+ VALUE sym = sym_find_or_insert_static_symbol(&ruby_global_symbols, str);
+ return SYM2ID(sym);
+}
- if (sym) {
- return SYM2ID(sym);
+bool
+rb_obj_is_symbol_table(VALUE obj)
+{
+ return obj == ruby_global_symbols.sym_set;
+}
+
+struct global_symbol_table_foreach_weak_reference_data {
+ int (*callback)(VALUE *key, void *data);
+ void *data;
+};
+
+static int
+rb_sym_global_symbol_table_foreach_weak_reference_i(VALUE *key, void *d)
+{
+ struct global_symbol_table_foreach_weak_reference_data *data = d;
+ VALUE sym = *key;
+
+ if (sym_set_sym_static_p(sym)) {
+ struct sym_set_static_sym_entry *static_sym = sym_set_static_sym_untag(sym);
+
+ return data->callback(&static_sym->str, data->data);
+ }
+ else {
+ return data->callback(key, data->data);
}
+}
+
+void
+rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data)
+{
+ if (!ruby_global_symbols.sym_set) return;
+
+ struct global_symbol_table_foreach_weak_reference_data foreach_data = {
+ .callback = callback,
+ .data = data,
+ };
- return intern_str(str, 0);
+ rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_sym_global_symbol_table_foreach_weak_reference_i, &foreach_data);
}
void
@@ -859,101 +950,48 @@ rb_gc_free_dsymbol(VALUE sym)
VALUE str = RSYMBOL(sym)->fstr;
if (str) {
- RSYMBOL(sym)->fstr = 0;
+ rb_concurrent_set_delete_by_identity(ruby_global_symbols.sym_set, sym);
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- unregister_sym(symbols, str, sym);
- rb_hash_delete_entry(symbols->dsymbol_fstr_hash, str);
- }
- GLOBAL_SYMBOLS_LEAVE();
+ RSYMBOL(sym)->fstr = 0;
}
}
/*
* call-seq:
- * str.intern -> symbol
- * str.to_sym -> symbol
- *
- * Returns the +Symbol+ corresponding to <i>str</i>, creating the
- * symbol if it did not previously exist. See Symbol#id2name.
- *
- * "Koala".intern #=> :Koala
- * s = 'cat'.to_sym #=> :cat
- * s == :cat #=> true
- * s = '@cat'.to_sym #=> :@cat
- * s == :@cat #=> true
+ * intern -> symbol
*
- * This can also be used to create symbols that cannot be represented using the
- * <code>:xxx</code> notation.
+ * :include: doc/string/intern.rdoc
*
- * 'cat and dog'.to_sym #=> :"cat and dog"
*/
VALUE
rb_str_intern(VALUE str)
{
- VALUE sym;
-
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- sym = lookup_str_sym_with_lock(symbols, str);
-
- if (sym) {
- // ok
- }
- else if (USE_SYMBOL_GC) {
- rb_encoding *enc = rb_enc_get(str);
- rb_encoding *ascii = rb_usascii_encoding();
- if (enc != ascii && sym_check_asciionly(str, false)) {
- str = rb_str_dup(str);
- rb_enc_associate(str, ascii);
- OBJ_FREEZE(str);
- enc = ascii;
- }
- else {
- str = rb_str_dup(str);
- OBJ_FREEZE(str);
- }
- str = rb_fstring(str);
- int type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
- if (type < 0) type = ID_JUNK;
- sym = dsymbol_alloc(symbols, rb_cSymbol, str, enc, type);
- }
- else {
- ID id = intern_str(str, 0);
- sym = ID2SYM(id);
- }
- }
- GLOBAL_SYMBOLS_LEAVE();
- return sym;
+ return sym_find_or_insert_dynamic_symbol(&ruby_global_symbols, str);
}
ID
rb_sym2id(VALUE sym)
{
- ID id;
+ ID id = 0;
if (STATIC_SYM_P(sym)) {
id = STATIC_SYM2ID(sym);
}
else if (DYNAMIC_SYM_P(sym)) {
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- sym = dsymbol_check(symbols, sym);
+ GLOBAL_SYMBOLS_LOCKING(symbols) {
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(sym));
id = RSYMBOL(sym)->id;
if (UNLIKELY(!(id & ~ID_SCOPE_MASK))) {
VALUE fstr = RSYMBOL(sym)->fstr;
- ID num = next_id_base_with_lock(symbols);
+ ID num = next_id_base();
RSYMBOL(sym)->id = id |= num;
/* make it permanent object */
set_id_entry(symbols, rb_id_to_serial(num), fstr, sym);
- rb_hash_delete_entry(symbols->dsymbol_fstr_hash, fstr);
}
}
- GLOBAL_SYMBOLS_LEAVE();
}
else {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Symbol)",
@@ -967,7 +1005,7 @@ VALUE
rb_id2sym(ID x)
{
if (!DYNAMIC_ID_P(x)) return STATIC_ID2SYM(x);
- return get_id_entry(x, ID_ENTRY_SYM);
+ return get_id_sym(x);
}
/*
@@ -1001,7 +1039,7 @@ rb_sym2str(VALUE sym)
VALUE
rb_id2str(ID id)
{
- return lookup_id_str(id);
+ return get_id_str(id);
}
const char *
@@ -1024,34 +1062,29 @@ rb_make_temporary_id(size_t n)
{
const ID max_id = RB_ID_SERIAL_MAX & ~0xffff;
const ID id = max_id - (ID)n;
- if (id <= ruby_global_symbols.last_id) {
+ if (id < RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id)) {
rb_raise(rb_eRuntimeError, "too big to make temporary ID: %" PRIdSIZE, n);
}
return (id << ID_SCOPE_SHIFT) | ID_STATIC_SYM | ID_INTERNAL;
}
static int
-symbols_i(st_data_t key, st_data_t value, st_data_t arg)
+symbols_i(VALUE *key, void *data)
{
- VALUE ary = (VALUE)arg;
- VALUE sym = (VALUE)value;
+ VALUE ary = (VALUE)data;
+ VALUE sym = (VALUE)*key;
- if (STATIC_SYM_P(sym)) {
- rb_ary_push(ary, sym);
- return ST_CONTINUE;
- }
- else if (!DYNAMIC_SYM_P(sym)) {
- rb_bug("invalid symbol: %s", RSTRING_PTR((VALUE)key));
+ if (sym_set_sym_static_p(sym)) {
+ rb_ary_push(ary, sym_set_static_sym_untag(sym)->sym);
}
- else if (!SYMBOL_PINNED_P(sym) && rb_objspace_garbage_object_p(sym)) {
- RSYMBOL(sym)->fstr = 0;
+ else if (rb_objspace_garbage_object_p(sym)) {
return ST_DELETE;
}
else {
rb_ary_push(ary, sym);
- return ST_CONTINUE;
}
+ return ST_CONTINUE;
}
VALUE
@@ -1059,12 +1092,10 @@ rb_sym_all_symbols(void)
{
VALUE ary;
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- ary = rb_ary_new2(symbols->str_sym->num_entries);
- st_foreach(symbols->str_sym, symbols_i, ary);
+ GLOBAL_SYMBOLS_LOCKING(symbols) {
+ ary = rb_ary_new2(rb_concurrent_set_size(symbols->sym_set));
+ rb_concurrent_set_foreach_with_replace(symbols->sym_set, symbols_i, (void *)ary);
}
- GLOBAL_SYMBOLS_LEAVE();
return ary;
}
@@ -1072,7 +1103,7 @@ rb_sym_all_symbols(void)
size_t
rb_sym_immortal_count(void)
{
- return (size_t)ruby_global_symbols.last_id;
+ return (size_t)(RUBY_ATOMIC_LOAD(ruby_global_symbols.next_id) - 1);
}
int
@@ -1114,7 +1145,7 @@ rb_is_local_id(ID id)
int
rb_is_junk_id(ID id)
{
- return is_junk_id(id);
+ return is_internal_id(id);
}
int
@@ -1197,15 +1228,7 @@ rb_check_symbol(volatile VALUE *namep)
return name;
}
else if (DYNAMIC_SYM_P(name)) {
- if (!SYMBOL_PINNED_P(name)) {
- GLOBAL_SYMBOLS_ENTER(symbols);
- {
- name = dsymbol_check(symbols, name);
- }
- GLOBAL_SYMBOLS_LEAVE();
-
- *namep = name;
- }
+ RUBY_ASSERT(!rb_objspace_garbage_object_p(name));
return name;
}
else if (!RB_TYPE_P(name, T_STRING)) {
@@ -1220,7 +1243,7 @@ rb_check_symbol(volatile VALUE *namep)
sym_check_asciionly(name, false);
- if ((sym = lookup_str_sym(name)) != 0) {
+ if ((sym = sym_find(name)) != 0) {
return sym;
}
@@ -1230,7 +1253,7 @@ rb_check_symbol(volatile VALUE *namep)
ID
rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
{
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
sym_check_asciionly(name, true);
@@ -1242,12 +1265,12 @@ VALUE
rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
{
VALUE sym;
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
sym_check_asciionly(name, true);
- if ((sym = lookup_str_sym(name)) != 0) {
+ if ((sym = sym_find(name)) != 0) {
return sym;
}
@@ -1266,7 +1289,7 @@ FUNC_MINIMIZED(VALUE rb_sym_intern_ascii_cstr(const char *ptr));
VALUE
rb_sym_intern(const char *ptr, long len, rb_encoding *enc)
{
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
const VALUE name = rb_setup_fake_str(&fake_str, ptr, len, enc);
return rb_str_intern(name);
}
diff --git a/symbol.h b/symbol.h
index 6b51868961..d28b5b4467 100644
--- a/symbol.h
+++ b/symbol.h
@@ -39,7 +39,7 @@ struct RSymbol {
#define is_attrset_id(id) ((id)==idASET||id_type(id)==ID_ATTRSET)
#define is_const_id(id) (id_type(id)==ID_CONST)
#define is_class_id(id) (id_type(id)==ID_CLASS)
-#define is_junk_id(id) (id_type(id)==ID_JUNK)
+#define is_internal_id(id) (id_type(id)==ID_INTERNAL)
static inline int
id_type(ID id)
@@ -58,13 +58,6 @@ static const uint32_t RB_ID_SERIAL_MAX = /* 256M on LP32 */
((sizeof(ID)-sizeof(rb_id_serial_t))*CHAR_BIT < RUBY_ID_SCOPE_SHIFT ?
RUBY_ID_SCOPE_SHIFT : 0);
-typedef struct {
- rb_id_serial_t last_id;
- st_table *str_sym;
- VALUE ids;
- VALUE dsymbol_fstr_hash;
-} rb_symbols_t;
-
static inline rb_id_serial_t
rb_id_to_serial(ID id)
{
@@ -98,7 +91,7 @@ sym_type(VALUE sym)
#define is_attrset_sym(sym) (sym_type(sym)==ID_ATTRSET)
#define is_const_sym(sym) (sym_type(sym)==ID_CONST)
#define is_class_sym(sym) (sym_type(sym)==ID_CLASS)
-#define is_junk_sym(sym) (sym_type(sym)==ID_JUNK)
+#define is_internal_sym(sym) (sym_type(sym)==ID_INTERNAL)
#ifndef RIPPER
RUBY_FUNC_EXPORTED
diff --git a/template/GNUmakefile.in b/template/GNUmakefile.in
index 22ff1078dc..452e7cdeef 100644
--- a/template/GNUmakefile.in
+++ b/template/GNUmakefile.in
@@ -27,5 +27,8 @@ override UNICODE_TABLES_DEPENDENTS = \
$(UNICODE_TABLES_DATA_FILES)))),\
force,none)
+# extract NMake-style include list
+$(eval common_mk_includes := $(shell sed -n 's/^!include *//p' $(srcdir)/common.mk))
+
-include uncommon.mk
include $(srcdir)/defs/gmake.mk
diff --git a/template/Makefile.in b/template/Makefile.in
index 91c68a1594..7ce612e8e9 100644
--- a/template/Makefile.in
+++ b/template/Makefile.in
@@ -37,6 +37,8 @@ CONFIGURE = @CONFIGURE@
MKFILES = @MAKEFILES@
BASERUBY = @BASERUBY@
HAVE_BASERUBY = @HAVE_BASERUBY@
+DUMP_AST = @X_DUMP_AST@
+DUMP_AST_TARGET = @X_DUMP_AST_TARGET@
TEST_RUNNABLE = @TEST_RUNNABLE@
CROSS_COMPILING = @CROSS_COMPILING@
DOXYGEN = @DOXYGEN@
@@ -77,7 +79,8 @@ DOCTARGETS = @RDOCTARGET@ @CAPITARGET@
EXTOUT = @EXTOUT@
TIMESTAMPDIR = $(EXTOUT)/.timestamp
-arch_hdrdir = $(EXTOUT)/include/$(arch)
+ext_hdrdir = $(EXTOUT)/include
+arch_hdrdir = $(ext_hdrdir)/$(arch)
VPATH = $(arch_hdrdir)/ruby:$(hdrdir)/ruby:$(srcdir):$(srcdir)/missing
empty =
@@ -101,12 +104,23 @@ XCFLAGS = @XCFLAGS@ $(INCFLAGS) $(_RUBY_DEVEL_enabled:yes=-DRUBY_DEVEL=1) -Dmodu
USE_RUBYGEMS = @USE_RUBYGEMS@
USE_RUBYGEMS_ = $(USE_RUBYGEMS:yes=)
CPPFLAGS = @CPPFLAGS@ $(USE_RUBYGEMS_:no=-DDISABLE_RUBYGEMS=1)
+TOP_BUILD_DIR=@abs_top_builddir@
+JIT_OBJ=@JIT_OBJ@
YJIT_SUPPORT=@YJIT_SUPPORT@
YJIT_LIBS=@YJIT_LIBS@
YJIT_OBJ=@YJIT_OBJ@
-YJIT_LIBOBJ = $(YJIT_LIBS:.a=.@OBJEXT@)
-CARGO_TARGET_DIR=@abs_top_builddir@/yjit/target
+ZJIT_SUPPORT=@ZJIT_SUPPORT@
+ZJIT_LIBS=@ZJIT_LIBS@
+ZJIT_OBJ=@ZJIT_OBJ@
+JIT_CARGO_SUPPORT=@JIT_CARGO_SUPPORT@
+CARGO_TARGET_DIR=@abs_top_builddir@/target
CARGO_BUILD_ARGS=@CARGO_BUILD_ARGS@
+ZJIT_TEST_FEATURES=@ZJIT_TEST_FEATURES@
+JIT_RUST_FLAGS=@JIT_RUST_FLAGS@
+RUSTC_FLAGS=@RUSTC_FLAGS@
+RLIB_DIR=@RLIB_DIR@
+RUST_LIB=@RUST_LIB@
+RUST_LIBOBJ = $(RUST_LIB:.a=.@OBJEXT@)
LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
EXE_LDFLAGS = $(LDFLAGS)
EXTLDFLAGS = @EXTLDFLAGS@
@@ -139,6 +153,7 @@ RUBY_API_VERSION=@RUBY_API_VERSION@
RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@
RUBY_SO_NAME=@RUBY_SO_NAME@
EXEEXT = @EXEEXT@
+BUILD_EXEEXT = @X_BUILD_EXEEXT@
LIBEXT = @LIBEXT@
PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT)
RUBY = $(RUBY_INSTALL_NAME)
@@ -201,7 +216,8 @@ DTRACE_DEPENDENT_OBJS = array.$(OBJEXT) \
string.$(OBJEXT) \
symbol.$(OBJEXT) \
vm.$(OBJEXT) \
- $(YJIT_OBJ)
+ $(YJIT_OBJ) \
+ $(ZJIT_OBJ)
THREAD_MODEL = @THREAD_MODEL@
@@ -279,6 +295,8 @@ ABI_VERSION_HDR = $(hdrdir)/ruby/internal/abi.h
CAT_DEPEND = sed -e 's/{\$$([^(){}]*)[^{}]*}//g' -e /AUTOGENERATED/q
+HASH_SIGN = \#
+
.SUFFIXES: .inc .h .c .y .i .$(ASMEXT) .$(DTRACE_EXT)
all:
@@ -325,7 +343,8 @@ $(LIBRUBY_SO):
@-[ -n "$(EXTSTATIC)" ] || $(PRE_LIBRUBY_UPDATE)
$(ECHO) linking shared-library $@
$(Q) $(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(EXTSOLIBS) $(OUTFLAG)$@
- -$(Q) $(OBJCOPY) -w -L '$(SYMBOL_PREFIX)Init_*' -L '$(SYMBOL_PREFIX)ruby_static_id_*' \
+ -$(Q) $(OBJCOPY) -w -L '$(SYMBOL_PREFIX)Init_*' -L '$(SYMBOL_PREFIX)InitVM_*' \
+ -L '$(SYMBOL_PREFIX)ruby_static_id_*' \
-L '$(SYMBOL_PREFIX)*_threadptr_*' -L '$(SYMBOL_PREFIX)*_ec_*' $@
$(Q) $(POSTLINK)
@-$(MINIRUBY) -e 'so, *aliases = ARGV; aliases.uniq!; aliases.delete(File.basename(so)); \
@@ -338,13 +357,40 @@ $(LIBRUBY_$(LIBRUBY_WITH_EXT)): $(LIBRUBY_SO_UPDATE)
PKG_CONFIG = @PKG_CONFIG@
ruby_pc = @ruby_pc@
$(ruby_pc): config.status Makefile
- $(Q)./config.status --file=-:$(srcdir)/template/ruby.pc.in | \
+ $(Q) \
+ pkg="$(@libdirname@)/pkgconfig" prefix="$(prefix)"; \
+ if [ "$(LIBRUBY_RELATIVE)" = yes ]; then \
+ case "$$pkg" in "$$prefix"/?*) \
+ pkg="$${pkg#$$prefix/}"; \
+ prefix='$${pcfiledir}'`echo "/$${pkg}" | sed -e 's|/[^/][^/]*|/..|g'`; \
+ esac; \
+ fi; \
+ ./config.status --file=-:$(srcdir)/template/ruby.pc.in | \
sed -e 's/\$$(\([A-Za-z_][A-Za-z0-9_]*\))/$${\1}/g' \
- -e 's|^prefix=.*|prefix=$(prefix)|' \
+ -e "s|^prefix=.*|prefix=$$prefix|" \
> ruby.tmp.pc
$(Q)pkg_config=${PKG_CONFIG} && PKG_CONFIG_PATH=. $${pkg_config:-:} --print-errors ruby.tmp
$(Q)$(MV) -f ruby.tmp.pc $(ruby_pc)
+test-pc: install-data
+ set -ex; \
+ [ -z "$${pkg_config=$(PKG_CONFIG)}" ] && exit; \
+ export PKG_CONFIG_PATH=$(DESTDIR)/$(libdir)/pkgconfig$${PKG_CONFIG_PATH:+:$$PKG_CONFIG_PATH}; \
+ $${pkg_config} --exists $(ruby_pc:.pc=); \
+ path=`$${pkg_config} --variable=prefix $(ruby_pc:.pc=)`; \
+ if [ "$(LIBRUBY_RELATIVE)" = yes ]; then \
+ test "$$path" -ef "$(DESTDIR)$(prefix)"; \
+ else \
+ test "$$path" = "$(prefix)"; \
+ fi
+
+install-data: pkgconfig-data pre-install-data do-install-data post-install-data
+pre-install-data:: install-prereq
+do-install-data: $(PREP) pre-install-data
+ $(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=data
+post-install-data::
+ @$(NULLCMD)
+
modular-gc-precheck:
$(Q) if test -z $(modular_gc_dir); then \
echo "You must configure with --with-modular-gc to use modular GC"; \
@@ -387,8 +433,8 @@ $(MKFILES): config.status $(srcdir)/version.h $(ABI_VERSION_HDR)
$(MAKE) -f conftest.mk | grep '^AUTO_REMAKE$$' >/dev/null 2>&1 || \
{ echo "$@ updated, restart."; exit 1; }
-uncommon.mk: $(srcdir)/common.mk
- sed 's/{\$$([^(){}]*)[^{}]*}//g' $< > $@
+uncommon.mk: $(srcdir)/tool/prereq.status
+ sed -f $(srcdir)/tool/prereq.status $(srcdir)/common.mk $(common_mk_includes) > $@
.PHONY: reconfig
reconfig-args = $(srcdir)/$(CONFIGURE) $(yes_silence:yes=--silent) $(configure_args)
@@ -471,7 +517,11 @@ _PREFIXED_SYMBOL = TOKEN_PASTE($(SYMBOL_PREFIX),name)
.d.h:
@$(ECHO) translating probes $<
- $(Q) $(DTRACE) -o $@.tmp -h -C $(INCFLAGS) $(CPPFLAGS) -s $<
+ $(Q) set x -o $@.tmp -h -C $(INCFLAGS); \
+ for flag in $(CPPFLAGS); do case $$flag in -[DU]*) set "$$@" "$$flag";; esac; done; \
+ shift; \
+ $(Q1:0=:) set -x; \
+ $(DTRACE) "$$@" -s $<
$(Q) sed -e 's/RUBY_/RUBY_DTRACE_/g' -e 's/PROBES_H_TMP/RUBY_PROBES_H/' -e 's/(char \*/(const char */g' -e 's/, char \*/, const char */g' $@.tmp > $@
$(Q) $(RM) $@.tmp
@@ -561,10 +611,10 @@ ext/distclean ext/realclean .bundle/distclean .bundle/realclean::
@$(RMALL) $(tooldir)/bunlder/*.lock $(srcdir)/.bundle
gc/clean gc/distclean gc/realclean::
- - for gc in gc/*/; do ($(CHDIR) $$gc && exec $(MAKE) TARGET_SO_DIR=./ $(@F)); done || $(NULLCMD)
+ - $(CHDIR) gc 2> /dev/null && for gc in */; do ($(CHDIR) $$gc && exec $(MAKE) TARGET_SO_DIR=./ $(@F)); done || $(NULLCMD)
gc/distclean gc/realclean::
- - for gc in gc/*/; do $(RMDIR) $$gc; done || $(NULLCMD)
+ - $(CHDIR) gc 2> /dev/null && for gc in */; do $(RMDIR) $$gc; done || $(NULLCMD)
clean-enc distclean-enc realclean-enc:
@test -f "$(ENC_MK)" || exit 0; \
@@ -625,13 +675,14 @@ $(INSNS): $(srcdir)/insns.def vm_opts.h \
$(tooldir)/ruby_vm/loaders/opt_operand_def.rb \
$(tooldir)/ruby_vm/loaders/vm_opts_h.rb \
$(tooldir)/ruby_vm/models/attribute.rb \
- $(tooldir)/ruby_vm/models/bare_instructions.rb \
+ $(tooldir)/ruby_vm/models/bare_instruction.rb \
$(tooldir)/ruby_vm/models/c_expr.rb \
$(tooldir)/ruby_vm/models/instructions.rb \
- $(tooldir)/ruby_vm/models/instructions_unifications.rb \
- $(tooldir)/ruby_vm/models/operands_unifications.rb \
- $(tooldir)/ruby_vm/models/trace_instructions.rb \
+ $(tooldir)/ruby_vm/models/instructions_unification.rb \
+ $(tooldir)/ruby_vm/models/operands_unification.rb \
+ $(tooldir)/ruby_vm/models/trace_instruction.rb \
$(tooldir)/ruby_vm/models/typemap.rb \
+ $(tooldir)/ruby_vm/models/zjit_instruction.rb \
$(tooldir)/ruby_vm/scripts/converter.rb \
$(tooldir)/ruby_vm/scripts/insns2vm.rb \
$(tooldir)/ruby_vm/views/_attributes.erb \
@@ -639,6 +690,7 @@ $(INSNS): $(srcdir)/insns.def vm_opts.h \
$(tooldir)/ruby_vm/views/_comptime_insn_stack_increase.erb \
$(tooldir)/ruby_vm/views/_copyright.erb \
$(tooldir)/ruby_vm/views/_insn_entry.erb \
+ $(tooldir)/ruby_vm/views/_insn_leaf_info.erb \
$(tooldir)/ruby_vm/views/_insn_len_info.erb \
$(tooldir)/ruby_vm/views/_insn_name_info.erb \
$(tooldir)/ruby_vm/views/_insn_operand_info.erb \
@@ -647,6 +699,7 @@ $(INSNS): $(srcdir)/insns.def vm_opts.h \
$(tooldir)/ruby_vm/views/_notice.erb \
$(tooldir)/ruby_vm/views/_sp_inc_helpers.erb \
$(tooldir)/ruby_vm/views/_trace_instruction.erb \
+ $(tooldir)/ruby_vm/views/_zjit_instruction.erb \
$(tooldir)/ruby_vm/views/insns.inc.erb \
$(tooldir)/ruby_vm/views/insns_info.inc.erb \
$(tooldir)/ruby_vm/views/optinsn.inc.erb \
@@ -706,5 +759,4 @@ yes-test-syntax-suggest: $(PREPARE_SYNTAX_SUGGEST)
no-test-syntax-suggest:
yesterday:
- $(GIT) -C $(srcdir) reset --hard \
- `$(GIT) -C $(srcdir) log -1 --before=00:00+0900 --format=%H`
+ $(GIT_IN_SRC) reset --hard `TZ=UTC-9 $(GIT_LOG_FORMAT)%H -1 --before=00:00`
diff --git a/template/builtin_binary.inc.tmpl b/template/builtin_binary.inc.tmpl
deleted file mode 100644
index 2c2f071705..0000000000
--- a/template/builtin_binary.inc.tmpl
+++ /dev/null
@@ -1,30 +0,0 @@
-// -*- c -*-
-// DO NOT MODIFY THIS FILE DIRECTLY.
-// auto-generated file by tool/generic_erb.rb
-// with template/builtin_binary.inc.tmpl
-% unless ARGV.include?('--cross=yes')
-% ary = RubyVM.enum_for(:each_builtin).to_a
-% ary.each{|feature, iseq|
-
-static const unsigned char <%= feature %>_bin[] = {
-% iseq \
-% . to_binary \
-% . each_byte \
-% . each_slice(12) {|a|
- <%= a.map{ '0x%02x,' % _1 }.join(' ') %>
-% }
-};
-% }
-
-#define BUILTIN_BIN(feature) \
- { #feature, feature ## _bin, sizeof(feature ## _bin), }
-static const struct builtin_binary builtin_binary[] = {
-% ary.each{|feature, |
- BUILTIN_BIN(<%= feature %>),
-% }
- { NULL, },/* sentinel */
-};
-
-#define BUILTIN_BINARY_SIZE <%= ary.size %>
-STATIC_ASSERT(n_builtin, numberof(builtin_binary) == BUILTIN_BINARY_SIZE + 1);
-% end
diff --git a/template/builtin_binary.rbbin.tmpl b/template/builtin_binary.rbbin.tmpl
new file mode 100644
index 0000000000..df835bbbf9
--- /dev/null
+++ b/template/builtin_binary.rbbin.tmpl
@@ -0,0 +1,35 @@
+// -*- c -*-
+// DO NOT MODIFY THIS FILE DIRECTLY.
+// auto-generated file by tool/generic_erb.rb
+// with template/builtin_binary.rbbin.tmpl
+% unless ARGV.include?('--cross=yes')
+% ary = RubyVM.enum_for(:each_builtin).to_a
+% ary.each{|feature, iseq|
+% bin = iseq.to_binary
+
+static const union {
+ unsigned char binary[<%= bin.bytesize %>];
+ uint32_t align_as_ibf_header;
+} <%= feature %>_builtin = {
+ .binary = {
+% bin \
+% . each_byte \
+% . each_slice(12) {|a|
+ <%= a.map{ '0x%02x,' % _1 }.join(' ') %>
+% }
+ }
+};
+% }
+
+#define BUILTIN_BIN(feature) \
+ { #feature, feature ## _builtin.binary, sizeof(feature ## _builtin.binary), }
+static const struct builtin_binary builtin_binary[] = {
+% ary.each{|feature, |
+ BUILTIN_BIN(<%= feature %>),
+% }
+ { NULL, },/* sentinel */
+};
+
+#define BUILTIN_BINARY_SIZE <%= ary.size %>
+STATIC_ASSERT(n_builtin, numberof(builtin_binary) == BUILTIN_BINARY_SIZE + 1);
+% end
diff --git a/template/configure-ext.mk.tmpl b/template/configure-ext.mk.tmpl
index cabdb652fd..b4e999fe8e 100644
--- a/template/configure-ext.mk.tmpl
+++ b/template/configure-ext.mk.tmpl
@@ -7,25 +7,49 @@ ECHO = $(ECHO1:0=@echo)
<%
srcdir = miniruby = script_args = nil
+with_exts = []
+without_exts = []
opt = OptionParser.new do |o|
o.on('--srcdir=SRCDIR') {|v| srcdir = v}
o.on('--miniruby=MINIRUBY') {|v| miniruby = v}
o.on('--script-args=MINIRUBY') {|v| script_args = v}
+ o.on('--with-ext=ext[,...]', Array) {|v| with_exts.concat(v)}
+ o.on('--without-ext=ext[,...]', Array) {|v| without_exts.concat(v)}
o.order!(ARGV)
end
srcdir ||= File.dirname(File.dirname(__FILE__))
-exts = {}
-[
- ["exts", "ext", "--extstatic $(EXTSTATIC)"],
- ["gems", ".bundle/gems", "--no-extstatic"],
-].each do |t, d, o|
- exts[t] = [o, Dir.glob("#{srcdir}/#{d}/*/").map {|n| n[(srcdir.size+1)..-2]}]
+script_args ||= ""
+
+filter = proc do |ext|
+ next false unless with_exts.empty? or !with_exts.any? {|w| File.fnmatch?(w, ext)}
+ without_exts.empty? or !without_exts.any? {|w| File.fnmatch?(w, ext)}
end
+exts = {
+ exts: [
+ "--extstatic $(EXTSTATIC)",
+ Dir.glob("ext/**/extconf.rb", base: srcdir).filter_map do |d|
+ d if filter[File.basename(d = d[%r[\Aext/[^/]+]])]
+ end.uniq
+ ],
+ gems: [
+ "--no-extstatic",
+ Dir.glob(".bundle/gems/**/extconf.rb", base: srcdir).grep_v(/test/).filter_map do |d|
+ d if filter[File.basename(d = d[%r[\A\.bundle/gems/[^/]+]])]
+ end.uniq
+ ],
+}
%>
MINIRUBY = <%=miniruby%>
SCRIPT_ARGS = <%=script_args.gsub("#", "\\#").gsub(/\A|[\s"']\K--jobserver-auth=[^\s'"]*/, "")%>
EXTMK_ARGS = $(SCRIPT_ARGS) --gnumake=$(gnumake) --extflags="$(EXTLDFLAGS)" \
- --make-flags="MINIRUBY='$(MINIRUBY)'"
+ --make-flags="MINIRUBY='$(MINIRUBY)'" \
+<% unless with_exts.empty? -%>
+ --with-ext=<%= with_exts.join(',') %> \
+<% end -%>
+<% unless without_exts.empty? -%>
+ --without-ext=<%= without_exts.join(',') %> \
+<% end -%>
+ # EXTMK_ARGS
all: exts gems
exts:
@@ -33,9 +57,6 @@ gems:
% exts.each do |t, (o, dirs)|
% dirs.each do |d|
-% extconf = Dir.glob("#{srcdir}/#{d}/**/extconf.rb")
-% next if extconf.empty?
-% next if extconf.any?{|f| f.include?(".bundle/gems") && f.include?("test") }
<%=t%>: <%=d%>/exts.mk
<%=d%>/exts.mk: FORCE
$(Q)$(MINIRUBY) $(srcdir)/ext/extmk.rb --make='$(MAKE)' \
diff --git a/template/fake.rb.in b/template/fake.rb.in
index b592fbd253..fed640aee7 100644
--- a/template/fake.rb.in
+++ b/template/fake.rb.in
@@ -9,6 +9,7 @@ while /\A(\w+)=(.*)/ =~ ARGV[0]
end
if inc = arg['i']
src = inc == '-' ? STDIN.read : File.read(inc)
+ src.tr!("\r", " ")
src.gsub!(/^#.*\n/, '')
else
src = ""
@@ -48,6 +49,7 @@ class Object
else%><%=v.inspect%><%end%>
% }
end
+v=$VERBOSE;$VERBOSE=nil;module Ruby; end;$VERBOSE=v
module Ruby
constants.each {|n| remove_const n}
% arg['versions'].each {|n, v|
diff --git a/template/id.c.tmpl b/template/id.c.tmpl
index 5b9e879730..d40f143065 100644
--- a/template/id.c.tmpl
+++ b/template/id.c.tmpl
@@ -1,5 +1,5 @@
%# -*- c -*-
-/* DO NOT EDIT THIS FILE DIRECTLY */
+/* DO NOT EDIT THIS FILE DIRECTLY: source is at template/id.c.tmpl */
/**********************************************************************
id.c -
@@ -22,7 +22,8 @@ ops = ids[:token_op].uniq {|id, op, token| token && op}
static const struct {
unsigned short token;
- const char name[3], term;
+ RBIMPL_ATTR_NONSTRING() const char name[3];
+ const char term;
} op_tbl[] = {
% ops.each do |_id, op, token|
% next unless token
diff --git a/template/id.h.tmpl b/template/id.h.tmpl
index 4f7053885f..eb37e15073 100644
--- a/template/id.h.tmpl
+++ b/template/id.h.tmpl
@@ -1,5 +1,5 @@
%# -*- c -*-
-/* DO NOT EDIT THIS FILE DIRECTLY */
+/* DO NOT EDIT THIS FILE DIRECTLY: source is at template/id.h.tmpl */
/**********************************************************************
id.h -
@@ -19,15 +19,14 @@ types = ids.keys.grep(/^[A-Z]/)
#define RUBY_ID_H
enum ruby_id_types {
- RUBY_ID_STATIC_SYM = 0x01,
RUBY_ID_LOCAL = 0x00,
+ RUBY_ID_STATIC_SYM = 0x01,
RUBY_ID_INSTANCE = (0x01<<1),
RUBY_ID_GLOBAL = (0x03<<1),
RUBY_ID_ATTRSET = (0x04<<1),
RUBY_ID_CONST = (0x05<<1),
RUBY_ID_CLASS = (0x06<<1),
- RUBY_ID_JUNK = (0x07<<1),
- RUBY_ID_INTERNAL = RUBY_ID_JUNK,
+ RUBY_ID_INTERNAL = (0x07<<1),
RUBY_ID_SCOPE_SHIFT = 4,
RUBY_ID_SCOPE_MASK = (~(~0U<<(RUBY_ID_SCOPE_SHIFT-1))<<1)
};
@@ -41,7 +40,6 @@ enum ruby_id_types {
#define ID_ATTRSET RUBY_ID_ATTRSET
#define ID_CONST RUBY_ID_CONST
#define ID_CLASS RUBY_ID_CLASS
-#define ID_JUNK RUBY_ID_JUNK
#define ID_INTERNAL RUBY_ID_INTERNAL
#define symIFUNC ID2SYM(idIFUNC)
diff --git a/template/prelude.c.tmpl b/template/prelude.c.tmpl
index 675973b913..04f65ec5e3 100644
--- a/template/prelude.c.tmpl
+++ b/template/prelude.c.tmpl
@@ -88,6 +88,7 @@ Prelude.new(output, ARGV, vpath).instance_eval do
#include "internal/ruby_parser.h"
#include "internal/warnings.h"
#include "iseq.h"
+#include "ruby/internal/attr/nonstring.h"
#include "ruby/ruby.h"
#include "vm_core.h"
@@ -107,12 +108,12 @@ static const struct {
% size += line.size
% next
% end
- char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=n%> */
+ RBIMPL_ATTR_NONSTRING() char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=n%> */
% size = line.size
% beg = n
% }
% if size > 0
- char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=lines.size+1%> */
+ RBIMPL_ATTR_NONSTRING() char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=lines.size+1%> */
% end
} prelude_code<%=i%><%=%> = {
% size = 0
diff --git a/template/unicode_norm_gen.tmpl b/template/unicode_norm_gen.tmpl
index a16712fbac..773a727cec 100644
--- a/template/unicode_norm_gen.tmpl
+++ b/template/unicode_norm_gen.tmpl
@@ -22,23 +22,6 @@ class Integer
end
end
-module Enumerable
- unless method_defined?(:each_slice)
- def each_slice(n)
- ary = []
- each do |i|
- ary << i
- if ary.size >= n
- yield ary
- ary = []
- end
- end
- yield ary unless ary.empty?
- self
- end
- end
-end
-
class Array
def to_UTF8() collect {|c| c.to_UTF8}.join('') end
@@ -112,6 +95,17 @@ accent_array = combining_class.keys + composition_table.keys.collect {|key| key.
composition_starters = composition_table.keys.collect {|key| key.first}
+# Special treatment for Unicode 16.0.0
+# Add characters that can be decomposed (even indirectly) so that
+# the first character in the decomposition is a an accent to accents.
+# We do this here up to two levels deep.
+# In the future, there may be even deeper levels.
+starter_accents = composition_starters & accent_array
+decomposition_table.each do |k, v|
+ accent_array << k if starter_accents.include? v.first
+ accent_array << k if starter_accents.include? decomposition_table[v.first]&.first
+end
+
hangul_no_trailing = []
0xAC00.step(0xD7A3, 28) {|c| hangul_no_trailing << c}
@@ -155,6 +149,9 @@ end
# frozen_string_literal: true
%# >
+Encoding::UNICODE_VERSION == <%= unicode_version.dump %><%=%> or
+ raise "Unicode version mismatch: <%= unicode_version %> expected but #{Encoding::UNICODE_VERSION}"
+
# automatically generated by template/unicode_norm_gen.tmpl
module UnicodeNormalize # :nodoc:
@@ -202,19 +199,19 @@ module UnicodeNormalize # :nodoc:
DECOMPOSITION_TABLE = {
% decomposition_table.each do |key, value|
- "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>"<%=%>,
+ "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>",
% end
}.freeze
KOMPATIBLE_TABLE = {
% kompatible_table.each do |key, value|
- "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>"<%=%>,
+ "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>",
% end
}.freeze
COMPOSITION_TABLE = {
% composition_table.each do |key, value|
- "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>"<%=%>,
+ "<%=key.to_UTF8%>"=>"<%=value.to_UTF8%>",
% end
}.freeze
end
diff --git a/test/-ext-/box/test_load_ext.rb b/test/-ext-/box/test_load_ext.rb
new file mode 100644
index 0000000000..ea3744375e
--- /dev/null
+++ b/test/-ext-/box/test_load_ext.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+require 'test/unit'
+
+class Test_Load_Extensions < Test::Unit::TestCase
+ ENV_ENABLE_BOX = {'RUBY_BOX' => '1'}
+
+ def test_load_extension
+ pend
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ require '-test-/box/yay1'
+ assert_equal "1.0.0", Yay.version
+ assert_equal "yay", Yay.yay
+ end;
+ end
+
+ def test_extension_contamination_in_global
+ pend
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ require '-test-/box/yay1'
+ yay1 = Yay
+ assert_equal "1.0.0", Yay.version
+ assert_equal "yay", Yay.yay
+
+ require '-test-/box/yay2'
+ assert_equal "2.0.0", Yay.version
+ v = Yay.yay
+ assert(v == "yay" || v == "yaaay") # "yay" on Linux, "yaaay" on macOS, Win32
+ end;
+ end
+
+ def test_load_extension_in_box
+ pend
+ assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ ns = Ruby::Box.new
+ ns.require '-test-/box/yay1'
+ assert_equal "1.0.0", ns::Yay.version
+ assert_raise(NameError) { Yay }
+ end;
+ end
+
+ def test_different_version_extensions
+ pend
+ assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ ns1 = Ruby::Box.new
+ ns2 = Ruby::Box.new
+ ns1.require('-test-/box/yay1')
+ ns2.require('-test-/box/yay2')
+
+ assert_raise(NameError) { Yay }
+ assert_not_nil ns1::Yay
+ assert_not_nil ns2::Yay
+ assert_equal "1.0.0", ns1::Yay::VERSION
+ assert_equal "2.0.0", ns2::Yay::VERSION
+ assert_equal "1.0.0", ns1::Yay.version
+ assert_equal "2.0.0", ns2::Yay.version
+ end;
+ end
+
+ def test_loading_extensions_from_global_to_local
+ pend
+ assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ require '-test-/box/yay1'
+ assert_equal "1.0.0", Yay.version
+ assert_equal "yay", Yay.yay
+
+ ns = Ruby::Box.new
+ ns.require '-test-/box/yay2'
+ assert_equal "2.0.0", ns::Yay.version
+ assert_equal "yaaay", ns::Yay.yay
+
+ assert_equal "yay", Yay.yay
+ end;
+ end
+
+ def test_loading_extensions_from_local_to_global
+ pend
+ assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ ns = Ruby::Box.new
+ ns.require '-test-/box/yay1'
+ assert_equal "1.0.0", ns::Yay.version
+ assert_equal "yay", ns::Yay.yay
+
+
+ require '-test-/box/yay2'
+ assert_equal "2.0.0", Yay.version
+ assert_equal "yaaay", Yay.yay
+
+ assert_equal "yay", ns::Yay.yay
+ end;
+ end
+end
diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_reporter/test_bug_reporter.rb
index 8293408518..83fdba2282 100644
--- a/test/-ext-/bug_reporter/test_bug_reporter.rb
+++ b/test/-ext-/bug_reporter/test_bug_reporter.rb
@@ -6,8 +6,6 @@ require_relative '../../lib/parser_support'
class TestBugReporter < Test::Unit::TestCase
def test_bug_reporter_add
- pend "macOS 15 is not working with this test" if macos?(15)
-
description = RUBY_DESCRIPTION
description = description.sub(/\+PRISM /, '') unless ParserSupport.prism_enabled_in_subprocess?
expected_stderr = [
@@ -22,8 +20,10 @@ class TestBugReporter < Test::Unit::TestCase
no_core = "Process.setrlimit(Process::RLIMIT_CORE, 0); " if defined?(Process.setrlimit) && defined?(Process::RLIMIT_CORE)
args = ["-r-test-/bug_reporter", "-C", tmpdir]
- args.push("--yjit") if JITSupport.yjit_enabled? # We want the printed description to match this process's RUBY_DESCRIPTION
- args.unshift({"RUBY_ON_BUG" => nil})
+ # We want the printed description to match this process's RUBY_DESCRIPTION
+ args.push("--yjit") if JITSupport.yjit_enabled?
+ args.push("--zjit") if JITSupport.zjit_enabled?
+ args.unshift({"RUBY_ON_BUG" => nil, "RUBY_CRASH_REPORT" => nil})
stdin = "#{no_core}register_sample_bug_reporter(12345); Process.kill :SEGV, $$"
assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT")
ensure
diff --git a/test/-ext-/debug/test_debug.rb b/test/-ext-/debug/test_debug.rb
index 98e178e34f..c9263d76fa 100644
--- a/test/-ext-/debug/test_debug.rb
+++ b/test/-ext-/debug/test_debug.rb
@@ -76,3 +76,57 @@ class TestDebug < Test::Unit::TestCase
assert_equal true, x, '[Bug #15105]'
end
end
+
+# This is a YJIT test, but we can't test this without a C extension that calls
+# rb_debug_inspector_open(), so we're testing it using "-test-/debug" here.
+class TestDebugWithYJIT < Test::Unit::TestCase
+ class LocalSetArray
+ def to_a
+ Bug::Debug.inspector.each do |_, binding,|
+ binding.local_variable_set(:local, :ok) if binding
+ end
+ [:ok]
+ end
+ end
+
+ class DebugArray
+ def to_a
+ Bug::Debug.inspector
+ [:ok]
+ end
+ end
+
+ def test_yjit_invalidates_getlocal_after_splatarray
+ val = getlocal_after_splatarray(LocalSetArray.new)
+ assert_equal [:ok, :ok], val
+ end
+
+ def test_yjit_invalidates_setlocal_after_splatarray
+ val = setlocal_after_splatarray(DebugArray.new)
+ assert_equal [:ok], val
+ end
+
+ def test_yjit_invalidates_setlocal_after_proc_call
+ val = setlocal_after_proc_call(proc { Bug::Debug.inspector; :ok })
+ assert_equal :ok, val
+ end
+
+ private
+
+ def getlocal_after_splatarray(array)
+ local = 1
+ [*array, local]
+ end
+
+ def setlocal_after_splatarray(array)
+ local = *array # setlocal followed by splatarray
+ itself # split a block using a C call
+ local # getlocal
+ end
+
+ def setlocal_after_proc_call(block)
+ local = block.call # setlocal followed by OPTIMIZED_METHOD_TYPE_CALL
+ itself # split a block using a C call
+ local # getlocal
+ end
+end if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
diff --git a/test/-ext-/gvl/test_last_thread.rb b/test/-ext-/gvl/test_last_thread.rb
index f1bebafeea..bcda0e3385 100644
--- a/test/-ext-/gvl/test_last_thread.rb
+++ b/test/-ext-/gvl/test_last_thread.rb
@@ -15,8 +15,7 @@ class TestLastThread < Test::Unit::TestCase
t1 = Time.now
t = t1 - t0
- assert_in_delta(1.0, t, 0.16)
+ assert_in_delta(1.0, t, 0.8)
end;
end
end
-
diff --git a/test/-ext-/postponed_job/test_postponed_job.rb b/test/-ext-/postponed_job/test_postponed_job.rb
index 8c2b3e95d1..01d6015de1 100644
--- a/test/-ext-/postponed_job/test_postponed_job.rb
+++ b/test/-ext-/postponed_job/test_postponed_job.rb
@@ -33,39 +33,4 @@ class TestPostponed_job < Test::Unit::TestCase
assert_equal [3, 4], values
RUBY
end
-
- def test_legacy_register
- assert_separately([], __FILE__, __LINE__, <<-'RUBY')
- require '-test-/postponed_job'
- direct, registered = [], []
-
- Bug.postponed_job_call_direct(direct)
- Bug.postponed_job_register(registered)
-
- assert_equal([0], direct)
- assert_equal([3], registered)
-
- Bug.postponed_job_register_one(ary = [])
- assert_equal [1], ary
- RUBY
- end
-
- def test_legacy_register_one_same
- assert_separately([], __FILE__, __LINE__, <<-'RUBY')
- require '-test-/postponed_job'
- # Registering the same job three times should result in three of the same handle
- handles = Bug.postponed_job_register_one_same
- assert_equal [handles[0]], handles.uniq
- RUBY
- end
-
- if Bug.respond_to?(:postponed_job_register_in_c_thread)
- def test_legacy_register_in_c_thread
- assert_separately([], __FILE__, __LINE__, <<-'RUBY')
- require '-test-/postponed_job'
- assert Bug.postponed_job_register_in_c_thread(ary = [])
- assert_equal [1], ary
- RUBY
- end
- end
end
diff --git a/test/-ext-/scheduler/test_interrupt_with_scheduler.rb b/test/-ext-/scheduler/test_interrupt_with_scheduler.rb
new file mode 100644
index 0000000000..eb7a0647e5
--- /dev/null
+++ b/test/-ext-/scheduler/test_interrupt_with_scheduler.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+require 'test/unit'
+require 'timeout'
+require_relative '../../fiber/scheduler'
+
+class TestSchedulerInterruptHandling < Test::Unit::TestCase
+ def setup
+ pend("No fork support") unless Process.respond_to?(:fork)
+ require '-test-/scheduler'
+ end
+
+ # Test without Thread.handle_interrupt - should work regardless of fix
+ def test_without_handle_interrupt_signal_works
+ IO.pipe do |input, output|
+ pid = fork do
+ STDERR.reopen(output)
+
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Signal.trap(:INT) do
+ ::Thread.current.raise(Interrupt)
+ end
+
+ Fiber.schedule do
+ # Yield to the scheduler:
+ sleep(0)
+
+ Bug::Scheduler.blocking_loop(output)
+ end
+ end
+
+ output.close
+ assert_equal "x", input.read(1)
+
+ Process.kill(:INT, pid)
+
+ reaper = Thread.new do
+ Process.waitpid2(pid)
+ end
+
+ unless reaper.join(10)
+ Process.kill(:KILL, pid)
+ end
+
+ _, status = reaper.value
+
+ # It should be interrupted (not killed):
+ assert_not_equal 0, status.exitstatus
+ assert_equal true, status.signaled?
+ assert_equal Signal.list["INT"], status.termsig
+ end
+ end
+end
diff --git a/test/-ext-/stack/test_stack_overflow.rb b/test/-ext-/stack/test_stack_overflow.rb
new file mode 100644
index 0000000000..3d7f00331d
--- /dev/null
+++ b/test/-ext-/stack/test_stack_overflow.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+require 'test/unit'
+
+class Test_StackOverflow < Test::Unit::TestCase
+ def setup
+ omit "Stack overflow tests are not supported on this platform: #{RUBY_PLATFORM.inspect}" unless RUBY_PLATFORM =~ /x86_64-linux|darwin/
+
+ require '-test-/stack'
+
+ omit "Stack overflow tests are not supported with ASAN" if Thread.asan?
+ end
+
+ def test_overflow
+ assert_separately([], <<~RUBY)
+ # GC may try to scan the top of the stack and cause a SEGV.
+ GC.disable
+ require '-test-/stack'
+
+ assert_raise(SystemStackError) do
+ Thread.stack_overflow
+ end
+ RUBY
+ end
+
+ def test_thread_stack_overflow
+ assert_separately([], <<~RUBY)
+ require '-test-/stack'
+ GC.disable
+
+ thread = Thread.new do
+ Thread.current.report_on_exception = false
+ Thread.stack_overflow
+ end
+
+ assert_raise(SystemStackError) do
+ thread.join
+ end
+ RUBY
+ end
+
+ def test_fiber_stack_overflow
+ assert_separately([], <<~RUBY)
+ require '-test-/stack'
+ GC.disable
+
+ fiber = Fiber.new do
+ Thread.stack_overflow
+ end
+
+ assert_raise(SystemStackError) do
+ fiber.resume
+ end
+ RUBY
+ end
+end
diff --git a/test/-ext-/string/test_capacity.rb b/test/-ext-/string/test_capacity.rb
index bcca64d85a..a23892142a 100644
--- a/test/-ext-/string/test_capacity.rb
+++ b/test/-ext-/string/test_capacity.rb
@@ -2,16 +2,17 @@
require 'test/unit'
require '-test-/string'
require 'rbconfig/sizeof'
+require 'objspace'
class Test_StringCapacity < Test::Unit::TestCase
def test_capacity_embedded
- assert_equal GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] - embed_header_size - 1, capa('foo')
+ assert_equal pool_slot_size(0) - embed_header_size - 1, capa('foo')
assert_equal max_embed_len, capa('1' * max_embed_len)
assert_equal max_embed_len, capa('1' * (max_embed_len - 1))
end
def test_capacity_shared
- sym = ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).to_sym
+ sym = ("a" * pool_slot_size(0)).to_sym
assert_equal 0, capa(sym.to_s)
end
@@ -47,7 +48,7 @@ class Test_StringCapacity < Test::Unit::TestCase
def test_capacity_frozen
s = String.new("I am testing", capacity: 1000)
- s << "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]
+ s << "a" * pool_slot_size(0)
s.freeze
assert_equal(s.length, capa(s))
end
@@ -66,7 +67,11 @@ class Test_StringCapacity < Test::Unit::TestCase
end
def embed_header_size
- 3 * RbConfig::SIZEOF['void*']
+ GC::INTERNAL_CONSTANTS[:RBASIC_SIZE] + RbConfig::SIZEOF['void*']
+ end
+
+ def pool_slot_size(_idx = 0)
+ Integer(ObjectSpace.dump("")[/"slot_size":(\d+)/, 1])
end
def max_embed_len
diff --git a/test/-ext-/string/test_interned_str.rb b/test/-ext-/string/test_interned_str.rb
index 340dba41e8..a81cb59aa5 100644
--- a/test/-ext-/string/test_interned_str.rb
+++ b/test/-ext-/string/test_interned_str.rb
@@ -9,4 +9,9 @@ class Test_RbInternedStr < Test::Unit::TestCase
src << "b" * 20
assert_equal "a" * 20, interned_str
end
+
+ def test_interned_str_encoding
+ src = :ascii.name
+ assert_equal Encoding::US_ASCII, Bug::String.rb_interned_str_dup(src).encoding
+ end
end
diff --git a/test/-ext-/string/test_set_len.rb b/test/-ext-/string/test_set_len.rb
index 1531d76167..41e14a293a 100644
--- a/test/-ext-/string/test_set_len.rb
+++ b/test/-ext-/string/test_set_len.rb
@@ -5,7 +5,7 @@ require "-test-/string"
class Test_StrSetLen < Test::Unit::TestCase
def setup
# Make string long enough so that it is not embedded
- @range_end = ("0".ord + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).chr
+ @range_end = ("0".ord + GC.stat_heap(0, :slot_size)).chr
@s0 = [*"0"..@range_end].join("").freeze
@s1 = Bug::String.new(@s0)
end
diff --git a/test/-ext-/symbol/test_type.rb b/test/-ext-/symbol/test_type.rb
index 2b0fbe5b79..ed019062fa 100644
--- a/test/-ext-/symbol/test_type.rb
+++ b/test/-ext-/symbol/test_type.rb
@@ -123,16 +123,20 @@ module Test_Symbol
def test_check_id_invalid_type
cx = EnvUtil.labeled_class("X\u{1f431}")
- assert_raise_with_message(TypeError, /X\u{1F431}/) {
- Bug::Symbol.pinneddown?(cx)
- }
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{1F431}/) {
+ Bug::Symbol.pinneddown?(cx)
+ }
+ end
end
def test_check_symbol_invalid_type
cx = EnvUtil.labeled_class("X\u{1f431}")
- assert_raise_with_message(TypeError, /X\u{1F431}/) {
- Bug::Symbol.find(cx)
- }
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{1F431}/) {
+ Bug::Symbol.find(cx)
+ }
+ end
end
def test_const_name_type
diff --git a/test/-ext-/test_abi.rb b/test/-ext-/test_abi.rb
index d3ea6bb9b1..7f30feb944 100644
--- a/test/-ext-/test_abi.rb
+++ b/test/-ext-/test_abi.rb
@@ -9,7 +9,11 @@ class TestABI < Test::Unit::TestCase
assert_separately [], <<~RUBY
err = assert_raise(LoadError) { require "-test-/abi" }
assert_match(/incompatible ABI version/, err.message)
- assert_include err.message, "/-test-/abi."
+ if Ruby::Box.enabled?
+ assert_include err.message, "_-test-+abi."
+ else
+ assert_include err.message, "/-test-/abi."
+ end
RUBY
end
@@ -27,7 +31,11 @@ class TestABI < Test::Unit::TestCase
assert_separately [{ "RUBY_ABI_CHECK" => "1" }], <<~RUBY
err = assert_raise(LoadError) { require "-test-/abi" }
assert_match(/incompatible ABI version/, err.message)
- assert_include err.message, "/-test-/abi."
+ if Ruby::Box.enabled?
+ assert_include err.message, "_-test-+abi."
+ else
+ assert_include err.message, "/-test-/abi."
+ end
RUBY
end
diff --git a/test/-ext-/thread/test_instrumentation_api.rb b/test/-ext-/thread/test_instrumentation_api.rb
index c0fad14908..ba41069304 100644
--- a/test/-ext-/thread/test_instrumentation_api.rb
+++ b/test/-ext-/thread/test_instrumentation_api.rb
@@ -151,7 +151,7 @@ class TestThreadInstrumentation < Test::Unit::TestCase
end
full_timeline = record do
- ractor.take
+ ractor.value
end
timeline = timeline_for(Thread.current, full_timeline)
@@ -172,7 +172,7 @@ class TestThreadInstrumentation < Test::Unit::TestCase
thread = Ractor.new{
sleep 0.1
Thread.current
- }.take
+ }.value
sleep 0.1
end
diff --git a/test/-ext-/thread/test_lock_native_thread.rb b/test/-ext-/thread/test_lock_native_thread.rb
index 8a5ba78838..b4044b2b93 100644
--- a/test/-ext-/thread/test_lock_native_thread.rb
+++ b/test/-ext-/thread/test_lock_native_thread.rb
@@ -15,6 +15,8 @@ end
class TestThreadLockNativeThread < Test::Unit::TestCase
def test_lock_native_thread
+ omit "LSAN reports memory leak because NT is not freed for MN thread" if Test::Sanitizers.lsan_enabled?
+
assert_separately([{'RUBY_MN_THREADS' => '1'}], <<-RUBY)
require '-test-/thread/lock_native_thread'
@@ -28,6 +30,8 @@ class TestThreadLockNativeThread < Test::Unit::TestCase
end
def test_lock_native_thread_tls
+ omit "LSAN reports memory leak because NT is not freed for MN thread" if Test::Sanitizers.lsan_enabled?
+
assert_separately([{'RUBY_MN_THREADS' => '1'}], <<-RUBY)
require '-test-/thread/lock_native_thread'
tn = 10
diff --git a/test/-ext-/thread_fd/test_thread_fd_close.rb b/test/-ext-/thread_fd/test_thread_fd_close.rb
deleted file mode 100644
index 1d2ef63635..0000000000
--- a/test/-ext-/thread_fd/test_thread_fd_close.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require '-test-/thread_fd'
-
-class TestThreadFdClose < Test::Unit::TestCase
-
- def test_thread_fd_close
- IO.pipe do |r, w|
- th = Thread.new do
- begin
- assert_raise(IOError) {
- r.read(4)
- }
- ensure
- w.syswrite('done')
- end
- end
- Thread.pass until th.stop?
- IO.thread_fd_close(r.fileno)
- assert_equal 'done', r.read(4)
- th.join
- end
- end
-end
diff --git a/test/-ext-/tracepoint/test_tracepoint.rb b/test/-ext-/tracepoint/test_tracepoint.rb
index bf66d8f105..603fd01fd5 100644
--- a/test/-ext-/tracepoint/test_tracepoint.rb
+++ b/test/-ext-/tracepoint/test_tracepoint.rb
@@ -83,7 +83,7 @@ class TestTracepointObj < Test::Unit::TestCase
end
def test_teardown_with_active_GC_end_hook
- assert_separately([], 'require("-test-/tracepoint"); Bug.after_gc_exit_hook = proc {}')
+ assert_ruby_status([], 'require("-test-/tracepoint"); Bug.after_gc_exit_hook = proc {}; GC.start')
end
end
diff --git a/test/.excludes-mmtk/TestEtc.rb b/test/.excludes-mmtk/TestEtc.rb
new file mode 100644
index 0000000000..746f5ba321
--- /dev/null
+++ b/test/.excludes-mmtk/TestEtc.rb
@@ -0,0 +1 @@
+exclude(:test_ractor_parallel, "glibc error: Mutex lock with MarkSweep debug")
diff --git a/test/.excludes-mmtk/TestGc.rb b/test/.excludes-mmtk/TestGc.rb
index 228a344aa5..cbab458b90 100644
--- a/test/.excludes-mmtk/TestGc.rb
+++ b/test/.excludes-mmtk/TestGc.rb
@@ -7,6 +7,7 @@ exclude(:test_gc_config_setting_returns_updated_config_hash, "testing behaviour
exclude(:test_gc_internals, "testing behaviour specific to default GC")
exclude(:test_gc_parameter, "testing behaviour specific to default GC")
exclude(:test_gc_parameter_init_slots, "testing behaviour specific to default GC")
+exclude(:test_heaps_grow_independently, "testing behaviour specific to default GC")
exclude(:test_latest_gc_info, "testing behaviour specific to default GC")
exclude(:test_latest_gc_info_argument, "testing behaviour specific to default GC")
exclude(:test_latest_gc_info_need_major_by, "testing behaviour specific to default GC")
diff --git a/test/.excludes-mmtk/TestObjSpace.rb b/test/.excludes-mmtk/TestObjSpace.rb
index 200faced19..94eb2c436d 100644
--- a/test/.excludes-mmtk/TestObjSpace.rb
+++ b/test/.excludes-mmtk/TestObjSpace.rb
@@ -1,4 +1,4 @@
exclude(:test_dump_all_full, "testing behaviour specific to default GC")
exclude(:test_dump_flag_age, "testing behaviour specific to default GC")
exclude(:test_dump_flags, "testing behaviour specific to default GC")
-exclude(:test_finalizer, "times out in debug mode on Ubuntu")
+exclude(:test_dump_objects_dumps_page_slot_sizes, "testing behaviour specific to default GC")
diff --git a/test/.excludes-mmtk/TestObjectSpace.rb b/test/.excludes-mmtk/TestObjectSpace.rb
new file mode 100644
index 0000000000..a92be8090c
--- /dev/null
+++ b/test/.excludes-mmtk/TestObjectSpace.rb
@@ -0,0 +1 @@
+exclude(:test_finalizer, "times out in debug mode on Ubuntu")
diff --git a/test/.excludes-parsey/TestDefined.rb b/test/.excludes-parsey/TestDefined.rb
deleted file mode 100644
index ae2a2a6270..0000000000
--- a/test/.excludes-parsey/TestDefined.rb
+++ /dev/null
@@ -1 +0,0 @@
-exclude(:test_defined_paren_void_stmts, "defined? (x;)")
diff --git a/test/.excludes-zjit/TestResolvDNS.rb b/test/.excludes-zjit/TestResolvDNS.rb
new file mode 100644
index 0000000000..1a85ea90be
--- /dev/null
+++ b/test/.excludes-zjit/TestResolvDNS.rb
@@ -0,0 +1 @@
+exclude(:test_multiple_servers_with_timeout_and_truncated_tcp_fallback, 'randomly crashes on Thread#value, showing up as Timeout') # https://github.com/Shopify/ruby/issues/852
diff --git a/test/.excludes/JSONGenericObjectTest.rb b/test/.excludes/JSONGenericObjectTest.rb
new file mode 100644
index 0000000000..820a6a0120
--- /dev/null
+++ b/test/.excludes/JSONGenericObjectTest.rb
@@ -0,0 +1,4 @@
+# ostruct will be loaded when JSON::GenericObject is autoloaded. By
+# removing all test methods, the autoload in `setup` is not triggered.
+
+exclude /test_/, 'JSON::GenericObject needs ostruct gem'
diff --git a/test/.excludes/TestPatternMatching.rb b/test/.excludes/TestPatternMatching.rb
new file mode 100644
index 0000000000..04b2f16de8
--- /dev/null
+++ b/test/.excludes/TestPatternMatching.rb
@@ -0,0 +1 @@
+exclude(:test_alternative_pattern_nested, "Changes here for syntax errors") if RUBY_DESCRIPTION.include?("+GC")
diff --git a/test/.excludes/TestThread.rb b/test/.excludes/TestThread.rb
index f26ea420a6..63f193e484 100644
--- a/test/.excludes/TestThread.rb
+++ b/test/.excludes/TestThread.rb
@@ -15,4 +15,6 @@ end
if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS')
# to avoid "`failed to allocate memory (NoMemoryError)" error
exclude(:test_thread_interrupt_for_killed_thread, 'TODO')
+ # timeout only on mswin, not mingw
+ exclude(:test_thread_join_during_finalizers, 'Timeout')
end
diff --git a/test/.excludes/URI/TestMailTo.rb b/test/.excludes/URI/TestMailTo.rb
new file mode 100644
index 0000000000..c9b1f94fe2
--- /dev/null
+++ b/test/.excludes/URI/TestMailTo.rb
@@ -0,0 +1 @@
+exclude :test_email_regexp, "still flaky with --repeat-count option"
diff --git a/test/.excludes/_appveyor/TestArray.rb b/test/.excludes/_appveyor/TestArray.rb
deleted file mode 100644
index 7d03833f07..0000000000
--- a/test/.excludes/_appveyor/TestArray.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# https://ci.appveyor.com/project/ruby/ruby/builds/20339189/job/ltdpffep976xtj85
-# `test_push_over_ary_max': failed to allocate memory (NoMemoryError)
-exclude(:test_push_over_ary_max, 'Sometimes AppVeyor has insufficient memory to run this test')
-# https://ci.appveyor.com/project/ruby/ruby/builds/20728419/job/o73q9fy1ojfibg5v
-exclude(:test_unshift_over_ary_max, 'Sometimes AppVeyor has insufficient memory to run this test')
-# https://ci.appveyor.com/project/ruby/ruby/builds/20427662/job/prq9i2lkfxv2j0uy
-exclude(:test_splice_over_ary_max, 'Sometimes AppVeyor has insufficient memory to run this test')
diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb
deleted file mode 100644
index eadae45313..0000000000
--- a/test/cgi/test_cgi_cookie.rb
+++ /dev/null
@@ -1,211 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'stringio'
-require_relative 'update_env'
-
-
-class CGICookieTest < Test::Unit::TestCase
- include UpdateEnv
-
-
- def setup
- @environ = {}
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => nil,
- )
- @str1="\xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93".dup
- @str1.force_encoding("UTF-8") if defined?(::Encoding)
- end
-
- def teardown
- ENV.update(@environ)
- end
-
-
- def test_cgi_cookie_new_simple
- cookie = CGI::Cookie.new('name1', 'val1', '&<>"', @str1)
- assert_equal('name1', cookie.name)
- assert_equal(['val1', '&<>"', @str1], cookie.value)
- assert_nil(cookie.domain)
- assert_nil(cookie.expires)
- assert_equal('', cookie.path)
- assert_equal(false, cookie.secure)
- assert_equal(false, cookie.httponly)
- assert_equal("name1=val1&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93; path=", cookie.to_s)
- end
-
-
- def test_cgi_cookie_new_complex
- t = Time.gm(2030, 12, 31, 23, 59, 59)
- value = ['val1', '&<>"', "\xA5\xE0\xA5\xB9\xA5\xAB".dup]
- value[2].force_encoding("EUC-JP") if defined?(::Encoding)
- cookie = CGI::Cookie.new('name'=>'name1',
- 'value'=>value,
- 'path'=>'/cgi-bin/myapp/',
- 'domain'=>'www.example.com',
- 'expires'=>t,
- 'secure'=>true,
- 'httponly'=>true
- )
- assert_equal('name1', cookie.name)
- assert_equal(value, cookie.value)
- assert_equal('www.example.com', cookie.domain)
- assert_equal(t, cookie.expires)
- assert_equal('/cgi-bin/myapp/', cookie.path)
- assert_equal(true, cookie.secure)
- assert_equal(true, cookie.httponly)
- assert_equal('name1=val1&%26%3C%3E%22&%A5%E0%A5%B9%A5%AB; domain=www.example.com; path=/cgi-bin/myapp/; expires=Tue, 31 Dec 2030 23:59:59 GMT; secure; HttpOnly', cookie.to_s)
- end
-
-
- def test_cgi_cookie_new_with_domain
- h = {'name'=>'name1', 'value'=>'value1'}
- cookie = CGI::Cookie.new(h.merge('domain'=>'a.example.com'))
- assert_equal('a.example.com', cookie.domain)
-
- cookie = CGI::Cookie.new(h.merge('domain'=>'.example.com'))
- assert_equal('.example.com', cookie.domain)
-
- cookie = CGI::Cookie.new(h.merge('domain'=>'1.example.com'))
- assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123')
-
- assert_raise(ArgumentError) {
- CGI::Cookie.new(h.merge('domain'=>'-a.example.com'))
- }
-
- assert_raise(ArgumentError) {
- CGI::Cookie.new(h.merge('domain'=>'a-.example.com'))
- }
- end
-
-
- def test_cgi_cookie_scriptname
- cookie = CGI::Cookie.new('name1', 'value1')
- assert_equal('', cookie.path)
- cookie = CGI::Cookie.new('name'=>'name1', 'value'=>'value1')
- assert_equal('', cookie.path)
- ## when ENV['SCRIPT_NAME'] is set, cookie.path is set automatically
- ENV['SCRIPT_NAME'] = '/cgi-bin/app/example.cgi'
- cookie = CGI::Cookie.new('name1', 'value1')
- assert_equal('/cgi-bin/app/', cookie.path)
- cookie = CGI::Cookie.new('name'=>'name1', 'value'=>'value1')
- assert_equal('/cgi-bin/app/', cookie.path)
- end
-
-
- def test_cgi_cookie_parse
- ## ';' separator
- cookie_str = 'name1=val1&val2; name2=val2&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93;_session_id=12345'
- cookies = CGI::Cookie.parse(cookie_str)
- list = [
- ['name1', ['val1', 'val2']],
- ['name2', ['val2', '&<>"',@str1]],
- ['_session_id', ['12345']],
- ]
- list.each do |name, value|
- cookie = cookies[name]
- assert_equal(name, cookie.name)
- assert_equal(value, cookie.value)
- end
- ## don't allow ',' separator
- cookie_str = 'name1=val1&val2, name2=val2'
- cookies = CGI::Cookie.parse(cookie_str)
- list = [
- ['name1', ['val1', 'val2, name2=val2']],
- ]
- list.each do |name, value|
- cookie = cookies[name]
- assert_equal(name, cookie.name)
- assert_equal(value, cookie.value)
- end
- end
-
- def test_cgi_cookie_parse_not_decode_name
- cookie_str = "%66oo=baz;foo=bar"
- cookies = CGI::Cookie.parse(cookie_str)
- assert_equal({"%66oo" => ["baz"], "foo" => ["bar"]}, cookies)
- end
-
- def test_cgi_cookie_arrayinterface
- cookie = CGI::Cookie.new('name1', 'a', 'b', 'c')
- assert_equal('a', cookie[0])
- assert_equal('c', cookie[2])
- assert_nil(cookie[3])
- assert_equal('a', cookie.first)
- assert_equal('c', cookie.last)
- assert_equal(['A', 'B', 'C'], cookie.collect{|e| e.upcase})
- end
-
-
- def test_cgi_cookie_domain_injection_into_name
- name = "a=b; domain=example.com;"
- path = "/"
- domain = "example.jp"
- assert_raise(ArgumentError) do
- CGI::Cookie.new('name' => name,
- 'value' => "value",
- 'domain' => domain,
- 'path' => path)
- end
- end
-
-
- def test_cgi_cookie_newline_injection_into_name
- name = "a=b;\r\nLocation: http://example.com#"
- path = "/"
- domain = "example.jp"
- assert_raise(ArgumentError) do
- CGI::Cookie.new('name' => name,
- 'value' => "value",
- 'domain' => domain,
- 'path' => path)
- end
- end
-
-
- def test_cgi_cookie_multibyte_injection_into_name
- name = "a=b;\u3042"
- path = "/"
- domain = "example.jp"
- assert_raise(ArgumentError) do
- CGI::Cookie.new('name' => name,
- 'value' => "value",
- 'domain' => domain,
- 'path' => path)
- end
- end
-
-
- def test_cgi_cookie_injection_into_path
- name = "name"
- path = "/; samesite=none"
- domain = "example.jp"
- assert_raise(ArgumentError) do
- CGI::Cookie.new('name' => name,
- 'value' => "value",
- 'domain' => domain,
- 'path' => path)
- end
- end
-
-
- def test_cgi_cookie_injection_into_domain
- name = "name"
- path = "/"
- domain = "example.jp; samesite=none"
- assert_raise(ArgumentError) do
- CGI::Cookie.new('name' => name,
- 'value' => "value",
- 'domain' => domain,
- 'path' => path)
- end
- end
-
-
- instance_methods.each do |method|
- private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
- end if ENV['TEST']
-
-end
diff --git a/test/cgi/test_cgi_core.rb b/test/cgi/test_cgi_core.rb
deleted file mode 100644
index f7adb7e99f..0000000000
--- a/test/cgi/test_cgi_core.rb
+++ /dev/null
@@ -1,307 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'stringio'
-require_relative 'update_env'
-
-
-class CGICoreTest < Test::Unit::TestCase
- include UpdateEnv
-
- def setup
- @environ = {}
- #@environ = {
- # 'SERVER_PROTOCOL' => 'HTTP/1.1',
- # 'REQUEST_METHOD' => 'GET',
- # 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- #}
- #ENV.update(@environ)
- end
-
- def teardown
- ENV.update(@environ)
- $stdout = STDOUT
- end
-
- def test_cgi_parse_illegal_query
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'QUERY_STRING' => 'a=111&&b=222&c&d=',
- 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- assert_equal(["a","b","c","d"],cgi.keys.sort)
- assert_equal("",cgi["d"])
- end
-
- def test_cgi_core_params_GET
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'QUERY_STRING' => 'id=123&id=456&id=&id&str=%40h+%3D%7E+%2F%5E%24%2F',
- 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- ## cgi[]
- assert_equal('123', cgi['id'])
- assert_equal('@h =~ /^$/', cgi['str'])
- ## cgi.params
- assert_equal(['123', '456', ''], cgi.params['id'])
- assert_equal(['@h =~ /^$/'], cgi.params['str'])
- ## cgi.keys
- assert_equal(['id', 'str'], cgi.keys.sort)
- ## cgi.key?, cgi.has_key?, cgi.include?
- assert_equal(true, cgi.key?('id'))
- assert_equal(true, cgi.has_key?('id'))
- assert_equal(true, cgi.include?('id'))
- assert_equal(false, cgi.key?('foo'))
- assert_equal(false, cgi.has_key?('foo'))
- assert_equal(false, cgi.include?('foo'))
- ## invalid parameter name
- assert_equal('', cgi['*notfound*']) # [ruby-dev:30740]
- assert_equal([], cgi.params['*notfound*'])
- end
-
-
- def test_cgi_core_params_POST
- query_str = 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F'
- update_env(
- 'REQUEST_METHOD' => 'POST',
- 'CONTENT_LENGTH' => query_str.length.to_s,
- 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- $stdin = StringIO.new
- $stdin << query_str
- $stdin.rewind
- cgi = CGI.new
- ## cgi[]
- assert_equal('123', cgi['id'])
- assert_equal('@h =~ /^$/', cgi['str'])
- ## cgi.params
- assert_equal(['123', '456', ''], cgi.params['id'])
- assert_equal(['@h =~ /^$/'], cgi.params['str'])
- ## invalid parameter name
- assert_equal('', cgi['*notfound*'])
- assert_equal([], cgi.params['*notfound*'])
- ensure
- $stdin = STDIN
- end
-
- def test_cgi_core_params_encoding_check
- query_str = 'str=%BE%BE%B9%BE'
- update_env(
- 'REQUEST_METHOD' => 'POST',
- 'CONTENT_LENGTH' => query_str.length.to_s,
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- $stdin = StringIO.new
- $stdin << query_str
- $stdin.rewind
- if defined?(::Encoding)
- hash={}
- cgi = CGI.new(:accept_charset=>"UTF-8"){|key,val|hash[key]=val}
- ## cgi[]
- assert_equal("\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8"), cgi['str'])
- ## cgi.params
- assert_equal(["\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8")], cgi.params['str'])
- ## accept-charset error
- assert_equal({"str"=>"\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8")},hash)
-
- $stdin.rewind
- assert_raise(CGI::InvalidEncoding) do
- cgi = CGI.new(:accept_charset=>"UTF-8")
- end
-
- $stdin.rewind
- cgi = CGI.new(:accept_charset=>"EUC-JP")
- ## cgi[]
- assert_equal("\xBE\xBE\xB9\xBE".dup.force_encoding("EUC-JP"), cgi['str'])
- ## cgi.params
- assert_equal(["\xBE\xBE\xB9\xBE".dup.force_encoding("EUC-JP")], cgi.params['str'])
- else
- assert(true)
- end
- ensure
- $stdin = STDIN
- end
-
-
- def test_cgi_core_cookie
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
- 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- assert_not_equal(nil,cgi.cookies)
- [ ['_session_id', ['12345'], ],
- ['name1', ['val1', 'val2'], ],
- ].each do |key, expected|
- cookie = cgi.cookies[key]
- assert_kind_of(CGI::Cookie, cookie)
- assert_equal(expected, cookie.value)
- assert_equal(false, cookie.secure)
- assert_nil(cookie.expires)
- assert_nil(cookie.domain)
- assert_equal('', cookie.path)
- end
- end
-
-
- def test_cgi_core_maxcontentlength
- update_env(
- 'REQUEST_METHOD' => 'POST',
- 'CONTENT_LENGTH' => (64 * 1024 * 1024).to_s
- )
- ex = assert_raise(StandardError) do
- CGI.new
- end
- assert_equal("too large post data.", ex.message)
- end if CGI.const_defined?(:MAX_CONTENT_LENGTH)
-
-
- def test_cgi_core_out
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
- 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- ## euc string
- euc_str = "\270\253\244\355\241\242\277\315\244\254\245\264\245\337\244\316\244\350\244\246\244\300"
- ## utf8 (not converted)
- options = { 'charset'=>'utf8' }
- $stdout = StringIO.new
- cgi.out(options) { euc_str }
- assert_nil(options['language'])
- actual = $stdout.string
- expected = "Content-Type: text/html; charset=utf8\r\n" +
- "Content-Length: 22\r\n" +
- "\r\n" +
- euc_str
- if defined?(::Encoding)
- actual.force_encoding("ASCII-8BIT")
- expected.force_encoding("ASCII-8BIT")
- end
- assert_equal(expected, actual)
- ## language is keeped
- options = { 'charset'=>'Shift_JIS', 'language'=>'en' }
- $stdout = StringIO.new
- cgi.out(options) { euc_str }
- assert_equal('en', options['language'])
- ## HEAD method
- update_env('REQUEST_METHOD' => 'HEAD')
- options = { 'charset'=>'utf8' }
- $stdout = StringIO.new
- cgi.out(options) { euc_str }
- actual = $stdout.string
- expected = "Content-Type: text/html; charset=utf8\r\n" +
- "Content-Length: 22\r\n" +
- "\r\n"
- assert_equal(expected, actual)
- end
-
-
- def test_cgi_core_print
- update_env(
- 'REQUEST_METHOD' => 'GET',
- )
- cgi = CGI.new
- $stdout = StringIO.new
- str = "foobar"
- cgi.print(str)
- expected = str
- actual = $stdout.string
- assert_equal(expected, actual)
- end
-
-
- def test_cgi_core_environs
- update_env(
- 'REQUEST_METHOD' => 'GET',
- )
- cgi = CGI.new
- ##
- list1 = %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
- PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
- REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
- SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
- HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
- HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
- HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT
- ]
- # list2 = %w[ CONTENT_LENGTH SERVER_PORT ]
- ## string expected
- list1.each do |name|
- update_env(name => "**#{name}**")
- end
- list1.each do |name|
- method = name.sub(/\AHTTP_/, '').downcase
- actual = cgi.__send__ method
- expected = "**#{name}**"
- assert_equal(expected, actual)
- end
- ## integer expected
- update_env('CONTENT_LENGTH' => '123')
- update_env('SERVER_PORT' => '8080')
- assert_equal(123, cgi.content_length)
- assert_equal(8080, cgi.server_port)
- ## raw cookie
- update_env('HTTP_COOKIE' => 'name1=val1')
- update_env('HTTP_COOKIE2' => 'name2=val2')
- assert_equal('name1=val1', cgi.raw_cookie)
- assert_equal('name2=val2', cgi.raw_cookie2)
- end
-
-
- def test_cgi_core_htmltype_header
- update_env(
- 'REQUEST_METHOD' => 'GET',
- )
- ## no htmltype
- cgi = CGI.new
- assert_raise(NoMethodError) do cgi.doctype end
- assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
- ## html3
- cgi = CGI.new('html3')
- expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'
- assert_equal(expected, cgi.doctype)
- assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
- ## html4
- cgi = CGI.new('html4')
- expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
- assert_equal(expected, cgi.doctype)
- assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
- ## html4 transitional
- cgi = CGI.new('html4Tr')
- expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
- assert_equal(expected, cgi.doctype)
- assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
- ## html4 frameset
- cgi = CGI.new('html4Fr')
- expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
- assert_equal(expected, cgi.doctype)
- assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
- ## html5
- cgi = CGI.new('html5')
- expected = '<!DOCTYPE HTML>'
- assert_equal(expected, cgi.doctype)
- assert_match(/^<HEADER><\/HEADER>$/i,cgi.header)
- end
-
-
- instance_methods.each do |method|
- private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
- end if ENV['TEST']
-
-end
diff --git a/test/cgi/test_cgi_escape.rb b/test/cgi/test_cgi_escape.rb
new file mode 100644
index 0000000000..73d99e8aac
--- /dev/null
+++ b/test/cgi/test_cgi_escape.rb
@@ -0,0 +1,325 @@
+# frozen_string_literal: true
+require 'test/unit'
+require 'cgi/escape'
+require 'stringio'
+require_relative 'update_env'
+
+
+class CGIEscapeTest < Test::Unit::TestCase
+ include CGI::Escape
+ include UpdateEnv
+
+ def setup
+ @environ = {}
+ update_env(
+ 'REQUEST_METHOD' => 'GET',
+ 'SCRIPT_NAME' => nil,
+ )
+ @str1="&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93".dup
+ @str1.force_encoding("UTF-8") if defined?(::Encoding)
+ end
+
+ def teardown
+ ENV.update(@environ)
+ end
+
+ def test_cgi_escape
+ assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escape(@str1))
+ assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI.escape(@str1).ascii_only?) if defined?(::Encoding)
+ end
+
+ def test_cgi_escape_with_unreserved_characters
+ assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
+ CGI.escape("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"),
+ "should not escape any unreserved characters, as per RFC3986 Section 2.3")
+ end
+
+ def test_cgi_escape_with_invalid_byte_sequence
+ assert_equal('%C0%3C%3C', CGI.escape("\xC0\<\<".dup.force_encoding("UTF-8")))
+ end
+
+ def test_cgi_escape_preserve_encoding
+ assert_equal(Encoding::US_ASCII, CGI.escape("\xC0\<\<".dup.force_encoding("US-ASCII")).encoding)
+ assert_equal(Encoding::ASCII_8BIT, CGI.escape("\xC0\<\<".dup.force_encoding("ASCII-8BIT")).encoding)
+ assert_equal(Encoding::UTF_8, CGI.escape("\xC0\<\<".dup.force_encoding("UTF-8")).encoding)
+ end
+
+ def test_cgi_unescape
+ str = CGI.unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
+ assert_equal(@str1, str)
+ return unless defined?(::Encoding)
+
+ assert_equal(@str1.encoding, str.encoding)
+ assert_equal("\u{30E1 30E2 30EA 691C 7D22}", CGI.unescape("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2"))
+ end
+
+ def test_cgi_unescape_preserve_encoding
+ assert_equal(Encoding::US_ASCII, CGI.unescape("%C0%3C%3C".dup.force_encoding("US-ASCII")).encoding)
+ assert_equal(Encoding::ASCII_8BIT, CGI.unescape("%C0%3C%3C".dup.force_encoding("ASCII-8BIT")).encoding)
+ assert_equal(Encoding::UTF_8, CGI.unescape("%C0%3C%3C".dup.force_encoding("UTF-8")).encoding)
+ end
+
+ def test_cgi_unescape_accept_charset
+ return unless defined?(::Encoding)
+
+ assert_raise(TypeError) {CGI.unescape('', nil)}
+ assert_separately(%w[-rcgi/escape], "#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ assert_equal("", CGI.unescape(''))
+ end;
+ end
+
+ def test_cgi_escapeURIComponent
+ assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escapeURIComponent(@str1))
+ assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI.escapeURIComponent(@str1).ascii_only?) if defined?(::Encoding)
+ end
+
+ def test_cgi_escape_uri_component
+ assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escape_uri_component(@str1))
+ end
+
+ def test_cgi_escapeURIComponent_with_unreserved_characters
+ assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
+ CGI.escapeURIComponent("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"),
+ "should not encode any unreserved characters, as per RFC3986 Section 2.3")
+ end
+
+ def test_cgi_escapeURIComponent_with_invalid_byte_sequence
+ assert_equal('%C0%3C%3C', CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("UTF-8")))
+ end
+
+ def test_cgi_escapeURIComponent_preserve_encoding
+ assert_equal(Encoding::US_ASCII, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("US-ASCII")).encoding)
+ assert_equal(Encoding::ASCII_8BIT, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("ASCII-8BIT")).encoding)
+ assert_equal(Encoding::UTF_8, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("UTF-8")).encoding)
+ end
+
+ def test_cgi_unescapeURIComponent
+ str = CGI.unescapeURIComponent('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
+ assert_equal(@str1, str)
+ return unless defined?(::Encoding)
+
+ assert_equal("foo+bar", CGI.unescapeURIComponent("foo+bar"))
+
+ assert_equal(@str1.encoding, str.encoding)
+ assert_equal("\u{30E1 30E2 30EA 691C 7D22}", CGI.unescapeURIComponent("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2"))
+ end
+
+ def test_cgi_unescape_uri_component
+ str = CGI.unescape_uri_component('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
+ assert_equal(@str1, str)
+ end
+
+ def test_cgi_unescapeURIComponent_preserve_encoding
+ assert_equal(Encoding::US_ASCII, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("US-ASCII")).encoding)
+ assert_equal(Encoding::ASCII_8BIT, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("ASCII-8BIT")).encoding)
+ assert_equal(Encoding::UTF_8, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("UTF-8")).encoding)
+ end
+
+ def test_cgi_unescapeURIComponent_accept_charset
+ return unless defined?(::Encoding)
+
+ assert_raise(TypeError) {CGI.unescapeURIComponent('', nil)}
+ assert_separately(%w[-rcgi/escape], "#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ assert_equal("", CGI.unescapeURIComponent(''))
+ end;
+ end
+
+ def test_cgi_escapeHTML
+ assert_equal("&#39;&amp;&quot;&gt;&lt;", CGI.escapeHTML("'&\"><"))
+ end
+
+ def test_cgi_escape_html_duplicated
+ orig = "Ruby".dup.force_encoding("US-ASCII")
+ str = CGI.escapeHTML(orig)
+ assert_equal(orig, str)
+ assert_not_same(orig, str)
+ end
+
+ def assert_cgi_escape_html_preserve_encoding(str, encoding)
+ assert_equal(encoding, CGI.escapeHTML(str.dup.force_encoding(encoding)).encoding)
+ end
+
+ def test_cgi_escape_html_preserve_encoding
+ Encoding.list do |enc|
+ assert_cgi_escape_html_preserve_encoding("'&\"><", enc)
+ assert_cgi_escape_html_preserve_encoding("Ruby", enc)
+ end
+ end
+
+ def test_cgi_escape_html_dont_freeze
+ assert_not_predicate CGI.escapeHTML("'&\"><".dup), :frozen?
+ assert_not_predicate CGI.escapeHTML("'&\"><".freeze), :frozen?
+ assert_not_predicate CGI.escapeHTML("Ruby".dup), :frozen?
+ assert_not_predicate CGI.escapeHTML("Ruby".freeze), :frozen?
+ end
+
+ def test_cgi_escape_html_large
+ return if RUBY_ENGINE == 'jruby'
+ ulong_max, size_max = RbConfig::LIMITS.values_at("ULONG_MAX", "SIZE_MAX")
+ return unless ulong_max < size_max # Platforms not concerned
+
+ size = (ulong_max / 6 + 1)
+ begin
+ str = '"' * size
+ escaped = CGI.escapeHTML(str)
+ rescue NoMemoryError
+ omit "Not enough memory"
+ rescue => e
+ end
+ assert_raise_with_message(ArgumentError, /overflow/, ->{"length = #{escaped.length}"}) do
+ raise e if e
+ end
+ end
+
+ def test_cgi_unescapeHTML
+ assert_equal("'&\"><", CGI.unescapeHTML("&#39;&amp;&quot;&gt;&lt;"))
+ end
+
+ def test_cgi_unescapeHTML_invalid
+ assert_equal('&<&amp>&quot&abcdefghijklmn', CGI.unescapeHTML('&&lt;&amp&gt;&quot&abcdefghijklmn'))
+ end
+
+ module UnescapeHTMLTests
+ def test_cgi_unescapeHTML_following_known_first_letter
+ assert_equal('&a>&q>&l>&g>', CGI.unescapeHTML('&a&gt;&q&gt;&l&gt;&g&gt;'))
+ end
+
+ def test_cgi_unescapeHTML_following_number_sign
+ assert_equal('&#>&#x>', CGI.unescapeHTML('&#&gt;&#x&gt;'))
+ end
+
+ def test_cgi_unescapeHTML_following_invalid_numeric
+ assert_equal('&#1114112>&#x110000>', CGI.unescapeHTML('&#1114112&gt;&#x110000&gt;'))
+ end
+ end
+
+ include UnescapeHTMLTests
+
+ Encoding.list.each do |enc|
+ begin
+ escaped = "&#39;&amp;&quot;&gt;&lt;".encode(enc)
+ unescaped = "'&\"><".encode(enc)
+ rescue Encoding::ConverterNotFoundError
+ next
+ else
+ define_method("test_cgi_escapeHTML:#{enc.name}") do
+ assert_equal(escaped, CGI.escapeHTML(unescaped))
+ end
+ define_method("test_cgi_unescapeHTML:#{enc.name}") do
+ assert_equal(unescaped, CGI.unescapeHTML(escaped))
+ end
+ end
+ end
+
+ Encoding.list.each do |enc|
+ next unless enc.ascii_compatible?
+ begin
+ escaped = "%25+%2B"
+ unescaped = "% +".encode(enc)
+ rescue Encoding::ConverterNotFoundError
+ next
+ else
+ define_method("test_cgi_escape:#{enc.name}") do
+ assert_equal(escaped, CGI.escape(unescaped))
+ end
+ define_method("test_cgi_unescape:#{enc.name}") do
+ assert_equal(unescaped, CGI.unescape(escaped, enc))
+ end
+ end
+ end
+
+ def test_cgi_unescapeHTML_uppercasecharacter
+ assert_equal("\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86", CGI.unescapeHTML("&#x3042;&#x3044;&#X3046;"))
+ end
+
+ def test_cgi_include_escape
+ assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', escape(@str1))
+ end
+
+ def test_cgi_include_escapeHTML
+ assert_equal("&#39;&amp;&quot;&gt;&lt;", escapeHTML("'&\"><"))
+ end
+
+ def test_cgi_include_h
+ assert_equal("&#39;&amp;&quot;&gt;&lt;", h("'&\"><"))
+ end
+
+ def test_cgi_include_unescape
+ str = unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
+ assert_equal(@str1, str)
+ return unless defined?(::Encoding)
+
+ assert_equal(@str1.encoding, str.encoding)
+ assert_equal("\u{30E1 30E2 30EA 691C 7D22}", unescape("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2"))
+ end
+
+ def test_cgi_include_unescapeHTML
+ assert_equal("'&\"><", unescapeHTML("&#39;&amp;&quot;&gt;&lt;"))
+ end
+
+ def test_cgi_escapeElement
+ assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<BR><A HREF="url"></A>', "A", "IMG"))
+ assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"]))
+ assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', "A", "IMG"))
+ assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', ["A", "IMG"]))
+
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', "A", "IMG"))
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', ["A", "IMG"]))
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', "A", "IMG"))
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', ["A", "IMG"]))
+
+ assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', "A", "IMG"))
+ assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', ["A", "IMG"]))
+ end
+
+
+ def test_cgi_unescapeElement
+ assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG"))
+ assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
+ assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG"))
+ assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
+
+ assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
+ assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
+ assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
+ assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
+
+ assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), "A", "IMG"))
+ assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), ["A", "IMG"]))
+ assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), "A", "IMG"))
+ assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), ["A", "IMG"]))
+ end
+end
+
+class CGIEscapePureRubyTest < Test::Unit::TestCase
+ def setup
+ CGI::EscapeExt.module_eval do
+ alias _escapeHTML escapeHTML
+ remove_method :escapeHTML
+ alias _unescapeHTML unescapeHTML
+ remove_method :unescapeHTML
+ end if defined?(CGI::EscapeExt) and CGI::EscapeExt.method_defined?(:escapeHTML)
+ end
+
+ def teardown
+ CGI::EscapeExt.module_eval do
+ alias escapeHTML _escapeHTML
+ remove_method :_escapeHTML
+ alias unescapeHTML _unescapeHTML
+ remove_method :_unescapeHTML
+ end if defined?(CGI::EscapeExt) and CGI::EscapeExt.method_defined?(:_escapeHTML)
+ end
+
+ include CGIEscapeTest::UnescapeHTMLTests
+
+ def test_cgi_escapeHTML_with_invalid_byte_sequence
+ assert_equal("&lt;\xA4??&gt;", CGI.escapeHTML(%[<\xA4??>]))
+ end
+
+ def test_cgi_unescapeHTML_with_invalid_byte_sequence
+ input = "\xFF&"
+ assert_equal(input, CGI.unescapeHTML(input))
+ end
+end
diff --git a/test/cgi/test_cgi_header.rb b/test/cgi/test_cgi_header.rb
deleted file mode 100644
index ec2f4deb72..0000000000
--- a/test/cgi/test_cgi_header.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'time'
-require_relative 'update_env'
-
-
-class CGIHeaderTest < Test::Unit::TestCase
- include UpdateEnv
-
-
- def setup
- @environ = {}
- update_env(
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'GET',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- )
- end
-
-
- def teardown
- ENV.update(@environ)
- end
-
-
- def test_cgi_http_header_simple
- cgi = CGI.new
- ## default content type
- expected = "Content-Type: text/html\r\n\r\n"
- actual = cgi.http_header
- assert_equal(expected, actual)
- ## content type specified as string
- expected = "Content-Type: text/xhtml; charset=utf8\r\n\r\n"
- actual = cgi.http_header('text/xhtml; charset=utf8')
- assert_equal(expected, actual)
- ## content type specified as hash
- expected = "Content-Type: image/png\r\n\r\n"
- actual = cgi.http_header('type'=>'image/png')
- assert_equal(expected, actual)
- ## charset specified
- expected = "Content-Type: text/html; charset=utf8\r\n\r\n"
- actual = cgi.http_header('charset'=>'utf8')
- assert_equal(expected, actual)
- end
-
-
- def test_cgi_http_header_complex
- cgi = CGI.new
- options = {
- 'type' => 'text/xhtml',
- 'charset' => 'utf8',
- 'status' => 'REDIRECT',
- 'server' => 'webrick',
- 'connection' => 'close',
- 'length' => 123,
- 'language' => 'ja',
- 'expires' => Time.gm(2000, 1, 23, 12, 34, 56),
- 'location' => 'http://www.ruby-lang.org/',
- }
- expected = "Status: 302 Found\r\n".dup
- expected << "Server: webrick\r\n"
- expected << "Connection: close\r\n"
- expected << "Content-Type: text/xhtml; charset=utf8\r\n"
- expected << "Content-Length: 123\r\n"
- expected << "Content-Language: ja\r\n"
- expected << "Expires: Sun, 23 Jan 2000 12:34:56 GMT\r\n"
- expected << "location: http://www.ruby-lang.org/\r\n"
- expected << "\r\n"
- actual = cgi.http_header(options)
- assert_equal(expected, actual)
- end
-
-
- def test_cgi_http_header_argerr
- cgi = CGI.new
- expected = ArgumentError
-
- assert_raise(expected) do
- cgi.http_header(nil)
- end
- end
-
-
- def test_cgi_http_header_cookie
- cgi = CGI.new
- cookie1 = CGI::Cookie.new('name1', 'abc', '123')
- cookie2 = CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true)
- ctype = "Content-Type: text/html\r\n"
- sep = "\r\n"
- c1 = "Set-Cookie: name1=abc&123; path=\r\n"
- c2 = "Set-Cookie: name2=value2; path=; secure\r\n"
- ## CGI::Cookie object
- actual = cgi.http_header('cookie'=>cookie1)
- expected = ctype + c1 + sep
- assert_equal(expected, actual)
- ## String
- actual = cgi.http_header('cookie'=>cookie2.to_s)
- expected = ctype + c2 + sep
- assert_equal(expected, actual)
- ## Array
- actual = cgi.http_header('cookie'=>[cookie1, cookie2])
- expected = ctype + c1 + c2 + sep
- assert_equal(expected, actual)
- ## Hash
- actual = cgi.http_header('cookie'=>{'name1'=>cookie1, 'name2'=>cookie2})
- expected = ctype + c1 + c2 + sep
- assert_equal(expected, actual)
- end
-
-
- def test_cgi_http_header_output_cookies
- cgi = CGI.new
- ## output cookies
- cookies = [ CGI::Cookie.new('name1', 'abc', '123'),
- CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true),
- ]
- cgi.instance_variable_set('@output_cookies', cookies)
- expected = "Content-Type: text/html; charset=utf8\r\n".dup
- expected << "Set-Cookie: name1=abc&123; path=\r\n"
- expected << "Set-Cookie: name2=value2; path=; secure\r\n"
- expected << "\r\n"
- ## header when string
- actual = cgi.http_header('text/html; charset=utf8')
- assert_equal(expected, actual)
- ## _header_for_string
- actual = cgi.http_header('type'=>'text/html', 'charset'=>'utf8')
- assert_equal(expected, actual)
- end
-
-
- def test_cgi_http_header_nph
- time_start = Time.now.to_i
- cgi = CGI.new
- ## 'nph' is true
- ENV['SERVER_SOFTWARE'] = 'Apache 2.2.0'
- actual1 = cgi.http_header('nph'=>true)
- ## when old IIS, NPH-mode is forced
- ENV['SERVER_SOFTWARE'] = 'IIS/4.0'
- actual2 = cgi.http_header
- actual3 = cgi.http_header('status'=>'REDIRECT', 'location'=>'http://www.example.com/')
- ## newer IIS doesn't require NPH-mode ## [ruby-dev:30537]
- ENV['SERVER_SOFTWARE'] = 'IIS/5.0'
- actual4 = cgi.http_header
- actual5 = cgi.http_header('status'=>'REDIRECT', 'location'=>'http://www.example.com/')
- time_end = Time.now.to_i
- date = /^Date: ([A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d GMT)\r\n/
- [actual1, actual2, actual3].each do |actual|
- assert_match(date, actual)
- assert_include(time_start..time_end, date =~ actual && Time.parse($1).to_i)
- actual.sub!(date, "Date: DATE_IS_REMOVED\r\n")
- end
- ## assertion
- expected = "HTTP/1.1 200 OK\r\n".dup
- expected << "Date: DATE_IS_REMOVED\r\n"
- expected << "Server: Apache 2.2.0\r\n"
- expected << "Connection: close\r\n"
- expected << "Content-Type: text/html\r\n"
- expected << "\r\n"
- assert_equal(expected, actual1)
- expected.sub!(/^Server: .*?\r\n/, "Server: IIS/4.0\r\n")
- assert_equal(expected, actual2)
- expected.sub!(/^HTTP\/1.1 200 OK\r\n/, "HTTP/1.1 302 Found\r\n")
- expected.sub!(/\r\n\r\n/, "\r\nlocation: http://www.example.com/\r\n\r\n")
- assert_equal(expected, actual3)
- expected = "Content-Type: text/html\r\n".dup
- expected << "\r\n"
- assert_equal(expected, actual4)
- expected = "Status: 302 Found\r\n".dup
- expected << "Content-Type: text/html\r\n"
- expected << "location: http://www.example.com/\r\n"
- expected << "\r\n"
- assert_equal(expected, actual5)
- ensure
- ENV.delete('SERVER_SOFTWARE')
- end
-
-
- def test_cgi_http_header_crlf_injection
- cgi = CGI.new
- assert_raise(RuntimeError) { cgi.http_header("text/xhtml\r\nBOO") }
- assert_raise(RuntimeError) { cgi.http_header("type" => "text/xhtml\r\nBOO") }
- assert_raise(RuntimeError) { cgi.http_header("status" => "200 OK\r\nBOO") }
- assert_raise(RuntimeError) { cgi.http_header("location" => "text/xhtml\r\nBOO") }
- end
-
-
- instance_methods.each do |method|
- private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
- end if ENV['TEST']
-
-end
diff --git a/test/cgi/test_cgi_modruby.rb b/test/cgi/test_cgi_modruby.rb
deleted file mode 100644
index 90132962b5..0000000000
--- a/test/cgi/test_cgi_modruby.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require_relative 'update_env'
-
-
-class CGIModrubyTest < Test::Unit::TestCase
- include UpdateEnv
-
-
- def setup
- @environ = {}
- update_env(
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'GET',
- #'QUERY_STRING' => 'a=foo&b=bar',
- )
- CGI.class_eval { const_set(:MOD_RUBY, true) }
- Apache._reset()
- #@cgi = CGI.new
- #@req = Apache.request
- end
-
-
- def teardown
- ENV.update(@environ)
- CGI.class_eval { remove_const(:MOD_RUBY) }
- end
-
-
- def test_cgi_modruby_simple
- req = Apache.request
- cgi = CGI.new
- assert(req._setup_cgi_env_invoked?)
- assert(! req._send_http_header_invoked?)
- actual = cgi.http_header
- assert_equal('', actual)
- assert_equal('text/html', req.content_type)
- assert(req._send_http_header_invoked?)
- end
-
-
- def test_cgi_modruby_complex
- req = Apache.request
- cgi = CGI.new
- options = {
- 'status' => 'FORBIDDEN',
- 'location' => 'http://www.example.com/',
- 'type' => 'image/gif',
- 'content-encoding' => 'deflate',
- 'cookie' => [ CGI::Cookie.new('name1', 'abc', '123'),
- CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true),
- ],
- }
- assert(req._setup_cgi_env_invoked?)
- assert(! req._send_http_header_invoked?)
- actual = cgi.http_header(options)
- assert_equal('', actual)
- assert_equal('image/gif', req.content_type)
- assert_equal('403 Forbidden', req.status_line)
- assert_equal(403, req.status)
- assert_equal('deflate', req.content_encoding)
- assert_equal('http://www.example.com/', req.headers_out['location'])
- assert_equal(["name1=abc&123; path=", "name2=value2; path=; secure"],
- req.headers_out['Set-Cookie'])
- assert(req._send_http_header_invoked?)
- end
-
-
- def test_cgi_modruby_location
- req = Apache.request
- cgi = CGI.new
- options = {
- 'status' => '200 OK',
- 'location' => 'http://www.example.com/',
- }
- cgi.http_header(options)
- assert_equal('200 OK', req.status_line) # should be '302 Found' ?
- assert_equal(302, req.status)
- assert_equal('http://www.example.com/', req.headers_out['location'])
- end
-
-
- def test_cgi_modruby_requestparams
- req = Apache.request
- req.args = 'a=foo&b=bar'
- cgi = CGI.new
- assert_equal('foo', cgi['a'])
- assert_equal('bar', cgi['b'])
- end
-
-
- instance_methods.each do |method|
- private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
- end if ENV['TEST']
-
-end
-
-
-
-## dummy class for mod_ruby
-class Apache #:nodoc:
-
- def self._reset
- @request = Request.new
- end
-
- def self.request
- return @request
- end
-
- class Request
-
- def initialize
- hash = {}
- def hash.add(name, value)
- (self[name] ||= []) << value
- end
- @http_header = nil
- @headers_out = hash
- @status_line = nil
- @status = nil
- @content_type = nil
- @content_encoding = nil
- end
- attr_accessor :headers_out, :status_line, :status, :content_type, :content_encoding
-
- attr_accessor :args
- #def args
- # return ENV['QUERY_STRING']
- #end
-
- def send_http_header
- @http_header = '*invoked*'
- end
- def _send_http_header_invoked?
- @http_header ? true : false
- end
-
- def setup_cgi_env
- @cgi_env = '*invoked*'
- end
- def _setup_cgi_env_invoked?
- @cgi_env ? true : false
- end
-
- end
-
-end
diff --git a/test/cgi/test_cgi_multipart.rb b/test/cgi/test_cgi_multipart.rb
deleted file mode 100644
index 5e8ec25390..0000000000
--- a/test/cgi/test_cgi_multipart.rb
+++ /dev/null
@@ -1,385 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'tempfile'
-require 'stringio'
-require_relative 'update_env'
-
-
-##
-## usage:
-## boundary = 'foobar1234' # or nil
-## multipart = MultiPart.new(boundary)
-## multipart.append('name1', 'value1')
-## multipart.append('file1', File.read('file1.html'), 'file1.html')
-## str = multipart.close()
-## str.each_line {|line| p line }
-## ## output:
-## # "--foobar1234\r\n"
-## # "Content-Disposition: form-data: name=\"name1\"\r\n"
-## # "\r\n"
-## # "value1\r\n"
-## # "--foobar1234\r\n"
-## # "Content-Disposition: form-data: name=\"file1\"; filename=\"file1.html\"\r\n"
-## # "Content-Type: text/html\r\n"
-## # "\r\n"
-## # "<html>\n"
-## # "<body><p>Hello</p></body>\n"
-## # "</html>\n"
-## # "\r\n"
-## # "--foobar1234--\r\n"
-##
-class MultiPart
-
- def initialize(boundary=nil)
- @boundary = boundary || create_boundary()
- @buf = ''.dup
- @buf.force_encoding(::Encoding::ASCII_8BIT) if defined?(::Encoding)
- end
- attr_reader :boundary
-
- def append(name, value, filename=nil, content_type=nil)
- content_type = detect_content_type(filename) if filename && content_type.nil?
- s = filename ? "; filename=\"#{filename}\"" : ''
- buf = @buf
- buf << "--#{boundary}\r\n"
- buf << "Content-Disposition: form-data: name=\"#{name}\"#{s}\r\n"
- buf << "Content-Type: #{content_type}\r\n" if content_type
- buf << "\r\n"
- buf << value.b
- buf << "\r\n"
- return self
- end
-
- def close
- buf = @buf
- @buf = ''.dup
- return buf << "--#{boundary}--\r\n"
- end
-
- def create_boundary() #:nodoc:
- return "--boundary#{rand().to_s[2..-1]}"
- end
-
- def detect_content_type(filename) #:nodoc:
- filename =~ /\.(\w+)\z/
- return MIME_TYPES[$1] || 'application/octet-stream'
- end
-
- MIME_TYPES = {
- 'gif' => 'image/gif',
- 'jpg' => 'image/jpeg',
- 'jpeg' => 'image/jpeg',
- 'png' => 'image/png',
- 'bmp' => 'image/bmp',
- 'tif' => 'image/tiff',
- 'tiff' => 'image/tiff',
- 'htm' => 'text/html',
- 'html' => 'text/html',
- 'xml' => 'text/xml',
- 'txt' => 'text/plain',
- 'text' => 'text/plain',
- 'css' => 'text/css',
- 'mpg' => 'video/mpeg',
- 'mpeg' => 'video/mpeg',
- 'mov' => 'video/quicktime',
- 'avi' => 'video/x-msvideo',
- 'mp3' => 'audio/mpeg',
- 'mid' => 'audio/midi',
- 'wav' => 'audio/x-wav',
- 'zip' => 'application/zip',
- #'tar.gz' => 'application/gtar',
- 'gz' => 'application/gzip',
- 'bz2' => 'application/bzip2',
- 'rtf' => 'application/rtf',
- 'pdf' => 'application/pdf',
- 'ps' => 'application/postscript',
- 'js' => 'application/x-javascript',
- 'xls' => 'application/vnd.ms-excel',
- 'doc' => 'application/msword',
- 'ppt' => 'application/vnd.ms-powerpoint',
- }
-
-end
-
-
-
-class CGIMultipartTest < Test::Unit::TestCase
- include UpdateEnv
-
-
- def setup
- @environ = {}
- update_env(
- 'REQUEST_METHOD' => 'POST',
- 'CONTENT_TYPE' => nil,
- 'CONTENT_LENGTH' => nil,
- )
- @tempfiles = []
- end
-
- def teardown
- ENV.update(@environ)
- $stdin.close() if $stdin.is_a?(Tempfile)
- $stdin = STDIN
- @tempfiles.each {|t|
- t.close!
- }
- end
-
- def _prepare(data)
- ## create multipart input
- multipart = MultiPart.new(defined?(@boundary) ? @boundary : nil)
- data.each do |hash|
- multipart.append(hash[:name], hash[:value], hash[:filename])
- end
- input = multipart.close()
- input = yield(input) if block_given?
- #$stderr.puts "*** debug: input=\n#{input.collect{|line| line.inspect}.join("\n")}"
- @boundary ||= multipart.boundary
- ## set environment
- ENV['CONTENT_TYPE'] = "multipart/form-data; boundary=#{@boundary}"
- ENV['CONTENT_LENGTH'] = input.length.to_s
- ENV['REQUEST_METHOD'] = 'POST'
- ## set $stdin
- tmpfile = Tempfile.new('test_cgi_multipart')
- @tempfiles << tmpfile
- tmpfile.binmode
- tmpfile << input
- tmpfile.rewind()
- $stdin = tmpfile
- end
-
- def _test_multipart(cgi_options={})
- caller(0).find {|s| s =~ /in `test_(.*?)'/ }
- #testname = $1
- #$stderr.puts "*** debug: testname=#{testname.inspect}"
- _prepare(@data)
- options = {:accept_charset=>"UTF-8"}
- options.merge! cgi_options
- cgi = CGI.new(options)
- expected_names = @data.collect{|hash| hash[:name] }.sort
- assert_equal(expected_names, cgi.params.keys.sort)
- threshold = 1024*10
- @data.each do |hash|
- name = hash[:name]
- expected = hash[:value]
- if hash[:filename] #if file
- expected_class = @expected_class || (hash[:value].length < threshold ? StringIO : Tempfile)
- assert(cgi.files.keys.member?(hash[:name]))
- else
- expected_class = String
- assert_equal(expected, cgi[name])
- assert_equal(false,cgi.files.keys.member?(hash[:name]))
- end
- assert_kind_of(expected_class, cgi[name])
- assert_equal(expected, cgi[name].read())
- assert_equal(hash[:filename] || '', cgi[name].original_filename) #if hash[:filename]
- assert_equal(hash[:content_type] || '', cgi[name].content_type) #if hash[:content_type]
- end
- ensure
- if cgi
- cgi.params.each {|name, vals|
- vals.each {|val|
- if val.kind_of?(Tempfile) && val.path
- val.close!
- end
- }
- }
- end
- end
-
-
- def _read(basename)
- filename = File.join(File.dirname(__FILE__), 'testdata', basename)
- s = File.open(filename, 'rb') {|f| f.read() }
-
- return s
- end
-
-
- def test_cgi_multipart_stringio
- @boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX'
- @data = [
- {:name=>'hidden1', :value=>'foobar'},
- {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup},
- {:name=>'file1', :value=>_read('file1.html'),
- :filename=>'file1.html', :content_type=>'text/html'},
- {:name=>'image1', :value=>_read('small.png'),
- :filename=>'small.png', :content_type=>'image/png'}, # small image
- ]
- @data[1][:value].force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
- @expected_class = StringIO
- _test_multipart()
- end
-
-
- def test_cgi_multipart_tempfile
- @boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX'
- @data = [
- {:name=>'hidden1', :value=>'foobar'},
- {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup},
- {:name=>'file1', :value=>_read('file1.html'),
- :filename=>'file1.html', :content_type=>'text/html'},
- {:name=>'image1', :value=>_read('large.png'),
- :filename=>'large.png', :content_type=>'image/png'}, # large image
- ]
- @data[1][:value].force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
- @expected_class = Tempfile
- _test_multipart()
- end
-
-
- def _set_const(klass, name, value)
- old = nil
- klass.class_eval do
- old = const_get(name)
- remove_const(name)
- const_set(name, value)
- end
- return old
- end
-
-
- def test_cgi_multipart_maxmultipartlength
- @data = [
- {:name=>'image1', :value=>_read('large.png'),
- :filename=>'large.png', :content_type=>'image/png'}, # large image
- ]
- begin
- ex = assert_raise(StandardError) do
- _test_multipart(:max_multipart_length=>2 * 1024) # set via simple scalar
- end
- assert_equal("too large multipart data.", ex.message)
- ensure
- end
- end
-
-
- def test_cgi_multipart_maxmultipartlength_lambda
- @data = [
- {:name=>'image1', :value=>_read('large.png'),
- :filename=>'large.png', :content_type=>'image/png'}, # large image
- ]
- begin
- ex = assert_raise(StandardError) do
- _test_multipart(:max_multipart_length=>lambda{2*1024}) # set via lambda
- end
- assert_equal("too large multipart data.", ex.message)
- ensure
- end
- end
-
-
- def test_cgi_multipart_maxmultipartcount
- @data = [
- {:name=>'file1', :value=>_read('file1.html'),
- :filename=>'file1.html', :content_type=>'text/html'},
- ]
- item = @data.first
- 500.times { @data << item }
- #original = _set_const(CGI, :MAX_MULTIPART_COUNT, 128)
- begin
- ex = assert_raise(StandardError) do
- _test_multipart()
- end
- assert_equal("too many parameters.", ex.message)
- ensure
- #_set_const(CGI, :MAX_MULTIPART_COUNT, original)
- end
- end if CGI.const_defined?(:MAX_MULTIPART_COUNT)
-
-
- def test_cgi_multipart_badbody ## [ruby-dev:28470]
- @data = [
- {:name=>'file1', :value=>_read('file1.html'),
- :filename=>'file1.html', :content_type=>'text/html'},
- ]
- _prepare(@data) do |input|
- input2 = input.sub(/--(\r\n)?\z/, "\r\n")
- assert input2 != input
- #p input2
- input2
- end
- ex = assert_raise(EOFError) do
- CGI.new(:accept_charset=>"UTF-8")
- end
- assert_equal("bad content body", ex.message)
- #
- _prepare(@data) do |input|
- input2 = input.sub(/--(\r\n)?\z/, "")
- assert input2 != input
- #p input2
- input2
- end
- ex = assert_raise(EOFError) do
- CGI.new(:accept_charset=>"UTF-8")
- end
- assert_equal("bad content body", ex.message)
- end
-
-
- def test_cgi_multipart_quoteboundary ## [JVN#84798830]
- @boundary = '(.|\n)*'
- @data = [
- {:name=>'hidden1', :value=>'foobar'},
- {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup},
- {:name=>'file1', :value=>_read('file1.html'),
- :filename=>'file1.html', :content_type=>'text/html'},
- {:name=>'image1', :value=>_read('small.png'),
- :filename=>'small.png', :content_type=>'image/png'}, # small image
- ]
- @data[1][:value].force_encoding("UTF-8")
- _prepare(@data)
- cgi = CGI.new(:accept_charset=>"UTF-8")
- assert_equal('file1.html', cgi['file1'].original_filename)
- end
-
- def test_cgi_multipart_boundary_10240 # [Bug #3866]
- @boundary = 'AaB03x'
- @data = [
- {:name=>'file', :value=>"b"*10134,
- :filename=>'file.txt', :content_type=>'text/plain'},
- {:name=>'foo', :value=>"bar"},
- ]
- _prepare(@data)
- cgi = CGI.new(:accept_charset=>"UTF-8")
- assert_equal(cgi['foo'], 'bar')
- assert_equal(cgi['file'].read, 'b'*10134)
- cgi['file'].close! if cgi['file'].kind_of? Tempfile
- end
-
- def test_cgi_multipart_without_tempfile
- assert_in_out_err([], <<-'EOM')
- require 'cgi'
- require 'stringio'
- ENV['REQUEST_METHOD'] = 'POST'
- ENV['CONTENT_TYPE'] = 'multipart/form-data; boundary=foobar1234'
- body = <<-BODY.gsub(/\n/, "\r\n")
---foobar1234
-Content-Disposition: form-data: name=\"name1\"
-
-value1
---foobar1234
-Content-Disposition: form-data: name=\"file1\"; filename=\"file1.html\"
-Content-Type: text/html
-
-<html>
-<body><p>Hello</p></body>
-</html>
-
---foobar1234--
-BODY
- ENV['CONTENT_LENGTH'] = body.size.to_s
- $stdin = StringIO.new(body)
- CGI.new
- EOM
- end
-
- ###
-
- self.instance_methods.each do |method|
- private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
- end if ENV['TEST']
-
-end
diff --git a/test/cgi/test_cgi_session.rb b/test/cgi/test_cgi_session.rb
deleted file mode 100644
index 32b907d741..0000000000
--- a/test/cgi/test_cgi_session.rb
+++ /dev/null
@@ -1,169 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'cgi/session'
-require 'cgi/session/pstore'
-require 'stringio'
-require 'tmpdir'
-require_relative 'update_env'
-
-class CGISessionTest < Test::Unit::TestCase
- include UpdateEnv
-
- def setup
- @environ = {}
- @session_dir = Dir.mktmpdir(%w'session dir')
- end
-
- def teardown
- ENV.update(@environ)
- $stdout = STDOUT
- FileUtils.rm_rf(@session_dir)
- end
-
- def test_cgi_session_filestore
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
- # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- value1="value1"
- value2="\x8F\xBC\x8D]".dup
- value2.force_encoding("SJIS") if defined?(::Encoding)
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir)
- session["key1"]=value1
- session["key2"]=value2
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- session.close
- $stdout = StringIO.new
- cgi.out{""}
-
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'HTTP_COOKIE' => "_session_id=#{session_id}",
- 'QUERY_STRING' => "_session_id=#{session.session_id}",
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir)
- $stdout = StringIO.new
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- session.close
-
- end
- def test_cgi_session_pstore
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
- # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- value1="value1"
- value2="\x8F\xBC\x8D]".dup
- value2.force_encoding("SJIS") if defined?(::Encoding)
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"database_manager"=>CGI::Session::PStore)
- session["key1"]=value1
- session["key2"]=value2
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- session.close
- $stdout = StringIO.new
- cgi.out{""}
-
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'HTTP_COOKIE' => "_session_id=#{session_id}",
- 'QUERY_STRING' => "_session_id=#{session.session_id}",
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"database_manager"=>CGI::Session::PStore)
- $stdout = StringIO.new
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- session.close
- end if defined?(::PStore)
- def test_cgi_session_specify_session_id
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
- # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- value1="value1"
- value2="\x8F\xBC\x8D]".dup
- value2.force_encoding("SJIS") if defined?(::Encoding)
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_id"=>"foo")
- session["key1"]=value1
- session["key2"]=value2
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- assert_equal("foo",session.session_id)
- #session_id=session.session_id
- session.close
- $stdout = StringIO.new
- cgi.out{""}
-
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'HTTP_COOKIE' => "_session_id=#{session_id}",
- 'QUERY_STRING' => "_session_id=#{session.session_id}",
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir)
- $stdout = StringIO.new
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- assert_equal("foo",session.session_id)
- session.close
- end
- def test_cgi_session_specify_session_key
- update_env(
- 'REQUEST_METHOD' => 'GET',
- # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
- # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- value1="value1"
- value2="\x8F\xBC\x8D]".dup
- value2.force_encoding("SJIS") if defined?(::Encoding)
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_key"=>"bar")
- session["key1"]=value1
- session["key2"]=value2
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- session_id=session.session_id
- session.close
- $stdout = StringIO.new
- cgi.out{""}
-
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'HTTP_COOKIE' => "bar=#{session_id}",
- # 'QUERY_STRING' => "bar=#{session.session_id}",
- 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- )
- cgi = CGI.new
- session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_key"=>"bar")
- $stdout = StringIO.new
- assert_equal(value1,session["key1"])
- assert_equal(value2,session["key2"])
- session.close
- end
-end
diff --git a/test/cgi/test_cgi_tag_helper.rb b/test/cgi/test_cgi_tag_helper.rb
deleted file mode 100644
index 0b99dfc1bc..0000000000
--- a/test/cgi/test_cgi_tag_helper.rb
+++ /dev/null
@@ -1,355 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'stringio'
-require_relative 'update_env'
-
-
-class CGITagHelperTest < Test::Unit::TestCase
- include UpdateEnv
-
-
- def setup
- @environ = {}
- #@environ = {
- # 'SERVER_PROTOCOL' => 'HTTP/1.1',
- # 'REQUEST_METHOD' => 'GET',
- # 'SERVER_SOFTWARE' => 'Apache 2.2.0',
- #}
- #ENV.update(@environ)
- end
-
-
- def teardown
- ENV.update(@environ)
- $stdout = STDOUT
- end
-
-
- def test_cgi_tag_helper_html3
- update_env(
- 'REQUEST_METHOD' => 'GET',
- )
- ## html3
- cgi = CGI.new('html3')
- assert_equal('<A HREF=""></A>',cgi.a)
- assert_equal('<A HREF="bar"></A>',cgi.a('bar'))
- assert_equal('<A HREF="">foo</A>',cgi.a{'foo'})
- assert_equal('<A HREF="bar">foo</A>',cgi.a('bar'){'foo'})
- assert_equal('<TT></TT>',cgi.tt)
- assert_equal('<TT></TT>',cgi.tt('bar'))
- assert_equal('<TT>foo</TT>',cgi.tt{'foo'})
- assert_equal('<TT>foo</TT>',cgi.tt('bar'){'foo'})
- assert_equal('<I></I>',cgi.i)
- assert_equal('<I></I>',cgi.i('bar'))
- assert_equal('<I>foo</I>',cgi.i{'foo'})
- assert_equal('<I>foo</I>',cgi.i('bar'){'foo'})
- assert_equal('<B></B>',cgi.b)
- assert_equal('<B></B>',cgi.b('bar'))
- assert_equal('<B>foo</B>',cgi.b{'foo'})
- assert_equal('<B>foo</B>',cgi.b('bar'){'foo'})
- assert_equal('<U></U>',cgi.u)
- assert_equal('<U></U>',cgi.u('bar'))
- assert_equal('<U>foo</U>',cgi.u{'foo'})
- assert_equal('<U>foo</U>',cgi.u('bar'){'foo'})
- assert_equal('<STRIKE></STRIKE>',cgi.strike)
- assert_equal('<STRIKE></STRIKE>',cgi.strike('bar'))
- assert_equal('<STRIKE>foo</STRIKE>',cgi.strike{'foo'})
- assert_equal('<STRIKE>foo</STRIKE>',cgi.strike('bar'){'foo'})
- assert_equal('<BIG></BIG>',cgi.big)
- assert_equal('<BIG></BIG>',cgi.big('bar'))
- assert_equal('<BIG>foo</BIG>',cgi.big{'foo'})
- assert_equal('<BIG>foo</BIG>',cgi.big('bar'){'foo'})
- assert_equal('<SMALL></SMALL>',cgi.small)
- assert_equal('<SMALL></SMALL>',cgi.small('bar'))
- assert_equal('<SMALL>foo</SMALL>',cgi.small{'foo'})
- assert_equal('<SMALL>foo</SMALL>',cgi.small('bar'){'foo'})
- assert_equal('<SUB></SUB>',cgi.sub)
- assert_equal('<SUB></SUB>',cgi.sub('bar'))
- assert_equal('<SUB>foo</SUB>',cgi.sub{'foo'})
- assert_equal('<SUB>foo</SUB>',cgi.sub('bar'){'foo'})
- assert_equal('<SUP></SUP>',cgi.sup)
- assert_equal('<SUP></SUP>',cgi.sup('bar'))
- assert_equal('<SUP>foo</SUP>',cgi.sup{'foo'})
- assert_equal('<SUP>foo</SUP>',cgi.sup('bar'){'foo'})
- assert_equal('<EM></EM>',cgi.em)
- assert_equal('<EM></EM>',cgi.em('bar'))
- assert_equal('<EM>foo</EM>',cgi.em{'foo'})
- assert_equal('<EM>foo</EM>',cgi.em('bar'){'foo'})
- assert_equal('<STRONG></STRONG>',cgi.strong)
- assert_equal('<STRONG></STRONG>',cgi.strong('bar'))
- assert_equal('<STRONG>foo</STRONG>',cgi.strong{'foo'})
- assert_equal('<STRONG>foo</STRONG>',cgi.strong('bar'){'foo'})
- assert_equal('<DFN></DFN>',cgi.dfn)
- assert_equal('<DFN></DFN>',cgi.dfn('bar'))
- assert_equal('<DFN>foo</DFN>',cgi.dfn{'foo'})
- assert_equal('<DFN>foo</DFN>',cgi.dfn('bar'){'foo'})
- assert_equal('<CODE></CODE>',cgi.code)
- assert_equal('<CODE></CODE>',cgi.code('bar'))
- assert_equal('<CODE>foo</CODE>',cgi.code{'foo'})
- assert_equal('<CODE>foo</CODE>',cgi.code('bar'){'foo'})
- assert_equal('<SAMP></SAMP>',cgi.samp)
- assert_equal('<SAMP></SAMP>',cgi.samp('bar'))
- assert_equal('<SAMP>foo</SAMP>',cgi.samp{'foo'})
- assert_equal('<SAMP>foo</SAMP>',cgi.samp('bar'){'foo'})
- assert_equal('<KBD></KBD>',cgi.kbd)
- assert_equal('<KBD></KBD>',cgi.kbd('bar'))
- assert_equal('<KBD>foo</KBD>',cgi.kbd{'foo'})
- assert_equal('<KBD>foo</KBD>',cgi.kbd('bar'){'foo'})
- assert_equal('<VAR></VAR>',cgi.var)
- assert_equal('<VAR></VAR>',cgi.var('bar'))
- assert_equal('<VAR>foo</VAR>',cgi.var{'foo'})
- assert_equal('<VAR>foo</VAR>',cgi.var('bar'){'foo'})
- assert_equal('<CITE></CITE>',cgi.cite)
- assert_equal('<CITE></CITE>',cgi.cite('bar'))
- assert_equal('<CITE>foo</CITE>',cgi.cite{'foo'})
- assert_equal('<CITE>foo</CITE>',cgi.cite('bar'){'foo'})
- assert_equal('<FONT></FONT>',cgi.font)
- assert_equal('<FONT></FONT>',cgi.font('bar'))
- assert_equal('<FONT>foo</FONT>',cgi.font{'foo'})
- assert_equal('<FONT>foo</FONT>',cgi.font('bar'){'foo'})
- assert_equal('<ADDRESS></ADDRESS>',cgi.address)
- assert_equal('<ADDRESS></ADDRESS>',cgi.address('bar'))
- assert_equal('<ADDRESS>foo</ADDRESS>',cgi.address{'foo'})
- assert_equal('<ADDRESS>foo</ADDRESS>',cgi.address('bar'){'foo'})
- assert_equal('<DIV></DIV>',cgi.div)
- assert_equal('<DIV></DIV>',cgi.div('bar'))
- assert_equal('<DIV>foo</DIV>',cgi.div{'foo'})
- assert_equal('<DIV>foo</DIV>',cgi.div('bar'){'foo'})
- assert_equal('<CENTER></CENTER>',cgi.center)
- assert_equal('<CENTER></CENTER>',cgi.center('bar'))
- assert_equal('<CENTER>foo</CENTER>',cgi.center{'foo'})
- assert_equal('<CENTER>foo</CENTER>',cgi.center('bar'){'foo'})
- assert_equal('<MAP></MAP>',cgi.map)
- assert_equal('<MAP></MAP>',cgi.map('bar'))
- assert_equal('<MAP>foo</MAP>',cgi.map{'foo'})
- assert_equal('<MAP>foo</MAP>',cgi.map('bar'){'foo'})
- assert_equal('<APPLET></APPLET>',cgi.applet)
- assert_equal('<APPLET></APPLET>',cgi.applet('bar'))
- assert_equal('<APPLET>foo</APPLET>',cgi.applet{'foo'})
- assert_equal('<APPLET>foo</APPLET>',cgi.applet('bar'){'foo'})
- assert_equal('<PRE></PRE>',cgi.pre)
- assert_equal('<PRE></PRE>',cgi.pre('bar'))
- assert_equal('<PRE>foo</PRE>',cgi.pre{'foo'})
- assert_equal('<PRE>foo</PRE>',cgi.pre('bar'){'foo'})
- assert_equal('<XMP></XMP>',cgi.xmp)
- assert_equal('<XMP></XMP>',cgi.xmp('bar'))
- assert_equal('<XMP>foo</XMP>',cgi.xmp{'foo'})
- assert_equal('<XMP>foo</XMP>',cgi.xmp('bar'){'foo'})
- assert_equal('<LISTING></LISTING>',cgi.listing)
- assert_equal('<LISTING></LISTING>',cgi.listing('bar'))
- assert_equal('<LISTING>foo</LISTING>',cgi.listing{'foo'})
- assert_equal('<LISTING>foo</LISTING>',cgi.listing('bar'){'foo'})
- assert_equal('<DL></DL>',cgi.dl)
- assert_equal('<DL></DL>',cgi.dl('bar'))
- assert_equal('<DL>foo</DL>',cgi.dl{'foo'})
- assert_equal('<DL>foo</DL>',cgi.dl('bar'){'foo'})
- assert_equal('<OL></OL>',cgi.ol)
- assert_equal('<OL></OL>',cgi.ol('bar'))
- assert_equal('<OL>foo</OL>',cgi.ol{'foo'})
- assert_equal('<OL>foo</OL>',cgi.ol('bar'){'foo'})
- assert_equal('<UL></UL>',cgi.ul)
- assert_equal('<UL></UL>',cgi.ul('bar'))
- assert_equal('<UL>foo</UL>',cgi.ul{'foo'})
- assert_equal('<UL>foo</UL>',cgi.ul('bar'){'foo'})
- assert_equal('<DIR></DIR>',cgi.dir)
- assert_equal('<DIR></DIR>',cgi.dir('bar'))
- assert_equal('<DIR>foo</DIR>',cgi.dir{'foo'})
- assert_equal('<DIR>foo</DIR>',cgi.dir('bar'){'foo'})
- assert_equal('<MENU></MENU>',cgi.menu)
- assert_equal('<MENU></MENU>',cgi.menu('bar'))
- assert_equal('<MENU>foo</MENU>',cgi.menu{'foo'})
- assert_equal('<MENU>foo</MENU>',cgi.menu('bar'){'foo'})
- assert_equal('<SELECT></SELECT>',cgi.select)
- assert_equal('<SELECT></SELECT>',cgi.select('bar'))
- assert_equal('<SELECT>foo</SELECT>',cgi.select{'foo'})
- assert_equal('<SELECT>foo</SELECT>',cgi.select('bar'){'foo'})
- assert_equal('<TABLE></TABLE>',cgi.table)
- assert_equal('<TABLE></TABLE>',cgi.table('bar'))
- assert_equal('<TABLE>foo</TABLE>',cgi.table{'foo'})
- assert_equal('<TABLE>foo</TABLE>',cgi.table('bar'){'foo'})
- assert_equal('<TITLE></TITLE>',cgi.title)
- assert_equal('<TITLE></TITLE>',cgi.title('bar'))
- assert_equal('<TITLE>foo</TITLE>',cgi.title{'foo'})
- assert_equal('<TITLE>foo</TITLE>',cgi.title('bar'){'foo'})
- assert_equal('<STYLE></STYLE>',cgi.style)
- assert_equal('<STYLE></STYLE>',cgi.style('bar'))
- assert_equal('<STYLE>foo</STYLE>',cgi.style{'foo'})
- assert_equal('<STYLE>foo</STYLE>',cgi.style('bar'){'foo'})
- assert_equal('<SCRIPT></SCRIPT>',cgi.script)
- assert_equal('<SCRIPT></SCRIPT>',cgi.script('bar'))
- assert_equal('<SCRIPT>foo</SCRIPT>',cgi.script{'foo'})
- assert_equal('<SCRIPT>foo</SCRIPT>',cgi.script('bar'){'foo'})
- assert_equal('<H1></H1>',cgi.h1)
- assert_equal('<H1></H1>',cgi.h1('bar'))
- assert_equal('<H1>foo</H1>',cgi.h1{'foo'})
- assert_equal('<H1>foo</H1>',cgi.h1('bar'){'foo'})
- assert_equal('<H2></H2>',cgi.h2)
- assert_equal('<H2></H2>',cgi.h2('bar'))
- assert_equal('<H2>foo</H2>',cgi.h2{'foo'})
- assert_equal('<H2>foo</H2>',cgi.h2('bar'){'foo'})
- assert_equal('<H3></H3>',cgi.h3)
- assert_equal('<H3></H3>',cgi.h3('bar'))
- assert_equal('<H3>foo</H3>',cgi.h3{'foo'})
- assert_equal('<H3>foo</H3>',cgi.h3('bar'){'foo'})
- assert_equal('<H4></H4>',cgi.h4)
- assert_equal('<H4></H4>',cgi.h4('bar'))
- assert_equal('<H4>foo</H4>',cgi.h4{'foo'})
- assert_equal('<H4>foo</H4>',cgi.h4('bar'){'foo'})
- assert_equal('<H5></H5>',cgi.h5)
- assert_equal('<H5></H5>',cgi.h5('bar'))
- assert_equal('<H5>foo</H5>',cgi.h5{'foo'})
- assert_equal('<H5>foo</H5>',cgi.h5('bar'){'foo'})
- assert_equal('<H6></H6>',cgi.h6)
- assert_equal('<H6></H6>',cgi.h6('bar'))
- assert_equal('<H6>foo</H6>',cgi.h6{'foo'})
- assert_equal('<H6>foo</H6>',cgi.h6('bar'){'foo'})
- assert_match(/^<TEXTAREA .*><\/TEXTAREA>$/,cgi.textarea)
- assert_match(/COLS="70"/,cgi.textarea)
- assert_match(/ROWS="10"/,cgi.textarea)
- assert_match(/NAME=""/,cgi.textarea)
- assert_match(/^<TEXTAREA .*><\/TEXTAREA>$/,cgi.textarea("bar"))
- assert_match(/COLS="70"/,cgi.textarea("bar"))
- assert_match(/ROWS="10"/,cgi.textarea("bar"))
- assert_match(/NAME="bar"/,cgi.textarea("bar"))
- assert_match(/^<TEXTAREA .*>foo<\/TEXTAREA>$/,cgi.textarea{"foo"})
- assert_match(/COLS="70"/,cgi.textarea{"foo"})
- assert_match(/ROWS="10"/,cgi.textarea{"foo"})
- assert_match(/NAME=""/,cgi.textarea{"foo"})
- assert_match(/^<TEXTAREA .*>foo<\/TEXTAREA>$/,cgi.textarea("bar"){"foo"})
- assert_match(/COLS="70"/,cgi.textarea("bar"){"foo"})
- assert_match(/ROWS="10"/,cgi.textarea("bar"){"foo"})
- assert_match(/NAME="bar"/,cgi.textarea("bar"){"foo"})
- assert_match(/^<FORM .*><\/FORM>$/,cgi.form)
- assert_match(/METHOD="post"/,cgi.form)
- assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form)
- assert_match(/^<FORM .*><\/FORM>$/,cgi.form("bar"))
- assert_match(/METHOD="bar"/,cgi.form("bar"))
- assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form("bar"))
- assert_match(/^<FORM .*>foo<\/FORM>$/,cgi.form{"foo"})
- assert_match(/METHOD="post"/,cgi.form{"foo"})
- assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form{"foo"})
- assert_match(/^<FORM .*>foo<\/FORM>$/,cgi.form("bar"){"foo"})
- assert_match(/METHOD="bar"/,cgi.form("bar"){"foo"})
- assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form("bar"){"foo"})
- assert_equal('<BLOCKQUOTE></BLOCKQUOTE>',cgi.blockquote)
- assert_equal('<BLOCKQUOTE CITE="bar"></BLOCKQUOTE>',cgi.blockquote('bar'))
- assert_equal('<BLOCKQUOTE>foo</BLOCKQUOTE>',cgi.blockquote{'foo'})
- assert_equal('<BLOCKQUOTE CITE="bar">foo</BLOCKQUOTE>',cgi.blockquote('bar'){'foo'})
- assert_equal('<CAPTION></CAPTION>',cgi.caption)
- assert_equal('<CAPTION ALIGN="bar"></CAPTION>',cgi.caption('bar'))
- assert_equal('<CAPTION>foo</CAPTION>',cgi.caption{'foo'})
- assert_equal('<CAPTION ALIGN="bar">foo</CAPTION>',cgi.caption('bar'){'foo'})
- assert_equal('<IMG SRC="" ALT="">',cgi.img)
- assert_equal('<IMG SRC="bar" ALT="">',cgi.img('bar'))
- assert_equal('<IMG SRC="" ALT="">',cgi.img{'foo'})
- assert_equal('<IMG SRC="bar" ALT="">',cgi.img('bar'){'foo'})
- assert_equal('<BASE HREF="">',cgi.base)
- assert_equal('<BASE HREF="bar">',cgi.base('bar'))
- assert_equal('<BASE HREF="">',cgi.base{'foo'})
- assert_equal('<BASE HREF="bar">',cgi.base('bar'){'foo'})
- assert_equal('<BASEFONT>',cgi.basefont)
- assert_equal('<BASEFONT>',cgi.basefont('bar'))
- assert_equal('<BASEFONT>',cgi.basefont{'foo'})
- assert_equal('<BASEFONT>',cgi.basefont('bar'){'foo'})
- assert_equal('<BR>',cgi.br)
- assert_equal('<BR>',cgi.br('bar'))
- assert_equal('<BR>',cgi.br{'foo'})
- assert_equal('<BR>',cgi.br('bar'){'foo'})
- assert_equal('<AREA>',cgi.area)
- assert_equal('<AREA>',cgi.area('bar'))
- assert_equal('<AREA>',cgi.area{'foo'})
- assert_equal('<AREA>',cgi.area('bar'){'foo'})
- assert_equal('<LINK>',cgi.link)
- assert_equal('<LINK>',cgi.link('bar'))
- assert_equal('<LINK>',cgi.link{'foo'})
- assert_equal('<LINK>',cgi.link('bar'){'foo'})
- assert_equal('<PARAM>',cgi.param)
- assert_equal('<PARAM>',cgi.param('bar'))
- assert_equal('<PARAM>',cgi.param{'foo'})
- assert_equal('<PARAM>',cgi.param('bar'){'foo'})
- assert_equal('<HR>',cgi.hr)
- assert_equal('<HR>',cgi.hr('bar'))
- assert_equal('<HR>',cgi.hr{'foo'})
- assert_equal('<HR>',cgi.hr('bar'){'foo'})
- assert_equal('<INPUT>',cgi.input)
- assert_equal('<INPUT>',cgi.input('bar'))
- assert_equal('<INPUT>',cgi.input{'foo'})
- assert_equal('<INPUT>',cgi.input('bar'){'foo'})
- assert_equal('<ISINDEX>',cgi.isindex)
- assert_equal('<ISINDEX>',cgi.isindex('bar'))
- assert_equal('<ISINDEX>',cgi.isindex{'foo'})
- assert_equal('<ISINDEX>',cgi.isindex('bar'){'foo'})
- assert_equal('<META>',cgi.meta)
- assert_equal('<META>',cgi.meta('bar'))
- assert_equal('<META>',cgi.meta{'foo'})
- assert_equal('<META>',cgi.meta('bar'){'foo'})
- assert_equal('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>',cgi.html)
- assert_equal('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>foo</HTML>',cgi.html{'foo'})
- assert_equal('<HEAD>',cgi.head)
- assert_equal('<HEAD>foo</HEAD>',cgi.head{'foo'})
- assert_equal('<BODY>',cgi.body)
- assert_equal('<BODY>foo</BODY>',cgi.body{'foo'})
- assert_equal('<P>',cgi.p)
- assert_equal('<P>foo</P>',cgi.p{'foo'})
- assert_equal('<PLAINTEXT>',cgi.plaintext)
- assert_equal('<PLAINTEXT>foo</PLAINTEXT>',cgi.plaintext{'foo'})
- assert_equal('<DT>',cgi.dt)
- assert_equal('<DT>foo</DT>',cgi.dt{'foo'})
- assert_equal('<DD>',cgi.dd)
- assert_equal('<DD>foo</DD>',cgi.dd{'foo'})
- assert_equal('<LI>',cgi.li)
- assert_equal('<LI>foo</LI>',cgi.li{'foo'})
- assert_equal('<OPTION>',cgi.option)
- assert_equal('<OPTION>foo</OPTION>',cgi.option{'foo'})
- assert_equal('<TR>',cgi.tr)
- assert_equal('<TR>foo</TR>',cgi.tr{'foo'})
- assert_equal('<TH>',cgi.th)
- assert_equal('<TH>foo</TH>',cgi.th{'foo'})
- assert_equal('<TD>',cgi.td)
- assert_equal('<TD>foo</TD>',cgi.td{'foo'})
- str=cgi.checkbox_group("foo",["aa","bb"],["cc","dd"])
- assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
- assert_match(/^<INPUT .*TYPE="checkbox".*>bb<INPUT .*TYPE="checkbox".*>dd$/,str)
- assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
- str=cgi.radio_group("foo",["aa","bb"],["cc","dd"])
- assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
- assert_match(/^<INPUT .*TYPE="radio".*>bb<INPUT .*TYPE="radio".*>dd$/,str)
- assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
- str=cgi.checkbox_group("foo",["aa","bb"],["cc","dd",true])
- assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
- assert_match(/^<INPUT .*TYPE="checkbox".*>bb<INPUT .*TYPE="checkbox".*>dd$/,str)
- assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
- assert_match(/^<INPUT .*>bb<INPUT .*CHECKED.*>dd$/,str)
- assert_match(/<INPUT .*TYPE="text".*>/,cgi.text_field(:name=>"name",:value=>"value"))
- str=cgi.radio_group("foo",["aa","bb"],["cc","dd",false])
- assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
- assert_match(/^<INPUT .*TYPE="radio".*>bb<INPUT .*TYPE="radio".*>dd$/,str)
- assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
- end
-
-=begin
- def test_cgi_tag_helper_html4
- ## html4
- cgi = CGI.new('html4')
- ## html4 transitional
- cgi = CGI.new('html4Tr')
- ## html4 frameset
- cgi = CGI.new('html4Fr')
- end
-=end
-
- def test_cgi_tag_helper_html5
- update_env(
- 'REQUEST_METHOD' => 'GET',
- )
- ## html5
- cgi = CGI.new('html5')
- assert_equal('<HEADER></HEADER>',cgi.header)
- assert_equal('<FOOTER></FOOTER>',cgi.footer)
- assert_equal('<ARTICLE></ARTICLE>',cgi.article)
- assert_equal('<SECTION></SECTION>',cgi.section)
- assert_equal('<!DOCTYPE HTML><HTML BLA="TEST"></HTML>',cgi.html("BLA"=>"TEST"){})
- end
-
-end
diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb
deleted file mode 100644
index bff77f7ffc..0000000000
--- a/test/cgi/test_cgi_util.rb
+++ /dev/null
@@ -1,330 +0,0 @@
-# frozen_string_literal: true
-require 'test/unit'
-require 'cgi'
-require 'stringio'
-require_relative 'update_env'
-
-
-class CGIUtilTest < Test::Unit::TestCase
- include CGI::Util
- include UpdateEnv
-
- def setup
- @environ = {}
- update_env(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => nil,
- )
- @str1="&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93".dup
- @str1.force_encoding("UTF-8") if defined?(::Encoding)
- end
-
- def teardown
- ENV.update(@environ)
- end
-
- def test_cgi_escape
- assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escape(@str1))
- assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI.escape(@str1).ascii_only?) if defined?(::Encoding)
- end
-
- def test_cgi_escape_with_unreserved_characters
- assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
- CGI.escape("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"),
- "should not escape any unreserved characters, as per RFC3986 Section 2.3")
- end
-
- def test_cgi_escape_with_invalid_byte_sequence
- assert_equal('%C0%3C%3C', CGI.escape("\xC0\<\<".dup.force_encoding("UTF-8")))
- end
-
- def test_cgi_escape_preserve_encoding
- assert_equal(Encoding::US_ASCII, CGI.escape("\xC0\<\<".dup.force_encoding("US-ASCII")).encoding)
- assert_equal(Encoding::ASCII_8BIT, CGI.escape("\xC0\<\<".dup.force_encoding("ASCII-8BIT")).encoding)
- assert_equal(Encoding::UTF_8, CGI.escape("\xC0\<\<".dup.force_encoding("UTF-8")).encoding)
- end
-
- def test_cgi_unescape
- str = CGI.unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
- assert_equal(@str1, str)
- return unless defined?(::Encoding)
-
- assert_equal(@str1.encoding, str.encoding)
- assert_equal("\u{30E1 30E2 30EA 691C 7D22}", CGI.unescape("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2"))
- end
-
- def test_cgi_unescape_preserve_encoding
- assert_equal(Encoding::US_ASCII, CGI.unescape("%C0%3C%3C".dup.force_encoding("US-ASCII")).encoding)
- assert_equal(Encoding::ASCII_8BIT, CGI.unescape("%C0%3C%3C".dup.force_encoding("ASCII-8BIT")).encoding)
- assert_equal(Encoding::UTF_8, CGI.unescape("%C0%3C%3C".dup.force_encoding("UTF-8")).encoding)
- end
-
- def test_cgi_unescape_accept_charset
- return unless defined?(::Encoding)
-
- assert_raise(TypeError) {CGI.unescape('', nil)}
- assert_separately(%w[-rcgi/util], "#{<<-"begin;"}\n#{<<-"end;"}")
- begin;
- assert_equal("", CGI.unescape(''))
- end;
- end
-
- def test_cgi_escapeURIComponent
- assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escapeURIComponent(@str1))
- assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI.escapeURIComponent(@str1).ascii_only?) if defined?(::Encoding)
- end
-
- def test_cgi_escape_uri_component
- assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escape_uri_component(@str1))
- end
-
- def test_cgi_escapeURIComponent_with_unreserved_characters
- assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
- CGI.escapeURIComponent("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"),
- "should not encode any unreserved characters, as per RFC3986 Section 2.3")
- end
-
- def test_cgi_escapeURIComponent_with_invalid_byte_sequence
- assert_equal('%C0%3C%3C', CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("UTF-8")))
- end
-
- def test_cgi_escapeURIComponent_preserve_encoding
- assert_equal(Encoding::US_ASCII, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("US-ASCII")).encoding)
- assert_equal(Encoding::ASCII_8BIT, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("ASCII-8BIT")).encoding)
- assert_equal(Encoding::UTF_8, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("UTF-8")).encoding)
- end
-
- def test_cgi_unescapeURIComponent
- str = CGI.unescapeURIComponent('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
- assert_equal(@str1, str)
- return unless defined?(::Encoding)
-
- assert_equal("foo+bar", CGI.unescapeURIComponent("foo+bar"))
-
- assert_equal(@str1.encoding, str.encoding)
- assert_equal("\u{30E1 30E2 30EA 691C 7D22}", CGI.unescapeURIComponent("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2"))
- end
-
- def test_cgi_unescape_uri_component
- str = CGI.unescape_uri_component('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
- assert_equal(@str1, str)
- end
-
- def test_cgi_unescapeURIComponent_preserve_encoding
- assert_equal(Encoding::US_ASCII, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("US-ASCII")).encoding)
- assert_equal(Encoding::ASCII_8BIT, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("ASCII-8BIT")).encoding)
- assert_equal(Encoding::UTF_8, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("UTF-8")).encoding)
- end
-
- def test_cgi_unescapeURIComponent_accept_charset
- return unless defined?(::Encoding)
-
- assert_raise(TypeError) {CGI.unescapeURIComponent('', nil)}
- assert_separately(%w[-rcgi/util], "#{<<-"begin;"}\n#{<<-"end;"}")
- begin;
- assert_equal("", CGI.unescapeURIComponent(''))
- end;
- end
-
- def test_cgi_pretty
- assert_equal("<HTML>\n <BODY>\n </BODY>\n</HTML>\n",CGI.pretty("<HTML><BODY></BODY></HTML>"))
- assert_equal("<HTML>\n\t<BODY>\n\t</BODY>\n</HTML>\n",CGI.pretty("<HTML><BODY></BODY></HTML>","\t"))
- end
-
- def test_cgi_escapeHTML
- assert_equal("&#39;&amp;&quot;&gt;&lt;", CGI.escapeHTML("'&\"><"))
- end
-
- def test_cgi_escape_html_duplicated
- orig = "Ruby".dup.force_encoding("US-ASCII")
- str = CGI.escapeHTML(orig)
- assert_equal(orig, str)
- assert_not_same(orig, str)
- end
-
- def assert_cgi_escape_html_preserve_encoding(str, encoding)
- assert_equal(encoding, CGI.escapeHTML(str.dup.force_encoding(encoding)).encoding)
- end
-
- def test_cgi_escape_html_preserve_encoding
- Encoding.list do |enc|
- assert_cgi_escape_html_preserve_encoding("'&\"><", enc)
- assert_cgi_escape_html_preserve_encoding("Ruby", enc)
- end
- end
-
- def test_cgi_escape_html_dont_freeze
- assert_not_predicate CGI.escapeHTML("'&\"><".dup), :frozen?
- assert_not_predicate CGI.escapeHTML("'&\"><".freeze), :frozen?
- assert_not_predicate CGI.escapeHTML("Ruby".dup), :frozen?
- assert_not_predicate CGI.escapeHTML("Ruby".freeze), :frozen?
- end
-
- def test_cgi_escape_html_large
- return if RUBY_ENGINE == 'jruby'
- ulong_max, size_max = RbConfig::LIMITS.values_at("ULONG_MAX", "SIZE_MAX")
- return unless ulong_max < size_max # Platforms not concerned
-
- size = (ulong_max / 6 + 1)
- begin
- str = '"' * size
- escaped = CGI.escapeHTML(str)
- rescue NoMemoryError
- omit "Not enough memory"
- rescue => e
- end
- assert_raise_with_message(ArgumentError, /overflow/, ->{"length = #{escaped.length}"}) do
- raise e if e
- end
- end
-
- def test_cgi_unescapeHTML
- assert_equal("'&\"><", CGI.unescapeHTML("&#39;&amp;&quot;&gt;&lt;"))
- end
-
- def test_cgi_unescapeHTML_invalid
- assert_equal('&<&amp>&quot&abcdefghijklmn', CGI.unescapeHTML('&&lt;&amp&gt;&quot&abcdefghijklmn'))
- end
-
- module UnescapeHTMLTests
- def test_cgi_unescapeHTML_following_known_first_letter
- assert_equal('&a>&q>&l>&g>', CGI.unescapeHTML('&a&gt;&q&gt;&l&gt;&g&gt;'))
- end
-
- def test_cgi_unescapeHTML_following_number_sign
- assert_equal('&#>&#x>', CGI.unescapeHTML('&#&gt;&#x&gt;'))
- end
-
- def test_cgi_unescapeHTML_following_invalid_numeric
- assert_equal('&#1114112>&#x110000>', CGI.unescapeHTML('&#1114112&gt;&#x110000&gt;'))
- end
- end
-
- include UnescapeHTMLTests
-
- Encoding.list.each do |enc|
- begin
- escaped = "&#39;&amp;&quot;&gt;&lt;".encode(enc)
- unescaped = "'&\"><".encode(enc)
- rescue Encoding::ConverterNotFoundError
- next
- else
- define_method("test_cgi_escapeHTML:#{enc.name}") do
- assert_equal(escaped, CGI.escapeHTML(unescaped))
- end
- define_method("test_cgi_unescapeHTML:#{enc.name}") do
- assert_equal(unescaped, CGI.unescapeHTML(escaped))
- end
- end
- end
-
- Encoding.list.each do |enc|
- next unless enc.ascii_compatible?
- begin
- escaped = "%25+%2B"
- unescaped = "% +".encode(enc)
- rescue Encoding::ConverterNotFoundError
- next
- else
- define_method("test_cgi_escape:#{enc.name}") do
- assert_equal(escaped, CGI.escape(unescaped))
- end
- define_method("test_cgi_unescape:#{enc.name}") do
- assert_equal(unescaped, CGI.unescape(escaped, enc))
- end
- end
- end
-
- def test_cgi_unescapeHTML_uppercasecharacter
- assert_equal("\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86", CGI.unescapeHTML("&#x3042;&#x3044;&#X3046;"))
- end
-
- def test_cgi_include_escape
- assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', escape(@str1))
- end
-
- def test_cgi_include_escapeHTML
- assert_equal("&#39;&amp;&quot;&gt;&lt;", escapeHTML("'&\"><"))
- end
-
- def test_cgi_include_h
- assert_equal("&#39;&amp;&quot;&gt;&lt;", h("'&\"><"))
- end
-
- def test_cgi_include_unescape
- str = unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93')
- assert_equal(@str1, str)
- return unless defined?(::Encoding)
-
- assert_equal(@str1.encoding, str.encoding)
- assert_equal("\u{30E1 30E2 30EA 691C 7D22}", unescape("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2"))
- end
-
- def test_cgi_include_unescapeHTML
- assert_equal("'&\"><", unescapeHTML("&#39;&amp;&quot;&gt;&lt;"))
- end
-
- def test_cgi_escapeElement
- assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<BR><A HREF="url"></A>', "A", "IMG"))
- assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"]))
- assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', "A", "IMG"))
- assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', ["A", "IMG"]))
-
- assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', "A", "IMG"))
- assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', ["A", "IMG"]))
- assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', "A", "IMG"))
- assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', ["A", "IMG"]))
-
- assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', "A", "IMG"))
- assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', ["A", "IMG"]))
- end
-
-
- def test_cgi_unescapeElement
- assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG"))
- assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
- assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG"))
- assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
-
- assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
- assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
- assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
- assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
-
- assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), "A", "IMG"))
- assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), ["A", "IMG"]))
- assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), "A", "IMG"))
- assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), ["A", "IMG"]))
- end
-end
-
-class CGIUtilPureRubyTest < Test::Unit::TestCase
- def setup
- CGI::Escape.module_eval do
- alias _escapeHTML escapeHTML
- remove_method :escapeHTML
- alias _unescapeHTML unescapeHTML
- remove_method :unescapeHTML
- end if defined?(CGI::Escape)
- end
-
- def teardown
- CGI::Escape.module_eval do
- alias escapeHTML _escapeHTML
- remove_method :_escapeHTML
- alias unescapeHTML _unescapeHTML
- remove_method :_unescapeHTML
- end if defined?(CGI::Escape)
- end
-
- include CGIUtilTest::UnescapeHTMLTests
-
- def test_cgi_escapeHTML_with_invalid_byte_sequence
- assert_equal("&lt;\xA4??&gt;", CGI.escapeHTML(%[<\xA4??>]))
- end
-
- def test_cgi_unescapeHTML_with_invalid_byte_sequence
- input = "\xFF&"
- assert_equal(input, CGI.unescapeHTML(input))
- end
-end
diff --git a/test/cgi/testdata/file1.html b/test/cgi/testdata/file1.html
deleted file mode 100644
index 2ceaf6bc39..0000000000
--- a/test/cgi/testdata/file1.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>ムスカ大佐のひとりごと</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF8">
- </head>
- <body>
- <p>バカどもにはちょうどいい目くらましだ。</p>
- </body>
-</html>
diff --git a/test/cgi/testdata/large.png b/test/cgi/testdata/large.png
deleted file mode 100644
index d716396fa3..0000000000
--- a/test/cgi/testdata/large.png
+++ /dev/null
Binary files differ
diff --git a/test/cgi/testdata/small.png b/test/cgi/testdata/small.png
deleted file mode 100644
index 753d58e3cb..0000000000
--- a/test/cgi/testdata/small.png
+++ /dev/null
Binary files differ
diff --git a/test/coverage/test_coverage.rb b/test/coverage/test_coverage.rb
index 9db1f8f253..adcd4a946c 100644
--- a/test/coverage/test_coverage.rb
+++ b/test/coverage/test_coverage.rb
@@ -82,6 +82,70 @@ class TestCoverage < Test::Unit::TestCase
}
end
+ def test_coverage_snapshot_iseq_compile
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ File.open("test.rb", "w") do |f|
+ f.puts <<-EOS
+ def coverage_test_snapshot
+ :ok
+ end
+ EOS
+ end
+
+ assert_in_out_err(ARGV, <<-"end;", ["[1, 0, nil]", "[1, 1, nil]", "[1, 1, nil]"], [])
+ class RubyVM::InstructionSequence
+ def self.load_iseq(path)
+ compile(File.read(path), path, path)
+ end
+ end
+
+ Coverage.start
+ tmp = Dir.pwd
+ require tmp + "/test.rb"
+ cov = Coverage.peek_result[tmp + "/test.rb"]
+ coverage_test_snapshot
+ cov2 = Coverage.peek_result[tmp + "/test.rb"]
+ p cov
+ p cov2
+ p Coverage.result[tmp + "/test.rb"]
+ end;
+ }
+ }
+ end
+
+ def test_coverage_snapshot_iseq_compile_file
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ File.open("test.rb", "w") do |f|
+ f.puts <<-EOS
+ def coverage_test_snapshot
+ :ok
+ end
+ EOS
+ end
+
+ assert_in_out_err(ARGV, <<-"end;", ["[1, 0, nil]", "[1, 1, nil]", "[1, 1, nil]"], [])
+ class RubyVM::InstructionSequence
+ def self.load_iseq(path)
+ compile_file(path)
+ end
+ end
+
+ Coverage.start
+ tmp = Dir.pwd
+ require tmp + "/test.rb"
+ cov = Coverage.peek_result[tmp + "/test.rb"]
+ coverage_test_snapshot
+ cov2 = Coverage.peek_result[tmp + "/test.rb"]
+ p cov
+ p cov2
+ p Coverage.result[tmp + "/test.rb"]
+ end;
+ }
+ }
+ end
+
def test_restarting_coverage
Dir.mktmpdir {|tmp|
Dir.chdir(tmp) {
@@ -192,6 +256,23 @@ class TestCoverage < Test::Unit::TestCase
end;
end
+ def test_eval_negative_lineno
+ assert_in_out_err(ARGV, <<-"end;", ["[1, 1, 1]"], [])
+ Coverage.start(eval: true, lines: true)
+
+ eval(<<-RUBY, TOPLEVEL_BINDING, "test.rb", -2)
+ p # -2 # Not subject to measurement
+ p # -1 # Not subject to measurement
+ p # 0 # Not subject to measurement
+ p # 1 # Subject to measurement
+ p # 2 # Subject to measurement
+ p # 3 # Subject to measurement
+ RUBY
+
+ p Coverage.result["test.rb"][:lines]
+ end;
+ end
+
def test_coverage_supported
assert Coverage.supported?(:lines)
assert Coverage.supported?(:oneshot_lines)
diff --git a/test/date/test_date.rb b/test/date/test_date.rb
index 3f9c893efa..7e37fc94d2 100644
--- a/test/date/test_date.rb
+++ b/test/date/test_date.rb
@@ -135,6 +135,10 @@ class TestDate < Test::Unit::TestCase
assert_equal(9, h[DateTime.new(1999,5,25)])
h = {}
+ h[Date.new(3171505571716611468830131104691,2,19)] = 0
+ assert_equal(true, h.key?(Date.new(3171505571716611468830131104691,2,19)))
+
+ h = {}
h[DateTime.new(1999,5,23)] = 0
h[DateTime.new(1999,5,24)] = 1
h[DateTime.new(1999,5,25)] = 2
diff --git a/test/date/test_date_conv.rb b/test/date/test_date_conv.rb
index 772fbee9a4..8d81084435 100644
--- a/test/date/test_date_conv.rb
+++ b/test/date/test_date_conv.rb
@@ -82,21 +82,17 @@ class TestDateConv < Test::Unit::TestCase
assert_equal([1582, 10, 13, 1, 2, 3, 456789],
[t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec])
- if Time.allocate.respond_to?(:nsec)
- d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789123.to_r/86400000000000
- t = d.to_time.utc
- assert_equal([2004, 9, 19, 1, 2, 3, 456789123],
- [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.nsec])
- end
+ d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789123.to_r/86400000000000
+ t = d.to_time.utc
+ assert_equal([2004, 9, 19, 1, 2, 3, 456789123],
+ [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.nsec])
# TruffleRuby does not support more than nanoseconds
unless RUBY_ENGINE == 'truffleruby'
- if Time.allocate.respond_to?(:subsec)
- d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789123456789123.to_r/86400000000000000000000
- t = d.to_time.utc
- assert_equal([2004, 9, 19, 1, 2, 3, Rational(456789123456789123,1000000000000000000)],
- [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.subsec])
- end
+ d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789123456789123.to_r/86400000000000000000000
+ t = d.to_time.utc
+ assert_equal([2004, 9, 19, 1, 2, 3, Rational(456789123456789123,1000000000000000000)],
+ [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.subsec])
end
end
diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb
index cc29771cf8..8308f258d5 100644
--- a/test/date/test_date_parse.rb
+++ b/test/date/test_date_parse.rb
@@ -544,6 +544,8 @@ class TestDateParse < Test::Unit::TestCase
h = Date._parse('')
assert_equal({}, h)
+
+ assert_raise(TypeError) {Date._parse(nil)}
end
def test_parse
@@ -589,13 +591,7 @@ class TestDateParse < Test::Unit::TestCase
end
def test__parse_too_long_year
- # Math.log10 does not support so big numbers like 10^100_000 on TruffleRuby
- unless RUBY_ENGINE == 'truffleruby'
- str = "Jan 1" + "0" * 100_000
- h = EnvUtil.timeout(3) {Date._parse(str, limit: 100_010)}
- assert_equal(100_000, Math.log10(h[:year]))
- assert_equal(1, h[:mon])
- end
+ omit 'transient' if RUBY_ENGINE == 'truffleruby'
str = "Jan - 1" + "0" * 100_000
h = EnvUtil.timeout(3) {Date._parse(str, limit: 100_010)}
@@ -1304,4 +1300,20 @@ class TestDateParse < Test::Unit::TestCase
assert_raise(ArgumentError) { Date._parse("Jan " + "9" * 1000000) }
end
+
+ def test_string_argument
+ s = '2001-02-03T04:05:06Z'
+ obj = Class.new(Struct.new(:to_str, :count)) do
+ def to_str
+ self.count +=1
+ super
+ end
+ end.new(s, 0)
+
+ all_assertions_foreach(nil, :_parse, :_iso8601, :_rfc3339, :_xmlschema) do |m|
+ obj.count = 0
+ assert_not_equal({}, Date.__send__(m, obj))
+ assert_equal(1, obj.count)
+ end
+ end
end
diff --git a/test/date/test_date_ractor.rb b/test/date/test_date_ractor.rb
index 7ec953d87a..91ea38bb93 100644
--- a/test/date/test_date_ractor.rb
+++ b/test/date/test_date_ractor.rb
@@ -8,7 +8,7 @@ class TestDateParseRactor < Test::Unit::TestCase
share = #{share}
d = Date.parse('Aug 23:55')
Ractor.make_shareable(d) if share
- d2, d3 = Ractor.new(d) { |d| [d, Date.parse(d.to_s)] }.take
+ d2, d3 = Ractor.new(d) { |d| [d, Date.parse(d.to_s)] }.value
if share
assert_same d, d2
else
diff --git a/test/date/test_date_strptime.rb b/test/date/test_date_strptime.rb
index 4efe1a47d0..6aa7db292d 100644
--- a/test/date/test_date_strptime.rb
+++ b/test/date/test_date_strptime.rb
@@ -517,7 +517,20 @@ class TestDateStrptime < Test::Unit::TestCase
d = DateTime.strptime('9000 +0200', '%Q %z')
assert_equal([1970, 1, 1, 2, 0, 9], [d.year, d.mon, d.mday, d.hour, d.min, d.sec])
assert_equal(Rational(2, 24), d.offset)
-
end
+ def test_format_modified
+ str = " " * 100
+ fmt = Struct.new(:str) {
+ def to_str
+ str << "2026-06-01" << " "*100
+ " %F "
+ end
+ }.new(str)
+ d = Date._strptime(str, fmt)
+ assert_not_nil(d)
+ assert_equal(2026, d[:year])
+ assert_equal(6, d[:mon])
+ assert_equal(1, d[:mday])
+ end
end
diff --git a/test/date/test_switch_hitter.rb b/test/date/test_switch_hitter.rb
index bdf299e030..cc75782537 100644
--- a/test/date/test_switch_hitter.rb
+++ b/test/date/test_switch_hitter.rb
@@ -97,6 +97,11 @@ class TestSH < Test::Unit::TestCase
[d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset])
end
+ def test_ajd
+ assert_equal(Date.civil(2008, 1, 16).ajd, 4908963r/2)
+ assert_equal(Date.civil(-11082381539297990, 2, 19).ajd, -8095679714453739481r/2)
+ end
+
def test_ordinal
d = Date.ordinal
assert_equal([-4712, 1], [d.year, d.yday])
diff --git a/test/did_you_mean/spell_checking/test_method_name_check.rb b/test/did_you_mean/spell_checking/test_method_name_check.rb
index 4daaf7cec7..2ae5fa7d03 100644
--- a/test/did_you_mean/spell_checking/test_method_name_check.rb
+++ b/test/did_you_mean/spell_checking/test_method_name_check.rb
@@ -98,6 +98,8 @@ class MethodNameCheckTest < Test::Unit::TestCase
end
def test_does_not_append_suggestions_twice
+ omit "This test is not working with JRuby" if RUBY_ENGINE == "jruby"
+
error = assert_raise NoMethodError do
begin
@user.firstname
@@ -110,6 +112,8 @@ class MethodNameCheckTest < Test::Unit::TestCase
end
def test_does_not_append_suggestions_three_times
+ omit "This test is not working with JRuby" if RUBY_ENGINE == "jruby"
+
error = assert_raise NoMethodError do
begin
@user.raise_no_method_error
diff --git a/test/did_you_mean/test_ractor_compatibility.rb b/test/did_you_mean/test_ractor_compatibility.rb
index 7385f10612..3166d0b6c5 100644
--- a/test/did_you_mean/test_ractor_compatibility.rb
+++ b/test/did_you_mean/test_ractor_compatibility.rb
@@ -14,7 +14,7 @@ class RactorCompatibilityTest < Test::Unit::TestCase
e.corrections # It is important to call the #corrections method within Ractor.
e
end
- }.take
+ }.value
assert_correction "Book", error.corrections
CODE
@@ -32,7 +32,7 @@ class RactorCompatibilityTest < Test::Unit::TestCase
e.corrections # It is important to call the #corrections method within Ractor.
e
end
- }.take
+ }.value
assert_correction ":bar", error.corrections
assert_match "Did you mean? :bar", get_message(error)
@@ -49,7 +49,7 @@ class RactorCompatibilityTest < Test::Unit::TestCase
e.corrections # It is important to call the #corrections method within Ractor.
e
end
- }.take
+ }.value
assert_correction :to_s, error.corrections
assert_match "Did you mean? to_s", get_message(error)
@@ -71,7 +71,7 @@ class RactorCompatibilityTest < Test::Unit::TestCase
e.corrections # It is important to call the #corrections method within Ractor.
e
end
- }.take
+ }.value
assert_correction ":foo", error.corrections
assert_match "Did you mean? :foo", get_message(error)
@@ -90,7 +90,7 @@ class RactorCompatibilityTest < Test::Unit::TestCase
e.corrections # It is important to call the #corrections method within Ractor.
e
end
- }.take
+ }.value
assert_not_match(/Did you mean\?/, error.message)
CODE
@@ -108,7 +108,7 @@ class RactorCompatibilityTest < Test::Unit::TestCase
e.corrections # It is important to call the #corrections method within Ractor.
e
end
- }.take
+ }.value
assert_correction :in_ractor, error.corrections
assert_match "Did you mean? in_ractor", get_message(error)
diff --git a/test/digest/test_ractor.rb b/test/digest/test_ractor.rb
index b34a3653b4..d7b03eaeba 100644
--- a/test/digest/test_ractor.rb
+++ b/test/digest/test_ractor.rb
@@ -15,6 +15,10 @@ module TestDigestRactor
def test_s_hexdigest
assert_in_out_err([], <<-"end;", ["true", "true"], [])
+ class Ractor
+ alias value take
+ end unless Ractor.method_defined? :value # compat with Ruby 3.4 and olders
+
$VERBOSE = nil
require "digest"
require "#{self.class::LIB}"
@@ -26,7 +30,7 @@ module TestDigestRactor
[r, hexdigest]
end
rs.each do |r, hexdigest|
- puts r.take == hexdigest
+ puts r.value == hexdigest
end
end;
end
diff --git a/test/dtrace/helper.rb b/test/dtrace/helper.rb
index 7fa16965f1..9e8c7ecd52 100644
--- a/test/dtrace/helper.rb
+++ b/test/dtrace/helper.rb
@@ -65,11 +65,7 @@ module DTrace
class TestCase < Test::Unit::TestCase
INCLUDE = File.expand_path('..', File.dirname(__FILE__))
- case RUBY_PLATFORM
- when /solaris/i
- # increase bufsize to 8m (default 4m on Solaris)
- DTRACE_CMD = %w[dtrace -b 8m]
- when /darwin/i
+ if RUBY_PLATFORM =~ /darwin/i
READ_PROBES = proc do |cmd|
lines = nil
PTY.spawn(*cmd) do |io, _, pid|
diff --git a/test/erb/test_erb.rb b/test/erb/test_erb.rb
index 555345a140..b2eaa4e5c4 100644
--- a/test/erb/test_erb.rb
+++ b/test/erb/test_erb.rb
@@ -24,29 +24,6 @@ class TestERB < Test::Unit::TestCase
assert_match(/\Atest filename:1\b/, e.backtrace[0])
end
- # [deprecated] This will be removed later
- def test_without_filename_with_safe_level
- erb = EnvUtil.suppress_warning do
- ERB.new("<% raise ::TestERB::MyError %>", 1)
- end
- e = assert_raise(MyError) {
- erb.result
- }
- assert_match(/\A\(erb\):1\b/, e.backtrace[0])
- end
-
- # [deprecated] This will be removed later
- def test_with_filename_and_safe_level
- erb = EnvUtil.suppress_warning do
- ERB.new("<% raise ::TestERB::MyError %>", 1)
- end
- erb.filename = "test filename"
- e = assert_raise(MyError) {
- erb.result
- }
- assert_match(/\Atest filename:1\b/, e.backtrace[0])
- end
-
def test_with_filename_lineno
erb = ERB.new("<% raise ::TestERB::MyError %>")
erb.filename = "test filename"
@@ -77,6 +54,9 @@ class TestERB < Test::Unit::TestCase
assert_equal("", ERB::Util.html_escape(nil))
assert_equal("123", ERB::Util.html_escape(123))
+
+ assert_equal(65536+5, ERB::Util.html_escape("x"*65536 + "&").size)
+ assert_equal(65536+5, ERB::Util.html_escape("&" + "x"*65536).size)
end
def test_html_escape_to_s
@@ -114,25 +94,16 @@ class TestERBCore < Test::Unit::TestCase
end
def test_core
- # [deprecated] Fix initializer later
- EnvUtil.suppress_warning do
- _test_core(nil)
- _test_core(0)
- _test_core(1)
- end
- end
-
- def _test_core(safe)
erb = @erb.new("hello")
assert_equal("hello", erb.result)
- erb = @erb.new("hello", safe, 0)
+ erb = @erb.new("hello", trim_mode: 0)
assert_equal("hello", erb.result)
- erb = @erb.new("hello", safe, 1)
+ erb = @erb.new("hello", trim_mode: 1)
assert_equal("hello", erb.result)
- erb = @erb.new("hello", safe, 2)
+ erb = @erb.new("hello", trim_mode: 2)
assert_equal("hello", erb.result)
src = <<EOS
@@ -160,9 +131,9 @@ EOS
EOS
erb = @erb.new(src)
assert_equal(ans, erb.result)
- erb = @erb.new(src, safe, 0)
+ erb = @erb.new(src, trim_mode: 0)
assert_equal(ans, erb.result)
- erb = @erb.new(src, safe, '')
+ erb = EnvUtil.suppress_warning { @erb.new(src, trim_mode: '') }
assert_equal(ans, erb.result)
ans = <<EOS
@@ -173,9 +144,9 @@ EOS
* 1% n=0
* 2
EOS
- erb = @erb.new(src, safe, 1)
+ erb = @erb.new(src, trim_mode: 1)
assert_equal(ans.chomp, erb.result)
- erb = @erb.new(src, safe, '>')
+ erb = @erb.new(src, trim_mode: '>')
assert_equal(ans.chomp, erb.result)
ans = <<EOS
@@ -189,9 +160,9 @@ EOS
* 2
EOS
- erb = @erb.new(src, safe, 2)
+ erb = @erb.new(src, trim_mode: 2)
assert_equal(ans, erb.result)
- erb = @erb.new(src, safe, '<>')
+ erb = @erb.new(src, trim_mode: '<>')
assert_equal(ans, erb.result)
ans = <<EOS
@@ -205,7 +176,7 @@ EOS
* 0
EOS
- erb = @erb.new(src, safe, '%')
+ erb = @erb.new(src, trim_mode: '%')
assert_equal(ans, erb.result)
ans = <<EOS
@@ -213,7 +184,7 @@ EOS
= hello
* 0* 0* 0
EOS
- erb = @erb.new(src, safe, '%>')
+ erb = @erb.new(src, trim_mode: '%>')
assert_equal(ans.chomp, erb.result)
ans = <<EOS
@@ -223,7 +194,7 @@ EOS
* 0
* 0
EOS
- erb = @erb.new(src, safe, '%<>')
+ erb = @erb.new(src, trim_mode: '%<>')
assert_equal(ans, erb.result)
end
@@ -627,10 +598,10 @@ EOS
def test_frozen_string_literal
bug12031 = '[ruby-core:73561] [Bug #12031]'
e = @erb.new("<%#encoding: us-ascii%>a")
- e.src.sub!(/\A#(?:-\*-)?(.*)(?:-\*-)?/) {
+ src = e.src.sub(/\A#(?:-\*-)?(.*)(?:-\*-)?/) {
'# -*- \1; frozen-string-literal: true -*-'
}
- assert_equal("a", e.result, bug12031)
+ assert_equal("a", eval(src), bug12031)
%w(false true).each do |flag|
erb = @erb.new("<%#frozen-string-literal: #{flag}%><%=''.frozen?%>")
@@ -679,27 +650,6 @@ EOS
end
end
- # [deprecated] These interfaces will be removed later
- def test_deprecated_interface_warnings
- [nil, 0, 1, 2].each do |safe|
- assert_warn(/2nd argument of ERB.new is deprecated/) do
- ERB.new('', safe)
- end
- end
-
- [nil, '', '%', '%<>'].each do |trim|
- assert_warn(/3rd argument of ERB.new is deprecated/) do
- ERB.new('', nil, trim)
- end
- end
-
- [nil, '_erbout', '_hamlout'].each do |eoutvar|
- assert_warn(/4th argument of ERB.new is deprecated/) do
- ERB.new('', nil, nil, eoutvar)
- end
- end
- end
-
def test_prohibited_marshal_dump
erb = ERB.new("")
assert_raise(TypeError) {Marshal.dump(erb)}
@@ -714,6 +664,33 @@ EOS
assert_raise(ArgumentError) {erb.result}
end
+ def test_prohibited_marshal_load_def_method
+ erb = ERB.allocate
+ erb.instance_variable_set(:@src, "")
+ erb.instance_variable_set(:@lineno, 1)
+ erb.instance_variable_set(:@_init, true)
+ erb = Marshal.load(Marshal.dump(erb))
+ assert_raise(ArgumentError) {erb.def_method(Class.new, 'render')}
+ end
+
+ def test_prohibited_marshal_load_def_module
+ erb = ERB.allocate
+ erb.instance_variable_set(:@src, "")
+ erb.instance_variable_set(:@lineno, 1)
+ erb.instance_variable_set(:@_init, true)
+ erb = Marshal.load(Marshal.dump(erb))
+ assert_raise(ArgumentError) {erb.def_module}
+ end
+
+ def test_prohibited_marshal_load_def_class
+ erb = ERB.allocate
+ erb.instance_variable_set(:@src, "")
+ erb.instance_variable_set(:@lineno, 1)
+ erb.instance_variable_set(:@_init, true)
+ erb = Marshal.load(Marshal.dump(erb))
+ assert_raise(ArgumentError) {erb.def_class}
+ end
+
def test_multi_line_comment_lineno
erb = ERB.new(<<~EOS)
<%= __LINE__ %>
diff --git a/test/error_highlight/test_error_highlight.rb b/test/error_highlight/test_error_highlight.rb
index 8aa5eb9c8d..5f664de502 100644
--- a/test/error_highlight/test_error_highlight.rb
+++ b/test/error_highlight/test_error_highlight.rb
@@ -44,14 +44,16 @@ class ErrorHighlightTest < Test::Unit::TestCase
def assert_error_message(klass, expected_msg, &blk)
omit unless klass < ErrorHighlight::CoreExt
err = assert_raise(klass, &blk)
- spot = ErrorHighlight.spot(err)
- if spot
- assert_kind_of(Integer, spot[:first_lineno])
- assert_kind_of(Integer, spot[:first_column])
- assert_kind_of(Integer, spot[:last_lineno])
- assert_kind_of(Integer, spot[:last_column])
- assert_kind_of(String, spot[:snippet])
- assert_kind_of(Array, spot[:script_lines])
+ unless klass == ArgumentError && err.message =~ /\A(?:wrong number of arguments|missing keyword[s]?|unknown keyword[s]?|no keywords accepted)\b/
+ spot = ErrorHighlight.spot(err)
+ if spot
+ assert_kind_of(Integer, spot[:first_lineno])
+ assert_kind_of(Integer, spot[:first_column])
+ assert_kind_of(Integer, spot[:last_lineno])
+ assert_kind_of(Integer, spot[:last_column])
+ assert_kind_of(String, spot[:snippet])
+ assert_kind_of(Array, spot[:script_lines])
+ end
end
assert_equal(preprocess(expected_msg).chomp, err.detailed_message(highlight: false).sub(/ \((?:NoMethod|Name)Error\)/, ""))
end
@@ -889,27 +891,13 @@ uninitialized constant ErrorHighlightTest::NotDefined
end
end
- if ErrorHighlight.const_get(:Spotter).const_get(:OPT_GETCONSTANT_PATH)
- def test_COLON2_5
- # Unfortunately, we cannot identify which `NotDefined` caused the NameError
- assert_error_message(NameError, <<~END) do
- uninitialized constant ErrorHighlightTest::NotDefined
- END
-
- ErrorHighlightTest::NotDefined::NotDefined
- end
- end
- else
- def test_COLON2_5
- assert_error_message(NameError, <<~END) do
+ def test_COLON2_5
+ # Unfortunately, we cannot identify which `NotDefined` caused the NameError
+ assert_error_message(NameError, <<~END) do
uninitialized constant ErrorHighlightTest::NotDefined
+ END
- ErrorHighlightTest::NotDefined::NotDefined
- ^^^^^^^^^^^^
- END
-
- ErrorHighlightTest::NotDefined::NotDefined
- end
+ ErrorHighlightTest::NotDefined::NotDefined
end
end
@@ -1097,10 +1085,11 @@ nil can't be coerced into Integer (TypeError)
end
end
+ OF_NIL_INTO_INTEGER = RUBY_VERSION < "4.1." ? "from nil to integer" : "of nil into Integer"
def test_args_CALL_2
v = []
assert_error_message(TypeError, <<~END) do
-no implicit conversion from nil to integer (TypeError)
+no implicit conversion #{OF_NIL_INTO_INTEGER} (TypeError)
v[nil]
^^^
@@ -1111,12 +1100,13 @@ no implicit conversion from nil to integer (TypeError)
end
def test_args_ATTRASGN_1
- v = []
- assert_error_message(ArgumentError, <<~END) do
-wrong number of arguments (given 1, expected 2..3) (ArgumentError)
+ v = method(:raise).to_proc
+ recv = NEW_MESSAGE_FORMAT ? "an instance of Proc" : v.inspect
+ assert_error_message(NoMethodError, <<~END) do
+undefined method `[]=' for #{ recv }
v [ ] = 1
- ^^^^^^
+ ^^^^^
END
v [ ] = 1
@@ -1126,7 +1116,7 @@ wrong number of arguments (given 1, expected 2..3) (ArgumentError)
def test_args_ATTRASGN_2
v = []
assert_error_message(TypeError, <<~END) do
-no implicit conversion from nil to integer (TypeError)
+no implicit conversion #{OF_NIL_INTO_INTEGER} (TypeError)
v [nil] = 1
^^^^^^^^
@@ -1188,7 +1178,7 @@ no implicit conversion of Symbol into String (TypeError)
v = []
assert_error_message(TypeError, <<~END) do
-no implicit conversion from nil to integer (TypeError)
+no implicit conversion #{OF_NIL_INTO_INTEGER} (TypeError)
v [nil] += 42
^^^^^^^^^^
@@ -1199,16 +1189,16 @@ no implicit conversion from nil to integer (TypeError)
end
def test_args_OP_ASGN1_aref_2
- v = []
+ v = method(:raise).to_proc
assert_error_message(ArgumentError, <<~END) do
-wrong number of arguments (given 0, expected 1..2) (ArgumentError)
+ArgumentError (ArgumentError)
- v [ ] += 42
- ^^^^^^^^
+ v [ArgumentError] += 42
+ ^^^^^^^^^^^^^^^^^^^^
END
- v [ ] += 42
+ v [ArgumentError] += 42
end
end
@@ -1453,6 +1443,199 @@ undefined method `foo' for #{ NIL_RECV_MESSAGE }
end
end
+ begin
+ ->{}.call(1)
+ rescue ArgumentError => exc
+ MethodDefLocationSupported =
+ RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location) &&
+ RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(exc.backtrace_locations.first)
+ end
+
+ def process_callee_snippet(str)
+ return str if MethodDefLocationSupported
+
+ str.sub(/\n +\|.*\n +\^+\n\z/, "")
+ end
+
+ WRONG_NUMBER_OF_ARGUMENTS_LINENO = __LINE__ + 1
+ def wrong_number_of_arguments_test(x, y)
+ x + y
+ end
+
+ def test_wrong_number_of_arguments_for_method
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+wrong number of arguments (given 1, expected 2) (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | wrong_number_of_arguments_test(1)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ WRONG_NUMBER_OF_ARGUMENTS_LINENO }
+ | def wrong_number_of_arguments_test(x, y)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ END
+
+ wrong_number_of_arguments_test(1)
+ end
+ end
+
+ KEYWORD_TEST_LINENO = __LINE__ + 1
+ def keyword_test(kw1:, kw2:, kw3:)
+ kw1 + kw2 + kw3
+ end
+
+ def test_missing_keyword
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+missing keyword: :kw3 (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | keyword_test(kw1: 1, kw2: 2)
+ ^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ KEYWORD_TEST_LINENO }
+ | def keyword_test(kw1:, kw2:, kw3:)
+ ^^^^^^^^^^^^
+ END
+
+ keyword_test(kw1: 1, kw2: 2)
+ end
+ end
+
+ def test_missing_keywords # multiple missing keywords
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+missing keywords: :kw2, :kw3 (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | keyword_test(kw1: 1)
+ ^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ KEYWORD_TEST_LINENO }
+ | def keyword_test(kw1:, kw2:, kw3:)
+ ^^^^^^^^^^^^
+ END
+
+ keyword_test(kw1: 1)
+ end
+ end
+
+ def test_unknown_keyword
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+unknown keyword: :kw4 (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | keyword_test(kw1: 1, kw2: 2, kw3: 3, kw4: 4)
+ ^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ KEYWORD_TEST_LINENO }
+ | def keyword_test(kw1:, kw2:, kw3:)
+ ^^^^^^^^^^^^
+ END
+
+ keyword_test(kw1: 1, kw2: 2, kw3: 3, kw4: 4)
+ end
+ end
+
+ def test_unknown_keywords
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+unknown keywords: :kw4, :kw5 (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | keyword_test(kw1: 1, kw2: 2, kw3: 3, kw4: 4, kw5: 5)
+ ^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ KEYWORD_TEST_LINENO }
+ | def keyword_test(kw1:, kw2:, kw3:)
+ ^^^^^^^^^^^^
+ END
+
+ keyword_test(kw1: 1, kw2: 2, kw3: 3, kw4: 4, kw5: 5)
+ end
+ end
+
+ WRONG_NUBMER_OF_ARGUMENTS_TEST2_LINENO = __LINE__ + 1
+ def wrong_number_of_arguments_test2(
+ long_argument_name_x,
+ long_argument_name_y,
+ long_argument_name_z
+ )
+ long_argument_name_x + long_argument_name_y + long_argument_name_z
+ end
+
+ def test_wrong_number_of_arguments_for_method2
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+wrong number of arguments (given 1, expected 3) (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | wrong_number_of_arguments_test2(1)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ WRONG_NUBMER_OF_ARGUMENTS_TEST2_LINENO }
+ | def wrong_number_of_arguments_test2(
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ END
+
+ wrong_number_of_arguments_test2(1)
+ end
+ end
+
+ def test_wrong_number_of_arguments_for_lambda_literal
+ v = -> {}
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+wrong number of arguments (given 1, expected 0) (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | v.call(1)
+ ^^^^^
+ callee: #{ __FILE__ }:#{ lineno - 1 }
+ | v = -> {}
+ ^^
+ END
+
+ v.call(1)
+ end
+ end
+
+ def test_wrong_number_of_arguments_for_lambda_method
+ v = lambda { }
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+wrong number of arguments (given 1, expected 0) (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | v.call(1)
+ ^^^^^
+ callee: #{ __FILE__ }:#{ lineno - 1 }
+ | v = lambda { }
+ ^
+ END
+
+ v.call(1)
+ end
+ end
+
+ DEFINE_METHOD_TEST_LINENO = __LINE__ + 1
+ define_method :define_method_test do |x, y|
+ x + y
+ end
+
+ def test_wrong_number_of_arguments_for_define_method
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+wrong number of arguments (given 1, expected 2) (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | define_method_test(1)
+ ^^^^^^^^^^^^^^^^^^
+ callee: #{ __FILE__ }:#{ DEFINE_METHOD_TEST_LINENO }
+ | define_method :define_method_test do |x, y|
+ ^^
+ END
+
+ define_method_test(1)
+ end
+ end
+
def test_spoofed_filename
Tempfile.create(["error_highlight_test", ".rb"], binmode: true) do |tmp|
tmp << "module Dummy\nend\n"
@@ -1521,6 +1704,54 @@ undefined method `foo' for #{ NIL_RECV_MESSAGE }
assert_equal expected_spot, actual_spot
end
+ module SingletonMethodWithSpacing
+ LINENO = __LINE__ + 1
+ def self . baz(x:)
+ x
+ end
+ end
+
+ def test_singleton_method_with_spacing_missing_keyword
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+missing keyword: :x (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | SingletonMethodWithSpacing.baz
+ ^^^^
+ callee: #{ __FILE__ }:#{ SingletonMethodWithSpacing::LINENO }
+ | def self . baz(x:)
+ ^^^^^
+ END
+
+ SingletonMethodWithSpacing.baz
+ end
+ end
+
+ module SingletonMethodMultipleKwargs
+ LINENO = __LINE__ + 1
+ def self.run(shop_id:, param1:)
+ shop_id + param1
+ end
+ end
+
+ def test_singleton_method_multiple_missing_keywords
+ lineno = __LINE__
+ assert_error_message(ArgumentError, process_callee_snippet(<<~END)) do
+missing keywords: :shop_id, :param1 (ArgumentError)
+
+ caller: #{ __FILE__ }:#{ lineno + 12 }
+ | SingletonMethodMultipleKwargs.run
+ ^^^^
+ callee: #{ __FILE__ }:#{ SingletonMethodMultipleKwargs::LINENO }
+ | def self.run(shop_id:, param1:)
+ ^^^^
+ END
+
+ SingletonMethodMultipleKwargs.run
+ end
+ end
+
private
def find_node_by_id(node, node_id)
diff --git a/test/etc/test_etc.rb b/test/etc/test_etc.rb
index feb05aa3c3..c2e3af6317 100644
--- a/test/etc/test_etc.rb
+++ b/test/etc/test_etc.rb
@@ -21,7 +21,7 @@ class TestEtc < Test::Unit::TestCase
assert_instance_of(String, s.shell)
assert_kind_of(Integer, s.change) if s.respond_to?(:change)
assert_kind_of(Integer, s.quota) if s.respond_to?(:quota)
- assert(s.age.is_a?(Integer) || s.age.is_a?(String)) if s.respond_to?(:age)
+ assert(s.age.is_a?(Integer) || s.age.is_a?(String), s.age) if s.respond_to?(:age)
assert_instance_of(String, s.uclass) if s.respond_to?(:uclass)
assert_instance_of(String, s.comment) if s.respond_to?(:comment)
assert_kind_of(Integer, s.expire) if s.respond_to?(:expire)
@@ -160,7 +160,7 @@ class TestEtc < Test::Unit::TestCase
end
IO.pipe {|r, w|
val = w.pathconf(Etc::PC_PIPE_BUF)
- assert(val.nil? || val.kind_of?(Integer))
+ assert_kind_of(Integer, val) if val
}
end if defined?(Etc::PC_PIPE_BUF)
@@ -198,7 +198,7 @@ class TestEtc < Test::Unit::TestCase
raise unless Integer === Etc.nprocessors
end
end
- end.each(&:take)
+ end.each(&:join)
RUBY
end
@@ -210,7 +210,7 @@ class TestEtc < Test::Unit::TestCase
rescue => e
e.class
end
- end.take
+ end.value
assert_equal Ractor::UnsafeError, r
RUBY
end
@@ -221,19 +221,19 @@ class TestEtc < Test::Unit::TestCase
Etc.endpwent
assert_ractor(<<~RUBY, require: 'etc')
- ractor = Ractor.new do
+ ractor = Ractor.new port = Ractor::Port.new do |port|
Etc.passwd do |s|
- Ractor.yield :sync
- Ractor.yield s.name
+ port << :sync
+ port << s.name
break :done
end
end
- ractor.take # => :sync
+ port.receive # => :sync
assert_raise RuntimeError, /parallel/ do
Etc.passwd {}
end
- name = ractor.take # => first name
- ractor.take # => :done
+ name = port.receive # => first name
+ ractor.join # => :done
name2 = Etc.passwd do |s|
break s.name
end
@@ -251,7 +251,7 @@ class TestEtc < Test::Unit::TestCase
raise unless Etc.getgrgid(Process.gid).gid == Process.gid
end
end
- end.each(&:take)
+ end.each(&:join)
RUBY
end
end
diff --git a/test/fiber/scheduler.rb b/test/fiber/scheduler.rb
index ac19bba7a2..8f1ce4376b 100644
--- a/test/fiber/scheduler.rb
+++ b/test/fiber/scheduler.rb
@@ -65,63 +65,79 @@ class Scheduler
end
end
- def run
- # $stderr.puts [__method__, Fiber.current].inspect
+ def run_once
+ readable = writable = nil
- while @readable.any? or @writable.any? or @waiting.any? or @blocking.any?
- # May only handle file descriptors up to 1024...
+ begin
readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], next_timeout)
+ rescue IOError
+ # Ignore - this can happen if the IO is closed while we are waiting.
+ end
- # puts "readable: #{readable}" if readable&.any?
- # puts "writable: #{writable}" if writable&.any?
+ # puts "readable: #{readable}" if readable&.any?
+ # puts "writable: #{writable}" if writable&.any?
- selected = {}
+ selected = {}
- readable&.each do |io|
- if fiber = @readable.delete(io)
- @writable.delete(io) if @writable[io] == fiber
- selected[fiber] = IO::READABLE
- elsif io == @urgent.first
- @urgent.first.read_nonblock(1024)
- end
+ readable&.each do |io|
+ if fiber = @readable.delete(io)
+ @writable.delete(io) if @writable[io] == fiber
+ selected[fiber] = IO::READABLE
+ elsif io == @urgent.first
+ @urgent.first.read_nonblock(1024)
end
+ end
- writable&.each do |io|
- if fiber = @writable.delete(io)
- @readable.delete(io) if @readable[io] == fiber
- selected[fiber] = selected.fetch(fiber, 0) | IO::WRITABLE
- end
+ writable&.each do |io|
+ if fiber = @writable.delete(io)
+ @readable.delete(io) if @readable[io] == fiber
+ selected[fiber] = selected.fetch(fiber, 0) | IO::WRITABLE
end
+ end
- selected.each do |fiber, events|
- fiber.transfer(events)
- end
+ selected.each do |fiber, events|
+ fiber.transfer(events)
+ end
+
+ if @waiting.any?
+ time = current_time
+ waiting, @waiting = @waiting, {}
- if @waiting.any?
- time = current_time
- waiting, @waiting = @waiting, {}
-
- waiting.each do |fiber, timeout|
- if fiber.alive?
- if timeout <= time
- fiber.transfer
- else
- @waiting[fiber] = timeout
- end
+ waiting.each do |fiber, timeout|
+ if fiber.alive?
+ if timeout <= time
+ fiber.transfer
+ else
+ @waiting[fiber] = timeout
end
end
end
+ end
- if @ready.any?
- ready = nil
+ if @ready.any?
+ ready = nil
- @lock.synchronize do
- ready, @ready = @ready, []
- end
+ @lock.synchronize do
+ ready, @ready = @ready, []
+ end
- ready.each do |fiber|
- fiber.transfer
- end
+ ready.each do |fiber|
+ fiber.transfer if fiber.alive?
+ end
+ end
+ end
+
+ def run
+ # $stderr.puts [__method__, Fiber.current].inspect
+
+ # Use Thread.handle_interrupt like Async::Scheduler does
+ # This defers signal processing, which is the root cause of the gRPC bug
+ # See: https://github.com/socketry/async/blob/main/lib/async/scheduler.rb
+ Thread.handle_interrupt(::SignalException => :never) do
+ while @readable.any? or @writable.any? or @waiting.any? or @blocking.any?
+ run_once
+
+ break if Thread.pending_interrupt?
end
end
end
@@ -239,6 +255,13 @@ class Scheduler
end.value
end
+ # This hook is invoked by `IO#close`. Using a separate IO object
+ # demonstrates that the close operation is asynchronous.
+ def io_close(descriptor)
+ Fiber.blocking{IO.for_fd(descriptor.to_i).close}
+ return true
+ end
+
# This hook is invoked by `Kernel#sleep` and `Thread::Mutex#sleep`.
def kernel_sleep(duration = nil)
# $stderr.puts [__method__, duration, Fiber.current].inspect
@@ -290,6 +313,30 @@ class Scheduler
io.write_nonblock('.')
end
+ class FiberInterrupt
+ def initialize(fiber, exception)
+ @fiber = fiber
+ @exception = exception
+ end
+
+ def alive?
+ @fiber.alive?
+ end
+
+ def transfer
+ @fiber.raise(@exception)
+ end
+ end
+
+ def fiber_interrupt(fiber, exception)
+ @lock.synchronize do
+ @ready << FiberInterrupt.new(fiber, exception)
+ end
+
+ io = @urgent.last
+ io.write_nonblock('.')
+ end
+
# This hook is invoked by `Fiber.schedule`. Strictly speaking, you should use
# it to create scheduled fibers, but it is not required in practice;
# `Fiber.new` is usually sufficient.
@@ -311,7 +358,7 @@ class Scheduler
end
def blocking_operation_wait(work)
- thread = Thread.new(&work)
+ thread = Thread.new{work.call}
thread.join
@@ -441,6 +488,33 @@ class IOBufferScheduler < Scheduler
end
end
+class IOScheduler < Scheduler
+ def operations
+ @operations ||= []
+ end
+
+ def io_write(io, buffer, length, offset)
+ descriptor = io.fileno
+ string = buffer.get_string
+
+ self.operations << [:io_write, descriptor, string]
+
+ Fiber.blocking do
+ buffer.write(io, 0, offset)
+ end
+ end
+end
+
+class IOErrorScheduler < Scheduler
+ def io_read(io, buffer, length, offset)
+ return -Errno::EBADF::Errno
+ end
+
+ def io_write(io, buffer, length, offset)
+ return -Errno::EINVAL::Errno
+ end
+end
+
# This scheduler has a broken implementation of `unblock`` in the sense that it
# raises an exception. This is used to test the behavior of the scheduler when
# unblock raises an exception.
diff --git a/test/fiber/test_io.rb b/test/fiber/test_io.rb
index 39e32c5987..eea06f97c8 100644
--- a/test/fiber/test_io.rb
+++ b/test/fiber/test_io.rb
@@ -9,7 +9,7 @@ class TestFiberIO < Test::Unit::TestCase
omit unless defined?(UNIXSocket)
i, o = UNIXSocket.pair
- if RUBY_PLATFORM=~/mswin|mingw/
+ if RUBY_PLATFORM =~ /mswin|mingw/
i.nonblock = true
o.nonblock = true
end
@@ -44,7 +44,7 @@ class TestFiberIO < Test::Unit::TestCase
16.times.map do
Thread.new do
i, o = UNIXSocket.pair
- if RUBY_PLATFORM=~/mswin|mingw/
+ if RUBY_PLATFORM =~ /mswin|mingw/
i.nonblock = true
o.nonblock = true
end
@@ -67,7 +67,7 @@ class TestFiberIO < Test::Unit::TestCase
def test_epipe_on_read
omit unless defined?(UNIXSocket)
- omit "nonblock=true isn't properly supported on Windows" if RUBY_PLATFORM=~/mswin|mingw/
+ omit "nonblock=true isn't properly supported on Windows" if RUBY_PLATFORM =~ /mswin|mingw/
i, o = UNIXSocket.pair
@@ -242,38 +242,37 @@ class TestFiberIO < Test::Unit::TestCase
# Windows has UNIXSocket, but only with VS 2019+
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
- i, o = Socket.pair(:UNIX, :STREAM)
- if RUBY_PLATFORM=~/mswin|mingw/
- i.nonblock = true
- o.nonblock = true
- end
+ Socket.pair(:UNIX, :STREAM) do |i, o|
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ i.nonblock = true
+ o.nonblock = true
+ end
- reading_thread = Thread.new do
- Thread.current.report_on_exception = false
- i.wait_readable
- end
+ reading_thread = Thread.new do
+ Thread.current.report_on_exception = false
+ i.wait_readable
+ end
- fs_thread = Thread.new do
- # Wait until the reading thread is blocked on read:
- Thread.pass until reading_thread.status == "sleep"
+ scheduler_thread = Thread.new do
+ # Wait until the reading thread is blocked on read:
+ Thread.pass until reading_thread.status == "sleep"
- scheduler = Scheduler.new
- Fiber.set_scheduler scheduler
- Fiber.schedule do
- i.close
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+ Fiber.schedule do
+ i.close
+ end
end
- end
- assert_raise(IOError) { reading_thread.join }
- refute_nil fs_thread.join(5), "expected thread to terminate within 5 seconds"
+ assert_raise(IOError) { reading_thread.join }
+ refute_nil scheduler_thread.join(5), "expected thread to terminate within 5 seconds"
- assert_predicate(i, :closed?)
- ensure
- fs_thread&.kill
- fs_thread&.join rescue nil
- reading_thread&.kill
- reading_thread&.join rescue nil
- i&.close
- o&.close
+ assert_predicate(i, :closed?)
+ ensure
+ scheduler_thread&.kill
+ scheduler_thread&.join rescue nil
+ reading_thread&.kill
+ reading_thread&.join rescue nil
+ end
end
end
diff --git a/test/fiber/test_io_close.rb b/test/fiber/test_io_close.rb
new file mode 100644
index 0000000000..742b40841d
--- /dev/null
+++ b/test/fiber/test_io_close.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+require 'test/unit'
+require_relative 'scheduler'
+
+class TestFiberIOClose < Test::Unit::TestCase
+ def with_socket_pair(&block)
+ omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
+
+ UNIXSocket.pair do |i, o|
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ i.nonblock = true
+ o.nonblock = true
+ end
+
+ yield i, o
+ end
+ end
+
+ def test_io_close_across_fibers
+ # omit "Interrupting a io_wait read is not supported!" if RUBY_PLATFORM =~ /mswin|mingw/
+
+ with_socket_pair do |i, o|
+ error = nil
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ i.read
+ rescue => error
+ # Ignore.
+ end
+
+ Fiber.schedule do
+ i.close
+ end
+ end
+
+ thread.join
+
+ assert_instance_of IOError, error
+ assert_match(/closed/, error.message)
+ end
+ end
+
+ def test_io_close_blocking_thread
+ omit "Interrupting a io_wait read is not supported!" if RUBY_PLATFORM =~ /mswin|mingw/
+
+ with_socket_pair do |i, o|
+ error = nil
+
+ reading_thread = Thread.new do
+ i.read
+ rescue => error
+ # Ignore.
+ end
+
+ Thread.pass until reading_thread.status == 'sleep'
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ i.close
+ end
+ end
+
+ thread.join
+ reading_thread.join
+
+ assert_instance_of IOError, error
+ assert_match(/closed/, error.message)
+ end
+ end
+
+ def test_io_close_blocking_fiber
+ # omit "Interrupting a io_wait read is not supported!" if RUBY_PLATFORM =~ /mswin|mingw/
+
+ with_socket_pair do |i, o|
+ error = nil
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ begin
+ i.read
+ rescue => error
+ # Ignore.
+ end
+ end
+ end
+
+ Thread.pass until thread.status == 'sleep'
+
+ i.close
+
+ thread.join
+
+ assert_instance_of IOError, error
+ assert_match(/closed/, error.message)
+ end
+ end
+end
diff --git a/test/fiber/test_ractor.rb b/test/fiber/test_ractor.rb
index 3c4ccbd8e5..7dd82eda62 100644
--- a/test/fiber/test_ractor.rb
+++ b/test/fiber/test_ractor.rb
@@ -17,7 +17,7 @@ class TestFiberCurrentRactor < Test::Unit::TestCase
Fiber.current.class
end.resume
end
- assert_equal(Fiber, r.take)
+ assert_equal(Fiber, r.value)
end;
end
end
diff --git a/test/fiber/test_scheduler.rb b/test/fiber/test_scheduler.rb
index 81d4581bea..d3696267f7 100644
--- a/test/fiber/test_scheduler.rb
+++ b/test/fiber/test_scheduler.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'test/unit'
+require 'securerandom'
+require 'fileutils'
require_relative 'scheduler'
class TestFiberScheduler < Test::Unit::TestCase
@@ -94,6 +96,9 @@ class TestFiberScheduler < Test::Unit::TestCase
def scheduler.kernel_sleep
end
+ def scheduler.fiber_interrupt(_fiber, _exception)
+ end
+
thread = Thread.new do
Fiber.set_scheduler scheduler
end
@@ -223,4 +228,159 @@ class TestFiberScheduler < Test::Unit::TestCase
thread.join
assert_kind_of RuntimeError, error
end
+
+ def test_post_fork_scheduler_reset
+ omit 'fork not supported' unless Process.respond_to?(:fork)
+
+ forked_scheduler_state = nil
+ thread = Thread.new do
+ r, w = IO.pipe
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ forked_pid = fork do
+ r.close
+ w << (Fiber.scheduler ? 'set' : 'reset')
+ w.close
+ end
+ w.close
+ forked_scheduler_state = r.read
+ Process.wait(forked_pid)
+ ensure
+ r.close rescue nil
+ w.close rescue nil
+ end
+ thread.join
+ assert_equal 'reset', forked_scheduler_state
+ ensure
+ thread.kill rescue nil
+ end
+
+ def test_post_fork_fiber_blocking
+ omit 'fork not supported' unless Process.respond_to?(:fork)
+
+ fiber_blocking_state = nil
+ thread = Thread.new do
+ r, w = IO.pipe
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ forked_pid = nil
+ Fiber.schedule do
+ forked_pid = fork do
+ r.close
+ w << (Fiber.current.blocking? ? 'blocking' : 'nonblocking')
+ w.close
+ end
+ end
+ w.close
+ fiber_blocking_state = r.read
+ Process.wait(forked_pid)
+ ensure
+ r.close rescue nil
+ w.close rescue nil
+ end
+ thread.join
+ assert_equal 'blocking', fiber_blocking_state
+ ensure
+ thread.kill rescue nil
+ end
+
+ def test_io_write_on_flush
+ begin
+ path = File.join(Dir.tmpdir, "ruby_test_io_write_on_flush_#{SecureRandom.hex}")
+ descriptor = nil
+ operations = nil
+
+ thread = Thread.new do
+ scheduler = IOScheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ File.open(path, 'w+') do |file|
+ descriptor = file.fileno
+ file << 'foo'
+ file.flush
+ file << 'bar'
+ end
+ end
+
+ operations = scheduler.operations
+ end
+
+ thread.join
+ assert_equal [
+ [:io_write, descriptor, 'foo'],
+ [:io_write, descriptor, 'bar']
+ ], operations
+
+ assert_equal 'foobar', IO.read(path)
+ ensure
+ thread.kill rescue nil
+ FileUtils.rm_f(path)
+ end
+ end
+
+ def test_io_read_error
+ path = File.join(Dir.tmpdir, "ruby_test_io_read_error_#{SecureRandom.hex}")
+ error = nil
+
+ thread = Thread.new do
+ scheduler = IOErrorScheduler.new
+ Fiber.set_scheduler scheduler
+ Fiber.schedule do
+ File.open(path, 'w+') { it.read }
+ rescue => error
+ # Ignore.
+ end
+ end
+
+ thread.join
+ assert_kind_of Errno::EBADF, error
+ ensure
+ thread.kill rescue nil
+ FileUtils.rm_f(path)
+ end
+
+ def test_io_write_error
+ path = File.join(Dir.tmpdir, "ruby_test_io_write_error_#{SecureRandom.hex}")
+ error = nil
+
+ thread = Thread.new do
+ scheduler = IOErrorScheduler.new
+ Fiber.set_scheduler scheduler
+ Fiber.schedule do
+ File.open(path, 'w+') { it.sync = true; it << 'foo' }
+ rescue => error
+ # Ignore.
+ end
+ end
+
+ thread.join
+ assert_kind_of Errno::EINVAL, error
+ ensure
+ thread.kill rescue nil
+ FileUtils.rm_f(path)
+ end
+
+ def test_io_write_flush_error
+ path = File.join(Dir.tmpdir, "ruby_test_io_write_flush_error_#{SecureRandom.hex}")
+ error = nil
+
+ thread = Thread.new do
+ scheduler = IOErrorScheduler.new
+ Fiber.set_scheduler scheduler
+ Fiber.schedule do
+ File.open(path, 'w+') { it << 'foo' }
+ rescue => error
+ # Ignore.
+ end
+ end
+
+ thread.join
+ assert_kind_of Errno::EINVAL, error
+ ensure
+ thread.kill rescue nil
+ FileUtils.rm_f(path)
+ end
end
diff --git a/test/fiber/test_sleep.rb b/test/fiber/test_sleep.rb
index a7e88c0367..187f59dbd4 100644
--- a/test/fiber/test_sleep.rb
+++ b/test/fiber/test_sleep.rb
@@ -35,13 +35,13 @@ class TestFiberSleep < Test::Unit::TestCase
scheduler = Scheduler.new
Fiber.set_scheduler scheduler
Fiber.schedule do
- seconds = sleep(2)
+ seconds = sleep(1.1)
end
end
thread.join
- assert_operator seconds, :>=, 2, "actual: %p" % seconds
+ assert_operator seconds, :>=, 1, "actual: %p" % seconds
end
def test_broken_sleep
diff --git a/test/fiber/test_thread.rb b/test/fiber/test_thread.rb
index 5e3cc6d0e1..4d2fbde9ed 100644
--- a/test/fiber/test_thread.rb
+++ b/test/fiber/test_thread.rb
@@ -90,6 +90,47 @@ class TestFiberThread < Test::Unit::TestCase
assert_equal :done, thread.value
end
+ def test_spurious_unblock_during_thread_join
+ ready = Thread::Queue.new
+
+ target_thread = Thread.new do
+ ready.pop
+ :success
+ end
+
+ Thread.pass until target_thread.status == "sleep"
+
+ result = nil
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ # Create a fiber that will join a long-running thread:
+ joining_fiber = Fiber.schedule do
+ result = target_thread.value
+ end
+
+ # Create another fiber that spuriously unblocks the joining fiber:
+ Fiber.schedule do
+ # This interrupts the join in joining_fiber:
+ scheduler.unblock(:spurious_wakeup, joining_fiber)
+
+ # This allows the unblock to be processed:
+ sleep(0)
+
+ # This allows the target thread to finish:
+ ready.push(:done)
+ end
+
+ scheduler.run
+ end
+
+ thread.join
+
+ assert_equal :success, result
+ end
+
def test_broken_unblock
thread = Thread.new do
Thread.current.report_on_exception = false
@@ -115,16 +156,20 @@ class TestFiberThread < Test::Unit::TestCase
end
def test_thread_join_hang
+ inner = nil
thread = Thread.new do
scheduler = SleepingUnblockScheduler.new
Fiber.set_scheduler scheduler
Fiber.schedule do
- Thread.new{sleep(0.01)}.value
+ inner = Thread.new{sleep(0.01)}
+ inner.value
end
end
thread.join
+ ensure
+ inner&.join
end
end
diff --git a/test/fileutils/test_fileutils.rb b/test/fileutils/test_fileutils.rb
index d2096a04cc..92308d9557 100644
--- a/test/fileutils/test_fileutils.rb
+++ b/test/fileutils/test_fileutils.rb
@@ -955,16 +955,27 @@ class TestFileUtils < Test::Unit::TestCase
def test_ln_s
check_singleton :ln_s
+ ln_s TARGETS, 'tmp'
+ each_srcdest do |fname, lnfname|
+ assert_equal fname, File.readlink(lnfname)
+ ensure
+ rm_f lnfname
+ end
+
+ lnfname = 'symlink'
+ assert_raise(Errno::ENOENT, "multiple targets need a destination directory") {
+ ln_s TARGETS, lnfname
+ }
+ assert_file.not_exist?(lnfname)
+
TARGETS.each do |fname|
- begin
- fname = "../#{fname}"
- lnfname = 'tmp/lnsdest'
- ln_s fname, lnfname
- assert FileTest.symlink?(lnfname), 'not symlink'
- assert_equal fname, File.readlink(lnfname)
- ensure
- rm_f lnfname
- end
+ fname = "../#{fname}"
+ lnfname = 'tmp/lnsdest'
+ ln_s fname, lnfname
+ assert_file.symlink?(lnfname)
+ assert_equal fname, File.readlink(lnfname)
+ ensure
+ rm_f lnfname
end
end if have_symlink? and !no_broken_symlink?
@@ -1017,22 +1028,64 @@ class TestFileUtils < Test::Unit::TestCase
def test_ln_sr
check_singleton :ln_sr
- TARGETS.each do |fname|
- begin
- lnfname = 'tmp/lnsdest'
- ln_sr fname, lnfname
- assert FileTest.symlink?(lnfname), 'not symlink'
- assert_equal "../#{fname}", File.readlink(lnfname), fname
+ assert_all_assertions_foreach(nil, *TARGETS) do |fname|
+ lnfname = 'tmp/lnsdest'
+ ln_sr fname, lnfname
+ assert_file.symlink?(lnfname)
+ assert_file.identical?(lnfname, fname)
+ assert_equal "../#{fname}", File.readlink(lnfname)
+ ensure
+ rm_f lnfname
+ end
+
+ ln_sr TARGETS, 'tmp'
+ assert_all_assertions do |all|
+ each_srcdest do |fname, lnfname|
+ all.for(fname) do
+ assert_equal "../#{fname}", File.readlink(lnfname)
+ end
ensure
rm_f lnfname
end
end
+
+ File.symlink 'data', 'link'
+ mkdir 'link/d1'
+ mkdir 'link/d2'
+ ln_sr 'link/d1/z', 'link/d2'
+ assert_equal '../d1/z', File.readlink('data/d2/z')
+
mkdir 'data/src'
File.write('data/src/xxx', 'ok')
File.symlink '../data/src', 'tmp/src'
ln_sr 'tmp/src/xxx', 'data'
- assert File.symlink?('data/xxx')
+ assert_file.symlink?('data/xxx')
assert_equal 'ok', File.read('data/xxx')
+ assert_equal 'src/xxx', File.readlink('data/xxx')
+ end
+
+ def test_ln_sr_not_target_directory
+ assert_raise(ArgumentError) {
+ ln_sr TARGETS, 'tmp', target_directory: false
+ }
+ assert_empty(Dir.children('tmp'))
+
+ lnfname = 'symlink'
+ assert_raise(ArgumentError) {
+ ln_sr TARGETS, lnfname, target_directory: false
+ }
+ assert_file.not_exist?(lnfname)
+
+ assert_all_assertions_foreach(nil, *TARGETS) do |fname|
+ assert_raise(Errno::EEXIST, Errno::EACCES) {
+ ln_sr fname, 'tmp', target_directory: false
+ }
+ dest = File.join('tmp/', File.basename(fname))
+ assert_file.not_exist? dest
+ ln_sr fname, dest, target_directory: false
+ assert_file.symlink?(dest)
+ assert_equal("../#{fname}", File.readlink(dest))
+ end
end if have_symlink?
def test_ln_sr_broken_symlink
@@ -1349,7 +1402,7 @@ class TestFileUtils < Test::Unit::TestCase
# regular file. It's slightly strange. Anyway it's no effect bit.
# see /usr/src/sys/ufs/ufs/ufs_chmod()
# NetBSD, OpenBSD, Solaris, and AIX also deny it.
- if /freebsd|netbsd|openbsd|solaris|aix/ !~ RUBY_PLATFORM
+ if /freebsd|netbsd|openbsd|aix/ !~ RUBY_PLATFORM
chmod "u+t,o+t", 'tmp/a'
assert_filemode 07500, 'tmp/a'
chmod "a-t,a-s", 'tmp/a'
@@ -1763,6 +1816,14 @@ class TestFileUtils < Test::Unit::TestCase
assert_file_not_exist 'data/tmpdir'
end if have_file_perm?
+ def test_remove_dir_with_file
+ File.write('data/tmpfile', 'dummy')
+ assert_raise(Errno::ENOTDIR) { remove_dir 'data/tmpfile' }
+ assert_file_exist 'data/tmpfile'
+ ensure
+ File.unlink('data/tmpfile') if File.exist?('data/tmpfile')
+ end
+
def test_compare_file
check_singleton :compare_file
# FIXME
diff --git a/test/io/console/test_io_console.rb b/test/io/console/test_io_console.rb
index 709ea53a88..c3f9c91c7d 100644
--- a/test/io/console/test_io_console.rb
+++ b/test/io/console/test_io_console.rb
@@ -7,6 +7,11 @@ rescue LoadError
end
class TestIO_Console < Test::Unit::TestCase
+ HOST_OS = RbConfig::CONFIG['host_os']
+ private def host_os?(os)
+ HOST_OS =~ os
+ end
+
begin
PATHS = $LOADED_FEATURES.grep(%r"/io/console(?:\.#{RbConfig::CONFIG['DLEXT']}|\.rb|/\w+\.rb)\z") {$`}
rescue Encoding::CompatibilityError
@@ -20,17 +25,13 @@ class TestIO_Console < Test::Unit::TestCase
# FreeBSD seems to hang on TTOU when running parallel tests
# tested on FreeBSD 11.x.
#
- # Solaris gets stuck too, even in non-parallel mode.
- # It occurs only in chkbuild. It does not occur when running
- # `make test-all` in SSH terminal.
- #
# I suspect that it occurs only when having no TTY.
# (Parallel mode runs tests in child processes, so I guess
# they has no TTY.)
# But it does not occur in `make test-all > /dev/null`, so
# there should be an additional factor, I guess.
def set_winsize_setup
- @old_ttou = trap(:TTOU, 'IGNORE') if RUBY_PLATFORM =~ /freebsd|solaris/i
+ @old_ttou = trap(:TTOU, 'IGNORE') if host_os?(/freebsd/)
end
def set_winsize_teardown
@@ -371,6 +372,15 @@ defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do
w.print cc
w.flush
result = EnvUtil.timeout(3) {r.gets}
+ if result
+ case cc.chr
+ when "\C-A".."\C-_"
+ cc = "^" + (cc.ord | 0x40).chr
+ when "\C-?"
+ cc = "^?"
+ end
+ result.sub!(cc, "")
+ end
assert_equal(expect, result.chomp)
end
@@ -382,7 +392,7 @@ defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do
# TestIO_Console#test_intr [/usr/home/chkbuild/chkbuild/tmp/build/20220304T163001Z/ruby/test/io/console/test_io_console.rb:387]:
# <"25"> expected but was
# <"-e:12:in `p': \e[1mexecution expired (\e[1;4mTimeout::Error\e[m\e[1m)\e[m">.
- omit if /freebsd/ =~ RUBY_PLATFORM
+ omit if host_os?(/freebsd/)
run_pty("#{<<~"begin;"}\n#{<<~'end;'}") do |r, w, _|
begin;
@@ -408,7 +418,7 @@ defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do
if cc = ctrl["intr"]
assert_ctrl("#{cc.ord}", cc, r, w)
assert_ctrl("#{cc.ord}", cc, r, w)
- assert_ctrl("Interrupt", cc, r, w) unless /linux|solaris/ =~ RUBY_PLATFORM
+ assert_ctrl("Interrupt", cc, r, w) unless host_os?(/linux/)
end
if cc = ctrl["dsusp"]
assert_ctrl("#{cc.ord}", cc, r, w)
@@ -546,9 +556,7 @@ defined?(IO.console) and TestIO_Console.class_eval do
File.open(ttyname) {|f| assert_predicate(f, :tty?)}
end
end
-end
-defined?(IO.console) and TestIO_Console.class_eval do
case
when Process.respond_to?(:daemon)
noctty = [EnvUtil.rubybin, "-e", "Process.daemon(true)"]
diff --git a/test/io/console/test_ractor.rb b/test/io/console/test_ractor.rb
index b30988f47e..dff0c67eab 100644
--- a/test/io/console/test_ractor.rb
+++ b/test/io/console/test_ractor.rb
@@ -8,6 +8,10 @@ class TestIOConsoleInRactor < Test::Unit::TestCase
path = $".find {|path| path.end_with?(ext)}
assert_in_out_err(%W[-r#{path}], "#{<<~"begin;"}\n#{<<~'end;'}", ["true"], [])
begin;
+ class Ractor
+ alias value take
+ end unless Ractor.method_defined? :value # compat with Ruby 3.4 and olders
+
$VERBOSE = nil
r = Ractor.new do
$stdout.console_mode
@@ -18,17 +22,21 @@ class TestIOConsoleInRactor < Test::Unit::TestCase
else
true # should not success
end
- puts r.take
+ puts r.value
end;
assert_in_out_err(%W[-r#{path}], "#{<<~"begin;"}\n#{<<~'end;'}", ["true"], [])
begin;
+ class Ractor
+ alias value take
+ end unless Ractor.method_defined? :value # compat with Ruby 3.4 and olders
+
console = IO.console
$VERBOSE = nil
r = Ractor.new do
IO.console
end
- puts console.class == r.take.class
+ puts console.class == r.value.class
end;
end
end if defined? Ractor
diff --git a/test/io/wait/test_io_wait.rb b/test/io/wait/test_io_wait.rb
index cbc01f9622..c532638e09 100644
--- a/test/io/wait/test_io_wait.rb
+++ b/test/io/wait/test_io_wait.rb
@@ -4,9 +4,6 @@ require 'test/unit'
require 'timeout'
require 'socket'
-# For `IO#ready?` and `IO#nread`:
-require 'io/wait'
-
class TestIOWait < Test::Unit::TestCase
def setup
@@ -22,38 +19,11 @@ class TestIOWait < Test::Unit::TestCase
@w.close unless @w.closed?
end
- def test_nread
- assert_equal 0, @r.nread
- @w.syswrite "."
- sleep 0.1
- assert_equal 1, @r.nread
- end
-
- def test_nread_buffered
- @w.syswrite ".\n!"
- assert_equal ".\n", @r.gets
- assert_equal 1, @r.nread
- end
-
- def test_ready?
- omit 'unstable on MinGW' if /mingw/ =~ RUBY_PLATFORM
- assert_not_predicate @r, :ready?, "shouldn't ready, but ready"
- @w.syswrite "."
- sleep 0.1
- assert_predicate @r, :ready?, "should ready, but not"
- end
-
- def test_buffered_ready?
- @w.syswrite ".\n!"
- assert_equal ".\n", @r.gets
- assert_predicate @r, :ready?
- end
-
def test_wait
omit 'unstable on MinGW' if /mingw/ =~ RUBY_PLATFORM
assert_nil @r.wait(0)
@w.syswrite "."
- sleep 0.1
+ IO.select([@r])
assert_equal @r, @r.wait(0)
end
@@ -78,7 +48,8 @@ class TestIOWait < Test::Unit::TestCase
ret = nil
assert_nothing_raised(Timeout::Error) do
q.push(true)
- Timeout.timeout(0.1) { ret = @r.wait }
+ t = EnvUtil.apply_timeout_scale(1)
+ Timeout.timeout(t) { ret = @r.wait }
end
assert_equal @r, ret
ensure
@@ -113,7 +84,8 @@ class TestIOWait < Test::Unit::TestCase
ret = nil
assert_nothing_raised(Timeout::Error) do
q.push(true)
- Timeout.timeout(0.1) { ret = @r.wait_readable }
+ t = EnvUtil.apply_timeout_scale(1)
+ Timeout.timeout(t) { ret = @r.wait_readable }
end
assert_equal @r, ret
ensure
diff --git a/test/io/wait/test_io_wait_uncommon.rb b/test/io/wait/test_io_wait_uncommon.rb
index 0f922f4e24..15b13b51b1 100644
--- a/test/io/wait/test_io_wait_uncommon.rb
+++ b/test/io/wait/test_io_wait_uncommon.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
require 'test/unit'
+require 'io/wait'
# test uncommon device types to check portability problems
# We may optimize IO#wait_*able for non-Linux kernels in the future
@@ -74,4 +75,18 @@ class TestIOWaitUncommon < Test::Unit::TestCase
def test_wait_writable_null
check_dev(IO::NULL, :wait_writable)
end
+
+ def test_after_ungetc_wait_readable
+ check_dev(IO::NULL, mode: "r") {|fp|
+ fp.ungetc(?a)
+ assert_predicate fp, :wait_readable
+ }
+ end
+
+ def test_after_ungetc_in_text_wait_readable
+ check_dev(IO::NULL, mode: "rt") {|fp|
+ fp.ungetc(?a)
+ assert_predicate fp, :wait_readable
+ }
+ end
end
diff --git a/test/io/wait/test_ractor.rb b/test/io/wait/test_ractor.rb
index 800216e610..c77a29bff3 100644
--- a/test/io/wait/test_ractor.rb
+++ b/test/io/wait/test_ractor.rb
@@ -7,11 +7,15 @@ class TestIOWaitInRactor < Test::Unit::TestCase
ext = "/io/wait.#{RbConfig::CONFIG['DLEXT']}"
path = $".find {|path| path.end_with?(ext)}
assert_in_out_err(%W[-r#{path}], <<-"end;", ["true"], [])
+ class Ractor
+ alias value take
+ end unless Ractor.method_defined? :value # compat with Ruby 3.4 and olders
+
$VERBOSE = nil
r = Ractor.new do
$stdout.equal?($stdout.wait_writable)
end
- puts r.take
+ puts r.value
end;
end
end if defined? Ractor
diff --git a/test/json/fixtures/pass15.json b/test/json/fixtures/fail15.json
index fc8376b605..fc8376b605 100644
--- a/test/json/fixtures/pass15.json
+++ b/test/json/fixtures/fail15.json
diff --git a/test/json/fixtures/pass16.json b/test/json/fixtures/fail16.json
index c43ae3c286..c43ae3c286 100644
--- a/test/json/fixtures/pass16.json
+++ b/test/json/fixtures/fail16.json
diff --git a/test/json/fixtures/pass17.json b/test/json/fixtures/fail17.json
index 62b9214aed..62b9214aed 100644
--- a/test/json/fixtures/pass17.json
+++ b/test/json/fixtures/fail17.json
diff --git a/test/json/fixtures/pass26.json b/test/json/fixtures/fail26.json
index 845d26a6a5..845d26a6a5 100644
--- a/test/json/fixtures/pass26.json
+++ b/test/json/fixtures/fail26.json
diff --git a/test/json/fixtures/pass1.json b/test/json/fixtures/pass1.json
index 7828fcc137..fa9058b136 100644
--- a/test/json/fixtures/pass1.json
+++ b/test/json/fixtures/pass1.json
@@ -12,7 +12,7 @@
"real": -9876.543210,
"e": 0.123456789e-12,
"E": 1.234567890E+34,
- "": 23456789012E666,
+ "": 23456789012E66,
"zero": 0,
"one": 1,
"space": " ",
diff --git a/test/json/json_coder_test.rb b/test/json/json_coder_test.rb
index 9861181910..a8477dd7be 100755
--- a/test/json/json_coder_test.rb
+++ b/test/json/json_coder_test.rb
@@ -12,12 +12,33 @@ class JSONCoderTest < Test::Unit::TestCase
end
def test_json_coder_with_proc_with_unsupported_value
- coder = JSON::Coder.new do |object|
+ coder = JSON::Coder.new do |object, is_key|
+ assert_equal false, is_key
Object.new
end
assert_raise(JSON::GeneratorError) { coder.dump([Object.new]) }
end
+ def test_json_coder_with_proc_returning_symbol
+ coder = JSON::Coder.new { _1 }
+ assert_equal %({"sym":"sym"}), coder.dump({ sym: :sym })
+ end
+
+ def test_json_coder_hash_key
+ obj = Object.new
+ coder = JSON::Coder.new do |obj, is_key|
+ assert_equal true, is_key
+ obj.to_s
+ end
+ assert_equal %({#{obj.to_s.inspect}:1}), coder.dump({ obj => 1 })
+
+ coder = JSON::Coder.new { 42 }
+ error = assert_raise JSON::GeneratorError do
+ coder.dump({ obj => 1 })
+ end
+ assert_equal "Integer not allowed as object key in JSON", error.message
+ end
+
def test_json_coder_options
coder = JSON::Coder.new(array_nl: "\n") do |object|
42
@@ -37,17 +58,97 @@ class JSONCoderTest < Test::Unit::TestCase
end
def test_json_coder_dump_NaN_or_Infinity
- coder = JSON::Coder.new(&:inspect)
+ coder = JSON::Coder.new { |o| o.inspect }
assert_equal "NaN", coder.load(coder.dump(Float::NAN))
assert_equal "Infinity", coder.load(coder.dump(Float::INFINITY))
assert_equal "-Infinity", coder.load(coder.dump(-Float::INFINITY))
end
def test_json_coder_dump_NaN_or_Infinity_loop
- coder = JSON::Coder.new(&:itself)
+ coder = JSON::Coder.new { |o| o.itself }
error = assert_raise JSON::GeneratorError do
coder.dump(Float::NAN)
end
assert_include error.message, "NaN not allowed in JSON"
end
+
+ def test_json_coder_string_invalid_encoding
+ calls = 0
+ coder = JSON::Coder.new do |object, is_key|
+ calls += 1
+ object
+ end
+
+ error = assert_raise JSON::GeneratorError do
+ coder.dump("\xFF")
+ end
+ assert_equal "source sequence is illegal/malformed utf-8", error.message
+ assert_equal 1, calls
+
+ error = assert_raise JSON::GeneratorError do
+ coder.dump({ "\xFF" => 1 })
+ end
+ assert_equal "source sequence is illegal/malformed utf-8", error.message
+ assert_equal 2, calls
+
+ calls = 0
+ coder = JSON::Coder.new do |object, is_key|
+ calls += 1
+ object.dup
+ end
+
+ error = assert_raise JSON::GeneratorError do
+ coder.dump("\xFF")
+ end
+ assert_equal "source sequence is illegal/malformed utf-8", error.message
+ assert_equal 1, calls
+
+ error = assert_raise JSON::GeneratorError do
+ coder.dump({ "\xFF" => 1 })
+ end
+ assert_equal "source sequence is illegal/malformed utf-8", error.message
+ assert_equal 2, calls
+
+ calls = 0
+ coder = JSON::Coder.new do |object, is_key|
+ calls += 1
+ object.bytes
+ end
+
+ assert_equal "[255]", coder.dump("\xFF")
+ assert_equal 1, calls
+
+ error = assert_raise JSON::GeneratorError do
+ coder.dump({ "\xFF" => 1 })
+ end
+ assert_equal "Array not allowed as object key in JSON", error.message
+ assert_equal 2, calls
+
+ calls = 0
+ coder = JSON::Coder.new do |object, is_key|
+ calls += 1
+ [object].pack("m")
+ end
+
+ assert_equal '"/w==\\n"', coder.dump("\xFF")
+ assert_equal 1, calls
+
+ assert_equal '{"/w==\\n":1}', coder.dump({ "\xFF" => 1 })
+ assert_equal 2, calls
+ end
+
+ def test_depth
+ coder = JSON::Coder.new(object_nl: "\n", array_nl: "\n", space: " ", indent: " ", depth: 1)
+ assert_equal %({\n "foo": 42\n }), coder.dump(foo: 42)
+ end
+
+ def test_nesting_recovery
+ coder = JSON::Coder.new
+ ary = []
+ ary << ary
+ assert_raise JSON::NestingError do
+ coder.dump(ary)
+ end
+ assert_equal '{"a":1}', coder.dump({ a: 1 })
+ end
end
diff --git a/test/json/json_common_interface_test.rb b/test/json/json_common_interface_test.rb
index 9c12551300..37568b556e 100644
--- a/test/json/json_common_interface_test.rb
+++ b/test/json/json_common_interface_test.rb
@@ -42,12 +42,6 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
'"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
end
- def test_index
- assert_equal @json, JSON[@hash]
- assert_equal @json, JSON[@hash_with_method_missing]
- assert_equal @hash, JSON[@json]
- end
-
def test_parser
assert_match(/::Parser\z/, JSON.parser.name)
end
@@ -68,11 +62,6 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
JSON.create_id = 'json_class'
end
- def test_deep_const_get
- assert_raise(ArgumentError) { JSON.deep_const_get('Nix::Da') }
- assert_equal File::SEPARATOR, JSON.deep_const_get('File::SEPARATOR')
- end
-
def test_parse
assert_equal [ 1, 2, 3, ], JSON.parse('[ 1, 2, 3 ]')
end
@@ -91,6 +80,30 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
def test_pretty_generate
assert_equal "[\n 1,\n 2,\n 3\n]", JSON.pretty_generate([ 1, 2, 3 ])
+ assert_equal <<~JSON.strip, JSON.pretty_generate({ a: { b: "f"}, c: "d"})
+ {
+ "a": {
+ "b": "f"
+ },
+ "c": "d"
+ }
+ JSON
+
+ # Cause the state to be spilled on the heap.
+ o = Object.new
+ def o.to_s
+ "Object"
+ end
+ actual = JSON.pretty_generate({ a: { b: o}, c: "d", e: "f"})
+ assert_equal <<~JSON.strip, actual
+ {
+ "a": {
+ "b": "Object"
+ },
+ "c": "d",
+ "e": "f"
+ }
+ JSON
end
def test_load
@@ -130,12 +143,97 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
def test_load_with_options
json = '{ "foo": NaN }'
assert JSON.load(json, nil, :allow_nan => true)['foo'].nan?
+ assert JSON.load(json, :allow_nan => true)['foo'].nan?
end
def test_load_null
assert_equal nil, JSON.load(nil, nil, :allow_blank => true)
assert_raise(TypeError) { JSON.load(nil, nil, :allow_blank => false) }
assert_raise(JSON::ParserError) { JSON.load('', nil, :allow_blank => false) }
+ assert_raise(TypeError) { JSON.load([], nil, :allow_blank => true) }
+ assert_raise(TypeError) { JSON.load({}, nil, :allow_blank => true) }
+ end
+
+ def test_unsafe_load
+ string_able_klass = Class.new do
+ def initialize(str)
+ @str = str
+ end
+
+ def to_str
+ @str
+ end
+ end
+
+ io_able_klass = Class.new do
+ def initialize(str)
+ @str = str
+ end
+
+ def to_io
+ StringIO.new(@str)
+ end
+ end
+
+ assert_equal @hash, JSON.unsafe_load(@json)
+ tempfile = Tempfile.open('@json')
+ tempfile.write @json
+ tempfile.rewind
+ assert_equal @hash, JSON.unsafe_load(tempfile)
+ stringio = StringIO.new(@json)
+ stringio.rewind
+ assert_equal @hash, JSON.unsafe_load(stringio)
+ string_able = string_able_klass.new(@json)
+ assert_equal @hash, JSON.unsafe_load(string_able)
+ io_able = io_able_klass.new(@json)
+ assert_equal @hash, JSON.unsafe_load(io_able)
+ assert_equal nil, JSON.unsafe_load(nil)
+ assert_equal nil, JSON.unsafe_load('')
+ ensure
+ tempfile.close!
+ end
+
+ def test_unsafe_load_with_proc
+ visited = []
+ JSON.unsafe_load('{"foo": [1, 2, 3], "bar": {"baz": "plop"}}', proc { |o| visited << JSON.dump(o); o })
+
+ expected = [
+ '"foo"',
+ '1',
+ '2',
+ '3',
+ '[1,2,3]',
+ '"bar"',
+ '"baz"',
+ '"plop"',
+ '{"baz":"plop"}',
+ '{"foo":[1,2,3],"bar":{"baz":"plop"}}',
+ ]
+ assert_equal expected, visited
+ end
+
+ def test_unsafe_load_default_options
+ too_deep = '[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'
+ assert JSON.unsafe_load(too_deep, nil).is_a?(Array)
+ nan_json = '{ "foo": NaN }'
+ assert JSON.unsafe_load(nan_json, nil)['foo'].nan?
+ assert_equal nil, JSON.unsafe_load(nil, nil)
+ t = Time.new(2025, 9, 3, 14, 50, 0)
+ assert_equal t.to_s, JSON.unsafe_load(JSON(t)).to_s
+ end
+
+ def test_unsafe_load_with_options
+ nan_json = '{ "foo": NaN }'
+ assert_raise(JSON::ParserError) { JSON.unsafe_load(nan_json, nil, :allow_nan => false)['foo'].nan? }
+ # make sure it still uses the defaults when something is provided
+ assert JSON.unsafe_load(nan_json, nil, :allow_blank => true)['foo'].nan?
+ assert JSON.unsafe_load(nan_json, :allow_nan => true)['foo'].nan?
+ end
+
+ def test_unsafe_load_null
+ assert_equal nil, JSON.unsafe_load(nil, nil, :allow_blank => true)
+ assert_raise(TypeError) { JSON.unsafe_load(nil, nil, :allow_blank => false) }
+ assert_raise(JSON::ParserError) { JSON.unsafe_load('', nil, :allow_blank => false) }
end
def test_dump
@@ -185,6 +283,12 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
assert_equal @hash, JSON(@json)
end
+ def test_index
+ assert_equal @json, JSON[@hash]
+ assert_equal @json, JSON[@hash_with_method_missing]
+ assert_equal @hash, JSON[@json]
+ end
+
def test_load_file
test_load_shared(:load_file)
end
diff --git a/test/json/json_encoding_test.rb b/test/json/json_encoding_test.rb
index afffd8976a..7ac06b2a7b 100644
--- a/test/json/json_encoding_test.rb
+++ b/test/json/json_encoding_test.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
require_relative 'test_helper'
class JSONEncodingTest < Test::Unit::TestCase
@@ -30,6 +31,18 @@ class JSONEncodingTest < Test::Unit::TestCase
assert_equal @generated, JSON.generate(@utf_16_data, ascii_only: true)
end
+ def test_generate_shared_string
+ # Ref: https://github.com/ruby/json/issues/859
+ s = "01234567890"
+ assert_equal '"234567890"', JSON.dump(s[2..-1])
+ s = '01234567890123456789"a"b"c"d"e"f"g"h'
+ assert_equal '"\"a\"b\"c\"d\"e\"f\"g\""', JSON.dump(s[20, 15])
+ s = "0123456789001234567890012345678900123456789001234567890"
+ assert_equal '"23456789001234567890012345678900123456789001234567890"', JSON.dump(s[2..-1])
+ s = "0123456789001234567890012345678900123456789001234567890"
+ assert_equal '"567890012345678900123456789001234567890012345678"', JSON.dump(s[5..-3])
+ end
+
def test_unicode
assert_equal '""', ''.to_json
assert_equal '"\\b"', "\b".to_json
@@ -37,7 +50,7 @@ class JSONEncodingTest < Test::Unit::TestCase
assert_equal '"\u001f"', 0x1f.chr.to_json
assert_equal '" "', ' '.to_json
assert_equal "\"#{0x7f.chr}\"", 0x7f.chr.to_json
- utf8 = [ "© ≠ €! \01" ]
+ utf8 = ["© ≠ €! \01"]
json = '["© ≠ €! \u0001"]'
assert_equal json, utf8.to_json(ascii_only: false)
assert_equal utf8, parse(json)
@@ -78,10 +91,10 @@ class JSONEncodingTest < Test::Unit::TestCase
json = '"\u%04x"' % i
i = i.chr
assert_equal i, parse(json)[0]
- if i == ?\b
+ if i == "\b"
generated = generate(i)
- assert '"\b"' == generated || '"\10"' == generated
- elsif [?\n, ?\r, ?\t, ?\f].include?(i)
+ assert ['"\b"', '"\10"'].include?(generated)
+ elsif ["\n", "\r", "\t", "\f"].include?(i)
assert_equal i.dump, generate(i)
elsif i.chr < 0x20.chr
assert_equal json, generate(i)
@@ -92,4 +105,171 @@ class JSONEncodingTest < Test::Unit::TestCase
end
assert_equal "\302\200", parse('"\u0080"')
end
+
+ def test_deeply_nested_structures
+ # Test for deeply nested arrays
+ nesting_level = 100
+ deeply_nested = []
+ current = deeply_nested
+
+ (nesting_level - 1).times do
+ current << []
+ current = current[0]
+ end
+
+ json = generate(deeply_nested)
+ assert_equal deeply_nested, parse(json)
+
+ # Test for deeply nested objects/hashes
+ deeply_nested_hash = {}
+ current_hash = deeply_nested_hash
+
+ (nesting_level - 1).times do |i|
+ current_hash["key#{i}"] = {}
+ current_hash = current_hash["key#{i}"]
+ end
+
+ json = generate(deeply_nested_hash)
+ assert_equal deeply_nested_hash, parse(json)
+ end
+
+ def test_very_large_json_strings
+ # Create a large array with repeated elements
+ large_array = Array.new(10_000) { |i| "item#{i}" }
+
+ json = generate(large_array)
+ parsed = parse(json)
+
+ assert_equal large_array.size, parsed.size
+ assert_equal large_array.first, parsed.first
+ assert_equal large_array.last, parsed.last
+
+ # Create a large hash
+ large_hash = {}
+ 10_000.times { |i| large_hash["key#{i}"] = "value#{i}" }
+
+ json = generate(large_hash)
+ parsed = parse(json)
+
+ assert_equal large_hash.size, parsed.size
+ assert_equal large_hash["key0"], parsed["key0"]
+ assert_equal large_hash["key9999"], parsed["key9999"]
+ end
+
+ def test_invalid_utf8_sequences
+ invalid_utf8 = "\xFF\xFF"
+ error = assert_raise(JSON::GeneratorError) do
+ generate(invalid_utf8)
+ end
+ assert_match(%r{source sequence is illegal/malformed utf-8}, error.message)
+ end
+
+ def test_surrogate_pair_handling
+ # Test valid surrogate pairs
+ assert_equal "\u{10000}", parse('"\ud800\udc00"')
+ assert_equal "\u{10FFFF}", parse('"\udbff\udfff"')
+
+ # The existing test already checks for orphaned high surrogate
+ assert_raise(JSON::ParserError) { parse('"\ud800"') }
+
+ # Test generating surrogate pairs
+ utf8_string = "\u{10437}"
+ generated = generate(utf8_string, ascii_only: true)
+ assert_match(/\\ud801\\udc37/, generated)
+ end
+
+ def test_json_escaping_edge_cases
+ # Test escaping forward slashes
+ assert_equal "/", parse('"\/"')
+
+ # Test escaping backslashes
+ assert_equal "\\", parse('"\\\\"')
+
+ # Test escaping quotes
+ assert_equal '"', parse('"\\""')
+
+ # Multiple escapes in sequence - different JSON parsers might handle escaped forward slashes differently
+ # Some parsers preserve the escaping, others don't
+ escaped_result = parse('"\\\\\\"\\/"')
+ assert_match(/\\"/, escaped_result)
+ assert_match(%r{/}, escaped_result)
+
+ # Generate string with all special characters
+ special_chars = "\b\f\n\r\t\"\\"
+ escaped_json = generate(special_chars)
+ assert_equal special_chars, parse(escaped_json)
+ end
+
+ def test_empty_objects_and_arrays
+ # Test empty objects with different encodings
+ assert_equal({}, parse('{}'))
+ assert_equal({}, parse('{}'.encode(Encoding::UTF_16BE)))
+ assert_equal({}, parse('{}'.encode(Encoding::UTF_16LE)))
+ assert_equal({}, parse('{}'.encode(Encoding::UTF_32BE)))
+ assert_equal({}, parse('{}'.encode(Encoding::UTF_32LE)))
+
+ # Test empty arrays with different encodings
+ assert_equal([], parse('[]'))
+ assert_equal([], parse('[]'.encode(Encoding::UTF_16BE)))
+ assert_equal([], parse('[]'.encode(Encoding::UTF_16LE)))
+ assert_equal([], parse('[]'.encode(Encoding::UTF_32BE)))
+ assert_equal([], parse('[]'.encode(Encoding::UTF_32LE)))
+
+ # Test generating empty objects and arrays
+ assert_equal '{}', generate({})
+ assert_equal '[]', generate([])
+ end
+
+ def test_null_character_handling
+ # Test parsing null character
+ assert_equal "\u0000", parse('"\u0000"')
+
+ # Test generating null character
+ string_with_null = "\u0000"
+ generated = generate(string_with_null)
+ assert_equal '"\u0000"', generated
+
+ # Test null characters in middle of string
+ mixed_string = "before\u0000after"
+ generated = generate(mixed_string)
+ assert_equal mixed_string, parse(generated)
+ end
+
+ def test_whitespace_handling
+ # Test parsing with various whitespace patterns
+ assert_equal({}, parse(' { } '))
+ assert_equal({}, parse("{\r\n}"))
+ assert_equal([], parse(" [ \n ] "))
+ assert_equal(["a", "b"], parse(" [ \n\"a\",\r\n \"b\"\n ] "))
+ assert_equal({ "a" => "b" }, parse(" { \n\"a\" \r\n: \t\"b\"\n } "))
+
+ # Test with excessive whitespace
+ excessive_whitespace = " \n\r\t" * 10 + "{}" + " \n\r\t" * 10
+ assert_equal({}, parse(excessive_whitespace))
+
+ # Mixed whitespace in keys and values
+ mixed_json = '{"a \n b":"c \r\n d"}'
+ assert_equal({ "a \n b" => "c \r\n d" }, parse(mixed_json))
+ end
+
+ def test_control_character_handling
+ # Test all control characters (U+0000 to U+001F)
+ (0..0x1F).each do |i|
+ # Skip already tested ones
+ next if [0x08, 0x0A, 0x0D, 0x0C, 0x09].include?(i)
+
+ control_char = i.chr('UTF-8')
+ escaped_json = '"' + "\\u%04x" % i + '"'
+ assert_equal control_char, parse(escaped_json)
+
+ # Check that the character is properly escaped when generating
+ assert_match(/\\u00[0-1][0-9a-f]/, generate(control_char))
+ end
+
+ # Test string with multiple control characters
+ control_str = "\u0001\u0002\u0003\u0004"
+ generated = generate(control_str)
+ assert_equal control_str, parse(generated)
+ assert_match(/\\u0001\\u0002\\u0003\\u0004/, generated)
+ end
end
diff --git a/test/json/json_ext_parser_test.rb b/test/json/json_ext_parser_test.rb
index 8aa626257e..e610f642f1 100644
--- a/test/json/json_ext_parser_test.rb
+++ b/test/json/json_ext_parser_test.rb
@@ -14,16 +14,35 @@ class JSONExtParserTest < Test::Unit::TestCase
end
def test_error_messages
- ex = assert_raise(ParserError) { parse('Infinity') }
- assert_equal "unexpected token at 'Infinity'", ex.message
+ ex = assert_raise(ParserError) { parse('Infinity something') }
+ unless RUBY_PLATFORM =~ /java/
+ assert_equal "unexpected token 'Infinity' at line 1 column 1", ex.message
+ end
+ ex = assert_raise(ParserError) { parse('foo bar') }
unless RUBY_PLATFORM =~ /java/
- ex = assert_raise(ParserError) { parse('-Infinity') }
- assert_equal "unexpected token at '-Infinity'", ex.message
+ assert_equal "unexpected token 'foo' at line 1 column 1", ex.message
end
- ex = assert_raise(ParserError) { parse('NaN') }
- assert_equal "unexpected token at 'NaN'", ex.message
+ ex = assert_raise(ParserError) { parse('-Infinity something') }
+ unless RUBY_PLATFORM =~ /java/
+ assert_equal "unexpected token '-Infinity' at line 1 column 1", ex.message
+ end
+
+ ex = assert_raise(ParserError) { parse('NaN something') }
+ unless RUBY_PLATFORM =~ /java/
+ assert_equal "unexpected token 'NaN' at line 1 column 1", ex.message
+ end
+
+ ex = assert_raise(ParserError) { parse(' ') }
+ unless RUBY_PLATFORM =~ /java/
+ assert_equal "unexpected end of input at line 1 column 4", ex.message
+ end
+
+ ex = assert_raise(ParserError) { parse('{ ') }
+ unless RUBY_PLATFORM =~ /java/
+ assert_equal "expected object key, got EOF at line 1 column 5", ex.message
+ end
end
if GC.respond_to?(:stress=)
diff --git a/test/json/json_fixtures_test.rb b/test/json/json_fixtures_test.rb
index c153ebef7c..c0d1037939 100644
--- a/test/json/json_fixtures_test.rb
+++ b/test/json/json_fixtures_test.rb
@@ -10,6 +10,8 @@ class JSONFixturesTest < Test::Unit::TestCase
source = File.read(f)
define_method("test_#{name}") do
assert JSON.parse(source), "Did not pass for fixture '#{File.basename(f)}': #{source.inspect}"
+ rescue JSON::ParserError
+ raise "#{File.basename(f)} parsing failure"
end
end
diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb
index f87006ac7b..753ee0fbdf 100755
--- a/test/json/json_generator_test.rb
+++ b/test/json/json_generator_test.rb
@@ -39,14 +39,6 @@ class JSONGeneratorTest < Test::Unit::TestCase
JSON
end
- def silence
- v = $VERBOSE
- $VERBOSE = nil
- yield
- ensure
- $VERBOSE = v
- end
-
def test_generate
json = generate(@hash)
assert_equal(parse(@json2), parse(json))
@@ -90,6 +82,66 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal '"hello"', dump(:hello, strict: true)
assert_equal '"hello"', :hello.to_json(strict: true)
assert_equal '"World"', "World".to_json(strict: true)
+ assert_equal '["hello"]', dump([:hello], strict: true)
+ assert_equal '{"hello":"world"}', dump({ hello: :world }, strict: true)
+ end
+
+ def test_not_frozen
+ [
+ [[], '[]'],
+ [{}, '{}'],
+ ["string", '"string"'],
+ [:sym, '"sym"'],
+ [1, '1'],
+ [1.0, '1.0'],
+ [true, 'true'],
+ [false, 'false'],
+ [nil, 'null'],
+ ].each do |(obj, exp)|
+ dumped = dump(obj, strict: true)
+ assert_equal exp, dumped
+ refute_predicate dumped, :frozen?
+ end
+ end
+
+ def test_state_depth_to_json
+ depth = Object.new
+ def depth.to_json(state)
+ JSON::State.from_state(state).depth.to_s
+ end
+
+ assert_equal "0", JSON.generate(depth)
+ assert_equal "[1]", JSON.generate([depth])
+ assert_equal %({"depth":1}), JSON.generate(depth: depth)
+ assert_equal "[[2]]", JSON.generate([[depth]])
+ assert_equal %([{"depth":2}]), JSON.generate([{depth: depth}])
+
+ state = JSON::State.new
+ assert_equal "0", state.generate(depth)
+ assert_equal "[1]", state.generate([depth])
+ assert_equal %({"depth":1}), state.generate(depth: depth)
+ assert_equal "[[2]]", state.generate([[depth]])
+ assert_equal %([{"depth":2}]), state.generate([{depth: depth}])
+ end
+
+ def test_state_depth_to_json_recursive
+ recur = Object.new
+ def recur.to_json(state = nil, *)
+ state = JSON::State.from_state(state)
+ if state.depth < 3
+ state.generate([state.depth, self])
+ else
+ state.generate([state.depth])
+ end
+ end
+
+ assert_raise(NestingError) { JSON.generate(recur, max_nesting: 3) }
+ assert_equal "[0,[1,[2,[3]]]]", JSON.generate(recur, max_nesting: 4)
+
+ state = JSON::State.new(max_nesting: 3)
+ assert_raise(NestingError) { state.generate(recur) }
+ state.max_nesting = 4
+ assert_equal "[0,[1,[2,[3]]]]", JSON.generate(recur, max_nesting: 4)
end
def test_generate_pretty
@@ -122,6 +174,22 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal '666', pretty_generate(666)
end
+ def test_generate_pretty_custom
+ state = State.new(:space_before => "<psb>", :space => "<ps>", :indent => "<pi>", :object_nl => "\n<po_nl>\n", :array_nl => "<pa_nl>")
+ json = pretty_generate({1=>{}, 2=>['a','b'], 3=>4}, state)
+ assert_equal(<<~'JSON'.chomp, json)
+ {
+ <po_nl>
+ <pi>"1"<psb>:<ps>{},
+ <po_nl>
+ <pi>"2"<psb>:<ps>[<pa_nl><pi><pi>"a",<pa_nl><pi><pi>"b"<pa_nl><pi>],
+ <po_nl>
+ <pi>"3"<psb>:<ps>4
+ <po_nl>
+ }
+ JSON
+ end
+
def test_generate_custom
state = State.new(:space_before => " ", :space => " ", :indent => "<i>", :object_nl => "\n", :array_nl => "<a_nl>")
json = generate({1=>{2=>3,4=>[5,6]}}, state)
@@ -167,7 +235,9 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal('{"1":2}', json)
s = JSON.state.new
assert s.check_circular?
- assert s[:check_circular?]
+ assert_deprecated_warning(/JSON::State/) do
+ assert s[:check_circular?]
+ end
h = { 1=>2 }
h[3] = h
assert_raise(JSON::NestingError) { generate(h) }
@@ -177,7 +247,9 @@ class JSONGeneratorTest < Test::Unit::TestCase
a << a
assert_raise(JSON::NestingError) { generate(a, s) }
assert s.check_circular?
- assert s[:check_circular?]
+ assert_deprecated_warning(/JSON::State/) do
+ assert s[:check_circular?]
+ end
end
def test_falsy_state
@@ -218,6 +290,24 @@ class JSONGeneratorTest < Test::Unit::TestCase
:space => "",
:space_before => "",
}.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
+
+ state = JSON::State.new(allow_duplicate_key: true)
+ assert_equal({
+ :allow_duplicate_key => true,
+ :allow_nan => false,
+ :array_nl => "",
+ :as_json => false,
+ :ascii_only => false,
+ :buffer_initial_length => 1024,
+ :depth => 0,
+ :script_safe => false,
+ :strict => false,
+ :indent => "",
+ :max_nesting => 100,
+ :object_nl => "",
+ :space => "",
+ :space_before => "",
+ }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
end
def test_allow_nan
@@ -243,14 +333,100 @@ class JSONGeneratorTest < Test::Unit::TestCase
end
end
+ # An object that changes state.depth when it receives to_json(state)
+ def bad_to_json
+ obj = Object.new
+ def obj.to_json(state)
+ state.depth += 1
+ "{#{state.object_nl}"\
+ "#{state.indent * state.depth}\"foo\":#{state.space}1#{state.object_nl}"\
+ "#{state.indent * (state.depth - 1)}}"
+ end
+ obj
+ end
+
+ def test_depth_restored_bad_to_json
+ state = JSON::State.new
+ state.generate(bad_to_json)
+ assert_equal 0, state.depth
+ end
+
+ def test_depth_restored_bad_to_json_in_Array
+ assert_equal <<~JSON.chomp, JSON.pretty_generate([bad_to_json] * 2)
+ [
+ {
+ "foo": 1
+ },
+ {
+ "foo": 1
+ }
+ ]
+ JSON
+ state = JSON::State.new
+ state.generate([bad_to_json])
+ assert_equal 0, state.depth
+ end
+
+ def test_depth_restored_bad_to_json_in_Hash
+ assert_equal <<~JSON.chomp, JSON.pretty_generate(a: bad_to_json, b: bad_to_json)
+ {
+ "a": {
+ "foo": 1
+ },
+ "b": {
+ "foo": 1
+ }
+ }
+ JSON
+ state = JSON::State.new
+ state.generate(a: bad_to_json)
+ assert_equal 0, state.depth
+ end
+
def test_depth
+ pretty = { object_nl: "\n", array_nl: "\n", space: " ", indent: " " }
+ state = JSON.state.new(**pretty)
+ assert_equal %({\n "foo": 42\n}), JSON.generate({ foo: 42 }, pretty)
+ assert_equal %({\n "foo": 42\n}), state.generate(foo: 42)
+ state.depth = 1
+ assert_equal %({\n "foo": 42\n }), JSON.generate({ foo: 42 }, pretty.merge(depth: 1))
+ assert_equal %({\n "foo": 42\n }), state.generate(foo: 42)
+ end
+
+ def test_depth_nesting_error
ary = []; ary << ary
assert_raise(JSON::NestingError) { generate(ary) }
assert_raise(JSON::NestingError) { JSON.pretty_generate(ary) }
- s = JSON.state.new
- assert_equal 0, s.depth
+ end
+
+ def test_depth_nesting_error_to_json
+ ary = []; ary << ary
+ s = JSON.state.new(depth: 1)
assert_raise(JSON::NestingError) { ary.to_json(s) }
- assert_equal 100, s.depth
+ assert_equal 1, s.depth
+ end
+
+ def test_depth_nesting_error_Hash_to_json
+ hash = {}; hash[:a] = hash
+ s = JSON.state.new(depth: 1)
+ assert_raise(JSON::NestingError) { hash.to_json(s) }
+ assert_equal 1, s.depth
+ end
+
+ def test_depth_nesting_error_generate
+ ary = []; ary << ary
+ s = JSON.state.new(depth: 1)
+ assert_raise(JSON::NestingError) { s.generate(ary) }
+ assert_equal 1, s.depth
+ end
+
+ def test_depth_exception_calling_to_json
+ def (obj = Object.new).to_json(*)
+ raise
+ end
+ s = JSON.state.new(depth: 1).freeze
+ assert_raise(RuntimeError) { s.generate([{ hash: obj }]) }
+ assert_equal 1, s.depth
end
def test_buffer_initial_length
@@ -319,50 +495,60 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal '2', state.indent
end
- def test_broken_bignum # [ruby-core:38867]
- pid = fork do
- x = 1 << 64
- x.class.class_eval do
- def to_s
- end
+ def test_broken_bignum # [Bug #5173]
+ bignum = 1 << 64
+ bignum_to_s = bignum.to_s
+
+ original_to_s = bignum.class.instance_method(:to_s)
+ bignum.class.class_eval do
+ def to_s
+ nil
+ end
+ alias_method :to_s, :to_s
+ end
+ case RUBY_ENGINE
+ when "jruby"
+ assert_equal bignum_to_s, JSON.generate(bignum)
+ when "truffleruby"
+ assert_raise(NoMethodError) do
+ JSON.generate(bignum)
end
- begin
- JSON::Ext::Generator::State.new.generate(x)
- exit 1
- rescue TypeError
- exit 0
+ when "ruby"
+ assert_raise(TypeError) do
+ JSON.generate(bignum)
end
end
- _, status = Process.waitpid2(pid)
- assert status.success?
- rescue NotImplementedError
- # forking to avoid modifying core class of a parent process and
- # introducing race conditions of tests are run in parallel
+ ensure
+ bignum.class.define_method(:to_s, original_to_s) if original_to_s
end
def test_hash_likeness_set_symbol
- state = JSON.state.new
- assert_equal nil, state[:foo]
- assert_equal nil.class, state[:foo].class
- assert_equal nil, state['foo']
- state[:foo] = :bar
- assert_equal :bar, state[:foo]
- assert_equal :bar, state['foo']
- state_hash = state.to_hash
- assert_kind_of Hash, state_hash
- assert_equal :bar, state_hash[:foo]
+ assert_deprecated_warning(/JSON::State/) do
+ state = JSON.state.new
+ assert_equal nil, state[:foo]
+ assert_equal nil.class, state[:foo].class
+ assert_equal nil, state['foo']
+ state[:foo] = :bar
+ assert_equal :bar, state[:foo]
+ assert_equal :bar, state['foo']
+ state_hash = state.to_hash
+ assert_kind_of Hash, state_hash
+ assert_equal :bar, state_hash[:foo]
+ end
end
def test_hash_likeness_set_string
- state = JSON.state.new
- assert_equal nil, state[:foo]
- assert_equal nil, state['foo']
- state['foo'] = :bar
- assert_equal :bar, state[:foo]
- assert_equal :bar, state['foo']
- state_hash = state.to_hash
- assert_kind_of Hash, state_hash
- assert_equal :bar, state_hash[:foo]
+ assert_deprecated_warning(/JSON::State/) do
+ state = JSON.state.new
+ assert_equal nil, state[:foo]
+ assert_equal nil, state['foo']
+ state['foo'] = :bar
+ assert_equal :bar, state[:foo]
+ assert_equal :bar, state['foo']
+ state_hash = state.to_hash
+ assert_kind_of Hash, state_hash
+ assert_equal :bar, state_hash[:foo]
+ end
end
def test_json_state_to_h_roundtrip
@@ -388,6 +574,18 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_raise JSON::GeneratorError do
generate(Object.new, strict: true)
end
+
+ assert_raise JSON::GeneratorError do
+ generate([Object.new], strict: true)
+ end
+
+ assert_raise JSON::GeneratorError do
+ generate({ "key" => Object.new }, strict: true)
+ end
+
+ assert_raise JSON::GeneratorError do
+ generate({ Object.new => "value" }, strict: true)
+ end
end
def test_nesting
@@ -403,6 +601,8 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal too_deep, ok
ok = generate too_deep_ary, :max_nesting => 0
assert_equal too_deep, ok
+
+ assert_raise(TypeError) { generate too_deep_ary, max_nesting: "garbage" }
end
def test_backslash
@@ -410,18 +610,34 @@ class JSONGeneratorTest < Test::Unit::TestCase
json = '["\\\\.(?i:gif|jpe?g|png)$"]'
assert_equal json, generate(data)
#
- data = [ '\\"' ]
- json = '["\\\\\""]'
+ data = [ '\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$\\.(?i:gif|jpe?g|png)$' ]
+ json = '["\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$\\\\.(?i:gif|jpe?g|png)$"]'
+ assert_equal json, generate(data)
+ #
+ data = [ '\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"' ]
+ json = '["\\\\\"\\\\\"\\\\\"\\\\\"\\\\\"\\\\\"\\\\\"\\\\\"\\\\\"\\\\\"\\\\\""]'
assert_equal json, generate(data)
#
data = [ '/' ]
json = '["/"]'
assert_equal json, generate(data)
#
+ data = [ '////////////////////////////////////////////////////////////////////////////////////' ]
+ json = '["////////////////////////////////////////////////////////////////////////////////////"]'
+ assert_equal json, generate(data)
+ #
data = [ '/' ]
json = '["\/"]'
assert_equal json, generate(data, :script_safe => true)
#
+ data = [ '///////////' ]
+ json = '["\/\/\/\/\/\/\/\/\/\/\/"]'
+ assert_equal json, generate(data, :script_safe => true)
+ #
+ data = [ '///////////////////////////////////////////////////////' ]
+ json = '["\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/"]'
+ assert_equal json, generate(data, :script_safe => true)
+ #
data = [ "\u2028\u2029" ]
json = '["\u2028\u2029"]'
assert_equal json, generate(data, :script_safe => true)
@@ -438,6 +654,38 @@ class JSONGeneratorTest < Test::Unit::TestCase
json = '["\""]'
assert_equal json, generate(data)
#
+ data = ['"""""""""""""""""""""""""']
+ json = '["\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\""]'
+ assert_equal json, generate(data)
+ #
+ data = '"""""'
+ json = '"\"\"\"\"\""'
+ assert_equal json, generate(data)
+ #
+ data = "abc\n"
+ json = '"abc\\n"'
+ assert_equal json, generate(data)
+ #
+ data = "\nabc"
+ json = '"\\nabc"'
+ assert_equal json, generate(data)
+ #
+ data = "\n"
+ json = '"\\n"'
+ assert_equal json, generate(data)
+ #
+ (0..16).each do |i|
+ data = ('a' * i) + "\n"
+ json = '"' + ('a' * i) + '\\n"'
+ assert_equal json, generate(data)
+ end
+ #
+ (0..16).each do |i|
+ data = "\n" + ('a' * i)
+ json = '"' + '\\n' + ('a' * i) + '"'
+ assert_equal json, generate(data)
+ end
+ #
data = ["'"]
json = '["\\\'"]'
assert_equal '["\'"]', generate(data)
@@ -445,6 +693,72 @@ class JSONGeneratorTest < Test::Unit::TestCase
data = ["倩", "瀨"]
json = '["倩","瀨"]'
assert_equal json, generate(data, script_safe: true)
+ #
+ data = '["This is a "test" of the emergency broadcast system."]'
+ json = "\"[\\\"This is a \\\"test\\\" of the emergency broadcast system.\\\"]\""
+ assert_equal json, generate(data)
+ #
+ data = '\tThis is a test of the emergency broadcast system.'
+ json = "\"\\\\tThis is a test of the emergency broadcast system.\""
+ assert_equal json, generate(data)
+ #
+ data = 'This\tis a test of the emergency broadcast system.'
+ json = "\"This\\\\tis a test of the emergency broadcast system.\""
+ assert_equal json, generate(data)
+ #
+ data = 'This is\ta test of the emergency broadcast system.'
+ json = "\"This is\\\\ta test of the emergency broadcast system.\""
+ assert_equal json, generate(data)
+ #
+ data = 'This is a test of the emergency broadcast\tsystem.'
+ json = "\"This is a test of the emergency broadcast\\\\tsystem.\""
+ assert_equal json, generate(data)
+ #
+ data = 'This is a test of the emergency broadcast\tsystem.\n'
+ json = "\"This is a test of the emergency broadcast\\\\tsystem.\\\\n\""
+ assert_equal json, generate(data)
+ data = '"' * 15
+ json = "\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\""
+ assert_equal json, generate(data)
+ data = "\"\"\"\"\"\"\"\"\"\"\"\"\"\"a"
+ json = "\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"a\""
+ assert_equal json, generate(data)
+ data = "\u0001\u0001\u0001\u0001"
+ json = "\"\\u0001\\u0001\\u0001\\u0001\""
+ assert_equal json, generate(data)
+ data = "\u0001a\u0001a\u0001a\u0001a"
+ json = "\"\\u0001a\\u0001a\\u0001a\\u0001a\""
+ assert_equal json, generate(data)
+ data = "\u0001aa\u0001aa"
+ json = "\"\\u0001aa\\u0001aa\""
+ assert_equal json, generate(data)
+ data = "\u0001aa\u0001aa\u0001aa"
+ json = "\"\\u0001aa\\u0001aa\\u0001aa\""
+ assert_equal json, generate(data)
+ data = "\u0001aa\u0001aa\u0001aa\u0001aa\u0001aa\u0001aa"
+ json = "\"\\u0001aa\\u0001aa\\u0001aa\\u0001aa\\u0001aa\\u0001aa\""
+ assert_equal json, generate(data)
+ data = "\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002"
+ json = "\"\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\""
+ assert_equal json, generate(data)
+ data = "ab\u0002c"
+ json = "\"ab\\u0002c\""
+ assert_equal json, generate(data)
+ data = "ab\u0002cab\u0002cab\u0002cab\u0002c"
+ json = "\"ab\\u0002cab\\u0002cab\\u0002cab\\u0002c\""
+ assert_equal json, generate(data)
+ data = "ab\u0002cab\u0002cab\u0002cab\u0002cab\u0002cab\u0002c"
+ json = "\"ab\\u0002cab\\u0002cab\\u0002cab\\u0002cab\\u0002cab\\u0002c\""
+ assert_equal json, generate(data)
+ data = "\n\t\f\b\n\t\f\b\n\t\f\b\n\t\f"
+ json = "\"\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\""
+ assert_equal json, generate(data)
+ data = "\n\t\f\b\n\t\f\b\n\t\f\b\n\t\f\b"
+ json = "\"\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\""
+ assert_equal json, generate(data)
+ data = "a\n\t\f\b\n\t\f\b\n\t\f\b\n\t"
+ json = "\"a\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\""
+ assert_equal json, generate(data)
end
def test_string_subclass
@@ -605,6 +919,22 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal '{"JSONGeneratorTest::StringWithToS#to_s":1}', JSON.generate(StringWithToS.new => 1)
end
+ def test_string_subclass_with_broken_to_s
+ klass = Class.new(String) do
+ def to_s
+ false
+ end
+ end
+ s = klass.new("test")
+ assert_equal '["test"]', JSON.generate([s])
+
+ omit("Can't figure out how to match behavior in java code") if RUBY_PLATFORM == "java"
+
+ assert_raise TypeError do
+ JSON.generate(s => 1)
+ end
+ end
+
if defined?(JSON::Ext::Generator) and RUBY_PLATFORM != "java"
def test_valid_utf8_in_different_encoding
utf8_string = "€™"
@@ -619,29 +949,6 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal JSON.dump(utf8_string), JSON.dump(wrong_encoding_string)
end
end
-
- def test_string_ext_included_calls_super
- included = false
-
- Module.send(:alias_method, :included_orig, :included)
- Module.send(:remove_method, :included)
- Module.send(:define_method, :included) do |base|
- included_orig(base)
- included = true
- end
-
- Class.new(String) do
- include JSON::Ext::Generator::GeneratorMethods::String
- end
-
- assert included
- ensure
- if Module.private_method_defined?(:included_orig)
- Module.send(:remove_method, :included) if Module.method_defined?(:included)
- Module.send(:alias_method, :included, :included_orig)
- Module.send(:remove_method, :included_orig)
- end
- end
end
def test_nonutf8_encoding
@@ -662,16 +969,53 @@ class JSONGeneratorTest < Test::Unit::TestCase
def test_json_generate_as_json_convert_to_proc
object = Object.new
- assert_equal object.object_id.to_json, JSON.generate(object, strict: true, as_json: :object_id)
+ assert_equal object.object_id.to_json, JSON.generate(object, strict: true, as_json: -> (o, is_key) { o.object_id })
+ end
+
+ def test_as_json_nan_does_not_call_to_json
+ def (obj = Object.new).to_json(*)
+ "null"
+ end
+ assert_raise(JSON::GeneratorError) do
+ JSON.generate(Float::NAN, strict: true, as_json: proc { obj })
+ end
+ end
+
+ def assert_float_roundtrip(expected, actual)
+ assert_equal(expected, JSON.generate(actual))
+ assert_equal(actual, JSON.parse(JSON.generate(actual)), "JSON: #{JSON.generate(actual)}")
end
def test_json_generate_float
- values = [-1.0, 1.0, 0.0, 12.2, 7.5 / 3.2, 12.0, 100.0, 1000.0]
- expecteds = ["-1.0", "1.0", "0.0", "12.2", "2.34375", "12.0", "100.0", "1000.0"]
+ assert_float_roundtrip "-1.0", -1.0
+ assert_float_roundtrip "1.0", 1.0
+ assert_float_roundtrip "0.0", 0.0
+ assert_float_roundtrip "12.2", 12.2
+ assert_float_roundtrip "2.34375", 7.5 / 3.2
+ assert_float_roundtrip "12.0", 12.0
+ assert_float_roundtrip "100.0", 100.0
+ assert_float_roundtrip "1000.0", 1000.0
+
+ if RUBY_ENGINE == "jruby"
+ assert_float_roundtrip "1.7468619377842371E9", 1746861937.7842371
+ else
+ assert_float_roundtrip "1746861937.7842371", 1746861937.7842371
+ end
- values.zip(expecteds).each do |value, expected|
- assert_equal expected, value.to_json
- end
+ if RUBY_ENGINE == "ruby"
+ assert_float_roundtrip "100000000000000.0", 100000000000000.0
+ assert_float_roundtrip "1e+15", 1e+15
+ assert_float_roundtrip "-100000000000000.0", -100000000000000.0
+ assert_float_roundtrip "-1e+15", -1e+15
+ assert_float_roundtrip "1111111111111111.1", 1111111111111111.1
+ assert_float_roundtrip "1.1111111111111112e+16", 11111111111111111.1
+ assert_float_roundtrip "-1111111111111111.1", -1111111111111111.1
+ assert_float_roundtrip "-1.1111111111111112e+16", -11111111111111111.1
+
+ assert_float_roundtrip "-0.000000022471348024634545", -2.2471348024634545e-08
+ assert_float_roundtrip "-0.0000000022471348024634545", -2.2471348024634545e-09
+ assert_float_roundtrip "-2.2471348024634546e-10", -2.2471348024634545e-10
+ end
end
def test_numbers_of_various_sizes
@@ -685,4 +1029,69 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal "[#{number}]", JSON.generate([number])
end
end
+
+ def test_generate_duplicate_keys_allowed
+ hash = { foo: 1, "foo" => 2 }
+ assert_equal %({"foo":1,"foo":2}), JSON.generate(hash, allow_duplicate_key: true)
+ end
+
+ def test_generate_duplicate_keys_deprecated
+ hash = { foo: 1, "foo" => 2 }
+ assert_deprecated_warning(/allow_duplicate_key/) do
+ assert_equal %({"foo":1,"foo":2}), JSON.generate(hash)
+ end
+ end
+
+ def test_generate_duplicate_keys_disallowed
+ hash = { foo: 1, "foo" => 2 }
+ error = assert_raise JSON::GeneratorError do
+ JSON.generate(hash, allow_duplicate_key: false)
+ end
+ assert_equal %(detected duplicate key "foo" in #{hash.inspect}), error.message
+ end
+
+ def test_frozen
+ state = JSON::State.new.freeze
+ assert_raise(FrozenError) do
+ state.configure(max_nesting: 1)
+ end
+ setters = state.methods.grep(/\w=$/)
+ assert_not_empty setters
+ setters.each do |setter|
+ assert_raise(FrozenError) do
+ state.send(setter, 1)
+ end
+ end
+ end
+
+ # The case when the State is frozen is tested in JSONCoderTest#test_nesting_recovery
+ def test_nesting_recovery
+ state = JSON::State.new
+ ary = []
+ ary << ary
+ assert_raise(JSON::NestingError) { state.generate(ary) }
+ assert_equal 0, state.depth
+ assert_equal '{"a":1}', state.generate({ a: 1 })
+ end
+
+ def test_negative_depth_raises
+ assert_raise(ArgumentError) do
+ JSON.generate({"a" => 1}, depth: -1)
+ end
+ assert_raise(ArgumentError) do
+ JSON.state.new(depth: -1)
+ end
+ end
+
+ def test_large_depth_raises
+ assert_raise(RangeError, ArgumentError) do
+ JSON.generate([[1]],
+ indent: " " * 5,
+ array_nl: "\n",
+ depth: 3_689_348_814_741_910_324,
+ max_nesting: 0
+ )
+ end
+ end
+
end
diff --git a/test/json/json_generic_object_test.rb b/test/json/json_generic_object_test.rb
index 471534192e..57e3bf3c52 100644
--- a/test/json/json_generic_object_test.rb
+++ b/test/json/json_generic_object_test.rb
@@ -1,10 +1,16 @@
# frozen_string_literal: true
require_relative 'test_helper'
-class JSONGenericObjectTest < Test::Unit::TestCase
+# ostruct is required to test JSON::GenericObject
+begin
+ require "ostruct"
+rescue LoadError
+ return
+end
+class JSONGenericObjectTest < Test::Unit::TestCase
def setup
- if defined?(GenericObject)
+ if defined?(JSON::GenericObject)
@go = JSON::GenericObject[ :a => 1, :b => 2 ]
else
omit("JSON::GenericObject is not available")
@@ -40,10 +46,10 @@ class JSONGenericObjectTest < Test::Unit::TestCase
)
assert_equal 1, l.a
assert_equal @go,
- l = JSON('{ "a": 1, "b": 2 }', :object_class => GenericObject)
+ l = JSON('{ "a": 1, "b": 2 }', :object_class => JSON::GenericObject)
assert_equal 1, l.a
- assert_equal GenericObject[:a => GenericObject[:b => 2]],
- l = JSON('{ "a": { "b": 2 } }', :object_class => GenericObject)
+ assert_equal JSON::GenericObject[:a => JSON::GenericObject[:b => 2]],
+ l = JSON('{ "a": { "b": 2 } }', :object_class => JSON::GenericObject)
assert_equal 2, l.a.b
end
end
@@ -51,12 +57,12 @@ class JSONGenericObjectTest < Test::Unit::TestCase
def test_from_hash
result = JSON::GenericObject.from_hash(
:foo => { :bar => { :baz => true }, :quux => [ { :foobar => true } ] })
- assert_kind_of GenericObject, result.foo
- assert_kind_of GenericObject, result.foo.bar
+ assert_kind_of JSON::GenericObject, result.foo
+ assert_kind_of JSON::GenericObject, result.foo.bar
assert_equal true, result.foo.bar.baz
- assert_kind_of GenericObject, result.foo.quux.first
+ assert_kind_of JSON::GenericObject, result.foo.quux.first
assert_equal true, result.foo.quux.first.foobar
- assert_equal true, GenericObject.from_hash(true)
+ assert_equal true, JSON::GenericObject.from_hash(true)
end
def test_json_generic_object_load
diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb
index 87b78fb0ca..292ca1a670 100644
--- a/test/json/json_parser_test.rb
+++ b/test/json/json_parser_test.rb
@@ -128,6 +128,18 @@ class JSONParserTest < Test::Unit::TestCase
assert_equal(1.0/0, parse('Infinity', :allow_nan => true))
assert_raise(ParserError) { parse('-Infinity') }
assert_equal(-1.0/0, parse('-Infinity', :allow_nan => true))
+ capture_output { assert_equal(Float::INFINITY, parse("23456789012E666")) }
+ end
+
+ def test_parse_bignum
+ bignum = Integer('1234567890' * 10)
+ assert_equal(bignum, JSON.parse(bignum.to_s))
+ assert_equal(bignum.to_f, JSON.parse(bignum.to_s + ".0"))
+
+ bignum = Integer('1234567890' * 50)
+ assert_equal(bignum, JSON.parse(bignum.to_s))
+ bignum_float = EnvUtil.suppress_warning { bignum.to_f }
+ assert_equal(bignum_float, EnvUtil.suppress_warning { JSON.parse(bignum.to_s + ".0") })
end
def test_parse_bigdecimals
@@ -157,6 +169,37 @@ class JSONParserTest < Test::Unit::TestCase
end
end
+ def test_parse_control_chars_in_string
+ 0.upto(31) do |ord|
+ assert_raise JSON::ParserError do
+ parse(%("#{ord.chr}"))
+ end
+ end
+ end
+
+ def test_parse_allowed_control_chars_in_string
+ 0.upto(31) do |ord|
+ assert_equal ord.chr, parse(%("#{ord.chr}"), allow_control_characters: true)
+ end
+ end
+
+ def test_parse_control_char_and_backslash
+ backslash_and_control_char = "\\\t"
+ assert_raise JSON::ParserError do
+ JSON.parse(%("#{'a' * 30}#{backslash_and_control_char}"), allow_control_characters: true, allow_invalid_escape: false)
+ end
+
+ JSON.parse(%("#{'a' * 30}#{backslash_and_control_char}"), allow_control_characters: true, allow_invalid_escape: true)
+ end
+
+ def test_parse_invalid_escape
+ assert_raise JSON::ParserError do
+ parse(%("fo\\o"))
+ end
+
+ assert_equal "foo", parse(%("fo\\o"), allow_invalid_escape: true)
+ end
+
def test_parse_arrays
assert_equal([1,2,3], parse('[1,2,3]'))
assert_equal([1.2,2,3], parse('[1.2,2,3]'))
@@ -318,6 +361,20 @@ class JSONParserTest < Test::Unit::TestCase
assert_raise(JSON::ParserError) { parse('"\u111___"') }
end
+ def test_unicode_followed_by_newline
+ # Ref: https://github.com/ruby/json/issues/912
+ assert_equal "🌌\n".bytes, JSON.parse('"\ud83c\udf0c\n"').bytes
+ assert_equal "🌌\n", JSON.parse('"\ud83c\udf0c\n"')
+ assert_predicate JSON.parse('"\ud83c\udf0c\n"'), :valid_encoding?
+ end
+
+ def test_invalid_surogates
+ assert_raise(JSON::ParserError) { parse('"\\uD800"') }
+ assert_raise(JSON::ParserError) { parse('"\\uD800_________________"') }
+ assert_raise(JSON::ParserError) { parse('"\\uD800\\u0041"') }
+ assert_raise(JSON::ParserError) { parse('"\\uD800\\u004') }
+ end
+
def test_parse_big_integers
json1 = JSON(orig = (1 << 31) - 1)
assert_equal orig, parse(json1)
@@ -331,6 +388,59 @@ class JSONParserTest < Test::Unit::TestCase
assert_equal orig, parse(json5)
end
+ def test_parse_escaped_key
+ doc = {
+ "test\r1" => 1,
+ "entries" => [
+ "test\t2" => 2,
+ "test\n3" => 3,
+ ]
+ }
+
+ assert_equal doc, parse(JSON.generate(doc))
+ end
+
+ def test_parse_duplicate_key
+ expected = {"a" => 2}
+ expected_sym = {a: 2}
+
+ assert_equal expected, parse('{"a": 1, "a": 2}', allow_duplicate_key: true)
+ assert_raise(ParserError) { parse('{"a": 1, "a": 2}', allow_duplicate_key: false) }
+ assert_raise(ParserError) { parse('{"a": 1, "a": 2}', allow_duplicate_key: false, symbolize_names: true) }
+
+ assert_deprecated_warning(/duplicate key "a"/) do
+ assert_equal expected, parse('{"a": 1, "a": 2}')
+ end
+ assert_deprecated_warning(/duplicate key "a"/) do
+ assert_equal expected_sym, parse('{"a": 1, "a": 2}', symbolize_names: true)
+ end
+
+ if RUBY_ENGINE == 'ruby'
+ assert_deprecated_warning(/#{File.basename(__FILE__)}\:#{__LINE__ + 1}/) do
+ assert_equal expected, parse('{"a": 1, "a": 2}')
+ end
+ end
+
+ unless RUBY_ENGINE == 'jruby'
+ assert_raise(ParserError) do
+ fake_key = Object.new
+ JSON.load('{"a": 1, "a": 2}', -> (obj) { obj == "a" ? fake_key : obj }, allow_duplicate_key: false)
+ end
+
+ assert_deprecated_warning(/duplicate key #<Object:0x/) do
+ fake_key = Object.new
+ JSON.load('{"a": 1, "a": 2}', -> (obj) { obj == "a" ? fake_key : obj })
+ end
+ end
+ end
+
+ def test_parse_duplicate_key_escape
+ error = assert_raise(ParserError) do
+ JSON.parse('{"%s%s%s%s":1,"%s%s%s%s":2}', allow_duplicate_key: false)
+ end
+ assert_match "%s%s%s%s", error.message
+ end
+
def test_some_wrong_inputs
assert_raise(ParserError) { parse('[] bla') }
assert_raise(ParserError) { parse('[] 1') }
@@ -362,10 +472,8 @@ class JSONParserTest < Test::Unit::TestCase
assert_predicate parse('[]', :freeze => true), :frozen?
assert_predicate parse('"foo"', :freeze => true), :frozen?
- if string_deduplication_available?
- assert_same(-'foo', parse('"foo"', :freeze => true))
- assert_same(-'foo', parse('{"foo": 1}', :freeze => true).keys.first)
- end
+ assert_same(-'foo', parse('"foo"', :freeze => true))
+ assert_same(-'foo', parse('{"foo": 1}', :freeze => true).keys.first)
end
def test_parse_comments
@@ -437,29 +545,117 @@ class JSONParserTest < Test::Unit::TestCase
end
def test_backslash
+ assert_raise(JSON::ParserError) do
+ JSON.parse('"\\')
+ end
+
data = [ '\\.(?i:gif|jpe?g|png)$' ]
json = '["\\\\.(?i:gif|jpe?g|png)$"]'
assert_equal data, parse(json)
- #
+
data = [ '\\"' ]
json = '["\\\\\""]'
assert_equal data, parse(json)
- #
+
json = '["/"]'
data = [ '/' ]
assert_equal data, parse(json)
- #
+
json = '["\""]'
data = ['"']
assert_equal data, parse(json)
- #
- json = '["\\\'"]'
- data = ["'"]
+
+ json = '["\\/"]'
+ data = ["/"]
assert_equal data, parse(json)
json = '["\/"]'
data = [ '/' ]
assert_equal data, parse(json)
+
+ data = ['"""""""""""""""""""""""""']
+ json = '["\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\""]'
+ assert_equal data, parse(json)
+
+ data = '["This is a "test" of the emergency broadcast system."]'
+ json = "\"[\\\"This is a \\\"test\\\" of the emergency broadcast system.\\\"]\""
+ assert_equal data, parse(json)
+
+ data = '\tThis is a test of the emergency broadcast system.'
+ json = "\"\\\\tThis is a test of the emergency broadcast system.\""
+ assert_equal data, parse(json)
+
+ data = 'This\tis a test of the emergency broadcast system.'
+ json = "\"This\\\\tis a test of the emergency broadcast system.\""
+ assert_equal data, parse(json)
+
+ data = 'This is\ta test of the emergency broadcast system.'
+ json = "\"This is\\\\ta test of the emergency broadcast system.\""
+ assert_equal data, parse(json)
+
+ data = 'This is a test of the emergency broadcast\tsystem.'
+ json = "\"This is a test of the emergency broadcast\\\\tsystem.\""
+ assert_equal data, parse(json)
+
+ data = 'This is a test of the emergency broadcast\tsystem.\n'
+ json = "\"This is a test of the emergency broadcast\\\\tsystem.\\\\n\""
+ assert_equal data, parse(json)
+
+ data = '"' * 15
+ json = "\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\""
+ assert_equal data, parse(json)
+
+ data = "\"\"\"\"\"\"\"\"\"\"\"\"\"\"a"
+ json = "\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"a\""
+ assert_equal data, parse(json)
+
+ data = "\u0001\u0001\u0001\u0001"
+ json = "\"\\u0001\\u0001\\u0001\\u0001\""
+ assert_equal data, parse(json)
+
+ data = "\u0001a\u0001a\u0001a\u0001a"
+ json = "\"\\u0001a\\u0001a\\u0001a\\u0001a\""
+ assert_equal data, parse(json)
+
+ data = "\u0001aa\u0001aa"
+ json = "\"\\u0001aa\\u0001aa\""
+ assert_equal data, parse(json)
+
+ data = "\u0001aa\u0001aa\u0001aa"
+ json = "\"\\u0001aa\\u0001aa\\u0001aa\""
+ assert_equal data, parse(json)
+
+ data = "\u0001aa\u0001aa\u0001aa\u0001aa\u0001aa\u0001aa"
+ json = "\"\\u0001aa\\u0001aa\\u0001aa\\u0001aa\\u0001aa\\u0001aa\""
+ assert_equal data, parse(json)
+
+ data = "\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002\u0001a\u0002"
+ json = "\"\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\\u0001a\\u0002\""
+ assert_equal data, parse(json)
+
+ data = "ab\u0002c"
+ json = "\"ab\\u0002c\""
+ assert_equal data, parse(json)
+
+ data = "ab\u0002cab\u0002cab\u0002cab\u0002c"
+ json = "\"ab\\u0002cab\\u0002cab\\u0002cab\\u0002c\""
+ assert_equal data, parse(json)
+
+ data = "ab\u0002cab\u0002cab\u0002cab\u0002cab\u0002cab\u0002c"
+ json = "\"ab\\u0002cab\\u0002cab\\u0002cab\\u0002cab\\u0002cab\\u0002c\""
+ assert_equal data, parse(json)
+
+ data = "\n\t\f\b\n\t\f\b\n\t\f\b\n\t\f"
+ json = "\"\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\""
+ assert_equal data, parse(json)
+
+ data = "\n\t\f\b\n\t\f\b\n\t\f\b\n\t\f\b"
+ json = "\"\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\""
+ assert_equal data, parse(json)
+
+ data = "a\n\t\f\b\n\t\f\b\n\t\f\b\n\t"
+ json = "\"a\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\\f\\b\\n\\t\""
+ assert_equal data, parse(json)
end
class SubArray < Array
@@ -518,6 +714,7 @@ class JSONParserTest < Test::Unit::TestCase
def test_parse_array_custom_non_array_derived_class
res = parse('[1,2]', :array_class => SubArrayWrapper)
assert_equal([1,2], res.data)
+ assert_equal(1, res[0])
assert_equal(SubArrayWrapper, res.class)
assert res.shifted?
end
@@ -579,6 +776,7 @@ class JSONParserTest < Test::Unit::TestCase
def test_parse_object_custom_non_hash_derived_class
res = parse('{"foo":"bar"}', :object_class => SubOpenStruct)
assert_equal "bar", res.foo
+ assert_equal "bar", res[:foo]
assert_equal(SubOpenStruct, res.class)
assert res.item_set?
end
@@ -638,7 +836,7 @@ class JSONParserTest < Test::Unit::TestCase
error = assert_raise(JSON::ParserError) do
JSON.parse('{"foo": ' + ('A' * 500) + '}')
end
- assert_operator 60, :>, error.message.bytesize
+ assert_operator 80, :>, error.message.bytesize
end
def test_parse_error_incomplete_hash
@@ -646,7 +844,7 @@ class JSONParserTest < Test::Unit::TestCase
JSON.parse('{"input":{"firstName":"Bob","lastName":"Mob","email":"bob@example.com"}')
end
if RUBY_ENGINE == "ruby"
- assert_equal %(expected ',' or '}' after object value, got: ''), error.message
+ assert_equal %(expected ',' or '}' after object value, got: EOF at line 1 column 72), error.message
end
end
@@ -654,16 +852,16 @@ class JSONParserTest < Test::Unit::TestCase
omit "C ext only test" unless RUBY_ENGINE == "ruby"
error = assert_raise(JSON::ParserError) { JSON.parse("あああああああああああああああああああああああ") }
- assert_equal "unexpected character: 'ああああああああああ'", error.message
+ assert_equal "unexpected character: 'ああああああああああ' at line 1 column 1", error.message
error = assert_raise(JSON::ParserError) { JSON.parse("aあああああああああああああああああああああああ") }
- assert_equal "unexpected character: 'aああああああああああ'", error.message
+ assert_equal "unexpected character: 'aああああああああああ' at line 1 column 1", error.message
error = assert_raise(JSON::ParserError) { JSON.parse("abあああああああああああああああああああああああ") }
- assert_equal "unexpected character: 'abあああああああああ'", error.message
+ assert_equal "unexpected character: 'abあああああああああ' at line 1 column 1", error.message
error = assert_raise(JSON::ParserError) { JSON.parse("abcあああああああああああああああああああああああ") }
- assert_equal "unexpected character: 'abcあああああああああ'", error.message
+ assert_equal "unexpected character: 'abcあああああああああ' at line 1 column 1", error.message
end
def test_parse_leading_slash
@@ -673,18 +871,35 @@ class JSONParserTest < Test::Unit::TestCase
end
end
- private
+ def test_parse_whitespace_after_newline
+ assert_equal [], JSON.parse("[\n#{' ' * (8 + 8 + 4 + 3)}]")
+ end
+
+ def test_frozen
+ parser_config = JSON::Parser::Config.new({}).freeze
+ assert_raise FrozenError do
+ parser_config.send(:initialize, {})
+ end
+ end
+
+ def test_mutating_source_string_during_parsing
+ expected = ([1] * 100) + [2.3] + ([1] * 100)
+ source = JSON.generate(expected)
+ expected.delete_at(100)
- def string_deduplication_available?
- r1 = rand.to_s
- r2 = r1.dup
- begin
- (-r1).equal?(-r2)
- rescue NoMethodError
- false # No String#-@
+ fake_decimal_class = Class.new
+ fake_decimal_class.define_method(:initialize) do |number|
+ source.tr!('1', '0')
+ number.to_f
end
+
+ actual = JSON.parse(source, decimal_class: fake_decimal_class)
+ actual.delete_at(100)
+ assert_equal expected, actual
end
+ private
+
def assert_equal_float(expected, actual, delta = 1e-2)
Array === expected and expected = expected.first
Array === actual and actual = actual.first
diff --git a/test/json/json_ryu_fallback_test.rb b/test/json/json_ryu_fallback_test.rb
new file mode 100644
index 0000000000..a61b3e668d
--- /dev/null
+++ b/test/json/json_ryu_fallback_test.rb
@@ -0,0 +1,191 @@
+# frozen_string_literal: true
+require_relative 'test_helper'
+begin
+ require 'bigdecimal'
+rescue LoadError
+end
+
+class JSONRyuFallbackTest < Test::Unit::TestCase
+ include JSON
+
+ # Test that numbers with more than 17 significant digits fall back to rb_cstr_to_dbl
+ def test_more_than_17_significant_digits
+ # These numbers have > 17 significant digits and should use fallback path
+ # They should still parse correctly, just not via the Ryu optimization
+
+ test_cases = [
+ # input, expected (rounded to double precision)
+ ["1.23456789012345678901234567890", 1.2345678901234567],
+ ["123456789012345678.901234567890", 1.2345678901234568e+17],
+ ["0.123456789012345678901234567890", 0.12345678901234568],
+ ["9999999999999999999999999999.9", 1.0e+28],
+ # Edge case: exactly 18 digits
+ ["123456789012345678", 123456789012345680.0],
+ # Many fractional digits
+ ["0.12345678901234567890123456789", 0.12345678901234568],
+ ]
+
+ test_cases.each do |input, expected|
+ result = JSON.parse(input)
+ assert_in_delta(expected, result, 1e-10,
+ "Failed to parse #{input} correctly (>17 digits, fallback path)")
+ end
+ end
+
+ # Test decimal_class option forces fallback
+ def test_decimal_class_option
+ input = "3.141"
+
+ # Without decimal_class: uses Ryu, returns Float
+ result_float = JSON.parse(input)
+ assert_instance_of(Float, result_float)
+ assert_equal(3.141, result_float)
+
+ # With decimal_class: uses fallback, returns BigDecimal
+ result_bigdecimal = JSON.parse(input, decimal_class: BigDecimal)
+ assert_instance_of(BigDecimal, result_bigdecimal)
+ assert_equal(BigDecimal("3.141"), result_bigdecimal)
+ end if defined?(::BigDecimal)
+
+ # Test that numbers with <= 17 digits use Ryu optimization
+ def test_ryu_optimization_used_for_normal_numbers
+ test_cases = [
+ ["3.141", 3.141],
+ ["1.23456789012345e100", 1.23456789012345e100],
+ ["0.00000000000001", 1.0e-14],
+ ["123456789012345.67", 123456789012345.67],
+ ["-1.7976931348623157e+308", -1.7976931348623157e+308],
+ ["2.2250738585072014e-308", 2.2250738585072014e-308],
+ # Exactly 17 significant digits
+ ["12345678901234567", 12345678901234567.0],
+ ["1.2345678901234567", 1.2345678901234567],
+ ]
+
+ test_cases.each do |input, expected|
+ result = JSON.parse(input)
+ assert_in_delta(expected, result, expected.abs * 1e-15,
+ "Failed to parse #{input} correctly (<=17 digits, Ryu path)")
+ end
+ end
+
+ # Test edge cases at the boundary (17 digits)
+ def test_seventeen_digit_boundary
+ # Exactly 17 significant digits should use Ryu
+ input_17 = "12345678901234567.0" # Force it to be a float with .0
+ result = JSON.parse(input_17)
+ assert_in_delta(12345678901234567.0, result, 1e-10)
+
+ # 18 significant digits should use fallback
+ input_18 = "123456789012345678.0"
+ result = JSON.parse(input_18)
+ # Note: This will be rounded to double precision
+ assert_in_delta(123456789012345680.0, result, 1e-10)
+ end
+
+ # Test that leading zeros don't count toward the 17-digit limit
+ def test_leading_zeros_dont_count
+ test_cases = [
+ ["0.00012345678901234567", 0.00012345678901234567], # 17 significant digits
+ ["0.000000000000001234567890123456789", 1.234567890123457e-15], # >17 significant
+ ]
+
+ test_cases.each do |input, expected|
+ result = JSON.parse(input)
+ assert_in_delta(expected, result, expected.abs * 1e-10,
+ "Failed to parse #{input} correctly")
+ end
+ end
+
+ # Test that Ryu handles special values correctly
+ def test_special_double_values
+ test_cases = [
+ ["1.7976931348623157e+308", Float::MAX], # Largest finite double
+ ["2.2250738585072014e-308", Float::MIN], # Smallest normalized double
+ ]
+
+ test_cases.each do |input, expected|
+ result = JSON.parse(input)
+ assert_in_delta(expected, result, expected.abs * 1e-10,
+ "Failed to parse #{input} correctly")
+ end
+
+ # Test zero separately
+ result_pos_zero = JSON.parse("0.0")
+ assert_equal(0.0, result_pos_zero)
+
+ # Note: JSON.parse doesn't preserve -0.0 vs +0.0 distinction in standard mode
+ result_neg_zero = JSON.parse("-0.0")
+ assert_equal(0.0, result_neg_zero.abs)
+ end
+
+ # Test subnormal numbers that caused precision issues before fallback was added
+ # These are extreme edge cases discovered by fuzzing (4 in 6 billion numbers tested)
+ def test_subnormal_edge_cases_round_trip
+ # These subnormal numbers (~1e-310) had 1 ULP rounding errors in original Ryu
+ # They now use rb_cstr_to_dbl fallback for exact precision
+ test_cases = [
+ "-3.2652630314355e-310",
+ "3.9701623107025e-310",
+ "-3.6607772435415e-310",
+ "2.9714076801985e-310",
+ ]
+
+ test_cases.each do |input|
+ # Parse the number
+ result = JSON.parse(input)
+
+ # Should be bit-identical
+ assert_equal(result, JSON.parse(result.to_s),
+ "Subnormal #{input} failed round-trip test")
+
+ # Should be bit-identical
+ assert_equal(result, JSON.parse(JSON.dump(result)),
+ "Subnormal #{input} failed round-trip test")
+
+ # Verify the value is in the expected subnormal range
+ assert(result.abs < 2.225e-308,
+ "#{input} should be subnormal (< 2.225e-308)")
+ end
+ end
+
+ # Test invalid numbers are properly rejected
+ def test_invalid_numbers_rejected
+ invalid_cases = [
+ "-",
+ ".",
+ "-.",
+ "-.e10",
+ "1.2.3",
+ "1e",
+ "1e+",
+ ]
+
+ invalid_cases.each do |input|
+ assert_raise(JSON::ParserError, "Should reject invalid number: #{input}") do
+ JSON.parse(input)
+ end
+ end
+ end
+
+ def test_large_exponent_numbers
+ assert_equal Float::INFINITY, JSON.parse("1e4294967296")
+ assert_equal 0.0, JSON.parse("1e-4294967296")
+ assert_equal 0.0, JSON.parse("99999999999999999e-4294967296")
+ assert_equal Float::INFINITY, JSON.parse("1e4294967295")
+ assert_equal Float::INFINITY, JSON.parse("1e4294967297")
+
+ assert_equal(-Float::INFINITY, JSON.parse("-1e4294967296"))
+ assert_equal(-0.0, JSON.parse("-1e-4294967296"))
+ assert_equal(-0.0, JSON.parse("-99999999999999999e-4294967296"))
+ assert_equal(-Float::INFINITY, JSON.parse("-1e4294967295"))
+ assert_equal(-Float::INFINITY, JSON.parse("-1e4294967297"))
+
+ assert_equal(Float::INFINITY, JSON.parse("1e9223372036854775808"))
+ assert_equal(Float::INFINITY, JSON.parse("1e9999999999999999999"))
+ assert_equal(Float::INFINITY, JSON.parse("1e18446744073709551616"))
+ assert_equal(Float::INFINITY, JSON.parse("1e10000000000000000000"))
+ assert_equal(Float::INFINITY, JSON.parse("1e184467440737095516160"))
+ assert_equal 0.0, JSON.parse("1e-18446744073709551615")
+ assert_equal 0.0, JSON.parse("1e-9223372036854775809")
+ end
+end
diff --git a/test/json/ractor_test.rb b/test/json/ractor_test.rb
index f857c9a8bf..e53c405a74 100644
--- a/test/json/ractor_test.rb
+++ b/test/json/ractor_test.rb
@@ -8,8 +8,19 @@ rescue LoadError
end
class JSONInRactorTest < Test::Unit::TestCase
+ unless Ractor.method_defined?(:value)
+ module RactorBackport
+ refine Ractor do
+ alias_method :value, :take
+ end
+ end
+
+ using RactorBackport
+ end
+
def test_generate
pid = fork do
+ Warning[:experimental] = false
r = Ractor.new do
json = JSON.generate({
'a' => 2,
@@ -25,14 +36,14 @@ class JSONInRactorTest < Test::Unit::TestCase
end
expected_json = JSON.parse('{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
'"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}')
- actual_json = r.take
+ actual_json = r.value
if expected_json == actual_json
exit 0
else
puts "Expected:"
puts expected_json
- puts "Acutual:"
+ puts "Actual:"
puts actual_json
puts
exit 1
@@ -41,4 +52,63 @@ class JSONInRactorTest < Test::Unit::TestCase
_, status = Process.waitpid2(pid)
assert_predicate status, :success?
end
+
+ def test_coder
+ coder = JSON::Coder.new.freeze
+ assert Ractor.shareable?(coder)
+ pid = fork do
+ Warning[:experimental] = false
+ r = Ractor.new(coder) do |coder|
+ json = coder.dump({
+ 'a' => 2,
+ 'b' => 3.141,
+ 'c' => 'c',
+ 'd' => [ 1, "b", 3.14 ],
+ 'e' => { 'foo' => 'bar' },
+ 'g' => "\"\0\037",
+ 'h' => 1000.0,
+ 'i' => 0.001
+ })
+ coder.load(json)
+ end
+ expected_json = JSON.parse('{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
+ '"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}')
+ actual_json = r.value
+
+ if expected_json == actual_json
+ exit 0
+ else
+ puts "Expected:"
+ puts expected_json
+ puts "Actual:"
+ puts actual_json
+ puts
+ exit 1
+ end
+ end
+ _, status = Process.waitpid2(pid)
+ assert_predicate status, :success?
+ end
+
+ class NonNative
+ def initialize(value)
+ @value = value
+ end
+ end
+
+ def test_coder_proc
+ block = Ractor.shareable_proc { |value| value.as_json }
+ coder = JSON::Coder.new(&block).freeze
+ assert Ractor.shareable?(coder)
+
+ pid = fork do
+ Warning[:experimental] = false
+ assert_equal [{}], Ractor.new(coder) { |coder|
+ coder.load('[{}]')
+ }.value
+ end
+
+ _, status = Process.waitpid2(pid)
+ assert_predicate status, :success?
+ end if Ractor.respond_to?(:shareable_proc)
end if defined?(Ractor) && Process.respond_to?(:fork)
diff --git a/test/json/test_helper.rb b/test/json/test_helper.rb
index d849e28b9b..4c5a91a192 100644
--- a/test/json/test_helper.rb
+++ b/test/json/test_helper.rb
@@ -1,5 +1,30 @@
$LOAD_PATH.unshift(File.expand_path('../../../ext', __FILE__), File.expand_path('../../../lib', __FILE__))
+if ENV["JSON_COVERAGE"]
+ # This test helper is loaded inside Ruby's own test suite, so we try to not mess it up.
+ require 'coverage'
+
+ branches_supported = Coverage.respond_to?(:supported?) && Coverage.supported?(:branches)
+
+ # Coverage module must be started before SimpleCov to work around the cyclic require order.
+ # Track both branches and lines, or else SimpleCov misleadingly reports 0/0 = 100% for non-branching files.
+ Coverage.start(lines: true,
+ branches: branches_supported)
+
+ require 'simplecov'
+ SimpleCov.start do
+ # Enabling both coverage types to let SimpleCov know to output them together in reports
+ enable_coverage :line
+ enable_coverage :branch if branches_supported
+
+ # Can't always trust SimpleCov to find files implicitly
+ track_files 'lib/**/*.rb'
+
+ add_filter 'lib/json/truffle_ruby' unless RUBY_ENGINE == 'truffleruby'
+ add_filter 'test/'
+ end
+end
+
require 'json'
require 'test/unit'
diff --git a/test/lib/jit_support.rb b/test/lib/jit_support.rb
index 1b15f685a0..386a5a6f1e 100644
--- a/test/lib/jit_support.rb
+++ b/test/lib/jit_support.rb
@@ -10,10 +10,20 @@ module JITSupport
end
def yjit_enabled?
- defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled?
+ defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
end
def yjit_force_enabled?
"#{RbConfig::CONFIG['CFLAGS']} #{RbConfig::CONFIG['CPPFLAGS']}".match?(/(\A|\s)-D ?YJIT_FORCE_ENABLE\b/)
end
+
+ def zjit_supported?
+ return @zjit_supported if defined?(@zjit_supported)
+ # nil in mswin
+ @zjit_supported = ![nil, 'no'].include?(RbConfig::CONFIG['ZJIT_SUPPORT'])
+ end
+
+ def zjit_enabled?
+ defined?(RubyVM::ZJIT) && RubyVM::ZJIT.enabled?
+ end
end
diff --git a/test/mkmf/test_egrep_cpp.rb b/test/mkmf/test_egrep_cpp.rb
index 7ac0e60010..1126324965 100644
--- a/test/mkmf/test_egrep_cpp.rb
+++ b/test/mkmf/test_egrep_cpp.rb
@@ -10,4 +10,18 @@ class TestMkmfEgrepCpp < TestMkmf
def test_not_have_func
assert_equal(false, egrep_cpp(/never match/, ""), MKMFLOG)
end
+
+ class TestMkmfEgrepCxx < self
+ def test_cxx_egrep_cpp
+ assert_equal(true, MakeMakefile["C++"].egrep_cpp(/^ok/, <<~SRC), MKMFLOG)
+ #ifdef __cplusplus
+ ok
+ #else
+ #error not C++
+ #endif
+ SRC
+ rescue Errno::ENOENT
+ omit "C++ compiler not available: #{$!.message}"
+ end
+ end
end
diff --git a/test/mkmf/test_pkg_config.rb b/test/mkmf/test_pkg_config.rb
index f6a960c7d9..adf5fa6e92 100644
--- a/test/mkmf/test_pkg_config.rb
+++ b/test/mkmf/test_pkg_config.rb
@@ -46,21 +46,26 @@ class TestMkmfPkgConfig < TestMkmf
def test_pkgconfig_with_libs_option_returns_output
pend("skipping because pkg-config is not installed") unless PKG_CONFIG
expected = ["-L#{@fixtures_lib_dir}", "-ltest1-public"].sort
- actual = pkg_config("test1", "libs").shellsplit.sort
- assert_equal(expected, actual, MKMFLOG)
+ actual = pkg_config("test1", "libs")
+ assert_equal_sorted(expected, actual, MKMFLOG)
end
def test_pkgconfig_with_cflags_option_returns_output
pend("skipping because pkg-config is not installed") unless PKG_CONFIG
expected = ["--cflags-other", "-I#{@fixtures_inc_dir}/cflags-I"].sort
- actual = pkg_config("test1", "cflags").shellsplit.sort
- assert_equal(expected, actual, MKMFLOG)
+ actual = pkg_config("test1", "cflags")
+ assert_equal_sorted(expected, actual, MKMFLOG)
end
def test_pkgconfig_with_multiple_options
pend("skipping because pkg-config is not installed") unless PKG_CONFIG
expected = ["-L#{@fixtures_lib_dir}", "-ltest1-public", "-ltest1-private"].sort
- actual = pkg_config("test1", "libs", "static").shellsplit.sort
- assert_equal(expected, actual, MKMFLOG)
+ actual = pkg_config("test1", "libs", "static")
+ assert_equal_sorted(expected, actual, MKMFLOG)
+ end
+
+ private def assert_equal_sorted(expected, actual, msg = nil)
+ actual = actual.shellsplit.sort if actual
+ assert_equal(expected, actual, msg)
end
end
diff --git a/test/monitor/test_monitor.rb b/test/monitor/test_monitor.rb
index 4c55afca6c..7a26831baf 100644
--- a/test/monitor/test_monitor.rb
+++ b/test/monitor/test_monitor.rb
@@ -274,7 +274,7 @@ class TestMonitor < Test::Unit::TestCase
@monitor.synchronize do
queue2.enq(nil)
assert_equal("foo", b)
- result2 = cond.wait(0.1)
+ result2 = cond.wait(10)
assert_equal(true, result2)
assert_equal("bar", b)
end
diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb
index a49cc87e8d..4e7fa22756 100644
--- a/test/net/http/test_http.rb
+++ b/test/net/http/test_http.rb
@@ -494,12 +494,10 @@ module TestNetHTTP_version_1_1_methods
def test_s_post
url = "http://#{config('host')}:#{config('port')}/?q=a"
- res = assert_warning(/Content-Type did not set/) do
- Net::HTTP.post(
- URI.parse(url),
- "a=x")
- end
- assert_equal "application/x-www-form-urlencoded", res["Content-Type"]
+ res = Net::HTTP.post(
+ URI.parse(url),
+ "a=x")
+ assert_equal "application/octet-stream", res["Content-Type"]
assert_equal "a=x", res.body
assert_equal url, res["X-request-uri"]
@@ -565,14 +563,12 @@ module TestNetHTTP_version_1_1_methods
conn = Net::HTTP.new('localhost', port)
conn.write_timeout = EnvUtil.apply_timeout_scale(0.01)
conn.read_timeout = EnvUtil.apply_timeout_scale(0.01) if windows?
- conn.open_timeout = EnvUtil.apply_timeout_scale(0.1)
+ conn.open_timeout = EnvUtil.apply_timeout_scale(1)
th = Thread.new do
err = !windows? ? Net::WriteTimeout : Net::ReadTimeout
assert_raise(err) do
- assert_warning(/Content-Type did not set/) do
- conn.post('/', "a"*50_000_000)
- end
+ conn.post('/', "a"*50_000_000)
end
end
assert th.join(EnvUtil.apply_timeout_scale(10))
@@ -589,9 +585,9 @@ module TestNetHTTP_version_1_1_methods
port = server.addr[1]
conn = Net::HTTP.new('localhost', port)
- conn.write_timeout = 0.01
- conn.read_timeout = 0.01 if windows?
- conn.open_timeout = 0.1
+ conn.write_timeout = EnvUtil.apply_timeout_scale(0.01)
+ conn.read_timeout = EnvUtil.apply_timeout_scale(0.01) if windows?
+ conn.open_timeout = EnvUtil.apply_timeout_scale(1)
req = Net::HTTP::Post.new('/')
data = "a"*50_000_000
@@ -1404,3 +1400,28 @@ class TestNetHTTPPartialResponse < Test::Unit::TestCase
assert_raise(EOFError) {http.get('/')}
end
end
+
+class TestNetHTTPInRactor < Test::Unit::TestCase
+ CONFIG = {
+ 'host' => '127.0.0.1',
+ 'proxy_host' => nil,
+ 'proxy_port' => nil,
+ }
+
+ include TestNetHTTPUtils
+
+ def test_get
+ assert_ractor(<<~RUBY, require: 'net/http')
+ expected = #{$test_net_http_data.dump}.b
+ ret = Ractor.new {
+ host = #{config('host').dump}
+ port = #{config('port')}
+ Net::HTTP.start(host, port) { |http|
+ res = http.get('/')
+ res.body
+ }
+ }.value
+ assert_equal expected, ret
+ RUBY
+ end
+end if defined?(Ractor) && Ractor.method_defined?(:value)
diff --git a/test/net/http/test_http_request.rb b/test/net/http/test_http_request.rb
index 7fd82b0353..9f5cf4f8f5 100644
--- a/test/net/http/test_http_request.rb
+++ b/test/net/http/test_http_request.rb
@@ -74,6 +74,18 @@ class HTTPRequestTest < Test::Unit::TestCase
assert_equal "/foo", req.path
assert_equal "example.com", req['Host']
+ req = Net::HTTP::Get.new(URI("https://203.0.113.1/foo"))
+ assert_equal "/foo", req.path
+ assert_equal "203.0.113.1", req['Host']
+
+ req = Net::HTTP::Get.new(URI("https://203.0.113.1:8000/foo"))
+ assert_equal "/foo", req.path
+ assert_equal "203.0.113.1:8000", req['Host']
+
+ req = Net::HTTP::Get.new(URI("https://[2001:db8::1]:8000/foo"))
+ assert_equal "/foo", req.path
+ assert_equal "[2001:db8::1]:8000", req['Host']
+
assert_raise(ArgumentError){ Net::HTTP::Get.new(URI("urn:ietf:rfc:7231")) }
assert_raise(ArgumentError){ Net::HTTP::Get.new(URI("http://")) }
end
@@ -89,5 +101,25 @@ class HTTPRequestTest < Test::Unit::TestCase
'Bug #7831 - do not decode content if the user overrides'
end if Net::HTTP::HAVE_ZLIB
+ def test_update_uri
+ req = Net::HTTP::Get.new(URI.parse("http://203.0.113.1"))
+ req.update_uri("test", 8080, false)
+ assert_equal "203.0.113.1", req.uri.host
+ assert_equal 8080, req.uri.port
+
+ req = Net::HTTP::Get.new(URI.parse("http://203.0.113.1:2020"))
+ req.update_uri("test", 8080, false)
+ assert_equal "203.0.113.1", req.uri.host
+ assert_equal 8080, req.uri.port
+
+ req = Net::HTTP::Get.new(URI.parse("http://[2001:db8::1]"))
+ req.update_uri("test", 8080, false)
+ assert_equal "[2001:db8::1]", req.uri.host
+ assert_equal 8080, req.uri.port
+
+ req = Net::HTTP::Get.new(URI.parse("http://[2001:db8::1]:2020"))
+ req.update_uri("test", 8080, false)
+ assert_equal "[2001:db8::1]", req.uri.host
+ assert_equal 8080, req.uri.port
+ end
end
-
diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb
index e860c8745e..f5b21b901f 100644
--- a/test/net/http/test_https.rb
+++ b/test/net/http/test_https.rb
@@ -7,6 +7,8 @@ rescue LoadError
# should skip this test
end
+return unless defined?(OpenSSL::SSL)
+
class TestNetHTTPS < Test::Unit::TestCase
include TestNetHTTPUtils
@@ -19,7 +21,6 @@ class TestNetHTTPS < Test::Unit::TestCase
CA_CERT = OpenSSL::X509::Certificate.new(read_fixture("cacert.pem"))
SERVER_KEY = OpenSSL::PKey.read(read_fixture("server.key"))
SERVER_CERT = OpenSSL::X509::Certificate.new(read_fixture("server.crt"))
- DHPARAMS = OpenSSL::PKey::DH.new(read_fixture("dhparams.pem"))
TEST_STORE = OpenSSL::X509::Store.new.tap {|s| s.add_cert(CA_CERT) }
CONFIG = {
@@ -29,25 +30,16 @@ class TestNetHTTPS < Test::Unit::TestCase
'ssl_enable' => true,
'ssl_certificate' => SERVER_CERT,
'ssl_private_key' => SERVER_KEY,
- 'ssl_tmp_dh_callback' => proc { DHPARAMS },
}
def test_get
http = Net::HTTP.new(HOST, config("port"))
http.use_ssl = true
http.cert_store = TEST_STORE
- certs = []
- http.verify_callback = Proc.new do |preverify_ok, store_ctx|
- certs << store_ctx.current_cert
- preverify_ok
- end
http.request_get("/") {|res|
assert_equal($test_net_http_data, res.body)
+ assert_equal(SERVER_CERT.to_der, http.peer_cert.to_der)
}
- # TODO: OpenSSL 1.1.1h seems to yield only SERVER_CERT; need to check the incompatibility
- certs.zip([CA_CERT, SERVER_CERT][-certs.size..-1]) do |actual, expected|
- assert_equal(expected.to_der, actual.to_der)
- end
end
def test_get_SNI
@@ -55,18 +47,10 @@ class TestNetHTTPS < Test::Unit::TestCase
http.ipaddr = config('host')
http.use_ssl = true
http.cert_store = TEST_STORE
- certs = []
- http.verify_callback = Proc.new do |preverify_ok, store_ctx|
- certs << store_ctx.current_cert
- preverify_ok
- end
http.request_get("/") {|res|
assert_equal($test_net_http_data, res.body)
+ assert_equal(SERVER_CERT.to_der, http.peer_cert.to_der)
}
- # TODO: OpenSSL 1.1.1h seems to yield only SERVER_CERT; need to check the incompatibility
- certs.zip([CA_CERT, SERVER_CERT][-certs.size..-1]) do |actual, expected|
- assert_equal(expected.to_der, actual.to_der)
- end
end
def test_get_SNI_proxy
@@ -78,11 +62,6 @@ class TestNetHTTPS < Test::Unit::TestCase
http.ipaddr = "192.0.2.1"
http.use_ssl = true
http.cert_store = TEST_STORE
- certs = []
- http.verify_callback = Proc.new do |preverify_ok, store_ctx|
- certs << store_ctx.current_cert
- preverify_ok
- end
begin
http.start
rescue EOFError
@@ -114,11 +93,6 @@ class TestNetHTTPS < Test::Unit::TestCase
http.ipaddr = config('host')
http.use_ssl = true
http.cert_store = TEST_STORE
- certs = []
- http.verify_callback = Proc.new do |preverify_ok, store_ctx|
- certs << store_ctx.current_cert
- preverify_ok
- end
@log_tester = lambda {|_| }
assert_raise(OpenSSL::SSL::SSLError){ http.start }
end
@@ -135,10 +109,6 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_session_reuse
- # FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h.
- # See https://github.com/openssl/openssl/pull/5967 for details.
- omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 1.1.0h')
-
http = Net::HTTP.new(HOST, config("port"))
http.use_ssl = true
http.cert_store = TEST_STORE
@@ -165,9 +135,6 @@ class TestNetHTTPS < Test::Unit::TestCase
end
def test_session_reuse_but_expire
- # FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h.
- omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 1.1.0h')
-
http = Net::HTTP.new(HOST, config("port"))
http.use_ssl = true
http.cert_store = TEST_STORE
@@ -240,6 +207,21 @@ class TestNetHTTPS < Test::Unit::TestCase
assert_match(/certificate verify failed/, ex.message)
end
+ def test_verify_callback
+ http = Net::HTTP.new(HOST, config("port"))
+ http.use_ssl = true
+ http.cert_store = TEST_STORE
+ certs = []
+ http.verify_callback = Proc.new {|preverify_ok, store_ctx|
+ certs << store_ctx.current_cert
+ preverify_ok
+ }
+ http.request_get("/") {|res|
+ assert_equal($test_net_http_data, res.body)
+ }
+ assert_equal(SERVER_CERT.to_der, certs.last.to_der)
+ end
+
def test_timeout_during_SSL_handshake
bug4246 = "expected the SSL connection to have timed out but have not. [ruby-core:34203]"
@@ -275,9 +257,7 @@ class TestNetHTTPS < Test::Unit::TestCase
http = Net::HTTP.new(HOST, config("port"))
http.use_ssl = true
http.max_version = :SSL2
- http.verify_callback = Proc.new do |preverify_ok, store_ctx|
- true
- end
+ http.cert_store = TEST_STORE
@log_tester = lambda {|_| }
ex = assert_raise(OpenSSL::SSL::SSLError){
http.request_get("/") {|res| }
@@ -286,7 +266,25 @@ class TestNetHTTPS < Test::Unit::TestCase
assert_match(re_msg, ex.message)
end
-end if defined?(OpenSSL::SSL)
+ def test_ractor
+ assert_ractor(<<~RUBY, require: 'net/https')
+ expected = #{$test_net_http_data.dump}.b
+ ret = Ractor.new {
+ host = #{HOST.dump}
+ port = #{config('port')}
+ ca_cert_pem = #{CA_CERT.to_pem.dump}
+ cert_store = OpenSSL::X509::Store.new.tap { |s|
+ s.add_cert(OpenSSL::X509::Certificate.new(ca_cert_pem))
+ }
+ Net::HTTP.start(host, port, use_ssl: true, cert_store: cert_store) { |http|
+ res = http.get('/')
+ res.body
+ }
+ }.value
+ assert_equal expected, ret
+ RUBY
+ end if defined?(Ractor) && Ractor.method_defined?(:value)
+end
class TestNetHTTPSIdentityVerifyFailure < Test::Unit::TestCase
include TestNetHTTPUtils
@@ -300,7 +298,6 @@ class TestNetHTTPSIdentityVerifyFailure < Test::Unit::TestCase
CA_CERT = OpenSSL::X509::Certificate.new(read_fixture("cacert.pem"))
SERVER_KEY = OpenSSL::PKey.read(read_fixture("server.key"))
SERVER_CERT = OpenSSL::X509::Certificate.new(read_fixture("server.crt"))
- DHPARAMS = OpenSSL::PKey::DH.new(read_fixture("dhparams.pem"))
TEST_STORE = OpenSSL::X509::Store.new.tap {|s| s.add_cert(CA_CERT) }
CONFIG = {
@@ -310,7 +307,6 @@ class TestNetHTTPSIdentityVerifyFailure < Test::Unit::TestCase
'ssl_enable' => true,
'ssl_certificate' => SERVER_CERT,
'ssl_private_key' => SERVER_KEY,
- 'ssl_tmp_dh_callback' => proc { DHPARAMS },
}
def test_identity_verify_failure
@@ -326,4 +322,4 @@ class TestNetHTTPSIdentityVerifyFailure < Test::Unit::TestCase
re_msg = /certificate verify failed|hostname \"#{HOST_IP}\" does not match/
assert_match(re_msg, ex.message)
end
-end if defined?(OpenSSL::SSL)
+end
diff --git a/test/net/http/test_https_proxy.rb b/test/net/http/test_https_proxy.rb
index f4c6aa0b6a..237c16e64d 100644
--- a/test/net/http/test_https_proxy.rb
+++ b/test/net/http/test_https_proxy.rb
@@ -5,14 +5,10 @@ rescue LoadError
end
require 'test/unit'
+return unless defined?(OpenSSL::SSL)
+
class HTTPSProxyTest < Test::Unit::TestCase
def test_https_proxy_authentication
- begin
- OpenSSL
- rescue LoadError
- omit 'autoload problem. see [ruby-dev:45021][Bug #5786]'
- end
-
TCPServer.open("127.0.0.1", 0) {|serv|
_, port, _, _ = serv.addr
client_thread = Thread.new {
@@ -50,12 +46,6 @@ class HTTPSProxyTest < Test::Unit::TestCase
end
def test_https_proxy_ssl_connection
- begin
- OpenSSL
- rescue LoadError
- omit 'autoload problem. see [ruby-dev:45021][Bug #5786]'
- end
-
TCPServer.open("127.0.0.1", 0) {|tcpserver|
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey.read(read_fixture("server.key"))
@@ -91,4 +81,4 @@ class HTTPSProxyTest < Test::Unit::TestCase
assert_join_threads([client_thread, server_thread])
}
end
-end if defined?(OpenSSL)
+end
diff --git a/test/net/http/utils.rb b/test/net/http/utils.rb
index b41341d0a0..0b9e440e7c 100644
--- a/test/net/http/utils.rb
+++ b/test/net/http/utils.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: false
require 'socket'
-require 'openssl'
module TestNetHTTPUtils
@@ -14,10 +13,10 @@ module TestNetHTTPUtils
@procs = {}
if @config['ssl_enable']
+ require 'openssl'
context = OpenSSL::SSL::SSLContext.new
context.cert = @config['ssl_certificate']
context.key = @config['ssl_private_key']
- context.tmp_dh_callback = @config['ssl_tmp_dh_callback']
@ssl_server = OpenSSL::SSL::SSLServer.new(@server, context)
end
@@ -71,6 +70,11 @@ module TestNetHTTPUtils
socket.write "HTTP/1.1 100 Continue\r\n\r\n"
end
+ # Set default Content-Type if not provided
+ if !headers['Content-Type'] && (method == 'POST' || method == 'PUT' || method == 'PATCH')
+ headers['Content-Type'] = 'application/octet-stream'
+ end
+
req = Request.new(method, path, headers, socket)
if @procs.key?(req.path) || @procs.key?("#{req.path}/")
proc = @procs[req.path] || @procs["#{req.path}/"]
@@ -306,16 +310,18 @@ module TestNetHTTPUtils
scheme = headers['X-Request-Scheme'] || 'http'
host = @config['host']
port = socket.addr[1]
- charset = parse_content_type(headers['Content-Type'])[1]
+ content_type = headers['Content-Type'] || 'application/octet-stream'
+ charset = parse_content_type(content_type)[1]
path = "#{scheme}://#{host}:#{port}#{path}"
path = path.encode(charset) if charset
- response = "HTTP/1.1 200 OK\r\nContent-Type: #{headers['Content-Type']}\r\nContent-Length: #{body.bytesize}\r\nX-request-uri: #{path}\r\n\r\n#{body}"
+ response = "HTTP/1.1 200 OK\r\nContent-Type: #{content_type}\r\nContent-Length: #{body.bytesize}\r\nX-request-uri: #{path}\r\n\r\n#{body}"
socket.print(response)
end
def handle_patch(path, headers, socket)
body = socket.read(headers['Content-Length'].to_i)
- response = "HTTP/1.1 200 OK\r\nContent-Type: #{headers['Content-Type']}\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}"
+ content_type = headers['Content-Type'] || 'application/octet-stream'
+ response = "HTTP/1.1 200 OK\r\nContent-Type: #{content_type}\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}"
socket.print(response)
end
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index c25882a580..faa22f1424 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -33,7 +33,7 @@ class TestObjSpace < Test::Unit::TestCase
b = a.dup
c = nil
ObjectSpace.each_object(String) {|x| break c = x if a == x and x.frozen?}
- rv_size = GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]
+ rv_size = Integer(ObjectSpace.dump(a)[/"slot_size":(\d+)/, 1])
assert_equal([rv_size, rv_size, a.length + 1 + rv_size], [a, b, c].map {|x| ObjectSpace.memsize_of(x)})
end
@@ -54,7 +54,11 @@ class TestObjSpace < Test::Unit::TestCase
assert_operator(a, :>, b)
assert_operator(a, :>, 0)
assert_operator(b, :>, 0)
- assert_raise(TypeError) {ObjectSpace.memsize_of_all('error')}
+ assert_kind_of(Integer, ObjectSpace.memsize_of_all(Enumerable))
+ end
+
+ def test_memsize_of_all_with_wrong_type
+ assert_raise(TypeError) { ObjectSpace.memsize_of_all(Object.new) }
end
def test_count_objects_size
@@ -76,16 +80,6 @@ class TestObjSpace < Test::Unit::TestCase
assert_raise(TypeError) { ObjectSpace.count_objects_size(0) }
end
- def test_count_nodes
- res = ObjectSpace.count_nodes
- assert_not_empty(res)
- arg = {}
- ObjectSpace.count_nodes(arg)
- assert_not_empty(arg)
- bug8014 = '[ruby-core:53130] [Bug #8014]'
- assert_empty(arg.select {|k, v| !(Symbol === k && Integer === v)}, bug8014)
- end if false
-
def test_count_tdata_objects
res = ObjectSpace.count_tdata_objects
assert_not_empty(res)
@@ -143,7 +137,7 @@ class TestObjSpace < Test::Unit::TestCase
def test_reachable_objects_during_iteration
omit 'flaky on Visual Studio with: [BUG] Unnormalized Fixnum value' if /mswin/ =~ RUBY_PLATFORM
opts = %w[--disable-gem --disable=frozen-string-literal -robjspace]
- assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}"
+ assert_ruby_status opts, "#{<<-"begin;"}\n#{<<-'end;'}"
begin;
ObjectSpace.each_object{|o|
o.inspect
@@ -179,7 +173,7 @@ class TestObjSpace < Test::Unit::TestCase
end
def test_trace_object_allocations_stop_first
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
require "objspace"
# Make sure stopping before the tracepoints are initialized doesn't raise. See [Bug #17020]
@@ -203,8 +197,9 @@ class TestObjSpace < Test::Unit::TestCase
assert_equal(line1, ObjectSpace.allocation_sourceline(o1))
assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o1))
assert_equal(c1, ObjectSpace.allocation_generation(o1))
- assert_equal(Class.name, ObjectSpace.allocation_class_path(o1))
- assert_equal(:new, ObjectSpace.allocation_method_id(o1))
+ # These assertions fail under coverage measurement: https://bugs.ruby-lang.org/issues/21298
+ #assert_equal(self.class.name, ObjectSpace.allocation_class_path(o1))
+ #assert_equal(__method__, ObjectSpace.allocation_method_id(o1))
assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o2))
assert_equal(line2, ObjectSpace.allocation_sourceline(o2))
@@ -287,6 +282,33 @@ class TestObjSpace < Test::Unit::TestCase
assert true # success
end
+ def test_trace_object_allocations_with_other_tracepoint
+ # Test that ObjectSpace.trace_object_allocations isn't changed by changes
+ # to another tracepoint
+ line_tp = TracePoint.new(:line) { }
+
+ ObjectSpace.trace_object_allocations_start
+
+ obj1 = Object.new; line1 = __LINE__
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(obj1)
+ assert_equal line1, ObjectSpace.allocation_sourceline(obj1)
+
+ line_tp.enable
+
+ obj2 = Object.new; line2 = __LINE__
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(obj2)
+ assert_equal line2, ObjectSpace.allocation_sourceline(obj2)
+
+ line_tp.disable
+
+ obj3 = Object.new; line3 = __LINE__
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(obj3)
+ assert_equal line3, ObjectSpace.allocation_sourceline(obj3)
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ ObjectSpace.trace_object_allocations_clear
+ end
+
def test_trace_object_allocations_compaction
omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
@@ -308,7 +330,7 @@ class TestObjSpace < Test::Unit::TestCase
def test_trace_object_allocations_compaction_freed_pages
omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
- assert_normal_exit(<<~RUBY)
+ assert_normal_exit(<<~RUBY, timeout: 60)
require "objspace"
objs = []
@@ -354,7 +376,7 @@ class TestObjSpace < Test::Unit::TestCase
if defined?(RubyVM::Shape)
class TooComplex; end
- def test_dump_too_complex_shape
+ def test_dump_complex_shape
omit "flaky test"
RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do
@@ -363,26 +385,26 @@ class TestObjSpace < Test::Unit::TestCase
tc = TooComplex.new
info = ObjectSpace.dump(tc)
- assert_not_match(/"too_complex_shape"/, info)
+ assert_not_match(/"complex_shape"/, info)
tc.instance_variable_set(:@new_ivar, 1)
info = ObjectSpace.dump(tc)
- assert_match(/"too_complex_shape":true/, info)
+ assert_match(/"complex_shape":true/, info)
if defined?(JSON)
- assert_true(JSON.parse(info)["too_complex_shape"])
+ assert_true(JSON.parse(info)["complex_shape"])
end
end
end
class NotTooComplex ; end
- def test_dump_not_too_complex_shape
+ def test_dump_not_complex_shape
tc = NotTooComplex.new
tc.instance_variable_set(:@new_ivar, 1)
info = ObjectSpace.dump(tc)
- assert_not_match(/"too_complex_shape"/, info)
+ assert_not_match(/"complex_shape"/, info)
if defined?(JSON)
- assert_nil(JSON.parse(info)["too_complex_shape"])
+ assert_nil(JSON.parse(info)["complex_shape"])
end
end
@@ -451,12 +473,12 @@ class TestObjSpace < Test::Unit::TestCase
assert_include(info, '"embedded":true')
assert_include(info, '"ivars":0')
- # Non-embed object
+ # Non-embed object (needs > 6 ivars to exceed pool 0 embed capacity)
obj = klass.new
- 5.times { |i| obj.instance_variable_set("@ivar#{i}", 0) }
+ 7.times { |i| obj.instance_variable_set("@ivar#{i}", 0) }
info = ObjectSpace.dump(obj)
assert_not_include(info, '"embedded":true')
- assert_include(info, '"ivars":5')
+ assert_include(info, '"ivars":7')
end
def test_dump_control_char
@@ -626,7 +648,8 @@ class TestObjSpace < Test::Unit::TestCase
next if obj["type"] == "SHAPE"
assert_not_nil obj["slot_size"]
- assert_equal 0, obj["slot_size"] % (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD])
+ slot_sizes = GC::INTERNAL_CONSTANTS[:HEAP_COUNT].times.map { |i| GC.stat_heap(i, :slot_size) }
+ assert_include slot_sizes, obj["slot_size"]
}
end
end
@@ -681,10 +704,11 @@ class TestObjSpace < Test::Unit::TestCase
end
def test_dump_includes_slot_size
- str = "TEST"
- dump = ObjectSpace.dump(str)
+ klass = Class.new
+ obj = klass.new
+ dump = ObjectSpace.dump(obj)
- assert_includes dump, "\"slot_size\":#{GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]}"
+ assert_includes dump, "\"slot_size\":#{GC.stat_heap(0, :slot_size) - GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]}"
end
def test_dump_reference_addresses_match_dump_all_addresses
@@ -799,6 +823,27 @@ class TestObjSpace < Test::Unit::TestCase
end
end
+ def test_dump_all_with_ractors
+ assert_ractor("#{<<-"begin;"}#{<<-'end;'}")
+ begin;
+ require "objspace"
+ require "tempfile"
+ require "json"
+ rs = 4.times.map do
+ Ractor.new do
+ Tempfile.create do |f|
+ ObjectSpace.dump_all(output: f)
+ f.close
+ File.readlines(f.path).each do |line|
+ JSON.parse(line)
+ end
+ end
+ end
+ end
+ rs.each(&:join)
+ end;
+ end
+
def test_dump_uninitialized_file
assert_in_out_err(%[-robjspace], <<-RUBY) do |(output), (error)|
puts ObjectSpace.dump(File.allocate)
@@ -977,6 +1022,27 @@ class TestObjSpace < Test::Unit::TestCase
assert_equal class_name, JSON.parse(json)["name"]
end
+ def test_dump_free_immediately
+ require '-test-/typeddata'
+
+ # Bug::TypedData has flags=0 (no FREE_IMMEDIATELY)
+ info = ObjectSpace.dump(Bug::TypedData.new)
+ assert_include(info, '"struct":"typed_data"')
+ assert_include(info, '"free_immediately":false')
+
+ # Most typed data objects have FREE_IMMEDIATELY, so the field should be absent
+ info = ObjectSpace.dump(Thread.current.group)
+ assert_include(info, '"struct":"thgroup"')
+ assert_not_include(info, '"free_immediately"')
+ end
+
+ def test_dump_include_shareable
+ omit 'Not provided by mmtk' if RUBY_DESCRIPTION.include?("+GC[mmtk]")
+
+ assert_include(ObjectSpace.dump(ENV), '"shareable":true')
+ assert_not_include(ObjectSpace.dump([]), '"shareable":true')
+ end
+
def test_utf8_method_names
name = "utf8_❨╯°□°❩╯︵┻━┻"
obj = ObjectSpace.trace_object_allocations do
diff --git a/test/objspace/test_ractor.rb b/test/objspace/test_ractor.rb
index 4901eeae2e..fb6432a827 100644
--- a/test/objspace/test_ractor.rb
+++ b/test/objspace/test_ractor.rb
@@ -5,12 +5,78 @@ class TestObjSpaceRactor < Test::Unit::TestCase
assert_ractor(<<~RUBY, require: 'objspace')
ObjectSpace.trace_object_allocations do
r = Ractor.new do
- obj = 'a' * 1024
- Ractor.yield obj
+ _obj = 'a' * 1024
end
- r.take
- r.take
+ r.join
+ end
+ RUBY
+ end
+
+ def test_undefine_finalizer
+ assert_ractor(<<~'RUBY', timeout: 20, require: 'objspace', signal: :SEGV)
+ def fin
+ ->(id) { }
+ end
+ ractors = 5.times.map do
+ Ractor.new do
+ 10_000.times do
+ o = Object.new
+ ObjectSpace.define_finalizer(o, fin)
+ ObjectSpace.undefine_finalizer(o)
+ end
+ end
+ end
+
+ ractors.each(&:join)
+ RUBY
+ end
+
+ def test_copy_finalizer
+ assert_ractor(<<~'RUBY', require: 'objspace')
+ def fin
+ ->(id) { }
+ end
+ OBJ = Object.new
+ ObjectSpace.define_finalizer(OBJ, fin)
+ OBJ.freeze
+
+ ractors = 5.times.map do
+ Ractor.new do
+ 10_000.times do
+ OBJ.clone
+ end
+ end
+ end
+
+ ractors.each(&:join)
+ RUBY
+ end
+
+ def test_trace_object_allocations_with_ractor_tracepoint
+ # Test that ObjectSpace.trace_object_allocations works globally across all Ractors
+ assert_ractor(<<~'RUBY', require: 'objspace')
+ ObjectSpace.trace_object_allocations do
+ obj1 = Object.new; line1 = __LINE__
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(obj1)
+ assert_equal line1, ObjectSpace.allocation_sourceline(obj1)
+
+ r = Ractor.new {
+ obj = Object.new; line = __LINE__
+ [line, obj]
+ }
+
+ obj2 = Object.new; line2 = __LINE__
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(obj2)
+ assert_equal line2, ObjectSpace.allocation_sourceline(obj2)
+
+ expected_line, ractor_obj = r.value
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(ractor_obj)
+ assert_equal expected_line, ObjectSpace.allocation_sourceline(ractor_obj)
+
+ obj3 = Object.new; line3 = __LINE__
+ assert_equal __FILE__, ObjectSpace.allocation_sourcefile(obj3)
+ assert_equal line3, ObjectSpace.allocation_sourceline(obj3)
end
RUBY
end
diff --git a/test/open-uri/test_open-uri.rb b/test/open-uri/test_open-uri.rb
index 0679180ce9..6f08b4089c 100644
--- a/test/open-uri/test_open-uri.rb
+++ b/test/open-uri/test_open-uri.rb
@@ -80,6 +80,8 @@ class TestOpenURI < Test::Unit::TestCase
sock.print "Content-Length: 4\r\n\r\n"
sleep 1
sock.print "ab\r\n"
+ rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
+ # expected when client times out and closes the connection
ensure
sock.close
end
diff --git a/test/openssl/fixtures/pkey/dsa1024.pem b/test/openssl/fixtures/pkey/dsa1024.pem
deleted file mode 100644
index 1bf498895e..0000000000
--- a/test/openssl/fixtures/pkey/dsa1024.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIIBugIBAAKBgQCH9aAoXvWWThIjkA6D+nI1F9ksF9iDq594rkiGNOT9sPDOdB+n
-D+qeeeeloRlj19ymCSADPI0ZLRgkchkAEnY2RnqnhHOjVf/roGgRbW+iQDMbQ9wa
-/pvc6/fAbsu1goE1hBYjm98/sZEeXavj8tR56IXnjF1b6Nx0+sgeUKFKEQIVAMiz
-4BJUFeTtddyM4uadBM7HKLPRAoGAZdLBSYNGiij7vAjesF5mGUKTIgPd+JKuBEDx
-OaBclsgfdoyoF/TMOkIty+PVlYD+//Vl2xnoUEIRaMXHwHfm0r2xUX++oeRaSScg
-YizJdUxe5jvBuBszGPRc/mGpb9YvP0sB+FL1KmuxYmdODfCe51zl8uM/CVhouJ3w
-DjmRGscCgYAuFlfC7p+e8huCKydfcv/beftqjewiOPpQ3u5uI6KPCtCJPpDhs3+4
-IihH2cPsAlqwGF4tlibW1+/z/OZ1AZinPK3y7b2jSJASEaPeEltVzB92hcd1khk2
-jTYcmSsV4VddplOPK9czytR/GbbibxsrhhgZUbd8LPbvIgaiadJ1PgIUBnJ/5vN2
-CVArsEzlPUCbohPvZnE=
------END DSA PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/dsa256.pem b/test/openssl/fixtures/pkey/dsa256.pem
deleted file mode 100644
index d9a407f736..0000000000
--- a/test/openssl/fixtures/pkey/dsa256.pem
+++ /dev/null
@@ -1,8 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE
-9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed
-AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM
-3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT
-b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn
-ISNX5cMzFHRW3Q==
------END DSA PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/dsa512.pem b/test/openssl/fixtures/pkey/dsa512.pem
deleted file mode 100644
index 962c41cc67..0000000000
--- a/test/openssl/fixtures/pkey/dsa512.pem
+++ /dev/null
@@ -1,8 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok
-RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D
-AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR
-S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++
-Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S
-55jreJD3Se3slps=
------END DSA PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/mldsa65-1.pem b/test/openssl/fixtures/pkey/mldsa65-1.pem
new file mode 100644
index 0000000000..21f08e3ac6
--- /dev/null
+++ b/test/openssl/fixtures/pkey/mldsa65-1.pem
@@ -0,0 +1,88 @@
+-----BEGIN PRIVATE KEY-----
+MIIP/gIBADALBglghkgBZQMEAxIEgg/qMIIP5gQg6Xunp08Ia0w6d93rvBnXnlYf
+ih3Z+9IDZSRIyAGfjbQEgg/A9DPSakjm2xFsVzCHpfwcUwP5dYpJGRYwG7/eSp8b
+/lJOHPmIHjOAC8jN3xS66UXcouWozGXbmieGjLzNs1HjBaJ0CEw51wQOuPLDg8nj
+Pdesnqu5Ct1sNzqz0K57ixyEPrdPI+Vd7XDNaXfOytZ1d4+yFBC6cGpznQ9CiRYm
+PpFEgUZSg3QzFmB0hREkB4FHhTIUZlckclcxNRRTg4UFUIVTdTcThxVyJSFFInZl
+GEUnKAIEcXBUdmgwMQMhRngCFEIFBIB2BVRjEiEwI3FwAQJEEScySFh0UVdQExeB
+ZDYgIUhlFUYxh1g2V2YRdohodCVgBXYIJRJCQHFGRiI0GGQENkgBFwUGNUeAMlh0
+ZgMhIWRmhyhGVEeAUUOHVVKEZHU4BQdwMjEBIIcQeBYFZhKBdwFjBlQECCJEdoYT
+E3FXYlcECCNIZAF4cTaAQwYxBkd2YRE3FTIYRCYgF2SBUiBCJ1ImFjZSFDCIaAY1
+J1ExVDRRVzFGgiUIV1UBCDcVFmcIM4OGeDIXEyZXaCFzBBeBFQQxcFeIJWBmJCdw
+hWMUdYFiNFAmMIEyKIRYIIeIgHA3AmNTElA3gwVmBUUHERE2AAJHUhQTJQAFAXhY
+QmYDdSZHWFhHQXUkRFBWViQ4VERRF1eEN0I2VzR1dUIxg1Uid2NmcDIWdBAzITEA
+AmJgh3JlgwIREgVoIiEoMCADEGSHFIGHUnJVU2I0CGRxaAR3JUVgAnJQOAQiZ2Vh
+OFM3MIEHUmFzQhcEdzSBhBcYVCgEKCIiWHUBhCVxhkBjRzUzJAhDQ2F3eGdUNTEj
+QQcjY3E3BnR2Q4cWIjJohyd2hCUzOIgSUodmIxY1AmaDFVBQEghncQQYQ2QIcjiB
+ZWNQZGZFhHiBIQcXURQQAVg2RBQQd0aDgGQXE3Q4eHY1iERUVoUTcQIjcmh0UVci
+Rhd4MRI0ZUVHNXEAIDQ2cVIGZYMiB1ZQQSYVMlZBQiAwQHJYCEUBExAjF4QwQBMT
+cjdGVCckJTBFJAcXREMzAlYmhRJXgEVSESFYAAJwFXRyKBZCQwcDIFQkJWUFB4gV
+F2GBiEcVEUAmcWEFREA4dEFDQwhFUQUIcHQRMRGHFTA2g0YmZxIiMjMjAQFgcHYF
+IgJlFyA4RhdRgWY1FVEhM4VoUhiIQkcIeCCFZIESZjVWFjNWQEZTNGUoBiR0cgFn
+hDNIAhIRdXQgaGBxNUdyBUIWAniAZIOHYTIyUYd0YXExBjEShGA1GBQ3FBZVEmEw
+EhhEJQNwRjUyQnSIAVNlQjKDdIEBQQhgdSdxc2RjEmRiFyY2RRYicjQCh3AhNSZo
+QzRlGDaGMzCIhRcjIocxN4cwM2gRA2WIN0NyaHR1NRVRAXIkFTR0J2NCCCEHKHYn
+FSYGF3QXBwhDYUZEJmdHEWAlBCIyVRFBR2NSNgJwZgBoAgMjcYQRNAFjI2ZVVgEE
+V3Y1eIREhFc1ABVEGGcUNGRnWAJYOAdlZmgWQlZncWJVNFNkBwOGRiAmJGQGNlIx
+NwNwZ3WBaGIBdiNlMEVXFwFkZRRCE3ZwFxgQWFKHVxOBdxJHJBhSF0d4IlAgIRUY
+UXdCWIQIKDGAhAIoVBAhdXU3AHKCiCBkF4KEhhRyU2JTIIdwdGYSCDcXIWM4QYIY
+NoCFNSESeBMnciUkMxV1RYNzYUSGggMIgWVCM3aAMRcCITMgKERIEjgiUkIlNoUT
+JkMjMzc3dxV1WGOCZRJSMzIhGIAgBEgicDM2CFclACBlBoYyhyNgJoOIExIoY3Qh
+EFRQhFYBZoJERhNoQCIUaAIARgiCQSUXYkUgR4RnYAczh0ECOCeGdBJXExNohzZH
+GFMAE2MAUUZ3NzF2FldoGCKEIzJzGDFHd3KAU4ZHUichAYUmEYVAdShYFlh3FIIl
+UzQYdScUdlAAglVjBiNCJYGBKHVTNEJBMBAQEFQhJSI0diJ0dFA3KBIAg2RxcXIA
+cWMBcoIEQBgAUBUyEDUwcQYTVwSCMjBCVEQiQWMThDhVE2YWZBNQhVZzY4cBhIZh
+IIBBQihmh4VgJjZkJ2J1VlAB5kLlGDaGXIOc++2QqMCGeB9FnTYpHFoSXQrOjQhS
+tfTln0rEelihhKhi3Bu8mdhyTSFZTShsQidqlN1/U50KnMTqII7r9QltUZqPH9sW
+CswVssxnVe1GAXY/LqJPN5DEN2ZEMoAgmxLbGYB5YdKID1lj5zquaCqpDUGDI/Wi
+zJ5xpFzn7nGJwedU2MBqcqlIVJg8VeIInkLL/v3y2uqD4+pewW8OewqosJOfBgjI
+RH1FXcdGbnqKJk1YZ8iwVMTNoU9U8gGDI5kk/dWWqqAdxaVrsmevmNRp6wtibFG6
+FxrSRb7hOP8IVv7TkMA+Cv4MRs0UhYJ2W8x0G0LxP4M+m3cAJkaHyHDda1NHjfTV
+zG9hWK8Ad7t+F9hw5++KBPlkW+/sX4eYpOlC/XjpMp1W6WIr9oIbRp6RXKNUuBXQ
+58uNAmq6peDenbwsmiBKG+RWntbMxtjOM9bo/JXMV9dIT/KIbljl2C/4TRbWy0D3
+KfZlvAHpiw2oH/vaLUFbIg7sK823keZA/uSFJ2KSPBVC6+AYX5tM/P/KKLJmFoVY
+U7h4F/SDCbOt5PJu9yg+fN6ftBT3a2723TAx7M8+WqPrvvOB5UFJRNCcpwnjqriz
+8ENLgoze5wm2sIk+QvB15tFG0n3+9eTOjD+q0dJDSxq5xAuAalBoFp7vSt2x1UO/
+4Nf/jXvJT2nXjR7QgtabQRzKqbP5lHVtL0BCJeGFlbGeuAGIfNuVY0809E66sWDo
+S18hNAfp9jKe0aU7MxGU6RvCB8vLK+cld/RzujyK8C307PJdzwCLEYIBMC3SvBcQ
+9CpJFuPIcEVoM1RiThw/l1MAaKJ3y73ekU5p+Dd2CN4P4pCDSiVj/PAOW1c7iA2A
+QBVuCfPMYJyW93toHaqpaZuD9VN3OKbtJvuMWCOIN59ERFvttv5CNQ01rhgCv3dZ
+kkkFrJsmFcwsgMW1JIGozMKywFzi9yDWUL6j/ZCc8xqkfP9fYPBBTcSsUvWV9Zq6
+AU22B9j6/EUP8crw0VViacbEJy2sJgIumEQiVlVNavorpPwjtWpVQFvsBrDm6X80
+jk9H/yTKrrR6LaTH7999s/88jOLszmbX7Yt8VmMkkliml2rd6UqG9D6zq2xEj1IV
+6ZT2zhVe+wHNmpkr1kYTIVsLXrHNpCWEQeHscSCzz/lg+aOv8kSfFqGq2VFjxnts
+7Z88TjxzIOQk14Lzkgl0PCyHXau8i2bteCOimqRYEd3ihNcC8U9MXLYrOiv24oXM
+RpkzoHGOtZoAie6k1Xj6aDwIl2mTBHg5BF0A4U+d/z7wS8Gr9nEc574s9OyKAZn6
+5L/1GgpWa0e2buxn8fkPAMptY0773prqKqwvV/SWdvUJ4B4HLNLsU70+N4XAZlRS
+7saNkghBkrD/WobJQwa/9OWWa5Gw6Frurr0AmnBU+EN7u6niFwARsa9f1yjuW8IJ
+tLD7H+Yu2bGouHWpeoXQHwqFxl+me7rQ/ePvOYQk/SzlzvroaqAGECrDoHU3kzhn
+rhJLueA9b0j3u0/+CQaNOFPWb6GAjmafVWpBcXtOSkHVUXitclURlITEwe47tn+g
+XffSw3k1q3XBKkFkJQrgPa2IbpAWvFKA7rOInY/b8N/lCI0bZAei2OOR2/MLifkx
+F3L8daWXslp7QSlIjUXwtgdD6CwQsEui99dZvTYlSxzUKC9nsF0oPYxWpHAcuoCE
+pQCR1CuyuGkDCaod2VNWqWOcZ5QXjEtbVHFO8qJdePJPKWV+0YcltaR4X5q2Pts9
+4a0SJMSM/tXrUi9g9RjjnB+F++rc4a5FrQ2r7FDXudk7NUEoJPyBvBDeowiSmXvv
+SHrL6WsQgf8n5sZxfA0uqs+8OMSLLNj72CSoBQMJNVJgYQkSyBuHl6Zk59+k/WeJ
+wX1qevXwaC6JrdF+naRcp16tNv+7230GPO1d3+X3zZOtAEuAzk6kw3da8Y15qZ5j
+FqzXPO8TsURyOf4Fp+kxpETSQ+mf8Do0hWzUYE8Cj2EFcwuE2Q7+c1ZHAFpQNk1j
+T4vR//yCYjO8/lY0yDV7iDzkT36twyvKZ/cMxC001RSNmtr3QNWWkRRDBWCSwnjW
++cn408gCVFPwVUOBwUr6aOeUY+fCcvWnYPCDj7ggdS5wEoUk+xrk4v2kU2gAH/mp
+DqhFNouIcExoNW5j7j0w0YKnZtZJ9pviiM0EXS6vhk4ayxI2pi3VOqL2RhoNleAa
+bTcCQ71wOxqpp4khssLcOsUR8trpadlvZJ9sc1ksUfoOz/pMI9Yj0IWctbuiriJp
+l193X2sPzVMn3MaEt+XPrsX5wOogbQAfSJyY8pfCnZuhVLoZDpJADJxou0EhP+wH
+p9yZc5GZosFgDJvTEhZfUmituLW4+op1FLJqA/LQSxBVz51OnmtzpgJLyR0ctTLG
+9CcYbFTrzltPlOTHVjVW4rD9jyoLjLdfUf9qG65qVpGBisV+wD+SI6P0x5rhN7Dt
+nC0YNZZ0cYyN24xw8Bxzcc9RkY8/MFfbTXOG43Uuh7fkPIdY2NQSUK2tkfiMdPgu
+zlR1HoZHBrCcsQXJH0OhbuJ6Uwzm340Upj4b/eykq+uUcVY8PAUHSg6mwKy+E4yp
+Za5Z5U50Kv9rFcE9Hwh09fGfdUrKTCFxoKrqfeW+ogTXJHQR5A41r9PP1l7/9Bp7
+P+UtdjJtAHzTO1r7/dckvghBslqhNBzA55wtWEmjMFh4Mm3lBMvBGrCelKPtaOrb
+CYlv4eqGZMEeE3VoEKO3QnXU/dqJvhwQhjCcgxPtOzm9eSrofTvXa4xIMKyuNF2z
+F6K0S5o3I+pBUInshXHWwN1pAT1R4FRYAUTv9mZbhLP+MWgPIMrdWWHAMDL5DeBH
+G4AT5RQbzIHjQ12fJq30m1LajjLlL+mF5og+plMgEGOCJMHZyT2NcNb7gFHWk2mh
+JmO/qxdXQ1FQ/oEf+gNmfgdlw/N6TY7PvmkVfdkhgp/zQLcGgJ33gj0gy4Jr284G
+EhmeOGQflVsMFDqrAgjCEEJSLl/+FXuDfJjTixyly/yTTJCAeiEXsSW4xDisYZyR
+dmEXPtx7eyelJjbsM2yMTNacvCA8TCywTqxYMlYF45kHhTrnQoMvx83U0vqB+ALA
+JsGGrYQZ3tx9j8ae27b0rkSrccFYhKCXI/mwEZcZ6SG3q6/PhHWQOaie2EkuVLDq
+YAK0ZjlTv0znE1OVN3ovKAqq8ga/y5tOKXREo/i/SRPj4aHel4Lky26+Nmm+t+E2
+CL3SBcqhBC45qIB27kdsqBsnCfSzm1fQsy6jivCEDneLTLNoltDyXunSwyLP/7HI
+qclQDtLzvC0mHUNlhcds4I20
+-----END PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/mldsa65-2.pem b/test/openssl/fixtures/pkey/mldsa65-2.pem
new file mode 100644
index 0000000000..0ae64c2c5d
--- /dev/null
+++ b/test/openssl/fixtures/pkey/mldsa65-2.pem
@@ -0,0 +1,88 @@
+-----BEGIN PRIVATE KEY-----
+MIIP/gIBADALBglghkgBZQMEAxIEgg/qMIIP5gQgDdLfrcKpbcx2qbjvcE+SqUnW
++y7uWok/WM51jtrhQGIEgg/Az2AAnia3lgXsNEHx5NtoKaslKSsMPpvhRGFlcTcT
+ZFF3hKrybqvpUxtqF8nqPTy0geEN/k/k6rYHDIcaBfE5J65Xn8dwRbUSzpjSJVD7
+aBv1qprz1pAAXMYcazKeqWCJxyy7u9opGuNMaJ7SHcqwQ1kZ4nWaxEua9JnXZ6aJ
+zGkVg3WFgnBFVFJjNwFRGGNDNjNVAUUgURZgiFhARkBIIIVFZkJ3UlaAFzBodRVj
+OGhnUHAyQkc0ZRQYVTUDAQcHNhVTInEyZ0hngkBRcmKFdxgjVShoRmAyRYRTMAFi
+KARRInZVhCMHhCQzcDh4hAd2V4UoVVGIIHclWFZXJVCDUXeFZ1YnIgcjgiJnU0BI
+EoFgEnZyF2OEUSUlJSNicSUChwFGJCglhnBCMUZWdAeACCVEVxVFYTRFQ3AyhkNo
+cwFSBAd0BGVBBlRyhVYQVyNHVSJmYhNhBXaFMIUTEEJYYFhxhWN0IQNYQQdHMHMC
+FTM0cUVGcnBlCAZSYQM4Unh0NTCBIlAHEYMmYzUmQ1cIBIKENGYlKAYnMSYwBFAy
+IiMWVBMQeAJQVRJBh2A1ImB3cYVgd2QhJSUVg3VYd0VxMmQhIhB4YQJTIoFiBkcj
+QgIBVEQIgXaABoNAOGUkcUdjUEB2SGiFKCRBYTZAISJRFnaEJmMoRndWBhCDBIJQ
+EXFDYIAieBYnQYIwY2J3hoVRMTYGaDEmgSMxFidoETEjFCgnUYCFQhB4NWhmVAZw
+M0gCEDAWCIcQgXQjgxNkFVZCKCOEiBIFFFA3NBQVZiSCYWRnYXASRISGQTUWAUA4
+IYMhckd2UhiDQYE3RxdAAnEIODYAUUhnMABIERdYFSQkcSYFAyIBASUkFAQEdTJA
+IxZABjhyBjF1Q4UWNEMgFBY4NSdjRxCFhyg0FVIAI1FWVhUlgRBHEGgYKEcIEoEl
+cIRzRWE0Z0g2BzQ2FxUGiEchJ1ZzUBY1d0EQQjd2AwY3KHhDQ1IVAUcIhDgWYIZI
+WFN3BEhTgBciRhNTGGUARoeBMXExNAIwcRYnBRgohUM4gYSARhCIMkMDJVhIgoMS
+R2BRKDFHh2JgGGUyMlIUKCR1ImJFgCY0gFgABgUYBXU2BDRGCHaGiCgTIDIyBFh4
+RmFzUBBCE2FUJWYAY4ZjSAg1BWWFAFQ1hkBjAnMiByEWVIVgN2MXYmBUU2BhYkUh
+OBNEWEBChUSDVgYEZiJ1cjUmNDIGQghgZEUIcUdwZVYjRzgBeHA1gRSGVXYhgmaB
+NVZ3UTgQUSF1NldYc1aDRgdGMVYUdwgQVThTVEJyN2IFUwdgUTZoJhQDVIRzEEdI
+E2YFd2EhESIVMSVFdhRHYAAFBShCEoAXQScWdEdSiGIydUNiZzhmJzY2ZlMTOCYH
+UzcVZxYUiHAxhDgmcWcHZjAFdBSHVhMyhiIyCCcwdgcACGOHRiNlAmAFAyFVVRcW
+FQQhNwIFYUBxNxKGVlQzF4IBEyAYFDF3BzMlUjJyYIMTFDAUFWRDhnWGdABYQRRQ
+h0VTAIgWhnd1FEhng4hlUwMiY2c4hzczM2BzgxRoZRRVRkF1VngWFFEogkEEQAWA
+J3R3A3IBhmQVaDVGKCJkMlc1GAFwIXQHF4h1RkJVEiJRRQB2ACGEgDFBBDEIWBEx
+VQBBRoFjMzKEKCZYcnRWYVh1M0N4GEMmRIInExYFNUMgExZRQ1h4h3NwdGYEJDJR
+ECiCYjQ0Z2ZGIGIwZCZGAFYjaEIzVFIQGEYUBHOBcTJiQSdCF3dCUQEBhgJBRyZU
+JlZxMHKHYHh2E0NwCIdCM3gHBjFWYhJoghJIBCgHI1hWJTRiF2eBcRBRNgISBYZx
+YzYTdoM4YGJWVBBYFzWBAUOHcVaAFERQEWEHExYyZIN4BjhEVQFIgyRAcGY3hiRI
+QkiDckYRgRQQISUQFDR0VxZyZ0hiIgQhOIhgiGdnIlaEJgQARjgxgWBzAgJ2FCAz
+NmgwVlGGdUcxYhZjVCQXAkGIMoJAJwFFBWMGhzExGCA1ZzdIRhMwQiaGN4AlMzNW
+RyFAA3UzYCBSNXOBMUEgRUY0E2wwl7ncBzQaQCHLGi4fo4iNcjppgeVmwIkz3lQc
+B1+enw6xro9Jj41TDjetf9GWcQeGt7rWjs2Q4b1R1IzuRhVgw7PuvtM1PzoP1Wfj
+sT1ugBTv5FzYo1zBx6L1hAYrB1ZR8EY/0qp3JhMeMDNry3kxoWxBk6NRXCl550nV
+DjxIXzzQYBOtvEUdRjX0jKFRtp5r+usf5BY+HjkFPlCxUNZ9U1EuWNZenAG47Q1a
+xL6aiyTUOsmyzXmIRXA3lQVurP1GqH5beYWgt6g+veH9MZm7HqC2iAqrQvTWrfQg
+Vh9h6K2VgK7rA7/SUHJS++3l3YqRV+0CL05OSa3+55ZheCQyinGcHqOR4DiaO4tl
+XWlYis6KU7ZkQPwEejPibzrK6OvCBHOYzBmZXu6Q3h57TzCAZoS7Uinm1VHVFqIw
+eid4VR9QHv14bj2pj8lz+bSEeP3/quUci+TF9A/CNzrTdv7eYxlS1EGd40PQMA6F
+p/ZHenXBp9vp8xCFPO6N4BSpLTm4HATPv0IfSJvalmj8YGMx9baCkuv1zInD/nij
+XjAOpuxXuLo4Odnsyh8nG3ApojSwPew6Nw0/gIkaaBAEHatk36bif14ZfpjdtMSu
+ZqqRe28YAX5Cc+CGgwmiMVp1wcfnsREStQljA51Wgh9BMDj864vIxDRwoDvnGUP0
+2us2kCc1YWOYO0fhXnQwLv0SfhMSueXSWI+TtavZ7XEpoxLR59KfQXNr54lD2LVi
+SAIfnugQFY6QWQJy9tqj/EQVRVAz7DtsKYhuaXXXUob1WjRpW1GA0Haz+fflunto
+PVI8jfubex+6clxGXhc8wef3P6mZI//C4qdhU1DL+Lfa+nUvzq2RbsrpZh6wB0RU
+a608XykbdkVPR56khUm+a+p4jMQrp2YCmiPj68CvZz49voij9v4sFhUPQ8NuqoRy
+VYRGSSiAccpoDocgn4mcScbj5WgxgDHxhYt2N2FeO37//2AiXNzOhZVSpjNe8OIs
+F5msuuf6lYDFQj8yy5wYkR9VLUMajV54E0vdo1ns3MCZzGUuibHRlkPrAOXMsHrY
+80le9gLR6QUtfT/2C3PPT6v6psdI86FvQbjly24skPaG9Vm0HGOc3ImuQu5m6CbQ
+37Nb8uIMSRG7QBxhVAXAwxXs6KiWZ8TxyS4zn7INRNyBHm1cgZPSxxXfPZIwosjv
+G0cMqD/CCtxriy0HkJjwtCbUYLc0nU+nMEuMCylWvf6w7hw0SkB/Sa9XvPTiMr3m
+B3qxGr69du5HKLFap9HhlYzgOOuPQrzQxAkIIQ2bCxsIPmTuDXJPvCBB84/I5RyL
+dG7j3LsOg4JGjp0+1wQE7+dynxIFru/DCfNSl5En0ON/Pmu4rteTd3X78Wovr6cV
+8bTp+AQ4ZuSk4bT0S9OtC3hAM8WUjQDZplmJkB8tzo6T5fRU9YX0MFAjUAh7MYAe
+a6+Up3mxWmYeo+c4msn7aRfvi4lplMoSKHs+rMgN93ExN/M+IUgTUsjlVQselOzV
+SKlUIQ5oXI+f/Sdtt8PKU/ltSFrAvNwowbarIOjClBPeNrNhYgascjzZ6vBbDYkU
+zaWo97QIvsW5Fj63uYNdeKEfGc+Pf6/IkiVBf5kKGUvHjmBXpgmf02FkDRF065pL
+Bx8UDeaHpzAcLBMDbUVejokoEtqDZjlkOljhUeiau99YGC3u3vQia8e64Z0IliaH
+FXXH/8l2FR3ZnYWnLBL4YBSmvwOvosB0iQhKaIb05oxzn6xmgotVhTT5IDqE3PX1
+OfpnFIoNe2IPvobu4z1Q5X2YjA8AvgXOsmH71Js4Ihy2DvGXSESVfF6EB9TqpmHC
+YPIhPORi2g7El4iZrbSvAqOoGILx+8HwBTm8rg4zuqCg44J/nEn7vgjA0rzmQ5mm
+uex3OEpi2RosZ4RecwFrbnkDtN8geeiaZGovGjGtLlBwd09VRji0DFy/l8fUqOqi
+NttZxiGLRL8SsOntUzbkNKcH3GnuN2FUOVD/xMiqOl8IvS6EO81CpPq0c8JxHWQ0
+ew2QsV8EIJLHpjZRNE4wp/3r4Z9U3ziV7ip8N64ScNj0YedJEvRgLM6hracg7Tey
+bOXhJ8FLh1/cGbeGD0tlbwg8YNZeXkA7YYDmlpWw57jZwYoyx7HqgziF0qqLIPIO
+s9CwjtAb26B0trIJHjkpv0EQHtRsOJuaQIXDcj/A8QVSb9F58cVALYb6NVCADdl5
+fytsoVJst8UQRT+AL5i61ZIVFG9URvoDFCJOYfp5WMF26lb6R0OVw0fuo5XHAcql
+T+gPyx5SaU8Klo/2k5jIm4+JQ74/d4srfcqnVPX/5ueIxtvJx+2q+MuhcOPelwmx
+BjPNvzLRcNFQU8/6meFFFVclBfIPDzOspxTOKu6DvcrkMLFiX1Vl40x/FpVMdRFj
+M5DmJR7NoFhoOguGin1cOdpvUmPxGEzKEJfrQqQ5CX4Kj4lHIFjHeYR1nLTagAyA
+rGv029l5af0CcPmQgl4NlTWh5eRtsFs16YDRkz+1xdQwJnpU9Qs91f6ckScGRHaM
+pbpJPoCGPT+kNvHbWrziupkaFYRTy3kHlhkZ7aqqq5phtDVk89LmS355V46t6CoL
+clkAwCWPBqUtJ4Dd0G1Qo6v/3wv63GkrezzxMjvINrJ6rVNqQBgLN5fiHzxYNRjD
+UB9BRLJq7updAnEFSNLqifwDwIHD75EtQEOfWoGBE/beMU4vecnzh7Q3aM3YE7zJ
+sZdtSoLzIycXZczICi8kNRZ/yXUS/mswUaUTNwANWGvYpXXsGRjdg8rCG7bMdBzX
+op9qNMFoxbZjg1NnEvlY33gMgHi0hTVeVd3WvFLrOSnV16dIb6wvgIjW90L/dqXx
+iKHKlXtaq01N1vpFBQnUhjL+ZvKh2rQpQpyVB4HBdQeSWC16/tYA8EPUZsISZAM2
+nYdbxHlIooPFz/Ali+g0B1JD0wFs/GljQloKVmBG1otF0FMBRvFlLUflcI4VSsDk
+odpZfBwFPq3K3qN6SAgtpKRzaJH7YDZn6XYIcekoAHP0rsqUH34eeHJ3Rv2U2ml0
+lzi+Ydsv+/REFoiLYNL8Gqa6WpVcZ1qCUse6ORnHCWd2Vxf4d8YDvcLwPwEqcB6u
+ewhC3Gme5ydV4hwTv9SzHOJ2ohTI9J4FpdEmGxOuB9HROQ3c8qPm6PDh5fXwOItz
+qaD8y6RLZUaPMXgwbAI/Gr5EFLAGp6CXfLrKE9yD3yLAop4DZ6GPPoHqOc+hKkgY
+edxUwijnQ25mtgrrJzvUWOpO0hi+CNdcMQMXXU2phyibN8h/JoejzIm9HXk2EvV9
+qX4cmZjkE9fKw15cRjvQt1K1
+-----END PRIVATE KEY-----
diff --git a/test/openssl/fixtures/pkey/rsa1024.pem b/test/openssl/fixtures/pkey/rsa1024.pem
deleted file mode 100644
index 464de074be..0000000000
--- a/test/openssl/fixtures/pkey/rsa1024.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx
-aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/
-Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB
-AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0
-maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T
-gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572
-74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE
-JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX
-sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII
-8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA
-wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi
-qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD
-dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA==
------END RSA PRIVATE KEY-----
diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb
index 869ecc0635..0293813a8d 100644
--- a/test/openssl/test_asn1.rb
+++ b/test/openssl/test_asn1.rb
@@ -6,7 +6,7 @@ if defined?(OpenSSL)
class OpenSSL::TestASN1 < OpenSSL::TestCase
def test_decode_x509_certificate
subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA")
- key = Fixtures.pkey("rsa1024")
+ key = Fixtures.pkey("rsa-1")
now = Time.at(Time.now.to_i) # suppress usec
s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf
exts = [
@@ -306,7 +306,11 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
end
def test_object_identifier
- encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b)
+ obj = encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b)
+ assert_equal "0.0", obj.oid
+ assert_nil obj.sn
+ assert_nil obj.ln
+ assert_equal obj.oid, obj.value
encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new("1.0".b)
encode_decode_test B(%w{ 06 03 88 37 03 }), OpenSSL::ASN1::ObjectId.new("2.999.3".b)
encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId.new("1.2.34.56789".b)
@@ -314,6 +318,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
assert_equal "2.16.840.1.101.3.4.2.1", obj.oid
assert_equal "SHA256", obj.sn
assert_equal "sha256", obj.ln
+ assert_equal obj.sn, obj.value
assert_raise(OpenSSL::ASN1::ASN1Error) {
OpenSSL::ASN1.decode(B(%w{ 06 00 }))
}
@@ -389,6 +394,11 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
])
expected.indefinite_length = true
encode_test B(%w{ 30 80 04 01 00 00 00 }), expected
+
+ # Missing EOC at the end of contents octets
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1.decode(B(%w{ 30 80 01 01 FF }))
+ }
end
def test_set
@@ -406,24 +416,38 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
def test_utctime
encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b,
OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39))
- begin
- # possible range of UTCTime is 1969-2068 currently
- encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b,
- OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 39))
- rescue OpenSSL::ASN1::ASN1Error
- pend "No negative time_t support?"
- end
- # not implemented
+
+ # 1950-2049 range is assumed to match RFC 5280's expectation
+ encode_decode_test B(%w{ 17 0D }) + "490908234339Z".b,
+ OpenSSL::ASN1::UTCTime.new(Time.utc(2049, 9, 8, 23, 43, 39))
+ encode_decode_test B(%w{ 17 0D }) + "500908234339Z".b,
+ OpenSSL::ASN1::UTCTime.new(Time.utc(1950, 9, 8, 23, 43, 39))
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1::UTCTime.new(Time.new(2049, 12, 31, 23, 0, 0, "-04:00")).to_der
+ }
+
+ # UTC offset (BER): ASN1_TIME_to_tm() may or may not support it
# decode_test B(%w{ 17 11 }) + "500908234339+0930".b,
# OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, "+09:30"))
# decode_test B(%w{ 17 0F }) + "5009082343-0930".b,
# OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, "-09:30"))
- # assert_raise(OpenSSL::ASN1::ASN1Error) {
- # OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b)
- # }
- # assert_raise(OpenSSL::ASN1::ASN1Error) {
- # OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b)
- # }
+
+ # Seconds is omitted (BER)
+ # decode_test B(%w{ 18 0D }) + "201612081934Z".b,
+ # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0))
+
+ # Fractional seconds is not allowed in UTCTime
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1.decode(B(%w{ 17 0F }) + "160908234339.5Z".b)
+ }
+
+ # Missing "Z"
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b)
+ }
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b)
+ }
end
def test_generalizedtime
@@ -431,24 +455,46 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29))
encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b,
OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39))
- # not implemented
+
+ # Fractional seconds (DER). Not supported by ASN1_TIME_to_tm()
+ # because struct tm cannot store it.
+ # encode_decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b,
+ # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5))
+
+ # UTC offset (BER): ASN1_TIME_to_tm() may or may not support it
# decode_test B(%w{ 18 13 }) + "20161208193439+0930".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30"))
# decode_test B(%w{ 18 11 }) + "201612081934-0930".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:30"))
# decode_test B(%w{ 18 11 }) + "201612081934-09".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00"))
+
+ # Minutes and seconds are omitted (BER)
+ # decode_test B(%w{ 18 0B }) + "2016120819Z".b,
+ # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 0, 0))
+ # Fractional hours (BER)
# decode_test B(%w{ 18 0D }) + "2016120819.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
+ # Fractional hours with "," as the decimal separator (BER)
# decode_test B(%w{ 18 0D }) + "2016120819,5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
+
+ # Seconds is omitted (BER)
+ # decode_test B(%w{ 18 0D }) + "201612081934Z".b,
+ # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0))
+ # Fractional minutes (BER)
# decode_test B(%w{ 18 0F }) + "201612081934.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30))
- # decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b,
- # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5))
- # assert_raise(OpenSSL::ASN1::ASN1Error) {
- # OpenSSL::ASN1.decode(B(%w{ 18 0D }) + "201612081934Y".b)
- # }
+
+ # Missing "Z"
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1.decode(B(%w{ 18 0F }) + "20161208193429Y".b)
+ }
+
+ # Encoding year out of range
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
+ OpenSSL::ASN1::GeneralizedTime.new(Time.utc(10000, 9, 8, 23, 43, 39)).to_der
+ }
end
def test_basic_asn1data
@@ -650,6 +696,20 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase
assert_equal 17, ret[0][6]
end
+ def test_decode_constructed_deeply_nested
+ bool = OpenSSL::ASN1::Boolean.new(true)
+ nested_100 = B(%w{ 30 80 }) * 100 + bool.to_der + B(%w{ 00 00 }) * 100
+ decoded = OpenSSL::ASN1.decode(nested_100)
+ assert_equal(nested_100, decoded.to_der)
+ content = 100.times.inject(decoded) { |a,| a.value[0] }
+ assert_kind_of(OpenSSL::ASN1::Boolean, content)
+
+ nested_500 = B(%w{ 30 80 }) * 500 + bool.to_der + B(%w{ 00 00 }) * 500
+ assert_raise_with_message(OpenSSL::ASN1::ASN1Error, /nesting depth/) {
+ OpenSSL::ASN1.decode(nested_500)
+ }
+ end
+
def test_constructive_each
data = [OpenSSL::ASN1::Integer.new(0), OpenSSL::ASN1::Integer.new(1)]
seq = OpenSSL::ASN1::Sequence.new data
diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb
index 5b68544574..f663102d45 100644
--- a/test/openssl/test_bn.rb
+++ b/test/openssl/test_bn.rb
@@ -345,29 +345,37 @@ class OpenSSL::TestBN < OpenSSL::TestCase
assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME))
end
- if respond_to?(:ractor)
+ if defined?(Ractor) && respond_to?(:ractor)
+ unless Ractor.method_defined?(:value) # Ruby 3.4 or earlier
+ using Module.new {
+ refine Ractor do
+ alias value take
+ end
+ }
+ end
+
ractor
def test_ractor
- assert_equal(@e1, Ractor.new { OpenSSL::BN.new("999") }.take)
- assert_equal(@e3, Ractor.new { OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2) }.take)
- assert_equal("999", Ractor.new(@e1) { |e1| e1.to_s }.take)
- assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", Ractor.new(@e3) { |e3| e3.to_s(16) }.take)
- assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.take)
- assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.take)
- assert_equal(false, Ractor.new { 1.to_bn.zero? }.take)
- assert_equal(true, Ractor.new { 1.to_bn.one? }.take)
- assert_equal(true, Ractor.new(@e2) { _1.negative? }.take)
- assert_equal("-03E7", Ractor.new(@e2) { _1.to_s(16) }.take)
- assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.take)
- assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.take)
- assert_equal(true, Ractor.new { 0.to_bn.zero? }.take)
- assert_equal(true, Ractor.new { 1.to_bn.one? }.take )
- assert_equal(false,Ractor.new { 2.to_bn.odd? }.take)
- assert_equal(true, Ractor.new(@e2) { _1.negative? }.take)
- assert_include(128..255, Ractor.new { OpenSSL::BN.rand(8)}.take)
- assert_include(0...2**32, Ractor.new { OpenSSL::BN.generate_prime(32) }.take)
+ assert_equal(@e1, Ractor.new { OpenSSL::BN.new("999") }.value)
+ assert_equal(@e3, Ractor.new { OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2) }.value)
+ assert_equal("999", Ractor.new(@e1) { |e1| e1.to_s }.value)
+ assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", Ractor.new(@e3) { |e3| e3.to_s(16) }.value)
+ assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.value)
+ assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.value)
+ assert_equal(false, Ractor.new { 1.to_bn.zero? }.value)
+ assert_equal(true, Ractor.new { 1.to_bn.one? }.value)
+ assert_equal(true, Ractor.new(@e2) { _1.negative? }.value)
+ assert_equal("-03E7", Ractor.new(@e2) { _1.to_s(16) }.value)
+ assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.value)
+ assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.value)
+ assert_equal(true, Ractor.new { 0.to_bn.zero? }.value)
+ assert_equal(true, Ractor.new { 1.to_bn.one? }.value )
+ assert_equal(false,Ractor.new { 2.to_bn.odd? }.value)
+ assert_equal(true, Ractor.new(@e2) { _1.negative? }.value)
+ assert_include(128..255, Ractor.new { OpenSSL::BN.rand(8)}.value)
+ assert_include(0...2**32, Ractor.new { OpenSSL::BN.generate_prime(32) }.value)
if !aws_lc? # AWS-LC does not support BN::CONSTTIME.
- assert_equal(0, Ractor.new { OpenSSL::BN.new(999).get_flags(OpenSSL::BN::CONSTTIME) }.take)
+ assert_equal(0, Ractor.new { OpenSSL::BN.new(999).get_flags(OpenSSL::BN::CONSTTIME) }.value)
end
# test if shareable when frozen
assert Ractor.shareable?(@e1.freeze)
diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb
index cd0b3dcb44..6a405da0a9 100644
--- a/test/openssl/test_cipher.rb
+++ b/test/openssl/test_cipher.rb
@@ -32,28 +32,28 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
salt = "\x01" * 8
num = 2048
pt = "data to be encrypted"
- cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
- cipher.pkcs5_keyivgen(pass, salt, num, "MD5")
+ cipher = OpenSSL::Cipher.new("AES-256-CBC").encrypt
+ cipher.pkcs5_keyivgen(pass, salt, num, "SHA256")
s1 = cipher.update(pt) << cipher.final
- d1 = num.times.inject(pass + salt) {|out, _| OpenSSL::Digest.digest('MD5', out) }
- d2 = num.times.inject(d1 + pass + salt) {|out, _| OpenSSL::Digest.digest('MD5', out) }
- key = (d1 + d2)[0, 24]
- iv = (d1 + d2)[24, 8]
- cipher = new_encryptor("DES-EDE3-CBC", key: key, iv: iv)
+ d1 = num.times.inject(pass + salt) {|out, _| OpenSSL::Digest.digest('SHA256', out) }
+ d2 = num.times.inject(d1 + pass + salt) {|out, _| OpenSSL::Digest.digest('SHA256', out) }
+ key = (d1 + d2)[0, 32]
+ iv = (d1 + d2)[32, 16]
+ cipher = new_encryptor("AES-256-CBC", key: key, iv: iv)
s2 = cipher.update(pt) << cipher.final
assert_equal s1, s2
- cipher2 = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
- assert_raise(ArgumentError) { cipher2.pkcs5_keyivgen(pass, salt, -1, "MD5") }
+ cipher2 = OpenSSL::Cipher.new("AES-256-CBC").encrypt
+ assert_raise(ArgumentError) { cipher2.pkcs5_keyivgen(pass, salt, -1, "SHA256") }
end
def test_info
- cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
- assert_equal "DES-EDE3-CBC", cipher.name
- assert_equal 24, cipher.key_len
- assert_equal 8, cipher.iv_len
+ cipher = OpenSSL::Cipher.new("AES-256-CBC").encrypt
+ assert_equal "AES-256-CBC", cipher.name
+ assert_equal 32, cipher.key_len
+ assert_equal 16, cipher.iv_len
end
def test_dup
@@ -80,13 +80,13 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
end
def test_key_iv_set
- cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
- assert_raise(ArgumentError) { cipher.key = "\x01" * 23 }
- assert_nothing_raised { cipher.key = "\x01" * 24 }
- assert_raise(ArgumentError) { cipher.key = "\x01" * 25 }
- assert_raise(ArgumentError) { cipher.iv = "\x01" * 7 }
- assert_nothing_raised { cipher.iv = "\x01" * 8 }
- assert_raise(ArgumentError) { cipher.iv = "\x01" * 9 }
+ cipher = OpenSSL::Cipher.new("AES-256-CBC").encrypt
+ assert_raise(ArgumentError) { cipher.key = "\x01" * 31 }
+ assert_nothing_raised { cipher.key = "\x01" * 32 }
+ assert_raise(ArgumentError) { cipher.key = "\x01" * 33 }
+ assert_raise(ArgumentError) { cipher.iv = "\x01" * 15 }
+ assert_nothing_raised { cipher.iv = "\x01" * 16 }
+ assert_raise(ArgumentError) { cipher.iv = "\x01" * 17 }
end
def test_random_key_iv
@@ -109,9 +109,12 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
end
def test_initialize
- cipher = OpenSSL::Cipher.new("DES-EDE3-CBC")
- assert_raise(RuntimeError) { cipher.__send__(:initialize, "DES-EDE3-CBC") }
+ cipher = OpenSSL::Cipher.new("AES-256-CBC")
+ assert_raise(RuntimeError) { cipher.__send__(:initialize, "AES-256-CBC") }
assert_raise(RuntimeError) { OpenSSL::Cipher.allocate.final }
+ assert_raise(OpenSSL::Cipher::CipherError) {
+ OpenSSL::Cipher.new("no such algorithm")
+ }
end
def test_ctr_if_exists
@@ -131,13 +134,14 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
def test_update_with_buffer
cipher = OpenSSL::Cipher.new("aes-128-ecb").encrypt
cipher.random_key
- expected = cipher.update("data") << cipher.final
- assert_equal 16, expected.bytesize
+ expected = cipher.update("data" * 10) << cipher.final
+ assert_equal 48, expected.bytesize
# Buffer is supplied
cipher.reset
buf = String.new
- assert_same buf, cipher.update("data", buf)
+ assert_same buf, cipher.update("data" * 10, buf)
+ assert_equal 32, buf.bytesize
assert_equal expected, buf + cipher.final
# Buffer is frozen
@@ -146,9 +150,9 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
# Buffer is a shared string [ruby-core:120141] [Bug #20937]
cipher.reset
- buf = "x" * 1024
- shared = buf[-("data".bytesize + 32)..-1]
- assert_same shared, cipher.update("data", shared)
+ buf = "x".b * 1024
+ shared = buf[-("data".bytesize * 10 + 32)..-1]
+ assert_same shared, cipher.update("data" * 10, shared)
assert_equal expected, shared + cipher.final
end
@@ -165,12 +169,12 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
%w(ecb cbc cfb ofb).each{|mode|
c1 = OpenSSL::Cipher.new("aes-256-#{mode}")
c1.encrypt
- c1.pkcs5_keyivgen("passwd")
+ c1.pkcs5_keyivgen("passwd", "12345678", 10000, "SHA256")
ct = c1.update(pt) + c1.final
c2 = OpenSSL::Cipher.new("aes-256-#{mode}")
c2.decrypt
- c2.pkcs5_keyivgen("passwd")
+ c2.pkcs5_keyivgen("passwd", "12345678", 10000, "SHA256")
assert_equal(pt, c2.update(ct) + c2.final)
}
end
@@ -182,6 +186,10 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
end
end
+ def test_auth_tag_error_inheritance
+ assert_equal OpenSSL::Cipher::CipherError, OpenSSL::Cipher::AuthTagError.superclass
+ end
+
def test_authenticated
cipher = OpenSSL::Cipher.new('aes-128-gcm')
assert_predicate(cipher, :authenticated?)
@@ -212,7 +220,8 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct.length, auth_tag: tag[0, 8], auth_data: aad)
assert_equal pt, cipher.update(ct) << cipher.final
- # wrong tag is rejected
+ # wrong tag is rejected - in CCM, authentication happens during update, but
+ # we consider this a general CipherError since update failures can have various causes
tag2 = tag.dup
tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff)
cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct.length, auth_tag: tag2, auth_data: aad)
@@ -265,19 +274,19 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff)
cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag2, auth_data: aad)
cipher.update(ct)
- assert_raise(OpenSSL::Cipher::CipherError) { cipher.final }
+ assert_raise(OpenSSL::Cipher::AuthTagError) { cipher.final }
# wrong aad is rejected
aad2 = aad[0..-2] << aad[-1].succ
cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad2)
cipher.update(ct)
- assert_raise(OpenSSL::Cipher::CipherError) { cipher.final }
+ assert_raise(OpenSSL::Cipher::AuthTagError) { cipher.final }
# wrong ciphertext is rejected
ct2 = ct[0..-2] << ct[-1].succ
cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad)
cipher.update(ct2)
- assert_raise(OpenSSL::Cipher::CipherError) { cipher.final }
+ assert_raise(OpenSSL::Cipher::AuthTagError) { cipher.final }
end
def test_aes_gcm_variable_iv_len
@@ -304,6 +313,9 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
end
def test_aes_ocb_tag_len
+ # AES-128-OCB is not FIPS-approved.
+ omit_on_fips
+
# RFC 7253 Appendix A; the second sample
key = ["000102030405060708090A0B0C0D0E0F"].pack("H*")
iv = ["BBAA99887766554433221101"].pack("H*")
@@ -337,6 +349,27 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
end if has_cipher?("aes-128-ocb")
+ def test_aes_gcm_siv
+ # AES-128-GCM-SIV is not FIPS-approved.
+ omit_on_fips
+
+ # RFC 8452 Appendix C.1., 8th example
+ key = ["01000000000000000000000000000000"].pack("H*")
+ iv = ["030000000000000000000000"].pack("H*")
+ aad = ["01"].pack("H*")
+ pt = ["0200000000000000"].pack("H*")
+ ct = ["1e6daba35669f4273b0a1a2560969cdf790d99759abd1508"].pack("H*")
+ tag = ["3b0a1a2560969cdf790d99759abd1508"].pack("H*")
+ ct_without_tag = ct.byteslice(0, ct.bytesize - tag.bytesize)
+
+ cipher = new_encryptor("aes-128-gcm-siv", key: key, iv: iv, auth_data: aad)
+ assert_equal ct_without_tag, cipher.update(pt) << cipher.final
+ assert_equal tag, cipher.auth_tag
+ cipher = new_decryptor("aes-128-gcm-siv", key: key, iv: iv, auth_tag: tag,
+ auth_data: aad)
+ assert_equal pt, cipher.update(ct_without_tag) << cipher.final
+ end if openssl?(3, 2, 0)
+
def test_aes_gcm_key_iv_order_issue
pt = "[ruby/openssl#49]"
cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt
@@ -363,7 +396,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
begin
cipher = OpenSSL::Cipher.new("id-aes192-wrap-pad").encrypt
- rescue OpenSSL::Cipher::CipherError, RuntimeError
+ rescue OpenSSL::Cipher::CipherError
omit "id-aes192-wrap-pad is not supported: #$!"
end
cipher.key = kek
diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb
index 5b4eb3c74c..bc1f680df5 100644
--- a/test/openssl/test_digest.rb
+++ b/test/openssl/test_digest.rb
@@ -6,23 +6,31 @@ if defined?(OpenSSL)
class OpenSSL::TestDigest < OpenSSL::TestCase
def setup
super
- @d1 = OpenSSL::Digest.new("MD5")
- @d2 = OpenSSL::Digest::MD5.new
+ @d1 = OpenSSL::Digest.new("SHA256")
+ @d2 = OpenSSL::Digest::SHA256.new
+ end
+
+ def test_initialize
+ assert_raise(OpenSSL::Digest::DigestError) {
+ OpenSSL::Digest.new("no such algorithm")
+ }
end
def test_digest
- null_hex = "d41d8cd98f00b204e9800998ecf8427e"
+ # SHA256 null value calculated by `echo -n "" | sha256sum`
+ null_hex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
null_bin = [null_hex].pack("H*")
data = "DATA"
- hex = "e44f9e348e41cb272efa87387728571b"
+ # SHA256 DATA value calculated by `echo -n "DATA" | sha256sum`
+ hex = "c97c29c7a71b392b437ee03fd17f09bb10b75e879466fc0eb757b2c4a78ac938"
bin = [hex].pack("H*")
assert_equal(null_bin, @d1.digest)
assert_equal(null_hex, @d1.hexdigest)
@d1 << data
assert_equal(bin, @d1.digest)
assert_equal(hex, @d1.hexdigest)
- assert_equal(bin, OpenSSL::Digest.digest('MD5', data))
- assert_equal(hex, OpenSSL::Digest.hexdigest('MD5', data))
+ assert_equal(bin, OpenSSL::Digest.digest('SHA256', data))
+ assert_equal(hex, OpenSSL::Digest.hexdigest('SHA256', data))
end
def test_eql
@@ -32,9 +40,9 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def test_info
- assert_equal("MD5", @d1.name, "name")
- assert_equal("MD5", @d2.name, "name")
- assert_equal(16, @d1.size, "size")
+ assert_equal("SHA256", @d1.name, "name")
+ assert_equal("SHA256", @d2.name, "name")
+ assert_equal(32, @d1.size, "size")
end
def test_dup
@@ -54,7 +62,10 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def test_digest_constants
- %w{MD5 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name|
+ non_fips_names = %w{MD5}
+ names = %w{SHA1 SHA224 SHA256 SHA384 SHA512}
+ names = non_fips_names + names unless OpenSSL.fips_mode
+ names.each do |name|
assert_not_nil(OpenSSL::Digest.new(name))
klass = OpenSSL::Digest.const_get(name.tr('-', '_'))
assert_not_nil(klass.new)
@@ -62,8 +73,17 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def test_digest_by_oid_and_name
- check_digest(OpenSSL::ASN1::ObjectId.new("MD5"))
- check_digest(OpenSSL::ASN1::ObjectId.new("SHA1"))
+ # SHA256
+ o1 = OpenSSL::Digest.digest("SHA256", "")
+ o2 = OpenSSL::Digest.digest("sha256", "")
+ assert_equal(o1, o2)
+ o3 = OpenSSL::Digest.digest("2.16.840.1.101.3.4.2.1", "")
+ assert_equal(o1, o3)
+
+ # An alias for SHA256 recognized by EVP_get_digestbyname(), but not by
+ # EVP_MD_fetch()
+ o4 = OpenSSL::Digest.digest("RSA-SHA256", "")
+ assert_equal(o1, o4)
end
def encode16(str)
@@ -109,12 +129,15 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
assert_equal(s512, OpenSSL::Digest.hexdigest('SHA3-512', ""))
end
- def test_digest_by_oid_and_name_sha2
- check_digest(OpenSSL::ASN1::ObjectId.new("SHA224"))
- check_digest(OpenSSL::ASN1::ObjectId.new("SHA256"))
- check_digest(OpenSSL::ASN1::ObjectId.new("SHA384"))
- check_digest(OpenSSL::ASN1::ObjectId.new("SHA512"))
- end
+ def test_fetched_evp_md
+ # KECCAK-256 is not FIPS-approved.
+ omit_on_fips
+
+ # Pre-NIST Keccak is an example of a digest algorithm that doesn't have an
+ # NID and requires dynamic allocation of EVP_MD
+ hex = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
+ assert_equal(hex, OpenSSL::Digest.hexdigest("KECCAK-256", ""))
+ end if openssl?(3, 2, 0)
def test_openssl_digest
assert_equal OpenSSL::Digest::MD5, OpenSSL::Digest("MD5")
@@ -133,15 +156,20 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
assert_include digests, "sha512"
end
- private
+ if respond_to?(:ractor) && defined?(Ractor.shareable_proc)
+ ractor
- def check_digest(oid)
- d = OpenSSL::Digest.new(oid.sn)
- assert_not_nil(d)
- d = OpenSSL::Digest.new(oid.ln)
- assert_not_nil(d)
- d = OpenSSL::Digest.new(oid.oid)
- assert_not_nil(d)
+ def test_ractor
+ assert_nothing_raised do
+ Ractor.new {
+ [
+ OpenSSL::Digest::SHA256.new(""),
+ OpenSSL::Digest::SHA256.hexdigest(""),
+ OpenSSL::Digest::SHA256.digest(""),
+ ]
+ }.value
+ end
+ end
end
end
diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb
index efc2655e25..683e0011e8 100644
--- a/test/openssl/test_fips.rb
+++ b/test/openssl/test_fips.rb
@@ -30,7 +30,7 @@ class OpenSSL::TestFIPS < OpenSSL::TestCase
def test_fips_mode_is_reentrant
return if aws_lc? # AWS-LC's FIPS mode is decided at compile time.
- assert_separately(["-ropenssl"], <<~"end;")
+ assert_ruby_status(["-ropenssl"], <<~"end;")
OpenSSL.fips_mode = false
OpenSSL.fips_mode = false
end;
diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb
index 3cb707448a..7cf820628e 100644
--- a/test/openssl/test_hmac.rb
+++ b/test/openssl/test_hmac.rb
@@ -4,14 +4,18 @@ require_relative 'utils'
if defined?(OpenSSL)
class OpenSSL::TestHMAC < OpenSSL::TestCase
- def test_hmac
+ def test_hmac_md5
+ omit_on_fips # MD5
+
# RFC 2202 2. Test Cases for HMAC-MD5
hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "MD5")
hmac.update("Hi There")
assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), hmac.digest
assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hmac.hexdigest
assert_equal "kpRyejY4uxwT9I74FYv8nQ==", hmac.base64digest
+ end
+ def test_hmac_sha224
# RFC 4231 4.2. Test Case 1
hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "SHA224")
hmac.update("Hi There")
@@ -21,7 +25,7 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase
end
def test_dup
- h1 = OpenSSL::HMAC.new("KEY", "MD5")
+ h1 = OpenSSL::HMAC.new("KEY"*32, "SHA256")
h1.update("DATA")
h = h1.dup
assert_equal(h1.digest, h.digest, "dup digest")
@@ -35,7 +39,7 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase
end
def test_reset_keep_key
- h1 = OpenSSL::HMAC.new("KEY", "MD5")
+ h1 = OpenSSL::HMAC.new("KEY"*32, "SHA256")
first = h1.update("test").hexdigest
h1.reset
second = h1.update("test").hexdigest
@@ -43,9 +47,9 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase
end
def test_eq
- h1 = OpenSSL::HMAC.new("KEY", "MD5")
- h2 = OpenSSL::HMAC.new("KEY", OpenSSL::Digest.new("MD5"))
- h3 = OpenSSL::HMAC.new("FOO", "MD5")
+ h1 = OpenSSL::HMAC.new("KEY"*32, "SHA256")
+ h2 = OpenSSL::HMAC.new("KEY"*32, OpenSSL::Digest.new("SHA256"))
+ h3 = OpenSSL::HMAC.new("FOO"*32, "SHA256")
assert_equal h1, h2
refute_equal h1, h2.digest
@@ -53,17 +57,19 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase
end
def test_singleton_methods
- # RFC 2202 2. Test Cases for HMAC-MD5
- key = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*")
- digest = OpenSSL::HMAC.digest("MD5", key, "Hi There")
- assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), digest
- hexdigest = OpenSSL::HMAC.hexdigest("MD5", key, "Hi There")
- assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hexdigest
- b64digest = OpenSSL::HMAC.base64digest("MD5", key, "Hi There")
- assert_equal "kpRyejY4uxwT9I74FYv8nQ==", b64digest
+ # RFC 4231 4.2. Test Case 1
+ key = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*")
+ digest = OpenSSL::HMAC.digest("SHA256", key, "Hi There")
+ assert_equal ["b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"].pack("H*"), digest
+ hexdigest = OpenSSL::HMAC.hexdigest("SHA256", key, "Hi There")
+ assert_equal "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", hexdigest
+ b64digest = OpenSSL::HMAC.base64digest("SHA256", key, "Hi There")
+ assert_equal "sDRMYdjbOFNcqK/OrwvxK4gdwgDJgz2nJuk3bC4yz/c=", b64digest
end
def test_zero_length_key
+ omit_on_fips # Key length
+
# Empty string as the key
hexdigest = OpenSSL::HMAC.hexdigest("SHA256", "\0"*32, "test")
assert_equal "43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb", hexdigest
diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb
index 6a12a25aa8..708d1883af 100644
--- a/test/openssl/test_kdf.rb
+++ b/test/openssl/test_kdf.rb
@@ -5,64 +5,31 @@ if defined?(OpenSSL)
class OpenSSL::TestKDF < OpenSSL::TestCase
def test_pkcs5_pbkdf2_hmac_compatibility
- expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1")
- assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1"))
- assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20))
+ # PBKDF2 salt >= 16 bytes (128 bits) and iterations >= 1000 are required in
+ # FIPS.
+ # SP 800-132.
+ # https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf
+ # * 5.1 The Salt (S)
+ # * 5.2 The Iteration Count (C)
+ # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L235-L240
+ # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L247-L252
+ # Use the same parameters with test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25.
+ expected = OpenSSL::KDF.pbkdf2_hmac("passwordPASSWORDpassword",
+ salt: "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ iterations: 4096,
+ length: 25,
+ hash: "sha1")
+ assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ 25,
+ "sha1"))
+ assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ 25))
end
- def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20
- p ="password"
- s = "salt"
- c = 1
- dk_len = 20
- raw = %w{ 0c 60 c8 0f 96 1f 0e 71
- f3 a9 b5 24 af 60 12 06
- 2f e0 37 a6 }
- expected = [raw.join('')].pack('H*')
- value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1")
- assert_equal(expected, value)
- end
-
- def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20
- p ="password"
- s = "salt"
- c = 2
- dk_len = 20
- raw = %w{ ea 6c 01 4d c7 2d 6f 8c
- cd 1e d9 2a ce 1d 41 f0
- d8 de 89 57 }
- expected = [raw.join('')].pack('H*')
- value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1")
- assert_equal(expected, value)
- end
-
- def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20
- p ="password"
- s = "salt"
- c = 4096
- dk_len = 20
- raw = %w{ 4b 00 79 01 b7 65 48 9a
- be ad 49 d9 26 f7 21 d0
- 65 a4 29 c1 }
- expected = [raw.join('')].pack('H*')
- value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1")
- assert_equal(expected, value)
- end
-
-# takes too long!
-# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20
-# p ="password"
-# s = "salt"
-# c = 16777216
-# dk_len = 20
-# raw = %w{ ee fe 3d 61 cd 4d a4 e4
-# e9 94 5b 3d 6b a2 15 8c
-# 26 34 e9 84 }
-# expected = [raw.join('')].pack('H*')
-# value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1")
-# assert_equal(expected, value)
-# end
-
def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25
p ="passwordPASSWORDpassword"
s = "saltSALTsaltSALTsaltSALTsaltSALTsalt"
@@ -78,18 +45,6 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
assert_equal(expected, value)
end
- def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16
- p ="pass\0word"
- s = "sa\0lt"
- c = 4096
- dk_len = 16
- raw = %w{ 56 fa 6a a7 55 48 09 9d
- cc 37 d7 f0 34 25 e0 c3 }
- expected = [raw.join('')].pack('H*')
- value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1")
- assert_equal(expected, value)
- end
-
def test_pbkdf2_hmac_sha256_c_20000_len_32
#unfortunately no official test vectors available yet for SHA-2
p ="password"
@@ -103,6 +58,11 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
def test_scrypt_rfc7914_first
pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0
+ # scrypt is not available in FIPS.
+ # EVP_KDF_fetch(ctx, OSSL_KDF_NAME_SCRYPT, propq) returns NULL in FIPS.
+ # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/crypto/evp/pbe_scrypt.c#L67-L71
+ omit_on_fips
+
pass = ""
salt = ""
n = 16
@@ -118,6 +78,9 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
def test_scrypt_rfc7914_second
pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0
+ # scrypt is not available in FIPS.
+ omit_on_fips
+
pass = "password"
salt = "NaCl"
n = 1024
@@ -131,6 +94,7 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen))
end
+ # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.1
def test_hkdf_rfc5869_test_case_1
hash = "sha256"
ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
@@ -144,6 +108,7 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))
end
+ # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.3
def test_hkdf_rfc5869_test_case_3
hash = "sha256"
ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
@@ -157,16 +122,32 @@ class OpenSSL::TestKDF < OpenSSL::TestCase
assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))
end
- def test_hkdf_rfc5869_test_case_4
+ # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.5
+ def test_hkdf_rfc5869_test_case_5
hash = "sha1"
- ikm = B("0b0b0b0b0b0b0b0b0b0b0b")
- salt = B("000102030405060708090a0b0c")
- info = B("f0f1f2f3f4f5f6f7f8f9")
- l = 42
-
- okm = B("085a01ea1b10f36933068b56efa5ad81" \
- "a4f14b822f5b091568a9cdd4f155fda2" \
- "c22e422478d305f3f896")
+ ikm = B("000102030405060708090a0b0c0d0e0f" \
+ "101112131415161718191a1b1c1d1e1f" \
+ "202122232425262728292a2b2c2d2e2f" \
+ "303132333435363738393a3b3c3d3e3f" \
+ "404142434445464748494a4b4c4d4e4f")
+ salt = B("606162636465666768696a6b6c6d6e6f" \
+ "707172737475767778797a7b7c7d7e7f" \
+ "808182838485868788898a8b8c8d8e8f" \
+ "909192939495969798999a9b9c9d9e9f" \
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf")
+ info = B("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" \
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" \
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
+ l = 82
+
+ okm = B("0bd770a74d1160f7c9f12cd5912a06eb" \
+ "ff6adcae899d92191fe4305673ba2ffe" \
+ "8fa3f1a4e5ad79f3f334b3b202b2173c" \
+ "486ea37ce3d397ed034c7f9dfeb15c5e" \
+ "927336d0441f4c4300e2cff0d0900b52" \
+ "d3b4")
assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))
end
diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb
index d76fc9e5cf..0484429289 100644
--- a/test/openssl/test_ns_spki.rb
+++ b/test/openssl/test_ns_spki.rb
@@ -17,8 +17,8 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase
end
def test_build_data
- key1 = Fixtures.pkey("rsa1024")
- key2 = Fixtures.pkey("rsa2048")
+ key1 = Fixtures.pkey("rsa-1")
+ key2 = Fixtures.pkey("rsa-2")
spki = OpenSSL::Netscape::SPKI.new
spki.challenge = "RandomString"
spki.public_key = key1.public_key
diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb
index cf96fc22e5..c43ff5cb55 100644
--- a/test/openssl/test_ocsp.rb
+++ b/test/openssl/test_ocsp.rb
@@ -13,7 +13,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
# @cert2 @ocsp_cert
ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA")
- @ca_key = Fixtures.pkey("rsa1024")
+ @ca_key = Fixtures.pkey("rsa-1")
ca_exts = [
["basicConstraints", "CA:TRUE", true],
["keyUsage", "cRLSign,keyCertSign", true],
@@ -22,7 +22,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
ca_subj, @ca_key, 1, ca_exts, nil, nil)
cert_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA2")
- @cert_key = Fixtures.pkey("rsa1024")
+ @cert_key = Fixtures.pkey("rsa-2")
cert_exts = [
["basicConstraints", "CA:TRUE", true],
["keyUsage", "cRLSign,keyCertSign", true],
@@ -31,14 +31,14 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
cert_subj, @cert_key, 5, cert_exts, @ca_cert, @ca_key)
cert2_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert")
- @cert2_key = Fixtures.pkey("rsa1024")
+ @cert2_key = Fixtures.pkey("rsa-3")
cert2_exts = [
]
@cert2 = OpenSSL::TestUtils.issue_cert(
cert2_subj, @cert2_key, 10, cert2_exts, @cert, @cert_key)
ocsp_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCAOCSP")
- @ocsp_key = Fixtures.pkey("rsa2048")
+ @ocsp_key = Fixtures.pkey("p256")
ocsp_exts = [
["extendedKeyUsage", "OCSPSigning", true],
]
@@ -63,8 +63,10 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
def test_certificate_id_issuer_key_hash
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
- assert_equal OpenSSL::Digest.hexdigest('SHA1', OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), cid.issuer_key_hash
- assert_equal "d1fef9fbf8ae1bc160cbfa03e2596dd873089213", cid.issuer_key_hash
+ # content of subjectPublicKey (bit string) in SubjectPublicKeyInfo
+ spki = OpenSSL::ASN1.decode(@ca_key.public_to_der)
+ assert_equal OpenSSL::Digest.hexdigest("SHA1", spki.value[1].value),
+ cid.issuer_key_hash
end
def test_certificate_id_hash_algorithm
@@ -213,6 +215,35 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
assert_equal bres.to_der, bres.dup.to_der
end
+ def test_basic_response_status_good
+ bres = OpenSSL::OCSP::BasicResponse.new
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, nil)
+ bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert])
+
+ statuses = bres.status
+ assert_equal 1, statuses.size
+ status = statuses[0]
+ assert_equal cid.to_der, status[0].to_der
+ assert_equal OpenSSL::OCSP::V_CERTSTATUS_GOOD, status[1]
+ assert_nil status[3] # revtime should be nil for GOOD status
+ end
+
+ def test_basic_response_status_revoked
+ bres = OpenSSL::OCSP::BasicResponse.new
+ now = Time.at(Time.now.to_i)
+ cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))
+ bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_REVOKED,
+ OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil)
+ bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert])
+
+ statuses = bres.status
+ assert_equal 1, statuses.size
+ status = statuses[0]
+ assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, status[1]
+ assert_equal now - 400, status[3] # revtime should be the revocation time
+ end
+
def test_basic_response_response_operations
bres = OpenSSL::OCSP::BasicResponse.new
now = Time.at(Time.now.to_i)
diff --git a/test/openssl/test_ossl.rb b/test/openssl/test_ossl.rb
index 9f4b39d4f5..1b9bde53ef 100644
--- a/test/openssl/test_ossl.rb
+++ b/test/openssl/test_ossl.rb
@@ -3,42 +3,52 @@ require_relative "utils"
if defined?(OpenSSL)
-class OpenSSL::OSSL < OpenSSL::SSLTestCase
+class OpenSSL::TestOSSL < OpenSSL::TestCase
def test_fixed_length_secure_compare
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "a") }
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aa") }
- assert OpenSSL.fixed_length_secure_compare("aaa", "aaa")
- assert OpenSSL.fixed_length_secure_compare(
+ assert_true(OpenSSL.fixed_length_secure_compare("aaa", "aaa"))
+ assert_true(OpenSSL.fixed_length_secure_compare(
OpenSSL::Digest.digest('SHA256', "aaa"), OpenSSL::Digest::SHA256.digest("aaa")
- )
+ ))
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aaaa") }
- refute OpenSSL.fixed_length_secure_compare("aaa", "baa")
- refute OpenSSL.fixed_length_secure_compare("aaa", "aba")
- refute OpenSSL.fixed_length_secure_compare("aaa", "aab")
+ assert_false(OpenSSL.fixed_length_secure_compare("aaa", "baa"))
+ assert_false(OpenSSL.fixed_length_secure_compare("aaa", "aba"))
+ assert_false(OpenSSL.fixed_length_secure_compare("aaa", "aab"))
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aaab") }
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "b") }
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bb") }
- refute OpenSSL.fixed_length_secure_compare("aaa", "bbb")
+ assert_false(OpenSSL.fixed_length_secure_compare("aaa", "bbb"))
assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bbbb") }
end
+ def test_fixed_length_secure_compare_uaf
+ str1 = "A" * 1000000
+ evil_obj = Object.new
+ evil_obj.define_singleton_method(:to_str) do
+ str1.replace("C" * 1000000)
+ "B" * 1000000
+ end
+ assert_false(OpenSSL.fixed_length_secure_compare(str1, evil_obj))
+ end
+
def test_secure_compare
- refute OpenSSL.secure_compare("aaa", "a")
- refute OpenSSL.secure_compare("aaa", "aa")
+ assert_false(OpenSSL.secure_compare("aaa", "a"))
+ assert_false(OpenSSL.secure_compare("aaa", "aa"))
- assert OpenSSL.secure_compare("aaa", "aaa")
+ assert_true(OpenSSL.secure_compare("aaa", "aaa"))
- refute OpenSSL.secure_compare("aaa", "aaaa")
- refute OpenSSL.secure_compare("aaa", "baa")
- refute OpenSSL.secure_compare("aaa", "aba")
- refute OpenSSL.secure_compare("aaa", "aab")
- refute OpenSSL.secure_compare("aaa", "aaab")
- refute OpenSSL.secure_compare("aaa", "b")
- refute OpenSSL.secure_compare("aaa", "bb")
- refute OpenSSL.secure_compare("aaa", "bbb")
- refute OpenSSL.secure_compare("aaa", "bbbb")
+ assert_false(OpenSSL.secure_compare("aaa", "aaaa"))
+ assert_false(OpenSSL.secure_compare("aaa", "baa"))
+ assert_false(OpenSSL.secure_compare("aaa", "aba"))
+ assert_false(OpenSSL.secure_compare("aaa", "aab"))
+ assert_false(OpenSSL.secure_compare("aaa", "aaab"))
+ assert_false(OpenSSL.secure_compare("aaa", "b"))
+ assert_false(OpenSSL.secure_compare("aaa", "bb"))
+ assert_false(OpenSSL.secure_compare("aaa", "bbb"))
+ assert_false(OpenSSL.secure_compare("aaa", "bbbb"))
end
def test_memcmp_timing
@@ -63,19 +73,30 @@ class OpenSSL::OSSL < OpenSSL::SSLTestCase
end
assert_operator(a_b_time, :<, a_c_time * 10, "fixed_length_secure_compare timing test failed")
assert_operator(a_c_time, :<, a_b_time * 10, "fixed_length_secure_compare timing test failed")
- end
+ end if ENV["OSSL_TEST_ALL"] == "1"
def test_error_data
- # X509V3_EXT_nconf_nid() called from OpenSSL::X509::ExtensionFactory#create_ext is a function
- # that uses ERR_raise_data() to append additional information about the error.
+ # X509V3_EXT_nconf_nid() called from
+ # OpenSSL::X509::ExtensionFactory#create_ext is a function that uses
+ # ERR_raise_data() to append additional information about the error.
#
# The generated message should look like:
# "subjectAltName = IP:not.a.valid.ip.address: bad ip address (value=not.a.valid.ip.address)"
# "subjectAltName = IP:not.a.valid.ip.address: error in extension (name=subjectAltName, value=IP:not.a.valid.ip.address)"
+ #
+ # The string inside parentheses is the ERR_TXT_STRING data, and is appended
+ # by ossl_make_error(), so we check it here.
ef = OpenSSL::X509::ExtensionFactory.new
- assert_raise_with_message(OpenSSL::X509::ExtensionError, /value=(IP:)?not.a.valid.ip.address\)/) {
+ e = assert_raise(OpenSSL::X509::ExtensionError) {
ef.create_ext("subjectAltName", "IP:not.a.valid.ip.address")
}
+ assert_match(/not.a.valid.ip.address\)\z/, e.message)
+
+ # We currently craft the strings based on ERR_error_string()'s style:
+ # error:<error code in hex>:<library>:<function>:<reason> (data)
+ assert_instance_of(Array, e.errors)
+ assert_match(/\Aerror:.*not.a.valid.ip.address\)\z/, e.errors.last)
+ assert_include(e.detailed_message, "not.a.valid.ip.address")
end
end
diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb
index 1b5328774e..617c156cbd 100644
--- a/test/openssl/test_pkcs12.rb
+++ b/test/openssl/test_pkcs12.rb
@@ -3,6 +3,29 @@ require_relative "utils"
if defined?(OpenSSL)
+# OpenSSL::PKCS12.create calling the PKCS12_create() has the argument mac_iter
+# which uses a MAC key using PKCS12KDF which is not FIPS-approved.
+# OpenSSL::PKCS12.new with base64-encoded example calling PKCS12_parse()
+# verifies the MAC key using PKCS12KDF which is not FIPS-approved.
+#
+# PBE-SHA1-3DES uses PKCS12KDF which is not FIPS-approved according to the RFC
+# 7292 PKCS#12.
+# https://datatracker.ietf.org/doc/html/rfc7292#appendix-C
+# > The PBES1 encryption scheme defined in PKCS #5 provides a number of
+# > algorithm identifiers for deriving keys and IVs; here, we specify a
+# > few more, all of which use the procedure detailed in Appendices B.2
+# > and B.3 to construct keys (and IVs, where needed). As is implied by
+# > their names, all of the object identifiers below use the hash
+# > function SHA-1.
+# > ...
+# > pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}
+#
+# Note that the pbeWithSHAAnd3-KeyTripleDES-CBC (pkcs12-pbeids 3) in the RFC
+# 7292 PKCS#12 means PBE-SHA1-3DES in OpenSSL. PKCS12KDF is used in PKCS#12.
+# https://oidref.com/1.2.840.113549.1.12.1.3
+# https://github.com/openssl/openssl/blob/ed57d1e06dca28689190e00d9893e0fd7ecc67c1/crypto/objects/objects.txt#L385
+return if OpenSSL.fips_mode
+
module OpenSSL
class TestPKCS12 < OpenSSL::TestCase
DEFAULT_PBE_PKEYS = "PBE-SHA1-3DES"
@@ -210,8 +233,13 @@ module OpenSSL
end
def test_new_with_no_keys
- # generated with:
- # openssl pkcs12 -certpbe PBE-SHA1-3DES -in <@mycert> -nokeys -export
+ # Generated with the following steps:
+ # Print the value of the @mycert such as by `puts @mycert.to_s` and
+ # save the value as the file `mycert.pem`.
+ # Run the following commands:
+ # openssl pkcs12 -certpbe PBE-SHA1-3DES -in <(cat mycert.pem) \
+ # -nokeys -export -passout pass:abc123 -out /tmp/p12.out
+ # base64 -w 60 /tmp/p12.out
str = <<~EOF.unpack1("m")
MIIGJAIBAzCCBeoGCSqGSIb3DQEHAaCCBdsEggXXMIIF0zCCBc8GCSqGSIb3
DQEHBqCCBcAwggW8AgEAMIIFtQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMw
@@ -259,8 +287,10 @@ AA==
end
def test_new_with_no_certs
- # generated with:
- # openssl pkcs12 -inkey fixtures/openssl/pkey/rsa-1.pem -nocerts -export
+ # Generated with the folowing steps:
+ # openssl pkcs12 -inkey test/openssl/fixtures/pkey/rsa-1.pem \
+ # -nocerts -export -passout pass:abc123 -out /tmp/p12.out
+ # base64 -w 60 /tmp/p12.out
str = <<~EOF.unpack1("m")
MIIJ7wIBAzCCCbUGCSqGSIb3DQEHAaCCCaYEggmiMIIJnjCCCZoGCSqGSIb3
DQEHAaCCCYsEggmHMIIJgzCCCX8GCyqGSIb3DQEMCgECoIIJbjCCCWowHAYK
diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb
index 80e341cab9..b3129c0cdf 100644
--- a/test/openssl/test_pkcs7.rb
+++ b/test/openssl/test_pkcs7.rb
@@ -6,92 +6,125 @@ if defined?(OpenSSL)
class OpenSSL::TestPKCS7 < OpenSSL::TestCase
def setup
super
- @rsa1024 = Fixtures.pkey("rsa1024")
- @rsa2048 = Fixtures.pkey("rsa2048")
- ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
- ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1")
- ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2")
+ @ca_key = Fixtures.pkey("rsa-1")
+ @ee1_key = Fixtures.pkey("rsa-2")
+ @ee2_key = Fixtures.pkey("rsa-3")
+ ca = OpenSSL::X509::Name.new([["CN", "CA"]])
+ ee1 = OpenSSL::X509::Name.new([["CN", "EE1"]])
+ ee2 = OpenSSL::X509::Name.new([["CN", "EE2"]])
ca_exts = [
- ["basicConstraints","CA:TRUE",true],
- ["keyUsage","keyCertSign, cRLSign",true],
- ["subjectKeyIdentifier","hash",false],
- ["authorityKeyIdentifier","keyid:always",false],
+ ["basicConstraints", "CA:TRUE", true],
+ ["keyUsage", "keyCertSign, cRLSign", true],
+ ["subjectKeyIdentifier", "hash", false],
+ ["authorityKeyIdentifier", "keyid:always", false],
]
- @ca_cert = issue_cert(ca, @rsa2048, 1, ca_exts, nil, nil)
+ @ca_cert = issue_cert(ca, @ca_key, 1, ca_exts, nil, nil)
ee_exts = [
- ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true],
- ["authorityKeyIdentifier","keyid:always",false],
- ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false],
+ ["keyUsage", "nonRepudiation, digitalSignature, keyEncipherment", true],
+ ["authorityKeyIdentifier", "keyid:always", false],
+ ["extendedKeyUsage", "clientAuth, emailProtection, codeSigning", false],
]
- @ee1_cert = issue_cert(ee1, @rsa1024, 2, ee_exts, @ca_cert, @rsa2048)
- @ee2_cert = issue_cert(ee2, @rsa1024, 3, ee_exts, @ca_cert, @rsa2048)
+ @ee1_cert = issue_cert(ee1, @ee1_key, 2, ee_exts, @ca_cert, @ca_key)
+ @ee2_cert = issue_cert(ee2, @ee2_key, 3, ee_exts, @ca_cert, @ca_key)
end
def test_signed
store = OpenSSL::X509::Store.new
store.add_cert(@ca_cert)
+
+ data = "aaaaa\nbbbbb\nccccc\n"
ca_certs = [@ca_cert]
+ tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, ca_certs)
+ # TODO: #data contains untranslated content
+ assert_equal("aaaaa\nbbbbb\nccccc\n", tmp.data)
+ assert_nil(tmp.error_string)
- data = "aaaaa\r\nbbbbb\r\nccccc\r\n"
- tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs)
p7 = OpenSSL::PKCS7.new(tmp.to_der)
+ assert_nil(p7.data)
+ assert_nil(p7.error_string)
+
+ assert_true(p7.verify([], store))
+ # AWS-LC does not appear to convert to CRLF automatically
+ assert_equal("aaaaa\r\nbbbbb\r\nccccc\r\n", p7.data) unless aws_lc?
+ assert_nil(p7.error_string)
+
certs = p7.certificates
- signers = p7.signers
- assert(p7.verify([], store))
- assert_equal(data, p7.data)
assert_equal(2, certs.size)
- assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s)
- assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s)
+ assert_equal(@ee1_cert.subject, certs[0].subject)
+ assert_equal(@ca_cert.subject, certs[1].subject)
+
+ signers = p7.signers
assert_equal(1, signers.size)
assert_equal(@ee1_cert.serial, signers[0].serial)
- assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s)
+ assert_equal(@ee1_cert.issuer, signers[0].issuer)
+ # AWS-LC does not generate authenticatedAttributes
+ assert_in_delta(Time.now, signers[0].signed_time, 10) unless aws_lc?
+
+ assert_false(p7.verify([@ca_cert], OpenSSL::X509::Store.new))
+ end
+
+ def test_signed_flags
+ store = OpenSSL::X509::Store.new
+ store.add_cert(@ca_cert)
# Normally OpenSSL tries to translate the supplied content into canonical
# MIME format (e.g. a newline character is converted into CR+LF).
# If the content is a binary, PKCS7::BINARY flag should be used.
-
+ #
+ # PKCS7::NOATTR flag suppresses authenticatedAttributes.
data = "aaaaa\nbbbbb\nccccc\n"
- flag = OpenSSL::PKCS7::BINARY
- tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag)
+ flag = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::NOATTR
+ tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, [@ca_cert], flag)
p7 = OpenSSL::PKCS7.new(tmp.to_der)
- certs = p7.certificates
- signers = p7.signers
- assert(p7.verify([], store))
+
+ assert_true(p7.verify([], store))
assert_equal(data, p7.data)
+
+ certs = p7.certificates
assert_equal(2, certs.size)
- assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s)
- assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s)
+ assert_equal(@ee1_cert.subject, certs[0].subject)
+ assert_equal(@ca_cert.subject, certs[1].subject)
+
+ signers = p7.signers
assert_equal(1, signers.size)
assert_equal(@ee1_cert.serial, signers[0].serial)
- assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s)
+ assert_equal(@ee1_cert.issuer, signers[0].issuer)
+ assert_raise(OpenSSL::PKCS7::PKCS7Error) { signers[0].signed_time }
+ end
+
+ def test_signed_multiple_signers
+ store = OpenSSL::X509::Store.new
+ store.add_cert(@ca_cert)
# A signed-data which have multiple signatures can be created
# through the following steps.
# 1. create two signed-data
# 2. copy signerInfo and certificate from one to another
-
- tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag)
- tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag)
+ data = "aaaaa\r\nbbbbb\r\nccccc\r\n"
+ tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data)
+ tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @ee2_key, data)
tmp1.add_signer(tmp2.signers[0])
tmp1.add_certificate(@ee2_cert)
p7 = OpenSSL::PKCS7.new(tmp1.to_der)
- certs = p7.certificates
- signers = p7.signers
- assert(p7.verify([], store))
+ assert_true(p7.verify([], store))
assert_equal(data, p7.data)
+
+ certs = p7.certificates
assert_equal(2, certs.size)
+
+ signers = p7.signers
assert_equal(2, signers.size)
assert_equal(@ee1_cert.serial, signers[0].serial)
- assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s)
+ assert_equal(@ee1_cert.issuer, signers[0].issuer)
assert_equal(@ee2_cert.serial, signers[1].serial)
- assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s)
+ assert_equal(@ee2_cert.issuer, signers[1].issuer)
end
def test_signed_add_signer
data = "aaaaa\nbbbbb\nccccc\n"
- psi = OpenSSL::PKCS7::SignerInfo.new(@ee1_cert, @rsa1024, "sha256")
+ psi = OpenSSL::PKCS7::SignerInfo.new(@ee1_cert, @ee1_key, "sha256")
p7 = OpenSSL::PKCS7.new
p7.type = :signed
p7.add_signer(psi)
@@ -110,30 +143,82 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase
def test_detached_sign
store = OpenSSL::X509::Store.new
store.add_cert(@ca_cert)
- ca_certs = [@ca_cert]
data = "aaaaa\nbbbbb\nccccc\n"
+ ca_certs = [@ca_cert]
flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED
- tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag)
+ tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, ca_certs, flag)
p7 = OpenSSL::PKCS7.new(tmp.to_der)
- assert_nothing_raised do
- OpenSSL::ASN1.decode(p7)
- end
+ assert_predicate(p7, :detached?)
+ assert_true(p7.detached)
- certs = p7.certificates
- signers = p7.signers
- assert(!p7.verify([], store))
- assert(p7.verify([], store, data))
+ assert_false(p7.verify([], store))
+ # FIXME: Should it be nil?
+ assert_equal("", p7.data)
+ assert_match(/no content|NO_CONTENT/, p7.error_string)
+
+ assert_true(p7.verify([], store, data))
assert_equal(data, p7.data)
+ assert_nil(p7.error_string)
+
+ certs = p7.certificates
assert_equal(2, certs.size)
- assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s)
- assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s)
+ assert_equal(@ee1_cert.subject, certs[0].subject)
+ assert_equal(@ca_cert.subject, certs[1].subject)
+
+ signers = p7.signers
assert_equal(1, signers.size)
assert_equal(@ee1_cert.serial, signers[0].serial)
- assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s)
+ assert_equal(@ee1_cert.issuer, signers[0].issuer)
+ end
+
+ def test_signed_authenticated_attributes
+ # Using static PEM data because AWS-LC does not support generating one
+ # with authenticatedAttributes.
+ #
+ # p7 was generated with OpenSSL 3.4.1 with this program with commandline
+ # "faketime 2025-04-03Z ruby prog.rb":
+ #
+ # require_relative "test/openssl/utils"
+ # include OpenSSL::TestUtils
+ # key = Fixtures.pkey("p256")
+ # cert = issue_cert(OpenSSL::X509::Name.new([["CN", "cert"]]), key, 1, [], nil, nil)
+ # p7 = OpenSSL::PKCS7.sign(cert, key, "content", [])
+ # puts p7.to_pem
+ p7 = OpenSSL::PKCS7.new(<<~EOF)
+-----BEGIN PKCS7-----
+MIICvgYJKoZIhvcNAQcCoIICrzCCAqsCAQExDzANBglghkgBZQMEAgEFADAWBgkq
+hkiG9w0BBwGgCQQHY29udGVudKCCAQ4wggEKMIGxoAMCAQICAQEwCgYIKoZIzj0E
+AwIwDzENMAsGA1UEAwwEY2VydDAeFw0yNTA0MDIyMzAwMDFaFw0yNTA0MDMwMTAw
+MDFaMA8xDTALBgNVBAMMBGNlcnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQW
+CWTZz6hVQgpDrh5kb1uEs09YHuVJn8CsrjV4bLnADNT/QbnVe20J4FSX4xqFm2f1
+87Ukp0XiomZLf11eekQ2MAoGCCqGSM49BAMCA0gAMEUCIEg1fDI8b3hZAArgniVk
+HeM6puwgcMh5NXwvJ9x0unVmAiEAppecVTSQ+yEPyBG415Og6sK+RC78pcByEC81
+C/QSwRYxggFpMIIBZQIBATAUMA8xDTALBgNVBAMMBGNlcnQCAQEwDQYJYIZIAWUD
+BAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx
+DxcNMjUwNDAzMDAwMDAxWjAvBgkqhkiG9w0BCQQxIgQg7XACtDnprIRfIjV9gius
+FERzD722AW0+yUMil7nsn3MweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASow
+CwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0D
+AgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwCgYI
+KoZIzj0EAwIESDBGAiEAssymc28HySAhg+XeWIpSbtzkwycr2JG6dzHRZ+vn0ocC
+IQCJVpo1FTLZOHSc9UpjS+VKR4cg50Iz0HiPyo6hwjCrwA==
+-----END PKCS7-----
+ EOF
+
+ cert = p7.certificates[0]
+ store = OpenSSL::X509::Store.new.tap { |store|
+ store.time = Time.utc(2025, 4, 3)
+ store.add_cert(cert)
+ }
+ assert_equal(true, p7.verify([], store))
+ assert_equal(1, p7.signers.size)
+ signer = p7.signers[0]
+ assert_in_delta(Time.utc(2025, 4, 3), signer.signed_time, 10)
end
def test_enveloped
+ omit_on_fips # PKCS #1 v1.5 padding
+
certs = [@ee1_cert, @ee2_cert]
cipher = OpenSSL::Cipher::AES.new("128-CBC")
data = "aaaaa\nbbbbb\nccccc\n"
@@ -144,15 +229,20 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase
assert_equal(:enveloped, p7.type)
assert_equal(2, recip.size)
- assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s)
- assert_equal(2, recip[0].serial)
- assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert))
+ assert_equal(@ca_cert.subject, recip[0].issuer)
+ assert_equal(@ee1_cert.serial, recip[0].serial)
+ assert_equal(16, @ee1_key.decrypt(recip[0].enc_key).size)
+ assert_equal(data, p7.decrypt(@ee1_key, @ee1_cert))
+
+ assert_equal(@ca_cert.subject, recip[1].issuer)
+ assert_equal(@ee2_cert.serial, recip[1].serial)
+ assert_equal(data, p7.decrypt(@ee2_key, @ee2_cert))
- assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s)
- assert_equal(3, recip[1].serial)
- assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert))
+ assert_equal(data, p7.decrypt(@ee1_key))
- assert_equal(data, p7.decrypt(@rsa1024))
+ assert_raise(OpenSSL::PKCS7::PKCS7Error) {
+ p7.decrypt(@ca_key, @ca_cert)
+ }
# Default cipher has been removed in v3.3
assert_raise_with_message(ArgumentError, /RC2-40-CBC/) {
@@ -160,6 +250,28 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase
}
end
+ def test_enveloped_add_recipient
+ omit_on_fips # PKCS #1 v1.5 padding
+
+ data = "aaaaa\nbbbbb\nccccc\n"
+ ktri_ee1 = OpenSSL::PKCS7::RecipientInfo.new(@ee1_cert)
+ ktri_ee2 = OpenSSL::PKCS7::RecipientInfo.new(@ee2_cert)
+
+ tmp = OpenSSL::PKCS7.new
+ tmp.type = :enveloped
+ tmp.cipher = "AES-128-CBC"
+ tmp.add_recipient(ktri_ee1)
+ tmp.add_recipient(ktri_ee2)
+ tmp.add_data(data)
+
+ p7 = OpenSSL::PKCS7.new(tmp.to_der)
+ assert_equal(:enveloped, p7.type)
+ assert_equal(data, p7.decrypt(@ee1_key, @ee1_cert))
+ assert_equal(data, p7.decrypt(@ee2_key, @ee2_cert))
+ assert_equal([@ee1_cert.serial, @ee2_cert.serial].sort,
+ p7.recipients.map(&:serial).sort)
+ end
+
def test_data
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("pkcs7-data"),
@@ -175,6 +287,7 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase
p7 = OpenSSL::PKCS7.new(asn1)
assert_equal(:data, p7.type)
+ assert_equal(false, p7.detached)
assert_equal(false, p7.detached?)
# Not applicable
assert_nil(p7.certificates)
@@ -185,12 +298,13 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase
# PKCS7#verify can't distinguish verification failure and other errors
store = OpenSSL::X509::Store.new
assert_equal(false, p7.verify([@ee1_cert], store))
- assert_raise(OpenSSL::PKCS7::PKCS7Error) { p7.decrypt(@rsa1024) }
+ assert_match(/wrong content type|WRONG_CONTENT_TYPE/, p7.error_string)
+ assert_raise(OpenSSL::PKCS7::PKCS7Error) { p7.decrypt(@ee1_key) }
end
def test_empty_signed_data_ruby_bug_19974
data = "-----BEGIN PKCS7-----\nMAsGCSqGSIb3DQEHAg==\n-----END PKCS7-----\n"
- assert_raise(ArgumentError) { OpenSSL::PKCS7.new(data) }
+ assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.new(data) }
data = <<END
MIME-Version: 1.0
@@ -204,8 +318,8 @@ END
end
def test_graceful_parsing_failure #[ruby-core:43250]
- contents = File.read(__FILE__)
- assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) }
+ contents = "not a valid PKCS #7 PEM block"
+ assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.new(contents) }
end
def test_set_type_signed
@@ -226,12 +340,6 @@ END
assert_equal(:signedAndEnveloped, p7.type)
end
- def test_set_type_enveloped
- p7 = OpenSSL::PKCS7.new
- p7.type = "enveloped"
- assert_equal(:enveloped, p7.type)
- end
-
def test_set_type_encrypted
p7 = OpenSSL::PKCS7.new
p7.type = "encrypted"
@@ -246,7 +354,7 @@ END
ca_certs = [@ca_cert]
data = "aaaaa\r\nbbbbb\r\nccccc\r\n"
- tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs)
+ tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, ca_certs)
p7 = OpenSSL::PKCS7.new(tmp.to_der)
smime = OpenSSL::PKCS7.write_smime(p7)
assert_equal(true, smime.start_with?(<<END))
@@ -307,80 +415,34 @@ END
end
end
- def test_split_content
- pend "AWS-LC ASN.1 parsers has no current support for parsing indefinite BER constructed strings" if aws_lc?
-
- pki_message_pem = <<END
------BEGIN PKCS7-----
-MIIHSwYJKoZIhvcNAQcCoIIHPDCCBzgCAQExCzAJBgUrDgMCGgUAMIIDiAYJKoZI
-hvcNAQcBoIIDeQSCA3UwgAYJKoZIhvcNAQcDoIAwgAIBADGCARAwggEMAgEAMHUw
-cDEQMA4GA1UECgwHZXhhbXBsZTEXMBUGA1UEAwwOVEFSTUFDIFJPT1QgQ0ExIjAg
-BgkqhkiG9w0BCQEWE3NvbWVvbmVAZXhhbXBsZS5vcmcxCzAJBgNVBAYTAlVTMRIw
-EAYDVQQHDAlUb3duIEhhbGwCAWYwDQYJKoZIhvcNAQEBBQAEgYBspXXse8ZhG1FE
-E3PVAulbvrdR52FWPkpeLvSjgEkYzTiUi0CC3poUL1Ku5mOlavWAJgoJpFICDbvc
-N4ZNDCwOhnzoI9fMGmm1gvPQy15BdhhZRo9lP7Ga/Hg2APKT0/0yhPsmJ+w+u1e7
-OoJEVeEZ27x3+u745bGEcu8of5th6TCABgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcE
-CBNs2U5mMsd/oIAEggIQU6cur8QBz02/4eMpHdlU9IkyrRMiaMZ/ky9zecOAjnvY
-d2jZqS7RhczpaNJaSli3GmDsKrF+XqE9J58s9ScGqUigzapusTsxIoRUPr7Ztb0a
-pg8VWDipAsuw7GfEkgx868sV93uC4v6Isfjbhd+JRTFp/wR1kTi7YgSXhES+RLUW
-gQbDIDgEQYxJ5U951AJtnSpjs9za2ZkTdd8RSEizJK0bQ1vqLoApwAVgZqluATqQ
-AHSDCxhweVYw6+y90B9xOrqPC0eU7Wzryq2+Raq5ND2Wlf5/N11RQ3EQdKq/l5Te
-ijp9PdWPlkUhWVoDlOFkysjk+BE+7AkzgYvz9UvBjmZsMsWqf+KsZ4S8/30ndLzu
-iucsu6eOnFLLX8DKZxV6nYffZOPzZZL8hFBcE7PPgSdBEkazMrEBXq1j5mN7exbJ
-NOA5uGWyJNBMOCe+1JbxG9UeoqvCCTHESxEeDu7xR3NnSOD47n7cXwHr81YzK2zQ
-5oWpP3C8jzI7tUjLd1S0Z3Psd17oaCn+JOfUtuB0nc3wfPF/WPo0xZQodWxp2/Cl
-EltR6qr1zf5C7GwmLzBZ6bHFAIT60/JzV0/56Pn8ztsRFtI4cwaBfTfvnwi8/sD9
-/LYOMY+/b6UDCUSR7RTN7XfrtAqDEzSdzdJkOWm1jvM8gkLmxpZdvxG3ZvDYnEQE
-5Nq+un5nAny1wf3rWierBAjE5ntiAmgs5AAAAAAAAAAAAACgggHqMIIB5jCCAU+g
-AwIBAgIBATANBgkqhkiG9w0BAQUFADAvMS0wKwYDVQQDEyQwQUM5RjAyNi1EQ0VB
-LTRDMTItOTEyNy1DMEZEN0QyQThCNUEwHhcNMTIxMDE5MDk0NTQ3WhcNMTMxMDE5
-MDk0NTQ3WjAvMS0wKwYDVQQDEyQwQUM5RjAyNi1EQ0VBLTRDMTItOTEyNy1DMEZE
-N0QyQThCNUEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALTsTNyGIsKvyw56
-WI3Gll/RmjsupkrdEtPbx7OjS9MEgyhOAf9+u6CV0LJGHpy7HUeROykF6xpbSdCm
-Mr6kNObl5N0ljOb8OmV4atKjmGg1rWawDLyDQ9Dtuby+dzfHtzAzP+J/3ZoOtSqq
-AHVTnCclU1pm/uHN0HZ5nL5iLJTvAgMBAAGjEjAQMA4GA1UdDwEB/wQEAwIFoDAN
-BgkqhkiG9w0BAQUFAAOBgQA8K+BouEV04HRTdMZd3akjTQOm6aEGW4nIRnYIf8ZV
-mvUpLirVlX/unKtJinhGisFGpuYLMpemx17cnGkBeLCQRvHQjC+ho7l8/LOGheMS
-nvu0XHhvmJtRbm8MKHhogwZqHFDnXonvjyqhnhEtK5F2Fimcce3MoF2QtEe0UWv/
-8DGCAaowggGmAgEBMDQwLzEtMCsGA1UEAxMkMEFDOUYwMjYtRENFQS00QzEyLTkx
-MjctQzBGRDdEMkE4QjVBAgEBMAkGBSsOAwIaBQCggc0wEgYKYIZIAYb4RQEJAjEE
-EwIxOTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0x
-MjEwMTkwOTQ1NDdaMCAGCmCGSAGG+EUBCQUxEgQQ2EFUJdQNwQDxclIQ8qNyYzAj
-BgkqhkiG9w0BCQQxFgQUy8GFXPpAwRJUT3rdvNC9Pn+4eoswOAYKYIZIAYb4RQEJ
-BzEqEygwRkU3QzJEQTVEMDc2NzFFOTcxNDlCNUE3MDRCMERDNkM4MDYwRDJBMA0G
-CSqGSIb3DQEBAQUABIGAWUNdzvU2iiQOtihBwF0h48Nnw/2qX8uRjg6CVTOMcGji
-BxjUMifEbT//KJwljshl4y3yBLqeVYLOd04k6aKSdjgdZnrnUPI6p5tL5PfJkTAE
-L6qflZ9YCU5erE4T5U98hCQBMh4nOYxgaTjnZzhpkKQuEiKq/755cjzTzlI/eok=
------END PKCS7-----
-END
- pki_message_content_pem = <<END
------BEGIN PKCS7-----
-MIIDawYJKoZIhvcNAQcDoIIDXDCCA1gCAQAxggEQMIIBDAIBADB1MHAxEDAOBgNV
-BAoMB2V4YW1wbGUxFzAVBgNVBAMMDlRBUk1BQyBST09UIENBMSIwIAYJKoZIhvcN
-AQkBFhNzb21lb25lQGV4YW1wbGUub3JnMQswCQYDVQQGEwJVUzESMBAGA1UEBwwJ
-VG93biBIYWxsAgFmMA0GCSqGSIb3DQEBAQUABIGAbKV17HvGYRtRRBNz1QLpW763
-UedhVj5KXi70o4BJGM04lItAgt6aFC9SruZjpWr1gCYKCaRSAg273DeGTQwsDoZ8
-6CPXzBpptYLz0MteQXYYWUaPZT+xmvx4NgDyk9P9MoT7JifsPrtXuzqCRFXhGdu8
-d/ru+OWxhHLvKH+bYekwggI9BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECBNs2U5m
-Msd/gIICGFOnLq/EAc9Nv+HjKR3ZVPSJMq0TImjGf5Mvc3nDgI572Hdo2aku0YXM
-6WjSWkpYtxpg7Cqxfl6hPSefLPUnBqlIoM2qbrE7MSKEVD6+2bW9GqYPFVg4qQLL
-sOxnxJIMfOvLFfd7guL+iLH424XfiUUxaf8EdZE4u2IEl4REvkS1FoEGwyA4BEGM
-SeVPedQCbZ0qY7Pc2tmZE3XfEUhIsyStG0Nb6i6AKcAFYGapbgE6kAB0gwsYcHlW
-MOvsvdAfcTq6jwtHlO1s68qtvkWquTQ9lpX+fzddUUNxEHSqv5eU3oo6fT3Vj5ZF
-IVlaA5ThZMrI5PgRPuwJM4GL8/VLwY5mbDLFqn/irGeEvP99J3S87ornLLunjpxS
-y1/AymcVep2H32Tj82WS/IRQXBOzz4EnQRJGszKxAV6tY+Zje3sWyTTgObhlsiTQ
-TDgnvtSW8RvVHqKrwgkxxEsRHg7u8UdzZ0jg+O5+3F8B6/NWMyts0OaFqT9wvI8y
-O7VIy3dUtGdz7Hde6Ggp/iTn1LbgdJ3N8Hzxf1j6NMWUKHVsadvwpRJbUeqq9c3+
-QuxsJi8wWemxxQCE+tPyc1dP+ej5/M7bERbSOHMGgX03758IvP7A/fy2DjGPv2+l
-AwlEke0Uze1367QKgxM0nc3SZDlptY7zPIJC5saWXb8Rt2bw2JxEBOTavrp+ZwJ8
-tcH961onq8Tme2ICaCzk
------END PKCS7-----
-END
- pki_msg = OpenSSL::PKCS7.new(pki_message_pem)
- store = OpenSSL::X509::Store.new
- assert_equal(true, pki_msg.verify(nil, store, nil, OpenSSL::PKCS7::NOVERIFY))
- p7enc = OpenSSL::PKCS7.new(pki_msg.data)
- assert_equal(pki_message_content_pem, p7enc.to_pem)
+ def test_decode_ber_constructed_string
+ omit_on_fips # PKCS #1 v1.5 padding
+
+ p7 = OpenSSL::PKCS7.encrypt([@ee1_cert], "content", "aes-128-cbc")
+
+ # Make an equivalent BER to p7.to_der. Here we convert the encryptedContent
+ # field of EncryptedContentInfo into a constructed encoding using the
+ # indefinite length form.
+ # See https://www.rfc-editor.org/rfc/rfc2315#section-10.1
+ asn1 = OpenSSL::ASN1.decode(p7.to_der)
+ asn1.indefinite_length = true
+ enveloped_data_explicit_tag = asn1.value[1]
+ enveloped_data_explicit_tag.indefinite_length = true
+ enveloped_data = enveloped_data_explicit_tag.value[0]
+ enveloped_data.indefinite_length = true
+ encrypted_content_info = enveloped_data.value[2]
+ encrypted_content_info.indefinite_length = true
+ orig = encrypted_content_info.value[2]
+ encrypted_content_info.value[2] = OpenSSL::ASN1::ASN1Data.new([
+ OpenSSL::ASN1::OctetString(orig.value[...5]),
+ OpenSSL::ASN1::OctetString(orig.value[5...]),
+ ], 0, :CONTEXT_SPECIFIC).tap { |x| x.indefinite_length = true }
+
+ assert_not_equal(p7.to_der, asn1.to_der)
+ assert_equal(p7.to_der, OpenSSL::PKCS7.new(asn1.to_der).to_der)
+
+ assert_equal("content", OpenSSL::PKCS7.new(p7.to_der).decrypt(@ee1_key))
+ assert_equal("content", OpenSSL::PKCS7.new(asn1.to_der).decrypt(@ee1_key))
end
end
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
index 8444cfdcda..93d9e1d42f 100644
--- a/test/openssl/test_pkey.rb
+++ b/test/openssl/test_pkey.rb
@@ -8,16 +8,7 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
assert_instance_of OpenSSL::PKey::RSA, rsa
assert_equal "rsaEncryption", rsa.oid
assert_match %r{oid=rsaEncryption}, rsa.inspect
- end
-
- def test_generic_oid_inspect_x25519
- omit_on_fips
-
- # X25519 private key
- x25519 = OpenSSL::PKey.generate_key("X25519")
- assert_instance_of OpenSSL::PKey::PKey, x25519
- assert_equal "X25519", x25519.oid
- assert_match %r{oid=X25519}, x25519.inspect
+ assert_match %r{type_name=RSA}, rsa.inspect if openssl?(3, 0, 0)
end
def test_s_generate_parameters
@@ -69,10 +60,115 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
assert_not_equal nil, pkey.private_key
end
+ def test_s_read_pem_unknown_block
+ # A PEM-encoded certificate and a PEM-encoded private key are combined.
+ # Check that OSSL_STORE doesn't stop after the first PEM block.
+ orig = Fixtures.pkey("rsa-1")
+ subject = OpenSSL::X509::Name.new([["CN", "test"]])
+ cert = issue_cert(subject, orig, 1, [], nil, nil)
+
+ input = cert.to_text + cert.to_pem + orig.to_text + orig.private_to_pem
+ pkey = OpenSSL::PKey.read(input)
+ assert_equal(orig.private_to_der, pkey.private_to_der)
+ end
+
+ def test_s_read_der_then_pem
+ # If the input is valid as both DER and PEM (which allows garbage data
+ # before and after the block), it is read as DER
+ #
+ # TODO: Garbage data after DER should not be allowed, but it is currently
+ # ignored
+ orig1 = Fixtures.pkey("rsa-1")
+ orig2 = Fixtures.pkey("rsa-2")
+ pkey = OpenSSL::PKey.read(orig1.public_to_der + orig2.private_to_pem)
+ assert_equal(orig1.public_to_der, pkey.public_to_der)
+ assert_not_predicate(pkey, :private?)
+ end
+
+ def test_s_read_passphrase
+ orig = Fixtures.pkey("rsa-1")
+ encrypted_pem = orig.private_to_pem("AES-256-CBC", "correct_passphrase")
+ assert_match(/\A-----BEGIN ENCRYPTED PRIVATE KEY-----/, encrypted_pem)
+
+ # Correct passphrase passed as the second argument
+ pkey1 = OpenSSL::PKey.read(encrypted_pem, "correct_passphrase")
+ assert_equal(orig.private_to_der, pkey1.private_to_der)
+
+ # Correct passphrase returned by the block. The block gets false
+ called = 0
+ flag = nil
+ pkey2 = OpenSSL::PKey.read(encrypted_pem) { |f|
+ called += 1
+ flag = f
+ "correct_passphrase"
+ }
+ assert_equal(orig.private_to_der, pkey2.private_to_der)
+ assert_equal(1, called)
+ assert_false(flag)
+
+ # Incorrect passphrase passed. The block is not called
+ called = 0
+ assert_raise(OpenSSL::PKey::PKeyError) {
+ OpenSSL::PKey.read(encrypted_pem, "incorrect_passphrase") {
+ called += 1
+ }
+ }
+ assert_equal(0, called)
+
+ # Incorrect passphrase returned by the block. The block is called only once
+ called = 0
+ assert_raise(OpenSSL::PKey::PKeyError) {
+ OpenSSL::PKey.read(encrypted_pem) {
+ called += 1
+ "incorrect_passphrase"
+ }
+ }
+ assert_equal(1, called)
+ end
+
+ def test_s_read_passphrase_tty
+ omit "https://github.com/aws/aws-lc/pull/2555" if aws_lc?
+
+ orig = Fixtures.pkey("rsa-1")
+ encrypted_pem = orig.private_to_pem("AES-256-CBC", "correct_passphrase")
+
+ # Correct passphrase passed to OpenSSL's prompt
+ script = <<~"end;"
+ require "openssl"
+ Process.setsid
+ OpenSSL::PKey.read(#{encrypted_pem.dump})
+ puts "ok"
+ end;
+ assert_in_out_err([*$:.map { |l| "-I#{l}" }, "-e#{script}"],
+ "correct_passphrase\n") { |stdout, stderr|
+ assert_equal(["Enter PEM pass phrase:"], stderr)
+ assert_equal(["ok"], stdout)
+ }
+
+ # Incorrect passphrase passed to OpenSSL's prompt
+ script = <<~"end;"
+ require "openssl"
+ Process.setsid
+ begin
+ OpenSSL::PKey.read(#{encrypted_pem.dump})
+ rescue OpenSSL::PKey::PKeyError
+ puts "ok"
+ else
+ puts "expected OpenSSL::PKey::PKeyError"
+ end
+ end;
+ stdin = "incorrect_passphrase\n" * 5
+ assert_in_out_err([*$:.map { |l| "-I#{l}" }, "-e#{script}"],
+ stdin) { |stdout, stderr|
+ assert_equal(1, stderr.count("Enter PEM pass phrase:"))
+ assert_equal(["ok"], stdout)
+ }
+ end if ENV["OSSL_TEST_ALL"] == "1" && Process.respond_to?(:setsid)
+
def test_hmac_sign_verify
- pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" })
+ pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "a"*32 })
- hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest
+ hmac = OpenSSL::HMAC.new("a"*32, "SHA256").update("data").digest
assert_equal hmac, pkey.sign("SHA256", "data")
# EVP_PKEY_HMAC does not support verify
@@ -152,6 +248,8 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
alice = OpenSSL::PKey.read(alice_pem)
bob = OpenSSL::PKey.read(bob_pem)
assert_instance_of OpenSSL::PKey::PKey, alice
+ assert_equal "X25519", alice.oid
+ assert_match %r{oid=X25519}, alice.inspect
assert_equal alice_pem, alice.private_to_pem
assert_equal bob_pem, bob.public_to_pem
assert_equal [shared_secret].pack("H*"), alice.derive(bob)
@@ -168,6 +266,25 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
bob.raw_public_key.unpack1("H*")
end
+ def test_ml_dsa
+ # AWS-LC also supports ML-DSA, but it's implemented in a different way
+ return unless openssl?(3, 5, 0)
+
+ pkey = OpenSSL::PKey.generate_key("ML-DSA-44")
+ assert_match(/type_name=ML-DSA-44/, pkey.inspect)
+ sig = pkey.sign(nil, "data")
+ assert_equal(2420, sig.bytesize)
+ assert_equal(true, pkey.verify(nil, sig, "data"))
+
+ pub2 = OpenSSL::PKey.read(pkey.public_to_der)
+ assert_equal(true, pub2.verify(nil, sig, "data"))
+
+ raw_public_key = pkey.raw_public_key
+ assert_equal(1312, raw_public_key.bytesize)
+ pub3 = OpenSSL::PKey.new_raw_public_key("ML-DSA-44", raw_public_key)
+ assert_equal(true, pub3.verify(nil, sig, "data"))
+ end
+
def test_raw_initialize_errors
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("foo123", "xxx") }
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("ED25519", "xxx") }
@@ -176,10 +293,10 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
end
def test_compare?
- key1 = Fixtures.pkey("rsa1024")
- key2 = Fixtures.pkey("rsa1024")
- key3 = Fixtures.pkey("rsa2048")
- key4 = Fixtures.pkey("dh-1")
+ key1 = Fixtures.pkey("rsa-1")
+ key2 = Fixtures.pkey("rsa-1")
+ key3 = Fixtures.pkey("rsa-2")
+ key4 = Fixtures.pkey("p256")
assert_equal(true, key1.compare?(key2))
assert_equal(true, key1.public_key.compare?(key2))
@@ -194,7 +311,14 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
end
def test_to_text
- rsa = Fixtures.pkey("rsa1024")
+ rsa = Fixtures.pkey("rsa-1")
assert_include rsa.to_text, "publicExponent"
end
+
+ def test_legacy_error_classes
+ assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::DSAError)
+ assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::DHError)
+ assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::ECError)
+ assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::RSAError)
+ end
end
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
index cf56032cb3..cd13283a2a 100644
--- a/test/openssl/test_pkey_dh.rb
+++ b/test/openssl/test_pkey_dh.rb
@@ -4,31 +4,42 @@ require_relative 'utils'
if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH)
class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
- NEW_KEYLEN = 2048
-
def test_new_empty
- dh = OpenSSL::PKey::DH.new
- assert_equal nil, dh.p
- assert_equal nil, dh.priv_key
+ # pkeys are immutable with OpenSSL >= 3.0
+ if openssl?(3, 0, 0)
+ assert_raise(ArgumentError) { OpenSSL::PKey::DH.new }
+ else
+ dh = OpenSSL::PKey::DH.new
+ assert_nil(dh.p)
+ assert_nil(dh.priv_key)
+ end
end
def test_new_generate
- # This test is slow
- dh = OpenSSL::PKey::DH.new(NEW_KEYLEN)
- assert_key(dh)
- end if ENV["OSSL_TEST_ALL"]
+ begin
+ dh1 = OpenSSL::PKey::DH.new(512)
+ rescue OpenSSL::PKey::PKeyError
+ omit "generating 512-bit DH parameters failed; " \
+ "likely not supported by this OpenSSL build"
+ end
+ assert_equal(512, dh1.p.num_bits)
+ assert_key(dh1)
+
+ dh2 = OpenSSL::PKey::DH.generate(512)
+ assert_equal(512, dh2.p.num_bits)
+ assert_key(dh2)
+ assert_not_equal(dh1.p, dh2.p)
+ end if ENV["OSSL_TEST_ALL"] == "1"
def test_new_break
unless openssl? && OpenSSL.fips_mode
- assert_nil(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break })
assert_raise(RuntimeError) do
- OpenSSL::PKey::DH.new(NEW_KEYLEN) { raise }
+ OpenSSL::PKey::DH.new(2048) { raise }
end
else
# The block argument is not executed in FIPS case.
# See https://github.com/ruby/openssl/issues/692 for details.
- assert(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break })
- assert(OpenSSL::PKey::DH.new(NEW_KEYLEN) { raise })
+ assert_kind_of(OpenSSL::PKey::DH, OpenSSL::PKey::DH.new(2048) { raise })
end
end
@@ -51,15 +62,15 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
end
def test_DHparams
- dh = Fixtures.pkey("dh2048_ffdhe2048")
- dh_params = dh.public_key
+ dh_params = Fixtures.pkey("dh2048_ffdhe2048")
asn1 = OpenSSL::ASN1::Sequence([
- OpenSSL::ASN1::Integer(dh.p),
- OpenSSL::ASN1::Integer(dh.g)
+ OpenSSL::ASN1::Integer(dh_params.p),
+ OpenSSL::ASN1::Integer(dh_params.g)
])
+ assert_equal(asn1.to_der, dh_params.to_der)
key = OpenSSL::PKey::DH.new(asn1.to_der)
- assert_same_dh dh_params, key
+ assert_same_dh_params(dh_params, key)
pem = <<~EOF
-----BEGIN DH PARAMETERS-----
@@ -71,14 +82,20 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----
EOF
+ assert_equal(pem, dh_params.export)
key = OpenSSL::PKey::DH.new(pem)
- assert_same_dh dh_params, key
+ assert_same_dh_params(dh_params, key)
+ assert_no_key(key)
key = OpenSSL::PKey.read(pem)
- assert_same_dh dh_params, key
-
- assert_equal asn1.to_der, dh.to_der
- assert_equal pem, dh.export
+ assert_same_dh_params(dh_params, key)
+ assert_no_key(key)
+
+ key = OpenSSL::PKey.generate_key(dh_params)
+ assert_same_dh_params(dh_params, key)
+ assert_key(key)
+ assert_equal(dh_params.to_der, key.to_der)
+ assert_equal(dh_params.to_pem, key.to_pem)
end
def test_public_key
@@ -91,18 +108,20 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
def test_generate_key
# Deprecated in v3.0.0; incompatible with OpenSSL 3.0
- # Creates a copy with params only
- dh = Fixtures.pkey("dh2048_ffdhe2048").public_key
+ dh = Fixtures.pkey("dh2048_ffdhe2048")
assert_no_key(dh)
dh.generate_key!
assert_key(dh)
- dh2 = dh.public_key
+ dh2 = OpenSSL::PKey::DH.new(dh.to_der)
dh2.generate_key!
+ assert_not_equal(dh.pub_key, dh2.pub_key)
assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))
end if !openssl?(3, 0, 0)
def test_params_ok?
+ omit_on_fips
+
# Skip the tests in old OpenSSL version 1.1.1c or early versions before
# applying the following commits in OpenSSL 1.1.1d to make `DH_check`
# function pass the RFC 7919 FFDHE group texts.
@@ -121,7 +140,7 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
# AWS-LC automatically does parameter checks on the parsed params.
if aws_lc?
- assert_raise(OpenSSL::PKey::DHError) {
+ assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(dh0.p + 1),
OpenSSL::ASN1::Integer(dh0.g)
@@ -202,14 +221,14 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
end
def assert_key(dh)
- assert(dh.public?)
- assert(dh.private?)
- assert(dh.pub_key)
- assert(dh.priv_key)
+ assert_true(dh.public?)
+ assert_true(dh.private?)
+ assert_kind_of(OpenSSL::BN, dh.pub_key)
+ assert_kind_of(OpenSSL::BN, dh.priv_key)
end
- def assert_same_dh(expected, key)
- check_component(expected, key, [:p, :q, :g, :pub_key, :priv_key])
+ def assert_same_dh_params(expected, key)
+ check_component(expected, key, [:p, :q, :g])
end
end
diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb
index b882476346..1ec0bf0b4d 100644
--- a/test/openssl/test_pkey_dsa.rb
+++ b/test/openssl/test_pkey_dsa.rb
@@ -10,7 +10,7 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
end
def test_private
- key = Fixtures.pkey("dsa1024")
+ key = Fixtures.pkey("dsa2048")
assert_equal true, key.private?
key2 = OpenSSL::PKey::DSA.new(key.to_der)
assert_equal true, key2.private?
@@ -34,9 +34,14 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
end
def test_new_empty
- key = OpenSSL::PKey::DSA.new
- assert_nil(key.p)
- assert_raise(OpenSSL::PKey::PKeyError) { key.to_der }
+ # pkeys are immutable with OpenSSL >= 3.0
+ if openssl?(3, 0, 0)
+ assert_raise(ArgumentError) { OpenSSL::PKey::DSA.new }
+ else
+ key = OpenSSL::PKey::DSA.new
+ assert_nil(key.p)
+ assert_raise(OpenSSL::PKey::PKeyError) { key.to_der }
+ end
end
def test_generate
@@ -47,11 +52,11 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
assert_equal 1024, key1024.p.num_bits
assert_equal 160, key1024.q.num_bits
- key2048 = OpenSSL::PKey::DSA.generate(2048)
- assert_equal 2048, key2048.p.num_bits
- assert_equal 256, key2048.q.num_bits
-
if ENV["OSSL_TEST_ALL"] == "1" # slow
+ key2048 = OpenSSL::PKey::DSA.generate(2048)
+ assert_equal 2048, key2048.p.num_bits
+ assert_equal 256, key2048.q.num_bits
+
key3072 = OpenSSL::PKey::DSA.generate(3072)
assert_equal 3072, key3072.p.num_bits
assert_equal 256, key3072.q.num_bits
@@ -92,7 +97,7 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
sig = key.syssign(digest)
assert_equal true, key.sysverify(digest, sig)
assert_equal false, key.sysverify(digest, invalid_sig)
- assert_sign_verify_false_or_error{ key.sysverify(digest, malformed_sig) }
+ assert_sign_verify_false_or_error { key.sysverify(digest, malformed_sig) }
assert_equal true, key.verify_raw(nil, sig, digest)
assert_equal false, key.verify_raw(nil, invalid_sig, digest)
assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, digest) }
@@ -109,105 +114,76 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
def test_DSAPrivateKey
# OpenSSL DSAPrivateKey format; similar to RSAPrivateKey
- dsa512 = Fixtures.pkey("dsa512")
+ orig = Fixtures.pkey("dsa2048")
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(0),
- OpenSSL::ASN1::Integer(dsa512.p),
- OpenSSL::ASN1::Integer(dsa512.q),
- OpenSSL::ASN1::Integer(dsa512.g),
- OpenSSL::ASN1::Integer(dsa512.pub_key),
- OpenSSL::ASN1::Integer(dsa512.priv_key)
+ OpenSSL::ASN1::Integer(orig.p),
+ OpenSSL::ASN1::Integer(orig.q),
+ OpenSSL::ASN1::Integer(orig.g),
+ OpenSSL::ASN1::Integer(orig.pub_key),
+ OpenSSL::ASN1::Integer(orig.priv_key)
])
key = OpenSSL::PKey::DSA.new(asn1.to_der)
assert_predicate key, :private?
- assert_same_dsa dsa512, key
-
- pem = <<~EOF
- -----BEGIN DSA PRIVATE KEY-----
- MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok
- RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D
- AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR
- S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++
- Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S
- 55jreJD3Se3slps=
- -----END DSA PRIVATE KEY-----
- EOF
+ assert_same_dsa orig, key
+
+ pem = der_to_pem(asn1.to_der, "DSA PRIVATE KEY")
key = OpenSSL::PKey::DSA.new(pem)
- assert_same_dsa dsa512, key
+ assert_same_dsa orig, key
- assert_equal asn1.to_der, dsa512.to_der
- assert_equal pem, dsa512.export
+ assert_equal asn1.to_der, orig.to_der
+ assert_equal pem, orig.export
end
def test_DSAPrivateKey_encrypted
- # key = abcdef
- dsa512 = Fixtures.pkey("dsa512")
- pem = <<~EOF
- -----BEGIN DSA PRIVATE KEY-----
- Proc-Type: 4,ENCRYPTED
- DEK-Info: AES-128-CBC,F8BB7BFC7EAB9118AC2E3DA16C8DB1D9
-
- D2sIzsM9MLXBtlF4RW42u2GB9gX3HQ3prtVIjWPLaKBYoToRUiv8WKsjptfZuLSB
- 74ZPdMS7VITM+W1HIxo/tjS80348Cwc9ou8H/E6WGat8ZUk/igLOUEII+coQS6qw
- QpuLMcCIavevX0gjdjEIkojBB81TYDofA1Bp1z1zDI/2Zhw822xapI79ZF7Rmywt
- OSyWzFaGipgDpdFsGzvT6//z0jMr0AuJVcZ0VJ5lyPGQZAeVBlbYEI4T72cC5Cz7
- XvLiaUtum6/sASD2PQqdDNpgx/WA6Vs1Po2kIUQIM5TIwyJI0GdykZcYm6xIK/ta
- Wgx6c8K+qBAIVrilw3EWxw==
- -----END DSA PRIVATE KEY-----
- EOF
+ # OpenSSL DSAPrivateKey with OpenSSL encryption
+ orig = Fixtures.pkey("dsa2048")
+
+ pem = der_to_encrypted_pem(orig.to_der, "DSA PRIVATE KEY", "abcdef")
key = OpenSSL::PKey::DSA.new(pem, "abcdef")
- assert_same_dsa dsa512, key
+ assert_same_dsa orig, key
key = OpenSSL::PKey::DSA.new(pem) { "abcdef" }
- assert_same_dsa dsa512, key
+ assert_same_dsa orig, key
cipher = OpenSSL::Cipher.new("aes-128-cbc")
- exported = dsa512.to_pem(cipher, "abcdef\0\1")
- assert_same_dsa dsa512, OpenSSL::PKey::DSA.new(exported, "abcdef\0\1")
- assert_raise(OpenSSL::PKey::DSAError) {
+ exported = orig.to_pem(cipher, "abcdef\0\1")
+ assert_same_dsa orig, OpenSSL::PKey::DSA.new(exported, "abcdef\0\1")
+ assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey::DSA.new(exported, "abcdef")
}
end
def test_PUBKEY
- dsa512 = Fixtures.pkey("dsa512")
- dsa512pub = OpenSSL::PKey::DSA.new(dsa512.public_to_der)
+ orig = Fixtures.pkey("dsa2048")
+ pub = OpenSSL::PKey::DSA.new(orig.public_to_der)
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("DSA"),
OpenSSL::ASN1::Sequence([
- OpenSSL::ASN1::Integer(dsa512.p),
- OpenSSL::ASN1::Integer(dsa512.q),
- OpenSSL::ASN1::Integer(dsa512.g)
+ OpenSSL::ASN1::Integer(orig.p),
+ OpenSSL::ASN1::Integer(orig.q),
+ OpenSSL::ASN1::Integer(orig.g)
])
]),
OpenSSL::ASN1::BitString(
- OpenSSL::ASN1::Integer(dsa512.pub_key).to_der
+ OpenSSL::ASN1::Integer(orig.pub_key).to_der
)
])
key = OpenSSL::PKey::DSA.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_dsa dsa512pub, key
-
- pem = <<~EOF
- -----BEGIN PUBLIC KEY-----
- MIHxMIGoBgcqhkjOOAQBMIGcAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgT
- YiEEHaOYhkIxv0OkRZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB
- 4DZGH7UyarcaGy6DAkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqo
- ji3/lHdKoVdTQNuRS/m6DlCwhjRjiQ/lBRgCLCcaA0QAAkEAjN891JBjzpMj4bWg
- sACmMggFf57DS0Ti+5++Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxX
- oXi9OA==
- -----END PUBLIC KEY-----
- EOF
+ assert_same_dsa pub, key
+
+ pem = der_to_pem(asn1.to_der, "PUBLIC KEY")
key = OpenSSL::PKey::DSA.new(pem)
- assert_same_dsa dsa512pub, key
+ assert_same_dsa pub, key
assert_equal asn1.to_der, key.to_der
assert_equal pem, key.export
- assert_equal asn1.to_der, dsa512.public_to_der
+ assert_equal asn1.to_der, orig.public_to_der
assert_equal asn1.to_der, key.public_to_der
- assert_equal pem, dsa512.public_to_pem
+ assert_equal pem, orig.public_to_pem
assert_equal pem, key.public_to_pem
end
@@ -258,7 +234,7 @@ fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ==
end
def test_dup
- key = Fixtures.pkey("dsa1024")
+ key = Fixtures.pkey("dsa2048")
key2 = key.dup
assert_equal key.params, key2.params
@@ -270,7 +246,7 @@ fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ==
end
def test_marshal
- key = Fixtures.pkey("dsa1024")
+ key = Fixtures.pkey("dsa2048")
deserialized = Marshal.load(Marshal.dump(key))
assert_equal key.to_der, deserialized.to_der
diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb
index 1953b4c2da..ec97a747a3 100644
--- a/test/openssl/test_pkey_ec.rb
+++ b/test/openssl/test_pkey_ec.rb
@@ -4,19 +4,9 @@ require_relative 'utils'
if defined?(OpenSSL)
class OpenSSL::TestEC < OpenSSL::PKeyTestCase
- def test_ec_key
+ def test_ec_key_new
key1 = OpenSSL::PKey::EC.generate("prime256v1")
- # PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is
- # deprecated
- if !openssl?(3, 0, 0)
- key2 = OpenSSL::PKey::EC.new
- key2.group = key1.group
- key2.private_key = key1.private_key
- key2.public_key = key1.public_key
- assert_equal key1.to_der, key2.to_der
- end
-
key3 = OpenSSL::PKey::EC.new(key1)
assert_equal key1.to_der, key3.to_der
@@ -35,6 +25,23 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
end
end
+ def test_ec_key_new_empty
+ # pkeys are immutable with OpenSSL >= 3.0; constructing an empty EC object is
+ # disallowed
+ if openssl?(3, 0, 0)
+ assert_raise(ArgumentError) { OpenSSL::PKey::EC.new }
+ else
+ key = OpenSSL::PKey::EC.new
+ assert_nil(key.group)
+
+ p256 = Fixtures.pkey("p256")
+ key.group = p256.group
+ key.private_key = p256.private_key
+ key.public_key = p256.public_key
+ assert_equal(p256.to_der, key.to_der)
+ end
+ end
+
def test_builtin_curves
builtin_curves = OpenSSL::PKey::EC.builtin_curves
assert_not_empty builtin_curves
@@ -47,7 +54,9 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
end
def test_generate
- assert_raise(OpenSSL::PKey::ECError) { OpenSSL::PKey::EC.generate("non-existent") }
+ assert_raise(OpenSSL::PKey::PKeyError) {
+ OpenSSL::PKey::EC.generate("non-existent")
+ }
g = OpenSSL::PKey::EC::Group.new("prime256v1")
ec = OpenSSL::PKey::EC.generate(g)
assert_equal(true, ec.private?)
@@ -58,7 +67,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
def test_generate_key
ec = OpenSSL::PKey::EC.new("prime256v1")
assert_equal false, ec.private?
- assert_raise(OpenSSL::PKey::ECError) { ec.to_der }
+ assert_raise(OpenSSL::PKey::PKeyError) { ec.to_der }
ec.generate_key!
assert_equal true, ec.private?
assert_nothing_raised { ec.to_der }
@@ -72,6 +81,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
end
def test_check_key
+ omit_on_fips
+
key0 = Fixtures.pkey("p256")
assert_equal(true, key0.check_key)
assert_equal(true, key0.private?)
@@ -100,13 +111,13 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.read(ec_key_data) }
else
key4 = OpenSSL::PKey.read(ec_key_data)
- assert_raise(OpenSSL::PKey::ECError) { key4.check_key }
+ assert_raise(OpenSSL::PKey::PKeyError) { key4.check_key }
end
# EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0
if !openssl?(3, 0, 0)
key2.private_key += 1
- assert_raise(OpenSSL::PKey::ECError) { key2.check_key }
+ assert_raise(OpenSSL::PKey::PKeyError) { key2.check_key }
end
end
@@ -260,7 +271,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
cipher = OpenSSL::Cipher.new("aes-128-cbc")
exported = p256.to_pem(cipher, "abcdef\0\1")
assert_same_ec p256, OpenSSL::PKey::EC.new(exported, "abcdef\0\1")
- assert_raise(OpenSSL::PKey::ECError) {
+ assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey::EC.new(exported, "abcdef")
}
end
@@ -334,6 +345,15 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
assert_equal group1.degree, group4.degree
end
+ def test_ec_group_initialize_error_message
+ # Test that passing 2 arguments raises the helpful error
+ e = assert_raise(ArgumentError) do
+ OpenSSL::PKey::EC::Group.new(:GFp, 123)
+ end
+
+ assert_equal("wrong number of arguments (given 2, expected 1 or 4)", e.message)
+ end
+
def test_ec_point
group = OpenSSL::PKey::EC::Group.new("prime256v1")
key = OpenSSL::PKey::EC.generate(group)
@@ -358,18 +378,26 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
point2.to_octet_string(:uncompressed)
assert_equal point2.to_octet_string(:uncompressed),
point3.to_octet_string(:uncompressed)
+ end
+ def test_small_curve
begin
group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2)
group.point_conversion_form = :uncompressed
generator = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 }))
group.set_generator(generator, 19, 1)
- point = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 }))
rescue OpenSSL::PKey::EC::Group::Error
pend "Patched OpenSSL rejected curve" if /unsupported field/ =~ $!.message
raise
end
-
+ assert_equal 17.to_bn.num_bits, group.degree
+ assert_equal B(%w{ 04 05 01 }),
+ group.generator.to_octet_string(:uncompressed)
+ assert_equal 19.to_bn, group.order
+ assert_equal 1.to_bn, group.cofactor
+ assert_nil group.curve_name
+
+ point = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 }))
assert_equal 0x040603.to_bn, point.to_bn
assert_equal 0x040603.to_bn, point.to_bn(:uncompressed)
assert_equal 0x0306.to_bn, point.to_bn(:compressed)
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
index 360309b475..1716aef380 100644
--- a/test/openssl/test_pkey_rsa.rb
+++ b/test/openssl/test_pkey_rsa.rb
@@ -6,40 +6,38 @@ if defined?(OpenSSL)
class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
def test_no_private_exp
key = OpenSSL::PKey::RSA.new
- rsa = Fixtures.pkey("rsa2048")
+ rsa = Fixtures.pkey("rsa-1")
key.set_key(rsa.n, rsa.e, nil)
key.set_factors(rsa.p, rsa.q)
- assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt("foo") }
- assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") }
+ assert_raise(OpenSSL::PKey::PKeyError){ key.private_encrypt("foo") }
+ assert_raise(OpenSSL::PKey::PKeyError){ key.private_decrypt("foo") }
end if !openssl?(3, 0, 0) # Impossible state in OpenSSL 3.0
def test_private
- key = Fixtures.pkey("rsa2048")
+ key = Fixtures.pkey("rsa-1")
# Generated by DER
key2 = OpenSSL::PKey::RSA.new(key.to_der)
- assert(key2.private?)
+ assert_true(key2.private?)
# public key
key3 = key.public_key
- assert(!key3.private?)
+ assert_false(key3.private?)
# Generated by public key DER
key4 = OpenSSL::PKey::RSA.new(key3.to_der)
- assert(!key4.private?)
- rsa1024 = Fixtures.pkey("rsa1024")
+ assert_false(key4.private?)
if !openssl?(3, 0, 0)
- key = OpenSSL::PKey::RSA.new
# Generated by RSA#set_key
key5 = OpenSSL::PKey::RSA.new
- key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
- assert(key5.private?)
+ key5.set_key(key.n, key.e, key.d)
+ assert_true(key5.private?)
# Generated by RSA#set_key, without d
key6 = OpenSSL::PKey::RSA.new
- key6.set_key(rsa1024.n, rsa1024.e, nil)
- assert(!key6.private?)
+ key6.set_key(key.n, key.e, nil)
+ assert_false(key6.private?)
end
end
@@ -61,6 +59,16 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
assert_equal 3, key.e
end
+ def test_new_empty
+ # pkeys are immutable with OpenSSL >= 3.0
+ if openssl?(3, 0, 0)
+ assert_raise(ArgumentError) { OpenSSL::PKey::RSA.new }
+ else
+ key = OpenSSL::PKey::RSA.new
+ assert_nil(key.n)
+ end
+ end
+
def test_s_generate
key1 = OpenSSL::PKey::RSA.generate(2048)
assert_equal 2048, key1.n.num_bits
@@ -108,13 +116,13 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
pssopts = {
"rsa_padding_mode" => "pss",
"rsa_pss_saltlen" => 20,
- "rsa_mgf1_md" => "SHA1"
+ "rsa_mgf1_md" => "SHA256"
}
sig_pss = key.sign("SHA256", data, pssopts)
assert_equal 256, sig_pss.bytesize
assert_equal true, key.verify("SHA256", sig_pss, data, pssopts)
assert_equal true, key.verify_pss("SHA256", sig_pss, data,
- salt_length: 20, mgf1_hash: "SHA1")
+ salt_length: 20, mgf1_hash: "SHA256")
# Defaults to PKCS #1 v1.5 padding => verification failure
assert_equal false, key.verify("SHA256", sig_pss, data)
@@ -172,7 +180,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
# Failure cases
assert_raise(ArgumentError){ key.private_encrypt() }
assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) }
- assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) }
+ assert_raise(OpenSSL::PKey::PKeyError){ key.private_encrypt(plain0, 666) }
end
@@ -181,29 +189,29 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") {
rsa.verify("SHA1", "a", "b")
}
- end
+ end unless openssl?(3, 0, 0) # Empty RSA is not possible with OpenSSL >= 3.0
def test_sign_verify_pss
key = Fixtures.pkey("rsa2048")
data = "Sign me!"
invalid_data = "Sign me?"
- signature = key.sign_pss("SHA256", data, salt_length: 20, mgf1_hash: "SHA1")
+ signature = key.sign_pss("SHA256", data, salt_length: 20, mgf1_hash: "SHA256")
assert_equal 256, signature.bytesize
assert_equal true,
- key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA256")
assert_equal true,
- key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA256")
assert_equal false,
- key.verify_pss("SHA256", signature, invalid_data, salt_length: 20, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, invalid_data, salt_length: 20, mgf1_hash: "SHA256")
- signature = key.sign_pss("SHA256", data, salt_length: :digest, mgf1_hash: "SHA1")
+ signature = key.sign_pss("SHA256", data, salt_length: :digest, mgf1_hash: "SHA256")
assert_equal true,
- key.verify_pss("SHA256", signature, data, salt_length: 32, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: 32, mgf1_hash: "SHA256")
assert_equal true,
- key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA256")
assert_equal false,
- key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA256")
# The sign_pss with `salt_length: :max` raises the "invalid salt length"
# error in FIPS. We need to skip the tests in FIPS.
@@ -213,18 +221,18 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
# FIPS 186-5 section 5.4 PKCS #1
# https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
unless OpenSSL.fips_mode
- signature = key.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA1")
+ signature = key.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256")
# Should verify on the following salt_length (sLen).
# sLen <= emLen (octat) - 2 - hLen (octet) = 2048 / 8 - 2 - 256 / 8 = 222
# https://datatracker.ietf.org/doc/html/rfc8017#section-9.1.1
assert_equal true,
- key.verify_pss("SHA256", signature, data, salt_length: 222, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: 222, mgf1_hash: "SHA256")
assert_equal true,
- key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1")
+ key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA256")
end
- assert_raise(OpenSSL::PKey::RSAError) {
- key.sign_pss("SHA256", data, salt_length: 223, mgf1_hash: "SHA1")
+ assert_raise(OpenSSL::PKey::PKeyError) {
+ key.sign_pss("SHA256", data, salt_length: 223, mgf1_hash: "SHA256")
}
end
@@ -270,57 +278,57 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
end
def test_export
- rsa1024 = Fixtures.pkey("rsa1024")
+ orig = Fixtures.pkey("rsa-1")
- pub = OpenSSL::PKey.read(rsa1024.public_to_der)
- assert_not_equal rsa1024.export, pub.export
- assert_equal rsa1024.public_to_pem, pub.export
+ pub = OpenSSL::PKey.read(orig.public_to_der)
+ assert_not_equal orig.export, pub.export
+ assert_equal orig.public_to_pem, pub.export
# PKey is immutable in OpenSSL >= 3.0
if !openssl?(3, 0, 0)
key = OpenSSL::PKey::RSA.new
# key has only n, e and d
- key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
- assert_equal rsa1024.public_key.export, key.export
+ key.set_key(orig.n, orig.e, orig.d)
+ assert_equal orig.public_key.export, key.export
# key has only n, e, d, p and q
- key.set_factors(rsa1024.p, rsa1024.q)
- assert_equal rsa1024.public_key.export, key.export
+ key.set_factors(orig.p, orig.q)
+ assert_equal orig.public_key.export, key.export
# key has n, e, d, p, q, dmp1, dmq1 and iqmp
- key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
- assert_equal rsa1024.export, key.export
+ key.set_crt_params(orig.dmp1, orig.dmq1, orig.iqmp)
+ assert_equal orig.export, key.export
end
end
def test_to_der
- rsa1024 = Fixtures.pkey("rsa1024")
+ orig = Fixtures.pkey("rsa-1")
- pub = OpenSSL::PKey.read(rsa1024.public_to_der)
- assert_not_equal rsa1024.to_der, pub.to_der
- assert_equal rsa1024.public_to_der, pub.to_der
+ pub = OpenSSL::PKey.read(orig.public_to_der)
+ assert_not_equal orig.to_der, pub.to_der
+ assert_equal orig.public_to_der, pub.to_der
# PKey is immutable in OpenSSL >= 3.0
if !openssl?(3, 0, 0)
key = OpenSSL::PKey::RSA.new
# key has only n, e and d
- key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
- assert_equal rsa1024.public_key.to_der, key.to_der
+ key.set_key(orig.n, orig.e, orig.d)
+ assert_equal orig.public_key.to_der, key.to_der
# key has only n, e, d, p and q
- key.set_factors(rsa1024.p, rsa1024.q)
- assert_equal rsa1024.public_key.to_der, key.to_der
+ key.set_factors(orig.p, orig.q)
+ assert_equal orig.public_key.to_der, key.to_der
# key has n, e, d, p, q, dmp1, dmq1 and iqmp
- key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
- assert_equal rsa1024.to_der, key.to_der
+ key.set_crt_params(orig.dmp1, orig.dmq1, orig.iqmp)
+ assert_equal orig.to_der, key.to_der
end
end
def test_RSAPrivateKey
- rsa = Fixtures.pkey("rsa2048")
+ rsa = Fixtures.pkey("rsa-1")
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(0),
OpenSSL::ASN1::Integer(rsa.n),
@@ -336,35 +344,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
assert_predicate key, :private?
assert_same_rsa rsa, key
- pem = <<~EOF
- -----BEGIN RSA PRIVATE KEY-----
- MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN
- s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign
- 4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D
- kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl
- NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J
- DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb
- I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq
- PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V
- seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0
- Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc
- VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW
- wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G
- 0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj
- XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb
- aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n
- h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw
- Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k
- IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb
- v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId
- U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr
- vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS
- Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC
- 9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41
- gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG
- 4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw==
- -----END RSA PRIVATE KEY-----
- EOF
+ pem = der_to_pem(asn1.to_der, "RSA PRIVATE KEY")
key = OpenSSL::PKey::RSA.new(pem)
assert_same_rsa rsa, key
@@ -379,69 +359,46 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
end
def test_RSAPrivateKey_encrypted
+ # PKCS #1 RSAPrivateKey with OpenSSL encryption
omit_on_fips
- rsa1024 = Fixtures.pkey("rsa1024")
- # key = abcdef
- pem = <<~EOF
- -----BEGIN RSA PRIVATE KEY-----
- Proc-Type: 4,ENCRYPTED
- DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
-
- zgJniZZQfvv8TFx3LzV6zhAQVayvQVZlAYqFq2yWbbxzF7C+IBhKQle9IhUQ9j/y
- /jkvol550LS8vZ7TX5WxyDLe12cdqzEvpR6jf3NbxiNysOCxwG4ErhaZGP+krcoB
- ObuL0nvls/+3myy5reKEyy22+0GvTDjaChfr+FwJjXMG+IBCLscYdgZC1LQL6oAn
- 9xY5DH3W7BW4wR5ttxvtN32TkfVQh8xi3jrLrduUh+hV8DTiAiLIhv0Vykwhep2p
- WZA+7qbrYaYM8GLLgLrb6LfBoxeNxAEKiTpl1quFkm+Hk1dKq0EhVnxHf92x0zVF
- jRGZxAMNcrlCoE4f5XK45epVZSZvihdo1k73GPbp84aZ5P/xlO4OwZ3i4uCQXynl
- jE9c+I+4rRWKyPz9gkkqo0+teJL8ifeKt/3ab6FcdA0aArynqmsKJMktxmNu83We
- YVGEHZPeOlyOQqPvZqWsLnXQUfg54OkbuV4/4mWSIzxFXdFy/AekSeJugpswMXqn
- oNck4qySNyfnlyelppXyWWwDfVus9CVAGZmJQaJExHMT/rQFRVchlmY0Ddr5O264
- gcjv90o1NBOc2fNcqjivuoX7ROqys4K/YdNQ1HhQ7usJghADNOtuLI8ZqMh9akXD
- Eqp6Ne97wq1NiJj0nt3SJlzTnOyTjzrTe0Y+atPkVKp7SsjkATMI9JdhXwGhWd7a
- qFVl0owZiDasgEhyG2K5L6r+yaJLYkPVXZYC/wtWC3NEchnDWZGQcXzB4xROCQkD
- OlWNYDkPiZioeFkA3/fTMvG4moB2Pp9Q4GU5fJ6k43Ccu1up8dX/LumZb4ecg5/x
- -----END RSA PRIVATE KEY-----
- EOF
+ rsa = Fixtures.pkey("rsa2048")
+
+ pem = der_to_encrypted_pem(rsa.to_der, "RSA PRIVATE KEY", "abcdef")
key = OpenSSL::PKey::RSA.new(pem, "abcdef")
- assert_same_rsa rsa1024, key
+ assert_same_rsa rsa, key
key = OpenSSL::PKey::RSA.new(pem) { "abcdef" }
- assert_same_rsa rsa1024, key
+ assert_same_rsa rsa, key
cipher = OpenSSL::Cipher.new("aes-128-cbc")
- exported = rsa1024.to_pem(cipher, "abcdef\0\1")
- assert_same_rsa rsa1024, OpenSSL::PKey::RSA.new(exported, "abcdef\0\1")
- assert_raise(OpenSSL::PKey::RSAError) {
+ exported = rsa.to_pem(cipher, "abcdef\0\1")
+ assert_same_rsa rsa, OpenSSL::PKey::RSA.new(exported, "abcdef\0\1")
+ assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey::RSA.new(exported, "abcdef")
}
end
def test_RSAPublicKey
- rsa1024 = Fixtures.pkey("rsa1024")
- rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der)
+ # PKCS #1 RSAPublicKey. Only decoding is supported
+ orig = Fixtures.pkey("rsa-1")
+ pub = OpenSSL::PKey::RSA.new(orig.public_to_der)
asn1 = OpenSSL::ASN1::Sequence([
- OpenSSL::ASN1::Integer(rsa1024.n),
- OpenSSL::ASN1::Integer(rsa1024.e)
+ OpenSSL::ASN1::Integer(orig.n),
+ OpenSSL::ASN1::Integer(orig.e)
])
key = OpenSSL::PKey::RSA.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_rsa rsa1024pub, key
+ assert_same_rsa pub, key
- pem = <<~EOF
- -----BEGIN RSA PUBLIC KEY-----
- MIGJAoGBAMvCxLDUQKc+1P4+Q6AeFwYDvWfALb+cvzlUEadGoPE6qNWHsLFoo8RF
- geyTgE8KQTduu1OE9Zz2SMcRBDu5/1jWtsLPSVrI2ofLLBARUsWanVyki39DeB4u
- /xkP2mKGjAokPIwOI3oCthSZlzO9bj3voxTf6XngTqUX8l8URTmHAgMBAAE=
- -----END RSA PUBLIC KEY-----
- EOF
+ pem = der_to_pem(asn1.to_der, "RSA PUBLIC KEY")
key = OpenSSL::PKey::RSA.new(pem)
- assert_same_rsa rsa1024pub, key
+ assert_same_rsa pub, key
end
def test_PUBKEY
- rsa1024 = Fixtures.pkey("rsa1024")
- rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der)
+ orig = Fixtures.pkey("rsa-1")
+ pub = OpenSSL::PKey::RSA.new(orig.public_to_der)
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
@@ -450,39 +407,32 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
]),
OpenSSL::ASN1::BitString(
OpenSSL::ASN1::Sequence([
- OpenSSL::ASN1::Integer(rsa1024.n),
- OpenSSL::ASN1::Integer(rsa1024.e)
+ OpenSSL::ASN1::Integer(orig.n),
+ OpenSSL::ASN1::Integer(orig.e)
]).to_der
)
])
key = OpenSSL::PKey::RSA.new(asn1.to_der)
assert_not_predicate key, :private?
- assert_same_rsa rsa1024pub, key
+ assert_same_rsa pub, key
- pem = <<~EOF
- -----BEGIN PUBLIC KEY-----
- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLwsSw1ECnPtT+PkOgHhcGA71n
- wC2/nL85VBGnRqDxOqjVh7CxaKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbC
- z0layNqHyywQEVLFmp1cpIt/Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU
- 3+l54E6lF/JfFEU5hwIDAQAB
- -----END PUBLIC KEY-----
- EOF
+ pem = der_to_pem(asn1.to_der, "PUBLIC KEY")
key = OpenSSL::PKey::RSA.new(pem)
- assert_same_rsa rsa1024pub, key
+ assert_same_rsa pub, key
assert_equal asn1.to_der, key.to_der
assert_equal pem, key.export
- assert_equal asn1.to_der, rsa1024.public_to_der
+ assert_equal asn1.to_der, orig.public_to_der
assert_equal asn1.to_der, key.public_to_der
- assert_equal pem, rsa1024.public_to_pem
+ assert_equal pem, orig.public_to_pem
assert_equal pem, key.public_to_pem
end
def test_pem_passwd
omit_on_fips
- key = Fixtures.pkey("rsa1024")
+ key = Fixtures.pkey("rsa-1")
pem3c = key.to_pem("aes-128-cbc", "key")
assert_match (/ENCRYPTED/), pem3c
assert_equal key.to_der, OpenSSL::PKey.read(pem3c, "key").to_der
@@ -493,90 +443,73 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
end
def test_private_encoding
- rsa1024 = Fixtures.pkey("rsa1024")
+ pkey = Fixtures.pkey("rsa-1")
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(0),
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("rsaEncryption"),
OpenSSL::ASN1::Null(nil)
]),
- OpenSSL::ASN1::OctetString(rsa1024.to_der)
+ OpenSSL::ASN1::OctetString(pkey.to_der)
])
- assert_equal asn1.to_der, rsa1024.private_to_der
- assert_same_rsa rsa1024, OpenSSL::PKey.read(asn1.to_der)
+ assert_equal asn1.to_der, pkey.private_to_der
+ assert_same_rsa pkey, OpenSSL::PKey.read(asn1.to_der)
- pem = <<~EOF
- -----BEGIN PRIVATE KEY-----
- MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMvCxLDUQKc+1P4+
- Q6AeFwYDvWfALb+cvzlUEadGoPE6qNWHsLFoo8RFgeyTgE8KQTduu1OE9Zz2SMcR
- BDu5/1jWtsLPSVrI2ofLLBARUsWanVyki39DeB4u/xkP2mKGjAokPIwOI3oCthSZ
- lzO9bj3voxTf6XngTqUX8l8URTmHAgMBAAECgYEApKX8xBqvJ7XI7Kypfo/x8MVC
- 3rxW+1eQ2aVKIo4a7PKGjQz5RVIVyzqTUvSZoMTbkAxlSIbO5YfJpTnl3tFcOB6y
- QMxqQPW/pl6Ni3EmRJdsRM5MsPBRZOfrXxOCdvXu1TWOS1S1TrvEr/TyL9eh2WCd
- CGzpWgdO4KHce7vs7pECQQDv6DGoG5lHnvbvj9qSJb9K5ebRJc8S+LI7Uy5JHC0j
- zsHTYPSqBXwPVQdGbgCEycnwwKzXzT2QxAQmJBQKun2ZAkEA2W3aeAE7Xi6zo2eG
- 4Cx4UNMHMIdfBRS7VgoekwybGmcapqV0aBew5kHeWAmxP1WUZ/dgZh2QtM1VuiBA
- qUqkHwJBAOJLCRvi/JB8N7z82lTk2i3R8gjyOwNQJv6ilZRMyZ9vFZFHcUE27zCf
- Kb+bX03h8WPwupjMdfgpjShU+7qq8nECQQDBrmyc16QVyo40sgTgblyiysitvviy
- ovwZsZv4q5MCmvOPnPUrwGbRRb2VONUOMOKpFiBl9lIv7HU//nj7FMVLAkBjUXED
- 83dA8JcKM+HlioXEAxCzZVVhN+D63QwRwkN08xAPklfqDkcqccWDaZm2hdCtaYlK
- funwYkrzI1OikQSs
- -----END PRIVATE KEY-----
- EOF
- assert_equal pem, rsa1024.private_to_pem
- assert_same_rsa rsa1024, OpenSSL::PKey.read(pem)
+ pem = der_to_pem(asn1.to_der, "PRIVATE KEY")
+ assert_equal pem, pkey.private_to_pem
+ assert_same_rsa pkey, OpenSSL::PKey.read(pem)
end
def test_private_encoding_encrypted
rsa = Fixtures.pkey("rsa2048")
- encoded = rsa.private_to_der("aes-128-cbc", "abcdef")
+ encoded = rsa.private_to_der("aes-128-cbc", "abcdefgh")
asn1 = OpenSSL::ASN1.decode(encoded) # PKCS #8 EncryptedPrivateKeyInfo
assert_kind_of OpenSSL::ASN1::Sequence, asn1
assert_equal 2, asn1.value.size
assert_not_equal rsa.private_to_der, encoded
- assert_same_rsa rsa, OpenSSL::PKey.read(encoded, "abcdef")
- assert_same_rsa rsa, OpenSSL::PKey.read(encoded) { "abcdef" }
+ assert_same_rsa rsa, OpenSSL::PKey.read(encoded, "abcdefgh")
+ assert_same_rsa rsa, OpenSSL::PKey.read(encoded) { "abcdefgh" }
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.read(encoded, "abcxyz") }
- encoded = rsa.private_to_pem("aes-128-cbc", "abcdef")
+ encoded = rsa.private_to_pem("aes-128-cbc", "abcdefgh")
assert_match (/BEGIN ENCRYPTED PRIVATE KEY/), encoded.lines[0]
- assert_same_rsa rsa, OpenSSL::PKey.read(encoded, "abcdef")
+ assert_same_rsa rsa, OpenSSL::PKey.read(encoded, "abcdefgh")
# Use openssl instead of certtool due to https://gitlab.com/gnutls/gnutls/-/issues/1632
- # openssl pkcs8 -in test/openssl/fixtures/pkey/rsa2048.pem -topk8 -v2 aes-128-cbc -passout pass:abcdef
+ # openssl pkcs8 -in test/openssl/fixtures/pkey/rsa2048.pem -topk8 -v2 aes-128-cbc -passout pass:abcdefgh
pem = <<~EOF
- -----BEGIN ENCRYPTED PRIVATE KEY-----
- MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIay5V8CDQi5oCAggA
- MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBB6eyagcbsvdQlM1kPcH7kiBIIE
- 0Ng1apIyoPAZ4BfC4kMNeSmeAv3XspxqYi3uWzXiNyTcoE6390swrwM6WvdpXvLI
- /n/V06krxPZ9X4fBG2kLUzXt5f09lEvmQU1HW1wJGU5Sq3bNeXBrlJF4DzJE4WWd
- whVVvNMm44ghdzN/jGSw3z+6d717N+waa7vrpBDsHjhsPNwxpyzUvcFPFysTazxx
- kN/dziIBF6SRKi6w8VaJEMQ8czGu5T3jOc2e/1p3/AYhHLPS4NHhLR5OUh0TKqLK
- tANAqI9YqCAjhqcYCmN3mMQXY52VfOqG9hlX1x9ZQyqiH7l102EWbPqouk6bCBLQ
- wHepPg4uK99Wsdh65qEryNnXQ5ZmO6aGb6T3TFENCaNKmi8Nh+/5dr7J7YfhIwpo
- FqHvk0hrZ8r3EQlr8/td0Yb1/IKzeQ34638uXf9UxK7C6o+ilsmJDR4PHJUfZL23
- Yb9qWJ0GEzd5AMsI7x6KuUxSuH9nKniv5Tzyty3Xmb4FwXUyADWE19cVuaT+HrFz
- GraKnA3UXbEgWAU48/l4K2HcAHyHDD2Kbp8k+o1zUkH0fWUdfE6OUGtx19Fv44Jh
- B7xDngK8K48C6nrj06/DSYfXlb2X7WQiapeG4jt6U57tLH2XAjHCkvu0IBZ+//+P
- yIWduEHQ3w8FBRcIsTNJo5CjkGk580TVQB/OBLWfX48Ay3oF9zgnomDIlVjl9D0n
- lKxw/KMCLkvB78rUeGbr1Kwj36FhGpTBw3FgcYGa5oWFZTlcOgMTXLqlbb9JnDlA
- Zs7Tu0WTyOTV/Dne9nEm39Dzu6wRojiIpmygTD4FI7rmOy3CYNvL3XPv7XQj0hny
- Ee/fLxugYlQnwPZSqOVEQY2HsG7AmEHRsvy4bIWIGt+yzAPZixt9MUdJh91ttRt7
- QA/8J1pAsGqEuQpF6UUINZop3J7twfhO4zWYN/NNQ52eWNX2KLfjfGRhrvatzmZ0
- BuCsCI9hwEeE6PTlhbX1Rs177MrDc3vlqz2V3Po0OrFjXAyg9DR/OC4iK5wOG2ZD
- 7StVSP8bzwQXsz3fJ0ardKXgnU2YDAP6Vykjgt+nFI09HV/S2faOc2g/UK4Y2khl
- J93u/GHMz/Kr3bKWGY1/6nPdIdFheQjsiNhd5gI4tWik2B3QwU9mETToZ2LSvDHU
- jYCys576xJLkdMM6nJdq72z4tCoES9IxyHVs4uLjHKIo/ZtKr+8xDo8IL4ax3U8+
- NMhs/lwReHmPGahm1fu9zLRbNCVL7e0zrOqbjvKcSEftObpV/LLcPYXtEm+lZcck
- /PMw49HSE364anKEXCH1cyVWJwdZRpFUHvRpLIrpHru7/cthhiEMdLgK1/x8sLob
- DiyieLxH1DPeXT4X+z94ER4IuPVOcV5AXc/omghispEX6DNUnn5jC4e3WyabjUbw
- MuO9lVH9Wi2/ynExCqVmQkdbTXuLwjni1fJ27Q5zb0aCmhO8eq6P869NCjhJuiUj
- NI9XtGLP50YVWE0kL8KEJqnyFudky8Khzk4/dyixQFqin5GfT4vetrLunGHy7lRB
- 3LpnFrpMOr+0xr1RW1k9vlmjRsJSiojJfReYO7gH3B5swiww2azogoL+4jhF1Jxh
- OYLWdkKhP2jSVGqtIDtny0O4lBm2+hLpWjiI0mJQ7wdA
- -----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQ+Sg92Hgy8EgVPf7t
+Hen1qwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEB5UX2xdDO8/AKA8
++Y5CZyUEggTQkArh4mMPpnAe3xOcDKMz8KCn5lrLb/6Dla7Rp9LHKGkUfyI11EZt
+m+OIriwy9oDQquKyVuLQVGAxXKk+3pyxMqLB0i3hLYamT3vzoPctyVwjuRuKoU3E
+CbF0YhCoxvWMvjHsolwYzx00DbLXouE4BGKvPjnhw5hwtdoZ9Px0ZnCXCxVXi8z/
+mlw7a2ptKEiHQVjuPPbttq+dA+ez7pbWonWVod5TMaPtyEZu5XfPD+0pMboceHZg
+H8ehgUhV3mzEJiisFGg1q9hj+4BaFl5m4tvqp43inCCdShE78CNnOPzJ7WCjKJqi
+jGvHjeMoVx3rZXHcZDAzfIZvDigp9uAfzjRJjpRG8sg5sDQVC7vdUhQDe5TorKT2
+Vb0tdVYxoEpMJ3dhU6Ds5JxMR6GTLjsjTqOkAl6db3HxulwfEpr7YjOpfODR+ttA
+BeIcUcMLsDHayIaQaMLIftHxOkfX7UxoFW9CMG5UMQf/m3eEgVUwgK/E5sUJRUTo
+yhRzJ4NAP4fgc4YH9tbzvUrhfdCXCBEOn6IlDQL66SZr8Mm+Ggu4Ij4TnKWXLrXL
+nSTDDa42kPOvtedKqxC/uXE7rrfh+uyw6J6OjSl6u86TIebndLuDo5DTdWKh8rsg
+fvZZ6332dfMp8JC9/4YnYIJdI7acInSoyHp52OB+2+dgYCr5OrZFjjKS7nELVfo7
+OxGy6uH3NHF9qyUEf3MN17TRHI7jP3zKbXcDTPSyxLQkWe/CU5B251CTmoTSidSW
+EhKnPlGZYbpVQJ4KGEL5UeY8W9PXQo4Dl7TmXBGvuPqNF8kMB3XrPIph7GmihmX0
+nlJqLk9eiRFmUETS0IdAyKJrm4R9Hf6rjYCbXlaApylyVUdSZ2BxgeoTY9BA6Kgf
+3xlgMv01MoUkXMx2+OLIc9MzhButQiDxh3mfS012CjKqUFrJhRSa8DOpUfVgmXpq
+/HP4drWamLWYJR8FsmJS11ZYc1EK/ctJTSpqfewvoUGOSHomhh7zXn1Acb6+9/3p
+bcrJjoR5K8Jg6NlG4dSNkpY/x92I7bFLXFqELIH5tteDrlQen5eASjaiyPPAoOw8
+IGfOmFS4VUPh1VP6g8Jtn5Hr2qXB3DoQoI6EvUZhJ6GJfi67mx5VKux6G9MzJkix
+GU1cL4WzWK2DU0l39UxXjS+4TmOYbrqLVnVMjusX0fwb8LkDC/fVohbhLwhHNwu6
+nSTSEpS9zSDrv1JXFtAtPv6XCSFs6ssPWJMwGSdThn7EfV0GEhG2mCzTyVhwxxQo
+6U/Suqq4oMZoracPUCZx0E4u/bb4KBoFA/eBNPJENTR18IiV+D7wAxlxauO3N1t4
+iJxwrrvSgQPmOGuxrh5LVD41UXYUWLtndzabnpByppFn2MbmvrqJgon0MSs84cTA
+7scnbPu1V3PpKy/t67gtVw9Ue8hLjrskWB1JPFYr7vRWvJzYjfbflyroF+QEJ3TA
+6rTfUC9+ePci6T+i9jF4xcmzqYzRtnGtp5nRUitJGw0uwBTDwzfI2WD6ltvvu7lc
+pHuzvY5zEapuu1JhjHLUd+OE8rVVM999DUXo/IDLsWyRCphCiYfVXJNogd9rB0Ta
+5AhVgpRhxkarBURZyLTYj7NRxCsbHq7XExJNrIdRG/KlBQfyEyIzZ7E=
+-----END ENCRYPTED PRIVATE KEY-----
EOF
- assert_same_rsa rsa, OpenSSL::PKey.read(pem, "abcdef")
+ assert_same_rsa rsa, OpenSSL::PKey.read(pem, "abcdefgh")
end
def test_params
@@ -600,7 +533,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
end
def test_dup
- key = Fixtures.pkey("rsa1024")
+ key = Fixtures.pkey("rsa-1")
key2 = key.dup
assert_equal key.params, key2.params
@@ -612,7 +545,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
end
def test_marshal
- key = Fixtures.pkey("rsa2048")
+ key = Fixtures.pkey("rsa-1")
deserialized = Marshal.load(Marshal.dump(key))
assert_equal key.to_der, deserialized.to_der
diff --git a/test/openssl/test_provider.rb b/test/openssl/test_provider.rb
index 6f85c00c98..10081e208c 100644
--- a/test/openssl/test_provider.rb
+++ b/test/openssl/test_provider.rb
@@ -46,6 +46,7 @@ class OpenSSL::TestProvider < OpenSSL::TestCase
with_openssl(<<-'end;')
begin
+ OpenSSL::Provider.load("default")
OpenSSL::Provider.load("legacy")
rescue OpenSSL::Provider::ProviderError
omit "Only for OpenSSL with legacy provider"
diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb
index f1ce0b5dfc..e4fd581079 100644
--- a/test/openssl/test_ssl.rb
+++ b/test/openssl/test_ssl.rb
@@ -270,6 +270,11 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ssl.syswrite(str)
assert_same buf, ssl.sysread(str.size, buf)
assert_equal(str, buf)
+
+ obj = Object.new
+ obj.define_singleton_method(:to_str) { str }
+ ssl.syswrite(obj)
+ assert_equal(str, ssl.sysread(str.bytesize))
}
}
end
@@ -350,6 +355,22 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
+ def test_sync_close_initialize_opt
+ start_server do |port|
+ begin
+ sock = TCPSocket.new("127.0.0.1", port)
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, sync_close: true)
+ assert_equal true, ssl.sync_close
+ ssl.connect
+ ssl.puts "abc"; assert_equal "abc\n", ssl.gets
+ ssl.close
+ assert_predicate sock, :closed?
+ ensure
+ sock&.close
+ end
+ end
+ end
+
def test_copy_stream
start_server do |port|
server_connect(port) do |ssl|
@@ -680,6 +701,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
def test_post_connect_check_with_anon_ciphers
+ # DH missing the q value on unknown named parameters is not FIPS-approved.
+ omit_on_fips
omit "AWS-LC does not support DHE ciphersuites" if aws_lc?
ctx_proc = -> ctx {
@@ -1057,36 +1080,46 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
- def test_servername_cb_raises_an_exception_on_unknown_objects
- hostname = 'example.org'
-
- ctx2 = OpenSSL::SSL::SSLContext.new
- ctx2.cert = @svr_cert
- ctx2.key = @svr_key
- ctx2.servername_cb = lambda { |args| Object.new }
-
+ def test_servername_cb_exception
sock1, sock2 = socketpair
+ t = Thread.new {
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1)
+ s1.hostname = "localhost"
+ assert_raise_with_message(OpenSSL::SSL::SSLError, /unrecognized.name/i) {
+ s1.connect
+ }
+ }
+
+ ctx2 = OpenSSL::SSL::SSLContext.new
+ ctx2.servername_cb = lambda { |args| raise RuntimeError, "foo" }
s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
+ assert_raise_with_message(RuntimeError, "foo") { s2.accept }
+ assert t.join
+ ensure
+ sock1.close
+ sock2.close
+ t.kill.join
+ end
- ctx1 = OpenSSL::SSL::SSLContext.new
+ def test_servername_cb_raises_an_exception_on_unknown_objects
+ sock1, sock2 = socketpair
- s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)
- s1.hostname = hostname
t = Thread.new {
- assert_raise(OpenSSL::SSL::SSLError) do
- s1.connect
- end
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1)
+ s1.hostname = "localhost"
+ assert_raise(OpenSSL::SSL::SSLError) { s1.connect }
}
- assert_raise(ArgumentError) do
- s2.accept
- end
-
+ ctx2 = OpenSSL::SSL::SSLContext.new
+ ctx2.servername_cb = lambda { |args| Object.new }
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)
+ assert_raise(ArgumentError) { s2.accept }
assert t.join
ensure
- sock1.close if sock1
- sock2.close if sock2
+ sock1.close
+ sock2.close
+ t.kill.join
end
def test_accept_errors_include_peeraddr
@@ -1742,6 +1775,9 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
def test_get_ephemeral_key
+ # kRSA is not FIPS-approved.
+ omit_on_fips
+
# kRSA
ctx_proc1 = proc { |ctx|
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
@@ -1759,33 +1795,28 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
- if !aws_lc? # AWS-LC does not support DHE ciphersuites.
- # DHE
- # TODO: SSL_CTX_set1_groups() is required for testing this with TLS 1.3
- ctx_proc2 = proc { |ctx|
- ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
- ctx.ciphers = "EDH"
- ctx.tmp_dh = Fixtures.pkey("dh-1")
- }
- start_server(ctx_proc: ctx_proc2) do |port|
+ # DHE
+ # OpenSSL 3.0 added support for named FFDHE groups in TLS 1.3
+ # LibreSSL does not support named FFDHE groups currently
+ # AWS-LC does not support DHE ciphersuites
+ if openssl?(3, 0, 0)
+ start_server do |port|
ctx = OpenSSL::SSL::SSLContext.new
- ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
- ctx.ciphers = "EDH"
+ ctx.groups = "ffdhe3072"
server_connect(port, ctx) { |ssl|
assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key
+ assert_equal 3072, ssl.tmp_key.p.num_bits
+ ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
end
end
# ECDHE
ctx_proc3 = proc { |ctx|
- ctx.ciphers = "DEFAULT:!kRSA:!kEDH"
- ctx.ecdh_curves = "P-256"
+ ctx.groups = "P-256"
}
start_server(ctx_proc: ctx_proc3) do |port|
- ctx = OpenSSL::SSL::SSLContext.new
- ctx.ciphers = "DEFAULT:!kRSA:!kEDH"
- server_connect(port, ctx) { |ssl|
+ server_connect(port) { |ssl|
assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key
ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
@@ -1863,6 +1894,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
def test_tmp_dh_callback
+ # DH missing the q value on unknown named parameters is not FIPS-approved.
+ omit_on_fips
omit "AWS-LC does not support DHE ciphersuites" if aws_lc?
dh = Fixtures.pkey("dh-1")
@@ -1876,7 +1909,9 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
}
}
start_server(ctx_proc: ctx_proc) do |port|
- server_connect(port) { |ssl|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.groups = "P-256" # Exclude RFC 7919 groups
+ server_connect(port, ctx) { |ssl|
assert called, "dh callback should be called"
assert_equal dh.to_der, ssl.tmp_key.to_der
}
@@ -1963,6 +1998,157 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
) { ssl_ctx.ciphers = 'BOGUS' }
end
+ def test_sigalgs
+ omit "SSL_CTX_set1_sigalgs_list() not supported" if libressl?
+
+ svr_exts = [
+ ["keyUsage", "keyEncipherment,digitalSignature", true],
+ ["subjectAltName", "DNS:localhost", false],
+ ]
+ ecdsa_key = Fixtures.pkey("p256")
+ ecdsa_cert = issue_cert(@svr, ecdsa_key, 10, svr_exts, @ca_cert, @ca_key)
+
+ ctx_proc = -> ctx {
+ # Unset values set by start_server
+ ctx.cert = ctx.key = ctx.extra_chain_cert = nil
+ ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA
+ ctx.add_certificate(ecdsa_cert, ecdsa_key, [@ca_cert]) # ECDSA
+ }
+ start_server(ctx_proc: ctx_proc) do |port|
+ ctx1 = OpenSSL::SSL::SSLContext.new
+ ctx1.sigalgs = "rsa_pss_rsae_sha256"
+ server_connect(port, ctx1) { |ssl|
+ assert_kind_of(OpenSSL::PKey::RSA, ssl.peer_cert.public_key)
+ ssl.puts("abc"); ssl.gets
+ }
+
+ ctx2 = OpenSSL::SSL::SSLContext.new
+ ctx2.sigalgs = "ed25519:ecdsa_secp256r1_sha256"
+ server_connect(port, ctx2) { |ssl|
+ assert_kind_of(OpenSSL::PKey::EC, ssl.peer_cert.public_key)
+ ssl.puts("abc"); ssl.gets
+ }
+ end
+
+ # Frozen
+ ssl_ctx = OpenSSL::SSL::SSLContext.new
+ ssl_ctx.freeze
+ assert_raise(FrozenError) { ssl_ctx.sigalgs = "ECDSA+SHA256:RSA+SHA256" }
+
+ # Bogus
+ ssl_ctx = OpenSSL::SSL::SSLContext.new
+ assert_raise(TypeError) { ssl_ctx.sigalgs = nil }
+ assert_raise(OpenSSL::SSL::SSLError) { ssl_ctx.sigalgs = "BOGUS" }
+ end
+
+ def test_client_sigalgs
+ omit "SSL_CTX_set1_client_sigalgs_list() not supported" if libressl? || aws_lc?
+
+ cli_exts = [
+ ["keyUsage", "keyEncipherment,digitalSignature", true],
+ ["subjectAltName", "DNS:localhost", false],
+ ]
+ ecdsa_key = Fixtures.pkey("p256")
+ ecdsa_cert = issue_cert(@cli, ecdsa_key, 10, cli_exts, @ca_cert, @ca_key)
+
+ ctx_proc = -> ctx {
+ store = OpenSSL::X509::Store.new
+ store.add_cert(@ca_cert)
+ store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
+ ctx.cert_store = store
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
+ ctx.client_sigalgs = "ECDSA+SHA256"
+ }
+ start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
+ ctx1 = OpenSSL::SSL::SSLContext.new
+ ctx1.add_certificate(@cli_cert, @cli_key) # RSA
+ assert_handshake_error {
+ server_connect(port, ctx1) { |ssl|
+ ssl.puts("abc"); ssl.gets
+ }
+ }
+
+ ctx2 = OpenSSL::SSL::SSLContext.new
+ ctx2.add_certificate(ecdsa_cert, ecdsa_key) # ECDSA
+ server_connect(port, ctx2) { |ssl|
+ ssl.puts("abc"); ssl.gets
+ }
+ end
+ end
+
+ def test_get_sigalg
+ # SSL_get0_signature_name() not supported
+ # SSL_get0_peer_signature_name() not supported
+ return unless openssl?(3, 5, 0)
+
+ server_proc = -> (ctx, ssl) {
+ assert_equal('rsa_pss_rsae_sha256', ssl.sigalg)
+ assert_nil(ssl.peer_sigalg)
+
+ readwrite_loop(ctx, ssl)
+ }
+ start_server(server_proc: server_proc) do |port|
+ cli_ctx = OpenSSL::SSL::SSLContext.new
+ server_connect(port, cli_ctx) do |ssl|
+ assert_nil(ssl.sigalg)
+ assert_equal('rsa_pss_rsae_sha256', ssl.peer_sigalg)
+ ssl.puts "abc"; ssl.gets
+ end
+ end
+ end
+
+ def test_pqc_sigalg
+ # PQC algorithm ML-DSA (FIPS 204) is supported on OpenSSL 3.5 or later.
+ return unless openssl?(3, 5, 0)
+
+ mldsa = Fixtures.pkey("mldsa65-1")
+ mldsa_ca_key = Fixtures.pkey("mldsa65-2")
+ mldsa_ca_cert = issue_cert(@ca, mldsa_ca_key, 1, @ca_exts, nil, nil,
+ digest: nil)
+ mldsa_cert = issue_cert(@svr, mldsa, 60, [], mldsa_ca_cert, mldsa_ca_key,
+ digest: nil)
+ rsa = Fixtures.pkey("rsa-1")
+ rsa_cert = issue_cert(@svr, rsa, 61, [], @ca_cert, @ca_key)
+ ctx_proc = -> ctx {
+ # Unset values set by start_server
+ ctx.cert = ctx.key = ctx.extra_chain_cert = nil
+ ctx.sigalgs = "rsa_pss_rsae_sha256:mldsa65"
+ ctx.add_certificate(mldsa_cert, mldsa)
+ ctx.add_certificate(rsa_cert, rsa)
+ }
+
+ server_proc = -> (ctx, ssl) {
+ assert_equal('mldsa65', ssl.sigalg)
+
+ readwrite_loop(ctx, ssl)
+ }
+ start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ # Set signature algorithm because while OpenSSL may use ML-DSA by
+ # default, the system OpenSSL configuration affects the used signature
+ # algorithm.
+ ctx.sigalgs = 'mldsa65'
+ server_connect(port, ctx) { |ssl|
+ assert_equal('mldsa65', ssl.peer_sigalg)
+ ssl.puts "abc"; ssl.gets
+ }
+ end
+
+ server_proc = -> (ctx, ssl) {
+ assert_equal('rsa_pss_rsae_sha256', ssl.sigalg)
+
+ readwrite_loop(ctx, ssl)
+ }
+ start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.sigalgs = 'rsa_pss_rsae_sha256'
+ server_connect(port, ctx) { |ssl|
+ assert_equal('rsa_pss_rsae_sha256', ssl.peer_sigalg)
+ ssl.puts "abc"; ssl.gets
+ }
+ end
+ end
+
def test_connect_works_when_setting_dh_callback_to_nil
omit "AWS-LC does not support DHE ciphersuites" if aws_lc?
@@ -1972,15 +2158,13 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx.tmp_dh_callback = nil
}
start_server(ctx_proc: ctx_proc) do |port|
- EnvUtil.suppress_warning { # uses default callback
- assert_nothing_raised {
- server_connect(port) { }
- }
- }
+ assert_nothing_raised { server_connect(port) { } }
end
end
def test_tmp_dh
+ # DH missing the q value on unknown named parameters is not FIPS-approved.
+ omit_on_fips
omit "AWS-LC does not support DHE ciphersuites" if aws_lc?
dh = Fixtures.pkey("dh-1")
@@ -1990,64 +2174,100 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ctx.tmp_dh = dh
}
start_server(ctx_proc: ctx_proc) do |port|
- server_connect(port) { |ssl|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.groups = "P-256" # Exclude RFC 7919 groups
+ server_connect(port, ctx) { |ssl|
assert_equal dh.to_der, ssl.tmp_key.to_der
}
end
end
- def test_ecdh_curves_tls12
+ def test_set_groups_tls12
ctx_proc = -> ctx {
# Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3
ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
ctx.ciphers = "kEECDH"
- ctx.ecdh_curves = "P-384:P-521"
+ ctx.groups = "P-384:P-521"
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
# Test 1: Client=P-256:P-384, Server=P-384:P-521 --> P-384
ctx = OpenSSL::SSL::SSLContext.new
- ctx.ecdh_curves = "P-256:P-384"
+ ctx.groups = "P-256:P-384"
server_connect(port, ctx) { |ssl|
cs = ssl.cipher[0]
assert_match (/\AECDH/), cs
+ # SSL_get0_group_name() is supported on OpenSSL 3.2 or later.
+ assert_equal "secp384r1", ssl.group if openssl?(3, 2, 0)
assert_equal "secp384r1", ssl.tmp_key.group.curve_name
ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
# Test 2: Client=P-256, Server=P-521:P-384 --> Fail
ctx = OpenSSL::SSL::SSLContext.new
- ctx.ecdh_curves = "P-256"
+ ctx.groups = "P-256"
assert_raise(OpenSSL::SSL::SSLError) {
server_connect(port, ctx) { }
}
# Test 3: Client=P-521:P-384, Server=P-521:P-384 --> P-521
ctx = OpenSSL::SSL::SSLContext.new
- ctx.ecdh_curves = "P-521:P-384"
+ ctx.groups = "P-521:P-384"
server_connect(port, ctx) { |ssl|
assert_equal "secp521r1", ssl.tmp_key.group.curve_name
ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
+
+ # Test 4: #ecdh_curves= alias
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.ecdh_curves = "P-256:P-384"
+ server_connect(port, ctx) { |ssl|
+ assert_equal "secp384r1", ssl.tmp_key.group.curve_name
+ }
end
end
- def test_ecdh_curves_tls13
+ def test_set_groups_tls13
ctx_proc = -> ctx {
# Assume TLS 1.3 is enabled and chosen by default
- ctx.ecdh_curves = "P-384:P-521"
+ ctx.groups = "P-384:P-521"
}
start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
ctx = OpenSSL::SSL::SSLContext.new
- ctx.ecdh_curves = "P-256:P-384" # disable P-521
+ ctx.groups = "P-256:P-384" # disable P-521
server_connect(port, ctx) { |ssl|
assert_equal "TLSv1.3", ssl.ssl_version
+ # SSL_get0_group_name() is supported on OpenSSL 3.2 or later.
+ assert_equal "secp384r1", ssl.group if openssl?(3, 2, 0)
assert_equal "secp384r1", ssl.tmp_key.group.curve_name
ssl.puts "abc"; assert_equal "abc\n", ssl.gets
}
end
end
+ def test_pqc_group
+ # PQC algorithm ML-KEM (FIPS 203) is supported on OpenSSL 3.5 or later.
+ return unless openssl?(3, 5, 0)
+
+ [
+ 'X25519MLKEM768',
+ 'SecP256r1MLKEM768',
+ 'SecP384r1MLKEM1024'
+ ].each do |group|
+ ctx_proc = -> ctx {
+ ctx.groups = group
+ }
+ start_server(ctx_proc: ctx_proc) do |port|
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.groups = group
+ server_connect(port, ctx) { |ssl|
+ assert_equal(group, ssl.group)
+ ssl.puts "abc"; ssl.gets
+ }
+ end
+ end
+ end
+
def test_security_level
ctx = OpenSSL::SSL::SSLContext.new
ctx.security_level = 1
@@ -2057,22 +2277,30 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
assert_equal(1, ctx.security_level)
- dsa512 = Fixtures.pkey("dsa512")
- dsa512_cert = issue_cert(@svr, dsa512, 50, [], @ca_cert, @ca_key)
- rsa1024 = Fixtures.pkey("rsa1024")
- rsa1024_cert = issue_cert(@svr, rsa1024, 51, [], @ca_cert, @ca_key)
+ # See SSL_CTX_set_security_level(3). Definitions of security levels may
+ # change in future OpenSSL versions. As of OpenSSL 1.1.0:
+ # - Level 1 requires 160-bit ECC keys or 1024-bit RSA keys.
+ # - Level 2 requires 224-bit ECC keys or 2048-bit RSA keys.
+ begin
+ ec112 = OpenSSL::PKey::EC.generate("secp112r1")
+ ec112_cert = issue_cert(@svr, ec112, 50, [], @ca_cert, @ca_key)
+ ec192 = OpenSSL::PKey::EC.generate("prime192v1")
+ ec192_cert = issue_cert(@svr, ec192, 51, [], @ca_cert, @ca_key)
+ rescue OpenSSL::PKey::PKeyError
+ # Distro-provided OpenSSL may refuse to generate small keys
+ return
+ end
assert_raise(OpenSSL::SSL::SSLError) {
- # 512 bit DSA key is rejected because it offers < 80 bits of security
- ctx.add_certificate(dsa512_cert, dsa512)
+ ctx.add_certificate(ec112_cert, ec112)
}
assert_nothing_raised {
- ctx.add_certificate(rsa1024_cert, rsa1024)
+ ctx.add_certificate(ec192_cert, ec192)
}
ctx.security_level = 2
assert_raise(OpenSSL::SSL::SSLError) {
# < 112 bits of security
- ctx.add_certificate(rsa1024_cert, rsa1024)
+ ctx.add_certificate(ec192_cert, ec192)
}
end
@@ -2128,6 +2356,50 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
end
end
+ # OpenSSL::Buffering requires $/ accessible from non-main Ractors (Ruby 4.0)
+ # https://bugs.ruby-lang.org/issues/21109
+ #
+ # Hangs on Windows
+ # https://bugs.ruby-lang.org/issues/21537
+ if respond_to?(:ractor) && RUBY_VERSION >= "4.0" && RUBY_PLATFORM !~ /mswin|mingw/
+ ractor
+ def test_ractor_client
+ start_server { |port|
+ s = Ractor.new(port, @ca_cert) { |port, ca_cert|
+ sock = TCPSocket.new("127.0.0.1", port)
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ ctx.cert_store = OpenSSL::X509::Store.new.tap { |store|
+ store.add_cert(ca_cert)
+ }
+ begin
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
+ ssl.connect
+ ssl.puts("abc")
+ ssl.gets
+ ensure
+ ssl.close
+ sock.close
+ end
+ }.value
+ assert_equal("abc\n", s)
+ }
+ end
+
+ ractor
+ def test_ractor_set_params
+ # We cannot actually test default stores in the test suite as it depends
+ # on the environment, but at least check that it does not raise an
+ # exception
+ ok = Ractor.new {
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.set_params
+ ctx.cert_store.kind_of?(OpenSSL::X509::Store)
+ }.value
+ assert(ok, "ctx.cert_store is an instance of OpenSSL::X509::Store")
+ end
+ end
+
private
def server_connect(port, ctx = nil)
diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb
index f453f58657..37874ca273 100644
--- a/test/openssl/test_ssl_session.rb
+++ b/test/openssl/test_ssl_session.rb
@@ -222,7 +222,7 @@ __EOS__
# Skipping tests that use session_remove_cb by default because it may cause
# deadlock.
- TEST_SESSION_REMOVE_CB = ENV["OSSL_TEST_ALL"] == "1"
+ TEST_SESSION_REMOVE_CB = ENV["OSSL_TEST_UNSAFE"] == "1"
def test_ctx_client_session_cb_tls12
start_server do |port|
diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb
index ac0469ad56..69780a6579 100644
--- a/test/openssl/test_ts.rb
+++ b/test/openssl/test_ts.rb
@@ -4,43 +4,11 @@ if defined?(OpenSSL) && defined?(OpenSSL::Timestamp)
class OpenSSL::TestTimestamp < OpenSSL::TestCase
def intermediate_key
- @intermediate_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_
------BEGIN RSA PRIVATE KEY-----
-MIICWwIBAAKBgQCcyODxH+oTrr7l7MITWcGaYnnBma6vidCCJjuSzZpaRmXZHAyH
-0YcY4ttC0BdJ4uV+cE05IySVC7tyvVfFb8gFQ6XJV+AEktP+XkLbcxZgj9d2NVu1
-ziXdI+ldXkPnMhyWpMS5E7SD6gflv9NhUYEsmAGsUgdK6LDmm2W2/4TlewIDAQAB
-AoGAYgx6KDFWONLqjW3f/Sv/mGYHUNykUyDzpcD1Npyf797gqMMSzwlo3FZa2tC6
-D7n23XirwpTItvEsW9gvgMikJDPlThAeGLZ+L0UbVNNBHVxGP998Nda1kxqKvhRE
-pfZCKc7PLM9ZXc6jBTmgxdcAYfVCCVUoa2mEf9Ktr3BlI4kCQQDQAM09+wHDXGKP
-o2UnCwCazGtyGU2r0QCzHlh9BVY+KD2KjjhuWh86rEbdWN7hEW23Je1vXIhuM6Pa
-/Ccd+XYnAkEAwPZ91PK6idEONeGQ4I3dyMKV2SbaUjfq3MDL4iIQPQPuj7QsBO/5
-3Nf9ReSUUTRFCUVwoC8k4Z1KAJhR/K/ejQJANE7PTnPuGJQGETs09+GTcFpR9uqY
-FspDk8fg1ufdrVnvSAXF+TJewiGK3KU5v33jinhWQngRsyz3Wt2odKhEZwJACbjh
-oicQqvzzgFd7GzVKpWDYd/ZzLY1PsgusuhoJQ2m9TVRAm4cTycLAKhNYPbcqe0sa
-X5fAffWU0u7ZwqeByQJAOUAbYET4RU3iymAvAIDFj8LiQnizG9t5Ty3HXlijKQYv
-y8gsvWd4CdxwOPatWpBUX9L7IXcMJmD44xXTUvpbfQ==
------END RSA PRIVATE KEY-----
-_end_of_pem_
+ @intermediate_key ||= Fixtures.pkey("rsa-1")
end
def ee_key
- @ee_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_
------BEGIN RSA PRIVATE KEY-----
-MIICWwIBAAKBgQDA6eB5r2O5KOKNbKMBhzadl43lgpwqq28m+G0gH38kKCL1f3o9
-P8xUZm7sZqcWEervZMSSXMGBV9DgeoSR+U6FMJywgQGx/JNRx7wZTMNym3PvgLkl
-xCXh6ZA0/xbtJtcNI+UUv0ENBkTIuUWBhkAf3jQclAr9aQ0ktYBuHAcRcQIDAQAB
-AoGAKNhcAuezwZx6e18pFEXAtpVEIfgJgK9TlXi8AjUpAkrNPBWFmDpN1QDrM3p4
-nh+lEpLPW/3vqqchPqYyM4YJraMLpS3KUG+s7+m9QIia0ri2WV5Cig7WL+Tl9p7K
-b3oi2Aj/wti8GfOLFQXOQQ4Ea4GoCv2Sxe0GZR39UBxzTsECQQD1zuVIwBvqU2YR
-8innsoa+j4u2hulRmQO6Zgpzj5vyRYfA9uZxQ9nKbfJvzuWwUv+UzyS9RqxarqrP
-5nQw5EmVAkEAyOmJg6+AfGrgvSWfSpXEds/WA/sHziCO3rE4/sd6cnDc6XcTgeMs
-mT8Z3kAYGpqFDew5orUylPfJJa+PUueJbQJAY+gkvw3+Cp69FLw1lgu0wo07fwOU
-n2qu3jsNMm0DOFRUWfTAMvcd9S385L7WEnWZldUfnKK1+OGXYYrMXPbchQJAChU2
-UoaHQzc16iguM1cK0g+iJPb/MEgQA3sPajHmokGpxIm2T+lvvo0dJjs/Om6QyN8X
-EWRYkoNQ8/Q4lCeMjQJAfvDIGtyqF4PieFHYgluQAv5pGgYpakdc8SYyeRH9NKey
-GaL27FRs4fRWf9OmxPhUVgIyGzLGXrueemvQUDHObA==
------END RSA PRIVATE KEY-----
-_end_of_pem_
+ @ee_key ||= Fixtures.pkey("rsa-2")
end
def ca_cert
@@ -70,15 +38,14 @@ _end_of_pem_
def test_request_mandatory_fields
req = OpenSSL::Timestamp::Request.new
assert_raise(OpenSSL::Timestamp::TimestampError) do
- tmp = req.to_der
- pp OpenSSL::ASN1.decode(tmp)
+ req.to_der
end
req.algorithm = "sha1"
assert_raise(OpenSSL::Timestamp::TimestampError) do
req.to_der
end
req.message_imprint = OpenSSL::Digest.digest('SHA1', "data")
- req.to_der
+ assert_nothing_raised { req.to_der }
end
def test_request_assignment
@@ -89,8 +56,9 @@ _end_of_pem_
assert_raise(TypeError) { req.version = nil }
assert_raise(TypeError) { req.version = "foo" }
- req.algorithm = "SHA1"
+ req.algorithm = "sha1"
assert_equal("SHA1", req.algorithm)
+ assert_equal("SHA1", OpenSSL::ASN1.ObjectId("SHA1").sn)
assert_raise(TypeError) { req.algorithm = nil }
assert_raise(OpenSSL::ASN1::ASN1Error) { req.algorithm = "xxx" }
@@ -371,60 +339,60 @@ _end_of_pem_
end
def test_response_no_policy_defined
- assert_raise(OpenSSL::Timestamp::TimestampError) do
- req = OpenSSL::Timestamp::Request.new
- req.algorithm = "SHA1"
- digest = OpenSSL::Digest.digest('SHA1', "test")
- req.message_imprint = digest
+ req = OpenSSL::Timestamp::Request.new
+ req.algorithm = "SHA1"
+ digest = OpenSSL::Digest.digest('SHA1', "test")
+ req.message_imprint = digest
- fac = OpenSSL::Timestamp::Factory.new
- fac.gen_time = Time.now
- fac.serial_number = 1
- fac.allowed_digests = ["sha1"]
+ fac = OpenSSL::Timestamp::Factory.new
+ fac.gen_time = Time.now
+ fac.serial_number = 1
+ fac.allowed_digests = ["sha1"]
+ assert_raise(OpenSSL::Timestamp::TimestampError) do
fac.create_timestamp(ee_key, ts_cert_ee, req)
end
end
def test_verify_ee_no_req
+ ts, _ = timestamp_ee
assert_raise(TypeError) do
- ts, _ = timestamp_ee
ts.verify(nil, ca_cert)
end
end
def test_verify_ee_no_store
+ ts, req = timestamp_ee
assert_raise(TypeError) do
- ts, req = timestamp_ee
ts.verify(req, nil)
end
end
def test_verify_ee_wrong_root_no_intermediate
+ ts, req = timestamp_ee
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_ee
ts.verify(req, intermediate_store)
end
end
def test_verify_ee_wrong_root_wrong_intermediate
+ ts, req = timestamp_ee
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_ee
ts.verify(req, intermediate_store, [ca_cert])
end
end
def test_verify_ee_nonce_mismatch
+ ts, req = timestamp_ee
+ req.nonce = 1
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_ee
- req.nonce = 1
ts.verify(req, ca_store, [intermediate_cert])
end
end
def test_verify_ee_intermediate_missing
+ ts, req = timestamp_ee
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_ee
ts.verify(req, ca_store)
end
end
@@ -472,27 +440,27 @@ _end_of_pem_
end
def test_verify_direct_wrong_root
+ ts, req = timestamp_direct
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_direct
ts.verify(req, intermediate_store)
end
end
def test_verify_direct_no_cert_no_intermediate
+ ts, req = timestamp_direct_no_cert
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_direct_no_cert
ts.verify(req, ca_store)
end
end
def test_verify_ee_no_cert
ts, req = timestamp_ee_no_cert
- ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert])
+ assert_same(ts, ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]))
end
def test_verify_ee_no_cert_no_intermediate
+ ts, req = timestamp_ee_no_cert
assert_raise(OpenSSL::Timestamp::TimestampError) do
- ts, req = timestamp_ee_no_cert
ts.verify(req, ca_store, [ts_cert_ee])
end
end
diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb
index 5fc87d9c67..9e0aa4edf6 100644
--- a/test/openssl/test_x509cert.rb
+++ b/test/openssl/test_x509cert.rb
@@ -6,17 +6,16 @@ if defined?(OpenSSL)
class OpenSSL::TestX509Certificate < OpenSSL::TestCase
def setup
super
- @rsa1024 = Fixtures.pkey("rsa1024")
- @rsa2048 = Fixtures.pkey("rsa2048")
- @dsa256 = Fixtures.pkey("dsa256")
- @dsa512 = Fixtures.pkey("dsa512")
+ @rsa1 = Fixtures.pkey("rsa-1")
+ @rsa2 = Fixtures.pkey("rsa-2")
+ @ec1 = Fixtures.pkey("p256")
@ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
@ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1")
end
def test_serial
[1, 2**32, 2**100].each{|s|
- cert = issue_cert(@ca, @rsa2048, s, [], nil, nil)
+ cert = issue_cert(@ca, @rsa1, s, [], nil, nil)
assert_equal(s, cert.serial)
cert = OpenSSL::X509::Certificate.new(cert.to_der)
assert_equal(s, cert.serial)
@@ -29,40 +28,34 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
["subjectKeyIdentifier","hash",false],
["authorityKeyIdentifier","keyid:always",false],
]
-
- [
- @rsa1024, @rsa2048, @dsa256, @dsa512,
- ].each{|pk|
- cert = issue_cert(@ca, pk, 1, exts, nil, nil)
- assert_equal(cert.extensions.sort_by(&:to_s)[2].value,
- OpenSSL::TestUtils.get_subject_key_id(cert))
- cert = OpenSSL::X509::Certificate.new(cert.to_der)
- assert_equal(cert.extensions.sort_by(&:to_s)[2].value,
- OpenSSL::TestUtils.get_subject_key_id(cert))
- }
+ cert = issue_cert(@ca, @rsa1, 1, exts, nil, nil)
+ assert_kind_of(OpenSSL::PKey::RSA, cert.public_key)
+ assert_equal(@rsa1.public_to_der, cert.public_key.public_to_der)
+ cert = OpenSSL::X509::Certificate.new(cert.to_der)
+ assert_equal(@rsa1.public_to_der, cert.public_key.public_to_der)
end
def test_validity
now = Time.at(Time.now.to_i + 0.9)
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil,
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,
not_before: now, not_after: now+3600)
assert_equal(Time.at(now.to_i), cert.not_before)
assert_equal(Time.at(now.to_i+3600), cert.not_after)
now = Time.at(now.to_i)
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil,
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,
not_before: now, not_after: now+3600)
assert_equal(now.getutc, cert.not_before)
assert_equal((now+3600).getutc, cert.not_after)
now = Time.at(0)
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil,
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,
not_before: now, not_after: now)
assert_equal(now.getutc, cert.not_before)
assert_equal(now.getutc, cert.not_after)
now = Time.at(0x7fffffff)
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil,
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,
not_before: now, not_after: now)
assert_equal(now.getutc, cert.not_before)
assert_equal(now.getutc, cert.not_after)
@@ -75,7 +68,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
["subjectKeyIdentifier","hash",false],
["authorityKeyIdentifier","issuer:always,keyid:always",false],
]
- ca_cert = issue_cert(@ca, @rsa2048, 1, ca_exts, nil, nil)
+ ca_cert = issue_cert(@ca, @rsa1, 1, ca_exts, nil, nil)
ca_cert.extensions.each_with_index{|ext, i|
assert_equal(ca_exts[i].first, ext.oid)
assert_equal(ca_exts[i].last, ext.critical?)
@@ -88,7 +81,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false],
["subjectAltName","email:ee1@ruby-lang.org",false],
]
- ee1_cert = issue_cert(@ee1, @rsa1024, 2, ee1_exts, ca_cert, @rsa2048)
+ ee1_cert = issue_cert(@ee1, @rsa2, 2, ee1_exts, ca_cert, @rsa1)
assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der)
ee1_cert.extensions.each_with_index{|ext, i|
assert_equal(ee1_exts[i].first, ext.oid)
@@ -97,25 +90,25 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
end
def test_akiski
- ca_cert = generate_cert(@ca, @rsa2048, 4, nil)
+ ca_cert = generate_cert(@ca, @rsa1, 4, nil)
ef = OpenSSL::X509::ExtensionFactory.new(ca_cert, ca_cert)
ca_cert.add_extension(
ef.create_extension("subjectKeyIdentifier", "hash", false))
ca_cert.add_extension(
ef.create_extension("authorityKeyIdentifier", "issuer:always,keyid:always", false))
- ca_cert.sign(@rsa2048, "sha256")
+ ca_cert.sign(@rsa1, "sha256")
ca_keyid = get_subject_key_id(ca_cert.to_der, hex: false)
assert_equal ca_keyid, ca_cert.authority_key_identifier
assert_equal ca_keyid, ca_cert.subject_key_identifier
- ee_cert = generate_cert(@ee1, Fixtures.pkey("p256"), 5, ca_cert)
+ ee_cert = generate_cert(@ee1, @rsa2, 5, ca_cert)
ef = OpenSSL::X509::ExtensionFactory.new(ca_cert, ee_cert)
ee_cert.add_extension(
ef.create_extension("subjectKeyIdentifier", "hash", false))
ee_cert.add_extension(
ef.create_extension("authorityKeyIdentifier", "issuer:always,keyid:always", false))
- ee_cert.sign(@rsa2048, "sha256")
+ ee_cert.sign(@rsa1, "sha256")
ee_keyid = get_subject_key_id(ee_cert.to_der, hex: false)
assert_equal ca_keyid, ee_cert.authority_key_identifier
@@ -123,13 +116,13 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
end
def test_akiski_missing
- cert = issue_cert(@ee1, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ee1, @rsa1, 1, [], nil, nil)
assert_nil(cert.authority_key_identifier)
assert_nil(cert.subject_key_identifier)
end
def test_crl_uris_no_crl_distribution_points
- cert = issue_cert(@ee1, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ee1, @rsa1, 1, [], nil, nil)
assert_nil(cert.crl_uris)
end
@@ -141,10 +134,10 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
URI.1 = http://www.example.com/crl
URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary
_cnf_
- cdp_cert = generate_cert(@ee1, @rsa2048, 3, nil)
+ cdp_cert = generate_cert(@ee1, @rsa1, 3, nil)
ef.subject_certificate = cdp_cert
cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "@crlDistPts"))
- cdp_cert.sign(@rsa2048, "sha256")
+ cdp_cert.sign(@rsa1, "sha256")
assert_equal(
["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"],
cdp_cert.crl_uris
@@ -158,10 +151,10 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
[crlDistPts_section]
fullname = URI:http://www.example.com/crl, URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary
_cnf_
- cdp_cert = generate_cert(@ee1, @rsa2048, 3, nil)
+ cdp_cert = generate_cert(@ee1, @rsa1, 3, nil)
ef.subject_certificate = cdp_cert
cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "crlDistPts_section"))
- cdp_cert.sign(@rsa2048, "sha256")
+ cdp_cert.sign(@rsa1, "sha256")
assert_equal(
["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"],
cdp_cert.crl_uris
@@ -177,22 +170,22 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
[dirname_section]
CN = dirname
_cnf_
- cdp_cert = generate_cert(@ee1, @rsa2048, 3, nil)
+ cdp_cert = generate_cert(@ee1, @rsa1, 3, nil)
ef.subject_certificate = cdp_cert
cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "crlDistPts_section"))
- cdp_cert.sign(@rsa2048, "sha256")
+ cdp_cert.sign(@rsa1, "sha256")
assert_nil(cdp_cert.crl_uris)
end
def test_aia_missing
- cert = issue_cert(@ee1, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ee1, @rsa1, 1, [], nil, nil)
assert_nil(cert.ca_issuer_uris)
assert_nil(cert.ocsp_uris)
end
def test_aia
ef = OpenSSL::X509::ExtensionFactory.new
- aia_cert = generate_cert(@ee1, @rsa2048, 4, nil)
+ aia_cert = generate_cert(@ee1, @rsa1, 4, nil)
ef.subject_certificate = aia_cert
aia_cert.add_extension(
ef.create_extension(
@@ -204,7 +197,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
false
)
)
- aia_cert.sign(@rsa2048, "sha256")
+ aia_cert.sign(@rsa1, "sha256")
assert_equal(
["http://www.example.com/caIssuers", "ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary"],
aia_cert.ca_issuer_uris
@@ -217,7 +210,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
def test_invalid_extension
integer = OpenSSL::ASN1::Integer.new(0)
- invalid_exts_cert = generate_cert(@ee1, @rsa1024, 1, nil)
+ invalid_exts_cert = generate_cert(@ee1, @rsa1, 1, nil)
["subjectKeyIdentifier", "authorityKeyIdentifier", "crlDistributionPoints", "authorityInfoAccess"].each do |ext|
invalid_exts_cert.add_extension(
OpenSSL::X509::Extension.new(ext, integer.to_der)
@@ -241,57 +234,17 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
}
end
- def test_sign_and_verify_rsa_sha1
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "SHA1")
- assert_equal(false, cert.verify(@rsa1024))
- assert_equal(true, cert.verify(@rsa2048))
- assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) })
- assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) })
+ def test_sign_and_verify
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil, digest: "SHA256")
+ assert_equal("sha256WithRSAEncryption", cert.signature_algorithm) # ln
+ assert_equal(true, cert.verify(@rsa1))
+ assert_equal(false, cert.verify(@rsa2))
+ assert_equal(false, certificate_error_returns_false { cert.verify(@ec1) })
cert.serial = 2
- assert_equal(false, cert.verify(@rsa2048))
- rescue OpenSSL::X509::CertificateError # RHEL 9 disables SHA1
- end
-
- def test_sign_and_verify_rsa_md5
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "md5")
- assert_equal(false, cert.verify(@rsa1024))
- assert_equal(true, cert.verify(@rsa2048))
-
- assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) })
- assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) })
- cert.subject = @ee1
- assert_equal(false, cert.verify(@rsa2048))
- rescue OpenSSL::X509::CertificateError # RHEL7 disables MD5
- end
-
- def test_sign_and_verify_dsa
- cert = issue_cert(@ca, @dsa512, 1, [], nil, nil)
- assert_equal(false, certificate_error_returns_false { cert.verify(@rsa1024) })
- assert_equal(false, certificate_error_returns_false { cert.verify(@rsa2048) })
- assert_equal(false, cert.verify(@dsa256))
- assert_equal(true, cert.verify(@dsa512))
- cert.not_after = Time.now
- assert_equal(false, cert.verify(@dsa512))
+ assert_equal(false, cert.verify(@rsa1))
end
- def test_sign_and_verify_rsa_dss1
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: OpenSSL::Digest.new('DSS1'))
- assert_equal(false, cert.verify(@rsa1024))
- assert_equal(true, cert.verify(@rsa2048))
- assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) })
- assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) })
- cert.subject = @ee1
- assert_equal(false, cert.verify(@rsa2048))
- rescue OpenSSL::X509::CertificateError
- end if defined?(OpenSSL::Digest::DSS1)
-
- def test_sign_and_verify_dsa_md5
- assert_raise(OpenSSL::X509::CertificateError){
- issue_cert(@ca, @dsa512, 1, [], nil, nil, digest: "md5")
- }
- end
-
- def test_sign_and_verify_ed25519
+ def test_sign_and_verify_nil_digest
# Ed25519 is not FIPS-approved.
omit_on_fips
ed25519 = OpenSSL::PKey::generate_key("ED25519")
@@ -299,24 +252,13 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
assert_equal(true, cert.verify(ed25519))
end
- def test_dsa_with_sha2
- cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256")
- assert_equal("dsa_with_SHA256", cert.signature_algorithm)
- # TODO: need more tests for dsa + sha2
-
- # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1)
- cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1")
- assert_equal("dsaWithSHA1", cert.signature_algorithm)
- rescue OpenSSL::X509::CertificateError # RHEL 9 disables SHA1
- end
-
def test_check_private_key
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
- assert_equal(true, cert.check_private_key(@rsa2048))
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ assert_equal(true, cert.check_private_key(@rsa1))
end
def test_read_from_file
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
Tempfile.create("cert") { |f|
f << cert.to_pem
f.rewind
@@ -325,12 +267,12 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
end
def test_read_der_then_pem
- cert1 = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+ cert1 = issue_cert(@ca, @rsa1, 1, [], nil, nil)
exts = [
# A new line before PEM block
["nsComment", "Another certificate:\n" + cert1.to_pem],
]
- cert2 = issue_cert(@ca, @rsa2048, 2, exts, nil, nil)
+ cert2 = issue_cert(@ca, @rsa1, 2, exts, nil, nil)
assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_der)
assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_pem)
@@ -338,15 +280,15 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
def test_eq
now = Time.now
- cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil,
+ cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil,
not_before: now, not_after: now + 3600)
- cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
+ cert1 = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,
not_before: now, not_after: now + 3600)
- cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
+ cert2 = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,
not_before: now, not_after: now + 3600)
- cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024,
+ cert3 = issue_cert(@ee1, @rsa2, 3, [], cacert, @rsa1,
not_before: now, not_after: now + 3600)
- cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
+ cert4 = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,
digest: "sha512", not_before: now, not_after: now + 3600)
assert_equal false, cert1 == 12345
@@ -356,11 +298,19 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
assert_equal false, cert3 == cert4
end
+ def test_inspect
+ cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ assert_include(cacert.inspect, "subject=#{@ca.inspect}")
+
+ # Do not raise an exception for an invalid certificate
+ assert_instance_of(String, OpenSSL::X509::Certificate.new.inspect)
+ end
+
def test_marshal
now = Time.now
- cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil,
+ cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil,
not_before: now, not_after: now + 3600)
- cert = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024,
+ cert = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,
not_before: now, not_after: now + 3600)
deserialized = Marshal.load(Marshal.dump(cert))
@@ -378,8 +328,8 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
end
def test_load_file_fullchain_pem
- cert1 = issue_cert(@ee1, @rsa2048, 1, [], nil, nil)
- cert2 = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+ cert1 = issue_cert(@ee1, @rsa1, 1, [], nil, nil)
+ cert2 = issue_cert(@ca, @rsa2, 1, [], nil, nil)
Tempfile.create("fullchain.pem") do |f|
f.puts cert1.to_pem
@@ -394,7 +344,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
end
def test_load_file_certificate_der
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
Tempfile.create("certificate.der", binmode: true) do |f|
f.write cert.to_der
f.close
@@ -419,7 +369,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase
end
def test_tbs_precert_bytes
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
seq = OpenSSL::ASN1.decode(cert.tbs_bytes)
assert_equal 7, seq.value.size
diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb
index 89165388db..81c9247df2 100644
--- a/test/openssl/test_x509crl.rb
+++ b/test/openssl/test_x509crl.rb
@@ -6,25 +6,21 @@ if defined?(OpenSSL)
class OpenSSL::TestX509CRL < OpenSSL::TestCase
def setup
super
- @rsa1024 = Fixtures.pkey("rsa1024")
- @rsa2048 = Fixtures.pkey("rsa2048")
- @dsa256 = Fixtures.pkey("dsa256")
- @dsa512 = Fixtures.pkey("dsa512")
+ @rsa1 = Fixtures.pkey("rsa-1")
+ @rsa2 = Fixtures.pkey("rsa-2")
@ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
- @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1")
- @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2")
end
def test_basic
now = Time.at(Time.now.to_i)
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
- crl = issue_crl([], 1, now, now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ crl = issue_crl([], 1, now, now+1600, [], cert, @rsa1, "SHA256")
assert_equal(1, crl.version)
assert_equal(cert.issuer.to_der, crl.issuer.to_der)
assert_equal(now, crl.last_update)
assert_equal(now+1600, crl.next_update)
+ assert_equal("sha256WithRSAEncryption", crl.signature_algorithm) # ln
crl = OpenSSL::X509::CRL.new(crl.to_der)
assert_equal(1, crl.version)
@@ -55,9 +51,9 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
[4, now, 4],
[5, now, 5],
]
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert, @rsa1, "SHA256")
revoked = crl.revoked
assert_equal(5, revoked.size)
assert_equal(1, revoked[0].serial)
@@ -98,7 +94,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
revoke_info = (1..1000).collect{|i| [i, now, 0] }
crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert, @rsa1, "SHA256")
revoked = crl.revoked
assert_equal(1000, revoked.size)
assert_equal(1, revoked[0].serial)
@@ -122,9 +118,9 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
["issuerAltName", "issuer:copy", false],
]
- cert = issue_cert(@ca, @rsa2048, 1, cert_exts, nil, nil)
+ cert = issue_cert(@ca, @rsa1, 1, cert_exts, nil, nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts,
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert, @rsa1, "SHA256")
exts = crl.extensions
assert_equal(3, exts.size)
assert_equal("1", exts[0].value)
@@ -160,59 +156,55 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
assert_equal(false, exts[2].critical?)
no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert, @rsa1, "SHA256")
assert_equal nil, no_ext_crl.authority_key_identifier
end
def test_crlnumber
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
- crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @rsa1, "SHA256")
assert_match(1.to_s, crl.extensions[0].value)
assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text)
crl = issue_crl([], 2**32, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert, @rsa1, "SHA256")
assert_match((2**32).to_s, crl.extensions[0].value)
assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text)
crl = issue_crl([], 2**100, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
+ cert, @rsa1, "SHA256")
assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text)
assert_match((2**100).to_s, crl.extensions[0].value)
end
def test_sign_and_verify
- cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
- crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @rsa2048, OpenSSL::Digest.new('SHA256'))
- assert_equal(false, crl.verify(@rsa1024))
- assert_equal(true, crl.verify(@rsa2048))
- assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) })
- assert_equal(false, crl_error_returns_false { crl.verify(@dsa512) })
+ p256 = Fixtures.pkey("p256")
+
+ cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @rsa1, "SHA256")
+ assert_equal(true, crl.verify(@rsa1))
+ assert_equal(false, crl.verify(@rsa2))
+ assert_equal(false, crl_error_returns_false { crl.verify(p256) })
crl.version = 0
- assert_equal(false, crl.verify(@rsa2048))
+ assert_equal(false, crl.verify(@rsa1))
- cert = issue_cert(@ca, @dsa512, 1, [], nil, nil)
- crl = issue_crl([], 1, Time.now, Time.now+1600, [],
- cert, @dsa512, OpenSSL::Digest.new('SHA256'))
- assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) })
- assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) })
- assert_equal(false, crl.verify(@dsa256))
- assert_equal(true, crl.verify(@dsa512))
+ cert = issue_cert(@ca, p256, 1, [], nil, nil)
+ crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, p256, "SHA256")
+ assert_equal(false, crl_error_returns_false { crl.verify(@rsa1) })
+ assert_equal(false, crl_error_returns_false { crl.verify(@rsa2) })
+ assert_equal(true, crl.verify(p256))
crl.version = 0
- assert_equal(false, crl.verify(@dsa512))
+ assert_equal(false, crl.verify(p256))
end
- def test_sign_and_verify_ed25519
+ def test_sign_and_verify_nil_digest
# Ed25519 is not FIPS-approved.
omit_on_fips
ed25519 = OpenSSL::PKey::generate_key("ED25519")
cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil)
crl = issue_crl([], 1, Time.now, Time.now+1600, [],
cert, ed25519, nil)
- assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) })
- assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) })
+ assert_equal(false, crl_error_returns_false { crl.verify(@rsa1) })
assert_equal(false, crl.verify(OpenSSL::PKey::generate_key("ED25519")))
assert_equal(true, crl.verify(ed25519))
crl.version = 0
@@ -245,8 +237,8 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
def test_eq
now = Time.now
- cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
- crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256")
+ cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1, "SHA256")
rev1 = OpenSSL::X509::Revoked.new.tap { |rev|
rev.serial = 1
rev.time = now
@@ -274,8 +266,8 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase
def test_marshal
now = Time.now
- cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
- crl = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256")
+ cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil)
+ crl = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1, "SHA256")
rev = OpenSSL::X509::Revoked.new.tap { |rev|
rev.serial = 1
rev.time = now
diff --git a/test/openssl/test_x509name.rb b/test/openssl/test_x509name.rb
index c6d15219f5..223c575e4e 100644
--- a/test/openssl/test_x509name.rb
+++ b/test/openssl/test_x509name.rb
@@ -423,24 +423,14 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase
assert_equal(nil, n3 <=> nil)
end
- def name_hash(name)
- # OpenSSL 1.0.0 uses SHA1 for canonical encoding (not just a der) of
- # X509Name for X509_NAME_hash.
- name.respond_to?(:hash_old) ? name.hash_old : name.hash
- end
+ def test_hash_old
+ omit_on_fips # MD5
- def test_hash
dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org"
name = OpenSSL::X509::Name.parse(dn)
d = OpenSSL::Digest.digest('MD5', name.to_der)
expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24
- assert_equal(expected, name_hash(name))
- #
- dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org"
- name = OpenSSL::X509::Name.parse(dn)
- d = OpenSSL::Digest.digest('MD5', name.to_der)
- expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24
- assert_equal(expected, name_hash(name))
+ assert_equal(expected, name.hash_old)
end
def test_equality
diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb
index 18d3e7f8f3..b198a1185a 100644
--- a/test/openssl/test_x509req.rb
+++ b/test/openssl/test_x509req.rb
@@ -6,10 +6,8 @@ if defined?(OpenSSL)
class OpenSSL::TestX509Request < OpenSSL::TestCase
def setup
super
- @rsa1024 = Fixtures.pkey("rsa1024")
- @rsa2048 = Fixtures.pkey("rsa2048")
- @dsa256 = Fixtures.pkey("dsa256")
- @dsa512 = Fixtures.pkey("dsa512")
+ @rsa1 = Fixtures.pkey("rsa-1")
+ @rsa2 = Fixtures.pkey("rsa-2")
@dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou")
end
@@ -23,31 +21,32 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
end
def test_public_key
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
- assert_equal(@rsa1024.public_to_der, req.public_key.public_to_der)
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
+ assert_kind_of(OpenSSL::PKey::RSA, req.public_key)
+ assert_equal(@rsa1.public_to_der, req.public_key.public_to_der)
req = OpenSSL::X509::Request.new(req.to_der)
- assert_equal(@rsa1024.public_to_der, req.public_key.public_to_der)
-
- req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256'))
- assert_equal(@dsa512.public_to_der, req.public_key.public_to_der)
- req = OpenSSL::X509::Request.new(req.to_der)
- assert_equal(@dsa512.public_to_der, req.public_key.public_to_der)
+ assert_equal(@rsa1.public_to_der, req.public_key.public_to_der)
end
def test_version
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
assert_equal(0, req.version)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(0, req.version)
end
def test_subject
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
assert_equal(@dn.to_der, req.subject.to_der)
req = OpenSSL::X509::Request.new(req.to_der)
assert_equal(@dn.to_der, req.subject.to_der)
end
+ def test_signature_algorithm
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
+ assert_equal("sha256WithRSAEncryption", req.signature_algorithm) # ln
+ end
+
def create_ext_req(exts)
ef = OpenSSL::X509::ExtensionFactory.new
exts = exts.collect{|e| ef.create_extension(*e) }
@@ -73,9 +72,9 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
OpenSSL::X509::Attribute.new("msExtReq", attrval),
]
- req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
+ req0 = issue_csr(0, @dn, @rsa1, "SHA256")
attrs.each{|attr| req0.add_attribute(attr) }
- req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
+ req1 = issue_csr(0, @dn, @rsa1, "SHA256")
req1.attributes = attrs
assert_equal(req0.to_der, req1.to_der)
@@ -95,65 +94,44 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
assert_equal(exts, get_ext_req(attrs[1].value))
end
- def test_sign_and_verify_rsa_sha1
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
- assert_equal(true, req.verify(@rsa1024))
- assert_equal(false, req.verify(@rsa2048))
- assert_equal(false, request_error_returns_false { req.verify(@dsa256) })
- assert_equal(false, request_error_returns_false { req.verify(@dsa512) })
- req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBarFooBar")
- assert_equal(false, req.verify(@rsa1024))
- rescue OpenSSL::X509::RequestError # RHEL 9 disables SHA1
- end
-
- def test_sign_and_verify_rsa_md5
- req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest.new('MD5'))
- assert_equal(false, req.verify(@rsa1024))
- assert_equal(true, req.verify(@rsa2048))
- assert_equal(false, request_error_returns_false { req.verify(@dsa256) })
- assert_equal(false, request_error_returns_false { req.verify(@dsa512) })
- req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar")
- assert_equal(false, req.verify(@rsa2048))
- rescue OpenSSL::X509::RequestError # RHEL7 disables MD5
- end
-
- def test_sign_and_verify_dsa
- req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256'))
- assert_equal(false, request_error_returns_false { req.verify(@rsa1024) })
- assert_equal(false, request_error_returns_false { req.verify(@rsa2048) })
- assert_equal(false, req.verify(@dsa256))
- assert_equal(true, req.verify(@dsa512))
- req.public_key = @rsa1024.public_key
- assert_equal(false, req.verify(@dsa512))
+ def test_sign_digest_instance
+ req1 = issue_csr(0, @dn, @rsa1, "SHA256")
+ req2 = issue_csr(0, @dn, @rsa1, OpenSSL::Digest.new("SHA256"))
+ assert_equal(req1.to_der, req2.to_der)
end
- def test_sign_and_verify_dsa_md5
- assert_raise(OpenSSL::X509::RequestError){
- issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('MD5')) }
+ def test_sign_and_verify
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
+ assert_equal(true, req.verify(@rsa1))
+ assert_equal(false, req.verify(@rsa2))
+ ec = OpenSSL::PKey::EC.generate("prime256v1")
+ assert_equal(false, request_error_returns_false { req.verify(ec) })
+ req.subject = OpenSSL::X509::Name.parse_rfc2253("CN=FooBarFooBar,C=JP")
+ assert_equal(false, req.verify(@rsa1))
end
- def test_sign_and_verify_ed25519
+ def test_sign_and_verify_nil_digest
# Ed25519 is not FIPS-approved.
omit_on_fips
ed25519 = OpenSSL::PKey::generate_key("ED25519")
req = issue_csr(0, @dn, ed25519, nil)
- assert_equal(false, request_error_returns_false { req.verify(@rsa1024) })
- assert_equal(false, request_error_returns_false { req.verify(@rsa2048) })
+ assert_equal(false, request_error_returns_false { req.verify(@rsa1) })
+ assert_equal(false, request_error_returns_false { req.verify(@rsa2) })
assert_equal(false, req.verify(OpenSSL::PKey::generate_key("ED25519")))
assert_equal(true, req.verify(ed25519))
- req.public_key = @rsa1024.public_key
+ req.public_key = @rsa1
assert_equal(false, req.verify(ed25519))
end
def test_dup
- req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
assert_equal(req.to_der, req.dup.to_der)
end
def test_eq
- req1 = issue_csr(0, @dn, @rsa1024, "sha256")
- req2 = issue_csr(0, @dn, @rsa1024, "sha256")
- req3 = issue_csr(0, @dn, @rsa1024, "sha512")
+ req1 = issue_csr(0, @dn, @rsa1, "SHA256")
+ req2 = issue_csr(0, @dn, @rsa1, "SHA256")
+ req3 = issue_csr(0, @dn, @rsa1, "SHA512")
assert_equal false, req1 == 12345
assert_equal true, req1 == req2
@@ -161,7 +139,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase
end
def test_marshal
- req = issue_csr(0, @dn, @rsa1024, "sha256")
+ req = issue_csr(0, @dn, @rsa1, "SHA256")
deserialized = Marshal.load(Marshal.dump(req))
assert_equal req.to_der, deserialized.to_der
diff --git a/test/openssl/test_x509store.rb b/test/openssl/test_x509store.rb
index 745ae7dd13..c13beae364 100644
--- a/test/openssl/test_x509store.rb
+++ b/test/openssl/test_x509store.rb
@@ -91,6 +91,18 @@ class OpenSSL::TestX509Store < OpenSSL::TestCase
assert_match(/ok/i, store.error_string)
assert_equal(OpenSSL::X509::V_OK, store.error)
assert_equal([ee1_cert, ca2_cert, ca1_cert], store.chain)
+
+ # Manually instantiated StoreContext
+ # Nothing trusted
+ store = OpenSSL::X509::Store.new
+ ctx = OpenSSL::X509::StoreContext.new(store, ee1_cert)
+ assert_nil(ctx.current_cert)
+ assert_nil(ctx.current_crl)
+ assert_equal(false, ctx.verify)
+ assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, ctx.error)
+ assert_equal(0, ctx.error_depth)
+ assert_equal([ee1_cert], ctx.chain)
+ assert_equal(ee1_cert, ctx.current_cert)
end
def test_verify_callback
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
index ff789ff284..7e6fe8b163 100644
--- a/test/openssl/utils.rb
+++ b/test/openssl/utils.rb
@@ -177,16 +177,16 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase
@ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
@svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
@cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
- ca_exts = [
+ @ca_exts = [
["basicConstraints","CA:TRUE",true],
["keyUsage","cRLSign,keyCertSign",true],
]
- ee_exts = [
+ @ee_exts = [
["keyUsage","keyEncipherment,digitalSignature",true],
]
- @ca_cert = issue_cert(@ca, @ca_key, 1, ca_exts, nil, nil)
- @svr_cert = issue_cert(@svr, @svr_key, 2, ee_exts, @ca_cert, @ca_key)
- @cli_cert = issue_cert(@cli, @cli_key, 3, ee_exts, @ca_cert, @ca_key)
+ @ca_cert = issue_cert(@ca, @ca_key, 1, @ca_exts, nil, nil)
+ @svr_cert = issue_cert(@svr, @svr_key, 2, @ee_exts, @ca_cert, @ca_key)
+ @cli_cert = issue_cert(@cli, @cli_key, 3, @ee_exts, @ca_cert, @ca_key)
@server = nil
end
@@ -294,6 +294,33 @@ class OpenSSL::PKeyTestCase < OpenSSL::TestCase
else
assert_equal(false, ret)
end
+
+ def der_to_pem(der, pem_header)
+ # RFC 7468
+ <<~EOS
+ -----BEGIN #{pem_header}-----
+ #{[der].pack("m0").scan(/.{1,64}/).join("\n")}
+ -----END #{pem_header}-----
+ EOS
+ end
+
+ def der_to_encrypted_pem(der, pem_header, password)
+ # OpenSSL encryption, non-standard
+ iv = 16.times.to_a.pack("C*")
+ encrypted = OpenSSL::Cipher.new("aes-128-cbc").encrypt.then { |cipher|
+ cipher.key = OpenSSL::Digest.digest("MD5", password + iv[0, 8])
+ cipher.iv = iv
+ cipher.update(der) << cipher.final
+ }
+ <<~EOS
+ -----BEGIN #{pem_header}-----
+ Proc-Type: 4,ENCRYPTED
+ DEK-Info: AES-128-CBC,#{iv.unpack1("H*").upcase}
+
+ #{[encrypted].pack("m0").scan(/.{1,64}/).join("\n")}
+ -----END #{pem_header}-----
+ EOS
+ end
end
module OpenSSL::Certs
diff --git a/test/optparse/test_load.rb b/test/optparse/test_load.rb
index 0ebe855682..f664cfbf72 100644
--- a/test/optparse/test_load.rb
+++ b/test/optparse/test_load.rb
@@ -31,7 +31,13 @@ class TestOptionParserLoad < Test::Unit::TestCase
assert_equal({test: result}, into)
end
+ def assert_load_nothing
+ assert !new_parser.load
+ assert_nil @result
+ end
+
def setup_options(env, dir, suffix = nil)
+ env.update({'HOME'=>@tmpdir})
optdir = File.join(@tmpdir, dir)
FileUtils.mkdir_p(optdir)
file = File.join(optdir, [@basename, suffix].join(""))
@@ -41,7 +47,7 @@ class TestOptionParserLoad < Test::Unit::TestCase
begin
yield dir, optdir
ensure
- File.unlink(file)
+ File.unlink(file) rescue nil
Dir.rmdir(optdir) rescue nil
end
else
@@ -50,7 +56,7 @@ class TestOptionParserLoad < Test::Unit::TestCase
end
def setup_options_home(&block)
- setup_options({'HOME'=>@tmpdir}, ".options", &block)
+ setup_options({}, ".options", &block)
end
def setup_options_xdg_config_home(&block)
@@ -58,7 +64,7 @@ class TestOptionParserLoad < Test::Unit::TestCase
end
def setup_options_home_config(&block)
- setup_options({'HOME'=>@tmpdir}, ".config", ".options", &block)
+ setup_options({}, ".config", ".options", &block)
end
def setup_options_xdg_config_dirs(&block)
@@ -66,7 +72,11 @@ class TestOptionParserLoad < Test::Unit::TestCase
end
def setup_options_home_config_settings(&block)
- setup_options({'HOME'=>@tmpdir}, "config/settings", ".options", &block)
+ setup_options({}, "config/settings", ".options", &block)
+ end
+
+ def setup_options_home_options(envname, &block)
+ setup_options({envname => '~/options'}, "options", ".options", &block)
end
def test_load_home_options
@@ -91,7 +101,7 @@ class TestOptionParserLoad < Test::Unit::TestCase
end
def test_load_xdg_config_home
- result, = setup_options_xdg_config_home
+ result, dir = setup_options_xdg_config_home
assert_load(result)
setup_options_home_config do
@@ -105,6 +115,11 @@ class TestOptionParserLoad < Test::Unit::TestCase
setup_options_home_config_settings do
assert_load(result)
end
+
+ File.unlink("#{dir}/#{@basename}.options")
+ setup_options_home_config do
+ assert_load_nothing
+ end
end
def test_load_home_config
@@ -118,6 +133,11 @@ class TestOptionParserLoad < Test::Unit::TestCase
setup_options_home_config_settings do
assert_load(result)
end
+
+ setup_options_xdg_config_home do |_, dir|
+ File.unlink("#{dir}/#{@basename}.options")
+ assert_load_nothing
+ end
end
def test_load_xdg_config_dirs
@@ -135,7 +155,34 @@ class TestOptionParserLoad < Test::Unit::TestCase
end
def test_load_nothing
- assert !new_parser.load
- assert_nil @result
+ setup_options({}, "") do
+ assert_load_nothing
+ end
+ end
+
+ def test_not_expand_path_basename
+ basename = @basename
+ @basename = "~"
+ $test_optparse_basename = "/" + @basename
+ alias $test_optparse_prog $0
+ alias $0 $test_optparse_basename
+ setup_options({'HOME'=>@tmpdir+"/~options"}, "", "options") do
+ assert_load_nothing
+ end
+ ensure
+ alias $0 $test_optparse_prog
+ @basename = basename
+ end
+
+ def test_not_expand_path_xdg_config_home
+ setup_options_home_options('XDG_CONFIG_HOME') do
+ assert_load_nothing
+ end
+ end
+
+ def test_not_expand_path_xdg_config_dirs
+ setup_options_home_options('XDG_CONFIG_DIRS') do
+ assert_load_nothing
+ end
end
end
diff --git a/test/optparse/test_optparse.rb b/test/optparse/test_optparse.rb
index d50203bb63..ff334009a6 100644
--- a/test/optparse/test_optparse.rb
+++ b/test/optparse/test_optparse.rb
@@ -216,4 +216,16 @@ class TestOptionParser < Test::Unit::TestCase
end
end
end
+
+ def test_program_name
+ program = $0
+ $0 = "rdbg3.5"
+ assert_equal "rdbg3.5", OptionParser.new.program_name
+ RbConfig::CONFIG["EXECUTABLE_EXTS"]&.split(" ") do |ext|
+ $0 = "rdbg3.5" + ext
+ assert_equal "rdbg3.5", OptionParser.new.program_name
+ end
+ ensure
+ $0 = program
+ end
end
diff --git a/test/optparse/test_switch.rb b/test/optparse/test_switch.rb
new file mode 100644
index 0000000000..b06f4e310b
--- /dev/null
+++ b/test/optparse/test_switch.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: false
+
+require 'test/unit'
+require 'optparse'
+
+
+class TestOptionParserSwitch < Test::Unit::TestCase
+
+ def setup
+ @parser = OptionParser.new
+ end
+
+ def assert_invalidarg_error(msg, &block)
+ exc = assert_raise(OptionParser::InvalidArgument) do
+ yield
+ end
+ assert_equal "invalid argument: #{msg}", exc.message
+ end
+
+ def test_make_switch__enum_array
+ p = @parser
+ p.on("--enum=<val>", ["aa", "bb", "cc"])
+ p.permute(["--enum=bb"], into: (opts={}))
+ assert_equal({:enum=>"bb"}, opts)
+ assert_invalidarg_error("--enum=dd") do
+ p.permute(["--enum=dd"], into: (opts={}))
+ end
+ end
+
+ def test_make_switch__enum_hash
+ p = @parser
+ p.on("--hash=<val>", {"aa"=>"AA", "bb"=>"BB"})
+ p.permute(["--hash=bb"], into: (opts={}))
+ assert_equal({:hash=>"BB"}, opts)
+ assert_invalidarg_error("--hash=dd") do
+ p.permute(["--hash=dd"], into: (opts={}))
+ end
+ end
+
+ def test_make_switch__enum_set
+ p = @parser
+ p.on("--set=<val>", Set.new(["aa", "bb", "cc"]))
+ p.permute(["--set=bb"], into: (opts={}))
+ assert_equal({:set=>"bb"}, opts)
+ assert_invalidarg_error("--set=dd") do
+ p.permute(["--set=dd"], into: (opts={}))
+ end
+ end
+
+end
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 6a4bb784bd..6354e6a9b5 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -175,19 +175,19 @@ class TestPathname < Test::Unit::TestCase
if DOSISH_UNC
defassert(:del_trailing_separator, "//", "//")
- defassert(:del_trailing_separator, "//a", "//a")
- defassert(:del_trailing_separator, "//a", "//a/")
- defassert(:del_trailing_separator, "//a", "//a//")
- defassert(:del_trailing_separator, "//a/b", "//a/b")
- defassert(:del_trailing_separator, "//a/b", "//a/b/")
- defassert(:del_trailing_separator, "//a/b", "//a/b//")
- defassert(:del_trailing_separator, "//a/b/c", "//a/b/c")
- defassert(:del_trailing_separator, "//a/b/c", "//a/b/c/")
- defassert(:del_trailing_separator, "//a/b/c", "//a/b/c//")
else
defassert(:del_trailing_separator, "/", "///")
- defassert(:del_trailing_separator, "///a", "///a/")
end
+ defassert(:del_trailing_separator, "//a", "//a")
+ defassert(:del_trailing_separator, "//a", "//a/")
+ defassert(:del_trailing_separator, "//a", "//a//")
+ defassert(:del_trailing_separator, "//a/b", "//a/b")
+ defassert(:del_trailing_separator, "//a/b", "//a/b/")
+ defassert(:del_trailing_separator, "//a/b", "//a/b//")
+ defassert(:del_trailing_separator, "//a/b/c", "//a/b/c")
+ defassert(:del_trailing_separator, "//a/b/c", "//a/b/c/")
+ defassert(:del_trailing_separator, "//a/b/c", "//a/b/c//")
+ defassert(:del_trailing_separator, "///a", "///a/")
if DOSISH
defassert(:del_trailing_separator, "a", "a\\")
@@ -260,13 +260,12 @@ class TestPathname < Test::Unit::TestCase
assert_equal(Pathname("/foo/var"), r)
end
- def test_absolute
- assert_equal(true, Pathname("/").absolute?)
- assert_equal(false, Pathname("a").absolute?)
- end
-
def relative?(path)
- Pathname.new(path).relative?
+ path = Pathname.new(path)
+ relative = path.relative?
+ absolute = path.absolute?
+ assert_equal(!relative, absolute)
+ relative
end
defassert(:relative?, true, '')
@@ -281,7 +280,7 @@ class TestPathname < Test::Unit::TestCase
defassert(:relative?, !DOSISH_DRIVE_LETTER, 'A:/')
defassert(:relative?, !DOSISH_DRIVE_LETTER, 'A:/a')
- if File.dirname('//') == '//'
+ if DOSISH_UNC
defassert(:relative?, false, '//')
defassert(:relative?, false, '//a')
defassert(:relative?, false, '//a/')
@@ -348,7 +347,7 @@ class TestPathname < Test::Unit::TestCase
rescue NotImplementedError
return false
rescue Errno::ENOENT
- return false
+ return true
rescue Errno::EACCES
return false
end
@@ -370,10 +369,11 @@ class TestPathname < Test::Unit::TestCase
end
def realpath(path, basedir=nil)
- Pathname.new(path).realpath(basedir).to_s
+ Pathname.new(path).realpath(*basedir).to_s
end
def test_realpath
+ omit "not working yet" if RUBY_ENGINE == "jruby"
return if !has_symlink?
with_tmpchdir('rubytest-pathname') {|dir|
assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") }
@@ -434,6 +434,7 @@ class TestPathname < Test::Unit::TestCase
end
def test_realdirpath
+ omit "not working yet" if RUBY_ENGINE == "jruby"
return if !has_symlink?
Dir.mktmpdir('rubytest-pathname') {|dir|
rdir = realpath(dir)
@@ -482,12 +483,28 @@ class TestPathname < Test::Unit::TestCase
assert_equal('a', p1.to_s)
p2 = Pathname.new(p1)
assert_equal(p1, p2)
+
+ obj = Object.new
+ assert_raise_with_message(TypeError, /#to_path or #to_str/) { Pathname.new(obj) }
+
+ obj = Object.new
+ def obj.to_path; "a/path"; end
+ assert_equal("a/path", Pathname.new(obj).to_s)
+
+ obj = Object.new
+ def obj.to_str; "a/b"; end
+ assert_equal("a/b", Pathname.new(obj).to_s)
end
def test_initialize_nul
assert_raise(ArgumentError) { Pathname.new("a\0") }
end
+ def test_initialize_encoding
+ omit "https://github.com/jruby/jruby/issues/9120" if RUBY_ENGINE == "jruby"
+ assert_raise(Encoding::CompatibilityError) { Pathname.new("a".encode(Encoding::UTF_32BE)) }
+ end
+
def test_global_constructor
p = Pathname.new('a')
assert_equal(p, Pathname('a'))
@@ -606,6 +623,7 @@ class TestPathname < Test::Unit::TestCase
end
def test_null_character
+ omit "https://github.com/truffleruby/truffleruby/issues/4047" if RUBY_ENGINE == "truffleruby"
assert_raise(ArgumentError) { Pathname.new("\0") }
end
@@ -682,6 +700,7 @@ class TestPathname < Test::Unit::TestCase
end
def test_each_line
+ omit "not working yet" if RUBY_ENGINE == "jruby"
with_tmpchdir('rubytest-pathname') {|dir|
open("a", "w") {|f| f.puts 1, 2 }
a = []
@@ -708,6 +727,7 @@ class TestPathname < Test::Unit::TestCase
end
def test_each_line_opts
+ omit "not working yet" if RUBY_ENGINE == "jruby"
with_tmpchdir('rubytest-pathname') {|dir|
open("a", "w") {|f| f.puts 1, 2 }
a = []
@@ -815,7 +835,7 @@ class TestPathname < Test::Unit::TestCase
end
def test_birthtime
- omit if RUBY_PLATFORM =~ /android/
+ omit "no File.birthtime" if RUBY_PLATFORM =~ /android/ or !File.respond_to?(:birthtime)
# Check under a (probably) local filesystem.
# Remote filesystems often may not support birthtime.
with_tmpchdir('rubytest-pathname') do |dir|
@@ -1052,7 +1072,11 @@ class TestPathname < Test::Unit::TestCase
latime = Time.utc(2000)
lmtime = Time.utc(1999)
File.symlink("a", "l")
- Pathname("l").utime(latime, lmtime)
+ begin
+ Pathname("l").lutime(latime, lmtime)
+ rescue NotImplementedError
+ next
+ end
s = File.lstat("a")
ls = File.lstat("l")
assert_equal(atime, s.atime)
@@ -1322,7 +1346,8 @@ class TestPathname < Test::Unit::TestCase
end
def test_s_glob_3args
- expect = RUBY_VERSION >= "3.1" ? [Pathname("."), Pathname("f")] : [Pathname("."), Pathname(".."), Pathname("f")]
+ # Note: truffleruby should behave like CRuby 3.1+, but it's not the case currently
+ expect = (RUBY_VERSION >= "3.1" && RUBY_ENGINE != "truffleruby") ? [Pathname("."), Pathname("f")] : [Pathname("."), Pathname(".."), Pathname("f")]
with_tmpchdir('rubytest-pathname') {|dir|
open("f", "w") {|f| f.write "abc" }
Dir.chdir("/") {
diff --git a/test/pathname/test_ractor.rb b/test/pathname/test_ractor.rb
index 3d7b63deed..737e4a4111 100644
--- a/test/pathname/test_ractor.rb
+++ b/test/pathname/test_ractor.rb
@@ -9,14 +9,22 @@ class TestPathnameRactor < Test::Unit::TestCase
def test_ractor_shareable
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ class Ractor
+ alias value take
+ end unless Ractor.method_defined? :value # compat with Ruby 3.4 and olders
+
begin;
$VERBOSE = nil
require "pathname"
r = Ractor.new Pathname("a") do |x|
x.join(Pathname("b"), Pathname("c"))
end
- assert_equal(Pathname("a/b/c"), r.take)
+ assert_equal(Pathname("a/b/c"), r.value)
+
+ r = Ractor.new Pathname("a") do |a|
+ Pathname("b").relative_path_from(a)
+ end
+ assert_equal(Pathname("../b"), r.value)
end;
end
end
-
diff --git a/test/prism/api/freeze_test.rb b/test/prism/api/freeze_test.rb
index 5533a00331..bf91792e69 100644
--- a/test/prism/api/freeze_test.rb
+++ b/test/prism/api/freeze_test.rb
@@ -8,6 +8,11 @@ module Prism
assert_frozen(Prism.parse("1 + 2; %i{foo} + %i{bar}", freeze: true))
end
+ def test_offsets_usable
+ node = Prism.parse_statement("1 + 2", freeze: true)
+ assert_equal(1, node.start_line)
+ end
+
def test_lex
assert_frozen(Prism.lex("1 + 2; %i{foo} + %i{bar}", freeze: true))
end
diff --git a/test/prism/api/parse_stream_test.rb b/test/prism/api/parse_stream_test.rb
index 1c068c617c..3bc86fbd61 100644
--- a/test/prism/api/parse_stream_test.rb
+++ b/test/prism/api/parse_stream_test.rb
@@ -30,16 +30,28 @@ module Prism
end
def test___END__
- io = StringIO.new("1 + 2\n3 + 4\n__END__\n5 + 6")
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ __END__
+ 5 + 6
+ RUBY
result = Prism.parse_stream(io)
assert result.success?
assert_equal 2, result.value.statements.body.length
- assert_equal "5 + 6", io.read
+ assert_equal "5 + 6\n", io.read
end
def test_false___END___in_string
- io = StringIO.new("1 + 2\n3 + 4\n\"\n__END__\n\"\n5 + 6")
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ "
+ __END__
+ "
+ 5 + 6
+ RUBY
result = Prism.parse_stream(io)
assert result.success?
@@ -47,7 +59,14 @@ module Prism
end
def test_false___END___in_regexp
- io = StringIO.new("1 + 2\n3 + 4\n/\n__END__\n/\n5 + 6")
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ /
+ __END__
+ /
+ 5 + 6
+ RUBY
result = Prism.parse_stream(io)
assert result.success?
@@ -55,7 +74,14 @@ module Prism
end
def test_false___END___in_list
- io = StringIO.new("1 + 2\n3 + 4\n%w[\n__END__\n]\n5 + 6")
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ %w[
+ __END__
+ ]
+ 5 + 6
+ RUBY
result = Prism.parse_stream(io)
assert result.success?
@@ -63,7 +89,14 @@ module Prism
end
def test_false___END___in_heredoc
- io = StringIO.new("1 + 2\n3 + 4\n<<-EOF\n__END__\nEOF\n5 + 6")
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ <<-EOF
+ __END__
+ EOF
+ 5 + 6
+ RUBY
result = Prism.parse_stream(io)
assert result.success?
@@ -71,7 +104,11 @@ module Prism
end
def test_nul_bytes
- io = StringIO.new("1 # \0\0\0 \n2 # \0\0\0\n3")
+ io = StringIO.new(<<~RUBY)
+ 1 # \0\0\0\t
+ 2 # \0\0\0
+ 3
+ RUBY
result = Prism.parse_stream(io)
assert result.success?
diff --git a/test/prism/api/parse_test.rb b/test/prism/api/parse_test.rb
index bbce8a8fad..c9a47c1a61 100644
--- a/test/prism/api/parse_test.rb
+++ b/test/prism/api/parse_test.rb
@@ -119,6 +119,12 @@ module Prism
assert Prism.parse_success?("1 + 1", version: "3.5")
assert Prism.parse_success?("1 + 1", version: "3.5.0")
+ assert Prism.parse_success?("1 + 1", version: "4.0")
+ assert Prism.parse_success?("1 + 1", version: "4.0.0")
+
+ assert Prism.parse_success?("1 + 1", version: "4.1")
+ assert Prism.parse_success?("1 + 1", version: "4.1.0")
+
assert Prism.parse_success?("1 + 1", version: "latest")
# Test edge case
@@ -140,6 +146,18 @@ module Prism
end
end
+ def test_version_current
+ if RUBY_VERSION >= "3.3"
+ assert Prism.parse_success?("1 + 1", version: "current")
+ else
+ assert_raise(CurrentVersionError) { Prism.parse_success?("1 + 1", version: "current") }
+ end
+ end
+
+ def test_nearest
+ assert Prism.parse_success?("1 + 1", version: "nearest")
+ end
+
def test_scopes
assert_kind_of Prism::CallNode, Prism.parse_statement("foo")
assert_kind_of Prism::LocalVariableReadNode, Prism.parse_statement("foo", scopes: [[:foo]])
diff --git a/test/prism/bom_test.rb b/test/prism/bom_test.rb
index 890bc4b36c..0fa00ae4e8 100644
--- a/test/prism/bom_test.rb
+++ b/test/prism/bom_test.rb
@@ -5,6 +5,7 @@
return if RUBY_ENGINE != "ruby"
require_relative "test_helper"
+require "ripper"
module Prism
class BOMTest < TestCase
@@ -53,7 +54,7 @@ module Prism
def assert_bom(source)
bommed = "\xEF\xBB\xBF#{source}"
- assert_equal Prism.lex_ripper(bommed), Prism.lex_compat(bommed).value
+ assert_equal Ripper.lex(bommed), Prism.lex_compat(bommed).value
end
end
end
diff --git a/test/prism/encoding/encodings_test.rb b/test/prism/encoding/encodings_test.rb
index 4ad2b465cc..b008fc3fa1 100644
--- a/test/prism/encoding/encodings_test.rb
+++ b/test/prism/encoding/encodings_test.rb
@@ -56,21 +56,11 @@ module Prism
# Check that we can properly parse every codepoint in the given encoding.
def assert_encoding(encoding, name, range)
- # I'm not entirely sure, but I believe these codepoints are incorrect in
- # their parsing in CRuby. They all report as matching `[[:lower:]]` but
- # then they are parsed as constants. This is because CRuby determines if
- # an identifier is a constant or not by case folding it down to lowercase
- # and checking if there is a difference. And even though they report
- # themselves as lowercase, their case fold is different. I have reported
- # this bug upstream.
+ unicode = false
+
case encoding
when Encoding::UTF_8, Encoding::UTF_8_MAC, Encoding::UTF8_DoCoMo, Encoding::UTF8_KDDI, Encoding::UTF8_SoftBank, Encoding::CESU_8
- range = range.to_a - [
- 0x01c5, 0x01c8, 0x01cb, 0x01f2, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b,
- 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b,
- 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab,
- 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fbc, 0x1fcc, 0x1ffc,
- ]
+ unicode = true
when Encoding::Windows_1253
range = range.to_a - [0xb5]
end
@@ -79,7 +69,7 @@ module Prism
character = codepoint.chr(encoding)
if character.match?(/[[:alpha:]]/)
- if character.match?(/[[:upper:]]/)
+ if character.match?(/[[:upper:]]/) || (unicode && character.match?(Regexp.new("\\p{Lt}".encode(encoding))))
assert_encoding_constant(name, character)
else
assert_encoding_identifier(name, character)
diff --git a/test/prism/encoding/regular_expression_encoding_test.rb b/test/prism/encoding/regular_expression_encoding_test.rb
index e2daae1d7f..fdff1e3281 100644
--- a/test/prism/encoding/regular_expression_encoding_test.rb
+++ b/test/prism/encoding/regular_expression_encoding_test.rb
@@ -2,6 +2,7 @@
return unless defined?(RubyVM::InstructionSequence)
return if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
+return if RUBY_VERSION < "3.2"
require_relative "../test_helper"
@@ -21,7 +22,7 @@ module Prism
["n", "u", "e", "s"].each do |modifier|
define_method(:"test_regular_expression_encoding_modifiers_/#{modifier}_#{encoding.name}") do
- regexp_sources = ["abc", "garçon", "\\x80", "gar\\xC3\\xA7on", "gar\\u{E7}on", "abc\\u{FFFFFF}", "\\x80\\u{80}" ]
+ regexp_sources = ["abc", "garçon", "\\x80", "gar\\xC3\\xA7on", "gar\\u{E7}on", "abc\\u{FFFFFF}", "\\x80\\u{80}", "\\p{L}" ]
assert_regular_expression_encoding_flags(
encoding,
@@ -35,17 +36,15 @@ module Prism
def assert_regular_expression_encoding_flags(encoding, regexps)
regexps.each do |regexp|
- regexp_modifier_used = regexp.end_with?("/u") || regexp.end_with?("/e") || regexp.end_with?("/s") || regexp.end_with?("/n")
source = "# encoding: #{encoding.name}\n#{regexp}"
- encoding_errors = ["invalid multibyte char", "escaped non ASCII character in UTF-8 regexp", "differs from source encoding"]
- skipped_errors = ["invalid multibyte escape", "incompatible character encoding", "UTF-8 character in non UTF-8 regexp", "invalid Unicode range", "invalid Unicode list"]
-
- # TODO (nirvdrum 21-Feb-2024): Prism currently does not handle Regexp validation unless modifiers are used. So, skip processing those errors for now: https://github.com/ruby/prism/issues/2104
- unless regexp_modifier_used
- skipped_errors += encoding_errors
- encoding_errors.clear
- end
+ encoding_errors = [
+ "invalid multibyte char", "escaped non ASCII character in UTF-8 regexp",
+ "differs from source encoding", "incompatible character encoding",
+ "invalid multibyte escape", "UTF-8 character in non UTF-8 regexp",
+ "invalid Unicode range", "non escaped non ASCII character",
+ "invalid character property name", "invalid Unicode list",
+ ]
expected =
begin
@@ -53,8 +52,6 @@ module Prism
rescue SyntaxError => error
if encoding_errors.find { |e| error.message.include?(e) }
error.message.split("\n").map { |m| m[/: (.+?)$/, 1] }
- elsif skipped_errors.find { |e| error.message.include?(e) }
- next
else
raise
end
@@ -111,19 +108,6 @@ module Prism
end
end
- # TODO (nirvdrum 22-Feb-2024): Remove this workaround once Prism better maps CRuby's error messages.
- # This class of error message is tricky. The part not being compared is a representation of the regexp.
- # Depending on the source encoding and any encoding modifiers being used, CRuby alters how the regexp is represented.
- # Sometimes it's an MBC string. Other times it uses hexadecimal character escapes. And in other cases it uses
- # the long-form Unicode escape sequences. This short-circuit checks that the error message is mostly correct.
- if expected.is_a?(Array) && actual.is_a?(Array)
- if expected.last.start_with?("/.../n has a non escaped non ASCII character in non ASCII-8BIT script:") &&
- actual.last.start_with?("/.../n has a non escaped non ASCII character in non ASCII-8BIT script:")
- expected.pop
- actual.pop
- end
- end
-
assert_equal expected, actual
end
end
diff --git a/test/prism/errors/3.3-3.3/circular_parameters.txt b/test/prism/errors/3.3-3.3/circular_parameters.txt
new file mode 100644
index 0000000000..ef9642b075
--- /dev/null
+++ b/test/prism/errors/3.3-3.3/circular_parameters.txt
@@ -0,0 +1,12 @@
+def foo(bar = bar) = 42
+ ^~~ circular argument reference - bar
+
+def foo(bar: bar) = 42
+ ^~~ circular argument reference - bar
+
+proc { |foo = foo| }
+ ^~~ circular argument reference - foo
+
+proc { |foo: foo| }
+ ^~~ circular argument reference - foo
+
diff --git a/test/prism/errors/3.3-3.4/leading_logical.txt b/test/prism/errors/3.3-3.4/leading_logical.txt
new file mode 100644
index 0000000000..2a702e281d
--- /dev/null
+++ b/test/prism/errors/3.3-3.4/leading_logical.txt
@@ -0,0 +1,34 @@
+1
+&& 2
+^~ unexpected '&&', ignoring it
+&& 3
+^~ unexpected '&&', ignoring it
+
+1
+|| 2
+^ unexpected '|', ignoring it
+ ^ unexpected '|', ignoring it
+|| 3
+^ unexpected '|', ignoring it
+ ^ unexpected '|', ignoring it
+
+1
+and 2
+^~~ unexpected 'and', ignoring it
+and 3
+^~~ unexpected 'and', ignoring it
+
+1
+or 2
+^~ unexpected 'or', ignoring it
+or 3
+^~ unexpected 'or', ignoring it
+
+1
+and foo
+^~~ unexpected 'and', ignoring it
+
+2
+or foo
+^~ unexpected 'or', ignoring it
+
diff --git a/test/prism/errors/3.3-3.4/private_endless_method.txt b/test/prism/errors/3.3-3.4/private_endless_method.txt
new file mode 100644
index 0000000000..8aae5e0cd3
--- /dev/null
+++ b/test/prism/errors/3.3-3.4/private_endless_method.txt
@@ -0,0 +1,3 @@
+private def foo = puts "Hello"
+ ^ unexpected string literal, expecting end-of-input
+
diff --git a/test/prism/errors/do_not_allow_trailing_commas_in_method_parameters.txt b/test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt
index c0fec0c704..c0fec0c704 100644
--- a/test/prism/errors/do_not_allow_trailing_commas_in_method_parameters.txt
+++ b/test/prism/errors/3.3-4.0/do_not_allow_trailing_commas_in_method_parameters.txt
diff --git a/test/prism/errors/3.3-4.0/noblock.txt b/test/prism/errors/3.3-4.0/noblock.txt
new file mode 100644
index 0000000000..07939041bb
--- /dev/null
+++ b/test/prism/errors/3.3-4.0/noblock.txt
@@ -0,0 +1,6 @@
+def foo(&nil)
+ ^~~ unexpected 'nil'; expected a `)` to close the parameters
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+end
+
diff --git a/test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt b/test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt
new file mode 100644
index 0000000000..2954f7ea48
--- /dev/null
+++ b/test/prism/errors/3.3-4.0/singleton_method_with_void_value.txt
@@ -0,0 +1,3 @@
+def ((return; 1)).bar; end
+ ^ cannot define singleton method for literals
+
diff --git a/test/prism/errors/3.4-4.0/void_value.txt b/test/prism/errors/3.4-4.0/void_value.txt
new file mode 100644
index 0000000000..c03139bb05
--- /dev/null
+++ b/test/prism/errors/3.4-4.0/void_value.txt
@@ -0,0 +1,18 @@
+x = begin
+ return
+ ^~~~~~ unexpected void value expression
+rescue
+ return
+else
+ return
+end
+
+x = begin
+ return
+rescue
+ "OK"
+else
+ return
+ ^~~~~~ unexpected void value expression
+end
+
diff --git a/test/prism/errors/block_args_in_array_assignment.txt b/test/prism/errors/3.4/block_args_in_array_assignment.txt
index 71dca8452b..71dca8452b 100644
--- a/test/prism/errors/block_args_in_array_assignment.txt
+++ b/test/prism/errors/3.4/block_args_in_array_assignment.txt
diff --git a/test/prism/errors/dont_allow_return_inside_sclass_body.txt b/test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt
index c29fe01728..c29fe01728 100644
--- a/test/prism/errors/dont_allow_return_inside_sclass_body.txt
+++ b/test/prism/errors/3.4/dont_allow_return_inside_sclass_body.txt
diff --git a/test/prism/errors/it_with_ordinary_parameter.txt b/test/prism/errors/3.4/it_with_ordinary_parameter.txt
index ff9c4276ca..ff9c4276ca 100644
--- a/test/prism/errors/it_with_ordinary_parameter.txt
+++ b/test/prism/errors/3.4/it_with_ordinary_parameter.txt
diff --git a/test/prism/errors/keyword_args_in_array_assignment.txt b/test/prism/errors/3.4/keyword_args_in_array_assignment.txt
index e379ec0ef4..e379ec0ef4 100644
--- a/test/prism/errors/keyword_args_in_array_assignment.txt
+++ b/test/prism/errors/3.4/keyword_args_in_array_assignment.txt
diff --git a/test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt b/test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt
new file mode 100644
index 0000000000..b3e06f4154
--- /dev/null
+++ b/test/prism/errors/4.1/do_not_allow_trailing_commas_after_terminating_arguments.txt
@@ -0,0 +1,6 @@
+def foo(a,b,...,);end
+ ^ unexpected `,` in parameters
+
+def foo(a,b,&block,);end
+ ^ unexpected `,` in parameters
+
diff --git a/test/prism/errors/4.1/end_block_exit.txt b/test/prism/errors/4.1/end_block_exit.txt
new file mode 100644
index 0000000000..a4a1e9bc2c
--- /dev/null
+++ b/test/prism/errors/4.1/end_block_exit.txt
@@ -0,0 +1,10 @@
+END {
+ break
+ ^~~~~ Invalid break
+}
+
+END {
+ next
+ ^~~~ Invalid next
+}
+
diff --git a/test/prism/errors/4.1/multiple_blocks.txt b/test/prism/errors/4.1/multiple_blocks.txt
new file mode 100644
index 0000000000..7e8433cf82
--- /dev/null
+++ b/test/prism/errors/4.1/multiple_blocks.txt
@@ -0,0 +1,12 @@
+def foo(&nil, &nil); end
+ ^ unexpected parameter order
+ ^~~~ multiple block parameters; only one block is allowed
+
+def foo(&foo, &nil); end
+ ^ unexpected parameter order
+ ^~~~ multiple block parameters; only one block is allowed
+
+def foo(&nil, &foo); end
+ ^ unexpected parameter order
+ ^~~~ multiple block parameters; only one block is allowed
+
diff --git a/test/prism/errors/4.1/singleton_method_with_void_value.txt b/test/prism/errors/4.1/singleton_method_with_void_value.txt
new file mode 100644
index 0000000000..bc6cf9c602
--- /dev/null
+++ b/test/prism/errors/4.1/singleton_method_with_void_value.txt
@@ -0,0 +1,4 @@
+def ((return; 1)).bar; end
+ ^~~~~~ unexpected void value expression
+ ^ cannot define singleton method for literals
+
diff --git a/test/prism/errors/4.1/void_value.txt b/test/prism/errors/4.1/void_value.txt
new file mode 100644
index 0000000000..a27ffd763a
--- /dev/null
+++ b/test/prism/errors/4.1/void_value.txt
@@ -0,0 +1,44 @@
+x = begin
+ return
+rescue
+ return
+else
+ return
+ ^~~~~~ unexpected void value expression
+end
+
+x = begin
+ ignored_because_else_branch
+rescue
+ return
+else
+ return
+ ^~~~~~ unexpected void value expression
+end
+
+x = case
+ when 1 then return
+ ^~~~~~ unexpected void value expression
+ else return
+end
+
+x = case 1
+ in 2 then return
+ ^~~~~~ unexpected void value expression
+ else return
+end
+
+x = begin
+ return
+ ^~~~~~ unexpected void value expression
+ "NG"
+end
+
+x = if rand < 0.5
+ return
+ ^~~~~~ unexpected void value expression
+ "NG"
+else
+ return
+end
+
diff --git a/test/prism/errors/block_args_with_endless_def.txt b/test/prism/errors/block_args_with_endless_def.txt
new file mode 100644
index 0000000000..a7242160d2
--- /dev/null
+++ b/test/prism/errors/block_args_with_endless_def.txt
@@ -0,0 +1,5 @@
+p do |a = def f = 1; b| end
+ ^~~~~~~ unexpected endless method definition; expected a default value for a parameter
+p do |a = def f = 1| 2; b|c end
+ ^~~~~~~ unexpected endless method definition; expected a default value for a parameter
+
diff --git a/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt b/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt
index 16af8200ec..1184b38ce8 100644
--- a/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt
+++ b/test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt
@@ -1,5 +1,5 @@
x.each { x end
^~~ unexpected 'end', expecting end-of-input
^~~ unexpected 'end', ignoring it
- ^ expected a block beginning with `{` to end with `}`
+ ^ expected a block beginning with `{` to end with `}`
diff --git a/test/prism/errors/block_pass_return_value.txt b/test/prism/errors/block_pass_return_value.txt
new file mode 100644
index 0000000000..c9d12281d9
--- /dev/null
+++ b/test/prism/errors/block_pass_return_value.txt
@@ -0,0 +1,33 @@
+return &b
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+
+return(&b)
+ ^ unexpected '&', ignoring it
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+return a, &b
+ ^~ block argument should not be given
+
+return(a, &b)
+ ^~ unexpected write target
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ expected a matching `)`
+ ^ unexpected '&', expecting end-of-input
+ ^ unexpected '&', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+tap { break a, &b }
+ ^~ block argument should not be given
+
+tap { next a, &b }
+ ^~ block argument should not be given
+
diff --git a/test/prism/errors/command_call_in.txt b/test/prism/errors/command_call_in.txt
index 2fdcf09738..2b7286abc3 100644
--- a/test/prism/errors/command_call_in.txt
+++ b/test/prism/errors/command_call_in.txt
@@ -2,4 +2,5 @@ foo 1 in a
^~ unexpected 'in', expecting end-of-input
^~ unexpected 'in', ignoring it
a = foo 2 in b
+ ^~ unexpected 'in', expecting end-of-input
diff --git a/test/prism/errors/command_call_in_2.txt b/test/prism/errors/command_call_in_2.txt
new file mode 100644
index 0000000000..6676b1acba
--- /dev/null
+++ b/test/prism/errors/command_call_in_2.txt
@@ -0,0 +1,4 @@
+a.b x in pattern
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/command_call_in_3.txt b/test/prism/errors/command_call_in_3.txt
new file mode 100644
index 0000000000..6fe026d7d3
--- /dev/null
+++ b/test/prism/errors/command_call_in_3.txt
@@ -0,0 +1,4 @@
+a.b x: in pattern
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/command_call_in_4.txt b/test/prism/errors/command_call_in_4.txt
new file mode 100644
index 0000000000..045afe6498
--- /dev/null
+++ b/test/prism/errors/command_call_in_4.txt
@@ -0,0 +1,4 @@
+a.b &x in pattern
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/command_call_in_5.txt b/test/prism/errors/command_call_in_5.txt
new file mode 100644
index 0000000000..be07287f81
--- /dev/null
+++ b/test/prism/errors/command_call_in_5.txt
@@ -0,0 +1,4 @@
+a.b *x => pattern
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
diff --git a/test/prism/errors/command_call_in_6.txt b/test/prism/errors/command_call_in_6.txt
new file mode 100644
index 0000000000..470f323872
--- /dev/null
+++ b/test/prism/errors/command_call_in_6.txt
@@ -0,0 +1,4 @@
+a.b x: => pattern
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
diff --git a/test/prism/errors/command_call_in_7.txt b/test/prism/errors/command_call_in_7.txt
new file mode 100644
index 0000000000..a8bea912b5
--- /dev/null
+++ b/test/prism/errors/command_call_in_7.txt
@@ -0,0 +1,4 @@
+a.b &x => pattern
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
diff --git a/test/prism/errors/command_call_value_and.txt b/test/prism/errors/command_call_value_and.txt
new file mode 100644
index 0000000000..a131aa5530
--- /dev/null
+++ b/test/prism/errors/command_call_value_and.txt
@@ -0,0 +1,3 @@
+a = b c and 1
+ ^~~ unexpected 'and', expecting end-of-input
+
diff --git a/test/prism/errors/command_call_value_or.txt b/test/prism/errors/command_call_value_or.txt
new file mode 100644
index 0000000000..cc75714166
--- /dev/null
+++ b/test/prism/errors/command_call_value_or.txt
@@ -0,0 +1,3 @@
+a = b c or 1
+ ^~ unexpected 'or', expecting end-of-input
+
diff --git a/test/prism/errors/command_calls.txt b/test/prism/errors/command_calls.txt
index 19812a1d0a..6601e5fbbc 100644
--- a/test/prism/errors/command_calls.txt
+++ b/test/prism/errors/command_calls.txt
@@ -1,3 +1,10 @@
[a b]
^ unexpected local variable or method; expected a `,` separator for the array elements
+
+[
+ a b do
+ ^ unexpected local variable or method; expected a `,` separator for the array elements
+ end,
+]
+
diff --git a/test/prism/errors/command_calls_2.txt b/test/prism/errors/command_calls_2.txt
index b0983c015b..13e10f7ebf 100644
--- a/test/prism/errors/command_calls_2.txt
+++ b/test/prism/errors/command_calls_2.txt
@@ -1,5 +1,5 @@
{a: b c}
- ^ expected a `}` to close the hash literal
+^ expected a `}` to close the hash literal
^ unexpected local variable or method, expecting end-of-input
^ unexpected '}', expecting end-of-input
^ unexpected '}', ignoring it
diff --git a/test/prism/errors/command_calls_24.txt b/test/prism/errors/command_calls_24.txt
index 3046b36dc1..27a32ea3bf 100644
--- a/test/prism/errors/command_calls_24.txt
+++ b/test/prism/errors/command_calls_24.txt
@@ -1,5 +1,5 @@
->a=b c{}
^ expected a `do` keyword or a `{` to open the lambda block
^ unexpected end-of-input, assuming it is closing the parent top level context
- ^ expected a lambda block beginning with `do` to end with `end`
+^~ expected a lambda block beginning with `do` to end with `end`
diff --git a/test/prism/errors/command_calls_25.txt b/test/prism/errors/command_calls_25.txt
index 5fddd90fdd..cf04508f87 100644
--- a/test/prism/errors/command_calls_25.txt
+++ b/test/prism/errors/command_calls_25.txt
@@ -4,5 +4,5 @@
^ unexpected ')', expecting end-of-input
^ unexpected ')', ignoring it
^ unexpected end-of-input, assuming it is closing the parent top level context
- ^ expected a lambda block beginning with `do` to end with `end`
+^~ expected a lambda block beginning with `do` to end with `end`
diff --git a/test/prism/errors/command_calls_31.txt b/test/prism/errors/command_calls_31.txt
new file mode 100644
index 0000000000..e662b25444
--- /dev/null
+++ b/test/prism/errors/command_calls_31.txt
@@ -0,0 +1,17 @@
+true && not true
+ ^~~~ expected a `(` after `not`
+ ^~~~ unexpected 'true', expecting end-of-input
+
+true || not true
+ ^~~~ expected a `(` after `not`
+ ^~~~ unexpected 'true', expecting end-of-input
+
+true && not (true)
+ ^ expected a `(` immediately after `not`
+ ^ unexpected '(', expecting end-of-input
+
+true && not
+true
+^~~~ expected a `(` after `not`
+^~~~ unexpected 'true', expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_32.txt b/test/prism/errors/command_calls_32.txt
new file mode 100644
index 0000000000..14488ca335
--- /dev/null
+++ b/test/prism/errors/command_calls_32.txt
@@ -0,0 +1,19 @@
+foo && return bar
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+tap { foo && break bar }
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+tap { foo && next bar }
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+foo && return()
+ ^ unexpected '(', expecting end-of-input
+
+foo && return(bar)
+ ^ unexpected '(', expecting end-of-input
+
+foo && return(bar, baz)
+ ^~~~~~~~~~ unexpected write target
+ ^ unexpected '(', expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_33.txt b/test/prism/errors/command_calls_33.txt
new file mode 100644
index 0000000000..13e3b35c9e
--- /dev/null
+++ b/test/prism/errors/command_calls_33.txt
@@ -0,0 +1,6 @@
+1 if foo = bar baz
+ ^~~ unexpected local variable or method, expecting end-of-input
+
+1 and foo = bar baz
+ ^~~ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/command_calls_34.txt b/test/prism/errors/command_calls_34.txt
new file mode 100644
index 0000000000..bc0ea5e81c
--- /dev/null
+++ b/test/prism/errors/command_calls_34.txt
@@ -0,0 +1,31 @@
+foo(bar 1 do end, 2)
+ ^~ unexpected 'do'; expected a `)` to close the arguments
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^ unexpected ',', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+foo(bar 1 do end,)
+ ^~ unexpected 'do'; expected a `)` to close the arguments
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^ unexpected ',', ignoring it
+ ^ unexpected ')', ignoring it
+
+foo(1, bar 2 do end)
+ ^ unexpected integer; expected a `)` to close the arguments
+ ^ unexpected integer, expecting end-of-input
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^ unexpected ')', ignoring it
+
+foo(1, bar 2)
+ ^ unexpected integer; expected a `)` to close the arguments
+ ^ unexpected integer, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/command_calls_35.txt b/test/prism/errors/command_calls_35.txt
new file mode 100644
index 0000000000..bd72d1be56
--- /dev/null
+++ b/test/prism/errors/command_calls_35.txt
@@ -0,0 +1,50 @@
+p(p a, x: b => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, x: => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, &block => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a do end => value)
+ ^~ unexpected 'do'; expected a `)` to close the arguments
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', ignoring it
+ ^~ unexpected '=>', ignoring it
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, *args => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p(p a, **kwargs => value)
+ ^~ unexpected '=>'; expected a `)` to close the arguments
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
+p p 1, &block => 2, &block
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+ ^ unexpected ',', expecting end-of-input
+ ^ unexpected ',', ignoring it
+ ^ unexpected '&', ignoring it
+
+p p p 1 => 2 => 3 => 4
+ ^~ unexpected '=>', expecting end-of-input
+ ^~ unexpected '=>', ignoring it
+
+p[p a, x: b => value]
+ ^ expected a matching `]`
+ ^ unexpected ']', expecting end-of-input
+ ^ unexpected ']', ignoring it
+
diff --git a/test/prism/errors/def_endless_do.txt b/test/prism/errors/def_endless_do.txt
new file mode 100644
index 0000000000..d66b7086da
--- /dev/null
+++ b/test/prism/errors/def_endless_do.txt
@@ -0,0 +1,6 @@
+def a = a b do 1 end
+ ^~ unexpected 'do', expecting end-of-input
+ ^~ unexpected 'do', ignoring it
+ ^~~ unexpected 'end', expecting end-of-input
+ ^~~ unexpected 'end', ignoring it
+
diff --git a/test/prism/errors/def_with_optional_splat.txt b/test/prism/errors/def_with_optional_splat.txt
new file mode 100644
index 0000000000..74a833ceec
--- /dev/null
+++ b/test/prism/errors/def_with_optional_splat.txt
@@ -0,0 +1,6 @@
+def foo(*bar = nil); end
+ ^ unexpected '='; expected a `)` to close the parameters
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+ ^~~ unexpected 'end', ignoring it
+
diff --git a/test/prism/errors/destroy_call_operator_write_arguments.txt b/test/prism/errors/destroy_call_operator_write_arguments.txt
new file mode 100644
index 0000000000..b6933d61d1
--- /dev/null
+++ b/test/prism/errors/destroy_call_operator_write_arguments.txt
@@ -0,0 +1,11 @@
+t next&&do end&=
+ ^~ unexpected 'do'; expected an expression after the operator
+ ^~~~ unexpected void value expression
+ ^~~~ unexpected void value expression
+ ^~ unexpected '&=', expecting end-of-input
+ ^~ unexpected '&=', ignoring it
+ ^~~~ Invalid next
+''while=
+ ^~~~~ expected a predicate expression for the `while` statement
+ ^ unexpected '='; target cannot be written
+
diff --git a/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt b/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt
index df49557617..639dec3af2 100644
--- a/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt
+++ b/test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt
@@ -1,3 +1,13 @@
a {|...|}
- ^~~ unexpected ... when the parent method is not forwarding
+ ^~~ unexpected ... in block argument
+
+def foo(...)
+ a {|...|}
+ ^~~ unexpected ... in block argument
+end
+
+def foo
+ a {|...|}
+ ^~~ unexpected ... in block argument
+end
diff --git a/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt b/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt
index c2405a5c66..03e17683e4 100644
--- a/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt
+++ b/test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt
@@ -1,3 +1,13 @@
->(...) {}
- ^~~ unexpected ... when the parent method is not forwarding
+ ^~~ unexpected ... in lambda argument
+
+def foo(...)
+ ->(...) {}
+ ^~~ unexpected ... in lambda argument
+end
+
+def foo
+ ->(...) {}
+ ^~~ unexpected ... in lambda argument
+end
diff --git a/test/prism/errors/endless_method_command_call.txt b/test/prism/errors/endless_method_command_call.txt
new file mode 100644
index 0000000000..e6a328c294
--- /dev/null
+++ b/test/prism/errors/endless_method_command_call.txt
@@ -0,0 +1,3 @@
+private :m, def hello = puts "Hello"
+ ^ unexpected string literal, expecting end-of-input
+
diff --git a/test/prism/errors/endless_method_command_call_parameters.txt b/test/prism/errors/endless_method_command_call_parameters.txt
new file mode 100644
index 0000000000..5dc92ce7f9
--- /dev/null
+++ b/test/prism/errors/endless_method_command_call_parameters.txt
@@ -0,0 +1,27 @@
+def f x: = 1
+ ^ could not parse the endless method parameters
+
+def f ... = 1
+ ^ could not parse the endless method parameters
+
+def f * = 1
+ ^ could not parse the endless method parameters
+
+def f ** = 1
+ ^ could not parse the endless method parameters
+
+def f & = 1
+ ^ could not parse the endless method parameters
+
+def f *a = 1
+ ^ could not parse the endless method parameters
+
+def f **a = 1
+ ^ could not parse the endless method parameters
+
+def f &a = 1
+ ^ could not parse the endless method parameters
+
+def f a, (b) = 1
+ ^ could not parse the endless method parameters
+
diff --git a/test/prism/errors/heredoc_percent_q_newline_delimiter.txt b/test/prism/errors/heredoc_percent_q_newline_delimiter.txt
new file mode 100644
index 0000000000..73664c071f
--- /dev/null
+++ b/test/prism/errors/heredoc_percent_q_newline_delimiter.txt
@@ -0,0 +1,11 @@
+%q
+#{<<B}
+B
+^ unexpected constant, expecting end-of-input
+
+<<A; %q
+A
+#{<<B}
+B
+^ unexpected constant, expecting end-of-input
+
diff --git a/test/prism/errors/heredoc_unterminated.txt b/test/prism/errors/heredoc_unterminated.txt
index 3c6aeaeb81..56bd162998 100644
--- a/test/prism/errors/heredoc_unterminated.txt
+++ b/test/prism/errors/heredoc_unterminated.txt
@@ -3,7 +3,7 @@ a=>{<<b
^~~ unexpected heredoc beginning; expected a key in the hash pattern
^ unterminated heredoc; can't find string "b" anywhere before EOF
^~~ expected a label as the key in the hash pattern
- ^ expected a `}` to close the pattern expression
+ ^ expected a `}` to close the pattern expression
^ unexpected heredoc ending, expecting end-of-input
^ unexpected heredoc ending, ignoring it
diff --git a/test/prism/errors/infix_after_label.txt b/test/prism/errors/infix_after_label.txt
index c3bcfaeceb..f02a29470f 100644
--- a/test/prism/errors/infix_after_label.txt
+++ b/test/prism/errors/infix_after_label.txt
@@ -1,6 +1,6 @@
{ 'a':.upcase => 1 }
^ unexpected '.'; expected a value in the hash literal
- ^ expected a `}` to close the hash literal
+^ expected a `}` to close the hash literal
^ unexpected '}', expecting end-of-input
^ unexpected '}', ignoring it
diff --git a/test/prism/errors/interpolated_symbol_pattern_hash_key.txt b/test/prism/errors/interpolated_symbol_pattern_hash_key.txt
new file mode 100644
index 0000000000..b4532439ff
--- /dev/null
+++ b/test/prism/errors/interpolated_symbol_pattern_hash_key.txt
@@ -0,0 +1,3 @@
+case foo; in { "bar#{1}": 1 }; end
+ ^~~~~~~~~~ symbol literal with interpolation is not allowed
+
diff --git a/test/prism/errors/label_in_interpolated_string.txt b/test/prism/errors/label_in_interpolated_string.txt
new file mode 100644
index 0000000000..29af5310a1
--- /dev/null
+++ b/test/prism/errors/label_in_interpolated_string.txt
@@ -0,0 +1,14 @@
+case in el""Q
+^~~~ expected a predicate for a case matching statement
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected constant, expecting end-of-input
+^~~~ expected an `end` to close the `case` statement
+ !"""#{in el"":Q
+ ^~ unexpected 'in', assuming it is closing the parent 'in' clause
+ ^ expected a `}` to close the embedded expression
+ ^~ cannot parse the string part
+ ^~ cannot parse the string part
+ ^ cannot parse the string part
+ ^~~~~~~~~~~ unexpected label
+ ^~~~~~~~~~~ expected a string for concatenation
+
diff --git a/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt b/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
index fead8aaf23..f599dc476b 100644
--- a/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
+++ b/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
@@ -1,3 +1,4 @@
'a' rescue 2 in 3.upcase
^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
diff --git a/test/prism/errors/match_predicate_after_rescue_with_opreator.txt b/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
index b2363a544d..44a4ba8488 100644
--- a/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
+++ b/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
@@ -1,3 +1,4 @@
1 rescue 2 in 3 << 4
^~ unexpected <<, expecting end-of-input
+ ^~ unexpected <<, ignoring it
diff --git a/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt b/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
index d72d72ce60..abcfaf094d 100644
--- a/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
+++ b/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
@@ -1,3 +1,4 @@
1 rescue 2 => 3.inspect
^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
diff --git a/test/prism/errors/match_required_after_rescue_with_opreator.txt b/test/prism/errors/match_required_after_rescue_with_opreator.txt
index 903e2ccc8e..5e6387ca4d 100644
--- a/test/prism/errors/match_required_after_rescue_with_opreator.txt
+++ b/test/prism/errors/match_required_after_rescue_with_opreator.txt
@@ -1,3 +1,4 @@
1 rescue 2 => 3 ** 4
^~ unexpected '**', expecting end-of-input
+ ^~ unexpected '**', ignoring it
diff --git a/test/prism/errors/modifier_conditional_in_predicate.txt b/test/prism/errors/modifier_conditional_in_predicate.txt
new file mode 100644
index 0000000000..5b89ee4a26
--- /dev/null
+++ b/test/prism/errors/modifier_conditional_in_predicate.txt
@@ -0,0 +1,12 @@
+if a if b then end
+ ^~ expected `then` or `;` or '\n'
+ ^~ unexpected 'if', ignoring it
+ ^~~~ unexpected 'then', expecting end-of-input
+ ^~~~ unexpected 'then', ignoring it
+
+unless a unless b then end
+ ^~~~~~ expected `then` or `;` or '\n'
+ ^~~~~~ unexpected 'unless', ignoring it
+ ^~~~ unexpected 'then', expecting end-of-input
+ ^~~~ unexpected 'then', ignoring it
+
diff --git a/test/prism/errors/not_without_parens_assignment.txt b/test/prism/errors/not_without_parens_assignment.txt
new file mode 100644
index 0000000000..32d58efedf
--- /dev/null
+++ b/test/prism/errors/not_without_parens_assignment.txt
@@ -0,0 +1,4 @@
+x = not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/not_without_parens_call.txt b/test/prism/errors/not_without_parens_call.txt
new file mode 100644
index 0000000000..a778193400
--- /dev/null
+++ b/test/prism/errors/not_without_parens_call.txt
@@ -0,0 +1,7 @@
+foo(not y)
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method; expected a `)` to close the arguments
+ ^ unexpected local variable or method, expecting end-of-input
+ ^ unexpected ')', expecting end-of-input
+ ^ unexpected ')', ignoring it
+
diff --git a/test/prism/errors/not_without_parens_command.txt b/test/prism/errors/not_without_parens_command.txt
new file mode 100644
index 0000000000..957a06f8f1
--- /dev/null
+++ b/test/prism/errors/not_without_parens_command.txt
@@ -0,0 +1,4 @@
+foo not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/not_without_parens_command_call.txt b/test/prism/errors/not_without_parens_command_call.txt
new file mode 100644
index 0000000000..564833c7de
--- /dev/null
+++ b/test/prism/errors/not_without_parens_command_call.txt
@@ -0,0 +1,4 @@
+a.b not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/not_without_parens_return.txt b/test/prism/errors/not_without_parens_return.txt
new file mode 100644
index 0000000000..1c7edb6ff1
--- /dev/null
+++ b/test/prism/errors/not_without_parens_return.txt
@@ -0,0 +1,4 @@
+return not y
+ ^ expected a `(` after `not`
+ ^ unexpected local variable or method, expecting end-of-input
+
diff --git a/test/prism/errors/pattern-capture-in-alt-array.txt b/test/prism/errors/pattern-capture-in-alt-array.txt
new file mode 100644
index 0000000000..5cb59fa328
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-array.txt
@@ -0,0 +1,4 @@
+1 => [a, b] | 2
+ ^ variable capture in alternative pattern
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern-capture-in-alt-hash.txt b/test/prism/errors/pattern-capture-in-alt-hash.txt
new file mode 100644
index 0000000000..150b3baecc
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-hash.txt
@@ -0,0 +1,3 @@
+1 => { a: b } | 2
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern-capture-in-alt-name.txt b/test/prism/errors/pattern-capture-in-alt-name.txt
new file mode 100644
index 0000000000..cbf2bae85f
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-name.txt
@@ -0,0 +1,3 @@
+1 => (2 => b) | 2
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern-capture-in-alt-top.txt b/test/prism/errors/pattern-capture-in-alt-top.txt
new file mode 100644
index 0000000000..bdf3a7f637
--- /dev/null
+++ b/test/prism/errors/pattern-capture-in-alt-top.txt
@@ -0,0 +1,4 @@
+1 => a | b
+ ^ variable capture in alternative pattern
+ ^ variable capture in alternative pattern
+
diff --git a/test/prism/errors/pattern_arithmetic_expressions.txt b/test/prism/errors/pattern_arithmetic_expressions.txt
new file mode 100644
index 0000000000..cfb3650531
--- /dev/null
+++ b/test/prism/errors/pattern_arithmetic_expressions.txt
@@ -0,0 +1,3 @@
+case 1; in -1**2; end
+ ^~~~~ expected a pattern expression after the `in` keyword
+
diff --git a/test/prism/errors/pattern_match_implicit_rest.txt b/test/prism/errors/pattern_match_implicit_rest.txt
new file mode 100644
index 0000000000..8602c0add0
--- /dev/null
+++ b/test/prism/errors/pattern_match_implicit_rest.txt
@@ -0,0 +1,3 @@
+a=>b, *,
+ ^ expected a pattern expression after `,`
+
diff --git a/test/prism/errors/pattern_string_key.txt b/test/prism/errors/pattern_string_key.txt
new file mode 100644
index 0000000000..41bc1fa57b
--- /dev/null
+++ b/test/prism/errors/pattern_string_key.txt
@@ -0,0 +1,8 @@
+case:a
+^~~~ expected an `end` to close the `case` statement
+in b:"","#{}"
+ ^~~~~ expected a label after the `,` in the hash pattern
+ ^ expected a pattern expression after the key
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/rescue_pattern.txt b/test/prism/errors/rescue_pattern.txt
new file mode 100644
index 0000000000..c85feb27bd
--- /dev/null
+++ b/test/prism/errors/rescue_pattern.txt
@@ -0,0 +1,4 @@
+a rescue b => c in d
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/test/prism/errors/shadow_args_in_lambda.txt b/test/prism/errors/shadow_args_in_lambda.txt
index 2399a0ebd5..7fc78d7d8f 100644
--- a/test/prism/errors/shadow_args_in_lambda.txt
+++ b/test/prism/errors/shadow_args_in_lambda.txt
@@ -1,5 +1,5 @@
->a;b{}
^ expected a `do` keyword or a `{` to open the lambda block
^ unexpected end-of-input, assuming it is closing the parent top level context
- ^ expected a lambda block beginning with `do` to end with `end`
+^~ expected a lambda block beginning with `do` to end with `end`
diff --git a/test/prism/errors/singleton_method_for_literals.txt b/test/prism/errors/singleton_method_for_literals.txt
index 6247b4f025..ae850fca29 100644
--- a/test/prism/errors/singleton_method_for_literals.txt
+++ b/test/prism/errors/singleton_method_for_literals.txt
@@ -2,8 +2,6 @@ def (1).g; end
^ cannot define singleton method for literals
def ((a; 1)).foo; end
^ cannot define singleton method for literals
-def ((return; 1)).bar; end
- ^ cannot define singleton method for literals
def (((1))).foo; end
^ cannot define singleton method for literals
def (__FILE__).foo; end
diff --git a/test/prism/errors/unterminated_begin.txt b/test/prism/errors/unterminated_begin.txt
new file mode 100644
index 0000000000..2733f830c9
--- /dev/null
+++ b/test/prism/errors/unterminated_begin.txt
@@ -0,0 +1,4 @@
+begin
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `begin` statement
+
diff --git a/test/prism/errors/unterminated_begin_upcase.txt b/test/prism/errors/unterminated_begin_upcase.txt
new file mode 100644
index 0000000000..5512f2089e
--- /dev/null
+++ b/test/prism/errors/unterminated_begin_upcase.txt
@@ -0,0 +1,4 @@
+BEGIN {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the `BEGIN` statement
+
diff --git a/test/prism/errors/unterminated_block.txt b/test/prism/errors/unterminated_block.txt
index 8cc772db16..db6a4aa56c 100644
--- a/test/prism/errors/unterminated_block.txt
+++ b/test/prism/errors/unterminated_block.txt
@@ -1,4 +1,4 @@
foo {
^ unexpected end-of-input, assuming it is closing the parent top level context
- ^ expected a block beginning with `{` to end with `}`
+ ^ expected a block beginning with `{` to end with `}`
diff --git a/test/prism/errors/unterminated_block_do_end.txt b/test/prism/errors/unterminated_block_do_end.txt
new file mode 100644
index 0000000000..0b7c64965f
--- /dev/null
+++ b/test/prism/errors/unterminated_block_do_end.txt
@@ -0,0 +1,4 @@
+foo do
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^~ expected a block beginning with `do` to end with `end`
+
diff --git a/test/prism/errors/unterminated_class.txt b/test/prism/errors/unterminated_class.txt
new file mode 100644
index 0000000000..f47a3aa7df
--- /dev/null
+++ b/test/prism/errors/unterminated_class.txt
@@ -0,0 +1,4 @@
+class Foo
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `class` statement
+
diff --git a/test/prism/errors/unterminated_def.txt b/test/prism/errors/unterminated_def.txt
new file mode 100644
index 0000000000..a6212e3a21
--- /dev/null
+++ b/test/prism/errors/unterminated_def.txt
@@ -0,0 +1,5 @@
+def foo
+ ^ expected a delimiter to close the parameters
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~ expected an `end` to close the `def` statement
+
diff --git a/test/prism/errors/unterminated_end_upcase.txt b/test/prism/errors/unterminated_end_upcase.txt
new file mode 100644
index 0000000000..ef01caa0ca
--- /dev/null
+++ b/test/prism/errors/unterminated_end_upcase.txt
@@ -0,0 +1,4 @@
+END {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the `END` statement
+
diff --git a/test/prism/errors/unterminated_for.txt b/test/prism/errors/unterminated_for.txt
new file mode 100644
index 0000000000..75978a7cae
--- /dev/null
+++ b/test/prism/errors/unterminated_for.txt
@@ -0,0 +1,5 @@
+for x in y
+ ^ unexpected end-of-input; expected a 'do', newline, or ';' after the 'for' loop collection
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~ expected an `end` to close the `for` loop
+
diff --git a/test/prism/errors/unterminated_heredoc_and_embexpr.txt b/test/prism/errors/unterminated_heredoc_and_embexpr.txt
new file mode 100644
index 0000000000..bed7fcd24e
--- /dev/null
+++ b/test/prism/errors/unterminated_heredoc_and_embexpr.txt
@@ -0,0 +1,11 @@
+<<A+B
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+ ^ unexpected '+', ignoring it
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+#{C
+ ^ unexpected heredoc ending; expected an argument
+ ^ unexpected heredoc ending, expecting end-of-input
+ ^ unexpected heredoc ending, ignoring it
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^ expected a `}` to close the embedded expression
+
diff --git a/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt b/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt
new file mode 100644
index 0000000000..a03ff1d212
--- /dev/null
+++ b/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt
@@ -0,0 +1,9 @@
+<<A+B
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+#{C + "#{"}
+ ^ unterminated string meets end of file
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the embedded expression
+ ^ unterminated string; expected a closing delimiter for the interpolated string
+ ^ expected a `}` to close the embedded expression
+
diff --git a/test/prism/errors/unterminated_if.txt b/test/prism/errors/unterminated_if.txt
new file mode 100644
index 0000000000..1697931773
--- /dev/null
+++ b/test/prism/errors/unterminated_if.txt
@@ -0,0 +1,5 @@
+if true
+ ^ expected `then` or `;` or '\n'
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~ expected an `end` to close the conditional clause
+
diff --git a/test/prism/errors/unterminated_if_else.txt b/test/prism/errors/unterminated_if_else.txt
new file mode 100644
index 0000000000..db7828cce8
--- /dev/null
+++ b/test/prism/errors/unterminated_if_else.txt
@@ -0,0 +1,5 @@
+if true
+^~ expected an `end` to close the `else` clause
+else
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_lambda_brace.txt b/test/prism/errors/unterminated_lambda_brace.txt
new file mode 100644
index 0000000000..75474c7534
--- /dev/null
+++ b/test/prism/errors/unterminated_lambda_brace.txt
@@ -0,0 +1,4 @@
+-> {
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a lambda block beginning with `{` to end with `}`
+
diff --git a/test/prism/errors/unterminated_module.txt b/test/prism/errors/unterminated_module.txt
new file mode 100644
index 0000000000..4c50ba5f63
--- /dev/null
+++ b/test/prism/errors/unterminated_module.txt
@@ -0,0 +1,4 @@
+module Foo
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~~ expected an `end` to close the `module` statement
+
diff --git a/test/prism/errors/unterminated_pattern_bracket.txt b/test/prism/errors/unterminated_pattern_bracket.txt
new file mode 100644
index 0000000000..4f35cd84af
--- /dev/null
+++ b/test/prism/errors/unterminated_pattern_bracket.txt
@@ -0,0 +1,7 @@
+case x
+^~~~ expected an `end` to close the `case` statement
+in [1
+ ^ expected a `]` to close the pattern expression
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_pattern_paren.txt b/test/prism/errors/unterminated_pattern_paren.txt
new file mode 100644
index 0000000000..426d614e61
--- /dev/null
+++ b/test/prism/errors/unterminated_pattern_paren.txt
@@ -0,0 +1,7 @@
+case x
+^~~~ expected an `end` to close the `case` statement
+in (1
+ ^ expected a `)` to close the pattern expression
+ ^ expected a delimiter after the patterns of an `in` clause
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+
diff --git a/test/prism/errors/unterminated_until.txt b/test/prism/errors/unterminated_until.txt
new file mode 100644
index 0000000000..42a0545200
--- /dev/null
+++ b/test/prism/errors/unterminated_until.txt
@@ -0,0 +1,5 @@
+until true
+ ^ expected a predicate expression for the `until` statement
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^~~~~ expected an `end` to close the `until` statement
+
diff --git a/test/prism/errors/void_value_expression_in_begin_statement.txt b/test/prism/errors/void_value_expression_in_begin_statement.txt
index aa8f1ded96..fb968a12e1 100644
--- a/test/prism/errors/void_value_expression_in_begin_statement.txt
+++ b/test/prism/errors/void_value_expression_in_begin_statement.txt
@@ -14,8 +14,6 @@ x = begin return ensure return end
^~~~~~ unexpected void value expression
x = begin return; rescue; return end
^~~~~~ unexpected void value expression
-x = begin return; rescue; return; else return end
- ^~~~~~ unexpected void value expression
x = begin; return; rescue; retry; end
^~~~~~ unexpected void value expression
diff --git a/test/prism/errors/while_endless_method.txt b/test/prism/errors/while_endless_method.txt
index 6f062d89d0..cdd7ba9aba 100644
--- a/test/prism/errors/while_endless_method.txt
+++ b/test/prism/errors/while_endless_method.txt
@@ -1,5 +1,5 @@
while def f = g do end
^ expected a predicate expression for the `while` statement
^ unexpected end-of-input, assuming it is closing the parent top level context
- ^ expected an `end` to close the `while` statement
+^~~~~ expected an `end` to close the `while` statement
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 62bbd8458b..9dd7fbe3fe 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -1,41 +1,24 @@
# frozen_string_literal: true
+return if RUBY_VERSION < "3.3.0"
+
require_relative "test_helper"
module Prism
class ErrorsTest < TestCase
base = File.expand_path("errors", __dir__)
- filepaths = Dir["*.txt", base: base]
-
- if RUBY_VERSION < "3.0"
- filepaths -= [
- "cannot_assign_to_a_reserved_numbered_parameter.txt",
- "writing_numbered_parameter.txt",
- "targeting_numbered_parameter.txt",
- "defining_numbered_parameter.txt",
- "defining_numbered_parameter_2.txt",
- "numbered_parameters_in_block_arguments.txt",
- "numbered_and_write.txt",
- "numbered_or_write.txt",
- "numbered_operator_write.txt"
- ]
- end
+ filepaths = Dir[ENV.fetch("FOCUS", "**/*.txt"), base: base]
- if RUBY_VERSION < "3.4"
- filepaths -= [
- "it_with_ordinary_parameter.txt",
- "block_args_in_array_assignment.txt",
- "keyword_args_in_array_assignment.txt"
- ]
- end
-
- if RUBY_VERSION < "3.4" || RUBY_RELEASE_DATE < "2024-07-24"
- filepaths -= ["dont_allow_return_inside_sclass_body.txt"]
- end
+ PARSE_Y_EXCLUDES = [
+ # https://bugs.ruby-lang.org/issues/20409
+ "#{base}/4.1/end_block_exit.txt"
+ ]
filepaths.each do |filepath|
- define_method(:"test_#{File.basename(filepath, ".txt")}") do
- assert_errors(File.join(base, filepath))
+ ruby_versions_for(filepath).each do |version|
+ define_method(:"test_#{version}_#{File.basename(filepath, ".txt")}") do
+ assert_errors(File.join(base, filepath), version)
+ end
end
end
@@ -67,52 +50,85 @@ module Prism
def test_unterminated_string_closing
statement = Prism.parse_statement("'hello")
assert_equal statement.unescaped, "hello"
- assert_empty statement.closing
+ assert_nil statement.closing
end
def test_unterminated_interpolated_string_closing
statement = Prism.parse_statement('"hello')
assert_equal statement.unescaped, "hello"
- assert_empty statement.closing
+ assert_nil statement.closing
end
def test_unterminated_empty_string_closing
statement = Prism.parse_statement('"')
assert_empty statement.unescaped
- assert_empty statement.closing
+ assert_nil statement.closing
end
- def test_invalid_message_name
- assert_equal :"", Prism.parse_statement("+.@foo,+=foo").write_name
+ def test_regexp_encoding_option_mismatch_error
+ # UTF-8 char with ASCII-8BIT modifier
+ result = Prism.parse('/Ȃ/n')
+ assert_includes result.errors.map(&:type), :regexp_encoding_option_mismatch
+
+ # UTF-8 char with EUC-JP modifier
+ result = Prism.parse('/Ȃ/e')
+ assert_includes result.errors.map(&:type), :regexp_encoding_option_mismatch
+
+ # UTF-8 char with Windows-31J modifier
+ result = Prism.parse('/Ȃ/s')
+ assert_includes result.errors.map(&:type), :regexp_encoding_option_mismatch
+
+ # UTF-8 char with UTF-8 modifier
+ result = Prism.parse('/Ȃ/u')
+ assert_empty result.errors
end
- def test_circular_parameters
- source = <<~RUBY
- def foo(bar = bar) = 42
- def foo(bar: bar) = 42
- proc { |foo = foo| }
- proc { |foo: foo| }
- RUBY
+ def test_incomplete_def_closing_loc
+ statement = Prism.parse_statement("def f; 123")
+ assert_nil(statement.end_keyword)
+ end
- source.each_line do |line|
- assert_predicate Prism.parse(line, version: "3.3.0"), :failure?
- assert_predicate Prism.parse(line), :success?
- end
+ def test_unclosed_interpolation
+ statement = Prism.parse_statement("\"\#{")
+ assert_equal('"', statement.opening)
+ assert_nil(statement.closing)
+
+ assert_equal(1, statement.parts.count)
+ assert_equal('#{', statement.parts[0].opening)
+ assert_equal("", statement.parts[0].closing)
+ assert_nil(statement.parts[0].statements)
+ end
+
+ def test_unclosed_heredoc_and_interpolation
+ statement = Prism.parse_statement("<<D\n\#{")
+ assert_equal("<<D", statement.opening)
+ assert_nil(statement.closing)
+
+ assert_equal(1, statement.parts.count)
+ assert_equal('#{', statement.parts[0].opening)
+ assert_equal("", statement.parts[0].closing)
+ assert_nil(statement.parts[0].statements)
end
private
- def assert_errors(filepath)
+ def assert_errors(filepath, version)
expected = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8)
source = expected.lines.grep_v(/^\s*\^/).join.gsub(/\n*\z/, "")
- refute_valid_syntax(source)
+ if CURRENT_MAJOR_MINOR == version && !PARSE_Y_EXCLUDES.include?(filepath)
+ refute_valid_syntax(source)
+ end
- result = Prism.parse(source)
+ result = Prism.parse(source, version: version)
errors = result.errors
refute_empty errors, "Expected errors in #{filepath}"
actual = result.errors_format
+ if expected != actual && ENV["UPDATE_SNAPSHOTS"]
+ File.write(filepath, actual)
+ end
+
assert_equal expected, actual, "Expected errors to match for #{filepath}"
end
end
diff --git a/test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt b/test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt
new file mode 100644
index 0000000000..6d6b052681
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/block_args_in_array_assignment.txt
@@ -0,0 +1 @@
+matrix[5, &block] = 8
diff --git a/test/prism/fixtures/3.3-3.3/it.txt b/test/prism/fixtures/3.3-3.3/it.txt
new file mode 100644
index 0000000000..5410b01e71
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/it.txt
@@ -0,0 +1,5 @@
+x do
+ it
+end
+
+-> { it }
diff --git a/test/prism/fixtures/it_indirect_writes.txt b/test/prism/fixtures/3.3-3.3/it_indirect_writes.txt
index bb87e9483e..bb87e9483e 100644
--- a/test/prism/fixtures/it_indirect_writes.txt
+++ b/test/prism/fixtures/3.3-3.3/it_indirect_writes.txt
diff --git a/test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt b/test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt
new file mode 100644
index 0000000000..2cceeb2a54
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/it_read_and_assignment.txt
@@ -0,0 +1 @@
+42.tap { p it; it = it; p it }
diff --git a/test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt b/test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt
new file mode 100644
index 0000000000..178b641e6b
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/it_with_ordinary_parameter.txt
@@ -0,0 +1 @@
+proc { || it }
diff --git a/test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt b/test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt
new file mode 100644
index 0000000000..88016c2afe
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/keyword_args_in_array_assignment.txt
@@ -0,0 +1 @@
+matrix[5, axis: :y] = 8
diff --git a/test/prism/fixtures/3.3-3.3/return_in_sclass.txt b/test/prism/fixtures/3.3-3.3/return_in_sclass.txt
new file mode 100644
index 0000000000..f1fde5771a
--- /dev/null
+++ b/test/prism/fixtures/3.3-3.3/return_in_sclass.txt
@@ -0,0 +1 @@
+class << A; return; end
diff --git a/test/prism/fixtures/3.3-4.0/end_block_exit.txt b/test/prism/fixtures/3.3-4.0/end_block_exit.txt
new file mode 100644
index 0000000000..8ebf0d6369
--- /dev/null
+++ b/test/prism/fixtures/3.3-4.0/end_block_exit.txt
@@ -0,0 +1,11 @@
+END {
+ return
+}
+
+END {
+ break
+}
+
+END {
+ next
+}
diff --git a/test/prism/fixtures/3.3-4.0/void_value.txt b/test/prism/fixtures/3.3-4.0/void_value.txt
new file mode 100644
index 0000000000..bfb8eff09c
--- /dev/null
+++ b/test/prism/fixtures/3.3-4.0/void_value.txt
@@ -0,0 +1,29 @@
+x = begin
+ foo
+rescue
+ return
+else
+ return
+end
+
+x = case
+ when 1 then return
+ else return
+end
+
+x = case 1
+ in 2 then return
+ else return
+end
+
+x = begin
+ return
+ "NG"
+end
+
+x = if rand < 0.5
+ return
+ "NG"
+else
+ return
+end
diff --git a/test/prism/fixtures/3.4/circular_parameters.txt b/test/prism/fixtures/3.4/circular_parameters.txt
new file mode 100644
index 0000000000..11537023ad
--- /dev/null
+++ b/test/prism/fixtures/3.4/circular_parameters.txt
@@ -0,0 +1,4 @@
+def foo(bar = bar) = 42
+def foo(bar: bar) = 42
+proc { |foo = foo| }
+proc { |foo: foo| }
diff --git a/test/prism/fixtures/3.4/it.txt b/test/prism/fixtures/3.4/it.txt
new file mode 100644
index 0000000000..5410b01e71
--- /dev/null
+++ b/test/prism/fixtures/3.4/it.txt
@@ -0,0 +1,5 @@
+x do
+ it
+end
+
+-> { it }
diff --git a/test/prism/fixtures/3.4/it_indirect_writes.txt b/test/prism/fixtures/3.4/it_indirect_writes.txt
new file mode 100644
index 0000000000..bb87e9483e
--- /dev/null
+++ b/test/prism/fixtures/3.4/it_indirect_writes.txt
@@ -0,0 +1,23 @@
+tap { it += 1 }
+
+tap { it ||= 1 }
+
+tap { it &&= 1 }
+
+tap { it; it += 1 }
+
+tap { it; it ||= 1 }
+
+tap { it; it &&= 1 }
+
+tap { it += 1; it }
+
+tap { it ||= 1; it }
+
+tap { it &&= 1; it }
+
+tap { it; it += 1; it }
+
+tap { it; it ||= 1; it }
+
+tap { it; it &&= 1; it }
diff --git a/test/prism/fixtures/3.4/it_read_and_assignment.txt b/test/prism/fixtures/3.4/it_read_and_assignment.txt
new file mode 100644
index 0000000000..2cceeb2a54
--- /dev/null
+++ b/test/prism/fixtures/3.4/it_read_and_assignment.txt
@@ -0,0 +1 @@
+42.tap { p it; it = it; p it }
diff --git a/test/prism/fixtures/4.0/endless_methods_command_call.txt b/test/prism/fixtures/4.0/endless_methods_command_call.txt
new file mode 100644
index 0000000000..146a6ee579
--- /dev/null
+++ b/test/prism/fixtures/4.0/endless_methods_command_call.txt
@@ -0,0 +1,11 @@
+private def foo = puts "Hello"
+private def foo = puts "Hello", "World"
+private def foo = puts "Hello" do expr end
+private def foo() = puts "Hello"
+private def foo(x) = puts x
+private def obj.foo = puts "Hello"
+private def obj.foo() = puts "Hello"
+private def obj.foo(x) = puts x
+
+private def foo = bar baz
+private def foo = bar baz do expr end
diff --git a/test/prism/fixtures/4.0/leading_logical.txt b/test/prism/fixtures/4.0/leading_logical.txt
new file mode 100644
index 0000000000..ee87e00d4f
--- /dev/null
+++ b/test/prism/fixtures/4.0/leading_logical.txt
@@ -0,0 +1,16 @@
+1
+&& 2
+&& 3
+
+1
+|| 2
+|| 3
+
+1
+and 2
+and 3
+
+1
+or 2
+or 3
+
diff --git a/test/prism/fixtures/4.1/noblock.txt b/test/prism/fixtures/4.1/noblock.txt
new file mode 100644
index 0000000000..2395393e22
--- /dev/null
+++ b/test/prism/fixtures/4.1/noblock.txt
@@ -0,0 +1,4 @@
+def foo(&nil)
+end
+
+-> (&nil) {}
diff --git a/test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt b/test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt
new file mode 100644
index 0000000000..ef1385d973
--- /dev/null
+++ b/test/prism/fixtures/4.1/trailing_comma_after_method_arguments.txt
@@ -0,0 +1,15 @@
+def foo(a,b,c,);end
+
+def foo(a,b,*c,);end
+
+def foo(a,b,*,);end
+
+def foo(a,b,**c,);end
+
+def foo(a,b,**,);end
+
+def foo(
+ a,
+ b,
+ c,
+);end
diff --git a/test/prism/fixtures/4.1/void_value.txt b/test/prism/fixtures/4.1/void_value.txt
new file mode 100644
index 0000000000..915112d623
--- /dev/null
+++ b/test/prism/fixtures/4.1/void_value.txt
@@ -0,0 +1,7 @@
+x = begin
+ return
+rescue
+ "OK"
+else
+ return
+end
diff --git a/test/prism/fixtures/__END__.txt b/test/prism/fixtures/__END__.txt
new file mode 100644
index 0000000000..c0f4f28004
--- /dev/null
+++ b/test/prism/fixtures/__END__.txt
@@ -0,0 +1,3 @@
+foo
+__END__
+Available in DATA constant
diff --git a/test/prism/fixtures/and_or_with_suffix.txt b/test/prism/fixtures/and_or_with_suffix.txt
new file mode 100644
index 0000000000..59ee4d0b88
--- /dev/null
+++ b/test/prism/fixtures/and_or_with_suffix.txt
@@ -0,0 +1,17 @@
+foo
+and?
+
+foo
+or?
+
+foo
+and!
+
+foo
+or!
+
+foo
+andbar
+
+foo
+orbar
diff --git a/test/prism/fixtures/blocks.txt b/test/prism/fixtures/blocks.txt
index e33d95c150..51ec84950c 100644
--- a/test/prism/fixtures/blocks.txt
+++ b/test/prism/fixtures/blocks.txt
@@ -52,3 +52,11 @@ foo lambda { |
}
foo do |bar,| end
+
+foo bar baz, qux do end
+
+foo.bar baz do end
+
+foo.bar baz do end.qux quux do end
+
+foo bar, baz do |x| x end
diff --git a/test/prism/fixtures/bom_leading_space.txt b/test/prism/fixtures/bom_leading_space.txt
new file mode 100644
index 0000000000..48d3ee50ea
--- /dev/null
+++ b/test/prism/fixtures/bom_leading_space.txt
@@ -0,0 +1 @@
+ p (42)
diff --git a/test/prism/fixtures/bom_spaces.txt b/test/prism/fixtures/bom_spaces.txt
new file mode 100644
index 0000000000..c18ad4c21a
--- /dev/null
+++ b/test/prism/fixtures/bom_spaces.txt
@@ -0,0 +1 @@
+p ( 42 )
diff --git a/test/prism/fixtures/break.txt b/test/prism/fixtures/break.txt
index 5532322c5c..d823f866df 100644
--- a/test/prism/fixtures/break.txt
+++ b/test/prism/fixtures/break.txt
@@ -20,6 +20,10 @@ tap { break() }
tap { break(1) }
+tap { (break 1) }
+
+tap { foo && (break 1) }
+
foo { break 42 } == 42
foo { |a| break } == 42
diff --git a/test/prism/fixtures/case_in_hash_key.txt b/test/prism/fixtures/case_in_hash_key.txt
new file mode 100644
index 0000000000..75ac8a846f
--- /dev/null
+++ b/test/prism/fixtures/case_in_hash_key.txt
@@ -0,0 +1,6 @@
+case 1
+in 2
+ A.print message:
+in 3
+ A.print message:
+end
diff --git a/test/prism/fixtures/case_in_in.txt b/test/prism/fixtures/case_in_in.txt
new file mode 100644
index 0000000000..a5f9e4ec41
--- /dev/null
+++ b/test/prism/fixtures/case_in_in.txt
@@ -0,0 +1,4 @@
+case args
+in [event]
+ context.event in ^event
+end
diff --git a/test/prism/fixtures/character_literal.txt b/test/prism/fixtures/character_literal.txt
new file mode 100644
index 0000000000..920332123f
--- /dev/null
+++ b/test/prism/fixtures/character_literal.txt
@@ -0,0 +1,2 @@
+# encoding: Windows-31J
+p ?\u3042""
diff --git a/test/prism/fixtures/command_method_call_2.txt b/test/prism/fixtures/command_method_call_2.txt
new file mode 100644
index 0000000000..8bd40cff9e
--- /dev/null
+++ b/test/prism/fixtures/command_method_call_2.txt
@@ -0,0 +1 @@
+foo(bar baz, bat)
diff --git a/test/prism/fixtures/command_method_call_3.txt b/test/prism/fixtures/command_method_call_3.txt
new file mode 100644
index 0000000000..6de0446aa9
--- /dev/null
+++ b/test/prism/fixtures/command_method_call_3.txt
@@ -0,0 +1,19 @@
+foo(bar 1, key => '2')
+
+foo(bar 1, KEY => '2')
+
+foo(bar 1, :key => '2')
+
+foo(bar 1, { baz: :bat } => '2')
+
+foo bar - %i[baz] => '2'
+
+foo(bar {} => '2')
+
+foo(bar baz {} => '2')
+
+foo(bar do end => '2')
+
+foo(1, bar {} => '2')
+
+foo(1, bar do end => '2')
diff --git a/test/prism/fixtures/endless_method_as_default_arg.txt b/test/prism/fixtures/endless_method_as_default_arg.txt
new file mode 100644
index 0000000000..0063d9a8fa
--- /dev/null
+++ b/test/prism/fixtures/endless_method_as_default_arg.txt
@@ -0,0 +1,11 @@
+def foo(a = def f = 1); end
+
+def foo(a = def f = 1, b); end
+
+def foo(b, a = def f = 1); end
+
+def foo(a: def f = 1); end
+
+def foo(a = def f = 1+2); end
+
+->(a = def f = 1) {}
diff --git a/test/prism/fixtures/endless_methods.txt b/test/prism/fixtures/endless_methods.txt
index 8c2f2a30cc..6e0488a5ee 100644
--- a/test/prism/fixtures/endless_methods.txt
+++ b/test/prism/fixtures/endless_methods.txt
@@ -3,3 +3,9 @@ def foo = 1
def bar = A ""
def method = 1 + 2 + 3
+
+x = def f = p 1
+
+def foo = bar baz
+
+def foo = bar(baz)
diff --git a/test/prism/fixtures/escaped_newline_with_trailing_content.txt b/test/prism/fixtures/escaped_newline_with_trailing_content.txt
new file mode 100644
index 0000000000..fe947a3f10
--- /dev/null
+++ b/test/prism/fixtures/escaped_newline_with_trailing_content.txt
@@ -0,0 +1,2 @@
+"A
+B\nCC"
diff --git a/test/prism/fixtures/heredoc_dedent_line_continuation.txt b/test/prism/fixtures/heredoc_dedent_line_continuation.txt
new file mode 100644
index 0000000000..661db490c7
--- /dev/null
+++ b/test/prism/fixtures/heredoc_dedent_line_continuation.txt
@@ -0,0 +1,5 @@
+<<~FOO
+ foo\
+ \
+ bar
+FOO
diff --git a/test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt b/test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt
new file mode 100644
index 0000000000..dbfa0bf4b4
--- /dev/null
+++ b/test/prism/fixtures/heredoc_percent_q_newline_delimiter.txt
@@ -0,0 +1,22 @@
+%Q
+#{<<B}
+B
+
+%
+#{<<B}
+B
+
+<<A; %Q
+A
+#{<<B}
+B
+
+<<A; %
+A
+#{<<B}
+B
+
+# \r\n
+%Q
+#{<<B}
+B
diff --git a/test/prism/fixtures/it.txt b/test/prism/fixtures/it.txt
deleted file mode 100644
index 76deb68028..0000000000
--- a/test/prism/fixtures/it.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-x do
- it
-end
diff --git a/test/prism/fixtures/it_assignment.txt b/test/prism/fixtures/it_assignment.txt
new file mode 100644
index 0000000000..523b0ffe1e
--- /dev/null
+++ b/test/prism/fixtures/it_assignment.txt
@@ -0,0 +1 @@
+42.tap { it = it; p it }
diff --git a/test/prism/fixtures/next.txt b/test/prism/fixtures/next.txt
index 2ef14c6304..0d2d6a11f5 100644
--- a/test/prism/fixtures/next.txt
+++ b/test/prism/fixtures/next.txt
@@ -22,3 +22,7 @@ tap { next
tap { next() }
tap { next(1) }
+
+tap { (next 1) }
+
+tap { foo && (next 1) }
diff --git a/test/prism/fixtures/non_void_value.txt b/test/prism/fixtures/non_void_value.txt
new file mode 100644
index 0000000000..388e9f2574
--- /dev/null
+++ b/test/prism/fixtures/non_void_value.txt
@@ -0,0 +1,31 @@
+x = begin
+ return if true
+ "conditional"
+end
+
+x = if rand < 0.5
+ return
+ "else is nil"
+end
+
+x = if true
+ return if true
+ "conditional"
+else
+ return
+end
+
+x = if true
+ return if true
+else
+ return if true
+ "conditional"
+end
+
+x = case
+ when 1
+ return if true
+ "conditional"
+ else
+ return
+end
diff --git a/test/prism/fixtures/patterns.txt b/test/prism/fixtures/patterns.txt
index 09584e43eb..449dac619b 100644
--- a/test/prism/fixtures/patterns.txt
+++ b/test/prism/fixtures/patterns.txt
@@ -218,3 +218,7 @@ a in b, and c
a in b, or c
(a in b,) and c
(a in b,) or c
+
+x => ^([*a.x])
+x => ^([**a.x])
+x => ^({ a: })
diff --git a/test/prism/fixtures/rescue.txt b/test/prism/fixtures/rescue.txt
index 99170fbe0f..f436463029 100644
--- a/test/prism/fixtures/rescue.txt
+++ b/test/prism/fixtures/rescue.txt
@@ -33,3 +33,7 @@ end
foo if bar rescue baz
z = x y rescue c d
+
+begin
+rescue => A[]
+end
diff --git a/test/prism/fixtures/return.txt b/test/prism/fixtures/return.txt
index a8b5b95fab..952fb80da8 100644
--- a/test/prism/fixtures/return.txt
+++ b/test/prism/fixtures/return.txt
@@ -22,3 +22,6 @@ return()
return(1)
+(return 1)
+
+foo && (return 1)
diff --git a/test/prism/fixtures/string_concatination_frozen_false.txt b/test/prism/fixtures/string_concatination_frozen_false.txt
new file mode 100644
index 0000000000..abe9301408
--- /dev/null
+++ b/test/prism/fixtures/string_concatination_frozen_false.txt
@@ -0,0 +1,5 @@
+# frozen_string_literal: false
+
+'foo' 'bar'
+
+'foo' 'bar' "baz#{bat}"
diff --git a/test/prism/fixtures/string_concatination_frozen_true.txt b/test/prism/fixtures/string_concatination_frozen_true.txt
new file mode 100644
index 0000000000..829777f0a7
--- /dev/null
+++ b/test/prism/fixtures/string_concatination_frozen_true.txt
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+'foo' 'bar'
+
+'foo' 'bar' "baz#{bat}"
diff --git a/test/prism/fixtures/strings.txt b/test/prism/fixtures/strings.txt
index 0787152786..1419f975b7 100644
--- a/test/prism/fixtures/strings.txt
+++ b/test/prism/fixtures/strings.txt
@@ -99,6 +99,34 @@ bar)
d
]
+%w[
+ foo\nbar baz\n\n\
+ bat\n\\\n\foo
+]
+
+%W[
+ foo\nbar baz\n\n\
+ bat\n\\\n\foo
+]
+
+%w[foo\
+ bar
+ baz\\
+ bat
+ 1\n
+ 2
+ 3\\n
+]
+
+%W[foo\
+ bar
+ baz\\
+ bat
+ 1\n
+ 2
+ 3\\n
+]
+
%W[f\u{006f 006f}]
%W[a b#{c}d e]
@@ -146,6 +174,10 @@ baz
%Q{abc}
+%Q(\«)
+
+%q(\«)
+
%^#$^#
%@#@#
diff --git a/test/prism/fixtures/unary_method_calls.txt b/test/prism/fixtures/unary_method_calls.txt
new file mode 100644
index 0000000000..a8327d23cc
--- /dev/null
+++ b/test/prism/fixtures/unary_method_calls.txt
@@ -0,0 +1,8 @@
+42.~@
+42.!@
+
+-
+42
+
++
+42
diff --git a/test/prism/fixtures/write_command_operator.txt b/test/prism/fixtures/write_command_operator.txt
new file mode 100644
index 0000000000..d719d24f87
--- /dev/null
+++ b/test/prism/fixtures/write_command_operator.txt
@@ -0,0 +1,3 @@
+foo = 123 | '456' or return
+
+foo = 123 | '456' in BAR
diff --git a/test/prism/fixtures_test.rb b/test/prism/fixtures_test.rb
index 3b4a502b90..dcbcb7c117 100644
--- a/test/prism/fixtures_test.rb
+++ b/test/prism/fixtures_test.rb
@@ -8,7 +8,6 @@ module Prism
class FixturesTest < TestCase
except = []
-
if RUBY_VERSION < "3.3.0"
# Ruby < 3.3.0 cannot parse heredocs where there are leading whitespace
# characters in the heredoc start.
@@ -25,7 +24,14 @@ module Prism
except << "whitequark/ruby_bug_19281.txt"
end
- Fixture.each(except: except) do |fixture|
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ except << "command_method_call_2.txt"
+ # https://bugs.ruby-lang.org/issues/21669
+ except << "4.1/void_value.txt"
+ # https://bugs.ruby-lang.org/issues/19107
+ except << "4.1/trailing_comma_after_method_arguments.txt"
+
+ Fixture.each_for_current_ruby(except: except) do |fixture|
define_method(fixture.test_name) { assert_valid_syntax(fixture.read) }
end
end
diff --git a/test/prism/lex_test.rb b/test/prism/lex_test.rb
index 2786c45a22..1e06d52184 100644
--- a/test/prism/lex_test.rb
+++ b/test/prism/lex_test.rb
@@ -3,49 +3,10 @@
return if !(RUBY_ENGINE == "ruby" && RUBY_VERSION >= "3.2.0")
require_relative "test_helper"
+require "ripper"
module Prism
class LexTest < TestCase
- except = [
- # It seems like there are some oddities with nested heredocs and ripper.
- # Waiting for feedback on https://bugs.ruby-lang.org/issues/19838.
- "seattlerb/heredoc_nested.txt",
- "whitequark/dedenting_heredoc.txt",
- # Ripper seems to have a bug that the regex portions before and after
- # the heredoc are combined into a single token. See
- # https://bugs.ruby-lang.org/issues/19838.
- "spanning_heredoc.txt",
- "spanning_heredoc_newlines.txt",
- # Prism emits a single :on_tstring_content in <<- style heredocs when there
- # is a line continuation preceeded by escaped backslashes. It should emit two, same
- # as if the backslashes are not present.
- "heredocs_with_fake_newlines.txt",
- ]
-
- if RUBY_VERSION < "3.3.0"
- # This file has changed behavior in Ripper in Ruby 3.3, so we skip it if
- # we're on an earlier version.
- except << "seattlerb/pct_w_heredoc_interp_nested.txt"
-
- # Ruby < 3.3.0 cannot parse heredocs where there are leading whitespace
- # characters in the heredoc start.
- # Example: <<~' EOF' or <<-' EOF'
- # https://bugs.ruby-lang.org/issues/19539
- except << "heredocs_leading_whitespace.txt"
- except << "whitequark/ruby_bug_19539.txt"
-
- # https://bugs.ruby-lang.org/issues/19025
- except << "whitequark/numparam_ruby_bug_19025.txt"
- # https://bugs.ruby-lang.org/issues/18878
- except << "whitequark/ruby_bug_18878.txt"
- # https://bugs.ruby-lang.org/issues/19281
- except << "whitequark/ruby_bug_19281.txt"
- end
-
- Fixture.each(except: except) do |fixture|
- define_method(fixture.test_name) { assert_lex(fixture) }
- end
-
def test_lex_file
assert_nothing_raised do
Prism.lex_file(__FILE__)
@@ -86,17 +47,77 @@ module Prism
end
end
- private
-
- def assert_lex(fixture)
- source = fixture.read
+ def test_lex_encoding
+ tokens = Prism.lex('"わたし"', encoding: Encoding::Windows_31J).value
+ tokens.each do |t|
+ assert_equal(Encoding::Windows_31J, t[0].value.encoding)
+ end
- result = Prism.lex_compat(source)
- assert_equal [], result.errors
+ # Shebangs must appear on the first line. For these cases, the encoding
+ # comment may appear second, but it should still change encoding.
+ tokens = Prism.lex(<<~RUBY, encoding: Encoding::Windows_31J).value
+ #! /usr/bin/env ruby
+ # encoding: utf-8
+ "わたし"
+ RUBY
+ tokens.each do |t|
+ assert_equal(Encoding::UTF_8, t[0].value.encoding)
+ end
+ end
- Prism.lex_ripper(source).zip(result.value).each do |(ripper, prism)|
- assert_equal ripper, prism
+ if RUBY_VERSION >= "3.3"
+ def test_lex_compat
+ source = "foo bar"
+ prism = Prism.lex_compat(source, version: "current").value
+ ripper = Ripper.lex(source)
+ assert_equal(ripper, prism)
end
end
+
+ def test_lex_interpolation_unterminated
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN EOF],
+ token_types('"#{')
+ )
+
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN IGNORED_NEWLINE EOF],
+ token_types('"#{' + "\n")
+ )
+ end
+
+ def test_lex_interpolation_unterminated_with_content
+ # FIXME: Emits EOL twice.
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN CONSTANT EOF EOF],
+ token_types('"#{C')
+ )
+
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN CONSTANT NEWLINE EOF],
+ token_types('"#{C' + "\n")
+ )
+ end
+
+ def test_lex_heredoc_unterminated
+ code = <<~'RUBY'.strip
+ <<A+B
+ #{C
+ RUBY
+
+ assert_equal(
+ %i[HEREDOC_START EMBEXPR_BEGIN CONSTANT HEREDOC_END PLUS CONSTANT NEWLINE EOF],
+ token_types(code)
+ )
+
+ assert_equal(
+ %i[HEREDOC_START EMBEXPR_BEGIN CONSTANT NEWLINE HEREDOC_END PLUS CONSTANT NEWLINE EOF],
+ token_types(code + "\n")
+ )
+ end
+
+ def token_types(code)
+ Prism.lex(code).value.map { |token, _state| token.type }
+ end
end
end
diff --git a/test/prism/locals_test.rb b/test/prism/locals_test.rb
index e0e9a45855..417730a8a7 100644
--- a/test/prism/locals_test.rb
+++ b/test/prism/locals_test.rb
@@ -13,11 +13,6 @@ return if !defined?(RubyVM::InstructionSequence) || RUBY_VERSION < "3.4.0"
# in comparing the locals because they will be the same.
return if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
-# In Ruby 3.4.0, the local table for method forwarding changed. But 3.4.0 can
-# refer to the dev version, so while 3.4.0 still isn't released, we need to
-# check if we have a high enough revision.
-return if RubyVM::InstructionSequence.compile("def foo(...); end").to_a[13][2][2][10].length != 1
-
# Omit tests if running on a 32-bit machine because there is a bug with how
# Ruby is handling large ISeqs on 32-bit machines
return if RUBY_PLATFORM =~ /i686/
@@ -29,10 +24,19 @@ module Prism
except = [
# Skip this fixture because it has a different number of locals because
# CRuby is eliminating dead code.
- "whitequark/ruby_bug_10653.txt"
+ "whitequark/ruby_bug_10653.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
+
+ # https://bugs.ruby-lang.org/issues/21669
+ "4.1/void_value.txt",
+
+ # https://bugs.ruby-lang.org/issues/19107
+ "4.1/trailing_comma_after_method_arguments.txt",
]
- Fixture.each(except: except) do |fixture|
+ Fixture.each_for_current_ruby(except: except) do |fixture|
define_method(fixture.test_name) { assert_locals(fixture) }
end
@@ -206,7 +210,7 @@ module Prism
end
end
- if params.block
+ if params.block.is_a?(BlockParameterNode)
sorted << (params.block.name || :&)
end
diff --git a/test/prism/magic_comment_test.rb b/test/prism/magic_comment_test.rb
index ab4b5f56e5..7985bae568 100644
--- a/test/prism/magic_comment_test.rb
+++ b/test/prism/magic_comment_test.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative "test_helper"
+require "ripper"
module Prism
class MagicCommentTest < TestCase
@@ -68,6 +69,10 @@ module Prism
assert_magic_encoding(Encoding::US_ASCII, "# -*- foo: bar; encoding: ascii -*-")
end
+ def test_emacs_missing_delimiter
+ assert_magic_encoding(Encoding::US_ASCII, '# -*- \1; encoding: ascii -*-')
+ end
+
def test_coding_whitespace
assert_magic_encoding(Encoding::ASCII_8BIT, "# coding \t \r \v : \t \v \r ascii-8bit")
end
diff --git a/test/prism/newline_offsets_test.rb b/test/prism/newline_offsets_test.rb
index 99b808b1df..bb06876a96 100644
--- a/test/prism/newline_offsets_test.rb
+++ b/test/prism/newline_offsets_test.rb
@@ -8,15 +8,38 @@ module Prism
define_method(fixture.test_name) { assert_newline_offsets(fixture) }
end
+ def test_escape_control_newline
+ # Newlines consumed inside escape sequences like \C-, \c, and \M-
+ # must be tracked in line offsets across all literal types.
+ %w[\\C- \\c \\M-].each do |escape|
+ assert_newline_offsets_for("\"#{escape}\n\"", "#{escape} in string")
+ assert_newline_offsets_for("`#{escape}\n`", "#{escape} in xstring")
+ assert_newline_offsets_for("/#{escape}\n/", "#{escape} in regexp")
+ assert_newline_offsets_for("%Q{#{escape}\n}", "#{escape} in %Q")
+ assert_newline_offsets_for("%W[#{escape}\n]", "#{escape} in %W")
+ assert_newline_offsets_for("<<~H\n#{escape}\n\nH\n", "#{escape} in heredoc")
+ assert_newline_offsets_for("?#{escape}\n", "#{escape} in char literal")
+ end
+
+ # Combined meta + control escapes
+ assert_newline_offsets_for("\"\\M-\\C-\n\"", "\\M-\\C- in string")
+ assert_newline_offsets_for("\"\\M-\\c\n\"", "\\M-\\c in string")
+
+ # \r\n consumed inside escape context
+ assert_newline_offsets_for("\"\\C-\r\n\"", "\\C- with \\r\\n")
+ end
+
private
def assert_newline_offsets(fixture)
- source = fixture.read
+ assert_newline_offsets_for(fixture.read)
+ end
+ def assert_newline_offsets_for(source, message = nil)
expected = [0]
source.b.scan("\n") { expected << $~.offset(0)[0] + 1 }
- assert_equal expected, Prism.parse(source).source.offsets
+ assert_equal expected, Prism.parse(source).source.offsets, message
end
end
end
diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb
index fefe9def91..97e698202d 100644
--- a/test/prism/newline_test.rb
+++ b/test/prism/newline_test.rb
@@ -17,7 +17,10 @@ module Prism
result/breadth_first_search_test.rb
result/static_literals_test.rb
result/warnings_test.rb
+ ruby/find_fixtures.rb
+ ruby/find_test.rb
ruby/parser_test.rb
+ ruby/ripper_test.rb
ruby/ruby_parser_test.rb
]
diff --git a/test/prism/ractor_test.rb b/test/prism/ractor_test.rb
index 55ff723395..0e008ffb08 100644
--- a/test/prism/ractor_test.rb
+++ b/test/prism/ractor_test.rb
@@ -62,7 +62,11 @@ module Prism
if reader
reader.gets.chomp
else
- puts(ignore_warnings { Ractor.new(*arguments, &block) }.take)
+ ractor = ignore_warnings { Ractor.new(*arguments, &block) }
+
+ # Somewhere in the Ruby 4.0.* series, Ractor#take was removed and
+ # Ractor#value was added.
+ puts(ractor.respond_to?(:value) ? ractor.value : ractor.take)
end
end
end
diff --git a/test/prism/result/breadth_first_search_test.rb b/test/prism/result/breadth_first_search_test.rb
index e2e043a902..7e7962f172 100644
--- a/test/prism/result/breadth_first_search_test.rb
+++ b/test/prism/result/breadth_first_search_test.rb
@@ -14,5 +14,16 @@ module Prism
refute_nil found
assert_equal 8, found.start_offset
end
+
+ def test_breadth_first_search_all
+ result = Prism.parse("[1 + 2, 2]")
+ found_nodes =
+ result.value.breadth_first_search_all do |node|
+ node.is_a?(IntegerNode)
+ end
+
+ assert_equal 3, found_nodes.size
+ assert_equal 8, found_nodes[0].start_offset
+ end
end
end
diff --git a/test/prism/result/continuable_test.rb b/test/prism/result/continuable_test.rb
new file mode 100644
index 0000000000..3533552167
--- /dev/null
+++ b/test/prism/result/continuable_test.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ContinuableTest < TestCase
+ def test_valid_input
+ # Valid input is not continuable (nothing to continue).
+ refute_predicate Prism.parse("1 + 1"), :continuable?
+ refute_predicate Prism.parse(""), :continuable?
+ end
+
+ def test_stray_closing_tokens
+ # Stray closing tokens make input non-continuable regardless of what
+ # follows (matches the feature-request examples exactly).
+ refute_predicate Prism.parse("1 + ]"), :continuable?
+ refute_predicate Prism.parse("end.tap do"), :continuable?
+
+ # A mix: stray end plus an unclosed block is not continuable because the
+ # stray end cannot be fixed by appending more input.
+ refute_predicate Prism.parse("end\ntap do"), :continuable?
+ end
+
+ def test_unclosed_constructs
+ # Unclosed constructs are continuable.
+ assert_predicate Prism.parse("1 + ["), :continuable?
+ assert_predicate Prism.parse("tap do"), :continuable?
+ end
+
+ def test_unclosed_keywords
+ assert_predicate Prism.parse("def foo"), :continuable?
+ assert_predicate Prism.parse("class Foo"), :continuable?
+ assert_predicate Prism.parse("module Foo"), :continuable?
+ assert_predicate Prism.parse("if true"), :continuable?
+ assert_predicate Prism.parse("while true"), :continuable?
+ assert_predicate Prism.parse("begin"), :continuable?
+ assert_predicate Prism.parse("for x in [1]"), :continuable?
+ end
+
+ def test_unclosed_delimiters
+ assert_predicate Prism.parse("{"), :continuable?
+ assert_predicate Prism.parse("foo("), :continuable?
+ assert_predicate Prism.parse('"hello'), :continuable?
+ assert_predicate Prism.parse("'hello"), :continuable?
+ assert_predicate Prism.parse("<<~HEREDOC\nhello"), :continuable?
+ end
+
+ def test_trailing_whitespace
+ # Trailing whitespace or newlines should not affect continuability.
+ assert_predicate Prism.parse("class A\n"), :continuable?
+ assert_predicate Prism.parse("def f "), :continuable?
+ assert_predicate Prism.parse("def f\n"), :continuable?
+ assert_predicate Prism.parse("def f\n "), :continuable?
+ assert_predicate Prism.parse("( "), :continuable?
+ assert_predicate Prism.parse("(\n"), :continuable?
+ assert_predicate Prism.parse("1 +\n"), :continuable?
+ end
+
+ def test_incomplete_expressions
+ assert_predicate Prism.parse("-"), :continuable?
+ assert_predicate Prism.parse("[1,"), :continuable?
+ assert_predicate Prism.parse("f arg1,"), :continuable?
+ assert_predicate Prism.parse("def f ="), :continuable?
+ assert_predicate Prism.parse("def $a"), :continuable?
+ assert_predicate Prism.parse("a ="), :continuable?
+ assert_predicate Prism.parse("a,b"), :continuable?
+ end
+
+ def test_modifier_keywords
+ assert_predicate Prism.parse("return if"), :continuable?
+ assert_predicate Prism.parse("return unless"), :continuable?
+ assert_predicate Prism.parse("while"), :continuable?
+ assert_predicate Prism.parse("until"), :continuable?
+ end
+
+ def test_ternary_operator
+ assert_predicate Prism.parse("x ?"), :continuable?
+ assert_predicate Prism.parse("x ? y :"), :continuable?
+ end
+
+ def test_class_with_superclass
+ assert_predicate Prism.parse("class Foo <"), :continuable?
+ end
+
+ def test_keyword_expressions
+ assert_predicate Prism.parse("not"), :continuable?
+ assert_predicate Prism.parse("defined?"), :continuable?
+ assert_predicate Prism.parse("module"), :continuable?
+ end
+
+ def test_for_loops
+ assert_predicate Prism.parse("for"), :continuable?
+ assert_predicate Prism.parse("for x in"), :continuable?
+ end
+
+ def test_pattern_matching
+ assert_predicate Prism.parse("foo => ["), :continuable?
+ assert_predicate Prism.parse("case foo; when"), :continuable?
+ end
+
+ def test_splat_and_block_pass
+ assert_predicate Prism.parse("[*"), :continuable?
+ assert_predicate Prism.parse("f(**"), :continuable?
+ assert_predicate Prism.parse("f(&"), :continuable?
+ end
+
+ def test_default_parameter_value
+ assert_predicate Prism.parse("def f(x ="), :continuable?
+ end
+
+ def test_line_continuation
+ assert_predicate Prism.parse("1 +\\"), :continuable?
+ assert_predicate Prism.parse("\"foo\" \\"), :continuable?
+ end
+
+ def test_embedded_document
+ # Embedded document (=begin) truncated at various points.
+ assert_predicate Prism.parse("=b"), :continuable?
+ assert_predicate Prism.parse("=beg"), :continuable?
+ assert_predicate Prism.parse("=begin"), :continuable?
+ assert_predicate Prism.parse("foo\n=b"), :continuable?
+ end
+ end
+end
diff --git a/test/prism/result/error_recovery_test.rb b/test/prism/result/error_recovery_test.rb
new file mode 100644
index 0000000000..d07c858d1b
--- /dev/null
+++ b/test/prism/result/error_recovery_test.rb
@@ -0,0 +1,237 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ErrorRecoveryTest < TestCase
+ def test_alias_global_variable_node_old_name_symbol
+ result = Prism.parse("alias $a b")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_kind_of SymbolNode, node.old_name.unexpected
+ end
+
+ def test_alias_global_variable_node_old_name_missing
+ result = Prism.parse("alias $a 42")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_nil node.old_name.unexpected
+ end
+
+ def test_alias_method_node_old_name_global_variable
+ result = Prism.parse("alias a $b")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_kind_of GlobalVariableReadNode, node.old_name.unexpected
+ end
+
+ def test_alias_method_node_old_name_missing
+ result = Prism.parse("alias a 42")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.old_name
+ assert_nil node.old_name.unexpected
+ end
+
+ def test_class_node_constant_path_call
+ result = Prism.parse("class 0.X; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.constant_path
+ assert_kind_of CallNode, node.constant_path.unexpected
+ end
+
+ def test_for_node_index_back_reference
+ result = Prism.parse("for $& in a; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.index
+ assert_kind_of BackReferenceReadNode, node.index.unexpected
+ end
+
+ def test_for_node_index_numbered_reference
+ result = Prism.parse("for $1 in a; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.index
+ assert_kind_of NumberedReferenceReadNode, node.index.unexpected
+ end
+
+ def test_for_node_index_missing
+ result = Prism.parse("for in 1..10; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.index
+ assert_nil node.index.unexpected
+ end
+
+ def test_interpolated_string_node_parts_xstring
+ result = Prism.parse("<<~`FOO` \"bar\"\nls\nFOO\n")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.parts.any? { |part| part.is_a?(ErrorRecoveryNode) && part.unexpected.is_a?(XStringNode) }
+ end
+
+ def test_interpolated_string_node_parts_interpolated_xstring
+ result = Prism.parse("<<~`FOO` \"bar\"\n\#{ls}\nFOO\n")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.parts.any? { |part| part.is_a?(ErrorRecoveryNode) && part.unexpected.is_a?(InterpolatedXStringNode) }
+ end
+
+ def test_module_node_constant_path_def
+ result = Prism.parse("module def foo; end")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert_kind_of ErrorRecoveryNode, node.constant_path
+ assert_kind_of DefNode, node.constant_path.unexpected
+ end
+
+ def test_module_node_constant_path_missing
+ result = Prism.parse("module Parent module end")
+ refute result.success?
+
+ node = result.value.statements.body.first.body.body.first
+ assert_kind_of ErrorRecoveryNode, node.constant_path
+ assert_nil node.constant_path.unexpected
+ end
+
+ def test_multi_target_node_lefts_back_reference
+ result = Prism.parse("a, (b, $&) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_target_node_lefts_numbered_reference
+ result = Prism.parse("a, (b, $1) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_multi_target_node_rights_back_reference
+ result = Prism.parse("a, (*, $&) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_target_node_rights_numbered_reference
+ result = Prism.parse("a, (*, $1) = z")
+ refute result.success?
+
+ node = result.value.statements.body.first.lefts.last
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_multi_write_node_lefts_back_reference
+ result = Prism.parse("$&, = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_write_node_lefts_numbered_reference
+ result = Prism.parse("$1, = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.lefts.any? { |left| left.is_a?(ErrorRecoveryNode) && left.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_multi_write_node_rights_back_reference
+ result = Prism.parse("*, $& = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(BackReferenceReadNode) }
+ end
+
+ def test_multi_write_node_rights_numbered_reference
+ result = Prism.parse("*, $1 = z")
+ refute result.success?
+
+ node = result.value.statements.body.first
+ assert node.rights.any? { |right| right.is_a?(ErrorRecoveryNode) && right.unexpected.is_a?(NumberedReferenceReadNode) }
+ end
+
+ def test_parameters_node_posts_keyword_rest
+ result = Prism.parse("def f(**kwargs, ...); end")
+ refute result.success?
+
+ node = result.value.statements.body.first.parameters
+ assert node.posts.any? { |post| post.is_a?(ErrorRecoveryNode) && post.unexpected.is_a?(KeywordRestParameterNode) }
+ end
+
+ def test_parameters_node_posts_no_keywords
+ result = Prism.parse("def f(**nil, ...); end")
+ refute result.success?
+
+ node = result.value.statements.body.first.parameters
+ assert node.posts.any? { |post| post.is_a?(ErrorRecoveryNode) && post.unexpected.is_a?(NoKeywordsParameterNode) }
+ end
+
+ def test_parameters_node_posts_forwarding
+ result = Prism.parse("def f(..., ...); end")
+ refute result.success?
+
+ node = result.value.statements.body.first.parameters
+ assert node.posts.any? { |post| post.is_a?(ErrorRecoveryNode) && post.unexpected.is_a?(ForwardingParameterNode) }
+ end
+
+ def test_pinned_variable_node_variable_missing
+ result = Prism.parse("foo in ^Bar")
+ refute result.success?
+
+ node = result.value.statements.body.first.pattern
+ assert_kind_of ErrorRecoveryNode, node.variable
+ assert_nil node.variable.unexpected
+ end
+
+ def test_rescue_node_reference_back_reference
+ result = Prism.parse("begin; rescue => $&; end")
+ refute result.success?
+
+ node = result.value.statements.body.first.rescue_clause
+ assert_kind_of ErrorRecoveryNode, node.reference
+ assert_kind_of BackReferenceReadNode, node.reference.unexpected
+ end
+
+ def test_rescue_node_reference_numbered_reference
+ result = Prism.parse("begin; rescue => $1; end")
+ refute result.success?
+
+ node = result.value.statements.body.first.rescue_clause
+ assert_kind_of ErrorRecoveryNode, node.reference
+ assert_kind_of NumberedReferenceReadNode, node.reference.unexpected
+ end
+
+ def test_rescue_node_reference_missing
+ result = Prism.parse("begin; rescue =>; end")
+ refute result.success?
+
+ node = result.value.statements.body.first.rescue_clause
+ assert_kind_of ErrorRecoveryNode, node.reference
+ assert_nil node.reference.unexpected
+ end
+ end
+end
diff --git a/test/prism/result/numeric_value_test.rb b/test/prism/result/numeric_value_test.rb
index 5c89230a1f..0207fa6a86 100644
--- a/test/prism/result/numeric_value_test.rb
+++ b/test/prism/result/numeric_value_test.rb
@@ -6,16 +6,27 @@ module Prism
class NumericValueTest < TestCase
def test_numeric_value
assert_equal 123, Prism.parse_statement("123").value
+ assert_equal 123, Prism.parse_statement("1_23").value
assert_equal 3.14, Prism.parse_statement("3.14").value
+ assert_equal 3.14, Prism.parse_statement("3.1_4").value
assert_equal 42i, Prism.parse_statement("42i").value
+ assert_equal 42i, Prism.parse_statement("4_2i").value
assert_equal 42.1ri, Prism.parse_statement("42.1ri").value
+ assert_equal 42.1ri, Prism.parse_statement("42.1_0ri").value
assert_equal 3.14i, Prism.parse_statement("3.14i").value
+ assert_equal 3.14i, Prism.parse_statement("3.1_4i").value
assert_equal 42r, Prism.parse_statement("42r").value
+ assert_equal 42r, Prism.parse_statement("4_2r").value
assert_equal 0.5r, Prism.parse_statement("0.5r").value
+ assert_equal 0.5r, Prism.parse_statement("0.5_0r").value
assert_equal 42ri, Prism.parse_statement("42ri").value
+ assert_equal 42ri, Prism.parse_statement("4_2ri").value
assert_equal 0.5ri, Prism.parse_statement("0.5ri").value
+ assert_equal 0.5ri, Prism.parse_statement("0.5_0ri").value
assert_equal 0xFFr, Prism.parse_statement("0xFFr").value
+ assert_equal 0xFFr, Prism.parse_statement("0xF_Fr").value
assert_equal 0xFFri, Prism.parse_statement("0xFFri").value
+ assert_equal 0xFFri, Prism.parse_statement("0xF_Fri").value
end
end
end
diff --git a/test/prism/result/overlap_test.rb b/test/prism/result/overlap_test.rb
index 155bc870d3..d605eeca44 100644
--- a/test/prism/result/overlap_test.rb
+++ b/test/prism/result/overlap_test.rb
@@ -33,8 +33,13 @@ module Prism
queue << child
if compare
- assert_operator current.location.start_offset, :<=, child.location.start_offset
- assert_operator current.location.end_offset, :>=, child.location.end_offset
+ assert_operator current.location.start_offset, :<=, child.location.start_offset, -> {
+ "[#{fixture.full_path}] Parent node #{current.class} at #{current.location} does not start before child node #{child.class} at #{child.location}"
+ }
+
+ assert_operator current.location.end_offset, :>=, child.location.end_offset, -> {
+ "[#{fixture.full_path}] Parent node #{current.class} at #{current.location} does not end after child node #{child.class} at #{child.location}"
+ }
end
end
end
diff --git a/test/prism/result/source_location_test.rb b/test/prism/result/source_location_test.rb
index 7bdc707658..a8d27b95a8 100644
--- a/test/prism/result/source_location_test.rb
+++ b/test/prism/result/source_location_test.rb
@@ -13,7 +13,7 @@ module Prism
end
def test_AlternationPatternNode
- assert_location(AlternationPatternNode, "foo => bar | baz", 7...16, &:pattern)
+ assert_location(AlternationPatternNode, "foo => 0 | 1", 7...12, &:pattern)
end
def test_AndNode
@@ -650,6 +650,10 @@ module Prism
assert_location(NilNode, "nil")
end
+ def test_NoBlockParameterNode
+ assert_location(NoBlockParameterNode, "def foo(&nil); end", 8...12) { |node| node.parameters.block }
+ end
+
def test_NoKeywordsParameterNode
assert_location(NoKeywordsParameterNode, "def foo(**nil); end", 8...13) { |node| node.parameters.keyword_rest }
end
@@ -920,7 +924,7 @@ module Prism
end
def test_all_tested
- expected = Prism.constants.grep(/.Node$/).sort - %i[MissingNode ProgramNode]
+ expected = Prism.constants.grep(/.Node$/).sort - %i[ErrorRecoveryNode ProgramNode]
actual = SourceLocationTest.instance_methods(false).grep(/.Node$/).map { |name| name[5..].to_sym }.sort
assert_equal expected, actual
end
@@ -935,16 +939,16 @@ module Prism
node = yield node if block_given?
if expected.begin == 0
- assert_equal 0, node.location.start_column
+ assert_equal 0, node.location.start_column, "#{kind} start_column"
end
if expected.end == source.length
- assert_equal source.split("\n").last.length, node.location.end_column
+ assert_equal source.split("\n").last.length, node.location.end_column, "#{kind} end_column"
end
assert_kind_of kind, node
- assert_equal expected.begin, node.location.start_offset
- assert_equal expected.end, node.location.end_offset
+ assert_equal expected.begin, node.location.start_offset, "#{kind} start_offset"
+ assert_equal expected.end, node.location.end_offset, "#{kind} end_offset"
end
end
end
diff --git a/test/prism/result/warnings_test.rb b/test/prism/result/warnings_test.rb
index 4643fb134f..27f1119b98 100644
--- a/test/prism/result/warnings_test.rb
+++ b/test/prism/result/warnings_test.rb
@@ -230,6 +230,8 @@ module Prism
refute_warning("foo = 1", compare: false, command_line: "e")
refute_warning("foo = 1", compare: false, scopes: [[]])
+ refute_warning("foo(bar = 1)")
+
assert_warning("def foo; bar = 1; end", "unused")
assert_warning("def foo; bar, = 1; end", "unused")
@@ -263,6 +265,23 @@ module Prism
refute_warning("def foo; bar = 1; end", line: -2, compare: false)
end
+ def test_unused_local_variable_or_assign_with_begin_node
+ assert_warning(<<~RUBY, "assigned but unused variable - foo", compare: false)
+ var ||= begin
+ foo = bar
+ baz
+ end
+ RUBY
+
+ assert_warning(<<~RUBY, "assigned but unused variable - foo", compare: false)
+ foo = false
+ var ||= begin
+ foo = true
+ bar
+ end
+ RUBY
+ end
+
def test_void_statements
assert_warning("foo = 1; foo", "a variable in void")
assert_warning("@foo", "a variable in void")
diff --git a/test/prism/ruby/find_fixtures.rb b/test/prism/ruby/find_fixtures.rb
new file mode 100644
index 0000000000..c1bef0d0e6
--- /dev/null
+++ b/test/prism/ruby/find_fixtures.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+# Test fixtures for Prism.find. These must be in a separate file because
+# source_location returns the file path and Prism.find re-parses the file.
+
+module Prism
+ module FindFixtures
+ module Methods
+ def simple_method
+ 42
+ end
+
+ def method_with_params(a, b, c)
+ a + b + c
+ end
+
+ def method_with_block(&block)
+ block.call
+ end
+
+ def self.singleton_method_fixture
+ :singleton
+ end
+
+ def été
+ :utf8
+ end
+
+ def inline_method; :inline; end
+ end
+
+ module Procs
+ SIMPLE_PROC = proc { 42 }
+ SIMPLE_LAMBDA = ->(x) { x * 2 }
+ MULTI_LINE_LAMBDA = lambda do |x|
+ x + 1
+ end
+ DO_BLOCK_PROC = proc do |x|
+ x - 1
+ end
+ end
+
+ module DefineMethod
+ define_method(:dynamic) { |x| x + 1 }
+ end
+
+ module ForLoop
+ for_proc = nil
+ o = Object.new
+ def o.each(&block) = block.call(block)
+ for for_proc in o; end
+ FOR_PROC = for_proc
+ end
+
+ module MultipleOnLine
+ def self.first; end; def self.second; end
+ end
+
+ module Errors
+ def self.divide(a, b)
+ a / b
+ end
+
+ def self.call_undefined
+ undefined_method_call
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/find_test.rb b/test/prism/ruby/find_test.rb
new file mode 100644
index 0000000000..5b59113d30
--- /dev/null
+++ b/test/prism/ruby/find_test.rb
@@ -0,0 +1,242 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE == "ruby" && RUBY_VERSION < "3.4"
+return if defined?(RubyVM::InstructionSequence) && RubyVM::InstructionSequence.compile("").to_a[4][:parser] != :prism
+
+require_relative "../test_helper"
+require_relative "find_fixtures"
+
+module Prism
+ class FindTest < TestCase
+ Fixtures = FindFixtures
+ FIXTURES_PATH = File.expand_path("find_fixtures.rb", __dir__)
+
+ # === Method / UnboundMethod tests ===
+
+ def test_simple_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method)), :simple_method
+ end
+
+ def test_method_with_params
+ node = Prism.find(Fixtures::Methods.instance_method(:method_with_params))
+ assert_def_node node, :method_with_params
+ assert_equal 3, node.parameters.requireds.length
+ end
+
+ def test_method_with_block_param
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:method_with_block)), :method_with_block
+ end
+
+ def test_singleton_method
+ assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture)), :singleton_method_fixture
+ end
+
+ def test_utf8_method_name
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:été)), :été
+ end
+
+ def test_inline_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:inline_method)), :inline_method
+ end
+
+ def test_bound_method
+ obj = Object.new
+ obj.extend(Fixtures::Methods)
+ assert_def_node Prism.find(obj.method(:simple_method)), :simple_method
+ end
+
+ # === Proc / Lambda tests ===
+
+ def test_simple_proc
+ assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_PROC)
+ end
+
+ def test_simple_lambda
+ assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_LAMBDA)
+ end
+
+ def test_multi_line_lambda
+ assert_not_nil Prism.find(Fixtures::Procs::MULTI_LINE_LAMBDA)
+ end
+
+ def test_do_block_proc
+ assert_not_nil Prism.find(Fixtures::Procs::DO_BLOCK_PROC)
+ end
+
+ # === define_method tests ===
+
+ def test_define_method
+ assert_not_nil Prism.find(Fixtures::DefineMethod.instance_method(:dynamic))
+ end
+
+ def test_define_method_bound
+ obj = Object.new
+ obj.extend(Fixtures::DefineMethod)
+ assert_not_nil Prism.find(obj.method(:dynamic))
+ end
+
+ # === for loop test ===
+
+ def test_for_loop_proc
+ node = Prism.find(Fixtures::ForLoop::FOR_PROC)
+ assert_instance_of ForNode, node
+ end
+
+ # === Thread::Backtrace::Location tests ===
+
+ def test_backtrace_location_zero_division
+ location = zero_division_location
+ assert_not_nil location, "could not find backtrace location in fixtures file"
+ assert_not_nil Prism.find(location)
+ end
+
+ def test_backtrace_location_name_error
+ location = begin
+ Fixtures::Errors.call_undefined
+ rescue NameError => e
+ fixture_backtrace_location(e)
+ end
+
+ assert_not_nil location, "could not find backtrace location in fixtures file"
+ assert_not_nil Prism.find(location)
+ end
+
+ def test_backtrace_location_from_caller
+ # caller_locations returns locations for the current call stack
+ location = caller_locations(0, 1).first
+ node = Prism.find(location)
+ assert_not_nil node
+ end
+
+ def test_backtrace_location_eval_returns_nil
+ location = begin
+ eval("raise 'eval error'")
+ rescue RuntimeError => e
+ e.backtrace_locations.find { |loc| loc.path == "(eval)" || loc.label&.include?("eval") }
+ end
+
+ # eval locations have no file on disk
+ assert_nil Prism.find(location) if location
+ end
+
+ # === Edge cases ===
+
+ def test_nil_source_location
+ # Built-in methods have nil source_location
+ assert_nil Prism.find(method(:puts))
+ end
+
+ def test_argument_error_on_wrong_type
+ assert_raise(ArgumentError) { Prism.find("not a callable") }
+ assert_raise(ArgumentError) { Prism.find(42) }
+ assert_raise(ArgumentError) { Prism.find(nil) }
+ end
+
+ def test_eval_returns_nil
+ # eval'd code has no file on disk
+ m = eval("proc { 1 }")
+ assert_nil Prism.find(m)
+ end
+
+ def test_multiple_methods_on_same_line
+ assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:first)), :first
+ assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:second)), :second
+ end
+
+ # === Fallback (line-based) tests via rubyvm: false ===
+
+ def test_fallback_simple_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method), rubyvm: false), :simple_method
+ end
+
+ def test_fallback_singleton_method
+ assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture), rubyvm: false), :singleton_method_fixture
+ end
+
+ def test_fallback_lambda
+ node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA, rubyvm: false)
+ assert_instance_of LambdaNode, node
+ end
+
+ def test_fallback_proc
+ node = Prism.find(Fixtures::Procs::SIMPLE_PROC, rubyvm: false)
+ assert_instance_of CallNode, node
+ assert node.block.is_a?(BlockNode)
+ end
+
+ def test_fallback_define_method
+ node = Prism.find(Fixtures::DefineMethod.instance_method(:dynamic), rubyvm: false)
+ assert_instance_of CallNode, node
+ assert node.block.is_a?(BlockNode)
+ end
+
+ def test_fallback_for_loop
+ node = Prism.find(Fixtures::ForLoop::FOR_PROC, rubyvm: false)
+ assert_instance_of ForNode, node
+ end
+
+ def test_fallback_backtrace_location
+ location = zero_division_location
+ assert_not_nil location
+ node = Prism.find(location, rubyvm: false)
+ assert_not_nil node
+ assert_equal location.lineno, node.location.start_line
+ end
+
+ # === Node identity with node_id (CRuby only) ===
+
+ if defined?(RubyVM::InstructionSequence)
+ def test_node_id_matches_iseq
+ m = Fixtures::Methods.instance_method(:simple_method)
+ node = Prism.find(m)
+ assert_equal node_id_of(m), node.node_id
+ end
+
+ def test_node_id_for_lambda
+ node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA)
+ assert_equal node_id_of(Fixtures::Procs::SIMPLE_LAMBDA), node.node_id
+ end
+
+ def test_node_id_for_proc
+ node = Prism.find(Fixtures::Procs::SIMPLE_PROC)
+ assert_equal node_id_of(Fixtures::Procs::SIMPLE_PROC), node.node_id
+ end
+
+ def test_node_id_for_define_method
+ m = Fixtures::DefineMethod.instance_method(:dynamic)
+ node = Prism.find(m)
+ assert_equal node_id_of(m), node.node_id
+ end
+
+ def test_node_id_for_backtrace_location
+ location = zero_division_location
+ assert_not_nil location
+ expected_node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
+
+ node = Prism.find(location)
+ assert_equal expected_node_id, node.node_id
+ end
+ end
+
+ private
+
+ def assert_def_node(node, expected_name)
+ assert_instance_of DefNode, node
+ assert_equal expected_name, node.name
+ end
+
+ def fixture_backtrace_location(exception)
+ exception.backtrace_locations.find { |loc| loc.path == FIXTURES_PATH }
+ end
+
+ def zero_division_location
+ Fixtures::Errors.divide(1, 0)
+ rescue ZeroDivisionError => e
+ fixture_backtrace_location(e)
+ end
+
+ def node_id_of(callable)
+ RubyVM::InstructionSequence.of(callable).to_a[4][:node_id]
+ end
+ end
+end
diff --git a/test/prism/ruby/location_test.rb b/test/prism/ruby/location_test.rb
index 33f844243c..12c4258cde 100644
--- a/test/prism/ruby/location_test.rb
+++ b/test/prism/ruby/location_test.rb
@@ -13,19 +13,22 @@ module Prism
assert_equal 0, joined.start_offset
assert_equal 10, joined.length
- assert_raise(RuntimeError, "Incompatible locations") do
+ e = assert_raise(RuntimeError) do
argument.location.join(receiver.location)
end
+ assert_equal "Incompatible locations", e.message
other_argument = Prism.parse_statement("1234 + 567").arguments.arguments.first
- assert_raise(RuntimeError, "Incompatible sources") do
+ e = assert_raise(RuntimeError) do
other_argument.location.join(receiver.location)
end
+ assert_equal "Incompatible sources", e.message
- assert_raise(RuntimeError, "Incompatible sources") do
+ e = assert_raise(RuntimeError) do
receiver.location.join(other_argument.location)
end
+ assert_equal "Incompatible sources", e.message
end
def test_character_offsets
@@ -70,7 +73,7 @@ module Prism
assert_equal 0, location.start_code_units_offset(Encoding::UTF_16LE)
assert_equal 0, location.start_code_units_offset(Encoding::UTF_32LE)
- assert_equal 1, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 4, location.end_code_units_offset(Encoding::UTF_8)
assert_equal 2, location.end_code_units_offset(Encoding::UTF_16LE)
assert_equal 1, location.end_code_units_offset(Encoding::UTF_32LE)
@@ -78,37 +81,37 @@ module Prism
assert_equal 0, location.start_code_units_column(Encoding::UTF_16LE)
assert_equal 0, location.start_code_units_column(Encoding::UTF_32LE)
- assert_equal 1, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 4, location.end_code_units_column(Encoding::UTF_8)
assert_equal 2, location.end_code_units_column(Encoding::UTF_16LE)
assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
# second 😀
location = program.statements.body.first.arguments.arguments.first.location
- assert_equal 4, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 7, location.start_code_units_offset(Encoding::UTF_8)
assert_equal 5, location.start_code_units_offset(Encoding::UTF_16LE)
assert_equal 4, location.start_code_units_offset(Encoding::UTF_32LE)
- assert_equal 5, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 11, location.end_code_units_offset(Encoding::UTF_8)
assert_equal 7, location.end_code_units_offset(Encoding::UTF_16LE)
assert_equal 5, location.end_code_units_offset(Encoding::UTF_32LE)
- assert_equal 4, location.start_code_units_column(Encoding::UTF_8)
+ assert_equal 7, location.start_code_units_column(Encoding::UTF_8)
assert_equal 5, location.start_code_units_column(Encoding::UTF_16LE)
assert_equal 4, location.start_code_units_column(Encoding::UTF_32LE)
- assert_equal 5, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 11, location.end_code_units_column(Encoding::UTF_8)
assert_equal 7, location.end_code_units_column(Encoding::UTF_16LE)
assert_equal 5, location.end_code_units_column(Encoding::UTF_32LE)
# first 😍
location = program.statements.body.last.name_loc
- assert_equal 6, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 12, location.start_code_units_offset(Encoding::UTF_8)
assert_equal 8, location.start_code_units_offset(Encoding::UTF_16LE)
assert_equal 6, location.start_code_units_offset(Encoding::UTF_32LE)
- assert_equal 7, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 16, location.end_code_units_offset(Encoding::UTF_8)
assert_equal 10, location.end_code_units_offset(Encoding::UTF_16LE)
assert_equal 7, location.end_code_units_offset(Encoding::UTF_32LE)
@@ -116,26 +119,26 @@ module Prism
assert_equal 0, location.start_code_units_column(Encoding::UTF_16LE)
assert_equal 0, location.start_code_units_column(Encoding::UTF_32LE)
- assert_equal 1, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 4, location.end_code_units_column(Encoding::UTF_8)
assert_equal 2, location.end_code_units_column(Encoding::UTF_16LE)
assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
# second 😍
location = program.statements.body.last.value.location
- assert_equal 12, location.start_code_units_offset(Encoding::UTF_8)
+ assert_equal 21, location.start_code_units_offset(Encoding::UTF_8)
assert_equal 15, location.start_code_units_offset(Encoding::UTF_16LE)
assert_equal 12, location.start_code_units_offset(Encoding::UTF_32LE)
- assert_equal 13, location.end_code_units_offset(Encoding::UTF_8)
+ assert_equal 25, location.end_code_units_offset(Encoding::UTF_8)
assert_equal 17, location.end_code_units_offset(Encoding::UTF_16LE)
assert_equal 13, location.end_code_units_offset(Encoding::UTF_32LE)
- assert_equal 6, location.start_code_units_column(Encoding::UTF_8)
+ assert_equal 9, location.start_code_units_column(Encoding::UTF_8)
assert_equal 7, location.start_code_units_column(Encoding::UTF_16LE)
assert_equal 6, location.start_code_units_column(Encoding::UTF_32LE)
- assert_equal 7, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 13, location.end_code_units_column(Encoding::UTF_8)
assert_equal 9, location.end_code_units_column(Encoding::UTF_16LE)
assert_equal 7, location.end_code_units_column(Encoding::UTF_32LE)
end
@@ -154,7 +157,7 @@ module Prism
assert_equal 0, location.cached_start_code_units_offset(utf16_cache)
assert_equal 0, location.cached_start_code_units_offset(utf32_cache)
- assert_equal 1, location.cached_end_code_units_offset(utf8_cache)
+ assert_equal 4, location.cached_end_code_units_offset(utf8_cache)
assert_equal 2, location.cached_end_code_units_offset(utf16_cache)
assert_equal 1, location.cached_end_code_units_offset(utf32_cache)
@@ -162,26 +165,26 @@ module Prism
assert_equal 0, location.cached_start_code_units_column(utf16_cache)
assert_equal 0, location.cached_start_code_units_column(utf32_cache)
- assert_equal 1, location.cached_end_code_units_column(utf8_cache)
+ assert_equal 4, location.cached_end_code_units_column(utf8_cache)
assert_equal 2, location.cached_end_code_units_column(utf16_cache)
assert_equal 1, location.cached_end_code_units_column(utf32_cache)
# second 😀
location = result.value.statements.body.first.arguments.arguments.first.location
- assert_equal 4, location.cached_start_code_units_offset(utf8_cache)
+ assert_equal 7, location.cached_start_code_units_offset(utf8_cache)
assert_equal 5, location.cached_start_code_units_offset(utf16_cache)
assert_equal 4, location.cached_start_code_units_offset(utf32_cache)
- assert_equal 5, location.cached_end_code_units_offset(utf8_cache)
+ assert_equal 11, location.cached_end_code_units_offset(utf8_cache)
assert_equal 7, location.cached_end_code_units_offset(utf16_cache)
assert_equal 5, location.cached_end_code_units_offset(utf32_cache)
- assert_equal 4, location.cached_start_code_units_column(utf8_cache)
+ assert_equal 7, location.cached_start_code_units_column(utf8_cache)
assert_equal 5, location.cached_start_code_units_column(utf16_cache)
assert_equal 4, location.cached_start_code_units_column(utf32_cache)
- assert_equal 5, location.cached_end_code_units_column(utf8_cache)
+ assert_equal 11, location.cached_end_code_units_column(utf8_cache)
assert_equal 7, location.cached_end_code_units_column(utf16_cache)
assert_equal 5, location.cached_end_code_units_column(utf32_cache)
end
@@ -197,7 +200,7 @@ module Prism
assert_equal "😀".b.to_sym, receiver.name
location = receiver.location
- assert_equal 1, location.end_code_units_column(Encoding::UTF_8)
+ assert_equal 4, location.end_code_units_column(Encoding::UTF_8)
assert_equal 2, location.end_code_units_column(Encoding::UTF_16LE)
assert_equal 1, location.end_code_units_column(Encoding::UTF_32LE)
end
diff --git a/test/prism/ruby/parameters_signature_test.rb b/test/prism/ruby/parameters_signature_test.rb
index af5b54ed91..1ca2b144a9 100644
--- a/test/prism/ruby/parameters_signature_test.rb
+++ b/test/prism/ruby/parameters_signature_test.rb
@@ -50,11 +50,16 @@ module Prism
assert_parameters([[:nokey]], "**nil")
end
+ def test_noblock
+ # FIXME: `compare: RUBY_VERSION >= "4.1"` once builds are available
+ assert_parameters([[:noblock]], "&nil", compare: false)
+ end
+
def test_keyrest_anonymous
assert_parameters([[:keyrest, :**]], "**")
end
- if RUBY_ENGINE != "truffleruby"
+ if RUBY_ENGINE == "ruby"
def test_key_ordering
assert_parameters([[:keyreq, :a], [:keyreq, :b], [:key, :c], [:key, :d]], "a:, c: 1, b:, d: 2")
end
@@ -72,12 +77,20 @@ module Prism
assert_parameters([[:rest, :*], [:keyrest, :**], [:block, :&]], "...")
end
+ def test_invalid_syntax
+ e = assert_raise(RuntimeError) do
+ Prism.parse_statement("def f(**nil, ...); end").parameters.signature
+ end
+ assert_equal("Invalid syntax", e.message)
+ end
+
private
- def assert_parameters(expected, source)
+ def assert_parameters(expected, source, compare: true)
# Compare against our expectation.
assert_equal(expected, signature(source))
+ return unless compare
# Compare against Ruby's expectation.
object = Object.new
eval("def object.m(#{source}); end")
diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb
index e94f9f860d..ad9fa0c92c 100644
--- a/test/prism/ruby/parser_test.rb
+++ b/test/prism/ruby/parser_test.rb
@@ -5,8 +5,6 @@ require_relative "../test_helper"
begin
verbose, $VERBOSE = $VERBOSE, nil
require "parser/ruby33"
- require "prism/translation/parser33"
- require "prism/translation/parser34"
rescue LoadError
# In CRuby's CI, we're not going to test against the parser gem because we
# don't want to have to install it. So in this case we'll just skip this test.
@@ -56,6 +54,22 @@ Parser::AST::Node.prepend(
module Prism
class ParserTest < TestCase
+ # These files contain code with valid syntax that can't be parsed.
+ skip_syntax_error = [
+ # alias/undef with %s(abc) symbol literal
+ "alias.txt",
+ "seattlerb/bug_215.txt",
+
+ # %Q with newline delimiter and heredoc interpolation
+ "heredoc_percent_q_newline_delimiter.txt",
+
+ # 1.. && 2
+ "ranges.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
+ ]
+
# These files contain code that is being parsed incorrectly by the parser
# gem, and therefore we don't want to compare against our translation.
skip_incorrect = [
@@ -87,18 +101,11 @@ module Prism
# Regex with \c escape
"unescaping.txt",
"seattlerb/regexp_esc_C_slash.txt",
- ]
- # These files are either failing to parse or failing to translate, so we'll
- # skip them for now.
- skip_all = skip_incorrect | [
+ # https://github.com/whitequark/parser/issues/1084
+ "unary_method_calls.txt",
]
- # Not sure why these files are failing on JRuby, but skipping them for now.
- if RUBY_ENGINE == "jruby"
- skip_all.push("emoji_method_calls.txt", "symbols.txt")
- end
-
# These files are failing to translate their lexer output into the lexer
# output expected by the parser gem, so we'll skip them for now.
skip_tokens = [
@@ -133,11 +140,11 @@ module Prism
"whitequark/space_args_block.txt"
]
- Fixture.each do |fixture|
+ Fixture.each_for_version(except: skip_syntax_error, version: "3.3") do |fixture|
define_method(fixture.test_name) do
assert_equal_parses(
fixture,
- compare_asts: !skip_all.include?(fixture.path),
+ compare_asts: !skip_incorrect.include?(fixture.path),
compare_tokens: !skip_tokens.include?(fixture.path),
compare_comments: fixture.path != "embdoc_no_newline_at_end.txt"
)
@@ -156,27 +163,52 @@ module Prism
if RUBY_VERSION >= "3.3"
def test_current_parser_for_current_ruby
- major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments
+ major, minor = CURRENT_MAJOR_MINOR.split(".")
# Let's just hope there never is a Ruby 3.10 or similar
- expected = major * 10 + minor
+ expected = major.to_i * 10 + minor.to_i
assert_equal(expected, Translation::ParserCurrent.new.version)
end
end
- def test_it_block_parameter_syntax
- it_fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures/it.txt")
+ def test_invalid_syntax
+ code = <<~RUBY
+ foo do
+ case bar
+ when
+ end
+ end
+ RUBY
+ buffer = Parser::Source::Buffer.new("(string)")
+ buffer.source = code
- buffer = Parser::Source::Buffer.new(it_fixture_path)
- buffer.source = it_fixture_path.read
- actual_ast = Prism::Translation::Parser34.new.tokenize(buffer)[0]
+ parser = Prism::Translation::Parser33.new
+ parser.diagnostics.all_errors_are_fatal = true
+ assert_raise(Parser::SyntaxError) { parser.tokenize(buffer) }
+ end
- it_block_parameter_sexp = parse_sexp {
+ def test_it_block_parameter_syntax
+ assert_new_syntax("3.4/it.txt", Prism::Translation::Parser34) do
+ s(:begin,
s(:itblock,
s(:send, nil, :x), :it,
- s(:lvar, :it))
- }
+ s(:lvar, :it)),
+ s(:itblock,
+ s(:lambda), :it,
+ s(:lvar, :it)))
+ end
+ end
- assert_equal(it_block_parameter_sexp, actual_ast.to_sexp)
+ def test_nil_block_parameter_syntax
+ assert_new_syntax("4.1/noblock.txt", Prism::Translation::Parser41) do
+ s(:begin,
+ s(:def, :foo,
+ s(:args,
+ s(:blocknilarg)), nil),
+ s(:block,
+ s(:lambda),
+ s(:args,
+ s(:blocknilarg)), nil))
+ end
end
private
@@ -190,11 +222,7 @@ module Prism
parser.diagnostics.all_errors_are_fatal = true
expected_ast, expected_comments, expected_tokens =
- begin
- ignore_warnings { parser.tokenize(buffer) }
- rescue ArgumentError, Parser::SyntaxError
- return
- end
+ ignore_warnings { parser.tokenize(buffer) }
actual_ast, actual_comments, actual_tokens =
ignore_warnings { Prism::Translation::Parser33.new.tokenize(buffer) }
@@ -278,6 +306,16 @@ module Prism
}
end
+ def assert_new_syntax(path, parser, &sexp)
+ fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures", path)
+
+ buffer = Parser::Source::Buffer.new(fixture_path)
+ buffer.source = fixture_path.read
+ actual_ast = parser.new.tokenize(buffer)[0]
+
+ assert_equal(parse_sexp(&sexp), actual_ast.to_sexp)
+ end
+
def parse_sexp(&block)
Class.new { extend AST::Sexp }.instance_eval(&block).to_sexp
end
diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb
index d4b278c28e..4fff630561 100644
--- a/test/prism/ruby/ripper_test.rb
+++ b/test/prism/ruby/ripper_test.rb
@@ -1,36 +1,58 @@
# frozen_string_literal: true
-return if RUBY_VERSION < "3.3" || RUBY_ENGINE == "truffleruby"
+return if RUBY_VERSION < "3.3" || RUBY_ENGINE != "ruby"
require_relative "../test_helper"
+require "ripper"
module Prism
class RipperTest < TestCase
# Skip these tests that Ripper is reporting the wrong results for.
incorrect = [
# Ripper incorrectly attributes the block to the keyword.
- "seattlerb/block_break.txt",
- "seattlerb/block_next.txt",
"seattlerb/block_return.txt",
- "whitequark/break_block.txt",
- "whitequark/next_block.txt",
"whitequark/return_block.txt",
- # Ripper is not accounting for locals created by patterns using the **
- # operator within an `in` clause.
- "seattlerb/parse_pattern_058.txt",
-
# Ripper cannot handle named capture groups in regular expressions.
"regex.txt",
- "regex_char_width.txt",
- "whitequark/lvar_injecting_match.txt",
# Ripper fails to understand some structures that span across heredocs.
- "spanning_heredoc.txt"
+ "spanning_heredoc.txt",
+
+ # Ripper interprets circular keyword arguments as method calls.
+ "3.4/circular_parameters.txt",
+
+ # Ripper doesn't emit `args_add_block` when endless method is prefixed by modifier.
+ "4.0/endless_methods_command_call.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
]
+ if RUBY_VERSION.start_with?("3.3.")
+ incorrect += [
+ "whitequark/lvar_injecting_match.txt",
+ "seattlerb/parse_pattern_058.txt",
+ "regex_char_width.txt",
+ ]
+ end
+
+ if RUBY_VERSION.start_with?("4.")
+ incorrect += [
+ # https://bugs.ruby-lang.org/issues/21945
+ "and_or_with_suffix.txt",
+ ]
+ end
+
+ # https://bugs.ruby-lang.org/issues/21669
+ incorrect << "4.1/void_value.txt"
+ # https://bugs.ruby-lang.org/issues/19107
+ incorrect << "4.1/trailing_comma_after_method_arguments.txt"
+
# Skip these tests that we haven't implemented yet.
- omitted = [
+ omitted_sexp_raw = [
+ "bom_leading_space.txt",
+ "bom_spaces.txt",
"dos_endings.txt",
"heredocs_with_fake_newlines.txt",
"heredocs_with_ignored_newlines.txt",
@@ -51,14 +73,237 @@ module Prism
"whitequark/slash_newline_in_heredocs.txt"
]
- Fixture.each(except: incorrect | omitted) do |fixture|
- define_method(fixture.test_name) { assert_ripper(fixture.read) }
+ omitted_lex = [
+ "heredoc_with_escaped_newline_at_start.txt",
+ "heredocs_with_fake_newlines.txt",
+ "indented_file_end.txt",
+ "spanning_heredoc_newlines.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/procarg0.txt",
+ ]
+
+ omitted_scan = [
+ "bom_leading_space.txt",
+ "bom_spaces.txt",
+ "dos_endings.txt",
+ "heredocs_with_fake_newlines.txt",
+ "rescue_modifier.txt",
+ "seattlerb/block_call_dot_op2_brace_block.txt",
+ "seattlerb/block_command_operation_colon.txt",
+ "seattlerb/block_command_operation_dot.txt",
+ "seattlerb/case_in.txt",
+ "seattlerb/heredoc__backslash_dos_format.txt",
+ "seattlerb/heredoc_backslash_nl.txt",
+ "seattlerb/heredoc_nested.txt",
+ "seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt",
+ "seattlerb/heredoc_squiggly_empty.txt",
+ "seattlerb/masgn_command_call.txt",
+ "seattlerb/messy_op_asgn_lineno.txt",
+ "seattlerb/op_asgn_primary_colon_const_command_call.txt",
+ "seattlerb/parse_pattern_076.txt",
+ "seattlerb/pct_w_heredoc_interp_nested.txt",
+ "tilde_heredocs.txt",
+ "unparser/corpus/literal/assignment.txt",
+ "unparser/corpus/literal/pattern.txt",
+ "unparser/corpus/semantic/dstr.txt",
+ "variables.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/masgn_nested.txt",
+ "whitequark/newline_in_hash_argument.txt",
+ "whitequark/numparam_ruby_bug_19025.txt",
+ "whitequark/op_asgn_cmd.txt",
+ "whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt",
+ "whitequark/parser_slash_slash_n_escaping_in_literals.txt",
+ "whitequark/pattern_matching_nil_pattern.txt",
+ "whitequark/ruby_bug_12402.txt",
+ "whitequark/ruby_bug_18878.txt",
+ "whitequark/send_block_chain_cmd.txt",
+ "whitequark/slash_newline_in_heredocs.txt",
+ ]
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_sexp_raw) do |fixture|
+ define_method("#{fixture.test_name}_sexp_raw") { assert_ripper_sexp_raw(fixture.read) }
+ end
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_lex) do |fixture|
+ define_method("#{fixture.test_name}_lex") { assert_ripper_lex(fixture.read) }
+ end
+
+ def test_lex_ignored_missing_heredoc_end
+ ["", "-", "~"].each do |type|
+ source = "<<#{type}FOO\n"
+ assert_ripper_lex(source)
+
+ source = "<<#{type}'FOO'\n"
+ assert_ripper_lex(source)
+ end
+ end
+
+ UNSUPPORTED_EVENTS = %i[comma ignored_nl nl semicolon sp ignored_sp]
+ # Events that are currently not emitted
+ SUPPORTED_EVENTS = Translation::Ripper::EVENTS - UNSUPPORTED_EVENTS
+ # Events that assert against their line/column
+ CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen words_sep label_end]
+
+ module Events
+ attr_reader :events
+
+ def initialize(...)
+ super
+ @events = []
+ end
+
+ SUPPORTED_EVENTS.each do |event|
+ define_method(:"on_#{event}") do |*args|
+ if CHECK_LOCATION_EVENTS.include?(event)
+ @events << [event, lineno, column, *args]
+ else
+ @events << [event, *args]
+ end
+ super(*args)
+ end
+ end
+ end
+
+ class RipperEvents < Ripper
+ include Events
+ end
+
+ class PrismEvents < Translation::Ripper
+ include Events
+ end
+
+ class ObjectEvents < Translation::Ripper
+ OBJECT = BasicObject.new
+ SUPPORTED_EVENTS.each do |event|
+ define_method(:"on_#{event}") { |*args| OBJECT }
+ end
+ end
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_scan) do |fixture|
+ define_method("#{fixture.test_name}_events") do
+ source = fixture.read
+ # Similar to test/ripper/assert_parse_files.rb in CRuby
+ object_events = ObjectEvents.new(source)
+ assert_nothing_raised { object_events.parse }
+
+ ripper = RipperEvents.new(source, fixture.path)
+ prism = PrismEvents.new(source, fixture.path)
+ ripper.parse
+ prism.parse
+ # Check that the same events are emitted, regardless of order
+ assert_equal(ripper.events.sort_by(&:inspect), prism.events.sort_by(&:inspect))
+ end
+ end
+
+ def test_lexer
+ lexer = Translation::Ripper::Lexer.new("foo")
+ expected = [[1, 0], :on_ident, "foo", Translation::Ripper::EXPR_CMDARG]
+
+ assert_equal([expected], lexer.lex)
+ assert_equal(expected, lexer.parse[0].to_a)
+ assert_equal(lexer.parse[0].to_a, lexer.scan[0].to_a)
+
+ assert_equal(%i[on_int on_sp on_op], Translation::Ripper::Lexer.new("1 +").lex.map { |token| token[1] })
+ assert_raise(SyntaxError) { Translation::Ripper::Lexer.new("1 +").lex(raise_errors: true) }
+ end
+
+
+ # On syntax invalid code the output doesn't always match up
+ # In these cases we just want to make sure that it doesn't raise.
+ def test_lex_invalid_syntax
+ assert_nothing_raised do
+ Translation::Ripper.lex('scan/\p{alpha}/')
+ end
+
+ assert_equal(Ripper.lex('if;)'), Translation::Ripper.lex('if;)'))
+ end
+
+ def test_tokenize
+ source = "foo;1;BAZ"
+ assert_equal(Ripper.tokenize(source), Translation::Ripper.tokenize(source))
+ end
+
+ def test_encoding
+ source = '"わたし"'.encode(Encoding::Windows_31J)
+ assert_equal(Ripper.tokenize(source), Translation::Ripper.tokenize(source))
+ assert_equal(Ripper.sexp(source), Translation::Ripper.sexp(source))
+ end
+
+ def test_sexp_coercion
+ string_like = Object.new
+ def string_like.to_str
+ "a"
+ end
+ assert_equal Ripper.sexp(string_like), Translation::Ripper.sexp(string_like)
+
+ File.open(__FILE__) do |file1|
+ File.open(__FILE__) do |file2|
+ assert_equal Ripper.sexp(file1), Translation::Ripper.sexp(file2)
+ end
+ end
+
+ File.open(__FILE__) do |file1|
+ File.open(__FILE__) do |file2|
+ object1_with_gets = Object.new
+ object1_with_gets.define_singleton_method(:gets) do
+ file1.gets
+ end
+
+ object2_with_gets = Object.new
+ object2_with_gets.define_singleton_method(:gets) do
+ file2.gets
+ end
+
+ assert_equal Ripper.sexp(object1_with_gets), Translation::Ripper.sexp(object2_with_gets)
+ end
+ end
+ end
+
+ def test_lex_coersion
+ string_like = Object.new
+ def string_like.to_str
+ "a"
+ end
+ assert_equal Ripper.lex(string_like), Translation::Ripper.lex(string_like)
+ end
+
+ # Check that the hardcoded values don't change without us noticing.
+ def test_internals
+ actual = Translation::Ripper.constants.select { |name| name.start_with?("EXPR_") }.sort
+ expected = Ripper.constants.select { |name| name.start_with?("EXPR_") }.sort
+
+ assert_equal(expected, actual)
+ expected.zip(actual).each do |ripper, prism|
+ assert_equal(Ripper.const_get(ripper), Translation::Ripper.const_get(prism))
+ end
end
private
- def assert_ripper(source)
+ def assert_ripper_sexp_raw(source)
assert_equal Ripper.sexp_raw(source), Prism::Translation::Ripper.sexp_raw(source)
end
+
+ def assert_ripper_lex(source)
+ prism = Translation::Ripper.lex(source)
+ ripper = Ripper.lex(source)
+
+ # Prism emits tokens by their order in the code, not in parse order
+ ripper.sort_by! { |elem| elem[0] }
+
+ [prism.size, ripper.size].max.times do |index|
+ expected = ripper[index]
+ actual = prism[index]
+
+ # There are some tokens that have slightly different state that do not
+ # effect the parse tree, so they may not match.
+ if expected && actual && expected[1] == actual[1] && %i[on_comment on_heredoc_end on_embexpr_end on_sp].include?(expected[1])
+ expected[3] = actual[3] = nil
+ end
+
+ assert_equal(expected, actual)
+ end
+ end
end
end
diff --git a/test/prism/ruby/ruby_parser_test.rb b/test/prism/ruby/ruby_parser_test.rb
index 03bcfafc42..bc89bdae72 100644
--- a/test/prism/ruby/ruby_parser_test.rb
+++ b/test/prism/ruby/ruby_parser_test.rb
@@ -13,23 +13,12 @@ rescue LoadError
return
end
-# We want to also compare lines and files to make sure we're setting them
-# correctly.
-Sexp.prepend(
- Module.new do
- def ==(other)
- super && line == other.line && file == other.file # && line_max == other.line_max
- end
- end
-)
-
module Prism
class RubyParserTest < TestCase
todos = [
+ "character_literal.txt",
"encoding_euc_jp.txt",
- "newline_terminated.txt",
"regex_char_width.txt",
- "seattlerb/bug169.txt",
"seattlerb/masgn_colon3.txt",
"seattlerb/messy_op_asgn_lineno.txt",
"seattlerb/op_asgn_primary_colon_const_command_call.txt",
@@ -37,15 +26,10 @@ module Prism
"seattlerb/str_lit_concat_bad_encodings.txt",
"strings.txt",
"unescaping.txt",
- "unparser/corpus/literal/kwbegin.txt",
- "unparser/corpus/literal/send.txt",
"whitequark/masgn_const.txt",
"whitequark/pattern_matching_constants.txt",
- "whitequark/pattern_matching_implicit_array_match.txt",
"whitequark/pattern_matching_single_match.txt",
"whitequark/ruby_bug_12402.txt",
- "whitequark/ruby_bug_14690.txt",
- "whitequark/space_args_block.txt"
]
# https://github.com/seattlerb/ruby_parser/issues/344
@@ -53,6 +37,8 @@ module Prism
"alias.txt",
"dsym_str.txt",
"dos_endings.txt",
+ "heredoc_dedent_line_continuation.txt",
+ "heredoc_percent_q_newline_delimiter.txt",
"heredocs_with_fake_newlines.txt",
"heredocs_with_ignored_newlines.txt",
"method_calls.txt",
@@ -73,6 +59,7 @@ module Prism
"spanning_heredoc.txt",
"symbols.txt",
"tilde_heredocs.txt",
+ "unary_method_calls.txt",
"unparser/corpus/literal/literal.txt",
"while.txt",
"whitequark/cond_eflipflop.txt",
@@ -90,10 +77,20 @@ module Prism
"whitequark/ruby_bug_11989.txt",
"whitequark/ruby_bug_18878.txt",
"whitequark/ruby_bug_19281.txt",
- "whitequark/slash_newline_in_heredocs.txt"
+ "whitequark/slash_newline_in_heredocs.txt",
+
+ "3.3-3.3/block_args_in_array_assignment.txt",
+ "3.3-3.3/it_with_ordinary_parameter.txt",
+ "3.3-3.3/keyword_args_in_array_assignment.txt",
+ "3.3-3.3/return_in_sclass.txt",
+
+ "3.3-4.0/void_value.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
]
- Fixture.each(except: failures) do |fixture|
+ Fixture.each_for_version(version: "3.3", except: failures) do |fixture|
define_method(fixture.test_name) do
assert_ruby_parser(fixture, todos.include?(fixture.path))
end
@@ -105,10 +102,16 @@ module Prism
source = fixture.read
expected = ignore_warnings { ::RubyParser.new.parse(source, fixture.path) }
actual = Prism::Translation::RubyParser.new.parse(source, fixture.path)
+ on_failure = -> { message(expected, actual) }
if !allowed_failure
- assert_equal(expected, actual, -> { message(expected, actual) })
- elsif expected == actual
+ assert_equal(expected, actual, on_failure)
+
+ unless actual.nil?
+ assert_equal(expected.line, actual.line, on_failure)
+ assert_equal(expected.file, actual.file, on_failure)
+ end
+ elsif expected == actual && expected.line && actual.line && expected.file == actual.file
puts "#{name} now passes"
end
end
diff --git a/test/prism/ruby/source_test.rb b/test/prism/ruby/source_test.rb
new file mode 100644
index 0000000000..f7cf4fe83a
--- /dev/null
+++ b/test/prism/ruby/source_test.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class SourceTest < TestCase
+ def test_byte_offset
+ source = Prism.parse(<<~SRC).source
+ abcd
+ efgh
+ ijkl
+ SRC
+
+ assert_equal 0, source.byte_offset(1, 0)
+ assert_equal 5, source.byte_offset(2, 0)
+ assert_equal 10, source.byte_offset(3, 0)
+ assert_equal 15, source.byte_offset(4, 0)
+
+ error = assert_raise(ArgumentError) { source.byte_offset(5, 0) }
+ assert_equal "line 5 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(0, 0) }
+ assert_equal "line 0 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(-1, 0) }
+ assert_equal "line -1 is out of range", error.message
+ end
+
+ def test_byte_offset_with_start_line
+ source = Prism.parse(<<~SRC, line: 11).source
+ abcd
+ efgh
+ ijkl
+ SRC
+
+ assert_equal 0, source.byte_offset(11, 0)
+ assert_equal 5, source.byte_offset(12, 0)
+ assert_equal 10, source.byte_offset(13, 0)
+ assert_equal 15, source.byte_offset(14, 0)
+
+ error = assert_raise(ArgumentError) { source.byte_offset(15, 0) }
+ assert_equal "line 15 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(10, 0) }
+ assert_equal "line 10 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(9, 0) }
+ assert_equal "line 9 is out of range", error.message
+ end
+ end
+end
diff --git a/test/prism/snippets_test.rb b/test/prism/snippets_test.rb
index 66802c5dc3..3c28d27a25 100644
--- a/test/prism/snippets_test.rb
+++ b/test/prism/snippets_test.rb
@@ -18,24 +18,24 @@ module Prism
"whitequark/multiple_pattern_matches.txt"
]
- Fixture.each(except: except) do |fixture|
- define_method(fixture.test_name) { assert_snippets(fixture) }
+ Fixture.each_with_all_versions(except: except) do |fixture, version|
+ define_method(fixture.test_name(version)) { assert_snippets(fixture, version) }
end
private
# We test every snippet (separated by \n\n) in isolation to ensure the
# parser does not try to read bytes further than the end of each snippet.
- def assert_snippets(fixture)
+ def assert_snippets(fixture, version)
fixture.read.split(/(?<=\S)\n\n(?=\S)/).each do |snippet|
snippet = snippet.rstrip
- result = Prism.parse(snippet, filepath: fixture.path)
+ result = Prism.parse(snippet, filepath: fixture.path, version: version)
assert result.success?
if !ENV["PRISM_BUILD_MINIMAL"]
- dumped = Prism.dump(snippet, filepath: fixture.path)
- assert_equal_nodes(result.value, Prism.load(snippet, dumped).value)
+ dumped = Prism.dump(snippet, filepath: fixture.path, version: version)
+ assert_equal_nodes(result.value, Prism.load(snippet, dumped, version: version).value)
end
end
end
diff --git a/test/prism/test_helper.rb b/test/prism/test_helper.rb
index 0be9d1e7da..406582c0a5 100644
--- a/test/prism/test_helper.rb
+++ b/test/prism/test_helper.rb
@@ -2,7 +2,6 @@
require "prism"
require "pp"
-require "ripper"
require "stringio"
require "test/unit"
require "tempfile"
@@ -58,8 +57,12 @@ module Prism
File.join(File.expand_path("../..", __dir__), "snapshots", path)
end
- def test_name
- :"test_#{path}"
+ def test_name(version = nil)
+ if version
+ :"test_#{version}_#{path}"
+ else
+ :"test_#{path}"
+ end
end
def self.each(except: [], &block)
@@ -68,6 +71,25 @@ module Prism
paths.each { |path| yield Fixture.new(path) }
end
+ def self.each_for_version(except: [], version:, &block)
+ each(except: except) do |fixture|
+ next unless TestCase.ruby_versions_for(fixture.path).include?(version)
+ yield fixture
+ end
+ end
+
+ def self.each_for_current_ruby(except: [], &block)
+ each_for_version(except: except, version: CURRENT_MAJOR_MINOR, &block)
+ end
+
+ def self.each_with_all_versions(except: [], &block)
+ each(except: except) do |fixture|
+ TestCase.ruby_versions_for(fixture.path).each do |version|
+ yield fixture, version
+ end
+ end
+ end
+
def self.custom_base_path?
ENV.key?("FIXTURE_BASE")
end
@@ -217,6 +239,36 @@ module Prism
RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince/i)
end
+ # All versions that prism can parse
+ SYNTAX_VERSIONS = %w[3.3 3.4 4.0 4.1]
+
+ # `RUBY_VERSION` with the patch version excluded
+ CURRENT_MAJOR_MINOR = RUBY_VERSION.split(".")[0, 2].join(".")
+
+ # Returns an array of ruby versions that a given filepath should test against:
+ # test.txt # => all available versions
+ # 3.4/test.txt # => versions since 3.4 (inclusive)
+ # 3.4-4.2/test.txt # => verisions since 3.4 (inclusive) up to 4.2 (inclusive)
+ def self.ruby_versions_for(filepath)
+ return [ENV['SYNTAX_VERSION']] if ENV['SYNTAX_VERSION']
+
+ parts = filepath.split("/")
+ return SYNTAX_VERSIONS if parts.size == 1
+
+ version_start, version_stop = parts[0].split("-")
+ if version_stop
+ SYNTAX_VERSIONS[SYNTAX_VERSIONS.index(version_start)..SYNTAX_VERSIONS.index(version_stop)]
+ else
+ SYNTAX_VERSIONS[SYNTAX_VERSIONS.index(version_start)..]
+ end
+ end
+
+ if RUBY_VERSION >= "3.3.0"
+ def test_all_syntax_versions_present
+ assert_include(SYNTAX_VERSIONS, CURRENT_MAJOR_MINOR)
+ end
+ end
+
private
if RUBY_ENGINE == "ruby" && RubyVM::InstructionSequence.compile("").to_a[4][:parser] != :prism
diff --git a/test/psych/test_data.rb b/test/psych/test_data.rb
new file mode 100644
index 0000000000..5e340c580a
--- /dev/null
+++ b/test/psych/test_data.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+require_relative 'helper'
+
+class PsychDataWithIvar < Data.define(:foo)
+ attr_reader :bar
+ def initialize(**)
+ @bar = 'hello'
+ super
+ end
+end unless RUBY_VERSION < "3.2"
+
+module Psych
+ class TestData < TestCase
+ class SelfReferentialData < Data.define(:foo)
+ attr_accessor :ref
+ def initialize(foo:)
+ @ref = self
+ super
+ end
+ end unless RUBY_VERSION < "3.2"
+
+ def setup
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ end
+
+ # TODO: move to another test?
+ def test_dump_data
+ assert_equal <<~eoyml, Psych.dump(PsychDataWithIvar["bar"])
+ --- !ruby/data-with-ivars:PsychDataWithIvar
+ members:
+ foo: bar
+ ivars:
+ "@bar": hello
+ eoyml
+ end
+
+ def test_self_referential_data
+ circular = SelfReferentialData.new("foo")
+
+ loaded = Psych.unsafe_load(Psych.dump(circular))
+ assert_instance_of(SelfReferentialData, loaded.ref)
+
+ assert_equal(circular, loaded)
+ assert_same(loaded, loaded.ref)
+ end
+
+ def test_roundtrip
+ thing = PsychDataWithIvar.new("bar")
+ data = Psych.unsafe_load(Psych.dump(thing))
+
+ assert_equal "hello", data.bar
+ assert_equal "bar", data.foo
+ end
+
+ def test_load
+ obj = Psych.unsafe_load(<<~eoyml)
+ --- !ruby/data-with-ivars:PsychDataWithIvar
+ members:
+ foo: bar
+ ivars:
+ "@bar": hello
+ eoyml
+
+ assert_equal "hello", obj.bar
+ assert_equal "bar", obj.foo
+ end
+
+ def test_members_must_be_identical
+ TestData.const_set :D, Data.define(:a, :b)
+ d = Psych.dump(TestData::D.new(1, 2))
+
+ # more members
+ TestData.send :remove_const, :D
+ TestData.const_set :D, Data.define(:a, :b, :c)
+ e = assert_raise(ArgumentError) { Psych.unsafe_load d }
+ assert_equal 'missing keyword: :c', e.message
+
+ # less members
+ TestData.send :remove_const, :D
+ TestData.const_set :D, Data.define(:a)
+ e = assert_raise(ArgumentError) { Psych.unsafe_load d }
+ assert_equal 'unknown keyword: :b', e.message
+
+ # completely different members
+ TestData.send :remove_const, :D
+ TestData.const_set :D, Data.define(:a, :c)
+ e = assert_raise(ArgumentError) { Psych.unsafe_load d }
+ assert_include e.message, 'keyword:'
+ ensure
+ TestData.send :remove_const, :D
+ end
+ end
+end
diff --git a/test/psych/test_exception.rb b/test/psych/test_exception.rb
index c1e69ab18d..6fd92abf9d 100644
--- a/test/psych/test_exception.rb
+++ b/test/psych/test_exception.rb
@@ -82,6 +82,19 @@ module Psych
assert_equal 'omg!', ex.file
end
+ def test_safe_load_stream_takes_file
+ ex = assert_raise(Psych::SyntaxError) do
+ Psych.safe_load_stream '--- `'
+ end
+ assert_nil ex.file
+ assert_match '(<unknown>)', ex.message
+
+ ex = assert_raise(Psych::SyntaxError) do
+ Psych.safe_load_stream '--- `', filename: 'omg!'
+ end
+ assert_equal 'omg!', ex.file
+ end
+
def test_parse_file_exception
Tempfile.create(['parsefile', 'yml']) {|t|
t.binmode
diff --git a/test/psych/test_object_references.rb b/test/psych/test_object_references.rb
index 86bb9034b9..0498d54eec 100644
--- a/test/psych/test_object_references.rb
+++ b/test/psych/test_object_references.rb
@@ -31,6 +31,11 @@ module Psych
assert_reference_trip Struct.new(:foo).new(1)
end
+ def test_data_has_references
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert_reference_trip Data.define(:foo).new(1)
+ end
+
def assert_reference_trip obj
yml = Psych.dump([obj, obj])
assert_match(/\*-?\d+/, yml)
diff --git a/test/psych/test_parser.rb b/test/psych/test_parser.rb
index c1e0abb89d..4ca4d63d80 100644
--- a/test/psych/test_parser.rb
+++ b/test/psych/test_parser.rb
@@ -198,6 +198,48 @@ module Psych
assert_called :end_stream
end
+ def test_parse_io_returns_more_bytes_than_requested
+ # An IO-like source whose #read returns more bytes than the size it was
+ # asked for must not overflow libyaml's read buffer.
+ io = Object.new
+ def io.external_encoding; Encoding::UTF_8 end
+ def io.read len
+ return nil if @done
+ @done = true
+ "--- a\n" + ("#" * (len + (1 << 20)))
+ end
+
+ # CRuby clamps the over-read and parses; JRuby's parser rejects the
+ # over-reading IO with an IOError. Either way there is no overflow.
+ begin
+ @parser.parse io
+ rescue IOError
+ return
+ end
+ assert_called :start_stream
+ assert_called :scalar
+ assert_called :end_stream
+ end
+
+ def test_parse_io_returns_more_bytes_than_requested_multibyte
+ # The over-read is rounded down to a character boundary so a multibyte
+ # character is never split when the copy is clamped.
+ io = Object.new
+ def io.external_encoding; Encoding::UTF_8 end
+ def io.read len
+ return nil if @done
+ @done = true
+ "--- a\n#" + ("あ" * (len + (1 << 20)))
+ end
+
+ begin
+ @parser.parse io
+ rescue IOError
+ return
+ end
+ assert_called :scalar
+ end
+
def test_syntax_error
assert_raise(Psych::SyntaxError) do
@parser.parse("---\n\"foo\"\n\"bar\"\n")
diff --git a/test/psych/test_psych.rb b/test/psych/test_psych.rb
index 42586a8779..4455c471e7 100644
--- a/test/psych/test_psych.rb
+++ b/test/psych/test_psych.rb
@@ -89,6 +89,7 @@ class TestPsych < Psych::TestCase
things = [22, "foo \n", {}]
stream = Psych.dump_stream(*things)
assert_equal things, Psych.load_stream(stream)
+ assert_equal things, Psych.safe_load_stream(stream)
end
def test_dump_file
@@ -119,6 +120,8 @@ class TestPsych < Psych::TestCase
def test_load_stream
docs = Psych.load_stream("--- foo\n...\n--- bar\n...")
assert_equal %w{ foo bar }, docs
+ safe_docs = Psych.safe_load_stream("--- foo\n...\n--- bar\n...")
+ assert_equal %w{ foo bar }, safe_docs
end
def test_load_stream_freeze
@@ -138,10 +141,18 @@ class TestPsych < Psych::TestCase
assert_equal [], Psych.load_stream("")
end
+ def test_safe_load_stream_default_fallback
+ assert_equal [], Psych.safe_load_stream("")
+ end
+
def test_load_stream_raises_on_bad_input
assert_raise(Psych::SyntaxError) { Psych.load_stream("--- `") }
end
+ def test_safe_load_stream_raises_on_bad_input
+ assert_raise(Psych::SyntaxError) { Psych.safe_load_stream("--- `") }
+ end
+
def test_parse_stream
docs = Psych.parse_stream("--- foo\n...\n--- bar\n...")
assert_equal(%w[foo bar], docs.children.map(&:transform))
diff --git a/test/psych/test_psych_set.rb b/test/psych/test_psych_set.rb
new file mode 100644
index 0000000000..c72cd73f18
--- /dev/null
+++ b/test/psych/test_psych_set.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+require_relative 'helper'
+
+module Psych
+ class TestPsychSet < TestCase
+ def setup
+ super
+ @set = Psych::Set.new
+ @set['foo'] = 'bar'
+ @set['bar'] = 'baz'
+ end
+
+ def test_dump
+ assert_match(/!set/, Psych.dump(@set))
+ end
+
+ def test_roundtrip
+ assert_cycle(@set)
+ end
+
+ ###
+ # FIXME: Syck should also support !!set as shorthand
+ def test_load_from_yaml
+ loaded = Psych.unsafe_load(<<-eoyml)
+--- !set
+foo: bar
+bar: baz
+ eoyml
+ assert_equal(@set, loaded)
+ end
+
+ def test_loaded_class
+ assert_instance_of(Psych::Set, Psych.unsafe_load(Psych.dump(@set)))
+ end
+
+ def test_set_shorthand
+ loaded = Psych.unsafe_load(<<-eoyml)
+--- !!set
+foo: bar
+bar: baz
+ eoyml
+ assert_instance_of(Psych::Set, loaded)
+ end
+
+ def test_set_self_reference
+ @set['self'] = @set
+ assert_cycle(@set)
+ end
+
+ def test_stringify_names
+ @set[:symbol] = :value
+
+ assert_match(/^:symbol: :value/, Psych.dump(@set))
+ assert_match(/^symbol: :value/, Psych.dump(@set, stringify_names: true))
+ end
+ end
+end
diff --git a/test/psych/test_ractor.rb b/test/psych/test_ractor.rb
index 1b0d810609..f1c8327aa3 100644
--- a/test/psych/test_ractor.rb
+++ b/test/psych/test_ractor.rb
@@ -7,7 +7,7 @@ class TestPsychRactor < Test::Unit::TestCase
obj = {foo: [42]}
obj2 = Ractor.new(obj) do |obj|
Psych.unsafe_load(Psych.dump(obj))
- end.take
+ end.value
assert_equal obj, obj2
RUBY
end
@@ -33,7 +33,7 @@ class TestPsychRactor < Test::Unit::TestCase
val * 2
end
Psych.load('--- !!omap hello')
- end.take
+ end.value
assert_equal 'hellohello', r
assert_equal 'hello', Psych.load('--- !!omap hello')
RUBY
@@ -43,7 +43,7 @@ class TestPsychRactor < Test::Unit::TestCase
assert_ractor(<<~RUBY, require_relative: 'helper')
r = Ractor.new do
Psych.libyaml_version.join('.') == Psych::LIBYAML_VERSION
- end.take
+ end.value
assert_equal true, r
RUBY
end
diff --git a/test/psych/test_safe_load.rb b/test/psych/test_safe_load.rb
index a9ed737528..e6ca1e142b 100644
--- a/test/psych/test_safe_load.rb
+++ b/test/psych/test_safe_load.rb
@@ -114,6 +114,38 @@ module Psych
end
end
+ D = Data.define(:d) unless RUBY_VERSION < "3.2"
+
+ def test_data_depends_on_sym
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert_safe_cycle(D.new(nil), permitted_classes: [D, Symbol])
+ assert_raise(Psych::DisallowedClass) do
+ cycle D.new(nil), permitted_classes: [D]
+ end
+ end
+
+ def test_anon_data
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert Psych.safe_load(<<-eoyml, permitted_classes: [Data, Symbol])
+--- !ruby/data
+ foo: bar
+ eoyml
+
+ assert_raise(Psych::DisallowedClass) do
+ Psych.safe_load(<<-eoyml, permitted_classes: [Data])
+--- !ruby/data
+ foo: bar
+ eoyml
+ end
+
+ assert_raise(Psych::DisallowedClass) do
+ Psych.safe_load(<<-eoyml, permitted_classes: [Symbol])
+--- !ruby/data
+ foo: bar
+ eoyml
+ end
+ end
+
def test_safe_load_default_fallback
assert_nil Psych.safe_load("")
end
diff --git a/test/psych/test_scalar_scanner.rb b/test/psych/test_scalar_scanner.rb
index 2637a74df8..bc6a74ad8b 100644
--- a/test/psych/test_scalar_scanner.rb
+++ b/test/psych/test_scalar_scanner.rb
@@ -138,6 +138,11 @@ module Psych
assert_equal '-0b___', scanner.tokenize('-0b___')
end
+ def test_scan_without_parse_symbols
+ scanner = Psych::ScalarScanner.new ClassLoader.new, parse_symbols: false
+ assert_equal ':foo', scanner.tokenize(':foo')
+ end
+
def test_scan_int_commas_and_underscores
# NB: This test is to ensure backward compatibility with prior Psych versions,
# not to test against any actual YAML specification.
diff --git a/test/psych/test_serialize_subclasses.rb b/test/psych/test_serialize_subclasses.rb
index 344c79b3ef..640c331337 100644
--- a/test/psych/test_serialize_subclasses.rb
+++ b/test/psych/test_serialize_subclasses.rb
@@ -35,5 +35,23 @@ module Psych
so = StructSubclass.new('foo', [1,2,3])
assert_equal so, Psych.unsafe_load(Psych.dump(so))
end
+
+ class DataSubclass < Data.define(:foo)
+ def initialize(foo:)
+ @bar = "hello #{foo}"
+ super(foo: foo)
+ end
+
+ def == other
+ super(other) && @bar == other.instance_eval{ @bar }
+ end
+ end unless RUBY_VERSION < "3.2"
+
+ def test_data_subclass
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ so = DataSubclass.new('foo')
+ assert_equal so, Psych.unsafe_load(Psych.dump(so))
+ end
+
end
end
diff --git a/test/psych/test_set.rb b/test/psych/test_set.rb
index b4968d3425..ccd591c626 100644
--- a/test/psych/test_set.rb
+++ b/test/psych/test_set.rb
@@ -1,57 +1,36 @@
+# encoding: UTF-8
# frozen_string_literal: true
require_relative 'helper'
+require 'set' unless defined?(Set)
module Psych
class TestSet < TestCase
def setup
- super
- @set = Psych::Set.new
- @set['foo'] = 'bar'
- @set['bar'] = 'baz'
+ @set = ::Set.new([1, 2, 3])
end
def test_dump
- assert_match(/!set/, Psych.dump(@set))
+ assert_equal <<~YAML, Psych.dump(@set)
+ --- !ruby/object:Set
+ hash:
+ 1: true
+ 2: true
+ 3: true
+ YAML
end
- def test_roundtrip
- assert_cycle(@set)
- end
-
- ###
- # FIXME: Syck should also support !!set as shorthand
- def test_load_from_yaml
- loaded = Psych.unsafe_load(<<-eoyml)
---- !set
-foo: bar
-bar: baz
- eoyml
- assert_equal(@set, loaded)
+ def test_load
+ assert_equal @set, Psych.load(<<~YAML, permitted_classes: [::Set])
+ --- !ruby/object:Set
+ hash:
+ 1: true
+ 2: true
+ 3: true
+ YAML
end
- def test_loaded_class
- assert_instance_of(Psych::Set, Psych.unsafe_load(Psych.dump(@set)))
- end
-
- def test_set_shorthand
- loaded = Psych.unsafe_load(<<-eoyml)
---- !!set
-foo: bar
-bar: baz
- eoyml
- assert_instance_of(Psych::Set, loaded)
- end
-
- def test_set_self_reference
- @set['self'] = @set
- assert_cycle(@set)
- end
-
- def test_stringify_names
- @set[:symbol] = :value
-
- assert_match(/^:symbol: :value/, Psych.dump(@set))
- assert_match(/^symbol: :value/, Psych.dump(@set, stringify_names: true))
+ def test_roundtrip
+ assert_equal @set, Psych.load(Psych.dump(@set), permitted_classes: [::Set])
end
end
end
diff --git a/test/psych/test_stream.rb b/test/psych/test_stream.rb
index 9b71c6d996..ae940d1ee4 100644
--- a/test/psych/test_stream.rb
+++ b/test/psych/test_stream.rb
@@ -54,6 +54,14 @@ module Psych
assert_equal %w{ foo bar }, list
end
+ def test_safe_load_stream_yields_documents
+ list = []
+ Psych.safe_load_stream("--- foo\n...\n--- bar") do |ruby|
+ list << ruby
+ end
+ assert_equal %w{ foo bar }, list
+ end
+
def test_load_stream_break
list = []
Psych.load_stream("--- foo\n...\n--- `") do |ruby|
diff --git a/test/psych/test_stringio.rb b/test/psych/test_stringio.rb
new file mode 100644
index 0000000000..7fef1402a0
--- /dev/null
+++ b/test/psych/test_stringio.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+require_relative 'helper'
+
+module Psych
+ class TestStringIO < TestCase
+ # The superclass of StringIO before Ruby 3.0 was `Data`,
+ # which can interfere with the Ruby 3.2+ `Data` dumping.
+ def test_stringio
+ assert_nothing_raised do
+ Psych.dump(StringIO.new("foo"))
+ end
+ end
+ end
+end
diff --git a/test/psych/test_yaml.rb b/test/psych/test_yaml.rb
index 897a7c8935..134c346c90 100644
--- a/test/psych/test_yaml.rb
+++ b/test/psych/test_yaml.rb
@@ -6,6 +6,7 @@ require_relative 'helper'
# [ruby-core:01946]
module Psych_Tests
StructTest = Struct::new( :c )
+ DataTest = Data.define( :c ) unless RUBY_VERSION < "3.2"
end
class Psych_Unit_Tests < Psych::TestCase
@@ -35,6 +36,10 @@ class Psych_Unit_Tests < Psych::TestCase
assert_cycle(Regexp.new("foo\nbar"))
end
+ def test_regexp_with_slash
+ assert_cycle(Regexp.new('/'))
+ end
+
# [ruby-core:34969]
def test_regexp_with_n
assert_cycle(Regexp.new('',Regexp::NOENCODING))
@@ -1037,7 +1042,6 @@ EOY
end
def test_ruby_struct
- Struct.send(:remove_const, :MyBookStruct) if Struct.const_defined?(:MyBookStruct)
# Ruby structures
book_struct = Struct::new( "MyBookStruct", :author, :title, :year, :isbn )
assert_to_yaml(
@@ -1069,6 +1073,47 @@ EOY
c: 123
EOY
+ ensure
+ Struct.__send__(:remove_const, :MyBookStruct) if book_struct
+ end
+
+ def test_ruby_data
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ # Ruby Data value objects
+ book_class = Data.define(:author, :title, :year, :isbn)
+ Object.const_set(:MyBookData, book_class)
+ assert_to_yaml(
+ [ book_class.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" ),
+ book_class.new( [ 'Dave Thomas', 'Andy Hunt' ], "The Pickaxe", 2002,
+ book_class.new( "This should be the ISBN", "but I have more data here", 2002, "None" )
+ )
+ ], <<EOY
+- !ruby/data:MyBookData
+ author: Yukihiro Matsumoto
+ title: Ruby in a Nutshell
+ year: 2002
+ isbn: 0-596-00214-9
+- !ruby/data:MyBookData
+ author:
+ - Dave Thomas
+ - Andy Hunt
+ title: The Pickaxe
+ year: 2002
+ isbn: !ruby/data:MyBookData
+ author: This should be the ISBN
+ title: but I have more data here
+ year: 2002
+ isbn: None
+EOY
+ )
+
+ assert_to_yaml( Psych_Tests::DataTest.new( 123 ), <<EOY )
+--- !ruby/data:Psych_Tests::DataTest
+c: 123
+EOY
+
+ ensure
+ Object.__send__(:remove_const, :MyBookData) if book_class
end
def test_ruby_rational
diff --git a/test/psych/test_yaml_special_cases.rb b/test/psych/test_yaml_special_cases.rb
index 205457bcae..f1a607783e 100644
--- a/test/psych/test_yaml_special_cases.rb
+++ b/test/psych/test_yaml_special_cases.rb
@@ -15,6 +15,7 @@ module Psych
s = ""
assert_equal false, Psych.unsafe_load(s)
assert_equal [], Psych.load_stream(s)
+ assert_equal [], Psych.safe_load_stream(s)
assert_equal false, Psych.parse(s)
assert_equal [], Psych.parse_stream(s).transform
assert_nil Psych.safe_load(s)
@@ -24,6 +25,7 @@ module Psych
s = "false"
assert_equal false, Psych.load(s)
assert_equal [false], Psych.load_stream(s)
+ assert_equal [false], Psych.safe_load_stream(s)
assert_equal false, Psych.parse(s).transform
assert_equal [false], Psych.parse_stream(s).transform
assert_equal false, Psych.safe_load(s)
@@ -33,6 +35,7 @@ module Psych
s = "n"
assert_equal "n", Psych.load(s)
assert_equal ["n"], Psych.load_stream(s)
+ assert_equal ["n"], Psych.safe_load_stream(s)
assert_equal "n", Psych.parse(s).transform
assert_equal ["n"], Psych.parse_stream(s).transform
assert_equal "n", Psych.safe_load(s)
@@ -42,6 +45,7 @@ module Psych
s = "off"
assert_equal false, Psych.load(s)
assert_equal [false], Psych.load_stream(s)
+ assert_equal [false], Psych.safe_load_stream(s)
assert_equal false, Psych.parse(s).transform
assert_equal [false], Psych.parse_stream(s).transform
assert_equal false, Psych.safe_load(s)
@@ -51,6 +55,7 @@ module Psych
s = "-.inf"
assert_equal(-Float::INFINITY, Psych.load(s))
assert_equal([-Float::INFINITY], Psych.load_stream(s))
+ assert_equal([-Float::INFINITY], Psych.safe_load_stream(s))
assert_equal(-Float::INFINITY, Psych.parse(s).transform)
assert_equal([-Float::INFINITY], Psych.parse_stream(s).transform)
assert_equal(-Float::INFINITY, Psych.safe_load(s))
@@ -60,6 +65,7 @@ module Psych
s = ".NaN"
assert Psych.load(s).nan?
assert Psych.load_stream(s).first.nan?
+ assert Psych.safe_load_stream(s).first.nan?
assert Psych.parse(s).transform.nan?
assert Psych.parse_stream(s).transform.first.nan?
assert Psych.safe_load(s).nan?
@@ -69,6 +75,7 @@ module Psych
s = "0xC"
assert_equal 12, Psych.load(s)
assert_equal [12], Psych.load_stream(s)
+ assert_equal [12], Psych.safe_load_stream(s)
assert_equal 12, Psych.parse(s).transform
assert_equal [12], Psych.parse_stream(s).transform
assert_equal 12, Psych.safe_load(s)
@@ -78,6 +85,7 @@ module Psych
s = "<<"
assert_equal "<<", Psych.load(s)
assert_equal ["<<"], Psych.load_stream(s)
+ assert_equal ["<<"], Psych.safe_load_stream(s)
assert_equal "<<", Psych.parse(s).transform
assert_equal ["<<"], Psych.parse_stream(s).transform
assert_equal "<<", Psych.safe_load(s)
@@ -87,6 +95,7 @@ module Psych
s = "<<: {}"
assert_equal({}, Psych.load(s))
assert_equal [{}], Psych.load_stream(s)
+ assert_equal [{}], Psych.safe_load_stream(s)
assert_equal({}, Psych.parse(s).transform)
assert_equal [{}], Psych.parse_stream(s).transform
assert_equal({}, Psych.safe_load(s))
@@ -96,6 +105,7 @@ module Psych
s = "- 1000\n- +1000\n- 1_000"
assert_equal [1000, 1000, 1000], Psych.load(s)
assert_equal [[1000, 1000, 1000]], Psych.load_stream(s)
+ assert_equal [[1000, 1000, 1000]], Psych.safe_load_stream(s)
assert_equal [1000, 1000, 1000], Psych.parse(s).transform
assert_equal [[1000, 1000, 1000]], Psych.parse_stream(s).transform
assert_equal [1000, 1000, 1000], Psych.safe_load(s)
@@ -105,6 +115,7 @@ module Psych
s = "[8, 08, 0o10, 010]"
assert_equal [8, "08", "0o10", 8], Psych.load(s)
assert_equal [[8, "08", "0o10", 8]], Psych.load_stream(s)
+ assert_equal [[8, "08", "0o10", 8]], Psych.safe_load_stream(s)
assert_equal [8, "08", "0o10", 8], Psych.parse(s).transform
assert_equal [[8, "08", "0o10", 8]], Psych.parse_stream(s).transform
assert_equal [8, "08", "0o10", 8], Psych.safe_load(s)
@@ -114,6 +125,7 @@ module Psych
s = "null"
assert_nil Psych.load(s)
assert_equal [nil], Psych.load_stream(s)
+ assert_equal [nil], Psych.safe_load_stream(s)
assert_nil Psych.parse(s).transform
assert_equal [nil], Psych.parse_stream(s).transform
assert_nil Psych.safe_load(s)
diff --git a/test/psych/visitors/test_to_ruby.rb b/test/psych/visitors/test_to_ruby.rb
index 89c3676651..c9b501dfa2 100644
--- a/test/psych/visitors/test_to_ruby.rb
+++ b/test/psych/visitors/test_to_ruby.rb
@@ -328,6 +328,12 @@ description:
mapping.children << Nodes::Scalar.new('bar')
assert_equal({'foo' => 'bar'}, mapping.to_ruby)
end
+
+ def test_parse_symbols
+ node = Nodes::Scalar.new(':foo')
+ assert_equal :foo, node.to_ruby
+ assert_equal ':foo', node.to_ruby(parse_symbols: false)
+ end
end
end
end
diff --git a/test/psych/visitors/test_yaml_tree.rb b/test/psych/visitors/test_yaml_tree.rb
index 01e685134a..bd3919f83d 100644
--- a/test/psych/visitors/test_yaml_tree.rb
+++ b/test/psych/visitors/test_yaml_tree.rb
@@ -73,6 +73,27 @@ module Psych
assert_equal s.method, obj.method
end
+ D = Data.define(:foo) unless RUBY_VERSION < "3.2"
+
+ def test_data
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert_cycle D.new('bar')
+ end
+
+ def test_data_anon
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ d = Data.define(:foo).new('bar')
+ obj = Psych.unsafe_load(Psych.dump(d))
+ assert_equal d.foo, obj.foo
+ end
+
+ def test_data_override_method
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ d = Data.define(:method).new('override')
+ obj = Psych.unsafe_load(Psych.dump(d))
+ assert_equal d.method, obj.method
+ end
+
def test_exception
ex = Exception.new 'foo'
loaded = Psych.unsafe_load(Psych.dump(ex))
diff --git a/test/resolv/test_dns.rb b/test/resolv/test_dns.rb
index 0a06fba3e7..0b81118c8c 100644
--- a/test/resolv/test_dns.rb
+++ b/test/resolv/test_dns.rb
@@ -525,6 +525,8 @@ class TestResolvDNS < Test::Unit::TestCase
if RUBY_PLATFORM.match?(/mingw/)
# cannot repo locally
omit 'Timeout Error on MinGW CI'
+ elsif macos?([26,1]..[])
+ omit 'Timeout Error on macOS 26.1+'
else
raise Timeout::Error
end
@@ -627,6 +629,13 @@ class TestResolvDNS < Test::Unit::TestCase
assert_operator(2**14, :<, m.to_s.length)
end
+ def test_too_long_address
+ too_long_address_message = [0, 0, 1, 0, 0, 0].pack("n*") + "\x01x" * 129 + [0, 0, 0].pack("cnn")
+ assert_raise_with_message(Resolv::DNS::DecodeError, /name label data exceed 255 octets/) do
+ Resolv::DNS::Message.decode too_long_address_message
+ end
+ end
+
def assert_no_fd_leak
socket = assert_throw(self) do |tag|
Resolv::DNS.stub(:bind_random_port, ->(s, *) {throw(tag, s)}) do
@@ -712,13 +721,14 @@ class TestResolvDNS < Test::Unit::TestCase
client_thread = Thread.new do
Resolv::DNS.open(nameserver_port: [[server1_address, server1_port], [server2_address, server2_port]]) do |dns|
- dns.timeouts = [0.1, 0.2]
+ dns.timeouts = [EnvUtil.apply_timeout_scale(0.5),
+ EnvUtil.apply_timeout_scale(1)]
dns.getresources('foo.example.org', Resolv::DNS::Resource::IN::A)
end
end
udp_server1_thread = Thread.new do
- msg, (_, client_port, _, client_address) = Timeout.timeout(5) { u1.recvfrom(4096) }
+ msg, (_, client_port, _, client_address) = Timeout.timeout(EnvUtil.apply_timeout_scale(5)) { u1.recvfrom(4096) }
id, word2, _qdcount, _ancount, _nscount, _arcount = msg.unpack('nnnnnn')
opcode = (word2 & 0x7800) >> 11
rd = (word2 & 0x0100) >> 8
@@ -813,4 +823,124 @@ class TestResolvDNS < Test::Unit::TestCase
end
end
end
+
+ def test_tcp_connection_closed_before_length
+ with_tcp('127.0.0.1', 0) do |t|
+ _, server_port, _, server_address = t.addr
+
+ server_thread = Thread.new do
+ ct = t.accept
+ ct.recv(512)
+ ct.close
+ end
+
+ client_thread = Thread.new do
+ requester = Resolv::DNS::Requester::TCP.new(server_address, server_port)
+ begin
+ msg = Resolv::DNS::Message.new
+ msg.add_question('example.org', Resolv::DNS::Resource::IN::A)
+ sender = requester.sender(msg, msg)
+ assert_raise(Resolv::ResolvTimeout) do
+ requester.request(sender, 2)
+ end
+ ensure
+ requester.close
+ end
+ end
+
+ server_thread.join
+ client_thread.join
+ end
+ end
+
+ def test_tcp_connection_closed_after_length
+ with_tcp('127.0.0.1', 0) do |t|
+ _, server_port, _, server_address = t.addr
+
+ server_thread = Thread.new do
+ ct = t.accept
+ ct.recv(512)
+ ct.send([100].pack('n'), 0)
+ ct.close
+ end
+
+ client_thread = Thread.new do
+ requester = Resolv::DNS::Requester::TCP.new(server_address, server_port)
+ begin
+ msg = Resolv::DNS::Message.new
+ msg.add_question('example.org', Resolv::DNS::Resource::IN::A)
+ sender = requester.sender(msg, msg)
+ assert_raise(Resolv::ResolvTimeout) do
+ requester.request(sender, 2)
+ end
+ ensure
+ requester.close
+ end
+ end
+
+ server_thread.join
+ client_thread.join
+ end
+ end
+
+ def test_tcp_connection_closed_with_partial_length_prefix
+ with_tcp('127.0.0.1', 0) do |t|
+ _, server_port, _, server_address = t.addr
+
+ server_thread = Thread.new do
+ ct = t.accept
+ ct.recv(512)
+ ct.write "A" # 1 byte
+ ct.close
+ end
+
+ client_thread = Thread.new do
+ requester = Resolv::DNS::Requester::TCP.new(server_address, server_port)
+ begin
+ msg = Resolv::DNS::Message.new
+ msg.add_question('example.org', Resolv::DNS::Resource::IN::A)
+ sender = requester.sender(msg, msg)
+ assert_raise(Resolv::ResolvTimeout) do
+ requester.request(sender, 2)
+ end
+ ensure
+ requester.close
+ end
+ end
+
+ server_thread.join
+ client_thread.join
+ end
+ end
+
+ def test_tcp_connection_closed_with_partial_message_body
+ with_tcp('127.0.0.1', 0) do |t|
+ _, server_port, _, server_address = t.addr
+
+ server_thread = Thread.new do
+ ct = t.accept
+ ct.recv(512)
+ ct.write([10].pack('n')) # length 10
+ ct.write "12345" # 5 bytes (partial)
+ ct.close
+ end
+
+ client_thread = Thread.new do
+ requester = Resolv::DNS::Requester::TCP.new(server_address, server_port)
+ begin
+ msg = Resolv::DNS::Message.new
+ msg.add_question('example.org', Resolv::DNS::Resource::IN::A)
+ sender = requester.sender(msg, msg)
+ assert_raise(Resolv::ResolvTimeout) do
+ requester.request(sender, 2)
+ end
+ ensure
+ requester.close
+ end
+ end
+
+ server_thread.join
+ client_thread.join
+ end
+ end
end
diff --git a/test/resolv/test_resource.rb b/test/resolv/test_resource.rb
index 434380236e..3a1c9ae3c3 100644
--- a/test/resolv/test_resource.rb
+++ b/test/resolv/test_resource.rb
@@ -20,10 +20,6 @@ class TestResolvResource < Test::Unit::TestCase
assert_equal(@name1.hash, @name2.hash, bug10857)
end
- def test_coord
- Resolv::LOC::Coord.create('1 2 1.1 N')
- end
-
def test_srv_no_compress
# Domain name in SRV RDATA should not be compressed
issue29 = 'https://github.com/ruby/resolv/issues/29'
@@ -33,6 +29,76 @@ class TestResolvResource < Test::Unit::TestCase
end
end
+class TestResolvResourceLOC < Test::Unit::TestCase
+ def test_size_create
+ assert_size("0.0m", 0, 0)
+ assert_size("0.01m", 1, 0)
+ assert_size("0.09m", 9, 0)
+ assert_size("0.11m", 1, 1)
+ assert_size("1.0m", 1, 2)
+ assert_size("1234.56m", 1, 5)
+ assert_size("12345678.90m", 1, 9)
+ assert_size("98765432.10m", 9, 9)
+ assert_raise(ArgumentError) {Resolv::LOC::Size.create("100000000.00m")}
+ end
+
+ private def assert_size(input, base, power)
+ size = Resolv::LOC::Size.create(input)
+ assert_equal([(base << 4) + power], size.scalar.unpack("C"))
+ assert_equal(size, Resolv::LOC::Size.create(size.to_s))
+ end
+
+ def test_coord
+ assert_coord('1 2 1.1 N', 'lat', 0x8038c78c)
+ assert_coord('42 21 43.952 N', 'lat', 0x89170690)
+ assert_coord('71 5 6.344 W', 'lon', 0x70bf2dd8)
+ assert_coord('52 14 05.000 N', 'lat', 0x8b3556c8)
+ assert_coord('90 0 0.000 N', 'lat', 0x934fd900)
+ assert_coord('90 0 0.000 S', 'lat', 0x6cb02700)
+ assert_coord('00 8 50.000 E', 'lon', 0x80081650)
+ assert_coord('0 8 50.001 E', 'lon', 0x80081651)
+ assert_coord('32 07 19.000 S', 'lat', 0x791b7d28)
+ assert_coord('116 02 25.000 E', 'lon', 0x98e64868)
+ assert_coord('116 02 25.000 W', 'lon', 0x6719b798)
+ assert_coord('180 00 00.000 E', 'lon', 0xa69fb200)
+ assert_coord('180 00 00.000 W', 'lon', 0x59604e00)
+ assert_raise(ArgumentError) {Resolv::LOC::Coord.create('90 0 0.001 N')}
+ assert_raise(ArgumentError) {Resolv::LOC::Coord.create('90 0 0.001 S')}
+ assert_raise(ArgumentError) {Resolv::LOC::Coord.create('180 0 0.001 E')}
+ assert_raise(ArgumentError) {Resolv::LOC::Coord.create('180 0 0.001 W')}
+ end
+
+ private def assert_coord(input, orientation, coordinate)
+ coord = Resolv::LOC::Coord.create(input)
+
+ assert_equal(orientation, coord.orientation)
+ assert_equal([coordinate].pack("N"), coord.coordinates)
+ assert_equal(coord, Resolv::LOC::Coord.create(coord.to_s))
+ end
+
+ def test_alt
+ assert_alt("0.0m", 0)
+ assert_alt("+0.0m", 0)
+ assert_alt("-0.0m", 0)
+ assert_alt("+0.01m", 1)
+ assert_alt("1.0m", 100)
+ assert_alt("+1.0m", 100)
+ assert_alt("100000.0m", +10000000)
+ assert_alt("+100000.0m", +10000000)
+ assert_alt("-100000.0m", -10000000)
+ assert_alt("+42849672.95m", 0xffff_ffff-100_000_00)
+ assert_raise(ArgumentError) {Resolv::LOC::Alt.create("-100000.01m")}
+ assert_raise(ArgumentError) {Resolv::LOC::Alt.create("+42849672.96m")}
+ end
+
+ private def assert_alt(input, altitude)
+ alt = Resolv::LOC::Alt.create(input)
+
+ assert_equal([altitude + 1e7].pack("N"), alt.altitude)
+ assert_equal(alt, Resolv::LOC::Alt.create(alt.to_s))
+ end
+end
+
class TestResolvResourceCAA < Test::Unit::TestCase
def test_caa_roundtrip
raw_msg = "\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x03new\x07example\x03com\x00\x01\x01\x00\x01\x00\x00\x00\x00\x00\x16\x00\x05issueca1.example.net\xC0\x0C\x01\x01\x00\x01\x00\x00\x00\x00\x00\x0C\x80\x03tbsUnknown".b
diff --git a/test/resolv/test_win32_config.rb b/test/resolv/test_win32_config.rb
new file mode 100644
index 0000000000..6167af6605
--- /dev/null
+++ b/test/resolv/test_win32_config.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'test/unit'
+require 'resolv'
+
+if defined?(Win32::Resolve)
+ class TestWin32Config < Test::Unit::TestCase
+ def test_get_item_property_string
+ # Test reading a string registry value
+ result = Win32::Resolv.send(:get_hosts_dir)
+
+ # Should return a string (empty or with a path)
+ assert_instance_of String, result
+ end
+
+ # Test reading a non-existent registry key
+ def test_nonexistent_key
+ assert_nil(Win32::Resolv.send(:tcpip_params) {|reg| reg.open('NonExistentKeyThatShouldNotExist')})
+ end
+
+ # Test reading a non-existent registry value
+ def test_nonexistent_value
+ assert_nil(Win32::Resolv.send(:tcpip_params) {|reg| reg.value('NonExistentKeyThatShouldNotExist')})
+ end
+ end
+end
diff --git a/test/ripper/assert_parse_files.rb b/test/ripper/assert_parse_files.rb
index 0d583a99e3..4f08589e41 100644
--- a/test/ripper/assert_parse_files.rb
+++ b/test/ripper/assert_parse_files.rb
@@ -40,6 +40,7 @@ class TestRipper::Generic < Test::Unit::TestCase
end
}
end
+ assert(true) if scripts.empty?
end;
end
end
diff --git a/test/ripper/test_lexer.rb b/test/ripper/test_lexer.rb
index 7a2c22ff2d..4bc6fd7ced 100644
--- a/test/ripper/test_lexer.rb
+++ b/test/ripper/test_lexer.rb
@@ -586,6 +586,58 @@ world"
assert_lexer(expected, code)
end
+ def test_fluent_and
+ code = "foo\n" "and"
+ expected = [
+ [[1, 0], :on_ident, "foo", state(:EXPR_CMDARG)],
+ [[1, 3], :on_ignored_nl, "\n", state(:EXPR_CMDARG)],
+ [[2, 0], :on_kw, "and", state(:EXPR_BEG)],
+ ]
+ assert_lexer(expected, code)
+
+ code = "foo\n" "and?"
+ expected = [
+ [[1, 0], :on_ident, "foo", state(:EXPR_CMDARG)],
+ [[1, 3], :on_nl, "\n", state(:EXPR_BEG)],
+ [[2, 0], :on_ident, "and?", state(:EXPR_CMDARG)],
+ ]
+ assert_lexer(expected, code)
+
+ code = "foo\n" "and!"
+ expected = [
+ [[1, 0], :on_ident, "foo", state(:EXPR_CMDARG)],
+ [[1, 3], :on_nl, "\n", state(:EXPR_BEG)],
+ [[2, 0], :on_ident, "and!", state(:EXPR_CMDARG)],
+ ]
+ assert_lexer(expected, code)
+ end
+
+ def test_fluent_or
+ code = "foo\n" "or"
+ expected = [
+ [[1, 0], :on_ident, "foo", state(:EXPR_CMDARG)],
+ [[1, 3], :on_ignored_nl, "\n", state(:EXPR_CMDARG)],
+ [[2, 0], :on_kw, "or", state(:EXPR_BEG)],
+ ]
+ assert_lexer(expected, code)
+
+ code = "foo\n" "or?"
+ expected = [
+ [[1, 0], :on_ident, "foo", state(:EXPR_CMDARG)],
+ [[1, 3], :on_nl, "\n", state(:EXPR_BEG)],
+ [[2, 0], :on_ident, "or?", state(:EXPR_CMDARG)],
+ ]
+ assert_lexer(expected, code)
+
+ code = "foo\n" "or!"
+ expected = [
+ [[1, 0], :on_ident, "foo", state(:EXPR_CMDARG)],
+ [[1, 3], :on_nl, "\n", state(:EXPR_BEG)],
+ [[2, 0], :on_ident, "or!", state(:EXPR_CMDARG)],
+ ]
+ assert_lexer(expected, code)
+ end
+
def assert_lexer(expected, code)
assert_equal(code, Ripper.tokenize(code).join(""))
assert_equal(expected, result = Ripper.lex(code),
diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb
index aa7434c083..3e72c7a331 100644
--- a/test/ripper/test_parser_events.rb
+++ b/test/ripper/test_parser_events.rb
@@ -482,6 +482,13 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
thru_call = false
assert_nothing_raised {
+ tree = parse("a b do end.()", :on_call) {thru_call = true}
+ }
+ assert_equal true, thru_call
+ assert_equal "[call(command(a,[vcall(b)],&do_block(,bodystmt([void()]))),.,call,[])]", tree
+
+ thru_call = false
+ assert_nothing_raised {
tree = parse("self::foo", :on_call) {thru_call = true}
}
assert_equal true, thru_call
diff --git a/test/ruby/box/a.1_1_0.rb b/test/ruby/box/a.1_1_0.rb
new file mode 100644
index 0000000000..0322585097
--- /dev/null
+++ b/test/ruby/box/a.1_1_0.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class BOX_A
+ VERSION = "1.1.0"
+
+ def yay
+ "yay #{VERSION}"
+ end
+end
+
+module BOX_B
+ VERSION = "1.1.0"
+
+ def self.yay
+ "yay_b1"
+ end
+end
diff --git a/test/ruby/box/a.1_2_0.rb b/test/ruby/box/a.1_2_0.rb
new file mode 100644
index 0000000000..29813ea57b
--- /dev/null
+++ b/test/ruby/box/a.1_2_0.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class BOX_A
+ VERSION = "1.2.0"
+
+ def yay
+ "yay #{VERSION}"
+ end
+end
+
+module BOX_B
+ VERSION = "1.2.0"
+
+ def self.yay
+ "yay_b1"
+ end
+end
diff --git a/test/ruby/box/a.rb b/test/ruby/box/a.rb
new file mode 100644
index 0000000000..26a622c92b
--- /dev/null
+++ b/test/ruby/box/a.rb
@@ -0,0 +1,15 @@
+class BOX_A
+ FOO = "foo_a1"
+
+ def yay
+ "yay_a1"
+ end
+end
+
+module BOX_B
+ BAR = "bar_b1"
+
+ def self.yay
+ "yay_b1"
+ end
+end
diff --git a/test/ruby/box/autoloading.rb b/test/ruby/box/autoloading.rb
new file mode 100644
index 0000000000..cba57ab377
--- /dev/null
+++ b/test/ruby/box/autoloading.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+autoload :BOX_A, File.join(__dir__, 'a.1_1_0')
+BOX_A.new.yay
+
+module BOX_B
+ autoload :BAR, File.join(__dir__, 'a')
+end
diff --git a/test/ruby/box/blank.rb b/test/ruby/box/blank.rb
new file mode 100644
index 0000000000..6d201b0966
--- /dev/null
+++ b/test/ruby/box/blank.rb
@@ -0,0 +1,2 @@
+module Blank1
+end
diff --git a/test/ruby/box/blank1.rb b/test/ruby/box/blank1.rb
new file mode 100644
index 0000000000..6d201b0966
--- /dev/null
+++ b/test/ruby/box/blank1.rb
@@ -0,0 +1,2 @@
+module Blank1
+end
diff --git a/test/ruby/box/blank2.rb b/test/ruby/box/blank2.rb
new file mode 100644
index 0000000000..ba38c1d6db
--- /dev/null
+++ b/test/ruby/box/blank2.rb
@@ -0,0 +1,2 @@
+module Blank2
+end
diff --git a/test/ruby/box/box.rb b/test/ruby/box/box.rb
new file mode 100644
index 0000000000..3b7da14e9d
--- /dev/null
+++ b/test/ruby/box/box.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+BOX1 = Ruby::Box.new
+BOX1.require_relative('a.1_1_0')
+
+def yay
+ BOX1::BOX_B::yay
+end
+
+yay
diff --git a/test/ruby/box/call_proc.rb b/test/ruby/box/call_proc.rb
new file mode 100644
index 0000000000..8acf538fc1
--- /dev/null
+++ b/test/ruby/box/call_proc.rb
@@ -0,0 +1,5 @@
+module Bar
+ def self.caller(proc_value)
+ proc_value.call
+ end
+end
diff --git a/test/ruby/box/call_toplevel.rb b/test/ruby/box/call_toplevel.rb
new file mode 100644
index 0000000000..c311a37028
--- /dev/null
+++ b/test/ruby/box/call_toplevel.rb
@@ -0,0 +1,8 @@
+foo
+
+#### TODO: this code should be valid, but can't be for now
+# module Foo
+# def self.wow
+# foo
+# end
+# end
diff --git a/test/ruby/box/consts.rb b/test/ruby/box/consts.rb
new file mode 100644
index 0000000000..e40cd5c50c
--- /dev/null
+++ b/test/ruby/box/consts.rb
@@ -0,0 +1,148 @@
+$VERBOSE = nil
+class String
+ STR_CONST1 = 111
+ STR_CONST2 = 222
+ STR_CONST3 = 333
+end
+
+class String
+ STR_CONST1 = 112
+
+ def self.set0(val)
+ const_set(:STR_CONST0, val)
+ end
+
+ def self.remove0
+ remove_const(:STR_CONST0)
+ end
+
+ def refer0
+ STR_CONST0
+ end
+
+ def refer1
+ STR_CONST1
+ end
+
+ def refer2
+ STR_CONST2
+ end
+
+ def refer3
+ STR_CONST3
+ end
+end
+
+module ForConsts
+ CONST1 = 111
+end
+
+TOP_CONST = 10
+
+module ForConsts
+ CONST1 = 112
+ CONST2 = 222
+ CONST3 = 333
+
+ def self.refer_all
+ ForConsts::CONST1
+ ForConsts::CONST2
+ ForConsts::CONST3
+ String::STR_CONST1
+ String::STR_CONST2
+ String::STR_CONST3
+ end
+
+ def self.refer1
+ CONST1
+ end
+
+ def self.get1
+ const_get(:CONST1)
+ end
+
+ def self.refer2
+ CONST2
+ end
+
+ def self.get2
+ const_get(:CONST2)
+ end
+
+ def self.refer3
+ CONST3
+ end
+
+ def self.get3
+ const_get(:CONST3)
+ end
+
+ def self.refer_top_const
+ TOP_CONST
+ end
+
+ # for String
+ class Proxy
+ def call_str_refer0
+ String.new.refer0
+ end
+
+ def call_str_get0
+ String.const_get(:STR_CONST0)
+ end
+
+ def call_str_set0(val)
+ String.set0(val)
+ end
+
+ def call_str_remove0
+ String.remove0
+ end
+
+ def call_str_refer1
+ String.new.refer1
+ end
+
+ def call_str_get1
+ String.const_get(:STR_CONST1)
+ end
+
+ String::STR_CONST2 = 223
+
+ def call_str_refer2
+ String.new.refer2
+ end
+
+ def call_str_get2
+ String.const_get(:STR_CONST2)
+ end
+
+ def call_str_set3
+ String.const_set(:STR_CONST3, 334)
+ end
+
+ def call_str_refer3
+ String.new.refer3
+ end
+
+ def call_str_get3
+ String.const_get(:STR_CONST3)
+ end
+
+ # for Integer
+ Integer::INT_CONST1 = 1
+
+ def refer_int_const1
+ Integer::INT_CONST1
+ end
+ end
+end
+
+# should not raise errors
+ForConsts.refer_all
+String::STR_CONST1
+Integer::INT_CONST1
+
+# If we execute this sentence once, the constant value will be cached on ISeq inline constant cache.
+# And it changes the behavior of ForConsts.refer_consts_directly called from global.
+# ForConsts.refer_consts_directly # should not raise errors too
diff --git a/test/ruby/box/define_toplevel.rb b/test/ruby/box/define_toplevel.rb
new file mode 100644
index 0000000000..aa77db3a13
--- /dev/null
+++ b/test/ruby/box/define_toplevel.rb
@@ -0,0 +1,5 @@
+def foo
+ "foooooooooo"
+end
+
+foo # should not raise errors
diff --git a/test/ruby/box/global_vars.rb b/test/ruby/box/global_vars.rb
new file mode 100644
index 0000000000..590363f617
--- /dev/null
+++ b/test/ruby/box/global_vars.rb
@@ -0,0 +1,37 @@
+module LineSplitter
+ def self.read
+ $-0
+ end
+
+ def self.write(char)
+ $-0 = char
+ end
+end
+
+module FieldSplitter
+ def self.read
+ $,
+ end
+
+ def self.write(char)
+ $, = char
+ end
+end
+
+module UniqueGvar
+ def self.read
+ $used_only_in_box
+ end
+
+ def self.write(val)
+ $used_only_in_box = val
+ end
+
+ def self.write_only(val)
+ $write_only_var_in_box = val
+ end
+
+ def self.gvars_in_box
+ global_variables
+ end
+end
diff --git a/test/ruby/box/instance_variables.rb b/test/ruby/box/instance_variables.rb
new file mode 100644
index 0000000000..1562ad5d45
--- /dev/null
+++ b/test/ruby/box/instance_variables.rb
@@ -0,0 +1,21 @@
+class String
+ class << self
+ attr_reader :str_ivar1
+
+ def str_ivar2
+ @str_ivar2
+ end
+ end
+
+ @str_ivar1 = 111
+ @str_ivar2 = 222
+end
+
+class StringDelegator < BasicObject
+private
+ def method_missing(...)
+ ::String.public_send(...)
+ end
+end
+
+StringDelegatorObj = StringDelegator.new
diff --git a/test/ruby/box/line_splitter.rb b/test/ruby/box/line_splitter.rb
new file mode 100644
index 0000000000..2596975ad7
--- /dev/null
+++ b/test/ruby/box/line_splitter.rb
@@ -0,0 +1,9 @@
+module LineSplitter
+ def self.read
+ $-0
+ end
+
+ def self.write(char)
+ $-0 = char
+ end
+end
diff --git a/test/ruby/box/load_path.rb b/test/ruby/box/load_path.rb
new file mode 100644
index 0000000000..7e5a83ef96
--- /dev/null
+++ b/test/ruby/box/load_path.rb
@@ -0,0 +1,26 @@
+module LoadPathCheck
+ FIRST_LOAD_PATH = $LOAD_PATH.dup
+ FIRST_LOAD_PATH_RESPOND_TO_RESOLVE = $LOAD_PATH.respond_to?(:resolve_feature_path)
+ FIRST_LOADED_FEATURES = $LOADED_FEATURES.dup
+
+ HERE = File.dirname(__FILE__)
+
+ def self.current_load_path
+ $LOAD_PATH
+ end
+
+ def self.current_loaded_features
+ $LOADED_FEATURES
+ end
+
+ def self.require_blank1
+ $LOAD_PATH << HERE
+ require 'blank1'
+ end
+
+ def self.require_blank2
+ require 'blank2'
+ end
+end
+
+LoadPathCheck.require_blank1
diff --git a/test/ruby/box/open_class_with_include.rb b/test/ruby/box/open_class_with_include.rb
new file mode 100644
index 0000000000..ad8fd58ea0
--- /dev/null
+++ b/test/ruby/box/open_class_with_include.rb
@@ -0,0 +1,31 @@
+module StringExt
+ FOO = "foo 1"
+ def say_foo
+ "I'm saying " + FOO
+ end
+end
+
+class String
+ include StringExt
+ def say
+ say_foo
+ end
+end
+
+module OpenClassWithInclude
+ def self.say
+ String.new.say
+ end
+
+ def self.say_foo
+ String.new.say_foo
+ end
+
+ def self.say_with_obj(str)
+ str.say
+ end
+
+ def self.refer_foo
+ String::FOO
+ end
+end
diff --git a/test/ruby/box/proc_callee.rb b/test/ruby/box/proc_callee.rb
new file mode 100644
index 0000000000..d30ab5d9f3
--- /dev/null
+++ b/test/ruby/box/proc_callee.rb
@@ -0,0 +1,14 @@
+module Target
+ def self.foo
+ "fooooo"
+ end
+end
+
+module Foo
+ def self.callee
+ lambda do
+ Target.foo
+ end
+ end
+end
+
diff --git a/test/ruby/box/proc_caller.rb b/test/ruby/box/proc_caller.rb
new file mode 100644
index 0000000000..8acf538fc1
--- /dev/null
+++ b/test/ruby/box/proc_caller.rb
@@ -0,0 +1,5 @@
+module Bar
+ def self.caller(proc_value)
+ proc_value.call
+ end
+end
diff --git a/test/ruby/box/procs.rb b/test/ruby/box/procs.rb
new file mode 100644
index 0000000000..1c39a8231b
--- /dev/null
+++ b/test/ruby/box/procs.rb
@@ -0,0 +1,64 @@
+class String
+ FOO = "foo"
+ def yay
+ "yay"
+ end
+end
+
+module ProcLookupTestA
+ module B
+ VALUE = 222
+ end
+end
+
+module ProcInBox
+ def self.make_proc_from_block(&b)
+ b
+ end
+
+ def self.call_proc(proc_arg)
+ proc_arg.call
+ end
+
+ def self.make_str_proc(type)
+ case type
+ when :proc_new then Proc.new { String.new.yay }
+ when :proc_f then proc { String.new.yay }
+ when :lambda_f then lambda { String.new.yay }
+ when :lambda_l then ->(){ String.new.yay }
+ when :block then make_proc_from_block { String.new.yay }
+ else
+ raise "invalid type :#{type}"
+ end
+ end
+
+ def self.make_const_proc(type)
+ case type
+ when :proc_new then Proc.new { ProcLookupTestA::B::VALUE }
+ when :proc_f then proc { ProcLookupTestA::B::VALUE }
+ when :lambda_f then lambda { ProcLookupTestA::B::VALUE }
+ when :lambda_l then ->(){ ProcLookupTestA::B::VALUE }
+ when :block then make_proc_from_block { ProcLookupTestA::B::VALUE }
+ else
+ raise "invalid type :#{type}"
+ end
+ end
+
+ def self.make_str_const_proc(type)
+ case type
+ when :proc_new then Proc.new { String::FOO }
+ when :proc_f then proc { String::FOO }
+ when :lambda_f then lambda { String::FOO }
+ when :lambda_l then ->(){ String::FOO }
+ when :block then make_proc_from_block { String::FOO }
+ else
+ raise "invalid type :#{type}"
+ end
+ end
+
+ CONST_PROC_NEW = Proc.new { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
+ CONST_PROC_F = proc { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
+ CONST_LAMBDA_F = lambda { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
+ CONST_LAMBDA_L = ->() { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
+ CONST_BLOCK = make_proc_from_block { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
+end
diff --git a/test/ruby/box/raise.rb b/test/ruby/box/raise.rb
new file mode 100644
index 0000000000..efb67f85c5
--- /dev/null
+++ b/test/ruby/box/raise.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+raise "Yay!"
diff --git a/test/ruby/box/returns_proc.rb b/test/ruby/box/returns_proc.rb
new file mode 100644
index 0000000000..bb816e5024
--- /dev/null
+++ b/test/ruby/box/returns_proc.rb
@@ -0,0 +1,12 @@
+module Foo
+ def self.foo
+ "fooooo"
+ end
+
+ def self.callee
+ lambda do
+ Foo.foo
+ end
+ end
+end
+
diff --git a/test/ruby/box/singleton_methods.rb b/test/ruby/box/singleton_methods.rb
new file mode 100644
index 0000000000..05470932d2
--- /dev/null
+++ b/test/ruby/box/singleton_methods.rb
@@ -0,0 +1,65 @@
+class String
+ def self.greeting
+ "Good evening!"
+ end
+end
+
+class Integer
+ class << self
+ def answer
+ 42
+ end
+ end
+end
+
+class Array
+ def a
+ size
+ end
+ def self.blank
+ []
+ end
+ def b
+ size
+ end
+end
+
+class Hash
+ def a
+ size
+ end
+ class << self
+ def http_200
+ {status: 200, body: 'OK'}
+ end
+ end
+ def b
+ size
+ end
+end
+
+module SingletonMethods
+ def self.string_greeing
+ String.greeting
+ end
+
+ def self.integer_answer
+ Integer.answer
+ end
+
+ def self.array_blank
+ Array.blank
+ end
+
+ def self.hash_http_200
+ Hash.http_200
+ end
+
+ def self.array_instance_methods_return_size(ary)
+ [ary.a, ary.b]
+ end
+
+ def self.hash_instance_methods_return_size(hash)
+ [hash.a, hash.b]
+ end
+end
diff --git a/test/ruby/box/string_ext.rb b/test/ruby/box/string_ext.rb
new file mode 100644
index 0000000000..d8c5a3d661
--- /dev/null
+++ b/test/ruby/box/string_ext.rb
@@ -0,0 +1,13 @@
+class String
+ def yay
+ "yay"
+ end
+end
+
+String.new.yay # check this doesn't raise NoMethodError
+
+module Bar
+ def self.yay
+ String.new.yay
+ end
+end
diff --git a/test/ruby/box/string_ext_caller.rb b/test/ruby/box/string_ext_caller.rb
new file mode 100644
index 0000000000..b8345d98ed
--- /dev/null
+++ b/test/ruby/box/string_ext_caller.rb
@@ -0,0 +1,5 @@
+module Foo
+ def self.yay
+ String.new.yay
+ end
+end
diff --git a/test/ruby/box/string_ext_calling.rb b/test/ruby/box/string_ext_calling.rb
new file mode 100644
index 0000000000..6467b728dd
--- /dev/null
+++ b/test/ruby/box/string_ext_calling.rb
@@ -0,0 +1 @@
+Foo.yay
diff --git a/test/ruby/box/string_ext_eval_caller.rb b/test/ruby/box/string_ext_eval_caller.rb
new file mode 100644
index 0000000000..0e6b20c19f
--- /dev/null
+++ b/test/ruby/box/string_ext_eval_caller.rb
@@ -0,0 +1,12 @@
+module Baz
+ def self.yay
+ eval 'String.new.yay'
+ end
+
+ def self.yay_with_binding
+ suffix = ", yay!"
+ eval 'String.new.yay + suffix', binding
+ end
+end
+
+Baz.yay # should not raise NeMethodError
diff --git a/test/ruby/box/top_level.rb b/test/ruby/box/top_level.rb
new file mode 100644
index 0000000000..90df145578
--- /dev/null
+++ b/test/ruby/box/top_level.rb
@@ -0,0 +1,33 @@
+def yaaay
+ "yay!"
+end
+
+module Foo
+ def self.foo
+ yaaay
+ end
+end
+
+eval 'def foo; "foo"; end'
+
+Foo.foo # Should not raise NameError
+
+foo
+
+module Bar
+ def self.bar
+ foo
+ end
+end
+
+Bar.bar
+
+$def_retval_in_namespace = def boooo
+ "boo"
+end
+
+module Baz
+ def self.baz
+ raise "#{$def_retval_in_namespace}"
+ end
+end
diff --git a/test/ruby/enc/test_emoji_breaks.rb b/test/ruby/enc/test_emoji_breaks.rb
index bb5114680e..0873e681c3 100644
--- a/test/ruby/enc/test_emoji_breaks.rb
+++ b/test/ruby/enc/test_emoji_breaks.rb
@@ -53,7 +53,7 @@ class TestEmojiBreaks < Test::Unit::TestCase
EMOJI_DATA_FILES = %w[emoji-sequences emoji-test emoji-zwj-sequences].map do |basename|
BreakFile.new(basename, EMOJI_DATA_PATH, EMOJI_VERSION)
end
- UNICODE_DATA_FILE = BreakFile.new('emoji-variation-sequences', UNICODE_DATA_PATH, UNICODE_VERSION)
+ UNICODE_DATA_FILE = BreakFile.new('emoji-variation-sequences', UNICODE_DATA_PATH, EMOJI_VERSION)
EMOJI_DATA_FILES << UNICODE_DATA_FILE
def self.data_files_available?
diff --git a/test/ruby/sentence.rb b/test/ruby/sentence.rb
index 9bfd7c7599..99ced05d2f 100644
--- a/test/ruby/sentence.rb
+++ b/test/ruby/sentence.rb
@@ -211,7 +211,7 @@ class Sentence
# returns new sentence object which
# _target_ is substituted by the block.
#
- # Sentence#subst invokes <tt>_target_ === _string_</tt> for each
+ # Sentence#subst invokes <tt>target === string</tt> for each
# string in the sentence.
# The strings which === returns true are substituted by the block.
# The block is invoked with the substituting string.
diff --git a/test/ruby/test_allocation.rb b/test/ruby/test_allocation.rb
index 2b181b1bdc..90d7c04f9b 100644
--- a/test/ruby/test_allocation.rb
+++ b/test/ruby/test_allocation.rb
@@ -2,6 +2,12 @@
require 'test/unit'
class TestAllocation < Test::Unit::TestCase
+ def setup
+ # The namespace changes on i686 platform triggers a bug to allocate objects unexpectedly.
+ # For now, skip these tests only on i686
+ pend if RUBY_PLATFORM =~ /^i686/
+ end
+
def munge_checks(checks)
checks
end
@@ -60,9 +66,7 @@ class TestAllocation < Test::Unit::TestCase
#{checks}
- unless failures.empty?
- assert_equal(true, false, failures.join("\n"))
- end
+ assert_empty(failures)
RUBY
end
@@ -523,6 +527,59 @@ class TestAllocation < Test::Unit::TestCase
RUBY
end
+ def test_anonymous_splat_parameter
+ only_block = block.empty? ? block : block[2..]
+ check_allocations(<<~RUBY)
+ def self.anon_splat(*#{block}); end
+
+ check_allocations(1, 1, "anon_splat(1, a: 2#{block})")
+ check_allocations(1, 1, "anon_splat(1, *empty_array, a: 2#{block})")
+ check_allocations(1, 1, "anon_splat(1, a:2, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, **empty_hash, a: 2#{block})")
+
+ check_allocations(1, 0, "anon_splat(1, **nil#{block})")
+ check_allocations(1, 0, "anon_splat(1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, **hash1#{block})")
+ check_allocations(1, 1, "anon_splat(1, *empty_array, **hash1#{block})")
+ check_allocations(1, 1, "anon_splat(1, **hash1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, **empty_hash, **hash1#{block})")
+
+ check_allocations(1, 0, "anon_splat(1, *empty_array#{block})")
+ check_allocations(1, 0, "anon_splat(1, *empty_array, *empty_array, **empty_hash#{block})")
+
+ check_allocations(1, 1, "anon_splat(*array1, a: 2#{block})")
+
+ check_allocations(0, 0, "anon_splat(*nil, **nill#{block})")
+ check_allocations(0, 0, "anon_splat(*array1, **nill#{block})")
+ check_allocations(0, 0, "anon_splat(*array1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, **hash1#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, *empty_array, **hash1#{block})")
+
+ check_allocations(1, 0, "anon_splat(*array1, *empty_array#{block})")
+ check_allocations(1, 0, "anon_splat(*array1, *empty_array, **empty_hash#{block})")
+
+ check_allocations(1, 1, "anon_splat(*array1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, *empty_array, **hash1, **empty_hash#{block})")
+
+ check_allocations(0, 0, "anon_splat(#{only_block})")
+ check_allocations(1, 1, "anon_splat(a: 2#{block})")
+ check_allocations(0, 0, "anon_splat(**empty_hash#{block})")
+
+ check_allocations(1, 1, "anon_splat(1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, **hash1, **empty_hash#{block})")
+
+ unless defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled?
+ check_allocations(0, 0, "anon_splat(*array1, **nil#{block})")
+ check_allocations(1, 0, "anon_splat(*r2k_empty_array#{block})")
+ check_allocations(1, 1, "anon_splat(*r2k_array#{block})")
+ check_allocations(1, 0, "anon_splat(*r2k_empty_array1#{block})")
+ check_allocations(1, 1, "anon_splat(*r2k_array1#{block})")
+ end
+ RUBY
+ end
+
def test_anonymous_splat_and_anonymous_keyword_splat_parameters
only_block = block.empty? ? block : block[2..]
check_allocations(<<~RUBY)
@@ -775,6 +832,7 @@ class TestAllocation < Test::Unit::TestCase
def test_no_array_allocation_with_splat_and_nonstatic_keywords
check_allocations(<<~RUBY)
def self.keyword(a: nil, b: nil#{block}); end
+ def self.Object; Object end
check_allocations(0, 1, "keyword(*nil, a: empty_array#{block})") # LVAR
check_allocations(0, 1, "keyword(*empty_array, a: empty_array#{block})") # LVAR
@@ -782,7 +840,8 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "$x = empty_array; keyword(*empty_array, a: $x#{block})") # GVAR
check_allocations(0, 1, "@x = empty_array; keyword(*empty_array, a: @x#{block})") # IVAR
check_allocations(0, 1, "self.class.const_set(:X, empty_array); keyword(*empty_array, a: X#{block})") # CONST
- check_allocations(0, 1, "keyword(*empty_array, a: Object::X#{block})") # COLON2
+ check_allocations(0, 1, "keyword(*empty_array, a: Object::X#{block})") # COLON2 - safe
+ check_allocations(1, 1, "keyword(*empty_array, a: Object()::X#{block})") # COLON2 - unsafe
check_allocations(0, 1, "keyword(*empty_array, a: ::X#{block})") # COLON3
check_allocations(0, 1, "T = self; #{'B = block' unless block.empty?}; class Object; @@x = X; T.keyword(*X, a: @@x#{', &B' unless block.empty?}) end") # CVAR
check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 1#{block})") # INTEGER
@@ -799,6 +858,13 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "keyword(*empty_array, a: ->{}#{block})") # LAMBDA
check_allocations(0, 1, "keyword(*empty_array, a: $1#{block})") # NTH_REF
check_allocations(0, 1, "keyword(*empty_array, a: $`#{block})") # BACK_REF
+
+ # LIST: Only 1 array (literal [:c]), not 2 (one for [:c] and one for *empty_array)
+ check_allocations(1, 1, "keyword(*empty_array, a: empty_array, b: [:c]#{block})")
+ check_allocations(1, 1, "keyword(*empty_array, a: empty_array, b: [:c, $x]#{block})")
+ # LIST unsafe: 2 (one for [Object()] and one for *empty_array)
+ check_allocations(2, 1, "keyword(*empty_array, a: empty_array, b: [Object()]#{block})")
+ check_allocations(2, 1, "keyword(*empty_array, a: empty_array, b: [:c, $x, Object()]#{block})")
RUBY
end
@@ -844,13 +910,15 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(<<~RUBY)
keyword = keyword = proc{ |a: nil, b: nil #{block}| }
+ def self.Object; Object end
check_allocations(0, 1, "keyword.(*empty_array, a: empty_array#{block})") # LVAR
check_allocations(0, 1, "->{keyword.(*empty_array, a: empty_array#{block})}.call") # DVAR
check_allocations(0, 1, "$x = empty_array; keyword.(*empty_array, a: $x#{block})") # GVAR
check_allocations(0, 1, "@x = empty_array; keyword.(*empty_array, a: @x#{block})") # IVAR
check_allocations(0, 1, "self.class.const_set(:X, empty_array); keyword.(*empty_array, a: X#{block})") # CONST
- check_allocations(0, 1, "keyword.(*empty_array, a: Object::X#{block})") # COLON2
+ check_allocations(0, 1, "keyword.(*empty_array, a: Object::X#{block})") # COLON2 - safe
+ check_allocations(1, 1, "keyword.(*empty_array, a: Object()::X#{block})") # COLON2 - unsafe
check_allocations(0, 1, "keyword.(*empty_array, a: ::X#{block})") # COLON3
check_allocations(0, 1, "T = keyword; #{'B = block' unless block.empty?}; class Object; @@x = X; T.(*X, a: @@x#{', &B' unless block.empty?}) end") # CVAR
check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 1#{block})") # INTEGER
@@ -867,6 +935,13 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "keyword.(*empty_array, a: ->{}#{block})") # LAMBDA
check_allocations(0, 1, "keyword.(*empty_array, a: $1#{block})") # NTH_REF
check_allocations(0, 1, "keyword.(*empty_array, a: $`#{block})") # BACK_REF
+
+ # LIST safe: Only 1 array (literal [:c]), not 2 (one for [:c] and one for *empty_array)
+ check_allocations(1, 1, "keyword.(*empty_array, a: empty_array, b: [:c]#{block})")
+ check_allocations(1, 1, "keyword.(*empty_array, a: empty_array, b: [:c, $x]#{block})")
+ # LIST unsafe: 2 (one for [:c] and one for *empty_array)
+ check_allocations(2, 1, "keyword.(*empty_array, a: empty_array, b: [Object()]#{block})")
+ check_allocations(2, 1, "keyword.(*empty_array, a: empty_array, b: [:c, $x, Object()]#{block})")
RUBY
end
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index 19f79d236d..76455187a5 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -1309,32 +1309,7 @@ class TestArray < Test::Unit::TestCase
assert_equal(ary.join(':'), ary2.join(':'))
assert_not_nil(x =~ /def/)
-=begin
- skipping "Not tested:
- D,d & double-precision float, native format\\
- E & double-precision float, little-endian byte order\\
- e & single-precision float, little-endian byte order\\
- F,f & single-precision float, native format\\
- G & double-precision float, network (big-endian) byte order\\
- g & single-precision float, network (big-endian) byte order\\
- I & unsigned integer\\
- i & integer\\
- L & unsigned long\\
- l & long\\
-
- N & long, network (big-endian) byte order\\
- n & short, network (big-endian) byte-order\\
- P & pointer to a structure (fixed-length string)\\
- p & pointer to a null-terminated string\\
- S & unsigned short\\
- s & short\\
- V & long, little-endian byte order\\
- v & short, little-endian byte order\\
- X & back up a byte\\
- x & null byte\\
- Z & ASCII string (null padded, count is width)\\
-"
-=end
+ # more comprehensive tests are in test_pack.rb
end
def test_pack_with_buffer
@@ -1361,6 +1336,28 @@ class TestArray < Test::Unit::TestCase
assert_equal(@cls[@cls[1,2], nil, 'dog', 'cat'], a.prepend(@cls[1, 2]))
end
+ def test_tolerant_to_redefinition
+ *code = __FILE__, __LINE__+1, "#{<<-"{#"}\n#{<<-'};'}"
+ {#
+ module M
+ def <<(a)
+ super(a * 2)
+ end
+ end
+ class Array; prepend M; end
+ ary = [*1..10]
+ mapped = ary.map {|i| i}
+ selected = ary.select {true}
+ module M
+ remove_method :<<
+ end
+ assert_equal(ary, mapped)
+ assert_equal(ary, selected)
+ };
+ assert_separately(%w[--disable-yjit], *code)
+ assert_separately(%w[--enable-yjit], *code)
+ end
+
def test_push
a = @cls[1, 2, 3]
assert_equal(@cls[1, 2, 3, 4, 5], a.push(4, 5))
@@ -1849,19 +1846,21 @@ class TestArray < Test::Unit::TestCase
assert_equal([1, 2, 3, 4], a)
end
- def test_freeze_inside_sort!
+ def test_freeze_inside_sort_bang
array = [1, 2, 3, 4, 5]
frozen_array = nil
assert_raise(FrozenError) do
count = 0
array.sort! do |a, b|
- array.freeze if (count += 1) == 6
+ array.freeze if (count += 1) == 3
frozen_array ||= array.map.to_a if array.frozen?
b <=> a
end
end
assert_equal(frozen_array, array)
+ end
+ def test_freeze_inside_sort_bang_non_numeric_block
object = Object.new
array = [1, 2, 3, 4, 5]
object.define_singleton_method(:>){|_| array.freeze; true}
@@ -1870,7 +1869,9 @@ class TestArray < Test::Unit::TestCase
object
end
end
+ end
+ def test_freeze_inside_sort_bang_non_numeric_no_block
object = Object.new
array = [object, object]
object.define_singleton_method(:>){|_| array.freeze; true}
@@ -3549,6 +3550,7 @@ class TestArray < Test::Unit::TestCase
assert_float_equal(3.5, [3].sum(0.5))
assert_float_equal(8.5, [3.5, 5].sum)
assert_float_equal(10.5, [2, 8.5].sum)
+ assert_float_equal(1_000 * 0.1, Array.new(1_000, 0.1).sum(0.0))
assert_float_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].sum)
assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].sum)
@@ -3609,6 +3611,23 @@ class TestArray < Test::Unit::TestCase
assert_equal((1..67).to_a.reverse, var_0)
end
+ def test_find
+ ary = [1, 2, 3, 4, 5]
+ assert_equal(2, ary.find {|x| x % 2 == 0 })
+ assert_equal(nil, ary.find {|x| false })
+ assert_equal(:foo, ary.find(proc { :foo }) {|x| false })
+ end
+
+ def test_rfind
+ ary = [1, 2, 3, 4, 5]
+ assert_equal(4, ary.rfind {|x| x % 2 == 0 })
+ assert_equal(1, ary.rfind {|x| x < 2 })
+ assert_equal(5, ary.rfind {|x| x > 4 })
+ assert_equal(nil, ary.rfind {|x| false })
+ assert_equal(:foo, ary.rfind(proc { :foo }) {|x| false })
+ assert_equal(nil, ary.rfind {|x| ary.clear; false })
+ end
+
private
def need_continuation
unless respond_to?(:callcc, true)
diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb
index 887dbb6ecf..8b9a3f615d 100644
--- a/test/ruby/test_ast.rb
+++ b/test/ruby/test_ast.rb
@@ -48,7 +48,7 @@ class TestAst < Test::Unit::TestCase
@path = path
@errors = []
@debug = false
- @ast = RubyVM::AbstractSyntaxTree.parse(src) if src
+ @ast = EnvUtil.suppress_warning { RubyVM::AbstractSyntaxTree.parse(src) } if src
end
def validate_range
@@ -67,7 +67,7 @@ class TestAst < Test::Unit::TestCase
def ast
return @ast if defined?(@ast)
- @ast = RubyVM::AbstractSyntaxTree.parse_file(@path)
+ @ast = EnvUtil.suppress_warning { RubyVM::AbstractSyntaxTree.parse_file(@path) }
end
private
@@ -135,7 +135,7 @@ class TestAst < Test::Unit::TestCase
Dir.glob("test/**/*.rb", base: SRCDIR).each do |path|
define_method("test_all_tokens:#{path}") do
- node = RubyVM::AbstractSyntaxTree.parse_file("#{SRCDIR}/#{path}", keep_tokens: true)
+ node = EnvUtil.suppress_warning { RubyVM::AbstractSyntaxTree.parse_file("#{SRCDIR}/#{path}", keep_tokens: true) }
tokens = node.all_tokens.sort_by { [_1.last[0], _1.last[1]] }
tokens_bytes = tokens.map { _1[2]}.join.bytes
source_bytes = File.read("#{SRCDIR}/#{path}").bytes
@@ -215,6 +215,17 @@ class TestAst < Test::Unit::TestCase
end
end
+ def test_cdecl_children_with_toplevel_constant_path
+ # [Bug #21974]
+ children = parse("::Foo = 1").children[2].children
+
+ assert_equal(:COLON3, children[0].type)
+ assert_equal([:Foo], children[0].children)
+ assert_equal(:Foo, children[1])
+ assert_equal(:INTEGER, children[2].type)
+ assert_equal([1], children[2].children)
+ end
+
def assert_parse(code, warning: '')
node = assert_warning(warning) {RubyVM::AbstractSyntaxTree.parse(code)}
assert_kind_of(RubyVM::AbstractSyntaxTree::Node, node, code)
@@ -244,7 +255,8 @@ class TestAst < Test::Unit::TestCase
assert_invalid_parse(msg, "#{code}")
assert_invalid_parse(msg, "def m; #{code}; end")
assert_invalid_parse(msg, "begin; #{code}; end")
- assert_parse("END {#{code}}")
+ assert_invalid_parse(msg, "BEGIN {#{code}}")
+ assert_invalid_parse(msg, "END {#{code}}")
assert_parse("!defined?(#{code})")
assert_parse("def m; defined?(#{code}); end")
@@ -337,6 +349,19 @@ class TestAst < Test::Unit::TestCase
assert_parse("END {defined? yield}")
end
+ def test_invalid_yield_no_memory_leak
+ # [Bug #21383]
+ assert_no_memory_leak([], "#{<<-"begin;"}", "#{<<-'end;'}", rss: true)
+ code = proc do
+ eval("class C; yield; end")
+ rescue SyntaxError
+ end
+ 1_000.times(&code)
+ begin;
+ 100_000.times(&code)
+ end;
+ end
+
def test_node_id_for_location
omit if ParserSupport.prism_enabled?
@@ -352,6 +377,50 @@ class TestAst < Test::Unit::TestCase
assert_equal node.node_id, node_id
end
+ def add(x, y)
+ end
+
+ def test_node_id_for_backtrace_location_of_method_definition
+ omit if ParserSupport.prism_enabled?
+
+ begin
+ add(1)
+ rescue ArgumentError => exc
+ loc = exc.backtrace_locations.first
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc)
+ node = RubyVM::AbstractSyntaxTree.of(method(:add))
+ assert_equal node.node_id, node_id
+ end
+ end
+
+ def test_node_id_for_backtrace_location_of_lambda
+ omit if ParserSupport.prism_enabled?
+
+ v = -> {}
+ begin
+ v.call(1)
+ rescue ArgumentError => exc
+ loc = exc.backtrace_locations.first
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc)
+ node = RubyVM::AbstractSyntaxTree.of(v)
+ assert_equal node.node_id, node_id
+ end
+ end
+
+ def test_node_id_for_backtrace_location_of_lambda_method
+ omit if ParserSupport.prism_enabled?
+
+ v = lambda {}
+ begin
+ v.call(1)
+ rescue ArgumentError => exc
+ loc = exc.backtrace_locations.first
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc)
+ node = RubyVM::AbstractSyntaxTree.of(v)
+ assert_equal node.node_id, node_id
+ end
+ end
+
def test_node_id_for_backtrace_location_raises_argument_error
bug19262 = '[ruby-core:111435]'
@@ -652,6 +721,7 @@ class TestAst < Test::Unit::TestCase
assert_equal(nil, block_arg.call(''))
assert_equal(:block, block_arg.call('&block'))
assert_equal(:&, block_arg.call('&'))
+ assert_equal(false, block_arg.call('&nil'))
end
def test_keyword_rest
@@ -788,7 +858,7 @@ dummy
node_proc = RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: true)
node_method = RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: true)
- assert_equal("{ 1 + 2 }", node_proc.source)
+ assert_equal("Proc.new { 1 + 2 }", node_proc.source)
assert_equal("def test_keep_script_lines_for_of\n", node_method.source.lines.first)
end
@@ -865,7 +935,7 @@ dummy
omit if ParserSupport.prism_enabled? || ParserSupport.prism_enabled_in_subprocess?
assert_in_out_err(["-e", "def foo; end; pp RubyVM::AbstractSyntaxTree.of(method(:foo)).type"],
- "", [":SCOPE"], [])
+ "", [":DEFN"], [])
end
def test_error_tolerant
@@ -1173,7 +1243,7 @@ dummy
args: nil
body:
(LAMBDA@1:0-2:3
- (SCOPE@1:2-2:3
+ (SCOPE@1:0-2:3
tbl: []
args:
(ARGS@1:2-1:2
@@ -1384,6 +1454,32 @@ dummy
assert_locations(node.children[-1].locations, [[1, 0, 1, 16], [1, 0, 1, 5], [1, 8, 1, 9], [1, 13, 1, 16]])
end
+ def test_colon2_locations
+ node = ast_parse("A::B")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 4], [1, 1, 1, 3], [1, 3, 1, 4]])
+
+ node = ast_parse("A::B::C")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 7], [1, 4, 1, 6], [1, 6, 1, 7]])
+ assert_locations(node.children[-1].children[0].locations, [[1, 0, 1, 4], [1, 1, 1, 3], [1, 3, 1, 4]])
+ end
+
+ def test_colon3_locations
+ node = ast_parse("::A")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 3], [1, 0, 1, 2], [1, 2, 1, 3]])
+
+ node = ast_parse("::A::B")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 3, 1, 5], [1, 5, 1, 6]])
+ assert_locations(node.children[-1].children[0].locations, [[1, 0, 1, 3], [1, 0, 1, 2], [1, 2, 1, 3]])
+ end
+
+ def test_defined_locations
+ node = ast_parse("defined? x")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 10], [1, 0, 1, 8]])
+
+ node = ast_parse("defined?(x)")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 11], [1, 0, 1, 8]])
+ end
+
def test_dot2_locations
node = ast_parse("1..2")
assert_locations(node.children[-1].locations, [[1, 0, 1, 4], [1, 1, 1, 3]])
@@ -1452,6 +1548,11 @@ dummy
assert_locations(node.children[-1].locations, [[1, 0, 1, 20], [1, 0, 1, 2], [1, 10, 1, 12], [1, 17, 1, 20]])
end
+ def test_module_locations
+ node = ast_parse('module A end')
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 12], [1, 0, 1, 6], [1, 9, 1, 12]])
+ end
+
def test_if_locations
node = ast_parse("if cond then 1 else 2 end")
assert_locations(node.children[-1].locations, [[1, 0, 1, 25], [1, 0, 1, 2], [1, 8, 1, 12], [1, 22, 1, 25]])
@@ -1470,6 +1571,20 @@ dummy
assert_locations(node.children[-1].children[1].children[0].locations, [[1, 11, 1, 17], [1, 13, 1, 15], nil, nil])
end
+ def test_in_locations
+ node = ast_parse("case 1; in 2 then 3; end")
+ assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 20], [1, 8, 1, 10], [1, 13, 1, 17], nil])
+
+ node = ast_parse("1 => a")
+ assert_locations(node.children[-1].children[1].locations, [[1, 5, 1, 6], nil, nil, [1, 2, 1, 4]])
+
+ node = ast_parse("1 in a")
+ assert_locations(node.children[-1].children[1].locations, [[1, 5, 1, 6], [1, 2, 1, 4], nil, nil])
+
+ node = ast_parse("case 1; in 2; 3; end")
+ assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 16], [1, 8, 1, 10], [1, 12, 1, 13], nil])
+ end
+
def test_next_locations
node = ast_parse("loop { next 1 }")
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 13], [1, 7, 1, 11]])
@@ -1534,6 +1649,14 @@ dummy
assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 0, 1, 6]])
end
+ def test_sclass_locations
+ node = ast_parse("class << self; end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 18], [1, 0, 1, 5], [1, 6, 1, 8], [1, 15, 1, 18]])
+
+ node = ast_parse("class << obj; foo; end")
+ assert_locations(node.children[-1].locations, [[1, 0, 1, 22], [1, 0, 1, 5], [1, 6, 1, 8], [1, 19, 1, 22]])
+ end
+
def test_splat_locations
node = ast_parse("a = *1")
assert_locations(node.children[-1].children[1].locations, [[1, 4, 1, 6], [1, 4, 1, 5]])
@@ -1622,7 +1745,20 @@ dummy
node = ast_parse("def foo; yield(1, 2) end")
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 20], [1, 9, 1, 14], [1, 14, 1, 15], [1, 19, 1, 20]])
- end
+ end
+
+ def test_negative_numeric_locations
+ node = ast_parse("-1")
+ assert_locations(node.children.last.locations, [[1, 0, 1, 2]])
+ end
+
+ def test_numeric_location_with_nonsuffix
+ node = ast_parse("1if true")
+ assert_locations(node.children.last.children[1].locations, [[1, 0, 1, 1]])
+
+ node = ast_parse("1q", error_tolerant: true)
+ assert_locations(node.children.last.locations, [[1, 0, 1, 1]])
+ end
private
def ast_parse(src, **options)
@@ -1637,7 +1773,7 @@ dummy
def assert_locations(locations, expected)
ary = locations.map {|loc| loc && [loc.first_lineno, loc.first_column, loc.last_lineno, loc.last_column] }
- assert_equal(ary, expected)
+ assert_equal(expected, ary)
end
end
end
diff --git a/test/ruby/test_autoload.rb b/test/ruby/test_autoload.rb
index ca3e3d5f7f..de08be96e4 100644
--- a/test/ruby/test_autoload.rb
+++ b/test/ruby/test_autoload.rb
@@ -224,11 +224,18 @@ p Foo::Bar
Kernel.module_eval do
alias old_require require
end
+ Ruby::Box.module_eval do
+ alias old_require require
+ end
called_with = []
Kernel.send :define_method, :require do |path|
called_with << path
old_require path
end
+ Ruby::Box.send :define_method, :require do |path|
+ called_with << path
+ old_require path
+ end
yield called_with
ensure
Kernel.module_eval do
@@ -236,6 +243,11 @@ p Foo::Bar
alias require old_require
undef old_require
end
+ Ruby::Box.module_eval do
+ undef require
+ alias require old_require
+ undef old_require
+ end
end
def test_require_implemented_in_ruby_is_called
@@ -249,7 +261,8 @@ p Foo::Bar
ensure
remove_autoload_constant
end
- assert_equal [file.path], called_with
+ # .dup to prevent breaking called_with by autoloading pp, etc
+ assert_equal [file.path], called_with.dup
}
end
end
@@ -267,7 +280,8 @@ p Foo::Bar
ensure
remove_autoload_constant
end
- assert_equal [a.path, b.path], called_with
+ # .dup to prevent breaking called_with by autoloading pp, etc
+ assert_equal [a.path, b.path], called_with.dup
end
end
end
@@ -560,7 +574,7 @@ p Foo::Bar
autoload_path = File.join(tmpdir, "autoload_parallel_race.rb")
File.write(autoload_path, 'module Foo; end; module Bar; end')
- assert_separately([], <<-RUBY, timeout: 100)
+ assert_ruby_status([], <<-RUBY, timeout: 100)
autoload_path = #{File.realpath(autoload_path).inspect}
# This should work with no errors or failures.
@@ -599,4 +613,103 @@ p Foo::Bar
RUBY
end
end
+
+ def test_autoload_relative_toplevel
+ Dir.mktmpdir('autoload_relative') do |tmpdir|
+ main_file = File.join(tmpdir, 'main.rb')
+ module_file = File.join(tmpdir, 'test_module.rb')
+
+ File.write(module_file, <<-RUBY)
+ module AutoloadRelativeTest
+ VERSION = '1.0'
+ end
+ RUBY
+
+ File.write(main_file, <<-RUBY)
+ autoload_relative :AutoloadRelativeTest, 'test_module.rb'
+ puts AutoloadRelativeTest::VERSION
+ RUBY
+
+ assert_in_out_err([main_file], '', ['1.0'], [])
+ end
+ end
+
+ def test_autoload_relative_module_level
+ Dir.mktmpdir('autoload_relative') do |tmpdir|
+ main_file = File.join(tmpdir, 'main_mod.rb')
+ module_file = File.join(tmpdir, 'nested_module.rb')
+
+ File.write(module_file, <<-RUBY)
+ module Container
+ module NestedModule
+ MSG = 'loaded'
+ end
+ end
+ RUBY
+
+ File.write(main_file, <<-RUBY)
+ module Container
+ autoload_relative :NestedModule, 'nested_module.rb'
+ end
+ puts Container::NestedModule::MSG
+ RUBY
+
+ assert_in_out_err([main_file], '', ['loaded'], [])
+ end
+ end
+
+ def test_autoload_relative_query
+ Dir.mktmpdir('autoload_relative') do |tmpdir|
+ main_file = File.join(tmpdir, 'query_test.rb')
+ module_file = File.join(tmpdir, 'query_module.rb')
+
+ File.write(module_file, 'module QueryModule; end')
+
+ File.write(main_file, <<-RUBY)
+ autoload_relative :QueryModule, 'query_module.rb'
+ path = autoload?(:QueryModule)
+ # Use realpath for comparison to handle symlinks (e.g., /var -> /private/var on macOS)
+ real_tmpdir = File.realpath('#{tmpdir}')
+ puts path.start_with?(real_tmpdir) && path.end_with?('query_module.rb')
+ RUBY
+
+ assert_in_out_err([main_file], '', ['true'], [])
+ end
+ end
+
+ def test_autoload_relative_nested_directory
+ Dir.mktmpdir('autoload_relative') do |tmpdir|
+ nested_dir = File.join(tmpdir, 'nested')
+ Dir.mkdir(nested_dir)
+
+ main_file = File.join(tmpdir, 'nested_test.rb')
+ module_file = File.join(nested_dir, 'deep_module.rb')
+
+ File.write(module_file, 'module DeepModule; VALUE = 42; end')
+
+ File.write(main_file, <<-RUBY)
+ autoload_relative :DeepModule, 'nested/deep_module.rb'
+ puts DeepModule::VALUE
+ RUBY
+
+ assert_in_out_err([main_file], '', ['42'], [])
+ end
+ end
+
+ def test_autoload_relative_no_basepath
+ # Test that autoload_relative raises an error when called from eval without file context
+ assert_raise(LoadError) do
+ eval('autoload_relative :TestConst, "test.rb"')
+ end
+ end
+
+ private
+
+ def assert_separately(*args, **kwargs)
+ super(*args, timeout: 60, **kwargs)
+ end
+
+ def assert_ruby_status(*args, **kwargs)
+ super(*args, timeout: 60, **kwargs)
+ end
end
diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb
index fca7b62030..332d76c58e 100644
--- a/test/ruby/test_backtrace.rb
+++ b/test/ruby/test_backtrace.rb
@@ -191,6 +191,16 @@ class TestBacktrace < Test::Unit::TestCase
assert_equal(cl.map(&:to_s), ary.map(&:to_s))
end
+ def test_each_caller_location_single_cfunc_frame
+ assert_normal_exit <<~'RUBY'
+ tap { Thread.each_caller_location(1, 1) { |loc| loc.label } }
+ RUBY
+
+ cl = nil; ary = []
+ tap { cl = caller_locations(1, 1); Thread.each_caller_location(1, 1) { |x| ary << x } }
+ assert_equal(cl.map(&:to_s), ary.map(&:to_s))
+ end
+
def test_caller_locations_first_label
def self.label
caller_locations.first.label
@@ -454,4 +464,16 @@ class TestBacktrace < Test::Unit::TestCase
foo::Bar.baz
end;
end
+
+ def test_backtrace_internal_frame
+ backtrace = tap { break caller_locations(0) }
+ assert_equal(__FILE__, backtrace[1].path) # not "<internal:kernel>"
+ assert_equal("Kernel#tap", backtrace[1].label)
+ end
+
+ def test_backtrace_on_argument_error
+ lineno = __LINE__; [1, 2].inject(:tap)
+ rescue ArgumentError
+ assert_equal("#{ __FILE__ }:#{ lineno }:in 'Kernel#tap'", $!.backtrace[0].to_s)
+ end
end
diff --git a/test/ruby/test_beginendblock.rb b/test/ruby/test_beginendblock.rb
index 3706efab52..74da11abf4 100644
--- a/test/ruby/test_beginendblock.rb
+++ b/test/ruby/test_beginendblock.rb
@@ -40,7 +40,8 @@ class TestBeginEndBlock < Test::Unit::TestCase
assert_in_out_err([], "#{<<~"begin;"}#{<<~'end;'}", [], ['-:2: warning: END in method; use at_exit'])
begin;
def end1
- END {}
+ END {
+ }
end
end;
end
diff --git a/test/ruby/test_bignum.rb b/test/ruby/test_bignum.rb
index beef33e2a6..c366f794b2 100644
--- a/test/ruby/test_bignum.rb
+++ b/test/ruby/test_bignum.rb
@@ -605,6 +605,49 @@ class TestBignum < Test::Unit::TestCase
assert_equal(1, (-2**(BIGNUM_MIN_BITS*4))[BIGNUM_MIN_BITS*4])
end
+ def test_aref2
+ x = (0x123456789abcdef << (BIGNUM_MIN_BITS + 32)) | 0x12345678
+ assert_equal(x, x[0, x.bit_length])
+ assert_equal(x >> 10, x[10, x.bit_length])
+ assert_equal(0x45678, x[0, 20])
+ assert_equal(0x6780, x[-4, 16])
+ assert_equal(0x123456, x[x.bit_length - 21, 40])
+ assert_equal(0x6789ab, x[x.bit_length - 41, 24])
+ assert_equal(0, x[-20, 10])
+ assert_equal(0, x[x.bit_length + 10, 10])
+
+ assert_equal(0, x[5, 0])
+ assert_equal(0, (-x)[5, 0])
+
+ assert_equal(x >> 5, x[5, -1])
+ assert_equal(x << 5, x[-5, -1])
+ assert_equal((-x) >> 5, (-x)[5, -1])
+ assert_equal((-x) << 5, (-x)[-5, -1])
+
+ assert_equal(x << 5, x[-5, FIXNUM_MAX])
+ assert_equal(x >> 5, x[5, FIXNUM_MAX])
+ assert_equal(0, x[FIXNUM_MIN, 100])
+ assert_equal(0, (-x)[FIXNUM_MIN, 100])
+
+ y = (x << 160) | 0x1234_0000_0000_0000_1234_0000_0000_0000
+ assert_equal(0xffffedcc00, (-y)[40, 40])
+ assert_equal(0xfffffffedc, (-y)[52, 40])
+ assert_equal(0xffffedcbff, (-y)[104, 40])
+ assert_equal(0xfffff6e5d4, (-y)[y.bit_length - 20, 40])
+ assert_equal(0, (-y)[-20, 10])
+ assert_equal(0xfff, (-y)[y.bit_length + 10, 12])
+
+ z = (1 << (BIGNUM_MIN_BITS * 2)) - 1
+ assert_equal(0x400, (-z)[-10, 20])
+ assert_equal(1, (-z)[0, 20])
+ assert_equal(0, (-z)[10, 20])
+ assert_equal(1, (-z)[0, z.bit_length])
+ assert_equal(0, (-z)[z.bit_length - 10, 10])
+ assert_equal(0x400, (-z)[z.bit_length - 10, 11])
+ assert_equal(0xfff, (-z)[z.bit_length, 12])
+ assert_equal(0xfff00, (-z)[z.bit_length - 8, 20])
+ end
+
def test_hash
assert_nothing_raised { T31P.hash }
end
@@ -778,6 +821,9 @@ class TestBignum < Test::Unit::TestCase
assert_equal([7215, 2413, 6242], T1024P.digits(10_000).first(3))
assert_equal([11], 11.digits(T1024P))
assert_equal([T1024P - 1, 1], (T1024P + T1024P - 1).digits(T1024P))
+ bug21680 = '[ruby-core:123769] [Bug #21680]'
+ assert_equal([0] * 64 + [1], (2**512).digits(256), bug21680)
+ assert_equal([0] * 128 + [1], (123**128).digits(123), bug21680)
end
def test_digits_for_negative_numbers
diff --git a/test/ruby/test_box.rb b/test/ruby/test_box.rb
new file mode 100644
index 0000000000..a425c5eb7d
--- /dev/null
+++ b/test/ruby/test_box.rb
@@ -0,0 +1,1219 @@
+# frozen_string_literal: true
+
+require 'test/unit'
+require 'rbconfig'
+require 'tempfile'
+
+class TestBox < Test::Unit::TestCase
+ EXPERIMENTAL_WARNING_LINE_PATTERNS = [
+ /#{RbConfig::CONFIG["ruby_install_name"] || "ruby"}(\.exe)?: warning: Ruby::Box is experimental, and the behavior may change in the future!/,
+ %r{See https://docs.ruby-lang.org/en/(master|\d\.\d)/Ruby/Box.html for known issues, etc.}
+ ]
+ ENV_ENABLE_BOX = {'RUBY_BOX' => '1', 'TEST_DIR' => __dir__}
+
+ def setup
+ @box = nil
+ @dir = __dir__
+ end
+
+ def teardown
+ @box = nil
+ end
+
+ def setup_box
+ pend unless Ruby::Box.enabled?
+ @box = Ruby::Box.new
+ end
+
+ def test_box_availability_in_default
+ assert_separately(['RUBY_BOX'=>nil], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ assert_nil ENV['RUBY_BOX']
+ assert_not_predicate Ruby::Box, :enabled?
+ end;
+ end
+
+ def test_box_availability_when_enabled
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ assert_equal '1', ENV['RUBY_BOX']
+ assert_predicate Ruby::Box, :enabled?
+ end;
+ end
+
+ def test_current_box_in_main
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ assert_equal Ruby::Box.main, Ruby::Box.current
+ assert_predicate Ruby::Box.main, :main?
+ end;
+ end
+
+ def test_require_rb_separately
+ setup_box
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+
+ @box.require(File.join(__dir__, 'box', 'a.1_1_0'))
+
+ assert_not_nil @box::BOX_A
+ assert_not_nil @box::BOX_B
+ assert_equal "1.1.0", @box::BOX_A::VERSION
+ assert_equal "yay 1.1.0", @box::BOX_A.new.yay
+ assert_equal "1.1.0", @box::BOX_B::VERSION
+ assert_equal "yay_b1", @box::BOX_B.yay
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+ end
+
+ def test_require_relative_rb_separately
+ setup_box
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+
+ @box.require_relative('box/a.1_1_0')
+
+ assert_not_nil @box::BOX_A
+ assert_not_nil @box::BOX_B
+ assert_equal "1.1.0", @box::BOX_A::VERSION
+ assert_equal "yay 1.1.0", @box::BOX_A.new.yay
+ assert_equal "1.1.0", @box::BOX_B::VERSION
+ assert_equal "yay_b1", @box::BOX_B.yay
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+ end
+
+ def test_load_separately
+ setup_box
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+
+ @box.load(File.join(__dir__, 'box', 'a.1_1_0.rb'))
+
+ assert_not_nil @box::BOX_A
+ assert_not_nil @box::BOX_B
+ assert_equal "1.1.0", @box::BOX_A::VERSION
+ assert_equal "yay 1.1.0", @box::BOX_A.new.yay
+ assert_equal "1.1.0", @box::BOX_B::VERSION
+ assert_equal "yay_b1", @box::BOX_B.yay
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+ end
+
+ def test_box_in_box
+ setup_box
+
+ assert_raise(NameError) { BOX1 }
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+
+ @box.require_relative('box/box')
+
+ assert_not_nil @box::BOX1
+ assert_not_nil @box::BOX1::BOX_A
+ assert_not_nil @box::BOX1::BOX_B
+ assert_equal "1.1.0", @box::BOX1::BOX_A::VERSION
+ assert_equal "yay 1.1.0", @box::BOX1::BOX_A.new.yay
+ assert_equal "1.1.0", @box::BOX1::BOX_B::VERSION
+ assert_equal "yay_b1", @box::BOX1::BOX_B.yay
+
+ assert_raise(NameError) { BOX1 }
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+ end
+
+ def test_require_rb_2versiobox
+ setup_box
+
+ assert_raise(NameError) { BOX_A }
+
+ @box.require(File.join(__dir__, 'box', 'a.1_2_0'))
+ assert_equal "1.2.0", @box::BOX_A::VERSION
+ assert_equal "yay 1.2.0", @box::BOX_A.new.yay
+
+ n2 = Ruby::Box.new
+ n2.require(File.join(__dir__, 'box', 'a.1_1_0'))
+ assert_equal "1.1.0", n2::BOX_A::VERSION
+ assert_equal "yay 1.1.0", n2::BOX_A.new.yay
+
+ # recheck @box is not affected by the following require
+ assert_equal "1.2.0", @box::BOX_A::VERSION
+ assert_equal "yay 1.2.0", @box::BOX_A.new.yay
+
+ assert_raise(NameError) { BOX_A }
+ end
+
+ def test_raising_errors_in_require
+ setup_box
+
+ assert_raise(RuntimeError, "Yay!") { @box.require(File.join(__dir__, 'box', 'raise')) }
+ assert_include Ruby::Box.current.inspect, "main"
+ end
+
+ def test_class_variables_in_root_are_invisible_in_other_boxes
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "here = '#{__dir__}'; #{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ Ruby::Box.root.eval(<<~RUBY)
+ module M
+ @@x = 1
+ end
+
+ class A
+ include M
+ end
+
+ class B < A
+ end
+ RUBY
+
+ code = <<~REPRO
+ class ::B
+ @@x += 1
+ end
+ REPRO
+
+ b1 = Ruby::Box.new
+ assert_raise(NameError, "uninitialized class variable @@x in B") {
+ b1.eval(code)
+ }
+ end;
+ end
+
+ def test_autoload_in_box
+ setup_box
+
+ assert_raise(NameError) { BOX_A }
+
+ @box.require_relative('box/autoloading')
+ # autoloaded A is visible from global
+ assert_equal '1.1.0', @box::BOX_A::VERSION
+
+ assert_raise(NameError) { BOX_A }
+
+ # autoload trigger BOX_B::BAR is valid even from global
+ assert_equal 'bar_b1', @box::BOX_B::BAR
+
+ assert_raise(NameError) { BOX_A }
+ assert_raise(NameError) { BOX_B }
+ end
+
+ def test_continuous_top_level_method_in_a_box
+ setup_box
+
+ @box.require_relative('box/define_toplevel')
+ @box.require_relative('box/call_toplevel')
+
+ assert_raise(NameError) { foo }
+ end
+
+ def test_top_level_methods_in_box
+ pend # TODO: fix loading/current box detection
+ setup_box
+ @box.require_relative('box/top_level')
+ assert_equal "yay!", @box::Foo.foo
+ assert_raise(NameError) { yaaay }
+ assert_equal "foo", @box::Bar.bar
+ assert_raise_with_message(RuntimeError, "boooo") { @box::Baz.baz }
+ end
+
+ def test_proc_defined_in_box_refers_module_in_box
+ setup_box
+
+ # require_relative dosn't work well in assert_separately even with __FILE__ and __LINE__
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "here = '#{__dir__}'; #{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ box1 = Ruby::Box.new
+ box1.require("#{here}/box/proc_callee")
+ proc_v = box1::Foo.callee
+ assert_raise(NameError) { Target }
+ assert box1::Target
+ assert_equal "fooooo", proc_v.call # refers Target in the box box1
+ box1.require("#{here}/box/proc_caller")
+ assert_equal "fooooo", box1::Bar.caller(proc_v)
+
+ box2 = Ruby::Box.new
+ box2.require("#{here}/box/proc_caller")
+ assert_raise(NameError) { box2::Target }
+ assert_equal "fooooo", box2::Bar.caller(proc_v) # refers Target in the box box1
+ end;
+ end
+
+ def test_proc_defined_globally_refers_global_module
+ setup_box
+
+ # require_relative dosn't work well in assert_separately even with __FILE__ and __LINE__
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "here = '#{__dir__}'; #{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ require("#{here}/box/proc_callee")
+ def Target.foo
+ "yay"
+ end
+ proc_v = Foo.callee
+ assert Target
+ assert_equal "yay", proc_v.call # refers global Foo
+ box1 = Ruby::Box.new
+ box1.require("#{here}/box/proc_caller")
+ assert_equal "yay", box1::Bar.caller(proc_v)
+
+ box2 = Ruby::Box.new
+ box2.require("#{here}/box/proc_callee")
+ box2.require("#{here}/box/proc_caller")
+ assert_equal "fooooo", box2::Foo.callee.call
+ assert_equal "yay", box2::Bar.caller(proc_v) # should refer the global Target, not Foo in box2
+ end;
+ end
+
+ def test_instance_variable
+ setup_box
+
+ @box.require_relative('box/instance_variables')
+
+ assert_equal [], String.instance_variables
+ assert_equal [:@str_ivar1, :@str_ivar2], @box::StringDelegatorObj.instance_variables
+ assert_equal 111, @box::StringDelegatorObj.str_ivar1
+ assert_equal 222, @box::StringDelegatorObj.str_ivar2
+ assert_equal 222, @box::StringDelegatorObj.instance_variable_get(:@str_ivar2)
+
+ @box::StringDelegatorObj.instance_variable_set(:@str_ivar3, 333)
+ assert_equal 333, @box::StringDelegatorObj.instance_variable_get(:@str_ivar3)
+ @box::StringDelegatorObj.remove_instance_variable(:@str_ivar1)
+ assert_nil @box::StringDelegatorObj.str_ivar1
+ assert_equal [:@str_ivar2, :@str_ivar3], @box::StringDelegatorObj.instance_variables
+
+ assert_equal [], String.instance_variables
+ end
+
+ def test_methods_added_in_box_are_invisible_globally
+ setup_box
+
+ @box.require_relative('box/string_ext')
+
+ assert_equal "yay", @box::Bar.yay
+
+ assert_raise(NoMethodError){ String.new.yay }
+ end
+
+ def test_continuous_method_definitions_in_a_box
+ setup_box
+
+ @box.require_relative('box/string_ext')
+ assert_equal "yay", @box::Bar.yay
+
+ @box.require_relative('box/string_ext_caller')
+ assert_equal "yay", @box::Foo.yay
+
+ @box.require_relative('box/string_ext_calling')
+ end
+
+ def test_methods_added_in_box_later_than_caller_code
+ setup_box
+
+ @box.require_relative('box/string_ext_caller')
+ @box.require_relative('box/string_ext')
+
+ assert_equal "yay", @box::Bar.yay
+ assert_equal "yay", @box::Foo.yay
+ end
+
+ def test_method_added_in_box_are_available_on_eval
+ setup_box
+
+ @box.require_relative('box/string_ext')
+ @box.require_relative('box/string_ext_eval_caller')
+
+ assert_equal "yay", @box::Baz.yay
+ end
+
+ def test_method_added_in_box_are_available_on_eval_with_binding
+ setup_box
+
+ @box.require_relative('box/string_ext')
+ @box.require_relative('box/string_ext_eval_caller')
+
+ assert_equal "yay, yay!", @box::Baz.yay_with_binding
+ end
+
+ def test_methods_and_constants_added_by_include
+ setup_box
+
+ @box.require_relative('box/open_class_with_include')
+
+ assert_equal "I'm saying foo 1", @box::OpenClassWithInclude.say
+ assert_equal "I'm saying foo 1", @box::OpenClassWithInclude.say_foo
+ assert_equal "I'm saying foo 1", @box::OpenClassWithInclude.say_with_obj("wow")
+
+ assert_raise(NameError) { String::FOO }
+
+ assert_equal "foo 1", @box::OpenClassWithInclude.refer_foo
+ end
+end
+
+module ProcLookupTestA
+ module B
+ VALUE = 111
+ end
+end
+
+class TestBox < Test::Unit::TestCase
+ def make_proc_from_block(&b)
+ b
+ end
+
+ def test_proc_from_main_works_with_global_definitions
+ setup_box
+
+ @box.require_relative('box/procs')
+
+ proc_and_labels = [
+ [Proc.new { String.new.yay }, "Proc.new"],
+ [proc { String.new.yay }, "proc{}"],
+ [lambda { String.new.yay }, "lambda{}"],
+ [->(){ String.new.yay }, "->(){}"],
+ [make_proc_from_block { String.new.yay }, "make_proc_from_block"],
+ [@box::ProcInBox.make_proc_from_block { String.new.yay }, "make_proc_from_block in @box"],
+ ]
+
+ proc_and_labels.each do |str_pr|
+ pr, pr_label = str_pr
+ assert_raise(NoMethodError, "NoMethodError expected: #{pr_label}, called in main") { pr.call }
+ assert_raise(NoMethodError, "NoMethodError expected: #{pr_label}, called in @box") { @box::ProcInBox.call_proc(pr) }
+ end
+
+ const_and_labels = [
+ [Proc.new { ProcLookupTestA::B::VALUE }, "Proc.new"],
+ [proc { ProcLookupTestA::B::VALUE }, "proc{}"],
+ [lambda { ProcLookupTestA::B::VALUE }, "lambda{}"],
+ [->(){ ProcLookupTestA::B::VALUE }, "->(){}"],
+ [make_proc_from_block { ProcLookupTestA::B::VALUE }, "make_proc_from_block"],
+ [@box::ProcInBox.make_proc_from_block { ProcLookupTestA::B::VALUE }, "make_proc_from_block in @box"],
+ ]
+
+ const_and_labels.each do |const_pr|
+ pr, pr_label = const_pr
+ assert_equal 111, pr.call, "111 expected, #{pr_label} called in main"
+ assert_equal 111, @box::ProcInBox.call_proc(pr), "111 expected, #{pr_label} called in @box"
+ end
+ end
+
+ def test_proc_from_box_works_with_definitions_in_box
+ setup_box
+
+ @box.require_relative('box/procs')
+
+ proc_types = [:proc_new, :proc_f, :lambda_f, :lambda_l, :block]
+
+ proc_types.each do |proc_type|
+ assert_equal 222, @box::ProcInBox.make_const_proc(proc_type).call, "ProcLookupTestA::B::VALUE should be 222 in @box"
+ assert_equal "foo", @box::ProcInBox.make_str_const_proc(proc_type).call, "String::FOO should be \"foo\" in @box"
+ assert_equal "yay", @box::ProcInBox.make_str_proc(proc_type).call, "String#yay should be callable in @box"
+ #
+ # TODO: method calls not-in-methods nor procs can't handle the current box correctly.
+ #
+ # assert_equal "yay,foo,222",
+ # @box::ProcInBox.const_get(('CONST_' + proc_type.to_s.upcase).to_sym).call,
+ # "Proc assigned to constants should refer constants correctly in @box"
+ end
+ end
+
+ def test_class_module_singleton_methods
+ setup_box
+
+ @box.require_relative('box/singleton_methods')
+
+ assert_equal "Good evening!", @box::SingletonMethods.string_greeing # def self.greeting
+ assert_equal 42, @box::SingletonMethods.integer_answer # class << self; def answer
+ assert_equal([], @box::SingletonMethods.array_blank) # def self.blank w/ instance methods
+ assert_equal({status: 200, body: 'OK'}, @box::SingletonMethods.hash_http_200) # class << self; def ... w/ instance methods
+
+ assert_equal([4, 4], @box::SingletonMethods.array_instance_methods_return_size([1, 2, 3, 4]))
+ assert_equal([3, 3], @box::SingletonMethods.hash_instance_methods_return_size({a: 2, b: 4, c: 8}))
+
+ assert_raise(NoMethodError) { String.greeting }
+ assert_raise(NoMethodError) { Integer.answer }
+ assert_raise(NoMethodError) { Array.blank }
+ assert_raise(NoMethodError) { Hash.http_200 }
+ end
+
+ def test_add_constants_in_box
+ setup_box
+
+ @box.require('envutil')
+
+ String.const_set(:STR_CONST0, 999)
+ assert_equal 999, String::STR_CONST0
+ assert_equal 999, String.const_get(:STR_CONST0)
+
+ assert_raise(NameError) { String.const_get(:STR_CONST1) }
+ assert_raise(NameError) { String::STR_CONST2 }
+ assert_raise(NameError) { String::STR_CONST3 }
+ assert_raise(NameError) { Integer.const_get(:INT_CONST1) }
+
+ EnvUtil.verbose_warning do
+ @box.require_relative('box/consts')
+ end
+
+ assert_equal 999, String::STR_CONST0
+ assert_raise(NameError) { String::STR_CONST1 }
+ assert_raise(NameError) { String::STR_CONST2 }
+ assert_raise(NameError) { Integer::INT_CONST1 }
+
+ assert_not_nil @box::ForConsts.refer_all
+
+ assert_equal 112, @box::ForConsts.refer1
+ assert_equal 112, @box::ForConsts.get1
+ assert_equal 112, @box::ForConsts::CONST1
+ assert_equal 222, @box::ForConsts.refer2
+ assert_equal 222, @box::ForConsts.get2
+ assert_equal 222, @box::ForConsts::CONST2
+ assert_equal 333, @box::ForConsts.refer3
+ assert_equal 333, @box::ForConsts.get3
+ assert_equal 333, @box::ForConsts::CONST3
+
+ @box::EnvUtil.suppress_warning do
+ @box::ForConsts.const_set(:CONST3, 334)
+ end
+ assert_equal 334, @box::ForConsts::CONST3
+ assert_equal 334, @box::ForConsts.refer3
+ assert_equal 334, @box::ForConsts.get3
+
+ assert_equal 10, @box::ForConsts.refer_top_const
+
+ # use Proxy object to use usual methods instead of singleton methods
+ proxy = @box::ForConsts::Proxy.new
+
+ assert_raise(NameError){ proxy.call_str_refer0 }
+ assert_raise(NameError){ proxy.call_str_get0 }
+
+ proxy.call_str_set0(30)
+ assert_equal 30, proxy.call_str_refer0
+ assert_equal 30, proxy.call_str_get0
+ assert_equal 999, String::STR_CONST0
+
+ proxy.call_str_remove0
+ assert_raise(NameError){ proxy.call_str_refer0 }
+ assert_raise(NameError){ proxy.call_str_get0 }
+
+ assert_equal 112, proxy.call_str_refer1
+ assert_equal 112, proxy.call_str_get1
+ assert_equal 223, proxy.call_str_refer2
+ assert_equal 223, proxy.call_str_get2
+ assert_equal 333, proxy.call_str_refer3
+ assert_equal 333, proxy.call_str_get3
+
+ EnvUtil.suppress_warning do
+ proxy.call_str_set3
+ end
+ assert_equal 334, proxy.call_str_refer3
+ assert_equal 334, proxy.call_str_get3
+
+ assert_equal 1, proxy.refer_int_const1
+
+ assert_equal 999, String::STR_CONST0
+ assert_raise(NameError) { String::STR_CONST1 }
+ assert_raise(NameError) { String::STR_CONST2 }
+ assert_raise(NameError) { String::STR_CONST3 }
+ assert_raise(NameError) { Integer::INT_CONST1 }
+ end
+
+ def test_global_variables
+ default_l = $-0
+ default_f = $,
+
+ setup_box
+
+ assert_equal "\n", $-0 # equal to $/, line splitter
+ assert_equal nil, $, # field splitter
+
+ @box.require_relative('box/global_vars')
+
+ # read first
+ assert_equal "\n", @box::LineSplitter.read
+ @box::LineSplitter.write("\r\n")
+ assert_equal "\r\n", @box::LineSplitter.read
+ assert_equal "\n", $-0
+
+ # write first
+ @box::FieldSplitter.write(",")
+ assert_equal ",", @box::FieldSplitter.read
+ assert_equal nil, $,
+
+ # used only in box
+ assert_not_include? global_variables, :$used_only_in_box
+ @box::UniqueGvar.write(123)
+ assert_equal 123, @box::UniqueGvar.read
+ assert_nil $used_only_in_box
+
+ # Kernel#global_variables returns the sum of all gvars.
+ global_gvars = global_variables.sort
+ assert_equal global_gvars, @box::UniqueGvar.gvars_in_box.sort
+ @box::UniqueGvar.write_only(456)
+ assert_equal (global_gvars + [:$write_only_var_in_box]).sort, @box::UniqueGvar.gvars_in_box.sort
+ assert_equal (global_gvars + [:$write_only_var_in_box]).sort, global_variables.sort
+ ensure
+ EnvUtil.suppress_warning do
+ $-0 = default_l
+ $, = default_f
+ end
+ end
+
+ def test_match_variables_are_not_cached_in_box
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ /(?<a>foo)/ =~ 'bar'
+ /(?<b>baz)/ =~ 'baz'
+ assert_equal "baz", b
+ assert_equal "baz", $~.to_s
+
+ /foo/ =~ 'bar'
+ assert_nil $~
+ /(?<word>foo)(bar)?/ =~ 'foo'
+ assert_equal "foo", word
+ assert_equal "foo", $~.to_s
+ assert_equal "foo", $&
+ assert_equal "", $`
+ assert_equal "", $'
+ assert_equal "foo", $+
+ end;
+ end
+
+ def test_lastline_not_cached_in_box
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ r, w = IO.pipe
+ w.write("first\nsecond\n")
+ w.close
+ STDIN.reopen(r)
+ via_gets = Ruby::Box.new.eval(<<~'CODE')
+ gets
+ _ = $_
+ gets
+ $_
+ CODE
+ assert_equal "second\n", via_gets
+ end;
+ end
+
+ def test_lastline_not_cached_in_nested_boxes
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ r, w = IO.pipe
+ w.write("outer1\ninner1\ninner2\nouter2\n")
+ w.close
+ STDIN.reopen(r)
+ inner_via_gets, outer_via_gets = Ruby::Box.new.eval(<<~'CODE')
+ gets
+ _ = $_
+
+ inner_result = Ruby::Box.new.eval(<<~'INNER')
+ gets
+ _ = $_
+ gets
+ $_
+ INNER
+
+ gets
+ [inner_result, $_]
+ CODE
+ assert_equal "inner2\n", inner_via_gets
+ assert_equal "outer2\n", outer_via_gets
+ end;
+ end
+
+ def test_errinfo_not_cached_in_box
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ first, second = Ruby::Box.new.eval(<<~'CODE')
+ a = begin; raise "first"; rescue RuntimeError; $!.message; end
+ b = begin; raise "second"; rescue RuntimeError; $!.message; end
+ [a, b]
+ CODE
+ assert_equal "first", first
+ assert_equal "second", second
+ end;
+ end
+
+ def test_errinfo_not_cached_in_nested_boxes
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ inner_msg, outer_msg = Ruby::Box.new.eval(<<~'CODE')
+ outer_a = begin; raise "outer1"; rescue RuntimeError; $!.message; end
+
+ inner_msg = Ruby::Box.new.eval(<<~'INNER')
+ begin; raise "inner1"; rescue RuntimeError; $!; end
+ begin; raise "inner2"; rescue RuntimeError; $!.message; end
+ INNER
+
+ outer_b = begin; raise "outer2"; rescue RuntimeError; $!.message; end
+ [inner_msg, outer_b]
+ CODE
+ assert_equal "inner2", inner_msg
+ assert_equal "outer2", outer_msg
+ end;
+ end
+
+ def test_backtrace_not_cached_in_box
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ a_actual, b_actual = Ruby::Box.new.eval(<<~'CODE')
+ a_actual = begin; raise "first"; rescue RuntimeError; $@.first[/:(\d+):/, 1].to_i; end
+ b_actual = begin; raise "second"; rescue RuntimeError; $@.first[/:(\d+):/, 1].to_i; end
+ [a_actual, b_actual]
+ CODE
+ assert_equal 1, a_actual
+ assert_equal 2, b_actual
+ end;
+ end
+
+ def test_backtrace_not_cached_in_nested_boxes
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ inner_actual, outer_actual = Ruby::Box.new.eval(<<~'CODE')
+ begin; raise "outer1"; rescue RuntimeError; $@; end
+ inner_actual = Ruby::Box.new.eval(<<~'INNER')
+ begin; raise "inner1"; rescue RuntimeError; $@; end
+ begin; raise "inner2"; rescue RuntimeError; $@.first[/:(\d+):/, 1].to_i; end
+ INNER
+ outer_actual = begin; raise "outer2"; rescue RuntimeError; $@.first[/:(\d+):/, 1].to_i; end
+ [inner_actual, outer_actual]
+ CODE
+ assert_equal 2, inner_actual
+ assert_equal 6, outer_actual
+ end;
+ end
+
+ def test_errinfo_isolated_between_boxes
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ box_a = Ruby::Box.new
+ box_b = Ruby::Box.new
+
+ a = box_a.eval('begin; raise "a"; rescue; $!.message; end')
+ b = box_b.eval('begin; raise "b"; rescue; $!.message; end')
+
+ assert_equal "a", a
+ assert_equal "b", b
+ end;
+ end
+
+ def test_backtrace_isolated_between_boxes
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ box_a = Ruby::Box.new
+ box_b = Ruby::Box.new
+
+ a_line = box_a.eval("\nbegin; raise; rescue; $@.first[/:(\\d+):/, 1].to_i; end")
+ b_line = box_b.eval('begin; raise; rescue; $@.first[/:(\d+):/, 1].to_i; end')
+
+ assert_equal 2, a_line
+ assert_equal 1, b_line
+ end;
+ end
+
+ def test_inner_box_rescue_does_not_disturb_outer_box_errinfo
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ box_a = Ruby::Box.new
+ errinfo_in_inner_rescue, errinfo_after_inner_rescue, errinfo_back_in_outer_rescue = box_a.eval(<<~'A')
+ errinfo_in_inner_rescue = errinfo_after_inner_rescue = errinfo_back_in_outer_rescue = nil
+ begin
+ raise "outer"
+ rescue
+ errinfo_in_inner_rescue, errinfo_after_inner_rescue = Ruby::Box.new.eval(<<~'B')
+ in_rescue = after_rescue = nil
+ begin
+ raise "inner"
+ rescue
+ in_rescue = $! && $!.message
+ end
+ after_rescue = $! && $!.message
+ [in_rescue, after_rescue]
+ B
+ errinfo_back_in_outer_rescue = $! && $!.message
+ end
+ [errinfo_in_inner_rescue, errinfo_after_inner_rescue, errinfo_back_in_outer_rescue]
+ A
+
+ assert_equal "inner", errinfo_in_inner_rescue
+ assert_equal "outer", errinfo_after_inner_rescue
+ assert_equal "outer", errinfo_back_in_outer_rescue
+ end;
+ end
+
+ def test_load_path_and_loaded_features
+ setup_box
+
+ assert_respond_to $LOAD_PATH, :resolve_feature_path
+
+ @box.require_relative('box/load_path')
+
+ assert_not_equal $LOAD_PATH, @box::LoadPathCheck::FIRST_LOAD_PATH
+
+ assert @box::LoadPathCheck::FIRST_LOAD_PATH_RESPOND_TO_RESOLVE
+
+ box_dir = File.join(__dir__, 'box')
+ # TODO: $LOADED_FEATURES in method calls should refer the current box in addition to the loading box.
+ # assert_include @box::LoadPathCheck.current_loaded_features, File.join(box_dir, 'blank1.rb')
+ # assert_not_include @box::LoadPathCheck.current_loaded_features, File.join(box_dir, 'blank2.rb')
+ # assert_predicate @box::LoadPathCheck, :require_blank2
+ # assert_include(@box::LoadPathCheck.current_loaded_features, File.join(box_dir, 'blank2.rb'))
+
+ assert_not_include $LOADED_FEATURES, File.join(box_dir, 'blank1.rb')
+ assert_not_include $LOADED_FEATURES, File.join(box_dir, 'blank2.rb')
+ end
+
+ def test_eval_basic
+ setup_box
+
+ # Test basic evaluation
+ result = @box.eval("1 + 1")
+ assert_equal 2, result
+
+ # Test string evaluation
+ result = @box.eval("'hello ' + 'world'")
+ assert_equal "hello world", result
+ end
+
+ def test_eval_with_constants
+ setup_box
+
+ # Define a constant in the box via eval
+ @box.eval("TEST_CONST = 42")
+ assert_equal 42, @box::TEST_CONST
+
+ # Constant should not be visible in main box
+ assert_raise(NameError) { TEST_CONST }
+ end
+
+ def test_eval_with_classes
+ setup_box
+
+ # Define a class in the box via eval
+ @box.eval("class TestClass; def hello; 'from box'; end; end")
+
+ # Class should be accessible in the box
+ instance = @box::TestClass.new
+ assert_equal "from box", instance.hello
+
+ # Class should not be visible in main box
+ assert_raise(NameError) { TestClass }
+ end
+
+ def test_eval_isolation
+ setup_box
+
+ # Create another box
+ n2 = Ruby::Box.new
+
+ # Define different constants in each box
+ @box.eval("ISOLATION_TEST = 'first'")
+ n2.eval("ISOLATION_TEST = 'second'")
+
+ # Each box should have its own constant
+ assert_equal "first", @box::ISOLATION_TEST
+ assert_equal "second", n2::ISOLATION_TEST
+
+ # Constants should not interfere with each other
+ assert_not_equal @box::ISOLATION_TEST, n2::ISOLATION_TEST
+ end
+
+ def test_eval_with_variables
+ setup_box
+
+ # Test local variable access (should work within the eval context)
+ result = @box.eval("x = 10; y = 20; x + y")
+ assert_equal 30, result
+ end
+
+ def test_eval_error_handling
+ setup_box
+
+ # Test syntax error
+ assert_raise(SyntaxError) { @box.eval("1 +") }
+
+ # Test name error
+ assert_raise(NameError) { @box.eval("undefined_variable") }
+
+ # Test that box is properly restored after error
+ begin
+ @box.eval("raise RuntimeError, 'test error'")
+ rescue RuntimeError
+ # Should be able to continue using the box
+ result = @box.eval("2 + 2")
+ assert_equal 4, result
+ end
+ end
+
+ # Tests which run always (w/o RUBY_BOX=1 globally)
+
+ def test_prelude_gems_and_loaded_features
+ assert_in_out_err([ENV_ENABLE_BOX, "--enable=gems"], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
+ begin;
+ puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
+ puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
+
+ require "error_highlight"
+
+ puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
+ puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
+ end;
+
+ # No additional warnings except for experimental warnings
+ assert_equal 2, error.size
+ assert_match EXPERIMENTAL_WARNING_LINE_PATTERNS[0], error[0]
+ assert_match EXPERIMENTAL_WARNING_LINE_PATTERNS[1], error[1]
+
+ assert_includes output.grep(/^before:/).join("\n"), '/bundled_gems.rb'
+ assert_includes output.grep(/^before:/).join("\n"), '/error_highlight.rb'
+ assert_includes output.grep(/^after:/).join("\n"), '/bundled_gems.rb'
+ assert_includes output.grep(/^after:/).join("\n"), '/error_highlight.rb'
+ end
+ end
+
+ def test_prelude_gems_and_loaded_features_with_disable_gems
+ assert_in_out_err([ENV_ENABLE_BOX, "--disable=gems"], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
+ begin;
+ puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
+ puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
+
+ require "error_highlight"
+
+ puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
+ puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
+ end;
+
+ assert_equal 2, error.size
+ assert_match EXPERIMENTAL_WARNING_LINE_PATTERNS[0], error[0]
+ assert_match EXPERIMENTAL_WARNING_LINE_PATTERNS[1], error[1]
+
+ refute_includes output.grep(/^before:/).join("\n"), '/bundled_gems.rb'
+ refute_includes output.grep(/^before:/).join("\n"), '/error_highlight.rb'
+ refute_includes output.grep(/^after:/).join("\n"), '/bundled_gems.rb'
+ assert_includes output.grep(/^after:/).join("\n"), '/error_highlight.rb'
+ end
+ end
+
+ def test_calling_root_box_methods_does_not_change_user_boxes_newly_created
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true, timeout: 60)
+ begin;
+ assert_not_include Object.constants.sort, :Find # required by Pathname#find
+ assert_not_include Ruby::Box.root.eval("Object.constants.sort"), :Find
+ b1 = Ruby::Box.new
+ assert_not_include b1.eval("Object.constants.sort"), :Find
+
+ require 'pathname'
+ Pathname.new('.').find{|path| path.directory?}
+ assert_include Object.constants.sort, :Find # required by Pathname#find
+
+ assert_not_include Ruby::Box.root.eval("Object.constants.sort"), :Find
+ assert_not_include b1.eval("Object.constants.sort"), :Find
+
+ Ruby::Box.root.eval("require 'pathname'; Pathname.new('.').find{|path| path.directory? }")
+ assert_include Ruby::Box.root.eval("Object.constants.sort"), :Find
+
+ assert_not_include b1.eval("Object.constants.sort"), :Find
+ b2 = Ruby::Box.new
+ assert_not_include b2.eval("Object.constants.sort"), :Find
+ end;
+ end
+
+ def test_boxes_have_different_rubygems
+ # assert_separately w/ ENV_ENABLE_BOX and --enable=gems causes timeouts on CI @ Windows
+ assert_in_out_err([ENV_ENABLE_BOX, "--enable=gems"], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
+ begin;
+ require "json"
+ h = {main: Gem.object_id, root: Ruby::Box.root.eval("Gem").object_id, box: Ruby::Box.new.eval("Gem").object_id}
+ puts h.to_json
+ end;
+ require "json"
+ result = JSON.parse(output.first, symbolize_names: true)
+ assert_not_equal result[:main], result[:root]
+ assert_not_equal result[:box], result[:root]
+ assert_not_equal result[:main], result[:box]
+ end
+ end
+
+ def test_require_list_loaded_only_in_main_box
+ Tempfile.create(["req_a", ".rb"]) do |t1|
+ Tempfile.create(["req_b", ".rb"]) do |t2|
+ t1.puts "module FooBarA; end"
+ t1.close
+ t2.puts "module FooBarB; end"
+ t2.close
+
+ opts = [ENV_ENABLE_BOX, "-r#{t1.path}", "-r#{t2.path}"]
+ assert_separately(opts, __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ main_constants = Object.constants
+ assert_include main_constants, :FooBarA
+ assert_include main_constants, :FooBarB
+
+ root_constants = Ruby::Box.root.eval("Object.constants.sort")
+ master_constants = Ruby::Box.master.eval("Object.constants.sort")
+ assert_not_include root_constants, :FooBarA
+ assert_not_include root_constants, :FooBarB
+ assert_not_include master_constants, :FooBarA
+ assert_not_include master_constants, :FooBarB
+ end;
+ end
+ end
+ end
+
+ def test_root_and_main_methods
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ pend unless Ruby::Box.respond_to?(:root) and Ruby::Box.respond_to?(:main) # for RUBY_DEBUG > 0
+
+ assert_respond_to Ruby::Box.root, :root?
+ assert_respond_to Ruby::Box.main, :main?
+
+ assert_predicate Ruby::Box.root, :root?
+ assert_predicate Ruby::Box.main, :main?
+ assert_equal Ruby::Box.main, Ruby::Box.current
+
+ $a = 1
+ $LOADED_FEATURES.push("/tmp/foobar")
+
+ assert_equal 2, Ruby::Box.root.eval('$a = 2; $a')
+ assert_not_include Ruby::Box.root.eval('$LOADED_FEATURES.push("/tmp/barbaz"); $LOADED_FEATURES'), "/tmp/foobar"
+ assert_equal "FooClass", Ruby::Box.root.eval('class FooClass; end; Object.const_get(:FooClass).to_s')
+
+ assert_equal 1, $a
+ assert_not_include $LOADED_FEATURES, "/tmp/barbaz"
+ assert_not_operator Object, :const_defined?, :FooClass
+ end;
+ end
+
+ def test_basic_box_detections
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ box = Ruby::Box.new
+ $gvar1 = 'bar'
+ code = <<~EOC
+ BOX1 = Ruby::Box.current
+ $gvar1 = 'foo'
+
+ def toplevel = $gvar1
+
+ class Foo
+ BOX2 = Ruby::Box.current
+ BOX2_proc = ->(){ BOX2 }
+ BOX3_proc = ->(){ Ruby::Box.current }
+
+ def box4 = Ruby::Box.current
+ def self.box5 = BOX2
+ def self.box6 = Ruby::Box.current
+ def self.box6_proc = ->(){ Ruby::Box.current }
+ def self.box7
+ res = []
+ [1,2].chunk{ it.even? }.each do |bool, members|
+ res << Ruby::Box.current.object_id.to_s + ":" + bool.to_s + ":" + members.map(&:to_s).join(",")
+ end
+ res
+ end
+
+ def self.yield_block = yield
+ def self.call_block(&b) = b.call
+
+ def self.gvar1 = $gvar1
+ def self.call_toplevel = toplevel
+ end
+ FOO_NAME = Foo.name
+
+ module Kernel
+ def foo_box = Ruby::Box.current
+ module_function :foo_box
+ end
+
+ BOX_X = Foo.new.box4
+ BOX_Y = foo_box
+ EOC
+ box.eval(code)
+ outer = Ruby::Box.current
+ assert_equal box, box::BOX1 # on TOP frame
+ assert_equal box, box::Foo::BOX2 # on CLASS frame
+ assert_equal box, box::Foo::BOX2_proc.call # proc -> a const on CLASS
+ assert_equal box, box::Foo::BOX3_proc.call # proc -> the current
+ assert_equal box, box::Foo.new.box4 # instance method -> the current
+ assert_equal box, box::Foo.box5 # singleton method -> a const on CLASS
+ assert_equal box, box::Foo.box6 # singleton method -> the current
+ assert_equal box, box::Foo.box6_proc.call # method returns a proc -> the current
+
+ # a block after CFUNC/IFUNC in a method -> the current
+ assert_equal ["#{box.object_id}:false:1", "#{box.object_id}:true:2"], box::Foo.box7
+
+ assert_equal outer, box::Foo.yield_block{ Ruby::Box.current } # method yields
+ assert_equal outer, box::Foo.call_block{ Ruby::Box.current } # method calls a block
+
+ assert_equal 'foo', box::Foo.gvar1 # method refers gvar
+ assert_equal 'bar', $gvar1 # gvar value out of the box
+ assert_equal 'foo', box::Foo.call_toplevel # toplevel method referring gvar
+
+ assert_equal box, box::BOX_X # on TOP frame, referring a class in the current
+ assert_equal box, box::BOX_Y # on TOP frame, referring Kernel method defined by a CFUNC method
+
+ assert_equal "Foo", box::FOO_NAME
+ assert_equal "Foo", box::Foo.name
+ end;
+ end
+
+ def test_very_basic_method_calls_and_constants
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ code = <<~EOC
+ consts = Object.constants
+ [consts.include?(:String), consts.include?(:Array)]
+ EOC
+ assert_equal([true, true], Ruby::Box.current.eval(code))
+ assert_equal([true, true], Ruby::Box.root.eval(code))
+ end;
+ end
+
+ def test_loading_extension_libs_in_main_box_1
+ pend if /mswin|mingw/ =~ RUBY_PLATFORM # timeout on windows environments
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ require "prism"
+ require "optparse"
+ require "date"
+ require "time"
+ require "delegate"
+ require "singleton"
+ require "pp"
+ require "fileutils"
+ require "tempfile"
+ require "tmpdir"
+ require "json"
+ require "psych"
+ require "yaml"
+ expected = 1
+ assert_equal expected, 1
+ end;
+ end
+
+ def test_loading_extension_libs_in_main_box_2
+ pend if /mswin|mingw/ =~ RUBY_PLATFORM # timeout on windows environments
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ require "zlib"
+ require "open3"
+ require "ipaddr"
+ require "net/http"
+ require "openssl"
+ require "socket"
+ require "uri"
+ require "digest"
+ require "erb"
+ require "stringio"
+ require "monitor"
+ require "timeout"
+ require "securerandom"
+ expected = 1
+ assert_equal expected, 1
+ end;
+ end
+
+ def test_mark_box_object_referred_only_from_binding
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ box = Ruby::Box.new
+ box.eval('class Integer; def +(*)=42; end')
+ b = box.eval('binding')
+ box = nil # remove direct reference to the box
+
+ assert_equal 42, b.eval('1+2')
+
+ GC.stress = true
+ GC.start
+
+ assert_equal 42, b.eval('1+2')
+ end;
+ end
+
+ def test_loaded_extension_deleted_in_user_box
+ require 'tmpdir'
+ Dir.mktmpdir do |tmpdir|
+ env = ENV_ENABLE_BOX.merge({'TMPDIR'=>tmpdir})
+ assert_ruby_status([env], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ require "json"
+ end;
+ assert_empty(Dir.children(tmpdir))
+ end
+ end
+
+ def test_root_box_iclasses_should_be_boxable
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ Ruby::Box.root.eval("class IMath; include Math; end") # (*)
+ module Math
+ def foo = :foo
+ end
+ # This test crashes here if iclasses (created at the line (*) is not boxable)
+ class IMath2; include Math; end
+ assert_equal :foo, IMath2.new.foo
+ assert_raise NoMethodError do
+ Ruby::Box.root.eval("IMath.new.foo")
+ end
+ end;
+ end
+
+ def test_user_box_iclass_with_module_modified_in_another_box
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ # A user box creates a class that includes a core module.
+ # The ICLASS is allocated in the user box context (non-boxable).
+ box1 = Ruby::Box.new
+ box1.eval("class IMath; include Math; end")
+
+ # A second user box adds an instance method on that module,
+ # triggering classext duplication which iterates the module's
+ # subclass list and encounters box1's non-boxable ICLASS.
+ box2 = Ruby::Box.new
+ box2.eval("module Math; def box2_test = :box2; end")
+
+ assert_equal :box2, box2.eval("Class.new { include Math }.new.box2_test")
+ end;
+ end
+
+ def test_method_invalidation_between_boxes_1
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ b = Ruby::Box.new
+ b.eval(<<~'RUBY')
+ Module.prepend(Module.new)
+ class C; end
+ class D < C; end
+ def C.===(x) = true
+ RUBY
+
+ assert String === "x"
+ assert b # to prevent GCing b
+ end;
+ end
+
+ def test_method_invalidation_between_boxes_2
+ assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
+ begin;
+ PrepM = Module.new
+ Module.prepend(PrepM)
+ Module.new.include?(Module.new)
+
+ b = Ruby::Box.new
+ b.eval(<<~'RUBY')
+ Module.class_eval { def _test_method; end }
+
+ class C; end
+ class D < C; end
+ def C.include?(x) = true
+ RUBY
+
+ Module.new.include?(Module.new)
+ end;
+ end
+end
diff --git a/test/ruby/test_call.rb b/test/ruby/test_call.rb
index ffbda1fdb9..dd1936c4e2 100644
--- a/test/ruby/test_call.rb
+++ b/test/ruby/test_call.rb
@@ -123,6 +123,25 @@ class TestCall < Test::Unit::TestCase
assert_equal([1, 2, {kw: 3}], f(*a, kw: 3))
end
+ def test_forward_argument_init
+ o = Object.new
+ def o.simple_forward_argument_init(a=eval('b'), b=1)
+ [a, b]
+ end
+
+ def o.complex_forward_argument_init(a=eval('b'), b=eval('kw'), kw: eval('kw2'), kw2: 3)
+ [a, b, kw, kw2]
+ end
+
+ def o.keyword_forward_argument_init(a: eval('b'), b: eval('kw'), kw: eval('kw2'), kw2: 3)
+ [a, b, kw, kw2]
+ end
+
+ assert_equal [nil, 1], o.simple_forward_argument_init
+ assert_equal [nil, nil, 3, 3], o.complex_forward_argument_init
+ assert_equal [nil, nil, 3, 3], o.keyword_forward_argument_init
+ end
+
def test_call_bmethod_proc
pr = proc{|sym| sym}
define_singleton_method(:a, &pr)
@@ -374,6 +393,84 @@ class TestCall < Test::Unit::TestCase
assert_equal({splat_modified: false}, b)
end
+ def test_anon_splat
+ r2kh = Hash.ruby2_keywords_hash(kw: 2)
+ r2kea = [r2kh]
+ r2ka = [1, r2kh]
+
+ def self.s(*) ->(*a){a}.call(*) end
+ assert_equal([], s)
+ assert_equal([1], s(1))
+ assert_equal([{kw: 2}], s(kw: 2))
+ assert_equal([{kw: 2}], s(**{kw: 2}))
+ assert_equal([1, {kw: 2}], s(1, kw: 2))
+ assert_equal([1, {kw: 2}], s(1, **{kw: 2}))
+ assert_equal([{kw: 2}], s(*r2kea))
+ assert_equal([1, {kw: 2}], s(*r2ka))
+
+ singleton_class.remove_method(:s)
+ def self.s(*, kw: 0) [*->(*a){a}.call(*), kw] end
+ assert_equal([0], s)
+ assert_equal([1, 0], s(1))
+ assert_equal([2], s(kw: 2))
+ assert_equal([2], s(**{kw: 2}))
+ assert_equal([1, 2], s(1, kw: 2))
+ assert_equal([1, 2], s(1, **{kw: 2}))
+ assert_equal([2], s(*r2kea))
+ assert_equal([1, 2], s(*r2ka))
+
+ singleton_class.remove_method(:s)
+ def self.s(*, **kw) [*->(*a){a}.call(*), kw] end
+ assert_equal([{}], s)
+ assert_equal([1, {}], s(1))
+ assert_equal([{kw: 2}], s(kw: 2))
+ assert_equal([{kw: 2}], s(**{kw: 2}))
+ assert_equal([1, {kw: 2}], s(1, kw: 2))
+ assert_equal([1, {kw: 2}], s(1, **{kw: 2}))
+ assert_equal([{kw: 2}], s(*r2kea))
+ assert_equal([1, {kw: 2}], s(*r2ka))
+
+ singleton_class.remove_method(:s)
+ def self.s(*, kw: 0, **kws) [*->(*a){a}.call(*), kw, kws] end
+ assert_equal([0, {}], s)
+ assert_equal([1, 0, {}], s(1))
+ assert_equal([2, {}], s(kw: 2))
+ assert_equal([2, {}], s(**{kw: 2}))
+ assert_equal([1, 2, {}], s(1, kw: 2))
+ assert_equal([1, 2, {}], s(1, **{kw: 2}))
+ assert_equal([2, {}], s(*r2kea))
+ assert_equal([1, 2, {}], s(*r2ka))
+ end
+
+ def test_anon_splat_mutated_bug_21757
+ args = [1, 2]
+ kw = {bug: true}
+
+ def self.m(*); end
+ m(*args, bug: true)
+ assert_equal(2, args.length)
+
+ proc = ->(*) { }
+ proc.(*args, bug: true)
+ assert_equal(2, args.length)
+
+ def self.m2(*); end
+ m2(*args, **kw)
+ assert_equal(2, args.length)
+
+ proc = ->(*) { }
+ proc.(*args, **kw)
+ assert_equal(2, args.length)
+
+ def self.m3(*, **nil); end
+ assert_raise(ArgumentError) { m3(*args, bug: true) }
+ assert_equal(2, args.length)
+
+ proc = ->(*, **nil) { }
+ assert_raise(ArgumentError) { proc.(*args, bug: true) }
+ assert_equal(2, args.length)
+ end
+
def test_kwsplat_block_eval_order
def self.t(**kw, &b) [kw, b] end
diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb
index 456362ef21..82199876ec 100644
--- a/test/ruby/test_class.rb
+++ b/test/ruby/test_class.rb
@@ -259,6 +259,46 @@ class TestClass < Test::Unit::TestCase
assert_raise(TypeError) { BasicObject.dup }
end
+ def test_class_hierarchy_inside_initialize_dup_bug_21538
+ ancestors = sc_ancestors = nil
+ b = Class.new
+ b.define_singleton_method(:initialize_dup) do |x|
+ ancestors = self.ancestors
+ sc_ancestors = singleton_class.ancestors
+ super(x)
+ end
+
+ a = Class.new(b)
+
+ c = a.dup
+
+ expected_ancestors = [c, b, *Object.ancestors]
+ expected_sc_ancestors = [c.singleton_class, b.singleton_class, *Object.singleton_class.ancestors]
+ assert_equal expected_ancestors, ancestors
+ assert_equal expected_sc_ancestors, sc_ancestors
+ assert_equal expected_ancestors, c.ancestors
+ assert_equal expected_sc_ancestors, c.singleton_class.ancestors
+ end
+
+ def test_class_hierarchy_inside_initialize_clone_bug_21538
+ ancestors = sc_ancestors = nil
+ a = Class.new
+ a.define_singleton_method(:initialize_clone) do |x|
+ ancestors = self.ancestors
+ sc_ancestors = singleton_class.ancestors
+ super(x)
+ end
+
+ c = a.clone
+
+ expected_ancestors = [c, *Object.ancestors]
+ expected_sc_ancestors = [c.singleton_class, *Object.singleton_class.ancestors]
+ assert_equal expected_ancestors, ancestors
+ assert_equal expected_sc_ancestors, sc_ancestors
+ assert_equal expected_ancestors, c.ancestors
+ assert_equal expected_sc_ancestors, c.singleton_class.ancestors
+ end
+
def test_singleton_class
assert_raise(TypeError) { 1.extend(Module.new) }
assert_raise(TypeError) { 1.0.extend(Module.new) }
@@ -283,12 +323,8 @@ class TestClass < Test::Unit::TestCase
assert_raise(TypeError, bug6863) { Class.new(Class.allocate) }
allocator = Class.instance_method(:allocate)
- assert_raise_with_message(TypeError, /prohibited/) {
- allocator.bind(Rational).call
- }
- assert_raise_with_message(TypeError, /prohibited/) {
- allocator.bind_call(Rational)
- }
+ assert_nothing_raised { allocator.bind(Rational).call }
+ assert_nothing_raised { allocator.bind_call(Rational) }
end
def test_nonascii_name
@@ -399,21 +435,24 @@ class TestClass < Test::Unit::TestCase
end
class CloneTest
+ TEST = :C0
def foo; TEST; end
end
CloneTest1 = CloneTest.clone
CloneTest2 = CloneTest.clone
class CloneTest1
+ remove_const :TEST
TEST = :C1
end
class CloneTest2
+ remove_const :TEST
TEST = :C2
end
def test_constant_access_from_method_in_cloned_class
- assert_equal :C1, CloneTest1.new.foo, '[Bug #15877]'
- assert_equal :C2, CloneTest2.new.foo, '[Bug #15877]'
+ assert_equal :C0, CloneTest1.new.foo, 'originally [Bug #15877], but behaviour changed'
+ assert_equal :C0, CloneTest2.new.foo, 'originally [Bug #15877], but behaviour changed'
end
def test_invalid_superclass
@@ -565,7 +604,7 @@ class TestClass < Test::Unit::TestCase
obj = Object.new
c = obj.singleton_class
obj.freeze
- assert_raise_with_message(FrozenError, /frozen object/) {
+ assert_raise_with_message(FrozenError, /frozen Object/) {
c.class_eval {def f; end}
}
end
@@ -697,12 +736,37 @@ class TestClass < Test::Unit::TestCase
}
end
+ def test_dynamic_module_cpath_constant_namespace # [Bug #20948]
+ assert_separately([], <<~'RUBY')
+ module M1
+ module Foo
+ X = 1
+ end
+ end
+
+ module M2
+ module Foo
+ X = 2
+ end
+ end
+
+ results = [M1, M2].map do
+ module it::Foo
+ X
+ end
+ end
+ assert_equal([1, 2], results)
+ RUBY
+ end
+
def test_namescope_error_message
m = Module.new
o = m.module_eval "class A\u{3042}; self; end.new"
- assert_raise_with_message(TypeError, /A\u{3042}/) {
- o::Foo
- }
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /A\u{3042}/) {
+ o::Foo
+ }
+ end
end
def test_redefinition_mismatch
@@ -841,4 +905,80 @@ CODE
klass.define_method(:bar) {}
assert_equal klass, klass.remove_method(:bar), '[Bug #19164]'
end
+
+ def test_method_table_assignment_just_after_class_init
+ assert_normal_exit "#{<<~"begin;"}\n#{<<~'end;'}", 'm_tbl assignment should be done only when Class object is not promoted'
+ begin;
+ GC.stress = true
+ class C; end
+ end;
+ end
+
+ def test_define_singleton_initialize
+ assert_normal_exit "#{<<~"begin;"}\n#{<<~'end;'}"
+ begin;
+ class C
+ def self.initialize
+ end
+ end
+ end;
+ end
+
+ def test_singleton_cc_invalidation
+ assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}")
+ begin;
+ class T
+ def hi
+ "hi"
+ end
+ end
+
+ t = T.new
+ t.singleton_class
+
+ def hello(t)
+ t.hi
+ end
+
+ 5.times do
+ hello(t) # populate inline cache on `t.singleton_class`.
+ end
+
+ class T
+ remove_method :hi # invalidate `t.singleton_class` ccs for `hi`
+ end
+
+ assert_raise NoMethodError do
+ hello(t)
+ end
+ end;
+ end
+
+ def test_safe_multi_ractor_subclasses_list_mutation
+ assert_ractor "#{<<~"begin;"}\n#{<<~'end;'}", signal: :SEGV
+ begin;
+ 4.times.map do
+ Ractor.new do
+ 20_000.times do
+ Object.new.singleton_class
+ end
+ end
+ end.each(&:join)
+ end;
+ end
+
+ def test_safe_multi_ractor_singleton_class_access
+ assert_ractor "#{<<~"begin;"}\n#{<<~'end;'}"
+ begin;
+ class A; end
+ 4.times.map do
+ Ractor.new do
+ a = A
+ 100.times do
+ a = a.singleton_class
+ end
+ end
+ end.each(&:join)
+ end;
+ end
end
diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb
index 819d0d35aa..c017111c0a 100644
--- a/test/ruby/test_compile_prism.rb
+++ b/test/ruby/test_compile_prism.rb
@@ -1046,13 +1046,19 @@ module Prism
end
def test_ForNode
- assert_prism_eval("for i in [1,2] do; i; end")
- assert_prism_eval("for @i in [1,2] do; @i; end")
- assert_prism_eval("for $i in [1,2] do; $i; end")
+ assert_prism_eval("r = []; for i in [1,2] do; r << i; end; r")
+ assert_prism_eval("r = []; for @i in [1,2] do; r << @i; end; r")
+ assert_prism_eval("r = []; for $i in [1,2] do; r << $i; end; r")
- assert_prism_eval("for foo, in [1,2,3] do end")
+ assert_prism_eval("r = []; for foo, in [1,2,3] do r << foo end; r")
- assert_prism_eval("for i, j in {a: 'b'} do; i; j; end")
+ assert_prism_eval("r = []; for i, j in {a: 'b'} do; r << [i, j]; end; r")
+
+ # Test splat node as index in for loop
+ assert_prism_eval("r = []; for *x in [[1,2], [3,4]] do; r << x; end; r")
+ assert_prism_eval("r = []; for * in [[1,2], [3,4]] do; r << 'ok'; end; r")
+ assert_prism_eval("r = []; for x, * in [[1,2], [3,4]] do; r << x; end; r")
+ assert_prism_eval("r = []; for x, *y in [[1,2], [3,4]] do; r << [x, y]; end; r")
end
############################################################################
@@ -2180,6 +2186,56 @@ end
RUBY
end
+ def test_ForwardingArgumentsNode_instruction_sequence_consistency
+ # Test that both parsers generate identical instruction sequences for forwarding arguments
+ # This prevents regressions like the one fixed in prism_compile.c for PM_FORWARDING_ARGUMENTS_NODE
+
+ # Test case from the bug report: def bar(buz, ...) = foo(buz, ...)
+ source = <<~RUBY
+ def foo(*, &block) = block
+ def bar(buz, ...) = foo(buz, ...)
+ RUBY
+
+ compare_instruction_sequences(source)
+
+ # Test simple forwarding
+ source = <<~RUBY
+ def target(...) = nil
+ def forwarder(...) = target(...)
+ RUBY
+
+ compare_instruction_sequences(source)
+
+ # Test mixed forwarding with regular arguments
+ source = <<~RUBY
+ def target(a, b, c) = [a, b, c]
+ def forwarder(x, ...) = target(x, ...)
+ RUBY
+
+ compare_instruction_sequences(source)
+
+ # Test forwarding with splat
+ source = <<~RUBY
+ def target(a, b, c) = [a, b, c]
+ def forwarder(x, ...); target(*x, ...); end
+ RUBY
+
+ compare_instruction_sequences(source)
+ end
+
+ private
+
+ def compare_instruction_sequences(source)
+ # Get instruction sequences from both parsers
+ parsey_iseq = RubyVM::InstructionSequence.compile_parsey(source)
+ prism_iseq = RubyVM::InstructionSequence.compile_prism(source)
+
+ # Compare instruction sequences
+ assert_equal parsey_iseq.disasm, prism_iseq.disasm
+ end
+
+ public
+
def test_ForwardingSuperNode
assert_prism_eval("class Forwarding; def to_s; super; end; end")
assert_prism_eval("class Forwarding; def eval(code); super { code }; end; end")
@@ -2638,7 +2694,7 @@ end
# Errors #
############################################################################
- def test_MissingNode
+ def test_ErrorRecoveryNode
# TODO
end
@@ -2665,6 +2721,12 @@ end
assert_raise TypeError do
RubyVM::InstructionSequence.compile_file_prism(nil)
end
+
+ assert_nothing_raised(Errno::EMFILE, Errno::ENFILE) do
+ 10000.times do
+ RubyVM::InstructionSequence.compile_file_prism(File::NULL)
+ end
+ end
end
private
diff --git a/test/ruby/test_data.rb b/test/ruby/test_data.rb
index bb38f8ec91..4818c8acb7 100644
--- a/test/ruby/test_data.rb
+++ b/test/ruby/test_data.rb
@@ -69,15 +69,33 @@ class TestData < Test::Unit::TestCase
assert_equal(1, test_kw.foo)
assert_equal(2, test_kw.bar)
assert_equal(test_kw, klass.new(foo: 1, bar: 2))
+ assert_equal(test_kw, klass.new('foo' => 1, 'bar' => 2))
assert_equal(test_kw, test)
# Wrong protocol
assert_raise(ArgumentError) { klass.new(1) }
assert_raise(ArgumentError) { klass.new(1, 2, 3) }
- assert_raise(ArgumentError) { klass.new(foo: 1) }
- assert_raise(ArgumentError) { klass.new(foo: 1, bar: 2, baz: 3) }
- # Could be converted to foo: 1, bar: 2, but too smart is confusing
- assert_raise(ArgumentError) { klass.new(1, bar: 2) }
+ assert_raise(TypeError) do
+ klass.new(0 => 1, 1 => 2)
+ end
+ assert_raise(TypeError) do
+ klass.new(foo: 0, bar: 2, 0 => 1)
+ end
+ assert_raise_with_message(ArgumentError, "missing keyword: :bar") do
+ klass.new(foo: 1)
+ end
+ assert_raise_with_message(ArgumentError, "missing keyword: :bar") do
+ klass.new('foo' => 1)
+ end
+ assert_raise_with_message(ArgumentError, "missing keyword: :bar") do
+ klass.new(foo: 1, 'foo' => 1)
+ end
+ assert_raise_with_message(ArgumentError, "missing keywords: :foo, :bar") do
+ klass.new(x: 1, y: 2)
+ end
+ assert_raise_with_message(ArgumentError, "unknown keyword: :baz") do
+ klass.new(foo: 1, bar: 2, baz: 3)
+ end
end
def test_initialize_redefine
@@ -259,9 +277,10 @@ class TestData < Test::Unit::TestCase
assert_equal(klass.new, test)
assert_not_equal(Data.define.new, test)
- assert_equal('#<data >', test.inspect)
+ assert_equal('#<data>', test.inspect)
assert_equal([], test.members)
assert_equal({}, test.to_h)
+ assert_predicate(test, :frozen?)
end
def test_dup
@@ -280,4 +299,10 @@ class TestData < Test::Unit::TestCase
assert_not_same(test, loaded)
assert_predicate(loaded, :frozen?)
end
+
+ def test_frozen_subclass
+ test = Class.new(Data.define(:a)).freeze.new(a: 0)
+ assert_kind_of(Data, test)
+ assert_equal([:a], test.members)
+ end
end
diff --git a/test/ruby/test_defined.rb b/test/ruby/test_defined.rb
index db1fdc8e25..75ed1a7534 100644
--- a/test/ruby/test_defined.rb
+++ b/test/ruby/test_defined.rb
@@ -62,6 +62,34 @@ class TestDefined < Test::Unit::TestCase
f.bar(Class.new(Foo).new) { |v| assert(v, "inherited protected method") }
end
+ module ProtectedInModule
+ def m
+ :m
+ end
+ protected :m
+ def call_m(o)
+ o.m
+ end
+ def defined_m(o)
+ defined?(o.m)
+ end
+ end
+ class ProtectedIncluderA
+ include ProtectedInModule
+ end
+ class ProtectedIncluderB
+ include ProtectedInModule
+ end
+
+ def test_defined_protected_method_in_included_module
+ a = ProtectedIncluderA.new
+ b = ProtectedIncluderB.new
+ assert_equal(:m, a.call_m(a))
+ assert_equal(:m, a.call_m(b))
+ assert_equal("method", a.defined_m(a))
+ assert_equal("method", a.defined_m(b))
+ end
+
def test_defined_undefined_method
f = Foo.new
assert_nil(defined?(f.quux)) # undefined method
diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb
index 1d3d151c85..edb5210af1 100644
--- a/test/ruby/test_dir.rb
+++ b/test/ruby/test_dir.rb
@@ -653,6 +653,8 @@ class TestDir < Test::Unit::TestCase
File.unlink("#{long_path}/c")
Dir.rmdir(long_path)
end
+ rescue Errno::ENOENT
+ omit "File system does not support long file name"
end
end
diff --git a/test/ruby/test_encoding.rb b/test/ruby/test_encoding.rb
index 388b94df39..0cd5bf49dc 100644
--- a/test/ruby/test_encoding.rb
+++ b/test/ruby/test_encoding.rb
@@ -33,7 +33,7 @@ class TestEncoding < Test::Unit::TestCase
encodings.each do |e|
assert_raise(TypeError) { e.dup }
assert_raise(TypeError) { e.clone }
- assert_equal(e.object_id, Marshal.load(Marshal.dump(e)).object_id)
+ assert_same(e, Marshal.load(Marshal.dump(e)))
end
end
@@ -130,10 +130,50 @@ class TestEncoding < Test::Unit::TestCase
def test_ractor_load_encoding
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
- Ractor.new{}.take
+ Ractor.new{}.join
$-w = nil
Encoding.default_external = Encoding::ISO8859_2
assert "[Bug #19562]"
end;
end
+
+ def test_ractor_lazy_load_encoding_concurrently
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ rs = []
+ autoload_encodings = Encoding.list.select { |e| e.inspect.include?("(autoload)") }.freeze
+ 7.times do
+ rs << Ractor.new(autoload_encodings) do |encodings|
+ str = "abc".dup
+ encodings.each do |enc|
+ str.force_encoding(enc)
+ end
+ end
+ end
+ while rs.any?
+ r, _obj = Ractor.select(*rs)
+ rs.delete(r)
+ end
+ assert_empty rs
+ end;
+ end
+
+ def test_ractor_set_default_external_string
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ $-w = nil
+ rs = []
+ 7.times do |i|
+ rs << Ractor.new(i) do |i|
+ Encoding.default_external = "us-ascii"
+ end
+ end
+
+ while rs.any?
+ r, _obj = Ractor.select(*rs)
+ rs.delete(r)
+ end
+ assert_empty rs
+ end;
+ end
end
diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb
index 237bdc8a4d..32ec4f5779 100644
--- a/test/ruby/test_enum.rb
+++ b/test/ruby/test_enum.rb
@@ -69,11 +69,11 @@ class TestEnumerable < Test::Unit::TestCase
assert_equal(['z', 42, nil], [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/), bug17030)
assert_equal('match', $1, bug17030)
- regexp = Regexp.new('x')
- assert_equal([], @obj.grep(regexp), bug17030) # sanity check
- def regexp.===(other)
- true
- end
+ regexp = Class.new(Regexp) {
+ def ===(other)
+ true
+ end
+ }.new('x')
assert_equal([1, 2, 3, 1, 2], @obj.grep(regexp), bug17030)
o = Object.new
diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb
index cd62cd8acb..9b972d7b22 100644
--- a/test/ruby/test_enumerator.rb
+++ b/test/ruby/test_enumerator.rb
@@ -886,6 +886,7 @@ class TestEnumerator < Test::Unit::TestCase
def test_produce
assert_raise(ArgumentError) { Enumerator.produce }
+ assert_raise(ArgumentError) { Enumerator.produce(a: 1, b: 1) {} }
# Without initial object
passed_args = []
@@ -903,14 +904,6 @@ class TestEnumerator < Test::Unit::TestCase
assert_equal [1, 2, 3], enum.take(3)
assert_equal [1, 2], passed_args
- # With initial keyword arguments
- passed_args = []
- enum = Enumerator.produce(a: 1, b: 1) { |obj| passed_args << obj; obj.shift if obj.respond_to?(:shift)}
- assert_instance_of(Enumerator, enum)
- assert_equal Float::INFINITY, enum.size
- assert_equal [{b: 1}, [1], :a, nil], enum.take(4)
- assert_equal [{b: 1}, [1], :a], passed_args
-
# Raising StopIteration
words = "The quick brown fox jumps over the lazy dog.".scan(/\w+/)
enum = Enumerator.produce { words.shift or raise StopIteration }
@@ -935,6 +928,25 @@ class TestEnumerator < Test::Unit::TestCase
"abc",
], enum.to_a
}
+
+ # With size keyword argument
+ enum = Enumerator.produce(1, size: 10) { |obj| obj.succ }
+ assert_equal 10, enum.size
+ assert_equal [1, 2, 3], enum.take(3)
+
+ enum = Enumerator.produce(1, size: -> { 5 }) { |obj| obj.succ }
+ assert_equal 5, enum.size
+
+ enum = Enumerator.produce(1, size: nil) { |obj| obj.succ }
+ assert_equal nil, enum.size
+
+ enum = Enumerator.produce(1, size: Float::INFINITY) { |obj| obj.succ }
+ assert_equal Float::INFINITY, enum.size
+
+ # Without initial value but with size
+ enum = Enumerator.produce(size: 3) { |obj| (obj || 0).succ }
+ assert_equal 3, enum.size
+ assert_equal [1, 2, 3], enum.take(3)
end
def test_chain_each_lambda
diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb
index c9ec920ea9..dd526544af 100644
--- a/test/ruby/test_env.rb
+++ b/test/ruby/test_env.rb
@@ -281,6 +281,26 @@ class TestEnv < Test::Unit::TestCase
assert_equal(["foo", "foo"], ENV.values_at("test", "test"))
end
+ def test_fetch_values
+ ENV["test"] = "foo"
+ ENV["test2"] = "bar"
+ assert_equal(["foo", "bar"], ENV.fetch_values("test", "test2"))
+ assert_equal(["foo", "foo"], ENV.fetch_values("test", "test"))
+ assert_equal([], ENV.fetch_values)
+
+ ENV.delete("test2")
+ assert_raise(KeyError) { ENV.fetch_values("test", "test2") }
+
+ assert_equal(["foo", "default"], ENV.fetch_values("test", "test2") { "default" })
+ assert_equal(["foo", "TEST2"], ENV.fetch_values("test", "test2") { |k| k.upcase })
+
+ e = assert_raise(KeyError) { ENV.fetch_values("test2") }
+ assert_same(ENV, e.receiver)
+ assert_equal("test2", e.key)
+
+ assert_invalid_env {|v| ENV.fetch_values(v)}
+ end
+
def test_select
ENV["test"] = "foo"
h = ENV.select {|k| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }
@@ -601,13 +621,13 @@ class TestEnv < Test::Unit::TestCase
rescue Exception => e
#{exception_var} = e
end
- Ractor.yield #{exception_var}.class
+ port.send #{exception_var}.class
end;
end
def str_for_assert_raise_on_yielded_exception_class(expected_error_class, ractor_var)
<<-"end;"
- error_class = #{ractor_var}.take
+ error_class = #{ractor_var}.receive
assert_raise(#{expected_error_class}) do
if error_class < Exception
raise error_class
@@ -649,100 +669,101 @@ class TestEnv < Test::Unit::TestCase
def test_bracket_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- Ractor.yield ENV['test']
- Ractor.yield ENV['TEST']
+ Ractor.new port = Ractor::Port.new do |port|
+ port << ENV['test']
+ port << ENV['TEST']
ENV['test'] = 'foo'
- Ractor.yield ENV['test']
- Ractor.yield ENV['TEST']
+ port << ENV['test']
+ port << ENV['TEST']
ENV['TEST'] = 'bar'
- Ractor.yield ENV['TEST']
- Ractor.yield ENV['test']
+ port << ENV['TEST']
+ port << ENV['test']
#{str_for_yielding_exception_class("ENV[1]")}
#{str_for_yielding_exception_class("ENV[1] = 'foo'")}
#{str_for_yielding_exception_class("ENV['test'] = 0")}
end
- assert_nil(r.take)
- assert_nil(r.take)
- assert_equal('foo', r.take)
+ assert_nil(port.receive)
+ assert_nil(port.receive)
+ assert_equal('foo', port.receive)
if #{ignore_case_str}
- assert_equal('foo', r.take)
+ assert_equal('foo', port.receive)
else
- assert_nil(r.take)
+ assert_nil(port.receive)
end
- assert_equal('bar', r.take)
+ assert_equal('bar', port.receive)
if #{ignore_case_str}
- assert_equal('bar', r.take)
+ assert_equal('bar', port.receive)
else
- assert_equal('foo', r.take)
+ assert_equal('foo', port.receive)
end
3.times do
- #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")}
+ #{str_for_assert_raise_on_yielded_exception_class(TypeError, "port")}
end
end;
end
def test_dup_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
#{str_for_yielding_exception_class("ENV.dup")}
end
- #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")}
+ #{str_for_assert_raise_on_yielded_exception_class(TypeError, "port")}
end;
end
def test_has_value_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ port = Ractor::Port.new
+ Ractor.new port do |port|
val = 'a'
val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase)
ENV['test'] = val[0...-1]
- Ractor.yield(ENV.has_value?(val))
- Ractor.yield(ENV.has_value?(val.upcase))
+ port.send(ENV.has_value?(val))
+ port.send(ENV.has_value?(val.upcase))
ENV['test'] = val
- Ractor.yield(ENV.has_value?(val))
- Ractor.yield(ENV.has_value?(val.upcase))
+ port.send(ENV.has_value?(val))
+ port.send(ENV.has_value?(val.upcase))
ENV['test'] = val.upcase
- Ractor.yield ENV.has_value?(val)
- Ractor.yield ENV.has_value?(val.upcase)
- end
- assert_equal(false, r.take)
- assert_equal(false, r.take)
- assert_equal(true, r.take)
- assert_equal(false, r.take)
- assert_equal(false, r.take)
- assert_equal(true, r.take)
+ port.send ENV.has_value?(val)
+ port.send ENV.has_value?(val.upcase)
+ end
+ assert_equal(false, port.receive)
+ assert_equal(false, port.receive)
+ assert_equal(true, port.receive)
+ assert_equal(false, port.receive)
+ assert_equal(false, port.receive)
+ assert_equal(true, port.receive)
end;
end
def test_key_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
val = 'a'
val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase)
ENV['test'] = val[0...-1]
- Ractor.yield ENV.key(val)
- Ractor.yield ENV.key(val.upcase)
+ port.send ENV.key(val)
+ port.send ENV.key(val.upcase)
ENV['test'] = val
- Ractor.yield ENV.key(val)
- Ractor.yield ENV.key(val.upcase)
+ port.send ENV.key(val)
+ port.send ENV.key(val.upcase)
ENV['test'] = val.upcase
- Ractor.yield ENV.key(val)
- Ractor.yield ENV.key(val.upcase)
+ port.send ENV.key(val)
+ port.send ENV.key(val.upcase)
end
- assert_nil(r.take)
- assert_nil(r.take)
+ assert_nil(port.receive)
+ assert_nil(port.receive)
if #{ignore_case_str}
- assert_equal('TEST', r.take.upcase)
+ assert_equal('TEST', port.receive.upcase)
else
- assert_equal('test', r.take)
+ assert_equal('test', port.receive)
end
- assert_nil(r.take)
- assert_nil(r.take)
+ assert_nil(port.receive)
+ assert_nil(port.receive)
if #{ignore_case_str}
- assert_equal('TEST', r.take.upcase)
+ assert_equal('TEST', port.receive.upcase)
else
- assert_equal('test', r.take)
+ assert_equal('test', port.receive)
end
end;
@@ -750,87 +771,87 @@ class TestEnv < Test::Unit::TestCase
def test_delete_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
#{str_to_yield_invalid_envvar_errors("v", "ENV.delete(v)")}
- Ractor.yield ENV.delete("TEST")
+ port.send ENV.delete("TEST")
#{str_for_yielding_exception_class("ENV.delete('#{PATH_ENV}')")}
- Ractor.yield(ENV.delete("TEST"){|name| "NO "+name})
+ port.send(ENV.delete("TEST"){|name| "NO "+name})
end
- #{str_to_receive_invalid_envvar_errors("r")}
- assert_nil(r.take)
- exception_class = r.take
+ #{str_to_receive_invalid_envvar_errors("port")}
+ assert_nil(port.receive)
+ exception_class = port.receive
assert_equal(NilClass, exception_class)
- assert_equal("NO TEST", r.take)
+ assert_equal("NO TEST", port.receive)
end;
end
def test_getenv_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
#{str_to_yield_invalid_envvar_errors("v", "ENV[v]")}
ENV["#{PATH_ENV}"] = ""
- Ractor.yield ENV["#{PATH_ENV}"]
- Ractor.yield ENV[""]
+ port.send ENV["#{PATH_ENV}"]
+ port.send ENV[""]
end
- #{str_to_receive_invalid_envvar_errors("r")}
- assert_equal("", r.take)
- assert_nil(r.take)
+ #{str_to_receive_invalid_envvar_errors("port")}
+ assert_equal("", port.receive)
+ assert_nil(port.receive)
end;
end
def test_fetch_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV["test"] = "foo"
- Ractor.yield ENV.fetch("test")
+ port.send ENV.fetch("test")
ENV.delete("test")
#{str_for_yielding_exception_class("ENV.fetch('test')", exception_var: "ex")}
- Ractor.yield ex.receiver.object_id
- Ractor.yield ex.key
- Ractor.yield ENV.fetch("test", "foo")
- Ractor.yield(ENV.fetch("test"){"bar"})
+ port.send ex.receiver.object_id
+ port.send ex.key
+ port.send ENV.fetch("test", "foo")
+ port.send(ENV.fetch("test"){"bar"})
#{str_to_yield_invalid_envvar_errors("v", "ENV.fetch(v)")}
#{str_for_yielding_exception_class("ENV.fetch('#{PATH_ENV}', 'foo')")}
ENV['#{PATH_ENV}'] = ""
- Ractor.yield ENV.fetch('#{PATH_ENV}')
- end
- assert_equal("foo", r.take)
- #{str_for_assert_raise_on_yielded_exception_class(KeyError, "r")}
- assert_equal(ENV.object_id, r.take)
- assert_equal("test", r.take)
- assert_equal("foo", r.take)
- assert_equal("bar", r.take)
- #{str_to_receive_invalid_envvar_errors("r")}
- exception_class = r.take
+ port.send ENV.fetch('#{PATH_ENV}')
+ end
+ assert_equal("foo", port.receive)
+ #{str_for_assert_raise_on_yielded_exception_class(KeyError, "port")}
+ assert_equal(ENV.object_id, port.receive)
+ assert_equal("test", port.receive)
+ assert_equal("foo", port.receive)
+ assert_equal("bar", port.receive)
+ #{str_to_receive_invalid_envvar_errors("port")}
+ exception_class = port.receive
assert_equal(NilClass, exception_class)
- assert_equal("", r.take)
+ assert_equal("", port.receive)
end;
end
def test_aset_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
#{str_for_yielding_exception_class("ENV['test'] = nil")}
ENV["test"] = nil
- Ractor.yield ENV["test"]
+ port.send ENV["test"]
#{str_to_yield_invalid_envvar_errors("v", "ENV[v] = 'test'")}
#{str_to_yield_invalid_envvar_errors("v", "ENV['test'] = v")}
end
- exception_class = r.take
+ exception_class = port.receive
assert_equal(NilClass, exception_class)
- assert_nil(r.take)
- #{str_to_receive_invalid_envvar_errors("r")}
- #{str_to_receive_invalid_envvar_errors("r")}
+ assert_nil(port.receive)
+ #{str_to_receive_invalid_envvar_errors("port")}
+ #{str_to_receive_invalid_envvar_errors("port")}
end;
end
def test_keys_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
a = ENV.keys
- Ractor.yield a
+ port.send a
end
- a = r.take
+ a = port.receive
assert_kind_of(Array, a)
a.each {|k| assert_kind_of(String, k) }
end;
@@ -839,11 +860,11 @@ class TestEnv < Test::Unit::TestCase
def test_each_key_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- ENV.each_key {|k| Ractor.yield(k)}
- Ractor.yield "finished"
+ Ractor.new port = Ractor::Port.new do |port|
+ ENV.each_key {|k| port.send(k)}
+ port.send "finished"
end
- while((x=r.take) != "finished")
+ while((x=port.receive) != "finished")
assert_kind_of(String, x)
end
end;
@@ -851,11 +872,11 @@ class TestEnv < Test::Unit::TestCase
def test_values_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
a = ENV.values
- Ractor.yield a
+ port.send a
end
- a = r.take
+ a = port.receive
assert_kind_of(Array, a)
a.each {|k| assert_kind_of(String, k) }
end;
@@ -863,11 +884,11 @@ class TestEnv < Test::Unit::TestCase
def test_each_value_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- ENV.each_value {|k| Ractor.yield(k)}
- Ractor.yield "finished"
+ Ractor.new port = Ractor::Port.new do |port|
+ ENV.each_value {|k| port.send(k)}
+ port.send "finished"
end
- while((x=r.take) != "finished")
+ while((x=port.receive) != "finished")
assert_kind_of(String, x)
end
end;
@@ -875,11 +896,11 @@ class TestEnv < Test::Unit::TestCase
def test_each_pair_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- ENV.each_pair {|k, v| Ractor.yield([k,v])}
- Ractor.yield "finished"
+ Ractor.new port = Ractor::Port.new do |port|
+ ENV.each_pair {|k, v| port.send([k,v])}
+ port.send "finished"
end
- while((k,v=r.take) != "finished")
+ while((k,v=port.receive) != "finished")
assert_kind_of(String, k)
assert_kind_of(String, v)
end
@@ -888,116 +909,116 @@ class TestEnv < Test::Unit::TestCase
def test_reject_bang_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h1 = {}
ENV.each_pair {|k, v| h1[k] = v }
ENV["test"] = "foo"
ENV.reject! {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }
h2 = {}
ENV.each_pair {|k, v| h2[k] = v }
- Ractor.yield [h1, h2]
- Ractor.yield(ENV.reject! {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" })
+ port.send [h1, h2]
+ port.send(ENV.reject! {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" })
end
- h1, h2 = r.take
+ h1, h2 = port.receive
assert_equal(h1, h2)
- assert_nil(r.take)
+ assert_nil(port.receive)
end;
end
def test_delete_if_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h1 = {}
ENV.each_pair {|k, v| h1[k] = v }
ENV["test"] = "foo"
ENV.delete_if {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }
h2 = {}
ENV.each_pair {|k, v| h2[k] = v }
- Ractor.yield [h1, h2]
- Ractor.yield (ENV.delete_if {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }).object_id
+ port.send [h1, h2]
+ port.send (ENV.delete_if {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" })
end
- h1, h2 = r.take
+ h1, h2 = port.receive
assert_equal(h1, h2)
- assert_equal(ENV.object_id, r.take)
+ assert_same(ENV, port.receive)
end;
end
def test_select_bang_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h1 = {}
ENV.each_pair {|k, v| h1[k] = v }
ENV["test"] = "foo"
ENV.select! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }
h2 = {}
ENV.each_pair {|k, v| h2[k] = v }
- Ractor.yield [h1, h2]
- Ractor.yield(ENV.select! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" })
+ port.send [h1, h2]
+ port.send(ENV.select! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" })
end
- h1, h2 = r.take
+ h1, h2 = port.receive
assert_equal(h1, h2)
- assert_nil(r.take)
+ assert_nil(port.receive)
end;
end
def test_filter_bang_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h1 = {}
ENV.each_pair {|k, v| h1[k] = v }
ENV["test"] = "foo"
ENV.filter! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }
h2 = {}
ENV.each_pair {|k, v| h2[k] = v }
- Ractor.yield [h1, h2]
- Ractor.yield(ENV.filter! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" })
+ port.send [h1, h2]
+ port.send(ENV.filter! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" })
end
- h1, h2 = r.take
+ h1, h2 = port.receive
assert_equal(h1, h2)
- assert_nil(r.take)
+ assert_nil(port.receive)
end;
end
def test_keep_if_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h1 = {}
ENV.each_pair {|k, v| h1[k] = v }
ENV["test"] = "foo"
ENV.keep_if {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }
h2 = {}
ENV.each_pair {|k, v| h2[k] = v }
- Ractor.yield [h1, h2]
- Ractor.yield (ENV.keep_if {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }).object_id
+ port.send [h1, h2]
+ port.send (ENV.keep_if {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" })
end
- h1, h2 = r.take
+ h1, h2 = port.receive
assert_equal(h1, h2)
- assert_equal(ENV.object_id, r.take)
+ assert_equal(ENV, port.receive)
end;
end
def test_values_at_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV["test"] = "foo"
- Ractor.yield ENV.values_at("test", "test")
+ port.send ENV.values_at("test", "test")
end
- assert_equal(["foo", "foo"], r.take)
+ assert_equal(["foo", "foo"], port.receive)
end;
end
def test_select_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV["test"] = "foo"
h = ENV.select {|k| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }
- Ractor.yield h.size
+ port.send h.size
k = h.keys.first
v = h.values.first
- Ractor.yield [k, v]
+ port.send [k, v]
end
- assert_equal(1, r.take)
- k, v = r.take
+ assert_equal(1, port.receive)
+ k, v = port.receive
if #{ignore_case_str}
assert_equal("TEST", k.upcase)
assert_equal("FOO", v.upcase)
@@ -1010,16 +1031,16 @@ class TestEnv < Test::Unit::TestCase
def test_filter_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV["test"] = "foo"
h = ENV.filter {|k| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }
- Ractor.yield(h.size)
+ port.send(h.size)
k = h.keys.first
v = h.values.first
- Ractor.yield [k, v]
+ port.send [k, v]
end
- assert_equal(1, r.take)
- k, v = r.take
+ assert_equal(1, port.receive)
+ k, v = port.receive
if #{ignore_case_str}
assert_equal("TEST", k.upcase)
assert_equal("FOO", v.upcase)
@@ -1032,49 +1053,49 @@ class TestEnv < Test::Unit::TestCase
def test_slice_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
ENV["bar"] = "rab"
- Ractor.yield(ENV.slice())
- Ractor.yield(ENV.slice(""))
- Ractor.yield(ENV.slice("unknown"))
- Ractor.yield(ENV.slice("foo", "baz"))
- end
- assert_equal({}, r.take)
- assert_equal({}, r.take)
- assert_equal({}, r.take)
- assert_equal({"foo"=>"bar", "baz"=>"qux"}, r.take)
+ port.send(ENV.slice())
+ port.send(ENV.slice(""))
+ port.send(ENV.slice("unknown"))
+ port.send(ENV.slice("foo", "baz"))
+ end
+ assert_equal({}, port.receive)
+ assert_equal({}, port.receive)
+ assert_equal({}, port.receive)
+ assert_equal({"foo"=>"bar", "baz"=>"qux"}, port.receive)
end;
end
def test_except_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
ENV["bar"] = "rab"
- Ractor.yield ENV.except()
- Ractor.yield ENV.except("")
- Ractor.yield ENV.except("unknown")
- Ractor.yield ENV.except("foo", "baz")
- end
- assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, r.take)
- assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, r.take)
- assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, r.take)
- assert_equal({"bar"=>"rab"}, r.take)
+ port.send ENV.except()
+ port.send ENV.except("")
+ port.send ENV.except("unknown")
+ port.send ENV.except("foo", "baz")
+ end
+ assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, port.receive)
+ assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, port.receive)
+ assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, port.receive)
+ assert_equal({"bar"=>"rab"}, port.receive)
end;
end
def test_clear_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
- Ractor.yield ENV.size
+ port.send ENV.size
end
- assert_equal(0, r.take)
+ assert_equal(0, port.receive)
end;
end
@@ -1083,20 +1104,20 @@ class TestEnv < Test::Unit::TestCase
r = Ractor.new do
ENV.to_s
end
- assert_equal("ENV", r.take)
+ assert_equal("ENV", r.value)
end;
end
def test_inspect_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
s = ENV.inspect
- Ractor.yield s
+ port.send s
end
- s = r.take
+ s = port.receive
expected = ['"foo" => "bar"', '"baz" => "qux"']
unless s.start_with?(/\{"foo"/i)
expected.reverse!
@@ -1112,14 +1133,14 @@ class TestEnv < Test::Unit::TestCase
def test_to_a_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
a = ENV.to_a
- Ractor.yield a
+ port.send a
end
- a = r.take
+ a = port.receive
assert_equal(2, a.size)
expected = [%w(baz qux), %w(foo bar)]
if #{ignore_case_str}
@@ -1136,59 +1157,59 @@ class TestEnv < Test::Unit::TestCase
r = Ractor.new do
ENV.rehash
end
- assert_nil(r.take)
+ assert_nil(r.value)
end;
end
def test_size_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
s = ENV.size
ENV["test"] = "foo"
- Ractor.yield [s, ENV.size]
+ port.send [s, ENV.size]
end
- s, s2 = r.take
+ s, s2 = port.receive
assert_equal(s + 1, s2)
end;
end
def test_empty_p_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
- Ractor.yield ENV.empty?
+ port.send ENV.empty?
ENV["test"] = "foo"
- Ractor.yield ENV.empty?
+ port.send ENV.empty?
end
- assert r.take
- assert !r.take
+ assert port.receive
+ assert !port.receive
end;
end
def test_has_key_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- Ractor.yield ENV.has_key?("test")
+ Ractor.new port = Ractor::Port.new do |port|
+ port.send ENV.has_key?("test")
ENV["test"] = "foo"
- Ractor.yield ENV.has_key?("test")
+ port.send ENV.has_key?("test")
#{str_to_yield_invalid_envvar_errors("v", "ENV.has_key?(v)")}
end
- assert !r.take
- assert r.take
- #{str_to_receive_invalid_envvar_errors("r")}
+ assert !port.receive
+ assert port.receive
+ #{str_to_receive_invalid_envvar_errors("port")}
end;
end
def test_assoc_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- Ractor.yield ENV.assoc("test")
+ Ractor.new port = Ractor::Port.new do |port|
+ port.send ENV.assoc("test")
ENV["test"] = "foo"
- Ractor.yield ENV.assoc("test")
+ port.send ENV.assoc("test")
#{str_to_yield_invalid_envvar_errors("v", "ENV.assoc(v)")}
end
- assert_nil(r.take)
- k, v = r.take
+ assert_nil(port.receive)
+ k, v = port.receive
if #{ignore_case_str}
assert_equal("TEST", k.upcase)
assert_equal("FOO", v.upcase)
@@ -1196,7 +1217,7 @@ class TestEnv < Test::Unit::TestCase
assert_equal("test", k)
assert_equal("foo", v)
end
- #{str_to_receive_invalid_envvar_errors("r")}
+ #{str_to_receive_invalid_envvar_errors("port")}
encoding = /mswin|mingw/ =~ RUBY_PLATFORM ? Encoding::UTF_8 : Encoding.find("locale")
assert_equal(encoding, v.encoding)
end;
@@ -1204,29 +1225,29 @@ class TestEnv < Test::Unit::TestCase
def test_has_value2_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
- Ractor.yield ENV.has_value?("foo")
+ port.send ENV.has_value?("foo")
ENV["test"] = "foo"
- Ractor.yield ENV.has_value?("foo")
+ port.send ENV.has_value?("foo")
end
- assert !r.take
- assert r.take
+ assert !port.receive
+ assert port.receive
end;
end
def test_rassoc_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
- Ractor.yield ENV.rassoc("foo")
+ port.send ENV.rassoc("foo")
ENV["foo"] = "bar"
ENV["test"] = "foo"
ENV["baz"] = "qux"
- Ractor.yield ENV.rassoc("foo")
+ port.send ENV.rassoc("foo")
end
- assert_nil(r.take)
- k, v = r.take
+ assert_nil(port.receive)
+ k, v = port.receive
if #{ignore_case_str}
assert_equal("TEST", k.upcase)
assert_equal("FOO", v.upcase)
@@ -1239,39 +1260,39 @@ class TestEnv < Test::Unit::TestCase
def test_to_hash_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h = {}
ENV.each {|k, v| h[k] = v }
- Ractor.yield [h, ENV.to_hash]
+ port.send [h, ENV.to_hash]
end
- h, h2 = r.take
+ h, h2 = port.receive
assert_equal(h, h2)
end;
end
def test_to_h_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
- Ractor.yield [ENV.to_hash, ENV.to_h]
- Ractor.yield [ENV.map {|k, v| ["$\#{k}", v.size]}.to_h, ENV.to_h {|k, v| ["$\#{k}", v.size]}]
+ Ractor.new port = Ractor::Port.new do |port|
+ port.send [ENV.to_hash, ENV.to_h]
+ port.send [ENV.map {|k, v| ["$\#{k}", v.size]}.to_h, ENV.to_h {|k, v| ["$\#{k}", v.size]}]
end
- a, b = r.take
+ a, b = port.receive
assert_equal(a,b)
- c, d = r.take
+ c, d = port.receive
assert_equal(c,d)
end;
end
def test_reject_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
h1 = {}
ENV.each_pair {|k, v| h1[k] = v }
ENV["test"] = "foo"
h2 = ENV.reject {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }
- Ractor.yield [h1, h2]
+ port.send [h1, h2]
end
- h1, h2 = r.take
+ h1, h2 = port.receive
assert_equal(h1, h2)
end;
end
@@ -1279,86 +1300,86 @@ class TestEnv < Test::Unit::TestCase
def test_shift_in_ractor
assert_ractor(<<-"end;")
#{STR_DEFINITION_FOR_CHECK}
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
a = ENV.shift
b = ENV.shift
- Ractor.yield [a,b]
- Ractor.yield ENV.shift
+ port.send [a,b]
+ port.send ENV.shift
end
- a,b = r.take
+ a,b = port.receive
check([a, b], [%w(foo bar), %w(baz qux)])
- assert_nil(r.take)
+ assert_nil(port.receive)
end;
end
def test_invert_in_ractor
assert_ractor(<<-"end;")
#{STR_DEFINITION_FOR_CHECK}
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
- Ractor.yield(ENV.invert)
+ port.send(ENV.invert)
end
- check(r.take.to_a, [%w(bar foo), %w(qux baz)])
+ check(port.receive.to_a, [%w(bar foo), %w(qux baz)])
end;
end
def test_replace_in_ractor
assert_ractor(<<-"end;")
#{STR_DEFINITION_FOR_CHECK}
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV["foo"] = "xxx"
ENV.replace({"foo"=>"bar", "baz"=>"qux"})
- Ractor.yield ENV.to_hash
+ port.send ENV.to_hash
ENV.replace({"Foo"=>"Bar", "Baz"=>"Qux"})
- Ractor.yield ENV.to_hash
+ port.send ENV.to_hash
end
- check(r.take.to_a, [%w(foo bar), %w(baz qux)])
- check(r.take.to_a, [%w(Foo Bar), %w(Baz Qux)])
+ check(port.receive.to_a, [%w(foo bar), %w(baz qux)])
+ check(port.receive.to_a, [%w(Foo Bar), %w(Baz Qux)])
end;
end
def test_update_in_ractor
assert_ractor(<<-"end;")
#{STR_DEFINITION_FOR_CHECK}
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
ENV.update({"baz"=>"quux","a"=>"b"})
- Ractor.yield ENV.to_hash
+ port.send ENV.to_hash
ENV.clear
ENV["foo"] = "bar"
ENV["baz"] = "qux"
ENV.update({"baz"=>"quux","a"=>"b"}) {|k, v1, v2| k + "_" + v1 + "_" + v2 }
- Ractor.yield ENV.to_hash
+ port.send ENV.to_hash
end
- check(r.take.to_a, [%w(foo bar), %w(baz quux), %w(a b)])
- check(r.take.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)])
+ check(port.receive.to_a, [%w(foo bar), %w(baz quux), %w(a b)])
+ check(port.receive.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)])
end;
end
def test_huge_value_in_ractor
assert_ractor(<<-"end;")
huge_value = "bar" * 40960
- r = Ractor.new huge_value do |v|
+ Ractor.new port = Ractor::Port.new, huge_value do |port, v|
ENV["foo"] = "bar"
#{str_for_yielding_exception_class("ENV['foo'] = v ")}
- Ractor.yield ENV["foo"]
+ port.send ENV["foo"]
end
if /mswin|ucrt/ =~ RUBY_PLATFORM
- #{str_for_assert_raise_on_yielded_exception_class(Errno::EINVAL, "r")}
- result = r.take
+ #{str_for_assert_raise_on_yielded_exception_class(Errno::EINVAL, "port")}
+ result = port.receive
assert_equal("bar", result)
else
- exception_class = r.take
+ exception_class = port.receive
assert_equal(NilClass, exception_class)
- result = r.take
+ result = port.receive
assert_equal(huge_value, result)
end
end;
@@ -1366,42 +1387,43 @@ class TestEnv < Test::Unit::TestCase
def test_frozen_env_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
#{str_for_yielding_exception_class("ENV.freeze")}
end
- #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")}
+ #{str_for_assert_raise_on_yielded_exception_class(TypeError, "port")}
end;
end
def test_frozen_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
ENV["#{PATH_ENV}"] = "/"
ENV.each do |k, v|
- Ractor.yield [k.frozen?]
- Ractor.yield [v.frozen?]
+ port.send [k]
+ port.send [v]
end
ENV.each_key do |k|
- Ractor.yield [k.frozen?]
+ port.send [k]
end
ENV.each_value do |v|
- Ractor.yield [v.frozen?]
+ port.send [v]
end
ENV.each_key do |k|
- Ractor.yield [ENV[k].frozen?, "[\#{k.dump}]"]
- Ractor.yield [ENV.fetch(k).frozen?, "fetch(\#{k.dump})"]
+ port.send [ENV[k], "[\#{k.dump}]"]
+ port.send [ENV.fetch(k), "fetch(\#{k.dump})"]
end
- Ractor.yield "finished"
+ port.send "finished"
end
- while((params=r.take) != "finished")
- assert(*params)
+ while((params=port.receive) != "finished")
+ value, *params = params
+ assert_predicate(value, :frozen?, *params)
end
end;
end
def test_shared_substring_in_ractor
assert_ractor(<<-"end;")
- r = Ractor.new do
+ Ractor.new port = Ractor::Port.new do |port|
bug12475 = '[ruby-dev:49655] [Bug #12475]'
n = [*"0".."9"].join("")*3
e0 = ENV[n0 = "E\#{n}"]
@@ -1411,9 +1433,9 @@ class TestEnv < Test::Unit::TestCase
ENV[n1.chop] = "T\#{n}.".chop
ENV[n0], e0 = e0, ENV[n0]
ENV[n1], e1 = e1, ENV[n1]
- Ractor.yield [n, e0, e1, bug12475]
+ port.send [n, e0, e1, bug12475]
end
- n, e0, e1, bug12475 = r.take
+ n, e0, e1, bug12475 = port.receive
assert_equal("T\#{n}", e0, bug12475)
assert_nil(e1, bug12475)
end;
@@ -1429,7 +1451,7 @@ class TestEnv < Test::Unit::TestCase
rescue Ractor::IsolationError => e
e
end
- assert_equal Ractor::IsolationError, r_get.take.class
+ assert_equal Ractor::IsolationError, r_get.value.class
r_get = Ractor.new do
ENV.instance_eval{ @a }
@@ -1437,7 +1459,7 @@ class TestEnv < Test::Unit::TestCase
e
end
- assert_equal Ractor::IsolationError, r_get.take.class
+ assert_equal Ractor::IsolationError, r_get.value.class
r_set = Ractor.new do
ENV.instance_eval{ @b = "hello" }
@@ -1445,7 +1467,7 @@ class TestEnv < Test::Unit::TestCase
e
end
- assert_equal Ractor::IsolationError, r_set.take.class
+ assert_equal Ractor::IsolationError, r_set.value.class
RUBY
end
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index 84581180b6..4365150a13 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -992,7 +992,7 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
assert_equal 1, outs.size
assert_equal 0, errs.size
err = outs.first.force_encoding('utf-8')
- assert err.valid_encoding?, 'must be valid encoding'
+ assert_predicate err, :valid_encoding?
assert_match %r/\u3042/, err
end
end
@@ -1525,4 +1525,31 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
assert_in_out_err(%W[-r#{lib} #{main}], "", [], [:*, "\n""path=#{main}\n", :*])
end
end
+
+ class Ex; end
+
+ def test_exception_message_for_unexpected_implicit_conversion_type
+ a = Ex.new
+ def self.x(a) = nil
+
+ assert_raise_with_message(TypeError, "no implicit conversion of TestException::Ex into Hash") do
+ x(**a)
+ end
+ assert_raise_with_message(TypeError, "no implicit conversion of TestException::Ex into Proc") do
+ x(&a)
+ end
+
+ def a.to_a = 1
+ def a.to_hash = 1
+ def a.to_proc = 1
+ assert_raise_with_message(TypeError, "can't convert TestException::Ex into Array (TestException::Ex#to_a gives Integer)") do
+ x(*a)
+ end
+ assert_raise_with_message(TypeError, "can't convert TestException::Ex into Hash (TestException::Ex#to_hash gives Integer)") do
+ x(**a)
+ end
+ assert_raise_with_message(TypeError, "can't convert TestException::Ex into Proc (TestException::Ex#to_proc gives Integer)") do
+ x(&a)
+ end
+ end
end
diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb
index b1defdf82c..6976bd9742 100644
--- a/test/ruby/test_fiber.rb
+++ b/test/ruby/test_fiber.rb
@@ -49,7 +49,7 @@ class TestFiber < Test::Unit::TestCase
end
def test_many_fibers_with_threads
- assert_normal_exit <<-SRC, timeout: (/solaris/i =~ RUBY_PLATFORM ? 1000 : 60)
+ assert_normal_exit <<-SRC, timeout: 60
max = 1000
@cnt = 0
(1..100).map{|ti|
@@ -498,7 +498,7 @@ class TestFiber < Test::Unit::TestCase
end
def test_machine_stack_gc
- assert_normal_exit <<-RUBY, '[Bug #14561]', timeout: 10
+ assert_normal_exit <<-RUBY, '[Bug #14561]', timeout: 60
enum = Enumerator.new { |y| y << 1 }
thread = Thread.new { enum.peek }
thread.join
@@ -506,4 +506,45 @@ class TestFiber < Test::Unit::TestCase
GC.start
RUBY
end
+
+ def test_fiber_pool_stack_acquire_failure
+ environment = {
+ "RUBY_SHARED_FIBER_POOL_MINIMUM_COUNT" => "0",
+ "RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT" => "128"
+ }
+
+ # This program requires, effectively, at most one fiber stack, since the fiber immediately becomes unreachable.
+ assert_separately([environment], <<~RUBY, timeout: 30)
+ GC.disable
+ count_before = GC.count
+
+ # Create more fibers than the pool can handle (but they become immediately unreachable):
+ assert_nothing_raised do
+ 256.times do
+ Fiber.new{Fiber.yield}.resume
+ end
+ end
+
+ # Major GC should have happened at least once:
+ assert_operator(GC.count, :>, count_before)
+ RUBY
+ end
+
+ def test_fiber_pool_stack_acquire_failure_at_maximum_count
+ environment = {
+ "RUBY_SHARED_FIBER_POOL_MAXIMUM_COUNT" => "128"
+ }
+
+ assert_separately([environment], <<~RUBY, timeout: 30)
+ GC.disable
+ fibers = []
+ assert_raise(FiberError) do
+ loop do
+ Fiber.new{fibers << Fiber.current; Fiber.yield}.resume
+ raise "expected FiberError before this" if fibers.size > 128
+ end
+ end
+ assert_operator fibers.size, :>=, 128
+ RUBY
+ end
end
diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb
index eae9a8e7b0..a3d6221c0f 100644
--- a/test/ruby/test_file.rb
+++ b/test/ruby/test_file.rb
@@ -372,9 +372,9 @@ class TestFile < Test::Unit::TestCase
end
def test_stat
- tb = Process.clock_gettime(Process::CLOCK_REALTIME)
+ btime = Process.clock_gettime(Process::CLOCK_REALTIME)
Tempfile.create("stat") {|file|
- tb = (tb + Process.clock_gettime(Process::CLOCK_REALTIME)) / 2
+ btime = (btime + Process.clock_gettime(Process::CLOCK_REALTIME)) / 2
file.close
path = file.path
@@ -384,33 +384,32 @@ class TestFile < Test::Unit::TestCase
sleep 2
- t1 = measure_time do
+ mtime = measure_time do
File.write(path, "bar")
end
sleep 2
- t2 = measure_time do
- File.read(path)
+ ctime = measure_time do
File.chmod(0644, path)
end
sleep 2
- t3 = measure_time do
+ atime = measure_time do
File.read(path)
end
delta = 1
stat = File.stat(path)
- assert_in_delta tb, stat.birthtime.to_f, delta
- assert_in_delta t1, stat.mtime.to_f, delta
+ assert_in_delta btime, stat.birthtime.to_f, delta
+ assert_in_delta mtime, stat.mtime.to_f, delta
if stat.birthtime != stat.ctime
- assert_in_delta t2, stat.ctime.to_f, delta
+ assert_in_delta ctime, stat.ctime.to_f, delta
end
if /mswin|mingw/ !~ RUBY_PLATFORM && !Bug::File::Fs.noatime?(path)
# Windows delays updating atime
- assert_in_delta t3, stat.atime.to_f, delta
+ assert_in_delta atime, stat.atime.to_f, delta
end
}
rescue NotImplementedError
diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb
index f3068cb189..6e7973897c 100644
--- a/test/ruby/test_file_exhaustive.rb
+++ b/test/ruby/test_file_exhaustive.rb
@@ -6,7 +6,8 @@ require "socket"
require '-test-/file'
class TestFileExhaustive < Test::Unit::TestCase
- DRIVE = Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i]
+ ROOT_REGEXP = %r'\A(?:[a-z]:(?=(/))|//[^/]+/[^/]+)'i
+ DRIVE = Dir.pwd[ROOT_REGEXP]
POSIX = /cygwin|mswin|bccwin|mingw|emx/ !~ RUBY_PLATFORM
NTFS = !(/mingw|mswin|bccwin/ !~ RUBY_PLATFORM)
@@ -196,12 +197,32 @@ class TestFileExhaustive < Test::Unit::TestCase
[regular_file, utf8_file].each do |file|
assert_equal(file, File.open(file) {|f| f.path})
assert_equal(file, File.path(file))
- o = Object.new
- class << o; self; end.class_eval do
- define_method(:to_path) { file }
- end
+ o = Struct.new(:to_path).new(file)
+ assert_equal(file, File.path(o))
+ o = Struct.new(:to_str).new(file)
assert_equal(file, File.path(o))
end
+
+ conv_error = ->(method, msg = "converting with #{method}") {
+ test = ->(&new) do
+ o = new.(42)
+ assert_raise(TypeError, msg) {File.path(o)}
+
+ o = new.("abc".encode(Encoding::UTF_32BE))
+ assert_raise(Encoding::CompatibilityError, msg) {File.path(o)}
+
+ ["\0", "a\0", "a\0c"].each do |path|
+ o = new.(path)
+ assert_raise(ArgumentError, msg) {File.path(o)}
+ end
+ end
+
+ test.call(&:itself)
+ test.call(&Struct.new(method).method(:new))
+ }
+
+ conv_error[:to_path]
+ conv_error[:to_str]
end
def assert_integer(n)
@@ -876,10 +897,12 @@ class TestFileExhaustive < Test::Unit::TestCase
bug9934 = '[ruby-core:63114] [Bug #9934]'
require "objspace"
path = File.expand_path("/foo")
- assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE], bug9934)
+ slot_size = Integer(ObjectSpace.dump(path)[/"slot_size":(\d+)/, 1])
+ assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + slot_size, bug9934)
path = File.expand_path("/a"*25)
+ slot_size = Integer(ObjectSpace.dump(path)[/"slot_size":(\d+)/, 1])
assert_operator(ObjectSpace.memsize_of(path), :<=,
- (path.bytesize + 1) * 2 + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE], bug9934)
+ (path.bytesize + 1) * 2 + slot_size, bug9934)
end
def test_expand_path_encoding
@@ -1214,6 +1237,7 @@ class TestFileExhaustive < Test::Unit::TestCase
assert_equal("foo", File.basename("foo", ".ext"))
assert_equal("foo", File.basename("foo.ext", ".ext"))
assert_equal("foo", File.basename("foo.ext", ".*"))
+ assert_raise(ArgumentError) {File.basename("", "\0")}
end
if NTFS
@@ -1278,9 +1302,10 @@ class TestFileExhaustive < Test::Unit::TestCase
assert_equal(regular_file, File.dirname(regular_file, 0))
assert_equal(@dir, File.dirname(regular_file, 1))
assert_equal(File.dirname(@dir), File.dirname(regular_file, 2))
- return if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS') # rootdir and tmpdir are in different drives
- assert_equal(rootdir, File.dirname(regular_file, regular_file.count('/')))
assert_raise(ArgumentError) {File.dirname(regular_file, -1)}
+ root = "#{@dir[ROOT_REGEXP]||?/}#{$1}"
+ assert_equal(root, File.dirname(regular_file, regular_file.count('/')))
+ assert_equal(root, File.dirname(regular_file, regular_file.count('/') + 100))
end
def test_dirname_encoding
@@ -1335,14 +1360,19 @@ class TestFileExhaustive < Test::Unit::TestCase
end
def test_join
- s = "foo" + File::SEPARATOR + "bar" + File::SEPARATOR + "baz"
+ sep = File::SEPARATOR
+ s = "foo" + sep + "bar" + sep + "baz"
assert_equal(s, File.join("foo", "bar", "baz"))
assert_equal(s, File.join(["foo", "bar", "baz"]))
+ assert_equal(s, File.join("foo" + sep, "bar", sep + "baz"))
+ assert_equal(s, File.join("foo" + sep, sep + "bar" + sep, sep + "baz"))
o = Object.new
def o.to_path; "foo"; end
assert_equal(s, File.join(o, "bar", "baz"))
- assert_equal(s, File.join("foo" + File::SEPARATOR, "bar", File::SEPARATOR + "baz"))
+
+ s = sep + "foo"
+ assert_equal(s, File.join(sep, s))
end
def test_join_alt_separator
@@ -1475,6 +1505,7 @@ class TestFileExhaustive < Test::Unit::TestCase
end
def test_test
+ omit 'timestamp check is unstable on macOS' if RUBY_PLATFORM =~ /darwin/
fn1 = regular_file
hardlinkfile
sleep(1.1)
diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb
index b865d339a9..c01e8bb80b 100644
--- a/test/ruby/test_float.rb
+++ b/test/ruby/test_float.rb
@@ -492,6 +492,22 @@ class TestFloat < Test::Unit::TestCase
assert_equal(-1.26, -1.255.round(2))
end
+ def test_round_ndigits
+ bug14635 = "[ruby-core:86323]"
+ f = 0.5
+ 31.times do |i|
+ assert_equal(0.5, f.round(i+1), bug14635 + " (argument: #{i+1})")
+ end
+ end
+
+ def test_round_with_precision_min
+ (0..3).each do |n|
+ n -= Float::MIN_10_EXP
+ f = Float::MIN.round(n)
+ assert_include([Float::MIN.floor(n), Float::MIN.ceil(n)], f, "round(#{n})")
+ end
+ end
+
def test_round_half_even_with_precision
assert_equal(767573.18759, 767573.1875850001.round(5, half: :even))
assert_equal(767573.18758, 767573.187585.round(5, half: :even))
@@ -536,6 +552,16 @@ class TestFloat < Test::Unit::TestCase
assert_equal(-100000000000000000000000000000000000000000000000000, -1.0.floor(-50), "[Bug #20654]")
end
+ def test_floor_with_precision_min
+ min = Float::MIN
+ (0..3).each do |n|
+ n -= Float::MIN_10_EXP
+ f = min.floor(n)
+ assert_operator(f, :<=, Float::MIN, "floor(#{n})")
+ assert_operator(f, :>=, Float::MIN.floor(n-1), "ceil(#{n})")
+ end
+ end
+
def test_ceil_with_precision
assert_equal(+0.1, +0.001.ceil(1))
assert_equal(-0.0, -0.001.ceil(1))
@@ -567,6 +593,19 @@ class TestFloat < Test::Unit::TestCase
assert_equal(100000000000000000000000000000000000000000000000000, 1.0.ceil(-50), "[Bug #20654]")
end
+ def test_ceil_with_precision_min
+ min = Float::MIN
+ (-Float::MIN_10_EXP).times do |n|
+ assert_equal(10.pow(-n), min.ceil(n))
+ end
+ (0..3).each do |n|
+ n -= Float::MIN_10_EXP
+ f = min.ceil(n)
+ assert_operator(f, :>=, Float::MIN, "ceil(#{n})")
+ assert_operator(f, :<=, Float::MIN.ceil(n-1), "ceil(#{n})")
+ end
+ end
+
def test_truncate_with_precision
assert_equal(1.100, 1.111.truncate(1))
assert_equal(1.110, 1.111.truncate(2))
@@ -861,7 +900,9 @@ class TestFloat < Test::Unit::TestCase
assert_raise(Encoding::CompatibilityError) {Float("0".encode("utf-32le"))}
assert_raise(Encoding::CompatibilityError) {Float("0".encode("iso-2022-jp"))}
- assert_raise_with_message(ArgumentError, /\u{1f4a1}/) {Float("\u{1f4a1}")}
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(ArgumentError, /\u{1f4a1}/) {Float("\u{1f4a1}")}
+ end
end
def test_invalid_str
diff --git a/test/ruby/test_frozen.rb b/test/ruby/test_frozen.rb
index 2918a2afd8..6721cb1128 100644
--- a/test/ruby/test_frozen.rb
+++ b/test/ruby/test_frozen.rb
@@ -27,4 +27,20 @@ class TestFrozen < Test::Unit::TestCase
str.freeze
assert_raise(FrozenError) { str.instance_variable_set(:@b, 1) }
end
+
+ def test_setting_ivar_on_frozen_string_with_singleton_class
+ str = "str"
+ str.singleton_class
+ str.freeze
+ assert_raise_with_message(FrozenError, "can't modify frozen String: \"str\"") { str.instance_variable_set(:@a, 1) }
+ end
+
+ class A
+ freeze
+ end
+
+ def test_setting_ivar_on_frozen_class
+ assert_raise_with_message(FrozenError, "can't modify frozen Class: TestFrozen::A") { A.instance_variable_set(:@a, 1) }
+ assert_raise_with_message(FrozenError, "can't modify frozen Class: #<Class:TestFrozen::A>") { A.singleton_class.instance_variable_set(:@a, 1) }
+ end
end
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
index 7ae05e206f..21448294c2 100644
--- a/test/ruby/test_gc.rb
+++ b/test/ruby/test_gc.rb
@@ -75,12 +75,9 @@ class TestGc < Test::Unit::TestCase
GC.start
end
- def test_gc_config_setting_returns_nil_for_missing_keys
- missing_value = GC.config(no_such_key: true)[:no_such_key]
- assert_nil(missing_value)
- ensure
- GC.config(full_mark: true)
- GC.start
+ def test_gc_config_setting_returns_config_hash
+ hash = GC.config(no_such_key: true)
+ assert_equal(GC.config, hash)
end
def test_gc_config_disable_major
@@ -211,7 +208,7 @@ class TestGc < Test::Unit::TestCase
assert_equal stat[:total_allocated_pages], stat[:heap_allocated_pages] + stat[:total_freed_pages]
assert_equal stat[:heap_available_slots], stat[:heap_live_slots] + stat[:heap_free_slots] + stat[:heap_final_slots]
assert_equal stat[:heap_live_slots], stat[:total_allocated_objects] - stat[:total_freed_objects] - stat[:heap_final_slots]
- assert_equal stat[:heap_allocated_pages], stat[:heap_eden_pages]
+ assert_equal stat[:heap_allocated_pages], stat[:heap_eden_pages] + stat[:heap_empty_pages]
if use_rgengc?
assert_equal stat[:count], stat[:major_gc_count] + stat[:minor_gc_count]
@@ -233,7 +230,10 @@ class TestGc < Test::Unit::TestCase
GC.stat(stat)
end
- assert_equal (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]) * (2**i), stat_heap[:slot_size]
+ assert_equal GC.stat_heap(i, :slot_size), stat_heap[:slot_size]
+ assert_operator stat_heap[:heap_live_slots], :<=, stat[:heap_live_slots]
+ assert_operator stat_heap[:heap_free_slots], :<=, stat[:heap_free_slots]
+ assert_operator stat_heap[:heap_final_slots], :<=, stat[:heap_final_slots]
assert_operator stat_heap[:heap_eden_pages], :<=, stat[:heap_eden_pages]
assert_operator stat_heap[:heap_eden_slots], :>=, 0
assert_operator stat_heap[:total_allocated_pages], :>=, 0
@@ -264,7 +264,7 @@ class TestGc < Test::Unit::TestCase
GC.stat_heap(i, stat_heap)
# Remove keys that can vary between invocations
- %i(total_allocated_objects).each do |sym|
+ %i(total_allocated_objects heap_live_slots heap_free_slots).each do |sym|
stat_heap[sym] = stat_heap_all[i][sym] = 0
end
@@ -289,6 +289,9 @@ class TestGc < Test::Unit::TestCase
hash.each { |k, v| stat_heap_sum[k] += v }
end
+ assert_equal stat[:heap_live_slots], stat_heap_sum[:heap_live_slots]
+ assert_equal stat[:heap_free_slots], stat_heap_sum[:heap_free_slots]
+ assert_equal stat[:heap_final_slots], stat_heap_sum[:heap_final_slots]
assert_equal stat[:heap_eden_pages], stat_heap_sum[:heap_eden_pages]
assert_equal stat[:heap_available_slots], stat_heap_sum[:heap_eden_slots]
assert_equal stat[:total_allocated_objects], stat_heap_sum[:total_allocated_objects]
@@ -296,7 +299,7 @@ class TestGc < Test::Unit::TestCase
end
def test_measure_total_time
- assert_separately([], __FILE__, __LINE__, <<~RUBY)
+ assert_separately([], __FILE__, __LINE__, <<~RUBY, timeout: 60)
GC.measure_total_time = false
time_before = GC.stat(:time)
@@ -315,9 +318,9 @@ class TestGc < Test::Unit::TestCase
def test_latest_gc_info
omit 'stress' if GC.stress
- assert_separately([], __FILE__, __LINE__, <<-'RUBY')
+ assert_separately([{"RUBY_GC_HEAP_INIT_BYTES" => "409600"}, "-W0"], __FILE__, __LINE__, <<-'RUBY')
GC.start
- count = GC.stat(:heap_free_slots) + GC.stat(:heap_allocatable_slots)
+ count = GC.stat(:heap_free_slots) + GC.stat_heap(0, :heap_allocatable_slots)
count.times{ "a" + "b" }
assert_equal :newobj, GC.latest_gc_info[:gc_by]
RUBY
@@ -379,51 +382,36 @@ class TestGc < Test::Unit::TestCase
def test_latest_gc_info_weak_references_count
assert_separately([], __FILE__, __LINE__, <<~RUBY)
GC.disable
- count = 10_000
+ COUNT = 10_000
# Some weak references may be created, so allow some margin of error
error_tolerance = 100
- # Run full GC to clear out weak references
- GC.start
- # Run full GC again to collect stats about weak references
+ # Run full GC to collect stats about weak references
GC.start
before_weak_references_count = GC.latest_gc_info(:weak_references_count)
- before_retained_weak_references_count = GC.latest_gc_info(:retained_weak_references_count)
- # Create some objects and place it in a WeakMap
- wmap = ObjectSpace::WeakMap.new
- ary = Array.new(count)
- enum = count.times
- enum.each.with_index do |i|
- obj = Object.new
- ary[i] = obj
- wmap[obj] = nil
+ # Create some WeakMaps
+ ary = Array.new(COUNT)
+ COUNT.times.with_index do |i|
+ ary[i] = ObjectSpace::WeakMap.new
end
# Run full GC to collect stats about weak references
GC.start
- assert_operator(GC.latest_gc_info(:weak_references_count), :>=, before_weak_references_count + count - error_tolerance)
- assert_operator(GC.latest_gc_info(:retained_weak_references_count), :>=, before_retained_weak_references_count + count - error_tolerance)
- assert_operator(GC.latest_gc_info(:retained_weak_references_count), :<=, GC.latest_gc_info(:weak_references_count))
+ assert_operator(GC.latest_gc_info(:weak_references_count), :>=, before_weak_references_count + COUNT - error_tolerance)
before_weak_references_count = GC.latest_gc_info(:weak_references_count)
- before_retained_weak_references_count = GC.latest_gc_info(:retained_weak_references_count)
+ # Clear ary, so if ary itself is somewhere on the stack, it won't hold all references
+ ary.clear
ary = nil
- # Free ary, which should empty out the wmap
+ # Free ary, which should GC all the WeakMaps
GC.start
- # Run full GC again to collect stats about weak references
- GC.start
-
- # Sometimes the WeakMap has a few elements, which might be held on by registers.
- assert_operator(wmap.size, :<=, 2)
- assert_operator(GC.latest_gc_info(:weak_references_count), :<=, before_weak_references_count - count + error_tolerance)
- assert_operator(GC.latest_gc_info(:retained_weak_references_count), :<=, before_retained_weak_references_count - count + error_tolerance)
- assert_operator(GC.latest_gc_info(:retained_weak_references_count), :<=, GC.latest_gc_info(:weak_references_count))
+ assert_operator(GC.latest_gc_info(:weak_references_count), :<=, before_weak_references_count - COUNT + error_tolerance)
RUBY
end
@@ -450,7 +438,7 @@ class TestGc < Test::Unit::TestCase
end
def test_singleton_method_added
- assert_in_out_err([], <<-EOS, [], [], "[ruby-dev:44436]")
+ assert_in_out_err([], <<-EOS, [], [], "[ruby-dev:44436]", timeout: 30)
class BasicObject
undef singleton_method_added
def singleton_method_added(mid)
@@ -465,32 +453,19 @@ class TestGc < Test::Unit::TestCase
end
def test_gc_parameter
- env = {
- "RUBY_GC_HEAP_INIT_SLOTS" => "100"
- }
- assert_in_out_err([env, "-W0", "-e", "exit"], "", [], [])
- assert_in_out_err([env, "-W:deprecated", "-e", "exit"], "", [],
- /The environment variable RUBY_GC_HEAP_INIT_SLOTS is deprecated; use environment variables RUBY_GC_HEAP_%d_INIT_SLOTS instead/)
-
- env = {}
- GC.stat_heap.keys.each do |heap|
- env["RUBY_GC_HEAP_#{heap}_INIT_SLOTS"] = "200000"
- end
+ env = { "RUBY_GC_HEAP_INIT_BYTES" => "#{200000 * 40}" }
assert_normal_exit("exit", "", :child_env => env)
- env = {}
- GC.stat_heap.keys.each do |heap|
- env["RUBY_GC_HEAP_#{heap}_INIT_SLOTS"] = "0"
- end
+ env = { "RUBY_GC_HEAP_INIT_BYTES" => "0" }
assert_normal_exit("exit", "", :child_env => env)
env = {
"RUBY_GC_HEAP_GROWTH_FACTOR" => "2.0",
- "RUBY_GC_HEAP_GROWTH_MAX_SLOTS" => "10000"
+ "RUBY_GC_HEAP_GROWTH_MAX_BYTES" => "409600"
}
assert_normal_exit("exit", "", :child_env => env)
assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_FACTOR=2.0/, "")
- assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_MAX_SLOTS=10000/, "[ruby-core:57928]")
+ assert_in_out_err([env, "-w", "-e", "exit"], "", [], /RUBY_GC_HEAP_GROWTH_MAX_BYTES=409600/, "[ruby-core:57928]")
if use_rgengc?
env = {
@@ -532,16 +507,19 @@ class TestGc < Test::Unit::TestCase
end
end
- def test_gc_parameter_init_slots
+ def test_gc_parameter_init_bytes
+ omit "[Bug #21203] This test is flaky and intermittently failing now"
+
assert_separately([], __FILE__, __LINE__, <<~RUBY, timeout: 60)
- # Constant from gc.c.
- GC_HEAP_INIT_SLOTS = 10_000
+ GC_HEAP_INIT_BYTES = 2560 * 1024
gc_count = GC.stat(:count)
- # Fill up all of the size pools to the init slots
+ # Fill up all heaps to the byte-derived init slot count
GC::INTERNAL_CONSTANTS[:HEAP_COUNT].times do |i|
- capa = (GC.stat_heap(i, :slot_size) - GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD] - (2 * RbConfig::SIZEOF["void*"])) / RbConfig::SIZEOF["void*"]
- while GC.stat_heap(i, :heap_eden_slots) < GC_HEAP_INIT_SLOTS
+ slot_size = GC.stat_heap(i, :slot_size)
+ init_slots = GC_HEAP_INIT_BYTES / slot_size
+ capa = (slot_size - GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD] - (2 * RbConfig::SIZEOF["void*"])) / RbConfig::SIZEOF["void*"]
+ while GC.stat_heap(i, :heap_eden_slots) < init_slots
Array.new(capa)
end
end
@@ -549,19 +527,17 @@ class TestGc < Test::Unit::TestCase
assert_equal gc_count, GC.stat(:count)
RUBY
- env = {}
- sizes = GC.stat_heap.keys.reverse.map { 20_000 }
- GC.stat_heap.keys.each do |heap|
- env["RUBY_GC_HEAP_#{heap}_INIT_SLOTS"] = sizes[heap].to_s
- end
+ env = { "RUBY_GC_HEAP_INIT_BYTES" => "#{800 * 1024}" }
assert_separately([env, "-W0"], __FILE__, __LINE__, <<~RUBY, timeout: 60)
- SIZES = #{sizes}
+ GC_HEAP_INIT_BYTES = 800 * 1024
gc_count = GC.stat(:count)
- # Fill up all of the size pools to the init slots
+ # Fill up all heaps to the byte-derived init slot count
GC::INTERNAL_CONSTANTS[:HEAP_COUNT].times do |i|
- capa = (GC.stat_heap(i, :slot_size) - GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD] - (2 * RbConfig::SIZEOF["void*"])) / RbConfig::SIZEOF["void*"]
- while GC.stat_heap(i, :heap_eden_slots) < SIZES[i]
+ slot_size = GC.stat_heap(i, :slot_size)
+ init_slots = GC_HEAP_INIT_BYTES / slot_size
+ capa = (slot_size - GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD] - (2 * RbConfig::SIZEOF["void*"])) / RbConfig::SIZEOF["void*"]
+ while GC.stat_heap(i, :heap_eden_slots) < init_slots
Array.new(capa)
end
end
@@ -676,17 +652,40 @@ class TestGc < Test::Unit::TestCase
debug_msg = "before_stats: #{before_stats}\nbefore_stat_heap: #{before_stat_heap}\nafter_stats: #{after_stats}\nafter_stat_heap: #{after_stat_heap}"
# Should not be thrashing in page creation
- assert_equal before_stats[:heap_allocated_pages], after_stats[:heap_allocated_pages], debug_msg
- assert_equal 0, after_stats[:heap_empty_pages], debug_msg
+ assert_in_epsilon before_stats[:heap_allocated_pages], after_stats[:heap_allocated_pages], 0.5, debug_msg
assert_equal 0, after_stats[:total_freed_pages], debug_msg
- # Only young objects, so should not trigger major GC
- assert_equal before_stats[:major_gc_count], after_stats[:major_gc_count], debug_msg
+ RUBY
+ end
+
+ def test_heaps_grow_independently
+ # [Bug #21214]
+
+ assert_separately([], __FILE__, __LINE__, <<-'RUBY', timeout: 60)
+ COUNT = 1_000_000
+
+ def allocate_small_object = []
+ def allocate_large_object = Array.new(10)
+
+ @arys = Array.new(COUNT) do
+ # Allocate 10 small transient objects
+ 10.times { allocate_small_object }
+ # Allocate 1 large object that is persistent
+ allocate_large_object
+ end
+
+ # Running GC here is required to prevent this test from being flaky because
+ # the heap for the small transient objects may not have been cleared by the
+ # GC causing heap_available_slots to be slightly over 2 * COUNT.
+ GC.start
+
+ heap_available_slots = GC.stat(:heap_available_slots)
+
+ assert_operator(heap_available_slots, :<, COUNT * 2, "GC.stat: #{GC.stat}\nGC.stat_heap: #{GC.stat_heap}")
RUBY
end
def test_gc_internals
- assert_not_nil GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT]
- assert_not_nil GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]
+ assert_not_nil GC::INTERNAL_CONSTANTS[:HEAP_COUNT]
end
def test_sweep_in_finalizer
@@ -717,6 +716,7 @@ class TestGc < Test::Unit::TestCase
end
def test_interrupt_in_finalizer
+ omit 'randomly hangs on many platforms' if ENV.key?('GITHUB_ACTIONS')
bug10595 = '[ruby-core:66825] [Bug #10595]'
src = <<-'end;'
Signal.trap(:INT, 'DEFAULT')
@@ -732,7 +732,7 @@ class TestGc < Test::Unit::TestCase
ObjectSpace.define_finalizer(Object.new, f)
end
end;
- out, err, status = assert_in_out_err(["-e", src], "", [], [], bug10595, signal: :SEGV) do |*result|
+ out, err, status = assert_in_out_err(["-e", src], "", [], [], bug10595, signal: :SEGV, timeout: 100) do |*result|
break result
end
unless /mswin|mingw/ =~ RUBY_PLATFORM
@@ -773,7 +773,7 @@ class TestGc < Test::Unit::TestCase
end
def test_gc_stress_at_startup
- assert_in_out_err([{"RUBY_DEBUG"=>"gc_stress"}], '', [], [], '[Bug #15784]', success: true, timeout: 60)
+ assert_in_out_err([{"RUBY_DEBUG"=>"gc_stress"}], '', [], [], '[Bug #15784]', success: true, timeout: 120)
end
def test_gc_disabled_start
@@ -799,6 +799,8 @@ class TestGc < Test::Unit::TestCase
end
def test_exception_in_finalizer_procs
+ require '-test-/stack'
+ omit 'failing with ASAN' if Thread.asan?
assert_in_out_err(["-W0"], "#{<<~"begin;"}\n#{<<~'end;'}", %w[c1 c2])
c1 = proc do
puts "c1"
@@ -819,6 +821,8 @@ class TestGc < Test::Unit::TestCase
end
def test_exception_in_finalizer_method
+ require '-test-/stack'
+ omit 'failing with ASAN' if Thread.asan?
assert_in_out_err(["-W0"], "#{<<~"begin;"}\n#{<<~'end;'}", %w[c1 c2])
def self.c1(x)
puts "c1"
@@ -884,4 +888,25 @@ class TestGc < Test::Unit::TestCase
assert_include ObjectSpace.dump(young_obj), '"old":true'
end
end
+
+ def test_finalizer_not_run_with_vm_lock
+ assert_ractor(<<~'RUBY', timeout: 30)
+ Thread.new do
+ loop do
+ Encoding.list.each do |enc|
+ enc.names
+ end
+ end
+ end
+
+ o = Object.new
+ ObjectSpace.define_finalizer(o, proc do
+ sleep 0.5 # finalizer shouldn't be run with VM lock, otherwise this context switch will crash
+ end)
+ o = nil
+ 4.times do
+ GC.start
+ end
+ RUBY
+ end
end
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
index 3eaa93dfae..cb5e9d6ccb 100644
--- a/test/ruby/test_gc_compact.rb
+++ b/test/ruby/test_gc_compact.rb
@@ -30,7 +30,7 @@ class TestGCCompact < Test::Unit::TestCase
def test_enable_autocompact
before = GC.auto_compact
GC.auto_compact = true
- assert GC.auto_compact
+ assert_predicate GC, :auto_compact
ensure
GC.auto_compact = before
end
@@ -151,12 +151,12 @@ class TestGCCompact < Test::Unit::TestCase
def walk_ast ast
children = ast.children.grep(RubyVM::AbstractSyntaxTree::Node)
children.each do |child|
- assert child.type
+ assert_predicate child, :type
walk_ast child
end
end
ast = RubyVM::AbstractSyntaxTree.parse_file #{__FILE__.dump}
- assert GC.compact
+ assert_predicate GC, :compact
walk_ast ast
end;
end
@@ -207,7 +207,7 @@ class TestGCCompact < Test::Unit::TestCase
end
def test_updating_references_for_embed_shared_arrays
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10)
begin;
@@ -256,7 +256,7 @@ class TestGCCompact < Test::Unit::TestCase
end
def test_updating_references_for_embed_frozen_shared_arrays
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10)
begin;
@@ -284,7 +284,7 @@ class TestGCCompact < Test::Unit::TestCase
end
def test_moving_arrays_down_heaps
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10)
begin;
@@ -300,13 +300,13 @@ class TestGCCompact < Test::Unit::TestCase
}.resume
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
- assert_operator(stats.dig(:moved_down, :T_ARRAY) || 0, :>=, ARY_COUNT - 10)
+ assert_operator(stats.dig(:moved_down, :T_ARRAY) || 0, :>=, ARY_COUNT - 25)
refute_empty($arys.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
def test_moving_arrays_up_heaps
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10)
begin;
@@ -315,7 +315,7 @@ class TestGCCompact < Test::Unit::TestCase
GC.verify_compaction_references(expand_heap: true, toward: :empty)
Fiber.new {
- ary = "hello".chars
+ ary = "hello world".chars # > 6 elements to exceed pool 0 embed capacity
$arys = ARY_COUNT.times.map do
x = []
ary.each { |e| x << e }
@@ -324,13 +324,13 @@ class TestGCCompact < Test::Unit::TestCase
}.resume
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
- assert_operator(stats.dig(:moved_up, :T_ARRAY) || 0, :>=, ARY_COUNT - 10)
+ assert_operator(stats.dig(:moved_up, :T_ARRAY) || 0, :>=, (0.9995 * ARY_COUNT).to_i)
refute_empty($arys.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
def test_moving_objects_between_heaps
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 60)
begin;
@@ -356,13 +356,29 @@ class TestGCCompact < Test::Unit::TestCase
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
- assert_operator(stats.dig(:moved_up, :T_OBJECT) || 0, :>=, OBJ_COUNT - 10)
+ assert_operator(stats.dig(:moved_up, :T_OBJECT) || 0, :>=, OBJ_COUNT - 25)
refute_empty($ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
+ def test_compact_objects_of_varying_sizes
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
+
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10)
+ begin;
+ $objects = []
+ 160.times do |n|
+ obj = Class.new.new
+ n.times { |i| obj.instance_variable_set("@foo" + i.to_s, 0) }
+ $objects << obj
+ end
+
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
+ end;
+ end
+
def test_moving_strings_up_heaps
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 30)
begin;
@@ -371,19 +387,19 @@ class TestGCCompact < Test::Unit::TestCase
GC.verify_compaction_references(expand_heap: true, toward: :empty)
Fiber.new {
- str = "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 4
+ str = "a" * GC.stat_heap(0, :slot_size) * 4
$ary = STR_COUNT.times.map { +"" << str }
}.resume
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
- assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT - 10)
+ assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT - 25)
refute_empty($ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
def test_moving_strings_down_heaps
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 30)
begin;
@@ -392,18 +408,18 @@ class TestGCCompact < Test::Unit::TestCase
GC.verify_compaction_references(expand_heap: true, toward: :empty)
Fiber.new {
- $ary = STR_COUNT.times.map { ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 4).squeeze! }
+ $ary = STR_COUNT.times.map { ("a" * GC.stat_heap(0, :slot_size) * 4).squeeze! }
}.resume
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
- assert_operator(stats[:moved_down][:T_STRING], :>=, STR_COUNT - 10)
+ assert_operator(stats[:moved_down][:T_STRING], :>=, STR_COUNT - 25)
refute_empty($ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
def test_moving_hashes_down_heaps
- omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
# AR and ST hashes are in the same size pool on 32 bit
omit unless RbConfig::SIZEOF["uint64_t"] <= RbConfig::SIZEOF["void*"]
@@ -421,7 +437,7 @@ class TestGCCompact < Test::Unit::TestCase
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
- assert_operator(stats[:moved_down][:T_HASH], :>=, HASH_COUNT - 10)
+ assert_operator(stats[:moved_down][:T_HASH], :>=, HASH_COUNT - 25)
end;
end
@@ -453,7 +469,7 @@ class TestGCCompact < Test::Unit::TestCase
end;
end
- def test_moving_too_complex_generic_ivar
+ def test_moving_complex_generic_ivar
omit "not compiled with SHAPE_DEBUG" unless defined?(RubyVM::Shape)
assert_separately([], <<~RUBY)
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index b6c18ea958..2d1b513c70 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -465,10 +465,10 @@ class TestHash < Test::Unit::TestCase
def test_each_value
res = []
@cls[].each_value { |v| res << v }
- assert_equal(0, [].length)
+ assert_equal(0, res.length)
@h.each_value { |v| res << v }
- assert_equal(0, [].length)
+ assert_equal(@h.size, res.length)
expected = []
@h.each { |k, v| expected << v }
@@ -880,21 +880,20 @@ class TestHash < Test::Unit::TestCase
assert_equal(quote1, eval(quote1).inspect)
assert_equal(quote2, eval(quote2).inspect)
assert_equal(quote3, eval(quote3).inspect)
- begin
- verbose_bak, $VERBOSE = $VERBOSE, nil
- enc = Encoding.default_external
- Encoding.default_external = Encoding::ASCII
+
+ EnvUtil.with_default_external(Encoding::ASCII) do
utf8_ascii_hash = '{"\\u3042": 1}'
assert_equal(eval(utf8_ascii_hash).inspect, utf8_ascii_hash)
- Encoding.default_external = Encoding::UTF_8
+ end
+
+ EnvUtil.with_default_external(Encoding::UTF_8) do
utf8_hash = "{\u3042: 1}"
assert_equal(eval(utf8_hash).inspect, utf8_hash)
- Encoding.default_external = Encoding::Windows_31J
+ end
+
+ EnvUtil.with_default_external(Encoding::Windows_31J) do
sjis_hash = "{\x87]: 1}".force_encoding('sjis')
assert_equal(eval(sjis_hash).inspect, sjis_hash)
- ensure
- Encoding.default_external = enc
- $VERBOSE = verbose_bak
end
end
@@ -1297,6 +1296,17 @@ class TestHash < Test::Unit::TestCase
assert_equal(@cls[a: 10, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], h)
end
+ def test_update_modify_in_block
+ a = @cls[]
+ (1..1337).each {|k| a[k] = k}
+ b = {1=>1338}
+ assert_raise_with_message(RuntimeError, /rehash during iteration/) do
+ a.update(b) {|k, o, n|
+ a.rehash
+ }
+ end
+ end
+
def test_update_on_identhash
key = +'a'
i = @cls[].compare_by_identity
@@ -1853,6 +1863,14 @@ class TestHash < Test::Unit::TestCase
end
end
assert_equal(@cls[a: 2, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], x)
+
+ x = (1..1337).to_h {|k| [k, k]}
+ assert_raise_with_message(RuntimeError, /rehash during iteration/) do
+ x.transform_values! {|v|
+ x.rehash if v == 1337
+ v * 2
+ }
+ end
end
def hrec h, n, &b
@@ -1989,7 +2007,7 @@ class TestHashOnly < Test::Unit::TestCase
EnvUtil.without_gc do
before = ObjectSpace.count_objects[:T_STRING]
- 5.times{ h["abc"] }
+ 5.times{ h["abc".freeze] }
assert_equal before, ObjectSpace.count_objects[:T_STRING]
end
end
@@ -2119,7 +2137,9 @@ class TestHashOnly < Test::Unit::TestCase
def test_iterlevel_in_ivar_bug19589
h = { a: nil }
- hash_iter_recursion(h, 200)
+ # Recursion level should be over 127 to actually test iterlevel being set in an instance variable,
+ # but it should be under 131 not to overflow the stack under MN threads/ractors.
+ hash_iter_recursion(h, 130)
assert true
end
@@ -2336,6 +2356,11 @@ class TestHashOnly < Test::Unit::TestCase
end
end
+ def test_bug_21357
+ h = {x: []}.merge(x: nil) { |_k, v1, _v2| v1 }
+ assert_equal({x: []}, h)
+ end
+
def test_any_hash_fixable
20.times do
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb
index 1dbb3fbb45..c3d9d311c8 100644
--- a/test/ruby/test_integer.rb
+++ b/test/ruby/test_integer.rb
@@ -158,7 +158,9 @@ class TestInteger < Test::Unit::TestCase
assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("utf-32le"))}
assert_raise(Encoding::CompatibilityError, bug6192) {Integer("0".encode("iso-2022-jp"))}
- assert_raise_with_message(ArgumentError, /\u{1f4a1}/) {Integer("\u{1f4a1}")}
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(ArgumentError, /\u{1f4a1}/) {Integer("\u{1f4a1}")}
+ end
obj = Struct.new(:s).new(%w[42 not-an-integer])
def obj.to_str; s.shift; end
@@ -708,6 +710,10 @@ class TestInteger < Test::Unit::TestCase
assert_equal(x, Integer.sqrt(x ** 2), "[ruby-core:95453]")
end
+ def test_bug_21217
+ assert_equal(0x10000 * 2**10, Integer.sqrt(0x100000008 * 2**20))
+ end
+
def test_fdiv
assert_equal(1.0, 1.fdiv(1))
assert_equal(0.5, 1.fdiv(2))
@@ -745,7 +751,7 @@ class TestInteger < Test::Unit::TestCase
o = Object.new
def o.to_int; Object.new; end
- assert_raise_with_message(TypeError, /can't convert Object to Integer/) {Integer.try_convert(o)}
+ assert_raise_with_message(TypeError, /can't convert Object into Integer/) {Integer.try_convert(o)}
end
def test_ceildiv
diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb
index 255de0b0a0..a78527d40e 100644
--- a/test/ruby/test_io.rb
+++ b/test/ruby/test_io.rb
@@ -467,6 +467,24 @@ class TestIO < Test::Unit::TestCase
}
end
+ def test_each_codepoint_with_ungetc
+ bug21562 = '[ruby-core:123176] [Bug #21562]'
+ with_read_pipe("") {|p|
+ p.binmode
+ p.ungetc("aa")
+ a = ""
+ p.each_codepoint { |c| a << c }
+ assert_equal("aa", a, bug21562)
+ }
+ with_read_pipe("") {|p|
+ p.set_encoding("ascii-8bit", universal_newline: true)
+ p.ungetc("aa")
+ a = ""
+ p.each_codepoint { |c| a << c }
+ assert_equal("aa", a, bug21562)
+ }
+ end
+
def test_rubydev33072
t = make_tempfile
path = t.path
@@ -1375,10 +1393,6 @@ class TestIO < Test::Unit::TestCase
args = ['-e', '$>.write($<.read)'] if args.empty?
ruby = EnvUtil.rubybin
opts = {}
- if defined?(Process::RLIMIT_NPROC)
- lim = Process.getrlimit(Process::RLIMIT_NPROC)[1]
- opts[:rlimit_nproc] = [lim, 2048].min
- end
f = IO.popen([ruby] + args, 'r+', opts)
pid = f.pid
yield(f)
@@ -2601,36 +2615,15 @@ class TestIO < Test::Unit::TestCase
assert_equal({:a=>1}, open(o, {a: 1}))
end
- def test_open_pipe
- assert_deprecated_warning(/Kernel#open with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630
- open("|" + EnvUtil.rubybin, "r+") do |f|
- f.puts "puts 'foo'"
- f.close_write
- assert_equal("foo\n", f.read)
- end
- end
- end
+ def test_path_with_pipe
+ mkcdtmpdir do
+ cmd = "|echo foo"
+ assert_file.not_exist?(cmd)
- def test_read_command
- assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630
- assert_equal("foo\n", IO.read("|echo foo"))
- end
- assert_raise(Errno::ENOENT, Errno::EINVAL) do
- File.read("|#{EnvUtil.rubybin} -e puts")
- end
- assert_raise(Errno::ENOENT, Errno::EINVAL) do
- File.binread("|#{EnvUtil.rubybin} -e puts")
- end
- assert_raise(Errno::ENOENT, Errno::EINVAL) do
- Class.new(IO).read("|#{EnvUtil.rubybin} -e puts")
- end
- assert_raise(Errno::ENOENT, Errno::EINVAL) do
- Class.new(IO).binread("|#{EnvUtil.rubybin} -e puts")
- end
- assert_raise(Errno::ESPIPE) do
- assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|#{EnvUtil.rubybin} -e 'puts :foo'", 1, 1)
- end
+ pipe_errors = [Errno::ENOENT, Errno::EINVAL, Errno::EACCES, Errno::EPERM]
+ assert_raise(*pipe_errors) { open(cmd, "r+") }
+ assert_raise(*pipe_errors) { IO.read(cmd) }
+ assert_raise(*pipe_errors) { IO.foreach(cmd) {|x| assert false } }
end
end
@@ -2835,19 +2828,6 @@ class TestIO < Test::Unit::TestCase
end
def test_foreach
- a = []
-
- assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x }
- end
- assert_equal(["foo\n", "bar\n", "baz\n"], a)
-
- a = []
- assert_deprecated_warning(/IO process creation with a leading '\|'/) do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :zot'", :open_args => ["r"]) {|x| a << x }
- end
- assert_equal(["zot\n"], a)
-
make_tempfile {|t|
a = []
IO.foreach(t.path) {|x| a << x }
@@ -2923,10 +2903,10 @@ class TestIO < Test::Unit::TestCase
end
def test_print_separators
- EnvUtil.suppress_warning {
- $, = ':'
- $\ = "\n"
- }
+ assert_deprecated_warning(/non-nil '\$,'/) {$, = ":"}
+ assert_raise(TypeError) {$, = 1}
+ assert_deprecated_warning(/non-nil '\$\\'/) {$\ = "\n"}
+ assert_raise(TypeError) {$/ = 1}
pipe(proc do |w|
w.print('a')
EnvUtil.suppress_warning {w.print('a','b','c')}
@@ -3826,7 +3806,7 @@ __END__
end
tempfiles = []
- (0..fd_setsize+1).map {|i|
+ (0...fd_setsize).map {|i|
tempfiles << Tempfile.create("test_io_select_with_many_files")
}
@@ -4262,6 +4242,23 @@ __END__
end
end if Socket.const_defined?(:MSG_OOB)
+ def test_select_timeout
+ assert_equal(nil, IO.select(nil,nil,nil,0))
+ assert_equal(nil, IO.select(nil,nil,nil,0.0))
+ assert_raise(TypeError) { IO.select(nil,nil,nil,"invalid-timeout") }
+ assert_raise(ArgumentError) { IO.select(nil,nil,nil,-1) }
+ assert_raise(ArgumentError) { IO.select(nil,nil,nil,-0.1) }
+ assert_raise(ArgumentError) { IO.select(nil,nil,nil,-Float::INFINITY) }
+ assert_raise(RangeError) { IO.select(nil,nil,nil,Float::NAN) }
+ IO.pipe {|r, w|
+ w << "x"
+ ret = [[r], [], []]
+ assert_equal(ret, IO.select([r],nil,nil,0.1))
+ assert_equal(ret, IO.select([r],nil,nil,1))
+ assert_equal(ret, IO.select([r],nil,nil,Float::INFINITY))
+ }
+ end
+
def test_recycled_fd_close
dot = -'.'
IO.pipe do |sig_rd, sig_wr|
@@ -4399,4 +4396,29 @@ __END__
end
RUBY
end
+
+ def test_fork_close
+ omit "fork is not supported" unless Process.respond_to?(:fork)
+
+ assert_separately([], <<~'RUBY')
+ r, w = IO.pipe
+
+ thread = Thread.new do
+ r.read
+ end
+
+ Thread.pass until thread.status == "sleep"
+
+ pid = fork do
+ r.close
+ end
+
+ w.close
+
+ status = Process.wait2(pid).last
+ thread.join
+
+ assert_predicate(status, :success?)
+ RUBY
+ end
end
diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb
index 55296c1f23..b6372f25b8 100644
--- a/test/ruby/test_io_buffer.rb
+++ b/test/ruby/test_io_buffer.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: false
require 'tempfile'
+require 'rbconfig/sizeof'
class TestIOBuffer < Test::Unit::TestCase
experimental = Warning[:experimental]
@@ -45,22 +46,22 @@ class TestIOBuffer < Test::Unit::TestCase
def test_new_internal
buffer = IO::Buffer.new(1024, IO::Buffer::INTERNAL)
assert_equal 1024, buffer.size
- refute buffer.external?
- assert buffer.internal?
- refute buffer.mapped?
+ refute_predicate buffer, :external?
+ assert_predicate buffer, :internal?
+ refute_predicate buffer, :mapped?
end
def test_new_mapped
buffer = IO::Buffer.new(1024, IO::Buffer::MAPPED)
assert_equal 1024, buffer.size
- refute buffer.external?
- refute buffer.internal?
- assert buffer.mapped?
+ refute_predicate buffer, :external?
+ refute_predicate buffer, :internal?
+ assert_predicate buffer, :mapped?
end
def test_new_readonly
buffer = IO::Buffer.new(128, IO::Buffer::INTERNAL|IO::Buffer::READONLY)
- assert buffer.readonly?
+ assert_predicate buffer, :readonly?
assert_raise IO::Buffer::AccessError do
buffer.set_string("")
@@ -73,12 +74,64 @@ class TestIOBuffer < Test::Unit::TestCase
def test_file_mapped
buffer = File.open(__FILE__) {|file| IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)}
- contents = buffer.get_string
+ assert_equal File.size(__FILE__), buffer.size
+ contents = buffer.get_string
assert_include contents, "Hello World"
assert_equal Encoding::BINARY, contents.encoding
end
+ def test_file_mapped_with_size
+ buffer = File.open(__FILE__) {|file| IO::Buffer.map(file, 30, 0, IO::Buffer::READONLY)}
+ assert_equal 30, buffer.size
+
+ contents = buffer.get_string
+ assert_equal "# frozen_string_literal: false", contents
+ assert_equal Encoding::BINARY, contents.encoding
+ end
+
+ def test_file_mapped_size_too_large
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, 200_000, 0, IO::Buffer::READONLY)}
+ end
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, File.size(__FILE__) + 1, 0, IO::Buffer::READONLY)}
+ end
+ end
+
+ def test_file_mapped_size_just_enough
+ File.open(__FILE__) {|file|
+ assert_equal File.size(__FILE__), IO::Buffer.map(file, File.size(__FILE__), 0, IO::Buffer::READONLY).size
+ }
+ end
+
+ def test_file_mapped_offset_too_large
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, nil, IO::Buffer::PAGE_SIZE * 100, IO::Buffer::READONLY)}
+ end
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, 20, IO::Buffer::PAGE_SIZE * 100, IO::Buffer::READONLY)}
+ end
+ end
+
+ def test_file_mapped_zero_size
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, 0, 0, IO::Buffer::READONLY)}
+ end
+ end
+
+ def test_file_mapped_negative_size
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, -10, 0, IO::Buffer::READONLY)}
+ end
+ end
+
+ def test_file_mapped_negative_offset
+ assert_raise ArgumentError do
+ File.open(__FILE__) {|file| IO::Buffer.map(file, 20, -1, IO::Buffer::READONLY)}
+ end
+ end
+
def test_file_mapped_invalid
assert_raise TypeError do
IO::Buffer.map("foobar")
@@ -88,19 +141,19 @@ class TestIOBuffer < Test::Unit::TestCase
def test_string_mapped
string = "Hello World"
buffer = IO::Buffer.for(string)
- assert buffer.readonly?
+ assert_predicate buffer, :readonly?
end
def test_string_mapped_frozen
string = "Hello World".freeze
buffer = IO::Buffer.for(string)
- assert buffer.readonly?
+ assert_predicate buffer, :readonly?
end
def test_string_mapped_mutable
string = "Hello World"
IO::Buffer.for(string) do |buffer|
- refute buffer.readonly?
+ refute_predicate buffer, :readonly?
buffer.set_value(:U8, 0, "h".ord)
@@ -121,6 +174,16 @@ class TestIOBuffer < Test::Unit::TestCase
end
end
+ def test_string_mapped_buffer_frozen
+ string = "Hello World".freeze
+ IO::Buffer.for(string) do |buffer|
+ assert_raise IO::Buffer::AccessError, "Buffer is not writable!" do
+ buffer.set_string("abc")
+ end
+ assert_equal "H".ord, buffer.get_value(:U8, 0)
+ end
+ end
+
def test_non_string
not_string = Object.new
@@ -343,10 +406,17 @@ class TestIOBuffer < Test::Unit::TestCase
:u64 => [0, 2**64-1],
:s64 => [-2**63, 0, 2**63-1],
+ :U128 => [0, 2**64, 2**127-1, 2**128-1],
+ :S128 => [-2**127, -2**63-1, -1, 0, 2**63, 2**127-1],
+ :u128 => [0, 2**64, 2**127-1, 2**128-1],
+ :s128 => [-2**127, -2**63-1, -1, 0, 2**63, 2**127-1],
+
:F32 => [-1.0, 0.0, 0.5, 1.0, 128.0],
:F64 => [-1.0, 0.0, 0.5, 1.0, 128.0],
}
+ SIZE_MAX = RbConfig::LIMITS["SIZE_MAX"]
+
def test_get_set_value
buffer = IO::Buffer.new(128)
@@ -355,6 +425,16 @@ class TestIOBuffer < Test::Unit::TestCase
buffer.set_value(data_type, 0, value)
assert_equal value, buffer.get_value(data_type, 0), "Converting #{value} as #{data_type}."
end
+ assert_raise(ArgumentError) {buffer.get_value(data_type, 128)}
+ assert_raise(ArgumentError) {buffer.set_value(data_type, 128, 0)}
+ case data_type
+ when :U8, :S8
+ else
+ assert_raise(ArgumentError) {buffer.get_value(data_type, 127)}
+ assert_raise(ArgumentError) {buffer.set_value(data_type, 127, 0)}
+ assert_raise(ArgumentError) {buffer.get_value(data_type, SIZE_MAX)}
+ assert_raise(ArgumentError) {buffer.set_value(data_type, SIZE_MAX, 0)}
+ end
end
end
@@ -411,6 +491,15 @@ class TestIOBuffer < Test::Unit::TestCase
buffer = IO::Buffer.for(string)
assert_equal string.bytes, buffer.each_byte.to_a
+ assert_equal string.bytes[3, 5], buffer.each_byte(3, 5).to_a
+ end
+
+ def test_each_byte_bounds_error
+ buffer = IO::Buffer.for("A")
+
+ assert_raise(ArgumentError) { buffer.each_byte(0, 2).to_a }
+ assert_raise(ArgumentError) { buffer.each_byte(1, 1).to_a }
+ assert_raise(ArgumentError) { buffer.each_byte(SIZE_MAX, 0).to_a }
end
def test_zero_length_each_byte
@@ -421,7 +510,21 @@ class TestIOBuffer < Test::Unit::TestCase
def test_clear
buffer = IO::Buffer.new(16)
- buffer.set_string("Hello World!")
+ assert_equal "\0" * 16, buffer.get_string
+ buffer.clear(1)
+ assert_equal "\1" * 16, buffer.get_string
+ buffer.clear(2, 1, 2)
+ assert_equal "\1" + "\2"*2 + "\1"*13, buffer.get_string
+ buffer.clear(2, 1)
+ assert_equal "\1" + "\2"*15, buffer.get_string
+ buffer.clear(260)
+ assert_equal "\4" * 16, buffer.get_string
+ assert_raise(TypeError) {buffer.clear("x")}
+
+ assert_raise(ArgumentError) {buffer.clear(0, 20)}
+ assert_raise(ArgumentError) {buffer.clear(0, 0, 20)}
+ assert_raise(ArgumentError) {buffer.clear(0, 10, 10)}
+ assert_raise(ArgumentError) {buffer.clear(0, SIZE_MAX-7, 10)}
end
def test_invalidation
@@ -599,6 +702,59 @@ class TestIOBuffer < Test::Unit::TestCase
assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), source.dup.not!
end
+ def test_operators_raise_on_freed_self
+ inner = IO::Buffer.new(IO::Buffer::PAGE_SIZE)
+ slice = inner.slice(0, 8)
+ inner.free
+
+ mask = IO::Buffer.for("ABCDEFGH")
+ assert_raise(IO::Buffer::InvalidatedError) { slice & mask }
+ assert_raise(IO::Buffer::InvalidatedError) { slice | mask }
+ assert_raise(IO::Buffer::InvalidatedError) { slice ^ mask }
+ assert_raise(IO::Buffer::InvalidatedError) { ~slice }
+ end
+
+ def test_operators_raise_on_freed_mask
+ inner = IO::Buffer.new(IO::Buffer::PAGE_SIZE)
+ mask_slice = inner.slice(0, 8)
+ inner.free
+
+ source = IO::Buffer.for("ABCDEFGH")
+ assert_raise(IO::Buffer::InvalidatedError) { source & mask_slice }
+ assert_raise(IO::Buffer::InvalidatedError) { source | mask_slice }
+ assert_raise(IO::Buffer::InvalidatedError) { source ^ mask_slice }
+ end
+
+ def test_bit_count
+ # All ones: 8 bits set per byte
+ assert_equal 8, IO::Buffer.for("\xFF").bit_count
+ # All zeros: no bits set
+ assert_equal 0, IO::Buffer.for("\x00").bit_count
+ # Mixed: 0xFF (8) + 0x00 (0) + 0x0F (4) = 12
+ assert_equal 12, IO::Buffer.for("\xFF\x00\x0F").bit_count
+ # Subrange: offset=0, length=1 => 0xFF => 8
+ assert_equal 8, IO::Buffer.for("\xFF\x00\x0F").bit_count(0, 1)
+ # Subrange: offset=1, length=1 => 0x00 => 0
+ assert_equal 0, IO::Buffer.for("\xFF\x00\x0F").bit_count(1, 1)
+ # Subrange: offset=2, length=1 => 0x0F => 4
+ assert_equal 4, IO::Buffer.for("\xFF\x00\x0F").bit_count(2, 1)
+ # Subrange: offset=1, length=2 => 0x00 + 0x0F = 4
+ assert_equal 4, IO::Buffer.for("\xFF\x00\x0F").bit_count(1, 2)
+ # Empty buffer: 0
+ assert_equal 0, IO::Buffer.new(0).bit_count
+ # 8-byte aligned: 8 bytes of 0xFF => 64 bits
+ assert_equal 64, IO::Buffer.for("\xFF" * 8).bit_count
+ # Cross 8-byte boundary: 9 bytes of 0xFF => 72 bits
+ assert_equal 72, IO::Buffer.for("\xFF" * 9).bit_count
+ # offset=0 with no length => defaults to full buffer:
+ assert_equal 12, IO::Buffer.for("\xFF\x00\x0F").bit_count(0)
+ # offset=1 with no length => 0x00 + 0x0F = 4:
+ assert_equal 4, IO::Buffer.for("\xFF\x00\x0F").bit_count(1)
+ # Out-of-range raises
+ assert_raise(ArgumentError) { IO::Buffer.for("\xFF").bit_count(0, 2) }
+ assert_raise(ArgumentError) { IO::Buffer.for("\xFF").bit_count(1, 1) }
+ end
+
def test_shared
message = "Hello World"
buffer = IO::Buffer.new(64, IO::Buffer::MAPPED | IO::Buffer::SHARED)
@@ -620,8 +776,8 @@ class TestIOBuffer < Test::Unit::TestCase
buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
begin
- assert buffer.private?
- refute buffer.readonly?
+ assert_predicate buffer, :private?
+ refute_predicate buffer, :readonly?
buffer.set_string("J")
@@ -683,4 +839,230 @@ class TestIOBuffer < Test::Unit::TestCase
buf.set_string('a', 0, 0)
assert_predicate buf, :empty?
end
+
+ # https://bugs.ruby-lang.org/issues/21210
+ def test_bug_21210
+ omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
+
+ str = +"hello"
+ buf = IO::Buffer.for(str)
+ assert_predicate buf, :valid?
+
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
+
+ assert_predicate buf, :valid?
+ end
+
+ def test_128_bit_integers
+ buffer = IO::Buffer.new(32)
+
+ # Test unsigned 128-bit integers
+ test_values_u128 = [
+ 0,
+ 1,
+ 2**64 - 1,
+ 2**64,
+ 2**127 - 1,
+ 2**128 - 1,
+ ]
+
+ test_values_u128.each do |value|
+ buffer.set_value(:u128, 0, value)
+ assert_equal value, buffer.get_value(:u128, 0), "u128: #{value}"
+
+ buffer.set_value(:U128, 0, value)
+ assert_equal value, buffer.get_value(:U128, 0), "U128: #{value}"
+ end
+
+ # Test signed 128-bit integers
+ test_values_s128 = [
+ -2**127,
+ -2**63 - 1,
+ -1,
+ 0,
+ 1,
+ 2**63,
+ 2**127 - 1,
+ ]
+
+ test_values_s128.each do |value|
+ buffer.set_value(:s128, 0, value)
+ assert_equal value, buffer.get_value(:s128, 0), "s128: #{value}"
+
+ buffer.set_value(:S128, 0, value)
+ assert_equal value, buffer.get_value(:S128, 0), "S128: #{value}"
+ end
+
+ # Test size_of
+ assert_equal 16, IO::Buffer.size_of(:u128)
+ assert_equal 16, IO::Buffer.size_of(:U128)
+ assert_equal 16, IO::Buffer.size_of(:s128)
+ assert_equal 16, IO::Buffer.size_of(:S128)
+ assert_equal 32, IO::Buffer.size_of([:u128, :u128])
+ end
+
+ def test_integer_endianness_swapping
+ # Test that byte order is swapped correctly for all signed and unsigned integers > 1 byte
+ host_is_le = IO::Buffer::HOST_ENDIAN == IO::Buffer::LITTLE_ENDIAN
+ host_is_be = IO::Buffer::HOST_ENDIAN == IO::Buffer::BIG_ENDIAN
+
+ # Test values that will produce different byte patterns when swapped
+ # Format: [little_endian_type, big_endian_type, test_value, expected_swapped_value]
+ # expected_swapped_value is the result when writing as le_type and reading as be_type
+ # (or vice versa) on a little-endian host
+ test_cases = [
+ [:u16, :U16, 0x1234, 0x3412],
+ [:s16, :S16, 0x1234, 0x3412],
+ [:u32, :U32, 0x12345678, 0x78563412],
+ [:s32, :S32, 0x12345678, 0x78563412],
+ [:u64, :U64, 0x0123456789ABCDEF, 0xEFCDAB8967452301],
+ [:s64, :S64, 0x0123456789ABCDEF, -1167088121787636991],
+ [:u128, :U128, 0x0123456789ABCDEF0123456789ABCDEF, 0xEFCDAB8967452301EFCDAB8967452301],
+ [:u128, :U128, 0x0123456789ABCDEFFEDCBA9876543210, 0x1032547698BADCFEEFCDAB8967452301],
+ [:u128, :U128, 0xFEDCBA98765432100123456789ABCDEF, 0xEFCDAB89674523011032547698BADCFE],
+ [:u128, :U128, 0x123456789ABCDEF0FEDCBA9876543210, 0x1032547698BADCFEF0DEBC9A78563412],
+ [:s128, :S128, 0x0123456789ABCDEF0123456789ABCDEF, -21528975894082904073953971026863512831],
+ [:s128, :S128, 0x0123456789ABCDEFFEDCBA9876543210, 0x1032547698BADCFEEFCDAB8967452301],
+ ]
+
+ test_cases.each do |le_type, be_type, value, expected_swapped|
+ buffer_size = IO::Buffer.size_of(le_type)
+ buffer = IO::Buffer.new(buffer_size * 2)
+
+ # Test little-endian round-trip
+ buffer.set_value(le_type, 0, value)
+ result_le = buffer.get_value(le_type, 0)
+ assert_equal value, result_le, "#{le_type}: round-trip failed"
+
+ # Test big-endian round-trip
+ buffer.set_value(be_type, buffer_size, value)
+ result_be = buffer.get_value(be_type, buffer_size)
+ assert_equal value, result_be, "#{be_type}: round-trip failed"
+
+ # Verify byte patterns are different when endianness differs from host
+ if host_is_le
+ # On little-endian host: le_type should match host, be_type should be swapped
+ # So the byte patterns should be different (unless value is symmetric)
+ # Read back with opposite endianness to verify swapping
+ result_le_read_as_be = buffer.get_value(be_type, 0)
+ result_be_read_as_le = buffer.get_value(le_type, buffer_size)
+
+ # The swapped reads should NOT equal the original value (unless it's symmetric)
+ # For most values, this will be different
+ if value != 0 && value != -1 && value.abs != 1
+ refute_equal value, result_le_read_as_be, "#{le_type} written, read as #{be_type} should be swapped on LE host"
+ refute_equal value, result_be_read_as_le, "#{be_type} written, read as #{le_type} should be swapped on LE host"
+ end
+
+ # Verify that reading back with correct endianness works
+ assert_equal value, buffer.get_value(le_type, 0), "#{le_type} should read correctly on LE host"
+ assert_equal value, buffer.get_value(be_type, buffer_size), "#{be_type} should read correctly on LE host (with swapping)"
+ elsif host_is_be
+ # On big-endian host: be_type should match host, le_type should be swapped
+ result_le_read_as_be = buffer.get_value(be_type, 0)
+ result_be_read_as_le = buffer.get_value(le_type, buffer_size)
+
+ # The swapped reads should NOT equal the original value (unless it's symmetric)
+ if value != 0 && value != -1 && value.abs != 1
+ refute_equal value, result_le_read_as_be, "#{le_type} written, read as #{be_type} should be swapped on BE host"
+ refute_equal value, result_be_read_as_le, "#{be_type} written, read as #{le_type} should be swapped on BE host"
+ end
+
+ # Verify that reading back with correct endianness works
+ assert_equal value, buffer.get_value(be_type, buffer_size), "#{be_type} should read correctly on BE host"
+ assert_equal value, buffer.get_value(le_type, 0), "#{le_type} should read correctly on BE host (with swapping)"
+ end
+
+ # Verify that when we write with one endianness and read with the opposite,
+ # we get the expected swapped value
+ buffer.set_value(le_type, 0, value)
+ swapped_value_le_to_be = buffer.get_value(be_type, 0)
+ assert_equal expected_swapped, swapped_value_le_to_be, "#{le_type} written, read as #{be_type} should produce expected swapped value"
+
+ # Also verify the reverse direction
+ buffer.set_value(be_type, buffer_size, value)
+ swapped_value_be_to_le = buffer.get_value(le_type, buffer_size)
+ assert_equal expected_swapped, swapped_value_be_to_le, "#{be_type} written, read as #{le_type} should produce expected swapped value"
+
+ # Verify that writing the swapped value back and reading with original endianness
+ # gives us the original value (double-swap should restore original)
+ buffer.set_value(be_type, 0, swapped_value_le_to_be)
+ round_trip_value = buffer.get_value(le_type, 0)
+ assert_equal value, round_trip_value, "#{le_type}/#{be_type}: double-swap should restore original value"
+ end
+ end
+
+ class Bug21882 < RuntimeError; end
+ def test_locked_exception
+ buf = IO::Buffer.new(10)
+ assert_raise(Bug21882, '#locked should propagate exception') do
+ buf.locked { raise Bug21882 }
+ end
+
+ # should be unlocked now and can be locked again
+ refute_predicate buf, :locked?
+ buf.locked { }
+ end
+
+ def test_locked_break
+ buf = IO::Buffer.new(10)
+ assert_equal :ok, (buf.locked { break :ok })
+
+ # should be unlocked now and can be locked again
+ refute_predicate buf, :locked?
+ buf.locked { }
+ end
+
+ def test_locked_throw
+ buf = IO::Buffer.new(10)
+ assert_equal :ok, (catch(:bug21882) { buf.locked { throw :bug21882, :ok } })
+
+ # should be unlocked now and can be locked again
+ refute_predicate buf, :locked?
+ buf.locked { }
+ end
+
+ def test_hexdump_default_width
+ buffer = IO::Buffer.for("Hello World")
+ hexdump = buffer.hexdump
+ assert_include hexdump, "Hello World"
+ assert_include hexdump, "0x00000000"
+ end
+
+ def test_hexdump_custom_width
+ buffer = IO::Buffer.for("A" * 64)
+ hexdump = buffer.hexdump(0, 64, 32)
+ assert_include hexdump, "0x00000000"
+ assert_include hexdump, "0x00000020"
+ end
+
+ def test_hexdump_maximum_width
+ buffer = IO::Buffer.for("A" * 2048)
+ # Maximum width is 1024
+ hexdump = buffer.hexdump(0, 1024, 1024)
+ assert_include hexdump, "0x00000000"
+ end
+
+ def test_hexdump_width_too_large
+ buffer = IO::Buffer.for("A")
+ # Width exceeding maximum (1024) should raise ArgumentError
+ assert_raise(ArgumentError) do
+ buffer.hexdump(0, 1, 1025)
+ end
+ end
+
+ def test_hexdump_width_negative
+ buffer = IO::Buffer.for("A")
+ assert_raise(ArgumentError) do
+ buffer.hexdump(0, 1, -1)
+ end
+ end
+
+ def test_hexdump_width_zero
+ buffer = IO::Buffer.for("A")
+ # Width must be at least 1
+ assert_raise(ArgumentError) do
+ buffer.hexdump(0, 1, 0)
+ end
+ end
end
diff --git a/test/ruby/test_io_m17n.rb b/test/ruby/test_io_m17n.rb
index b01d627d92..83d4fb0c7b 100644
--- a/test/ruby/test_io_m17n.rb
+++ b/test/ruby/test_io_m17n.rb
@@ -1395,30 +1395,6 @@ EOT
}
end
- def test_open_pipe_r_enc
- EnvUtil.suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- open("|#{EnvUtil.rubybin} -e 'putc 255'", "r:ascii-8bit") {|f|
- assert_equal(Encoding::ASCII_8BIT, f.external_encoding)
- assert_equal(nil, f.internal_encoding)
- s = f.read
- assert_equal(Encoding::ASCII_8BIT, s.encoding)
- assert_equal("\xff".force_encoding("ascii-8bit"), s)
- }
- end
- end
-
- def test_open_pipe_r_enc2
- EnvUtil.suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- open("|#{EnvUtil.rubybin} -e 'putc \"\\u3042\"'", "r:UTF-8") {|f|
- assert_equal(Encoding::UTF_8, f.external_encoding)
- assert_equal(nil, f.internal_encoding)
- s = f.read
- assert_equal(Encoding::UTF_8, s.encoding)
- assert_equal("\u3042", s)
- }
- end
- end
-
def test_s_foreach_enc
with_tmpdir {
generate_file("t", "\xff")
@@ -2748,8 +2724,8 @@ EOT
def test_pos_with_buffer_end_cr
bug6401 = '[ruby-core:44874]'
with_tmpdir {
- # Read buffer size is 8191. This generates '\r' at 8191.
- lines = ["X" * 8187, "X"]
+ # Read buffer size is 8192. This generates '\r' at 8192.
+ lines = ["X" * 8188, "X"]
generate_file("tmp", lines.join("\r\n") + "\r\n")
open("tmp", "r") do |f|
@@ -2830,4 +2806,17 @@ EOT
flunk failure.join("\n---\n")
end
end
+
+ def test_each_codepoint_encoding_with_ungetc
+ File.open(File::NULL, "rt:utf-8") do |f|
+ f.ungetc(%Q[\u{3042}\u{3044}\u{3046}])
+ assert_equal [0x3042, 0x3044, 0x3046], f.each_codepoint.to_a
+ end
+ File.open(File::NULL, "rt:us-ascii") do |f|
+ f.ungetc(%Q[\u{3042}\u{3044}\u{3046}])
+ assert_raise(ArgumentError) do
+ f.each_codepoint.to_a
+ end
+ end
+ end
end
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 032f78f6a8..b4760dc412 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -92,7 +92,7 @@ class TestISeq < Test::Unit::TestCase
42
end
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_forwardable
@@ -102,7 +102,7 @@ class TestISeq < Test::Unit::TestCase
def foo(...); bar(...); end
}
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval.new.foo(40, 2))
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval.new.foo(40, 2))
end
def test_super_with_block
@@ -112,7 +112,7 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_super_with_block_hash_0
@@ -123,7 +123,7 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_super_with_block_and_kwrest
@@ -133,17 +133,16 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_lambda_with_ractor_roundtrip
iseq = compile(<<~EOF, __LINE__+1)
x = 42
- y = nil.instance_eval{ lambda { x } }
- Ractor.make_shareable(y)
+ y = Ractor.shareable_lambda{x}
y.call
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_super_with_anonymous_block
@@ -153,27 +152,23 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_ractor_unshareable_outer_variable
name = "\u{2603 26a1}"
- y = nil.instance_eval do
- eval("proc {#{name} = nil; proc {|x| #{name} = x}}").call
+ assert_raise_with_message(Ractor::IsolationError, /\(#{name}\)/) do
+ eval("#{name} = nil; Ractor.shareable_proc{#{name} = nil}")
end
- assert_raise_with_message(ArgumentError, /\(#{name}\)/) do
- Ractor.make_shareable(y)
- end
- y = nil.instance_eval do
- eval("proc {#{name} = []; proc {|x| #{name}}}").call
- end
- assert_raise_with_message(Ractor::IsolationError, /'#{name}'/) do
- Ractor.make_shareable(y)
+
+ assert_raise_with_message(Ractor::IsolationError, /\'#{name}\'/) do
+ eval("#{name} = []; Ractor.shareable_proc{#{name}}")
end
+
obj = Object.new
- def obj.foo(*) nil.instance_eval{ ->{super} } end
- assert_raise_with_message(Ractor::IsolationError, /refer unshareable object \[\] from variable '\*'/) do
- Ractor.make_shareable(obj.foo(*[]))
+ def obj.foo(*) Ractor.shareable_proc{super} end
+ assert_raise_with_message(Ractor::IsolationError, /cannot make a shareable Proc because it can refer unshareable object \[\]/) do
+ obj.foo(*[])
end
end
@@ -182,7 +177,7 @@ class TestISeq < Test::Unit::TestCase
# shareable_constant_value: literal
REGEX = /#{}/ # [Bug #20569]
RUBY
- assert_includes iseq.to_binary, "REGEX".b
+ assert_includes iseq_to_binary(iseq), "REGEX".b
end
def test_disasm_encoding
@@ -217,6 +212,26 @@ class TestISeq < Test::Unit::TestCase
end
end
+ def test_compile_file_options
+ Tempfile.create(%w"test_iseq .rb") do |f|
+ f.puts('_ = "test"')
+ f.close
+ iseq = RubyVM::InstructionSequence.compile_file(f.path, { frozen_string_literal: false })
+ refute_predicate iseq.eval, :frozen?
+
+ iseq = RubyVM::InstructionSequence.compile_file(f.path, { frozen_string_literal: true })
+ assert_predicate iseq.eval, :frozen?
+ end
+ end
+
+ def test_compile_options
+ iseq = RubyVM::InstructionSequence.compile("'test'", nil, nil, nil, { frozen_string_literal: false })
+ refute_predicate iseq.eval, :frozen?
+
+ iseq = RubyVM::InstructionSequence.compile("'test'", nil, nil, nil, { frozen_string_literal: true })
+ assert_predicate iseq.eval, :frozen?
+ end
+
LINE_BEFORE_METHOD = __LINE__
def method_test_line_trace
@@ -297,6 +312,56 @@ class TestISeq < Test::Unit::TestCase
assert_raise(TypeError, bug11159) {compile(1)}
end
+ def test_invalid_source_no_memory_leak
+ # [Bug #21394]
+ assert_no_memory_leak(["-rtempfile"], "#{<<-"begin;"}", "#{<<-'end;'}", rss: true)
+ code = proc do |t|
+ RubyVM::InstructionSequence.new(nil)
+ rescue TypeError
+ else
+ raise "TypeError was not raised during RubyVM::InstructionSequence.new"
+ end
+
+ 10.times(&code)
+ begin;
+ 1_000_000.times(&code)
+ end;
+
+ # [Bug #21394]
+ # RubyVM::InstructionSequence.new calls rb_io_path, which dups the string
+ # and can leak memory if the dup raises
+ assert_no_memory_leak(["-rtempfile"], "#{<<-"begin;"}", "#{<<-'end;'}", rss: true)
+ MyError = Class.new(StandardError)
+ String.prepend(Module.new do
+ def initialize_dup(_)
+ if $raise_on_dup
+ raise MyError
+ else
+ super
+ end
+ end
+ end)
+
+ code = proc do |t|
+ Tempfile.create do |f|
+ $raise_on_dup = true
+ t.times do
+ RubyVM::InstructionSequence.new(f)
+ rescue MyError
+ else
+ raise "MyError was not raised during RubyVM::InstructionSequence.new"
+ end
+ ensure
+ $raise_on_dup = false
+ end
+ end
+
+ code.call(100)
+ begin;
+ code.call(1_000_000)
+ end;
+ end
+
def test_frozen_string_literal_compile_option
$f = 'f'
line = __LINE__ + 2
@@ -310,6 +375,20 @@ class TestISeq < Test::Unit::TestCase
assert_not_predicate(s4, :frozen?)
end
+ def test_frozen_string_literal_compile_option_file
+ Tempfile.create(%w[fsl .rb]) do |f|
+ f.write("['foo', 'foo', \"\#{$f}foo\", \"\#{'foo'}\"]\n")
+ f.flush
+ $f = 'f'
+ s1, s2, s3, s4 = RubyVM::InstructionSequence
+ .compile_file(f.path, frozen_string_literal: true).eval
+ assert_predicate(s1, :frozen?)
+ assert_predicate(s2, :frozen?)
+ assert_not_predicate(s3, :frozen?)
+ assert_not_predicate(s4, :frozen?)
+ end
+ end
+
# Safe call chain is not optimized when Coverage is running.
# So we can test it only when Coverage is not running.
def test_safe_call_chain
@@ -566,16 +645,20 @@ class TestISeq < Test::Unit::TestCase
}
end
+ def iseq_to_binary(iseq)
+ iseq.to_binary
+ rescue RuntimeError => e
+ omit e.message if /compile with coverage/ =~ e.message
+ raise
+ end
+
def assert_iseq_to_binary(code, mesg = nil)
iseq = RubyVM::InstructionSequence.compile(code)
bin = assert_nothing_raised(mesg) do
- iseq.to_binary
- rescue RuntimeError => e
- omit e.message if /compile with coverage/ =~ e.message
- raise
+ iseq_to_binary(iseq)
end
10.times do
- bin2 = iseq.to_binary
+ bin2 = iseq_to_binary(iseq)
assert_equal(bin, bin2, message(mesg) {diff hexdump(bin), hexdump(bin2)})
end
iseq2 = RubyVM::InstructionSequence.load_from_binary(bin)
@@ -593,7 +676,7 @@ class TestISeq < Test::Unit::TestCase
def test_to_binary_with_hidden_local_variables
assert_iseq_to_binary("for _foo in bar; end")
- bin = RubyVM::InstructionSequence.compile(<<-RUBY).to_binary
+ bin = iseq_to_binary(RubyVM::InstructionSequence.compile(<<-RUBY))
Object.new.instance_eval do
a = []
def self.bar; [1] end
@@ -633,6 +716,17 @@ class TestISeq < Test::Unit::TestCase
assert_equal([[:nokey]], iseq.eval.singleton_method(:foo).parameters)
end
+ def test_to_binary_dumps_noblock
+ iseq = assert_iseq_to_binary(<<-RUBY)
+ o = Object.new
+ class << o
+ def foo(&nil); end
+ end
+ o
+ RUBY
+ assert_equal([[:noblock]], iseq.eval.singleton_method(:foo).parameters)
+ end
+
def test_to_binary_line_info
assert_iseq_to_binary("#{<<~"begin;"}\n#{<<~'end;'}", '[Bug #14660]').eval
begin;
@@ -668,7 +762,7 @@ class TestISeq < Test::Unit::TestCase
end
RUBY
- iseq_bin = iseq.to_binary
+ iseq_bin = iseq_to_binary(iseq)
iseq = ISeq.load_from_binary(iseq_bin)
lines = []
TracePoint.new(tracepoint_type){|tp|
@@ -764,7 +858,7 @@ class TestISeq < Test::Unit::TestCase
def test_iseq_builtin_load
Tempfile.create(["builtin", ".iseq"]) do |f|
f.binmode
- f.write(RubyVM::InstructionSequence.of(1.method(:abs)).to_binary)
+ f.write(iseq_to_binary(RubyVM::InstructionSequence.of(1.method(:abs))))
f.close
assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
@@ -804,7 +898,7 @@ class TestISeq < Test::Unit::TestCase
GC.start
Float(30)
}
- assert_equal :new, r.take
+ assert_equal :new, r.value
RUBY
end
@@ -812,6 +906,10 @@ class TestISeq < Test::Unit::TestCase
assert_ruby_status([], "BEGIN {exit}; while true && true; end")
end
+ def test_short_circuited_loop_condition
+ assert_ruby_status([], "while true || true; exit; end; abort")
+ end
+
def test_unreachable_syntax_error
mesg = /Invalid break/
assert_syntax_error("false and break", mesg)
@@ -855,9 +953,28 @@ class TestISeq < Test::Unit::TestCase
end
end
+ def test_serialize_anonymous_outer_variables
+ iseq = RubyVM::InstructionSequence.compile(<<~'RUBY')
+ obj = Object.new
+ def obj.test
+ [1].each do
+ raise "Oops"
+ rescue
+ return it
+ end
+ end
+ obj
+ RUBY
+
+ binary = iseq.to_binary # [Bug # 21370]
+ roundtripped_iseq = RubyVM::InstructionSequence.load_from_binary(binary)
+ object = roundtripped_iseq.eval
+ assert_equal 1, object.test
+ end
+
def test_loading_kwargs_memory_leak
assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~'end;'}", rss: true)
- a = RubyVM::InstructionSequence.compile("foo(bar: :baz)").to_binary
+ a = RubyVM::InstructionSequence.compile("foo(bar: :baz)").to_binary
begin;
1_000_000.times do
RubyVM::InstructionSequence.load_from_binary(a)
@@ -868,7 +985,7 @@ class TestISeq < Test::Unit::TestCase
def test_ibf_bignum
iseq = RubyVM::InstructionSequence.compile("0x0"+"_0123_4567_89ab_cdef"*5)
expected = iseq.eval
- result = RubyVM::InstructionSequence.load_from_binary(iseq.to_binary).eval
+ result = RubyVM::InstructionSequence.load_from_binary(iseq_to_binary(iseq)).eval
assert_equal expected, result, proc {sprintf("expected: %x, result: %x", expected, result)}
end
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index 4563308fa2..c836abd0c6 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -2424,6 +2424,21 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_raise(ArgumentError) { m.call(42, a: 1, **h2) }
end
+ def test_ruby2_keywords_post_arg
+ def self.a(*c, **kw) [c, kw] end
+ def self.b(*a, b) a(*a, b) end
+ assert_warn(/Skipping set of ruby2_keywords flag for b \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
+ assert_nil(singleton_class.send(:ruby2_keywords, :b))
+ end
+ assert_equal([[{foo: 1}, {bar: 1}], {}], b({foo: 1}, bar: 1))
+
+ b = ->(*a, b){a(*a, b)}
+ assert_warn(/Skipping set of ruby2_keywords flag for proc \(proc accepts keywords or post arguments or proc does not accept argument splat\)/) do
+ b.ruby2_keywords
+ end
+ assert_equal([[{foo: 1}, {bar: 1}], {}], b.({foo: 1}, bar: 1))
+ end
+
def test_proc_ruby2_keywords
h1 = {:a=>1}
foo = ->(*args, &block){block.call(*args)}
@@ -2436,8 +2451,8 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_raise(ArgumentError) { foo.call(:a=>1, &->(arg, **kw){[arg, kw]}) }
assert_equal(h1, foo.call(:a=>1, &->(arg){arg}))
- [->(){}, ->(arg){}, ->(*args, **kw){}, ->(*args, k: 1){}, ->(*args, k: ){}].each do |pr|
- assert_warn(/Skipping set of ruby2_keywords flag for proc \(proc accepts keywords or proc does not accept argument splat\)/) do
+ [->(){}, ->(arg){}, ->(*args, x){}, ->(*args, **kw){}, ->(*args, k: 1){}, ->(*args, k: ){}].each do |pr|
+ assert_warn(/Skipping set of ruby2_keywords flag for proc \(proc accepts keywords or post arguments or proc does not accept argument splat\)/) do
pr.ruby2_keywords
end
end
@@ -2790,10 +2805,21 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal(:opt, o.clear_last_opt(a: 1))
assert_nothing_raised(ArgumentError) { o.clear_last_empty_method(a: 1) }
- assert_warn(/Skipping set of ruby2_keywords flag for bar \(method accepts keywords or method does not accept argument splat\)/) do
+ assert_warn(/Skipping set of ruby2_keywords flag for bar \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
assert_nil(c.send(:ruby2_keywords, :bar))
end
+ c.class_eval do
+ def bar_post(*a, x) = nil
+ define_method(:bar_post_bmethod) { |*a, x| }
+ end
+ assert_warn(/Skipping set of ruby2_keywords flag for bar_post \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
+ assert_nil(c.send(:ruby2_keywords, :bar_post))
+ end
+ assert_warn(/Skipping set of ruby2_keywords flag for bar_post_bmethod \(method accepts keywords or post arguments or method does not accept argument splat\)/) do
+ assert_nil(c.send(:ruby2_keywords, :bar_post_bmethod))
+ end
+
utf16_sym = "abcdef".encode("UTF-16LE").to_sym
c.send(:define_method, utf16_sym, c.instance_method(:itself))
assert_warn(/abcdef/) do
@@ -4033,7 +4059,7 @@ class TestKeywordArguments < Test::Unit::TestCase
tap { m }
GC.start
tap { m }
- }, bug8964
+ }, bug8964, timeout: 30
assert_normal_exit %q{
prc = Proc.new {|a: []|}
GC.stress = true
diff --git a/test/ruby/test_lambda.rb b/test/ruby/test_lambda.rb
index 3cbb54306c..ce0f338760 100644
--- a/test/ruby/test_lambda.rb
+++ b/test/ruby/test_lambda.rb
@@ -163,7 +163,7 @@ class TestLambdaParameters < Test::Unit::TestCase
end
def test_proc_inside_lambda_toplevel
- assert_separately [], <<~RUBY
+ assert_ruby_status [], <<~RUBY
lambda{
$g = proc{ return :pr }
}.call
@@ -276,27 +276,27 @@ class TestLambdaParameters < Test::Unit::TestCase
end
def test_do_lambda_source_location
- exp = [__LINE__ + 1, 12, __LINE__ + 5, 7]
+ exp_lineno = __LINE__ + 3
lmd = ->(x,
y,
z) do
#
end
- file, *loc = lmd.source_location
+ file, lineno = lmd.source_location
assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
- assert_equal(exp, loc)
+ assert_equal(exp_lineno, lineno, "must be at the beginning of the block")
end
def test_brace_lambda_source_location
- exp = [__LINE__ + 1, 12, __LINE__ + 5, 5]
+ exp_lineno = __LINE__ + 3
lmd = ->(x,
y,
z) {
#
}
- file, *loc = lmd.source_location
+ file, lineno = lmd.source_location
assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
- assert_equal(exp, loc)
+ assert_equal(exp_lineno, lineno, "must be at the beginning of the block")
end
def test_not_orphan_return
diff --git a/test/ruby/test_lazy_enumerator.rb b/test/ruby/test_lazy_enumerator.rb
index 4dddbab50c..3652096237 100644
--- a/test/ruby/test_lazy_enumerator.rb
+++ b/test/ruby/test_lazy_enumerator.rb
@@ -608,7 +608,7 @@ EOS
end
def test_require_block
- %i[select reject drop_while take_while map flat_map].each do |method|
+ %i[select reject drop_while take_while map flat_map tap_each].each do |method|
assert_raise(ArgumentError){ [].lazy.send(method) }
end
end
@@ -715,4 +715,23 @@ EOS
def test_with_index_size
assert_equal(3, Enumerator::Lazy.new([1, 2, 3], 3){|y, v| y << v}.with_index.size)
end
+
+ def test_tap_each
+ out = []
+
+ e = (1..Float::INFINITY).lazy
+ .tap_each { |x| out << x }
+ .select(&:even?)
+ .first(5)
+
+ assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], out)
+ assert_equal([2, 4, 6, 8, 10], e)
+ end
+
+ def test_tap_each_is_not_intrusive
+ s = Step.new(1..3)
+
+ assert_equal(2, s.lazy.tap_each { |x| x }.map { |x| x * 2 }.first)
+ assert_equal(1, s.current)
+ end
end
diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb
index dbff3c4734..cff888d4b3 100644
--- a/test/ruby/test_literal.rb
+++ b/test/ruby/test_literal.rb
@@ -682,6 +682,11 @@ class TestRubyLiteral < Test::Unit::TestCase
$VERBOSE = verbose_bak
end
+ def test_rational_float
+ assert_equal(12, 0.12r * 100)
+ assert_equal(12, 0.1_2r * 100)
+ end
+
def test_symbol_list
assert_equal([:foo, :bar], %i[foo bar])
assert_equal([:"\"foo"], %i["foo])
diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb
index b0e2e9f849..9f7a3c7f4b 100644
--- a/test/ruby/test_m17n.rb
+++ b/test/ruby/test_m17n.rb
@@ -186,33 +186,35 @@ class TestM17N < Test::Unit::TestCase
end
def test_string_inspect_encoding
- EnvUtil.suppress_warning do
- begin
- orig_int = Encoding.default_internal
- orig_ext = Encoding.default_external
- Encoding.default_internal = nil
- [Encoding::UTF_8, Encoding::EUC_JP, Encoding::Windows_31J, Encoding::GB18030].
- each do |e|
- Encoding.default_external = e
- str = "\x81\x30\x81\x30".force_encoding('GB18030')
- assert_equal(Encoding::GB18030 == e ? %{"#{str}"} : '"\x{81308130}"', str.inspect)
- str = e("\xa1\x8f\xa1\xa1")
- expected = "\"\\xA1\x8F\xA1\xA1\"".force_encoding("EUC-JP")
- assert_equal(Encoding::EUC_JP == e ? expected : "\"\\xA1\\x{8FA1A1}\"", str.inspect)
- str = s("\x81@")
- assert_equal(Encoding::Windows_31J == e ? %{"#{str}"} : '"\x{8140}"', str.inspect)
- str = "\u3042\u{10FFFD}"
- assert_equal(Encoding::UTF_8 == e ? %{"#{str}"} : '"\u3042\u{10FFFD}"', str.inspect)
- end
- Encoding.default_external = Encoding::UTF_8
- [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE,
- Encoding::UTF8_SOFTBANK].each do |e|
- str = "abc".encode(e)
- assert_equal('"abc"', str.inspect)
- end
- ensure
- Encoding.default_internal = orig_int
- Encoding.default_external = orig_ext
+ [
+ Encoding::UTF_8,
+ Encoding::EUC_JP,
+ Encoding::Windows_31J,
+ Encoding::GB18030,
+ ].each do |e|
+ EnvUtil.with_default_external(e) do
+ str = "\x81\x30\x81\x30".force_encoding('GB18030')
+ assert_equal(Encoding::GB18030 == e ? %{"#{str}"} : '"\x{81308130}"', str.inspect)
+ str = e("\xa1\x8f\xa1\xa1")
+ expected = "\"\\xA1\x8F\xA1\xA1\"".force_encoding("EUC-JP")
+ assert_equal(Encoding::EUC_JP == e ? expected : "\"\\xA1\\x{8FA1A1}\"", str.inspect)
+ str = s("\x81@")
+ assert_equal(Encoding::Windows_31J == e ? %{"#{str}"} : '"\x{8140}"', str.inspect)
+ str = "\u3042\u{10FFFD}"
+ assert_equal(Encoding::UTF_8 == e ? %{"#{str}"} : '"\u3042\u{10FFFD}"', str.inspect)
+ end
+ end
+
+ EnvUtil.with_default_external(Encoding::UTF_8) do
+ [
+ Encoding::UTF_16BE,
+ Encoding::UTF_16LE,
+ Encoding::UTF_32BE,
+ Encoding::UTF_32LE,
+ Encoding::UTF8_SOFTBANK
+ ].each do |e|
+ str = "abc".encode(e)
+ assert_equal('"abc"', str.inspect)
end
end
end
@@ -246,59 +248,43 @@ class TestM17N < Test::Unit::TestCase
end
def test_object_utf16_32_inspect
- EnvUtil.suppress_warning do
- begin
- orig_int = Encoding.default_internal
- orig_ext = Encoding.default_external
- Encoding.default_internal = nil
- Encoding.default_external = Encoding::UTF_8
- o = Object.new
- [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e|
- o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end"
- assert_equal '[abc]', [o].inspect
- end
- ensure
- Encoding.default_internal = orig_int
- Encoding.default_external = orig_ext
+ EnvUtil.with_default_external(Encoding::UTF_8) do
+ o = Object.new
+ [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e|
+ o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end"
+ assert_equal '[abc]', [o].inspect
end
end
end
def test_object_inspect_external
- orig_v, $VERBOSE = $VERBOSE, false
- orig_int, Encoding.default_internal = Encoding.default_internal, nil
- orig_ext = Encoding.default_external
-
omit "https://bugs.ruby-lang.org/issues/18338"
o = Object.new
- Encoding.default_external = Encoding::UTF_16BE
- def o.inspect
- "abc"
- end
- assert_nothing_raised(Encoding::CompatibilityError) { [o].inspect }
+ EnvUtil.with_default_external(Encoding::UTF_16BE) do
+ def o.inspect
+ "abc"
+ end
+ assert_nothing_raised(Encoding::CompatibilityError) { [o].inspect }
- def o.inspect
- "abc".encode(Encoding.default_external)
+ def o.inspect
+ "abc".encode(Encoding.default_external)
+ end
+ assert_equal '[abc]', [o].inspect
end
- assert_equal '[abc]', [o].inspect
-
- Encoding.default_external = Encoding::US_ASCII
- def o.inspect
- "\u3042"
- end
- assert_equal '[\u3042]', [o].inspect
+ EnvUtil.with_default_external(Encoding::US_ASCII) do
+ def o.inspect
+ "\u3042"
+ end
+ assert_equal '[\u3042]', [o].inspect
- def o.inspect
- "\x82\xa0".force_encoding(Encoding::Windows_31J)
+ def o.inspect
+ "\x82\xa0".force_encoding(Encoding::Windows_31J)
+ end
+ assert_equal '[\x{82A0}]', [o].inspect
end
- assert_equal '[\x{82A0}]', [o].inspect
- ensure
- Encoding.default_internal = orig_int
- Encoding.default_external = orig_ext
- $VERBOSE = orig_v
end
def test_str_dump
diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb
index e4f6e5e91a..48a67e1dc5 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -268,7 +268,11 @@ class TestMarshal < Test::Unit::TestCase
classISO8859_1.name
ClassISO8859_1 = classISO8859_1
- def test_class_nonascii
+ moduleUTF8 = const_set("C\u{30af 30e9 30b9}", Module.new)
+ moduleUTF8.name
+ ModuleUTF8 = moduleUTF8
+
+ def test_nonascii_class_instance
a = ClassUTF8.new
assert_instance_of(ClassUTF8, Marshal.load(Marshal.dump(a)), '[ruby-core:24790]')
@@ -301,10 +305,16 @@ class TestMarshal < Test::Unit::TestCase
end
end
+ def test_nonascii_class_module
+ assert_same(ClassUTF8, Marshal.load(Marshal.dump(ClassUTF8)))
+ assert_same(ClassISO8859_1, Marshal.load(Marshal.dump(ClassISO8859_1)))
+ assert_same(ModuleUTF8, Marshal.load(Marshal.dump(ModuleUTF8)))
+ end
+
def test_regexp2
assert_equal(/\\u/, Marshal.load("\004\b/\b\\\\u\000"))
assert_equal(/u/, Marshal.load("\004\b/\a\\u\000"))
- assert_equal(/u/, Marshal.load("\004\bI/\a\\u\000\006:\016@encoding\"\vEUC-JP"))
+ assert_raise(FrozenError) { Marshal.load("\x04\bI/\x06u\x00\a:\x06EF:\t@fooi/") }
bug2109 = '[ruby-core:25625]'
a = "\x82\xa0".force_encoding(Encoding::Windows_31J)
@@ -459,6 +469,30 @@ class TestMarshal < Test::Unit::TestCase
assert_equal(o1.foo, o2.foo)
end
+ class TooComplex
+ def initialize
+ @marshal_complex = 1
+ end
+ end
+
+ def test_complex_shape_object_id_not_dumped
+ if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
+ assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
+ end
+ 8.times do |i|
+ TooComplex.new.instance_variable_set("@TestObjectIdTooComplex#{i}", 1)
+ end
+ obj = TooComplex.new
+ ivar = "@a#{rand(10_000).to_s.rjust(5, '0')}"
+ obj.instance_variable_set(ivar, 1)
+
+ if defined?(RubyVM::Shape)
+ assert_predicate(RubyVM::Shape.of(obj), :complex?)
+ end
+ obj.object_id
+ assert_equal "\x04\bo:\x1CTestMarshal::TooComplex\a:\x15@marshal_complexi\x06:\f#{ivar}i\x06".b, Marshal.dump(obj)
+ end
+
def test_marshal_complex
assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\x05")}
assert_raise(ArgumentError){Marshal.load("\x04\bU:\fComplex[\x06i\x00")}
@@ -678,7 +712,6 @@ class TestMarshal < Test::Unit::TestCase
def test_recursive_userdef
t = Time.utc(0)
- str = "b".b
t.instance_eval {@v = t}
assert_raise_with_message(RuntimeError, /recursive\b.*\b_dump/) do
Marshal.dump(t)
@@ -826,17 +859,15 @@ class TestMarshal < Test::Unit::TestCase
def test_marshal_dump_adding_instance_variable
obj = Bug15968.new
- assert_raise_with_message(RuntimeError, /instance variable added/) do
- Marshal.dump(obj)
- end
+ loaded = Marshal.load(Marshal.dump(obj))
+ assert_nil loaded.baz
end
def test_marshal_dump_removing_instance_variable
obj = Bug15968.new
obj.baz = :Bug15968
- assert_raise_with_message(RuntimeError, /instance variable removed/) do
- Marshal.dump(obj)
- end
+ loaded = Marshal.load(Marshal.dump(obj))
+ assert_equal :Bug15968, loaded.baz
end
ruby2_keywords def ruby2_keywords_hash(*a)
@@ -902,6 +933,41 @@ class TestMarshal < Test::Unit::TestCase
end
end
+ def test_load_overread
+ input = Struct.new(:bytes, :used) do
+ def initialize
+ super("\x04\x08[\x07".bytes, false)
+ end
+
+ def getbyte
+ bytes.shift
+ end
+
+ def read(_len, _outbuf = nil)
+ return nil if used
+ self.used = true
+ "0" * (1024 * 128)
+ end
+ end.new
+
+ assert_equal([nil, nil], Marshal.load(input))
+ end
+
+ def test_bignum_len_overflow
+ assert_raise(ArgumentError) do
+ Marshal.load("\x04\x08l+\x04\x00\x00\x00\x40")
+ end
+ assert_raise(ArgumentError) do
+ Marshal.load("\x04\x08l+\xfc\x00\x00\x00\x80")
+ end
+ end
+
+ def test_bignum_invalid_sign
+ assert_raise(ArgumentError) do
+ Marshal.load("\x04\bl?")
+ end
+ end
+
class TestMarshalFreezeProc < Test::Unit::TestCase
include MarshalTestLib
@@ -955,7 +1021,7 @@ class TestMarshal < Test::Unit::TestCase
end
def test_proc_returned_object_are_not_frozen
- source = ["foo", {}, /foo/, 1..2]
+ source = ["foo", {}, 1..2]
objects = Marshal.load(encode(source), ->(o) { o.dup }, freeze: true)
assert_equal source, objects
refute_predicate objects, :frozen?
@@ -969,5 +1035,19 @@ class TestMarshal < Test::Unit::TestCase
refute_predicate Object, :frozen?
refute_predicate Kernel, :frozen?
end
+
+ def test_linked_strings_are_frozen
+ str = "test"
+ str.instance_variable_set(:@self, str)
+ source = [str, str]
+
+ objects = Marshal.load(encode(source), freeze: true)
+ assert_predicate objects[0], :frozen?
+ assert_predicate objects[1], :frozen?
+ assert_same objects[0], objects[1]
+ assert_same objects[0], objects[0].instance_variable_get(:@self)
+ assert_same objects[1], objects[1].instance_variable_get(:@self)
+ assert_same objects[0].instance_variable_get(:@self), objects[1].instance_variable_get(:@self)
+ end
end
end
diff --git a/test/ruby/test_math.rb b/test/ruby/test_math.rb
index 6e67099c6b..e134600cc4 100644
--- a/test/ruby/test_math.rb
+++ b/test/ruby/test_math.rb
@@ -147,6 +147,13 @@ class TestMath < Test::Unit::TestCase
check(Math::E ** 2, Math.exp(2))
end
+ def test_expm1
+ check(0, Math.expm1(0))
+ check(Math.sqrt(Math::E) - 1, Math.expm1(0.5))
+ check(Math::E - 1, Math.expm1(1))
+ check(Math::E ** 2 - 1, Math.expm1(2))
+ end
+
def test_log
check(0, Math.log(1))
check(1, Math.log(Math::E))
@@ -201,6 +208,19 @@ class TestMath < Test::Unit::TestCase
assert_nothing_raised { assert_infinity(-Math.log10(0)) }
end
+ def test_log1p
+ check(0, Math.log1p(0))
+ check(1, Math.log1p(Math::E - 1))
+ check(Math.log(2.0 ** 64 + 1), Math.log1p(1 << 64))
+ check(Math.log(2) * 1024.0, Math.log1p(2 ** 1024))
+ assert_nothing_raised { assert_infinity(Math.log1p(1.0/0)) }
+ assert_nothing_raised { assert_infinity(-Math.log1p(-1.0)) }
+ assert_raise_with_message(Math::DomainError, /\blog1p\b/) { Math.log1p(-1.1) }
+ assert_raise_with_message(Math::DomainError, /\blog1p\b/) { Math.log1p(-Float::EPSILON-1) }
+ assert_nothing_raised { assert_nan(Math.log1p(Float::NAN)) }
+ assert_nothing_raised { assert_infinity(-Math.log1p(-1)) }
+ end
+
def test_sqrt
check(0, Math.sqrt(0))
check(1, Math.sqrt(1))
@@ -301,11 +321,21 @@ class TestMath < Test::Unit::TestCase
assert_float_and_int([Math.log(6), 1], Math.lgamma(4))
assert_raise_with_message(Math::DomainError, /\blgamma\b/) { Math.lgamma(-Float::INFINITY) }
+
+ x, sign = Math.lgamma(+0.0)
+ mesg = "Math.lgamma(+0.0) should be [INF, +1]"
+ assert_infinity(x, mesg)
+ assert_equal(+1, sign, mesg)
+
x, sign = Math.lgamma(-0.0)
mesg = "Math.lgamma(-0.0) should be [INF, -1]"
assert_infinity(x, mesg)
assert_equal(-1, sign, mesg)
- x, sign = Math.lgamma(Float::NAN)
+
+ x, = Math.lgamma(-1)
+ assert_infinity(x, "Math.lgamma(-1) should be +INF")
+
+ x, = Math.lgamma(Float::NAN)
assert_nan(x)
end
diff --git a/test/ruby/test_memory_view.rb b/test/ruby/test_memory_view.rb
index 5a39084d18..d0122ddd59 100644
--- a/test/ruby/test_memory_view.rb
+++ b/test/ruby/test_memory_view.rb
@@ -335,7 +335,7 @@ class TestMemoryView < Test::Unit::TestCase
p mv[[0, 2]]
mv[[1, 3]]
end
- p r.take
+ p r.value
end;
end
end
diff --git a/test/ruby/test_metaclass.rb b/test/ruby/test_metaclass.rb
index 8c1990a78c..6570fa5945 100644
--- a/test/ruby/test_metaclass.rb
+++ b/test/ruby/test_metaclass.rb
@@ -163,6 +163,6 @@ class TestMetaclass < Test::Unit::TestCase
assert_nothing_raised{ metametaclass_of_bar.metaclass_method_c }
assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_o }
assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_f }
- assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b }
+ assert_raise(NoMethodError){ metametaclass_of_bar.metametaclass_method_b }
end
end
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index a865f6100b..00512bf2c6 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -32,6 +32,7 @@ class TestMethod < Test::Unit::TestCase
def mk7(a, b = nil, *c, d, **o) nil && o end
def mk8(a, b = nil, *c, d, e:, f: nil, **o) nil && o end
def mnk(**nil) end
+ def mnb(&nil) end
def mf(...) end
class Base
@@ -111,6 +112,20 @@ class TestMethod < Test::Unit::TestCase
end
end
+ def test_unbound_method_equality_with_extended_module
+ m = Module.new { def hello; "hello"; end }
+ base = Class.new { extend m }
+ sub = Class.new(base)
+
+ from_module = m.instance_method(:hello)
+ from_base = base.method(:hello).unbind
+ from_sub = sub.method(:hello).unbind
+
+ assert_equal(from_module, from_base)
+ assert_equal(from_module, from_sub)
+ assert_equal(from_base, from_sub)
+ end
+
def test_callee
assert_equal(:test_callee, __method__)
assert_equal(:m, Class.new {def m; __method__; end}.new.m)
@@ -284,8 +299,10 @@ class TestMethod < Test::Unit::TestCase
assert_raise(TypeError) { m.bind(Object.new) }
cx = EnvUtil.labeled_class("X\u{1f431}")
- assert_raise_with_message(TypeError, /X\u{1f431}/) do
- o.method(cx)
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{1f431}/) do
+ o.method(cx)
+ end
end
end
@@ -315,9 +332,12 @@ class TestMethod < Test::Unit::TestCase
assert_raise(TypeError) do
Class.new.class_eval { define_method(:bar, o.method(:bar)) }
end
+
cx = EnvUtil.labeled_class("X\u{1f431}")
- assert_raise_with_message(TypeError, /X\u{1F431}/) do
- Class.new {define_method(cx) {}}
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{1F431}/) do
+ Class.new {define_method(cx) {}}
+ end
end
end
@@ -483,6 +503,20 @@ class TestMethod < Test::Unit::TestCase
end
end
+ def test_clone_preserves_singleton_methods
+ m = method(:itself)
+ m.define_singleton_method(:foo) { :bar }
+ assert_equal(:bar, m.foo)
+ assert_equal(:bar, m.clone.foo)
+ end
+
+ def test_dup_does_not_preserve_singleton_methods
+ m = method(:itself)
+ m.define_singleton_method(:foo) { :bar }
+ assert_equal(:bar, m.foo)
+ assert_raise(NoMethodError) { m.dup.foo }
+ end
+
def test_inspect
o = Object.new
def o.foo; end; line_no = __LINE__
@@ -598,6 +632,7 @@ class TestMethod < Test::Unit::TestCase
define_method(:pmk7) {|a, b = nil, *c, d, **o|}
define_method(:pmk8) {|a, b = nil, *c, d, e:, f: nil, **o|}
define_method(:pmnk) {|**nil|}
+ define_method(:pmnb) {|&nil|}
def test_bound_parameters
assert_equal([], method(:m0).parameters)
@@ -621,6 +656,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:mk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:mk8).parameters)
assert_equal([[:nokey]], method(:mnk).parameters)
+ assert_equal([[:noblock]], method(:mnb).parameters)
# pending
assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], method(:mf).parameters)
end
@@ -647,6 +683,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:mk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:mk8).parameters)
assert_equal([[:nokey]], self.class.instance_method(:mnk).parameters)
+ assert_equal([[:noblock]], self.class.instance_method(:mnb).parameters)
# pending
assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], self.class.instance_method(:mf).parameters)
end
@@ -672,6 +709,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:pmk8).parameters)
assert_equal([[:nokey]], method(:pmnk).parameters)
+ assert_equal([[:noblock]], method(:pmnb).parameters)
end
def test_bmethod_unbound_parameters
@@ -696,6 +734,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:pmk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:pmk8).parameters)
assert_equal([[:nokey]], self.class.instance_method(:pmnk).parameters)
+ assert_equal([[:noblock]], self.class.instance_method(:pmnb).parameters)
end
def test_hidden_parameters
@@ -1612,7 +1651,7 @@ class TestMethod < Test::Unit::TestCase
begin
foo(1)
rescue ArgumentError => e
- assert_equal "main.rb:#{$line_method}:in 'foo'", e.backtrace.first
+ assert_equal "main.rb:#{$line_method}:in 'Object#foo'", e.backtrace.first
end
EOS
END_OF_BODY
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index 9a21113fe0..ad83d09823 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -9,18 +9,18 @@ class TestModule < Test::Unit::TestCase
yield
end
- def assert_method_defined?(klass, mid, message="")
+ def assert_method_defined?(klass, (mid, *args), message="")
message = build_message(message, "#{klass}\##{mid} expected to be defined.")
_wrap_assertion do
- klass.method_defined?(mid) or
+ klass.method_defined?(mid, *args) or
raise Test::Unit::AssertionFailedError, message, caller(3)
end
end
- def assert_method_not_defined?(klass, mid, message="")
+ def assert_method_not_defined?(klass, (mid, *args), message="")
message = build_message(message, "#{klass}\##{mid} expected to not be defined.")
_wrap_assertion do
- klass.method_defined?(mid) and
+ klass.method_defined?(mid, *args) and
raise Test::Unit::AssertionFailedError, message, caller(3)
end
end
@@ -412,19 +412,6 @@ class TestModule < Test::Unit::TestCase
assert_equal([:MIXIN, :USER], User.constants.sort)
end
- def test_initialize_copy
- mod = Module.new { define_method(:foo) {:first} }
- klass = Class.new { include mod }
- instance = klass.new
- assert_equal(:first, instance.foo)
- new_mod = Module.new { define_method(:foo) { :second } }
- assert_raise(TypeError) do
- mod.send(:initialize_copy, new_mod)
- end
- 4.times { GC.start }
- assert_equal(:first, instance.foo) # [BUG] unreachable
- end
-
def test_initialize_copy_empty
m = Module.new do
def x
@@ -435,11 +422,6 @@ class TestModule < Test::Unit::TestCase
assert_equal([:x], m.instance_methods)
assert_equal([:@x], m.instance_variables)
assert_equal([:X], m.constants)
- assert_raise(TypeError) do
- m.module_eval do
- initialize_copy(Module.new)
- end
- end
m = Class.new(Module) do
def initialize_copy(other)
@@ -601,7 +583,7 @@ class TestModule < Test::Unit::TestCase
end
def test_gc_prepend_chain
- assert_separately([], <<-EOS)
+ assert_ruby_status([], <<-EOS)
10000.times { |i|
m1 = Module.new do
def foo; end
@@ -831,40 +813,40 @@ class TestModule < Test::Unit::TestCase
def test_method_defined?
[User, Class.new{include User}, Class.new{prepend User}].each do |klass|
[[], [true]].each do |args|
- assert !klass.method_defined?(:wombat, *args)
- assert klass.method_defined?(:mixin, *args)
- assert klass.method_defined?(:user, *args)
- assert klass.method_defined?(:user2, *args)
- assert !klass.method_defined?(:user3, *args)
+ assert_method_not_defined?(klass, [:wombat, *args])
+ assert_method_defined?(klass, [:mixin, *args])
+ assert_method_defined?(klass, [:user, *args])
+ assert_method_defined?(klass, [:user2, *args])
+ assert_method_not_defined?(klass, [:user3, *args])
- assert !klass.method_defined?("wombat", *args)
- assert klass.method_defined?("mixin", *args)
- assert klass.method_defined?("user", *args)
- assert klass.method_defined?("user2", *args)
- assert !klass.method_defined?("user3", *args)
+ assert_method_not_defined?(klass, ["wombat", *args])
+ assert_method_defined?(klass, ["mixin", *args])
+ assert_method_defined?(klass, ["user", *args])
+ assert_method_defined?(klass, ["user2", *args])
+ assert_method_not_defined?(klass, ["user3", *args])
end
end
end
def test_method_defined_without_include_super
- assert User.method_defined?(:user, false)
- assert !User.method_defined?(:mixin, false)
- assert Mixin.method_defined?(:mixin, false)
+ assert_method_defined?(User, [:user, false])
+ assert_method_not_defined?(User, [:mixin, false])
+ assert_method_defined?(Mixin, [:mixin, false])
User.const_set(:FOO, c = Class.new)
c.prepend(User)
- assert !c.method_defined?(:user, false)
+ assert_method_not_defined?(c, [:user, false])
c.define_method(:user){}
- assert c.method_defined?(:user, false)
+ assert_method_defined?(c, [:user, false])
- assert !c.method_defined?(:mixin, false)
+ assert_method_not_defined?(c, [:mixin, false])
c.define_method(:mixin){}
- assert c.method_defined?(:mixin, false)
+ assert_method_defined?(c, [:mixin, false])
- assert !c.method_defined?(:userx, false)
+ assert_method_not_defined?(c, [:userx, false])
c.define_method(:userx){}
- assert c.method_defined?(:userx, false)
+ assert_method_defined?(c, [:userx, false])
# cleanup
User.class_eval do
@@ -1291,8 +1273,11 @@ class TestModule < Test::Unit::TestCase
assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16le"), :foo) }
assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32be"), :foo) }
assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32le"), :foo) }
+
cx = EnvUtil.labeled_class("X\u{3042}")
- assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :foo) }
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :foo) }
+ end
end
def test_const_get_invalid_name
@@ -1449,6 +1434,7 @@ class TestModule < Test::Unit::TestCase
c.instance_eval { attr_reader :"." }
end
+ c = Class.new
assert_equal([:a], c.class_eval { attr :a })
assert_equal([:b, :c], c.class_eval { attr :b, :c })
assert_equal([:d], c.class_eval { attr_reader :d })
@@ -1457,6 +1443,16 @@ class TestModule < Test::Unit::TestCase
assert_equal([:h=, :i=], c.class_eval { attr_writer :h, :i })
assert_equal([:j, :j=], c.class_eval { attr_accessor :j })
assert_equal([:k, :k=, :l, :l=], c.class_eval { attr_accessor :k, :l })
+
+ c = Class.new
+ assert_equal([:a], c.class_eval { attr "a" })
+ assert_equal([:b, :c], c.class_eval { attr "b", "c" })
+ assert_equal([:d], c.class_eval { attr_reader "d" })
+ assert_equal([:e, :f], c.class_eval { attr_reader "e", "f" })
+ assert_equal([:g=], c.class_eval { attr_writer "g" })
+ assert_equal([:h=, :i=], c.class_eval { attr_writer "h", "i" })
+ assert_equal([:j, :j=], c.class_eval { attr_accessor "j" })
+ assert_equal([:k, :k=, :l, :l=], c.class_eval { attr_accessor "k", "l" })
end
def test_alias_method
@@ -2826,7 +2822,7 @@ class TestModule < Test::Unit::TestCase
b = a.dup
b.new.a = 'B'
- assert_equal 'A', a.new.a, '[ruby-core:17019]'
+ assert_equal 'B', a.new.a, '[ruby-core:17019] behaviour changed: cvar resolves through original CREF'
end
Bug6891 = '[ruby-core:47241]'
@@ -3020,17 +3016,17 @@ class TestModule < Test::Unit::TestCase
bug11532 = '[ruby-core:70828] [Bug #11532]'
c = Class.new {const_set(:A, 1)}.freeze
- assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
+ assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {private_constant :A}
}
c = Class.new {const_set(:A, 1); private_constant :A}.freeze
- assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
+ assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {public_constant :A}
}
c = Class.new {const_set(:A, 1)}.freeze
- assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
+ assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {deprecate_constant :A}
}
end
@@ -3077,7 +3073,7 @@ class TestModule < Test::Unit::TestCase
end
def test_prepend_gc
- assert_separately [], %{
+ assert_ruby_status [], %{
module Foo
end
class Object
@@ -3269,15 +3265,18 @@ class TestModule < Test::Unit::TestCase
end
module CloneTestM0
+ TEST = :M0
def foo; TEST; end
end
CloneTestM1 = CloneTestM0.clone
CloneTestM2 = CloneTestM0.clone
module CloneTestM1
+ remove_const :TEST
TEST = :M1
end
module CloneTestM2
+ remove_const :TEST
TEST = :M2
end
class CloneTestC1
@@ -3292,8 +3291,8 @@ class TestModule < Test::Unit::TestCase
assert_equal 1, m::C, '[ruby-core:47834]'
assert_equal 1, m.m, '[ruby-core:47834]'
- assert_equal :M1, CloneTestC1.new.foo, '[Bug #15877]'
- assert_equal :M2, CloneTestC2.new.foo, '[Bug #15877]'
+ assert_equal :M0, CloneTestC1.new.foo, 'originally [Bug #15877], but behaviour changed'
+ assert_equal :M0, CloneTestC2.new.foo, 'originally [Bug #15877], but behaviour changed'
end
def test_clone_freeze
@@ -3371,11 +3370,11 @@ class TestModule < Test::Unit::TestCase
m.const_set(:N, Module.new)
assert_match(/\A#<Module:0x\h+>::N\z/, m::N.name)
- m::N.set_temporary_name(name = "fake_name_under_M")
+ assert_same m::N, m::N.set_temporary_name(name = "fake_name_under_M")
name.upcase!
assert_equal("fake_name_under_M", m::N.name)
assert_raise(FrozenError) {m::N.name.upcase!}
- m::N.set_temporary_name(nil)
+ assert_same m::N, m::N.set_temporary_name(nil)
assert_nil(m::N.name)
m::N.const_set(:O, Module.new)
@@ -3383,14 +3382,14 @@ class TestModule < Test::Unit::TestCase
m::N.const_set(:Recursive, m)
m.const_set(:A, 42)
- m.set_temporary_name(name = "fake_name")
+ assert_same m, m.set_temporary_name(name = "fake_name")
name.upcase!
assert_equal("fake_name", m.name)
assert_raise(FrozenError) {m.name.upcase!}
assert_equal("fake_name::N", m::N.name)
assert_equal("fake_name::N::O", m::N::O.name)
- m.set_temporary_name(nil)
+ assert_same m, m.set_temporary_name(nil)
assert_nil m.name
assert_nil m::N.name
assert_nil m::N::O.name
diff --git a/test/ruby/test_nomethod_error.rb b/test/ruby/test_nomethod_error.rb
index 6d413e6391..6abd20cc81 100644
--- a/test/ruby/test_nomethod_error.rb
+++ b/test/ruby/test_nomethod_error.rb
@@ -78,7 +78,7 @@ class TestNoMethodError < Test::Unit::TestCase
assert_equal :foo, error.name
assert_equal [1, 2], error.args
assert_equal receiver, error.receiver
- assert error.private_call?, "private_call? was false."
+ assert_predicate error, :private_call?
end
def test_message_encoding
@@ -106,4 +106,32 @@ class TestNoMethodError < Test::Unit::TestCase
assert_match(/undefined method.+this_method_does_not_exist.+for.+Module/, err.to_s)
end
+
+ def test_send_forward_raises
+ t = EnvUtil.labeled_class("Test") do
+ def foo(...)
+ forward(...)
+ end
+ end
+ obj = t.new
+ assert_raise(NoMethodError) do
+ obj.foo
+ end
+ end
+
+ # [Bug #21535]
+ def test_send_forward_raises_when_called_through_vcall
+ t = EnvUtil.labeled_class("Test") do
+ def foo(...)
+ forward(...)
+ end
+ def foo_indirect
+ foo # vcall
+ end
+ end
+ obj = t.new
+ assert_raise(NoMethodError) do
+ obj.foo_indirect
+ end
+ end
end
diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb
index ab492743f6..b272b89921 100644
--- a/test/ruby/test_numeric.rb
+++ b/test/ruby/test_numeric.rb
@@ -18,18 +18,24 @@ class TestNumeric < Test::Unit::TestCase
assert_raise_with_message(TypeError, /can't be coerced into /) {1|:foo}
assert_raise_with_message(TypeError, /can't be coerced into /) {1^:foo}
- assert_raise_with_message(TypeError, /:\u{3042}/) {1+:"\u{3042}"}
- assert_raise_with_message(TypeError, /:\u{3042}/) {1&:"\u{3042}"}
- assert_raise_with_message(TypeError, /:\u{3042}/) {1|:"\u{3042}"}
- assert_raise_with_message(TypeError, /:\u{3042}/) {1^:"\u{3042}"}
- assert_raise_with_message(TypeError, /:"\\u3042"/) {1+:"\u{3042}"}
- assert_raise_with_message(TypeError, /:"\\u3042"/) {1&:"\u{3042}"}
- assert_raise_with_message(TypeError, /:"\\u3042"/) {1|:"\u{3042}"}
- assert_raise_with_message(TypeError, /:"\\u3042"/) {1^:"\u{3042}"}
- assert_raise_with_message(TypeError, /:\u{3044}/) {1+"\u{3044}".to_sym}
- assert_raise_with_message(TypeError, /:\u{3044}/) {1&"\u{3044}".to_sym}
- assert_raise_with_message(TypeError, /:\u{3044}/) {1|"\u{3044}".to_sym}
- assert_raise_with_message(TypeError, /:\u{3044}/) {1^"\u{3044}".to_sym}
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1+:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1&:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1|:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:\u{3042}/) {1^:"\u{3042}"}
+
+ assert_raise_with_message(TypeError, /:\u{3044}/) {1+"\u{3044}".to_sym}
+ assert_raise_with_message(TypeError, /:\u{3044}/) {1&"\u{3044}".to_sym}
+ assert_raise_with_message(TypeError, /:\u{3044}/) {1|"\u{3044}".to_sym}
+ assert_raise_with_message(TypeError, /:\u{3044}/) {1^"\u{3044}".to_sym}
+ end
+
+ EnvUtil.with_default_internal(Encoding::US_ASCII) do
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1+:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1&:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1|:"\u{3042}"}
+ assert_raise_with_message(TypeError, /:"\\u3042"/) {1^:"\u{3042}"}
+ end
bug10711 = '[ruby-core:67405] [Bug #10711]'
exp = "1.2 can't be coerced into Integer"
@@ -200,14 +206,6 @@ class TestNumeric < Test::Unit::TestCase
assert_nil(a <=> :foo)
end
- def test_float_round_ndigits
- bug14635 = "[ruby-core:86323]"
- f = 0.5
- 31.times do |i|
- assert_equal(0.5, f.round(i+1), bug14635 + " (argument: #{i+1})")
- end
- end
-
def test_floor_ceil_round_truncate
a = Class.new(Numeric) do
def to_f; 1.5; end
@@ -483,6 +481,10 @@ class TestNumeric < Test::Unit::TestCase
assert_equal(0, 0.pow(3, 1))
assert_equal(0, 2.pow(3, 1))
assert_equal(0, -2.pow(3, 1))
+
+ min, max = RbConfig::LIMITS.values_at("FIXNUM_MIN", "FIXNUM_MAX")
+ assert_equal(0, 0.pow(2, min))
+ assert_equal(0, Integer.sqrt(max+1).pow(2, min))
end
end
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb
index 7d00422629..53ae4fb110 100644
--- a/test/ruby/test_object.rb
+++ b/test/ruby/test_object.rb
@@ -280,6 +280,12 @@ class TestObject < Test::Unit::TestCase
assert_equal([:foo], k.private_methods(false))
end
+ class ToStrCounter
+ def initialize(str = "@foo") @str = str; @count = 0; end
+ def to_str; @count += 1; @str; end
+ def count; @count; end
+ end
+
def test_instance_variable_get
o = Object.new
o.instance_eval { @foo = :foo }
@@ -291,9 +297,7 @@ class TestObject < Test::Unit::TestCase
assert_raise(NameError) { o.instance_variable_get("bar") }
assert_raise(TypeError) { o.instance_variable_get(1) }
- n = Object.new
- def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end
- def n.count; @count; end
+ n = ToStrCounter.new
assert_equal(:foo, o.instance_variable_get(n))
assert_equal(1, n.count)
end
@@ -308,9 +312,7 @@ class TestObject < Test::Unit::TestCase
assert_raise(NameError) { o.instance_variable_set("bar", 1) }
assert_raise(TypeError) { o.instance_variable_set(1, 1) }
- n = Object.new
- def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end
- def n.count; @count; end
+ n = ToStrCounter.new
o.instance_variable_set(n, :bar)
assert_equal(:bar, o.instance_eval { @foo })
assert_equal(1, n.count)
@@ -327,9 +329,7 @@ class TestObject < Test::Unit::TestCase
assert_raise(NameError) { o.instance_variable_defined?("bar") }
assert_raise(TypeError) { o.instance_variable_defined?(1) }
- n = Object.new
- def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end
- def n.count; @count; end
+ n = ToStrCounter.new
assert_equal(true, o.instance_variable_defined?(n))
assert_equal(1, n.count)
end
@@ -356,38 +356,43 @@ class TestObject < Test::Unit::TestCase
end
def test_remove_instance_variable_re_embed
- require "objspace"
-
- c = Class.new do
- def a = @a
-
- def b = @b
-
- def c = @c
- end
-
- o1 = c.new
- o2 = c.new
-
- o1.instance_variable_set(:@foo, 5)
- o1.instance_variable_set(:@a, 0)
- o1.instance_variable_set(:@b, 1)
- o1.instance_variable_set(:@c, 2)
- refute_includes ObjectSpace.dump(o1), '"embedded":true'
- o1.remove_instance_variable(:@foo)
- assert_includes ObjectSpace.dump(o1), '"embedded":true'
-
- o2.instance_variable_set(:@a, 0)
- o2.instance_variable_set(:@b, 1)
- o2.instance_variable_set(:@c, 2)
- assert_includes ObjectSpace.dump(o2), '"embedded":true'
-
- assert_equal(0, o1.a)
- assert_equal(1, o1.b)
- assert_equal(2, o1.c)
- assert_equal(0, o2.a)
- assert_equal(1, o2.b)
- assert_equal(2, o2.c)
+ assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ # Determine the RVALUE pool's embed capacity from GC constants.
+ rvalue_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
+ rbasic_size = GC::INTERNAL_CONSTANTS[:RBASIC_SIZE]
+ embed_cap = (rvalue_size - rbasic_size) / RbConfig::SIZEOF["void*"]
+
+ # Build a class whose initialize sets embed_cap ivars so objects
+ # are allocated in the RVALUE pool with embedded storage.
+ init_body = embed_cap.times.map { |i| "@v#{i} = nil" }.join("; ")
+ c = Class.new { class_eval("def initialize; #{init_body}; end") }
+
+ o1 = c.new
+ o2 = c.new
+
+ # All embed_cap ivars fit - should be embedded
+ embed_cap.times { |i| o1.instance_variable_set(:"@v#{i}", i) }
+ assert_includes ObjectSpace.dump(o1), '"embedded":true'
+
+ # One more ivar overflows embed capacity
+ o1.instance_variable_set(:@overflow, 99)
+ refute_includes ObjectSpace.dump(o1), '"embedded":true'
+
+ # Remove the overflow ivar - should re-embed
+ o1.remove_instance_variable(:@overflow)
+ assert_includes ObjectSpace.dump(o1), '"embedded":true'
+
+ # An object that never overflowed is also embedded
+ embed_cap.times { |i| o2.instance_variable_set(:"@v#{i}", i) }
+ assert_includes ObjectSpace.dump(o2), '"embedded":true'
+
+ # Verify values survived re-embedding
+ embed_cap.times do |i|
+ assert_equal(i, o1.instance_variable_get(:"@v#{i}"))
+ assert_equal(i, o2.instance_variable_get(:"@v#{i}"))
+ end
+ end;
end
def test_convert_string
@@ -950,6 +955,82 @@ class TestObject < Test::Unit::TestCase
assert_match(/\bInspect\u{3042}:.* @\u{3044}=42\b/, x.inspect)
x.instance_variable_set("@\u{3046}".encode(Encoding::EUC_JP), 6)
assert_match(/@\u{3046}=6\b/, x.inspect)
+
+ x = Object.new
+ x.singleton_class.class_eval do
+ private def instance_variables_to_inspect = [:@host, :@user]
+ end
+
+ x.instance_variable_set(:@host, "localhost")
+ x.instance_variable_set(:@user, "root")
+ x.instance_variable_set(:@password, "hunter2")
+ s = x.inspect
+ assert_include(s, "@host=\"localhost\"")
+ assert_include(s, "@user=\"root\"")
+ assert_not_include(s, "@password=")
+ end
+
+ def test_inspect_mutating_ivar
+ obj = Object.new
+ evil = Object.new
+ evil.define_singleton_method(:inspect) do
+ obj.instance_variables.each { |v| obj.remove_instance_variable(v) }
+ "evil"
+ end
+ obj.instance_variable_set(:@evil, evil)
+ 10.times { |i| obj.instance_variable_set(:"@v#{i}", 0) }
+ # Buffered iteration: inspect sees a snapshot of the original ivars
+ result = obj.inspect
+ assert_include result, "@evil=evil"
+ 10.times { |i| assert_include result, "@v#{i}=0" }
+ end
+
+ def test_inspect_mutating_ivar_complex
+ # Force complex by creating many shape variations on the same class
+ c = Class.new
+ 50.times do |i|
+ o = c.new
+ o.instance_variable_set(:"@unique_#{i}", 0)
+ end
+
+ obj = c.new
+ evil = Object.new
+ evil.define_singleton_method(:inspect) do
+ obj.instance_variables.each { |v| obj.remove_instance_variable(v) }
+ ""
+ end
+ obj.instance_variable_set(:@evil, evil)
+ 10.times { |i| obj.instance_variable_set(:"@v#{i}", 0) }
+ # complex objects use st_foreach which handles mutation gracefully
+ obj.inspect
+ end
+
+ def test_inspect_complex
+ kernel_inspect = Kernel.instance_method(:inspect)
+
+ klasses = [
+ Class.new,
+ Class.new(String),
+ Class.new(Array),
+ Class.new(Hash),
+ Struct.new(:x),
+ Class.new(Thread::Mutex),
+ # It's very difficult to get a complex T_CLASS, so that isn't tested here
+ ]
+
+ klasses.each_with_index do |klass, idx|
+ 8.times do |i|
+ klass.new.instance_variable_set(:"@sib_#{rand(999999)}", 1)
+ end
+
+ obj = klass.new
+ obj.instance_variable_set(:@a, 1)
+ obj.instance_variable_set(:@b, 2)
+
+ s = kernel_inspect.bind_call(obj)
+ assert_include(s, "@a=1")
+ assert_include(s, "@b=2")
+ end
end
def test_singleton_methods
@@ -1009,6 +1090,47 @@ class TestObject < Test::Unit::TestCase
assert_predicate(ys, :frozen?, '[Bug #19169]')
end
+ def test_singleton_class_of_singleton_class_freeze
+ x = Object.new
+ xs = x.singleton_class
+ xxs = xs.singleton_class
+ xxxs = xxs.singleton_class
+ x.freeze
+ assert_predicate(xs, :frozen?, '[Bug #20319]')
+ assert_predicate(xxs, :frozen?, '[Bug #20319]')
+ assert_predicate(xxxs, :frozen?, '[Bug #20319]')
+
+ y = Object.new
+ ys = y.singleton_class
+ ys.prepend(Module.new)
+ yys = ys.singleton_class
+ yys.prepend(Module.new)
+ yyys = yys.singleton_class
+ yyys.prepend(Module.new)
+ y.freeze
+ assert_predicate(ys, :frozen?, '[Bug #20319]')
+ assert_predicate(yys, :frozen?, '[Bug #20319]')
+ assert_predicate(yyys, :frozen?, '[Bug #20319]')
+
+ c = Class.new
+ cs = c.singleton_class
+ ccs = cs.singleton_class
+ cccs = ccs.singleton_class
+ d = Class.new(c)
+ ds = d.singleton_class
+ dds = ds.singleton_class
+ ddds = dds.singleton_class
+ d.freeze
+ assert_predicate(d, :frozen?, '[Bug #20319]')
+ assert_predicate(ds, :frozen?, '[Bug #20319]')
+ assert_predicate(dds, :frozen?, '[Bug #20319]')
+ assert_predicate(ddds, :frozen?, '[Bug #20319]')
+ assert_not_predicate(c, :frozen?, '[Bug #20319]')
+ assert_not_predicate(cs, :frozen?, '[Bug #20319]')
+ assert_not_predicate(ccs, :frozen?, '[Bug #20319]')
+ assert_not_predicate(cccs, :frozen?, '[Bug #20319]')
+ end
+
def test_redef_method_missing
bug5473 = '[ruby-core:40287]'
['ArgumentError.new("bug5473")', 'ArgumentError, "bug5473"', '"bug5473"'].each do |code|
diff --git a/test/ruby/test_object_id.rb b/test/ruby/test_object_id.rb
new file mode 100644
index 0000000000..034674e5be
--- /dev/null
+++ b/test/ruby/test_object_id.rb
@@ -0,0 +1,303 @@
+require 'test/unit'
+require "securerandom"
+
+class TestObjectId < Test::Unit::TestCase
+ def setup
+ @obj = Object.new
+ end
+
+ def test_dup_new_id
+ id = @obj.object_id
+ refute_equal id, @obj.dup.object_id
+ end
+
+ def test_dup_with_ivar_and_id
+ id = @obj.object_id
+ @obj.instance_variable_set(:@foo, 42)
+
+ copy = @obj.dup
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ end
+
+ def test_dup_with_id_and_ivar
+ @obj.instance_variable_set(:@foo, 42)
+ id = @obj.object_id
+
+ copy = @obj.dup
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ end
+
+ def test_dup_with_id_and_ivar_and_frozen
+ @obj.instance_variable_set(:@foo, 42)
+ @obj.freeze
+ id = @obj.object_id
+
+ copy = @obj.dup
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ refute_predicate copy, :frozen?
+ end
+
+ def test_clone_new_id
+ id = @obj.object_id
+ refute_equal id, @obj.clone.object_id
+ end
+
+ def test_clone_with_ivar_and_id
+ id = @obj.object_id
+ @obj.instance_variable_set(:@foo, 42)
+
+ copy = @obj.clone
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ end
+
+ def test_clone_with_id_and_ivar
+ @obj.instance_variable_set(:@foo, 42)
+ id = @obj.object_id
+
+ copy = @obj.clone
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ end
+
+ def test_clone_with_id_and_ivar_and_frozen
+ @obj.instance_variable_set(:@foo, 42)
+ @obj.freeze
+ id = @obj.object_id
+
+ copy = @obj.clone
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ assert_predicate copy, :frozen?
+ end
+
+ def test_marshal_new_id
+ return pass if @obj.is_a?(Module)
+
+ id = @obj.object_id
+ refute_equal id, Marshal.load(Marshal.dump(@obj)).object_id
+ end
+
+ def test_marshal_with_ivar_and_id
+ return pass if @obj.is_a?(Module)
+
+ id = @obj.object_id
+ @obj.instance_variable_set(:@foo, 42)
+
+ copy = Marshal.load(Marshal.dump(@obj))
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ end
+
+ def test_marshal_with_id_and_ivar
+ return pass if @obj.is_a?(Module)
+
+ @obj.instance_variable_set(:@foo, 42)
+ id = @obj.object_id
+
+ copy = Marshal.load(Marshal.dump(@obj))
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ end
+
+ def test_marshal_with_id_and_ivar_and_frozen
+ return pass if @obj.is_a?(Module)
+
+ @obj.instance_variable_set(:@foo, 42)
+ @obj.freeze
+ id = @obj.object_id
+
+ copy = Marshal.load(Marshal.dump(@obj))
+ refute_equal id, copy.object_id
+ assert_equal 42, copy.instance_variable_get(:@foo)
+ refute_predicate copy, :frozen?
+ end
+
+ def test_object_id_need_resize
+ (3 - @obj.instance_variables.size).times do |i|
+ @obj.instance_variable_set("@a_#{i}", "[Bug #21445]")
+ end
+ @obj.object_id
+ GC.start
+ end
+end
+
+class TestObjectIdClass < TestObjectId
+ def setup
+ @obj = Class.new
+ end
+end
+
+class TestObjectIdGeneric < TestObjectId
+ def setup
+ @obj = Array.new
+ end
+end
+
+class TestObjectIdTooComplex < TestObjectId
+ class TooComplex
+ def initialize
+ @complex_obj_id_test = 1
+ end
+ end
+
+ def setup
+ if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
+ assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
+ end
+ 8.times do |i|
+ TooComplex.new.instance_variable_set("@TestObjectIdTooComplex#{i}", 1)
+ end
+ @obj = TooComplex.new
+ @obj.instance_variable_set("@a#{rand(10_000)}", 1)
+
+ if defined?(RubyVM::Shape)
+ assert_predicate(RubyVM::Shape.of(@obj), :complex?)
+ end
+ end
+end
+
+class TestObjectIdTooComplexClass < TestObjectId
+ class TooComplex < Module
+ end
+
+ def setup
+ if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
+ assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
+ end
+
+ @obj = TooComplex.new
+
+ @obj.instance_variable_set("@___#{SecureRandom.hex}", 1)
+
+ 8.times do |i|
+ @obj.instance_variable_set("@TestObjectIdTooComplexClass#{i}", 1)
+ @obj.remove_instance_variable("@TestObjectIdTooComplexClass#{i}")
+ end
+
+ @obj.instance_variable_set("@test", 1)
+
+ if defined?(RubyVM::Shape)
+ assert_predicate(RubyVM::Shape.of(@obj), :complex?)
+ end
+ end
+end
+
+class TestObjectIdTooComplexGeneric < TestObjectId
+ class TooComplex < Array
+ end
+
+ def setup
+ if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
+ assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
+ end
+ 8.times do |i|
+ TooComplex.new.instance_variable_set("@TestObjectIdTooComplexGeneric#{i}", 1)
+ end
+ @obj = TooComplex.new
+ @obj.instance_variable_set("@a#{rand(10_000)}", 1)
+ @obj.instance_variable_set("@a#{rand(10_000)}", 1)
+
+ if defined?(RubyVM::Shape)
+ assert_predicate(RubyVM::Shape.of(@obj), :complex?)
+ end
+ end
+end
+
+class TestObjectIdRactor < Test::Unit::TestCase
+ def test_object_id_race_free
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ Warning[:experimental] = false
+ class MyClass
+ attr_reader :a, :b, :c
+ def initialize
+ @a = @b = @c = nil
+ end
+ end
+ N = 10_000
+ objs = Ractor.make_shareable(N.times.map { MyClass.new })
+ results = 4.times.map{
+ Ractor.new(objs) { |objs|
+ vars = []
+ ids = []
+ objs.each do |obj|
+ vars << obj.a << obj.b << obj.c
+ ids << obj.object_id
+ end
+ [vars, ids]
+ }
+ }.map(&:value)
+ assert_equal 1, results.uniq.size
+ end;
+ end
+
+ def test_external_object_id_ractor_move
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ Warning[:experimental] = false
+ class MyClass
+ attr_reader :a, :b, :c
+ def initialize
+ @a = @b = @c = nil
+ end
+ end
+ obj = Ractor.make_shareable(MyClass.new)
+ object_id = obj.object_id
+ obj = Ractor.new { Ractor.receive }.send(obj, move: true).value
+ assert_equal object_id, obj.object_id
+ end;
+ end
+end
+
+class TestObjectIdStruct < TestObjectId
+ EmbeddedStruct = Struct.new(:embedded_field)
+
+ def setup
+ @obj = EmbeddedStruct.new
+ end
+end
+
+class TestObjectIdStructGenIvar < TestObjectId
+ GenIvarStruct = Struct.new(:a, :b, :c)
+
+ def setup
+ @obj = GenIvarStruct.new
+ end
+end
+
+class TestObjectIdStructNotEmbed < TestObjectId
+ MANY_IVS = 80
+
+ StructNotEmbed = Struct.new(*MANY_IVS.times.map { |i| :"field_#{i}" })
+
+ def setup
+ @obj = StructNotEmbed.new
+ end
+end
+
+class TestObjectIdStructTooComplex < TestObjectId
+ StructTooComplex = Struct.new(:a) do
+ def initialize
+ @complex_obj_id_test = 1
+ end
+ end
+
+ def setup
+ if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
+ assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
+ end
+ 8.times do |i|
+ StructTooComplex.new.instance_variable_set("@TestObjectIdStructTooComplex#{i}", 1)
+ end
+ @obj = StructTooComplex.new
+ @obj.instance_variable_set("@a#{rand(10_000)}", 1)
+
+ if defined?(RubyVM::Shape)
+ assert_predicate(RubyVM::Shape.of(@obj), :complex?)
+ end
+ end
+end
diff --git a/test/ruby/test_objectspace.rb b/test/ruby/test_objectspace.rb
index 5c79983b7e..a479547599 100644
--- a/test/ruby/test_objectspace.rb
+++ b/test/ruby/test_objectspace.rb
@@ -8,7 +8,7 @@ class TestObjectSpace < Test::Unit::TestCase
line = $1.to_i
code = <<"End"
define_method("test_id2ref_#{line}") {\
- o = ObjectSpace._id2ref(obj.object_id);\
+ o = EnvUtil.suppress_warning { ObjectSpace._id2ref(obj.object_id) }
assert_same(obj, o, "didn't round trip: \#{obj.inspect}");\
}
End
@@ -57,20 +57,20 @@ End
def test_id2ref_invalid_argument
msg = /no implicit conversion/
- assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref(nil)}
- assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref(false)}
- assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref(true)}
- assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref(:a)}
- assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref("0")}
- assert_raise_with_message(TypeError, msg) {ObjectSpace._id2ref(Object.new)}
+ assert_raise_with_message(TypeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref(nil) } }
+ assert_raise_with_message(TypeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref(false) } }
+ assert_raise_with_message(TypeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref(true) } }
+ assert_raise_with_message(TypeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref(:a) } }
+ assert_raise_with_message(TypeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref("0") } }
+ assert_raise_with_message(TypeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref(Object.new) } }
end
def test_id2ref_invalid_symbol_id
# RB_STATIC_SYM_P checks for static symbols by checking that the bottom
# 8 bits of the object is equal to RUBY_SYMBOL_FLAG, so we need to make
# sure that the bottom 8 bits remain unchanged.
- msg = /is not symbol id value/
- assert_raise_with_message(RangeError, msg) { ObjectSpace._id2ref(:a.object_id + 256) }
+ msg = /is not a symbol id value/
+ assert_raise_with_message(RangeError, msg) { EnvUtil.suppress_warning { ObjectSpace._id2ref(:a.object_id + 256) } }
end
def test_count_objects
@@ -94,7 +94,7 @@ End
end
def test_finalizer
- assert_in_out_err(["-e", <<-END], "", %w(:ok :ok :ok :ok), [])
+ assert_in_out_err(["-e", <<-END], "", %w(:ok :ok :ok), [])
a = []
ObjectSpace.define_finalizer(a) { p :ok }
b = a.dup
@@ -137,6 +137,25 @@ End
}
end
+ def test_finalizer_copy
+ assert_in_out_err(["-e", <<~'RUBY'], "", %w(:ok), [])
+ def fin
+ ids = Set.new
+ ->(id) { puts "object_id (#{id}) reused" unless ids.add?(id) }
+ end
+
+ OBJ = Object.new
+ ObjectSpace.define_finalizer(OBJ, fin)
+ OBJ.freeze
+
+ 10.times do
+ OBJ.clone
+ end
+
+ p :ok
+ RUBY
+ end
+
def test_finalizer_with_super
assert_in_out_err(["-e", <<-END], "", %w(:ok), [])
class A
@@ -265,6 +284,21 @@ End
end;
end
+ def test_id2ref_table_build
+ assert_separately([], <<-End)
+ 10.times do
+ Object.new.object_id
+ end
+
+ GC.start(immediate_mark: false)
+
+ obj = Object.new
+ EnvUtil.suppress_warning do
+ assert_equal obj, ObjectSpace._id2ref(obj.object_id)
+ end
+ End
+ end
+
def test_each_object_singleton_class
assert_separately([], <<-End)
class C
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index ea9752f85a..1554b43f18 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -606,11 +606,11 @@ class TestRubyOptimization < Test::Unit::TestCase
end
class Bug10557
- def [](_)
+ def [](_, &)
block_given?
end
- def []=(_, _)
+ def []=(_, _, &)
block_given?
end
end
@@ -728,7 +728,7 @@ class TestRubyOptimization < Test::Unit::TestCase
insn = iseq.disasm
assert_match %r{putobject\s+#{Regexp.quote('"1.8.0"..."1.8.8"')}}, insn
assert_match %r{putobject\s+#{Regexp.quote('"2.0.0".."2.3.2"')}}, insn
- assert_no_match(/putstring/, insn)
+ assert_no_match(/dupstring/, insn)
assert_no_match(/newrange/, insn)
end
end
@@ -946,14 +946,14 @@ class TestRubyOptimization < Test::Unit::TestCase
end
def test_peephole_optimization_without_trace
- assert_separately [], <<-END
+ assert_ruby_status [], <<-END
RubyVM::InstructionSequence.compile_option = {trace_instruction: false}
eval "def foo; 1.times{|(a), &b| nil && a}; end"
END
end
def test_clear_unreachable_keyword_args
- assert_separately [], <<-END, timeout: 60
+ assert_ruby_status [], <<-END, timeout: 60
script = <<-EOS
if true
else
@@ -1080,7 +1080,7 @@ class TestRubyOptimization < Test::Unit::TestCase
class Objtostring
end
- def test_objtostring
+ def test_objtostring_immediate
assert_raise(NoMethodError){"#{BasicObject.new}"}
assert_redefine_method('Symbol', 'to_s', <<-'end')
assert_match %r{\A#<Symbol:0x[0-9a-f]+>\z}, "#{:foo}"
@@ -1094,11 +1094,17 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_redefine_method('FalseClass', 'to_s', <<-'end')
assert_match %r{\A#<FalseClass:0x[0-9a-f]+>\z}, "#{false}"
end
+ end
+
+ def test_objtostring_fixnum
assert_redefine_method('Integer', 'to_s', <<-'end')
(-1..10).each { |i|
assert_match %r{\A#<Integer:0x[0-9a-f]+>\z}, "#{i}"
}
end
+ end
+
+ def test_objtostring
assert_equal "TestRubyOptimization::Objtostring", "#{Objtostring}"
assert_match %r{\A#<Class:0x[0-9a-f]+>\z}, "#{Class.new}"
assert_match %r{\A#<Module:0x[0-9a-f]+>\z}, "#{Module.new}"
@@ -1215,4 +1221,58 @@ class TestRubyOptimization < Test::Unit::TestCase
end
RUBY
end
+
+ def test_opt_new_with_safe_navigation
+ payload = nil
+ assert_nil payload&.new
+ end
+
+ def test_opt_new
+ pos_initialize = "
+ def initialize a, b
+ @a = a
+ @b = b
+ end
+ "
+ kw_initialize = "
+ def initialize a:, b:
+ @a = a
+ @b = b
+ end
+ "
+ kw_hash_initialize = "
+ def initialize a, **kw
+ @a = a
+ @b = kw[:b]
+ end
+ "
+ pos_prelude = "class OptNewFoo; #{pos_initialize}; end;"
+ kw_prelude = "class OptNewFoo; #{kw_initialize}; end;"
+ kw_hash_prelude = "class OptNewFoo; #{kw_hash_initialize}; end;"
+ [
+ "#{pos_prelude} OptNewFoo.new 1, 2",
+ "#{pos_prelude} a = 1; b = 2; OptNewFoo.new a, b",
+ "#{pos_prelude} def optnew_foo(a, b) = OptNewFoo.new(a, b); optnew_foo 1, 2",
+ "#{pos_prelude} def optnew_foo(*a) = OptNewFoo.new(*a); optnew_foo 1, 2",
+ "#{pos_prelude} def optnew_foo(...) = OptNewFoo.new(...); optnew_foo 1, 2",
+ "#{kw_prelude} def optnew_foo(**a) = OptNewFoo.new(**a); optnew_foo a: 1, b: 2",
+ "#{kw_hash_prelude} def optnew_foo(*a, **b) = OptNewFoo.new(*a, **b); optnew_foo 1, b: 2",
+ ].each do |code|
+ iseq = RubyVM::InstructionSequence.compile(code)
+ insn = iseq.disasm
+ assert_match(/opt_new/, insn)
+ assert_match(/OptNewFoo:.+@a=1, @b=2/, iseq.eval.inspect)
+ # clean up to avoid warnings
+ Object.send :remove_const, :OptNewFoo
+ Object.remove_method :optnew_foo if defined?(optnew_foo)
+ end
+ [
+ 'def optnew_foo(&) = OptNewFoo.new(&)',
+ 'def optnew_foo(a, ...) = OptNewFoo.new(a, ...)',
+ ].each do |code|
+ iseq = RubyVM::InstructionSequence.compile(code)
+ insn = iseq.disasm
+ assert_no_match(/opt_new/, insn)
+ end
+ end
end
diff --git a/test/ruby/test_pack.rb b/test/ruby/test_pack.rb
index ca089f09c3..6e5f0fe7ff 100644
--- a/test/ruby/test_pack.rb
+++ b/test/ruby/test_pack.rb
@@ -283,6 +283,15 @@ class TestPack < Test::Unit::TestCase
assert_equal(["foo "], "foo ".unpack("a4"))
assert_equal(["foo"], "foo".unpack("A4"))
assert_equal(["foo"], "foo".unpack("a4"))
+
+ assert_equal(["foo", 4], "foo\0 ".unpack("A4^"))
+ assert_equal(["foo\0", 4], "foo\0 ".unpack("a4^"))
+ assert_equal(["foo", 4], "foo ".unpack("A4^"))
+ assert_equal(["foo ", 4], "foo ".unpack("a4^"))
+ assert_equal(["foo", 3], "foo".unpack("A4^"))
+ assert_equal(["foo", 3], "foo".unpack("a4^"))
+ assert_equal(["foo", 6], "foo\0 ".unpack("A*^"))
+ assert_equal(["foo", 6], "foo ".unpack("A*^"))
end
def test_pack_unpack_Z
@@ -298,6 +307,11 @@ class TestPack < Test::Unit::TestCase
assert_equal(["foo"], "foo".unpack("Z*"))
assert_equal(["foo"], "foo\0".unpack("Z*"))
assert_equal(["foo"], "foo".unpack("Z5"))
+
+ assert_equal(["foo", 3], "foo".unpack("Z*^"))
+ assert_equal(["foo", 4], "foo\0".unpack("Z*^"))
+ assert_equal(["foo", 3], "foo".unpack("Z5^"))
+ assert_equal(["foo", 5], "foo\0\0\0".unpack("Z5^"))
end
def test_pack_unpack_bB
@@ -549,6 +563,8 @@ class TestPack < Test::Unit::TestCase
assert_equal([0, 2], "\x00\x00\x02".unpack("CxC"))
assert_raise(ArgumentError) { "".unpack("x") }
+
+ assert_equal([0, 1, 2, 2, 3], "\x00\x00\x02".unpack("C^x^C^"))
end
def test_pack_unpack_X
@@ -558,6 +574,7 @@ class TestPack < Test::Unit::TestCase
assert_equal([0, 2, 2], "\x00\x02".unpack("CCXC"))
assert_raise(ArgumentError) { "".unpack("X") }
+ assert_equal([0, 1, 2, 2, 1, 2, 2], "\x00\x02".unpack("C^C^X^C^"))
end
def test_pack_unpack_atmark
@@ -571,6 +588,17 @@ class TestPack < Test::Unit::TestCase
pos = RbConfig::LIMITS["UINTPTR_MAX"] - 99 # -100
assert_raise(RangeError) {"0123456789".unpack("@#{pos}C10")}
+
+ assert_equal([1, 3, 4], "\x01\x00\x00\x02".unpack("x^@3^x^"))
+ end
+
+ def test_unpack_carret
+ assert_equal([0], "abc".unpack("^"))
+ assert_equal([2], "abc".unpack("^", offset: 2))
+ assert_equal([97, nil, 1], "a".unpack("CC^"))
+
+ assert_raise(ArgumentError) { "".unpack("^!") }
+ assert_raise(ArgumentError) { "".unpack("^_") }
end
def test_pack_unpack_percent
@@ -853,6 +881,19 @@ EXPECTED
assert_equal "\xDE\xAD\xBE\xEF\xBA\xBE\xF0\x0D\0\0\xBA\xAD\xFA\xCE", buf
assert_equal addr, [buf].pack('p')
+
+ assert_packing_buffer_fail("b*")
+ assert_packing_buffer_fail("B*")
+ assert_packing_buffer_fail("h*")
+ assert_packing_buffer_fail("H*")
+ assert_packing_buffer_fail("u", 16384)
+ assert_packing_buffer_fail("m", 16384)
+ assert_packing_buffer_fail("M", 16384)
+ end
+
+ def assert_packing_buffer_fail(fmt, size = 8192)
+ s = "\x01".b * size
+ assert_raise(ArgumentError) {[s].pack(fmt, buffer: s)}
end
def test_unpack_with_block
@@ -872,27 +913,29 @@ EXPECTED
def test_unpack1_offset
assert_equal 65, "ZA".unpack1("C", offset: 1)
+ assert_equal 65, "ZA".unpack1("C", offset: -1)
assert_equal "01000001", "YZA".unpack1("B*", offset: 2)
assert_nil "abc".unpack1("C", offset: 3)
- assert_raise_with_message(ArgumentError, /offset can't be negative/) {
- "a".unpack1("C", offset: -1)
- }
assert_raise_with_message(ArgumentError, /offset outside of string/) {
"a".unpack1("C", offset: 2)
}
+ assert_raise_with_message(ArgumentError, /offset outside of string/) {
+ "a".unpack1("C", offset: -2)
+ }
assert_nil "a".unpack1("C", offset: 1)
end
def test_unpack_offset
assert_equal [65], "ZA".unpack("C", offset: 1)
+ assert_equal [65], "ZA".unpack("C", offset: -1)
assert_equal ["01000001"], "YZA".unpack("B*", offset: 2)
assert_equal [nil, nil, nil], "abc".unpack("CCC", offset: 3)
- assert_raise_with_message(ArgumentError, /offset can't be negative/) {
- "a".unpack("C", offset: -1)
- }
assert_raise_with_message(ArgumentError, /offset outside of string/) {
"a".unpack("C", offset: 2)
}
+ assert_raise_with_message(ArgumentError, /offset outside of string/) {
+ "a".unpack("C", offset: -2)
+ }
assert_equal [nil], "a".unpack("C", offset: 1)
end
@@ -936,4 +979,116 @@ EXPECTED
assert_equal "oh no", v
end;
end
+
+ def test_unpack_broken_R
+ assert_equal([nil], "\xFF".unpack("R"))
+ assert_nil("\xFF".unpack1("R"))
+ assert_equal([nil], "\xFF".unpack("r"))
+ assert_nil("\xFF".unpack1("r"))
+
+ bytes = [256].pack("r")
+ assert_equal([256, nil, nil, nil], (bytes + "\xFF").unpack("rrrr"))
+
+ bytes = [256].pack("R")
+ assert_equal([256, nil, nil, nil], (bytes + "\xFF").unpack("RRRR"))
+
+ assert_equal([], "\xFF".unpack("R*"))
+ assert_equal([], "\xFF".unpack("r*"))
+ end
+
+ def test_pack_unpack_R
+ # ULEB128 encoding (unsigned)
+ assert_equal("\x00", [0].pack("R"))
+ assert_equal("\x01", [1].pack("R"))
+ assert_equal("\x7f", [127].pack("R"))
+ assert_equal("\x80\x01", [128].pack("R"))
+ assert_equal("\xff\x7f", [0x3fff].pack("R"))
+ assert_equal("\x80\x80\x01", [0x4000].pack("R"))
+ assert_equal("\xff\xff\xff\xff\x0f", [0xffffffff].pack("R"))
+ assert_equal("\x80\x80\x80\x80\x10", [0x100000000].pack("R"))
+ assert_equal("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", [0xffff_ffff_ffff_ffff].pack("R"))
+ assert_equal("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x1f", [0xffff_ffff_ffff_ffff_ffff_ffff].pack("R"))
+
+ # Multiple values
+ assert_equal("\x01\x02", [1, 2].pack("R*"))
+ assert_equal("\x7f\x80\x01", [127, 128].pack("R*"))
+
+ # Negative numbers should raise an error
+ assert_raise(ArgumentError) { [-1].pack("R") }
+ assert_raise(ArgumentError) { [-100].pack("R") }
+
+ # Unpack tests
+ assert_equal([0], "\x00".unpack("R"))
+ assert_equal([1], "\x01".unpack("R"))
+ assert_equal([127], "\x7f".unpack("R"))
+ assert_equal([128], "\x80\x01".unpack("R"))
+ assert_equal([0x3fff], "\xff\x7f".unpack("R"))
+ assert_equal([0x4000], "\x80\x80\x01".unpack("R"))
+ assert_equal([0xffffffff], "\xff\xff\xff\xff\x0f".unpack("R"))
+ assert_equal([0x100000000], "\x80\x80\x80\x80\x10".unpack("R"))
+ assert_equal([0xffff_ffff_ffff_ffff], "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01".unpack("R"))
+ assert_equal([0xffff_ffff_ffff_ffff_ffff_ffff].pack("R"), "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x1f")
+
+ # Multiple values
+ assert_equal([1, 2], "\x01\x02".unpack("R*"))
+ assert_equal([127, 128], "\x7f\x80\x01".unpack("R*"))
+
+ # Round-trip test
+ values = [0, 1, 127, 128, 0x3fff, 0x4000, 0xffffffff, 0x100000000]
+ assert_equal(values, values.pack("R*").unpack("R*"))
+ end
+
+ def test_pack_unpack_r
+ # SLEB128 encoding (signed)
+ assert_equal("\x00", [0].pack("r"))
+ assert_equal("\x01", [1].pack("r"))
+ assert_equal("\x7f", [-1].pack("r"))
+ assert_equal("\x7e", [-2].pack("r"))
+ assert_equal("\xff\x00", [127].pack("r"))
+ assert_equal("\x80\x01", [128].pack("r"))
+ assert_equal("\x81\x7f", [-127].pack("r"))
+ assert_equal("\x80\x7f", [-128].pack("r"))
+
+ # Larger positive numbers
+ assert_equal("\xff\xff\x00", [0x3fff].pack("r"))
+ assert_equal("\x80\x80\x01", [0x4000].pack("r"))
+
+ # Larger negative numbers
+ assert_equal("\x81\x80\x7f", [-0x3fff].pack("r"))
+ assert_equal("\x80\x80\x7f", [-0x4000].pack("r"))
+
+ # Very large numbers
+ assert_equal("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1F", [0xffff_ffff_ffff_ffff_ffff_ffff].pack("r"))
+ assert_equal("\x81\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80`", [-0xffff_ffff_ffff_ffff_ffff_ffff].pack("r"))
+
+ # Multiple values
+ assert_equal("\x00\x01\x7f", [0, 1, -1].pack("r*"))
+
+ # Unpack tests
+ assert_equal([0], "\x00".unpack("r"))
+ assert_equal([1], "\x01".unpack("r"))
+ assert_equal([-1], "\x7f".unpack("r"))
+ assert_equal([-2], "\x7e".unpack("r"))
+ assert_equal([127], "\xff\x00".unpack("r"))
+ assert_equal([128], "\x80\x01".unpack("r"))
+ assert_equal([-127], "\x81\x7f".unpack("r"))
+ assert_equal([-128], "\x80\x7f".unpack("r"))
+
+ # Larger numbers
+ assert_equal([0x3fff], "\xff\xff\x00".unpack("r"))
+ assert_equal([0x4000], "\x80\x80\x01".unpack("r"))
+ assert_equal([-0x3fff], "\x81\x80\x7f".unpack("r"))
+ assert_equal([-0x4000], "\x80\x80\x7f".unpack("r"))
+
+ # Very large numbers
+ assert_equal("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x1f", [0xffff_ffff_ffff_ffff_ffff_ffff].pack("r"))
+ assert_equal("\x81\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80`", [-0xffff_ffff_ffff_ffff_ffff_ffff].pack("r"))
+
+ # Multiple values
+ assert_equal([0, 1, -1], "\x00\x01\x7f".unpack("r*"))
+
+ # Round-trip test
+ values = [0, 1, -1, 127, -127, 128, -128, 0x3fff, -0x3fff, 0x4000, -0x4000]
+ assert_equal(values, values.pack("r*").unpack("r*"))
+ end
end
diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb
index 98e95b98af..def41d6017 100644
--- a/test/ruby/test_parse.rb
+++ b/test/ruby/test_parse.rb
@@ -352,6 +352,21 @@ class TestParse < Test::Unit::TestCase
assert_equal("foobar", b)
end
+ def test_call_command
+ a = b = nil
+ o = Object.new
+ def o.m(*arg); proc {|a| arg.join + a }; end
+
+ assert_nothing_raised do
+ o.instance_eval <<-END, __FILE__, __LINE__+1
+ a = o.m "foo", "bar" do end.("buz")
+ b = o.m "foo", "bar" do end::("buz")
+ END
+ end
+ assert_equal("foobarbuz", a)
+ assert_equal("foobarbuz", b)
+ end
+
def test_xstring
assert_raise(Errno::ENOENT) do
eval("``")
@@ -1544,7 +1559,7 @@ x = __ENCODING__
end
def test_shareable_constant_value_simple
- obj = [['unsharable_value']]
+ obj = [['unshareable_value']]
a, b, c = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
# shareable_constant_value: experimental_everything
@@ -1573,7 +1588,7 @@ x = __ENCODING__
assert_ractor_shareable(a)
assert_not_ractor_shareable(obj)
assert_equal obj, a
- assert !obj.equal?(a)
+ assert_not_same obj, a
bug_20339 = '[ruby-core:117186] [Bug #20339]'
bug_20341 = '[ruby-core:117197] [Bug #20341]'
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index 92a3244fc2..96aa2a7fd6 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -197,11 +197,49 @@ class TestPatternMatching < Test::Unit::TestCase
end
end
- assert_syntax_error(%q{
+ assert_valid_syntax(%{
+ case 0
+ in [ :a | :b, x]
+ true
+ end
+ })
+
+ assert_in_out_err(['-c'], %q{
case 0
in a | 0
end
- }, /illegal variable in alternative pattern/)
+ }, [], /alternative pattern/,
+ success: false)
+
+ assert_in_out_err(['-c'], %q{
+ case 0
+ in 0 | a
+ end
+ }, [], /alternative pattern/,
+ success: false)
+ end
+
+ def test_alternative_pattern_nested
+ assert_in_out_err(['-c'], %q{
+ case 0
+ in [a] | 1
+ end
+ }, [], /alternative pattern/,
+ success: false)
+
+ assert_in_out_err(['-c'], %q{
+ case 0
+ in { a: b } | 1
+ end
+ }, [], /alternative pattern/,
+ success: false)
+
+ assert_in_out_err(['-c'], %q{
+ case 0
+ in [{ a: [{ b: [{ c: }] }] }] | 1
+ end
+ }, [], /alternative pattern/,
+ success: false)
end
def test_var_pattern
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index 35aa16063d..f74342322f 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -513,7 +513,7 @@ class TestProc < Test::Unit::TestCase
file, lineno = method(:source_location_test).to_proc.binding.source_location
assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
- assert_equal(@@line_of_source_location_test[0], lineno, 'Bug #2427')
+ assert_equal(@@line_of_source_location_test, lineno, 'Bug #2427')
end
def test_binding_error_unless_ruby_frame
@@ -1499,19 +1499,15 @@ class TestProc < Test::Unit::TestCase
assert_include(EnvUtil.labeled_class(name, Proc).new {}.to_s, name)
end
- @@line_of_source_location_test = [__LINE__ + 1, 2, __LINE__ + 3, 5]
+ @@line_of_source_location_test = __LINE__ + 1
def source_location_test a=1,
b=2
end
def test_source_location
- file, *loc = method(:source_location_test).source_location
+ file, lineno = method(:source_location_test).source_location
assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
- assert_equal(@@line_of_source_location_test, loc, 'Bug #2427')
-
- file, *loc = self.class.instance_method(:source_location_test).source_location
- assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
- assert_equal(@@line_of_source_location_test, loc, 'Bug #2427')
+ assert_equal(@@line_of_source_location_test, lineno, 'Bug #2427')
end
@@line_of_attr_reader_source_location_test = __LINE__ + 3
@@ -1544,13 +1540,13 @@ class TestProc < Test::Unit::TestCase
end
def test_block_source_location
- exp_loc = [__LINE__ + 3, 49, __LINE__ + 4, 49]
- file, *loc = block_source_location_test(1,
+ exp_lineno = __LINE__ + 3
+ file, lineno = block_source_location_test(1,
2,
3) do
end
assert_match(/^#{ Regexp.quote(__FILE__) }$/, file)
- assert_equal(exp_loc, loc)
+ assert_equal(exp_lineno, lineno)
end
def test_splat_without_respond_to
@@ -1637,6 +1633,10 @@ class TestProc < Test::Unit::TestCase
assert_equal(3, b.local_variable_get(:when))
assert_equal(4, b.local_variable_get(:begin))
assert_equal(5, b.local_variable_get(:end))
+
+ assert_raise_with_message(NameError, /local variable \Wdefault\W/) {
+ binding.local_variable_get(:default)
+ }
end
def test_local_variable_set
@@ -1651,33 +1651,103 @@ class TestProc < Test::Unit::TestCase
def test_numparam_is_not_local_variables
"foo".tap do
- _9
+ _9 and flunk
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:_9) }
assert_raise(NameError) { binding.local_variable_set(:_9, 1) }
+ assert_raise(NameError) { binding.local_variable_defined?(:_9) }
"bar".tap do
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:_9) }
assert_raise(NameError) { binding.local_variable_set(:_9, 1) }
+ assert_raise(NameError) { binding.local_variable_defined?(:_9) }
end
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:_9) }
assert_raise(NameError) { binding.local_variable_set(:_9, 1) }
+ assert_raise(NameError) { binding.local_variable_defined?(:_9) }
end
"foo".tap do
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:_9) }
assert_raise(NameError) { binding.local_variable_set(:_9, 1) }
+ assert_raise(NameError) { binding.local_variable_defined?(:_9) }
"bar".tap do
- _9
+ _9 and flunk
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:_9) }
assert_raise(NameError) { binding.local_variable_set(:_9, 1) }
+ assert_raise(NameError) { binding.local_variable_defined?(:_9) }
end
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:_9) }
assert_raise(NameError) { binding.local_variable_set(:_9, 1) }
+ assert_raise(NameError) { binding.local_variable_defined?(:_9) }
+ end
+ end
+
+ def test_implicit_parameters_for_numparams
+ x = x = 1
+ assert_raise(NameError) { binding.implicit_parameter_get(:x) }
+ assert_raise(NameError) { binding.implicit_parameter_defined?(:x) }
+
+ "foo".tap do
+ _5 and flunk
+ assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
+ assert_equal("foo", binding.implicit_parameter_get(:_1))
+ assert_equal(nil, binding.implicit_parameter_get(:_5))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_equal(true, binding.implicit_parameter_defined?(:_1))
+ assert_equal(true, binding.implicit_parameter_defined?(:_5))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ "bar".tap do
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ end
+ assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
+ assert_equal("foo", binding.implicit_parameter_get(:_1))
+ assert_equal(nil, binding.implicit_parameter_get(:_5))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_equal(true, binding.implicit_parameter_defined?(:_1))
+ assert_equal(true, binding.implicit_parameter_defined?(:_5))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ end
+
+ "foo".tap do
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ "bar".tap do
+ _5 and flunk
+ assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
+ assert_equal("bar", binding.implicit_parameter_get(:_1))
+ assert_equal(nil, binding.implicit_parameter_get(:_5))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_equal(true, binding.implicit_parameter_defined?(:_1))
+ assert_equal(true, binding.implicit_parameter_defined?(:_5))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ end
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
end
end
@@ -1686,32 +1756,165 @@ class TestProc < Test::Unit::TestCase
it
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
"bar".tap do
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
end
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
"bar".tap do
it
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
end
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
end
"foo".tap do
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
"bar".tap do
it
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
+ end
+ assert_equal([], binding.local_variables)
+ assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
+ end
+ end
+
+ def test_implicit_parameters_for_it
+ "foo".tap do
+ it or flunk
+ assert_equal([:it], binding.implicit_parameters)
+ assert_equal("foo", binding.implicit_parameter_get(:it))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_equal(true, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ "bar".tap do
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ end
+ assert_equal([:it], binding.implicit_parameters)
+ assert_equal("foo", binding.implicit_parameter_get(:it))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_equal(true, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ end
+
+ "foo".tap do
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ "bar".tap do
+ it or flunk
+ assert_equal([:it], binding.implicit_parameters)
+ assert_equal("bar", binding.implicit_parameter_get(:it))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_equal(true, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
end
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ end
+ end
+
+ def test_implicit_parameters_for_it_complex
+ "foo".tap do
+ it = it = "bar"
+
+ assert_equal([], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+
+ assert_equal([:it], binding.local_variables)
+ assert_equal("bar", binding.local_variable_get(:it))
+ assert_equal(true, binding.local_variable_defined?(:it))
+ end
+
+ "foo".tap do
+ it or flunk
+
+ assert_equal([:it], binding.implicit_parameters)
+ assert_equal("foo", binding.implicit_parameter_get(:it))
+ assert_equal(true, binding.implicit_parameter_defined?(:it))
+
assert_equal([], binding.local_variables)
assert_raise(NameError) { binding.local_variable_get(:it) }
+ assert_equal(false, binding.local_variable_defined?(:it))
end
+
+ "foo".tap do
+ it or flunk
+ it = it = "bar"
+
+ assert_equal([:it], binding.implicit_parameters)
+ assert_equal("foo", binding.implicit_parameter_get(:it))
+ assert_equal(true, binding.implicit_parameter_defined?(:it))
+
+ assert_equal([:it], binding.local_variables)
+ assert_equal("bar", binding.local_variable_get(:it))
+ assert_equal(true, binding.local_variable_defined?(:it))
+ end
+ end
+
+ def test_implicit_parameters_for_it_and_numparams
+ "foo".tap do
+ it or flunk
+ "bar".tap do
+ _5 and flunk
+ assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
+ assert_raise(NameError) { binding.implicit_parameter_get(:it) }
+ assert_equal("bar", binding.implicit_parameter_get(:_1))
+ assert_equal(nil, binding.implicit_parameter_get(:_5))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_equal(false, binding.implicit_parameter_defined?(:it))
+ assert_equal(true, binding.implicit_parameter_defined?(:_1))
+ assert_equal(true, binding.implicit_parameter_defined?(:_5))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ end
+ end
+
+ "foo".tap do
+ _5 and flunk
+ "bar".tap do
+ it or flunk
+ assert_equal([:it], binding.implicit_parameters)
+ assert_equal("bar", binding.implicit_parameter_get(:it))
+ assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_5) }
+ assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
+ assert_equal(true, binding.implicit_parameter_defined?(:it))
+ assert_equal(false, binding.implicit_parameter_defined?(:_1))
+ assert_equal(false, binding.implicit_parameter_defined?(:_5))
+ assert_equal(false, binding.implicit_parameter_defined?(:_6))
+ end
+ end
+ end
+
+ def test_implicit_parameter_invalid_name
+ message_pattern = /is not an implicit parameter/
+ assert_raise_with_message(NameError, message_pattern) { binding.implicit_parameter_defined?(:foo) }
+ assert_raise_with_message(NameError, message_pattern) { binding.implicit_parameter_get(:foo) }
+ assert_raise_with_message(NameError, message_pattern) { binding.implicit_parameter_defined?("wrong_implicit_parameter_name_#{rand(10000)}") }
+ assert_raise_with_message(NameError, message_pattern) { binding.implicit_parameter_get("wrong_implicit_parameter_name_#{rand(10000)}") }
end
def test_local_variable_set_wb
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index 5a91e94b09..d99e356e69 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -58,6 +58,8 @@ class TestProcess < Test::Unit::TestCase
def test_rlimit_nofile
return unless rlimit_exist?
+ omit "LSAN needs to open proc file" if Test::Sanitizers.lsan_enabled?
+
with_tmpchdir {
File.write 's', <<-"End"
# Too small RLIMIT_NOFILE, such as zero, causes problems.
@@ -114,14 +116,19 @@ class TestProcess < Test::Unit::TestCase
}
assert_raise(ArgumentError) { Process.getrlimit(:FOO) }
assert_raise(ArgumentError) { Process.getrlimit("FOO") }
- assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.getrlimit("\u{30eb 30d3 30fc}") }
+
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.getrlimit("\u{30eb 30d3 30fc}") }
+ end
end
def test_rlimit_value
return unless rlimit_exist?
assert_raise(ArgumentError) { Process.setrlimit(:FOO, 0) }
assert_raise(ArgumentError) { Process.setrlimit(:CORE, :FOO) }
- assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit("\u{30eb 30d3 30fc}", 0) }
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit("\u{30eb 30d3 30fc}", 0) }
+ end
assert_raise_with_message(ArgumentError, /\u{30eb 30d3 30fc}/) { Process.setrlimit(:CORE, "\u{30eb 30d3 30fc}") }
with_tmpchdir do
s = run_in_child(<<-'End')
@@ -275,21 +282,22 @@ class TestProcess < Test::Unit::TestCase
end;
end
- MANDATORY_ENVS = %w[RUBYLIB GEM_HOME GEM_PATH]
- case RbConfig::CONFIG['target_os']
- when /linux/
- MANDATORY_ENVS << 'LD_PRELOAD'
- when /mswin|mingw/
- MANDATORY_ENVS.concat(%w[HOME USER TMPDIR PROCESSOR_ARCHITECTURE])
- when /darwin/
- MANDATORY_ENVS.concat(ENV.keys.grep(/\A__CF_/))
- end
+ MANDATORY_ENVS = %w[RUBYLIB GEM_HOME GEM_PATH RUBY_FREE_AT_EXIT]
if e = RbConfig::CONFIG['LIBPATHENV']
MANDATORY_ENVS << e
end
if e = RbConfig::CONFIG['PRELOADENV'] and !e.empty?
MANDATORY_ENVS << e
end
+ case RbConfig::CONFIG['target_os']
+ when /mswin|mingw/
+ MANDATORY_ENVS.concat(%w[HOME USER TMPDIR PROCESSOR_ARCHITECTURE])
+ when /darwin/
+ MANDATORY_ENVS.concat(%w[TMPDIR], ENV.keys.grep(/\A__CF_/))
+ # IO.popen([ENV.keys.to_h {|e| [e, nil]},
+ # RUBY, "-e", %q[print ENV.keys.join(?\0)]],
+ # &:read).split(?\0)
+ end
PREENVARG = ['-e', "%w[#{MANDATORY_ENVS.join(' ')}].each{|e|ENV.delete(e)}"]
ENVARG = ['-e', 'ENV.each {|k,v| puts "#{k}=#{v}" }']
ENVCOMMAND = [RUBY].concat(PREENVARG).concat(ENVARG)
@@ -1560,7 +1568,7 @@ class TestProcess < Test::Unit::TestCase
def test_wait_exception
bug11340 = '[ruby-dev:49176] [Bug #11340]'
t0 = t1 = nil
- sec = 3
+ sec = EnvUtil.apply_timeout_scale(3)
code = "puts;STDOUT.flush;Thread.start{gets;exit};sleep(#{sec})"
IO.popen([RUBY, '-e', code], 'r+') do |f|
pid = f.pid
@@ -1682,9 +1690,10 @@ class TestProcess < Test::Unit::TestCase
if u = Etc.getpwuid(Process.uid)
assert_equal(Process.uid, Process::UID.from_name(u.name), u.name)
end
- assert_raise_with_message(ArgumentError, /\u{4e0d 5b58 5728}/) {
+ exc = assert_raise_kind_of(ArgumentError, SystemCallError) {
Process::UID.from_name("\u{4e0d 5b58 5728}")
}
+ assert_match(/\u{4e0d 5b58 5728}/, exc.message) if exc.is_a?(ArgumentError)
end
end
@@ -1758,15 +1767,12 @@ class TestProcess < Test::Unit::TestCase
end
def test_no_curdir
- if /solaris/i =~ RUBY_PLATFORM
- omit "Temporary omit to avoid CI failures after commit to use realpath on required files"
- end
with_tmpchdir {|d|
Dir.mkdir("vd")
status = nil
Dir.chdir("vd") {
dir = "#{d}/vd"
- # OpenSolaris cannot remove the current directory.
+ # Windows cannot remove the current directory with permission issues.
system(RUBY, "--disable-gems", "-e", "Dir.chdir '..'; Dir.rmdir #{dir.dump}", err: File::NULL)
system({"RUBYLIB"=>nil}, RUBY, "--disable-gems", "-e", "exit true")
status = $?
@@ -1800,9 +1806,6 @@ class TestProcess < Test::Unit::TestCase
end
def test_aspawn_too_long_path
- if /solaris/i =~ RUBY_PLATFORM && !defined?(Process::RLIMIT_NPROC)
- omit "Too exhaustive test on platforms without Process::RLIMIT_NPROC such as Solaris 10"
- end
bug4315 = '[ruby-core:34833] #7904 [ruby-core:52628] #11613'
assert_fail_too_long_path(%w"echo |", bug4315)
end
@@ -1993,7 +1996,7 @@ class TestProcess < Test::Unit::TestCase
end
def test_popen_reopen
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
io = File.open(IO::NULL)
io2 = io.dup
@@ -2384,7 +2387,7 @@ EOS
end
def test_deadlock_by_signal_at_forking
- assert_separately(%W(- #{RUBY}), <<-INPUT, timeout: 100)
+ assert_ruby_status(%W(- #{RUBY}), <<-INPUT, timeout: 100)
ruby = ARGV.shift
GC.start # reduce garbage
GC.disable # avoid triggering CoW after forks
@@ -2771,11 +2774,13 @@ EOS
# Disable GC so we can make sure GC only runs in Process.warmup
GC.disable
- total_slots_before = GC.stat(:heap_available_slots) + GC.stat(:heap_allocatable_slots)
+ total_slots_before = GC.stat(:heap_available_slots) + GC.stat(:heap_allocatable_bytes) / GC.stat_heap(0, :slot_size)
Process.warmup
- assert_equal(total_slots_before, GC.stat(:heap_available_slots) + GC.stat(:heap_allocatable_slots))
+ # TODO: flaky
+ # assert_equal(total_slots_before, GC.stat(:heap_available_slots) + GC.stat(:heap_allocatable_bytes) / GC.stat_heap(0, :slot_size))
+
assert_equal(0, GC.stat(:heap_empty_pages))
assert_operator(GC.stat(:total_freed_pages), :>, 0)
end;
diff --git a/test/ruby/test_ractor.rb b/test/ruby/test_ractor.rb
index ec94df361f..611b3b7715 100644
--- a/test/ruby/test_ractor.rb
+++ b/test/ruby/test_ractor.rb
@@ -3,38 +3,19 @@ require 'test/unit'
class TestRactor < Test::Unit::TestCase
def test_shareability_of_iseq_proc
- y = nil.instance_eval do
+ assert_raise Ractor::IsolationError do
foo = []
- proc { foo }
+ Ractor.shareable_proc{ foo }
end
- assert_unshareable(y, /unshareable object \[\] from variable 'foo'/)
-
- y = [].instance_eval { proc { self } }
- assert_unshareable(y, /Proc's self is not shareable/)
-
- y = [].freeze.instance_eval { proc { self } }
- assert_make_shareable(y)
- end
-
- def test_shareability_of_curried_proc
- x = nil.instance_eval do
- foo = []
- proc { foo }.curry
- end
- assert_unshareable(x, /unshareable object \[\] from variable 'foo'/)
-
- x = nil.instance_eval do
- foo = 123
- proc { foo }.curry
- end
- assert_make_shareable(x)
end
def test_shareability_of_method_proc
+ # TODO: fix with Ractor.shareable_proc/lambda
+=begin
str = +""
x = str.instance_exec { proc { to_s } }
- assert_unshareable(x, /Proc's self is not shareable/)
+ assert_unshareable(x, /Proc\'s self is not shareable/)
x = str.instance_exec { method(:to_s) }
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
@@ -58,6 +39,119 @@ class TestRactor < Test::Unit::TestCase
x = str.instance_exec { method(:itself).to_proc }
assert_unshareable(x, "can not make shareable object for #<Method: String(Kernel)#itself()>", exception: Ractor::Error)
+=end
+ end
+
+ def test_shareable_proc_define_method_super_method_missing
+ assert_ractor(<<~'RUBY', timeout: 30)
+ iterations = 1_000_000
+
+ class SuperFromShareableProcMethodMissingBase
+ def method_missing(mid, *) = mid
+ end
+
+ class SuperFromShareableProcMethodMissingChild < SuperFromShareableProcMethodMissingBase
+ BODY = Ractor.shareable_proc { super() }
+ define_method(:foo, &BODY)
+ define_method(:bar, &BODY)
+ end
+
+ [:foo, :bar].map do |mid|
+ Ractor.new(mid, iterations) do |mid, iterations|
+ obj = SuperFromShareableProcMethodMissingChild.new
+ iterations.times do
+ got = obj.__send__(mid)
+ raise "#{mid} returned #{got.inspect}" unless got == mid
+ end
+ end
+ end.each(&:value)
+ RUBY
+ end
+
+ def test_shareable_proc_define_method_super_method_entry
+ assert_ractor(<<~'RUBY', timeout: 30)
+ iterations = 1_000_000
+
+ class SuperFromShareableProcBase
+ def foo = :foo
+ def bar = :bar
+ end
+
+ class SuperFromShareableProcChild < SuperFromShareableProcBase
+ BODY = Ractor.shareable_proc { super() }
+ define_method(:foo, &BODY)
+ define_method(:bar, &BODY)
+ end
+
+ [:foo, :bar].map do |mid|
+ Ractor.new(mid, iterations) do |mid, iterations|
+ obj = SuperFromShareableProcChild.new
+ iterations.times do
+ got = obj.__send__(mid)
+ raise "#{mid} returned #{got.inspect}" unless got == mid
+ end
+ end
+ end.each(&:value)
+ RUBY
+ end
+
+ def test_shareability_error_uses_inspect
+ x = (+"").instance_exec { method(:to_s) }
+ def x.to_s
+ raise "this should not be called"
+ end
+ assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()> because it refers unshareable objects", exception: Ractor::Error)
+ end
+
+ def test_sending_exception_with_backtrace
+ assert_ractor(<<~'RUBY')
+ def build_error
+ raise "Test"
+ rescue => error
+ error
+ end
+
+ error = build_error
+ refute_empty error.backtrace
+ refute_empty error.backtrace_locations
+
+ backtrace, backtrace_locations = Ractor.new(error) do |error2|
+ [error2.backtrace, error2.backtrace_locations]
+ end.value
+
+ assert_equal error.backtrace, backtrace
+ refute_empty backtrace_locations
+ RUBY
+ end
+
+ def test_sending_exception_with_array_backtrace
+ assert_ractor(<<~'RUBY')
+ error = StandardError.new
+ error.set_backtrace(["foo", "bar"])
+ refute_empty error.backtrace
+ assert_nil error.backtrace_locations
+
+ backtrace, backtrace_locations = Ractor.new(error) do |error2|
+ [error2.backtrace, error2.backtrace_locations]
+ end.value
+
+ assert_equal error.backtrace, backtrace
+ assert_nil backtrace_locations
+ RUBY
+ end
+
+ def test_sending_object_with_broken_clone
+ assert_ractor(<<~'RUBY')
+ o = Object.new
+ def o.clone
+ self
+ end
+ ractor = Ractor.new { Ractor.receive }
+ error = assert_raise Ractor::Error do
+ ractor.send(o)
+ end
+ assert_match "#clone returned self", error.message
+ RUBY
end
def test_default_thread_group
@@ -66,11 +160,207 @@ class TestRactor < Test::Unit::TestCase
Warning[:experimental] = false
main_ractor_id = Thread.current.group.object_id
- ractor_id = Ractor.new { Thread.current.group.object_id }.take
+ ractor_id = Ractor.new { Thread.current.group.object_id }.value
refute_equal main_ractor_id, ractor_id
end;
end
+ def test_class_instance_variables
+ assert_ractor(<<~'RUBY')
+ # Once we're in multi-ractor mode, the codepaths
+ # for class instance variables are a bit different.
+ Ractor.new {}.value
+
+ class TestClass
+ @a = 1
+ @b = 2
+ @c = 3
+ @d = 4
+ end
+
+ assert_equal 4, TestClass.remove_instance_variable(:@d)
+ assert_nil TestClass.instance_variable_get(:@d)
+ assert_equal 4, TestClass.instance_variable_set(:@d, 4)
+ assert_equal 4, TestClass.instance_variable_get(:@d)
+ RUBY
+ end
+
+
+ def test_class_variables
+ # [Bug #22072]
+ assert_ractor(<<~'RUBY')
+ module Foo
+ def self.foo = @@foo
+ end
+
+ Foo.class_variable_set(:@@foo, 1)
+
+ 10.times { |i| Foo.class_variable_set(:"@@bar#{i}", i) }
+
+ assert_equal(Foo.foo, 1)
+ RUBY
+ end
+
+ def test_struct_instance_variables
+ assert_ractor(<<~'RUBY')
+ StructIvar = Struct.new(:member) do
+ def initialize(*)
+ super
+ @ivar = "ivar"
+ end
+ attr_reader :ivar
+ end
+ obj = StructIvar.new("member")
+ obj_copy = Ractor.new { Ractor.receive }.send(obj).value
+ assert_equal obj.ivar, obj_copy.ivar
+ refute_same obj.ivar, obj_copy.ivar
+ assert_equal obj.member, obj_copy.member
+ refute_same obj.member, obj_copy.member
+ RUBY
+ end
+
+ def test_move_nested_hash_during_gc_with_yjit
+ assert_ractor(<<~'RUBY', timeout: 20, args: [{ "RUBY_YJIT_ENABLE" => "1" }])
+ GC.stress = true
+ hash = { foo: { bar: "hello" }, baz: { qux: "there" } }
+ result = Ractor.new { Ractor.receive }.send(hash, move: true).value
+ assert_equal "hello", result[:foo][:bar]
+ assert_equal "there", result[:baz][:qux]
+ RUBY
+ end
+
+ def test_fork_raise_isolation_error
+ assert_ractor(<<~'RUBY')
+ ractor = Ractor.new do
+ Process.fork
+ rescue Ractor::IsolationError => e
+ e
+ end
+ assert_equal Ractor::IsolationError, ractor.value.class
+ RUBY
+ end if Process.respond_to?(:fork)
+
+ def test_require_raises_and_no_ractor_belonging_issue
+ assert_ractor(<<~'RUBY')
+ require "tempfile"
+ f = Tempfile.new(["file_to_require_from_ractor", ".rb"])
+ f.write("raise 'uh oh'")
+ f.flush
+ err_msg = Ractor.new(f.path) do |path|
+ begin
+ require path
+ rescue RuntimeError => e
+ e.message # had confirm belonging issue here
+ else
+ nil
+ end
+ end.value
+ assert_equal "uh oh", err_msg
+ RUBY
+ end
+
+ def test_require_non_string
+ assert_ractor(<<~'RUBY')
+ require "tempfile"
+ require "pathname"
+ f = Tempfile.new(["file_to_require_from_ractor", ".rb"])
+ f.write("")
+ f.flush
+ result = Ractor.new(f.path) do |path|
+ require Pathname.new(path)
+ "success"
+ end.value
+ assert_equal "success", result
+ RUBY
+ end
+
+ # [Bug #21398]
+ def test_port_receive_dnt_with_port_send
+ omit 'unstable on windows and macos-14' if RUBY_PLATFORM =~ /mswin|mingw|darwin/
+ assert_ractor(<<~'RUBY', timeout: 90)
+ THREADS = 10
+ JOBS_PER_THREAD = 50
+ ARRAY_SIZE = 20_000
+ def ractor_job(job_count, array_size)
+ port = Ractor::Port.new
+ workers = (1..4).map do |i|
+ Ractor.new(port) do |job_port|
+ while job = Ractor.receive
+ result = job.map { |x| x * 2 }.sum
+ job_port.send result
+ end
+ end
+ end
+ jobs = Array.new(job_count) { Array.new(array_size) { rand(1000) } }
+ jobs.each_with_index do |job, i|
+ w_idx = i % 4
+ workers[w_idx].send(job)
+ end
+ results = []
+ jobs.size.times do
+ result = port.receive # dnt receive
+ results << result
+ end
+ results
+ end
+ threads = []
+ # creates 40 ractors (THREADSx4)
+ THREADS.times do
+ threads << Thread.new do
+ ractor_job(JOBS_PER_THREAD, ARRAY_SIZE)
+ end
+ end
+ threads.each(&:join)
+ RUBY
+ end
+
+ # [Bug #20146]
+ def test_max_cpu_1
+ assert_ractor(<<~'RUBY', args: [{ "RUBY_MAX_CPU" => "1" }])
+ assert_equal :ok, Ractor.new { :ok }.value
+ RUBY
+ end
+
+ def test_symbol_proc_is_shareable
+ pr = :symbol.to_proc
+ assert_make_shareable(pr)
+ end
+
+ # [Bug #21775]
+ def test_ifunc_proc_not_shareable
+ h = Hash.new { self }
+ pr = h.to_proc
+ assert_unshareable(pr, /not supported yet/, exception: RuntimeError)
+ end
+
+ def test_copy_unshareable_object_error_message
+ assert_ractor(<<~'RUBY')
+ pr = proc {}
+ err = assert_raise(Ractor::Error) do
+ Ractor.new(pr) {}.join
+ end
+ assert_match(/can not copy Proc object/, err.message)
+ RUBY
+ end
+
+ def test_ractor_new_raises_isolation_error_if_outer_variables_are_accessed
+ assert_raise(Ractor::IsolationError) do
+ channel = Ractor::Port.new
+ Ractor.new(channel) do
+ inbound_work = Ractor::Port.new
+ channel << inbound_work
+ end
+ end
+ end
+
+ def test_ractor_new_raises_isolation_error_if_proc_uses_yield
+ assert_raise(Ractor::IsolationError) do
+ Ractor.new do
+ yield
+ end
+ end
+ end
+
def assert_make_shareable(obj)
refute Ractor.shareable?(obj), "object was already shareable"
Ractor.make_shareable(obj)
diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb
index f875c0ab40..ff17dca69e 100644
--- a/test/ruby/test_range.rb
+++ b/test/ruby/test_range.rb
@@ -36,6 +36,7 @@ class TestRange < Test::Unit::TestCase
assert_equal(["a"], ("a" ... "b").to_a)
assert_equal(["a", "b"], ("a" .. "b").to_a)
assert_equal([*"a".."z", "aa"], ("a"..).take(27))
+ assert_equal([*"a".."z"], eval("('a' || 'b')..'z'").to_a)
end
def test_range_numeric_string
@@ -1457,6 +1458,12 @@ class TestRange < Test::Unit::TestCase
assert_raise(RangeError) { (1..).to_a }
end
+ def test_to_set
+ assert_equal(Set[1,2,3,4,5], (1..5).to_set)
+ assert_equal(Set[1,2,3,4], (1...5).to_set)
+ assert_raise(RangeError) { (1..).to_set }
+ end
+
def test_beginless_range_iteration
assert_raise(TypeError) { (..1).each { } }
end
diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb
index 89bb7b20a8..a02e11acc5 100644
--- a/test/ruby/test_rational.rb
+++ b/test/ruby/test_rational.rb
@@ -65,7 +65,7 @@ class Rational_Test < Test::Unit::TestCase
assert_instance_of(String, c.to_s)
end
- def test_conv
+ def test_conv_integer
c = Rational(0,1)
assert_equal(Rational(0,1), c)
@@ -94,6 +94,11 @@ class Rational_Test < Test::Unit::TestCase
c = Rational(Rational(1,2),Rational(1,2))
assert_equal(Rational(1), c)
+ assert_equal(Rational(3),Rational(3))
+ assert_equal(Rational(1),Rational(3,3))
+ end
+
+ def test_conv_complex
c = Rational(Complex(1,2),2)
assert_equal(Complex(Rational(1,2),1), c)
@@ -102,11 +107,21 @@ class Rational_Test < Test::Unit::TestCase
c = Rational(Complex(1,2),Complex(1,2))
assert_equal(Rational(1), c)
+ end
- assert_equal(Rational(3),Rational(3))
- assert_equal(Rational(1),Rational(3,3))
+ def test_conv_float
assert_equal(3.3.to_r,Rational(3.3))
assert_equal(1,Rational(3.3,3.3))
+
+ if (0.0/0).nan?
+ assert_raise(FloatDomainError){Rational(0.0/0)}
+ end
+ if (1.0/0).infinite?
+ assert_raise(FloatDomainError){Rational(1.0/0)}
+ end
+ end
+
+ def test_conv_string
assert_equal(Rational(3),Rational('3'))
assert_equal(Rational(1),Rational('3.0','3.0'))
assert_equal(Rational(1),Rational('3/3','3/3'))
@@ -115,11 +130,19 @@ class Rational_Test < Test::Unit::TestCase
assert_equal(Rational(111, 10), Rational('1.11e1'))
assert_equal(Rational(111, 100), Rational('1.11e0'))
assert_equal(Rational(111, 1000), Rational('1.11e-1'))
+ assert_equal(Rational(5, 4), Rational('3.0r','2.4R'))
+ end
+
+ def test_conv_error
assert_raise(TypeError){Rational(nil)}
assert_raise(ArgumentError){Rational('')}
- assert_raise_with_message(ArgumentError, /\u{221a 2668}/) {
- Rational("\u{221a 2668}")
- }
+
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(ArgumentError, /\u{221a 2668}/) {
+ Rational("\u{221a 2668}")
+ }
+ end
+
assert_warning('') {
assert_predicate(Rational('1e-99999999999999999999'), :zero?)
}
@@ -127,7 +150,9 @@ class Rational_Test < Test::Unit::TestCase
assert_raise(TypeError){Rational(Object.new)}
assert_raise(TypeError){Rational(Object.new, Object.new)}
assert_raise(TypeError){Rational(1, Object.new)}
+ end
+ def test_conv_coerce
bug12485 = '[ruby-core:75995] [Bug #12485]'
o = Object.new
def o.to_int; 1; end
@@ -159,13 +184,6 @@ class Rational_Test < Test::Unit::TestCase
assert_raise(ArgumentError){Rational()}
assert_raise(ArgumentError){Rational(1,2,3)}
- if (0.0/0).nan?
- assert_raise(FloatDomainError){Rational(0.0/0)}
- end
- if (1.0/0).infinite?
- assert_raise(FloatDomainError){Rational(1.0/0)}
- end
-
bug16518 = "[ruby-core:96942] [Bug #16518]"
cls = Class.new(Numeric) do
def /(y); 42; end
@@ -825,6 +843,10 @@ class Rational_Test < Test::Unit::TestCase
ng[5, 3, '5/3x']
ng[5, 1, '5/-3']
+
+ ok[30, 24, '3.0r/2.4R']
+ ng[30, 24, '3.0r/2.4re1']
+ ng[30, 240, '3.0r/2.4e1r']
end
def test_parse_zero_denominator
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index 6ce434790b..dce09c2dd8 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -1035,6 +1035,43 @@ class TestRefinement < Test::Unit::TestCase
RUBY
end
+ def test_prohibit_super_in_refined_module_method
+ assert_separately([], <<-"end;")
+ bug22071 = '[ruby-core:125511] [Bug #22071]'
+ class BasicObject
+ def a; "B" end
+ end
+
+ module G
+ def a; "G" + super end
+ end
+
+ module F
+ include G
+ def a; "F" + super end
+ end
+
+ class A
+ def a; "A" + super end
+ end
+
+ class B < A
+ include F
+ end
+
+ module R
+ refine F do
+ def a; "R"+super end
+ end
+ end
+ using R
+
+ msg = "super in a method in a module that has been refined and that is called via super" +
+ " from a refinement method is not supported."
+ assert_raise(NoMethodError, msg, bug22071) { B.new.a }
+ end;
+ end
+
def test_refine_after_using
assert_separately([], <<-"end;")
bug8880 = '[ruby-core:57079] [Bug #8880]'
@@ -1058,6 +1095,613 @@ class TestRefinement < Test::Unit::TestCase
end;
end
+ {
+ zsuper: "public :a",
+ super: "def a = super"
+ }.each do |desc, method_def|
+ define_method :"test_modify_#{desc}_refinement_method_in_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ alias a a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ class A
+ def a = :b
+ end
+ assert_equal(:b, B.new.a)
+ end;
+ end
+
+ define_method :"test_modify_#{desc}_refinement_method_in_module_prepended_to_superclass" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :a
+ alias a a
+ end
+
+ class A
+ prepend M
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ module M
+ def a = :b
+ end
+ assert_equal(:b, B.new.a)
+ end;
+ end
+
+ define_method :"test_modify_#{desc}_refinement_method_in_module_included_in_superclass" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :a
+ alias a a
+ end
+
+ class A
+ include M
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ module M
+ def a = :b
+ end
+ assert_equal(:b, B.new.a)
+ end;
+ end
+
+ define_method :"test_remove_#{desc}_refinement_method_from_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ private def a = :b
+ end
+
+ class C < B
+ end
+
+ module R
+ refine C do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, C.new.a)
+
+ class B
+ remove_method(:a)
+ end
+ assert_equal(:a, C.new.a)
+ end;
+ end
+
+ define_method :"test_remove_#{desc}_refinement_method_from_module_prepended_to_superclass" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ prepend M
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, B.new.a)
+
+ module M
+ remove_method(:a)
+ end
+ assert_equal(:a, B.new.a)
+ end;
+ end
+
+ define_method :"test_remove_#{desc}_refinement_method_from_module_prepended_to_class" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ prepend M
+ private def a = :a
+ end
+
+ module R
+ refine A do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, A.new.a)
+
+ module M
+ remove_method(:a)
+ end
+ assert_equal(:a, A.new.a)
+ end;
+ end
+
+ define_method :"test_remove_#{desc}_refinement_method_from_module_included_in_superclass" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ include M
+ end
+
+ class C < B
+ end
+
+ module R
+ refine C do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, C.new.a)
+
+ module M
+ remove_method(:a)
+ end
+ assert_equal(:a, C.new.a)
+ end;
+ end
+
+ define_method :"test_remove_#{desc}_refinement_method_from_module_included_in_class" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ include M
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, B.new.a)
+
+ module M
+ remove_method(:a)
+ end
+ assert_equal(:a, B.new.a)
+ end;
+ end
+
+ define_method :"test_undef_#{desc}_refinement_method_in_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ private def a = :b
+ end
+
+ class C < B
+ end
+
+ module R
+ refine C do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, C.new.a)
+
+ class B
+ undef_method(:a)
+ end
+ assert_raise(NoMethodError) { C.new.a }
+ end;
+ end
+
+ define_method :"test_undef_#{desc}_refinement_method_in_module_prepended_to_superclass" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ prepend M
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, B.new.a)
+
+ module M
+ undef_method(:a)
+ end
+ assert_raise(NoMethodError) { B.new.a }
+ end;
+ end
+
+ define_method :"test_undef_#{desc}_refinement_method_in_module_prepended_to_class" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ prepend M
+ private def a = :a
+ end
+
+ module R
+ refine A do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, A.new.a)
+
+ module M
+ undef_method(:a)
+ end
+ assert_raise(NoMethodError) { A.new.a }
+ end;
+ end
+
+ define_method :"test_undef_#{desc}_refinement_method_in_module_included_in_superclass" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ include M
+ end
+
+ class C < B
+ end
+
+ module R
+ refine C do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, C.new.a)
+
+ module M
+ undef_method(:a)
+ end
+ assert_raise(NoMethodError) { C.new.a }
+ end;
+ end
+
+ define_method :"test_undef_#{desc}_refinement_method_in_module_included_in_class" do
+ assert_separately([], <<-"end;")
+ module M
+ private def a = :b
+ end
+
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ include M
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:b, B.new.a)
+
+ module M
+ undef_method(:a)
+ end
+ assert_raise(NoMethodError) { B.new.a }
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_prepending_to_class" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ module R
+ refine A do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, A.new.a)
+
+ module M
+ def a = :b
+ end
+ A.prepend M
+ assert_equal(:b, A.new.a)
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_prepending_to_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ module M
+ def a = :b
+ end
+ A.prepend M
+ assert_equal(:b, B.new.a)
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_including_in_class" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ module M
+ def a = :b
+ end
+ B.include M
+ assert_equal(:b, B.new.a)
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_including_in_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ class C < B
+ end
+
+ module R
+ refine C do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, C.new.a)
+
+ module M
+ def a = :b
+ end
+ B.include M
+ assert_equal(:b, C.new.a)
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_prepending_undef_to_class" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ module R
+ refine A do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, A.new.a)
+
+ module M
+ def a = :b
+ undef_method :a
+ end
+ A.prepend M
+ assert_raise(NoMethodError) { A.new.a }
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_prepending_undef_to_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ module M
+ def a = :b
+ undef_method :a
+ end
+ A.prepend M
+ assert_raise(NoMethodError) { B.new.a }
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_including_undef_in_class" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ module R
+ refine B do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, B.new.a)
+
+ module M
+ def a = :b
+ undef_method :a
+ end
+ B.include M
+ assert_raise(NoMethodError) { B.new.a }
+ end;
+ end
+
+ define_method :"test_override_#{desc}_refinement_method_by_including_undef_in_superclass" do
+ assert_separately([], <<-"end;")
+ class A
+ private def a = :a
+ end
+
+ class B < A
+ end
+
+ class C < B
+ end
+
+ module R
+ refine C do
+ #{method_def}
+ end
+ end
+ using R
+ assert_equal(:a, C.new.a)
+
+ module M
+ def a = :b
+ undef_method :a
+ end
+ B.include M
+ assert_raise(NoMethodError) { C.new.a }
+ end;
+ end
+ end
+
+ def test_zsuper_refinement_method_arity_and_parameters
+ assert_separately([], <<-"end;")
+ class A
+ private def a(b) = b
+ end
+
+ class B < A
+ public :a
+ end
+
+ module R
+ refine A do
+ public :a
+ end
+ end
+ using R
+
+ m = B.instance_method(:a)
+ assert_equal(1, m.arity)
+ assert_equal([[:req, :b]], m.parameters)
+
+ m = A.instance_method(:a)
+ assert_equal(1, m.arity)
+ assert_equal([[:req, :b]], m.parameters)
+ end;
+ end
+
def test_instance_methods
bug8881 = '[ruby-core:57080] [Bug #8881]'
assert_not_include(Foo.instance_methods(false), :z, bug8881)
@@ -1933,6 +2577,29 @@ class TestRefinement < Test::Unit::TestCase
end;
end
+ def test_public_in_refine_for_method_in_superclass
+ assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ bug21446 = '[ruby-core:122558] [Bug #21446]'
+
+ class CowSuper
+ private
+ def moo() "Moo"; end
+ end
+ class Cow < CowSuper
+ end
+
+ module PublicCows
+ refine(Cow) {
+ public :moo
+ }
+ end
+
+ using PublicCows
+ assert_equal("Moo", Cow.new.moo, bug21446)
+ end;
+ end
+
module SuperToModule
class Parent
end
@@ -2232,7 +2899,7 @@ class TestRefinement < Test::Unit::TestCase
def test_refining_module_repeatedly
bug14070 = '[ruby-core:83617] [Bug #14070]'
- assert_in_out_err([], <<-INPUT, ["ok"], [], bug14070)
+ assert_in_out_err([], <<-INPUT, ["ok"], [], bug14070, timeout: 30)
1000.times do
Class.new do
include Enumerable
@@ -2712,6 +3379,287 @@ class TestRefinement < Test::Unit::TestCase
INPUT
end
+ def test_refined_module_method
+ m = Module.new {
+ x = Module.new {def qux;end}
+ refine(x) {def qux;end}
+ break x
+ }
+ extend m
+ meth = method(:qux)
+ assert_equal m, meth.owner
+ assert_equal :qux, meth.name
+ end
+
+ def test_symbol_proc_from_using_scope
+ # assert_separately to contain the side effects of refining Kernel
+ assert_separately([], <<~RUBY)
+ class RefinedScope
+ using(Module.new { refine(Kernel) { def itself = 0 } })
+ ITSELF = :itself.to_proc
+ end
+
+ assert_equal(1, RefinedScope::ITSELF[1], "[Bug #21265]")
+ RUBY
+ end
+
+ def test_method_super_method_single_refinements
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ using M
+ a = A.new
+ m = a.method(:b)
+ assert_equal("MA", a.b)
+ assert_equal("MA", m.call)
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_method_super_method_multiple_refinements_with_activated_refinements_during_super
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ module N
+ using M
+ R = refine(A) { def b; "N" + super; end }
+ end
+ using M
+ using N
+ a = A.new
+ m = a.method(:b)
+ assert_equal("NMA", a.b)
+ assert_equal("NMA", m.call)
+ assert_equal(N::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_method_super_method_multiple_refinements_without_activated_refinements_during_super
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ module N
+ R = refine(A) { def b; "N" + super; end }
+ end
+ using M
+ using N
+ a = A.new
+ m = a.method(:b)
+ assert_equal("NA", a.b)
+ assert_equal("NA", m.call)
+ assert_equal(N::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_unbound_method_super_method_single_refinements
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ using M
+ m = A.instance_method(:b)
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_method_super_method_nonrefined_finds_refined_super
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ using M
+ class B < A
+ def b = "B" + super
+ end
+ b = B.new
+ m = b.method(:b)
+ assert_equal("BMA", b.b)
+ assert_equal("BMA", m.call)
+ assert_equal(B, m.owner)
+ m = m.super_method
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_method_super_method_refined_finds_refined_method_in_superclass
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ class B < A
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ using M
+ module N
+ R = refine(B) { def b; "N" + super; end }
+ end
+ using N
+
+ b = B.new
+ m = b.method(:b)
+ assert_equal("NMA", b.b)
+ assert_equal("NMA", m.call)
+ assert_equal(N::R, m.owner)
+ assert_equal(B, m.owner.target)
+
+ m = m.super_method
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_method_super_method_uses_cref_of_method_not_cref_of_caller
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ class B < A
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ module N
+ R = refine(B) do
+ using M
+ def b; "N" + super; end
+ end
+ end
+ using N
+
+ b = B.new
+ m = b.method(:b)
+ assert_equal("NMA", b.b)
+ assert_equal("NMA", m.call)
+ assert_equal(N::R, m.owner)
+ assert_equal(B, m.owner.target)
+
+ m = m.super_method
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
+ def test_method_super_method_only_considers_activated_refinements
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ class B < A
+ def b = "B" + super
+ end
+ module M
+ R = refine(A){def b = "M" + super}
+ end
+ module N
+ R = refine(B){def b = "N" + super}
+ end
+
+ module O
+ using M
+ using N
+
+ b = B.new
+ m = b.method(:b)
+ assert_equal("NBA", b.b)
+ assert_equal("NBA", m.call)
+ assert_equal(N::R, m.owner)
+ assert_equal(B, m.owner.target)
+
+ m = m.super_method
+ assert_equal(B, m.owner)
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ end
+ RUBY
+ end
+
+ def test_method_super_method_bmethod_finds_refinements
+ assert_separately([], <<~RUBY)
+ class A
+ def b = "A"
+ end
+ module M
+ R = refine(A) { def b; "M" + super; end }
+ end
+ using M
+ class B < A
+ define_method(:b) { "B" + super() }
+ end
+
+ b = B.new
+ m = b.method(:b)
+ assert_equal("BMA", b.b)
+ assert_equal("BMA", m.call)
+ assert_equal(B, m.owner)
+
+ m = m.super_method
+ assert_equal(M::R, m.owner)
+ assert_equal(A, m.owner.target)
+
+ m = m.super_method
+ assert_equal(A, m.owner)
+ assert_nil(m.super_method)
+ RUBY
+ end
+
private
def eval_using(mod, s)
diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb
index b1ae039009..805c57b472 100644
--- a/test/ruby/test_regexp.rb
+++ b/test/ruby/test_regexp.rb
@@ -975,7 +975,7 @@ class TestRegexp < Test::Unit::TestCase
def test_dup
assert_equal(//, //.dup)
- assert_raise(TypeError) { //.dup.instance_eval { initialize_copy(nil) } }
+ assert_raise(FrozenError) { //.dup.instance_eval { initialize_copy(/a/) } }
end
def test_regsub
@@ -1011,6 +1011,18 @@ class TestRegexp < Test::Unit::TestCase
end;
end
+ def test_regsub_no_memory_leak_many_captures
+ assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~"end;"}", rss: true)
+ code = proc do
+ "aaaaaaaaaaa".gsub(/(a)(b)?(c)?(d)?(e)?(f)?(g)?(h)?/, "")
+ end
+
+ 1_000.times(&code)
+ begin;
+ 100_000.times(&code)
+ end;
+ end
+
def test_ignorecase
v = assert_deprecated_warning(/variable \$= is no longer effective/) { $= }
assert_equal(false, v)
@@ -1036,10 +1048,12 @@ class TestRegexp < Test::Unit::TestCase
[Encoding::UTF_8, Encoding::Shift_JIS, Encoding::EUC_JP].each do |enc|
idx = key.encode(enc)
pat = /#{idx}/
- test.call {|m| assert_raise_with_message(IndexError, pat, bug10877) {m[idx]} }
- test.call {|m| assert_raise_with_message(IndexError, pat, bug18160) {m.offset(idx)} }
- test.call {|m| assert_raise_with_message(IndexError, pat, bug18160) {m.begin(idx)} }
- test.call {|m| assert_raise_with_message(IndexError, pat, bug18160) {m.end(idx)} }
+ EnvUtil.with_default_internal(enc) do
+ test.call {|m| assert_raise_with_message(IndexError, pat, bug10877) {m[idx]} }
+ test.call {|m| assert_raise_with_message(IndexError, pat, bug18160) {m.offset(idx)} }
+ test.call {|m| assert_raise_with_message(IndexError, pat, bug18160) {m.begin(idx)} }
+ test.call {|m| assert_raise_with_message(IndexError, pat, bug18160) {m.end(idx)} }
+ end
end
test.call {|m| assert_equal(/a/, m.regexp) }
test.call {|m| assert_equal("abc", m.string) }
@@ -1308,6 +1322,9 @@ class TestRegexp < Test::Unit::TestCase
assert_match(/\A[[:space:]]+\z/, "\r\n\v\f\r\s\u0085")
assert_match(/\A[[:ascii:]]+\z/, "\x00\x7F")
assert_no_match(/[[:ascii:]]/, "\x80\xFF")
+
+ assert_match(/[[:word:]]/, "\u{200C}")
+ assert_match(/[[:word:]]/, "\u{200D}")
end
def test_cclass_R
@@ -1524,6 +1541,107 @@ class TestRegexp < Test::Unit::TestCase
"CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D")
end
+ def test_unicode_age_16_0
+ @matches = %w"16.0"
+ @unmatches = %w"15.1"
+
+ # https://www.unicode.org/Public/16.0.0/ucd/DerivedAge.txt
+ assert_unicode_age("\u{0897}",
+ "ARABIC PEPET")
+ assert_unicode_age("\u{1B4E}".."\u{1B4F}",
+ "BALINESE INVERTED CARIK SIKI..BALINESE INVERTED CARIK PAREREN")
+ assert_unicode_age("\u{1B7F}",
+ "BALINESE PANTI BAWAK")
+ assert_unicode_age("\u{1C89}".."\u{1C8A}",
+ "CYRILLIC CAPITAL LETTER TJE..CYRILLIC SMALL LETTER TJE")
+ assert_unicode_age("\u{2427}".."\u{2429}",
+ "SYMBOL FOR DELETE SQUARE CHECKER BOARD FORM..SYMBOL FOR DELETE MEDIUM SHADE FORM")
+ assert_unicode_age("\u{31E4}".."\u{31E5}",
+ "CJK STROKE HXG..CJK STROKE SZP")
+ assert_unicode_age("\u{A7CB}".."\u{A7CD}",
+ "LATIN CAPITAL LETTER RAMS HORN..LATIN SMALL LETTER S WITH DIAGONAL STROKE")
+ assert_unicode_age("\u{A7DA}".."\u{A7DC}",
+ "LATIN CAPITAL LETTER LAMBDA..LATIN CAPITAL LETTER LAMBDA WITH STROKE")
+ assert_unicode_age("\u{105C0}".."\u{105F3}",
+ "TODHRI LETTER A..TODHRI LETTER OO")
+ assert_unicode_age("\u{10D40}".."\u{10D65}",
+ "GARAY DIGIT ZERO..GARAY CAPITAL LETTER OLD NA")
+ assert_unicode_age("\u{10D69}".."\u{10D85}",
+ "GARAY VOWEL SIGN E..GARAY SMALL LETTER OLD NA")
+ assert_unicode_age("\u{10D8E}".."\u{10D8F}",
+ "GARAY PLUS SIGN..GARAY MINUS SIGN")
+ assert_unicode_age("\u{10EC2}".."\u{10EC4}",
+ "ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW")
+ assert_unicode_age("\u{10EFC}",
+ "ARABIC COMBINING ALEF OVERLAY")
+ assert_unicode_age("\u{11380}".."\u{11389}",
+ "TULU-TIGALARI LETTER A..TULU-TIGALARI LETTER VOCALIC LL")
+ assert_unicode_age("\u{1138B}",
+ "TULU-TIGALARI LETTER EE")
+ assert_unicode_age("\u{1138E}",
+ "TULU-TIGALARI LETTER AI")
+ assert_unicode_age("\u{11390}".."\u{113B5}",
+ "TULU-TIGALARI LETTER OO..TULU-TIGALARI LETTER LLLA")
+ assert_unicode_age("\u{113B7}".."\u{113C0}",
+ "TULU-TIGALARI SIGN AVAGRAHA..TULU-TIGALARI VOWEL SIGN VOCALIC LL")
+ assert_unicode_age("\u{113C2}",
+ "TULU-TIGALARI VOWEL SIGN EE")
+ assert_unicode_age("\u{113C5}",
+ "TULU-TIGALARI VOWEL SIGN AI")
+ assert_unicode_age("\u{113C7}".."\u{113CA}",
+ "TULU-TIGALARI VOWEL SIGN OO..TULU-TIGALARI SIGN CANDRA ANUNASIKA")
+ assert_unicode_age("\u{113CC}".."\u{113D5}",
+ "TULU-TIGALARI SIGN ANUSVARA..TULU-TIGALARI DOUBLE DANDA")
+ assert_unicode_age("\u{113D7}".."\u{113D8}",
+ "TULU-TIGALARI SIGN OM PUSHPIKA..TULU-TIGALARI SIGN SHRII PUSHPIKA")
+ assert_unicode_age("\u{113E1}".."\u{113E2}",
+ "TULU-TIGALARI VEDIC TONE SVARITA..TULU-TIGALARI VEDIC TONE ANUDATTA")
+ assert_unicode_age("\u{116D0}".."\u{116E3}",
+ "MYANMAR PAO DIGIT ZERO..MYANMAR EASTERN PWO KAREN DIGIT NINE")
+ assert_unicode_age("\u{11BC0}".."\u{11BE1}",
+ "SUNUWAR LETTER DEVI..SUNUWAR SIGN PVO")
+ assert_unicode_age("\u{11BF0}".."\u{11BF9}",
+ "SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE")
+ assert_unicode_age("\u{11F5A}",
+ "KAWI SIGN NUKTA")
+ assert_unicode_age("\u{13460}".."\u{143FA}",
+ "EGYPTIAN HIEROGLYPH-13460..EGYPTIAN HIEROGLYPH-143FA")
+ assert_unicode_age("\u{16100}".."\u{16139}",
+ "GURUNG KHEMA LETTER A..GURUNG KHEMA DIGIT NINE")
+ assert_unicode_age("\u{16D40}".."\u{16D79}",
+ "KIRAT RAI SIGN ANUSVARA..KIRAT RAI DIGIT NINE")
+ assert_unicode_age("\u{18CFF}",
+ "KHITAN SMALL SCRIPT CHARACTER-18CFF")
+ assert_unicode_age("\u{1CC00}".."\u{1CCF9}",
+ "UP-POINTING GO-KART..OUTLINED DIGIT NINE")
+ assert_unicode_age("\u{1CD00}".."\u{1CEB3}",
+ "BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET")
+ assert_unicode_age("\u{1E5D0}".."\u{1E5FA}",
+ "OL ONAL LETTER O..OL ONAL DIGIT NINE")
+ assert_unicode_age("\u{1E5FF}",
+ "OL ONAL ABBREVIATION SIGN")
+ assert_unicode_age("\u{1F8B2}".."\u{1F8BB}",
+ "RIGHTWARDS ARROW WITH LOWER HOOK..SOUTH WEST ARROW FROM BAR")
+ assert_unicode_age("\u{1F8C0}".."\u{1F8C1}",
+ "LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW")
+ assert_unicode_age("\u{1FA89}",
+ "HARP")
+ assert_unicode_age("\u{1FA8F}",
+ "SHOVEL")
+ assert_unicode_age("\u{1FABE}",
+ "LEAFLESS TREE")
+ assert_unicode_age("\u{1FAC6}",
+ "FINGERPRINT")
+ assert_unicode_age("\u{1FADC}",
+ "ROOT VEGETABLE")
+ assert_unicode_age("\u{1FADF}",
+ "SPLATTER")
+ assert_unicode_age("\u{1FAE9}",
+ "FACE WITH BAGS UNDER EYES")
+ assert_unicode_age("\u{1FBCB}".."\u{1FBEF}",
+ "WHITE CROSS MARK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE")
+ end
+
UnicodeAgeRegexps = Hash.new do |h, age|
h[age] = [/\A\p{age=#{age}}+\z/u, /\A\P{age=#{age}}+\z/u].freeze
end
@@ -1563,6 +1681,65 @@ class TestRegexp < Test::Unit::TestCase
assert_equal("hoge fuga", h["body"])
end
+ def test_matchdata_large_capture_groups_stack
+ env = {"RUBY_THREAD_MACHINE_STACK_SIZE" => (256 * 1024).to_s}
+ assert_separately([env], <<~'RUBY')
+ n = 20000
+ require "rbconfig/sizeof"
+ stack = RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]
+ size = RbConfig::SIZEOF["long"]
+ required = (n + 1) * 4 * size
+ if !stack || stack == 0 || stack >= required
+ omit "thread machine stack size not reduced (#{stack}:#{required})"
+ end
+
+ inspect = Thread.new do
+ str = "\u{3042}" * n
+ m = Regexp.new("(.)" * n).match(str)
+ assert_not_nil(m)
+ assert_equal([n - 1, n], m.offset(n))
+ m.inspect
+ end.value
+
+ assert_include(inspect, "MatchData")
+ RUBY
+ end
+
+ def test_match_integer_at
+ m = /(\d{4})(\d{2})(\d{2})/.match("20260308")
+ assert_equal(20260308, m.integer_at(0))
+ assert_equal(2026, m.integer_at(1))
+ assert_equal(3, m.integer_at(2))
+ assert_equal(8, m.integer_at(3))
+ assert_equal(nil, m.integer_at(4))
+ assert_equal(8, m.integer_at(-1))
+ assert_equal(3, m.integer_at(-2))
+ assert_equal(2026, m.integer_at(-3))
+ assert_equal(nil, m.integer_at(-4))
+
+ re = /[a-z]+|(\d+)/
+ assert_equal(123, re.match("123").integer_at(1))
+ assert_equal(nil, re.match("abc").integer_at(1))
+ end
+
+ def test_match_integer_at_name
+ m = /(?<y>\d{4})(?<m>\d{2})(?<d>\d{2})/.match("20260308")
+ assert_equal(2026, m.integer_at("y"))
+ assert_equal(3, m.integer_at("m"))
+ assert_equal(8, m.integer_at("d"))
+ end
+
+ def test_match_integer_at_base
+ assert_equal(91, /\w+/.match("111").integer_at(0, 9))
+ assert_equal(10_0000, /\w+/.match("10_0000").integer_at(0))
+ assert_equal(0d1_0000, /\w+/.match("01_0000").integer_at(0))
+ assert_equal(0o1_0000, /\w+/.match("01_0000").integer_at(0, 0))
+ assert_equal(0b1_0000, /\w+/.match("0b1_0000").integer_at(0, 0))
+ assert_equal(0o1_0000, /\w+/.match("0o1_0000").integer_at(0, 0))
+ assert_equal(0d1_0000, /\w+/.match("0d1_0000").integer_at(0, 0))
+ assert_equal(0x1_0000, /\w+/.match("0x1_0000").integer_at(0, 0))
+ end
+
def test_regexp_popped
EnvUtil.suppress_warning do
assert_nothing_raised { eval("a = 1; /\#{ a }/; a") }
@@ -1637,6 +1814,33 @@ class TestRegexp < Test::Unit::TestCase
assert_raise(RegexpError, bug12418){ Regexp.new('(0?0|(?(5)||)|(?(5)||))?') }
end
+ def test_quick_search
+ assert_match_at('(?i) *TOOKY', 'Mozilla/5.0 (Linux; Android 4.0.3; TOOKY', [[34, 40]]) # Issue #120
+ end
+
+ def test_ss_in_look_behind
+ assert_match_at("(?i:ss)", "ss", [[0, 2]])
+ assert_match_at("(?i:ss)", "Ss", [[0, 2]])
+ assert_match_at("(?i:ss)", "SS", [[0, 2]])
+ assert_match_at("(?i:ss)", "\u017fS", [[0, 2]]) # LATIN SMALL LETTER LONG S
+ assert_match_at("(?i:ss)", "s\u017f", [[0, 2]])
+ assert_match_at("(?i:ss)", "\u00df", [[0, 1]]) # LATIN SMALL LETTER SHARP S
+ assert_match_at("(?i:ss)", "\u1e9e", [[0, 1]]) # LATIN CAPITAL LETTER SHARP S
+ assert_match_at("(?i:xssy)", "xssy", [[0, 4]])
+ assert_match_at("(?i:xssy)", "xSsy", [[0, 4]])
+ assert_match_at("(?i:xssy)", "xSSy", [[0, 4]])
+ assert_match_at("(?i:xssy)", "x\u017fSy", [[0, 4]])
+ assert_match_at("(?i:xssy)", "xs\u017fy", [[0, 4]])
+ assert_match_at("(?i:xssy)", "x\u00dfy", [[0, 3]])
+ assert_match_at("(?i:xssy)", "x\u1e9ey", [[0, 3]])
+ assert_match_at("(?i:\u00df)", "ss", [[0, 2]])
+ assert_match_at("(?i:\u00df)", "SS", [[0, 2]])
+ assert_match_at("(?i:[\u00df])", "ss", [[0, 2]])
+ assert_match_at("(?i:[\u00df])", "SS", [[0, 2]])
+ assert_match_at("(?i)(?<!ss)\u2728", "qq\u2728", [[2, 3]]) # Issue #92
+ assert_match_at("(?i)(?<!xss)\u2728", "qq\u2728", [[2, 3]])
+ end
+
def test_options_in_look_behind
assert_nothing_raised {
assert_match_at("(?<=(?i)ab)cd", "ABcd", [[2,4]])
@@ -1774,6 +1978,12 @@ class TestRegexp < Test::Unit::TestCase
end;
end
+ def test_too_big_number_for_repeat_range
+ assert_raise_with_message(SyntaxError, /too big number for repeat range/) do
+ eval(%[/|{1000000}/])
+ end
+ end
+
# This assertion is for porting x2() tests in testpy.py of Onigmo.
def assert_match_at(re, str, positions, msg = nil)
re = Regexp.new(re) unless re.is_a?(Regexp)
@@ -1837,6 +2047,7 @@ class TestRegexp < Test::Unit::TestCase
Regexp.timeout = 1e300
assert_equal(((1<<64)-1) / 1000000000.0, Regexp.timeout)
+ assert_raise(ArgumentError) { Regexp.timeout = Float::NAN }
assert_raise(ArgumentError) { Regexp.timeout = 0 }
assert_raise(ArgumentError) { Regexp.timeout = -1 }
@@ -1878,7 +2089,7 @@ class TestRegexp < Test::Unit::TestCase
end
def per_instance_redos_test(global_timeout, per_instance_timeout, expected_timeout)
- assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
+ assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}", timeout: 60)
global_timeout = #{ EnvUtil.apply_timeout_scale(global_timeout).inspect }
per_instance_timeout = #{ (per_instance_timeout ? EnvUtil.apply_timeout_scale(per_instance_timeout) : nil).inspect }
expected_timeout = #{ EnvUtil.apply_timeout_scale(expected_timeout).inspect }
@@ -1929,6 +2140,7 @@ class TestRegexp < Test::Unit::TestCase
assert_equal(((1<<64)-1) / 1000000000.0, Regexp.new("foo", timeout: 1e300).timeout)
+ assert_raise(ArgumentError) { Regexp.new("foo", timeout: Float::NAN) }
assert_raise(ArgumentError) { Regexp.new("foo", timeout: 0) }
assert_raise(ArgumentError) { Regexp.new("foo", timeout: -1) }
end;
@@ -2152,4 +2364,16 @@ class TestRegexp < Test::Unit::TestCase
assert_match(/[x#{e_acute_lower}]/i, "CAF#{e_acute_upper}", "should match e acute case insensitive")
end
end
+
+ def test_too_many_range_repeat
+ source = '(?:foobar){0,100}' * 100000
+ assert_raise(RegexpError) { Regexp.new(source) }
+ assert_raise(SyntaxError) { eval("/#{source}/") }
+ end
+
+ def test_too_many_null_check
+ source = '(?:(?:foo)?|(?:bar)?)*' * 100000
+ assert_raise(RegexpError) { Regexp.new(source) }
+ assert_raise(SyntaxError) { eval("/#{source}/") }
+ end
end
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index 13e7076391..eed8e97da8 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -54,7 +54,7 @@ class TestRequire < Test::Unit::TestCase
end;
begin
- assert_in_out_err(["-S", "-w", "foo/" * 1024 + "foo"], "") do |r, e|
+ assert_in_out_err(["-S", "-w", (["foo"] * 1025).join("_")], "") do |r, e|
assert_equal([], r)
assert_operator(2, :<=, e.size)
assert_match(/warning: openpath: pathname too long \(ignored\)/, e.first)
@@ -840,6 +840,36 @@ class TestRequire < Test::Unit::TestCase
p :ok
end;
}
+
+ # [Bug #21567]
+ assert_ruby_status(%w[-rtempfile], "#{<<~"begin;"}\n#{<<~"end;"}")
+ begin;
+ class MyString
+ def initialize(path)
+ @path = path
+ end
+
+ def to_str
+ $LOADED_FEATURES.clear
+ @path
+ end
+
+ def to_path = @path
+ end
+
+ FILES = []
+
+ def create_ruby_file
+ file = Tempfile.open(["test", ".rb"])
+ FILES << file
+ file.path
+ end
+
+ require MyString.new(create_ruby_file)
+ $LOADED_FEATURES.unshift(create_ruby_file)
+ $LOADED_FEATURES << MyString.new(create_ruby_file)
+ require create_ruby_file
+ end;
end
def test_loading_fifo_threading_raise
@@ -999,7 +1029,7 @@ class TestRequire < Test::Unit::TestCase
def test_require_with_public_method_missing
# [Bug #19793]
- assert_separately(["-W0", "-rtempfile"], __FILE__, __LINE__, <<~RUBY, timeout: 60)
+ assert_ruby_status(["-W0", "-rtempfile"], <<~RUBY, timeout: 60)
GC.stress = true
class Object
@@ -1011,4 +1041,18 @@ class TestRequire < Test::Unit::TestCase
end
RUBY
end
+
+ def test_bug_21568
+ load_path = $LOAD_PATH.dup
+ loaded_featrures = $LOADED_FEATURES.dup
+
+ $LOAD_PATH.clear
+ $LOADED_FEATURES.replace(["foo.so", "a/foo.rb", "b/foo.rb"])
+
+ assert_nothing_raised(LoadError) { require "foo" }
+
+ ensure
+ $LOAD_PATH.replace(load_path) if load_path
+ $LOADED_FEATURES.replace loaded_featrures
+ end
end
diff --git a/test/ruby/test_require_lib.rb b/test/ruby/test_require_lib.rb
index 81c2fdf833..44dfbcf9ec 100644
--- a/test/ruby/test_require_lib.rb
+++ b/test/ruby/test_require_lib.rb
@@ -13,7 +13,7 @@ class TestRequireLib < Test::Unit::TestCase
scripts.concat(Dir.glob(dirs.map {|d| d + '/*.rb'}, base: libdir).map {|f| f.chomp('.rb')})
# skip some problems
- scripts -= %w[bundler bundled_gems rubygems mkmf]
+ scripts -= %w[bundler bundled_gems rubygems mkmf set/sorted_set]
scripts.each do |lib|
define_method "test_thread_size:#{lib}" do
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index d7184f1057..4a31f91b4a 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -8,8 +8,6 @@ require_relative '../lib/jit_support'
require_relative '../lib/parser_support'
class TestRubyOptions < Test::Unit::TestCase
- def self.yjit_enabled? = defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
-
# Here we're defining our own RUBY_DESCRIPTION without "+PRISM". We do this
# here so that the various tests that reference RUBY_DESCRIPTION don't have to
# worry about it. The flag itself is tested in its own test.
@@ -22,8 +20,10 @@ class TestRubyOptions < Test::Unit::TestCase
NO_JIT_DESCRIPTION =
case
- when yjit_enabled?
- RUBY_DESCRIPTION.sub(/\+YJIT( (dev|dev_nodebug|stats))? /, '')
+ when JITSupport.yjit_enabled?
+ RUBY_DESCRIPTION.sub(/\+YJIT( \w+)? /, '')
+ when JITSupport.zjit_enabled?
+ RUBY_DESCRIPTION.sub(/\+ZJIT( \w+)? /, '')
else
RUBY_DESCRIPTION
end
@@ -47,10 +47,15 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err([], "", [], [])
end
+ # This constant enforces the traditional 80x25 terminal size standard
+ TRADITIONAL_TERM_COLS = 80 # DO NOT MODIFY!
+ TRADITIONAL_TERM_ROWS = 25 # DO NOT MODIFY!
+
def test_usage
+ # This test checks if the output of `ruby -h` fits in 80x25
assert_in_out_err(%w(-h)) do |r, e|
- assert_operator(r.size, :<=, 25)
- longer = r[1..-1].select {|x| x.size >= 80}
+ assert_operator(r.size, :<=, TRADITIONAL_TERM_ROWS)
+ longer = r[1..-1].select {|x| x.size >= TRADITIONAL_TERM_COLS}
assert_equal([], longer)
assert_equal([], e)
end
@@ -174,7 +179,7 @@ class TestRubyOptions < Test::Unit::TestCase
def test_verbose
assert_in_out_err([{'RUBY_YJIT_ENABLE' => nil}, "-vve", ""]) do |r, e|
assert_match(VERSION_PATTERN, r[0])
- if self.class.yjit_enabled? && !JITSupport.yjit_force_enabled?
+ if (JITSupport.yjit_enabled? && !JITSupport.yjit_force_enabled?) || JITSupport.zjit_enabled?
assert_equal(NO_JIT_DESCRIPTION, r[0])
else
assert_equal(RUBY_DESCRIPTION, r[0])
@@ -203,6 +208,8 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [],
/unknown argument for --enable: 'foobarbazqux'/)
assert_in_out_err(%w(--enable), "", [], /missing argument for --enable/)
+ assert_in_out_err(%w(-e) + ['p defined? Gem'], "", %w["constant"], [], gems: true)
+ assert_in_out_err(%w(-e) + ['p defined? Gem'], "", %w["constant"], [], gems: nil)
end
def test_disable
@@ -212,7 +219,7 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [],
/unknown argument for --disable: 'foobarbazqux'/)
assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/)
- assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], [])
+ assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], [], gems: false)
assert_in_out_err(%w(--disable-did_you_mean -e) + ['p defined? DidYouMean'], "", ["nil"], [])
assert_in_out_err(%w(-e) + ['p defined? DidYouMean'], "", ["nil"], [])
end
@@ -240,7 +247,7 @@ class TestRubyOptions < Test::Unit::TestCase
assert_match(VERSION_PATTERN, r[0])
if ENV['RUBY_YJIT_ENABLE'] == '1'
assert_equal(NO_JIT_DESCRIPTION, r[0])
- elsif self.class.yjit_enabled? # checking -DYJIT_FORCE_ENABLE
+ elsif JITSupport.yjit_enabled? || JITSupport.zjit_enabled? # checking -DYJIT_FORCE_ENABLE
assert_equal(EnvUtil.invoke_ruby(['-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0])
else
assert_equal(RUBY_DESCRIPTION, r[0])
@@ -260,6 +267,8 @@ class TestRubyOptions < Test::Unit::TestCase
end
def test_parser_flag
+ omit if ENV["RUBYOPT"]&.include?("--parser=")
+
assert_in_out_err(%w(--parser=prism -e) + ["puts :hi"], "", %w(hi), [])
assert_in_out_err(%w(--parser=prism --dump=parsetree -e _=:hi), "", /"hi"/, [])
@@ -437,37 +446,28 @@ class TestRubyOptions < Test::Unit::TestCase
def test_search
rubypath_orig = ENV['RUBYPATH']
path_orig = ENV['PATH']
+ libpath = (path_orig if path_orig && RbConfig::CONFIG['LIBPATHENV'] == 'PATH')
- Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
- t.puts "p 1"
- t.close
-
- @verbose = $VERBOSE
- $VERBOSE = nil
+ Dir.mktmpdir("test_ruby_test_rubyoption") do |path|
+ name = "test_rubyoption.rb"
+ parent, dir = File.split(path)
+ File.write("#{path}/#{name}", "p 1")
+ load_error = %r[#{Regexp.quote dir}/#{Regexp.quote name} \(LoadError\)]
- path, name = File.split(t.path)
-
- ENV['PATH'] = (path_orig && RbConfig::CONFIG['LIBPATHENV'] == 'PATH') ?
- [path, path_orig].join(File::PATH_SEPARATOR) : path
+ ENV['PATH'] = [path, *libpath].join(File::PATH_SEPARATOR)
assert_in_out_err(%w(-S) + [name], "", %w(1), [])
+ ENV['PATH'] = [parent, *libpath].join(File::PATH_SEPARATOR)
+ assert_in_out_err(%W(-S) + ["#{dir}/#{name}"], "", [], load_error)
ENV['PATH'] = path_orig
ENV['RUBYPATH'] = path
assert_in_out_err(%w(-S) + [name], "", %w(1), [])
- }
-
- ensure
- if rubypath_orig
+ ENV['RUBYPATH'] = parent
+ assert_in_out_err(%w(-S) + ["#{dir}/#{name}"], "", [], load_error)
+ ensure
ENV['RUBYPATH'] = rubypath_orig
- else
- ENV.delete('RUBYPATH')
- end
- if path_orig
ENV['PATH'] = path_orig
- else
- ENV.delete('PATH')
end
- $VERBOSE = @verbose
end
def test_shebang
@@ -519,6 +519,8 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err(%w(- -#=foo), "#!ruby -s\n", [],
/invalid name for global variable - -# \(NameError\)/)
+
+ assert_in_out_err(['-s', '-e', 'GC.start; p $DEBUG', '--', '-DEBUG=x'], "", ['"x"'])
end
def test_option_missing_argument
@@ -785,6 +787,12 @@ class TestRubyOptions < Test::Unit::TestCase
unless /mswin|mingw/ =~ RUBY_PLATFORM
opts[:rlimit_core] = 0
end
+ opts[:failed] = proc do |status, message = "", out = ""|
+ if (sig = status.termsig) && Signal.list["SEGV"] == sig
+ out = ""
+ end
+ Test::Unit::CoreAssertions::FailDesc[status, message]
+ end
ExecOptions = opts.freeze
# The regexp list that should match the entire stderr output.
@@ -834,20 +842,24 @@ class TestRubyOptions < Test::Unit::TestCase
end
def assert_segv(args, message=nil, list: SEGVTest::ExpectedStderrList, **opt, &block)
- pend "macOS 15 is not working with this assertion" if macos?(15)
-
# We want YJIT to be enabled in the subprocess if it's enabled for us
# so that the Ruby description matches.
env = Hash === args.first ? args.shift : {}
- args.unshift("--yjit") if self.class.yjit_enabled?
+ args.unshift("--yjit") if JITSupport.yjit_enabled?
+ args.unshift("--zjit") if JITSupport.zjit_enabled?
env.update({'RUBY_ON_BUG' => nil})
+ env['RUBY_CRASH_REPORT'] ||= nil # default to not passing down parent setting
# ASAN registers a segv handler which prints out "AddressSanitizer: DEADLYSIGNAL" when
# catching sigsegv; we don't expect that output, so suppress it.
- env.update({'ASAN_OPTIONS' => 'handle_segv=0'})
+ env.update({'ASAN_OPTIONS' => 'handle_segv=0', 'LSAN_OPTIONS' => 'handle_segv=0'})
args.unshift(env)
test_stdin = ""
- tests = [//, list] unless block
+ if !block
+ tests = [//, list, message]
+ elsif message
+ tests = [[], [], message]
+ end
assert_in_out_err(args, test_stdin, *tests, encoding: "ASCII-8BIT",
**SEGVTest::ExecOptions, **opt, &block)
@@ -860,13 +872,12 @@ class TestRubyOptions < Test::Unit::TestCase
def test_segv_loaded_features
bug7402 = '[ruby-core:49573]'
- status = assert_segv(['-e', "END {#{SEGVTest::KILL_SELF}}",
- '-e', 'class Bogus; def to_str; exit true; end; end',
- '-e', '$".clear',
- '-e', '$".unshift Bogus.new',
- '-e', '(p $"; abort) unless $".size == 1',
- ])
- assert_not_predicate(status, :success?, "segv but success #{bug7402}")
+ assert_segv(['-e', "END {#{SEGVTest::KILL_SELF}}",
+ '-e', 'class Bogus; def to_str; exit true; end; end',
+ '-e', '$".clear',
+ '-e', '$".unshift Bogus.new',
+ '-e', '(p $"; abort) unless $".size == 1',
+ ], bug7402, success: false)
end
def test_segv_setproctitle
@@ -879,8 +890,6 @@ class TestRubyOptions < Test::Unit::TestCase
end
def assert_crash_report(path, cmd = nil, &block)
- pend "macOS 15 is not working with this assertion" if macos?(15)
-
Dir.mktmpdir("ruby_crash_report") do |dir|
list = SEGVTest::ExpectedStderrList
if cmd
@@ -934,6 +943,27 @@ class TestRubyOptions < Test::Unit::TestCase
end
end
+ def test_crash_report_pipe_script
+ omit "only runs on Linux" unless RUBY_PLATFORM.include?("linux")
+
+ Tempfile.create(["script", ".sh"]) do |script|
+ Tempfile.create("crash_report") do |crash_report|
+ script.write(<<~BASH)
+ #!/usr/bin/env bash
+
+ cat > #{crash_report.path}
+ BASH
+ script.close
+
+ FileUtils.chmod("+x", script)
+
+ assert_crash_report("| #{script.path}") do
+ assert_include(File.read(crash_report.path), "[BUG] Segmentation fault at")
+ end
+ end
+ end
+ end
+
def test_DATA
Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
t.puts "puts DATA.read.inspect"
@@ -980,7 +1010,7 @@ class TestRubyOptions < Test::Unit::TestCase
pid = spawn(EnvUtil.rubybin, :in => s, :out => w)
w.close
assert_nothing_raised('[ruby-dev:37798]') do
- result = EnvUtil.timeout(3) {r.read}
+ result = EnvUtil.timeout(10) {r.read}
end
Process.wait pid
}
@@ -1278,4 +1308,10 @@ class TestRubyOptions < Test::Unit::TestCase
def test_toplevel_ruby
assert_instance_of Module, ::Ruby
end
+
+ def test_ruby_patchlevel
+ # We stopped bumping RUBY_PATCHLEVEL at Ruby 4.0.0.
+ # Released versions have RUBY_PATCHLEVEL 0, and un-released versions have -1.
+ assert_include [-1, 0], RUBY_PATCHLEVEL
+ end
end
diff --git a/test/ruby/test_set.rb b/test/ruby/test_set.rb
new file mode 100644
index 0000000000..427dd4b6b0
--- /dev/null
+++ b/test/ruby/test_set.rb
@@ -0,0 +1,1072 @@
+# frozen_string_literal: false
+require 'test/unit'
+require 'set'
+
+class TC_Set < Test::Unit::TestCase
+ class SetSubclass < Set
+ end
+ class CoreSetSubclass < Set::CoreSet
+ end
+ ALL_SET_CLASSES = [Set, SetSubclass, CoreSetSubclass].freeze
+
+ def test_marshal
+ set = Set[1, 2, 3]
+ mset = Marshal.load(Marshal.dump(set))
+ assert_equal(set, mset)
+ assert_equal(set.compare_by_identity?, mset.compare_by_identity?)
+
+ set.compare_by_identity
+ mset = Marshal.load(Marshal.dump(set))
+ assert_equal(set, mset)
+ assert_equal(set.compare_by_identity?, mset.compare_by_identity?)
+
+ set.instance_variable_set(:@a, 1)
+ mset = Marshal.load(Marshal.dump(set))
+ assert_equal(set, mset)
+ assert_equal(set.compare_by_identity?, mset.compare_by_identity?)
+ assert_equal(1, mset.instance_variable_get(:@a))
+
+ old_stdlib_set_data = "\x04\bo:\bSet\x06:\n@hash}\bi\x06Ti\aTi\bTF".b
+ set = Marshal.load(old_stdlib_set_data)
+ assert_equal(Set[1, 2, 3], set)
+
+ old_stdlib_set_cbi_data = "\x04\bo:\bSet\x06:\n@hashC:\tHash}\ai\x06Ti\aTF".b
+ set = Marshal.load(old_stdlib_set_cbi_data)
+ assert_equal(Set[1, 2].compare_by_identity, set)
+ end
+
+ def test_aref
+ assert_nothing_raised {
+ Set[]
+ Set[nil]
+ Set[1,2,3]
+ }
+
+ assert_equal(0, Set[].size)
+ assert_equal(1, Set[nil].size)
+ assert_equal(1, Set[[]].size)
+ assert_equal(1, Set[[nil]].size)
+
+ set = Set[2,4,6,4]
+ assert_equal(Set.new([2,4,6]), set)
+ end
+
+ def test_s_new
+ assert_nothing_raised {
+ Set.new()
+ Set.new(nil)
+ Set.new([])
+ Set.new([1,2])
+ Set.new('a'..'c')
+ }
+ assert_raise(ArgumentError) {
+ Set.new(false)
+ }
+ assert_raise(ArgumentError) {
+ Set.new(1)
+ }
+ assert_raise(ArgumentError) {
+ Set.new(1,2)
+ }
+
+ assert_equal(0, Set.new().size)
+ assert_equal(0, Set.new(nil).size)
+ assert_equal(0, Set.new([]).size)
+ assert_equal(1, Set.new([nil]).size)
+
+ ary = [2,4,6,4]
+ set = Set.new(ary)
+ ary.clear
+ assert_equal(false, set.empty?)
+ assert_equal(3, set.size)
+
+ ary = [1,2,3]
+
+ s = Set.new(ary) { |o| o * 2 }
+ assert_equal([2,4,6], s.sort)
+ end
+
+ def test_clone
+ set1 = Set.new
+ set2 = set1.clone
+ set1 << 'abc'
+ assert_equal(Set.new, set2)
+ end
+
+ def test_dup
+ set1 = Set[1,2]
+ set2 = set1.dup
+
+ assert_not_same(set1, set2)
+
+ assert_equal(set1, set2)
+
+ set1.add(3)
+
+ assert_not_equal(set1, set2)
+ end
+
+ def test_size
+ assert_equal(0, Set[].size)
+ assert_equal(2, Set[1,2].size)
+ assert_equal(2, Set[1,2,1].size)
+ end
+
+ def test_empty?
+ assert_equal(true, Set[].empty?)
+ assert_equal(false, Set[1, 2].empty?)
+ end
+
+ def test_clear
+ set = Set[1,2]
+ ret = set.clear
+
+ assert_same(set, ret)
+ assert_equal(true, set.empty?)
+ end
+
+ def test_replace
+ set = Set[1,2]
+ ret = set.replace('a'..'c')
+
+ assert_same(set, ret)
+ assert_equal(Set['a','b','c'], set)
+
+ set = Set[1,2]
+ ret = set.replace(Set.new('a'..'c'))
+
+ assert_same(set, ret)
+ assert_equal(Set['a','b','c'], set)
+
+ set = Set[1,2]
+ assert_raise(ArgumentError) {
+ set.replace(3)
+ }
+ assert_equal(Set[1,2], set)
+ end
+
+ def test_to_a
+ set = Set[1,2,3,2]
+ ary = set.to_a
+
+ assert_equal([1,2,3], ary.sort)
+ end
+
+ def test_flatten
+ # test1
+ set1 = Set[
+ 1,
+ Set[
+ 5,
+ Set[7,
+ Set[0]
+ ],
+ Set[6,2],
+ 1
+ ],
+ 3,
+ Set[3,4]
+ ]
+
+ set2 = set1.flatten
+ set3 = Set.new(0..7)
+
+ assert_not_same(set2, set1)
+ assert_equal(set3, set2)
+
+ # test2; destructive
+ orig_set1 = set1
+ set1.flatten!
+
+ assert_same(orig_set1, set1)
+ assert_equal(set3, set1)
+
+ # test3; multiple occurrences of a set in an set
+ set1 = Set[1, 2]
+ set2 = Set[set1, Set[set1, 4], 3]
+
+ assert_nothing_raised {
+ set2.flatten!
+ }
+
+ assert_equal(Set.new(1..4), set2)
+
+ # test4; recursion
+ set2 = Set[]
+ set1 = Set[1, set2]
+ set2.add(set1)
+
+ assert_raise(ArgumentError) {
+ set1.flatten!
+ }
+
+ # test5; miscellaneous
+ empty = Set[]
+ set = Set[Set[empty, "a"],Set[empty, "b"]]
+
+ assert_nothing_raised {
+ set.flatten
+ }
+
+ set1 = empty.merge(Set["no_more", set])
+
+ assert_nil(Set.new(0..31).flatten!)
+
+ x = Set[Set[],Set[1,2]].flatten!
+ y = Set[1,2]
+
+ assert_equal(x, y)
+ end
+
+ def test_include?
+ set = Set[1,2,3]
+
+ assert_equal(true, set.include?(1))
+ assert_equal(true, set.include?(2))
+ assert_equal(true, set.include?(3))
+ assert_equal(false, set.include?(0))
+ assert_equal(false, set.include?(nil))
+
+ set = Set["1",nil,"2",nil,"0","1",false]
+ assert_equal(true, set.include?(nil))
+ assert_equal(true, set.include?(false))
+ assert_equal(true, set.include?("1"))
+ assert_equal(false, set.include?(0))
+ assert_equal(false, set.include?(true))
+ end
+
+ def test_eqq
+ set = Set[1,2,3]
+
+ assert_equal(true, set === 1)
+ assert_equal(true, set === 2)
+ assert_equal(true, set === 3)
+ assert_equal(false, set === 0)
+ assert_equal(false, set === nil)
+
+ set = Set["1",nil,"2",nil,"0","1",false]
+ assert_equal(true, set === nil)
+ assert_equal(true, set === false)
+ assert_equal(true, set === "1")
+ assert_equal(false, set === 0)
+ assert_equal(false, set === true)
+ end
+
+ def test_superset?
+ set = Set[1,2,3]
+
+ assert_raise(ArgumentError) {
+ set.superset?()
+ }
+
+ assert_raise(ArgumentError) {
+ set.superset?(2)
+ }
+
+ assert_raise(ArgumentError) {
+ set.superset?([2])
+ }
+
+ ALL_SET_CLASSES.each { |klass|
+ assert_equal(true, set.superset?(klass[]), klass.name)
+ assert_equal(true, set.superset?(klass[1,2]), klass.name)
+ assert_equal(true, set.superset?(klass[1,2,3]), klass.name)
+ assert_equal(false, set.superset?(klass[1,2,3,4]), klass.name)
+ assert_equal(false, set.superset?(klass[1,4]), klass.name)
+
+ assert_equal(true, set >= klass[1,2,3], klass.name)
+ assert_equal(true, set >= klass[1,2], klass.name)
+
+ assert_equal(true, Set[].superset?(klass[]), klass.name)
+ }
+ end
+
+ def test_proper_superset?
+ set = Set[1,2,3]
+
+ assert_raise(ArgumentError) {
+ set.proper_superset?()
+ }
+
+ assert_raise(ArgumentError) {
+ set.proper_superset?(2)
+ }
+
+ assert_raise(ArgumentError) {
+ set.proper_superset?([2])
+ }
+
+ ALL_SET_CLASSES.each { |klass|
+ assert_equal(true, set.proper_superset?(klass[]), klass.name)
+ assert_equal(true, set.proper_superset?(klass[1,2]), klass.name)
+ assert_equal(false, set.proper_superset?(klass[1,2,3]), klass.name)
+ assert_equal(false, set.proper_superset?(klass[1,2,3,4]), klass.name)
+ assert_equal(false, set.proper_superset?(klass[1,4]), klass.name)
+
+ assert_equal(false, set > klass[1,2,3], klass.name)
+ assert_equal(true, set > klass[1,2], klass.name)
+
+ assert_equal(false, Set[].proper_superset?(klass[]), klass.name)
+ }
+ end
+
+ def test_subset?
+ set = Set[1,2,3]
+
+ assert_raise(ArgumentError) {
+ set.subset?()
+ }
+
+ assert_raise(ArgumentError) {
+ set.subset?(2)
+ }
+
+ assert_raise(ArgumentError) {
+ set.subset?([2])
+ }
+
+ ALL_SET_CLASSES.each { |klass|
+ assert_equal(true, set.subset?(klass[1,2,3,4]), klass.name)
+ assert_equal(true, set.subset?(klass[1,2,3]), klass.name)
+ assert_equal(false, set.subset?(klass[1,2]), klass.name)
+ assert_equal(false, set.subset?(klass[]), klass.name)
+
+ assert_equal(true, set <= klass[1,2,3], klass.name)
+ assert_equal(true, set <= klass[1,2,3,4], klass.name)
+
+ assert_equal(true, Set[].subset?(klass[1]), klass.name)
+ assert_equal(true, Set[].subset?(klass[]), klass.name)
+ }
+ end
+
+ def test_proper_subset?
+ set = Set[1,2,3]
+
+ assert_raise(ArgumentError) {
+ set.proper_subset?()
+ }
+
+ assert_raise(ArgumentError) {
+ set.proper_subset?(2)
+ }
+
+ assert_raise(ArgumentError) {
+ set.proper_subset?([2])
+ }
+
+ ALL_SET_CLASSES.each { |klass|
+ assert_equal(true, set.proper_subset?(klass[1,2,3,4]), klass.name)
+ assert_equal(false, set.proper_subset?(klass[1,2,3]), klass.name)
+ assert_equal(false, set.proper_subset?(klass[1,2]), klass.name)
+ assert_equal(false, set.proper_subset?(klass[]), klass.name)
+
+ assert_equal(false, set < klass[1,2,3], klass.name)
+ assert_equal(true, set < klass[1,2,3,4], klass.name)
+
+ assert_equal(false, Set[].proper_subset?(klass[]), klass.name)
+ }
+ end
+
+ def test_spacecraft_operator
+ set = Set[1,2,3]
+
+ assert_nil(set <=> 2)
+
+ assert_nil(set <=> set.to_a)
+
+ ALL_SET_CLASSES.each { |klass|
+ assert_equal(-1, set <=> klass[1,2,3,4], klass.name)
+ assert_equal( 0, set <=> klass[3,2,1] , klass.name)
+ assert_equal(nil, set <=> klass[1,2,4] , klass.name)
+ assert_equal(+1, set <=> klass[2,3] , klass.name)
+ assert_equal(+1, set <=> klass[] , klass.name)
+
+ assert_equal(0, Set[] <=> klass[], klass.name)
+ }
+ end
+
+ def assert_intersect(expected, set, other)
+ case expected
+ when true
+ assert_send([set, :intersect?, other])
+ assert_send([set, :intersect?, other.to_a])
+ assert_send([other, :intersect?, set])
+ assert_not_send([set, :disjoint?, other])
+ assert_not_send([set, :disjoint?, other.to_a])
+ assert_not_send([other, :disjoint?, set])
+ when false
+ assert_not_send([set, :intersect?, other])
+ assert_not_send([set, :intersect?, other.to_a])
+ assert_not_send([other, :intersect?, set])
+ assert_send([set, :disjoint?, other])
+ assert_send([set, :disjoint?, other.to_a])
+ assert_send([other, :disjoint?, set])
+ when Class
+ assert_raise(expected) {
+ set.intersect?(other)
+ }
+ assert_raise(expected) {
+ set.disjoint?(other)
+ }
+ else
+ raise ArgumentError, "%s: unsupported expected value: %s" % [__method__, expected.inspect]
+ end
+ end
+
+ def test_intersect?
+ set = Set[3,4,5]
+
+ assert_intersect(ArgumentError, set, 3)
+ assert_intersect(true, set, Set[2,4,6])
+
+ assert_intersect(true, set, set)
+ assert_intersect(true, set, Set[2,4])
+ assert_intersect(true, set, Set[5,6,7])
+ assert_intersect(true, set, Set[1,2,6,8,4])
+
+ assert_intersect(false, set, Set[])
+ assert_intersect(false, set, Set[0,2])
+ assert_intersect(false, set, Set[0,2,6])
+ assert_intersect(false, set, Set[0,2,6,8,10])
+
+ # Make sure set hasn't changed
+ assert_equal(Set[3,4,5], set)
+ end
+
+ def test_each
+ ary = [1,3,5,7,10,20]
+ set = Set.new(ary)
+
+ ret = set.each { |o| }
+ assert_same(set, ret)
+
+ e = set.each
+ assert_instance_of(Enumerator, e)
+
+ assert_nothing_raised {
+ set.each { |o|
+ ary.delete(o) or raise "unexpected element: #{o}"
+ }
+
+ ary.empty? or raise "forgotten elements: #{ary.join(', ')}"
+ }
+
+ assert_equal(6, e.size)
+ set << 42
+ assert_equal(7, e.size)
+ end
+
+ def test_add
+ set = Set[1,2,3]
+
+ ret = set.add(2)
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3], set)
+
+ ret = set.add?(2)
+ assert_nil(ret)
+ assert_equal(Set[1,2,3], set)
+
+ ret = set.add(4)
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3,4], set)
+
+ ret = set.add?(5)
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3,4,5], set)
+ end
+
+ def test_delete
+ set = Set[1,2,3]
+
+ ret = set.delete(4)
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3], set)
+
+ ret = set.delete?(4)
+ assert_nil(ret)
+ assert_equal(Set[1,2,3], set)
+
+ ret = set.delete(2)
+ assert_equal(set, ret)
+ assert_equal(Set[1,3], set)
+
+ ret = set.delete?(1)
+ assert_equal(set, ret)
+ assert_equal(Set[3], set)
+ end
+
+ def test_delete_if
+ set = Set.new(1..10)
+ ret = set.delete_if { |i| i > 10 }
+ assert_same(set, ret)
+ assert_equal(Set.new(1..10), set)
+
+ set = Set.new(1..10)
+ ret = set.delete_if { |i| i % 3 == 0 }
+ assert_same(set, ret)
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+
+ set = Set.new(1..10)
+ enum = set.delete_if
+ assert_equal(set.size, enum.size)
+ assert_same(set, enum.each { |i| i % 3 == 0 })
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+ end
+
+ def test_keep_if
+ set = Set.new(1..10)
+ ret = set.keep_if { |i| i <= 10 }
+ assert_same(set, ret)
+ assert_equal(Set.new(1..10), set)
+
+ set = Set.new(1..10)
+ ret = set.keep_if { |i| i % 3 != 0 }
+ assert_same(set, ret)
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+
+ set = Set.new(1..10)
+ enum = set.keep_if
+ assert_equal(set.size, enum.size)
+ assert_same(set, enum.each { |i| i % 3 != 0 })
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+ end
+
+ def test_collect!
+ set = Set[1,2,3,'a','b','c',-1..1,2..4]
+
+ ret = set.collect! { |i|
+ case i
+ when Numeric
+ i * 2
+ when String
+ i.upcase
+ else
+ nil
+ end
+ }
+
+ assert_same(set, ret)
+ assert_equal(Set[2,4,6,'A','B','C',nil], set)
+
+ set = Set[1,2,3,'a','b','c',-1..1,2..4]
+ enum = set.collect!
+
+ assert_equal(set.size, enum.size)
+ assert_same(set, enum.each { |i|
+ case i
+ when Numeric
+ i * 2
+ when String
+ i.upcase
+ else
+ nil
+ end
+ })
+ assert_equal(Set[2,4,6,'A','B','C',nil], set)
+ end
+
+ def test_reject!
+ set = Set.new(1..10)
+
+ ret = set.reject! { |i| i > 10 }
+ assert_nil(ret)
+ assert_equal(Set.new(1..10), set)
+
+ ret = set.reject! { |i| i % 3 == 0 }
+ assert_same(set, ret)
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+
+ set = Set.new(1..10)
+ enum = set.reject!
+ assert_equal(set.size, enum.size)
+ assert_same(set, enum.each { |i| i % 3 == 0 })
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+ end
+
+ def test_select!
+ set = Set.new(1..10)
+ ret = set.select! { |i| i <= 10 }
+ assert_equal(nil, ret)
+ assert_equal(Set.new(1..10), set)
+
+ set = Set.new(1..10)
+ ret = set.select! { |i| i % 3 != 0 }
+ assert_same(set, ret)
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+
+ set = Set.new(1..10)
+ enum = set.select!
+ assert_equal(set.size, enum.size)
+ assert_equal(nil, enum.each { |i| i <= 10 })
+ assert_equal(Set.new(1..10), set)
+ end
+
+ def test_filter!
+ set = Set.new(1..10)
+ ret = set.filter! { |i| i <= 10 }
+ assert_equal(nil, ret)
+ assert_equal(Set.new(1..10), set)
+
+ set = Set.new(1..10)
+ ret = set.filter! { |i| i % 3 != 0 }
+ assert_same(set, ret)
+ assert_equal(Set[1,2,4,5,7,8,10], set)
+
+ set = Set.new(1..10)
+ enum = set.filter!
+ assert_equal(set.size, enum.size)
+ assert_equal(nil, enum.each { |i| i <= 10 })
+ assert_equal(Set.new(1..10), set)
+ end
+
+ def test_merge
+ set = Set[1,2,3]
+ ret = set.merge([2,4,6])
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3,4,6], set)
+
+ set = Set[1,2,3]
+ ret = set.merge()
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3], set)
+
+ set = Set[1,2,3]
+ ret = set.merge([2,4,6], Set[4,5,6])
+ assert_same(set, ret)
+ assert_equal(Set[1,2,3,4,5,6], set)
+
+ assert_raise(ArgumentError) {
+ Set[].merge(a: 1)
+ }
+ end
+
+ def test_merge_mutating_hash_bug_21305
+ a = (1..100).to_a
+ o = Object.new
+ o.define_singleton_method(:hash) do
+ a.clear
+ 0
+ end
+ a.unshift o
+ assert_equal([o], Set.new.merge(a).to_a)
+ end
+
+ def test_initialize_mutating_array_bug_21306
+ a = (1..100).to_a
+ assert_equal(Set[0], Set.new(a){a.clear; 0})
+ end
+
+ def test_subtract
+ set = Set[1,2,3]
+
+ ret = set.subtract([2,4,6])
+ assert_same(set, ret)
+ assert_equal(Set[1,3], set)
+ end
+
+ def test_plus
+ set = Set[1,2,3]
+
+ ret = set + [2,4,6]
+ assert_not_same(set, ret)
+ assert_equal(Set[1,2,3,4,6], ret)
+ end
+
+ def test_minus
+ set = Set[1,2,3]
+
+ ret = set - [2,4,6]
+ assert_not_same(set, ret)
+ assert_equal(Set[1,3], ret)
+ end
+
+ def test_and
+ set = Set[1,2,3,4]
+
+ ret = set & [2,4,6]
+ assert_not_same(set, ret)
+ assert_equal(Set[2,4], ret)
+ end
+
+ def test_xor
+ ALL_SET_CLASSES.each { |klass|
+ set = klass[1,2,3,4]
+ ret = set ^ [2,4,5,5]
+ assert_not_same(set, ret)
+ assert_equal(klass[1,3,5], ret)
+
+ set2 = klass[1,2,3,4]
+ ret2 = set2 ^ [2,4,5,5]
+ assert_instance_of(klass, ret2)
+ assert_equal(klass[1,3,5], ret2)
+ }
+ end
+
+ def test_xor_does_not_mutate_other_set
+ a = Set[1]
+ b = Set[1, 2]
+ original_b = b.dup
+
+ result = a ^ b
+
+ assert_equal(original_b, b)
+ assert_equal(Set[2], result)
+ end
+
+ def test_eq
+ set1 = Set[2,3,1]
+ set2 = Set[1,2,3]
+
+ assert_equal(set1, set1)
+ assert_equal(set1, set2)
+ assert_not_equal(Set[1], [1])
+
+ set1 = Class.new(Set)["a", "b"]
+ set1.add(set1).reset # Make recursive
+ set2 = Set["a", "b", Set["a", "b", set1]]
+
+ assert_equal(set1, set2)
+
+ assert_not_equal(Set[Exception.new,nil], Set[Exception.new,Exception.new], "[ruby-dev:26127]")
+ end
+
+ def test_classify
+ set = Set.new(1..10)
+ ret = set.classify { |i| i % 3 }
+
+ assert_equal(3, ret.size)
+ assert_instance_of(Hash, ret)
+ ret.each_value { |value| assert_instance_of(Set, value) }
+ assert_equal(Set[3,6,9], ret[0])
+ assert_equal(Set[1,4,7,10], ret[1])
+ assert_equal(Set[2,5,8], ret[2])
+
+ set = Set.new(1..10)
+ enum = set.classify
+
+ assert_equal(set.size, enum.size)
+ ret = enum.each { |i| i % 3 }
+ assert_equal(3, ret.size)
+ assert_instance_of(Hash, ret)
+ ret.each_value { |value| assert_instance_of(Set, value) }
+ assert_equal(Set[3,6,9], ret[0])
+ assert_equal(Set[1,4,7,10], ret[1])
+ assert_equal(Set[2,5,8], ret[2])
+ end
+
+ def test_divide
+ set = Set.new(1..10)
+ ret = set.divide { |i| i % 3 }
+
+ assert_equal(3, ret.size)
+ n = 0
+ ret.each { |s| n += s.size }
+ assert_equal(set.size, n)
+ assert_equal(set, ret.flatten)
+
+ set = Set[7,10,5,11,1,3,4,9,0]
+ ret = set.divide { |a,b| (a - b).abs == 1 }
+
+ assert_equal(4, ret.size)
+ n = 0
+ ret.each { |s| n += s.size }
+ assert_equal(set.size, n)
+ assert_equal(set, ret.flatten)
+ ret.each { |s|
+ if s.include?(0)
+ assert_equal(Set[0,1], s)
+ elsif s.include?(3)
+ assert_equal(Set[3,4,5], s)
+ elsif s.include?(7)
+ assert_equal(Set[7], s)
+ elsif s.include?(9)
+ assert_equal(Set[9,10,11], s)
+ else
+ raise "unexpected group: #{s.inspect}"
+ end
+ }
+
+ set = Set.new(1..10)
+ enum = set.divide
+ ret = enum.each { |i| i % 3 }
+
+ assert_equal(set.size, enum.size)
+ assert_equal(3, ret.size)
+ n = 0
+ ret.each { |s| n += s.size }
+ assert_equal(set.size, n)
+ assert_equal(set, ret.flatten)
+
+ set = Set[2,12,9,11,13,4,10,15,3,8,5,0,1,7,14]
+ ret = set.divide { |a,b| (a - b).abs == 1 }
+ assert_equal(2, ret.size)
+ end
+
+ def test_freeze
+ orig = set = Set[1,2,3]
+ assert_equal false, set.frozen?
+ set << 4
+ assert_same orig, set.freeze
+ assert_equal true, set.frozen?
+ assert_raise(FrozenError) {
+ set << 5
+ }
+ assert_equal 4, set.size
+ end
+
+ def test_freeze_dup
+ set1 = Set[1,2,3]
+ set1.freeze
+ set2 = set1.dup
+
+ assert_not_predicate set2, :frozen?
+ assert_nothing_raised {
+ set2.add 4
+ }
+ end
+
+ def test_freeze_clone
+ set1 = Set[1,2,3]
+ set1.freeze
+ set2 = set1.clone
+
+ assert_predicate set2, :frozen?
+ assert_raise(FrozenError) {
+ set2.add 5
+ }
+ end
+
+ def test_freeze_clone_false
+ set1 = Set[1,2,3]
+ set1.freeze
+ set2 = set1.clone(freeze: false)
+
+ assert_not_predicate set2, :frozen?
+ set2.add 5
+ assert_equal Set[1,2,3,5], set2
+ assert_equal Set[1,2,3], set1
+ end if Kernel.instance_method(:initialize_clone).arity != 1
+
+ def test_join
+ assert_equal('123', Set[1, 2, 3].join)
+ assert_equal('1 & 2 & 3', Set[1, 2, 3].join(' & '))
+ end
+
+ def test_inspect
+ set1 = Set[1, 2]
+ assert_equal('Set[1, 2]', set1.inspect)
+
+ set2 = Set[Set[0], 1, 2, set1]
+ assert_equal('Set[Set[0], 1, 2, Set[1, 2]]', set2.inspect)
+
+ set1.add(set2)
+ assert_equal('Set[Set[0], 1, 2, Set[1, 2, Set[...]]]', set2.inspect)
+
+ c = Class.new(Set::CoreSet)
+ c.set_temporary_name("_MySet")
+ assert_equal('_MySet[1, 2]', c[1, 2].inspect)
+
+ c = Class.new(Set)
+ c.set_temporary_name("_MySet")
+ assert_equal('#<_MySet: {1, 2}>', c[1, 2].inspect)
+ end
+
+ def test_to_s
+ set1 = Set[1, 2]
+ assert_equal('Set[1, 2]', set1.to_s)
+
+ set2 = Set[Set[0], 1, 2, set1]
+ assert_equal('Set[Set[0], 1, 2, Set[1, 2]]', set2.to_s)
+
+ set1.add(set2)
+ assert_equal('Set[Set[0], 1, 2, Set[1, 2, Set[...]]]', set2.to_s)
+ end
+
+ def test_compare_by_identity
+ a1, a2 = "a", "a"
+ b1, b2 = "b", "b"
+ c = "c"
+ array = [a1, b1, c, a2, b2]
+
+ iset = Set.new.compare_by_identity
+ assert_send([iset, :compare_by_identity?])
+ iset.merge(array)
+ assert_equal(5, iset.size)
+ assert_equal(array.map(&:object_id).sort, iset.map(&:object_id).sort)
+
+ set = Set.new
+ assert_not_send([set, :compare_by_identity?])
+ set.merge(array)
+ assert_equal(3, set.size)
+ assert_equal(array.uniq.sort, set.sort)
+ end
+
+ def test_compare_by_identity_compact
+ omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
+
+ # [Bug #22064]
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ set = Set.new.compare_by_identity
+
+ o = Object.new
+ set.add(o)
+
+ assert_include(set, o)
+
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
+
+ assert_include(set, o)
+ end;
+ end
+
+ def test_reset
+ [Set, Class.new(Set)].each { |klass|
+ a = [1, 2]
+ b = [1]
+ set = klass.new([a, b])
+
+ b << 2
+ set.reset
+
+ assert_equal(klass.new([a]), set, klass.name)
+ }
+ end
+
+ def test_set_gc_compact_does_not_allocate
+ assert_in_out_err([], <<-"end;", [], [])
+ def x
+ s = Set.new
+ s << Object.new
+ s
+ end
+
+ x
+ begin
+ GC.compact
+ rescue NotImplementedError
+ end
+ end;
+ end
+
+ def test_larger_sets
+ set = Set.new
+ 10_000.times do |i|
+ set << i
+ end
+ set = set.dup
+
+ 10_000.times do |i|
+ assert_includes set, i
+ end
+ end
+
+ def test_subclass_new_calls_add
+ c = Class.new(Set) do
+ def add(o)
+ super
+ super(o+1)
+ end
+ end
+ assert_equal([1, 2], c.new([1]).to_a)
+ end
+
+ def test_subclass_aref_calls_initialize
+ c = Class.new(Set) do
+ def initialize(enum)
+ super
+ add(1)
+ end
+ end
+ assert_equal([2, 1], c[2].to_a)
+ end
+
+end
+
+class TC_Enumerable < Test::Unit::TestCase
+ def test_to_set
+ ary = [2,5,4,3,2,1,3]
+
+ set = ary.to_set
+ assert_instance_of(Set, set)
+ assert_equal([1,2,3,4,5], set.sort)
+
+ set = ary.to_set { |o| o * -2 }
+ assert_instance_of(Set, set)
+ assert_equal([-10,-8,-6,-4,-2], set.sort)
+
+ assert_same set, set.to_set
+ transformed = set.to_set { |o| o + 1 }
+ assert_equal([-9,-7,-5,-3,-1], transformed.sort)
+ end
+
+ class MyEnum
+ include Enumerable
+
+ def initialize(array)
+ @array = array
+ end
+
+ def each(&block)
+ @array.each(&block)
+ end
+
+ def size
+ raise "should not be called"
+ end
+ end
+
+ def test_to_set_not_calling_size
+ enum = MyEnum.new([1,2,3])
+
+ set = assert_nothing_raised { enum.to_set }
+ assert(set.is_a?(Set))
+ assert_equal(Set[1,2,3], set)
+
+ enumerator = enum.to_enum
+
+ set = assert_nothing_raised { enumerator.to_set }
+ assert(set.is_a?(Set))
+ assert_equal(Set[1,2,3], set)
+ end
+end
+
+class TC_Set_Builtin < Test::Unit::TestCase
+ private def should_omit?
+ (RUBY_VERSION.scan(/\d+/).map(&:to_i) <=> [3, 2]) < 0 ||
+ !File.exist?(File.expand_path('../prelude.rb', __dir__))
+ end
+
+ def test_Set
+ omit "skipping the test for the builtin Set" if should_omit?
+
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ assert_nothing_raised do
+ set = Set.new([1, 2])
+ assert_equal('Set', set.class.name)
+ end
+ end;
+
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ assert_nothing_raised do
+ set = Set[1, 2]
+ assert_equal('Set', set.class.name)
+ end
+ end;
+ end
+
+ def test_to_set
+ omit "skipping the test for the builtin Enumerable#to_set" if should_omit?
+
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ assert_nothing_raised do
+ set = [1, 2].to_set
+ assert_equal('Set', set.class.name)
+ end
+ end;
+ end
+end
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index 5542ad248a..8b0e08fc97 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -168,14 +168,14 @@ class TestSetTraceFunc < Test::Unit::TestCase
events.shift)
assert_equal(["line", 4, __method__, self.class],
events.shift)
- assert_equal(["c-call", 4, :inherited, Class],
- events.shift)
- assert_equal(["c-return", 4, :inherited, Class],
- events.shift)
assert_equal(["c-call", 4, :const_added, Module],
events.shift)
assert_equal(["c-return", 4, :const_added, Module],
events.shift)
+ assert_equal(["c-call", 4, :inherited, Class],
+ events.shift)
+ assert_equal(["c-return", 4, :inherited, Class],
+ events.shift)
assert_equal(["class", 4, nil, nil],
events.shift)
assert_equal(["line", 5, nil, nil],
@@ -411,10 +411,10 @@ class TestSetTraceFunc < Test::Unit::TestCase
[["c-return", 2, :add_trace_func, Thread],
["line", 3, __method__, self.class],
- ["c-call", 3, :inherited, Class],
- ["c-return", 3, :inherited, Class],
["c-call", 3, :const_added, Module],
["c-return", 3, :const_added, Module],
+ ["c-call", 3, :inherited, Class],
+ ["c-return", 3, :inherited, Class],
["class", 3, nil, nil],
["line", 4, nil, nil],
["c-call", 4, :method_added, Module],
@@ -558,10 +558,10 @@ class TestSetTraceFunc < Test::Unit::TestCase
[:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
[:c_return, 4, "xyzzy", Array, :reverse_each, [1], nil, [1]],
[:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
- [:c_call, 7, "xyzzy", Class, :inherited, Object, nil, :nothing],
- [:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil],
[:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing],
[:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil],
+ [:c_call, 7, "xyzzy", Class, :inherited, Object, nil, :nothing],
+ [:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil],
[:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
[:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
[:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing],
@@ -1999,7 +1999,7 @@ CODE
TracePoint.new(:c_call, &capture_events).enable{
c.new
}
- assert_equal [:c_call, :itself, :initialize], events[1]
+ assert_equal [:c_call, :itself, :initialize], events[0]
events.clear
o = Class.new{
@@ -2226,7 +2226,7 @@ CODE
def test_thread_add_trace_func
events = []
base_line = __LINE__
- q = Thread::Queue.new
+ q = []
t = Thread.new{
Thread.current.add_trace_func proc{|ev, file, line, *args|
events << [ev, line] if file == __FILE__
@@ -2583,6 +2583,7 @@ CODE
def test_enable_target_thread
events = []
TracePoint.new(:line) do |tp|
+ next unless tp.path == __FILE__
events << Thread.current
end.enable(target_thread: Thread.current) do
_a = 1
@@ -2596,6 +2597,7 @@ CODE
events = []
tp = TracePoint.new(:line) do |tp|
+ next unless tp.path == __FILE__
events << Thread.current
end
@@ -2724,7 +2726,7 @@ CODE
end
def test_disable_local_tracepoint_in_trace
- assert_normal_exit <<-EOS
+ assert_normal_exit(<<-EOS, timeout: 60)
def foo
trace = TracePoint.new(:b_return){|tp|
tp.disable
@@ -2957,4 +2959,210 @@ CODE
assert_kind_of(Thread, target_thread)
end
+
+ def test_tracepoint_garbage_collected_when_disable
+ before_count_stat = 0
+ before_count_objspace = 0
+ TracePoint.stat.each do
+ before_count_stat += 1
+ end
+ ObjectSpace.each_object(TracePoint) do
+ before_count_objspace += 1
+ end
+ tp = TracePoint.new(:c_call, :c_return) do
+ end
+ tp.enable
+ Class.inspect # c_call, c_return invoked
+ tp.disable
+ tp_id = tp.object_id
+ tp = nil
+
+ gc_times = 0
+ gc_max_retries = 10
+ EnvUtil.suppress_warning do
+ until (ObjectSpace._id2ref(tp_id) rescue nil).nil?
+ GC.start
+ gc_times += 1
+ if gc_times == gc_max_retries
+ break
+ end
+ end
+ end
+ return if gc_times == gc_max_retries
+
+ after_count_stat = 0
+ TracePoint.stat.each do |v|
+ after_count_stat += 1
+ end
+ assert after_count_stat <= before_count_stat
+ after_count_objspace = 0
+ ObjectSpace.each_object(TracePoint) do
+ after_count_objspace += 1
+ end
+ assert after_count_objspace <= before_count_objspace
+ end
+
+ def test_tp_ractor_local_untargeted
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ r = Ractor.new do
+ results = []
+ tp = TracePoint.new(:line) { |tp| results << tp.path }
+ tp.enable
+ Ractor.main << :continue
+ Ractor.receive
+ tp.disable
+ results
+ end
+ outer_results = []
+ outer_tp = TracePoint.new(:line) { |tp| outer_results << tp.path }
+ outer_tp.enable
+ Ractor.receive
+ GC.start # so I can check <internal:gc> path
+ r << :continue
+ inner_results = r.value
+ outer_tp.disable
+ assert_equal 1, outer_results.select { |path| path.match?(/internal:gc/) }.size
+ assert_equal 0, inner_results.select { |path| path.match?(/internal:gc/) }.size
+ end;
+ end
+
+ def test_tp_targeted_ractor_local_bmethod
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ mname = :foo
+ prok = Ractor.shareable_proc do
+ end
+ klass = EnvUtil.labeled_class(:Klass) do
+ define_method(mname, &prok)
+ end
+ outer_results = 0
+ _outer_tp = TracePoint.new(:call) do
+ outer_results += 1
+ end # not enabled
+ rs = 10.times.map do
+ Ractor.new(mname, klass) do |mname, klass0|
+ inner_results = 0
+ tp = TracePoint.new(:call) { |tp| inner_results += 1 }
+ target = klass0.instance_method(mname)
+ tp.enable(target: target)
+ obj = klass0.new
+ 10.times { obj.send(mname) }
+ tp.disable
+ inner_results
+ end
+ end
+ inner_results = rs.map(&:value).sum
+ obj = klass.new
+ 10.times { obj.send(mname) }
+ assert_equal 100, inner_results
+ assert_equal 0, outer_results
+ end;
+ end
+
+ def test_tp_targeted_ractor_local_method
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ def foo
+ end
+ outer_results = 0
+ _outer_tp = TracePoint.new(:call) do
+ outer_results += 1
+ end # not enabled
+
+ rs = 10.times.map do
+ Ractor.new do
+ inner_results = 0
+ tp = TracePoint.new(:call) do
+ inner_results += 1
+ end
+ tp.enable(target: method(:foo))
+ 10.times { foo }
+ tp.disable
+ inner_results
+ end
+ end
+
+ inner_results = rs.map(&:value).sum
+ 10.times { foo }
+ assert_equal 100, inner_results
+ assert_equal 0, outer_results
+ end;
+ end
+
+ def test_tracepoints_not_disabled_by_ractor_gc
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ $-w = nil # uses ObjectSpace._id2ref
+ def hi = "hi"
+ greetings = 0
+ tp_target = TracePoint.new(:call) do |tp|
+ greetings += 1
+ end
+ tp_target.enable(target: method(:hi))
+
+ raises = 0
+ tp_global = TracePoint.new(:raise) do |tp|
+ raises += 1
+ end
+ tp_global.enable
+
+ r = Ractor.new { 10 }
+ r.join
+ ractor_id = r.object_id
+ r = nil # allow gc for ractor
+ gc_max_retries = 15
+ gc_times = 0
+ # force GC of ractor (or try, because we have a conservative GC)
+ until (ObjectSpace._id2ref(ractor_id) rescue nil).nil?
+ GC.start
+ gc_times += 1
+ if gc_times == gc_max_retries
+ break
+ end
+ end
+
+ # tracepoints should still be enabled after GC of `r`
+ 5.times {
+ hi
+ }
+ 6.times {
+ raise "uh oh" rescue nil
+ }
+ tp_target.disable
+ tp_global.disable
+ assert_equal 5, greetings
+ if gc_times == gc_max_retries # _id2ref never raised
+ assert_equal 6, raises
+ else
+ assert_equal 7, raises
+ end
+ end;
+ end
+
+ def test_lots_of_enabled_tracepoints_ractor_gc
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ def foo; end
+ sum = 8.times.map do
+ Ractor.new do
+ called = 0
+ TracePoint.new(:call) do |tp|
+ next if tp.callee_id != :foo
+ called += 1
+ end.enable
+ 200.times do
+ TracePoint.new(:line) {
+ # all these allocations shouldn't GC these tracepoints while the ractor is alive.
+ Object.new
+ }.enable
+ end
+ 100.times { foo }
+ called
+ end
+ end.map(&:value).sum
+ assert_equal 800, sum
+ 4.times { GC.start } # Now the tracepoints can be GC'd because the ractors can be GC'd
+ end;
+ end
end
diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb
index 0c1d8d424e..bace69658a 100644
--- a/test/ruby/test_shapes.rb
+++ b/test/ruby/test_shapes.rb
@@ -2,10 +2,11 @@
require 'test/unit'
require 'objspace'
require 'json'
+require 'securerandom'
# These test the functionality of object shapes
class TestShapes < Test::Unit::TestCase
- MANY_IVS = 80
+ MANY_IVS = RubyVM::Shape::SHAPE_MAX_FIELDS + 1
class IVOrder
def expected_ivs
@@ -92,15 +93,18 @@ class TestShapes < Test::Unit::TestCase
# RubyVM::Shape.of returns new instances of shape objects for
# each call. This helper method allows us to define equality for
# shapes
- def assert_shape_equal(shape1, shape2)
- assert_equal(shape1.id, shape2.id)
- assert_equal(shape1.parent_id, shape2.parent_id)
- assert_equal(shape1.depth, shape2.depth)
- assert_equal(shape1.type, shape2.type)
+ def assert_shape_equal(e, a)
+ assert_equal(
+ {id: e.offset, parent_offset: e.parent_offset, depth: e.depth, type: e.type, name: e.edge_name},
+ {id: a.offset, parent_offset: a.parent_offset, depth: a.depth, type: a.type, name: e.edge_name},
+ )
end
- def refute_shape_equal(shape1, shape2)
- refute_equal(shape1.id, shape2.id)
+ def refute_shape_equal(e, a)
+ refute_equal(
+ {id: e.offset, parent_offset: e.parent_offset, depth: e.depth, type: e.type, name: e.edge_name},
+ {id: a.offset, parent_offset: a.parent_offset, depth: a.depth, type: a.type, name: e.edge_name},
+ )
end
def test_iv_order_correct_on_complex_objects
@@ -113,12 +117,12 @@ class TestShapes < Test::Unit::TestCase
assert_equal obj.expected_ivs, iv_list.map(&:to_s)
end
- def test_too_complex
+ def test_complex
ensure_complex
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
end
def test_ordered_alloc_is_not_complex
@@ -127,6 +131,48 @@ class TestShapes < Test::Unit::TestCase
assert_operator obj["variation_count"], :<, RubyVM::Shape::SHAPE_MAX_VARIATIONS
end
+ def test_max_iv_count
+ klass = Class.new
+ object = klass.new
+
+ assert_equal 0, RubyVM::Shape.class_max_iv_count(klass)
+ 8.times do |i|
+ object.instance_variable_set("@ivar_#{i}", i)
+ end
+ assert_equal 8, RubyVM::Shape.class_max_iv_count(klass)
+
+ subklass = Class.new(klass)
+ assert_equal 8, RubyVM::Shape.class_max_iv_count(subklass)
+ end
+
+ def test_max_iv_count_on_Object
+ object = Object.new
+
+ assert_equal 0, RubyVM::Shape.class_max_iv_count(Object)
+ 8.times do |i|
+ object.instance_variable_set("@ivar_#{i}", i)
+ end
+ assert_equal 0, RubyVM::Shape.class_max_iv_count(Object)
+ end
+
+ def test_max_iv_count_on_BasicObject
+ object = BasicObject.new
+
+ assert_equal 0, RubyVM::Shape.class_max_iv_count(BasicObject)
+ 8.times do |i|
+ Object.instance_method(:instance_variable_set).bind_call(object, "@ivar_#{i}", i)
+ end
+ assert_equal 0, RubyVM::Shape.class_max_iv_count(BasicObject)
+
+ subklass = Class.new(BasicObject)
+ object = subklass.new
+ assert_equal 0, RubyVM::Shape.class_max_iv_count(subklass)
+ 8.times do |i|
+ Object.instance_method(:instance_variable_set).bind_call(object, "@ivar_#{i}", i)
+ end
+ assert_equal 8, RubyVM::Shape.class_max_iv_count(subklass)
+ end
+
def test_too_many_ivs_on_obj
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
@@ -139,18 +185,21 @@ class TestShapes < Test::Unit::TestCase
obj.instance_variable_set(:@c, 1)
obj.instance_variable_set(:@d, 1)
- assert_predicate RubyVM::Shape.of(obj), :too_complex?
+ assert_predicate RubyVM::Shape.of(obj), :complex?
end;
end
def test_too_many_ivs_on_class
obj = Class.new
- (MANY_IVS + 1).times do
+ obj.instance_variable_set(:@test_too_many_ivs_on_class, 1)
+ refute_predicate RubyVM::Shape.of(obj), :complex?
+
+ MANY_IVS.times do
obj.instance_variable_set(:"@a#{_1}", 1)
end
- assert_false RubyVM::Shape.of(obj).too_complex?
+ assert_predicate RubyVM::Shape.of(obj), :complex?
end
def test_removing_when_too_many_ivs_on_class
@@ -179,7 +228,7 @@ class TestShapes < Test::Unit::TestCase
assert_empty obj.instance_variables
end
- def test_too_complex_geniv
+ def test_complex_geniv
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class TooComplex < Hash
@@ -221,7 +270,7 @@ class TestShapes < Test::Unit::TestCase
end
def test_run_out_of_shape_for_object
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class A
def initialize
@@ -332,7 +381,7 @@ class TestShapes < Test::Unit::TestCase
end
def test_gc_stress_during_evacuate_generic_ivar
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
[].instance_variable_set(:@a, 1)
@@ -500,7 +549,7 @@ class TestShapes < Test::Unit::TestCase
end
def test_run_out_of_shape_rb_obj_copy_ivar
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class A
def initialize
@@ -579,7 +628,7 @@ class TestShapes < Test::Unit::TestCase
end;
end
- def test_too_complex_ractor
+ def test_complex_ractor
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
$VERBOSE = nil
@@ -594,14 +643,14 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.instance_variable_set(:"@very_unique", 3)
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal 3, tc.very_unique
- assert_equal 3, Ractor.new(tc) { |x| Ractor.yield(x.very_unique) }.take
- assert_equal tc.instance_variables.sort, Ractor.new(tc) { |x| Ractor.yield(x.instance_variables) }.take.sort
+ assert_equal 3, Ractor.new(tc) { |x| x.very_unique }.value
+ assert_equal tc.instance_variables.sort, Ractor.new(tc) { |x| x.instance_variables }.value.sort
end;
end
- def test_too_complex_ractor_shareable
+ def test_complex_ractor_shareable
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
$VERBOSE = nil
@@ -616,13 +665,104 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.instance_variable_set(:"@very_unique", 3)
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal 3, tc.very_unique
assert_equal 3, Ractor.make_shareable(tc).very_unique
end;
end
- def test_too_complex_obj_ivar_ractor_share
+ def test_complex_and_frozen
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ $VERBOSE = nil
+ class TooComplex
+ attr_reader :very_unique
+ end
+
+ RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do
+ TooComplex.new.instance_variable_set(:"@unique_#{_1}", Object.new)
+ end
+
+ tc = TooComplex.new
+ tc.instance_variable_set(:"@very_unique", 3)
+
+ shape = RubyVM::Shape.of(tc)
+ assert_predicate shape, :complex?
+ refute_predicate shape, :shape_frozen?
+ tc.freeze
+ frozen_shape = RubyVM::Shape.of(tc)
+ refute_equal shape.id, frozen_shape.id
+ assert_predicate frozen_shape, :complex?
+ assert_predicate frozen_shape, :shape_frozen?
+
+ assert_equal 3, tc.very_unique
+ assert_equal 3, Ractor.make_shareable(tc).very_unique
+ end;
+ end
+
+ def test_object_id_transition_complex
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ obj = Object.new
+ obj.instance_variable_set(:@a, 1)
+ RubyVM::Shape.exhaust_shapes
+ assert_equal obj.object_id, obj.object_id
+ end;
+
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ class Hi; end
+ obj = Hi.new
+ obj.instance_variable_set(:@a, 1)
+ obj.instance_variable_set(:@b, 2)
+ old_id = obj.object_id
+
+ RubyVM::Shape.exhaust_shapes
+ obj.remove_instance_variable(:@a)
+
+ assert_equal old_id, obj.object_id
+ end;
+ end
+
+ def test_complex_and_frozen_and_object_id
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ $VERBOSE = nil
+ class TooComplex
+ attr_reader :very_unique
+ end
+
+ RubyVM::Shape::SHAPE_MAX_VARIATIONS.times do
+ TooComplex.new.instance_variable_set(:"@unique_#{_1}", Object.new)
+ end
+
+ tc = TooComplex.new
+ tc.instance_variable_set(:"@very_unique", 3)
+
+ shape = RubyVM::Shape.of(tc)
+ assert_predicate shape, :complex?
+ refute_predicate shape, :shape_frozen?
+ tc.freeze
+ frozen_shape = RubyVM::Shape.of(tc)
+ refute_equal shape.id, frozen_shape.id
+ assert_predicate frozen_shape, :complex?
+ assert_predicate frozen_shape, :shape_frozen?
+ refute_predicate frozen_shape, :has_object_id?
+
+ assert_equal tc.object_id, tc.object_id
+
+ id_shape = RubyVM::Shape.of(tc)
+ refute_equal frozen_shape.id, id_shape.id
+ assert_predicate id_shape, :complex?
+ assert_predicate id_shape, :has_object_id?
+ assert_predicate id_shape, :shape_frozen?
+
+ assert_equal 3, tc.very_unique
+ assert_equal 3, Ractor.make_shareable(tc).very_unique
+ end;
+ end
+
+ def test_complex_obj_ivar_ractor_share
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
$VERBOSE = nil
@@ -632,15 +772,15 @@ class TestShapes < Test::Unit::TestCase
r = Ractor.new do
o = Object.new
o.instance_variable_set(:@a, "hello")
- Ractor.yield(o)
+ o
end
- o = r.take
+ o = r.value
assert_equal "hello", o.instance_variable_get(:@a)
end;
end
- def test_too_complex_generic_ivar_ractor_share
+ def test_complex_generic_ivar_ractor_share
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
$VERBOSE = nil
@@ -650,10 +790,10 @@ class TestShapes < Test::Unit::TestCase
r = Ractor.new do
o = []
o.instance_variable_set(:@a, "hello")
- Ractor.yield(o)
+ o
end
- o = r.take
+ o = r.value
assert_equal "hello", o.instance_variable_get(:@a)
end;
end
@@ -663,7 +803,7 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal 3, tc.a3_m
end
@@ -672,7 +812,7 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal 3, tc.a3_m
assert_equal 3, tc.a3
end
@@ -682,7 +822,7 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
tc.write_iv_method
tc.write_iv_method
assert_equal 12345, tc.a3_m
@@ -694,7 +834,7 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
tc.write_iv
tc.write_iv
assert_equal 12345, tc.a3_m
@@ -706,7 +846,7 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal 3, tc.a3_m
assert_equal 3, tc.instance_variable_get(:@a3)
end
@@ -716,20 +856,53 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
+
+ assert_equal 3, tc.a3_m # make sure IV is initialized
+ assert tc.instance_variable_defined?(:@a3)
+ tc.remove_instance_variable(:@a3)
+ refute tc.instance_variable_defined?(:@a3)
+ assert_nil tc.a3
+ end
+
+ def test_delete_iv_after_complex_and_object_id
+ ensure_complex
+
+ tc = TooComplex.new
+ tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal 3, tc.a3_m # make sure IV is initialized
assert tc.instance_variable_defined?(:@a3)
+ tc.object_id
tc.remove_instance_variable(:@a3)
+ refute tc.instance_variable_defined?(:@a3)
assert_nil tc.a3
end
+ def test_delete_iv_after_complex_and_freeze
+ ensure_complex
+
+ tc = TooComplex.new
+ tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
+ assert_predicate RubyVM::Shape.of(tc), :complex?
+
+ assert_equal 3, tc.a3_m # make sure IV is initialized
+ assert tc.instance_variable_defined?(:@a3)
+ tc.freeze
+ assert_raise FrozenError do
+ tc.remove_instance_variable(:@a3)
+ end
+ assert tc.instance_variable_defined?(:@a3)
+ assert_equal 3, tc.a3
+ end
+
def test_delete_undefined_after_complex
ensure_complex
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
refute tc.instance_variable_defined?(:@a3)
assert_raise(NameError) do
@@ -786,13 +959,15 @@ class TestShapes < Test::Unit::TestCase
def test_remove_instance_variable_capacity_transition
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
- t_object_shape = RubyVM::Shape.find_by_id(RubyVM::Shape::FIRST_T_OBJECT_SHAPE_ID)
- assert_equal(RubyVM::Shape::SHAPE_T_OBJECT, t_object_shape.type)
-
- initial_capacity = t_object_shape.capacity
# a does not transition in capacity
a = Class.new.new
+ root_shape = RubyVM::Shape.of(a)
+
+ assert_equal(RubyVM::Shape::SHAPE_ROOT, root_shape.type)
+ initial_capacity = root_shape.capacity
+ refute_equal(0, initial_capacity)
+
initial_capacity.times do |i|
a.instance_variable_set(:"@ivar#{i + 1}", i)
end
@@ -821,11 +996,11 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
tc.freeze
assert_raise(FrozenError) { tc.a3_m }
# doesn't transition to frozen shape in this case
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
end
def test_read_undefined_iv_after_complex
@@ -833,9 +1008,9 @@ class TestShapes < Test::Unit::TestCase
tc = TooComplex.new
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
assert_equal nil, tc.iv_not_defined
- assert_predicate RubyVM::Shape.of(tc), :too_complex?
+ assert_predicate RubyVM::Shape.of(tc), :complex?
end
def test_shape_order
@@ -852,13 +1027,13 @@ class TestShapes < Test::Unit::TestCase
def test_iv_index
example = RemoveAndAdd.new
initial_shape = RubyVM::Shape.of(example)
- assert_equal 0, initial_shape.next_iv_index
+ assert_equal 0, initial_shape.next_field_index
example.add_foo # makes a transition
add_foo_shape = RubyVM::Shape.of(example)
assert_equal([:@foo], example.instance_variables)
- assert_equal(initial_shape.id, add_foo_shape.parent.id)
- assert_equal(1, add_foo_shape.next_iv_index)
+ assert_equal(initial_shape.offset, add_foo_shape.parent.offset)
+ assert_equal(1, add_foo_shape.next_field_index)
example.remove_foo # makes a transition
remove_foo_shape = RubyVM::Shape.of(example)
@@ -868,8 +1043,8 @@ class TestShapes < Test::Unit::TestCase
example.add_bar # makes a transition
bar_shape = RubyVM::Shape.of(example)
assert_equal([:@bar], example.instance_variables)
- assert_equal(initial_shape.id, bar_shape.parent_id)
- assert_equal(1, bar_shape.next_iv_index)
+ assert_equal(initial_shape.offset, bar_shape.parent_offset)
+ assert_equal(1, bar_shape.next_field_index)
end
def test_remove_then_add_again
@@ -888,10 +1063,41 @@ class TestShapes < Test::Unit::TestCase
def test_new_obj_has_t_object_shape
obj = TestObject.new
shape = RubyVM::Shape.of(obj)
- assert_equal RubyVM::Shape::SHAPE_T_OBJECT, shape.type
+ assert_equal RubyVM::Shape::SHAPE_ROOT, shape.type
assert_nil shape.parent
end
+ def test_shape_layout
+ assert_equal :robject, RubyVM::Shape.of(TestObject.new).layout
+
+ if ENV["RUBY_BOX"]
+ assert_equal :other, RubyVM::Shape.of(Kernel).layout
+ assert_equal :other, RubyVM::Shape.of(String).layout
+ else
+ assert_equal :rclass, RubyVM::Shape.of(Kernel).layout
+ assert_equal :rclass, RubyVM::Shape.of(String).layout
+ end
+
+ assert_equal :rclass, RubyVM::Shape.of(Class.new).layout
+ assert_equal :rclass, RubyVM::Shape.of(Module.new).layout
+
+ klass = Class.new
+ assert_equal :rclass, RubyVM::Shape.of(klass).layout
+ klass.instance_variable_set(:@a, 123)
+ assert_equal :rclass, RubyVM::Shape.of(klass).layout
+
+ assert_equal :rdata, RubyVM::Shape.of(Thread.current).layout
+ assert_equal :rdata, RubyVM::Shape.of(lambda {}).layout
+
+ assert_equal :other, RubyVM::Shape.of(Struct.new(:x).new(1)).layout
+ assert_equal :other, RubyVM::Shape.of([]).layout
+ assert_equal :other, RubyVM::Shape.of("hello").layout
+ assert_equal :other, RubyVM::Shape.of(/foo/).layout
+ assert_equal :other, RubyVM::Shape.of(2..3).layout
+ assert_equal :other, RubyVM::Shape.of(2**67).layout
+ assert_equal :other, RubyVM::Shape.of(:"aaroniscool#{123}").layout
+ end
+
def test_str_has_root_shape
assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of(""))
end
@@ -900,16 +1106,29 @@ class TestShapes < Test::Unit::TestCase
assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of([]))
end
- def test_true_has_special_const_shape_id
- assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of(true).id)
- end
-
- def test_nil_has_special_const_shape_id
- assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of(nil).id)
+ def test_raise_on_special_consts
+ assert_raise ArgumentError do
+ RubyVM::Shape.of(true)
+ end
+ assert_raise ArgumentError do
+ RubyVM::Shape.of(false)
+ end
+ assert_raise ArgumentError do
+ RubyVM::Shape.of(nil)
+ end
+ assert_raise ArgumentError do
+ RubyVM::Shape.of(0)
+ end
+ # 32-bit platforms don't have flonums or static symbols as special
+ # constants
+ # TODO(max): Add ArgumentError tests for symbol and flonum, skipping if
+ # RUBY_PLATFORM =~ /i686/
end
- def test_root_shape_transition_to_special_const_on_frozen
- assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of([].freeze).id)
+ def test_root_shape_frozen
+ frozen_root_shape = RubyVM::Shape.of([].freeze)
+ assert_predicate(frozen_root_shape, :frozen?)
+ assert_equal(RubyVM::Shape.root_shape.id, frozen_root_shape.offset)
end
def test_basic_shape_transition
@@ -920,7 +1139,7 @@ class TestShapes < Test::Unit::TestCase
assert_equal RubyVM::Shape::SHAPE_IVAR, shape.type
shape = shape.parent
- assert_equal RubyVM::Shape::SHAPE_T_OBJECT, shape.type
+ assert_equal RubyVM::Shape::SHAPE_ROOT, shape.type
assert_nil shape.parent
assert_equal(1, obj.instance_variable_get(:@a))
@@ -940,7 +1159,7 @@ class TestShapes < Test::Unit::TestCase
assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2))
end
- def test_duplicating_too_complex_objects_memory_leak
+ def test_duplicating_complex_objects_memory_leak
assert_no_memory_leak([], "#{<<~'begin;'}", "#{<<~'end;'}", "[Bug #20162]", rss: true)
RubyVM::Shape.exhaust_shapes
@@ -955,18 +1174,19 @@ class TestShapes < Test::Unit::TestCase
def test_freezing_and_duplicating_object
obj = Object.new.freeze
+ assert_predicate(RubyVM::Shape.of(obj), :shape_frozen?)
+
+ # dup'd objects shouldn't be frozen
obj2 = obj.dup
refute_predicate(obj2, :frozen?)
- # dup'd objects shouldn't be frozen, and the shape should be the
- # parent shape of the copied object
- assert_equal(RubyVM::Shape.of(obj).parent.id, RubyVM::Shape.of(obj2).id)
+ refute_predicate(RubyVM::Shape.of(obj2), :shape_frozen?)
end
def test_freezing_and_duplicating_object_with_ivars
obj = Example.new.freeze
obj2 = obj.dup
refute_predicate(obj2, :frozen?)
- refute_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2))
+ refute_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2))
assert_equal(obj2.instance_variable_get(:@a), 1)
end
@@ -976,6 +1196,7 @@ class TestShapes < Test::Unit::TestCase
str.freeze
str2 = str.dup
refute_predicate(str2, :frozen?)
+
refute_equal(RubyVM::Shape.of(str).id, RubyVM::Shape.of(str2).id)
assert_equal(str2.instance_variable_get(:@a), 1)
end
@@ -991,9 +1212,8 @@ class TestShapes < Test::Unit::TestCase
obj = Object.new
obj2 = obj.clone(freeze: true)
assert_predicate(obj2, :frozen?)
- refute_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2))
- assert_equal(RubyVM::Shape::SHAPE_FROZEN, RubyVM::Shape.of(obj2).type)
- assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2).parent)
+ refute_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2))
+ assert_predicate(RubyVM::Shape.of(obj2), :shape_frozen?)
end
def test_freezing_and_cloning_object_with_ivars
@@ -1036,4 +1256,68 @@ class TestShapes < Test::Unit::TestCase
tc.send("a#{_1}_m")
end
end
+
+ def assert_complex_during_delete(obj)
+ obj.instance_variable_set("@___#{SecureRandom.hex}", 1)
+
+ (RubyVM::Shape::SHAPE_MAX_VARIATIONS * 2).times do |i|
+ obj.instance_variable_set("@ivar#{i}", i)
+ end
+
+ refute_predicate RubyVM::Shape.of(obj), :complex?
+ (RubyVM::Shape::SHAPE_MAX_VARIATIONS * 2).times do |i|
+ obj.remove_instance_variable("@ivar#{i}")
+ end
+ assert_predicate RubyVM::Shape.of(obj), :complex?
+ end
+
+ def test_object_complex_during_delete
+ assert_complex_during_delete(Class.new.new)
+ end
+
+ def test_class_complex_during_delete
+ assert_complex_during_delete(Module.new)
+ end
+
+ def test_generic_complex_during_delete
+ assert_complex_during_delete(Class.new(Array).new)
+ end
+
+ def assert_complex_max_fields(obj)
+ extra_fields = RubyVM::Shape::SHAPE_MAX_FIELDS - obj.instance_variables.size
+ extra_fields.times do |i|
+ obj.instance_variable_set("@camel_ivar#{i}", i)
+ end
+ refute_predicate RubyVM::Shape.of(obj), :complex?
+ obj.instance_variable_set("@camel_straw", true)
+ assert_predicate RubyVM::Shape.of(obj), :complex?
+ end
+
+ def test_max_fields_complex
+ assert_complex_max_fields(Class.new(Object).new)
+ end
+
+ def test_generic_max_fields_complex
+ assert_complex_max_fields(Class.new(Array).new)
+ end
+
+ def test_class_max_fields_complex
+ assert_complex_max_fields(Class.new(Module).new)
+ end
+
+ def test_max_initial_fields
+ klass = Class.new
+ init_ivars = (RubyVM::Shape::SHAPE_MAX_FIELDS + 1).times.map { |i| "@ivar_#{i} = #{i}" }
+ klass.class_eval(<<~RUBY)
+ def initialize(init = false)
+ if init
+ #{init_ivars.join(";")}
+ end
+ end
+ RUBY
+ assert_predicate RubyVM::Shape.of(klass.new), :complex?
+ assert_predicate RubyVM::Shape.of(klass.new.dup), :complex?
+ assert_predicate RubyVM::Shape.of(klass.new(true)), :complex?
+ assert_predicate RubyVM::Shape.of(klass.new(true).dup), :complex?
+ end
end if defined?(RubyVM::Shape)
diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb
index a2bdf02b88..1ee3720ded 100644
--- a/test/ruby/test_signal.rb
+++ b/test/ruby/test_signal.rb
@@ -320,20 +320,20 @@ class TestSignal < Test::Unit::TestCase
# The parent should be notified about the stop
_, status = Process.waitpid2(child_pid, Process::WUNTRACED)
- assert status.stopped?
+ assert_predicate status, :stopped?
# It can be continued
Process.kill(:CONT, child_pid)
# And the child then runs to completion
_, status = Process.waitpid2(child_pid)
- assert status.exited?
- assert status.success?
+ assert_predicate status, :exited?
+ assert_predicate status, :success?
end
def test_sigwait_fd_unused
t = EnvUtil.apply_timeout_scale(0.1)
- assert_separately([], <<-End)
+ assert_ruby_status([], <<-End)
tgt = $$
trap(:TERM) { exit(0) }
e = "Process.daemon; sleep #{t * 2}; Process.kill(:TERM,\#{tgt})"
@@ -350,4 +350,18 @@ class TestSignal < Test::Unit::TestCase
loop { sleep }
End
end if Process.respond_to?(:kill) && Process.respond_to?(:daemon)
+
+ def test_signal_during_kwarg_call
+ status = assert_in_out_err([], <<~'RUBY', [], [], success: false)
+ Thread.new do
+ sleep 0.1
+ Process.kill("TERM", $$)
+ end
+
+ loop do
+ File.open(IO::NULL, kwarg: true) {}
+ end
+ RUBY
+ assert_predicate(status, :signaled?) if Signal.list.include?("QUIT")
+ end if Process.respond_to?(:kill)
end
diff --git a/test/ruby/test_sleep.rb b/test/ruby/test_sleep.rb
index 991b73ebd5..7ef962db4a 100644
--- a/test/ruby/test_sleep.rb
+++ b/test/ruby/test_sleep.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: false
require 'test/unit'
require 'etc'
+require 'timeout'
class TestSleep < Test::Unit::TestCase
def test_sleep_5sec
@@ -13,4 +14,21 @@ class TestSleep < Test::Unit::TestCase
assert_operator(slept, :<=, 6.0, "[ruby-core:18015]: longer than expected")
end
end
+
+ def test_sleep_forever_not_woken_by_sigchld
+ begin
+ t = Thread.new do
+ sleep 0.5
+ `echo hello`
+ end
+
+ assert_raise Timeout::Error do
+ Timeout.timeout 2 do
+ sleep # Should block forever
+ end
+ end
+ ensure
+ t.join
+ end
+ end
end
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 1011967fe9..aedfc93e5d 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -675,7 +675,7 @@ CODE
omit if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
require 'objspace'
- base_slot_size = GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]
+ base_slot_size = GC.stat_heap(0, :slot_size) - GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]
small_obj_size = (base_slot_size / 2)
large_obj_size = base_slot_size * 2
@@ -851,7 +851,6 @@ CODE
assert_equal(S("\u{AB}"), S('"\\u00AB"').undump)
assert_equal(S("\u{ABC}"), S('"\\u0ABC"').undump)
assert_equal(S("\uABCD"), S('"\\uABCD"').undump)
- assert_equal(S("\uABCD"), S('"\\uABCD"').undump)
assert_equal(S("\u{ABCDE}"), S('"\\u{ABCDE}"').undump)
assert_equal(S("\u{10ABCD}"), S('"\\u{10ABCD}"').undump)
assert_equal(S("\u{ABCDE 10ABCD}"), S('"\\u{ABCDE 10ABCD}"').undump)
@@ -872,6 +871,10 @@ CODE
assert_equal('\#', S('"\\\\#"').undump)
assert_equal('\#{', S('"\\\\\#{"').undump)
+ assert_undump("\0\u{ABCD}")
+ assert_undump(S('"\x00\u3042"'.force_encoding("SJIS")))
+ assert_undump(S('"\u3042\x7E"'.force_encoding("SJIS")))
+
assert_raise(RuntimeError) { S('\u3042').undump }
assert_raise(RuntimeError) { S('"\x82\xA0\u3042"'.force_encoding("SJIS")).undump }
assert_raise(RuntimeError) { S('"\u3042\x82\xA0"'.force_encoding("SJIS")).undump }
@@ -994,6 +997,32 @@ CODE
assert_equal [65, 66, 67], res
end
+ def test_getbyte
+ s = S('foo')
+ assert_equal(102, s.getbyte(0))
+ assert_equal(111, s.getbyte(2))
+ assert_equal(102, s.getbyte(-3))
+ assert_nil(s.getbyte(3))
+ assert_nil(s.getbyte(-4))
+ assert_nil(S('').getbyte(0))
+ assert_nil(S('').getbyte(-1))
+ end
+
+ def test_setbyte
+ s = S('xyzzy')
+ assert_equal(129, s.setbyte(2, 129))
+ assert_equal(S("xy\x81zy").force_encoding(s.encoding), s)
+
+ s = S('foo')
+ s.setbyte(-3, 98)
+ assert_equal(S('boo').force_encoding(s.encoding), s)
+
+ assert_raise(IndexError) { S('foo').setbyte(3, 0) }
+ assert_raise(IndexError) { S('foo').setbyte(-4, 0) }
+
+ assert_raise(FrozenError) { S('foo').freeze.setbyte(0, 0x61) }
+ end
+
def test_each_codepoint
# Single byte optimization
assert_equal 65, S("ABC").each_codepoint.next
@@ -1869,6 +1898,13 @@ CODE
result = []; S("aaa,bbb,ccc,ddd").split(/,/) {|s| result << s.gsub(/./, "A")}
assert_equal(["AAA"]*4, result)
+
+ s = S("abc ") * 20
+ assert_raise(RuntimeError) {
+ 10.times do
+ s.split {s.prepend("xxx" * 100)}
+ end
+ }
ensure
EnvUtil.suppress_warning {$; = fs}
end
@@ -1876,9 +1912,24 @@ CODE
def test_fs
return unless @cls == String
- assert_raise_with_message(TypeError, /\$;/) {
- $; = []
- }
+ begin
+ fs = $;
+ assert_deprecated_warning(/non-nil '\$;'/) {$; = "x"}
+ assert_raise_with_message(TypeError, /\$;/) {$; = []}
+ ensure
+ EnvUtil.suppress_warning {$; = fs}
+ end
+ name = "\u{5206 5217}"
+ assert_separately([], "#{<<~"do;"}\n#{<<~"end;"}")
+ do;
+ alias $#{name} $;
+ assert_deprecated_warning(/\\$#{name}/) { $#{name} = "" }
+ assert_raise_with_message(TypeError, /\\$#{name}/) { $#{name} = 1 }
+ end;
+ end
+
+ def test_fs_gc
+ return unless @cls == String
assert_separately(%W[-W0], "#{<<~"begin;"}\n#{<<~'end;'}")
bug = '[ruby-core:79582] $; must not be GCed'
@@ -2027,6 +2078,117 @@ CODE
assert_equal(S("x") ,a)
end
+ def test_strip_with_selectors
+ assert_equal(S("abc"), S("---abc+++").strip("-+"))
+ assert_equal(S("abc"), S("+++abc---").strip("-+"))
+ assert_equal(S("abc"), S("+-+abc-+-").strip("-+"))
+ assert_equal(S(""), S("---+++").strip("-+"))
+ assert_equal(S("abc "), S("---abc ").strip("-"))
+ assert_equal(S(" abc"), S(" abc+++").strip("+"))
+
+ # Test with multibyte characters
+ assert_equal(S("abc"), S("あああabcいいい").strip("あい"))
+ assert_equal(S("abc"), S("いいいabcあああ").strip("あい"))
+
+ # Test with NUL characters
+ assert_equal(S("abc\0"), S("---abc\0--").strip("-"))
+ assert_equal(S("\0abc"), S("--\0abc---").strip("-"))
+
+ # Test without modification
+ assert_equal(S("abc"), S("abc").strip("-+"))
+ assert_equal(S("abc"), S("abc").strip(""))
+
+ # Test with range
+ assert_equal(S("abc"), S("012abc345").strip("0-9"))
+ assert_equal(S("abc"), S("012abc345").strip("^a-z"))
+
+ # Test with multiple selectors
+ assert_equal(S("4abc56"), S("01234abc56789").strip("0-9", "^4-6"))
+ end
+
+ def test_strip_bang_with_chars
+ a = S("---abc+++")
+ assert_equal(S("abc"), a.strip!("-+"))
+ assert_equal(S("abc"), a)
+
+ a = S("+++abc---")
+ assert_equal(S("abc"), a.strip!("-+"))
+ assert_equal(S("abc"), a)
+
+ a = S("abc")
+ assert_nil(a.strip!("-+"))
+ assert_equal(S("abc"), a)
+
+ # Test with multibyte characters
+ a = S("あああabcいいい")
+ assert_equal(S("abc"), a.strip!("あい"))
+ assert_equal(S("abc"), a)
+ end
+
+ def test_lstrip_with_selectors
+ assert_equal(S("abc+++"), S("---abc+++").lstrip("-"))
+ assert_equal(S("abc---"), S("+++abc---").lstrip("+"))
+ assert_equal(S("abc"), S("---abc").lstrip("-"))
+ assert_equal(S(""), S("---").lstrip("-"))
+
+ # Test with multibyte characters
+ assert_equal(S("abcいいい"), S("あああabcいいい").lstrip("あ"))
+
+ # Test with NUL characters
+ assert_equal(S("\0abc+++"), S("--\0abc+++").lstrip("-"))
+
+ # Test without modification
+ assert_equal(S("abc"), S("abc").lstrip("-"))
+
+ # Test with range
+ assert_equal(S("abc345"), S("012abc345").lstrip("0-9"))
+
+ # Test with multiple selectors
+ assert_equal(S("4abc56789"), S("01234abc56789").lstrip("0-9", "^4-6"))
+ end
+
+ def test_lstrip_bang_with_chars
+ a = S("---abc+++")
+ assert_equal(S("abc+++"), a.lstrip!("-"))
+ assert_equal(S("abc+++"), a)
+
+ a = S("abc")
+ assert_nil(a.lstrip!("-"))
+ assert_equal(S("abc"), a)
+ end
+
+ def test_rstrip_with_selectors
+ assert_equal(S("---abc"), S("---abc+++").rstrip("+"))
+ assert_equal(S("+++abc"), S("+++abc---").rstrip("-"))
+ assert_equal(S("abc"), S("abc+++").rstrip("+"))
+ assert_equal(S(""), S("+++").rstrip("+"))
+
+ # Test with multibyte characters
+ assert_equal(S("あああabc"), S("あああabcいいい").rstrip("い"))
+
+ # Test with NUL characters
+ assert_equal(S("---abc\0"), S("---abc\0++").rstrip("+"))
+
+ # Test without modification
+ assert_equal(S("abc"), S("abc").rstrip("-"))
+
+ # Test with range
+ assert_equal(S("012abc"), S("012abc345").rstrip("0-9"))
+
+ # Test with multiple selectors
+ assert_equal(S("01234abc56"), S("01234abc56789").rstrip("0-9", "^4-6"))
+ end
+
+ def test_rstrip_bang_with_chars
+ a = S("---abc+++")
+ assert_equal(S("---abc"), a.rstrip!("+"))
+ assert_equal(S("---abc"), a)
+
+ a = S("abc")
+ assert_nil(a.rstrip!("+"))
+ assert_equal(S("abc"), a)
+ end
+
def test_sub
assert_equal(S("h*llo"), S("hello").sub(/[aeiou]/, S('*')))
assert_equal(S("h<e>llo"), S("hello").sub(/([aeiou])/, S('<\1>')))
@@ -2462,37 +2624,11 @@ CODE
assert_equal([0xa9, 0x42, 0x2260], S("\xc2\xa9B\xe2\x89\xa0").unpack(S("U*")))
-=begin
- skipping "Not tested:
- D,d & double-precision float, native format\\
- E & double-precision float, little-endian byte order\\
- e & single-precision float, little-endian byte order\\
- F,f & single-precision float, native format\\
- G & double-precision float, network (big-endian) byte order\\
- g & single-precision float, network (big-endian) byte order\\
- I & unsigned integer\\
- i & integer\\
- L & unsigned long\\
- l & long\\
-
- m & string encoded in base64 (uuencoded)\\
- N & long, network (big-endian) byte order\\
- n & short, network (big-endian) byte-order\\
- P & pointer to a structure (fixed-length string)\\
- p & pointer to a null-terminated string\\
- S & unsigned short\\
- s & short\\
- V & long, little-endian byte order\\
- v & short, little-endian byte order\\
- X & back up a byte\\
- x & null byte\\
- Z & ASCII string (null padded, count is width)\\
-"
-=end
+ # more comprehensive tests are in test_pack.rb
end
def test_upcase
- assert_equal(S("HELLO"), S("hello").upcase)
+ assert_equal(S("HELLO"), S("helLO").upcase)
assert_equal(S("HELLO"), S("hello").upcase)
assert_equal(S("HELLO"), S("HELLO").upcase)
assert_equal(S("ABC HELLO 123"), S("abc HELLO 123").upcase)
@@ -2646,8 +2782,9 @@ CODE
def test_match_method
assert_equal("bar", S("foobarbaz").match(/bar/).to_s)
- o = Regexp.new('foo')
- def o.match(x, y, z); x + y + z; end
+ o = Class.new(Regexp) {
+ def match(x, y, z) = x + y + z
+ }.new('foo')
assert_equal("foobarbaz", S("foo").match(o, "bar", "baz"))
x = nil
S("foo").match(o, "bar", "baz") {|y| x = y }
@@ -2780,14 +2917,21 @@ CODE
assert_equal([S("abcdb"), S("c"), S("e")], S("abcdbce").rpartition(/b\Kc/))
end
- def test_fs_setter
+ def test_rs
return unless @cls == String
- assert_raise(TypeError) { $/ = 1 }
+ begin
+ rs = $/
+ assert_deprecated_warning(/non-nil '\$\/'/) { $/ = "" }
+ assert_raise(TypeError) { $/ = 1 }
+ ensure
+ EnvUtil.suppress_warning { $/ = rs }
+ end
name = "\u{5206 884c}"
assert_separately([], "#{<<~"do;"}\n#{<<~"end;"}")
do;
alias $#{name} $/
+ assert_deprecated_warning(/\\$#{name}/) { $#{name} = "" }
assert_raise_with_message(TypeError, /\\$#{name}/) { $#{name} = 1 }
end;
end
@@ -2838,27 +2982,45 @@ CODE
assert_equal("\u3042", ("\u3042" * 100)[-1])
end
-=begin
def test_compare_different_encoding_string
s1 = S("\xff".force_encoding("UTF-8"))
s2 = S("\xff".force_encoding("ISO-2022-JP"))
assert_equal([-1, 1], [s1 <=> s2, s2 <=> s1].sort)
+
+ s3 = S("あ".force_encoding("UTF-16LE"))
+ s4 = S("a".force_encoding("IBM437"))
+ assert_equal([-1, 1], [s3 <=> s4, s4 <=> s3].sort)
end
-=end
def test_casecmp
assert_equal(0, S("FoO").casecmp("fOO"))
assert_equal(1, S("FoO").casecmp("BaR"))
+ assert_equal(-1, S("foo").casecmp("FOOBAR"))
assert_equal(-1, S("baR").casecmp("FoO"))
assert_equal(1, S("\u3042B").casecmp("\u3042a"))
assert_equal(-1, S("foo").casecmp("foo\0"))
+ assert_equal(1, S("FOOBAR").casecmp("foo"))
+ assert_equal(0, S("foo\0bar").casecmp("FOO\0BAR"))
assert_nil(S("foo").casecmp(:foo))
assert_nil(S("foo").casecmp(Object.new))
+ assert_nil(S("foo").casecmp(0))
+ assert_nil(S("foo").casecmp(5.00))
+
o = Object.new
def o.to_str; "fOO"; end
assert_equal(0, S("FoO").casecmp(o))
+
+ assert_equal(0, S("#" * 128 + "A" * 256 + "b").casecmp("#" * 128 + "a" * 256 + "B"))
+ assert_equal(0, S("a" * 256 + "B").casecmp("A" * 256 + "b"))
+
+ assert_equal(-1, S("@").casecmp("`"))
+ assert_equal(0, S("hello\u00E9X").casecmp("HELLO\u00E9x"))
+
+ s1 = S("\xff".force_encoding("UTF-8"))
+ s2 = S("\xff".force_encoding("ISO-2022-JP"))
+ assert_nil(s1.casecmp(s2))
end
def test_casecmp?
@@ -2871,9 +3033,16 @@ CODE
assert_nil(S("foo").casecmp?(:foo))
assert_nil(S("foo").casecmp?(Object.new))
+ assert_nil(S("foo").casecmp(0))
+ assert_nil(S("foo").casecmp(5.00))
+
o = Object.new
def o.to_str; "fOO"; end
assert_equal(true, S("FoO").casecmp?(o))
+
+ s1 = S("\xff".force_encoding("UTF-8"))
+ s2 = S("\xff".force_encoding("ISO-2022-JP"))
+ assert_nil(s1.casecmp?(s2))
end
def test_upcase2
@@ -2946,7 +3115,6 @@ CODE
s5 = S("\u0000\u3042")
assert_equal("\u3042", s5.lstrip!)
assert_equal("\u3042", s5)
-
end
def test_delete_prefix_type_error
@@ -3246,18 +3414,12 @@ CODE
assert_equal('"\\u3042\\u3044\\u3046"', S("\u3042\u3044\u3046".encode(e)).inspect)
assert_equal('"ab\\"c"', S("ab\"c".encode(e)).inspect, bug4081)
end
- begin
- verbose, $VERBOSE = $VERBOSE, nil
- ext = Encoding.default_external
- Encoding.default_external = "us-ascii"
- $VERBOSE = verbose
+
+ EnvUtil.with_default_external(Encoding::US_ASCII) do
i = S("abc\"\\".force_encoding("utf-8")).inspect
- ensure
- $VERBOSE = nil
- Encoding.default_external = ext
- $VERBOSE = verbose
+
+ assert_equal('"abc\\"\\\\"', i, bug4081)
end
- assert_equal('"abc\\"\\\\"', i, bug4081)
end
def test_dummy_inspect
@@ -3314,11 +3476,37 @@ CODE
assert_equal(u("\x82")+("\u3042"*9), S("\u3042"*10).byteslice(2, 28))
+ assert_equal("\xE3", S("こんにちは").byteslice(0))
+ assert_equal("こんにちは", S("こんにちは").byteslice(0, 15))
+ assert_equal("こ", S("こんにちは").byteslice(0, 3))
+ assert_equal("は", S("こんにちは").byteslice(12, 15))
+
bug7954 = '[ruby-dev:47108]'
assert_equal(false, S("\u3042").byteslice(0, 2).valid_encoding?, bug7954)
assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954)
end
+ def test_shared_middle_string_terminator
+ ten = "0123456789"
+ hundred = ten * 10
+ str = "#{hundred}\0#{hundred}".freeze
+
+ require 'objspace'
+
+ substr = str.byteslice(0, hundred.bytesize)
+ assert_equal hundred, substr
+ assert_includes ObjectSpace.dump(substr), ' "shared":true,'
+
+ # Larger terminator
+ substr.force_encoding(Encoding::UTF_16BE)
+ assert_equal hundred.dup.force_encoding(Encoding::UTF_16BE), substr
+ refute_includes ObjectSpace.dump(substr), ' "shared":true,'
+
+ substr = str.byteslice(0, hundred.bytesize + 1)
+ assert_equal hundred + "\0", substr
+ refute_includes ObjectSpace.dump(substr), ' "shared":true,'
+ end
+
def test_unknown_string_option
str = nil
assert_nothing_raised(SyntaxError) do
@@ -3437,6 +3625,17 @@ CODE
assert_equal(false, str.frozen?)
end
+ def test_uminus_no_embed_gc
+ pad = "a"*2048
+ File.open(IO::NULL, "w") do |dev_null|
+ ("aa".."zz").each do |c|
+ fstr = -(c + pad).freeze
+ dev_null.write(fstr)
+ end
+ end
+ GC.start
+ end
+
def test_ord
assert_equal(97, S("a").ord)
assert_equal(97, S("abc").ord)
@@ -3743,6 +3942,96 @@ CODE
Warning[:deprecated] = deprecated
end
+ def test_encode_fallback_raise_memory_leak
+ {
+ "hash" => <<~RUBY,
+ fallback = Hash.new { raise MyError }
+ RUBY
+ "proc" => <<~RUBY,
+ fallback = proc { raise MyError }
+ RUBY
+ "method" => <<~RUBY,
+ def my_method(_str) = raise MyError
+ fallback = method(:my_method)
+ RUBY
+ "aref" => <<~RUBY,
+ fallback = Object.new
+ def fallback.[](_str) = raise MyError
+ RUBY
+ }.each do |type, code|
+ assert_no_memory_leak([], '', <<~RUBY, "fallback type is #{type}", rss: true)
+ class MyError < StandardError; end
+
+ #{code}
+
+ 100_000.times do |i|
+ "\\ufffd".encode(Encoding::US_ASCII, fallback:)
+ rescue MyError
+ end
+ RUBY
+ end
+ end
+
+ def test_encode_fallback_too_big_memory_leak
+ {
+ "hash" => <<~RUBY,
+ fallback = Hash.new { "\\uffee" }
+ RUBY
+ "proc" => <<~RUBY,
+ fallback = proc { "\\uffee" }
+ RUBY
+ "method" => <<~RUBY,
+ def my_method(_str) = "\\uffee"
+ fallback = method(:my_method)
+ RUBY
+ "aref" => <<~RUBY,
+ fallback = Object.new
+ def fallback.[](_str) = "\\uffee"
+ RUBY
+ }.each do |type, code|
+ assert_no_memory_leak([], '', <<~RUBY, "fallback type is #{type}", rss: true)
+ class MyError < StandardError; end
+
+ #{code}
+
+ 100_000.times do |i|
+ "\\ufffd".encode(Encoding::US_ASCII, fallback:)
+ rescue ArgumentError
+ end
+ RUBY
+ end
+ end
+
+ def test_encode_fallback_not_string_memory_leak
+ {
+ "hash" => <<~RUBY,
+ fallback = Hash.new { Object.new }
+ RUBY
+ "proc" => <<~RUBY,
+ fallback = proc { Object.new }
+ RUBY
+ "method" => <<~RUBY,
+ def my_method(_str) = Object.new
+ fallback = method(:my_method)
+ RUBY
+ "aref" => <<~RUBY,
+ fallback = Object.new
+ def fallback.[](_str) = Object.new
+ RUBY
+ }.each do |type, code|
+ assert_no_memory_leak([], '', <<~RUBY, "fallback type is #{type}", rss: true)
+ class MyError < StandardError; end
+
+ #{code}
+
+ 100_000.times do |i|
+ "\\ufffd".encode(Encoding::US_ASCII, fallback:)
+ rescue TypeError
+ end
+ RUBY
+ end
+ end
+
private
def assert_bytesplice_result(expected, s, *args)
@@ -3789,6 +4078,10 @@ CODE
def assert_byterindex(expected, string, match, *rest)
assert_index_like(:byterindex, expected, string, match, *rest)
end
+
+ def assert_undump(str, *rest)
+ assert_equal(str, str.dump.undump, *rest)
+ end
end
class TestString2 < TestString
diff --git a/test/ruby/test_struct.rb b/test/ruby/test_struct.rb
index 3d727adf04..b37f4dba97 100644
--- a/test/ruby/test_struct.rb
+++ b/test/ruby/test_struct.rb
@@ -41,8 +41,14 @@ module TestStruct
end
end
+ MAX_EMBEDDED_MEMBERS = (
+ GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE] -
+ GC::INTERNAL_CONSTANTS[:RBASIC_SIZE] -
+ GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]
+ ) / RbConfig::SIZEOF["void*"]
+
def test_larger_than_largest_pool
- count = (GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE] / RbConfig::SIZEOF["void*"]) + 1
+ count = MAX_EMBEDDED_MEMBERS + 1
list = Array(0..count)
klass = @Struct.new(*list.map { |i| :"a_#{i}"})
struct = klass.new(*list)
@@ -535,19 +541,27 @@ module TestStruct
end
def test_named_structs_are_not_rooted
+ omit 'skip on riscv64-linux CI machine. See https://github.com/ruby/ruby/pull/13422' if ENV['RUBY_DEBUG'] == 'ci' && /riscv64-linux/ =~ RUBY_DESCRIPTION
+
# [Bug #20311]
- assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true)
+ assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true, limit: 2.2)
code = proc do
Struct.new("A")
Struct.send(:remove_const, :A)
end
- 1_000.times(&code)
+ 10_000.times(&code)
PREP
50_000.times(&code)
CODE
end
+ def test_frozen_subclass
+ test = Class.new(@Struct.new(:a)).freeze.new(a: 0)
+ assert_kind_of(@Struct, test)
+ assert_equal([:a], test.members)
+ end
+
class TopStruct < Test::Unit::TestCase
include TestStruct
diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb
index 8e973b0f7f..39594d74be 100644
--- a/test/ruby/test_super.rb
+++ b/test/ruby/test_super.rb
@@ -759,4 +759,33 @@ class TestSuper < Test::Unit::TestCase
inherited = inherited_class.new
assert_equal 2, inherited.test # it may read index=1 while it should be index=2
end
+
+ def test_define_initialize_in_basic_object
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ class ::BasicObject
+ alias_method :initialize, :initialize
+ def initialize
+ @bug = "[Bug #21992]"
+ end
+ end
+
+ assert_not_nil Object.new
+ end;
+ end
+
+ def test_super_in_basic_object
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ class ::BasicObject
+ def no_super
+ super()
+ rescue ::NameError
+ :ok
+ end
+ end
+
+ assert_equal :ok, "[Bug #21694]".no_super
+ end;
+ end
end
diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb
index c50febf5d1..fa65dca225 100644
--- a/test/ruby/test_symbol.rb
+++ b/test/ruby/test_symbol.rb
@@ -417,8 +417,9 @@ class TestSymbol < Test::Unit::TestCase
def test_match_method
assert_equal("bar", :"foobarbaz".match(/bar/).to_s)
- o = Regexp.new('foo')
- def o.match(x, y, z); x + y + z; end
+ o = Class.new(Regexp) {
+ def match(x, y, z) = x + y + z
+ }.new('foo')
assert_equal("foobarbaz", :"foo".match(o, "bar", "baz"))
x = nil
:"foo".match(o, "bar", "baz") {|y| x = y }
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 62f1d99bdc..ae4cdf5fe7 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -202,6 +202,59 @@ class TestSyntax < Test::Unit::TestCase
assert_syntax_error("def f(...); g(&); end", /no anonymous block parameter/)
end
+ def test_no_block_argument_in_method
+ assert_valid_syntax("def f(&nil) end")
+ assert_valid_syntax("def f(a, &nil) end")
+ assert_valid_syntax("def f(*rest, &nil) end")
+ assert_valid_syntax("def f(*rest, p, &nil) end")
+ assert_valid_syntax("def f(a, *rest, &nil) end")
+ assert_valid_syntax("def f(a, *rest, p, &nil) end")
+ assert_valid_syntax("def f(a, k: nil, &nil) end")
+ assert_valid_syntax("def f(a, k: nil, **kw, &nil) end")
+ assert_valid_syntax("def f(a, *rest, k: nil, &nil) end")
+ assert_valid_syntax("def f(a, *rest, k: nil, **kw, &nil) end")
+ assert_valid_syntax("def f(a, *rest, p, k: nil, &nil) end")
+ assert_valid_syntax("def f(a, *rest, p, k: nil, **kw, &nil) end")
+
+ obj = Object.new
+ obj.instance_eval "def f(&nil) end"
+ assert_raise_with_message(ArgumentError, /block accepted/) {obj.f {}}
+ assert_raise_with_message(ArgumentError, /block accepted/) {obj.f(&proc {})}
+ end
+
+ def test_trailing_comma_in_method_parameters
+ assert_valid_syntax("def f(a,b,c,); end")
+ assert_valid_syntax("def f(a,b,*c,); end")
+ assert_valid_syntax("def f(a,b,*,); end")
+ assert_valid_syntax("def f(a,b,**c,); end")
+ assert_valid_syntax("def f(a,b,**,); end")
+ assert_syntax_error("def f(a,b,&block,); end", /unexpected/)
+ assert_syntax_error("def f(a,b,...,); end", /unexpected/)
+ end
+
+ def test_no_block_argument_in_block
+ assert_valid_syntax("proc do |&nil| end")
+ assert_valid_syntax("proc do |a, &nil| end")
+ assert_valid_syntax("proc do |*rest, &nil| end")
+ assert_valid_syntax("proc do |*rest, p, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, p, &nil| end")
+ assert_valid_syntax("proc do |a, k: nil, &nil| end")
+ assert_valid_syntax("proc do |a, k: nil, **kw, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, k: nil, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, k: nil, **kw, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, p, k: nil, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, p, k: nil, **kw, &nil| end")
+
+ pr = eval "proc {|&nil|}"
+ assert_nil(pr.call)
+ assert_raise_with_message(ArgumentError, /block accepted/) {pr.call {}}
+ pr = eval "proc {|a, &nil| a}"
+ assert_nil(pr.call)
+ assert_equal(1, pr.call(1))
+ assert_raise_with_message(ArgumentError, /block accepted/) {pr.call {}}
+ end
+
def test_newline_in_block_parameters
bug = '[ruby-dev:45292]'
["", "a", "a, b"].product(["", ";x", [";", "x"]]) do |params|
@@ -1259,6 +1312,52 @@ eom
assert_valid_syntax("a #\n#\n&.foo\n")
end
+ def test_fluent_and
+ assert_valid_syntax("a\n" "&& foo")
+ assert_valid_syntax("a\n" "and foo")
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = true
+ if a
+ && (a = :ok; true)
+ a
+ end
+ end;
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = true
+ if a
+ and (a = :ok; true)
+ a
+ end
+ end;
+ end
+
+ def test_fluent_or
+ assert_valid_syntax("a\n" "|| foo")
+ assert_valid_syntax("a\n" "or foo")
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = false
+ if a
+ || (a = :ok; true)
+ a
+ end
+ end;
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = false
+ if a
+ or (a = :ok; true)
+ a
+ end
+ end;
+ end
+
def test_safe_call_in_massign_lhs
assert_syntax_error("*a&.x=0", /multiple assignment destination/)
assert_syntax_error("a&.x,=0", /multiple assignment destination/)
@@ -1493,10 +1592,10 @@ eom
begin raise; rescue; return; end
return false; raise
return 1; raise
- "#{return}"
- raise((return; "should not raise"))
+ "#{return if true}"
+ raise((return if true; "should not raise"))
begin raise; ensure return; end; self
- nil&defined?0--begin e=no_method_error(); return; 0;end
+ nil&defined?0--begin e=no_method_error(); return if true; 0;end
return puts('ignored') #=> ignored
BEGIN {return}
END {return if false}
@@ -1794,15 +1893,12 @@ eom
assert_equal("class ok", k.rescued("ok"))
assert_equal("instance ok", k.new.rescued("ok"))
- # Current technical limitation: cannot prepend "private" or something for command endless def
- error = /(syntax error,|\^~*) unexpected string literal/
- error2 = /(syntax error,|\^~*) unexpected local variable or method/
- assert_syntax_error('private def foo = puts "Hello"', error)
- assert_syntax_error('private def foo() = puts "Hello"', error)
- assert_syntax_error('private def foo(x) = puts x', error2)
- assert_syntax_error('private def obj.foo = puts "Hello"', error)
- assert_syntax_error('private def obj.foo() = puts "Hello"', error)
- assert_syntax_error('private def obj.foo(x) = puts x', error2)
+ assert_valid_syntax('private def foo = puts "Hello"')
+ assert_valid_syntax('private def foo() = puts "Hello"')
+ assert_valid_syntax('private def foo(x) = puts x')
+ assert_valid_syntax('private def obj.foo = puts "Hello"')
+ assert_valid_syntax('private def obj.foo() = puts "Hello"')
+ assert_valid_syntax('private def obj.foo(x) = puts x')
end
def test_methoddef_in_cond
@@ -1815,6 +1911,24 @@ eom
assert_valid_syntax('while class Foo a = tap do end; end; break; end')
end
+ def test_while_until_conditional_bug_22002
+ @foo = 123 until defined?(@foo)
+ assert_equal(123, @foo)
+
+ @bar = 456 while @bar==nil..true
+ assert_equal(456, @bar)
+
+ while false and @baz
+ @baz = 789
+ end
+ assert_equal(nil, @baz)
+
+ until true || @baz
+ @baz = 789
+ end
+ assert_equal(nil, @baz)
+ end
+
def test_command_with_cmd_brace_block
assert_valid_syntax('obj.foo (1) {}')
assert_valid_syntax('obj::foo (1) {}')
@@ -1946,6 +2060,40 @@ eom
end
assert_valid_syntax('proc {def foo(_);end;it}')
assert_syntax_error('p { [it **2] }', /unexpected \*\*/)
+ assert_equal(1, eval('1.then { raise rescue it }'))
+ assert_equal(2, eval('1.then { 2.then { raise rescue it } }'))
+ assert_equal(3, eval('3.then { begin; raise; rescue; it; end }'))
+ assert_equal(4, eval('4.tap { begin; raise ; rescue; raise rescue it; end; }'))
+ assert_equal(5, eval('a = 0; 5.then { begin; nil; ensure; a = it; end }; a'))
+ assert_equal(6, eval('a = 0; 6.then { begin; nil; rescue; ensure; a = it; end }; a'))
+ assert_equal(7, eval('a = 0; 7.then { begin; raise; ensure; a = it; end } rescue a'))
+ assert_equal(8, eval('a = 0; 8.then { begin; raise; rescue; ensure; a = it; end }; a'))
+ assert_equal(/9/, eval('9.then { /#{it}/o }'))
+ end
+
+ def test_it_with_splat_super_method
+ bug21256 = '[ruby-core:121592] [Bug #21256]'
+
+ a = Class.new do
+ define_method(:foo) { it }
+ end
+ b = Class.new(a) do
+ def foo(*args) = super
+ end
+
+ assert_equal(1, b.new.foo(1), bug21256)
+ end
+
+ BUG_21669 = '[Bug #21669]'
+
+ def test_value_expr_in_block
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 2.1")
+ {#
+ x = begin
+ return
+ "NG"
+ end
+ };
end
def test_value_expr_in_condition
@@ -1954,6 +2102,51 @@ eom
assert_valid_syntax("tap {a = (true ? true : break)}")
assert_valid_syntax("tap {a = (break if false)}")
assert_valid_syntax("tap {a = (break unless true)}")
+
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.4")
+ {#
+ x = if rand < 0.5
+ return
+ else
+ return
+ end
+ };
+
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 2.2")
+ {#
+ x = if rand < 0.5
+ return
+ "NG"
+ else
+ return
+ end
+ };
+
+ assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}", "#{BUG_21669} 2.3")
+ {#
+ x = begin
+ return if true
+ "OK"
+ end
+ };
+
+ assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}")
+ {#
+ x = if true
+ return "NG"
+ else
+ "OK"
+ end
+ };
+
+ assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}")
+ {#
+ x = if false
+ "OK"
+ else
+ return "NG"
+ end
+ };
end
def test_value_expr_in_singleton
@@ -1961,6 +2154,67 @@ eom
assert_syntax_error("class << (return); end", mesg)
end
+ def test_value_expr_in_rescue
+ assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}", "#{BUG_21669} 1.1")
+ {#
+ x = begin
+ raise
+ return
+ rescue
+ "OK"
+ else
+ return
+ end
+ };
+
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.2")
+ {#
+ x = begin
+ foo
+ rescue
+ return
+ else
+ return
+ end
+ };
+ end
+
+ def test_value_expr_in_case
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3")
+ {#
+ x =
+ case a
+ when 1; return
+ when 2; return
+ else return
+ end
+ };
+ end
+
+ def test_value_expr_in_case2
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3")
+ {#
+ x =
+ case
+ when 1; return
+ when 2; return
+ else return
+ end
+ };
+ end
+
+ def test_value_expr_in_case3
+ assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3")
+ {#
+ x =
+ case a
+ in 1; return
+ in 2; return
+ else return
+ end
+ };
+ end
+
def test_tautological_condition
assert_valid_syntax("def f() return if false and invalid; nil end")
assert_valid_syntax("def f() return unless true or invalid; nil end")
@@ -2018,10 +2272,11 @@ eom
end
obj4 = obj1.clone
obj5 = obj1.clone
+ obj6 = obj1.clone
obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
- obj1.instance_eval('def foo(...) eval("bar(...)") end', __FILE__, __LINE__)
obj4.instance_eval("def foo ...\n bar(...)\n""end", __FILE__, __LINE__)
obj5.instance_eval("def foo ...; bar(...); end", __FILE__, __LINE__)
+ obj6.instance_eval('def foo(...) eval("bar(...)") end', __FILE__, __LINE__)
klass = Class.new {
def foo(*args, **kws, &block)
@@ -2050,7 +2305,7 @@ eom
end
obj3.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
- [obj1, obj2, obj3, obj4, obj5].each do |obj|
+ [obj1, obj2, obj3, obj4, obj5, obj6].each do |obj|
assert_warning('') {
assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5) {|*x| x})
}
@@ -2230,13 +2485,13 @@ eom
end
def test_class_module_Object_ancestors
- assert_separately([], <<-RUBY)
+ assert_ruby_status([], <<-RUBY)
m = Module.new
m::Bug18832 = 1
include m
class Bug18832; end
RUBY
- assert_separately([], <<-RUBY)
+ assert_ruby_status([], <<-RUBY)
m = Module.new
m::Bug18832 = 1
include m
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index 7784e0bdae..c3d9dcf56d 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -243,6 +243,10 @@ class TestThread < Test::Unit::TestCase
def test_join_argument_conversion
t = Thread.new {}
+
+ # Make sure that the thread terminates
+ Thread.pass while t.status
+
assert_raise(TypeError) {t.join(:foo)}
limit = Struct.new(:to_f, :count).new(0.05)
@@ -794,7 +798,7 @@ class TestThread < Test::Unit::TestCase
def for_test_handle_interrupt_with_return
Thread.handle_interrupt(Object => :never){
- Thread.current.raise RuntimeError.new("have to be rescured")
+ Thread.current.raise RuntimeError.new("have to be rescued")
return
}
rescue
@@ -811,7 +815,7 @@ class TestThread < Test::Unit::TestCase
assert_nothing_raised do
begin
Thread.handle_interrupt(Object => :never){
- Thread.current.raise RuntimeError.new("have to be rescured")
+ Thread.current.raise RuntimeError.new("have to be rescued")
break
}
rescue
@@ -1476,6 +1480,8 @@ q.pop
end
def test_thread_interrupt_for_killed_thread
+ pend "hang-up" if /mswin|mingw/ =~ RUBY_PLATFORM
+
opts = { timeout: 5, timeout_error: nil }
assert_normal_exit(<<-_end, '[Bug #8996]', **opts)
@@ -1585,4 +1591,107 @@ q.pop
frame_for_deadlock_test_2 { t.join }
INPUT
end
+
+ def test_unlock_locked_mutex_with_collected_fiber
+ bug21342 = '[ruby-core:122121] [Bug #21342]'
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}", bug21342)
+ begin;
+ 5.times do
+ m = Mutex.new
+ Thread.new do
+ m.synchronize do
+ end
+ end.join
+ Fiber.new do
+ GC.start
+ m.lock
+ end.resume
+ end
+ end;
+ end
+
+ def test_unlock_locked_mutex_with_collected_fiber2
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ MUTEXES = []
+ 5.times do
+ m = Mutex.new
+ Fiber.new do
+ GC.start
+ m.lock
+ end.resume
+ MUTEXES << m
+ end
+ 10.times do
+ MUTEXES.clear
+ GC.start
+ end
+ end;
+ end
+
+ def test_mutexes_locked_in_fiber_dont_have_aba_issue_with_new_fibers
+ assert_ruby_status([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ mutexes = 1000.times.map do
+ Mutex.new
+ end
+
+ mutexes.map do |m|
+ Fiber.new do
+ m.lock
+ end.resume
+ end
+
+ GC.start
+
+ 1000.times.map do
+ Fiber.new do
+ raise "FAILED!" if mutexes.any?(&:owned?)
+ end.resume
+ end
+ end;
+ end
+
+ # [Bug #21836]
+ def test_mn_threads_sub_millisecond_sleep
+ assert_separately([{'RUBY_MN_THREADS' => '1'}], "#{<<~"begin;"}\n#{<<~'end;'}", timeout: 30)
+ begin;
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ 1000.times { sleep 0.0001 }
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ elapsed = t1 - t0
+ assert_operator elapsed, :>=, 0.1, "sub-millisecond sleeps should not return immediately"
+ end;
+ end
+
+ # [Bug #21926]
+ def test_thread_join_during_finalizers
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", timeout: 60)
+ begin;
+ require 'open3'
+
+ class ProcessWrapper
+ def initialize
+ @stdin, @stdout, @stderr, @wait_thread = Open3.popen3("cat") # hangs until we close our stdin side
+ ObjectSpace.define_finalizer(self, self.class.make_finalizer(@stdin, @stdout, @stderr, @wait_thread))
+ end
+
+ def self.make_finalizer(stdin, stdout, stderr, wait_thread)
+ proc do
+ stdin.close rescue nil
+ stdout.close rescue nil
+ stderr.close rescue nil
+ # On some GC implementations (e.g. mmtk), finalizers run as postponed
+ # jobs which can execute on any thread, including the wait_thread itself.
+ # Guard against joining the current thread.
+ wait_thread.value unless Thread.current == wait_thread
+ end
+ end
+ end
+
+ 20.times { ProcessWrapper.new }
+ GC.stress = true
+ 1000.times { Object.new }
+ end;
+ end
end
diff --git a/test/ruby/test_thread_cv.rb b/test/ruby/test_thread_cv.rb
index eb88b9606c..e5fd513c5c 100644
--- a/test/ruby/test_thread_cv.rb
+++ b/test/ruby/test_thread_cv.rb
@@ -70,13 +70,13 @@ class TestThreadConditionVariable < Test::Unit::TestCase
end
end
end
- sleep 0.1
+ Thread.pass until threads.all?(&:stop?)
mutex.synchronize do
result << "P1"
condvar.broadcast
result << "P2"
end
- Timeout.timeout(5) do
+ Timeout.timeout(60) do
nr_threads.times do |i|
threads[i].join
end
diff --git a/test/ruby/test_thread_queue.rb b/test/ruby/test_thread_queue.rb
index 545bf98888..4046185fd2 100644
--- a/test/ruby/test_thread_queue.rb
+++ b/test/ruby/test_thread_queue.rb
@@ -217,7 +217,7 @@ class TestThreadQueue < Test::Unit::TestCase
bug5343 = '[ruby-core:39634]'
Dir.mktmpdir {|d|
- timeout = 60
+ timeout = 120
total_count = 250
begin
assert_normal_exit(<<-"_eom", bug5343, timeout: timeout, chdir: d)
@@ -235,8 +235,14 @@ class TestThreadQueue < Test::Unit::TestCase
end
_eom
rescue Timeout::Error
+ # record load average:
+ uptime = `uptime` rescue nil
+ if uptime && /(load average: [\d.]+),/ =~ uptime
+ la = " (#{$1})"
+ end
+
count = File.read("#{d}/test_thr_kill_count").to_i
- flunk "only #{count}/#{total_count} done in #{timeout} seconds."
+ flunk "only #{count}/#{total_count} done in #{timeout} seconds.#{la}"
end
}
end
@@ -373,7 +379,7 @@ class TestThreadQueue < Test::Unit::TestCase
assert_equal false, q.closed?
q << :something
assert_equal q, q.close
- assert q.closed?
+ assert_predicate q, :closed?
assert_raise_with_message(ClosedQueueError, /closed/){q << :nothing}
assert_equal q.pop, :something
assert_nil q.pop
@@ -427,7 +433,7 @@ class TestThreadQueue < Test::Unit::TestCase
assert_equal 1, q.size
assert_equal :one, q.pop
- assert q.empty?, "queue not empty"
+ assert_empty q
end
# make sure that shutdown state is handled properly by empty? for the non-blocking case
@@ -561,7 +567,7 @@ class TestThreadQueue < Test::Unit::TestCase
assert_equal 0, q.size
assert_equal 3, ary.size
- ary.each{|e| assert [0,1,2,3,4,5].include?(e)}
+ ary.each{|e| assert_include [0,1,2,3,4,5], e}
assert_nil q.pop
prod_threads.each{|t|
diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb
index 333edb8021..b2cbd06a9f 100644
--- a/test/ruby/test_time.rb
+++ b/test/ruby/test_time.rb
@@ -1421,7 +1421,7 @@ class TestTime < Test::Unit::TestCase
# Time objects are common in some code, try to keep them small
omit "Time object size test" if /^(?:i.?86|x86_64)-linux/ !~ RUBY_PLATFORM
omit "GC is in debug" if GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD] > 0
- omit "memsize is not accurate due to using malloc_usable_size" if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
+ omit "memsize is not accurate due to using malloc_usable_size" if GC::INTERNAL_CONSTANTS[:HEAP_COUNT] == 1
omit "Only run this test on 64-bit" if RbConfig::SIZEOF["void*"] != 8
require 'objspace'
@@ -1433,7 +1433,10 @@ class TestTime < Test::Unit::TestCase
RbConfig::SIZEOF["void*"] # Same size as VALUE
end
sizeof_vtm = RbConfig::SIZEOF["void*"] * 4 + 8
- expect = GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + sizeof_timew + sizeof_vtm
+ data_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] + sizeof_timew + sizeof_vtm
+ # Round up to the smallest slot size that fits
+ slot_sizes = GC::INTERNAL_CONSTANTS[:HEAP_COUNT].times.map { |i| GC.stat_heap(i, :slot_size) }
+ expect = slot_sizes.find { |s| s >= data_size } || slot_sizes.last
assert_operator ObjectSpace.memsize_of(t), :<=, expect
rescue LoadError => e
omit "failed to load objspace: #{e.message}"
diff --git a/test/ruby/test_time_tz.rb b/test/ruby/test_time_tz.rb
index f66cd9bec2..473c3cabcb 100644
--- a/test/ruby/test_time_tz.rb
+++ b/test/ruby/test_time_tz.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: false
require 'test/unit'
-require '-test-/time'
class TestTimeTZ < Test::Unit::TestCase
has_right_tz = true
diff --git a/test/ruby/test_transcode.rb b/test/ruby/test_transcode.rb
index 63d37f4ba4..2c4462eb71 100644
--- a/test/ruby/test_transcode.rb
+++ b/test/ruby/test_transcode.rb
@@ -2320,6 +2320,93 @@ class TestTranscode < Test::Unit::TestCase
assert_equal("A\nB\nC", s.encode(usascii, newline: :lf))
end
+ def test_ractor_lazy_load_encoding
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}", timeout: 60)
+ begin;
+ rs = []
+ autoload_encodings = Encoding.list.select { |e| e.inspect.include?("(autoload)") }.freeze
+ 7.times do
+ rs << Ractor.new(autoload_encodings) do |encodings|
+ str = "\u0300"
+ encodings.each do |enc|
+ str.encode(enc) rescue Encoding::UndefinedConversionError
+ end
+ end
+ end
+
+ while rs.any?
+ r, _obj = Ractor.select(*rs)
+ rs.delete(r)
+ end
+ assert_empty rs
+ end;
+ end
+
+ def test_ractor_lazy_load_encoding_random
+ omit 'unstable on s390x and windows' if RUBY_PLATFORM =~ /s390x|mswin/
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}", timeout: 30)
+ begin;
+ rs = []
+ 100.times do
+ rs << Ractor.new do
+ "\u0300".encode(Encoding.list.sample) rescue Encoding::UndefinedConversionError
+ end
+ end
+
+ while rs.any?
+ r, _obj = Ractor.select(*rs)
+ rs.delete(r)
+ end
+ assert_empty rs
+ end;
+ end
+
+ def test_ractor_asciicompat_encoding_exists
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ rs = []
+ 7.times do
+ rs << Ractor.new do
+ string = "ISO-2022-JP"
+ encoding = Encoding.find(string)
+ 20_000.times do
+ Encoding::Converter.asciicompat_encoding(string)
+ Encoding::Converter.asciicompat_encoding(encoding)
+ end
+ end
+ end
+
+ while rs.any?
+ r, _obj = Ractor.select(*rs)
+ rs.delete(r)
+ end
+ assert_empty rs
+ end;
+ end
+
+ def test_ractor_asciicompat_encoding_doesnt_exist
+ assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}", timeout: 60)
+ begin;
+ rs = []
+ NO_EXIST = "I".freeze
+ 7.times do
+ rs << Ractor.new do
+ 50.times do
+ if (val = Encoding::Converter.asciicompat_encoding(NO_EXIST))
+ raise "Got #{val}, expected nil"
+ end
+ end
+ end
+ end
+
+ while rs.any?
+ r, _obj = Ractor.select(*rs)
+ rs.delete(r)
+ end
+ assert_empty rs
+ end;
+ end
+
private
def assert_conversion_both_ways_utf8(utf8, raw, encoding)
diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb
index 49fec2d40e..a305ad6b2a 100644
--- a/test/ruby/test_variable.rb
+++ b/test/ruby/test_variable.rb
@@ -50,6 +50,11 @@ class TestVariable < Test::Unit::TestCase
end
Zeus = Gods.clone
+ class Zeus
+ def ruler5
+ @@rule
+ end
+ end
def test_cloned_allows_setting_cvar
Zeus.class_variable_set(:@@rule, "Athena")
@@ -58,8 +63,12 @@ class TestVariable < Test::Unit::TestCase
zeus = Zeus.new.ruler0
assert_equal "Cronus", god
- assert_equal "Athena", zeus
- assert_not_equal god.object_id, zeus.object_id
+ assert_equal "Cronus", zeus
+
+ assert_equal "Athena", Zeus.new.ruler5
+
+ assert_equal "Cronus", Gods.class_variable_get(:@@rule)
+ assert_equal "Athena", Zeus.class_variable_get(:@@rule)
end
def test_singleton_class_included_class_variable
@@ -120,6 +129,34 @@ class TestVariable < Test::Unit::TestCase
TestVariable.send(:remove_const, :Parent) rescue nil
end
+ def test_cvar_cache_invalidated_by_parent_class_variable_set
+ m = Module.new { class_variable_set(:@@x, 1) }
+ a = Class.new
+ b = Class.new(a) do
+ include m
+ class_eval "def self.x; @@x; end"
+ end
+ assert_equal 1, b.x # warm cache
+ a.class_variable_set(:@@x, 2)
+ error = assert_raise(RuntimeError) { b.x }
+ assert_match(/class variable @@x of .+ is overtaken by .+/, error.message)
+ end
+
+ def test_cvar_cache_invalidated_by_module_class_variable_set
+ m = Module.new
+ n = Module.new
+ b = Class.new do
+ include m
+ include n
+ class_eval "def self.x; @@x; end"
+ end
+ m.class_variable_set(:@@x, 1)
+ assert_equal 1, b.x # warm cache
+ n.class_variable_set(:@@x, 2)
+ error = assert_raise(RuntimeError) { b.x }
+ assert_match(/class variable @@x of .+ is overtaken by .+/, error.message)
+ end
+
def test_cvar_overtaken_by_module
error = eval <<~EORB
class ParentForModule
@@ -388,6 +425,61 @@ class TestVariable < Test::Unit::TestCase
end
end
+ class RemoveIvar
+ class << self
+ attr_reader :ivar
+
+ def add_ivar
+ @ivar = 1
+ end
+ end
+
+ attr_reader :ivar
+
+ def add_ivar
+ @ivar = 1
+ end
+ end
+
+ def add_and_remove_ivar(obj)
+ assert_nil obj.ivar
+ assert_equal 1, obj.add_ivar
+ assert_equal 1, obj.instance_variable_get(:@ivar)
+ assert_equal 1, obj.ivar
+
+ obj.remove_instance_variable(:@ivar)
+ assert_nil obj.ivar
+
+ assert_raise NameError do
+ obj.remove_instance_variable(:@ivar)
+ end
+ end
+
+ def test_remove_instance_variables_object
+ obj = RemoveIvar.new
+ add_and_remove_ivar(obj)
+ add_and_remove_ivar(obj)
+ end
+
+ def test_remove_instance_variables_class
+ add_and_remove_ivar(RemoveIvar)
+ add_and_remove_ivar(RemoveIvar)
+ end
+
+ class RemoveIvarGeneric < Array
+ attr_reader :ivar
+
+ def add_ivar
+ @ivar = 1
+ end
+ end
+
+ def test_remove_instance_variables_generic
+ obj = RemoveIvarGeneric.new
+ add_and_remove_ivar(obj)
+ add_and_remove_ivar(obj)
+ end
+
class ExIvar < Hash
def initialize
@a = 1
@@ -407,6 +499,21 @@ class TestVariable < Test::Unit::TestCase
}
end
+ def test_exivar_resize_with_compaction_stress
+ omit "compaction doesn't work well on s390x" if RUBY_PLATFORM =~ /s390x/ # https://github.com/ruby/ruby/pull/5077
+ objs = 10_000.times.map do
+ ExIvar.new
+ end
+ EnvUtil.under_gc_compact_stress do
+ 10.times do
+ x = ExIvar.new
+ x.instance_variable_set(:@resize, 1)
+ x
+ end
+ end
+ objs or flunk
+ end
+
def test_local_variables_with_kwarg
bug11674 = '[ruby-core:71437] [Bug #11674]'
v = with_kwargs_11(v1:1,v2:2,v3:3,v4:4,v5:5,v6:6,v7:7,v8:8,v9:9,v10:10,v11:11)
@@ -426,12 +533,55 @@ class TestVariable < Test::Unit::TestCase
end
def test_local_variables_encoding
- α = 1
+ α = 1 or flunk
b = binding
b.eval("".encode("us-ascii"))
assert_equal(%i[α b], b.local_variables)
end
+ def test_genivar_cache
+ bug21547 = '[Bug #21547]'
+ klass = Class.new(Array)
+ instance = klass.new
+ instance.instance_variable_set(:@a1, 1)
+ instance.instance_variable_set(:@a2, 2)
+ Fiber.new do
+ instance.instance_variable_set(:@a3, 3)
+ instance.instance_variable_set(:@a4, 4)
+ end.resume
+ assert_equal 4, instance.instance_variable_get(:@a4), bug21547
+ end
+
+ def test_genivar_cache_free
+ str = +"hello"
+ str.instance_variable_set(:@x, :old_value)
+
+ str.instance_variable_get(:@x) # populate cache
+
+ Fiber.new {
+ str.remove_instance_variable(:@x)
+ str.instance_variable_set(:@x, :new_value)
+ }.resume
+
+ assert_equal :new_value, str.instance_variable_get(:@x)
+ end
+
+ def test_genivar_cache_invalidated_by_gc
+ str = +"hello"
+ str.instance_variable_set(:@x, :old_value)
+
+ str.instance_variable_get(:@x) # populate cache
+
+ Fiber.new {
+ str.remove_instance_variable(:@x)
+ str.instance_variable_set(:@x, :new_value)
+ }.resume
+
+ GC.start
+
+ assert_equal :new_value, str.instance_variable_get(:@x)
+ end
+
private
def with_kwargs_11(v1:, v2:, v3:, v4:, v5:, v6:, v7:, v8:, v9:, v10:, v11:)
local_variables
diff --git a/test/ruby/test_vm_dump.rb b/test/ruby/test_vm_dump.rb
index 709fd5eadf..d183e03391 100644
--- a/test/ruby/test_vm_dump.rb
+++ b/test/ruby/test_vm_dump.rb
@@ -5,8 +5,7 @@ return unless /darwin/ =~ RUBY_PLATFORM
class TestVMDump < Test::Unit::TestCase
def assert_darwin_vm_dump_works(args, timeout=nil)
- pend "macOS 15 is not working with this assertion" if macos?(15)
-
+ args.unshift({"RUBY_ON_BUG" => nil, "RUBY_CRASH_REPORT" => nil})
assert_in_out_err(args, "", [], /^\[IMPORTANT\]/, timeout: timeout || 300)
end
@@ -15,7 +14,7 @@ class TestVMDump < Test::Unit::TestCase
end
def test_darwin_segv_in_syscall
- assert_darwin_vm_dump_works('-e1.times{Process.kill :SEGV,$$}')
+ assert_darwin_vm_dump_works(['-e1.times{Process.kill :SEGV,$$}'])
end
def test_darwin_invalid_access
diff --git a/test/ruby/test_weakmap.rb b/test/ruby/test_weakmap.rb
index a2904776bc..2f5c747339 100644
--- a/test/ruby/test_weakmap.rb
+++ b/test/ruby/test_weakmap.rb
@@ -39,6 +39,13 @@ class TestWeakMap < Test::Unit::TestCase
assert_same(:foo, @wm[x])
end
+ def test_aset_returns_value
+ key = Object.new
+ value = Object.new
+
+ assert_same(value, @wm.send(:[]=, key, value))
+ end
+
def assert_weak_include(m, k, n = 100)
if n > 0
return assert_weak_include(m, k, n-1)
@@ -203,7 +210,7 @@ class TestWeakMap < Test::Unit::TestCase
@wm[i] = obj
end
- assert_separately([], <<-'end;')
+ assert_ruby_status([], <<-'end;')
wm = ObjectSpace::WeakMap.new
obj = Object.new
100.times do
@@ -224,7 +231,7 @@ class TestWeakMap < Test::Unit::TestCase
assert_equal(val, wm[key])
end;
- assert_separately(["-W0"], <<-'end;')
+ assert_ruby_status(["-W0"], <<-'end;')
wm = ObjectSpace::WeakMap.new
ary = 10_000.times.map do
@@ -265,4 +272,27 @@ class TestWeakMap < Test::Unit::TestCase
10_000.times { weakmap[Object.new] = Object.new }
RUBY
end
+
+ def test_generational_gc
+ EnvUtil.without_gc do
+ wmap = ObjectSpace::WeakMap.new
+
+ (GC::INTERNAL_CONSTANTS[:RVALUE_OLD_AGE] - 1).times { GC.start }
+
+ retain = []
+ 50.times do
+ k = Object.new
+ wmap[k] = true
+ retain << k
+ end
+
+ GC.start # WeakMap promoted, other objects still young
+
+ retain.clear
+
+ GC.start(full_mark: false)
+
+ wmap.keys.each(&:itself) # call method on keys to cause crash
+ end
+ end
end
diff --git a/test/ruby/test_yield.rb b/test/ruby/test_yield.rb
index 9b2b2f37e0..e7e65fce9e 100644
--- a/test/ruby/test_yield.rb
+++ b/test/ruby/test_yield.rb
@@ -401,7 +401,7 @@ class TestRubyYieldGen < Test::Unit::TestCase
def test_block_cached_argc
# [Bug #11451]
- assert_separately([], <<-"end;")
+ assert_ruby_status([], <<-"end;")
class Yielder
def each
yield :x, :y, :z
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index 7c0524354b..0d7fe66e1c 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -133,7 +133,7 @@ class TestYJIT < Test::Unit::TestCase
end
def test_yjit_enable_with_monkey_patch
- assert_separately(%w[--yjit-disable], <<~RUBY)
+ assert_ruby_status(%w[--yjit-disable], <<~RUBY)
# This lets rb_method_entry_at(rb_mKernel, ...) return NULL
Kernel.prepend(Module.new)
@@ -166,6 +166,11 @@ class TestYJIT < Test::Unit::TestCase
end
end
+ if JITSupport.zjit_supported?
+ def test_yjit_enable_with_zjit_enabled
+ assert_in_out_err(['--zjit'], 'puts RubyVM::YJIT.enable', ['false'], ['Only one JIT can be enabled at the same time.'])
+ end
+ end
def test_yjit_stats_and_v_no_error
_stdout, stderr, _status = invoke_ruby(%w(-v --yjit-stats), '', true, true)
@@ -542,7 +547,7 @@ class TestYJIT < Test::Unit::TestCase
end
def test_opt_getconstant_path_slowpath
- assert_compiles(<<~RUBY, exits: { opt_getconstant_path: 1 }, result: [42, 42, 1, 1], call_threshold: 2)
+ assert_compiles(<<~RUBY, result: [42, 42, 1, 1], call_threshold: 2)
class A
FOO = 42
class << self
@@ -639,6 +644,40 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ STRUCT_MAX_EMBEDDED_MEMBERS = (
+ GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE] -
+ GC::INTERNAL_CONSTANTS[:RBASIC_SIZE] -
+ GC::INTERNAL_CONSTANTS[:RVALUE_OVERHEAD]
+ ) / RbConfig::SIZEOF["void*"]
+
+ def test_spilled_struct_aref
+ omit("FIXME: https://github.com/Shopify/ruby/issues/977")
+ assert_compiles(<<~RUBY)
+ LargeStruct = Struct.new(:foo, :bar, *(#{STRUCT_MAX_EMBEDDED_MEMBERS} - 2).times.map { :"m_\#{it}" })
+
+ def foo(obj)
+ foo = obj.foo
+ raise "Expected 1, got: \#{foo}" unless foo == 1
+ bar = obj.bar
+ raise "Expected 2, got: \#{bar}" unless bar == 2
+ end
+
+ embedded_struct = LargeStruct.new(1, 2)
+ # Bump RCLASS_MAX_IV_COUNT for LargeStruct
+ embedded_struct.instance_variable_set(:@test, 1)
+
+ # Next allocation reserves space for the imemo/fields reference.
+ heap_struct = LargeStruct.new(1, 2)
+
+ RubyVM::YJIT.reset_stats!
+
+ foo(embedded_struct)
+ foo(embedded_struct)
+ foo(heap_struct)
+ foo(heap_struct)
+ RUBY
+ end
+
def test_struct_aset
assert_compiles(<<~RUBY)
def foo(obj)
@@ -652,6 +691,26 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ def test_struct_aset_guards_recv_is_not_frozen
+ assert_compiles(<<~RUBY, result: :ok, exits: { opt_send_without_block: 1 })
+ def foo(obj)
+ obj.foo = 123
+ end
+
+ Foo = Struct.new(:foo)
+ obj = Foo.new(123)
+ 100.times do
+ foo(obj)
+ end
+ obj.freeze
+ begin
+ foo(obj)
+ rescue FrozenError
+ :ok
+ end
+ RUBY
+ end
+
def test_getblockparam
assert_compiles(<<~'RUBY', insns: [:getblockparam])
def foo &blk
@@ -948,6 +1007,40 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ def test_super_bmethod
+ # Bmethod defined at class scope
+ assert_compiles(<<~'RUBY', insns: %i[invokesuper], result: true, exits: {})
+ class SuperItself
+ define_method(:itself) { super() }
+ end
+
+ obj = SuperItself.new
+ obj.itself
+ obj.itself == obj
+ RUBY
+
+ # Bmethod defined inside a method (the block's local_iseq is ISEQ_TYPE_METHOD
+ # but the CME is at the bmethod frame, not the enclosing method's frame)
+ assert_compiles(<<~'RUBY', insns: %i[invokesuper], result: "Base#foo via bmethod", exits: {})
+ class Base
+ def foo = "Base#foo"
+ end
+
+ class SetupHelper
+ def add_bmethod_to(klass)
+ klass.define_method(:foo) { super() + " via bmethod" }
+ end
+ end
+
+ class Target < Base; end
+
+ SetupHelper.new.add_bmethod_to(Target)
+ obj = Target.new
+ obj.foo
+ obj.foo
+ RUBY
+ end
+
# Tests calling a variadic cfunc with many args
def test_build_large_struct
assert_compiles(<<~RUBY, insns: %i[opt_send_without_block], call_threshold: 2)
@@ -1529,14 +1622,6 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
- def test_opt_aref_with
- assert_compiles(<<~RUBY, insns: %i[opt_aref_with], result: "bar", frozen_string_literal: false)
- h = {"foo" => "bar"}
-
- h["foo"]
- RUBY
- end
-
def test_proc_block_arg
assert_compiles(<<~RUBY, result: [:proc, :no_block])
def yield_if_given = block_given? ? yield : :no_block
@@ -1775,6 +1860,62 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ def test_proc_block_with_kwrest
+ # When the bug was present this required --yjit-stats to trigger.
+ assert_compiles(<<~RUBY, result: {extra: 5})
+ def foo = bar(w: 1, x: 2, y: 3, z: 4, extra: 5, &proc { _1 })
+ def bar(w:, x:, y:, z:, **kwrest) = yield kwrest
+
+ GC.stress = true
+ foo
+ foo
+ RUBY
+ end
+
+ def test_yjit_dump_insns
+ # Testing that this undocumented debugging feature doesn't crash
+ args = [
+ '--yjit-call-threshold=1',
+ '--yjit-dump-insns',
+ '-e def foo(case:) = {case:}[:case]',
+ '-e foo(case:0)',
+ ]
+ _out, _err, status = invoke_ruby(args, '', true, true)
+ assert_not_predicate(status, :signaled?)
+ end
+
+ def test_yjit_prelude_kernel_prepend
+ # Simulate what bundler/setup can do: prepend a module to Kernel during
+ # the prelude via the BUNDLER_SETUP mechanism in rubygems.rb:
+ # require ENV["BUNDLER_SETUP"] if ENV["BUNDLER_SETUP"] && !defined?(Bundler)
+ Tempfile.create(["kernel_prepend", ".rb"]) do |f|
+ f.write("Kernel.prepend(Module.new)\n")
+ f.flush
+ assert_separately([{ "BUNDLER_SETUP" => f.path }, "--enable=gems", "--yjit"], "", ignore_stderr: true)
+ end
+ end
+
+ def test_exceptional_entry_into_env_escaped_before_yjit_enablement
+ threshold = 2
+ assert_separately(["--disable-all", "--yjit-disable", "--yjit-call-threshold=#{threshold}"], <<~RUBY)
+ def run
+ @captured_env = ->{}
+ RubyVM::YJIT.enable
+
+ i = 0
+ while i < #{threshold}
+ next_i = i + 1
+ from_break = tap { break i + 1 } # break from the block generates an exceptional entry
+ assert_equal(from_break, next_i, '[Bug #21941]')
+ i = next_i
+ end
+ end
+
+ run
+ assert_equal(#{threshold}, @captured_env.binding.local_variable_get(:i))
+ RUBY
+ end
+
private
def code_gc_helpers
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb
new file mode 100644
index 0000000000..a56fea6d51
--- /dev/null
+++ b/test/ruby/test_zjit.rb
@@ -0,0 +1,556 @@
+# frozen_string_literal: true
+#
+# This set of tests can be run with:
+# make test-all TESTS=test/ruby/test_zjit.rb
+
+require 'test/unit'
+require 'envutil'
+require_relative '../lib/jit_support'
+return unless JITSupport.zjit_supported?
+
+class TestZJIT < Test::Unit::TestCase
+ def test_enabled
+ assert_runs 'false', <<~RUBY, zjit: false
+ RubyVM::ZJIT.enabled?
+ RUBY
+ assert_runs 'true', <<~RUBY, zjit: true
+ RubyVM::ZJIT.enabled?
+ RUBY
+ end
+
+ def test_stats_enabled
+ assert_runs 'false', <<~RUBY, stats: false
+ RubyVM::ZJIT.stats_enabled?
+ RUBY
+ assert_runs 'true', <<~RUBY, stats: true
+ RubyVM::ZJIT.stats_enabled?
+ RUBY
+ end
+
+ def test_stats_string_no_zjit
+ assert_runs 'nil', <<~RUBY, zjit: false
+ RubyVM::ZJIT.stats_string
+ RUBY
+ assert_runs 'true', <<~RUBY, stats: false
+ RubyVM::ZJIT.stats_string.is_a?(String)
+ RUBY
+ assert_runs 'true', <<~RUBY, stats: true
+ RubyVM::ZJIT.stats_string.is_a?(String)
+ RUBY
+ end
+
+ def test_stats_quiet
+ # Test that --zjit-stats-quiet collects stats but doesn't print them
+ script = <<~RUBY
+ def test = 42
+ test
+ test
+ puts RubyVM::ZJIT.stats_enabled?
+ RUBY
+
+ stats_header = "***ZJIT: Printing ZJIT statistics on exit***"
+
+ # With --zjit-stats, stats should be printed to stderr
+ out, err, status = eval_with_jit(script, stats: true)
+ assert_success(out, err, status)
+ assert_includes(err, stats_header)
+ assert_equal("true\n", out)
+
+ # With --zjit-stats-quiet, stats should NOT be printed but still enabled
+ out, err, status = eval_with_jit(script, stats: :quiet)
+ assert_success(out, err, status)
+ refute_includes(err, stats_header)
+ assert_equal("true\n", out)
+
+ # With --zjit-stats=<path>, stats should be printed to the path
+ Tempfile.create("zjit-stats-") {|tmp|
+ stats_file = tmp.path
+ tmp.puts("Lorem ipsum dolor sit amet, consectetur adipiscing elit, ...")
+ tmp.close
+
+ out, err, status = eval_with_jit(script, stats: stats_file)
+ assert_success(out, err, status)
+ refute_includes(err, stats_header)
+ assert_equal("true\n", out)
+ assert_equal stats_header, File.open(stats_file) {|f| f.gets(chomp: true)}, "should be overwritten"
+ }
+ end
+
+ def test_enable_through_env
+ child_env = {'RUBY_YJIT_ENABLE' => nil, 'RUBY_ZJIT_ENABLE' => '1'}
+ assert_in_out_err([child_env, '-v'], '') do |stdout, stderr|
+ assert_includes(stdout.first, '+ZJIT')
+ assert_equal([], stderr)
+ end
+ end
+
+ def test_zjit_enable
+ # --disable-all is important in case the build/environment has YJIT enabled by
+ # default through e.g. -DYJIT_FORCE_ENABLE. Can't enable ZJIT when YJIT is on.
+ assert_separately(["--disable-all"], <<~'RUBY')
+ refute_predicate RubyVM::ZJIT, :enabled?
+ refute_predicate RubyVM::ZJIT, :stats_enabled?
+ refute_includes RUBY_DESCRIPTION, "+ZJIT"
+
+ RubyVM::ZJIT.enable
+
+ assert_predicate RubyVM::ZJIT, :enabled?
+ refute_predicate RubyVM::ZJIT, :stats_enabled?
+ assert_includes RUBY_DESCRIPTION, "+ZJIT"
+ RUBY
+ end
+
+ def test_zjit_disable
+ assert_separately(["--zjit", "--zjit-disable"], <<~'RUBY')
+ refute_predicate RubyVM::ZJIT, :enabled?
+ refute_includes RUBY_DESCRIPTION, "+ZJIT"
+
+ RubyVM::ZJIT.enable
+
+ assert_predicate RubyVM::ZJIT, :enabled?
+ assert_includes RUBY_DESCRIPTION, "+ZJIT"
+ RUBY
+ end
+
+ def test_zjit_prelude_kernel_prepend
+ # Simulate what bundler/setup can do: prepend a module to Kernel during
+ # the prelude via the BUNDLER_SETUP mechanism in rubygems.rb:
+ # require ENV["BUNDLER_SETUP"] if ENV["BUNDLER_SETUP"] && !defined?(Bundler)
+ Tempfile.create(["kernel_prepend", ".rb"]) do |f|
+ f.write("Kernel.prepend(Module.new)\n")
+ f.flush
+ assert_separately([{ "BUNDLER_SETUP" => f.path }, "--enable=gems", "--zjit"], "", ignore_stderr: true)
+ end
+ end
+
+ def test_zjit_enable_respects_existing_options
+ assert_separately(['--zjit-disable', '--zjit-stats-quiet'], <<~RUBY)
+ refute_predicate RubyVM::ZJIT, :enabled?
+ assert_predicate RubyVM::ZJIT, :stats_enabled?
+
+ RubyVM::ZJIT.enable
+
+ assert_predicate RubyVM::ZJIT, :enabled?
+ assert_predicate RubyVM::ZJIT, :stats_enabled?
+ RUBY
+ end
+
+ def test_toplevel_binding
+ # Not using assert_compiles, which doesn't use the toplevel frame for `test_script`.
+ out, err, status = eval_with_jit(%q{
+ a = 1
+ b = 2
+ TOPLEVEL_BINDING.local_variable_set(:b, 3)
+ c = 4
+ print [a, b, c]
+ })
+ assert_success(out, err, status)
+ assert_equal "[1, 3, 4]", out
+ end
+
+ def test_send_exit_with_uninitialized_locals
+ assert_runs 'nil', %q{
+ def entry(init)
+ function_stub_exit(init)
+ end
+
+ def function_stub_exit(init)
+ uninitialized_local = 1 if init
+ uninitialized_local
+ end
+
+ entry(true) # profile and set 1 to the local slot
+ entry(false)
+ }, call_threshold: 2, allowed_iseqs: 'entry@-e:2'
+ end
+
+ def test_opt_new_with_custom_allocator
+ assert_compiles '"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"', %q{
+ require "digest"
+ def test = Digest::SHA256.new.hexdigest
+ test; test
+ }, insns: [:opt_new], call_threshold: 2
+ end
+
+ def test_opt_new_with_custom_allocator_raises
+ assert_compiles '[42, 42]', %q{
+ require "digest"
+ class C < Digest::Base; end
+ def test
+ begin
+ Digest::Base.new
+ rescue NotImplementedError
+ 42
+ end
+ end
+ [test, test]
+ }, insns: [:opt_new], call_threshold: 2
+ end
+
+ def test_uncached_getconstant_path
+ assert_compiles RUBY_COPYRIGHT.dump, %q{
+ def test = RUBY_COPYRIGHT
+ test
+ }, call_threshold: 1, insns: [:opt_getconstant_path]
+ end
+
+ def test_getconstant_path_autoload
+ # A constant-referencing expression can run arbitrary code through Kernel#autoload.
+ Dir.mktmpdir('autoload') do |tmpdir|
+ autoload_path = File.join(tmpdir, 'test_getconstant_path_autoload.rb')
+ File.write(autoload_path, 'X = RUBY_COPYRIGHT')
+
+ assert_compiles RUBY_COPYRIGHT.dump, %Q{
+ Object.autoload(:X, #{File.realpath(autoload_path).inspect})
+ def test = X
+ test
+ }, call_threshold: 1, insns: [:opt_getconstant_path]
+ end
+ end
+
+ def test_send_backtrace
+ backtrace = [
+ "-e:2:in 'Object#jit_frame1'",
+ "-e:3:in 'Object#entry'",
+ "-e:5:in 'block in <main>'",
+ "-e:6:in '<main>'",
+ ]
+ assert_compiles backtrace.inspect, %q{
+ def jit_frame2 = caller # 1
+ def jit_frame1 = jit_frame2 # 2
+ def entry = jit_frame1 # 3
+ entry # profile send # 4
+ entry # 5
+ }, call_threshold: 2
+ end
+
+ # tool/ruby_vm/views/*.erb relies on the zjit instructions a) being contiguous and
+ # b) being reliably ordered after all the other instructions.
+ def test_instruction_order
+ insn_names = RubyVM::INSTRUCTION_NAMES
+ zjit, others = insn_names.map.with_index.partition { |name, _| name.start_with?('zjit_') }
+ zjit_indexes = zjit.map(&:last)
+ other_indexes = others.map(&:last)
+ zjit_indexes.product(other_indexes).each do |zjit_index, other_index|
+ assert zjit_index > other_index, "'#{insn_names[zjit_index]}' at #{zjit_index} "\
+ "must be defined after '#{insn_names[other_index]}' at #{other_index}"
+ end
+ end
+
+ def test_require_rubygems
+ assert_runs 'true', %q{
+ require 'rubygems'
+ }, call_threshold: 2
+ end
+
+ def test_require_rubygems_with_auto_compact
+ omit("GC.auto_compact= support is required for this test") unless GC.respond_to?(:auto_compact=)
+ assert_runs 'true', %q{
+ GC.auto_compact = true
+ require 'rubygems'
+ }, call_threshold: 2
+ end
+
+ def test_stats_availability
+ assert_runs '[true, true]', %q{
+ def test = 1
+ test
+ [
+ RubyVM::ZJIT.stats[:zjit_insn_count] > 0,
+ RubyVM::ZJIT.stats(:zjit_insn_count) > 0,
+ ]
+ }, stats: true
+ end
+
+ def test_stats_consistency
+ assert_runs '[]', %q{
+ def test = 1
+ test # increment some counters
+
+ RubyVM::ZJIT.stats.to_a.filter_map do |key, value|
+ # The value may be incremented, but the class should stay the same
+ other_value = RubyVM::ZJIT.stats(key)
+ if value.class != other_value.class
+ [key, value, other_value]
+ end
+ end
+ }, stats: true
+ end
+
+ def test_reset_stats
+ assert_runs 'true', %q{
+ def test = 1
+ 100.times { test }
+
+ # Get initial stats and verify they're non-zero
+ initial_stats = RubyVM::ZJIT.stats
+
+ # Reset the stats
+ RubyVM::ZJIT.reset_stats!
+
+ # Get stats after reset
+ reset_stats = RubyVM::ZJIT.stats
+
+ [
+ # After reset, counters should be zero or at least much smaller
+ # (some instructions might execute between reset and reading stats)
+ :zjit_insn_count.then { |s| initial_stats[s] > 0 && reset_stats[s] < initial_stats[s] },
+ :compiled_iseq_count.then { |s| initial_stats[s] > 0 && reset_stats[s] < initial_stats[s] }
+ ].all?
+ }, stats: true
+ end
+
+ def test_zjit_option_uses_array_each_in_ruby
+ omit 'ZJIT wrongly compiles Array#each, so it is disabled for now'
+ assert_runs '"<internal:array>"', %q{
+ Array.instance_method(:each).source_location&.first
+ }
+ end
+
+ def test_line_tracepoint_on_c_method
+ assert_compiles '"[[:line, true]]"', %q{
+ events = []
+ events.instance_variable_set(
+ :@tp,
+ TracePoint.new(:line) { |tp| events << [tp.event, tp.lineno] if tp.path == __FILE__ }
+ )
+ def events.to_str
+ @tp.enable; ''
+ end
+
+ # Stay in generated code while enabling tracing
+ def events.compiled(obj)
+ String(obj)
+ @tp.disable; __LINE__
+ end
+
+ line = events.compiled(events)
+ events[0][-1] = (events[0][-1] == line)
+
+ events.to_s # can't dump events as it's a singleton object AND it has a TracePoint instance variable, which also can't be dumped
+ }
+ end
+
+ def test_targeted_line_tracepoint_in_c_method_call
+ assert_compiles '"[true]"', %q{
+ events = []
+ events.instance_variable_set(:@tp, TracePoint.new(:line) { |tp| events << tp.lineno })
+ def events.to_str
+ @tp.enable(target: method(:compiled))
+ ''
+ end
+
+ # Stay in generated code while enabling tracing
+ def events.compiled(obj)
+ String(obj)
+ __LINE__
+ end
+
+ line = events.compiled(events)
+ events[0] = (events[0] == line)
+
+ events.to_s # can't dump events as it's a singleton object AND it has a TracePoint instance variable, which also can't be dumped
+ }
+ end
+
+ def test_regression_cfp_sp_set_correctly_before_leaf_gc_call
+ assert_compiles ':ok', %q{
+ def check(l, r)
+ return 1 unless l
+ 1 + check(*l) + check(*r)
+ end
+
+ def tree(depth)
+ # This duparray is our leaf-gc target.
+ return [nil, nil] unless depth > 0
+
+ # Modify the local and pass it to the following calls.
+ depth -= 1
+ [tree(depth), tree(depth)]
+ end
+
+ def test
+ GC.stress = true
+ 2.times do
+ t = tree(11)
+ check(*t)
+ end
+ :ok
+ end
+
+ test
+ }, call_threshold: 14, num_profiles: 5
+ end
+
+ def test_exit_tracing
+ # Smoke test: --zjit-trace-exits writes a Fuchsia trace (.fxt) file to /tmp
+ assert_compiles('true', <<~RUBY, extra_args: ['--zjit-trace-exits'])
+ def test(object) = object.itself
+
+ # induce an exit just for good measure
+ array = []
+ test(array)
+ test(array)
+ def array.itself = :not_itself
+ test(array)
+
+ fxt_files = Dir.glob("/tmp/perfetto-\#{Process.pid}.fxt")
+ result = fxt_files.length == 1 && !File.empty?(fxt_files.first)
+ File.unlink(*fxt_files)
+ result
+ RUBY
+ end
+
+ def test_send_no_profiles_with_disabled_specialized_instruction
+ # Regression test: when specialized_instruction is disabled (as power_assert does),
+ # eval'd code uses `send` instead of `opt_send_without_block`, producing SendNoProfiles.
+ # The `times` call with a literal block is the SendNoProfiles send whose exit profiling
+ # triggers recompilation of `run`. After recompilation, `make`'s eval("proc { }") crashes
+ # in vm_make_env_each because the caller frame's EP[-1] (specval) has a stale value.
+ assert_runs ':ok', <<~RUBY
+ RubyVM::InstructionSequence.compile_option = { specialized_instruction: false }
+ eval <<~'INNERRUBY'
+ def make = eval("proc { }")
+ def run(n) = n.times { make }
+ INNERRUBY
+ run(6)
+ :ok
+ RUBY
+ end
+
+ def test_float_arithmetic
+ assert_compiles '4.0', 'def test = 1.5 + 2.5; test'
+ assert_compiles '6.0', 'def test = 2.0 * 3.0; test'
+ assert_compiles '1.5', 'def test = 3.5 - 2.0; test'
+ assert_compiles '2.5', 'def test = 5.0 / 2.0; test'
+ assert_compiles '4.5', 'def test = 1.5 * 3; test' # Float * Fixnum
+ assert_compiles 'true', 'def test = (Float::NAN + 1.0).nan?; test'
+ assert_compiles 'Infinity', 'def test = Float::INFINITY * 2.0; test'
+ assert_compiles '3', 'def test = 3.7.to_i; test'
+ assert_compiles '-2', 'def test = (-2.9).to_i; test'
+ end
+
+ private
+
+ # Assert that every method call in `test_script` can be compiled by ZJIT
+ # at a given call_threshold
+ def assert_compiles(expected, test_script, insns: [], **opts)
+ assert_runs(expected, test_script, insns:, assert_compiles: true, **opts)
+ end
+
+ # Assert that `test_script` runs successfully with ZJIT enabled.
+ # Unlike `assert_compiles`, `assert_runs(assert_compiles: false)`
+ # allows ZJIT to skip compiling methods.
+ def assert_runs(expected, test_script, insns: [], assert_compiles: false, **opts)
+ pipe_fd = 3
+ disasm_method = :test
+
+ script = <<~RUBY
+ ret_val = (_test_proc = -> { #{('RubyVM::ZJIT.assert_compiles; ' if assert_compiles)}#{test_script.lstrip} }).call
+ result = {
+ ret_val:,
+ #{ unless insns.empty?
+ "insns: RubyVM::InstructionSequence.of(method(#{disasm_method.inspect})).to_a"
+ end}
+ }
+ IO.open(#{pipe_fd}).write(Marshal.dump(result))
+ RUBY
+
+ out, err, status, result = eval_with_jit(script, pipe_fd:, **opts)
+ assert_success(out, err, status)
+
+ result = Marshal.load(result)
+ assert_equal(expected, result.fetch(:ret_val).inspect)
+
+ unless insns.empty?
+ iseq = result.fetch(:insns)
+ assert_equal(
+ "YARVInstructionSequence/SimpleDataFormat",
+ iseq.first,
+ "Failed to get ISEQ disassembly. " \
+ "Make sure to put code directly under the '#{disasm_method}' method."
+ )
+ iseq_insns = iseq.last
+
+ expected_insns = Set.new(insns)
+ iseq_insns.each do
+ next unless it.is_a?(Array)
+ expected_insns.delete(it.first)
+ end
+ assert(expected_insns.empty?, -> { "Not present in ISeq: #{expected_insns.to_a}" })
+ end
+ end
+
+ # Run a Ruby process with ZJIT options and a pipe for writing test results
+ def eval_with_jit(
+ script,
+ call_threshold: 1,
+ num_profiles: 1,
+ zjit: true,
+ stats: false,
+ debug: true,
+ allowed_iseqs: nil,
+ extra_args: nil,
+ timeout: 1000,
+ pipe_fd: nil
+ )
+ args = ["--disable-gems", *extra_args]
+ if zjit
+ args << "--zjit-call-threshold=#{call_threshold}"
+ args << "--zjit-num-profiles=#{num_profiles}"
+ case stats
+ when true
+ args << "--zjit-stats"
+ when :quiet
+ args << "--zjit-stats-quiet"
+ else
+ args << "--zjit-stats=#{stats}" if stats
+ end
+ args << "--zjit-debug" if debug
+ if allowed_iseqs
+ jitlist = Tempfile.new("jitlist")
+ jitlist.write(allowed_iseqs)
+ jitlist.close
+ args << "--zjit-allowed-iseqs=#{jitlist.path}"
+ end
+ end
+ args << "-e" << script_shell_encode(script)
+ ios = {}
+ if pipe_fd
+ pipe_r, pipe_w = IO.pipe
+ # Separate thread so we don't deadlock when
+ # the child ruby blocks writing the output to pipe_fd
+ pipe_out = nil
+ pipe_reader = Thread.new do
+ pipe_out = pipe_r.read
+ pipe_r.close
+ end
+ ios[pipe_fd] = pipe_w
+ end
+ result = EnvUtil.invoke_ruby(args, '', true, true, rubybin: RbConfig.ruby, timeout: timeout, ios:)
+ if pipe_fd
+ pipe_w.close
+ pipe_reader.join(timeout)
+ result << pipe_out
+ end
+ result
+ ensure
+ pipe_reader&.kill
+ pipe_reader&.join(timeout)
+ pipe_r&.close
+ pipe_w&.close
+ jitlist&.unlink
+ end
+
+ def assert_success(out, err, status)
+ message = "exited with status #{status.to_i}"
+ message << "\nstdout:\n```\n#{out}```\n" unless out.empty?
+ message << "\nstderr:\n```\n#{err}```\n" unless err.empty?
+ assert status.success?, message
+ end
+
+ def script_shell_encode(s)
+ # We can't pass utf-8-encoded characters directly in a shell arg. But we can use Ruby \u constants.
+ s.chars.map { |c| c.ascii_only? ? c : "\\u%x" % c.codepoints[0] }.join
+ end
+end
diff --git a/test/rubygems/coverage_setup.rb b/test/rubygems/coverage_setup.rb
new file mode 100644
index 0000000000..7e978e59e0
--- /dev/null
+++ b/test/rubygems/coverage_setup.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+# This file is loaded via -r flag BEFORE rubygems to enable coverage tracking
+# of rubygems boot files. It must be used with --disable-gems and -Ilib
+# so that Coverage.start runs before rubygems is loaded.
+
+require "coverage"
+Coverage.start(lines: true)
+require "rubygems"
diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb
index eaf3e7037e..2411dbc649 100644
--- a/test/rubygems/helper.rb
+++ b/test/rubygems/helper.rb
@@ -3,6 +3,32 @@
require "rubygems"
begin
+ raise LoadError if ENV["GEM_COMMAND"]
+
+ gem "simplecov_json_formatter"
+ require "simplecov"
+
+ unless ENV["SIMPLECOV_SUBPROCESS"]
+ SimpleCov.start do
+ command_name "rubygems"
+ root File.expand_path("../..", __dir__)
+ coverage_dir File.expand_path("../../coverage", __dir__)
+
+ add_filter "/test/"
+ add_filter "/bundler/"
+ add_filter "/tool/"
+ add_filter "/lib/rubygems/vendor/"
+ add_filter ".gemspec"
+ end
+
+ # Prevent SimpleCov from running in subprocesses spawned by assert_separately
+ ENV["SIMPLECOV_SUBPROCESS"] = "1"
+ end
+rescue LoadError
+ # SimpleCov is not installed
+end
+
+begin
gem "test-unit", "~> 3.0"
rescue Gem::LoadError
end
@@ -12,6 +38,7 @@ require "test/unit"
require "fileutils"
require "pathname"
require "pp"
+require "rubygems/installer"
require "rubygems/package"
require "shellwords"
require "tmpdir"
@@ -19,6 +46,24 @@ require "rubygems/vendor/uri/lib/uri"
require "zlib"
require_relative "mock_gem_ui"
+# JRuby on Windows raises TypeError inside File.symlink (the wincode helper
+# trips on a nil path), so any test that exercises Gem::Installer's symlink
+# branch fails to even install the gem. Real users hit the wrapper branch via
+# `gem install` (DependencyInstaller passes wrappers: true), so mirror that
+# default for direct Gem::Installer.at callers in the test suite.
+if Gem.win_platform? && Gem.java_platform?
+ module Gem::InstallerDefaultWrappersOnJRubyWindows
+ def at(path, options = {})
+ super(path, { wrappers: true }.merge(options))
+ end
+
+ def for_spec(spec, options = {})
+ super(spec, { wrappers: true }.merge(options))
+ end
+ end
+ Gem::Installer.singleton_class.prepend(Gem::InstallerDefaultWrappersOnJRubyWindows)
+end
+
module Gem
##
# Allows setting the gem path searcher.
@@ -60,6 +105,44 @@ class Gem::Command
end
end
+class Gem::Installer
+ # Copy from Gem::Installer#install with install_as_default option from old version
+ def install_default_gem
+ pre_install_checks
+
+ run_pre_install_hooks
+
+ spec.loaded_from = default_spec_file
+
+ FileUtils.rm_rf gem_dir
+ FileUtils.rm_rf spec.extension_dir
+
+ dir_mode = options[:dir_mode]
+ FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755
+
+ extract_bin
+ write_default_spec
+
+ generate_bin
+ generate_plugins
+
+ File.chmod(dir_mode, gem_dir) if dir_mode
+
+ say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?
+
+ Gem::Specification.add_spec(spec)
+
+ load_plugin
+
+ run_post_install_hooks
+
+ spec
+ rescue Errno::EACCES => e
+ # Permission denied - /path/to/foo
+ raise Gem::FilePermissionError, e.message.split(" - ").last
+ end
+end
+
##
# RubyGemTestCase provides a variety of methods for testing rubygems and
# gem-related behavior in a sandbox. Through RubyGemTestCase you can install
@@ -295,8 +378,12 @@ class Gem::TestCase < Test::Unit::TestCase
ENV["XDG_CONFIG_HOME"] = nil
ENV["XDG_DATA_HOME"] = nil
ENV["XDG_STATE_HOME"] = nil
+ ENV["MAKEFLAGS"] = nil
ENV["SOURCE_DATE_EPOCH"] = nil
ENV["BUNDLER_VERSION"] = nil
+ ENV["BUNDLE_CONFIG"] = nil
+ ENV["BUNDLE_USER_CONFIG"] = nil
+ ENV["BUNDLE_USER_HOME"] = nil
ENV["RUBYGEMS_PREVENT_UPDATE_SUGGESTION"] = "true"
@current_dir = Dir.pwd
@@ -400,8 +487,9 @@ class Gem::TestCase < Test::Unit::TestCase
Gem::RemoteFetcher.fetcher = Gem::FakeFetcher.new
@gem_repo = "http://gems.example.com/"
+ Gem.instance_variable_set :@default_sources, [@gem_repo]
+ Gem.instance_variable_set :@sources, nil
@uri = Gem::URI.parse @gem_repo
- Gem.sources.replace [@gem_repo]
Gem.searcher = nil
Gem::SpecFetcher.fetcher = nil
@@ -418,6 +506,9 @@ class Gem::TestCase < Test::Unit::TestCase
@orig_hooks[name] = Gem.send(name).dup
end
+ Gem::Platform.const_get(:GENERIC_CACHE).clear
+ Gem::Platform.const_get(:GENERICS).each {|g| Gem::Platform.const_get(:GENERIC_CACHE)[g] = g }
+
@marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
@orig_loaded_features = $LOADED_FEATURES.dup
end
@@ -680,15 +771,19 @@ class Gem::TestCase < Test::Unit::TestCase
path
end
+ def write_dummy_extconf(gem_name)
+ write_file File.join(@tempdir, "extconf.rb") do |io|
+ io.puts "require 'mkmf'"
+ yield io if block_given?
+ io.puts "create_makefile '#{gem_name}'"
+ end
+ end
+
##
- # Load a YAML string, the psych 3 way
+ # Load a YAML string using the safe loader with gem-spec permitted classes.
def load_yaml(yaml)
- if Psych.respond_to?(:unsafe_load)
- Psych.unsafe_load(yaml)
- else
- Psych.load(yaml)
- end
+ Gem::SafeYAML.safe_load(yaml)
end
##
@@ -713,7 +808,7 @@ class Gem::TestCase < Test::Unit::TestCase
#
# Use this with #write_file to build an installed gem.
- def quick_gem(name, version="2")
+ def quick_gem(name, version = "2")
require "rubygems/specification"
spec = Gem::Specification.new do |s|
@@ -799,8 +894,8 @@ class Gem::TestCase < Test::Unit::TestCase
def install_default_gems(*specs)
specs.each do |spec|
- installer = Gem::Installer.for_spec(spec, install_as_default: true)
- installer.install
+ installer = Gem::Installer.for_spec(spec)
+ installer.install_default_gem
Gem.register_default_spec(spec)
end
end
@@ -1022,7 +1117,7 @@ Also, a list:
# Add +spec+ to +@fetcher+ serving the data in the file +path+.
# +repo+ indicates which repo to make +spec+ appear to be in.
- def add_to_fetcher(spec, path=nil, repo=@gem_repo)
+ def add_to_fetcher(spec, path = nil, repo = @gem_repo)
path ||= spec.cache_file
@fetcher.data["#{@gem_repo}gems/#{spec.file_name}"] = read_binary(path)
end
@@ -1184,6 +1279,26 @@ Also, a list:
system("nmake /? 1>NUL 2>&1")
end
+ @@symlink_supported = nil
+
+ # This is needed for Windows environment without symlink support enabled (the default
+ # for non admin) to be able to skip test for features using symlinks.
+ def symlink_supported?
+ if @@symlink_supported.nil?
+ begin
+ File.symlink(File.join(@tempdir, "a"), File.join(@tempdir, "b"))
+ File.readlink(File.join(@tempdir, "b"))
+ rescue NotImplementedError, SystemCallError
+ @@symlink_supported = false
+ else
+ @@symlink_supported = true
+ ensure
+ File.unlink(File.join(@tempdir, "b")) if File.symlink?(File.join(@tempdir, "b"))
+ end
+ end
+ @@symlink_supported
+ end
+
# In case we're building docs in a background process, this method waits for
# that process to exit (or if it's already been reaped, or never happened,
# swallows the Errno::ECHILD error).
@@ -1195,7 +1310,7 @@ Also, a list:
##
# Allows the proper version of +rake+ to be used for the test.
- def build_rake_in(good=true)
+ def build_rake_in(good = true)
gem_ruby = Gem.ruby
Gem.ruby = self.class.rubybin
env_rake = ENV["rake"]
@@ -1567,3 +1682,9 @@ class Object
end
require_relative "utilities"
+
+# mise installed rubygems_plugin.rb to system wide `site_ruby` directory.
+# This empty module avoid to call `mise` command.
+module ReshimInstaller
+ def self.reshim; end
+end
diff --git a/test/rubygems/installer_test_case.rb b/test/rubygems/installer_test_case.rb
index 8a34d28db8..9e0cbf9c69 100644
--- a/test/rubygems/installer_test_case.rb
+++ b/test/rubygems/installer_test_case.rb
@@ -215,26 +215,26 @@ class Gem::InstallerTestCase < Gem::TestCase
##
# Creates an installer for +spec+ that will install into +gem_home+.
- def util_installer(spec, gem_home, force=true)
+ def util_installer(spec, gem_home, force = true)
Gem::Installer.at(spec.cache_file,
install_dir: gem_home,
force: force)
end
- @@symlink_supported = nil
-
- # This is needed for Windows environment without symlink support enabled (the default
- # for non admin) to be able to skip test for features using symlinks.
- def symlink_supported?
- if @@symlink_supported.nil?
- begin
- File.symlink("", "")
- rescue Errno::ENOENT, Errno::EEXIST
- @@symlink_supported = true
- rescue NotImplementedError, SystemCallError
- @@symlink_supported = false
- end
+ def test_ensure_writable_dir_creates_missing_parent_directories
+ installer = setup_base_installer(false)
+
+ non_existent_parent = File.join(@tempdir, "non_existent_parent")
+ target_dir = File.join(non_existent_parent, "target_dir")
+
+ refute_directory_exists non_existent_parent, "Parent directory should not exist yet"
+ refute_directory_exists target_dir, "Target directory should not exist yet"
+
+ assert_nothing_raised do
+ installer.send(:ensure_writable_dir, target_dir)
end
- @@symlink_supported
+
+ assert_directory_exists non_existent_parent, "Parent directory should exist now"
+ assert_directory_exists target_dir, "Target directory should exist now"
end
end
diff --git a/test/rubygems/mock_gem_ui.rb b/test/rubygems/mock_gem_ui.rb
index 218d4b6965..fb804c5555 100644
--- a/test/rubygems/mock_gem_ui.rb
+++ b/test/rubygems/mock_gem_ui.rb
@@ -77,7 +77,7 @@ class Gem::MockGemUi < Gem::StreamUI
@terminated
end
- def terminate_interaction(status=0)
+ def terminate_interaction(status = 0)
@terminated = true
raise TermError, status if status != 0
diff --git a/test/rubygems/package/tar_test_case.rb b/test/rubygems/package/tar_test_case.rb
index e3d812bf3f..26135cf296 100644
--- a/test/rubygems/package/tar_test_case.rb
+++ b/test/rubygems/package/tar_test_case.rb
@@ -6,23 +6,7 @@ require "rubygems/package"
##
# A test case for Gem::Package::Tar* classes
-class Gem::Package::TarTestCase < Gem::TestCase
- def ASCIIZ(str, length)
- str + "\0" * (length - str.length)
- end
-
- def SP(s)
- s + " "
- end
-
- def SP_Z(s)
- s + " \0"
- end
-
- def Z(s)
- s + "\0"
- end
-
+module Gem::Package::TarTestMethods
def assert_headers_equal(expected, actual)
expected = expected.to_s unless String === expected
actual = actual.to_s unless String === actual
@@ -66,6 +50,26 @@ class Gem::Package::TarTestCase < Gem::TestCase
assert_equal expected[chksum_off, 8], actual[chksum_off, 8]
end
+end
+
+class Gem::Package::TarTestCase < Gem::TestCase
+ include Gem::Package::TarTestMethods
+
+ def ASCIIZ(str, length)
+ str + "\0" * (length - str.length)
+ end
+
+ def SP(s)
+ s + " "
+ end
+
+ def SP_Z(s)
+ s + " \0"
+ end
+
+ def Z(s)
+ s + "\0"
+ end
def calc_checksum(header)
sum = header.sum(0)
diff --git a/test/rubygems/test_bundled_ca.rb b/test/rubygems/test_bundled_ca.rb
index a737185681..cc8fa884ca 100644
--- a/test/rubygems/test_bundled_ca.rb
+++ b/test/rubygems/test_bundled_ca.rb
@@ -12,7 +12,7 @@ require "rubygems/request"
# = Testing Bundled CA
#
-# The tested hosts are explained in detail here: https://github.com/rubygems/rubygems/commit/5e16a5428f973667cabfa07e94ff939e7a83ebd9
+# The tested hosts are explained in detail here: https://github.com/ruby/rubygems/commit/5e16a5428f973667cabfa07e94ff939e7a83ebd9
#
class TestGemBundledCA < Gem::TestCase
diff --git a/test/rubygems/test_config.rb b/test/rubygems/test_config.rb
index 657624d526..822b57b0dc 100644
--- a/test/rubygems/test_config.rb
+++ b/test/rubygems/test_config.rb
@@ -5,13 +5,6 @@ require "rubygems"
require "shellwords"
class TestGemConfig < Gem::TestCase
- def test_datadir
- util_make_gems
- spec = Gem::Specification.find_by_name("a")
- spec.activate
- assert_equal "#{spec.full_gem_path}/data/a", spec.datadir
- end
-
def test_good_rake_path_is_escaped
path = Gem::TestCase.class_variable_get(:@@good_rake)
ruby, rake = path.shellsplit
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index cdc3479e37..c81b0b0547 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -150,6 +150,8 @@ class TestGem < Gem::TestCase
end
def assert_self_install_permissions(format_executable: false, data_mode: 0o640)
+ omit "FileUtils.install signature differs on JRuby/Windows" if Gem.win_platform? && Gem.java_platform?
+
mask = Gem.win_platform? ? 0o700 : 0o777
options = {
dir_mode: 0o500,
@@ -199,7 +201,8 @@ class TestGem < Gem::TestCase
end
assert_equal(expected, result)
ensure
- File.chmod(0o755, *Dir.glob(@gemhome + "/gems/**/"))
+ files = Dir.glob(@gemhome + "/gems/**/")
+ File.chmod(0o755, *files) unless files.empty?
end
def test_require_missing
@@ -310,7 +313,7 @@ class TestGem < Gem::TestCase
assert_equal %w[a-1 b-2 c-2], loaded_spec_names
end
- def test_activate_bin_path_raises_a_meaningful_error_if_a_gem_thats_finally_activated_has_orphaned_dependencies
+ def test_activate_bin_path_backtracks_when_highest_version_has_orphaned_dependencies
a1 = util_spec "a", "1" do |s|
s.executables = ["exec"]
s.add_dependency "b"
@@ -328,13 +331,11 @@ class TestGem < Gem::TestCase
install_specs c1, b1, b2, a1
- # c2 is missing, and b2 which has it as a dependency will be activated, so we should get an error about the orphaned dependency
-
- e = assert_raise Gem::UnsatisfiableDependencyError do
- load Gem.activate_bin_path("a", "exec", ">= 0")
- end
+ # c2 is missing, but the resolver backtracks from b2 to b1 which
+ # works with c1, finding a valid solution despite partial installation
+ load Gem.activate_bin_path("a", "exec", ">= 0")
- assert_equal "Unable to resolve dependency: 'b (>= 0)' requires 'c (= 2)'", e.message
+ assert_equal %w[a-1 b-1 c-1], loaded_spec_names
end
def test_activate_bin_path_in_debug_mode
@@ -527,35 +528,6 @@ class TestGem < Gem::TestCase
assert_equal expected, Gem.configuration
end
- def test_self_datadir
- foo = nil
-
- Dir.chdir @tempdir do
- FileUtils.mkdir_p "data"
- File.open File.join("data", "foo.txt"), "w" do |fp|
- fp.puts "blah"
- end
-
- foo = util_spec "foo" do |s|
- s.files = %w[data/foo.txt]
- end
-
- install_gem foo
- end
-
- gem "foo"
-
- expected = File.join @gemhome, "gems", foo.full_name, "data", "foo"
-
- assert_equal expected, Gem::Specification.find_by_name("foo").datadir
- end
-
- def test_self_datadir_nonexistent_package
- assert_raise(Gem::MissingSpecError) do
- Gem::Specification.find_by_name("xyzzy").datadir
- end
- end
-
def test_self_default_exec_format
ruby_install_name "ruby" do
assert_equal "%s", Gem.default_exec_format
@@ -615,6 +587,7 @@ class TestGem < Gem::TestCase
end
def test_self_default_sources
+ Gem.remove_instance_variable :@default_sources
assert_equal %w[https://rubygems.org/], Gem.default_sources
end
@@ -1227,6 +1200,8 @@ class TestGem < Gem::TestCase
Gem.sources = nil
Gem.configuration.sources = %w[http://test.example.com/]
assert_equal %w[http://test.example.com/], Gem.sources
+ ensure
+ Gem.configuration.sources = nil
end
def test_try_activate_returns_true_for_activated_specs
@@ -1239,6 +1214,28 @@ class TestGem < Gem::TestCase
assert Gem.try_activate("b"), "try_activate should still return true"
end
+ def test_try_activate_does_not_raise_no_method_error_on_activation_conflict
+ a1 = util_spec "a", "1.0" do |s|
+ s.files << "lib/a/old.rb"
+ end
+
+ a2 = util_spec "a", "2.0" do |s|
+ s.files << "lib/a/old.rb"
+ s.files << "lib/a/new_file.rb"
+ end
+
+ install_specs a1, a2
+
+ # Activate the older version
+ gem "a", "= 1.0"
+
+ # try_activate a file only in the newer version should not raise
+ # NoMethodError on nil (https://bugs.ruby-lang.org/issues/21954)
+ assert_nothing_raised do
+ Gem.try_activate("a/new_file")
+ end
+ end
+
def test_spec_order_is_consistent
b1 = util_spec "b", "1.0"
b2 = util_spec "b", "2.0"
@@ -1308,10 +1305,14 @@ class TestGem < Gem::TestCase
refute Gem.try_activate "nonexistent"
end
- expected = "Ignoring ext-1 because its extensions are not built. " \
- "Try: gem pristine ext --version 1\n"
+ if RUBY_ENGINE == "jruby"
+ assert_equal "", err
+ else
+ expected = "Ignoring ext-1 because its extensions are not built. " \
+ "Try: gem pristine ext --version 1\n"
- assert_equal expected, err
+ assert_equal expected, err
+ end
end
def test_self_use_paths_with_nils
@@ -1659,6 +1660,27 @@ class TestGem < Gem::TestCase
assert_nil Gem.find_unresolved_default_spec("README")
end
+ def test_register_default_spec_new_style_with_native_extension
+ Gem.clear_default_specs
+
+ dlext = RbConfig::CONFIG["DLEXT"]
+
+ new_style = Gem::Specification.new do |spec|
+ spec.name = "my_ext"
+ spec.version = "1.0"
+ spec.files = ["lib/my_ext.rb", "my_ext_core.#{dlext}", "ext/my_ext/my_ext_core.c", "README.md"]
+ spec.require_paths = ["lib"]
+ end
+
+ Gem.register_default_spec new_style
+
+ assert_equal new_style, Gem.find_unresolved_default_spec("my_ext.rb")
+ assert_equal new_style, Gem.find_unresolved_default_spec("my_ext_core")
+ assert_equal new_style, Gem.find_unresolved_default_spec("my_ext_core.#{dlext}")
+ assert_nil Gem.find_unresolved_default_spec("ext/my_ext/my_ext_core.c")
+ assert_nil Gem.find_unresolved_default_spec("README.md")
+ end
+
def test_register_default_spec_old_style_with_folder_starting_with_lib
Gem.clear_default_specs
diff --git a/test/rubygems/test_gem_bundler_version_finder.rb b/test/rubygems/test_gem_bundler_version_finder.rb
index b72670b802..b5ef6293ab 100644
--- a/test/rubygems/test_gem_bundler_version_finder.rb
+++ b/test/rubygems/test_gem_bundler_version_finder.rb
@@ -2,6 +2,7 @@
require_relative "helper"
require "rubygems/bundler_version_finder"
+require "tempfile"
class TestGemBundlerVersionFinder < Gem::TestCase
def setup
@@ -32,6 +33,11 @@ class TestGemBundlerVersionFinder < Gem::TestCase
assert_equal v("1.1.1.1"), bvf.bundler_version
end
+ def test_bundler_version_with_empty_env_var
+ ENV["BUNDLER_VERSION"] = ""
+ assert_nil bvf.bundler_version
+ end
+
def test_bundler_version_with_bundle_update_bundler
ARGV.replace %w[update --bundler]
assert_nil bvf.bundler_version
@@ -51,6 +57,157 @@ class TestGemBundlerVersionFinder < Gem::TestCase
assert_nil bvf.bundler_version
end
+ def test_bundler_version_with_bundle_config
+ config_content = <<~CONFIG
+ BUNDLE_VERSION: "system"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_content)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ assert_nil bvf.bundler_version
+ end
+ end
+ end
+
+ def test_bundler_version_with_bundle_config_single_quoted
+ config_with_single_quoted_version = <<~CONFIG
+ BUNDLE_VERSION: 'system'
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_with_single_quoted_version)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ assert_nil bvf.bundler_version
+ end
+ end
+ end
+
+ def test_bundler_version_with_bundle_config_version
+ ENV["BUNDLER_VERSION"] = "1.1.1.1"
+
+ config_content = <<~CONFIG
+ BUNDLE_VERSION: "1.2.3"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_content)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ assert_equal v("1.1.1.1"), bvf.bundler_version
+ end
+ end
+ end
+
+ def test_bundler_version_with_bundle_version_env_system
+ ENV["BUNDLE_VERSION"] = "system"
+
+ bvf.stub(:lockfile_contents, "\n\nBUNDLED WITH\n 1.1.1.1\n") do
+ assert_nil bvf.bundler_version
+ end
+ end
+
+ def test_bundler_version_with_bundle_version_env_overrides_config
+ ENV["BUNDLE_VERSION"] = "2.3.4"
+
+ config_content = <<~CONFIG
+ BUNDLE_VERSION: "1.2.3"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_content)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ assert_equal v("2.3.4"), bvf.bundler_version
+ end
+ end
+ end
+
+ def test_bundler_version_with_empty_bundle_version_env
+ ENV["BUNDLE_VERSION"] = ""
+
+ config_content = <<~CONFIG
+ BUNDLE_VERSION: "1.2.3"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_content)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ assert_equal v("1.2.3"), bvf.bundler_version
+ end
+ end
+ end
+
+ def test_bundler_version_with_bundle_version_env_lockfile
+ ENV["BUNDLE_VERSION"] = "lockfile"
+
+ bvf.stub(:lockfile_contents, "\n\nBUNDLED WITH\n 1.1.1.1\n") do
+ assert_equal v("1.1.1.1"), bvf.bundler_version
+ end
+ end
+
+ def test_bundler_version_with_bundle_config_version_lockfile
+ config_content = <<~CONFIG
+ BUNDLE_VERSION: "lockfile"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_content)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ bvf.stub(:lockfile_contents, "\n\nBUNDLED WITH\n 1.1.1.1\n") do
+ assert_equal v("1.1.1.1"), bvf.bundler_version
+ end
+ end
+ end
+ end
+
+ def test_bundler_version_with_bundle_config_non_existent_file
+ bvf.stub(:bundler_global_config_file, "/non/existent/path") do
+ assert_nil bvf.bundler_version
+ end
+ end
+
+ def test_bundler_version_set_on_local_config
+ config_content = <<~CONFIG
+ BUNDLE_VERSION: "1.2.3"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_content)
+ f.flush
+
+ bvf.stub(:bundler_local_config_file, f.path) do
+ assert_equal v("1.2.3"), bvf.bundler_version
+ end
+ end
+ end
+
+ def test_bundler_version_with_bundle_config_without_version
+ config_without_version = <<~CONFIG
+ BUNDLE_JOBS: "8"
+ BUNDLE_GEM__TEST: "minitest"
+ CONFIG
+
+ Tempfile.create("bundle_config") do |f|
+ f.write(config_without_version)
+ f.flush
+
+ bvf.stub(:bundler_global_config_file, f.path) do
+ assert_nil bvf.bundler_version
+ end
+ end
+ end
+
def test_bundler_version_with_lockfile
bvf.stub(:lockfile_contents, "") do
assert_nil bvf.bundler_version
@@ -82,7 +239,7 @@ class TestGemBundlerVersionFinder < Gem::TestCase
def test_deleted_directory
pend "Cannot perform this test on windows" if Gem.win_platform?
- pend "Cannot perform this test on Solaris" if RUBY_PLATFORM.include?("solaris")
+
require "tmpdir"
orig_dir = Dir.pwd
diff --git a/test/rubygems/test_gem_command_manager.rb b/test/rubygems/test_gem_command_manager.rb
index f3848e498d..889d5ce9e6 100644
--- a/test/rubygems/test_gem_command_manager.rb
+++ b/test/rubygems/test_gem_command_manager.rb
@@ -43,7 +43,7 @@ class TestGemCommandManager < Gem::TestCase
assert_kind_of Gem::Commands::SigninCommand, command
end
- def test_find_logout_alias_comamnd
+ def test_find_logout_alias_command
command = @command_manager.find_command "logout"
assert_kind_of Gem::Commands::SignoutCommand, command
@@ -78,7 +78,7 @@ class TestGemCommandManager < Gem::TestCase
message = "Unknown command pish".dup
- if defined?(DidYouMean::SPELL_CHECKERS) && defined?(DidYouMean::Correctable)
+ if e.respond_to?(:corrections)
message << "\nDid you mean? \"push\""
end
@@ -287,47 +287,6 @@ class TestGemCommandManager < Gem::TestCase
assert_equal "foobar.rb", check_options[:args].first
end
- # HACK: move to query command test
- def test_process_args_query
- # capture all query options
- check_options = nil
- @command_manager["query"].when_invoked do |options|
- check_options = options
- true
- end
-
- # check defaults
- Gem::Deprecate.skip_during do
- @command_manager.process_args %w[query]
- end
- assert_nil(check_options[:name])
- assert_equal :local, check_options[:domain]
- assert_equal false, check_options[:details]
-
- # check settings
- check_options = nil
- Gem::Deprecate.skip_during do
- @command_manager.process_args %w[query --name foobar --local --details]
- end
- assert_equal(/foobar/i, check_options[:name])
- assert_equal :local, check_options[:domain]
- assert_equal true, check_options[:details]
-
- # remote domain
- check_options = nil
- Gem::Deprecate.skip_during do
- @command_manager.process_args %w[query --remote]
- end
- assert_equal :remote, check_options[:domain]
-
- # both (local/remote) domains
- check_options = nil
- Gem::Deprecate.skip_during do
- @command_manager.process_args %w[query --both]
- end
- assert_equal :both, check_options[:domain]
- end
-
# HACK: move to update command test
def test_process_args_update
# capture all update options
diff --git a/test/rubygems/test_gem_commands_build_command.rb b/test/rubygems/test_gem_commands_build_command.rb
index d44126d204..9339f41f7c 100644
--- a/test/rubygems/test_gem_commands_build_command.rb
+++ b/test/rubygems/test_gem_commands_build_command.rb
@@ -43,16 +43,6 @@ class TestGemCommandsBuildCommand < Gem::TestCase
assert_includes Gem.platforms, Gem::Platform.local
end
- def test_handle_deprecated_options
- use_ui @ui do
- @cmd.handle_options %w[-C ./test/dir]
- end
-
- assert_equal "WARNING: The \"-C\" option has been deprecated and will be removed in Rubygems 4.0. " \
- "-C is a global flag now. Use `gem -C PATH build GEMSPEC_FILE [options]` instead\n",
- @ui.error
- end
-
def test_options_filename
gemspec_file = File.join(@tempdir, @gem.spec_name)
diff --git a/test/rubygems/test_gem_commands_cert_command.rb b/test/rubygems/test_gem_commands_cert_command.rb
index c173467935..ed1a1c8627 100644
--- a/test/rubygems/test_gem_commands_cert_command.rb
+++ b/test/rubygems/test_gem_commands_cert_command.rb
@@ -31,14 +31,6 @@ class TestGemCommandsCertCommand < Gem::TestCase
@cmd = Gem::Commands::CertCommand.new
@trust_dir = Gem::Security.trust_dir
-
- @cleanup = []
- end
-
- def teardown
- FileUtils.rm_f(@cleanup)
-
- super
end
def test_certificates_matching
@@ -498,7 +490,7 @@ Removed '/CN=alternate/DC=example'
assert_equal "/CN=nobody/DC=example", cert.issuer.to_s
- mask = 0o100600 & (~File.umask)
+ mask = 0o100600 & ~File.umask
assert_equal mask, File.stat(path).mode unless Gem.win_platform?
end
@@ -527,7 +519,7 @@ Removed '/CN=alternate/DC=example'
assert_equal "/CN=nobody/DC=example", cert.issuer.to_s
- mask = 0o100600 & (~File.umask)
+ mask = 0o100600 & ~File.umask
assert_equal mask, File.stat(path).mode unless Gem.win_platform?
end
@@ -559,7 +551,7 @@ Removed '/CN=alternate/DC=example'
assert_equal "/CN=nobody/DC=example", cert.issuer.to_s
- mask = 0o100600 & (~File.umask)
+ mask = 0o100600 & ~File.umask
assert_equal mask, File.stat(path).mode unless Gem.win_platform?
end
@@ -591,7 +583,7 @@ Removed '/CN=alternate/DC=example'
assert_equal "/CN=nobody/DC=example", cert.issuer.to_s
- mask = 0o100600 & (~File.umask)
+ mask = 0o100600 & ~File.umask
assert_equal mask, File.stat(path).mode unless Gem.win_platform?
end
@@ -661,8 +653,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
assert_equal "/CN=nobody/DC=example", EXPIRED_PUBLIC_CERT.issuer.to_s
- tmp_expired_cert_file = File.join(Dir.tmpdir, File.basename(EXPIRED_PUBLIC_CERT_FILE))
- @cleanup << tmp_expired_cert_file
+ tmp_expired_cert_file = File.join(@tempdir, File.basename(EXPIRED_PUBLIC_CERT_FILE))
File.write(tmp_expired_cert_file, File.read(EXPIRED_PUBLIC_CERT_FILE))
@cmd.handle_options %W[
@@ -694,8 +685,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
assert_equal "/CN=nobody/DC=example", EXPIRED_PUBLIC_CERT.issuer.to_s
- tmp_expired_cert_file = File.join(Dir.tmpdir, File.basename(EXPIRED_PUBLIC_CERT_FILE))
- @cleanup << tmp_expired_cert_file
+ tmp_expired_cert_file = File.join(@tempdir, File.basename(EXPIRED_PUBLIC_CERT_FILE))
File.write(tmp_expired_cert_file, File.read(EXPIRED_PUBLIC_CERT_FILE))
@cmd.handle_options %W[
diff --git a/test/rubygems/test_gem_commands_environment_command.rb b/test/rubygems/test_gem_commands_environment_command.rb
index 48252d84d4..e27de544c6 100644
--- a/test/rubygems/test_gem_commands_environment_command.rb
+++ b/test/rubygems/test_gem_commands_environment_command.rb
@@ -164,4 +164,8 @@ class TestGemCommandsEnvironmentCommand < Gem::TestCase
assert_equal "#{Gem.platforms.join File::PATH_SEPARATOR}\n", @ui.output
assert_equal "", @ui.error
end
+
+ def test_description_mentions_concurrent_downloads
+ assert_match(/:concurrent_downloads:/, @cmd.description)
+ end
end
diff --git a/test/rubygems/test_gem_commands_exec_command.rb b/test/rubygems/test_gem_commands_exec_command.rb
index db738b5e9f..b949cd34a6 100644
--- a/test/rubygems/test_gem_commands_exec_command.rb
+++ b/test/rubygems/test_gem_commands_exec_command.rb
@@ -856,4 +856,33 @@ class TestGemCommandsExecCommand < Gem::TestCase
assert_equal %w[a-1.1.a], @installed_specs.map(&:full_name)
end
end
+
+ def test_install_dependency_resolution_error
+ spec_fetcher do |fetcher|
+ fetcher.gem "a", 2 do |s|
+ s.executables = %w[a]
+ s.add_dependency "b", "~> 1.0"
+ s.add_dependency "c", "~> 1.0"
+ end
+ fetcher.gem "b", 1 do |s|
+ s.add_dependency "d", "= 1.0"
+ end
+ fetcher.gem "c", 1 do |s|
+ s.add_dependency "d", "= 2.0"
+ end
+ fetcher.gem "d", 1
+ fetcher.gem "d", 2
+ end
+
+ util_clear_gems
+
+ use_ui @ui do
+ e = assert_raise Gem::MockGemUi::TermError do
+ @cmd.invoke "a:2"
+ end
+ assert_equal 2, e.exit_code
+ end
+
+ assert_match(/ERROR:.*Error installing a:/, @ui.error)
+ end
end
diff --git a/test/rubygems/test_gem_commands_fetch_command.rb b/test/rubygems/test_gem_commands_fetch_command.rb
index 84fad08fd6..e673e391fe 100644
--- a/test/rubygems/test_gem_commands_fetch_command.rb
+++ b/test/rubygems/test_gem_commands_fetch_command.rb
@@ -157,7 +157,7 @@ class TestGemCommandsFetchCommand < Gem::TestCase
execute_with_term_error
msg = "ERROR: Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem fetch 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem fetch 'my_gem:1.0.0' 'my_other_gem:>=2'`"
assert_empty @ui.output
assert_equal msg, @ui.error.chomp
diff --git a/test/rubygems/test_gem_commands_help_command.rb b/test/rubygems/test_gem_commands_help_command.rb
index 01ab4aab2f..4ce7285d1f 100644
--- a/test/rubygems/test_gem_commands_help_command.rb
+++ b/test/rubygems/test_gem_commands_help_command.rb
@@ -36,7 +36,7 @@ class TestGemCommandsHelpCommand < Gem::TestCase
def test_gem_help_build
util_gem "build" do |out, err|
- assert_match(/-C PATH *Run as if gem build was started in <PATH>/, out)
+ assert_match(/--platform PLATFORM\s+Specify the platform of gem to build/, out)
assert_equal "", err
end
end
diff --git a/test/rubygems/test_gem_commands_info_command.rb b/test/rubygems/test_gem_commands_info_command.rb
index f020d380d2..dab7cfb836 100644
--- a/test/rubygems/test_gem_commands_info_command.rb
+++ b/test/rubygems/test_gem_commands_info_command.rb
@@ -13,7 +13,7 @@ class TestGemCommandsInfoCommand < Gem::TestCase
def gem(name, version = "1.0")
spec = quick_gem name do |gem|
gem.summary = "test gem"
- gem.homepage = "https://github.com/rubygems/rubygems"
+ gem.homepage = "https://github.com/ruby/rubygems"
gem.files = %W[lib/#{name}.rb Rakefile]
gem.authors = ["Colby", "Jack"]
gem.license = "MIT"
diff --git a/test/rubygems/test_gem_commands_install_command.rb b/test/rubygems/test_gem_commands_install_command.rb
index 4e49f52b4c..d75ba349f9 100644
--- a/test/rubygems/test_gem_commands_install_command.rb
+++ b/test/rubygems/test_gem_commands_install_command.rb
@@ -119,11 +119,7 @@ class TestGemCommandsInstallCommand < Gem::TestCase
end
end
- expected = <<-EXPECTED
-ERROR: Could not find a valid gem 'bar' (= 0.5) (required by 'foo' (>= 0)) in any repository
- EXPECTED
-
- assert_equal expected, @ui.error
+ assert_match(/ERROR:.*foo.*bar/m, @ui.error)
end
def test_execute_local_dependency_nonexistent_ignore_dependencies
@@ -303,11 +299,7 @@ ERROR: Could not find a valid gem 'bar' (= 0.5) (required by 'foo' (>= 0)) in a
assert_equal 2, e.exit_code
end
- expected = <<-EXPECTED
-ERROR: Could not find a valid gem 'bar' (= 0.5) (required by 'foo' (>= 0)) in any repository
- EXPECTED
-
- assert_equal expected, @ui.error
+ assert_match(/ERROR:.*foo.*bar/m, @ui.error)
end
def test_execute_http_proxy
@@ -647,17 +639,10 @@ ERROR: Possible alternatives: non_existent_with_hint
@cmd.options[:args] = %w[a]
use_ui @ui do
- # Don't use Dir.chdir with a block, it warnings a lot because
- # of a downstream Dir.chdir with a block
- old = Dir.getwd
-
- begin
- Dir.chdir @tempdir
+ Dir.chdir @tempdir do
assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
@cmd.execute
end
- ensure
- Dir.chdir old
end
end
@@ -684,17 +669,10 @@ ERROR: Possible alternatives: non_existent_with_hint
@cmd.options[:args] = %w[a]
use_ui @ui do
- # Don't use Dir.chdir with a block, it warnings a lot because
- # of a downstream Dir.chdir with a block
- old = Dir.getwd
-
- begin
- Dir.chdir @tempdir
+ Dir.chdir @tempdir do
assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
@cmd.execute
end
- ensure
- Dir.chdir old
end
end
@@ -720,17 +698,10 @@ ERROR: Possible alternatives: non_existent_with_hint
@cmd.options[:args] = %w[a]
use_ui @ui do
- # Don't use Dir.chdir with a block, it warnings a lot because
- # of a downstream Dir.chdir with a block
- old = Dir.getwd
-
- begin
- Dir.chdir @tempdir
+ Dir.chdir @tempdir do
assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
@cmd.execute
end
- ensure
- Dir.chdir old
end
end
@@ -901,7 +872,7 @@ ERROR: Possible alternatives: non_existent_with_hint
assert_empty @cmd.installed_specs
msg = "ERROR: Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:>=2'`"
assert_empty @ui.output
assert_equal msg, @ui.error.chomp
@@ -1005,6 +976,38 @@ ERROR: Possible alternatives: non_existent_with_hint
assert_equal %W[a-3-#{local}], @cmd.installed_specs.map(&:full_name)
end
+ def test_install_gem_platform_specificity_match
+ util_set_arch "arm64-darwin-20"
+
+ spec_fetcher do |fetcher|
+ %w[ruby universal-darwin universal-darwin-20 x64-darwin-20 arm64-darwin-20].each do |platform|
+ fetcher.download "a", 3 do |s|
+ s.platform = platform
+ end
+ end
+ end
+
+ @cmd.install_gem "a", ">= 0"
+
+ assert_equal %w[a-3-arm64-darwin-20], @cmd.installed_specs.map(&:full_name)
+ end
+
+ def test_install_gem_platform_specificity_match_reverse_order
+ util_set_arch "arm64-darwin-20"
+
+ spec_fetcher do |fetcher|
+ %w[ruby universal-darwin universal-darwin-20 x64-darwin-20 arm64-darwin-20].reverse_each do |platform|
+ fetcher.download "a", 3 do |s|
+ s.platform = platform
+ end
+ end
+ end
+
+ @cmd.install_gem "a", ">= 0"
+
+ assert_equal %w[a-3-arm64-darwin-20], @cmd.installed_specs.map(&:full_name)
+ end
+
def test_install_gem_ignore_dependencies_specific_file
spec = util_spec "a", 2
@@ -1214,6 +1217,30 @@ ERROR: Possible alternatives: non_existent_with_hint
assert_match "Installing a (2)", @ui.output
end
+ def test_execute_installs_from_a_gemdeps_with_prerelease
+ spec_fetcher do |fetcher|
+ fetcher.download "a", 1
+ fetcher.download "a", "2.a"
+ end
+
+ File.open @gemdeps, "w" do |f|
+ f << "gem 'a'"
+ end
+
+ @cmd.handle_options %w[--prerelease]
+ @cmd.options[:gemdeps] = @gemdeps
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
+ @cmd.execute
+ end
+ end
+
+ assert_equal %w[a-2.a], @cmd.installed_specs.map(&:full_name)
+
+ assert_match "Installing a (2.a)", @ui.output
+ end
+
def test_execute_installs_deps_a_gemdeps
spec_fetcher do |fetcher|
fetcher.download "q", "1.0"
@@ -1548,4 +1575,63 @@ ERROR: Possible alternatives: non_existent_with_hint
assert_includes @ui.output, "A new release of RubyGems is available: 1.2.3 → 2.0.0!"
end
end
+
+ def test_pass_down_the_job_option_to_make
+ gemspec = nil
+
+ spec_fetcher do |fetcher|
+ fetcher.gem "a", 2 do |spec|
+ gemspec = spec
+
+ extconf_path = "#{spec.gem_dir}/extconf.rb"
+
+ write_file(extconf_path) do |io|
+ io.puts "require 'mkmf'"
+ io.puts "create_makefile '#{spec.name}'"
+ end
+
+ spec.extensions = "extconf.rb"
+ end
+ end
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
+ @cmd.invoke "a", "-j4"
+ end
+ end
+
+ gem_make_out = File.read(File.join(gemspec.extension_dir, "gem_make.out"))
+ if vc_windows? && nmake_found?
+ refute_includes(gem_make_out, " -j4")
+ else
+ assert_includes(gem_make_out, "make -j4")
+ end
+ end
+
+ def test_execute_bindir_with_nonexistent_parent_dirs
+ spec_fetcher do |fetcher|
+ fetcher.gem "a", 2 do |s|
+ s.executables = %w[a_bin]
+ s.files = %w[bin/a_bin]
+ end
+ end
+
+ @cmd.options[:args] = %w[a]
+
+ nested_bin_dir = File.join(@tempdir, "not", "exists")
+ refute_directory_exists nested_bin_dir, "Nested bin directory should not exist yet"
+
+ @cmd.options[:bin_dir] = nested_bin_dir
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
+ @cmd.execute
+ end
+ end
+
+ assert_directory_exists nested_bin_dir, "Nested bin directory should exist now"
+ assert_path_exist File.join(nested_bin_dir, "a_bin")
+
+ assert_equal %w[a-2], @cmd.installed_specs.map(&:full_name)
+ end
end
diff --git a/test/rubygems/test_gem_commands_open_command.rb b/test/rubygems/test_gem_commands_open_command.rb
index d9e518048c..addc7427e2 100644
--- a/test/rubygems/test_gem_commands_open_command.rb
+++ b/test/rubygems/test_gem_commands_open_command.rb
@@ -21,6 +21,8 @@ class TestGemCommandsOpenCommand < Gem::TestCase
end
def test_execute
+ omit "JRuby on Windows spawns the editor with a different cwd" if Gem.win_platform? && Gem.java_platform?
+
@cmd.options[:args] = %w[foo]
@cmd.options[:editor] = (ruby_with_rubygems_in_load_path + ["-e", "puts(ARGV,Dir.pwd)", "--"]).join(" ")
diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb
index bc4f13ff2a..f6d4d03f84 100644
--- a/test/rubygems/test_gem_commands_owner_command.rb
+++ b/test/rubygems/test_gem_commands_owner_command.rb
@@ -32,9 +32,12 @@ class TestGemCommandsOwnerCommand < Gem::TestCase
- email: user1@example.com
id: 1
handle: user1
+ role: owner
- email: user2@example.com
+ role: maintainer
- id: 3
handle: user3
+ role: owner
- id: 4
EOF
@@ -48,14 +51,14 @@ EOF
assert_equal Gem.configuration.rubygems_api_key, @stub_fetcher.last_request["Authorization"]
assert_match(/Owners for gem: freewill/, @stub_ui.output)
- assert_match(/- user1@example.com/, @stub_ui.output)
- assert_match(/- user2@example.com/, @stub_ui.output)
- assert_match(/- user3/, @stub_ui.output)
+ assert_match(/- user1@example.com \(owner\)/, @stub_ui.output)
+ assert_match(/- user2@example.com \(maintainer\)/, @stub_ui.output)
+ assert_match(/- user3 \(owner\)/, @stub_ui.output)
assert_match(/- 4/, @stub_ui.output)
end
def test_show_owners_dont_load_objects
- pend "testing a psych-only API" unless defined?(::Psych::DisallowedClass)
+ Gem.load_yaml
response = <<EOF
---
@@ -386,9 +389,10 @@ EOF
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
assert_match response_success, @stub_ui.output
@@ -412,10 +416,12 @@ EOF
end
end
- assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ webauthn_verification_request = @stub_fetcher.requests.find {|req| req.path == "/api/v1/webauthn_verification" }
+ assert_match webauthn_verification_request["Authorization"], Gem.configuration.rubygems_api_key
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @stub_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
refute_match response_success, @stub_ui.output
@@ -435,9 +441,10 @@ EOF
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
assert_match response_success, @stub_ui.output
@@ -463,16 +470,17 @@ EOF
end
assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @stub_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
refute_match response_success, @stub_ui.output
end
- def test_remove_owners_unathorized_api_key
+ def test_remove_owners_unauthorized_api_key
response_forbidden = "The API key doesn't have access"
response_success = "Owner removed successfully."
@@ -537,7 +545,7 @@ EOF
assert_empty reused_otp_codes
end
- def test_add_owners_unathorized_api_key
+ def test_add_owners_unauthorized_api_key
response_forbidden = "The API key doesn't have access"
response_success = "Owner added successfully."
diff --git a/test/rubygems/test_gem_commands_pristine_command.rb b/test/rubygems/test_gem_commands_pristine_command.rb
index 46c06db014..0ea140897c 100644
--- a/test/rubygems/test_gem_commands_pristine_command.rb
+++ b/test/rubygems/test_gem_commands_pristine_command.rb
@@ -125,8 +125,8 @@ class TestGemCommandsPristineCommand < Gem::TestCase
@cmd.execute
end
- assert File.exist?(gem_bin)
- assert File.exist?(gem_stub)
+ assert_path_exist gem_bin
+ assert_path_exist gem_stub
out = @ui.output.split "\n"
@@ -248,7 +248,13 @@ class TestGemCommandsPristineCommand < Gem::TestCase
end
refute_includes @ui.output, "Restored #{a.full_name}"
- assert_includes @ui.output, "Restored #{b.full_name}"
+
+ if Gem.java_platform?
+ refute_includes @ui.output, "Restored #{b.full_name}"
+ assert_includes @ui.output, "No gems with missing extensions to restore"
+ else
+ assert_includes @ui.output, "Restored #{b.full_name}"
+ end
end
def test_execute_no_extension
@@ -537,8 +543,8 @@ class TestGemCommandsPristineCommand < Gem::TestCase
@cmd.execute
end
- assert File.exist? gem_exec
- refute File.exist? gem_lib
+ assert_path_exist gem_exec
+ assert_path_not_exist gem_lib
end
def test_execute_only_plugins
@@ -572,9 +578,9 @@ class TestGemCommandsPristineCommand < Gem::TestCase
@cmd.execute
end
- refute File.exist? gem_exec
- assert File.exist? gem_plugin
- refute File.exist? gem_lib
+ assert_path_not_exist gem_exec
+ assert_path_exist gem_plugin
+ assert_path_not_exist gem_lib
end
def test_execute_bindir
@@ -606,8 +612,8 @@ class TestGemCommandsPristineCommand < Gem::TestCase
@cmd.execute
end
- refute File.exist? gem_exec
- assert File.exist? gem_bindir
+ assert_path_not_exist gem_exec
+ assert_path_exist gem_bindir
end
def test_execute_unknown_gem_at_remote_source
@@ -659,6 +665,42 @@ class TestGemCommandsPristineCommand < Gem::TestCase
refute_includes "ruby_executable_hooks", File.read(exe)
end
+ def test_execute_default_gem_and_regular_gem
+ a_default = new_default_spec("a", "1.2.0")
+
+ a = util_spec "a" do |s|
+ s.extensions << "ext/a/extconf.rb"
+ end
+
+ ext_path = File.join @tempdir, "ext", "a", "extconf.rb"
+ write_file ext_path do |io|
+ io.write <<-'RUBY'
+ File.open "Makefile", "w" do |f|
+ f.puts "clean:\n\techo cleaned\n"
+ f.puts "all:\n\techo built\n"
+ f.puts "install:\n\techo installed\n"
+ end
+ RUBY
+ end
+
+ install_default_gems a_default
+ install_gem a
+
+ # Remove the extension files for a
+ FileUtils.rm_rf a.gem_build_complete_path
+
+ @cmd.options[:args] = %w[a]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ assert_includes @ui.output, "Restored #{a.full_name}"
+
+ # Check extension files for a were restored
+ assert_path_exist a.gem_build_complete_path
+ end
+
def test_execute_multi_platform
a = util_spec "a" do |s|
s.extensions << "ext/a/extconf.rb"
diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb
index 2d0190b49f..ada95e89b4 100644
--- a/test/rubygems/test_gem_commands_push_command.rb
+++ b/test/rubygems/test_gem_commands_push_command.rb
@@ -115,40 +115,116 @@ class TestGemCommandsPushCommand < Gem::TestCase
assert_equal Gem::Net::HTTP::Post, @fetcher.last_request.class
content_length = @fetcher.last_request["Content-Length"].to_i
assert_equal content_length, @fetcher.last_request.body.length
- assert_equal "multipart", @fetcher.last_request.main_type, @fetcher.last_request.content_type
- assert_equal "form-data", @fetcher.last_request.sub_type
- assert_include @fetcher.last_request.type_params, "boundary"
- boundary = @fetcher.last_request.type_params["boundary"]
+ assert_attestation_multipart Gem.read_binary("#{@path}.sigstore.json")
+ end
- parts = @fetcher.last_request.body.split(/(?:\r\n|\A)--#{Regexp.quote(boundary)}(?:\r\n|--)/m)
- refute_empty parts
- assert_empty parts[0]
- parts.shift # remove the first empty part
+ def test_execute_attestation_auto
+ omit if RUBY_ENGINE == "jruby"
- p1 = parts.shift
- p2 = parts.shift
- assert_equal "\r\n", parts.shift
- assert_empty parts
+ ENV["GITHUB_ACTIONS"] = "true"
+ begin
+ @response = "Successfully registered gem: freewill (1.0.0)"
+ @fetcher.data["#{Gem.host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK")
- assert_equal [
- "Content-Disposition: form-data; name=\"gem\"; filename=\"#{@path}\"",
- "Content-Type: application/octet-stream",
- nil,
- Gem.read_binary(@path),
- ].join("\r\n").b, p1
- assert_equal [
- "Content-Disposition: form-data; name=\"attestations\"",
- nil,
- "[#{Gem.read_binary("#{@path}.sigstore.json")}]",
- ].join("\r\n").b, p2
+ attestation_path = "#{@path}.sigstore.json"
+ attestation_content = "auto-attestation"
+ File.write(attestation_path, attestation_content)
+ @cmd.options[:args] = [@path]
+
+ @cmd.stub(:attest!, attestation_path) do
+ @cmd.execute
+ end
+
+ assert_equal Gem::Net::HTTP::Post, @fetcher.last_request.class
+ content_length = @fetcher.last_request["Content-Length"].to_i
+ assert_equal content_length, @fetcher.last_request.body.length
+ assert_attestation_multipart attestation_content
+ ensure
+ ENV.delete("GITHUB_ACTIONS")
+ end
end
- def test_execute_allowed_push_host
+ def test_execute_attestation_fallback
+ omit if RUBY_ENGINE == "jruby"
+
+ ENV["GITHUB_ACTIONS"] = "true"
+ begin
+ @response = "Successfully registered gem: freewill (1.0.0)"
+ @fetcher.data["#{Gem.host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK")
+
+ @cmd.options[:args] = [@path]
+
+ @cmd.stub(:attest!, proc { raise Gem::Exception, "boom" }) do
+ use_ui @ui do
+ @cmd.execute
+ end
+ end
+
+ assert_match "Failed to push with attestation, retrying without attestation.", @ui.error
+ assert_equal Gem::Net::HTTP::Post, @fetcher.last_request.class
+ assert_equal Gem.read_binary(@path), @fetcher.last_request.body
+ assert_equal "application/octet-stream",
+ @fetcher.last_request["Content-Type"]
+ ensure
+ ENV.delete("GITHUB_ACTIONS")
+ end
+ end
+
+ def test_execute_attestation_skipped_on_non_rubygems_host
@spec, @path = util_gem "freebird", "1.0.1" do |spec|
spec.metadata["allowed_push_host"] = "https://privategemserver.example"
end
+ @response = "Successfully registered gem: freebird (1.0.1)"
+ @fetcher.data["#{@spec.metadata["allowed_push_host"]}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK")
+
+ @cmd.options[:args] = [@path]
+
+ attest_called = false
+ @cmd.stub(:attest!, proc { attest_called = true }) do
+ @cmd.execute
+ end
+
+ refute attest_called, "attest! should not be called for non-rubygems.org hosts"
+ assert_equal Gem::Net::HTTP::Post, @fetcher.last_request.class
+ assert_equal Gem.read_binary(@path), @fetcher.last_request.body
+ assert_equal "application/octet-stream",
+ @fetcher.last_request["Content-Type"]
+ end
+
+ def test_execute_attestation_skipped_on_jruby
@response = "Successfully registered gem: freewill (1.0.0)"
+ @fetcher.data["#{Gem.host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK")
+
+ @cmd.options[:args] = [@path]
+
+ attest_called = false
+ engine = RUBY_ENGINE
+ Object.send :remove_const, :RUBY_ENGINE
+ Object.const_set :RUBY_ENGINE, "jruby"
+
+ begin
+ @cmd.stub(:attest!, proc { attest_called = true }) do
+ @cmd.execute
+ end
+
+ refute attest_called, "attest! should not be called on JRuby"
+ assert_equal Gem::Net::HTTP::Post, @fetcher.last_request.class
+ assert_equal Gem.read_binary(@path), @fetcher.last_request.body
+ assert_equal "application/octet-stream",
+ @fetcher.last_request["Content-Type"]
+ ensure
+ Object.send :remove_const, :RUBY_ENGINE
+ Object.const_set :RUBY_ENGINE, engine
+ end
+ end
+
+ def test_execute_allowed_push_host
+ @spec, @path = util_gem "freebird", "1.0.1" do |spec|
+ spec.metadata["allowed_push_host"] = "https://privategemserver.example"
+ end
+
+ @response = "Successfully registered gem: freebird (1.0.1)"
@fetcher.data["#{@spec.metadata["allowed_push_host"]}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK")
@fetcher.data["#{Gem.host}/api/v1/gems"] =
["fail", 500, "Internal Server Error"]
@@ -477,15 +553,17 @@ class TestGemCommandsPushCommand < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match response_success, @ui.output
end
def test_with_webauthn_enabled_failure
+ pend "Flaky on TruffleRuby" if RUBY_ENGINE == "truffleruby"
response_success = "Successfully registered gem: freewill (1.0.0)"
server = Gem::MockTCPServer.new
error = Gem::WebauthnVerificationError.new("Something went wrong")
@@ -505,9 +583,10 @@ class TestGemCommandsPushCommand < Gem::TestCase
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
refute_match response_success, @ui.output
@@ -527,9 +606,10 @@ class TestGemCommandsPushCommand < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match response_success, @ui.output
@@ -553,16 +633,17 @@ class TestGemCommandsPushCommand < Gem::TestCase
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.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.", @ui.output
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
+ "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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
refute_match response_success, @ui.output
end
- def test_sending_gem_unathorized_api_key_with_mfa_enabled
+ def test_sending_gem_unauthorized_api_key_with_mfa_enabled
response_mfa_enabled = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
response_forbidden = "The API key doesn't have access"
response_success = "Successfully registered gem: freewill (1.0.0)"
@@ -638,6 +719,35 @@ class TestGemCommandsPushCommand < Gem::TestCase
private
+ def assert_attestation_multipart(attestation_payload)
+ assert_equal "multipart", @fetcher.last_request.main_type, @fetcher.last_request.content_type
+ assert_equal "form-data", @fetcher.last_request.sub_type
+ assert_include @fetcher.last_request.type_params, "boundary"
+ boundary = @fetcher.last_request.type_params["boundary"]
+
+ parts = @fetcher.last_request.body.split(/(?:\r\n|\A)--#{Regexp.quote(boundary)}(?:\r\n|--)/m)
+ refute_empty parts
+ assert_empty parts[0]
+ parts.shift # remove the first empty part
+
+ p1 = parts.shift
+ p2 = parts.shift
+ assert_equal "\r\n", parts.shift
+ assert_empty parts
+
+ assert_equal [
+ "Content-Disposition: form-data; name=\"gem\"; filename=\"#{@path}\"",
+ "Content-Type: application/octet-stream",
+ nil,
+ Gem.read_binary(@path),
+ ].join("\r\n").b, p1
+ assert_equal [
+ "Content-Disposition: form-data; name=\"attestations\"",
+ nil,
+ "[#{attestation_payload}]",
+ ].join("\r\n").b, p2
+ end
+
def singleton_gem_class
class << Gem; self; end
end
diff --git a/test/rubygems/test_gem_commands_query_command.rb b/test/rubygems/test_gem_commands_query_command.rb
deleted file mode 100644
index 8e590df124..0000000000
--- a/test/rubygems/test_gem_commands_query_command.rb
+++ /dev/null
@@ -1,830 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-require "rubygems/commands/query_command"
-
-module TestGemCommandsQueryCommandSetup
- def setup
- super
-
- @cmd = Gem::Commands::QueryCommand.new
-
- @specs = add_gems_to_fetcher
- @stub_ui = Gem::MockGemUi.new
- @stub_fetcher = Gem::FakeFetcher.new
-
- @stub_fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
- raise Gem::RemoteFetcher::FetchError
- end
- end
-end
-
-class TestGemCommandsQueryCommandWithInstalledGems < Gem::TestCase
- include TestGemCommandsQueryCommandSetup
-
- def test_execute
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-r]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_all
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-r --all]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_all_prerelease
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-r --all --prerelease]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (3.a, 2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_details
- spec_fetcher do |fetcher|
- fetcher.spec "a", 2 do |s|
- s.summary = "This is a lot of text. " * 4
- s.authors = ["Abraham Lincoln", "Hirohito"]
- s.homepage = "http://a.example.com/"
- end
-
- fetcher.legacy_platform
- end
-
- @cmd.handle_options %w[-r -d]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2)
- Authors: Abraham Lincoln, Hirohito
- Homepage: http://a.example.com/
-
- This is a lot of text. This is a lot of text. This is a lot of text.
- This is a lot of text.
-
-pl (1)
- Platform: i386-linux
- Author: A User
- Homepage: http://example.com
-
- this is a summary
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_details_cleans_text
- spec_fetcher do |fetcher|
- fetcher.spec "a", 2 do |s|
- s.summary = "This is a lot of text. " * 4
- s.authors = ["Abraham Lincoln \x01", "\x02 Hirohito"]
- s.homepage = "http://a.example.com/\x03"
- end
-
- fetcher.legacy_platform
- end
-
- @cmd.handle_options %w[-r -d]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2)
- Authors: Abraham Lincoln ., . Hirohito
- Homepage: http://a.example.com/.
-
- This is a lot of text. This is a lot of text. This is a lot of text.
- This is a lot of text.
-
-pl (1)
- Platform: i386-linux
- Author: A User
- Homepage: http://example.com
-
- this is a summary
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_details_truncates_summary
- spec_fetcher do |fetcher|
- fetcher.spec "a", 2 do |s|
- s.summary = "This is a lot of text. " * 10_000
- s.authors = ["Abraham Lincoln \x01", "\x02 Hirohito"]
- s.homepage = "http://a.example.com/\x03"
- end
-
- fetcher.legacy_platform
- end
-
- @cmd.handle_options %w[-r -d]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2)
- Authors: Abraham Lincoln ., . Hirohito
- Homepage: http://a.example.com/.
-
- Truncating the summary for a-2 to 100,000 characters:
-#{" This is a lot of text. This is a lot of text. This is a lot of text.\n" * 1449} This is a lot of te
-
-pl (1)
- Platform: i386-linux
- Author: A User
- Homepage: http://example.com
-
- this is a summary
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_installed
- @cmd.handle_options %w[-n a --installed]
-
- assert_raise Gem::MockGemUi::SystemExitException do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "true\n", @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_installed_inverse
- @cmd.handle_options %w[-n a --no-installed]
-
- e = assert_raise Gem::MockGemUi::TermError do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "false\n", @stub_ui.output
- assert_equal "", @stub_ui.error
-
- assert_equal 1, e.exit_code
- end
-
- def test_execute_installed_inverse_not_installed
- @cmd.handle_options %w[-n not_installed --no-installed]
-
- assert_raise Gem::MockGemUi::SystemExitException do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "true\n", @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_installed_no_name
- @cmd.handle_options %w[--installed]
-
- e = assert_raise Gem::MockGemUi::TermError do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "", @stub_ui.output
- assert_equal "ERROR: You must specify a gem name\n", @stub_ui.error
-
- assert_equal 4, e.exit_code
- end
-
- def test_execute_installed_not_installed
- @cmd.handle_options %w[-n not_installed --installed]
-
- e = assert_raise Gem::MockGemUi::TermError do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "false\n", @stub_ui.output
- assert_equal "", @stub_ui.error
-
- assert_equal 1, e.exit_code
- end
-
- def test_execute_installed_version
- @cmd.handle_options %w[-n a --installed --version 2]
-
- assert_raise Gem::MockGemUi::SystemExitException do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "true\n", @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_installed_version_not_installed
- @cmd.handle_options %w[-n c --installed --version 2]
-
- e = assert_raise Gem::MockGemUi::TermError do
- use_ui @stub_ui do
- @cmd.execute
- end
- end
-
- assert_equal "false\n", @stub_ui.output
- assert_equal "", @stub_ui.error
-
- assert_equal 1, e.exit_code
- end
-
- def test_execute_local
- spec_fetcher(&:legacy_platform)
-
- @cmd.options[:domain] = :local
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (3.a, 2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_local_notty
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[]
-
- @stub_ui.outs.tty = false
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-a (3.a, 2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_local_quiet
- spec_fetcher(&:legacy_platform)
-
- @cmd.options[:domain] = :local
- Gem.configuration.verbose = false
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-a (3.a, 2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_no_versions
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-r --no-versions]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a
-pl
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_notty
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-r]
-
- @stub_ui.outs.tty = false
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-a (2)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_prerelease
- @cmd.handle_options %w[-r --prerelease]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (3.a)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_prerelease_local
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-l --prerelease]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (3.a, 2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_no_prerelease_local
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[-l --no-prerelease]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_remote
- spec_fetcher(&:legacy_platform)
-
- @cmd.options[:domain] = :remote
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_remote_notty
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[]
-
- @stub_ui.outs.tty = false
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-a (3.a, 2, 1)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_remote_quiet
- spec_fetcher(&:legacy_platform)
-
- @cmd.options[:domain] = :remote
- Gem.configuration.verbose = false
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-a (2)
-pl (1 i386-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_make_entry
- a_2_name = @specs["a-2"].original_name
-
- @stub_fetcher.data.delete \
- "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a_2_name}.gemspec.rz"
-
- a2 = @specs["a-2"]
- entry_tuples = [
- [Gem::NameTuple.new(a2.name, a2.version, a2.platform),
- Gem.sources.first],
- ]
-
- platforms = { a2.version => [a2.platform] }
-
- entry = @cmd.send :make_entry, entry_tuples, platforms
-
- assert_equal "a (2)", entry
- end
-
- # Test for multiple args handling!
- def test_execute_multiple_args
- spec_fetcher(&:legacy_platform)
-
- @cmd.handle_options %w[a pl]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- assert_match(/^a /, @stub_ui.output)
- assert_match(/^pl /, @stub_ui.output)
- assert_equal "", @stub_ui.error
- end
-
- def test_show_gems
- @cmd.options[:name] = //
- @cmd.options[:domain] = :remote
-
- use_ui @stub_ui do
- @cmd.send :show_gems, /a/i
- end
-
- assert_match(/^a /, @stub_ui.output)
- refute_match(/^pl /, @stub_ui.output)
- assert_empty @stub_ui.error
- end
-
- private
-
- def add_gems_to_fetcher
- spec_fetcher do |fetcher|
- fetcher.spec "a", 1
- fetcher.spec "a", 2
- fetcher.spec "a", "3.a"
- end
- end
-end
-
-class TestGemCommandsQueryCommandWithoutInstalledGems < Gem::TestCase
- include TestGemCommandsQueryCommandSetup
-
- def test_execute_platform
- spec_fetcher do |fetcher|
- fetcher.spec "a", 1
- fetcher.spec "a", 1 do |s|
- s.platform = "x86-linux"
- end
-
- fetcher.spec "a", 2 do |s|
- s.platform = "universal-darwin"
- end
- end
-
- @cmd.handle_options %w[-r -a]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-a (2 universal-darwin, 1 ruby x86-linux)
- EOF
-
- assert_equal expected, @stub_ui.output
- assert_equal "", @stub_ui.error
- end
-
- def test_execute_show_default_gems
- spec_fetcher {|fetcher| fetcher.spec "a", 2 }
-
- a1 = new_default_spec "a", 1
- install_default_gems a1
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (2, default: 1)
-EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_show_default_gems_with_platform
- a1 = new_default_spec "a", 1
- a1.platform = "java"
- install_default_gems a1
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (default: 1 java)
-EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_default_details
- spec_fetcher do |fetcher|
- fetcher.spec "a", 2
- end
-
- a1 = new_default_spec "a", 1
- install_default_gems a1
-
- @cmd.handle_options %w[-l -d]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (2, 1)
- Author: A User
- Homepage: http://example.com
- Installed at (2): #{@gemhome}
- (1, default): #{a1.base_dir}
-
- this is a summary
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_local_details
- spec_fetcher do |fetcher|
- fetcher.spec "a", 1 do |s|
- s.platform = "x86-linux"
- end
-
- fetcher.spec "a", 2 do |s|
- s.summary = "This is a lot of text. " * 4
- s.authors = ["Abraham Lincoln", "Hirohito"]
- s.homepage = "http://a.example.com/"
- s.platform = "universal-darwin"
- end
-
- fetcher.legacy_platform
- end
-
- @cmd.handle_options %w[-l -d]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- str = @stub_ui.output
-
- str.gsub!(/\(\d\): [^\n]*/, "-")
- str.gsub!(/at: [^\n]*/, "at: -")
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-a (2, 1)
- Platforms:
- 1: x86-linux
- 2: universal-darwin
- Authors: Abraham Lincoln, Hirohito
- Homepage: http://a.example.com/
- Installed at -
- -
-
- This is a lot of text. This is a lot of text. This is a lot of text.
- This is a lot of text.
-
-pl (1)
- Platform: i386-linux
- Author: A User
- Homepage: http://example.com
- Installed at: -
-
- this is a summary
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_exact_remote
- spec_fetcher do |fetcher|
- fetcher.spec "coolgem-omg", 3
- fetcher.spec "coolgem", "4.2.1"
- fetcher.spec "wow_coolgem", 1
- end
-
- @cmd.handle_options %w[--remote --exact coolgem]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** REMOTE GEMS ***
-
-coolgem (4.2.1)
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_exact_local
- spec_fetcher do |fetcher|
- fetcher.spec "coolgem-omg", 3
- fetcher.spec "coolgem", "4.2.1"
- fetcher.spec "wow_coolgem", 1
- end
-
- @cmd.handle_options %w[--exact coolgem]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-coolgem (4.2.1)
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_execute_exact_multiple
- spec_fetcher do |fetcher|
- fetcher.spec "coolgem-omg", 3
- fetcher.spec "coolgem", "4.2.1"
- fetcher.spec "wow_coolgem", 1
-
- fetcher.spec "othergem-omg", 3
- fetcher.spec "othergem", "1.2.3"
- fetcher.spec "wow_othergem", 1
- end
-
- @cmd.handle_options %w[--exact coolgem othergem]
-
- use_ui @stub_ui do
- @cmd.execute
- end
-
- expected = <<-EOF
-
-*** LOCAL GEMS ***
-
-coolgem (4.2.1)
-
-*** LOCAL GEMS ***
-
-othergem (1.2.3)
- EOF
-
- assert_equal expected, @stub_ui.output
- end
-
- def test_depprecated
- assert @cmd.deprecated?
- end
-
- private
-
- def add_gems_to_fetcher
- spec_fetcher do |fetcher|
- fetcher.download "a", 1
- fetcher.download "a", 2
- fetcher.download "a", "3.a"
- end
- end
-end
diff --git a/test/rubygems/test_gem_commands_setup_command.rb b/test/rubygems/test_gem_commands_setup_command.rb
index c3622c02cd..b33e05ab28 100644
--- a/test/rubygems/test_gem_commands_setup_command.rb
+++ b/test/rubygems/test_gem_commands_setup_command.rb
@@ -4,13 +4,6 @@ require_relative "helper"
require "rubygems/commands/setup_command"
class TestGemCommandsSetupCommand < Gem::TestCase
- bundler_gemspec = File.expand_path("../../bundler/lib/bundler/version.rb", __dir__)
- if File.exist?(bundler_gemspec)
- BUNDLER_VERS = File.read(bundler_gemspec).match(/VERSION = "(#{Gem::Version::VERSION_PATTERN})"/)[1]
- else
- BUNDLER_VERS = "2.0.1"
- end
-
def setup
super
@@ -35,9 +28,10 @@ class TestGemCommandsSetupCommand < Gem::TestCase
create_dummy_files(filelist)
- gemspec = util_spec "bundler", BUNDLER_VERS do |s|
+ gemspec = util_spec "bundler", "9.9.9" do |s|
s.bindir = "exe"
s.executables = ["bundle", "bundler"]
+ s.files = ["lib/bundler.rb"]
end
File.open "bundler/bundler.gemspec", "w" do |io|
@@ -229,6 +223,9 @@ class TestGemCommandsSetupCommand < Gem::TestCase
assert_path_exist "#{Gem.dir}/gems/bundler-#{bundler_version}"
assert_path_exist "#{Gem.dir}/gems/bundler-audit-1.0.0"
+
+ assert_path_exist "#{Gem.dir}/gems/bundler-#{bundler_version}/exe/bundle"
+ assert_path_not_exist "#{Gem.dir}/gems/bundler-#{bundler_version}/lib/bundler.rb"
end
def test_install_default_bundler_gem_with_default_gems_not_installed_at_default_dir
@@ -380,20 +377,22 @@ class TestGemCommandsSetupCommand < Gem::TestCase
File.open "CHANGELOG.md", "w" do |io|
io.puts <<-HISTORY_TXT
-# #{Gem::VERSION} / 2013-03-26
+# Changelog
+
+## #{Gem::VERSION} / 2013-03-26
-## Bug fixes:
+### Bug fixes:
* Fixed release note display for LANG=C when installing rubygems
* π is tasty
-# 2.0.2 / 2013-03-06
+## 2.0.2 / 2013-03-06
-## Bug fixes:
+### Bug fixes:
* Other bugs fixed
-# 2.0.1 / 2013-03-05
+## 2.0.1 / 2013-03-05
-## Bug fixes:
+### Bug fixes:
* Yet more bugs fixed
HISTORY_TXT
end
@@ -403,9 +402,9 @@ class TestGemCommandsSetupCommand < Gem::TestCase
end
expected = <<-EXPECTED
-# #{Gem::VERSION} / 2013-03-26
+## #{Gem::VERSION} / 2013-03-26
-## Bug fixes:
+### Bug fixes:
* Fixed release note display for LANG=C when installing rubygems
* π is tasty
diff --git a/test/rubygems/test_gem_commands_signin_command.rb b/test/rubygems/test_gem_commands_signin_command.rb
index 29e5edceb7..e612288faf 100644
--- a/test/rubygems/test_gem_commands_signin_command.rb
+++ b/test/rubygems/test_gem_commands_signin_command.rb
@@ -121,7 +121,7 @@ class TestGemCommandsSigninCommand < Gem::TestCase
assert_match "The default access scope is:", key_name_ui.output
assert_match "index_rubygems: y", key_name_ui.output
assert_match "Do you want to customise scopes? [yN]", key_name_ui.output
- assert_equal "name=test-key&index_rubygems=true", fetcher.last_request.body
+ assert_equal "name=test-key&index_rubygems=true&push_rubygem=true", fetcher.last_request.body
credentials = load_yaml_file Gem.configuration.credentials_path
assert_equal api_key, credentials[:rubygems_api_key]
diff --git a/test/rubygems/test_gem_commands_sources_command.rb b/test/rubygems/test_gem_commands_sources_command.rb
index 5e675e5c84..71c6d5ce16 100644
--- a/test/rubygems/test_gem_commands_sources_command.rb
+++ b/test/rubygems/test_gem_commands_sources_command.rb
@@ -32,7 +32,7 @@ class TestGemCommandsSourcesCommand < Gem::TestCase
end
expected = <<-EOF
-*** CURRENT SOURCES ***
+*** NO CONFIGURED SOURCES, DEFAULT SOURCES LISTED BELOW ***
#{@gem_repo}
EOF
@@ -42,23 +42,104 @@ class TestGemCommandsSourcesCommand < Gem::TestCase
end
def test_execute_add
- spec_fetcher do |fetcher|
- fetcher.spec "a", 1
+ setup_fake_source(@new_repo)
+
+ @cmd.handle_options %W[--add #{@new_repo}]
+
+ use_ui @ui do
+ @cmd.execute
end
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
+ assert_equal [@gem_repo, @new_repo], Gem.sources
+
+ expected = <<-EOF
+#{@new_repo} added to sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_add_without_trailing_slash
+ setup_fake_source("https://rubygems.pkg.github.com/my-org")
+
+ @cmd.handle_options %W[--add https://rubygems.pkg.github.com/my-org]
+
+ use_ui @ui do
+ @cmd.execute
end
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap specs_dump_gz do |io|
- Marshal.dump specs, io
+ assert_equal [@gem_repo, "https://rubygems.pkg.github.com/my-org/"], Gem.sources
+
+ expected = <<-EOF
+https://rubygems.pkg.github.com/my-org/ added to sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_add_multiple_trailing_slash
+ setup_fake_source("https://rubygems.pkg.github.com/my-org/")
+
+ @cmd.handle_options %W[--add https://rubygems.pkg.github.com/my-org///]
+
+ use_ui @ui do
+ @cmd.execute
end
- @fetcher.data["#{@new_repo}/specs.#{@marshal_version}.gz"] =
- specs_dump_gz.string
+ assert_equal [@gem_repo, "https://rubygems.pkg.github.com/my-org/"], Gem.sources
- @cmd.handle_options %W[--add #{@new_repo}]
+ expected = <<-EOF
+https://rubygems.pkg.github.com/my-org/ added to sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_append_without_trailing_slash
+ setup_fake_source("https://rubygems.pkg.github.com/my-org")
+
+ @cmd.handle_options %W[--append https://rubygems.pkg.github.com/my-org]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ assert_equal [@gem_repo, "https://rubygems.pkg.github.com/my-org/"], Gem.sources
+
+ expected = <<-EOF
+https://rubygems.pkg.github.com/my-org/ added to sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_prepend_without_trailing_slash
+ setup_fake_source("https://rubygems.pkg.github.com/my-org")
+
+ @cmd.handle_options %W[--prepend https://rubygems.pkg.github.com/my-org]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ assert_equal ["https://rubygems.pkg.github.com/my-org/", @gem_repo], Gem.sources
+
+ expected = <<-EOF
+https://rubygems.pkg.github.com/my-org/ added to sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_append
+ setup_fake_source(@new_repo)
+
+ @cmd.handle_options %W[--append #{@new_repo}]
use_ui @ui do
@cmd.execute
@@ -77,21 +158,31 @@ class TestGemCommandsSourcesCommand < Gem::TestCase
def test_execute_add_allow_typo_squatting_source
rubygems_org = "https://rubyems.org"
- spec_fetcher do |fetcher|
- fetcher.spec("a", 1)
- end
+ setup_fake_source(rubygems_org)
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
- end
+ @cmd.handle_options %W[--add #{rubygems_org}]
+ ui = Gem::MockGemUi.new("y")
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap(specs_dump_gz) do |io|
- Marshal.dump(specs, io)
+ use_ui ui do
+ @cmd.execute
end
- @fetcher.data["#{rubygems_org}/specs.#{@marshal_version}.gz"] = specs_dump_gz.string
- @cmd.handle_options %W[--add #{rubygems_org}]
+ expected = "https://rubyems.org is too similar to https://rubygems.org\n\nDo you want to add this source? [yn] https://rubyems.org added to sources\n"
+
+ assert_equal expected, ui.output
+
+ source = Gem::Source.new(rubygems_org)
+ assert Gem.sources.include?(source)
+
+ assert_empty ui.error
+ end
+
+ def test_execute_append_allow_typo_squatting_source
+ rubygems_org = "https://rubyems.org"
+
+ setup_fake_source(rubygems_org)
+
+ @cmd.handle_options %W[--append #{rubygems_org}]
ui = Gem::MockGemUi.new("y")
use_ui ui do
@@ -111,21 +202,27 @@ class TestGemCommandsSourcesCommand < Gem::TestCase
def test_execute_add_allow_typo_squatting_source_forced
rubygems_org = "https://rubyems.org"
- spec_fetcher do |fetcher|
- fetcher.spec("a", 1)
- end
+ setup_fake_source(rubygems_org)
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
- end
+ @cmd.handle_options %W[--force --add #{rubygems_org}]
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap(specs_dump_gz) do |io|
- Marshal.dump(specs, io)
- end
+ @cmd.execute
- @fetcher.data["#{rubygems_org}/specs.#{@marshal_version}.gz"] = specs_dump_gz.string
- @cmd.handle_options %W[--force --add #{rubygems_org}]
+ expected = "https://rubyems.org added to sources\n"
+ assert_equal expected, ui.output
+
+ source = Gem::Source.new(rubygems_org)
+ assert Gem.sources.include?(source)
+
+ assert_empty ui.error
+ end
+
+ def test_execute_append_allow_typo_squatting_source_forced
+ rubygems_org = "https://rubyems.org"
+
+ setup_fake_source(rubygems_org)
+
+ @cmd.handle_options %W[--force --append #{rubygems_org}]
@cmd.execute
@@ -141,23 +238,34 @@ class TestGemCommandsSourcesCommand < Gem::TestCase
def test_execute_add_deny_typo_squatting_source
rubygems_org = "https://rubyems.org"
- spec_fetcher do |fetcher|
- fetcher.spec("a", 1)
- end
+ setup_fake_source(rubygems_org)
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
- end
+ @cmd.handle_options %W[--add #{rubygems_org}]
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap(specs_dump_gz) do |io|
- Marshal.dump(specs, io)
+ ui = Gem::MockGemUi.new("n")
+
+ use_ui ui do
+ assert_raise Gem::MockGemUi::TermError do
+ @cmd.execute
+ end
end
- @fetcher.data["#{rubygems_org}/specs.#{@marshal_version}.gz"] =
- specs_dump_gz.string
+ expected = "https://rubyems.org is too similar to https://rubygems.org\n\nDo you want to add this source? [yn] "
- @cmd.handle_options %W[--add #{rubygems_org}]
+ assert_equal expected, ui.output
+
+ source = Gem::Source.new(rubygems_org)
+ refute Gem.sources.include?(source)
+
+ assert_empty ui.error
+ end
+
+ def test_execute_append_deny_typo_squatting_source
+ rubygems_org = "https://rubyems.org"
+
+ setup_fake_source(rubygems_org)
+
+ @cmd.handle_options %W[--append #{rubygems_org}]
ui = Gem::MockGemUi.new("n")
@@ -202,6 +310,31 @@ Error fetching http://beta-gems.example.com:
assert_equal "", @ui.error
end
+ def test_execute_append_nonexistent_source
+ spec_fetcher
+
+ uri = "http://beta-gems.example.com/specs.#{@marshal_version}.gz"
+ @fetcher.data[uri] = proc do
+ raise Gem::RemoteFetcher::FetchError.new("it died", uri)
+ end
+
+ @cmd.handle_options %w[--append http://beta-gems.example.com]
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::TermError do
+ @cmd.execute
+ end
+ end
+
+ expected = <<-EOF
+Error fetching http://beta-gems.example.com:
+\tit died (#{uri})
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
def test_execute_add_existent_source_invalid_uri
spec_fetcher
@@ -227,6 +360,31 @@ Error fetching https://u:REDACTED@example.com:
assert_equal "", @ui.error
end
+ def test_execute_append_existent_source_invalid_uri
+ spec_fetcher
+
+ uri = "https://u:p@example.com/specs.#{@marshal_version}.gz"
+
+ @cmd.handle_options %w[--append https://u:p@example.com]
+ @fetcher.data[uri] = proc do
+ raise Gem::RemoteFetcher::FetchError.new("it died", uri)
+ end
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::TermError do
+ @cmd.execute
+ end
+ end
+
+ expected = <<-EOF
+Error fetching https://u:REDACTED@example.com:
+\tit died (https://u:REDACTED@example.com/specs.#{@marshal_version}.gz)
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
def test_execute_add_existent_source_invalid_uri_with_error_by_chance_including_the_uri_password
spec_fetcher
@@ -252,6 +410,31 @@ Error fetching https://u:REDACTED@example.com:
assert_equal "", @ui.error
end
+ def test_execute_append_existent_source_invalid_uri_with_error_by_chance_including_the_uri_password
+ spec_fetcher
+
+ uri = "https://u:secret@example.com/specs.#{@marshal_version}.gz"
+
+ @cmd.handle_options %w[--append https://u:secret@example.com]
+ @fetcher.data[uri] = proc do
+ raise Gem::RemoteFetcher::FetchError.new("it secretly died", uri)
+ end
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::TermError do
+ @cmd.execute
+ end
+ end
+
+ expected = <<-EOF
+Error fetching https://u:REDACTED@example.com:
+\tit secretly died (https://u:REDACTED@example.com/specs.#{@marshal_version}.gz)
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
def test_execute_add_redundant_source
spec_fetcher
@@ -271,27 +454,34 @@ source #{@gem_repo} already present in the cache
assert_equal "", @ui.error
end
- def test_execute_add_redundant_source_trailing_slash
+ def test_execute_append_redundant_source
spec_fetcher
- # Remove pre-existing gem source (w/ slash)
- repo_with_slash = "http://gems.example.com/"
- @cmd.handle_options %W[--remove #{repo_with_slash}]
+ @cmd.handle_options %W[--append #{@gem_repo}]
+
use_ui @ui do
@cmd.execute
end
- source = Gem::Source.new repo_with_slash
- assert_equal false, Gem.sources.include?(source)
+
+ assert_equal [@gem_repo], Gem.sources
expected = <<-EOF
-#{repo_with_slash} removed from sources
+#{@gem_repo} moved to end of sources
EOF
assert_equal expected, @ui.output
assert_equal "", @ui.error
+ end
+
+ def test_execute_add_redundant_source_trailing_slash
+ repo_with_slash = "http://sample.repo/"
+
+ Gem.configuration.sources = [repo_with_slash]
+
+ setup_fake_source(repo_with_slash)
# Re-add pre-existing gem source (w/o slash)
- repo_without_slash = "http://gems.example.com"
+ repo_without_slash = repo_with_slash.delete_suffix("/")
@cmd.handle_options %W[--add #{repo_without_slash}]
use_ui @ui do
@cmd.execute
@@ -300,8 +490,7 @@ source #{@gem_repo} already present in the cache
assert_equal true, Gem.sources.include?(source)
expected = <<-EOF
-http://gems.example.com/ removed from sources
-http://gems.example.com added to sources
+source #{repo_without_slash} already present in the cache
EOF
assert_equal expected, @ui.output
@@ -316,35 +505,46 @@ http://gems.example.com added to sources
assert_equal true, Gem.sources.include?(source)
expected = <<-EOF
-http://gems.example.com/ removed from sources
-http://gems.example.com added to sources
-source http://gems.example.com/ already present in the cache
+source #{repo_without_slash} already present in the cache
+source #{repo_with_slash} already present in the cache
EOF
assert_equal expected, @ui.output
assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
end
def test_execute_add_http_rubygems_org
http_rubygems_org = "http://rubygems.org/"
- spec_fetcher do |fetcher|
- fetcher.spec "a", 1
- end
+ setup_fake_source(http_rubygems_org)
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
- end
+ @cmd.handle_options %W[--add #{http_rubygems_org}]
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap specs_dump_gz do |io|
- Marshal.dump specs, io
+ ui = Gem::MockGemUi.new "n"
+
+ use_ui ui do
+ assert_raise Gem::MockGemUi::TermError do
+ @cmd.execute
+ end
end
- @fetcher.data["#{http_rubygems_org}/specs.#{@marshal_version}.gz"] =
- specs_dump_gz.string
+ assert_equal [@gem_repo], Gem.sources
- @cmd.handle_options %W[--add #{http_rubygems_org}]
+ expected = <<-EXPECTED
+ EXPECTED
+
+ assert_equal expected, @ui.output
+ assert_empty @ui.error
+ end
+
+ def test_execute_append_http_rubygems_org
+ http_rubygems_org = "http://rubygems.org/"
+
+ setup_fake_source(http_rubygems_org)
+
+ @cmd.handle_options %W[--append #{http_rubygems_org}]
ui = Gem::MockGemUi.new "n"
@@ -366,21 +566,27 @@ source http://gems.example.com/ already present in the cache
def test_execute_add_http_rubygems_org_forced
rubygems_org = "http://rubygems.org"
- spec_fetcher do |fetcher|
- fetcher.spec("a", 1)
- end
+ setup_fake_source(rubygems_org)
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
- end
+ @cmd.handle_options %W[--force --add #{rubygems_org}]
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap(specs_dump_gz) do |io|
- Marshal.dump(specs, io)
- end
+ @cmd.execute
- @fetcher.data["#{rubygems_org}/specs.#{@marshal_version}.gz"] = specs_dump_gz.string
- @cmd.handle_options %W[--force --add #{rubygems_org}]
+ expected = "http://rubygems.org added to sources\n"
+ assert_equal expected, ui.output
+
+ source = Gem::Source.new(rubygems_org)
+ assert Gem.sources.include?(source)
+
+ assert_empty ui.error
+ end
+
+ def test_execute_append_http_rubygems_org_forced
+ rubygems_org = "http://rubygems.org"
+
+ setup_fake_source(rubygems_org)
+
+ @cmd.handle_options %W[--force --append #{rubygems_org}]
@cmd.execute
@@ -396,27 +602,68 @@ source http://gems.example.com/ already present in the cache
def test_execute_add_https_rubygems_org
https_rubygems_org = "https://rubygems.org/"
- spec_fetcher do |fetcher|
- fetcher.spec "a", 1
+ setup_fake_source(https_rubygems_org)
+
+ @cmd.handle_options %W[--add #{https_rubygems_org}]
+
+ use_ui @ui do
+ @cmd.execute
end
- specs = Gem::Specification.map do |spec|
- [spec.name, spec.version, spec.original_platform]
+ assert_equal [@gem_repo, https_rubygems_org], Gem.sources
+
+ expected = <<-EXPECTED
+#{https_rubygems_org} added to sources
+ EXPECTED
+
+ assert_equal expected, @ui.output
+ assert_empty @ui.error
+ end
+
+ def test_execute_append_https_rubygems_org
+ https_rubygems_org = "https://rubygems.org/"
+
+ setup_fake_source(https_rubygems_org)
+
+ @cmd.handle_options %W[--append #{https_rubygems_org}]
+
+ use_ui @ui do
+ @cmd.execute
end
- specs_dump_gz = StringIO.new
- Zlib::GzipWriter.wrap specs_dump_gz do |io|
- Marshal.dump specs, io
+ assert_equal [@gem_repo, https_rubygems_org], Gem.sources
+
+ expected = <<-EXPECTED
+#{https_rubygems_org} added to sources
+ EXPECTED
+
+ assert_equal expected, @ui.output
+ assert_empty @ui.error
+ end
+
+ def test_execute_add_bad_uri
+ @cmd.handle_options %w[--add beta-gems.example.com]
+
+ use_ui @ui do
+ assert_raise Gem::MockGemUi::TermError do
+ @cmd.execute
+ end
end
- @fetcher.data["#{https_rubygems_org}/specs.#{@marshal_version}.gz"] =
- specs_dump_gz.string
+ assert_equal [@gem_repo], Gem.sources
- @cmd.handle_options %W[--add #{https_rubygems_org}]
+ expected = <<-EOF
+beta-gems.example.com/ is not a URI
+ EOF
- ui = Gem::MockGemUi.new "n"
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
- use_ui ui do
+ def test_execute_append_bad_uri
+ @cmd.handle_options %w[--append beta-gems.example.com]
+
+ use_ui @ui do
assert_raise Gem::MockGemUi::TermError do
@cmd.execute
end
@@ -424,15 +671,16 @@ source http://gems.example.com/ already present in the cache
assert_equal [@gem_repo], Gem.sources
- expected = <<-EXPECTED
- EXPECTED
+ expected = <<-EOF
+beta-gems.example.com/ is not a URI
+ EOF
assert_equal expected, @ui.output
- assert_empty @ui.error
+ assert_equal "", @ui.error
end
- def test_execute_add_bad_uri
- @cmd.handle_options %w[--add beta-gems.example.com]
+ def test_execute_prepend_bad_uri
+ @cmd.handle_options %w[--prepend beta-gems.example.com]
use_ui @ui do
assert_raise Gem::MockGemUi::TermError do
@@ -443,7 +691,7 @@ source http://gems.example.com/ already present in the cache
assert_equal [@gem_repo], Gem.sources
expected = <<-EOF
-beta-gems.example.com is not a URI
+beta-gems.example.com/ is not a URI
EOF
assert_equal expected, @ui.output
@@ -476,7 +724,7 @@ beta-gems.example.com is not a URI
end
expected = <<-EOF
-*** CURRENT SOURCES ***
+*** NO CONFIGURED SOURCES, DEFAULT SOURCES LISTED BELOW ***
#{@gem_repo}
EOF
@@ -486,24 +734,32 @@ beta-gems.example.com is not a URI
end
def test_execute_remove
- @cmd.handle_options %W[--remove #{@gem_repo}]
+ Gem.configuration.sources = [@new_repo]
+
+ setup_fake_source(@new_repo)
+
+ @cmd.handle_options %W[--remove #{@new_repo}]
use_ui @ui do
@cmd.execute
end
- expected = "#{@gem_repo} removed from sources\n"
+ expected = "#{@new_repo} removed from sources\n"
assert_equal expected, @ui.output
assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
end
def test_execute_remove_no_network
+ Gem.configuration.sources = [@new_repo]
+
spec_fetcher
- @cmd.handle_options %W[--remove #{@gem_repo}]
+ @cmd.handle_options %W[--remove #{@new_repo}]
- @fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
+ @fetcher.data["#{@new_repo}Marshal.#{Gem.marshal_version}"] = proc do
raise Gem::RemoteFetcher::FetchError
end
@@ -511,10 +767,129 @@ beta-gems.example.com is not a URI
@cmd.execute
end
+ expected = "#{@new_repo} removed from sources\n"
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
+ end
+
+ def test_execute_remove_not_present
+ Gem.configuration.sources = ["https://other.repo"]
+
+ @cmd.handle_options %W[--remove #{@new_repo}]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ expected = "source #{@new_repo} cannot be removed because it's not present in #{Gem.configuration.config_file_name}\n"
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
+ end
+
+ def test_execute_remove_nothing_configured
+ spec_fetcher
+
+ @cmd.handle_options %W[--remove https://does.not.exist]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ expected = "source https://does.not.exist cannot be removed because there are no configured sources in #{Gem.configuration.config_file_name}\n"
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_remove_default_also_present_in_configuration
+ Gem.configuration.sources = [@gem_repo]
+
+ @cmd.handle_options %W[--remove #{@gem_repo}]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ expected = "WARNING: Removing a default source when it is the only source has no effect. Add a different source to #{Gem.configuration.config_file_name} if you want to stop using it as a source.\n"
+
+ assert_equal "", @ui.output
+ assert_equal expected, @ui.error
+ ensure
+ Gem.configuration.sources = nil
+ end
+
+ def test_remove_default_also_present_in_configuration_when_there_are_more_configured_sources
+ Gem.configuration.sources = [@gem_repo, "https://other.repo"]
+
+ @cmd.handle_options %W[--remove #{@gem_repo}]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
expected = "#{@gem_repo} removed from sources\n"
assert_equal expected, @ui.output
assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
+ end
+
+ def test_execute_remove_redundant_source_trailing_slash
+ repo_with_slash = "http://sample.repo/"
+
+ Gem.configuration.sources = [repo_with_slash]
+
+ setup_fake_source(repo_with_slash)
+
+ repo_without_slash = repo_with_slash.delete_suffix("/")
+
+ @cmd.handle_options %W[--remove #{repo_without_slash}]
+ use_ui @ui do
+ @cmd.execute
+ end
+ source = Gem::Source.new repo_without_slash
+ assert_equal false, Gem.sources.include?(source)
+
+ expected = <<-EOF
+#{repo_without_slash} removed from sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
+ end
+
+ def test_execute_remove_without_trailing_slash
+ source_uri = "https://rubygems.pkg.github.com/my-org/"
+
+ Gem.configuration.sources = [source_uri]
+
+ setup_fake_source(source_uri)
+
+ @cmd.handle_options %W[--remove https://rubygems.pkg.github.com/my-org]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ assert_equal [], Gem.sources
+
+ expected = <<-EOF
+#{source_uri} removed from sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ ensure
+ Gem.configuration.sources = nil
end
def test_execute_update
@@ -531,4 +906,102 @@ beta-gems.example.com is not a URI
assert_equal "source cache successfully updated\n", @ui.output
assert_equal "", @ui.error
end
+
+ def test_execute_prepend_new_source
+ setup_fake_source(@new_repo)
+
+ @cmd.handle_options %W[--prepend #{@new_repo}]
+
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ assert_equal [@new_repo, @gem_repo], Gem.sources
+
+ expected = <<-EOF
+#{@new_repo} added to sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_prepend_existing_source
+ setup_fake_source(@new_repo)
+
+ # Append the source normally first
+ @cmd.handle_options %W[--append #{@new_repo}]
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ # Initial state: [@gem_repo, @new_repo]
+ assert_equal [@gem_repo, @new_repo], Gem.sources
+
+ # Now prepend the existing source
+ @cmd.handle_options %W[--prepend #{@new_repo}]
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ # Should be moved to front: [@new_repo, @gem_repo]
+ assert_equal [@new_repo, @gem_repo], Gem.sources
+
+ expected = <<-EOF
+#{@new_repo} added to sources
+#{@new_repo} moved to top of sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ def test_execute_append_existing_source
+ setup_fake_source(@new_repo)
+
+ # Prepend the source first so it's at the beginning
+ @cmd.handle_options %W[--prepend #{@new_repo}]
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ # Initial state: [@new_repo, @gem_repo] (new_repo is first)
+ assert_equal [@new_repo, @gem_repo], Gem.sources
+
+ # Now append the existing source
+ @cmd.handle_options %W[--append #{@new_repo}]
+ use_ui @ui do
+ @cmd.execute
+ end
+
+ # Should be moved to end: [@gem_repo, @new_repo]
+ assert_equal [@gem_repo, @new_repo], Gem.sources
+
+ expected = <<-EOF
+#{@new_repo} added to sources
+#{@new_repo} moved to end of sources
+ EOF
+
+ assert_equal expected, @ui.output
+ assert_equal "", @ui.error
+ end
+
+ private
+
+ def setup_fake_source(uri)
+ spec_fetcher do |fetcher|
+ fetcher.spec "a", 1
+ end
+
+ specs = Gem::Specification.map do |spec|
+ [spec.name, spec.version, spec.original_platform]
+ end
+
+ specs_dump_gz = StringIO.new
+ Zlib::GzipWriter.wrap specs_dump_gz do |io|
+ Marshal.dump specs, io
+ end
+
+ @fetcher.data["#{uri.chomp("/")}/specs.#{@marshal_version}.gz"] = specs_dump_gz.string
+ end
end
diff --git a/test/rubygems/test_gem_commands_uninstall_command.rb b/test/rubygems/test_gem_commands_uninstall_command.rb
index 32553d1730..71ceb22ce5 100644
--- a/test/rubygems/test_gem_commands_uninstall_command.rb
+++ b/test/rubygems/test_gem_commands_uninstall_command.rb
@@ -513,7 +513,7 @@ WARNING: Use your OS package manager to uninstall vendor gems
end
msg = "ERROR: Can't use --version with multiple gems. You can specify multiple gems with" \
- " version requirements using `gem uninstall 'my_gem:1.0.0' 'my_other_gem:~>2.0.0'`"
+ " version requirements using `gem uninstall 'my_gem:1.0.0' 'my_other_gem:>=2'`"
assert_empty @ui.output
assert_equal msg, @ui.error.lines.last.chomp
diff --git a/test/rubygems/test_gem_commands_update_command.rb b/test/rubygems/test_gem_commands_update_command.rb
index 3b106e4581..5ed12ad481 100644
--- a/test/rubygems/test_gem_commands_update_command.rb
+++ b/test/rubygems/test_gem_commands_update_command.rb
@@ -696,6 +696,38 @@ class TestGemCommandsUpdateCommand < Gem::TestCase
assert_equal expected, @cmd.fetch_remote_gems(specs["a-1"])
end
+ def test_pass_down_the_job_option_to_make
+ gemspec = nil
+
+ spec_fetcher do |fetcher|
+ fetcher.download "a", 3 do |spec|
+ gemspec = spec
+
+ extconf_path = "#{spec.gem_dir}/extconf.rb"
+
+ write_file(extconf_path) do |io|
+ io.puts "require 'mkmf'"
+ io.puts "create_makefile '#{spec.name}'"
+ end
+
+ spec.extensions = "extconf.rb"
+ end
+
+ fetcher.gem "a", 2
+ end
+
+ use_ui @ui do
+ @cmd.invoke("a", "-j2")
+ end
+
+ gem_make_out = File.read(File.join(gemspec.extension_dir, "gem_make.out"))
+ if vc_windows? && nmake_found?
+ refute_includes(gem_make_out, " -j2")
+ else
+ assert_includes(gem_make_out, "make -j2")
+ end
+ end
+
def test_handle_options_system
@cmd.handle_options %w[--system]
diff --git a/test/rubygems/test_gem_commands_which_command.rb b/test/rubygems/test_gem_commands_which_command.rb
index cbd5b5ef14..e114d6e689 100644
--- a/test/rubygems/test_gem_commands_which_command.rb
+++ b/test/rubygems/test_gem_commands_which_command.rb
@@ -38,8 +38,6 @@ class TestGemCommandsWhichCommand < Gem::TestCase
end
def test_execute_one_missing
- # TODO: this test fails in isolation
-
util_foo_bar
@cmd.handle_options %w[foo_bar missinglib]
diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb
index eb78e3a542..457a0e65c8 100644
--- a/test/rubygems/test_gem_commands_yank_command.rb
+++ b/test/rubygems/test_gem_commands_yank_command.rb
@@ -131,15 +131,17 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match "Successfully yanked", @ui.output
end
def test_with_webauthn_enabled_failure
+ pend "Flaky on TruffleRuby" if RUBY_ENGINE == "truffleruby"
server = Gem::MockTCPServer.new
error = Gem::WebauthnVerificationError.new("Something went wrong")
@@ -163,9 +165,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
refute_match "Successfully yanked", @ui.output
@@ -189,9 +192,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match "Successfully yanked", @ui.output
@@ -219,9 +223,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -267,7 +272,7 @@ class TestGemCommandsYankCommand < Gem::TestCase
assert_equal [yank_uri], @fetcher.paths
end
- def test_yank_gem_unathorized_api_key
+ def test_yank_gem_unauthorized_api_key
response_forbidden = "The API key doesn't have access"
response_success = "Successfully yanked"
host = "http://example"
diff --git a/test/rubygems/test_gem_config_file.rb b/test/rubygems/test_gem_config_file.rb
index 4230eda4d3..3c79cb0762 100644
--- a/test/rubygems/test_gem_config_file.rb
+++ b/test/rubygems/test_gem_config_file.rb
@@ -43,6 +43,7 @@ class TestGemConfigFile < Gem::TestCase
assert_equal [@gem_repo], Gem.sources
assert_equal 365, @cfg.cert_expiration_length_days
assert_equal false, @cfg.ipv4_fallback_enabled
+ assert_equal true, @cfg.install_extension_in_lib
File.open @temp_conf, "w" do |fp|
fp.puts ":backtrace: true"
@@ -52,14 +53,16 @@ class TestGemConfigFile < Gem::TestCase
fp.puts ":sources:"
fp.puts " - http://more-gems.example.com"
fp.puts "install: --wrappers"
+ fp.puts ":gemhome: /tmp/gems"
fp.puts ":gempath:"
fp.puts "- /usr/ruby/1.8/lib/ruby/gems/1.8"
fp.puts "- /var/ruby/1.8/gem_home"
fp.puts ":ssl_verify_mode: 0"
fp.puts ":ssl_ca_cert: /etc/ssl/certs"
fp.puts ":cert_expiration_length_days: 28"
- fp.puts ":install_extension_in_lib: true"
+ fp.puts ":install_extension_in_lib: false"
fp.puts ":ipv4_fallback_enabled: true"
+ fp.puts ":use_psych: true"
end
util_config_file
@@ -69,13 +72,15 @@ class TestGemConfigFile < Gem::TestCase
assert_equal false, @cfg.update_sources
assert_equal %w[http://more-gems.example.com], @cfg.sources
assert_equal "--wrappers", @cfg[:install]
+ assert_equal "/tmp/gems", @cfg.home
assert_equal(["/usr/ruby/1.8/lib/ruby/gems/1.8", "/var/ruby/1.8/gem_home"],
@cfg.path)
assert_equal 0, @cfg.ssl_verify_mode
assert_equal "/etc/ssl/certs", @cfg.ssl_ca_cert
assert_equal 28, @cfg.cert_expiration_length_days
- assert_equal true, @cfg.install_extension_in_lib
+ assert_equal false, @cfg.install_extension_in_lib
assert_equal true, @cfg.ipv4_fallback_enabled
+ assert_equal true, @cfg.use_psych
end
def test_initialize_ipv4_fallback_enabled_env
@@ -83,6 +88,53 @@ class TestGemConfigFile < Gem::TestCase
util_config_file %W[--config-file #{@temp_conf}]
assert_equal true, @cfg.ipv4_fallback_enabled
+ ensure
+ ENV.delete("IPV4_FALLBACK_ENABLED")
+ end
+
+ def test_initialize_global_gem_cache_default
+ util_config_file %W[--config-file #{@temp_conf}]
+
+ assert_equal false, @cfg.global_gem_cache
+ end
+
+ def test_initialize_global_gem_cache_env
+ ENV["RUBYGEMS_GLOBAL_GEM_CACHE"] = "true"
+ util_config_file %W[--config-file #{@temp_conf}]
+
+ assert_equal true, @cfg.global_gem_cache
+ ensure
+ ENV.delete("RUBYGEMS_GLOBAL_GEM_CACHE")
+ end
+
+ def test_initialize_global_gem_cache_gemrc
+ File.open @temp_conf, "w" do |fp|
+ fp.puts ":global_gem_cache: true"
+ end
+
+ util_config_file %W[--config-file #{@temp_conf}]
+
+ assert_equal true, @cfg.global_gem_cache
+ end
+
+ def test_initialize_use_psych_env
+ orig_use_psych = ENV["RUBYGEMS_USE_PSYCH"]
+ ENV["RUBYGEMS_USE_PSYCH"] = "true"
+ util_config_file %W[--config-file #{@temp_conf}]
+
+ assert_equal true, @cfg.use_psych
+ ensure
+ ENV["RUBYGEMS_USE_PSYCH"] = orig_use_psych
+ end
+
+ def test_initialize_concurrent_downloads
+ File.open @temp_conf, "w" do |fp|
+ fp.puts ":concurrent_downloads: 2"
+ end
+
+ util_config_file %W[--config-file #{@temp_conf}]
+
+ assert_equal 2, @cfg.concurrent_downloads
end
def test_initialize_handle_arguments_config_file
diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb
index 56b84160c4..c2fb6f264b 100644
--- a/test/rubygems/test_gem_dependency_installer.rb
+++ b/test/rubygems/test_gem_dependency_installer.rb
@@ -382,13 +382,9 @@ class TestGemDependencyInstaller < Gem::TestCase
FileUtils.mv f1_gem, @tempdir
inst = nil
- pwd = Dir.getwd
- Dir.chdir @tempdir
- begin
+ Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new
inst.install "f"
- ensure
- Dir.chdir pwd
end
assert_equal %w[f-1], inst.installed_gems.map(&:full_name)
@@ -523,6 +519,58 @@ class TestGemDependencyInstaller < Gem::TestCase
assert_equal %w[a-1], inst.installed_gems.map(&:full_name)
end
+ def test_install_local_with_extensions_already_installed
+ pend "needs investigation" if Gem.java_platform?
+ pend "ruby.h is not provided by ruby repo" if ruby_repo?
+
+ @spec = quick_gem "a" do |s|
+ s.extensions << "extconf.rb"
+ s.files += %w[extconf.rb a.c]
+ end
+
+ write_dummy_extconf "a"
+
+ c_source_path = File.join(@tempdir, "a.c")
+
+ write_file c_source_path do |io|
+ io.write <<-C
+ #include <ruby.h>
+ void Init_a() { }
+ C
+ end
+
+ package_path = Gem::Package.build @spec
+ installer = Gem::Installer.at(package_path)
+
+ # Make sure the gem is installed and backup the correct package
+
+ installer.install
+
+ package_bkp_path = "#{package_path}.bkp"
+ FileUtils.cp package_path, package_bkp_path
+
+ # Break the extension, rebuild it, and try to install it
+
+ write_file c_source_path do |io|
+ io.write "typo"
+ end
+
+ Gem::Package.build @spec
+
+ assert_raise Gem::Ext::BuildError do
+ installer.install
+ end
+
+ # Make sure installing the good package again still works
+
+ FileUtils.cp "#{package_path}.bkp", package_path
+
+ Dir.chdir @tempdir do
+ inst = Gem::DependencyInstaller.new domain: :local
+ inst.install package_path
+ end
+ end
+
def test_install_minimal_deps
util_setup_gems
@@ -629,8 +677,7 @@ class TestGemDependencyInstaller < Gem::TestCase
util_setup_gems
FileUtils.mv @b1_gem, @tempdir
- si = util_setup_spec_fetcher @b1
- @fetcher.data["http://gems.example.com/gems/yaml"] = si.to_yaml
+ util_setup_spec_fetcher @b1
inst = nil
Dir.chdir @tempdir do
@@ -641,6 +688,25 @@ class TestGemDependencyInstaller < Gem::TestCase
assert_equal %w[b-1], inst.installed_gems.map(&:full_name)
end
+ def test_install_force_with_unsatisfiable_dep
+ # foo depends on bar >= 2.0, but only bar-1.0 exists.
+ # With --force, the unsatisfiable dep should be skipped.
+ _, foo_gem = util_gem "foo", "1" do |s|
+ s.add_dependency "bar", ">= 2.0"
+ end
+
+ util_setup_spec_fetcher(util_spec("bar", "1.0"))
+ FileUtils.mv foo_gem, @tempdir
+ inst = nil
+
+ Dir.chdir @tempdir do
+ inst = Gem::DependencyInstaller.new force: true
+ inst.install "foo"
+ end
+
+ assert_equal %w[foo-1], inst.installed_gems.map(&:full_name)
+ end
+
def test_install_build_args
util_setup_gems
@@ -746,13 +812,12 @@ class TestGemDependencyInstaller < Gem::TestCase
inst = nil
Dir.chdir @tempdir do
- e = assert_raise Gem::UnsatisfiableDependencyError do
+ e = assert_raise Gem::DependencyResolutionError do
inst = Gem::DependencyInstaller.new domain: :local
inst.install "b"
end
- expected = "Unable to resolve dependency: 'b (>= 0)' requires 'a (>= 0)'"
- assert_equal expected, e.message
+ assert_match(/depends on a >= 0 which could not be found in any repository/, e.message)
end
assert_equal [], inst.installed_gems.map(&:full_name)
@@ -907,9 +972,7 @@ class TestGemDependencyInstaller < Gem::TestCase
s.platform = Gem::Platform.new %w[cpu other_platform 1]
end
- si = util_setup_spec_fetcher @a1, a2_o
-
- @fetcher.data["http://gems.example.com/gems/yaml"] = si.to_yaml
+ util_setup_spec_fetcher @a1, a2_o
a1_data = nil
a2_o_data = nil
@@ -1066,117 +1129,6 @@ class TestGemDependencyInstaller < Gem::TestCase
assert_equal %w[activesupport-1.0.0], Gem::Specification.map(&:full_name)
end
- def test_find_gems_gems_with_sources
- util_setup_gems
-
- inst = Gem::DependencyInstaller.new
- dep = Gem::Dependency.new "b", ">= 0"
-
- Gem::Specification.reset
-
- set = Gem::Deprecate.skip_during do
- inst.find_gems_with_sources(dep)
- end
-
- assert_kind_of Gem::AvailableSet, set
-
- s = set.set.first
-
- assert_equal @b1, s.spec
- assert_equal Gem::Source.new(@gem_repo), s.source
- end
-
- def test_find_gems_with_sources_local
- util_setup_gems
-
- FileUtils.mv @a1_gem, @tempdir
- inst = Gem::DependencyInstaller.new
- dep = Gem::Dependency.new "a", ">= 0"
- set = nil
-
- Dir.chdir @tempdir do
- set = Gem::Deprecate.skip_during do
- inst.find_gems_with_sources dep
- end
- end
-
- gems = set.sorted
-
- assert_equal 2, gems.length
-
- remote, local = gems
-
- assert_equal "a-1", local.spec.full_name, "local spec"
- assert_equal File.join(@tempdir, @a1.file_name),
- local.source.download(local.spec), "local path"
-
- assert_equal "a-1", remote.spec.full_name, "remote spec"
- assert_equal Gem::Source.new(@gem_repo), remote.source, "remote path"
- end
-
- def test_find_gems_with_sources_prerelease
- util_setup_gems
-
- installer = Gem::DependencyInstaller.new
-
- dependency = Gem::Dependency.new("a", Gem::Requirement.default)
-
- set = Gem::Deprecate.skip_during do
- installer.find_gems_with_sources(dependency)
- end
-
- releases = set.all_specs
-
- assert releases.any? {|s| s.name == "a" && s.version.to_s == "1" }
- refute releases.any? {|s| s.name == "a" && s.version.to_s == "1.a" }
-
- dependency.prerelease = true
-
- set = Gem::Deprecate.skip_during do
- installer.find_gems_with_sources(dependency)
- end
-
- prereleases = set.all_specs
-
- assert_equal [@a1_pre, @a1], prereleases
- end
-
- def test_find_gems_with_sources_with_best_only_and_platform
- util_setup_gems
- a1_x86_mingw32, = util_gem "a", "1" do |s|
- s.platform = "x86-mingw32"
- end
- util_setup_spec_fetcher @a1, a1_x86_mingw32
- Gem.platforms << Gem::Platform.new("x86-mingw32")
-
- installer = Gem::DependencyInstaller.new
-
- dependency = Gem::Dependency.new("a", Gem::Requirement.default)
-
- set = Gem::Deprecate.skip_during do
- installer.find_gems_with_sources(dependency, true)
- end
-
- releases = set.all_specs
-
- assert_equal [a1_x86_mingw32], releases
- end
-
- def test_find_gems_with_sources_with_bad_source
- Gem.sources.replace ["http://not-there.nothing"]
-
- installer = Gem::DependencyInstaller.new
-
- dep = Gem::Dependency.new("a")
-
- out = Gem::Deprecate.skip_during do
- installer.find_gems_with_sources(dep)
- end
-
- assert out.empty?
- assert_kind_of Gem::SourceFetchProblem, installer.errors.first
- end
-
def test_resolve_dependencies
util_setup_gems
diff --git a/test/rubygems/test_gem_dependency_resolution_error.rb b/test/rubygems/test_gem_dependency_resolution_error.rb
index 98a6b6b8fd..d8fa96a260 100644
--- a/test/rubygems/test_gem_dependency_resolution_error.rb
+++ b/test/rubygems/test_gem_dependency_resolution_error.rb
@@ -6,20 +6,23 @@ class TestGemDependencyResolutionError < Gem::TestCase
def setup
super
- @spec = util_spec "a", 2
-
- @a1_req = Gem::Resolver::DependencyRequest.new dep("a", "= 1"), nil
- @a2_req = Gem::Resolver::DependencyRequest.new dep("a", "= 2"), nil
+ failure = Struct.new(:explanation).new("a depends on b (= 1.0) but no versions match")
+ @error = Gem::DependencyResolutionError.new failure
+ end
- @activated = Gem::Resolver::ActivationRequest.new @spec, @a2_req
+ def test_message
+ assert_equal "a depends on b (= 1.0) but no versions match", @error.message
+ end
- @conflict = Gem::Resolver::Conflict.new @a1_req, @activated
+ def test_explanation
+ assert_equal "a depends on b (= 1.0) but no versions match", @error.explanation
+ end
- @error = Gem::DependencyResolutionError.new @conflict
+ def test_conflict
+ assert_nil @error.conflict
end
- def test_message
- assert_match(/^conflicting dependencies a \(= 1\) and a \(= 2\)$/,
- @error.message)
+ def test_conflicting_dependencies
+ assert_equal [], @error.conflicting_dependencies
end
end
diff --git a/test/rubygems/test_gem_ext_builder.rb b/test/rubygems/test_gem_ext_builder.rb
index 34f85e6b75..37204f3c47 100644
--- a/test/rubygems/test_gem_ext_builder.rb
+++ b/test/rubygems/test_gem_ext_builder.rb
@@ -18,7 +18,7 @@ class TestGemExtBuilder < Gem::TestCase
@spec = util_spec "a"
- @builder = Gem::Ext::Builder.new @spec, ""
+ @builder = Gem::Ext::Builder.new @spec
end
def teardown
@@ -106,6 +106,22 @@ install:
assert_match(/install: OK/, results)
end
+ def test_class_run_closes_stdin
+ results = []
+ check_stdin_script = <<~'RUBY'
+ if IO.select([STDIN], nil, nil, 1)
+ puts "STDIN: #{STDIN.read.inspect}"
+ else
+ puts "NOT_READY"
+ end
+ RUBY
+
+ Gem::Ext::Builder.run([Gem.ruby, "-e", check_stdin_script], results)
+
+ command_output = results.last
+ assert_equal "STDIN: \"\"\n", command_output
+ end
+
def test_build_extensions
pend "terminates on mswin" if vc_windows? && ruby_repo?
@@ -201,6 +217,57 @@ install:
Gem.configuration.install_extension_in_lib = @orig_install_extension_in_lib
end
+ def test_build_multiple_extensions
+ pend if RUBY_ENGINE == "truffleruby"
+ pend "terminates on ruby/ruby" if ruby_repo?
+
+ extension_in_lib do
+ @spec.extensions << "ext/Rakefile"
+ @spec.extensions << "ext/extconf.rb"
+
+ ext_dir = File.join @spec.gem_dir, "ext"
+
+ FileUtils.mkdir_p ext_dir
+
+ extconf_rb = File.join ext_dir, "extconf.rb"
+ rakefile = File.join ext_dir, "Rakefile"
+
+ File.open extconf_rb, "w" do |f|
+ f.write <<-'RUBY'
+ require 'mkmf'
+
+ create_makefile 'a'
+ RUBY
+ end
+
+ File.open rakefile, "w" do |f|
+ f.write <<-RUBY
+ task :default do
+ FileUtils.touch File.join "#{ext_dir}", 'foo'
+ end
+ RUBY
+ end
+
+ ext_lib_dir = File.join ext_dir, "lib"
+ FileUtils.mkdir ext_lib_dir
+ FileUtils.touch File.join ext_lib_dir, "a.rb"
+ FileUtils.mkdir File.join ext_lib_dir, "a"
+ FileUtils.touch File.join ext_lib_dir, "a", "b.rb"
+
+ use_ui @ui do
+ @builder.build_extensions
+ end
+
+ assert_path_exist @spec.extension_dir
+ assert_path_exist @spec.gem_build_complete_path
+ assert_path_exist File.join @spec.gem_dir, "ext", "foo"
+ assert_path_exist File.join @spec.extension_dir, "gem_make.out"
+ assert_path_exist File.join @spec.extension_dir, "a.rb"
+ assert_path_exist File.join @spec.gem_dir, "lib", "a.rb"
+ assert_path_exist File.join @spec.gem_dir, "lib", "a", "b.rb"
+ end
+ end
+
def test_build_extensions_none
use_ui @ui do
@builder.build_extensions
diff --git a/test/rubygems/test_gem_ext_cargo_builder.rb b/test/rubygems/test_gem_ext_cargo_builder.rb
index 5035937544..b970e442c2 100644
--- a/test/rubygems/test_gem_ext_cargo_builder.rb
+++ b/test/rubygems/test_gem_ext_cargo_builder.rb
@@ -141,6 +141,58 @@ class TestGemExtCargoBuilder < Gem::TestCase
end
end
+ def test_linker_args
+ orig_cc = RbConfig::MAKEFILE_CONFIG["CC"]
+ RbConfig::MAKEFILE_CONFIG["CC"] = "clang"
+
+ builder = Gem::Ext::CargoBuilder.new
+ args = builder.send(:linker_args)
+
+ assert args[1], "linker=clang"
+ assert_nil args[2]
+ ensure
+ RbConfig::MAKEFILE_CONFIG["CC"] = orig_cc
+ end
+
+ def test_linker_args_with_options
+ orig_cc = RbConfig::MAKEFILE_CONFIG["CC"]
+ RbConfig::MAKEFILE_CONFIG["CC"] = "gcc -Wl,--no-undefined"
+
+ builder = Gem::Ext::CargoBuilder.new
+ args = builder.send(:linker_args)
+
+ assert args[1], "linker=clang"
+ assert args[3], "link-args=-Wl,--no-undefined"
+ ensure
+ RbConfig::MAKEFILE_CONFIG["CC"] = orig_cc
+ end
+
+ def test_linker_args_with_cachetools
+ orig_cc = RbConfig::MAKEFILE_CONFIG["CC"]
+ RbConfig::MAKEFILE_CONFIG["CC"] = "sccache clang"
+
+ builder = Gem::Ext::CargoBuilder.new
+ args = builder.send(:linker_args)
+
+ assert args[1], "linker=clang"
+ assert_nil args[2]
+ ensure
+ RbConfig::MAKEFILE_CONFIG["CC"] = orig_cc
+ end
+
+ def test_linker_args_with_cachetools_and_options
+ orig_cc = RbConfig::MAKEFILE_CONFIG["CC"]
+ RbConfig::MAKEFILE_CONFIG["CC"] = "ccache gcc -Wl,--no-undefined"
+
+ builder = Gem::Ext::CargoBuilder.new
+ args = builder.send(:linker_args)
+
+ assert args[1], "linker=clang"
+ assert args[3], "link-args=-Wl,--no-undefined"
+ ensure
+ RbConfig::MAKEFILE_CONFIG["CC"] = orig_cc
+ end
+
private
def skip_unsupported_platforms!
diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock
index f16c0eb140..d6c49c3de1 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock
+++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock
@@ -13,16 +13,14 @@ dependencies = [
[[package]]
name = "bindgen"
-version = "0.69.1"
+version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
- "lazy_static",
- "lazycell",
- "peeking_take_while",
+ "itertools",
"proc-macro2",
"quote",
"regex",
@@ -71,22 +69,31 @@ dependencies = [
]
[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
-name = "lazy_static"
-version = "1.4.0"
+name = "itertools"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
[[package]]
-name = "lazycell"
-version = "1.3.0"
+name = "lazy_static"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
@@ -127,16 +134,10 @@ dependencies = [
]
[[package]]
-name = "peeking_take_while"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
-
-[[package]]
name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
@@ -152,18 +153,18 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.9.111"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "becea799ce051c16fb140be80f5e7cf781070f99ca099332383c2b17861249af"
+checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
-version = "0.9.111"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64691175abc704862f60a9ca8ef06174080cc50615f2bf1d4759f46db18b4d29"
+checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
dependencies = [
"bindgen",
"lazy_static",
@@ -193,9 +194,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustc-hash"
-version = "1.1.0"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]]
name = "shell-words"
diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml
index a66404aa41..056567c708 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml
+++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
-rb-sys = "0.9.111"
+rb-sys = "0.9.128"
diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
index 1230f8ae96..806d51d3a1 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
+++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
@@ -13,16 +13,14 @@ dependencies = [
[[package]]
name = "bindgen"
-version = "0.69.1"
+version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
- "lazy_static",
- "lazycell",
- "peeking_take_while",
+ "itertools",
"proc-macro2",
"quote",
"regex",
@@ -64,22 +62,31 @@ dependencies = [
]
[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
-name = "lazy_static"
-version = "1.4.0"
+name = "itertools"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
[[package]]
-name = "lazycell"
-version = "1.3.0"
+name = "lazy_static"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
@@ -120,16 +127,10 @@ dependencies = [
]
[[package]]
-name = "peeking_take_while"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
-
-[[package]]
name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
@@ -145,18 +146,18 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.9.111"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "becea799ce051c16fb140be80f5e7cf781070f99ca099332383c2b17861249af"
+checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
-version = "0.9.111"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64691175abc704862f60a9ca8ef06174080cc50615f2bf1d4759f46db18b4d29"
+checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
dependencies = [
"bindgen",
"lazy_static",
@@ -193,9 +194,9 @@ dependencies = [
[[package]]
name = "rustc-hash"
-version = "1.1.0"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]]
name = "shell-words"
diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
index 03853fea08..f0ddeeb91c 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
+++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
-rb-sys = "0.9.111"
+rb-sys = "0.9.128"
diff --git a/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb b/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb
index a3fef50d54..3693f63df6 100644
--- a/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb
+++ b/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb
@@ -25,7 +25,7 @@ class TestGemExtCargoBuilderLinkFlagConverter < Gem::TestCase
}.freeze
CASES.each do |test_name, (arg, expected)|
- raise "duplicate test name" if instance_methods.include?(test_name)
+ raise "duplicate test name" if method_defined?(test_name)
define_method(test_name) do
assert_equal(expected, Gem::Ext::CargoBuilder::LinkFlagConverter.convert(arg))
diff --git a/test/rubygems/test_gem_ext_cmake_builder.rb b/test/rubygems/test_gem_ext_cmake_builder.rb
index 5f886af05f..b9b57084d4 100644
--- a/test/rubygems/test_gem_ext_cmake_builder.rb
+++ b/test/rubygems/test_gem_ext_cmake_builder.rb
@@ -7,7 +7,7 @@ class TestGemExtCmakeBuilder < Gem::TestCase
def setup
super
- # Details: https://github.com/rubygems/rubygems/issues/1270#issuecomment-177368340
+ # Details: https://github.com/ruby/rubygems/issues/1270#issuecomment-177368340
pend "CmakeBuilder doesn't work on Windows." if Gem.win_platform?
require "open3"
@@ -29,7 +29,7 @@ class TestGemExtCmakeBuilder < Gem::TestCase
def test_self_build
File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists|
cmakelists.write <<-EO_CMAKE
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 3.26)
project(self_build NONE)
install (FILES test.txt DESTINATION bin)
EO_CMAKE
@@ -39,46 +39,107 @@ install (FILES test.txt DESTINATION bin)
output = []
- Gem::Ext::CmakeBuilder.build nil, @dest_path, output, [], nil, @ext
+ builder = Gem::Ext::CmakeBuilder.new
+ builder.build nil, @dest_path, output, [], @dest_path, @ext
output = output.join "\n"
- assert_match(/^cmake \. -DCMAKE_INSTALL_PREFIX\\=#{Regexp.escape @dest_path}/, output)
+ assert_match(/^current directory: #{Regexp.escape @ext}/, output)
+ assert_match(/cmake.*-DCMAKE_RUNTIME_OUTPUT_DIRECTORY\\=#{Regexp.escape @dest_path}/, output)
+ assert_match(/cmake.*-DCMAKE_LIBRARY_OUTPUT_DIRECTORY\\=#{Regexp.escape @dest_path}/, output)
+ assert_match(/#{Regexp.escape @ext}/, output)
+ end
+
+ def test_self_build_presets
+ File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists|
+ cmakelists.write <<-EO_CMAKE
+cmake_minimum_required(VERSION 3.26)
+project(self_build NONE)
+install (FILES test.txt DESTINATION bin)
+ EO_CMAKE
+ end
+
+ File.open File.join(@ext, "CMakePresets.json"), "w" do |presets|
+ presets.write <<-EO_CMAKE
+{
+ "version": 6,
+ "configurePresets": [
+ {
+ "name": "debug",
+ "displayName": "Debug",
+ "generator": "Ninja",
+ "binaryDir": "build/debug",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug"
+ }
+ },
+ {
+ "name": "release",
+ "displayName": "Release",
+ "generator": "Ninja",
+ "binaryDir": "build/release",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Release"
+ }
+ }
+ ]
+}
+ EO_CMAKE
+ end
+
+ FileUtils.touch File.join(@ext, "test.txt")
+
+ output = []
+
+ builder = Gem::Ext::CmakeBuilder.new
+ builder.build nil, @dest_path, output, [], @dest_path, @ext
+
+ output = output.join "\n"
+
+ assert_match(/The gem author provided a list of presets that can be used to build the gem./, output)
+ assert_match(/Available configure presets/, output)
+ assert_match(/\"debug\" - Debug/, output)
+ assert_match(/\"release\" - Release/, output)
+ assert_match(/^current directory: #{Regexp.escape @ext}/, output)
+ assert_match(/cmake.*-DCMAKE_RUNTIME_OUTPUT_DIRECTORY\\=#{Regexp.escape @dest_path}/, output)
+ assert_match(/cmake.*-DCMAKE_LIBRARY_OUTPUT_DIRECTORY\\=#{Regexp.escape @dest_path}/, output)
assert_match(/#{Regexp.escape @ext}/, output)
- assert_contains_make_command "", output
- assert_contains_make_command "install", output
- assert_match(/test\.txt/, output)
end
def test_self_build_fail
output = []
+ builder = Gem::Ext::CmakeBuilder.new
error = assert_raise Gem::InstallError do
- Gem::Ext::CmakeBuilder.build nil, @dest_path, output, [], nil, @ext
+ builder.build nil, @dest_path, output, [], @dest_path, @ext
end
- output = output.join "\n"
+ assert_match "cmake_configure failed", error.message
shell_error_msg = /(CMake Error: .*)/
-
- assert_match "cmake failed", error.message
-
- assert_match(/^cmake . -DCMAKE_INSTALL_PREFIX\\=#{Regexp.escape @dest_path}/, output)
+ output = output.join "\n"
assert_match(/#{shell_error_msg}/, output)
+ assert_match(/CMake Error: The source directory .* does not appear to contain CMakeLists.txt./, output)
end
def test_self_build_has_makefile
- File.open File.join(@ext, "Makefile"), "w" do |makefile|
- makefile.puts "all:\n\t@echo ok\ninstall:\n\t@echo ok"
+ File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists|
+ cmakelists.write <<-EO_CMAKE
+cmake_minimum_required(VERSION 3.26)
+project(self_build NONE)
+install (FILES test.txt DESTINATION bin)
+ EO_CMAKE
end
output = []
- Gem::Ext::CmakeBuilder.build nil, @dest_path, output, [], nil, @ext
+ builder = Gem::Ext::CmakeBuilder.new
+ builder.build nil, @dest_path, output, [], @dest_path, @ext
output = output.join "\n"
- assert_contains_make_command "", output
- assert_contains_make_command "install", output
+ # The default generator will create a Makefile in the build directory
+ makefile = File.join(@ext, "build", "Makefile")
+ assert(File.exist?(makefile))
end
end
diff --git a/test/rubygems/test_gem_ext_ext_conf_builder.rb b/test/rubygems/test_gem_ext_ext_conf_builder.rb
index 218c6f3d5e..bc383e5540 100644
--- a/test/rubygems/test_gem_ext_ext_conf_builder.rb
+++ b/test/rubygems/test_gem_ext_ext_conf_builder.rb
@@ -15,15 +15,12 @@ class TestGemExtExtConfBuilder < Gem::TestCase
end
def test_class_build
- if Gem.java_platform?
- pend("failing on jruby")
- end
-
if vc_windows? && !nmake_found?
pend("test_class_build skipped - nmake not found")
end
File.open File.join(@ext, "extconf.rb"), "w" do |extconf|
+ extconf.puts "return if Gem.java_platform?"
extconf.puts "require 'mkmf'\ncreate_makefile 'foo'"
end
@@ -35,20 +32,22 @@ class TestGemExtExtConfBuilder < Gem::TestCase
assert_match(/^current directory:/, output[0])
assert_match(/^#{Regexp.quote(Gem.ruby)}.* extconf.rb/, output[1])
- assert_equal "creating Makefile\n", output[2]
- assert_match(/^current directory:/, output[3])
- assert_contains_make_command "clean", output[4]
- assert_contains_make_command "", output[7]
- assert_contains_make_command "install", output[10]
+
+ if Gem.java_platform?
+ assert_includes(output, "Skipping make for extconf.rb as no Makefile was found.")
+ else
+ assert_equal "creating Makefile\n", output[2]
+ assert_match(/^current directory:/, output[3])
+ assert_contains_make_command "clean", output[4]
+ assert_contains_make_command "", output[7]
+ assert_contains_make_command "install", output[10]
+ end
+
assert_empty Dir.glob(File.join(@ext, "siteconf*.rb"))
assert_empty Dir.glob(File.join(@ext, ".gem.*"))
end
def test_class_build_rbconfig_make_prog
- if Gem.java_platform?
- pend("failing on jruby")
- end
-
configure_args do
File.open File.join(@ext, "extconf.rb"), "w" do |extconf|
extconf.puts "require 'mkmf'\ncreate_makefile 'foo'"
@@ -72,10 +71,6 @@ class TestGemExtExtConfBuilder < Gem::TestCase
env_large_make = ENV.delete "MAKE"
ENV["MAKE"] = "anothermake"
- if Gem.java_platform?
- pend("failing on jruby")
- end
-
configure_args "" do
File.open File.join(@ext, "extconf.rb"), "w" do |extconf|
extconf.puts "require 'mkmf'\ncreate_makefile 'foo'"
@@ -206,11 +201,11 @@ end
end
def test_class_make_no_Makefile
- error = assert_raise Gem::InstallError do
+ error = assert_raise Gem::Ext::Builder::NoMakefileError do
Gem::Ext::ExtConfBuilder.make @ext, ["output"], @ext
end
- assert_equal "Makefile not found", error.message
+ assert_match(/No Makefile found/, error.message)
end
def configure_args(args = nil)
diff --git a/test/rubygems/test_gem_ext_rake_builder.rb b/test/rubygems/test_gem_ext_rake_builder.rb
index bd72c1aa08..68ad15b044 100644
--- a/test/rubygems/test_gem_ext_rake_builder.rb
+++ b/test/rubygems/test_gem_ext_rake_builder.rb
@@ -29,7 +29,7 @@ class TestGemExtRakeBuilder < Gem::TestCase
end
end
- # https://github.com/rubygems/rubygems/pull/1819
+ # https://github.com/ruby/rubygems/pull/1819
#
# It should not fail with a non-empty args list either
def test_class_build_with_args
diff --git a/test/rubygems/test_gem_gem_runner.rb b/test/rubygems/test_gem_gem_runner.rb
index 4fb205040c..9cc2fac619 100644
--- a/test/rubygems/test_gem_gem_runner.rb
+++ b/test/rubygems/test_gem_gem_runner.rb
@@ -82,17 +82,6 @@ class TestGemGemRunner < Gem::TestCase
assert_equal %w[--foo], args
end
- def test_query_is_deprecated
- args = %w[query]
-
- use_ui @ui do
- @runner.run(args)
- end
-
- assert_match(/WARNING: query command is deprecated. It will be removed in Rubygems [0-9]+/, @ui.error)
- assert_match(/WARNING: It is recommended that you use `gem search` or `gem list` instead/, @ui.error)
- end
-
def test_info_succeeds
args = %w[info]
diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb
index a3236e6276..ca34c8d03d 100644
--- a/test/rubygems/test_gem_gemcutter_utilities.rb
+++ b/test/rubygems/test_gem_gemcutter_utilities.rb
@@ -150,7 +150,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
util_sign_in
- assert_equal "", @sign_in_ui.output
+ assert_match(/You are already signed in/, @sign_in_ui.output)
end
def test_sign_in_skips_with_key_override
@@ -158,7 +158,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
@cmd.options[:key] = :KEY
util_sign_in
- assert_equal "", @sign_in_ui.output
+ assert_match(/You are already signed in/, @sign_in_ui.output)
end
def test_sign_in_with_other_credentials_doesnt_overwrite_other_keys
@@ -233,9 +233,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
end
@@ -255,9 +256,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
assert_equal 1, error.exit_code
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @sign_in_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
refute_match "Signed in with API key:", @sign_in_ui.output
@@ -273,9 +275,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
util_sign_in
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
end
@@ -292,9 +295,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"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.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "ERROR: Security device verification failed: " \
"The token in the link you used has either expired or been used already.", @sign_in_ui.error
end
diff --git a/test/rubygems/test_gem_impossible_dependencies_error.rb b/test/rubygems/test_gem_impossible_dependencies_error.rb
deleted file mode 100644
index 94c0290ea1..0000000000
--- a/test/rubygems/test_gem_impossible_dependencies_error.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-
-class TestGemImpossibleDependenciesError < Gem::TestCase
- def test_message_conflict
- request = dependency_request dep("net-ssh", ">= 2.0.13"), "rye", "0.9.8"
-
- conflicts = []
-
- # These conflicts are lies as their dependencies does not have the correct
- # requested-by entries, but they are suitable for testing the message.
- # See #485 to construct a correct conflict.
- net_ssh_2_2_2 =
- dependency_request dep("net-ssh", ">= 2.6.5"), "net-ssh", "2.2.2", request
- net_ssh_2_6_5 =
- dependency_request dep("net-ssh", "~> 2.2.2"), "net-ssh", "2.6.5", request
-
- conflict1 = Gem::Resolver::Conflict.new \
- net_ssh_2_6_5, net_ssh_2_6_5.requester
-
- conflict2 = Gem::Resolver::Conflict.new \
- net_ssh_2_2_2, net_ssh_2_2_2.requester
-
- conflicts << [net_ssh_2_6_5.requester.spec, conflict1]
- conflicts << [net_ssh_2_2_2.requester.spec, conflict2]
-
- error = Gem::ImpossibleDependenciesError.new request, conflicts
-
- expected = <<-EXPECTED
-rye-0.9.8 requires net-ssh (>= 2.0.13) but it conflicted:
- Activated net-ssh-2.6.5
- which does not match conflicting dependency (~> 2.2.2)
-
- Conflicting dependency chains:
- rye (= 0.9.8), 0.9.8 activated, depends on
- net-ssh (>= 2.0.13), 2.6.5 activated
-
- versus:
- rye (= 0.9.8), 0.9.8 activated, depends on
- net-ssh (>= 2.0.13), 2.6.5 activated, depends on
- net-ssh (~> 2.2.2)
-
- Activated net-ssh-2.2.2
- which does not match conflicting dependency (>= 2.6.5)
-
- Conflicting dependency chains:
- rye (= 0.9.8), 0.9.8 activated, depends on
- net-ssh (>= 2.0.13), 2.2.2 activated
-
- versus:
- rye (= 0.9.8), 0.9.8 activated, depends on
- net-ssh (>= 2.0.13), 2.2.2 activated, depends on
- net-ssh (>= 2.6.5)
-
- EXPECTED
-
- assert_equal expected, error.message
- end
-end
diff --git a/test/rubygems/test_gem_install_update_options.rb b/test/rubygems/test_gem_install_update_options.rb
index 8fd5d9c543..1e451dcb05 100644
--- a/test/rubygems/test_gem_install_update_options.rb
+++ b/test/rubygems/test_gem_install_update_options.rb
@@ -202,4 +202,16 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase
assert_equal true, @cmd.options[:minimal_deps]
end
+
+ def test_build_jobs_short_version
+ @cmd.handle_options %w[-j 4]
+
+ assert_equal 4, @cmd.options[:build_jobs]
+ end
+
+ def test_build_jobs_long_version
+ @cmd.handle_options %w[--build-jobs 4]
+
+ assert_equal 4, @cmd.options[:build_jobs]
+ end
end
diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb
index 83e43c135f..bf7a4a8dfc 100644
--- a/test/rubygems/test_gem_installer.rb
+++ b/test/rubygems/test_gem_installer.rb
@@ -24,36 +24,35 @@ class TestGemInstaller < Gem::InstallerTestCase
util_make_exec @spec, ""
- expected = <<-EOF
-#!#{Gem.ruby}
-#
-# This file was generated by RubyGems.
-#
-# The application 'a' is installed as part of a gem, and
-# this file is here to facilitate running it.
-#
-
-require 'rubygems'
-
-Gem.use_gemdeps
-
-version = \">= 0.a\"
-
-str = ARGV.first
-if str
- str = str.b[/\\A_(.*)_\\z/, 1]
- if str and Gem::Version.correct?(str)
- version = str
- ARGV.shift
- end
-end
+ expected = <<~EOF
+ #!#{Gem.ruby}
+ #
+ # This file was generated by RubyGems.
+ #
+ # The application 'a' is installed as part of a gem, and
+ # this file is here to facilitate running it.
+ #
+
+ require 'rubygems'
+
+ Gem.use_gemdeps
+
+ version = \">= 0.a\"
+
+ str = ARGV.first
+ if str
+ str = str.b[/\\A_(.*)_\\z/, 1]
+ if str and Gem::Version.correct?(str)
+ version = str
+ ARGV.shift
+ end
+ end
-if Gem.respond_to?(:activate_bin_path)
-load Gem.activate_bin_path('a', 'executable', version)
-else
-gem "a", version
-load Gem.bin_path("a", "executable", version)
-end
+ if Gem.respond_to?(:activate_and_load_bin_path)
+ Gem.activate_and_load_bin_path('a', 'executable', version)
+ else
+ load Gem.activate_bin_path('a', 'executable', version)
+ end
EOF
wrapper = installer.app_script_text "executable"
@@ -121,12 +120,12 @@ end
end
File.open File.join(util_inst_bindir, "executable"), "w" do |io|
- io.write <<-EXEC
-#!/usr/local/bin/ruby
-#
-# This file was generated by RubyGems
+ io.write <<~EXEC
+ #!/usr/local/bin/ruby
+ #
+ # This file was generated by RubyGems
-gem 'other', version
+ gem 'other', version
EXEC
end
@@ -690,8 +689,11 @@ gem 'other', version
def test_generate_bin_symlink_win32
old_win_platform = Gem.win_platform?
- Gem.win_platform = true
old_alt_separator = File::ALT_SEPARATOR
+
+ omit "JRuby on Windows still creates the symlink so the wrapper branch is not exercised" if Gem.win_platform? && Gem.java_platform?
+
+ Gem.win_platform = true
File.__send__(:remove_const, :ALT_SEPARATOR)
File.const_set(:ALT_SEPARATOR, "\\")
@@ -744,6 +746,8 @@ gem 'other', version
end
def test_generate_bin_with_dangling_symlink
+ omit "JRuby on Windows still creates the symlink so the wrapper branch is not exercised" if Gem.win_platform? && Gem.java_platform?
+
gem_with_dangling_symlink = File.expand_path("packages/ascii_binder-0.1.10.1.gem", __dir__)
installer = Gem::Installer.at(
@@ -760,8 +764,12 @@ gem 'other', version
errors = @ui.error.split("\n")
assert_equal "WARNING: ascii_binder-0.1.10.1 ships with a dangling symlink named bin/ascii_binder pointing to missing bin/asciibinder file. Ignoring", errors.shift
- assert_empty errors
-
+ if symlink_supported?
+ assert_empty errors
+ else
+ assert_match(/Unable to use symlinks, installing wrapper/i,
+ errors.to_s)
+ end
assert_empty @ui.output
end
@@ -869,11 +877,11 @@ gem 'other', version
spec_version = spec.version
plugin_path = File.join("lib", "rubygems_plugin.rb")
write_file File.join(@tempdir, plugin_path) do |io|
- io.write <<-PLUGIN
-#{self.class}.plugin_loaded = true
-Gem.post_install do
- #{self.class}.post_install_is_called = true
-end
+ io.write <<~PLUGIN
+ #{self.class}.plugin_loaded = true
+ Gem.post_install do
+ #{self.class}.post_install_is_called = true
+ end
PLUGIN
end
spec.files += [plugin_path]
@@ -1247,7 +1255,7 @@ end
end
assert_raise(Gem::Ext::BuildError) do
- installer.install
+ build_rake_in { installer.install }
end
assert_path_not_exist(File.join(installer.bin_dir, "executable.lock"))
@@ -1478,12 +1486,7 @@ end
@spec = setup_base_spec
@spec.extensions << "extconf.rb"
- write_file File.join(@tempdir, "extconf.rb") do |io|
- io.write <<-RUBY
- require "mkmf"
- create_makefile("#{@spec.name}")
- RUBY
- end
+ write_dummy_extconf @spec.name
@spec.files += %w[extconf.rb]
@@ -1503,12 +1506,7 @@ end
@spec = setup_base_spec
@spec.extensions << "extconf.rb"
- write_file File.join(@tempdir, "extconf.rb") do |io|
- io.write <<-RUBY
- require "mkmf"
- create_makefile("#{@spec.name}")
- RUBY
- end
+ write_dummy_extconf @spec.name
@spec.files += %w[extconf.rb]
@@ -1539,12 +1537,7 @@ end
def test_install_user_extension_dir
@spec = setup_base_spec
@spec.extensions << "extconf.rb"
- write_file File.join(@tempdir, "extconf.rb") do |io|
- io.write <<-RUBY
- require "mkmf"
- create_makefile("#{@spec.name}")
- RUBY
- end
+ write_dummy_extconf @spec.name
@spec.files += %w[extconf.rb]
@@ -1571,22 +1564,20 @@ end
@spec = setup_base_spec
@spec.extensions << "extconf.rb"
- write_file File.join(@tempdir, "extconf.rb") do |io|
- io.write <<-RUBY
- require "mkmf"
+ write_dummy_extconf @spec.name do |io|
+ io.write <<~RUBY
CONFIG['CC'] = '$(TOUCH) $@ ||'
CONFIG['LDSHARED'] = '$(TOUCH) $@ ||'
$ruby = '#{Gem.ruby}'
- create_makefile("#{@spec.name}")
RUBY
end
write_file File.join(@tempdir, "depend")
write_file File.join(@tempdir, "a.c") do |io|
- io.write <<-C
+ io.write <<~C
#include <ruby.h>
void Init_a() { }
C
@@ -1618,17 +1609,12 @@ end
@spec = setup_base_spec
@spec.extensions << "extconf.rb"
- write_file File.join(@tempdir, "extconf.rb") do |io|
- io.write <<-RUBY
- require "mkmf"
- create_makefile("#{@spec.name}")
- RUBY
- end
+ write_dummy_extconf @spec.name
rb = File.join("lib", "#{@spec.name}.rb")
@spec.files += [rb]
write_file File.join(@tempdir, rb) do |io|
- io.write <<-RUBY
+ io.write <<~RUBY
# #{@spec.name}.rb
RUBY
end
@@ -1637,7 +1623,7 @@ end
rb2 = File.join("lib", @spec.name, "#{@spec.name}.rb")
@spec.files << rb2
write_file File.join(@tempdir, rb2) do |io|
- io.write <<-RUBY
+ io.write <<~RUBY
# #{@spec.name}/#{@spec.name}.rb
RUBY
end
@@ -1663,15 +1649,13 @@ end
@spec.extensions << "extconf.rb"
- write_file File.join(@tempdir, "extconf.rb") do |io|
- io.write <<-RUBY
- require "mkmf"
+ write_dummy_extconf @spec.name do |io|
+ io.write <<~RUBY
CONFIG['CC'] = '$(TOUCH) $@ ||'
CONFIG['LDSHARED'] = '$(TOUCH) $@ ||'
$ruby = '#{Gem.ruby}'
- create_makefile("#{@spec.name}")
RUBY
end
@@ -1698,13 +1682,13 @@ end
@spec.require_paths = ["."]
@spec.extensions << "extconf.rb"
- File.write File.join(@tempdir, "extconf.rb"), <<-RUBY
- require "mkmf"
- CONFIG['CC'] = '$(TOUCH) $@ ||'
- CONFIG['LDSHARED'] = '$(TOUCH) $@ ||'
- $ruby = '#{Gem.ruby}'
- create_makefile("#{@spec.name}")
- RUBY
+ write_dummy_extconf @spec.name do |io|
+ io.write <<~RUBY
+ CONFIG['CC'] = '$(TOUCH) $@ ||'
+ CONFIG['LDSHARED'] = '$(TOUCH) $@ ||'
+ $ruby = '#{Gem.ruby}'
+ RUBY
+ end
# empty depend file for no auto dependencies
@spec.files += %W[depend #{@spec.name}.c].each do |file|
@@ -1938,10 +1922,10 @@ end
end
def test_pre_install_checks_malicious_platform_before_eval
- gem_with_ill_formated_platform = File.expand_path("packages/ill-formatted-platform-1.0.0.10.gem", __dir__)
+ gem_with_ill_formatted_platform = File.expand_path("packages/ill-formatted-platform-1.0.0.10.gem", __dir__)
installer = Gem::Installer.at(
- gem_with_ill_formated_platform,
+ gem_with_ill_formatted_platform,
install_dir: @gemhome,
user_install: false,
force: true
@@ -2304,19 +2288,6 @@ end
assert_equal "#!1 #{bin_env} 2 #{Gem.ruby} -ws 3 executable", shebang
end
- def test_unpack
- installer = util_setup_installer
-
- dest = File.join @gemhome, "gems", @spec.full_name
-
- Gem::Deprecate.skip_during do
- installer.unpack dest
- end
-
- assert_path_exist File.join dest, "lib", "code.rb"
- assert_path_exist File.join dest, "bin", "executable"
- end
-
def test_write_build_info_file
installer = setup_base_installer
@@ -2423,25 +2394,31 @@ end
installer = Gem::Installer.for_spec @spec
installer.gem_home = @gemhome
- File.singleton_class.class_eval do
- alias_method :original_binwrite, :binwrite
-
- def binwrite(path, data)
+ assert_raise(Errno::ENOSPC) do
+ Gem::AtomicFileWriter.open(@spec.spec_file) do
raise Errno::ENOSPC
end
end
- assert_raise Errno::ENOSPC do
- installer.write_spec
- end
-
assert_path_not_exist @spec.spec_file
- ensure
- File.singleton_class.class_eval do
- remove_method :binwrite
- alias_method :binwrite, :original_binwrite
- remove_method :original_binwrite
- end
+ end
+
+ def test_write_default_spec
+ @spec = setup_base_spec
+ @spec.files = %w[a.rb b.rb c.rb]
+
+ installer = Gem::Installer.for_spec @spec
+ installer.gem_home = @gemhome
+
+ installer.write_default_spec
+
+ assert_path_exist installer.default_spec_file
+
+ loaded = Gem::Specification.load installer.default_spec_file
+
+ assert_equal @spec.files, loaded.files
+ assert_equal @spec.name, loaded.name
+ assert_equal @spec.version, loaded.version
end
def test_dir
@@ -2450,137 +2427,154 @@ end
assert_match %r{/gemhome/gems/a-2$}, installer.dir
end
- def test_default_gem_loaded_from
- spec = util_spec "a"
- installer = Gem::Installer.for_spec spec, install_as_default: true
- installer.install
- assert_predicate spec, :default_gem?
+ def test_package_attribute
+ gem = quick_gem "c" do |spec|
+ util_make_exec spec, "#!/usr/bin/ruby", "exe"
+ end
+
+ installer = util_installer(gem, @gemhome)
+ assert_respond_to(installer, :package)
+ assert_kind_of(Gem::Package, installer.package)
end
- def test_default_gem_without_wrappers
- installer = setup_base_installer
+ def test_gem_attribute
+ gem = quick_gem "c" do |spec|
+ util_make_exec spec, "#!/usr/bin/ruby", "exe"
+ end
- FileUtils.rm_rf File.join(Gem.default_dir, "specifications")
+ installer = util_installer(gem, @gemhome)
+ assert_respond_to(installer, :gem)
+ assert_kind_of(String, installer.gem)
+ end
- installer.wrappers = false
- installer.options[:install_as_default] = true
- installer.gem_dir = @spec.gem_dir
+ def test_install_no_build_extension
+ installer = util_setup_installer
+
+ gemdir = File.join @gemhome, "gems", @spec.full_name
+
+ installer.options[:build_extension] = false
use_ui @ui do
installer.install
end
- assert_directory_exists File.join(@spec.gem_dir, "bin")
- installed_exec = File.join @spec.gem_dir, "bin", "executable"
- assert_path_exist installed_exec
-
- assert_directory_exists File.join(Gem.default_dir, "specifications")
- assert_directory_exists File.join(Gem.default_dir, "specifications", "default")
-
- default_spec = eval File.read File.join(Gem.default_dir, "specifications", "default", "a-2.gemspec")
- assert_equal Gem::Version.new("2"), default_spec.version
- assert_equal ["bin/executable"], default_spec.files
+ assert_path_exist gemdir
+ assert_path_not_exist File.join(@spec.extension_dir, "gem.build_complete")
+ assert_match "contains native extensions that were not built", @ui.error
+ assert_match "gem pristine #{@spec.name} --extensions", @ui.error
+ end
- assert_directory_exists util_inst_bindir
+ def test_install_no_build_extension_without_extensions
+ spec = quick_gem "b", 2
- installed_exec = File.join util_inst_bindir, "executable"
- assert_path_exist installed_exec
+ util_build_gem spec
- wrapper = File.read installed_exec
+ installer = util_installer spec, @gemhome
+ installer.options[:build_extension] = false
- if symlink_supported?
- refute_match(/generated by RubyGems/, wrapper)
- else # when symlink not supported, it warns and fallbacks back to installing wrapper
- assert_match(/Unable to use symlinks, installing wrapper/, @ui.error)
- assert_match(/generated by RubyGems/, wrapper)
+ use_ui @ui do
+ installer.install
end
- end
- def test_default_gem_with_wrappers
- installer = setup_base_installer
+ refute_match "contains native extensions", @ui.error
+ end
- installer.wrappers = true
- installer.options[:install_as_default] = true
- installer.gem_dir = @spec.gem_dir
+ def test_install_no_install_plugin
+ installer = util_setup_installer do |spec|
+ write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io|
+ io.write "# do nothing"
+ end
- use_ui @ui do
- installer.install
+ spec.files += %w[lib/rubygems_plugin.rb]
end
- assert_directory_exists util_inst_bindir
+ installer.options[:install_plugin] = false
- installed_exec = File.join util_inst_bindir, "executable"
- assert_path_exist installed_exec
+ build_rake_in do
+ use_ui @ui do
+ installer.install
+ end
+ end
- wrapper = File.read installed_exec
- assert_match(/generated by RubyGems/, wrapper)
+ plugin_path = File.join Gem.plugindir, "a_plugin.rb"
+ refute File.exist?(plugin_path), "plugin must not be written when --no-install-plugin"
+ assert_match "contains plugins that were not installed", @ui.error
+ assert_match "gem pristine #{@spec.name} --only-plugins", @ui.error
end
- def test_default_gem_with_exe_as_bindir
- @spec = quick_gem "c" do |spec|
- util_make_exec spec, "#!/usr/bin/ruby", "exe"
+ def test_install_no_install_plugin_skips_load_plugin
+ installer = util_setup_installer do |spec|
+ write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io|
+ io.write "$no_install_plugin_test_loaded = true"
+ end
+
+ spec.files += %w[lib/rubygems_plugin.rb]
end
- util_build_gem @spec
+ # Simulate a pre-existing plugin wrapper from a previous install
+ FileUtils.mkdir_p Gem.plugindir
+ plugin_path = File.join Gem.plugindir, "a_plugin.rb"
+ File.write(plugin_path, "require_relative '../../gems/#{@spec.full_name}/lib/rubygems_plugin'")
- @spec.cache_file
+ installer.options[:install_plugin] = false
- installer = util_installer @spec, @gemhome
+ build_rake_in do
+ use_ui @ui do
+ installer.install
+ end
+ end
- installer.options[:install_as_default] = true
- installer.gem_dir = @spec.gem_dir
+ refute defined?($no_install_plugin_test_loaded) && $no_install_plugin_test_loaded,
+ "plugin must not be loaded when --no-install-plugin"
+ ensure
+ $no_install_plugin_test_loaded = nil
+ end
- use_ui @ui do
- installer.install
- end
+ def test_install_no_install_plugin_without_plugins
+ installer = util_setup_installer
- assert_directory_exists File.join(@spec.gem_dir, "exe")
- installed_exec = File.join @spec.gem_dir, "exe", "executable"
- assert_path_exist installed_exec
+ installer.options[:install_plugin] = false
- assert_directory_exists File.join(Gem.default_dir, "specifications")
- assert_directory_exists File.join(Gem.default_dir, "specifications", "default")
+ build_rake_in do
+ use_ui @ui do
+ installer.install
+ end
+ end
- default_spec = eval File.read File.join(Gem.default_dir, "specifications", "default", "c-2.gemspec")
- assert_equal Gem::Version.new("2"), default_spec.version
- assert_equal ["exe/executable"], default_spec.files
+ refute_match "contains plugins", @ui.error
end
- def test_default_gem_to_specific_install_dir
- @gem = setup_base_gem
- installer = util_installer @spec, "#{@gemhome}2"
- installer.options[:install_as_default] = true
+ def test_install_no_install_plugin_removes_stale_wrappers
+ # First install a version with a plugin
+ installer = util_setup_installer do |spec|
+ write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io|
+ io.write "# plugin code"
+ end
- use_ui @ui do
- installer.install
+ spec.files += %w[lib/rubygems_plugin.rb]
end
- assert_directory_exists File.join("#{@gemhome}2", "specifications")
- assert_directory_exists File.join("#{@gemhome}2", "specifications", "default")
+ build_rake_in do
+ use_ui @ui do
+ installer.install
+ end
+ end
- default_spec = eval File.read File.join("#{@gemhome}2", "specifications", "default", "a-2.gemspec")
- assert_equal Gem::Version.new("2"), default_spec.version
- assert_equal ["bin/executable"], default_spec.files
- end
+ plugin_path = File.join Gem.plugindir, "a_plugin.rb"
+ assert File.exist?(plugin_path), "plugin wrapper should exist after first install"
- def test_package_attribute
- gem = quick_gem "c" do |spec|
- util_make_exec spec, "#!/usr/bin/ruby", "exe"
- end
+ # Now install a new version without plugins, using --no-install-plugin
+ spec2 = quick_gem "a", 3
+ util_build_gem spec2
- installer = util_installer(gem, @gemhome)
- assert_respond_to(installer, :package)
- assert_kind_of(Gem::Package, installer.package)
- end
+ installer2 = util_installer spec2, @gemhome
+ installer2.options[:install_plugin] = false
- def test_gem_attribute
- gem = quick_gem "c" do |spec|
- util_make_exec spec, "#!/usr/bin/ruby", "exe"
+ use_ui @ui do
+ installer2.install
end
- installer = util_installer(gem, @gemhome)
- assert_respond_to(installer, :gem)
- assert_kind_of(String, installer.gem)
+ refute File.exist?(plugin_path), "stale plugin wrapper must be removed"
end
private
diff --git a/test/rubygems/test_gem_name_tuple.rb b/test/rubygems/test_gem_name_tuple.rb
index bdb8181ce8..4876737c83 100644
--- a/test/rubygems/test_gem_name_tuple.rb
+++ b/test/rubygems/test_gem_name_tuple.rb
@@ -57,4 +57,41 @@ class TestGemNameTuple < Gem::TestCase
assert_equal 1, a_p.<=>(a)
end
+
+ def test_deconstruct
+ name_tuple = Gem::NameTuple.new "rails", Gem::Version.new("7.0.0"), "ruby"
+ assert_equal ["rails", Gem::Version.new("7.0.0"), "ruby"], name_tuple.deconstruct
+ end
+
+ def test_deconstruct_keys
+ name_tuple = Gem::NameTuple.new "rails", Gem::Version.new("7.0.0"), "x86_64-linux"
+ keys = name_tuple.deconstruct_keys(nil)
+ assert_equal "rails", keys[:name]
+ assert_equal Gem::Version.new("7.0.0"), keys[:version]
+ assert_equal "x86_64-linux", keys[:platform]
+ end
+
+ def test_pattern_matching_array
+ name_tuple = Gem::NameTuple.new "rails", Gem::Version.new("7.0.0"), "ruby"
+ result =
+ case name_tuple
+ in [name, version, "ruby"]
+ "#{name}-#{version}"
+ else
+ "no match"
+ end
+ assert_equal "rails-7.0.0", result
+ end
+
+ def test_pattern_matching_hash
+ name_tuple = Gem::NameTuple.new "rails", Gem::Version.new("7.0.0"), "ruby"
+ result =
+ case name_tuple
+ in name: "rails", version:, platform: "ruby"
+ version.to_s
+ else
+ "no match"
+ end
+ assert_equal "7.0.0", result
+ end
end
diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb
index 8a9cc85580..0014c20737 100644
--- a/test/rubygems/test_gem_package.rb
+++ b/test/rubygems/test_gem_package.rb
@@ -175,6 +175,9 @@ class TestGemPackage < Gem::Package::TarTestCase
end
def test_add_files_symlink
+ unless symlink_supported?
+ omit("symlink - developer mode must be enabled on Windows")
+ end
spec = Gem::Specification.new
spec.files = %w[lib/code.rb lib/code_sym.rb lib/code_sym2.rb]
@@ -185,16 +188,8 @@ class TestGemPackage < Gem::Package::TarTestCase
end
# NOTE: 'code.rb' is correct, because it's relative to lib/code_sym.rb
- begin
- File.symlink("code.rb", "lib/code_sym.rb")
- File.symlink("../lib/code.rb", "lib/code_sym2.rb")
- rescue Errno::EACCES => e
- if Gem.win_platform?
- pend "symlink - must be admin with no UAC on Windows"
- else
- raise e
- end
- end
+ File.symlink("code.rb", "lib/code_sym.rb")
+ File.symlink("../lib/code.rb", "lib/code_sym2.rb")
package = Gem::Package.new "bogus.gem"
package.spec = spec
@@ -506,7 +501,7 @@ class TestGemPackage < Gem::Package::TarTestCase
extracted = File.join @destination, "lib/code.rb"
assert_path_exist extracted
- mask = 0o100666 & (~File.umask)
+ mask = 0o100666 & ~File.umask
assert_equal mask.to_s(8), File.stat(extracted).mode.to_s(8) unless
Gem.win_platform?
@@ -583,25 +578,71 @@ class TestGemPackage < Gem::Package::TarTestCase
tar.add_symlink "lib/foo.rb", "../relative.rb", 0o644
end
- begin
- package.extract_tar_gz tgz_io, @destination
- rescue Errno::EACCES => e
- if Gem.win_platform?
- pend "symlink - must be admin with no UAC on Windows"
- else
- raise e
- end
- end
+ package.extract_tar_gz tgz_io, @destination
extracted = File.join @destination, "lib/foo.rb"
assert_path_exist extracted
- assert_equal "../relative.rb",
- File.readlink(extracted)
+ if symlink_supported?
+ assert_equal "../relative.rb",
+ File.readlink(extracted)
+ end
assert_equal "hi",
+ File.read(extracted),
+ "should read file content either by following symlink or on Windows by reading copy"
+ end
+
+ def test_extract_tar_gz_symlink_directory
+ package = Gem::Package.new @gem
+ package.verify
+
+ tgz_io = util_tar_gz do |tar|
+ tar.add_symlink "link", "lib/orig", 0o644
+ tar.mkdir "lib", 0o755
+ tar.mkdir "lib/orig", 0o755
+ tar.add_file "lib/orig/file.rb", 0o644 do |io|
+ io.write "ok"
+ end
+ end
+
+ package.extract_tar_gz tgz_io, @destination
+ extracted = File.join @destination, "link/file.rb"
+ assert_path_exist extracted
+ if symlink_supported?
+ assert_equal "lib/orig",
+ File.readlink(File.dirname(extracted))
+ end
+ assert_equal "ok",
File.read(extracted)
end
+ def test_extract_tar_gz_rejects_preexisting_symlink_escape
+ omit "Symlinks not supported or not enabled" unless symlink_supported?
+
+ package = Gem::Package.new @gem
+
+ tgz_io = util_tar_gz do |tar|
+ tar.add_file "lib/owned.txt", 0o644 do |io|
+ io.write "poc-content"
+ end
+ end
+
+ escape_dir = File.join(@tempdir, "escape")
+ FileUtils.mkdir_p escape_dir
+
+ FileUtils.rm_rf File.join(@destination, "lib")
+ File.symlink escape_dir, File.join(@destination, "lib")
+
+ escaped = File.join(escape_dir, "owned.txt")
+
+ assert_raise Gem::Package::PathError do
+ package.extract_tar_gz tgz_io, @destination
+ end
+
+ refute File.exist?(escaped), "must not write outside extraction root via symlink"
+ end
+
def test_extract_symlink_into_symlink_dir
+ omit "Symlinks not supported or not enabled" unless symlink_supported?
package = Gem::Package.new @gem
tgz_io = util_tar_gz do |tar|
tar.mkdir "lib", 0o755
@@ -665,14 +706,10 @@ class TestGemPackage < Gem::Package::TarTestCase
destination_subdir = File.join @destination, "subdir"
FileUtils.mkdir_p destination_subdir
- expected_exceptions = Gem.win_platform? ? [Gem::Package::SymlinkError, Errno::EACCES] : [Gem::Package::SymlinkError]
-
- e = assert_raise(*expected_exceptions) do
+ e = assert_raise(Gem::Package::SymlinkError) do
package.extract_tar_gz tgz_io, destination_subdir
end
- pend "symlink - must be admin with no UAC on Windows" if Errno::EACCES === e
-
assert_equal("installing symlink 'lib/link' pointing to parent path #{@destination} of " \
"#{destination_subdir} is not allowed", e.message)
@@ -700,14 +737,10 @@ class TestGemPackage < Gem::Package::TarTestCase
tar.add_symlink "link/dir", ".", 16_877
end
- expected_exceptions = Gem.win_platform? ? [Gem::Package::SymlinkError, Errno::EACCES] : [Gem::Package::SymlinkError]
-
- e = assert_raise(*expected_exceptions) do
+ e = assert_raise(Gem::Package::SymlinkError) do
package.extract_tar_gz tgz_io, destination_subdir
end
- pend "symlink - must be admin with no UAC on Windows" if Errno::EACCES === e
-
assert_equal("installing symlink 'link' pointing to parent path #{destination_user_dir} of " \
"#{destination_subdir} is not allowed", e.message)
@@ -858,7 +891,7 @@ class TestGemPackage < Gem::Package::TarTestCase
"#{@destination} is not allowed", e.message)
end
- def test_load_spec
+ def test_load_spec_from_metadata
entry = StringIO.new Gem::Util.gzip @spec.to_yaml
def entry.full_name
"metadata.gz"
@@ -866,7 +899,7 @@ class TestGemPackage < Gem::Package::TarTestCase
package = Gem::Package.new "nonexistent.gem"
- spec = package.load_spec entry
+ spec = package.load_spec_from_metadata entry
assert_equal @spec, spec
end
@@ -909,7 +942,11 @@ class TestGemPackage < Gem::Package::TarTestCase
}
tar.add_file "checksums.yaml.gz", 0o444 do |io|
Zlib::GzipWriter.wrap io do |gz_io|
- gz_io.write Psych.dump bogus_checksums
+ if Gem.use_psych?
+ gz_io.write Psych.dump(bogus_checksums)
+ else
+ gz_io.write Gem::YAMLSerializer.dump(bogus_checksums)
+ end
end
end
end
@@ -955,7 +992,11 @@ class TestGemPackage < Gem::Package::TarTestCase
tar.add_file "checksums.yaml.gz", 0o444 do |io|
Zlib::GzipWriter.wrap io do |gz_io|
- gz_io.write Psych.dump checksums
+ if Gem.use_psych?
+ gz_io.write Psych.dump(checksums)
+ else
+ gz_io.write Gem::YAMLSerializer.dump(checksums)
+ end
end
end
@@ -1247,71 +1288,25 @@ class TestGemPackage < Gem::Package::TarTestCase
# end #verify tests
- def test_verify_entry
- entry = Object.new
- def entry.full_name
- raise ArgumentError, "whatever"
- end
-
- package = Gem::Package.new @gem
-
- _, err = use_ui @ui do
- e = nil
-
- out_err = capture_output do
- e = assert_raise ArgumentError do
- package.verify_entry entry
+ def test_missing_metadata
+ invalid_metadata = ["metadataxgz", "foobar\nmetadata", "metadata\nfoobar"]
+ invalid_metadata.each do |fname|
+ tar = StringIO.new
+
+ Gem::Package::TarWriter.new(tar) do |gem_tar|
+ gem_tar.add_file fname, 0o444 do |io|
+ gz_io = Zlib::GzipWriter.new io, Zlib::BEST_COMPRESSION
+ gz_io.write "bad metadata"
+ gz_io.close
end
end
- assert_equal "whatever", e.message
- assert_equal "full_name", e.backtrace_locations.first.label
-
- out_err
- end
-
- assert_equal "Exception while verifying #{@gem}\n", err
-
- valid_metadata = ["metadata", "metadata.gz"]
- valid_metadata.each do |vm|
- $spec_loaded = false
- $good_name = vm
-
- entry = Object.new
- def entry.full_name
- $good_name
- end
-
- package = Gem::Package.new(@gem)
- package.instance_variable_set(:@files, [])
- def package.load_spec(entry)
- $spec_loaded = true
- end
-
- package.verify_entry(entry)
+ tar.rewind
- assert $spec_loaded
- end
-
- invalid_metadata = ["metadataxgz", "foobar\nmetadata", "metadata\nfoobar"]
- invalid_metadata.each do |vm|
- $spec_loaded = false
- $bad_name = vm
-
- entry = Object.new
- def entry.full_name
- $bad_name
- end
-
- package = Gem::Package.new(@gem)
- package.instance_variable_set(:@files, [])
- def package.load_spec(entry)
- $spec_loaded = true
+ package = Gem::Package.new(Gem::Package::IOSource.new(tar))
+ assert_raise Gem::Package::FormatError do
+ package.verify
end
-
- package.verify_entry(entry)
-
- refute $spec_loaded
end
end
diff --git a/test/rubygems/test_gem_package_old.rb b/test/rubygems/test_gem_package_old.rb
index 7582dbedd4..e532fa25e1 100644
--- a/test/rubygems/test_gem_package_old.rb
+++ b/test/rubygems/test_gem_package_old.rb
@@ -39,7 +39,7 @@ unless Gem.java_platform? # jruby can't require the simple_gem file
extracted = File.join @destination, "lib/foo.rb"
assert_path_exist extracted
- mask = 0o100644 & (~File.umask)
+ mask = 0o100644 & ~File.umask
assert_equal mask, File.stat(extracted).mode unless Gem.win_platform?
end
diff --git a/test/rubygems/test_gem_package_tar_header_ractor.rb b/test/rubygems/test_gem_package_tar_header_ractor.rb
new file mode 100644
index 0000000000..5714064805
--- /dev/null
+++ b/test/rubygems/test_gem_package_tar_header_ractor.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require_relative "package/tar_test_case"
+
+unless Gem::Package::TarTestCase.method_defined?(:assert_ractor)
+ require "core_assertions"
+ Gem::Package::TarTestCase.include Test::Unit::CoreAssertions
+end
+
+class TestGemPackageTarHeaderRactor < Gem::Package::TarTestCase
+ SETUP = <<~RUBY
+ header = {
+ name: "x",
+ mode: 0o644,
+ uid: 1000,
+ gid: 10_000,
+ size: 100,
+ mtime: 12_345,
+ typeflag: "0",
+ linkname: "link",
+ uname: "user",
+ gname: "group",
+ devmajor: 1,
+ devminor: 2,
+ prefix: "y",
+ }
+
+ tar_header = Gem::Package::TarHeader.new header
+ # Move this require to arguments of assert_ractor after Ruby 4.0 or updating core_assertions.rb at Ruby 3.4.
+ require "stringio"
+ # Remove this after Ruby 4.0 or updating core_assertions.rb at Ruby 3.4.
+ class Ractor; alias value take unless method_defined?(:value); end
+ RUBY
+
+ def test_decode_in_ractor
+ assert_ractor(SETUP + <<~RUBY, require: "rubygems/package", require_relative: "package/tar_test_case")
+ include Gem::Package::TarTestMethods
+
+ new_header = Ractor.new(tar_header.to_s) do |str|
+ Gem::Package::TarHeader.from StringIO.new str
+ end.value
+
+ assert_headers_equal tar_header, new_header
+ RUBY
+ end
+
+ def test_encode_in_ractor
+ assert_ractor(SETUP + <<~RUBY, require: "rubygems/package", require_relative: "package/tar_test_case")
+ include Gem::Package::TarTestMethods
+
+ header_bytes = tar_header.to_s
+
+ new_header_bytes = Ractor.new(header_bytes) do |str|
+ new_header = Gem::Package::TarHeader.from StringIO.new str
+ new_header.to_s
+ end.value
+
+ assert_headers_equal header_bytes, new_header_bytes
+ RUBY
+ end
+end unless RUBY_PLATFORM.match?(/mingw|mswin/)
diff --git a/test/rubygems/test_gem_package_tar_writer.rb b/test/rubygems/test_gem_package_tar_writer.rb
index 67a9d0db43..cb9e0d26fa 100644
--- a/test/rubygems/test_gem_package_tar_writer.rb
+++ b/test/rubygems/test_gem_package_tar_writer.rb
@@ -50,6 +50,19 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
end
end
+ def test_add_file_with_mtime
+ Time.stub :now, Time.at(1_458_518_157) do
+ mtime = Time.now
+
+ @tar_writer.add_file "x", 0o644, mtime do |f|
+ f.write "a" * 10
+ end
+
+ assert_headers_equal(tar_file_header("x", "", 0o644, 10, mtime),
+ @io.string[0, 512])
+ end
+ end
+
def test_add_symlink
Time.stub :now, Time.at(1_458_518_157) do
@tar_writer.add_symlink "x", "y", 0o644
diff --git a/test/rubygems/test_gem_path_support.rb b/test/rubygems/test_gem_path_support.rb
index 8720bcf858..c5181496c0 100644
--- a/test/rubygems/test_gem_path_support.rb
+++ b/test/rubygems/test_gem_path_support.rb
@@ -121,14 +121,12 @@ class TestGemPathSupport < Gem::TestCase
end
def test_gem_paths_do_not_contain_symlinks
+ pend "symlinks not supported" unless symlink_supported?
+
dir = "#{@tempdir}/realgemdir"
symlink = "#{@tempdir}/symdir"
Dir.mkdir dir
- begin
- File.symlink(dir, symlink)
- rescue NotImplementedError, SystemCallError
- pend "symlinks not supported"
- end
+ File.symlink(dir, symlink)
not_existing = "#{@tempdir}/does_not_exist"
path = "#{symlink}#{File::PATH_SEPARATOR}#{not_existing}"
diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb
index 070c8007bc..c1ff36772b 100644
--- a/test/rubygems/test_gem_platform.rb
+++ b/test/rubygems/test_gem_platform.rb
@@ -11,15 +11,6 @@ class TestGemPlatform < Gem::TestCase
assert_equal Gem::Platform.new(%w[x86 darwin 8]), Gem::Platform.local
end
- def test_self_match
- Gem::Deprecate.skip_during do
- assert Gem::Platform.match(nil), "nil == ruby"
- assert Gem::Platform.match(Gem::Platform.local), "exact match"
- assert Gem::Platform.match(Gem::Platform.local.to_s), "=~ match"
- assert Gem::Platform.match(Gem::Platform::RUBY), "ruby"
- end
- end
-
def test_self_match_gem?
assert Gem::Platform.match_gem?(nil, "json"), "nil == ruby"
assert Gem::Platform.match_gem?(Gem::Platform.local, "json"), "exact match"
@@ -148,12 +139,29 @@ class TestGemPlatform < Gem::TestCase
"wasm32-wasi" => ["wasm32", "wasi", nil],
"wasm32-wasip1" => ["wasm32", "wasi", nil],
"wasm32-wasip2" => ["wasm32", "wasi", nil],
+
+ "darwin-java-java" => ["darwin", "java", nil],
+ "linux-linux-linux" => ["linux", "linux", "linux"],
+ "linux-linux-linux1.0" => ["linux", "linux", "linux1"],
+ "x86x86-1x86x86x86x861linuxx86x86" => ["x86x86", "linux", "x86x86"],
+ "freebsd0" => [nil, "freebsd", "0"],
+ "darwin0" => [nil, "darwin", "0"],
+ "darwin0---" => [nil, "darwin", "0"],
+ "x86-linux-x8611.0l" => ["x86", "linux", "x8611"],
+ "0-x86linuxx86---" => ["0", "linux", "x86"],
+ "x86_64-macruby-x86" => ["x86_64", "macruby", nil],
+ "x86_64-dotnetx86" => ["x86_64", "dotnet", nil],
+ "x86_64-dalvik0" => ["x86_64", "dalvik", "0"],
+ "x86_64-dotnet1." => ["x86_64", "dotnet", "1"],
+
+ "--" => [nil, "unknown", nil],
}
test_cases.each do |arch, expected|
platform = Gem::Platform.new arch
assert_equal expected, platform.to_a, arch.inspect
- assert_equal expected, Gem::Platform.new(platform.to_s).to_a, arch.inspect
+ platform2 = Gem::Platform.new platform.to_s
+ assert_equal expected, platform2.to_a, "#{arch.inspect} => #{platform2.inspect}"
end
end
@@ -246,19 +254,19 @@ class TestGemPlatform < Gem::TestCase
x86_darwin8 = Gem::Platform.new "i686-darwin8.0"
util_set_arch "powerpc-darwin8"
- assert((ppc_darwin8 === Gem::Platform.local), "powerpc =~ universal")
- assert((uni_darwin8 === Gem::Platform.local), "powerpc =~ universal")
- refute((x86_darwin8 === Gem::Platform.local), "powerpc =~ universal")
+ assert(ppc_darwin8 === Gem::Platform.local, "powerpc =~ universal")
+ assert(uni_darwin8 === Gem::Platform.local, "powerpc =~ universal")
+ refute(x86_darwin8 === Gem::Platform.local, "powerpc =~ universal")
util_set_arch "i686-darwin8"
- refute((ppc_darwin8 === Gem::Platform.local), "powerpc =~ universal")
- assert((uni_darwin8 === Gem::Platform.local), "x86 =~ universal")
- assert((x86_darwin8 === Gem::Platform.local), "powerpc =~ universal")
+ refute(ppc_darwin8 === Gem::Platform.local, "powerpc =~ universal")
+ assert(uni_darwin8 === Gem::Platform.local, "x86 =~ universal")
+ assert(x86_darwin8 === Gem::Platform.local, "powerpc =~ universal")
util_set_arch "universal-darwin8"
- assert((ppc_darwin8 === Gem::Platform.local), "universal =~ ppc")
- assert((uni_darwin8 === Gem::Platform.local), "universal =~ universal")
- assert((x86_darwin8 === Gem::Platform.local), "universal =~ x86")
+ assert(ppc_darwin8 === Gem::Platform.local, "universal =~ ppc")
+ assert(uni_darwin8 === Gem::Platform.local, "universal =~ universal")
+ assert(x86_darwin8 === Gem::Platform.local, "universal =~ x86")
end
def test_nil_cpu_arch_is_treated_as_universal
@@ -266,18 +274,18 @@ class TestGemPlatform < Gem::TestCase
with_uni_arch = Gem::Platform.new ["universal", "mingw32"]
with_x86_arch = Gem::Platform.new ["x86", "mingw32"]
- assert((with_nil_arch === with_uni_arch), "nil =~ universal")
- assert((with_uni_arch === with_nil_arch), "universal =~ nil")
- assert((with_nil_arch === with_x86_arch), "nil =~ x86")
- assert((with_x86_arch === with_nil_arch), "x86 =~ nil")
+ assert(with_nil_arch === with_uni_arch, "nil =~ universal")
+ assert(with_uni_arch === with_nil_arch, "universal =~ nil")
+ assert(with_nil_arch === with_x86_arch, "nil =~ x86")
+ assert(with_x86_arch === with_nil_arch, "x86 =~ nil")
end
def test_nil_version_is_treated_as_any_version
x86_darwin_8 = Gem::Platform.new "i686-darwin8.0"
x86_darwin_nil = Gem::Platform.new "i686-darwin"
- assert((x86_darwin_8 === x86_darwin_nil), "8.0 =~ nil")
- assert((x86_darwin_nil === x86_darwin_8), "nil =~ 8.0")
+ assert(x86_darwin_8 === x86_darwin_nil, "8.0 =~ nil")
+ assert(x86_darwin_nil === x86_darwin_8, "nil =~ 8.0")
end
def test_nil_version_is_stricter_for_linux_os
@@ -371,40 +379,33 @@ class TestGemPlatform < Gem::TestCase
arm64 = Gem::Platform.new "arm64-linux"
util_set_arch "armv5-linux"
- assert((arm === Gem::Platform.local), "arm === armv5")
- assert((armv5 === Gem::Platform.local), "armv5 === armv5")
- refute((armv7 === Gem::Platform.local), "armv7 === armv5")
- refute((arm64 === Gem::Platform.local), "arm64 === armv5")
- refute((Gem::Platform.local === arm), "armv5 === arm")
+ assert(arm === Gem::Platform.local, "arm === armv5")
+ assert(armv5 === Gem::Platform.local, "armv5 === armv5")
+ refute(armv7 === Gem::Platform.local, "armv7 === armv5")
+ refute(arm64 === Gem::Platform.local, "arm64 === armv5")
+ refute(Gem::Platform.local === arm, "armv5 === arm")
util_set_arch "armv7-linux"
- assert((arm === Gem::Platform.local), "arm === armv7")
- refute((armv5 === Gem::Platform.local), "armv5 === armv7")
- assert((armv7 === Gem::Platform.local), "armv7 === armv7")
- refute((arm64 === Gem::Platform.local), "arm64 === armv7")
- refute((Gem::Platform.local === arm), "armv7 === arm")
+ assert(arm === Gem::Platform.local, "arm === armv7")
+ refute(armv5 === Gem::Platform.local, "armv5 === armv7")
+ assert(armv7 === Gem::Platform.local, "armv7 === armv7")
+ refute(arm64 === Gem::Platform.local, "arm64 === armv7")
+ refute(Gem::Platform.local === arm, "armv7 === arm")
util_set_arch "arm64-linux"
- refute((arm === Gem::Platform.local), "arm === arm64")
- refute((armv5 === Gem::Platform.local), "armv5 === arm64")
- refute((armv7 === Gem::Platform.local), "armv7 === arm64")
- assert((arm64 === Gem::Platform.local), "arm64 === arm64")
+ refute(arm === Gem::Platform.local, "arm === arm64")
+ refute(armv5 === Gem::Platform.local, "armv5 === arm64")
+ refute(armv7 === Gem::Platform.local, "armv7 === arm64")
+ assert(arm64 === Gem::Platform.local, "arm64 === arm64")
end
def test_equals3_universal_mingw
uni_mingw = Gem::Platform.new "universal-mingw"
- mingw32 = Gem::Platform.new "x64-mingw32"
mingw_ucrt = Gem::Platform.new "x64-mingw-ucrt"
- util_set_arch "x64-mingw32"
- assert((uni_mingw === Gem::Platform.local), "uni_mingw === mingw32")
- assert((mingw32 === Gem::Platform.local), "mingw32 === mingw32")
- refute((mingw_ucrt === Gem::Platform.local), "mingw32 === mingw_ucrt")
-
util_set_arch "x64-mingw-ucrt"
- assert((uni_mingw === Gem::Platform.local), "uni_mingw === mingw32")
- assert((mingw_ucrt === Gem::Platform.local), "mingw_ucrt === mingw_ucrt")
- refute((mingw32 === Gem::Platform.local), "mingw32 === mingw_ucrt")
+ assert(uni_mingw === Gem::Platform.local, "uni_mingw === mingw_ucrt")
+ assert(mingw_ucrt === Gem::Platform.local, "mingw_ucrt === mingw_ucrt")
end
def test_equals3_version
@@ -415,11 +416,11 @@ class TestGemPlatform < Gem::TestCase
x86_darwin8 = Gem::Platform.new ["x86", "darwin", "8"]
x86_darwin9 = Gem::Platform.new ["x86", "darwin", "9"]
- assert((x86_darwin === Gem::Platform.local), "x86_darwin === x86_darwin8")
- assert((x86_darwin8 === Gem::Platform.local), "x86_darwin8 === x86_darwin8")
+ assert(x86_darwin === Gem::Platform.local, "x86_darwin === x86_darwin8")
+ assert(x86_darwin8 === Gem::Platform.local, "x86_darwin8 === x86_darwin8")
- refute((x86_darwin7 === Gem::Platform.local), "x86_darwin7 === x86_darwin8")
- refute((x86_darwin9 === Gem::Platform.local), "x86_darwin9 === x86_darwin8")
+ refute(x86_darwin7 === Gem::Platform.local, "x86_darwin7 === x86_darwin8")
+ refute(x86_darwin9 === Gem::Platform.local, "x86_darwin9 === x86_darwin8")
end
def test_equals_tilde
@@ -492,15 +493,171 @@ class TestGemPlatform < Gem::TestCase
assert_equal 1, result.scan(/@version=/).size
end
- def test_gem_platform_match_with_string_argument
- util_set_arch "x86_64-linux-musl"
+ def test_constants
+ assert_equal [nil, "java", nil], Gem::Platform::JAVA.to_a
+ assert_equal ["x86", "mswin32", nil], Gem::Platform::MSWIN.to_a
+ assert_equal [nil, "mswin64", nil], Gem::Platform::MSWIN64.to_a
+ assert_equal ["x86", "mingw32", nil], Gem::Platform::MINGW.to_a
+ assert_equal ["x64", "mingw", "ucrt"], Gem::Platform::X64_MINGW.to_a
+ assert_equal ["universal", "mingw", nil], Gem::Platform::UNIVERSAL_MINGW.to_a
+ assert_equal [["x86", "mswin32", nil], [nil, "mswin64", nil], ["universal", "mingw", nil]], Gem::Platform::WINDOWS.map(&:to_a)
+ assert_equal ["x86_64", "linux", nil], Gem::Platform::X64_LINUX.to_a
+ assert_equal ["x86_64", "linux", "musl"], Gem::Platform::X64_LINUX_MUSL.to_a
+ end
+
+ def test_generic
+ # converts non-windows platforms into ruby
+ assert_equal Gem::Platform::RUBY, Gem::Platform.generic(Gem::Platform.new("x86-darwin-10"))
+ assert_equal Gem::Platform::RUBY, Gem::Platform.generic(Gem::Platform::RUBY)
+
+ # converts java platform variants into java
+ assert_equal Gem::Platform::JAVA, Gem::Platform.generic(Gem::Platform.new("java"))
+ assert_equal Gem::Platform::JAVA, Gem::Platform.generic(Gem::Platform.new("universal-java-17"))
+
+ # converts mswin platform variants into x86-mswin32
+ assert_equal Gem::Platform::MSWIN, Gem::Platform.generic(Gem::Platform.new("mswin32"))
+ assert_equal Gem::Platform::MSWIN, Gem::Platform.generic(Gem::Platform.new("i386-mswin32"))
+ assert_equal Gem::Platform::MSWIN, Gem::Platform.generic(Gem::Platform.new("x86-mswin32"))
+
+ # converts 32-bit mingw platform variants into universal-mingw
+ assert_equal Gem::Platform::UNIVERSAL_MINGW, Gem::Platform.generic(Gem::Platform.new("i386-mingw32"))
+ assert_equal Gem::Platform::UNIVERSAL_MINGW, Gem::Platform.generic(Gem::Platform.new("x86-mingw32"))
+
+ # converts 64-bit mingw platform variants into universal-mingw
+ assert_equal Gem::Platform::UNIVERSAL_MINGW, Gem::Platform.generic(Gem::Platform.new("x64-mingw32"))
- Gem::Deprecate.skip_during do
- assert(Gem::Platform.match(Gem::Platform.new("x86_64-linux")), "should match Gem::Platform")
- assert(Gem::Platform.match("x86_64-linux"), "should match String platform")
+ # converts x64 mingw UCRT platform variants into universal-mingw
+ assert_equal Gem::Platform::UNIVERSAL_MINGW, Gem::Platform.generic(Gem::Platform.new("x64-mingw-ucrt"))
+
+ # converts aarch64 mingw UCRT platform variants into universal-mingw
+ assert_equal Gem::Platform::UNIVERSAL_MINGW, Gem::Platform.generic(Gem::Platform.new("aarch64-mingw-ucrt"))
+
+ assert_equal Gem::Platform::RUBY, Gem::Platform.generic(Gem::Platform.new("unknown"))
+ assert_equal Gem::Platform::RUBY, Gem::Platform.generic(nil)
+ assert_equal Gem::Platform::MSWIN64, Gem::Platform.generic(Gem::Platform.new("mswin64"))
+ end
+
+ def test_platform_specificity_match
+ [
+ ["ruby", "ruby", -1, -1],
+ ["x86_64-linux-musl", "x86_64-linux-musl", -1, -1],
+ ["x86_64-linux", "x86_64-linux-musl", 100, 200],
+ ["universal-darwin", "x86-darwin", 10, 20],
+ ["universal-darwin-19", "x86-darwin", 210, 120],
+ ["universal-darwin-19", "universal-darwin-20", 200, 200],
+ ["arm-darwin-19", "arm64-darwin-19", 0, 20],
+ ].each do |spec_platform, user_platform, s1, s2|
+ spec_platform = Gem::Platform.new(spec_platform)
+ user_platform = Gem::Platform.new(user_platform)
+ assert_equal s1, Gem::Platform.platform_specificity_match(spec_platform, user_platform),
+ "Gem::Platform.platform_specificity_match(#{spec_platform.to_s.inspect}, #{user_platform.to_s.inspect})"
+ assert_equal s2, Gem::Platform.platform_specificity_match(user_platform, spec_platform),
+ "Gem::Platform.platform_specificity_match(#{user_platform.to_s.inspect}, #{spec_platform.to_s.inspect})"
end
end
+ def test_sort_and_filter_best_platform_match
+ a_1 = util_spec "a", "1"
+ a_1_java = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform::JAVA
+ end
+ a_1_universal_darwin = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("universal-darwin")
+ end
+ a_1_universal_darwin_19 = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("universal-darwin-19")
+ end
+ a_1_universal_darwin_20 = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("universal-darwin-20")
+ end
+ a_1_arm_darwin_19 = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("arm64-darwin-19")
+ end
+ a_1_x86_darwin = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("x86-darwin")
+ end
+ specs = [a_1, a_1_java, a_1_universal_darwin, a_1_universal_darwin_19, a_1_universal_darwin_20, a_1_arm_darwin_19, a_1_x86_darwin]
+ assert_equal [a_1], Gem::Platform.sort_and_filter_best_platform_match(specs, "ruby")
+ assert_equal [a_1_java], Gem::Platform.sort_and_filter_best_platform_match(specs, Gem::Platform::JAVA)
+ assert_equal [a_1_arm_darwin_19], Gem::Platform.sort_and_filter_best_platform_match(specs, Gem::Platform.new("arm64-darwin-19"))
+ assert_equal [a_1_universal_darwin_20], Gem::Platform.sort_and_filter_best_platform_match(specs, Gem::Platform.new("arm64-darwin-20"))
+ assert_equal [a_1_universal_darwin_19], Gem::Platform.sort_and_filter_best_platform_match(specs, Gem::Platform.new("x86-darwin-19"))
+ assert_equal [a_1_universal_darwin_20], Gem::Platform.sort_and_filter_best_platform_match(specs, Gem::Platform.new("x86-darwin-20"))
+ assert_equal [a_1_x86_darwin], Gem::Platform.sort_and_filter_best_platform_match(specs, Gem::Platform.new("x86-darwin-21"))
+ end
+
+ def test_sort_best_platform_match
+ a_1 = util_spec "a", "1"
+ a_1_java = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform::JAVA
+ end
+ a_1_universal_darwin = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("universal-darwin")
+ end
+ a_1_universal_darwin_19 = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("universal-darwin-19")
+ end
+ a_1_universal_darwin_20 = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("universal-darwin-20")
+ end
+ a_1_arm_darwin_19 = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("arm64-darwin-19")
+ end
+ a_1_x86_darwin = util_spec "a", "1" do |s|
+ s.platform = Gem::Platform.new("x86-darwin")
+ end
+ specs = [a_1, a_1_java, a_1_universal_darwin, a_1_universal_darwin_19, a_1_universal_darwin_20, a_1_arm_darwin_19, a_1_x86_darwin]
+ assert_equal ["ruby",
+ "java",
+ "universal-darwin",
+ "universal-darwin-19",
+ "universal-darwin-20",
+ "arm64-darwin-19",
+ "x86-darwin"], Gem::Platform.sort_best_platform_match(specs, "ruby").map {|s| s.platform.to_s }
+ assert_equal ["java",
+ "universal-darwin",
+ "x86-darwin",
+ "universal-darwin-19",
+ "universal-darwin-20",
+ "arm64-darwin-19",
+ "ruby"], Gem::Platform.sort_best_platform_match(specs, Gem::Platform::JAVA).map {|s| s.platform.to_s }
+ assert_equal ["arm64-darwin-19",
+ "universal-darwin-19",
+ "universal-darwin",
+ "java",
+ "x86-darwin",
+ "universal-darwin-20",
+ "ruby"], Gem::Platform.sort_best_platform_match(specs, Gem::Platform.new("arm64-darwin-19")).map {|s| s.platform.to_s }
+ assert_equal ["universal-darwin-20",
+ "universal-darwin",
+ "java",
+ "x86-darwin",
+ "arm64-darwin-19",
+ "universal-darwin-19",
+ "ruby"], Gem::Platform.sort_best_platform_match(specs, Gem::Platform.new("arm64-darwin-20")).map {|s| s.platform.to_s }
+ assert_equal ["universal-darwin-19",
+ "arm64-darwin-19",
+ "x86-darwin",
+ "universal-darwin",
+ "java",
+ "universal-darwin-20",
+ "ruby"], Gem::Platform.sort_best_platform_match(specs, Gem::Platform.new("x86-darwin-19")).map {|s| s.platform.to_s }
+ assert_equal ["universal-darwin-20",
+ "x86-darwin",
+ "universal-darwin",
+ "java",
+ "universal-darwin-19",
+ "arm64-darwin-19",
+ "ruby"], Gem::Platform.sort_best_platform_match(specs, Gem::Platform.new("x86-darwin-20")).map {|s| s.platform.to_s }
+ assert_equal ["x86-darwin",
+ "universal-darwin",
+ "java",
+ "universal-darwin-19",
+ "universal-darwin-20",
+ "arm64-darwin-19",
+ "ruby"], Gem::Platform.sort_best_platform_match(specs, Gem::Platform.new("x86-darwin-21")).map {|s| s.platform.to_s }
+ end
+
def assert_local_match(name)
assert_match Gem::Platform.local, name
end
@@ -508,4 +665,38 @@ class TestGemPlatform < Gem::TestCase
def refute_local_match(name)
refute_match Gem::Platform.local, name
end
+
+ def test_deconstruct
+ platform = Gem::Platform.new("x86_64-linux")
+ assert_equal ["x86_64", "linux", nil], platform.deconstruct
+ end
+
+ def test_deconstruct_keys
+ platform = Gem::Platform.new("x86_64-darwin-20")
+ assert_equal({ cpu: "x86_64", os: "darwin", version: "20" }, platform.deconstruct_keys(nil))
+ end
+
+ def test_pattern_matching_array
+ platform = Gem::Platform.new("arm64-darwin-21")
+ result =
+ case platform
+ in ["arm64", "darwin", version]
+ version
+ else
+ "no match"
+ end
+ assert_equal "21", result
+ end
+
+ def test_pattern_matching_hash
+ platform = Gem::Platform.new("x86_64-linux")
+ result =
+ case platform
+ in cpu: "x86_64", os: "linux"
+ "matched"
+ else
+ "no match"
+ end
+ assert_equal "matched", result
+ end
end
diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb
index ca858cfda5..c35da2fc5a 100644
--- a/test/rubygems/test_gem_remote_fetcher.rb
+++ b/test/rubygems/test_gem_remote_fetcher.rb
@@ -60,7 +60,7 @@ class TestGemRemoteFetcher < Gem::TestCase
uri = Gem::URI "http://example/file"
path = File.join @tempdir, "file"
- fetcher = util_fuck_with_fetcher "hello"
+ fetcher = fake_fetcher(uri.to_s, "hello")
data = fetcher.cache_update_path uri, path
@@ -75,7 +75,7 @@ class TestGemRemoteFetcher < Gem::TestCase
path = File.join @tempdir, "file"
data = String.new("\xC8").force_encoding(Encoding::BINARY)
- fetcher = util_fuck_with_fetcher data
+ fetcher = fake_fetcher(uri.to_s, data)
written_data = fetcher.cache_update_path uri, path
@@ -88,7 +88,7 @@ class TestGemRemoteFetcher < Gem::TestCase
uri = Gem::URI "http://example/file"
path = File.join @tempdir, "file"
- fetcher = util_fuck_with_fetcher "hello"
+ fetcher = fake_fetcher(uri.to_s, "hello")
data = fetcher.cache_update_path uri, path, false
@@ -97,103 +97,79 @@ class TestGemRemoteFetcher < Gem::TestCase
assert_path_not_exist path
end
- def util_fuck_with_fetcher(data, blow = false)
- fetcher = Gem::RemoteFetcher.fetcher
- fetcher.instance_variable_set :@test_data, data
-
- if blow
- def fetcher.fetch_path(arg, *rest)
- # OMG I'm such an ass
- class << self; remove_method :fetch_path; end
- def self.fetch_path(arg, *rest)
- @test_arg = arg
- @test_data
- end
+ def test_cache_update_path_overwrites_existing_file
+ uri = Gem::URI "http://example/file"
+ path = File.join @tempdir, "file"
- raise Gem::RemoteFetcher::FetchError.new("haha!", "")
- end
- else
- def fetcher.fetch_path(arg, *rest)
- @test_arg = arg
- @test_data
- end
- end
+ # Create existing file with old content
+ File.write(path, "old content")
+ assert_equal "old content", File.read(path)
+
+ fetcher = fake_fetcher(uri.to_s, "new content")
+
+ data = fetcher.cache_update_path uri, path
- fetcher
+ assert_equal "new content", data
+ assert_equal "new content", File.read(path)
end
def test_download
- a1_data = nil
- File.open @a1_gem, "rb" do |fp|
- a1_data = fp.read
- end
+ a1_data = File.open @a1_gem, "rb", &:read
+ a1_url = "http://gems.example.com/gems/a-1.gem"
- fetcher = util_fuck_with_fetcher a1_data
+ fetcher = fake_fetcher(a1_url, a1_data)
a1_cache_gem = @a1.cache_file
assert_equal a1_cache_gem, fetcher.download(@a1, "http://gems.example.com")
- assert_equal("http://gems.example.com/gems/a-1.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
+ assert_equal a1_url, fetcher.paths.last
assert File.exist?(a1_cache_gem)
end
def test_download_with_auth
- a1_data = nil
- File.open @a1_gem, "rb" do |fp|
- a1_data = fp.read
- end
+ a1_data = File.open @a1_gem, "rb", &:read
+ a1_url = "http://user:password@gems.example.com/gems/a-1.gem"
- fetcher = util_fuck_with_fetcher a1_data
+ fetcher = fake_fetcher(a1_url, a1_data)
a1_cache_gem = @a1.cache_file
assert_equal a1_cache_gem, fetcher.download(@a1, "http://user:password@gems.example.com")
- assert_equal("http://user:password@gems.example.com/gems/a-1.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
+ assert_equal a1_url, fetcher.paths.last
assert File.exist?(a1_cache_gem)
end
def test_download_with_token
- a1_data = nil
- File.open @a1_gem, "rb" do |fp|
- a1_data = fp.read
- end
+ a1_data = File.open @a1_gem, "rb", &:read
+ a1_url = "http://token@gems.example.com/gems/a-1.gem"
- fetcher = util_fuck_with_fetcher a1_data
+ fetcher = fake_fetcher(a1_url, a1_data)
a1_cache_gem = @a1.cache_file
assert_equal a1_cache_gem, fetcher.download(@a1, "http://token@gems.example.com")
- assert_equal("http://token@gems.example.com/gems/a-1.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
+ assert_equal a1_url, fetcher.paths.last
assert File.exist?(a1_cache_gem)
end
def test_download_with_x_oauth_basic
- a1_data = nil
- File.open @a1_gem, "rb" do |fp|
- a1_data = fp.read
- end
+ a1_data = File.open @a1_gem, "rb", &:read
+ a1_url = "http://token:x-oauth-basic@gems.example.com/gems/a-1.gem"
- fetcher = util_fuck_with_fetcher a1_data
+ fetcher = fake_fetcher(a1_url, a1_data)
a1_cache_gem = @a1.cache_file
assert_equal a1_cache_gem, fetcher.download(@a1, "http://token:x-oauth-basic@gems.example.com")
- assert_equal("http://token:x-oauth-basic@gems.example.com/gems/a-1.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
+ assert_equal a1_url, fetcher.paths.last
assert File.exist?(a1_cache_gem)
end
def test_download_with_encoded_auth
- a1_data = nil
- File.open @a1_gem, "rb" do |fp|
- a1_data = fp.read
- end
+ a1_data = File.open @a1_gem, "rb", &:read
+ a1_url = "http://user:%25pas%25sword@gems.example.com/gems/a-1.gem"
- fetcher = util_fuck_with_fetcher a1_data
+ fetcher = fake_fetcher(a1_url, a1_data)
a1_cache_gem = @a1.cache_file
assert_equal a1_cache_gem, fetcher.download(@a1, "http://user:%25pas%25sword@gems.example.com")
- assert_equal("http://user:%25pas%25sword@gems.example.com/gems/a-1.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
+ assert_equal a1_url, fetcher.paths.last
assert File.exist?(a1_cache_gem)
end
@@ -235,8 +211,9 @@ class TestGemRemoteFetcher < Gem::TestCase
def test_download_install_dir
a1_data = File.open @a1_gem, "rb", &:read
+ a1_url = "http://gems.example.com/gems/a-1.gem"
- fetcher = util_fuck_with_fetcher a1_data
+ fetcher = fake_fetcher(a1_url, a1_data)
install_dir = File.join @tempdir, "more_gems"
@@ -245,8 +222,7 @@ class TestGemRemoteFetcher < Gem::TestCase
actual = fetcher.download(@a1, "http://gems.example.com", install_dir)
assert_equal a1_cache_gem, actual
- assert_equal("http://gems.example.com/gems/a-1.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
+ assert_equal a1_url, fetcher.paths.last
assert File.exist?(a1_cache_gem)
end
@@ -282,7 +258,12 @@ class TestGemRemoteFetcher < Gem::TestCase
FileUtils.chmod 0o555, @a1.cache_dir
FileUtils.chmod 0o555, @gemhome
- fetcher = util_fuck_with_fetcher File.read(@a1_gem)
+ fetcher = Gem::RemoteFetcher.fetcher
+ def fetcher.fetch_path(uri, *rest)
+ File.read File.join(@test_gem_dir, "a-1.gem")
+ end
+ fetcher.instance_variable_set(:@test_gem_dir, File.dirname(@a1_gem))
+
fetcher.download(@a1, "http://gems.example.com")
a1_cache_gem = File.join Gem.user_dir, "cache", @a1.file_name
assert File.exist? a1_cache_gem
@@ -301,19 +282,21 @@ class TestGemRemoteFetcher < Gem::TestCase
end
e1.loaded_from = File.join(@gemhome, "specifications", e1.full_name)
- e1_data = nil
- File.open e1_gem, "rb" do |fp|
- e1_data = fp.read
- end
+ e1_data = File.open e1_gem, "rb", &:read
- fetcher = util_fuck_with_fetcher e1_data, :blow_chunks
+ fetcher = Gem::RemoteFetcher.fetcher
+ def fetcher.fetch_path(uri, *rest)
+ @call_count ||= 0
+ @call_count += 1
+ raise Gem::RemoteFetcher::FetchError.new("error", uri) if @call_count == 1
+ @test_data
+ end
+ fetcher.instance_variable_set(:@test_data, e1_data)
e1_cache_gem = e1.cache_file
assert_equal e1_cache_gem, fetcher.download(e1, "http://gems.example.com")
- assert_equal("http://gems.example.com/gems/#{e1.original_name}.gem",
- fetcher.instance_variable_get(:@test_arg).to_s)
assert File.exist?(e1_cache_gem)
end
@@ -592,7 +575,112 @@ class TestGemRemoteFetcher < Gem::TestCase
end
end
- def assert_error(exception_class=Exception)
+ def test_download_with_global_gem_cache
+ # Use a temp directory to safely test global cache behavior
+ test_cache_dir = File.join(@tempdir, "global_gem_cache_test")
+
+ Gem.stub :global_gem_cache_path, test_cache_dir do
+ Gem.configuration.global_gem_cache = true
+
+ # Use the real RemoteFetcher with stubbed fetch_path
+ fetcher = Gem::RemoteFetcher.fetcher
+ def fetcher.fetch_path(uri, *rest)
+ File.binread File.join(@test_gem_dir, "a-1.gem")
+ end
+ fetcher.instance_variable_set(:@test_gem_dir, File.dirname(@a1_gem))
+
+ # With global cache enabled, gem goes directly to global cache
+ global_cache_gem = File.join(test_cache_dir, @a1.file_name)
+ assert_equal global_cache_gem, fetcher.download(@a1, "http://gems.example.com")
+ assert File.exist?(global_cache_gem), "Gem should be in global cache"
+ end
+ ensure
+ Gem.configuration.global_gem_cache = false
+ end
+
+ def test_download_uses_global_gem_cache
+ # Use a temp directory to safely test global cache behavior
+ test_cache_dir = File.join(@tempdir, "global_gem_cache_test")
+
+ Gem.stub :global_gem_cache_path, test_cache_dir do
+ Gem.configuration.global_gem_cache = true
+
+ # Pre-populate global cache
+ FileUtils.mkdir_p test_cache_dir
+ global_cache_gem = File.join(test_cache_dir, @a1.file_name)
+ FileUtils.cp @a1_gem, global_cache_gem
+
+ fetcher = Gem::RemoteFetcher.fetcher
+
+ # Should return global cache path without downloading
+ result = fetcher.download(@a1, "http://gems.example.com")
+ assert_equal global_cache_gem, result
+ end
+ ensure
+ Gem.configuration.global_gem_cache = false
+ end
+
+ def test_download_without_global_gem_cache
+ # Use a temp directory to safely test global cache behavior
+ test_cache_dir = File.join(@tempdir, "global_gem_cache_test")
+
+ Gem.stub :global_gem_cache_path, test_cache_dir do
+ Gem.configuration.global_gem_cache = false
+
+ # Use the real RemoteFetcher with stubbed fetch_path
+ fetcher = Gem::RemoteFetcher.fetcher
+ def fetcher.fetch_path(uri, *rest)
+ File.binread File.join(@test_gem_dir, "a-1.gem")
+ end
+ fetcher.instance_variable_set(:@test_gem_dir, File.dirname(@a1_gem))
+
+ a1_cache_gem = @a1.cache_file
+ assert_equal a1_cache_gem, fetcher.download(@a1, "http://gems.example.com")
+
+ # Verify gem was NOT copied to global cache
+ global_cache_gem = File.join(test_cache_dir, @a1.file_name)
+ refute File.exist?(global_cache_gem), "Gem should not be copied to global cache when disabled"
+ end
+ end
+
+ def test_fetch_http_with_custom_error_header
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ url = "http://gems.example.com/error"
+
+ def fetcher.request(uri, request_class, last_modified = nil)
+ res = Gem::Net::HTTPBadRequest.new nil, 403, "Forbidden"
+ res.add_field "X-Error-Message", "Component blocked by policy"
+ res
+ end
+
+ e = assert_raise Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_http Gem::URI.parse(url)
+ end
+
+ assert_equal "Bad response Component blocked by policy 403 (#{url})", e.message
+ end
+
+ def test_fetch_http_without_custom_error_header
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ url = "http://gems.example.com/error"
+
+ def fetcher.request(uri, request_class, last_modified = nil)
+ res = Gem::Net::HTTPBadRequest.new nil, 403, "Forbidden"
+ res
+ end
+
+ e = assert_raise Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_http Gem::URI.parse(url)
+ end
+
+ assert_equal "Bad response Forbidden 403 (#{url})", e.message
+ end
+
+ private
+
+ def assert_error(exception_class = Exception)
got_exception = false
begin
@@ -603,4 +691,13 @@ class TestGemRemoteFetcher < Gem::TestCase
assert got_exception, "Expected exception conforming to #{exception_class}"
end
+
+ def fake_fetcher(url, data)
+ original_fetcher = Gem::RemoteFetcher.fetcher
+ fetcher = Gem::FakeFetcher.new
+ fetcher.data[url] = data
+ Gem::RemoteFetcher.fetcher = fetcher
+ ensure
+ Gem::RemoteFetcher.fetcher = original_fetcher
+ end
end
diff --git a/test/rubygems/test_gem_remote_fetcher_s3.rb b/test/rubygems/test_gem_remote_fetcher_s3.rb
index fe7eb7ec01..4a5acc5a86 100644
--- a/test/rubygems/test_gem_remote_fetcher_s3.rb
+++ b/test/rubygems/test_gem_remote_fetcher_s3.rb
@@ -8,6 +8,100 @@ require "rubygems/package"
class TestGemRemoteFetcherS3 < Gem::TestCase
include Gem::DefaultUserInteraction
+ class FakeGemRequest < Gem::Request
+ attr_reader :last_request, :uri
+
+ # Override perform_request to stub things
+ def perform_request(request)
+ @last_request = request
+ @response
+ end
+
+ def set_response(response)
+ @response = response
+ end
+ end
+
+ class FakeS3URISigner < Gem::S3URISigner
+ class << self
+ attr_accessor :return_token, :instance_profile
+ end
+
+ # Convenience method to output the recent aws iam queries made in tests
+ # this outputs the verb, path, and any non-generic headers
+ def recent_aws_query_logs
+ sreqs = @aws_iam_calls.map do |c|
+ r = c.last_request
+ s = +"#{r.method} #{c.uri}\n"
+ r.each_header do |key, v|
+ # Only include headers that start with x-
+ next unless key.start_with?("x-")
+ s << " #{key}=#{v}\n"
+ end
+ s
+ end
+
+ sreqs.join("")
+ end
+
+ def initialize(uri, method)
+ @aws_iam_calls = []
+ super
+ end
+
+ def ec2_iam_request(uri, verb)
+ fake_s3_request = FakeGemRequest.new(uri, verb, nil, nil)
+ @aws_iam_calls << fake_s3_request
+
+ case uri.to_s
+ when "http://169.254.169.254/latest/api/token"
+ if FakeS3URISigner.return_token.nil?
+ res = Gem::Net::HTTPUnauthorized.new nil, 401, nil
+ def res.body = "you got a 401! panic!"
+ else
+ res = Gem::Net::HTTPOK.new nil, 200, nil
+ def res.body = FakeS3URISigner.return_token
+ end
+ when "http://169.254.169.254/latest/meta-data/iam/info"
+ res = Gem::Net::HTTPOK.new nil, 200, nil
+ def res.body
+ <<~JSON
+ {
+ "Code": "Success",
+ "LastUpdated": "2023-05-27:05:05",
+ "InstanceProfileArn": "arn:aws:iam::somesecretid:instance-profile/TestRole",
+ "InstanceProfileId": "SOMEPROFILEID"
+ }
+ JSON
+ end
+
+ when "http://169.254.169.254/latest/meta-data/iam/security-credentials/TestRole"
+ res = Gem::Net::HTTPOK.new nil, 200, nil
+ def res.body = FakeS3URISigner.instance_profile
+ else
+ raise "Unexpected request to #{uri}"
+ end
+
+ fake_s3_request.set_response(res)
+ fake_s3_request
+ end
+ end
+
+ class FakeGemFetcher < Gem::RemoteFetcher
+ attr_reader :fetched_uri, :last_s3_uri_signer
+
+ def request(uri, request_class, last_modified = nil)
+ @fetched_uri = uri
+ res = Gem::Net::HTTPOK.new nil, 200, nil
+ def res.body = "success"
+ res
+ end
+
+ def s3_uri_signer(uri, method)
+ @last_s3_uri_signer = FakeS3URISigner.new(uri, method)
+ end
+ end
+
def setup
super
@@ -18,39 +112,61 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
@a1.loaded_from = File.join(@gemhome, "specifications", @a1.full_name)
end
- def assert_fetch_s3(url, signature, token=nil, region="us-east-1", instance_profile_json=nil)
- fetcher = Gem::RemoteFetcher.new nil
- @fetcher = fetcher
- $fetched_uri = nil
- $instance_profile = instance_profile_json
+ def assert_fetched_s3_with_imds_v2(expected_token)
+ # Three API requests:
+ # 1. Get the token
+ # 2. Lookup profile details
+ # 3. Query the credentials
+ expected = <<~TEXT
+ PUT http://169.254.169.254/latest/api/token
+ x-aws-ec2-metadata-token-ttl-seconds=60
+ GET http://169.254.169.254/latest/meta-data/iam/info
+ x-aws-ec2-metadata-token=#{expected_token}
+ GET http://169.254.169.254/latest/meta-data/iam/security-credentials/TestRole
+ x-aws-ec2-metadata-token=#{expected_token}
+ TEXT
+ recent_aws_query_logs = @fetcher.last_s3_uri_signer.recent_aws_query_logs
+ assert_equal(expected.strip, recent_aws_query_logs.strip)
+ end
- def fetcher.request(uri, request_class, last_modified = nil)
- $fetched_uri = uri
- res = Gem::Net::HTTPOK.new nil, 200, nil
- def res.body
- "success"
- end
- res
- end
+ def assert_fetched_s3_with_imds_v1
+ # Three API requests:
+ # 1. Get the token (which fails)
+ # 2. Lookup profile details without token
+ # 3. Query the credentials without token
+ expected = <<~TEXT
+ PUT http://169.254.169.254/latest/api/token
+ x-aws-ec2-metadata-token-ttl-seconds=60
+ GET http://169.254.169.254/latest/meta-data/iam/info
+ GET http://169.254.169.254/latest/meta-data/iam/security-credentials/TestRole
+ TEXT
+ recent_aws_query_logs = @fetcher.last_s3_uri_signer.recent_aws_query_logs
+ assert_equal(expected.strip, recent_aws_query_logs.strip)
+ end
- def fetcher.s3_uri_signer(uri)
- require "json"
- s3_uri_signer = Gem::S3URISigner.new(uri)
- def s3_uri_signer.ec2_metadata_credentials_json
- JSON.parse($instance_profile)
- end
- # Running sign operation to make sure uri.query is not mutated
- s3_uri_signer.sign
- raise "URI query is not empty: #{uri.query}" unless uri.query.nil?
- s3_uri_signer
- end
+ def with_imds_v2_failure
+ FakeS3URISigner.should_fail = true
+ yield(fetcher)
+ ensure
+ FakeS3URISigner.should_fail = false
+ end
- data = fetcher.fetch_s3 Gem::URI.parse(url)
+ def assert_fetch_s3(url:, signature:, token: nil, region: "us-east-1", instance_profile_json: nil, fetcher: nil, method: "GET")
+ FakeS3URISigner.instance_profile = instance_profile_json
+ FakeS3URISigner.return_token = token
- assert_equal "https://my-bucket.s3.#{region}.amazonaws.com/gems/specs.4.8.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=testuser%2F20190624%2F#{region}%2Fs3%2Faws4_request&X-Amz-Date=20190624T050641Z&X-Amz-Expires=86400#{token ? "&X-Amz-Security-Token=" + token : ""}&X-Amz-SignedHeaders=host&X-Amz-Signature=#{signature}", $fetched_uri.to_s
- assert_equal "success", data
+ @fetcher = fetcher || FakeGemFetcher.new(nil)
+ res = @fetcher.fetch_s3 Gem::URI.parse(url), nil, (method == "HEAD")
+
+ assert_equal "https://my-bucket.s3.#{region}.amazonaws.com/gems/specs.4.8.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=testuser%2F20190624%2F#{region}%2Fs3%2Faws4_request&X-Amz-Date=20190624T051941Z&X-Amz-Expires=86400#{token ? "&X-Amz-Security-Token=" + token : ""}&X-Amz-SignedHeaders=host&X-Amz-Signature=#{signature}", @fetcher.fetched_uri.to_s
+ if method == "HEAD"
+ assert_equal 200, res.code
+ else
+ assert_equal "success", res
+ end
ensure
- $fetched_uri = nil
+ FakeS3URISigner.instance_profile = nil
+ FakeS3URISigner.return_token = nil
end
def test_fetch_s3_config_creds
@@ -59,7 +175,34 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "20f974027db2f3cd6193565327a7c73457a138efb1a63ea248d185ce6827d41b"
+ assert_fetch_s3(
+ url: url,
+ signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c",
+ )
+ end
+ ensure
+ Gem.configuration[:s3_source] = nil
+ end
+
+ def test_fetch_s3_head_request
+ Gem.configuration[:s3_source] = {
+ "my-bucket" => { id: "testuser", secret: "testpass" },
+ }
+ url = "s3://my-bucket/gems/specs.4.8.gz"
+ Time.stub :now, Time.at(1_561_353_581) do
+ token = nil
+ region = "us-east-1"
+ instance_profile_json = nil
+ method = "HEAD"
+
+ assert_fetch_s3(
+ url: url,
+ signature: "a3c6cf9a2db62e85f4e57f8fc8ac8b5ff5c1fdd4aeef55935d05e05174d9c885",
+ token: token,
+ region: region,
+ instance_profile_json: instance_profile_json,
+ method: method
+ )
end
ensure
Gem.configuration[:s3_source] = nil
@@ -71,7 +214,11 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "4afc3010757f1fd143e769f1d1dabd406476a4fc7c120e9884fd02acbb8f26c9", nil, "us-west-2"
+ assert_fetch_s3(
+ url: url,
+ signature: "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716",
+ region: "us-west-2"
+ )
end
ensure
Gem.configuration[:s3_source] = nil
@@ -83,7 +230,11 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "935160a427ef97e7630f799232b8f208c4a4e49aad07d0540572a2ad5fe9f93c", "testtoken"
+ assert_fetch_s3(
+ url: url,
+ signature: "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625",
+ token: "testtoken"
+ )
end
ensure
Gem.configuration[:s3_source] = nil
@@ -98,7 +249,10 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "20f974027db2f3cd6193565327a7c73457a138efb1a63ea248d185ce6827d41b"
+ assert_fetch_s3(
+ url: url,
+ signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
+ )
end
ensure
ENV.each_key {|key| ENV.delete(key) if key.start_with?("AWS") }
@@ -114,7 +268,12 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "4afc3010757f1fd143e769f1d1dabd406476a4fc7c120e9884fd02acbb8f26c9", nil, "us-west-2"
+ assert_fetch_s3(
+ url: url,
+ signature: "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716",
+ token: nil,
+ region: "us-west-2"
+ )
end
ensure
ENV.each_key {|key| ENV.delete(key) if key.start_with?("AWS") }
@@ -130,7 +289,11 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "935160a427ef97e7630f799232b8f208c4a4e49aad07d0540572a2ad5fe9f93c", "testtoken"
+ assert_fetch_s3(
+ url: url,
+ signature: "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625",
+ token: "testtoken"
+ )
end
ensure
ENV.each_key {|key| ENV.delete(key) if key.start_with?("AWS") }
@@ -140,7 +303,10 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
def test_fetch_s3_url_creds
url = "s3://testuser:testpass@my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "20f974027db2f3cd6193565327a7c73457a138efb1a63ea248d185ce6827d41b"
+ assert_fetch_s3(
+ url: url,
+ signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
+ )
end
end
@@ -151,8 +317,14 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "20f974027db2f3cd6193565327a7c73457a138efb1a63ea248d185ce6827d41b", nil, "us-east-1",
- '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass"}'
+ assert_fetch_s3(
+ url: url,
+ signature: "da82e098bdaed0d3087047670efc98eaadc20559a473b5eac8d70190d2a9e8fd",
+ region: "us-east-1",
+ token: "mysecrettoken",
+ instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "mysecrettoken"}'
+ )
+ assert_fetched_s3_with_imds_v2("mysecrettoken")
end
ensure
Gem.configuration[:s3_source] = nil
@@ -165,8 +337,14 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "4afc3010757f1fd143e769f1d1dabd406476a4fc7c120e9884fd02acbb8f26c9", nil, "us-west-2",
- '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass"}'
+ assert_fetch_s3(
+ url: url,
+ signature: "532960594dbfe31d1bbfc0e8e7a666c3cbdd8b00a143774da51b7f920704afd2",
+ region: "us-west-2",
+ token: "mysecrettoken",
+ instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "mysecrettoken"}'
+ )
+ assert_fetched_s3_with_imds_v2("mysecrettoken")
end
ensure
Gem.configuration[:s3_source] = nil
@@ -179,14 +357,40 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
url = "s3://my-bucket/gems/specs.4.8.gz"
Time.stub :now, Time.at(1_561_353_581) do
- assert_fetch_s3 url, "935160a427ef97e7630f799232b8f208c4a4e49aad07d0540572a2ad5fe9f93c", "testtoken", "us-east-1",
- '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "testtoken"}'
+ assert_fetch_s3(
+ url: url,
+ signature: "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625",
+ token: "testtoken",
+ region: "us-east-1",
+ instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "testtoken"}'
+ )
+ assert_fetched_s3_with_imds_v2("testtoken")
+ end
+ ensure
+ Gem.configuration[:s3_source] = nil
+ end
+
+ def test_fetch_s3_instance_profile_creds_with_fallback
+ Gem.configuration[:s3_source] = {
+ "my-bucket" => { provider: "instance_profile" },
+ }
+
+ url = "s3://my-bucket/gems/specs.4.8.gz"
+ Time.stub :now, Time.at(1_561_353_581) do
+ assert_fetch_s3(
+ url: url,
+ signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c",
+ token: nil,
+ region: "us-east-1",
+ instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass"}'
+ )
+ assert_fetched_s3_with_imds_v1
end
ensure
Gem.configuration[:s3_source] = nil
end
- def refute_fetch_s3(url, expected_message)
+ def refute_fetch_s3(url:, expected_message:)
fetcher = Gem::RemoteFetcher.new nil
@fetcher = fetcher
@@ -199,7 +403,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
def test_fetch_s3_no_source_key
url = "s3://my-bucket/gems/specs.4.8.gz"
- refute_fetch_s3 url, "no s3_source key exists in .gemrc"
+ refute_fetch_s3(url: url, expected_message: "no s3_source key exists in .gemrc")
end
def test_fetch_s3_no_host
@@ -208,7 +412,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
}
url = "s3://other-bucket/gems/specs.4.8.gz"
- refute_fetch_s3 url, "no key for host other-bucket in s3_source in .gemrc"
+ refute_fetch_s3(url: url, expected_message: "no key for host other-bucket in s3_source in .gemrc")
ensure
Gem.configuration[:s3_source] = nil
end
@@ -217,7 +421,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
Gem.configuration[:s3_source] = { "my-bucket" => { secret: "testpass" } }
url = "s3://my-bucket/gems/specs.4.8.gz"
- refute_fetch_s3 url, "s3_source for my-bucket missing id or secret"
+ refute_fetch_s3(url: url, expected_message: "s3_source for my-bucket missing id or secret")
ensure
Gem.configuration[:s3_source] = nil
end
@@ -226,7 +430,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
Gem.configuration[:s3_source] = { "my-bucket" => { id: "testuser" } }
url = "s3://my-bucket/gems/specs.4.8.gz"
- refute_fetch_s3 url, "s3_source for my-bucket missing id or secret"
+ refute_fetch_s3(url: url, expected_message: "s3_source for my-bucket missing id or secret")
ensure
Gem.configuration[:s3_source] = nil
end
diff --git a/test/rubygems/test_gem_request.rb b/test/rubygems/test_gem_request.rb
index eb15eed749..cd0a416e79 100644
--- a/test/rubygems/test_gem_request.rb
+++ b/test/rubygems/test_gem_request.rb
@@ -248,7 +248,7 @@ class TestGemRequest < Gem::TestCase
auth_header = conn.payload["Authorization"]
assert_equal "Basic #{base64_encode64("{DEScede}pass:x-oauth-basic")}".strip, auth_header
- assert_includes @ui.output, "GET https://REDACTED:x-oauth-basic@example.rubygems/specs.#{Gem.marshal_version}"
+ assert_includes @ui.output, "GET https://REDACTED@example.rubygems/specs.#{Gem.marshal_version}"
end
def test_fetch_head
@@ -363,19 +363,19 @@ class TestGemRequest < Gem::TestCase
def test_verify_certificate_extra_message
pend if Gem.java_platform?
- error_number = OpenSSL::X509::V_ERR_INVALID_CA
+ error_number = OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
store = OpenSSL::X509::Store.new
- context = OpenSSL::X509::StoreContext.new store
- context.error = error_number
+ context = OpenSSL::X509::StoreContext.new store, CHILD_CERT
+ context.verify
use_ui @ui do
Gem::Request.verify_certificate context
end
expected = <<-ERROR
-ERROR: SSL verification error at depth 0: invalid CA certificate (#{error_number})
-ERROR: Certificate is an invalid CA certificate
+ERROR: SSL verification error at depth 0: unable to get local issuer certificate (#{error_number})
+ERROR: You must add #{CHILD_CERT.issuer} to your local trusted store
ERROR
assert_equal expected, @ui.error
diff --git a/test/rubygems/test_gem_request_connection_pools.rb b/test/rubygems/test_gem_request_connection_pools.rb
index 966447bff6..2860deabf7 100644
--- a/test/rubygems/test_gem_request_connection_pools.rb
+++ b/test/rubygems/test_gem_request_connection_pools.rb
@@ -148,4 +148,16 @@ class TestGemRequestConnectionPool < Gem::TestCase
end
end.join
end
+
+ def test_checkouts_multiple_connections_from_the_pool
+ uri = Gem::URI.parse("http://example/some_endpoint")
+ pools = Gem::Request::ConnectionPools.new nil, [], 2
+ pool = pools.pool_for uri
+
+ pool.checkout
+
+ Thread.new do
+ assert_not_nil(pool.checkout)
+ end.join
+ end
end
diff --git a/test/rubygems/test_gem_request_set.rb b/test/rubygems/test_gem_request_set.rb
index 9aa244892c..33054aa8e5 100644
--- a/test/rubygems/test_gem_request_set.rb
+++ b/test/rubygems/test_gem_request_set.rb
@@ -93,6 +93,34 @@ Gems to install:
end
end
+ def test_install_from_gemdeps_explain_verbose
+ spec_fetcher do |fetcher|
+ fetcher.gem "a", 2
+ end
+
+ rs = Gem::RequestSet.new
+
+ verbose = Gem.configuration.verbose
+ Gem.configuration.verbose = :really
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "a"'
+ io.flush
+
+ expected = <<-EXPECTED
+Gems to install:
+ a-2
+ EXPECTED
+
+ actual, _ = capture_output do
+ rs.install_from_gemdeps gemdeps: io.path, explain: true
+ end
+ assert_equal(expected, actual)
+ end
+ ensure
+ Gem.configuration.verbose = verbose
+ end
+
def test_install_from_gemdeps_install_dir
spec_fetcher do |fetcher|
fetcher.gem "a", 2
@@ -311,6 +339,110 @@ ruby "0"
assert_empty rs.dependencies
end
+ def test_load_gemdeps_with_lockfile_gem_section
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "b"'
+ end
+
+ File.open "gem.deps.rb.lock", "w" do |io|
+ io.puts <<~LOCKFILE
+ GEM
+ remote: #{@gem_repo}
+ specs:
+ a (1)
+ b (1)
+ a (~> 1.0)
+
+ PLATFORMS
+ #{Gem::Platform::RUBY}
+
+ DEPENDENCIES
+ b
+ LOCKFILE
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ lock_set = rs.sets.find {|set| Gem::Resolver::LockSet === set }
+ refute_nil lock_set, "LockSet should be created from GEM section"
+ assert_equal %w[a-1 b-1], lock_set.specs.map(&:full_name).sort
+ end
+
+ def test_load_gemdeps_with_lockfile_git_section
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "a", :git => "git://example/a.git"'
+ end
+
+ File.open "gem.deps.rb.lock", "w" do |io|
+ io.puts <<~LOCKFILE
+ GIT
+ remote: git://example/a.git
+ revision: deadbeef
+ specs:
+ a (1)
+
+ PLATFORMS
+ #{Gem::Platform::RUBY}
+
+ DEPENDENCIES
+ a!
+ LOCKFILE
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ git_set = rs.sets.find {|set| Gem::Resolver::GitSet === set }
+ refute_nil git_set, "GitSet should be created from GIT section"
+ assert_includes git_set.specs.keys, "a"
+ end
+
+ def test_load_gemdeps_with_lockfile_path_section
+ _, _, directory = vendor_gem
+
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts "gem \"a\", :path => #{directory.inspect}"
+ end
+
+ File.open "gem.deps.rb.lock", "w" do |io|
+ io.puts <<~LOCKFILE
+ PATH
+ remote: #{directory}
+ specs:
+ a (1)
+
+ PLATFORMS
+ #{Gem::Platform::RUBY}
+
+ DEPENDENCIES
+ a!
+ LOCKFILE
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ vendor_set = rs.sets.find {|set| Gem::Resolver::VendorSet === set }
+ refute_nil vendor_set, "VendorSet should be created from PATH section"
+ assert_equal %w[a-1], vendor_set.specs.values.map(&:full_name)
+ end
+
+ def test_load_gemdeps_with_missing_lockfile
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "a"'
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ assert_equal [dep("a")], rs.dependencies
+ end
+
def test_resolve
a = util_spec "a", "2", "b" => ">= 2"
b = util_spec "b", "2"
diff --git a/test/rubygems/test_gem_request_set_lockfile_parser.rb b/test/rubygems/test_gem_request_set_lockfile_parser.rb
deleted file mode 100644
index 253a59b243..0000000000
--- a/test/rubygems/test_gem_request_set_lockfile_parser.rb
+++ /dev/null
@@ -1,544 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-require "rubygems/request_set"
-require "rubygems/request_set/lockfile"
-require "rubygems/request_set/lockfile/tokenizer"
-require "rubygems/request_set/lockfile/parser"
-
-class TestGemRequestSetLockfileParser < Gem::TestCase
- def setup
- super
- @gem_deps_file = "gem.deps.rb"
- @lock_file = File.expand_path "#{@gem_deps_file}.lock"
- @set = Gem::RequestSet.new
- end
-
- def test_get
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
- parser = tokenizer.make_parser nil, nil
-
- assert_equal :newline, parser.get.first
- end
-
- def test_get_type_mismatch
- filename = File.expand_path("#{@gem_deps_file}.lock")
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "foo", filename, 1, 0
- parser = tokenizer.make_parser nil, nil
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- parser.get :section
- end
-
- expected =
- 'unexpected token [:text, "foo"], expected :section (at line 1 column 0)'
-
- assert_equal expected, e.message
-
- assert_equal 1, e.line
- assert_equal 0, e.column
- assert_equal filename, e.path
- end
-
- def test_get_type_multiple
- filename = File.expand_path("#{@gem_deps_file}.lock")
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "x", filename, 1
- parser = tokenizer.make_parser nil, nil
-
- assert parser.get [:text, :section]
- end
-
- def test_get_type_value_mismatch
- filename = File.expand_path("#{@gem_deps_file}.lock")
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "x", filename, 1
- parser = tokenizer.make_parser nil, nil
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- parser.get :text, "y"
- end
-
- expected =
- 'unexpected token [:text, "x"], expected [:text, "y"] (at line 1 column 0)'
-
- assert_equal expected, e.message
-
- assert_equal 1, e.line
- assert_equal 0, e.column
- assert_equal File.expand_path("#{@gem_deps_file}.lock"), e.path
- end
-
- def test_parse
- write_lockfile <<-LOCKFILE.strip
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a
- LOCKFILE
-
- platforms = []
- parse_lockfile @set, platforms
-
- assert_equal [dep("a")], @set.dependencies
-
- assert_equal [Gem::Platform::RUBY], platforms
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "could not find a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
- end
-
- def test_parse_dependencies
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a (>= 1, <= 2)
- LOCKFILE
-
- platforms = []
- parse_lockfile @set, platforms
-
- assert_equal [dep("a", ">= 1", "<= 2")], @set.dependencies
-
- assert_equal [Gem::Platform::RUBY], platforms
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "could not find a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
- end
-
- def test_parse_DEPENDENCIES_git
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://git.example/josevalim/rails-footnotes.git
- revision: 3a6ac1971e91d822f057650cc5916ebfcbd6ee37
- specs:
- rails-footnotes (3.7.9)
- rails (>= 3.0.0)
-
-GIT
- remote: git://git.example/svenfuchs/i18n-active_record.git
- revision: 55507cf59f8f2173d38e07e18df0e90d25b1f0f6
- specs:
- i18n-active_record (0.0.2)
- i18n (>= 0.5.0)
-
-GEM
- remote: http://gems.example/
- specs:
- i18n (0.6.9)
- rails (4.0.0)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- i18n-active_record!
- rails-footnotes!
- LOCKFILE
-
- parse_lockfile @set, []
-
- expected = [
- dep("i18n-active_record", "= 0.0.2"),
- dep("rails-footnotes", "= 3.7.9"),
- ]
-
- assert_equal expected, @set.dependencies
- end
-
- def test_parse_DEPENDENCIES_git_version
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://github.com/progrium/ruby-jwt.git
- revision: 8d74770c6cd92ea234b428b5d0c1f18306a4f41c
- specs:
- jwt (1.1)
-
-GEM
- remote: http://gems.example/
- specs:
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- jwt (= 1.1)!
- LOCKFILE
-
- parse_lockfile @set, []
-
- expected = [
- dep("jwt", "= 1.1"),
- ]
-
- assert_equal expected, @set.dependencies
- end
-
- def test_parse_GEM
- write_lockfile <<-LOCKFILE
-GEM
- specs:
- a (2)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- a
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", ">= 0")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "found a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
- end
-
- def test_parse_GEM_remote_multiple
- write_lockfile <<-LOCKFILE
-GEM
- remote: https://gems.example/
- remote: https://other.example/
- specs:
- a (2)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- a
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", ">= 0")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "found a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
-
- assert_equal %w[https://gems.example/ https://other.example/],
- lockfile_set.specs.flat_map {|s| s.sources.map {|src| src.uri.to_s } }
- end
-
- def test_parse_GIT
- @set.instance_variable_set :@install_dir, "install_dir"
-
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: abranch
- specs:
- a (2)
- b (>= 3)
- c
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- assert_equal %w[a-2], git_set.specs.values.map(&:full_name)
-
- assert_equal [dep("b", ">= 3"), dep("c")],
- git_set.specs.values.first.dependencies
-
- expected = {
- "a" => %w[git://example/a.git abranch],
- }
-
- assert_equal expected, git_set.repositories
- assert_equal "install_dir", git_set.root_dir
- end
-
- def test_parse_GIT_branch
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: 1234abc
- branch: 0-9-12-stable
- specs:
- a (2)
- b (>= 3)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- expected = {
- "a" => %w[git://example/a.git 1234abc],
- }
-
- assert_equal expected, git_set.repositories
- end
-
- def test_parse_GIT_ref
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: 1234abc
- ref: 1234abc
- specs:
- a (2)
- b (>= 3)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- expected = {
- "a" => %w[git://example/a.git 1234abc],
- }
-
- assert_equal expected, git_set.repositories
- end
-
- def test_parse_GIT_tag
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: 1234abc
- tag: v0.9.12
- specs:
- a (2)
- b (>= 3)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- expected = {
- "a" => %w[git://example/a.git 1234abc],
- }
-
- assert_equal expected, git_set.repositories
- end
-
- def test_parse_PATH
- _, _, directory = vendor_gem
-
- write_lockfile <<-LOCKFILE
-PATH
- remote: #{directory}
- specs:
- a (1)
- b (2)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 1")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- vendor_set = @set.sets.find do |set|
- Gem::Resolver::VendorSet === set
- end
-
- assert vendor_set, "could not find a VendorSet"
-
- assert_equal %w[a-1], vendor_set.specs.values.map(&:full_name)
-
- spec = vendor_set.load_spec "a", nil, nil, nil
-
- assert_equal [dep("b", "= 2")], spec.dependencies
- end
-
- def test_parse_dependency
- write_lockfile " 1)"
-
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file
- parser = tokenizer.make_parser nil, nil
-
- parsed = parser.parse_dependency "a", "="
-
- assert_equal dep("a", "= 1"), parsed
-
- write_lockfile ")"
-
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file
- parser = tokenizer.make_parser nil, nil
-
- parsed = parser.parse_dependency "a", "2"
-
- assert_equal dep("a", "= 2"), parsed
- end
-
- def test_parse_gem_specs_dependency
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
- b (= 3)
- c (~> 4)
- d
- e (~> 5.0, >= 5.0.1)
- b (3-x86_64-linux)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a
- LOCKFILE
-
- platforms = []
- parse_lockfile @set, platforms
-
- assert_equal [dep("a")], @set.dependencies
-
- assert_equal [Gem::Platform::RUBY], platforms
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "could not find a LockSet"
-
- assert_equal %w[a-2 b-3], lockfile_set.specs.map(&:full_name)
-
- expected = [
- Gem::Platform::RUBY,
- Gem::Platform.new("x86_64-linux"),
- ]
-
- assert_equal expected, lockfile_set.specs.map(&:platform)
-
- spec = lockfile_set.specs.first
-
- expected = [
- dep("b", "= 3"),
- dep("c", "~> 4"),
- dep("d"),
- dep("e", "~> 5.0", ">= 5.0.1"),
- ]
-
- assert_equal expected, spec.dependencies
- end
-
- def test_parse_missing
- assert_raise(Errno::ENOENT) do
- parse_lockfile @set, []
- end
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set
- end
-
- def write_lockfile(lockfile)
- File.open @lock_file, "w" do |io|
- io.write lockfile
- end
- end
-
- def parse_lockfile(set, platforms)
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file
- parser = tokenizer.make_parser set, platforms
- parser.parse
- end
-end
diff --git a/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb b/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb
deleted file mode 100644
index dce8c9ada5..0000000000
--- a/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb
+++ /dev/null
@@ -1,307 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-require "rubygems/request_set"
-require "rubygems/request_set/lockfile"
-require "rubygems/request_set/lockfile/tokenizer"
-require "rubygems/request_set/lockfile/parser"
-
-class TestGemRequestSetLockfileTokenizer < Gem::TestCase
- def setup
- super
-
- @gem_deps_file = "gem.deps.rb"
- @lock_file = File.expand_path "#{@gem_deps_file}.lock"
- end
-
- def test_peek
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
-
- assert_equal :newline, tokenizer.peek.first
-
- assert_equal :newline, tokenizer.next_token.first
-
- assert_equal :EOF, tokenizer.peek.first
- end
-
- def test_skip
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
-
- refute_predicate tokenizer, :empty?
-
- tokenizer.skip :newline
-
- assert_empty tokenizer
- end
-
- def test_token_pos
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new ""
- assert_equal [5, 0], tokenizer.token_pos(5)
-
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "", nil, 1, 2
- assert_equal [3, 1], tokenizer.token_pos(5)
- end
-
- def test_tokenize
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
- b (= 2)
- c (!= 3)
- d (> 4)
- e (< 5)
- f (>= 6)
- g (<= 7)
- h (~> 8)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a
- LOCKFILE
-
- expected = [
- [:section, "GEM", 0, 0],
- [:newline, nil, 3, 0],
-
- [:entry, "remote", 2, 1],
- [:text, @gem_repo, 10, 1],
- [:newline, nil, 34, 1],
-
- [:entry, "specs", 2, 2],
- [:newline, nil, 8, 2],
-
- [:text, "a", 4, 3],
- [:l_paren, nil, 6, 3],
- [:text, "2", 7, 3],
- [:r_paren, nil, 8, 3],
- [:newline, nil, 9, 3],
-
- [:text, "b", 6, 4],
- [:l_paren, nil, 8, 4],
- [:requirement, "=", 9, 4],
- [:text, "2", 11, 4],
- [:r_paren, nil, 12, 4],
- [:newline, nil, 13, 4],
-
- [:text, "c", 6, 5],
- [:l_paren, nil, 8, 5],
- [:requirement, "!=", 9, 5],
- [:text, "3", 12, 5],
- [:r_paren, nil, 13, 5],
- [:newline, nil, 14, 5],
-
- [:text, "d", 6, 6],
- [:l_paren, nil, 8, 6],
- [:requirement, ">", 9, 6],
- [:text, "4", 11, 6],
- [:r_paren, nil, 12, 6],
- [:newline, nil, 13, 6],
-
- [:text, "e", 6, 7],
- [:l_paren, nil, 8, 7],
- [:requirement, "<", 9, 7],
- [:text, "5", 11, 7],
- [:r_paren, nil, 12, 7],
- [:newline, nil, 13, 7],
-
- [:text, "f", 6, 8],
- [:l_paren, nil, 8, 8],
- [:requirement, ">=", 9, 8],
- [:text, "6", 12, 8],
- [:r_paren, nil, 13, 8],
- [:newline, nil, 14, 8],
-
- [:text, "g", 6, 9],
- [:l_paren, nil, 8, 9],
- [:requirement, "<=", 9, 9],
- [:text, "7", 12, 9],
- [:r_paren, nil, 13, 9],
- [:newline, nil, 14, 9],
-
- [:text, "h", 6, 10],
- [:l_paren, nil, 8, 10],
- [:requirement, "~>", 9, 10],
- [:text, "8", 12, 10],
- [:r_paren, nil, 13, 10],
- [:newline, nil, 14, 10],
-
- [:newline, nil, 0, 11],
-
- [:section, "PLATFORMS", 0, 12],
- [:newline, nil, 9, 12],
-
- [:text, Gem::Platform::RUBY, 2, 13],
- [:newline, nil, 6, 13],
-
- [:newline, nil, 0, 14],
-
- [:section, "DEPENDENCIES", 0, 15],
- [:newline, nil, 12, 15],
-
- [:text, "a", 2, 16],
- [:newline, nil, 3, 16],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_tokenize_capitals
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- Ab (2)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- Ab
- LOCKFILE
-
- expected = [
- [:section, "GEM", 0, 0],
- [:newline, nil, 3, 0],
- [:entry, "remote", 2, 1],
- [:text, @gem_repo, 10, 1],
- [:newline, nil, 34, 1],
- [:entry, "specs", 2, 2],
- [:newline, nil, 8, 2],
- [:text, "Ab", 4, 3],
- [:l_paren, nil, 7, 3],
- [:text, "2", 8, 3],
- [:r_paren, nil, 9, 3],
- [:newline, nil, 10, 3],
- [:newline, nil, 0, 4],
- [:section, "PLATFORMS", 0, 5],
- [:newline, nil, 9, 5],
- [:text, Gem::Platform::RUBY, 2, 6],
- [:newline, nil, 6, 6],
- [:newline, nil, 0, 7],
- [:section, "DEPENDENCIES", 0, 8],
- [:newline, nil, 12, 8],
- [:text, "Ab", 2, 9],
- [:newline, nil, 4, 9],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_tokenize_conflict_markers
- write_lockfile "<<<<<<<"
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
-
- write_lockfile "|||||||"
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
-
- write_lockfile "======="
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
-
- write_lockfile ">>>>>>>"
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
- end
-
- def test_tokenize_git
- write_lockfile <<-LOCKFILE
-DEPENDENCIES
- a!
- LOCKFILE
-
- expected = [
- [:section, "DEPENDENCIES", 0, 0],
- [:newline, nil, 12, 0],
-
- [:text, "a", 2, 1],
- [:bang, nil, 3, 1],
- [:newline, nil, 4, 1],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_tokenize_multiple
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
- b (~> 3.0, >= 3.0.1)
- LOCKFILE
-
- expected = [
- [:section, "GEM", 0, 0],
- [:newline, nil, 3, 0],
-
- [:entry, "remote", 2, 1],
- [:text, @gem_repo, 10, 1],
- [:newline, nil, 34, 1],
-
- [:entry, "specs", 2, 2],
- [:newline, nil, 8, 2],
-
- [:text, "a", 4, 3],
- [:l_paren, nil, 6, 3],
- [:text, "2", 7, 3],
- [:r_paren, nil, 8, 3],
- [:newline, nil, 9, 3],
-
- [:text, "b", 6, 4],
- [:l_paren, nil, 8, 4],
- [:requirement, "~>", 9, 4],
- [:text, "3.0", 12, 4],
- [:comma, nil, 15, 4],
- [:requirement, ">=", 17, 4],
- [:text, "3.0.1", 20, 4],
- [:r_paren, nil, 25, 4],
- [:newline, nil, 26, 4],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_unget
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
- tokenizer.unshift :token
- parser = tokenizer.make_parser nil, nil
-
- assert_equal :token, parser.get
- end
-
- def write_lockfile(lockfile)
- File.open @lock_file, "w" do |io|
- io.write lockfile
- end
- end
-
- def tokenize_lockfile
- Gem::RequestSet::Lockfile::Tokenizer.from_file(@lock_file).to_a
- end
-end
diff --git a/test/rubygems/test_gem_requirement.rb b/test/rubygems/test_gem_requirement.rb
index de0d11ec00..00634dc7f4 100644
--- a/test/rubygems/test_gem_requirement.rb
+++ b/test/rubygems/test_gem_requirement.rb
@@ -137,11 +137,7 @@ class TestGemRequirement < Gem::TestCase
refute_satisfied_by "1.2", r
assert_satisfied_by "1.3", r
- assert_raise ArgumentError do
- Gem::Deprecate.skip_during do
- assert_satisfied_by nil, r
- end
- end
+ assert_satisfied_by nil, r
end
def test_satisfied_by_eh_blank
@@ -151,11 +147,7 @@ class TestGemRequirement < Gem::TestCase
assert_satisfied_by "1.2", r
refute_satisfied_by "1.3", r
- assert_raise ArgumentError do
- Gem::Deprecate.skip_during do
- assert_satisfied_by nil, r
- end
- end
+ refute_satisfied_by nil, r
end
def test_satisfied_by_eh_equal
@@ -165,11 +157,7 @@ class TestGemRequirement < Gem::TestCase
assert_satisfied_by "1.2", r
refute_satisfied_by "1.3", r
- assert_raise ArgumentError do
- Gem::Deprecate.skip_during do
- assert_satisfied_by nil, r
- end
- end
+ refute_satisfied_by nil, r
end
def test_satisfied_by_eh_gt
@@ -179,9 +167,7 @@ class TestGemRequirement < Gem::TestCase
refute_satisfied_by "1.2", r
assert_satisfied_by "1.3", r
- assert_raise ArgumentError do
- r.satisfied_by? nil
- end
+ refute_satisfied_by nil, r
end
def test_satisfied_by_eh_gte
diff --git a/test/rubygems/test_gem_resolver.rb b/test/rubygems/test_gem_resolver.rb
index 4990d5d2dd..84ede36b6c 100644
--- a/test/rubygems/test_gem_resolver.rb
+++ b/test/rubygems/test_gem_resolver.rb
@@ -86,63 +86,6 @@ class TestGemResolver < Gem::TestCase
assert_same index_set, composed
end
- def test_requests
- a1 = util_spec "a", 1, "b" => 2
-
- r1 = Gem::Resolver::DependencyRequest.new dep("a", "= 1"), nil
-
- act = Gem::Resolver::ActivationRequest.new a1, r1
-
- res = Gem::Resolver.new [a1]
-
- reqs = []
-
- res.requests a1, act, reqs
-
- assert_equal ["b (= 2)"], reqs.map(&:to_s)
- end
-
- def test_requests_development
- a1 = util_spec "a", 1, "b" => 2
-
- spec = Gem::Resolver::SpecSpecification.new nil, a1
- def spec.fetch_development_dependencies
- @called = true
- end
-
- r1 = Gem::Resolver::DependencyRequest.new dep("a", "= 1"), nil
-
- act = Gem::Resolver::ActivationRequest.new spec, r1
-
- res = Gem::Resolver.new [act]
- res.development = true
-
- reqs = []
-
- res.requests spec, act, reqs
-
- assert_equal ["b (= 2)"], reqs.map(&:to_s)
-
- assert spec.instance_variable_defined? :@called
- end
-
- def test_requests_ignore_dependencies
- a1 = util_spec "a", 1, "b" => 2
-
- r1 = Gem::Resolver::DependencyRequest.new dep("a", "= 1"), nil
-
- act = Gem::Resolver::ActivationRequest.new a1, r1
-
- res = Gem::Resolver.new [a1]
- res.ignore_dependencies = true
-
- reqs = []
-
- res.requests a1, act, reqs
-
- assert_empty reqs
- end
-
def test_resolve_conservative
a1_spec = util_spec "a", 1
@@ -197,6 +140,34 @@ class TestGemResolver < Gem::TestCase
assert_resolves_to [a2_spec, b2_spec, c1_spec, d2_spec, e1_spec], res
end
+ def test_conservative_upgrades_when_installed_blocked
+ # Conservative mode floats the installed (skip) version to the front but
+ # keeps newer versions selectable. When the installed version cannot be
+ # used because its own dependency is unsatisfiable, the solver backtracks
+ # to a newer version instead of failing. This intentionally diverges from
+ # Molinillo (which hard-restricted to skip versions and raised) and reaches
+ # Bundler's upgrade-over-raise outcome. See the comment in
+ # Gem::Resolver#all_versions_for.
+ a1_spec = util_spec "a", 1 do |s|
+ s.add_dependency "b", ">= 2"
+ end
+ a2_spec = util_spec "a", 2 do |s|
+ s.add_dependency "b", ">= 1"
+ end
+ b1_spec = util_spec "b", 1
+
+ # b-2 is intentionally absent, so a-1's `b >= 2` cannot be satisfied.
+ deps = [make_dep("a", ">= 1")]
+ s = set a1_spec, a2_spec, b1_spec
+
+ res = Gem::Resolver.new deps, s
+ # a-1 is already installed and satisfies `a >= 1`, so conservative mode
+ # prefers it - but it is blocked by the missing b-2, forcing an upgrade.
+ res.skip_gems = { "a" => [a1_spec] }
+
+ assert_resolves_to [a2_spec, b1_spec], res
+ end
+
def test_resolve_development
a_spec = util_spec "a", 1 do |s|
s.add_development_dependency "b"
@@ -511,19 +482,10 @@ class TestGemResolver < Gem::TestCase
r.resolve
end
- deps = [make_dep("c", "= 2"), make_dep("c", "= 1")]
- assert_equal deps, e.conflicting_dependencies
-
- con = e.conflict
-
- act = con.activated
- assert_equal "c-1", act.spec.full_name
-
- parent = act.parent
- assert_equal "a-1", parent.spec.full_name
-
- act = con.requester
- assert_equal "b-1", act.spec.full_name
+ assert_nil e.conflict
+ assert_match(/your request/, e.message)
+ assert_match(/a depends on c/, e.message)
+ assert_match(/b depends on c/, e.message)
end
def test_raises_when_a_gem_is_missing
@@ -578,12 +540,11 @@ class TestGemResolver < Gem::TestCase
r = Gem::Resolver.new([ad], set(a1))
- e = assert_raise Gem::UnsatisfiableDependencyError do
+ e = assert_raise Gem::DependencyResolutionError do
r.resolve
end
- assert_equal "Unable to resolve dependency: 'a (= 1)' requires 'b (= 2)'",
- e.message
+ assert_match(/depends on b = 2 which could not be found in any repository/, e.message)
end
def test_raises_when_possibles_are_exhausted
@@ -605,18 +566,9 @@ class TestGemResolver < Gem::TestCase
r.resolve
end
- dependency = e.conflict.dependency
-
- assert_includes %w[a b], dependency.name
- assert_equal req(">= 0"), dependency.requirement
-
- activated = e.conflict.activated
- assert_equal "c-1", activated.full_name
-
- assert_equal dep("c", "= 1"), activated.request.dependency
-
- assert_equal [dep("c", ">= 2"), dep("c", "= 1")],
- e.conflict.conflicting_dependencies
+ assert_nil e.conflict
+ assert_match(/a depends on c/, e.message)
+ assert_match(/b depends on c/, e.message)
end
def test_keeps_resolving_after_seeing_satisfied_dep
@@ -772,7 +724,7 @@ class TestGemResolver < Gem::TestCase
assert_resolves_to [b1, c1, d2], r
end
- def test_sorts_by_source_then_version
+ def test_picks_highest_version_across_sources
source_a = Gem::Source.new "http://example.com/a"
source_b = Gem::Source.new "http://example.com/b"
source_c = Gem::Source.new "http://example.com/c"
@@ -795,7 +747,43 @@ class TestGemResolver < Gem::TestCase
resolver = Gem::Resolver.new [dependency], set
- assert_resolves_to [spec_b_2], resolver
+ assert_resolves_to [spec_a_2], resolver
+ end
+
+ def test_same_version_prefers_earlier_source
+ source_a = Gem::Source.new "http://example.com/a"
+ source_b = Gem::Source.new "http://example.com/b"
+
+ spec_a = util_spec "some-dep", "1.0.0"
+ spec_b = util_spec "some-dep", "1.0.0"
+
+ set = StaticSet.new [
+ Gem::Resolver::SpecSpecification.new(nil, spec_a, source_a),
+ Gem::Resolver::SpecSpecification.new(nil, spec_b, source_b),
+ ]
+
+ resolver = Gem::Resolver.new [make_dep("some-dep", "> 0")], set
+ result = resolver.resolve
+
+ assert_equal source_a, result.first.spec.source
+ end
+
+ def test_same_version_prefers_earlier_source_when_order_flipped
+ source_a = Gem::Source.new "http://example.com/a"
+ source_b = Gem::Source.new "http://example.com/b"
+
+ spec_a = util_spec "some-dep", "1.0.0"
+ spec_b = util_spec "some-dep", "1.0.0"
+
+ set = StaticSet.new [
+ Gem::Resolver::SpecSpecification.new(nil, spec_b, source_b),
+ Gem::Resolver::SpecSpecification.new(nil, spec_a, source_a),
+ ]
+
+ resolver = Gem::Resolver.new [make_dep("some-dep", "> 0")], set
+ result = resolver.resolve
+
+ assert_equal source_b, result.first.spec.source
end
def test_select_local_platforms
@@ -850,4 +838,338 @@ class TestGemResolver < Gem::TestCase
assert_match "No match for 'a (= 1)' on this platform. Found: c-p-1",
e.message
end
+
+ def test_resolve_prerelease_not_considered_when_stable_exists
+ # a-1.0 depends on b ~> 2.0 - only b-2.0.pre satisfies that, but
+ # b also has a stable version (1.0), so prereleases are filtered out.
+ # The resolver must fail, not silently use b-2.0.pre during propagation.
+ a_stable = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", "~> 2.0"
+ end
+
+ b_stable = util_spec "b", "1.0"
+ b_pre = util_spec "b", "2.0.pre"
+
+ s = set(a_stable, b_stable, b_pre)
+
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+ end
+
+ def test_resolve_prerelease_considered_when_enabled
+ a_stable = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", ">= 1.0"
+ end
+
+ b_pre = util_spec "b", "2.0.pre"
+
+ s = set(a_stable, b_pre)
+ s.prerelease = true
+
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ assert_resolves_to [a_stable, b_pre], r
+ end
+
+ def test_resolve_prerelease_used_when_no_stable_versions_exist
+ a_stable = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", ">= 1.0"
+ end
+
+ b_pre = util_spec "b", "2.0.pre"
+ b_other_pre = util_spec "b", "1.0.pre"
+
+ s = set(a_stable, b_pre, b_other_pre)
+
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ assert_resolves_to [a_stable, b_pre], r
+ end
+
+ def test_resolve_prerelease_required_by_exact_requirement
+ # A root dep with an exact prerelease version must resolve to that
+ # version even when stable versions of the same gem are in the set.
+ # Gem.finish_resolve hits this: it imports loaded_specs as exact-version
+ # deps, so the currently-activated prerelease bundler becomes a root dep.
+ a_stable = util_spec "a", "1.0"
+ a_pre = util_spec "a", "2.0.pre"
+
+ s = set(a_stable, a_pre)
+
+ ad = make_dep "a", "= 2.0.pre"
+ r = Gem::Resolver.new([ad], s)
+
+ assert_resolves_to [a_pre], r
+ end
+
+ def test_resolve_transitive_prerelease_required_by_exact_requirement
+ # A transitive dep with an exact prerelease version must resolve to that
+ # version even when stable versions of the same gem are in the set.
+ # The gate on prereleases lives in versions_for and is per-constraint:
+ # `= 2.0.pre` carries a prerelease bound, so prereleases are admitted for
+ # this range even though the global prerelease flag is off.
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", "= 2.0.pre"
+ end
+
+ b_stable = util_spec "b", "1.0"
+ b_pre = util_spec "b", "2.0.pre"
+
+ s = set(a, b_stable, b_pre)
+
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ assert_resolves_to [a, b_pre], r
+ end
+
+ def test_error_includes_platform_hint_when_specs_exist_for_other_platforms
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", ">= 1.0"
+ end
+
+ b_foreign = util_spec "b", "1.0" do |s|
+ s.platform = "java"
+ end
+
+ s = set(a, b_foreign)
+
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/could not be found in any repository/, e.message)
+ assert_match(/b-1.0-java/, e.message)
+ end
+
+ def test_error_includes_ruby_version_hint_when_filtered
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", ">= 1.0"
+ end
+
+ b = util_spec "b", "1.0" do |s|
+ s.required_ruby_version = ">= 999.0"
+ end
+
+ s = set(a, b)
+
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/requires Ruby/, e.message)
+ assert_match(/you have/, e.message)
+ end
+
+ def test_root_gem_incompatible_ruby_version_names_ruby_requirement
+ # A requested (root) gem available only for an incompatible Ruby version
+ # flows through the solver to a DependencyResolutionError whose message
+ # names the Ruby requirement. This matches Bundler (which models Ruby as a
+ # synthetic dependency and reports a solve failure) and is clearer than the
+ # platform-oriented UnsatisfiableDependencyError. Contrast the foreign-
+ # *platform* case (test_raises_and_explains_when_platform_prevents_install),
+ # which is genuinely "not found" and does raise UnsatisfiableDependencyError.
+ a = util_spec "a", "1.0" do |s|
+ s.required_ruby_version = ">= 999.0"
+ end
+
+ ad = make_dep "a", "= 1.0"
+ r = Gem::Resolver.new([ad], set(a))
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/requires Ruby >= 999.0/, e.message)
+ end
+
+ def test_self_dependency_does_not_crash
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "a"
+ end
+
+ s = set(a)
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ assert_resolves_to [a], r
+ end
+
+ def test_contradictory_root_requirements_give_clear_error
+ a1 = util_spec "a", "1"
+ a2 = util_spec "a", "2"
+
+ s = set(a1, a2)
+ r = Gem::Resolver.new([make_dep("a", "= 1"), make_dep("a", "= 2")], s)
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/contradictory/, e.message)
+ refute_match(/unknown package/, e.message)
+ end
+
+ def test_empty_range_transitive_dep_does_not_say_unknown
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", "> 2", "< 1"
+ end
+
+ b = util_spec "b", "1.5"
+
+ s = set(a, b)
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/contradictory/, e.message)
+ refute_match(/unknown package/, e.message)
+ end
+
+ def test_error_hints_about_prerelease_when_filtered
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", "~> 2.0"
+ end
+
+ b_stable = util_spec "b", "1.0"
+ b_pre = util_spec "b", "2.0.pre"
+
+ s = set(a, b_stable, b_pre)
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/pre-release/, e.message)
+ assert_match(/--prerelease/, e.message)
+ end
+
+ def test_soft_missing_skips_dep_with_wrong_version
+ a = util_spec "a", "1.0" do |s|
+ s.add_dependency "b", ">= 2.0"
+ end
+
+ b = util_spec "b", "1.0"
+
+ s = set(a, b)
+ ad = make_dep "a"
+ r = Gem::Resolver.new([ad], s)
+ r.soft_missing = true
+
+ # b exists but only 1.0, which doesn't satisfy >= 2.0.
+ # With soft_missing (--force), the dep should be skipped.
+ assert_resolves_to [a], r
+ end
+
+ def test_backtracks_to_clean_sibling_when_higher_version_has_missing_dep
+ a1 = util_spec "a", "1"
+ a2 = util_spec "a", "2" do |s|
+ s.add_dependency "zzz", ">= 1"
+ end
+
+ r = Gem::Resolver.new([make_dep("a")], set(a1, a2))
+
+ # 'zzz' has zero specs anywhere, so a-2 is unusable, but a-1 is clean
+ # and resolution must backtrack to it rather than declaring every
+ # version of 'a' invalid.
+ assert_resolves_to [a1], r
+ end
+
+ def test_backtracks_over_band_of_bad_high_versions_to_clean_lower
+ a1 = util_spec "a", "1"
+ a2 = util_spec "a", "2" do |s|
+ s.add_dependency "zzz", ">= 1"
+ end
+ a3 = util_spec "a", "3" do |s|
+ s.add_dependency "zzz", ">= 1"
+ end
+
+ r = Gem::Resolver.new([make_dep("a")], set(a1, a2, a3))
+
+ # Only the a-2..a-3 band shares the missing 'zzz' dep and should be
+ # eliminated; band scoping is load-bearing here, not just sibling
+ # presence.
+ assert_resolves_to [a1], r
+ end
+
+ def test_backtracks_when_one_of_several_deps_is_missing
+ good = util_spec "good", "1"
+ a1 = util_spec "a", "1" do |s|
+ s.add_dependency "good", ">= 1"
+ end
+ a2 = util_spec "a", "2" do |s|
+ s.add_dependency "good", ">= 1"
+ s.add_dependency "zzz", ">= 1"
+ end
+
+ r = Gem::Resolver.new([make_dep("a")], set(a1, a2, good))
+
+ # Only a-2, which carries the missing 'zzz' dep, is eliminated; the
+ # per-dep check inside a multi-dep version must not poison a-1.
+ assert_resolves_to [a1, good], r
+ end
+
+ def test_fails_when_every_version_depends_on_missing_package
+ a1 = util_spec "a", "1" do |s|
+ s.add_dependency "zzz", ">= 1"
+ end
+ a2 = util_spec "a", "2" do |s|
+ s.add_dependency "zzz", ">= 1"
+ end
+
+ r = Gem::Resolver.new([make_dep("a")], set(a1, a2))
+
+ e = assert_raise Gem::DependencyResolutionError do
+ r.resolve
+ end
+
+ assert_match(/every version of a depends on zzz >= 1 which could not be found in any repository/, e.message)
+ end
+
+ def test_resolves_when_only_lowest_version_has_missing_dep
+ a1 = util_spec "a", "1" do |s|
+ s.add_dependency "zzz", ">= 1"
+ end
+ a2 = util_spec "a", "2"
+
+ r = Gem::Resolver.new([make_dep("a")], set(a1, a2))
+
+ # a-2 is preferred/tried first, so this is already green; it guards
+ # against the bug being re-introduced in an order-sensitive way.
+ assert_resolves_to [a2], r
+ end
+
+ def test_filtered_platform_dep_lets_clean_sibling_backtrack
+ a1 = util_spec "a", "1"
+ a2 = util_spec "a", "2" do |s|
+ s.add_dependency "b", ">= 1.0"
+ end
+ b_java = util_spec "b", "1.0" do |s|
+ s.platform = "java"
+ end
+
+ r = Gem::Resolver.new([make_dep("a")], set(a1, a2, b_java))
+
+ # 'b' EXISTS in the unfiltered specs but is platform-filtered, so a-2
+ # is unusable via NoVersions (not InvalidDependency). Resolution must
+ # backtrack to the clean a-1 rather than eliminating it.
+ assert_resolves_to [a1], r
+ end
end
diff --git a/test/rubygems/test_gem_resolver_best_set.rb b/test/rubygems/test_gem_resolver_best_set.rb
index 02f542efc0..ac186884d1 100644
--- a/test/rubygems/test_gem_resolver_best_set.rb
+++ b/test/rubygems/test_gem_resolver_best_set.rb
@@ -31,6 +31,20 @@ class TestGemResolverBestSet < Gem::TestCase
assert_equal %w[a-1], found.map(&:full_name)
end
+ def test_pick_sets_prerelease
+ set = Gem::Resolver::BestSet.new
+ set.prerelease = true
+
+ set.pick_sets
+
+ sets = set.sets
+
+ assert_equal 1, sets.count
+
+ source_set = sets.first
+ assert_equal true, source_set.prerelease
+ end
+
def test_find_all_local
spec_fetcher do |fetcher|
fetcher.spec "a", 1
diff --git a/test/rubygems/test_gem_resolver_conflict.rb b/test/rubygems/test_gem_resolver_conflict.rb
deleted file mode 100644
index 5696ff266d..0000000000
--- a/test/rubygems/test_gem_resolver_conflict.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-
-class TestGemResolverConflict < Gem::TestCase
- def test_explanation
- root =
- dependency_request dep("net-ssh", ">= 2.0.13"), "rye", "0.9.8"
- child =
- dependency_request dep("net-ssh", ">= 2.6.5"), "net-ssh", "2.2.2", root
-
- dep = Gem::Resolver::DependencyRequest.new dep("net-ssh", ">= 2.0.13"), nil
-
- spec = util_spec "net-ssh", "2.2.2"
- active =
- Gem::Resolver::ActivationRequest.new spec, dep
-
- conflict =
- Gem::Resolver::Conflict.new child, active
-
- expected = <<-EXPECTED
- Activated net-ssh-2.2.2
- which does not match conflicting dependency (>= 2.6.5)
-
- Conflicting dependency chains:
- net-ssh (>= 2.0.13), 2.2.2 activated
-
- versus:
- rye (= 0.9.8), 0.9.8 activated, depends on
- net-ssh (>= 2.0.13), 2.2.2 activated, depends on
- net-ssh (>= 2.6.5)
-
- EXPECTED
-
- assert_equal expected, conflict.explanation
- end
-
- def test_explanation_user_request
- spec = util_spec "a", 2
-
- a1_req = Gem::Resolver::DependencyRequest.new dep("a", "= 1"), nil
- a2_req = Gem::Resolver::DependencyRequest.new dep("a", "= 2"), nil
-
- activated = Gem::Resolver::ActivationRequest.new spec, a2_req
-
- conflict = Gem::Resolver::Conflict.new a1_req, activated
-
- expected = <<-EXPECTED
- Activated a-2
- which does not match conflicting dependency (= 1)
-
- Conflicting dependency chains:
- a (= 2), 2 activated
-
- versus:
- a (= 1)
-
- EXPECTED
-
- assert_equal expected, conflict.explanation
- end
-
- def test_request_path
- root =
- dependency_request dep("net-ssh", ">= 2.0.13"), "rye", "0.9.8"
-
- child =
- dependency_request dep("other", ">= 1.0"), "net-ssh", "2.2.2", root
-
- conflict =
- Gem::Resolver::Conflict.new nil, nil
-
- expected = [
- "net-ssh (>= 2.0.13), 2.2.2 activated",
- "rye (= 0.9.8), 0.9.8 activated",
- ]
-
- assert_equal expected, conflict.request_path(child.requester)
- end
-end
diff --git a/test/rubygems/test_gem_resolver_git_specification.rb b/test/rubygems/test_gem_resolver_git_specification.rb
index 621333d3bf..e03c61e27d 100644
--- a/test/rubygems/test_gem_resolver_git_specification.rb
+++ b/test/rubygems/test_gem_resolver_git_specification.rb
@@ -97,6 +97,44 @@ class TestGemResolverGitSpecification < Gem::TestCase
assert_path_exist File.join git_spec.spec.extension_dir, "b.rb"
end
+ def test_install_no_build_extension
+ pend if Gem.java_platform?
+ pend "terminates on mswin" if vc_windows? && ruby_repo?
+ name, _, repository, = git_gem "a", 1 do |s|
+ s.extensions << "ext/extconf.rb"
+ end
+
+ Dir.chdir "git/a" do
+ FileUtils.mkdir_p "ext/lib"
+
+ File.open "ext/extconf.rb", "w" do |io|
+ io.puts 'require "mkmf"'
+ io.puts 'create_makefile "a"'
+ end
+
+ FileUtils.touch "ext/lib/b.rb"
+
+ system @git, "add", "ext/extconf.rb"
+ system @git, "add", "ext/lib/b.rb"
+
+ system @git, "commit", "--quiet", "-m", "Add extension files"
+ end
+
+ source = Gem::Source::Git.new name, repository, nil, true
+
+ spec = source.specs.first
+
+ git_spec = Gem::Resolver::GitSpecification.new @set, spec, source
+
+ use_ui @ui do
+ git_spec.install(build_extension: false)
+ end
+
+ assert_path_not_exist File.join(git_spec.spec.extension_dir, "b.rb")
+ assert_match "contains native extensions that were not built", @ui.error
+ assert_match "gem pristine #{git_spec.spec.name} --extensions", @ui.error
+ end
+
def test_install_installed
git_gem "a", 1
diff --git a/test/rubygems/test_gem_resolver_strategy.rb b/test/rubygems/test_gem_resolver_strategy.rb
new file mode 100644
index 0000000000..57c9aadde8
--- /dev/null
+++ b/test/rubygems/test_gem_resolver_strategy.rb
@@ -0,0 +1,163 @@
+# frozen_string_literal: true
+
+require_relative "helper"
+
+class TestGemResolverStrategy < Gem::TestCase
+ # Minimal source that implements the two methods Strategy calls:
+ # all_versions_for(package) - returns versions in preference order
+ # versions_for(package, range) - returns versions matching a range
+ #
+ # Tracks call counts so we can assert on caching behavior.
+ class StubSource
+ attr_reader :versions_for_calls
+
+ def initialize(versions_by_package)
+ @versions_by_package = versions_by_package
+ @versions_for_calls = 0
+ end
+
+ def all_versions_for(package)
+ @versions_by_package.fetch(package.to_s, [])
+ end
+
+ def versions_for(package, range)
+ @versions_for_calls += 1
+ all = @versions_by_package.fetch(package.to_s, [])
+ all.select {|v| range.include?(v) }
+ end
+ end
+
+ def v(version_string)
+ Gem::Version.new(version_string)
+ end
+
+ def make_package(name)
+ Gem::PubGrub::Package.new(name)
+ end
+
+ def make_range_any
+ Gem::PubGrub::VersionRange.any
+ end
+
+ # A range >= min (unbounded above)
+ def make_range_gte(version)
+ Gem::PubGrub::VersionRange.new(min: version, include_min: true)
+ end
+
+ # A range >= min AND < max
+ def make_range_between(min, max)
+ Gem::PubGrub::VersionRange.new(
+ min: min, max: max,
+ include_min: true, include_max: false
+ )
+ end
+
+ def test_most_preferred_version_respects_all_versions_for_ordering
+ # all_versions_for returns [2.0, 1.0, 3.0] - so 2.0 is most preferred
+ # even though 3.0 is numerically highest.
+ pkg = make_package("a")
+ source = StubSource.new("a" => [v("2.0"), v("1.0"), v("3.0")])
+
+ strategy = Gem::Resolver::Strategy.new(source)
+ unsatisfied = { pkg => make_range_any }
+
+ _package, version = strategy.next_package_and_version(unsatisfied)
+
+ assert_equal v("2.0"), version
+ end
+
+ def test_picks_most_constrained_package
+ # "a" has 3 matching versions, "b" has 1 matching version.
+ # Strategy should pick "b" because it's more constrained.
+ pkg_a = make_package("a")
+ pkg_b = make_package("b")
+
+ source = StubSource.new(
+ "a" => [v("3.0"), v("2.0"), v("1.0")],
+ "b" => [v("1.0")]
+ )
+
+ strategy = Gem::Resolver::Strategy.new(source)
+
+ unsatisfied = {
+ pkg_a => make_range_any,
+ pkg_b => make_range_any,
+ }
+
+ package, _version = strategy.next_package_and_version(unsatisfied)
+
+ assert_equal pkg_b, package
+ end
+
+ def test_picks_package_with_fewer_higher_versions_as_tiebreaker
+ # Both "a" and "b" have 2 matching versions (so both get priority [1, ...]).
+ # "a" has matching [2.0, 1.0] with higher (above range) = [] (0 higher)
+ # "b" has matching [2.0, 1.0] with higher [3.0] (1 higher)
+ # Tiebreaker: fewer higher versions wins, so "a" is picked.
+ pkg_a = make_package("a")
+ pkg_b = make_package("b")
+
+ range = make_range_between(v("0.5"), v("2.5"))
+
+ source = StubSource.new(
+ "a" => [v("2.0"), v("1.0")],
+ "b" => [v("3.0"), v("2.0"), v("1.0")]
+ )
+
+ strategy = Gem::Resolver::Strategy.new(source)
+
+ unsatisfied = {
+ pkg_a => range,
+ pkg_b => range,
+ }
+
+ package, _version = strategy.next_package_and_version(unsatisfied)
+
+ assert_equal pkg_a, package
+ end
+
+ def test_cache_prevents_redundant_versions_for_calls
+ pkg = make_package("a")
+ source = StubSource.new("a" => [v("2.0"), v("1.0")])
+
+ strategy = Gem::Resolver::Strategy.new(source)
+
+ range = make_range_any
+ unsatisfied = { pkg => range }
+
+ # First call: should call versions_for for matching + upper_invert + most_preferred
+ strategy.next_package_and_version(unsatisfied)
+ calls_after_first = source.versions_for_calls
+
+ # Second call with same package+range: next_term_to_try_from should
+ # hit the cache, so only most_preferred_version_of adds a call.
+ strategy.next_package_and_version(unsatisfied)
+ calls_after_second = source.versions_for_calls
+
+ # The cached path saves the 2 calls in next_term_to_try_from,
+ # so only the 1 call from most_preferred_version_of is added.
+ assert_equal 1, calls_after_second - calls_after_first
+ end
+
+ def test_cache_is_keyed_by_package_and_range
+ pkg = make_package("a")
+ source = StubSource.new("a" => [v("3.0"), v("2.0"), v("1.0")])
+
+ strategy = Gem::Resolver::Strategy.new(source)
+
+ range_any = make_range_any
+ range_gte = make_range_gte(v("2.0"))
+
+ # First call with range_any
+ strategy.next_package_and_version({ pkg => range_any })
+ calls_after_first = source.versions_for_calls
+
+ # Second call with different range - cache miss, so versions_for is called again
+ strategy.next_package_and_version({ pkg => range_gte })
+ calls_after_second = source.versions_for_calls
+
+ # A cache miss means 2 new versions_for calls (matching + upper_invert)
+ # plus 1 from most_preferred_version_of = 3 total new calls
+ assert_equal 3, calls_after_second - calls_after_first
+ end
+end
diff --git a/test/rubygems/test_gem_safe_marshal.rb b/test/rubygems/test_gem_safe_marshal.rb
index deeb8205bc..7e3a046c4e 100644
--- a/test/rubygems/test_gem_safe_marshal.rb
+++ b/test/rubygems/test_gem_safe_marshal.rb
@@ -234,8 +234,6 @@ class TestGemSafeMarshal < Gem::TestCase
end
def test_link_after_float
- pend "Marshal.load of links and floats is broken on truffleruby, see https://github.com/oracle/truffleruby/issues/3747" if RUBY_ENGINE == "truffleruby"
-
a = []
a << a
assert_safe_load_as [0.0, a, 1.0, a]
@@ -254,6 +252,8 @@ class TestGemSafeMarshal < Gem::TestCase
end
def test_hash_with_compare_by_identity
+ pend "Marshal.dump of a compare_by_identity Hash emits an unexpected ivar on jruby" if RUBY_ENGINE == "jruby"
+
with_const(Gem::SafeMarshal, :PERMITTED_CLASSES, %w[Hash]) do
assert_safe_load_as Hash.new.compare_by_identity.tap {|h|
h[+"a"] = 1
diff --git a/test/rubygems/test_gem_safe_yaml.rb b/test/rubygems/test_gem_safe_yaml.rb
index 02df9f97da..8d0ac63c41 100644
--- a/test/rubygems/test_gem_safe_yaml.rb
+++ b/test/rubygems/test_gem_safe_yaml.rb
@@ -5,6 +5,28 @@ require_relative "helper"
Gem.load_yaml
class TestGemSafeYAML < Gem::TestCase
+ def yaml_load(input, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES,
+ permitted_symbols: Gem::SafeYAML::PERMITTED_SYMBOLS,
+ aliases: true)
+ if Gem.use_psych?
+ Psych.safe_load(input, permitted_classes: permitted_classes,
+ permitted_symbols: permitted_symbols,
+ aliases: aliases)
+ else
+ Gem::YAMLSerializer.load(input, permitted_classes: permitted_classes,
+ permitted_symbols: permitted_symbols,
+ aliases: aliases)
+ end
+ end
+
+ def yaml_dump(obj)
+ if Gem.use_psych?
+ obj.to_yaml
+ else
+ Gem::YAMLSerializer.dump(obj)
+ end
+ end
+
def test_aliases_enabled_by_default
assert_predicate Gem::SafeYAML, :aliases_enabled?
assert_equal({ "a" => "a", "b" => "a" }, Gem::SafeYAML.safe_load("a: &a a\nb: *a\n"))
@@ -21,4 +43,1284 @@ class TestGemSafeYAML < Gem::TestCase
ensure
Gem::SafeYAML.aliases_enabled = aliases_enabled
end
+
+ def test_specification_version_is_integer
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test
+ version: !ruby/object:Gem::Version
+ version: 1.0.0
+ specification_version: 4
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Integer, spec.specification_version
+ assert_equal 4, spec.specification_version
+ end
+
+ def test_disallowed_class_rejected
+ yaml = <<~YAML
+ --- !ruby/object:SomeDisallowedClass
+ foo: bar
+ YAML
+
+ exception = assert_raise(Psych::DisallowedClass) do
+ Gem::SafeYAML.safe_load(yaml)
+ end
+ assert_match(/unspecified class/, exception.message)
+ end
+
+ def test_plain_tag_key_does_not_construct_specification
+ yaml = <<~YAML
+ tag: "!ruby/object:Gem::Specification"
+ name: pwned
+ arbitrary_ivar: hello
+ YAML
+
+ result = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Hash, result
+ assert_equal "!ruby/object:Gem::Specification", result["tag"]
+ assert_equal "pwned", result["name"]
+ end
+
+ def test_disallowed_symbol_rejected
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Dependency
+ name: test
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 0
+ type: :invalid_type
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 0
+ YAML
+
+ exception = assert_raise(Psych::DisallowedClass) do
+ Gem::SafeYAML.safe_load(yaml)
+ end
+ assert_match(/unspecified class/, exception.message)
+ end
+
+ def test_disallowed_symbol_not_interned
+ unique = "rejected_symbol_#{rand(1 << 30)}"
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Dependency
+ name: test
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 0
+ type: :#{unique}
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 0
+ YAML
+
+ assert_raise(Psych::DisallowedClass) do
+ Gem::YAMLSerializer.load(yaml,
+ permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES,
+ permitted_symbols: Gem::SafeYAML::PERMITTED_SYMBOLS)
+ end
+ refute_includes Symbol.all_symbols.map(&:to_s), unique
+ end
+
+ def test_inline_array_nesting_capped
+ depth = Gem::YAMLSerializer::Parser::MAX_NESTING_DEPTH + 1
+ yaml = "x: " + ("[" * depth) + "a" + ("]" * depth) + "\n"
+
+ expected = [Psych::SyntaxError]
+ # JRuby's JVM stack overflows before the Ruby-level nesting cap fires.
+ expected << ::Java::JavaLang::StackOverflowError if RUBY_ENGINE == "jruby"
+
+ assert_raise(*expected) do
+ Gem::YAMLSerializer.load(yaml, permitted_classes: [])
+ end
+ end
+
+ def test_unknown_alias_raises
+ yaml = <<~YAML
+ foo: 1
+ bar: *missing
+ YAML
+
+ expected_error = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias
+ assert_raise(expected_error) { Gem::SafeYAML.safe_load(yaml) }
+ end
+
+ def test_unused_anchor_with_aliases_disabled_is_allowed
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = false
+
+ result = Gem::SafeYAML.safe_load("foo: &unused 1\nbar: 2\n")
+ assert_equal({ "foo" => 1, "bar" => 2 }, result)
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_yaml_serializer_aliases_disabled
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = false
+ refute_predicate Gem::SafeYAML, :aliases_enabled?
+
+ yaml = "a: &anchor value\nb: *anchor\n"
+
+ assert_raise(Psych::AliasesNotEnabled) do
+ Gem::SafeYAML.safe_load(yaml)
+ end
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_real_gemspec_fileutils
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: fileutils
+ version: !ruby/object:Gem::Version
+ version: 1.8.0
+ platform: ruby
+ authors:
+ - Minero Aoki
+ bindir: bin
+ cert_chain: []
+ date: 1980-01-02 00:00:00.000000000 Z
+ dependencies: []
+ description: Several file utility methods for copying, moving, removing, etc.
+ email:
+ -
+ executables: []
+ extensions: []
+ extra_rdoc_files: []
+ files:
+ - BSDL
+ - COPYING
+ - README.md
+ - Rakefile
+ - fileutils.gemspec
+ - lib/fileutils.rb
+ homepage: https://github.com/ruby/fileutils
+ licenses:
+ - Ruby
+ - BSD-2-Clause
+ metadata:
+ source_code_uri: https://github.com/ruby/fileutils
+ rdoc_options: []
+ require_paths:
+ - lib
+ required_ruby_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 2.5.0
+ required_rubygems_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ requirements: []
+ rubygems_version: 3.6.9
+ specification_version: 4
+ summary: Several file utility methods for copying, moving, removing, etc.
+ test_files: []
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "fileutils", spec.name
+ assert_equal Gem::Version.new("1.8.0"), spec.version
+ assert_kind_of Integer, spec.specification_version
+ assert_equal 4, spec.specification_version
+ end
+
+ def test_yaml_anchor_and_alias_enabled
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = true
+
+ yaml = <<~YAML
+ dependencies:
+ - &req !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ - *req
+ YAML
+
+ result = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Hash, result
+ assert_kind_of Array, result["dependencies"]
+ assert_equal 2, result["dependencies"].size
+ assert_kind_of Gem::Requirement, result["dependencies"][0]
+ assert_kind_of Gem::Requirement, result["dependencies"][1]
+ assert_equal result["dependencies"][0].requirements, result["dependencies"][1].requirements
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_real_gemspec_rubygems_bundler
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: rubygems-bundler
+ version: !ruby/object:Gem::Version
+ version: 1.4.5
+ platform: ruby
+ authors:
+ - Josh Hull
+ - Michal Papis
+ autorequire:
+ bindir: bin
+ cert_chain: []
+ date: 2018-06-24 00:00:00.000000000 Z
+ dependencies:
+ - !ruby/object:Gem::Dependency
+ name: bundler-unload
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 1.0.2
+ type: :runtime
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 1.0.2
+ description: Stop using bundle exec.
+ email:
+ - joshbuddy@gmail.com
+ - mpapis@gmail.com
+ executables: []
+ extensions: []
+ extra_rdoc_files: []
+ files:
+ - ".gem.config"
+ homepage: http://mpapis.github.com/rubygems-bundler
+ licenses:
+ - Apache-2.0
+ metadata: {}
+ post_install_message:
+ rdoc_options: []
+ require_paths:
+ - lib
+ required_ruby_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ rubyforge_project:
+ rubygems_version: 2.7.6
+ signing_key:
+ specification_version: 4
+ summary: Stop using bundle exec
+ test_files: []
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "rubygems-bundler", spec.name
+ assert_equal Gem::Version.new("1.4.5"), spec.version
+ assert_equal 1, spec.dependencies.size
+
+ dep = spec.dependencies.first
+ assert_equal "bundler-unload", dep.name
+ assert_kind_of Gem::Requirement, dep.requirement
+ assert_kind_of Gem::Requirement, dep.instance_variable_get(:@version_requirements)
+ assert_equal dep.requirement.requirements, [[">=", Gem::Version.new("1.0.2")]]
+
+ # Empty fields should be nil
+ assert_nil spec.autorequire
+ assert_nil spec.post_install_message
+
+ # Metadata should be empty hash
+ assert_equal({}, spec.metadata)
+
+ # specification_version should be Integer
+ assert_kind_of Integer, spec.specification_version
+ assert_equal 4, spec.specification_version
+ end
+
+ def test_empty_requirements_array
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test
+ dependencies:
+ - !ruby/object:Gem::Dependency
+ name: foo
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ type: :runtime
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "test", spec.name
+ assert_equal 1, spec.dependencies.size
+
+ dep = spec.dependencies.first
+ assert_equal "foo", dep.name
+ assert_kind_of Gem::Requirement, dep.requirement
+
+ reqs = dep.requirement.instance_variable_get(:@requirements)
+ assert_nil reqs
+ end
+
+ def test_requirements_hash_converted_to_array
+ # Malformed YAML where requirements is a Hash instead of Array
+ yaml = <<~YAML
+ !ruby/object:Gem::Requirement
+ requirements:
+ foo: bar
+ YAML
+
+ req = yaml_load(yaml, permitted_classes: ["Gem::Requirement"])
+ assert_kind_of Gem::Requirement, req
+
+ reqs = req.instance_variable_get(:@requirements)
+ assert_kind_of Hash, reqs
+ end
+
+ def test_requirement_quote
+ yaml = <<~YAML
+ requirements:
+ - "system: arrow-glib>=25.0.0: amazon_linux: arrow-glib-devel"
+ - 'system: arrow-glib>=25.0.0: fedora: libarrow-glib-devel'
+ YAML
+
+ expected = [
+ "system: arrow-glib>=25.0.0: amazon_linux: arrow-glib-devel",
+ "system: arrow-glib>=25.0.0: fedora: libarrow-glib-devel",
+ ]
+ assert_equal expected, yaml_load(yaml)["requirements"]
+ end
+
+ def test_rdoc_options_hash_converted_to_array
+ # Some gemspecs incorrectly have rdoc_options: {} instead of rdoc_options: []
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test-gem
+ version: !ruby/object:Gem::Version
+ version: 1.0.0
+ rdoc_options: {}
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "test-gem", spec.name
+
+ assert_equal [], spec.rdoc_options
+ end
+
+ def test_load_returns_nil_for_comment_only_yaml
+ # Bundler config files may contain only comments after deleting all keys
+ result = yaml_load("---\n# BUNDLE_FOO: \"bar\"\n")
+ assert_nil result
+ end
+
+ def test_load_returns_nil_for_empty_document
+ assert_nil yaml_load("---\n")
+ assert_nil yaml_load("")
+ assert_raise(TypeError) { yaml_load(nil) }
+ end
+
+ def test_load_returns_hash_for_flow_empty_hash
+ # yaml_dump({}) produces "--- {}\n"
+ result = yaml_load("--- {}\n")
+ assert_kind_of Hash, result
+ assert_empty result
+ end
+
+ def test_load_parses_flow_empty_hash_as_value
+ result = yaml_load("metadata: {}\n")
+ assert_kind_of Hash, result
+ assert_kind_of Hash, result["metadata"]
+ assert_empty result["metadata"]
+ end
+
+ def test_yaml_non_specific_tag_stripped
+ # Legacy RubyGems (1.x) generated YAML with ! non-specific tags like:
+ # - ! '>='
+ # The ! prefix should be ignored.
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: legacy-gem
+ version: !ruby/object:Gem::Version
+ version: 0.1.0
+ required_ruby_version: !ruby/object:Gem::Requirement
+ none: false
+ requirements:
+ - - ! '>='
+ - !ruby/object:Gem::Version
+ version: '0'
+ required_rubygems_version: !ruby/object:Gem::Requirement
+ none: false
+ requirements:
+ - - ! '>='
+ - !ruby/object:Gem::Version
+ version: 1.3.5
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "legacy-gem", spec.name
+ assert_equal Gem::Requirement.new(">= 0"), spec.required_ruby_version
+ assert_equal Gem::Requirement.new(">= 1.3.5"), spec.required_rubygems_version
+ end
+
+ def test_legacy_gemspec_with_anchors_and_non_specific_tags
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = true
+
+ # Real-world pattern from gems like vegas-0.1.11 that combine
+ # YAML anchors/aliases with ! non-specific tags
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: legacy-gem
+ version: !ruby/object:Gem::Version
+ version: 0.1.11
+ dependencies:
+ - !ruby/object:Gem::Dependency
+ name: rack
+ requirement: &id001 !ruby/object:Gem::Requirement
+ none: false
+ requirements:
+ - - ! '>='
+ - !ruby/object:Gem::Version
+ version: 1.0.0
+ type: :runtime
+ prerelease: false
+ version_requirements: *id001
+ - !ruby/object:Gem::Dependency
+ name: mocha
+ requirement: &id002 !ruby/object:Gem::Requirement
+ none: false
+ requirements:
+ - - ~>
+ - !ruby/object:Gem::Version
+ version: 0.9.8
+ type: :development
+ prerelease: false
+ version_requirements: *id002
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "legacy-gem", spec.name
+
+ assert_equal 2, spec.dependencies.size
+
+ rack_dep = spec.dependencies.find {|d| d.name == "rack" }
+ assert_kind_of Gem::Dependency, rack_dep
+ assert_equal :runtime, rack_dep.type
+ assert_equal Gem::Requirement.new(">= 1.0.0"), rack_dep.requirement
+
+ mocha_dep = spec.dependencies.find {|d| d.name == "mocha" }
+ assert_kind_of Gem::Dependency, mocha_dep
+ assert_equal :development, mocha_dep.type
+ assert_equal Gem::Requirement.new("~> 0.9.8"), mocha_dep.requirement
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_non_specific_tag_on_plain_value
+ # ! tag on a bracketed value like rubyforge_project: ! '[none]'
+ result = yaml_load("key: ! '[none]'\n")
+ assert_equal({ "key" => "[none]" }, result)
+ end
+
+ def test_dump_quotes_dollar_sign_values
+ # Values starting with $ should be quoted to preserve them as strings
+ yaml = yaml_dump({ "BUNDLE_FOO" => "$BUILD_DIR", "BUNDLE_BAR" => "baz" })
+ assert_include yaml, 'BUNDLE_FOO: "$BUILD_DIR"'
+ assert_include yaml, "BUNDLE_BAR: baz"
+
+ # Round-trip: ensure the quoted value is parsed back correctly
+ result = yaml_load(yaml)
+ assert_equal "$BUILD_DIR", result["BUNDLE_FOO"]
+ assert_equal "baz", result["BUNDLE_BAR"]
+ end
+
+ def test_dump_quotes_special_characters
+ # Various special characters that should trigger quoting
+ special_values = {
+ "dollar" => "$HOME",
+ "exclamation" => "!important",
+ "ampersand" => "&anchor",
+ "asterisk" => "*ref",
+ "colon_prefix" => ":symbol",
+ "at_sign" => "@mention",
+ "percent" => "%encoded",
+ }
+
+ yaml = yaml_dump(special_values)
+ special_values.each do |key, value|
+ assert_include yaml, "#{key}: #{value.inspect}", "Value #{value.inspect} for key #{key} should be quoted"
+ end
+
+ # Round-trip
+ result = yaml_load(yaml)
+ special_values.each do |key, value|
+ assert_equal value, result[key], "Round-trip failed for key #{key}"
+ end
+ end
+
+ def test_load_ambiguous_value_with_colon
+ # "invalid: yaml: hah" is ambiguous YAML - our parser treats it as
+ # {"invalid" => "yaml: hah"}, but the value looks like a nested mapping.
+ # config_file.rb's load_file should detect this and reject it.
+ if Gem.use_psych?
+ # Psych raises a syntax error for this ambiguous YAML
+ assert_raise(Psych::SyntaxError) do
+ yaml_load("invalid: yaml: hah")
+ end
+ else
+ result = yaml_load("invalid: yaml: hah")
+ assert_kind_of Hash, result
+ assert_equal "yaml: hah", result["invalid"]
+ end
+ end
+
+ def test_nested_anchor_in_array_item
+ # Ensure aliases are enabled for this test
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = true
+
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test-gem
+ version: !ruby/object:Gem::Version
+ version: 1.0.0
+ dependencies:
+ - !ruby/object:Gem::Dependency
+ name: foo
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - &id002
+ - ">="
+ - !ruby/object:Gem::Version
+ version: "0"
+ type: :runtime
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ assert_equal "test-gem", spec.name
+
+ dep = spec.dependencies.first
+ assert_kind_of Gem::Dependency, dep
+
+ # Requirements should be parsed as nested arrays, not strings
+ assert_kind_of Array, dep.requirement.requirements
+ assert_equal 1, dep.requirement.requirements.size
+
+ req_item = dep.requirement.requirements.first
+ assert_kind_of Array, req_item
+ assert_equal ">=", req_item[0]
+ assert_kind_of Gem::Version, req_item[1]
+ assert_equal "0", req_item[1].version
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_roundtrip_specification
+ spec = Gem::Specification.new do |s|
+ s.name = "round-trip-test"
+ s.version = "2.3.4"
+ s.platform = "ruby"
+ s.authors = ["Test Author"]
+ s.summary = "A test gem for round-trip"
+ s.description = "Longer description of the test gem"
+ s.files = ["lib/foo.rb", "README.md"]
+ s.require_paths = ["lib"]
+ s.homepage = "https://example.com"
+ s.licenses = ["MIT"]
+ s.metadata = { "source_code_uri" => "https://example.com/src" }
+ s.add_dependency "rake", ">= 1.0"
+ end
+
+ yaml = yaml_dump(spec)
+ loaded = Gem::SafeYAML.safe_load(yaml)
+
+ assert_kind_of Gem::Specification, loaded
+ assert_equal "round-trip-test", loaded.name
+ assert_equal Gem::Version.new("2.3.4"), loaded.version
+ assert_equal ["Test Author"], loaded.authors
+ assert_equal "A test gem for round-trip", loaded.summary
+ assert_equal ["README.md", "lib/foo.rb"], loaded.files
+ assert_equal ["lib"], loaded.require_paths
+ assert_equal "https://example.com", loaded.homepage
+ assert_equal ["MIT"], loaded.licenses
+ assert_equal({ "source_code_uri" => "https://example.com/src" }, loaded.metadata)
+ assert_equal 1, loaded.dependencies.size
+
+ dep = loaded.dependencies.first
+ assert_equal "rake", dep.name
+ assert_equal :runtime, dep.type
+ end
+
+ def test_roundtrip_specification_with_extensions
+ spec = Gem::Specification.new do |s|
+ s.name = "native-ext-test"
+ s.version = "1.0.0"
+ s.authors = ["Test"]
+ s.summary = "A gem with native extensions"
+ s.files = ["lib/native.rb", "ext/native/extconf.rb", "ext/native/native.c"]
+ s.extensions = ["ext/native/extconf.rb"]
+ s.require_paths = ["lib"]
+ end
+
+ yaml = yaml_dump(spec)
+ loaded = Gem::SafeYAML.safe_load(yaml)
+
+ assert_kind_of Gem::Specification, loaded
+ assert_equal ["ext/native/extconf.rb"], loaded.extensions
+ assert_equal ["ext/native/extconf.rb", "ext/native/native.c", "lib/native.rb"], loaded.files
+ end
+
+ def test_roundtrip_specification_with_windows_paths
+ spec = Gem::Specification.new do |s|
+ s.name = "win-path-test"
+ s.version = "1.0.0"
+ s.authors = ["Test"]
+ s.summary = "A gem with Windows-style paths"
+ s.files = ["lib/foo.rb", "lib/foo/bar.rb"]
+ s.require_paths = ["lib"]
+ s.description = 'Installed in D:\ruby\lib\ruby\gems'
+ s.post_install_message = "Installed to C:\\Program Files\\Ruby\\lib\\rdoc"
+ end
+
+ yaml = yaml_dump(spec)
+ loaded = Gem::SafeYAML.safe_load(yaml)
+
+ assert_kind_of Gem::Specification, loaded
+ assert_equal 'Installed in D:\ruby\lib\ruby\gems', loaded.description
+ assert_equal "Installed to C:\\Program Files\\Ruby\\lib\\rdoc", loaded.post_install_message
+ end
+
+ def test_roundtrip_specification_with_metadata
+ spec = Gem::Specification.new do |s|
+ s.name = "metadata-test"
+ s.version = "1.0.0"
+ s.authors = ["Test"]
+ s.summary = "A gem with metadata"
+ s.files = ["lib/foo.rb"]
+ s.require_paths = ["lib"]
+ s.metadata = {
+ "changelog_uri" => "https://example.com/CHANGELOG.md",
+ "source_code_uri" => "https://github.com/example/metadata-test",
+ "bug_tracker_uri" => "https://github.com/example/metadata-test/issues",
+ "allowed_push_host" => "https://rubygems.org",
+ }
+ end
+
+ yaml = yaml_dump(spec)
+ loaded = Gem::SafeYAML.safe_load(yaml)
+
+ assert_kind_of Gem::Specification, loaded
+ assert_kind_of Hash, loaded.metadata
+ assert_equal 4, loaded.metadata.size
+ assert_equal "https://example.com/CHANGELOG.md", loaded.metadata["changelog_uri"]
+ assert_equal "https://github.com/example/metadata-test", loaded.metadata["source_code_uri"]
+ assert_equal "https://github.com/example/metadata-test/issues", loaded.metadata["bug_tracker_uri"]
+ assert_equal "https://rubygems.org", loaded.metadata["allowed_push_host"]
+ end
+
+ def test_roundtrip_version
+ ver = Gem::Version.new("1.2.3")
+ yaml = yaml_dump(ver)
+ loaded = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+
+ assert_kind_of Gem::Version, loaded
+ assert_equal ver, loaded
+ end
+
+ def test_roundtrip_platform
+ plat = Gem::Platform.new("x86_64-linux")
+ yaml = yaml_dump(plat)
+ loaded = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+
+ assert_kind_of Gem::Platform, loaded
+ assert_equal plat.cpu, loaded.cpu
+ assert_equal plat.os, loaded.os
+ assert_equal plat.version, loaded.version
+ end
+
+ def test_roundtrip_requirement
+ req = Gem::Requirement.new(">= 1.0", "< 2.0")
+ yaml = yaml_dump(req)
+ loaded = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+
+ assert_kind_of Gem::Requirement, loaded
+ assert_equal req.requirements.sort_by(&:to_s), loaded.requirements.sort_by(&:to_s)
+ end
+
+ def test_roundtrip_dependency
+ dep = Gem::Dependency.new("foo", ">= 1.0", :development)
+ yaml = yaml_dump(dep)
+ loaded = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+
+ assert_kind_of Gem::Dependency, loaded
+ assert_equal "foo", loaded.name
+ assert_equal :development, loaded.type
+ assert_equal dep.requirement.requirements, loaded.requirement.requirements
+ end
+
+ def test_roundtrip_nested_hash
+ obj = { "a" => { "b" => "c", "d" => [1, 2, 3] } }
+ yaml = yaml_dump(obj)
+ loaded = yaml_load(yaml)
+
+ assert_equal obj, loaded
+ end
+
+ def test_roundtrip_block_scalar
+ obj = { "text" => "line1\nline2\n" }
+ yaml = yaml_dump(obj)
+ loaded = yaml_load(yaml)
+
+ assert_equal "line1\nline2\n", loaded["text"]
+ end
+
+ def test_roundtrip_special_characters
+ obj = {
+ "dollar" => "$HOME",
+ "exclamation" => "!important",
+ "ampersand" => "&anchor",
+ "asterisk" => "*ref",
+ "colon_prefix" => ":symbol",
+ "hash_char" => "value#comment",
+ "brackets" => "[item]",
+ "braces" => "{key}",
+ "comma" => "a,b,c",
+ }
+ yaml = yaml_dump(obj)
+ loaded = yaml_load(yaml)
+
+ obj.each do |key, value|
+ assert_equal value, loaded[key], "Round-trip failed for key #{key}"
+ end
+ end
+
+ def test_roundtrip_boolean_nil_integer
+ obj = { "flag" => true, "count" => 42, "empty" => nil, "off" => false }
+ yaml = yaml_dump(obj)
+ loaded = yaml_load(yaml)
+
+ assert_equal true, loaded["flag"]
+ assert_equal 42, loaded["count"]
+ assert_nil loaded["empty"]
+ assert_equal false, loaded["off"]
+ end
+
+ def test_roundtrip_time
+ time = Time.utc(2024, 6, 15, 12, 30, 45)
+ obj = { "created" => time }
+ yaml = yaml_dump(obj)
+ loaded = yaml_load(yaml)
+
+ assert_kind_of Time, loaded["created"]
+ assert_equal time.year, loaded["created"].year
+ assert_equal time.month, loaded["created"].month
+ assert_equal time.day, loaded["created"].day
+ end
+
+ def test_roundtrip_empty_collections
+ obj = { "arr" => [], "hash" => {} }
+ yaml = yaml_dump(obj)
+ loaded = yaml_load(yaml)
+
+ assert_equal [], loaded["arr"]
+ assert_equal({}, loaded["hash"])
+ end
+
+ def test_load_double_quoted_escape_sequences
+ result = yaml_load("newline: \"hello\\nworld\"")
+ assert_equal "hello\nworld", result["newline"]
+
+ result = yaml_load("tab: \"col1\\tcol2\"")
+ assert_equal "col1\tcol2", result["tab"]
+
+ result = yaml_load("cr: \"line\\rend\"")
+ assert_equal "line\rend", result["cr"]
+
+ result = yaml_load("quote: \"say\\\"hi\\\"\"")
+ assert_equal "say\"hi\"", result["quote"]
+ end
+
+ def test_load_double_quoted_backslash_before_escape_chars
+ # \\r in YAML should become literal backslash + r, not carriage return
+ result = yaml_load('path: "D:\\\\ruby-mswin\\\\lib"')
+ assert_equal "D:\\ruby-mswin\\lib", result["path"]
+
+ # \\n should become literal backslash + n, not newline
+ result = yaml_load('path: "C:\\\\new_folder"')
+ assert_equal "C:\\new_folder", result["path"]
+
+ # \\t should become literal backslash + t, not tab
+ result = yaml_load('path: "C:\\\\tmp\\\\test"')
+ assert_equal "C:\\tmp\\test", result["path"]
+
+ # \\\\ should become two literal backslashes
+ result = yaml_load('val: "a\\\\\\\\b"')
+ assert_equal "a\\\\b", result["val"]
+ end
+
+ def test_load_single_quoted_escape
+ result = yaml_load("key: 'it''s'")
+ assert_equal "it's", result["key"]
+
+ result = yaml_load("key: 'no escape \\n here'")
+ assert_equal "no escape \\n here", result["key"]
+ end
+
+ def test_load_quoted_numeric_stays_string
+ result = yaml_load("key: \"42\"")
+ assert_equal "42", result["key"]
+ assert_kind_of String, result["key"]
+
+ result = yaml_load("key: '99'")
+ assert_equal "99", result["key"]
+ assert_kind_of String, result["key"]
+ end
+
+ def test_load_empty_string_value
+ result = yaml_load("key: \"\"")
+ assert_equal "", result["key"]
+ end
+
+ def test_load_unquoted_integer
+ result = yaml_load("key: 42")
+ assert_equal 42, result["key"]
+ assert_kind_of Integer, result["key"]
+
+ result = yaml_load("key: -7")
+ assert_equal(-7, result["key"])
+ end
+
+ def test_load_boolean_values
+ result = yaml_load("a: true\nb: false")
+ assert_equal true, result["a"]
+ assert_equal false, result["b"]
+ end
+
+ def test_load_nil_value
+ # YAML 1.2: "nil" is not a null value, only ~ and null are
+ result = yaml_load("key: nil")
+ assert_equal "nil", result["key"]
+
+ result = yaml_load("key: ~")
+ assert_nil result["key"]
+
+ result = yaml_load("key: null")
+ assert_nil result["key"]
+ end
+
+ def test_load_time_value
+ result = yaml_load("date: 2024-06-15 12:30:45.000000000 Z")
+ assert_kind_of Time, result["date"]
+ assert_equal 2024, result["date"].year
+ assert_equal 6, result["date"].month
+ assert_equal 15, result["date"].day
+ end
+
+ def test_load_block_scalar_keep_trailing_newline
+ yaml = "text: |\n line1\n line2\n"
+ result = yaml_load(yaml)
+ assert_equal "line1\nline2\n", result["text"]
+ end
+
+ def test_load_block_scalar_strip_trailing_newline
+ yaml = "text: |-\n no trailing newline\n"
+ result = yaml_load(yaml)
+ assert_equal "no trailing newline", result["text"]
+ refute result["text"].end_with?("\n")
+ end
+
+ def test_load_flow_array
+ result = yaml_load("items: [a, b, c]")
+ assert_equal ["a", "b", "c"], result["items"]
+ end
+
+ def test_load_flow_empty_array
+ result = yaml_load("items: []")
+ assert_equal [], result["items"]
+ end
+
+ def test_load_mapping_key_with_no_value
+ result = yaml_load("key:")
+ assert_kind_of Hash, result
+ assert_nil result["key"]
+ end
+
+ def test_load_sequence_item_as_mapping
+ yaml = "items:\n- name: foo\n ver: 1\n- name: bar\n ver: 2"
+ result = yaml_load(yaml)
+ assert_equal [{ "name" => "foo", "ver" => 1 }, { "name" => "bar", "ver" => 2 }], result["items"]
+ end
+
+ def test_load_nested_sequence
+ yaml = "matrix:\n- - a\n - b\n- - c\n - d"
+ result = yaml_load(yaml)
+ assert_equal [["a", "b"], ["c", "d"]], result["matrix"]
+ end
+
+ def test_load_comment_stripped_from_value
+ result = yaml_load("key: value # this is a comment")
+ assert_equal "value", result["key"]
+ end
+
+ def test_load_comment_in_quoted_string_preserved
+ result = yaml_load("key: \"value # not a comment\"")
+ assert_equal "value # not a comment", result["key"]
+
+ result = yaml_load("key: 'value # not a comment'")
+ assert_equal "value # not a comment", result["key"]
+ end
+
+ def test_load_crlf_line_endings
+ result = yaml_load("key: value\r\nother: data\r\n")
+ assert_equal "value", result["key"]
+ assert_equal "data", result["other"]
+ end
+
+ def test_load_version_requirement_old_tag
+ yaml = <<~YAML
+ !ruby/object:Gem::Version::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: "1.0"
+ YAML
+
+ req = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ assert_kind_of Gem::Requirement, req
+ assert_equal [[">=", Gem::Version.new("1.0")]], req.requirements
+ end
+
+ def test_load_dependency_version_version_requirement_old_tag
+ yaml = <<~YAML
+ - !ruby/object:Gem::Dependency
+ name: test-unit
+ type: :development
+ version_requirement:
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 2.0.2
+ version:
+ YAML
+
+ deps = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ assert_not_nil(deps.first)
+
+ assert_equal [[">=", Gem::Version.new("2.0.2")]], deps.first.requirement.requirements
+ end
+
+ def test_load_platform_from_value_field
+ yaml = "!ruby/object:Gem::Platform\nvalue: x86-linux\n"
+ plat = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ assert_kind_of Gem::Platform, plat
+ assert_nil plat.cpu
+ end
+
+ def test_load_platform_from_cpu_os_version_fields
+ yaml = "!ruby/object:Gem::Platform\ncpu: x86_64\nos: darwin\nversion: nil\n"
+ plat = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ assert_kind_of Gem::Platform, plat
+ assert_equal "x86_64", plat.cpu
+ assert_equal "darwin", plat.os
+ end
+
+ def test_load_platform_malicious_sequence
+ yaml = "!ruby/object:Gem::Platform\n- \"x86-mswin32\\n system('id')#\"\n"
+ result = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ refute_kind_of Gem::Platform, result
+ assert_kind_of Array, result
+ end
+
+ def test_load_dependency_missing_requirement_uses_default
+ yaml = <<~YAML
+ !ruby/object:Gem::Dependency
+ name: foo
+ type: :runtime
+ YAML
+
+ dep = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ assert_kind_of Gem::Dependency, dep
+ assert_equal "foo", dep.name
+ assert_equal :runtime, dep.type
+ assert_nil dep.instance_variable_get(:@requirement)
+ end
+
+ def test_load_dependency_missing_type_defaults_to_runtime
+ yaml = <<~YAML
+ !ruby/object:Gem::Dependency
+ name: bar
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ YAML
+
+ dep = yaml_load(yaml, permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES)
+ assert_equal :runtime, dep.type
+ end
+
+ def test_specification_version_non_numeric_string_not_converted
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test
+ version: !ruby/object:Gem::Version
+ version: 1.0.0
+ specification_version: abc
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Specification, spec
+ # Non-numeric string should not be converted to Integer
+ assert_equal "abc", spec.specification_version
+ end
+
+ def test_unknown_permitted_tag_raises_argument_error
+ yaml = "!ruby/object:MyCustomClass\nfoo: bar\n"
+ assert_raise(ArgumentError) do
+ yaml_load(yaml, permitted_classes: ["MyCustomClass"])
+ end
+ end
+
+ def test_dump_block_scalar_with_trailing_newline
+ yaml = yaml_dump({ "text" => "line1\nline2\n" })
+ assert_include yaml, " |\n"
+ refute_includes yaml, " |-\n"
+ end
+
+ def test_dump_block_scalar_without_trailing_newline
+ yaml = yaml_dump({ "text" => "line1\nline2" })
+ assert_include yaml, " |-\n"
+ end
+
+ def test_dump_nil_value
+ yaml = yaml_dump({ "key" => nil })
+
+ loaded = yaml_load(yaml)
+ assert_nil loaded["key"]
+ end
+
+ def test_dump_symbol_keys_quoted
+ yaml = yaml_dump({ foo: "bar" })
+ # Symbol keys should use inspect format
+ assert_include yaml, ":foo:"
+
+ # Symbol values in hash with symbol keys should be quoted
+ yaml = yaml_dump({ type: ":runtime" })
+ assert_include yaml, "\":runtime\""
+ end
+
+ def test_regression_flow_empty_hash_as_root
+ # Previously returned Mapping struct instead of Hash
+ result = yaml_load("--- {}")
+ assert_kind_of Hash, result
+ assert_empty result
+ end
+
+ def test_regression_alias_check_in_builder_not_parser
+ # Previously aliases were resolved in Parser, bypassing Builder's policy check.
+ # The Builder must enforce aliases: false.
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = false
+
+ # Alias in mapping value
+ assert_raise(Psych::AliasesNotEnabled) do
+ yaml_load("a: &x val\nb: *x", aliases: false)
+ end
+
+ # Alias in sequence item
+ assert_raise(Psych::AliasesNotEnabled) do
+ yaml_load("items:\n- &x val\n- *x", aliases: false)
+ end
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_regression_anchored_mapping_stored_for_alias_resolution
+ # Previously build_mapping didn't call store_anchor, so anchored
+ # Gem types (Requirement, etc.) couldn't be resolved via aliases.
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = true
+
+ yaml = <<~YAML
+ a: &req !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: '0'
+ b: *req
+ YAML
+
+ result = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Gem::Requirement, result["a"]
+ assert_kind_of Gem::Requirement, result["b"]
+ assert_equal result["a"].requirements, result["b"].requirements
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_regression_register_anchor_sets_node_anchor
+ # Previously register_anchor only stored node in @anchors hash but
+ # didn't set node.anchor, so Builder couldn't track anchored values.
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = true
+
+ yaml = <<~YAML
+ items:
+ - &item !ruby/object:Gem::Version
+ version: '1.0'
+ - *item
+ YAML
+
+ result = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Array, result["items"]
+ assert_equal 2, result["items"].size
+ assert_kind_of Gem::Version, result["items"][0]
+ assert_kind_of Gem::Version, result["items"][1]
+ assert_equal result["items"][0], result["items"][1]
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
+ def test_regression_coerce_empty_hash_not_wrapped_in_scalar
+ # Previously coerce("{}") returned Mapping but parse_plain_scalar
+ # wrapped it in Scalar.new(value: Mapping), causing type mismatch.
+ result = yaml_load("--- {}")
+ assert_kind_of Hash, result
+
+ result = yaml_load("key: {}")
+ assert_kind_of Hash, result["key"]
+ end
+
+ def test_regression_rdoc_options_normalized_to_array
+ # rdoc_options as Hash (malformed gemspec)
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test
+ version: !ruby/object:Gem::Version
+ version: 1.0.0
+ rdoc_options:
+ --title: MyGem
+ --main: README
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_equal ["--title", "MyGem", "--main", "README"], spec.rdoc_options
+ end
+
+ def test_regression_requirements_field_normalized_to_array
+ # The "requirements" field in a Specification (not Requirement)
+ # should be normalized from Hash to Array if malformed
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: test
+ version: !ruby/object:Gem::Version
+ version: 1.0.0
+ requirements:
+ foo: bar
+ YAML
+
+ spec = Gem::SafeYAML.safe_load(yaml)
+ assert_equal [["foo", "bar"]], spec.requirements
+ end
+
+ def test_binary_tag_decoded_in_mapping_key
+ yaml = <<~YAML
+ ---
+ !binary "U0hBMQ==":
+ metadata.gz: abc123
+ YAML
+
+ result = yaml_load(yaml)
+ assert_equal "SHA1", result.keys.first
+ assert_equal "abc123", result["SHA1"]["metadata.gz"]
+ end
+
+ def test_binary_tag_decoded_in_block_scalar_value
+ yaml = <<~YAML
+ ---
+ SHA256:
+ metadata.gz: !binary |-
+ OWY4YTM5Y2MxOTc3Mzc5MWYzNzk1NjRmZjVlYzljYjY1MDQwYWIwMg==
+ YAML
+
+ result = yaml_load(yaml)
+ assert_equal "9f8a39cc19773791f379564ff5ec9cb65040ab02", result["SHA256"]["metadata.gz"]
+ end
+
+ def test_binary_tag_decoded_in_inline_value
+ yaml = <<~YAML
+ ---
+ key: !binary "U0hBMQ=="
+ YAML
+
+ result = yaml_load(yaml)
+ assert_equal "SHA1", result["key"]
+ end
+
+ def test_binary_tag_checksums_yaml_roundtrip
+ # Simulates the checksums.yaml.gz format from older gems
+ yaml = <<~YAML
+ ---
+ !binary "U0hBMQ==":
+ metadata.gz: !binary |-
+ OWY4YTM5Y2MxOTc3Mzc5MWYzNzk1NjRmZjVlYzljYjY1MDQwYWIwMg==
+ data.tar.gz: !binary |-
+ ZTRmZGRhNjc1MWM5NmIwYzRhODFkYjI0OTlkMjY3ZjQ2MWNkMGM1ZA==
+ YAML
+
+ result = yaml_load(yaml)
+ assert_equal ["SHA1"], result.keys
+ assert_equal "9f8a39cc19773791f379564ff5ec9cb65040ab02", result["SHA1"]["metadata.gz"]
+ assert_equal "e4fdda6751c96b0c4a81db2499d267f461cd0c5d", result["SHA1"]["data.tar.gz"]
+ end
+
+ def test_binary_tag_decoded_in_sequence_item_inline
+ yaml = <<~YAML
+ ---
+ - !binary "U0hBMQ=="
+ YAML
+
+ result = yaml_load(yaml)
+ assert_equal ["SHA1"], result
+ end
+
+ def test_version_requirement_tag_always_permitted
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Specification
+ name: escape
+ version: !ruby/object:Gem::Version
+ version: 0.0.4
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
+ requirements:
+ - - ">"
+ - !ruby/object:Gem::Version
+ version: 0.0.0
+ version:
+ YAML
+
+ result = yaml_load(yaml)
+ assert_kind_of Gem::Specification, result
+ assert_equal "escape", result.name
+ assert_kind_of Gem::Requirement, result.required_ruby_version
+ end
end
diff --git a/test/rubygems/test_gem_security_trust_dir.rb b/test/rubygems/test_gem_security_trust_dir.rb
index cfde8e9d48..bd3dfb86c2 100644
--- a/test/rubygems/test_gem_security_trust_dir.rb
+++ b/test/rubygems/test_gem_security_trust_dir.rb
@@ -56,7 +56,7 @@ class TestGemSecurityTrustDir < Gem::TestCase
assert_path_exist trusted
- mask = 0o100600 & (~File.umask)
+ mask = 0o100600 & ~File.umask
assert_equal mask, File.stat(trusted).mode unless Gem.win_platform?
@@ -70,7 +70,7 @@ class TestGemSecurityTrustDir < Gem::TestCase
assert_path_exist @dest_dir
- mask = 0o040700 & (~File.umask)
+ mask = 0o040700 & ~File.umask
mask |= 0o200000 if RUBY_PLATFORM.include?("aix")
assert_equal mask, File.stat(@dest_dir).mode unless Gem.win_platform?
@@ -91,7 +91,7 @@ class TestGemSecurityTrustDir < Gem::TestCase
@trust_dir.verify
- mask = 0o40700 & (~File.umask)
+ mask = 0o40700 & ~File.umask
mask |= 0o200000 if RUBY_PLATFORM.include?("aix")
assert_equal mask, File.stat(@dest_dir).mode unless Gem.win_platform?
diff --git a/test/rubygems/test_gem_source_git.rb b/test/rubygems/test_gem_source_git.rb
index fef79a0743..b7b2c52f9a 100644
--- a/test/rubygems/test_gem_source_git.rb
+++ b/test/rubygems/test_gem_source_git.rb
@@ -65,6 +65,8 @@ class TestGemSourceGit < Gem::TestCase
end
def test_checkout_submodules
+ omit "JRuby on Windows hits git submodule path differences" if Gem.win_platform? && Gem.java_platform?
+
# We need to allow to checkout submodules with file:// protocol
# CVE-2022-39253
# https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
diff --git a/test/rubygems/test_gem_source_list.rb b/test/rubygems/test_gem_source_list.rb
index 64353f8f90..5327b14db8 100644
--- a/test/rubygems/test_gem_source_list.rb
+++ b/test/rubygems/test_gem_source_list.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
-require "rubygems"
-require "rubygems/source_list"
require_relative "helper"
+require "rubygems/source_list"
class TestGemSourceList < Gem::TestCase
def setup
@@ -116,4 +115,128 @@ class TestGemSourceList < Gem::TestCase
@sl.delete Gem::Source.new(@uri)
assert_equal @sl.sources, []
end
+
+ def test_prepend_new_source
+ uri2 = "http://example2"
+ source2 = Gem::Source.new(uri2)
+
+ result = @sl.prepend(uri2)
+
+ assert_kind_of Gem::Source, result
+ assert_kind_of Gem::URI, result.uri
+ assert_equal uri2, result.uri.to_s
+ assert_equal [source2, @source], @sl.sources
+ end
+
+ def test_prepend_existing_source
+ uri2 = "http://example2"
+ source2 = Gem::Source.new(uri2)
+ @sl << uri2
+
+ assert_equal [@source, source2], @sl.sources
+
+ result = @sl.prepend(uri2)
+
+ assert_kind_of Gem::Source, result
+ assert_kind_of Gem::URI, result.uri
+ assert_equal uri2, result.uri.to_s
+ assert_equal [source2, @source], @sl.sources
+ end
+
+ def test_prepend_alias_behaves_like_unshift
+ sl = Gem::SourceList.new
+
+ uri1 = "http://one"
+ uri2 = "http://two"
+
+ source1 = sl << uri1
+ source2 = sl << uri2
+
+ # move existing to front
+ result = sl.prepend(uri2)
+
+ assert_kind_of Gem::Source, result
+ assert_equal [source2, source1], sl.sources
+
+ # and again with the other
+ result = sl.prepend(uri1)
+ assert_equal [source1, source2], sl.sources
+ end
+
+ def test_append_method_new_source
+ sl = Gem::SourceList.new
+
+ uri1 = "http://example1"
+
+ result = sl.append(uri1)
+
+ assert_kind_of Gem::Source, result
+ assert_kind_of Gem::URI, result.uri
+ assert_equal uri1, result.uri.to_s
+ assert_equal [result], sl.sources
+ end
+
+ def test_append_method_existing_moves_to_end
+ sl = Gem::SourceList.new
+
+ uri1 = "http://example1"
+ uri2 = "http://example2"
+
+ s1 = sl << uri1
+ s2 = sl << uri2
+
+ # list is [s1, s2]; appending s1 should move it to end => [s2, s1]
+ result = sl.append(uri1)
+
+ assert_equal s1, result
+ assert_equal [s2, s1], sl.sources
+ end
+
+ def test_prepend_with_gem_source_object
+ sl = Gem::SourceList.new
+
+ uri1 = "http://example1"
+ uri2 = "http://example2"
+ source1 = Gem::Source.new(uri1)
+ source2 = Gem::Source.new(uri2)
+
+ # Add first source
+ sl << source1
+
+ # Prepend with Gem::Source object
+ result = sl.prepend(source2)
+
+ assert_equal source2, result
+ assert_equal [source2, source1], sl.sources
+
+ # Prepend existing source - should move to front
+ result = sl.prepend(source1)
+
+ assert_equal source1, result
+ assert_equal [source1, source2], sl.sources
+ end
+
+ def test_append_with_gem_source_object
+ sl = Gem::SourceList.new
+
+ uri1 = "http://example1"
+ uri2 = "http://example2"
+ source1 = Gem::Source.new(uri1)
+ source2 = Gem::Source.new(uri2)
+
+ # Add first source
+ sl << source1
+
+ # Append with Gem::Source object
+ result = sl.append(source2)
+
+ assert_equal source2, result
+ assert_equal [source1, source2], sl.sources
+
+ # Append existing source - should move to end
+ result = sl.append(source1)
+
+ assert_equal source1, result
+ assert_equal [source2, source1], sl.sources
+ end
end
diff --git a/test/rubygems/test_gem_source_local.rb b/test/rubygems/test_gem_source_local.rb
index e9d7f45482..6062173629 100644
--- a/test/rubygems/test_gem_source_local.rb
+++ b/test/rubygems/test_gem_source_local.rb
@@ -63,6 +63,30 @@ class TestGemSourceLocal < Gem::TestCase
assert_equal "a-2.a", @sl.find_gem("a", req, true).full_name
end
+ def test_find_all_gems
+ _, a2_gem = util_gem "a", "2"
+ FileUtils.mv a2_gem, @tempdir
+
+ results = @sl.find_all_gems("a")
+ assert_equal ["a-1", "a-2"], results.map(&:full_name).sort
+ end
+
+ def test_find_all_gems_excludes_prerelease_by_default
+ results = @sl.find_all_gems("a")
+ assert_equal ["a-1"], results.map(&:full_name)
+ end
+
+ def test_find_all_gems_includes_prerelease_when_requested
+ results = @sl.find_all_gems("a", Gem::Requirement.create(">= 0"), true)
+ assert_equal ["a-1", "a-2.a"], results.map(&:full_name).sort
+ end
+
+ def test_find_all_gems_includes_prerelease_when_requirement_is_prerelease
+ req = Gem::Requirement.create("= 2.a")
+ results = @sl.find_all_gems("a", req)
+ assert_equal ["a-2.a"], results.map(&:full_name)
+ end
+
def test_fetch_spec
s = @sl.fetch_spec @a.name_tuple
assert_equal s, @a
diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb
index 3f8d921467..79be0c996d 100644
--- a/test/rubygems/test_gem_specification.rb
+++ b/test/rubygems/test_gem_specification.rb
@@ -33,7 +33,6 @@ has_rdoc: true
Gem::Specification.new do |s|
s.name = %q{keyedlist}
s.version = %q{0.4.0}
- s.has_rdoc = true
s.summary = %q{A Hash which automatically computes keys.}
s.files = [%q{lib/keyedlist.rb}]
s.require_paths = [%q{lib}]
@@ -818,7 +817,7 @@ dependencies: []
write_file full_path do |io|
io.write @a2.to_ruby_for_cache
end
- rescue Errno::EINVAL
+ rescue Errno::EINVAL, Errno::EACCES
pend "cannot create '#{full_path}' on this platform"
end
@@ -837,7 +836,7 @@ dependencies: []
write_file full_path do |io|
io.write @a2.to_ruby_for_cache
end
- rescue Errno::EINVAL
+ rescue Errno::EINVAL, Errno::EACCES
pend "cannot create '#{full_path}' on this platform"
end
@@ -856,7 +855,7 @@ dependencies: []
write_file full_path do |io|
io.write @a2.to_ruby_for_cache
end
- rescue Errno::EINVAL
+ rescue Errno::EINVAL, Errno::EACCES
pend "cannot create '#{full_path}' on this platform"
end
@@ -1029,7 +1028,7 @@ dependencies: []
gem = "mingw"
v = "1.1.1"
- platforms = ["x86-mingw32", "x64-mingw32"]
+ platforms = ["x86-mingw32", "x64-mingw-ucrt"]
# create specs
platforms.each do |plat|
@@ -1248,12 +1247,37 @@ dependencies: []
end
def test_initialize_nil_version
- expected = "nil versions are discouraged and will be deprecated in Rubygems 4\n"
- actual_stdout, actual_stderr = capture_output do
- Gem::Specification.new.version = nil
+ spec = Gem::Specification.new
+ spec.name = "test-name"
+
+ assert_nil spec.version
+ spec.version = nil
+ assert_nil spec.version
+
+ spec.summary = "test gem"
+ spec.authors = ["test author"]
+ e = assert_raise Gem::InvalidSpecificationException do
+ spec.validate
end
- assert_empty actual_stdout
- assert_equal(expected, actual_stderr)
+ assert_match("missing value for attribute version", e.message)
+ end
+
+ def test_set_version_to_nil_after_setting_version
+ spec = Gem::Specification.new
+ spec.name = "test-name"
+
+ assert_nil spec.version
+ spec.version = "1.0.0"
+ assert_equal "1.0.0", spec.version.to_s
+ spec.version = nil
+ assert_nil spec.version
+
+ spec.summary = "test gem"
+ spec.authors = ["test author"]
+ e = assert_raise Gem::InvalidSpecificationException do
+ spec.validate
+ end
+ assert_match("missing value for attribute version", e.message)
end
def test__dump
@@ -1554,13 +1578,21 @@ dependencies: []
ext_spec
_, err = capture_output do
- refute @ext.contains_requirable_file? "nonexistent"
+ if RUBY_ENGINE == "jruby"
+ refute @ext.ignored?
+ else
+ refute @ext.contains_requirable_file? "nonexistent"
+ end
end
- expected = "Ignoring ext-1 because its extensions are not built. " \
- "Try: gem pristine ext --version 1\n"
+ if RUBY_ENGINE == "jruby"
+ assert_equal "", err
+ else
+ expected = "Ignoring ext-1 because its extensions are not built. " \
+ "Try: gem pristine ext --version 1\n"
- assert_equal expected, err
+ assert_equal expected, err
+ end
end
def test_contains_requirable_file_eh_extension_java_platform
@@ -2216,9 +2248,9 @@ dependencies: []
s1 = util_spec "a", "1"
s2 = util_spec "b", "1"
- assert_equal(-1, (s1 <=> s2))
- assert_equal(0, (s1 <=> s1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
- assert_equal(1, (s2 <=> s1))
+ assert_equal(-1, s1 <=> s2)
+ assert_equal(0, s1 <=> s1) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
+ assert_equal(1, s2 <=> s1)
end
def test_spaceship_platform
@@ -2227,18 +2259,18 @@ dependencies: []
s.platform = Gem::Platform.new "x86-my_platform1"
end
- assert_equal(-1, (s1 <=> s2))
- assert_equal(0, (s1 <=> s1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
- assert_equal(1, (s2 <=> s1))
+ assert_equal(-1, s1 <=> s2)
+ assert_equal(0, s1 <=> s1) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
+ assert_equal(1, s2 <=> s1)
end
def test_spaceship_version
s1 = util_spec "a", "1"
s2 = util_spec "a", "2"
- assert_equal(-1, (s1 <=> s2))
- assert_equal(0, (s1 <=> s1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
- assert_equal(1, (s2 <=> s1))
+ assert_equal(-1, s1 <=> s2)
+ assert_equal(0, s1 <=> s1) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
+ assert_equal(1, s2 <=> s1)
end
def test_spec_file
@@ -2671,27 +2703,7 @@ end
@a1.validate
end
- expected = <<-EXPECTED
-#{w}: prerelease dependency on b (>= 1.0.rc1) is not recommended
-#{w}: prerelease dependency on c (>= 2.0.rc2, development) is not recommended
-#{w}: open-ended dependency on i (>= 1.2) is not recommended
- if i is semantically versioned, use:
- add_runtime_dependency "i", "~> 1.2"
-#{w}: open-ended dependency on j (>= 1.2.3) is not recommended
- if j is semantically versioned, use:
- add_runtime_dependency "j", "~> 1.2", ">= 1.2.3"
-#{w}: open-ended dependency on k (> 1.2) is not recommended
- if k is semantically versioned, use:
- add_runtime_dependency "k", "~> 1.2", "> 1.2"
-#{w}: open-ended dependency on l (> 1.2.3) is not recommended
- if l is semantically versioned, use:
- add_runtime_dependency "l", "~> 1.2", "> 1.2.3"
-#{w}: open-ended dependency on o (>= 0) is not recommended
- use a bounded requirement, such as "~> x.y"
-#{w}: See https://guides.rubygems.org/specification-reference/ for help
- EXPECTED
-
- assert_equal expected, @ui.error, "warning"
+ assert_equal "", @ui.error, "warning"
end
end
@@ -2808,14 +2820,13 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use:
Dir.chdir @tempdir do
@a1.add_dependency @a1.name, "1"
- use_ui @ui do
+ e = assert_raise Gem::InvalidSpecificationException do
@a1.validate
end
- assert_equal <<-EXPECTED, @ui.error
-#{w}: Self referencing dependency is unnecessary and strongly discouraged.
-#{w}: See https://guides.rubygems.org/specification-reference/ for help
- EXPECTED
+ expected = "Dependencies of this gem include a self-reference."
+
+ assert_equal expected, e.message
end
end
@@ -2883,6 +2894,61 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use:
end
end
+ def test_validate_extension_require_relative_warning
+ util_setup_validate
+
+ Dir.chdir @tempdir do
+ @a1.extensions = ["ext/a/extconf.rb"]
+ @a1.files = %w[lib/code.rb lib/a.rb ext/a/extconf.rb]
+
+ File.write File.join("lib", "a.rb"), 'require_relative "a/a"'
+
+ use_ui @ui do
+ @a1.validate
+ end
+
+ assert_match(%r{require_relative "a/a"}, @ui.error)
+ assert_match(/will break in RubyGems 4\.2/, @ui.error)
+ assert_match(/Use `require` instead of `require_relative`/, @ui.error)
+ end
+ end
+
+ def test_validate_extension_require_relative_no_warning_when_rb_exists
+ util_setup_validate
+
+ Dir.chdir @tempdir do
+ @a1.extensions = ["ext/a/extconf.rb"]
+ @a1.files = %w[lib/code.rb lib/a.rb lib/a/a.rb ext/a/extconf.rb]
+
+ FileUtils.mkdir_p File.join("lib", "a")
+ File.write File.join("lib", "a.rb"), 'require_relative "a/a"'
+ File.write File.join("lib", "a", "a.rb"), ""
+
+ use_ui @ui do
+ @a1.validate
+ end
+
+ refute_match(/require_relative/, @ui.error)
+ end
+ end
+
+ def test_validate_extension_require_relative_no_warning_without_extensions
+ util_setup_validate
+
+ Dir.chdir @tempdir do
+ @a1.extensions = []
+ @a1.files = %w[lib/code.rb lib/a.rb]
+
+ File.write File.join("lib", "a.rb"), 'require_relative "a/a"'
+
+ use_ui @ui do
+ @a1.validate
+ end
+
+ refute_match(/require_relative/, @ui.error)
+ end
+ end
+
def test_validate_description
util_setup_validate
@@ -3009,6 +3075,65 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use:
assert_match "#{w}: bin/exec is missing #! line\n", @ui.error, "error"
end
+ def test_validate_executables_with_space
+ util_setup_validate
+
+ FileUtils.mkdir_p File.join(@tempdir, "bin")
+ File.write File.join(@tempdir, "bin", "echo hax"), "#!/usr/bin/env ruby\n"
+
+ @a1.executables = ["echo hax"]
+
+ e = assert_raise Gem::InvalidSpecificationException do
+ use_ui @ui do
+ Dir.chdir @tempdir do
+ @a1.validate
+ end
+ end
+ end
+
+ assert_match "executable \"echo hax\" contains invalid characters", e.message
+ end
+
+ def test_validate_executables_with_path_separator
+ util_setup_validate
+
+ FileUtils.mkdir_p File.join(@tempdir, "bin")
+ File.write File.join(@tempdir, "exe"), "#!/usr/bin/env ruby\n"
+
+ @a1.executables = Gem.win_platform? ? ["..\\exe"] : ["../exe"]
+
+ e = assert_raise Gem::InvalidSpecificationException do
+ use_ui @ui do
+ Dir.chdir @tempdir do
+ @a1.validate
+ end
+ end
+ end
+
+ assert_match "executable \"#{Gem.win_platform? ? "..\\exe" : "../exe"}\" contains invalid characters", e.message
+ end
+
+ def test_validate_executables_with_path_list_separator
+ sep = Gem.win_platform? ? ";" : ":"
+
+ util_setup_validate
+
+ FileUtils.mkdir_p File.join(@tempdir, "bin")
+ File.write File.join(@tempdir, "bin", "foo#{sep}bar"), "#!/usr/bin/env ruby\n"
+
+ @a1.executables = ["foo#{sep}bar"]
+
+ e = assert_raise Gem::InvalidSpecificationException do
+ use_ui @ui do
+ Dir.chdir @tempdir do
+ @a1.validate
+ end
+ end
+ end
+
+ assert_match "executable \"foo#{sep}bar\" contains invalid characters", e.message
+ end
+
def test_validate_empty_require_paths
util_setup_validate
@@ -3664,8 +3789,6 @@ Did you mean 'Ruby'?
end
def test__load_fixes_Date_objects
- pend "Marshal.load of links and floats is broken on truffleruby, see https://github.com/oracle/truffleruby/issues/3747" if RUBY_ENGINE == "truffleruby"
-
spec = util_spec "a", 1
spec.instance_variable_set :@date, Date.today
@@ -3892,7 +4015,11 @@ end
def test_missing_extensions_eh
ext_spec
- assert @ext.missing_extensions?
+ if RUBY_ENGINE == "jruby"
+ refute @ext.missing_extensions?
+ else
+ assert @ext.missing_extensions?
+ end
extconf_rb = File.join @ext.gem_dir, @ext.extensions.first
FileUtils.mkdir_p File.dirname extconf_rb
diff --git a/test/rubygems/test_gem_stub_specification.rb b/test/rubygems/test_gem_stub_specification.rb
index 4b2d4c570a..6c07480c7f 100644
--- a/test/rubygems/test_gem_stub_specification.rb
+++ b/test/rubygems/test_gem_stub_specification.rb
@@ -68,13 +68,21 @@ class TestStubSpecification < Gem::TestCase
def test_contains_requirable_file_eh_extension
stub_with_extension do |stub|
_, err = capture_output do
- refute stub.contains_requirable_file? "nonexistent"
+ if RUBY_ENGINE == "jruby"
+ refute stub.ignored?
+ else
+ refute stub.contains_requirable_file? "nonexistent"
+ end
end
- expected = "Ignoring stub_e-2 because its extensions are not built. " \
- "Try: gem pristine stub_e --version 2\n"
+ if RUBY_ENGINE == "jruby"
+ assert_equal "", err
+ else
+ expected = "Ignoring stub_e-2 because its extensions are not built. " \
+ "Try: gem pristine stub_e --version 2\n"
- assert_equal expected, err
+ assert_equal expected, err
+ end
end
end
@@ -137,7 +145,11 @@ class TestStubSpecification < Gem::TestCase
end
end
- assert stub.missing_extensions?
+ if RUBY_ENGINE == "jruby"
+ refute stub.missing_extensions?
+ else
+ assert stub.missing_extensions?
+ end
stub.build_extensions
@@ -209,7 +221,7 @@ class TestStubSpecification < Gem::TestCase
end
def stub_with_version
- spec = File.join @gemhome, "specifications", "stub_e-2.gemspec"
+ spec = File.join @gemhome, "specifications", "stub_v-with-version.gemspec"
File.open spec, "w" do |io|
io.write <<~STUB
# -*- encoding: utf-8 -*-
@@ -232,7 +244,7 @@ class TestStubSpecification < Gem::TestCase
end
def stub_without_version
- spec = File.join @gemhome, "specifications", "stub-2.gemspec"
+ spec = File.join @gemhome, "specifications", "stub_v-without-version.gemspec"
File.open spec, "w" do |io|
io.write <<~STUB
# -*- encoding: utf-8 -*-
diff --git a/test/rubygems/test_gem_uri.rb b/test/rubygems/test_gem_uri.rb
index 1253ebc6de..ce633c99b6 100644
--- a/test/rubygems/test_gem_uri.rb
+++ b/test/rubygems/test_gem_uri.rb
@@ -21,7 +21,7 @@ class TestUri < Gem::TestCase
end
def test_redacted_with_user_x_oauth_basic
- assert_equal "https://REDACTED:x-oauth-basic@example.com", Gem::Uri.new("https://token:x-oauth-basic@example.com").redacted.to_s
+ assert_equal "https://REDACTED@example.com", Gem::Uri.new("https://token:x-oauth-basic@example.com").redacted.to_s
end
def test_redacted_without_credential
diff --git a/test/rubygems/test_gem_util.rb b/test/rubygems/test_gem_util.rb
index 608210a903..9688d066db 100644
--- a/test/rubygems/test_gem_util.rb
+++ b/test/rubygems/test_gem_util.rb
@@ -13,17 +13,6 @@ class TestGemUtil < Gem::TestCase
end
end
- def test_silent_system
- pend if Gem.java_platform?
- Gem::Deprecate.skip_during do
- out, err = capture_output do
- Gem::Util.silent_system(*ruby_with_rubygems_in_load_path, "-e", 'puts "hello"; warn "hello"')
- end
- assert_empty out
- assert_empty err
- end
- end
-
def test_traverse_parents
FileUtils.mkdir_p "a/b/c"
diff --git a/test/rubygems/test_gem_util_atomic_file_writer.rb b/test/rubygems/test_gem_util_atomic_file_writer.rb
new file mode 100644
index 0000000000..e011a38ad4
--- /dev/null
+++ b/test/rubygems/test_gem_util_atomic_file_writer.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require_relative "helper"
+require "rubygems/util/atomic_file_writer"
+
+class TestGemUtilAtomicFileWriter < Gem::TestCase
+ def test_external_encoding
+ Gem::AtomicFileWriter.open(File.join(@tempdir, "test.txt")) do |file|
+ assert_equal(Encoding::ASCII_8BIT, file.external_encoding)
+ end
+ end
+end
diff --git a/test/rubygems/test_gem_version.rb b/test/rubygems/test_gem_version.rb
index cf771bc5a1..f58359e54c 100644
--- a/test/rubygems/test_gem_version.rb
+++ b/test/rubygems/test_gem_version.rb
@@ -7,6 +7,11 @@ class TestGemVersion < Gem::TestCase
class V < ::Gem::Version
end
+ def test_nil_is_zero
+ zero = Gem::Version.create nil
+ assert_equal Gem::Version.create(0), zero
+ end
+
def test_bump
assert_bumped_version_equal "5.3", "5.2.4"
end
@@ -35,13 +40,6 @@ class TestGemVersion < Gem::TestCase
assert_same real, Gem::Version.create(real)
- expected = "nil versions are discouraged and will be deprecated in Rubygems 4\n"
- actual_stdout, actual_stderr = capture_output do
- assert_nil Gem::Version.create(nil)
- end
- assert_empty actual_stdout
- assert_equal(expected, actual_stderr)
-
assert_equal v("5.1"), Gem::Version.create("5.1")
ver = "1.1"
@@ -51,13 +49,7 @@ class TestGemVersion < Gem::TestCase
def test_class_correct
assert_equal true, Gem::Version.correct?("5.1")
assert_equal false, Gem::Version.correct?("an incorrect version")
-
- expected = "nil versions are discouraged and will be deprecated in Rubygems 4\n"
- actual_stdout, actual_stderr = capture_output do
- Gem::Version.correct?(nil)
- end
- assert_empty actual_stdout
- assert_equal(expected, actual_stderr)
+ assert_equal true, Gem::Version.correct?(nil)
end
def test_class_new_subclass
@@ -162,33 +154,36 @@ class TestGemVersion < Gem::TestCase
assert_equal(-1, v("5.a") <=> v("5.0.0.rc2"))
assert_equal(1, v("5.x") <=> v("5.0.0.rc2"))
- assert_equal(0, v("1.9.3") <=> "1.9.3")
- assert_equal(1, v("1.9.3") <=> "1.9.2.99")
- assert_equal(-1, v("1.9.3") <=> "1.9.3.1")
-
- assert_nil v("1.0") <=> "whatever"
+ [
+ [0, "1.9.3"],
+ [1, "1.9.2.99"],
+ [-1, "1.9.3.1"],
+ [nil, "whatever"],
+ ].each do |cmp, string_ver|
+ assert_equal(cmp, v("1.9.3") <=> string_ver)
+ end
end
def test_approximate_recommendation
- assert_approximate_equal "~> 1.0", "1"
+ assert_approximate_equal ">= 1.0", "1"
assert_approximate_satisfies_itself "1"
- assert_approximate_equal "~> 1.0", "1.0"
+ assert_approximate_equal ">= 1.0", "1.0"
assert_approximate_satisfies_itself "1.0"
- assert_approximate_equal "~> 1.2", "1.2"
+ assert_approximate_equal ">= 1.2", "1.2"
assert_approximate_satisfies_itself "1.2"
- assert_approximate_equal "~> 1.2", "1.2.0"
+ assert_approximate_equal ">= 1.2", "1.2.0"
assert_approximate_satisfies_itself "1.2.0"
- assert_approximate_equal "~> 1.2", "1.2.3"
+ assert_approximate_equal ">= 1.2", "1.2.3"
assert_approximate_satisfies_itself "1.2.3"
- assert_approximate_equal "~> 1.2.a", "1.2.3.a.4"
+ assert_approximate_equal ">= 1.2.a", "1.2.3.a.4"
assert_approximate_satisfies_itself "1.2.3.a.4"
- assert_approximate_equal "~> 1.9.a", "1.9.0.dev"
+ assert_approximate_equal ">= 1.9.a", "1.9.0.dev"
assert_approximate_satisfies_itself "1.9.0.dev"
end
@@ -205,6 +200,51 @@ class TestGemVersion < Gem::TestCase
assert_less_than "1.0.0-1", "1"
end
+ def test_sort_key_is_computed_on_regular_release
+ refute_nil v("9.8.7").send(:sort_key)
+ end
+
+ def test_sort_key_is_computed_on_security_release
+ refute_nil v("9.8.7.1").send(:sort_key)
+ end
+
+ def test_sort_key_is_not_computed_on_prerelease
+ assert_nil v("9.8.7.pre1").send(:sort_key)
+ end
+
+ def test_sort_key_is_not_computed_on_version_with_more_segments
+ assert_nil v("1.1.1.1.1.1.1").send(:sort_key)
+ end
+
+ def test_sort_key_is_not_computed_on_huge_numbers
+ assert_nil v("2.30.1.250000").send(:sort_key)
+ end
+
+ def test_sort_key_on_timestamped_version
+ a = v("1.0.0")
+ b = v("0.0.1.20220404083012")
+
+ assert_operator a, :>, b
+ end
+
+ def test_sort_key_when_segment_is_higher_than_radix
+ a = v("0.7.0")
+ b = v("0.6.63000")
+
+ assert_operator(a, :>, b)
+ end
+
+ def test_sort_key_is_used_for_comparison
+ a = v("18.0.1")
+ b = v("18.0.2")
+
+ # Ensure the slow path isn't getting hit
+ a.instance_variable_set(:@version, nil)
+ a.instance_variable_set(:@canonical_segments, nil)
+
+ assert_operator(a, :<, b)
+ end
+
# modifying the segments of a version should not affect the segments of the cached version object
def test_segments
v("9.8.7").segments[2] += 1
diff --git a/test/rubygems/test_project_sanity.rb b/test/rubygems/test_project_sanity.rb
index 8f23b2d8c0..3b08d1ec7b 100644
--- a/test/rubygems/test_project_sanity.rb
+++ b/test/rubygems/test_project_sanity.rb
@@ -12,6 +12,7 @@ class TestGemProjectSanity < Gem::TestCase
def test_manifest_is_up_to_date
pend unless File.exist?("#{root}/Rakefile")
+ omit "JRuby on Windows cannot exec the bin/rake shebang" if Gem.win_platform? && Gem.java_platform?
rake = "#{root}/bin/rake"
_, status = Open3.capture2e(rake, "check_manifest")
@@ -37,6 +38,8 @@ class TestGemProjectSanity < Gem::TestCase
end
def test_require_rubygems_package
+ omit "JRuby on Windows fails to spawn ruby --disable-gems here" if Gem.win_platform? && Gem.java_platform?
+
err, status = Open3.capture2e(*ruby_with_rubygems_in_load_path, "--disable-gems", "-e", "require \"rubygems/package\"")
assert status.success?, err
diff --git a/test/rubygems/test_require.rb b/test/rubygems/test_require.rb
index f63c23c315..db86a30905 100644
--- a/test/rubygems/test_require.rb
+++ b/test/rubygems/test_require.rb
@@ -431,6 +431,22 @@ class TestGemRequire < Gem::TestCase
assert_equal %w[default-2.0.0.0], loaded_spec_names
end
+ def test_multiple_gems_with_the_same_path_the_non_activated_spec_is_chosen
+ a1 = util_spec "a", "1", nil, "lib/ib.rb"
+ a2 = util_spec "a", "2", nil, "lib/foo.rb"
+ b1 = util_spec "b", "1", nil, "lib/ib.rb"
+
+ install_specs a1, a2, b1
+
+ a2.activate
+
+ assert_equal %w[a-2], loaded_spec_names
+ assert_empty unresolved_names
+
+ assert_require "ib"
+ assert_equal %w[a-2 b-1], loaded_spec_names
+ end
+
def test_default_gem_require_activates_just_once
default_gem_spec = new_default_spec("default", "2.0.0.0",
nil, "default/gem.rb")
@@ -460,6 +476,7 @@ class TestGemRequire < Gem::TestCase
def test_realworld_default_gem
omit "this test can't work under ruby-core setup" if ruby_repo?
+ omit "JRuby on Windows does not register json as a default gem the same way" if Gem.win_platform? && Gem.java_platform?
cmd = <<-RUBY
$stderr = $stdout
@@ -770,6 +787,8 @@ class TestGemRequire < Gem::TestCase
end
def test_require_does_not_crash_when_utilizing_bundler_version_finder
+ omit "JRuby on Windows hits a different require path" if Gem.win_platform? && Gem.java_platform?
+
a1 = util_spec "a", "1.1", { "bundler" => ">= 0" }
a2 = util_spec "a", "1.2", { "bundler" => ">= 0" }
b1 = util_spec "bundler", "2.3.7"
diff --git a/test/rubygems/test_rubygems.rb b/test/rubygems/test_rubygems.rb
index ec195b65cd..6566b5981e 100644
--- a/test/rubygems/test_rubygems.rb
+++ b/test/rubygems/test_rubygems.rb
@@ -10,6 +10,7 @@ class GemTest < Gem::TestCase
def test_operating_system_other_exceptions
pend "does not apply to truffleruby" if RUBY_ENGINE == "truffleruby"
+ omit "JRuby on Windows loads a different operating_system defaults file" if Gem.win_platform? && Gem.java_platform?
path = util_install_operating_system_rb <<-RUBY
intentionally_not_implemented_method
diff --git a/test/rubygems/test_webauthn_listener.rb b/test/rubygems/test_webauthn_listener.rb
index 08edabceb2..ded4128928 100644
--- a/test/rubygems/test_webauthn_listener.rb
+++ b/test/rubygems/test_webauthn_listener.rb
@@ -17,7 +17,7 @@ class WebauthnListenerTest < Gem::TestCase
super
end
- def test_listener_thread_retreives_otp_code
+ def test_listener_thread_retrieves_otp_code
thread = Gem::GemcutterUtilities::WebauthnListener.listener_thread(Gem.host, @server)
Gem::MockBrowser.get Gem::URI("http://localhost:#{@port}?code=xyz")
diff --git a/test/set/fixtures/fake_sorted_set_gem/sorted_set.rb b/test/set/fixtures/fake_sorted_set_gem/sorted_set.rb
deleted file mode 100644
index f45a766303..0000000000
--- a/test/set/fixtures/fake_sorted_set_gem/sorted_set.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-Object.instance_exec do
- # Remove the constant to cancel autoload that would be fired by
- # `class SortedSet` and cause circular require.
- remove_const :SortedSet if const_defined?(:SortedSet)
-end
-
-class SortedSet < Set
- # ...
-end
diff --git a/test/set/test_set.rb b/test/set/test_set.rb
deleted file mode 100644
index 565946096e..0000000000
--- a/test/set/test_set.rb
+++ /dev/null
@@ -1,897 +0,0 @@
-# frozen_string_literal: false
-require 'test/unit'
-require 'set'
-
-class TC_Set < Test::Unit::TestCase
- class Set2 < Set
- end
-
- def test_aref
- assert_nothing_raised {
- Set[]
- Set[nil]
- Set[1,2,3]
- }
-
- assert_equal(0, Set[].size)
- assert_equal(1, Set[nil].size)
- assert_equal(1, Set[[]].size)
- assert_equal(1, Set[[nil]].size)
-
- set = Set[2,4,6,4]
- assert_equal(Set.new([2,4,6]), set)
- end
-
- def test_s_new
- assert_nothing_raised {
- Set.new()
- Set.new(nil)
- Set.new([])
- Set.new([1,2])
- Set.new('a'..'c')
- }
- assert_raise(ArgumentError) {
- Set.new(false)
- }
- assert_raise(ArgumentError) {
- Set.new(1)
- }
- assert_raise(ArgumentError) {
- Set.new(1,2)
- }
-
- assert_equal(0, Set.new().size)
- assert_equal(0, Set.new(nil).size)
- assert_equal(0, Set.new([]).size)
- assert_equal(1, Set.new([nil]).size)
-
- ary = [2,4,6,4]
- set = Set.new(ary)
- ary.clear
- assert_equal(false, set.empty?)
- assert_equal(3, set.size)
-
- ary = [1,2,3]
-
- s = Set.new(ary) { |o| o * 2 }
- assert_equal([2,4,6], s.sort)
- end
-
- def test_clone
- set1 = Set.new
- set2 = set1.clone
- set1 << 'abc'
- assert_equal(Set.new, set2)
- end
-
- def test_dup
- set1 = Set[1,2]
- set2 = set1.dup
-
- assert_not_same(set1, set2)
-
- assert_equal(set1, set2)
-
- set1.add(3)
-
- assert_not_equal(set1, set2)
- end
-
- def test_size
- assert_equal(0, Set[].size)
- assert_equal(2, Set[1,2].size)
- assert_equal(2, Set[1,2,1].size)
- end
-
- def test_empty?
- assert_equal(true, Set[].empty?)
- assert_equal(false, Set[1, 2].empty?)
- end
-
- def test_clear
- set = Set[1,2]
- ret = set.clear
-
- assert_same(set, ret)
- assert_equal(true, set.empty?)
- end
-
- def test_replace
- set = Set[1,2]
- ret = set.replace('a'..'c')
-
- assert_same(set, ret)
- assert_equal(Set['a','b','c'], set)
-
- set = Set[1,2]
- assert_raise(ArgumentError) {
- set.replace(3)
- }
- assert_equal(Set[1,2], set)
- end
-
- def test_to_a
- set = Set[1,2,3,2]
- ary = set.to_a
-
- assert_equal([1,2,3], ary.sort)
- end
-
- def test_flatten
- # test1
- set1 = Set[
- 1,
- Set[
- 5,
- Set[7,
- Set[0]
- ],
- Set[6,2],
- 1
- ],
- 3,
- Set[3,4]
- ]
-
- set2 = set1.flatten
- set3 = Set.new(0..7)
-
- assert_not_same(set2, set1)
- assert_equal(set3, set2)
-
- # test2; destructive
- orig_set1 = set1
- set1.flatten!
-
- assert_same(orig_set1, set1)
- assert_equal(set3, set1)
-
- # test3; multiple occurrences of a set in an set
- set1 = Set[1, 2]
- set2 = Set[set1, Set[set1, 4], 3]
-
- assert_nothing_raised {
- set2.flatten!
- }
-
- assert_equal(Set.new(1..4), set2)
-
- # test4; recursion
- set2 = Set[]
- set1 = Set[1, set2]
- set2.add(set1)
-
- assert_raise(ArgumentError) {
- set1.flatten!
- }
-
- # test5; miscellaneous
- empty = Set[]
- set = Set[Set[empty, "a"],Set[empty, "b"]]
-
- assert_nothing_raised {
- set.flatten
- }
-
- set1 = empty.merge(Set["no_more", set])
-
- assert_nil(Set.new(0..31).flatten!)
-
- x = Set[Set[],Set[1,2]].flatten!
- y = Set[1,2]
-
- assert_equal(x, y)
- end
-
- def test_include?
- set = Set[1,2,3]
-
- assert_equal(true, set.include?(1))
- assert_equal(true, set.include?(2))
- assert_equal(true, set.include?(3))
- assert_equal(false, set.include?(0))
- assert_equal(false, set.include?(nil))
-
- set = Set["1",nil,"2",nil,"0","1",false]
- assert_equal(true, set.include?(nil))
- assert_equal(true, set.include?(false))
- assert_equal(true, set.include?("1"))
- assert_equal(false, set.include?(0))
- assert_equal(false, set.include?(true))
- end
-
- def test_eqq
- set = Set[1,2,3]
-
- assert_equal(true, set === 1)
- assert_equal(true, set === 2)
- assert_equal(true, set === 3)
- assert_equal(false, set === 0)
- assert_equal(false, set === nil)
-
- set = Set["1",nil,"2",nil,"0","1",false]
- assert_equal(true, set === nil)
- assert_equal(true, set === false)
- assert_equal(true, set === "1")
- assert_equal(false, set === 0)
- assert_equal(false, set === true)
- end
-
- def test_superset?
- set = Set[1,2,3]
-
- assert_raise(ArgumentError) {
- set.superset?()
- }
-
- assert_raise(ArgumentError) {
- set.superset?(2)
- }
-
- assert_raise(ArgumentError) {
- set.superset?([2])
- }
-
- [Set, Set2].each { |klass|
- assert_equal(true, set.superset?(klass[]), klass.name)
- assert_equal(true, set.superset?(klass[1,2]), klass.name)
- assert_equal(true, set.superset?(klass[1,2,3]), klass.name)
- assert_equal(false, set.superset?(klass[1,2,3,4]), klass.name)
- assert_equal(false, set.superset?(klass[1,4]), klass.name)
-
- assert_equal(true, set >= klass[1,2,3], klass.name)
- assert_equal(true, set >= klass[1,2], klass.name)
-
- assert_equal(true, Set[].superset?(klass[]), klass.name)
- }
- end
-
- def test_proper_superset?
- set = Set[1,2,3]
-
- assert_raise(ArgumentError) {
- set.proper_superset?()
- }
-
- assert_raise(ArgumentError) {
- set.proper_superset?(2)
- }
-
- assert_raise(ArgumentError) {
- set.proper_superset?([2])
- }
-
- [Set, Set2].each { |klass|
- assert_equal(true, set.proper_superset?(klass[]), klass.name)
- assert_equal(true, set.proper_superset?(klass[1,2]), klass.name)
- assert_equal(false, set.proper_superset?(klass[1,2,3]), klass.name)
- assert_equal(false, set.proper_superset?(klass[1,2,3,4]), klass.name)
- assert_equal(false, set.proper_superset?(klass[1,4]), klass.name)
-
- assert_equal(false, set > klass[1,2,3], klass.name)
- assert_equal(true, set > klass[1,2], klass.name)
-
- assert_equal(false, Set[].proper_superset?(klass[]), klass.name)
- }
- end
-
- def test_subset?
- set = Set[1,2,3]
-
- assert_raise(ArgumentError) {
- set.subset?()
- }
-
- assert_raise(ArgumentError) {
- set.subset?(2)
- }
-
- assert_raise(ArgumentError) {
- set.subset?([2])
- }
-
- [Set, Set2].each { |klass|
- assert_equal(true, set.subset?(klass[1,2,3,4]), klass.name)
- assert_equal(true, set.subset?(klass[1,2,3]), klass.name)
- assert_equal(false, set.subset?(klass[1,2]), klass.name)
- assert_equal(false, set.subset?(klass[]), klass.name)
-
- assert_equal(true, set <= klass[1,2,3], klass.name)
- assert_equal(true, set <= klass[1,2,3,4], klass.name)
-
- assert_equal(true, Set[].subset?(klass[1]), klass.name)
- assert_equal(true, Set[].subset?(klass[]), klass.name)
- }
- end
-
- def test_proper_subset?
- set = Set[1,2,3]
-
- assert_raise(ArgumentError) {
- set.proper_subset?()
- }
-
- assert_raise(ArgumentError) {
- set.proper_subset?(2)
- }
-
- assert_raise(ArgumentError) {
- set.proper_subset?([2])
- }
-
- [Set, Set2].each { |klass|
- assert_equal(true, set.proper_subset?(klass[1,2,3,4]), klass.name)
- assert_equal(false, set.proper_subset?(klass[1,2,3]), klass.name)
- assert_equal(false, set.proper_subset?(klass[1,2]), klass.name)
- assert_equal(false, set.proper_subset?(klass[]), klass.name)
-
- assert_equal(false, set < klass[1,2,3], klass.name)
- assert_equal(true, set < klass[1,2,3,4], klass.name)
-
- assert_equal(false, Set[].proper_subset?(klass[]), klass.name)
- }
- end
-
- def test_spacecraft_operator
- set = Set[1,2,3]
-
- assert_nil(set <=> 2)
-
- assert_nil(set <=> set.to_a)
-
- [Set, Set2].each { |klass|
- assert_equal(-1, set <=> klass[1,2,3,4], klass.name)
- assert_equal( 0, set <=> klass[3,2,1] , klass.name)
- assert_equal(nil, set <=> klass[1,2,4] , klass.name)
- assert_equal(+1, set <=> klass[2,3] , klass.name)
- assert_equal(+1, set <=> klass[] , klass.name)
-
- assert_equal(0, Set[] <=> klass[], klass.name)
- }
- end
-
- def assert_intersect(expected, set, other)
- case expected
- when true
- assert_send([set, :intersect?, other])
- assert_send([set, :intersect?, other.to_a])
- assert_send([other, :intersect?, set])
- assert_not_send([set, :disjoint?, other])
- assert_not_send([set, :disjoint?, other.to_a])
- assert_not_send([other, :disjoint?, set])
- when false
- assert_not_send([set, :intersect?, other])
- assert_not_send([set, :intersect?, other.to_a])
- assert_not_send([other, :intersect?, set])
- assert_send([set, :disjoint?, other])
- assert_send([set, :disjoint?, other.to_a])
- assert_send([other, :disjoint?, set])
- when Class
- assert_raise(expected) {
- set.intersect?(other)
- }
- assert_raise(expected) {
- set.disjoint?(other)
- }
- else
- raise ArgumentError, "%s: unsupported expected value: %s" % [__method__, expected.inspect]
- end
- end
-
- def test_intersect?
- set = Set[3,4,5]
-
- assert_intersect(ArgumentError, set, 3)
- assert_intersect(true, set, Set[2,4,6])
-
- assert_intersect(true, set, set)
- assert_intersect(true, set, Set[2,4])
- assert_intersect(true, set, Set[5,6,7])
- assert_intersect(true, set, Set[1,2,6,8,4])
-
- assert_intersect(false, set, Set[])
- assert_intersect(false, set, Set[0,2])
- assert_intersect(false, set, Set[0,2,6])
- assert_intersect(false, set, Set[0,2,6,8,10])
-
- # Make sure set hasn't changed
- assert_equal(Set[3,4,5], set)
- end
-
- def test_each
- ary = [1,3,5,7,10,20]
- set = Set.new(ary)
-
- ret = set.each { |o| }
- assert_same(set, ret)
-
- e = set.each
- assert_instance_of(Enumerator, e)
-
- assert_nothing_raised {
- set.each { |o|
- ary.delete(o) or raise "unexpected element: #{o}"
- }
-
- ary.empty? or raise "forgotten elements: #{ary.join(', ')}"
- }
-
- assert_equal(6, e.size)
- set << 42
- assert_equal(7, e.size)
- end
-
- def test_add
- set = Set[1,2,3]
-
- ret = set.add(2)
- assert_same(set, ret)
- assert_equal(Set[1,2,3], set)
-
- ret = set.add?(2)
- assert_nil(ret)
- assert_equal(Set[1,2,3], set)
-
- ret = set.add(4)
- assert_same(set, ret)
- assert_equal(Set[1,2,3,4], set)
-
- ret = set.add?(5)
- assert_same(set, ret)
- assert_equal(Set[1,2,3,4,5], set)
- end
-
- def test_delete
- set = Set[1,2,3]
-
- ret = set.delete(4)
- assert_same(set, ret)
- assert_equal(Set[1,2,3], set)
-
- ret = set.delete?(4)
- assert_nil(ret)
- assert_equal(Set[1,2,3], set)
-
- ret = set.delete(2)
- assert_equal(set, ret)
- assert_equal(Set[1,3], set)
-
- ret = set.delete?(1)
- assert_equal(set, ret)
- assert_equal(Set[3], set)
- end
-
- def test_delete_if
- set = Set.new(1..10)
- ret = set.delete_if { |i| i > 10 }
- assert_same(set, ret)
- assert_equal(Set.new(1..10), set)
-
- set = Set.new(1..10)
- ret = set.delete_if { |i| i % 3 == 0 }
- assert_same(set, ret)
- assert_equal(Set[1,2,4,5,7,8,10], set)
-
- set = Set.new(1..10)
- enum = set.delete_if
- assert_equal(set.size, enum.size)
- assert_same(set, enum.each { |i| i % 3 == 0 })
- assert_equal(Set[1,2,4,5,7,8,10], set)
- end
-
- def test_keep_if
- set = Set.new(1..10)
- ret = set.keep_if { |i| i <= 10 }
- assert_same(set, ret)
- assert_equal(Set.new(1..10), set)
-
- set = Set.new(1..10)
- ret = set.keep_if { |i| i % 3 != 0 }
- assert_same(set, ret)
- assert_equal(Set[1,2,4,5,7,8,10], set)
-
- set = Set.new(1..10)
- enum = set.keep_if
- assert_equal(set.size, enum.size)
- assert_same(set, enum.each { |i| i % 3 != 0 })
- assert_equal(Set[1,2,4,5,7,8,10], set)
- end
-
- def test_collect!
- set = Set[1,2,3,'a','b','c',-1..1,2..4]
-
- ret = set.collect! { |i|
- case i
- when Numeric
- i * 2
- when String
- i.upcase
- else
- nil
- end
- }
-
- assert_same(set, ret)
- assert_equal(Set[2,4,6,'A','B','C',nil], set)
-
- set = Set[1,2,3,'a','b','c',-1..1,2..4]
- enum = set.collect!
-
- assert_equal(set.size, enum.size)
- assert_same(set, enum.each { |i|
- case i
- when Numeric
- i * 2
- when String
- i.upcase
- else
- nil
- end
- })
- assert_equal(Set[2,4,6,'A','B','C',nil], set)
- end
-
- def test_reject!
- set = Set.new(1..10)
-
- ret = set.reject! { |i| i > 10 }
- assert_nil(ret)
- assert_equal(Set.new(1..10), set)
-
- ret = set.reject! { |i| i % 3 == 0 }
- assert_same(set, ret)
- assert_equal(Set[1,2,4,5,7,8,10], set)
-
- set = Set.new(1..10)
- enum = set.reject!
- assert_equal(set.size, enum.size)
- assert_same(set, enum.each { |i| i % 3 == 0 })
- assert_equal(Set[1,2,4,5,7,8,10], set)
- end
-
- def test_select!
- set = Set.new(1..10)
- ret = set.select! { |i| i <= 10 }
- assert_equal(nil, ret)
- assert_equal(Set.new(1..10), set)
-
- set = Set.new(1..10)
- ret = set.select! { |i| i % 3 != 0 }
- assert_same(set, ret)
- assert_equal(Set[1,2,4,5,7,8,10], set)
-
- set = Set.new(1..10)
- enum = set.select!
- assert_equal(set.size, enum.size)
- assert_equal(nil, enum.each { |i| i <= 10 })
- assert_equal(Set.new(1..10), set)
- end
-
- def test_filter!
- set = Set.new(1..10)
- ret = set.filter! { |i| i <= 10 }
- assert_equal(nil, ret)
- assert_equal(Set.new(1..10), set)
-
- set = Set.new(1..10)
- ret = set.filter! { |i| i % 3 != 0 }
- assert_same(set, ret)
- assert_equal(Set[1,2,4,5,7,8,10], set)
-
- set = Set.new(1..10)
- enum = set.filter!
- assert_equal(set.size, enum.size)
- assert_equal(nil, enum.each { |i| i <= 10 })
- assert_equal(Set.new(1..10), set)
- end
-
- def test_merge
- set = Set[1,2,3]
- ret = set.merge([2,4,6])
- assert_same(set, ret)
- assert_equal(Set[1,2,3,4,6], set)
-
- set = Set[1,2,3]
- ret = set.merge()
- assert_same(set, ret)
- assert_equal(Set[1,2,3], set)
-
- set = Set[1,2,3]
- ret = set.merge([2,4,6], Set[4,5,6])
- assert_same(set, ret)
- assert_equal(Set[1,2,3,4,5,6], set)
-
- assert_raise(ArgumentError) {
- Set[].merge(a: 1)
- }
- end
-
- def test_subtract
- set = Set[1,2,3]
-
- ret = set.subtract([2,4,6])
- assert_same(set, ret)
- assert_equal(Set[1,3], set)
- end
-
- def test_plus
- set = Set[1,2,3]
-
- ret = set + [2,4,6]
- assert_not_same(set, ret)
- assert_equal(Set[1,2,3,4,6], ret)
- end
-
- def test_minus
- set = Set[1,2,3]
-
- ret = set - [2,4,6]
- assert_not_same(set, ret)
- assert_equal(Set[1,3], ret)
- end
-
- def test_and
- set = Set[1,2,3,4]
-
- ret = set & [2,4,6]
- assert_not_same(set, ret)
- assert_equal(Set[2,4], ret)
- end
-
- def test_xor
- set = Set[1,2,3,4]
- ret = set ^ [2,4,5,5]
- assert_not_same(set, ret)
- assert_equal(Set[1,3,5], ret)
-
- set2 = Set2[1,2,3,4]
- ret2 = set2 ^ [2,4,5,5]
- assert_instance_of(Set2, ret2)
- assert_equal(Set2[1,3,5], ret2)
- end
-
- def test_eq
- set1 = Set[2,3,1]
- set2 = Set[1,2,3]
-
- assert_equal(set1, set1)
- assert_equal(set1, set2)
- assert_not_equal(Set[1], [1])
-
- set1 = Class.new(Set)["a", "b"]
- set1.add(set1).reset # Make recursive
- set2 = Set["a", "b", Set["a", "b", set1]]
-
- assert_equal(set1, set2)
-
- assert_not_equal(Set[Exception.new,nil], Set[Exception.new,Exception.new], "[ruby-dev:26127]")
- end
-
- def test_classify
- set = Set.new(1..10)
- ret = set.classify { |i| i % 3 }
-
- assert_equal(3, ret.size)
- assert_instance_of(Hash, ret)
- ret.each_value { |value| assert_instance_of(Set, value) }
- assert_equal(Set[3,6,9], ret[0])
- assert_equal(Set[1,4,7,10], ret[1])
- assert_equal(Set[2,5,8], ret[2])
-
- set = Set.new(1..10)
- enum = set.classify
-
- assert_equal(set.size, enum.size)
- ret = enum.each { |i| i % 3 }
- assert_equal(3, ret.size)
- assert_instance_of(Hash, ret)
- ret.each_value { |value| assert_instance_of(Set, value) }
- assert_equal(Set[3,6,9], ret[0])
- assert_equal(Set[1,4,7,10], ret[1])
- assert_equal(Set[2,5,8], ret[2])
- end
-
- def test_divide
- set = Set.new(1..10)
- ret = set.divide { |i| i % 3 }
-
- assert_equal(3, ret.size)
- n = 0
- ret.each { |s| n += s.size }
- assert_equal(set.size, n)
- assert_equal(set, ret.flatten)
-
- set = Set[7,10,5,11,1,3,4,9,0]
- ret = set.divide { |a,b| (a - b).abs == 1 }
-
- assert_equal(4, ret.size)
- n = 0
- ret.each { |s| n += s.size }
- assert_equal(set.size, n)
- assert_equal(set, ret.flatten)
- ret.each { |s|
- if s.include?(0)
- assert_equal(Set[0,1], s)
- elsif s.include?(3)
- assert_equal(Set[3,4,5], s)
- elsif s.include?(7)
- assert_equal(Set[7], s)
- elsif s.include?(9)
- assert_equal(Set[9,10,11], s)
- else
- raise "unexpected group: #{s.inspect}"
- end
- }
-
- set = Set.new(1..10)
- enum = set.divide
- ret = enum.each { |i| i % 3 }
-
- assert_equal(set.size, enum.size)
- assert_equal(3, ret.size)
- n = 0
- ret.each { |s| n += s.size }
- assert_equal(set.size, n)
- assert_equal(set, ret.flatten)
- end
-
- def test_freeze
- orig = set = Set[1,2,3]
- assert_equal false, set.frozen?
- set << 4
- assert_same orig, set.freeze
- assert_equal true, set.frozen?
- assert_raise(FrozenError) {
- set << 5
- }
- assert_equal 4, set.size
- end
-
- def test_freeze_dup
- set1 = Set[1,2,3]
- set1.freeze
- set2 = set1.dup
-
- assert_not_predicate set2, :frozen?
- assert_nothing_raised {
- set2.add 4
- }
- end
-
- def test_freeze_clone
- set1 = Set[1,2,3]
- set1.freeze
- set2 = set1.clone
-
- assert_predicate set2, :frozen?
- assert_raise(FrozenError) {
- set2.add 5
- }
- end
-
- def test_freeze_clone_false
- set1 = Set[1,2,3]
- set1.freeze
- set2 = set1.clone(freeze: false)
-
- assert_not_predicate set2, :frozen?
- set2.add 5
- assert_equal Set[1,2,3,5], set2
- assert_equal Set[1,2,3], set1
- end if Kernel.instance_method(:initialize_clone).arity != 1
-
- def test_join
- assert_equal('123', Set[1, 2, 3].join)
- assert_equal('1 & 2 & 3', Set[1, 2, 3].join(' & '))
- end
-
- def test_inspect
- set1 = Set[1, 2]
- assert_equal('#<Set: {1, 2}>', set1.inspect)
-
- set2 = Set[Set[0], 1, 2, set1]
- assert_equal('#<Set: {#<Set: {0}>, 1, 2, #<Set: {1, 2}>}>', set2.inspect)
-
- set1.add(set2)
- assert_equal('#<Set: {#<Set: {0}>, 1, 2, #<Set: {1, 2, #<Set: {...}>}>}>', set2.inspect)
- end
-
- def test_to_s
- set1 = Set[1, 2]
- assert_equal('#<Set: {1, 2}>', set1.to_s)
-
- set2 = Set[Set[0], 1, 2, set1]
- assert_equal('#<Set: {#<Set: {0}>, 1, 2, #<Set: {1, 2}>}>', set2.to_s)
-
- set1.add(set2)
- assert_equal('#<Set: {#<Set: {0}>, 1, 2, #<Set: {1, 2, #<Set: {...}>}>}>', set2.to_s)
- end
-
- def test_compare_by_identity
- a1, a2 = "a", "a"
- b1, b2 = "b", "b"
- c = "c"
- array = [a1, b1, c, a2, b2]
-
- iset = Set.new.compare_by_identity
- assert_send([iset, :compare_by_identity?])
- iset.merge(array)
- assert_equal(5, iset.size)
- assert_equal(array.map(&:object_id).sort, iset.map(&:object_id).sort)
-
- set = Set.new
- assert_not_send([set, :compare_by_identity?])
- set.merge(array)
- assert_equal(3, set.size)
- assert_equal(array.uniq.sort, set.sort)
- end
-
- def test_reset
- [Set, Class.new(Set)].each { |klass|
- a = [1, 2]
- b = [1]
- set = klass.new([a, b])
-
- b << 2
- set.reset
-
- assert_equal(klass.new([a]), set, klass.name)
- }
- end
-end
-
-class TC_Enumerable < Test::Unit::TestCase
- def test_to_set
- ary = [2,5,4,3,2,1,3]
-
- set = ary.to_set
- assert_instance_of(Set, set)
- assert_equal([1,2,3,4,5], set.sort)
-
- set = ary.to_set { |o| o * -2 }
- assert_instance_of(Set, set)
- assert_equal([-10,-8,-6,-4,-2], set.sort)
-
- assert_same set, set.to_set
- assert_not_same set, set.to_set { |o| o }
- end
-end
-
-class TC_Set_Builtin < Test::Unit::TestCase
- private def should_omit?
- (RUBY_VERSION.scan(/\d+/).map(&:to_i) <=> [3, 2]) < 0 ||
- !File.exist?(File.expand_path('../prelude.rb', __dir__))
- end
-
- def test_Set
- omit "skipping the test for the builtin Set" if should_omit?
-
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
- begin;
- assert_nothing_raised do
- set = Set.new([1, 2])
- assert_equal('Set', set.class.name)
- end
- end;
-
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
- begin;
- assert_nothing_raised do
- set = Set[1, 2]
- assert_equal('Set', set.class.name)
- end
- end;
- end
-
- def test_to_set
- omit "skipping the test for the builtin Enumerable#to_set" if should_omit?
-
- assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
- begin;
- assert_nothing_raised do
- set = [1, 2].to_set
- assert_equal('Set', set.class.name)
- end
- end;
- end
-end
diff --git a/test/set/test_sorted_set.rb b/test/set/test_sorted_set.rb
deleted file mode 100644
index f7ad7af299..0000000000
--- a/test/set/test_sorted_set.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: false
-require 'test/unit'
-require 'set'
-
-class TC_SortedSet < Test::Unit::TestCase
- def base_dir
- "#{__dir__}/../lib"
- end
-
- def assert_runs(ruby, options: nil)
- options = ['-I', base_dir, *options]
- r = system(RbConfig.ruby, *options, '-e', ruby)
- assert(r)
- end
-
- def test_error
- assert_runs <<~RUBY
- require "set"
-
- r = begin
- puts SortedSet.new
- rescue Exception => e
- e.message
- end
- raise r unless r.match?(/has been extracted/)
- RUBY
- end
-
- def test_ok_with_gem
- assert_runs <<~RUBY, options: ['-I', "#{__dir__}/fixtures/fake_sorted_set_gem"]
- require "set"
-
- var = SortedSet.new.to_s
- RUBY
- end
-
- def test_ok_require
- assert_runs <<~RUBY, options: ['-I', "#{__dir__}/fixtures/fake_sorted_set_gem"]
- require "set"
- require "sorted_set"
-
- var = SortedSet.new.to_s
- RUBY
- end
-end
diff --git a/test/socket/test_addrinfo.rb b/test/socket/test_addrinfo.rb
index c61764d76d..0c9529090e 100644
--- a/test/socket/test_addrinfo.rb
+++ b/test/socket/test_addrinfo.rb
@@ -360,6 +360,12 @@ class TestSocketAddrinfo < Test::Unit::TestCase
assert_raise(Socket::ResolutionError) { Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("::1", 80) }
end
+ def test_ractor_shareable
+ assert_ractor(<<~'RUBY', require: 'socket', timeout: 60)
+ Ractor.make_shareable Addrinfo.new "\x10\x02\x14\xE9\xE0\x00\x00\xFB\x00\x00\x00\x00\x00\x00\x00\x00".b
+ RUBY
+ end
+
def random_port
# IANA suggests dynamic port for 49152 to 65535
# http://www.iana.org/assignments/port-numbers
diff --git a/test/socket/test_nonblock.rb b/test/socket/test_nonblock.rb
index 5a4688bac3..68fefc44b3 100644
--- a/test/socket/test_nonblock.rb
+++ b/test/socket/test_nonblock.rb
@@ -104,7 +104,7 @@ class TestSocketNonblock < Test::Unit::TestCase
assert_raise(IO::WaitReadable) { u1.recvfrom_nonblock(100) }
u2.send("", 0, u1.getsockname)
assert_nothing_raised("cygwin 1.5.19 has a problem to send an empty UDP packet. [ruby-dev:28915]") {
- Timeout.timeout(1) { IO.select [u1] }
+ Timeout.timeout(30) { IO.select [u1] }
}
mesg, inet_addr = u1.recvfrom_nonblock(100)
assert_equal("", mesg)
@@ -126,7 +126,7 @@ class TestSocketNonblock < Test::Unit::TestCase
assert_raise(IO::WaitReadable) { u1.recv_nonblock(100) }
u2.send("", 0, u1.getsockname)
assert_nothing_raised("cygwin 1.5.19 has a problem to send an empty UDP packet. [ruby-dev:28915]") {
- Timeout.timeout(1) { IO.select [u1] }
+ Timeout.timeout(30) { IO.select [u1] }
}
mesg = u1.recv_nonblock(100)
assert_equal("", mesg)
diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb
index b15cf63297..3b5f5b9d74 100644
--- a/test/socket/test_socket.rb
+++ b/test/socket/test_socket.rb
@@ -173,8 +173,11 @@ class TestSocket < Test::Unit::TestCase
def errors_addrinuse
errs = [Errno::EADDRINUSE]
- # MinGW fails with "Errno::EACCES: Permission denied - bind(2) for 0.0.0.0:49721"
- errs << Errno::EACCES if /mingw/ =~ RUBY_PLATFORM
+ # Windows can fail with "Errno::EACCES: Permission denied - bind(2) for 0.0.0.0:49721"
+ # or "Test::Unit::ProxyError: Permission denied - bind(2) for 0.0.0.0:55333"
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ errs += [Errno::EACCES, Test::Unit::ProxyError]
+ end
errs
end
@@ -415,12 +418,16 @@ class TestSocket < Test::Unit::TestCase
ping_p = false
th = Thread.new {
- Socket.udp_server_loop_on(sockets) {|msg, msg_src|
- break if msg == "exit"
- rmsg = Marshal.dump([msg, msg_src.remote_address, msg_src.local_address])
- ping_p = true
- msg_src.reply rmsg
- }
+ begin
+ Socket.udp_server_loop_on(sockets) {|msg, msg_src|
+ break if msg == "exit"
+ rmsg = Marshal.dump([msg, msg_src.remote_address, msg_src.local_address])
+ ping_p = true
+ msg_src.reply rmsg
+ }
+ rescue Errno::ENOBUFS
+ # transient OS error on macOS CI, let client timeout and omit
+ end
}
ifaddrs.each {|ifa|
@@ -478,9 +485,11 @@ class TestSocket < Test::Unit::TestCase
}
end
- def timestamp_retry_rw(s1, s2, t1, type)
+ def timestamp_retry_rw(s1, type)
IO.pipe do |r,w|
+ t1 = Time.now
# UDP may not be reliable, keep sending until recvmsg returns:
+ s2 = Socket.new(:INET, :DGRAM, 0)
th = Thread.new do
n = 0
begin
@@ -493,80 +502,54 @@ class TestSocket < Test::Unit::TestCase
assert_equal([[s1],[],[]], IO.select([s1], nil, nil, timeout))
msg, _, _, stamp = s1.recvmsg
assert_equal("a", msg)
- assert(stamp.cmsg_is?(:SOCKET, type))
+ assert_send([stamp, :cmsg_is?, :SOCKET, type])
w.close # stop th
n = th.value
th = nil
n > 1 and
warn "UDP packet loss for #{type} over loopback, #{n} tries needed"
- t2 = Time.now.strftime("%Y-%m-%d")
- pat = Regexp.union([t1, t2].uniq)
- assert_match(pat, stamp.inspect)
- t = stamp.timestamp
- assert_match(pat, t.strftime("%Y-%m-%d"))
+ t2 = Time.now
+ assert_include(t1..t2, stamp.timestamp)
stamp
ensure
if th and !th.join(10)
th.kill.join(10)
end
+ s2.close
end
end
def test_timestamp
- return if /linux|freebsd|netbsd|openbsd|solaris|darwin/ !~ RUBY_PLATFORM
+ return if /linux|freebsd|netbsd|openbsd|darwin/ !~ RUBY_PLATFORM
return if !defined?(Socket::AncillaryData) || !defined?(Socket::SO_TIMESTAMP)
- t1 = Time.now.strftime("%Y-%m-%d")
- stamp = nil
Addrinfo.udp("127.0.0.1", 0).bind {|s1|
- Addrinfo.udp("127.0.0.1", 0).bind {|s2|
- s1.setsockopt(:SOCKET, :TIMESTAMP, true)
- stamp = timestamp_retry_rw(s1, s2, t1, :TIMESTAMP)
- }
+ s1.setsockopt(:SOCKET, :TIMESTAMP, true)
+ timestamp_retry_rw(s1, :TIMESTAMP)
}
- t = stamp.timestamp
- pat = /\.#{"%06d" % t.usec}/
- assert_match(pat, stamp.inspect)
end
def test_timestampns
return if /linux/ !~ RUBY_PLATFORM || !defined?(Socket::SO_TIMESTAMPNS)
- t1 = Time.now.strftime("%Y-%m-%d")
- stamp = nil
Addrinfo.udp("127.0.0.1", 0).bind {|s1|
- Addrinfo.udp("127.0.0.1", 0).bind {|s2|
- begin
- s1.setsockopt(:SOCKET, :TIMESTAMPNS, true)
- rescue Errno::ENOPROTOOPT
- # SO_TIMESTAMPNS is available since Linux 2.6.22
- return
- end
- stamp = timestamp_retry_rw(s1, s2, t1, :TIMESTAMPNS)
- }
+ begin
+ s1.setsockopt(:SOCKET, :TIMESTAMPNS, true)
+ rescue Errno::ENOPROTOOPT
+ # SO_TIMESTAMPNS is available since Linux 2.6.22
+ return
+ end
+ timestamp_retry_rw(s1, :TIMESTAMPNS)
}
- t = stamp.timestamp
- pat = /\.#{"%09d" % t.nsec}/
- assert_match(pat, stamp.inspect)
end
def test_bintime
return if /freebsd/ !~ RUBY_PLATFORM
- t1 = Time.now.strftime("%Y-%m-%d")
- stamp = nil
- Addrinfo.udp("127.0.0.1", 0).bind {|s1|
- Addrinfo.udp("127.0.0.1", 0).bind {|s2|
- s1.setsockopt(:SOCKET, :BINTIME, true)
- s2.send "a", 0, s1.local_address
- msg, _, _, stamp = s1.recvmsg
- assert_equal("a", msg)
- assert(stamp.cmsg_is?(:SOCKET, :BINTIME))
- }
+ stamp = Addrinfo.udp("127.0.0.1", 0).bind {|s1|
+ s1.setsockopt(:SOCKET, :BINTIME, true)
+ timestamp_retry_rw(s1, :BINTIME)
}
- t2 = Time.now.strftime("%Y-%m-%d")
- pat = Regexp.union([t1, t2].uniq)
- assert_match(pat, stamp.inspect)
t = stamp.timestamp
- assert_match(pat, t.strftime("%Y-%m-%d"))
- assert_equal(stamp.data[-8,8].unpack("Q")[0], t.subsec * 2**64)
+ data = stamp.data
+ assert_equal(data.unpack1("Q", offset: data.bytesize-8), t.subsec * 2**64)
end
def test_closed_read
@@ -906,7 +889,7 @@ class TestSocket < Test::Unit::TestCase
Addrinfo.define_singleton_method(:getaddrinfo) { |*_| sleep }
- assert_raise(Errno::ETIMEDOUT) do
+ assert_raise(IO::TimeoutError) do
Socket.tcp("localhost", port, resolv_timeout: 0.01)
end
ensure
@@ -931,12 +914,38 @@ class TestSocket < Test::Unit::TestCase
server.close
- assert_raise(Errno::ETIMEDOUT) do
+ assert_raise(IO::TimeoutError) do
Socket.tcp("localhost", port, resolv_timeout: 0.01)
end
RUBY
end
+ def test_tcp_socket_open_timeout
+ opts = %w[-rsocket -W1]
+ assert_separately opts, <<~RUBY
+ Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_|
+ if family == Socket::AF_INET6
+ sleep
+ else
+ [Addrinfo.tcp("127.0.0.1", 12345)]
+ end
+ end
+
+ assert_raise(IO::TimeoutError) do
+ Socket.tcp("localhost", 12345, open_timeout: 0.01)
+ end
+ RUBY
+ end
+
+ def test_tcp_socket_open_timeout_with_other_timeouts
+ opts = %w[-rsocket -W1]
+ assert_separately opts, <<~RUBY
+ assert_raise(ArgumentError) do
+ Socket.tcp("localhost", 12345, open_timeout: 0.01, resolv_timout: 0.01)
+ end
+ RUBY
+ end
+
def test_tcp_socket_one_hostname_resolution_succeeded_at_least
opts = %w[-rsocket -W1]
assert_separately opts, <<~RUBY
@@ -982,7 +991,7 @@ class TestSocket < Test::Unit::TestCase
Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_|
case family
when Socket::AF_INET6 then raise SocketError
- when Socket::AF_INET then sleep(0.001); raise SocketError, "Last hostname resolution error"
+ when Socket::AF_INET then sleep(0.01); raise SocketError, "Last hostname resolution error"
end
end
diff --git a/test/socket/test_tcp.rb b/test/socket/test_tcp.rb
index be6d59b31e..d689ab2376 100644
--- a/test/socket/test_tcp.rb
+++ b/test/socket/test_tcp.rb
@@ -73,6 +73,30 @@ class TestSocket_TCPSocket < Test::Unit::TestCase
end
end
+ def test_tcp_initialize_open_timeout
+ return if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
+
+ server = TCPServer.new("127.0.0.1", 0)
+ port = server.connect_address.ip_port
+ server.close
+
+ assert_raise(IO::TimeoutError) do
+ TCPSocket.new(
+ "localhost",
+ port,
+ open_timeout: 0.01,
+ fast_fallback: true,
+ test_mode_settings: { delay: { ipv4: 1000 } }
+ )
+ end
+ end
+
+ def test_initialize_open_timeout_with_other_timeouts
+ assert_raise(ArgumentError) do
+ TCPSocket.new("localhost", 12345, open_timeout: 0.01, resolv_timeout: 0.01)
+ end
+ end
+
def test_initialize_connect_timeout
assert_raise(IO::TimeoutError, Errno::ENETUNREACH, Errno::EACCES) do
TCPSocket.new("192.0.2.1", 80, connect_timeout: 0)
@@ -297,7 +321,7 @@ class TestSocket_TCPSocket < Test::Unit::TestCase
port = server.connect_address.ip_port
server.close
- assert_raise(Errno::ETIMEDOUT) do
+ assert_raise(IO::TimeoutError) do
TCPSocket.new(
"localhost",
port,
diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb
index 3e7d85befc..e239e3935b 100644
--- a/test/socket/test_unix.rb
+++ b/test/socket/test_unix.rb
@@ -146,6 +146,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
end
def test_fd_passing_race_condition
+ omit 'randomly crashes on macOS' if RUBY_PLATFORM =~ /darwin/
r1, w = IO.pipe
s1, s2 = UNIXSocket.pair
s1.nonblock = s2.nonblock = true
@@ -292,14 +293,18 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
File.unlink path if path && File.socket?(path)
end
- def test_open_nul_byte
- tmpfile = Tempfile.new("s")
- path = tmpfile.path
- tmpfile.close(true)
- assert_raise(ArgumentError) {UNIXServer.open(path+"\0")}
- assert_raise(ArgumentError) {UNIXSocket.open(path+"\0")}
- ensure
- File.unlink path if path && File.socket?(path)
+ def test_open_argument
+ assert_raise(TypeError) {UNIXServer.new(nil)}
+ assert_raise(TypeError) {UNIXServer.new(1)}
+ Tempfile.create("s") do |s|
+ path = s.path
+ s.close
+ File.unlink(path)
+ assert_raise(ArgumentError) {UNIXServer.open(path+"\0")}
+ assert_raise(ArgumentError) {UNIXSocket.open(path+"\0")}
+ arg = Struct.new(:to_path).new(path)
+ assert_equal(path, UNIXServer.open(arg) { |server| server.path })
+ end
end
def test_addr
diff --git a/test/stringio/test_ractor.rb b/test/stringio/test_ractor.rb
index 4a2033bc1f..6acf53fb0a 100644
--- a/test/stringio/test_ractor.rb
+++ b/test/stringio/test_ractor.rb
@@ -8,6 +8,10 @@ class TestStringIOInRactor < Test::Unit::TestCase
def test_ractor
assert_in_out_err([], <<-"end;", ["true"], [])
+ class Ractor
+ alias value take unless method_defined? :value # compat with Ruby 3.4 and olders
+ end
+
require "stringio"
$VERBOSE = nil
r = Ractor.new do
@@ -17,7 +21,7 @@ class TestStringIOInRactor < Test::Unit::TestCase
io.puts "def"
"\0\0\0\0def\n" == io.string
end
- puts r.take
+ puts r.value
end;
end
end
diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb
index 570b3d7ad6..0f61245a8a 100644
--- a/test/stringio/test_stringio.rb
+++ b/test/stringio/test_stringio.rb
@@ -70,6 +70,31 @@ class TestStringIO < Test::Unit::TestCase
assert_nil io.getc
end
+ def test_eof_null
+ io = StringIO.new(nil)
+ assert_predicate io, :eof?
+ end
+
+ def test_pread_null
+ io = StringIO.new(nil)
+ assert_raise(EOFError) { io.pread(1, 0) }
+ end
+
+ def test_read_null
+ io = StringIO.new(nil)
+ assert_equal "", io.read(0)
+ end
+
+ def test_seek_null
+ io = StringIO.new(nil)
+ assert_equal(0, io.seek(0, IO::SEEK_SET))
+ assert_equal(0, io.pos)
+ assert_equal(0, io.seek(0, IO::SEEK_CUR))
+ assert_equal(0, io.pos)
+ assert_equal(0, io.seek(0, IO::SEEK_END)) # This should not segfault
+ assert_equal(0, io.pos)
+ end
+
def test_truncate
io = StringIO.new("")
io.puts "abc"
@@ -334,6 +359,9 @@ class TestStringIO < Test::Unit::TestCase
def test_isatty
assert_equal(false, StringIO.new("").isatty)
+ assert_equal(false, StringIO.new("").tty?)
+ assert_nothing_raised { StringIO.new("").freeze.isatty}
+ assert_nothing_raised { StringIO.new("").freeze.tty?}
end
def test_fsync
@@ -343,6 +371,7 @@ class TestStringIO < Test::Unit::TestCase
def test_sync
assert_equal(true, StringIO.new("").sync)
assert_equal(false, StringIO.new("").sync = false)
+ assert_nothing_raised { StringIO.new("").freeze.sync}
end
def test_set_fcntl
@@ -395,8 +424,8 @@ class TestStringIO < Test::Unit::TestCase
assert_equal(false, f.closed?)
f.close
assert_equal(true, f.closed?)
- ensure
- f.close unless f.closed?
+ f.freeze
+ assert_nothing_raised { f.closed? }
end
def test_closed_read
@@ -406,8 +435,8 @@ class TestStringIO < Test::Unit::TestCase
assert_equal(false, f.closed_read?)
f.close_read
assert_equal(true, f.closed_read?)
- ensure
- f.close unless f.closed?
+ f.freeze
+ assert_nothing_raised { f.closed_read? }
end
def test_closed_write
@@ -417,8 +446,8 @@ class TestStringIO < Test::Unit::TestCase
assert_equal(false, f.closed_write?)
f.close_write
assert_equal(true, f.closed_write?)
- ensure
- f.close unless f.closed?
+ f.freeze
+ assert_nothing_raised { f.closed_write? }
end
def test_dup
@@ -444,8 +473,8 @@ class TestStringIO < Test::Unit::TestCase
f.lineno = 1000
assert_equal([1000, "baz\n"], [f.lineno, f.gets])
assert_equal([1001, nil], [f.lineno, f.gets])
- ensure
- f.close unless f.closed?
+ f.freeze
+ assert_nothing_raised { f.lineno }
end
def test_pos
@@ -458,8 +487,8 @@ class TestStringIO < Test::Unit::TestCase
assert_equal([4, "bar\n"], [f.pos, f.gets])
assert_equal([8, "baz\n"], [f.pos, f.gets])
assert_equal([12, nil], [f.pos, f.gets])
- ensure
- f.close unless f.closed?
+ f.freeze
+ assert_nothing_raised { f.pos }
end
def test_reopen
@@ -483,13 +512,10 @@ class TestStringIO < Test::Unit::TestCase
assert_raise(Errno::EINVAL) { f.seek(1, 3) }
f.close
assert_raise(IOError) { f.seek(0) }
- ensure
- f.close unless f.closed?
- end
-
- def test_seek_frozen_string
f = StringIO.new(-"1234")
assert_equal(0, f.seek(1))
+ ensure
+ f.close unless f.closed?
end
def test_each_byte
@@ -739,6 +765,8 @@ class TestStringIO < Test::Unit::TestCase
s = ""
f.read(nil, s)
assert_equal(Encoding::ASCII_8BIT, s.encoding, bug20418)
+
+ assert_raise(ArgumentError) {f.read(1, f.string)}
end
def test_readpartial
@@ -804,19 +832,28 @@ class TestStringIO < Test::Unit::TestCase
assert_raise(EOFError) { f.pread(1, 5) }
assert_raise(ArgumentError) { f.pread(-1, 0) }
+ assert_raise(ArgumentError) { f.pread(0, 0, f.string) }
assert_raise(Errno::EINVAL) { f.pread(3, -1) }
+ assert_raise(Errno::EINVAL) { f.pread(0, -1) }
+ assert_raise(IOError) { StringIO.new(nil, "w").pread(3, 0) }
+ assert_raise(TypeError) { f.pread(3, 0, []) }
assert_equal "".b, StringIO.new("").pread(0, 0)
- assert_equal "".b, StringIO.new("").pread(0, -10)
buf = "stale".b
assert_equal "stale".b, StringIO.new("").pread(0, 0, buf)
assert_equal "stale".b, buf
+
+ assert_nothing_raised { StringIO.new("pread").freeze.pread(3, 0)}
end
def test_size
f = StringIO.new("1234")
assert_equal(4, f.size)
+ assert_equal(4, f.length)
+ f.freeze
+ assert_nothing_raised { f.size }
+ assert_nothing_raised { f.length }
end
# This test is should in ruby/test_method.rb
@@ -971,7 +1008,7 @@ class TestStringIO < Test::Unit::TestCase
intptr_max = RbConfig::LIMITS["INTPTR_MAX"]
return if intptr_max > StringIO::MAX_LENGTH
limit = intptr_max - 0x10
- assert_separately(%w[-rstringio], "#{<<-"begin;"}\n#{<<-"end;"}")
+ assert_separately(%w[-W0 -rstringio], "#{<<-"begin;"}\n#{<<-"end;"}")
begin;
limit = #{limit}
ary = []
@@ -1039,6 +1076,20 @@ class TestStringIO < Test::Unit::TestCase
assert_predicate(s.string, :ascii_only?)
end
+ def test_coderange_after_read_into_buffer
+ s = StringIO.new("01234567890".b)
+
+ buf = "¿Cómo estás? Ça va bien?"
+ assert_not_predicate(buf, :ascii_only?)
+
+ assert_predicate(s.string, :ascii_only?)
+
+ s.read(10, buf)
+
+ assert_predicate(buf, :ascii_only?)
+ assert_equal '0123456789', buf
+ end
+
require "objspace"
if ObjectSpace.respond_to?(:dump) && ObjectSpace.dump(eval(%{"test"})).include?('"chilled":true') # Ruby 3.4+ chilled strings
def test_chilled_string
@@ -1057,6 +1108,72 @@ class TestStringIO < Test::Unit::TestCase
assert_equal("test", io.string)
assert_same(chilled_string, io.string)
end
+
+ def test_chilled_string_set_enocoding
+ chilled_string = eval(%{""})
+ io = StringIO.new(chilled_string)
+ assert_warning("") { io.set_encoding(Encoding::BINARY) }
+ assert_same(chilled_string, io.string)
+ end
+ end
+
+ def test_eof
+ f = StringIO.new
+ assert_equal(true, f.eof)
+ assert_equal(true, f.eof?)
+ f.ungetc("1234")
+ assert_equal(false, f.eof)
+ assert_equal(false, f.eof?)
+ f.freeze
+ assert_nothing_raised { f.eof }
+ assert_nothing_raised { f.eof? }
+ end
+
+ def test_pid
+ f = StringIO.new
+ assert_equal(nil, f.pid)
+ f.freeze
+ assert_nothing_raised { f.pid }
+ end
+
+ def test_fileno
+ f = StringIO.new
+ assert_equal(nil, f.fileno)
+ f.freeze
+ assert_nothing_raised { f.fileno }
+ end
+
+ def test_external_encoding
+ f = StringIO.new
+ assert_equal(Encoding.find("external"), f.external_encoding)
+ f = StringIO.new("1234".encode("UTF-16BE"))
+ assert_equal(Encoding::UTF_16BE, f.external_encoding)
+ f.freeze
+ assert_nothing_raised { f.external_encoding }
+ end
+
+ def test_string
+ f = StringIO.new
+ assert_equal("", f.string)
+ f = StringIO.new("1234")
+ assert_equal("1234", f.string)
+ f.freeze
+ assert_nothing_raised { f.string }
+ end
+
+ def test_initialize_copy
+ f = StringIO.new("1234")
+ f.read(1)
+ f2 = f.dup
+ assert_equal(1, f2.pos)
+ f.read(1)
+ assert_equal(2, f2.pos)
+ f.ungetc("56")
+ assert_equal(0, f2.pos)
+ assert_equal("5634", f2.string)
+ f.freeze
+ f2 = f.dup
+ assert_not_predicate(f2, :frozen?)
end
private
diff --git a/test/strscan/test_ractor.rb b/test/strscan/test_ractor.rb
index 9a279d2929..a13fd8fd13 100644
--- a/test/strscan/test_ractor.rb
+++ b/test/strscan/test_ractor.rb
@@ -8,6 +8,10 @@ class TestStringScannerRactor < Test::Unit::TestCase
def test_ractor
assert_in_out_err([], <<-"end;", ["stra", " ", "strb", " ", "strc"], [])
+ class Ractor
+ alias value take unless method_defined? :value # compat with Ruby 3.4 and olders
+ end
+
require "strscan"
$VERBOSE = nil
r = Ractor.new do
@@ -22,7 +26,7 @@ class TestStringScannerRactor < Test::Unit::TestCase
s.scan(/\\w+/)
]
end
- puts r.take.compact
+ puts r.value.compact
end;
end
end
diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb
index 0a28d92368..96a1badb1f 100644
--- a/test/strscan/test_stringscanner.rb
+++ b/test/strscan/test_stringscanner.rb
@@ -45,19 +45,6 @@ module StringScannerTests
assert_same(str, s.string)
end
- UNINIT_ERROR = ArgumentError
-
- def test_s_allocate
- s = StringScanner.allocate
- assert_equal('#<StringScanner (uninitialized)>', s.inspect.sub(/StringScanner_C/, 'StringScanner'))
- assert_raise(UNINIT_ERROR) { s.eos? }
- assert_raise(UNINIT_ERROR) { s.scan(/a/) }
- s.string = 'test'
- assert_equal('#<StringScanner 0/4 @ "test">', s.inspect.sub(/StringScanner_C/, 'StringScanner'))
- assert_nothing_raised(UNINIT_ERROR) { s.eos? }
- assert_equal(false, s.eos?)
- end
-
def test_s_mustc
assert_nothing_raised(NotImplementedError) {
StringScanner.must_C_version
@@ -107,11 +94,6 @@ module StringScannerTests
assert_equal(true, StringScanner::Version.frozen?)
end
- def test_const_Id
- assert_instance_of(String, StringScanner::Id)
- assert_equal(true, StringScanner::Id.frozen?)
- end
-
def test_inspect
str = 'test string'.dup
s = create_string_scanner(str, false)
@@ -543,6 +525,59 @@ module StringScannerTests
end
end
+ def assert_integer_at(s, specifier, *to_i_args)
+ assert_equal(s[specifier]&.to_i(*to_i_args),
+ s.integer_at(specifier, *to_i_args))
+ end
+
+ def test_integer_at
+ s = create_string_scanner("before 20260514 after")
+ s.skip_until(" ")
+ assert_equal("20260514", s.scan(/(\d{4})(\d{2})(\d{2})/))
+ assert_integer_at(s, 0) # 20260514
+ assert_integer_at(s, 1) # 2026
+ assert_integer_at(s, 2) # 5
+ assert_integer_at(s, 3) # 14
+ assert_integer_at(s, 4) # nil
+ assert_integer_at(s, -1) # 14
+ assert_integer_at(s, -2) # 5
+ assert_integer_at(s, -3) # 2026
+ assert_integer_at(s, -4) # 20260514
+ assert_integer_at(s, -5) # nil
+ end
+
+ def test_integer_at_name_string
+ s = create_string_scanner("before 20260514 after")
+ s.skip_until(" ")
+ assert_equal("20260514", s.scan(/(?<y>\d{4})(?<m>\d{2})(?<d>\d{2})/))
+ assert_integer_at(s, "y")
+ assert_integer_at(s, "m")
+ assert_integer_at(s, "d")
+ end
+
+ def test_integer_at_name_symbol
+ s = create_string_scanner("before 20260514 after")
+ s.skip_until(" ")
+ assert_equal("20260514", s.scan(/(?<y>\d{4})(?<m>\d{2})(?<d>\d{2})/))
+ assert_integer_at(s, :y)
+ assert_integer_at(s, :m)
+ assert_integer_at(s, :d)
+ end
+
+ def test_integer_at_base
+ s = create_string_scanner("before 111 after")
+ s.skip_until(" ")
+ assert_equal("111", s.scan(/\d+/))
+ assert_integer_at(s, 0, 2)
+ end
+
+ def test_integer_at_base_auto
+ s = create_string_scanner("before 0xa_f after")
+ s.skip_until(" ")
+ assert_equal("0xa_f", s.scan(/0x[\h_]+/))
+ assert_integer_at(s, 0, 0) # 0xaf
+ end
+
def test_pre_match
s = create_string_scanner('a b c d e')
s.scan(/\w/)
@@ -875,7 +910,7 @@ module StringScannerTests
assert_equal({}, s.named_captures)
assert_equal("te", s.scan(/../))
assert_equal(nil, s.scan(/\d/))
- assert_raise(ScanError) { s.unscan }
+ assert_raise(StringScanner::Error) { s.unscan }
end
def test_rest
@@ -967,6 +1002,12 @@ module StringScannerTests
assert_equal({}, scan.named_captures)
end
+ def test_named_captures_same_name_union
+ scan = StringScanner.new("123")
+ assert_equal(1, scan.match?(/(?<number>0)|(?<number>1)|(?<number>2)/))
+ assert_equal({"number" => "1"}, scan.named_captures)
+ end
+
def test_scan_integer
s = create_string_scanner('abc')
assert_equal(3, s.match?(/(?<a>abc)/)) # set named_captures
@@ -995,11 +1036,27 @@ module StringScannerTests
assert_equal(0, s.pos)
refute_predicate(s, :matched?)
+ s = create_string_scanner('-')
+ assert_nil(s.scan_integer)
+ assert_equal(0, s.pos)
+ refute_predicate(s, :matched?)
+
+ s = create_string_scanner('+')
+ assert_nil(s.scan_integer)
+ assert_equal(0, s.pos)
+ refute_predicate(s, :matched?)
+
huge_integer = '1' * 2_000
s = create_string_scanner(huge_integer)
assert_equal(huge_integer.to_i, s.scan_integer)
assert_equal(2_000, s.pos)
assert_predicate(s, :matched?)
+
+ s = create_string_scanner('abc1')
+ s.pos = 3
+ assert_equal(1, s.scan_integer)
+ assert_equal(4, s.pos)
+ assert_predicate(s, :matched?)
end
def test_scan_integer_unmatch
diff --git a/test/test_bundled_gems.rb b/test/test_bundled_gems.rb
index 19546dd296..0889584185 100644
--- a/test/test_bundled_gems.rb
+++ b/test/test_bundled_gems.rb
@@ -32,4 +32,42 @@ class TestBundlerGem < Gem::TestCase
assert Gem::BUNDLED_GEMS.warning?(path, specs: {})
assert_nil Gem::BUNDLED_GEMS.warning?(path, specs: {})
end
+
+ def test_no_warning_for_hyphenated_gem
+ # When benchmark-ips gem is in specs, requiring "benchmark/ips" should not warn
+ # about the benchmark gem (Bug #21828)
+ assert_nil Gem::BUNDLED_GEMS.warning?("benchmark/ips", specs: {"benchmark-ips" => true})
+ end
+
+ def test_no_warning_for_subfeatures_of_hyphenated_gem
+ # When benchmark-ips gem is in specs, requiring any "benchmark/*" subfeature
+ # should not warn, since hyphenated gems may provide multiple files
+ # (e.g., benchmark-ips provides benchmark/ips, benchmark/timing, benchmark/compare)
+ assert_nil Gem::BUNDLED_GEMS.warning?("benchmark/timing", specs: {"benchmark-ips" => true})
+ assert_nil Gem::BUNDLED_GEMS.warning?("benchmark/compare", specs: {"benchmark-ips" => true})
+ end
+
+ def test_warning_without_hyphenated_gem
+ # When benchmark-ips is NOT in specs, requiring "benchmark/ips" should warn
+ warning = Gem::BUNDLED_GEMS.warning?("benchmark/ips", specs: {})
+ assert warning
+ assert_match(/benchmark/, warning)
+ end
+
+ def test_no_warning_for_subfeature_found_outside_stdlib
+ # When a subfeature like "benchmark/ips" is found on $LOAD_PATH
+ # from a non-standard-library location (e.g., benchmark-ips gem's lib dir),
+ # don't warn even if the gem is not in specs (Bug #21828)
+ Dir.mktmpdir do |dir|
+ FileUtils.mkdir_p(File.join(dir, "benchmark"))
+ File.write(File.join(dir, "benchmark", "ips.rb"), "")
+ original_load_path = $LOAD_PATH.dup
+ $LOAD_PATH.unshift(dir)
+ begin
+ assert_nil Gem::BUNDLED_GEMS.warning?("benchmark/ips", specs: {})
+ ensure
+ $LOAD_PATH.replace(original_load_path)
+ end
+ end
+ end
end
diff --git a/test/test_delegate.rb b/test/test_delegate.rb
index f7bedf37fb..7aa90cb0c6 100644
--- a/test/test_delegate.rb
+++ b/test/test_delegate.rb
@@ -23,7 +23,7 @@ class TestDelegateClass < Test::Unit::TestCase
def test_systemcallerror_eq
e = SystemCallError.new(0)
- assert((SimpleDelegator.new(e) == e) == (e == SimpleDelegator.new(e)), "[ruby-dev:34808]")
+ assert_equal((SimpleDelegator.new(e) == e), (e == SimpleDelegator.new(e)), "[ruby-dev:34808]")
end
class Myclass < DelegateClass(Array);end
@@ -93,15 +93,21 @@ class TestDelegateClass < Test::Unit::TestCase
end
class Parent
- def parent_public; end
+ def parent_public
+ :public
+ end
protected
- def parent_protected; end
+ def parent_protected
+ :protected
+ end
private
- def parent_private; end
+ def parent_private
+ :private
+ end
end
class Child < DelegateClass(Parent)
@@ -157,6 +163,29 @@ class TestDelegateClass < Test::Unit::TestCase
assert_instance_of UnboundMethod, Child.public_instance_method(:to_s)
end
+ def test_call_visibiltiy
+ obj = Child.new(Parent.new)
+ assert_equal :public, obj.parent_public
+ assert_equal :protected, obj.__send__(:parent_protected)
+ assert_raise(NoMethodError) { obj.__send__(:parent_private) }
+ end
+
+ class ClassWithInvalidName
+ define_method(:" ") { :space }
+ define_method(:"\t") { :tab }
+ protected :"\t"
+ end
+
+ def test_delegateclass_invalid_name
+ delegate = DelegateClass(ClassWithInvalidName)
+ instance = delegate.new(ClassWithInvalidName.new)
+ assert_equal :space, instance.send(:" ")
+ assert_equal :space, instance.__send__(:" ")
+
+ assert_equal :tab, instance.send(:"\t")
+ assert_equal :tab, instance.__send__(:"\t")
+ end
+
class IV < DelegateClass(Integer)
attr_accessor :var
@@ -181,8 +210,8 @@ class TestDelegateClass < Test::Unit::TestCase
assert_nothing_raised(bug2679) {d.dup[0] += 1}
assert_raise(FrozenError) {d.clone[0] += 1}
d.freeze
- assert(d.clone.frozen?)
- assert(!d.dup.frozen?)
+ assert_predicate(d.clone, :frozen?)
+ assert_not_predicate(d.dup, :frozen?)
end
def test_frozen
@@ -390,4 +419,20 @@ class TestDelegateClass < Test::Unit::TestCase
a = DelegateClass(k).new(k.new)
assert_equal([1, 0], a.test(1, k: 0))
end
+
+ def test_delegate_class_can_be_used_in_ractors
+ omit "no Ractor#value" unless defined?(Ractor) && Ractor.method_defined?(:value)
+ require_path = File.expand_path(File.join(__dir__, "..", "lib", "delegate.rb"))
+ raise "file doesn't exist: #{require_path}" unless File.exist?(require_path)
+ assert_ractor <<-RUBY
+ require "#{require_path}"
+ class MyClass < DelegateClass(Array);end
+ values = 2.times.map do
+ Ractor.new do
+ MyClass.new([1,2,3]).at(0)
+ end
+ end.map(&:value)
+ assert_equal [1,1], values
+ RUBY
+ end
end
diff --git a/test/test_extlibs.rb b/test/test_extlibs.rb
index 8969c3c50f..122eca3f5c 100644
--- a/test/test_extlibs.rb
+++ b/test/test_extlibs.rb
@@ -10,7 +10,7 @@ class TestExtLibs < Test::Unit::TestCase
add_msg = ". #{add_msg}" if add_msg
log = "#{@extdir}/#{ext}/mkmf.log"
define_method("test_existence_of_#{ext}") do
- assert_separately([], <<-"end;", ignore_stderr: true) # do
+ assert_separately([], <<-"end;", ignore_stderr: true, timeout: 60) # do
log = #{log.dump}
msg = proc {
"extension library `#{ext}' is not found#{add_msg}\n" <<
diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb
index f2b7ed713f..9725ab31c1 100644
--- a/test/test_ipaddr.rb
+++ b/test/test_ipaddr.rb
@@ -196,6 +196,24 @@ class TC_IPAddr < Test::Unit::TestCase
}
assert_equal("::192.168.1.2", b.to_s)
assert_equal(Socket::AF_INET6, b.family)
+ assert_equal(128, b.prefix)
+
+ a = IPAddr.new("192.168.0.0/16")
+ assert_warning(/obsolete/) {
+ b = a.ipv4_compat
+ }
+ assert_equal("::192.168.0.0", b.to_s)
+ assert_equal(Socket::AF_INET6, b.family)
+ assert_equal(112, b.prefix)
+ end
+
+ def test_ipv4_compat_with_error_message
+ e = assert_raise(IPAddr::InvalidAddressError) do
+ assert_warning(/obsolete/) {
+ IPAddr.new('2001:db8::').ipv4_compat
+ }
+ end
+ assert_equal('not an IPv4 address: 2001:db8::', e.message)
end
def test_ipv4_mapped
@@ -215,6 +233,13 @@ class TC_IPAddr < Test::Unit::TestCase
assert_equal(Socket::AF_INET6, b.family)
end
+ def test_ipv4_mapped_with_error_message
+ e = assert_raise(IPAddr::InvalidAddressError) do
+ IPAddr.new('2001:db8::').ipv4_mapped
+ end
+ assert_equal('not an IPv4 address: 2001:db8::', e.message)
+ end
+
def test_reverse
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").reverse)
assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse)
@@ -222,16 +247,18 @@ class TC_IPAddr < Test::Unit::TestCase
def test_ip6_arpa
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa)
- assert_raise(IPAddr::InvalidAddressError) {
+ e = assert_raise(IPAddr::InvalidAddressError) {
IPAddr.new("192.168.2.1").ip6_arpa
}
+ assert_equal('not an IPv6 address: 192.168.2.1', e.message)
end
def test_ip6_int
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int)
- assert_raise(IPAddr::InvalidAddressError) {
+ e = assert_raise(IPAddr::InvalidAddressError) {
IPAddr.new("192.168.2.1").ip6_int
}
+ assert_equal('not an IPv6 address: 192.168.2.1', e.message)
end
def test_prefix_writer
@@ -399,6 +426,46 @@ class TC_Operator < Test::Unit::TestCase
assert_equal("::", @in6_addr_any.to_s)
end
+ def test_plus
+ a = IPAddr.new("192.168.1.10")
+ assert_equal("192.168.1.20", (a + 10).to_s)
+
+ a = IPAddr.new("0.0.0.0")
+ assert_equal("0.0.0.10", (a + 10).to_s)
+
+ a = IPAddr.new("255.255.255.255")
+ assert_raise(IPAddr::InvalidAddressError) { a + 10 }
+
+ a = IPAddr.new("3ffe:505:2::a")
+ assert_equal("3ffe:505:2::14", (a + 10).to_s)
+
+ a = IPAddr.new("::")
+ assert_equal("::a", (a + 10).to_s)
+
+ a = IPAddr.new("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
+ assert_raise(IPAddr::InvalidAddressError) { a + 10 }
+ end
+
+ def test_minus
+ a = IPAddr.new("192.168.1.10")
+ assert_equal("192.168.1.0", (a - 10).to_s)
+
+ a = IPAddr.new("0.0.0.0")
+ assert_raise(IPAddr::InvalidAddressError) { a - 10 }
+
+ a = IPAddr.new("255.255.255.255")
+ assert_equal("255.255.255.245", (a - 10).to_s)
+
+ a = IPAddr.new("3ffe:505:2::a")
+ assert_equal("3ffe:505:2::", (a - 10).to_s)
+
+ a = IPAddr.new("::")
+ assert_raise(IPAddr::InvalidAddressError) { a - 10 }
+
+ a = IPAddr.new("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
+ assert_equal("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff5", (a - 10).to_s)
+ end
+
def test_equal
assert_equal(true, @a == IPAddr.new("3FFE:505:2::"))
assert_equal(true, @a == IPAddr.new("3ffe:0505:0002::"))
@@ -408,6 +475,8 @@ class TC_Operator < Test::Unit::TestCase
assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
assert_equal(false, @a == @inconvertible_range)
assert_equal(false, @a == @inconvertible_string)
+ assert_equal(false, IPAddr.new("0.0.0.0") == nil)
+ assert_equal(false, IPAddr.new("::") == nil)
end
def test_compare
@@ -466,6 +535,9 @@ class TC_Operator < Test::Unit::TestCase
assert_equal(false, IPAddr.new('::ffff:0.0.0.0').loopback?)
assert_equal(false, IPAddr.new('::ffff:192.168.2.0').loopback?)
assert_equal(false, IPAddr.new('::ffff:255.0.0.0').loopback?)
+
+ # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:127.x.x.x
+ assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:7f00:1').loopback?)
end
def test_private?
@@ -516,6 +588,10 @@ class TC_Operator < Test::Unit::TestCase
assert_equal(false, IPAddr.new('::ffff:192.169.0.0').private?)
assert_equal(false, IPAddr.new('::ffff:169.254.0.1').private?)
+
+ # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:10/172.16/192.168.x
+ assert_equal(false, IPAddr.new('2001:718:1404:c8:0:ffff:ac19:c80e').private?)
+ assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:c0a8:1').private?)
end
def test_link_local?
@@ -542,6 +618,9 @@ class TC_Operator < Test::Unit::TestCase
assert_equal(true, IPAddr.new('::ffff:169.254.1.1').link_local?)
assert_equal(true, IPAddr.new('::ffff:169.254.254.255').link_local?)
+
+ # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:169.254.x.x
+ assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:a9fe:101').link_local?)
end
def test_hash
@@ -571,4 +650,21 @@ class TC_Operator < Test::Unit::TestCase
assert_equal(true, s.include?(a5))
assert_equal(true, s.include?(a6))
end
+
+ def test_raises_invalid_address_error_with_error_message
+ e = assert_raise(IPAddr::InvalidAddressError) do
+ IPAddr.new('192.168.0.1000')
+ end
+ assert_equal('invalid address: 192.168.0.1000', e.message)
+
+ e = assert_raise(IPAddr::InvalidAddressError) do
+ IPAddr.new('192.168.01.100')
+ end
+ assert_equal('zero-filled number in IPv4 address is ambiguous: 192.168.01.100', e.message)
+
+ e = assert_raise(IPAddr::InvalidAddressError) do
+ IPAddr.new('INVALID')
+ end
+ assert_equal('invalid address: INVALID', e.message)
+ end
end
diff --git a/test/test_pp.rb b/test/test_pp.rb
index c71445c9bc..922ed371af 100644
--- a/test/test_pp.rb
+++ b/test/test_pp.rb
@@ -2,11 +2,14 @@
require 'pp'
require 'delegate'
+require 'set'
require 'test/unit'
require 'ruby2_keywords'
module PPTestModule
+SetPP = Set.instance_method(:pretty_print).source_location[0].end_with?("/pp.rb")
+
class PPTest < Test::Unit::TestCase
def test_list0123_12
assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], ''.dup, 12))
@@ -16,6 +19,10 @@ class PPTest < Test::Unit::TestCase
assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], ''.dup, 11))
end
+ def test_set
+ assert_equal("Set[0, 1, 2, 3]\n", PP.pp(Set[0,1,2,3], ''.dup, 16))
+ end if SetPP
+
OverriddenStruct = Struct.new("OverriddenStruct", :members, :class)
def test_struct_override_members # [ruby-core:7865]
a = OverriddenStruct.new(1,2)
@@ -130,6 +137,22 @@ class PPInspectTest < Test::Unit::TestCase
assert_equal("#{a.inspect}\n", result)
end
+ def test_iv_hiding
+ a = Object.new
+ def a.pretty_print_instance_variables() [:@b] end
+ a.instance_eval { @a = "aaa"; @b = "bbb" }
+ assert_match(/\A#<Object:0x[\da-f]+ @b="bbb">\n\z/, PP.pp(a, ''.dup))
+ end
+
+ def test_iv_hiding_via_ruby
+ a = Object.new
+ a.singleton_class.class_eval do
+ private def instance_variables_to_inspect() [:@b] end
+ end
+ a.instance_eval { @a = "aaa"; @b = "bbb" }
+ assert_match(/\A#<Object:0x[\da-f]+ @b="bbb">\n\z/, PP.pp(a, ''.dup))
+ end
+
def test_basic_object
a = BasicObject.new
assert_match(/\A#<BasicObject:0x[\da-f]+>\n\z/, PP.pp(a, ''.dup))
@@ -150,6 +173,12 @@ class PPCycleTest < Test::Unit::TestCase
assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup))
end
+ def test_set
+ s = Set[]
+ s.add s
+ assert_equal("Set[Set[...]]\n", PP.pp(s, ''.dup))
+ end if SetPP
+
S = Struct.new("S", :a, :b)
def test_struct
a = S.new(1,2)
@@ -158,7 +187,14 @@ class PPCycleTest < Test::Unit::TestCase
assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup)) unless RUBY_ENGINE == "truffleruby"
end
- if defined?(Data.define)
+ verbose, $VERBOSE = $VERBOSE, nil
+ begin
+ has_data_define = defined?(Data.define)
+ ensure
+ $VERBOSE = verbose
+ end
+
+ if has_data_define
D = Data.define(:aaa, :bbb)
def test_data
a = D.new("aaa", "bbb")
@@ -223,7 +259,6 @@ class PPSingleLineTest < Test::Unit::TestCase
end
def test_hash_symbol_colon_key
- omit if RUBY_VERSION < "3.4."
no_quote = "{a: 1, a!: 1, a?: 1}"
unicode_quote = "{\u{3042}: 1}"
quote0 = '{"": 1}'
@@ -236,12 +271,25 @@ class PPSingleLineTest < Test::Unit::TestCase
assert_equal(quote1, PP.singleline_pp(eval(quote1), ''.dup))
assert_equal(quote2, PP.singleline_pp(eval(quote2), ''.dup))
assert_equal(quote3, PP.singleline_pp(eval(quote3), ''.dup))
- end
+ end if RUBY_VERSION >= "3.4."
def test_hash_in_array
omit if RUBY_ENGINE == "jruby"
- assert_equal("[{}]", PP.singleline_pp([->(*a){a.last.clear}.ruby2_keywords.call(a: 1)], ''.dup))
- assert_equal("[{}]", PP.singleline_pp([Hash.ruby2_keywords_hash({})], ''.dup))
+ assert_equal("[{}]", passing_keywords {PP.singleline_pp([->(*a){a.last.clear}.ruby2_keywords.call(a: 1)], ''.dup)})
+ assert_equal("[{}]", passing_keywords {PP.singleline_pp([Hash.ruby2_keywords_hash({})], ''.dup)})
+ end
+
+ if RUBY_VERSION >= "3.0"
+ def passing_keywords(&_)
+ yield
+ end
+ else
+ def passing_keywords(&_)
+ verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ ensure
+ $VERBOSE = verbose
+ end
end
def test_direct_pp
diff --git a/test/test_prettyprint.rb b/test/test_prettyprint.rb
index 27e7198886..a9ea55d5b3 100644
--- a/test/test_prettyprint.rb
+++ b/test/test_prettyprint.rb
@@ -518,4 +518,75 @@ End
end
+class SingleLineFormat < Test::Unit::TestCase # :nodoc:
+
+ def test_singleline_format_with_breakables
+ singleline_format = PrettyPrint.singleline_format("".dup) do |q|
+ q.group 0, "(", ")" do
+ q.text "abc"
+ q.breakable
+ q.text "def"
+ q.breakable
+ q.text "ghi"
+ q.breakable
+ q.text "jkl"
+ q.breakable
+ q.text "mno"
+ q.breakable
+ q.text "pqr"
+ q.breakable
+ q.text "stu"
+ end
+ end
+ expected = <<'End'.chomp
+(abc def ghi jkl mno pqr stu)
+End
+
+ assert_equal(expected, singleline_format)
+ end
+
+ def test_singleline_format_with_fill_breakables
+ singleline_format = PrettyPrint.singleline_format("".dup) do |q|
+ q.group 0, "(", ")" do
+ q.text "abc"
+ q.fill_breakable
+ q.text "def"
+ q.fill_breakable
+ q.text "ghi"
+ q.fill_breakable
+ q.text "jkl"
+ q.fill_breakable
+ q.text "mno"
+ q.fill_breakable
+ q.text "pqr"
+ q.fill_breakable
+ q.text "stu"
+ end
+ end
+ expected = <<'End'.chomp
+(abc def ghi jkl mno pqr stu)
+End
+
+ assert_equal(expected, singleline_format)
+ end
+
+ def test_singleline_format_with_group_sub
+ singleline_format = PrettyPrint.singleline_format("".dup) do |q|
+ q.group 0, "(", ")" do
+ q.group_sub do
+ q.text "abc"
+ q.breakable
+ q.text "def"
+ end
+ q.breakable
+ q.text "ghi"
+ end
+ end
+ expected = <<'End'.chomp
+(abc def ghi)
+End
+
+ assert_equal(expected, singleline_format)
+ end
+end
end
diff --git a/test/test_rbconfig.rb b/test/test_rbconfig.rb
index 7dbd525e99..e01264762d 100644
--- a/test/test_rbconfig.rb
+++ b/test/test_rbconfig.rb
@@ -60,7 +60,7 @@ class TestRbConfig < Test::Unit::TestCase
[sizeof_int, fixnum_max]
end
- sizeof_int, fixnum_max = r.take
+ sizeof_int, fixnum_max = r.value
assert_kind_of Integer, sizeof_int, "RbConfig::SIZEOF['int'] should be an Integer"
assert_kind_of Integer, fixnum_max, "RbConfig::LIMITS['FIXNUM_MAX'] should be an Integer"
diff --git a/test/test_time.rb b/test/test_time.rb
index 23e8e104a1..55964d02fc 100644
--- a/test/test_time.rb
+++ b/test/test_time.rb
@@ -74,7 +74,7 @@ class TestTimeExtension < Test::Unit::TestCase # :nodoc:
if defined?(Ractor)
def test_rfc2822_ractor
assert_ractor(<<~RUBY, require: 'time')
- actual = Ractor.new { Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600") }.take
+ actual = Ractor.new { Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600") }.value
assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600, actual)
RUBY
end
diff --git a/test/test_timeout.rb b/test/test_timeout.rb
index 01156867b0..2703a0314d 100644
--- a/test/test_timeout.rb
+++ b/test/test_timeout.rb
@@ -4,6 +4,23 @@ require 'timeout'
class TestTimeout < Test::Unit::TestCase
+ private def kill_timeout_thread
+ thread = Timeout.const_get(:State).instance.instance_variable_get(:@timeout_thread)
+ if thread
+ thread.kill
+ thread.join
+ end
+ end
+
+ def test_public_methods
+ assert_equal [:timeout], Timeout.private_instance_methods(false)
+ assert_equal [], Timeout.public_instance_methods(false)
+
+ assert_equal [:timeout], Timeout.singleton_class.public_instance_methods(false)
+
+ assert_equal [:Error, :ExitException, :VERSION], Timeout.constants.sort
+ end
+
def test_work_is_done_in_same_thread_as_caller
assert_equal Thread.current, Timeout.timeout(10){ Thread.current }
end
@@ -37,6 +54,12 @@ class TestTimeout < Test::Unit::TestCase
end
end
+ def test_raise_for_string_argument
+ assert_raise(NoMethodError) do
+ Timeout.timeout("1") { sleep(0.01) }
+ end
+ end
+
def test_included
c = Class.new do
include Timeout
@@ -105,8 +128,8 @@ class TestTimeout < Test::Unit::TestCase
def test_nested_timeout_which_error_bubbles_up
raised_exception = nil
begin
- Timeout.timeout(0.1) {
- Timeout.timeout(1) {
+ Timeout.timeout(1) {
+ Timeout.timeout(10) {
raise Timeout::ExitException.new("inner message")
}
}
@@ -212,6 +235,24 @@ class TestTimeout < Test::Unit::TestCase
end
end
+ def test_handle_interrupt_with_exception_class
+ bug11344 = '[ruby-dev:49179] [Bug #11344]'
+ ok = false
+ assert_raise(Timeout::Error) {
+ Thread.handle_interrupt(Timeout::Error => :never) {
+ Timeout.timeout(0.01, Timeout::Error) {
+ sleep 0.2
+ ok = true
+ Thread.handle_interrupt(Timeout::Error => :on_blocking) {
+ sleep 0.2
+ raise "unreachable"
+ }
+ }
+ }
+ }
+ assert(ok, bug11344)
+ end
+
def test_handle_interrupt
bug11344 = '[ruby-dev:49179] [Bug #11344]'
ok = false
@@ -222,6 +263,7 @@ class TestTimeout < Test::Unit::TestCase
ok = true
Thread.handle_interrupt(Timeout::ExitException => :on_blocking) {
sleep 0.2
+ raise "unreachable"
}
}
}
@@ -229,6 +271,94 @@ class TestTimeout < Test::Unit::TestCase
assert(ok, bug11344)
end
+ def test_handle_interrupt_with_interrupt_mask_inheritance
+ issue = 'https://github.com/ruby/timeout/issues/41'
+
+ [
+ -> {}, # not blocking so no opportunity to interrupt
+ -> { sleep 5 }
+ ].each_with_index do |body, idx|
+ # We need to create a new Timeout thread
+ kill_timeout_thread
+
+ # Create the timeout thread under a handle_interrupt(:never)
+ # due to the interrupt mask being inherited
+ Thread.handle_interrupt(Object => :never) {
+ assert_equal :ok, Timeout.timeout(1) { :ok }
+ }
+
+ # Ensure a simple timeout works and the interrupt mask was not inherited
+ assert_raise(Timeout::Error) {
+ Timeout.timeout(0.001) { sleep 1 }
+ }
+
+ r = []
+ # This raises Timeout::ExitException and not Timeout::Error for the non-blocking body
+ # because of the handle_interrupt(:never) which delays raising Timeout::ExitException
+ # on the main thread until getting outside of that handle_interrupt(:never) call.
+ # For this reason we document handle_interrupt(Timeout::ExitException) should not be used.
+ exc = idx == 0 ? Timeout::ExitException : Timeout::Error
+ assert_raise(exc) {
+ Thread.handle_interrupt(Timeout::ExitException => :never) {
+ Timeout.timeout(0.1) do
+ sleep 0.2
+ r << :sleep_before_done
+ Thread.handle_interrupt(Timeout::ExitException => :on_blocking) {
+ r << :body
+ body.call
+ }
+ ensure
+ sleep 0.2
+ r << :ensure_sleep_done
+ end
+ }
+ }
+ assert_equal([:sleep_before_done, :body, :ensure_sleep_done], r, issue)
+ end
+ end
+
+ # Same as above but with an exception class
+ def test_handle_interrupt_with_interrupt_mask_inheritance_with_exception_class
+ issue = 'https://github.com/ruby/timeout/issues/41'
+
+ [
+ -> {}, # not blocking so no opportunity to interrupt
+ -> { sleep 5 }
+ ].each do |body|
+ # We need to create a new Timeout thread
+ kill_timeout_thread
+
+ # Create the timeout thread under a handle_interrupt(:never)
+ # due to the interrupt mask being inherited
+ Thread.handle_interrupt(Object => :never) {
+ assert_equal :ok, Timeout.timeout(1) { :ok }
+ }
+
+ # Ensure a simple timeout works and the interrupt mask was not inherited
+ assert_raise(Timeout::Error) {
+ Timeout.timeout(0.001) { sleep 1 }
+ }
+
+ r = []
+ assert_raise(Timeout::Error) {
+ Thread.handle_interrupt(Timeout::Error => :never) {
+ Timeout.timeout(0.1, Timeout::Error) do
+ sleep 0.2
+ r << :sleep_before_done
+ Thread.handle_interrupt(Timeout::Error => :on_blocking) {
+ r << :body
+ body.call
+ }
+ ensure
+ sleep 0.2
+ r << :ensure_sleep_done
+ end
+ }
+ }
+ assert_equal([:sleep_before_done, :body, :ensure_sleep_done], r, issue)
+ end
+ end
+
def test_fork
omit 'fork not supported' unless Process.respond_to?(:fork)
r, w = IO.pipe
@@ -274,4 +404,134 @@ class TestTimeout < Test::Unit::TestCase
}.join
end;
end
+
+ def test_ractor
+ assert_separately(%w[-rtimeout -W0], <<-'end;')
+ r = Ractor.new do
+ Timeout.timeout(1) { 42 }
+ end.value
+
+ assert_equal 42, r
+
+ r = Ractor.new do
+ begin
+ Timeout.timeout(0.1) { sleep }
+ rescue Timeout::Error
+ :ok
+ end
+ end.value
+
+ assert_equal :ok, r
+ end;
+ end if defined?(::Ractor) && RUBY_VERSION >= '4.0'
+
+ def test_timeout_in_trap_handler
+ # https://github.com/ruby/timeout/issues/17
+
+ # Test as if this was the first timeout usage
+ kill_timeout_thread
+
+ rd, wr = IO.pipe
+
+ signal = :TERM
+
+ original_handler = trap(signal) do
+ begin
+ Timeout.timeout(0.1) do
+ sleep 1
+ end
+ rescue Timeout::Error
+ wr.write "OK"
+ wr.close
+ else
+ wr.write "did not raise"
+ ensure
+ wr.close
+ end
+ end
+
+ begin
+ Process.kill signal, Process.pid
+
+ assert_equal "OK", rd.read
+ rd.close
+ ensure
+ trap(signal, original_handler)
+ end
+ end
+
+ if Fiber.respond_to?(:current_scheduler)
+ # Stubs Fiber.current_scheduler for the duration of the block, then restores it.
+ def with_mock_scheduler(mock)
+ original = Fiber.method(:current_scheduler)
+ Fiber.singleton_class.remove_method(:current_scheduler)
+ Fiber.define_singleton_method(:current_scheduler) { mock }
+ begin
+ yield
+ ensure
+ Fiber.singleton_class.remove_method(:current_scheduler)
+ Fiber.define_singleton_method(:current_scheduler, original)
+ end
+ end
+
+ def test_fiber_scheduler_delegates_to_timeout_after
+ received = nil
+ mock = Object.new
+ mock.define_singleton_method(:timeout_after) do |sec, exc, msg, &blk|
+ received = [sec, exc, msg]
+ blk.call(sec)
+ end
+
+ with_mock_scheduler(mock) do
+ assert_equal :ok, Timeout.timeout(5) { :ok }
+ end
+
+ assert_equal 5, received[0]
+ assert_instance_of Timeout::ExitException, received[1], "scheduler should receive an ExitException instance when no klass given"
+ assert_equal "execution expired", received[2]
+ end
+
+ def test_fiber_scheduler_delegates_to_timeout_after_with_custom_exception
+ custom_error = Class.new(StandardError)
+ received = nil
+ mock = Object.new
+ mock.define_singleton_method(:timeout_after) do |sec, exc, msg, &blk|
+ received = [sec, exc, msg]
+ blk.call(sec)
+ end
+
+ with_mock_scheduler(mock) do
+ assert_equal :ok, Timeout.timeout(5, custom_error, "custom message") { :ok }
+ end
+
+ assert_equal [5, custom_error, "custom message"], received
+ end
+
+ def test_fiber_scheduler_timeout_raises_timeout_error
+ mock = Object.new
+ mock.define_singleton_method(:timeout_after) do |sec, exc, msg, &blk|
+ raise exc # simulate timeout firing
+ end
+
+ with_mock_scheduler(mock) do
+ assert_raise(Timeout::Error) do
+ Timeout.timeout(5) { :should_not_reach }
+ end
+ end
+ end
+
+ def test_fiber_scheduler_timeout_raises_custom_error
+ custom_error = Class.new(StandardError)
+ mock = Object.new
+ mock.define_singleton_method(:timeout_after) do |sec, exc, msg, &blk|
+ raise exc, msg
+ end
+
+ with_mock_scheduler(mock) do
+ assert_raise_with_message(custom_error, "custom message") do
+ Timeout.timeout(5, custom_error, "custom message") { :should_not_reach }
+ end
+ end
+ end
+ end
end
diff --git a/test/test_tmpdir.rb b/test/test_tmpdir.rb
index adc29183a8..c91fc334ed 100644
--- a/test/test_tmpdir.rb
+++ b/test/test_tmpdir.rb
@@ -134,17 +134,32 @@ class TestTmpdir < Test::Unit::TestCase
def test_ractor
assert_ractor(<<~'end;', require: "tmpdir")
- r = Ractor.new do
- Dir.mktmpdir() do |d|
- Ractor.yield d
- Ractor.receive
+ if defined?(Ractor::Port)
+ port = Ractor::Port.new
+ r = Ractor.new port do |port|
+ Dir.mktmpdir() do |d|
+ port << d
+ Ractor.receive
+ end
+ end
+ dir = port.receive
+ assert_file.directory? dir
+ r.send true
+ r.join
+ assert_file.not_exist? dir
+ else
+ r = Ractor.new do
+ Dir.mktmpdir() do |d|
+ Ractor.yield d
+ Ractor.receive
+ end
end
+ dir = r.take
+ assert_file.directory? dir
+ r.send true
+ r.take
+ assert_file.not_exist? dir
end
- dir = r.take
- assert_file.directory? dir
- r.send true
- r.take
- assert_file.not_exist? dir
end;
end
end
diff --git a/test/test_tsort.rb b/test/test_tsort.rb
deleted file mode 100644
index 354d928908..0000000000
--- a/test/test_tsort.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-# frozen_string_literal: true
-
-require 'tsort'
-require 'test/unit'
-
-class TSortHash < Hash # :nodoc:
- include TSort
- alias tsort_each_node each_key
- def tsort_each_child(node, &block)
- fetch(node).each(&block)
- end
-end
-
-class TSortArray < Array # :nodoc:
- include TSort
- alias tsort_each_node each_index
- def tsort_each_child(node, &block)
- fetch(node).each(&block)
- end
-end
-
-class TSortTest < Test::Unit::TestCase # :nodoc:
- def test_dag
- h = TSortHash[{1=>[2, 3], 2=>[3], 3=>[]}]
- assert_equal([3, 2, 1], h.tsort)
- assert_equal([[3], [2], [1]], h.strongly_connected_components)
- end
-
- def test_cycle
- h = TSortHash[{1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}]
- assert_equal([[4], [2, 3], [1]],
- h.strongly_connected_components.map {|nodes| nodes.sort})
- assert_raise(TSort::Cyclic) { h.tsort }
- end
-
- def test_array
- a = TSortArray[[1], [0], [0], [2]]
- assert_equal([[0, 1], [2], [3]],
- a.strongly_connected_components.map {|nodes| nodes.sort})
-
- a = TSortArray[[], [0]]
- assert_equal([[0], [1]],
- a.strongly_connected_components.map {|nodes| nodes.sort})
- end
-
- def test_s_tsort
- 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) }
- assert_equal([4, 2, 3, 1], TSort.tsort(each_node, each_child))
- g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- assert_raise(TSort::Cyclic) { TSort.tsort(each_node, each_child) }
- end
-
- def test_s_tsort_each
- 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) }
- r = []
- TSort.tsort_each(each_node, each_child) {|n| r << n }
- assert_equal([4, 2, 3, 1], r)
-
- r = TSort.tsort_each(each_node, each_child).map {|n| n.to_s }
- assert_equal(['4', '2', '3', '1'], r)
- end
-
- def test_s_strongly_connected_components
- 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) }
- assert_equal([[4], [2], [3], [1]],
- TSort.strongly_connected_components(each_node, each_child))
- g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- assert_equal([[4], [2, 3], [1]],
- TSort.strongly_connected_components(each_node, each_child))
- end
-
- def test_s_each_strongly_connected_component
- 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) }
- r = []
- TSort.each_strongly_connected_component(each_node, each_child) {|scc|
- r << scc
- }
- assert_equal([[4], [2], [3], [1]], r)
- g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- r = []
- TSort.each_strongly_connected_component(each_node, each_child) {|scc|
- r << scc
- }
- assert_equal([[4], [2, 3], [1]], r)
-
- r = TSort.each_strongly_connected_component(each_node, each_child).map {|scc|
- scc.map(&:to_s)
- }
- assert_equal([['4'], ['2', '3'], ['1']], r)
- end
-
- def test_s_each_strongly_connected_component_from
- g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- each_child = lambda {|n, &b| g[n].each(&b) }
- r = []
- TSort.each_strongly_connected_component_from(1, each_child) {|scc|
- r << scc
- }
- assert_equal([[4], [2, 3], [1]], r)
-
- r = TSort.each_strongly_connected_component_from(1, each_child).map {|scc|
- scc.map(&:to_s)
- }
- assert_equal([['4'], ['2', '3'], ['1']], r)
- end
-end
-
diff --git a/test/test_unicode_normalize.rb b/test/test_unicode_normalize.rb
index 8789ed92d2..dd06d27131 100644
--- a/test/test_unicode_normalize.rb
+++ b/test/test_unicode_normalize.rb
@@ -209,4 +209,32 @@ class TestUnicodeNormalize
assert_equal true, ascii_string.unicode_normalized?(:nfkc)
assert_equal true, ascii_string.unicode_normalized?(:nfkd)
end
+
+ def test_bug_21559
+ str = "s\u{1611e}\u{323}\u{1611e}\u{307}\u{1611f}"
+ assert_equal str.unicode_normalize(:nfd), str.unicode_normalize(:nfc).unicode_normalize(:nfd)
+ end
+
+ def test_gurung_khema
+ assert_equal "\u{16121 16121 16121 16121 16121 1611E}", "\u{1611E 16121 16121 16121 16121 16121}".unicode_normalize
+ end
+
+ def test_canonical_ordering
+ a = "\u03B1\u0313\u0300\u0345"
+ a_unordered1 = "\u03B1\u0345\u0313\u0300"
+ a_unordered2 = "\u03B1\u0313\u0345\u0300"
+ u1 = "U\u0308\u0304"
+ u2 = "U\u0304\u0308"
+ s = "s\u0323\u0307"
+ s_unordered = "s\u0307\u0323"
+ o = "\u{1611e}\u{1611e}\u{1611f}"
+ # Actual cases called through String#unicode_normalize
+ assert_equal(s + o, UnicodeNormalize.canonical_ordering_one(s_unordered + o))
+ assert_equal(a[1..], UnicodeNormalize.canonical_ordering_one(a_unordered1[1..]))
+ assert_equal(a[1..] + o, UnicodeNormalize.canonical_ordering_one(a_unordered2[1..] + o))
+ # Artificial cases
+ assert_equal(a + u1 + o + u2 + s, UnicodeNormalize.canonical_ordering_one(a + u1 + o + u2 + s))
+ assert_equal(s[1..] + a + a, UnicodeNormalize.canonical_ordering_one(s_unordered[1..] + a_unordered1 + a_unordered2))
+ assert_equal(o + s + u1 + a + o + a + u2 + o, UnicodeNormalize.canonical_ordering_one(o + s_unordered + u1 + a_unordered1 + o + a_unordered2 + u2 + o))
+ end
end
diff --git a/test/uri/test_common.rb b/test/uri/test_common.rb
index 6326aec561..569264005a 100644
--- a/test/uri/test_common.rb
+++ b/test/uri/test_common.rb
@@ -31,12 +31,14 @@ class URI::TestCommon < Test::Unit::TestCase
def test_parser_switch
assert_equal(URI::Parser, URI::RFC3986_Parser)
+ assert_equal(URI::PARSER, URI::RFC3986_PARSER)
refute defined?(URI::REGEXP)
refute defined?(URI::PATTERN)
URI.parser = URI::RFC2396_PARSER
assert_equal(URI::Parser, URI::RFC2396_Parser)
+ assert_equal(URI::PARSER, URI::RFC2396_PARSER)
assert defined?(URI::REGEXP)
assert defined?(URI::PATTERN)
assert defined?(URI::PATTERN::ESCAPED)
@@ -45,6 +47,7 @@ class URI::TestCommon < Test::Unit::TestCase
URI.parser = URI::RFC3986_PARSER
assert_equal(URI::Parser, URI::RFC3986_Parser)
+ assert_equal(URI::PARSER, URI::RFC3986_PARSER)
refute defined?(URI::REGEXP)
refute defined?(URI::PATTERN)
ensure
@@ -75,7 +78,7 @@ class URI::TestCommon < Test::Unit::TestCase
return unless defined?(Ractor)
assert_ractor(<<~RUBY, require: 'uri')
r = Ractor.new { URI.parse("https://ruby-lang.org/").inspect }
- assert_equal(URI.parse("https://ruby-lang.org/").inspect, r.take)
+ assert_equal(URI.parse("https://ruby-lang.org/").inspect, r.value)
RUBY
end
@@ -113,17 +116,18 @@ class URI::TestCommon < Test::Unit::TestCase
def test_register_scheme_with_symbols
# Valid schemes from https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
- some_uri_class = Class.new(URI::Generic)
- assert_raise(NameError) { URI.register_scheme 'ms-search', some_uri_class }
- assert_raise(NameError) { URI.register_scheme 'microsoft.windows.camera', some_uri_class }
- assert_raise(NameError) { URI.register_scheme 'coaps+ws', some_uri_class }
+ list = []
+ %w[ms-search microsoft.windows.camera coaps+ws].each {|name|
+ list << [name, URI.register_scheme(name, Class.new(URI::Generic))]
+ }
- ms_search_class = Class.new(URI::Generic)
- URI.register_scheme 'MS_SEARCH', ms_search_class
- begin
- assert_equal URI::Generic, URI.parse('ms-search://localhost').class
- ensure
- URI.const_get(:Schemes).send(:remove_const, :MS_SEARCH)
+ list.each do |scheme, uri_class|
+ assert_equal uri_class, URI.parse("#{scheme}://localhost").class
+ end
+ ensure
+ schemes = URI.const_get(:Schemes)
+ list.each do |scheme, |
+ schemes.send(:remove_const, schemes.escape(scheme))
end
end
diff --git a/test/uri/test_ftp.rb b/test/uri/test_ftp.rb
index f45bb0667c..3ad7864490 100644
--- a/test/uri/test_ftp.rb
+++ b/test/uri/test_ftp.rb
@@ -33,11 +33,11 @@ class URI::TestFTP < Test::Unit::TestCase
# If you think what's below is wrong, please read RubyForge bug 2055,
# RFC 1738 section 3.2.2, and RFC 2396.
u = URI.parse('ftp://ftp.example.com/foo/bar/file.ext')
- assert(u.path == 'foo/bar/file.ext')
+ assert_equal('foo/bar/file.ext', u.path)
u = URI.parse('ftp://ftp.example.com//foo/bar/file.ext')
- assert(u.path == '/foo/bar/file.ext')
+ assert_equal('/foo/bar/file.ext', u.path)
u = URI.parse('ftp://ftp.example.com/%2Ffoo/bar/file.ext')
- assert(u.path == '/foo/bar/file.ext')
+ assert_equal('/foo/bar/file.ext', u.path)
end
def test_assemble
@@ -45,8 +45,8 @@ class URI::TestFTP < Test::Unit::TestCase
# assuming everyone else has implemented RFC 2396.
uri = URI::FTP.build(['user:password', 'ftp.example.com', nil,
'/path/file.zip', 'i'])
- assert(uri.to_s ==
- 'ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i')
+ assert_equal('ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i',
+ uri.to_s)
end
def test_select
diff --git a/test/uri/test_generic.rb b/test/uri/test_generic.rb
index 1d5fbc715e..94eea71b51 100644
--- a/test/uri/test_generic.rb
+++ b/test/uri/test_generic.rb
@@ -240,9 +240,9 @@ class URI::TestGeneric < Test::Unit::TestCase
u = URI.parse('http://foo/bar/baz')
assert_equal(nil, u.merge!(""))
assert_equal(nil, u.merge!(u))
- assert(nil != u.merge!("."))
+ refute_nil(u.merge!("."))
assert_equal('http://foo/bar/', u.to_s)
- assert(nil != u.merge!("../baz"))
+ refute_nil(u.merge!("../baz"))
assert_equal('http://foo/baz', u.to_s)
url = URI.parse('http://a/b//c') + 'd//e'
@@ -283,6 +283,9 @@ class URI::TestGeneric < Test::Unit::TestCase
u0 = URI.parse('http://new.example.org/path')
u1 = u.merge('//new.example.org/path')
assert_equal(u0, u1)
+ u0 = URI.parse('http://other@example.net')
+ u1 = u.merge('//other@example.net')
+ assert_equal(u0, u1)
end
def test_route
@@ -356,7 +359,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/g', url.to_s)
url = @base_url.route_to('http://a/b/c/g')
assert_kind_of(URI::Generic, url)
- assert('./g' != url.to_s) # ok
+ refute_equal('./g', url.to_s) # ok
assert_equal('g', url.to_s)
# http://a/b/c/d;p?q
@@ -375,7 +378,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/g', url.to_s)
url = @base_url.route_to('http://a/g')
assert_kind_of(URI::Generic, url)
- assert('/g' != url.to_s) # ok
+ refute_equal('/g', url.to_s) # ok
assert_equal('../../g', url.to_s)
# http://a/b/c/d;p?q
@@ -466,7 +469,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/', url.to_s)
url = @base_url.route_to('http://a/b/c/')
assert_kind_of(URI::Generic, url)
- assert('.' != url.to_s) # ok
+ refute_equal('.', url.to_s) # ok
assert_equal('./', url.to_s)
# http://a/b/c/d;p?q
@@ -485,7 +488,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/', url.to_s)
url = @base_url.route_to('http://a/b/')
assert_kind_of(URI::Generic, url)
- assert('..' != url.to_s) # ok
+ refute_equal('..', url.to_s) # ok
assert_equal('../', url.to_s)
# http://a/b/c/d;p?q
@@ -513,7 +516,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/', url.to_s)
url = @base_url.route_to('http://a/')
assert_kind_of(URI::Generic, url)
- assert('../..' != url.to_s) # ok
+ refute_equal('../..', url.to_s) # ok
assert_equal('../../', url.to_s)
# http://a/b/c/d;p?q
@@ -604,7 +607,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/g', url.to_s)
url = @base_url.route_to('http://a/g')
assert_kind_of(URI::Generic, url)
- assert('../../../g' != url.to_s) # ok? yes, it confuses you
+ refute_equal('../../../g', url.to_s) # ok? yes, it confuses you
assert_equal('../../g', url.to_s) # and it is clearly
# http://a/b/c/d;p?q
@@ -614,7 +617,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/g', url.to_s)
url = @base_url.route_to('http://a/g')
assert_kind_of(URI::Generic, url)
- assert('../../../../g' != url.to_s) # ok? yes, it confuses you
+ refute_equal('../../../../g', url.to_s) # ok? yes, it confuses you
assert_equal('../../g', url.to_s) # and it is clearly
# http://a/b/c/d;p?q
@@ -624,7 +627,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/g', url.to_s)
url = @base_url.route_to('http://a/b/g')
assert_kind_of(URI::Generic, url)
- assert('./../g' != url.to_s) # ok
+ refute_equal('./../g', url.to_s) # ok
assert_equal('../g', url.to_s)
# http://a/b/c/d;p?q
@@ -634,7 +637,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/g/', url.to_s)
url = @base_url.route_to('http://a/b/c/g/')
assert_kind_of(URI::Generic, url)
- assert('./g/.' != url.to_s) # ok
+ refute_equal('./g/.', url.to_s) # ok
assert_equal('g/', url.to_s)
# http://a/b/c/d;p?q
@@ -644,7 +647,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/g/h', url.to_s)
url = @base_url.route_to('http://a/b/c/g/h')
assert_kind_of(URI::Generic, url)
- assert('g/./h' != url.to_s) # ok
+ refute_equal('g/./h', url.to_s) # ok
assert_equal('g/h', url.to_s)
# http://a/b/c/d;p?q
@@ -654,7 +657,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/h', url.to_s)
url = @base_url.route_to('http://a/b/c/h')
assert_kind_of(URI::Generic, url)
- assert('g/../h' != url.to_s) # ok
+ refute_equal('g/../h', url.to_s) # ok
assert_equal('h', url.to_s)
# http://a/b/c/d;p?q
@@ -664,7 +667,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/g;x=1/y', url.to_s)
url = @base_url.route_to('http://a/b/c/g;x=1/y')
assert_kind_of(URI::Generic, url)
- assert('g;x=1/./y' != url.to_s) # ok
+ refute_equal('g;x=1/./y', url.to_s) # ok
assert_equal('g;x=1/y', url.to_s)
# http://a/b/c/d;p?q
@@ -674,7 +677,7 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal('http://a/b/c/y', url.to_s)
url = @base_url.route_to('http://a/b/c/y')
assert_kind_of(URI::Generic, url)
- assert('g;x=1/../y' != url.to_s) # ok
+ refute_equal('g;x=1/../y', url.to_s) # ok
assert_equal('y', url.to_s)
# http://a/b/c/d;p?q
@@ -748,17 +751,18 @@ class URI::TestGeneric < Test::Unit::TestCase
def test_set_component
uri = URI.parse('http://foo:bar@baz')
assert_equal('oof', uri.user = 'oof')
- assert_equal('http://oof:bar@baz', uri.to_s)
+ assert_equal('http://oof@baz', uri.to_s)
assert_equal('rab', uri.password = 'rab')
assert_equal('http://oof:rab@baz', uri.to_s)
assert_equal('foo', uri.userinfo = 'foo')
- assert_equal('http://foo:rab@baz', uri.to_s)
+ assert_equal('http://foo@baz', uri.to_s)
assert_equal(['foo', 'bar'], uri.userinfo = ['foo', 'bar'])
assert_equal('http://foo:bar@baz', uri.to_s)
assert_equal(['foo'], uri.userinfo = ['foo'])
- assert_equal('http://foo:bar@baz', uri.to_s)
+ assert_equal('http://foo@baz', uri.to_s)
assert_equal('zab', uri.host = 'zab')
- assert_equal('http://foo:bar@zab', uri.to_s)
+ assert_equal('http://zab', uri.to_s)
+ uri.userinfo = ['foo', 'bar']
uri.port = ""
assert_nil(uri.port)
uri.port = "80"
@@ -768,7 +772,8 @@ class URI::TestGeneric < Test::Unit::TestCase
uri.port = " 080 "
assert_equal(80, uri.port)
assert_equal(8080, uri.port = 8080)
- assert_equal('http://foo:bar@zab:8080', uri.to_s)
+ assert_equal('http://zab:8080', uri.to_s)
+ uri = URI.parse('http://foo:bar@zab:8080')
assert_equal('/', uri.path = '/')
assert_equal('http://foo:bar@zab:8080/', uri.to_s)
assert_equal('a=1', uri.query = 'a=1')
@@ -822,18 +827,18 @@ class URI::TestGeneric < Test::Unit::TestCase
hierarchical = URI.parse('http://a.b.c/example')
opaque = URI.parse('mailto:mduerst@ifi.unizh.ch')
- assert hierarchical.hierarchical?
- refute opaque.hierarchical?
+ assert_predicate hierarchical, :hierarchical?
+ refute_predicate opaque, :hierarchical?
end
def test_absolute
abs_uri = URI.parse('http://a.b.c/')
not_abs = URI.parse('a.b.c')
- refute not_abs.absolute?
+ refute_predicate not_abs, :absolute?
- assert abs_uri.absolute
- assert abs_uri.absolute?
+ assert_predicate abs_uri, :absolute
+ assert_predicate abs_uri, :absolute?
end
def test_ipv6
@@ -846,8 +851,10 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal("http://[::1]/bar", u.to_s)
u.hostname = "::1"
assert_equal("http://[::1]/bar", u.to_s)
- u.hostname = ""
- assert_equal("http:///bar", u.to_s)
+
+ u = URI("file://foo/bar")
+ u.hostname = ''
+ assert_equal("file:///bar", u.to_s)
end
def test_build
@@ -868,6 +875,19 @@ class URI::TestGeneric < Test::Unit::TestCase
assert_equal("http://[::1]/bar/baz", u.to_s)
assert_equal("[::1]", u.host)
assert_equal("::1", u.hostname)
+
+ assert_raise_with_message(ArgumentError, /URI::Generic/) {
+ URI::Generic.build(nil)
+ }
+
+ c = Class.new(URI::Generic) do
+ def self.component; raise; end
+ end
+ expected = /\(#{URI::Generic::COMPONENT.join(', ')}\)/
+ message = "fallback to URI::Generic::COMPONENT if component raised"
+ assert_raise_with_message(ArgumentError, expected, message) {
+ c.build(nil)
+ }
end
def test_build2
diff --git a/test/uri/test_http.rb b/test/uri/test_http.rb
index e937b1a26b..8816d20175 100644
--- a/test/uri/test_http.rb
+++ b/test/uri/test_http.rb
@@ -19,6 +19,10 @@ class URI::TestHTTP < Test::Unit::TestCase
assert_kind_of(URI::HTTP, u)
end
+ def test_build_empty_host
+ assert_raise(URI::InvalidComponentError) { URI::HTTP.build(host: '') }
+ end
+
def test_parse
u = URI.parse('http://a')
assert_kind_of(URI::HTTP, u)
@@ -33,19 +37,19 @@ class URI::TestHTTP < Test::Unit::TestCase
host = 'aBcD'
u1 = URI.parse('http://' + host + '/eFg?HiJ')
u2 = URI.parse('http://' + host.downcase + '/eFg?HiJ')
- assert(u1.normalize.host == 'abcd')
- assert(u1.normalize.path == u1.path)
- assert(u1.normalize == u2.normalize)
- assert(!u1.normalize.host.equal?(u1.host))
- assert( u2.normalize.host.equal?(u2.host))
+ assert_equal('abcd', u1.normalize.host)
+ assert_equal(u1.path, u1.normalize.path)
+ assert_equal(u2.normalize, u1.normalize)
+ refute_same(u1.host, u1.normalize.host)
+ assert_same(u2.host, u2.normalize.host)
assert_equal('http://abc/', URI.parse('http://abc').normalize.to_s)
end
def test_equal
- assert(URI.parse('http://abc') == URI.parse('http://ABC'))
- assert(URI.parse('http://abc/def') == URI.parse('http://ABC/def'))
- assert(URI.parse('http://abc/def') != URI.parse('http://ABC/DEF'))
+ assert_equal(URI.parse('http://ABC'), URI.parse('http://abc'))
+ assert_equal(URI.parse('http://ABC/def'), URI.parse('http://abc/def'))
+ refute_equal(URI.parse('http://ABC/DEF'), URI.parse('http://abc/def'))
end
def test_request_uri
diff --git a/test/uri/test_mailto.rb b/test/uri/test_mailto.rb
index e7d3142198..6cd3352978 100644
--- a/test/uri/test_mailto.rb
+++ b/test/uri/test_mailto.rb
@@ -141,6 +141,21 @@ class URI::TestMailTo < Test::Unit::TestCase
def test_check_to
u = URI::MailTo.build(['joe@example.com', 'subject=Ruby'])
+ # Valid emails
+ u.to = 'a@valid.com'
+ assert_equal(u.to, 'a@valid.com')
+
+ # Intentionally allowed violations of RFC 5322
+ u.to = 'a..a@valid.com'
+ assert_equal(u.to, 'a..a@valid.com')
+
+ u.to = 'hello.@valid.com'
+ assert_equal(u.to, 'hello.@valid.com')
+
+ u.to = '.hello@valid.com'
+ assert_equal(u.to, '.hello@valid.com')
+
+ # Invalid emails
assert_raise(URI::InvalidComponentError) do
u.to = '#1@mail.com'
end
@@ -148,6 +163,63 @@ class URI::TestMailTo < Test::Unit::TestCase
assert_raise(URI::InvalidComponentError) do
u.to = '@invalid.email'
end
+
+ # Invalid host emails
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@.invalid.email'
+ end
+
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@invalid.email.'
+ end
+
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@invalid..email'
+ end
+
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@-invalid.email'
+ end
+
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@invalid-.email'
+ end
+
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@invalid.-email'
+ end
+
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@invalid.email-'
+ end
+
+ u.to = 'a@'+'invalid'.ljust(63, 'd')+'.email'
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@'+'invalid'.ljust(64, 'd')+'.email'
+ end
+
+ u.to = 'a@invalid.'+'email'.rjust(63, 'e')
+ assert_raise(URI::InvalidComponentError) do
+ u.to = 'a@invalid.'+'email'.rjust(64, 'e')
+ end
+ end
+
+ def test_email_regexp
+ re = URI::MailTo::EMAIL_REGEXP
+
+ repeat = 10
+ longlabel = '.' + 'invalid'.ljust(63, 'd')
+ endlabel = ''
+ seq = (1..3).map {|i| 10**i}
+ rehearsal = 10
+ pre = ->(n) {'a@invalid' + longlabel*(n) + endlabel}
+ assert_linear_performance(seq, rehearsal: rehearsal, pre: pre) do |to|
+ repeat.times {re =~ to or flunk}
+ end
+ endlabel = '.' + 'email'.rjust(64, 'd')
+ assert_linear_performance(seq, rehearsal: rehearsal, pre: pre) do |to|
+ repeat.times {re =~ to and flunk}
+ end
end
def test_to_s
diff --git a/test/uri/test_parser.rb b/test/uri/test_parser.rb
index f455a5cc9b..c14824f5e8 100644
--- a/test/uri/test_parser.rb
+++ b/test/uri/test_parser.rb
@@ -20,17 +20,17 @@ class URI::TestParser < Test::Unit::TestCase
u2 = p.parse(url)
u3 = p.parse(url)
- assert(u0 == u1)
- assert(u0.eql?(u1))
- assert(!u0.equal?(u1))
+ assert_equal(u1, u0)
+ assert_send([u0, :eql?, u1])
+ refute_same(u1, u0)
- assert(u1 == u2)
- assert(!u1.eql?(u2))
- assert(!u1.equal?(u2))
+ assert_equal(u2, u1)
+ assert_not_send([u1, :eql?, u2])
+ refute_same(u1, u2)
- assert(u2 == u3)
- assert(u2.eql?(u3))
- assert(!u2.equal?(u3))
+ assert_equal(u3, u2)
+ assert_send([u2, :eql?, u3])
+ refute_same(u3, u2)
end
def test_parse_rfc2396_parser
@@ -113,4 +113,12 @@ class URI::TestParser < Test::Unit::TestCase
end
end
end
+
+ def test_rfc2822_make_regexp
+ parser = URI::RFC2396_Parser.new
+ regexp = parser.make_regexp("HTTP")
+ assert_match(regexp, "HTTP://EXAMPLE.COM/")
+ assert_match(regexp, "http://example.com/")
+ refute_match(regexp, "https://example.com/")
+ end
end
diff --git a/test/uri/test_ws.rb b/test/uri/test_ws.rb
index f3918f617c..d63ebd4a46 100644
--- a/test/uri/test_ws.rb
+++ b/test/uri/test_ws.rb
@@ -31,19 +31,19 @@ class URI::TestWS < Test::Unit::TestCase
host = 'aBcD'
u1 = URI.parse('ws://' + host + '/eFg?HiJ')
u2 = URI.parse('ws://' + host.downcase + '/eFg?HiJ')
- assert(u1.normalize.host == 'abcd')
- assert(u1.normalize.path == u1.path)
- assert(u1.normalize == u2.normalize)
- assert(!u1.normalize.host.equal?(u1.host))
- assert( u2.normalize.host.equal?(u2.host))
+ assert_equal('abcd', u1.normalize.host)
+ assert_equal(u1.path, u1.normalize.path)
+ assert_equal(u2.normalize, u1.normalize)
+ refute_same(u1.host, u1.normalize.host)
+ assert_same(u2.host, u2.normalize.host)
assert_equal('ws://abc/', URI.parse('ws://abc').normalize.to_s)
end
def test_equal
- assert(URI.parse('ws://abc') == URI.parse('ws://ABC'))
- assert(URI.parse('ws://abc/def') == URI.parse('ws://ABC/def'))
- assert(URI.parse('ws://abc/def') != URI.parse('ws://ABC/DEF'))
+ assert_equal(URI.parse('ws://ABC'), URI.parse('ws://abc'))
+ assert_equal(URI.parse('ws://ABC/def'), URI.parse('ws://abc/def'))
+ refute_equal(URI.parse('ws://ABC/DEF'), URI.parse('ws://abc/def'))
end
def test_request_uri
diff --git a/test/uri/test_wss.rb b/test/uri/test_wss.rb
index 13a2583059..cbef327cc6 100644
--- a/test/uri/test_wss.rb
+++ b/test/uri/test_wss.rb
@@ -31,19 +31,19 @@ class URI::TestWSS < Test::Unit::TestCase
host = 'aBcD'
u1 = URI.parse('wss://' + host + '/eFg?HiJ')
u2 = URI.parse('wss://' + host.downcase + '/eFg?HiJ')
- assert(u1.normalize.host == 'abcd')
- assert(u1.normalize.path == u1.path)
- assert(u1.normalize == u2.normalize)
- assert(!u1.normalize.host.equal?(u1.host))
- assert( u2.normalize.host.equal?(u2.host))
+ assert_equal('abcd', u1.normalize.host)
+ assert_equal(u1.path, u1.normalize.path)
+ assert_equal(u2.normalize, u1.normalize)
+ refute_same(u1.host, u1.normalize.host)
+ assert_same(u2.host, u2.normalize.host)
assert_equal('wss://abc/', URI.parse('wss://abc').normalize.to_s)
end
def test_equal
- assert(URI.parse('wss://abc') == URI.parse('wss://ABC'))
- assert(URI.parse('wss://abc/def') == URI.parse('wss://ABC/def'))
- assert(URI.parse('wss://abc/def') != URI.parse('wss://ABC/DEF'))
+ assert_equal(URI.parse('wss://ABC'), URI.parse('wss://abc'))
+ assert_equal(URI.parse('wss://ABC/def'), URI.parse('wss://abc/def'))
+ refute_equal(URI.parse('wss://ABC/DEF'), URI.parse('wss://abc/def'))
end
def test_request_uri
diff --git a/test/win32/test_registry.rb b/test/win32/test_registry.rb
deleted file mode 100644
index 9a38d0d314..0000000000
--- a/test/win32/test_registry.rb
+++ /dev/null
@@ -1,256 +0,0 @@
-# frozen_string_literal: true
-
-require "rbconfig"
-
-if /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os']
- begin
- require 'win32/registry'
- rescue LoadError
- else
- require 'test/unit'
- end
-end
-
-if defined?(Win32::Registry)
- class TestWin32Registry < Test::Unit::TestCase
- COMPUTERNAME = 'SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName'
- TEST_REGISTRY_PATH = 'Volatile Environment'
- TEST_REGISTRY_KEY = 'ruby-win32-registry-test-<RND>'
-
- # Create a new registry key per test in an atomic way, which is deleted on teardown.
- #
- # Fills the following instance variables:
- #
- # @test_registry_key - A registry path which is not yet created,
- # but can be created without collisions even when running
- # multiple test processes.
- # @test_registry_rnd - The part of the registry path with a random number.
- # @createopts - Required parameters (desired, opt) for create method in
- # the volatile environment of the registry.
- def setup
- @createopts = [Win32::Registry::KEY_ALL_ACCESS, Win32::Registry::REG_OPTION_VOLATILE]
- 100.times do |i|
- k = TEST_REGISTRY_KEY.gsub("<RND>", i.to_s)
- next unless Win32::Registry::HKEY_CURRENT_USER.create(
- TEST_REGISTRY_PATH + "\\" + k,
- *@createopts
- ).created?
- @test_registry_key = TEST_REGISTRY_PATH + "\\" + k + "\\" + "test\\"
- @test_registry_rnd = k
- break
- end
- omit "Unused registry subkey not found in #{TEST_REGISTRY_KEY}" unless @test_registry_key
- end
-
- def teardown
- Win32::Registry::HKEY_CURRENT_USER.open(TEST_REGISTRY_PATH) do |reg|
- reg.delete_key @test_registry_rnd, true
- end
- end
-
- def test_predefined
- assert_predefined_key Win32::Registry::HKEY_CLASSES_ROOT
- assert_predefined_key Win32::Registry::HKEY_CURRENT_USER
- assert_predefined_key Win32::Registry::HKEY_LOCAL_MACHINE
- assert_predefined_key Win32::Registry::HKEY_USERS
- assert_predefined_key Win32::Registry::HKEY_PERFORMANCE_DATA
- assert_predefined_key Win32::Registry::HKEY_PERFORMANCE_TEXT
- assert_predefined_key Win32::Registry::HKEY_PERFORMANCE_NLSTEXT
- assert_predefined_key Win32::Registry::HKEY_CURRENT_CONFIG
- assert_predefined_key Win32::Registry::HKEY_DYN_DATA
- end
-
- def test_open_no_block
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts).close
-
- reg = Win32::Registry::HKEY_CURRENT_USER.open(@test_registry_key, Win32::Registry::KEY_ALL_ACCESS)
- assert_kind_of Win32::Registry, reg
- assert_equal true, reg.open?
- assert_equal false, reg.created?
- reg["test"] = "abc"
- reg.close
- assert_raise(Win32::Registry::Error) do
- reg["test"] = "abc"
- end
- end
-
- def test_open_with_block
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts).close
-
- regs = []
- Win32::Registry::HKEY_CURRENT_USER.open(@test_registry_key, Win32::Registry::KEY_ALL_ACCESS) do |reg|
- regs << reg
- assert_equal true, reg.open?
- assert_equal false, reg.created?
- reg["test"] = "abc"
- end
-
- assert_equal 1, regs.size
- assert_kind_of Win32::Registry, regs[0]
- assert_raise(Win32::Registry::Error) do
- regs[0]["test"] = "abc"
- end
- end
-
- def test_class_open
- name1, keys1 = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, "SYSTEM") do |reg|
- assert_predicate reg, :open?
- [reg.name, reg.keys]
- end
- name2, keys2 = Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM") do |reg|
- assert_predicate reg, :open?
- [reg.name, reg.keys]
- end
- assert_equal name1, name2
- assert_equal keys1, keys2
- end
-
- def test_read
- computername = ENV['COMPUTERNAME']
- Win32::Registry::HKEY_LOCAL_MACHINE.open(COMPUTERNAME) do |reg|
- assert_equal computername, reg['ComputerName']
- assert_equal [Win32::Registry::REG_SZ, computername], reg.read('ComputerName')
- assert_raise(TypeError) {reg.read('ComputerName', Win32::Registry::REG_DWORD)}
- end
- end
-
- def test_create_no_block
- reg = Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts)
- assert_kind_of Win32::Registry, reg
- assert_equal true, reg.open?
- assert_equal true, reg.created?
- reg["test"] = "abc"
- reg.close
- assert_equal false, reg.open?
- assert_raise(Win32::Registry::Error) do
- reg["test"] = "abc"
- end
- end
-
- def test_create_with_block
- regs = []
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- regs << reg
- reg["test"] = "abc"
- assert_equal true, reg.open?
- assert_equal true, reg.created?
- end
-
- assert_equal 1, regs.size
- assert_kind_of Win32::Registry, regs[0]
- assert_equal false, regs[0].open?
- assert_raise(Win32::Registry::Error) do
- regs[0]["test"] = "abc"
- end
- end
-
- def test_write
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.write_s("key1", "data")
- assert_equal [Win32::Registry::REG_SZ, "data"], reg.read("key1")
- reg.write_i("key2", 0x5fe79027)
- assert_equal [Win32::Registry::REG_DWORD, 0x5fe79027], reg.read("key2")
- end
- end
-
- def test_accessors
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- assert_kind_of Integer, reg.hkey
- assert_kind_of Win32::Registry, reg.parent
- assert_equal "HKEY_CURRENT_USER", reg.parent.name
- assert_equal "Volatile Environment\\#{@test_registry_rnd}\\test\\", reg.keyname
- assert_equal Win32::Registry::REG_CREATED_NEW_KEY, reg.disposition
- end
- end
-
- def test_name
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- assert_equal "HKEY_CURRENT_USER\\Volatile Environment\\#{@test_registry_rnd}\\test\\", reg.name
- end
- end
-
- def test_keys
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("key1", *@createopts)
- assert_equal ["key1"], reg.keys
- end
- end
-
- def test_each_key
- keys = []
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("key1", *@createopts)
- reg.each_key { |*a| keys << a }
- end
- assert_equal [2], keys.map(&:size)
- assert_equal ["key1"], keys.map(&:first)
- assert_in_delta Win32::Registry.time2wtime(Time.now), keys[0][1], 10_000_000_000, "wtime should roughly match Time.now"
- end
-
- def test_each_key_enum
- keys = nil
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("key1", *@createopts)
- reg.create("key2", *@createopts)
- reg.create("key3", *@createopts)
- reg["value1"] = "abcd"
- keys = reg.each_key.to_a
- end
- assert_equal 3, keys.size
- assert_equal [2, 2, 2], keys.map(&:size)
- assert_equal ["key1", "key2", "key3"], keys.map(&:first)
- end
-
- def test_values
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("key1", *@createopts)
- reg["value1"] = "abcd"
- assert_equal ["abcd"], reg.values
- end
- end
-
- def test_each_value
- vals = []
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("key1", *@createopts)
- reg["value1"] = "abcd"
- reg.each_value { |*a| vals << a }
- end
- assert_equal [["value1", Win32::Registry::REG_SZ, "abcd"]], vals
- end
-
- def test_each_value_enum
- vals = nil
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("key1", *@createopts)
- reg["value1"] = "abcd"
- reg["value2"] = 42
- vals = reg.each_value.to_a
- end
- assert_equal [["value1", Win32::Registry::REG_SZ, "abcd"],
- ["value2", Win32::Registry::REG_DWORD, 42]], vals
- end
-
- def test_utf8_encoding
- keys = []
- Win32::Registry::HKEY_CURRENT_USER.create(@test_registry_key, *@createopts) do |reg|
- reg.create("abc EUR", *@createopts)
- reg.create("abc €", *@createopts)
- reg.each_key do |subkey|
- keys << subkey
- end
- end
-
- assert_equal [Encoding::UTF_8] * 2, keys.map(&:encoding)
- assert_equal ["abc EUR", "abc €"], keys
- end
-
- private
-
- def assert_predefined_key(key)
- assert_kind_of Win32::Registry, key
- assert_predicate key, :open?
- refute_predicate key, :created?
- end
- end
-end
diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb
index 5a8463ad8e..48b8f172ff 100644
--- a/test/zlib/test_zlib.rb
+++ b/test/zlib/test_zlib.rb
@@ -9,6 +9,9 @@ require 'securerandom'
begin
require 'zlib'
rescue LoadError
+else
+ z = "/zlib.#{RbConfig::CONFIG["DLEXT"]}"
+ LOADED_ZLIB, = $".select {|f| f.end_with?(z)}
end
if defined? Zlib
@@ -879,6 +882,25 @@ if defined? Zlib
assert_equal(-1, r.pos, "[ruby-core:81488][Bug #13616]")
end
+ def test_ungetc_buffer_underflow
+ initial_bufsize = 1024
+ payload = "A" * initial_bufsize
+ gzip_io = StringIO.new
+ Zlib::GzipWriter.wrap(gzip_io) { |gz| gz.write(payload) }
+ compressed = gzip_io.string
+
+ reader = Zlib::GzipReader.new(StringIO.new(compressed))
+ reader.read(1)
+ overflow_bytes = "B" * (initial_bufsize)
+ reader.ungetc(overflow_bytes)
+ data = reader.read(overflow_bytes.bytesize)
+ assert_equal overflow_bytes.bytesize, data.bytesize, data
+ assert_empty data.delete("B"), data
+ data = reader.read()
+ assert_equal initial_bufsize - 1, data.bytesize, data
+ assert_empty data.delete("A"), data
+ end
+
def test_open
Tempfile.create("test_zlib_gzip_reader_open") {|t|
t.close
@@ -1263,6 +1285,36 @@ if defined? Zlib
end
}
end
+
+ # Test for signal interrupt bug: Z_BUF_ERROR with avail_out > 0
+ # This reproduces the issue where thread wakeup during GzipReader operations
+ # can cause Z_BUF_ERROR to be raised incorrectly
+ def test_thread_wakeup_interrupt
+ pend 'fails' if RUBY_ENGINE == 'truffleruby'
+ content = SecureRandom.base64(5000)
+ gzipped = Zlib.gzip(content)
+
+ 1000.times do
+ thr = Thread.new do
+ loop do
+ Zlib::GzipReader.new(StringIO.new(gzipped)).read
+ end
+ end
+
+ # Wakeup the thread multiple times to trigger interrupts
+ 10.times do
+ thr.wakeup
+ Thread.pass
+ end
+
+ # Give thread a moment to process
+ sleep 0.001
+
+ # Clean up
+ thr.kill
+ thr.join
+ end
+ end
end
class TestZlibGzipWriter < Test::Unit::TestCase
@@ -1525,11 +1577,42 @@ if defined? Zlib
end
def test_gunzip_no_memory_leak
- assert_no_memory_leak(%[-rzlib], "#{<<~"{#"}", "#{<<~'};'}")
+ assert_no_memory_leak(%W[-r#{LOADED_ZLIB}], "#{<<~"{#"}", "#{<<~'};'}")
d = Zlib.gzip("data")
{#
10_000.times {Zlib.gunzip(d)}
};
end
+
+ # Test for signal interrupt bug: Z_BUF_ERROR with avail_out > 0
+ # This reproduces the issue where thread wakeup during GzipReader operations
+ # can cause Z_BUF_ERROR to be raised incorrectly
+ def test_thread_wakeup_interrupt
+ pend 'fails' if RUBY_ENGINE == 'truffleruby'
+
+ content = SecureRandom.base64(5000)
+ gzipped = Zlib.gzip(content)
+
+ 1000.times do
+ thr = Thread.new do
+ loop do
+ Zlib::GzipReader.new(StringIO.new(gzipped)).read
+ end
+ end
+
+ # Wakeup the thread multiple times to trigger interrupts
+ 10.times do
+ thr.wakeup
+ Thread.pass
+ end
+
+ # Give thread a moment to process
+ sleep 0.001
+
+ # Clean up
+ thr.kill
+ thr.join
+ end
+ end
end
end
diff --git a/thread.c b/thread.c
index 661ee977a9..25dde73fd7 100644
--- a/thread.c
+++ b/thread.c
@@ -78,6 +78,7 @@
#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/io.h"
@@ -98,6 +99,9 @@
#include "ractor_core.h"
#include "vm_debug.h"
#include "vm_sync.h"
+#include "zjit.h"
+
+#include "ccan/list/list.h"
#ifndef USE_NATIVE_THREAD_PRIORITY
#define USE_NATIVE_THREAD_PRIORITY 0
@@ -146,16 +150,9 @@ static int hrtime_update_expire(rb_hrtime_t *, const rb_hrtime_t);
NORETURN(static void async_bug_fd(const char *mesg, int errno_arg, int fd));
MAYBE_UNUSED(static int consume_communication_pipe(int fd));
-static volatile int system_working = 1;
+static rb_atomic_t system_working = 1;
static rb_internal_thread_specific_key_t specific_key_count;
-struct waiting_fd {
- struct ccan_list_node wfd_node; /* <=> vm.waiting_fds */
- rb_thread_t *th;
- int fd;
- struct rb_io_close_wait_list *busy;
-};
-
/********************************************************************************/
#define THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
@@ -174,11 +171,11 @@ static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_regio
#define THREAD_BLOCKING_BEGIN(th) do { \
struct rb_thread_sched * const sched = TH_SCHED(th); \
RB_VM_SAVE_MACHINE_CONTEXT(th); \
- thread_sched_to_waiting((sched), (th));
+ thread_sched_to_waiting((sched), (th), true);
#define THREAD_BLOCKING_END(th) \
thread_sched_to_running((sched), (th)); \
- rb_ractor_thread_switch(th->ractor, th); \
+ rb_ractor_thread_switch(th->ractor, th, false); \
} while(0)
#ifdef __GNUC__
@@ -198,7 +195,7 @@ static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_regio
/* Important that this is inlined into the macro, and not part of \
* blocking_region_begin - see bug #20493 */ \
RB_VM_SAVE_MACHINE_CONTEXT(th); \
- thread_sched_to_waiting(TH_SCHED(th), th); \
+ thread_sched_to_waiting(TH_SCHED(th), th, false); \
exec; \
blocking_region_end(th, &__region); \
}; \
@@ -212,6 +209,10 @@ static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_regio
static inline int
vm_check_ints_blocking(rb_execution_context_t *ec)
{
+#ifdef RUBY_ASSERT_CRITICAL_SECTION
+ VM_ASSERT(ruby_assert_critical_section_entered == 0);
+#endif
+
rb_thread_t *th = rb_ec_thread_ptr(ec);
if (LIKELY(rb_threadptr_pending_interrupt_empty_p(th))) {
@@ -221,7 +222,18 @@ vm_check_ints_blocking(rb_execution_context_t *ec)
th->pending_interrupt_queue_checked = 0;
RUBY_VM_SET_INTERRUPT(ec);
}
- return rb_threadptr_execute_interrupts(th, 1);
+
+ int result = rb_threadptr_execute_interrupts(th, 1);
+
+ // When a signal is received, we yield to the scheduler as soon as possible:
+ if (result || RUBY_VM_INTERRUPTED(ec)) {
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
+ if (scheduler != Qnil) {
+ rb_fiber_scheduler_yield(scheduler);
+ }
+ }
+
+ return result;
}
int
@@ -340,7 +352,7 @@ unblock_function_clear(rb_thread_t *th)
}
static void
-threadptr_interrupt_locked(rb_thread_t *th, bool trap)
+threadptr_set_interrupt_locked(rb_thread_t *th, bool trap)
{
// th->interrupt_lock should be acquired here
@@ -362,26 +374,27 @@ threadptr_interrupt_locked(rb_thread_t *th, bool trap)
}
static void
-threadptr_interrupt(rb_thread_t *th, int trap)
+threadptr_set_interrupt(rb_thread_t *th, int trap)
{
rb_native_mutex_lock(&th->interrupt_lock);
{
- threadptr_interrupt_locked(th, trap);
+ threadptr_set_interrupt_locked(th, trap);
}
rb_native_mutex_unlock(&th->interrupt_lock);
}
+/* Set interrupt flag on another thread or current thread, and call its UBF if it has one set */
void
rb_threadptr_interrupt(rb_thread_t *th)
{
RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
- threadptr_interrupt(th, false);
+ threadptr_set_interrupt(th, false);
}
static void
threadptr_trap_interrupt(rb_thread_t *th)
{
- threadptr_interrupt(th, true);
+ threadptr_set_interrupt(th, true);
}
static void
@@ -441,8 +454,8 @@ rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
th->keeping_mutexes = mutex->next_mutex;
// rb_warn("mutex #<%p> was not unlocked by thread #<%p>", (void *)mutex, (void*)th);
-
- const char *error_message = rb_mutex_unlock_th(mutex, th, mutex->fiber);
+ VM_ASSERT(mutex->ec_serial);
+ const char *error_message = rb_mutex_unlock_th(mutex, th, 0);
if (error_message) rb_bug("invalid keeping_mutexes: %s", error_message);
}
}
@@ -519,12 +532,8 @@ thread_cleanup_func(void *th_ptr, int atfork)
th->locking_mutex = Qfalse;
thread_cleanup_func_before_exec(th_ptr);
- /*
- * Unfortunately, we can't release native threading resource at fork
- * because libc may have unstable locking state therefore touching
- * a threading resource may cause a deadlock.
- */
if (atfork) {
+ native_thread_destroy_atfork(th->nt);
th->nt = NULL;
return;
}
@@ -532,6 +541,15 @@ thread_cleanup_func(void *th_ptr, int atfork)
rb_native_mutex_destroy(&th->interrupt_lock);
}
+void
+rb_thread_free_native_thread(void *th_ptr)
+{
+ rb_thread_t *th = th_ptr;
+
+ native_thread_destroy_atfork(th->nt);
+ th->nt = NULL;
+}
+
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
static VALUE rb_thread_to_s(VALUE thread);
@@ -693,7 +711,8 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
if (state == TAG_NONE) {
// This must be set AFTER doing all user-level code. At this point, the thread is effectively finished and calls to `Thread#join` will succeed.
th->value = result;
- } else {
+ }
+ else {
errinfo = th->ec->errinfo;
VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
@@ -706,6 +725,10 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
/* fatal error within this thread, need to stop whole script */
}
else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
+ if (th->invoke_type == thread_invoke_type_ractor_proc) {
+ rb_ractor_atexit_exception(th->ec);
+ }
+
/* exit on main_thread. */
}
else {
@@ -838,8 +861,9 @@ thread_create_core(VALUE thval, struct thread_create_params *params)
#endif
th->invoke_type = thread_invoke_type_ractor_proc;
th->ractor = params->g;
+ th->ec->ractor_id = rb_ractor_id(th->ractor);
th->ractor->threads.main = th;
- th->invoke_arg.proc.proc = rb_proc_isolate_bang(params->proc);
+ th->invoke_arg.proc.proc = rb_proc_isolate_bang(params->proc, Qnil);
th->invoke_arg.proc.args = INT2FIX(RARRAY_LENINT(params->args));
th->invoke_arg.proc.kw_splat = rb_keyword_given_p();
rb_ractor_send_parameters(ec, params->g, params->args);
@@ -1002,7 +1026,7 @@ rb_thread_create_ractor(rb_ractor_t *r, VALUE args, VALUE proc)
.args = args,
.proc = proc,
};
- return thread_create_core(rb_thread_alloc(rb_cThread), &params);;
+ return thread_create_core(rb_thread_alloc(rb_cThread), &params);
}
@@ -1053,25 +1077,30 @@ thread_join_sleep(VALUE arg)
}
while (!thread_finished(target_th)) {
- VALUE scheduler = rb_fiber_scheduler_current();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
- if (scheduler != Qnil) {
- rb_fiber_scheduler_block(scheduler, target_th->self, p->timeout);
- // Check if the target thread is finished after blocking:
- if (thread_finished(target_th)) break;
- // Otherwise, a timeout occurred:
- else return Qfalse;
- }
- else if (!limit) {
- sleep_forever(th, SLEEP_DEADLOCKABLE | SLEEP_ALLOW_SPURIOUS | SLEEP_NO_CHECKINTS);
+ if (!limit) {
+ if (scheduler != Qnil) {
+ rb_fiber_scheduler_block(scheduler, target_th->self, Qnil);
+ }
+ else {
+ sleep_forever(th, SLEEP_DEADLOCKABLE | SLEEP_ALLOW_SPURIOUS | SLEEP_NO_CHECKINTS);
+ }
}
else {
if (hrtime_update_expire(limit, end)) {
RUBY_DEBUG_LOG("timeout target_th:%u", rb_th_serial(target_th));
return Qfalse;
}
- th->status = THREAD_STOPPED;
- native_sleep(th, limit);
+
+ if (scheduler != Qnil) {
+ VALUE timeout = rb_float_new(hrtime2double(*limit));
+ rb_fiber_scheduler_block(scheduler, target_th->self, timeout);
+ }
+ else {
+ th->status = THREAD_STOPPED;
+ native_sleep(th, limit);
+ }
}
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
th->status = THREAD_RUNNABLE;
@@ -1130,6 +1159,10 @@ thread_join(rb_thread_t *target_th, VALUE timeout, rb_hrtime_t *limit)
/* OK. killed. */
break;
default:
+ if (err == RUBY_FATAL_FIBER_KILLED) { // not integer constant so can't be a case expression
+ // root fiber killed in non-main thread
+ break;
+ }
rb_bug("thread_join: Fixnum (%d) should not reach here.", FIX2INT(err));
}
}
@@ -1393,17 +1426,18 @@ rb_thread_sleep_deadly(void)
static void
rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker, VALUE timeout, rb_hrtime_t end)
{
- VALUE scheduler = rb_fiber_scheduler_current();
+ rb_thread_t *th = GET_THREAD();
+ VALUE scheduler = rb_fiber_scheduler_current_for_threadptr(th);
if (scheduler != Qnil) {
rb_fiber_scheduler_block(scheduler, blocker, timeout);
}
else {
RUBY_DEBUG_LOG("...");
if (end) {
- sleep_hrtime_until(GET_THREAD(), end, SLEEP_SPURIOUS_CHECK);
+ sleep_hrtime_until(th, end, SLEEP_SPURIOUS_CHECK);
}
else {
- sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE);
+ sleep_forever(th, SLEEP_DEADLOCKABLE);
}
}
}
@@ -1470,7 +1504,7 @@ rb_thread_schedule_limits(uint32_t limits_us)
RB_VM_SAVE_MACHINE_CONTEXT(th);
thread_sched_yield(TH_SCHED(th), th);
- rb_ractor_thread_switch(th->ractor, th);
+ rb_ractor_thread_switch(th->ractor, th, true);
RUBY_DEBUG_LOG("switch %s", "done");
}
@@ -1518,7 +1552,7 @@ blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
unregister_ubf_list(th);
thread_sched_to_running(TH_SCHED(th), th);
- rb_ractor_thread_switch(th->ractor, th);
+ rb_ractor_thread_switch(th->ractor, th, false);
th->blocking_region_buffer = 0;
rb_ractor_blocking_threads_dec(th->ractor, __FILE__, __LINE__);
@@ -1534,6 +1568,29 @@ blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
#endif
}
+/*
+ * Resolve sentinel unblock function values to their actual function pointers
+ * and appropriate data2 values. This centralizes the logic for handling
+ * RUBY_UBF_IO and RUBY_UBF_PROCESS sentinel values.
+ *
+ * @param unblock_function Pointer to unblock function pointer (modified in place)
+ * @param data2 Pointer to data2 pointer (modified in place)
+ * @param thread Thread context for resolving data2 when needed
+ * @return true if sentinel values were resolved, false otherwise
+ */
+bool
+rb_thread_resolve_unblock_function(rb_unblock_function_t **unblock_function, void **data2, struct rb_thread_struct *thread)
+{
+ rb_unblock_function_t *ubf = *unblock_function;
+
+ if ((ubf == RUBY_UBF_IO) || (ubf == RUBY_UBF_PROCESS)) {
+ *unblock_function = ubf_select;
+ *data2 = thread;
+ return true;
+ }
+ return false;
+}
+
void *
rb_nogvl(void *(*func)(void *), void *data1,
rb_unblock_function_t *ubf, void *data2,
@@ -1542,7 +1599,7 @@ rb_nogvl(void *(*func)(void *), void *data1,
if (flags & RB_NOGVL_OFFLOAD_SAFE) {
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- struct rb_fiber_scheduler_blocking_operation_state state;
+ struct rb_fiber_scheduler_blocking_operation_state state = {0};
VALUE result = rb_fiber_scheduler_blocking_operation_wait(scheduler, func, data1, ubf, data2, flags, &state);
@@ -1560,11 +1617,9 @@ rb_nogvl(void *(*func)(void *), void *data1,
bool is_main_thread = vm->ractor.main_thread == th;
int saved_errno = 0;
- if ((ubf == RUBY_UBF_IO) || (ubf == RUBY_UBF_PROCESS)) {
- ubf = ubf_select;
- data2 = th;
- }
- else if (ubf && rb_ractor_living_thread_num(th->ractor) == 1 && is_main_thread) {
+ rb_thread_resolve_unblock_function(&ubf, &data2, th);
+
+ if (ubf && rb_ractor_living_thread_num(th->ractor) == 1 && is_main_thread) {
if (flags & RB_NOGVL_UBF_ASYNC_SAFE) {
vm->ubf_async_safe = 1;
}
@@ -1693,46 +1748,146 @@ waitfd_to_waiting_flag(int wfd_event)
return wfd_event << 1;
}
+static struct ccan_list_head *
+rb_io_blocking_operations(struct rb_io *io)
+{
+ rb_serial_t fork_generation = GET_VM()->fork_gen;
+
+ // On fork, all existing entries in this list (which are stack allocated) become invalid.
+ // Therefore, we re-initialize the list which clears it.
+ if (io->fork_generation != fork_generation) {
+ ccan_list_head_init(&io->blocking_operations);
+ io->fork_generation = fork_generation;
+ }
+
+ return &io->blocking_operations;
+}
+
+/*
+ * Registers a blocking operation for an IO object. This is used to track all threads and fibers
+ * that are currently blocked on this IO for reading, writing or other operations.
+ *
+ * When the IO is closed, all blocking operations will be notified via rb_fiber_scheduler_fiber_interrupt
+ * for fibers with a scheduler, or via rb_threadptr_interrupt for threads without a scheduler.
+ *
+ * @parameter io The IO object on which the operation will block
+ * @parameter blocking_operation The operation details including the execution context that will be blocked
+ */
static void
-thread_io_setup_wfd(rb_thread_t *th, int fd, struct waiting_fd *wfd)
+rb_io_blocking_operation_enter(struct rb_io *io, struct rb_io_blocking_operation *blocking_operation)
{
- wfd->fd = fd;
- wfd->th = th;
- wfd->busy = NULL;
+ ccan_list_add(rb_io_blocking_operations(io), &blocking_operation->list);
+}
- RB_VM_LOCK_ENTER();
- {
- ccan_list_add(&th->vm->waiting_fds, &wfd->wfd_node);
+static void
+rb_io_blocking_operation_pop(struct rb_io *io, struct rb_io_blocking_operation *blocking_operation)
+{
+ ccan_list_del(&blocking_operation->list);
+}
+
+struct io_blocking_operation_arguments {
+ struct rb_io *io;
+ struct rb_io_blocking_operation *blocking_operation;
+};
+
+static VALUE
+io_blocking_operation_exit(VALUE _arguments)
+{
+ struct io_blocking_operation_arguments *arguments = (void*)_arguments;
+ struct rb_io_blocking_operation *blocking_operation = arguments->blocking_operation;
+
+ rb_io_blocking_operation_pop(arguments->io, blocking_operation);
+
+ rb_io_t *io = arguments->io;
+ rb_thread_t *thread = io->closing_ec->thread_ptr;
+ rb_fiber_t *fiber = io->closing_ec->fiber_ptr;
+
+ if (thread->scheduler != Qnil) {
+ // This can cause spurious wakeups...
+ rb_fiber_scheduler_unblock(thread->scheduler, io->self, rb_fiberptr_self(fiber));
+ }
+ else {
+ rb_thread_wakeup(thread->self);
}
- RB_VM_LOCK_LEAVE();
+
+ return Qnil;
}
+/*
+ * Called when a blocking operation completes or is interrupted. Removes the operation from
+ * the IO's blocking_operations list and wakes up any waiting threads/fibers.
+ *
+ * If there's a wakeup_mutex (meaning an IO close is in progress), synchronizes the cleanup
+ * through that mutex to ensure proper coordination with the closing thread.
+ *
+ * @parameter io The IO object the operation was performed on
+ * @parameter blocking_operation The completed operation to clean up
+ */
static void
-thread_io_wake_pending_closer(struct waiting_fd *wfd)
-{
- bool has_waiter = wfd->busy && RB_TEST(wfd->busy->wakeup_mutex);
- if (has_waiter) {
- rb_mutex_lock(wfd->busy->wakeup_mutex);
- }
-
- /* Needs to be protected with RB_VM_LOCK because we don't know if
- wfd is on the global list of pending FD ops or if it's on a
- struct rb_io_close_wait_list close-waiter. */
- RB_VM_LOCK_ENTER();
- ccan_list_del(&wfd->wfd_node);
- RB_VM_LOCK_LEAVE();
-
- if (has_waiter) {
- rb_thread_t *th = rb_thread_ptr(wfd->busy->closing_thread);
- if (th->scheduler != Qnil) {
- rb_fiber_scheduler_unblock(th->scheduler, wfd->busy->closing_thread, wfd->busy->closing_fiber);
- } else {
- rb_thread_wakeup(wfd->busy->closing_thread);
- }
- rb_mutex_unlock(wfd->busy->wakeup_mutex);
+rb_io_blocking_operation_exit(struct rb_io *io, struct rb_io_blocking_operation *blocking_operation)
+{
+ VALUE wakeup_mutex = io->wakeup_mutex;
+
+ // Indicate that the blocking operation is no longer active:
+ blocking_operation->ec = NULL;
+
+ if (RB_TEST(wakeup_mutex)) {
+ struct io_blocking_operation_arguments arguments = {
+ .io = io,
+ .blocking_operation = blocking_operation
+ };
+
+ rb_mutex_synchronize(wakeup_mutex, io_blocking_operation_exit, (VALUE)&arguments);
+ }
+ else {
+ // If there's no wakeup_mutex, we can safely remove the operation directly:
+ rb_io_blocking_operation_pop(io, blocking_operation);
}
}
+static VALUE
+rb_thread_io_blocking_operation_ensure(VALUE _argument)
+{
+ struct io_blocking_operation_arguments *arguments = (void*)_argument;
+
+ rb_io_blocking_operation_exit(arguments->io, arguments->blocking_operation);
+
+ return Qnil;
+}
+
+/*
+ * Executes a function that performs a blocking IO operation, while properly tracking
+ * the operation in the IO's blocking_operations list. This ensures proper cleanup
+ * and interruption handling if the IO is closed while blocked.
+ *
+ * The operation is automatically removed from the blocking_operations list when the function
+ * returns, whether normally or due to an exception.
+ *
+ * @parameter self The IO object
+ * @parameter function The function to execute that will perform the blocking operation
+ * @parameter argument The argument to pass to the function
+ * @returns The result of the blocking operation function
+ */
+VALUE
+rb_thread_io_blocking_operation(VALUE self, VALUE(*function)(VALUE), VALUE argument)
+{
+ struct rb_io *io;
+ RB_IO_POINTER(self, io);
+
+ rb_execution_context_t *ec = GET_EC();
+ struct rb_io_blocking_operation blocking_operation = {
+ .ec = ec,
+ };
+ rb_io_blocking_operation_enter(io, &blocking_operation);
+
+ struct io_blocking_operation_arguments io_blocking_operation_arguments = {
+ .io = io,
+ .blocking_operation = &blocking_operation
+ };
+
+ return rb_ensure(function, argument, rb_thread_io_blocking_operation_ensure, (VALUE)&io_blocking_operation_arguments);
+}
+
static bool
thread_io_mn_schedulable(rb_thread_t *th, int events, const struct timeval *timeout)
{
@@ -1798,44 +1953,52 @@ rb_thread_mn_schedulable(VALUE thval)
}
VALUE
-rb_thread_io_blocking_call(rb_blocking_function_t *func, void *data1, int fd, int events)
+rb_thread_io_blocking_call(struct rb_io* io, rb_blocking_function_t *func, void *data1, int events)
{
- rb_execution_context_t *volatile ec = GET_EC();
- rb_thread_t *volatile th = rb_ec_thread_ptr(ec);
+ rb_execution_context_t * volatile ec = GET_EC();
+ rb_thread_t * volatile th = rb_ec_thread_ptr(ec);
- RUBY_DEBUG_LOG("th:%u fd:%d ev:%d", rb_th_serial(th), fd, events);
+ RUBY_DEBUG_LOG("th:%u fd:%d ev:%d", rb_th_serial(th), io->fd, events);
- struct waiting_fd waiting_fd;
volatile VALUE val = Qundef; /* shouldn't be used */
volatile int saved_errno = 0;
enum ruby_tag_type state;
volatile bool prev_mn_schedulable = th->mn_schedulable;
th->mn_schedulable = thread_io_mn_schedulable(th, events, NULL);
+ int fd = io->fd;
+
// `errno` is only valid when there is an actual error - but we can't
// extract that from the return value of `func` alone, so we clear any
// prior `errno` value here so that we can later check if it was set by
// `func` or not (as opposed to some previously set value).
errno = 0;
- thread_io_setup_wfd(th, fd, &waiting_fd);
+ struct rb_io_blocking_operation blocking_operation = {
+ .ec = ec,
+ };
+ rb_io_blocking_operation_enter(io, &blocking_operation);
+
{
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
volatile enum ruby_tag_type saved_state = state; /* for BLOCKING_REGION */
retry:
- BLOCKING_REGION(waiting_fd.th, {
+ BLOCKING_REGION(th, {
val = func(data1);
saved_errno = errno;
- }, ubf_select, waiting_fd.th, FALSE);
+ }, ubf_select, th, FALSE);
- th = rb_ec_thread_ptr(ec);
+ RUBY_ASSERT(th == rb_ec_thread_ptr(ec));
if (events &&
blocking_call_retryable_p((int)val, saved_errno) &&
thread_io_wait_events(th, fd, events, NULL)) {
RUBY_VM_CHECK_INTS_BLOCKING(ec);
goto retry;
}
+
+ RUBY_VM_CHECK_INTS_BLOCKING(ec);
+
state = saved_state;
}
EC_POP_TAG();
@@ -1843,17 +2006,12 @@ rb_thread_io_blocking_call(rb_blocking_function_t *func, void *data1, int fd, in
th = rb_ec_thread_ptr(ec);
th->mn_schedulable = prev_mn_schedulable;
}
- /*
- * must be deleted before jump
- * this will delete either from waiting_fds or on-stack struct rb_io_close_wait_list
- */
- thread_io_wake_pending_closer(&waiting_fd);
+
+ rb_io_blocking_operation_exit(io, &blocking_operation);
if (state) {
EC_JUMP_TAG(ec, state);
}
- /* TODO: check func() */
- RUBY_VM_CHECK_INTS_BLOCKING(ec);
// If the error was a timeout, we raise a specific exception for that:
if (saved_errno == ETIMEDOUT) {
@@ -1866,9 +2024,9 @@ rb_thread_io_blocking_call(rb_blocking_function_t *func, void *data1, int fd, in
}
VALUE
-rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
+rb_thread_io_blocking_region(struct rb_io *io, rb_blocking_function_t *func, void *data1)
{
- return rb_thread_io_blocking_call(func, data1, fd, 0);
+ return rb_thread_io_blocking_call(io, func, data1, 0);
}
/*
@@ -1898,6 +2056,9 @@ rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
* created as Ruby thread (created by Thread.new or so). In other
* words, this function *DOES NOT* associate or convert a NON-Ruby
* thread to a Ruby thread.
+ *
+ * NOTE: If this thread has already acquired the GVL, then the method call
+ * is performed without acquiring or releasing the GVL (from Ruby 4.0).
*/
void *
rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
@@ -1921,7 +2082,8 @@ rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
prev_unblock = th->unblock;
if (brb == 0) {
- rb_bug("rb_thread_call_with_gvl: called by a thread which has GVL.");
+ /* the GVL is already acquired, call method directly */
+ return (*func)(data1);
}
blocking_region_end(th, brb);
@@ -1931,17 +2093,12 @@ rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
int released = blocking_region_begin(th, brb, prev_unblock.func, prev_unblock.arg, FALSE);
RUBY_ASSERT_ALWAYS(released);
RB_VM_SAVE_MACHINE_CONTEXT(th);
- thread_sched_to_waiting(TH_SCHED(th), th);
+ thread_sched_to_waiting(TH_SCHED(th), th, true);
return r;
}
/*
* ruby_thread_has_gvl_p - check if current native thread has GVL.
- *
- ***
- *** This API is EXPERIMENTAL!
- *** We do not guarantee that this API remains in ruby 1.9.2 or later.
- ***
*/
int
@@ -2427,6 +2584,7 @@ NORETURN(static void rb_threadptr_to_kill(rb_thread_t *th));
static void
rb_threadptr_to_kill(rb_thread_t *th)
{
+ VM_ASSERT(GET_THREAD() == th);
rb_threadptr_pending_interrupt_clear(th);
th->status = THREAD_RUNNABLE;
th->to_kill = 1;
@@ -2441,8 +2599,9 @@ threadptr_get_interrupts(rb_thread_t *th)
rb_atomic_t interrupt;
rb_atomic_t old;
+ old = ATOMIC_LOAD_RELAXED(ec->interrupt_flag);
do {
- interrupt = ec->interrupt_flag;
+ interrupt = old;
old = ATOMIC_CAS(ec->interrupt_flag, interrupt, interrupt & ec->interrupt_mask);
} while (old != interrupt);
return interrupt & (rb_atomic_t)~ec->interrupt_mask;
@@ -2450,6 +2609,11 @@ threadptr_get_interrupts(rb_thread_t *th)
static void threadptr_interrupt_exec_exec(rb_thread_t *th);
+// Execute interrupts on currently running thread
+// In certain situations, calling this function will raise an exception. Some examples are:
+// * during VM shutdown (`rb_ractor_terminate_all`)
+// * Call to Thread#exit for current thread (`rb_thread_kill`)
+// * Call to Thread#raise for current thread
int
rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
{
@@ -2457,6 +2621,8 @@ rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
int postponed_job_interrupt = 0;
int ret = FALSE;
+ VM_ASSERT(GET_THREAD() == th);
+
if (th->ec->raised_flag) return ret;
while ((interrupt = threadptr_get_interrupts(th)) != 0) {
@@ -2473,8 +2639,7 @@ rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
terminate_interrupt = interrupt & TERMINATE_INTERRUPT_MASK; // request from other ractors
if (interrupt & VM_BARRIER_INTERRUPT_MASK) {
- RB_VM_LOCK_ENTER();
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING();
}
if (postponed_job_interrupt) {
@@ -2595,6 +2760,7 @@ rb_threadptr_raise(rb_thread_t *target_th, int argc, VALUE *argv)
rb_ec_setup_exception(GET_EC(), exc, Qundef);
rb_threadptr_pending_interrupt_enque(target_th, exc);
rb_threadptr_interrupt(target_th);
+
return Qnil;
}
@@ -2640,86 +2806,122 @@ rb_ec_reset_raised(rb_execution_context_t *ec)
return 1;
}
-int
-rb_notify_fd_close(int fd, struct rb_io_close_wait_list *busy)
+/*
+ * Thread-safe IO closing mechanism.
+ *
+ * When an IO is closed while other threads or fibers are blocked on it, we need to:
+ * 1. Track and notify all blocking operations through io->blocking_operations
+ * 2. Ensure only one thread can close at a time using io->closing_ec
+ * 3. Synchronize cleanup using wakeup_mutex
+ *
+ * The close process works as follows:
+ * - First check if any thread is already closing (io->closing_ec)
+ * - Set up wakeup_mutex for synchronization
+ * - Iterate through all blocking operations in io->blocking_operations
+ * - For each blocked fiber with a scheduler:
+ * - Notify via rb_fiber_scheduler_fiber_interrupt
+ * - For each blocked thread without a scheduler:
+ * - Enqueue IOError via rb_threadptr_pending_interrupt_enque
+ * - Wake via rb_threadptr_interrupt
+ * - Wait on wakeup_mutex until all operations are cleaned up
+ * - Only then clear closing state and allow actual close to proceed
+ */
+static VALUE
+thread_io_close_notify_all(VALUE _io)
{
- rb_vm_t *vm = GET_THREAD()->vm;
- struct waiting_fd *wfd = 0, *next;
- ccan_list_head_init(&busy->pending_fd_users);
- int has_any;
- VALUE wakeup_mutex;
+ struct rb_io *io = (struct rb_io *)_io;
- RB_VM_LOCK_ENTER();
- {
- ccan_list_for_each_safe(&vm->waiting_fds, wfd, next, wfd_node) {
- if (wfd->fd == fd) {
- rb_thread_t *th = wfd->th;
- VALUE err;
-
- ccan_list_del(&wfd->wfd_node);
- ccan_list_add(&busy->pending_fd_users, &wfd->wfd_node);
-
- wfd->busy = busy;
- err = th->vm->special_exceptions[ruby_error_stream_closed];
- rb_threadptr_pending_interrupt_enque(th, err);
- rb_threadptr_interrupt(th);
+ size_t count = 0;
+ rb_vm_t *vm = io->closing_ec->thread_ptr->vm;
+ VALUE error = vm->special_exceptions[ruby_error_stream_closed];
+
+ struct rb_io_blocking_operation *blocking_operation;
+ ccan_list_for_each(rb_io_blocking_operations(io), blocking_operation, list) {
+ rb_execution_context_t *ec = blocking_operation->ec;
+
+ // If the operation is in progress, we need to interrupt it:
+ if (ec) {
+ rb_thread_t *thread = ec->thread_ptr;
+
+ VALUE result = RUBY_Qundef;
+ if (thread->scheduler != Qnil) {
+ result = rb_fiber_scheduler_fiber_interrupt(thread->scheduler, rb_fiberptr_self(ec->fiber_ptr), error);
+ }
+
+ if (result == RUBY_Qundef) {
+ // If the thread is not the current thread, we need to enqueue an error:
+ rb_threadptr_pending_interrupt_enque(thread, error);
+ rb_threadptr_interrupt(thread);
}
}
+
+ count += 1;
}
- has_any = !ccan_list_empty(&busy->pending_fd_users);
- busy->closing_thread = rb_thread_current();
- busy->closing_fiber = rb_fiber_current();
- wakeup_mutex = Qnil;
- if (has_any) {
- wakeup_mutex = rb_mutex_new();
- RBASIC_CLEAR_CLASS(wakeup_mutex); /* hide from ObjectSpace */
+ return (VALUE)count;
+}
+
+size_t
+rb_thread_io_close_interrupt(struct rb_io *io)
+{
+ // We guard this operation based on `io->closing_ec` -> only one thread will ever enter this function.
+ if (io->closing_ec) {
+ return 0;
}
- busy->wakeup_mutex = wakeup_mutex;
- RB_VM_LOCK_LEAVE();
+ // If there are no blocking operations, we are done:
+ if (ccan_list_empty(rb_io_blocking_operations(io))) {
+ return 0;
+ }
+
+ // Otherwise, we are now closing the IO:
+ rb_execution_context_t *ec = GET_EC();
+ io->closing_ec = ec;
+
+ // This is used to ensure the correct execution context is woken up after the blocking operation is interrupted:
+ io->wakeup_mutex = rb_mutex_new();
+ rb_mutex_allow_trap(io->wakeup_mutex, 1);
- /* If the caller didn't pass *busy as a pointer to something on the stack,
- we need to guard this mutex object on _our_ C stack for the duration
- of this function. */
- RB_GC_GUARD(wakeup_mutex);
- return has_any;
+ // We need to use a mutex here as entering the fiber scheduler may cause a context switch:
+ VALUE result = rb_mutex_synchronize(io->wakeup_mutex, thread_io_close_notify_all, (VALUE)io);
+
+ return (size_t)result;
}
void
-rb_notify_fd_close_wait(struct rb_io_close_wait_list *busy)
+rb_thread_io_close_wait(struct rb_io* io)
{
- if (!RB_TEST(busy->wakeup_mutex)) {
- /* There was nobody else using this file when we closed it, so we
- never bothered to allocate a mutex*/
+ VALUE wakeup_mutex = io->wakeup_mutex;
+
+ if (!RB_TEST(wakeup_mutex)) {
+ // There was nobody else using this file when we closed it, so we never bothered to allocate a mutex:
return;
}
- rb_mutex_lock(busy->wakeup_mutex);
- while (!ccan_list_empty(&busy->pending_fd_users)) {
- rb_mutex_sleep(busy->wakeup_mutex, Qnil);
+ rb_mutex_lock(wakeup_mutex);
+ while (!ccan_list_empty(rb_io_blocking_operations(io))) {
+ rb_mutex_sleep(wakeup_mutex, Qnil);
}
- rb_mutex_unlock(busy->wakeup_mutex);
+ rb_mutex_unlock(wakeup_mutex);
+
+ // We are done closing:
+ io->wakeup_mutex = Qnil;
+ io->closing_ec = NULL;
}
void
rb_thread_fd_close(int fd)
{
- struct rb_io_close_wait_list busy;
-
- if (rb_notify_fd_close(fd, &busy)) {
- rb_notify_fd_close_wait(&busy);
- }
+ rb_warn("rb_thread_fd_close is deprecated (and is now a no-op).");
}
/*
* call-seq:
- * thr.raise
- * thr.raise(string)
- * thr.raise(exception [, string [, array]])
+ * raise(exception, message = exception.to_s, backtrace = nil, cause: $!)
+ * raise(message = nil, cause: $!)
*
* Raises an exception from the given thread. The caller does not have to be
- * +thr+. See Kernel#raise for more information.
+ * +thr+. See Kernel#raise for more information on arguments.
*
* Thread.abort_on_exception = true
* a = Thread.new { sleep(200) }
@@ -2740,7 +2942,14 @@ thread_raise_m(int argc, VALUE *argv, VALUE self)
const rb_thread_t *current_th = GET_THREAD();
threadptr_check_pending_interrupt_queue(target_th);
- rb_threadptr_raise(target_th, argc, argv);
+
+ if (rb_threadptr_dead(target_th)) {
+ return Qnil;
+ }
+
+ VALUE exception = rb_exception_setup(argc, argv);
+ rb_threadptr_pending_interrupt_enque(target_th, exception);
+ rb_threadptr_interrupt(target_th);
/* To perform Thread.current.raise as Kernel.raise */
if (current_th == target_th) {
@@ -2758,7 +2967,10 @@ thread_raise_m(int argc, VALUE *argv, VALUE self)
*
* Terminates +thr+ and schedules another thread to be run, returning
* the terminated Thread. If this is the main thread, or the last
- * thread, exits the process.
+ * thread, exits the process. Note that the caller does not wait for
+ * the thread to terminate if the receiver is different from the currently
+ * running thread. The termination is asynchronous, and the thread can still
+ * run a small amount of ruby code before exiting.
*/
VALUE
@@ -4055,13 +4267,20 @@ rb_fd_init(rb_fdset_t *fds)
FD_ZERO(fds->fdset);
}
+static inline size_t
+fdset_memsize(int maxfd)
+{
+ size_t o = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+ if (o < sizeof(fd_set)) {
+ return sizeof(fd_set);
+ }
+ return o;
+}
+
void
rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
{
- size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
-
- if (size < sizeof(fd_set))
- size = sizeof(fd_set);
+ size_t size = fdset_memsize(rb_fd_max(src));
dst->maxfd = src->maxfd;
dst->fdset = xmalloc(size);
memcpy(dst->fdset, src->fdset, size);
@@ -4070,7 +4289,7 @@ rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
void
rb_fd_term(rb_fdset_t *fds)
{
- xfree(fds->fdset);
+ ruby_xfree_sized(fds->fdset, fdset_memsize(fds->maxfd));
fds->maxfd = 0;
fds->fdset = 0;
}
@@ -4085,14 +4304,11 @@ rb_fd_zero(rb_fdset_t *fds)
static void
rb_fd_resize(int n, rb_fdset_t *fds)
{
- size_t m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
- size_t o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
-
- if (m < sizeof(fd_set)) m = sizeof(fd_set);
- if (o < sizeof(fd_set)) o = sizeof(fd_set);
+ size_t m = fdset_memsize(n + 1);
+ size_t o = fdset_memsize(fds->maxfd);
if (m > o) {
- fds->fdset = xrealloc(fds->fdset, m);
+ fds->fdset = ruby_xrealloc_sized(fds->fdset, m, o);
memset((char *)fds->fdset + o, 0, m - o);
}
if (n >= fds->maxfd) fds->maxfd = n + 1;
@@ -4122,23 +4338,18 @@ rb_fd_isset(int n, const rb_fdset_t *fds)
void
rb_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
{
- size_t size = howmany(max, NFDBITS) * sizeof(fd_mask);
-
- if (size < sizeof(fd_set)) size = sizeof(fd_set);
+ size_t size = fdset_memsize(max);
+ dst->fdset = ruby_xrealloc_sized(dst->fdset, size, fdset_memsize(dst->maxfd));
dst->maxfd = max;
- dst->fdset = xrealloc(dst->fdset, size);
memcpy(dst->fdset, src, size);
}
void
rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
{
- size_t size = howmany(rb_fd_max(src), NFDBITS) * sizeof(fd_mask);
-
- if (size < sizeof(fd_set))
- size = sizeof(fd_set);
+ size_t size = fdset_memsize(rb_fd_max(src));
+ dst->fdset = ruby_xrealloc_sized(dst->fdset, size, fdset_memsize(dst->maxfd));
dst->maxfd = src->maxfd;
- dst->fdset = xrealloc(dst->fdset, size);
memcpy(dst->fdset, src->fdset, size);
}
@@ -4190,10 +4401,19 @@ rb_fd_init_copy(rb_fdset_t *dst, rb_fdset_t *src)
rb_fd_dup(dst, src);
}
+static inline size_t
+fdset_memsize(int capa)
+{
+ if (capa == FD_SETSIZE) {
+ return sizeof(fd_set);
+ }
+ return sizeof(unsigned int) + (capa * sizeof(SOCKET));
+}
+
void
rb_fd_term(rb_fdset_t *set)
{
- xfree(set->fdset);
+ ruby_xfree_sized(set->fdset, fdset_memsize(set->capa));
set->fdset = NULL;
set->capa = 0;
}
@@ -4323,6 +4543,8 @@ do_select(VALUE p)
RUBY_VM_CHECK_INTS_BLOCKING(set->th->ec); /* may raise */
} while (wait_retryable(&result, lerrno, to, endtime) && do_select_update());
+ RUBY_VM_CHECK_INTS_BLOCKING(set->th->ec);
+
if (result < 0) {
errno = lerrno;
}
@@ -4403,8 +4625,8 @@ wait_for_single_fd_blocking_region(rb_thread_t *th, struct pollfd *fds, nfds_t n
/*
* returns a mask of events
*/
-int
-rb_thread_wait_for_single_fd(int fd, int events, struct timeval *timeout)
+static int
+thread_io_wait(rb_thread_t *th, struct rb_io *io, int fd, int events, struct timeval *timeout)
{
struct pollfd fds[1] = {{
.fd = fd,
@@ -4413,14 +4635,17 @@ rb_thread_wait_for_single_fd(int fd, int events, struct timeval *timeout)
}};
volatile int result = 0;
nfds_t nfds;
- struct waiting_fd wfd;
+ struct rb_io_blocking_operation blocking_operation;
enum ruby_tag_type state;
volatile int lerrno;
- rb_execution_context_t *ec = GET_EC();
- rb_thread_t *th = rb_ec_thread_ptr(ec);
+ RUBY_ASSERT(th);
+ rb_execution_context_t *ec = th->ec;
- thread_io_setup_wfd(th, fd, &wfd);
+ if (io) {
+ blocking_operation.ec = ec;
+ rb_io_blocking_operation_enter(io, &blocking_operation);
+ }
if (timeout == NULL && thread_io_wait_events(th, fd, events, NULL)) {
// fd is readable
@@ -4429,25 +4654,30 @@ rb_thread_wait_for_single_fd(int fd, int events, struct timeval *timeout)
errno = 0;
}
else {
- EC_PUSH_TAG(wfd.th->ec);
+ EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
rb_hrtime_t *to, rel, end = 0;
- RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec);
+ RUBY_VM_CHECK_INTS_BLOCKING(ec);
timeout_prepare(&to, &rel, &end, timeout);
do {
nfds = numberof(fds);
- result = wait_for_single_fd_blocking_region(wfd.th, fds, nfds, to, &lerrno);
+ result = wait_for_single_fd_blocking_region(th, fds, nfds, to, &lerrno);
- RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec);
+ RUBY_VM_CHECK_INTS_BLOCKING(ec);
} while (wait_retryable(&result, lerrno, to, end));
+
+ RUBY_VM_CHECK_INTS_BLOCKING(ec);
}
+
EC_POP_TAG();
}
- thread_io_wake_pending_closer(&wfd);
+ if (io) {
+ rb_io_blocking_operation_exit(io, &blocking_operation);
+ }
if (state) {
- EC_JUMP_TAG(wfd.th->ec, state);
+ EC_JUMP_TAG(ec, state);
}
if (result < 0) {
@@ -4480,6 +4710,9 @@ rb_thread_wait_for_single_fd(int fd, int events, struct timeval *timeout)
}
#else /* ! USE_POLL - implement rb_io_poll_fd() using select() */
struct select_args {
+ struct rb_io *io;
+ struct rb_io_blocking_operation *blocking_operation;
+
union {
int fd;
int error;
@@ -4487,7 +4720,6 @@ struct select_args {
rb_fdset_t *read;
rb_fdset_t *write;
rb_fdset_t *except;
- struct waiting_fd wfd;
struct timeval *tv;
};
@@ -4518,7 +4750,10 @@ select_single_cleanup(VALUE ptr)
{
struct select_args *args = (struct select_args *)ptr;
- thread_io_wake_pending_closer(&args->wfd);
+ if (args->blocking_operation) {
+ rb_io_blocking_operation_exit(args->io, args->blocking_operation);
+ }
+
if (args->read) rb_fd_term(args->read);
if (args->write) rb_fd_term(args->write);
if (args->except) rb_fd_term(args->except);
@@ -4538,31 +4773,52 @@ init_set_fd(int fd, rb_fdset_t *fds)
return fds;
}
-int
-rb_thread_wait_for_single_fd(int fd, int events, struct timeval *timeout)
+static int
+thread_io_wait(rb_thread_t *th, struct rb_io *io, int fd, int events, struct timeval *timeout)
{
rb_fdset_t rfds, wfds, efds;
struct select_args args;
- int r;
VALUE ptr = (VALUE)&args;
- rb_execution_context_t *ec = GET_EC();
- rb_thread_t *th = rb_ec_thread_ptr(ec);
+
+ struct rb_io_blocking_operation blocking_operation;
+ if (io) {
+ args.io = io;
+ blocking_operation.ec = th->ec;
+ rb_io_blocking_operation_enter(io, &blocking_operation);
+ args.blocking_operation = &blocking_operation;
+ }
+ else {
+ args.io = NULL;
+ blocking_operation.ec = NULL;
+ args.blocking_operation = NULL;
+ }
args.as.fd = fd;
args.read = (events & RB_WAITFD_IN) ? init_set_fd(fd, &rfds) : NULL;
args.write = (events & RB_WAITFD_OUT) ? init_set_fd(fd, &wfds) : NULL;
args.except = (events & RB_WAITFD_PRI) ? init_set_fd(fd, &efds) : NULL;
args.tv = timeout;
- thread_io_setup_wfd(th, fd, &args.wfd);
- r = (int)rb_ensure(select_single, ptr, select_single_cleanup, ptr);
- if (r == -1)
+ int result = (int)rb_ensure(select_single, ptr, select_single_cleanup, ptr);
+ if (result == -1)
errno = args.as.error;
- return r;
+ return result;
}
#endif /* ! USE_POLL */
+int
+rb_thread_wait_for_single_fd(rb_thread_t *th, int fd, int events, struct timeval *timeout)
+{
+ return thread_io_wait(th, NULL, fd, events, timeout);
+}
+
+int
+rb_thread_io_wait(rb_thread_t *th, struct rb_io *io, int events, struct timeval * timeout)
+{
+ return thread_io_wait(th, io, io->fd, events, timeout);
+}
+
/*
* for GC
*/
@@ -4573,7 +4829,7 @@ rb_gc_set_stack_end(VALUE **stack_end_p)
{
VALUE stack_end;
COMPILER_WARNING_PUSH
-#if __has_warning("-Wdangling-pointer")
+#if RBIMPL_COMPILER_IS(GCC)
COMPILER_WARNING_IGNORED(-Wdangling-pointer);
#endif
*stack_end_p = &stack_end;
@@ -4727,9 +4983,13 @@ rb_thread_atfork_internal(rb_thread_t *th, void (*atfork)(rb_thread_t *, const r
thread_sched_atfork(TH_SCHED(th));
ubf_list_atfork();
+ rb_signal_atfork();
// OK. Only this thread accesses:
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
+ if (r != vm->ractor.main_ractor) {
+ rb_ractor_terminate_atfork(vm, r);
+ }
ccan_list_for_each(&r->threads.set, i, lt_node) {
atfork(i, th);
}
@@ -4759,6 +5019,9 @@ static void
terminate_atfork_i(rb_thread_t *th, const rb_thread_t *current_th)
{
if (th != current_th) {
+ // Clear the scheduler as it is no longer operational:
+ th->scheduler = Qnil;
+
rb_native_mutex_initialize(&th->interrupt_lock);
rb_mutex_abandon_keeping_mutexes(th);
rb_mutex_abandon_locking_mutex(th);
@@ -4774,6 +5037,7 @@ rb_thread_atfork(void)
rb_threadptr_pending_interrupt_clear(th);
rb_thread_atfork_internal(th, terminate_atfork_i);
th->join_list = NULL;
+ th->scheduler = Qnil;
rb_fiber_atfork(th);
/* We don't want reproduce CVE-2003-0900. */
@@ -5043,7 +5307,7 @@ rb_thread_shield_owned(VALUE self)
rb_mutex_t *m = mutex_ptr(mutex);
- return m->fiber == GET_EC()->fiber_ptr;
+ return m->ec_serial == rb_ec_serial(GET_EC());
}
/*
@@ -5062,7 +5326,7 @@ rb_thread_shield_wait(VALUE self)
if (!mutex) return Qfalse;
m = mutex_ptr(mutex);
- if (m->fiber == GET_EC()->fiber_ptr) return Qnil;
+ if (m->ec_serial == rb_ec_serial(GET_EC())) return Qnil;
rb_thread_shield_waiting_inc(self);
rb_mutex_lock(mutex);
rb_thread_shield_waiting_dec(self);
@@ -5579,8 +5843,8 @@ debug_deadlock_check(rb_ractor_t *r, VALUE msg)
if (th->locking_mutex) {
rb_mutex_t *mutex = mutex_ptr(th->locking_mutex);
- rb_str_catf(msg, " mutex:%p cond:%"PRIuSIZE,
- (void *)mutex->fiber, rb_mutex_num_waiting(mutex));
+ rb_str_catf(msg, " mutex:%llu cond:%"PRIuSIZE,
+ (unsigned long long)mutex->ec_serial, rb_mutex_num_waiting(mutex));
}
{
@@ -5620,7 +5884,7 @@ rb_check_deadlock(rb_ractor_t *r)
}
else if (th->locking_mutex) {
rb_mutex_t *mutex = mutex_ptr(th->locking_mutex);
- if (mutex->fiber == th->ec->fiber_ptr || (!mutex->fiber && !ccan_list_empty(&mutex->waitq))) {
+ if (mutex->ec_serial == rb_ec_serial(th->ec) || (!mutex->ec_serial && !ccan_list_empty(&mutex->waitq))) {
found = 1;
}
}
@@ -5638,35 +5902,21 @@ rb_check_deadlock(rb_ractor_t *r)
}
}
-// Used for VM memsize reporting. Returns the size of a list of waiting_fd
-// structs. Defined here because the struct definition lives here as well.
-size_t
-rb_vm_memsize_waiting_fds(struct ccan_list_head *waiting_fds)
-{
- struct waiting_fd *waitfd = 0;
- size_t size = 0;
-
- ccan_list_for_each(waiting_fds, waitfd, wfd_node) {
- size += sizeof(struct waiting_fd);
- }
-
- return size;
-}
-
static void
update_line_coverage(VALUE data, const rb_trace_arg_t *trace_arg)
{
const rb_control_frame_t *cfp = GET_EC()->cfp;
- VALUE coverage = rb_iseq_coverage(cfp->iseq);
+ VALUE coverage = rb_iseq_coverage(CFP_ISEQ(cfp));
if (RB_TYPE_P(coverage, T_ARRAY) && !RBASIC_CLASS(coverage)) {
VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES);
if (lines) {
long line = rb_sourceline() - 1;
+ VM_ASSERT(line >= 0);
long count;
VALUE num;
void rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset);
if (GET_VM()->coverage_mode & COVERAGE_TARGET_ONESHOT_LINES) {
- rb_iseq_clear_event_flags(cfp->iseq, cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded - 1, RUBY_EVENT_COVERAGE_LINE);
+ rb_iseq_clear_event_flags(CFP_ISEQ(cfp), CFP_PC(cfp) - ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded - 1, RUBY_EVENT_COVERAGE_LINE);
rb_ary_push(lines, LONG2FIX(line + 1));
return;
}
@@ -5687,12 +5937,12 @@ static void
update_branch_coverage(VALUE data, const rb_trace_arg_t *trace_arg)
{
const rb_control_frame_t *cfp = GET_EC()->cfp;
- VALUE coverage = rb_iseq_coverage(cfp->iseq);
+ VALUE coverage = rb_iseq_coverage(CFP_ISEQ(cfp));
if (RB_TYPE_P(coverage, T_ARRAY) && !RBASIC_CLASS(coverage)) {
VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES);
if (branches) {
- long pc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded - 1;
- long idx = FIX2INT(RARRAY_AREF(ISEQ_PC2BRANCHINDEX(cfp->iseq), pc)), count;
+ long pc = CFP_PC(cfp) - ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded - 1;
+ long idx = FIX2INT(RARRAY_AREF(ISEQ_PC2BRANCHINDEX(CFP_ISEQ(cfp)), pc)), count;
VALUE counters = RARRAY_AREF(branches, 1);
VALUE num = RARRAY_AREF(counters, idx);
count = FIX2LONG(num) + 1;
@@ -6013,7 +6263,7 @@ rb_threadptr_interrupt_exec(rb_thread_t *th, rb_interrupt_exec_func_t *func, voi
rb_native_mutex_lock(&th->interrupt_lock);
{
ccan_list_add_tail(&th->interrupt_exec_tasks, &task->node);
- threadptr_interrupt_locked(th, true);
+ threadptr_set_interrupt_locked(th, true);
}
rb_native_mutex_unlock(&th->interrupt_lock);
}
@@ -6030,9 +6280,16 @@ threadptr_interrupt_exec_exec(rb_thread_t *th)
}
rb_native_mutex_unlock(&th->interrupt_lock);
+ RUBY_DEBUG_LOG("task:%p", task);
+
if (task) {
- (*task->func)(task->data);
- ruby_xfree(task);
+ if (task->flags & rb_interrupt_exec_flag_new_thread) {
+ rb_thread_create(task->func, task->data);
+ }
+ else {
+ (*task->func)(task->data);
+ }
+ SIZED_FREE(task);
}
else {
break;
@@ -6048,46 +6305,21 @@ threadptr_interrupt_exec_cleanup(rb_thread_t *th)
struct rb_interrupt_exec_task *task;
while ((task = ccan_list_pop(&th->interrupt_exec_tasks, struct rb_interrupt_exec_task, node)) != NULL) {
- ruby_xfree(task);
+ SIZED_FREE(task);
}
}
rb_native_mutex_unlock(&th->interrupt_lock);
}
-struct interrupt_ractor_new_thread_data {
- rb_interrupt_exec_func_t *func;
- void *data;
-};
-
-static VALUE
-interrupt_ractor_new_thread_func(void *data)
-{
- struct interrupt_ractor_new_thread_data d = *(struct interrupt_ractor_new_thread_data *)data;
- ruby_xfree(data);
-
- d.func(d.data);
- return Qnil;
-}
-
-static VALUE
-interrupt_ractor_func(void *data)
-{
- rb_thread_create(interrupt_ractor_new_thread_func, data);
- return Qnil;
-}
-
// native thread safe
// func/data should be native thread safe
void
rb_ractor_interrupt_exec(struct rb_ractor_struct *target_r,
rb_interrupt_exec_func_t *func, void *data, enum rb_interrupt_exec_flag flags)
{
- struct interrupt_ractor_new_thread_data *d = ALLOC(struct interrupt_ractor_new_thread_data);
+ RUBY_DEBUG_LOG("flags:%d", (int)flags);
- d->func = func;
- d->data = data;
rb_thread_t *main_th = target_r->threads.main;
- rb_threadptr_interrupt_exec(main_th, interrupt_ractor_func, d, flags);
-
- // TODO MEMO: we can create a new thread in a ractor, but not sure how to do that now.
+ rb_threadptr_interrupt_exec(main_th, func, data, flags | rb_interrupt_exec_flag_new_thread);
}
+
diff --git a/thread_none.c b/thread_none.c
index 8d32aaabee..cb844148e1 100644
--- a/thread_none.c
+++ b/thread_none.c
@@ -26,11 +26,11 @@ thread_sched_to_running(struct rb_thread_sched *sched, rb_thread_t *th)
}
static void
-thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th)
+thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th, bool yield_immediately)
{
}
-#define thread_sched_to_dead thread_sched_to_waiting
+#define thread_sched_to_dead(a,b) thread_sched_to_waiting(a,b,true)
static void
thread_sched_yield(struct rb_thread_sched *sched, rb_thread_t *th)
@@ -137,6 +137,12 @@ ruby_mn_threads_params(void)
{
}
+static void
+native_thread_destroy_atfork(struct rb_native_thread *nt)
+{
+ /* no-op */
+}
+
static int
native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame)
{
@@ -276,7 +282,8 @@ th_has_dedicated_nt(const rb_thread_t *th)
}
void
-rb_add_running_thread(rb_thread_t *th){
+rb_add_running_thread(rb_thread_t *th)
+{
// do nothing
}
@@ -328,4 +335,10 @@ rb_thread_prevent_fork(void *(*func)(void *), void *data)
return func(data);
}
+void
+rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size)
+{
+ // no-op
+}
+
#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
diff --git a/thread_pthread.c b/thread_pthread.c
index 993437f02b..6e3ce8ef87 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -90,9 +90,16 @@ static const void *const condattr_monotonic = NULL;
#endif
#endif
+#ifdef HAVE_SCHED_YIELD
+#define native_thread_yield() (void)sched_yield()
+#else
+#define native_thread_yield() ((void)0)
+#endif
+
// native thread wrappers
#define NATIVE_MUTEX_LOCK_DEBUG 0
+#define NATIVE_MUTEX_LOCK_DEBUG_YIELD 0
static void
mutex_debug(const char *msg, void *lock)
@@ -111,6 +118,9 @@ void
rb_native_mutex_lock(pthread_mutex_t *lock)
{
int r;
+#if NATIVE_MUTEX_LOCK_DEBUG_YIELD
+ native_thread_yield();
+#endif
mutex_debug("lock", lock);
if ((r = pthread_mutex_lock(lock)) != 0) {
rb_bug_errno("pthread_mutex_lock", r);
@@ -310,12 +320,6 @@ static rb_serial_t current_fork_gen = 1; /* We can't use GET_VM()->fork_gen */
static void threadptr_trap_interrupt(rb_thread_t *);
-#ifdef HAVE_SCHED_YIELD
-#define native_thread_yield() (void)sched_yield()
-#else
-#define native_thread_yield() ((void)0)
-#endif
-
static void native_thread_dedicated_inc(rb_vm_t *vm, rb_ractor_t *cr, struct rb_native_thread *nt);
static void native_thread_dedicated_dec(rb_vm_t *vm, rb_ractor_t *cr, struct rb_native_thread *nt);
static void native_thread_assign(struct rb_native_thread *nt, rb_thread_t *th);
@@ -374,40 +378,47 @@ ractor_sched_dump_(const char *file, int line, rb_vm_t *vm)
#define thread_sched_unlock(a, b) thread_sched_unlock_(a, b, __FILE__, __LINE__)
static void
-thread_sched_lock_(struct rb_thread_sched *sched, rb_thread_t *th, const char *file, int line)
+thread_sched_set_locked(struct rb_thread_sched *sched, rb_thread_t *th)
{
- rb_native_mutex_lock(&sched->lock_);
-
-#if VM_CHECK_MODE
- RUBY_DEBUG_LOG2(file, line, "th:%u prev_owner:%u", rb_th_serial(th), rb_th_serial(sched->lock_owner));
+#if VM_CHECK_MODE > 0
VM_ASSERT(sched->lock_owner == NULL);
+
sched->lock_owner = th;
-#else
- RUBY_DEBUG_LOG2(file, line, "th:%u", rb_th_serial(th));
#endif
}
static void
-thread_sched_unlock_(struct rb_thread_sched *sched, rb_thread_t *th, const char *file, int line)
+thread_sched_set_unlocked(struct rb_thread_sched *sched, rb_thread_t *th)
{
- RUBY_DEBUG_LOG2(file, line, "th:%u", rb_th_serial(th));
-
-#if VM_CHECK_MODE
+#if VM_CHECK_MODE > 0
VM_ASSERT(sched->lock_owner == th);
+
sched->lock_owner = NULL;
#endif
-
- rb_native_mutex_unlock(&sched->lock_);
}
static void
-thread_sched_set_lock_owner(struct rb_thread_sched *sched, rb_thread_t *th)
+thread_sched_lock_(struct rb_thread_sched *sched, rb_thread_t *th, const char *file, int line)
{
- RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
+ rb_native_mutex_lock(&sched->lock_);
-#if VM_CHECK_MODE > 0
- sched->lock_owner = th;
+#if VM_CHECK_MODE
+ RUBY_DEBUG_LOG2(file, line, "r:%d th:%u", th ? (int)rb_ractor_id(th->ractor) : -1, rb_th_serial(th));
+#else
+ RUBY_DEBUG_LOG2(file, line, "th:%u", rb_th_serial(th));
#endif
+
+ thread_sched_set_locked(sched, th);
+}
+
+static void
+thread_sched_unlock_(struct rb_thread_sched *sched, rb_thread_t *th, const char *file, int line)
+{
+ RUBY_DEBUG_LOG2(file, line, "th:%u", rb_th_serial(th));
+
+ thread_sched_set_unlocked(sched, th);
+
+ rb_native_mutex_unlock(&sched->lock_);
}
static void
@@ -430,7 +441,8 @@ ASSERT_thread_sched_locked(struct rb_thread_sched *sched, rb_thread_t *th)
RBIMPL_ATTR_MAYBE_UNUSED()
static unsigned int
-rb_ractor_serial(const rb_ractor_t *r) {
+rb_ractor_serial(const rb_ractor_t *r)
+{
if (r) {
return rb_ractor_id(r);
}
@@ -541,7 +553,6 @@ ractor_sched_timeslice_threads_contain_p(rb_vm_t *vm, rb_thread_t *th)
}
static void ractor_sched_barrier_join_signal_locked(rb_vm_t *vm);
-static void ractor_sched_barrier_join_wait_locked(rb_vm_t *vm, rb_thread_t *th);
// setup timeslice signals by the timer thread.
static void
@@ -584,11 +595,10 @@ thread_sched_setup_running_threads(struct rb_thread_sched *sched, rb_ractor_t *c
}
if (add_th) {
- while (UNLIKELY(vm->ractor.sched.barrier_waiting)) {
- RUBY_DEBUG_LOG("barrier-wait");
-
- ractor_sched_barrier_join_signal_locked(vm);
- ractor_sched_barrier_join_wait_locked(vm, add_th);
+ if (vm->ractor.sched.barrier_waiting) {
+ // TODO: GC barrier check?
+ RUBY_DEBUG_LOG("barrier_waiting");
+ RUBY_VM_SET_VM_BARRIER_INTERRUPT(add_th->ec);
}
VM_ASSERT(!ractor_sched_running_threads_contain_p(vm, add_th));
@@ -597,7 +607,6 @@ thread_sched_setup_running_threads(struct rb_thread_sched *sched, rb_ractor_t *c
ccan_list_add(&vm->ractor.sched.running_threads, &add_th->sched.node.running_threads);
vm->ractor.sched.running_cnt++;
sched->is_running = true;
- VM_ASSERT(!vm->ractor.sched.barrier_waiting);
}
if (add_timeslice_th) {
@@ -621,20 +630,6 @@ thread_sched_setup_running_threads(struct rb_thread_sched *sched, rb_ractor_t *c
}
ractor_sched_unlock(vm, cr);
- if (add_th && !del_th && UNLIKELY(vm->ractor.sync.lock_owner != NULL)) {
- // it can be after barrier synchronization by another ractor
- rb_thread_t *lock_owner = NULL;
-#if VM_CHECK_MODE
- lock_owner = sched->lock_owner;
-#endif
- thread_sched_unlock(sched, lock_owner);
- {
- RB_VM_LOCK_ENTER();
- RB_VM_LOCK_LEAVE();
- }
- thread_sched_lock(sched, lock_owner);
- }
-
//RUBY_DEBUG_LOG("+:%u -:%u +ts:%u -ts:%u run:%u->%u",
// rb_th_serial(add_th), rb_th_serial(del_th),
// rb_th_serial(add_timeslice_th), rb_th_serial(del_timeslice_th),
@@ -703,8 +698,12 @@ thread_sched_readyq_contain_p(struct rb_thread_sched *sched, rb_thread_t *th)
{
rb_thread_t *rth;
ccan_list_for_each(&sched->readyq, rth, sched.node.readyq) {
- if (rth == th) return true;
+ if (rth == th) {
+ VM_ASSERT(th->sched.node.is_ready);
+ return true;
+ }
}
+ VM_ASSERT(!th->sched.node.is_ready);
return false;
}
@@ -725,6 +724,8 @@ thread_sched_deq(struct rb_thread_sched *sched)
}
else {
next_th = ccan_list_pop(&sched->readyq, rb_thread_t, sched.node.readyq);
+ VM_ASSERT(next_th->sched.node.is_ready);
+ next_th->sched.node.is_ready = false;
VM_ASSERT(sched->readyq_cnt > 0);
sched->readyq_cnt--;
@@ -753,10 +754,12 @@ thread_sched_enq(struct rb_thread_sched *sched, rb_thread_t *ready_th)
}
}
else {
- VM_ASSERT(!ractor_sched_timeslice_threads_contain_p(ready_th->vm, sched->running));
+ // ractor_sched lock is needed
+ // VM_ASSERT(!ractor_sched_timeslice_threads_contain_p(ready_th->vm, sched->running));
}
ccan_list_add_tail(&sched->readyq, &ready_th->sched.node.readyq);
+ ready_th->sched.node.is_ready = true;
sched->readyq_cnt++;
}
@@ -840,6 +843,30 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
VM_ASSERT(th == rb_ec_thread_ptr(rb_current_ec_noinline()));
if (th != sched->running) {
+ // TODO: This optimization should also be made to work for MN_THREADS
+ if (th->has_dedicated_nt && th == sched->runnable_hot_th && (sched->running == NULL || sched->running->has_dedicated_nt)) {
+ RUBY_DEBUG_LOG("(nt) stealing: hot-th:%u. running:%u", rb_th_serial(th), rb_th_serial(sched->running));
+
+ // If there is a thread set to run, move it back to the front of the readyq
+ if (sched->running != NULL) {
+ rb_thread_t *running = sched->running;
+ VM_ASSERT(!thread_sched_readyq_contain_p(sched, running));
+ running->sched.node.is_ready = true;
+ ccan_list_add(&sched->readyq, &running->sched.node.readyq);
+ sched->readyq_cnt++;
+ }
+
+ // Pull off the ready queue and start running.
+ if (th->sched.node.is_ready) {
+ VM_ASSERT(thread_sched_readyq_contain_p(sched, th));
+ ccan_list_del_init(&th->sched.node.readyq);
+ th->sched.node.is_ready = false;
+ sched->readyq_cnt--;
+ }
+ thread_sched_set_running(sched, th);
+ rb_ractor_thread_switch(th->ractor, th, false);
+ }
+
// already deleted from running threads
// VM_ASSERT(!ractor_sched_running_threads_contain_p(th->vm, th)); // need locking
@@ -849,16 +876,25 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
if (th_has_dedicated_nt(th)) {
RUBY_DEBUG_LOG("(nt) sleep th:%u running:%u", rb_th_serial(th), rb_th_serial(sched->running));
- thread_sched_set_lock_owner(sched, NULL);
+ thread_sched_set_unlocked(sched, th);
{
RUBY_DEBUG_LOG("nt:%d cond:%p", th->nt->serial, &th->nt->cond.readyq);
rb_native_cond_wait(&th->nt->cond.readyq, &sched->lock_);
}
- thread_sched_set_lock_owner(sched, th);
+ thread_sched_set_locked(sched, th);
+
+ if (sched->runnable_hot_th != NULL && sched->runnable_hot_th_waiting) {
+ VM_ASSERT(sched->runnable_hot_th != th);
+ // Give the hot thread a chance to preempt, if it's actively spinning.
+ // On multicore, this reduces the rate of core-switching. On single-core it
+ // should mostly be a nop, since the other thread can't be concurrently spinning.
+ thread_sched_unlock(sched, th);
+ thread_sched_lock(sched, th);
+ }
RUBY_DEBUG_LOG("(nt) wakeup %s", sched->running == th ? "success" : "failed");
if (th == sched->running) {
- rb_ractor_thread_switch(th->ractor, th);
+ rb_ractor_thread_switch(th->ractor, th, false);
}
}
else {
@@ -870,12 +906,12 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
RUBY_DEBUG_LOG("th:%u->%u (direct)", rb_th_serial(th), rb_th_serial(next_th));
- thread_sched_set_lock_owner(sched, NULL);
+ thread_sched_set_unlocked(sched, th);
{
rb_ractor_set_current_ec(th->ractor, NULL);
thread_sched_switch(th, next_th);
}
- thread_sched_set_lock_owner(sched, th);
+ thread_sched_set_locked(sched, th);
}
else {
// search another ready ractor
@@ -884,12 +920,12 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
RUBY_DEBUG_LOG("th:%u->%u (ractor scheduling)", rb_th_serial(th), rb_th_serial(next_th));
- thread_sched_set_lock_owner(sched, NULL);
+ thread_sched_set_unlocked(sched, th);
{
rb_ractor_set_current_ec(th->ractor, NULL);
coroutine_transfer0(th->sched.context, nt->nt_context, false);
}
- thread_sched_set_lock_owner(sched, th);
+ thread_sched_set_locked(sched, th);
}
VM_ASSERT(rb_current_ec_noinline() == th->ec);
@@ -904,6 +940,11 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
thread_sched_add_running_thread(sched, th);
}
+ // Control transfer to the current thread is now complete. The original thread
+ // cannot steal control at this point.
+ sched->runnable_hot_th = NULL;
+ sched->runnable_hot_th_waiting = 0;
+
// VM_ASSERT(ractor_sched_running_threads_contain_p(th->vm, th)); need locking
RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_RESUMED, th);
}
@@ -940,6 +981,13 @@ thread_sched_to_running_common(struct rb_thread_sched *sched, rb_thread_t *th)
static void
thread_sched_to_running(struct rb_thread_sched *sched, rb_thread_t *th)
{
+ // We are reading and writing these sched fields without lock cover, but
+ // there are no correctness issues resulting from stale cache or delayed writeback.
+ // When it works, this causes the next-scheduled thread to yield the sched lock
+ // briefly so that we can grab it if we're still spinning (not descheduled yet).
+ if (sched->runnable_hot_th == th) {
+ sched->runnable_hot_th_waiting = 1;
+ }
thread_sched_lock(sched, th);
{
thread_sched_to_running_common(sched, th);
@@ -976,33 +1024,16 @@ thread_sched_wakeup_next_thread(struct rb_thread_sched *sched, rb_thread_t *th,
}
}
-// running -> waiting
-//
-// to_dead: false
-// th will run dedicated task.
-// run another ready thread.
-// to_dead: true
-// th will be dead.
-// run another ready thread.
+// running -> dead (locked)
static void
-thread_sched_to_waiting_common0(struct rb_thread_sched *sched, rb_thread_t *th, bool to_dead)
+thread_sched_to_dead_common(struct rb_thread_sched *sched, rb_thread_t *th)
{
- RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
+ RUBY_DEBUG_LOG("th:%u DNT:%d", rb_th_serial(th), th->nt->dedicated);
- if (!to_dead) native_thread_dedicated_inc(th->vm, th->ractor, th->nt);
-
- RUBY_DEBUG_LOG("%sth:%u", to_dead ? "to_dead " : "", rb_th_serial(th));
+ RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
- bool can_switch = to_dead ? !th_has_dedicated_nt(th) : false;
- thread_sched_wakeup_next_thread(sched, th, can_switch);
-}
+ thread_sched_wakeup_next_thread(sched, th, !th_has_dedicated_nt(th));
-// running -> dead (locked)
-static void
-thread_sched_to_dead_common(struct rb_thread_sched *sched, rb_thread_t *th)
-{
- RUBY_DEBUG_LOG("dedicated:%d", th->nt->dedicated);
- thread_sched_to_waiting_common0(sched, th, true);
RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_EXITED, th);
}
@@ -1021,33 +1052,76 @@ thread_sched_to_dead(struct rb_thread_sched *sched, rb_thread_t *th)
//
// This thread will run dedicated task (th->nt->dedicated++).
static void
-thread_sched_to_waiting_common(struct rb_thread_sched *sched, rb_thread_t *th)
+thread_sched_to_waiting_common(struct rb_thread_sched *sched, rb_thread_t *th, bool yield_immediately)
{
- RUBY_DEBUG_LOG("dedicated:%d", th->nt->dedicated);
- thread_sched_to_waiting_common0(sched, th, false);
+ RUBY_DEBUG_LOG("th:%u DNT:%d", rb_th_serial(th), th->nt->dedicated);
+
+ RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
+
+ native_thread_dedicated_inc(th->vm, th->ractor, th->nt);
+ if (!yield_immediately) {
+ sched->runnable_hot_th = th;
+ sched->runnable_hot_th_waiting = 0;
+ }
+ thread_sched_wakeup_next_thread(sched, th, false);
}
// running -> waiting
//
// This thread will run a dedicated task.
static void
-thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th)
+thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th, bool yield_immediately)
{
thread_sched_lock(sched, th);
{
- thread_sched_to_waiting_common(sched, th);
+ thread_sched_to_waiting_common(sched, th, yield_immediately);
}
thread_sched_unlock(sched, th);
}
// mini utility func
-static void
-setup_ubf(rb_thread_t *th, rb_unblock_function_t *func, void *arg)
+// return true if any there are any interrupts
+static bool
+ubf_set(rb_thread_t *th, rb_unblock_function_t *func, void *arg, rb_atomic_t *event_serial)
{
+ VM_ASSERT(func != NULL);
+
+ retry:
+ if (RUBY_VM_INTERRUPTED(th->ec)) {
+ RUBY_DEBUG_LOG("interrupted:0x%x", th->ec->interrupt_flag);
+ return true;
+ }
+
rb_native_mutex_lock(&th->interrupt_lock);
{
+ if (!th->ec->raised_flag && RUBY_VM_INTERRUPTED(th->ec)) {
+ rb_native_mutex_unlock(&th->interrupt_lock);
+ goto retry;
+ }
+
+ VM_ASSERT(th->unblock.func == NULL);
th->unblock.func = func;
th->unblock.arg = arg;
+ if (event_serial) {
+ rb_atomic_t prev_serial = RUBY_ATOMIC_FETCH_ADD(th->unblock.event_serial, 1);
+ *event_serial = prev_serial+1;
+ }
+ }
+ rb_native_mutex_unlock(&th->interrupt_lock);
+
+ return false;
+}
+
+static void
+ubf_clear(rb_thread_t *th, bool clear_serial)
+{
+ rb_native_mutex_lock(&th->interrupt_lock);
+ {
+ th->unblock.func = NULL;
+ th->unblock.arg = NULL;
+ if (clear_serial) {
+ RUBY_ATOMIC_ADD(th->unblock.event_serial, 1);
+ }
}
rb_native_mutex_unlock(&th->interrupt_lock);
}
@@ -1085,24 +1159,26 @@ thread_sched_to_waiting_until_wakeup(struct rb_thread_sched *sched, rb_thread_t
RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
RB_VM_SAVE_MACHINE_CONTEXT(th);
- setup_ubf(th, ubf_waiting, (void *)th);
+
RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
thread_sched_lock(sched, th);
{
- if (!RUBY_VM_INTERRUPTED(th->ec)) {
+ // NOTE: there's a lock ordering inversion here with the ubf call, but it's benign.
+ if (ubf_set(th, ubf_waiting, (void *)th, NULL)) {
+ RUBY_DEBUG_LOG("th:%u interrupted", rb_th_serial(th));
+ }
+ else {
bool can_direct_transfer = !th_has_dedicated_nt(th);
+ // NOTE: th->status is set before and after this sleep outside of this function in `sleep_forever`
thread_sched_wakeup_next_thread(sched, th, can_direct_transfer);
thread_sched_wait_running_turn(sched, th, can_direct_transfer);
}
- else {
- RUBY_DEBUG_LOG("th:%u interrupted", rb_th_serial(th));
- }
}
thread_sched_unlock(sched, th);
- setup_ubf(th, NULL, NULL);
+ ubf_clear(th, false);
}
// run another thread in the ready queue.
@@ -1120,6 +1196,7 @@ thread_sched_yield(struct rb_thread_sched *sched, rb_thread_t *th)
bool can_direct_transfer = !th_has_dedicated_nt(th);
thread_sched_to_ready_common(sched, th, false, can_direct_transfer);
thread_sched_wait_running_turn(sched, th, can_direct_transfer);
+ th->status = THREAD_RUNNABLE;
}
else {
VM_ASSERT(sched->readyq_cnt == 0);
@@ -1308,62 +1385,57 @@ ractor_sched_deq(rb_vm_t *vm, rb_ractor_t *cr)
void rb_ractor_lock_self(rb_ractor_t *r);
void rb_ractor_unlock_self(rb_ractor_t *r);
+// The current thread for a ractor is put to "sleep" (descheduled in the STOPPED_FOREVER state) waiting for
+// a ractor action to wake it up.
void
-rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf)
+rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf, void *ubf_arg)
{
// ractor lock of cr is acquired
- // r is sleeping status
+
+ RUBY_DEBUG_LOG("start%s", "");
+
rb_thread_t * volatile th = rb_ec_thread_ptr(ec);
struct rb_thread_sched *sched = TH_SCHED(th);
- cr->sync.wait.waiting_thread = th; // TODO: multi-thread
+ struct ractor_waiter *waiter = (struct ractor_waiter*)ubf_arg;
- setup_ubf(th, ubf, (void *)cr);
+ if (ubf_set(th, ubf, ubf_arg, &waiter->event_serial)) {
+ // interrupted
+ return;
+ }
thread_sched_lock(sched, th);
+ rb_ractor_unlock_self(cr);
{
- rb_ractor_unlock_self(cr);
- {
- if (RUBY_VM_INTERRUPTED(th->ec)) {
- RUBY_DEBUG_LOG("interrupted");
- }
- else if (cr->sync.wait.wakeup_status != wakeup_none) {
- RUBY_DEBUG_LOG("awaken:%d", (int)cr->sync.wait.wakeup_status);
- }
- else {
- // sleep
- RB_VM_SAVE_MACHINE_CONTEXT(th);
- th->status = THREAD_STOPPED_FOREVER;
-
- RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
-
- bool can_direct_transfer = !th_has_dedicated_nt(th);
- thread_sched_wakeup_next_thread(sched, th, can_direct_transfer);
- thread_sched_wait_running_turn(sched, th, can_direct_transfer);
- th->status = THREAD_RUNNABLE;
- // wakeup
- }
- }
+ // setup sleep
+ bool can_direct_transfer = !th_has_dedicated_nt(th);
+ RB_VM_SAVE_MACHINE_CONTEXT(th);
+ th->status = THREAD_STOPPED_FOREVER;
+ RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
+ thread_sched_wakeup_next_thread(sched, th, can_direct_transfer);
+ // sleep
+ thread_sched_wait_running_turn(sched, th, can_direct_transfer);
+ th->status = THREAD_RUNNABLE;
}
thread_sched_unlock(sched, th);
+ rb_ractor_lock_self(cr);
- setup_ubf(th, NULL, NULL);
+ ubf_clear(th, true);
- rb_ractor_lock_self(cr);
- cr->sync.wait.waiting_thread = NULL;
+ RUBY_DEBUG_LOG("end%s", "");
}
void
-rb_ractor_sched_wakeup(rb_ractor_t *r)
+rb_ractor_sched_wakeup(rb_ractor_t *r, rb_thread_t *r_th)
{
- rb_thread_t *r_th = r->sync.wait.waiting_thread;
- // ractor lock of r is acquired
+ // ractor lock of r acquired
struct rb_thread_sched *sched = TH_SCHED(r_th);
- VM_ASSERT(r->sync.wait.wakeup_status != 0);
+ RUBY_DEBUG_LOG("r:%u th:%d", (unsigned int)rb_ractor_id(r), r_th->serial);
thread_sched_lock(sched, r_th);
{
if (r_th->status == THREAD_STOPPED_FOREVER) {
+ RUBY_ATOMIC_ADD(r_th->unblock.event_serial, 1);
thread_sched_to_ready_common(sched, r_th, true, false);
}
}
@@ -1375,6 +1447,7 @@ ractor_sched_barrier_completed_p(rb_vm_t *vm)
{
RUBY_DEBUG_LOG("run:%u wait:%u", vm->ractor.sched.running_cnt, vm->ractor.sched.barrier_waiting_cnt);
VM_ASSERT(vm->ractor.sched.running_cnt - 1 >= vm->ractor.sched.barrier_waiting_cnt);
+
return (vm->ractor.sched.running_cnt - vm->ractor.sched.barrier_waiting_cnt) == 1;
}
@@ -1385,6 +1458,8 @@ rb_ractor_sched_barrier_start(rb_vm_t *vm, rb_ractor_t *cr)
VM_ASSERT(vm->ractor.sync.lock_owner == cr); // VM is locked
VM_ASSERT(!vm->ractor.sched.barrier_waiting);
VM_ASSERT(vm->ractor.sched.barrier_waiting_cnt == 0);
+ VM_ASSERT(vm->ractor.sched.barrier_ractor == NULL);
+ VM_ASSERT(vm->ractor.sched.barrier_lock_rec == 0);
RUBY_DEBUG_LOG("start serial:%u", vm->ractor.sched.barrier_serial);
@@ -1393,46 +1468,60 @@ rb_ractor_sched_barrier_start(rb_vm_t *vm, rb_ractor_t *cr)
ractor_sched_lock(vm, cr);
{
vm->ractor.sched.barrier_waiting = true;
+ vm->ractor.sched.barrier_ractor = cr;
+ vm->ractor.sched.barrier_lock_rec = vm->ractor.sync.lock_rec;
// release VM lock
lock_rec = vm->ractor.sync.lock_rec;
vm->ractor.sync.lock_rec = 0;
vm->ractor.sync.lock_owner = NULL;
rb_native_mutex_unlock(&vm->ractor.sync.lock);
- {
- // interrupts all running threads
- rb_thread_t *ith;
- ccan_list_for_each(&vm->ractor.sched.running_threads, ith, sched.node.running_threads) {
- if (ith->ractor != cr) {
- RUBY_DEBUG_LOG("barrier int:%u", rb_th_serial(ith));
- RUBY_VM_SET_VM_BARRIER_INTERRUPT(ith->ec);
- }
- }
- // wait for other ractors
- while (!ractor_sched_barrier_completed_p(vm)) {
- ractor_sched_set_unlocked(vm, cr);
- rb_native_cond_wait(&vm->ractor.sched.barrier_complete_cond, &vm->ractor.sched.lock);
- ractor_sched_set_locked(vm, cr);
+ // interrupts all running threads
+ rb_thread_t *ith;
+ ccan_list_for_each(&vm->ractor.sched.running_threads, ith, sched.node.running_threads) {
+ if (ith->ractor != cr) {
+ RUBY_DEBUG_LOG("barrier request to th:%u", rb_th_serial(ith));
+ RUBY_VM_SET_VM_BARRIER_INTERRUPT(ith->ec);
}
}
- }
- ractor_sched_unlock(vm, cr);
- // acquire VM lock
- rb_native_mutex_lock(&vm->ractor.sync.lock);
- vm->ractor.sync.lock_rec = lock_rec;
- vm->ractor.sync.lock_owner = cr;
+ // wait for other ractors
+ while (!ractor_sched_barrier_completed_p(vm)) {
+ ractor_sched_set_unlocked(vm, cr);
+ rb_native_cond_wait(&vm->ractor.sched.barrier_complete_cond, &vm->ractor.sched.lock);
+ ractor_sched_set_locked(vm, cr);
+ }
- RUBY_DEBUG_LOG("completed seirial:%u", vm->ractor.sched.barrier_serial);
+ RUBY_DEBUG_LOG("completed seirial:%u", vm->ractor.sched.barrier_serial);
- ractor_sched_lock(vm, cr);
- {
- vm->ractor.sched.barrier_waiting = false;
+ // no other ractors are there
vm->ractor.sched.barrier_serial++;
vm->ractor.sched.barrier_waiting_cnt = 0;
rb_native_cond_broadcast(&vm->ractor.sched.barrier_release_cond);
+
+ // acquire VM lock
+ rb_native_mutex_lock(&vm->ractor.sync.lock);
+ vm->ractor.sync.lock_rec = lock_rec;
+ vm->ractor.sync.lock_owner = cr;
}
+
+ // do not release ractor_sched_lock and there is no newly added (resumed) thread
+ // thread_sched_setup_running_threads
+}
+
+// called from vm_lock_leave if the vm_lock used for barrierred
+void
+rb_ractor_sched_barrier_end(rb_vm_t *vm, rb_ractor_t *cr)
+{
+ RUBY_DEBUG_LOG("serial:%u", (unsigned int)vm->ractor.sched.barrier_serial - 1);
+ VM_ASSERT(vm->ractor.sched.barrier_waiting);
+ VM_ASSERT(vm->ractor.sched.barrier_ractor);
+ VM_ASSERT(vm->ractor.sched.barrier_lock_rec > 0);
+
+ vm->ractor.sched.barrier_waiting = false;
+ vm->ractor.sched.barrier_ractor = NULL;
+ vm->ractor.sched.barrier_lock_rec = 0;
ractor_sched_unlock(vm, cr);
}
@@ -1532,6 +1621,8 @@ get_native_thread_id(void)
#endif
#if defined(HAVE_WORKING_FORK)
+void rb_internal_thread_event_hooks_rw_lock_atfork(void);
+
static void
thread_sched_atfork(struct rb_thread_sched *sched)
{
@@ -1563,6 +1654,8 @@ thread_sched_atfork(struct rb_thread_sched *sched)
ccan_list_head_init(&vm->ractor.sched.timeslice_threads);
ccan_list_head_init(&vm->ractor.sched.running_threads);
+ rb_internal_thread_event_hooks_rw_lock_atfork();
+
VM_ASSERT(sched->is_running);
sched->is_running_timeslice = false;
@@ -1779,6 +1872,27 @@ native_thread_assign(struct rb_native_thread *nt, rb_thread_t *th)
}
static void
+native_thread_destroy_atfork(struct rb_native_thread *nt)
+{
+ if (nt) {
+ /* We can't call rb_native_cond_destroy here because according to the
+ * specs of pthread_cond_destroy:
+ *
+ * Attempting to destroy a condition variable upon which other threads
+ * are currently blocked results in undefined behavior.
+ *
+ * Specifically, glibc's pthread_cond_destroy waits on all the other
+ * listeners. Since after forking all the threads are dead, the condition
+ * variable's listeners will never wake up, so it will hang forever.
+ */
+
+ RB_ALTSTACK_FREE(nt->altstack);
+ SIZED_FREE(nt->nt_context);
+ SIZED_FREE(nt);
+ }
+}
+
+static void
native_thread_destroy(struct rb_native_thread *nt)
{
if (nt) {
@@ -1788,9 +1902,7 @@ native_thread_destroy(struct rb_native_thread *nt)
rb_native_cond_destroy(&nt->cond.intr);
}
- RB_ALTSTACK_FREE(nt->altstack);
- ruby_xfree(nt->nt_context);
- ruby_xfree(nt);
+ native_thread_destroy_atfork(nt);
}
}
@@ -2154,7 +2266,7 @@ native_thread_create_dedicated(rb_thread_t *th)
th->sched.malloc_stack = true;
rb_ec_initialize_vm_stack(th->ec, vm_stack, vm_stack_word_size);
th->sched.context_stack = vm_stack;
-
+ th->sched.context_stack_size = vm_stack_word_size;
int err = native_thread_create0(th->nt);
if (!err) {
@@ -2279,11 +2391,9 @@ rb_threadptr_remove(rb_thread_t *th)
rb_vm_t *vm = th->vm;
th->sched.finished = false;
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
ccan_list_add(&vm->ractor.sched.zombie_threads, &th->sched.node.zombie_threads);
}
- RB_VM_LOCK_LEAVE();
}
#endif
}
@@ -2294,7 +2404,7 @@ rb_threadptr_sched_free(rb_thread_t *th)
#if USE_MN_THREADS
if (th->sched.malloc_stack) {
// has dedicated
- ruby_xfree(th->sched.context_stack);
+ SIZED_FREE_N((VALUE *)th->sched.context_stack, th->sched.context_stack_size);
native_thread_destroy(th->nt);
}
else {
@@ -2302,11 +2412,11 @@ rb_threadptr_sched_free(rb_thread_t *th)
// TODO: how to free nt and nt->altstack?
}
- ruby_xfree(th->sched.context);
+ SIZED_FREE(th->sched.context);
th->sched.context = NULL;
// VM_ASSERT(th->sched.context == NULL);
#else
- ruby_xfree(th->sched.context_stack);
+ SIZED_FREE_N((VALUE *)th->sched.context_stack, th->sched.context_stack_size);
native_thread_destroy(th->nt);
#endif
@@ -2536,16 +2646,14 @@ ubf_threads_empty(void)
static void
ubf_wakeup_all_threads(void)
{
- if (!ubf_threads_empty()) {
- rb_thread_t *th;
- rb_native_mutex_lock(&ubf_list_lock);
- {
- ccan_list_for_each(&ubf_list_head, th, sched.node.ubf) {
- ubf_wakeup_thread(th);
- }
+ rb_thread_t *th;
+ rb_native_mutex_lock(&ubf_list_lock);
+ {
+ ccan_list_for_each(&ubf_list_head, th, sched.node.ubf) {
+ ubf_wakeup_thread(th);
}
- rb_native_mutex_unlock(&ubf_list_lock);
}
+ rb_native_mutex_unlock(&ubf_list_lock);
}
#else /* USE_UBF_LIST */
@@ -2570,7 +2678,7 @@ rb_thread_wakeup_timer_thread(int sig)
timer_thread_wakeup_force();
// interrupt main thread if main thread is available
- if (system_working) {
+ if (RUBY_ATOMIC_LOAD(system_working)) {
rb_vm_t *vm = GET_VM();
rb_thread_t *main_th = vm->ractor.main_thread;
@@ -2814,7 +2922,7 @@ static struct {
static void timer_thread_check_timeslice(rb_vm_t *vm);
static int timer_thread_set_timeout(rb_vm_t *vm);
-static void timer_thread_wakeup_thread(rb_thread_t *th);
+static void timer_thread_wakeup_thread(rb_thread_t *th, uint32_t event_serial);
#include "thread_pthread_mn.c"
@@ -2858,24 +2966,29 @@ timer_thread_set_timeout(rb_vm_t *vm)
}
ractor_sched_unlock(vm, NULL);
- if (vm->ractor.sched.timeslice_wait_inf) {
- rb_native_mutex_lock(&timer_th.waiting_lock);
- {
- struct rb_thread_sched_waiting *w = ccan_list_top(&timer_th.waiting, struct rb_thread_sched_waiting, node);
- rb_thread_t *th = thread_sched_waiting_thread(w);
+ // Always check waiting threads to find minimum timeout
+ // even when scheduler has work (grq_cnt > 0)
+ rb_native_mutex_lock(&timer_th.waiting_lock);
+ {
+ struct rb_thread_sched_waiting *w = ccan_list_top(&timer_th.waiting, struct rb_thread_sched_waiting, node);
+ rb_thread_t *th = thread_sched_waiting_thread(w);
- if (th && (th->sched.waiting_reason.flags & thread_sched_waiting_timeout)) {
- rb_hrtime_t now = rb_hrtime_now();
- rb_hrtime_t hrrel = rb_hrtime_sub(th->sched.waiting_reason.data.timeout, now);
+ if (th && (th->sched.waiting_reason.flags & thread_sched_waiting_timeout)) {
+ rb_hrtime_t now = rb_hrtime_now();
+ rb_hrtime_t hrrel = rb_hrtime_sub(th->sched.waiting_reason.data.timeout, now);
- RUBY_DEBUG_LOG("th:%u now:%lu rel:%lu", rb_th_serial(th), (unsigned long)now, (unsigned long)hrrel);
+ RUBY_DEBUG_LOG("th:%u now:%lu rel:%lu", rb_th_serial(th), (unsigned long)now, (unsigned long)hrrel);
- // TODO: overflow?
- timeout = (int)((hrrel + RB_HRTIME_PER_MSEC - 1) / RB_HRTIME_PER_MSEC); // ms
+ // TODO: overflow?
+ int thread_timeout = (int)((hrrel + RB_HRTIME_PER_MSEC - 1) / RB_HRTIME_PER_MSEC); // ms
+
+ // Use minimum of scheduler timeout and thread sleep timeout
+ if (timeout < 0 || thread_timeout < timeout) {
+ timeout = thread_timeout;
}
}
- rb_native_mutex_unlock(&timer_th.waiting_lock);
}
+ rb_native_mutex_unlock(&timer_th.waiting_lock);
RUBY_DEBUG_LOG("timeout:%d inf:%d", timeout, (int)vm->ractor.sched.timeslice_wait_inf);
@@ -2899,19 +3012,11 @@ timer_thread_check_signal(rb_vm_t *vm)
static bool
timer_thread_check_exceed(rb_hrtime_t abs, rb_hrtime_t now)
{
- if (abs < now) {
- return true;
- }
- else if (abs - now < RB_HRTIME_PER_MSEC) {
- return true; // too short time
- }
- else {
- return false;
- }
+ return abs <= now;
}
static rb_thread_t *
-timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now)
+timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now, uint32_t *event_serial)
{
struct rb_thread_sched_waiting *w = ccan_list_top(&timer_th.waiting, struct rb_thread_sched_waiting, node);
@@ -2928,26 +3033,31 @@ timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now)
w->flags = thread_sched_waiting_none;
w->data.result = 0;
- return thread_sched_waiting_thread(w);
+ rb_thread_t *th = thread_sched_waiting_thread(w);
+ *event_serial = w->data.event_serial;
+ return th;
}
return NULL;
}
static void
-timer_thread_wakeup_thread(rb_thread_t *th)
+timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th, uint32_t event_serial)
+{
+ if (sched->running != th && th->sched.event_serial == event_serial) {
+ thread_sched_to_ready_common(sched, th, true, false);
+ }
+}
+
+static void
+timer_thread_wakeup_thread(rb_thread_t *th, uint32_t event_serial)
{
RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
struct rb_thread_sched *sched = TH_SCHED(th);
thread_sched_lock(sched, th);
{
- if (sched->running != th) {
- thread_sched_to_ready_common(sched, th, true, false);
- }
- else {
- // will be release the execution right
- }
+ timer_thread_wakeup_thread_locked(sched, th, event_serial);
}
thread_sched_unlock(sched, th);
}
@@ -2957,11 +3067,14 @@ timer_thread_check_timeout(rb_vm_t *vm)
{
rb_hrtime_t now = rb_hrtime_now();
rb_thread_t *th;
+ uint32_t event_serial;
rb_native_mutex_lock(&timer_th.waiting_lock);
{
- while ((th = timer_thread_deq_wakeup(vm, now)) != NULL) {
- timer_thread_wakeup_thread(th);
+ while ((th = timer_thread_deq_wakeup(vm, now, &event_serial)) != NULL) {
+ rb_native_mutex_unlock(&timer_th.waiting_lock);
+ timer_thread_wakeup_thread(th, event_serial);
+ rb_native_mutex_lock(&timer_th.waiting_lock);
}
}
rb_native_mutex_unlock(&timer_th.waiting_lock);
@@ -3001,12 +3114,12 @@ timer_thread_func(void *ptr)
RUBY_DEBUG_LOG("started%s", "");
- while (system_working) {
+ while (RUBY_ATOMIC_LOAD(system_working)) {
timer_thread_check_signal(vm);
timer_thread_check_timeout(vm);
ubf_wakeup_all_threads();
- RUBY_DEBUG_LOG("system_working:%d", system_working);
+ RUBY_DEBUG_LOG("system_working:%d", RUBY_ATOMIC_LOAD(system_working));
timer_thread_polling(vm);
}
@@ -3120,18 +3233,16 @@ rb_thread_create_timer_thread(void)
static int
native_stop_timer_thread(void)
{
- int stopped;
- stopped = --system_working <= 0;
+ RUBY_ATOMIC_SET(system_working, 0);
- if (stopped) {
- RUBY_DEBUG_LOG("wakeup send %d", timer_th.comm_fds[1]);
- timer_thread_wakeup_force();
- RUBY_DEBUG_LOG("wakeup sent");
- pthread_join(timer_th.pthread_id, NULL);
- }
+ RUBY_DEBUG_LOG("wakeup send %d", timer_th.comm_fds[1]);
+ timer_thread_wakeup_force();
+ RUBY_DEBUG_LOG("wakeup sent");
+ pthread_join(timer_th.pthread_id, NULL);
if (TT_DEBUG) fprintf(stderr, "stop timer thread\n");
- return stopped;
+
+ return 1;
}
static void
@@ -3149,8 +3260,12 @@ ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr)
const size_t water_mark = 1024 * 1024;
STACK_GROW_DIR_DETECTION;
+ if (th) {
+ size = th->ec->machine.stack_maxsize;
+ base = (char *)th->ec->machine.stack_start - STACK_DIR_UPPER(0, size);
+ }
#ifdef STACKADDR_AVAILABLE
- if (get_stack(&base, &size) == 0) {
+ else if (get_stack(&base, &size) == 0) {
# ifdef __APPLE__
if (pthread_equal(th->nt->thread_id, native_main_thread.id)) {
struct rlimit rlim;
@@ -3161,15 +3276,11 @@ ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr)
# endif
base = (char *)base + STACK_DIR_UPPER(+size, -size);
}
- else
#endif
- if (th) {
- size = th->ec->machine.stack_maxsize;
- base = (char *)th->ec->machine.stack_start - STACK_DIR_UPPER(0, size);
- }
else {
return 0;
}
+
size /= RUBY_STACK_SPACE_RATIO;
if (size > water_mark) size = water_mark;
if (IS_STACK_DIR_UPPER()) {
@@ -3348,6 +3459,22 @@ struct rb_internal_thread_event_hook {
static pthread_rwlock_t rb_internal_thread_event_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER;
+#if defined(HAVE_WORKING_FORK)
+void
+rb_internal_thread_event_hooks_rw_lock_atfork(void)
+{
+ // After fork(), this rwlock may have been held by a now-dead thread.
+ //
+ // pthread_rwlock_destroy() on a held lock is undefined behavior, and
+ // pthread_rwlock_init() on an already-initialized lock is also undefined
+ // behavior
+ //
+ // Direct assignment of PTHREAD_RWLOCK_INITIALIZER is safe and portable.
+ rb_internal_thread_event_hooks_rw_lock =
+ (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
+}
+#endif
+
rb_internal_thread_event_hook_t *
rb_internal_thread_add_event_hook(rb_internal_thread_event_callback callback, rb_event_flag_t internal_event, void *user_data)
{
@@ -3401,7 +3528,7 @@ rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook)
}
if (success) {
- ruby_xfree(hook);
+ SIZED_FREE(hook);
}
return success;
}
@@ -3442,4 +3569,12 @@ rb_thread_lock_native_thread(void)
return is_snt;
}
+void
+rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size)
+{
+ th->sched.malloc_stack = true;
+ th->sched.context_stack = stack;
+ th->sched.context_stack_size = stack_size;
+}
+
#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
diff --git a/thread_pthread.h b/thread_pthread.h
index b632668a2a..36f2273d5b 100644
--- a/thread_pthread.h
+++ b/thread_pthread.h
@@ -17,6 +17,11 @@
#define RB_NATIVETHREAD_LOCK_INIT PTHREAD_MUTEX_INITIALIZER
#define RB_NATIVETHREAD_COND_INIT PTHREAD_COND_INITIALIZER
+// TLS can not be accessed across .so on arm64 and perhaps ppc64le too.
+#if defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__)
+# define RB_THREAD_CURRENT_EC_NOINLINE
+#endif
+
// this data should be protected by timer_th.waiting_lock
struct rb_thread_sched_waiting {
enum thread_sched_waiting_flag {
@@ -34,6 +39,7 @@ struct rb_thread_sched_waiting {
#else
uint64_t timeout;
#endif
+ uint32_t event_serial;
int fd; // -1 for timeout only
int result;
} data;
@@ -42,7 +48,7 @@ struct rb_thread_sched_waiting {
struct ccan_list_node node;
};
-// per-Thead scheduler helper data
+// per-Thread scheduler helper data
struct rb_thread_sched_item {
struct {
struct ccan_list_node ubf;
@@ -50,6 +56,9 @@ struct rb_thread_sched_item {
// connected to ractor->threads.sched.reqdyq
// locked by ractor->threads.sched.lock
struct ccan_list_node readyq;
+ // Indicates whether thread is on the readyq.
+ // There is no clear relationship between this and th->status.
+ bool is_ready;
// connected to vm->ractor.sched.timeslice_threads
// locked by vm->ractor.sched.lock
@@ -64,10 +73,12 @@ struct rb_thread_sched_item {
} node;
struct rb_thread_sched_waiting waiting_reason;
+ uint32_t event_serial;
bool finished;
bool malloc_stack;
void *context_stack;
+ size_t context_stack_size;
struct coroutine_context *context;
};
@@ -120,6 +131,11 @@ struct rb_thread_sched {
struct rb_thread_struct *lock_owner;
#endif
struct rb_thread_struct *running; // running thread or NULL
+ // Most recently running thread or NULL. If this thread wakes up before the newly running
+ // thread completes the transfer of control, it can interrupt and resume running.
+ // The new thread clears this field when it takes control.
+ struct rb_thread_struct *runnable_hot_th;
+ int runnable_hot_th_waiting;
bool is_running;
bool is_running_timeslice;
bool enable_mn_threads;
@@ -133,8 +149,7 @@ struct rb_thread_sched {
#ifdef RB_THREAD_LOCAL_SPECIFIER
NOINLINE(void rb_current_ec_set(struct rb_execution_context_struct *));
- # if defined(__arm64__) || defined(__aarch64__)
- // on Arm64, TLS can not be accessed across .so
+ # ifdef RB_THREAD_CURRENT_EC_NOINLINE
NOINLINE(struct rb_execution_context_struct *rb_current_ec(void));
# else
RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER struct rb_execution_context_struct *ruby_current_ec;
@@ -164,4 +179,8 @@ native_tls_set(native_tls_key_t key, void *ptr)
RUBY_EXTERN native_tls_key_t ruby_current_ec_key;
#endif
+struct rb_ractor_struct;
+void rb_ractor_sched_wait(struct rb_execution_context_struct *ec, struct rb_ractor_struct *cr, rb_unblock_function_t *ubf, void *ptr);
+void rb_ractor_sched_wakeup(struct rb_ractor_struct *r, struct rb_thread_struct *th);
+
#endif /* RUBY_THREAD_PTHREAD_H */
diff --git a/thread_pthread_mn.c b/thread_pthread_mn.c
index cc0dae3b70..c9e6649832 100644
--- a/thread_pthread_mn.c
+++ b/thread_pthread_mn.c
@@ -3,26 +3,23 @@
#if USE_MN_THREADS
static void timer_thread_unregister_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags);
+static void timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th, uint32_t event_serial);
static bool
timer_thread_cancel_waiting(rb_thread_t *th)
{
bool canceled = false;
- if (th->sched.waiting_reason.flags) {
- rb_native_mutex_lock(&timer_th.waiting_lock);
- {
- if (th->sched.waiting_reason.flags) {
- canceled = true;
- ccan_list_del_init(&th->sched.waiting_reason.node);
- if (th->sched.waiting_reason.flags & (thread_sched_waiting_io_read | thread_sched_waiting_io_write)) {
- timer_thread_unregister_waiting(th, th->sched.waiting_reason.data.fd, th->sched.waiting_reason.flags);
- }
- th->sched.waiting_reason.flags = thread_sched_waiting_none;
- }
+ rb_native_mutex_lock(&timer_th.waiting_lock);
+ {
+ if (th->sched.waiting_reason.flags) {
+ canceled = true;
+ ccan_list_del_init(&th->sched.waiting_reason.node);
+ timer_thread_unregister_waiting(th, th->sched.waiting_reason.data.fd, th->sched.waiting_reason.flags);
+ th->sched.waiting_reason.flags = thread_sched_waiting_none;
}
- rb_native_mutex_unlock(&timer_th.waiting_lock);
}
+ rb_native_mutex_unlock(&timer_th.waiting_lock);
return canceled;
}
@@ -41,10 +38,10 @@ ubf_event_waiting(void *ptr)
th->unblock.func = NULL;
th->unblock.arg = NULL;
- bool canceled = timer_thread_cancel_waiting(th);
-
thread_sched_lock(sched, th);
{
+ bool canceled = timer_thread_cancel_waiting(th);
+
if (sched->running == th) {
RUBY_DEBUG_LOG("not waiting yet");
}
@@ -58,7 +55,7 @@ ubf_event_waiting(void *ptr)
thread_sched_unlock(sched, th);
}
-static bool timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel);
+static bool timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel, uint32_t event_serial);
// return true if timed out
static bool
@@ -68,20 +65,30 @@ thread_sched_wait_events(struct rb_thread_sched *sched, rb_thread_t *th, int fd,
volatile bool timedout = false, need_cancel = false;
- if (timer_thread_register_waiting(th, fd, events, rel)) {
- RUBY_DEBUG_LOG("wait fd:%d", fd);
+ uint32_t event_serial = ++th->sched.event_serial; // overflow is okay
- RB_VM_SAVE_MACHINE_CONTEXT(th);
- setup_ubf(th, ubf_event_waiting, (void *)th);
- RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
+ thread_sched_lock(sched, th);
+ {
+ // NOTE: there's a lock ordering inversion here with the ubf call, but it's benign.
+ if (ubf_set(th, ubf_event_waiting, (void *)th, NULL)) {
+ thread_sched_unlock(sched, th);
+ return false;
+ }
+
+ if (timer_thread_register_waiting(th, fd, events, rel, event_serial)) {
+ RUBY_DEBUG_LOG("wait fd:%d", fd);
+
+ RB_VM_SAVE_MACHINE_CONTEXT(th);
+
+ RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
- thread_sched_lock(sched, th);
- {
if (th->sched.waiting_reason.flags == thread_sched_waiting_none) {
- // already awaken
+ th->sched.event_serial++;
+ // timer thread has dequeued us already, but it won't try to wake us because we bumped our serial
}
else if (RUBY_VM_INTERRUPTED(th->ec)) {
+ th->sched.event_serial++; // make sure timer thread doesn't try to wake us
need_cancel = true;
}
else {
@@ -95,21 +102,22 @@ thread_sched_wait_events(struct rb_thread_sched *sched, rb_thread_t *th, int fd,
}
timedout = th->sched.waiting_reason.data.result == 0;
- }
- thread_sched_unlock(sched, th);
-
- if (need_cancel) {
- timer_thread_cancel_waiting(th);
- }
- setup_ubf(th, NULL, NULL); // TODO: maybe it is already NULL?
+ if (need_cancel) {
+ timer_thread_cancel_waiting(th);
+ }
- th->status = THREAD_RUNNABLE;
- }
- else {
- RUBY_DEBUG_LOG("can not wait fd:%d", fd);
- return false;
+ th->status = THREAD_RUNNABLE;
+ }
+ else {
+ RUBY_DEBUG_LOG("can not wait fd:%d", fd);
+ timedout = false;
+ }
}
+ thread_sched_unlock(sched, th);
+
+ // if ubf triggered between sched unlock and ubf clear, sched->running == th here
+ ubf_clear(th, false);
VM_ASSERT(sched->running == th);
@@ -184,12 +192,7 @@ nt_thread_stack_size(void)
static struct nt_stack_chunk_header *
nt_alloc_thread_stack_chunk(void)
{
- int mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE;
-#if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
- mmap_flags |= MAP_STACK;
-#endif
-
- const char *m = (void *)mmap(NULL, MSTACK_CHUNK_SIZE, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
+ const char *m = (void *)mmap(NULL, MSTACK_CHUNK_SIZE, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (m == MAP_FAILED) {
return NULL;
}
@@ -208,6 +211,12 @@ nt_alloc_thread_stack_chunk(void)
VM_ASSERT(stack_count <= UINT16_MAX);
+ // Enable read/write for the header pages
+ if (mprotect((void *)m, (size_t)header_page_cnt * MSTACK_PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+ munmap((void *)m, MSTACK_CHUNK_SIZE);
+ return NULL;
+ }
+
struct nt_stack_chunk_header *ch = (struct nt_stack_chunk_header *)m;
ch->start_page = header_page_cnt;
@@ -236,7 +245,7 @@ nt_stack_chunk_get_msf(const rb_vm_t *vm, const char *mstack)
return (struct nt_machine_stack_footer *)&mstack[msz - sizeof(struct nt_machine_stack_footer)];
}
-static void *
+static void
nt_stack_chunk_get_stack(const rb_vm_t *vm, struct nt_stack_chunk_header *ch, size_t idx, void **vm_stack, void **machine_stack)
{
// TODO: only support stack going down
@@ -261,8 +270,6 @@ nt_stack_chunk_get_stack(const rb_vm_t *vm, struct nt_stack_chunk_header *ch, si
*vm_stack = (void *)vstack;
*machine_stack = (void *)mstack;
-
- return (void *)guard_page;
}
RBIMPL_ATTR_MAYBE_UNUSED()
@@ -286,17 +293,6 @@ nt_stack_chunk_dump(void)
}
static int
-nt_guard_page(const char *p, size_t len)
-{
- if (mprotect((void *)p, len, PROT_NONE) != -1) {
- return 0;
- }
- else {
- return errno;
- }
-}
-
-static int
nt_alloc_stack(rb_vm_t *vm, void **vm_stack, void **machine_stack)
{
int err = 0;
@@ -314,8 +310,26 @@ nt_alloc_stack(rb_vm_t *vm, void **vm_stack, void **machine_stack)
RUBY_DEBUG_LOG("uninitialized_stack_count:%d", ch->uninitialized_stack_count);
size_t idx = ch->stack_count - ch->uninitialized_stack_count--;
- void *guard_page = nt_stack_chunk_get_stack(vm, ch, idx, vm_stack, machine_stack);
- err = nt_guard_page(guard_page, MSTACK_PAGE_SIZE);
+
+ // The chunk was mapped PROT_NONE; enable the VM stack and
+ // machine stack pages, leaving the guard page as PROT_NONE.
+ char *stack_start = nt_stack_chunk_get_stack_start(ch, idx);
+ size_t vm_stack_size = vm->default_params.thread_vm_stack_size;
+ size_t mstack_size = nt_thread_stack_size() - vm_stack_size - MSTACK_PAGE_SIZE;
+ char *mstack_start = stack_start + vm_stack_size + MSTACK_PAGE_SIZE;
+
+ int mstack_flags = MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE;
+#if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
+ mstack_flags |= MAP_STACK;
+#endif
+
+ if (mprotect(stack_start, vm_stack_size, PROT_READ | PROT_WRITE) != 0 ||
+ mmap(mstack_start, mstack_size, PROT_READ | PROT_WRITE, mstack_flags, -1, 0) == MAP_FAILED) {
+ err = errno;
+ }
+ else {
+ nt_stack_chunk_get_stack(vm, ch, idx, vm_stack, machine_stack);
+ }
}
else {
nt_free_stack_chunks = ch->prev_free_chunk;
@@ -397,11 +411,15 @@ native_thread_check_and_create_shared(rb_vm_t *vm)
rb_native_mutex_lock(&vm->ractor.sched.lock);
{
- unsigned int snt_cnt = vm->ractor.sched.snt_cnt;
- if (!vm->ractor.main_ractor->threads.sched.enable_mn_threads) snt_cnt++; // do not need snt for main ractor
+ unsigned int schedulable_ractor_cnt = vm->ractor.cnt;
+ RUBY_ASSERT(schedulable_ractor_cnt >= 1);
+
+ if (!vm->ractor.main_ractor->threads.sched.enable_mn_threads)
+ schedulable_ractor_cnt--; // do not need snt for main ractor
+ unsigned int snt_cnt = vm->ractor.sched.snt_cnt;
if (((int)snt_cnt < MINIMUM_SNT) ||
- (snt_cnt < vm->ractor.cnt &&
+ (snt_cnt < schedulable_ractor_cnt &&
snt_cnt < vm->ractor.sched.max_cpu)) {
RUBY_DEBUG_LOG("added snt:%u dnt:%u ractor_cnt:%u grq_cnt:%u",
@@ -450,7 +468,7 @@ co_start(struct coroutine_context *from, struct coroutine_context *self)
// RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
- thread_sched_set_lock_owner(sched, th);
+ thread_sched_set_locked(sched, th);
thread_sched_add_running_thread(TH_SCHED(th), th);
thread_sched_unlock(sched, th);
{
@@ -475,13 +493,11 @@ co_start(struct coroutine_context *from, struct coroutine_context *self)
coroutine_transfer0(self, nt->nt_context, true);
}
else {
- rb_vm_t *vm = th->vm;
- bool has_ready_ractor = vm->ractor.sched.grq_cnt > 0; // at least this ractor is not queued
rb_thread_t *next_th = sched->running;
- if (!has_ready_ractor && next_th && !next_th->nt) {
+ if (next_th && !next_th->nt) {
// switch to the next thread
- thread_sched_set_lock_owner(sched, NULL);
+ thread_sched_set_unlocked(sched, NULL);
th->sched.finished = true;
thread_sched_switch0(th->sched.context, next_th, nt, true);
}
@@ -515,6 +531,7 @@ native_thread_create_shared(rb_thread_t *th)
th->ec->machine.stack_start = (void *)((uintptr_t)machine_stack + machine_stack_size);
th->ec->machine.stack_maxsize = machine_stack_size; // TODO
th->sched.context_stack = machine_stack;
+ th->sched.context_stack_size = machine_stack_size;
th->sched.context = ruby_xmalloc(sizeof(struct coroutine_context));
coroutine_initialize(th->sched.context, co_start, machine_stack, machine_stack_size);
@@ -610,11 +627,17 @@ kqueue_wait(rb_vm_t *vm)
struct timespec *timeout = NULL;
int timeout_ms = timer_thread_set_timeout(vm);
- if (timeout_ms >= 0) {
+ if (timeout_ms > 0) {
calculated_timeout.tv_sec = timeout_ms / 1000;
calculated_timeout.tv_nsec = (timeout_ms % 1000) * 1000000;
timeout = &calculated_timeout;
}
+ else if (timeout_ms == 0) {
+ // Relying on the absence of other members of struct timespec is not strictly portable,
+ // and kevent needs a 0-valued timespec to mean immediate timeout.
+ memset(&calculated_timeout, 0, sizeof(struct timespec));
+ timeout = &calculated_timeout;
+ }
return kevent(timer_th.event_fd, NULL, 0, timer_th.finished_events, KQUEUE_EVENTS_MAX, timeout);
}
@@ -676,7 +699,7 @@ kqueue_already_registered(int fd)
// return false if the fd is not waitable or not need to wait.
static bool
-timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel)
+timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags, rb_hrtime_t *rel, uint32_t event_serial)
{
RUBY_DEBUG_LOG("th:%u fd:%d flag:%d rel:%lu", rb_th_serial(th), fd, flags, rel ? (unsigned long)*rel : 0);
@@ -803,6 +826,7 @@ timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting
th->sched.waiting_reason.data.timeout = abs;
th->sched.waiting_reason.data.fd = fd;
th->sched.waiting_reason.data.result = 0;
+ th->sched.waiting_reason.data.event_serial = event_serial;
}
if (abs == 0) { // no timeout
@@ -835,8 +859,8 @@ timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting
verify_waiting_list();
- // update timeout seconds
- timer_thread_wakeup();
+ // update timeout seconds; force wake so timer thread notices short deadlines
+ timer_thread_wakeup_force();
}
}
else {
@@ -851,6 +875,10 @@ timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting
static void
timer_thread_unregister_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting_flag flags)
{
+ if (!(th->sched.waiting_reason.flags & (thread_sched_waiting_io_read | thread_sched_waiting_io_write))) {
+ return;
+ }
+
RUBY_DEBUG_LOG("th:%u fd:%d", rb_th_serial(th), fd);
#if HAVE_SYS_EVENT_H
kqueue_unregister_waiting(fd, flags);
@@ -881,7 +909,7 @@ timer_thread_setup_mn(void)
#endif
RUBY_DEBUG_LOG("comm_fds:%d/%d", timer_th.comm_fds[0], timer_th.comm_fds[1]);
- timer_thread_register_waiting(NULL, timer_th.comm_fds[0], thread_sched_waiting_io_read | thread_sched_waiting_io_force, NULL);
+ timer_thread_register_waiting(NULL, timer_th.comm_fds[0], thread_sched_waiting_io_read | thread_sched_waiting_io_force, NULL, 0);
}
static int
@@ -970,6 +998,8 @@ timer_thread_polling(rb_vm_t *vm)
(filter == EVFILT_READ) ? "read/" : "",
(filter == EVFILT_WRITE) ? "write/" : "");
+ struct rb_thread_sched *sched = TH_SCHED(th);
+ thread_sched_lock(sched, th);
rb_native_mutex_lock(&timer_th.waiting_lock);
{
if (th->sched.waiting_reason.flags) {
@@ -980,14 +1010,16 @@ timer_thread_polling(rb_vm_t *vm)
th->sched.waiting_reason.flags = thread_sched_waiting_none;
th->sched.waiting_reason.data.fd = -1;
th->sched.waiting_reason.data.result = filter;
+ uint32_t event_serial = th->sched.waiting_reason.data.event_serial;
- timer_thread_wakeup_thread(th);
+ timer_thread_wakeup_thread_locked(sched, th, event_serial);
}
else {
// already released
}
}
rb_native_mutex_unlock(&timer_th.waiting_lock);
+ thread_sched_unlock(sched, th);
}
}
#else
@@ -1012,6 +1044,8 @@ timer_thread_polling(rb_vm_t *vm)
(events & EPOLLERR) ? "err/" : "",
(events & EPOLLHUP) ? "hup/" : "");
+ struct rb_thread_sched *sched = TH_SCHED(th);
+ thread_sched_lock(sched, th);
rb_native_mutex_lock(&timer_th.waiting_lock);
{
if (th->sched.waiting_reason.flags) {
@@ -1022,14 +1056,16 @@ timer_thread_polling(rb_vm_t *vm)
th->sched.waiting_reason.flags = thread_sched_waiting_none;
th->sched.waiting_reason.data.fd = -1;
th->sched.waiting_reason.data.result = (int)events;
+ uint32_t event_serial = th->sched.waiting_reason.data.event_serial;
- timer_thread_wakeup_thread(th);
+ timer_thread_wakeup_thread_locked(sched, th, event_serial);
}
else {
// already released
}
}
rb_native_mutex_unlock(&timer_th.waiting_lock);
+ thread_sched_unlock(sched, th);
}
}
#endif
@@ -1058,12 +1094,12 @@ timer_thread_polling(rb_vm_t *vm)
switch (r) {
case 0: // timeout
- rb_native_mutex_lock(&vm->ractor.sched.lock);
+ ractor_sched_lock(vm, NULL);
{
// (1-1) timeslice
timer_thread_check_timeslice(vm);
}
- rb_native_mutex_unlock(&vm->ractor.sched.lock);
+ ractor_sched_unlock(vm, NULL);
break;
case -1: // error
diff --git a/thread_sync.c b/thread_sync.c
index 462506b20b..c9e056dfe2 100644
--- a/thread_sync.c
+++ b/thread_sync.c
@@ -2,12 +2,12 @@
#include "ccan/list/list.h"
#include "builtin.h"
-static VALUE rb_cMutex, rb_cQueue, rb_cSizedQueue, rb_cConditionVariable;
-static VALUE rb_eClosedQueueError;
+static VALUE rb_cMutex, rb_eClosedQueueError;
/* Mutex */
typedef struct rb_mutex_struct {
- rb_fiber_t *fiber;
+ rb_serial_t ec_serial;
+ rb_thread_t *th; // even if the fiber is collected, we might need access to the thread in mutex_free
struct rb_mutex_struct *next_mutex;
struct ccan_list_head waitq; /* protected by GVL */
} rb_mutex_t;
@@ -80,33 +80,7 @@ static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
static void rb_mutex_abandon_keeping_mutexes(rb_thread_t *th);
static void rb_mutex_abandon_locking_mutex(rb_thread_t *th);
#endif
-static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber);
-
-/*
- * Document-class: Thread::Mutex
- *
- * Thread::Mutex implements a simple semaphore that can be used to
- * coordinate access to shared data from multiple concurrent threads.
- *
- * Example:
- *
- * semaphore = Thread::Mutex.new
- *
- * a = Thread.new {
- * semaphore.synchronize {
- * # access shared resource
- * }
- * }
- *
- * b = Thread.new {
- * semaphore.synchronize {
- * # access shared resource
- * }
- * }
- *
- */
-
-#define mutex_mark ((void(*)(void*))0)
+static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial);
static size_t
rb_mutex_num_waiting(rb_mutex_t *mutex)
@@ -123,13 +97,18 @@ rb_mutex_num_waiting(rb_mutex_t *mutex)
rb_thread_t* rb_fiber_threadptr(const rb_fiber_t *fiber);
+static bool
+mutex_locked_p(rb_mutex_t *mutex)
+{
+ return mutex->ec_serial != 0;
+}
+
static void
mutex_free(void *ptr)
{
rb_mutex_t *mutex = ptr;
- if (mutex->fiber) {
- /* rb_warn("free locked mutex"); */
- const char *err = rb_mutex_unlock_th(mutex, rb_fiber_threadptr(mutex->fiber), mutex->fiber);
+ if (mutex_locked_p(mutex)) {
+ const char *err = rb_mutex_unlock_th(mutex, mutex->th, 0);
if (err) rb_bug("%s", err);
}
ruby_xfree(ptr);
@@ -143,8 +122,8 @@ mutex_memsize(const void *ptr)
static const rb_data_type_t mutex_data_type = {
"mutex",
- {mutex_mark, mutex_free, mutex_memsize,},
- 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
+ {NULL, mutex_free, mutex_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static rb_mutex_t *
@@ -175,41 +154,24 @@ mutex_alloc(VALUE klass)
return obj;
}
-/*
- * call-seq:
- * Thread::Mutex.new -> mutex
- *
- * Creates a new Mutex
- */
-static VALUE
-mutex_initialize(VALUE self)
-{
- return self;
-}
-
VALUE
rb_mutex_new(void)
{
return mutex_alloc(rb_cMutex);
}
-/*
- * call-seq:
- * mutex.locked? -> true or false
- *
- * Returns +true+ if this lock is currently held by some thread.
- */
VALUE
rb_mutex_locked_p(VALUE self)
{
rb_mutex_t *mutex = mutex_ptr(self);
- return RBOOL(mutex->fiber);
+ return RBOOL(mutex_locked_p(mutex));
}
static void
thread_mutex_insert(rb_thread_t *thread, rb_mutex_t *mutex)
{
+ RUBY_ASSERT(!mutex->next_mutex);
if (thread->keeping_mutexes) {
mutex->next_mutex = thread->keeping_mutexes;
}
@@ -234,45 +196,50 @@ thread_mutex_remove(rb_thread_t *thread, rb_mutex_t *mutex)
}
static void
-mutex_locked(rb_thread_t *th, VALUE self)
+mutex_set_owner(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial)
{
- rb_mutex_t *mutex = mutex_ptr(self);
+ mutex->th = th;
+ mutex->ec_serial = ec_serial;
+}
+static void
+mutex_locked(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial)
+{
+ mutex_set_owner(mutex, th, ec_serial);
thread_mutex_insert(th, mutex);
}
-/*
- * call-seq:
- * mutex.try_lock -> true or false
- *
- * Attempts to obtain the lock and returns immediately. Returns +true+ if the
- * lock was granted.
- */
-VALUE
-rb_mutex_trylock(VALUE self)
+static inline bool
+do_mutex_trylock(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial)
{
- rb_mutex_t *mutex = mutex_ptr(self);
-
- if (mutex->fiber == 0) {
+ if (mutex->ec_serial == 0) {
RUBY_DEBUG_LOG("%p ok", mutex);
- rb_fiber_t *fiber = GET_EC()->fiber_ptr;
- rb_thread_t *th = GET_THREAD();
- mutex->fiber = fiber;
-
- mutex_locked(th, self);
- return Qtrue;
+ mutex_locked(mutex, th, ec_serial);
+ return true;
}
else {
RUBY_DEBUG_LOG("%p ng", mutex);
- return Qfalse;
+ return false;
}
}
static VALUE
-mutex_owned_p(rb_fiber_t *fiber, rb_mutex_t *mutex)
+rb_mut_trylock(rb_execution_context_t *ec, VALUE self)
{
- return RBOOL(mutex->fiber == fiber);
+ return RBOOL(do_mutex_trylock(mutex_ptr(self), ec->thread_ptr, rb_ec_serial(ec)));
+}
+
+VALUE
+rb_mutex_trylock(VALUE self)
+{
+ return rb_mut_trylock(GET_EC(), self);
+}
+
+static VALUE
+mutex_owned_p(rb_serial_t ec_serial, rb_mutex_t *mutex)
+{
+ return RBOOL(mutex->ec_serial == ec_serial);
}
static VALUE
@@ -292,13 +259,29 @@ delete_from_waitq(VALUE value)
static inline rb_atomic_t threadptr_get_interrupts(rb_thread_t *th);
+struct mutex_args {
+ VALUE self;
+ rb_mutex_t *mutex;
+ rb_execution_context_t *ec;
+};
+
+static inline void
+mutex_args_init(struct mutex_args *args, VALUE mutex)
+{
+ args->self = mutex;
+ args->mutex = mutex_ptr(mutex);
+ args->ec = GET_EC();
+}
+
static VALUE
-do_mutex_lock(VALUE self, int interruptible_p)
+do_mutex_lock(struct mutex_args *args, int interruptible_p)
{
- rb_execution_context_t *ec = GET_EC();
+ VALUE self = args->self;
+ rb_execution_context_t *ec = args->ec;
rb_thread_t *th = ec->thread_ptr;
rb_fiber_t *fiber = ec->fiber_ptr;
- rb_mutex_t *mutex = mutex_ptr(self);
+ rb_serial_t ec_serial = rb_ec_serial(ec);
+ rb_mutex_t *mutex = args->mutex;
rb_atomic_t saved_ints = 0;
/* When running trap handler */
@@ -307,13 +290,13 @@ do_mutex_lock(VALUE self, int interruptible_p)
rb_raise(rb_eThreadError, "can't be called from trap context");
}
- if (rb_mutex_trylock(self) == Qfalse) {
- if (mutex->fiber == fiber) {
+ if (!do_mutex_trylock(mutex, th, ec_serial)) {
+ if (mutex->ec_serial == ec_serial) {
rb_raise(rb_eThreadError, "deadlock; recursive locking");
}
- while (mutex->fiber != fiber) {
- VM_ASSERT(mutex->fiber != NULL);
+ while (mutex->ec_serial != ec_serial) {
+ VM_ASSERT(mutex->ec_serial != 0);
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
@@ -327,12 +310,12 @@ do_mutex_lock(VALUE self, int interruptible_p)
rb_ensure(call_rb_fiber_scheduler_block, self, delete_from_waitq, (VALUE)&sync_waiter);
- if (!mutex->fiber) {
- mutex->fiber = fiber;
+ if (!mutex->ec_serial) {
+ mutex_set_owner(mutex, th, ec_serial);
}
}
else {
- if (!th->vm->thread_ignore_deadlock && rb_fiber_threadptr(mutex->fiber) == th) {
+ if (!th->vm->thread_ignore_deadlock && mutex->th == th) {
rb_raise(rb_eThreadError, "deadlock; lock already owned by another fiber belonging to the same thread");
}
@@ -358,6 +341,7 @@ do_mutex_lock(VALUE self, int interruptible_p)
rb_ractor_sleeper_threads_inc(th->ractor);
rb_check_deadlock(th->ractor);
+ RUBY_ASSERT(!th->locking_mutex);
th->locking_mutex = self;
ccan_list_add_tail(&mutex->waitq, &sync_waiter.node);
@@ -367,14 +351,13 @@ do_mutex_lock(VALUE self, int interruptible_p)
ccan_list_del(&sync_waiter.node);
// unlocked by another thread while sleeping
- if (!mutex->fiber) {
- mutex->fiber = fiber;
+ if (!mutex->ec_serial) {
+ mutex_set_owner(mutex, th, ec_serial);
}
rb_ractor_sleeper_threads_dec(th->ractor);
th->status = prev_status;
th->locking_mutex = Qfalse;
- th->locking_mutex = Qfalse;
RUBY_DEBUG_LOG("%p wakeup", mutex);
}
@@ -382,10 +365,13 @@ do_mutex_lock(VALUE self, int interruptible_p)
if (interruptible_p) {
/* release mutex before checking for interrupts...as interrupt checking
* code might call rb_raise() */
- if (mutex->fiber == fiber) mutex->fiber = 0;
+ if (mutex->ec_serial == ec_serial) {
+ mutex->th = NULL;
+ mutex->ec_serial = 0;
+ }
RUBY_VM_CHECK_INTS_BLOCKING(th->ec); /* may release mutex */
- if (!mutex->fiber) {
- mutex->fiber = fiber;
+ if (!mutex->ec_serial) {
+ mutex_set_owner(mutex, th, ec_serial);
}
}
else {
@@ -404,13 +390,13 @@ do_mutex_lock(VALUE self, int interruptible_p)
}
if (saved_ints) th->ec->interrupt_flag = saved_ints;
- if (mutex->fiber == fiber) mutex_locked(th, self);
+ if (mutex->ec_serial == ec_serial) mutex_locked(mutex, th, ec_serial);
}
RUBY_DEBUG_LOG("%p locked", mutex);
// assertion
- if (mutex_owned_p(fiber, mutex) == Qfalse) rb_bug("do_mutex_lock: mutex is not owned.");
+ if (mutex_owned_p(ec_serial, mutex) == Qfalse) rb_bug("do_mutex_lock: mutex is not owned.");
return self;
}
@@ -418,52 +404,57 @@ do_mutex_lock(VALUE self, int interruptible_p)
static VALUE
mutex_lock_uninterruptible(VALUE self)
{
- return do_mutex_lock(self, 0);
+ struct mutex_args args;
+ mutex_args_init(&args, self);
+ return do_mutex_lock(&args, 0);
+}
+
+static VALUE
+rb_mut_lock(rb_execution_context_t *ec, VALUE self)
+{
+ struct mutex_args args = {
+ .self = self,
+ .mutex = mutex_ptr(self),
+ .ec = ec,
+ };
+ return do_mutex_lock(&args, 1);
}
-/*
- * call-seq:
- * mutex.lock -> self
- *
- * Attempts to grab the lock and waits if it isn't available.
- * Raises +ThreadError+ if +mutex+ was locked by the current thread.
- */
VALUE
rb_mutex_lock(VALUE self)
{
- return do_mutex_lock(self, 1);
+ struct mutex_args args;
+ mutex_args_init(&args, self);
+ return do_mutex_lock(&args, 1);
+}
+
+static VALUE
+rb_mut_owned_p(rb_execution_context_t *ec, VALUE self)
+{
+ return mutex_owned_p(rb_ec_serial(ec), mutex_ptr(self));
}
-/*
- * call-seq:
- * mutex.owned? -> true or false
- *
- * Returns +true+ if this lock is currently held by current thread.
- */
VALUE
rb_mutex_owned_p(VALUE self)
{
- rb_fiber_t *fiber = GET_EC()->fiber_ptr;
- rb_mutex_t *mutex = mutex_ptr(self);
-
- return mutex_owned_p(fiber, mutex);
+ return rb_mut_owned_p(GET_EC(), self);
}
static const char *
-rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber)
+rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial)
{
RUBY_DEBUG_LOG("%p", mutex);
- if (mutex->fiber == 0) {
+ if (mutex->ec_serial == 0) {
return "Attempt to unlock a mutex which is not locked";
}
- else if (mutex->fiber != fiber) {
+ else if (ec_serial && mutex->ec_serial != ec_serial) {
return "Attempt to unlock a mutex which is locked by another thread/fiber";
}
struct sync_waiter *cur = 0, *next;
- mutex->fiber = 0;
+ mutex->ec_serial = 0;
thread_mutex_remove(th, mutex);
ccan_list_for_each_safe(&mutex->waitq, cur, next, node) {
@@ -494,6 +485,24 @@ rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber)
return NULL;
}
+static void
+do_mutex_unlock(struct mutex_args *args)
+{
+ const char *err;
+ rb_mutex_t *mutex = args->mutex;
+ rb_thread_t *th = rb_ec_thread_ptr(args->ec);
+
+ err = rb_mutex_unlock_th(mutex, th, rb_ec_serial(args->ec));
+ if (err) rb_raise(rb_eThreadError, "%s", err);
+}
+
+static VALUE
+do_mutex_unlock_safe(VALUE args)
+{
+ do_mutex_unlock((struct mutex_args *)args);
+ return Qnil;
+}
+
/*
* call-seq:
* mutex.unlock -> self
@@ -504,13 +513,21 @@ rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber)
VALUE
rb_mutex_unlock(VALUE self)
{
- const char *err;
- rb_mutex_t *mutex = mutex_ptr(self);
- rb_thread_t *th = GET_THREAD();
-
- err = rb_mutex_unlock_th(mutex, th, GET_EC()->fiber_ptr);
- if (err) rb_raise(rb_eThreadError, "%s", err);
+ struct mutex_args args;
+ mutex_args_init(&args, self);
+ do_mutex_unlock(&args);
+ return self;
+}
+static VALUE
+rb_mut_unlock(rb_execution_context_t *ec, VALUE self)
+{
+ struct mutex_args args = {
+ .self = self,
+ .mutex = mutex_ptr(self),
+ .ec = ec,
+ };
+ do_mutex_unlock(&args);
return self;
}
@@ -541,7 +558,7 @@ rb_mutex_abandon_all(rb_mutex_t *mutexes)
while (mutexes) {
mutex = mutexes;
mutexes = mutex->next_mutex;
- mutex->fiber = 0;
+ mutex->ec_serial = 0;
mutex->next_mutex = 0;
ccan_list_head_init(&mutex->waitq);
}
@@ -579,15 +596,15 @@ mutex_sleep_begin(VALUE _arguments)
return woken;
}
-VALUE
-rb_mutex_sleep(VALUE self, VALUE timeout)
+static VALUE
+rb_mut_sleep(rb_execution_context_t *ec, VALUE self, VALUE timeout)
{
if (!NIL_P(timeout)) {
// Validate the argument:
rb_time_interval(timeout);
}
- rb_mutex_unlock(self);
+ rb_mut_unlock(ec, self);
time_t beg = time(0);
struct rb_mutex_sleep_arguments arguments = {
@@ -595,69 +612,45 @@ rb_mutex_sleep(VALUE self, VALUE timeout)
.timeout = timeout,
};
- VALUE woken = rb_ensure(mutex_sleep_begin, (VALUE)&arguments, mutex_lock_uninterruptible, self);
+ VALUE woken = rb_ec_ensure(ec, mutex_sleep_begin, (VALUE)&arguments, mutex_lock_uninterruptible, self);
- RUBY_VM_CHECK_INTS_BLOCKING(GET_EC());
+ RUBY_VM_CHECK_INTS_BLOCKING(ec);
if (!woken) return Qnil;
time_t end = time(0) - beg;
return TIMET2NUM(end);
}
-/*
- * call-seq:
- * mutex.sleep(timeout = nil) -> number or nil
- *
- * Releases the lock and sleeps +timeout+ seconds if it is given and
- * non-nil or forever. Raises +ThreadError+ if +mutex+ wasn't locked by
- * the current thread.
- *
- * When the thread is next woken up, it will attempt to reacquire
- * the lock.
- *
- * Note that this method can wakeup without explicit Thread#wakeup call.
- * For example, receiving signal and so on.
- *
- * Returns the slept time in seconds if woken up, or +nil+ if timed out.
- */
-static VALUE
-mutex_sleep(int argc, VALUE *argv, VALUE self)
+VALUE
+rb_mutex_sleep(VALUE self, VALUE timeout)
{
- VALUE timeout;
-
- timeout = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
- return rb_mutex_sleep(self, timeout);
+ return rb_mut_sleep(GET_EC(), self, timeout);
}
-/*
- * call-seq:
- * mutex.synchronize { ... } -> result of the block
- *
- * Obtains a lock, runs the block, and releases the lock when the block
- * completes. See the example under Thread::Mutex.
- */
-
VALUE
-rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg)
+rb_mutex_synchronize(VALUE self, VALUE (*func)(VALUE arg), VALUE arg)
{
- rb_mutex_lock(mutex);
- return rb_ensure(func, arg, rb_mutex_unlock, mutex);
+ struct mutex_args args;
+ mutex_args_init(&args, self);
+ do_mutex_lock(&args, 1);
+ return rb_ec_ensure(args.ec, func, arg, do_mutex_unlock_safe, (VALUE)&args);
}
-/*
- * call-seq:
- * mutex.synchronize { ... } -> result of the block
- *
- * Obtains a lock, runs the block, and releases the lock when the block
- * completes. See the example under Thread::Mutex.
- */
static VALUE
-rb_mutex_synchronize_m(VALUE self)
+do_ec_yield(VALUE _ec)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eThreadError, "must be called with a block");
- }
+ return rb_ec_yield((rb_execution_context_t *)_ec, Qundef);
+}
- return rb_mutex_synchronize(self, rb_yield, Qundef);
+VALUE
+rb_mut_synchronize(rb_execution_context_t *ec, VALUE self)
+{
+ struct mutex_args args = {
+ .self = self,
+ .mutex = mutex_ptr(self),
+ .ec = ec,
+ };
+ do_mutex_lock(&args, 1);
+ return rb_ec_ensure(args.ec, do_ec_yield, (VALUE)ec, do_mutex_unlock_safe, (VALUE)&args);
}
void
@@ -673,46 +666,68 @@ rb_mutex_allow_trap(VALUE self, int val)
/* Queue */
-#define queue_waitq(q) UNALIGNED_MEMBER_PTR(q, waitq)
-#define queue_list(q) UNALIGNED_MEMBER_PTR(q, que)
-RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
struct rb_queue {
struct ccan_list_head waitq;
rb_serial_t fork_gen;
- const VALUE que;
+ long capa;
+ long len;
+ long offset;
+ VALUE *buffer;
int num_waiting;
-} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
+};
+
+#define szqueue_waitq(sq) &sq->q.waitq
+#define szqueue_pushq(sq) &sq->pushq
-#define szqueue_waitq(sq) UNALIGNED_MEMBER_PTR(sq, q.waitq)
-#define szqueue_list(sq) UNALIGNED_MEMBER_PTR(sq, q.que)
-#define szqueue_pushq(sq) UNALIGNED_MEMBER_PTR(sq, pushq)
-RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
struct rb_szqueue {
struct rb_queue q;
int num_waiting_push;
struct ccan_list_head pushq;
long max;
-} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
+};
static void
-queue_mark(void *ptr)
+queue_mark_and_move(void *ptr)
{
struct rb_queue *q = ptr;
-
/* no need to mark threads in waitq, they are on stack */
- rb_gc_mark(q->que);
+ for (long index = 0; index < q->len; index++) {
+ rb_gc_mark_and_move(&q->buffer[((q->offset + index) % q->capa)]);
+ }
+}
+
+static inline void
+queue_free_buffer(struct rb_queue *q)
+{
+ if (q->buffer) {
+ SIZED_FREE_N(q->buffer, q->capa);
+ }
+}
+
+static void
+queue_free(void *ptr)
+{
+ struct rb_queue *q = ptr;
+ queue_free_buffer(q);
+ SIZED_FREE(q);
}
static size_t
queue_memsize(const void *ptr)
{
- return sizeof(struct rb_queue);
+ const struct rb_queue *q = ptr;
+ return sizeof(struct rb_queue) + (q->capa * sizeof(VALUE));
}
static const rb_data_type_t queue_data_type = {
- "queue",
- {queue_mark, RUBY_TYPED_DEFAULT_FREE, queue_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+ .wrap_struct_name = "Thread::Queue",
+ .function = {
+ .dmark = queue_mark_and_move,
+ .dfree = queue_free,
+ .dsize = queue_memsize,
+ .dcompact = queue_mark_and_move,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
@@ -722,27 +737,27 @@ queue_alloc(VALUE klass)
struct rb_queue *q;
obj = TypedData_Make_Struct(klass, struct rb_queue, &queue_data_type, q);
- ccan_list_head_init(queue_waitq(q));
+ ccan_list_head_init(&q->waitq);
return obj;
}
-static int
+static inline bool
queue_fork_check(struct rb_queue *q)
{
rb_serial_t fork_gen = GET_VM()->fork_gen;
- if (q->fork_gen == fork_gen) {
- return 0;
+ if (RB_LIKELY(q->fork_gen == fork_gen)) {
+ return false;
}
/* forked children can't reach into parent thread stacks */
q->fork_gen = fork_gen;
- ccan_list_head_init(queue_waitq(q));
+ ccan_list_head_init(&q->waitq);
q->num_waiting = 0;
- return 1;
+ return true;
}
-static struct rb_queue *
-queue_ptr(VALUE obj)
+static inline struct rb_queue *
+raw_queue_ptr(VALUE obj)
{
struct rb_queue *q;
@@ -752,6 +767,22 @@ queue_ptr(VALUE obj)
return q;
}
+static inline void
+check_queue(VALUE obj, struct rb_queue *q)
+{
+ if (RB_UNLIKELY(q->buffer == NULL)) {
+ rb_raise(rb_eTypeError, "%+"PRIsVALUE" not initialized", obj);
+ }
+}
+
+static inline struct rb_queue *
+queue_ptr(VALUE obj)
+{
+ struct rb_queue *q = raw_queue_ptr(obj);
+ check_queue(obj, q);
+ return q;
+}
+
#define QUEUE_CLOSED FL_USER5
static rb_hrtime_t
@@ -771,23 +802,38 @@ queue_timeout2hrtime(VALUE timeout)
}
static void
-szqueue_mark(void *ptr)
+szqueue_mark_and_move(void *ptr)
{
struct rb_szqueue *sq = ptr;
- queue_mark(&sq->q);
+ queue_mark_and_move(&sq->q);
+}
+
+static void
+szqueue_free(void *ptr)
+{
+ struct rb_szqueue *sq = ptr;
+ queue_free_buffer(&sq->q);
+ SIZED_FREE(sq);
}
static size_t
szqueue_memsize(const void *ptr)
{
- return sizeof(struct rb_szqueue);
+ const struct rb_szqueue *sq = ptr;
+ return sizeof(struct rb_szqueue) + (sq->q.capa * sizeof(VALUE));
}
static const rb_data_type_t szqueue_data_type = {
- "sized_queue",
- {szqueue_mark, RUBY_TYPED_DEFAULT_FREE, szqueue_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+ .wrap_struct_name = "Thread::SizedQueue",
+ .function = {
+ .dmark = szqueue_mark_and_move,
+ .dfree = szqueue_free,
+ .dsize = szqueue_memsize,
+ .dcompact = szqueue_mark_and_move,
+ },
+ .parent = &queue_data_type,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
@@ -801,13 +847,13 @@ szqueue_alloc(VALUE klass)
return obj;
}
-static struct rb_szqueue *
-szqueue_ptr(VALUE obj)
+static inline struct rb_szqueue *
+raw_szqueue_ptr(VALUE obj)
{
struct rb_szqueue *sq;
TypedData_Get_Struct(obj, struct rb_szqueue, &szqueue_data_type, sq);
- if (queue_fork_check(&sq->q)) {
+ if (RB_UNLIKELY(queue_fork_check(&sq->q))) {
ccan_list_head_init(szqueue_pushq(sq));
sq->num_waiting_push = 0;
}
@@ -815,28 +861,15 @@ szqueue_ptr(VALUE obj)
return sq;
}
-static VALUE
-ary_buf_new(void)
-{
- return rb_ary_hidden_new(1);
-}
-
-static VALUE
-check_array(VALUE obj, VALUE ary)
-{
- if (!RB_TYPE_P(ary, T_ARRAY)) {
- rb_raise(rb_eTypeError, "%+"PRIsVALUE" not initialized", obj);
- }
- return ary;
-}
-
-static long
-queue_length(VALUE self, struct rb_queue *q)
+static inline struct rb_szqueue *
+szqueue_ptr(VALUE obj)
{
- return RARRAY_LEN(check_array(self, q->que));
+ struct rb_szqueue *sq = raw_szqueue_ptr(obj);
+ check_queue(obj, &sq->q);
+ return sq;
}
-static int
+static inline bool
queue_closed_p(VALUE self)
{
return FL_TEST_RAW(self, QUEUE_CLOSED) != 0;
@@ -860,171 +893,95 @@ raise_closed_queue_error(VALUE self)
static VALUE
queue_closed_result(VALUE self, struct rb_queue *q)
{
- RUBY_ASSERT(queue_length(self, q) == 0);
+ RUBY_ASSERT(q->len == 0);
return Qnil;
}
-/*
- * Document-class: Thread::Queue
- *
- * The Thread::Queue class implements multi-producer, multi-consumer
- * queues. It is especially useful in threaded programming when
- * information must be exchanged safely between multiple threads. The
- * Thread::Queue class implements all the required locking semantics.
- *
- * The class implements FIFO (first in, first out) type of queue.
- * In a FIFO queue, the first tasks added are the first retrieved.
- *
- * Example:
- *
- * queue = Thread::Queue.new
- *
- * producer = Thread.new do
- * 5.times do |i|
- * sleep rand(i) # simulate expense
- * queue << i
- * puts "#{i} produced"
- * end
- * end
- *
- * consumer = Thread.new do
- * 5.times do |i|
- * value = queue.pop
- * sleep rand(i/2) # simulate expense
- * puts "consumed #{value}"
- * end
- * end
- *
- * consumer.join
- *
- */
+#define QUEUE_INITIAL_CAPA 8
-/*
- * Document-method: Queue::new
- *
- * call-seq:
- * Thread::Queue.new -> empty_queue
- * Thread::Queue.new(enumerable) -> queue
- *
- * Creates a new queue instance, optionally using the contents of an +enumerable+
- * for its initial state.
- *
- * Example:
- *
- * q = Thread::Queue.new
- * #=> #<Thread::Queue:0x00007ff7501110d0>
- * q.empty?
- * #=> true
- *
- * q = Thread::Queue.new([1, 2, 3])
- * #=> #<Thread::Queue:0x00007ff7500ec500>
- * q.empty?
- * #=> false
- * q.pop
- * #=> 1
- */
+static inline void
+ring_buffer_init(struct rb_queue *q, long initial_capa)
+{
+ q->buffer = ALLOC_N(VALUE, initial_capa);
+ q->capa = initial_capa;
+}
-static VALUE
-rb_queue_initialize(int argc, VALUE *argv, VALUE self)
+static inline void
+ring_buffer_expand(struct rb_queue *q)
{
- VALUE initial;
- struct rb_queue *q = queue_ptr(self);
- if ((argc = rb_scan_args(argc, argv, "01", &initial)) == 1) {
- initial = rb_to_array(initial);
- }
- RB_OBJ_WRITE(self, queue_list(q), ary_buf_new());
- ccan_list_head_init(queue_waitq(q));
- if (argc == 1) {
- rb_ary_concat(q->que, initial);
- }
- return self;
+ RUBY_ASSERT(q->capa > 0);
+ VALUE *new_buffer = ALLOC_N(VALUE, q->capa * 2);
+ MEMCPY(new_buffer, q->buffer + q->offset, VALUE, q->capa - q->offset);
+ MEMCPY(new_buffer + (q->capa - q->offset), q->buffer, VALUE, q->offset);
+ VALUE *old_buffer = q->buffer;
+ q->buffer = new_buffer;
+ q->offset = 0;
+ ruby_xfree_sized(old_buffer, q->capa * sizeof(VALUE));
+ q->capa *= 2;
}
-static VALUE
-queue_do_push(VALUE self, struct rb_queue *q, VALUE obj)
+static void
+ring_buffer_push(VALUE self, struct rb_queue *q, VALUE obj)
{
- if (queue_closed_p(self)) {
- raise_closed_queue_error(self);
+ if (RB_UNLIKELY(q->len >= q->capa)) {
+ ring_buffer_expand(q);
}
- rb_ary_push(check_array(self, q->que), obj);
- wakeup_one(queue_waitq(q));
- return self;
+ RUBY_ASSERT(q->capa > q->len);
+ long index = (q->offset + q->len) % q->capa;
+ q->len++;
+ RB_OBJ_WRITE(self, &q->buffer[index], obj);
}
-/*
- * Document-method: Thread::Queue#close
- * call-seq:
- * close
- *
- * Closes the queue. A closed queue cannot be re-opened.
- *
- * After the call to close completes, the following are true:
- *
- * - +closed?+ will return true
- *
- * - +close+ will be ignored.
- *
- * - calling enq/push/<< will raise a +ClosedQueueError+.
- *
- * - when +empty?+ is false, calling deq/pop/shift will return an object
- * from the queue as usual.
- * - when +empty?+ is true, deq(false) will not suspend the thread and will return nil.
- * deq(true) will raise a +ThreadError+.
- *
- * ClosedQueueError is inherited from StopIteration, so that you can break loop block.
- *
- * Example:
- *
- * q = Thread::Queue.new
- * Thread.new{
- * while e = q.deq # wait for nil to break loop
- * # ...
- * end
- * }
- * q.close
- */
-
static VALUE
-rb_queue_close(VALUE self)
+ring_buffer_shift(struct rb_queue *q)
{
- struct rb_queue *q = queue_ptr(self);
-
- if (!queue_closed_p(self)) {
- FL_SET(self, QUEUE_CLOSED);
-
- wakeup_all(queue_waitq(q));
+ if (!q->len) {
+ return Qnil;
}
- return self;
+ VALUE obj = q->buffer[q->offset];
+ q->len--;
+ if (q->len == 0) {
+ q->offset = 0;
+ }
+ else {
+ q->offset = (q->offset + 1) % q->capa;
+ }
+ return obj;
}
-/*
- * Document-method: Thread::Queue#closed?
- * call-seq: closed?
- *
- * Returns +true+ if the queue is closed.
- */
-
static VALUE
-rb_queue_closed_p(VALUE self)
+queue_initialize(rb_execution_context_t *ec, VALUE self, VALUE initial)
{
- return RBOOL(queue_closed_p(self));
+ struct rb_queue *q = raw_queue_ptr(self);
+ ccan_list_head_init(&q->waitq);
+ if (NIL_P(initial)) {
+ ring_buffer_init(q, QUEUE_INITIAL_CAPA);
+ }
+ else {
+ initial = rb_to_array(initial);
+ long len = RARRAY_LEN(initial);
+ long initial_capa = QUEUE_INITIAL_CAPA;
+ while (initial_capa < len) {
+ initial_capa *= 2;
+ }
+ ring_buffer_init(q, initial_capa);
+ MEMCPY(q->buffer, RARRAY_CONST_PTR(initial), VALUE, len);
+ q->len = len;
+ }
+ return self;
}
-/*
- * Document-method: Thread::Queue#push
- * call-seq:
- * push(object)
- * enq(object)
- * <<(object)
- *
- * Pushes the given +object+ to the queue.
- */
-
static VALUE
-rb_queue_push(VALUE self, VALUE obj)
+queue_do_push(VALUE self, struct rb_queue *q, VALUE obj)
{
- return queue_do_push(self, queue_ptr(self), obj);
+ check_queue(self, q);
+ if (queue_closed_p(self)) {
+ raise_closed_queue_error(self);
+ }
+ ring_buffer_push(self, q, obj);
+ wakeup_one(&q->waitq);
+ return self;
}
static VALUE
@@ -1065,12 +1022,11 @@ szqueue_sleep_done(VALUE p)
return Qfalse;
}
-static VALUE
-queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
+static inline VALUE
+queue_do_pop(rb_execution_context_t *ec, VALUE self, struct rb_queue *q, VALUE non_block, VALUE timeout)
{
- check_array(self, q->que);
- if (RARRAY_LEN(q->que) == 0) {
- if (!should_block) {
+ if (q->len == 0) {
+ if (RTEST(non_block)) {
rb_raise(rb_eThreadError, "queue empty");
}
@@ -1080,14 +1036,12 @@ queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
}
rb_hrtime_t end = queue_timeout2hrtime(timeout);
- while (RARRAY_LEN(q->que) == 0) {
+ while (q->len == 0) {
if (queue_closed_p(self)) {
return queue_closed_result(self, q);
}
else {
- rb_execution_context_t *ec = GET_EC();
-
- RUBY_ASSERT(RARRAY_LEN(q->que) == 0);
+ RUBY_ASSERT(q->len == 0);
RUBY_ASSERT(queue_closed_p(self) == 0);
struct queue_waiter queue_waiter = {
@@ -1095,7 +1049,7 @@ queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
.as = {.q = q}
};
- struct ccan_list_head *waitq = queue_waitq(q);
+ struct ccan_list_head *waitq = &q->waitq;
ccan_list_add_tail(waitq, &queue_waiter.w.node);
queue_waiter.as.q->num_waiting++;
@@ -1112,116 +1066,32 @@ queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
}
}
- return rb_ary_shift(q->que);
+ return ring_buffer_shift(q);
}
static VALUE
rb_queue_pop(rb_execution_context_t *ec, VALUE self, VALUE non_block, VALUE timeout)
{
- return queue_do_pop(self, queue_ptr(self), !RTEST(non_block), timeout);
+ return queue_do_pop(ec, self, queue_ptr(self), non_block, timeout);
}
-/*
- * Document-method: Thread::Queue#empty?
- * call-seq: empty?
- *
- * Returns +true+ if the queue is empty.
- */
-
-static VALUE
-rb_queue_empty_p(VALUE self)
-{
- return RBOOL(queue_length(self, queue_ptr(self)) == 0);
-}
-
-/*
- * Document-method: Thread::Queue#clear
- *
- * Removes all objects from the queue.
- */
-
-static VALUE
-rb_queue_clear(VALUE self)
-{
- struct rb_queue *q = queue_ptr(self);
-
- rb_ary_clear(check_array(self, q->que));
- return self;
-}
-
-/*
- * Document-method: Thread::Queue#length
- * call-seq:
- * length
- * size
- *
- * Returns the length of the queue.
- */
-
-static VALUE
-rb_queue_length(VALUE self)
-{
- return LONG2NUM(queue_length(self, queue_ptr(self)));
-}
-
-NORETURN(static VALUE rb_queue_freeze(VALUE self));
-/*
- * call-seq:
- * freeze
- *
- * The queue can't be frozen, so this method raises an exception:
- * Thread::Queue.new.freeze # Raises TypeError (cannot freeze #<Thread::Queue:0x...>)
- *
- */
-static VALUE
-rb_queue_freeze(VALUE self)
-{
- rb_raise(rb_eTypeError, "cannot freeze " "%+"PRIsVALUE, self);
- UNREACHABLE_RETURN(self);
-}
-
-/*
- * Document-method: Thread::Queue#num_waiting
- *
- * Returns the number of threads waiting on the queue.
- */
-
-static VALUE
-rb_queue_num_waiting(VALUE self)
+static void
+queue_clear(struct rb_queue *q)
{
- struct rb_queue *q = queue_ptr(self);
-
- return INT2NUM(q->num_waiting);
+ q->len = 0;
+ q->offset = 0;
}
-/*
- * Document-class: Thread::SizedQueue
- *
- * This class represents queues of specified size capacity. The push operation
- * may be blocked if the capacity is full.
- *
- * See Thread::Queue for an example of how a Thread::SizedQueue works.
- */
-
-/*
- * Document-method: SizedQueue::new
- * call-seq: new(max)
- *
- * Creates a fixed-length queue with a maximum size of +max+.
- */
-
static VALUE
-rb_szqueue_initialize(VALUE self, VALUE vmax)
+szqueue_initialize(rb_execution_context_t *ec, VALUE self, VALUE vmax)
{
- long max;
- struct rb_szqueue *sq = szqueue_ptr(self);
+ long max = NUM2LONG(vmax);
+ struct rb_szqueue *sq = raw_szqueue_ptr(self);
- max = NUM2LONG(vmax);
if (max <= 0) {
rb_raise(rb_eArgError, "queue size must be positive");
}
-
- RB_OBJ_WRITE(self, szqueue_list(sq), ary_buf_new());
+ ring_buffer_init(&sq->q, QUEUE_INITIAL_CAPA);
ccan_list_head_init(szqueue_waitq(sq));
ccan_list_head_init(szqueue_pushq(sq));
sq->max = max;
@@ -1229,74 +1099,12 @@ rb_szqueue_initialize(VALUE self, VALUE vmax)
return self;
}
-/*
- * Document-method: Thread::SizedQueue#close
- * call-seq:
- * close
- *
- * Similar to Thread::Queue#close.
- *
- * The difference is behavior with waiting enqueuing threads.
- *
- * If there are waiting enqueuing threads, they are interrupted by
- * raising ClosedQueueError('queue closed').
- */
-static VALUE
-rb_szqueue_close(VALUE self)
-{
- if (!queue_closed_p(self)) {
- struct rb_szqueue *sq = szqueue_ptr(self);
-
- FL_SET(self, QUEUE_CLOSED);
- wakeup_all(szqueue_waitq(sq));
- wakeup_all(szqueue_pushq(sq));
- }
- return self;
-}
-
-/*
- * Document-method: Thread::SizedQueue#max
- *
- * Returns the maximum size of the queue.
- */
-
-static VALUE
-rb_szqueue_max_get(VALUE self)
-{
- return LONG2NUM(szqueue_ptr(self)->max);
-}
-
-/*
- * Document-method: Thread::SizedQueue#max=
- * call-seq: max=(number)
- *
- * Sets the maximum size of the queue to the given +number+.
- */
-
-static VALUE
-rb_szqueue_max_set(VALUE self, VALUE vmax)
-{
- long max = NUM2LONG(vmax);
- long diff = 0;
- struct rb_szqueue *sq = szqueue_ptr(self);
-
- if (max <= 0) {
- rb_raise(rb_eArgError, "queue size must be positive");
- }
- if (max > sq->max) {
- diff = max - sq->max;
- }
- sq->max = max;
- sync_wakeup(szqueue_pushq(sq), diff);
- return vmax;
-}
-
static VALUE
rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_block, VALUE timeout)
{
struct rb_szqueue *sq = szqueue_ptr(self);
- if (queue_length(self, &sq->q) >= sq->max) {
+ if (sq->q.len >= sq->max) {
if (RTEST(non_block)) {
rb_raise(rb_eThreadError, "queue full");
}
@@ -1307,12 +1115,11 @@ rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_
}
rb_hrtime_t end = queue_timeout2hrtime(timeout);
- while (queue_length(self, &sq->q) >= sq->max) {
+ while (sq->q.len >= sq->max) {
if (queue_closed_p(self)) {
raise_closed_queue_error(self);
}
else {
- rb_execution_context_t *ec = GET_EC();
struct queue_waiter queue_waiter = {
.w = {.self = self, .th = ec->thread_ptr, .fiber = nonblocking_fiber(ec->fiber_ptr)},
.as = {.sq = sq}
@@ -1339,85 +1146,17 @@ rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_
}
static VALUE
-szqueue_do_pop(VALUE self, int should_block, VALUE timeout)
+rb_szqueue_pop(rb_execution_context_t *ec, VALUE self, VALUE non_block, VALUE timeout)
{
struct rb_szqueue *sq = szqueue_ptr(self);
- VALUE retval = queue_do_pop(self, &sq->q, should_block, timeout);
+ VALUE retval = queue_do_pop(ec, self, &sq->q, non_block, timeout);
- if (queue_length(self, &sq->q) < sq->max) {
+ if (sq->q.len < sq->max) {
wakeup_one(szqueue_pushq(sq));
}
return retval;
}
-static VALUE
-rb_szqueue_pop(rb_execution_context_t *ec, VALUE self, VALUE non_block, VALUE timeout)
-{
- return szqueue_do_pop(self, !RTEST(non_block), timeout);
-}
-
-/*
- * Document-method: Thread::SizedQueue#clear
- *
- * Removes all objects from the queue.
- */
-
-static VALUE
-rb_szqueue_clear(VALUE self)
-{
- struct rb_szqueue *sq = szqueue_ptr(self);
-
- rb_ary_clear(check_array(self, sq->q.que));
- wakeup_all(szqueue_pushq(sq));
- return self;
-}
-
-/*
- * Document-method: Thread::SizedQueue#length
- * call-seq:
- * length
- * size
- *
- * Returns the length of the queue.
- */
-
-static VALUE
-rb_szqueue_length(VALUE self)
-{
- struct rb_szqueue *sq = szqueue_ptr(self);
-
- return LONG2NUM(queue_length(self, &sq->q));
-}
-
-/*
- * Document-method: Thread::SizedQueue#num_waiting
- *
- * Returns the number of threads waiting on the queue.
- */
-
-static VALUE
-rb_szqueue_num_waiting(VALUE self)
-{
- struct rb_szqueue *sq = szqueue_ptr(self);
-
- return INT2NUM(sq->q.num_waiting + sq->num_waiting_push);
-}
-
-/*
- * Document-method: Thread::SizedQueue#empty?
- * call-seq: empty?
- *
- * Returns +true+ if the queue is empty.
- */
-
-static VALUE
-rb_szqueue_empty_p(VALUE self)
-{
- struct rb_szqueue *sq = szqueue_ptr(self);
-
- return RBOOL(queue_length(self, &sq->q) == 0);
-}
-
/* ConditionalVariable */
struct rb_condvar {
@@ -1425,34 +1164,6 @@ struct rb_condvar {
rb_serial_t fork_gen;
};
-/*
- * Document-class: Thread::ConditionVariable
- *
- * ConditionVariable objects augment class Mutex. Using condition variables,
- * it is possible to suspend while in the middle of a critical section until a
- * resource becomes available.
- *
- * Example:
- *
- * mutex = Thread::Mutex.new
- * resource = Thread::ConditionVariable.new
- *
- * a = Thread.new {
- * mutex.synchronize {
- * # Thread 'a' now needs the resource
- * resource.wait(mutex)
- * # 'a' can now have the resource
- * }
- * }
- *
- * b = Thread.new {
- * mutex.synchronize {
- * # Thread 'b' has finished using the resource
- * resource.signal
- * }
- * }
- */
-
static size_t
condvar_memsize(const void *ptr)
{
@@ -1494,21 +1205,8 @@ condvar_alloc(VALUE klass)
return obj;
}
-/*
- * Document-method: ConditionVariable::new
- *
- * Creates a new condition variable instance.
- */
-
-static VALUE
-rb_condvar_initialize(VALUE self)
-{
- struct rb_condvar *cv = condvar_ptr(self);
- ccan_list_head_init(&cv->waitq);
- return self;
-}
-
struct sleep_call {
+ rb_execution_context_t *ec;
VALUE mutex;
VALUE timeout;
};
@@ -1519,160 +1217,334 @@ static VALUE
do_sleep(VALUE args)
{
struct sleep_call *p = (struct sleep_call *)args;
- return rb_funcallv(p->mutex, id_sleep, 1, &p->timeout);
+ if (CLASS_OF(p->mutex) == rb_cMutex) {
+ return rb_mut_sleep(p->ec, p->mutex, p->timeout);
+ }
+ else {
+ return rb_funcallv(p->mutex, id_sleep, 1, &p->timeout);
+ }
}
-/*
- * Document-method: Thread::ConditionVariable#wait
- * call-seq: wait(mutex, timeout=nil)
- *
- * Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
- *
- * If +timeout+ is given, this method returns after +timeout+ seconds passed,
- * even if no other thread doesn't signal.
- *
- * Returns the slept result on +mutex+.
- */
-
static VALUE
-rb_condvar_wait(int argc, VALUE *argv, VALUE self)
+rb_condvar_wait(rb_execution_context_t *ec, VALUE self, VALUE mutex, VALUE timeout)
{
- rb_execution_context_t *ec = GET_EC();
-
struct rb_condvar *cv = condvar_ptr(self);
- struct sleep_call args;
-
- rb_scan_args(argc, argv, "11", &args.mutex, &args.timeout);
+ struct sleep_call args = {
+ .ec = ec,
+ .mutex = mutex,
+ .timeout = timeout,
+ };
struct sync_waiter sync_waiter = {
- .self = args.mutex,
+ .self = mutex,
.th = ec->thread_ptr,
.fiber = nonblocking_fiber(ec->fiber_ptr)
};
ccan_list_add_tail(&cv->waitq, &sync_waiter.node);
- return rb_ensure(do_sleep, (VALUE)&args, delete_from_waitq, (VALUE)&sync_waiter);
+ return rb_ec_ensure(ec, do_sleep, (VALUE)&args, delete_from_waitq, (VALUE)&sync_waiter);
}
-/*
- * Document-method: Thread::ConditionVariable#signal
- *
- * Wakes up the first thread in line waiting for this lock.
- */
-
static VALUE
-rb_condvar_signal(VALUE self)
+rb_condvar_signal(rb_execution_context_t *ec, VALUE self)
{
struct rb_condvar *cv = condvar_ptr(self);
wakeup_one(&cv->waitq);
return self;
}
-/*
- * Document-method: Thread::ConditionVariable#broadcast
- *
- * Wakes up all threads waiting for this lock.
- */
-
static VALUE
-rb_condvar_broadcast(VALUE self)
+rb_condvar_broadcast(rb_execution_context_t *ec, VALUE self)
{
struct rb_condvar *cv = condvar_ptr(self);
wakeup_all(&cv->waitq);
return self;
}
-NORETURN(static VALUE undumpable(VALUE obj));
-/* :nodoc: */
+/* Thread::Monitor */
+
+struct rb_monitor {
+ long count;
+ rb_serial_t ec_serial;
+ VALUE mutex;
+};
+
+static void
+monitor_mark(void *ptr)
+{
+ struct rb_monitor *mc = ptr;
+ rb_gc_mark_movable(mc->mutex);
+}
+
+static void
+monitor_compact(void *ptr)
+{
+ struct rb_monitor *mc = ptr;
+ mc->mutex = rb_gc_location(mc->mutex);
+}
+
+static const rb_data_type_t monitor_data_type = {
+ .wrap_struct_name = "monitor",
+ .function = {
+ .dmark = monitor_mark,
+ .dfree = RUBY_TYPED_DEFAULT_FREE,
+ .dsize = NULL, // Fully embeded
+ .dcompact = monitor_compact,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+};
+
static VALUE
-undumpable(VALUE obj)
+monitor_alloc(VALUE klass)
{
- rb_raise(rb_eTypeError, "can't dump %"PRIsVALUE, rb_obj_class(obj));
- UNREACHABLE_RETURN(Qnil);
+ struct rb_monitor *mc;
+ VALUE obj;
+
+ obj = TypedData_Make_Struct(klass, struct rb_monitor, &monitor_data_type, mc);
+ RB_OBJ_WRITE(obj, &mc->mutex, rb_mutex_new());
+ mc->ec_serial = 0;
+ mc->count = 0;
+
+ return obj;
+}
+
+static struct rb_monitor *
+monitor_ptr(VALUE monitor)
+{
+ struct rb_monitor *mc;
+ TypedData_Get_Struct(monitor, struct rb_monitor, &monitor_data_type, mc);
+ return mc;
+}
+
+static bool
+mc_owner_p(struct rb_monitor *mc, rb_serial_t current_fiber_serial)
+{
+ return mc->ec_serial == current_fiber_serial;
}
static VALUE
-define_thread_class(VALUE outer, const ID name, VALUE super)
+rb_monitor_try_enter(rb_execution_context_t *ec, VALUE monitor)
{
- VALUE klass = rb_define_class_id_under(outer, name, super);
- rb_const_set(rb_cObject, name, klass);
- return klass;
+ struct rb_monitor *mc = monitor_ptr(monitor);
+
+ rb_serial_t current_fiber_serial = rb_ec_serial(ec);
+ if (!mc_owner_p(mc, current_fiber_serial)) {
+ if (!rb_mut_trylock(ec, mc->mutex)) {
+ return Qfalse;
+ }
+ mc->ec_serial = current_fiber_serial;
+ mc->count = 0;
+ }
+ mc->count += 1;
+ return Qtrue;
}
+struct monitor_args {
+ VALUE monitor;
+ struct rb_monitor *mc;
+ rb_serial_t current_fiber_serial;
+ rb_execution_context_t *ec;
+};
+
static void
-Init_thread_sync(void)
+monitor_enter0(struct monitor_args *args)
+{
+ if (!mc_owner_p(args->mc, args->current_fiber_serial)) {
+ struct mutex_args mut_args = {
+ .self = args->mc->mutex,
+ .mutex = mutex_ptr(args->mc->mutex),
+ .ec= args->ec,
+ };
+ do_mutex_lock(&mut_args, 1);
+ args->mc->ec_serial = args->current_fiber_serial;
+ args->mc->count = 0;
+ }
+ args->mc->count++;
+}
+
+static VALUE
+rb_monitor_enter(rb_execution_context_t *ec, VALUE monitor)
{
-#undef rb_intern
-#if defined(TEACH_RDOC) && TEACH_RDOC == 42
- rb_cMutex = rb_define_class_under(rb_cThread, "Mutex", rb_cObject);
- rb_cConditionVariable = rb_define_class_under(rb_cThread, "ConditionVariable", rb_cObject);
- rb_cQueue = rb_define_class_under(rb_cThread, "Queue", rb_cObject);
- rb_cSizedQueue = rb_define_class_under(rb_cThread, "SizedQueue", rb_cObject);
-#endif
+ struct monitor_args args = {
+ .monitor = monitor,
+ .mc = monitor_ptr(monitor),
+ .ec = ec,
+ .current_fiber_serial = rb_ec_serial(ec),
+ };
+ monitor_enter0(&args);
+ return Qnil;
+}
-#define DEFINE_CLASS(name, super) \
- rb_c##name = define_thread_class(rb_cThread, rb_intern(#name), rb_c##super)
+static inline void
+monitor_check_owner0(struct monitor_args *args)
+{
+ if (!mc_owner_p(args->mc, args->current_fiber_serial)) {
+ rb_raise(rb_eThreadError, "current fiber not owner");
+ }
+}
+
+static VALUE
+rb_monitor_check_owner(rb_execution_context_t *ec, VALUE monitor)
+{
+ struct monitor_args args = {
+ .monitor = monitor,
+ .mc = monitor_ptr(monitor),
+ .ec = ec,
+ .current_fiber_serial = rb_ec_serial(ec),
+ };
+ monitor_check_owner0(&args);
+ return Qnil;
+}
+
+static void
+monitor_exit0(struct monitor_args *args)
+{
+ monitor_check_owner0(args);
+
+ if (args->mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)args->mc->count);
+ args->mc->count--;
+
+ if (args->mc->count == 0) {
+ args->mc->ec_serial = 0;
+
+ struct mutex_args mut_args = {
+ .self = args->mc->mutex,
+ .mutex = mutex_ptr(args->mc->mutex),
+ .ec= args->ec,
+ };
+ do_mutex_unlock(&mut_args);
+ }
+}
+
+static VALUE
+rb_monitor_exit(rb_execution_context_t *ec, VALUE monitor)
+{
+ struct monitor_args args = {
+ .monitor = monitor,
+ .mc = monitor_ptr(monitor),
+ .ec = ec,
+ .current_fiber_serial = rb_ec_serial(ec),
+ };
+ monitor_exit0(&args);
+ return Qnil;
+}
+
+static VALUE
+rb_monitor_locked_p(rb_execution_context_t *ec, VALUE monitor)
+{
+ struct rb_monitor *mc = monitor_ptr(monitor);
+ return rb_mutex_locked_p(mc->mutex);
+}
+
+static VALUE
+rb_monitor_owned_p(rb_execution_context_t *ec, VALUE monitor)
+{
+ struct rb_monitor *mc = monitor_ptr(monitor);
+ return RBOOL(rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc, rb_ec_serial(ec)));
+}
+
+static VALUE
+monitor_exit_for_cond(VALUE monitor)
+{
+ struct rb_monitor *mc = monitor_ptr(monitor);
+ long cnt = mc->count;
+ mc->ec_serial = 0;
+ mc->count = 0;
+ return LONG2NUM(cnt);
+}
+
+struct wait_for_cond_data {
+ VALUE monitor;
+ VALUE cond;
+ VALUE timeout;
+ VALUE count;
+};
+
+static VALUE
+monitor_wait_for_cond_body(VALUE v)
+{
+ struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
+ struct rb_monitor *mc = monitor_ptr(data->monitor);
+ // cond.wait(monitor.mutex, timeout)
+ VALUE signaled = rb_funcall(data->cond, rb_intern("wait"), 2, mc->mutex, data->timeout);
+ return RTEST(signaled) ? Qtrue : Qfalse;
+}
+
+static VALUE
+monitor_enter_for_cond(VALUE v)
+{
+ // assert(rb_mutex_owned_p(mc->mutex) == Qtrue)
+ // but rb_mutex_owned_p is not exported...
+
+ struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
+ struct rb_monitor *mc = monitor_ptr(data->monitor);
+ mc->ec_serial = rb_ec_serial(GET_EC());
+ mc->count = NUM2LONG(data->count);
+ return Qnil;
+}
+
+static VALUE
+rb_monitor_wait_for_cond(rb_execution_context_t *ec, VALUE monitor, VALUE cond, VALUE timeout)
+{
+ VALUE count = monitor_exit_for_cond(monitor);
+ struct wait_for_cond_data data = {
+ monitor,
+ cond,
+ timeout,
+ count,
+ };
+ return rb_ensure(monitor_wait_for_cond_body, (VALUE)&data,
+ monitor_enter_for_cond, (VALUE)&data);
+}
+
+static VALUE
+monitor_sync_ensure(VALUE v_args)
+{
+ monitor_exit0((struct monitor_args *)v_args);
+ return Qnil;
+}
+
+static VALUE
+rb_monitor_synchronize(rb_execution_context_t *ec, VALUE monitor)
+{
+ struct monitor_args args = {
+ .monitor = monitor,
+ .mc = monitor_ptr(monitor),
+ .ec = ec,
+ .current_fiber_serial = rb_ec_serial(ec),
+ };
+ monitor_enter0(&args);
+ return rb_ec_ensure(ec, do_ec_yield, (VALUE)ec, monitor_sync_ensure, (VALUE)&args);
+}
+
+static void
+Init_thread_sync(void)
+{
/* Mutex */
- DEFINE_CLASS(Mutex, Object);
+ rb_cMutex = rb_define_class_id_under(rb_cThread, rb_intern("Mutex"), rb_cObject);
rb_define_alloc_func(rb_cMutex, mutex_alloc);
- rb_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
- rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
- rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
- rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
- rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
- rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
- rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize_m, 0);
- rb_define_method(rb_cMutex, "owned?", rb_mutex_owned_p, 0);
/* Queue */
- DEFINE_CLASS(Queue, Object);
+ VALUE rb_cQueue = rb_define_class_id_under_no_pin(rb_cThread, rb_intern("Queue"), rb_cObject);
rb_define_alloc_func(rb_cQueue, queue_alloc);
rb_eClosedQueueError = rb_define_class("ClosedQueueError", rb_eStopIteration);
- rb_define_method(rb_cQueue, "initialize", rb_queue_initialize, -1);
- rb_undef_method(rb_cQueue, "initialize_copy");
- rb_define_method(rb_cQueue, "marshal_dump", undumpable, 0);
- rb_define_method(rb_cQueue, "close", rb_queue_close, 0);
- rb_define_method(rb_cQueue, "closed?", rb_queue_closed_p, 0);
- rb_define_method(rb_cQueue, "push", rb_queue_push, 1);
- rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0);
- rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0);
- rb_define_method(rb_cQueue, "length", rb_queue_length, 0);
- rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
- rb_define_method(rb_cQueue, "freeze", rb_queue_freeze, 0);
-
- rb_define_alias(rb_cQueue, "enq", "push");
- rb_define_alias(rb_cQueue, "<<", "push");
- rb_define_alias(rb_cQueue, "size", "length");
-
- DEFINE_CLASS(SizedQueue, Queue);
+ VALUE rb_cSizedQueue = rb_define_class_id_under_no_pin(rb_cThread, rb_intern("SizedQueue"), rb_cQueue);
rb_define_alloc_func(rb_cSizedQueue, szqueue_alloc);
- rb_define_method(rb_cSizedQueue, "initialize", rb_szqueue_initialize, 1);
- rb_define_method(rb_cSizedQueue, "close", rb_szqueue_close, 0);
- rb_define_method(rb_cSizedQueue, "max", rb_szqueue_max_get, 0);
- rb_define_method(rb_cSizedQueue, "max=", rb_szqueue_max_set, 1);
- rb_define_method(rb_cSizedQueue, "empty?", rb_szqueue_empty_p, 0);
- rb_define_method(rb_cSizedQueue, "clear", rb_szqueue_clear, 0);
- rb_define_method(rb_cSizedQueue, "length", rb_szqueue_length, 0);
- rb_define_method(rb_cSizedQueue, "num_waiting", rb_szqueue_num_waiting, 0);
- rb_define_alias(rb_cSizedQueue, "size", "length");
-
/* CVar */
- DEFINE_CLASS(ConditionVariable, Object);
+ VALUE rb_cConditionVariable = rb_define_class_id_under_no_pin(rb_cThread, rb_intern("ConditionVariable"), rb_cObject);
rb_define_alloc_func(rb_cConditionVariable, condvar_alloc);
id_sleep = rb_intern("sleep");
- rb_define_method(rb_cConditionVariable, "initialize", rb_condvar_initialize, 0);
- rb_undef_method(rb_cConditionVariable, "initialize_copy");
- rb_define_method(rb_cConditionVariable, "marshal_dump", undumpable, 0);
- rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, -1);
- rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0);
- rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0);
+ /* Monitor */
+ VALUE rb_cMonitor = rb_define_class_id_under_no_pin(rb_cThread, rb_intern("Monitor"), rb_cObject);
+ rb_define_alloc_func(rb_cMonitor, monitor_alloc);
+ rb_provide("monitor.so");
rb_provide("thread.rb");
}
diff --git a/thread_sync.rb b/thread_sync.rb
index f8fa69900b..18c7cc7adc 100644
--- a/thread_sync.rb
+++ b/thread_sync.rb
@@ -1,5 +1,62 @@
+# frozen_string_literal: true
+
class Thread
+ # The Thread::Queue class implements multi-producer, multi-consumer
+ # queues. It is especially useful in threaded programming when
+ # information must be exchanged safely between multiple threads. The
+ # Thread::Queue class implements all the required locking semantics.
+ #
+ # The class implements FIFO (first in, first out) type of queue.
+ # In a FIFO queue, the first tasks added are the first retrieved.
+ #
+ # Example:
+ #
+ # queue = Thread::Queue.new
+ #
+ # producer = Thread.new do
+ # 5.times do |i|
+ # sleep rand(i) # simulate expense
+ # queue << i
+ # puts "#{i} produced"
+ # end
+ # end
+ #
+ # consumer = Thread.new do
+ # 5.times do |i|
+ # value = queue.pop
+ # sleep rand(i/2) # simulate expense
+ # puts "consumed #{value}"
+ # end
+ # end
+ #
+ # consumer.join
class Queue
+ # Document-method: Queue::new
+ #
+ # call-seq:
+ # Thread::Queue.new -> empty_queue
+ # Thread::Queue.new(enumerable) -> queue
+ #
+ # Creates a new queue instance, optionally using the contents of an +enumerable+
+ # for its initial state.
+ #
+ # Example:
+ #
+ # q = Thread::Queue.new
+ # #=> #<Thread::Queue:0x00007ff7501110d0>
+ # q.empty?
+ # #=> true
+ #
+ # q = Thread::Queue.new([1, 2, 3])
+ # #=> #<Thread::Queue:0x00007ff7500ec500>
+ # q.empty?
+ # #=> false
+ # q.pop
+ # #=> 1
+ def initialize(enumerable = nil)
+ Primitive.queue_initialize(enumerable)
+ end
+
# call-seq:
# pop(non_block=false, timeout: nil)
#
@@ -19,9 +76,129 @@ class Thread
end
alias_method :deq, :pop
alias_method :shift, :pop
+
+ undef_method :initialize_copy
+
+ # call-seq:
+ # push(object)
+ # enq(object)
+ # <<(object)
+ #
+ # Pushes the given +object+ to the queue.
+ def push(object)
+ Primitive.cexpr!('queue_do_push(self, queue_ptr(self), object)')
+ end
+ alias_method :enq, :push
+ alias_method :<<, :push
+
+ # call-seq:
+ # close
+ #
+ # Closes the queue. A closed queue cannot be re-opened.
+ #
+ # After the call to close completes, the following are true:
+ #
+ # - +closed?+ will return true
+ #
+ # - +close+ will be ignored.
+ #
+ # - calling enq/push/<< will raise a +ClosedQueueError+.
+ #
+ # - when +empty?+ is false, calling deq/pop/shift will return an object
+ # from the queue as usual.
+ # - when +empty?+ is true, deq(false) will not suspend the thread and will return nil.
+ # deq(true) will raise a +ThreadError+.
+ #
+ # ClosedQueueError is inherited from StopIteration, so that you can break loop block.
+ #
+ # Example:
+ #
+ # q = Thread::Queue.new
+ # Thread.new{
+ # while e = q.deq # wait for nil to break loop
+ # # ...
+ # end
+ # }
+ # q.close
+ def close
+ Primitive.cstmt! %{
+ if (!queue_closed_p(self)) {
+ FL_SET_RAW(self, QUEUE_CLOSED);
+
+ wakeup_all(&queue_ptr(self)->waitq);
+ }
+
+ return self;
+ }
+ end
+
+ # call-seq: closed?
+ #
+ # Returns +true+ if the queue is closed.
+ def closed?
+ Primitive.cexpr!('RBOOL(FL_TEST_RAW(self, QUEUE_CLOSED))')
+ end
+
+ # call-seq:
+ # length
+ # size
+ #
+ # Returns the length of the queue.
+ def length
+ Primitive.cexpr!('LONG2NUM(queue_ptr(self)->len)')
+ end
+ alias_method :size, :length
+
+ # call-seq: empty?
+ #
+ # Returns +true+ if the queue is empty.
+ def empty?
+ Primitive.cexpr!('RBOOL(queue_ptr(self)->len == 0)')
+ end
+
+ # Removes all objects from the queue.
+ def clear
+ Primitive.cstmt! %{
+ queue_clear(queue_ptr(self));
+ return self;
+ }
+ end
+
+ # call-seq:
+ # num_waiting
+ #
+ # Returns the number of threads waiting on the queue.
+ def num_waiting
+ Primitive.cexpr!('INT2NUM(queue_ptr(self)->num_waiting)')
+ end
+
+ def marshal_dump # :nodoc:
+ raise TypeError, "can't dump #{self.class}"
+ end
+
+ # call-seq:
+ # freeze
+ #
+ # The queue can't be frozen, so this method raises an exception:
+ # Thread::Queue.new.freeze # Raises TypeError (cannot freeze #<Thread::Queue:0x...>)
+ def freeze
+ raise TypeError, "cannot freeze #{self}"
+ end
end
- class SizedQueue
+ # This class represents queues of specified size capacity. The push operation
+ # may be blocked if the capacity is full.
+ #
+ # See Thread::Queue for an example of how a Thread::SizedQueue works.
+ class SizedQueue < Queue
+ # Document-method: SizedQueue::new
+ # call-seq: new(max)
+ #
+ # Creates a fixed-length queue with a maximum size of +max+.
+ def initialize(vmax)
+ Primitive.szqueue_initialize(vmax)
+ end
+
# call-seq:
# pop(non_block=false, timeout: nil)
#
@@ -64,5 +241,475 @@ class Thread
end
alias_method :enq, :push
alias_method :<<, :push
+
+ # call-seq:
+ # close
+ #
+ # Similar to Thread::Queue#close.
+ #
+ # The difference is behavior with waiting enqueuing threads.
+ #
+ # If there are waiting enqueuing threads, they are interrupted by
+ # raising ClosedQueueError('queue closed').
+ def close
+ Primitive.cstmt! %{
+ if (!queue_closed_p(self)) {
+ struct rb_szqueue *sq = szqueue_ptr(self);
+
+ FL_SET(self, QUEUE_CLOSED);
+ wakeup_all(szqueue_waitq(sq));
+ wakeup_all(szqueue_pushq(sq));
+ }
+ return self;
+ }
+ end
+
+ # Removes all objects from the queue.
+ def clear
+ Primitive.cstmt! %{
+ struct rb_szqueue *sq = szqueue_ptr(self);
+ queue_clear(&sq->q);
+ wakeup_all(szqueue_pushq(sq));
+ return self;
+ }
+ end
+
+ # Returns the number of threads waiting on the queue.
+ def num_waiting
+ Primitive.cstmt! %{
+ struct rb_szqueue *sq = szqueue_ptr(self);
+ return INT2NUM(sq->q.num_waiting + sq->num_waiting_push);
+ }
+ end
+
+ # Returns the maximum size of the queue.
+ def max
+ Primitive.cexpr!('LONG2NUM(szqueue_ptr(self)->max)')
+ end
+
+ # call-seq: max=(number)
+ #
+ # Sets the maximum size of the queue to the given +number+.
+ def max=(vmax)
+ Primitive.cstmt! %{
+ long max = NUM2LONG(vmax);
+ if (max <= 0) {
+ rb_raise(rb_eArgError, "queue size must be positive");
+ }
+
+ long diff = 0;
+ struct rb_szqueue *sq = szqueue_ptr(self);
+
+ if (max > sq->max) {
+ diff = max - sq->max;
+ }
+ sq->max = max;
+ sync_wakeup(szqueue_pushq(sq), diff);
+ return vmax;
+ }
+ end
+ end
+
+ # Thread::Mutex implements a simple semaphore that can be used to
+ # coordinate access to shared data from multiple concurrent threads.
+ #
+ # Example:
+ #
+ # semaphore = Thread::Mutex.new
+ #
+ # a = Thread.new {
+ # semaphore.synchronize {
+ # # access shared resource
+ # }
+ # }
+ #
+ # b = Thread.new {
+ # semaphore.synchronize {
+ # # access shared resource
+ # }
+ # }
+ class Mutex
+ # call-seq:
+ # Thread::Mutex.new -> mutex
+ #
+ # Creates a new Mutex
+ def initialize
+ end
+
+ # call-seq:
+ # mutex.locked? -> true or false
+ #
+ # Returns +true+ if this lock is currently held by some thread.
+ def locked?
+ Primitive.cexpr! %q{ RBOOL(mutex_locked_p(mutex_ptr(self))) }
+ end
+
+ # call-seq:
+ # mutex.owned? -> true or false
+ #
+ # Returns +true+ if this lock is currently held by current thread.
+ def owned?
+ Primitive.rb_mut_owned_p
+ end
+
+ # call-seq:
+ # mutex.lock -> self
+ #
+ # Attempts to grab the lock and waits if it isn't available.
+ # Raises +ThreadError+ if +mutex+ was locked by the current thread.
+ def lock
+ Primitive.rb_mut_lock
+ end
+
+ # call-seq:
+ # mutex.try_lock -> true or false
+ #
+ # Attempts to obtain the lock and returns immediately. Returns +true+ if the
+ # lock was granted.
+ def try_lock
+ Primitive.rb_mut_trylock
+ end
+
+ # call-seq:
+ # mutex.lock -> self
+ #
+ # Attempts to grab the lock and waits if it isn't available.
+ # Raises +ThreadError+ if +mutex+ was locked by the current thread.
+ def unlock
+ Primitive.rb_mut_unlock
+ end
+
+ # call-seq:
+ # mutex.synchronize { ... } -> result of the block
+ #
+ # Obtains a lock, runs the block, and releases the lock when the block
+ # completes. See the example under Thread::Mutex.
+ def synchronize
+ raise ThreadError, "must be called with a block" unless defined?(yield)
+
+ Primitive.rb_mut_synchronize
+ end
+
+ # call-seq:
+ # mutex.sleep(timeout = nil) -> number or nil
+ #
+ # Releases the lock and sleeps +timeout+ seconds if it is given and
+ # non-nil or forever. Raises +ThreadError+ if +mutex+ wasn't locked by
+ # the current thread.
+ #
+ # When the thread is next woken up, it will attempt to reacquire
+ # the lock.
+ #
+ # Note that this method can wakeup without explicit Thread#wakeup call.
+ # For example, receiving signal and so on.
+ #
+ # Returns the slept time in seconds if woken up, or +nil+ if timed out.
+ def sleep(timeout = nil)
+ Primitive.rb_mut_sleep(timeout)
+ end
+ end
+
+ # ConditionVariable objects augment class Mutex. Using condition variables,
+ # it is possible to suspend while in the middle of a critical section until a
+ # condition is met, such as a resource becomes available.
+ #
+ # Due to non-deterministic scheduling and spurious wake-ups, users of
+ # condition variables should always use a separate boolean predicate (such as
+ # reading from a boolean variable) to check if the condition is actually met
+ # before starting to wait, and should wait in a loop, re-checking the
+ # condition every time the ConditionVariable is waken up. The idiomatic way
+ # of using condition variables is calling the +wait+ method in an +until+
+ # loop with the predicate as the loop condition.
+ #
+ # condvar.wait(mutex) until condition_is_met
+ #
+ # In the example below, we use the boolean variable +resource_available+
+ # (which is protected by +mutex+) to indicate the availability of the
+ # resource, and use +condvar+ to wait for that variable to become true. Note
+ # that:
+ #
+ # 1. Thread +b+ may be scheduled before thread +a1+ and +a2+, and may run so
+ # fast that it have already made the resource available before either
+ # +a1+ or +a2+ starts. Therefore, +a1+ and +a2+ should check if
+ # +resource_available+ is already true before starting to wait.
+ # 2. The +wait+ method may spuriously wake up without signalling. Therefore,
+ # thread +a1+ and +a2+ should recheck +resource_available+ after the
+ # +wait+ method returns, and go back to wait if the condition is not
+ # actually met.
+ # 3. It is possible that thread +a2+ starts right after thread +a1+ is waken
+ # up by +b+. Thread +a2+ may have acquired the +mutex+ and consumed the
+ # resource before thread +a1+ acquires the +mutex+. This necessitates
+ # rechecking after +wait+, too.
+ #
+ # Example:
+ #
+ # mutex = Thread::Mutex.new
+ #
+ # resource_available = false
+ # condvar = Thread::ConditionVariable.new
+ #
+ # a1 = Thread.new {
+ # # Thread 'a1' waits for the resource to become available and consumes
+ # # the resource.
+ # mutex.synchronize {
+ # condvar.wait(mutex) until resource_available
+ # # After the loop, 'resource_available' is guaranteed to be true.
+ #
+ # resource_available = false
+ # puts "a1 consumed the resource"
+ # }
+ # }
+ #
+ # a2 = Thread.new {
+ # # Thread 'a2' behaves like 'a1'.
+ # mutex.synchronize {
+ # condvar.wait(mutex) until resource_available
+ # resource_available = false
+ # puts "a2 consumed the resource"
+ # }
+ # }
+ #
+ # b = Thread.new {
+ # # Thread 'b' periodically makes the resource available.
+ # loop {
+ # mutex.synchronize {
+ # resource_available = true
+ #
+ # # Notify one waiting thread if any. It is possible that neither
+ # # 'a1' nor 'a2 is waiting on 'condvar' at this moment. That's OK.
+ # condvar.signal
+ # }
+ # sleep 1
+ # }
+ # }
+ #
+ # # Eventually both 'a1' and 'a2' will have their resources, albeit in an
+ # # unspecified order.
+ # [a1, a2].each {|th| th.join}
+ class ConditionVariable
+ # Document-method: ConditionVariable::new
+ #
+ # Creates a new condition variable instance.
+ def initialize
+ end
+
+ undef_method :initialize_copy
+
+ # :nodoc:
+ def marshal_dump
+ raise TypeError, "can't dump #{self.class}"
+ end
+
+ # Document-method: Thread::ConditionVariable#signal
+ #
+ # Wakes up the first thread in line waiting for this lock.
+ def signal
+ Primitive.rb_condvar_signal
+ end
+
+ # Document-method: Thread::ConditionVariable#broadcast
+ #
+ # Wakes up all threads waiting for this lock.
+ def broadcast
+ Primitive.rb_condvar_broadcast
+ end
+
+ # Document-method: Thread::ConditionVariable#wait
+ # call-seq: wait(mutex, timeout=nil)
+ #
+ # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
+ #
+ # If +timeout+ is given, this method returns after +timeout+ seconds passed,
+ # even if no other thread doesn't signal.
+ #
+ # This method may wake up spuriously due to underlying implementation details.
+ #
+ # Returns the slept result on +mutex+.
+ def wait(mutex, timeout=nil)
+ Primitive.rb_condvar_wait(mutex, timeout)
+ end
+ end
+
+ # Use the Monitor class when you want to have a lock object for blocks with
+ # mutual exclusion.
+ #
+ # lock = Monitor.new
+ # lock.synchronize do
+ # # exclusive access
+ # end
+ #
+ # Contrary to Mutex, Monitor is reentrant:
+ #
+ # lock = Monitor.new
+ # lock.synchronize do
+ # lock.synchronize do
+ # # exclusive access
+ # end
+ # end
+ class Monitor
+ # call-seq:
+ # synchronize { } -> result of the block
+ #
+ # Enters exclusive section and executes the block. Leaves the exclusive
+ # section automatically when the block exits. See example under
+ # +MonitorMixin+.
+ def synchronize(&)
+ Primitive.rb_monitor_synchronize
+ end
+
+ # call-seq:
+ # try_enter -> true or false
+ #
+ # Attempts to enter exclusive section. Returns +false+ if lock fails.
+ def try_enter
+ Primitive.rb_monitor_try_enter
+ end
+
+ # call-seq:
+ # enter -> nil
+ #
+ # Enters exclusive section.
+ def enter
+ Primitive.rb_monitor_enter
+ end
+
+ # call-seq:
+ # exit -> nil
+ #
+ # Leaves exclusive section.
+ def exit
+ Primitive.rb_monitor_exit
+ end
+
+ # internal methods for MonitorMixin
+ def mon_check_owner # :nodoc:
+ Primitive.rb_monitor_check_owner
+ end
+
+ def mon_locked? # :nodoc:
+ Primitive.rb_monitor_locked_p
+ end
+
+ def mon_owned? # :nodoc:
+ Primitive.rb_monitor_owned_p
+ end
+
+ # internal methods for MonitorMixin::ConditionVariable
+ def wait_for_cond(cond, timeout) # :nodoc:
+ Primitive.rb_monitor_wait_for_cond(cond, timeout)
+ end
+
+ # Creates a new Monitor::ConditionVariable associated with the
+ # Monitor object.
+ #
+ def new_cond
+ ConditionVariable.new(self)
+ end
+
+ # Condition variables, allow to suspend the current thread while in
+ # the middle of a critical section until a condition is met, such as
+ # a resource being available.
+ #
+ # Example:
+ #
+ # monitor = Thread::Monitor.new
+ #
+ # resource_available = false
+ # condvar = monitor.new_cond
+ #
+ # a1 = Thread.new {
+ # # Thread 'a1' waits for the resource to become available and consumes
+ # # the resource.
+ # monitor.synchronize {
+ # condvar.wait_until { resource_available }
+ # # After the loop, 'resource_available' is guaranteed to be true.
+ #
+ # resource_available = false
+ # puts "a1 consumed the resource"
+ # }
+ # }
+ #
+ # a2 = Thread.new {
+ # # Thread 'a2' behaves like 'a1'.
+ # monitor.synchronize {
+ # condvar.wait_until { resource_available }
+ # resource_available = false
+ # puts "a2 consumed the resource"
+ # }
+ # }
+ #
+ # b = Thread.new {
+ # # Thread 'b' periodically makes the resource available.
+ # loop {
+ # monitor.synchronize {
+ # resource_available = true
+ #
+ # # Notify one waiting thread if any. It is possible that neither
+ # # 'a1' nor 'a2 is waiting on 'condvar' at this moment. That's OK.
+ # condvar.signal
+ # }
+ # sleep 1
+ # }
+ # }
+ #
+ # # Eventually both 'a1' and 'a2' will have their resources, albeit in an
+ # # unspecified order.
+ # [a1, a2].each {|th| th.join}
+ class ConditionVariable
+ def initialize(monitor) # :nodoc:
+ @monitor = monitor
+ @cond = Thread::ConditionVariable.new
+ end
+
+ # Releases the lock held in the associated monitor and waits; reacquires the lock on wakeup.
+ #
+ # If +timeout+ is given, this method returns after +timeout+ seconds passed,
+ # even if no other thread doesn't signal.
+ #
+ def wait(timeout = nil)
+ @monitor.mon_check_owner
+ @monitor.wait_for_cond(@cond, timeout)
+ end
+
+ #
+ # Calls wait repeatedly while the given block yields a truthy value.
+ #
+ def wait_while
+ while yield
+ wait
+ end
+ end
+
+ #
+ # Calls wait repeatedly until the given block yields a truthy value.
+ #
+ def wait_until
+ until yield
+ wait
+ end
+ end
+
+ #
+ # Wakes up the first thread in line waiting for this lock.
+ #
+ def signal
+ @monitor.mon_check_owner
+ @cond.signal
+ end
+
+ #
+ # Wakes up all threads waiting for this lock.
+ #
+ def broadcast
+ @monitor.mon_check_owner
+ @cond.broadcast
+ end
+ end
end
end
+
+Mutex = Thread::Mutex # :nodoc:
+Monitor = Thread::Monitor # :nodoc:
+ConditionVariable = Thread::ConditionVariable # :nodoc:
+Queue = Thread::Queue # :nodoc:
+SizedQueue = Thread::SizedQueue # :nodoc:
diff --git a/thread_win32.c b/thread_win32.c
index 3bca58cbac..a2ce3b9d15 100644
--- a/thread_win32.c
+++ b/thread_win32.c
@@ -132,18 +132,22 @@ thread_sched_to_running(struct rb_thread_sched *sched, rb_thread_t *th)
if (GVL_DEBUG) fprintf(stderr, "gvl acquire (%p): acquire\n", th);
}
-#define thread_sched_to_dead thread_sched_to_waiting
-
static void
-thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th)
+thread_sched_to_waiting(struct rb_thread_sched *sched, rb_thread_t *th, bool yield_immediately)
{
ReleaseMutex(sched->lock);
}
static void
+thread_sched_to_dead(struct rb_thread_sched *sched, rb_thread_t *th)
+{
+ thread_sched_to_waiting(sched, th, true);
+}
+
+static void
thread_sched_yield(struct rb_thread_sched *sched, rb_thread_t *th)
{
- thread_sched_to_waiting(sched, th);
+ thread_sched_to_waiting(sched, th, true);
native_thread_yield();
thread_sched_to_running(sched, th);
}
@@ -617,6 +621,12 @@ native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame)
th->ec->machine.stack_maxsize = size - space;
}
+static void
+native_thread_destroy_atfork(struct rb_native_thread *nt)
+{
+ /* no-op */
+}
+
#ifndef InterlockedExchangePointer
#define InterlockedExchangePointer(t, v) \
(void *)InterlockedExchange((long *)(t), (long)(v))
@@ -798,14 +808,14 @@ rb_thread_create_timer_thread(void)
static int
native_stop_timer_thread(void)
{
- int stopped = --system_working <= 0;
- if (stopped) {
- SetEvent(timer_thread.lock);
- native_thread_join(timer_thread.id);
- CloseHandle(timer_thread.lock);
- timer_thread.lock = 0;
- }
- return stopped;
+ RUBY_ATOMIC_SET(system_working, 0);
+
+ SetEvent(timer_thread.lock);
+ native_thread_join(timer_thread.id);
+ CloseHandle(timer_thread.lock);
+ timer_thread.lock = 0;
+
+ return 1;
}
static void
@@ -875,7 +885,8 @@ native_thread_native_thread_id(rb_thread_t *th)
#define USE_NATIVE_THREAD_NATIVE_THREAD_ID 1
void
-rb_add_running_thread(rb_thread_t *th){
+rb_add_running_thread(rb_thread_t *th)
+{
// do nothing
}
@@ -921,6 +932,7 @@ vm_barrier_finish_p(rb_vm_t *vm)
vm->ractor.blocking_cnt);
VM_ASSERT(vm->ractor.blocking_cnt <= vm->ractor.cnt);
+
return vm->ractor.blocking_cnt == vm->ractor.cnt;
}
@@ -946,7 +958,7 @@ rb_ractor_sched_barrier_start(rb_vm_t *vm, rb_ractor_t *cr)
// wait
while (!vm_barrier_finish_p(vm)) {
- rb_vm_cond_wait(vm, &vm->ractor.sync.barrier_cond);
+ rb_vm_cond_wait(vm, &vm->ractor.sync.barrier_complete_cond);
}
RUBY_DEBUG_LOG("cnt:%u barrier success", vm->ractor.sync.barrier_cnt);
@@ -956,9 +968,7 @@ rb_ractor_sched_barrier_start(rb_vm_t *vm, rb_ractor_t *cr)
vm->ractor.sync.barrier_waiting = false;
vm->ractor.sync.barrier_cnt++;
- ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
- rb_native_cond_signal(&r->barrier_wait_cond);
- }
+ rb_native_cond_broadcast(&vm->ractor.sync.barrier_release_cond);
}
void
@@ -982,7 +992,7 @@ rb_ractor_sched_barrier_join(rb_vm_t *vm, rb_ractor_t *cr)
if (vm_barrier_finish_p(vm)) {
RUBY_DEBUG_LOG("wakeup barrier owner");
- rb_native_cond_signal(&vm->ractor.sync.barrier_cond);
+ rb_native_cond_signal(&vm->ractor.sync.barrier_complete_cond);
}
else {
RUBY_DEBUG_LOG("wait for barrier finish");
@@ -990,10 +1000,7 @@ rb_ractor_sched_barrier_join(rb_vm_t *vm, rb_ractor_t *cr)
// wait for restart
while (barrier_cnt == vm->ractor.sync.barrier_cnt) {
- vm->ractor.sync.lock_owner = NULL;
- rb_native_cond_wait(&cr->barrier_wait_cond, &vm->ractor.sync.lock);
- VM_ASSERT(vm->ractor.sync.lock_owner == NULL);
- vm->ractor.sync.lock_owner = cr;
+ rb_vm_cond_wait(vm, &vm->ractor.sync.barrier_release_cond);
}
RUBY_DEBUG_LOG("barrier is released. Acquire vm_lock");
@@ -1017,4 +1024,10 @@ rb_thread_prevent_fork(void *(*func)(void *), void *data)
return func(data);
}
+void
+rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size)
+{
+ // no-op
+}
+
#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
diff --git a/time.c b/time.c
index 1b02cf4259..c3bda3f6af 100644
--- a/time.c
+++ b/time.c
@@ -36,6 +36,7 @@
#include "internal/array.h"
#include "internal/hash.h"
#include "internal/compar.h"
+#include "internal/error.h"
#include "internal/numeric.h"
#include "internal/rational.h"
#include "internal/string.h"
@@ -46,7 +47,7 @@
#include "timev.h"
#if defined(_WIN32)
-# include "timezoneapi.h" /* DYNAMIC_TIME_ZONE_INFORMATION */
+# include <timezoneapi.h> /* DYNAMIC_TIME_ZONE_INFORMATION */
#endif
#include "builtin.h"
@@ -249,6 +250,7 @@ divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
# define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w))
#endif
+#define SIZEOF_WIDEINT SIZEOF_INT64_T
#define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
#define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
#define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w))
@@ -563,8 +565,7 @@ NORETURN(static void num_exact_fail(VALUE v));
static void
num_exact_fail(VALUE v)
{
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into an exact number",
- rb_obj_class(v));
+ rb_cant_convert(v, "an exact number");
}
static VALUE
@@ -745,6 +746,8 @@ get_tzname(int dst)
}
#endif
+static void ruby_reset_leap_second_info(void);
+
void
ruby_reset_timezone(const char *val)
{
@@ -980,7 +983,6 @@ zone_str(const char *zone)
{
const char *p;
int ascii_only = 1;
- VALUE str;
size_t len;
if (zone == NULL) {
@@ -996,18 +998,18 @@ zone_str(const char *zone)
}
len = p - zone;
if (ascii_only) {
- str = rb_usascii_str_new(zone, len);
+ return rb_enc_interned_str(zone, len, rb_usascii_encoding());
}
else {
#ifdef _WIN32
- str = rb_utf8_str_new(zone, len);
+ VALUE str = rb_utf8_str_new(zone, len);
/* until we move to UTF-8 on Windows completely */
str = rb_str_export_locale(str);
+ return rb_fstring(str);
#else
- str = rb_enc_str_new(zone, len, rb_locale_encoding());
+ return rb_enc_interned_str(zone, len, rb_locale_encoding());
#endif
}
- return rb_fstring(str);
}
static void
@@ -1887,39 +1889,25 @@ force_make_tm(VALUE time, struct time_object *tobj)
}
static void
-time_mark(void *ptr)
+time_mark_and_move(void *ptr)
{
struct time_object *tobj = ptr;
- if (!FIXWV_P(tobj->timew)) {
- rb_gc_mark_movable(WIDEVAL_GET(tobj->timew));
+ if (!WIDEVALUE_IS_WIDER || !FIXWV_P(tobj->timew)) {
+ rb_gc_mark_and_move((VALUE *)&WIDEVAL_GET(tobj->timew));
}
- rb_gc_mark_movable(tobj->vtm.year);
- rb_gc_mark_movable(tobj->vtm.subsecx);
- rb_gc_mark_movable(tobj->vtm.utc_offset);
- rb_gc_mark_movable(tobj->vtm.zone);
-}
-
-static void
-time_compact(void *ptr)
-{
- struct time_object *tobj = ptr;
- if (!FIXWV_P(tobj->timew)) {
- WIDEVAL_GET(tobj->timew) = rb_gc_location(WIDEVAL_GET(tobj->timew));
- }
-
- tobj->vtm.year = rb_gc_location(tobj->vtm.year);
- tobj->vtm.subsecx = rb_gc_location(tobj->vtm.subsecx);
- tobj->vtm.utc_offset = rb_gc_location(tobj->vtm.utc_offset);
- tobj->vtm.zone = rb_gc_location(tobj->vtm.zone);
+ rb_gc_mark_and_move(&tobj->vtm.year);
+ rb_gc_mark_and_move(&tobj->vtm.subsecx);
+ rb_gc_mark_and_move(&tobj->vtm.utc_offset);
+ rb_gc_mark_and_move(&tobj->vtm.zone);
}
static const rb_data_type_t time_data_type = {
.wrap_struct_name = "time",
.function = {
- .dmark = time_mark,
+ .dmark = time_mark_and_move,
.dfree = RUBY_TYPED_DEFAULT_FREE,
.dsize = NULL,
- .dcompact = time_compact,
+ .dcompact = time_mark_and_move,
},
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
};
@@ -1968,11 +1956,11 @@ time_modify(VALUE time)
}
static wideval_t
-timenano2timew(time_t sec, long nsec)
+timenano2timew(wideint_t sec, long nsec)
{
wideval_t timew;
- timew = rb_time_magnify(TIMET2WV(sec));
+ timew = rb_time_magnify(WINT2WV(sec));
if (nsec)
timew = wadd(timew, wmulquoll(WINT2WV(nsec), TIME_SCALE, 1000000000));
return timew;
@@ -2306,14 +2294,14 @@ utc_offset_arg(VALUE arg)
static void
zone_set_offset(VALUE zone, struct time_object *tobj,
- wideval_t tlocal, wideval_t tutc)
+ wideval_t tlocal, wideval_t tutc, VALUE time)
{
/* tlocal and tutc must be unmagnified and in seconds */
wideval_t w = wsub(tlocal, tutc);
VALUE off = w2v(w);
validate_utc_offset(off);
- tobj->vtm.utc_offset = off;
- tobj->vtm.zone = zone;
+ RB_OBJ_WRITE(time, &tobj->vtm.utc_offset, off);
+ RB_OBJ_WRITE(time, &tobj->vtm.zone, zone);
TZMODE_SET_LOCALTIME(tobj);
}
@@ -2428,7 +2416,7 @@ zone_timelocal(VALUE zone, VALUE time)
if (UNDEF_P(utc)) return 0;
s = extract_time(utc);
- zone_set_offset(zone, tobj, t, s);
+ zone_set_offset(zone, tobj, t, s, time);
s = rb_time_magnify(s);
if (tobj->vtm.subsecx != INT2FIX(0)) {
s = wadd(s, v2w(tobj->vtm.subsecx));
@@ -2457,7 +2445,7 @@ zone_localtime(VALUE zone, VALUE time)
s = extract_vtm(local, time, tobj, subsecx);
tobj->vtm.tm_got = 1;
- zone_set_offset(zone, tobj, s, t);
+ zone_set_offset(zone, tobj, s, t, time);
zone_set_dst(zone, tobj, tm);
RB_GC_GUARD(time);
@@ -2747,15 +2735,15 @@ only_year:
}
static void
-subsec_normalize(time_t *secp, long *subsecp, const long maxsubsec)
+subsec_normalize(wideint_t *secp, long *subsecp, const long maxsubsec)
{
- time_t sec = *secp;
+ wideint_t sec = *secp;
long subsec = *subsecp;
long sec2;
if (UNLIKELY(subsec >= maxsubsec)) { /* subsec positive overflow */
sec2 = subsec / maxsubsec;
- if (TIMET_MAX - sec2 < sec) {
+ if (WIDEINT_MAX - sec2 < sec) {
rb_raise(rb_eRangeError, "out of Time range");
}
subsec -= sec2 * maxsubsec;
@@ -2763,16 +2751,12 @@ subsec_normalize(time_t *secp, long *subsecp, const long maxsubsec)
}
else if (UNLIKELY(subsec < 0)) { /* subsec negative overflow */
sec2 = NDIV(subsec, maxsubsec); /* negative div */
- if (sec < TIMET_MIN - sec2) {
+ if (sec < WIDEINT_MIN - sec2) {
rb_raise(rb_eRangeError, "out of Time range");
}
subsec -= sec2 * maxsubsec;
sec += sec2;
}
-#ifndef NEGATIVE_TIME_T
- if (sec < 0)
- rb_raise(rb_eArgError, "time must be positive");
-#endif
*secp = sec;
*subsecp = subsec;
}
@@ -2780,13 +2764,6 @@ subsec_normalize(time_t *secp, long *subsecp, const long maxsubsec)
#define time_usec_normalize(secp, usecp) subsec_normalize(secp, usecp, 1000000)
#define time_nsec_normalize(secp, nsecp) subsec_normalize(secp, nsecp, 1000000000)
-static wideval_t
-nsec2timew(time_t sec, long nsec)
-{
- time_nsec_normalize(&sec, &nsec);
- return timenano2timew(sec, nsec);
-}
-
static VALUE
time_new_timew(VALUE klass, wideval_t timew)
{
@@ -2800,25 +2777,39 @@ time_new_timew(VALUE klass, wideval_t timew)
return time;
}
+static wideint_t
+TIMETtoWIDEINT(time_t t)
+{
+#if SIZEOF_TIME_T * CHAR_BIT - (SIGNEDNESS_OF_TIME_T < 0) > \
+ SIZEOF_WIDEINT * CHAR_BIT - 1
+ /* compare in bit size without sign bit */
+ if (t > WIDEINT_MAX) rb_raise(rb_eArgError, "out of Time range");
+#endif
+ return (wideint_t)t;
+}
+
VALUE
rb_time_new(time_t sec, long usec)
{
- time_usec_normalize(&sec, &usec);
- return time_new_timew(rb_cTime, timenano2timew(sec, usec * 1000));
+ wideint_t isec = TIMETtoWIDEINT(sec);
+ time_usec_normalize(&isec, &usec);
+ return time_new_timew(rb_cTime, timenano2timew(isec, usec * 1000));
}
/* returns localtime time object */
VALUE
rb_time_nano_new(time_t sec, long nsec)
{
- return time_new_timew(rb_cTime, nsec2timew(sec, nsec));
+ wideint_t isec = TIMETtoWIDEINT(sec);
+ time_nsec_normalize(&isec, &nsec);
+ return time_new_timew(rb_cTime, timenano2timew(isec, nsec));
}
VALUE
rb_time_timespec_new(const struct timespec *ts, int offset)
{
struct time_object *tobj;
- VALUE time = time_new_timew(rb_cTime, nsec2timew(ts->tv_sec, ts->tv_nsec));
+ VALUE time = rb_time_nano_new(ts->tv_sec, ts->tv_nsec);
if (-86400 < offset && offset < 86400) { /* fixoff */
GetTimeval(time, tobj);
@@ -2933,8 +2924,7 @@ time_timespec(VALUE num, int interval)
t.tv_nsec = NUM2LONG(f);
}
else {
- rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into %s",
- rb_obj_class(num), tstr);
+ rb_cant_convert(num, tstr);
}
}
return t;
@@ -3830,8 +3820,7 @@ time_to_i(VALUE time)
* {Epoch seconds}[rdoc-ref:Time@Epoch+Seconds];
* subseconds are included.
*
- * The stored value of +self+ is a
- * {Rational}[rdoc-ref:Rational@#method-i-to_f],
+ * The stored value of +self+ is a Rational,
* which means that the returned value may be approximate:
*
* Time.utc(1970, 1, 1, 0, 0, 0).to_f # => 0.0
@@ -4084,7 +4073,9 @@ time_init_copy(VALUE copy, VALUE time)
if (!OBJ_INIT_COPY(copy, time)) return copy;
GetTimeval(time, tobj);
GetNewTimeval(copy, tcopy);
- MEMCPY(tcopy, tobj, struct time_object, 1);
+
+ time_set_timew(copy, tcopy, tobj->timew);
+ time_set_vtm(copy, tcopy, tobj->vtm);
return copy;
}
@@ -5748,7 +5739,7 @@ end_submicro: ;
}
if (!NIL_P(zone)) {
zone = mload_zone(time, zone);
- tobj->vtm.zone = zone;
+ RB_OBJ_WRITE(time, &tobj->vtm.zone, zone);
zone_localtime(zone, time);
}
@@ -5794,8 +5785,10 @@ tm_from_time(VALUE klass, VALUE time)
tm = time_s_alloc(klass);
ttm = RTYPEDDATA_GET_DATA(tm);
v = &vtm;
- GMTIMEW(ttm->timew = tobj->timew, v);
- ttm->timew = wsub(ttm->timew, v->subsecx);
+
+ WIDEVALUE timew = tobj->timew;
+ GMTIMEW(timew, v);
+ time_set_timew(tm, ttm, wsub(timew, v->subsecx));
v->subsecx = INT2FIX(0);
v->zone = Qnil;
time_set_vtm(tm, ttm, *v);
diff --git a/timev.rb b/timev.rb
index cf8a88e64e..4500b8f169 100644
--- a/timev.rb
+++ b/timev.rb
@@ -57,7 +57,7 @@
# Other calendars, such as Julian calendar, are not supported.
#
# The implementation uses a signed 63 bit integer, Integer (Bignum) object or
-# Ratoinal object to represent a rational value.
+# Rational object to represent a rational value.
# (The signed 63 bit integer is used regardless of 32 and 64 bit environments.)
# The value represents the number of nanoseconds from _Epoch_.
# The signed 63 bit integer can represent 1823-11-12 to 2116-02-20.
@@ -68,23 +68,23 @@
# and 6-tuple (year,month,day,hour,minute,second).
# +localtime+ is used for local time and +gmtime+ is used for UTC.
#
-# Integer and Rational has no range limit, but the localtime and
-# gmtime has range limits due to the C types +time_t+ and <tt>struct tm</tt>.
+# Integer and Rational have no range limit, but localtime and
+# gmtime have range limits due to the C types +time_t+ and <tt>struct tm</tt>.
# If that limit is exceeded, Ruby extrapolates the localtime function.
#
# +time_t+ can represent 1901-12-14 to 2038-01-19 if it is 32 bit signed integer,
# -292277022657-01-27 to 292277026596-12-05 if it is 64 bit signed integer.
-# However +localtime+ on some platforms doesn't supports negative +time_t+ (before 1970).
+# However +localtime+ on some platforms doesn't support negative +time_t+ (before 1970).
#
# <tt>struct tm</tt> has _tm_year_ member to represent years.
# (<tt>tm_year = 0</tt> means the year 1900.)
# It is defined as +int+ in the C standard.
# _tm_year_ can represent years between -2147481748 to 2147485547 if +int+ is 32 bit.
#
-# Ruby supports leap seconds as far as if the C function +localtime+ and
-# +gmtime+ supports it.
+# Ruby supports leap seconds as far as the C functions +localtime+ and
+# +gmtime+ support them.
# They use the tz database in most Unix systems.
-# The tz database has timezones which supports leap seconds.
+# The tz database has timezones which support leap seconds.
# For example, "Asia/Tokyo" doesn't support leap seconds but
# "right/Asia/Tokyo" supports leap seconds.
# So, Ruby supports leap seconds if the TZ environment variable is
@@ -170,8 +170,8 @@
#
# First, what's elsewhere. Class +Time+:
#
-# - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
-# - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+# - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+# - Includes {module Comparable}[rdoc-ref:Comparable@Whats+Here].
#
# Here, class +Time+ provides methods that are useful for:
#
diff --git a/tool/auto-style.rb b/tool/auto-style.rb
new file mode 100755
index 0000000000..3b93c8c317
--- /dev/null
+++ b/tool/auto-style.rb
@@ -0,0 +1,284 @@
+#!/usr/bin/env ruby
+# Usage:
+# auto-style.rb oldrev newrev [pushref]
+
+require 'shellwords'
+require 'tmpdir'
+ENV['LC_ALL'] = 'C'
+
+class Git
+ attr_reader :depth
+
+ def initialize(oldrev, newrev, branch = nil)
+ @oldrev = oldrev
+ @newrev = !newrev || newrev.empty? ? 'HEAD' : newrev
+ @branch = branch
+
+ return unless oldrev
+
+ # GitHub may not fetch github.event.pull_request.base.sha at checkout
+ git('log', '--format=%H', '-1', @oldrev, out: IO::NULL, err: [:child, :out]) or
+ git('fetch', '--depth=1', 'origin', @oldrev)
+ git('log', '--format=%H', '-1', "#@newrev~99", out: IO::NULL, err: [:child, :out]) or
+ git('fetch', '--depth=100', 'origin', @newrev)
+
+ with_clean_env do
+ @revs = {}
+ IO.popen(['git', 'log', '--format=%H %s', "#{@oldrev}..#{@newrev}"]) do |f|
+ f.each do |line|
+ line.chomp!
+ rev, subj = line.split(' ', 2)
+ @revs[rev] = subj
+ end
+ end
+ @depth = @revs.size
+ end
+ end
+
+ # ["foo/bar.c", "baz.h", ...]
+ def updated_paths
+ with_clean_env do
+ IO.popen(['git', 'diff', '--name-only', @oldrev, @newrev], &:readlines).each(&:chomp!)
+ end
+ end
+
+ # [0, 1, 4, ...]
+ def updated_lines(file) # NOTE: This doesn't work well on pull requests, so not used anymore
+ lines = []
+ revs = @revs.map {|rev, subj| rev unless subj.start_with?("Revert ")}.compact
+ revs_pattern = /\A(?:#{revs.join('|')}) /
+ with_clean_env { IO.popen(['git', 'blame', '-l', '--', file], &:readlines) }.each_with_index do |line, index|
+ if revs_pattern =~ line
+ lines << index
+ end
+ end
+ lines
+ end
+
+ def commit(log, *files)
+ git('add', *files)
+ git('commit', '-m', log)
+ end
+
+ def push
+ git('push', 'origin', @branch) if @branch
+ end
+
+ def diff
+ git('--no-pager', 'diff')
+ end
+
+ private
+
+ def git(*args, **opts)
+ cmd = ['git', *args]
+ puts "+ #{cmd.shelljoin}"
+ ret = with_clean_env { system(*cmd, **opts) }
+ unless ret or opts[:err]
+ abort "Failed to run: #{cmd}"
+ end
+ ret
+ end
+
+ def with_clean_env
+ git_dir = ENV.delete('GIT_DIR') # this overcomes '-C' or pwd
+ yield
+ ensure
+ ENV['GIT_DIR'] = git_dir if git_dir
+ end
+end
+
+DEFAULT_GEM_LIBS = %w[
+ bundler
+ cmath
+ csv
+ e2mmap
+ fileutils
+ forwardable
+ ipaddr
+ irb
+ logger
+ matrix
+ mutex_m
+ ostruct
+ prime
+ rdoc
+ rexml
+ rss
+ scanf
+ shell
+ sync
+ thwait
+ tracer
+ webrick
+]
+
+DEFAULT_GEM_EXTS = %w[
+ bigdecimal
+ date
+ dbm
+ digest
+ etc
+ fcntl
+ fiddle
+ gdbm
+ io/console
+ io/nonblock
+ json
+ openssl
+ psych
+ racc
+ sdbm
+ stringio
+ strscan
+ zlib
+]
+
+IGNORED_FILES = [
+ # default gems whose master is GitHub
+ %r{\Abin/(?!erb)\w+\z},
+ *(DEFAULT_GEM_LIBS + DEFAULT_GEM_EXTS).flat_map { |lib|
+ [
+ %r{\Alib/#{lib}/},
+ %r{\Alib/#{lib}\.gemspec\z},
+ %r{\Alib/#{lib}\.rb\z},
+ %r{\Atest/#{lib}/},
+ ]
+ },
+ *DEFAULT_GEM_EXTS.flat_map { |ext|
+ [
+ %r{\Aext/#{ext}/},
+ %r{\Atest/#{ext}/},
+ ]
+ },
+
+ # vendoring (ccan)
+ %r{\Accan/},
+
+ # vendoring (io/)
+ %r{\Aext/io/},
+
+ # vendoring (nkf)
+ %r{\Aext/nkf/nkf-utf8/},
+
+ # vendoring (onigmo)
+ %r{\Aenc/},
+ %r{\Ainclude/ruby/onigmo\.h\z},
+ %r{\Areg.+\.(c|h)\z},
+
+ # explicit or implicit `c-file-style: "linux"`
+ %r{\Aaddr2line\.c\z},
+ %r{\Amissing/},
+ %r{\Astrftime\.c\z},
+ %r{\Avsnprintf\.c\z},
+
+ # to respect the original statements of licenses
+ %r{\ALEGAL\z},
+
+ # trailing spaces could be intentional in TRICK code
+ %r{\Asample/trick[^/]*/},
+]
+
+DIFFERENT_STYLE_FILES = %w[
+ addr2line.c io_buffer.c prism*.c scheduler.c
+]
+
+def adjust_styles(files)
+ trailing = eofnewline = expandtab = indent = false
+
+ edited_files = files.select do |f|
+ src = File.binread(f) rescue next
+ eofnewline = eofnewline0 = true if src.sub!(/(?<!\A|\n)\z/, "\n")
+
+ trailing0 = false
+ expandtab0 = false
+ indent0 = false
+
+ src.gsub!(/^.*$/).with_index do |line, lineno|
+ trailing = trailing0 = true if line.sub!(/[ \t]+$/, '')
+ line
+ end
+
+ if f.end_with?('.c') || f.end_with?('.h') || f == 'insns.def'
+ # If and only if unedited lines did not have tab indentation, prevent introducing tab indentation to the file.
+ expandtab_allowed = src.each_line.with_index.all? do |line, lineno|
+ !line.start_with?("\t")
+ end
+
+ if expandtab_allowed
+ src.gsub!(/^.*$/).with_index do |line, lineno|
+ if line.start_with?("\t") # last-committed line with hard tabs
+ expandtab = expandtab0 = true
+ line.sub(/\A\t+/) { |tabs| ' ' * (8 * tabs.length) }
+ else
+ line
+ end
+ end
+ end
+ end
+
+ if File.fnmatch?("*.[chy]", f, File::FNM_PATHNAME) &&
+ !DIFFERENT_STYLE_FILES.any? {|pat| File.fnmatch?(pat, f, File::FNM_PATHNAME)}
+ indent0 = true if src.gsub!(/^\w+\([^\n]*?\)\K[ \t]*(?=\{( *\\)?$)/, '\1' "\n")
+ indent0 = true if src.gsub!(/^([ \t]*)\}\K[ \t]*(?=else\b.*?( *\\)?$)/, '\2' "\n" '\1')
+ indent0 = true if src.gsub!(/^[ \t]*\}\n\K\n+(?=[ \t]*else\b)/, '')
+ indent ||= indent0
+ end
+
+ if trailing0 or eofnewline0 or expandtab0 or indent0
+ File.binwrite(f, src)
+ true
+ end
+ end
+ if edited_files.empty?
+ return
+ else
+ msg = [('remove trailing spaces' if trailing),
+ ('append newline at EOF' if eofnewline),
+ ('expand tabs' if expandtab),
+ ('adjust indents' if indent),
+ ].compact
+ message = "* #{msg.join(', ')}. [ci skip]"
+ if expandtab
+ message += "\nPlease consider using misc/expand_tabs.rb as a pre-commit hook."
+ end
+ return message, edited_files
+ end
+end
+
+oldrev, newrev, pushref = ARGV
+if (dry_run = oldrev == '-n') or oldrev == '--'
+ _, *updated_files = ARGV
+ git = Git.new(nil, nil)
+else
+ unless dry_run = pushref.nil?
+ branch = IO.popen(['git', 'rev-parse', '--symbolic', '--abbrev-ref', pushref], &:read).strip
+ end
+ git = Git.new(oldrev, newrev, branch)
+
+ updated_files = git.updated_paths
+end
+
+files = updated_files.select {|l|
+ /^\d/ !~ l and /\.bat\z/ !~ l and
+ (/\A(?:config|[Mm]akefile|GNUmakefile|README)/ =~ File.basename(l) or
+ /\A\z|\.(?:[chsy]|\d+|e?rb|tmpl|bas[eh]|z?sh|in|ma?k|def|src|trans|rdoc|ja|en|el|sed|awk|p[ly]|scm|mspec|html|rs)\z/ =~ File.extname(l))
+}
+files.select! {|n| File.file?(n) }
+files.reject! do |f|
+ IGNORED_FILES.any? { |re| f.match(re) }
+end
+
+if files.empty?
+ puts "No files are an auto-style target:\n#{updated_files.join("\n")}"
+elsif !(message, edited_files = adjust_styles(files))
+ puts "All edited lines are formatted well:\n#{files.join("\n")}"
+else
+ if dry_run
+ git.diff
+ abort message
+ else
+ git.commit(message, *edited_files)
+ git.push
+ end
+end
diff --git a/tool/auto_review_pr.rb b/tool/auto_review_pr.rb
new file mode 100755
index 0000000000..38adf9fdb7
--- /dev/null
+++ b/tool/auto_review_pr.rb
@@ -0,0 +1,172 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'json'
+require 'net/http'
+require 'uri'
+require_relative './sync_default_gems'
+
+class GitHubAPIClient
+ def initialize(token)
+ @token = token
+ end
+
+ def get(path)
+ response = Net::HTTP.get_response(URI("https://api.github.com#{path}"), {
+ 'Authorization' => "token #{@token}",
+ 'Accept' => 'application/vnd.github.v3+json',
+ }).tap(&:value)
+ JSON.parse(response.body, symbolize_names: true)
+ end
+
+ def post(path, body = {})
+ body = JSON.dump(body)
+ response = Net::HTTP.post(URI("https://api.github.com#{path}"), body, {
+ 'Authorization' => "token #{@token}",
+ 'Accept' => 'application/vnd.github.v3+json',
+ 'Content-Type' => 'application/json',
+ }).tap(&:value)
+ JSON.parse(response.body, symbolize_names: true)
+ end
+end
+
+class AutoReviewPR
+ REPO = 'ruby/ruby'
+
+ COMMENT_USER = 'github-actions[bot]'
+
+ UPSTREAM_COMMENT_PREFIX = 'The following files are maintained in the following upstream repositories:'
+ UPSTREAM_COMMENT_SUFFIX = 'Please file a pull request to the above instead. Thank you!'
+
+ REDMINE_TICKET_PATTERN = /\[(Bug|Feature|Misc)\s*#(\d+)\]/
+ REDMINE_COMMENT_PREFIX = 'This pull request references the following Redmine tickets:'
+
+ FORK_COMMENT_PREFIX = 'It looks like this pull request was filed from a branch in ruby/ruby.'
+ FORK_COMMENT_BODY = <<~COMMENT
+ #{FORK_COMMENT_PREFIX}
+
+ Since ruby/ruby is bi-directionally mirrored with the official git repository at git.ruby-lang.org, \
+ having topic branches in ruby/ruby makes it harder to manage the mirror.
+
+ Could you please close this pull request and re-file it from a branch in your personal fork instead? \
+ You can fork https://github.com/ruby/ruby, push your branch there, and open a new pull request from it.
+
+ Thank you for your contribution!
+ COMMENT
+
+ def initialize(client)
+ @client = client
+ end
+
+ def review(pr_number)
+ existing_comments = fetch_existing_comments(pr_number)
+ pr = @client.get("/repos/#{REPO}/pulls/#{pr_number}")
+ review_non_fork_branch(pr_number, pr, existing_comments)
+ review_upstream_repos(pr_number, existing_comments)
+ review_redmine_links(pr_number, pr, existing_comments)
+ end
+
+ private
+
+ def fetch_existing_comments(pr_number)
+ comments = @client.get("/repos/#{REPO}/issues/#{pr_number}/comments")
+ comments.map { [it.fetch(:user).fetch(:login), it.fetch(:body)] }
+ end
+
+ def already_commented?(existing_comments, prefix)
+ existing_comments.any? { |user, comment| user == COMMENT_USER && comment.start_with?(prefix) }
+ end
+
+ def post_comment(pr_number, comment)
+ result = @client.post("/repos/#{REPO}/issues/#{pr_number}/comments", { body: comment })
+ puts "Success: #{JSON.pretty_generate(result)}"
+ end
+
+ # Suggest re-filing from a fork if the PR branch is in ruby/ruby itself
+ def review_non_fork_branch(pr_number, pr, existing_comments)
+ if already_commented?(existing_comments, FORK_COMMENT_PREFIX)
+ puts "Skipped: The PR ##{pr_number} already has a fork branch comment."
+ return
+ end
+
+ head_repo = pr.dig(:head, :repo, :full_name)
+ if head_repo != REPO
+ puts "Skipped: The PR ##{pr_number} is already from a fork (#{head_repo})."
+ return
+ end
+
+ author = pr.dig(:user, :login)
+ if author == 'dependabot[bot]'
+ puts "Skipped: The PR ##{pr_number} is from dependabot."
+ return
+ end
+
+ post_comment(pr_number, FORK_COMMENT_BODY)
+ end
+
+ # Suggest filing PRs to upstream repositories for files that have one
+ def review_upstream_repos(pr_number, existing_comments)
+ if already_commented?(existing_comments, UPSTREAM_COMMENT_PREFIX)
+ puts "Skipped: The PR ##{pr_number} already has an upstream repos comment."
+ return
+ end
+
+ changed_files = @client.get("/repos/#{REPO}/pulls/#{pr_number}/files").map { it.fetch(:filename) }
+
+ upstream_repos = SyncDefaultGems::Repository.group(changed_files)
+ upstream_repos.delete(nil)
+ upstream_repos.delete('prism') if changed_files.include?('prism_compile.c')
+ if upstream_repos.empty?
+ puts "Skipped: The PR ##{pr_number} doesn't have upstream repositories."
+ return
+ end
+
+ post_comment(pr_number, format_upstream_comment(upstream_repos))
+ end
+
+ def review_redmine_links(pr_number, pr, existing_comments)
+ if already_commented?(existing_comments, REDMINE_COMMENT_PREFIX)
+ puts "Skipped: The PR ##{pr_number} already has a Redmine links comment."
+ return
+ end
+
+ text = "#{pr[:title]}\n#{pr[:body]}"
+
+ tickets = text.scan(REDMINE_TICKET_PATTERN).uniq
+ tickets.reject! { |_, number| text.include?("https://bugs.ruby-lang.org/issues/#{number}") }
+ if tickets.empty?
+ puts "Skipped: The PR ##{pr_number} doesn't reference any Redmine tickets."
+ return
+ end
+
+ post_comment(pr_number, format_redmine_comment(tickets))
+ end
+
+ def format_redmine_comment(tickets)
+ comment = +"#{REDMINE_COMMENT_PREFIX}\n\n"
+ tickets.each do |type, number|
+ comment << "* [#{type} ##{number}](https://bugs.ruby-lang.org/issues/#{number})\n"
+ end
+ comment
+ end
+
+ def format_upstream_comment(upstream_repos)
+ comment = +''
+ comment << "#{UPSTREAM_COMMENT_PREFIX}\n\n"
+
+ upstream_repos.each do |upstream_repo, files|
+ comment << "* https://github.com/ruby/#{upstream_repo}\n"
+ files.each do |file|
+ comment << " * #{file}\n"
+ end
+ end
+
+ comment << "\n#{UPSTREAM_COMMENT_SUFFIX}"
+ comment
+ end
+end
+
+pr_number = ARGV[0] || abort("Usage: #{$0} <pr_number>")
+client = GitHubAPIClient.new(ENV.fetch('GITHUB_TOKEN'))
+
+AutoReviewPR.new(client).review(pr_number)
diff --git a/tool/bundler/dev_gems.rb b/tool/bundler/dev_gems.rb
index 0d4dbd7f2e..c8e4d5345c 100644
--- a/tool/bundler/dev_gems.rb
+++ b/tool/bundler/dev_gems.rb
@@ -3,8 +3,9 @@
source "https://rubygems.org"
gem "test-unit", "~> 3.0"
+gem "test-unit-ruby-core"
gem "rake", "~> 13.1"
-gem "rb_sys"
+gem "rb_sys", ">= 0.9.128"
gem "turbo_tests", "~> 2.2.3"
gem "parallel_tests", "~> 4.10.1"
@@ -12,6 +13,8 @@ gem "parallel", "~> 1.19"
gem "rspec-core", "~> 3.12"
gem "rspec-expectations", "~> 3.12"
gem "rspec-mocks", "~> 3.12"
+gem "rubygems-generate_index", "~> 1.1"
+gem "simplecov", "~> 0.22"
group :doc do
gem "ronn-ng", "~> 0.10.1", platform: :ruby
diff --git a/tool/bundler/dev_gems.rb.lock b/tool/bundler/dev_gems.rb.lock
index cbdb17a661..ee91c8baff 100644
--- a/tool/bundler/dev_gems.rb.lock
+++ b/tool/bundler/dev_gems.rb.lock
@@ -1,61 +1,73 @@
GEM
remote: https://rubygems.org/
specs:
- diff-lcs (1.6.1)
- kramdown (2.5.1)
- rexml (>= 3.3.9)
+ compact_index (0.15.0)
+ diff-lcs (1.6.2)
+ docile (1.4.1)
+ kramdown (2.5.2)
+ rexml (>= 3.4.4)
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
- mini_portile2 (2.8.8)
- mustache (1.1.1)
- nokogiri (1.18.6)
+ mini_portile2 (2.8.9)
+ mustache (1.1.2)
+ nokogiri (1.19.3)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
- nokogiri (1.18.6-aarch64-linux-gnu)
+ nokogiri (1.19.3-aarch64-linux-gnu)
racc (~> 1.4)
- nokogiri (1.18.6-arm-linux-gnu)
+ nokogiri (1.19.3-arm-linux-gnu)
racc (~> 1.4)
- nokogiri (1.18.6-arm64-darwin)
+ nokogiri (1.19.3-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.18.6-java)
+ nokogiri (1.19.3-java)
racc (~> 1.4)
- nokogiri (1.18.6-x64-mingw-ucrt)
+ nokogiri (1.19.3-x64-mingw-ucrt)
racc (~> 1.4)
- nokogiri (1.18.6-x86_64-darwin)
+ nokogiri (1.19.3-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.18.6-x86_64-linux-gnu)
+ nokogiri (1.19.3-x86_64-linux-gnu)
racc (~> 1.4)
- parallel (1.26.3)
+ parallel (1.28.0)
parallel_tests (4.10.1)
parallel
- power_assert (2.0.5)
+ power_assert (3.0.1)
racc (1.8.1)
racc (1.8.1-java)
- rake (13.2.1)
- rake-compiler-dock (1.9.1)
- rb_sys (0.9.111)
- rake-compiler-dock (= 1.9.1)
- rexml (3.4.1)
+ rake (13.4.2)
+ rake-compiler-dock (1.12.0)
+ rb_sys (0.9.128)
+ rake-compiler-dock (= 1.12.0)
+ rexml (3.4.4)
ronn-ng (0.10.1)
kramdown (~> 2, >= 2.1)
kramdown-parser-gfm (~> 1, >= 1.0.1)
mustache (~> 1)
nokogiri (~> 1, >= 1.14.3)
- rspec (3.13.0)
+ rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
- rspec-core (3.13.3)
+ rspec-core (3.13.6)
rspec-support (~> 3.13.0)
- rspec-expectations (3.13.3)
+ rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-mocks (3.13.2)
+ rspec-mocks (3.13.8)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-support (3.13.2)
- test-unit (3.6.7)
+ rspec-support (3.13.7)
+ rubygems-generate_index (1.1.3)
+ compact_index (~> 0.15.0)
+ simplecov (0.22.0)
+ docile (~> 1.1)
+ simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-html (0.13.2)
+ simplecov_json_formatter (0.1.4)
+ test-unit (3.7.7)
power_assert
+ test-unit-ruby-core (1.0.14)
+ test-unit (>= 3.7.2)
turbo_tests (2.2.5)
parallel_tests (>= 3.3.0, < 5)
rspec (>= 3.10)
@@ -69,6 +81,7 @@ PLATFORMS
ruby
universal-java
x64-mingw-ucrt
+ x64-mswin64-140
x86-linux
x86_64-darwin
x86_64-linux
@@ -77,45 +90,55 @@ DEPENDENCIES
parallel (~> 1.19)
parallel_tests (~> 4.10.1)
rake (~> 13.1)
- rb_sys
+ rb_sys (>= 0.9.128)
ronn-ng (~> 0.10.1)
rspec-core (~> 3.12)
rspec-expectations (~> 3.12)
rspec-mocks (~> 3.12)
+ rubygems-generate_index (~> 1.1)
+ simplecov (~> 0.22)
test-unit (~> 3.0)
+ test-unit-ruby-core
turbo_tests (~> 2.2.3)
CHECKSUMS
- diff-lcs (1.6.1) sha256=12a5a83f3e37a8e2f4427268e305914d5f1879f22b4e73bb1a09f76a3dd86cd4
- kramdown (2.5.1) sha256=87bbb6abd9d3cebe4fc1f33e367c392b4500e6f8fa19dd61c0972cf4afe7368c
+ compact_index (0.15.0) sha256=5c6c404afca8928a7d9f4dde9524f6e1610db17e675330803055db282da84a8b
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
+ docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
+ kramdown (2.5.2) sha256=1ba542204c66b6f9111ff00dcc26075b95b220b07f2905d8261740c82f7f02fa
kramdown-parser-gfm (1.1.0) sha256=fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729
- mini_portile2 (2.8.8) sha256=8e47136cdac04ce81750bb6c09733b37895bf06962554e4b4056d78168d70a75
- mustache (1.1.1) sha256=90891fdd50b53919ca334c8c1031eada1215e78d226d5795e523d6123a2717d0
- nokogiri (1.18.6) sha256=4d283431d7829719ea1287ca388f24c6ce343af736bbcbd1365cbdb83bce41a4
- nokogiri (1.18.6-aarch64-linux-gnu) sha256=1b11f9a814068282cc2b47ebe61395b2a69d1918092d2ca3bd664074f72540e9
- nokogiri (1.18.6-arm-linux-gnu) sha256=2da07a07ef4c9d9e9da809b3dc0937ed90b031e32c2c658d9918941b85d68b95
- nokogiri (1.18.6-arm64-darwin) sha256=727a441d179d934b4b7c73e0e28e6723ee46463d96bb0cc6e2e33a13540962c4
- nokogiri (1.18.6-java) sha256=bf16c53446987007ff3e1deb29d65d20444073ba112cb5bddbd2671135ba293c
- nokogiri (1.18.6-x64-mingw-ucrt) sha256=134f6d54f56edd46cb6db77c9d9de1704b3f83b3981a6763671e3cfbeba221f5
- nokogiri (1.18.6-x86_64-darwin) sha256=fb72568c97ccd90a8d68cb765b0ff0720b109bd62e3babbf372e854ef8fef995
- nokogiri (1.18.6-x86_64-linux-gnu) sha256=df065db6ba6e1e80f76ef04f860fcf260cc24685125fe33cdc3d1572a1c66b71
- parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
+ mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289
+ mustache (1.1.2) sha256=d420243400354da78ded2d81541b381ad8d94e8e9b95022d0d71d66f8ef36c00
+ nokogiri (1.19.3) sha256=78312cbac32a40c812780d9678221b79d51288eec00054c1a8d15f7ce05960e8
+ nokogiri (1.19.3-aarch64-linux-gnu) sha256=46b89e5d7b9e844c2ee360794240c6ea2a4e6fa0c5892a4ed487db621224b639
+ nokogiri (1.19.3-arm-linux-gnu) sha256=3919d5ffc334ad778a4a9eb88fda7dcb8b1fb58c8a52ac640c6dcd2f038e774f
+ nokogiri (1.19.3-arm64-darwin) sha256=71b9bd424b1b7abc18b05052a1a3cfd3627abdca62be280854cc411791357e42
+ nokogiri (1.19.3-java) sha256=40ea6ebf5cf2005dae1dee26dd557d3afb41fb6de6c9764aca8cf06fdb841db1
+ nokogiri (1.19.3-x64-mingw-ucrt) sha256=8bb7132cad356c879a1286eaabcb5e68326cb2490317984280fbc62f456d506a
+ nokogiri (1.19.3-x86_64-darwin) sha256=77f3fba57d46c53ab31e62fc6c28f705109d1bf6264356c76f132b2be5728d4d
+ nokogiri (1.19.3-x86_64-linux-gnu) sha256=2f5078620fe12e83669b5b17311b32532a8153d02eee7ad06948b926d6080976
+ parallel (1.28.0) sha256=33e6de1484baf2524792d178b0913fc8eb94c628d6cfe45599ad4458c638c970
parallel_tests (4.10.1) sha256=df05458c691462b210f7a41fc2651d4e4e8a881e8190e6d1e122c92c07735d70
- power_assert (2.0.5) sha256=63b511b85bb8ea57336d25156864498644f5bbf028699ceda27949e0125bc323
+ power_assert (3.0.1) sha256=8ce9876716cc74e863fcd4cdcdc52d792bd983598d1af3447083a3a9a4d34103
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
racc (1.8.1-java) sha256=54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98
- rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
- rake-compiler-dock (1.9.1) sha256=e73720a29aba9c114728ce39cc0d8eef69ba61d88e7978c57bac171724cd4d53
- rb_sys (0.9.111) sha256=65822fd8d57c248cd893db0efe01bc6edc15fcbea3ba6666091e35430c1cbaf0
- rexml (3.4.1) sha256=c74527a9a0a04b4ec31dbe0dc4ed6004b960af943d8db42e539edde3a871abca
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
+ rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
+ rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
ronn-ng (0.10.1) sha256=4eeb0185c0fbfa889efed923b5b50e949cd869e7d82ac74138acd0c9c7165ec0
- rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
- rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4
- rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
- rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
- rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec
- test-unit (3.6.7) sha256=c342bb9f7334ea84a361b43c20b063f405c0bf3c7dbe3ff38f61a91661d29221
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
+ rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
+ rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
+ rubygems-generate_index (1.1.3) sha256=3571424322666598e9586a906485e1543b617f87644913eaf137d986a3393f5c
+ simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
+ simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
+ simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
+ test-unit (3.7.7) sha256=3c89d5ff0690a16bef9946156c4624390402b9d54dfcf4ce9cbd5b06bead1e45
+ test-unit-ruby-core (1.0.14) sha256=d2e997796c9c5c5e8e31ac014f83a473ff5c2523a67cfa491b08893e12d43d22
turbo_tests (2.2.5) sha256=3fa31497d12976d11ccc298add29107b92bda94a90d8a0a5783f06f05102509f
BUNDLED WITH
- 2.7.0.dev
+ 4.1.0.dev
diff --git a/tool/bundler/rubocop_gems.rb b/tool/bundler/rubocop_gems.rb
index ab13b1b2c3..c71b862318 100644
--- a/tool/bundler/rubocop_gems.rb
+++ b/tool/bundler/rubocop_gems.rb
@@ -4,10 +4,10 @@ source "https://rubygems.org"
gem "rubocop", ">= 1.52.1", "< 2"
-gem "minitest"
+gem "minitest", "~> 5.1"
gem "irb"
gem "rake"
gem "rake-compiler"
gem "rspec"
gem "test-unit"
-gem "rb_sys"
+gem "rb_sys", ">= 0.9.128"
diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock
index 1461ad5072..f265e7c9eb 100644
--- a/tool/bundler/rubocop_gems.rb.lock
+++ b/tool/bundler/rubocop_gems.rb.lock
@@ -2,84 +2,90 @@ GEM
remote: https://rubygems.org/
specs:
ast (2.4.3)
- date (3.4.1)
- date (3.4.1-java)
- diff-lcs (1.6.1)
- io-console (0.8.0)
- io-console (0.8.0-java)
- irb (1.15.1)
+ date (3.5.1)
+ date (3.5.1-java)
+ diff-lcs (1.6.2)
+ erb (6.0.4)
+ erb (6.0.4-java)
+ io-console (0.8.2)
+ io-console (0.8.2-java)
+ irb (1.18.0)
pp (>= 0.6.0)
+ prism (>= 1.3.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
- jar-dependencies (0.5.5)
- json (2.10.2)
- json (2.10.2-java)
- language_server-protocol (3.17.0.4)
+ jar-dependencies (0.5.7)
+ json (2.19.4)
+ json (2.19.4-java)
+ language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
- minitest (5.25.5)
- parallel (1.26.3)
- parser (3.3.7.3)
+ minitest (5.27.0)
+ parallel (2.1.0)
+ parser (3.3.11.1)
ast (~> 2.4.1)
racc
- power_assert (2.0.5)
- pp (0.6.2)
+ power_assert (3.0.1)
+ pp (0.6.3)
prettyprint
prettyprint (0.2.0)
- prism (1.4.0)
- psych (5.2.3)
+ prism (1.9.0)
+ psych (5.3.1)
date
stringio
- psych (5.2.3-java)
+ psych (5.3.1-java)
date
jar-dependencies (>= 0.1.7)
racc (1.8.1)
racc (1.8.1-java)
rainbow (3.1.1)
- rake (13.2.1)
- rake-compiler (1.2.9)
+ rake (13.4.2)
+ rake-compiler (1.3.1)
rake
- rake-compiler-dock (1.9.1)
- rb_sys (0.9.111)
- rake-compiler-dock (= 1.9.1)
- rdoc (6.13.0)
+ rake-compiler-dock (1.12.0)
+ rb_sys (0.9.128)
+ rake-compiler-dock (= 1.12.0)
+ rdoc (7.2.0)
+ erb
psych (>= 4.0.0)
- regexp_parser (2.10.0)
- reline (0.6.0)
+ tsort
+ regexp_parser (2.12.0)
+ reline (0.6.3)
io-console (~> 0.5)
- rspec (3.13.0)
+ rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
- rspec-core (3.13.3)
+ rspec-core (3.13.6)
rspec-support (~> 3.13.0)
- rspec-expectations (3.13.3)
+ rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-mocks (3.13.2)
+ rspec-mocks (3.13.8)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-support (3.13.2)
- rubocop (1.75.1)
+ rspec-support (3.13.7)
+ rubocop (1.86.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
- parallel (~> 1.10)
+ parallel (>= 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
- rubocop-ast (>= 1.43.0, < 2.0)
+ rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
- rubocop-ast (1.43.0)
+ rubocop-ast (1.49.1)
parser (>= 3.3.7.2)
- prism (~> 1.4)
+ prism (~> 1.7)
ruby-progressbar (1.13.0)
- stringio (3.1.6)
- test-unit (3.6.7)
+ stringio (3.2.0)
+ test-unit (3.7.7)
power_assert
- unicode-display_width (3.1.4)
- unicode-emoji (~> 4.0, >= 4.0.4)
- unicode-emoji (4.0.4)
+ tsort (0.2.0)
+ unicode-display_width (3.2.0)
+ unicode-emoji (~> 4.1)
+ unicode-emoji (4.2.0)
PLATFORMS
aarch64-darwin
@@ -88,63 +94,67 @@ PLATFORMS
ruby
universal-java
x64-mingw-ucrt
+ x64-mswin64-140
x86_64-darwin
x86_64-linux
DEPENDENCIES
irb
- minitest
+ minitest (~> 5.1)
rake
rake-compiler
- rb_sys
+ rb_sys (>= 0.9.128)
rspec
rubocop (>= 1.52.1, < 2)
test-unit
CHECKSUMS
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
- date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
- date (3.4.1-java) sha256=74740d914c65a922a15657c25ff0e203c16f1d0f7aa910a9ebed712afe9819c4
- diff-lcs (1.6.1) sha256=12a5a83f3e37a8e2f4427268e305914d5f1879f22b4e73bb1a09f76a3dd86cd4
- io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
- io-console (0.8.0-java) sha256=3cc6fd5c66e587145c1fdf8dc40c2e3d851e90722a5d0cc3f38da352f06fe1bd
- irb (1.15.1) sha256=d9bca745ac4207a8b728a52b98b766ca909b86ff1a504bcde3d6f8c84faae890
- jar-dependencies (0.5.5) sha256=2972b9fcba4b014e6446a84b5c09674a3e8648b95b71768e729f0e8e40568059
- json (2.10.2) sha256=34e0eada93022b2a0a3345bb0b5efddb6e9ff5be7c48e409cfb54ff8a36a8b06
- json (2.10.2-java) sha256=fe31faac61ea21ea1448c35450183f84e85c2b94cc6522c241959ba9d1362006
- language_server-protocol (3.17.0.4) sha256=c484626478664fd13482d8180947c50a8590484b1258b99b7aedb3b69df89669
+ date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
+ date (3.5.1-java) sha256=12e09477dc932afe45bf768cd362bf73026804e0db1e6c314186d6cd0bee3344
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
+ erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9
+ erb (6.0.4-java) sha256=3014611d37917a20e14ea3ba71e06a8d581b71c073858d7796eeee45b01e8407
+ io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
+ io-console (0.8.2-java) sha256=837efefe96084c13ae91114917986ae6c6d1cf063b27b8419cc564a722a38af8
+ irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
+ jar-dependencies (0.5.7) sha256=013ce5f4639414ac8cf1169cdbe763da164b81e2d2c983d11042b5ff7bfcce80
+ json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac
+ json (2.19.4-java) sha256=f7f0fe701e2bef648497b0eb59422f5b453e5038cfbaf9cde09af20e22241efb
+ language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
- minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756
- parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
- parser (3.3.7.3) sha256=5803acc132cf1155fac2656bf02d3fb9223dccd66f1aa538dac095b785fa4d64
- power_assert (2.0.5) sha256=63b511b85bb8ea57336d25156864498644f5bbf028699ceda27949e0125bc323
- pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
+ minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
+ parallel (2.1.0) sha256=b35258865c2e31134c5ecb708beaaf6772adf9d5efae28e93e99260877b09356
+ parser (3.3.11.1) sha256=d17ace7aabe3e72c3cc94043714be27cc6f852f104d81aa284c2281aecc65d54
+ power_assert (3.0.1) sha256=8ce9876716cc74e863fcd4cdcdc52d792bd983598d1af3447083a3a9a4d34103
+ pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
- prism (1.4.0) sha256=dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e
- psych (5.2.3) sha256=84a54bb952d14604fea22d99938348814678782f58b12648fcdfa4d2fce859ee
- psych (5.2.3-java) sha256=3e5425b9e8a2f41cc2707d5ef14fdc1ae908abbafb12fe45727bd63900056585
+ prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
+ psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
+ psych (5.3.1-java) sha256=20a4a81ad01479ef060f604ed75ba42fe673169e67d923b1bae5aa4e13cc5820
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
racc (1.8.1-java) sha256=54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
- rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
- rake-compiler (1.2.9) sha256=5a3213a5dda977dfdf73e28beed6f4cd6a2cc86ac640bb662728eb7049a23607
- rake-compiler-dock (1.9.1) sha256=e73720a29aba9c114728ce39cc0d8eef69ba61d88e7978c57bac171724cd4d53
- rb_sys (0.9.111) sha256=65822fd8d57c248cd893db0efe01bc6edc15fcbea3ba6666091e35430c1cbaf0
- rdoc (6.13.0) sha256=32c2139ae43ed91b7c43032fe5423d21d57718829cc5a11e5c9710d2aa5e0329
- regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
- reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2
- rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
- rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4
- rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
- rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
- rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec
- rubocop (1.75.1) sha256=c12900c55b0b52e6ed1384f7f7575beb92047019ce37ca14b9572d80239adc29
- rubocop-ast (1.43.0) sha256=92cd649e336ce10212cb2f2b29028f487777ecc477f108f437a1dce1ee3db79a
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
+ rake-compiler (1.3.1) sha256=6b351612b6e2d73ddd5563ee799bb58685176e05363db6758504bd11573d670a
+ rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
+ rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
+ regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
+ reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
+ rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
+ rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
+ rubocop (1.86.1) sha256=44415f3f01d01a21e01132248d2fd0867572475b566ca188a0a42133a08d4531
+ rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
- stringio (3.1.6) sha256=292c495d1657adfcdf0a32eecf12a60e6691317a500c3112ad3b2e31068274f5
- test-unit (3.6.7) sha256=c342bb9f7334ea84a361b43c20b063f405c0bf3c7dbe3ff38f61a91661d29221
- unicode-display_width (3.1.4) sha256=8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1
- unicode-emoji (4.0.4) sha256=2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a
+ stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
+ test-unit (3.7.7) sha256=3c89d5ff0690a16bef9946156c4624390402b9d54dfcf4ce9cbd5b06bead1e45
+ tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
+ unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
+ unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
BUNDLED WITH
- 2.7.0.dev
+ 4.1.0.dev
diff --git a/tool/bundler/standard_gems.rb b/tool/bundler/standard_gems.rb
index fab93e6d6d..84028a385d 100644
--- a/tool/bundler/standard_gems.rb
+++ b/tool/bundler/standard_gems.rb
@@ -4,10 +4,10 @@ source "https://rubygems.org"
gem "standard", "~> 1.0"
-gem "minitest"
+gem "minitest", "~> 5.1"
gem "irb"
gem "rake"
gem "rake-compiler"
gem "rspec"
gem "test-unit"
-gem "rb_sys"
+gem "rb_sys", ">= 0.9.128"
diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock
index e0fc70a6bb..8ef7806bcc 100644
--- a/tool/bundler/standard_gems.rb.lock
+++ b/tool/bundler/standard_gems.rb.lock
@@ -2,64 +2,69 @@ GEM
remote: https://rubygems.org/
specs:
ast (2.4.3)
- date (3.4.1)
- date (3.4.1-java)
- diff-lcs (1.6.1)
- io-console (0.8.0)
- io-console (0.8.0-java)
- irb (1.15.1)
+ date (3.5.1)
+ date (3.5.1-java)
+ diff-lcs (1.6.2)
+ erb (6.0.4)
+ erb (6.0.4-java)
+ io-console (0.8.2)
+ io-console (0.8.2-java)
+ irb (1.18.0)
pp (>= 0.6.0)
+ prism (>= 1.3.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
- jar-dependencies (0.5.5)
- json (2.10.2)
- json (2.10.2-java)
- language_server-protocol (3.17.0.4)
+ jar-dependencies (0.5.7)
+ json (2.19.4)
+ json (2.19.4-java)
+ language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
- minitest (5.25.5)
- parallel (1.26.3)
- parser (3.3.7.3)
+ minitest (5.27.0)
+ parallel (1.28.0)
+ parser (3.3.11.1)
ast (~> 2.4.1)
racc
- power_assert (2.0.5)
- pp (0.6.2)
+ power_assert (3.0.1)
+ pp (0.6.3)
prettyprint
prettyprint (0.2.0)
- prism (1.4.0)
- psych (5.2.3)
+ prism (1.9.0)
+ psych (5.3.1)
date
stringio
- psych (5.2.3-java)
+ psych (5.3.1-java)
date
jar-dependencies (>= 0.1.7)
racc (1.8.1)
racc (1.8.1-java)
rainbow (3.1.1)
- rake (13.2.1)
- rake-compiler (1.2.9)
+ rake (13.4.2)
+ rake-compiler (1.3.1)
rake
- rake-compiler-dock (1.9.1)
- rb_sys (0.9.111)
- rake-compiler-dock (= 1.9.1)
- rdoc (6.13.0)
+ rake-compiler-dock (1.12.0)
+ rb_sys (0.9.128)
+ rake-compiler-dock (= 1.12.0)
+ rdoc (7.2.0)
+ erb
psych (>= 4.0.0)
- regexp_parser (2.10.0)
- reline (0.6.0)
+ tsort
+ regexp_parser (2.12.0)
+ reline (0.6.3)
io-console (~> 0.5)
- rspec (3.13.0)
+ rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
- rspec-core (3.13.3)
+ rspec-core (3.13.6)
rspec-support (~> 3.13.0)
- rspec-expectations (3.13.3)
+ rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-mocks (3.13.2)
+ rspec-mocks (3.13.8)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-support (3.13.2)
- rubocop (1.73.2)
+ rspec-support (3.13.7)
+ rubocop (1.84.2)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
@@ -67,35 +72,36 @@ GEM
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
- rubocop-ast (>= 1.38.0, < 2.0)
+ rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
- rubocop-ast (1.43.0)
+ rubocop-ast (1.49.1)
parser (>= 3.3.7.2)
- prism (~> 1.4)
- rubocop-performance (1.24.0)
+ prism (~> 1.7)
+ rubocop-performance (1.26.1)
lint_roller (~> 1.1)
- rubocop (>= 1.72.1, < 2.0)
- rubocop-ast (>= 1.38.0, < 2.0)
+ rubocop (>= 1.75.0, < 2.0)
+ rubocop-ast (>= 1.47.1, < 2.0)
ruby-progressbar (1.13.0)
- standard (1.47.0)
+ standard (1.54.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
- rubocop (~> 1.73.0)
+ rubocop (~> 1.84.0)
standard-custom (~> 1.0.0)
- standard-performance (~> 1.7)
+ standard-performance (~> 1.8)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
- standard-performance (1.7.0)
+ standard-performance (1.9.0)
lint_roller (~> 1.1)
- rubocop-performance (~> 1.24.0)
- stringio (3.1.6)
- test-unit (3.6.7)
+ rubocop-performance (~> 1.26.0)
+ stringio (3.2.0)
+ test-unit (3.7.7)
power_assert
- unicode-display_width (3.1.4)
- unicode-emoji (~> 4.0, >= 4.0.4)
- unicode-emoji (4.0.4)
+ tsort (0.2.0)
+ unicode-display_width (3.2.0)
+ unicode-emoji (~> 4.1)
+ unicode-emoji (4.2.0)
PLATFORMS
aarch64-darwin
@@ -104,67 +110,71 @@ PLATFORMS
ruby
universal-java
x64-mingw-ucrt
+ x64-mswin64-140
x86_64-darwin
x86_64-linux
DEPENDENCIES
irb
- minitest
+ minitest (~> 5.1)
rake
rake-compiler
- rb_sys
+ rb_sys (>= 0.9.128)
rspec
standard (~> 1.0)
test-unit
CHECKSUMS
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
- date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
- date (3.4.1-java) sha256=74740d914c65a922a15657c25ff0e203c16f1d0f7aa910a9ebed712afe9819c4
- diff-lcs (1.6.1) sha256=12a5a83f3e37a8e2f4427268e305914d5f1879f22b4e73bb1a09f76a3dd86cd4
- io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
- io-console (0.8.0-java) sha256=3cc6fd5c66e587145c1fdf8dc40c2e3d851e90722a5d0cc3f38da352f06fe1bd
- irb (1.15.1) sha256=d9bca745ac4207a8b728a52b98b766ca909b86ff1a504bcde3d6f8c84faae890
- jar-dependencies (0.5.5) sha256=2972b9fcba4b014e6446a84b5c09674a3e8648b95b71768e729f0e8e40568059
- json (2.10.2) sha256=34e0eada93022b2a0a3345bb0b5efddb6e9ff5be7c48e409cfb54ff8a36a8b06
- json (2.10.2-java) sha256=fe31faac61ea21ea1448c35450183f84e85c2b94cc6522c241959ba9d1362006
- language_server-protocol (3.17.0.4) sha256=c484626478664fd13482d8180947c50a8590484b1258b99b7aedb3b69df89669
+ date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
+ date (3.5.1-java) sha256=12e09477dc932afe45bf768cd362bf73026804e0db1e6c314186d6cd0bee3344
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
+ erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9
+ erb (6.0.4-java) sha256=3014611d37917a20e14ea3ba71e06a8d581b71c073858d7796eeee45b01e8407
+ io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
+ io-console (0.8.2-java) sha256=837efefe96084c13ae91114917986ae6c6d1cf063b27b8419cc564a722a38af8
+ irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
+ jar-dependencies (0.5.7) sha256=013ce5f4639414ac8cf1169cdbe763da164b81e2d2c983d11042b5ff7bfcce80
+ json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac
+ json (2.19.4-java) sha256=f7f0fe701e2bef648497b0eb59422f5b453e5038cfbaf9cde09af20e22241efb
+ language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
- minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756
- parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
- parser (3.3.7.3) sha256=5803acc132cf1155fac2656bf02d3fb9223dccd66f1aa538dac095b785fa4d64
- power_assert (2.0.5) sha256=63b511b85bb8ea57336d25156864498644f5bbf028699ceda27949e0125bc323
- pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
+ minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
+ parallel (1.28.0) sha256=33e6de1484baf2524792d178b0913fc8eb94c628d6cfe45599ad4458c638c970
+ parser (3.3.11.1) sha256=d17ace7aabe3e72c3cc94043714be27cc6f852f104d81aa284c2281aecc65d54
+ power_assert (3.0.1) sha256=8ce9876716cc74e863fcd4cdcdc52d792bd983598d1af3447083a3a9a4d34103
+ pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
- prism (1.4.0) sha256=dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e
- psych (5.2.3) sha256=84a54bb952d14604fea22d99938348814678782f58b12648fcdfa4d2fce859ee
- psych (5.2.3-java) sha256=3e5425b9e8a2f41cc2707d5ef14fdc1ae908abbafb12fe45727bd63900056585
+ prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
+ psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
+ psych (5.3.1-java) sha256=20a4a81ad01479ef060f604ed75ba42fe673169e67d923b1bae5aa4e13cc5820
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
racc (1.8.1-java) sha256=54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
- rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
- rake-compiler (1.2.9) sha256=5a3213a5dda977dfdf73e28beed6f4cd6a2cc86ac640bb662728eb7049a23607
- rake-compiler-dock (1.9.1) sha256=e73720a29aba9c114728ce39cc0d8eef69ba61d88e7978c57bac171724cd4d53
- rb_sys (0.9.111) sha256=65822fd8d57c248cd893db0efe01bc6edc15fcbea3ba6666091e35430c1cbaf0
- rdoc (6.13.0) sha256=32c2139ae43ed91b7c43032fe5423d21d57718829cc5a11e5c9710d2aa5e0329
- regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
- reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2
- rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
- rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4
- rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
- rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
- rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec
- rubocop (1.73.2) sha256=35cd1b1365ba97234323fe771abcecd09c9b77098464cd726c76aa7d9bc12b5d
- rubocop-ast (1.43.0) sha256=92cd649e336ce10212cb2f2b29028f487777ecc477f108f437a1dce1ee3db79a
- rubocop-performance (1.24.0) sha256=e5bd39ff3e368395b9af886927cc37f5892f43db4bd6c8526594352d5b4440b5
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
+ rake-compiler (1.3.1) sha256=6b351612b6e2d73ddd5563ee799bb58685176e05363db6758504bd11573d670a
+ rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
+ rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
+ regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
+ reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
+ rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
+ rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
+ rubocop (1.84.2) sha256=5692cea54168f3dc8cb79a6fe95c5424b7ea893c707ad7a4307b0585e88dbf5f
+ rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
+ rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
- standard (1.47.0) sha256=b0da6b71d8dec53e760c7216b723e3507ebdcd6962f7ce7c37c016a36c7cc190
+ standard (1.54.0) sha256=7a4b08f83d9893083c8f03bc486f0feeb6a84d48233b40829c03ef4767ea0100
standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b
- standard-performance (1.7.0) sha256=c46a9aef3348c0cfc03053ed9a1c1f73b967f7e4edcdf30dac0101b143897314
- stringio (3.1.6) sha256=292c495d1657adfcdf0a32eecf12a60e6691317a500c3112ad3b2e31068274f5
- test-unit (3.6.7) sha256=c342bb9f7334ea84a361b43c20b063f405c0bf3c7dbe3ff38f61a91661d29221
- unicode-display_width (3.1.4) sha256=8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1
- unicode-emoji (4.0.4) sha256=2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a
+ standard-performance (1.9.0) sha256=49483d31be448292951d80e5e67cdcb576c2502103c7b40aec6f1b6e9c88e3f2
+ stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
+ test-unit (3.7.7) sha256=3c89d5ff0690a16bef9946156c4624390402b9d54dfcf4ce9cbd5b06bead1e45
+ tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
+ unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
+ unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
BUNDLED WITH
- 2.7.0.dev
+ 4.1.0.dev
diff --git a/tool/bundler/test_gems.rb b/tool/bundler/test_gems.rb
index e60d187485..71230c32b7 100644
--- a/tool/bundler/test_gems.rb
+++ b/tool/bundler/test_gems.rb
@@ -2,14 +2,16 @@
source "https://rubygems.org"
-gem "rack", "~> 3.0"
-gem "rackup", "~> 2.1"
-gem "webrick", "~> 1.9"
+gem "rack", "~> 3.1"
gem "rack-test", "~> 2.1"
-gem "compact_index", "~> 0.15.0"
gem "sinatra", "~> 4.1"
gem "rake", "~> 13.1"
gem "builder", "~> 3.2"
-gem "rb_sys"
+gem "rb_sys", ">= 0.9.128"
gem "fiddle"
gem "rubygems-generate_index", "~> 1.1"
+gem "concurrent-ruby"
+gem "psych"
+gem "etc", platforms: [:ruby, :windows]
+gem "open3"
+gem "shellwords"
diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock
index 703e21144f..0b9ac34162 100644
--- a/tool/bundler/test_gems.rb.lock
+++ b/tool/bundler/test_gems.rb.lock
@@ -1,83 +1,102 @@
GEM
remote: https://rubygems.org/
specs:
- base64 (0.2.0)
+ base64 (0.3.0)
builder (3.3.0)
compact_index (0.15.0)
- fiddle (1.1.6)
+ concurrent-ruby (1.3.6)
+ date (3.5.1)
+ date (3.5.1-java)
+ etc (1.4.6)
+ fiddle (1.1.8)
+ jar-dependencies (0.5.7)
logger (1.7.0)
- mustermann (3.0.3)
- ruby2_keywords (~> 0.0.1)
- rack (3.1.12)
- rack-protection (4.1.1)
+ mustermann (3.1.1)
+ open3 (0.2.1)
+ psych (5.3.1)
+ date
+ stringio
+ psych (5.3.1-java)
+ date
+ jar-dependencies (>= 0.1.7)
+ rack (3.2.6)
+ rack-protection (4.2.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
- rack-session (2.1.0)
+ rack-session (2.1.2)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
rack (>= 1.3)
- rackup (2.2.1)
- rack (>= 3)
- rake (13.2.1)
- rake-compiler-dock (1.9.1)
- rb_sys (0.9.111)
- rake-compiler-dock (= 1.9.1)
- ruby2_keywords (0.0.5)
+ rake (13.4.2)
+ rake-compiler-dock (1.12.0)
+ rb_sys (0.9.128)
+ rake-compiler-dock (= 1.12.0)
rubygems-generate_index (1.1.3)
compact_index (~> 0.15.0)
- sinatra (4.1.1)
+ shellwords (0.2.2)
+ sinatra (4.2.1)
logger (>= 1.6.0)
mustermann (~> 3.0)
rack (>= 3.0.0, < 4)
- rack-protection (= 4.1.1)
+ rack-protection (= 4.2.1)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0)
- tilt (2.6.0)
- webrick (1.9.1)
+ stringio (3.2.0)
+ tilt (2.7.0)
PLATFORMS
java
ruby
universal-java
x64-mingw-ucrt
+ x64-mswin64-140
x86_64-darwin
x86_64-linux
DEPENDENCIES
builder (~> 3.2)
- compact_index (~> 0.15.0)
+ concurrent-ruby
+ etc
fiddle
- rack (~> 3.0)
+ open3
+ psych
+ rack (~> 3.1)
rack-test (~> 2.1)
- rackup (~> 2.1)
rake (~> 13.1)
- rb_sys
+ rb_sys (>= 0.9.128)
rubygems-generate_index (~> 1.1)
+ shellwords
sinatra (~> 4.1)
- webrick (~> 1.9)
CHECKSUMS
- base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
+ base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
compact_index (0.15.0) sha256=5c6c404afca8928a7d9f4dde9524f6e1610db17e675330803055db282da84a8b
- fiddle (1.1.6) sha256=79e8d909e602d979434cf9fccfa6e729cb16432bb00e39c7596abe6bee1249ab
+ concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
+ date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
+ date (3.5.1-java) sha256=12e09477dc932afe45bf768cd362bf73026804e0db1e6c314186d6cd0bee3344
+ etc (1.4.6) sha256=0f7e9e7842ea5e3c3bd9bc81746ebb8c65ea29e4c42a93520a0d638129c7de01
+ fiddle (1.1.8) sha256=7fa8ee3627271497f3add5503acdbc3f40b32f610fc1cf49634f083ef3f32eee
+ jar-dependencies (0.5.7) sha256=013ce5f4639414ac8cf1169cdbe763da164b81e2d2c983d11042b5ff7bfcce80
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
- mustermann (3.0.3) sha256=d1f8e9ba2ddaed47150ddf81f6a7ea046826b64c672fbc92d83bce6b70657e88
- rack (3.1.12) sha256=00d83055c89273eb13679ab562767b8826955aa6c4371d7d161deb975c50c540
- rack-protection (4.1.1) sha256=51a254a5d574a7f0ca4f0672025ce2a5ef7c8c3bd09c431349d683e825d7d16a
- rack-session (2.1.0) sha256=437c3916535b58ef71c816ce4a2dee0a01c8a52ae6077dc2b6cd19085760a290
+ mustermann (3.1.1) sha256=4c6170c7234d5499c345562ba7c7dfe73e1754286dcc1abb053064d66a127198
+ open3 (0.2.1) sha256=8e2d7d2113526351201438c1aa35c8139f0141c9e8913baa007c898973bf3952
+ psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
+ psych (5.3.1-java) sha256=20a4a81ad01479ef060f604ed75ba42fe673169e67d923b1bae5aa4e13cc5820
+ rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2
+ rack-protection (4.2.1) sha256=cf6e2842df8c55f5e4d1a4be015e603e19e9bc3a7178bae58949ccbb58558bac
+ rack-session (2.1.2) sha256=595434f8c0c3473ae7d7ac56ecda6cc6dfd9d37c0b2b5255330aa1576967ffe8
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
- rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d
- rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
- rake-compiler-dock (1.9.1) sha256=e73720a29aba9c114728ce39cc0d8eef69ba61d88e7978c57bac171724cd4d53
- rb_sys (0.9.111) sha256=65822fd8d57c248cd893db0efe01bc6edc15fcbea3ba6666091e35430c1cbaf0
- ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
+ rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
rubygems-generate_index (1.1.3) sha256=3571424322666598e9586a906485e1543b617f87644913eaf137d986a3393f5c
- sinatra (4.1.1) sha256=4e997b859aa1b5d2e624f85d5b0fd0f0b3abc0da44daa6cbdf10f7c0da9f4d00
- tilt (2.6.0) sha256=263d748466e0d83e510aa1a2e2281eff547937f0ef06be33d3632721e255f76b
- webrick (1.9.1) sha256=b42d3c94f166f3fb73d87e9b359def9b5836c426fc8beacf38f2184a21b2a989
+ shellwords (0.2.2) sha256=b8695a791de2f71472de5abdc3f4332f6535a4177f55d8f99e7e44266cd32f94
+ sinatra (4.2.1) sha256=b7aeb9b11d046b552972ade834f1f9be98b185fa8444480688e3627625377080
+ stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
+ tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3
BUNDLED WITH
- 2.7.0.dev
+ 4.1.0.dev
diff --git a/tool/bundler/vendor_gems.rb b/tool/bundler/vendor_gems.rb
index 467bbf33b3..8d12c5adde 100644
--- a/tool/bundler/vendor_gems.rb
+++ b/tool/bundler/vendor_gems.rb
@@ -2,16 +2,16 @@
source "https://rubygems.org"
-gem "fileutils", "1.7.3"
-gem "molinillo", github: "cocoapods/molinillo"
-gem "net-http", "0.6.0"
-gem "net-http-persistent", "4.0.4"
+gem "fileutils", "1.8.0"
+gem "molinillo", github: "cocoapods/molinillo", ref: "1d62d7d5f448e79418716dc779a4909509ccda2a"
+gem "net-http", "0.7.0" # net-http-0.8.0 is broken with JRuby
+gem "net-http-persistent", "4.0.6"
gem "net-protocol", "0.2.2"
-gem "optparse", "0.6.0"
+gem "optparse", "0.8.0"
gem "pub_grub", github: "jhawthorn/pub_grub", ref: "df6add45d1b4d122daff2f959c9bd1ca93d14261"
-gem "resolv", "0.6.0"
+gem "resolv", "0.6.2"
gem "securerandom", "0.4.1"
-gem "timeout", "0.4.3"
-gem "thor", "1.3.2"
+gem "timeout", "0.4.4"
+gem "thor", "1.4.0"
gem "tsort", "0.2.0"
-gem "uri", "1.0.3"
+gem "uri", "1.1.1"
diff --git a/tool/bundler/vendor_gems.rb.lock b/tool/bundler/vendor_gems.rb.lock
index 55ac15bd03..cc7886e60b 100644
--- a/tool/bundler/vendor_gems.rb.lock
+++ b/tool/bundler/vendor_gems.rb.lock
@@ -1,6 +1,7 @@
GIT
remote: https://github.com/cocoapods/molinillo.git
revision: 1d62d7d5f448e79418716dc779a4909509ccda2a
+ ref: 1d62d7d5f448e79418716dc779a4909509ccda2a
specs:
molinillo (0.8.0)
@@ -14,60 +15,61 @@ GIT
GEM
remote: https://rubygems.org/
specs:
- connection_pool (2.4.1)
- fileutils (1.7.3)
- net-http (0.6.0)
+ connection_pool (2.5.4)
+ fileutils (1.8.0)
+ net-http (0.7.0)
uri
- net-http-persistent (4.0.4)
- connection_pool (~> 2.2)
+ net-http-persistent (4.0.6)
+ connection_pool (~> 2.2, >= 2.2.4)
net-protocol (0.2.2)
timeout
- optparse (0.6.0)
- resolv (0.6.0)
+ optparse (0.8.0)
+ resolv (0.6.2)
securerandom (0.4.1)
- thor (1.3.2)
- timeout (0.4.3)
+ thor (1.4.0)
+ timeout (0.4.4)
tsort (0.2.0)
- uri (1.0.3)
+ uri (1.1.1)
PLATFORMS
java
ruby
universal-java
x64-mingw-ucrt
+ x64-mswin64-140
x86_64-darwin
x86_64-linux
DEPENDENCIES
- fileutils (= 1.7.3)
+ fileutils (= 1.8.0)
molinillo!
- net-http (= 0.6.0)
- net-http-persistent (= 4.0.4)
+ net-http (= 0.7.0)
+ net-http-persistent (= 4.0.6)
net-protocol (= 0.2.2)
- optparse (= 0.6.0)
+ optparse (= 0.8.0)
pub_grub!
- resolv (= 0.6.0)
+ resolv (= 0.6.2)
securerandom (= 0.4.1)
- thor (= 1.3.2)
- timeout (= 0.4.3)
+ thor (= 1.4.0)
+ timeout (= 0.4.4)
tsort (= 0.2.0)
- uri (= 1.0.3)
+ uri (= 1.1.1)
CHECKSUMS
- connection_pool (2.4.1) sha256=0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4
- fileutils (1.7.3) sha256=57271e854b694a87755d76f836f5c57b2c9538ebbaf4b2154bb66addf15eb5da
+ connection_pool (2.5.4) sha256=e9e1922327416091f3f6542f5f4446c2a20745276b9aa796dd0bb2fd0ea1e70a
+ fileutils (1.8.0) sha256=8c6b1df54e2540bdb2f39258f08af78853aa70bad52b4d394bbc6424593c6e02
molinillo (0.8.0)
- net-http (0.6.0) sha256=9621b20c137898af9d890556848c93603716cab516dc2c89b01a38b894e259fb
- net-http-persistent (4.0.4) sha256=b62b7e528f72890f5cd67e7f687eeae55cf9f2cda22fd659494363da2fa7f4b2
+ net-http (0.7.0) sha256=4db7d9f558f8ffd4dcf832d0aefd02320c569c7d4f857def49e585069673a425
+ net-http-persistent (4.0.6) sha256=2abb3a04438edf6cb9e0e7e505969605f709eda3e3c5211beadd621a2c84dd5d
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
- optparse (0.6.0) sha256=25e90469c1cd44048a89dc01c1dde9d5f0bdf717851055fb18237780779b068c
+ optparse (0.8.0) sha256=ef6b7fbaf7ec331474f325bc08dd5622e6e1e651007a5341330ee4b08ce734f0
pub_grub (0.5.0)
- resolv (0.6.0) sha256=b8b73f7734d4102ef9f75bad281d8fd1c434f8588b6aba17832ddc16fe679fab
+ resolv (0.6.2) sha256=61efe545cedddeb1b14f77e51f85c85ca66af5098fdbf567fadf32c34590fb14
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
- thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda
- timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e
+ thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d
+ timeout (0.4.4) sha256=f0f6f970104b82427cd990680f539b6bbb8b1e55efa913a55c6492935e4e0edb
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
- uri (1.0.3) sha256=e9f2244608eea2f7bc357d954c65c910ce0399ca5e18a7a29207ac22d8767011
+ uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
BUNDLED WITH
- 2.7.0.dev
+ 4.0.0.dev
diff --git a/tool/commit-email.rb b/tool/commit-email.rb
new file mode 100755
index 0000000000..c887f8783e
--- /dev/null
+++ b/tool/commit-email.rb
@@ -0,0 +1,372 @@
+#!/usr/bin/env ruby
+
+require "optparse"
+require "nkf"
+require "shellwords"
+
+CommitEmailInfo = Struct.new(
+ :author,
+ :author_email,
+ :revision,
+ :entire_sha256,
+ :date,
+ :log,
+ :branch,
+ :diffs,
+ :added_files, :deleted_files, :updated_files,
+ :added_dirs, :deleted_dirs, :updated_dirs,
+)
+
+class GitInfoBuilder
+ GitCommandFailure = Class.new(RuntimeError)
+
+ def initialize(repo_path)
+ @repo_path = repo_path
+ end
+
+ def build(oldrev, newrev, refname)
+ diffs = build_diffs(oldrev, newrev)
+
+ info = CommitEmailInfo.new
+ info.author = git_show(newrev, format: '%an')
+ info.author_email = normalize_email(git_show(newrev, format: '%aE'))
+ info.revision = newrev[0...10]
+ info.entire_sha256 = newrev
+ info.date = Time.at(Integer(git_show(newrev, format: '%at')))
+ info.log = git_show(newrev, format: '%B')
+ info.branch = git('rev-parse', '--symbolic', '--abbrev-ref', refname).strip
+ info.diffs = diffs
+ info.added_files = find_files(diffs, status: :added)
+ info.deleted_files = find_files(diffs, status: :deleted)
+ info.updated_files = find_files(diffs, status: :modified)
+ info.added_dirs = [] # git does not deal with directory
+ info.deleted_dirs = [] # git does not deal with directory
+ info.updated_dirs = [] # git does not deal with directory
+ info
+ end
+
+ private
+
+ # Force git-svn email address to @ruby-lang.org to avoid email bounce by invalid email address.
+ def normalize_email(email)
+ if email.match(/\A[^@]+@\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/) # git-svn
+ svn_user, _ = email.split('@', 2)
+ "#{svn_user}@ruby-lang.org"
+ else
+ email
+ end
+ end
+
+ def find_files(diffs, status:)
+ files = []
+ diffs.each do |path, values|
+ if values.keys.first == status
+ files << path
+ end
+ end
+ files
+ end
+
+ # SVN version:
+ # {
+ # "filename" => {
+ # "[modified|added|deleted|copied|property_changed]" => {
+ # type: "[modified|added|deleted|copied|property_changed]",
+ # body: "diff body", # not implemented because not used
+ # added: Integer,
+ # deleted: Integer,
+ # }
+ # }
+ # }
+ def build_diffs(oldrev, newrev)
+ diffs = {}
+
+ numstats = git('diff', '--numstat', oldrev, newrev).lines.map { |l| l.strip.split("\t", 3) }
+ git('diff', '--name-status', oldrev, newrev).each_line do |line|
+ status, path, _newpath = line.strip.split("\t", 3)
+ diff = build_diff(path, numstats)
+
+ case status
+ when 'A'
+ diffs[path] = { added: { type: :added, **diff } }
+ when 'M'
+ diffs[path] = { modified: { type: :modified, **diff } }
+ when 'C'
+ diffs[path] = { copied: { type: :copied, **diff } }
+ when 'D'
+ diffs[path] = { deleted: { type: :deleted, **diff } }
+ when /\AR/ # R100 (which does not exist in git.ruby-lang.org's git 2.1.4)
+ # TODO: implement something
+ else
+ $stderr.puts "unexpected git diff status: #{status}"
+ end
+ end
+
+ diffs
+ end
+
+ def build_diff(path, numstats)
+ diff = { added: 0, deleted: 0 } # :body not implemented because not used
+ line = numstats.find { |(_added, _deleted, file, *)| file == path }
+ return diff if line.nil?
+
+ added, deleted, _ = line
+ if added
+ diff[:added] = Integer(added)
+ end
+ if deleted
+ diff[:deleted] = Integer(deleted)
+ end
+ diff
+ end
+
+ def git_show(revision, format:)
+ git('show', '--no-show-signature', "--pretty=#{format}", '--no-patch', revision).strip
+ end
+
+ def git(*args)
+ command = ['git', '-C', @repo_path, *args]
+ output = with_gitenv { IO.popen(command, external_encoding: 'UTF-8', &:read) }
+ unless $?.success?
+ raise GitCommandFailure, "failed to execute '#{command.join(' ')}':\n#{output}"
+ end
+ output
+ end
+
+ def with_gitenv
+ orig = ENV.to_h.dup
+ begin
+ ENV.delete('GIT_DIR')
+ yield
+ ensure
+ ENV.replace(orig)
+ end
+ end
+end
+
+CommitEmailOptions = Struct.new(:error_to, :viewer_uri)
+
+CommitEmail = Module.new
+class << CommitEmail
+ SENDMAIL = ENV.fetch('SENDMAIL', '/usr/sbin/sendmail')
+ private_constant :SENDMAIL
+
+ def parse(args)
+ options = CommitEmailOptions.new
+
+ opts = OptionParser.new do |opts|
+ opts.separator('')
+
+ opts.on('-e', '--error-to [TO]',
+ 'Add [TO] to to address when error is occurred') do |to|
+ options.error_to = to
+ end
+
+ opts.on('--viewer-uri [URI]',
+ 'Use [URI] as URI of revision viewer') do |uri|
+ options.viewer_uri = uri
+ end
+
+ opts.on_tail('--help', 'Show this message') do
+ puts opts
+ exit
+ end
+ end
+
+ return opts.parse(args), options
+ end
+
+ def main(repo_path, to, rest)
+ args, options = parse(rest)
+
+ infos = args.each_slice(3).flat_map do |oldrev, newrev, refname|
+ revisions = IO.popen(['git', 'log', '--no-show-signature', '--reverse', '--pretty=%H', "#{oldrev}^..#{newrev}"], &:read).lines.map(&:strip)
+ revisions[0..-2].zip(revisions[1..-1]).map do |old, new|
+ GitInfoBuilder.new(repo_path).build(old, new, refname)
+ end
+ end
+
+ infos.each do |info|
+ next if info.branch.start_with?('notes/')
+ puts "#{info.branch}: #{info.revision} (#{info.author})"
+
+ from = make_from(name: info.author, email: "noreply@ruby-lang.org")
+ sendmail(to, from, make_mail(to, from, info, viewer_uri: options.viewer_uri))
+ end
+ end
+
+ def sendmail(to, from, mail)
+ IO.popen([*SENDMAIL.shellsplit, to], 'w') do |f|
+ f.print(mail)
+ end
+ unless $?.success?
+ raise "Failed to run `#{SENDMAIL} #{to}` with: '#{mail}'"
+ end
+ end
+
+ private
+
+ def b_encode(str)
+ NKF.nkf('-WwM', str)
+ end
+
+ def make_body(info, viewer_uri:)
+ body = +''
+ body << "#{info.author}\t#{format_time(info.date)}\n"
+ body << "\n"
+ body << " New Revision: #{info.revision}\n"
+ body << "\n"
+ body << " #{viewer_uri}#{info.revision}\n"
+ body << "\n"
+ body << " Log:\n"
+ body << info.log.lstrip.gsub(/^\t*/, ' ').rstrip
+ body << "\n\n"
+ body << added_dirs(info)
+ body << added_files(info)
+ body << deleted_dirs(info)
+ body << deleted_files(info)
+ body << modified_dirs(info)
+ body << modified_files(info)
+ [body.rstrip].pack('M')
+ end
+
+ def format_time(time)
+ time.strftime('%Y-%m-%d %X %z (%a, %d %b %Y)')
+ end
+
+ def changed_items(title, type, items)
+ rv = ''
+ unless items.empty?
+ rv << " #{title} #{type}:\n"
+ rv << items.collect {|item| " #{item}\n"}.join('')
+ end
+ rv
+ end
+
+ def changed_files(title, files)
+ changed_items(title, 'files', files)
+ end
+
+ def added_files(info)
+ changed_files('Added', info.added_files)
+ end
+
+ def deleted_files(info)
+ changed_files('Removed', info.deleted_files)
+ end
+
+ def modified_files(info)
+ changed_files('Modified', info.updated_files)
+ end
+
+ def changed_dirs(title, files)
+ changed_items(title, 'directories', files)
+ end
+
+ def added_dirs(info)
+ changed_dirs('Added', info.added_dirs)
+ end
+
+ def deleted_dirs(info)
+ changed_dirs('Removed', info.deleted_dirs)
+ end
+
+ def modified_dirs(info)
+ changed_dirs('Modified', info.updated_dirs)
+ end
+
+ def changed_dirs_info(info, uri)
+ (info.added_dirs.collect do |dir|
+ " Added: #{dir}\n"
+ end + info.deleted_dirs.collect do |dir|
+ " Deleted: #{dir}\n"
+ end + info.updated_dirs.collect do |dir|
+ " Modified: #{dir}\n"
+ end).join("\n")
+ end
+
+ def diff_info(info, uri)
+ info.diffs.collect do |key, values|
+ [
+ key,
+ values.collect do |type, value|
+ case type
+ when :added
+ rev = "?revision=#{info.revision}&view=markup"
+ when :modified, :property_changed
+ prev_revision = (info.revision.is_a?(Integer) ? info.revision - 1 : "#{info.revision}^")
+ rev = "?r1=#{info.revision}&r2=#{prev_revision}&diff_format=u"
+ when :deleted, :copied
+ rev = ''
+ else
+ raise "unknown diff type: #{value[:type]}"
+ end
+
+ link = [uri, key.sub(/ .+/, '') || ''].join('/') + rev
+
+ desc = ''
+
+ [desc, link]
+ end
+ ]
+ end
+ end
+
+ def make_header(to, from, info)
+ <<~EOS
+ Mime-Version: 1.0
+ Content-Type: text/plain; charset=utf-8
+ Content-Transfer-Encoding: quoted-printable
+ From: #{from}
+ To: #{to}
+ Subject: #{make_subject(info)}
+ EOS
+ end
+
+ def make_subject(info)
+ subject = +''
+ subject << "#{info.revision}"
+ subject << " (#{info.branch})"
+ subject << ': '
+ subject << info.log.lstrip.lines.first.to_s.strip
+ b_encode(subject)
+ end
+
+ # https://tools.ietf.org/html/rfc822#section-4.1
+ # https://tools.ietf.org/html/rfc822#section-6.1
+ # https://tools.ietf.org/html/rfc822#appendix-D
+ # https://tools.ietf.org/html/rfc2047
+ def make_from(name:, email:)
+ if name.ascii_only?
+ escaped_name = name.gsub(/["\\\n]/) { |c| "\\#{c}" }
+ %Q["#{escaped_name}" <#{email}>]
+ else
+ escaped_name = "=?UTF-8?B?#{NKF.nkf('-WwMB', name)}?="
+ %Q[#{escaped_name} <#{email}>]
+ end
+ end
+
+ def make_mail(to, from, info, viewer_uri:)
+ make_header(to, from, info) + make_body(info, viewer_uri: viewer_uri)
+ end
+end
+
+repo_path, to, *rest = ARGV
+begin
+ CommitEmail.main(repo_path, to, rest)
+rescue StandardError => e
+ $stderr.puts "#{e.class}: #{e.message}"
+ $stderr.puts e.backtrace
+
+ _, options = CommitEmail.parse(rest)
+ to = options.error_to
+ CommitEmail.sendmail(to, to, <<-MAIL)
+From: #{to}
+To: #{to}
+Subject: Error
+
+#{$!.class}: #{$!.message}
+#{$@.join("\n")}
+MAIL
+ exit 1
+end
diff --git a/tool/downloader.rb b/tool/downloader.rb
index a1520eb6a9..39ebf44a83 100644
--- a/tool/downloader.rb
+++ b/tool/downloader.rb
@@ -1,41 +1,14 @@
# Used by configure and make to download or update mirrored Ruby and GCC
-# files. This will use HTTPS if possible, falling back to HTTP.
+# files.
# -*- frozen-string-literal: true -*-
require 'fileutils'
require 'open-uri'
require 'pathname'
-begin
- require 'net/https'
-rescue LoadError
- https = 'http'
-else
- https = 'https'
-
- # open-uri of ruby 2.2.0 accepts an array of PEMs as ssl_ca_cert, but old
- # versions do not. so, patching OpenSSL::X509::Store#add_file instead.
- class OpenSSL::X509::Store
- alias orig_add_file add_file
- def add_file(pems)
- Array(pems).each do |pem|
- if File.directory?(pem)
- add_path pem
- else
- orig_add_file pem
- end
- end
- end
- end
- # since open-uri internally checks ssl_ca_cert using File.directory?,
- # allow to accept an array.
- class <<File
- alias orig_directory? directory?
- def File.directory? files
- files.is_a?(Array) ? false : orig_directory?(files)
- end
- end
-end
+verbose, $VERBOSE = $VERBOSE, nil
+require 'net/https'
+$VERBOSE = verbose
class Downloader
def self.find(dlname)
@@ -44,34 +17,25 @@ class Downloader
end
end
- def self.https=(https)
- @@https = https
- end
-
- def self.https?
- @@https == 'https'
- end
-
- def self.https
- @@https
- end
-
def self.get_option(argv, options)
false
end
class GNU < self
+ Mirrors = %w[
+ https://raw.githubusercontent.com/autotools-mirror/autoconf/refs/heads/master/build-aux/
+ https://cdn.jsdelivr.net/gh/gcc-mirror/gcc@master
+ ]
+
def self.download(name, *rest, **options)
- if https?
- begin
- super("https://cdn.jsdelivr.net/gh/gcc-mirror/gcc@master/#{name}", name, *rest, **options)
- rescue => e
- m1, m2 = e.message.split("\n", 2)
- STDERR.puts "Download failed (#{m1}), try another URL\n#{m2}"
- super("https://raw.githubusercontent.com/gcc-mirror/gcc/master/#{name}", name, *rest, **options)
- end
+ Mirrors.each_with_index do |url, i|
+ super("#{url}/#{name}", name, *rest, **options)
+ rescue => e
+ raise if i + 1 == Mirrors.size # no more URLs
+ m1, m2 = e.message.split("\n", 2)
+ STDERR.puts "Download failed (#{m1}), try another URL\n#{m2}"
else
- super("https://repo.or.cz/official-gcc.git/blob_plain/HEAD:/#{name}", name, *rest, **options)
+ return
end
end
end
@@ -222,11 +186,6 @@ class Downloader
if link_cache(cache, file, name, verbose: verbose)
return file.to_path
end
- if !https? and URI::HTTPS === url
- warn "*** using http instead of https ***"
- url.scheme = 'http'
- url = URI(url.to_s)
- end
if verbose
$stdout.print "downloading #{name} ... "
$stdout.flush
@@ -234,13 +193,7 @@ class Downloader
mtime = nil
options = options.merge(http_options(file, since.nil? ? true : since))
begin
- data = with_retry(10) do
- data = url.read(options)
- if mtime = data.meta["last-modified"]
- mtime = Time.httpdate(mtime)
- end
- data
- end
+ data = with_retry(10) {url.read(options)}
rescue OpenURI::HTTPError => http_error
case http_error.message
when /^304 / # 304 Not Modified
@@ -268,6 +221,10 @@ class Downloader
return file.to_path
end
raise
+ else
+ if mtime = data.meta["last-modified"]
+ mtime = Time.httpdate(mtime)
+ end
end
dest = (cache_save && cache && !cache.exist? ? cache : file)
dest.parent.mkpath
@@ -386,8 +343,6 @@ class Downloader
private_class_method :with_retry
end
-Downloader.https = https.freeze
-
if $0 == __FILE__
since = true
options = {}
diff --git a/tool/dump_ast.c b/tool/dump_ast.c
new file mode 100644
index 0000000000..58250e9b8c
--- /dev/null
+++ b/tool/dump_ast.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+/*
+ * When prism is compiled as part of CRuby, the xmalloc/xfree/etc. macros are
+ * redirected to ruby_xmalloc/ruby_xfree/etc. Since this is a standalone
+ * program that links against those same object files, we need to provide
+ * implementations of these functions.
+ */
+void *ruby_xmalloc(size_t size) { return malloc(size); }
+void *ruby_xcalloc(size_t nelems, size_t elemsiz) { return calloc(nelems, elemsiz); }
+void *ruby_xrealloc(void *ptr, size_t newsiz) { return realloc(ptr, newsiz); }
+void ruby_xfree(void *ptr) { free(ptr); }
+void ruby_xfree_sized(void *ptr, size_t _oldsize) { free(ptr); }
+void *ruby_xrealloc_sized(void *ptr, size_t newsiz, size_t _oldsiz) { return realloc(ptr, newsiz); }
+
+#include "prism.h"
+
+static void
+print_error(const pm_diagnostic_t *diagnostic, void *data)
+{
+ const pm_parser_t *parser = (const pm_parser_t *) data;
+ pm_location_t loc = pm_diagnostic_location(diagnostic);
+ const pm_line_column_t line_column = pm_line_offset_list_line_column(pm_parser_line_offsets(parser), loc.start, pm_parser_start_line(parser));
+ fprintf(stderr, "%" PRIi32 ":%" PRIu32 ":%s\n", line_column.line, line_column.column, pm_diagnostic_message(diagnostic));
+}
+
+int
+main(int argc, const char *argv[]) {
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ const char *filepath = argv[1];
+ pm_source_init_result_t init_result;
+ pm_source_t *source = pm_source_mapped_new(filepath, 0, &init_result);
+
+ if (init_result != PM_SOURCE_INIT_SUCCESS)
+ {
+ fprintf(stderr, "unable to map file: %s\n", filepath);
+ return EXIT_FAILURE;
+ }
+
+ pm_options_t *options = pm_options_new();
+ pm_options_line_set(options, 1);
+ pm_options_filepath_set(options, filepath);
+
+ pm_arena_t *arena = pm_arena_new();
+ pm_parser_t *parser = pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
+
+ pm_node_t *node = pm_parse(parser);
+ int exit_status;
+
+ if (pm_parser_errors_size(parser) > 0)
+ {
+ fprintf(stderr, "error parsing %s\n", filepath);
+ pm_parser_errors_each(parser, print_error, parser);
+ exit_status = EXIT_FAILURE;
+ }
+ else {
+ pm_buffer_t *json = pm_buffer_new();
+ pm_dump_json(json, parser, node);
+ printf("%.*s\n", (int) pm_buffer_length(json), pm_buffer_value(json));
+ pm_buffer_free(json);
+ exit_status = EXIT_SUCCESS;
+ }
+
+ pm_parser_free(parser);
+ pm_arena_free(arena);
+ pm_source_free(source);
+ pm_options_free(options);
+
+ return exit_status;
+}
diff --git a/tool/dump_ast.mkmf.rb b/tool/dump_ast.mkmf.rb
new file mode 100755
index 0000000000..eec6b72f79
--- /dev/null
+++ b/tool/dump_ast.mkmf.rb
@@ -0,0 +1,37 @@
+#!ruby -s
+require 'mkmf'
+require 'pathname'
+require 'fileutils'
+
+workdir, src, *objs = ARGV
+src = Pathname(src)
+tooldir = src.parent.relative_path_from(workdir)
+srcdir = tooldir.parent
+target = src.basename.sub_ext('')
+dirs = objs.map {|obj| File.dirname(obj)}.uniq - %w[.]
+link = MakeMakefile::TRY_LINK.sub(MakeMakefile::CONFTEST+$EXEEXT, '$(@)')
+prismdir= "$(srcdir)/#{dirs.first}"
+$VPATH = ["$(srcdir)", "$(srcdir)/#{tooldir.basename}", prismdir, tooldir]
+$INCFLAGS << " -I#{prismdir}"
+$CPPFLAGS = $CFLAGS = $INCFLAGS
+
+include FileUtils::Verbose
+mkpath(workdir)
+Dir.chdir(workdir) {
+ mkpath(dirs)
+ File.write('Makefile', [MakeMakefile.configuration(srcdir.to_s), <<~MAKEFILE].join(""))
+ target = #{target}#{$EXEEXT}
+ objs = #{objs.join(' ')}
+
+ $(target): $(objs)
+ \t#{link} $(objs)
+
+ objs: $(objs)
+ .c.#{$OBJEXT}:
+ \t#{MakeMakefile::COMPILE_C}
+
+ clean:
+ \t$(RM) $(target) $(objs) Makefile
+ \t$(RMDIRS) #{dirs.join(' ')}
+ MAKEFILE
+}
diff --git a/tool/enc-unicode.rb b/tool/enc-unicode.rb
index 04d436281d..a89390ad8f 100755
--- a/tool/enc-unicode.rb
+++ b/tool/enc-unicode.rb
@@ -12,6 +12,9 @@
# You can get source file for gperf. After this, simply make ruby.
# Or directly run:
# tool/enc-unicode.rb --header data_dir emoji_data_dir > enc/unicode/<VERSION>/name2ctype.h
+#
+# There are Makefile rules that automate steps above: `make update-unicode` and
+# `make enc/unicode/<VERSION>/name2ctype.h`.
while arg = ARGV.shift
case arg
@@ -143,7 +146,8 @@ def define_posix_props(data)
data['Space'] = data['White_Space']
data['Blank'] = data['Space_Separator'] + [0x0009]
data['Cntrl'] = data['Cc']
- data['Word'] = data['Alpha'] + data['Mark'] + data['Digit'] + data['Connector_Punctuation']
+ data['Word'] = data['Alpha'] + data['Mark'] + data['Digit'] +
+ data['Connector_Punctuation'] + data['Join_Control']
data['Graph'] = data['Any'] - data['Space'] - data['Cntrl'] -
data['Surrogate'] - data['Unassigned']
data['Print'] = data['Graph'] + data['Space_Separator']
diff --git a/tool/fetch-bundled_gems.rb b/tool/fetch-bundled_gems.rb
index f50bda360a..4d2af06a85 100755
--- a/tool/fetch-bundled_gems.rb
+++ b/tool/fetch-bundled_gems.rb
@@ -1,4 +1,4 @@
-#!ruby -an
+#!ruby -alnF\s+|#.*
BEGIN {
require 'fileutils'
require_relative 'lib/colorize'
@@ -21,27 +21,21 @@ BEGIN {
n, v, u, r = $F
next unless n
-next if n =~ /^#/
next if bundled_gems&.all? {|pat| !File.fnmatch?(pat, n)}
-if File.directory?(n)
- puts "updating #{color.notice(n)} ..."
- system("git", "fetch", "--all", chdir: n) or abort
-else
+unless File.exist?("#{n}/.git")
puts "retrieving #{color.notice(n)} ..."
- system(*%W"git clone #{u} #{n}") or abort
+ system(*%W"git clone --depth=1 --no-tags #{u} #{n}") or abort
end
-if r
- puts "fetching #{color.notice(r)} ..."
- system("git", "fetch", "origin", r, chdir: n) or abort
-end
+c = (r ? [r] : ["v#{v}", v]).find do |c|
+ puts "fetching #{n} #{color.notice(c)} ..."
+ system("git", "fetch", "origin", r || "refs/tags/#{c}:refs/tags/#{c}", chdir: n)
+end or abort
-c = r || "v#{v}"
checkout = %w"git -c advice.detachedHead=false checkout"
-print %[checking out #{color.notice(c)} (v=#{color.info(v)}]
-print %[, r=#{color.info(r)}] if r
-puts ") ..."
+info = %[, r=#{color.info(r)}] if r
+puts "checking out #{color.notice(c)} (v=#{color.info(v)}#{info}) ..."
unless system(*checkout, c, "--", chdir: n)
abort if r or !system(*checkout, v, "--", chdir: n)
end
diff --git a/tool/format-release b/tool/format-release
index 72fc173000..d02154df1f 100755
--- a/tool/format-release
+++ b/tool/format-release
@@ -9,6 +9,7 @@ end
require "open-uri"
require "yaml"
+require_relative "./ruby-version"
Diffy::Diff.default_options.merge!(
include_diff_info: true,
@@ -30,10 +31,9 @@ class Tarball
def gz?; @url.end_with?('.gz'); end
def zip?; @url.end_with?('.zip'); end
- def bz2?; @url.end_with?('.bz2'); end
def xz?; @url.end_with?('.xz'); end
- def ext; @url[/(?:zip|tar\.(?:gz|bz2|xz))\z/]; end
+ def ext; @url[/(?:zip|tar\.(?:gz|xz))\z/]; end
def to_md
<<eom
@@ -51,29 +51,14 @@ eom
# SHA1: 21f62c369661a2ab1b521fd2fa8191a4273e12a1
# SHA256: 97cea8aa63dfa250ba6902b658a7aa066daf817b22f82b7ee28f44aec7c2e394
# SHA512: 1e2042324821bb4e110af7067f52891606dcfc71e640c194ab1c117f0b941550e0b3ac36ad3511214ac80c536b9e5cfaf8789eec74cf56971a832ea8fc4e6d94
- def self.parse(wwwdir, version, rubydir)
+ def self.parse(wwwdir, version, rubydir, source_ref_or_sha = nil)
unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version
raise "unexpected version string '#{version}'"
end
- x = $1.to_i
- y = $2.to_i
- z = $3.to_i
- # previous tag for git diff --shortstat
- # It's only for x.y.0 release
- if z != 0
- prev_tag = nil
- elsif y != 0
- prev_tag = "v#{x}_#{y-1}_0"
- prev_ver = "#{x}.#{y-1}.0"
- elsif x == 3 && y == 0 && z == 0
- prev_tag = "v2_7_0"
- prev_ver = "2.7.0"
- else
- raise "unexpected version for prev_ver '#{version}'"
- end
+ teeny = Integer($3)
uri = "https://cache.ruby-lang.org/pub/tmp/ruby-info-#{version}-draft.yml"
- info = YAML.load(URI(uri).read)
+ info = YAML.unsafe_load(URI(uri).read)
if info.size != 1
raise "unexpected info.yml '#{uri}'"
end
@@ -88,10 +73,14 @@ eom
tarballs << tarball
end
- if prev_tag
+ if teeny == 0
# show diff shortstat
- tag = "v#{version.gsub(/[.\-]/, '_')}"
- stat = `git -C #{rubydir} diff -l0 --shortstat #{prev_tag}..#{tag}`
+ tag = source_ref_or_sha || RubyVersion.tag(version)
+ prev_tag = RubyVersion.tag(RubyVersion.previous(version))
+ stat = IO.popen(["git", "-C", rubydir, "diff", "-l0", "--shortstat", "#{prev_tag}..#{tag}"], &:read)
+ unless $?.success?
+ raise "failed to diff #{prev_tag}..#{tag}"
+ end
files_changed, insertions, deletions = stat.scan(/\d+/)
end
@@ -184,7 +173,7 @@ eom
if /\.0(?:-\w+)?\z/ =~ ver
# preview, rc, or first release
entry <<= <<eom
- tag: v#{ver.tr('.-', '_')}
+ tag: #{RubyVersion.tag(ver)}
stats:
files_changed: #{files_changed}
insertions: #{insertions}
@@ -196,34 +185,25 @@ eom
url:
gz: https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.tar.gz
zip: https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.zip
- bz2: https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.tar.bz2
xz: https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.tar.xz
size:
gz: #{ary.find{|x|x.gz? }.size}
zip: #{ary.find{|x|x.zip?}.size}
- bz2: #{ary.find{|x|x.bz2?}&.size}
xz: #{ary.find{|x|x.xz? }.size}
sha1:
gz: #{ary.find{|x|x.gz? }.sha1}
zip: #{ary.find{|x|x.zip?}.sha1}
- bz2: #{ary.find{|x|x.bz2?}&.sha1}
xz: #{ary.find{|x|x.xz? }.sha1}
sha256:
gz: #{ary.find{|x|x.gz? }.sha256}
zip: #{ary.find{|x|x.zip?}.sha256}
- bz2: #{ary.find{|x|x.bz2?}&.sha256}
xz: #{ary.find{|x|x.xz? }.sha256}
sha512:
gz: #{ary.find{|x|x.gz? }.sha512}
zip: #{ary.find{|x|x.zip?}.sha512}
- bz2: #{ary.find{|x|x.bz2?}&.sha512}
xz: #{ary.find{|x|x.xz? }.sha512}
eom
- if ver.start_with?("3.")
- entry = entry.gsub(/ bz2: .*\n/, "")
- end
-
if data.include?("\n- version: #{ver}\n")
# update existing entry
data.sub!(/\n- version: #{ver}\n(^ .*\n)*\n/, "\n#{entry}\n")
@@ -258,11 +238,12 @@ def main
wwwdir = ARGV.shift
version = ARGV.shift
rubydir = ARGV.shift
+ source_ref_or_sha = ARGV.shift
unless rubydir
- STDERR.puts "usage: format-release <dir-of-w.r-l.o> <version> <ruby-dir>"
+ STDERR.puts "usage: format-release <dir-of-w.r-l.o> <version> <ruby-dir> [source-ref-or-sha]"
exit
end
- Tarball.parse(wwwdir, version, rubydir)
+ Tarball.parse(wwwdir, version, rubydir, source_ref_or_sha)
end
main
diff --git a/tool/ifchange b/tool/ifchange
index 9e4a89533c..2a5f3db522 100755
--- a/tool/ifchange
+++ b/tool/ifchange
@@ -1,7 +1,8 @@
#!/bin/sh
# usage: ifchange target temporary
-# Used in generating revision.h via Makefiles.
+# Used in generating various files such as rbconfig.rb, revision.h,
+# etc. via Makefiles.
help() {
cat <<HELP
@@ -20,6 +21,7 @@ timestamp=
keepsuffix=
srcavail=f
color=auto
+[ "x${NO_COLOR-}" = x ] || color=never
until [ $# -eq 0 ]; do
case "$1" in
--)
diff --git a/tool/leaked-globals b/tool/leaked-globals
index 6118cd56e8..73da769318 100755
--- a/tool/leaked-globals
+++ b/tool/leaked-globals
@@ -96,7 +96,7 @@ Pipe.new(NM + ARGV).each do |line|
next
when /\Aruby_static_id_/
next unless so
- when /\A(?:RUBY_|ruby_|rb_)/
+ when /\A(?:RUBY_|ruby_|rb_|rbimpl_)/
next unless so and /_(threadptr|ec)_/ =~ n
when *SYMBOLS_IN_EMPTYLIB
next
diff --git a/tool/lib/_tmpdir.rb b/tool/lib/_tmpdir.rb
index fd429dab37..ac5b9be792 100644
--- a/tool/lib/_tmpdir.rb
+++ b/tool/lib/_tmpdir.rb
@@ -4,11 +4,11 @@ template = "rubytest."
# Assume the directory by these environment variables are safe.
base = [ENV["TMPDIR"], ENV["TMP"], "/tmp"].find do |tmp|
next unless tmp and tmp.size <= 50 and File.directory?(tmp)
- # On macOS, the default TMPDIR is very long, inspite of UNIX socket
- # path length is limited.
+ # On macOS, the default TMPDIR is very long, in spite of UNIX socket
+ # path length being limited.
#
# Also Rubygems creates its own temporary directory per tests, and
- # some tests copy the full path of gemhome there. In that caes, the
+ # some tests copy the full path of gemhome there. In that case, the
# path contains both temporary names twice, and can exceed path name
# limit very easily.
tmp
@@ -28,66 +28,71 @@ END {
Dir.rmdir(tmpdir)
rescue Errno::ENOENT
rescue Errno::ENOTEMPTY
- require_relative "colorize"
- colorize = Colorize.new
- ls = Struct.new(:colorize) do
- def mode_inspect(m, s)
- [
- (m & 0o4 == 0 ? ?- : ?r),
- (m & 0o2 == 0 ? ?- : ?w),
- (m & 0o1 == 0 ? (s ? s.upcase : ?-) : (s || ?x)),
- ]
- end
- def decorate_path(path, st)
- case
- when st.directory?
- color = "bold;blue"
- type = "/"
- when st.symlink?
- color = "bold;cyan"
- # type = "@"
- when st.executable?
- color = "bold;green"
- type = "*"
- when path.end_with?(".gem")
- color = "green"
+ unless $no_report_tmpdir ||= nil
+ require_relative "colorize"
+ colorize = Colorize.new
+ ls = Struct.new(:colorize) do
+ def mode_inspect(m, s)
+ [
+ (m & 0o4 == 0 ? ?- : ?r),
+ (m & 0o2 == 0 ? ?- : ?w),
+ (m & 0o1 == 0 ? (s ? s.upcase : ?-) : (s || ?x)),
+ ]
end
- colorize.decorate(path, color) + (type || "")
- end
- def list_tree(parent, indent = "", &block)
- children = Dir.children(parent).map do |child|
- [child, path = File.join(parent, child), File.lstat(path)]
+ def decorate_path(path, st)
+ case
+ when st.directory?
+ color = "bold;blue"
+ type = "/"
+ when st.symlink?
+ color = "bold;cyan"
+ # type = "@"
+ when st.executable?
+ color = "bold;green"
+ type = "*"
+ when path.end_with?(".gem")
+ color = "green"
+ end
+ colorize.decorate(path, color) + (type || "")
end
- nlink_width = children.map {|child, path, st| st.nlink}.max.to_s.size
- size_width = children.map {|child, path, st| st.size}.max.to_s.size
+ def list_tree(parent, indent = "", &block)
+ children = Dir.children(parent).map do |child|
+ [child, path = File.join(parent, child), File.lstat(path)]
+ end
+ nlink_width = children.map {|child, path, st| st.nlink}.max.to_s.size
+ size_width = children.map {|child, path, st| st.size}.max.to_s.size
- children.each do |child, path, st|
- m = st.mode
- m = [
- (st.file? ? ?- : st.ftype[0]),
- mode_inspect(m >> 6, (?s unless m & 04000 == 0)),
- mode_inspect(m >> 3, (?s unless m & 02000 == 0)),
- mode_inspect(m, (?t unless m & 01000 == 0)),
- ].join("")
- warn sprintf("%s* %s %*d %*d %s % s%s",
- indent, m, nlink_width, st.nlink, size_width, st.size,
- st.mtime.to_s, decorate_path(child, st),
- (" -> " + decorate_path(File.readlink(path), File.stat(path)) if
- st.symlink?))
- if st.directory?
- list_tree(File.join(parent, child), indent + " ", &block)
+ children.each do |child, path, st|
+ m = st.mode
+ m = [
+ (st.file? ? ?- : st.ftype[0]),
+ mode_inspect(m >> 6, (?s unless m & 04000 == 0)),
+ mode_inspect(m >> 3, (?s unless m & 02000 == 0)),
+ mode_inspect(m, (?t unless m & 01000 == 0)),
+ ].join("")
+ warn sprintf("%s* %s %*d %*d %s % s%s",
+ indent, m, nlink_width, st.nlink, size_width, st.size,
+ st.mtime.to_s, decorate_path(child, st),
+ (" -> " + decorate_path(File.readlink(path), File.stat(path)) if
+ st.symlink?))
+ if st.directory?
+ list_tree(File.join(parent, child), indent + " ", &block)
+ end
+ yield path, st if block
end
- yield path, st if block
end
- end
- end.new(colorize)
- warn colorize.notice("Children under ")+colorize.fail(tmpdir)+":"
- Dir.chdir(tmpdir) do
- ls.list_tree(".") do |path, st|
- if st.directory?
- Dir.rmdir(path)
- else
- File.unlink(path)
+ end.new(colorize)
+ warn colorize.notice("Children under ")+colorize.fail(tmpdir)+":"
+ Dir.chdir(tmpdir) do
+ ls.list_tree(".") do |path, st|
+ if st.directory?
+ Dir.rmdir(path)
+ else
+ File.unlink(path)
+ end
+ rescue Errno::EACCES
+ # On Windows, a killed process may still hold file locks briefly.
+ # Ignore and let FileUtils.rm_rf handle it below.
end
end
end
diff --git a/tool/lib/bundle_env.rb b/tool/lib/bundle_env.rb
new file mode 100644
index 0000000000..9ad5ea220b
--- /dev/null
+++ b/tool/lib/bundle_env.rb
@@ -0,0 +1,4 @@
+ENV["GEM_HOME"] = File.expand_path("../../.bundle", __dir__)
+ENV["BUNDLE_APP_CONFIG"] = File.expand_path("../../.bundle", __dir__)
+ENV["BUNDLE_PATH__SYSTEM"] = "true"
+ENV["BUNDLE_WITHOUT"] = "lint doc"
diff --git a/tool/lib/bundled_gem.rb b/tool/lib/bundled_gem.rb
index 45e41ac648..ad103825bc 100644
--- a/tool/lib/bundled_gem.rb
+++ b/tool/lib/bundled_gem.rb
@@ -16,11 +16,21 @@ module BundledGem
"psych" # rdoc
]
+ def self.command(gem, cmd)
+ if stub = Gem::Specification.latest_spec_for(gem)
+ spec = stub.spec
+ File.join(spec.gem_dir, spec.bindir, cmd)
+ end
+ end
+
module_function
def unpack(file, *rest)
pkg = Gem::Package.new(file)
- prepare_test(pkg.spec, *rest) {|dir| pkg.extract_files(dir)}
+ prepare_test(pkg.spec, *rest) do |dir|
+ pkg.extract_files(dir)
+ FileUtils.rm_rf(Dir.glob(".git*", base: dir).map {|n| File.join(dir, n)})
+ end
puts "Unpacked #{file}"
rescue Gem::Package::FormatError, Errno::ENOENT
puts "Try with hash version of bundled gems instead of #{file}. We don't use this gem with release version of Ruby."
@@ -120,4 +130,46 @@ module BundledGem
command = "#{git} checkout --detach #{rev}"
system(command, chdir: gemdir) or raise "failed: #{command}"
end
+
+ class GemspecLoader
+ module NoPipe
+ refine IO.singleton_class do
+ def popen(...) ""; end
+ end
+ end
+ using NoPipe
+
+ def `(command) ""; end
+
+ def load_gemspec(file)
+ code = File.read(file, encoding: "utf-8:-")
+ eval(code, binding, file)
+ rescue
+ nil
+ end
+ end
+
+ def load_gemspec(g)
+ spec = GemspecLoader.new.load_gemspec(g)
+ spec.files.clear
+ spec.extensions.clear
+ src = spec.to_ruby
+ src.sub!(/^$$/) {
+ %[# default: #{g} #{File.mtime(g).strftime(%[%s.%N])}\n]
+ }
+ return spec.full_name+'.gemspec', src
+ end
+
+ def update_default_gemspecs(basedirs, out, quiet: true)
+ basedirs.each do |basedir|
+ Dir.glob(basedir+'/**/*.gemspec') do |g|
+ name, src = BundledGem.load_gemspec(g)
+ unless src
+ puts "Ignoring #{g}" unless quiet
+ next
+ end
+ out.write(src, name: name, newer: File.mtime(g), quiet: quiet)
+ end
+ end
+ end
end
diff --git a/tool/lib/colorize.rb b/tool/lib/colorize.rb
index 0904312119..89da90e075 100644
--- a/tool/lib/colorize.rb
+++ b/tool/lib/colorize.rb
@@ -1,57 +1,78 @@
# frozen-string-literal: true
+# Decorate TTY output using ANSI Select Graphic Rendition control
+# sequences.
class Colorize
# call-seq:
# Colorize.new(colorize = nil)
# Colorize.new(color: color, colors_file: colors_file)
- def initialize(color = nil, opts = ((_, color = color, nil)[0] if Hash === color))
- @colors = @reset = nil
- @color = opts && opts[:color] || color
+ #
+ # Creates and load color settings.
+ def initialize(_color = nil, color: _color, colors_file: nil)
+ @colors = nil
+ @color = color
if color or (color == nil && coloring?)
- if (%w[smso so].any? {|attr| /\A\e\[.*m\z/ =~ IO.popen("tput #{attr}", "r", :err => IO::NULL, &:read)} rescue nil)
+ if (%w[smso so].any? {|attr| /\A\e\[.*m\z/ =~ IO.popen("tput #{attr}", "r", err: IO::NULL, &:read)} rescue nil)
@beg = "\e["
- colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(/(\w+)=([^:\n]*)/)] : {}
- if opts and colors_file = opts[:colors_file]
+ colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(COLORS_PATTERN)] : {}
+ if colors_file
begin
- File.read(colors_file).scan(/(\w+)=([^:\n]*)/) do |n, c|
+ File.read(colors_file).scan(COLORS_PATTERN) do |n, c|
colors[n] ||= c
end
rescue Errno::ENOENT
end
end
@colors = colors
- @reset = "#{@beg}m"
end
end
self
end
+ COLORS_PATTERN = /(\w+)=([^:\n]*)/
+ private_constant :COLORS_PATTERN
+
DEFAULTS = {
# color names
"black"=>"30", "red"=>"31", "green"=>"32", "yellow"=>"33",
"blue"=>"34", "magenta"=>"35", "cyan"=>"36", "white"=>"37",
- "bold"=>"1", "underline"=>"4", "reverse"=>"7",
+ "bold"=>"1", "faint"=>"2", "underline"=>"4", "reverse"=>"7",
"bright_black"=>"90", "bright_red"=>"91", "bright_green"=>"92", "bright_yellow"=>"93",
"bright_blue"=>"94", "bright_magenta"=>"95", "bright_cyan"=>"96", "bright_white"=>"97",
+ "bg_black"=>"40", "bg_red"=>"41", "bg_green"=>"42", "bg_yellow"=>"43",
+ "bg_blue"=>"44", "bg_magenta"=>"45", "bg_cyan"=>"46", "bg_white"=>"47",
+ "bg_bright_black"=>"100", "bg_bright_red"=>"101",
+ "bg_bright_green"=>"102", "bg_bright_yellow"=>"103",
+ "bg_bright_blue"=>"104", "bg_bright_magenta"=>"105",
+ "bg_bright_cyan"=>"106", "bg_bright_white"=>"107",
# abstract decorations
"pass"=>"green", "fail"=>"red;bold", "skip"=>"yellow;bold",
"note"=>"bright_yellow", "notice"=>"bright_yellow", "info"=>"bright_magenta",
- }
-
- def coloring?
- STDOUT.tty? && (!(nc = ENV['NO_COLOR']) || nc.empty?)
- end
+ }.freeze
+ private_constant :DEFAULTS
# colorize.decorate(str, name = color_name)
def decorate(str, name = @color)
if coloring? and color = resolve_color(name)
- "#{@beg}#{color}m#{str}#{@reset}"
+ "#{@beg}#{color}m#{str}#{reset_color(color)}"
else
str
end
end
+ DEFAULTS.each_key do |name|
+ define_method(name) {|str|
+ decorate(str, name)
+ }
+ end
+
+ private
+
+ def coloring?
+ STDOUT.tty? && (!(nc = ENV['NO_COLOR']) || nc.empty?)
+ end
+
def resolve_color(color = @color, seen = {}, colors = nil)
return unless @colors
color.to_s.gsub(/\b[a-z][\w ]+/) do |n|
@@ -69,10 +90,23 @@ class Colorize
end
end
- DEFAULTS.each_key do |name|
- define_method(name) {|str|
- decorate(str, name)
- }
+ def reset_color(colors)
+ resets = []
+ colors.scan(/\G;*\K(?:[34]8;(?:5;\d+|2(?:;\d+){3})|\d+)/) do |c|
+ case c
+ when '1', '2'
+ resets << '22'
+ when '4'
+ resets << '24'
+ when '7'
+ resets << '27'
+ when /\A[39]\d(?:;|\z)/
+ resets << '39'
+ when /\A(?:4|10)\d(?:;|\z)/
+ resets << '49'
+ end
+ end
+ "#{@beg}#{resets.reverse.join(';')}m"
end
end
diff --git a/tool/lib/core_assertions.rb b/tool/lib/core_assertions.rb
index ede490576c..5ca318a598 100644
--- a/tool/lib/core_assertions.rb
+++ b/tool/lib/core_assertions.rb
@@ -75,9 +75,18 @@ module Test
require_relative 'envutil'
require 'pp'
begin
- require '-test-/asan'
+ require '-test-/sanitizers'
rescue LoadError
+ # in test-unit-ruby-core gem
+ def sanitizers
+ nil
+ end
+ else
+ def sanitizers
+ Test::Sanitizers
+ end
end
+ module_function :sanitizers
nil.pretty_inspect
@@ -97,11 +106,14 @@ module Test
end
def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil,
- success: nil, **opt)
+ success: nil, failed: nil, gems: false, **opt)
args = Array(args).dup
- args.insert((Hash === args[0] ? 1 : 0), '--disable=gems')
+ unless gems.nil?
+ args.insert((Hash === args[0] ? 1 : 0), "--#{gems ? 'enable' : 'disable'}=gems")
+ end
stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, **opt)
- desc = FailDesc[status, message, stderr]
+ desc = failed[status, message, stderr] if failed
+ desc ||= FailDesc[status, message, stderr]
if block_given?
raise "test_stdout ignored, use block only or without block" if test_stdout != []
raise "test_stderr ignored, use block only or without block" if test_stderr != []
@@ -159,7 +171,7 @@ module Test
pend 'assert_no_memory_leak may consider MJIT memory usage as leak' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?
# ASAN has the same problem - its shadow memory greatly increases memory usage
# (plus asan has better ways to detect memory leaks than this assertion)
- pend 'assert_no_memory_leak may consider ASAN memory usage as leak' if defined?(Test::ASAN) && Test::ASAN.enabled?
+ pend 'assert_no_memory_leak may consider ASAN memory usage as leak' if sanitizers&.asan_enabled?
require_relative 'memory_status'
raise Test::Unit::PendedError, "unsupported platform" unless defined?(Memory::Status)
@@ -291,9 +303,34 @@ module Test
def separated_runner(token, out = nil)
include(*Test::Unit::TestCase.ancestors.select {|c| !c.is_a?(Class) })
+
out = out ? IO.new(out, 'w') : STDOUT
+
+ # avoid method redefinitions
+ out_write = out.method(:write)
+ integer_to_s = Integer.instance_method(:to_s)
+ array_pack = Array.instance_method(:pack)
+ marshal_dump = Marshal.method(:dump)
+ assertions_ivar_set = Test::Unit::Assertions.method(:instance_variable_set)
+ assertions_ivar_get = Test::Unit::Assertions.method(:instance_variable_get)
+ Test::Unit::Assertions.module_eval do
+ @_assertions = 0
+
+ undef _assertions=
+ define_method(:_assertions=, ->(n) {assertions_ivar_set.call(:@_assertions, n)})
+
+ undef _assertions
+ define_method(:_assertions, -> {assertions_ivar_get.call(:@_assertions)})
+ end
+ # assume Method#call and UnboundMethod#bind_call need to work as the original
+
at_exit {
- out.puts "#{token}<error>", [Marshal.dump($!)].pack('m'), "#{token}</error>", "#{token}assertions=#{self._assertions}"
+ assertions = assertions_ivar_get.call(:@_assertions)
+ out_write.call <<~OUT
+ <error id="#{token}" assertions=#{integer_to_s.bind_call(assertions)}>
+ #{array_pack.bind_call([marshal_dump.call($!)], 'm0')}
+ </error id="#{token}">
+ OUT
}
if defined?(Test::Unit::Runner)
Test::Unit::Runner.class_variable_set(:@@stop_auto_run, true)
@@ -327,7 +364,16 @@ eom
args = args.dup
args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"})
args << "--debug" if RUBY_ENGINE == 'jruby' # warning: tracing (e.g. set_trace_func) will not capture all events without --debug flag
+ # power_assert 3 requires ruby 3.1 or later
+ args << "-W:no-experimental" if RUBY_VERSION < "3.1."
stdout, stderr, status = EnvUtil.invoke_ruby(args, src, capture_stdout, true, **opt)
+
+ if sanitizers&.lsan_enabled?
+ # LSAN may output messages like the following line into stderr. We should ignore it.
+ # ==276855==Running thread 276851 was not suspended. False leaks are possible.
+ # See https://github.com/google/sanitizers/issues/1479
+ stderr.gsub!(/==\d+==Running thread \d+ was not suspended\. False leaks are possible\.\n/, "")
+ end
ensure
if res_c
res_c.close
@@ -338,15 +384,16 @@ eom
end
raise if $!
abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig))
+ marshal_error = nil
assert(!abort, FailDesc[status, nil, stderr])
- self._assertions += res[/^#{token_re}assertions=(\d+)/, 1].to_i
- begin
- res = Marshal.load(res[/^#{token_re}<error>\n\K.*\n(?=#{token_re}<\/error>$)/m].unpack1("m"))
+ res.scan(/^<error id="#{token_re}" assertions=(\d+)>\n(.*?)\n(?=<\/error id="#{token_re}">$)/m) do
+ self._assertions += $1.to_i
+ res = Marshal.load($2.unpack1("m")) or next
rescue => marshal_error
ignore_stderr = nil
res = nil
- end
- if res and !(SystemExit === res)
+ else
+ next if SystemExit === res
if bt = res.backtrace
bt.each do |l|
l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"}
@@ -358,7 +405,7 @@ eom
raise res
end
- # really is it succeed?
+ # really did it succeed?
unless ignore_stderr
# the body of assert_separately must not output anything to detect error
assert(stderr.empty?, FailDesc[status, "assert_separately failed with error message", stderr])
@@ -369,9 +416,17 @@ eom
# Run Ractor-related test without influencing the main test suite
def assert_ractor(src, args: [], require: nil, require_relative: nil, file: nil, line: nil, ignore_stderr: nil, **opt)
- return unless defined?(Ractor)
+ omit unless defined?(Ractor)
+
+ # https://bugs.ruby-lang.org/issues/21262
+ shim_value = "class Ractor; alias value take; end" unless Ractor.method_defined?(:value)
+ shim_join = "class Ractor; alias join take; end" unless Ractor.method_defined?(:join)
+
+ if require
+ require = [require] unless require.is_a?(Array)
+ require = require.map {|r| "require #{r.inspect}"}.join("\n")
+ end
- require = "require #{require.inspect}" if require
if require_relative
dir = File.dirname(caller_locations[0,1][0].absolute_path)
full_path = File.expand_path(require_relative, dir)
@@ -379,6 +434,8 @@ eom
end
assert_separately(args, file, line, <<~RUBY, ignore_stderr: ignore_stderr, **opt)
+ #{shim_value}
+ #{shim_join}
#{require}
previous_verbose = $VERBOSE
$VERBOSE = nil
@@ -494,13 +551,10 @@ eom
assert = :assert_match
end
- ex = m = nil
- EnvUtil.with_default_internal(of: expected) do
- ex = assert_raise(exception, msg || proc {"Exception(#{exception}) with message matches to #{expected.inspect}"}) do
- yield
- end
- m = ex.message
+ ex = assert_raise(exception, msg || proc {"Exception(#{exception}) with message matches to #{expected.inspect}"}) do
+ yield
end
+ m = ex.message
msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"}
if assert == :assert_equal
@@ -683,17 +737,15 @@ eom
assert_warning(*args) {$VERBOSE = false; yield}
end
- def assert_deprecated_warning(mesg = /deprecated/)
+ def assert_deprecated_warning(mesg = /deprecated/, &block)
assert_warning(mesg) do
- Warning[:deprecated] = true if Warning.respond_to?(:[]=)
- yield
+ EnvUtil.deprecation_warning(&block)
end
end
- def assert_deprecated_warn(mesg = /deprecated/)
+ def assert_deprecated_warn(mesg = /deprecated/, &block)
assert_warn(mesg) do
- Warning[:deprecated] = true if Warning.respond_to?(:[]=)
- yield
+ EnvUtil.deprecation_warning(&block)
end
end
@@ -830,6 +882,9 @@ eom
rescue
# Constants may be defined but not implemented, e.g., mingw.
else
+ unless Process.clock_getres(clk) < 1.0e-03
+ next # needs msec precision
+ end
PERFORMANCE_CLOCK = clk
end
end
@@ -856,10 +911,11 @@ eom
first = seq.first
*arg = pre.call(first)
- times = (0..(rehearsal || (2 * first))).map do
+ raw_times = (0..(rehearsal || (2 * first))).map do
measure[arg, "rehearsal"].nonzero?
end
- times.compact!
+ times = raw_times.compact
+ raise "all measurements are zero: #{raw_times.inspect}" if times.empty?
tmin, tmax = times.minmax
# safe_factor * tmax * rehearsal_time_variance_factor(equals to 1 when variance is small)
diff --git a/tool/lib/dump.gdb b/tool/lib/dump.gdb
new file mode 100644
index 0000000000..56b420a546
--- /dev/null
+++ b/tool/lib/dump.gdb
@@ -0,0 +1,17 @@
+set height 0
+set width 0
+set confirm off
+
+echo \n>>> Threads\n\n
+info threads
+
+echo \n>>> Machine level backtrace\n\n
+thread apply all info stack full
+
+echo \n>>> Dump Ruby level backtrace (if possible)\n\n
+call rb_vmdebug_stack_dump_all_threads()
+call fflush(stderr)
+
+echo ">>> Finish\n"
+detach
+quit
diff --git a/tool/lib/dump.lldb b/tool/lib/dump.lldb
new file mode 100644
index 0000000000..ed9cb89010
--- /dev/null
+++ b/tool/lib/dump.lldb
@@ -0,0 +1,13 @@
+script print("\n>>> Threads\n\n")
+thread list
+
+script print("\n>>> Machine level backtrace\n\n")
+thread backtrace all
+
+script print("\n>>> Dump Ruby level backtrace (if possible)\n\n")
+call rb_vmdebug_stack_dump_all_threads()
+call fflush(stderr)
+
+script print(">>> Finish\n")
+detach
+quit
diff --git a/tool/lib/envutil.rb b/tool/lib/envutil.rb
index 65c86c1685..b4c7d1d035 100644
--- a/tool/lib/envutil.rb
+++ b/tool/lib/envutil.rb
@@ -63,6 +63,14 @@ module EnvUtil
end
end
+ if RUBY_ENGINE == "truffleruby"
+ # Tests relying on timeout have high variance on TruffleRuby due to the highly-optimizing JIT, deoptimization, profiling interpreter, different GC, etc.
+ # Setting a default timeout scale helps avoid transient failures for tests relying on timeouts.
+ # We choose 10 because it is the same number used in CRuby CI on macOS:
+ # https://github.com/ruby/ruby/blob/9d46b0c735877f152a0b4b16b8153c6f395dee28/.github/workflows/macos.yml#L133
+ self.timeout_scale = 10
+ end
+
def apply_timeout_scale(t)
if scale = EnvUtil.timeout_scale
t * scale
@@ -79,6 +87,72 @@ module EnvUtil
end
module_function :timeout
+ class Debugger
+ @list = []
+
+ attr_accessor :name
+
+ def self.register(name, &block)
+ @list << new(name, &block)
+ end
+
+ def initialize(name, &block)
+ @name = name
+ instance_eval(&block)
+ end
+
+ def usable?; false; end
+
+ def start(pid, *args) end
+
+ def dump(pid, timeout: 60, reprieve: timeout&.div(4))
+ dpid = start(pid, *command_file(File.join(__dir__, "dump.#{name}")), out: :err)
+ rescue Errno::ENOENT
+ return
+ else
+ return unless dpid
+ [[timeout, :TERM], [reprieve, :KILL]].find do |t, sig|
+ begin
+ return EnvUtil.timeout(t) {Process.wait(dpid)}
+ rescue Timeout::Error
+ Process.kill(sig, dpid)
+ end
+ end
+ true
+ end
+
+ # sudo -n: --non-interactive
+ PRECOMMAND = (%[sudo -n] if /darwin/ =~ RUBY_PLATFORM)
+
+ def spawn(*args, **opts)
+ super(*PRECOMMAND, *args, **opts)
+ end
+
+ register("gdb") do
+ class << self
+ def usable?; system(*%w[gdb --batch --quiet --nx -ex exit]); end
+ def start(pid, *args, **opts)
+ spawn(*%W[gdb --batch --quiet --pid #{pid}], *args, **opts)
+ end
+ def command_file(file) "--command=#{file}"; end
+ end
+ end
+
+ register("lldb") do
+ class << self
+ def usable?; system(*%w[lldb -Q --no-lldbinit -o exit]); end
+ def start(pid, *args, **opts)
+ spawn(*%W[lldb --batch -Q --attach-pid #{pid}], *args, **opts)
+ end
+ def command_file(file) ["--source", file]; end
+ end
+ end
+
+ def self.search
+ @debugger ||= @list.find(&:usable?)
+ end
+ end
+
def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
reprieve = apply_timeout_scale(reprieve) if reprieve
@@ -94,17 +168,12 @@ module EnvUtil
pgroup = pid
end
- lldb = true if /darwin/ =~ RUBY_PLATFORM
-
+ dumped = false
while signal = signals.shift
- if lldb and [:ABRT, :KILL].include?(signal)
- lldb = false
- # sudo -n: --non-interactive
- # lldb -p: attach
- # -o: run command
- system(*%W[sudo -n lldb -p #{pid} --batch -o bt\ all -o call\ rb_vmdebug_stack_dump_all_threads() -o quit])
- true
+ if !dumped and [:ABRT, :KILL].include?(signal)
+ Debugger.search&.dump(pid)
+ dumped = true
end
begin
@@ -166,8 +235,8 @@ module EnvUtil
args = [args] if args.kind_of?(String)
# use the same parser as current ruby
- if args.none? { |arg| arg.start_with?("--parser=") }
- current_parser = RUBY_DESCRIPTION =~ /prism/i ? "prism" : "parse.y"
+ if (args.none? { |arg| arg.start_with?("--parser=") } and
+ /^ +--parser=/ =~ IO.popen([rubybin, "--help"], &:read))
args = ["--parser=#{current_parser}"] + args
end
pid = spawn(child_env, *precommand, rubybin, *args, opt)
@@ -217,6 +286,12 @@ module EnvUtil
end
module_function :invoke_ruby
+ def current_parser
+ features = RUBY_DESCRIPTION[%r{\)\K [-+*/%._0-9a-zA-Z\[\] ]*(?=\[[-+*/%._0-9a-zA-Z]+\]\z)}]
+ features&.split&.include?("+PRISM") ? "prism" : "parse.y"
+ end
+ module_function :current_parser
+
def verbose_warning
class << (stderr = "".dup)
alias write concat
@@ -233,6 +308,21 @@ module EnvUtil
end
module_function :verbose_warning
+ if defined?(Warning.[]=)
+ def deprecation_warning
+ previous_deprecated = Warning[:deprecated]
+ Warning[:deprecated] = true
+ yield
+ ensure
+ Warning[:deprecated] = previous_deprecated
+ end
+ else
+ def deprecation_warning
+ yield
+ end
+ end
+ module_function :deprecation_warning
+
def default_warning
$VERBOSE = false
yield
diff --git a/tool/lib/gem_env.rb b/tool/lib/gem_env.rb
index 70a2469db2..1893e07657 100644
--- a/tool/lib/gem_env.rb
+++ b/tool/lib/gem_env.rb
@@ -1,2 +1 @@
-ENV['GEM_HOME'] = gem_home = File.expand_path('.bundle')
-ENV['GEM_PATH'] = [gem_home, File.expand_path('../../../.bundle', __FILE__)].uniq.join(File::PATH_SEPARATOR)
+ENV['GEM_HOME'] = File.expand_path('../../.bundle', __dir__)
diff --git a/tool/lib/leakchecker.rb b/tool/lib/leakchecker.rb
index 69aeb2c254..33a546699f 100644
--- a/tool/lib/leakchecker.rb
+++ b/tool/lib/leakchecker.rb
@@ -77,6 +77,7 @@ class LeakChecker
end
(h[fd] ||= []) << [io, autoclose, inspect]
}
+ inspect = {}
fd_leaked.select! {|fd|
str = ''.dup
pos = nil
@@ -98,6 +99,7 @@ class LeakChecker
s = io.stat
rescue Errno::EBADF
# something un-stat-able
+ live2.delete(fd)
next
else
next if /darwin/ =~ RUBY_PLATFORM and [0, -1].include?(s.dev)
@@ -106,15 +108,41 @@ class LeakChecker
io&.close
end
end
- puts "Leaked file descriptor: #{test_name}: #{fd}#{str}"
- puts " The IO was created at #{pos}" if pos
+ inspect[fd] = [str, pos]
true
}
unless fd_leaked.empty?
unless @@try_lsof == false
- @@try_lsof |= system(*%W[lsof -a -d #{fd_leaked.minmax.uniq.join("-")} -p #$$], out: Test::Unit::Runner.output)
+ begin
+ open_list = IO.popen(%W[lsof -w -a -d #{fd_leaked.minmax.uniq.join("-")} -p #$$], &:readlines)
+ rescue
+ @@try_lsof = false
+ else
+ @@try_lsof |= $?.success?
+ end
+ if header = open_list&.shift
+ columns = header.split
+ fd_index, node_index = columns.index('FD'), columns.index('NODE')
+ open_list.reject! do |of|
+ of = of.chomp.split(' ', node_index + 2)
+ if of[node_index] == 'TCP' and of.last.end_with?('(CLOSE_WAIT)')
+ fd = of[fd_index].to_i
+ inspect.delete(fd)
+ h.delete(fd)
+ live2.delete(fd)
+ true
+ else
+ false
+ end
+ end
+ puts(header, open_list) unless open_list.empty?
+ end
end
end
+ inspect.each {|fd, (str, pos)|
+ puts "Leaked file descriptor: #{test_name}: #{fd}#{str}"
+ puts " The IO was created at #{pos}" if pos
+ }
h.each {|fd, list|
next if list.length <= 1
if 1 < list.count {|io, autoclose, inspect| autoclose }
@@ -156,7 +184,7 @@ class LeakChecker
[prev_count, []]
else
tempfiles = ObjectSpace.each_object(Tempfile).reject {|t|
- t.instance_variables.empty? || t.closed?
+ t.instance_variables.empty? || (t.closed? rescue true)
}
[count, tempfiles]
end
diff --git a/tool/lib/memory_status.rb b/tool/lib/memory_status.rb
index 60632523a8..429e5f6a1d 100644
--- a/tool/lib/memory_status.rb
+++ b/tool/lib/memory_status.rb
@@ -20,48 +20,68 @@ module Memory
data.scan(pat) {|k, v| keys << k.downcase.intern}
when /mswin|mingw/ =~ RUBY_PLATFORM
- require 'fiddle/import'
- require 'fiddle/types'
-
- module Win32
- extend Fiddle::Importer
- dlload "kernel32.dll", "psapi.dll"
- include Fiddle::Win32Types
- typealias "SIZE_T", "size_t"
-
- PROCESS_MEMORY_COUNTERS = struct [
- "DWORD cb",
- "DWORD PageFaultCount",
- "SIZE_T PeakWorkingSetSize",
- "SIZE_T WorkingSetSize",
- "SIZE_T QuotaPeakPagedPoolUsage",
- "SIZE_T QuotaPagedPoolUsage",
- "SIZE_T QuotaPeakNonPagedPoolUsage",
- "SIZE_T QuotaNonPagedPoolUsage",
- "SIZE_T PagefileUsage",
- "SIZE_T PeakPagefileUsage",
- ]
-
- typealias "PPROCESS_MEMORY_COUNTERS", "PROCESS_MEMORY_COUNTERS*"
-
- extern "HANDLE GetCurrentProcess()", :stdcall
- extern "BOOL GetProcessMemoryInfo(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD)", :stdcall
-
- module_function
- def memory_info
- size = PROCESS_MEMORY_COUNTERS.size
- data = PROCESS_MEMORY_COUNTERS.malloc
- data.cb = size
- data if GetProcessMemoryInfo(GetCurrentProcess(), data, size)
+ keys.push(:size, :rss, :peak)
+
+ begin
+ require 'fiddle/import'
+ require 'fiddle/types'
+ rescue LoadError
+ # Fallback to PowerShell command to get memory information for current process
+ def self.read_status
+ cmd = [
+ "powershell.exe", "-NoProfile", "-Command",
+ "Get-Process -Id #{$$} | " \
+ "% { Write-Output $_.PagedMemorySize64 $_.WorkingSet64 $_.PeakWorkingSet64 }"
+ ]
+
+ IO.popen(cmd, "r", err: [:child, :out]) do |out|
+ if /^(\d+)\n(\d+)\n(\d+)$/ =~ out.read
+ yield :size, $1.to_i
+ yield :rss, $2.to_i
+ yield :peak, $3.to_i
+ end
+ end
+ end
+ else
+ module Win32
+ extend Fiddle::Importer
+ dlload "kernel32.dll", "psapi.dll"
+ include Fiddle::Win32Types
+ typealias "SIZE_T", "size_t"
+
+ PROCESS_MEMORY_COUNTERS = struct [
+ "DWORD cb",
+ "DWORD PageFaultCount",
+ "SIZE_T PeakWorkingSetSize",
+ "SIZE_T WorkingSetSize",
+ "SIZE_T QuotaPeakPagedPoolUsage",
+ "SIZE_T QuotaPagedPoolUsage",
+ "SIZE_T QuotaPeakNonPagedPoolUsage",
+ "SIZE_T QuotaNonPagedPoolUsage",
+ "SIZE_T PagefileUsage",
+ "SIZE_T PeakPagefileUsage",
+ ]
+
+ typealias "PPROCESS_MEMORY_COUNTERS", "PROCESS_MEMORY_COUNTERS*"
+
+ extern "HANDLE GetCurrentProcess()", :stdcall
+ extern "BOOL GetProcessMemoryInfo(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD)", :stdcall
+
+ module_function
+ def memory_info
+ size = PROCESS_MEMORY_COUNTERS.size
+ data = PROCESS_MEMORY_COUNTERS.malloc
+ data.cb = size
+ data if GetProcessMemoryInfo(GetCurrentProcess(), data, size)
+ end
end
- end
- keys.push(:size, :rss, :peak)
- def self.read_status
- if info = Win32.memory_info
- yield :size, info.PagefileUsage
- yield :rss, info.WorkingSetSize
- yield :peak, info.PeakWorkingSetSize
+ def self.read_status
+ if info = Win32.memory_info
+ yield :size, info.PagefileUsage
+ yield :rss, info.WorkingSetSize
+ yield :peak, info.PeakWorkingSetSize
+ end
end
end
when (require_relative 'find_executable'
diff --git a/tool/lib/output.rb b/tool/lib/output.rb
index 8cb426ae4a..8590e0ffe2 100644
--- a/tool/lib/output.rb
+++ b/tool/lib/output.rb
@@ -31,8 +31,8 @@ class Output
@vpath.def_options(opt)
end
- def write(data, overwrite: @overwrite, create_only: @create_only)
- unless @path
+ def write(data, overwrite: @overwrite, create_only: @create_only, name: nil, newer: nil, quiet: false)
+ unless (name = name ? (@path ? File.join(@path, name) : name) : @path)
$stdout.print data
return true
end
@@ -41,20 +41,21 @@ class Output
updated = color.fail("updated")
outpath = nil
- if (@ifchange or overwrite or create_only) and (@vpath.open(@path, "rb") {|f|
+ if (@ifchange or overwrite or create_only or newer) and (@vpath.open(name, "rb") {|f|
outpath = f.path
+ next true if newer and f.mtime > newer
if @ifchange or create_only
original = f.read
(@ifchange and original == data) or (create_only and !original.empty?)
end
} rescue false)
- puts "#{outpath} #{unchanged}"
+ puts "#{outpath} #{unchanged}" unless quiet
written = false
else
unless overwrite and outpath and (File.binwrite(outpath, data) rescue nil)
- File.binwrite(outpath = @path, data)
+ File.binwrite(outpath = name, data)
end
- puts "#{outpath} #{updated}"
+ puts "#{outpath} #{updated}" unless quiet
written = true
end
if timestamp = @timestamp
diff --git a/tool/lib/test/jobserver.rb b/tool/lib/test/jobserver.rb
new file mode 100644
index 0000000000..7b889163b0
--- /dev/null
+++ b/tool/lib/test/jobserver.rb
@@ -0,0 +1,47 @@
+module Test
+ module JobServer
+ end
+end
+
+class << Test::JobServer
+ def connect(makeflags = ENV["MAKEFLAGS"])
+ return unless /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ makeflags
+ begin
+ if fifo = $3
+ fifo.gsub!(/\\(?=.)/, '')
+ r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY)
+ w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY)
+ else
+ r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
+ w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
+ end
+ rescue
+ r&.close
+ nil
+ else
+ return r, w
+ end
+ end
+
+ def acquire_possible(r, w, max)
+ return unless tokens = r.read_nonblock(max - 1, exception: false)
+ if (jobs = tokens.size) > 0
+ jobserver, w = w, nil
+ at_exit do
+ jobserver.print(tokens)
+ jobserver.close
+ end
+ end
+ return jobs + 1
+ rescue Errno::EBADF
+ ensure
+ r&.close
+ w&.close
+ end
+
+ def max_jobs(max = 2, makeflags = ENV["MAKEFLAGS"])
+ if max > 1 and (r, w = connect(makeflags))
+ acquire_possible(r, w, max)
+ end
+ end
+end
diff --git a/tool/lib/test/unit.rb b/tool/lib/test/unit.rb
index 9ca29b6e64..2663b7b76a 100644
--- a/tool/lib/test/unit.rb
+++ b/tool/lib/test/unit.rb
@@ -19,6 +19,7 @@ require_relative '../envutil'
require_relative '../colorize'
require_relative '../leakchecker'
require_relative '../test/unit/testcase'
+require_relative '../test/jobserver'
require 'optparse'
# See Test::Unit
@@ -262,27 +263,8 @@ module Test
def non_options(files, options)
@jobserver = nil
- makeflags = ENV.delete("MAKEFLAGS")
- if !options[:parallel] and
- /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ makeflags
- begin
- if fifo = $3
- fifo.gsub!(/\\(?=.)/, '')
- r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY)
- w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY)
- else
- r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
- w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
- end
- rescue
- r.close if r
- nil
- else
- r.close_on_exec = true
- w.close_on_exec = true
- @jobserver = [r, w]
- options[:parallel] ||= 256 # number of tokens to acquire first
- end
+ if !options[:parallel] and @jobserver = Test::JobServer.connect(ENV.delete("MAKEFLAGS"))
+ options[:parallel] ||= 256 # number of tokens to acquire first
end
@worker_timeout = EnvUtil.apply_timeout_scale(options[:worker_timeout] || 1200)
super
@@ -421,6 +403,7 @@ module Test
end
def kill
+ EnvUtil::Debugger.search&.dump(@pid)
signal = RUBY_PLATFORM =~ /mswin|mingw/ ? :KILL : :SEGV
Process.kill(signal, @pid)
warn "worker #{to_s} does not respond; #{signal} is sent"
@@ -1298,10 +1281,15 @@ module Test
parser.on '--repeat-count=NUM', "Number of times to repeat", Integer do |n|
options[:repeat_count] = n
end
+ options[:keep_repeating] = false
+ parser.on '--[no-]keep-repeating', "Keep repeating even failed" do |n|
+ options[:keep_repeating] = true
+ end
end
def _run_anything(type)
@repeat_count = @options[:repeat_count]
+ @keep_repeating = @options[:keep_repeating]
super
end
end
@@ -1623,7 +1611,7 @@ module Test
[(@repeat_count ? "(#{@@current_repeat_count}/#{@repeat_count}) " : ""), type,
t, @test_count.fdiv(t), @assertion_count.fdiv(t)]
end while @repeat_count && @@current_repeat_count < @repeat_count &&
- report.empty? && failures.zero? && errors.zero?
+ (@keep_repeating || report.empty? && failures.zero? && errors.zero?)
output.sync = old_sync if sync
diff --git a/tool/lib/test/unit/assertions.rb b/tool/lib/test/unit/assertions.rb
index 19581fc3ab..0908666166 100644
--- a/tool/lib/test/unit/assertions.rb
+++ b/tool/lib/test/unit/assertions.rb
@@ -128,8 +128,16 @@ module Test
def assert_in_delta exp, act, delta = 0.001, msg = nil
n = (exp - act).abs
+ loadavg = begin
+ if File.readable?("/proc/loadavg")
+ " (/proc/loadavg=#{File.read("/proc/loadavg").strip})"
+ end
+ rescue StandardError
+ nil
+ end
+ loadavg ||= ""
msg = message(msg) {
- "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}"
+ "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}#{loadavg}"
}
assert delta >= n, msg
end
diff --git a/tool/lib/vcs.rb b/tool/lib/vcs.rb
index 51cdb0fdc3..d6374f9de0 100644
--- a/tool/lib/vcs.rb
+++ b/tool/lib/vcs.rb
@@ -51,23 +51,9 @@ module DebugPOpen
end
using DebugPOpen
module DebugSystem
- def system(*args)
+ def system(*args, exception: true, **opts)
VCS.dump(args, "args: ") if $DEBUG
- exception = false
- opts = Hash.try_convert(args[-1])
- if RUBY_VERSION >= "2.6"
- unless opts
- opts = {}
- args << opts
- end
- exception = opts.fetch(:exception) {opts[:exception] = true}
- elsif opts
- exception = opts.delete(:exception) {true}
- args.pop if opts.empty?
- end
- ret = super(*args)
- raise "Command failed with status (#$?): #{args[0]}" if exception and !ret
- ret
+ super(*args, exception: exception, **opts)
end
end
@@ -183,19 +169,7 @@ class VCS
)
last or raise VCS::NotFoundError, "last revision not found"
changed or raise VCS::NotFoundError, "changed revision not found"
- if modified
- /\A(\d+)-(\d+)-(\d+)\D(\d+):(\d+):(\d+(?:\.\d+)?)\s*(?:Z|([-+]\d\d)(\d\d))\z/ =~ modified or
- raise "unknown time format - #{modified}"
- match = $~[1..6].map { |x| x.to_i }
- off = $7 ? "#{$7}:#{$8}" : "+00:00"
- match << off
- begin
- modified = Time.new(*match)
- rescue ArgumentError
- modified = Time.utc(*$~[1..6]) + $7.to_i * 3600 + $8.to_i * 60
- end
- modified = modified.getlocal(@zone)
- end
+ modified &&= parse_iso_date(modified)
return last, changed, modified, *rest
end
@@ -204,9 +178,9 @@ class VCS
modified
end
- def relative_to(path)
+ def relative_to(path, srcdir = @srcdir)
if path
- srcdir = File.realpath(@srcdir)
+ srcdir = File.realpath(srcdir || @srcdir)
path = File.realdirpath(path)
list1 = srcdir.split(%r{/})
list2 = path.split(%r{/})
@@ -224,6 +198,20 @@ class VCS
end
end
+ def parse_iso_date(date)
+ /\A(\d+)-(\d+)-(\d+)\D(\d+):(\d+):(\d+(?:\.\d+)?)\s*(?:Z|([-+]\d\d)(\d\d))\z/ =~ date or
+ raise "unknown time format - #{date}"
+ match = $~[1..6].map { |x| x.to_i }
+ off = $7 ? "#{$7}:#{$8}" : "+00:00"
+ match << off
+ begin
+ date = Time.new(*match)
+ rescue ArgumentError
+ date = Time.utc(*$~[1..6]) + $7.to_i * 3600 + $8.to_i * 60
+ end
+ date.getlocal(@zone)
+ end
+
def after_export(dir)
FileUtils.rm_rf(Dir.glob("#{dir}/.git*"))
FileUtils.rm_rf(Dir.glob("#{dir}/.mailmap"))
@@ -271,155 +259,6 @@ class VCS
code
end
- class SVN < self
- register(".svn")
- COMMAND = ENV['SVN'] || 'svn'
-
- def self.revision_name(rev)
- "r#{rev}"
- end
-
- def _get_revisions(path, srcdir = nil)
- if srcdir and self.class.local_path?(path)
- path = File.join(srcdir, path)
- end
- if srcdir
- info_xml = IO.pread(%W"#{COMMAND} info --xml #{srcdir}")
- info_xml = nil unless info_xml[/<url>(.*)<\/url>/, 1] == path.to_s
- end
- info_xml ||= IO.pread(%W"#{COMMAND} info --xml #{path}")
- _, last, _, changed, _ = info_xml.split(/revision="(\d+)"/)
- modified = info_xml[/<date>([^<>]*)/, 1]
- branch = info_xml[%r'<relative-url>\^/(?:branches/|tags/)?([^<>]+)', 1]
- [Integer(last), Integer(changed), modified, branch]
- end
-
- def self.search_root(path)
- return unless local_path?(path)
- parent = File.realpath(path)
- begin
- parent = File.dirname(wkdir = parent)
- return wkdir if File.directory?(wkdir + "/.svn")
- end until parent == wkdir
- end
-
- def get_info
- @info ||= IO.pread(%W"#{COMMAND} info --xml #{@srcdir}")
- end
-
- def url
- @url ||= begin
- url = get_info[/<root>(.*)<\/root>/, 1]
- @url = URI.parse(url+"/") if url
- end
- end
-
- def wcroot
- @wcroot ||= begin
- info = get_info
- @wcroot = info[/<wcroot-abspath>(.*)<\/wcroot-abspath>/, 1]
- @wcroot ||= self.class.search_root(@srcdir)
- end
- end
-
- def branch(name)
- return trunk if name == "trunk"
- url + "branches/#{name}"
- end
-
- def tag(name)
- url + "tags/#{name}"
- end
-
- def trunk
- url + "trunk"
- end
- alias master trunk
-
- def branch_list(pat)
- IO.popen(%W"#{COMMAND} ls #{branch('')}") do |f|
- f.each do |line|
- line.chomp!
- line.chomp!('/')
- yield(line) if File.fnmatch?(pat, line)
- end
- end
- end
-
- def grep(pat, tag, *files, &block)
- cmd = %W"#{COMMAND} cat"
- files.map! {|n| File.join(tag, n)} if tag
- set = block.binding.eval("proc {|match| $~ = match}")
- IO.popen([cmd, *files]) do |f|
- f.grep(pat) do |s|
- set[$~]
- yield s
- end
- end
- end
-
- def export(revision, url, dir, keep_temp = false)
- if @srcdir and (rootdir = wcroot)
- srcdir = File.realpath(@srcdir)
- rootdir << "/"
- if srcdir.start_with?(rootdir)
- subdir = srcdir[rootdir.size..-1]
- subdir = nil if subdir.empty?
- FileUtils.mkdir_p(svndir = dir+"/.svn")
- FileUtils.ln_s(Dir.glob(rootdir+"/.svn/*"), svndir)
- system(COMMAND, "-q", "revert", "-R", subdir || ".", :chdir => dir) or return false
- FileUtils.rm_rf(svndir) unless keep_temp
- if subdir
- tmpdir = Dir.mktmpdir("tmp-co.", "#{dir}/#{subdir}")
- File.rename(tmpdir, tmpdir = "#{dir}/#{File.basename(tmpdir)}")
- FileUtils.mv(Dir.glob("#{dir}/#{subdir}/{.[^.]*,..?*,*}"), tmpdir)
- begin
- Dir.rmdir("#{dir}/#{subdir}")
- end until (subdir = File.dirname(subdir)) == '.'
- FileUtils.mv(Dir.glob("#{tmpdir}/#{subdir}/{.[^.]*,..?*,*}"), dir)
- Dir.rmdir(tmpdir)
- end
- return self
- end
- end
- IO.popen(%W"#{COMMAND} export -r #{revision} #{url} #{dir}") do |pipe|
- pipe.each {|line| /^A/ =~ line or yield line}
- end
- self if $?.success?
- end
-
- def after_export(dir)
- super
- FileUtils.rm_rf(dir+"/.svn")
- end
-
- def branch_beginning(url)
- # `--limit` of svn-log is useless in this case, because it is
- # applied before `--search`.
- rev = IO.pread(%W[ #{COMMAND} log --xml
- --search=matz --search-and=has\ started
- -- #{url}/version.h])[/<logentry\s+revision="(\d+)"/m, 1]
- rev.to_i if rev
- end
-
- def export_changelog(url = '.', from = nil, to = nil, _path = nil, path: _path)
- range = [to || 'HEAD', (from ? from+1 : branch_beginning(url))].compact.join(':')
- IO.popen({'TZ' => 'JST-9', 'LANG' => 'C', 'LC_ALL' => 'C'},
- %W"#{COMMAND} log -r#{range} #{url}") do |r|
- IO.copy_stream(r, path)
- end
- end
-
- def commit
- args = %W"#{COMMAND} commit"
- if dryrun?
- VCS.dump(args, "commit: ")
- return true
- end
- system(*args)
- end
- end
-
class GIT < self
register(".git") do |path, dir|
SAFE_DIRECTORIES ||=
@@ -525,6 +364,11 @@ class VCS
[last, changed, modified, branch, title]
end
+ def author_date(path, srcdir = @srcdir)
+ log = cmd_read_at(srcdir, [[COMMAND, 'log', '-n1', '--pretty=%at', path]])
+ Time.at(log.to_i, in: @zone)
+ end
+
def self.revision_name(rev)
short_revision(rev)
end
@@ -533,15 +377,6 @@ class VCS
rev[0, 10]
end
- def revision_handler(rev)
- case rev
- when Integer
- SVN
- else
- super
- end
- end
-
def without_gitconfig
envs = (%w'HOME XDG_CONFIG_HOME' + ENV.keys.grep(/\AGIT_/)).each_with_object({}) do |v, h|
h[v] = ENV.delete(v)
@@ -616,60 +451,50 @@ class VCS
def export(revision, url, dir, keep_temp = false)
system(COMMAND, "clone", "-c", "advice.detachedHead=false", "-s", (@srcdir || '.').to_s, "-b", url, dir) or return
- (Integer === revision ? GITSVN : GIT).new(File.expand_path(dir))
+ GIT.new(File.expand_path(dir))
end
def branch_beginning(url)
- cmd_read(%W[ #{COMMAND} log -n1 --format=format:%H
+ year = cmd_read(%W[ #{COMMAND} log -n1 --format=%cd --date=format:%Y #{url} --]).to_i
+ cmd_read(%W[ #{COMMAND} log --format=format:%H --reverse --since=#{year-1}-12-25
--author=matz --committer=matz --grep=started\\.$
- #{url.to_str} -- version.h include/ruby/version.h])
+ #{url} -- version.h include/ruby/version.h])[/.*/]
end
- def export_changelog(url = '@', from = nil, to = nil, _path = nil, path: _path, base_url: nil)
- svn = nil
+ def export_changelog(url = '@', from = nil, to = nil, _path = nil, path: _path, base_url: true)
from, to = [from, to].map do |rev|
rev or next
- if Integer === rev
- svn = true
- rev = cmd_read({'LANG' => 'C', 'LC_ALL' => 'C'},
- %W"#{COMMAND} log -n1 --format=format:%H" <<
- "--grep=^ *git-svn-id: .*@#{rev} ")
- end
rev unless rev.empty?
end
- unless (from && /./.match(from)) or ((from = branch_beginning(url)) && /./.match(from))
+ to ||= url.to_str
+ unless from&.match?(/./) or (from = branch_beginning(to))&.match?(/./)
warn "no starting commit found", uplevel: 1
from = nil
end
- if svn or system(*%W"#{COMMAND} fetch origin refs/notes/commits:refs/notes/commits",
+ if system(*%W"#{COMMAND} fetch origin refs/notes/commits:refs/notes/commits",
chdir: @srcdir, exception: false)
system(*%W"#{COMMAND} fetch origin refs/notes/log-fix:refs/notes/log-fix",
chdir: @srcdir, exception: false)
else
warn "Could not fetch notes/commits tree", uplevel: 1
end
- to ||= url.to_str
if from
arg = ["#{from}^..#{to}"]
else
arg = ["--since=25 Dec 00:00:00", to]
end
- writer =
- if svn
- format_changelog_as_svn(path, arg)
- else
- if base_url == true
- remote, = upstream
- if remote &&= cmd_read(env, %W[#{COMMAND} remote get-url --no-push #{remote}])
- remote.chomp!
- # hack to redirect git.r-l.o to github
- remote.sub!(/\Agit@git\.ruby-lang\.org:/, 'git@github.com:ruby/')
- remote.sub!(/\Agit@(.*?):(.*?)(?:\.git)?\z/, 'https://\1/\2/commit/')
- end
- base_url = remote
- end
- format_changelog(path, arg, base_url)
+ if base_url == true
+ env = CHANGELOG_ENV
+ remote, = upstream
+ if remote &&= cmd_read(env, %W[#{COMMAND} remote get-url --no-push #{remote}])
+ remote.chomp!
+ # hack to redirect git.r-l.o to github
+ remote.sub!(/\Agit@git\.ruby-lang\.org:/, 'git@github.com:ruby/')
+ remote.sub!(/\Agit@(.*?):(.*?)(?:\.git)?\z/, 'https://\1/\2/commit/')
end
+ base_url = remote
+ end
+ writer = changelog_formatter(path, arg, base_url)
if !path or path == '-'
writer[$stdout]
else
@@ -678,9 +503,10 @@ class VCS
end
LOG_FIX_REGEXP_SEPARATORS = '/!:;|,#%&'
+ CHANGELOG_ENV = {'TZ' => 'JST-9', 'LANG' => 'C', 'LC_ALL' => 'C'}
- def format_changelog(path, arg, base_url = nil)
- env = {'TZ' => 'JST-9', 'LANG' => 'C', 'LC_ALL' => 'C'}
+ def changelog_formatter(path, arg, base_url = nil)
+ env = CHANGELOG_ENV
cmd = %W[#{COMMAND} log
--format=fuller --notes=commits --notes=log-fix --topo-order --no-merges
--fixed-strings --invert-grep --grep=[ci\ skip] --grep=[skip\ ci]
@@ -692,17 +518,32 @@ class VCS
cmd << date
cmd.concat(arg)
proc do |w|
- w.print "-*- coding: utf-8 -*-\n\n"
- w.print "base-url = #{base_url}\n\n" if base_url
+ w.print "-*- coding: utf-8 -*-\n"
+ w.print "\n""base-url = #{base_url}\n" if base_url
+
+ begin
+ ignore_revs = File.readlines(File.join(@srcdir, ".git-blame-ignore-revs"), chomp: true)
+ .grep_v(/^ *(?:#|$)/)
+ .to_h {|v| [v, true]}
+ ignore_revs = nil if ignore_revs.empty?
+ rescue Errno::ENOENT
+ end
+
cmd_pipe(env, cmd, chdir: @srcdir) do |r|
- while s = r.gets("\ncommit ")
+ r.gets(sep = "commit ")
+ sep = "\n" + sep
+ while s = r.gets(sep, chomp: true)
h, s = s.split(/^$/, 2)
+ if ignore_revs&.key?(h[/\A\h{40}/])
+ next
+ end
next if /^Author: *dependabot\[bot\]/ =~ h
h.gsub!(/^(?:(?:Author|Commit)(?:Date)?|Date): /, ' \&')
if s.sub!(/\nNotes \(log-fix\):\n((?: +.*\n)+)/, '')
fix = $1
+ next if /\A *skip\Z/ =~ fix
s = s.lines
fix.each_line do |x|
next unless x.sub!(/^(\s+)(?:(\d+)|\$(?:-\d+)?)/, '')
@@ -739,7 +580,7 @@ class VCS
next
end
end
- message = ["format_changelog failed to replace #{wrong.dump} with #{correct.dump} at #{n}\n"]
+ message = ["changelog_formatter failed to replace #{wrong.dump} with #{correct.dump} at #{n}\n"]
from = [1, n-2].max
to = [s.size-1, n+2].min
s.each_with_index do |e, i|
@@ -761,35 +602,9 @@ class VCS
s = s.join('')
end
- if %r[^ +(https://github\.com/[^/]+/[^/]+/)commit/\h+\n(?=(?: +\n(?i: +Co-authored-by: .*\n)+)?(?:\n|\Z))] =~ s
- issue = "#{$1}pull/"
- s.gsub!(/\b(?:(?i:fix(?:e[sd])?) +|GH-)\K#(?=\d+\b)|\(\K#(?=\d+\))/) {issue}
- end
-
s.gsub!(/ +\n/, "\n")
s.sub!(/^Notes:/, ' \&')
- w.print h, s
- end
- end
- end
- end
-
- def format_changelog_as_svn(path, arg)
- cmd = %W"#{COMMAND} log --topo-order --no-notes -z --format=%an%n%at%n%B"
- cmd.concat(arg)
- proc do |w|
- sep = "-"*72 + "\n"
- w.print sep
- cmd_pipe(cmd) do |r|
- while s = r.gets("\0")
- s.chomp!("\0")
- author, time, s = s.split("\n", 3)
- s.sub!(/\n\ngit-svn-id: .*@(\d+) .*\n\Z/, '')
- rev = $1
- time = Time.at(time.to_i).getlocal("+09:00").strftime("%F %T %z (%a, %d %b %Y)")
- lines = s.count("\n") + 1
- lines = "#{lines} line#{lines == 1 ? '' : 's'}"
- w.print "r#{rev} | #{author} | #{time} | #{lines}\n\n", s, "\n", sep
+ w.print sep, h, s
end
end
end
@@ -826,46 +641,6 @@ class VCS
end
end
- class GITSVN < GIT
- def self.revision_name(rev)
- SVN.revision_name(rev)
- end
-
- def last_changed_revision
- rev = cmd_read(%W"#{COMMAND} svn info"+[STDERR=>[:child, :out]])[/^Last Changed Rev: (\d+)/, 1]
- com = cmd_read(%W"#{COMMAND} svn find-rev r#{rev}").chomp
- return rev, com
- end
-
- def commit(opts = {})
- rev, com = last_changed_revision
- head = cmd_read(%W"#{COMMAND} symbolic-ref --short HEAD").chomp
-
- commits = cmd_read([COMMAND, "log", "--reverse", "--format=%H %ae %ce", "#{com}..@"], "rb").split("\n")
- commits.each_with_index do |l, i|
- r, a, c = l.split(' ')
- dcommit = [COMMAND, "svn", "dcommit"]
- dcommit.insert(-2, "-n") if dryrun?
- dcommit << "--add-author-from" unless a == c
- dcommit << r
- system(*dcommit) or return false
- system(COMMAND, "checkout", head) or return false
- system(COMMAND, "rebase") or return false
- end
-
- if rev
- old = [cmd_read(%W"#{COMMAND} log -1 --format=%H").chomp]
- old << cmd_read(%W"#{COMMAND} svn reset -r#{rev}")[/^r#{rev} = (\h+)/, 1]
- 3.times do
- sleep 2
- system(*%W"#{COMMAND} pull --no-edit --rebase")
- break unless old.include?(cmd_read(%W"#{COMMAND} log -1 --format=%H").chomp)
- end
- end
- true
- end
- end
-
class Null < self
def get_revisions(path, srcdir = nil)
@modified ||= Time.now - 10
diff --git a/tool/lrama/NEWS.md b/tool/lrama/NEWS.md
index a535332ec3..693b46f018 100644
--- a/tool/lrama/NEWS.md
+++ b/tool/lrama/NEWS.md
@@ -1,8 +1,383 @@
# NEWS for Lrama
+## Lrama 0.8.0 (2026-03-01)
+
+### Support parser generation without %union directive (Bison compatibility)
+
+When writing simple parsers or prototypes, defining `%union` can be cumbersome and unnecessary.
+Lrama now supports generating parsers without the `%union` directive, defaulting `YYSTYPE` to `int`, the same behavior as Bison.
+
+When `%union` is not defined:
+
+- `YYSTYPE` defaults to `int`
+- Semantic value references are generated without union member access
+- The generated parser behaves identically to Bison-generated parsers
+
+https://github.com/ruby/lrama/pull/765
+
+### Allow named references on parameterized rule calls inside %rule
+
+Named references (e.g. `[opt]`) can now be used with parameterized rule calls inside a `%rule` body.
+Previously, writing `f_opt_arg(value)[opt]` inside a `%rule` resulted in a parse error.
+
+```yacc
+%rule example(X): f_opt_arg(X)[opt] { $$ = $opt; }
+ ;
+```
+
+https://github.com/ruby/lrama/pull/778
+
+### Fix nested parameterized rule calls in subsequent argument positions
+
+Nested parameterized rule calls (e.g. `f_opt(number)`) can now appear in any argument position, not only the first one.
+Previously, using a nested call as the second or later argument caused a parse error.
+
+```yacc
+%%
+program: args_list(f_opt(number), opt_tail(string), number)
+ ;
+```
+
+https://github.com/ruby/lrama/pull/779
+
+## Lrama 0.7.1 (2025-12-24)
+
+### Optimize IELR
+
+Optimized performance to a level that allows for IELR testing in practical applications.
+
+https://github.com/ruby/lrama/pull/595
+https://github.com/ruby/lrama/pull/605
+https://github.com/ruby/lrama/pull/685
+https://github.com/ruby/lrama/pull/700
+
+### Introduce counterexamples timeout
+
+Counterexample searches can sometimes take a long time, so we've added a timeout to abort the process after a set period. The current limits are:
+
+* 10 seconds per case
+* 120 seconds total (cumulative)
+
+Please note that these are hard-coded and cannot be modified by the user in the current version.
+
+https://github.com/ruby/lrama/pull/623
+
+### Optimize Counterexamples
+
+Optimized counterexample search performance.
+
+https://github.com/ruby/lrama/pull/607
+https://github.com/ruby/lrama/pull/610
+https://github.com/ruby/lrama/pull/614
+https://github.com/ruby/lrama/pull/622
+https://github.com/ruby/lrama/pull/627
+https://github.com/ruby/lrama/pull/629
+https://github.com/ruby/lrama/pull/659
+
+### Support parameterized rule's arguments include inline
+
+Allow to use %inline directive with Parameterized rules arguments. When an inline rule is used as an argument to a Parameterized rule, it expands inline at the point of use.
+
+```yacc
+%rule %inline op : '+'
+ | '-'
+ ;
+%%
+operation : op?
+ ;
+```
+
+This expands to:
+
+```yacc
+operation : /* empty */
+ | '+'
+ | '-'
+ ;
+```
+
+https://github.com/ruby/lrama/pull/637
+
+### Render conflicts of each state on output file
+
+Added token information for conflicts in the output file.
+These information are useful when a state has many actions.
+
+```
+State 1
+
+ 4 class: keyword_class • tSTRING "end"
+ 5 $@1: ε • [tSTRING]
+ 7 class: keyword_class • $@1 tSTRING '!' "end" $@2
+ 8 $@3: ε • [tSTRING]
+ 10 class: keyword_class • $@3 tSTRING '?' "end" $@4
+
+ Conflict on tSTRING. shift/reduce($@1)
+ Conflict on tSTRING. shift/reduce($@3)
+ Conflict on tSTRING. reduce($@1)/reduce($@3)
+
+ tSTRING shift, and go to state 6
+
+ tSTRING reduce using rule 5 ($@1)
+ tSTRING reduce using rule 8 ($@3)
+
+ $@1 go to state 7
+ $@3 go to state 8
+```
+
+https://github.com/ruby/lrama/pull/541
+
+### Render the origin of conflicted tokens on output file
+
+For example, for the grammar file like below:
+
+```
+%%
+
+program: expr
+ ;
+
+expr: expr '+' expr
+ | tNUMBER
+ ;
+
+%%
+```
+
+Lrama generates output file which describes where `"plus"` (`'+'`) look ahead tokens come from:
+
+```
+State 6
+
+ 2 expr: expr • "plus" expr
+ 2 | expr "plus" expr • ["end of file", "plus"]
+
+ Conflict on "plus". shift/reduce(expr)
+ "plus" comes from state 0 goto by expr
+ "plus" comes from state 5 goto by expr
+```
+
+state 0 and state 5 look like below:
+
+```
+State 0
+
+ 0 $accept: • program "end of file"
+ 1 program: • expr
+ 2 expr: • expr "plus" expr
+ 3 | • tNUMBER
+
+ tNUMBER shift, and go to state 1
+
+ program go to state 2
+ expr go to state 3
+
+State 5
+
+ 2 expr: • expr "plus" expr
+ 2 | expr "plus" • expr
+ 3 | • tNUMBER
+
+ tNUMBER shift, and go to state 1
+
+ expr go to state 6
+```
+
+https://github.com/ruby/lrama/pull/726
+
+### Render precedences usage information on output file
+
+For example, for the grammar file like below:
+
+```
+%left tPLUS
+%right tUPLUS
+
+%%
+
+program: expr ;
+
+expr: tUPLUS expr
+ | expr tPLUS expr
+ | tNUMBER
+ ;
+
+%%
+```
+
+Lrama generates output file which describes where these precedences are used to resolve conflicts:
+
+```
+Precedences
+ precedence on "unary+" is used to resolve conflict on
+ LALR
+ state 5. Conflict between reduce by "expr -> tUPLUS expr" and shift "+" resolved as reduce ("+" < "unary+").
+ precedence on "+" is used to resolve conflict on
+ LALR
+ state 5. Conflict between reduce by "expr -> tUPLUS expr" and shift "+" resolved as reduce ("+" < "unary+").
+ state 8. Conflict between reduce by "expr -> expr tPLUS expr" and shift "+" resolved as reduce (%left "+").
+```
+
+https://github.com/ruby/lrama/pull/741
+
+### Add support for reporting Rule Usage Frequency
+
+Support to report rule usage frequency statistics for analyzing grammar characteristics.
+Run `exe/lrama --report=rules` to show how frequently each terminal and non-terminal symbol is used in the grammar rules.
+
+```console
+$ exe/lrama --report=rules sample/calc.y
+Rule Usage Frequency
+ 0 tSTRING (4 times)
+ 1 keyword_class (3 times)
+ 2 keyword_end (3 times)
+ 3 '+' (2 times)
+ 4 string (2 times)
+ 5 string_1 (2 times)
+ 6 '!' (1 times)
+ 7 '-' (1 times)
+ 8 '?' (1 times)
+ 9 EOI (1 times)
+ 10 class (1 times)
+ 11 program (1 times)
+ 12 string_2 (1 times)
+ 13 strings_1 (1 times)
+ 14 strings_2 (1 times)
+ 15 tNUMBER (1 times)
+```
+
+This feature provides insights into the language characteristics by showing:
+- Which symbols are most frequently used in the grammar
+- The distribution of terminal and non-terminal usage
+- Potential areas for grammar optimization or refactoring
+
+The frequency statistics help developers understand the grammar structure and can be useful for:
+- Grammar complexity analysis
+- Performance optimization hints
+- Language design decisions
+- Documentation and educational purposes
+
+https://github.com/ruby/lrama/pull/677
+
+### Render Split States information on output file
+
+For example, for the grammar file like below:
+
+```
+%token a
+%token b
+%token c
+%define lr.type ielr
+
+%precedence tLOWEST
+%precedence a
+%precedence tHIGHEST
+
+%%
+
+S: a A B a
+ | b A B b
+ ;
+
+A: a C D E
+ ;
+
+B: c
+ | // empty
+ ;
+
+C: D
+ ;
+
+D: a
+ ;
+
+E: a
+ | %prec tHIGHEST // empty
+ ;
+
+%%
+```
+
+Lrama generates output file which describes where which new states are created when IELR is enabled:
+
+```
+Split States
+
+ State 19 is split from state 4
+ State 20 is split from state 9
+ State 21 is split from state 14
+```
+
+https://github.com/ruby/lrama/pull/624
+
+### Add ioption support to the Standard library
+
+Support `ioption` (inline option) rule, which is expanded inline without creating intermediate rules.
+
+Unlike the regular `option` rule that generates a separate rule, `ioption` directly expands at the point of use:
+
+```yacc
+program: ioption(number) expr
+
+// Expanded inline to:
+
+program: expr
+ | number expr
+```
+
+This differs from the regular `option` which would generate:
+
+```yacc
+program: option(number) expr
+
+// Expanded to:
+
+program: option_number expr
+option_number: %empty
+ | number
+```
+
+The `ioption` rule provides more compact grammar generation by avoiding intermediate rule creation, which can be beneficial for reducing the parser's rule count and potentially improving performance.
+
+This feature is inspired by Menhir's standard library and maintains compatibility with [Menhir's `ioption` behavior](https://github.com/let-def/menhir/blob/e8ba7bef219acd355798072c42abbd11335ecf09/src/standard.mly#L33-L41).
+
+https://github.com/ruby/lrama/pull/666
+
+### Syntax Diagrams
+
+Lrama provides an API for generating HTML syntax diagrams. These visual diagrams are highly useful as grammar development tools and can also serve as a form of automatic self-documentation.
+
+![Syntax Diagrams](https://github.com/user-attachments/assets/5d9bca77-93fd-4416-bc24-9a0f70693a22)
+
+If you use syntax diagrams, you add `--diagram` option.
+
+```console
+$ exe/lrama --diagram sample.y
+```
+
+https://github.com/ruby/lrama/pull/523
+
+### Support `--profile` option
+
+You can profile parser generation process without modification for Lrama source code.
+Currently `--profile=call-stack` and `--profile=memory` are supported.
+
+```console
+$ exe/lrama --profile=call-stack sample/calc.y
+```
+
+Then "tmp/stackprof-cpu-myapp.dump" is generated.
+
+https://github.com/ruby/lrama/pull/525
+
+### Add support Start-Symbol: `%start`
+
+https://github.com/ruby/lrama/pull/576
+
## Lrama 0.7.0 (2025-01-21)
-## [EXPERIMENTAL] Support the generation of the IELR(1) parser described in this paper
+### [EXPERIMENTAL] Support the generation of the IELR(1) parser described in this paper
Support the generation of the IELR(1) parser described in this paper.
https://www.sciencedirect.com/science/article/pii/S0167642309001191
@@ -15,12 +390,12 @@ If you use IELR(1) parser, you can write the following directive in your grammar
But, currently IELR(1) parser is experimental feature. If you find any bugs, please report it to us. Thank you.
-## Support `-t` option as same as `--debug` option
+### Support `-t` option as same as `--debug` option
Support to `-t` option as same as `--debug` option.
These options align with Bison behavior. So same as `--debug` option.
-## Trace only explicit rules
+### Trace only explicit rules
Support to trace only explicit rules.
If you use `--trace=rules` option, it shows include mid-rule actions. If you want to show only explicit rules, you can use `--trace=only-explicit-rules` option.
@@ -97,9 +472,9 @@ nterm.y:6:7: symbol EOI redeclared as a nonterminal
## Lrama 0.6.10 (2024-09-11)
-### Aliased Named References for actions of RHS in parameterizing rules
+### Aliased Named References for actions of RHS in Parameterizing rules
-Allow to use aliased named references for actions of RHS in parameterizing rules.
+Allow to use aliased named references for actions of RHS in Parameterizing rules.
```yacc
%rule sum(X, Y): X[summand] '+' Y[addend] { $$ = $summand + $addend }
@@ -109,9 +484,9 @@ Allow to use aliased named references for actions of RHS in parameterizing rules
https://github.com/ruby/lrama/pull/410
-### Named References for actions of RHS in parameterizing rules caller side
+### Named References for actions of RHS in Parameterizing rules caller side
-Allow to use named references for actions of RHS in parameterizing rules caller side.
+Allow to use named references for actions of RHS in Parameterizing rules caller side.
```yacc
opt_nl: '\n'?[nl] <str> { $$ = $nl; }
@@ -120,9 +495,9 @@ opt_nl: '\n'?[nl] <str> { $$ = $nl; }
https://github.com/ruby/lrama/pull/414
-### Widen the definable position of parameterizing rules
+### Widen the definable position of Parameterizing rules
-Allow to define parameterizing rules in the middle of the grammar.
+Allow to define Parameterizing rules in the middle of the grammar.
```yacc
%rule defined_option(X): /* empty */
@@ -186,15 +561,15 @@ Change to `%locations` directive not set by default.
https://github.com/ruby/lrama/pull/446
-### Diagnostics report for parameterizing rules redefine
+### Diagnostics report for parameterized rules redefine
-Support to warning redefined parameterizing rules.
-Run `exe/lrama -W` or `exe/lrama --warnings` to show redefined parameterizing rules.
+Support to warning redefined parameterized rules.
+Run `exe/lrama -W` or `exe/lrama --warnings` to show redefined parameterized rules.
```console
$ exe/lrama -W sample/calc.y
-parameterizing rule redefined: redefined_method(X)
-parameterizing rule redefined: redefined_method(X)
+parameterized rule redefined: redefined_method(X)
+parameterized rule redefined: redefined_method(X)
```
https://github.com/ruby/lrama/pull/448
@@ -208,9 +583,9 @@ https://github.com/ruby/lrama/pull/457
## Lrama 0.6.9 (2024-05-02)
-### Callee side tag specification of parameterizing rules
+### Callee side tag specification of Parameterizing rules
-Allow to specify tag on callee side of parameterizing rules.
+Allow to specify tag on callee side of Parameterizing rules.
```yacc
%union {
@@ -221,9 +596,9 @@ Allow to specify tag on callee side of parameterizing rules.
;
```
-### Named References for actions of RHS in parameterizing rules
+### Named References for actions of RHS in Parameterizing rules
-Allow to use named references for actions of RHS in parameterizing rules.
+Allow to use named references for actions of RHS in Parameterizing rules.
```yacc
%rule option(number): /* empty */
@@ -233,9 +608,9 @@ Allow to use named references for actions of RHS in parameterizing rules.
## Lrama 0.6.8 (2024-04-29)
-### Nested parameterizing rules with tag
+### Nested Parameterizing rules with tag
-Allow to nested parameterizing rules with tag.
+Allow to nested Parameterizing rules with tag.
```yacc
%union {
@@ -257,9 +632,9 @@ Allow to nested parameterizing rules with tag.
## Lrama 0.6.7 (2024-04-28)
-### RHS of user defined parameterizing rules contains `'symbol'?`, `'symbol'+` and `'symbol'*`.
+### RHS of user defined Parameterizing rules contains `'symbol'?`, `'symbol'+` and `'symbol'*`.
-User can use `'symbol'?`, `'symbol'+` and `'symbol'*` in RHS of user defined parameterizing rules.
+User can use `'symbol'?`, `'symbol'+` and `'symbol'*` in RHS of user defined Parameterizing rules.
```
%rule with_word_seps(X): /* empty */
@@ -319,7 +694,7 @@ expr : number { $$ = $1; }
### Typed Midrule Actions
-User can specify the type of mid rule action by tag (`<bar>`) instead of specifying it with in an action.
+User can specify the type of mid-rule action by tag (`<bar>`) instead of specifying it with in an action.
```yacc
primary: k_case expr_value terms?
@@ -394,7 +769,7 @@ https://github.com/ruby/lrama/pull/382
User can set codes for freeing semantic value resources by using `%destructor`.
In general, these resources are freed by actions or after parsing.
-However if syntax error happens in parsing, these codes may not be executed.
+However, if syntax error happens in parsing, these codes may not be executed.
Codes associated to `%destructor` are executed when semantic value is popped from the stack by an error.
```yacc
@@ -432,7 +807,7 @@ Lrama introduces two features to support another semantic value stack by parser
1. Callback entry points
User can emulate semantic value stack by these callbacks.
-Lrama provides these five callbacks. Registered functions are called when each event happen. For example %after-shift function is called when shift happens on original semantic value stack.
+Lrama provides these five callbacks. Registered functions are called when each event happens. For example %after-shift function is called when shift happens on original semantic value stack.
* `%after-shift` function_name
* `%before-reduce` function_name
@@ -460,15 +835,15 @@ https://github.com/ruby/lrama/pull/367
### %no-stdlib directive
If `%no-stdlib` directive is set, Lrama doesn't load Lrama standard library for
-parameterizing rules, stdlib.y.
+parameterized rules, stdlib.y.
https://github.com/ruby/lrama/pull/344
## Lrama 0.6.1 (2024-01-13)
-### Nested parameterizing rules
+### Nested Parameterizing rules
-Allow to pass an instantiated rule to other parameterizing rules.
+Allow to pass an instantiated rule to other Parameterizing rules.
```yacc
%rule constant(X) : X
@@ -485,7 +860,7 @@ program : option(constant(number)) // Nested rule
%%
```
-Allow to use nested parameterizing rules when define parameterizing rules.
+Allow to use nested Parameterizing rules when define Parameterizing rules.
```yacc
%rule option(x) : /* empty */
@@ -510,9 +885,9 @@ https://github.com/ruby/lrama/pull/337
## Lrama 0.6.0 (2023-12-25)
-### User defined parameterizing rules
+### User defined Parameterizing rules
-Allow to define parameterizing rule by `%rule` directive.
+Allow to define Parameterizing rule by `%rule` directive.
```yacc
%rule pair(X, Y): X Y { $$ = $1 + $2; }
@@ -532,7 +907,7 @@ https://github.com/ruby/lrama/pull/285
## Lrama 0.5.11 (2023-12-02)
-### Type specification of parameterizing rules
+### Type specification of Parameterizing rules
Allow to specify type of rules by specifying tag, `<i>` in below example.
Tag is post-modification style.
@@ -556,13 +931,13 @@ https://github.com/ruby/lrama/pull/272
### Parameterizing rules (option, nonempty_list, list)
-Support function call style parameterizing rules for `option`, `nonempty_list` and `list`.
+Support function call style Parameterizing rules for `option`, `nonempty_list` and `list`.
https://github.com/ruby/lrama/pull/197
### Parameterizing rules (separated_list)
-Support `separated_list` and `separated_nonempty_list` parameterizing rules.
+Support `separated_list` and `separated_nonempty_list` Parameterizing rules.
```text
program: separated_list(',', number)
@@ -618,7 +993,7 @@ https://github.com/ruby/lrama/pull/181
### Racc parser
-Replace Lrama's parser from hand written parser to LR parser generated by Racc.
+Replace Lrama's parser from handwritten parser to LR parser generated by Racc.
Lrama uses `--embedded` option to generate LR parser because Racc is changed from default gem to bundled gem by Ruby 3.3 (https://github.com/ruby/lrama/pull/132).
https://github.com/ruby/lrama/pull/62
diff --git a/tool/lrama/exe/lrama b/tool/lrama/exe/lrama
index 1aece5d141..710ac0cb96 100755
--- a/tool/lrama/exe/lrama
+++ b/tool/lrama/exe/lrama
@@ -4,4 +4,4 @@
$LOAD_PATH << File.join(__dir__, "../lib")
require "lrama"
-Lrama::Command.new.run(ARGV.dup)
+Lrama::Command.new(ARGV.dup).run
diff --git a/tool/lrama/lib/lrama.rb b/tool/lrama/lib/lrama.rb
index fe2e05807c..56ba0044d4 100644
--- a/tool/lrama/lib/lrama.rb
+++ b/tool/lrama/lib/lrama.rb
@@ -4,19 +4,19 @@ require_relative "lrama/bitmap"
require_relative "lrama/command"
require_relative "lrama/context"
require_relative "lrama/counterexamples"
-require_relative "lrama/diagnostics"
+require_relative "lrama/diagram"
require_relative "lrama/digraph"
+require_relative "lrama/erb"
require_relative "lrama/grammar"
-require_relative "lrama/grammar_validator"
require_relative "lrama/lexer"
require_relative "lrama/logger"
require_relative "lrama/option_parser"
require_relative "lrama/options"
require_relative "lrama/output"
require_relative "lrama/parser"
-require_relative "lrama/report"
+require_relative "lrama/reporter"
require_relative "lrama/state"
require_relative "lrama/states"
-require_relative "lrama/states_reporter"
-require_relative "lrama/trace_reporter"
+require_relative "lrama/tracer"
require_relative "lrama/version"
+require_relative "lrama/warnings"
diff --git a/tool/lrama/lib/lrama/bitmap.rb b/tool/lrama/lib/lrama/bitmap.rb
index 098c6e0b77..88b255b012 100644
--- a/tool/lrama/lib/lrama/bitmap.rb
+++ b/tool/lrama/lib/lrama/bitmap.rb
@@ -3,7 +3,10 @@
module Lrama
module Bitmap
- # @rbs (Array[Integer] ary) -> Integer
+ # @rbs!
+ # type bitmap = Integer
+
+ # @rbs (Array[Integer] ary) -> bitmap
def self.from_array(ary)
bit = 0
@@ -14,21 +17,31 @@ module Lrama
bit
end
- # @rbs (Integer int) -> Array[Integer]
+ # @rbs (Integer int) -> bitmap
+ def self.from_integer(int)
+ 1 << int
+ end
+
+ # @rbs (bitmap int) -> Array[Integer]
def self.to_array(int)
a = [] #: Array[Integer]
i = 0
- while int > 0 do
- if int & 1 == 1
+ len = int.bit_length
+ while i < len do
+ if int[i] == 1
a << i
end
i += 1
- int >>= 1
end
a
end
+
+ # @rbs (bitmap int, Integer size) -> Array[bool]
+ def self.to_bool_array(int, size)
+ Array.new(size) { |i| int[i] == 1 }
+ end
end
end
diff --git a/tool/lrama/lib/lrama/command.rb b/tool/lrama/lib/lrama/command.rb
index 3ff39d578d..17aad1a1c1 100644
--- a/tool/lrama/lib/lrama/command.rb
+++ b/tool/lrama/lib/lrama/command.rb
@@ -5,64 +5,116 @@ module Lrama
LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__)))
STDLIB_FILE_PATH = File.join(LRAMA_LIB, 'grammar', 'stdlib.y')
- def run(argv)
- begin
- options = OptionParser.new.parse(argv)
- rescue => e
- message = e.message
- message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
- abort message
- end
-
- Report::Duration.enable if options.trace_opts[:time]
+ def initialize(argv)
+ @logger = Lrama::Logger.new
+ @options = OptionParser.parse(argv)
+ @tracer = Tracer.new(STDERR, **@options.trace_opts)
+ @reporter = Reporter.new(**@options.report_opts)
+ @warnings = Warnings.new(@logger, @options.warnings)
+ rescue => e
+ abort format_error_message(e.message)
+ end
- text = options.y.read
- options.y.close if options.y != STDIN
- begin
- grammar = Lrama::Parser.new(text, options.grammar_file, options.debug, options.define).parse
- unless grammar.no_stdlib
- stdlib_grammar = Lrama::Parser.new(File.read(STDLIB_FILE_PATH), STDLIB_FILE_PATH, options.debug).parse
- grammar.insert_before_parameterizing_rules(stdlib_grammar.parameterizing_rules)
+ def run
+ Lrama::Reporter::Profile::CallStack.report(@options.profile_opts[:call_stack]) do
+ Lrama::Reporter::Profile::Memory.report(@options.profile_opts[:memory]) do
+ execute_command_workflow
end
- grammar.prepare
- grammar.validate!
- rescue => e
- raise e if options.debug
- message = e.message
- message = message.gsub(/.+/, "\e[1m\\&\e[m") if Exception.to_tty?
- abort message
end
- states = Lrama::States.new(grammar, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
+ end
+
+ private
+
+ def execute_command_workflow
+ @tracer.enable_duration
+ text = read_input
+ grammar = build_grammar(text)
+ states, context = compute_status(grammar)
+ render_reports(states) if @options.report_file
+ @tracer.trace(grammar)
+ render_diagram(grammar)
+ render_output(context, grammar)
+ states.validate!(@logger)
+ @warnings.warn(grammar, states)
+ end
+
+ def read_input
+ text = @options.y.read
+ @options.y.close unless @options.y == STDIN
+ text
+ end
+
+ def build_grammar(text)
+ grammar =
+ Lrama::Parser.new(text, @options.grammar_file, @options.debug, @options.locations, @options.define).parse
+ merge_stdlib(grammar)
+ prepare_grammar(grammar)
+ grammar
+ rescue => e
+ raise e if @options.debug
+ abort format_error_message(e.message)
+ end
+
+ def format_error_message(message)
+ return message unless Exception.to_tty?
+
+ message.gsub(/.+/, "\e[1m\\&\e[m")
+ end
+
+ def merge_stdlib(grammar)
+ return if grammar.no_stdlib
+
+ stdlib_text = File.read(STDLIB_FILE_PATH)
+ stdlib_grammar = Lrama::Parser.new(
+ stdlib_text,
+ STDLIB_FILE_PATH,
+ @options.debug,
+ @options.locations,
+ @options.define,
+ ).parse
+
+ grammar.prepend_parameterized_rules(stdlib_grammar.parameterized_rules)
+ end
+
+ def prepare_grammar(grammar)
+ grammar.prepare
+ grammar.validate!
+ end
+
+ def compute_status(grammar)
+ states = Lrama::States.new(grammar, @tracer)
states.compute
states.compute_ielr if grammar.ielr_defined?
- context = Lrama::Context.new(states)
+ [states, Lrama::Context.new(states)]
+ end
- if options.report_file
- reporter = Lrama::StatesReporter.new(states)
- File.open(options.report_file, "w+") do |f|
- reporter.report(f, **options.report_opts)
- end
+ def render_reports(states)
+ File.open(@options.report_file, "w+") do |f|
+ @reporter.report(f, states)
end
+ end
- reporter = Lrama::TraceReporter.new(grammar)
- reporter.report(**options.trace_opts)
+ def render_diagram(grammar)
+ return unless @options.diagram
- File.open(options.outfile, "w+") do |f|
+ File.open(@options.diagram_file, "w+") do |f|
+ Lrama::Diagram.render(out: f, grammar: grammar)
+ end
+ end
+
+ def render_output(context, grammar)
+ File.open(@options.outfile, "w+") do |f|
Lrama::Output.new(
out: f,
- output_file_path: options.outfile,
- template_name: options.skeleton,
- grammar_file_path: options.grammar_file,
- header_file_path: options.header_file,
+ output_file_path: @options.outfile,
+ template_name: @options.skeleton,
+ grammar_file_path: @options.grammar_file,
+ header_file_path: @options.header_file,
context: context,
grammar: grammar,
- error_recovery: options.error_recovery,
+ error_recovery: @options.error_recovery,
).render
end
-
- logger = Lrama::Logger.new
- exit false unless Lrama::GrammarValidator.new(grammar, states, logger).valid?
- Lrama::Diagnostics.new(grammar, states, logger).run(options.diagnostic)
end
end
end
diff --git a/tool/lrama/lib/lrama/context.rb b/tool/lrama/lib/lrama/context.rb
index 9f406f8de0..eb068c1b9e 100644
--- a/tool/lrama/lib/lrama/context.rb
+++ b/tool/lrama/lib/lrama/context.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require_relative "report/duration"
+require_relative "tracer/duration"
module Lrama
# This is passed to a template
class Context
- include Report::Duration
+ include Tracer::Duration
ErrorActionNumber = -Float::INFINITY
BaseMin = -Float::INFINITY
@@ -231,8 +231,8 @@ module Lrama
end
# Shift is selected when S/R conflict exists.
- state.selected_term_transitions.each do |shift, next_state|
- actions[shift.next_sym.number] = next_state.id
+ state.selected_term_transitions.each do |shift|
+ actions[shift.next_sym.number] = shift.to_state.id
end
state.resolved_conflicts.select do |conflict|
@@ -292,18 +292,18 @@ module Lrama
# of a default nterm transition destination.
@yydefgoto = Array.new(@states.nterms.count, 0)
# Mapping from nterm to next_states
- nterm_to_next_states = {}
+ nterm_to_to_states = {}
@states.states.each do |state|
- state.nterm_transitions.each do |shift, next_state|
- key = shift.next_sym
- nterm_to_next_states[key] ||= []
- nterm_to_next_states[key] << [state, next_state] # [from_state, to_state]
+ state.nterm_transitions.each do |goto|
+ key = goto.next_sym
+ nterm_to_to_states[key] ||= []
+ nterm_to_to_states[key] << [state, goto.to_state] # [from_state, to_state]
end
end
@states.nterms.each do |nterm|
- if (states = nterm_to_next_states[nterm])
+ if (states = nterm_to_to_states[nterm])
default_state = states.map(&:last).group_by {|s| s }.max_by {|_, v| v.count }.first
default_goto = default_state.id
not_default_gotos = []
@@ -417,27 +417,25 @@ module Lrama
res = lowzero - froms_and_tos.first[0]
+ # Find the smallest `res` such that `@table[res + from]` is empty for all `from` in `froms_and_tos`
while true do
- ok = true
+ advanced = false
- froms_and_tos.each do |from, to|
- loc = res + from
-
- if @table[loc]
- # If the cell of table is set, can not use the cell.
- ok = false
- break
- end
+ while used_res[res]
+ res += 1
+ advanced = true
end
- if ok && used_res[res]
- ok = false
+ froms_and_tos.each do |from, to|
+ while @table[res + from]
+ res += 1
+ advanced = true
+ end
end
- if ok
+ unless advanced
+ # no advance means that the current `res` satisfies the condition
break
- else
- res += 1
end
end
diff --git a/tool/lrama/lib/lrama/counterexamples.rb b/tool/lrama/lib/lrama/counterexamples.rb
index ee2b5d5959..60d830d048 100644
--- a/tool/lrama/lib/lrama/counterexamples.rb
+++ b/tool/lrama/lib/lrama/counterexamples.rb
@@ -1,35 +1,64 @@
+# rbs_inline: enabled
# frozen_string_literal: true
require "set"
+require "timeout"
require_relative "counterexamples/derivation"
require_relative "counterexamples/example"
+require_relative "counterexamples/node"
require_relative "counterexamples/path"
-require_relative "counterexamples/production_path"
-require_relative "counterexamples/start_path"
require_relative "counterexamples/state_item"
-require_relative "counterexamples/transition_path"
require_relative "counterexamples/triple"
module Lrama
# See: https://www.cs.cornell.edu/andru/papers/cupex/cupex.pdf
# 4. Constructing Nonunifying Counterexamples
class Counterexamples
- attr_reader :transitions, :productions
-
+ PathSearchTimeLimit = 10 # 10 sec
+ CumulativeTimeLimit = 120 # 120 sec
+
+ # @rbs!
+ # @states: States
+ # @iterate_count: Integer
+ # @total_duration: Float
+ # @exceed_cumulative_time_limit: bool
+ # @state_items: Hash[[State, State::Item], StateItem]
+ # @triples: Hash[Integer, Triple]
+ # @transitions: Hash[[StateItem, Grammar::Symbol], StateItem]
+ # @reverse_transitions: Hash[[StateItem, Grammar::Symbol], Set[StateItem]]
+ # @productions: Hash[StateItem, Set[StateItem]]
+ # @reverse_productions: Hash[[State, Grammar::Symbol], Set[StateItem]] # Grammar::Symbol is nterm
+ # @state_item_shift: Integer
+
+ attr_reader :transitions #: Hash[[StateItem, Grammar::Symbol], StateItem]
+ attr_reader :productions #: Hash[StateItem, Set[StateItem]]
+
+ # @rbs (States states) -> void
def initialize(states)
@states = states
+ @iterate_count = 0
+ @total_duration = 0
+ @exceed_cumulative_time_limit = false
+ @triples = {}
+ setup_state_items
setup_transitions
setup_productions
end
+ # @rbs () -> "#<Counterexamples>"
def to_s
"#<Counterexamples>"
end
alias :inspect :to_s
+ # @rbs (State conflict_state) -> Array[Example]
def compute(conflict_state)
conflict_state.conflicts.flat_map do |conflict|
+ # Check cumulative time limit for not each path search method call but each conflict
+ # to avoid one of example's path to be nil.
+ next if @exceed_cumulative_time_limit
+
case conflict.type
when :shift_reduce
# @type var conflict: State::ShiftReduceConflict
@@ -38,22 +67,50 @@ module Lrama
# @type var conflict: State::ReduceReduceConflict
reduce_reduce_examples(conflict_state, conflict)
end
+ rescue Timeout::Error => e
+ STDERR.puts "Counterexamples calculation for state #{conflict_state.id} #{e.message} with #{@iterate_count} iteration"
+ increment_total_duration(PathSearchTimeLimit)
+ nil
end.compact
end
private
+ # @rbs (State state, State::Item item) -> StateItem
+ def get_state_item(state, item)
+ @state_items[[state, item]]
+ end
+
+ # For optimization, create all StateItem in advance
+ # and use them by fetching an instance from `@state_items`.
+ # Do not create new StateItem instance in the shortest path search process
+ # to avoid miss hash lookup.
+ #
+ # @rbs () -> void
+ def setup_state_items
+ @state_items = {}
+ count = 0
+
+ @states.states.each do |state|
+ state.items.each do |item|
+ @state_items[[state, item]] = StateItem.new(count, state, item)
+ count += 1
+ end
+ end
+
+ @state_item_shift = Math.log(count, 2).ceil
+ end
+
+ # @rbs () -> void
def setup_transitions
- # Hash [StateItem, Symbol] => StateItem
@transitions = {}
- # Hash [StateItem, Symbol] => Set(StateItem)
@reverse_transitions = {}
@states.states.each do |src_state|
trans = {} #: Hash[Grammar::Symbol, State]
- src_state.transitions.each do |shift, next_state|
- trans[shift.next_sym] = next_state
+ src_state.transitions.each do |transition|
+ trans[transition.next_sym] = transition.to_state
end
src_state.items.each do |src_item|
@@ -63,8 +120,8 @@ module Lrama
dest_state.kernels.each do |dest_item|
next unless (src_item.rule == dest_item.rule) && (src_item.position + 1 == dest_item.position)
- src_state_item = StateItem.new(src_state, src_item)
- dest_state_item = StateItem.new(dest_state, dest_item)
+ src_state_item = get_state_item(src_state, src_item)
+ dest_state_item = get_state_item(dest_state, dest_item)
@transitions[[src_state_item, sym]] = dest_state_item
@@ -77,21 +134,20 @@ module Lrama
end
end
+ # @rbs () -> void
def setup_productions
- # Hash [StateItem] => Set(Item)
@productions = {}
- # Hash [State, Symbol] => Set(Item). Symbol is nterm
@reverse_productions = {}
@states.states.each do |state|
- # LHS => Set(Item)
- h = {} #: Hash[Grammar::Symbol, Set[States::Item]]
+ # Grammar::Symbol is LHS
+ h = {} #: Hash[Grammar::Symbol, Set[StateItem]]
state.closure.each do |item|
sym = item.lhs
h[sym] ||= Set.new
- h[sym] << item
+ h[sym] << get_state_item(state, item)
end
state.items.each do |item|
@@ -99,101 +155,118 @@ module Lrama
next if item.next_sym.term?
sym = item.next_sym
- state_item = StateItem.new(state, item)
- # @type var key: [State, Grammar::Symbol]
- key = [state, sym]
-
+ state_item = get_state_item(state, item)
@productions[state_item] = h[sym]
+ # @type var key: [State, Grammar::Symbol]
+ key = [state, sym]
@reverse_productions[key] ||= Set.new
- @reverse_productions[key] << item
+ @reverse_productions[key] << state_item
end
end
end
+ # For optimization, use same Triple if it's already created.
+ # Do not create new Triple instance anywhere else
+ # to avoid miss hash lookup.
+ #
+ # @rbs (StateItem state_item, Bitmap::bitmap precise_lookahead_set) -> Triple
+ def get_triple(state_item, precise_lookahead_set)
+ key = (precise_lookahead_set << @state_item_shift) | state_item.id
+ @triples[key] ||= Triple.new(state_item, precise_lookahead_set)
+ end
+
+ # @rbs (State conflict_state, State::ShiftReduceConflict conflict) -> Example
def shift_reduce_example(conflict_state, conflict)
conflict_symbol = conflict.symbols.first
- # @type var shift_conflict_item: ::Lrama::States::Item
+ # @type var shift_conflict_item: ::Lrama::State::Item
shift_conflict_item = conflict_state.items.find { |item| item.next_sym == conflict_symbol }
- path2 = shortest_path(conflict_state, conflict.reduce.item, conflict_symbol)
- path1 = find_shift_conflict_shortest_path(path2, conflict_state, shift_conflict_item)
+ path2 = with_timeout("#shortest_path:") do
+ shortest_path(conflict_state, conflict.reduce.item, conflict_symbol)
+ end
+ path1 = with_timeout("#find_shift_conflict_shortest_path:") do
+ find_shift_conflict_shortest_path(path2, conflict_state, shift_conflict_item)
+ end
Example.new(path1, path2, conflict, conflict_symbol, self)
end
+ # @rbs (State conflict_state, State::ReduceReduceConflict conflict) -> Example
def reduce_reduce_examples(conflict_state, conflict)
conflict_symbol = conflict.symbols.first
- path1 = shortest_path(conflict_state, conflict.reduce1.item, conflict_symbol)
- path2 = shortest_path(conflict_state, conflict.reduce2.item, conflict_symbol)
+ path1 = with_timeout("#shortest_path:") do
+ shortest_path(conflict_state, conflict.reduce1.item, conflict_symbol)
+ end
+ path2 = with_timeout("#shortest_path:") do
+ shortest_path(conflict_state, conflict.reduce2.item, conflict_symbol)
+ end
Example.new(path1, path2, conflict, conflict_symbol, self)
end
- def find_shift_conflict_shortest_path(reduce_path, conflict_state, conflict_item)
- state_items = find_shift_conflict_shortest_state_items(reduce_path, conflict_state, conflict_item)
- build_paths_from_state_items(state_items)
- end
+ # @rbs (Array[StateItem]? reduce_state_items, State conflict_state, State::Item conflict_item) -> Array[StateItem]
+ def find_shift_conflict_shortest_path(reduce_state_items, conflict_state, conflict_item)
+ time1 = Time.now.to_f
+ @iterate_count = 0
- def find_shift_conflict_shortest_state_items(reduce_path, conflict_state, conflict_item)
- target_state_item = StateItem.new(conflict_state, conflict_item)
+ target_state_item = get_state_item(conflict_state, conflict_item)
result = [target_state_item]
- reversed_reduce_path = reduce_path.to_a.reverse
+ reversed_state_items = reduce_state_items.to_a.reverse
# Index for state_item
i = 0
- while (path = reversed_reduce_path[i])
+ while (state_item = reversed_state_items[i])
# Index for prev_state_item
j = i + 1
_j = j
- while (prev_path = reversed_reduce_path[j])
- if prev_path.production?
+ while (prev_state_item = reversed_state_items[j])
+ if prev_state_item.type == :production
j += 1
else
break
end
end
- state_item = path.to
- prev_state_item = prev_path&.to
-
if target_state_item == state_item || target_state_item.item.start_item?
result.concat(
- reversed_reduce_path[_j..-1] #: Array[StartPath|TransitionPath|ProductionPath]
- .map(&:to))
+ reversed_state_items[_j..-1] #: Array[StateItem]
+ )
break
end
- if target_state_item.item.beginning_of_rule?
- queue = [] #: Array[Array[StateItem]]
- queue << [target_state_item]
+ if target_state_item.type == :production
+ queue = [] #: Array[Node[StateItem]]
+ queue << Node.new(target_state_item, nil)
# Find reverse production
while (sis = queue.shift)
- si = sis.last
+ @iterate_count += 1
+ si = sis.elem
# Reach to start state
if si.item.start_item?
- sis.shift
- result.concat(sis)
+ a = Node.to_a(sis).reverse
+ a.shift
+ result.concat(a)
target_state_item = si
break
end
- if si.item.beginning_of_rule?
+ if si.type == :production
# @type var key: [State, Grammar::Symbol]
key = [si.state, si.item.lhs]
- @reverse_productions[key].each do |item|
- state_item = StateItem.new(si.state, item)
- queue << (sis + [state_item])
+ @reverse_productions[key].each do |state_item|
+ queue << Node.new(state_item, sis)
end
else
# @type var key: [StateItem, Grammar::Symbol]
key = [si, si.item.previous_sym]
@reverse_transitions[key].each do |prev_target_state_item|
next if prev_target_state_item.state != prev_state_item&.state
- sis.shift
- result.concat(sis)
+ a = Node.to_a(sis).reverse
+ a.shift
+ result.concat(a)
result << prev_target_state_item
target_state_item = prev_target_state_item
i = j
@@ -216,68 +289,106 @@ module Lrama
end
end
+ time2 = Time.now.to_f
+ duration = time2 - time1
+ increment_total_duration(duration)
+
+ if Tracer::Duration.enabled?
+ STDERR.puts sprintf(" %s %10.5f s", "find_shift_conflict_shortest_path #{@iterate_count} iteration", duration)
+ end
+
result.reverse
end
- def build_paths_from_state_items(state_items)
- state_items.zip([nil] + state_items).map do |si, prev_si|
- case
- when prev_si.nil?
- StartPath.new(si)
- when si.item.beginning_of_rule?
- ProductionPath.new(prev_si, si)
- else
- TransitionPath.new(prev_si, si)
+ # @rbs (StateItem target) -> Set[StateItem]
+ def reachable_state_items(target)
+ result = Set.new
+ queue = [target]
+
+ while (state_item = queue.shift)
+ next if result.include?(state_item)
+ result << state_item
+
+ @reverse_transitions[[state_item, state_item.item.previous_sym]]&.each do |prev_state_item|
+ queue << prev_state_item
+ end
+
+ if state_item.item.beginning_of_rule?
+ @reverse_productions[[state_item.state, state_item.item.lhs]]&.each do |si|
+ queue << si
+ end
end
end
+
+ result
end
+ # @rbs (State conflict_state, State::Item conflict_reduce_item, Grammar::Symbol conflict_term) -> ::Array[StateItem]?
def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
- # queue: is an array of [Triple, [Path]]
- queue = [] #: Array[[Triple, Array[StartPath|TransitionPath|ProductionPath]]]
+ time1 = Time.now.to_f
+ @iterate_count = 0
+
+ queue = [] #: Array[[Triple, Path]]
visited = {} #: Hash[Triple, true]
start_state = @states.states.first #: Lrama::State
+ conflict_term_bit = Bitmap::from_integer(conflict_term.number)
raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
+ reachable = reachable_state_items(get_state_item(conflict_state, conflict_reduce_item))
+ start = get_triple(get_state_item(start_state, start_state.kernels.first), Bitmap::from_integer(@states.eof_symbol.number))
- start = Triple.new(start_state, start_state.kernels.first, Set.new([@states.eof_symbol]))
+ queue << [start, Path.new(start.state_item, nil)]
- queue << [start, [StartPath.new(start.state_item)]]
+ while (triple, path = queue.shift)
+ @iterate_count += 1
- while true
- triple, paths = queue.shift
+ # Found
+ if (triple.state == conflict_state) && (triple.item == conflict_reduce_item) && (triple.l & conflict_term_bit != 0)
+ state_items = [path.state_item]
- next if visited[triple]
- visited[triple] = true
+ while (path = path.parent)
+ state_items << path.state_item
+ end
- # Found
- if triple.state == conflict_state && triple.item == conflict_reduce_item && triple.l.include?(conflict_term)
- return paths
+ time2 = Time.now.to_f
+ duration = time2 - time1
+ increment_total_duration(duration)
+
+ if Tracer::Duration.enabled?
+ STDERR.puts sprintf(" %s %10.5f s", "shortest_path #{@iterate_count} iteration", duration)
+ end
+
+ return state_items.reverse
end
# transition
- triple.state.transitions.each do |shift, next_state|
- next unless triple.item.next_sym && triple.item.next_sym == shift.next_sym
- next_state.kernels.each do |kernel|
- next if kernel.rule != triple.item.rule
- t = Triple.new(next_state, kernel, triple.l)
- queue << [t, paths + [TransitionPath.new(triple.state_item, t.state_item)]]
+ next_state_item = @transitions[[triple.state_item, triple.item.next_sym]]
+ if next_state_item && reachable.include?(next_state_item)
+ # @type var t: Triple
+ t = get_triple(next_state_item, triple.l)
+ unless visited[t]
+ visited[t] = true
+ queue << [t, Path.new(t.state_item, path)]
end
end
# production step
- triple.state.closure.each do |item|
- next unless triple.item.next_sym && triple.item.next_sym == item.lhs
+ @productions[triple.state_item]&.each do |si|
+ next unless reachable.include?(si)
+
l = follow_l(triple.item, triple.l)
- t = Triple.new(triple.state, item, l)
- queue << [t, paths + [ProductionPath.new(triple.state_item, t.state_item)]]
+ # @type var t: Triple
+ t = get_triple(si, l)
+ unless visited[t]
+ visited[t] = true
+ queue << [t, Path.new(t.state_item, path)]
+ end
end
-
- break if queue.empty?
end
return nil
end
+ # @rbs (State::Item item, Bitmap::bitmap current_l) -> Bitmap::bitmap
def follow_l(item, current_l)
# 1. follow_L (A -> X1 ... Xn-1 • Xn) = L
# 2. follow_L (A -> X1 ... Xk • Xk+1 Xk+2 ... Xn) = {Xk+2} if Xk+2 is a terminal
@@ -287,11 +398,28 @@ module Lrama
when item.number_of_rest_symbols == 1
current_l
when item.next_next_sym.term?
- Set.new([item.next_next_sym])
+ item.next_next_sym.number_bitmap
when !item.next_next_sym.nullable
- item.next_next_sym.first_set
+ item.next_next_sym.first_set_bitmap
else
- item.next_next_sym.first_set + follow_l(item.new_by_next_position, current_l)
+ item.next_next_sym.first_set_bitmap | follow_l(item.new_by_next_position, current_l)
+ end
+ end
+
+ # @rbs [T] (String message) { -> T } -> T
+ def with_timeout(message)
+ Timeout.timeout(PathSearchTimeLimit, Timeout::Error, message + " timeout of #{PathSearchTimeLimit} sec exceeded") do
+ yield
+ end
+ end
+
+ # @rbs (Float|Integer duration) -> void
+ def increment_total_duration(duration)
+ @total_duration += duration
+
+ if !@exceed_cumulative_time_limit && @total_duration > CumulativeTimeLimit
+ @exceed_cumulative_time_limit = true
+ STDERR.puts "CumulativeTimeLimit #{CumulativeTimeLimit} sec exceeded then skip following Counterexamples calculation"
end
end
end
diff --git a/tool/lrama/lib/lrama/counterexamples/derivation.rb b/tool/lrama/lib/lrama/counterexamples/derivation.rb
index 368d7f1032..a2b74767a9 100644
--- a/tool/lrama/lib/lrama/counterexamples/derivation.rb
+++ b/tool/lrama/lib/lrama/counterexamples/derivation.rb
@@ -1,34 +1,44 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Counterexamples
class Derivation
- attr_reader :item, :left, :right
- attr_writer :right
+ # @rbs!
+ # @item: State::Item
+ # @left: Derivation?
- def initialize(item, left, right = nil)
+ attr_reader :item #: State::Item
+ attr_reader :left #: Derivation?
+ attr_accessor :right #: Derivation?
+
+ # @rbs (State::Item item, Derivation? left) -> void
+ def initialize(item, left)
@item = item
@left = left
- @right = right
end
+ # @rbs () -> ::String
def to_s
"#<Derivation(#{item.display_name})>"
end
alias :inspect :to_s
+ # @rbs () -> Array[String]
def render_strings_for_report
result = [] #: Array[String]
_render_for_report(self, 0, result, 0)
result.map(&:rstrip)
end
+ # @rbs () -> String
def render_for_report
render_strings_for_report.join("\n")
end
private
+ # @rbs (Derivation derivation, Integer offset, Array[String] strings, Integer index) -> Integer
def _render_for_report(derivation, offset, strings, index)
item = derivation.item
if strings[index]
diff --git a/tool/lrama/lib/lrama/counterexamples/example.rb b/tool/lrama/lib/lrama/counterexamples/example.rb
index bb08428fcd..c007f45af4 100644
--- a/tool/lrama/lib/lrama/counterexamples/example.rb
+++ b/tool/lrama/lib/lrama/counterexamples/example.rb
@@ -1,12 +1,31 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Counterexamples
class Example
- attr_reader :path1, :path2, :conflict, :conflict_symbol
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @path1: ::Array[StateItem]
+ # @path2: ::Array[StateItem]
+ # @conflict: State::conflict
+ # @conflict_symbol: Grammar::Symbol
+ # @counterexamples: Counterexamples
+ # @derivations1: Derivation
+ # @derivations2: Derivation
+
+ attr_reader :path1 #: ::Array[StateItem]
+ attr_reader :path2 #: ::Array[StateItem]
+ attr_reader :conflict #: State::conflict
+ attr_reader :conflict_symbol #: Grammar::Symbol
# path1 is shift conflict when S/R conflict
# path2 is always reduce conflict
+ #
+ # @rbs (Array[StateItem]? path1, Array[StateItem]? path2, State::conflict conflict, Grammar::Symbol conflict_symbol, Counterexamples counterexamples) -> void
def initialize(path1, path2, conflict, conflict_symbol, counterexamples)
@path1 = path1
@path2 = path2
@@ -15,69 +34,75 @@ module Lrama
@counterexamples = counterexamples
end
+ # @rbs () -> (:shift_reduce | :reduce_reduce)
def type
@conflict.type
end
+ # @rbs () -> State::Item
def path1_item
- @path1.last.to.item
+ @path1.last.item
end
+ # @rbs () -> State::Item
def path2_item
- @path2.last.to.item
+ @path2.last.item
end
+ # @rbs () -> Derivation
def derivations1
@derivations1 ||= _derivations(path1)
end
+ # @rbs () -> Derivation
def derivations2
@derivations2 ||= _derivations(path2)
end
private
- def _derivations(paths)
+ # @rbs (Array[StateItem] state_items) -> Derivation
+ def _derivations(state_items)
derivation = nil #: Derivation
current = :production
- last_path = paths.last #: Path
- lookahead_sym = last_path.to.item.end_of_rule? ? @conflict_symbol : nil
+ last_state_item = state_items.last #: StateItem
+ lookahead_sym = last_state_item.item.end_of_rule? ? @conflict_symbol : nil
- paths.reverse_each do |path|
- item = path.to.item
+ state_items.reverse_each do |si|
+ item = si.item
case current
when :production
- case path
- when StartPath
+ case si.type
+ when :start
derivation = Derivation.new(item, derivation)
current = :start
- when TransitionPath
+ when :transition
derivation = Derivation.new(item, derivation)
current = :transition
- when ProductionPath
+ when :production
derivation = Derivation.new(item, derivation)
current = :production
else
- raise "Unexpected. #{path}"
+ raise "Unexpected. #{si}"
end
if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym)
- state_item = @counterexamples.transitions[[path.to, item.next_sym]]
- derivation2 = find_derivation_for_symbol(state_item, lookahead_sym)
+ si2 = @counterexamples.transitions[[si, item.next_sym]]
+ derivation2 = find_derivation_for_symbol(si2, lookahead_sym)
derivation.right = derivation2 # steep:ignore
lookahead_sym = nil
end
when :transition
- case path
- when StartPath
+ case si.type
+ when :start
derivation = Derivation.new(item, derivation)
current = :start
- when TransitionPath
+ when :transition
# ignore
current = :transition
- when ProductionPath
+ when :production
# ignore
current = :production
end
@@ -91,6 +116,7 @@ module Lrama
derivation
end
+ # @rbs (StateItem state_item, Grammar::Symbol sym) -> Derivation?
def find_derivation_for_symbol(state_item, sym)
queue = [] #: Array[Array[StateItem]]
queue << [state_item]
@@ -110,9 +136,8 @@ module Lrama
end
if next_sym.nterm? && next_sym.first_set.include?(sym)
- @counterexamples.productions[si].each do |next_item|
- next if next_item.empty_rule?
- next_si = StateItem.new(si.state, next_item)
+ @counterexamples.productions[si].each do |next_si|
+ next if next_si.item.empty_rule?
next if sis.include?(next_si)
queue << (sis + [next_si])
end
diff --git a/tool/lrama/lib/lrama/counterexamples/node.rb b/tool/lrama/lib/lrama/counterexamples/node.rb
new file mode 100644
index 0000000000..9214a0e7f1
--- /dev/null
+++ b/tool/lrama/lib/lrama/counterexamples/node.rb
@@ -0,0 +1,30 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Counterexamples
+ # @rbs generic E < Object -- Type of an element
+ class Node
+ attr_reader :elem #: E
+ attr_reader :next_node #: Node[E]?
+
+ # @rbs [E < Object] (Node[E] node) -> Array[E]
+ def self.to_a(node)
+ a = [] # steep:ignore UnannotatedEmptyCollection
+
+ while (node)
+ a << node.elem
+ node = node.next_node
+ end
+
+ a
+ end
+
+ # @rbs (E elem, Node[E]? next_node) -> void
+ def initialize(elem, next_node)
+ @elem = elem
+ @next_node = next_node
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/counterexamples/path.rb b/tool/lrama/lib/lrama/counterexamples/path.rb
index 0a5823dd21..6b1325f73b 100644
--- a/tool/lrama/lib/lrama/counterexamples/path.rb
+++ b/tool/lrama/lib/lrama/counterexamples/path.rb
@@ -1,29 +1,27 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Counterexamples
class Path
- def initialize(from_state_item, to_state_item)
- @from_state_item = from_state_item
- @to_state_item = to_state_item
- end
+ # @rbs!
+ # @state_item: StateItem
+ # @parent: Path?
- def from
- @from_state_item
- end
+ attr_reader :state_item #: StateItem
+ attr_reader :parent #: Path?
- def to
- @to_state_item
+ # @rbs (StateItem state_item, Path? parent) -> void
+ def initialize(state_item, parent)
+ @state_item = state_item
+ @parent = parent
end
+ # @rbs () -> ::String
def to_s
- "#<Path(#{type})>"
+ "#<Path>"
end
alias :inspect :to_s
-
- def type
- raise NotImplementedError
- end
end
end
end
diff --git a/tool/lrama/lib/lrama/counterexamples/production_path.rb b/tool/lrama/lib/lrama/counterexamples/production_path.rb
deleted file mode 100644
index 0a230c7fce..0000000000
--- a/tool/lrama/lib/lrama/counterexamples/production_path.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Counterexamples
- class ProductionPath < Path
- def type
- :production
- end
-
- def transition?
- false
- end
-
- def production?
- true
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/counterexamples/start_path.rb b/tool/lrama/lib/lrama/counterexamples/start_path.rb
deleted file mode 100644
index c0351c8248..0000000000
--- a/tool/lrama/lib/lrama/counterexamples/start_path.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Counterexamples
- class StartPath < Path
- def initialize(to_state_item)
- super nil, to_state_item
- end
-
- def type
- :start
- end
-
- def transition?
- false
- end
-
- def production?
- false
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/counterexamples/state_item.rb b/tool/lrama/lib/lrama/counterexamples/state_item.rb
index c919818324..8c2481d793 100644
--- a/tool/lrama/lib/lrama/counterexamples/state_item.rb
+++ b/tool/lrama/lib/lrama/counterexamples/state_item.rb
@@ -1,8 +1,31 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Counterexamples
- class StateItem < Struct.new(:state, :item)
+ class StateItem
+ attr_reader :id #: Integer
+ attr_reader :state #: State
+ attr_reader :item #: State::Item
+
+ # @rbs (Integer id, State state, State::Item item) -> void
+ def initialize(id, state, item)
+ @id = id
+ @state = state
+ @item = item
+ end
+
+ # @rbs () -> (:start | :transition | :production)
+ def type
+ case
+ when item.start_item?
+ :start
+ when item.beginning_of_rule?
+ :production
+ else
+ :transition
+ end
+ end
end
end
end
diff --git a/tool/lrama/lib/lrama/counterexamples/transition_path.rb b/tool/lrama/lib/lrama/counterexamples/transition_path.rb
deleted file mode 100644
index 47bfbc4f98..0000000000
--- a/tool/lrama/lib/lrama/counterexamples/transition_path.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Counterexamples
- class TransitionPath < Path
- def type
- :transition
- end
-
- def transition?
- true
- end
-
- def production?
- false
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/counterexamples/triple.rb b/tool/lrama/lib/lrama/counterexamples/triple.rb
index 64014ee223..98fe051f53 100644
--- a/tool/lrama/lib/lrama/counterexamples/triple.rb
+++ b/tool/lrama/lib/lrama/counterexamples/triple.rb
@@ -1,21 +1,39 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Counterexamples
- # s: state
- # itm: item within s
- # l: precise lookahead set
- class Triple < Struct.new(:s, :itm, :l)
- alias :state :s
- alias :item :itm
- alias :precise_lookahead_set :l
+ class Triple
+ attr_reader :precise_lookahead_set #: Bitmap::bitmap
+ alias :l :precise_lookahead_set
+
+ # @rbs (StateItem state_item, Bitmap::bitmap precise_lookahead_set) -> void
+ def initialize(state_item, precise_lookahead_set)
+ @state_item = state_item
+ @precise_lookahead_set = precise_lookahead_set
+ end
+
+ # @rbs () -> State
+ def state
+ @state_item.state
+ end
+ alias :s :state
+
+ # @rbs () -> State::Item
+ def item
+ @state_item.item
+ end
+ alias :itm :item
+
+ # @rbs () -> StateItem
def state_item
- StateItem.new(state, item)
+ @state_item
end
+ # @rbs () -> ::String
def inspect
- "#{state.inspect}. #{item.display_name}. #{l.map(&:id).map(&:s_value)}"
+ "#{state.inspect}. #{item.display_name}. #{l.to_s(2)}"
end
alias :to_s :inspect
end
diff --git a/tool/lrama/lib/lrama/diagnostics.rb b/tool/lrama/lib/lrama/diagnostics.rb
deleted file mode 100644
index e9da398c89..0000000000
--- a/tool/lrama/lib/lrama/diagnostics.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Diagnostics
- def initialize(grammar, states, logger)
- @grammar = grammar
- @states = states
- @logger = logger
- end
-
- def run(diagnostic)
- if diagnostic
- diagnose_conflict
- diagnose_parameterizing_redefined
- end
- end
-
- private
-
- def diagnose_conflict
- if @states.sr_conflicts_count != 0
- @logger.warn("shift/reduce conflicts: #{@states.sr_conflicts_count} found")
- end
-
- if @states.rr_conflicts_count != 0
- @logger.warn("reduce/reduce conflicts: #{@states.rr_conflicts_count} found")
- end
- end
-
- def diagnose_parameterizing_redefined
- @grammar.parameterizing_rule_resolver.redefined_rules.each do |rule|
- @logger.warn("parameterizing rule redefined: #{rule}")
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/diagram.rb b/tool/lrama/lib/lrama/diagram.rb
new file mode 100644
index 0000000000..985808933f
--- /dev/null
+++ b/tool/lrama/lib/lrama/diagram.rb
@@ -0,0 +1,77 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Diagram
+ class << self
+ # @rbs (IO out, Grammar grammar, String template_name) -> void
+ def render(out:, grammar:, template_name: 'diagram/diagram.html')
+ return unless require_railroad_diagrams
+ new(out: out, grammar: grammar, template_name: template_name).render
+ end
+
+ # @rbs () -> bool
+ def require_railroad_diagrams
+ require "railroad_diagrams"
+ true
+ rescue LoadError
+ warn "railroad_diagrams is not installed. Please run `bundle install`."
+ false
+ end
+ end
+
+ # @rbs (IO out, Grammar grammar, String template_name) -> void
+ def initialize(out:, grammar:, template_name: 'diagram/diagram.html')
+ @grammar = grammar
+ @out = out
+ @template_name = template_name
+ end
+
+ # @rbs () -> void
+ def render
+ RailroadDiagrams::TextDiagram.set_formatting(RailroadDiagrams::TextDiagram::PARTS_UNICODE)
+ @out << ERB.render(template_file, output: self)
+ end
+
+ # @rbs () -> string
+ def default_style
+ RailroadDiagrams::Style::default_style
+ end
+
+ # @rbs () -> string
+ def diagrams
+ result = +''
+ @grammar.unique_rule_s_values.each do |s_value|
+ diagrams =
+ @grammar.select_rules_by_s_value(s_value).map { |r| r.to_diagrams }
+ add_diagram(
+ s_value,
+ RailroadDiagrams::Diagram.new(
+ RailroadDiagrams::Choice.new(0, *diagrams),
+ ),
+ result
+ )
+ end
+ result
+ end
+
+ private
+
+ # @rbs () -> string
+ def template_dir
+ File.expand_path('../../template', __dir__)
+ end
+
+ # @rbs () -> string
+ def template_file
+ File.join(template_dir, @template_name)
+ end
+
+ # @rbs (String name, RailroadDiagrams::Diagram diagram, String result) -> void
+ def add_diagram(name, diagram, result)
+ result << "\n<h2 class=\"diagram-header\">#{RailroadDiagrams.escape_html(name)}</h2>"
+ diagram.write_svg(result.method(:<<))
+ result << "\n"
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/digraph.rb b/tool/lrama/lib/lrama/digraph.rb
index 2161f30474..52865f52dd 100644
--- a/tool/lrama/lib/lrama/digraph.rb
+++ b/tool/lrama/lib/lrama/digraph.rb
@@ -2,13 +2,34 @@
# frozen_string_literal: true
module Lrama
- # Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
+ # Digraph Algorithm of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
#
- # @rbs generic X < Object -- Type of a member of `sets`
- # @rbs generic Y < _Or -- Type of sets assigned to a member of `sets`
+ # Digraph is an algorithm for graph data structure.
+ # The algorithm efficiently traverses SCC (Strongly Connected Component) of graph
+ # and merges nodes attributes within the same SCC.
+ #
+ # `compute_read_sets` and `compute_follow_sets` have the same structure.
+ # Graph of gotos and attributes of gotos are given then compute propagated attributes for each node.
+ #
+ # In the case of `compute_read_sets`:
+ #
+ # * Set of gotos is nodes of graph
+ # * `reads_relation` is edges of graph
+ # * `direct_read_sets` is nodes attributes
+ #
+ # In the case of `compute_follow_sets`:
+ #
+ # * Set of gotos is nodes of graph
+ # * `includes_relation` is edges of graph
+ # * `read_sets` is nodes attributes
+ #
+ #
+ # @rbs generic X < Object -- Type of a node
+ # @rbs generic Y < _Or -- Type of attribute sets assigned to a node which should support merge operation (#| method)
class Digraph
- # TODO: rbs-inline 0.10.0 doesn't support instance variables.
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
# Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
#
# @rbs!
# interface _Or
@@ -21,9 +42,9 @@ module Lrama
# @h: Hash[X, (Integer|Float)?]
# @result: Hash[X, Y]
- # @rbs sets: Array[X]
- # @rbs relation: Hash[X, Array[X]]
- # @rbs base_function: Hash[X, Y]
+ # @rbs sets: Array[X] -- Nodes of graph
+ # @rbs relation: Hash[X, Array[X]] -- Edges of graph
+ # @rbs base_function: Hash[X, Y] -- Attributes of nodes
# @rbs return: void
def initialize(sets, relation, base_function)
diff --git a/tool/lrama/lib/lrama/erb.rb b/tool/lrama/lib/lrama/erb.rb
new file mode 100644
index 0000000000..8f8be54811
--- /dev/null
+++ b/tool/lrama/lib/lrama/erb.rb
@@ -0,0 +1,29 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+require "erb"
+
+module Lrama
+ class ERB
+ # @rbs (String file, **untyped kwargs) -> String
+ def self.render(file, **kwargs)
+ new(file).render(**kwargs)
+ end
+
+ # @rbs (String file) -> void
+ def initialize(file)
+ input = File.read(file)
+ if ::ERB.instance_method(:initialize).parameters.last.first == :key
+ @erb = ::ERB.new(input, trim_mode: '-')
+ else
+ @erb = ::ERB.new(input, nil, '-') # steep:ignore UnexpectedPositionalArgument
+ end
+ @erb.filename = file
+ end
+
+ # @rbs (**untyped kwargs) -> String
+ def render(**kwargs)
+ @erb.result_with_hash(kwargs)
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/grammar.rb b/tool/lrama/lib/lrama/grammar.rb
index 214ca1a3f2..95a80bb01c 100644
--- a/tool/lrama/lib/lrama/grammar.rb
+++ b/tool/lrama/lib/lrama/grammar.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
require "forwardable"
@@ -7,7 +8,8 @@ require_relative "grammar/code"
require_relative "grammar/counter"
require_relative "grammar/destructor"
require_relative "grammar/error_token"
-require_relative "grammar/parameterizing_rule"
+require_relative "grammar/inline"
+require_relative "grammar/parameterized"
require_relative "grammar/percent_code"
require_relative "grammar/precedence"
require_relative "grammar/printer"
@@ -23,19 +25,89 @@ require_relative "lexer"
module Lrama
# Grammar is the result of parsing an input grammar file
class Grammar
+ # @rbs!
+ #
+ # interface _DelegatedMethods
+ # def rules: () -> Array[Rule]
+ # def accept_symbol: () -> Grammar::Symbol
+ # def eof_symbol: () -> Grammar::Symbol
+ # def undef_symbol: () -> Grammar::Symbol
+ # def precedences: () -> Array[Precedence]
+ #
+ # # delegate to @symbols_resolver
+ # def symbols: () -> Array[Grammar::Symbol]
+ # def terms: () -> Array[Grammar::Symbol]
+ # def nterms: () -> Array[Grammar::Symbol]
+ # def find_symbol_by_s_value!: (::String s_value) -> Grammar::Symbol
+ # def ielr_defined?: () -> bool
+ # end
+ #
+ # include Symbols::Resolver::_DelegatedMethods
+ #
+ # @rule_counter: Counter
+ # @percent_codes: Array[PercentCode]
+ # @printers: Array[Printer]
+ # @destructors: Array[Destructor]
+ # @error_tokens: Array[ErrorToken]
+ # @symbols_resolver: Symbols::Resolver
+ # @types: Array[Type]
+ # @rule_builders: Array[RuleBuilder]
+ # @rules: Array[Rule]
+ # @sym_to_rules: Hash[Integer, Array[Rule]]
+ # @parameterized_resolver: Parameterized::Resolver
+ # @empty_symbol: Grammar::Symbol
+ # @eof_symbol: Grammar::Symbol
+ # @error_symbol: Grammar::Symbol
+ # @undef_symbol: Grammar::Symbol
+ # @accept_symbol: Grammar::Symbol
+ # @aux: Auxiliary
+ # @no_stdlib: bool
+ # @locations: bool
+ # @define: Hash[String, String]
+ # @required: bool
+ # @union: Union
+ # @precedences: Array[Precedence]
+ # @start_nterm: Lrama::Lexer::Token::Base?
+
extend Forwardable
- attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux, :parameterizing_rule_resolver
- attr_accessor :union, :expect, :printers, :error_tokens, :lex_param, :parse_param, :initial_action,
- :after_shift, :before_reduce, :after_reduce, :after_shift_error_token, :after_pop_stack,
- :symbols_resolver, :types, :rules, :rule_builders, :sym_to_rules, :no_stdlib, :locations, :define
+ attr_reader :percent_codes #: Array[PercentCode]
+ attr_reader :eof_symbol #: Grammar::Symbol
+ attr_reader :error_symbol #: Grammar::Symbol
+ attr_reader :undef_symbol #: Grammar::Symbol
+ attr_reader :accept_symbol #: Grammar::Symbol
+ attr_reader :aux #: Auxiliary
+ attr_reader :parameterized_resolver #: Parameterized::Resolver
+ attr_reader :precedences #: Array[Precedence]
+ attr_accessor :union #: Union
+ attr_accessor :expect #: Integer
+ attr_accessor :printers #: Array[Printer]
+ attr_accessor :error_tokens #: Array[ErrorToken]
+ attr_accessor :lex_param #: String
+ attr_accessor :parse_param #: String
+ attr_accessor :initial_action #: Grammar::Code::InitialActionCode
+ attr_accessor :after_shift #: Lexer::Token::Base
+ attr_accessor :before_reduce #: Lexer::Token::Base
+ attr_accessor :after_reduce #: Lexer::Token::Base
+ attr_accessor :after_shift_error_token #: Lexer::Token::Base
+ attr_accessor :after_pop_stack #: Lexer::Token::Base
+ attr_accessor :symbols_resolver #: Symbols::Resolver
+ attr_accessor :types #: Array[Type]
+ attr_accessor :rules #: Array[Rule]
+ attr_accessor :rule_builders #: Array[RuleBuilder]
+ attr_accessor :sym_to_rules #: Hash[Integer, Array[Rule]]
+ attr_accessor :no_stdlib #: bool
+ attr_accessor :locations #: bool
+ attr_accessor :define #: Hash[String, String]
+ attr_accessor :required #: bool
def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term, :find_term_by_s_value,
:find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol,
:find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type,
:fill_printer, :fill_destructor, :fill_error_token, :sort_by_number!
- def initialize(rule_counter, define = {})
+ # @rbs (Counter rule_counter, bool locations, Hash[String, String] define) -> void
+ def initialize(rule_counter, locations, define = {})
@rule_counter = rule_counter
# Code defined by "%code"
@@ -48,7 +120,7 @@ module Lrama
@rule_builders = []
@rules = []
@sym_to_rules = {}
- @parameterizing_rule_resolver = ParameterizingRule::Resolver.new
+ @parameterized_resolver = Parameterized::Resolver.new
@empty_symbol = nil
@eof_symbol = nil
@error_symbol = nil
@@ -56,93 +128,131 @@ module Lrama
@accept_symbol = nil
@aux = Auxiliary.new
@no_stdlib = false
- @locations = false
- @define = define.map {|d| d.split('=') }.to_h
+ @locations = locations
+ @define = define
+ @required = false
+ @precedences = []
+ @start_nterm = nil
append_special_symbols
end
+ # @rbs (Counter rule_counter, Counter midrule_action_counter) -> RuleBuilder
def create_rule_builder(rule_counter, midrule_action_counter)
- RuleBuilder.new(rule_counter, midrule_action_counter, @parameterizing_rule_resolver)
+ RuleBuilder.new(rule_counter, midrule_action_counter, @parameterized_resolver)
end
+ # @rbs (id: Lexer::Token::Base, code: Lexer::Token::UserCode) -> Array[PercentCode]
def add_percent_code(id:, code:)
@percent_codes << PercentCode.new(id.s_value, code.s_value)
end
+ # @rbs (ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag], token_code: Lexer::Token::UserCode, lineno: Integer) -> Array[Destructor]
def add_destructor(ident_or_tags:, token_code:, lineno:)
@destructors << Destructor.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end
+ # @rbs (ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag], token_code: Lexer::Token::UserCode, lineno: Integer) -> Array[Printer]
def add_printer(ident_or_tags:, token_code:, lineno:)
@printers << Printer.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end
+ # @rbs (ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag], token_code: Lexer::Token::UserCode, lineno: Integer) -> Array[ErrorToken]
def add_error_token(ident_or_tags:, token_code:, lineno:)
@error_tokens << ErrorToken.new(ident_or_tags: ident_or_tags, token_code: token_code, lineno: lineno)
end
+ # @rbs (id: Lexer::Token::Base, tag: Lexer::Token::Tag) -> Array[Type]
def add_type(id:, tag:)
@types << Type.new(id: id, tag: tag)
end
- def add_nonassoc(sym, precedence)
- set_precedence(sym, Precedence.new(type: :nonassoc, precedence: precedence))
+ # @rbs (Grammar::Symbol sym, Integer precedence, String s_value, Integer lineno) -> Precedence
+ def add_nonassoc(sym, precedence, s_value, lineno)
+ set_precedence(sym, Precedence.new(symbol: sym, s_value: s_value, type: :nonassoc, precedence: precedence, lineno: lineno))
+ end
+
+ # @rbs (Grammar::Symbol sym, Integer precedence, String s_value, Integer lineno) -> Precedence
+ def add_left(sym, precedence, s_value, lineno)
+ set_precedence(sym, Precedence.new(symbol: sym, s_value: s_value, type: :left, precedence: precedence, lineno: lineno))
end
- def add_left(sym, precedence)
- set_precedence(sym, Precedence.new(type: :left, precedence: precedence))
+ # @rbs (Grammar::Symbol sym, Integer precedence, String s_value, Integer lineno) -> Precedence
+ def add_right(sym, precedence, s_value, lineno)
+ set_precedence(sym, Precedence.new(symbol: sym, s_value: s_value, type: :right, precedence: precedence, lineno: lineno))
end
- def add_right(sym, precedence)
- set_precedence(sym, Precedence.new(type: :right, precedence: precedence))
+ # @rbs (Grammar::Symbol sym, Integer precedence, String s_value, Integer lineno) -> Precedence
+ def add_precedence(sym, precedence, s_value, lineno)
+ set_precedence(sym, Precedence.new(symbol: sym, s_value: s_value, type: :precedence, precedence: precedence, lineno: lineno))
end
- def add_precedence(sym, precedence)
- set_precedence(sym, Precedence.new(type: :precedence, precedence: precedence))
+ # @rbs (Lrama::Lexer::Token::Base id) -> Lrama::Lexer::Token::Base
+ def set_start_nterm(id)
+ # When multiple `%start` directives are defined, Bison does not generate an error,
+ # whereas Lrama does generate an error.
+ # Related Bison's specification are
+ # refs: https://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html
+ if @start_nterm.nil?
+ @start_nterm = id
+ else
+ start = @start_nterm #: Lrama::Lexer::Token::Base
+ raise "Start non-terminal is already set to #{start.s_value} (line: #{start.first_line}). Cannot set to #{id.s_value} (line: #{id.first_line})."
+ end
end
+ # @rbs (Grammar::Symbol sym, Precedence precedence) -> (Precedence | bot)
def set_precedence(sym, precedence)
- raise "" if sym.nterm?
+ @precedences << precedence
sym.precedence = precedence
end
+ # @rbs (Grammar::Code::NoReferenceCode code, Integer lineno) -> Union
def set_union(code, lineno)
@union = Union.new(code: code, lineno: lineno)
end
+ # @rbs (RuleBuilder builder) -> Array[RuleBuilder]
def add_rule_builder(builder)
@rule_builders << builder
end
- def add_parameterizing_rule(rule)
- @parameterizing_rule_resolver.add_parameterizing_rule(rule)
+ # @rbs (Parameterized::Rule rule) -> Array[Parameterized::Rule]
+ def add_parameterized_rule(rule)
+ @parameterized_resolver.add_rule(rule)
end
- def parameterizing_rules
- @parameterizing_rule_resolver.rules
+ # @rbs () -> Array[Parameterized::Rule]
+ def parameterized_rules
+ @parameterized_resolver.rules
end
- def insert_before_parameterizing_rules(rules)
- @parameterizing_rule_resolver.rules = rules + @parameterizing_rule_resolver.rules
+ # @rbs (Array[Parameterized::Rule] rules) -> Array[Parameterized::Rule]
+ def prepend_parameterized_rules(rules)
+ @parameterized_resolver.rules = rules + @parameterized_resolver.rules
end
+ # @rbs (Integer prologue_first_lineno) -> Integer
def prologue_first_lineno=(prologue_first_lineno)
@aux.prologue_first_lineno = prologue_first_lineno
end
+ # @rbs (String prologue) -> String
def prologue=(prologue)
@aux.prologue = prologue
end
+ # @rbs (Integer epilogue_first_lineno) -> Integer
def epilogue_first_lineno=(epilogue_first_lineno)
@aux.epilogue_first_lineno = epilogue_first_lineno
end
+ # @rbs (String epilogue) -> String
def epilogue=(epilogue)
@aux.epilogue = epilogue
end
+ # @rbs () -> void
def prepare
resolve_inline_rules
normalize_rules
@@ -151,6 +261,7 @@ module Lrama
fill_default_precedence
fill_symbols
fill_sym_to_rules
+ sort_precedence
compute_nullable
compute_first_set
set_locations
@@ -159,25 +270,51 @@ module Lrama
# TODO: More validation methods
#
# * Validation for no_declared_type_reference
+ #
+ # @rbs () -> void
def validate!
@symbols_resolver.validate!
+ validate_no_precedence_for_nterm!
validate_rule_lhs_is_nterm!
+ validate_duplicated_precedence!
end
+ # @rbs (Grammar::Symbol sym) -> Array[Rule]
def find_rules_by_symbol!(sym)
find_rules_by_symbol(sym) || (raise "Rules for #{sym} not found")
end
+ # @rbs (Grammar::Symbol sym) -> Array[Rule]?
def find_rules_by_symbol(sym)
@sym_to_rules[sym.number]
end
+ # @rbs (String s_value) -> Array[Rule]
+ def select_rules_by_s_value(s_value)
+ @rules.select {|rule| rule.lhs.id.s_value == s_value }
+ end
+
+ # @rbs () -> Array[String]
+ def unique_rule_s_values
+ @rules.map {|rule| rule.lhs.id.s_value }.uniq
+ end
+
+ # @rbs () -> bool
def ielr_defined?
@define.key?('lr.type') && @define['lr.type'] == 'ielr'
end
private
+ # @rbs () -> void
+ def sort_precedence
+ @precedences.sort_by! do |prec|
+ prec.symbol.number
+ end
+ @precedences.freeze
+ end
+
+ # @rbs () -> Array[Grammar::Symbol]
def compute_nullable
@rules.each do |rule|
case
@@ -227,6 +364,7 @@ module Lrama
end
end
+ # @rbs () -> Array[Grammar::Symbol]
def compute_first_set
terms.each do |term|
term.first_set = Set.new([term]).freeze
@@ -262,12 +400,14 @@ module Lrama
end
end
+ # @rbs () -> Array[RuleBuilder]
def setup_rules
@rule_builders.each do |builder|
builder.setup_rules
end
end
+ # @rbs () -> Grammar::Symbol
def append_special_symbols
# YYEMPTY (token_id: -2, number: -2) is added when a template is evaluated
# term = add_term(id: Token.new(Token::Ident, "YYEMPTY"), token_id: -2)
@@ -298,11 +438,12 @@ module Lrama
@accept_symbol = term
end
+ # @rbs () -> void
def resolve_inline_rules
while @rule_builders.any?(&:has_inline_rules?) do
@rule_builders = @rule_builders.flat_map do |builder|
if builder.has_inline_rules?
- builder.resolve_inline_rules
+ Inline::Resolver.new(builder).resolve
else
builder
end
@@ -310,14 +451,10 @@ module Lrama
end
end
+ # @rbs () -> void
def normalize_rules
- # Add $accept rule to the top of rules
- rule_builder = @rule_builders.first # : RuleBuilder
- lineno = rule_builder ? rule_builder.line : 0
- @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [rule_builder.lhs, @eof_symbol.id], token_code: nil, lineno: lineno)
-
+ add_accept_rule
setup_rules
-
@rule_builders.each do |builder|
builder.rules.each do |rule|
add_nterm(id: rule._lhs, tag: rule.lhs_tag)
@@ -325,23 +462,42 @@ module Lrama
end
end
- @rules.sort_by!(&:id)
+ nterms.freeze
+ @rules.sort_by!(&:id).freeze
+ end
+
+ # Add $accept rule to the top of rules
+ def add_accept_rule
+ if @start_nterm
+ start = @start_nterm #: Lrama::Lexer::Token::Base
+ @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [start, @eof_symbol.id], token_code: nil, lineno: start.line)
+ else
+ rule_builder = @rule_builders.first #: RuleBuilder
+ lineno = rule_builder ? rule_builder.line : 0
+ lhs = rule_builder.lhs #: Lexer::Token::Base
+ @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [lhs, @eof_symbol.id], token_code: nil, lineno: lineno)
+ end
end
# Collect symbols from rules
+ #
+ # @rbs () -> void
def collect_symbols
@rules.flat_map(&:_rhs).each do |s|
case s
when Lrama::Lexer::Token::Char
add_term(id: s)
- when Lrama::Lexer::Token
+ when Lrama::Lexer::Token::Base
# skip
else
raise "Unknown class: #{s}"
end
end
+
+ terms.freeze
end
+ # @rbs () -> void
def set_lhs_and_rhs
@rules.each do |rule|
rule.lhs = token_to_symbol(rule._lhs) if rule._lhs
@@ -355,6 +511,8 @@ module Lrama
# Rule inherits precedence from the last term in RHS.
#
# https://www.gnu.org/software/bison/manual/html_node/How-Precedence.html
+ #
+ # @rbs () -> void
def fill_default_precedence
@rules.each do |rule|
# Explicitly specified precedence has the highest priority
@@ -369,6 +527,7 @@ module Lrama
end
end
+ # @rbs () -> Array[Grammar::Symbol]
def fill_symbols
fill_symbol_number
fill_nterm_type(@types)
@@ -378,6 +537,7 @@ module Lrama
sort_by_number!
end
+ # @rbs () -> Array[Rule]
def fill_sym_to_rules
@rules.each do |rule|
key = rule.lhs.number
@@ -386,13 +546,48 @@ module Lrama
end
end
+ # @rbs () -> void
+ def validate_no_precedence_for_nterm!
+ errors = [] #: Array[String]
+
+ nterms.each do |nterm|
+ next if nterm.precedence.nil?
+
+ errors << "[BUG] Precedence #{nterm.name} (line: #{nterm.precedence.lineno}) is defined for nonterminal symbol (line: #{nterm.id.first_line}). Precedence can be defined for only terminal symbol."
+ end
+
+ return if errors.empty?
+
+ raise errors.join("\n")
+ end
+
+ # @rbs () -> void
def validate_rule_lhs_is_nterm!
errors = [] #: Array[String]
rules.each do |rule|
next if rule.lhs.nterm?
- errors << "[BUG] LHS of #{rule.display_name} (line: #{rule.lineno}) is term. It should be nterm."
+ errors << "[BUG] LHS of #{rule.display_name} (line: #{rule.lineno}) is terminal symbol. It should be nonterminal symbol."
+ end
+
+ return if errors.empty?
+
+ raise errors.join("\n")
+ end
+
+ # # @rbs () -> void
+ def validate_duplicated_precedence!
+ errors = [] #: Array[String]
+ seen = {} #: Hash[String, Precedence]
+
+ precedences.each do |prec|
+ s_value = prec.s_value
+ if first = seen[s_value]
+ errors << "%#{prec.type} redeclaration for #{s_value} (line: #{prec.lineno}) previous declaration was %#{first.type} (line: #{first.lineno})"
+ else
+ seen[s_value] = prec
+ end
end
return if errors.empty?
@@ -400,6 +595,7 @@ module Lrama
raise errors.join("\n")
end
+ # @rbs () -> void
def set_locations
@locations = @locations || @rules.any? {|rule| rule.contains_at_reference? }
end
diff --git a/tool/lrama/lib/lrama/grammar/auxiliary.rb b/tool/lrama/lib/lrama/grammar/auxiliary.rb
index 2bacee6f1a..76cfb74d4d 100644
--- a/tool/lrama/lib/lrama/grammar/auxiliary.rb
+++ b/tool/lrama/lib/lrama/grammar/auxiliary.rb
@@ -1,9 +1,14 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
# Grammar file information not used by States but by Output
- class Auxiliary < Struct.new(:prologue_first_lineno, :prologue, :epilogue_first_lineno, :epilogue, keyword_init: true)
+ class Auxiliary
+ attr_accessor :prologue_first_lineno #: Integer?
+ attr_accessor :prologue #: String?
+ attr_accessor :epilogue_first_lineno #: Integer?
+ attr_accessor :epilogue #: String?
end
end
end
diff --git a/tool/lrama/lib/lrama/grammar/binding.rb b/tool/lrama/lib/lrama/grammar/binding.rb
index 2efb918a0b..94d00a410e 100644
--- a/tool/lrama/lib/lrama/grammar/binding.rb
+++ b/tool/lrama/lib/lrama/grammar/binding.rb
@@ -4,51 +4,64 @@
module Lrama
class Grammar
class Binding
- # @rbs @actual_args: Array[Lexer::Token]
- # @rbs @param_to_arg: Hash[String, Lexer::Token]
+ # @rbs @actual_args: Array[Lexer::Token::Base]
+ # @rbs @param_to_arg: Hash[String, Lexer::Token::Base]
- # @rbs (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> void
+ # @rbs (Array[Lexer::Token::Base] params, Array[Lexer::Token::Base] actual_args) -> void
def initialize(params, actual_args)
@actual_args = actual_args
- @param_to_arg = map_params_to_args(params, @actual_args)
+ @param_to_arg = build_param_to_arg(params, @actual_args)
end
- # @rbs (Lexer::Token sym) -> Lexer::Token
+ # @rbs (Lexer::Token::Base sym) -> Lexer::Token::Base
def resolve_symbol(sym)
- if sym.is_a?(Lexer::Token::InstantiateRule)
- Lrama::Lexer::Token::InstantiateRule.new(
- s_value: sym.s_value, location: sym.location, args: resolved_args(sym), lhs_tag: sym.lhs_tag
- )
- else
- param_to_arg(sym)
- end
+ return create_instantiate_rule(sym) if sym.is_a?(Lexer::Token::InstantiateRule)
+ find_arg_for_param(sym)
end
# @rbs (Lexer::Token::InstantiateRule token) -> String
def concatenated_args_str(token)
- "#{token.rule_name}_#{token_to_args_s_values(token).join('_')}"
+ "#{token.rule_name}_#{format_args(token)}"
end
private
- # @rbs (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> Hash[String, Lexer::Token]
- def map_params_to_args(params, actual_args)
- params.zip(actual_args).map do |param, arg|
- [param.s_value, arg]
- end.to_h
+ # @rbs (Lexer::Token::InstantiateRule sym) -> Lexer::Token::InstantiateRule
+ def create_instantiate_rule(sym)
+ Lrama::Lexer::Token::InstantiateRule.new(
+ s_value: sym.s_value,
+ alias_name: sym.alias_name,
+ location: sym.location,
+ args: resolve_args(sym.args),
+ lhs_tag: sym.lhs_tag
+ )
end
- # @rbs (Lexer::Token::InstantiateRule sym) -> Array[Lexer::Token]
- def resolved_args(sym)
- sym.args.map { |arg| resolve_symbol(arg) }
+ # @rbs (Array[Lexer::Token::Base]) -> Array[Lexer::Token::Base]
+ def resolve_args(args)
+ args.map { |arg| resolve_symbol(arg) }
end
- # @rbs (Lexer::Token sym) -> Lexer::Token
- def param_to_arg(sym)
- if (arg = @param_to_arg[sym.s_value].dup)
+ # @rbs (Lexer::Token::Base sym) -> Lexer::Token::Base
+ def find_arg_for_param(sym)
+ if (arg = @param_to_arg[sym.s_value]&.dup)
arg.alias_name = sym.alias_name
+ arg
+ else
+ sym
end
- arg || sym
+ end
+
+ # @rbs (Array[Lexer::Token::Base] params, Array[Lexer::Token::Base] actual_args) -> Hash[String, Lexer::Token::Base?]
+ def build_param_to_arg(params, actual_args)
+ params.zip(actual_args).map do |param, arg|
+ [param.s_value, arg]
+ end.to_h
+ end
+
+ # @rbs (Lexer::Token::InstantiateRule token) -> String
+ def format_args(token)
+ token_to_args_s_values(token).join('_')
end
# @rbs (Lexer::Token::InstantiateRule token) -> Array[String]
diff --git a/tool/lrama/lib/lrama/grammar/code.rb b/tool/lrama/lib/lrama/grammar/code.rb
index b6c1cc49e7..f1b860eeba 100644
--- a/tool/lrama/lib/lrama/grammar/code.rb
+++ b/tool/lrama/lib/lrama/grammar/code.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
require "forwardable"
@@ -10,17 +11,28 @@ require_relative "code/rule_action"
module Lrama
class Grammar
class Code
+ # @rbs!
+ #
+ # # delegated
+ # def s_value: -> String
+ # def line: -> Integer
+ # def column: -> Integer
+ # def references: -> Array[Lrama::Grammar::Reference]
+
extend Forwardable
def_delegators "token_code", :s_value, :line, :column, :references
- attr_reader :type, :token_code
+ attr_reader :type #: ::Symbol
+ attr_reader :token_code #: Lexer::Token::UserCode
+ # @rbs (type: ::Symbol, token_code: Lexer::Token::UserCode) -> void
def initialize(type:, token_code:)
@type = type
@token_code = token_code
end
+ # @rbs (Code other) -> bool
def ==(other)
self.class == other.class &&
self.type == other.type &&
@@ -28,6 +40,8 @@ module Lrama
end
# $$, $n, @$, @n are translated to C code
+ #
+ # @rbs () -> String
def translated_code
t_code = s_value.dup
@@ -45,6 +59,7 @@ module Lrama
private
+ # @rbs (Lrama::Grammar::Reference ref) -> bot
def reference_to_c(ref)
raise NotImplementedError.new("#reference_to_c is not implemented")
end
diff --git a/tool/lrama/lib/lrama/grammar/code/destructor_code.rb b/tool/lrama/lib/lrama/grammar/code/destructor_code.rb
index 794017257c..d71b62e513 100644
--- a/tool/lrama/lib/lrama/grammar/code/destructor_code.rb
+++ b/tool/lrama/lib/lrama/grammar/code/destructor_code.rb
@@ -1,9 +1,18 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Code
class DestructorCode < Code
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @tag: Lexer::Token::Tag
+
+ # @rbs (type: ::Symbol, token_code: Lexer::Token::UserCode, tag: Lexer::Token::Tag) -> void
def initialize(type:, token_code:, tag:)
super(type: type, token_code: token_code)
@tag = tag
@@ -17,6 +26,8 @@ module Lrama
# * ($1) error
# * (@1) error
# * ($:1) error
+ #
+ # @rbs (Reference ref) -> (String | bot)
def reference_to_c(ref)
case
when ref.type == :dollar && ref.name == "$" # $$
diff --git a/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb b/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb
index 02f2badc9e..cb36041524 100644
--- a/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb
+++ b/tool/lrama/lib/lrama/grammar/code/initial_action_code.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
@@ -12,6 +13,8 @@ module Lrama
# * ($1) error
# * (@1) error
# * ($:1) error
+ #
+ # @rbs (Reference ref) -> (String | bot)
def reference_to_c(ref)
case
when ref.type == :dollar && ref.name == "$" # $$
diff --git a/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb b/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb
index ab12f32e29..1d39919979 100644
--- a/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb
+++ b/tool/lrama/lib/lrama/grammar/code/no_reference_code.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
@@ -12,6 +13,8 @@ module Lrama
# * ($1) error
# * (@1) error
# * ($:1) error
+ #
+ # @rbs (Reference ref) -> bot
def reference_to_c(ref)
case
when ref.type == :dollar # $$, $n
diff --git a/tool/lrama/lib/lrama/grammar/code/printer_code.rb b/tool/lrama/lib/lrama/grammar/code/printer_code.rb
index c0b8d24306..c6e25d5235 100644
--- a/tool/lrama/lib/lrama/grammar/code/printer_code.rb
+++ b/tool/lrama/lib/lrama/grammar/code/printer_code.rb
@@ -1,9 +1,18 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Code
class PrinterCode < Code
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @tag: Lexer::Token::Tag
+
+ # @rbs (type: ::Symbol, token_code: Lexer::Token::UserCode, tag: Lexer::Token::Tag) -> void
def initialize(type:, token_code:, tag:)
super(type: type, token_code: token_code)
@tag = tag
@@ -17,6 +26,8 @@ module Lrama
# * ($1) error
# * (@1) error
# * ($:1) error
+ #
+ # @rbs (Reference ref) -> (String | bot)
def reference_to_c(ref)
case
when ref.type == :dollar && ref.name == "$" # $$
diff --git a/tool/lrama/lib/lrama/grammar/code/rule_action.rb b/tool/lrama/lib/lrama/grammar/code/rule_action.rb
index 363ecdf25d..24729a1ee0 100644
--- a/tool/lrama/lib/lrama/grammar/code/rule_action.rb
+++ b/tool/lrama/lib/lrama/grammar/code/rule_action.rb
@@ -1,12 +1,23 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Code
class RuleAction < Code
- def initialize(type:, token_code:, rule:)
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @rule: Rule
+ # @grammar: Grammar
+
+ # @rbs (type: ::Symbol, token_code: Lexer::Token::UserCode, rule: Rule, grammar: Grammar) -> void
+ def initialize(type:, token_code:, rule:, grammar:)
super(type: type, token_code: token_code)
@rule = rule
+ @grammar = grammar
end
private
@@ -38,13 +49,21 @@ module Lrama
# "Position in grammar" $1
# "Index for yyvsp" 0
# "$:n" $:1
+ #
+ # @rbs (Reference ref) -> String
def reference_to_c(ref)
case
when ref.type == :dollar && ref.name == "$" # $$
tag = ref.ex_tag || lhs.tag
- raise_tag_not_found_error(ref) unless tag
- # @type var tag: Lexer::Token::Tag
- "(yyval.#{tag.member})"
+ if tag
+ # @type var tag: Lexer::Token::Tag
+ "(yyval.#{tag.member})"
+ elsif union_not_defined?
+ # When %union is not defined, YYSTYPE defaults to int
+ "(yyval)"
+ else
+ raise_tag_not_found_error(ref)
+ end
when ref.type == :at && ref.name == "$" # @$
"(yyloc)"
when ref.type == :index && ref.name == "$" # $:$
@@ -52,9 +71,15 @@ module Lrama
when ref.type == :dollar # $n
i = -position_in_rhs + ref.index
tag = ref.ex_tag || rhs[ref.index - 1].tag
- raise_tag_not_found_error(ref) unless tag
- # @type var tag: Lexer::Token::Tag
- "(yyvsp[#{i}].#{tag.member})"
+ if tag
+ # @type var tag: Lexer::Token::Tag
+ "(yyvsp[#{i}].#{tag.member})"
+ elsif union_not_defined?
+ # When %union is not defined, YYSTYPE defaults to int
+ "(yyvsp[#{i}])"
+ else
+ raise_tag_not_found_error(ref)
+ end
when ref.type == :at # @n
i = -position_in_rhs + ref.index
"(yylsp[#{i}])"
@@ -66,6 +91,7 @@ module Lrama
end
end
+ # @rbs () -> Integer
def position_in_rhs
# If rule is not derived rule, User Code is only action at
# the end of rule RHS. In such case, the action is located on
@@ -74,15 +100,25 @@ module Lrama
end
# If this is midrule action, RHS is an RHS of the original rule.
+ #
+ # @rbs () -> Array[Grammar::Symbol]
def rhs
(@rule.original_rule || @rule).rhs
end
# Unlike `rhs`, LHS is always an LHS of the rule.
+ #
+ # @rbs () -> Grammar::Symbol
def lhs
@rule.lhs
end
+ # @rbs () -> bool
+ def union_not_defined?
+ @grammar.union.nil?
+ end
+
+ # @rbs (Reference ref) -> bot
def raise_tag_not_found_error(ref)
raise "Tag is not specified for '$#{ref.value}' in '#{@rule.display_name}'"
end
diff --git a/tool/lrama/lib/lrama/grammar/counter.rb b/tool/lrama/lib/lrama/grammar/counter.rb
index dc91b87b71..ced934309d 100644
--- a/tool/lrama/lib/lrama/grammar/counter.rb
+++ b/tool/lrama/lib/lrama/grammar/counter.rb
@@ -1,12 +1,22 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Counter
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @number: Integer
+
+ # @rbs (Integer number) -> void
def initialize(number)
@number = number
end
+ # @rbs () -> Integer
def increment
n = @number
@number += 1
diff --git a/tool/lrama/lib/lrama/grammar/destructor.rb b/tool/lrama/lib/lrama/grammar/destructor.rb
index a2b6fde0ed..0ce8611e77 100644
--- a/tool/lrama/lib/lrama/grammar/destructor.rb
+++ b/tool/lrama/lib/lrama/grammar/destructor.rb
@@ -1,8 +1,21 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
- class Destructor < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
+ class Destructor
+ attr_reader :ident_or_tags #: Array[Lexer::Token::Ident|Lexer::Token::Tag]
+ attr_reader :token_code #: Lexer::Token::UserCode
+ attr_reader :lineno #: Integer
+
+ # @rbs (ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag], token_code: Lexer::Token::UserCode, lineno: Integer) -> void
+ def initialize(ident_or_tags:, token_code:, lineno:)
+ @ident_or_tags = ident_or_tags
+ @token_code = token_code
+ @lineno = lineno
+ end
+
+ # @rbs (Lexer::Token::Tag tag) -> String
def translated_code(tag)
Code::DestructorCode.new(type: :destructor, token_code: token_code, tag: tag).translated_code
end
diff --git a/tool/lrama/lib/lrama/grammar/error_token.rb b/tool/lrama/lib/lrama/grammar/error_token.rb
index 50eaafeebc..9d9ed54ae2 100644
--- a/tool/lrama/lib/lrama/grammar/error_token.rb
+++ b/tool/lrama/lib/lrama/grammar/error_token.rb
@@ -1,8 +1,21 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
- class ErrorToken < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
+ class ErrorToken
+ attr_reader :ident_or_tags #: Array[Lexer::Token::Ident | Lexer::Token::Tag]
+ attr_reader :token_code #: Lexer::Token::UserCode
+ attr_reader :lineno #: Integer
+
+ # @rbs (ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag], token_code: Lexer::Token::UserCode, lineno: Integer) -> void
+ def initialize(ident_or_tags:, token_code:, lineno:)
+ @ident_or_tags = ident_or_tags
+ @token_code = token_code
+ @lineno = lineno
+ end
+
+ # @rbs (Lexer::Token::Tag tag) -> String
def translated_code(tag)
Code::PrinterCode.new(type: :error_token, token_code: token_code, tag: tag).translated_code
end
diff --git a/tool/lrama/lib/lrama/grammar/inline.rb b/tool/lrama/lib/lrama/grammar/inline.rb
new file mode 100644
index 0000000000..c02ab6002b
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/inline.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative 'inline/resolver'
diff --git a/tool/lrama/lib/lrama/grammar/inline/resolver.rb b/tool/lrama/lib/lrama/grammar/inline/resolver.rb
new file mode 100644
index 0000000000..aca689ccfb
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/inline/resolver.rb
@@ -0,0 +1,80 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Grammar
+ class Inline
+ class Resolver
+ # @rbs (Lrama::Grammar::RuleBuilder rule_builder) -> void
+ def initialize(rule_builder)
+ @rule_builder = rule_builder
+ end
+
+ # @rbs () -> Array[Lrama::Grammar::RuleBuilder]
+ def resolve
+ resolved_builders = [] #: Array[Lrama::Grammar::RuleBuilder]
+ @rule_builder.rhs.each_with_index do |token, i|
+ if (rule = @rule_builder.parameterized_resolver.find_inline(token))
+ rule.rhs.each do |rhs|
+ builder = build_rule(rhs, token, i, rule)
+ resolved_builders << builder
+ end
+ break
+ end
+ end
+ resolved_builders
+ end
+
+ private
+
+ # @rbs (Lrama::Grammar::Parameterized::Rhs rhs, Lrama::Lexer::Token token, Integer index, Lrama::Grammar::Parameterized::Rule rule) -> Lrama::Grammar::RuleBuilder
+ def build_rule(rhs, token, index, rule)
+ builder = RuleBuilder.new(
+ @rule_builder.rule_counter,
+ @rule_builder.midrule_action_counter,
+ @rule_builder.parameterized_resolver,
+ lhs_tag: @rule_builder.lhs_tag
+ )
+ resolve_rhs(builder, rhs, index, token, rule)
+ builder.lhs = @rule_builder.lhs
+ builder.line = @rule_builder.line
+ builder.precedence_sym = @rule_builder.precedence_sym
+ builder.user_code = replace_user_code(rhs, index)
+ builder
+ end
+
+ # @rbs (Lrama::Grammar::RuleBuilder builder, Lrama::Grammar::Parameterized::Rhs rhs, Integer index, Lrama::Lexer::Token token, Lrama::Grammar::Parameterized::Rule rule) -> void
+ def resolve_rhs(builder, rhs, index, token, rule)
+ @rule_builder.rhs.each_with_index do |tok, i|
+ if i == index
+ rhs.symbols.each do |sym|
+ if token.is_a?(Lexer::Token::InstantiateRule)
+ bindings = Binding.new(rule.parameters, token.args)
+ builder.add_rhs(bindings.resolve_symbol(sym))
+ else
+ builder.add_rhs(sym)
+ end
+ end
+ else
+ builder.add_rhs(tok)
+ end
+ end
+ end
+
+ # @rbs (Lrama::Grammar::Parameterized::Rhs rhs, Integer index) -> Lrama::Lexer::Token::UserCode
+ def replace_user_code(rhs, index)
+ user_code = @rule_builder.user_code
+ return user_code if rhs.user_code.nil? || user_code.nil?
+
+ code = user_code.s_value.gsub(/\$#{index + 1}/, rhs.user_code.s_value)
+ user_code.references.each do |ref|
+ next if ref.index.nil? || ref.index <= index # nil は $$ の場合
+ code = code.gsub(/\$#{ref.index}/, "$#{ref.index + (rhs.symbols.count - 1)}")
+ code = code.gsub(/@#{ref.index}/, "@#{ref.index + (rhs.symbols.count - 1)}")
+ end
+ Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location)
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/grammar/parameterized.rb b/tool/lrama/lib/lrama/grammar/parameterized.rb
new file mode 100644
index 0000000000..48db3433f3
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/parameterized.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+require_relative 'parameterized/resolver'
+require_relative 'parameterized/rhs'
+require_relative 'parameterized/rule'
diff --git a/tool/lrama/lib/lrama/grammar/parameterized/resolver.rb b/tool/lrama/lib/lrama/grammar/parameterized/resolver.rb
new file mode 100644
index 0000000000..558f308190
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/parameterized/resolver.rb
@@ -0,0 +1,73 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Grammar
+ class Parameterized
+ class Resolver
+ attr_accessor :rules #: Array[Rule]
+ attr_accessor :created_lhs_list #: Array[Lexer::Token::Base]
+
+ # @rbs () -> void
+ def initialize
+ @rules = []
+ @created_lhs_list = []
+ end
+
+ # @rbs (Rule rule) -> Array[Rule]
+ def add_rule(rule)
+ @rules << rule
+ end
+
+ # @rbs (Lexer::Token::InstantiateRule token) -> Rule?
+ def find_rule(token)
+ select_rules(@rules, token).last
+ end
+
+ # @rbs (Lexer::Token::Base token) -> Rule?
+ def find_inline(token)
+ @rules.reverse.find { |rule| rule.name == token.s_value && rule.inline? }
+ end
+
+ # @rbs (String lhs_s_value) -> Lexer::Token::Base?
+ def created_lhs(lhs_s_value)
+ @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
+ end
+
+ # @rbs () -> Array[Rule]
+ def redefined_rules
+ @rules.select { |rule| @rules.count { |r| r.name == rule.name && r.required_parameters_count == rule.required_parameters_count } > 1 }
+ end
+
+ private
+
+ # @rbs (Array[Rule] rules, Lexer::Token::InstantiateRule token) -> Array[Rule]
+ def select_rules(rules, token)
+ rules = reject_inline_rules(rules)
+ rules = select_rules_by_name(rules, token.rule_name)
+ rules = rules.select { |rule| rule.required_parameters_count == token.args_count }
+ if rules.empty?
+ raise "Invalid number of arguments. `#{token.rule_name}`"
+ else
+ rules
+ end
+ end
+
+ # @rbs (Array[Rule] rules) -> Array[Rule]
+ def reject_inline_rules(rules)
+ rules.reject(&:inline?)
+ end
+
+ # @rbs (Array[Rule] rules, String rule_name) -> Array[Rule]
+ def select_rules_by_name(rules, rule_name)
+ rules = rules.select { |rule| rule.name == rule_name }
+ if rules.empty?
+ raise "Parameterized rule does not exist. `#{rule_name}`"
+ else
+ rules
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/grammar/parameterized/rhs.rb b/tool/lrama/lib/lrama/grammar/parameterized/rhs.rb
new file mode 100644
index 0000000000..663de49100
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/parameterized/rhs.rb
@@ -0,0 +1,45 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Grammar
+ class Parameterized
+ class Rhs
+ attr_accessor :symbols #: Array[Lexer::Token::Base]
+ attr_accessor :user_code #: Lexer::Token::UserCode?
+ attr_accessor :precedence_sym #: Grammar::Symbol?
+
+ # @rbs () -> void
+ def initialize
+ @symbols = []
+ @user_code = nil
+ @precedence_sym = nil
+ end
+
+ # @rbs (Grammar::Binding bindings) -> Lexer::Token::UserCode?
+ def resolve_user_code(bindings)
+ return unless user_code
+
+ resolved = Lexer::Token::UserCode.new(s_value: user_code.s_value, location: user_code.location)
+ var_to_arg = {} #: Hash[String, String]
+ symbols.each do |sym|
+ resolved_sym = bindings.resolve_symbol(sym)
+ if resolved_sym != sym
+ var_to_arg[sym.s_value] = resolved_sym.s_value
+ end
+ end
+
+ var_to_arg.each do |var, arg|
+ resolved.references.each do |ref|
+ if ref.name == var
+ ref.name = arg
+ end
+ end
+ end
+
+ return resolved
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/grammar/parameterized/rule.rb b/tool/lrama/lib/lrama/grammar/parameterized/rule.rb
new file mode 100644
index 0000000000..7048be3cff
--- /dev/null
+++ b/tool/lrama/lib/lrama/grammar/parameterized/rule.rb
@@ -0,0 +1,36 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Grammar
+ class Parameterized
+ class Rule
+ attr_reader :name #: String
+ attr_reader :parameters #: Array[Lexer::Token::Base]
+ attr_reader :rhs #: Array[Rhs]
+ attr_reader :required_parameters_count #: Integer
+ attr_reader :tag #: Lexer::Token::Tag?
+
+ # @rbs (String name, Array[Lexer::Token::Base] parameters, Array[Rhs] rhs, tag: Lexer::Token::Tag?, is_inline: bool) -> void
+ def initialize(name, parameters, rhs, tag: nil, is_inline: false)
+ @name = name
+ @parameters = parameters
+ @rhs = rhs
+ @tag = tag
+ @is_inline = is_inline
+ @required_parameters_count = parameters.count
+ end
+
+ # @rbs () -> String
+ def to_s
+ "#{@name}(#{@parameters.map(&:s_value).join(', ')})"
+ end
+
+ # @rbs () -> bool
+ def inline?
+ @is_inline
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/grammar/parameterizing_rule.rb b/tool/lrama/lib/lrama/grammar/parameterizing_rule.rb
deleted file mode 100644
index ddc1a467ce..0000000000
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'parameterizing_rule/resolver'
-require_relative 'parameterizing_rule/rhs'
-require_relative 'parameterizing_rule/rule'
diff --git a/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb b/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb
deleted file mode 100644
index 06f2f1cef7..0000000000
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Grammar
- class ParameterizingRule
- class Resolver
- attr_accessor :rules, :created_lhs_list
-
- def initialize
- @rules = []
- @created_lhs_list = []
- end
-
- def add_parameterizing_rule(rule)
- @rules << rule
- end
-
- def find_rule(token)
- select_rules(@rules, token).last
- end
-
- def find_inline(token)
- @rules.reverse.find { |rule| rule.name == token.s_value && rule.is_inline }
- end
-
- def created_lhs(lhs_s_value)
- @created_lhs_list.reverse.find { |created_lhs| created_lhs.s_value == lhs_s_value }
- end
-
- def redefined_rules
- @rules.select { |rule| @rules.count { |r| r.name == rule.name && r.required_parameters_count == rule.required_parameters_count } > 1 }
- end
-
- private
-
- def select_rules(rules, token)
- rules = select_not_inline_rules(rules)
- rules = select_rules_by_name(rules, token.rule_name)
- rules = rules.select { |rule| rule.required_parameters_count == token.args_count }
- if rules.empty?
- raise "Invalid number of arguments. `#{token.rule_name}`"
- else
- rules
- end
- end
-
- def select_not_inline_rules(rules)
- rules.select { |rule| !rule.is_inline }
- end
-
- def select_rules_by_name(rules, rule_name)
- rules = rules.select { |rule| rule.name == rule_name }
- if rules.empty?
- raise "Parameterizing rule does not exist. `#{rule_name}`"
- else
- rules
- end
- end
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb b/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb
deleted file mode 100644
index f60781c053..0000000000
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Grammar
- class ParameterizingRule
- class Rhs
- attr_accessor :symbols, :user_code, :precedence_sym
-
- def initialize
- @symbols = []
- @user_code = nil
- @precedence_sym = nil
- end
-
- def resolve_user_code(bindings)
- return unless user_code
-
- resolved = Lexer::Token::UserCode.new(s_value: user_code.s_value, location: user_code.location)
- var_to_arg = {} #: Hash[String, String]
- symbols.each do |sym|
- resolved_sym = bindings.resolve_symbol(sym)
- if resolved_sym != sym
- var_to_arg[sym.s_value] = resolved_sym.s_value
- end
- end
-
- var_to_arg.each do |var, arg|
- resolved.references.each do |ref|
- if ref.name == var
- ref.name = arg
- end
- end
- end
-
- return resolved
- end
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb b/tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb
deleted file mode 100644
index cc200d2fb6..0000000000
--- a/tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Grammar
- class ParameterizingRule
- class Rule
- attr_reader :name, :parameters, :rhs_list, :required_parameters_count, :tag, :is_inline
-
- def initialize(name, parameters, rhs_list, tag: nil, is_inline: false)
- @name = name
- @parameters = parameters
- @rhs_list = rhs_list
- @tag = tag
- @is_inline = is_inline
- @required_parameters_count = parameters.count
- end
-
- def to_s
- "#{@name}(#{@parameters.map(&:s_value).join(', ')})"
- end
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/grammar/percent_code.rb b/tool/lrama/lib/lrama/grammar/percent_code.rb
index 416a2d2753..9afb903056 100644
--- a/tool/lrama/lib/lrama/grammar/percent_code.rb
+++ b/tool/lrama/lib/lrama/grammar/percent_code.rb
@@ -1,10 +1,21 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class PercentCode
- attr_reader :name, :code
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @name: String
+ # @code: String
+ attr_reader :name #: String
+ attr_reader :code #: String
+
+ # @rbs (String name, String code) -> void
def initialize(name, code)
@name = name
@code = code
diff --git a/tool/lrama/lib/lrama/grammar/precedence.rb b/tool/lrama/lib/lrama/grammar/precedence.rb
index 13cf960c32..b4c6403372 100644
--- a/tool/lrama/lib/lrama/grammar/precedence.rb
+++ b/tool/lrama/lib/lrama/grammar/precedence.rb
@@ -1,13 +1,55 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
- class Precedence < Struct.new(:type, :precedence, keyword_init: true)
+ class Precedence < Struct.new(:type, :symbol, :precedence, :s_value, :lineno, keyword_init: true)
include Comparable
+ # @rbs!
+ # type type_enum = :left | :right | :nonassoc | :precedence
+ #
+ # attr_accessor type: type_enum
+ # attr_accessor symbol: Grammar::Symbol
+ # attr_accessor precedence: Integer
+ # attr_accessor s_value: String
+ # attr_accessor lineno: Integer
+ #
+ # def initialize: (?type: type_enum, ?symbol: Grammar::Symbol, ?precedence: Integer, ?s_value: ::String, ?lineno: Integer) -> void
+ attr_reader :used_by_lalr #: Array[State::ResolvedConflict]
+ attr_reader :used_by_ielr #: Array[State::ResolvedConflict]
+
+ # @rbs (Precedence other) -> Integer
def <=>(other)
self.precedence <=> other.precedence
end
+
+ # @rbs (State::ResolvedConflict resolved_conflict) -> void
+ def mark_used_by_lalr(resolved_conflict)
+ @used_by_lalr ||= [] #: Array[State::ResolvedConflict]
+ @used_by_lalr << resolved_conflict
+ end
+
+ # @rbs (State::ResolvedConflict resolved_conflict) -> void
+ def mark_used_by_ielr(resolved_conflict)
+ @used_by_ielr ||= [] #: Array[State::ResolvedConflict]
+ @used_by_ielr << resolved_conflict
+ end
+
+ # @rbs () -> bool
+ def used_by?
+ used_by_lalr? || used_by_ielr?
+ end
+
+ # @rbs () -> bool
+ def used_by_lalr?
+ !@used_by_lalr.nil? && !@used_by_lalr.empty?
+ end
+
+ # @rbs () -> bool
+ def used_by_ielr?
+ !@used_by_ielr.nil? && !@used_by_ielr.empty?
+ end
end
end
end
diff --git a/tool/lrama/lib/lrama/grammar/printer.rb b/tool/lrama/lib/lrama/grammar/printer.rb
index b78459e819..490fe701db 100644
--- a/tool/lrama/lib/lrama/grammar/printer.rb
+++ b/tool/lrama/lib/lrama/grammar/printer.rb
@@ -1,8 +1,17 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Printer < Struct.new(:ident_or_tags, :token_code, :lineno, keyword_init: true)
+ # @rbs!
+ # attr_accessor ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag]
+ # attr_accessor token_code: Lexer::Token::UserCode
+ # attr_accessor lineno: Integer
+ #
+ # def initialize: (?ident_or_tags: Array[Lexer::Token::Ident|Lexer::Token::Tag], ?token_code: Lexer::Token::UserCode, ?lineno: Integer) -> void
+
+ # @rbs (Lexer::Token::Tag tag) -> String
def translated_code(tag)
Code::PrinterCode.new(type: :printer, token_code: token_code, tag: tag).translated_code
end
diff --git a/tool/lrama/lib/lrama/grammar/reference.rb b/tool/lrama/lib/lrama/grammar/reference.rb
index b044516bdb..7e3badfecc 100644
--- a/tool/lrama/lib/lrama/grammar/reference.rb
+++ b/tool/lrama/lib/lrama/grammar/reference.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
@@ -8,6 +9,18 @@ module Lrama
# index: Integer
# ex_tag: "$<tag>1" (Optional)
class Reference < Struct.new(:type, :name, :number, :index, :ex_tag, :first_column, :last_column, keyword_init: true)
+ # @rbs!
+ # attr_accessor type: ::Symbol
+ # attr_accessor name: String
+ # attr_accessor number: Integer
+ # attr_accessor index: Integer
+ # attr_accessor ex_tag: Lexer::Token::Base?
+ # attr_accessor first_column: Integer
+ # attr_accessor last_column: Integer
+ #
+ # def initialize: (type: ::Symbol, ?name: String, ?number: Integer, ?index: Integer, ?ex_tag: Lexer::Token::Base?, first_column: Integer, last_column: Integer) -> void
+
+ # @rbs () -> (String|Integer)
def value
name || number
end
diff --git a/tool/lrama/lib/lrama/grammar/rule.rb b/tool/lrama/lib/lrama/grammar/rule.rb
index 445752ae0d..b023b0e454 100644
--- a/tool/lrama/lib/lrama/grammar/rule.rb
+++ b/tool/lrama/lib/lrama/grammar/rule.rb
@@ -1,11 +1,38 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
# _rhs holds original RHS element. Use rhs to refer to Symbol.
class Rule < Struct.new(:id, :_lhs, :lhs, :lhs_tag, :_rhs, :rhs, :token_code, :position_in_original_rule_rhs, :nullable, :precedence_sym, :lineno, keyword_init: true)
- attr_accessor :original_rule
+ # @rbs!
+ #
+ # interface _DelegatedMethods
+ # def lhs: -> Grammar::Symbol
+ # def rhs: -> Array[Grammar::Symbol]
+ # end
+ #
+ # attr_accessor id: Integer
+ # attr_accessor _lhs: Lexer::Token::Base
+ # attr_accessor lhs: Grammar::Symbol
+ # attr_accessor lhs_tag: Lexer::Token::Tag?
+ # attr_accessor _rhs: Array[Lexer::Token::Base]
+ # attr_accessor rhs: Array[Grammar::Symbol]
+ # attr_accessor token_code: Lexer::Token::UserCode?
+ # attr_accessor position_in_original_rule_rhs: Integer
+ # attr_accessor nullable: bool
+ # attr_accessor precedence_sym: Grammar::Symbol?
+ # attr_accessor lineno: Integer?
+ #
+ # def initialize: (
+ # ?id: Integer, ?_lhs: Lexer::Token::Base?, ?lhs: Lexer::Token::Base, ?lhs_tag: Lexer::Token::Tag?, ?_rhs: Array[Lexer::Token::Base], ?rhs: Array[Grammar::Symbol],
+ # ?token_code: Lexer::Token::UserCode?, ?position_in_original_rule_rhs: Integer?, ?nullable: bool,
+ # ?precedence_sym: Grammar::Symbol?, ?lineno: Integer?
+ # ) -> void
+ attr_accessor :original_rule #: Rule
+
+ # @rbs (Rule other) -> bool
def ==(other)
self.class == other.class &&
self.lhs == other.lhs &&
@@ -18,12 +45,14 @@ module Lrama
self.lineno == other.lineno
end
+ # @rbs () -> String
def display_name
l = lhs.id.s_value
r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ")
"#{l} -> #{r}"
end
+ # @rbs () -> String
def display_name_without_action
l = lhs.id.s_value
r = empty_rule? ? "ε" : rhs.map do |r|
@@ -33,7 +62,18 @@ module Lrama
"#{l} -> #{r}"
end
+ # @rbs () -> (RailroadDiagrams::Skip | RailroadDiagrams::Sequence)
+ def to_diagrams
+ if rhs.empty?
+ RailroadDiagrams::Skip.new
+ else
+ RailroadDiagrams::Sequence.new(*rhs_to_diagram)
+ end
+ end
+
# Used by #user_actions
+ #
+ # @rbs () -> String
def as_comment
l = lhs.id.s_value
r = empty_rule? ? "%empty" : rhs.map(&:display_name).join(" ")
@@ -41,35 +81,55 @@ module Lrama
"#{l}: #{r}"
end
+ # @rbs () -> String
def with_actions
"#{display_name} {#{token_code&.s_value}}"
end
# opt_nl: ε <-- empty_rule
# | '\n' <-- not empty_rule
+ #
+ # @rbs () -> bool
def empty_rule?
rhs.empty?
end
+ # @rbs () -> Precedence?
def precedence
precedence_sym&.precedence
end
+ # @rbs () -> bool
def initial_rule?
id == 0
end
- def translated_code
+ # @rbs (Grammar grammar) -> String?
+ def translated_code(grammar)
return nil unless token_code
- Code::RuleAction.new(type: :rule_action, token_code: token_code, rule: self).translated_code
+ Code::RuleAction.new(type: :rule_action, token_code: token_code, rule: self, grammar: grammar).translated_code
end
+ # @rbs () -> bool
def contains_at_reference?
return false unless token_code
token_code.references.any? {|r| r.type == :at }
end
+
+ private
+
+ # @rbs () -> Array[(RailroadDiagrams::Terminal | RailroadDiagrams::NonTerminal)]
+ def rhs_to_diagram
+ rhs.map do |r|
+ if r.term
+ RailroadDiagrams::Terminal.new(r.id.s_value)
+ else
+ RailroadDiagrams::NonTerminal.new(r.id.s_value)
+ end
+ end
+ end
end
end
end
diff --git a/tool/lrama/lib/lrama/grammar/rule_builder.rb b/tool/lrama/lib/lrama/grammar/rule_builder.rb
index 481a3780f4..34fdca6c86 100644
--- a/tool/lrama/lib/lrama/grammar/rule_builder.rb
+++ b/tool/lrama/lib/lrama/grammar/rule_builder.rb
@@ -1,15 +1,38 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class RuleBuilder
- attr_accessor :lhs, :line
- attr_reader :lhs_tag, :rhs, :user_code, :precedence_sym
-
- def initialize(rule_counter, midrule_action_counter, parameterizing_rule_resolver, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false)
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @position_in_original_rule_rhs: Integer?
+ # @skip_preprocess_references: bool
+ # @rules: Array[Rule]
+ # @rule_builders_for_parameterized: Array[RuleBuilder]
+ # @rule_builders_for_derived_rules: Array[RuleBuilder]
+ # @parameterized_rules: Array[Rule]
+ # @midrule_action_rules: Array[Rule]
+ # @replaced_rhs: Array[Lexer::Token::Base]?
+
+ attr_accessor :lhs #: Lexer::Token::Base?
+ attr_accessor :line #: Integer?
+ attr_reader :rule_counter #: Counter
+ attr_reader :midrule_action_counter #: Counter
+ attr_reader :parameterized_resolver #: Grammar::Parameterized::Resolver
+ attr_reader :lhs_tag #: Lexer::Token::Tag?
+ attr_reader :rhs #: Array[Lexer::Token::Base]
+ attr_reader :user_code #: Lexer::Token::UserCode?
+ attr_reader :precedence_sym #: Grammar::Symbol?
+
+ # @rbs (Counter rule_counter, Counter midrule_action_counter, Grammar::Parameterized::Resolver parameterized_resolver, ?Integer position_in_original_rule_rhs, ?lhs_tag: Lexer::Token::Tag?, ?skip_preprocess_references: bool) -> void
+ def initialize(rule_counter, midrule_action_counter, parameterized_resolver, position_in_original_rule_rhs = nil, lhs_tag: nil, skip_preprocess_references: false)
@rule_counter = rule_counter
@midrule_action_counter = midrule_action_counter
- @parameterizing_rule_resolver = parameterizing_rule_resolver
+ @parameterized_resolver = parameterized_resolver
@position_in_original_rule_rhs = position_in_original_rule_rhs
@skip_preprocess_references = skip_preprocess_references
@@ -20,12 +43,13 @@ module Lrama
@precedence_sym = nil
@line = nil
@rules = []
- @rule_builders_for_parameterizing_rules = []
+ @rule_builders_for_parameterized = []
@rule_builders_for_derived_rules = []
- @parameterizing_rules = []
+ @parameterized_rules = []
@midrule_action_rules = []
end
+ # @rbs (Lexer::Token::Base rhs) -> void
def add_rhs(rhs)
@line ||= rhs.line
@@ -34,6 +58,7 @@ module Lrama
@rhs << rhs
end
+ # @rbs (Lexer::Token::UserCode? user_code) -> void
def user_code=(user_code)
@line ||= user_code&.line
@@ -42,72 +67,59 @@ module Lrama
@user_code = user_code
end
+ # @rbs (Grammar::Symbol? precedence_sym) -> void
def precedence_sym=(precedence_sym)
flush_user_code
@precedence_sym = precedence_sym
end
+ # @rbs () -> void
def complete_input
freeze_rhs
end
+ # @rbs () -> void
def setup_rules
preprocess_references unless @skip_preprocess_references
process_rhs
+ resolve_inline_rules
build_rules
end
+ # @rbs () -> Array[Grammar::Rule]
def rules
- @parameterizing_rules + @midrule_action_rules + @rules
+ @parameterized_rules + @midrule_action_rules + @rules
end
+ # @rbs () -> bool
def has_inline_rules?
- rhs.any? { |token| @parameterizing_rule_resolver.find_inline(token) }
- end
-
- def resolve_inline_rules
- resolved_builders = [] #: Array[RuleBuilder]
- rhs.each_with_index do |token, i|
- if (inline_rule = @parameterizing_rule_resolver.find_inline(token))
- inline_rule.rhs_list.each do |inline_rhs|
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: lhs_tag)
- if token.is_a?(Lexer::Token::InstantiateRule)
- resolve_inline_rhs(rule_builder, inline_rhs, i, Binding.new(inline_rule.parameters, token.args))
- else
- resolve_inline_rhs(rule_builder, inline_rhs, i)
- end
- rule_builder.lhs = lhs
- rule_builder.line = line
- rule_builder.precedence_sym = precedence_sym
- rule_builder.user_code = replace_inline_user_code(inline_rhs, i)
- resolved_builders << rule_builder
- end
- break
- end
- end
- resolved_builders
+ rhs.any? { |token| @parameterized_resolver.find_inline(token) }
end
private
+ # @rbs () -> void
def freeze_rhs
@rhs.freeze
end
+ # @rbs () -> void
def preprocess_references
numberize_references
end
+ # @rbs () -> void
def build_rules
- tokens = @replaced_rhs
+ tokens = @replaced_rhs #: Array[Lexer::Token::Base]
+ return if tokens.any? { |t| @parameterized_resolver.find_inline(t) }
rule = Rule.new(
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, lhs_tag: lhs_tag, token_code: user_code,
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
)
@rules = [rule]
- @parameterizing_rules = @rule_builders_for_parameterizing_rules.map do |rule_builder|
+ @parameterized_rules = @rule_builders_for_parameterized.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
@@ -120,31 +132,33 @@ module Lrama
# rhs is a mixture of variety type of tokens like `Ident`, `InstantiateRule`, `UserCode` and so on.
# `#process_rhs` replaces some kind of tokens to `Ident` so that all `@replaced_rhs` are `Ident` or `Char`.
+ #
+ # @rbs () -> void
def process_rhs
return if @replaced_rhs
- @replaced_rhs = []
+ replaced_rhs = [] #: Array[Lexer::Token::Base]
rhs.each_with_index do |token, i|
case token
when Lrama::Lexer::Token::Char
- @replaced_rhs << token
+ replaced_rhs << token
when Lrama::Lexer::Token::Ident
- @replaced_rhs << token
+ replaced_rhs << token
when Lrama::Lexer::Token::InstantiateRule
- parameterizing_rule = @parameterizing_rule_resolver.find_rule(token)
- raise "Unexpected token. #{token}" unless parameterizing_rule
+ parameterized_rule = @parameterized_resolver.find_rule(token)
+ raise "Unexpected token. #{token}" unless parameterized_rule
- bindings = Binding.new(parameterizing_rule.parameters, token.args)
+ bindings = Binding.new(parameterized_rule.parameters, token.args)
lhs_s_value = bindings.concatenated_args_str(token)
- if (created_lhs = @parameterizing_rule_resolver.created_lhs(lhs_s_value))
- @replaced_rhs << created_lhs
+ if (created_lhs = @parameterized_resolver.created_lhs(lhs_s_value))
+ replaced_rhs << created_lhs
else
lhs_token = Lrama::Lexer::Token::Ident.new(s_value: lhs_s_value, location: token.location)
- @replaced_rhs << lhs_token
- @parameterizing_rule_resolver.created_lhs_list << lhs_token
- parameterizing_rule.rhs_list.each do |r|
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, lhs_tag: token.lhs_tag || parameterizing_rule.tag)
+ replaced_rhs << lhs_token
+ @parameterized_resolver.created_lhs_list << lhs_token
+ parameterized_rule.rhs.each do |r|
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterized_resolver, lhs_tag: token.lhs_tag || parameterized_rule.tag)
rule_builder.lhs = lhs_token
r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) }
rule_builder.line = line
@@ -152,51 +166,48 @@ module Lrama
rule_builder.user_code = r.resolve_user_code(bindings)
rule_builder.complete_input
rule_builder.setup_rules
- @rule_builders_for_parameterizing_rules << rule_builder
+ @rule_builders_for_parameterized << rule_builder
end
end
when Lrama::Lexer::Token::UserCode
prefix = token.referred ? "@" : "$@"
tag = token.tag || lhs_tag
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
- @replaced_rhs << new_token
+ replaced_rhs << new_token
- rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterizing_rule_resolver, i, lhs_tag: tag, skip_preprocess_references: true)
+ rule_builder = RuleBuilder.new(@rule_counter, @midrule_action_counter, @parameterized_resolver, i, lhs_tag: tag, skip_preprocess_references: true)
rule_builder.lhs = new_token
rule_builder.user_code = token
rule_builder.complete_input
rule_builder.setup_rules
@rule_builders_for_derived_rules << rule_builder
+ when Lrama::Lexer::Token::Empty
+ # Noop
else
raise "Unexpected token. #{token}"
end
end
- end
- def resolve_inline_rhs(rule_builder, inline_rhs, index, bindings = nil)
- rhs.each_with_index do |token, i|
- if index == i
- inline_rhs.symbols.each { |sym| rule_builder.add_rhs(bindings.nil? ? sym : bindings.resolve_symbol(sym)) }
- else
- rule_builder.add_rhs(token)
- end
- end
+ @replaced_rhs = replaced_rhs
end
- def replace_inline_user_code(inline_rhs, index)
- return user_code if inline_rhs.user_code.nil?
- return user_code if user_code.nil?
-
- code = user_code.s_value.gsub(/\$#{index + 1}/, inline_rhs.user_code.s_value)
- user_code.references.each do |ref|
- next if ref.index.nil? || ref.index <= index # nil is a case for `$$`
- code = code.gsub(/\$#{ref.index}/, "$#{ref.index + (inline_rhs.symbols.count-1)}")
- code = code.gsub(/@#{ref.index}/, "@#{ref.index + (inline_rhs.symbols.count-1)}")
+ # @rbs () -> void
+ def resolve_inline_rules
+ while @rule_builders_for_parameterized.any?(&:has_inline_rules?) do
+ @rule_builders_for_parameterized = @rule_builders_for_parameterized.flat_map do |rule_builder|
+ if rule_builder.has_inline_rules?
+ inlined_builders = Inline::Resolver.new(rule_builder).resolve
+ inlined_builders.each { |builder| builder.setup_rules }
+ inlined_builders
+ else
+ rule_builder
+ end
+ end
end
- Lrama::Lexer::Token::UserCode.new(s_value: code, location: user_code.location)
end
+ # @rbs () -> void
def numberize_references
# Bison n'th component is 1-origin
(rhs + [user_code]).compact.each.with_index(1) do |token, i|
@@ -209,7 +220,10 @@ module Lrama
if ref_name == '$'
ref.name = '$'
else
- candidates = ([lhs] + rhs).each_with_index.select {|token, _i| token.referred_by?(ref_name) }
+ candidates = ([lhs] + rhs).each_with_index.select do |token, _i|
+ # @type var token: Lexer::Token::Base
+ token.referred_by?(ref_name)
+ end
if candidates.size >= 2
token.invalid_ref(ref, "Referring symbol `#{ref_name}` is duplicated.")
@@ -244,6 +258,7 @@ module Lrama
end
end
+ # @rbs () -> void
def flush_user_code
if (c = @user_code)
@rhs << c
diff --git a/tool/lrama/lib/lrama/grammar/stdlib.y b/tool/lrama/lib/lrama/grammar/stdlib.y
index d6e89c908c..dd397c9e08 100644
--- a/tool/lrama/lib/lrama/grammar/stdlib.y
+++ b/tool/lrama/lib/lrama/grammar/stdlib.y
@@ -3,26 +3,43 @@
stdlib.y
This is lrama's standard library. It provides a number of
- parameterizing rule definitions, such as options and lists,
+ parameterized rule definitions, such as options and lists,
that should be useful in a number of situations.
**********************************************************************/
+%%
+
// -------------------------------------------------------------------
// Options
/*
- * program: option(number)
+ * program: option(X)
+ *
+ * =>
+ *
+ * program: option_X
+ * option_X: %empty
+ * option_X: X
+ */
+%rule option(X)
+ : /* empty */
+ | X
+ ;
+
+
+/*
+ * program: ioption(X)
*
* =>
*
- * program: option_number
- * option_number: %empty
- * option_number: number
+ * program: %empty
+ * program: X
*/
-%rule option(X): /* empty */
- | X
- ;
+%rule %inline ioption(X)
+ : /* empty */
+ | X
+ ;
// -------------------------------------------------------------------
// Sequences
@@ -35,8 +52,9 @@
* program: preceded_opening_X
* preceded_opening_X: opening X
*/
-%rule preceded(opening, X): opening X { $$ = $2; }
- ;
+%rule preceded(opening, X)
+ : opening X { $$ = $2; }
+ ;
/*
* program: terminated(X, closing)
@@ -46,8 +64,9 @@
* program: terminated_X_closing
* terminated_X_closing: X closing
*/
-%rule terminated(X, closing): X closing { $$ = $1; }
- ;
+%rule terminated(X, closing)
+ : X closing { $$ = $1; }
+ ;
/*
* program: delimited(opening, X, closing)
@@ -57,66 +76,67 @@
* program: delimited_opening_X_closing
* delimited_opening_X_closing: opening X closing
*/
-%rule delimited(opening, X, closing): opening X closing { $$ = $2; }
- ;
+%rule delimited(opening, X, closing)
+ : opening X closing { $$ = $2; }
+ ;
// -------------------------------------------------------------------
// Lists
/*
- * program: list(number)
+ * program: list(X)
*
* =>
*
- * program: list_number
- * list_number: %empty
- * list_number: list_number number
+ * program: list_X
+ * list_X: %empty
+ * list_X: list_X X
*/
-%rule list(X): /* empty */
- | list(X) X
- ;
+%rule list(X)
+ : /* empty */
+ | list(X) X
+ ;
/*
- * program: nonempty_list(number)
+ * program: nonempty_list(X)
*
* =>
*
- * program: nonempty_list_number
- * nonempty_list_number: number
- * nonempty_list_number: nonempty_list_number number
+ * program: nonempty_list_X
+ * nonempty_list_X: X
+ * nonempty_list_X: nonempty_list_X X
*/
-%rule nonempty_list(X): X
- | nonempty_list(X) X
- ;
+%rule nonempty_list(X)
+ : X
+ | nonempty_list(X) X
+ ;
/*
- * program: separated_nonempty_list(comma, number)
+ * program: separated_nonempty_list(separator, X)
*
* =>
*
- * program: separated_nonempty_list_comma_number
- * separated_nonempty_list_comma_number: number
- * separated_nonempty_list_comma_number: separated_nonempty_list_comma_number comma number
+ * program: separated_nonempty_list_separator_X
+ * separated_nonempty_list_separator_X: X
+ * separated_nonempty_list_separator_X: separated_nonempty_list_separator_X separator X
*/
-%rule separated_nonempty_list(separator, X): X
- | separated_nonempty_list(separator, X) separator X
- ;
+%rule separated_nonempty_list(separator, X)
+ : X
+ | separated_nonempty_list(separator, X) separator X
+ ;
/*
- * program: separated_list(comma, number)
+ * program: separated_list(separator, X)
*
* =>
*
- * program: separated_list_comma_number
- * separated_list_comma_number: option_separated_nonempty_list_comma_number
- * option_separated_nonempty_list_comma_number: %empty
- * option_separated_nonempty_list_comma_number: separated_nonempty_list_comma_number
- * separated_nonempty_list_comma_number: number
- * separated_nonempty_list_comma_number: comma separated_nonempty_list_comma_number number
+ * program: separated_list_separator_X
+ * separated_list_separator_X: option_separated_nonempty_list_separator_X
+ * option_separated_nonempty_list_separator_X: %empty
+ * option_separated_nonempty_list_separator_X: separated_nonempty_list_separator_X
+ * separated_nonempty_list_separator_X: X
+ * separated_nonempty_list_separator_X: separator separated_nonempty_list_separator_X X
*/
-%rule separated_list(separator, X): option(separated_nonempty_list(separator, X))
- ;
-
-%%
-
-%union{};
+%rule separated_list(separator, X)
+ : option(separated_nonempty_list(separator, X))
+ ;
diff --git a/tool/lrama/lib/lrama/grammar/symbol.rb b/tool/lrama/lib/lrama/grammar/symbol.rb
index f9dffcad6c..07aee0c0a2 100644
--- a/tool/lrama/lib/lrama/grammar/symbol.rb
+++ b/tool/lrama/lib/lrama/grammar/symbol.rb
@@ -1,19 +1,35 @@
+# rbs_inline: enabled
# frozen_string_literal: true
# Symbol is both of nterm and term
# `number` is both for nterm and term
# `token_id` is tokentype for term, internal sequence number for nterm
#
-# TODO: Add validation for ASCII code range for Token::Char
module Lrama
class Grammar
class Symbol
- attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence,
- :printer, :destructor, :error_token, :first_set, :first_set_bitmap
- attr_reader :term
- attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
+ attr_accessor :id #: Lexer::Token::Base
+ attr_accessor :alias_name #: String?
+ attr_reader :number #: Integer
+ attr_accessor :number_bitmap #: Bitmap::bitmap
+ attr_accessor :tag #: Lexer::Token::Tag?
+ attr_accessor :token_id #: Integer
+ attr_accessor :nullable #: bool
+ attr_accessor :precedence #: Precedence?
+ attr_accessor :printer #: Printer?
+ attr_accessor :destructor #: Destructor?
+ attr_accessor :error_token #: ErrorToken
+ attr_accessor :first_set #: Set[Grammar::Symbol]
+ attr_accessor :first_set_bitmap #: Bitmap::bitmap
+ attr_reader :term #: bool
+ attr_writer :eof_symbol #: bool
+ attr_writer :error_symbol #: bool
+ attr_writer :undef_symbol #: bool
+ attr_writer :accept_symbol #: bool
+ # @rbs (id: Lexer::Token::Base, term: bool, ?alias_name: String?, ?number: Integer?, ?tag: Lexer::Token::Tag?,
+ # ?token_id: Integer?, ?nullable: bool?, ?precedence: Precedence?, ?printer: Printer?) -> void
def initialize(id:, term:, alias_name: nil, number: nil, tag: nil, token_id: nil, nullable: nil, precedence: nil, printer: nil, destructor: nil)
@id = id
@alias_name = alias_name
@@ -27,77 +43,105 @@ module Lrama
@destructor = destructor
end
+ # @rbs (Integer) -> void
+ def number=(number)
+ @number = number
+ @number_bitmap = Bitmap::from_integer(number)
+ end
+
+ # @rbs () -> bool
def term?
term
end
+ # @rbs () -> bool
def nterm?
!term
end
+ # @rbs () -> bool
def eof_symbol?
!!@eof_symbol
end
+ # @rbs () -> bool
def error_symbol?
!!@error_symbol
end
+ # @rbs () -> bool
def undef_symbol?
!!@undef_symbol
end
+ # @rbs () -> bool
def accept_symbol?
!!@accept_symbol
end
+ # @rbs () -> bool
+ def midrule?
+ return false if term?
+
+ name.include?("$") || name.include?("@")
+ end
+
+ # @rbs () -> String
+ def name
+ id.s_value
+ end
+
+ # @rbs () -> String
def display_name
- alias_name || id.s_value
+ alias_name || name
end
# name for yysymbol_kind_t
#
# See: b4_symbol_kind_base
# @type var name: String
+ # @rbs () -> String
def enum_name
case
when accept_symbol?
- name = "YYACCEPT"
+ res = "YYACCEPT"
when eof_symbol?
- name = "YYEOF"
+ res = "YYEOF"
when term? && id.is_a?(Lrama::Lexer::Token::Char)
- name = number.to_s + display_name
+ res = number.to_s + display_name
when term? && id.is_a?(Lrama::Lexer::Token::Ident)
- name = id.s_value
- when nterm? && (id.s_value.include?("$") || id.s_value.include?("@"))
- name = number.to_s + id.s_value
+ res = name
+ when midrule?
+ res = number.to_s + name
when nterm?
- name = id.s_value
+ res = name
else
raise "Unexpected #{self}"
end
- "YYSYMBOL_" + name.gsub(/\W+/, "_")
+ "YYSYMBOL_" + res.gsub(/\W+/, "_")
end
# comment for yysymbol_kind_t
+ #
+ # @rbs () -> String?
def comment
case
when accept_symbol?
# YYSYMBOL_YYACCEPT
- id.s_value
+ name
when eof_symbol?
# YYEOF
alias_name
when (term? && 0 < token_id && token_id < 128)
# YYSYMBOL_3_backslash_, YYSYMBOL_14_
- alias_name || id.s_value
- when id.s_value.include?("$") || id.s_value.include?("@")
+ display_name
+ when midrule?
# YYSYMBOL_21_1
- id.s_value
+ name
else
# YYSYMBOL_keyword_class, YYSYMBOL_strings_1
- alias_name || id.s_value
+ display_name
end
end
end
diff --git a/tool/lrama/lib/lrama/grammar/symbols/resolver.rb b/tool/lrama/lib/lrama/grammar/symbols/resolver.rb
index 52f4ff90bd..085a835d28 100644
--- a/tool/lrama/lib/lrama/grammar/symbols/resolver.rb
+++ b/tool/lrama/lib/lrama/grammar/symbols/resolver.rb
@@ -1,24 +1,54 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Symbols
class Resolver
- attr_reader :terms, :nterms
-
+ # @rbs!
+ #
+ # interface _DelegatedMethods
+ # def symbols: () -> Array[Grammar::Symbol]
+ # def nterms: () -> Array[Grammar::Symbol]
+ # def terms: () -> Array[Grammar::Symbol]
+ # def add_nterm: (id: Lexer::Token::Base, ?alias_name: String?, ?tag: Lexer::Token::Tag?) -> Grammar::Symbol
+ # def add_term: (id: Lexer::Token::Base, ?alias_name: String?, ?tag: Lexer::Token::Tag?, ?token_id: Integer?, ?replace: bool) -> Grammar::Symbol
+ # def find_symbol_by_number!: (Integer number) -> Grammar::Symbol
+ # def find_symbol_by_id!: (Lexer::Token::Base id) -> Grammar::Symbol
+ # def token_to_symbol: (Lexer::Token::Base token) -> Grammar::Symbol
+ # def find_symbol_by_s_value!: (::String s_value) -> Grammar::Symbol
+ # def fill_nterm_type: (Array[Grammar::Type] types) -> void
+ # def fill_symbol_number: () -> void
+ # def fill_printer: (Array[Grammar::Printer] printers) -> void
+ # def fill_destructor: (Array[Destructor] destructors) -> (Destructor | bot)
+ # def fill_error_token: (Array[Grammar::ErrorToken] error_tokens) -> void
+ # def sort_by_number!: () -> Array[Grammar::Symbol]
+ # end
+ #
+ # @symbols: Array[Grammar::Symbol]?
+ # @number: Integer
+ # @used_numbers: Hash[Integer, bool]
+
+ attr_reader :terms #: Array[Grammar::Symbol]
+ attr_reader :nterms #: Array[Grammar::Symbol]
+
+ # @rbs () -> void
def initialize
@terms = []
@nterms = []
end
+ # @rbs () -> Array[Grammar::Symbol]
def symbols
@symbols ||= (@terms + @nterms)
end
+ # @rbs () -> Array[Grammar::Symbol]
def sort_by_number!
symbols.sort_by!(&:number)
end
+ # @rbs (id: Lexer::Token::Base, ?alias_name: String?, ?tag: Lexer::Token::Tag?, ?token_id: Integer?, ?replace: bool) -> Grammar::Symbol
def add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false)
if token_id && (sym = find_symbol_by_token_id(token_id))
if replace
@@ -43,6 +73,7 @@ module Lrama
term
end
+ # @rbs (id: Lexer::Token::Base, ?alias_name: String?, ?tag: Lexer::Token::Tag?) -> Grammar::Symbol
def add_nterm(id:, alias_name: nil, tag: nil)
if (sym = find_symbol_by_id(id))
return sym
@@ -57,32 +88,39 @@ module Lrama
nterm
end
+ # @rbs (::String s_value) -> Grammar::Symbol?
def find_term_by_s_value(s_value)
terms.find { |s| s.id.s_value == s_value }
end
+ # @rbs (::String s_value) -> Grammar::Symbol?
def find_symbol_by_s_value(s_value)
symbols.find { |s| s.id.s_value == s_value }
end
+ # @rbs (::String s_value) -> Grammar::Symbol
def find_symbol_by_s_value!(s_value)
find_symbol_by_s_value(s_value) || (raise "Symbol not found. value: `#{s_value}`")
end
+ # @rbs (Lexer::Token::Base id) -> Grammar::Symbol?
def find_symbol_by_id(id)
symbols.find do |s|
s.id == id || s.alias_name == id.s_value
end
end
+ # @rbs (Lexer::Token::Base id) -> Grammar::Symbol
def find_symbol_by_id!(id)
find_symbol_by_id(id) || (raise "Symbol not found. #{id}")
end
+ # @rbs (Integer token_id) -> Grammar::Symbol?
def find_symbol_by_token_id(token_id)
symbols.find {|s| s.token_id == token_id }
end
+ # @rbs (Integer number) -> Grammar::Symbol
def find_symbol_by_number!(number)
sym = symbols[number]
@@ -92,6 +130,7 @@ module Lrama
sym
end
+ # @rbs () -> void
def fill_symbol_number
# YYEMPTY = -2
# YYEOF = 0
@@ -102,6 +141,7 @@ module Lrama
fill_nterms_number
end
+ # @rbs (Array[Grammar::Type] types) -> void
def fill_nterm_type(types)
types.each do |type|
nterm = find_nterm_by_id!(type.id)
@@ -109,6 +149,7 @@ module Lrama
end
end
+ # @rbs (Array[Grammar::Printer] printers) -> void
def fill_printer(printers)
symbols.each do |sym|
printers.each do |printer|
@@ -126,6 +167,7 @@ module Lrama
end
end
+ # @rbs (Array[Destructor] destructors) -> (Array[Grammar::Symbol] | bot)
def fill_destructor(destructors)
symbols.each do |sym|
destructors.each do |destructor|
@@ -143,6 +185,7 @@ module Lrama
end
end
+ # @rbs (Array[Grammar::ErrorToken] error_tokens) -> void
def fill_error_token(error_tokens)
symbols.each do |sym|
error_tokens.each do |token|
@@ -160,28 +203,33 @@ module Lrama
end
end
+ # @rbs (Lexer::Token::Base token) -> Grammar::Symbol
def token_to_symbol(token)
case token
- when Lrama::Lexer::Token
+ when Lrama::Lexer::Token::Base
find_symbol_by_id!(token)
else
raise "Unknown class: #{token}"
end
end
+ # @rbs () -> void
def validate!
validate_number_uniqueness!
validate_alias_name_uniqueness!
+ validate_symbols!
end
private
+ # @rbs (Lexer::Token::Base id) -> Grammar::Symbol
def find_nterm_by_id!(id)
@nterms.find do |s|
s.id == id
end || (raise "Symbol not found. #{id}")
end
+ # @rbs () -> void
def fill_terms_number
# Character literal in grammar file has
# token id corresponding to ASCII code by default,
@@ -245,6 +293,7 @@ module Lrama
end
end
+ # @rbs () -> void
def fill_nterms_number
token_id = 0
@@ -266,6 +315,7 @@ module Lrama
end
end
+ # @rbs () -> Hash[Integer, bool]
def used_numbers
return @used_numbers if defined?(@used_numbers)
@@ -276,6 +326,7 @@ module Lrama
@used_numbers
end
+ # @rbs () -> void
def validate_number_uniqueness!
invalid = symbols.group_by(&:number).select do |number, syms|
syms.count > 1
@@ -286,6 +337,7 @@ module Lrama
raise "Symbol number is duplicated. #{invalid}"
end
+ # @rbs () -> void
def validate_alias_name_uniqueness!
invalid = symbols.select(&:alias_name).group_by(&:alias_name).select do |alias_name, syms|
syms.count > 1
@@ -295,6 +347,15 @@ module Lrama
raise "Symbol alias name is duplicated. #{invalid}"
end
+
+ # @rbs () -> void
+ def validate_symbols!
+ symbols.each { |sym| sym.id.validate }
+ errors = symbols.map { |sym| sym.id.errors }.flatten.compact
+ return if errors.empty?
+
+ raise errors.join("\n")
+ end
end
end
end
diff --git a/tool/lrama/lib/lrama/grammar/type.rb b/tool/lrama/lib/lrama/grammar/type.rb
index 65537288b3..c631769447 100644
--- a/tool/lrama/lib/lrama/grammar/type.rb
+++ b/tool/lrama/lib/lrama/grammar/type.rb
@@ -1,15 +1,27 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
class Type
- attr_reader :id, :tag
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @id: Lexer::Token::Base
+ # @tag: Lexer::Token::Tag
+ attr_reader :id #: Lexer::Token::Base
+ attr_reader :tag #: Lexer::Token::Tag
+
+ # @rbs (id: Lexer::Token::Base, tag: Lexer::Token::Tag) -> void
def initialize(id:, tag:)
@id = id
@tag = tag
end
+ # @rbs (Grammar::Type other) -> bool
def ==(other)
self.class == other.class &&
self.id == other.id &&
diff --git a/tool/lrama/lib/lrama/grammar/union.rb b/tool/lrama/lib/lrama/grammar/union.rb
index 5f1bee0069..774cc66fc6 100644
--- a/tool/lrama/lib/lrama/grammar/union.rb
+++ b/tool/lrama/lib/lrama/grammar/union.rb
@@ -1,8 +1,19 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class Grammar
- class Union < Struct.new(:code, :lineno, keyword_init: true)
+ class Union
+ attr_reader :code #: Grammar::Code::NoReferenceCode
+ attr_reader :lineno #: Integer
+
+ # @rbs (code: Grammar::Code::NoReferenceCode, lineno: Integer) -> void
+ def initialize(code:, lineno:)
+ @code = code
+ @lineno = lineno
+ end
+
+ # @rbs () -> String
def braces_less_code
# Braces is already removed by lexer
code.s_value
diff --git a/tool/lrama/lib/lrama/grammar_validator.rb b/tool/lrama/lib/lrama/grammar_validator.rb
deleted file mode 100644
index 7790499589..0000000000
--- a/tool/lrama/lib/lrama/grammar_validator.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class GrammarValidator
- def initialize(grammar, states, logger)
- @grammar = grammar
- @states = states
- @logger = logger
- end
-
- def valid?
- conflicts_within_threshold?
- end
-
- private
-
- def conflicts_within_threshold?
- return true unless @grammar.expect
-
- [sr_conflicts_within_threshold(@grammar.expect), rr_conflicts_within_threshold(0)].all?
- end
-
- def sr_conflicts_within_threshold(expected)
- return true if expected == @states.sr_conflicts_count
-
- @logger.error("shift/reduce conflicts: #{@states.sr_conflicts_count} found, #{expected} expected")
- false
- end
-
- def rr_conflicts_within_threshold(expected)
- return true if expected == @states.rr_conflicts_count
-
- @logger.error("reduce/reduce conflicts: #{@states.rr_conflicts_count} found, #{expected} expected")
- false
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/lexer.rb b/tool/lrama/lib/lrama/lexer.rb
index c50af82ae4..ce98b505a7 100644
--- a/tool/lrama/lib/lrama/lexer.rb
+++ b/tool/lrama/lib/lrama/lexer.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
require "strscan"
@@ -8,10 +9,26 @@ require_relative "lexer/token"
module Lrama
class Lexer
- attr_reader :head_line, :head_column, :line
- attr_accessor :status, :end_symbol
-
- SYMBOLS = ['%{', '%}', '%%', '{', '}', '\[', '\]', '\(', '\)', '\,', ':', '\|', ';'].freeze
+ # @rbs!
+ #
+ # type token = lexer_token | c_token
+ #
+ # type lexer_token = [String, Token::Token] |
+ # [::Symbol, Token::Tag] |
+ # [::Symbol, Token::Char] |
+ # [::Symbol, Token::Str] |
+ # [::Symbol, Token::Int] |
+ # [::Symbol, Token::Ident]
+ #
+ # type c_token = [:C_DECLARATION, Token::UserCode]
+
+ attr_reader :head_line #: Integer
+ attr_reader :head_column #: Integer
+ attr_reader :line #: Integer
+ attr_accessor :status #: :initial | :c_declaration
+ attr_accessor :end_symbol #: String?
+
+ SYMBOLS = ['%{', '%}', '%%', '{', '}', '\[', '\]', '\(', '\)', '\,', ':', '\|', ';'].freeze #: Array[String]
PERCENT_TOKENS = %w(
%union
%token
@@ -42,8 +59,11 @@ module Lrama
%no-stdlib
%inline
%locations
- ).freeze
+ %categories
+ %start
+ ).freeze #: Array[String]
+ # @rbs (GrammarFile grammar_file) -> void
def initialize(grammar_file)
@grammar_file = grammar_file
@scanner = StringScanner.new(grammar_file.text)
@@ -53,6 +73,7 @@ module Lrama
@end_symbol = nil
end
+ # @rbs () -> token?
def next_token
case @status
when :initial
@@ -62,10 +83,12 @@ module Lrama
end
end
+ # @rbs () -> Integer
def column
@scanner.pos - @head
end
+ # @rbs () -> Location
def location
Location.new(
grammar_file: @grammar_file,
@@ -74,13 +97,14 @@ module Lrama
)
end
+ # @rbs () -> lexer_token?
def lex_token
until @scanner.eos? do
case
when @scanner.scan(/\n/)
newline
when @scanner.scan(/\s+/)
- # noop
+ @scanner.matched.count("\n").times { newline }
when @scanner.scan(/\/\*/)
lex_comment
when @scanner.scan(/\/\/.*(?<newline>\n)?/)
@@ -96,11 +120,11 @@ module Lrama
when @scanner.eos?
return
when @scanner.scan(/#{SYMBOLS.join('|')}/)
- return [@scanner.matched, @scanner.matched]
+ return [@scanner.matched, Lrama::Lexer::Token::Token.new(s_value: @scanner.matched, location: location)]
when @scanner.scan(/#{PERCENT_TOKENS.join('|')}/)
- return [@scanner.matched, @scanner.matched]
+ return [@scanner.matched, Lrama::Lexer::Token::Token.new(s_value: @scanner.matched, location: location)]
when @scanner.scan(/[\?\+\*]/)
- return [@scanner.matched, @scanner.matched]
+ return [@scanner.matched, Lrama::Lexer::Token::Token.new(s_value: @scanner.matched, location: location)]
when @scanner.scan(/<\w+>/)
return [:TAG, Lrama::Lexer::Token::Tag.new(s_value: @scanner.matched, location: location)]
when @scanner.scan(/'.'/)
@@ -108,9 +132,9 @@ module Lrama
when @scanner.scan(/'\\\\'|'\\b'|'\\t'|'\\f'|'\\r'|'\\n'|'\\v'|'\\13'/)
return [:CHARACTER, Lrama::Lexer::Token::Char.new(s_value: @scanner.matched, location: location)]
when @scanner.scan(/".*?"/)
- return [:STRING, %Q(#{@scanner.matched})]
+ return [:STRING, Lrama::Lexer::Token::Str.new(s_value: %Q(#{@scanner.matched}), location: location)]
when @scanner.scan(/\d+/)
- return [:INTEGER, Integer(@scanner.matched)]
+ return [:INTEGER, Lrama::Lexer::Token::Int.new(s_value: Integer(@scanner.matched), location: location)]
when @scanner.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)/)
token = Lrama::Lexer::Token::Ident.new(s_value: @scanner.matched, location: location)
type =
@@ -121,51 +145,53 @@ module Lrama
end
return [type, token]
else
- raise ParseError, "Unexpected token: #{@scanner.peek(10).chomp}."
+ raise ParseError, location.generate_error_message("Unexpected token") # steep:ignore UnknownConstant
end
end
+ # @rbs () -> c_token
def lex_c_code
nested = 0
- code = ''
+ code = +''
reset_first_position
until @scanner.eos? do
case
when @scanner.scan(/{/)
- code += @scanner.matched
+ code << @scanner.matched
nested += 1
when @scanner.scan(/}/)
if nested == 0 && @end_symbol == '}'
@scanner.unscan
return [:C_DECLARATION, Lrama::Lexer::Token::UserCode.new(s_value: code, location: location)]
else
- code += @scanner.matched
+ code << @scanner.matched
nested -= 1
end
when @scanner.check(/#{@end_symbol}/)
return [:C_DECLARATION, Lrama::Lexer::Token::UserCode.new(s_value: code, location: location)]
when @scanner.scan(/\n/)
- code += @scanner.matched
+ code << @scanner.matched
newline
when @scanner.scan(/".*?"/)
- code += %Q(#{@scanner.matched})
+ code << %Q(#{@scanner.matched})
@line += @scanner.matched.count("\n")
when @scanner.scan(/'.*?'/)
- code += %Q(#{@scanner.matched})
+ code << %Q(#{@scanner.matched})
when @scanner.scan(/[^\"'\{\}\n]+/)
- code += @scanner.matched
- when @scanner.scan(/#{Regexp.escape(@end_symbol)}/)
- code += @scanner.matched
+ code << @scanner.matched
+ when @scanner.scan(/#{Regexp.escape(@end_symbol)}/) # steep:ignore
+ code << @scanner.matched
else
- code += @scanner.getch
+ code << @scanner.getch
end
end
- raise ParseError, "Unexpected code: #{code}."
+ raise ParseError, location.generate_error_message("Unexpected code: #{code}") # steep:ignore UnknownConstant
end
private
+ # @rbs () -> void
def lex_comment
until @scanner.eos? do
case
@@ -178,11 +204,13 @@ module Lrama
end
end
+ # @rbs () -> void
def reset_first_position
@head_line = line
@head_column = column
end
+ # @rbs () -> void
def newline
@line += 1
@head = @scanner.pos
diff --git a/tool/lrama/lib/lrama/lexer/location.rb b/tool/lrama/lib/lrama/lexer/location.rb
index defdbf8a0b..4465576d53 100644
--- a/tool/lrama/lib/lrama/lexer/location.rb
+++ b/tool/lrama/lib/lrama/lexer/location.rb
@@ -69,15 +69,15 @@ module Lrama
def generate_error_message(error_message)
<<~ERROR.chomp
#{path}:#{first_line}:#{first_column}: #{error_message}
- #{line_with_carets}
+ #{error_with_carets}
ERROR
end
# @rbs () -> String
- def line_with_carets
+ def error_with_carets
<<~TEXT
- #{text}
- #{carets}
+ #{formatted_first_lineno} | #{text}
+ #{line_number_padding} | #{carets_line}
TEXT
end
@@ -89,13 +89,30 @@ module Lrama
end
# @rbs () -> String
- def blanks
- (text[0...first_column] or raise "#{first_column} is invalid").gsub(/[^\t]/, ' ')
+ def carets_line
+ leading_whitespace + highlight_marker
end
# @rbs () -> String
- def carets
- blanks + '^' * (last_column - first_column)
+ def leading_whitespace
+ (text[0...first_column] or raise "Invalid first_column: #{first_column}")
+ .gsub(/[^\t]/, ' ')
+ end
+
+ # @rbs () -> String
+ def highlight_marker
+ length = last_column - first_column
+ '^' + '~' * [0, length - 1].max
+ end
+
+ # @rbs () -> String
+ def formatted_first_lineno
+ first_line.to_s.rjust(4)
+ end
+
+ # @rbs () -> String
+ def line_number_padding
+ ' ' * formatted_first_lineno.length
end
# @rbs () -> String
diff --git a/tool/lrama/lib/lrama/lexer/token.rb b/tool/lrama/lib/lrama/lexer/token.rb
index 63da8be4a4..37f77aa069 100644
--- a/tool/lrama/lib/lrama/lexer/token.rb
+++ b/tool/lrama/lib/lrama/lexer/token.rb
@@ -1,70 +1,20 @@
# rbs_inline: enabled
# frozen_string_literal: true
+require_relative 'token/base'
require_relative 'token/char'
+require_relative 'token/empty'
require_relative 'token/ident'
require_relative 'token/instantiate_rule'
+require_relative 'token/int'
+require_relative 'token/str'
require_relative 'token/tag'
+require_relative 'token/token'
require_relative 'token/user_code'
module Lrama
class Lexer
- class Token
- attr_reader :s_value #: String
- attr_reader :location #: Location
- attr_accessor :alias_name #: String
- attr_accessor :referred #: bool
-
- # @rbs (s_value: String, ?alias_name: String, ?location: Location) -> void
- def initialize(s_value:, alias_name: nil, location: nil)
- s_value.freeze
- @s_value = s_value
- @alias_name = alias_name
- @location = location
- end
-
- # @rbs () -> String
- def to_s
- "value: `#{s_value}`, location: #{location}"
- end
-
- # @rbs (String string) -> bool
- def referred_by?(string)
- [self.s_value, self.alias_name].compact.include?(string)
- end
-
- # @rbs (Token other) -> bool
- def ==(other)
- self.class == other.class && self.s_value == other.s_value
- end
-
- # @rbs () -> Integer
- def first_line
- location.first_line
- end
- alias :line :first_line
-
- # @rbs () -> Integer
- def first_column
- location.first_column
- end
- alias :column :first_column
-
- # @rbs () -> Integer
- def last_line
- location.last_line
- end
-
- # @rbs () -> Integer
- def last_column
- location.last_column
- end
-
- # @rbs (Lrama::Grammar::Reference ref, String message) -> bot
- def invalid_ref(ref, message)
- location = self.location.partial_location(ref.first_column, ref.last_column)
- raise location.generate_error_message(message)
- end
+ module Token
end
end
end
diff --git a/tool/lrama/lib/lrama/lexer/token/base.rb b/tool/lrama/lib/lrama/lexer/token/base.rb
new file mode 100644
index 0000000000..3df93bbc73
--- /dev/null
+++ b/tool/lrama/lib/lrama/lexer/token/base.rb
@@ -0,0 +1,73 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Lexer
+ module Token
+ class Base
+ attr_reader :s_value #: String
+ attr_reader :location #: Location
+ attr_accessor :alias_name #: String
+ attr_accessor :referred #: bool
+ attr_reader :errors #: Array[String]
+
+ # @rbs (s_value: String, ?alias_name: String, ?location: Location) -> void
+ def initialize(s_value:, alias_name: nil, location: nil)
+ s_value.freeze
+ @s_value = s_value
+ @alias_name = alias_name
+ @location = location
+ @errors = []
+ end
+
+ # @rbs () -> String
+ def to_s
+ "value: `#{s_value}`, location: #{location}"
+ end
+
+ # @rbs (String string) -> bool
+ def referred_by?(string)
+ [self.s_value, self.alias_name].compact.include?(string)
+ end
+
+ # @rbs (Lexer::Token::Base other) -> bool
+ def ==(other)
+ self.class == other.class && self.s_value == other.s_value
+ end
+
+ # @rbs () -> Integer
+ def first_line
+ location.first_line
+ end
+ alias :line :first_line
+
+ # @rbs () -> Integer
+ def first_column
+ location.first_column
+ end
+ alias :column :first_column
+
+ # @rbs () -> Integer
+ def last_line
+ location.last_line
+ end
+
+ # @rbs () -> Integer
+ def last_column
+ location.last_column
+ end
+
+ # @rbs (Lrama::Grammar::Reference ref, String message) -> bot
+ def invalid_ref(ref, message)
+ location = self.location.partial_location(ref.first_column, ref.last_column)
+ raise location.generate_error_message(message)
+ end
+
+ # @rbs () -> bool
+ def validate
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/lexer/token/char.rb b/tool/lrama/lib/lrama/lexer/token/char.rb
index fcab7a588f..f4ef7c9fbc 100644
--- a/tool/lrama/lib/lrama/lexer/token/char.rb
+++ b/tool/lrama/lib/lrama/lexer/token/char.rb
@@ -3,8 +3,21 @@
module Lrama
class Lexer
- class Token
- class Char < Token
+ module Token
+ class Char < Base
+ # @rbs () -> void
+ def validate
+ validate_ascii_code_range
+ end
+
+ private
+
+ # @rbs () -> void
+ def validate_ascii_code_range
+ unless s_value.ascii_only?
+ errors << "Invalid character: `#{s_value}`. Only ASCII characters are allowed."
+ end
+ end
end
end
end
diff --git a/tool/lrama/lib/lrama/lexer/token/empty.rb b/tool/lrama/lib/lrama/lexer/token/empty.rb
new file mode 100644
index 0000000000..375e256493
--- /dev/null
+++ b/tool/lrama/lib/lrama/lexer/token/empty.rb
@@ -0,0 +1,14 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Lexer
+ module Token
+ class Empty < Base
+ def initialize(location: nil)
+ super(s_value: '%empty', location: location)
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/lexer/token/ident.rb b/tool/lrama/lib/lrama/lexer/token/ident.rb
index 8b1328a040..4880be9073 100644
--- a/tool/lrama/lib/lrama/lexer/token/ident.rb
+++ b/tool/lrama/lib/lrama/lexer/token/ident.rb
@@ -3,8 +3,8 @@
module Lrama
class Lexer
- class Token
- class Ident < Token
+ module Token
+ class Ident < Base
end
end
end
diff --git a/tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb b/tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb
index 37d412aa83..7051ba75a4 100644
--- a/tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb
+++ b/tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb
@@ -3,12 +3,12 @@
module Lrama
class Lexer
- class Token
- class InstantiateRule < Token
- attr_reader :args #: Array[Lexer::Token]
+ module Token
+ class InstantiateRule < Base
+ attr_reader :args #: Array[Lexer::Token::Base]
attr_reader :lhs_tag #: Lexer::Token::Tag?
- # @rbs (s_value: String, ?alias_name: String, ?location: Location, ?args: Array[Lexer::Token], ?lhs_tag: Lexer::Token::Tag?) -> void
+ # @rbs (s_value: String, ?alias_name: String, ?location: Location, ?args: Array[Lexer::Token::Base], ?lhs_tag: Lexer::Token::Tag?) -> void
def initialize(s_value:, alias_name: nil, location: nil, args: [], lhs_tag: nil)
super s_value: s_value, alias_name: alias_name, location: location
@args = args
diff --git a/tool/lrama/lib/lrama/lexer/token/int.rb b/tool/lrama/lib/lrama/lexer/token/int.rb
new file mode 100644
index 0000000000..7daf48d4d3
--- /dev/null
+++ b/tool/lrama/lib/lrama/lexer/token/int.rb
@@ -0,0 +1,14 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Lexer
+ module Token
+ class Int < Base
+ # @rbs!
+ # def initialize: (s_value: Integer, ?alias_name: String, ?location: Location) -> void
+ # def s_value: () -> Integer
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/lexer/token/str.rb b/tool/lrama/lib/lrama/lexer/token/str.rb
new file mode 100644
index 0000000000..cf9de6cf0f
--- /dev/null
+++ b/tool/lrama/lib/lrama/lexer/token/str.rb
@@ -0,0 +1,11 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Lexer
+ module Token
+ class Str < Base
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/lexer/token/tag.rb b/tool/lrama/lib/lrama/lexer/token/tag.rb
index b346ef7c5c..68c6268219 100644
--- a/tool/lrama/lib/lrama/lexer/token/tag.rb
+++ b/tool/lrama/lib/lrama/lexer/token/tag.rb
@@ -3,8 +3,8 @@
module Lrama
class Lexer
- class Token
- class Tag < Token
+ module Token
+ class Tag < Base
# @rbs () -> String
def member
# Omit "<>"
diff --git a/tool/lrama/lib/lrama/lexer/token/token.rb b/tool/lrama/lib/lrama/lexer/token/token.rb
new file mode 100644
index 0000000000..935797efc6
--- /dev/null
+++ b/tool/lrama/lib/lrama/lexer/token/token.rb
@@ -0,0 +1,11 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Lexer
+ module Token
+ class Token < Base
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/lexer/token/user_code.rb b/tool/lrama/lib/lrama/lexer/token/user_code.rb
index 4ef40e6dc8..166f04954a 100644
--- a/tool/lrama/lib/lrama/lexer/token/user_code.rb
+++ b/tool/lrama/lib/lrama/lexer/token/user_code.rb
@@ -5,8 +5,8 @@ require "strscan"
module Lrama
class Lexer
- class Token
- class UserCode < Token
+ module Token
+ class UserCode < Base
attr_accessor :tag #: Lexer::Token::Tag
# @rbs () -> Array[Lrama::Grammar::Reference]
@@ -38,43 +38,69 @@ module Lrama
# @rbs (StringScanner scanner) -> Lrama::Grammar::Reference?
def scan_reference(scanner)
start = scanner.pos
- case
- # $ references
- # It need to wrap an identifier with brackets to use ".-" for identifiers
- when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $<long>$
- tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
- return Lrama::Grammar::Reference.new(type: :dollar, name: "$", ex_tag: tag, first_column: start, last_column: scanner.pos)
- when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $<long>1
- tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
- return Lrama::Grammar::Reference.new(type: :dollar, number: Integer(scanner[2]), index: Integer(scanner[2]), ex_tag: tag, first_column: start, last_column: scanner.pos)
- when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_][a-zA-Z0-9_]*)/) # $foo, $expr, $<long>program (named reference without brackets)
- tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
- return Lrama::Grammar::Reference.new(type: :dollar, name: scanner[2], ex_tag: tag, first_column: start, last_column: scanner.pos)
- when scanner.scan(/\$(<[a-zA-Z0-9_]+>)?\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # $[expr.right], $[expr-right], $<long>[expr.right] (named reference with brackets)
- tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
- return Lrama::Grammar::Reference.new(type: :dollar, name: scanner[2], ex_tag: tag, first_column: start, last_column: scanner.pos)
-
- # @ references
- # It need to wrap an identifier with brackets to use ".-" for identifiers
- when scanner.scan(/@\$/) # @$
- return Lrama::Grammar::Reference.new(type: :at, name: "$", first_column: start, last_column: scanner.pos)
- when scanner.scan(/@(\d+)/) # @1
- return Lrama::Grammar::Reference.new(type: :at, number: Integer(scanner[1]), index: Integer(scanner[1]), first_column: start, last_column: scanner.pos)
- when scanner.scan(/@([a-zA-Z][a-zA-Z0-9_]*)/) # @foo, @expr (named reference without brackets)
- return Lrama::Grammar::Reference.new(type: :at, name: scanner[1], first_column: start, last_column: scanner.pos)
- when scanner.scan(/@\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # @[expr.right], @[expr-right] (named reference with brackets)
- return Lrama::Grammar::Reference.new(type: :at, name: scanner[1], first_column: start, last_column: scanner.pos)
+ if scanner.scan(/
+ # $ references
+ # It need to wrap an identifier with brackets to use ".-" for identifiers
+ \$(<[a-zA-Z0-9_]+>)?(?:
+ (\$) # $$, $<long>$
+ | (\d+) # $1, $2, $<long>1
+ | ([a-zA-Z_][a-zA-Z0-9_]*) # $foo, $expr, $<long>program (named reference without brackets)
+ | \[([a-zA-Z_.][-a-zA-Z0-9_.]*)\] # $[expr.right], $[expr-right], $<long>[expr.right] (named reference with brackets)
+ )
+ |
+ # @ references
+ # It need to wrap an identifier with brackets to use ".-" for identifiers
+ @(?:
+ (\$) # @$
+ | (\d+) # @1
+ | ([a-zA-Z_][a-zA-Z0-9_]*) # @foo, @expr (named reference without brackets)
+ | \[([a-zA-Z_.][-a-zA-Z0-9_.]*)\] # @[expr.right], @[expr-right] (named reference with brackets)
+ )
+ |
+ # $: references
+ \$:
+ (?:
+ (\$) # $:$
+ | (\d+) # $:1
+ | ([a-zA-Z_][a-zA-Z0-9_]*) # $:foo, $:expr (named reference without brackets)
+ | \[([a-zA-Z_.][-a-zA-Z0-9_.]*)\] # $:[expr.right], $:[expr-right] (named reference with brackets)
+ )
+ /x)
+ case
+ # $ references
+ when scanner[2] # $$, $<long>$
+ tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
+ return Lrama::Grammar::Reference.new(type: :dollar, name: "$", ex_tag: tag, first_column: start, last_column: scanner.pos)
+ when scanner[3] # $1, $2, $<long>1
+ tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
+ return Lrama::Grammar::Reference.new(type: :dollar, number: Integer(scanner[3]), index: Integer(scanner[3]), ex_tag: tag, first_column: start, last_column: scanner.pos)
+ when scanner[4] # $foo, $expr, $<long>program (named reference without brackets)
+ tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
+ return Lrama::Grammar::Reference.new(type: :dollar, name: scanner[4], ex_tag: tag, first_column: start, last_column: scanner.pos)
+ when scanner[5] # $[expr.right], $[expr-right], $<long>[expr.right] (named reference with brackets)
+ tag = scanner[1] ? Lrama::Lexer::Token::Tag.new(s_value: scanner[1]) : nil
+ return Lrama::Grammar::Reference.new(type: :dollar, name: scanner[5], ex_tag: tag, first_column: start, last_column: scanner.pos)
- # $: references
- when scanner.scan(/\$:\$/) # $:$
- return Lrama::Grammar::Reference.new(type: :index, name: "$", first_column: start, last_column: scanner.pos)
- when scanner.scan(/\$:(\d+)/) # $:1
- return Lrama::Grammar::Reference.new(type: :index, number: Integer(scanner[1]), first_column: start, last_column: scanner.pos)
- when scanner.scan(/\$:([a-zA-Z_][a-zA-Z0-9_]*)/) # $:foo, $:expr (named reference without brackets)
- return Lrama::Grammar::Reference.new(type: :index, name: scanner[1], first_column: start, last_column: scanner.pos)
- when scanner.scan(/\$:\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # $:[expr.right], $:[expr-right] (named reference with brackets)
- return Lrama::Grammar::Reference.new(type: :index, name: scanner[1], first_column: start, last_column: scanner.pos)
+ # @ references
+ when scanner[6] # @$
+ return Lrama::Grammar::Reference.new(type: :at, name: "$", first_column: start, last_column: scanner.pos)
+ when scanner[7] # @1
+ return Lrama::Grammar::Reference.new(type: :at, number: Integer(scanner[7]), index: Integer(scanner[7]), first_column: start, last_column: scanner.pos)
+ when scanner[8] # @foo, @expr (named reference without brackets)
+ return Lrama::Grammar::Reference.new(type: :at, name: scanner[8], first_column: start, last_column: scanner.pos)
+ when scanner[9] # @[expr.right], @[expr-right] (named reference with brackets)
+ return Lrama::Grammar::Reference.new(type: :at, name: scanner[9], first_column: start, last_column: scanner.pos)
+ # $: references
+ when scanner[10] # $:$
+ return Lrama::Grammar::Reference.new(type: :index, name: "$", first_column: start, last_column: scanner.pos)
+ when scanner[11] # $:1
+ return Lrama::Grammar::Reference.new(type: :index, number: Integer(scanner[11]), index: Integer(scanner[11]), first_column: start, last_column: scanner.pos)
+ when scanner[12] # $:foo, $:expr (named reference without brackets)
+ return Lrama::Grammar::Reference.new(type: :index, name: scanner[12], first_column: start, last_column: scanner.pos)
+ when scanner[13] # $:[expr.right], $:[expr-right] (named reference with brackets)
+ return Lrama::Grammar::Reference.new(type: :index, name: scanner[13], first_column: start, last_column: scanner.pos)
+ end
end
end
end
diff --git a/tool/lrama/lib/lrama/logger.rb b/tool/lrama/lib/lrama/logger.rb
index 88bb920960..291eea5296 100644
--- a/tool/lrama/lib/lrama/logger.rb
+++ b/tool/lrama/lib/lrama/logger.rb
@@ -8,14 +8,24 @@ module Lrama
@out = out
end
+ # @rbs () -> void
+ def line_break
+ @out << "\n"
+ end
+
# @rbs (String message) -> void
- def warn(message)
+ def trace(message)
@out << message << "\n"
end
# @rbs (String message) -> void
+ def warn(message)
+ @out << 'warning: ' << message << "\n"
+ end
+
+ # @rbs (String message) -> void
def error(message)
- @out << message << "\n"
+ @out << 'error: ' << message << "\n"
end
end
end
diff --git a/tool/lrama/lib/lrama/option_parser.rb b/tool/lrama/lib/lrama/option_parser.rb
index 23988a5fbb..5a15d59c7b 100644
--- a/tool/lrama/lib/lrama/option_parser.rb
+++ b/tool/lrama/lib/lrama/option_parser.rb
@@ -1,3 +1,4 @@
+# rbs_inline: enabled
# frozen_string_literal: true
require 'optparse'
@@ -5,17 +6,32 @@ require 'optparse'
module Lrama
# Handle option parsing for the command line interface.
class OptionParser
+ # @rbs!
+ # @options: Lrama::Options
+ # @trace: Array[String]
+ # @report: Array[String]
+ # @profile: Array[String]
+
+ # @rbs (Array[String]) -> Lrama::Options
+ def self.parse(argv)
+ new.parse(argv)
+ end
+
+ # @rbs () -> void
def initialize
@options = Options.new
@trace = []
@report = []
+ @profile = []
end
+ # @rbs (Array[String]) -> Lrama::Options
def parse(argv)
parse_by_option_parser(argv)
@options.trace_opts = validate_trace(@trace)
@options.report_opts = validate_report(@report)
+ @options.profile_opts = validate_profile(@profile)
@options.grammar_file = argv.shift
unless @options.grammar_file
@@ -46,6 +62,7 @@ module Lrama
private
+ # @rbs (Array[String]) -> void
def parse_by_option_parser(argv)
::OptionParser.new do |o|
o.banner = <<~BANNER
@@ -60,7 +77,14 @@ module Lrama
o.separator 'Tuning the Parser:'
o.on('-S', '--skeleton=FILE', 'specify the skeleton to use') {|v| @options.skeleton = v }
o.on('-t', '--debug', 'display debugging outputs of internal parser') {|v| @options.debug = true }
- o.on('-D', '--define=NAME[=VALUE]', Array, "similar to '%define NAME VALUE'") {|v| @options.define = v }
+ o.separator " same as '-Dparse.trace'"
+ o.on('--locations', 'enable location support') {|v| @options.locations = true }
+ o.on('-D', '--define=NAME[=VALUE]', Array, "similar to '%define NAME VALUE'") do |v|
+ @options.define = v.each_with_object({}) do |item, hash| # steep:ignore UnannotatedEmptyCollection
+ key, value = item.split('=', 2)
+ hash[key] = value
+ end
+ end
o.separator ''
o.separator 'Output:'
o.on('-H', '--header=[FILE]', 'also produce a header file named FILE') {|v| @options.header = true; @options.header_file = v }
@@ -91,10 +115,19 @@ module Lrama
o.on_tail ' time display generation time'
o.on_tail ' all include all the above traces'
o.on_tail ' none disable all traces'
+ o.on('--diagram=[FILE]', 'generate a diagram of the rules') do |v|
+ @options.diagram = true
+ @options.diagram_file = v if v
+ end
+ o.on('--profile=PROFILES', Array, 'profiles parser generation parts') {|v| @profile = v }
+ o.on_tail ''
+ o.on_tail 'PROFILES is a list of comma-separated words that can include:'
+ o.on_tail ' call-stack use sampling call-stack profiler (stackprof gem)'
+ o.on_tail ' memory use memory profiler (memory_profiler gem)'
o.on('-v', '--verbose', "same as '--report=state'") {|_v| @report << 'states' }
o.separator ''
o.separator 'Diagnostics:'
- o.on('-W', '--warnings', 'report the warnings') {|v| @options.diagnostic = true }
+ o.on('-W', '--warnings', 'report the warnings') {|v| @options.warnings = true }
o.separator ''
o.separator 'Error Recovery:'
o.on('-e', 'enable error recovery') {|v| @options.error_recovery = true }
@@ -107,9 +140,10 @@ module Lrama
end
end
- ALIASED_REPORTS = { cex: :counterexamples }.freeze
- VALID_REPORTS = %i[states itemsets lookaheads solved counterexamples rules terms verbose].freeze
+ ALIASED_REPORTS = { cex: :counterexamples }.freeze #: Hash[Symbol, Symbol]
+ VALID_REPORTS = %i[states itemsets lookaheads solved counterexamples rules terms verbose].freeze #: Array[Symbol]
+ # @rbs (Array[String]) -> Hash[Symbol, bool]
def validate_report(report)
h = { grammar: true }
return h if report.empty?
@@ -131,6 +165,7 @@ module Lrama
return h
end
+ # @rbs (String) -> Symbol
def aliased_report_option(opt)
(ALIASED_REPORTS[opt.to_sym] || opt).to_sym
end
@@ -139,15 +174,16 @@ module Lrama
locations scan parse automaton bitsets closure
grammar rules only-explicit-rules actions resource
sets muscles tools m4-early m4 skeleton time ielr cex
- ].freeze
+ ].freeze #: Array[String]
NOT_SUPPORTED_TRACES = %w[
locations scan parse bitsets grammar resource
sets muscles tools m4-early m4 skeleton ielr cex
- ].freeze
- SUPPORTED_TRACES = VALID_TRACES - NOT_SUPPORTED_TRACES
+ ].freeze #: Array[String]
+ SUPPORTED_TRACES = VALID_TRACES - NOT_SUPPORTED_TRACES #: Array[String]
+ # @rbs (Array[String]) -> Hash[Symbol, bool]
def validate_trace(trace)
- h = {}
+ h = {} #: Hash[Symbol, bool]
return h if trace.empty? || trace == ['none']
all_traces = SUPPORTED_TRACES - %w[only-explicit-rules]
if trace == ['all']
@@ -159,7 +195,25 @@ module Lrama
if SUPPORTED_TRACES.include?(t)
h[t.gsub(/-/, '_').to_sym] = true
else
- raise "Invalid trace option \"#{t}\"."
+ raise "Invalid trace option \"#{t}\".\nValid options are [#{SUPPORTED_TRACES.join(", ")}]."
+ end
+ end
+
+ return h
+ end
+
+ VALID_PROFILES = %w[call-stack memory].freeze #: Array[String]
+
+ # @rbs (Array[String]) -> Hash[Symbol, bool]
+ def validate_profile(profile)
+ h = {} #: Hash[Symbol, bool]
+ return h if profile.empty?
+
+ profile.each do |t|
+ if VALID_PROFILES.include?(t)
+ h[t.gsub(/-/, '_').to_sym] = true
+ else
+ raise "Invalid profile option \"#{t}\".\nValid options are [#{VALID_PROFILES.join(", ")}]."
end
end
diff --git a/tool/lrama/lib/lrama/options.rb b/tool/lrama/lib/lrama/options.rb
index 08f75a770f..87aec62448 100644
--- a/tool/lrama/lib/lrama/options.rb
+++ b/tool/lrama/lib/lrama/options.rb
@@ -1,28 +1,46 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
# Command line options.
class Options
- attr_accessor :skeleton, :header, :header_file,
- :report_file, :outfile,
- :error_recovery, :grammar_file,
- :trace_opts, :report_opts,
- :diagnostic, :y, :debug, :define
+ attr_accessor :skeleton #: String
+ attr_accessor :locations #: bool
+ attr_accessor :header #: bool
+ attr_accessor :header_file #: String?
+ attr_accessor :report_file #: String?
+ attr_accessor :outfile #: String
+ attr_accessor :error_recovery #: bool
+ attr_accessor :grammar_file #: String
+ attr_accessor :trace_opts #: Hash[Symbol, bool]?
+ attr_accessor :report_opts #: Hash[Symbol, bool]?
+ attr_accessor :warnings #: bool
+ attr_accessor :y #: IO
+ attr_accessor :debug #: bool
+ attr_accessor :define #: Hash[String, String]
+ attr_accessor :diagram #: bool
+ attr_accessor :diagram_file #: String
+ attr_accessor :profile_opts #: Hash[Symbol, bool]?
+ # @rbs () -> void
def initialize
@skeleton = "bison/yacc.c"
+ @locations = false
@define = {}
@header = false
@header_file = nil
@report_file = nil
@outfile = "y.tab.c"
@error_recovery = false
- @grammar_file = nil
+ @grammar_file = ''
@trace_opts = nil
@report_opts = nil
- @diagnostic = false
+ @warnings = false
@y = STDIN
@debug = false
+ @diagram = false
+ @diagram_file = "diagram.html"
+ @profile_opts = nil
end
end
end
diff --git a/tool/lrama/lib/lrama/output.rb b/tool/lrama/lib/lrama/output.rb
index 3c7316ac6d..24cf725c77 100644
--- a/tool/lrama/lib/lrama/output.rb
+++ b/tool/lrama/lib/lrama/output.rb
@@ -1,13 +1,12 @@
# frozen_string_literal: true
-require "erb"
require "forwardable"
-require_relative "report/duration"
+require_relative "tracer/duration"
module Lrama
class Output
extend Forwardable
- include Report::Duration
+ include Tracer::Duration
attr_reader :grammar_file_path, :context, :grammar, :error_recovery, :include_header
@@ -43,7 +42,7 @@ module Lrama
end
def render_partial(file)
- render_template(partial_file(file))
+ ERB.render(partial_file(file), context: @context, output: self)
end
def render
@@ -247,7 +246,7 @@ module Lrama
<<-STR
case #{rule.id + 1}: /* #{rule.as_comment} */
#line #{code.line} "#{@grammar_file_path}"
-#{spaces}{#{rule.translated_code}}
+#{spaces}{#{rule.translated_code(@grammar)}}
#line [@oline@] [@ofile@]
break;
@@ -405,16 +404,10 @@ module Lrama
private
def eval_template(file, path)
- tmp = render_template(file)
+ tmp = ERB.render(file, context: @context, output: self)
replace_special_variables(tmp, path)
end
- def render_template(file)
- erb = self.class.erb(File.read(file))
- erb.filename = file
- erb.result_with_hash(context: @context, output: self)
- end
-
def template_file
File.join(template_dir, @template_name)
end
diff --git a/tool/lrama/lib/lrama/parser.rb b/tool/lrama/lib/lrama/parser.rb
index 177e784e5c..04632cbae0 100644
--- a/tool/lrama/lib/lrama/parser.rb
+++ b/tool/lrama/lib/lrama/parser.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
#
# DO NOT MODIFY!!!!
# This file is automatically generated by Racc 1.8.1
@@ -654,22 +655,25 @@ end
module Lrama
class Parser < Racc::Parser
-module_eval(<<'...end parser.y/module_eval...', 'parser.y', 428)
+module_eval(<<'...end parser.y/module_eval...', 'parser.y', 505)
-include Lrama::Report::Duration
+include Lrama::Tracer::Duration
-def initialize(text, path, debug = false, define = {})
+def initialize(text, path, debug = false, locations = false, define = {})
+ @path = path
@grammar_file = Lrama::Lexer::GrammarFile.new(path, text)
- @yydebug = debug
+ @yydebug = debug || define.key?('parse.trace')
@rule_counter = Lrama::Grammar::Counter.new(0)
@midrule_action_counter = Lrama::Grammar::Counter.new(1)
+ @locations = locations
@define = define
end
def parse
- report_duration(:parse) do
+ message = "parse '#{File.basename(@path)}'"
+ report_duration(message) do
@lexer = Lrama::Lexer.new(@grammar_file)
- @grammar = Lrama::Grammar.new(@rule_counter, @define)
+ @grammar = Lrama::Grammar.new(@rule_counter, @locations, @define)
@precedence_number = 0
reset_precs
do_parse
@@ -682,7 +686,14 @@ def next_token
end
def on_error(error_token_id, error_value, value_stack)
- if error_value.is_a?(Lrama::Lexer::Token)
+ case error_value
+ when Lrama::Lexer::Token::Int
+ location = error_value.location
+ value = "#{error_value.s_value}"
+ when Lrama::Lexer::Token::Token
+ location = error_value.location
+ value = "\"#{error_value.s_value}\""
+ when Lrama::Lexer::Token::Base
location = error_value.location
value = "'#{error_value.s_value}'"
else
@@ -696,7 +707,7 @@ def on_error(error_token_id, error_value, value_stack)
end
def on_action_error(error_message, error_value)
- if error_value.is_a?(Lrama::Lexer::Token)
+ if error_value.is_a?(Lrama::Lexer::Token::Base)
location = error_value.location
else
location = @lexer.location
@@ -708,10 +719,15 @@ end
private
def reset_precs
- @prec_seen = false
+ @opening_prec_seen = false
+ @trailing_prec_seen = false
@code_after_prec = false
end
+def prec_seen?
+ @opening_prec_seen || @trailing_prec_seen
+end
+
def begin_c_declaration(end_symbol)
@lexer.status = :c_declaration
@lexer.end_symbol = end_symbol
@@ -729,306 +745,325 @@ end
##### State transition tables begin ###
racc_action_table = [
- 89, 49, 90, 167, 49, 101, 173, 49, 101, 167,
- 49, 101, 173, 6, 101, 80, 49, 49, 48, 48,
- 41, 76, 76, 49, 49, 48, 48, 42, 76, 76,
- 49, 49, 48, 48, 101, 96, 113, 49, 87, 48,
- 150, 101, 96, 151, 45, 171, 169, 170, 151, 176,
- 170, 91, 169, 170, 81, 176, 170, 20, 24, 25,
- 26, 27, 28, 29, 30, 31, 87, 32, 33, 34,
- 35, 36, 37, 38, 39, 49, 4, 48, 5, 101,
- 96, 181, 182, 183, 128, 20, 24, 25, 26, 27,
- 28, 29, 30, 31, 46, 32, 33, 34, 35, 36,
- 37, 38, 39, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 53, 20, 24, 25, 26, 27, 28, 29,
- 30, 31, 53, 32, 33, 34, 35, 36, 37, 38,
- 39, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- 44, 20, 24, 25, 26, 27, 28, 29, 30, 31,
- 53, 32, 33, 34, 35, 36, 37, 38, 39, 49,
- 4, 48, 5, 101, 96, 49, 49, 48, 48, 101,
- 101, 49, 49, 48, 48, 101, 101, 49, 49, 48,
- 197, 101, 101, 49, 49, 197, 48, 101, 101, 49,
- 49, 197, 48, 101, 181, 182, 183, 128, 204, 210,
- 217, 205, 205, 205, 49, 49, 48, 48, 49, 49,
- 48, 48, 49, 49, 48, 48, 181, 182, 183, 116,
- 117, 56, 53, 53, 53, 53, 53, 62, 63, 64,
- 65, 66, 68, 68, 68, 82, 53, 53, 104, 108,
- 108, 115, 122, 123, 125, 128, 129, 133, 139, 140,
- 141, 142, 144, 145, 101, 154, 139, 157, 154, 161,
- 162, 68, 164, 165, 172, 177, 154, 184, 128, 188,
- 154, 190, 128, 154, 199, 154, 128, 68, 165, 206,
- 165, 68, 68, 215, 128, 68 ]
+ 98, 98, 99, 99, 87, 53, 53, 52, 178, 110,
+ 110, 97, 53, 53, 184, 178, 110, 110, 53, 181,
+ 184, 162, 110, 6, 163, 181, 181, 53, 53, 52,
+ 52, 181, 79, 79, 53, 53, 52, 52, 43, 79,
+ 79, 53, 4, 52, 5, 110, 88, 94, 182, 125,
+ 126, 163, 100, 100, 180, 193, 194, 195, 137, 185,
+ 188, 180, 4, 44, 5, 185, 188, 94, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 46, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 47, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 47, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 12, 13, 50,
+ 57, 14, 15, 16, 17, 18, 19, 20, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 57, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 12, 13, 57,
+ 60, 14, 15, 16, 17, 18, 19, 20, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 57, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 53, 53, 52,
+ 52, 110, 105, 53, 53, 52, 52, 110, 105, 53,
+ 53, 52, 52, 110, 105, 53, 53, 52, 52, 110,
+ 105, 53, 53, 52, 52, 110, 110, 53, 53, 52,
+ 209, 110, 110, 53, 53, 209, 225, 110, 110, 53,
+ 53, 209, 209, 110, 110, 193, 194, 195, 137, 216,
+ 222, 232, 217, 217, 217, 235, 57, 53, 217, 52,
+ 53, 53, 52, 52, 193, 194, 195, 57, 57, 57,
+ 66, 67, 68, 69, 70, 72, 72, 72, 86, 89,
+ 47, 57, 57, 113, 117, 117, 79, 123, 124, 131,
+ 47, 133, 137, 139, 143, 149, 150, 151, 152, 133,
+ 155, 156, 157, 110, 166, 149, 169, 172, 173, 72,
+ 175, 176, 183, 189, 166, 196, 137, 200, 202, 137,
+ 166, 211, 166, 137, 72, 176, 218, 176, 72, 137,
+ 228, 137, 72, 231, 72 ]
racc_action_check = [
- 47, 153, 47, 153, 159, 153, 159, 178, 159, 178,
- 189, 178, 189, 1, 189, 39, 35, 36, 35, 36,
- 5, 35, 36, 37, 38, 37, 38, 6, 37, 38,
- 59, 74, 59, 74, 59, 59, 74, 60, 45, 60,
- 138, 60, 60, 138, 9, 156, 153, 153, 156, 159,
- 159, 47, 178, 178, 39, 189, 189, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 83, 45, 45, 45,
- 45, 45, 45, 45, 45, 61, 0, 61, 0, 61,
- 61, 166, 166, 166, 166, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 11, 83, 83, 83, 83, 83,
- 83, 83, 83, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 13, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 14, 3, 3, 3, 3, 3, 3, 3,
- 3, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 15, 8, 8, 8, 8, 8, 8, 8, 8, 97,
- 2, 97, 2, 97, 97, 71, 108, 71, 108, 71,
- 108, 109, 169, 109, 169, 109, 169, 176, 184, 176,
- 184, 176, 184, 190, 205, 190, 205, 190, 205, 206,
- 12, 206, 12, 206, 174, 174, 174, 174, 196, 201,
- 214, 196, 201, 214, 69, 76, 69, 76, 104, 105,
- 104, 105, 111, 113, 111, 113, 198, 198, 198, 81,
- 81, 16, 17, 20, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 33, 34, 40, 51, 56, 67, 70,
- 72, 80, 84, 85, 86, 87, 93, 107, 115, 116,
- 117, 118, 127, 128, 134, 140, 141, 143, 144, 145,
- 146, 150, 151, 152, 158, 163, 165, 167, 168, 171,
- 172, 173, 175, 177, 187, 188, 192, 193, 195, 197,
- 200, 202, 204, 209, 210, 216 ]
+ 51, 97, 51, 97, 41, 75, 165, 75, 165, 75,
+ 165, 51, 171, 190, 171, 190, 171, 190, 201, 165,
+ 201, 148, 201, 1, 148, 171, 190, 36, 37, 36,
+ 37, 201, 36, 37, 38, 39, 38, 39, 5, 38,
+ 39, 117, 0, 117, 0, 117, 41, 46, 168, 88,
+ 88, 168, 51, 97, 165, 177, 177, 177, 177, 171,
+ 171, 190, 2, 6, 2, 201, 201, 90, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 9, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 10, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 11, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 3, 3, 12,
+ 14, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 15, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 8, 8, 16,
+ 17, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 18, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 63, 13, 63,
+ 13, 63, 63, 64, 73, 64, 73, 64, 64, 65,
+ 78, 65, 78, 65, 65, 106, 79, 106, 79, 106,
+ 106, 118, 180, 118, 180, 118, 180, 188, 196, 188,
+ 196, 188, 196, 202, 217, 202, 217, 202, 217, 218,
+ 231, 218, 231, 218, 231, 186, 186, 186, 186, 208,
+ 213, 227, 208, 213, 227, 234, 24, 113, 234, 113,
+ 114, 123, 114, 123, 210, 210, 210, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 40, 42,
+ 47, 55, 60, 71, 74, 76, 80, 81, 87, 91,
+ 92, 93, 94, 102, 116, 124, 125, 126, 127, 133,
+ 136, 137, 138, 144, 150, 151, 153, 156, 158, 162,
+ 163, 164, 170, 174, 176, 178, 179, 182, 184, 187,
+ 189, 199, 200, 204, 205, 207, 209, 212, 214, 216,
+ 221, 222, 224, 225, 229 ]
racc_action_pointer = [
- 66, 13, 150, 90, nil, 13, 27, nil, 118, 35,
- nil, 88, 187, 63, 73, 101, 216, 173, nil, nil,
- 174, nil, nil, nil, 175, 176, 177, 222, 223, 224,
- 225, 226, 224, 225, 226, 13, 14, 20, 21, 10,
- 233, nil, nil, nil, nil, 34, nil, -5, nil, nil,
- nil, 187, nil, nil, nil, nil, 188, nil, nil, 27,
- 34, 72, nil, nil, nil, nil, nil, 230, nil, 201,
- 231, 162, 232, nil, 28, nil, 202, nil, nil, nil,
- 200, 215, nil, 62, 233, 221, 222, 191, nil, nil,
- nil, nil, nil, 244, nil, nil, nil, 156, nil, nil,
- nil, nil, nil, nil, 205, 206, nil, 241, 163, 168,
- nil, 209, nil, 210, nil, 243, 206, 209, 240, nil,
- nil, nil, nil, nil, nil, nil, nil, 209, 248, nil,
- nil, nil, nil, nil, 247, nil, nil, nil, -2, nil,
- 208, 251, nil, 255, 211, 204, 210, nil, nil, nil,
- 253, 257, 217, -2, nil, nil, 3, nil, 218, 1,
- nil, nil, nil, 222, nil, 219, 30, 226, 214, 169,
- nil, 226, 223, 230, 143, 218, 174, 226, 4, nil,
- nil, nil, nil, nil, 175, nil, nil, 272, 228, 7,
- 180, nil, 222, 269, nil, 232, 156, 238, 165, nil,
- 234, 157, 273, nil, 274, 181, 186, nil, nil, 233,
- 230, nil, nil, nil, 158, nil, 277, nil, nil ]
+ 32, 23, 52, 93, nil, 31, 63, nil, 123, 68,
+ 74, 84, 103, 165, 94, 111, 123, 135, 141, nil,
+ nil, nil, nil, nil, 210, 221, 222, 223, 235, 236,
+ 237, 238, 239, 237, 238, 239, 24, 25, 31, 32,
+ 243, -1, 247, nil, nil, nil, 43, 237, nil, nil,
+ nil, -5, nil, nil, nil, 235, nil, nil, nil, nil,
+ 236, nil, nil, 164, 170, 176, nil, nil, nil, nil,
+ nil, 245, nil, 171, 246, 2, 247, nil, 177, 183,
+ 248, 249, nil, nil, nil, nil, nil, 214, 45, nil,
+ 63, 250, 247, 248, 207, nil, nil, -4, nil, nil,
+ nil, nil, 261, nil, nil, nil, 182, nil, nil, nil,
+ nil, nil, nil, 224, 227, nil, 258, 38, 188, nil,
+ nil, nil, nil, 228, 260, 220, 223, 257, nil, nil,
+ nil, nil, nil, 256, nil, nil, 224, 266, 255, nil,
+ nil, nil, nil, nil, 266, nil, nil, nil, -24, nil,
+ 224, 270, nil, 274, nil, nil, 221, nil, 261, nil,
+ nil, nil, 271, 275, 232, 3, nil, nil, 3, nil,
+ 233, 9, nil, nil, 237, nil, 234, 3, 241, 231,
+ 189, nil, 241, nil, 244, nil, 163, 234, 194, 240,
+ 10, nil, nil, nil, nil, nil, 195, nil, nil, 289,
+ 242, 15, 200, nil, 238, 286, nil, 246, 174, 252,
+ 182, nil, 248, 175, 290, nil, 244, 201, 206, nil,
+ nil, 283, 246, nil, 294, 259, nil, 176, nil, 296,
+ nil, 207, nil, nil, 180, nil ]
racc_action_default = [
- -1, -128, -1, -3, -10, -128, -128, -2, -3, -128,
- -16, -128, -128, -128, -128, -128, -128, -128, -24, -25,
- -128, -32, -33, -34, -128, -128, -128, -128, -128, -128,
- -128, -128, -50, -50, -50, -128, -128, -128, -128, -128,
- -128, -13, 219, -4, -26, -128, -17, -123, -93, -94,
- -122, -14, -19, -85, -20, -21, -128, -23, -31, -128,
- -128, -128, -38, -39, -40, -41, -42, -43, -51, -128,
- -44, -128, -45, -46, -88, -90, -128, -47, -48, -49,
- -128, -128, -11, -5, -7, -95, -128, -68, -18, -124,
- -125, -126, -15, -128, -22, -27, -28, -29, -35, -83,
- -84, -127, -36, -37, -128, -52, -54, -56, -128, -79,
- -81, -88, -89, -128, -91, -128, -128, -128, -128, -6,
- -8, -9, -120, -96, -97, -98, -69, -128, -128, -86,
- -30, -55, -53, -57, -76, -82, -80, -92, -128, -62,
- -66, -128, -12, -128, -66, -128, -128, -58, -77, -78,
- -50, -128, -60, -64, -67, -70, -128, -121, -99, -100,
- -102, -119, -87, -128, -63, -66, -68, -93, -68, -128,
- -116, -128, -66, -93, -68, -68, -128, -66, -65, -71,
- -72, -108, -109, -110, -128, -74, -75, -128, -66, -101,
- -128, -103, -68, -50, -107, -59, -128, -93, -111, -117,
- -61, -128, -50, -106, -50, -128, -128, -112, -113, -128,
- -68, -104, -73, -114, -128, -118, -50, -115, -105 ]
+ -1, -137, -1, -3, -10, -137, -137, -2, -3, -137,
+ -14, -14, -137, -137, -137, -137, -137, -137, -137, -28,
+ -29, -34, -35, -36, -137, -137, -137, -137, -137, -137,
+ -137, -137, -137, -54, -54, -54, -137, -137, -137, -137,
+ -137, -137, -137, -13, 236, -4, -137, -14, -16, -17,
+ -20, -132, -100, -101, -131, -18, -23, -89, -24, -25,
+ -137, -27, -37, -137, -137, -137, -41, -42, -43, -44,
+ -45, -46, -55, -137, -47, -137, -48, -49, -92, -137,
+ -95, -97, -98, -50, -51, -52, -53, -137, -137, -11,
+ -5, -7, -14, -137, -72, -15, -21, -132, -133, -134,
+ -135, -19, -137, -26, -30, -31, -32, -38, -87, -88,
+ -136, -39, -40, -137, -56, -58, -60, -137, -83, -85,
+ -93, -94, -96, -137, -137, -137, -137, -137, -6, -8,
+ -9, -129, -104, -102, -105, -73, -137, -137, -137, -90,
+ -33, -59, -57, -61, -80, -86, -84, -99, -137, -66,
+ -70, -137, -12, -137, -103, -109, -137, -22, -137, -62,
+ -81, -82, -54, -137, -64, -68, -71, -74, -137, -130,
+ -106, -107, -128, -91, -137, -67, -70, -72, -100, -72,
+ -137, -125, -137, -109, -100, -110, -72, -72, -137, -70,
+ -69, -75, -76, -116, -117, -118, -137, -78, -79, -137,
+ -70, -108, -137, -111, -72, -54, -115, -63, -137, -100,
+ -119, -126, -65, -137, -54, -114, -72, -137, -137, -120,
+ -121, -137, -72, -112, -54, -100, -122, -137, -127, -54,
+ -77, -137, -124, -113, -137, -123 ]
racc_goto_table = [
- 69, 109, 50, 152, 57, 127, 84, 58, 112, 160,
- 114, 59, 60, 61, 86, 52, 54, 55, 98, 102,
- 103, 159, 106, 110, 175, 74, 74, 74, 74, 138,
- 9, 1, 3, 180, 7, 43, 120, 160, 109, 109,
- 195, 192, 121, 94, 119, 112, 40, 137, 118, 189,
- 47, 200, 86, 92, 175, 156, 130, 131, 132, 107,
- 135, 136, 88, 196, 111, 207, 111, 70, 72, 201,
- 73, 77, 78, 79, 67, 147, 134, 178, 148, 149,
- 93, 146, 124, 166, 179, 214, 185, 158, 208, 174,
- 187, 209, 191, 193, 107, 107, 143, nil, nil, 186,
- nil, 111, nil, 111, nil, nil, 194, nil, 166, nil,
- 202, nil, nil, nil, 198, nil, nil, nil, 163, 174,
- 198, nil, nil, nil, nil, nil, nil, nil, 216, nil,
- nil, nil, nil, nil, nil, 213, 198, nil, nil, nil,
+ 73, 118, 136, 54, 48, 49, 164, 96, 91, 120,
+ 121, 93, 187, 208, 107, 111, 112, 119, 134, 213,
+ 56, 58, 59, 171, 61, 1, 78, 78, 78, 78,
+ 62, 63, 64, 65, 115, 227, 129, 192, 148, 74,
+ 76, 95, 187, 118, 118, 207, 204, 3, 234, 7,
+ 130, 201, 128, 138, 147, 93, 212, 140, 154, 145,
+ 146, 101, 9, 116, 42, 168, 103, 45, 78, 78,
+ 219, 127, 51, 71, 141, 142, 77, 83, 84, 85,
+ 159, 144, 190, 160, 161, 191, 132, 197, 102, 158,
+ 122, 177, 170, 220, 203, 205, 199, 186, 221, 153,
+ nil, nil, nil, 116, 116, nil, 198, nil, nil, nil,
+ nil, nil, 214, 78, 206, nil, 177, nil, nil, nil,
+ nil, nil, 210, nil, 224, nil, nil, 186, 210, 174,
+ 229, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, 226, 210, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, 210, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, 203, nil, nil, nil, nil, nil, nil, nil, nil,
- 211, nil, 212, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, nil, 218 ]
+ nil, nil, 215, nil, nil, nil, nil, nil, nil, nil,
+ nil, 223, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, 230, nil, nil, nil, nil, 233 ]
racc_goto_check = [
- 27, 20, 29, 33, 15, 40, 8, 15, 46, 39,
- 46, 15, 15, 15, 12, 16, 16, 16, 22, 22,
- 22, 50, 28, 43, 38, 29, 29, 29, 29, 32,
- 7, 1, 6, 36, 6, 7, 5, 39, 20, 20,
- 33, 36, 9, 15, 8, 46, 10, 46, 11, 50,
- 13, 33, 12, 16, 38, 32, 22, 28, 28, 29,
- 43, 43, 14, 37, 29, 36, 29, 24, 24, 37,
- 25, 25, 25, 25, 23, 30, 31, 34, 41, 42,
- 44, 45, 48, 20, 40, 37, 40, 49, 51, 20,
- 52, 53, 40, 40, 29, 29, 54, nil, nil, 20,
- nil, 29, nil, 29, nil, nil, 20, nil, 20, nil,
- 40, nil, nil, nil, 20, nil, nil, nil, 27, 20,
- 20, nil, nil, nil, nil, nil, nil, nil, 40, nil,
- nil, nil, nil, nil, nil, 20, 20, nil, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ 29, 22, 42, 31, 14, 14, 35, 16, 8, 48,
+ 48, 13, 40, 39, 24, 24, 24, 45, 52, 39,
+ 18, 18, 18, 54, 17, 1, 31, 31, 31, 31,
+ 17, 17, 17, 17, 30, 39, 5, 38, 34, 26,
+ 26, 14, 40, 22, 22, 35, 38, 6, 39, 6,
+ 9, 54, 8, 16, 48, 13, 35, 24, 52, 45,
+ 45, 18, 7, 31, 10, 34, 17, 7, 31, 31,
+ 38, 11, 15, 25, 30, 30, 27, 27, 27, 27,
+ 32, 33, 36, 43, 44, 42, 14, 42, 46, 47,
+ 50, 22, 53, 55, 42, 42, 56, 22, 57, 58,
+ nil, nil, nil, 31, 31, nil, 22, nil, nil, nil,
+ nil, nil, 42, 31, 22, nil, 22, nil, nil, nil,
+ nil, nil, 22, nil, 42, nil, nil, 22, 22, 29,
+ 42, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, 22, 22, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, 22, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
- nil, 27, nil, nil, nil, nil, nil, nil, nil, nil,
- 27, nil, 27, nil, nil, nil, nil, nil, nil, nil,
- nil, nil, nil, nil, 27 ]
+ nil, nil, 29, nil, nil, nil, nil, nil, nil, nil,
+ nil, 29, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, 29, nil, nil, nil, nil, 29 ]
racc_goto_pointer = [
- nil, 31, nil, nil, nil, -48, 32, 27, -39, -42,
- 42, -34, -31, 38, 15, -13, 2, nil, nil, nil,
- -70, nil, -41, 42, 34, 35, nil, -32, -47, -10,
- -59, -31, -86, -137, -88, nil, -133, -121, -135, -135,
- -82, -56, -55, -48, 27, -48, -66, nil, -3, -57,
- -123, -110, -80, -108, -26 ]
+ nil, 25, nil, nil, nil, -55, 47, 59, -38, -41,
+ 60, -18, nil, -35, -6, 59, -44, 6, 6, nil,
+ nil, nil, -74, nil, -49, 40, 5, 40, nil, -33,
+ -39, -10, -64, -35, -86, -144, -94, nil, -140, -183,
+ -159, nil, -92, -61, -60, -58, 31, -50, -69, nil,
+ 10, nil, -75, -63, -132, -117, -85, -113, -32 ]
racc_goto_default = [
- nil, nil, 2, 8, 83, nil, nil, nil, nil, nil,
- nil, nil, 10, nil, nil, 51, nil, 21, 22, 23,
- 95, 97, nil, nil, nil, nil, 105, 71, nil, 99,
- nil, nil, nil, nil, 153, 126, nil, nil, 168, 155,
- nil, 100, nil, nil, nil, nil, 75, 85, nil, nil,
- nil, nil, nil, nil, nil ]
+ nil, nil, 2, 8, 90, nil, nil, nil, nil, nil,
+ nil, nil, 10, 11, nil, nil, nil, 55, nil, 21,
+ 22, 23, 104, 106, nil, nil, nil, nil, 114, 75,
+ nil, 108, nil, nil, nil, nil, 165, 135, nil, nil,
+ 179, 167, nil, 109, nil, nil, nil, nil, 81, 80,
+ 82, 92, nil, nil, nil, nil, nil, nil, nil ]
racc_reduce_table = [
0, 0, :racc_error,
- 0, 63, :_reduce_1,
- 2, 63, :_reduce_2,
- 0, 64, :_reduce_3,
- 2, 64, :_reduce_4,
- 1, 65, :_reduce_5,
- 2, 65, :_reduce_6,
- 0, 66, :_reduce_none,
- 1, 66, :_reduce_none,
- 5, 58, :_reduce_none,
- 0, 67, :_reduce_10,
- 0, 68, :_reduce_11,
- 5, 59, :_reduce_12,
- 2, 59, :_reduce_none,
- 1, 73, :_reduce_14,
- 2, 73, :_reduce_15,
- 1, 60, :_reduce_none,
- 2, 60, :_reduce_17,
- 3, 60, :_reduce_18,
- 2, 60, :_reduce_none,
- 2, 60, :_reduce_20,
- 2, 60, :_reduce_21,
- 3, 60, :_reduce_22,
- 2, 60, :_reduce_23,
- 1, 60, :_reduce_24,
- 1, 60, :_reduce_25,
- 2, 60, :_reduce_none,
- 1, 78, :_reduce_27,
- 1, 78, :_reduce_28,
- 1, 79, :_reduce_29,
- 2, 79, :_reduce_30,
- 2, 69, :_reduce_31,
- 1, 69, :_reduce_none,
- 1, 69, :_reduce_none,
- 1, 69, :_reduce_none,
- 3, 69, :_reduce_35,
- 3, 69, :_reduce_36,
- 3, 69, :_reduce_37,
- 2, 69, :_reduce_38,
- 2, 69, :_reduce_39,
- 2, 69, :_reduce_40,
- 2, 69, :_reduce_41,
- 2, 69, :_reduce_42,
- 2, 74, :_reduce_none,
- 2, 74, :_reduce_44,
- 2, 74, :_reduce_45,
- 2, 74, :_reduce_46,
- 2, 74, :_reduce_47,
- 2, 74, :_reduce_48,
- 2, 74, :_reduce_49,
- 0, 84, :_reduce_none,
- 1, 84, :_reduce_none,
- 1, 85, :_reduce_52,
- 2, 85, :_reduce_53,
- 2, 80, :_reduce_54,
- 3, 80, :_reduce_55,
- 0, 88, :_reduce_none,
- 1, 88, :_reduce_none,
- 3, 83, :_reduce_58,
- 8, 75, :_reduce_59,
- 5, 76, :_reduce_60,
- 8, 76, :_reduce_61,
- 1, 89, :_reduce_62,
- 3, 89, :_reduce_63,
- 1, 90, :_reduce_64,
- 3, 90, :_reduce_65,
- 0, 96, :_reduce_none,
- 1, 96, :_reduce_none,
- 0, 97, :_reduce_none,
- 1, 97, :_reduce_none,
- 1, 91, :_reduce_70,
- 3, 91, :_reduce_71,
- 3, 91, :_reduce_72,
- 6, 91, :_reduce_73,
- 3, 91, :_reduce_74,
- 3, 91, :_reduce_75,
- 0, 99, :_reduce_none,
- 1, 99, :_reduce_none,
- 1, 87, :_reduce_78,
- 1, 100, :_reduce_79,
- 2, 100, :_reduce_80,
- 2, 81, :_reduce_81,
- 3, 81, :_reduce_82,
- 1, 77, :_reduce_none,
- 1, 77, :_reduce_none,
- 0, 101, :_reduce_85,
- 0, 102, :_reduce_86,
- 5, 72, :_reduce_87,
- 1, 103, :_reduce_88,
- 2, 103, :_reduce_89,
- 1, 82, :_reduce_90,
- 2, 82, :_reduce_91,
- 3, 82, :_reduce_92,
- 1, 86, :_reduce_93,
- 1, 86, :_reduce_94,
- 0, 105, :_reduce_none,
- 1, 105, :_reduce_none,
+ 0, 64, :_reduce_1,
+ 2, 64, :_reduce_2,
+ 0, 65, :_reduce_3,
+ 2, 65, :_reduce_4,
+ 1, 66, :_reduce_5,
+ 2, 66, :_reduce_6,
+ 0, 67, :_reduce_none,
+ 1, 67, :_reduce_none,
+ 5, 59, :_reduce_none,
+ 0, 68, :_reduce_10,
+ 0, 69, :_reduce_11,
+ 5, 60, :_reduce_12,
+ 2, 60, :_reduce_13,
+ 0, 72, :_reduce_14,
+ 2, 72, :_reduce_15,
2, 61, :_reduce_none,
2, 61, :_reduce_none,
- 4, 104, :_reduce_99,
- 1, 106, :_reduce_100,
- 3, 106, :_reduce_101,
- 1, 107, :_reduce_102,
- 3, 107, :_reduce_103,
- 5, 107, :_reduce_104,
- 7, 107, :_reduce_105,
- 4, 107, :_reduce_106,
- 3, 107, :_reduce_107,
- 1, 93, :_reduce_108,
- 1, 93, :_reduce_109,
- 1, 93, :_reduce_110,
- 0, 108, :_reduce_none,
- 1, 108, :_reduce_none,
- 2, 94, :_reduce_113,
- 3, 94, :_reduce_114,
- 4, 94, :_reduce_115,
- 0, 109, :_reduce_116,
- 0, 110, :_reduce_117,
- 5, 95, :_reduce_118,
- 3, 92, :_reduce_119,
- 0, 111, :_reduce_120,
- 3, 62, :_reduce_121,
- 1, 70, :_reduce_none,
- 0, 71, :_reduce_none,
+ 1, 76, :_reduce_18,
+ 2, 76, :_reduce_19,
+ 2, 70, :_reduce_20,
+ 3, 70, :_reduce_21,
+ 5, 70, :_reduce_22,
+ 2, 70, :_reduce_none,
+ 2, 70, :_reduce_24,
+ 2, 70, :_reduce_25,
+ 3, 70, :_reduce_26,
+ 2, 70, :_reduce_27,
+ 1, 70, :_reduce_28,
+ 1, 70, :_reduce_29,
+ 1, 81, :_reduce_30,
+ 1, 81, :_reduce_31,
+ 1, 82, :_reduce_32,
+ 2, 82, :_reduce_33,
1, 71, :_reduce_none,
1, 71, :_reduce_none,
1, 71, :_reduce_none,
- 1, 98, :_reduce_127 ]
-
-racc_reduce_n = 128
-
-racc_shift_n = 219
+ 2, 71, :_reduce_37,
+ 3, 71, :_reduce_38,
+ 3, 71, :_reduce_39,
+ 3, 71, :_reduce_40,
+ 2, 71, :_reduce_41,
+ 2, 71, :_reduce_42,
+ 2, 71, :_reduce_43,
+ 2, 71, :_reduce_44,
+ 2, 71, :_reduce_45,
+ 2, 77, :_reduce_none,
+ 2, 77, :_reduce_47,
+ 2, 77, :_reduce_48,
+ 2, 77, :_reduce_49,
+ 2, 77, :_reduce_50,
+ 2, 77, :_reduce_51,
+ 2, 77, :_reduce_52,
+ 2, 77, :_reduce_53,
+ 0, 87, :_reduce_none,
+ 1, 87, :_reduce_none,
+ 1, 88, :_reduce_56,
+ 2, 88, :_reduce_57,
+ 2, 83, :_reduce_58,
+ 3, 83, :_reduce_59,
+ 0, 91, :_reduce_none,
+ 1, 91, :_reduce_none,
+ 3, 86, :_reduce_62,
+ 8, 78, :_reduce_63,
+ 5, 79, :_reduce_64,
+ 8, 79, :_reduce_65,
+ 1, 92, :_reduce_66,
+ 3, 92, :_reduce_67,
+ 1, 93, :_reduce_68,
+ 3, 93, :_reduce_69,
+ 0, 99, :_reduce_none,
+ 1, 99, :_reduce_none,
+ 0, 100, :_reduce_none,
+ 1, 100, :_reduce_none,
+ 1, 94, :_reduce_74,
+ 3, 94, :_reduce_75,
+ 3, 94, :_reduce_76,
+ 7, 94, :_reduce_77,
+ 3, 94, :_reduce_78,
+ 3, 94, :_reduce_79,
+ 0, 102, :_reduce_none,
+ 1, 102, :_reduce_none,
+ 1, 90, :_reduce_82,
+ 1, 103, :_reduce_83,
+ 2, 103, :_reduce_84,
+ 2, 84, :_reduce_85,
+ 3, 84, :_reduce_86,
+ 1, 80, :_reduce_none,
+ 1, 80, :_reduce_none,
+ 0, 104, :_reduce_89,
+ 0, 105, :_reduce_90,
+ 5, 75, :_reduce_91,
+ 1, 106, :_reduce_92,
+ 2, 106, :_reduce_93,
+ 2, 107, :_reduce_94,
+ 1, 108, :_reduce_95,
+ 2, 108, :_reduce_96,
+ 1, 85, :_reduce_97,
+ 1, 85, :_reduce_98,
+ 3, 85, :_reduce_99,
+ 1, 89, :_reduce_none,
+ 1, 89, :_reduce_none,
+ 1, 110, :_reduce_102,
+ 2, 110, :_reduce_103,
+ 2, 62, :_reduce_none,
+ 2, 62, :_reduce_none,
+ 4, 109, :_reduce_106,
+ 1, 111, :_reduce_107,
+ 3, 111, :_reduce_108,
+ 0, 112, :_reduce_109,
+ 2, 112, :_reduce_110,
+ 3, 112, :_reduce_111,
+ 5, 112, :_reduce_112,
+ 7, 112, :_reduce_113,
+ 4, 112, :_reduce_114,
+ 3, 112, :_reduce_115,
+ 1, 96, :_reduce_116,
+ 1, 96, :_reduce_117,
+ 1, 96, :_reduce_118,
+ 0, 113, :_reduce_none,
+ 1, 113, :_reduce_none,
+ 2, 97, :_reduce_121,
+ 3, 97, :_reduce_122,
+ 6, 97, :_reduce_123,
+ 4, 97, :_reduce_124,
+ 0, 114, :_reduce_125,
+ 0, 115, :_reduce_126,
+ 5, 98, :_reduce_127,
+ 3, 95, :_reduce_128,
+ 0, 116, :_reduce_129,
+ 3, 63, :_reduce_130,
+ 1, 73, :_reduce_none,
+ 0, 74, :_reduce_none,
+ 1, 74, :_reduce_none,
+ 1, 74, :_reduce_none,
+ 1, 74, :_reduce_none,
+ 1, 101, :_reduce_136 ]
+
+racc_reduce_n = 137
+
+racc_shift_n = 236
racc_token_table = {
false => 0,
@@ -1044,52 +1079,53 @@ racc_token_table = {
"%{" => 10,
"%}" => 11,
"%require" => 12,
- "%expect" => 13,
- "%define" => 14,
- "%param" => 15,
- "%lex-param" => 16,
- "%parse-param" => 17,
- "%code" => 18,
- "%initial-action" => 19,
- "%no-stdlib" => 20,
- "%locations" => 21,
- ";" => 22,
- "%union" => 23,
- "%destructor" => 24,
- "%printer" => 25,
- "%error-token" => 26,
- "%after-shift" => 27,
- "%before-reduce" => 28,
- "%after-reduce" => 29,
- "%after-shift-error-token" => 30,
- "%after-pop-stack" => 31,
- "-temp-group" => 32,
- "%token" => 33,
- "%type" => 34,
- "%nterm" => 35,
- "%left" => 36,
- "%right" => 37,
- "%precedence" => 38,
- "%nonassoc" => 39,
- "%rule" => 40,
- "(" => 41,
- ")" => 42,
- ":" => 43,
- "%inline" => 44,
- "," => 45,
- "|" => 46,
- "%empty" => 47,
- "%prec" => 48,
- "{" => 49,
- "}" => 50,
- "?" => 51,
- "+" => 52,
- "*" => 53,
- "[" => 54,
- "]" => 55,
- "{...}" => 56 }
-
-racc_nt_base = 57
+ ";" => 13,
+ "%expect" => 14,
+ "%define" => 15,
+ "{" => 16,
+ "}" => 17,
+ "%param" => 18,
+ "%lex-param" => 19,
+ "%parse-param" => 20,
+ "%code" => 21,
+ "%initial-action" => 22,
+ "%no-stdlib" => 23,
+ "%locations" => 24,
+ "%union" => 25,
+ "%destructor" => 26,
+ "%printer" => 27,
+ "%error-token" => 28,
+ "%after-shift" => 29,
+ "%before-reduce" => 30,
+ "%after-reduce" => 31,
+ "%after-shift-error-token" => 32,
+ "%after-pop-stack" => 33,
+ "-temp-group" => 34,
+ "%token" => 35,
+ "%type" => 36,
+ "%nterm" => 37,
+ "%left" => 38,
+ "%right" => 39,
+ "%precedence" => 40,
+ "%nonassoc" => 41,
+ "%start" => 42,
+ "%rule" => 43,
+ "(" => 44,
+ ")" => 45,
+ ":" => 46,
+ "%inline" => 47,
+ "," => 48,
+ "|" => 49,
+ "%empty" => 50,
+ "%prec" => 51,
+ "?" => 52,
+ "+" => 53,
+ "*" => 54,
+ "[" => 55,
+ "]" => 56,
+ "{...}" => 57 }
+
+racc_nt_base = 58
racc_use_result_var = true
@@ -1124,8 +1160,11 @@ Racc_token_to_s_table = [
"\"%{\"",
"\"%}\"",
"\"%require\"",
+ "\";\"",
"\"%expect\"",
"\"%define\"",
+ "\"{\"",
+ "\"}\"",
"\"%param\"",
"\"%lex-param\"",
"\"%parse-param\"",
@@ -1133,7 +1172,6 @@ Racc_token_to_s_table = [
"\"%initial-action\"",
"\"%no-stdlib\"",
"\"%locations\"",
- "\";\"",
"\"%union\"",
"\"%destructor\"",
"\"%printer\"",
@@ -1151,6 +1189,7 @@ Racc_token_to_s_table = [
"\"%right\"",
"\"%precedence\"",
"\"%nonassoc\"",
+ "\"%start\"",
"\"%rule\"",
"\"(\"",
"\")\"",
@@ -1160,8 +1199,6 @@ Racc_token_to_s_table = [
"\"|\"",
"\"%empty\"",
"\"%prec\"",
- "\"{\"",
- "\"}\"",
"\"?\"",
"\"+\"",
"\"*\"",
@@ -1180,7 +1217,9 @@ Racc_token_to_s_table = [
"\"-option@epilogue_declaration\"",
"@1",
"@2",
+ "parser_option",
"grammar_declaration",
+ "\"-many@;\"",
"variable",
"value",
"param",
@@ -1204,9 +1243,9 @@ Racc_token_to_s_table = [
"rule_rhs_list",
"rule_rhs",
"named_ref",
- "parameterizing_suffix",
- "parameterizing_args",
- "midrule_action",
+ "parameterized_suffix",
+ "parameterized_args",
+ "action",
"\"-option@%empty\"",
"\"-option@named_ref\"",
"string_as_id",
@@ -1215,11 +1254,13 @@ Racc_token_to_s_table = [
"@3",
"@4",
"\"-many1@id\"",
+ "\"-group@TAG-\\\"-many1@id\\\"\"",
+ "\"-many1@-group@TAG-\\\"-many1@id\\\"\"",
"rules",
- "\"-option@;\"",
+ "\"-many1@;\"",
"rhs_list",
"rhs",
- "\"-option@parameterizing_suffix\"",
+ "\"-option@parameterized_suffix\"",
"@5",
"@6",
"@7" ]
@@ -1279,10 +1320,9 @@ module_eval(<<'.,.,', 'parser.y', 11)
# reduce 9 omitted
-module_eval(<<'.,.,', 'parser.y', 12)
+module_eval(<<'.,.,', 'parser.y', 13)
def _reduce_10(val, _values, result)
- begin_c_declaration("%}")
- @grammar.prologue_first_lineno = @lexer.line
+ begin_c_declaration("%}")
result
end
@@ -1290,7 +1330,7 @@ module_eval(<<'.,.,', 'parser.y', 12)
module_eval(<<'.,.,', 'parser.y', 17)
def _reduce_11(val, _values, result)
- end_c_declaration
+ end_c_declaration
result
end
@@ -1298,22 +1338,29 @@ module_eval(<<'.,.,', 'parser.y', 17)
module_eval(<<'.,.,', 'parser.y', 21)
def _reduce_12(val, _values, result)
- @grammar.prologue = val[2].s_value
+ @grammar.prologue_first_lineno = val[0].first_line
+ @grammar.prologue = val[2].s_value
result
end
.,.,
-# reduce 13 omitted
+module_eval(<<'.,.,', 'parser.y', 26)
+ def _reduce_13(val, _values, result)
+ @grammar.required = true
+
+ result
+ end
+.,.,
-module_eval(<<'.,.,', 'parser.y', 54)
+module_eval(<<'.,.,', 'parser.y', 34)
def _reduce_14(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 54)
+module_eval(<<'.,.,', 'parser.y', 34)
def _reduce_15(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
@@ -1322,150 +1369,140 @@ module_eval(<<'.,.,', 'parser.y', 54)
# reduce 16 omitted
-module_eval(<<'.,.,', 'parser.y', 26)
- def _reduce_17(val, _values, result)
- @grammar.expect = val[1]
+# reduce 17 omitted
+
+module_eval(<<'.,.,', 'parser.y', 77)
+ def _reduce_18(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 27)
- def _reduce_18(val, _values, result)
- @grammar.define[val[1].s_value] = val[2]&.s_value
+module_eval(<<'.,.,', 'parser.y', 77)
+ def _reduce_19(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-# reduce 19 omitted
-
-module_eval(<<'.,.,', 'parser.y', 31)
+module_eval(<<'.,.,', 'parser.y', 36)
def _reduce_20(val, _values, result)
- val[1].each {|token|
- @grammar.lex_param = Grammar::Code::NoReferenceCode.new(type: :lex_param, token_code: token).token_code.s_value
- }
+ @grammar.expect = val[1].s_value
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 37)
+module_eval(<<'.,.,', 'parser.y', 40)
def _reduce_21(val, _values, result)
- val[1].each {|token|
- @grammar.parse_param = Grammar::Code::NoReferenceCode.new(type: :parse_param, token_code: token).token_code.s_value
- }
+ @grammar.define[val[1].s_value] = val[2]&.s_value
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 43)
+module_eval(<<'.,.,', 'parser.y', 44)
def _reduce_22(val, _values, result)
- @grammar.add_percent_code(id: val[1], code: val[2])
+ @grammar.define[val[1].s_value] = val[3]&.s_value
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 47)
- def _reduce_23(val, _values, result)
- @grammar.initial_action = Grammar::Code::InitialActionCode.new(type: :initial_action, token_code: val[1])
-
- result
- end
-.,.,
+# reduce 23 omitted
module_eval(<<'.,.,', 'parser.y', 49)
def _reduce_24(val, _values, result)
- @grammar.no_stdlib = true
+ val[1].each {|token|
+ @grammar.lex_param = Grammar::Code::NoReferenceCode.new(type: :lex_param, token_code: token).token_code.s_value
+ }
+
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 50)
+module_eval(<<'.,.,', 'parser.y', 55)
def _reduce_25(val, _values, result)
- @grammar.locations = true
+ val[1].each {|token|
+ @grammar.parse_param = Grammar::Code::NoReferenceCode.new(type: :parse_param, token_code: token).token_code.s_value
+ }
+
result
end
.,.,
-# reduce 26 omitted
+module_eval(<<'.,.,', 'parser.y', 61)
+ def _reduce_26(val, _values, result)
+ @grammar.add_percent_code(id: val[1], code: val[2])
-module_eval(<<'.,.,', 'parser.y', 109)
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 65)
def _reduce_27(val, _values, result)
- result = val
+ @grammar.initial_action = Grammar::Code::InitialActionCode.new(type: :initial_action, token_code: val[1])
+
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 109)
+module_eval(<<'.,.,', 'parser.y', 69)
def _reduce_28(val, _values, result)
- result = val
+ @grammar.no_stdlib = true
+
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 109)
+module_eval(<<'.,.,', 'parser.y', 73)
def _reduce_29(val, _values, result)
- result = val[1] ? val[1].unshift(val[0]) : val
+ @grammar.locations = true
+
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 109)
+module_eval(<<'.,.,', 'parser.y', 133)
def _reduce_30(val, _values, result)
- result = val[1] ? val[1].unshift(val[0]) : val
+ result = val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 55)
+module_eval(<<'.,.,', 'parser.y', 133)
def _reduce_31(val, _values, result)
- @grammar.set_union(
- Grammar::Code::NoReferenceCode.new(type: :union, token_code: val[1]),
- val[1].line
- )
-
+ result = val
result
end
.,.,
-# reduce 32 omitted
-
-# reduce 33 omitted
-
-# reduce 34 omitted
-
-module_eval(<<'.,.,', 'parser.y', 65)
- def _reduce_35(val, _values, result)
- @grammar.add_destructor(
- ident_or_tags: val[2].flatten,
- token_code: val[1],
- lineno: val[1].line
- )
-
+module_eval(<<'.,.,', 'parser.y', 133)
+ def _reduce_32(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 73)
- def _reduce_36(val, _values, result)
- @grammar.add_printer(
- ident_or_tags: val[2].flatten,
- token_code: val[1],
- lineno: val[1].line
- )
-
+module_eval(<<'.,.,', 'parser.y', 133)
+ def _reduce_33(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 81)
+# reduce 34 omitted
+
+# reduce 35 omitted
+
+# reduce 36 omitted
+
+module_eval(<<'.,.,', 'parser.y', 82)
def _reduce_37(val, _values, result)
- @grammar.add_error_token(
- ident_or_tags: val[2].flatten,
- token_code: val[1],
- lineno: val[1].line
- )
+ @grammar.set_union(
+ Grammar::Code::NoReferenceCode.new(type: :union, token_code: val[1]),
+ val[1].line
+ )
result
end
@@ -1473,665 +1510,769 @@ module_eval(<<'.,.,', 'parser.y', 81)
module_eval(<<'.,.,', 'parser.y', 89)
def _reduce_38(val, _values, result)
- @grammar.after_shift = val[1]
+ @grammar.add_destructor(
+ ident_or_tags: val[2].flatten,
+ token_code: val[1],
+ lineno: val[1].line
+ )
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 93)
+module_eval(<<'.,.,', 'parser.y', 97)
def _reduce_39(val, _values, result)
- @grammar.before_reduce = val[1]
+ @grammar.add_printer(
+ ident_or_tags: val[2].flatten,
+ token_code: val[1],
+ lineno: val[1].line
+ )
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 97)
+module_eval(<<'.,.,', 'parser.y', 105)
def _reduce_40(val, _values, result)
- @grammar.after_reduce = val[1]
+ @grammar.add_error_token(
+ ident_or_tags: val[2].flatten,
+ token_code: val[1],
+ lineno: val[1].line
+ )
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 101)
+module_eval(<<'.,.,', 'parser.y', 113)
def _reduce_41(val, _values, result)
- @grammar.after_shift_error_token = val[1]
+ @grammar.after_shift = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 105)
+module_eval(<<'.,.,', 'parser.y', 117)
def _reduce_42(val, _values, result)
- @grammar.after_pop_stack = val[1]
+ @grammar.before_reduce = val[1]
result
end
.,.,
-# reduce 43 omitted
-
-module_eval(<<'.,.,', 'parser.y', 111)
- def _reduce_44(val, _values, result)
- val[1].each {|hash|
- hash[:tokens].each {|id|
- @grammar.add_type(id: id, tag: hash[:tag])
- }
- }
+module_eval(<<'.,.,', 'parser.y', 121)
+ def _reduce_43(val, _values, result)
+ @grammar.after_reduce = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 119)
- def _reduce_45(val, _values, result)
- val[1].each {|hash|
- hash[:tokens].each {|id|
- if @grammar.find_term_by_s_value(id.s_value)
- on_action_error("symbol #{id.s_value} redeclared as a nonterminal", id)
- else
- @grammar.add_type(id: id, tag: hash[:tag])
- end
- }
- }
+module_eval(<<'.,.,', 'parser.y', 125)
+ def _reduce_44(val, _values, result)
+ @grammar.after_shift_error_token = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 131)
- def _reduce_46(val, _values, result)
- val[1].each {|hash|
- hash[:tokens].each {|id|
- sym = @grammar.add_term(id: id)
- @grammar.add_left(sym, @precedence_number)
- }
- }
- @precedence_number += 1
+module_eval(<<'.,.,', 'parser.y', 129)
+ def _reduce_45(val, _values, result)
+ @grammar.after_pop_stack = val[1]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 141)
+# reduce 46 omitted
+
+module_eval(<<'.,.,', 'parser.y', 136)
def _reduce_47(val, _values, result)
- val[1].each {|hash|
- hash[:tokens].each {|id|
- sym = @grammar.add_term(id: id)
- @grammar.add_right(sym, @precedence_number)
- }
- }
- @precedence_number += 1
+ val[1].each {|hash|
+ hash[:tokens].each {|id|
+ @grammar.add_type(id: id, tag: hash[:tag])
+ }
+ }
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 151)
+module_eval(<<'.,.,', 'parser.y', 144)
def _reduce_48(val, _values, result)
- val[1].each {|hash|
- hash[:tokens].each {|id|
- sym = @grammar.add_term(id: id)
- @grammar.add_precedence(sym, @precedence_number)
- }
- }
- @precedence_number += 1
+ val[1].each {|hash|
+ hash[:tokens].each {|id|
+ if @grammar.find_term_by_s_value(id.s_value)
+ on_action_error("symbol #{id.s_value} redeclared as a nonterminal", id)
+ else
+ @grammar.add_type(id: id, tag: hash[:tag])
+ end
+ }
+ }
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 161)
+module_eval(<<'.,.,', 'parser.y', 156)
def _reduce_49(val, _values, result)
- val[1].each {|hash|
- hash[:tokens].each {|id|
- sym = @grammar.add_term(id: id)
- @grammar.add_nonassoc(sym, @precedence_number)
- }
- }
- @precedence_number += 1
+ val[1].each {|hash|
+ hash[:tokens].each {|id|
+ sym = @grammar.add_term(id: id, tag: hash[:tag])
+ @grammar.add_left(sym, @precedence_number, id.s_value, id.first_line)
+ }
+ }
+ @precedence_number += 1
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 166)
+ def _reduce_50(val, _values, result)
+ val[1].each {|hash|
+ hash[:tokens].each {|id|
+ sym = @grammar.add_term(id: id, tag: hash[:tag])
+ @grammar.add_right(sym, @precedence_number, id.s_value, id.first_line)
+ }
+ }
+ @precedence_number += 1
result
end
.,.,
-# reduce 50 omitted
+module_eval(<<'.,.,', 'parser.y', 176)
+ def _reduce_51(val, _values, result)
+ val[1].each {|hash|
+ hash[:tokens].each {|id|
+ sym = @grammar.add_term(id: id, tag: hash[:tag])
+ @grammar.add_precedence(sym, @precedence_number, id.s_value, id.first_line)
+ }
+ }
+ @precedence_number += 1
-# reduce 51 omitted
+ result
+ end
+.,.,
-module_eval(<<'.,.,', 'parser.y', 184)
+module_eval(<<'.,.,', 'parser.y', 186)
def _reduce_52(val, _values, result)
- result = val[1] ? val[1].unshift(val[0]) : val
+ val[1].each {|hash|
+ hash[:tokens].each {|id|
+ sym = @grammar.add_term(id: id, tag: hash[:tag])
+ @grammar.add_nonassoc(sym, @precedence_number, id.s_value, id.first_line)
+ }
+ }
+ @precedence_number += 1
+
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 184)
+module_eval(<<'.,.,', 'parser.y', 196)
def _reduce_53(val, _values, result)
+ @grammar.set_start_nterm(val[1])
+
+ result
+ end
+.,.,
+
+# reduce 54 omitted
+
+# reduce 55 omitted
+
+module_eval(<<'.,.,', 'parser.y', 214)
+ def _reduce_56(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 172)
- def _reduce_54(val, _values, result)
- val[1].each {|token_declaration|
- @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1], tag: val[0], replace: true)
- }
+module_eval(<<'.,.,', 'parser.y', 214)
+ def _reduce_57(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 202)
+ def _reduce_58(val, _values, result)
+ val[1].each {|token_declaration|
+ @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1]&.s_value, tag: val[0], replace: true)
+ }
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 178)
- def _reduce_55(val, _values, result)
- val[2].each {|token_declaration|
- @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1], tag: val[1], replace: true)
- }
+module_eval(<<'.,.,', 'parser.y', 208)
+ def _reduce_59(val, _values, result)
+ val[2].each {|token_declaration|
+ @grammar.add_term(id: token_declaration[0], alias_name: token_declaration[2], token_id: token_declaration[1]&.s_value, tag: val[1], replace: true)
+ }
result
end
.,.,
-# reduce 56 omitted
+# reduce 60 omitted
-# reduce 57 omitted
+# reduce 61 omitted
-module_eval(<<'.,.,', 'parser.y', 183)
- def _reduce_58(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 213)
+ def _reduce_62(val, _values, result)
result = val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 187)
- def _reduce_59(val, _values, result)
- rule = Grammar::ParameterizingRule::Rule.new(val[1].s_value, val[3], val[7], tag: val[5])
- @grammar.add_parameterizing_rule(rule)
+module_eval(<<'.,.,', 'parser.y', 218)
+ def _reduce_63(val, _values, result)
+ rule = Grammar::Parameterized::Rule.new(val[1].s_value, val[3], val[7], tag: val[5])
+ @grammar.add_parameterized_rule(rule)
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 193)
- def _reduce_60(val, _values, result)
- rule = Grammar::ParameterizingRule::Rule.new(val[2].s_value, [], val[4], is_inline: true)
- @grammar.add_parameterizing_rule(rule)
+module_eval(<<'.,.,', 'parser.y', 225)
+ def _reduce_64(val, _values, result)
+ rule = Grammar::Parameterized::Rule.new(val[2].s_value, [], val[4], is_inline: true)
+ @grammar.add_parameterized_rule(rule)
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 198)
- def _reduce_61(val, _values, result)
- rule = Grammar::ParameterizingRule::Rule.new(val[2].s_value, val[4], val[7], is_inline: true)
- @grammar.add_parameterizing_rule(rule)
+module_eval(<<'.,.,', 'parser.y', 230)
+ def _reduce_65(val, _values, result)
+ rule = Grammar::Parameterized::Rule.new(val[2].s_value, val[4], val[7], is_inline: true)
+ @grammar.add_parameterized_rule(rule)
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 202)
- def _reduce_62(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 235)
+ def _reduce_66(val, _values, result)
result = [val[0]]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 203)
- def _reduce_63(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 236)
+ def _reduce_67(val, _values, result)
result = val[0].append(val[2])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 207)
- def _reduce_64(val, _values, result)
- builder = val[0]
- result = [builder]
+module_eval(<<'.,.,', 'parser.y', 241)
+ def _reduce_68(val, _values, result)
+ builder = val[0]
+ result = [builder]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 212)
- def _reduce_65(val, _values, result)
- builder = val[2]
- result = val[0].append(builder)
+module_eval(<<'.,.,', 'parser.y', 246)
+ def _reduce_69(val, _values, result)
+ builder = val[2]
+ result = val[0].append(builder)
result
end
.,.,
-# reduce 66 omitted
+# reduce 70 omitted
-# reduce 67 omitted
+# reduce 71 omitted
-# reduce 68 omitted
+# reduce 72 omitted
-# reduce 69 omitted
+# reduce 73 omitted
-module_eval(<<'.,.,', 'parser.y', 218)
- def _reduce_70(val, _values, result)
- reset_precs
- result = Grammar::ParameterizingRule::Rhs.new
+module_eval(<<'.,.,', 'parser.y', 253)
+ def _reduce_74(val, _values, result)
+ reset_precs
+ result = Grammar::Parameterized::Rhs.new
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 223)
- def _reduce_71(val, _values, result)
- token = val[1]
- token.alias_name = val[2]
- builder = val[0]
- builder.symbols << token
- result = builder
+module_eval(<<'.,.,', 'parser.y', 258)
+ def _reduce_75(val, _values, result)
+ on_action_error("intermediate %prec in a rule", val[1]) if @trailing_prec_seen
+ token = val[1]
+ token.alias_name = val[2]
+ builder = val[0]
+ builder.symbols << token
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 231)
- def _reduce_72(val, _values, result)
- builder = val[0]
- builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]])
- result = builder
+module_eval(<<'.,.,', 'parser.y', 267)
+ def _reduce_76(val, _values, result)
+ on_action_error("intermediate %prec in a rule", val[1]) if @trailing_prec_seen
+ builder = val[0]
+ builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], location: @lexer.location, args: [val[1]])
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 237)
- def _reduce_73(val, _values, result)
- builder = val[0]
- builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[3], lhs_tag: val[5])
- result = builder
+module_eval(<<'.,.,', 'parser.y', 274)
+ def _reduce_77(val, _values, result)
+ on_action_error("intermediate %prec in a rule", val[1]) if @trailing_prec_seen
+ builder = val[0]
+ builder.symbols << Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, alias_name: val[5], location: @lexer.location, args: val[3], lhs_tag: val[6])
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 243)
- def _reduce_74(val, _values, result)
- user_code = val[1]
- user_code.alias_name = val[2]
- builder = val[0]
- builder.user_code = user_code
- result = builder
+module_eval(<<'.,.,', 'parser.y', 281)
+ def _reduce_78(val, _values, result)
+ user_code = val[1]
+ user_code.alias_name = val[2]
+ builder = val[0]
+ builder.user_code = user_code
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 251)
- def _reduce_75(val, _values, result)
- sym = @grammar.find_symbol_by_id!(val[2])
- @prec_seen = true
- builder = val[0]
- builder.precedence_sym = sym
- result = builder
+module_eval(<<'.,.,', 'parser.y', 289)
+ def _reduce_79(val, _values, result)
+ on_action_error("multiple %prec in a rule", val[0]) if prec_seen?
+ sym = @grammar.find_symbol_by_id!(val[2])
+ if val[0].rhs.empty?
+ @opening_prec_seen = true
+ else
+ @trailing_prec_seen = true
+ end
+ builder = val[0]
+ builder.precedence_sym = sym
+ result = builder
result
end
.,.,
-# reduce 76 omitted
+# reduce 80 omitted
-# reduce 77 omitted
+# reduce 81 omitted
-module_eval(<<'.,.,', 'parser.y', 258)
- def _reduce_78(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 301)
+ def _reduce_82(val, _values, result)
result = val[0].s_value if val[0]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 271)
- def _reduce_79(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 315)
+ def _reduce_83(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 271)
- def _reduce_80(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 315)
+ def _reduce_84(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 262)
- def _reduce_81(val, _values, result)
- result = if val[0]
- [{tag: val[0], tokens: val[1]}]
- else
- [{tag: nil, tokens: val[1]}]
- end
+module_eval(<<'.,.,', 'parser.y', 306)
+ def _reduce_85(val, _values, result)
+ result = if val[0]
+ [{tag: val[0], tokens: val[1]}]
+ else
+ [{tag: nil, tokens: val[1]}]
+ end
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 268)
- def _reduce_82(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 312)
+ def _reduce_86(val, _values, result)
result = val[0].append({tag: val[1], tokens: val[2]})
result
end
.,.,
-# reduce 83 omitted
+# reduce 87 omitted
-# reduce 84 omitted
+# reduce 88 omitted
-module_eval(<<'.,.,', 'parser.y', 274)
- def _reduce_85(val, _values, result)
- begin_c_declaration("}")
+module_eval(<<'.,.,', 'parser.y', 321)
+ def _reduce_89(val, _values, result)
+ begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 278)
- def _reduce_86(val, _values, result)
- end_c_declaration
+module_eval(<<'.,.,', 'parser.y', 325)
+ def _reduce_90(val, _values, result)
+ end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 282)
- def _reduce_87(val, _values, result)
- result = val[2]
+module_eval(<<'.,.,', 'parser.y', 329)
+ def _reduce_91(val, _values, result)
+ result = val[2]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 290)
- def _reduce_88(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 338)
+ def _reduce_92(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 290)
- def _reduce_89(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 338)
+ def _reduce_93(val, _values, result)
result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 285)
- def _reduce_90(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 338)
+ def _reduce_94(val, _values, result)
+ result = val
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 338)
+ def _reduce_95(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 338)
+ def _reduce_96(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 333)
+ def _reduce_97(val, _values, result)
result = [{tag: nil, tokens: val[0]}]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 286)
- def _reduce_91(val, _values, result)
- result = [{tag: val[0], tokens: val[1]}]
+module_eval(<<'.,.,', 'parser.y', 334)
+ def _reduce_98(val, _values, result)
+ result = val[0].map {|tag, ids| {tag: tag, tokens: ids} }
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 287)
- def _reduce_92(val, _values, result)
- result = val[0].append({tag: val[1], tokens: val[2]})
+module_eval(<<'.,.,', 'parser.y', 335)
+ def _reduce_99(val, _values, result)
+ result = [{tag: nil, tokens: val[0]}, {tag: val[1], tokens: val[2]}]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 289)
- def _reduce_93(val, _values, result)
- on_action_error("ident after %prec", val[0]) if @prec_seen
+# reduce 100 omitted
+
+# reduce 101 omitted
+
+module_eval(<<'.,.,', 'parser.y', 346)
+ def _reduce_102(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 290)
- def _reduce_94(val, _values, result)
- on_action_error("char after %prec", val[0]) if @prec_seen
+module_eval(<<'.,.,', 'parser.y', 346)
+ def _reduce_103(val, _values, result)
+ result = val[1] ? val[1].unshift(val[0]) : val
result
end
.,.,
-# reduce 95 omitted
+# reduce 104 omitted
-# reduce 96 omitted
+# reduce 105 omitted
-# reduce 97 omitted
+module_eval(<<'.,.,', 'parser.y', 348)
+ def _reduce_106(val, _values, result)
+ lhs = val[0]
+ lhs.alias_name = val[1]
+ val[3].each do |builder|
+ builder.lhs = lhs
+ builder.complete_input
+ @grammar.add_rule_builder(builder)
+ end
-# reduce 98 omitted
+ result
+ end
+.,.,
-module_eval(<<'.,.,', 'parser.y', 298)
- def _reduce_99(val, _values, result)
- lhs = val[0]
- lhs.alias_name = val[1]
- val[3].each do |builder|
- builder.lhs = lhs
- builder.complete_input
- @grammar.add_rule_builder(builder)
- end
+module_eval(<<'.,.,', 'parser.y', 360)
+ def _reduce_107(val, _values, result)
+ if val[0].rhs.count > 1
+ empties = val[0].rhs.select { |sym| sym.is_a?(Lrama::Lexer::Token::Empty) }
+ empties.each do |empty|
+ on_action_error("%empty on non-empty rule", empty)
+ end
+ end
+ builder = val[0]
+ if !builder.line
+ builder.line = @lexer.line - 1
+ end
+ result = [builder]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 309)
- def _reduce_100(val, _values, result)
- builder = val[0]
- if !builder.line
- builder.line = @lexer.line - 1
- end
- result = [builder]
+module_eval(<<'.,.,', 'parser.y', 374)
+ def _reduce_108(val, _values, result)
+ builder = val[2]
+ if !builder.line
+ builder.line = @lexer.line - 1
+ end
+ result = val[0].append(builder)
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 317)
- def _reduce_101(val, _values, result)
- builder = val[2]
- if !builder.line
- builder.line = @lexer.line - 1
- end
- result = val[0].append(builder)
+module_eval(<<'.,.,', 'parser.y', 384)
+ def _reduce_109(val, _values, result)
+ reset_precs
+ result = @grammar.create_rule_builder(@rule_counter, @midrule_action_counter)
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 326)
- def _reduce_102(val, _values, result)
- reset_precs
- result = @grammar.create_rule_builder(@rule_counter, @midrule_action_counter)
+module_eval(<<'.,.,', 'parser.y', 389)
+ def _reduce_110(val, _values, result)
+ builder = val[0]
+ builder.add_rhs(Lrama::Lexer::Token::Empty.new(location: @lexer.location))
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 331)
- def _reduce_103(val, _values, result)
- token = val[1]
- token.alias_name = val[2]
- builder = val[0]
- builder.add_rhs(token)
- result = builder
+module_eval(<<'.,.,', 'parser.y', 395)
+ def _reduce_111(val, _values, result)
+ on_action_error("intermediate %prec in a rule", val[1]) if @trailing_prec_seen
+ token = val[1]
+ token.alias_name = val[2]
+ builder = val[0]
+ builder.add_rhs(token)
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 339)
- def _reduce_104(val, _values, result)
- token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], alias_name: val[3], location: @lexer.location, args: [val[1]], lhs_tag: val[4])
- builder = val[0]
- builder.add_rhs(token)
- builder.line = val[1].first_line
- result = builder
+module_eval(<<'.,.,', 'parser.y', 404)
+ def _reduce_112(val, _values, result)
+ on_action_error("intermediate %prec in a rule", val[1]) if @trailing_prec_seen
+ token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2], alias_name: val[3], location: @lexer.location, args: [val[1]], lhs_tag: val[4])
+ builder = val[0]
+ builder.add_rhs(token)
+ builder.line = val[1].first_line
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 347)
- def _reduce_105(val, _values, result)
- token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, alias_name: val[5], location: @lexer.location, args: val[3], lhs_tag: val[6])
- builder = val[0]
- builder.add_rhs(token)
- builder.line = val[1].first_line
- result = builder
+module_eval(<<'.,.,', 'parser.y', 413)
+ def _reduce_113(val, _values, result)
+ on_action_error("intermediate %prec in a rule", val[1]) if @trailing_prec_seen
+ token = Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, alias_name: val[5], location: @lexer.location, args: val[3], lhs_tag: val[6])
+ builder = val[0]
+ builder.add_rhs(token)
+ builder.line = val[1].first_line
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 355)
- def _reduce_106(val, _values, result)
- user_code = val[1]
- user_code.alias_name = val[2]
- user_code.tag = val[3]
- builder = val[0]
- builder.user_code = user_code
- result = builder
+module_eval(<<'.,.,', 'parser.y', 422)
+ def _reduce_114(val, _values, result)
+ user_code = val[1]
+ user_code.alias_name = val[2]
+ user_code.tag = val[3]
+ builder = val[0]
+ builder.user_code = user_code
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 364)
- def _reduce_107(val, _values, result)
- sym = @grammar.find_symbol_by_id!(val[2])
- @prec_seen = true
- builder = val[0]
- builder.precedence_sym = sym
- result = builder
+module_eval(<<'.,.,', 'parser.y', 431)
+ def _reduce_115(val, _values, result)
+ on_action_error("multiple %prec in a rule", val[0]) if prec_seen?
+ sym = @grammar.find_symbol_by_id!(val[2])
+ if val[0].rhs.empty?
+ @opening_prec_seen = true
+ else
+ @trailing_prec_seen = true
+ end
+ builder = val[0]
+ builder.precedence_sym = sym
+ result = builder
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 371)
- def _reduce_108(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 444)
+ def _reduce_116(val, _values, result)
result = "option"
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 372)
- def _reduce_109(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 445)
+ def _reduce_117(val, _values, result)
result = "nonempty_list"
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 373)
- def _reduce_110(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 446)
+ def _reduce_118(val, _values, result)
result = "list"
result
end
.,.,
-# reduce 111 omitted
+# reduce 119 omitted
-# reduce 112 omitted
+# reduce 120 omitted
-module_eval(<<'.,.,', 'parser.y', 377)
- def _reduce_113(val, _values, result)
- result = if val[1]
- [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[0])]
- else
- [val[0]]
- end
+module_eval(<<'.,.,', 'parser.y', 451)
+ def _reduce_121(val, _values, result)
+ result = if val[1]
+ [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[1].s_value, location: @lexer.location, args: val[0])]
+ else
+ [val[0]]
+ end
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 383)
- def _reduce_114(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 457)
+ def _reduce_122(val, _values, result)
result = val[0].append(val[2])
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 384)
- def _reduce_115(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 458)
+ def _reduce_123(val, _values, result)
+ result = val[0].append(Lrama::Lexer::Token::InstantiateRule.new(s_value: val[2].s_value, location: @lexer.location, args: val[4]))
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'parser.y', 459)
+ def _reduce_124(val, _values, result)
result = [Lrama::Lexer::Token::InstantiateRule.new(s_value: val[0].s_value, location: @lexer.location, args: val[2])]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 388)
- def _reduce_116(val, _values, result)
- if @prec_seen
- on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec
- @code_after_prec = true
- end
- begin_c_declaration("}")
+module_eval(<<'.,.,', 'parser.y', 464)
+ def _reduce_125(val, _values, result)
+ if prec_seen?
+ on_action_error("multiple User_code after %prec", val[0]) if @code_after_prec
+ @code_after_prec = true
+ end
+ begin_c_declaration("}")
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 396)
- def _reduce_117(val, _values, result)
- end_c_declaration
+module_eval(<<'.,.,', 'parser.y', 472)
+ def _reduce_126(val, _values, result)
+ end_c_declaration
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 400)
- def _reduce_118(val, _values, result)
- result = val[2]
+module_eval(<<'.,.,', 'parser.y', 476)
+ def _reduce_127(val, _values, result)
+ result = val[2]
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 403)
- def _reduce_119(val, _values, result)
+module_eval(<<'.,.,', 'parser.y', 479)
+ def _reduce_128(val, _values, result)
result = val[1].s_value
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 407)
- def _reduce_120(val, _values, result)
- begin_c_declaration('\Z')
- @grammar.epilogue_first_lineno = @lexer.line + 1
+module_eval(<<'.,.,', 'parser.y', 484)
+ def _reduce_129(val, _values, result)
+ begin_c_declaration('\Z')
result
end
.,.,
-module_eval(<<'.,.,', 'parser.y', 412)
- def _reduce_121(val, _values, result)
- end_c_declaration
- @grammar.epilogue = val[2].s_value
+module_eval(<<'.,.,', 'parser.y', 488)
+ def _reduce_130(val, _values, result)
+ end_c_declaration
+ @grammar.epilogue_first_lineno = val[0].first_line + 1
+ @grammar.epilogue = val[2].s_value
result
end
.,.,
-# reduce 122 omitted
+# reduce 131 omitted
-# reduce 123 omitted
+# reduce 132 omitted
-# reduce 124 omitted
+# reduce 133 omitted
-# reduce 125 omitted
+# reduce 134 omitted
-# reduce 126 omitted
+# reduce 135 omitted
-module_eval(<<'.,.,', 'parser.y', 423)
- def _reduce_127(val, _values, result)
- result = Lrama::Lexer::Token::Ident.new(s_value: val[0])
+module_eval(<<'.,.,', 'parser.y', 500)
+ def _reduce_136(val, _values, result)
+ result = Lrama::Lexer::Token::Ident.new(s_value: val[0].s_value)
result
end
.,.,
diff --git a/tool/lrama/lib/lrama/report.rb b/tool/lrama/lib/lrama/report.rb
deleted file mode 100644
index 890e5f1e8c..0000000000
--- a/tool/lrama/lib/lrama/report.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'report/duration'
-require_relative 'report/profile'
diff --git a/tool/lrama/lib/lrama/report/duration.rb b/tool/lrama/lib/lrama/report/duration.rb
deleted file mode 100644
index fe09a0d028..0000000000
--- a/tool/lrama/lib/lrama/report/duration.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Report
- module Duration
- def self.enable
- @_report_duration_enabled = true
- end
-
- def self.enabled?
- !!@_report_duration_enabled
- end
-
- def report_duration(method_name)
- time1 = Time.now.to_f
- result = yield
- time2 = Time.now.to_f
-
- if Duration.enabled?
- puts sprintf("%s %10.5f s", method_name, time2 - time1)
- end
-
- return result
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/report/profile.rb b/tool/lrama/lib/lrama/report/profile.rb
deleted file mode 100644
index 10488cf913..0000000000
--- a/tool/lrama/lib/lrama/report/profile.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class Report
- module Profile
- # See "Profiling Lrama" in README.md for how to use.
- def self.report_profile
- require "stackprof"
-
- StackProf.run(mode: :cpu, raw: true, out: 'tmp/stackprof-cpu-myapp.dump') do
- yield
- end
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/reporter.rb b/tool/lrama/lib/lrama/reporter.rb
new file mode 100644
index 0000000000..ed25cc7f8f
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter.rb
@@ -0,0 +1,39 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+require_relative 'reporter/conflicts'
+require_relative 'reporter/grammar'
+require_relative 'reporter/precedences'
+require_relative 'reporter/profile'
+require_relative 'reporter/rules'
+require_relative 'reporter/states'
+require_relative 'reporter/terms'
+
+module Lrama
+ class Reporter
+ include Lrama::Tracer::Duration
+
+ # @rbs (**bool options) -> void
+ def initialize(**options)
+ @options = options
+ @rules = Rules.new(**options)
+ @terms = Terms.new(**options)
+ @conflicts = Conflicts.new
+ @precedences = Precedences.new
+ @grammar = Grammar.new(**options)
+ @states = States.new(**options)
+ end
+
+ # @rbs (File io, Lrama::States states) -> void
+ def report(io, states)
+ report_duration(:report) do
+ report_duration(:report_rules) { @rules.report(io, states) }
+ report_duration(:report_terms) { @terms.report(io, states) }
+ report_duration(:report_conflicts) { @conflicts.report(io, states) }
+ report_duration(:report_precedences) { @precedences.report(io, states) }
+ report_duration(:report_grammar) { @grammar.report(io, states) }
+ report_duration(:report_states) { @states.report(io, states, ielr: states.ielr_defined?) }
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/conflicts.rb b/tool/lrama/lib/lrama/reporter/conflicts.rb
new file mode 100644
index 0000000000..f4d8c604c9
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/conflicts.rb
@@ -0,0 +1,44 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ class Conflicts
+ # @rbs (IO io, Lrama::States states) -> void
+ def report(io, states)
+ report_conflicts(io, states)
+ end
+
+ private
+
+ # @rbs (IO io, Lrama::States states) -> void
+ def report_conflicts(io, states)
+ has_conflict = false
+
+ states.states.each do |state|
+ messages = format_conflict_messages(state.conflicts)
+
+ unless messages.empty?
+ has_conflict = true
+ io << "State #{state.id} conflicts: #{messages.join(', ')}\n"
+ end
+ end
+
+ io << "\n\n" if has_conflict
+ end
+
+ # @rbs (Array[(Lrama::State::ShiftReduceConflict | Lrama::State::ReduceReduceConflict)] conflicts) -> Array[String]
+ def format_conflict_messages(conflicts)
+ conflict_types = {
+ shift_reduce: "shift/reduce",
+ reduce_reduce: "reduce/reduce"
+ }
+
+ conflict_types.keys.map do |type|
+ type_conflicts = conflicts.select { |c| c.type == type }
+ "#{type_conflicts.count} #{conflict_types[type]}" unless type_conflicts.empty?
+ end.compact
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/grammar.rb b/tool/lrama/lib/lrama/reporter/grammar.rb
new file mode 100644
index 0000000000..dc3f3f6bfd
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/grammar.rb
@@ -0,0 +1,39 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ class Grammar
+ # @rbs (?grammar: bool, **bool _) -> void
+ def initialize(grammar: false, **_)
+ @grammar = grammar
+ end
+
+ # @rbs (IO io, Lrama::States states) -> void
+ def report(io, states)
+ return unless @grammar
+
+ io << "Grammar\n"
+ last_lhs = nil
+
+ states.rules.each do |rule|
+ if rule.empty_rule?
+ r = "ε"
+ else
+ r = rule.rhs.map(&:display_name).join(" ")
+ end
+
+ if rule.lhs == last_lhs
+ io << sprintf("%5d %s| %s", rule.id, " " * rule.lhs.display_name.length, r) << "\n"
+ else
+ io << "\n"
+ io << sprintf("%5d %s: %s", rule.id, rule.lhs.display_name, r) << "\n"
+ end
+
+ last_lhs = rule.lhs
+ end
+ io << "\n\n"
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/precedences.rb b/tool/lrama/lib/lrama/reporter/precedences.rb
new file mode 100644
index 0000000000..73c0888700
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/precedences.rb
@@ -0,0 +1,54 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ class Precedences
+ # @rbs (IO io, Lrama::States states) -> void
+ def report(io, states)
+ report_precedences(io, states)
+ end
+
+ private
+
+ # @rbs (IO io, Lrama::States states) -> void
+ def report_precedences(io, states)
+ used_precedences = states.precedences.select(&:used_by?)
+
+ return if used_precedences.empty?
+
+ io << "Precedences\n\n"
+
+ used_precedences.each do |precedence|
+ io << " precedence on #{precedence.symbol.display_name} is used to resolve conflict on\n"
+
+ if precedence.used_by_lalr?
+ io << " LALR\n"
+
+ precedence.used_by_lalr.uniq.sort_by do |resolved_conflict|
+ resolved_conflict.state.id
+ end.each do |resolved_conflict|
+ io << " state #{resolved_conflict.state.id}. #{resolved_conflict.report_precedences_message}\n"
+ end
+
+ io << "\n"
+ end
+
+ if precedence.used_by_ielr?
+ io << " IELR\n"
+
+ precedence.used_by_ielr.uniq.sort_by do |resolved_conflict|
+ resolved_conflict.state.id
+ end.each do |resolved_conflict|
+ io << " state #{resolved_conflict.state.id}. #{resolved_conflict.report_precedences_message}\n"
+ end
+
+ io << "\n"
+ end
+ end
+
+ io << "\n"
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/profile.rb b/tool/lrama/lib/lrama/reporter/profile.rb
new file mode 100644
index 0000000000..b569b94d4f
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/profile.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+require_relative 'profile/call_stack'
+require_relative 'profile/memory'
diff --git a/tool/lrama/lib/lrama/reporter/profile/call_stack.rb b/tool/lrama/lib/lrama/reporter/profile/call_stack.rb
new file mode 100644
index 0000000000..8a4d44b61c
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/profile/call_stack.rb
@@ -0,0 +1,45 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ module Profile
+ module CallStack
+ # See "Call-stack Profiling Lrama" in README.md for how to use.
+ #
+ # @rbs enabled: bool
+ # @rbs &: -> void
+ # @rbs return: StackProf::result | void
+ def self.report(enabled)
+ if enabled && require_stackprof
+ ex = nil #: Exception?
+ path = 'tmp/stackprof-cpu-myapp.dump'
+
+ StackProf.run(mode: :cpu, raw: true, out: path) do
+ yield
+ rescue Exception => e
+ ex = e
+ end
+
+ STDERR.puts("Call-stack Profiling result is generated on #{path}")
+
+ if ex
+ raise ex
+ end
+ else
+ yield
+ end
+ end
+
+ # @rbs return: bool
+ def self.require_stackprof
+ require "stackprof"
+ true
+ rescue LoadError
+ warn "stackprof is not installed. Please run `bundle install`."
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/profile/memory.rb b/tool/lrama/lib/lrama/reporter/profile/memory.rb
new file mode 100644
index 0000000000..a019581fdf
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/profile/memory.rb
@@ -0,0 +1,44 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ module Profile
+ module Memory
+ # See "Memory Profiling Lrama" in README.md for how to use.
+ #
+ # @rbs enabled: bool
+ # @rbs &: -> void
+ # @rbs return: StackProf::result | void
+ def self.report(enabled)
+ if enabled && require_memory_profiler
+ ex = nil #: Exception?
+
+ report = MemoryProfiler.report do # steep:ignore UnknownConstant
+ yield
+ rescue Exception => e
+ ex = e
+ end
+
+ report.pretty_print(to_file: "tmp/memory_profiler.txt")
+
+ if ex
+ raise ex
+ end
+ else
+ yield
+ end
+ end
+
+ # @rbs return: bool
+ def self.require_memory_profiler
+ require "memory_profiler"
+ true
+ rescue LoadError
+ warn "memory_profiler is not installed. Please run `bundle install`."
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/rules.rb b/tool/lrama/lib/lrama/reporter/rules.rb
new file mode 100644
index 0000000000..3e8bf19a0a
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/rules.rb
@@ -0,0 +1,43 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ class Rules
+ # @rbs (?rules: bool, **bool _) -> void
+ def initialize(rules: false, **_)
+ @rules = rules
+ end
+
+ # @rbs (IO io, Lrama::States states) -> void
+ def report(io, states)
+ return unless @rules
+
+ used_rules = states.rules.flat_map(&:rhs)
+
+ unless used_rules.empty?
+ io << "Rule Usage Frequency\n\n"
+ frequency_counts = used_rules.each_with_object(Hash.new(0)) { |rule, counts| counts[rule] += 1 }
+
+ frequency_counts
+ .select { |rule,| !rule.midrule? }
+ .sort_by { |rule, count| [-count, rule.name] }
+ .each_with_index { |(rule, count), i| io << sprintf("%5d %s (%d times)", i, rule.name, count) << "\n" }
+ io << "\n\n"
+ end
+
+ unused_rules = states.rules.map(&:lhs).select do |rule|
+ !used_rules.include?(rule) && rule.token_id != 0
+ end
+
+ unless unused_rules.empty?
+ io << "#{unused_rules.count} Unused Rules\n\n"
+ unused_rules.each_with_index do |rule, index|
+ io << sprintf("%5d %s", index, rule.display_name) << "\n"
+ end
+ io << "\n\n"
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/states.rb b/tool/lrama/lib/lrama/reporter/states.rb
new file mode 100644
index 0000000000..d152d0511a
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/states.rb
@@ -0,0 +1,387 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ class States
+ # @rbs (?itemsets: bool, ?lookaheads: bool, ?solved: bool, ?counterexamples: bool, ?verbose: bool, **bool _) -> void
+ def initialize(itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false, **_)
+ @itemsets = itemsets
+ @lookaheads = lookaheads
+ @solved = solved
+ @counterexamples = counterexamples
+ @verbose = verbose
+ end
+
+ # @rbs (IO io, Lrama::States states, ielr: bool) -> void
+ def report(io, states, ielr: false)
+ cex = Counterexamples.new(states) if @counterexamples
+
+ states.compute_la_sources_for_conflicted_states
+ report_split_states(io, states.states) if ielr
+
+ states.states.each do |state|
+ report_state_header(io, state)
+ report_items(io, state)
+ report_conflicts(io, state)
+ report_shifts(io, state)
+ report_nonassoc_errors(io, state)
+ report_reduces(io, state)
+ report_nterm_transitions(io, state)
+ report_conflict_resolutions(io, state) if @solved
+ report_counterexamples(io, state, cex) if @counterexamples && state.has_conflicts? # @type var cex: Lrama::Counterexamples
+ report_verbose_info(io, state, states) if @verbose
+ # End of Report State
+ io << "\n"
+ end
+ end
+
+ private
+
+ # @rbs (IO io, Array[Lrama::State] states) -> void
+ def report_split_states(io, states)
+ ss = states.select(&:split_state?)
+
+ return if ss.empty?
+
+ io << "Split States\n\n"
+
+ ss.each do |state|
+ io << " State #{state.id} is split from state #{state.lalr_isocore.id}\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_state_header(io, state)
+ io << "State #{state.id}\n\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_items(io, state)
+ last_lhs = nil
+ list = @itemsets ? state.items : state.kernels
+
+ list.sort_by {|i| [i.rule_id, i.position] }.each do |item|
+ r = item.empty_rule? ? "ε •" : item.rhs.map(&:display_name).insert(item.position, "•").join(" ")
+
+ l = if item.lhs == last_lhs
+ " " * item.lhs.id.s_value.length + "|"
+ else
+ item.lhs.id.s_value + ":"
+ end
+
+ la = ""
+ if @lookaheads && item.end_of_rule?
+ reduce = state.find_reduce_by_item!(item)
+ look_ahead = reduce.selected_look_ahead
+ unless look_ahead.empty?
+ la = " [#{look_ahead.compact.map(&:display_name).join(", ")}]"
+ end
+ end
+
+ last_lhs = item.lhs
+ io << sprintf("%5i %s %s%s", item.rule_id, l, r, la) << "\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_conflicts(io, state)
+ return if state.conflicts.empty?
+
+ state.conflicts.each do |conflict|
+ syms = conflict.symbols.map { |sym| sym.display_name }
+ io << " Conflict on #{syms.join(", ")}. "
+
+ case conflict.type
+ when :shift_reduce
+ # @type var conflict: Lrama::State::ShiftReduceConflict
+ io << "shift/reduce(#{conflict.reduce.item.rule.lhs.display_name})\n"
+
+ conflict.symbols.each do |token|
+ conflict.reduce.look_ahead_sources[token].each do |goto| # steep:ignore NoMethod
+ io << " #{token.display_name} comes from state #{goto.from_state.id} goto by #{goto.next_sym.display_name}\n"
+ end
+ end
+ when :reduce_reduce
+ # @type var conflict: Lrama::State::ReduceReduceConflict
+ io << "reduce(#{conflict.reduce1.item.rule.lhs.display_name})/reduce(#{conflict.reduce2.item.rule.lhs.display_name})\n"
+
+ conflict.symbols.each do |token|
+ conflict.reduce1.look_ahead_sources[token].each do |goto| # steep:ignore NoMethod
+ io << " #{token.display_name} comes from state #{goto.from_state.id} goto by #{goto.next_sym.display_name}\n"
+ end
+
+ conflict.reduce2.look_ahead_sources[token].each do |goto| # steep:ignore NoMethod
+ io << " #{token.display_name} comes from state #{goto.from_state.id} goto by #{goto.next_sym.display_name}\n"
+ end
+ end
+ else
+ raise "Unknown conflict type #{conflict.type}"
+ end
+
+ io << "\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_shifts(io, state)
+ shifts = state.term_transitions.reject(&:not_selected)
+
+ return if shifts.empty?
+
+ next_syms = shifts.map(&:next_sym)
+ max_len = next_syms.map(&:display_name).map(&:length).max
+ shifts.each do |shift|
+ io << " #{shift.next_sym.display_name.ljust(max_len)} shift, and go to state #{shift.to_state.id}\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_nonassoc_errors(io, state)
+ error_symbols = state.resolved_conflicts.select { |resolved| resolved.which == :error }.map { |error| error.symbol.display_name }
+
+ return if error_symbols.empty?
+
+ max_len = error_symbols.map(&:length).max
+ error_symbols.each do |name|
+ io << " #{name.ljust(max_len)} error (nonassociative)\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_reduces(io, state)
+ reduce_pairs = [] #: Array[[Lrama::Grammar::Symbol, Lrama::State::Action::Reduce]]
+
+ state.non_default_reduces.each do |reduce|
+ reduce.look_ahead&.each do |term|
+ reduce_pairs << [term, reduce]
+ end
+ end
+
+ return if reduce_pairs.empty? && !state.default_reduction_rule
+
+ max_len = [
+ reduce_pairs.map(&:first).map(&:display_name).map(&:length).max || 0,
+ state.default_reduction_rule ? "$default".length : 0
+ ].max
+
+ reduce_pairs.sort_by { |term, _| term.number }.each do |term, reduce|
+ rule = reduce.item.rule
+ io << " #{term.display_name.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.display_name})\n"
+ end
+
+ if (r = state.default_reduction_rule)
+ s = "$default".ljust(max_len)
+
+ if r.initial_rule?
+ io << " #{s} accept\n"
+ else
+ io << " #{s} reduce using rule #{r.id} (#{r.lhs.display_name})\n"
+ end
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_nterm_transitions(io, state)
+ return if state.nterm_transitions.empty?
+
+ goto_transitions = state.nterm_transitions.sort_by do |goto|
+ goto.next_sym.number
+ end
+
+ max_len = goto_transitions.map(&:next_sym).map do |nterm|
+ nterm.id.s_value.length
+ end.max
+ goto_transitions.each do |goto|
+ io << " #{goto.next_sym.id.s_value.ljust(max_len)} go to state #{goto.to_state.id}\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state) -> void
+ def report_conflict_resolutions(io, state)
+ return if state.resolved_conflicts.empty?
+
+ state.resolved_conflicts.each do |resolved|
+ io << " #{resolved.report_message}\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::Counterexamples cex) -> void
+ def report_counterexamples(io, state, cex)
+ examples = cex.compute(state)
+
+ examples.each do |example|
+ is_shift_reduce = example.type == :shift_reduce
+ label0 = is_shift_reduce ? "shift/reduce" : "reduce/reduce"
+ label1 = is_shift_reduce ? "Shift derivation" : "First Reduce derivation"
+ label2 = is_shift_reduce ? "Reduce derivation" : "Second Reduce derivation"
+
+ io << " #{label0} conflict on token #{example.conflict_symbol.id.s_value}:\n"
+ io << " #{example.path1_item}\n"
+ io << " #{example.path2_item}\n"
+ io << " #{label1}\n"
+
+ example.derivations1.render_strings_for_report.each do |str|
+ io << " #{str}\n"
+ end
+
+ io << " #{label2}\n"
+
+ example.derivations2.render_strings_for_report.each do |str|
+ io << " #{str}\n"
+ end
+ end
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_verbose_info(io, state, states)
+ report_direct_read_sets(io, state, states)
+ report_reads_relation(io, state, states)
+ report_read_sets(io, state, states)
+ report_includes_relation(io, state, states)
+ report_lookback_relation(io, state, states)
+ report_follow_sets(io, state, states)
+ report_look_ahead_sets(io, state, states)
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_direct_read_sets(io, state, states)
+ io << " [Direct Read sets]\n"
+ direct_read_sets = states.direct_read_sets
+
+ state.nterm_transitions.each do |goto|
+ terms = direct_read_sets[goto]
+ next unless terms && !terms.empty?
+
+ str = terms.map { |sym| sym.id.s_value }.join(", ")
+ io << " read #{goto.next_sym.id.s_value} shift #{str}\n"
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_reads_relation(io, state, states)
+ io << " [Reads Relation]\n"
+
+ state.nterm_transitions.each do |goto|
+ goto2 = states.reads_relation[goto]
+ next unless goto2
+
+ goto2.each do |goto2|
+ io << " (State #{goto2.from_state.id}, #{goto2.next_sym.id.s_value})\n"
+ end
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_read_sets(io, state, states)
+ io << " [Read sets]\n"
+ read_sets = states.read_sets
+
+ state.nterm_transitions.each do |goto|
+ terms = read_sets[goto]
+ next unless terms && !terms.empty?
+
+ terms.each do |sym|
+ io << " #{sym.id.s_value}\n"
+ end
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_includes_relation(io, state, states)
+ io << " [Includes Relation]\n"
+
+ state.nterm_transitions.each do |goto|
+ gotos = states.includes_relation[goto]
+ next unless gotos
+
+ gotos.each do |goto2|
+ io << " (State #{state.id}, #{goto.next_sym.id.s_value}) -> (State #{goto2.from_state.id}, #{goto2.next_sym.id.s_value})\n"
+ end
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_lookback_relation(io, state, states)
+ io << " [Lookback Relation]\n"
+
+ states.rules.each do |rule|
+ gotos = states.lookback_relation.dig(state.id, rule.id)
+ next unless gotos
+
+ gotos.each do |goto2|
+ io << " (Rule: #{rule.display_name}) -> (State #{goto2.from_state.id}, #{goto2.next_sym.id.s_value})\n"
+ end
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_follow_sets(io, state, states)
+ io << " [Follow sets]\n"
+ follow_sets = states.follow_sets
+
+ state.nterm_transitions.each do |goto|
+ terms = follow_sets[goto]
+ next unless terms
+
+ terms.each do |sym|
+ io << " #{goto.next_sym.id.s_value} -> #{sym.id.s_value}\n"
+ end
+ end
+
+ io << "\n"
+ end
+
+ # @rbs (IO io, Lrama::State state, Lrama::States states) -> void
+ def report_look_ahead_sets(io, state, states)
+ io << " [Look-Ahead Sets]\n"
+ look_ahead_rules = [] #: Array[[Lrama::Grammar::Rule, Array[Lrama::Grammar::Symbol]]]
+
+ states.rules.each do |rule|
+ syms = states.la.dig(state.id, rule.id)
+ next unless syms
+
+ look_ahead_rules << [rule, syms]
+ end
+
+ return if look_ahead_rules.empty?
+
+ max_len = look_ahead_rules.flat_map { |_, syms| syms.map { |s| s.id.s_value.length } }.max
+
+ look_ahead_rules.each do |rule, syms|
+ syms.each do |sym|
+ io << " #{sym.id.s_value.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n"
+ end
+ end
+
+ io << "\n"
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/reporter/terms.rb b/tool/lrama/lib/lrama/reporter/terms.rb
new file mode 100644
index 0000000000..f72d8b1a1a
--- /dev/null
+++ b/tool/lrama/lib/lrama/reporter/terms.rb
@@ -0,0 +1,44 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Reporter
+ class Terms
+ # @rbs (?terms: bool, **bool _) -> void
+ def initialize(terms: false, **_)
+ @terms = terms
+ end
+
+ # @rbs (IO io, Lrama::States states) -> void
+ def report(io, states)
+ return unless @terms
+
+ look_aheads = states.states.each do |state|
+ state.reduces.flat_map do |reduce|
+ reduce.look_ahead unless reduce.look_ahead.nil?
+ end
+ end
+
+ next_terms = states.states.flat_map do |state|
+ state.term_transitions.map {|shift| shift.next_sym }
+ end
+
+ unused_symbols = states.terms.reject do |term|
+ (look_aheads + next_terms).include?(term)
+ end
+
+ io << states.terms.count << " Terms\n\n"
+
+ io << states.nterms.count << " Non-Terminals\n\n"
+
+ unless unused_symbols.empty?
+ io << "#{unused_symbols.count} Unused Terms\n\n"
+ unused_symbols.each_with_index do |term, index|
+ io << sprintf("%5d %s", index, term.id.s_value) << "\n"
+ end
+ io << "\n\n"
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/state.rb b/tool/lrama/lib/lrama/state.rb
index 3008786ced..50912e094e 100644
--- a/tool/lrama/lib/lrama/state.rb
+++ b/tool/lrama/lib/lrama/state.rb
@@ -1,17 +1,62 @@
+# rbs_inline: enabled
# frozen_string_literal: true
-require_relative "state/reduce"
+require_relative "state/action"
+require_relative "state/inadequacy_annotation"
+require_relative "state/item"
require_relative "state/reduce_reduce_conflict"
require_relative "state/resolved_conflict"
-require_relative "state/shift"
require_relative "state/shift_reduce_conflict"
module Lrama
class State
- attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
- :default_reduction_rule, :closure, :items
- attr_accessor :shifts, :reduces, :ielr_isocores, :lalr_isocore
-
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # type conflict = State::ShiftReduceConflict | State::ReduceReduceConflict
+ # type transition = Action::Shift | Action::Goto
+ # type lookahead_set = Hash[Item, Array[Grammar::Symbol]]
+ #
+ # @id: Integer
+ # @accessing_symbol: Grammar::Symbol
+ # @kernels: Array[Item]
+ # @items: Array[Item]
+ # @items_to_state: Hash[Array[Item], State]
+ # @conflicts: Array[conflict]
+ # @resolved_conflicts: Array[ResolvedConflict]
+ # @default_reduction_rule: Grammar::Rule?
+ # @closure: Array[Item]
+ # @nterm_transitions: Array[Action::Goto]
+ # @term_transitions: Array[Action::Shift]
+ # @transitions: Array[transition]
+ # @internal_dependencies: Hash[Action::Goto, Array[Action::Goto]]
+ # @successor_dependencies: Hash[Action::Goto, Array[Action::Goto]]
+
+ attr_reader :id #: Integer
+ attr_reader :accessing_symbol #: Grammar::Symbol
+ attr_reader :kernels #: Array[Item]
+ attr_reader :conflicts #: Array[conflict]
+ attr_reader :resolved_conflicts #: Array[ResolvedConflict]
+ attr_reader :default_reduction_rule #: Grammar::Rule?
+ attr_reader :closure #: Array[Item]
+ attr_reader :items #: Array[Item]
+ attr_reader :annotation_list #: Array[InadequacyAnnotation]
+ attr_reader :predecessors #: Array[State]
+ attr_reader :items_to_state #: Hash[Array[Item], State]
+ attr_reader :lane_items #: Hash[State, Array[[Item, Item]]]
+
+ attr_accessor :_transitions #: Array[[Grammar::Symbol, Array[Item]]]
+ attr_accessor :reduces #: Array[Action::Reduce]
+ attr_accessor :ielr_isocores #: Array[State]
+ attr_accessor :lalr_isocore #: State
+ attr_accessor :lookaheads_recomputed #: bool
+ attr_accessor :follow_kernel_items #: Hash[Action::Goto, Hash[Item, bool]]
+ attr_accessor :always_follows #: Hash[Action::Goto, Array[Grammar::Symbol]]
+ attr_accessor :goto_follows #: Hash[Action::Goto, Array[Grammar::Symbol]]
+
+ # @rbs (Integer id, Grammar::Symbol accessing_symbol, Array[Item] kernels) -> void
def initialize(id, accessing_symbol, kernels)
@id = id
@accessing_symbol = accessing_symbol
@@ -28,48 +73,72 @@ module Lrama
@ielr_isocores = [self]
@internal_dependencies = {}
@successor_dependencies = {}
+ @annotation_list = []
+ @lookaheads_recomputed = false
+ @follow_kernel_items = {}
@always_follows = {}
+ @goto_follows = {}
+ @lhs_contributions = {}
+ @lane_items = {}
+ end
+
+ # @rbs (State other) -> bool
+ def ==(other)
+ self.id == other.id
end
+ # @rbs (Array[Item] closure) -> void
def closure=(closure)
@closure = closure
@items = @kernels + @closure
end
+ # @rbs () -> Array[Action::Reduce]
def non_default_reduces
reduces.reject do |reduce|
reduce.rule == @default_reduction_rule
end
end
- def compute_shifts_reduces
- _shifts = {}
+ # @rbs () -> void
+ def compute_transitions_and_reduces
+ _transitions = {}
+ @_lane_items ||= {}
reduces = []
items.each do |item|
# TODO: Consider what should be pushed
if item.end_of_rule?
- reduces << Reduce.new(item)
+ reduces << Action::Reduce.new(item)
else
key = item.next_sym
- _shifts[key] ||= []
- _shifts[key] << item.new_by_next_position
+ _transitions[key] ||= []
+ @_lane_items[key] ||= []
+ next_item = item.new_by_next_position
+ _transitions[key] << next_item
+ @_lane_items[key] << [item, next_item]
end
end
# It seems Bison 3.8.2 iterates transitions order by symbol number
- shifts = _shifts.sort_by do |next_sym, new_items|
+ transitions = _transitions.sort_by do |next_sym, to_items|
next_sym.number
- end.map do |next_sym, new_items|
- Shift.new(next_sym, new_items.flatten)
end
- self.shifts = shifts.freeze
+
+ self._transitions = transitions.freeze
self.reduces = reduces.freeze
end
+ # @rbs (Grammar::Symbol next_sym, State next_state) -> void
+ def set_lane_items(next_sym, next_state)
+ @lane_items[next_state] = @_lane_items[next_sym]
+ end
+
+ # @rbs (Array[Item] items, State next_state) -> void
def set_items_to_state(items, next_state)
@items_to_state[items] = next_state
end
+ # @rbs (Grammar::Rule rule, Array[Grammar::Symbol] look_ahead) -> void
def set_look_ahead(rule, look_ahead)
reduce = reduces.find do |r|
r.rule == rule
@@ -78,50 +147,78 @@ module Lrama
reduce.look_ahead = look_ahead
end
- def nterm_transitions
- @nterm_transitions ||= transitions.select {|shift, _| shift.next_sym.nterm? }
+ # @rbs (Grammar::Rule rule, Hash[Grammar::Symbol, Array[Action::Goto]] sources) -> void
+ def set_look_ahead_sources(rule, sources)
+ reduce = reduces.find do |r|
+ r.rule == rule
+ end
+
+ reduce.look_ahead_sources = sources
+ end
+
+ # @rbs () -> Array[Action::Goto]
+ def nterm_transitions # steep:ignore
+ @nterm_transitions ||= transitions.select {|transition| transition.is_a?(Action::Goto) }
end
- def term_transitions
- @term_transitions ||= transitions.select {|shift, _| shift.next_sym.term? }
+ # @rbs () -> Array[Action::Shift]
+ def term_transitions # steep:ignore
+ @term_transitions ||= transitions.select {|transition| transition.is_a?(Action::Shift) }
end
+ # @rbs () -> Array[transition]
def transitions
- @transitions ||= shifts.map {|shift| [shift, @items_to_state[shift.next_items]] }
+ @transitions ||= _transitions.map do |next_sym, to_items|
+ if next_sym.term?
+ Action::Shift.new(self, next_sym, to_items.flatten, @items_to_state[to_items])
+ else
+ Action::Goto.new(self, next_sym, to_items.flatten, @items_to_state[to_items])
+ end
+ end
end
- def update_transition(shift, next_state)
- set_items_to_state(shift.next_items, next_state)
+ # @rbs (transition transition, State next_state) -> void
+ def update_transition(transition, next_state)
+ set_items_to_state(transition.to_items, next_state)
next_state.append_predecessor(self)
- clear_transitions_cache
+ update_transitions_caches(transition)
end
- def clear_transitions_cache
+ # @rbs () -> void
+ def update_transitions_caches(transition)
+ new_transition =
+ if transition.next_sym.term?
+ Action::Shift.new(self, transition.next_sym, transition.to_items, @items_to_state[transition.to_items])
+ else
+ Action::Goto.new(self, transition.next_sym, transition.to_items, @items_to_state[transition.to_items])
+ end
+
+ @transitions.delete(transition)
+ @transitions << new_transition
@nterm_transitions = nil
@term_transitions = nil
- @transitions = nil
+
+ @follow_kernel_items[new_transition] = @follow_kernel_items.delete(transition)
+ @always_follows[new_transition] = @always_follows.delete(transition)
end
+ # @rbs () -> Array[Action::Shift]
def selected_term_transitions
- term_transitions.reject do |shift, next_state|
+ term_transitions.reject do |shift|
shift.not_selected
end
end
# Move to next state by sym
+ #
+ # @rbs (Grammar::Symbol sym) -> State
def transition(sym)
result = nil
if sym.term?
- term_transitions.each do |shift, next_state|
- term = shift.next_sym
- result = next_state if term == sym
- end
+ result = term_transitions.find {|shift| shift.next_sym == sym }.to_state
else
- nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
- result = next_state if nterm == sym
- end
+ result = nterm_transitions.find {|goto| goto.next_sym == sym }.to_state
end
raise "Can not transit by #{sym} #{self}" if result.nil?
@@ -129,12 +226,14 @@ module Lrama
result
end
+ # @rbs (Item item) -> Action::Reduce
def find_reduce_by_item!(item)
reduces.find do |r|
r.item == item
end || (raise "reduce is not found. #{item}")
end
+ # @rbs (Grammar::Rule default_reduction_rule) -> void
def default_reduction_rule=(default_reduction_rule)
@default_reduction_rule = default_reduction_rule
@@ -145,200 +244,219 @@ module Lrama
end
end
+ # @rbs () -> bool
def has_conflicts?
!@conflicts.empty?
end
+ # @rbs () -> Array[conflict]
def sr_conflicts
@conflicts.select do |conflict|
conflict.type == :shift_reduce
end
end
+ # @rbs () -> Array[conflict]
def rr_conflicts
@conflicts.select do |conflict|
conflict.type == :reduce_reduce
end
end
+ # Clear information related to conflicts.
+ # IELR computation re-calculates conflicts and default reduction of states
+ # after LALR computation.
+ # Call this method before IELR computation to avoid duplicated conflicts information
+ # is stored.
+ #
+ # @rbs () -> void
+ def clear_conflicts
+ @conflicts = []
+ @resolved_conflicts = []
+ @default_reduction_rule = nil
+
+ term_transitions.each(&:clear_conflicts)
+ reduces.each(&:clear_conflicts)
+ end
+
+ # @rbs () -> bool
+ def split_state?
+ @lalr_isocore != self
+ end
+
+ # Definition 3.40 (propagate_lookaheads)
+ #
+ # @rbs (State next_state) -> lookahead_set
def propagate_lookaheads(next_state)
- next_state.kernels.map {|item|
+ next_state.kernels.map {|next_kernel|
lookahead_sets =
- if item.position == 1
- goto_follow_set(item.lhs)
- else
- kernel = kernels.find {|k| k.predecessor_item_of?(item) }
+ if next_kernel.position > 1
+ kernel = kernels.find {|k| k.predecessor_item_of?(next_kernel) }
item_lookahead_set[kernel]
+ else
+ goto_follow_set(next_kernel.lhs)
end
- [item, lookahead_sets & next_state.lookahead_set_filters[item]]
+ [next_kernel, lookahead_sets & next_state.lookahead_set_filters[next_kernel]]
}.to_h
end
- def lookaheads_recomputed
- !@item_lookahead_set.nil?
- end
-
- def compatible_lookahead?(filtered_lookahead)
+ # Definition 3.43 (is_compatible)
+ #
+ # @rbs (lookahead_set filtered_lookahead) -> bool
+ def is_compatible?(filtered_lookahead)
!lookaheads_recomputed ||
- @lalr_isocore.annotation_list.all? {|token, actions|
- a = dominant_contribution(token, actions, item_lookahead_set)
- b = dominant_contribution(token, actions, filtered_lookahead)
+ @lalr_isocore.annotation_list.all? {|annotation|
+ a = annotation.dominant_contribution(item_lookahead_set)
+ b = annotation.dominant_contribution(filtered_lookahead)
a.nil? || b.nil? || a == b
}
end
+ # Definition 3.38 (lookahead_set_filters)
+ #
+ # @rbs () -> lookahead_set
def lookahead_set_filters
- kernels.map {|kernel|
- [kernel,
- @lalr_isocore.annotation_list.select {|token, actions|
- token.term? && actions.any? {|action, contributions|
- !contributions.nil? && contributions.key?(kernel) && contributions[kernel]
- }
- }.map {|token, _| token }
- ]
+ @lookahead_set_filters ||= kernels.map {|kernel|
+ [kernel, @lalr_isocore.annotation_list.select {|annotation| annotation.contributed?(kernel) }.map(&:token)]
}.to_h
end
- def dominant_contribution(token, actions, lookaheads)
- a = actions.select {|action, contributions|
- contributions.nil? || contributions.any? {|item, contributed| contributed && lookaheads[item].include?(token) }
- }.map {|action, _| action }
- return nil if a.empty?
- a.reject {|action|
- if action.is_a?(State::Shift)
- action.not_selected
- elsif action.is_a?(State::Reduce)
- action.not_selected_symbols.include?(token)
- end
- }
- end
-
+ # Definition 3.27 (inadequacy_lists)
+ #
+ # @rbs () -> Hash[Grammar::Symbol, Array[Action::Shift | Action::Reduce]]
def inadequacy_list
return @inadequacy_list if @inadequacy_list
- shift_contributions = shifts.map {|shift|
- [shift.next_sym, [shift]]
- }.to_h
- reduce_contributions = reduces.map {|reduce|
- (reduce.look_ahead || []).map {|sym|
- [sym, [reduce]]
- }.to_h
- }.reduce(Hash.new([])) {|hash, cont|
- hash.merge(cont) {|_, a, b| a | b }
- }
+ inadequacy_list = {}
- list = shift_contributions.merge(reduce_contributions) {|_, a, b| a | b }
- @inadequacy_list = list.select {|token, actions| token.term? && actions.size > 1 }
- end
-
- def annotation_list
- return @annotation_list if @annotation_list
-
- @annotation_list = annotate_manifestation
- @annotation_list = @items_to_state.values.map {|next_state| next_state.annotate_predecessor(self) }
- .reduce(@annotation_list) {|result, annotations|
- result.merge(annotations) {|_, actions_a, actions_b|
- if actions_a.nil? || actions_b.nil?
- actions_a || actions_b
- else
- actions_a.merge(actions_b) {|_, contributions_a, contributions_b|
- if contributions_a.nil? || contributions_b.nil?
- next contributions_a || contributions_b
- end
-
- contributions_a.merge(contributions_b) {|_, contributed_a, contributed_b|
- contributed_a || contributed_b
- }
- }
- end
- }
- }
+ term_transitions.each do |shift|
+ inadequacy_list[shift.next_sym] ||= []
+ inadequacy_list[shift.next_sym] << shift.dup
+ end
+ reduces.each do |reduce|
+ next if reduce.look_ahead.nil?
+
+ reduce.look_ahead.each do |token|
+ inadequacy_list[token] ||= []
+ inadequacy_list[token] << reduce.dup
+ end
+ end
+
+ @inadequacy_list = inadequacy_list.select {|token, actions| actions.size > 1 }
end
+ # Definition 3.30 (annotate_manifestation)
+ #
+ # @rbs () -> void
def annotate_manifestation
- inadequacy_list.transform_values {|actions|
- actions.map {|action|
- if action.is_a?(Shift)
+ inadequacy_list.each {|token, actions|
+ contribution_matrix = actions.map {|action|
+ if action.is_a?(Action::Shift)
[action, nil]
- elsif action.is_a?(Reduce)
- if action.rule.empty_rule?
- [action, lhs_contributions(action.rule.lhs, inadequacy_list.key(actions))]
- else
- contributions = kernels.map {|kernel| [kernel, kernel.rule == action.rule && kernel.end_of_rule?] }.to_h
- [action, contributions]
- end
+ else
+ [action, action.rule.empty_rule? ? lhs_contributions(action.rule.lhs, token) : kernels.map {|k| [k, k.rule == action.item.rule && k.end_of_rule?] }.to_h]
end
}.to_h
+ @annotation_list << InadequacyAnnotation.new(self, token, actions, contribution_matrix)
}
end
+ # Definition 3.32 (annotate_predecessor)
+ #
+ # @rbs (State predecessor) -> void
def annotate_predecessor(predecessor)
- annotation_list.transform_values {|actions|
- token = annotation_list.key(actions)
- actions.transform_values {|inadequacy|
- next nil if inadequacy.nil?
- lhs_adequacy = kernels.any? {|kernel|
- inadequacy[kernel] && kernel.position == 1 && predecessor.lhs_contributions(kernel.lhs, token).nil?
- }
- if lhs_adequacy
- next nil
+ propagating_list = annotation_list.map {|annotation|
+ contribution_matrix = annotation.contribution_matrix.map {|action, contributions|
+ if contributions.nil?
+ [action, nil]
+ elsif first_kernels.any? {|kernel| contributions[kernel] && predecessor.lhs_contributions(kernel.lhs, annotation.token).empty? }
+ [action, nil]
else
- predecessor.kernels.map {|pred_k|
- [pred_k, kernels.any? {|k|
- inadequacy[k] && (
- pred_k.predecessor_item_of?(k) && predecessor.item_lookahead_set[pred_k].include?(token) ||
- k.position == 1 && predecessor.lhs_contributions(k.lhs, token)[pred_k]
- )
- }]
+ cs = predecessor.lane_items[self].map {|pred_kernel, kernel|
+ c = contributions[kernel] && (
+ (kernel.position > 1 && predecessor.item_lookahead_set[pred_kernel].include?(annotation.token)) ||
+ (kernel.position == 1 && predecessor.lhs_contributions(kernel.lhs, annotation.token)[pred_kernel])
+ )
+ [pred_kernel, c]
}.to_h
+ [action, cs]
end
- }
- }
+ }.to_h
+
+ # Observation 3.33 (Simple Split-Stable Dominance)
+ #
+ # If all of contributions in the contribution_matrix are
+ # always contribution or never contribution, we can stop annotate propagations
+ # to the predecessor state.
+ next nil if contribution_matrix.all? {|_, contributions| contributions.nil? || contributions.all? {|_, contributed| !contributed } }
+
+ InadequacyAnnotation.new(annotation.state, annotation.token, annotation.actions, contribution_matrix)
+ }.compact
+ predecessor.append_annotation_list(propagating_list)
end
- def lhs_contributions(sym, token)
- shift, next_state = nterm_transitions.find {|sh, _| sh.next_sym == sym }
- if always_follows(shift, next_state).include?(token)
- nil
- else
- kernels.map {|kernel| [kernel, follow_kernel_items(shift, next_state, kernel) && item_lookahead_set[kernel].include?(token)] }.to_h
- end
+ # @rbs () -> Array[Item]
+ def first_kernels
+ @first_kernels ||= kernels.select {|kernel| kernel.position == 1 }
end
- def follow_kernel_items(shift, next_state, kernel)
- queue = [[self, shift, next_state]]
- until queue.empty?
- st, sh, next_st = queue.pop
- return true if kernel.next_sym == sh.next_sym && kernel.symbols_after_transition.all?(&:nullable)
- st.internal_dependencies(sh, next_st).each {|v| queue << v }
+ # @rbs (Array[InadequacyAnnotation] propagating_list) -> void
+ def append_annotation_list(propagating_list)
+ annotation_list.each do |annotation|
+ merging_list = propagating_list.select {|a| a.state == annotation.state && a.token == annotation.token && a.actions == annotation.actions }
+ annotation.merge_matrix(merging_list.map(&:contribution_matrix))
+ propagating_list -= merging_list
end
- false
+
+ @annotation_list += propagating_list
end
+ # Definition 3.31 (compute_lhs_contributions)
+ #
+ # @rbs (Grammar::Symbol sym, Grammar::Symbol token) -> (nil | Hash[Item, bool])
+ def lhs_contributions(sym, token)
+ return @lhs_contributions[sym][token] unless @lhs_contributions.dig(sym, token).nil?
+
+ transition = nterm_transitions.find {|goto| goto.next_sym == sym }
+ @lhs_contributions[sym] ||= {}
+ @lhs_contributions[sym][token] =
+ if always_follows[transition].include?(token)
+ {}
+ else
+ kernels.map {|kernel| [kernel, follow_kernel_items[transition][kernel] && item_lookahead_set[kernel].include?(token)] }.to_h
+ end
+ end
+
+ # Definition 3.26 (item_lookahead_sets)
+ #
+ # @rbs () -> lookahead_set
def item_lookahead_set
return @item_lookahead_set if @item_lookahead_set
- kernels.map {|item|
+ @item_lookahead_set = kernels.map {|k| [k, []] }.to_h
+ @item_lookahead_set = kernels.map {|kernel|
value =
- if item.lhs.accept_symbol?
+ if kernel.lhs.accept_symbol?
[]
- elsif item.position > 1
- prev_items = predecessors_with_item(item)
+ elsif kernel.position > 1
+ prev_items = predecessors_with_item(kernel)
prev_items.map {|st, i| st.item_lookahead_set[i] }.reduce([]) {|acc, syms| acc |= syms }
- elsif item.position == 1
- prev_state = @predecessors.find {|p| p.shifts.any? {|shift| shift.next_sym == item.lhs } }
- shift, next_state = prev_state.nterm_transitions.find {|shift, _| shift.next_sym == item.lhs }
- prev_state.goto_follows(shift, next_state)
+ elsif kernel.position == 1
+ prev_state = @predecessors.find {|p| p.transitions.any? {|transition| transition.next_sym == kernel.lhs } }
+ goto = prev_state.nterm_transitions.find {|goto| goto.next_sym == kernel.lhs }
+ prev_state.goto_follows[goto]
end
- [item, value]
+ [kernel, value]
}.to_h
end
+ # @rbs (lookahead_set k) -> void
def item_lookahead_set=(k)
@item_lookahead_set = k
end
+ # @rbs (Item item) -> Array[[State, Item]]
def predecessors_with_item(item)
result = []
@predecessors.each do |pre|
@@ -349,69 +467,53 @@ module Lrama
result
end
+ # @rbs (State prev_state) -> void
def append_predecessor(prev_state)
@predecessors << prev_state
@predecessors.uniq!
end
+ # Definition 3.39 (compute_goto_follow_set)
+ #
+ # @rbs (Grammar::Symbol nterm_token) -> Array[Grammar::Symbol]
def goto_follow_set(nterm_token)
return [] if nterm_token.accept_symbol?
- shift, next_state = @lalr_isocore.nterm_transitions.find {|sh, _| sh.next_sym == nterm_token }
+ goto = @lalr_isocore.nterm_transitions.find {|g| g.next_sym == nterm_token }
@kernels
- .select {|kernel| follow_kernel_items(shift, next_state, kernel) }
+ .select {|kernel| @lalr_isocore.follow_kernel_items[goto][kernel] }
.map {|kernel| item_lookahead_set[kernel] }
- .reduce(always_follows(shift, next_state)) {|result, terms| result |= terms }
- end
-
- def goto_follows(shift, next_state)
- queue = internal_dependencies(shift, next_state) + predecessor_dependencies(shift, next_state)
- terms = always_follows(shift, next_state)
- until queue.empty?
- st, sh, next_st = queue.pop
- terms |= st.always_follows(sh, next_st)
- st.internal_dependencies(sh, next_st).each {|v| queue << v }
- st.predecessor_dependencies(sh, next_st).each {|v| queue << v }
- end
- terms
- end
-
- def always_follows(shift, next_state)
- return @always_follows[[shift, next_state]] if @always_follows[[shift, next_state]]
-
- queue = internal_dependencies(shift, next_state) + successor_dependencies(shift, next_state)
- terms = []
- until queue.empty?
- st, sh, next_st = queue.pop
- terms |= next_st.term_transitions.map {|sh, _| sh.next_sym }
- st.internal_dependencies(sh, next_st).each {|v| queue << v }
- st.successor_dependencies(sh, next_st).each {|v| queue << v }
- end
- @always_follows[[shift, next_state]] = terms
+ .reduce(@lalr_isocore.always_follows[goto]) {|result, terms| result |= terms }
end
- def internal_dependencies(shift, next_state)
- return @internal_dependencies[[shift, next_state]] if @internal_dependencies[[shift, next_state]]
+ # Definition 3.8 (Goto Follows Internal Relation)
+ #
+ # @rbs (Action::Goto goto) -> Array[Action::Goto]
+ def internal_dependencies(goto)
+ return @internal_dependencies[goto] if @internal_dependencies[goto]
syms = @items.select {|i|
- i.next_sym == shift.next_sym && i.symbols_after_transition.all?(&:nullable) && i.position == 0
+ i.next_sym == goto.next_sym && i.symbols_after_transition.all?(&:nullable) && i.position == 0
}.map(&:lhs).uniq
- @internal_dependencies[[shift, next_state]] = nterm_transitions.select {|sh, _| syms.include?(sh.next_sym) }.map {|goto| [self, *goto] }
+ @internal_dependencies[goto] = nterm_transitions.select {|goto2| syms.include?(goto2.next_sym) }
end
- def successor_dependencies(shift, next_state)
- return @successor_dependencies[[shift, next_state]] if @successor_dependencies[[shift, next_state]]
+ # Definition 3.5 (Goto Follows Successor Relation)
+ #
+ # @rbs (Action::Goto goto) -> Array[Action::Goto]
+ def successor_dependencies(goto)
+ return @successor_dependencies[goto] if @successor_dependencies[goto]
- @successor_dependencies[[shift, next_state]] =
- next_state.nterm_transitions
- .select {|next_shift, _| next_shift.next_sym.nullable }
- .map {|transition| [next_state, *transition] }
+ @successor_dependencies[goto] = goto.to_state.nterm_transitions.select {|next_goto| next_goto.next_sym.nullable }
end
- def predecessor_dependencies(shift, next_state)
+ # Definition 3.9 (Goto Follows Predecessor Relation)
+ #
+ # @rbs (Action::Goto goto) -> Array[Action::Goto]
+ def predecessor_dependencies(goto)
state_items = []
@kernels.select {|kernel|
- kernel.next_sym == shift.next_sym && kernel.symbols_after_transition.all?(&:nullable)
+ kernel.next_sym == goto.next_sym && kernel.symbols_after_transition.all?(&:nullable)
}.each do |item|
queue = predecessors_with_item(item)
until queue.empty?
@@ -425,8 +527,7 @@ module Lrama
end
state_items.map {|state, item|
- sh, next_st = state.nterm_transitions.find {|shi, _| shi.next_sym == item.lhs }
- [state, sh, next_st]
+ state.nterm_transitions.find {|goto2| goto2.next_sym == item.lhs }
}
end
end
diff --git a/tool/lrama/lib/lrama/state/action.rb b/tool/lrama/lib/lrama/state/action.rb
new file mode 100644
index 0000000000..791685fc23
--- /dev/null
+++ b/tool/lrama/lib/lrama/state/action.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+require_relative "action/goto"
+require_relative "action/reduce"
+require_relative "action/shift"
diff --git a/tool/lrama/lib/lrama/state/action/goto.rb b/tool/lrama/lib/lrama/state/action/goto.rb
new file mode 100644
index 0000000000..4c2c82afdc
--- /dev/null
+++ b/tool/lrama/lib/lrama/state/action/goto.rb
@@ -0,0 +1,33 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class State
+ class Action
+ class Goto
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @from_state: State
+ # @next_sym: Grammar::Symbol
+ # @to_items: Array[Item]
+ # @to_state: State
+
+ attr_reader :from_state #: State
+ attr_reader :next_sym #: Grammar::Symbol
+ attr_reader :to_items #: Array[Item]
+ attr_reader :to_state #: State
+
+ # @rbs (State from_state, Grammar::Symbol next_sym, Array[Item] to_items, State to_state) -> void
+ def initialize(from_state, next_sym, to_items, to_state)
+ @from_state = from_state
+ @next_sym = next_sym
+ @to_items = to_items
+ @to_state = to_state
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/state/action/reduce.rb b/tool/lrama/lib/lrama/state/action/reduce.rb
new file mode 100644
index 0000000000..9678ab0a98
--- /dev/null
+++ b/tool/lrama/lib/lrama/state/action/reduce.rb
@@ -0,0 +1,71 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class State
+ class Action
+ class Reduce
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @item: Item
+ # @look_ahead: Array[Grammar::Symbol]?
+ # @look_ahead_sources: Hash[Grammar::Symbol, Array[Action::Goto]]?
+ # @not_selected_symbols: Array[Grammar::Symbol]
+
+ attr_reader :item #: Item
+ attr_reader :look_ahead #: Array[Grammar::Symbol]?
+ attr_reader :look_ahead_sources #: Hash[Grammar::Symbol, Array[Action::Goto]]?
+ attr_reader :not_selected_symbols #: Array[Grammar::Symbol]
+
+ # https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html
+ attr_accessor :default_reduction #: bool
+
+ # @rbs (Item item) -> void
+ def initialize(item)
+ @item = item
+ @look_ahead = nil
+ @look_ahead_sources = nil
+ @not_selected_symbols = []
+ end
+
+ # @rbs () -> Grammar::Rule
+ def rule
+ @item.rule
+ end
+
+ # @rbs (Array[Grammar::Symbol] look_ahead) -> Array[Grammar::Symbol]
+ def look_ahead=(look_ahead)
+ @look_ahead = look_ahead.freeze
+ end
+
+ # @rbs (Hash[Grammar::Symbol, Array[Action::Goto]] sources) -> Hash[Grammar::Symbol, Array[Action::Goto]]
+ def look_ahead_sources=(sources)
+ @look_ahead_sources = sources.freeze
+ end
+
+ # @rbs (Grammar::Symbol sym) -> Array[Grammar::Symbol]
+ def add_not_selected_symbol(sym)
+ @not_selected_symbols << sym
+ end
+
+ # @rbs () -> (::Array[Grammar::Symbol?])
+ def selected_look_ahead
+ if look_ahead
+ look_ahead - @not_selected_symbols
+ else
+ []
+ end
+ end
+
+ # @rbs () -> void
+ def clear_conflicts
+ @not_selected_symbols = []
+ @default_reduction = nil
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/state/action/shift.rb b/tool/lrama/lib/lrama/state/action/shift.rb
new file mode 100644
index 0000000000..52d9f8c4f0
--- /dev/null
+++ b/tool/lrama/lib/lrama/state/action/shift.rb
@@ -0,0 +1,39 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class State
+ class Action
+ class Shift
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @from_state: State
+ # @next_sym: Grammar::Symbol
+ # @to_items: Array[Item]
+ # @to_state: State
+
+ attr_reader :from_state #: State
+ attr_reader :next_sym #: Grammar::Symbol
+ attr_reader :to_items #: Array[Item]
+ attr_reader :to_state #: State
+ attr_accessor :not_selected #: bool
+
+ # @rbs (State from_state, Grammar::Symbol next_sym, Array[Item] to_items, State to_state) -> void
+ def initialize(from_state, next_sym, to_items, to_state)
+ @from_state = from_state
+ @next_sym = next_sym
+ @to_items = to_items
+ @to_state = to_state
+ end
+
+ # @rbs () -> void
+ def clear_conflicts
+ @not_selected = nil
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/state/inadequacy_annotation.rb b/tool/lrama/lib/lrama/state/inadequacy_annotation.rb
new file mode 100644
index 0000000000..3654fa4607
--- /dev/null
+++ b/tool/lrama/lib/lrama/state/inadequacy_annotation.rb
@@ -0,0 +1,140 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class State
+ class InadequacyAnnotation
+ # @rbs!
+ # type action = Action::Shift | Action::Reduce
+
+ attr_accessor :state #: State
+ attr_accessor :token #: Grammar::Symbol
+ attr_accessor :actions #: Array[action]
+ attr_accessor :contribution_matrix #: Hash[action, Hash[Item, bool]]
+
+ # @rbs (State state, Grammar::Symbol token, Array[action] actions, Hash[action, Hash[Item, bool]] contribution_matrix) -> void
+ def initialize(state, token, actions, contribution_matrix)
+ @state = state
+ @token = token
+ @actions = actions
+ @contribution_matrix = contribution_matrix
+ end
+
+ # @rbs (Item item) -> bool
+ def contributed?(item)
+ @contribution_matrix.any? {|action, contributions| !contributions.nil? && contributions[item] }
+ end
+
+ # @rbs (Array[Hash[action, Hash[Item, bool]]] another_matrixes) -> void
+ def merge_matrix(another_matrixes)
+ another_matrixes.each do |another_matrix|
+ @contribution_matrix.merge!(another_matrix) {|action, contributions, another_contributions|
+ next contributions if another_contributions.nil?
+ next another_contributions if contributions.nil?
+
+ contributions.merge!(another_contributions) {|_, contributed, another_contributed| contributed || another_contributed }
+ }
+ end
+ end
+
+ # Definition 3.42 (dominant_contribution)
+ #
+ # @rbs (State::lookahead_set lookaheads) -> Array[action]?
+ def dominant_contribution(lookaheads)
+ actions = @actions.select {|action|
+ contribution_matrix[action].nil? || contribution_matrix[action].any? {|item, contributed| contributed && lookaheads[item].include?(@token) }
+ }
+ return nil if actions.empty?
+
+ resolve_conflict(actions)
+ end
+
+ # @rbs (Array[action] actions) -> Array[action]
+ def resolve_conflict(actions)
+ # @type var shifts: Array[Action::Shift]
+ # @type var reduces: Array[Action::Reduce]
+ shifts = actions.select {|action| action.is_a?(Action::Shift)}
+ reduces = actions.select {|action| action.is_a?(Action::Reduce) }
+
+ shifts.each do |shift|
+ reduces.each do |reduce|
+ sym = shift.next_sym
+
+ shift_prec = sym.precedence
+ reduce_prec = reduce.item.rule.precedence
+
+ # Can resolve only when both have prec
+ unless shift_prec && reduce_prec
+ next
+ end
+
+ case
+ when shift_prec < reduce_prec
+ # Reduce is selected
+ actions.delete(shift)
+ next
+ when shift_prec > reduce_prec
+ # Shift is selected
+ actions.delete(reduce)
+ next
+ end
+
+ # shift_prec == reduce_prec, then check associativity
+ case sym.precedence&.type
+ when :precedence
+ # %precedence only specifies precedence and not specify associativity
+ # then a conflict is unresolved if precedence is same.
+ next
+ when :right
+ # Shift is selected
+ actions.delete(reduce)
+ next
+ when :left
+ # Reduce is selected
+ actions.delete(shift)
+ next
+ when :nonassoc
+ # Can not resolve
+ #
+ # nonassoc creates "run-time" error, precedence creates "compile-time" error.
+ # Then omit both the shift and reduce.
+ #
+ # https://www.gnu.org/software/bison/manual/html_node/Using-Precedence.html
+ actions.delete(shift)
+ actions.delete(reduce)
+ else
+ raise "Unknown precedence type. #{sym}"
+ end
+ end
+ end
+
+ actions
+ end
+
+ # @rbs () -> String
+ def to_s
+ "State: #{@state.id}, Token: #{@token.id.s_value}, Actions: #{actions_to_s}, Contributions: #{contribution_matrix_to_s}"
+ end
+
+ private
+
+ # @rbs () -> String
+ def actions_to_s
+ '[' + @actions.map {|action|
+ if action.is_a?(Action::Shift) || action.is_a?(Action::Goto)
+ action.class.name
+ elsif action.is_a?(Action::Reduce)
+ "#{action.class.name}: (#{action.item})"
+ end
+ }.join(', ') + ']'
+ end
+
+ # @rbs () -> String
+ def contribution_matrix_to_s
+ '[' + @contribution_matrix.map {|action, contributions|
+ "#{(action.is_a?(Action::Shift) || action.is_a?(Action::Goto)) ? action.class.name : "#{action.class.name}: (#{action.item})"}: " + contributions&.transform_keys(&:to_s).to_s
+ }.join(', ') + ']'
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/state/item.rb b/tool/lrama/lib/lrama/state/item.rb
new file mode 100644
index 0000000000..3ecdd70b76
--- /dev/null
+++ b/tool/lrama/lib/lrama/state/item.rb
@@ -0,0 +1,120 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+# TODO: Validate position is not over rule rhs
+
+require "forwardable"
+
+module Lrama
+ class State
+ class Item < Struct.new(:rule, :position, keyword_init: true)
+ # @rbs!
+ # include Grammar::Rule::_DelegatedMethods
+ #
+ # attr_accessor rule: Grammar::Rule
+ # attr_accessor position: Integer
+ #
+ # def initialize: (?rule: Grammar::Rule, ?position: Integer) -> void
+
+ extend Forwardable
+
+ def_delegators "rule", :lhs, :rhs
+
+ # Optimization for States#setup_state
+ #
+ # @rbs () -> Integer
+ def hash
+ [rule_id, position].hash
+ end
+
+ # @rbs () -> Integer
+ def rule_id
+ rule.id
+ end
+
+ # @rbs () -> bool
+ def empty_rule?
+ rule.empty_rule?
+ end
+
+ # @rbs () -> Integer
+ def number_of_rest_symbols
+ @number_of_rest_symbols ||= rhs.count - position
+ end
+
+ # @rbs () -> Grammar::Symbol
+ def next_sym
+ rhs[position]
+ end
+
+ # @rbs () -> Grammar::Symbol
+ def next_next_sym
+ @next_next_sym ||= rhs[position + 1]
+ end
+
+ # @rbs () -> Grammar::Symbol
+ def previous_sym
+ rhs[position - 1]
+ end
+
+ # @rbs () -> bool
+ def end_of_rule?
+ rhs.count == position
+ end
+
+ # @rbs () -> bool
+ def beginning_of_rule?
+ position == 0
+ end
+
+ # @rbs () -> bool
+ def start_item?
+ rule.initial_rule? && beginning_of_rule?
+ end
+
+ # @rbs () -> State::Item
+ def new_by_next_position
+ Item.new(rule: rule, position: position + 1)
+ end
+
+ # @rbs () -> Array[Grammar::Symbol]
+ def symbols_before_dot # steep:ignore
+ rhs[0...position]
+ end
+
+ # @rbs () -> Array[Grammar::Symbol]
+ def symbols_after_dot # steep:ignore
+ rhs[position..-1]
+ end
+
+ # @rbs () -> Array[Grammar::Symbol]
+ def symbols_after_transition # steep:ignore
+ rhs[position+1..-1]
+ end
+
+ # @rbs () -> ::String
+ def to_s
+ "#{lhs.id.s_value}: #{display_name}"
+ end
+
+ # @rbs () -> ::String
+ def display_name
+ r = rhs.map(&:display_name).insert(position, "•").join(" ")
+ "#{r} (rule #{rule_id})"
+ end
+
+ # Right after position
+ #
+ # @rbs () -> ::String
+ def display_rest
+ r = symbols_after_dot.map(&:display_name).join(" ")
+ ". #{r} (rule #{rule_id})"
+ end
+
+ # @rbs (State::Item other_item) -> bool
+ def predecessor_item_of?(other_item)
+ rule == other_item.rule && position == other_item.position - 1
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/state/reduce.rb b/tool/lrama/lib/lrama/state/reduce.rb
deleted file mode 100644
index 54ab87b468..0000000000
--- a/tool/lrama/lib/lrama/state/reduce.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class State
- class Reduce
- # https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html
- attr_reader :item, :look_ahead, :not_selected_symbols
- attr_accessor :default_reduction
-
- def initialize(item)
- @item = item
- @look_ahead = nil
- @not_selected_symbols = []
- end
-
- def rule
- @item.rule
- end
-
- def look_ahead=(look_ahead)
- @look_ahead = look_ahead.freeze
- end
-
- def add_not_selected_symbol(sym)
- @not_selected_symbols << sym
- end
-
- def selected_look_ahead
- if look_ahead
- look_ahead - @not_selected_symbols
- else
- []
- end
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb b/tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb
index 736d08376a..55ecad40bd 100644
--- a/tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb
+++ b/tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb
@@ -1,8 +1,21 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class State
- class ReduceReduceConflict < Struct.new(:symbols, :reduce1, :reduce2, keyword_init: true)
+ class ReduceReduceConflict
+ attr_reader :symbols #: Array[Grammar::Symbol]
+ attr_reader :reduce1 #: State::Action::Reduce
+ attr_reader :reduce2 #: State::Action::Reduce
+
+ # @rbs (symbols: Array[Grammar::Symbol], reduce1: State::Action::Reduce, reduce2: State::Action::Reduce) -> void
+ def initialize(symbols:, reduce1:, reduce2:)
+ @symbols = symbols
+ @reduce1 = reduce1
+ @reduce2 = reduce2
+ end
+
+ # @rbs () -> :reduce_reduce
def type
:reduce_reduce
end
diff --git a/tool/lrama/lib/lrama/state/resolved_conflict.rb b/tool/lrama/lib/lrama/state/resolved_conflict.rb
index 3bb3d1446e..014533c233 100644
--- a/tool/lrama/lib/lrama/state/resolved_conflict.rb
+++ b/tool/lrama/lib/lrama/state/resolved_conflict.rb
@@ -1,20 +1,54 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class State
+ # * state: A state on which the conflct is resolved
# * symbol: A symbol under discussion
# * reduce: A reduce under discussion
# * which: For which a conflict is resolved. :shift, :reduce or :error (for nonassociative)
- class ResolvedConflict < Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true)
+ # * resolved_by_precedence: If the conflict is resolved by precedence definition or not
+ class ResolvedConflict
+ # @rbs!
+ # type which_enum = :reduce | :shift | :error
+
+ attr_reader :state #: State
+ attr_reader :symbol #: Grammar::Symbol
+ attr_reader :reduce #: State::Action::Reduce
+ attr_reader :which #: which_enum
+ attr_reader :resolved_by_precedence #: bool
+
+ # @rbs (state: State, symbol: Grammar::Symbol, reduce: State::Action::Reduce, which: which_enum, resolved_by_precedence: bool) -> void
+ def initialize(state:, symbol:, reduce:, which:, resolved_by_precedence:)
+ @state = state
+ @symbol = symbol
+ @reduce = reduce
+ @which = which
+ @resolved_by_precedence = resolved_by_precedence
+ end
+
+ # @rbs () -> (::String | bot)
def report_message
+ "Conflict between rule #{reduce.rule.id} and token #{symbol.display_name} #{how_resolved}."
+ end
+
+ # @rbs () -> (::String | bot)
+ def report_precedences_message
+ "Conflict between reduce by \"#{reduce.rule.display_name}\" and shift #{symbol.display_name} #{how_resolved}."
+ end
+
+ private
+
+ # @rbs () -> (::String | bot)
+ def how_resolved
s = symbol.display_name
r = reduce.rule.precedence_sym&.display_name
case
- when which == :shift && same_prec
+ when which == :shift && resolved_by_precedence
msg = "resolved as #{which} (%right #{s})"
when which == :shift
msg = "resolved as #{which} (#{r} < #{s})"
- when which == :reduce && same_prec
+ when which == :reduce && resolved_by_precedence
msg = "resolved as #{which} (%left #{s})"
when which == :reduce
msg = "resolved as #{which} (#{s} < #{r})"
@@ -24,7 +58,7 @@ module Lrama
raise "Unknown direction. #{self}"
end
- "Conflict between rule #{reduce.rule.id} and token #{s} #{msg}."
+ msg
end
end
end
diff --git a/tool/lrama/lib/lrama/state/shift.rb b/tool/lrama/lib/lrama/state/shift.rb
deleted file mode 100644
index 81ef013a17..0000000000
--- a/tool/lrama/lib/lrama/state/shift.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class State
- class Shift
- attr_reader :next_sym, :next_items
- attr_accessor :not_selected
-
- def initialize(next_sym, next_items)
- @next_sym = next_sym
- @next_items = next_items
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/state/shift_reduce_conflict.rb b/tool/lrama/lib/lrama/state/shift_reduce_conflict.rb
index fd66834539..548f2de614 100644
--- a/tool/lrama/lib/lrama/state/shift_reduce_conflict.rb
+++ b/tool/lrama/lib/lrama/state/shift_reduce_conflict.rb
@@ -1,8 +1,21 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
class State
- class ShiftReduceConflict < Struct.new(:symbols, :shift, :reduce, keyword_init: true)
+ class ShiftReduceConflict
+ attr_reader :symbols #: Array[Grammar::Symbol]
+ attr_reader :shift #: State::Action::Shift
+ attr_reader :reduce #: State::Action::Reduce
+
+ # @rbs (symbols: Array[Grammar::Symbol], shift: State::Action::Shift, reduce: State::Action::Reduce) -> void
+ def initialize(symbols:, shift:, reduce:)
+ @symbols = symbols
+ @shift = shift
+ @reduce = reduce
+ end
+
+ # @rbs () -> :shift_reduce
def type
:shift_reduce
end
diff --git a/tool/lrama/lib/lrama/states.rb b/tool/lrama/lib/lrama/states.rb
index fd8ded905f..ddce627df4 100644
--- a/tool/lrama/lib/lrama/states.rb
+++ b/tool/lrama/lib/lrama/states.rb
@@ -1,8 +1,9 @@
+# rbs_inline: enabled
# frozen_string_literal: true
require "forwardable"
-require_relative "report/duration"
-require_relative "states/item"
+require_relative "tracer/duration"
+require_relative "state/item"
module Lrama
# States is passed to a template file
@@ -10,17 +11,42 @@ module Lrama
# "Efficient Computation of LALR(1) Look-Ahead Sets"
# https://dl.acm.org/doi/pdf/10.1145/69622.357187
class States
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # type state_id = Integer
+ # type rule_id = Integer
+ #
+ # include Grammar::_DelegatedMethods
+ #
+ # @grammar: Grammar
+ # @tracer: Tracer
+ # @states: Array[State]
+ # @direct_read_sets: Hash[State::Action::Goto, Bitmap::bitmap]
+ # @reads_relation: Hash[State::Action::Goto, Array[State::Action::Goto]]
+ # @read_sets: Hash[State::Action::Goto, Bitmap::bitmap]
+ # @includes_relation: Hash[State::Action::Goto, Array[State::Action::Goto]]
+ # @lookback_relation: Hash[state_id, Hash[rule_id, Array[State::Action::Goto]]]
+ # @follow_sets: Hash[State::Action::Goto, Bitmap::bitmap]
+ # @la: Hash[state_id, Hash[rule_id, Bitmap::bitmap]]
+
extend Forwardable
- include Lrama::Report::Duration
+ include Lrama::Tracer::Duration
- def_delegators "@grammar", :symbols, :terms, :nterms, :rules,
- :accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value!
+ def_delegators "@grammar", :symbols, :terms, :nterms, :rules, :precedences,
+ :accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value!, :ielr_defined?
- attr_reader :states, :reads_relation, :includes_relation, :lookback_relation
+ attr_reader :states #: Array[State]
+ attr_reader :reads_relation #: Hash[State::Action::Goto, Array[State::Action::Goto]]
+ attr_reader :includes_relation #: Hash[State::Action::Goto, Array[State::Action::Goto]]
+ attr_reader :lookback_relation #: Hash[state_id, Hash[rule_id, Array[State::Action::Goto]]]
- def initialize(grammar, trace_state: false)
+ # @rbs (Grammar grammar, Tracer tracer) -> void
+ def initialize(grammar, tracer)
@grammar = grammar
- @trace_state = trace_state
+ @tracer = tracer
@states = []
@@ -28,7 +54,7 @@ module Lrama
# where p is state, A is nterm, t is term.
#
# `@direct_read_sets` is a hash whose
- # key is [state.id, nterm.token_id],
+ # key is goto,
# value is bitmap of term.
@direct_read_sets = {}
@@ -37,14 +63,14 @@ module Lrama
# where p, r are state, A, C are nterm.
#
# `@reads_relation` is a hash whose
- # key is [state.id, nterm.token_id],
- # value is array of [state.id, nterm.token_id].
+ # key is goto,
+ # value is array of goto.
@reads_relation = {}
# `Read(p, A) =s DR(p, A) ∪ ∪{Read(r, C) | (p, A) reads (r, C)}`
#
# `@read_sets` is a hash whose
- # key is [state.id, nterm.token_id],
+ # key is goto,
# value is bitmap of term.
@read_sets = {}
@@ -52,112 +78,163 @@ module Lrama
# where p, p' are state, A, B are nterm, β, γ is sequence of symbol.
#
# `@includes_relation` is a hash whose
- # key is [state.id, nterm.token_id],
- # value is array of [state.id, nterm.token_id].
+ # key is goto,
+ # value is array of goto.
@includes_relation = {}
# `(q, A -> ω) lookback (p, A) iff p -(ω)-> q`
# where p, q are state, A -> ω is rule, A is nterm, ω is sequence of symbol.
#
- # `@lookback_relation` is a hash whose
- # key is [state.id, rule.id],
- # value is array of [state.id, nterm.token_id].
+ # `@lookback_relation` is a two-stage hash whose
+ # first key is state_id,
+ # second key is rule_id,
+ # value is array of goto.
@lookback_relation = {}
# `Follow(p, A) =s Read(p, A) ∪ ∪{Follow(p', B) | (p, A) includes (p', B)}`
#
# `@follow_sets` is a hash whose
- # key is [state.id, rule.id],
+ # key is goto,
# value is bitmap of term.
@follow_sets = {}
# `LA(q, A -> ω) = ∪{Follow(p, A) | (q, A -> ω) lookback (p, A)`
#
- # `@la` is a hash whose
- # key is [state.id, rule.id],
+ # `@la` is a two-stage hash whose
+ # first key is state_id,
+ # second key is rule_id,
# value is bitmap of term.
@la = {}
end
+ # @rbs () -> void
def compute
- # Look Ahead Sets
report_duration(:compute_lr0_states) { compute_lr0_states }
- report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
- report_duration(:compute_reads_relation) { compute_reads_relation }
- report_duration(:compute_read_sets) { compute_read_sets }
- report_duration(:compute_includes_relation) { compute_includes_relation }
- report_duration(:compute_lookback_relation) { compute_lookback_relation }
- report_duration(:compute_follow_sets) { compute_follow_sets }
+
+ # Look Ahead Sets
report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
# Conflicts
- report_duration(:compute_conflicts) { compute_conflicts }
+ report_duration(:compute_conflicts) { compute_conflicts(:lalr) }
report_duration(:compute_default_reduction) { compute_default_reduction }
end
+ # @rbs () -> void
def compute_ielr
+ # Preparation
+ report_duration(:clear_conflicts) { clear_conflicts }
+ # Phase 1
+ report_duration(:compute_predecessors) { compute_predecessors }
+ report_duration(:compute_follow_kernel_items) { compute_follow_kernel_items }
+ report_duration(:compute_always_follows) { compute_always_follows }
+ report_duration(:compute_goto_follows) { compute_goto_follows }
+ # Phase 2
+ report_duration(:compute_inadequacy_annotations) { compute_inadequacy_annotations }
+ # Phase 3
report_duration(:split_states) { split_states }
- report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
- report_duration(:compute_reads_relation) { compute_reads_relation }
- report_duration(:compute_read_sets) { compute_read_sets }
- report_duration(:compute_includes_relation) { compute_includes_relation }
- report_duration(:compute_lookback_relation) { compute_lookback_relation }
- report_duration(:compute_follow_sets) { compute_follow_sets }
+ # Phase 4
+ report_duration(:clear_look_ahead_sets) { clear_look_ahead_sets }
report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
- report_duration(:compute_conflicts) { compute_conflicts }
-
+ # Phase 5
+ report_duration(:compute_conflicts) { compute_conflicts(:ielr) }
report_duration(:compute_default_reduction) { compute_default_reduction }
end
- def reporter
- StatesReporter.new(self)
- end
-
+ # @rbs () -> Integer
def states_count
@states.count
end
+ # @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
def direct_read_sets
- @direct_read_sets.transform_values do |v|
+ @_direct_read_sets ||= @direct_read_sets.transform_values do |v|
bitmap_to_terms(v)
end
end
+ # @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
def read_sets
- @read_sets.transform_values do |v|
+ @_read_sets ||= @read_sets.transform_values do |v|
bitmap_to_terms(v)
end
end
+ # @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
def follow_sets
- @follow_sets.transform_values do |v|
+ @_follow_sets ||= @follow_sets.transform_values do |v|
bitmap_to_terms(v)
end
end
+ # @rbs () -> Hash[state_id, Hash[rule_id, Array[Grammar::Symbol]]]
def la
- @la.transform_values do |v|
- bitmap_to_terms(v)
+ @_la ||= @la.transform_values do |second_hash|
+ second_hash.transform_values do |v|
+ bitmap_to_terms(v)
+ end
end
end
+ # @rbs () -> Integer
def sr_conflicts_count
@sr_conflicts_count ||= @states.flat_map(&:sr_conflicts).count
end
+ # @rbs () -> Integer
def rr_conflicts_count
@rr_conflicts_count ||= @states.flat_map(&:rr_conflicts).count
end
- private
+ # @rbs (Logger logger) -> void
+ def validate!(logger)
+ validate_conflicts_within_threshold!(logger)
+ end
- def trace_state
- if @trace_state
- yield STDERR
+ def compute_la_sources_for_conflicted_states
+ reflexive = {}
+ @states.each do |state|
+ state.nterm_transitions.each do |goto|
+ reflexive[goto] = [goto]
+ end
+ end
+
+ # compute_read_sets
+ read_sets = Digraph.new(nterm_transitions, @reads_relation, reflexive).compute
+ # compute_follow_sets
+ follow_sets = Digraph.new(nterm_transitions, @includes_relation, read_sets).compute
+
+ @states.select(&:has_conflicts?).each do |state|
+ lookback_relation_on_state = @lookback_relation[state.id]
+ next unless lookback_relation_on_state
+ rules.each do |rule|
+ ary = lookback_relation_on_state[rule.id]
+ next unless ary
+
+ sources = {}
+
+ ary.each do |goto|
+ source = follow_sets[goto]
+
+ next unless source
+
+ source.each do |goto2|
+ tokens = direct_read_sets[goto2]
+ tokens.each do |token|
+ sources[token] ||= []
+ sources[token] |= [goto2]
+ end
+ end
+ end
+
+ state.set_look_ahead_sources(rule, sources)
+ end
end
end
+ private
+
+ # @rbs (Grammar::Symbol accessing_symbol, Array[State::Item] kernels, Hash[Array[State::Item], State] states_created) -> [State, bool]
def create_state(accessing_symbol, kernels, states_created)
# A item can appear in some states,
# so need to use `kernels` (not `kernels.first`) as a key.
@@ -204,27 +281,25 @@ module Lrama
return [state, true]
end
+ # @rbs (State state) -> void
def setup_state(state)
# closure
closure = []
- visited = {}
queued = {}
items = state.kernels.dup
items.each do |item|
- queued[item] = true
+ queued[item.rule_id] = true if item.position == 0
end
while (item = items.shift) do
- visited[item] = true
-
if (sym = item.next_sym) && sym.nterm?
@grammar.find_rules_by_symbol!(sym).each do |rule|
- i = Item.new(rule: rule, position: 0)
- next if queued[i]
+ next if queued[rule.id]
+ i = State::Item.new(rule: rule, position: 0)
closure << i
items << i
- queued[i] = true
+ queued[i.rule_id] = true
end
end
end
@@ -232,119 +307,107 @@ module Lrama
state.closure = closure.sort_by {|i| i.rule.id }
# Trace
- trace_state do |out|
- out << "Closure: input\n"
- state.kernels.each do |item|
- out << " #{item.display_rest}\n"
- end
- out << "\n\n"
- out << "Closure: output\n"
- state.items.each do |item|
- out << " #{item.display_rest}\n"
- end
- out << "\n\n"
- end
+ @tracer.trace_closure(state)
# shift & reduce
- state.compute_shifts_reduces
+ state.compute_transitions_and_reduces
end
+ # @rbs (Array[State] states, State state) -> void
def enqueue_state(states, state)
# Trace
- previous = state.kernels.first.previous_sym
- trace_state do |out|
- out << sprintf("state_list_append (state = %d, symbol = %d (%s))\n",
- @states.count, previous.number, previous.display_name)
- end
+ @tracer.trace_state_list_append(@states.count, state)
states << state
end
+ # @rbs () -> void
def compute_lr0_states
# State queue
states = []
states_created = {}
- state, _ = create_state(symbols.first, [Item.new(rule: @grammar.rules.first, position: 0)], states_created)
+ state, _ = create_state(symbols.first, [State::Item.new(rule: @grammar.rules.first, position: 0)], states_created)
enqueue_state(states, state)
while (state = states.shift) do
# Trace
- #
- # Bison 3.8.2 renders "(reached by "end-of-input")" for State 0 but
- # I think it is not correct...
- previous = state.kernels.first.previous_sym
- trace_state do |out|
- out << "Processing state #{state.id} (reached by #{previous.display_name})\n"
- end
+ @tracer.trace_state(state)
setup_state(state)
- state.shifts.each do |shift|
- new_state, created = create_state(shift.next_sym, shift.next_items, states_created)
- state.set_items_to_state(shift.next_items, new_state)
- if created
- enqueue_state(states, new_state)
- new_state.append_predecessor(state)
- end
+ # `State#transitions` can not be used here
+ # because `items_to_state` of the `state` is not set yet.
+ state._transitions.each do |next_sym, to_items|
+ new_state, created = create_state(next_sym, to_items, states_created)
+ state.set_items_to_state(to_items, new_state)
+ state.set_lane_items(next_sym, new_state)
+ enqueue_state(states, new_state) if created
end
end
end
+ # @rbs () -> Array[State::Action::Goto]
def nterm_transitions
a = []
@states.each do |state|
- state.nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
- a << [state, nterm, next_state]
+ state.nterm_transitions.each do |goto|
+ a << goto
end
end
a
end
+ # @rbs () -> void
+ def compute_look_ahead_sets
+ report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
+ report_duration(:compute_reads_relation) { compute_reads_relation }
+ report_duration(:compute_read_sets) { compute_read_sets }
+ report_duration(:compute_includes_relation) { compute_includes_relation }
+ report_duration(:compute_lookback_relation) { compute_lookback_relation }
+ report_duration(:compute_follow_sets) { compute_follow_sets }
+ report_duration(:compute_la) { compute_la }
+ end
+
+ # @rbs () -> void
def compute_direct_read_sets
@states.each do |state|
- state.nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
-
- ary = next_state.term_transitions.map do |shift, _|
+ state.nterm_transitions.each do |goto|
+ ary = goto.to_state.term_transitions.map do |shift|
shift.next_sym.number
end
- key = [state.id, nterm.token_id]
- @direct_read_sets[key] = Bitmap.from_array(ary)
+ @direct_read_sets[goto] = Bitmap.from_array(ary)
end
end
end
+ # @rbs () -> void
def compute_reads_relation
@states.each do |state|
- state.nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
- next_state.nterm_transitions.each do |shift2, _next_state2|
- nterm2 = shift2.next_sym
+ state.nterm_transitions.each do |goto|
+ goto.to_state.nterm_transitions.each do |goto2|
+ nterm2 = goto2.next_sym
if nterm2.nullable
- key = [state.id, nterm.token_id]
- @reads_relation[key] ||= []
- @reads_relation[key] << [next_state.id, nterm2.token_id]
+ @reads_relation[goto] ||= []
+ @reads_relation[goto] << goto2
end
end
end
end
end
+ # @rbs () -> void
def compute_read_sets
- sets = nterm_transitions.map do |state, nterm, next_state|
- [state.id, nterm.token_id]
- end
-
- @read_sets = Digraph.new(sets, @reads_relation, @direct_read_sets).compute
+ @read_sets = Digraph.new(nterm_transitions, @reads_relation, @direct_read_sets).compute
end
# Execute transition of state by symbols
# then return final state.
+ #
+ # @rbs (State state, Array[Grammar::Symbol] symbols) -> State
def transition(state, symbols)
symbols.each do |sym|
state = state.transition(sym)
@@ -353,10 +416,11 @@ module Lrama
state
end
+ # @rbs () -> void
def compute_includes_relation
@states.each do |state|
- state.nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
+ state.nterm_transitions.each do |goto|
+ nterm = goto.next_sym
@grammar.find_rules_by_symbol!(nterm).each do |rule|
i = rule.rhs.count - 1
@@ -366,10 +430,12 @@ module Lrama
break if sym.term?
state2 = transition(state, rule.rhs[0...i])
# p' = state, B = nterm, p = state2, A = sym
- key = [state2.id, sym.token_id]
+ key = state2.nterm_transitions.find do |goto2|
+ goto2.next_sym.token_id == sym.token_id
+ end || (raise "Goto by #{sym.name} on state #{state2.id} is not found")
# TODO: need to omit if state == state2 ?
@includes_relation[key] ||= []
- @includes_relation[key] << [state.id, nterm.token_id]
+ @includes_relation[key] << goto
break unless sym.nullable
i -= 1
end
@@ -378,45 +444,46 @@ module Lrama
end
end
+ # @rbs () -> void
def compute_lookback_relation
@states.each do |state|
- state.nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
+ state.nterm_transitions.each do |goto|
+ nterm = goto.next_sym
@grammar.find_rules_by_symbol!(nterm).each do |rule|
state2 = transition(state, rule.rhs)
# p = state, A = nterm, q = state2, A -> ω = rule
- key = [state2.id, rule.id]
- @lookback_relation[key] ||= []
- @lookback_relation[key] << [state.id, nterm.token_id]
+ @lookback_relation[state2.id] ||= {}
+ @lookback_relation[state2.id][rule.id] ||= []
+ @lookback_relation[state2.id][rule.id] << goto
end
end
end
end
+ # @rbs () -> void
def compute_follow_sets
- sets = nterm_transitions.map do |state, nterm, next_state|
- [state.id, nterm.token_id]
- end
-
- @follow_sets = Digraph.new(sets, @includes_relation, @read_sets).compute
+ @follow_sets = Digraph.new(nterm_transitions, @includes_relation, @read_sets).compute
end
- def compute_look_ahead_sets
+ # @rbs () -> void
+ def compute_la
@states.each do |state|
+ lookback_relation_on_state = @lookback_relation[state.id]
+ next unless lookback_relation_on_state
rules.each do |rule|
- ary = @lookback_relation[[state.id, rule.id]]
+ ary = lookback_relation_on_state[rule.id]
next unless ary
- ary.each do |state2_id, nterm_token_id|
+ ary.each do |goto|
# q = state, A -> ω = rule, p = state2, A = nterm
- follows = @follow_sets[[state2_id, nterm_token_id]]
+ follows = @follow_sets[goto]
next if follows == 0
- key = [state.id, rule.id]
- @la[key] ||= 0
- look_ahead = @la[key] | follows
- @la[key] |= look_ahead
+ @la[state.id] ||= {}
+ @la[state.id][rule.id] ||= 0
+ look_ahead = @la[state.id][rule.id] | follows
+ @la[state.id][rule.id] |= look_ahead
# No risk of conflict when
# * the state only has single reduce
@@ -429,6 +496,7 @@ module Lrama
end
end
+ # @rbs (Bitmap::bitmap bit) -> Array[Grammar::Symbol]
def bitmap_to_terms(bit)
ary = Bitmap.to_array(bit)
ary.map do |i|
@@ -436,14 +504,16 @@ module Lrama
end
end
- def compute_conflicts
- compute_shift_reduce_conflicts
+ # @rbs () -> void
+ def compute_conflicts(lr_type)
+ compute_shift_reduce_conflicts(lr_type)
compute_reduce_reduce_conflicts
end
- def compute_shift_reduce_conflicts
+ # @rbs () -> void
+ def compute_shift_reduce_conflicts(lr_type)
states.each do |state|
- state.shifts.each do |shift|
+ state.term_transitions.each do |shift|
state.reduces.each do |reduce|
sym = shift.next_sym
@@ -463,43 +533,57 @@ module Lrama
case
when shift_prec < reduce_prec
# Reduce is selected
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :reduce)
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :reduce, resolved_by_precedence: false)
+ state.resolved_conflicts << resolved_conflict
shift.not_selected = true
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
next
when shift_prec > reduce_prec
# Shift is selected
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :shift)
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :shift, resolved_by_precedence: false)
+ state.resolved_conflicts << resolved_conflict
reduce.add_not_selected_symbol(sym)
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
next
end
# shift_prec == reduce_prec, then check associativity
case sym.precedence.type
when :precedence
+ # Can not resolve the conflict
+ #
# %precedence only specifies precedence and not specify associativity
# then a conflict is unresolved if precedence is same.
state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
next
when :right
# Shift is selected
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :shift, same_prec: true)
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :shift, resolved_by_precedence: true)
+ state.resolved_conflicts << resolved_conflict
reduce.add_not_selected_symbol(sym)
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
next
when :left
# Reduce is selected
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :reduce, same_prec: true)
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :reduce, resolved_by_precedence: true)
+ state.resolved_conflicts << resolved_conflict
shift.not_selected = true
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
next
when :nonassoc
- # Can not resolve
+ # The conflict is resolved
#
- # nonassoc creates "run-time" error, precedence creates "compile-time" error.
- # Then omit both the shift and reduce.
+ # %nonassoc creates "run-time" error by removing both shift and reduce from
+ # the state. This makes the state to get syntax error if the conflicted token appears.
+ # On the other hand, %precedence creates "compile-time" error by keeping both
+ # shift and reduce on the state. This makes the state to be conflicted on the token.
#
# https://www.gnu.org/software/bison/manual/html_node/Using-Precedence.html
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :error)
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :error, resolved_by_precedence: false)
+ state.resolved_conflicts << resolved_conflict
shift.not_selected = true
reduce.add_not_selected_symbol(sym)
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
else
raise "Unknown precedence type. #{sym}"
end
@@ -508,35 +592,41 @@ module Lrama
end
end
+ # @rbs (Grammar::Precedence shift_prec, Grammar::Precedence reduce_prec, State::ResolvedConflict resolved_conflict) -> void
+ def mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
+ case lr_type
+ when :lalr
+ shift_prec.mark_used_by_lalr(resolved_conflict)
+ reduce_prec.mark_used_by_lalr(resolved_conflict)
+ when :ielr
+ shift_prec.mark_used_by_ielr(resolved_conflict)
+ reduce_prec.mark_used_by_ielr(resolved_conflict)
+ end
+ end
+
+ # @rbs () -> void
def compute_reduce_reduce_conflicts
states.each do |state|
- count = state.reduces.count
-
- (0...count).each do |i|
- reduce1 = state.reduces[i]
- next if reduce1.look_ahead.nil?
+ state.reduces.combination(2) do |reduce1, reduce2|
+ next if reduce1.look_ahead.nil? || reduce2.look_ahead.nil?
- ((i+1)...count).each do |j|
- reduce2 = state.reduces[j]
- next if reduce2.look_ahead.nil?
+ intersection = reduce1.look_ahead & reduce2.look_ahead
- intersection = reduce1.look_ahead & reduce2.look_ahead
-
- unless intersection.empty?
- state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
- end
+ unless intersection.empty?
+ state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
end
end
end
end
+ # @rbs () -> void
def compute_default_reduction
states.each do |state|
next if state.reduces.empty?
# Do not set, if conflict exist
next unless state.conflicts.empty?
# Do not set, if shift with `error` exists.
- next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol)
+ next if state.term_transitions.map {|shift| shift.next_sym }.include?(@grammar.error_symbol)
state.default_reduction_rule = state.reduces.map do |r|
[r.rule, r.rule.id, (r.look_ahead || []).count]
@@ -546,35 +636,171 @@ module Lrama
end
end
+ # @rbs () -> void
+ def clear_conflicts
+ states.each(&:clear_conflicts)
+ end
+
+ # Definition 3.15 (Predecessors)
+ #
+ # @rbs () -> void
+ def compute_predecessors
+ @states.each do |state|
+ state.transitions.each do |transition|
+ transition.to_state.append_predecessor(state)
+ end
+ end
+ end
+
+ # Definition 3.16 (follow_kernel_items)
+ #
+ # @rbs () -> void
+ def compute_follow_kernel_items
+ set = nterm_transitions
+ relation = compute_goto_internal_relation
+ base_function = compute_goto_bitmaps
+ Digraph.new(set, relation, base_function).compute.each do |goto, follow_kernel_items|
+ state = goto.from_state
+ state.follow_kernel_items[goto] = state.kernels.map {|kernel|
+ [kernel, Bitmap.to_bool_array(follow_kernel_items, state.kernels.count)]
+ }.to_h
+ end
+ end
+
+ # @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
+ def compute_goto_internal_relation
+ relations = {}
+
+ @states.each do |state|
+ state.nterm_transitions.each do |goto|
+ relations[goto] = state.internal_dependencies(goto)
+ end
+ end
+
+ relations
+ end
+
+ # @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
+ def compute_goto_bitmaps
+ nterm_transitions.map {|goto|
+ bools = goto.from_state.kernels.map.with_index {|kernel, i| i if kernel.next_sym == goto.next_sym && kernel.symbols_after_transition.all?(&:nullable) }.compact
+ [goto, Bitmap.from_array(bools)]
+ }.to_h
+ end
+
+ # Definition 3.20 (always_follows, one closure)
+ #
+ # @rbs () -> void
+ def compute_always_follows
+ set = nterm_transitions
+ relation = compute_goto_successor_or_internal_relation
+ base_function = compute_transition_bitmaps
+ Digraph.new(set, relation, base_function).compute.each do |goto, always_follows_bitmap|
+ goto.from_state.always_follows[goto] = bitmap_to_terms(always_follows_bitmap)
+ end
+ end
+
+ # @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
+ def compute_goto_successor_or_internal_relation
+ relations = {}
+
+ @states.each do |state|
+ state.nterm_transitions.each do |goto|
+ relations[goto] = state.successor_dependencies(goto) + state.internal_dependencies(goto)
+ end
+ end
+
+ relations
+ end
+
+ # @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
+ def compute_transition_bitmaps
+ nterm_transitions.map {|goto|
+ [goto, Bitmap.from_array(goto.to_state.term_transitions.map {|shift| shift.next_sym.number })]
+ }.to_h
+ end
+
+ # Definition 3.24 (goto_follows, via always_follows)
+ #
+ # @rbs () -> void
+ def compute_goto_follows
+ set = nterm_transitions
+ relation = compute_goto_internal_or_predecessor_dependencies
+ base_function = compute_always_follows_bitmaps
+ Digraph.new(set, relation, base_function).compute.each do |goto, goto_follows_bitmap|
+ goto.from_state.goto_follows[goto] = bitmap_to_terms(goto_follows_bitmap)
+ end
+ end
+
+ # @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
+ def compute_goto_internal_or_predecessor_dependencies
+ relations = {}
+
+ @states.each do |state|
+ state.nterm_transitions.each do |goto|
+ relations[goto] = state.internal_dependencies(goto) + state.predecessor_dependencies(goto)
+ end
+ end
+
+ relations
+ end
+
+ # @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
+ def compute_always_follows_bitmaps
+ nterm_transitions.map {|goto|
+ [goto, Bitmap.from_array(goto.from_state.always_follows[goto].map(&:number))]
+ }.to_h
+ end
+
+ # @rbs () -> void
def split_states
@states.each do |state|
- state.transitions.each do |shift, next_state|
- compute_state(state, shift, next_state)
+ state.transitions.each do |transition|
+ compute_state(state, transition, transition.to_state)
end
end
end
+ # @rbs () -> void
+ def compute_inadequacy_annotations
+ @states.each do |state|
+ state.annotate_manifestation
+ end
+
+ queue = @states.reject {|state| state.annotation_list.empty? }
+
+ while (curr = queue.shift) do
+ curr.predecessors.each do |pred|
+ cache = pred.annotation_list.dup
+ curr.annotate_predecessor(pred)
+ queue << pred if cache != pred.annotation_list && !queue.include?(pred)
+ end
+ end
+ end
+
+ # @rbs (State state, State::lookahead_set filtered_lookaheads) -> void
def merge_lookaheads(state, filtered_lookaheads)
return if state.kernels.all? {|item| (filtered_lookaheads[item] - state.item_lookahead_set[item]).empty? }
state.item_lookahead_set = state.item_lookahead_set.merge {|_, v1, v2| v1 | v2 }
- state.transitions.each do |shift, next_state|
- next if next_state.lookaheads_recomputed
- compute_state(state, shift, next_state)
+ state.transitions.each do |transition|
+ next if transition.to_state.lookaheads_recomputed
+ compute_state(state, transition, transition.to_state)
end
end
- def compute_state(state, shift, next_state)
- filtered_lookaheads = state.propagate_lookaheads(next_state)
- s = next_state.ielr_isocores.find {|st| st.compatible_lookahead?(filtered_lookaheads) }
+ # @rbs (State state, State::Action::Shift | State::Action::Goto transition, State next_state) -> void
+ def compute_state(state, transition, next_state)
+ propagating_lookaheads = state.propagate_lookaheads(next_state)
+ s = next_state.ielr_isocores.find {|st| st.is_compatible?(propagating_lookaheads) }
if s.nil?
- s = next_state.ielr_isocores.last
+ s = next_state.lalr_isocore
new_state = State.new(@states.count, s.accessing_symbol, s.kernels)
new_state.closure = s.closure
- new_state.compute_shifts_reduces
- s.transitions.each do |sh, next_state|
- new_state.set_items_to_state(sh.next_items, next_state)
+ new_state.compute_transitions_and_reduces
+ s.transitions.each do |transition|
+ new_state.set_items_to_state(transition.to_items, transition.to_state)
end
@states << new_state
new_state.lalr_isocore = s
@@ -582,14 +808,60 @@ module Lrama
s.ielr_isocores.each do |st|
st.ielr_isocores = s.ielr_isocores
end
- new_state.item_lookahead_set = filtered_lookaheads
- state.update_transition(shift, new_state)
+ new_state.lookaheads_recomputed = true
+ new_state.item_lookahead_set = propagating_lookaheads
+ state.update_transition(transition, new_state)
elsif(!s.lookaheads_recomputed)
- s.item_lookahead_set = filtered_lookaheads
+ s.lookaheads_recomputed = true
+ s.item_lookahead_set = propagating_lookaheads
else
- state.update_transition(shift, s)
- merge_lookaheads(s, filtered_lookaheads)
+ merge_lookaheads(s, propagating_lookaheads)
+ state.update_transition(transition, s) if state.items_to_state[transition.to_items].id != s.id
end
end
+
+ # @rbs (Logger logger) -> void
+ def validate_conflicts_within_threshold!(logger)
+ exit false unless conflicts_within_threshold?(logger)
+ end
+
+ # @rbs (Logger logger) -> bool
+ def conflicts_within_threshold?(logger)
+ return true unless @grammar.expect
+
+ [sr_conflicts_within_threshold?(logger), rr_conflicts_within_threshold?(logger)].all?
+ end
+
+ # @rbs (Logger logger) -> bool
+ def sr_conflicts_within_threshold?(logger)
+ return true if @grammar.expect == sr_conflicts_count
+
+ logger.error("shift/reduce conflicts: #{sr_conflicts_count} found, #{@grammar.expect} expected")
+ false
+ end
+
+ # @rbs (Logger logger) -> bool
+ def rr_conflicts_within_threshold?(logger, expected: 0)
+ return true if expected == rr_conflicts_count
+
+ logger.error("reduce/reduce conflicts: #{rr_conflicts_count} found, #{expected} expected")
+ false
+ end
+
+ # @rbs () -> void
+ def clear_look_ahead_sets
+ @direct_read_sets.clear
+ @reads_relation.clear
+ @read_sets.clear
+ @includes_relation.clear
+ @lookback_relation.clear
+ @follow_sets.clear
+ @la.clear
+
+ @_direct_read_sets = nil
+ @_read_sets = nil
+ @_follow_sets = nil
+ @_la = nil
+ end
end
end
diff --git a/tool/lrama/lib/lrama/states/item.rb b/tool/lrama/lib/lrama/states/item.rb
deleted file mode 100644
index e89cb9695b..0000000000
--- a/tool/lrama/lib/lrama/states/item.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-# TODO: Validate position is not over rule rhs
-
-require "forwardable"
-
-module Lrama
- class States
- class Item < Struct.new(:rule, :position, keyword_init: true)
- extend Forwardable
-
- def_delegators "rule", :lhs, :rhs
-
- # Optimization for States#setup_state
- def hash
- [rule_id, position].hash
- end
-
- def rule_id
- rule.id
- end
-
- def empty_rule?
- rule.empty_rule?
- end
-
- def number_of_rest_symbols
- rhs.count - position
- end
-
- def next_sym
- rhs[position]
- end
-
- def next_next_sym
- rhs[position + 1]
- end
-
- def previous_sym
- rhs[position - 1]
- end
-
- def end_of_rule?
- rhs.count == position
- end
-
- def beginning_of_rule?
- position == 0
- end
-
- def start_item?
- rule.initial_rule? && beginning_of_rule?
- end
-
- def new_by_next_position
- Item.new(rule: rule, position: position + 1)
- end
-
- def symbols_before_dot # steep:ignore
- rhs[0...position]
- end
-
- def symbols_after_dot # steep:ignore
- rhs[position..-1]
- end
-
- def symbols_after_transition
- rhs[position+1..-1]
- end
-
- def to_s
- "#{lhs.id.s_value}: #{display_name}"
- end
-
- def display_name
- r = rhs.map(&:display_name).insert(position, "•").join(" ")
- "#{r} (rule #{rule_id})"
- end
-
- # Right after position
- def display_rest
- r = symbols_after_dot.map(&:display_name).join(" ")
- ". #{r} (rule #{rule_id})"
- end
-
- def predecessor_item_of?(other_item)
- rule == other_item.rule && position == other_item.position - 1
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/states_reporter.rb b/tool/lrama/lib/lrama/states_reporter.rb
deleted file mode 100644
index 64ff4de100..0000000000
--- a/tool/lrama/lib/lrama/states_reporter.rb
+++ /dev/null
@@ -1,362 +0,0 @@
-# frozen_string_literal: true
-
-module Lrama
- class StatesReporter
- include Lrama::Report::Duration
-
- def initialize(states)
- @states = states
- end
-
- def report(io, **options)
- report_duration(:report) do
- _report(io, **options)
- end
- end
-
- private
-
- def _report(io, grammar: false, rules: false, terms: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false)
- report_unused_rules(io) if rules
- report_unused_terms(io) if terms
- report_conflicts(io)
- report_grammar(io) if grammar
- report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
- end
-
- def report_unused_terms(io)
- look_aheads = @states.states.each do |state|
- state.reduces.flat_map do |reduce|
- reduce.look_ahead unless reduce.look_ahead.nil?
- end
- end
-
- next_terms = @states.states.flat_map do |state|
- state.shifts.map(&:next_sym).select(&:term?)
- end
-
- unused_symbols = @states.terms.select do |term|
- !(look_aheads + next_terms).include?(term)
- end
-
- unless unused_symbols.empty?
- io << "#{unused_symbols.count} Unused Terms\n\n"
- unused_symbols.each_with_index do |term, index|
- io << sprintf("%5d %s\n", index, term.id.s_value)
- end
- io << "\n\n"
- end
- end
-
- def report_unused_rules(io)
- used_rules = @states.rules.flat_map(&:rhs)
-
- unused_rules = @states.rules.map(&:lhs).select do |rule|
- !used_rules.include?(rule) && rule.token_id != 0
- end
-
- unless unused_rules.empty?
- io << "#{unused_rules.count} Unused Rules\n\n"
- unused_rules.each_with_index do |rule, index|
- io << sprintf("%5d %s\n", index, rule.display_name)
- end
- io << "\n\n"
- end
- end
-
- def report_conflicts(io)
- has_conflict = false
-
- @states.states.each do |state|
- messages = []
- cs = state.conflicts.group_by(&:type)
- if cs[:shift_reduce]
- messages << "#{cs[:shift_reduce].count} shift/reduce"
- end
-
- if cs[:reduce_reduce]
- messages << "#{cs[:reduce_reduce].count} reduce/reduce"
- end
-
- unless messages.empty?
- has_conflict = true
- io << "State #{state.id} conflicts: #{messages.join(', ')}\n"
- end
- end
-
- if has_conflict
- io << "\n\n"
- end
- end
-
- def report_grammar(io)
- io << "Grammar\n"
- last_lhs = nil
-
- @states.rules.each do |rule|
- if rule.empty_rule?
- r = "ε"
- else
- r = rule.rhs.map(&:display_name).join(" ")
- end
-
- if rule.lhs == last_lhs
- io << sprintf("%5d %s| %s\n", rule.id, " " * rule.lhs.display_name.length, r)
- else
- io << "\n"
- io << sprintf("%5d %s: %s\n", rule.id, rule.lhs.display_name, r)
- end
-
- last_lhs = rule.lhs
- end
- io << "\n\n"
- end
-
- def report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
- if counterexamples
- cex = Counterexamples.new(@states)
- end
-
- @states.states.each do |state|
- # Report State
- io << "State #{state.id}\n\n"
-
- # Report item
- last_lhs = nil
- list = itemsets ? state.items : state.kernels
- list.sort_by {|i| [i.rule_id, i.position] }.each do |item|
- if item.empty_rule?
- r = "ε •"
- else
- r = item.rhs.map(&:display_name).insert(item.position, "•").join(" ")
- end
- if item.lhs == last_lhs
- l = " " * item.lhs.id.s_value.length + "|"
- else
- l = item.lhs.id.s_value + ":"
- end
- la = ""
- if lookaheads && item.end_of_rule?
- reduce = state.find_reduce_by_item!(item)
- look_ahead = reduce.selected_look_ahead
- unless look_ahead.empty?
- la = " [#{look_ahead.map(&:display_name).join(", ")}]"
- end
- end
- last_lhs = item.lhs
-
- io << sprintf("%5i %s %s%s\n", item.rule_id, l, r, la)
- end
- io << "\n"
-
- # Report shifts
- tmp = state.term_transitions.reject do |shift, _|
- shift.not_selected
- end.map do |shift, next_state|
- [shift.next_sym, next_state.id]
- end
- max_len = tmp.map(&:first).map(&:display_name).map(&:length).max
- tmp.each do |term, state_id|
- io << " #{term.display_name.ljust(max_len)} shift, and go to state #{state_id}\n"
- end
- io << "\n" unless tmp.empty?
-
- # Report error caused by %nonassoc
- nl = false
- tmp = state.resolved_conflicts.select do |resolved|
- resolved.which == :error
- end.map do |error|
- error.symbol.display_name
- end
- max_len = tmp.map(&:length).max
- tmp.each do |name|
- nl = true
- io << " #{name.ljust(max_len)} error (nonassociative)\n"
- end
- io << "\n" unless tmp.empty?
-
- # Report reduces
- nl = false
- max_len = state.non_default_reduces.flat_map(&:look_ahead).compact.map(&:display_name).map(&:length).max || 0
- max_len = [max_len, "$default".length].max if state.default_reduction_rule
- ary = []
-
- state.non_default_reduces.each do |reduce|
- reduce.look_ahead.each do |term|
- ary << [term, reduce]
- end
- end
-
- ary.sort_by do |term, reduce|
- term.number
- end.each do |term, reduce|
- rule = reduce.item.rule
- io << " #{term.display_name.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.display_name})\n"
- nl = true
- end
-
- if (r = state.default_reduction_rule)
- nl = true
- s = "$default".ljust(max_len)
-
- if r.initial_rule?
- io << " #{s} accept\n"
- else
- io << " #{s} reduce using rule #{r.id} (#{r.lhs.display_name})\n"
- end
- end
- io << "\n" if nl
-
- # Report nonterminal transitions
- tmp = []
- max_len = 0
- state.nterm_transitions.each do |shift, next_state|
- nterm = shift.next_sym
- tmp << [nterm, next_state.id]
- max_len = [max_len, nterm.id.s_value.length].max
- end
- tmp.uniq!
- tmp.sort_by! do |nterm, state_id|
- nterm.number
- end
- tmp.each do |nterm, state_id|
- io << " #{nterm.id.s_value.ljust(max_len)} go to state #{state_id}\n"
- end
- io << "\n" unless tmp.empty?
-
- if solved
- # Report conflict resolutions
- state.resolved_conflicts.each do |resolved|
- io << " #{resolved.report_message}\n"
- end
- io << "\n" unless state.resolved_conflicts.empty?
- end
-
- if counterexamples && state.has_conflicts?
- # Report counterexamples
- examples = cex.compute(state)
- examples.each do |example|
- label0 = example.type == :shift_reduce ? "shift/reduce" : "reduce/reduce"
- label1 = example.type == :shift_reduce ? "Shift derivation" : "First Reduce derivation"
- label2 = example.type == :shift_reduce ? "Reduce derivation" : "Second Reduce derivation"
-
- io << " #{label0} conflict on token #{example.conflict_symbol.id.s_value}:\n"
- io << " #{example.path1_item}\n"
- io << " #{example.path2_item}\n"
- io << " #{label1}\n"
- example.derivations1.render_strings_for_report.each do |str|
- io << " #{str}\n"
- end
- io << " #{label2}\n"
- example.derivations2.render_strings_for_report.each do |str|
- io << " #{str}\n"
- end
- end
- end
-
- if verbose
- # Report direct_read_sets
- io << " [Direct Read sets]\n"
- direct_read_sets = @states.direct_read_sets
- @states.nterms.each do |nterm|
- terms = direct_read_sets[[state.id, nterm.token_id]]
- next unless terms
- next if terms.empty?
-
- str = terms.map {|sym| sym.id.s_value }.join(", ")
- io << " read #{nterm.id.s_value} shift #{str}\n"
- end
- io << "\n"
-
- # Report reads_relation
- io << " [Reads Relation]\n"
- @states.nterms.each do |nterm|
- a = @states.reads_relation[[state.id, nterm.token_id]]
- next unless a
-
- a.each do |state_id2, nterm_id2|
- n = @states.nterms.find {|n| n.token_id == nterm_id2 }
- io << " (State #{state_id2}, #{n.id.s_value})\n"
- end
- end
- io << "\n"
-
- # Report read_sets
- io << " [Read sets]\n"
- read_sets = @states.read_sets
- @states.nterms.each do |nterm|
- terms = read_sets[[state.id, nterm.token_id]]
- next unless terms
- next if terms.empty?
-
- terms.each do |sym|
- io << " #{sym.id.s_value}\n"
- end
- end
- io << "\n"
-
- # Report includes_relation
- io << " [Includes Relation]\n"
- @states.nterms.each do |nterm|
- a = @states.includes_relation[[state.id, nterm.token_id]]
- next unless a
-
- a.each do |state_id2, nterm_id2|
- n = @states.nterms.find {|n| n.token_id == nterm_id2 }
- io << " (State #{state.id}, #{nterm.id.s_value}) -> (State #{state_id2}, #{n.id.s_value})\n"
- end
- end
- io << "\n"
-
- # Report lookback_relation
- io << " [Lookback Relation]\n"
- @states.rules.each do |rule|
- a = @states.lookback_relation[[state.id, rule.id]]
- next unless a
-
- a.each do |state_id2, nterm_id2|
- n = @states.nterms.find {|n| n.token_id == nterm_id2 }
- io << " (Rule: #{rule.display_name}) -> (State #{state_id2}, #{n.id.s_value})\n"
- end
- end
- io << "\n"
-
- # Report follow_sets
- io << " [Follow sets]\n"
- follow_sets = @states.follow_sets
- @states.nterms.each do |nterm|
- terms = follow_sets[[state.id, nterm.token_id]]
-
- next unless terms
-
- terms.each do |sym|
- io << " #{nterm.id.s_value} -> #{sym.id.s_value}\n"
- end
- end
- io << "\n"
-
- # Report LA
- io << " [Look-Ahead Sets]\n"
- tmp = []
- max_len = 0
- @states.rules.each do |rule|
- syms = @states.la[[state.id, rule.id]]
- next unless syms
-
- tmp << [rule, syms]
- max_len = ([max_len] + syms.map {|s| s.id.s_value.length }).max
- end
- tmp.each do |rule, syms|
- syms.each do |sym|
- io << " #{sym.id.s_value.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n"
- end
- end
- io << "\n" unless tmp.empty?
- end
-
- # End of Report State
- io << "\n"
- end
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/trace_reporter.rb b/tool/lrama/lib/lrama/trace_reporter.rb
deleted file mode 100644
index bcf1ef1e50..0000000000
--- a/tool/lrama/lib/lrama/trace_reporter.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# rbs_inline: enabled
-# frozen_string_literal: true
-
-module Lrama
- class TraceReporter
- # @rbs (Lrama::Grammar grammar) -> void
- def initialize(grammar)
- @grammar = grammar
- end
-
- # @rbs (**Hash[Symbol, bool] options) -> void
- def report(**options)
- _report(**options)
- end
-
- private
-
- # @rbs rules: (bool rules, bool actions, bool only_explicit_rules, **untyped _) -> void
- def _report(rules: false, actions: false, only_explicit_rules: false, **_)
- report_rules if rules && !only_explicit_rules
- report_only_explicit_rules if only_explicit_rules
- report_actions if actions
- end
-
- # @rbs () -> void
- def report_rules
- puts "Grammar rules:"
- @grammar.rules.each { |rule| puts rule.display_name }
- end
-
- # @rbs () -> void
- def report_only_explicit_rules
- puts "Grammar rules:"
- @grammar.rules.each do |rule|
- puts rule.display_name_without_action if rule.lhs.first_set.any?
- end
- end
-
- # @rbs () -> void
- def report_actions
- puts "Grammar rules with actions:"
- @grammar.rules.each { |rule| puts rule.with_actions }
- end
- end
-end
diff --git a/tool/lrama/lib/lrama/tracer.rb b/tool/lrama/lib/lrama/tracer.rb
new file mode 100644
index 0000000000..fda699a665
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer.rb
@@ -0,0 +1,51 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+require_relative "tracer/actions"
+require_relative "tracer/closure"
+require_relative "tracer/duration"
+require_relative "tracer/only_explicit_rules"
+require_relative "tracer/rules"
+require_relative "tracer/state"
+
+module Lrama
+ class Tracer
+ # @rbs (IO io, **bool options) -> void
+ def initialize(io, **options)
+ @io = io
+ @options = options
+ @only_explicit_rules = OnlyExplicitRules.new(io, **options)
+ @rules = Rules.new(io, **options)
+ @actions = Actions.new(io, **options)
+ @closure = Closure.new(io, **options)
+ @state = State.new(io, **options)
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def trace(grammar)
+ @only_explicit_rules.trace(grammar)
+ @rules.trace(grammar)
+ @actions.trace(grammar)
+ end
+
+ # @rbs (Lrama::State state) -> void
+ def trace_closure(state)
+ @closure.trace(state)
+ end
+
+ # @rbs (Lrama::State state) -> void
+ def trace_state(state)
+ @state.trace(state)
+ end
+
+ # @rbs (Integer state_count, Lrama::State state) -> void
+ def trace_state_list_append(state_count, state)
+ @state.trace_list_append(state_count, state)
+ end
+
+ # @rbs () -> void
+ def enable_duration
+ Duration.enable if @options[:time]
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/tracer/actions.rb b/tool/lrama/lib/lrama/tracer/actions.rb
new file mode 100644
index 0000000000..7b9c9b9f53
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer/actions.rb
@@ -0,0 +1,22 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Tracer
+ class Actions
+ # @rbs (IO io, ?actions: bool, **bool options) -> void
+ def initialize(io, actions: false, **options)
+ @io = io
+ @actions = actions
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def trace(grammar)
+ return unless @actions
+
+ @io << "Grammar rules with actions:" << "\n"
+ grammar.rules.each { |rule| @io << rule.with_actions << "\n" }
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/tracer/closure.rb b/tool/lrama/lib/lrama/tracer/closure.rb
new file mode 100644
index 0000000000..5b2f0b27e6
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer/closure.rb
@@ -0,0 +1,30 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Tracer
+ class Closure
+ # @rbs (IO io, ?automaton: bool, ?closure: bool, **bool) -> void
+ def initialize(io, automaton: false, closure: false, **_)
+ @io = io
+ @closure = automaton || closure
+ end
+
+ # @rbs (Lrama::State state) -> void
+ def trace(state)
+ return unless @closure
+
+ @io << "Closure: input" << "\n"
+ state.kernels.each do |item|
+ @io << " #{item.display_rest}" << "\n"
+ end
+ @io << "\n\n"
+ @io << "Closure: output" << "\n"
+ state.items.each do |item|
+ @io << " #{item.display_rest}" << "\n"
+ end
+ @io << "\n\n"
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/tracer/duration.rb b/tool/lrama/lib/lrama/tracer/duration.rb
new file mode 100644
index 0000000000..91c49625b2
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer/duration.rb
@@ -0,0 +1,38 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Tracer
+ module Duration
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
+ # Move these type declarations above instance variable definitions, once it's supported.
+ # see: https://github.com/soutaro/rbs-inline/pull/149
+ #
+ # @rbs!
+ # @_report_duration_enabled: bool
+
+ # @rbs () -> void
+ def self.enable
+ @_report_duration_enabled = true
+ end
+
+ # @rbs () -> bool
+ def self.enabled?
+ !!@_report_duration_enabled
+ end
+
+ # @rbs [T] (_ToS message) { -> T } -> T
+ def report_duration(message)
+ time1 = Time.now.to_f
+ result = yield
+ time2 = Time.now.to_f
+
+ if Duration.enabled?
+ STDERR.puts sprintf("%s %10.5f s", message, time2 - time1)
+ end
+
+ return result
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/tracer/only_explicit_rules.rb b/tool/lrama/lib/lrama/tracer/only_explicit_rules.rb
new file mode 100644
index 0000000000..4f64e7d2f4
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer/only_explicit_rules.rb
@@ -0,0 +1,24 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Tracer
+ class OnlyExplicitRules
+ # @rbs (IO io, ?only_explicit: bool, **bool) -> void
+ def initialize(io, only_explicit: false, **_)
+ @io = io
+ @only_explicit = only_explicit
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def trace(grammar)
+ return unless @only_explicit
+
+ @io << "Grammar rules:" << "\n"
+ grammar.rules.each do |rule|
+ @io << rule.display_name_without_action << "\n" if rule.lhs.first_set.any?
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/tracer/rules.rb b/tool/lrama/lib/lrama/tracer/rules.rb
new file mode 100644
index 0000000000..d6e85b8432
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer/rules.rb
@@ -0,0 +1,23 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Tracer
+ class Rules
+ # @rbs (IO io, ?rules: bool, ?only_explicit: bool, **bool) -> void
+ def initialize(io, rules: false, only_explicit: false, **_)
+ @io = io
+ @rules = rules
+ @only_explicit = only_explicit
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def trace(grammar)
+ return if !@rules || @only_explicit
+
+ @io << "Grammar rules:" << "\n"
+ grammar.rules.each { |rule| @io << rule.display_name << "\n" }
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/tracer/state.rb b/tool/lrama/lib/lrama/tracer/state.rb
new file mode 100644
index 0000000000..21c0047f8e
--- /dev/null
+++ b/tool/lrama/lib/lrama/tracer/state.rb
@@ -0,0 +1,33 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Tracer
+ class State
+ # @rbs (IO io, ?automaton: bool, ?closure: bool, **bool) -> void
+ def initialize(io, automaton: false, closure: false, **_)
+ @io = io
+ @state = automaton || closure
+ end
+
+ # @rbs (Lrama::State state) -> void
+ def trace(state)
+ return unless @state
+
+ # Bison 3.8.2 renders "(reached by "end-of-input")" for State 0 but
+ # I think it is not correct...
+ previous = state.kernels.first.previous_sym
+ @io << "Processing state #{state.id} (reached by #{previous.display_name})" << "\n"
+ end
+
+ # @rbs (Integer state_count, Lrama::State state) -> void
+ def trace_list_append(state_count, state)
+ return unless @state
+
+ previous = state.kernels.first.previous_sym
+ @io << sprintf("state_list_append (state = %d, symbol = %d (%s))",
+ state_count, previous.number, previous.display_name) << "\n"
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/version.rb b/tool/lrama/lib/lrama/version.rb
index 12ece5a8f2..eb1d1b46c7 100644
--- a/tool/lrama/lib/lrama/version.rb
+++ b/tool/lrama/lib/lrama/version.rb
@@ -1,5 +1,6 @@
+# rbs_inline: enabled
# frozen_string_literal: true
module Lrama
- VERSION = "0.7.0".freeze
+ VERSION = "0.8.0".freeze #: String
end
diff --git a/tool/lrama/lib/lrama/warnings.rb b/tool/lrama/lib/lrama/warnings.rb
new file mode 100644
index 0000000000..52f09144ef
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings.rb
@@ -0,0 +1,33 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+require_relative 'warnings/conflicts'
+require_relative 'warnings/implicit_empty'
+require_relative 'warnings/name_conflicts'
+require_relative 'warnings/redefined_rules'
+require_relative 'warnings/required'
+require_relative 'warnings/useless_precedence'
+
+module Lrama
+ class Warnings
+ # @rbs (Logger logger, bool warnings) -> void
+ def initialize(logger, warnings)
+ @conflicts = Conflicts.new(logger, warnings)
+ @implicit_empty = ImplicitEmpty.new(logger, warnings)
+ @name_conflicts = NameConflicts.new(logger, warnings)
+ @redefined_rules = RedefinedRules.new(logger, warnings)
+ @required = Required.new(logger, warnings)
+ @useless_precedence = UselessPrecedence.new(logger, warnings)
+ end
+
+ # @rbs (Lrama::Grammar grammar, Lrama::States states) -> void
+ def warn(grammar, states)
+ @conflicts.warn(states)
+ @implicit_empty.warn(grammar)
+ @name_conflicts.warn(grammar)
+ @redefined_rules.warn(grammar)
+ @required.warn(grammar)
+ @useless_precedence.warn(grammar, states)
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/warnings/conflicts.rb b/tool/lrama/lib/lrama/warnings/conflicts.rb
new file mode 100644
index 0000000000..6ba0de6f9c
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings/conflicts.rb
@@ -0,0 +1,27 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Warnings
+ class Conflicts
+ # @rbs (Lrama::Logger logger, bool warnings) -> void
+ def initialize(logger, warnings)
+ @logger = logger
+ @warnings = warnings
+ end
+
+ # @rbs (Lrama::States states) -> void
+ def warn(states)
+ return unless @warnings
+
+ if states.sr_conflicts_count != 0
+ @logger.warn("shift/reduce conflicts: #{states.sr_conflicts_count} found")
+ end
+
+ if states.rr_conflicts_count != 0
+ @logger.warn("reduce/reduce conflicts: #{states.rr_conflicts_count} found")
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/warnings/implicit_empty.rb b/tool/lrama/lib/lrama/warnings/implicit_empty.rb
new file mode 100644
index 0000000000..ba81adca01
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings/implicit_empty.rb
@@ -0,0 +1,29 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Warnings
+ # Warning rationale: Empty rules are easily overlooked and ambiguous
+ # - Empty alternatives like `rule: | "token";` can be missed during code reading
+ # - Difficult to distinguish between intentional empty rules vs. omissions
+ # - Explicit marking with %empty directive comment improves clarity
+ class ImplicitEmpty
+ # @rbs (Lrama::Logger logger, bool warnings) -> void
+ def initialize(logger, warnings)
+ @logger = logger
+ @warnings = warnings
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def warn(grammar)
+ return unless @warnings
+
+ grammar.rule_builders.each do |builder|
+ if builder.rhs.empty?
+ @logger.warn("warning: empty rule without %empty")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/warnings/name_conflicts.rb b/tool/lrama/lib/lrama/warnings/name_conflicts.rb
new file mode 100644
index 0000000000..c0754ab551
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings/name_conflicts.rb
@@ -0,0 +1,63 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Warnings
+ # Warning rationale: Parameterized rule names conflicting with symbol names
+ # - When a %rule name is identical to a terminal or non-terminal symbol name,
+ # it reduces grammar readability and may cause unintended behavior
+ # - Detecting these conflicts helps improve grammar definition quality
+ class NameConflicts
+ # @rbs (Lrama::Logger logger, bool warnings) -> void
+ def initialize(logger, warnings)
+ @logger = logger
+ @warnings = warnings
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def warn(grammar)
+ return unless @warnings
+ return if grammar.parameterized_rules.empty?
+
+ symbol_names = collect_symbol_names(grammar)
+ check_conflicts(grammar.parameterized_rules, symbol_names)
+ end
+
+ private
+
+ # @rbs (Lrama::Grammar grammar) -> Set[String]
+ def collect_symbol_names(grammar)
+ symbol_names = Set.new
+
+ collect_term_names(grammar.terms, symbol_names)
+ collect_nterm_names(grammar.nterms, symbol_names)
+
+ symbol_names
+ end
+
+ # @rbs (Array[untyped] terms, Set[String] symbol_names) -> void
+ def collect_term_names(terms, symbol_names)
+ terms.each do |term|
+ symbol_names.add(term.id.s_value)
+ symbol_names.add(term.alias_name) if term.alias_name
+ end
+ end
+
+ # @rbs (Array[untyped] nterms, Set[String] symbol_names) -> void
+ def collect_nterm_names(nterms, symbol_names)
+ nterms.each do |nterm|
+ symbol_names.add(nterm.id.s_value)
+ end
+ end
+
+ # @rbs (Array[untyped] parameterized_rules, Set[String] symbol_names) -> void
+ def check_conflicts(parameterized_rules, symbol_names)
+ parameterized_rules.each do |param_rule|
+ next unless symbol_names.include?(param_rule.name)
+
+ @logger.warn("warning: parameterized rule name \"#{param_rule.name}\" conflicts with symbol name")
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/warnings/redefined_rules.rb b/tool/lrama/lib/lrama/warnings/redefined_rules.rb
new file mode 100644
index 0000000000..8ac2f1f103
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings/redefined_rules.rb
@@ -0,0 +1,23 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Warnings
+ class RedefinedRules
+ # @rbs (Lrama::Logger logger, bool warnings) -> void
+ def initialize(logger, warnings)
+ @logger = logger
+ @warnings = warnings
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def warn(grammar)
+ return unless @warnings
+
+ grammar.parameterized_resolver.redefined_rules.each do |rule|
+ @logger.warn("parameterized rule redefined: #{rule}")
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/warnings/required.rb b/tool/lrama/lib/lrama/warnings/required.rb
new file mode 100644
index 0000000000..4ab1ed787e
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings/required.rb
@@ -0,0 +1,23 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Warnings
+ class Required
+ # @rbs (Lrama::Logger logger, bool warnings) -> void
+ def initialize(logger, warnings = false, **_)
+ @logger = logger
+ @warnings = warnings
+ end
+
+ # @rbs (Lrama::Grammar grammar) -> void
+ def warn(grammar)
+ return unless @warnings
+
+ if grammar.required
+ @logger.warn("currently, %require is simply valid as a grammar but does nothing")
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/warnings/useless_precedence.rb b/tool/lrama/lib/lrama/warnings/useless_precedence.rb
new file mode 100644
index 0000000000..2913d6d7e5
--- /dev/null
+++ b/tool/lrama/lib/lrama/warnings/useless_precedence.rb
@@ -0,0 +1,25 @@
+# rbs_inline: enabled
+# frozen_string_literal: true
+
+module Lrama
+ class Warnings
+ class UselessPrecedence
+ # @rbs (Lrama::Logger logger, bool warnings) -> void
+ def initialize(logger, warnings)
+ @logger = logger
+ @warnings = warnings
+ end
+
+ # @rbs (Lrama::Grammar grammar, Lrama::States states) -> void
+ def warn(grammar, states)
+ return unless @warnings
+
+ grammar.precedences.each do |precedence|
+ unless precedence.used_by?
+ @logger.warn("Precedence #{precedence.s_value} (line: #{precedence.lineno}) is defined but not used in any rule.")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/tool/lrama/template/bison/_yacc.h b/tool/lrama/template/bison/_yacc.h
index 34ed6d81f5..3e270c9171 100644
--- a/tool/lrama/template/bison/_yacc.h
+++ b/tool/lrama/template/bison/_yacc.h
@@ -28,6 +28,7 @@ extern int yydebug;
<%-# b4_declare_yylstype -%>
<%-# b4_value_type_define -%>
/* Value type. */
+<% if output.grammar.union %>
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
@@ -40,6 +41,13 @@ typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
+<% else %>
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+<% end %>
<%-# b4_location_type_define -%>
/* Location type. */
diff --git a/tool/lrama/template/diagram/diagram.html b/tool/lrama/template/diagram/diagram.html
new file mode 100644
index 0000000000..3e87e6e519
--- /dev/null
+++ b/tool/lrama/template/diagram/diagram.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Lrama syntax diagrams</title>
+
+ <style>
+ <%= output.default_style %>
+ .diagram-header {
+ display: inline-block;
+ font-weight: bold;
+ font-size: 18px;
+ margin-bottom: -8px;
+ text-align: center;
+ }
+
+ svg {
+ width: 100%;
+ }
+
+ svg.railroad-diagram g.non-terminal text {
+ cursor: pointer;
+ }
+
+ h2.hover-header {
+ background-color: #90ee90;
+ }
+
+ svg.railroad-diagram g.non-terminal.hover-g rect {
+ fill: #eded91;
+ stroke: 5;
+ }
+
+ svg.railroad-diagram g.terminal.hover-g rect {
+ fill: #eded91;
+ stroke: 5;
+ }
+ </style>
+</head>
+
+<body align="center">
+ <%= output.diagrams %>
+ <script>
+ document.addEventListener("DOMContentLoaded", () => {
+ function addHoverEffect(selector, hoverClass, relatedSelector, relatedHoverClass, getTextElements) {
+ document.querySelectorAll(selector).forEach(element => {
+ element.addEventListener("mouseenter", () => {
+ element.classList.add(hoverClass);
+ getTextElements(element).forEach(textEl => {
+ if (!relatedSelector) return;
+ getElementsByText(relatedSelector, textEl.textContent).forEach(related => {
+ related.classList.add(relatedHoverClass);
+ });
+ });
+ });
+
+ element.addEventListener("mouseleave", () => {
+ element.classList.remove(hoverClass);
+ if (!relatedSelector) return;
+ getTextElements(element).forEach(textEl => {
+ getElementsByText(relatedSelector, textEl.textContent).forEach(related => {
+ related.classList.remove(relatedHoverClass);
+ });
+ });
+ });
+ });
+ }
+
+ function getElementsByText(selector, text) {
+ return [...document.querySelectorAll(selector)].filter(el => el.textContent.trim() === text.trim());
+ }
+
+ function getParentElementsByText(selector, text) {
+ return [...document.querySelectorAll(selector)].filter(el =>
+ [...el.querySelectorAll("text")].some(textEl => textEl.textContent.trim() === text.trim())
+ );
+ }
+
+ function scrollToMatchingHeader() {
+ document.querySelectorAll("g.non-terminal").forEach(element => {
+ element.addEventListener("click", () => {
+ const textElements = [...element.querySelectorAll("text")];
+ for (const textEl of textElements) {
+ const targetHeader = getElementsByText("h2", textEl.textContent)[0];
+ if (targetHeader) {
+ targetHeader.scrollIntoView({ behavior: "smooth", block: "start" });
+ break;
+ }
+ }
+ });
+ });
+ }
+
+ addHoverEffect("h2", "hover-header", "g.non-terminal", "hover-g", element => [element]);
+ addHoverEffect("g.non-terminal", "hover-g", "h2", "hover-header",
+ element => [...element.querySelectorAll("text")]
+ );
+ addHoverEffect("g.terminal", "hover-g", "", "", element => [element]);
+ scrollToMatchingHeader();
+ });
+ </script>
+</body>
+</html>
diff --git a/tool/m4/ruby_append_option.m4 b/tool/m4/ruby_append_option.m4
index 98359fa1f9..8cd2741ae8 100644
--- a/tool/m4/ruby_append_option.m4
+++ b/tool/m4/ruby_append_option.m4
@@ -4,6 +4,6 @@ AC_DEFUN([RUBY_APPEND_OPTION],
AS_CASE([" [$]{$1-} "],
[*" $2 "*], [], [' '], [ $1="$2"], [ $1="[$]$1 $2"])])dnl
AC_DEFUN([RUBY_PREPEND_OPTION],
- [# RUBY_APPEND_OPTION($1)
+ [# RUBY_PREPEND_OPTION($1)
AS_CASE([" [$]{$1-} "],
[*" $2 "*], [], [' '], [ $1="$2"], [ $1="$2 [$]$1"])])dnl
diff --git a/tool/m4/ruby_defint.m4 b/tool/m4/ruby_defint.m4
index e9ed68e5b8..7f262a73fc 100644
--- a/tool/m4/ruby_defint.m4
+++ b/tool/m4/ruby_defint.m4
@@ -17,7 +17,8 @@ typedef $1 t; int s = sizeof(t) == 42;])],
["${ac_cv_sizeof___int128@%:@*:}"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int128"],
[ rb_cv_type_$1=no])])])
AS_IF([test "${rb_cv_type_$1}" != no], [
- type="${rb_cv_type_$1@%:@@%:@unsigned }"
+ type="${rb_cv_type_$1@%:@@%:@*signed }"
+ AS_IF([test "$type" = "long long"], [type=long_long])
AS_IF([test "$type" != yes && eval 'test -n "${ac_cv_sizeof_'$type'+set}"'], [
eval cond='"${ac_cv_sizeof_'$type'}"'
AS_CASE([$cond], [*:*], [
diff --git a/tool/make-snapshot b/tool/make-snapshot
index c7ccc468d4..dff636d601 100755
--- a/tool/make-snapshot
+++ b/tool/make-snapshot
@@ -10,6 +10,7 @@ require 'fileutils'
require 'shellwords'
require 'tmpdir'
require 'pathname'
+require 'date'
require 'yaml'
require 'json'
require File.expand_path("../lib/vcs", __FILE__)
@@ -53,7 +54,7 @@ PACKAGES = {
"xz" => %w".tar.xz xz -c",
"zip" => %w".zip zip -Xqr",
}
-DEFAULT_PACKAGES = PACKAGES.keys - ["tar"]
+DEFAULT_PACKAGES = PACKAGES.keys - ["tar", "bzip"]
if !$no7z and system("7z", out: IO::NULL)
PACKAGES["gzip"] = %w".tar.gz 7z a dummy -tgzip -mx -so"
PACKAGES["zip"] = %w".zip 7z a -tzip -mx -mtc=off" << {out: IO::NULL}
@@ -252,7 +253,6 @@ end
def package(vcs, rev, destdir, tmp = nil)
pwd = Dir.pwd
- patchlevel = false
prerelease = false
if rev and revision = rev[/@(\h+)\z/, 1]
rev = $`
@@ -269,22 +269,23 @@ def package(vcs, rev, destdir, tmp = nil)
when /\Astable\z/
vcs.branch_list("ruby_[0-9]*") {|n| url = n[/\Aruby_\d+_\d+\z/]}
url &&= vcs.branch(url)
- when /\A(.*)\.(.*)\.(.*)-(preview|rc)(\d+)/
+ when /\A(\d+)\.(\d+)\.(\d+)-(preview|rc)(\d+)/
prerelease = true
tag = "#{$4}#{$5}"
- url = vcs.tag("v#{$1}_#{$2}_#{$3}_#{$4}#{$5}")
- when /\A(.*)\.(.*)\.(.*)-p(\d+)/
- patchlevel = true
- tag = "p#{$4}"
- url = vcs.tag("v#{$1}_#{$2}_#{$3}_#{$4}")
- when /\A(\d+)\.(\d+)(?:\.(\d+))?\z/
- if $3 && ($1 > "2" || $1 == "2" && $2 >= "1")
- patchlevel = true
- tag = ""
- url = vcs.tag("v#{$1}_#{$2}_#{$3}")
+ if Integer($1) >= 4
+ url = vcs.tag("v#{rev}")
+ else
+ url = vcs.tag("v#{$1}_#{$2}_#{$3}_#{$4}#{$5}")
+ end
+ when /\A(\d+)\.(\d+)\.(\d+)\z/
+ tag = ""
+ if Integer($1) >= 4
+ url = vcs.tag("v#{rev}")
else
- url = vcs.branch("ruby_#{rev.tr('.', '_')}")
+ url = vcs.tag("v#{$1}_#{$2}_#{$3}")
end
+ when /\A(\d+)\.(\d+)\z/
+ url = vcs.branch("ruby_#{rev.tr('.', '_')}")
else
warn "#{$0}: unknown version - #{rev}"
return
@@ -334,7 +335,7 @@ def package(vcs, rev, destdir, tmp = nil)
FileUtils.rm(file, verbose: $VERBOSE)
end
- status = IO.read(File.dirname(__FILE__) + "/prereq.status")
+ status = File.read(File.dirname(__FILE__) + "/prereq.status")
Dir.chdir(tmp) if tmp
if !File.directory?(v)
@@ -346,26 +347,20 @@ def package(vcs, rev, destdir, tmp = nil)
File.open("#{v}/revision.h", "wb") {|f|
f.puts vcs.revision_header(revision, modified)
}
- version ||= (versionhdr = IO.read("#{v}/version.h"))[RUBY_VERSION_PATTERN, 1]
+ version ||= (versionhdr = File.read("#{v}/version.h"))[RUBY_VERSION_PATTERN, 1]
version ||=
begin
- include_ruby_versionhdr = IO.read("#{v}/include/ruby/version.h")
+ include_ruby_versionhdr = File.read("#{v}/include/ruby/version.h")
api_major_version = include_ruby_versionhdr[/^\#define\s+RUBY_API_VERSION_MAJOR\s+([\d.]+)/, 1]
api_minor_version = include_ruby_versionhdr[/^\#define\s+RUBY_API_VERSION_MINOR\s+([\d.]+)/, 1]
version_teeny = versionhdr[/^\#define\s+RUBY_VERSION_TEENY\s+(\d+)/, 1]
[api_major_version, api_minor_version, version_teeny].join('.')
end
version or return
- if patchlevel
- unless tag.empty?
- versionhdr ||= IO.read("#{v}/version.h")
- patchlevel = versionhdr[/^\#define\s+RUBY_PATCHLEVEL\s+(\d+)/, 1]
- tag = (patchlevel ? "p#{patchlevel}" : vcs.revision_name(revision))
- end
- elsif prerelease
- versionhdr ||= IO.read("#{v}/version.h")
+ if prerelease
+ versionhdr ||= File.read("#{v}/version.h")
versionhdr.sub!(/^\#\s*define\s+RUBY_PATCHLEVEL_STR\s+"\K.+?(?=")/, tag) or raise "no match of RUBY_PATCHLEVEL_STR to replace"
- IO.write("#{v}/version.h", versionhdr)
+ File.write("#{v}/version.h", versionhdr)
else
tag ||= vcs.revision_name(revision)
end
@@ -430,7 +425,7 @@ def package(vcs, rev, destdir, tmp = nil)
puts "cross.rb:", File.read("cross.rb").gsub(/^/, "> "), "" if $VERBOSE
unless File.exist?("configure")
print "creating configure..."
- unless system([ENV["AUTOCONF"]]*2)
+ unless system(File.exist?(gen = "./autogen.sh") ? gen : [ENV["AUTOCONF"]]*2)
puts $colorize.fail(" failed")
return
end
@@ -439,11 +434,11 @@ def package(vcs, rev, destdir, tmp = nil)
clean.add("autom4te.cache")
clean.add("enc/unicode/data")
print "creating prerequisites..."
- if File.file?("common.mk") && /^prereq/ =~ commonmk = IO.read("common.mk")
+ if File.file?("common.mk") && /^prereq/ =~ commonmk = File.read("common.mk")
puts
extout = clean.add('tmp')
begin
- status = IO.read("tool/prereq.status")
+ status = File.read("tool/prereq.status")
rescue Errno::ENOENT
# use fallback file
end
@@ -456,7 +451,7 @@ def package(vcs, rev, destdir, tmp = nil)
File.binwrite("#{defaults}/ruby.rb", "")
miniruby = ENV['MINIRUBY'] + " -I. -I#{extout} -rcross"
baseruby = ENV["BASERUBY"]
- mk = (IO.read("template/Makefile.in") rescue IO.read("Makefile.in")).
+ mk = (File.read("template/Makefile.in") rescue File.read("Makefile.in")).
gsub(/^@.*\n/, '')
vars = {
"EXTOUT"=>extout,
@@ -472,6 +467,7 @@ def package(vcs, rev, destdir, tmp = nil)
"VPATH"=>(ENV["VPATH"] || "include/ruby"),
"PROGRAM"=>(ENV["PROGRAM"] || "ruby"),
"BUILTIN_TRANSOBJS"=>(ENV["BUILTIN_TRANSOBJS"] || "newline.o"),
+ "DUMP_AST"=>"build-tool/dump_ast#{RbConfig::CONFIG['EXEEXT']} ",
}
status.scan(/^s([%,])@([A-Za-z_][A-Za-z_0-9]*)@\1(.*?)\1g$/) do
vars[$2] ||= $3
@@ -480,6 +476,13 @@ def package(vcs, rev, destdir, tmp = nil)
vars["UNICODE_VERSION"] = $unicode_version if $unicode_version
args = vars.dup
mk.gsub!(/@([A-Za-z_]\w*)@/) {args.delete($1); vars[$1] || ENV[$1]}
+ commonmk.gsub!(/^!(?:include \$\(srcdir\)\/(.*))?/) do
+ if inc = $1 and File.exist?(inc)
+ File.binread(inc).gsub(/^!/, '# !')
+ else
+ "#"
+ end
+ end
mk << commonmk.gsub(/\{\$([^(){}]*)[^{}]*\}/, "").sub(/^revision\.tmp::$/, '\& Makefile')
mk << <<-'APPEND'
@@ -508,6 +511,7 @@ touch-unicode-files:
File.utime(modified, modified, *Dir.glob(["tool/config.{guess,sub}", "gems/*.gem", "tool"]))
return unless make.run("prepare-package")
return unless make.run("clean-cache")
+ return unless make.run("clean")
if modified
new_time = modified + 2
touch_all(new_time, "**/*", File::FNM_DOTMATCH) do |name, stat|
@@ -634,7 +638,7 @@ revisions.collect {|rev| package(vcs, rev, destdir, tmp)}.flatten.each do |name|
key = basename[/\A(.*)\.(?:tar|zip)/, 1]
info[key] ||= Hash.new{|h,k|h[k]={}}
info[key]['version'] = version if version
- info[key]['date'] = release_date.strftime('%Y-%m-%d')
+ info[key]['date'] = release_date.to_date
if version
info[key]['post'] = "/en/news/#{release_date.strftime('%Y/%m/%d')}/ruby-#{version.tr('.', '-')}-released/"
info[key]['url'][extname] = "https://cache.ruby-lang.org/pub/ruby/#{version[/\A\d+\.\d+/]}/#{basename}"
diff --git a/tool/merger.rb b/tool/merger.rb
index 8b12334b73..4c096087fc 100755
--- a/tool/merger.rb
+++ b/tool/merger.rb
@@ -65,7 +65,8 @@ class << Merger = Object.new
if teeny
v[2].succ!
end
- if pl != '-1' # trunk does not have patchlevel
+ # We stopped bumping RUBY_PATCHLEVEL at Ruby 4.0.0.
+ if Integer(v[0]) <= 3
pl.succ!
end
@@ -113,7 +114,13 @@ class << Merger = Object.new
abort 'no relname is given and not in a release branch even if this is patch release'
end
end
- tagname = "v#{v.join('_')}#{("_#{pl}" if v[0] < "2" || (v[0] == "2" && v[1] < "1") || /^(?:preview|rc)/ =~ pl)}"
+ if /^(?:preview|rc)/ =~ pl
+ tagname = "v#{v.join('.')}-#{pl}"
+ elsif Integer(v[0]) >= 4
+ tagname = "v#{v.join('.')}"
+ else
+ tagname = "v#{v.join('_')}"
+ end
unless execute('git', 'diff', '--exit-code')
abort 'uncommitted changes'
@@ -135,10 +142,12 @@ class << Merger = Object.new
unless relname
raise ArgumentError, 'relname is not specified'
end
- if /^v/ !~ relname
- tagname = "v#{relname.gsub(/[.-]/, '_')}"
- else
+ if relname.start_with?('v')
tagname = relname
+ elsif Integer(relname.split('.', 2).first) >= 4
+ tagname = "v#{relname}"
+ else
+ tagname = "v#{relname.gsub(/[.-]/, '_')}"
end
execute('git', 'tag', '-d', tagname)
@@ -263,7 +272,7 @@ else
end
# Merge revision from Git patch
- git_uri = "https://git.ruby-lang.org/ruby.git/patch/?id=#{git_rev}"
+ git_uri = "https://github.com/ruby/ruby/commit/#{git_rev}.patch"
resp = Net::HTTP.get_response(URI(git_uri))
if resp.code != '200'
abort "'#{git_uri}' returned status '#{resp.code}':\n#{resp.body}"
diff --git a/tool/missing-baseruby.bat b/tool/missing-baseruby.bat
index fcc75ea902..d39568fe86 100755
--- a/tool/missing-baseruby.bat
+++ b/tool/missing-baseruby.bat
@@ -18,6 +18,13 @@
: ; abort () { exit 1; }
call :warn "executable host ruby is required. use --with-baseruby option."
-call :warn "Note that BASERUBY must be Ruby 3.0.0 or later."
+call :warn "Note that BASERUBY must be Ruby 3.1.0 or later."
call :abort
-: || (:^; abort if RUBY_VERSION < s[%r"warn .*Ruby ([\d.]+)(?:\.0)?",1])
+(goto :eof ^;)
+verbose = true if ARGV[0] == "--verbose"
+case
+when !defined?(RubyVM::InstructionSequence)
+ abort(*(["BASERUBY must be CRuby"] if verbose))
+when RUBY_VERSION < s[%r[warn .*\KBASERUBY .*Ruby ([\d.]+)(?:\.0)?.*(?=\")],1]
+ abort(*(["#{$&}. Found: #{RUBY_VERSION}"] if verbose))
+end
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index 6e1f5c666a..a84f322e84 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -1,12 +1,13 @@
# Parse built-in script and make rbinc file
-require 'ripper'
+require 'json'
+require 'open3'
require 'stringio'
require_relative 'ruby_vm/helpers/c_escape'
SUBLIBS = {}
REQUIRED = {}
-BUILTIN_ATTRS = %w[leaf inline_block use_block c_trace]
+BUILTIN_ATTRS = %w[leaf inline_block use_block c_trace without_interrupts]
module CompileWarning
@@warnings = 0
@@ -24,231 +25,204 @@ end
Warning.extend CompileWarning
-def string_literal(lit, str = [])
- while lit
- case lit.first
- when :string_concat, :string_embexpr, :string_content
- _, *lit = lit
- lit.each {|s| string_literal(s, str)}
- return str
- when :string_literal
- _, lit = lit
- when :@tstring_content
- str << lit[1]
- return str
- else
- raise "unexpected #{lit.first}"
- end
- end
-end
+# ruby mk_builtin_loader.rb path/to/dump_ast TARGET_FILE.rb
+# #=> generate TARGET_FILE.rbinc
+#
+# dump_ast is a standalone C program (tool/dump_ast.c) that parses Ruby files
+# with prism and dumps the AST as JSON. It must be compiled with CC before this
+# script can run, which means rbinc generation is skipped during `make up`
+# (where CC=false). The rbinc files are gitignored build artifacts, so they do
+# not need to be present in srcdir after `make up` — they will be generated in
+# the build directory during `make all` once dump_ast has been compiled.
+
+LOCALS_DB = {} # [method_name, first_line] = locals
-# e.g. [:symbol_literal, [:symbol, [:@ident, "inline", [19, 21]]]]
-def symbol_literal(lit)
- symbol_literal, symbol_lit = lit
- raise "#{lit.inspect} was not :symbol_literal" if symbol_literal != :symbol_literal
- symbol, ident_lit = symbol_lit
- raise "#{symbol_lit.inspect} was not :symbol" if symbol != :symbol
- ident, symbol_name, = ident_lit
- raise "#{ident.inspect} was not :@ident" if ident != :@ident
- symbol_name
+# Extract the contents of the given string node.
+def extract_string_literal(node)
+ case node["type"]
+ when "StringNode"
+ node["unescaped"]
+ when "InterpolatedStringNode"
+ node["parts"].map { |part| extract_string_literal(part) }.join
+ else
+ raise "unexpected #{node["type"]}"
+ end
end
-def inline_text argc, arg1
- raise "argc (#{argc}) of inline! should be 1" unless argc == 1
- arg1 = string_literal(arg1)
- raise "1st argument should be string literal" unless arg1
- arg1.join("").rstrip
+# Retrieve the line number of the given node in the source.
+def line_number(source, node)
+ source.b.byteslice(0, node["location"]["start"]).count("\n") + 1
end
-def inline_attrs(args)
- raise "args was empty" if args.empty?
- args.each do |arg|
- attr = symbol_literal(arg)
- unless BUILTIN_ATTRS.include?(attr)
- raise "attr (#{attr}) was not in: #{BUILTIN_ATTRS.join(', ')}"
- end
+def visit_call_node(source, node, name, locals, requires, bs, inlines)
+ # If this is a call to require or require relative with a single string node
+ # argument, then we will attempt to find the file that is being required and
+ # add it to the files that should be processed.
+ if %w[require require_relative].include?(node["name"]) && !node["arguments"].nil? && (argument = node["arguments"]["arguments"][0])["type"] == "StringNode"
+ requires << argument["unescaped"]
+ return true
end
-end
-def make_cfunc_name inlines, name, lineno
- case name
- when /\[\]/
- name = '_GETTER'
- when /\[\]=/
- name = '_SETTER'
+ primitive_name = nil
+
+ receiver = node["receiver"]
+
+ if (!receiver.nil? && receiver["type"] == "ConstantReadNode" && receiver["name"] == "Primitive") ||
+ (!receiver.nil? && receiver["type"] == "CallNode" && receiver["flags"].include?("VARIABLE_CALL") && receiver["name"] == "__builtin")
+ primitive_name = node["name"]
+ elsif node["name"].start_with?("__builtin_")
+ primitive_name = node["name"][10..-1]
else
- name = name.tr('!?', 'EP')
+ # If we get here, then this isn't a primitive function call and we can
+ # continue the visit.
+ return true
end
- base = "builtin_inline_#{name}_#{lineno}"
- if inlines[base]
- 1000.times{|i|
- name = "#{base}_#{i}"
- return name unless inlines[name]
- }
- raise "too many functions in same line..."
- else
- base
+ # The name of the C function that we will be calling for this call node. It
+ # may change later in this method depending on the type of primitive.
+ cfunction_name = primitive_name
+
+ args = node["arguments"].nil? ? [] : node["arguments"]["arguments"]
+ argc = args.size
+
+ if primitive_name.match?(/[\!\?]$/)
+ case (primitive_macro = primitive_name[0...-1])
+ when "arg"
+ # This is a call to Primitive.arg!, which expects a single symbol argument
+ # detailing the name of the argument.
+ raise "unexpected argument number #{argc}" if argc != 1
+ raise "symbol literal expected, got #{args[0]["type"]}" if args[0]["type"] != "SymbolNode"
+ return true
+ when "attr"
+ # This is a call to Primitive.attr!, which expects a list of known
+ # symbols. We will check that each of the arguments is a symbol and that
+ # the symbol is one of the known symbols.
+ raise "args was empty" if argc == 0
+
+ args.each do |arg|
+ raise "#{arg["type"]} was not a SymbolNode" if arg["type"] != "SymbolNode"
+ raise "attr (#{arg["unescaped"]}) was not in: leaf, inline_block, use_block" unless BUILTIN_ATTRS.include?(arg["unescaped"])
+ end
+
+ return true
+ when "mandatory_only"
+ # This is a call to Primitive.mandatory_only?. This method does not
+ # require any further processing.
+ return true
+ when "cstmt", "cexpr", "cconst", "cinit"
+ # This is a call to Primitive.cstmt!, Primitive.cexpr!, Primitive.cconst!,
+ # or Primitive.cinit!. These methods expect a single string argument that
+ # is the C code that should be executed. We will extract the string, emit
+ # an inline function, and then continue the visit.
+ raise "argc (#{argc}) of inline! should be 1" if argc != 1
+
+ text = extract_string_literal(args[0]).rstrip
+ lineno = line_number(source, node)
+
+ case primitive_macro
+ when "cstmt", "cexpr", "cconst"
+ cfunction_name = "builtin_inline_#{name}_#{lineno}"
+ primitive_name = "_bi#{lineno}"
+
+ if primitive_macro == "cstmt"
+ inlines << [cfunction_name, lineno, text, locals, primitive_name]
+ else
+ inlines << [cfunction_name, lineno, "return #{text};", primitive_macro == "cexpr" ? locals : nil, primitive_name]
+ end
+ when "cinit"
+ inlines << [inlines.size, lineno, text, nil, nil]
+ return true
+ end
+
+ argc -= 1
+ else
+ # This is a call to Primitive that is not a known method, so it must be a
+ # regular C function. In this case we do not need any special processing.
+ end
end
+
+ bs << [primitive_name, argc, cfunction_name]
+ return true
end
-def collect_locals tree
- _type, name, (line, _cols) = tree
- if locals = LOCALS_DB[[name, line]]
- locals
- else
- if false # for debugging
- pp LOCALS_DB
- raise "not found: [#{name}, #{line}]"
+def each_node(root, &blk)
+ return unless yield root
+
+ root.each do |key, value|
+ next if key == "type" || key == "location"
+
+ if value.is_a?(Hash)
+ each_node(value, &blk) if value.key?("type")
+ elsif value.is_a?(Array) && value[0].is_a?(Hash)
+ value.each { |node| each_node(node, &blk) }
end
end
end
-def collect_builtin base, tree, name, bs, inlines, locals = nil
- while tree
- recv = sep = mid = args = nil
- case tree.first
- when :def
- locals = collect_locals(tree[1])
- tree = tree[3]
- next
- when :defs
- locals = collect_locals(tree[3])
- tree = tree[5]
- next
- when :class
- name = 'class'
- tree = tree[3]
- next
- when :sclass, :module
- name = 'class'
- tree = tree[2]
- next
- when :method_add_arg
- _method_add_arg, mid, (_arg_paren, args) = tree
- case mid.first
- when :call
- _, recv, sep, mid = mid
- when :fcall
- _, mid = mid
- else
- mid = nil
- end
- # w/ trailing comma: [[:method_add_arg, ...]]
- # w/o trailing comma: [:args_add_block, [[:method_add_arg, ...]], false]
- if args && args.first == :args_add_block
- args = args[1]
- end
- when :vcall
- _, mid = tree
- when :command # FCALL
- _, mid, (_, args) = tree
- when :call, :command_call # CALL
- _, recv, sep, mid, (_, args) = tree
+def visit_node(source, root, name, locals, requires, bs, inlines)
+ each_node(root) do |node|
+ case node["type"]
+ when "CallNode"
+ visit_call_node(source, node, name, locals, requires, bs, inlines)
+ when "DefNode"
+ lineno = line_number(source, node)
+ visit_node(source, node["body"], name, LOCALS_DB[[node["name"], lineno]], requires, bs, inlines) if node["body"]
+ false
+ when "ClassNode", "ModuleNode", "SingletonClassNode"
+ visit_node(source, node["body"], "class", nil, requires, bs, inlines) if node["body"]
+ false
+ else
+ true
end
+ end
+end
- if mid
- raise "unknown sexp: #{mid.inspect}" unless %i[@ident @const].include?(mid.first)
- _, mid, (lineno,) = mid
- if recv
- func_name = nil
- case recv.first
- when :var_ref
- _, recv = recv
- if recv.first == :@const and recv[1] == "Primitive"
- func_name = mid.to_s
- end
- when :vcall
- _, recv = recv
- if recv.first == :@ident and recv[1] == "__builtin"
- func_name = mid.to_s
- end
- end
- collect_builtin(base, recv, name, bs, inlines) unless func_name
- else
- func_name = mid[/\A__builtin_(.+)/, 1]
- end
- if func_name
- cfunc_name = func_name
- args.pop unless (args ||= []).last
- argc = args.size
-
- if /(.+)[\!\?]\z/ =~ func_name
- case $1
- when 'attr'
- # Compile-time validation only. compile.c will parse them.
- inline_attrs(args)
- break
- when 'cstmt'
- text = inline_text argc, args.first
-
- func_name = "_bi#{lineno}"
- cfunc_name = make_cfunc_name(inlines, name, lineno)
- inlines[cfunc_name] = [lineno, text, locals, func_name]
- argc -= 1
- when 'cexpr', 'cconst'
- text = inline_text argc, args.first
- code = "return #{text};"
-
- func_name = "_bi#{lineno}"
- cfunc_name = make_cfunc_name(inlines, name, lineno)
-
- locals = [] if $1 == 'cconst'
- inlines[cfunc_name] = [lineno, code, locals, func_name]
- argc -= 1
- when 'cinit'
- text = inline_text argc, args.first
- func_name = nil # required
- inlines[inlines.size] = [lineno, text, nil, nil]
- argc -= 1
- when 'mandatory_only'
- func_name = nil
- when 'arg'
- argc == 1 or raise "unexpected argument number #{argc}"
- (arg = args.first)[0] == :symbol_literal or raise "symbol literal expected #{args}"
- (arg = arg[1])[0] == :symbol or raise "symbol expected #{arg}"
- (var = arg[1] and var = var[1]) or raise "argument name expected #{arg}"
- func_name = nil
- end
- end
+def collect_builtins(dump_ast, file)
+ stdout, stderr, status = Open3.capture3(dump_ast, file)
+ unless status.success?
+ warn(stderr)
+ exit(1)
+ end
- if bs[func_name] &&
- bs[func_name] != [argc, cfunc_name]
- raise "same builtin function \"#{func_name}\", but different arity (was #{bs[func_name]} but #{argc})"
- end
+ source = File.read(file)
+ root = JSON.parse(stdout)
+ visit_node(source, root, "top", nil, requires = [], builtins = [], inlines = [])
- bs[func_name] = [argc, cfunc_name] if func_name
- elsif /\Arequire(?:_relative)\z/ =~ mid and args.size == 1 and
- (arg1 = args[0])[0] == :string_literal and
- (arg1 = arg1[1])[0] == :string_content and
- (arg1 = arg1[1])[0] == :@tstring_content and
- sublib = arg1[1]
- if File.exist?(f = File.join(@dir, sublib)+".rb")
- puts "- #{@base}.rb requires #{sublib}"
- if REQUIRED[sublib]
- warn "!!! #{sublib} is required from #{REQUIRED[sublib]} already; ignored"
- else
- REQUIRED[sublib] = @base
- (SUBLIBS[@base] ||= []) << sublib
- end
- ARGV.push(f)
- end
+ requires.each do |sublib|
+ if File.exist?(f = File.join(@dir, sublib)+".rb")
+ puts "- #{@base}.rb requires #{sublib}"
+ if REQUIRED[sublib]
+ warn "!!! #{sublib} is required from #{REQUIRED[sublib]} already; ignored"
+ else
+ REQUIRED[sublib] = @base
+ (SUBLIBS[@base] ||= []) << sublib
end
- break unless tree = args
+ ARGV.push(f)
end
+ end
- tree.each do |t|
- collect_builtin base, t, name, bs, inlines, locals if Array === t
+ processed_builtins = {}
+ builtins.each do |(primitive_name, argc, cfunction_name)|
+ if processed_builtins.key?(primitive_name) && processed_builtins[primitive_name] != [argc, cfunction_name]
+ raise "same builtin function \"#{primitive_name}\", but different arity (was #{processed_builtins[primitive_name]} but #{argc})"
end
- break
+
+ processed_builtins[primitive_name] = [argc, cfunction_name]
end
-end
-# ruby mk_builtin_loader.rb TARGET_FILE.rb
-# #=> generate TARGET_FILE.rbinc
-#
+ processed_inlines = {}
+ inlines.each do |(cfunction_name, lineno, text, locals, primitive_name)|
+ if processed_inlines.key?(cfunction_name)
+ found = 1000.times.find { |i| !processed_inlines.key?("#{cfunction_name}_#{i}") }
+ raise "too many functions in same line..." unless found
+ cfunction_name = "#{cfunction_name}_#{found}"
+ end
-LOCALS_DB = {} # [method_name, first_line] = locals
+ processed_inlines[cfunction_name] = [lineno, text, locals, primitive_name]
+ end
+
+ [processed_builtins, processed_inlines]
+end
def collect_iseq iseq_ary
# iseq_ary.each_with_index{|e, i| p [i, e]}
@@ -282,17 +256,22 @@ def generate_cexpr(ofile, lineno, line_file, body_lineno, text, locals, func_nam
# Avoid generating fetches of lvars we don't need. This is imperfect as it
# will match text inside strings or other false positives.
- local_candidates = text.scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
+ local_ptrs = []
+ local_candidates = text.gsub(/\bLOCAL_PTR\(\K[a-zA-Z_][a-zA-Z0-9_]*(?=\))/) {
+ local_ptrs << $&; ''
+ }.scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
f.puts '{'
lineno += 1
# locals is nil outside methods
locals&.reverse_each&.with_index{|param, i|
next unless Symbol === param
- next unless local_candidates.include?(param.to_s)
+ param = param.to_s
+ lvar = local_candidates.include?(param)
+ next unless lvar or local_ptrs.include?(param)
f.puts "VALUE *const #{param}__ptr = (VALUE *)&ec->cfp->ep[#{-3 - i}];"
- f.puts "MAYBE_UNUSED(const VALUE) #{param} = *#{param}__ptr;"
- lineno += 1
+ f.puts "MAYBE_UNUSED(const VALUE) #{param} = *#{param}__ptr;" if lvar
+ lineno += lvar ? 2 : 1
}
f.puts "#line #{body_lineno} \"#{line_file}\""
lineno += 1
@@ -308,24 +287,24 @@ def generate_cexpr(ofile, lineno, line_file, body_lineno, text, locals, func_nam
return lineno, f.string
end
-def mk_builtin_header file
+def mk_builtin_header dump_ast, file
@dir = File.dirname(file)
base = File.basename(file, '.rb')
@base = base
ofile = "#{file}inc"
- # bs = { func_name => argc }
- code = File.read(file)
begin
verbose, $VERBOSE = $VERBOSE, true
- collect_iseq RubyVM::InstructionSequence.compile(code, base).to_a
+ collect_iseq RubyVM::InstructionSequence.compile_file(file).to_a
ensure
$VERBOSE = verbose
end
if warnings = CompileWarning.reset
raise "#{warnings} warnings in #{file}"
end
- collect_builtin(base, Ripper.sexp(code), 'top', bs = {}, inlines = {})
+
+ # bs = { func_name => argc }
+ bs, inlines = collect_builtins(dump_ast, file)
StringIO.open do |f|
if File::ALT_SEPARATOR
@@ -418,7 +397,9 @@ def mk_builtin_header file
end
end
+dump_ast = ARGV.shift
+
ARGV.each{|file|
# feature.rb => load_feature.inc
- mk_builtin_header file
+ mk_builtin_header dump_ast, file
}
diff --git a/tool/mkconfig.rb b/tool/mkconfig.rb
index ffa4c1c0b2..db74115730 100755
--- a/tool/mkconfig.rb
+++ b/tool/mkconfig.rb
@@ -394,6 +394,7 @@ print <<EOS
)
end
end
+# Non-nil if configured for cross compiling.
CROSS_COMPILING = nil unless defined? CROSS_COMPILING
EOS
diff --git a/tool/notes-github-pr.rb b/tool/notes-github-pr.rb
new file mode 100644
index 0000000000..d69d479cdf
--- /dev/null
+++ b/tool/notes-github-pr.rb
@@ -0,0 +1,138 @@
+#!/usr/bin/env ruby
+# Add GitHub pull request reference / author info to git notes.
+
+require 'net/http'
+require 'uri'
+require 'tmpdir'
+require 'json'
+require 'yaml'
+
+# Conversion for people whose GitHub account name and SVN_ACCOUNT_NAME are different.
+GITHUB_TO_SVN = {
+ 'amatsuda' => 'a_matsuda',
+ 'matzbot' => 'git',
+ 'jeremyevans' => 'jeremy',
+ 'znz' => 'kazu',
+ 'k-tsj' => 'ktsj',
+ 'nurse' => 'naruse',
+ 'ioquatix' => 'samuel',
+ 'suketa' => 'suke',
+ 'unak' => 'usa',
+}
+
+EMAIL_YML_URL = 'https://raw.githubusercontent.com/ruby/git.ruby-lang.org/refs/heads/master/config/email.yml'
+SVN_TO_EMAILS = YAML.safe_load(Net::HTTP.get_response(URI(EMAIL_YML_URL)).tap(&:value).body)
+
+class GitHub
+ ENDPOINT = URI.parse('https://api.github.com')
+
+ def initialize(access_token)
+ @access_token = access_token
+ end
+
+ # https://developer.github.com/changes/2019-04-11-pulls-branches-for-commit/
+ def pulls(owner:, repo:, commit_sha:)
+ resp = get("/repos/#{owner}/#{repo}/commits/#{commit_sha}/pulls", accept: 'application/vnd.github.groot-preview+json')
+ JSON.parse(resp.body)
+ end
+
+ # https://developer.github.com/v3/pulls/#get-a-single-pull-request
+ def pull_request(owner:, repo:, number:)
+ resp = get("/repos/#{owner}/#{repo}/pulls/#{number}")
+ JSON.parse(resp.body)
+ end
+
+ # https://developer.github.com/v3/users/#get-a-single-user
+ def user(username:)
+ resp = get("/users/#{username}")
+ JSON.parse(resp.body)
+ end
+
+ private
+
+ def get(path, accept: 'application/vnd.github.v3+json')
+ Net::HTTP.start(ENDPOINT.host, ENDPOINT.port, use_ssl: ENDPOINT.scheme == 'https') do |http|
+ headers = { 'Accept': accept, 'Authorization': "bearer #{@access_token}" }
+ http.get(path, headers).tap(&:value)
+ end
+ end
+end
+
+module Git
+ class << self
+ def abbrev_ref(refname, repo_path:)
+ git('rev-parse', '--symbolic', '--abbrev-ref', refname, repo_path: repo_path).strip
+ end
+
+ def rev_list(arg, first_parent: false, repo_path: nil)
+ git('rev-list', *[('--first-parent' if first_parent)].compact, arg, repo_path: repo_path).lines.map(&:chomp)
+ end
+
+ def commit_message(sha)
+ git('log', '-1', '--pretty=format:%B', sha)
+ end
+
+ def notes_message(sha)
+ git('log', '-1', '--pretty=format:%N', sha)
+ end
+
+ def committer_name(sha)
+ git('log', '-1', '--pretty=format:%cn', sha)
+ end
+
+ def committer_email(sha)
+ git('log', '-1', '--pretty=format:%cE', sha)
+ end
+
+ private
+
+ def git(*cmd, repo_path: nil)
+ env = {}
+ if repo_path
+ env['GIT_DIR'] = repo_path
+ end
+ out = IO.popen(env, ['git', *cmd], &:read)
+ unless $?.success?
+ abort "Failed to execute: git #{cmd.join(' ')}\n#{out}"
+ end
+ out
+ end
+ end
+end
+
+github = GitHub.new(ENV.fetch('GITHUB_TOKEN'))
+
+repo_path, *rest = ARGV
+rest.each_slice(3).map do |oldrev, newrev, _refname|
+ system('git', 'fetch', 'origin', 'refs/notes/commits:refs/notes/commits', exception: true)
+
+ updated = false
+ Git.rev_list("#{oldrev}..#{newrev}", first_parent: true).each do |sha|
+ github.pulls(owner: 'ruby', repo: 'ruby', commit_sha: sha).each do |pull|
+ number = pull.fetch('number')
+ url = pull.fetch('html_url')
+ next unless url.start_with?('https://github.com/ruby/ruby/pull/')
+
+ # "Merged" notes for "Squash and merge"
+ message = Git.commit_message(sha)
+ notes = Git.notes_message(sha)
+ if !message.include?(url) && !message.match(/[ (]##{number}[) ]/) && !notes.include?(url)
+ system('git', 'notes', 'append', '-m', "Merged: #{url}", sha, exception: true)
+ updated = true
+ end
+
+ # "Merged-By" notes for "Rebase and merge"
+ if Git.committer_name(sha) == 'GitHub' && Git.committer_email(sha) == 'noreply@github.com'
+ username = github.pull_request(owner: 'ruby', repo: 'ruby', number: number).fetch('merged_by').fetch('login')
+ email = github.user(username: username).fetch('email')
+ email ||= SVN_TO_EMAILS[GITHUB_TO_SVN.fetch(username, username)]&.first
+ system('git', 'notes', 'append', '-m', "Merged-By: #{username}#{(" <#{email}>" if email)}", sha, exception: true)
+ updated = true
+ end
+ end
+ end
+
+ if updated
+ system('git', 'push', 'origin', 'refs/notes/commits', exception: true)
+ end
+end
diff --git a/tool/notify-slack-commits.rb b/tool/notify-slack-commits.rb
new file mode 100644
index 0000000000..73e22b9a03
--- /dev/null
+++ b/tool/notify-slack-commits.rb
@@ -0,0 +1,87 @@
+#!/usr/bin/env ruby
+
+require "net/https"
+require "open3"
+require "json"
+require "digest/md5"
+
+SLACK_WEBHOOK_URLS = [
+ ENV.fetch("SLACK_WEBHOOK_URL_ALERTS").chomp, # ruby-lang#alerts
+ ENV.fetch("SLACK_WEBHOOK_URL_COMMITS").chomp, # ruby-lang#commits
+ ENV.fetch("SLACK_WEBHOOK_URL_RUBY_JP").chomp, # ruby-jp#ruby-commits
+]
+GRAVATAR_OVERRIDES = {
+ "nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e" => "https://avatars0.githubusercontent.com/u/21976",
+ "noreply@github.com" => "https://avatars1.githubusercontent.com/u/9919",
+ "nurse@users.noreply.github.com" => "https://avatars1.githubusercontent.com/u/13423",
+ "svn-admin@ruby-lang.org" => "https://avatars1.githubusercontent.com/u/29403229",
+ "svn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e" => "https://avatars1.githubusercontent.com/u/29403229",
+ "usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e" => "https://avatars2.githubusercontent.com/u/17790",
+ "usa@ruby-lang.org" => "https://avatars2.githubusercontent.com/u/17790",
+ "yui-knk@ruby-lang.org" => "https://avatars0.githubusercontent.com/u/5356517",
+ "znz@users.noreply.github.com" => "https://avatars3.githubusercontent.com/u/11857",
+}
+
+def escape(s)
+ s.gsub(/[&<>]/, "&" => "&amp;", "<" => "&lt;", ">" => "&gt;")
+end
+
+ARGV.each_slice(3) do |oldrev, newrev, refname|
+ out, = Open3.capture2("git", "rev-parse", "--symbolic", "--abbrev-ref", refname)
+ branch = out.strip
+
+ out, = Open3.capture2("git", "log", "--pretty=format:%H\n%h\n%cn\n%ce\n%ct\n%B", "--abbrev=10", "-z", "#{oldrev}..#{newrev}")
+
+ attachments = []
+ out.split("\0").reverse_each do |s|
+ sha, sha_abbr, committer, committeremail, committertime, body = s.split("\n", 6)
+ subject, body = body.split("\n", 2)
+
+ # Append notes content to `body` if it's notes
+ if refname.match(%r[\Arefs/notes/\w+\z])
+ # `--diff-filter=AM -M` to exclude rename by git's directory optimization
+ object = IO.popen(["git", "diff", "--diff-filter=AM", "-M", "--name-only", "#{sha}^..#{sha}"], &:read).chomp
+ if md = object.match(/\A(?<prefix>\h{2})\/?(?<rest>\h{38})\z/)
+ body = [body, IO.popen(["git", "notes", "show", md[:prefix] + md[:rest]], &:read)].join
+ end
+ end
+
+ gravatar = GRAVATAR_OVERRIDES.fetch(committeremail) do
+ "https://www.gravatar.com/avatar/#{ Digest::MD5.hexdigest(committeremail.downcase) }"
+ end
+
+ attachments << {
+ title: "#{ sha_abbr } (#{ branch }): #{ escape(subject) }",
+ title_link: "https://github.com/ruby/ruby/commit/#{ sha }",
+ text: escape((body || "").strip),
+ footer: committer,
+ footer_icon: gravatar,
+ ts: committertime.to_i,
+ color: '#24282D',
+ }
+ end
+
+ # 100 attachments cannot be exceeded. 20 is recommended. https://api.slack.com/docs/message-attachments
+ attachments.each_slice(20).each do |attachments_group|
+ payload = { attachments: attachments_group }
+
+ #Net::HTTP.post(
+ # URI.parse(SLACK_WEBHOOK_URL),
+ # JSON.generate(payload),
+ # "Content-Type" => "application/json"
+ #)
+ responses = SLACK_WEBHOOK_URLS.map do |url|
+ uri = URI.parse(url)
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+ http.start do
+ req = Net::HTTP::Post.new(uri.path)
+ req.set_form_data(payload: payload.to_json)
+ http.request(req)
+ end
+ end
+
+ results = responses.map { |resp| "#{resp.code} (#{resp.body})" }.join(', ')
+ puts "#{results} -- #{payload.to_json}"
+ end
+end
diff --git a/tool/outdate-bundled-gems.rb b/tool/outdate-bundled-gems.rb
index c82d31d743..b272c448c6 100755
--- a/tool/outdate-bundled-gems.rb
+++ b/tool/outdate-bundled-gems.rb
@@ -60,6 +60,7 @@ class Removal
def initialize(base = nil)
@base = (File.join(base, "/") if base)
@remove = {}
+ @defaults = nil
end
def prefixed(name)
@@ -92,10 +93,22 @@ class Removal
@remove[slash(stripped(name))] = :rm_rf
end
- def glob(pattern, *rest)
- Dir.glob(prefixed(pattern), *rest) {|n|
- yield stripped(n)
- }
+ def glob(pattern, *rest, &block)
+ Dir.glob(pattern, *rest, base: @base, &block)
+ end
+
+ def default_gem?(spec)
+ (@defaults ||= {}).fetch(spec) do
+ File.open(prefixed(spec)) do |f|
+ if /^# default: (\S+) (\d+\.\d+)/ =~ f.gets("")
+ File.mtime(prefixed($1)) <= Time.at(Rational($2))
+ else
+ false
+ end
+ rescue
+ false
+ end
+ end
end
def sorted
@@ -115,7 +128,7 @@ srcdir = Removal.new(ARGV.shift)
curdir = !srcdir.base || File.identical?(srcdir.base, ".") ? srcdir : Removal.new
bundled = File.readlines("#{srcdir.base}gems/bundled_gems").
- grep(/^(\w\S+)\s+\S+(?:\s+\S+\s+(\S+))?/) {$~.captures}.to_h rescue nil
+ grep(/^(\w[^\#\s]+)\s+[^\#\s]+(?:\s+[^\#\s]+\s+([^\#\s]+))?/) {$~.captures}.to_h rescue nil
srcdir.glob(".bundle/gems/*/") do |dir|
base = File.basename(dir)
@@ -133,12 +146,14 @@ end
srcdir.glob(".bundle/specifications/*.gemspec") do |spec|
unless srcdir.directory?(".bundle/gems/#{File.basename(spec, '.gemspec')}/")
+ next if srcdir.default_gem?(spec)
srcdir.unlink(spec)
end
end
curdir.glob(".bundle/specifications/*.gemspec") do |spec|
unless srcdir.directory?(".bundle/gems/#{File.basename(spec, '.gemspec')}")
+ next if curdir.default_gem?(spec)
curdir.unlink(spec)
end
end
diff --git a/tool/prereq.status b/tool/prereq.status
index 6de00c8a92..44c0718a2d 100644
--- a/tool/prereq.status
+++ b/tool/prereq.status
@@ -9,6 +9,7 @@ s,@CC@,false,g
s,@CFLAGS@,,g
s,@CHDIR@,cd,g
s,@CONFIGURE@,configure,g
+s,@COUTFLAG@,-o ,g
s,@CP@,cp,g
s,@CPPFLAGS@,,g
s,@CXXFLAGS@,,g
@@ -24,6 +25,7 @@ s,@LIBRUBY_A@,libruby.a,g
s,@MINIRUBY@,$(BASERUBY),g
s,@MKDIR_P@,mkdir -p,g
s,@OBJEXT@,o,g
+s,@OUTFLAG@,-o ,g
s,@PATH_SEPARATOR@,:,g
s,@PWD@,.,g
s,@RM@,rm -f,g
@@ -32,6 +34,9 @@ s,@RMDIR@,rmdir,g
s,@RMDIRS@,$(RMDIR) -p,g
s,@RUBY@,$(BASERUBY),g
s,@RUNRUBY@,$(MINIRUBY),g
+s,@X_BUILD_EXEEXT@,,g
+s,@X_DUMP_AST@,build-tool/dump_ast$(BUILD_EXEEXT),g
+s,@X_DUMP_AST_TARGET@,$(DUMP_AST),g
s,@arch@,noarch,g
s,@bindir@,,g
s,@configure_args@,,g
@@ -40,5 +45,9 @@ s,@rubyarchdir@,,g
s,@rubylibprefix@,,g
s,@srcdir@,.,g
+# for comipling dump_ast on build-os
+/^CC *=/d
+
s/@[A-Za-z][A-Za-z0-9_]*@//g
-s/{\$([A-Za-z]*)}//g
+s/{\$([^(){}]*)}//g
+s/^!/#!/
diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb
index d00d3ff69c..047fd0a571 100755
--- a/tool/rbinstall.rb
+++ b/tool/rbinstall.rb
@@ -527,6 +527,8 @@ module RbInstall
const_set(:FileUtils, fu::NoWrite)
fu
end
+ # RubyGems 3.0.0 or later supports `dir_mode`, but it uses
+ # `File` method to apply it, not `FileUtils`.
dir_mode = options.delete(:dir_mode) if options
end
yield
@@ -659,6 +661,17 @@ module RbInstall
"#{srcdir}/lib"
end
end
+
+ class UnpackedGem < self
+ def collect
+ base = @srcdir or return []
+ Dir.glob("**/*", File::FNM_DOTMATCH, base: base).select do |n|
+ next if n == "."
+ next if File.fnmatch?("*.gemspec", n, File::FNM_DOTMATCH|File::FNM_PATHNAME)
+ !File.directory?(File.join(base, n))
+ end
+ end
+ end
end
end
@@ -696,6 +709,77 @@ module RbInstall
end
class UnpackedInstaller < Gem::Installer
+ # This method is mostly copied from old version of Gem::Installer#install
+ def install_with_default_gem
+ verify_gem_home
+
+ # The name and require_paths must be verified first, since it could contain
+ # ruby code that would be eval'ed in #ensure_loadable_spec
+ verify_spec
+
+ ensure_loadable_spec
+
+ if options[:install_as_default]
+ Gem.ensure_default_gem_subdirectories gem_home
+ else
+ Gem.ensure_gem_subdirectories gem_home
+ end
+
+ return true if @force
+
+ ensure_dependencies_met unless @ignore_dependencies
+
+ run_pre_install_hooks
+
+ # Set loaded_from to ensure extension_dir is correct
+ if @options[:install_as_default]
+ spec.loaded_from = default_spec_file
+ else
+ spec.loaded_from = spec_file
+ end
+
+ # Completely remove any previous gem files
+ FileUtils.rm_rf gem_dir
+ FileUtils.rm_rf spec.extension_dir
+
+ dir_mode = options[:dir_mode]
+ FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755
+
+ if @options[:install_as_default]
+ extract_bin
+ write_default_spec
+ else
+ extract_files
+
+ build_extensions
+ write_build_info_file
+ run_post_build_hooks
+ end
+
+ generate_bin
+ generate_plugins
+
+ unless @options[:install_as_default]
+ write_spec
+ write_cache_file
+ end
+
+ File.chmod(dir_mode, gem_dir) if dir_mode
+
+ 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
+
+ run_post_install_hooks
+
+ spec
+ rescue Errno::EACCES => e
+ # Permission denied - /path/to/foo
+ raise Gem::FilePermissionError, e.message.split(" - ").last
+ end
+
def write_cache_file
end
@@ -741,7 +825,7 @@ module RbInstall
def install
spec.post_install_message = nil
dir_creating(without_destdir(gem_dir))
- RbInstall.no_write(options) {super}
+ RbInstall.no_write(options) { install_with_default_gem }
end
# Now build-ext builds all extensions including bundled gems.
@@ -770,32 +854,57 @@ module RbInstall
$installed_list.puts(d+"/") if $installed_list
end
end
+
+ def load_plugin
+ # Suppress warnings for constant re-assignment
+ verbose, $VERBOSE = $VERBOSE, nil
+ super
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def regenerate_plugins_for(spec, plugins_dir)
+ plugins = spec.plugins
+ return if plugins.empty?
+ dir = without_destdir(plugins_dir)
+ plugins.each do |plugin|
+ $installed_list.puts(File.join(dir, "#{spec.name}_plugin#{File.extname(plugin)}"))
+ end
+ unless $dryrun
+ super
+ end
+ end
end
end
-def load_gemspec(file, base = nil)
+def load_gemspec(file, base = nil, files: nil)
file = File.realpath(file)
code = File.read(file, encoding: "utf-8:-")
- files = []
- Dir.glob("**/*", File::FNM_DOTMATCH, base: base) do |n|
- case File.basename(n); when ".", ".."; next; end
- next if File.directory?(File.join(base, n))
- files << n.dump
- end if base
+ code.gsub!(/^ *#.*/, "")
+ spec_files = files ? files.map(&:dump).join(", ") : ""
code.gsub!(/(?:`git[^\`]*`|%x\[git[^\]]*\])\.split(\([^\)]*\))?/m) do
- "[" + files.join(", ") + "]"
- end
+ "[" + spec_files + "]"
+ end \
+ or
code.gsub!(/IO\.popen\(.*git.*?\)/) do
- "[" + files.join(", ") + "] || itself"
+ "[" + spec_files + "] || itself"
end
spec = eval(code, binding, file)
+ # for out-of-place build
+ collected_files = files ? spec.files.concat(files).uniq : spec.files
+ spec.files = collected_files.map do |f|
+ if !File.exist?(File.join(base || ".", f)) && f.end_with?(".rb")
+ "lib/#{f}"
+ else
+ f
+ end
+ end
unless Gem::Specification === spec
raise TypeError, "[#{file}] isn't a Gem::Specification (#{spec.class} instead)."
end
spec.loaded_from = base ? File.join(base, File.basename(file)) : file
- spec.files.reject! {|n| n.end_with?(".gemspec") or n.start_with?(".git")}
spec.date = RUBY_RELEASE_DATE
spec
@@ -806,6 +915,7 @@ def install_default_gem(dir, srcdir, bindir)
install_dir = with_destdir(gem_dir)
prepare "default gems from #{dir}", gem_dir
RbInstall.no_write do
+ # Record making directories
makedirs(Gem.ensure_default_gem_subdirectories(install_dir, $dir_mode).map {|d| File.join(gem_dir, d)})
end
@@ -824,14 +934,11 @@ def install_default_gem(dir, srcdir, bindir)
base = "#{srcdir}/#{dir}"
gems = Dir.glob("**/*.gemspec", base: base).map {|src|
- spec = load_gemspec("#{base}/#{src}")
- file_collector = RbInstall::Specs::FileCollector.for(srcdir, dir, src)
- files = file_collector.collect
+ files = RbInstall::Specs::FileCollector.for(srcdir, dir, src).collect
if files.empty?
next
end
- spec.files = files
- spec
+ load_gemspec("#{base}/#{src}", files: files)
}
gems.compact.sort_by(&:name).each do |gemspec|
old_gemspecs = Dir[File.join(with_destdir(default_spec_dir), "#{gemspec.name}-*.gemspec")]
@@ -1006,7 +1113,6 @@ install?(:local, :comm, :man) do
prepare "manpages", mandir, ([] | mdocs.collect {|mdoc| mdoc[/\d+$/]}).sort.collect {|sec| "man#{sec}"}
mantype, suffix, compress = Compressors.for($mantype)
- mandir = File.join(mandir, "man")
has_goruby = File.exist?(goruby_install_name+exeext)
require File.join(srcdir, "tool/mdoc2man.rb") if /\Adoc\b/ !~ mantype
mdocs.each do |mdoc|
@@ -1016,8 +1122,8 @@ install?(:local, :comm, :man) do
next unless has_goruby
end
- destdir = mandir + (section = mdoc[/\d+$/])
- destname = ruby_install_name.sub(/ruby/, base.chomp(".#{section}"))
+ destdir = File.join(mandir, "man" + (section = mdoc[/\d+$/]))
+ destname = $script_installer.transform(base.chomp(".#{section}"))
destfile = File.join(destdir, "#{destname}.#{section}")
if /\Adoc\b/ =~ mantype or !mdoc_file?(mdoc)
@@ -1103,6 +1209,7 @@ install?(:ext, :comm, :gem, :'bundled-gems') do
install_dir = with_destdir(gem_dir)
prepare "bundled gems", gem_dir
RbInstall.no_write do
+ # Record making directories
makedirs(Gem.ensure_gem_subdirectories(install_dir, $dir_mode).map {|d| File.join(gem_dir, d)})
end
@@ -1131,6 +1238,7 @@ install?(:ext, :comm, :gem, :'bundled-gems') do
# the newly installed ruby.
ENV.delete('RUBYOPT')
+ collector = RbInstall::Specs::FileCollector::UnpackedGem
File.foreach("#{srcdir}/gems/bundled_gems") do |name|
next if /^\s*(?:#|$)/ =~ name
next unless /^(\S+)\s+(\S+).*/ =~ name
@@ -1149,7 +1257,11 @@ install?(:ext, :comm, :gem, :'bundled-gems') do
skipped[gem_name] = "gemspec not found"
next
end
- spec = load_gemspec(path, "#{srcdir}/.bundle/gems/#{gem_name}")
+ base = "#{srcdir}/.bundle/gems/#{gem_name}"
+ files = collector.new(path, base, nil).collect
+ files.delete("#{gem}.gemspec")
+ files.delete("#{gem_name}.gemspec")
+ spec = load_gemspec(path, base, files: files)
unless spec.platform == Gem::Platform::RUBY
skipped[gem_name] = "not ruby platform (#{spec.platform})"
next
@@ -1164,6 +1276,7 @@ install?(:ext, :comm, :gem, :'bundled-gems') do
next
end
spec.extension_dir = "#{extensions_dir}/#{spec.full_name}"
+
package = RbInstall::DirPackage.new spec
ins = RbInstall::UnpackedInstaller.new(package, options)
puts "#{INDENT}#{spec.name} #{spec.version}"
@@ -1183,7 +1296,8 @@ install?(:ext, :comm, :gem, :'bundled-gems') do
skipped.default = "not found in bundled_gems"
puts "skipped bundled gems:"
gems.each do |gem|
- printf " %-32s%s\n", File.basename(gem), skipped[gem]
+ gem = File.basename(gem)
+ printf " %-31s %s\n", gem, skipped[gem.chomp(".gem")]
end
end
end
diff --git a/tool/rbs_skip_tests b/tool/rbs_skip_tests
index ce3293a997..39ac16cb8f 100644
--- a/tool/rbs_skip_tests
+++ b/tool/rbs_skip_tests
@@ -37,6 +37,9 @@ TestInstanceNetHTTPResponse depending on external resources
test_TOPDIR(RbConfigSingletonTest) `TOPDIR` is `nil` during CI while RBS type is declared as `String`
+# Failing because ObjectSpace.count_nodes has been removed
+test_count_nodes(ObjectSpaceTest)
+
## Unknown failures
# NoMethodError: undefined method 'inspect' for an instance of RBS::UnitTest::Convertibles::ToInt
@@ -44,31 +47,6 @@ test_compile(RegexpSingletonTest)
test_linear_time?(RegexpSingletonTest)
test_new(RegexpSingletonTest)
-## Failed tests caused by unreleased version of Ruby
-
-# https://github.com/ruby/openssl/pull/774
-test_params(OpenSSLDHTest)
-
-# RBS isn't compatible with RDoc 6.13
-RDocPluginParserTest
-
-# https://github.com/ruby/json/pull/773
-test_load(JSONInstanceTest)
-test_load(JSONSingletonTest)
-
-# https://github.com/ruby/json/pull/775
-test_fast_unparse(JSONInstanceTest)
-test_pretty_unparse(JSONInstanceTest)
-test_restore(JSONInstanceTest)
-test_unparse(JSONInstanceTest)
-test_fast_unparse(JSONSingletonTest)
-test_pretty_unparse(JSONSingletonTest)
-test_restore(JSONSingletonTest)
-test_unparse(JSONSingletonTest)
-
-# https://github.com/ruby/json/pull/779
-test_iconv(JSONSingletonTest)
-
-# https://github.com/ruby/json/pull/774
-test_recurse_proc(JSONInstanceTest)
-test_recurse_proc(JSONSingletonTest)
+# Errno::ENOENT: No such file or directory - bundle
+test_collection_install__pathname_set(RBS::CliTest)
+test_collection_install__set_pathname__manifest(RBS::CliTest)
diff --git a/tool/rbs_skip_tests_windows b/tool/rbs_skip_tests_windows
new file mode 100644
index 0000000000..db12c69419
--- /dev/null
+++ b/tool/rbs_skip_tests_windows
@@ -0,0 +1,111 @@
+ARGFTest Failing on Windows
+
+RactorSingletonTest Hangs up on Windows
+RactorInstanceTest Hangs up on Windows
+
+# NotImplementedError: fileno() function is unimplemented on this machine
+test_fileno(DirInstanceTest)
+test_fchdir(DirSingletonTest)
+test_for_fd(DirSingletonTest)
+
+# ArgumentError: user root doesn't exist
+test_home(DirSingletonTest)
+
+# NameError: uninitialized constant Etc::CS_PATH
+test_confstr(EtcSingletonTest)
+
+# NameError: uninitialized constant Etc::SC_ARG_MAX
+test_sysconf(EtcSingletonTest)
+
+# Errno::EACCES: Permission denied @ apply2files - C:/a/_temp/d20250813-10156-udw6rx/chmod
+test_chmod(FileInstanceTest)
+test_chmod(FileInstanceTest)
+test_truncate(FileInstanceTest)
+
+# Errno::EISDIR: Is a directory @ rb_sysopen - C:/a/ruby/ruby/src/gems/src/rbs/test/stdlib
+test_directory?(FileSingletonTest)
+
+# NotImplementedError: lutime() function is unimplemented on this machine
+test_lutime(FileSingletonTest)
+
+# NotImplementedError: mkfifo() function is unimplemented on this machine
+test_mkfifo(FileSingletonTest)
+
+# Returns `nil` on Windows
+test_getgrgid(EtcSingletonTest)
+test_getgrnam(EtcSingletonTest)
+test_getpwnam(EtcSingletonTest)
+test_getpwuid(EtcSingletonTest)
+
+# Returns `false`
+test_setgid?(FileSingletonTest)
+test_setuid?(FileSingletonTest)
+test_sticky?(FileSingletonTest)
+
+test_world_readable?(FileSingletonTest) # Returns `420`
+test_world_readable?(FileStatInstanceTest) # Returns `420`
+test_world_writable?(FileSingletonTest) # Returns `nil`
+test_dev_major(FileStatInstanceTest) # Returns `nil`
+test_dev_minor(FileStatInstanceTest) # Returns `nil`
+test_rdev_major(FileStatInstanceTest) # Returns `nil`
+test_rdev_minor(FileStatInstanceTest) # Returns `nil`
+
+# ArgumentError: wrong number of arguments (given -403772944, expected 0+)
+test_curry(MethodInstanceTest)
+
+# ArgumentError: no output encoding given
+test_tolocale(KconvSingletonTest)
+
+# Errno::EINVAL: Invalid argument - :
+test_system(KernelInstanceTest)
+
+# OpenSSL::ConfigError: BIO_new_file: no such file
+test_load(OpenSSLConfigSingletonTest)
+
+# Errno::ENOENT: No such file or directory @ rb_sysopen -
+test_parse(OpenSSLConfigSingletonTest)
+test_parse_config(OpenSSLConfigSingletonTest)
+
+# OpenSSL::ConfigError: BIO_new_file: no such file
+test_each(OpenSSLConfigTest)
+test_lookup_and_set(OpenSSLConfigTest)
+test_sections(OpenSSLConfigTest)
+
+# OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 peeraddr=185.199.108.153:443 state=error: certificate verify failed (unable to get local issuer certificate)
+test_URI_open(OpenURISingletonTest)
+
+# ArgumentError: both textmode and binmode specified
+test_binwrite(PathnameInstanceTest)
+
+# Errno::EACCES: Permission denied @ apply2files - C:/a/_temp/rbs-pathname-delete-test20250813-10156-mb3e9i
+test_delete(PathnameInstanceTest)
+# Errno::EACCES: Permission denied @ apply2files - C:/a/_temp/rbs-pathname-binwrite-test20250813-10156-sh8145
+test_open(PathnameInstanceTest)
+# Errno::EACCES: Permission denied @ rb_file_s_truncate - C:/a/_temp/rbs-pathname-truncate-test20250813-10156-dqqiw3
+test_truncate(PathnameInstanceTest)
+# Errno::EACCES: Permission denied @ rb_file_s_truncate - C:/a/_temp/rbs-pathname-truncate-test20250813-10156-dqqiw3
+test_unlink(PathnameInstanceTest)
+
+# Errno::ENOENT: No such file or directory @ rb_sysopen - /etc/resolv.conf
+test_parse_resolv_conf(ResolvDNSConfigSingletonTest)
+# Resolv::ResolvError: no name for 127.0.0.1
+test_getname(ResolvInstanceTest)
+# Resolv::ResolvError: no name for 127.0.0.1
+test_getname(ResolvSingletonTest)
+
+# ArgumentError: unsupported signal 'SIGUSR2'
+test_trap(SignalSingletonTest)
+
+# Errno::ENOENT: No such file or directory @ rb_sysopen - /tmp/README.md20250813-10156-mgr4tx
+test_create(TempfileSingletonTest)
+
+# Errno::ENOENT: No such file or directory @ rb_sysopen - /tmp/README.md20250813-10156-hp9nzu
+test_initialize(TempfileSingletonTest)
+test_new(TempfileSingletonTest)
+
+# Errno::EACCES: Permission denied @ apply2files - C:/a/_temp/d20250813-10156-f8z9pn/test.gz
+test_open(ZlibGzipReaderSingletonTest)
+
+# Errno::EACCES: Permission denied @ rb_file_s_rename
+# D:/a/ruby/ruby/src/lib/rubygems/util/atomic_file_writer.rb:42:in 'File.rename'
+test_write_binary(GemSingletonTest)
diff --git a/tool/rdoc-srcdir b/tool/rdoc-srcdir
index f830fdc302..417a057d7f 100755
--- a/tool/rdoc-srcdir
+++ b/tool/rdoc-srcdir
@@ -1,7 +1,6 @@
#!ruby -W0
-rdoc_path = Dir.glob("#{File.dirname(__dir__)}/.bundle/gems/rdoc-*").first
-$LOAD_PATH.unshift("#{rdoc_path}/lib")
+require 'rubygems'
require 'rdoc/rdoc'
# Make only the output directory relative to the invoked directory.
@@ -17,7 +16,7 @@ options.title = options.title.sub(/Ruby \K.*version/) {
.sort # "MAJOR" < "MINOR", fortunately
.to_h.values.join(".")
}
-options.parse ARGV
+options.parse ARGV + ["#{invoked}/rbconfig.rb"]
options.singleton_class.define_method(:finish) do
super()
diff --git a/tool/redmine-backporter.rb b/tool/redmine-backporter.rb
index 7f08eb8d1a..95a9688cb2 100755
--- a/tool/redmine-backporter.rb
+++ b/tool/redmine-backporter.rb
@@ -190,7 +190,7 @@ def backport_command_string
next false if c.match(/\A\d{1,6}\z/) # skip SVN revision
# check if the Git revision is included in master
- has_commit(c, "master")
+ has_commit(c, "origin/master")
end.sort_by do |changeset|
Integer(IO.popen(%W[git show -s --format=%ct #{changeset}], &:read))
end
diff --git a/tool/releng/gen-mail.rb b/tool/releng/gen-mail.rb
index 6dc0e4cec1..17fa499d69 100755
--- a/tool/releng/gen-mail.rb
+++ b/tool/releng/gen-mail.rb
@@ -10,7 +10,7 @@ end
# Confirm current directory is www.ruby-lang.org's working directory
def confirm_w_r_l_o_wd
File.foreach('.git/config') do |line|
- return true if line.include?('git@github.com:ruby/www.ruby-lang.org.git')
+ return true if line.include?('ruby/www.ruby-lang.org.git')
end
abort "Run this script in www.ruby-lang.org's working directory"
end
diff --git a/tool/releng/update-www-meta.rb b/tool/releng/update-www-meta.rb
index 8a5651dcd0..0dd5b25631 100755
--- a/tool/releng/update-www-meta.rb
+++ b/tool/releng/update-www-meta.rb
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby
require "open-uri"
require "yaml"
+require_relative "../ruby-version"
class Tarball
attr_reader :version, :size, :sha1, :sha256, :sha512
@@ -41,22 +42,7 @@ eom
unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version
raise "unexpected version string '#{version}'"
end
- x = $1.to_i
- y = $2.to_i
- z = $3.to_i
- # previous tag for git diff --shortstat
- # It's only for x.y.0 release
- if z != 0
- prev_tag = nil
- elsif y != 0
- prev_tag = "v#{x}_#{y-1}_0"
- prev_ver = "#{x}.#{y-1}.0"
- elsif x == 3 && y == 0 && z == 0
- prev_tag = "v2_7_0"
- prev_ver = "2.7.0"
- else
- raise "unexpected version for prev_ver '#{version}'"
- end
+ teeny = Integer($3)
uri = "https://cache.ruby-lang.org/pub/tmp/ruby-info-#{version}-draft.yml"
info = YAML.load(URI(uri).read)
@@ -74,9 +60,10 @@ eom
tarballs << tarball
end
- if prev_tag
+ if teeny == 0
# show diff shortstat
- tag = "v#{version.gsub(/[.\-]/, '_')}"
+ tag = RubyVersion.tag(version)
+ prev_tag = RubyVersion.tag(RubyVersion.previous(version))
rubydir = File.expand_path(File.join(__FILE__, '../../../'))
puts %`git -C #{rubydir} diff --shortstat #{prev_tag}..#{tag}`
stat = `git -C #{rubydir} diff --shortstat #{prev_tag}..#{tag}`
@@ -155,7 +142,7 @@ eom
date = Time.now.utc # use utc to use previous day in midnight
entry = <<eom
- version: #{ver}
- tag: v#{ver.tr('-.', '_')}
+ tag: #{RubyVersion.tag(ver)}
date: #{date.strftime("%Y-%m-%d")}
post: /en/news/#{date.strftime("%Y/%m/%d")}/ruby-#{ver.tr('.', '-')}-released/
stats:
diff --git a/tool/ruby-version.rb b/tool/ruby-version.rb
new file mode 100755
index 0000000000..3bbec576e1
--- /dev/null
+++ b/tool/ruby-version.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+
+module RubyVersion
+ def self.tag(version)
+ major_version = Integer(version.split('.', 2)[0])
+ if major_version >= 4
+ "v#{version}"
+ else
+ "v#{version.tr('.-', '_')}"
+ end
+ end
+
+ # Return the previous version to be used for release diff links.
+ # For a ".0" version, it returns the previous ".0" version.
+ # For a non-".0" version, it returns the previous teeny version.
+ def self.previous(version)
+ unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version
+ raise "unexpected version string '#{version}'"
+ end
+ major = Integer($1)
+ minor = Integer($2)
+ teeny = Integer($3)
+
+ if teeny != 0
+ "#{major}.#{minor}.#{teeny-1}"
+ elsif minor != 0 # && teeny == 0
+ "#{major}.#{minor-1}.#{teeny}"
+ else # minor == 0 && teeny == 0
+ case major
+ when 3
+ "2.7.0"
+ when 4
+ "3.4.0"
+ else
+ raise "it doesn't know what is the previous version of '#{version}'"
+ end
+ end
+ end
+end
+
+if __FILE__ == $0
+ case ARGV[0]
+ when "tag"
+ print RubyVersion.tag(ARGV[1])
+ when "previous"
+ print RubyVersion.previous(ARGV[1])
+ when "previous-tag"
+ print RubyVersion.tag(RubyVersion.previous(ARGV[1]))
+ else
+ "#{$0}: unexpected command #{ARGV[0].inspect}"
+ end
+end
diff --git a/tool/ruby_vm/models/bare_instruction.rb b/tool/ruby_vm/models/bare_instruction.rb
new file mode 100644
index 0000000000..f87dd74179
--- /dev/null
+++ b/tool/ruby_vm/models/bare_instruction.rb
@@ -0,0 +1,236 @@
+# -*- Ruby -*-
+# -*- frozen_string_literal: true; -*-
+# -*- warn_indent: true; -*-
+#
+# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
+#
+# 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.
+
+require_relative '../loaders/insns_def'
+require_relative 'c_expr'
+require_relative 'typemap'
+require_relative 'attribute'
+
+class RubyVM::BareInstruction
+ attr_reader :template, :name, :operands, :pops, :rets, :decls, :expr
+
+ def initialize opts = {}
+ @template = opts[:template]
+ @name = opts[:name]
+ @loc = opts[:location]
+ @sig = opts[:signature]
+ @expr = RubyVM::CExpr.new opts[:expr]
+ @operands = typesplit @sig[:ope]
+ @pops = typesplit @sig[:pop].reject {|i| i == '...' }
+ @rets = typesplit @sig[:ret].reject {|i| i == '...' }
+ @attrs = opts[:attributes].map {|i|
+ RubyVM::Attribute.new i.merge(:insn => self)
+ }.each_with_object({}) {|a, h|
+ h[a.key] = a
+ }
+ @attrs_orig = @attrs.dup
+ check_attribute_consistency
+ predefine_attributes
+ end
+
+ def pretty_name
+ n = @sig[:name]
+ o = @sig[:ope].map{|i| i[/\S+$/] }.join ', '
+ p = @sig[:pop].map{|i| i[/\S+$/] }.join ', '
+ r = @sig[:ret].map{|i| i[/\S+$/] }.join ', '
+ return sprintf "%s(%s)(%s)(%s)", n, o, p, r
+ end
+
+ def bin
+ return "BIN(#{name})"
+ end
+
+ def call_attribute name
+ return sprintf 'attr_%s_%s(%s)', name, @name, \
+ @operands.map {|i| i[:name] }.compact.join(', ')
+ end
+
+ def has_attribute? k
+ @attrs_orig.has_key? k
+ end
+
+ def attributes
+ return @attrs \
+ . sort_by {|k, _| k } \
+ . map {|_, v| v }
+ end
+
+ def width
+ return 1 + operands.size
+ end
+
+ def declarations
+ return @variables \
+ . values \
+ . group_by {|h| h[:type] } \
+ . sort_by {|t, v| t } \
+ . map {|t, v| [t, v.map {|i| i[:name] }.sort ] } \
+ . map {|t, v|
+ sprintf("MAYBE_UNUSED(%s) %s", t, v.join(', '))
+ }
+ end
+
+ def preamble
+ # preamble makes sense for operand unifications
+ return []
+ end
+
+ def sc?
+ # sc stands for stack caching.
+ return false
+ end
+
+ def cast_to_VALUE var, expr = var[:name]
+ RubyVM::Typemap.typecast_to_VALUE var[:type], expr
+ end
+
+ def cast_from_VALUE var, expr = var[:name]
+ RubyVM::Typemap.typecast_from_VALUE var[:type], expr
+ end
+
+ def operands_info
+ operands.map {|o|
+ c, _ = RubyVM::Typemap.fetch o[:type]
+ next c
+ }.join
+ end
+
+ def handles_sp?
+ /\b(false|0)\b/ !~ @attrs.fetch('handles_sp').expr.expr
+ end
+
+ def handle_canary stmt
+ # Stack canary is basically a good thing that we want to add, however:
+ #
+ # - When the instruction returns variadic number of return values,
+ # it is not easy to tell where is the stack top. We can't but
+ # skip it.
+ #
+ # - When the instruction body is empty (like putobject), we can
+ # say for 100% sure that canary is a waste of time.
+ #
+ # So we skip canary for those cases.
+ return '' if @sig[:ret].any? {|i| i == '...' }
+ return '' if @expr.blank?
+ return " #{stmt};\n"
+ end
+
+ def inspect
+ sprintf "#<%s %s@%s:%d>", self.class.name, @name, @loc[0], @loc[1]
+ end
+
+ def has_ope? var
+ return @operands.any? {|i| i[:name] == var[:name] }
+ end
+
+ def has_pop? var
+ return @pops.any? {|i| i[:name] == var[:name] }
+ end
+
+ def use_call_data?
+ @use_call_data ||=
+ @variables.find { |_, var_info| var_info[:type] == 'CALL_DATA' }
+ end
+
+ def zjit_profile?
+ @attrs.fetch('zjit_profile').expr.expr != 'false;'
+ end
+
+ private
+
+ def check_attribute_consistency
+ if has_attribute?('sp_inc') \
+ && use_call_data? \
+ && !has_attribute?('comptime_sp_inc')
+ # As the call cache caches information that can only be obtained at
+ # runtime, we do not need it when compiling from AST to bytecode. This
+ # attribute defines an expression that computes the stack pointer
+ # increase based on just the call info to avoid reserving space for the
+ # call cache at compile time. In the expression, all call data operands
+ # are mapped to their call info counterpart. Additionally, all mentions
+ # of `cd` in the operand name are replaced with `ci`.
+ raise "Please define attribute `comptime_sp_inc` for `#{@name}`"
+ end
+ end
+
+ def generate_attribute t, k, v
+ @attrs[k] ||= RubyVM::Attribute.new \
+ insn: self, \
+ name: k, \
+ type: t, \
+ location: [], \
+ expr: v.to_s + ';'
+ return @attrs[k] ||= attr
+ end
+
+ def predefine_attributes
+ # Beware: order matters here because some attribute depends another.
+ generate_attribute 'const char*', 'name', "insn_name(#{bin})"
+ generate_attribute 'enum ruby_vminsn_type', 'bin', bin
+ generate_attribute 'rb_num_t', 'open', operands.size
+ generate_attribute 'rb_num_t', 'popn', pops.size
+ generate_attribute 'rb_num_t', 'retn', rets.size
+ generate_attribute 'rb_num_t', 'width', width
+ generate_attribute 'rb_snum_t', 'sp_inc', rets.size - pops.size
+ generate_attribute 'bool', 'handles_sp', default_definition_of_handles_sp
+ generate_attribute 'bool', 'leaf', default_definition_of_leaf
+ generate_attribute 'bool', 'zjit_profile', false
+ end
+
+ def default_definition_of_handles_sp
+ # Insn with ISEQ should yield it; can handle sp.
+ return operands.any? {|o| o[:type] == 'ISEQ' }
+ end
+
+ def default_definition_of_leaf
+ # Insn that handles SP can never be a leaf.
+ if not has_attribute? 'handles_sp' then
+ return ! default_definition_of_handles_sp
+ elsif handles_sp? then
+ return "! #{call_attribute 'handles_sp'}"
+ else
+ return true
+ end
+ end
+
+ def typesplit a
+ @variables ||= {}
+ a.map do |decl|
+ md = %r'
+ (?<comment> /[*] [^*]* [*]+ (?: [^*/] [^*]* [*]+ )* / ){0}
+ (?<ws> \g<comment> | \s ){0}
+ (?<ident> [_a-zA-Z] [0-9_a-zA-Z]* ){0}
+ (?<type> (?: \g<ident> \g<ws>+ )* \g<ident> ){0}
+ (?<var> \g<ident> ){0}
+ \G \g<ws>* \g<type> \g<ws>+ \g<var>
+ 'x.match(decl)
+ @variables[md['var']] ||= {
+ decl: decl,
+ type: md['type'],
+ name: md['var'],
+ }
+ end
+ end
+
+ @instances = RubyVM::InsnsDef.map {|h|
+ new h.merge(:template => h)
+ }
+
+ def self.find(name)
+ @instances.find do |insn|
+ insn.name == name
+ end or raise IndexError, "instruction not found: #{name}"
+ end
+
+ def self.all
+ @instances
+ end
+end
diff --git a/tool/ruby_vm/models/bare_instructions.rb b/tool/ruby_vm/models/bare_instructions.rb
deleted file mode 100644
index f813760cb6..0000000000
--- a/tool/ruby_vm/models/bare_instructions.rb
+++ /dev/null
@@ -1,239 +0,0 @@
-# -*- Ruby -*-
-# -*- frozen_string_literal: true; -*-
-# -*- warn_indent: true; -*-
-#
-# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
-#
-# 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.
-
-require_relative '../loaders/insns_def'
-require_relative 'c_expr'
-require_relative 'typemap'
-require_relative 'attribute'
-
-class RubyVM::BareInstructions
- attr_reader :template, :name, :operands, :pops, :rets, :decls, :expr
-
- def initialize opts = {}
- @template = opts[:template]
- @name = opts[:name]
- @loc = opts[:location]
- @sig = opts[:signature]
- @expr = RubyVM::CExpr.new opts[:expr]
- @operands = typesplit @sig[:ope]
- @pops = typesplit @sig[:pop].reject {|i| i == '...' }
- @rets = typesplit @sig[:ret].reject {|i| i == '...' }
- @attrs = opts[:attributes].map {|i|
- RubyVM::Attribute.new i.merge(:insn => self)
- }.each_with_object({}) {|a, h|
- h[a.key] = a
- }
- @attrs_orig = @attrs.dup
- check_attribute_consistency
- predefine_attributes
- end
-
- def pretty_name
- n = @sig[:name]
- o = @sig[:ope].map{|i| i[/\S+$/] }.join ', '
- p = @sig[:pop].map{|i| i[/\S+$/] }.join ', '
- r = @sig[:ret].map{|i| i[/\S+$/] }.join ', '
- return sprintf "%s(%s)(%s)(%s)", n, o, p, r
- end
-
- def bin
- return "BIN(#{name})"
- end
-
- def call_attribute name
- return sprintf 'attr_%s_%s(%s)', name, @name, \
- @operands.map {|i| i[:name] }.compact.join(', ')
- end
-
- def has_attribute? k
- @attrs_orig.has_key? k
- end
-
- def attributes
- return @attrs \
- . sort_by {|k, _| k } \
- . map {|_, v| v }
- end
-
- def width
- return 1 + operands.size
- end
-
- def declarations
- return @variables \
- . values \
- . group_by {|h| h[:type] } \
- . sort_by {|t, v| t } \
- . map {|t, v| [t, v.map {|i| i[:name] }.sort ] } \
- . map {|t, v|
- sprintf("MAYBE_UNUSED(%s) %s", t, v.join(', '))
- }
- end
-
- def preamble
- # preamble makes sense for operand unifications
- return []
- end
-
- def sc?
- # sc stands for stack caching.
- return false
- end
-
- def cast_to_VALUE var, expr = var[:name]
- RubyVM::Typemap.typecast_to_VALUE var[:type], expr
- end
-
- def cast_from_VALUE var, expr = var[:name]
- RubyVM::Typemap.typecast_from_VALUE var[:type], expr
- end
-
- def operands_info
- operands.map {|o|
- c, _ = RubyVM::Typemap.fetch o[:type]
- next c
- }.join
- end
-
- def handles_sp?
- /\b(false|0)\b/ !~ @attrs.fetch('handles_sp').expr.expr
- end
-
- def always_leaf?
- @attrs.fetch('leaf').expr.expr == 'true;'
- end
-
- def leaf_without_check_ints?
- @attrs.fetch('leaf').expr.expr == 'leafness_of_check_ints;'
- end
-
- def handle_canary stmt
- # Stack canary is basically a good thing that we want to add, however:
- #
- # - When the instruction returns variadic number of return values,
- # it is not easy to tell where is the stack top. We can't but
- # skip it.
- #
- # - When the instruction body is empty (like putobject), we can
- # say for 100% sure that canary is a waste of time.
- #
- # So we skip canary for those cases.
- return '' if @sig[:ret].any? {|i| i == '...' }
- return '' if @expr.blank?
- return " #{stmt};\n"
- end
-
- def inspect
- sprintf "#<%s %s@%s:%d>", self.class.name, @name, @loc[0], @loc[1]
- end
-
- def has_ope? var
- return @operands.any? {|i| i[:name] == var[:name] }
- end
-
- def has_pop? var
- return @pops.any? {|i| i[:name] == var[:name] }
- end
-
- def use_call_data?
- @use_call_data ||=
- @variables.find { |_, var_info| var_info[:type] == 'CALL_DATA' }
- end
-
- private
-
- def check_attribute_consistency
- if has_attribute?('sp_inc') \
- && use_call_data? \
- && !has_attribute?('comptime_sp_inc')
- # As the call cache caches information that can only be obtained at
- # runtime, we do not need it when compiling from AST to bytecode. This
- # attribute defines an expression that computes the stack pointer
- # increase based on just the call info to avoid reserving space for the
- # call cache at compile time. In the expression, all call data operands
- # are mapped to their call info counterpart. Additionally, all mentions
- # of `cd` in the operand name are replaced with `ci`.
- raise "Please define attribute `comptime_sp_inc` for `#{@name}`"
- end
- end
-
- def generate_attribute t, k, v
- @attrs[k] ||= RubyVM::Attribute.new \
- insn: self, \
- name: k, \
- type: t, \
- location: [], \
- expr: v.to_s + ';'
- return @attrs[k] ||= attr
- end
-
- def predefine_attributes
- # Beware: order matters here because some attribute depends another.
- generate_attribute 'const char*', 'name', "insn_name(#{bin})"
- generate_attribute 'enum ruby_vminsn_type', 'bin', bin
- generate_attribute 'rb_num_t', 'open', operands.size
- generate_attribute 'rb_num_t', 'popn', pops.size
- generate_attribute 'rb_num_t', 'retn', rets.size
- generate_attribute 'rb_num_t', 'width', width
- generate_attribute 'rb_snum_t', 'sp_inc', rets.size - pops.size
- generate_attribute 'bool', 'handles_sp', default_definition_of_handles_sp
- generate_attribute 'bool', 'leaf', default_definition_of_leaf
- end
-
- def default_definition_of_handles_sp
- # Insn with ISEQ should yield it; can handle sp.
- return operands.any? {|o| o[:type] == 'ISEQ' }
- end
-
- def default_definition_of_leaf
- # Insn that handles SP can never be a leaf.
- if not has_attribute? 'handles_sp' then
- return ! default_definition_of_handles_sp
- elsif handles_sp? then
- return "! #{call_attribute 'handles_sp'}"
- else
- return true
- end
- end
-
- def typesplit a
- @variables ||= {}
- a.map do |decl|
- md = %r'
- (?<comment> /[*] [^*]* [*]+ (?: [^*/] [^*]* [*]+ )* / ){0}
- (?<ws> \g<comment> | \s ){0}
- (?<ident> [_a-zA-Z] [0-9_a-zA-Z]* ){0}
- (?<type> (?: \g<ident> \g<ws>+ )* \g<ident> ){0}
- (?<var> \g<ident> ){0}
- \G \g<ws>* \g<type> \g<ws>+ \g<var>
- 'x.match(decl)
- @variables[md['var']] ||= {
- decl: decl,
- type: md['type'],
- name: md['var'],
- }
- end
- end
-
- @instances = RubyVM::InsnsDef.map {|h|
- new h.merge(:template => h)
- }
-
- def self.fetch name
- @instances.find do |insn|
- insn.name == name
- end or raise IndexError, "instruction not found: #{name}"
- end
-
- def self.to_a
- @instances
- end
-end
diff --git a/tool/ruby_vm/models/instructions.rb b/tool/ruby_vm/models/instructions.rb
index d243ffa49b..7be7064b14 100644
--- a/tool/ruby_vm/models/instructions.rb
+++ b/tool/ruby_vm/models/instructions.rb
@@ -9,13 +9,15 @@
# conditions mentioned in the file COPYING are met. Consult the file for
# details.
-require_relative 'bare_instructions'
-require_relative 'operands_unifications'
-require_relative 'instructions_unifications'
+require_relative 'bare_instruction'
+require_relative 'operands_unification'
+require_relative 'instructions_unification'
+require_relative 'trace_instruction'
+require_relative 'zjit_instruction'
-RubyVM::Instructions = RubyVM::BareInstructions.to_a + \
- RubyVM::OperandsUnifications.to_a + \
- RubyVM::InstructionsUnifications.to_a
-
-require_relative 'trace_instructions'
+RubyVM::Instructions = RubyVM::BareInstruction.all +
+ RubyVM::OperandsUnification.all +
+ RubyVM::InstructionsUnification.all +
+ RubyVM::TraceInstruction.all +
+ RubyVM::ZJITInstruction.all
RubyVM::Instructions.freeze
diff --git a/tool/ruby_vm/models/instructions_unification.rb b/tool/ruby_vm/models/instructions_unification.rb
new file mode 100644
index 0000000000..5c798e6d54
--- /dev/null
+++ b/tool/ruby_vm/models/instructions_unification.rb
@@ -0,0 +1,42 @@
+# -*- Ruby -*-
+# -*- frozen_string_literal: true; -*-
+# -*- warn_indent: true; -*-
+#
+# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
+#
+# 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.
+
+require_relative '../helpers/c_escape'
+require_relative '../loaders/opt_insn_unif_def'
+require_relative 'bare_instruction'
+
+class RubyVM::InstructionsUnification
+ include RubyVM::CEscape
+
+ attr_reader :name
+
+ def initialize opts = {}
+ @location = opts[:location]
+ @name = namegen opts[:signature]
+ @series = opts[:signature].map do |i|
+ RubyVM::BareInstruction.find(i) # Misshit is fatal
+ end
+ end
+
+ private
+
+ def namegen signature
+ as_tr_cpp ['UNIFIED', *signature].join('_')
+ end
+
+ @instances = RubyVM::OptInsnUnifDef.map do |h|
+ new h
+ end
+
+ def self.all
+ @instances
+ end
+end
diff --git a/tool/ruby_vm/models/instructions_unifications.rb b/tool/ruby_vm/models/instructions_unifications.rb
deleted file mode 100644
index 2932ec57b2..0000000000
--- a/tool/ruby_vm/models/instructions_unifications.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- Ruby -*-
-# -*- frozen_string_literal: true; -*-
-# -*- warn_indent: true; -*-
-#
-# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
-#
-# 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.
-
-require_relative '../helpers/c_escape'
-require_relative '../loaders/opt_insn_unif_def'
-require_relative 'bare_instructions'
-
-class RubyVM::InstructionsUnifications
- include RubyVM::CEscape
-
- attr_reader :name
-
- def initialize opts = {}
- @location = opts[:location]
- @name = namegen opts[:signature]
- @series = opts[:signature].map do |i|
- RubyVM::BareInstructions.fetch i # Misshit is fatal
- end
- end
-
- private
-
- def namegen signature
- as_tr_cpp ['UNIFIED', *signature].join('_')
- end
-
- @instances = RubyVM::OptInsnUnifDef.map do |h|
- new h
- end
-
- def self.to_a
- @instances
- end
-end
diff --git a/tool/ruby_vm/models/operands_unification.rb b/tool/ruby_vm/models/operands_unification.rb
new file mode 100644
index 0000000000..ce118648ca
--- /dev/null
+++ b/tool/ruby_vm/models/operands_unification.rb
@@ -0,0 +1,141 @@
+# -*- Ruby -*-
+# -*- frozen_string_literal: true; -*-
+# -*- warn_indent: true; -*-
+#
+# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
+#
+# 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.
+
+require_relative '../helpers/c_escape'
+require_relative '../loaders/opt_operand_def'
+require_relative 'bare_instruction'
+
+class RubyVM::OperandsUnification < RubyVM::BareInstruction
+ include RubyVM::CEscape
+
+ attr_reader :preamble, :original, :spec
+
+ def initialize opts = {}
+ name = opts[:signature][0]
+ @original = RubyVM::BareInstruction.find(name)
+ template = @original.template
+ parts = compose opts[:location], opts[:signature], template[:signature]
+ json = template.dup
+ json[:location] = opts[:location]
+ json[:signature] = parts[:signature]
+ json[:name] = parts[:name]
+ @preamble = parts[:preamble]
+ @spec = parts[:spec]
+ super json.merge(:template => template)
+ @konsts = parts[:vars]
+ @konsts.each do |v|
+ @variables[v[:name]] ||= v
+ end
+ end
+
+ def operand_shift_of var
+ before = @original.operands.find_index var
+ after = @operands.find_index var
+ raise "no #{var} for #{@name}" unless before and after
+ return before - after
+ end
+
+ def condition ptr
+ # :FIXME: I'm not sure if this method should be in model?
+ exprs = @spec.each_with_index.map do |(var, val), i|
+ case val when '*' then
+ next nil
+ else
+ type = @original.operands[i][:type]
+ expr = RubyVM::Typemap.typecast_to_VALUE type, val
+ next "#{ptr}[#{i}] == #{expr}"
+ end
+ end
+ exprs.compact!
+ if exprs.size == 1 then
+ return exprs[0]
+ else
+ exprs.map! {|i| "(#{i})" }
+ return exprs.join ' && '
+ end
+ end
+
+ def has_ope? var
+ super or @konsts.any? {|i| i[:name] == var[:name] }
+ end
+
+ private
+
+ def namegen signature
+ insn, argv = *signature
+ wcary = argv.map do |i|
+ case i when '*' then
+ 'WC'
+ else
+ i
+ end
+ end
+ as_tr_cpp [insn, *wcary].join(', ')
+ end
+
+ def compose location, spec, template
+ name = namegen spec
+ *, argv = *spec
+ opes = @original.operands
+ if opes.size != argv.size
+ raise sprintf("operand size mismatch for %s (%s's: %d, given: %d)",
+ name, template[:name], opes.size, argv.size)
+ else
+ src = []
+ mod = []
+ spec = []
+ vars = []
+ argv.each_index do |i|
+ j = argv[i]
+ k = opes[i]
+ spec[i] = [k, j]
+ case j when '*' then
+ # operand is from iseq
+ mod << k[:decl]
+ else
+ # operand is inside C
+ vars << k
+ src << {
+ location: location,
+ expr: " const #{k[:decl]} = #{j};"
+ }
+ end
+ end
+ src.map! {|i| RubyVM::CExpr.new i }
+ return {
+ name: name,
+ signature: {
+ name: name,
+ ope: mod,
+ pop: template[:pop],
+ ret: template[:ret],
+ },
+ preamble: src,
+ vars: vars,
+ spec: spec
+ }
+ end
+ end
+
+ @instances = RubyVM::OptOperandDef.map do |h|
+ new h
+ end
+
+ def self.all
+ @instances
+ end
+
+ def self.each_group
+ all.group_by(&:original).each_pair do |k, v|
+ yield k, v
+ end
+ end
+end
diff --git a/tool/ruby_vm/models/operands_unifications.rb b/tool/ruby_vm/models/operands_unifications.rb
deleted file mode 100644
index ff84abb3c3..0000000000
--- a/tool/ruby_vm/models/operands_unifications.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-# -*- Ruby -*-
-# -*- frozen_string_literal: true; -*-
-# -*- warn_indent: true; -*-
-#
-# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
-#
-# 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.
-
-require_relative '../helpers/c_escape'
-require_relative '../loaders/opt_operand_def'
-require_relative 'bare_instructions'
-
-class RubyVM::OperandsUnifications < RubyVM::BareInstructions
- include RubyVM::CEscape
-
- attr_reader :preamble, :original, :spec
-
- def initialize opts = {}
- name = opts[:signature][0]
- @original = RubyVM::BareInstructions.fetch name
- template = @original.template
- parts = compose opts[:location], opts[:signature], template[:signature]
- json = template.dup
- json[:location] = opts[:location]
- json[:signature] = parts[:signature]
- json[:name] = parts[:name]
- @preamble = parts[:preamble]
- @spec = parts[:spec]
- super json.merge(:template => template)
- @konsts = parts[:vars]
- @konsts.each do |v|
- @variables[v[:name]] ||= v
- end
- end
-
- def operand_shift_of var
- before = @original.operands.find_index var
- after = @operands.find_index var
- raise "no #{var} for #{@name}" unless before and after
- return before - after
- end
-
- def condition ptr
- # :FIXME: I'm not sure if this method should be in model?
- exprs = @spec.each_with_index.map do |(var, val), i|
- case val when '*' then
- next nil
- else
- type = @original.operands[i][:type]
- expr = RubyVM::Typemap.typecast_to_VALUE type, val
- next "#{ptr}[#{i}] == #{expr}"
- end
- end
- exprs.compact!
- if exprs.size == 1 then
- return exprs[0]
- else
- exprs.map! {|i| "(#{i})" }
- return exprs.join ' && '
- end
- end
-
- def has_ope? var
- super or @konsts.any? {|i| i[:name] == var[:name] }
- end
-
- private
-
- def namegen signature
- insn, argv = *signature
- wcary = argv.map do |i|
- case i when '*' then
- 'WC'
- else
- i
- end
- end
- as_tr_cpp [insn, *wcary].join(', ')
- end
-
- def compose location, spec, template
- name = namegen spec
- *, argv = *spec
- opes = @original.operands
- if opes.size != argv.size
- raise sprintf("operand size mismatch for %s (%s's: %d, given: %d)",
- name, template[:name], opes.size, argv.size)
- else
- src = []
- mod = []
- spec = []
- vars = []
- argv.each_index do |i|
- j = argv[i]
- k = opes[i]
- spec[i] = [k, j]
- case j when '*' then
- # operand is from iseq
- mod << k[:decl]
- else
- # operand is inside C
- vars << k
- src << {
- location: location,
- expr: " const #{k[:decl]} = #{j};"
- }
- end
- end
- src.map! {|i| RubyVM::CExpr.new i }
- return {
- name: name,
- signature: {
- name: name,
- ope: mod,
- pop: template[:pop],
- ret: template[:ret],
- },
- preamble: src,
- vars: vars,
- spec: spec
- }
- end
- end
-
- @instances = RubyVM::OptOperandDef.map do |h|
- new h
- end
-
- def self.to_a
- @instances
- end
-
- def self.each_group
- to_a.group_by(&:original).each_pair do |k, v|
- yield k, v
- end
- end
-end
diff --git a/tool/ruby_vm/models/trace_instruction.rb b/tool/ruby_vm/models/trace_instruction.rb
new file mode 100644
index 0000000000..6a3ad53c44
--- /dev/null
+++ b/tool/ruby_vm/models/trace_instruction.rb
@@ -0,0 +1,70 @@
+# -*- Ruby -*-
+# -*- frozen_string_literal: true; -*-
+# -*- warn_indent: true; -*-
+#
+# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
+#
+# 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.
+
+require_relative '../helpers/c_escape'
+require_relative 'bare_instruction'
+
+class RubyVM::TraceInstruction
+ include RubyVM::CEscape
+
+ attr_reader :name
+
+ def initialize orig
+ @orig = orig
+ @name = as_tr_cpp "trace @ #{@orig.name}"
+ end
+
+ def pretty_name
+ return sprintf "%s(...)(...)(...)", @name
+ end
+
+ def jump_destination
+ return @orig.name
+ end
+
+ def bin
+ return sprintf "BIN(%s)", @name
+ end
+
+ def width
+ return @orig.width
+ end
+
+ def operands_info
+ return @orig.operands_info
+ end
+
+ def rets
+ return ['...']
+ end
+
+ def pops
+ return ['...']
+ end
+
+ def attributes
+ return []
+ end
+
+ def has_attribute? *;
+ return false
+ end
+
+ private
+
+ @instances = (RubyVM::BareInstruction.all +
+ RubyVM::OperandsUnification.all +
+ RubyVM::InstructionsUnification.all).map {|i| new(i) }
+
+ def self.all
+ @instances
+ end
+end
diff --git a/tool/ruby_vm/models/trace_instructions.rb b/tool/ruby_vm/models/trace_instructions.rb
deleted file mode 100644
index d6501ece9d..0000000000
--- a/tool/ruby_vm/models/trace_instructions.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# -*- Ruby -*-
-# -*- frozen_string_literal: true; -*-
-# -*- warn_indent: true; -*-
-#
-# Copyright (c) 2017 Urabe, Shyouhei. All rights reserved.
-#
-# 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.
-
-require_relative '../helpers/c_escape'
-require_relative 'bare_instructions'
-
-class RubyVM::TraceInstructions
- include RubyVM::CEscape
-
- attr_reader :name
-
- def initialize orig
- @orig = orig
- @name = as_tr_cpp "trace @ #{@orig.name}"
- end
-
- def pretty_name
- return sprintf "%s(...)(...)(...)", @name
- end
-
- def jump_destination
- return @orig.name
- end
-
- def bin
- return sprintf "BIN(%s)", @name
- end
-
- def width
- return @orig.width
- end
-
- def operands_info
- return @orig.operands_info
- end
-
- def rets
- return ['...']
- end
-
- def pops
- return ['...']
- end
-
- def attributes
- return []
- end
-
- def has_attribute? *;
- return false
- end
-
- private
-
- @instances = RubyVM::Instructions.map {|i| new i }
-
- def self.to_a
- @instances
- end
-
- RubyVM::Instructions.push(*to_a)
-end
diff --git a/tool/ruby_vm/models/zjit_instruction.rb b/tool/ruby_vm/models/zjit_instruction.rb
new file mode 100644
index 0000000000..04764e4c61
--- /dev/null
+++ b/tool/ruby_vm/models/zjit_instruction.rb
@@ -0,0 +1,56 @@
+require_relative '../helpers/c_escape'
+require_relative 'bare_instruction'
+
+# Profile YARV instructions to optimize code generated by ZJIT
+class RubyVM::ZJITInstruction
+ include RubyVM::CEscape
+
+ attr_reader :name
+
+ def initialize(orig)
+ @orig = orig
+ @name = as_tr_cpp "zjit @ #{@orig.name}"
+ end
+
+ def pretty_name
+ return sprintf "%s(...)(...)(...)", @name
+ end
+
+ def jump_destination
+ return @orig.name
+ end
+
+ def bin
+ return sprintf "BIN(%s)", @name
+ end
+
+ def width
+ return @orig.width
+ end
+
+ def operands_info
+ return @orig.operands_info
+ end
+
+ def rets
+ return ['...']
+ end
+
+ def pops
+ return ['...']
+ end
+
+ def attributes
+ return []
+ end
+
+ def has_attribute?(*)
+ return false
+ end
+
+ @instances = RubyVM::BareInstruction.all.filter(&:zjit_profile?).map {|i| new(i) }
+
+ def self.all
+ @instances
+ end
+end
diff --git a/tool/ruby_vm/views/_comptime_insn_stack_increase.erb b/tool/ruby_vm/views/_comptime_insn_stack_increase.erb
index cb895815ce..8bb28db1c1 100644
--- a/tool/ruby_vm/views/_comptime_insn_stack_increase.erb
+++ b/tool/ruby_vm/views/_comptime_insn_stack_increase.erb
@@ -6,6 +6,16 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%#
+%
+% stack_increase = proc do |i|
+% if i.has_attribute?('sp_inc')
+% '-127'
+% else
+% sprintf("%4d", i.rets.size - i.pops.size)
+% end
+% end
+% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
+%
PUREFUNC(MAYBE_UNUSED(static int comptime_insn_stack_increase(int depth, int insn, const VALUE *opes)));
PUREFUNC(static rb_snum_t comptime_insn_stack_increase_dispatch(enum ruby_vminsn_type insn, const VALUE *opes));
@@ -13,15 +23,14 @@ rb_snum_t
comptime_insn_stack_increase_dispatch(enum ruby_vminsn_type insn, const VALUE *opes)
{
static const signed char t[] = {
-% RubyVM::Instructions.each_slice 8 do |a|
- <%= a.map { |i|
- if i.has_attribute?('sp_inc')
- '-127'
- else
- sprintf("%4d", i.rets.size - i.pops.size)
- end
- }.join(', ') -%>,
+% insns.each_slice(8) do |row|
+ <%= row.map(&stack_increase).join(', ') -%>,
+% end
+#if USE_ZJIT
+% zjit_insns.each_slice(8) do |row|
+ <%= row.map(&stack_increase).join(', ') -%>,
% end
+#endif
};
signed char c = t[insn];
diff --git a/tool/ruby_vm/views/_insn_leaf_info.erb b/tool/ruby_vm/views/_insn_leaf_info.erb
new file mode 100644
index 0000000000..f30366ffda
--- /dev/null
+++ b/tool/ruby_vm/views/_insn_leaf_info.erb
@@ -0,0 +1,18 @@
+MAYBE_UNUSED(static bool insn_leaf(int insn, const VALUE *opes));
+static bool
+insn_leaf(int insn, const VALUE *opes)
+{
+ switch (insn) {
+% RubyVM::Instructions.each do |insn|
+% next if insn.is_a?(RubyVM::TraceInstruction) || insn.is_a?(RubyVM::ZJITInstruction)
+ case <%= insn.bin %>:
+ return attr_leaf_<%= insn.name %>(<%=
+ insn.operands.map.with_index do |ope, i|
+ "(#{ope[:type]})opes[#{i}]"
+ end.join(', ')
+ %>);
+% end
+ default:
+ return false;
+ }
+}
diff --git a/tool/ruby_vm/views/_insn_len_info.erb b/tool/ruby_vm/views/_insn_len_info.erb
index 569dca5845..b29a405918 100644
--- a/tool/ruby_vm/views/_insn_len_info.erb
+++ b/tool/ruby_vm/views/_insn_len_info.erb
@@ -5,6 +5,9 @@
%# 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.
+%
+% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
+%
CONSTFUNC(MAYBE_UNUSED(static int insn_len(VALUE insn)));
RUBY_SYMBOL_EXPORT_BEGIN /* for debuggers */
@@ -13,9 +16,14 @@ RUBY_SYMBOL_EXPORT_END
#ifdef RUBY_VM_INSNS_INFO
const uint8_t rb_vm_insn_len_info[] = {
-% RubyVM::Instructions.each_slice 23 do |a|
- <%= a.map(&:width).join(', ') -%>,
+% insns.each_slice(23) do |row|
+ <%= row.map(&:width).join(', ') -%>,
% end
+#if USE_ZJIT
+% zjit_insns.each_slice(23) do |row|
+ <%= row.map(&:width).join(', ') -%>,
+% end
+#endif
};
ASSERT_VM_INSTRUCTION_SIZE(rb_vm_insn_len_info);
diff --git a/tool/ruby_vm/views/_insn_name_info.erb b/tool/ruby_vm/views/_insn_name_info.erb
index e7ded75e65..2862908631 100644
--- a/tool/ruby_vm/views/_insn_name_info.erb
+++ b/tool/ruby_vm/views/_insn_name_info.erb
@@ -6,10 +6,14 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
-% a = RubyVM::Instructions.map {|i| i.name }
-% b = (0...a.size)
-% c = a.inject([0]) {|r, i| r << (r[-1] + i.length + 1) }
-% c.pop
+% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
+%
+% next_offset = 0
+% name_offset = proc do |i|
+% offset = sprintf("%4d", next_offset)
+% next_offset += i.name.length + 1 # insn.name + \0
+% offset
+% end
%
CONSTFUNC(MAYBE_UNUSED(static const char *insn_name(VALUE insn)));
@@ -20,18 +24,29 @@ extern const unsigned short rb_vm_insn_name_offset[VM_INSTRUCTION_SIZE];
RUBY_SYMBOL_EXPORT_END
#ifdef RUBY_VM_INSNS_INFO
-const int rb_vm_max_insn_name_size = <%= a.map(&:size).max %>;
+%# "trace_" is longer than "zjit_", so USE_ZJIT doesn't impact the max name size.
+const int rb_vm_max_insn_name_size = <%= RubyVM::Instructions.map { |i| i.name.size }.max %>;
const char rb_vm_insn_name_base[] =
-% a.each do |i|
- <%=cstr i%> "\0"
+% insns.each do |i|
+ <%= cstr i.name %> "\0"
+% end
+#if USE_ZJIT
+% zjit_insns.each do |i|
+ <%= cstr i.name %> "\0"
% end
+#endif
;
const unsigned short rb_vm_insn_name_offset[] = {
-% c.each_slice 12 do |d|
- <%= d.map {|i| sprintf("%4d", i) }.join(', ') %>,
+% insns.each_slice(12) do |row|
+ <%= row.map(&name_offset).join(', ') %>,
+% end
+#if USE_ZJIT
+% zjit_insns.each_slice(12) do |row|
+ <%= row.map(&name_offset).join(', ') %>,
% end
+#endif
};
ASSERT_VM_INSTRUCTION_SIZE(rb_vm_insn_name_offset);
diff --git a/tool/ruby_vm/views/_insn_operand_info.erb b/tool/ruby_vm/views/_insn_operand_info.erb
index 996c33e960..410869fcd3 100644
--- a/tool/ruby_vm/views/_insn_operand_info.erb
+++ b/tool/ruby_vm/views/_insn_operand_info.erb
@@ -6,10 +6,16 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
-% a = RubyVM::Instructions.map {|i| i.operands_info }
-% b = (0...a.size)
-% c = a.inject([0]) {|r, i| r << (r[-1] + i.length + 1) }
-% c.pop
+% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
+%
+% operands_info = proc { |i| sprintf("%-6s", cstr(i.operands_info)) }
+%
+% next_offset = 0
+% op_offset = proc do |i|
+% offset = sprintf("%3d", next_offset)
+% next_offset += i.operands_info.length + 1 # insn.operands_info + \0
+% offset
+% end
%
CONSTFUNC(MAYBE_UNUSED(static const char *insn_op_types(VALUE insn)));
CONSTFUNC(MAYBE_UNUSED(static int insn_op_type(VALUE insn, long pos)));
@@ -21,15 +27,25 @@ RUBY_SYMBOL_EXPORT_END
#ifdef RUBY_VM_INSNS_INFO
const char rb_vm_insn_op_base[] =
-% a.each_slice 5 do |d|
- <%= d.map {|i| sprintf("%-6s", cstr(i)) }.join(' "\0" ') %> "\0"
+% insns.each_slice(5) do |row|
+ <%= row.map(&operands_info).join(' "\0" ') %> "\0"
+% end
+#if USE_ZJIT
+% zjit_insns.each_slice(5) do |row|
+ <%= row.map(&operands_info).join(' "\0" ') %> "\0"
% end
+#endif
;
const unsigned short rb_vm_insn_op_offset[] = {
-% c.each_slice 12 do |d|
- <%= d.map {|i| sprintf("%3d", i) }.join(', ') %>,
+% insns.each_slice(12) do |row|
+ <%= row.map(&op_offset).join(', ') %>,
+% end
+#if USE_ZJIT
+% zjit_insns.each_slice(12) do |row|
+ <%= row.map(&op_offset).join(', ') %>,
% end
+#endif
};
ASSERT_VM_INSTRUCTION_SIZE(rb_vm_insn_op_offset);
diff --git a/tool/ruby_vm/views/_leaf_helpers.erb b/tool/ruby_vm/views/_leaf_helpers.erb
index 6dae554a51..2756fa2dec 100644
--- a/tool/ruby_vm/views/_leaf_helpers.erb
+++ b/tool/ruby_vm/views/_leaf_helpers.erb
@@ -10,10 +10,6 @@
#include "iseq.h"
-// This is used to tell JIT that this insn would be leaf if CHECK_INTS didn't exist.
-// It should be used only when RUBY_VM_CHECK_INTS is directly written in insns.def.
-static bool leafness_of_check_ints = false;
-
static bool
leafness_of_defined(rb_num_t op_type)
{
@@ -25,7 +21,7 @@ leafness_of_defined(rb_num_t op_type)
case DEFINED_YIELD:
case DEFINED_REF:
case DEFINED_ZSUPER:
- return false;
+ return true;
case DEFINED_CONST:
case DEFINED_CONST_FROM:
/* has rb_autoload_load(); */
diff --git a/tool/ruby_vm/views/_zjit_helpers.erb b/tool/ruby_vm/views/_zjit_helpers.erb
new file mode 100644
index 0000000000..1185dbd9d8
--- /dev/null
+++ b/tool/ruby_vm/views/_zjit_helpers.erb
@@ -0,0 +1,31 @@
+#if USE_ZJIT
+
+MAYBE_UNUSED(static int vm_bare_insn_to_zjit_insn(int insn));
+static int
+vm_bare_insn_to_zjit_insn(int insn)
+{
+ switch (insn) {
+% RubyVM::ZJITInstruction.all.each do |insn|
+ case BIN(<%= insn.jump_destination %>):
+ return <%= insn.bin %>;
+% end
+ default:
+ return insn;
+ }
+}
+
+MAYBE_UNUSED(static int vm_zjit_insn_to_bare_insn(int insn));
+static int
+vm_zjit_insn_to_bare_insn(int insn)
+{
+ switch (insn) {
+% RubyVM::ZJITInstruction.all.each do |insn|
+ case <%= insn.bin %>:
+ return BIN(<%= insn.jump_destination %>);
+% end
+ default:
+ return insn;
+ }
+}
+
+#endif
diff --git a/tool/ruby_vm/views/_zjit_instruction.erb b/tool/ruby_vm/views/_zjit_instruction.erb
new file mode 100644
index 0000000000..7fd657697c
--- /dev/null
+++ b/tool/ruby_vm/views/_zjit_instruction.erb
@@ -0,0 +1,12 @@
+#if USE_ZJIT
+
+/* insn <%= insn.pretty_name %> */
+INSN_ENTRY(<%= insn.name %>)
+{
+ START_OF_ORIGINAL_INSN(<%= insn.name %>);
+ rb_zjit_profile_insn(BIN(<%= insn.jump_destination %>), ec);
+ DISPATCH_ORIGINAL_INSN(<%= insn.jump_destination %>);
+ END_INSN(<%= insn.name %>);
+}
+
+#endif
diff --git a/tool/ruby_vm/views/insns.inc.erb b/tool/ruby_vm/views/insns.inc.erb
index 29981a8a2d..6521a89b8a 100644
--- a/tool/ruby_vm/views/insns.inc.erb
+++ b/tool/ruby_vm/views/insns.inc.erb
@@ -6,21 +6,36 @@
%# 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.
+%
+% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
+%
<%= render 'copyright' %>
<%= render 'notice', locals: {
this_file: 'contains YARV instruction list',
edit: __FILE__,
} -%>
+#ifndef INSNS_INC
+#define INSNS_INC 1
+
/* BIN : Basic Instruction Name */
#define BIN(n) YARVINSN_##n
enum ruby_vminsn_type {
-% RubyVM::Instructions.each do |i|
+% insns.each do |i|
+ <%= i.bin %>,
+% end
+#if USE_ZJIT
+% zjit_insns.each do |i|
<%= i.bin %>,
% end
+#endif
VM_INSTRUCTION_SIZE
};
+#define VM_BARE_INSTRUCTION_SIZE <%= RubyVM::Instructions.count { |i| i.name !~ /\A(trace|zjit)_/ } %>
+
#define ASSERT_VM_INSTRUCTION_SIZE(array) \
STATIC_ASSERT(numberof_##array, numberof(array) == VM_INSTRUCTION_SIZE)
+
+#endif
diff --git a/tool/ruby_vm/views/insns_info.inc.erb b/tool/ruby_vm/views/insns_info.inc.erb
index 110d9dfae5..48dd0e8832 100644
--- a/tool/ruby_vm/views/insns_info.inc.erb
+++ b/tool/ruby_vm/views/insns_info.inc.erb
@@ -11,11 +11,16 @@
this_file: 'contains instruction information for yarv instruction sequence.',
edit: __FILE__,
} %>
+#ifndef INSNS_INFO_INC
+#define INSNS_INFO_INC 1
<%= render 'insn_type_chars' %>
<%= render 'insn_name_info' %>
<%= render 'insn_len_info' %>
<%= render 'insn_operand_info' %>
<%= render 'leaf_helpers' %>
<%= render 'sp_inc_helpers' %>
+<%= render 'zjit_helpers' %>
<%= render 'attributes' %>
+<%= render 'insn_leaf_info' %>
<%= render 'comptime_insn_stack_increase' %>
+#endif
diff --git a/tool/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb b/tool/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb
new file mode 100644
index 0000000000..793528af5d
--- /dev/null
+++ b/tool/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb
@@ -0,0 +1,14 @@
+module RubyVM::RJIT # :nodoc: all
+ Instruction = Data.define(:name, :bin, :len, :operands)
+
+ INSNS = {
+% RubyVM::Instructions.each_with_index do |insn, i|
+ <%= i %> => Instruction.new(
+ name: :<%= insn.name %>,
+ bin: <%= i %>, # BIN(<%= insn.name %>)
+ len: <%= insn.width %>, # insn_len
+ operands: <%= (insn.operands unless insn.name.start_with?(/trace_|zjit_/)).inspect %>,
+ ),
+% end
+ }
+end
diff --git a/tool/ruby_vm/views/optinsn.inc.erb b/tool/ruby_vm/views/optinsn.inc.erb
index de7bb210ea..9d9cf0a43a 100644
--- a/tool/ruby_vm/views/optinsn.inc.erb
+++ b/tool/ruby_vm/views/optinsn.inc.erb
@@ -23,7 +23,7 @@ insn_operands_unification(INSN *iobj)
/* do nothing */;
break;
-% RubyVM::OperandsUnifications.each_group do |orig, unifs|
+% RubyVM::OperandsUnification.each_group do |orig, unifs|
case <%= orig.bin %>:
% unifs.each do |insn|
@@ -56,7 +56,7 @@ rb_insn_unified_local_var_level(VALUE insn)
switch (insn) {
default:
return -1; /* do nothing */;
-% RubyVM::OperandsUnifications.each_group do |orig, unifs|
+% RubyVM::OperandsUnification.each_group do |orig, unifs|
% unifs.each do|insn|
case <%= insn.bin %>:
% insn.spec.map{|(var,val)|val}.reject{|i| i == '*' }.each do |val|
diff --git a/tool/ruby_vm/views/optunifs.inc.erb b/tool/ruby_vm/views/optunifs.inc.erb
index e92a95beff..c096712936 100644
--- a/tool/ruby_vm/views/optunifs.inc.erb
+++ b/tool/ruby_vm/views/optunifs.inc.erb
@@ -7,7 +7,6 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
% raise ':FIXME:TBW' if RubyVM::VmOptsH['INSTRUCTIONS_UNIFICATION']
-% n = RubyVM::Instructions.size
<%= render 'copyright' %>
<%= render 'notice', locals: {
this_file: 'is for threaded code',
@@ -16,6 +15,4 @@
/* Let .bss section automatically initialize this variable */
/* cf. Section 6.7.8 of ISO/IEC 9899:1999 */
-static const int *const *const unified_insns_data[<%= n %>];
-
-ASSERT_VM_INSTRUCTION_SIZE(unified_insns_data);
+static const int *const *const unified_insns_data[VM_INSTRUCTION_SIZE];
diff --git a/tool/ruby_vm/views/vm.inc.erb b/tool/ruby_vm/views/vm.inc.erb
index c1a3faf60a..38bf5f05ae 100644
--- a/tool/ruby_vm/views/vm.inc.erb
+++ b/tool/ruby_vm/views/vm.inc.erb
@@ -13,18 +13,22 @@
} -%>
#include "vm_insnhelper.h"
-% RubyVM::BareInstructions.to_a.each do |insn|
+% RubyVM::BareInstruction.all.each do |insn|
<%= render 'insn_entry', locals: { insn: insn } -%>
% end
%
-% RubyVM::OperandsUnifications.to_a.each do |insn|
+% RubyVM::OperandsUnification.all.each do |insn|
<%= render 'insn_entry', locals: { insn: insn } -%>
% end
%
-% RubyVM::InstructionsUnifications.to_a.each do |insn|
+% RubyVM::InstructionsUnification.all.each do |insn|
<%= render 'insn_entry', locals: { insn: insn } -%>
% end
%
-% RubyVM::TraceInstructions.to_a.each do |insn|
+% RubyVM::ZJITInstruction.all.each do |insn|
+<%= render 'zjit_instruction', locals: { insn: insn } -%>
+% end
+%
+% RubyVM::TraceInstruction.all.each do |insn|
<%= render 'trace_instruction', locals: { insn: insn } -%>
% end
diff --git a/tool/ruby_vm/views/vmtc.inc.erb b/tool/ruby_vm/views/vmtc.inc.erb
index 99cbd92614..39dc8bfa6b 100644
--- a/tool/ruby_vm/views/vmtc.inc.erb
+++ b/tool/ruby_vm/views/vmtc.inc.erb
@@ -6,6 +6,9 @@
%# 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.
+%
+% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
+%
<%= render 'copyright' -%>
<%= render 'notice', locals: {
this_file: 'is for threaded code',
@@ -13,9 +16,14 @@
} -%>
static const void *const insns_address_table[] = {
-% RubyVM::Instructions.each do |i|
+% insns.each do |i|
LABEL_PTR(<%= i.name %>),
% end
+#if USE_ZJIT
+% zjit_insns.each do |i|
+ LABEL_PTR(<%= i.name %>),
+% end
+#endif
};
ASSERT_VM_INSTRUCTION_SIZE(insns_address_table);
diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb
index 9863c6bbe9..db64e20274 100755
--- a/tool/sync_default_gems.rb
+++ b/tool/sync_default_gems.rb
@@ -4,6 +4,8 @@
require 'fileutils'
require "rbconfig"
+require "find"
+require "tempfile"
module SyncDefaultGems
include FileUtils
@@ -11,80 +13,331 @@ module SyncDefaultGems
module_function
+ # upstream: "owner/repo"
+ # branch: "branch_name"
+ # mappings: [ ["path_in_upstream", "path_in_ruby"], ... ]
+ # NOTE: path_in_ruby is assumed to be "owned" by this gem, and the contents
+ # will be removed before sync
+ # exclude: [ "fnmatch_pattern_after_mapping", ... ]
+ Repository = Data.define(:upstream, :branch, :mappings, :exclude) do
+ def excluded?(newpath)
+ p = newpath
+ until p == "."
+ return true if exclude.any? {|pat| File.fnmatch?(pat, p, File::FNM_PATHNAME|File::FNM_EXTGLOB)}
+ p = File.dirname(p)
+ end
+ false
+ end
+
+ def rewrite_for_ruby(path)
+ newpath = mappings.find do |src, dst|
+ if path == src || path.start_with?(src + "/")
+ break path.sub(src, dst)
+ end
+ end
+ return nil unless newpath
+ return nil if excluded?(newpath)
+ newpath
+ end
+ end
+
+ CLASSICAL_DEFAULT_BRANCH = "master"
+
+ def repo((upstream, branch), mappings, exclude: [])
+ branch ||= CLASSICAL_DEFAULT_BRANCH
+ exclude += ["ext/**/depend"]
+ Repository.new(upstream:, branch:, mappings:, exclude:)
+ end
+
+ def lib((upstream, branch), gemspec_in_subdir: false)
+ _org, name = upstream.split("/")
+ gemspec_dst = gemspec_in_subdir ? "lib/#{name}/#{name}.gemspec" : "lib/#{name}.gemspec"
+ repo([upstream, branch], [
+ ["lib/#{name}.rb", "lib/#{name}.rb"],
+ ["lib/#{name}", "lib/#{name}"],
+ ["test/test_#{name}.rb", "test/test_#{name}.rb"],
+ ["test/#{name}", "test/#{name}"],
+ ["#{name}.gemspec", gemspec_dst],
+ ])
+ end
+
+ # Note: tool/auto_review_pr.rb also depends on these constants.
+ NO_UPSTREAM = [
+ "lib/unicode_normalize", # not to match with "lib/un"
+ ]
REPOSITORIES = {
- "io-console": 'ruby/io-console',
- "io-nonblock": 'ruby/io-nonblock',
- "io-wait": 'ruby/io-wait',
- "net-http": "ruby/net-http",
- "net-protocol": "ruby/net-protocol",
- "open-uri": "ruby/open-uri",
- "win32-registry": "ruby/win32-registry",
- English: "ruby/English",
- cgi: "ruby/cgi",
- date: 'ruby/date',
- delegate: "ruby/delegate",
- did_you_mean: "ruby/did_you_mean",
- digest: "ruby/digest",
- erb: "ruby/erb",
- error_highlight: "ruby/error_highlight",
- etc: 'ruby/etc',
- fcntl: 'ruby/fcntl',
- fileutils: 'ruby/fileutils',
- find: "ruby/find",
- forwardable: "ruby/forwardable",
- ipaddr: 'ruby/ipaddr',
- json: 'ruby/json',
- mmtk: ['ruby/mmtk', "main"],
- open3: "ruby/open3",
- openssl: "ruby/openssl",
- optparse: "ruby/optparse",
- pathname: "ruby/pathname",
- pp: "ruby/pp",
- prettyprint: "ruby/prettyprint",
- prism: ["ruby/prism", "main"],
- psych: 'ruby/psych',
- resolv: "ruby/resolv",
- rubygems: 'rubygems/rubygems',
- securerandom: "ruby/securerandom",
- set: "ruby/set",
- shellwords: "ruby/shellwords",
- singleton: "ruby/singleton",
- stringio: 'ruby/stringio',
- strscan: 'ruby/strscan',
- syntax_suggest: ["ruby/syntax_suggest", "main"],
- tempfile: "ruby/tempfile",
- time: "ruby/time",
- timeout: "ruby/timeout",
- tmpdir: "ruby/tmpdir",
- tsort: "ruby/tsort",
- un: "ruby/un",
- uri: "ruby/uri",
- weakref: "ruby/weakref",
- yaml: "ruby/yaml",
- zlib: 'ruby/zlib',
+ Onigmo: repo("k-takata/Onigmo", [
+ ["regcomp.c", "regcomp.c"],
+ ["regenc.c", "regenc.c"],
+ ["regenc.h", "regenc.h"],
+ ["regerror.c", "regerror.c"],
+ ["regexec.c", "regexec.c"],
+ ["regint.h", "regint.h"],
+ ["regparse.c", "regparse.c"],
+ ["regparse.h", "regparse.h"],
+ ["regsyntax.c", "regsyntax.c"],
+ ["onigmo.h", "include/ruby/onigmo.h"],
+ ["enc", "enc"],
+ ]),
+ "io-console": repo("ruby/io-console", [
+ ["ext/io/console", "ext/io/console"],
+ ["test/io/console", "test/io/console"],
+ ["lib/io/console", "ext/io/console/lib/console"],
+ ["io-console.gemspec", "ext/io/console/io-console.gemspec"],
+ ]),
+ "io-nonblock": repo("ruby/io-nonblock", [
+ ["ext/io/nonblock", "ext/io/nonblock"],
+ ["test/io/nonblock", "test/io/nonblock"],
+ ["io-nonblock.gemspec", "ext/io/nonblock/io-nonblock.gemspec"],
+ ]),
+ "io-wait": repo("ruby/io-wait", [
+ ["ext/io/wait", "ext/io/wait"],
+ ["test/io/wait", "test/io/wait"],
+ ["io-wait.gemspec", "ext/io/wait/io-wait.gemspec"],
+ ]),
+ "net-http": repo("ruby/net-http", [
+ ["lib/net/http.rb", "lib/net/http.rb"],
+ ["lib/net/http", "lib/net/http"],
+ ["test/net/http", "test/net/http"],
+ ["net-http.gemspec", "lib/net/http/net-http.gemspec"],
+ ]),
+ "net-protocol": repo("ruby/net-protocol", [
+ ["lib/net/protocol.rb", "lib/net/protocol.rb"],
+ ["test/net/protocol", "test/net/protocol"],
+ ["net-protocol.gemspec", "lib/net/net-protocol.gemspec"],
+ ]),
+ "open-uri": lib("ruby/open-uri"),
+ English: lib("ruby/English"),
+ date: repo("ruby/date", [
+ ["doc/date", "doc/date"],
+ ["ext/date", "ext/date"],
+ ["lib", "ext/date/lib"],
+ ["test/date", "test/date"],
+ ["date.gemspec", "ext/date/date.gemspec"],
+ ], exclude: [
+ "ext/date/lib/date_core.bundle",
+ ]),
+ delegate: lib("ruby/delegate"),
+ did_you_mean: repo("ruby/did_you_mean", [
+ ["lib/did_you_mean.rb", "lib/did_you_mean.rb"],
+ ["lib/did_you_mean", "lib/did_you_mean"],
+ ["test", "test/did_you_mean"],
+ ["did_you_mean.gemspec", "lib/did_you_mean/did_you_mean.gemspec"],
+ ], exclude: [
+ "test/did_you_mean/lib",
+ "test/did_you_mean/tree_spell/test_explore.rb",
+ ]),
+ digest: repo("ruby/digest", [
+ ["ext/digest/lib/digest/sha2", "ext/digest/sha2/lib/sha2"],
+ ["ext/digest", "ext/digest"],
+ ["lib/digest.rb", "ext/digest/lib/digest.rb"],
+ ["lib/digest/version.rb", "ext/digest/lib/digest/version.rb"],
+ ["lib/digest/sha2.rb", "ext/digest/sha2/lib/sha2.rb"],
+ ["test/digest", "test/digest"],
+ ["digest.gemspec", "ext/digest/digest.gemspec"],
+ ]),
+ erb: repo("ruby/erb", [
+ ["ext/erb", "ext/erb"],
+ ["lib/erb", "lib/erb"],
+ ["lib/erb.rb", "lib/erb.rb"],
+ ["test/erb", "test/erb"],
+ ["erb.gemspec", "lib/erb/erb.gemspec"],
+ ["libexec/erb", "libexec/erb"],
+ ]),
+ error_highlight: repo("ruby/error_highlight", [
+ ["lib/error_highlight.rb", "lib/error_highlight.rb"],
+ ["lib/error_highlight", "lib/error_highlight"],
+ ["test", "test/error_highlight"],
+ ["error_highlight.gemspec", "lib/error_highlight/error_highlight.gemspec"],
+ ]),
+ etc: repo("ruby/etc", [
+ ["ext/etc", "ext/etc"],
+ ["test/etc", "test/etc"],
+ ["etc.gemspec", "ext/etc/etc.gemspec"],
+ ]),
+ fcntl: repo("ruby/fcntl", [
+ ["ext/fcntl", "ext/fcntl"],
+ ["fcntl.gemspec", "ext/fcntl/fcntl.gemspec"],
+ ]),
+ fileutils: lib("ruby/fileutils"),
+ find: lib("ruby/find"),
+ forwardable: lib("ruby/forwardable", gemspec_in_subdir: true),
+ ipaddr: lib("ruby/ipaddr"),
+ json: repo("ruby/json", [
+ ["ext/json/ext", "ext/json"],
+ ["test/json", "test/json"],
+ ["lib", "ext/json/lib"],
+ ["json.gemspec", "ext/json/json.gemspec"],
+ ], exclude: [
+ "ext/json/lib/json/ext/.keep",
+ "ext/json/lib/json/pure.rb",
+ "ext/json/lib/json/pure",
+ "ext/json/lib/json/truffle_ruby",
+ "test/json/lib",
+ "ext/json/extconf.rb",
+ ]),
+ mmtk: repo(["ruby/mmtk", "main"], [
+ ["gc/mmtk", "gc/mmtk"],
+ ]),
+ open3: lib("ruby/open3", gemspec_in_subdir: true).tap {
+ it.exclude << "lib/open3/jruby_windows.rb"
+ },
+ openssl: repo("ruby/openssl", [
+ ["ext/openssl", "ext/openssl"],
+ ["lib", "ext/openssl/lib"],
+ ["test/openssl", "test/openssl"],
+ ["sample", "sample/openssl"],
+ ["openssl.gemspec", "ext/openssl/openssl.gemspec"],
+ ["History.md", "ext/openssl/History.md"],
+ ], exclude: [
+ "test/openssl/envutil.rb",
+ "ext/openssl/depend",
+ ]),
+ optparse: lib("ruby/optparse", gemspec_in_subdir: true).tap {
+ it.mappings << ["doc/optparse", "doc/optparse"]
+ },
+ pp: lib("ruby/pp"),
+ prettyprint: lib("ruby/prettyprint"),
+ prism: repo(["ruby/prism", "main"], [
+ ["ext/prism", "prism"],
+ ["lib/prism.rb", "lib/prism.rb"],
+ ["lib/prism", "lib/prism"],
+ ["test/prism", "test/prism"],
+ ["src", "prism"],
+ ["prism.gemspec", "lib/prism/prism.gemspec"],
+ ["include/prism", "prism"],
+ ["include/prism.h", "prism/prism.h"],
+ ["config.yml", "prism/config.yml"],
+ ["templates", "prism/templates"],
+ ], exclude: [
+ "prism/templates/{javascript,java,rbi,sig}",
+ "test/prism/snapshots_test.rb",
+ "test/prism/snapshots",
+ "prism/extconf.rb",
+ "prism/srcs.mk*",
+ ]),
+ psych: repo("ruby/psych", [
+ ["ext/psych", "ext/psych"],
+ ["lib", "ext/psych/lib"],
+ ["test/psych", "test/psych"],
+ ["psych.gemspec", "ext/psych/psych.gemspec"],
+ ], exclude: [
+ "ext/psych/lib/org",
+ "ext/psych/lib/psych.jar",
+ "ext/psych/lib/psych_jars.rb",
+ "ext/psych/lib/psych.{bundle,so}",
+ "ext/psych/lib/2.*",
+ "ext/psych/yaml/LICENSE",
+ "ext/psych/.gitignore",
+ ]),
+ resolv: repo("ruby/resolv", [
+ ["lib/resolv.rb", "lib/resolv.rb"],
+ ["test/resolv", "test/resolv"],
+ ["resolv.gemspec", "lib/resolv.gemspec"],
+ ["ext/win32/resolv/lib/resolv.rb", "ext/win32/lib/win32/resolv.rb"],
+ ["ext/win32/resolv", "ext/win32/resolv"],
+ ]),
+ rubygems: repo("ruby/rubygems", [
+ ["lib/rubygems.rb", "lib/rubygems.rb"],
+ ["lib/rubygems", "lib/rubygems"],
+ ["test/rubygems", "test/rubygems"],
+ ["bundler/lib/bundler.rb", "lib/bundler.rb"],
+ ["bundler/lib/bundler", "lib/bundler"],
+ ["bundler/exe/bundle", "libexec/bundle"],
+ ["bundler/exe/bundler", "libexec/bundler"],
+ ["bundler/bundler.gemspec", "lib/bundler/bundler.gemspec"],
+ ["spec", "spec/bundler"],
+ *["bundle", "parallel_rspec", "rspec"].map {|binstub|
+ ["bin/#{binstub}", "spec/bin/#{binstub}"]
+ },
+ *%w[dev_gems test_gems rubocop_gems standard_gems].flat_map {|gemfile|
+ ["rb.lock", "rb"].map do |ext|
+ ["tool/bundler/#{gemfile}.#{ext}", "tool/bundler/#{gemfile}.#{ext}"]
+ end
+ },
+ ], exclude: [
+ "spec/bundler/bin",
+ "spec/bundler/support/artifice/vcr_cassettes",
+ "spec/bundler/support/artifice/used_cassettes.txt",
+ "lib/{bundler,rubygems}/**/{COPYING,LICENSE,README}{,.{md,txt,rdoc}}",
+ ]),
+ securerandom: lib("ruby/securerandom"),
+ shellwords: lib("ruby/shellwords"),
+ singleton: lib("ruby/singleton"),
+ stringio: repo("ruby/stringio", [
+ ["ext/stringio", "ext/stringio"],
+ ["test/stringio", "test/stringio"],
+ ["stringio.gemspec", "ext/stringio/stringio.gemspec"],
+ ["doc/stringio", "doc/stringio"],
+ ], exclude: [
+ "ext/stringio/README.md",
+ ]),
+ strscan: repo("ruby/strscan", [
+ ["ext/strscan", "ext/strscan"],
+ ["lib", "ext/strscan/lib"],
+ ["test/strscan", "test/strscan"],
+ ["strscan.gemspec", "ext/strscan/strscan.gemspec"],
+ ["doc/strscan", "doc/strscan"],
+ ], exclude: [
+ "ext/strscan/regenc.h",
+ "ext/strscan/regint.h",
+ "ext/strscan/lib/strscan/truffleruby.rb",
+ ]),
+ syntax_suggest: repo(["ruby/syntax_suggest", "main"], [
+ ["lib/syntax_suggest.rb", "lib/syntax_suggest.rb"],
+ ["lib/syntax_suggest", "lib/syntax_suggest"],
+ ["syntax_suggest.gemspec", "lib/syntax_suggest/syntax_suggest.gemspec"],
+ ["exe/syntax_suggest", "libexec/syntax_suggest"],
+ ["spec", "spec/syntax_suggest"],
+ ]),
+ tempfile: lib("ruby/tempfile"),
+ time: lib("ruby/time"),
+ timeout: lib("ruby/timeout"),
+ tmpdir: lib("ruby/tmpdir"),
+ un: lib("ruby/un"),
+ uri: lib("ruby/uri", gemspec_in_subdir: true),
+ weakref: lib("ruby/weakref"),
+ yaml: lib("ruby/yaml", gemspec_in_subdir: true),
+ zlib: repo("ruby/zlib", [
+ ["ext/zlib", "ext/zlib"],
+ ["test/zlib", "test/zlib"],
+ ["zlib.gemspec", "ext/zlib/zlib.gemspec"],
+ ]),
}.transform_keys(&:to_s)
- CLASSICAL_DEFAULT_BRANCH = "master"
+ def REPOSITORIES.[](gem)
+ fetch(gem) {raise "unknown repository - #{gem}"}
+ end
- class << REPOSITORIES
- def [](gem)
- repo, branch = super(gem)
- return repo, branch || CLASSICAL_DEFAULT_BRANCH
+ class << Repository
+ def find_upstream(file)
+ return if NO_UPSTREAM.any? {|dst| file.start_with?(dst) }
+ REPOSITORIES.find do |repo_name, repository|
+ if repository.mappings.any? {|_src, dst| file.start_with?(dst) }
+ break repo_name
+ end
+ end
end
- def each_pair
- super do |gem, (repo, branch)|
- yield gem, [repo, branch || CLASSICAL_DEFAULT_BRANCH]
- end
+ def group(files)
+ files.group_by {|file| find_upstream(file)}
end
end
+ # Allow synchronizing commits up to this FETCH_DEPTH. We've historically merged PRs
+ # with about 250 commits to ruby/ruby, so we use this depth for ruby/ruby in general.
+ FETCH_DEPTH = 500
+
def pipe_readlines(args, rs: "\0", chomp: true)
IO.popen(args) do |f|
f.readlines(rs, chomp: chomp)
end
end
+ def porcelain_status(*pattern)
+ pipe_readlines(%W"git status --porcelain --no-renames -z --" + pattern)
+ end
+
def replace_rdoc_ref(file)
src = File.binread(file)
changed = false
@@ -103,7 +356,7 @@ module SyncDefaultGems
end
def replace_rdoc_ref_all
- result = pipe_readlines(%W"git status --porcelain -z -- *.c *.rb *.rdoc")
+ result = porcelain_status("*.c", "*.rb", "*.rdoc")
result.map! {|line| line[/\A.M (.*)/, 1]}
result.compact!
return if result.empty?
@@ -111,247 +364,69 @@ module SyncDefaultGems
result.inject(false) {|changed, file| changed | replace_rdoc_ref(file)}
end
+ def replace_rdoc_ref_all_full
+ Dir.glob("**/*.{c,rb,rdoc}").inject(false) {|changed, file| changed | replace_rdoc_ref(file)}
+ end
+
+ def rubygems_do_fixup
+ gemspec_content = File.readlines("lib/bundler/bundler.gemspec").map do |line|
+ next if line =~ /LICENSE\.md/
+
+ line.gsub("bundler.gemspec", "lib/bundler/bundler.gemspec")
+ end.compact.join
+ File.write("lib/bundler/bundler.gemspec", gemspec_content)
+
+ ["bundle", "parallel_rspec", "rspec"].each do |binstub|
+ path = "spec/bin/#{binstub}"
+ next unless File.exist?(path)
+ content = File.read(path).gsub("../spec", "../bundler")
+ File.write(path, content)
+ chmod("+x", path)
+ end
+ end
+
# We usually don't use this. Please consider using #sync_default_gems_with_commits instead.
def sync_default_gems(gem)
- repo, = REPOSITORIES[gem]
- puts "Sync #{repo}"
-
- upstream = File.join("..", "..", repo)
-
- case gem
- when "rubygems"
- rm_rf(%w[lib/rubygems lib/rubygems.rb test/rubygems])
- cp_r(Dir.glob("#{upstream}/lib/rubygems*"), "lib")
- cp_r("#{upstream}/test/rubygems", "test")
- rm_rf(%w[lib/bundler lib/bundler.rb libexec/bundler libexec/bundle spec/bundler tool/bundler/*])
- cp_r(Dir.glob("#{upstream}/bundler/lib/bundler*"), "lib")
- cp_r(Dir.glob("#{upstream}/bundler/exe/bundle*"), "libexec")
-
- gemspec_content = File.readlines("#{upstream}/bundler/bundler.gemspec").map do |line|
- next if line =~ /LICENSE\.md/
-
- line.gsub("bundler.gemspec", "lib/bundler/bundler.gemspec")
- end.compact.join
- File.write("lib/bundler/bundler.gemspec", gemspec_content)
-
- cp_r("#{upstream}/bundler/spec", "spec/bundler")
- %w[dev_gems test_gems rubocop_gems standard_gems].each do |gemfile|
- ["rb.lock", "rb"].each do |ext|
- cp_r("#{upstream}/tool/bundler/#{gemfile}.#{ext}", "tool/bundler")
+ config = REPOSITORIES[gem]
+ puts "Sync #{config.upstream}"
+
+ upstream = File.join("..", "..", config.upstream)
+
+ unless File.exist?(upstream)
+ abort %[Expected '#{upstream}' (#{File.expand_path("#{upstream}")}) to be a directory, but it didn't exist.]
+ end
+
+ config.mappings.each do |src, dst|
+ rm_rf(dst)
+ end
+
+ copied = Set.new
+ config.mappings.each do |src, dst|
+ prefix = File.join(upstream, src)
+ # Maybe mapping needs to be updated?
+ next unless File.exist?(prefix)
+ Find.find(prefix) do |path|
+ next if File.directory?(path)
+ if copied.add?(path)
+ newpath = config.rewrite_for_ruby(path.sub(%r{\A#{Regexp.escape(upstream)}/}, ""))
+ next unless newpath
+ mkdir_p(File.dirname(newpath))
+ cp(path, newpath)
end
end
- rm_rf Dir.glob("spec/bundler/support/artifice/{vcr_cassettes,used_cassettes.txt}")
- rm_rf Dir.glob("lib/{bundler,rubygems}/**/{COPYING,LICENSE,README}{,.{md,txt,rdoc}}")
- when "json"
- rm_rf(%w[ext/json lib/json test/json])
- cp_r("#{upstream}/ext/json/ext", "ext/json")
- cp_r("#{upstream}/test/json", "test/json")
- rm_rf("test/json/lib")
- cp_r("#{upstream}/lib", "ext/json")
- cp_r("#{upstream}/json.gemspec", "ext/json")
- rm_rf(%w[ext/json/lib/json/pure.rb ext/json/lib/json/pure ext/json/lib/json/truffle_ruby/])
- json_files = Dir.glob("ext/json/lib/json/ext/**/*", File::FNM_DOTMATCH).select { |f| File.file?(f) }
- rm_rf(json_files - Dir.glob("ext/json/lib/json/ext/**/*.rb") - Dir.glob("ext/json/lib/json/ext/**/depend"))
- `git checkout ext/json/extconf.rb ext/json/generator/depend ext/json/parser/depend ext/json/depend benchmark/`
- when "psych"
- rm_rf(%w[ext/psych test/psych])
- cp_r("#{upstream}/ext/psych", "ext")
- cp_r("#{upstream}/lib", "ext/psych")
- cp_r("#{upstream}/test/psych", "test")
- rm_rf(%w[ext/psych/lib/org ext/psych/lib/psych.jar ext/psych/lib/psych_jars.rb])
- rm_rf(%w[ext/psych/lib/psych.{bundle,so} ext/psych/lib/2.*])
- rm_rf(["ext/psych/yaml/LICENSE"])
- cp_r("#{upstream}/psych.gemspec", "ext/psych")
- `git checkout ext/psych/depend ext/psych/.gitignore`
- when "stringio"
- rm_rf(%w[ext/stringio test/stringio])
- cp_r("#{upstream}/ext/stringio", "ext")
- cp_r("#{upstream}/test/stringio", "test")
- cp_r("#{upstream}/stringio.gemspec", "ext/stringio")
- `git checkout ext/stringio/depend ext/stringio/README.md`
- when "io-console"
- rm_rf(%w[ext/io/console test/io/console])
- cp_r("#{upstream}/ext/io/console", "ext/io")
- cp_r("#{upstream}/test/io/console", "test/io")
- mkdir_p("ext/io/console/lib")
- cp_r("#{upstream}/lib/io/console", "ext/io/console/lib")
- rm_rf("ext/io/console/lib/console/ffi")
- cp_r("#{upstream}/io-console.gemspec", "ext/io/console")
- `git checkout ext/io/console/depend`
- when "io-nonblock"
- rm_rf(%w[ext/io/nonblock test/io/nonblock])
- cp_r("#{upstream}/ext/io/nonblock", "ext/io")
- cp_r("#{upstream}/test/io/nonblock", "test/io")
- cp_r("#{upstream}/io-nonblock.gemspec", "ext/io/nonblock")
- `git checkout ext/io/nonblock/depend`
- when "io-wait"
- rm_rf(%w[ext/io/wait test/io/wait])
- cp_r("#{upstream}/ext/io/wait", "ext/io")
- cp_r("#{upstream}/test/io/wait", "test/io")
- cp_r("#{upstream}/io-wait.gemspec", "ext/io/wait")
- `git checkout ext/io/wait/depend`
- when "etc"
- rm_rf(%w[ext/etc test/etc])
- cp_r("#{upstream}/ext/etc", "ext")
- cp_r("#{upstream}/test/etc", "test")
- cp_r("#{upstream}/etc.gemspec", "ext/etc")
- `git checkout ext/etc/depend`
- when "date"
- rm_rf(%w[ext/date test/date])
- cp_r("#{upstream}/doc/date", "doc")
- cp_r("#{upstream}/ext/date", "ext")
- cp_r("#{upstream}/lib", "ext/date")
- cp_r("#{upstream}/test/date", "test")
- cp_r("#{upstream}/date.gemspec", "ext/date")
- `git checkout ext/date/depend`
- rm_rf(["ext/date/lib/date_core.bundle"])
- when "zlib"
- rm_rf(%w[ext/zlib test/zlib])
- cp_r("#{upstream}/ext/zlib", "ext")
- cp_r("#{upstream}/test/zlib", "test")
- cp_r("#{upstream}/zlib.gemspec", "ext/zlib")
- `git checkout ext/zlib/depend`
- when "fcntl"
- rm_rf(%w[ext/fcntl])
- cp_r("#{upstream}/ext/fcntl", "ext")
- cp_r("#{upstream}/fcntl.gemspec", "ext/fcntl")
- `git checkout ext/fcntl/depend`
- when "strscan"
- rm_rf(%w[ext/strscan test/strscan])
- cp_r("#{upstream}/ext/strscan", "ext")
- cp_r("#{upstream}/lib", "ext/strscan")
- cp_r("#{upstream}/test/strscan", "test")
- cp_r("#{upstream}/strscan.gemspec", "ext/strscan")
- begin
- cp_r("#{upstream}/doc/strscan", "doc")
- rescue Errno::ENOENT
+ end
+
+ porcelain_status().each do |line|
+ /\A(?:.)(?:.) (?<path>.*)\z/ =~ line or raise
+ if config.excluded?(path)
+ puts "Restoring excluded file: #{path}"
+ IO.popen(%W"git checkout --" + [path], "rb", &:read)
end
- rm_rf(%w["ext/strscan/regenc.h ext/strscan/regint.h"])
- `git checkout ext/strscan/depend`
- when "cgi"
- rm_rf(%w[lib/cgi.rb lib/cgi ext/cgi test/cgi])
- cp_r("#{upstream}/ext/cgi", "ext")
- cp_r("#{upstream}/lib/cgi", "lib")
- cp_r("#{upstream}/lib/cgi.rb", "lib")
- rm_rf("lib/cgi/escape.jar")
- cp_r("#{upstream}/test/cgi", "test")
- cp_r("#{upstream}/cgi.gemspec", "lib/cgi")
- `git checkout ext/cgi/escape/depend`
- when "openssl"
- rm_rf(%w[ext/openssl test/openssl])
- cp_r("#{upstream}/ext/openssl", "ext")
- cp_r("#{upstream}/lib", "ext/openssl")
- cp_r("#{upstream}/test/openssl", "test")
- rm_rf("test/openssl/envutil.rb")
- cp_r("#{upstream}/openssl.gemspec", "ext/openssl")
- cp_r("#{upstream}/History.md", "ext/openssl")
- `git checkout ext/openssl/depend`
- when "net-protocol"
- rm_rf(%w[lib/net/protocol.rb lib/net/net-protocol.gemspec test/net/protocol])
- cp_r("#{upstream}/lib/net/protocol.rb", "lib/net")
- cp_r("#{upstream}/test/net/protocol", "test/net")
- cp_r("#{upstream}/net-protocol.gemspec", "lib/net")
- when "net-http"
- rm_rf(%w[lib/net/http.rb lib/net/http test/net/http])
- cp_r("#{upstream}/lib/net/http.rb", "lib/net")
- cp_r("#{upstream}/lib/net/http", "lib/net")
- cp_r("#{upstream}/test/net/http", "test/net")
- cp_r("#{upstream}/net-http.gemspec", "lib/net/http")
- when "did_you_mean"
- rm_rf(%w[lib/did_you_mean lib/did_you_mean.rb test/did_you_mean])
- cp_r(Dir.glob("#{upstream}/lib/did_you_mean*"), "lib")
- cp_r("#{upstream}/did_you_mean.gemspec", "lib/did_you_mean")
- cp_r("#{upstream}/test", "test/did_you_mean")
- rm_rf("test/did_you_mean/lib")
- rm_rf(%w[test/did_you_mean/tree_spell/test_explore.rb])
- when "erb"
- rm_rf(%w[lib/erb* test/erb libexec/erb])
- cp_r("#{upstream}/lib/erb.rb", "lib")
- cp_r("#{upstream}/test/erb", "test")
- cp_r("#{upstream}/erb.gemspec", "lib")
- cp_r("#{upstream}/libexec/erb", "libexec")
- when "pathname"
- rm_rf(%w[ext/pathname test/pathname])
- cp_r("#{upstream}/ext/pathname", "ext")
- cp_r("#{upstream}/test/pathname", "test")
- cp_r("#{upstream}/lib", "ext/pathname")
- cp_r("#{upstream}/pathname.gemspec", "ext/pathname")
- `git checkout ext/pathname/depend`
- when "digest"
- rm_rf(%w[ext/digest test/digest])
- cp_r("#{upstream}/ext/digest", "ext")
- mkdir_p("ext/digest/lib/digest")
- cp_r("#{upstream}/lib/digest.rb", "ext/digest/lib/")
- cp_r("#{upstream}/lib/digest/version.rb", "ext/digest/lib/digest/")
- mkdir_p("ext/digest/sha2/lib")
- cp_r("#{upstream}/lib/digest/sha2.rb", "ext/digest/sha2/lib")
- move("ext/digest/lib/digest/sha2", "ext/digest/sha2/lib")
- cp_r("#{upstream}/test/digest", "test")
- cp_r("#{upstream}/digest.gemspec", "ext/digest")
- `git checkout ext/digest/depend ext/digest/*/depend`
- when "set"
- sync_lib gem, upstream
- cp_r(Dir.glob("#{upstream}/test/*"), "test/set")
- when "optparse"
- sync_lib gem, upstream
- rm_rf(%w[doc/optparse])
- mkdir_p("doc/optparse")
- cp_r("#{upstream}/doc/optparse", "doc")
- when "error_highlight"
- rm_rf(%w[lib/error_highlight lib/error_highlight.rb test/error_highlight])
- cp_r(Dir.glob("#{upstream}/lib/error_highlight*"), "lib")
- cp_r("#{upstream}/error_highlight.gemspec", "lib/error_highlight")
- cp_r("#{upstream}/test", "test/error_highlight")
- when "open3"
- sync_lib gem, upstream
- rm_rf("lib/open3/jruby_windows.rb")
- when "syntax_suggest"
- sync_lib gem, upstream
- rm_rf(%w[spec/syntax_suggest libexec/syntax_suggest])
- cp_r("#{upstream}/spec", "spec/syntax_suggest")
- cp_r("#{upstream}/exe/syntax_suggest", "libexec/syntax_suggest")
- when "prism"
- rm_rf(%w[test/prism prism])
-
- cp_r("#{upstream}/ext/prism", "prism")
- cp_r("#{upstream}/lib/.", "lib")
- cp_r("#{upstream}/test/prism", "test")
- cp_r("#{upstream}/src/.", "prism")
-
- cp_r("#{upstream}/prism.gemspec", "lib/prism")
- cp_r("#{upstream}/include/prism/.", "prism")
- cp_r("#{upstream}/include/prism.h", "prism")
-
- cp_r("#{upstream}/config.yml", "prism/")
- cp_r("#{upstream}/templates", "prism/")
- rm_rf("prism/templates/javascript")
- rm_rf("prism/templates/java")
- rm_rf("prism/templates/rbi")
- rm_rf("prism/templates/sig")
-
- rm("test/prism/snapshots_test.rb")
- rm_rf("test/prism/snapshots")
-
- rm("prism/extconf.rb")
- when "resolv"
- rm_rf(%w[lib/resolv.* ext/win32/resolv test/resolv ext/win32/lib/win32/resolv.rb])
- cp_r("#{upstream}/lib/resolv.rb", "lib")
- cp_r("#{upstream}/resolv.gemspec", "lib")
- cp_r("#{upstream}/ext/win32/resolv", "ext/win32")
- move("ext/win32/resolv/lib/resolv.rb", "ext/win32/lib/win32")
- rm_rf("ext/win32/resolv/lib") # Clean up empty directory
- cp_r("#{upstream}/test/resolv", "test")
- `git checkout ext/win32/resolv/depend`
- when "win32-registry"
- rm_rf(%w[ext/win32/lib/win32/registry.rb test/win32/test_registry.rb])
- cp_r("#{upstream}/lib/win32/registry.rb", "ext/win32/lib/win32")
- cp_r("#{upstream}/test/win32/test_registry.rb", "test/win32")
- cp_r("#{upstream}/win32-registry.gemspec", "ext/win32")
- when "mmtk"
- rm_rf("gc/mmtk")
- cp_r("#{upstream}/gc/mmtk", "gc")
- else
- sync_lib gem, upstream
+ end
+
+ # RubyGems/Bundler needs special care
+ if gem == "rubygems"
+ rubygems_do_fixup
end
check_prerelease_version(gem)
@@ -362,16 +437,13 @@ module SyncDefaultGems
end
def check_prerelease_version(gem)
- return if gem == "rubygems"
- return if gem == "mmtk"
-
- gem = gem.downcase
+ return if ["rubygems", "mmtk", "Onigmo"].include?(gem)
require "net/https"
require "json"
require "uri"
- uri = URI("https://rubygems.org/api/v1/versions/#{gem}/latest.json")
+ uri = URI("https://rubygems.org/api/v1/versions/#{gem.downcase}/latest.json")
response = Net::HTTP.get(uri)
latest_version = JSON.parse(response)["version"]
@@ -388,42 +460,19 @@ module SyncDefaultGems
puts "#{gem}-#{spec.version} is not latest version of rubygems.org" if spec.version.to_s != latest_version
end
- def ignore_file_pattern_for(gem)
- patterns = []
-
- # Common patterns
- patterns << %r[\A(?:
- [^/]+ # top-level entries
- |\.git.*
- |bin/.*
- |ext/.*\.java
- |rakelib/.*
- |test/(?:lib|fixtures)/.*
- |tool/(?!bundler/).*
- )\z]mx
-
- # Gem-specific patterns
- case gem
- when nil
- end&.tap do |pattern|
- patterns << pattern
- end
-
- Regexp.union(*patterns)
- end
-
- def message_filter(repo, sha, input: ARGF)
+ def message_filter(repo, sha, log, context: nil)
unless repo.count("/") == 1 and /\A\S+\z/ =~ repo
raise ArgumentError, "invalid repository: #{repo}"
end
unless /\A\h{10,40}\z/ =~ sha
raise ArgumentError, "invalid commit-hash: #{sha}"
end
- log = input.read
- log.delete!("\r")
- log << "\n" if !log.end_with?("\n")
repo_url = "https://github.com/#{repo}"
+ # Log messages generated by GitHub web UI have inconsistent line endings
+ log = log.delete("\r")
+ log << "\n" if !log.end_with?("\n")
+
# Split the subject from the log message according to git conventions.
# SPECIAL TREAT: when the first line ends with a dot `.` (which is not
# obeying the conventions too), takes only that line.
@@ -445,41 +494,69 @@ module SyncDefaultGems
end
end
commit_url = "#{repo_url}/commit/#{sha[0,10]}\n"
+ sync_note = context ? "#{commit_url}\n#{context}" : commit_url
if log and !log.empty?
log.sub!(/(?<=\n)\n+\z/, '') # drop empty lines at the last
conv[log]
log.sub!(/(?:(\A\s*)|\s*\n)(?=((?i:^Co-authored-by:.*\n?)+)?\Z)/) {
- ($~.begin(1) ? "" : "\n\n") + commit_url + ($~.begin(2) ? "\n" : "")
+ ($~.begin(1) ? "" : "\n\n") + sync_note + ($~.begin(2) ? "\n" : "")
}
else
- log = commit_url
+ log = sync_note
end
- puts subject, "\n", log
+ "#{subject}\n\n#{log}"
end
- # Returns commit list as array of [commit_hash, subject].
- def commits_in_ranges(gem, repo, default_branch, ranges)
- # If -a is given, discover all commits since the last picked commit
- if ranges == true
- # \r? needed in the regex in case the commit has windows-style line endings (because e.g. we're running
- # tests on Windows)
- pattern = "https://github\.com/#{Regexp.quote(repo)}/commit/([0-9a-f]+)\r?$"
- log = IO.popen(%W"git log -E --grep=#{pattern} -n1 --format=%B", "rb", &:read)
- ranges = ["#{log[%r[#{pattern}\n\s*(?i:co-authored-by:.*)*\s*\Z], 1]}..#{gem}/#{default_branch}"]
- end
+ def log_format(format, args, &block)
+ IO.popen(%W[git -c core.autocrlf=false -c core.eol=lf
+ log --no-show-signature --format=#{format}] + args, "rb", &block)
+ end
- # Parse a given range with git log
- ranges.flat_map do |range|
- unless range.include?("..")
- range = "#{range}~1..#{range}"
- end
+ def commits_in_range(upto, exclude, toplevel:)
+ args = [upto, *exclude.map {|s|"^#{s}"}]
+ log_format('%H,%P,%s', %W"--first-parent" + args) do |f|
+ f.read.split("\n").reverse.flat_map {|commit|
+ hash, parents, subject = commit.split(',', 3)
+ parents = parents.split
+
+ # Non-merge commit
+ if parents.size <= 1
+ puts "#{hash} #{subject}"
+ next [[hash, subject]]
+ end
- IO.popen(%W"git log --format=%H,%s #{range} --", "rb") do |f|
- f.read.split("\n").reverse.map{|commit| commit.split(',', 2)}
- end
+ # Clean 2-parent merge commit: follow the other parent as long as it
+ # contains no potentially-non-clean merges
+ if parents.size == 2 &&
+ IO.popen(%W"git diff-tree --remerge-diff #{hash}", "rb", &:read).empty?
+ puts "\e[2mChecking the other parent of #{hash} #{subject}\e[0m"
+ ret = catch(:quit) {
+ commits_in_range(parents[1], exclude + [parents[0]], toplevel: false)
+ }
+ next ret if ret
+ end
+
+ unless toplevel
+ puts "\e[1mMerge commit with possible conflict resolution #{hash} #{subject}\e[0m"
+ throw :quit
+ end
+
+ puts "#{hash} #{subject} " \
+ "\e[1m[merge commit with possible conflicts, will do a squash merge]\e[0m"
+ [[hash, subject]]
+ }
end
end
+ # Returns commit list as array of [commit_hash, subject, sync_note].
+ def commits_in_ranges(ranges)
+ ranges.flat_map do |range|
+ exclude, upto = range.include?("..") ? range.split("..", 2) : ["#{range}~1", range]
+ puts "Looking for commits in range #{exclude}..#{upto}"
+ commits_in_range(upto, exclude.empty? ? [] : [exclude], toplevel: true)
+ end.uniq
+ end
+
#--
# Following methods used by sync_default_gems_with_commits return
# true: success
@@ -488,27 +565,9 @@ module SyncDefaultGems
#++
def resolve_conflicts(gem, sha, edit)
- # Skip this commit if everything has been removed as `ignored_paths`.
- changes = pipe_readlines(%W"git status --porcelain -z")
- if changes.empty?
- puts "Skip empty commit #{sha}"
- return false
- end
-
- # We want to skip DD: deleted by both.
- deleted = changes.grep(/^DD /) {$'}
- system(*%W"git rm -f --", *deleted) unless deleted.empty?
-
- # Import UA: added by them
- added = changes.grep(/^UA /) {$'}
- system(*%W"git add --", *added) unless added.empty?
-
- # Discover unmerged files
- # AU: unmerged, added by us
- # DU: unmerged, deleted by us
- # UU: unmerged, both modified
- # AA: unmerged, both added
- conflict = changes.grep(/\A(?:.U|AA) /) {$'}
+ # Discover unmerged files: any unstaged changes
+ changes = porcelain_status()
+ conflict = changes.grep(/\A(?:.[^ ?]) /) {$'}
# If -e option is given, open each conflicted file with an editor
unless conflict.empty?
if edit
@@ -529,123 +588,170 @@ module SyncDefaultGems
return true
end
- def preexisting?(base, file)
- system(*%w"git cat-file -e", "#{base}:#{file}", err: File::NULL)
+ def collect_cacheinfo(tree)
+ pipe_readlines(%W"git ls-tree -r -t -z #{tree}").filter_map do |line|
+ fields, path = line.split("\t", 2)
+ mode, type, object = fields.split(" ", 3)
+ next unless type == "blob"
+ [mode, type, object, path]
+ end
end
- def filter_pickup_files(changed, ignore_file_pattern, base)
- toplevels = {}
- remove = []
- ignore = []
- changed = changed.reject do |f|
- case
- when toplevels.fetch(top = f[%r[\A[^/]+(?=/|\z)]m]) {
- remove << top if toplevels[top] = !preexisting?(base, top)
- }
- # Remove any new top-level directories.
- true
- when ignore_file_pattern.match?(f)
- # Forcibly reset any changes matching ignore_file_pattern.
- (preexisting?(base, f) ? ignore : remove) << f
- end
+ def rewrite_cacheinfo(gem, blobs)
+ config = REPOSITORIES[gem]
+ rewritten = []
+ ignored = blobs.dup
+ ignored.delete_if do |mode, type, object, path|
+ newpath = config.rewrite_for_ruby(path)
+ next unless newpath
+ rewritten << [mode, type, object, newpath]
end
- return changed, remove, ignore
+ [rewritten, ignored]
end
- def pickup_files(gem, changed, picked)
- # Forcibly remove any files that we don't want to copy to this
- # repository.
-
- ignore_file_pattern = ignore_file_pattern_for(gem)
+ def make_commit_info(gem, sha)
+ config = REPOSITORIES[gem]
+ headers, orig = IO.popen(%W[git cat-file commit #{sha}], "rb", &:read).split("\n\n", 2)
+ /^author (?<author_name>.+?) <(?<author_email>.*?)> (?<author_date>.+?)$/ =~ headers or
+ raise "unable to parse author info for commit #{sha}"
+ author = {
+ "GIT_AUTHOR_NAME" => author_name,
+ "GIT_AUTHOR_EMAIL" => author_email,
+ "GIT_AUTHOR_DATE" => author_date,
+ }
+ context = nil
+ if /^parent (?<first_parent>.{40})\nparent .{40}$/ =~ headers
+ # Squashing a merge commit: keep authorship information
+ context = IO.popen(%W"git shortlog #{first_parent}..#{sha} --", "rb", &:read)
+ end
+ message = message_filter(config.upstream, sha, orig, context: context)
+ [author, message]
+ end
- base = picked ? "HEAD~" : "HEAD"
- changed, remove, ignore = filter_pickup_files(changed, ignore_file_pattern, base)
+ def fixup_commit(gem, commit)
+ wt = File.join("tmp", "sync_default_gems-fixup-worktree")
+ if File.directory?(wt)
+ IO.popen(%W"git -C #{wt} clean -xdf", "rb", &:read)
+ IO.popen(%W"git -C #{wt} reset --hard #{commit}", "rb", &:read)
+ else
+ IO.popen(%W"git worktree remove --force #{wt}", "rb", err: File::NULL, &:read)
+ IO.popen(%W"git worktree add --detach #{wt} #{commit}", "rb", &:read)
+ end
+ raise "git worktree prepare failed for commit #{commit}" unless $?.success?
- unless remove.empty?
- puts "Remove added files: #{remove.join(', ')}"
- system(*%w"git rm -fr --", *remove)
- if picked
- system(*%w"git commit --amend --no-edit --", *remove, %i[out err] => File::NULL)
+ Dir.chdir(wt) do
+ if gem == "rubygems"
+ rubygems_do_fixup
end
+ replace_rdoc_ref_all_full
end
- unless ignore.empty?
- puts "Reset ignored files: #{ignore.join(', ')}"
- system(*%W"git rm -r --", *ignore)
- ignore.each {|f| system(*%W"git checkout -f", base, "--", f)}
- end
+ IO.popen(%W"git -C #{wt} add -u", "rb", &:read)
+ IO.popen(%W"git -C #{wt} commit --amend --no-edit", "rb", &:read)
+ IO.popen(%W"git -C #{wt} rev-parse HEAD", "rb", &:read).chomp
+ end
+
+ def make_and_fixup_commit(gem, original_commit, cacheinfo, parent: nil, message: nil, author: nil)
+ tree = Tempfile.create("sync_default_gems-#{gem}-index") do |f|
+ File.unlink(f.path)
+ IO.popen({"GIT_INDEX_FILE" => f.path},
+ %W"git update-index --index-info", "wb", out: IO::NULL) do |io|
+ cacheinfo.each do |mode, type, object, path|
+ io.puts("#{mode} #{type} #{object}\t#{path}")
+ end
+ end
+ raise "git update-index failed" unless $?.success?
- if changed.empty?
- return nil
+ IO.popen({"GIT_INDEX_FILE" => f.path}, %W"git write-tree --missing-ok", "rb", &:read).chomp
end
- return changed
+ args = ["-m", message || "Rewriten commit for #{original_commit}"]
+ args += ["-p", parent] if parent
+ commit = IO.popen({**author}, %W"git commit-tree #{tree}" + args, "rb", &:read).chomp
+
+ # Apply changes that require a working tree
+ commit = fixup_commit(gem, commit)
+
+ commit
end
- def pickup_commit(gem, sha, edit)
- # Attempt to cherry-pick a commit
- result = IO.popen(%W"git cherry-pick #{sha}", "rb", &:read)
- picked = $?.success?
- if result =~ /nothing\ to\ commit/
- `git reset`
- puts "Skip empty commit #{sha}"
+ def rewrite_commit(gem, sha)
+ author, message = make_commit_info(gem, sha)
+ new_blobs = collect_cacheinfo("#{sha}")
+ new_rewritten, new_ignored = rewrite_cacheinfo(gem, new_blobs)
+
+ headers, _ = IO.popen(%W[git cat-file commit #{sha}], "rb", &:read).split("\n\n", 2)
+ first_parent = headers[/^parent (.{40})$/, 1]
+ unless first_parent
+ # Root commit, first time to sync this repo
+ return make_and_fixup_commit(gem, sha, new_rewritten, message: message, author: author)
+ end
+
+ old_blobs = collect_cacheinfo(first_parent)
+ old_rewritten, old_ignored = rewrite_cacheinfo(gem, old_blobs)
+ if old_ignored != new_ignored
+ paths = (old_ignored + new_ignored - (old_ignored & new_ignored))
+ .map {|*_, path| path}.uniq
+ puts "\e\[1mIgnoring file changes not in mappings: #{paths.join(" ")}\e\[0m"
+ end
+ changed_paths = (old_rewritten + new_rewritten - (old_rewritten & new_rewritten))
+ .map {|*_, path| path}.uniq
+ if changed_paths.empty?
+ puts "Skip commit only for tools or toplevel"
return false
end
- # Skip empty commits
- if result.empty?
- return false
- end
+ # Build commit objects from "cacheinfo"
+ new_parent = make_and_fixup_commit(gem, first_parent, old_rewritten)
+ new_commit = make_and_fixup_commit(gem, sha, new_rewritten, parent: new_parent, message: message, author: author)
+ puts "Created a temporary commit for cherry-pick: #{new_commit}"
+ new_commit
+ end
- if picked
- changed = pipe_readlines(%w"git diff-tree --name-only -r -z HEAD~..HEAD --")
- else
- changed = pipe_readlines(%w"git diff --name-only -r -z HEAD --")
- end
+ def pickup_commit(gem, sha, edit)
+ rewritten = rewrite_commit(gem, sha)
- # Pick up files to merge.
- unless changed = pickup_files(gem, changed, picked)
- puts "Skip commit #{sha} only for tools or toplevel"
- if picked
- `git reset --hard HEAD~`
- else
- `git cherry-pick --abort`
- end
- return false
- end
+ # No changes remaining after rewriting
+ return false unless rewritten
- # If the cherry-pick attempt failed, try to resolve conflicts.
- # Skip the commit, if it contains unresolved conflicts or no files to pick up.
- unless picked or resolve_conflicts(gem, sha, edit)
- `git reset` && `git checkout .` && `git clean -fd`
- return picked || nil # Fail unless cherry-picked
- end
+ # Attempt to cherry-pick a commit
+ result = IO.popen(%W"git cherry-pick #{rewritten}", "rb", err: [:child, :out], &:read)
+ unless $?.success?
+ if result =~ /The previous cherry-pick is now empty/
+ system(*%w"git cherry-pick --skip")
+ puts "Skip empty commit #{sha}"
+ return false
+ end
- # Commit cherry-picked commit
- if picked
- system(*%w"git commit --amend --no-edit")
- else
- system(*%w"git cherry-pick --continue --no-edit")
- end or return nil
+ # If the cherry-pick attempt failed, try to resolve conflicts.
+ # Skip the commit, if it contains unresolved conflicts or no files to pick up.
+ unless resolve_conflicts(gem, sha, edit)
+ system(*%w"git --no-pager diff") if !edit # If failed, show `git diff` unless editing
+ `git reset` && `git checkout .` && `git clean -fd` # Clean up un-committed diffs
+ return nil # Fail unless cherry-picked
+ end
- # Amend the commit if RDoc references need to be replaced
- head = `git log --format=%H -1 HEAD`.chomp
- system(*%w"git reset --quiet HEAD~ --")
- amend = replace_rdoc_ref_all
- system(*%W"git reset --quiet #{head} --")
- if amend
- `git commit --amend --no-edit --all`
+ # Commit cherry-picked commit
+ if porcelain_status().empty?
+ system(*%w"git cherry-pick --skip")
+ return false
+ else
+ system(*%w"git cherry-pick --continue --no-edit")
+ return nil unless $?.success?
+ end
end
+ new_head = IO.popen(%W"git rev-parse HEAD", "rb", &:read).chomp
+ puts "Committed cherry-pick as #{new_head}"
return true
end
- # NOTE: This method is also used by GitHub ruby/git.ruby-lang.org's bin/update-default-gem.sh
# @param gem [String] A gem name, also used as a git remote name. REPOSITORIES converts it to the appropriate GitHub repository.
- # @param ranges [Array<String>] "before..after". Note that it will NOT sync "before" (but commits after that).
+ # @param ranges [Array<String>, true] "commit", "before..after", or true. Note that it will NOT sync "before" (but commits after that).
# @param edit [TrueClass] Set true if you want to resolve conflicts. Obviously, update-default-gem.sh doesn't use this.
def sync_default_gems_with_commits(gem, ranges, edit: nil)
- repo, default_branch = REPOSITORIES[gem]
+ config = REPOSITORIES[gem]
+ repo, default_branch = config.upstream, config.branch
puts "Sync #{repo} with commit history."
# Fetch the repository to be synchronized
@@ -654,86 +760,46 @@ module SyncDefaultGems
`git remote add #{gem} https://github.com/#{repo}.git`
end
end
- system(*%W"git fetch --no-tags #{gem}")
-
- commits = commits_in_ranges(gem, repo, default_branch, ranges)
+ system(*%W"git fetch --no-tags --depth=#{FETCH_DEPTH} #{gem} #{default_branch}")
- # Ignore Merge commits and already-merged commits.
- commits.delete_if do |sha, subject|
- subject.start_with?("Merge", "Auto Merge")
+ # If -a is given, discover all commits since the last picked commit
+ if ranges == true
+ pattern = "https://github\.com/#{Regexp.quote(repo)}/commit/([0-9a-f]+)$"
+ log = log_format('%B', %W"-E --grep=#{pattern} -n1 --", &:read)
+ ranges = ["#{log[%r[#{pattern}\n\s*(?i:co-authored-by:.*)*\s*\Z], 1]}..#{gem}/#{default_branch}"]
end
-
+ commits = commits_in_ranges(ranges)
if commits.empty?
puts "No commits to pick"
return true
end
- puts "Try to pick these commits:"
- puts commits.map{|commit| commit.join(": ")}
- puts "----"
-
failed_commits = []
-
- require 'shellwords'
- filter = [
- ENV.fetch('RUBY', 'ruby').shellescape,
- File.realpath(__FILE__).shellescape,
- "--message-filter",
- ]
commits.each do |sha, subject|
- puts "Pick #{sha} from #{repo}."
+ puts "----"
+ puts "Pick #{sha} #{subject}"
case pickup_commit(gem, sha, edit)
when false
- next
+ # skipped
when nil
- failed_commits << sha
- next
- end
-
- puts "Update commit message: #{sha}"
-
- # Run this script itself (tool/sync_default_gems.rb --message-filter) as a message filter
- IO.popen({"FILTER_BRANCH_SQUELCH_WARNING" => "1"},
- %W[git filter-branch -f --msg-filter #{[filter, repo, sha].join(' ')} -- HEAD~1..HEAD],
- &:read)
- unless $?.success?
- puts "Failed to modify commit message of #{sha}"
- break
+ failed_commits << [sha, subject]
end
end
unless failed_commits.empty?
puts "---- failed commits ----"
- puts failed_commits
+ failed_commits.each do |sha, subject|
+ puts "#{sha} #{subject}"
+ end
return false
end
return true
end
- def sync_lib(repo, upstream = nil)
- unless upstream and File.directory?(upstream) or File.directory?(upstream = "../#{repo}")
- abort %[Expected '#{upstream}' \(#{File.expand_path("#{upstream}")}\) to be a directory, but it wasn't.]
- end
- rm_rf(["lib/#{repo}.rb", "lib/#{repo}/*", "test/test_#{repo}.rb"])
- cp_r(Dir.glob("#{upstream}/lib/*"), "lib")
- tests = if File.directory?("test/#{repo}")
- "test/#{repo}"
- else
- "test/test_#{repo}.rb"
- end
- cp_r("#{upstream}/#{tests}", "test") if File.exist?("#{upstream}/#{tests}")
- gemspec = if File.directory?("lib/#{repo}")
- "lib/#{repo}/#{repo}.gemspec"
- else
- "lib/#{repo}.gemspec"
- end
- cp_r("#{upstream}/#{repo}.gemspec", "#{gemspec}")
- end
-
def update_default_gems(gem, release: false)
-
- repository, default_branch = REPOSITORIES[gem]
- author, repository = repository.split('/')
+ config = REPOSITORIES[gem]
+ author, repository = config.upstream.split('/')
+ default_branch = config.branch
puts "Update #{author}/#{repository}"
@@ -773,28 +839,18 @@ module SyncDefaultGems
REPOSITORIES.each_key {|gem| update_default_gems(gem)}
end
when "all"
- if ARGV[1] == "release"
- REPOSITORIES.each_key do |gem|
- update_default_gems(gem, release: true)
- sync_default_gems(gem)
- end
- else
- REPOSITORIES.each_key {|gem| sync_default_gems(gem)}
+ REPOSITORIES.each_key do |gem|
+ next if ["Onigmo"].include?(gem)
+ update_default_gems(gem, release: true) if ARGV[1] == "release"
+ sync_default_gems(gem)
end
when "list"
ARGV.shift
pattern = Regexp.new(ARGV.join('|'))
- REPOSITORIES.each_pair do |name, (gem)|
- next unless pattern =~ name or pattern =~ gem
- printf "%-15s https://github.com/%s\n", name, gem
- end
- when "--message-filter"
- ARGV.shift
- if ARGV.size < 2
- abort "usage: #{$0} --message-filter repository commit-hash [input...]"
+ REPOSITORIES.each do |gem, config|
+ next unless pattern =~ gem or pattern =~ config.upstream
+ printf "%-15s https://github.com/%s\n", gem, config.upstream
end
- message_filter(*ARGV.shift(2))
- exit
when "rdoc-ref"
ARGV.shift
pattern = ARGV.empty? ? %w[*.c *.rb *.rdoc] : ARGV
@@ -810,7 +866,13 @@ module SyncDefaultGems
puts <<-HELP
\e[1mSync with upstream code of default libraries\e[0m
-\e[1mImport a default library through `git clone` and `cp -rf` (git commits are lost)\e[0m
+\e[1mImport all default gems through `git clone` and `cp -rf` (git commits are lost)\e[0m
+ ruby #$0 all
+
+\e[1mImport all released version of default gems\e[0m
+ ruby #$0 all release
+
+\e[1mImport a default gem with specific gem same as all command\e[0m
ruby #$0 rubygems
\e[1mPick a single commit from the upstream repository\e[0m
@@ -822,6 +884,9 @@ module SyncDefaultGems
\e[1mPick all commits since the last picked commit\e[0m
ruby #$0 -a rubygems
+\e[1mUpdate repositories of default gems\e[0m
+ ruby #$0 up
+
\e[1mList known libraries\e[0m
ruby #$0 list
diff --git a/tool/test-bundled-gems.rb b/tool/test-bundled-gems.rb
index 535d101d48..b603cc09d7 100644
--- a/tool/test-bundled-gems.rb
+++ b/tool/test-bundled-gems.rb
@@ -1,37 +1,57 @@
require 'rbconfig'
require 'timeout'
require 'fileutils'
+require 'shellwords'
+require 'etc'
require_relative 'lib/colorize'
require_relative 'lib/gem_env'
+require_relative 'lib/test/jobserver'
ENV.delete("GNUMAKEFLAGS")
github_actions = ENV["GITHUB_ACTIONS"] == "true"
+DEFAULT_ALLOWED_FAILURES = RUBY_PLATFORM =~ /mswin|mingw/ ? [
+ 'debug',
+ 'irb',
+ 'csv',
+] : []
allowed_failures = ENV['TEST_BUNDLED_GEMS_ALLOW_FAILURES'] || ''
-if RUBY_PLATFORM =~ /mswin|mingw/
- allowed_failures = [allowed_failures, "rbs,debug,irb"].join(',')
-end
-allowed_failures = allowed_failures.split(',').uniq.reject(&:empty?)
+allowed_failures = allowed_failures.split(',').concat(DEFAULT_ALLOWED_FAILURES).uniq.reject(&:empty?)
# make test-bundled-gems BUNDLED_GEMS=gem1,gem2,gem3
-bundled_gems = ARGV.first || ''
+bundled_gems = nil if (bundled_gems = ARGV.first&.split(","))&.empty?
colorize = Colorize.new
rake = File.realpath("../../.bundle/bin/rake", __FILE__)
gem_dir = File.realpath('../../gems', __FILE__)
rubylib = [gem_dir+'/lib', ENV["RUBYLIB"]].compact.join(File::PATH_SEPARATOR)
+run_opts = ENV["RUN_OPTS"]&.shellsplit
exit_code = 0
ruby = ENV['RUBY'] || RbConfig.ruby
failed = []
+
+max = ENV['TEST_BUNDLED_GEMS_NPROCS']&.to_i || [Etc.nprocessors, 8].min
+nprocs = Test::JobServer.max_jobs(max) || max
+nprocs = 1 if nprocs < 1
+
+if /mingw|mswin/ =~ RUBY_PLATFORM
+ spawn_group = :new_pgroup
+ signal_prefix = ""
+else
+ spawn_group = :pgroup
+ signal_prefix = "-"
+end
+
+jobs = []
File.foreach("#{gem_dir}/bundled_gems") do |line|
- next if /^\s*(?:#|$)/ =~ line
- gem = line.split.first
- next unless bundled_gems.empty? || bundled_gems.split(",").include?(gem)
+ next unless gem = line[/^[^\s\#]+/]
+ next if bundled_gems&.none? {|pat| File.fnmatch?(pat, gem)}
next unless File.directory?("#{gem_dir}/src/#{gem}/test")
- test_command = "#{ruby} -C #{gem_dir}/src/#{gem} #{rake} test"
+ test_command = [ruby, *run_opts, "-C", "#{gem_dir}/src/#{gem}", rake, "test"]
first_timeout = 600 # 10min
+ env_rubylib = rubylib
toplib = gem
unless File.exist?("#{gem_dir}/src/#{gem}/lib/#{toplib}.rb")
@@ -50,68 +70,174 @@ File.foreach("#{gem_dir}/bundled_gems") do |line|
File.unlink(path) if File.exist?(path)
end
- test_command << " stdlib_test validate RBS_SKIP_TESTS=#{__dir__}/rbs_skip_tests SKIP_RBS_VALIDATION=true"
+ rbs_skip_tests = [
+ File.join(__dir__, "/rbs_skip_tests")
+ ]
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ rbs_skip_tests << File.join(__dir__, "/rbs_skip_tests_windows")
+ end
+
+ test_command.concat %W[stdlib_test validate RBS_SKIP_TESTS=#{rbs_skip_tests.join(File::PATH_SEPARATOR)} SKIP_RBS_VALIDATION=true]
first_timeout *= 3
when "debug"
# Since debug gem requires debug.so in child processes without
# activating the gem, we preset necessary paths in RUBYLIB
# environment variable.
- load_path = true
+ libs = IO.popen([ruby, "-e", "old = $:.dup; require '#{toplib}'; puts $:-old"], &:read)
+ next unless $?.success?
+ env_rubylib = [libs.split("\n"), rubylib].join(File::PATH_SEPARATOR)
when "test-unit"
- test_command = "#{ruby} -C #{gem_dir}/src/#{gem} test/run-test.rb"
+ test_command = [ruby, *run_opts, "-C", "#{gem_dir}/src/#{gem}", "test/run.rb"]
+
+ when "csv"
+ first_timeout = 30
when "win32ole"
next unless /mswin|mingw/ =~ RUBY_PLATFORM
end
- if load_path
- libs = IO.popen([ruby, "-e", "old = $:.dup; require '#{toplib}'; puts $:-old"], &:read)
- next unless $?.success?
- ENV["RUBYLIB"] = [libs.split("\n"), rubylib].join(File::PATH_SEPARATOR)
- else
- ENV["RUBYLIB"] = rubylib
+ jobs << {
+ gem: gem,
+ test_command: test_command,
+ first_timeout: first_timeout,
+ rubylib: env_rubylib,
+ }
+end
+
+running_pids = []
+interrupted = false
+
+trap(:INT) do
+ interrupted = true
+ running_pids.each do |pid|
+ Process.kill("#{signal_prefix}INT", pid) rescue nil
end
+end
- # 93(bright yellow) is copied from .github/workflows/mingw.yml
- puts "#{github_actions ? "::group::\e\[93m" : "\n"}Testing the #{gem} gem#{github_actions ? "\e\[m" : ""}"
- print "[command]" if github_actions
- puts test_command
- pid = Process.spawn(test_command, "#{/mingw|mswin/ =~ RUBY_PLATFORM ? 'new_' : ''}pgroup": true)
- {nil => first_timeout, INT: 30, TERM: 10, KILL: nil}.each do |sig, sec|
- if sig
- puts "Sending #{sig} signal"
- Process.kill("-#{sig}", pid)
- end
- begin
- break Timeout.timeout(sec) {Process.wait(pid)}
- rescue Timeout::Error
+results = Array.new(jobs.size)
+queue = Queue.new
+jobs.each_with_index { |j, i| queue << [j, i] }
+nprocs.times { queue << nil }
+print_queue = Queue.new
+
+puts "Running #{jobs.size} gem tests with #{nprocs} workers..."
+
+printer = Thread.new do
+ printed = 0
+ while printed < jobs.size
+ result = print_queue.pop
+ break if result.nil?
+
+ gem = result[:gem]
+ elapsed = result[:elapsed]
+ status = result[:status]
+ t = " in %.6f sec" % elapsed
+
+ print (github_actions ? "::group::" : "\n")
+ puts colorize.decorate("Testing the #{gem} gem", "note")
+ print "[command]" if github_actions
+ p result[:test_command]
+ result[:log_lines].each { |l| puts l }
+ print result[:output]
+ print "::endgroup::\n" if github_actions
+
+ if status&.success?
+ puts colorize.decorate("Test passed#{t}", "pass")
+ else
+ mesg = "Tests failed " +
+ (status&.signaled? ? "by SIG#{Signal.signame(status.termsig)}" :
+ "with exit code #{status&.exitstatus}") + t
+ puts colorize.decorate(mesg, "fail")
+ if allowed_failures.include?(gem)
+ mesg = "Ignoring test failures for #{gem} due to \$TEST_BUNDLED_GEMS_ALLOW_FAILURES or DEFAULT_ALLOWED_FAILURES"
+ puts colorize.decorate(mesg, "skip")
+ else
+ failed << gem
+ exit_code = 1
+ end
end
- rescue Interrupt
- exit_code = Signal.list["INT"]
- Process.kill("-KILL", pid)
- Process.wait(pid)
- break
- end
- print "::endgroup::\n" if github_actions
- unless $?.success?
+ printed += 1
+ end
+end
- mesg = "Tests failed " +
- ($?.signaled? ? "by SIG#{Signal.signame($?.termsig)}" :
- "with exit code #{$?.exitstatus}")
- puts colorize.decorate(mesg, "fail")
- if allowed_failures.include?(gem)
- mesg = "Ignoring test failures for #{gem} due to \$TEST_BUNDLED_GEMS_ALLOW_FAILURES"
- puts colorize.decorate(mesg, "skip")
- else
- failed << gem
- exit_code = $?.exitstatus if $?.exitstatus
+threads = nprocs.times.map do
+ Thread.new do
+ while (item = queue.pop)
+ break if interrupted
+ job, index = item
+
+ start_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ rd, wr = IO.pipe
+ env = { "RUBYLIB" => job[:rubylib] }
+ pid = Process.spawn(env, *job[:test_command], spawn_group => true, [:out, :err] => wr)
+ wr.close
+ running_pids << pid
+ output_thread = Thread.new { rd.read }
+
+ timeouts = { nil => job[:first_timeout], INT: 30, TERM: 10, KILL: nil }
+ if /mingw|mswin/ =~ RUBY_PLATFORM
+ timeouts.delete(:TERM)
+ end
+
+ log_lines = []
+ status = nil
+ timeouts.each do |sig, sec|
+ if sig
+ log_lines << "Sending #{sig} signal"
+ begin
+ Process.kill("#{signal_prefix}#{sig}", pid)
+ rescue Errno::ESRCH
+ _, status = Process.wait2(pid) unless status
+ break
+ end
+ end
+ begin
+ break Timeout.timeout(sec) { _, status = Process.wait2(pid) }
+ rescue Timeout::Error
+ end
+ end
+
+ captured = output_thread.value
+ rd.close
+ running_pids.delete(pid)
+
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_at
+
+ result = {
+ gem: job[:gem],
+ test_command: job[:test_command],
+ status: status,
+ elapsed: elapsed,
+ output: captured,
+ log_lines: log_lines,
+ }
+ results[index] = result
+ print_queue << result
end
end
end
-puts "Failed gems: #{failed.join(', ')}" unless failed.empty?
+threads.each(&:join)
+print_queue << nil
+printer.join
+
+if interrupted
+ exit Signal.list["INT"]
+end
+
+unless failed.empty?
+ puts "\n#{colorize.decorate("Failed gems: #{failed.join(', ')}", "fail")}"
+ results.compact.each do |result|
+ next if result[:status]&.success?
+ next if allowed_failures.include?(result[:gem])
+ puts colorize.decorate("\nTesting the #{result[:gem]} gem", "note")
+ print result[:output]
+ end
+end
exit exit_code
diff --git a/tool/test-coverage.rb b/tool/test-coverage.rb
index 055577feea..28ef0bf7f8 100644
--- a/tool/test-coverage.rb
+++ b/tool/test-coverage.rb
@@ -114,6 +114,10 @@ pid = $$
pwd = Dir.pwd
at_exit do
+ # Some tests leave GC.stress enabled, causing slow coverage processing.
+ # Reset it here to avoid performance issues.
+ GC.stress = false
+
exit_exc = $!
Dir.chdir(pwd) do
diff --git a/tool/test/init.rb b/tool/test/init.rb
index 3a1143d01d..3fd1419a9c 100644
--- a/tool/test/init.rb
+++ b/tool/test/init.rb
@@ -1,7 +1,15 @@
-# This file includes the settings for "make test-all".
+# This file includes the settings for "make test-all" and "make test-tool".
# Note that this file is loaded not only by test/runner.rb but also by tool/lib/test/unit/parallel.rb.
-ENV["GEM_SKIP"] = ENV["GEM_HOME"] = ENV["GEM_PATH"] = "".freeze
+# Prevent test-all from using bundled gems
+["GEM_HOME", "GEM_PATH"].each do |gem_env|
+ # Preserve the gem environment prepared by tool/runruby.rb for test-tool, which uses bundled gems.
+ ENV["BUNDLED_#{gem_env}"] = ENV[gem_env]
+
+ ENV[gem_env] = "".freeze
+end
+ENV["GEM_SKIP"] = "".freeze
+
ENV.delete("RUBY_CODESIGN")
Warning[:experimental] = false
diff --git a/tool/test/test_commit_email.rb b/tool/test/test_commit_email.rb
new file mode 100644
index 0000000000..db441584fd
--- /dev/null
+++ b/tool/test/test_commit_email.rb
@@ -0,0 +1,102 @@
+require 'test/unit'
+require 'shellwords'
+require 'tmpdir'
+require 'fileutils'
+require 'open3'
+
+class TestCommitEmail < Test::Unit::TestCase
+ STDIN_DELIMITER = "---\n"
+
+ def setup
+ omit 'git command is not available' unless system('git', '--version', out: File::NULL, err: File::NULL)
+
+ @ruby = Dir.mktmpdir
+ Dir.chdir(@ruby) do
+ git('init', '--initial-branch=master')
+ git('config', 'user.name', 'Jóhän Grübél')
+ git('config', 'user.email', 'johan@example.com')
+ env = {
+ 'GIT_AUTHOR_DATE' => '2025-10-08T12:00:00Z',
+ 'GIT_CONFIG_GLOBAL' => @ruby + "/gitconfig",
+ 'TZ' => 'UTC',
+ }
+ git('commit', '--allow-empty', '-m', 'New repository initialized by cvs2svn.', env:)
+ git('commit', '--allow-empty', '-m', 'Initial revision', env:)
+ git('commit', '--allow-empty', '-m', 'version 1.0.0', env:)
+ end
+
+ @sendmail = File.join(Dir.mktmpdir, 'sendmail')
+ File.write(@sendmail, <<~SENDMAIL, mode: "wx", perm: 0755)
+ #!/bin/sh
+ echo #{STDIN_DELIMITER.chomp.dump}
+ exec cat
+ SENDMAIL
+
+ @commit_email = File.expand_path('../../tool/commit-email.rb', __dir__)
+ end
+
+ def teardown
+ # Clean up temporary files if #setup was not omitted
+ if @sendmail
+ File.unlink(@sendmail)
+ Dir.rmdir(File.dirname(@sendmail))
+ end
+ if @ruby
+ FileUtils.rm_rf(@ruby)
+ end
+ end
+
+ def test_sendmail_encoding
+ omit 'the sendmail script does not work on windows' if windows?
+
+ Dir.chdir(@ruby) do
+ before_rev = git('rev-parse', 'HEAD^').chomp
+ after_rev = git('rev-parse', 'HEAD').chomp
+ short_rev = after_rev[0...10]
+
+ out, _, status = EnvUtil.invoke_ruby([
+ { 'SENDMAIL' => @sendmail, 'TZ' => 'UTC' }.merge!(gem_env),
+ @commit_email, './', 'cvs-admin@ruby-lang.org',
+ before_rev, after_rev, 'refs/heads/master',
+ '--viewer-uri', 'https://github.com/ruby/ruby/commit/',
+ '--error-to', 'cvs-admin@ruby-lang.org',
+ ], '', true)
+ stdin = out.b.split(STDIN_DELIMITER.b, 2).last.force_encoding('UTF-8')
+
+ assert_true(status.success?)
+ assert_equal(stdin, <<~EOS)
+ Mime-Version: 1.0
+ Content-Type: text/plain; charset=utf-8
+ Content-Transfer-Encoding: quoted-printable
+ From: =?UTF-8?B?SsOzaMOkbiBHcsO8YsOpbA==?= <noreply@ruby-lang.org>
+ To: cvs-admin@ruby-lang.org
+ Subject: #{short_rev} (master): =?UTF-8?B?dmVyc2lvbuOAgDEuMC4w?=
+ J=C3=B3h=C3=A4n Gr=C3=BCb=C3=A9l\t2025-10-08 12:00:00 +0000 (Wed, 08 Oct 2=
+ 025)
+
+ New Revision: #{short_rev}
+
+ https://github.com/ruby/ruby/commit/#{short_rev}
+
+ Log:
+ version=E3=80=801.0.0=
+ EOS
+ end
+ end
+
+ private
+
+ # Resurrect the gem environment preserved by tool/test/init.rb.
+ # This should work as long as you have run `make up` or `make install`.
+ def gem_env
+ { 'GEM_PATH' => ENV['BUNDLED_GEM_PATH'], 'GEM_HOME' => ENV['BUNDLED_GEM_HOME'] }
+ end
+
+ def git(*cmd, env: {})
+ out, status = Open3.capture2(env, 'git', *cmd)
+ unless status.success?
+ raise "git #{cmd.shelljoin}\n#{out}"
+ end
+ out
+ end
+end
diff --git a/tool/test/test_sync_default_gems.rb b/tool/test/test_sync_default_gems.rb
index e64c6c6fda..7fb39f010e 100755
--- a/tool/test/test_sync_default_gems.rb
+++ b/tool/test/test_sync_default_gems.rb
@@ -2,6 +2,7 @@
require 'test/unit'
require 'stringio'
require 'tmpdir'
+require 'rubygems/version'
require_relative '../sync_default_gems'
module Test_SyncDefaultGems
@@ -19,14 +20,8 @@ module Test_SyncDefaultGems
expected.concat(trailers.map {_1+"\n"})
end
- out, err = capture_output do
- SyncDefaultGems.message_filter(repo, sha, input: StringIO.new(input, "r"))
- end
-
- all_assertions do |a|
- a.for("error") {assert_empty err}
- a.for("result") {assert_pattern_list(expected, out)}
- end
+ out = SyncDefaultGems.message_filter(repo, sha, input)
+ assert_pattern_list(expected, out)
end
def test_subject_only
@@ -90,14 +85,41 @@ module Test_SyncDefaultGems
@target = nil
pend "No git" unless system("git --version", out: IO::NULL)
@testdir = Dir.mktmpdir("sync")
- @git_config = %W"HOME GIT_CONFIG_GLOBAL".each_with_object({}) {|k, c| c[k] = ENV[k]}
+ user, email = "Ruby", "test@ruby-lang.org"
+ @git_config = %W"HOME USER GIT_CONFIG_GLOBAL GNUPGHOME".each_with_object({}) {|k, c| c[k] = ENV[k]}
ENV["HOME"] = @testdir
+ ENV["USER"] = user
+ ENV["GNUPGHOME"] = @testdir + '/.gnupg'
+ expire = EnvUtil.apply_timeout_scale(30).to_i
+ # Generate a new unprotected key with default parameters that
+ # expires after 30 seconds.
+ if @gpgsign = system(*%w"gpg --quiet --batch --passphrase", "",
+ "--quick-generate-key", email, *%W"default default seconds=#{expire}",
+ err: IO::NULL)
+ # Fetch the generated public key.
+ signingkey = IO.popen(%W"gpg --quiet --list-public-key #{email}", &:read)[/^pub .*\n +\K\h+/]
+ end
ENV["GIT_CONFIG_GLOBAL"] = @testdir + "/gitconfig"
- git(*%W"config --global user.email test@ruby-lang.org")
- git(*%W"config --global user.name", "Ruby")
+ git(*%W"config --global user.email", email)
+ git(*%W"config --global user.name", user)
git(*%W"config --global init.defaultBranch default")
+ if signingkey
+ git(*%W"config --global user.signingkey", signingkey)
+ git(*%W"config --global commit.gpgsign true")
+ git(*%W"config --global gpg.program gpg")
+ git(*%W"config --global log.showSignature true")
+ end
@target = "sync-test"
- SyncDefaultGems::REPOSITORIES[@target] = ["ruby/#{@target}", "default"]
+ SyncDefaultGems::REPOSITORIES[@target] = SyncDefaultGems.repo(
+ ["ruby/#{@target}", "default"],
+ [
+ ["lib", "lib"],
+ ["test", "test"],
+ ],
+ exclude: [
+ "test/fixtures/*",
+ ],
+ )
@sha = {}
@origdir = Dir.pwd
Dir.chdir(@testdir)
@@ -129,6 +151,9 @@ module Test_SyncDefaultGems
def teardown
if @target
+ if @gpgsign
+ system(*%W"gpgconf --kill all")
+ end
Dir.chdir(@origdir)
SyncDefaultGems::REPOSITORIES.delete(@target)
ENV.update(@git_config)
@@ -168,7 +193,7 @@ module Test_SyncDefaultGems
end
def top_commit(dir, format: "%H")
- IO.popen(%W[git log --format=#{format} -1], chdir: dir, &:read)&.chomp
+ IO.popen(%W[git log --no-show-signature --format=#{format} -1], chdir: dir, &:read)&.chomp
end
def assert_sync(commits = true, success: true, editor: nil)
@@ -200,6 +225,12 @@ module Test_SyncDefaultGems
assert_operator(top_commit(@target), :start_with?, log.last[/\h+$/], out)
end
+ def test_unknown_repository
+ assert_raise_with_message(RuntimeError, /unknown/) do
+ SyncDefaultGems::REPOSITORIES["not-exist"]
+ end
+ end
+
def test_skip_tool
git(*%W"rm -q tool/ok", chdir: @target)
git(*%W"commit -q -m", "Remove tool", chdir: @target)
@@ -293,5 +324,56 @@ module Test_SyncDefaultGems
assert_equal(":ok\n""Should.be_merged\n", File.read("src/lib/common.rb"), out)
assert_not_operator(File, :exist?, "src/lib/bad.rb", out)
end
- end
+
+ def test_squash_merge
+ # This test is known to fail with git 2.43.0, which is used by Ubuntu 24.04.
+ # We don't know which exact version fixed it, but we know git 2.52.0 works.
+ stdout, status = Open3.capture2('git', '--version', err: File::NULL)
+ omit 'git version check failed' unless status.success?
+ git_version = stdout[/\Agit version \K\S+/]
+ omit "git #{git_version} is too old" if Gem::Version.new(git_version) < Gem::Version.new('2.44.0')
+
+ # 2---. <- branch
+ # / \
+ # 1---3---3'<- merge commit with conflict resolution
+ File.write("#@target/lib/conflict.rb", "# 1\n")
+ git(*%W"add lib/conflict.rb", chdir: @target)
+ git(*%W"commit -q -m", "Add conflict.rb", chdir: @target)
+
+ git(*%W"checkout -q -b branch", chdir: @target)
+ File.write("#@target/lib/conflict.rb", "# 2\n")
+ File.write("#@target/lib/new.rb", "# new\n")
+ git(*%W"add lib/conflict.rb lib/new.rb", chdir: @target)
+ git(*%W"commit -q -m", "Commit in branch", chdir: @target)
+
+ git(*%W"checkout -q default", chdir: @target)
+ File.write("#@target/lib/conflict.rb", "# 3\n")
+ git(*%W"add lib/conflict.rb", chdir: @target)
+ git(*%W"commit -q -m", "Commit in default", chdir: @target)
+
+ # How can I suppress "Auto-merging ..." message from git merge?
+ git(*%W"merge -X ours -m", "Merge commit", "branch", chdir: @target, out: IO::NULL)
+
+ out = assert_sync()
+ assert_equal("# 3\n", File.read("src/lib/conflict.rb"), out)
+ subject, body = top_commit("src", format: "%B").split("\n\n", 2)
+ assert_equal("[ruby/#@target] Merge commit", subject, out)
+ assert_includes(body, "Commit in branch", out)
+ end
+
+ def test_no_upstream_file
+ group = SyncDefaultGems::Repository.group(%w[
+ lib/un.rb
+ lib/unicode_normalize/normalize.rb
+ lib/unicode_normalize/tables.rb
+ lib/net/https.rb
+ ])
+ expected = {
+ "un" => %w[lib/un.rb],
+ "net-http" => %w[lib/net/https.rb],
+ nil => %w[lib/unicode_normalize/normalize.rb lib/unicode_normalize/tables.rb],
+ }
+ assert_equal(expected, group)
+ end
+ end if /darwin|linux/ =~ RUBY_PLATFORM
end
diff --git a/tool/test/testunit/test_assertion.rb b/tool/test/testunit/test_assertion.rb
index b0c2267b31..d9bdc8f3c5 100644
--- a/tool/test/testunit/test_assertion.rb
+++ b/tool/test/testunit/test_assertion.rb
@@ -8,6 +8,8 @@ class TestAssertion < Test::Unit::TestCase
end
def test_timeout_separately
+ pend "hang-up" if /mswin|mingw/ =~ RUBY_PLATFORM
+
assert_raise(Timeout::Error) do
assert_separately([], <<~"end;", timeout: 0.1)
sleep
@@ -15,6 +17,29 @@ class TestAssertion < Test::Unit::TestCase
end
end
+ def test_assertion_count_separately
+ beginning = self._assertions
+
+ assert_separately([], "")
+ assertions_at_nothing = self._assertions - beginning
+
+ prev_assertions = self._assertions + assertions_at_nothing
+ assert_separately([], "assert true")
+ assert_equal(1, self._assertions - prev_assertions)
+
+ omit unless Process.respond_to?(:fork)
+ prev_assertions = self._assertions + assertions_at_nothing
+ assert_separately([], "Process.fork {assert true}; assert true")
+ assert_equal(2, self._assertions - prev_assertions)
+
+ prev_assertions = self._assertions + assertions_at_nothing
+ # TODO: assertions before `fork` are counted twice; it is possible
+ # to reset `_assertions` at `Process._fork`, but the hook can
+ # interfere in other tests.
+ assert_separately([], "assert true; Process.fork {assert true}")
+ assert_equal(3, self._assertions - prev_assertions)
+ end
+
def return_in_assert_raise
assert_raise(RuntimeError) do
return
diff --git a/tool/test/testunit/test_minitest_unit.rb b/tool/test/testunit/test_minitest_unit.rb
index 84b6cf688c..7f53e4b7dd 100644
--- a/tool/test/testunit/test_minitest_unit.rb
+++ b/tool/test/testunit/test_minitest_unit.rb
@@ -646,7 +646,7 @@ class TestMiniTestUnitTestCase < Test::Unit::TestCase
def test_assert_in_delta_triggered
x = "1.0e-06"
- util_assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do
+ util_assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}.", strip: /\s+\(\/proc\/loadavg=.*\)/ do
@tc.assert_in_delta 0.0, 1.0 / 1000, 0.000001
end
end
@@ -678,7 +678,7 @@ class TestMiniTestUnitTestCase < Test::Unit::TestCase
end
def test_assert_in_epsilon_triggered
- util_assert_triggered 'Expected |10000 - 9990| (10) to be <= 9.99.' do
+ util_assert_triggered 'Expected |10000 - 9990| (10) to be <= 9.99.', strip: /\s+\(\/proc\/loadavg=.*\)/ do
@tc.assert_in_epsilon 10000, 9990
end
end
@@ -686,7 +686,7 @@ class TestMiniTestUnitTestCase < Test::Unit::TestCase
def test_assert_in_epsilon_triggered_negative_case
x = "0.100000xxx"
y = "0.1"
- util_assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}." do
+ util_assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}.", strip: /\s+\(\/proc\/loadavg=.*\)/ do
@tc.assert_in_epsilon(-1.1, -1, 0.1)
end
end
@@ -1352,7 +1352,7 @@ class TestMiniTestUnitTestCase < Test::Unit::TestCase
assert_equal expected, sample_test_case.test_methods.sort
end
- def assert_triggered expected, klass = Test::Unit::AssertionFailedError
+ def assert_triggered expected, klass = Test::Unit::AssertionFailedError, strip: nil
e = assert_raise klass do
yield
end
@@ -1360,6 +1360,7 @@ class TestMiniTestUnitTestCase < Test::Unit::TestCase
msg = e.message.sub(/(---Backtrace---).*/m, '\1')
msg.gsub!(/\(oid=[-0-9]+\)/, '(oid=N)')
msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform
+ msg.gsub!(strip, '') if strip
assert_equal expected, msg
end
diff --git a/tool/test/testunit/test_parallel.rb b/tool/test/testunit/test_parallel.rb
index a0cbca69eb..adf7d62ecd 100644
--- a/tool/test/testunit/test_parallel.rb
+++ b/tool/test/testunit/test_parallel.rb
@@ -126,19 +126,19 @@ module TestParallel
assert_not_nil($1, "'done' was not found")
result = Marshal.load($1.chomp.unpack1("m"))
- assert_equal(5, result[0])
- pend "TODO: result[1] returns 17. We should investigate it" do # TODO: misusage of pend (pend doens't use given block)
- assert_equal(12, result[1])
- end
- assert_kind_of(Array,result[2])
- assert_kind_of(Array,result[3])
- assert_kind_of(Array,result[4])
- assert_kind_of(Array,result[2][1])
- assert_kind_of(Test::Unit::AssertionFailedError,result[2][0][2])
- assert_kind_of(Test::Unit::PendedError,result[2][1][2])
- assert_kind_of(Test::Unit::PendedError,result[2][2][2])
- assert_kind_of(Exception, result[2][3][2])
- assert_equal(result[5], "TestE")
+ tests, asserts, reports, failures, loadpaths, suite = result
+ assert_equal(5, tests)
+ assert_equal(12, asserts)
+ assert_kind_of(Array, reports)
+ assert_kind_of(Array, failures)
+ assert_kind_of(Array, loadpaths)
+ reports.sort_by! {|_, t| t}
+ assert_kind_of(Array, reports[1])
+ assert_kind_of(Test::Unit::AssertionFailedError, reports[0][2])
+ assert_kind_of(Test::Unit::PendedError, reports[1][2])
+ assert_kind_of(Test::Unit::PendedError, reports[2][2])
+ assert_kind_of(Exception, reports[3][2])
+ assert_equal("TestE", suite)
end
end
@@ -151,9 +151,9 @@ module TestParallel
end
class TestParallel < Test::Unit::TestCase
- def spawn_runner(*opt_args, jobs: "t1")
+ def spawn_runner(*opt_args, jobs: "t1", env: {})
@test_out, o = IO.pipe
- @test_pid = spawn(*@__runner_options__[:ruby], TESTS+"/runner.rb",
+ @test_pid = spawn(env, *@__runner_options__[:ruby], TESTS+"/runner.rb",
"--ruby", @__runner_options__[:ruby].join(" "),
"-j", jobs, *opt_args, out: o, err: o)
o.close
@@ -214,7 +214,7 @@ module TestParallel
end
def test_hungup
- spawn_runner "--worker-timeout=1", "--retry", "test4test_hungup.rb"
+ spawn_runner("--worker-timeout=1", "--retry", "test4test_hungup.rb", env: {"RUBY_CRASH_REPORT"=>nil})
buf = ::TestParallel.timeout(TIMEOUT) {@test_out.read}
assert_match(/^Retrying hung up testcases\.+$/, buf)
assert_match(/^2 tests,.* 0 failures,/, buf)
diff --git a/tool/test/testunit/tests_for_parallel/ptest_forth.rb b/tool/test/testunit/tests_for_parallel/ptest_forth.rb
index 8831676e19..54474c828d 100644
--- a/tool/test/testunit/tests_for_parallel/ptest_forth.rb
+++ b/tool/test/testunit/tests_for_parallel/ptest_forth.rb
@@ -8,19 +8,19 @@ class TestE < Test::Unit::TestCase
assert_equal(1,1)
end
- def test_always_skip
- skip "always"
+ def test_always_omit
+ omit "always"
end
def test_always_fail
assert_equal(0,1)
end
- def test_skip_after_unknown_error
+ def test_pend_after_unknown_error
begin
raise UnknownError, "unknown error"
rescue
- skip "after raise"
+ pend "after raise"
end
end
diff --git a/tool/update-NEWS-gemlist.rb b/tool/update-NEWS-gemlist.rb
index e1535eb400..68284ab76a 100755
--- a/tool/update-NEWS-gemlist.rb
+++ b/tool/update-NEWS-gemlist.rb
@@ -5,13 +5,29 @@ prev = news[/since the \*+(\d+\.\d+\.\d+)\*+/, 1]
prevs = [prev, prev.sub(/\.\d+\z/, '')]
update = ->(list, type, desc = "updated") do
- item = ->(mark = "* ") do
- "The following #{type} gem#{list.size == 1 ? ' is' : 's are'} #{desc}.\n\n" +
- list.map {|g, v|"#{mark}#{g} #{v}\n"}.join("") + "\n"
+ item = ->(mark = "* ", sub_bullets = {}) do
+ "### The following #{type} gem#{list.size == 1 ? ' is' : 's are'} #{desc}.\n\n" +
+ list.map {|g, v|
+ s = "#{mark}#{g} #{v}\n"
+ s += sub_bullets[g].join("") if sub_bullets[g]
+ s
+ }.join("") + "\n"
end
- news.sub!(/^(?:\*( +))?The following #{type} gems? (?:are|is) #{desc}\.\n+(?:(?(1) \1)\*( *).*\n)*\n*/) do
- item["#{$1&.<< " "}*#{$2 || ' '}"]
- end or news.sub!(/^## Stdlib updates(?:\n+The following.*(?:\n+( *\* *).*)*)*\n+\K/) do
+ news.sub!(/^(?:\*( +)|#+ *)?The following #{type} gems? (?:are|is) #{desc}\.\n+(?:(?:(?(1) \1)\*( *).*\n)(?:[ \t]+\*.*\n)*)*\n*/) do
+ mark = "#{$1&.dup&.<< " "}*#{$2 || ' '}"
+ # Parse existing sub-bullets from matched section
+ sb = {}; cg = nil
+ $~.to_s.each_line do |l|
+ if l =~ /^\* ([A-Za-z0-9_\-]+)\s/
+ cg = $1
+ elsif cg && l =~ /^\s+\*/
+ (sb[cg] ||= []) << l
+ else
+ cg = nil
+ end
+ end
+ item[mark, sb]
+ end or news.sub!(/^## Stdlib updates(?:\n+The following.*(?:\n+(?:( *\* *).*|[ \t]+\*.*))*)* *\n+\K/) do
item[$1 || "* "]
end
end
diff --git a/tool/update-NEWS-github-release.rb b/tool/update-NEWS-github-release.rb
new file mode 100755
index 0000000000..f346209a7d
--- /dev/null
+++ b/tool/update-NEWS-github-release.rb
@@ -0,0 +1,395 @@
+#!/usr/bin/env ruby
+
+require "bundler/inline"
+require "json"
+require "net/http"
+require "uri"
+
+gemfile do
+ source "https://rubygems.org"
+ gem "octokit"
+ gem "faraday-retry"
+end
+
+Octokit.configure do |c|
+ c.access_token = ENV["GITHUB_TOKEN"]
+ c.auto_paginate = true
+ c.per_page = 100
+end
+
+# Build a gem=>version map from stdgems.org stdgems.json for a given Ruby version (e.g., "3.4")
+def fetch_default_gems_versions(ruby_version)
+ uri = URI.parse("https://stdgems.org/stdgems.json")
+ body = http_get(uri)
+ json = JSON.parse(body)
+ gems = json["gems"] || []
+
+ # Prefer the initial release key (e.g. "4.0.0") over the rolling
+ # major.minor key (e.g. "4.0") so the diff baseline reflects the original
+ # X.Y.0 release rather than the latest patch level.
+ initial_release_key = (ruby_version =~ /\A\d+\.\d+\z/) ? "#{ruby_version}.0" : nil
+
+ map = {}
+ gems.each do |g|
+ # Only include default gems (skip ones marked removed)
+ next if g["removed"]
+ versions = g["versions"] || {}
+
+ # versions has "default" and "bundled" keys, each containing Ruby version => version mappings
+ selected_version = nil
+
+ # Try both "default" and "bundled" categories
+ ["default", "bundled"].each do |category|
+ category_versions = versions[category] || {}
+ next if selected_version
+
+ if initial_release_key && category_versions.key?(initial_release_key)
+ selected_version = category_versions[initial_release_key]
+ elsif category_versions.key?(ruby_version)
+ selected_version = category_versions[ruby_version]
+ else
+ # Fall back to the highest patch version matching the given major.minor
+ major_minor = /^#{Regexp.escape(ruby_version)}\./
+ candidates = category_versions.select { |k, _| k.match?(major_minor) }
+ if !candidates.empty?
+ # Sort keys as Gem::Version to pick the highest patch
+ selected_version = candidates.sort_by { |k, _| Gem::Version.new(k) }.last[1]
+ end
+ end
+ end
+
+ next unless selected_version
+
+ name = g["gem"]
+ # Normalize name to match existing special cases
+ name = "RubyGems" if name == "rubygems"
+ map[name] = selected_version
+ end
+
+ map
+end
+
+def previous_ruby_version
+ version_h = File.join(__dir__, "..", "include", "ruby", "version.h")
+ major = minor = nil
+ File.foreach(version_h) do |l|
+ major = $1.to_i if l =~ /^\s*#\s*define\s+RUBY_API_VERSION_MAJOR\s+(\d+)/
+ minor = $1.to_i if l =~ /^\s*#\s*define\s+RUBY_API_VERSION_MINOR\s+(\d+)/
+ end
+ abort "Cannot detect Ruby version from #{version_h}" unless major && minor
+ minor > 0 ? "#{major}.#{minor - 1}" : "#{major - 1}.0"
+end
+
+# Load gem=>version map from a file or from stdgems.org if a Ruby version is given.
+def load_versions(arg)
+ arg ||= previous_ruby_version
+ if File.exist?(arg)
+ File.readlines(arg).map(&:split).to_h
+ elsif arg.match?(/^\d+\.\d+(?:\.\d+)?$/)
+ fetch_default_gems_versions(arg)
+ elsif arg.downcase == "news" || arg =~ %r{https?://.*/NEWS\.md}
+ fetch_versions_from_news(arg)
+ else
+ abort "Invalid argument: #{arg}. Provide a file path or a Ruby version (e.g., 3.4)."
+ end
+end
+
+# Build a gem=>version map by parsing the "## Stdlib updates" section from Ruby's NEWS.md
+def fetch_versions_from_news(arg)
+ if arg.downcase == "news"
+ body = read_local_news_md
+ else
+ body = http_get(URI.parse(arg))
+ end
+
+ parse_stdlib_versions_from_news(body)
+end
+
+# Fetch a URL with a clear abort message on network or HTTP failures.
+# Used for sources whose absence makes the rest of the script meaningless.
+def http_get(uri)
+ res = Net::HTTP.get_response(uri)
+ unless res.is_a?(Net::HTTPSuccess)
+ abort "error: #{uri} returned HTTP #{res.code} #{res.message}"
+ end
+ res.body
+rescue SystemCallError, SocketError, IOError, Net::HTTPError => e
+ abort "error: failed to fetch #{uri}: #{e.class}: #{e.message}"
+end
+
+def read_local_news_md
+ news_path = File.join(__dir__, "..", "NEWS.md")
+ unless File.exist?(news_path)
+ abort "NEWS.md not found at #{news_path}"
+ end
+ File.read(news_path)
+end
+
+# Build a gem=>version map from the current repository state. Default gems
+# come from {ext,lib}/**/*.gemspec (mirroring default_gems_list.yml) and
+# bundled gems come from gems/bundled_gems. This avoids reading NEWS.md as
+# the source of "current versions", which would create a circular dependency
+# with update-NEWS-gemlist.rb.
+def load_current_versions
+ require "rubygems"
+ root = File.expand_path("..", __dir__)
+ map = {}
+
+ rg_path = File.join(root, "lib", "rubygems.rb")
+ if File.exist?(rg_path)
+ File.foreach(rg_path) do |line|
+ if /^\s*VERSION\s*=\s*"([^"]+)"/ =~ line
+ map["RubyGems"] = $1
+ break
+ end
+ end
+ end
+
+ Dir.glob(File.join(root, "{ext,lib}/**/*.gemspec")).each do |path|
+ spec = Gem::Specification.load(path)
+ next unless spec
+ map[spec.name] = spec.version.to_s
+ end
+
+ bundled_path = File.join(root, "gems", "bundled_gems")
+ if File.exist?(bundled_path)
+ File.foreach(bundled_path) do |line|
+ next if line.start_with?("#")
+ name, version = line.split(" ", 3)
+ map[name] = version if name && version
+ end
+ end
+
+ map
+end
+
+def parse_stdlib_versions_from_news(body)
+ # Extract the Stdlib updates section
+ start_idx = body.index(/^## Stdlib updates$/)
+ unless start_idx
+ # Try a more lenient search if anchors differ
+ start_idx = body.index("## Stdlib\nupdates") || body.index("## Stdlib updates")
+ end
+ abort "Stdlib updates section not found in NEWS.md" unless start_idx
+
+ section = body[start_idx..-1]
+ # Stop at the next top-level section header (skip the current header line)
+ first_line_len = section.lines.first ? section.lines.first.length : 0
+ stop_idx = section.index(/^##\s+/, first_line_len)
+ section = stop_idx ? section[0...stop_idx] : section
+
+ map = {}
+
+ # Normalize lines and collect bullet entries like: "* gemname x.y.z"
+ section.each_line do |line|
+ line = line.strip
+ next unless line.start_with?("*")
+ # Remove leading bullet
+ entry = line.sub(/^\*\s+/, "")
+
+ # Some lines can include descriptions or links; we only take simple "name version"
+ # Accept names with hyphens/underscores and versions like 1.2.3 or 1.2.3.4
+ if entry =~ /^([A-Za-z0-9_\-]+)\s+(\d+(?:\.\d+){0,3})\b/
+ name = $1
+ ver = $2
+ name = "RubyGems" if name.downcase == "rubygems"
+ map[name] = ver
+ end
+ end
+
+ map
+end
+
+def resolve_repo(name)
+ case name
+ when "minitest"
+ { repo: name, org: "minitest" }
+ when "test-unit"
+ { repo: name, org: "test-unit" }
+ when "RubyGems"
+ { repo: "rubygems", org: "rubygems" }
+ when "bundler"
+ { repo: "rubygems", org: "rubygems", tag_prefix: "bundler-" }
+ else
+ { repo: name, org: "ruby" }
+ end
+end
+
+def fetch_release_range(name, from_version, to_version, org, repo, tag_prefix: "")
+ releases = []
+ begin
+ Octokit.releases("#{org}/#{repo}").each do |release|
+ releases << release.tag_name
+ end
+ rescue Octokit::Error, Faraday::Error => e
+ warn "warning: skipping #{name} (#{org}/#{repo}): #{e.class}: #{e.message}"
+ return nil
+ end
+
+ # Keep only this gem's version-like tags and sort ascending by semantic version
+ prefix = Regexp.escape(tag_prefix)
+ releases = releases.select { |t| t =~ /\A#{prefix}v?\d/ }
+ releases = releases.sort_by { |t| Gem::Version.new(t.sub(/\A#{prefix}/, "").sub(/^v/, "").tr("_", ".")) }
+
+ start_index = releases.index("#{tag_prefix}v#{from_version}") || releases.index("#{tag_prefix}#{from_version}")
+ end_index = releases.index("#{tag_prefix}v#{to_version}") || releases.index("#{tag_prefix}#{to_version}")
+
+ # If the "to" version is unreleased (e.g. 4.1.0.dev), include every released
+ # tag after the baseline up to the latest one available.
+ end_index ||= releases.length - 1 if to_version =~ /(?:\.|-)(?:dev|beta|alpha|rc|pre)/i
+
+ return nil unless start_index && end_index
+
+ range = releases[start_index + 1..end_index]
+ return nil if range.nil? || range.empty?
+
+ range
+end
+
+def collect_gem_updates(versions_from, versions_to)
+ results = []
+
+ versions_to.each do |name, version|
+ # Skip items which do not exist in the FROM map to reduce API calls
+ next unless versions_from.key?(name)
+
+ info = resolve_repo(name)
+ org = info[:org]
+ repo = info[:repo]
+ tag_prefix = info[:tag_prefix] || ""
+
+ release_range = fetch_release_range(name, versions_from[name], version, org, repo, tag_prefix: tag_prefix)
+ next unless release_range
+
+ footnote_links = release_range.map do |rel|
+ tag = rel.sub(/\A#{Regexp.escape(tag_prefix)}/, "")
+ {
+ ref: "#{name}-#{tag}",
+ url: "https://github.com/#{org}/#{repo}/releases/tag/#{rel}",
+ }
+ end
+
+ results << {
+ name: name,
+ version: version,
+ from_version: versions_from[name],
+ release_range: release_range,
+ footnote_links: footnote_links,
+ tag_prefix: tag_prefix,
+ }
+ end
+
+ results
+end
+
+def format_release_diff(result)
+ prefix = Regexp.escape(result[:tag_prefix] || "")
+ links = result[:release_range].map do |rel|
+ tag = rel.sub(/\A#{prefix}/, "")
+ "[#{tag}][#{result[:name]}-#{tag}]"
+ end
+ " * #{result[:from_version]} to #{links.join(', ')}"
+end
+
+def print_results(results)
+ footnote_lines = []
+
+ results.each do |r|
+ puts "* #{r[:name]} #{r[:version]}"
+ puts format_release_diff(r)
+ r[:footnote_links].each do |fl|
+ footnote_lines << "[#{fl[:ref]}]: #{fl[:url]}"
+ end
+ end
+
+ puts footnote_lines.join("\n")
+end
+
+def update_news_md(results)
+ news_path = File.join(__dir__, "..", "NEWS.md")
+ unless File.exist?(news_path)
+ abort "NEWS.md not found at #{news_path}"
+ end
+ content = File.read(news_path)
+ lines = content.lines
+
+ result_by_name = results.to_h { |r| [r[:name], r] }
+
+ new_lines = []
+ i = 0
+ while i < lines.length
+ line = lines[i]
+
+ if line =~ /^\* ([A-Za-z0-9_\-]+)\s+(\d+(?:\.\d+){0,3})\b/
+ gem_name = $1
+
+ new_lines << line
+
+ if (r = result_by_name[gem_name])
+ # Skip any existing sub-bullet lines that follow
+ while i + 1 < lines.length && lines[i + 1] =~ /^\s+\*/
+ i += 1
+ end
+
+ new_lines << "#{format_release_diff(r)}\n"
+ end
+ else
+ new_lines << line
+ end
+ i += 1
+ end
+
+ # All footnote definitions we can emit, indexed by ref name. Seed from existing
+ # release-tag defs in the file so gems skipped this run (e.g. transient API
+ # failures) keep their URLs, then overlay freshly fetched URLs.
+ release_ref_pattern = %r{^\[([^\]]+)\]:\s+(https://github\.com/[^/]+/[^/]+/releases/tag/.*)}
+ available_footnotes = {}
+ new_lines.each do |line|
+ if (m = line.match(release_ref_pattern))
+ available_footnotes[m[1]] = "[#{m[1]}]: #{m[2]}"
+ end
+ end
+ results.each do |r|
+ r[:footnote_links].each do |fl|
+ available_footnotes[fl[:ref]] = "[#{fl[:ref]}]: #{fl[:url]}"
+ end
+ end
+
+ # Refs the regenerated body actually uses (e.g. `][gem-vX.Y.Z]`)
+ used_refs = new_lines.join.scan(/\]\[([^\]]+)\]/).flatten.uniq
+
+ # Drop all existing GitHub release-tag link defs; the used subset is
+ # re-emitted below in body-ref order so the footer is deterministic.
+ new_lines.reject! { |line| line.match?(release_ref_pattern) }
+
+ # Trim trailing blank lines so the appended footer block is clean
+ new_lines.pop while new_lines.last == "\n"
+ new_lines << "\n" unless new_lines.last&.end_with?("\n")
+
+ # Append footnote defs only for refs the body still references
+ emitted = 0
+ used_refs.each do |ref|
+ if (footnote = available_footnotes[ref])
+ new_lines << "#{footnote}\n"
+ emitted += 1
+ end
+ end
+
+ File.write(news_path, new_lines.join)
+ puts "Updated #{news_path} with #{results.length} gem update entries and #{emitted} footnote links."
+end
+
+# --- Main ---
+
+update_mode = ARGV.delete("--update")
+
+versions_from = load_versions(ARGV[0])
+versions_to = load_current_versions
+
+results = collect_gem_updates(versions_from, versions_to)
+
+print_results(results)
+
+if update_mode
+ update_news_md(results)
+end
diff --git a/tool/update-bundled_gems.rb b/tool/update-bundled_gems.rb
index 2842516cac..565a522aa0 100755
--- a/tool/update-bundled_gems.rb
+++ b/tool/update-bundled_gems.rb
@@ -1,38 +1,45 @@
-#!ruby -pla
+#!ruby -alpF\s+|#.*
BEGIN {
require 'rubygems'
date = nil
# STDOUT is not usable in inplace edit mode
output = $-i ? STDOUT : STDERR
+ # Gems to skip auto-updating (e.g. when a new major version breaks CI)
+ pinned = %w[rbs]
}
output = STDERR if ARGF.file == STDIN
END {
output.print date.strftime("latest_date=%F") if date
}
-unless /^[^#]/ !~ (gem = $F[0])
- ver = Gem::Version.new($F[1])
- (gem, src), = Gem::SpecFetcher.fetcher.detect(:latest) {|s|
- s.platform == "ruby" && s.name == gem
- }
- if gem.version > ver
- gem = src.fetch_spec(gem)
- if ENV["UPDATE_BUNDLED_GEMS_ALL"]
- uri = gem.metadata["source_code_uri"] || gem.homepage
- uri = uri.sub(%r[\Ahttps://github\.com/[^/]+/[^/]+\K/tree/.*], "").chomp(".git")
- else
- uri = $F[2]
- end
- date = gem.date if !date or gem.date && gem.date > date
- if $F[3]
- if $F[3].include?($F[1])
- $F[3][$F[1]] = gem.version.to_s
- elsif Gem::Version.new($F[1]) != gem.version and /\A\h+\z/ =~ $F[3]
- $F[3..-1] = []
+if gem = $F[0]
+ unless pinned.include?(gem)
+ ver = Gem::Version.new($F[1])
+ (gem, src), = Gem::SpecFetcher.fetcher.detect(:latest) {|s|
+ s.platform == "ruby" && s.name == gem
+ }
+ if gem.version > ver
+ gem = src.fetch_spec(gem)
+ if ENV["UPDATE_BUNDLED_GEMS_ALL"]
+ uri = gem.metadata["source_code_uri"] || gem.homepage
+ uri = uri.sub(%r[\Ahttps://github\.com/[^/]+/[^/]+\K/tree/.*], "").chomp(".git")
+ else
+ uri = $F[2]
+ end
+ if (!date or gem.date && gem.date > date) and gem.date.to_i != 315_619_200
+ # DEFAULT_SOURCE_DATE_EPOCH is meaningless
+ date = gem.date
+ end
+ if $F[3]
+ if $F[3].include?($F[1])
+ $F[3][$F[1]] = gem.version.to_s
+ elsif Gem::Version.new($F[1]) != gem.version and /\A\h+\z/ =~ $F[3]
+ $F[3..-1] = []
+ end
end
+ f = [gem.name, gem.version.to_s, uri, *$F[3..-1]]
+ $_.gsub!(/\S+\s*(?=\s|$)/) {|s| (f.shift || "").ljust(s.size)}
+ $_ = [$_, *f].join(" ") unless f.empty?
+ $_.rstrip!
end
- f = [gem.name, gem.version.to_s, uri, *$F[3..-1]]
- $_.gsub!(/\S+\s*(?=\s|$)/) {|s| (f.shift || "").ljust(s.size)}
- $_ = [$_, *f].join(" ") unless f.empty?
- $_.rstrip!
end
end
diff --git a/tool/update-deps b/tool/update-deps
index 0b90876cd2..0b73228b88 100755
--- a/tool/update-deps
+++ b/tool/update-deps
@@ -17,6 +17,14 @@
# 3. Use --fix to fix makefiles.
# Ex. ./ruby tool/update-deps --fix
#
+# Usage to create a depend file initially:
+# 1. Copy the dependency section from the Makefile generated by extconf.rb.
+# Ex. ext/cgi/escape/Makefile
+# 2. Add `# AUTOGENERATED DEPENDENCIES START` and `# AUTOGENERATED DEPENDENCIES END`
+# sections to top and end of the depend file.
+# 3. Run tool/update-deps --fix to fix the depend file.
+# 4. Commit the depend file.
+#
# Other usages:
# * Fix makefiles using previously detected dependency problems
# Ex. ruby tool/update-deps --actual-fix [file]
@@ -88,6 +96,15 @@ result.each {|k,v|
# They can be referenced as $(top_srcdir)/filename.
# % ruby -e 'def g(d) Dir.chdir(d) { Dir["**/*.{c,h,inc,dmyh}"] } end; puts((g("repo_source_dir_after_build") - g("repo_source_dir_original")).sort)'
FILES_IN_SOURCE_DIRECTORY = %w[
+ 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
+ prism/version.h
]
# Files built in the build directory (except extconf.h).
@@ -149,16 +166,6 @@ FILES_NEED_VPATH = %w[
enc/trans/single_byte.c
enc/trans/utf8_mac.c
enc/trans/utf_16_32.c
-
- 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
- prism/version.h
]
# Multiple files with same filename.
@@ -206,7 +213,7 @@ def in_makefile(target, source)
when %r{\Acoroutine/} then source2 = "{$(VPATH)}$(COROUTINE_H)"
else source2 = "$(top_srcdir)/#{source}"
end
- ["common.mk", target2, source2]
+ ["depend", target2, source2]
when %r{\Aenc/}
target2 = "#{target.sub(/\.o\z/, '.$(OBJEXT)')}"
case source
@@ -319,6 +326,9 @@ def read_make_deps(cwd)
deps.delete_if {|dep| /\.time\z/ =~ dep} # skip timestamp
next if /\.o\z/ !~ target.to_s
next if /libyjit.o\z/ =~ target.to_s # skip YJIT Rust object (no corresponding C source)
+ next if /libzjit.o\z/ =~ target.to_s # skip ZJIT Rust object (no corresponding C source)
+ next if /target\/release\/libruby.o\z/ =~ target.to_s # skip YJIT+ZJIT Rust object (no corresponding C source)
+ next if /\.bundle\// =~ curdir.to_s
next if /\.bundle\// =~ target.to_s
next if /\A\./ =~ target.to_s # skip rules such as ".c.o"
#p [curdir, target, deps]
diff --git a/tool/zjit_bisect.rb b/tool/zjit_bisect.rb
new file mode 100755
index 0000000000..a265a3c01f
--- /dev/null
+++ b/tool/zjit_bisect.rb
@@ -0,0 +1,165 @@
+#!/usr/bin/env ruby
+require 'logger'
+require 'optparse'
+require 'shellwords'
+require 'tempfile'
+require 'timeout'
+
+required_ruby_version = Gem::Version.new("3.4.0")
+raise "Ruby version #{required_ruby_version} or higher is required" if Gem::Version.new(RUBY_VERSION) < required_ruby_version
+
+ARGS = {timeout: 5}
+OptionParser.new do |opts|
+ opts.banner += " <path_to_ruby> -- <options>"
+ opts.on("--timeout=TIMEOUT_SEC", "Seconds until child process is killed") do |timeout|
+ ARGS[:timeout] = Integer(timeout)
+ end
+ opts.on("-h", "--help", "Prints this help") do
+ puts opts
+ exit
+ end
+end.parse!
+
+usage = "Usage: zjit_bisect.rb <path_to_ruby> -- <options>"
+RUBY = ARGV[0] || raise(usage)
+OPTIONS = ARGV[1..]
+raise(usage) if OPTIONS.empty?
+LOGGER = Logger.new($stdout)
+
+# From https://github.com/tekknolagi/omegastar
+# MIT License
+# Copyright (c) 2024 Maxwell Bernstein and Meta Platforms
+# Attempt to reduce the `items` argument as much as possible, returning the
+# shorter version. `fixed` will always be used as part of the items when
+# running `command`.
+# `command` should return True if the command succeeded (the failure did not
+# reproduce) and False if the command failed (the failure reproduced).
+def bisect_impl(command, fixed, items, indent="")
+ LOGGER.info("#{indent}step fixed[#{fixed.length}] and items[#{items.length}]")
+ while items.length > 1
+ LOGGER.info("#{indent}#{fixed.length + items.length} candidates")
+ # Return two halves of the given list. For odd-length lists, the second
+ # half will be larger.
+ half = items.length / 2
+ left = items[0...half]
+ right = items[half..]
+ if !command.call(fixed + left)
+ items = left
+ next
+ end
+ if !command.call(fixed + right)
+ items = right
+ next
+ end
+ # We need something from both halves to trigger the failure. Try
+ # holding each half fixed and bisecting the other half to reduce the
+ # candidates.
+ new_right = bisect_impl(command, fixed + left, right, indent + "< ")
+ new_left = bisect_impl(command, fixed + new_right, left, indent + "> ")
+ return new_left + new_right
+ end
+ items
+end
+
+# From https://github.com/tekknolagi/omegastar
+# MIT License
+# Copyright (c) 2024 Maxwell Bernstein and Meta Platforms
+def run_bisect(command, items)
+ LOGGER.info("Verifying items")
+ if command.call(items)
+ raise StandardError.new("Command succeeded with full items")
+ end
+ if !command.call([])
+ raise StandardError.new("Command failed with empty items")
+ end
+ bisect_impl(command, [], items)
+end
+
+def add_zjit_options cmd
+ if RUBY == "make"
+ # Automatically detect that we're running a make command instead of a Ruby
+ # one. Pass the bisection options via RUN_OPTS/SPECOPTS instead.
+ zjit_opts = cmd.select { |arg| arg.start_with?("--zjit") }
+ run_opts_index = cmd.find_index { |arg| arg.start_with?("RUN_OPTS=") }
+ specopts_index = cmd.find_index { |arg| arg.start_with?("SPECOPTS=") }
+ if run_opts_index && specopts_index
+ raise "Expected only one of RUN_OPTS or SPECOPTS to be present in make command, but both were found"
+ end
+ if run_opts_index
+ run_opts = Shellwords.split(cmd[run_opts_index].delete_prefix("RUN_OPTS="))
+ run_opts.concat(zjit_opts)
+ cmd[run_opts_index] = "RUN_OPTS=#{run_opts.shelljoin}"
+ elsif specopts_index
+ specopts = Shellwords.split(cmd[specopts_index].delete_prefix("SPECOPTS="))
+ # SPECOPTS needs -T before each option to pass it through mspec to Ruby
+ zjit_opts.each { |opt| specopts.concat(["-T", opt]) }
+ cmd[specopts_index] = "SPECOPTS=#{specopts.shelljoin}"
+ else
+ raise "Expected RUN_OPTS or SPECOPTS to be present in make command"
+ end
+ cmd = cmd - zjit_opts
+ end
+ cmd
+end
+
+def run_ruby *cmd
+ cmd = add_zjit_options(cmd)
+ pid = Process.spawn(*cmd, {
+ in: :close,
+ out: [File::NULL, File::RDWR],
+ err: [File::NULL, File::RDWR],
+ })
+ begin
+ status = Timeout.timeout(ARGS[:timeout]) do
+ Process::Status.wait(pid)
+ end
+ rescue Timeout::Error
+ Process.kill("KILL", pid)
+ LOGGER.warn("Timed out after #{ARGS[:timeout]} seconds")
+ status = Process::Status.wait(pid)
+ end
+
+ status
+end
+
+def run_with_jit_list(ruby, options, jit_list)
+ # Make a new temporary file containing the JIT list
+ Tempfile.create("jit_list") do |temp_file|
+ temp_file.write(jit_list.join("\n"))
+ temp_file.flush
+ temp_file.close
+ # Run the JIT with the temporary file
+ run_ruby ruby, "--zjit-allowed-iseqs=#{temp_file.path}", *options
+ end
+end
+
+# Try running with no JIT list to get a stable baseline
+unless run_with_jit_list(RUBY, OPTIONS, []).success?
+ cmd = add_zjit_options([RUBY, "--zjit-allowed-iseqs=/dev/null", *OPTIONS]).shelljoin
+ raise "The command failed unexpectedly with an empty JIT list. To reproduce, try running the following: `#{cmd}`"
+end
+# Collect the JIT list from the failing Ruby process
+jit_list = nil
+Tempfile.create "jit_list" do |temp_file|
+ run_ruby RUBY, "--zjit-log-compiled-iseqs=#{temp_file.path}", *OPTIONS
+ jit_list = File.readlines(temp_file.path).map(&:strip).reject(&:empty?)
+end
+LOGGER.info("Starting with JIT list of #{jit_list.length} items.")
+# Try running without the optimizer
+status = run_with_jit_list(RUBY, ["--zjit-disable-hir-opt", *OPTIONS], jit_list)
+if status.success?
+ LOGGER.warn "*** Command suceeded with HIR optimizer disabled. HIR optimizer is probably at fault. ***"
+end
+# Now narrow it down
+command = lambda do |items|
+ run_with_jit_list(RUBY, OPTIONS, items).success?
+end
+result = run_bisect(command, jit_list)
+File.open("jitlist.txt", "w") do |file|
+ file.puts(result)
+end
+puts "Run:"
+jitlist_path = File.expand_path("jitlist.txt")
+puts add_zjit_options([RUBY, "--zjit-allowed-iseqs=#{jitlist_path}", *OPTIONS]).shelljoin
+puts "Reduced JIT list (available in jitlist.txt):"
+puts result
diff --git a/tool/zjit_diff.rb b/tool/zjit_diff.rb
new file mode 100755
index 0000000000..4f8f74d20f
--- /dev/null
+++ b/tool/zjit_diff.rb
@@ -0,0 +1,272 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'fileutils'
+require 'optparse'
+require 'tmpdir'
+require 'logger'
+require 'digest'
+require 'shellwords'
+
+GitRef = Struct.new(:ref, :commit_hash)
+
+RUBIES_DIR = File.join(Dir.home, '.zjit-diff')
+BEFORE_NAME = 'ruby-zjit-before'
+AFTER_NAME = 'ruby-zjit-after'
+
+LOG = Logger.new($stderr)
+
+def macos?
+ Gem::Platform.local == 'darwin'
+end
+
+class CommandRunner
+ def initialize(quiet: false)
+ @quiet = quiet
+ end
+
+ def cmd(*args, **options)
+ options[:out] ||= @quiet ? File::NULL : $stderr
+ options = options.merge(exception: true)
+ system(*args, **options)
+ end
+end
+
+class ZJITDiff
+ DATA_FILENAME = File.join('data', 'zjit_diff')
+ RUBY_BENCH_REPO_URL = 'https://github.com/ruby/ruby-bench.git'
+
+ def initialize(before_hash:, after_hash:, runner:, options:)
+ @before_hash = before_hash
+ @after_hash = after_hash
+ @runner = runner
+ @options = options
+ end
+
+ def bench!
+ LOG.info('Running benchmarks')
+ ruby_bench_path = @options[:bench_path] || setup_ruby_bench
+ run_benchmarks(ruby_bench_path)
+ end
+
+ private
+
+ def run_benchmarks(ruby_bench_path)
+ Dir.chdir(ruby_bench_path) do
+ @runner.cmd({ 'RUBIES_DIR' => RUBIES_DIR },
+ './run_benchmarks.rb',
+ '--chruby',
+ "before::#{@before_hash} --zjit-stats;after::#{@after_hash} --zjit-stats",
+ '--out-name',
+ DATA_FILENAME,
+ *@options[:bench_args],
+ *@options[:name_filters])
+
+ @runner.cmd('./misc/zjit_diff.rb', "#{DATA_FILENAME}.json", out: $stdout)
+ end
+ end
+
+ def setup_ruby_bench
+ path = File.join(Dir.tmpdir, 'ruby-bench')
+ if Dir.exist?(path)
+ LOG.info('ruby-bench already cloned, pulling from upstream')
+ Dir.chdir(path) do
+ @runner.cmd('git', 'pull')
+ end
+ else
+ LOG.info("ruby-bench not cloned yet, cloning repository to #{path}")
+ @runner.cmd('git', 'clone', RUBY_BENCH_REPO_URL, path)
+ end
+ path
+ end
+end
+
+class RubyWorktree
+ attr_reader :hash
+
+ BREW_REQUIRED_PACKAGES = %w[openssl readline libyaml].freeze
+
+ def initialize(name:, ref:, runner:, force_rebuild: false)
+ @path = File.join(Dir.tmpdir, name)
+ @ref = ref
+ @force_rebuild = force_rebuild
+ @runner = runner
+ @hash = nil
+
+ setup_worktree
+ end
+
+ def build!
+ Dir.chdir(@path) do
+ configure_cmd_args = ['--enable-zjit=dev', '--disable-install-doc']
+ if macos?
+ brew_prefixes = BREW_REQUIRED_PACKAGES.map do |pkg|
+ `brew --prefix #{pkg}`.strip
+ end
+ configure_cmd_args << "--with-opt-dir=#{brew_prefixes.join(':')}"
+ end
+ configure_cmd_hash = Digest::MD5.hexdigest(configure_cmd_args.join(''))
+
+ build_cmd_args = ['-j', 'miniruby']
+ build_cmd_hash = Digest::MD5.hexdigest(build_cmd_args.join(''))
+
+ @hash = "#{configure_cmd_hash}-#{build_cmd_hash}-#{@ref.commit_hash}"
+ prefix = File.join(RUBIES_DIR, @hash)
+
+ if Dir.exist?(prefix) && !@force_rebuild
+ LOG.info("Found existing build for #{@ref.ref}, skipping build")
+ return
+ end
+
+ @runner.cmd('./autogen.sh')
+
+ cmd = [
+ './configure',
+ *configure_cmd_args,
+ "--prefix=#{prefix}"
+ ]
+
+ @runner.cmd(*cmd)
+ @runner.cmd('make', *build_cmd_args)
+ @runner.cmd('make', 'install')
+ end
+ end
+
+ private
+
+ def setup_worktree
+ if Dir.exist?(@path)
+ LOG.info("Existing worktree found at #{@path}")
+ Dir.chdir(@path) do
+ @runner.cmd('git', 'checkout', @ref.commit_hash)
+ end
+ else
+ LOG.info("Creating worktree for ref '#{@ref.ref}' at #{@path}")
+ @runner.cmd('git', 'worktree', 'add', '--detach', @path, @ref.commit_hash)
+ end
+ end
+end
+
+def clean!
+ [BEFORE_NAME, AFTER_NAME].each do |name|
+ path = File.join(Dir.tmpdir, name)
+ if Dir.exist?(path)
+ LOG.info("Removing worktree at #{path}")
+ system('git', 'worktree', 'remove', '--force', path)
+ end
+ end
+
+ if Dir.exist?(RUBIES_DIR)
+ LOG.info("Removing ruby installations from #{RUBIES_DIR}")
+ FileUtils.rm_rf(RUBIES_DIR)
+ end
+
+ bench_path = File.join(Dir.tmpdir, 'ruby-bench')
+ return unless Dir.exist?(bench_path)
+
+ LOG.info("Removing ruby-bench clone at #{bench_path}")
+ FileUtils.rm_rf(bench_path)
+end
+
+def parse_ref(ref)
+ out = `git rev-parse --verify #{ref}`
+ return nil unless $?.success?
+
+ GitRef.new(ref: ref, commit_hash: out.strip)
+end
+
+DEFAULT_BENCHMARKS = %w[lobsters railsbench].freeze
+
+options = {}
+
+subtext = <<~HELP
+ Subcommands:
+ bench : Run benchmarks
+ clean : Clean temporary files created by benchmarks
+ See '#{$PROGRAM_NAME} COMMAND --help' for more information on a specific command.
+HELP
+
+top_level = OptionParser.new do |opts|
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
+ opts.separator('')
+ opts.separator(subtext)
+end
+
+subcommands = {
+ 'bench' => OptionParser.new do |opts|
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options] <benchmarks to run>"
+
+ opts.on('--before REF', 'Git ref for ruby (before)') do |ref|
+ git_ref = parse_ref ref
+ if git_ref.nil?
+ warn "Error: '#{ref}' is not a valid git ref"
+ exit 1
+ end
+
+ options[:before] = git_ref
+ end
+
+ opts.on('--after REF', 'Git ref for ruby (after)') do |ref|
+ git_ref = parse_ref ref
+ if git_ref.nil?
+ warn "Error: '#{ref}' is not a valid git ref"
+ exit 1
+ end
+
+ options[:after] = git_ref
+ end
+
+ opts.on('--bench-path PATH',
+ 'Path to an existing ruby-bench repository clone ' \
+ '(if not specified, ruby-bench will be cloned automatically to a temporary directory)') do |path|
+ options[:bench_path] = path
+ end
+
+ opts.on('--bench-args ARGS', 'Args to pass to ruby-bench') do |bench_args|
+ options[:bench_args] = bench_args.shellsplit
+ end
+
+ opts.on('--force-rebuild',
+ 'Force building ruby again instead of using even if existing builds exist in the cache at ~/.diffs') do
+ options[:force_rebuild] = true
+ end
+
+ opts.on('--quiet', 'Silence output of commands except for benchmark result') do
+ options[:quiet] = true
+ end
+
+ opts.separator('')
+ opts.separator('If no benchmarks are specified, the benchmarks that will be run are:')
+ opts.separator(DEFAULT_BENCHMARKS.join(', '))
+ end,
+ 'clean' => OptionParser.new do |opts|
+ end
+}
+
+top_level.order!
+command = ARGV.shift
+subcommands[command].order!
+
+case command
+when 'bench'
+ options[:name_filters] = ARGV.empty? ? DEFAULT_BENCHMARKS : ARGV
+ options[:after] ||= parse_ref('HEAD')
+
+ runner = CommandRunner.new(quiet: options[:quiet])
+
+ before = RubyWorktree.new(name: BEFORE_NAME,
+ ref: options[:before],
+ runner: runner,
+ force_rebuild: options[:force_rebuild])
+ before.build!
+ after = RubyWorktree.new(name: AFTER_NAME,
+ ref: options[:after],
+ runner: runner,
+ force_rebuild: options[:force_rebuild])
+ after.build!
+
+ zjit_diff = ZJITDiff.new(runner: runner, before_hash: before.hash, after_hash: after.hash, options: options)
+ zjit_diff.bench!
+when 'clean'
+ clean!
+end
diff --git a/tool/zjit_iongraph.html b/tool/zjit_iongraph.html
new file mode 100644
index 0000000000..993cce9045
--- /dev/null
+++ b/tool/zjit_iongraph.html
@@ -0,0 +1,551 @@
+<!-- Copyright Mozilla and licensed under Mozilla Public License Version 2.0.
+ Source can be found at https://github.com/mozilla-spidermonkey/iongraph -->
+<!-- Generated by `npm run build-www` on
+ 39b04fa18f23cbf3fd2ca7339a45341ff3351ba1 in tekknolagi/iongraph -->
+<!DOCTYPE html>
+
+<head>
+ <title>iongraph</title>
+ <style>/* iongraph-specific styles inspired by Tachyons */
+
+:root {
+ --ig-size-1: 1rem;
+ --ig-size-2: 2rem;
+ --ig-size-3: 4rem;
+ --ig-size-4: 8rem;
+ --ig-size-5: 16rem;
+
+ --ig-spacing-1: .25rem;
+ --ig-spacing-2: .5rem;
+ --ig-spacing-3: 1rem;
+ --ig-spacing-4: 2rem;
+ --ig-spacing-5: 4rem;
+ --ig-spacing-6: 8rem;
+ --ig-spacing-7: 16rem;
+
+ --ig-text-color: black;
+ --ig-text-color-dim: #777;
+ --ig-background-primary: #ffb54e;
+ --ig-background-light: white;
+ --ig-border-color: #0c0c0d;
+
+ --ig-block-header-color: #0c0c0d;
+ --ig-loop-header-color: #1fa411;
+ --ig-movable-color: #1048af;
+ --ig-rob-color: #444;
+ --ig-in-worklist-color: red;
+
+ --ig-block-selected: #ffc863;
+ --ig-block-last-selected: #ffb54e;
+
+ --ig-highlight-0: #ffb54e;
+ --ig-highlight-1: #ffb5c5;
+ --ig-highlight-2: #a4cbff;
+ --ig-highlight-3: #8be182;
+ --ig-highlight-4: #d9a4fd;
+
+ --ig-flash-color: #ffb54e;
+
+ /*
+ * The heatmap of sample counts will effectively be sampled from a gradient:
+ *
+ * |----------|---------------------------------------|
+ * cold "cool" hot
+ *
+ * The "cold" color will simply be transparent. Therefore, the "cool"
+ * threshold indicates where the instruction will be fully colored and
+ * noticeable to the user.
+ */
+ --ig-hot-color: #ff849e;
+ --ig-cool-color: #ffe546;
+ --ig-cool-threshold: 0.2;
+}
+
+a.ig-link-normal {
+ color: inherit;
+ text-decoration: inherit;
+}
+
+.ig-flex {
+ display: flex;
+}
+
+.ig-flex-column {
+ flex-direction: column;
+}
+
+.ig-flex-basis-0 {
+ flex-basis: 0;
+}
+
+.ig-flex-grow-1 {
+ flex-grow: 1;
+}
+
+.ig-flex-shrink-0 {
+ flex-shrink: 0;
+}
+
+.ig-flex-shrink-1 {
+ flex-shrink: 1;
+}
+
+.ig-items-center {
+ align-items: center;
+}
+
+.ig-relative {
+ position: relative;
+}
+
+.ig-absolute {
+ position: absolute;
+}
+
+.ig-absolute-fill {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+
+.ig-g1 {
+ gap: var(--ig-spacing-1);
+}
+
+.ig-g2 {
+ gap: var(--ig-spacing-2);
+}
+
+.ig-g3 {
+ gap: var(--ig-spacing-3);
+}
+
+.ig-w1 {
+ width: var(--ig-size-1);
+}
+
+.ig-w2 {
+ width: var(--ig-size-2);
+}
+
+.ig-w3 {
+ width: var(--ig-size-3);
+}
+
+.ig-w4 {
+ width: var(--ig-size-4);
+}
+
+.ig-w5 {
+ width: var(--ig-size-5);
+}
+
+.ig-w-100 {
+ width: 100%;
+}
+
+.ig-ba {
+ border-style: solid;
+ border-width: 1px;
+ border-color: var(--ig-border-color);
+}
+
+.ig-bt {
+ border-top-style: solid;
+ border-top-width: 1px;
+ border-color: var(--ig-border-color);
+}
+
+.ig-br {
+ border-right-style: solid;
+ border-right-width: 1px;
+ border-color: var(--ig-border-color);
+}
+
+.ig-bb {
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ border-color: var(--ig-border-color);
+}
+
+.ig-bl {
+ border-left-style: solid;
+ border-left-width: 1px;
+ border-color: var(--ig-border-color);
+}
+
+.ig-pa1 {
+ padding: var(--ig-spacing-1);
+}
+
+.ig-pa2 {
+ padding: var(--ig-spacing-2);
+}
+
+.ig-pa3 {
+ padding: var(--ig-spacing-3);
+}
+
+.ig-ph1 {
+ padding-left: var(--ig-spacing-1);
+ padding-right: var(--ig-spacing-1);
+}
+
+.ig-ph2 {
+ padding-left: var(--ig-spacing-2);
+ padding-right: var(--ig-spacing-2);
+}
+
+.ig-ph3 {
+ padding-left: var(--ig-spacing-3);
+ padding-right: var(--ig-spacing-3);
+}
+
+.ig-pv1 {
+ padding-top: var(--ig-spacing-1);
+ padding-bottom: var(--ig-spacing-1);
+}
+
+.ig-pv2 {
+ padding-top: var(--ig-spacing-2);
+ padding-bottom: var(--ig-spacing-2);
+}
+
+.ig-pv3 {
+ padding-top: var(--ig-spacing-3);
+ padding-bottom: var(--ig-spacing-3);
+}
+
+.ig-pt1 {
+ padding-top: var(--ig-spacing-1);
+}
+
+.ig-pt2 {
+ padding-top: var(--ig-spacing-2);
+}
+
+.ig-pt3 {
+ padding-top: var(--ig-spacing-3);
+}
+
+.ig-pr1 {
+ padding-right: var(--ig-spacing-1);
+}
+
+.ig-pr2 {
+ padding-right: var(--ig-spacing-2);
+}
+
+.ig-pr3 {
+ padding-right: var(--ig-spacing-3);
+}
+
+.ig-pb1 {
+ padding-bottom: var(--ig-spacing-1);
+}
+
+.ig-pb2 {
+ padding-bottom: var(--ig-spacing-2);
+}
+
+.ig-pb3 {
+ padding-bottom: var(--ig-spacing-3);
+}
+
+.ig-pl1 {
+ padding-left: var(--ig-spacing-1);
+}
+
+.ig-pl2 {
+ padding-left: var(--ig-spacing-2);
+}
+
+.ig-pl3 {
+ padding-left: var(--ig-spacing-3);
+}
+
+.ig-f1 {
+ font-size: 3rem;
+}
+
+.ig-f2 {
+ font-size: 2.25rem;
+}
+
+.ig-f3 {
+ font-size: 1.5rem;
+}
+
+.ig-f4 {
+ font-size: 1.25rem;
+}
+
+.ig-f5 {
+ font-size: 1rem;
+}
+
+.ig-f6 {
+ font-size: .875rem;
+}
+
+.ig-f7 {
+ font-size: .75rem;
+}
+
+.ig-text-normal {
+ color: var(--ig-text-color);
+}
+
+.ig-text-dim {
+ color: var(--ig-text-color-dim);
+}
+
+.ig-tl {
+ text-align: left;
+}
+
+.ig-tr {
+ text-align: right;
+}
+
+.ig-tc {
+ text-align: center;
+}
+
+.ig-bg-white {
+ background-color: var(--ig-background-light);
+}
+
+.ig-bg-primary {
+ background-color: var(--ig-background-primary);
+}
+
+.ig-overflow-hidden {
+ overflow: hidden;
+}
+
+.ig-overflow-auto {
+ overflow: auto;
+}
+
+.ig-overflow-x-auto {
+ overflow-x: auto;
+}
+
+.ig-overflow-y-auto {
+ overflow-y: auto;
+}
+
+.ig-hide-if-empty:empty {
+ display: none;
+}
+
+/* Non-utility styles */
+
+.ig-graph {
+ color: var(--ig-text-color);
+ position: absolute;
+ left: 0;
+ top: 0;
+ isolation: isolate;
+}
+
+.ig-block {
+ position: absolute;
+
+ .ig-block-header {
+ font-weight: bold;
+ text-align: center;
+ background-color: var(--ig-block-header-color);
+ color: white;
+ padding: 0 1em;
+ border: 1px solid var(--ig-border-color);
+ border-width: 1px 1px 0;
+ }
+
+ .ig-instructions {
+ padding: 0.5em;
+ border: 1px solid var(--ig-border-color);
+ border-width: 0 1px 1px;
+
+ table {
+ border-collapse: collapse;
+ }
+
+ td,
+ th {
+ white-space: nowrap;
+ padding: 0.1em 0.5em;
+ }
+
+ th {
+ font-weight: normal;
+ }
+ }
+
+ &.ig-selected {
+ outline: 4px solid var(--ig-block-selected);
+ }
+
+ &.ig-last-selected {
+ outline-color: var(--ig-block-last-selected);
+ }
+}
+
+.ig-block-att-loopheader {
+ .ig-block-header {
+ background-color: var(--ig-loop-header-color);
+ }
+}
+
+.ig-block-att-splitedge {
+ .ig-instructions {
+ border-style: dotted;
+ border-width: 0 2px 2px;
+ }
+}
+
+.ig-ins-num {
+ text-align: right;
+ cursor: pointer;
+}
+
+.ig-ins-type {
+ text-align: right;
+}
+
+.ig-ins-samples {
+ font-size: 0.875em;
+ text-align: right;
+ cursor: pointer;
+}
+
+.ig-use {
+ padding: 0 0.25em;
+ border-radius: 2px;
+ cursor: pointer;
+}
+
+.ig-edge-label {
+ position: absolute;
+ font-size: 0.8em;
+ line-height: 1;
+ bottom: -1em;
+ padding-left: 4px;
+}
+
+.ig-ins-att-RecoveredOnBailout {
+ color: var(--ig-rob-color);
+}
+
+.ig-ins-att-Movable {
+ color: var(--ig-movable-color);
+}
+
+.ig-ins-att-Guard {
+ text-decoration: underline;
+}
+
+.ig-ins-att-InWorklist {
+ color: var(--ig-in-worklist-color);
+}
+
+.ig-can-flash {
+ transition: outline-color 1s ease-out;
+ outline: 3px solid color-mix(in srgb, var(--ig-flash-color) 0%, transparent);
+}
+
+.ig-flash {
+ transition: outline-color 0s;
+ outline-color: var(--ig-flash-color);
+}
+
+.ig-hotness {
+ --ig-hotness: 0;
+
+ --ig-cold-color: color-mix(in srgb, var(--ig-cool-color) 20%, transparent);
+ background-color:
+ /* cool <-> hot */
+ color-mix(in oklab,
+ /* cold <-> cool */
+ color-mix(in oklab,
+ /* dead or cold */
+ color-mix(in srgb, transparent, var(--ig-cold-color) clamp(0%, calc(var(--ig-hotness) * 100000000%), 100%)),
+ var(--ig-cool-color) clamp(0%, calc((var(--ig-hotness) / var(--ig-cool-threshold)) * 100%), 100%)),
+ var(--ig-hot-color) clamp(0%, calc(((var(--ig-hotness) - var(--ig-cool-threshold)) / (1 - var(--ig-cool-threshold))) * 100%), 100%));
+}
+
+.ig-highlight {
+ --ig-highlight-color: transparent;
+ background-color: var(--ig-highlight-color);
+}</style>
+ <style>* {
+ box-sizing: border-box;
+}
+
+:root {
+ font-size: 0.875rem;
+}
+
+body {
+ margin: 0;
+ background-color: #e5e8ea;
+ /* Font, and many other styles, taken from the Firefox Profiler/ */
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Noto Sans, Liberation Sans, Cantarell, Helvetica Neue, sans-serif;
+}
+
+#container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.tweaks-panel {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ padding: 1rem;
+ border: 1px solid black;
+ border-width: 1px 0 0 1px;
+ background-color: white;
+}</style>
+</head>
+
+<body>
+ <script>"use strict";var iongraph=(()=>{var J=Object.defineProperty;var mt=Object.getOwnPropertyDescriptor;var gt=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var bt=(a,t)=>{for(var e in t)J(a,e,{get:t[e],enumerable:!0})},kt=(a,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of gt(t))!ft.call(a,i)&&i!==e&&J(a,i,{get:()=>t[i],enumerable:!(s=mt(t,i))||s.enumerable});return a};var yt=a=>kt(J({},"__esModule",{value:!0}),a);var Yt={};bt(Yt,{StandaloneUI:()=>et,WebUI:()=>tt});function X(a){a.version===void 0&&(a.version=0);for(let t of a.functions)xt(t,a.version);return a.version=1,a}function xt(a,t){for(let e of a.passes){for(let s of e.mir.blocks)wt(s,t);for(let s of e.lir.blocks)It(s,t)}return a}function wt(a,t){t===0&&(a.ptr=(a.id??a.number)+1,a.id=a.number);for(let e of a.instructions)vt(e,t);return a}function vt(a,t){return t===0&&(a.ptr=a.id),a}function It(a,t){t===0&&(a.ptr=a.id??a.number,a.id=a.number);for(let e of a.instructions)Lt(e,t);return a}function Lt(a,t){return t===0&&(a.ptr=a.id,a.mirPtr=null),a}function q(a,t,e){return Math.max(t,Math.min(e,a))}function R(a,t,e,s){return(a-t)*Math.pow(e,s)+t}function k(a,t,e=!1){if(!a)if(e)console.error(t??"Assertion failed");else throw new Error(t??"Assertion failed")}function L(a,t){return k(a,t),a}function Pt(a){return typeof a=="string"?document.createTextNode(a):a}function Bt(a,t){for(let e of t)e&&a.appendChild(Pt(e))}function x(a,t,e,s){let i=document.createElement(a);if(t&&t.length>0){let c=t.filter(l=>!!l);i.classList.add(...c)}return e?.(i),s&&Bt(i,s),i}var st=Object.prototype.hasOwnProperty;function E(a,t){var e,s;if(a===t)return!0;if(a&&t&&(e=a.constructor)===t.constructor){if(e===Date)return a.getTime()===t.getTime();if(e===RegExp)return a.toString()===t.toString();if(e===Array){if((s=a.length)===t.length)for(;s--&&E(a[s],t[s]););return s===-1}if(!e||typeof a=="object"){s=0;for(e in a)if(st.call(a,e)&&++s&&!st.call(t,e)||!(e in t)||!E(a[e],t[e]))return!1;return Object.keys(t).length===s}}return a!==a&&t!==t}function N(a,t,e={}){let s=t,i=[],c={get(){return s},set(l){s=l;for(let o of i)o(s)},valueOf(){return s},toString(){return String(s)},[Symbol.toPrimitive](l){return l==="string"?String(s):s},onChange(l){i.push(l)},initial:t,name:a,min:e.min??0,max:e.max??100,step:e.step??1};return(e.tweaksObject??K).add(c)}var F=class{constructor(t){this.container=t.container,this.tweaks=[],this.callbacks=[]}add(t){let e=this.tweaks.find(r=>r.name===t.name);if(e)return e;this.tweaks.push(t);let s=document.createElement("div");this.container.appendChild(s),s.style.display="flex",s.style.alignItems="center",s.style.justifyContent="end",s.style.gap="0.5rem";let i=t.name.replace(/[a-zA-Z0-9]/g,"_"),c=document.createElement("label");s.appendChild(c),c.innerText=t.name,c.htmlFor=`tweak-${i}-input`;let l=document.createElement("input");s.appendChild(l),l.type="number",l.value=String(t),l.id=`tweak-${i}-input`,l.style.width="4rem",l.addEventListener("input",()=>{t.set(l.valueAsNumber)});let o=document.createElement("input");s.appendChild(o),o.type="range",o.value=String(t),o.min=String(t.min),o.max=String(t.max),o.step=t.step===0?"any":String(t.step),o.addEventListener("input",()=>{t.set(o.valueAsNumber)});let n=document.createElement("button");return s.appendChild(n),n.innerText="Reset",n.disabled=t.get()===t.initial,n.addEventListener("click",()=>{t.set(t.initial)}),t.onChange(r=>{l.value=String(r),o.value=String(r),n.disabled=t.get()===t.initial;for(let d of this.callbacks)d(t)}),t}onTweak(t){this.callbacks.push(t)}},nt=document.createElement("div");nt.classList.add("tweaks-panel");var K=new F({container:nt});K.onTweak(a=>{window.dispatchEvent(new CustomEvent("tweak",{detail:a}))});window.tweaks=K;var Nt=document.createElement("div"),St=new F({container:Nt}),ot=N("Test Value",3,{tweaksObject:St});ot.set(4);ot=4;var dt=N("Debug?",0,{min:0,max:1}),P=20,C=44,I=16,S=60,T=12,H=36,it=16,D=16,Tt=N("Layout Iterations",2,{min:0,max:6}),rt=N("Nearly Straight Threshold",30,{min:0,max:200}),$t=N("Nearly Straight Iterations",8,{min:0,max:10}),at=N("Stop At Pass",30,{min:0,max:30}),Mt=1.5,Et=.01,Ct=1,Ht=.1,z=40;function _(a){return a.mir.attributes.includes("loopheader")}function Dt(a){return a.loopHeight!==void 0}function $(a){if(k(a),Dt(a))return a;throw new Error(`Block ${a.id} is not a pseudo LoopHeader`)}var j=1,lt=2,U=4,O=0,W=1,w=new Proxy(console,{get(a,t){let e=a[t];return typeof e!="function"?e:+dt?e.bind(a):()=>{}}}),V=class{constructor(t,e,s={}){this.viewport=t;let i=t.getBoundingClientRect();this.viewportSize={x:i.width,y:i.height},this.graphContainer=document.createElement("div"),this.graphContainer.classList.add("ig-graph"),this.graphContainer.style.transformOrigin="top left",this.viewport.appendChild(this.graphContainer),this.sampleCounts=s.sampleCounts,this.maxSampleCounts=[0,0],this.heatmapMode=O;for(let[n,r]of this.sampleCounts?.totalLineHits??[])this.maxSampleCounts[O]=Math.max(this.maxSampleCounts[O],r);for(let[n,r]of this.sampleCounts?.selfLineHits??[])this.maxSampleCounts[W]=Math.max(this.maxSampleCounts[W],r);this.size={x:0,y:0},this.numLayers=0,this.zoom=1,this.translation={x:0,y:0},this.animating=!1,this.targetZoom=1,this.targetTranslation={x:0,y:0},this.startMousePos={x:0,y:0},this.lastMousePos={x:0,y:0},this.selectedBlockPtrs=new Set,this.lastSelectedBlockPtr=0,this.nav={visited:[],currentIndex:-1,siblings:[]},this.highlightedInstructions=[],this.instructionPalette=s.instructionPalette??[0,1,2,3,4].map(n=>`var(--ig-highlight-${n})`),this.blocks=e.mir.blocks.map(n=>{let r={ptr:n.ptr,id:n.id,mir:n,lir:e.lir.blocks.find(d=>d.id===n.id)??null,preds:[],succs:[],el:void 0,size:{x:0,y:0},layer:-1,loopID:-1,layoutNode:void 0};if(r.mir.attributes.includes("loopheader")){let d=r;d.loopHeight=0,d.parentLoop=null,d.outgoingEdges=[]}return k(r.ptr,"blocks must always have non-null ptrs"),r}),this.blocksByID=new Map,this.blocksByPtr=new Map,this.insPtrsByID=new Map,this.insIDsByPtr=new Map,this.loops=[];for(let n of this.blocks){this.blocksByID.set(n.id,n),this.blocksByPtr.set(n.ptr,n);for(let r of n.mir.instructions)this.insPtrsByID.set(r.id,r.ptr),this.insIDsByPtr.set(r.ptr,r.id);if(n.lir)for(let r of n.lir.instructions)this.insPtrsByID.set(r.id,r.ptr),this.insIDsByPtr.set(r.ptr,r.id)}for(let n of this.blocks)if(n.preds=n.mir.predecessors.map(r=>L(this.blocksByID.get(r))),n.succs=n.mir.successors.map(r=>L(this.blocksByID.get(r))),_(n)){let r=n.preds.filter(d=>d.mir.attributes.includes("backedge"));k(r.length===1),n.backedge=r[0]}for(let n of this.blocks)n.el=this.renderBlock(n);for(let n of this.blocks)n.size={x:n.el.clientWidth,y:n.el.clientHeight};let[c,l,o]=this.layout();this.render(c,l,o),this.addEventListeners()}layout(){let[t,e]=this.findLayoutRoots();w.log("Layout roots:",t.map(l=>l.id));for(let l of[...t,...e]){let o=l;o.loopHeight=0,o.parentLoop=null,o.outgoingEdges=[],Object.defineProperty(o,"backedge",{get(){throw new Error("Accessed .backedge on a pseudo loop header! Don't do that.")},configurable:!0})}for(let l of t)w.group("findLoops"),this.findLoops(l),w.groupEnd();for(let l of t)w.group("layer"),this.layer(l),w.groupEnd();for(let l of e)l.layer=0,l.loopID=l.id;let s=this.makeLayoutNodes();this.straightenEdges(s);let i=this.finagleJoints(s),c=this.verticalize(s,i);return[s,c,i]}findLayoutRoots(){let t=[],e=[],s=this.blocks.filter(i=>i.preds.length===0);for(let i of s){let c=i;if(i.mir.attributes.includes("osr")){k(i.succs.length>0);let l=i.succs[0];c=l;for(let o=0;;o++){if(o>=1e7)throw new Error("likely infinite loop");let n=c.preds.filter(r=>!r.mir.attributes.includes("osr")&&!r.mir.attributes.includes("backedge"));if(n.length===0)break;c=n[0]}c!==l?e.push(i):c=i}t.includes(c)||t.push(c)}return[t,e]}findLoops(t,e=null){if(e===null&&(e=[t.id]),!(t.loopID>=0)){if(w.log("block:",t.id,t.mir.loopDepth,"loopIDsByDepth:",e),w.log(t.mir.attributes),_(t)){let s=e[e.length-1],i=$(this.blocksByID.get(s));t.parentLoop=i,e=[...e,t.id],w.log("Block",t.id,"is true loop header, loopIDsByDepth is now",e)}if(t.mir.loopDepth>e.length-1&&(t.mir.loopDepth=e.length-1,w.log("Block",t.id,"has been forced back to loop depth",t.mir.loopDepth)),t.mir.loopDepth<e.length-1&&(e=e.slice(0,t.mir.loopDepth+1),w.log("Block",t.id,"has low loop depth, therefore we exited a loop. loopIDsByDepth:",e)),t.loopID=e[t.mir.loopDepth],!t.mir.attributes.includes("backedge"))for(let s of t.succs)this.findLoops(s,e)}}layer(t,e=0){if(w.log("block",t.id,"layer",e),t.mir.attributes.includes("backedge")){t.layer=t.succs[0].layer;return}if(e<=t.layer)return;t.layer=Math.max(t.layer,e),this.numLayers=Math.max(t.layer+1,this.numLayers);let s=$(this.blocksByID.get(t.loopID));for(;s;)s.loopHeight=Math.max(s.loopHeight,t.layer-s.layer+1),s=s.parentLoop;for(let i of t.succs)i.mir.loopDepth<t.mir.loopDepth?$(this.blocksByID.get(t.loopID)).outgoingEdges.push(i):this.layer(i,e+1);if(_(t))for(let i of t.outgoingEdges)this.layer(i,e+t.loopHeight)}makeLayoutNodes(){w.group("makeLayoutNodes");function t(o,n,r){o.dstNodes[n]=r,r.srcNodes.includes(o)||r.srcNodes.push(o),w.log("connected",o.id,"to",r.id)}let e;{let o={};for(let n of this.blocks)o[n.layer]||(o[n.layer]=[]),o[n.layer].push(n);e=Object.entries(o).map(([n,r])=>[Number(n),r]).sort((n,r)=>n[0]-r[0]).map(([n,r])=>r)}let s=0,i=e.map(()=>[]),c=[],l=new Map;for(let[o,n]of e.entries()){w.group("layer",o,"blocks",n.map(u=>u.id));let r=[];for(let u of n)for(let h=c.length-1;h>=0;h--){let p=c[h];p.dstBlock===u&&(r.unshift(p),c.splice(h,1))}let d=new Map;for(let u of c){let h,p=d.get(u.dstBlock.id);if(p)t(u.src,u.srcPort,p),h=p;else{let m={id:s++,pos:{x:P,y:P},size:{x:0,y:0},block:null,srcNodes:[],dstNodes:[],dstBlock:u.dstBlock,jointOffsets:[],flags:0};t(u.src,u.srcPort,m),i[o].push(m),d.set(u.dstBlock.id,m),h=m,w.log("Created dummy",h.id,"on the way to block",u.dstBlock.id)}u.src=h,u.srcPort=0}let b=[];for(let u of n){let h=$(this.blocksByID.get(u.loopID));for(;_(h);){let p=b.find(f=>f.loopID===h.id);p?p.block=u:b.push({loopID:h.id,block:u});let m=h.parentLoop;if(!m)break;h=m}}let g=[];for(let u of n){let h={id:s++,pos:{x:P,y:P},size:u.size,block:u,srcNodes:[],dstNodes:[],jointOffsets:[],flags:0};for(let p of r)p.dstBlock===u&&t(p.src,p.srcPort,h);i[o].push(h),u.layoutNode=h;for(let p of b.filter(m=>m.block===u)){let m=$(this.blocksByID.get(p.loopID)).backedge,f={id:s++,pos:{x:P,y:P},size:{x:0,y:0},block:null,srcNodes:[],dstNodes:[],dstBlock:m,jointOffsets:[],flags:0},y=l.get(m);y?t(f,0,y):(f.flags|=U,t(f,0,m.layoutNode)),i[o].push(f),l.set(m,f)}if(u.mir.attributes.includes("backedge"))t(u.layoutNode,0,u.succs[0].layoutNode);else for(let[p,m]of u.succs.entries())m.mir.attributes.includes("backedge")?g.push({src:h,srcPort:p,dstBlock:m}):c.push({src:h,srcPort:p,dstBlock:m})}for(let u of g){let h=L(l.get(u.dstBlock));t(u.src,u.srcPort,h)}w.groupEnd()}w.log("Pruning backedge dummies");{let o=[];for(let r of At(i))r.srcNodes.length===0&&o.push(r);let n=new Set;for(let r of o){let d=r;for(;d.block===null&&d.srcNodes.length===0;)Ot(d),n.add(d),k(d.dstNodes.length===1),d=d.dstNodes[0]}for(let r of i)for(let d=r.length-1;d>=0;d--)n.has(r[d])&&r.splice(d,1)}w.log("Marking leftmost and rightmost dummies");for(let o of i){for(let n=0;n<o.length&&o[n].block===null;n++)o[n].flags|=j;for(let n=o.length-1;n>=0&&o[n].block===null;n--)o[n].flags|=lt}w.log("Verifying integrity of all nodes");for(let o of i)for(let n of o){n.block?k(n.dstNodes.length===n.block.succs.length,`expected node ${n.id} for block ${n.block.id} to have ${n.block.succs.length} destination nodes, but got ${n.dstNodes.length} instead`):k(n.dstNodes.length===1,`expected dummy node ${n.id} to have only one destination node, but got ${n.dstNodes.length} instead`);for(let r=0;r<n.dstNodes.length;r++)k(n.dstNodes[r]!==void 0,`dst slot ${r} of node ${n.id} was undefined`)}return w.groupEnd(),i}straightenEdges(t){let e=g=>{for(let u=0;u<g.length-1;u++){let h=g[u],p=g[u+1],m=h.block===null&&p.block!==null,f=h.pos.x+h.size.x+(m?I:0)+C;p.pos.x=Math.max(p.pos.x,f)}},s=()=>{for(let g of t)for(let u of g){if(u.block===null)continue;let h=u.block.loopID!==null?$(this.blocksByID.get(u.block.loopID)):null;if(h){let p=h.layoutNode;u.pos.x=Math.max(u.pos.x,p.pos.x)}}},i=()=>{let g=new Map;for(let u of Q(t)){let h=u.dstBlock,p=u.pos.x;g.set(h,Math.max(g.get(h)??0,p))}for(let u of Q(t)){let h=u.dstBlock,p=g.get(h);k(p,`no position for backedge ${h.id}`),u.pos.x=p}for(let u of t)e(u)},c=()=>{let g=new Map;for(let u of t){let h=0,p=0;for(;h<u.length;h++)if(!(u[h].flags&j)){p=u[h].pos.x;break}for(h-=1,p-=C+I;h>=0;h--){let m=u[h];k(m.block===null&&m.flags&j);let f=p;for(let y of m.srcNodes){let v=y.pos.x+y.dstNodes.indexOf(m)*S;v<f&&(f=v)}m.pos.x=f,p=m.pos.x-C,g.set(m.dstBlock,Math.min(g.get(m.dstBlock)??1/0,f))}}for(let u of Q(t)){if(!(u.flags&j))continue;let h=g.get(u.dstBlock);k(h,`no position for run to block ${u.dstBlock.id}`),u.pos.x=h}},l=()=>{for(let g=0;g<t.length-1;g++){let u=t[g];e(u);let h=-1;for(let p of u)for(let[m,f]of p.dstNodes.entries()){let y=t[g+1].indexOf(f);if(y>h&&f.srcNodes[0]===p){let v=I+S*m,B=I,Z=f.pos.x;f.pos.x=Math.max(f.pos.x,p.pos.x+v-B),f.pos.x!==Z&&(h=y)}}}},o=()=>{for(let g of t){for(let u=g.length-1;u>=0;u--){let h=g[u];if(!h.block||h.block.mir.attributes.includes("backedge"))continue;let p=[];for(let m of h.srcNodes){let f=I+m.dstNodes.indexOf(h)*S,y=I;p.push(m.pos.x+f-(h.pos.x+y))}for(let[m,f]of h.dstNodes.entries()){if(f.block===null&&f.dstBlock.mir.attributes.includes("backedge"))continue;let y=I+m*S,v=I;p.push(f.pos.x+v-(h.pos.x+y))}if(!p.includes(0)){p=p.filter(m=>m>0).sort((m,f)=>m-f);for(let m of p){let f=!1;for(let y=u+1;y<g.length;y++){let v=g[y];if(v.flags&lt)continue;let B=h.pos.x+m,Z=h.pos.x+m+h.size.x,ht=v.pos.x-C,pt=v.pos.x+v.size.x+C;Z>=ht&&B<=pt&&(f=!0)}if(!f){h.pos.x+=m;break}}}}e(g)}},n=()=>{for(let g=t.length-1;g>=0;g--){let u=t[g];e(u);for(let h of u)for(let p of h.srcNodes){if(p.block!==null)continue;Math.abs(p.pos.x-h.pos.x)<=rt&&(p.pos.x=Math.max(p.pos.x,h.pos.x),h.pos.x=Math.max(p.pos.x,h.pos.x))}}},r=()=>{for(let g=0;g<t.length;g++){let u=t[g];e(u);for(let h of u){if(h.dstNodes.length===0)continue;let p=h.dstNodes[0];if(p.block!==null)continue;Math.abs(p.pos.x-h.pos.x)<=rt&&(p.pos.x=Math.max(p.pos.x,h.pos.x),h.pos.x=Math.max(p.pos.x,h.pos.x))}}};function d(g,u){let h=[];for(let p=0;p<u;p++)for(let m of g)h.push(m);return h}let b=[...d([l,s,i],Tt),i,...d([n,r],$t),o,i,c];k(b.length<=(at.initial??1/0),`STOP_AT_PASS was too small - should be at least ${b.length}`),w.group("Running passes");for(let[g,u]of b.entries())g<at&&(w.log(u.name??u.toString()),u());w.groupEnd()}finagleJoints(t){let e=[];for(let s of t){let i=[];for(let r of s)if(r.jointOffsets=new Array(r.dstNodes.length).fill(0),!r.block?.mir.attributes.includes("backedge"))for(let[d,b]of r.dstNodes.entries()){let g=r.pos.x+I+S*d,u=b.pos.x+I;Math.abs(u-g)<2*T||i.push({x1:g,x2:u,src:r,srcPort:d,dst:b})}i.sort((r,d)=>r.x1-d.x1);let c=[],l=[];t:for(let r of i){let d=r.x2-r.x1>=0?c:l,b=null;for(let g=d.length-1;g>=0;g--){let u=d[g],h=!1;for(let p of u){if(r.dst===p.dst){u.push(r);continue t}let m=Math.min(r.x1,r.x2),f=Math.max(r.x1,r.x2),y=Math.min(p.x1,p.x2),v=Math.max(p.x1,p.x2);if(f>=y&&m<=v){h=!0;break}}if(h)break;b=u}b?b.push(r):d.push([r])}let o=Math.max(0,c.length+l.length-1)*it,n=-o/2;for(let r of[...c.reverse(),...l]){for(let d of r)d.src.jointOffsets[d.srcPort]=n;n+=it}e.push(o)}return k(e.length===t.length),e}verticalize(t,e){let s=new Array(t.length),i=P;for(let c=0;c<t.length;c++){let l=t[c],o=0;for(let n of l)n.pos.y=i,o=Math.max(o,n.size.y);s[c]=o,i+=o+H+e[c]+H}return s}renderBlock(t){let e=document.createElement("div");this.graphContainer.appendChild(e),e.classList.add("ig-block","ig-bg-white");for(let o of t.mir.attributes)e.classList.add(`ig-block-att-${o}`);e.setAttribute("data-ig-block-ptr",`${t.ptr}`),e.setAttribute("data-ig-block-id",`${t.id}`);let s="";t.mir.attributes.includes("loopheader")?s=" (loop header)":t.mir.attributes.includes("backedge")?s=" (backedge)":t.mir.attributes.includes("splitedge")&&(s=" (split edge)");let i=document.createElement("div");i.classList.add("ig-block-header"),i.innerText=`Block ${t.id}${s}`,e.appendChild(i);let c=document.createElement("div");c.classList.add("ig-instructions"),e.appendChild(c);let l=document.createElement("table");if(t.lir){l.innerHTML=`
+ <colgroup>
+ <col style="width: 1px">
+ <col style="width: auto">
+ ${this.sampleCounts?`
+ <col style="width: 1px">
+ <col style="width: 1px">
+ `:""}
+ </colgroup>
+ ${this.sampleCounts?`
+ <thead>
+ <tr>
+ <th></th>
+ <th></th>
+ <th class="ig-f6">Total</th>
+ <th class="ig-f6">Self</th>
+ </tr>
+ </thead>
+ `:""}
+ `;for(let o of t.lir.instructions)l.appendChild(this.renderLIRInstruction(o))}else{l.innerHTML=`
+ <colgroup>
+ <col style="width: 1px">
+ <col style="width: auto">
+ <col style="width: 1px">
+ </colgroup>
+ `;for(let o of t.mir.instructions)l.appendChild(this.renderMIRInstruction(o))}if(c.appendChild(l),t.succs.length===2)for(let[o,n]of[1,0].entries()){let r=document.createElement("div");r.innerText=`${n}`,r.classList.add("ig-edge-label"),r.style.left=`${I+S*o}px`,e.appendChild(r)}return i.addEventListener("pointerdown",o=>{o.preventDefault(),o.stopPropagation()}),i.addEventListener("click",o=>{o.stopPropagation(),o.shiftKey||this.selectedBlockPtrs.clear(),this.setSelection([],t.ptr)}),e}render(t,e,s){for(let n of t)for(let r of n)if(r.block!==null){let d=r.block;d.el.style.left=`${r.pos.x}px`,d.el.style.top=`${r.pos.y}px`}let i=0,c=0;for(let n of t)for(let r of n)i=Math.max(i,r.pos.x+r.size.x+P),c=Math.max(c,r.pos.y+r.size.y+P);let l=document.createElementNS("http://www.w3.org/2000/svg","svg");this.graphContainer.appendChild(l);let o=(n,r)=>{for(let d of n)i=Math.max(i,d+P);for(let d of r)c=Math.max(c,d+P)};for(let n=0;n<t.length;n++){let r=t[n];for(let d of r){d.block||k(d.dstNodes.length===1,`dummy nodes must have exactly one destination, but dummy ${d.id} had ${d.dstNodes.length}`),k(d.dstNodes.length===d.jointOffsets.length,"must have a joint offset for each destination");for(let[b,g]of d.dstNodes.entries()){let u=d.pos.x+I+S*b,h=d.pos.y+d.size.y;if(d.block?.mir.attributes.includes("backedge")){let p=d.block.succs[0],m=d.pos.x,f=d.pos.y+D,y=p.layoutNode.pos.x+p.size.x,v=p.layoutNode.pos.y+D,B=jt(m,f,y,v);l.appendChild(B),o([m,y],[f,v])}else if(d.flags&U){let p=L(g.block),m=d.pos.x+I,f=d.pos.y+D+T,y=p.layoutNode.pos.x+p.size.x,v=p.layoutNode.pos.y+D,B=zt(m,f,y,v);l.appendChild(B),o([m,y],[f,v])}else if(g.block===null&&g.dstBlock.mir.attributes.includes("backedge")){let p=g.pos.x+I,m=g.pos.y+(g.flags&U?D+T:0);if(d.block===null){let f=h-H,y=Ft(u,h,p,m,f,!1);l.appendChild(y),o([u,p],[h,m,f])}else{let f=h-d.size.y+e[n]+H+s[n]/2+d.jointOffsets[b],y=_t(u,h,p,m,f);l.appendChild(y),o([u,p],[h,m,f])}}else{let p=g.pos.x+I,m=g.pos.y,f=h-d.size.y+e[n]+H+s[n]/2+d.jointOffsets[b],y=Rt(u,h,p,m,f,g.block!==null);l.appendChild(y),o([u,p],[h,m,f])}}}}if(l.setAttribute("width",`${i}`),l.setAttribute("height",`${c}`),this.size={x:i,y:c},+dt)for(let n of t)for(let r of n){let d=document.createElement("div");d.innerHTML=`${r.id}<br>&lt;- ${r.srcNodes.map(b=>b.id)}<br>-&gt; ${r.dstNodes.map(b=>b.id)}<br>${r.flags}`,d.style.position="absolute",d.style.border="1px solid black",d.style.backgroundColor="white",d.style.left=`${r.pos.x}px`,d.style.top=`${r.pos.y}px`,d.style.whiteSpace="nowrap",this.graphContainer.appendChild(d)}this.updateHighlightedInstructions(),this.updateHotness()}renderMIRInstruction(t){let e=t.opcode.replace("->","\u2192").replace("<-","\u2190"),s=document.createElement("tr");s.classList.add("ig-ins","ig-ins-mir","ig-can-flash",...t.attributes.map(o=>`ig-ins-att-${o}`)),s.setAttribute("data-ig-ins-ptr",`${t.ptr}`),s.setAttribute("data-ig-ins-id",`${t.id}`);let i=document.createElement("td");i.classList.add("ig-ins-num"),i.innerText=`v${t.id}`,s.appendChild(i);let c=document.createElement("td");c.innerHTML=e.replace(/(v)(\d+)/g,(o,n,r)=>`<span class="ig-use ig-highlightable" data-ig-use="${r}">${n}${r}</span>`),s.appendChild(c);let l=document.createElement("td");return l.classList.add("ig-ins-type"),l.innerText=t.type==="None"?"":t.type,s.appendChild(l),i.addEventListener("pointerdown",o=>{o.preventDefault(),o.stopPropagation()}),i.addEventListener("click",()=>{this.toggleInstructionHighlight(t.ptr)}),c.querySelectorAll(".ig-use").forEach(o=>{o.addEventListener("pointerdown",n=>{n.preventDefault(),n.stopPropagation()}),o.addEventListener("click",n=>{let r=parseInt(L(o.getAttribute("data-ig-use")),10);this.jumpToInstruction(r,{zoom:1})})}),s}renderLIRInstruction(t){let e=t.opcode.replace("->","\u2192").replace("<-","\u2190"),s=document.createElement("tr");s.classList.add("ig-ins","ig-ins-lir","ig-hotness"),s.setAttribute("data-ig-ins-ptr",`${t.ptr}`),s.setAttribute("data-ig-ins-id",`${t.id}`);let i=document.createElement("td");i.classList.add("ig-ins-num"),i.innerText=String(t.id),s.appendChild(i);let c=document.createElement("td");if(c.innerText=e,s.appendChild(c),this.sampleCounts){let l=this.sampleCounts?.totalLineHits.get(t.id)??0,o=this.sampleCounts?.selfLineHits.get(t.id)??0,n=document.createElement("td");n.classList.add("ig-ins-samples"),n.classList.toggle("ig-text-dim",l===0),n.innerText=`${l}`,n.title="Color by total count",s.appendChild(n);let r=document.createElement("td");r.classList.add("ig-ins-samples"),r.classList.toggle("ig-text-dim",o===0),r.innerText=`${o}`,r.title="Color by self count",s.appendChild(r);for(let[d,b]of[n,r].entries())b.addEventListener("pointerdown",g=>{g.preventDefault(),g.stopPropagation()}),b.addEventListener("click",()=>{k(d===O||d===W),this.heatmapMode=d,this.updateHotness()})}return i.addEventListener("pointerdown",l=>{l.preventDefault(),l.stopPropagation()}),i.addEventListener("click",()=>{this.toggleInstructionHighlight(t.ptr)}),s}renderSelection(){this.graphContainer.querySelectorAll(".ig-block").forEach(t=>{let e=parseInt(L(t.getAttribute("data-ig-block-ptr")),10);t.classList.toggle("ig-selected",this.selectedBlockPtrs.has(e)),t.classList.toggle("ig-last-selected",this.lastSelectedBlockPtr===e)})}removeNonexistentHighlights(){this.highlightedInstructions=this.highlightedInstructions.filter(t=>this.graphContainer.querySelector(`.ig-ins[data-ig-ins-ptr="${t.ptr}"]`))}updateHighlightedInstructions(){for(let t of this.highlightedInstructions)k(this.highlightedInstructions.filter(e=>e.ptr===t.ptr).length===1,`instruction ${t.ptr} was highlighted more than once`);this.graphContainer.querySelectorAll(".ig-ins, .ig-use").forEach(t=>{Vt(t)});for(let t of this.highlightedInstructions){let e=this.instructionPalette[t.paletteColor%this.instructionPalette.length],s=this.graphContainer.querySelector(`.ig-ins[data-ig-ins-ptr="${t.ptr}"]`);if(s){ct(s,e);let i=this.insIDsByPtr.get(t.ptr);this.graphContainer.querySelectorAll(`.ig-use[data-ig-use="${i}"]`).forEach(c=>{ct(c,e)})}}}updateHotness(){this.graphContainer.querySelectorAll(".ig-ins-lir").forEach(t=>{k(t.classList.contains("ig-hotness"));let e=parseInt(L(t.getAttribute("data-ig-ins-id")),10),s=0;this.sampleCounts&&(s=((this.heatmapMode===O?this.sampleCounts.totalLineHits:this.sampleCounts.selfLineHits).get(e)??0)/this.maxSampleCounts[this.heatmapMode]),t.style.setProperty("--ig-hotness",`${s}`)})}addEventListeners(){this.viewport.addEventListener("wheel",e=>{e.preventDefault();let s=this.zoom;if(e.ctrlKey){s=Math.max(Ht,Math.min(Ct,this.zoom*Math.pow(Mt,-e.deltaY*Et)));let c=s/this.zoom-1;this.zoom=s;let{x:l,y:o}=this.viewport.getBoundingClientRect(),n=e.clientX-l-this.translation.x,r=e.clientY-o-this.translation.y;this.translation.x-=n*c,this.translation.y-=r*c}else this.translation.x-=e.deltaX,this.translation.y-=e.deltaY;let i=this.clampTranslation(this.translation,s);this.translation.x=i.x,this.translation.y=i.y,this.animating=!1,this.updatePanAndZoom()}),this.viewport.addEventListener("pointerdown",e=>{e.pointerType==="mouse"&&!(e.button===0||e.button===1)||(e.preventDefault(),this.viewport.setPointerCapture(e.pointerId),this.startMousePos={x:e.clientX,y:e.clientY},this.lastMousePos={x:e.clientX,y:e.clientY},this.animating=!1)}),this.viewport.addEventListener("pointermove",e=>{if(!this.viewport.hasPointerCapture(e.pointerId))return;let s=e.clientX-this.lastMousePos.x,i=e.clientY-this.lastMousePos.y;this.translation.x+=s,this.translation.y+=i,this.lastMousePos={x:e.clientX,y:e.clientY};let c=this.clampTranslation(this.translation,this.zoom);this.translation.x=c.x,this.translation.y=c.y,this.animating=!1,this.updatePanAndZoom()}),this.viewport.addEventListener("pointerup",e=>{this.viewport.releasePointerCapture(e.pointerId);let s=2,i=this.startMousePos.x-e.clientX,c=this.startMousePos.y-e.clientY;Math.abs(i)<=s&&Math.abs(c)<=s&&this.setSelection([]),this.animating=!1}),new ResizeObserver(e=>{k(e.length===1);let s=e[0].contentRect;this.viewportSize.x=s.width,this.viewportSize.y=s.height}).observe(this.viewport)}setSelection(t,e=0){this.setSelectionRaw(t,e),e?this.nav={visited:[e],currentIndex:0,siblings:[e]}:this.nav={visited:[],currentIndex:-1,siblings:[]}}setSelectionRaw(t,e){this.selectedBlockPtrs.clear();for(let s of[...t,e])this.blocksByPtr.has(s)&&this.selectedBlockPtrs.add(s);this.lastSelectedBlockPtr=this.blocksByPtr.has(e)?e:0,this.renderSelection()}navigate(t){let e=this.lastSelectedBlockPtr;if(t==="down"||t==="up")if(e){let s=L(this.blocksByPtr.get(e)),i=(t==="down"?s.succs:s.preds).map(l=>l.ptr);s.ptr!==this.nav.visited[this.nav.currentIndex]&&(this.nav.visited=[s.ptr],this.nav.currentIndex=0);let c=this.nav.currentIndex+(t==="down"?1:-1);if(0<=c&&c<this.nav.visited.length)this.nav.currentIndex=c,this.nav.siblings=i;else{let l=i[0];l!==void 0&&(t==="down"?(this.nav.visited.push(l),this.nav.currentIndex+=1,k(this.nav.currentIndex===this.nav.visited.length-1)):(this.nav.visited.unshift(l),k(this.nav.currentIndex===0)),this.nav.siblings=i)}this.setSelectionRaw([],this.nav.visited[this.nav.currentIndex])}else{let s=[...this.blocks].sort((n,r)=>n.id-r.id),i=s.filter(n=>n.preds.length===0),c=s.filter(n=>n.succs.length===0),l=t==="down"?i:c,o=l[0];k(o),this.setSelectionRaw([],o.ptr),this.nav={visited:[o.ptr],currentIndex:0,siblings:l.map(n=>n.ptr)}}else if(e!==void 0){let s=this.nav.siblings.indexOf(e);k(s>=0,"currently selected node should be in siblings array");let i=s+(t==="right"?1:-1);0<=i&&i<this.nav.siblings.length&&this.setSelectionRaw([],this.nav.siblings[i])}k(this.nav.visited.length===0||this.nav.siblings.includes(this.nav.visited[this.nav.currentIndex]),"expected currently visited node to be in the siblings array"),k(this.lastSelectedBlockPtr===0||this.nav.siblings.includes(this.lastSelectedBlockPtr),"expected currently selected block to be in siblings array")}toggleInstructionHighlight(t,e){this.removeNonexistentHighlights();let s=this.highlightedInstructions.findIndex(c=>c.ptr===t),i=s>=0;if(e!==void 0&&(i=!e),i)s>=0&&this.highlightedInstructions.splice(s,1);else if(s<0){let c=0;for(;;){if(this.highlightedInstructions.find(l=>l.paletteColor===c)){c+=1;continue}break}this.highlightedInstructions.push({ptr:t,paletteColor:c})}this.updateHighlightedInstructions()}clampTranslation(t,e){let s=z-this.size.x*e,i=this.viewportSize.x-z,c=z-this.size.y*e,l=this.viewportSize.y-z,o=q(t.x,s,i),n=q(t.y,c,l);return{x:o,y:n}}updatePanAndZoom(){let t=this.clampTranslation(this.translation,this.zoom);this.graphContainer.style.transform=`translate(${t.x}px, ${t.y}px) scale(${this.zoom})`}graph2viewport(t,e=this.translation,s=this.zoom){return{x:t.x*s+e.x,y:t.y*s+e.y}}viewport2graph(t,e=this.translation,s=this.zoom){return{x:(t.x-e.x)/s,y:(t.y-e.y)/s}}async goToGraphCoordinates(t,{zoom:e=this.zoom,animate:s=!0}){let i={x:-t.x*e,y:-t.y*e};if(!s){this.animating=!1,this.translation.x=i.x,this.translation.y=i.y,this.zoom=e,this.updatePanAndZoom(),await new Promise(l=>setTimeout(l,0));return}if(this.targetTranslation=i,this.targetZoom=e,this.animating)return;this.animating=!0;let c=performance.now();for(;this.animating;){let l=await new Promise(h=>requestAnimationFrame(h)),o=(l-c)/1e3;c=l;let n=1,r=.01,d=1e-6,b=this.targetTranslation.x-this.translation.x,g=this.targetTranslation.y-this.translation.y,u=this.targetZoom-this.zoom;if(this.translation.x=R(this.translation.x,this.targetTranslation.x,d,o),this.translation.y=R(this.translation.y,this.targetTranslation.y,d,o),this.zoom=R(this.zoom,this.targetZoom,d,o),this.updatePanAndZoom(),Math.abs(b)<=n&&Math.abs(g)<=n&&Math.abs(u)<=r){this.translation.x=this.targetTranslation.x,this.translation.y=this.targetTranslation.y,this.zoom=this.targetZoom,this.animating=!1,this.updatePanAndZoom();break}}await new Promise(l=>setTimeout(l,0))}jumpToBlock(t,{zoom:e=this.zoom,animate:s=!0,viewportPos:i}={}){let c=this.blocksByPtr.get(t);if(!c)return Promise.resolve();let l;return i?l={x:c.layoutNode.pos.x-i.x/e,y:c.layoutNode.pos.y-i.y/e}:l=this.graphPosToCenterRect(c.layoutNode.pos,c.layoutNode.size,e),this.goToGraphCoordinates(l,{zoom:e,animate:s})}async jumpToInstruction(t,{zoom:e=this.zoom,animate:s=!0}){let i=this.graphContainer.querySelector(`.ig-ins[data-ig-ins-id="${t}"]`);if(!i)return;let c=i.getBoundingClientRect(),l=this.graphContainer.getBoundingClientRect(),o=(c.x-l.x)/this.zoom,n=(c.y-l.y)/this.zoom,r=c.width/this.zoom,d=c.height/this.zoom,b=this.graphPosToCenterRect({x:o,y:n},{x:r,y:d},e);i.classList.add("ig-flash"),await this.goToGraphCoordinates(b,{zoom:e,animate:s}),i.classList.remove("ig-flash")}graphPosToCenterRect(t,e,s){let i=this.viewportSize.x/s,c=this.viewportSize.y/s,l=Math.max(20/s,(i-e.x)/2),o=Math.max(20/s,(c-e.y)/2),n=t.x-l,r=t.y-o;return{x:n,y:r}}exportState(){let t={translation:this.translation,zoom:this.zoom,heatmapMode:this.heatmapMode,highlightedInstructions:this.highlightedInstructions,selectedBlockPtrs:this.selectedBlockPtrs,lastSelectedBlockPtr:this.lastSelectedBlockPtr,viewportPosOfSelectedBlock:void 0};return this.lastSelectedBlockPtr&&(t.viewportPosOfSelectedBlock=this.graph2viewport(L(this.blocksByPtr.get(this.lastSelectedBlockPtr)).layoutNode.pos)),t}restoreState(t,e){this.translation.x=t.translation.x,this.translation.y=t.translation.y,this.zoom=t.zoom,this.heatmapMode=t.heatmapMode,this.highlightedInstructions=t.highlightedInstructions,this.setSelection(Array.from(t.selectedBlockPtrs),t.lastSelectedBlockPtr),this.updatePanAndZoom(),this.updateHotness(),this.updateHighlightedInstructions(),e.preserveSelectedBlockPosition&&this.jumpToBlock(this.lastSelectedBlockPtr,{zoom:this.zoom,animate:!1,viewportPos:t.viewportPosOfSelectedBlock})}};function Ot(a){for(let t of a.dstNodes){let e=t.srcNodes.indexOf(a);k(e!==-1),t.srcNodes.splice(e,1)}}function*Q(a){for(let t of a)for(let e of t)e.block===null&&(yield e)}function*At(a){for(let t of a)for(let e of t)e.block===null&&e.dstBlock.mir.attributes.includes("backedge")&&(yield e)}function Rt(a,t,e,s,i,c,l=1){let o=T;k(t+o<=i&&i<s-o,`downward arrow: x1 = ${a}, y1 = ${t}, x2 = ${e}, y2 = ${s}, ym = ${i}, r = ${o} `,!0),l%2===1&&(a+=.5,e+=.5,i+=.5);let n="";if(n+=`M ${a} ${t} `,Math.abs(e-a)<2*o)n+=`C ${a} ${t+(s-t)/3} ${e} ${t+2*(s-t)/3} ${e} ${s} `;else{let b=Math.sign(e-a);n+=`L ${a} ${i-o} `,n+=`A ${o} ${o} 0 0 ${b>0?0:1} ${a+o*b} ${i} `,n+=`L ${e-o*b} ${i} `,n+=`A ${o} ${o} 0 0 ${b>0?1:0} ${e} ${i+o} `,n+=`L ${e} ${s} `}let r=document.createElementNS("http://www.w3.org/2000/svg","g"),d=document.createElementNS("http://www.w3.org/2000/svg","path");if(d.setAttribute("d",n),d.setAttribute("fill","none"),d.setAttribute("stroke","black"),d.setAttribute("stroke-width",`${l} `),r.appendChild(d),c){let b=G(e,s,180);r.appendChild(b)}return r}function Ft(a,t,e,s,i,c,l=1){let o=T;k(s+o<=i&&i<=t-o,`upward arrow: x1 = ${a}, y1 = ${t}, x2 = ${e}, y2 = ${s}, ym = ${i}, r = ${o} `,!0),l%2===1&&(a+=.5,e+=.5,i+=.5);let n="";if(n+=`M ${a} ${t} `,Math.abs(e-a)<2*o)n+=`C ${a} ${t+(s-t)/3} ${e} ${t+2*(s-t)/3} ${e} ${s} `;else{let b=Math.sign(e-a);n+=`L ${a} ${i+o} `,n+=`A ${o} ${o} 0 0 ${b>0?1:0} ${a+o*b} ${i} `,n+=`L ${e-o*b} ${i} `,n+=`A ${o} ${o} 0 0 ${b>0?0:1} ${e} ${i-o} `,n+=`L ${e} ${s} `}let r=document.createElementNS("http://www.w3.org/2000/svg","g"),d=document.createElementNS("http://www.w3.org/2000/svg","path");if(d.setAttribute("d",n),d.setAttribute("fill","none"),d.setAttribute("stroke","black"),d.setAttribute("stroke-width",`${l} `),r.appendChild(d),c){let b=G(e,s,0);r.appendChild(b)}return r}function zt(a,t,e,s,i=1){let c=T;k(t-c>=s&&a-c>=e,`to backedge: x1 = ${a}, y1 = ${t}, x2 = ${e}, y2 = ${s}, r = ${c} `,!0),i%2===1&&(a+=.5,s+=.5);let l="";l+=`M ${a} ${t} `,l+=`A ${c} ${c} 0 0 0 ${a-c} ${s} `,l+=`L ${e} ${s} `;let o=document.createElementNS("http://www.w3.org/2000/svg","g"),n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("d",l),n.setAttribute("fill","none"),n.setAttribute("stroke","black"),n.setAttribute("stroke-width",`${i} `),o.appendChild(n);let r=G(e,s,270);return o.appendChild(r),o}function _t(a,t,e,s,i,c=1){let l=T;k(t+l<=i&&a<=e&&s<=t,`block to backedge dummy: x1 = ${a}, y1 = ${t}, x2 = ${e}, y2 = ${s}, ym = ${i}, r = ${l} `,!0),c%2===1&&(a+=.5,e+=.5,i+=.5);let o="";o+=`M ${a} ${t} `,o+=`L ${a} ${i-l} `,o+=`A ${l} ${l} 0 0 0 ${a+l} ${i} `,o+=`L ${e-l} ${i} `,o+=`A ${l} ${l} 0 0 0 ${e} ${i-l} `,o+=`L ${e} ${s} `;let n=document.createElementNS("http://www.w3.org/2000/svg","g"),r=document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d",o),r.setAttribute("fill","none"),r.setAttribute("stroke","black"),r.setAttribute("stroke-width",`${c} `),n.appendChild(r),n}function jt(a,t,e,s,i=1){k(e<a&&s===t,`x1 = ${a}, y1 = ${t}, x2 = ${e}, y2 = ${s} `,!0),i%2===1&&(t+=.5,s+=.5);let c="";c+=`M ${a} ${t} `,c+=`L ${e} ${s} `;let l=document.createElementNS("http://www.w3.org/2000/svg","g"),o=document.createElementNS("http://www.w3.org/2000/svg","path");o.setAttribute("d",c),o.setAttribute("fill","none"),o.setAttribute("stroke","black"),o.setAttribute("stroke-width",`${i} `),l.appendChild(o);let n=G(e,s,270);return l.appendChild(n),l}function G(a,t,e,s=5){let i=document.createElementNS("http://www.w3.org/2000/svg","path");return i.setAttribute("d",`M 0 0 L ${-s} ${s*1.5} L ${s} ${s*1.5} Z`),i.setAttribute("transform",`translate(${a}, ${t}) rotate(${e})`),i}function ct(a,t){a.classList.add("ig-highlight"),a.style.setProperty("--ig-highlight-color",t)}function Vt(a){a.classList.remove("ig-highlight"),a.style.setProperty("--ig-highlight-color","transparent")}var A=class{constructor(t,{func:e,pass:s=0,sampleCounts:i}){this.graph=null,this.func=e,this.passNumber=s,this.sampleCounts=i,this.keyPasses=[null,null,null,null];{let c=null;for(let[l,o]of e.passes.entries())o.mir.blocks.length>0&&(this.keyPasses[0]===null&&(this.keyPasses[0]=l),o.lir.blocks.length===0&&(this.keyPasses[1]=l)),o.lir.blocks.length>0&&(c?.lir.blocks.length===0&&(this.keyPasses[2]=l),this.keyPasses[3]=l),c=o}this.redundantPasses=[];{let c=null;for(let[l,o]of e.passes.entries()){if(c===null){c=o;continue}E(c.mir,o.mir)&&E(c.lir,o.lir)&&this.redundantPasses.push(l),c=o}}this.viewport=x("div",["ig-flex-grow-1","ig-overflow-hidden"],c=>{c.style.position="relative"}),this.sidebarLinks=e.passes.map((c,l)=>x("a",["ig-link-normal","ig-pv1","ig-ph2","ig-flex","ig-g2"],o=>{o.href="#",o.addEventListener("click",n=>{n.preventDefault(),this.switchPass(l)})},[x("div",["ig-w1","ig-tr","ig-f6","ig-text-dim"],o=>{o.style.paddingTop="0.08rem"},[`${l}`]),x("div",[this.redundantPasses.includes(l)&&"ig-text-dim"],()=>{},[c.name])])),this.container=x("div",["ig-absolute","ig-absolute-fill","ig-flex"],()=>{},[x("div",["ig-w5","ig-br","ig-flex-shrink-0","ig-overflow-y-auto","ig-bg-white"],()=>{},[...this.sidebarLinks]),this.viewport]),t.appendChild(this.container),this.keydownHandler=this.keydownHandler.bind(this),this.tweakHandler=this.tweakHandler.bind(this),window.addEventListener("keydown",this.keydownHandler),window.addEventListener("tweak",this.tweakHandler),this.update()}destroy(){this.container.remove(),window.removeEventListener("keydown",this.keydownHandler),window.removeEventListener("tweak",this.tweakHandler)}update(){for(let[s,i]of this.sidebarLinks.entries())i.classList.toggle("ig-bg-primary",this.passNumber===s);let t=this.graph?.exportState();this.viewport.innerHTML="",this.graph=null;let e=this.func.passes[this.passNumber];if(e)try{this.graph=new V(this.viewport,e,{sampleCounts:this.sampleCounts}),t&&this.graph.restoreState(t,{preserveSelectedBlockPosition:!0})}catch(s){this.viewport.innerHTML="An error occurred while laying out the graph. See console.",console.error(s)}}switchPass(t){this.passNumber=t,this.update()}keydownHandler(t){switch(t.key){case"w":case"s":this.graph?.navigate(t.key==="s"?"down":"up"),this.graph?.jumpToBlock(this.graph.lastSelectedBlockPtr);break;case"a":case"d":this.graph?.navigate(t.key==="d"?"right":"left"),this.graph?.jumpToBlock(this.graph.lastSelectedBlockPtr);break;case"f":for(let e=this.passNumber+1;e<this.func.passes.length;e++)if(!this.redundantPasses.includes(e)){this.switchPass(e);break}break;case"r":for(let e=this.passNumber-1;e>=0;e--)if(!this.redundantPasses.includes(e)){this.switchPass(e);break}break;case"1":case"2":case"3":case"4":{let e=["1","2","3","4"].indexOf(t.key),s=this.keyPasses[e];typeof s=="number"&&this.switchPass(s)}break;case"c":{let e=this.graph?.blocksByPtr.get(this.graph?.lastSelectedBlockPtr??-1);e&&this.graph?.jumpToBlock(e.ptr,{zoom:1})}break}}tweakHandler(){this.update()}};var M=new URL(window.location.toString()).searchParams,Gt=M.has("func")?parseInt(M.get("func"),10):void 0,ut=M.has("pass")?parseInt(M.get("pass"),10):void 0,Y=class{constructor(t){this.exportButton=null,this.ionjson=null,this.funcIndex=Gt??0,this.funcSelected=t.funcSelected,this.funcSelector=x("div",[],()=>{},["Function",x("input",["ig-w3"],e=>{e.type="number",e.min="1",e.addEventListener("input",()=>{this.switchFunc(parseInt(e.value,10)-1)})},[])," / ",x("span",["num-functions"])]),this.funcSelectorNone=x("div",[],()=>{},["No functions to display."]),this.funcName=x("div"),this.root=x("div",["ig-bb","ig-flex","ig-bg-white"],()=>{},[x("div",["ig-pv2","ig-ph3","ig-flex","ig-g2","ig-items-center","ig-br","ig-hide-if-empty"],()=>{},[t.browse&&x("div",[],()=>{},[x("input",[],e=>{e.type="file",e.addEventListener("change",s=>{let i=s.target;i.files?.length&&this.fileSelected(i.files[0])})})]),this.funcSelector,this.funcSelectorNone]),x("div",["ig-flex-grow-1","ig-pv2","ig-ph3","ig-flex","ig-g2","ig-items-center"],()=>{},[this.funcName,x("div",["ig-flex-grow-1"]),t.export&&x("div",[],()=>{},[x("button",[],e=>{this.exportButton=e,e.addEventListener("click",()=>{this.exportStandalone()})},["Export"])])])]),this.update()}async fileSelected(t){let e=JSON.parse(await t.text());this.ionjson=X(e),this.switchFunc(0),this.update()}switchIonJSON(t){this.ionjson=t,this.switchFunc(this.funcIndex)}switchFunc(t){t=Math.max(0,Math.min(this.numFunctions()-1,t)),this.funcIndex=isNaN(t)?0:t,this.funcSelected(this.ionjson?.functions[this.funcIndex]??null),this.update()}numFunctions(){return this.ionjson?.functions.length??0}update(){let t=0<=this.funcIndex&&this.funcIndex<this.numFunctions();this.funcSelector.hidden=this.numFunctions()<=1,this.funcSelectorNone.hidden=!(this.ionjson&&this.numFunctions()===0);let e=this.funcSelector.querySelector("input");e.max=`${this.numFunctions()}`,e.value=`${this.funcIndex+1}`,this.funcSelector.querySelector(".num-functions").innerHTML=`${this.numFunctions()}`,this.funcName.hidden=!t,this.funcName.innerText=`${this.ionjson?.functions[this.funcIndex].name??""}`,this.exportButton&&(this.exportButton.disabled=!this.ionjson||!t)}async exportStandalone(){let t=L(this.ionjson),e=t.functions[this.funcIndex].name,s={version:1,functions:[t.functions[this.funcIndex]]},c=(await(await fetch("./standalone.html")).text()).replace(/\{\{\s*IONJSON\s*\}\}/,JSON.stringify(s)),l=URL.createObjectURL(new Blob([c],{type:"text/html;charset=utf-8"})),o=document.createElement("a");o.href=l,o.download=`iongraph-${e}.html`,document.body.appendChild(o),o.click(),o.remove(),URL.revokeObjectURL(l)}},tt=class{constructor(){this.menuBar=new Y({browse:!0,export:!0,funcSelected:t=>this.switchFunc(t)}),this.func=null,this.sampleCountsFromFile=void 0,this.graph=null,this.loadStuffFromQueryParams(),this.graphContainer=x("div",["ig-relative","ig-flex-basis-0","ig-flex-grow-1","ig-overflow-hidden"]),this.root=x("div",["ig-absolute","ig-absolute-fill","ig-flex","ig-flex-column"],()=>{},[this.menuBar.root,this.graphContainer]),this.update()}update(){this.graph&&this.graph.destroy(),this.func&&(this.graph=new A(this.graphContainer,{func:this.func,pass:ut,sampleCounts:this.sampleCountsFromFile}))}loadStuffFromQueryParams(){(async()=>{let t=M.get("file");if(t){let s=await(await fetch(t)).json(),i=X(s);this.menuBar.switchIonJSON(i)}})(),(async()=>{let t=M.get("sampleCounts");if(t){let s=await(await fetch(t)).json();this.sampleCountsFromFile={selfLineHits:new Map(s.selfLineHits),totalLineHits:new Map(s.totalLineHits)},this.update()}})()}switchFunc(t){this.func=t,this.update()}},et=class{constructor(){this.menuBar=new Y({funcSelected:t=>this.switchFunc(t)}),this.func=null,this.graph=null,this.graphContainer=x("div",["ig-relative","ig-flex-basis-0","ig-flex-grow-1","ig-overflow-hidden"]),this.root=x("div",["ig-absolute","ig-absolute-fill","ig-flex","ig-flex-column"],()=>{},[this.menuBar.root,this.graphContainer])}update(){this.graph&&this.graph.destroy(),this.func&&(this.graph=new A(this.graphContainer,{func:this.func,pass:ut}))}setIonJSON(t){this.menuBar.switchIonJSON(t)}switchFunc(t){this.func=t,this.update()}};return yt(Yt);})();
+</script>
+ <script>window.__exportedIonJSON = {{ IONJSON }}</script>
+ <script>
+ const ui = new iongraph.StandaloneUI();
+ document.body.appendChild(ui.root);
+ ui.setIonJSON(window.__exportedIonJSON);
+ </script>
+</body>
diff --git a/tool/zjit_iongraph.rb b/tool/zjit_iongraph.rb
new file mode 100755
index 0000000000..0cb7701614
--- /dev/null
+++ b/tool/zjit_iongraph.rb
@@ -0,0 +1,38 @@
+#!/usr/bin/env ruby
+require 'json'
+require 'logger'
+
+LOGGER = Logger.new($stderr)
+
+def run_ruby *cmd
+ # Find the first --zjit* option and add --zjit-dump-hir-iongraph after it
+ zjit_index = cmd.find_index { |arg| arg.start_with?("--zjit") }
+ raise "No --zjit option found in command" unless zjit_index
+ cmd.insert(zjit_index + 1, "--zjit-dump-hir-iongraph")
+ pid = Process.spawn(*cmd)
+ _, status = Process.wait2(pid)
+ if status.exitstatus != 0
+ LOGGER.warn("Command failed with exit status #{status.exitstatus}")
+ end
+ pid
+end
+
+usage = "Usage: zjit_iongraph.rb <path_to_ruby> <options>"
+RUBY = ARGV[0] || raise(usage)
+OPTIONS = ARGV[1..]
+pid = run_ruby(RUBY, *OPTIONS)
+functions = Dir["/tmp/zjit-iongraph-#{pid}/fun*.json"].map do |path|
+ JSON.parse(File.read(path))
+end
+
+if functions.empty?
+ LOGGER.warn("No iongraph functions found for PID #{pid}")
+end
+
+json = JSON.dump({version: 1, functions: functions})
+# Get zjit_iongraph.html from the sibling file next to this script
+html = File.read(File.join(File.dirname(__FILE__), "zjit_iongraph.html"))
+html.sub!("{{ IONJSON }}", json)
+output_path = "zjit_iongraph_#{pid}.html"
+File.write(output_path, html)
+puts "Wrote iongraph to #{output_path}"
diff --git a/trace_point.rb b/trace_point.rb
index 682398ec3f..7e8af21a68 100644
--- a/trace_point.rb
+++ b/trace_point.rb
@@ -26,7 +26,7 @@
# change. Instead, it is recommended to specify the types of events you
# want to use.
#
-# To filter what is traced, you can pass any of the following as +events+:
+# To filter what is traced, you can pass any number of the following as +events+:
#
# +:line+:: Execute an expression or statement on a new line.
# +:class+:: Start a class or module definition.
@@ -74,7 +74,7 @@ class TracePoint
#
# A block must be given; otherwise, an ArgumentError is raised.
#
- # If the trace method isn't included in the given events filter, a
+ # If the trace method isn't supported for the given event(s) filter, a
# RuntimeError is raised.
#
# TracePoint.trace(:line) do |tp|
@@ -89,7 +89,9 @@ class TracePoint
# end
# $tp.lineno #=> access from outside (RuntimeError)
#
- # Access from other threads is also forbidden.
+ # Access from other ractors, threads or fibers is forbidden. TracePoints are active
+ # per-ractor so if you enable a TracePoint in one ractor, other ractors will not be
+ # affected.
#
def self.new(*events)
Primitive.attr! :use_block
diff --git a/transcode.c b/transcode.c
index bff9268e1c..a70dc9d9ea 100644
--- a/transcode.c
+++ b/transcode.c
@@ -16,10 +16,13 @@
#include "internal.h"
#include "internal/array.h"
#include "internal/inits.h"
+#include "internal/gc.h"
#include "internal/object.h"
#include "internal/string.h"
#include "internal/transcode.h"
+#include "internal/encoding.h"
#include "ruby/encoding.h"
+#include "vm_sync.h"
#include "transcode_data.h"
#include "id.h"
@@ -65,7 +68,7 @@ static unsigned char *
allocate_converted_string(const char *sname, const char *dname,
const unsigned char *str, size_t len,
unsigned char *caller_dst_buf, size_t caller_dst_bufsize,
- size_t *dst_len_ptr);
+ size_t *dst_len_ptr, size_t *dst_bufsize_ptr);
/* dynamic structure, one per conversion (similar to iconv_t) */
/* may carry conversion state (e.g. for iso-2022-jp) */
@@ -136,6 +139,7 @@ struct rb_econv_t {
const unsigned char *replacement_str;
size_t replacement_len;
+ size_t replacement_bufsize;
const char *replacement_enc;
unsigned char *in_buf_start;
@@ -184,7 +188,7 @@ static st_table *transcoder_table;
static int
free_inner_transcode_i(st_data_t key, st_data_t val, st_data_t arg)
{
- xfree((void *)val);
+ SIZED_FREE((transcoder_entry_t *)val);
return ST_DELETE;
}
@@ -209,19 +213,21 @@ make_transcoder_entry(const char *sname, const char *dname)
st_data_t val;
st_table *table2;
- if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
- val = (st_data_t)st_init_strcasetable();
- st_add_direct(transcoder_table, (st_data_t)sname, val);
- }
- table2 = (st_table *)val;
- if (!st_lookup(table2, (st_data_t)dname, &val)) {
- transcoder_entry_t *entry = ALLOC(transcoder_entry_t);
- entry->sname = sname;
- entry->dname = dname;
- entry->lib = NULL;
- entry->transcoder = NULL;
- val = (st_data_t)entry;
- st_add_direct(table2, (st_data_t)dname, val);
+ RB_VM_LOCKING() {
+ if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
+ val = (st_data_t)st_init_strcasetable();
+ st_add_direct(transcoder_table, (st_data_t)sname, val);
+ }
+ table2 = (st_table *)val;
+ if (!st_lookup(table2, (st_data_t)dname, &val)) {
+ transcoder_entry_t *entry = ALLOC(transcoder_entry_t);
+ entry->sname = sname;
+ entry->dname = dname;
+ entry->lib = NULL;
+ entry->transcoder = NULL;
+ val = (st_data_t)entry;
+ st_add_direct(table2, (st_data_t)dname, val);
+ }
}
return (transcoder_entry_t *)val;
}
@@ -229,15 +235,15 @@ make_transcoder_entry(const char *sname, const char *dname)
static transcoder_entry_t *
get_transcoder_entry(const char *sname, const char *dname)
{
- st_data_t val;
+ st_data_t val = 0;
st_table *table2;
-
- if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
- return NULL;
- }
- table2 = (st_table *)val;
- if (!st_lookup(table2, (st_data_t)dname, &val)) {
- return NULL;
+ RB_VM_LOCKING() {
+ if (st_lookup(transcoder_table, (st_data_t)sname, &val)) {
+ table2 = (st_table *)val;
+ if (!st_lookup(table2, (st_data_t)dname, &val)) {
+ val = 0;
+ }
+ }
}
return (transcoder_entry_t *)val;
}
@@ -250,13 +256,14 @@ rb_register_transcoder(const rb_transcoder *tr)
transcoder_entry_t *entry;
- entry = make_transcoder_entry(sname, dname);
- if (entry->transcoder) {
- rb_raise(rb_eArgError, "transcoder from %s to %s has been already registered",
- sname, dname);
+ RB_VM_LOCKING() {
+ entry = make_transcoder_entry(sname, dname);
+ if (entry->transcoder) {
+ rb_raise(rb_eArgError, "transcoder from %s to %s has been already registered",
+ sname, dname);
+ }
+ entry->transcoder = tr;
}
-
- entry->transcoder = tr;
}
static void
@@ -323,8 +330,9 @@ transcode_search_path(const char *sname, const char *dname,
search_path_queue_t *q;
st_data_t val;
st_table *table2;
- int found;
int pathlen = -1;
+ bool found = false;
+ bool lookup_res;
if (encoding_equal(sname, dname))
return -1;
@@ -335,41 +343,43 @@ transcode_search_path(const char *sname, const char *dname,
bfs.queue_last_ptr = &q->next;
bfs.queue = q;
- bfs.visited = st_init_strcasetable();
+ bfs.visited = st_init_strcasetable(); // due to base encodings, we need to do search in a loop
st_add_direct(bfs.visited, (st_data_t)sname, (st_data_t)NULL);
- while (bfs.queue) {
- q = bfs.queue;
- bfs.queue = q->next;
- if (!bfs.queue)
- bfs.queue_last_ptr = &bfs.queue;
+ RB_VM_LOCKING() {
+ while (bfs.queue) {
+ q = bfs.queue;
+ bfs.queue = q->next;
+ if (!bfs.queue) {
+ bfs.queue_last_ptr = &bfs.queue;
+ }
- if (!st_lookup(transcoder_table, (st_data_t)q->enc, &val)) {
- xfree(q);
- continue;
- }
- table2 = (st_table *)val;
+ lookup_res = st_lookup(transcoder_table, (st_data_t)q->enc, &val); // src => table2
+ if (!lookup_res) {
+ SIZED_FREE(q);
+ continue;
+ }
+ table2 = (st_table *)val;
- if (st_lookup(table2, (st_data_t)dname, &val)) {
- st_add_direct(bfs.visited, (st_data_t)dname, (st_data_t)q->enc);
- xfree(q);
- found = 1;
- goto cleanup;
- }
+ if (st_lookup(table2, (st_data_t)dname, &val)) { // dest => econv
+ st_add_direct(bfs.visited, (st_data_t)dname, (st_data_t)q->enc);
+ SIZED_FREE(q);
+ found = true;
+ break;
+ }
- bfs.base_enc = q->enc;
- st_foreach(table2, transcode_search_path_i, (st_data_t)&bfs);
- bfs.base_enc = NULL;
+ bfs.base_enc = q->enc;
+ st_foreach(table2, transcode_search_path_i, (st_data_t)&bfs);
- xfree(q);
+ bfs.base_enc = NULL;
+ SIZED_FREE(q);
+ }
}
- found = 0;
- cleanup:
while (bfs.queue) {
q = bfs.queue;
bfs.queue = q->next;
- xfree(q);
+ SIZED_FREE(q);
}
if (found) {
@@ -404,6 +414,7 @@ int rb_require_internal_silent(VALUE fname);
static const rb_transcoder *
load_transcoder_entry(transcoder_entry_t *entry)
{
+ ASSERT_vm_unlocking();
if (entry->transcoder)
return entry->transcoder;
@@ -418,7 +429,7 @@ load_transcoder_entry(transcoder_entry_t *entry)
memcpy(path + sizeof(transcoder_lib_prefix) - 1, lib, len);
rb_str_set_len(fn, total_len);
OBJ_FREEZE(fn);
- rb_require_internal_silent(fn);
+ rb_require_internal_silent(fn); // Sets entry->transcoder
}
if (entry->transcoder)
@@ -864,12 +875,12 @@ rb_transcoding_close(rb_transcoding *tc)
(tr->state_fini_func)(TRANSCODING_STATE(tc)); /* check return value? */
}
if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
- xfree(tc->state.ptr);
+ ruby_xfree_sized(tc->state.ptr, tr->state_size);
if ((int)sizeof(tc->readbuf.ary) < tr->max_input)
- xfree(tc->readbuf.ptr);
+ ruby_xfree_sized(tc->readbuf.ptr, tr->max_input);
if ((int)sizeof(tc->writebuf.ary) < tr->max_output)
- xfree(tc->writebuf.ptr);
- xfree(tc);
+ ruby_xfree_sized(tc->writebuf.ptr, tr->max_output);
+ SIZED_FREE(tc);
}
static size_t
@@ -905,6 +916,7 @@ rb_econv_alloc(int n_hint)
ec->started = 0;
ec->replacement_str = NULL;
ec->replacement_len = 0;
+ ec->replacement_bufsize = 0;
ec->replacement_enc = NULL;
ec->replacement_allocated = 0;
ec->in_buf_start = NULL;
@@ -937,7 +949,7 @@ rb_econv_add_transcoder_at(rb_econv_t *ec, const rb_transcoder *tr, int i)
if (ec->num_trans == ec->num_allocated) {
n = ec->num_allocated * 2;
- REALLOC_N(ec->elems, rb_econv_elem_t, n);
+ SIZED_REALLOC_N(ec->elems, rb_econv_elem_t, n, ec->num_allocated);
ec->num_allocated = n;
}
@@ -996,7 +1008,6 @@ rb_econv_open_by_transcoder_entries(int n, transcoder_entry_t **entries)
struct trans_open_t {
transcoder_entry_t **entries;
- int num_additional;
};
static void
@@ -1005,7 +1016,7 @@ trans_open_i(const char *sname, const char *dname, int depth, void *arg)
struct trans_open_t *toarg = arg;
if (!toarg->entries) {
- toarg->entries = ALLOC_N(transcoder_entry_t *, depth+1+toarg->num_additional);
+ toarg->entries = ALLOC_N(transcoder_entry_t *, depth + 1);
}
toarg->entries[depth] = get_transcoder_entry(sname, dname);
}
@@ -1017,8 +1028,7 @@ rb_econv_open0(const char *sname, const char *dname, int ecflags)
int num_trans;
rb_econv_t *ec;
- /* Just check if sname and dname are defined */
- /* (This check is needed?) */
+ // loads encodings if not loaded already
if (*sname) rb_enc_find_index(sname);
if (*dname) rb_enc_find_index(dname);
@@ -1028,19 +1038,17 @@ rb_econv_open0(const char *sname, const char *dname, int ecflags)
sname = dname = "";
}
else {
- struct trans_open_t toarg;
- toarg.entries = NULL;
- toarg.num_additional = 0;
+ struct trans_open_t toarg = {0};
num_trans = transcode_search_path(sname, dname, trans_open_i, (void *)&toarg);
entries = toarg.entries;
if (num_trans < 0) {
- xfree(entries);
+ SIZED_FREE_N(entries, num_trans);
return NULL;
}
}
ec = rb_econv_open_by_transcoder_entries(num_trans, entries);
- xfree(entries);
+ SIZED_FREE_N(entries, num_trans);
if (!ec)
return NULL;
@@ -1107,18 +1115,20 @@ rb_econv_open(const char *sname, const char *dname, int ecflags)
return NULL;
ec = rb_econv_open0(sname, dname, ecflags & ECONV_ERROR_HANDLER_MASK);
- if (!ec)
- return NULL;
-
- for (i = 0; i < num_decorators; i++)
- if (rb_econv_decorate_at_last(ec, decorators[i]) == -1) {
- rb_econv_close(ec);
- return NULL;
+ if (ec) {
+ for (i = 0; i < num_decorators; i++) {
+ if (rb_econv_decorate_at_last(ec, decorators[i]) == -1) {
+ rb_econv_close(ec);
+ ec = NULL;
+ break;
+ }
}
+ }
- ec->flags |= ecflags & ~ECONV_ERROR_HANDLER_MASK;
-
- return ec;
+ if (ec) {
+ ec->flags |= ecflags & ~ECONV_ERROR_HANDLER_MASK;
+ }
+ return ec; // can be NULL
}
static int
@@ -1421,7 +1431,7 @@ output_hex_charref(rb_econv_t *ec)
int ret;
unsigned char utfbuf[1024];
const unsigned char *utf;
- size_t utf_len;
+ size_t utf_len, utf_bufsize;
int utf_allocated = 0;
char charef_buf[16];
const unsigned char *p;
@@ -1434,7 +1444,7 @@ output_hex_charref(rb_econv_t *ec)
utf = allocate_converted_string(ec->last_error.source_encoding, "UTF-32BE",
ec->last_error.error_bytes_start, ec->last_error.error_bytes_len,
utfbuf, sizeof(utfbuf),
- &utf_len);
+ &utf_len, &utf_bufsize);
if (!utf)
return -1;
if (utf != utfbuf && utf != ec->last_error.error_bytes_start)
@@ -1462,12 +1472,12 @@ output_hex_charref(rb_econv_t *ec)
}
if (utf_allocated)
- xfree((void *)utf);
+ ruby_xfree_sized((void *)utf, utf_bufsize);
return 0;
fail:
if (utf_allocated)
- xfree((void *)utf);
+ ruby_xfree_sized((void *)utf, utf_bufsize);
return -1;
}
@@ -1548,7 +1558,7 @@ static unsigned char *
allocate_converted_string(const char *sname, const char *dname,
const unsigned char *str, size_t len,
unsigned char *caller_dst_buf, size_t caller_dst_bufsize,
- size_t *dst_len_ptr)
+ size_t *dst_len_ptr, size_t *dst_bufsize_ptr)
{
unsigned char *dst_str;
size_t dst_len;
@@ -1591,7 +1601,7 @@ allocate_converted_string(const char *sname, const char *dname,
dst_str = tmp;
}
else {
- dst_str = xrealloc(dst_str, dst_bufsize);
+ dst_str = ruby_xrealloc_sized(dst_str, dst_bufsize, dst_bufsize / 2);
}
dp = dst_str+dst_len;
res = rb_econv_convert(ec, &sp, str+len, &dp, dst_str+dst_bufsize, 0);
@@ -1602,11 +1612,12 @@ allocate_converted_string(const char *sname, const char *dname,
}
rb_econv_close(ec);
*dst_len_ptr = dst_len;
+ *dst_bufsize_ptr = dst_bufsize;
return dst_str;
fail:
if (dst_str != caller_dst_buf)
- xfree(dst_str);
+ ruby_xfree_sized(dst_str, dst_bufsize);
rb_econv_close(ec);
return NULL;
}
@@ -1619,7 +1630,7 @@ rb_econv_insert_output(rb_econv_t *ec,
const char *insert_encoding = rb_econv_encoding_to_insert_output(ec);
unsigned char insert_buf[4096];
const unsigned char *insert_str = NULL;
- size_t insert_len;
+ size_t insert_len, insert_bufsize;
int last_trans_index;
rb_transcoding *tc;
@@ -1642,7 +1653,7 @@ rb_econv_insert_output(rb_econv_t *ec,
}
else {
insert_str = allocate_converted_string(str_encoding, insert_encoding,
- str, len, insert_buf, sizeof(insert_buf), &insert_len);
+ str, len, insert_buf, sizeof(insert_buf), &insert_len, &insert_bufsize);
if (insert_str == NULL)
return -1;
}
@@ -1701,7 +1712,7 @@ rb_econv_insert_output(rb_econv_t *ec,
size_t s = (*data_end_p - *buf_start_p) + need;
if (s < need)
goto fail;
- buf = xrealloc(*buf_start_p, s);
+ buf = ruby_xrealloc_sized(*buf_start_p, s, buf_end_p - buf_start_p);
*data_start_p = buf;
*data_end_p = buf + (*data_end_p - *buf_start_p);
*buf_start_p = buf;
@@ -1718,12 +1729,12 @@ rb_econv_insert_output(rb_econv_t *ec,
}
if (insert_str != str && insert_str != insert_buf)
- xfree((void*)insert_str);
+ ruby_xfree_sized((void *)insert_str, insert_bufsize);
return 0;
fail:
if (insert_str != str && insert_str != insert_buf)
- xfree((void*)insert_str);
+ ruby_xfree_sized((void *)insert_str, insert_bufsize);
return -1;
}
@@ -1733,15 +1744,15 @@ rb_econv_close(rb_econv_t *ec)
int i;
if (ec->replacement_allocated) {
- xfree((void *)ec->replacement_str);
+ SIZED_FREE_N((char *)ec->replacement_str, ec->replacement_len);
}
for (i = 0; i < ec->num_trans; i++) {
rb_transcoding_close(ec->elems[i].tc);
- xfree(ec->elems[i].out_buf_start);
+ ruby_xfree_sized(ec->elems[i].out_buf_start, ec->elems[i].out_buf_end - ec->elems[i].out_buf_start);
}
- xfree(ec->in_buf_start);
- xfree(ec->elems);
- xfree(ec);
+ SIZED_FREE_N(ec->in_buf_start, ec->in_buf_end - ec->in_buf_start);
+ SIZED_FREE_N(ec->elems, ec->num_allocated);
+ SIZED_FREE(ec);
}
size_t
@@ -1815,26 +1826,44 @@ rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
{
st_data_t v;
st_table *table2;
- struct asciicompat_encoding_t data;
+ struct asciicompat_encoding_t data = {0};
- if (!st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v))
- return NULL;
- table2 = (st_table *)v;
+ unsigned int lev;
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ {
+ if (st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v)) {
+ table2 = (st_table *)v;
+ /*
+ * Assumption:
+ * There is at most one transcoder for
+ * converting from ASCII incompatible encoding.
+ *
+ * For ISO-2022-JP, there is ISO-2022-JP -> stateless-ISO-2022-JP and no others.
+ */
+ if (table2->num_entries == 1) {
+ data.ascii_incompat_name = ascii_incompat_name;
+ data.ascii_compat_name = NULL;
+ if (rb_multi_ractor_p()) {
+ /*
+ * We need to unlock in case `load_transcoder_entry` actually loads the encoding
+ * and table2 could be inserted into when we unlock.
+ */
+ st_table *dup_table2 = st_copy(table2);
+ RB_VM_LOCK_LEAVE_LEV(&lev);
+ st_foreach(dup_table2, asciicompat_encoding_i, (st_data_t)&data);
+ st_free_table(dup_table2);
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ }
+ else {
+ st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
+ }
+ }
- /*
- * Assumption:
- * There is at most one transcoder for
- * converting from ASCII incompatible encoding.
- *
- * For ISO-2022-JP, there is ISO-2022-JP -> stateless-ISO-2022-JP and no others.
- */
- if (table2->num_entries != 1)
- return NULL;
+ }
+ }
+ RB_VM_LOCK_LEAVE_LEV(&lev);
- data.ascii_incompat_name = ascii_incompat_name;
- data.ascii_compat_name = NULL;
- st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
- return data.ascii_compat_name;
+ return data.ascii_compat_name; // can be NULL
}
/*
@@ -1937,19 +1966,17 @@ static int
rb_econv_add_converter(rb_econv_t *ec, const char *sname, const char *dname, int n)
{
transcoder_entry_t *entry;
- const rb_transcoder *tr;
+ const rb_transcoder *tr = NULL;
if (ec->started != 0)
return -1;
entry = get_transcoder_entry(sname, dname);
- if (!entry)
- return -1;
-
- tr = load_transcoder_entry(entry);
- if (!tr) return -1;
+ if (entry) {
+ tr = load_transcoder_entry(entry);
+ }
- return rb_econv_add_transcoder_at(ec, tr, n);
+ return tr ? rb_econv_add_transcoder_at(ec, tr, n) : -1;
}
static int
@@ -2020,7 +2047,7 @@ rb_econv_binmode(rb_econv_t *ec)
for (i=0; i < num_trans; i++) {
if (transcoder == ec->elems[i].tc->transcoder) {
rb_transcoding_close(ec->elems[i].tc);
- xfree(ec->elems[i].out_buf_start);
+ ruby_xfree_sized(ec->elems[i].out_buf_start, ec->elems[i].out_buf_end - ec->elems[i].out_buf_start);
ec->num_trans--;
}
else
@@ -2250,6 +2277,7 @@ make_replacement(rb_econv_t *ec)
ec->replacement_str = replacement;
ec->replacement_len = len;
+ ec->replacement_bufsize = len;
ec->replacement_enc = repl_enc;
ec->replacement_allocated = 0;
return 0;
@@ -2260,7 +2288,7 @@ rb_econv_set_replacement(rb_econv_t *ec,
const unsigned char *str, size_t len, const char *encname)
{
unsigned char *str2;
- size_t len2;
+ size_t len2, buf_size2;
const char *encname2;
encname2 = rb_econv_encoding_to_insert_output(ec);
@@ -2268,21 +2296,22 @@ rb_econv_set_replacement(rb_econv_t *ec,
if (!*encname2 || encoding_equal(encname, encname2)) {
str2 = xmalloc(len);
MEMCPY(str2, str, unsigned char, len); /* xxx: str may be invalid */
- len2 = len;
+ buf_size2 = len2 = len;
encname2 = encname;
}
else {
- str2 = allocate_converted_string(encname, encname2, str, len, NULL, 0, &len2);
+ str2 = allocate_converted_string(encname, encname2, str, len, NULL, 0, &len2, &buf_size2);
if (!str2)
return -1;
}
if (ec->replacement_allocated) {
- xfree((void *)ec->replacement_str);
+ SIZED_FREE_N((char *)ec->replacement_str, ec->replacement_bufsize);
}
ec->replacement_allocated = 1;
ec->replacement_str = str2;
ec->replacement_len = len2;
+ ec->replacement_bufsize = buf_size2;
ec->replacement_enc = encname2;
return 0;
}
@@ -2323,6 +2352,26 @@ aref_fallback(VALUE fallback, VALUE c)
return rb_funcallv_public(fallback, idAREF, 1, &c);
}
+struct transcode_loop_fallback_args {
+ VALUE (*fallback_func)(VALUE, VALUE);
+ VALUE fallback;
+ VALUE rep;
+};
+
+static VALUE
+transcode_loop_fallback_try(VALUE a)
+{
+ struct transcode_loop_fallback_args *args = (struct transcode_loop_fallback_args *)a;
+
+ VALUE ret = args->fallback_func(args->fallback, args->rep);
+
+ if (!UNDEF_P(ret) && !NIL_P(ret)) {
+ StringValue(ret);
+ }
+
+ return ret;
+}
+
static void
transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
const unsigned char *in_stop, unsigned char *out_stop,
@@ -2372,12 +2421,26 @@ transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
(const char *)ec->last_error.error_bytes_start,
ec->last_error.error_bytes_len,
rb_enc_find(ec->last_error.source_encoding));
- rep = (*fallback_func)(fallback, rep);
+
+
+ struct transcode_loop_fallback_args args = {
+ .fallback_func = fallback_func,
+ .fallback = fallback,
+ .rep = rep,
+ };
+
+ int state;
+ rep = rb_protect(transcode_loop_fallback_try, (VALUE)&args, &state);
+ if (state) {
+ rb_econv_close(ec);
+ rb_jump_tag(state);
+ }
+
if (!UNDEF_P(rep) && !NIL_P(rep)) {
- StringValue(rep);
ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep),
RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
if ((int)ret == -1) {
+ rb_econv_close(ec);
rb_raise(rb_eArgError, "too big fallback string");
}
goto resume;
@@ -2663,23 +2726,22 @@ rb_econv_open_opts(const char *source_encoding, const char *destination_encoding
}
ec = rb_econv_open(source_encoding, destination_encoding, ecflags);
- if (!ec)
- return ec;
-
- if (!NIL_P(replacement)) {
- int ret;
- rb_encoding *enc = rb_enc_get(replacement);
-
- ret = rb_econv_set_replacement(ec,
- (const unsigned char *)RSTRING_PTR(replacement),
- RSTRING_LEN(replacement),
- rb_enc_name(enc));
- if (ret == -1) {
- rb_econv_close(ec);
- return NULL;
+ if (ec) {
+ if (!NIL_P(replacement)) {
+ int ret;
+ rb_encoding *enc = rb_enc_get(replacement);
+
+ ret = rb_econv_set_replacement(ec,
+ (const unsigned char *)RSTRING_PTR(replacement),
+ RSTRING_LEN(replacement),
+ rb_enc_name(enc));
+ if (ret == -1) {
+ rb_econv_close(ec);
+ ec = NULL;
+ }
}
}
- return ec;
+ return ec; // can be NULL
}
static int
@@ -2869,6 +2931,7 @@ str_encode_associate(VALUE str, int encidx)
*
* Like #encode, but applies encoding changes to +self+; returns +self+.
*
+ * Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@@ -2980,8 +3043,16 @@ make_encoding(const char *name)
{
rb_encoding *enc;
enc = rb_enc_find(name);
- if (!enc)
- enc = make_dummy_encoding(name);
+ if (!enc) {
+ RB_VM_LOCKING() {
+ if (rb_enc_registered(name)) {
+ enc = NULL;
+ }
+ else {
+ enc = make_dummy_encoding(name);
+ }
+ }
+ }
return enc;
}
@@ -3014,17 +3085,15 @@ econv_s_asciicompat_encoding(VALUE klass, VALUE arg)
{
const char *arg_name, *result_name;
rb_encoding *arg_enc, *result_enc;
+ VALUE enc = Qnil;
enc_arg(&arg, &arg_name, &arg_enc);
-
result_name = rb_econv_asciicompat_encoding(arg_name);
-
- if (result_name == NULL)
- return Qnil;
-
- result_enc = make_encoding(result_name);
-
- return rb_enc_from_encoding(result_enc);
+ if (result_name) {
+ result_enc = make_encoding(result_name);
+ enc = rb_enc_from_encoding(result_enc);
+ }
+ return enc;
}
static void
@@ -3105,8 +3174,10 @@ decorate_convpath(VALUE convpath, int ecflags)
if (RB_TYPE_P(pair, T_ARRAY)) {
const char *sname = rb_enc_name(rb_to_encoding(RARRAY_AREF(pair, 0)));
const char *dname = rb_enc_name(rb_to_encoding(RARRAY_AREF(pair, 1)));
- transcoder_entry_t *entry = get_transcoder_entry(sname, dname);
- const rb_transcoder *tr = load_transcoder_entry(entry);
+ transcoder_entry_t *entry;
+ const rb_transcoder *tr;
+ entry = get_transcoder_entry(sname, dname);
+ tr = load_transcoder_entry(entry);
if (!tr)
return -1;
if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
diff --git a/universal_parser.c b/universal_parser.c
index ad2e2fbd11..b9cddd2879 100644
--- a/universal_parser.c
+++ b/universal_parser.c
@@ -13,7 +13,6 @@
#include "ruby/backward/2/inttypes.h"
#include "probes.h"
-#define LIKELY(x) RB_LIKELY(x)
#define UNLIKELY(x) RB_UNLIKELY(x)
#ifndef TRUE
# define TRUE 1
@@ -167,7 +166,7 @@
#define rb_set_errinfo p->config->set_errinfo
#define rb_make_exception p->config->make_exception
-#define ruby_sized_xfree p->config->sized_xfree
+#define ruby_xfree_sized p->config->sized_xfree
#define SIZED_REALLOC_N(v, T, m, n) ((v) = (T *)p->config->sized_realloc_n((void *)(v), (m), sizeof(T), (n)))
#undef RB_GC_GUARD
#define RB_GC_GUARD p->config->gc_guard
diff --git a/util.c b/util.c
index 2e887618b1..3315eb575e 100644
--- a/util.c
+++ b/util.c
@@ -42,40 +42,19 @@ const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF";
unsigned long
ruby_scan_oct(const char *start, size_t len, size_t *retlen)
{
- register const char *s = start;
- register unsigned long retval = 0;
- size_t i;
-
- for (i = 0; i < len; i++) {
- if ((s[0] < '0') || ('7' < s[0])) {
- break;
- }
- retval <<= 3;
- retval |= *s++ - '0';
- }
- *retlen = (size_t)(s - start);
- return retval;
+ int overflow;
+ unsigned long val = ruby_scan_digits(start, (ssize_t)len, 8, retlen, &overflow);
+ (void)overflow;
+ return val;
}
unsigned long
ruby_scan_hex(const char *start, size_t len, size_t *retlen)
{
- register const char *s = start;
- register unsigned long retval = 0;
- signed char d;
- size_t i = 0;
-
- for (i = 0; i < len; i++) {
- d = ruby_digit36_to_number_table[(unsigned char)*s];
- if (d < 0 || 15 < d) {
- break;
- }
- retval <<= 4;
- retval |= d;
- s++;
- }
- *retlen = (size_t)(s - start);
- return retval;
+ int overflow;
+ unsigned long val = ruby_scan_digits(start, (ssize_t)len, 16, retlen, &overflow);
+ (void)overflow;
+ return val;
}
const signed char ruby_digit36_to_number_table[] = {
@@ -550,45 +529,43 @@ ruby_strdup(const char *str)
char *
ruby_getcwd(void)
{
- VALUE guard = rb_imemo_tmpbuf_auto_free_pointer();
int size = 200;
char *buf = xmalloc(size);
while (!getcwd(buf, size)) {
int e = errno;
if (e != ERANGE) {
- rb_free_tmp_buffer(&guard);
+ xfree(buf);
rb_syserr_fail(e, "getcwd");
}
size *= 2;
- rb_imemo_tmpbuf_set_ptr(guard, buf);
- buf = xrealloc(buf, size);
+ xfree(buf);
+ buf = xmalloc(size);
}
- rb_imemo_tmpbuf_set_ptr(guard, NULL);
return buf;
}
# else
-static const rb_data_type_t getcwd_buffer_guard_type = {
- .wrap_struct_name = "ruby_getcwd_guard",
- .function = {
- .dfree = free // not xfree.
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
-};
+static VALUE
+getcwd_strdup(VALUE arg)
+{
+ return (VALUE)ruby_strdup((const char *)arg);
+}
+
+static VALUE
+getcwd_free(VALUE arg)
+{
+ free((void *)arg);
+ return Qnil;
+}
char *
ruby_getcwd(void)
{
- VALUE guard = TypedData_Wrap_Struct((VALUE)0, &getcwd_buffer_guard_type, NULL);
- char *buf, *cwd = getcwd(NULL, 0);
- RTYPEDDATA_DATA(guard) = cwd;
+ char *cwd = getcwd(NULL, 0);
if (!cwd) rb_sys_fail("getcwd");
- buf = ruby_strdup(cwd); /* allocate by xmalloc */
- free(cwd);
- RTYPEDDATA_DATA(RB_GC_GUARD(guard)) = NULL;
- return buf;
+ return (char *)rb_ensure(getcwd_strdup, (VALUE)cwd, getcwd_free, (VALUE)cwd);
}
# endif
diff --git a/variable.c b/variable.c
index b987a57f1e..687fa03631 100644
--- a/variable.c
+++ b/variable.c
@@ -20,13 +20,16 @@
#include "id.h"
#include "id_table.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/class.h"
#include "internal/compilers.h"
#include "internal/error.h"
#include "internal/eval.h"
#include "internal/hash.h"
#include "internal/object.h"
+#include "internal/gc.h"
#include "internal/re.h"
+#include "internal/struct.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
@@ -60,14 +63,17 @@ static VALUE autoload_mutex;
static void check_before_mod_set(VALUE, ID, VALUE, const char *);
static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
-static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility);
-static st_table *generic_iv_tbl_;
+static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility, VALUE *found_in);
+static st_table *generic_fields_tbl_;
+
+typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg);
+static void rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only);
void
Init_var_tables(void)
{
rb_global_tbl = rb_id_table_create(0);
- generic_iv_tbl_ = st_init_numtable();
+ generic_fields_tbl_ = st_init_numtable();
autoload = rb_intern_const("__autoload__");
autoload_mutex = rb_mutex_new();
@@ -105,10 +111,10 @@ classname(VALUE klass, bool *permanent)
{
*permanent = false;
- VALUE classpath = RCLASS_EXT(klass)->classpath;
+ VALUE classpath = RCLASS_CLASSPATH(klass);
if (classpath == 0) return Qnil;
- *permanent = RCLASS_EXT(klass)->permanent_classpath;
+ *permanent = RCLASS_PERMANENT_CLASSPATH_P(klass);
return classpath;
}
@@ -206,7 +212,7 @@ static enum rb_id_table_iterator_result
set_sub_temporary_name_i(ID id, VALUE val, void *data)
{
val = ((rb_const_entry_t *)val)->value;
- if (rb_namespace_p(val) && !RCLASS_EXT(val)->permanent_classpath) {
+ if (rb_namespace_p(val) && !RCLASS_PERMANENT_CLASSPATH_P(val)) {
VALUE arg = (VALUE)data;
struct sub_temporary_name_args *args = data;
args->last = id;
@@ -218,7 +224,7 @@ set_sub_temporary_name_i(ID id, VALUE val, void *data)
static void
set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name)
{
- RCLASS_SET_CLASSPATH(mod, name, FALSE);
+ RCLASS_WRITE_CLASSPATH(mod, name, FALSE);
struct rb_id_table *tbl = RCLASS_CONST_TBL(mod);
if (!tbl) return;
if (!name) {
@@ -273,7 +279,7 @@ set_sub_temporary_name(VALUE mod, VALUE name)
* m.name #=> nil
*
* c = Class.new
- * c.set_temporary_name("MyClass(with description)")
+ * c.set_temporary_name("MyClass(with description)") # => MyClass(with description)
*
* c.new # => #<MyClass(with description):0x0....>
*
@@ -292,15 +298,15 @@ VALUE
rb_mod_set_temporary_name(VALUE mod, VALUE name)
{
// We don't allow setting the name if the classpath is already permanent:
- if (RCLASS_EXT(mod)->permanent_classpath) {
+ if (RCLASS_PERMANENT_CLASSPATH_P(mod)) {
rb_raise(rb_eRuntimeError, "can't change permanent name");
}
if (NIL_P(name)) {
// Set the temporary classpath to NULL (anonymous):
- RB_VM_LOCK_ENTER();
- set_sub_temporary_name(mod, 0);
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING() {
+ set_sub_temporary_name(mod, 0);
+ }
}
else {
// Ensure the name is a string:
@@ -315,11 +321,12 @@ rb_mod_set_temporary_name(VALUE mod, VALUE name)
}
name = rb_str_new_frozen(name);
+ RB_OBJ_SET_SHAREABLE(name);
// Set the temporary classpath to the given name:
- RB_VM_LOCK_ENTER();
- set_sub_temporary_name(mod, name);
- RB_VM_LOCK_LEAVE();
+ RB_VM_LOCKING() {
+ set_sub_temporary_name(mod, name);
+ }
}
return mod;
@@ -426,6 +433,7 @@ rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
str = build_const_pathname(str, name);
}
+ RB_OBJ_SET_SHAREABLE(str);
RCLASS_SET_CLASSPATH(klass, str, permanent);
}
@@ -465,7 +473,7 @@ rb_path_to_class(VALUE pathname)
if (!id) {
goto undefined_class;
}
- c = rb_const_search(c, id, TRUE, FALSE, FALSE);
+ c = rb_const_search(c, id, TRUE, FALSE, FALSE, NULL);
if (UNDEF_P(c)) goto undefined_class;
if (!rb_namespace_p(c)) {
rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
@@ -525,6 +533,8 @@ struct rb_global_variable {
rb_gvar_marker_t *marker;
rb_gvar_compact_t *compactor;
struct trace_var *trace;
+ bool box_ready;
+ bool box_dynamic;
};
struct rb_global_entry {
@@ -541,10 +551,10 @@ free_global_variable(struct rb_global_variable *var)
struct trace_var *trace = var->trace;
while (trace) {
struct trace_var *next = trace->next;
- xfree(trace);
+ SIZED_FREE(trace);
trace = next;
}
- xfree(var);
+ SIZED_FREE(var);
}
static enum rb_id_table_iterator_result
@@ -555,7 +565,7 @@ free_global_entry_i(VALUE val, void *arg)
if (entry->var->counter == 0) {
free_global_variable(entry->var);
}
- ruby_xfree(entry);
+ SIZED_FREE(entry);
return ID_TABLE_DELETE;
}
@@ -567,9 +577,9 @@ rb_free_rb_global_tbl(void)
}
void
-rb_free_generic_iv_tbl_(void)
+rb_free_generic_fields_tbl_(void)
{
- st_free_table(generic_iv_tbl_);
+ st_free_table(generic_fields_tbl_);
}
static struct rb_global_entry*
@@ -578,16 +588,18 @@ rb_find_global_entry(ID id)
struct rb_global_entry *entry;
VALUE data;
- if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
- entry = NULL;
- }
- else {
- entry = (struct rb_global_entry *)data;
- RUBY_ASSERT(entry != NULL);
+ RB_VM_LOCKING() {
+ if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
+ entry = NULL;
+ }
+ else {
+ entry = (struct rb_global_entry *)data;
+ RUBY_ASSERT(entry != NULL);
+ }
}
if (UNLIKELY(!rb_ractor_main_p()) && (!entry || !entry->ractor_local)) {
- rb_raise(rb_eRactorIsolationError, "can not access global variables %s from non-main Ractors", rb_id2name(id));
+ rb_raise(rb_eRactorIsolationError, "can not access global variable %s from non-main Ractor", rb_id2name(id));
}
return entry;
@@ -600,6 +612,20 @@ rb_gvar_ractor_local(const char *name)
entry->ractor_local = true;
}
+void
+rb_gvar_box_ready(const char *name)
+{
+ struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
+ entry->var->box_ready = true;
+}
+
+void
+rb_gvar_box_dynamic(const char *name)
+{
+ struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
+ entry->var->box_dynamic = true;
+}
+
static void
rb_gvar_undef_compactor(void *var)
{
@@ -608,24 +634,29 @@ rb_gvar_undef_compactor(void *var)
static struct rb_global_entry*
rb_global_entry(ID id)
{
- struct rb_global_entry *entry = rb_find_global_entry(id);
- if (!entry) {
- struct rb_global_variable *var;
- entry = ALLOC(struct rb_global_entry);
- var = ALLOC(struct rb_global_variable);
- entry->id = id;
- entry->var = var;
- entry->ractor_local = false;
- var->counter = 1;
- var->data = 0;
- var->getter = rb_gvar_undef_getter;
- var->setter = rb_gvar_undef_setter;
- var->marker = rb_gvar_undef_marker;
- var->compactor = rb_gvar_undef_compactor;
-
- var->block_trace = 0;
- var->trace = 0;
- rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
+ struct rb_global_entry *entry;
+ RB_VM_LOCKING() {
+ entry = rb_find_global_entry(id);
+ if (!entry) {
+ struct rb_global_variable *var;
+ entry = ALLOC(struct rb_global_entry);
+ var = ALLOC(struct rb_global_variable);
+ entry->id = id;
+ entry->var = var;
+ entry->ractor_local = false;
+ var->counter = 1;
+ var->data = 0;
+ var->getter = rb_gvar_undef_getter;
+ var->setter = rb_gvar_undef_setter;
+ var->marker = rb_gvar_undef_marker;
+ var->compactor = rb_gvar_undef_compactor;
+
+ var->block_trace = 0;
+ var->trace = 0;
+ var->box_ready = false;
+ var->box_dynamic = false;
+ rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
+ }
}
return entry;
}
@@ -840,7 +871,7 @@ rb_define_virtual_variable(
static void
rb_trace_eval(VALUE cmd, VALUE val)
{
- rb_eval_cmd_kw(cmd, rb_ary_new3(1, val), RB_NO_KEYWORDS);
+ rb_eval_cmd_call_kw(cmd, 1, &val, RB_NO_KEYWORDS);
}
VALUE
@@ -880,7 +911,7 @@ remove_trace(struct rb_global_variable *var)
next = trace->next;
if (next->removed) {
trace->next = next->next;
- xfree(next);
+ SIZED_FREE(next);
}
else {
trace = next;
@@ -978,13 +1009,37 @@ rb_gvar_set_entry(struct rb_global_entry *entry, VALUE val)
return val;
}
+static inline bool
+gvar_use_box_tbl(const rb_box_t *box, const struct rb_global_entry *entry)
+{
+ return BOX_USER_P(box) &&
+ !entry->var->box_dynamic &&
+ (!entry->var->box_ready || entry->var->setter != rb_gvar_readonly_setter);
+}
+
VALUE
rb_gvar_set(ID id, VALUE val)
{
- struct rb_global_entry *entry;
- entry = rb_global_entry(id);
+ VALUE retval;
+ struct rb_global_entry *entry = NULL;
+ const rb_box_t *box = rb_current_box();
+ bool use_box_tbl = false;
+
+ RB_VM_LOCKING() {
+ entry = rb_global_entry(id);
+
+ if (gvar_use_box_tbl(box, entry)) {
+ use_box_tbl = true;
+ rb_hash_aset(box->gvar_tbl, rb_id2sym(entry->id), val);
+ retval = val;
+ // TODO: think about trace
+ }
+ }
- return rb_gvar_set_entry(entry, val);
+ if (!use_box_tbl) {
+ retval = rb_gvar_set_entry(entry, val);
+ }
+ return retval;
}
VALUE
@@ -996,9 +1051,40 @@ rb_gv_set(const char *name, VALUE val)
VALUE
rb_gvar_get(ID id)
{
- struct rb_global_entry *entry = rb_global_entry(id);
- struct rb_global_variable *var = entry->var;
- return (*var->getter)(entry->id, var->data);
+ VALUE retval, gvars, key;
+ const rb_box_t *box = rb_current_box();
+ bool use_box_tbl = false;
+ struct rb_global_entry *entry = NULL;
+ struct rb_global_variable *var = NULL;
+ // TODO: use lock-free rb_id_table when it's available for use (doesn't yet exist)
+ RB_VM_LOCKING() {
+ entry = rb_global_entry(id);
+ var = entry->var;
+
+ if (gvar_use_box_tbl(box, entry)) {
+ use_box_tbl = true;
+ gvars = box->gvar_tbl;
+ key = rb_id2sym(entry->id);
+ if (RTEST(rb_hash_has_key(gvars, key))) { // this gvar is already cached
+ retval = rb_hash_aref(gvars, key);
+ }
+ else {
+ RB_VM_UNLOCK();
+ {
+ retval = (*var->getter)(entry->id, var->data);
+ if (rb_obj_respond_to(retval, rb_intern("clone"), 1)) {
+ retval = rb_funcall(retval, rb_intern("clone"), 0);
+ }
+ }
+ RB_VM_LOCK();
+ rb_hash_aset(gvars, key, retval);
+ }
+ }
+ }
+ if (!use_box_tbl) {
+ retval = (*var->getter)(entry->id, var->data);
+ }
+ return retval;
}
VALUE
@@ -1052,6 +1138,7 @@ rb_f_global_variables(void)
if (!rb_ractor_main_p()) {
rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
}
+ /* gvar access (get/set) in boxes creates gvar entries globally */
rb_id_table_foreach(rb_global_tbl, gvar_i, (void *)ary);
if (!NIL_P(backref)) {
@@ -1078,7 +1165,7 @@ rb_f_global_variables(void)
void
rb_alias_variable(ID name1, ID name2)
{
- struct rb_global_entry *entry1, *entry2;
+ struct rb_global_entry *entry1 = NULL, *entry2;
VALUE data1;
struct rb_id_table *gtbl = rb_global_tbl;
@@ -1086,27 +1173,29 @@ rb_alias_variable(ID name1, ID name2)
rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
}
- entry2 = rb_global_entry(name2);
- if (!rb_id_table_lookup(gtbl, name1, &data1)) {
- entry1 = ALLOC(struct rb_global_entry);
- entry1->id = name1;
- rb_id_table_insert(gtbl, name1, (VALUE)entry1);
- }
- else if ((entry1 = (struct rb_global_entry *)data1)->var != entry2->var) {
- struct rb_global_variable *var = entry1->var;
- if (var->block_trace) {
- rb_raise(rb_eRuntimeError, "can't alias in tracer");
+ RB_VM_LOCKING() {
+ entry2 = rb_global_entry(name2);
+ if (!rb_id_table_lookup(gtbl, name1, &data1)) {
+ entry1 = ZALLOC(struct rb_global_entry);
+ entry1->id = name1;
+ rb_id_table_insert(gtbl, name1, (VALUE)entry1);
}
- var->counter--;
- if (var->counter == 0) {
- free_global_variable(var);
+ else if ((entry1 = (struct rb_global_entry *)data1)->var != entry2->var) {
+ struct rb_global_variable *var = entry1->var;
+ if (var->block_trace) {
+ RB_VM_UNLOCK();
+ rb_raise(rb_eRuntimeError, "can't alias in tracer");
+ }
+ var->counter--;
+ if (var->counter == 0) {
+ free_global_variable(var);
+ }
+ }
+ if (entry1->var != entry2->var) {
+ entry2->var->counter++;
+ entry1->var = entry2->var;
}
}
- else {
- return;
- }
- entry2->var->counter++;
- entry1->var = entry2->var;
}
static void
@@ -1119,179 +1208,240 @@ IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
}
}
-#define CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR() \
- if (UNLIKELY(!rb_ractor_main_p())) { \
- rb_raise(rb_eRactorIsolationError, "can not access class variables from non-main Ractors"); \
- }
+static void
+CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(VALUE klass, ID id)
+{
+ if (UNLIKELY(!rb_ractor_main_p())) {
+ rb_raise(rb_eRactorIsolationError, "can not set class variables from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")", rb_id2str(id), klass);
+ }
+}
-static inline struct st_table *
-generic_ivtbl(VALUE obj, ID id, bool force_check_ractor)
+static void
+cvar_read_ractor_check(VALUE klass, ID id, VALUE val)
{
- ASSERT_vm_locking();
+ if (UNLIKELY(!rb_ractor_main_p()) && !rb_ractor_shareable_p(val)) {
+ rb_raise(rb_eRactorIsolationError,
+ "can not read non-shareable class variable %"PRIsVALUE" from non-main Ractors (%"PRIsVALUE")",
+ rb_id2str(id), klass);
+ }
+}
- if ((force_check_ractor || LIKELY(rb_is_instance_id(id)) /* not internal ID */ ) &&
+static inline void
+ivar_ractor_check(VALUE obj, ID id)
+{
+ if (LIKELY(rb_is_instance_id(id)) /* not internal ID */ &&
!RB_OBJ_FROZEN_RAW(obj) &&
UNLIKELY(!rb_ractor_main_p()) &&
UNLIKELY(rb_ractor_shareable_p(obj))) {
rb_raise(rb_eRactorIsolationError, "can not access instance variables of shareable objects from non-main Ractors");
}
- return generic_iv_tbl_;
}
static inline struct st_table *
-generic_ivtbl_no_ractor_check(VALUE obj)
+generic_fields_tbl_no_ractor_check(void)
{
- return generic_ivtbl(obj, 0, false);
+ ASSERT_vm_locking();
+
+ return generic_fields_tbl_;
}
struct st_table *
-rb_generic_ivtbl_get(void)
+rb_generic_fields_tbl_get(void)
{
- return generic_iv_tbl_;
+ return generic_fields_tbl_;
}
-int
-rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl)
+void
+rb_mark_generic_ivar(VALUE obj)
{
- RUBY_ASSERT(!RB_TYPE_P(obj, T_ICLASS));
-
- st_data_t data;
- int r = 0;
-
- RB_VM_LOCK_ENTER();
- {
- if (st_lookup(generic_ivtbl(obj, id, false), (st_data_t)obj, &data)) {
- *ivtbl = (struct gen_ivtbl *)data;
- r = 1;
- }
+ VALUE data;
+ // Bypass ASSERT_vm_locking() check because marking may happen concurrently with mmtk
+ if (st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&data)) {
+ rb_gc_mark_movable(data);
}
- RB_VM_LOCK_LEAVE();
-
- return r;
}
-int
-rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl)
-{
- return rb_gen_ivtbl_get(obj, 0, ivtbl);
-}
-
-static size_t
-gen_ivtbl_bytes(size_t n)
+VALUE
+rb_obj_fields_generic_uncached(VALUE obj)
{
- return offsetof(struct gen_ivtbl, as.shape.ivptr) + n * sizeof(VALUE);
+ VALUE fields_obj = 0;
+ RB_VM_LOCKING() {
+ if (!st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&fields_obj)) {
+ rb_bug("Object is missing entry in generic_fields_tbl");
+ }
+ }
+ return fields_obj;
}
-static struct gen_ivtbl *
-gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n)
+VALUE
+rb_obj_fields(VALUE obj, ID field_name)
{
- RUBY_ASSERT(n > 0);
-
- uint32_t len = old ? old->as.shape.numiv : 0;
- struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO));
+ ivar_ractor_check(obj, field_name);
- ivtbl->as.shape.numiv = n;
- for (; len < n; len++) {
- ivtbl->as.shape.ivptr[len] = Qundef;
+ VALUE fields_obj = 0;
+ if (rb_obj_shape_has_fields(obj)) {
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ fields_obj = RTYPEDDATA(obj)->fields_obj;
+ break;
+ case T_STRUCT:
+ if (LIKELY(!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS))) {
+ fields_obj = RSTRUCT_FIELDS_OBJ(obj);
+ break;
+ }
+ goto generic_fields;
+ default:
+ generic_fields:
+ {
+ rb_execution_context_t *ec = GET_EC();
+ if (ec->gen_fields_cache.obj == obj && !UNDEF_P(ec->gen_fields_cache.fields_obj) && rb_imemo_fields_owner(ec->gen_fields_cache.fields_obj) == obj) {
+ fields_obj = ec->gen_fields_cache.fields_obj;
+ RUBY_ASSERT(fields_obj == rb_obj_fields_generic_uncached(obj));
+ }
+ else {
+ fields_obj = rb_obj_fields_generic_uncached(obj);
+ ec->gen_fields_cache.fields_obj = fields_obj;
+ ec->gen_fields_cache.obj = obj;
+ }
+ }
+ }
}
-
- return ivtbl;
+ return fields_obj;
}
void
-rb_mark_generic_ivar(VALUE obj)
+rb_free_generic_ivar(VALUE obj)
{
- st_data_t data;
- if (st_lookup(generic_ivtbl_no_ractor_check(obj), (st_data_t)obj, &data)) {
- struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)data;
- if (rb_shape_obj_too_complex(obj)) {
- rb_mark_tbl_no_pin(ivtbl->as.complex.table);
- }
- else {
- for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
- rb_gc_mark_movable(ivtbl->as.shape.ivptr[i]);
+ if (rb_obj_gen_fields_p(obj)) {
+ st_data_t key = (st_data_t)obj, value;
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ RB_OBJ_WRITE(obj, &RTYPEDDATA(obj)->fields_obj, 0);
+ break;
+ case T_STRUCT:
+ if (LIKELY(!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS))) {
+ RSTRUCT_SET_FIELDS_OBJ(obj, 0);
+ break;
+ }
+ goto generic_fields;
+ default:
+ generic_fields:
+ {
+ // Other EC may have stale caches, so fields_obj should be
+ // invalidated and the GC will replace with Qundef
+ rb_execution_context_t *ec = GET_EC();
+ if (ec->gen_fields_cache.obj == obj) {
+ ec->gen_fields_cache.obj = Qundef;
+ ec->gen_fields_cache.fields_obj = Qundef;
+ }
+ RB_VM_LOCKING() {
+ if (!st_delete(generic_fields_tbl_no_ractor_check(), &key, &value)) {
+ rb_bug("Object is missing entry in generic_fields_tbl");
+ }
+ }
}
}
+ RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | ROOT_SHAPE_ID);
}
}
-void
-rb_free_generic_ivar(VALUE obj)
+static void
+rb_obj_set_fields(VALUE obj, VALUE fields_obj, ID field_name, VALUE original_fields_obj)
{
- st_data_t key = (st_data_t)obj, value;
+ ivar_ractor_check(obj, field_name);
+
+ if (!fields_obj) {
+ RUBY_ASSERT(original_fields_obj);
+ rb_free_generic_ivar(obj);
+ rb_imemo_fields_clear(original_fields_obj);
+ return;
+ }
- bool too_complex = rb_shape_obj_too_complex(obj);
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields));
+ RUBY_ASSERT(!original_fields_obj || IMEMO_TYPE_P(original_fields_obj, imemo_fields));
- if (st_delete(generic_ivtbl_no_ractor_check(obj), &key, &value)) {
- struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)value;
+ if (fields_obj != original_fields_obj) {
+ switch (BUILTIN_TYPE(obj)) {
+ case T_DATA:
+ RB_OBJ_WRITE(obj, &RTYPEDDATA(obj)->fields_obj, fields_obj);
+ break;
+ case T_STRUCT:
+ if (LIKELY(!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS))) {
+ RSTRUCT_SET_FIELDS_OBJ(obj, fields_obj);
+ break;
+ }
+ goto generic_fields;
+ default:
+ generic_fields:
+ {
+ RB_VM_LOCKING() {
+ st_insert(generic_fields_tbl_, (st_data_t)obj, (st_data_t)fields_obj);
+ }
+ RB_OBJ_WRITTEN(obj, original_fields_obj, fields_obj);
- if (UNLIKELY(too_complex)) {
- st_free_table(ivtbl->as.complex.table);
+ rb_execution_context_t *ec = GET_EC();
+ if (ec->gen_fields_cache.fields_obj != fields_obj) {
+ ec->gen_fields_cache.obj = obj;
+ ec->gen_fields_cache.fields_obj = fields_obj;
+ }
+ }
}
- xfree(ivtbl);
+ if (original_fields_obj) {
+ // Clear root shape to avoid triggering cleanup such as free_object_id.
+ rb_imemo_fields_clear(original_fields_obj);
+ }
}
+
+ RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | RBASIC_SHAPE_ID(fields_obj));
}
-size_t
-rb_generic_ivar_memsize(VALUE obj)
+void
+rb_obj_replace_fields(VALUE obj, VALUE fields_obj)
{
- struct gen_ivtbl *ivtbl;
-
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- if (rb_shape_obj_too_complex(obj)) {
- return sizeof(struct gen_ivtbl) + st_memsize(ivtbl->as.complex.table);
- }
- else {
- return gen_ivtbl_bytes(ivtbl->as.shape.numiv);
- }
+ RB_VM_LOCKING() {
+ VALUE original_fields_obj = rb_obj_fields_no_ractor_check(obj);
+ rb_obj_set_fields(obj, fields_obj, 0, original_fields_obj);
}
- return 0;
}
-#if !SHAPE_IN_BASIC_FLAGS
-shape_id_t
-rb_generic_shape_id(VALUE obj)
+VALUE
+rb_obj_field_get(VALUE obj, shape_id_t target_shape_id)
{
- struct gen_ivtbl *ivtbl = 0;
- shape_id_t shape_id = 0;
+ RUBY_ASSERT(!SPECIAL_CONST_P(obj));
+ RUBY_ASSERT(RSHAPE_TYPE_P(target_shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(target_shape_id, SHAPE_OBJ_ID));
- RB_VM_LOCK_ENTER();
- {
- st_table* global_iv_table = generic_ivtbl(obj, 0, false);
+ VALUE fields_obj;
- if (global_iv_table && st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) {
- shape_id = ivtbl->shape_id;
- }
- else if (OBJ_FROZEN(obj)) {
- shape_id = SPECIAL_CONST_SHAPE_ID;
- }
+ switch (BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ break;
+ case T_OBJECT:
+ fields_obj = obj;
+ break;
+ case T_IMEMO:
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
+ fields_obj = obj;
+ break;
+ default:
+ fields_obj = rb_obj_fields(obj, RSHAPE_EDGE_NAME(target_shape_id));
+ break;
}
- RB_VM_LOCK_LEAVE();
- return shape_id;
-}
-#endif
-
-static size_t
-gen_ivtbl_count(VALUE obj, const struct gen_ivtbl *ivtbl)
-{
- uint32_t i;
- size_t n = 0;
-
- if (rb_shape_obj_too_complex(obj)) {
- n = st_table_size(ivtbl->as.complex.table);
- }
- else {
- for (i = 0; i < ivtbl->as.shape.numiv; i++) {
- if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
- n++;
- }
- }
+ if (UNLIKELY(rb_shape_complex_p(target_shape_id))) {
+ st_table *fields_hash = rb_imemo_fields_complex_tbl(fields_obj);
+ VALUE value = Qundef;
+ st_lookup(fields_hash, RSHAPE_EDGE_NAME(target_shape_id), &value);
+ RUBY_ASSERT(!UNDEF_P(value));
+ return value;
}
- return n;
+ attr_index_t index = RSHAPE_INDEX(target_shape_id);
+ return rb_imemo_fields_ptr(fields_obj)[index];
}
VALUE
@@ -1299,113 +1449,54 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
{
if (SPECIAL_CONST_P(obj)) return undef;
- shape_id_t shape_id;
- VALUE * ivar_list;
- rb_shape_t * shape;
-
-#if SHAPE_IN_BASIC_FLAGS
- shape_id = RBASIC_SHAPE_ID(obj);
-#endif
+ VALUE fields_obj;
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
{
- bool found = false;
- VALUE val;
-
- RB_VM_LOCK_ENTER();
- {
-#if !SHAPE_IN_BASIC_FLAGS
- shape_id = RCLASS_SHAPE_ID(obj);
-#endif
-
- if (rb_shape_obj_too_complex(obj)) {
- st_table * iv_table = RCLASS_IV_HASH(obj);
- if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
- found = true;
- }
- else {
- val = undef;
- }
- }
- else {
- attr_index_t index = 0;
- shape = rb_shape_get_shape_by_id(shape_id);
- found = rb_shape_get_iv_index(shape, id, &index);
-
- if (found) {
- ivar_list = RCLASS_IVPTR(obj);
- RUBY_ASSERT(ivar_list);
-
- val = ivar_list[index];
- }
- else {
- val = undef;
- }
- }
- }
- RB_VM_LOCK_LEAVE();
-
- if (found &&
+ VALUE val = rb_ivar_lookup(RCLASS_WRITABLE_FIELDS_OBJ(obj), id, undef);
+ if (val != undef &&
rb_is_instance_id(id) &&
UNLIKELY(!rb_ractor_main_p()) &&
!rb_ractor_shareable_p(val)) {
rb_raise(rb_eRactorIsolationError,
- "can not get unshareable values from instance variables of classes/modules from non-main Ractors");
+ "can not get unshareable values from instance variables of classes/modules from non-main Ractors (%"PRIsVALUE" from %"PRIsVALUE")",
+ rb_id2str(id), obj);
}
return val;
}
+ case T_IMEMO:
+ // Handled like T_OBJECT
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
+ fields_obj = obj;
+ break;
case T_OBJECT:
- {
-#if !SHAPE_IN_BASIC_FLAGS
- shape_id = ROBJECT_SHAPE_ID(obj);
-#endif
- if (rb_shape_obj_too_complex(obj)) {
- st_table * iv_table = ROBJECT_IV_HASH(obj);
- VALUE val;
- if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
- return val;
- }
- else {
- return undef;
- }
- }
-
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
- ivar_list = ROBJECT_IVPTR(obj);
- break;
- }
+ fields_obj = obj;
+ break;
default:
- if (FL_TEST_RAW(obj, FL_EXIVAR)) {
- struct gen_ivtbl *ivtbl;
- rb_gen_ivtbl_get(obj, id, &ivtbl);
-
- if (rb_shape_obj_too_complex(obj)) {
- VALUE val;
- if (rb_st_lookup(ivtbl->as.complex.table, (st_data_t)id, (st_data_t *)&val)) {
- return val;
- }
- else {
- return undef;
- }
- }
+ fields_obj = rb_obj_fields(obj, id);
+ break;
+ }
-#if !SHAPE_IN_BASIC_FLAGS
- shape_id = ivtbl->shape_id;
-#endif
- ivar_list = ivtbl->as.shape.ivptr;
- }
- else {
- return undef;
+ if (!fields_obj) {
+ return undef;
+ }
+
+ shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
+
+ if (UNLIKELY(rb_shape_complex_p(shape_id))) {
+ st_table *iv_table = rb_imemo_fields_complex_tbl(fields_obj);
+ VALUE val;
+ if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
+ return val;
}
- break;
+ return undef;
}
attr_index_t index = 0;
- shape = rb_shape_get_shape_by_id(shape_id);
- if (rb_shape_get_iv_index(shape, id, &index)) {
- return ivar_list[index];
+ if (rb_shape_get_iv_index(shape_id, id, &index)) {
+ return rb_imemo_fields_ptr(fields_obj)[index];
}
return undef;
@@ -1420,345 +1511,413 @@ rb_ivar_get(VALUE obj, ID id)
}
VALUE
-rb_attr_get(VALUE obj, ID id)
-{
- return rb_ivar_lookup(obj, id, Qnil);
-}
-
-static VALUE
-rb_ivar_delete(VALUE obj, ID id, VALUE undef)
+rb_ivar_get_at(VALUE obj, attr_index_t index, ID id)
{
- rb_check_frozen(obj);
-
- VALUE val = undef;
- rb_shape_t *shape = rb_shape_get_shape(obj);
+ RUBY_ASSERT(rb_is_instance_id(id));
+ // Used by JITs, but never for T_OBJECT.
- if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) {
- IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
- }
-
- if (!rb_shape_transition_shape_remove_ivar(obj, id, shape, &val)) {
- if (!rb_shape_obj_too_complex(obj)) {
- rb_evict_ivars_to_hash(obj);
- }
-
- st_table *table = NULL;
- switch (BUILTIN_TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- table = RCLASS_IV_HASH(obj);
- break;
-
- case T_OBJECT:
- table = ROBJECT_IV_HASH(obj);
- break;
+ switch (BUILTIN_TYPE(obj)) {
+ case T_OBJECT:
+ UNREACHABLE_RETURN(Qundef);
+ case T_CLASS:
+ case T_MODULE:
+ {
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ VALUE val = rb_imemo_fields_ptr(fields_obj)[index];
- default: {
- struct gen_ivtbl *ivtbl;
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- table = ivtbl->as.complex.table;
+ if (UNLIKELY(!rb_ractor_main_p()) && !rb_ractor_shareable_p(val)) {
+ rb_raise(rb_eRactorIsolationError,
+ "can not get unshareable values from instance variables of classes/modules from non-main Ractors");
}
- break;
- }
- }
- if (table) {
- if (!st_delete(table, (st_data_t *)&id, (st_data_t *)&val)) {
- val = undef;
- }
+ return val;
+ }
+ default:
+ {
+ VALUE fields_obj = rb_obj_fields(obj, id);
+ return rb_imemo_fields_ptr(fields_obj)[index];
}
}
-
- return val;
}
VALUE
-rb_attr_delete(VALUE obj, ID id)
+rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index)
{
- return rb_ivar_delete(obj, id, Qnil);
+ // Used by JITs, but never for T_OBJECT.
+
+ VALUE fields_obj;
+ switch (BUILTIN_TYPE(obj)) {
+ case T_OBJECT:
+ UNREACHABLE_RETURN(Qundef);
+ case T_CLASS:
+ case T_MODULE:
+ fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ break;
+ default:
+ fields_obj = rb_obj_fields_no_ractor_check(obj);
+ break;
+ }
+ return rb_imemo_fields_ptr(fields_obj)[index];
}
-void
-rb_obj_convert_to_too_complex(VALUE obj, st_table *table)
+VALUE
+rb_attr_get(VALUE obj, ID id)
{
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ return rb_ivar_lookup(obj, id, Qnil);
+}
+
+void rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table);
+static VALUE imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id);
- VALUE *old_ivptr = NULL;
+static shape_id_t
+obj_transition_complex(VALUE obj, st_table *table)
+{
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
+ shape_id_t shape_id = rb_obj_shape_transition_complex(obj);
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
- old_ivptr = ROBJECT_IVPTR(obj);
+ {
+ VALUE *old_fields = NULL;
+ uint32_t old_fields_len = 0;
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ old_fields = ROBJECT_FIELDS(obj);
+ old_fields_len = ROBJECT_FIELDS_CAPACITY(obj);
+ }
+ else {
+ FL_SET_RAW(obj, ROBJECT_HEAP);
+ }
+ RBASIC_SET_SHAPE_ID(obj, shape_id);
+ ROBJECT_SET_FIELDS_HASH(obj, table);
+ if (old_fields) {
+ SIZED_FREE_N(old_fields, old_fields_len);
+ }
}
- rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
- ROBJECT_SET_IV_HASH(obj, table);
break;
case T_CLASS:
case T_MODULE:
- old_ivptr = RCLASS_IVPTR(obj);
- rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
- RCLASS_SET_IV_HASH(obj, table);
+ case T_IMEMO:
+ UNREACHABLE;
break;
default:
- RB_VM_LOCK_ENTER();
{
- struct st_table *gen_ivs = generic_ivtbl_no_ractor_check(obj);
-
- struct gen_ivtbl *old_ivtbl = NULL;
- st_lookup(gen_ivs, (st_data_t)obj, (st_data_t *)&old_ivtbl);
-
- if (old_ivtbl) {
- /* We need to modify old_ivtbl to have the too complex shape
- * and hold the table because the xmalloc could trigger a GC
- * compaction. We want the table to be updated rather than
- * the original ivptr. */
-#if SHAPE_IN_BASIC_FLAGS
- rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
-#else
- old_ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
-#endif
- old_ivtbl->as.complex.table = table;
- old_ivptr = (VALUE *)old_ivtbl;
- }
-
- struct gen_ivtbl *ivtbl = xmalloc(sizeof(struct gen_ivtbl));
- ivtbl->as.complex.table = table;
- st_insert(gen_ivs, (st_data_t)obj, (st_data_t)ivtbl);
-#if SHAPE_IN_BASIC_FLAGS
- rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
-#else
- ivtbl->shape_id = OBJ_TOO_COMPLEX_SHAPE_ID;
-#endif
+ VALUE fields_obj = rb_imemo_fields_new_complex_tbl(obj, shape_id, table, RB_OBJ_SHAREABLE_P(obj));
+ rb_obj_replace_fields(obj, fields_obj);
}
- RB_VM_LOCK_LEAVE();
}
- xfree(old_ivptr);
+ return shape_id;
+}
+
+// Copy all object fields, including ivars and internal object_id, etc
+static shape_id_t
+rb_evict_fields_to_hash(VALUE obj)
+{
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
+
+ st_table *table = st_init_numtable_with_size(RSHAPE_LEN(RBASIC_SHAPE_ID(obj)));
+ rb_obj_copy_fields_to_hash_table(obj, table);
+ shape_id_t new_shape_id = obj_transition_complex(obj, table);
+
+ RUBY_ASSERT(rb_obj_shape_complex_p(obj));
+ return new_shape_id;
}
void
rb_evict_ivars_to_hash(VALUE obj)
{
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
st_table *table = st_init_numtable_with_size(rb_ivar_count(obj));
// Evacuate all previous values from shape into id_table
rb_obj_copy_ivs_to_hash_table(obj, table);
- rb_obj_convert_to_too_complex(obj, table);
+ obj_transition_complex(obj, table);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(rb_obj_shape_complex_p(obj));
}
-struct general_ivar_set_result {
- attr_index_t index;
- bool existing;
-};
+static VALUE
+rb_ivar_delete(VALUE obj, ID id, VALUE undef)
+{
+ rb_check_frozen(obj);
-static struct general_ivar_set_result
-general_ivar_set(VALUE obj, ID id, VALUE val, void *data,
- VALUE *(*shape_ivptr_func)(VALUE, void *),
- void (*shape_resize_ivptr_func)(VALUE, attr_index_t, attr_index_t, void *),
- void (*set_shape_func)(VALUE, rb_shape_t *, void *),
- void (*transition_too_complex_func)(VALUE, void *),
- st_table *(*too_complex_table_func)(VALUE, void *))
-{
- struct general_ivar_set_result result = {
- .index = 0,
- .existing = true
- };
+ VALUE val = undef;
+ VALUE fields_obj;
+ bool concurrent = false;
+ int type = BUILTIN_TYPE(obj);
- rb_shape_t *current_shape = rb_shape_get_shape(obj);
+ switch(type) {
+ case T_CLASS:
+ case T_MODULE:
+ IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
- if (UNLIKELY(current_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- goto too_complex;
+ fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (rb_multi_ractor_p()) {
+ concurrent = true;
+ }
+ break;
+ case T_OBJECT:
+ fields_obj = obj;
+ break;
+ default: {
+ fields_obj = rb_obj_fields(obj, id);
+ break;
+ }
}
- attr_index_t index;
- if (!rb_shape_get_iv_index(current_shape, id, &index)) {
- result.existing = false;
+ if (!fields_obj) {
+ return undef;
+ }
+
+ const VALUE original_fields_obj = fields_obj;
+ if (concurrent) {
+ fields_obj = rb_imemo_fields_clone(fields_obj);
+ }
- index = current_shape->next_iv_index;
- if (index >= MAX_IVARS) {
- rb_raise(rb_eArgError, "too many instance variables");
+ shape_id_t old_shape_id = RBASIC_SHAPE_ID(fields_obj);
+ shape_id_t removed_shape_id;
+ shape_id_t next_shape_id = rb_obj_shape_transition_remove_ivar(fields_obj, id, &removed_shape_id);
+
+ if (UNLIKELY(rb_shape_complex_p(next_shape_id))) {
+ if (UNLIKELY(!rb_shape_complex_p(old_shape_id))) {
+ if (type == T_OBJECT) {
+ rb_evict_fields_to_hash(obj);
+ }
+ else {
+ fields_obj = imemo_fields_complex_from_obj(obj, fields_obj, next_shape_id);
+ }
+ }
+ st_data_t key = id;
+ if (!st_delete(rb_imemo_fields_complex_tbl(fields_obj), &key, (st_data_t *)&val)) {
+ val = undef;
+ }
+ }
+ else {
+ if (next_shape_id == old_shape_id) {
+ return undef;
}
- rb_shape_t *next_shape = rb_shape_get_next(current_shape, obj, id);
- if (UNLIKELY(next_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- transition_too_complex_func(obj, data);
- goto too_complex;
+ RUBY_ASSERT(removed_shape_id != INVALID_SHAPE_ID);
+ RUBY_ASSERT(RSHAPE_LEN(next_shape_id) == RSHAPE_LEN(old_shape_id) - 1);
+
+ VALUE *fields = rb_imemo_fields_ptr(fields_obj);
+ attr_index_t removed_index = RSHAPE_INDEX(removed_shape_id);
+ val = fields[removed_index];
+
+ attr_index_t new_fields_count = RSHAPE_LEN(next_shape_id);
+ if (new_fields_count) {
+ size_t trailing_fields = new_fields_count - removed_index;
+
+ MEMMOVE(&fields[removed_index], &fields[removed_index + 1], VALUE, trailing_fields);
+ RUBY_ASSERT(rb_shape_layout(next_shape_id) == SHAPE_ID_LAYOUT_ROBJECT);
+ RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id);
+
+ if (FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP)) {
+ if (rb_obj_embedded_size(new_fields_count) <= rb_gc_obj_slot_size(fields_obj)) {
+ // 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)
+ FL_UNSET_RAW(fields_obj, ROBJECT_HEAP);
+ MEMCPY(rb_imemo_fields_ptr(fields_obj), fields, VALUE, new_fields_count);
+ SIZED_FREE_N(fields, RSHAPE_CAPACITY(old_shape_id));
+ }
+ else if (RSHAPE_CAPACITY(old_shape_id) != RSHAPE_CAPACITY(next_shape_id)) {
+ IMEMO_OBJ_FIELDS(fields_obj)->as.external.ptr = ruby_xrealloc_sized(fields, RSHAPE_CAPACITY(next_shape_id) * sizeof(VALUE), RSHAPE_CAPACITY(old_shape_id) * sizeof(VALUE));
+ }
+ }
}
- else if (UNLIKELY(next_shape->capacity != current_shape->capacity)) {
- RUBY_ASSERT(next_shape->capacity > current_shape->capacity);
- shape_resize_ivptr_func(obj, current_shape->capacity, next_shape->capacity, data);
+ else {
+ fields_obj = 0;
+ rb_free_generic_ivar(obj);
}
+ }
- RUBY_ASSERT(next_shape->type == SHAPE_IVAR);
- RUBY_ASSERT(index == (next_shape->next_iv_index - 1));
- set_shape_func(obj, next_shape, data);
+ RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | next_shape_id);
+ if (fields_obj != original_fields_obj) {
+ switch (type) {
+ case T_OBJECT:
+ break;
+ case T_CLASS:
+ case T_MODULE:
+ RCLASS_WRITABLE_SET_FIELDS_OBJ(obj, fields_obj);
+ break;
+ default:
+ rb_obj_set_fields(obj, fields_obj, id, original_fields_obj);
+ break;
+ }
}
- VALUE *table = shape_ivptr_func(obj, data);
- RB_OBJ_WRITE(obj, &table[index], val);
+ return val;
+}
- result.index = index;
- return result;
+VALUE
+rb_attr_delete(VALUE obj, ID id)
+{
+ return rb_ivar_delete(obj, id, Qnil);
+}
-too_complex:
- {
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+void
+rb_obj_init_complex(VALUE obj, st_table *table)
+{
+ // This method is meant to be called on newly allocated object.
+ RUBY_ASSERT(rb_shape_canonical_p(RBASIC_SHAPE_ID(obj)));
+ RUBY_ASSERT(RSHAPE_LEN(RBASIC_SHAPE_ID(obj)) == 0);
- st_table *table = too_complex_table_func(obj, data);
- result.existing = st_insert(table, (st_data_t)id, (st_data_t)val);
- result.index = 0;
- RB_OBJ_WRITTEN(obj, Qundef, val);
+ if (rb_obj_shape_complex_p(obj)) {
+ st_table *old_table = ROBJECT_FIELDS_HASH(obj);
+ ROBJECT_SET_FIELDS_HASH(obj, table);
+ if (old_table) st_free_table(old_table);
+ }
+ else {
+ obj_transition_complex(obj, table);
}
- return result;
}
-struct gen_ivar_lookup_ensure_size {
- VALUE obj;
- ID id;
- struct gen_ivtbl *ivtbl;
- rb_shape_t *shape;
- bool resize;
-};
-
static int
-generic_ivar_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int existing)
+imemo_fields_complex_from_obj_i(ID key, VALUE val, st_data_t arg)
{
- ASSERT_vm_locking();
+ VALUE fields = (VALUE)arg;
+ st_table *table = rb_imemo_fields_complex_tbl(fields);
- struct gen_ivar_lookup_ensure_size *ivar_lookup = (struct gen_ivar_lookup_ensure_size *)u;
- struct gen_ivtbl *ivtbl = existing ? (struct gen_ivtbl *)*v : NULL;
+ RUBY_ASSERT(!st_lookup(table, (st_data_t)key, NULL));
+ st_add_direct(table, (st_data_t)key, (st_data_t)val);
+ RB_OBJ_WRITTEN(fields, Qundef, val);
- if (!existing || ivar_lookup->resize) {
- if (existing) {
- RUBY_ASSERT(ivar_lookup->shape->type == SHAPE_IVAR);
- RUBY_ASSERT(rb_shape_get_shape_by_id(ivar_lookup->shape->parent_id)->capacity < ivar_lookup->shape->capacity);
- }
- else {
- FL_SET_RAW((VALUE)*k, FL_EXIVAR);
- }
-
- ivtbl = gen_ivtbl_resize(ivtbl, ivar_lookup->shape->capacity);
- *v = (st_data_t)ivtbl;
- }
+ return ST_CONTINUE;
+}
- RUBY_ASSERT(FL_TEST((VALUE)*k, FL_EXIVAR));
+static VALUE
+imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id)
+{
+ attr_index_t len = source_fields_obj ? RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)) : 0;
+ VALUE fields_obj = rb_imemo_fields_new_complex(owner, shape_id, len + 1, RB_OBJ_SHAREABLE_P(owner));
- ivar_lookup->ivtbl = ivtbl;
- if (ivar_lookup->shape) {
-#if SHAPE_IN_BASIC_FLAGS
- rb_shape_set_shape(ivar_lookup->obj, ivar_lookup->shape);
-#else
- ivtbl->shape_id = rb_shape_id(ivar_lookup->shape);
-#endif
- }
+ rb_field_foreach(source_fields_obj, imemo_fields_complex_from_obj_i, (st_data_t)fields_obj, false);
- return ST_CONTINUE;
+ return fields_obj;
}
-static VALUE *
-generic_ivar_set_shape_ivptr(VALUE obj, void *data)
+static VALUE
+imemo_fields_copy_append(VALUE owner, VALUE source_fields_obj, shape_id_t current_shape_id, shape_id_t target_shape_id, VALUE val)
{
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ attr_index_t fields_count = RSHAPE_LEN(current_shape_id);
- struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
+ VALUE fields_obj = rb_imemo_fields_new(owner, target_shape_id, RB_OBJ_SHAREABLE_P(owner));
- RB_VM_LOCK_ENTER();
- {
- st_update(generic_ivtbl(obj, ivar_lookup->id, false), (st_data_t)obj, generic_ivar_lookup_ensure_size, (st_data_t)ivar_lookup);
+ VALUE *fields = rb_imemo_fields_ptr(fields_obj);
+
+ if (source_fields_obj) {
+ MEMCPY(fields, rb_imemo_fields_ptr(source_fields_obj), VALUE, fields_count);
+ for (attr_index_t i = 0; i < fields_count; i++) {
+ RB_OBJ_WRITTEN(fields_obj, Qundef, fields[i]);
+ }
}
- RB_VM_LOCK_LEAVE();
- FL_SET_RAW(obj, FL_EXIVAR);
+ RB_OBJ_WRITE(fields_obj, &fields[fields_count], val);
- return ivar_lookup->ivtbl->as.shape.ivptr;
+ return fields_obj;
}
-static void
-generic_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *data)
-{
- struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
+static VALUE
+imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent)
+{
+ const VALUE original_fields_obj = fields_obj;
+ shape_id_t current_shape_id = fields_obj ? RBASIC_SHAPE_ID(fields_obj) : ROOT_SHAPE_ID;
+
+ if (UNLIKELY(rb_shape_complex_p(target_shape_id))) {
+ if (rb_shape_complex_p(current_shape_id)) {
+ if (concurrent) {
+ // In multi-ractor case, we must always work on a copy because
+ // even if the field already exist, inserting in a st_table may
+ // cause a rebuild.
+ fields_obj = rb_imemo_fields_clone(fields_obj);
+ }
+ }
+ else {
+ fields_obj = imemo_fields_complex_from_obj(owner, original_fields_obj, target_shape_id);
+ current_shape_id = target_shape_id;
+ }
- ivar_lookup->resize = true;
-}
+ st_table *table = rb_imemo_fields_complex_tbl(fields_obj);
-static void
-generic_ivar_set_set_shape(VALUE obj, rb_shape_t *shape, void *data)
-{
- struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
+ RUBY_ASSERT(field_name);
+ st_insert(table, (st_data_t)field_name, (st_data_t)val);
+ RB_OBJ_WRITTEN(fields_obj, Qundef, val);
+ RBASIC_SET_SHAPE_ID(fields_obj, rb_shape_id_with_robject_layout(target_shape_id));
+ }
+ else {
+ attr_index_t index = RSHAPE_INDEX(target_shape_id);
+ if (concurrent || index >= RSHAPE_CAPACITY(current_shape_id)) {
+ return imemo_fields_copy_append(owner, original_fields_obj, current_shape_id, target_shape_id, val);
+ }
+
+ VALUE *table = rb_imemo_fields_ptr(fields_obj);
+ RB_OBJ_WRITE(fields_obj, &table[index], val);
- ivar_lookup->shape = shape;
+ if (index >= RSHAPE_LEN(current_shape_id)) {
+ RBASIC_SET_SHAPE_ID(fields_obj, rb_shape_id_with_robject_layout(target_shape_id));
+ }
+ }
+
+ return fields_obj;
}
-static void
-generic_ivar_set_transition_too_complex(VALUE obj, void *_data)
+static attr_index_t
+generic_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val)
{
- rb_evict_ivars_to_hash(obj);
- FL_SET_RAW(obj, FL_EXIVAR);
+ if (!field_name) {
+ field_name = RSHAPE_EDGE_NAME(target_shape_id);
+ RUBY_ASSERT(field_name);
+ }
+
+ const VALUE original_fields_obj = rb_obj_fields(obj, field_name);
+ VALUE fields_obj = imemo_fields_set(obj, original_fields_obj, target_shape_id, field_name, val, false);
+
+ rb_obj_set_fields(obj, fields_obj, field_name, original_fields_obj);
+ return rb_shape_complex_p(target_shape_id) ? ATTR_INDEX_NOT_SET : RSHAPE_INDEX(target_shape_id);
}
-static st_table *
-generic_ivar_set_too_complex_table(VALUE obj, void *data)
+static shape_id_t
+generic_shape_ivar(VALUE obj, ID id, bool *new_ivar_out)
{
- struct gen_ivar_lookup_ensure_size *ivar_lookup = data;
-
- struct gen_ivtbl *ivtbl;
- if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- ivtbl = xmalloc(sizeof(struct gen_ivtbl));
-#if !SHAPE_IN_BASIC_FLAGS
- ivtbl->shape_id = SHAPE_OBJ_TOO_COMPLEX;
-#endif
- ivtbl->as.complex.table = st_init_numtable_with_size(1);
+ bool new_ivar = false;
+ shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
+ shape_id_t target_shape_id = current_shape_id;
- RB_VM_LOCK_ENTER();
- {
- st_insert(generic_ivtbl(obj, ivar_lookup->id, false), (st_data_t)obj, (st_data_t)ivtbl);
+ if (!rb_shape_complex_p(current_shape_id)) {
+ if (!rb_shape_find_ivar(current_shape_id, id, &target_shape_id)) {
+ new_ivar = true;
+ target_shape_id = rb_obj_shape_transition_add_ivar(obj, id);
}
- RB_VM_LOCK_LEAVE();
-
- FL_SET_RAW(obj, FL_EXIVAR);
}
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
-
- return ivtbl->as.complex.table;
+ *new_ivar_out = new_ivar;
+ return target_shape_id;
}
-static void
+static attr_index_t
generic_ivar_set(VALUE obj, ID id, VALUE val)
{
- struct gen_ivar_lookup_ensure_size ivar_lookup = {
- .obj = obj,
- .id = id,
- .resize = false,
- .shape = NULL,
- };
-
- general_ivar_set(obj, id, val, &ivar_lookup,
- generic_ivar_set_shape_ivptr,
- generic_ivar_set_shape_resize_ivptr,
- generic_ivar_set_set_shape,
- generic_ivar_set_transition_too_complex,
- generic_ivar_set_too_complex_table);
+ bool dontcare;
+ shape_id_t target_shape_id = generic_shape_ivar(obj, id, &dontcare);
+ return generic_field_set(obj, target_shape_id, id, val);
}
void
-rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capacity)
+rb_ensure_iv_list_size(VALUE obj, uint32_t current_len, uint32_t new_capacity)
{
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(!rb_obj_shape_complex_p(obj));
- if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- VALUE *ptr = ROBJECT_IVPTR(obj);
- VALUE *newptr = ALLOC_N(VALUE, new_capacity);
- MEMCPY(newptr, ptr, VALUE, current_capacity);
- RB_FL_UNSET_RAW(obj, ROBJECT_EMBED);
- ROBJECT(obj)->as.heap.ivptr = newptr;
+ if (FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ SIZED_REALLOC_N(ROBJECT(obj)->as.heap.fields, VALUE, new_capacity, current_len);
}
else {
- REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, new_capacity);
+ VALUE *ptr = ROBJECT_FIELDS(obj);
+ VALUE *newptr = ALLOC_N(VALUE, new_capacity);
+ MEMCPY(newptr, ptr, VALUE, current_len);
+ FL_SET_RAW(obj, ROBJECT_HEAP);
+ ROBJECT(obj)->as.heap.fields = newptr;
}
}
@@ -1777,49 +1936,58 @@ rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table)
rb_ivar_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table);
}
-static VALUE *
-obj_ivar_set_shape_ivptr(VALUE obj, void *_data)
+void
+rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table)
{
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
-
- return ROBJECT_IVPTR(obj);
+ rb_field_foreach(obj, rb_obj_copy_ivs_to_hash_table_i, (st_data_t)table, false);
}
-static void
-obj_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t old_capa, attr_index_t new_capa, void *_data)
+static attr_index_t
+obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val)
{
- rb_ensure_iv_list_size(obj, old_capa, new_capa);
-}
+ shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
-static void
-obj_ivar_set_set_shape(VALUE obj, rb_shape_t *shape, void *_data)
-{
- rb_shape_set_shape(obj, shape);
-}
+ if (UNLIKELY(rb_shape_complex_p(target_shape_id))) {
+ if (UNLIKELY(!rb_shape_complex_p(current_shape_id))) {
+ current_shape_id = rb_evict_fields_to_hash(obj);
+ }
-static void
-obj_ivar_set_transition_too_complex(VALUE obj, void *_data)
-{
- rb_evict_ivars_to_hash(obj);
-}
+ if (RSHAPE_LEN(target_shape_id) > RSHAPE_LEN(current_shape_id)) {
+ RBASIC_SET_SHAPE_ID(obj, target_shape_id);
+ }
-static st_table *
-obj_ivar_set_too_complex_table(VALUE obj, void *_data)
-{
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ if (!field_name) {
+ field_name = RSHAPE_EDGE_NAME(target_shape_id);
+ RUBY_ASSERT(field_name);
+ }
+
+ st_insert(ROBJECT_FIELDS_HASH(obj), (st_data_t)field_name, (st_data_t)val);
+ RB_OBJ_WRITTEN(obj, Qundef, val);
+
+ return ATTR_INDEX_NOT_SET;
+ }
+ else {
+ attr_index_t index = RSHAPE_INDEX(target_shape_id);
+
+ if (index >= RSHAPE_LEN(current_shape_id)) {
+ if (UNLIKELY(index >= RSHAPE_CAPACITY(current_shape_id))) {
+ rb_ensure_iv_list_size(obj, RSHAPE_CAPACITY(current_shape_id), RSHAPE_CAPACITY(target_shape_id));
+ }
+ RBASIC_SET_SHAPE_ID(obj, target_shape_id);
+ }
+
+ RB_OBJ_WRITE(obj, &ROBJECT_FIELDS(obj)[index], val);
- return ROBJECT_IV_HASH(obj);
+ return index;
+ }
}
-attr_index_t
-rb_obj_ivar_set(VALUE obj, ID id, VALUE val)
+static attr_index_t
+obj_ivar_set(VALUE obj, ID id, VALUE val)
{
- return general_ivar_set(obj, id, val, NULL,
- obj_ivar_set_shape_ivptr,
- obj_ivar_set_shape_resize_ivptr,
- obj_ivar_set_set_shape,
- obj_ivar_set_transition_too_complex,
- obj_ivar_set_too_complex_table).index;
+ bool dontcare;
+ shape_id_t target_shape_id = generic_shape_ivar(obj, id, &dontcare);
+ return obj_field_set(obj, target_shape_id, id, val);
}
/* Set the instance variable +val+ on object +obj+ at ivar name +id+.
@@ -1830,51 +1998,12 @@ VALUE
rb_vm_set_ivar_id(VALUE obj, ID id, VALUE val)
{
rb_check_frozen(obj);
- rb_obj_ivar_set(obj, id, val);
+ obj_ivar_set(obj, id, val);
return val;
}
-bool
-rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id)
-{
- if (rb_shape_get_shape_id(obj) == shape_id) {
- return false;
- }
-
-#if SHAPE_IN_BASIC_FLAGS
- RBASIC_SET_SHAPE_ID(obj, shape_id);
-#else
- switch (BUILTIN_TYPE(obj)) {
- case T_OBJECT:
- ROBJECT_SET_SHAPE_ID(obj, shape_id);
- break;
- case T_CLASS:
- case T_MODULE:
- RCLASS_SET_SHAPE_ID(obj, shape_id);
- break;
- default:
- if (shape_id != SPECIAL_CONST_SHAPE_ID) {
- struct gen_ivtbl *ivtbl = 0;
- RB_VM_LOCK_ENTER();
- {
- st_table* global_iv_table = generic_ivtbl(obj, 0, false);
-
- if (st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) {
- ivtbl->shape_id = shape_id;
- }
- else {
- rb_bug("Expected shape_id entry in global iv table");
- }
- }
- RB_VM_LOCK_LEAVE();
- }
- }
-#endif
-
- return true;
-}
-
-void rb_obj_freeze_inline(VALUE x)
+void
+rb_obj_freeze_inline(VALUE x)
{
if (RB_FL_ABLE(x)) {
RB_FL_SET_RAW(x, RUBY_FL_FREEZE);
@@ -1882,41 +2011,45 @@ void rb_obj_freeze_inline(VALUE x)
RB_FL_UNSET_RAW(x, FL_USER2 | FL_USER3); // STR_CHILLED
}
- rb_shape_t * next_shape = rb_shape_transition_shape_frozen(x);
-
- // If we're transitioning from "not complex" to "too complex"
- // then evict ivars. This can happen if we run out of shapes
- if (!rb_shape_obj_too_complex(x) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- rb_evict_ivars_to_hash(x);
+ // rb_obj_freeze_inline(String)
+ shape_id_t shape_id = rb_obj_shape_transition_frozen(x);
+ switch (BUILTIN_TYPE(x)) {
+ case T_CLASS:
+ case T_MODULE:
+ rb_obj_freeze_inline(RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(x));
+ // FIXME: How to do multi-shape?
+ RBASIC_SET_SHAPE_ID(x, shape_id);
+ break;
+ default:
+ RBASIC_SET_SHAPE_ID(x, shape_id);
+ break;
}
- rb_shape_set_shape(x, next_shape);
- if (RBASIC_CLASS(x)) {
+ if (RBASIC_CLASS(x) && RCLASS_SINGLETON_P(RBASIC_CLASS(x))) {
rb_freeze_singleton_class(x);
}
}
}
-static void
+static attr_index_t class_ivar_set(VALUE obj, ID id, VALUE val, bool *new_ivar);
+
+static attr_index_t
ivar_set(VALUE obj, ID id, VALUE val)
{
RB_DEBUG_COUNTER_INC(ivar_set_base);
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- {
- rb_obj_ivar_set(obj, id, val);
- break;
- }
+ return obj_ivar_set(obj, id, val);
case T_CLASS:
case T_MODULE:
- IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
- rb_class_ivar_set(obj, id, val);
-
- break;
+ {
+ IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id);
+ bool dontcare;
+ return class_ivar_set(obj, id, val, &dontcare);
+ }
default:
- generic_ivar_set(obj, id, val);
- break;
+ return generic_ivar_set(obj, id, val);
}
}
@@ -1928,6 +2061,12 @@ rb_ivar_set(VALUE obj, ID id, VALUE val)
return val;
}
+attr_index_t
+rb_ivar_set_index(VALUE obj, ID id, VALUE val)
+{
+ return ivar_set(obj, id, val);
+}
+
void
rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
{
@@ -1937,31 +2076,48 @@ rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
ivar_set(obj, id, val);
}
-VALUE
-rb_ivar_defined(VALUE obj, ID id)
+attr_index_t
+rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val)
+{
+ switch (BUILTIN_TYPE(obj)) {
+ case T_OBJECT:
+ return obj_field_set(obj, target_shape_id, field_name, val);
+ case T_CLASS:
+ case T_MODULE:
+ // The only field is object_id and T_CLASS handle it differently.
+ rb_bug("Unreachable");
+ break;
+ default:
+ return generic_field_set(obj, target_shape_id, field_name, val);
+ }
+}
+
+static VALUE
+ivar_defined0(VALUE obj, ID id)
{
attr_index_t index;
- if (SPECIAL_CONST_P(obj)) return Qfalse;
- if (rb_shape_obj_too_complex(obj)) {
+ if (rb_obj_shape_complex_p(obj)) {
VALUE idx;
st_table *table = NULL;
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
- table = (st_table *)RCLASS_IVPTR(obj);
+ rb_bug("Unreachable");
+ break;
+
+ case T_IMEMO:
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
+ table = rb_imemo_fields_complex_tbl(obj);
break;
case T_OBJECT:
- table = ROBJECT_IV_HASH(obj);
+ table = ROBJECT_FIELDS_HASH(obj);
break;
default: {
- struct gen_ivtbl *ivtbl;
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- table = ivtbl->as.complex.table;
- }
- break;
+ VALUE fields_obj = rb_obj_fields_no_ractor_check(obj); // defined? doesn't require ractor checks
+ table = rb_imemo_fields_complex_tbl(fields_obj);
}
}
@@ -1972,66 +2128,85 @@ rb_ivar_defined(VALUE obj, ID id)
return Qtrue;
}
else {
- return RBOOL(rb_shape_get_iv_index(rb_shape_get_shape(obj), id, &index));
+ return RBOOL(rb_shape_get_iv_index(RBASIC_SHAPE_ID(obj), id, &index));
}
}
-typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg);
+VALUE
+rb_ivar_defined(VALUE obj, ID id)
+{
+ if (SPECIAL_CONST_P(obj)) return Qfalse;
+
+ VALUE defined = Qfalse;
+ switch (BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ {
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (fields_obj) {
+ defined = ivar_defined0(fields_obj, id);
+ }
+ }
+ break;
+ default:
+ defined = ivar_defined0(obj, id);
+ break;
+ }
+ return defined;
+}
struct iv_itr_data {
VALUE obj;
- struct gen_ivtbl * ivtbl;
+ struct gen_fields_tbl *fields_tbl;
st_data_t arg;
rb_ivar_foreach_callback_func *func;
+ VALUE *fields;
+ shape_id_t shape_id;
+ bool ivar_only;
};
-/*
- * Returns a flag to stop iterating depending on the result of +callback+.
- */
-static bool
-iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_func *callback, struct iv_itr_data * itr_data)
+static int
+iterate_over_shapes_callback(shape_id_t shape_id, void *data)
{
- switch ((enum shape_type)shape->type) {
- case SHAPE_ROOT:
- case SHAPE_T_OBJECT:
- return false;
- case SHAPE_IVAR:
- ASSUME(callback);
- if (iterate_over_shapes_with_callback(rb_shape_get_parent(shape), callback, itr_data))
- return true;
- VALUE * iv_list;
- switch (BUILTIN_TYPE(itr_data->obj)) {
- case T_OBJECT:
- RUBY_ASSERT(!rb_shape_obj_too_complex(itr_data->obj));
- iv_list = ROBJECT_IVPTR(itr_data->obj);
- break;
- case T_CLASS:
- case T_MODULE:
- iv_list = RCLASS_IVPTR(itr_data->obj);
- break;
- default:
- iv_list = itr_data->ivtbl->as.shape.ivptr;
- break;
- }
- VALUE val = iv_list[shape->next_iv_index - 1];
- if (!UNDEF_P(val)) {
- switch (callback(shape->edge_name, val, itr_data->arg)) {
- case ST_CHECK:
- case ST_CONTINUE:
- break;
- case ST_STOP:
- return true;
- default:
- rb_bug("unreachable");
- }
- }
- return false;
- case SHAPE_FROZEN:
- return iterate_over_shapes_with_callback(rb_shape_get_parent(shape), callback, itr_data);
- case SHAPE_OBJ_TOO_COMPLEX:
+ struct iv_itr_data *itr_data = data;
+
+ if (itr_data->ivar_only && !RSHAPE_TYPE_P(shape_id, SHAPE_IVAR)) {
+ return ST_CONTINUE;
+ }
+
+ VALUE *fields;
+ switch (BUILTIN_TYPE(itr_data->obj)) {
+ case T_OBJECT:
+ RUBY_ASSERT(!rb_obj_shape_complex_p(itr_data->obj));
+ fields = ROBJECT_FIELDS(itr_data->obj);
+ break;
+ case T_IMEMO:
+ RUBY_ASSERT(IMEMO_TYPE_P(itr_data->obj, imemo_fields));
+ RUBY_ASSERT(!rb_obj_shape_complex_p(itr_data->obj));
+
+ fields = rb_imemo_fields_ptr(itr_data->obj);
+ break;
default:
rb_bug("Unreachable");
}
+
+ RUBY_ASSERT(itr_data->shape_id == RBASIC_SHAPE_ID(itr_data->obj));
+
+ VALUE val = fields[RSHAPE_INDEX(shape_id)];
+ int ret = itr_data->func(RSHAPE_EDGE_NAME(shape_id), val, itr_data->arg);
+
+ RUBY_ASSERT(itr_data->shape_id == RBASIC_SHAPE_ID(itr_data->obj));
+
+ return ret;
+}
+
+/*
+ * Returns a flag to stop iterating depending on the result of +callback+.
+ */
+static void
+iterate_over_shapes(shape_id_t shape_id, rb_ivar_foreach_callback_func *callback, struct iv_itr_data *itr_data)
+{
+ rb_shape_foreach_field(shape_id, iterate_over_shapes_callback, itr_data);
}
static int
@@ -2039,171 +2214,262 @@ each_hash_iv(st_data_t id, st_data_t val, st_data_t data)
{
struct iv_itr_data * itr_data = (struct iv_itr_data *)data;
rb_ivar_foreach_callback_func *callback = itr_data->func;
- return callback((ID)id, (VALUE)val, itr_data->arg);
-}
-
-static void
-obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
-{
- rb_shape_t* shape = rb_shape_get_shape(obj);
- struct iv_itr_data itr_data;
- itr_data.obj = obj;
- itr_data.arg = arg;
- itr_data.func = func;
- if (rb_shape_obj_too_complex(obj)) {
- rb_st_foreach(ROBJECT_IV_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
- }
- else {
- iterate_over_shapes_with_callback(shape, func, &itr_data);
+ if (is_internal_id((ID)id)) {
+ return ST_CONTINUE;
}
+ return callback((ID)id, (VALUE)val, itr_data->arg);
}
static void
-gen_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+obj_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only)
{
- rb_shape_t *shape = rb_shape_get_shape(obj);
- struct gen_ivtbl *ivtbl;
- if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) return;
+ struct iv_itr_data itr_data = {
+ .obj = obj,
+ .arg = arg,
+ .func = func,
+ .ivar_only = ivar_only,
+ };
- struct iv_itr_data itr_data;
- itr_data.obj = obj;
- itr_data.ivtbl = ivtbl;
- itr_data.arg = arg;
- itr_data.func = func;
- if (rb_shape_obj_too_complex(obj)) {
- rb_st_foreach(ivtbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data);
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ if (rb_shape_complex_p(shape_id)) {
+ st_foreach_safe(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
}
else {
- iterate_over_shapes_with_callback(shape, func, &itr_data);
+ itr_data.fields = ROBJECT_FIELDS(obj);
+ itr_data.shape_id = shape_id;
+ iterate_over_shapes(shape_id, func, &itr_data);
}
}
static void
-class_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+imemo_fields_each(VALUE fields_obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only)
{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
+ IMEMO_TYPE_P(fields_obj, imemo_fields);
+
+ struct iv_itr_data itr_data = {
+ .obj = fields_obj,
+ .arg = arg,
+ .func = func,
+ .ivar_only = ivar_only,
+ };
- rb_shape_t* shape = rb_shape_get_shape(obj);
- struct iv_itr_data itr_data;
- itr_data.obj = obj;
- itr_data.arg = arg;
- itr_data.func = func;
- if (rb_shape_obj_too_complex(obj)) {
- rb_st_foreach(RCLASS_IV_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
+ shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
+ if (rb_shape_complex_p(shape_id)) {
+ rb_st_foreach(rb_imemo_fields_complex_tbl(fields_obj), each_hash_iv, (st_data_t)&itr_data);
}
else {
- iterate_over_shapes_with_callback(shape, func, &itr_data);
+ itr_data.fields = rb_imemo_fields_ptr(fields_obj);
+ itr_data.shape_id = shape_id;
+ iterate_over_shapes(shape_id, func, &itr_data);
}
}
void
-rb_copy_generic_ivar(VALUE clone, VALUE obj)
+rb_copy_generic_ivar(VALUE dest, VALUE obj)
{
- struct gen_ivtbl *obj_ivtbl;
- struct gen_ivtbl *new_ivtbl;
+ VALUE new_fields_obj;
- rb_check_frozen(clone);
+ rb_check_frozen(dest);
- if (!FL_TEST(obj, FL_EXIVAR)) {
- goto clear;
+ if (!rb_obj_gen_fields_p(obj)) {
+ return;
}
- if (rb_gen_ivtbl_get(obj, 0, &obj_ivtbl)) {
- if (gen_ivtbl_count(obj, obj_ivtbl) == 0)
- goto clear;
+ shape_id_t src_shape_id = rb_obj_shape_id(obj);
- FL_SET(clone, FL_EXIVAR);
+ VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
+ if (fields_obj) {
+ unsigned long src_num_ivs = rb_ivar_count(fields_obj);
+ if (!src_num_ivs) {
+ goto clear;
+ }
- if (rb_shape_obj_too_complex(obj)) {
- new_ivtbl = xmalloc(sizeof(struct gen_ivtbl));
-#if !SHAPE_IN_BASIC_FLAGS
- new_ivtbl->shape_id = SHAPE_OBJ_TOO_COMPLEX;
-#endif
- new_ivtbl->as.complex.table = st_copy(obj_ivtbl->as.complex.table);
+ if (rb_shape_complex_p(src_shape_id)) {
+ rb_shape_copy_complex_ivars(dest, obj, src_shape_id, rb_imemo_fields_complex_tbl(fields_obj));
+ return;
}
- else {
- new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->as.shape.numiv);
- for (uint32_t i=0; i<obj_ivtbl->as.shape.numiv; i++) {
- RB_OBJ_WRITE(clone, &new_ivtbl->as.shape.ivptr[i], obj_ivtbl->as.shape.ivptr[i]);
+ shape_id_t dest_shape_id = src_shape_id;
+ shape_id_t initial_shape_id = rb_obj_shape_id(dest);
+
+ if (!rb_shape_canonical_p(src_shape_id)) {
+ RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT));
+
+ dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id);
+ if (UNLIKELY(rb_shape_complex_p(dest_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_init_complex(dest, table);
+ return;
}
}
- /*
- * c.ivtbl may change in gen_ivar_copy due to realloc,
- * no need to free
- */
- RB_VM_LOCK_ENTER();
- {
- generic_ivtbl_no_ractor_check(clone);
- st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)new_ivtbl);
+ if (!RSHAPE_LEN(dest_shape_id)) {
+ RBASIC_SET_SHAPE_ID(dest, rb_shape_layout(RBASIC_SHAPE_ID(dest)) | dest_shape_id);
+ return;
}
- RB_VM_LOCK_LEAVE();
- rb_shape_t * obj_shape = rb_shape_get_shape(obj);
- if (rb_shape_frozen_shape_p(obj_shape)) {
- rb_shape_set_shape_id(clone, obj_shape->parent_id);
- }
- else {
- rb_shape_set_shape(clone, obj_shape);
- }
+ new_fields_obj = rb_imemo_fields_new(dest, dest_shape_id, RB_OBJ_SHAREABLE_P(dest));
+ VALUE *src_buf = rb_imemo_fields_ptr(fields_obj);
+ VALUE *dest_buf = rb_imemo_fields_ptr(new_fields_obj);
+ rb_shape_copy_fields(new_fields_obj, dest_buf, dest_shape_id, src_buf, src_shape_id);
+
+ rb_obj_replace_fields(dest, new_fields_obj);
}
return;
clear:
- if (FL_TEST(clone, FL_EXIVAR)) {
- rb_free_generic_ivar(clone);
- FL_UNSET(clone, FL_EXIVAR);
+ rb_free_generic_ivar(dest);
+}
+
+void
+rb_replace_generic_ivar(VALUE clone, VALUE obj)
+{
+ RB_VM_LOCKING() {
+ st_data_t fields_tbl, obj_data = (st_data_t)obj;
+ if (st_delete(generic_fields_tbl_, &obj_data, &fields_tbl)) {
+ st_insert(generic_fields_tbl_, (st_data_t)clone, fields_tbl);
+ RB_OBJ_WRITTEN(clone, Qundef, fields_tbl);
+ }
+ else {
+ rb_bug("unreachable");
+ }
}
}
void
-rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, bool ivar_only)
{
if (SPECIAL_CONST_P(obj)) return;
switch (BUILTIN_TYPE(obj)) {
+ case T_IMEMO:
+ if (IMEMO_TYPE_P(obj, imemo_fields)) {
+ imemo_fields_each(obj, func, arg, ivar_only);
+ }
+ break;
case T_OBJECT:
- obj_ivar_each(obj, func, arg);
+ obj_fields_each(obj, func, arg, ivar_only);
break;
case T_CLASS:
case T_MODULE:
- IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0);
- RB_VM_LOCK_ENTER();
{
- class_ivar_each(obj, func, arg);
+ IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0);
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (fields_obj) {
+ imemo_fields_each(fields_obj, func, arg, ivar_only);
+ }
}
- RB_VM_LOCK_LEAVE();
break;
default:
- if (FL_TEST(obj, FL_EXIVAR)) {
- gen_ivar_each(obj, func, arg);
+ {
+ VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
+ if (fields_obj) {
+ imemo_fields_each(fields_obj, func, arg, ivar_only);
+ }
}
break;
}
}
+struct ivar_buf_entry {
+ ID name;
+ VALUE val;
+};
+
+static int
+collect_ivar_i(ID id, VALUE val, st_data_t arg)
+{
+ struct ivar_buf_entry **pos = (struct ivar_buf_entry **)arg;
+ (*pos)->name = id;
+ (*pos)->val = val;
+ (*pos)++;
+ return ST_CONTINUE;
+}
+
+void
+rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+{
+ rb_field_foreach(obj, func, arg, true);
+}
+
+void
+rb_ivar_foreach_buffered(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+{
+ st_index_t count = rb_ivar_count(obj);
+ if (count == 0) return;
+
+ VALUE tmpbuf;
+ struct ivar_buf_entry *buf = ALLOCV_N(struct ivar_buf_entry, tmpbuf, count);
+ struct ivar_buf_entry *pos = buf;
+
+ rb_field_foreach(obj, collect_ivar_i, (st_data_t)&pos, true);
+ RUBY_ASSERT((st_index_t)(pos - buf) == count);
+
+ for (st_index_t i = 0; i < count; i++) {
+ if (func(buf[i].name, buf[i].val, arg) == ST_STOP) break;
+ }
+
+ ALLOCV_END(tmpbuf);
+}
+
st_index_t
rb_ivar_count(VALUE obj)
{
if (SPECIAL_CONST_P(obj)) return 0;
+ st_index_t iv_count = 0;
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- return ROBJECT_IV_COUNT(obj);
+ iv_count = ROBJECT_FIELDS_COUNT(obj);
+ break;
+
case T_CLASS:
case T_MODULE:
- return RCLASS_IV_COUNT(obj);
- default:
- if (FL_TEST(obj, FL_EXIVAR)) {
- struct gen_ivtbl *ivtbl;
+ {
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (!fields_obj) {
+ return 0;
+ }
+ if (rb_obj_shape_complex_p(fields_obj)) {
+ iv_count = rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
+ }
+ else {
+ iv_count = RBASIC_FIELDS_COUNT(fields_obj);
+ }
+ }
+ break;
+
+ case T_IMEMO:
+ RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
+
+ if (rb_obj_shape_complex_p(obj)) {
+ iv_count = rb_st_table_size(rb_imemo_fields_complex_tbl(obj));
+ }
+ else {
+ iv_count = RBASIC_FIELDS_COUNT(obj);
+ }
+ break;
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- return gen_ivtbl_count(obj, ivtbl);
+ default:
+ {
+ VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
+ if (fields_obj) {
+ if (rb_obj_shape_complex_p(fields_obj)) {
+ iv_count = rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
+ }
+ else {
+ iv_count = RBASIC_FIELDS_COUNT(obj);
+ }
}
}
break;
}
- return 0;
+
+ if (rb_obj_shape_has_id(obj)) {
+ iv_count--;
+ }
+
+ return iv_count;
}
static int
@@ -2237,9 +2503,7 @@ ivar_i(ID key, VALUE v, st_data_t a)
VALUE
rb_obj_instance_variables(VALUE obj)
{
- VALUE ary;
-
- ary = rb_ary_new();
+ VALUE ary = rb_ary_new_capa(rb_ivar_count(obj));
rb_ivar_foreach(obj, ivar_i, ary);
return ary;
}
@@ -2427,7 +2691,7 @@ autoload_data(VALUE mod, ID id)
// If we are called with a non-origin ICLASS, fetch the autoload data from
// the original module.
if (RB_TYPE_P(mod, T_ICLASS)) {
- if (FL_TEST_RAW(mod, RICLASS_IS_ORIGIN)) {
+ if (RICLASS_IS_ORIGIN_P(mod)) {
return 0;
}
else {
@@ -2455,6 +2719,10 @@ struct autoload_const {
// The shared "autoload_data" if multiple constants are defined from the same feature.
VALUE autoload_data_value;
+ // The box object when the autoload is called in a user box
+ // Otherwise, Qnil means the root box
+ VALUE box_value;
+
// The module we are loading a constant into.
VALUE module;
@@ -2488,21 +2756,12 @@ struct autoload_data {
};
static void
-autoload_data_compact(void *ptr)
-{
- struct autoload_data *p = ptr;
-
- p->feature = rb_gc_location(p->feature);
- p->mutex = rb_gc_location(p->mutex);
-}
-
-static void
-autoload_data_mark(void *ptr)
+autoload_data_mark_and_move(void *ptr)
{
struct autoload_data *p = ptr;
- rb_gc_mark_movable(p->feature);
- rb_gc_mark_movable(p->mutex);
+ rb_gc_mark_and_move(&p->feature);
+ rb_gc_mark_and_move(&p->mutex);
}
static void
@@ -2515,7 +2774,7 @@ autoload_data_free(void *ptr)
ccan_list_del_init(&autoload_const->cnode);
}
- ruby_xfree(p);
+ SIZED_FREE(p);
}
static size_t
@@ -2526,30 +2785,20 @@ autoload_data_memsize(const void *ptr)
static const rb_data_type_t autoload_data_type = {
"autoload_data",
- {autoload_data_mark, autoload_data_free, autoload_data_memsize, autoload_data_compact},
+ {autoload_data_mark_and_move, autoload_data_free, autoload_data_memsize, autoload_data_mark_and_move},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static void
-autoload_const_compact(void *ptr)
+autoload_const_mark_and_move(void *ptr)
{
struct autoload_const *ac = ptr;
- ac->module = rb_gc_location(ac->module);
- ac->autoload_data_value = rb_gc_location(ac->autoload_data_value);
- ac->value = rb_gc_location(ac->value);
- ac->file = rb_gc_location(ac->file);
-}
-
-static void
-autoload_const_mark(void *ptr)
-{
- struct autoload_const *ac = ptr;
-
- rb_gc_mark_movable(ac->module);
- rb_gc_mark_movable(ac->autoload_data_value);
- rb_gc_mark_movable(ac->value);
- rb_gc_mark_movable(ac->file);
+ rb_gc_mark_and_move(&ac->module);
+ rb_gc_mark_and_move(&ac->autoload_data_value);
+ rb_gc_mark_and_move(&ac->value);
+ rb_gc_mark_and_move(&ac->file);
+ rb_gc_mark_and_move(&ac->box_value);
}
static size_t
@@ -2564,13 +2813,13 @@ autoload_const_free(void *ptr)
struct autoload_const *autoload_const = ptr;
ccan_list_del(&autoload_const->cnode);
- ruby_xfree(ptr);
+ SIZED_FREE(autoload_const);
}
static const rb_data_type_t autoload_const_type = {
"autoload_const",
- {autoload_const_mark, autoload_const_free, autoload_const_memsize, autoload_const_compact,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ {autoload_const_mark_and_move, autoload_const_free, autoload_const_memsize, autoload_const_mark_and_move,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static struct autoload_data *
@@ -2592,6 +2841,70 @@ get_autoload_data(VALUE autoload_const_value, struct autoload_const **autoload_c
return autoload_data;
}
+struct autoload_copy_table_data {
+ VALUE dst_tbl_value;
+ struct st_table *dst_tbl;
+ const rb_box_t *box;
+};
+
+static int
+autoload_copy_table_for_box_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct autoload_const *autoload_const;
+ struct autoload_copy_table_data *data = (struct autoload_copy_table_data *)arg;
+ struct st_table *tbl = data->dst_tbl;
+ VALUE tbl_value = data->dst_tbl_value;
+ const rb_box_t *box = data->box;
+
+ VALUE src_value = (VALUE)value;
+ struct autoload_const *src_const = rb_check_typeddata(src_value, &autoload_const_type);
+ // autoload_data can be shared between copies because the feature is equal between copies.
+ VALUE autoload_data_value = src_const->autoload_data_value;
+ struct autoload_data *autoload_data = rb_check_typeddata(autoload_data_value, &autoload_data_type);
+
+ VALUE new_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const);
+ RB_OBJ_WRITE(new_value, &autoload_const->box_value, rb_get_box_object((rb_box_t *)box));
+ RB_OBJ_WRITE(new_value, &autoload_const->module, src_const->module);
+ autoload_const->name = src_const->name;
+ RB_OBJ_WRITE(new_value, &autoload_const->value, src_const->value);
+ autoload_const->flag = src_const->flag;
+ RB_OBJ_WRITE(new_value, &autoload_const->autoload_data_value, autoload_data_value);
+ ccan_list_add_tail(&autoload_data->constants, &autoload_const->cnode);
+
+ st_insert(tbl, (st_data_t)autoload_const->name, (st_data_t)new_value);
+ RB_OBJ_WRITTEN(tbl_value, Qundef, new_value);
+
+ return ST_CONTINUE;
+}
+
+void
+rb_autoload_copy_table_for_box(st_table *iv_ptr, const rb_box_t *box)
+{
+ struct st_table *src_tbl, *dst_tbl;
+ VALUE src_tbl_value, dst_tbl_value;
+ if (!rb_st_lookup(iv_ptr, (st_data_t)autoload, (st_data_t *)&src_tbl_value)) {
+ // the class has no autoload table yet.
+ return;
+ }
+ if (!RTEST(src_tbl_value) || !(src_tbl = check_autoload_table(src_tbl_value))) {
+ // the __autoload__ ivar value isn't autoload table value.
+ return;
+ }
+ src_tbl = check_autoload_table(src_tbl_value);
+
+ dst_tbl_value = TypedData_Wrap_Struct(0, &autoload_table_type, NULL);
+ RTYPEDDATA_DATA(dst_tbl_value) = dst_tbl = st_init_numtable();
+
+ struct autoload_copy_table_data data = {
+ .dst_tbl_value = dst_tbl_value,
+ .dst_tbl = dst_tbl,
+ .box = box,
+ };
+
+ st_foreach(src_tbl, autoload_copy_table_for_box_i, (st_data_t)&data);
+ st_insert(iv_ptr, (st_data_t)autoload, (st_data_t)dst_tbl_value);
+}
+
void
rb_autoload(VALUE module, ID name, const char *feature)
{
@@ -2603,11 +2916,13 @@ rb_autoload(VALUE module, ID name, const char *feature)
}
static void const_set(VALUE klass, ID id, VALUE val);
+static void const_added(VALUE klass, ID const_name);
struct autoload_arguments {
VALUE module;
ID name;
VALUE feature;
+ VALUE box_value;
};
static VALUE
@@ -2677,11 +2992,12 @@ autoload_synchronized(VALUE _arguments)
{
struct autoload_const *autoload_const;
VALUE autoload_const_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const);
- autoload_const->module = arguments->module;
+ RB_OBJ_WRITE(autoload_const_value, &autoload_const->box_value, arguments->box_value);
+ RB_OBJ_WRITE(autoload_const_value, &autoload_const->module, arguments->module);
autoload_const->name = arguments->name;
autoload_const->value = Qundef;
autoload_const->flag = CONST_PUBLIC;
- autoload_const->autoload_data_value = autoload_data_value;
+ RB_OBJ_WRITE(autoload_const_value, &autoload_const->autoload_data_value, autoload_data_value);
ccan_list_add_tail(&autoload_data->constants, &autoload_const->cnode);
st_insert(autoload_table, (st_data_t)arguments->name, (st_data_t)autoload_const_value);
RB_OBJ_WRITTEN(autoload_table_value, Qundef, autoload_const_value);
@@ -2693,6 +3009,9 @@ autoload_synchronized(VALUE _arguments)
void
rb_autoload_str(VALUE module, ID name, VALUE feature)
{
+ const rb_box_t *box = rb_current_box();
+ VALUE current_box_value = rb_get_box_object((rb_box_t *)box);
+
if (!rb_is_const_id(name)) {
rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"", QUOTE_ID(name));
}
@@ -2706,12 +3025,13 @@ rb_autoload_str(VALUE module, ID name, VALUE feature)
.module = module,
.name = name,
.feature = feature,
+ .box_value = current_box_value,
};
VALUE result = rb_mutex_synchronize(autoload_mutex, autoload_synchronized, (VALUE)&arguments);
if (result == Qtrue) {
- rb_const_added(module, name);
+ const_added(module, name);
}
}
@@ -2890,11 +3210,9 @@ autoload_const_set(struct autoload_const *ac)
{
check_before_mod_set(ac->module, ac->name, ac->value, "constant");
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
const_tbl_update(ac, true);
}
- RB_VM_LOCK_LEAVE();
return 0; /* ignored */
}
@@ -2969,19 +3287,32 @@ autoload_apply_constants(VALUE _arguments)
static VALUE
autoload_feature_require(VALUE _arguments)
{
+ VALUE receiver = rb_vm_top_self();
+
struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
struct autoload_const *autoload_const = arguments->autoload_const;
+ VALUE autoload_box_value = autoload_const->box_value;
// We save this for later use in autoload_apply_constants:
arguments->autoload_data = rb_check_typeddata(autoload_const->autoload_data_value, &autoload_data_type);
- VALUE result = rb_funcall(rb_vm_top_self(), rb_intern("require"), 1, arguments->autoload_data->feature);
+ if (rb_box_available() && BOX_OBJ_P(autoload_box_value))
+ receiver = autoload_box_value;
+
+ /*
+ * Clear the global cc cache table because the require method can be different from the current
+ * box's one and it may cause inconsistent cc-cme states.
+ * For example, the assertion below may fail in gccct_method_search();
+ * VM_ASSERT(vm_cc_check_cme(cc, rb_callable_method_entry(klass, mid)))
+ */
+ rb_gccct_clear_table();
+
+ VALUE result = rb_funcall(receiver, rb_intern("require"), 1, arguments->autoload_data->feature);
if (RTEST(result)) {
return rb_mutex_synchronize(autoload_mutex, autoload_apply_constants, _arguments);
}
-
return result;
}
@@ -3102,11 +3433,12 @@ rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id)
static VALUE
rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
{
- VALUE c = rb_const_search(klass, id, exclude, recurse, visibility);
+ VALUE found_in;
+ VALUE c = rb_const_search(klass, id, exclude, recurse, visibility, &found_in);
if (!UNDEF_P(c)) {
if (UNLIKELY(!rb_ractor_main_p())) {
if (!rb_ractor_shareable_p(c)) {
- rb_raise(rb_eRactorIsolationError, "can not access non-shareable objects in constant %"PRIsVALUE"::%s by non-main Ractor.", rb_class_path(klass), rb_id2name(id));
+ rb_raise(rb_eRactorIsolationError, "can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main Ractor.", rb_class_path(found_in), rb_id2str(id));
}
}
return c;
@@ -3115,7 +3447,7 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
}
static VALUE
-rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibility)
+rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibility, VALUE *found_in)
{
VALUE value, current;
bool first_iteration = true;
@@ -3152,13 +3484,17 @@ rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibilit
if (am == tmp) break;
am = tmp;
ac = autoloading_const_entry(tmp, id);
- if (ac) return ac->value;
+ if (ac) {
+ if (found_in) { *found_in = tmp; }
+ return ac->value;
+ }
rb_autoload_load(tmp, id);
continue;
}
if (exclude && tmp == rb_cObject) {
goto not_found;
}
+ if (found_in) { *found_in = tmp; }
return value;
}
if (!recurse) break;
@@ -3170,17 +3506,17 @@ rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibilit
}
static VALUE
-rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility)
+rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility, VALUE *found_in)
{
VALUE value;
if (klass == rb_cObject) exclude = FALSE;
- value = rb_const_search_from(klass, id, exclude, recurse, visibility);
+ value = rb_const_search_from(klass, id, exclude, recurse, visibility, found_in);
if (!UNDEF_P(value)) return value;
if (exclude) return value;
if (BUILTIN_TYPE(klass) != T_MODULE) return value;
/* search global const too, if klass is a module */
- return rb_const_search_from(rb_cObject, id, FALSE, recurse, visibility);
+ return rb_const_search_from(rb_cObject, id, FALSE, recurse, visibility, found_in);
}
VALUE
@@ -3305,6 +3641,8 @@ rb_mod_remove_const(VALUE mod, VALUE name)
return rb_const_remove(mod, id);
}
+static rb_const_entry_t * const_lookup(struct rb_id_table *tbl, ID id);
+
VALUE
rb_const_remove(VALUE mod, ID id)
{
@@ -3314,7 +3652,8 @@ rb_const_remove(VALUE mod, ID id)
rb_check_frozen(mod);
ce = rb_const_lookup(mod, id);
- if (!ce || !rb_id_table_delete(RCLASS_CONST_TBL(mod), id)) {
+
+ if (!ce) {
if (rb_const_defined_at(mod, id)) {
rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
}
@@ -3322,6 +3661,14 @@ rb_const_remove(VALUE mod, ID id)
undefined_constant(mod, ID2SYM(id));
}
+ VALUE writable_ce = 0;
+ if (rb_id_table_lookup(RCLASS_WRITABLE_CONST_TBL(mod), id, &writable_ce)) {
+ rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id);
+ if ((rb_const_entry_t *)writable_ce != ce) {
+ SIZED_FREE((rb_const_entry_t *)writable_ce);
+ }
+ }
+
rb_const_warn_if_deprecated(ce, mod, id);
rb_clear_constant_cache_for_id(id);
@@ -3332,7 +3679,10 @@ rb_const_remove(VALUE mod, ID id)
val = Qnil;
}
- ruby_xfree(ce);
+ if (ce != const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
+ SIZED_FREE(ce);
+ }
+ // else - skip free'ing the ce because it still exists in the prime classext
return val;
}
@@ -3374,12 +3724,10 @@ rb_local_constants(VALUE mod)
if (!tbl) return rb_ary_new2(0);
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
ary = rb_ary_new2(rb_id_table_size(tbl));
rb_id_table_foreach(tbl, rb_local_constants_i, (void *)ary);
}
- RB_VM_LOCK_LEAVE();
return ary;
}
@@ -3392,11 +3740,9 @@ rb_mod_const_at(VALUE mod, void *data)
tbl = st_init_numtable();
}
if (RCLASS_CONST_TBL(mod)) {
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
rb_id_table_foreach(RCLASS_CONST_TBL(mod), sv_i, tbl);
}
- RB_VM_LOCK_LEAVE();
}
return tbl;
}
@@ -3554,8 +3900,8 @@ set_namespace_path_i(ID id, VALUE v, void *payload)
}
set_namespace_path(value, build_const_path(parental_path, id));
- if (!RCLASS_EXT(value)->permanent_classpath) {
- RCLASS_SET_CLASSPATH(value, 0, false);
+ if (!RCLASS_PERMANENT_CLASSPATH_P(value)) {
+ RCLASS_WRITE_CLASSPATH(value, 0, false);
}
return ID_TABLE_CONTINUE;
@@ -3570,20 +3916,19 @@ static void
set_namespace_path(VALUE named_namespace, VALUE namespace_path)
{
struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace);
+ RB_OBJ_SET_SHAREABLE(namespace_path);
- RB_VM_LOCK_ENTER();
- {
- RCLASS_SET_CLASSPATH(named_namespace, namespace_path, true);
+ RB_VM_LOCKING() {
+ RCLASS_WRITE_CLASSPATH(named_namespace, namespace_path, true);
if (const_table) {
rb_id_table_foreach(const_table, set_namespace_path_i, &namespace_path);
}
}
- RB_VM_LOCK_LEAVE();
}
-void
-rb_const_added(VALUE klass, ID const_name)
+static void
+const_added(VALUE klass, ID const_name)
{
if (GET_VM()->running) {
VALUE name = ID2SYM(const_name);
@@ -3607,11 +3952,11 @@ const_set(VALUE klass, ID id, VALUE val)
check_before_mod_set(klass, id, val, "constant");
- RB_VM_LOCK_ENTER();
- {
- struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
+ RB_VM_LOCKING() {
+ struct rb_id_table *tbl = RCLASS_WRITABLE_CONST_TBL(klass);
if (!tbl) {
- RCLASS_CONST_TBL(klass) = tbl = rb_id_table_create(0);
+ tbl = rb_id_table_create(0);
+ RCLASS_WRITE_CONST_TBL(klass, tbl, false);
rb_clear_constant_cache_for_id(id);
ce = ZALLOC(rb_const_entry_t);
rb_id_table_insert(tbl, id, (VALUE)ce);
@@ -3627,7 +3972,6 @@ const_set(VALUE klass, ID id, VALUE val)
const_tbl_update(&ac, false);
}
}
- RB_VM_LOCK_LEAVE();
/*
* Resolve and cache class name immediately to resolve ambiguity
@@ -3651,7 +3995,8 @@ const_set(VALUE klass, ID id, VALUE val)
set_namespace_path(val, build_const_path(parental_path, id));
}
else if (!parental_path_permanent && NIL_P(val_path)) {
- RCLASS_SET_CLASSPATH(val, build_const_path(parental_path, id), false);
+ VALUE path = build_const_path(parental_path, id);
+ RCLASS_SET_CLASSPATH(val, path, false);
}
}
}
@@ -3659,33 +4004,27 @@ const_set(VALUE klass, ID id, VALUE val)
}
void
-rb_const_set_raw(VALUE klass, ID id, VALUE val)
-{
- const_set(klass, id, val);
-}
-
-void
rb_const_set(VALUE klass, ID id, VALUE val)
{
const_set(klass, id, val);
- rb_const_added(klass, id);
+ const_added(klass, id);
}
-static struct autoload_data *
-autoload_data_for_named_constant(VALUE module, ID name, struct autoload_const **autoload_const_pointer)
+static VALUE
+autoload_const_value_for_named_constant(VALUE module, ID name, struct autoload_const **autoload_const_pointer)
{
- VALUE autoload_data_value = autoload_data(module, name);
- if (!autoload_data_value) return 0;
+ VALUE autoload_const_value = autoload_data(module, name);
+ if (!autoload_const_value) return Qfalse;
- struct autoload_data *autoload_data = get_autoload_data(autoload_data_value, autoload_const_pointer);
- if (!autoload_data) return 0;
+ struct autoload_data *autoload_data = get_autoload_data(autoload_const_value, autoload_const_pointer);
+ if (!autoload_data) return Qfalse;
/* for autoloading thread, keep the defined value to autoloading storage */
if (autoload_by_current(autoload_data)) {
- return autoload_data;
+ return autoload_const_value;
}
- return 0;
+ return Qfalse;
}
static void
@@ -3705,13 +4044,13 @@ const_tbl_update(struct autoload_const *ac, int autoload_force)
RUBY_ASSERT_CRITICAL_SECTION_ENTER();
VALUE file = ac->file;
int line = ac->line;
- struct autoload_data *ele = autoload_data_for_named_constant(klass, id, &ac);
+ VALUE autoload_const_value = autoload_const_value_for_named_constant(klass, id, &ac);
- if (!autoload_force && ele) {
+ if (!autoload_force && autoload_const_value) {
rb_clear_constant_cache_for_id(id);
- ac->value = val; /* autoload_data is non-WB-protected */
- ac->file = rb_source_location(&ac->line);
+ RB_OBJ_WRITE(autoload_const_value, &ac->value, val);
+ RB_OBJ_WRITE(autoload_const_value, &ac->file, rb_source_location(&ac->line));
}
else {
/* otherwise autoloaded constant, allow to override */
@@ -3727,20 +4066,23 @@ const_tbl_update(struct autoload_const *ac, int autoload_force)
else {
VALUE name = QUOTE_ID(id);
visibility = ce->flag;
- if (klass == rb_cObject)
- rb_warn("already initialized constant %"PRIsVALUE"", name);
- else
- rb_warn("already initialized constant %"PRIsVALUE"::%"PRIsVALUE"",
- rb_class_name(klass), name);
+
+ VALUE previous = Qnil;
if (!NIL_P(ce->file) && ce->line) {
- rb_compile_warn(RSTRING_PTR(ce->file), ce->line,
- "previous definition of %"PRIsVALUE" was here", name);
+ previous = rb_sprintf("\n%"PRIsVALUE":%d: warning: previous definition of %"PRIsVALUE" was here", ce->file, ce->line, name);
}
+
+ if (klass == rb_cObject)
+ rb_warn("already initialized constant %"PRIsVALUE"%"PRIsVALUE"", name, previous);
+ else
+ rb_warn("already initialized constant %"PRIsVALUE"::%"PRIsVALUE"%"PRIsVALUE"",
+ rb_class_name(klass), name, previous);
}
rb_clear_constant_cache_for_id(id);
setup_const_entry(ce, klass, val, visibility);
}
else {
+ tbl = RCLASS_WRITABLE_CONST_TBL(klass);
rb_clear_constant_cache_for_id(id);
ce = ZALLOC(rb_const_entry_t);
@@ -3804,15 +4146,12 @@ set_const_visibility(VALUE mod, int argc, const VALUE *argv,
ce->flag &= ~mask;
ce->flag |= flag;
if (UNDEF_P(ce->value)) {
- struct autoload_data *ele;
-
- ele = autoload_data_for_named_constant(mod, id, &ac);
- if (ele) {
+ if (autoload_const_value_for_named_constant(mod, id, &ac)) {
ac->flag &= ~mask;
ac->flag |= flag;
}
}
- rb_clear_constant_cache_for_id(id);
+ rb_clear_constant_cache_for_id(id);
}
else {
undefined_constant(mod, ID2SYM(id));
@@ -3903,7 +4242,7 @@ static int
cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
{
if (RB_TYPE_P(klass, T_ICLASS)) {
- if (FL_TEST_RAW(klass, RICLASS_IS_ORIGIN)) {
+ if (RICLASS_IS_ORIGIN_P(klass)) {
return 0;
}
else {
@@ -3955,7 +4294,6 @@ cvar_overtaken(VALUE front, VALUE target, ID id)
}
#define CVAR_LOOKUP(v,r) do {\
- CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(); \
if (cvar_lookup_at(klass, id, (v))) {r;}\
CVAR_FOREACH_ANCESTORS(klass, v, r);\
} while(0)
@@ -3974,22 +4312,11 @@ find_cvar(VALUE klass, VALUE * front, VALUE * target, ID id)
return v;
}
-static void
-check_for_cvar_table(VALUE subclass, VALUE key)
-{
- // Must not check ivar on ICLASS
- if (!RB_TYPE_P(subclass, T_ICLASS) && RTEST(rb_ivar_defined(subclass, key))) {
- RB_DEBUG_COUNTER_INC(cvar_class_invalidate);
- ruby_vm_global_cvar_state++;
- return;
- }
-
- rb_class_foreach_subclass(subclass, check_for_cvar_table, key);
-}
-
void
rb_cvar_set(VALUE klass, ID id, VALUE val)
{
+ CVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(klass, id);
+
VALUE tmp, front = 0, target = 0;
tmp = klass;
@@ -4006,23 +4333,31 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
}
check_before_mod_set(target, id, val, "class variable");
- int result = rb_class_ivar_set(target, id, val);
-
- struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(target);
+ bool new_cvar = rb_class_ivar_set(target, id, val);
- if (!rb_cvc_tbl) {
- rb_cvc_tbl = RCLASS_CVC_TBL(target) = rb_id_table_create(2);
- }
+ VALUE cvc_tbl = RCLASS_WRITABLE_CVC_TBL(target);
struct rb_cvar_class_tbl_entry *ent;
VALUE ent_data;
- if (!rb_id_table_lookup(rb_cvc_tbl, id, &ent_data)) {
- ent = ALLOC(struct rb_cvar_class_tbl_entry);
- ent->class_value = target;
+ if (!cvc_tbl || !rb_marked_id_table_lookup(cvc_tbl, id, &ent_data)) {
+ ent = (struct rb_cvar_class_tbl_entry *)SHAREABLE_IMEMO_NEW(struct rb_cvar_class_tbl_entry, imemo_cvar_entry, 0);
+ RB_OBJ_WRITE((VALUE)ent, &ent->class_value, target);
+ RB_OBJ_WRITE((VALUE)ent, &ent->cref, 0);
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
- ent->cref = 0;
- rb_id_table_insert(rb_cvc_tbl, id, (VALUE)ent);
+
+ VALUE new_cvc_tbl = cvc_tbl;
+ if (!new_cvc_tbl) {
+ new_cvc_tbl = rb_marked_id_table_new(2);
+ }
+ else if (rb_multi_ractor_p()) {
+ new_cvc_tbl = rb_marked_id_table_dup(cvc_tbl);
+ }
+
+ rb_marked_id_table_insert(new_cvc_tbl, id, (VALUE)ent);
+ if (new_cvc_tbl != cvc_tbl) {
+ RCLASS_WRITE_CVC_TBL(target, new_cvc_tbl);
+ }
RB_DEBUG_COUNTER_INC(cvar_inline_miss);
}
else {
@@ -4030,15 +4365,11 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
}
- // Break the cvar cache if this is a new class variable
- // and target is a module or a subclass with the same
- // cvar in this lookup.
- if (result == 0) {
- if (RB_TYPE_P(target, T_CLASS)) {
- if (RCLASS_SUBCLASSES(target)) {
- rb_class_foreach_subclass(target, check_for_cvar_table, id);
- }
- }
+ // Break the cvar cache if this is a new class variable.
+ // Existing caches may have resolved this name to a different
+ // location in the hierarchy, so we must invalidate globally.
+ if (new_cvar) {
+ ruby_vm_global_cvar_state++;
}
}
@@ -4054,6 +4385,7 @@ rb_cvar_find(VALUE klass, ID id, VALUE *front)
klass, ID2SYM(id));
}
cvar_overtaken(*front, target, id);
+ cvar_read_ractor_check(klass, id, value);
return (VALUE)value;
}
@@ -4264,96 +4596,144 @@ rb_iv_set(VALUE obj, const char *name, VALUE val)
return rb_ivar_set(obj, id, val);
}
-static VALUE *
-class_ivar_set_shape_ivptr(VALUE obj, void *_data)
+static attr_index_t
+class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool concurrent, VALUE *new_fields_obj, bool *new_ivar_out)
{
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ const VALUE original_fields_obj = fields_obj;
+ fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(klass, ROOT_SHAPE_ID, true);
- return RCLASS_IVPTR(obj);
-}
+ shape_id_t current_shape_id = RBASIC_SHAPE_ID(fields_obj);
+ shape_id_t next_shape_id = current_shape_id; // for complex
+ if (UNLIKELY(rb_shape_complex_p(current_shape_id))) {
+ goto complex;
+ }
-static void
-class_ivar_set_shape_resize_ivptr(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *_data)
-{
- REALLOC_N(RCLASS_IVPTR(obj), VALUE, new_capa);
-}
+ bool new_ivar;
+ next_shape_id = generic_shape_ivar(fields_obj, id, &new_ivar);
-static void
-class_ivar_set_set_shape(VALUE obj, rb_shape_t *shape, void *_data)
-{
- rb_shape_set_shape(obj, shape);
-}
+ if (UNLIKELY(rb_shape_complex_p(next_shape_id))) {
+ fields_obj = imemo_fields_complex_from_obj(klass, fields_obj, next_shape_id);
+ goto complex;
+ }
-static void
-class_ivar_set_transition_too_complex(VALUE obj, void *_data)
-{
- rb_evict_ivars_to_hash(obj);
-}
+ attr_index_t index = RSHAPE_INDEX(next_shape_id);
+ if (new_ivar && index >= RSHAPE_CAPACITY(current_shape_id)) {
+ // We allocate a new fields_obj even when concurrency isn't a concern
+ // so that we're embedded as long as possible.
+ fields_obj = imemo_fields_copy_append(klass, fields_obj, current_shape_id, next_shape_id, val);
+ }
+ else {
+ VALUE *fields = rb_imemo_fields_ptr(fields_obj);
+
+ if (concurrent && original_fields_obj == fields_obj) {
+ // In the concurrent case, if we're mutating the existing
+ // fields_obj, we must use an atomic write, because if we're
+ // adding a new field, the shape_id must be written after the field
+ // and if we're updating an existing field, we at least need a relaxed
+ // write to avoid reaping.
+ RB_OBJ_ATOMIC_WRITE(fields_obj, &fields[index], val);
+ }
+ else {
+ RB_OBJ_WRITE(fields_obj, &fields[index], val);
+ }
-static st_table *
-class_ivar_set_too_complex_table(VALUE obj, void *_data)
-{
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ if (new_ivar) {
+ RUBY_ASSERT(rb_shape_layout(next_shape_id) == SHAPE_ID_LAYOUT_ROBJECT);
+ RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id);
+ }
+ }
+
+ *new_fields_obj = fields_obj;
+ *new_ivar_out = new_ivar;
+ return index;
+
+complex:
+ {
+ if (concurrent && fields_obj == original_fields_obj) {
+ // In multi-ractor case, we must always work on a copy because
+ // even if the field already exist, inserting in a st_table may
+ // cause a rebuild.
+ fields_obj = rb_imemo_fields_clone(fields_obj);
+ }
- return RCLASS_IV_HASH(obj);
+ st_table *table = rb_imemo_fields_complex_tbl(fields_obj);
+ new_ivar = !st_insert(table, (st_data_t)id, (st_data_t)val);
+ RB_OBJ_WRITTEN(fields_obj, Qundef, val);
+
+ if (fields_obj != original_fields_obj) {
+ RUBY_ASSERT(rb_shape_layout(next_shape_id) == SHAPE_ID_LAYOUT_ROBJECT);
+ RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id);
+ }
+ }
+
+ *new_fields_obj = fields_obj;
+ *new_ivar_out = new_ivar;
+ return ATTR_INDEX_NOT_SET;
}
-int
-rb_class_ivar_set(VALUE obj, ID id, VALUE val)
+static attr_index_t
+class_ivar_set(VALUE obj, ID id, VALUE val, bool *new_ivar)
{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- bool existing = false;
- rb_check_frozen(obj);
+ rb_class_ensure_writable(obj);
- RB_VM_LOCK_ENTER();
- {
- existing = general_ivar_set(obj, id, val, NULL,
- class_ivar_set_shape_ivptr,
- class_ivar_set_shape_resize_ivptr,
- class_ivar_set_set_shape,
- class_ivar_set_transition_too_complex,
- class_ivar_set_too_complex_table).existing;
+ const VALUE original_fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ VALUE new_fields_obj = 0;
+
+ attr_index_t index = class_fields_ivar_set(obj, original_fields_obj, id, val, rb_multi_ractor_p(), &new_fields_obj, new_ivar);
+
+ if (new_fields_obj != original_fields_obj) {
+ RCLASS_WRITABLE_SET_FIELDS_OBJ(obj, new_fields_obj);
}
- RB_VM_LOCK_LEAVE();
- return existing;
+ // TODO: What should we set as the T_CLASS shape_id?
+ // In most case we can replicate the single `fields_obj` shape
+ // but in namespaced case? Perhaps INVALID_SHAPE_ID?
+ RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | RBASIC_SHAPE_ID(new_fields_obj));
+ return index;
}
-static int
-tbl_copy_i(ID key, VALUE val, st_data_t dest)
+bool
+rb_class_ivar_set(VALUE obj, ID id, VALUE val)
{
- rb_class_ivar_set((VALUE)dest, key, val);
+ RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
+ rb_check_frozen(obj);
- return ST_CONTINUE;
+ bool new_ivar;
+ class_ivar_set(obj, id, val, &new_ivar);
+ return new_ivar;
}
void
-rb_iv_tbl_copy(VALUE dst, VALUE src)
+rb_fields_tbl_copy(VALUE dst, VALUE src)
{
RUBY_ASSERT(rb_type(dst) == rb_type(src));
RUBY_ASSERT(RB_TYPE_P(dst, T_CLASS) || RB_TYPE_P(dst, T_MODULE));
+ RUBY_ASSERT(RSHAPE_TYPE_P(RBASIC_SHAPE_ID(dst), SHAPE_ROOT));
- RUBY_ASSERT(rb_shape_get_shape(dst)->type == SHAPE_ROOT);
- RUBY_ASSERT(!RCLASS_IVPTR(dst));
-
- rb_ivar_foreach(src, tbl_copy_i, dst);
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(src);
+ if (fields_obj) {
+ RCLASS_WRITABLE_SET_FIELDS_OBJ(dst, rb_imemo_fields_clone(fields_obj));
+ RBASIC_SET_SHAPE_ID(dst, rb_shape_layout(RBASIC_SHAPE_ID(dst)) | RBASIC_SHAPE_ID(src));
+ }
}
-rb_const_entry_t *
-rb_const_lookup(VALUE klass, ID id)
+static rb_const_entry_t *
+const_lookup(struct rb_id_table *tbl, ID id)
{
- struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
-
if (tbl) {
VALUE val;
bool r;
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
r = rb_id_table_lookup(tbl, id, &val);
}
- RB_VM_LOCK_LEAVE();
if (r) return (rb_const_entry_t *)val;
}
return NULL;
}
+
+rb_const_entry_t *
+rb_const_lookup(VALUE klass, ID id)
+{
+ return const_lookup(RCLASS_CONST_TBL(klass), id);
+}
diff --git a/variable.h b/variable.h
index 1abc89ed99..f2afead9d3 100644
--- a/variable.h
+++ b/variable.h
@@ -12,28 +12,16 @@
#include "shape.h"
-struct gen_ivtbl {
-#if !SHAPE_IN_BASIC_FLAGS
- uint16_t shape_id;
-#endif
- union {
- struct {
- uint32_t numiv;
- VALUE ivptr[1];
- } shape;
- struct {
- st_table *table;
- } complex;
- } as;
-};
+void rb_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table);
+VALUE rb_obj_fields(VALUE obj, ID field_name);
-int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **);
-
-#if !SHAPE_IN_BASIC_FLAGS
-shape_id_t rb_generic_shape_id(VALUE obj);
-#endif
+static inline VALUE
+rb_obj_fields_no_ractor_check(VALUE obj)
+{
+ return rb_obj_fields(obj, 0);
+}
void rb_free_rb_global_tbl(void);
-void rb_free_generic_iv_tbl_(void);
+void rb_free_generic_fields_tbl_(void);
#endif /* RUBY_TOPLEVEL_VARIABLE_H */
diff --git a/vcpkg.json b/vcpkg.json
index 16415dece1..64d73c4048 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -7,5 +7,5 @@
"openssl",
"zlib"
],
- "builtin-baseline": "65be7019941e1401e02daaba0738cab2c8a4a355"
-}
+ "builtin-baseline": "56bb2411609227288b70117ead2c47585ba07713"
+} \ No newline at end of file
diff --git a/version.c b/version.c
index 1063e456e2..5547832652 100644
--- a/version.c
+++ b/version.c
@@ -12,6 +12,7 @@
#include "internal/cmdlineopt.h"
#include "internal/parse.h"
#include "internal/gc.h"
+#include "ruby/internal/globals.h"
#include "ruby/ruby.h"
#include "version.h"
#include "vm_core.h"
@@ -24,8 +25,9 @@
#ifdef RUBY_REVISION
# if RUBY_PATCHLEVEL == -1
+# define RUBY_API_VERSION_NAME "master"
# ifndef RUBY_BRANCH_NAME
-# define RUBY_BRANCH_NAME "master"
+# define RUBY_BRANCH_NAME RUBY_API_VERSION_NAME
# endif
# define RUBY_REVISION_STR " "RUBY_BRANCH_NAME" "RUBY_REVISION
# else
@@ -35,6 +37,9 @@
# define RUBY_REVISION "HEAD"
# define RUBY_REVISION_STR ""
#endif
+#ifndef RUBY_API_VERSION_NAME
+# define RUBY_API_VERSION_NAME RUBY_API_VERSION_STR
+#endif
#if !defined RUBY_RELEASE_DATETIME || RUBY_PATCHLEVEL != -1
# undef RUBY_RELEASE_DATETIME
# define RUBY_RELEASE_DATETIME RUBY_RELEASE_DATE
@@ -44,6 +49,9 @@
#define MKSTR(type) rb_obj_freeze(rb_usascii_str_new_static(ruby_##type, sizeof(ruby_##type)-1))
#define MKINT(name) INT2FIX(ruby_##name)
+#define RUBY_API_VERSION_STR \
+ STRINGIZE(RUBY_API_VERSION_MAJOR) "." \
+ STRINGIZE(RUBY_API_VERSION_MINOR)
const int ruby_api_version[] = {
RUBY_API_VERSION_MAJOR,
RUBY_API_VERSION_MINOR,
@@ -61,6 +69,11 @@ const int ruby_api_version[] = {
#else
#define YJIT_DESCRIPTION " +YJIT"
#endif
+#ifdef ZJIT_SUPPORT
+#define ZJIT_DESCRIPTION " +ZJIT " STRINGIZE(ZJIT_SUPPORT)
+#else
+#define ZJIT_DESCRIPTION " +ZJIT"
+#endif
#if USE_MODULAR_GC
#define GC_DESCRIPTION " +GC"
#else
@@ -71,6 +84,7 @@ const char ruby_revision[] = RUBY_FULL_REVISION;
const char ruby_release_date[] = RUBY_RELEASE_DATE;
const char ruby_platform[] = RUBY_PLATFORM;
const int ruby_patchlevel = RUBY_PATCHLEVEL;
+const char ruby_api_version_name[] = RUBY_API_VERSION_NAME;
const char ruby_description[] =
"ruby " RUBY_VERSION RUBY_PATCHLEVEL_STR " "
"(" RUBY_RELEASE_DATETIME RUBY_REVISION_STR ") "
@@ -100,6 +114,12 @@ define_ruby_const(VALUE mod, const char *name, VALUE value, bool toplevel)
#define rb_define_const(mod, name, value) \
define_ruby_const(mod, (mod == mRuby ? "RUBY_" name : name), value, (mod == mRuby))
+void
+Init_Ruby_module(void)
+{
+ rb_define_module("Ruby");
+}
+
/*! Defines platform-depended Ruby-level constants */
void
Init_version(void)
@@ -162,6 +182,12 @@ Init_version(void)
#define YJIT_OPTS_ON 0
#endif
+#if USE_ZJIT
+#define ZJIT_OPTS_ON opt->zjit
+#else
+#define ZJIT_OPTS_ON 0
+#endif
+
int ruby_mn_threads_enabled;
#ifndef RB_DEFAULT_PARSER
@@ -184,9 +210,11 @@ rb_ruby_default_parser_set(ruby_default_parser_enum parser)
static void
define_ruby_description(const char *const jit_opt)
{
+#define JIT_DESCRIPTION YJIT_DESCRIPTION ZJIT_DESCRIPTION
+
static char desc[
sizeof(ruby_description)
- + rb_strlen_lit(YJIT_DESCRIPTION)
+ + rb_strlen_lit(JIT_DESCRIPTION)
+ rb_strlen_lit(" +MN")
+ rb_strlen_lit(" +PRISM")
#if USE_MODULAR_GC
@@ -203,7 +231,7 @@ define_ruby_description(const char *const jit_opt)
memcpy(desc, ruby_description, n);
# define append(s) (n += (int)strlcpy(desc + n, s, sizeof(desc) - n))
if (*jit_opt) append(jit_opt);
- RUBY_ASSERT(n <= ruby_description_opt_point + (int)rb_strlen_lit(YJIT_DESCRIPTION));
+ RUBY_ASSERT(n <= ruby_description_opt_point + (int)rb_strlen_lit(JIT_DESCRIPTION));
if (ruby_mn_threads_enabled) append(" +MN");
if (rb_ruby_prism_p()) append(" +PRISM");
#if USE_MODULAR_GC
@@ -225,6 +253,7 @@ define_ruby_description(const char *const jit_opt)
* The full ruby version string, like <tt>ruby -v</tt> prints
*/
rb_define_const(mRuby, "DESCRIPTION", /* MKSTR(description) */ description);
+#undef JIT_DESCRIPTION
}
void
@@ -232,6 +261,7 @@ Init_ruby_description(ruby_cmdline_options_t *opt)
{
const char *const jit_opt =
YJIT_OPTS_ON ? YJIT_DESCRIPTION :
+ ZJIT_OPTS_ON ? ZJIT_DESCRIPTION :
"";
define_ruby_description(jit_opt);
}
@@ -246,6 +276,15 @@ ruby_set_yjit_description(void)
}
void
+ruby_set_zjit_description(void)
+{
+ VALUE mRuby = rb_path2class("Ruby");
+ rb_const_remove(rb_cObject, rb_intern("RUBY_DESCRIPTION"));
+ rb_const_remove(mRuby, rb_intern("DESCRIPTION"));
+ define_ruby_description(ZJIT_DESCRIPTION);
+}
+
+void
ruby_show_version(void)
{
puts(rb_dynamic_description);
diff --git a/vm.c b/vm.c
index d31759724e..1d2a3eb66a 100644
--- a/vm.c
+++ b/vm.c
@@ -12,6 +12,7 @@
#include "eval_intern.h"
#include "internal.h"
+#include "internal/box.h"
#include "internal/class.h"
#include "internal/compile.h"
#include "internal/cont.h"
@@ -25,6 +26,7 @@
#include "internal/proc.h"
#include "internal/re.h"
#include "internal/ruby_parser.h"
+#include "internal/st.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/transcode.h"
@@ -34,6 +36,8 @@
#include "iseq.h"
#include "symbol.h" // This includes a macro for a more performant rb_id2sym.
#include "yjit.h"
+#include "insns.inc"
+#include "zjit.h"
#include "ruby/st.h"
#include "ruby/vm.h"
#include "vm_core.h"
@@ -56,6 +60,8 @@ int ruby_assert_critical_section_entered = 0;
static void *native_main_thread_stack_top;
+bool ruby_vm_during_cleanup = false;
+
VALUE rb_str_concat_literals(size_t, const VALUE*);
VALUE vm_exec(rb_execution_context_t *);
@@ -92,6 +98,81 @@ rb_vm_search_cf_from_ep(const rb_execution_context_t *ec, const rb_control_frame
}
}
+#if VM_CHECK_MODE > 0
+// ruby_box_crashed defined in internal/box.h
+#define VM_BOX_CRASHED() {ruby_box_crashed = true;}
+#define VM_BOX_ASSERT(expr, msg) \
+ if (!(expr)) { ruby_box_crashed = true; rb_bug(msg); }
+#else
+#define VM_BOX_CRASHED() {}
+#define VM_BOX_ASSERT(expr, msg) ((void)0)
+#endif
+
+static const VALUE *
+VM_EP_RUBY_LEP(const rb_execution_context_t *ec, const rb_control_frame_t *current_cfp)
+{
+ // rb_vmdebug_box_env_dump_raw() simulates this function
+ const VALUE *ep = current_cfp->ep;
+ const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(ec); /* end of control frame pointer */
+ const rb_control_frame_t *cfp = current_cfp;
+
+ if (VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_IFUNC)) {
+ ep = VM_EP_LEP(current_cfp->ep);
+ /**
+ * Returns CFUNC frame only in this case.
+ *
+ * Usually CFUNC frame doesn't represent the current box and it should operate
+ * the caller box. See the example:
+ *
+ * # in the main box
+ * module Kernel
+ * def foo = "foo"
+ * module_function :foo
+ * end
+ *
+ * In the case above, `module_function` is defined in the root box.
+ * If `module_function` worked in the root box, `Kernel#foo` is invisible
+ * from it and it causes NameError: undefined method `foo` for module `Kernel`.
+ *
+ * But in cases of IFUNC (blocks written in C), IFUNC doesn't have its own box
+ * and its local env frame will be CFUNC frame.
+ * For example, `Enumerator#chunk` calls IFUNC blocks, written as `chunk_i` function.
+ *
+ * [1].chunk{ it.even? }.each{ ... }
+ *
+ * Before calling the Ruby block `{ it.even? }`, `#chunk` calls `chunk_i` as IFUNC
+ * to iterate the array's members (it's just like `#each`).
+ * We expect that `chunk_i` works as expected by the implementation of `#chunk`
+ * without any overwritten definitions from boxes.
+ * So the definitions on IFUNC frames should be equal to the caller CFUNC.
+ */
+ VM_ASSERT(VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CFUNC));
+ return ep;
+ }
+
+ while (VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CFUNC)) {
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+
+ VM_BOX_ASSERT(cfp, "CFUNC should have a valid previous control frame");
+ VM_BOX_ASSERT(cfp < eocfp, "CFUNC should have a valid caller frame");
+ if (!cfp || cfp >= eocfp) {
+ return NULL;
+ }
+
+ VM_BOX_ASSERT(cfp->ep, "CFUNC should have a valid caller frame with env");
+ ep = cfp->ep;
+ if (!ep) {
+ return NULL;
+ }
+ }
+
+ while (!VM_ENV_LOCAL_P(ep)) {
+ ep = VM_ENV_PREV_EP(ep);
+ }
+
+ return ep;
+}
+
const VALUE *
rb_vm_ep_local_ep(const VALUE *ep)
{
@@ -115,7 +196,15 @@ PUREFUNC(static inline VALUE VM_CF_BLOCK_HANDLER(const rb_control_frame_t * cons
static inline VALUE
VM_CF_BLOCK_HANDLER(const rb_control_frame_t * const cfp)
{
- const VALUE *ep = VM_CF_LEP(cfp);
+ const VALUE *ep;
+ if (VM_ENV_BOXED_P(cfp->ep)) {
+ VM_ASSERT(VM_ENV_LOCAL_P(cfp->ep));
+ /* Never set black_handler for VM_FRAME_MAGIC_TOP or VM_FRAME_MAGIC_CLASS
+ * and the specval is used for boxes (rb_box_t) in these case
+ */
+ return VM_BLOCK_HANDLER_NONE;
+ }
+ ep = VM_CF_LEP(cfp);
return VM_ENV_BLOCK_HANDLER(ep);
}
@@ -230,13 +319,9 @@ vm_cref_new0(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_
int omod_shared = FALSE;
/* scope */
- union {
- rb_scope_visibility_t visi;
- VALUE value;
- } scope_visi;
-
- scope_visi.visi.method_visi = visi;
- scope_visi.visi.module_func = module_func;
+ rb_scope_visibility_t scope_visi;
+ scope_visi.method_visi = visi;
+ scope_visi.module_func = module_func;
/* refinements */
if (prev_cref != NULL && prev_cref != (void *)1 /* TODO: why CREF_NEXT(cref) is 1? */) {
@@ -250,10 +335,10 @@ vm_cref_new0(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_
VM_ASSERT(singleton || klass);
- rb_cref_t *cref = IMEMO_NEW(rb_cref_t, imemo_cref, refinements);
+ rb_cref_t *cref = SHAREABLE_IMEMO_NEW(rb_cref_t, imemo_cref, refinements);
cref->klass_or_self = klass;
cref->next = use_prev_prev ? CREF_NEXT(prev_cref) : prev_cref;
- *((rb_scope_visibility_t *)&cref->scope_visi) = scope_visi.visi;
+ *((rb_scope_visibility_t *)&cref->scope_visi) = scope_visi;
if (pushed_by_eval) CREF_PUSHED_BY_EVAL_SET(cref);
if (omod_shared) CREF_OMOD_SHARED_SET(cref);
@@ -268,12 +353,6 @@ vm_cref_new(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_t
return vm_cref_new0(klass, visi, module_func, prev_cref, pushed_by_eval, FALSE, singleton);
}
-static rb_cref_t *
-vm_cref_new_use_prev(VALUE klass, rb_method_visibility_t visi, int module_func, rb_cref_t *prev_cref, int pushed_by_eval)
-{
- return vm_cref_new0(klass, visi, module_func, prev_cref, pushed_by_eval, TRUE, FALSE);
-}
-
static int
ref_delete_symkey(VALUE key, VALUE value, VALUE unused)
{
@@ -429,13 +508,13 @@ rb_yjit_threshold_hit(const rb_iseq_t *iseq, uint64_t entry_calls)
// The current frame doesn't have VM_FRAME_FLAG_FINISH. The current
// vm_exec does NOT stop whether JIT code returns Qundef or not.
static inline rb_jit_func_t
-jit_compile(rb_execution_context_t *ec)
+yjit_compile(rb_execution_context_t *ec)
{
- const rb_iseq_t *iseq = ec->cfp->iseq;
+ const rb_iseq_t *iseq = CFP_ISEQ(ec->cfp);
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
- if (body->jit_entry == NULL && rb_yjit_enabled_p) {
+ if (body->jit_entry == NULL) {
body->jit_entry_calls++;
if (rb_yjit_threshold_hit(iseq, body->jit_entry_calls)) {
rb_yjit_compile_iseq(iseq, ec, false);
@@ -443,26 +522,65 @@ jit_compile(rb_execution_context_t *ec)
}
return body->jit_entry;
}
+#else
+# define yjit_compile(ec) ((rb_jit_func_t)0)
+#endif
-// Execute JIT code compiled by jit_compile()
-static inline VALUE
-jit_exec(rb_execution_context_t *ec)
+#if USE_ZJIT
+static inline rb_jit_func_t
+zjit_compile(rb_execution_context_t *ec)
{
- rb_jit_func_t func = jit_compile(ec);
- if (func) {
- // Call the JIT code
- return func(ec, ec->cfp);
- }
- else {
- return Qundef;
+ const rb_iseq_t *iseq = CFP_ISEQ(ec->cfp);
+ struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+
+ if (body->jit_entry == NULL) {
+ body->jit_entry_calls++;
+
+ // At profile-threshold, rewrite some of the YARV instructions
+ // to zjit_* instructions to profile these instructions.
+ if (body->jit_entry_calls == rb_zjit_profile_threshold) {
+ rb_zjit_profile_enable(iseq);
+ }
+
+ // At call-threshold, compile the ISEQ with ZJIT.
+ if (body->jit_entry_calls == rb_zjit_call_threshold) {
+ rb_zjit_compile_iseq(iseq, ec, false);
+ }
}
+ return body->jit_entry;
}
#else
-# define jit_compile(ec) ((rb_jit_func_t)0)
-# define jit_exec(ec) Qundef
+# define zjit_compile(ec) ((rb_jit_func_t)0)
#endif
+#if USE_YJIT || USE_ZJIT
+// Execute JIT code compiled by yjit_compile() or zjit_compile()
+static inline VALUE
+jit_exec(rb_execution_context_t *ec)
+{
#if USE_YJIT
+ if (rb_yjit_enabled_p) {
+ rb_jit_func_t func = yjit_compile(ec);
+ if (func) {
+ return func(ec, ec->cfp);
+ }
+ return Qundef;
+ }
+#endif
+
+#if USE_ZJIT
+ void *zjit_entry = rb_zjit_entry;
+ if (zjit_entry) {
+ rb_jit_func_t func = zjit_compile(ec);
+ if (func) {
+ VALUE result = ((rb_zjit_func_t)zjit_entry)(ec, ec->cfp, func);
+ return result;
+ }
+ }
+#endif
+ return Qundef;
+}
+
// Generate JIT code that supports the following kind of ISEQ entry:
// * The first ISEQ pushed by vm_exec_handle_exception. The frame would
// point to a location specified by a catch table, and it doesn't have
@@ -472,9 +590,27 @@ jit_exec(rb_execution_context_t *ec)
static inline rb_jit_func_t
jit_compile_exception(rb_execution_context_t *ec)
{
- const rb_iseq_t *iseq = ec->cfp->iseq;
+ const rb_iseq_t *iseq = CFP_ISEQ(ec->cfp);
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+#if USE_ZJIT
+ if (body->jit_exception == NULL && rb_zjit_enabled_p) {
+ body->jit_exception_calls++;
+
+ // At profile-threshold, rewrite some of the YARV instructions
+ // to zjit_* instructions to profile these instructions.
+ if (body->jit_exception_calls == rb_zjit_profile_threshold) {
+ rb_zjit_profile_enable(iseq);
+ }
+
+ // At call-threshold, compile the ISEQ with ZJIT.
+ if (body->jit_exception_calls == rb_zjit_call_threshold) {
+ rb_zjit_compile_iseq(iseq, ec, true);
+ }
+ }
+#endif
+
+#if USE_YJIT
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
if (body->jit_exception == NULL && rb_yjit_enabled_p) {
body->jit_exception_calls++;
@@ -482,6 +618,7 @@ jit_compile_exception(rb_execution_context_t *ec)
rb_yjit_compile_iseq(iseq, ec, true);
}
}
+#endif
return body->jit_exception;
}
@@ -500,6 +637,7 @@ jit_exec_exception(rb_execution_context_t *ec)
}
#else
# define jit_compile_exception(ec) ((rb_jit_func_t)0)
+# define jit_exec(ec) Qundef
# define jit_exec_exception(ec) Qundef
#endif
@@ -557,7 +695,7 @@ rb_current_ec_set(rb_execution_context_t *ec)
}
-#if defined(__arm64__) || defined(__aarch64__)
+#ifdef RB_THREAD_CURRENT_EC_NOINLINE
rb_execution_context_t *
rb_current_ec(void)
{
@@ -577,9 +715,10 @@ rb_current_ec_noinline(void)
#endif
-rb_event_flag_t ruby_vm_event_flags;
-rb_event_flag_t ruby_vm_event_enabled_global_flags;
-unsigned int ruby_vm_event_local_num;
+rb_event_flag_t ruby_vm_event_flags = 0;
+rb_event_flag_t ruby_vm_event_enabled_global_flags = 0;
+unsigned int ruby_vm_c_events_enabled = 0;
+unsigned int ruby_vm_iseq_events_enabled = 0;
rb_serial_t ruby_vm_constant_cache_invalidations = 0;
rb_serial_t ruby_vm_constant_cache_misses = 0;
@@ -587,7 +726,7 @@ rb_serial_t ruby_vm_global_cvar_state = 1;
static const struct rb_callcache vm_empty_cc = {
.flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE,
- .klass = Qfalse,
+ .klass = Qundef,
.cme_ = NULL,
.call_ = vm_call_general,
.aux_ = {
@@ -597,7 +736,7 @@ static const struct rb_callcache vm_empty_cc = {
static const struct rb_callcache vm_empty_cc_for_super = {
.flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE,
- .klass = Qfalse,
+ .klass = Qundef,
.cme_ = NULL,
.call_ = vm_call_super_method,
.aux_ = {
@@ -712,8 +851,8 @@ vm_stat(int argc, VALUE *argv, VALUE self)
SET(constant_cache_invalidations, ruby_vm_constant_cache_invalidations);
SET(constant_cache_misses, ruby_vm_constant_cache_misses);
SET(global_cvar_state, ruby_vm_global_cvar_state);
- SET(next_shape_id, (rb_serial_t)GET_SHAPE_TREE()->next_shape_id);
- SET(shape_cache_size, (rb_serial_t)GET_SHAPE_TREE()->cache_size);
+ SET(next_shape_id, (rb_serial_t)rb_shapes_count());
+ SET(shape_cache_size, (rb_serial_t)rb_shapes_cache_size());
#undef SET
#if USE_DEBUG_COUNTER
@@ -741,15 +880,16 @@ vm_stat(int argc, VALUE *argv, VALUE self)
/* control stack frame */
static void
-vm_set_top_stack(rb_execution_context_t *ec, const rb_iseq_t *iseq)
+vm_set_top_stack(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_box_t *box)
{
if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_TOP) {
rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence");
}
/* for return */
- vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH, rb_ec_thread_ptr(ec)->top_self,
- VM_BLOCK_HANDLER_NONE,
+ vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
+ rb_ec_thread_ptr(ec)->top_self,
+ GC_GUARDED_PTR(box),
(VALUE)vm_cref_new_toplevel(ec), /* cref or me */
ISEQ_BODY(iseq)->iseq_encoded, ec->cfp->sp,
ISEQ_BODY(iseq)->local_table_size, ISEQ_BODY(iseq)->stack_max);
@@ -787,7 +927,7 @@ rb_control_frame_t *
rb_vm_get_binding_creatable_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
{
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
- if (cfp->iseq) {
+ if (CFP_ISEQ(cfp)) {
return (rb_control_frame_t *)cfp;
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
@@ -956,6 +1096,7 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
}
}
else {
+ VM_ASSERT(VM_ENV_LOCAL_P(ep));
VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep);
if (block_handler != VM_BLOCK_HANDLER_NONE) {
@@ -964,13 +1105,14 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
}
}
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
if (!VM_FRAME_RUBYFRAME_P(cfp)) {
local_size = VM_ENV_DATA_SIZE;
}
else {
- local_size = ISEQ_BODY(cfp->iseq)->local_table_size;
- if (ISEQ_BODY(cfp->iseq)->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
- int ci_offset = local_size - ISEQ_BODY(cfp->iseq)->param.size + VM_ENV_DATA_SIZE;
+ local_size = ISEQ_BODY(iseq)->local_table_size;
+ if (ISEQ_BODY(iseq)->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
+ int ci_offset = local_size - ISEQ_BODY(iseq)->param.size + VM_ENV_DATA_SIZE;
CALL_INFO ci = (CALL_INFO)VM_CF_LEP(cfp)[-ci_offset];
local_size += vm_ci_argc(ci);
@@ -978,6 +1120,14 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
local_size += VM_ENV_DATA_SIZE;
}
+ // Invalidate JIT code that assumes cfp->ep == vm_base_ptr(cfp).
+ // This is done before creating the imemo_env because VM_STACK_ENV_WRITE
+ // below leaves the on-stack ep in a state that is unsafe to GC.
+ if (VM_FRAME_RUBYFRAME_P(cfp)) {
+ rb_yjit_invalidate_ep_is_bp(iseq);
+ rb_zjit_invalidate_no_ep_escape(iseq);
+ }
+
/*
* # local variables on a stack frame (N == local_size)
* [lvar1, lvar2, ..., lvarN, SPECVAL]
@@ -1003,7 +1153,7 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
env_ep = &env_body[local_size - 1 /* specval */];
env_ep[VM_ENV_DATA_INDEX_ENV] = (VALUE)env;
- env->iseq = (rb_iseq_t *)(VM_FRAME_RUBYFRAME_P(cfp) ? cfp->iseq : NULL);
+ env->iseq = (rb_iseq_t *)(VM_FRAME_RUBYFRAME_P(cfp) ? iseq : NULL);
env->ep = env_ep;
env->env = env_body;
env->env_size = env_size;
@@ -1021,11 +1171,6 @@ vm_make_env_each(const rb_execution_context_t * const ec, rb_control_frame_t *co
}
#endif
- // Invalidate JIT code that assumes cfp->ep == vm_base_ptr(cfp).
- if (env->iseq) {
- rb_yjit_invalidate_ep_is_bp(env->iseq);
- }
-
return (VALUE)env;
}
@@ -1209,7 +1354,7 @@ rb_proc_dup(VALUE self)
break;
}
- if (RB_OBJ_SHAREABLE_P(self)) FL_SET_RAW(procval, RUBY_FL_SHAREABLE);
+ if (RB_OBJ_SHAREABLE_P(self)) RB_OBJ_SET_SHAREABLE(procval);
RB_GC_GUARD(self); /* for: body = rb_proc_dup(body) */
return procval;
}
@@ -1273,7 +1418,19 @@ env_copy(const VALUE *src_ep, VALUE read_only_variables)
const rb_env_t *copied_env = vm_env_new(ep, env_body, src_env->env_size, src_env->iseq);
// Copy after allocations above, since they can move objects in src_ep.
- RB_OBJ_WRITE(copied_env, &ep[VM_ENV_DATA_INDEX_ME_CREF], src_ep[VM_ENV_DATA_INDEX_ME_CREF]);
+ VALUE svar_val = src_ep[VM_ENV_DATA_INDEX_ME_CREF];
+ if (imemo_type_p(svar_val, imemo_svar)) {
+ const struct vm_svar *svar = (struct vm_svar *)svar_val;
+
+ if (svar->cref_or_me) {
+ svar_val = svar->cref_or_me;
+ }
+ else {
+ svar_val = Qfalse;
+ }
+ }
+ RB_OBJ_WRITE(copied_env, &ep[VM_ENV_DATA_INDEX_ME_CREF], svar_val);
+
ep[VM_ENV_DATA_INDEX_FLAGS] = src_ep[VM_ENV_DATA_INDEX_FLAGS] | VM_ENV_FLAG_ISOLATED;
if (!VM_ENV_LOCAL_P(src_ep)) {
VM_ENV_FLAGS_SET(ep, VM_ENV_FLAG_LOCAL);
@@ -1283,12 +1440,22 @@ env_copy(const VALUE *src_ep, VALUE read_only_variables)
for (int i=RARRAY_LENINT(read_only_variables)-1; i>=0; i--) {
ID id = NUM2ID(RARRAY_AREF(read_only_variables, i));
- for (unsigned int j=0; j<ISEQ_BODY(src_env->iseq)->local_table_size; j++) {
- if (id == ISEQ_BODY(src_env->iseq)->local_table[j]) {
+ const struct rb_iseq_constant_body *body = ISEQ_BODY(src_env->iseq);
+ for (unsigned int j=0; j<body->local_table_size; j++) {
+ if (id == body->local_table[j]) {
+ // check reassignment
+ if (body->lvar_states[j] == lvar_reassigned) {
+ VALUE name = rb_id2str(id);
+ VALUE msg = rb_sprintf("cannot make a shareable Proc because "
+ "the outer variable '%" PRIsVALUE "' may be reassigned.", name);
+ rb_exc_raise(rb_exc_new_str(rb_eRactorIsolationError, msg));
+ }
+
+ // check shareable
VALUE v = src_env->env[j];
if (!rb_ractor_shareable_p(v)) {
VALUE name = rb_id2str(id);
- VALUE msg = rb_sprintf("can not make shareable Proc because it can refer"
+ VALUE msg = rb_sprintf("cannot make a shareable Proc because it can refer"
" unshareable object %+" PRIsVALUE " from ", v);
if (name)
rb_str_catf(msg, "variable '%" PRIsVALUE "'", name);
@@ -1315,6 +1482,7 @@ env_copy(const VALUE *src_ep, VALUE read_only_variables)
ep[VM_ENV_DATA_INDEX_SPECVAL] = VM_BLOCK_HANDLER_NONE;
}
+ RB_OBJ_SET_SHAREABLE((VALUE)copied_env);
return copied_env;
}
@@ -1351,22 +1519,28 @@ proc_shared_outer_variables(struct rb_id_table *outer_variables, bool isolate, c
}
if (*sep == ',') rb_str_cat_cstr(str, ")");
rb_str_cat_cstr(str, data.yield ? " and uses 'yield'." : ".");
- rb_exc_raise(rb_exc_new_str(rb_eArgError, str));
+ rb_exc_raise(rb_exc_new_str(rb_eRactorIsolationError, str));
}
else if (data.yield) {
- rb_raise(rb_eArgError, "can not %s because it uses 'yield'.", message);
+ rb_raise(rb_eRactorIsolationError, "can not %s because it uses 'yield'.", message);
}
return data.read_only;
}
VALUE
-rb_proc_isolate_bang(VALUE self)
+rb_proc_isolate_bang(VALUE self, VALUE replace_self)
{
const rb_iseq_t *iseq = vm_proc_iseq(self);
if (iseq) {
rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
+
+ if (!UNDEF_P(replace_self)) {
+ VM_ASSERT(rb_ractor_shareable_p(replace_self));
+ RB_OBJ_WRITE(self, &proc->block.as.captured.self, replace_self);
+ }
+
if (proc->block.type != block_type_iseq) rb_raise(rb_eRuntimeError, "not supported yet");
if (ISEQ_BODY(iseq)->outer_variables) {
@@ -1375,9 +1549,10 @@ rb_proc_isolate_bang(VALUE self)
proc_isolate_env(self, proc, Qfalse);
proc->is_isolated = TRUE;
+ RB_OBJ_WRITE(self, &proc->block.as.captured.self, Qnil);
}
- FL_SET_RAW(self, RUBY_FL_SHAREABLE);
+ RB_OBJ_SET_SHAREABLE(self);
return self;
}
@@ -1385,17 +1560,22 @@ VALUE
rb_proc_isolate(VALUE self)
{
VALUE dst = rb_proc_dup(self);
- rb_proc_isolate_bang(dst);
+ rb_proc_isolate_bang(dst, Qundef);
return dst;
}
VALUE
-rb_proc_ractor_make_shareable(VALUE self)
+rb_proc_ractor_make_shareable(VALUE self, VALUE replace_self)
{
const rb_iseq_t *iseq = vm_proc_iseq(self);
if (iseq) {
rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self);
+
+ if (!UNDEF_P(replace_self)) {
+ RB_OBJ_WRITE(self, &proc->block.as.captured.self, replace_self);
+ }
+
if (proc->block.type != block_type_iseq) rb_raise(rb_eRuntimeError, "not supported yet");
if (!rb_ractor_shareable_p(vm_block_self(&proc->block))) {
@@ -1414,8 +1594,19 @@ rb_proc_ractor_make_shareable(VALUE self)
proc_isolate_env(self, proc, read_only_variables);
proc->is_isolated = TRUE;
}
+ else {
+ const struct rb_block *block = vm_proc_block(self);
+ if (block->type != block_type_symbol) rb_raise(rb_eRuntimeError, "not supported yet");
+
+ VALUE proc_self = vm_block_self(block);
+ if (!rb_ractor_shareable_p(proc_self)) {
+ rb_raise(rb_eRactorIsolationError,
+ "Proc's self is not shareable: %" PRIsVALUE,
+ self);
+ }
+ }
- rb_obj_freeze(self);
+ RB_OBJ_SET_FROZEN_SHAREABLE(self);
return self;
}
@@ -1484,8 +1675,8 @@ rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *s
GetBindingPtr(bindval, bind);
vm_bind_update_env(bindval, bind, envval);
RB_OBJ_WRITE(bindval, &bind->block.as.captured.self, cfp->self);
- RB_OBJ_WRITE(bindval, &bind->block.as.captured.code.iseq, cfp->iseq);
- RB_OBJ_WRITE(bindval, &bind->pathobj, ISEQ_BODY(ruby_level_cfp->iseq)->location.pathobj);
+ RB_OBJ_WRITE(bindval, &bind->block.as.captured.code.iseq, CFP_ISEQ(cfp));
+ RB_OBJ_WRITE(bindval, &bind->pathobj, ISEQ_BODY(CFP_ISEQ(ruby_level_cfp))->location.pathobj);
bind->first_lineno = rb_vm_get_sourceline(ruby_level_cfp);
return bindval;
@@ -1516,6 +1707,7 @@ rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const I
rb_node_init(RNODE(&tmp_node), NODE_SCOPE);
tmp_node.nd_tbl = dyns;
tmp_node.nd_body = 0;
+ tmp_node.nd_parent = NULL;
tmp_node.nd_args = 0;
VALUE ast_value = rb_ruby_ast_new(RNODE(&tmp_node));
@@ -1791,9 +1983,9 @@ rb_vm_invoke_proc_with_self(rb_execution_context_t *ec, rb_proc_t *proc, VALUE s
VALUE *
rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
{
- while (cfp->pc == 0 || cfp->iseq == 0) {
+ while (!CFP_PC(cfp) || !CFP_ISEQ(cfp)) {
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC) {
- struct vm_ifunc *ifunc = (struct vm_ifunc *)cfp->iseq;
+ struct vm_ifunc *ifunc = (struct vm_ifunc *)CFP_ISEQ(cfp);
return ifunc->svar_lep;
}
else {
@@ -1876,7 +2068,7 @@ rb_sourcefile(void)
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
if (cfp) {
- return RSTRING_PTR(rb_iseq_path(cfp->iseq));
+ return RSTRING_PTR(rb_iseq_path(CFP_ISEQ(cfp)));
}
else {
return 0;
@@ -1905,7 +2097,7 @@ rb_source_location(int *pline)
if (cfp && VM_FRAME_RUBYFRAME_P(cfp)) {
if (pline) *pline = rb_vm_get_sourceline(cfp);
- return rb_iseq_path(cfp->iseq);
+ return rb_iseq_path(CFP_ISEQ(cfp));
}
else {
if (pline) *pline = 0;
@@ -2160,7 +2352,7 @@ static void
rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
{
st_data_t bop;
- if (RB_TYPE_P(klass, T_ICLASS) && FL_TEST(klass, RICLASS_IS_ORIGIN) &&
+ if (RB_TYPE_P(klass, T_ICLASS) && RICLASS_IS_ORIGIN_P(klass) &&
RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) {
klass = RBASIC_CLASS(klass);
}
@@ -2175,6 +2367,7 @@ rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
rb_id2name(me->called_id)
);
rb_yjit_bop_redefined(flag, (enum ruby_basic_operators)bop);
+ rb_zjit_bop_redefined(flag, (enum ruby_basic_operators)bop);
ruby_vm_redefined_flag[bop] |= flag;
}
}
@@ -2255,6 +2448,7 @@ vm_init_redefined_flag(void)
OP(GT, GT), (C(Integer), C(Float));
OP(GE, GE), (C(Integer), C(Float));
OP(LTLT, LTLT), (C(String), C(Array));
+ OP(GTGT, GTGT), (C(Integer));
OP(AREF, AREF), (C(Array), C(Hash), C(Integer));
OP(ASET, ASET), (C(Array), C(Hash));
OP(Length, LENGTH), (C(Array), C(String), C(Hash));
@@ -2385,8 +2579,12 @@ hook_before_rewind(rb_execution_context_t *ec, bool cfp_returning_with_value, in
return;
}
else {
- const rb_iseq_t *iseq = ec->cfp->iseq;
- rb_hook_list_t *local_hooks = iseq->aux.exec.local_hooks;
+ const rb_iseq_t *iseq = CFP_ISEQ(ec->cfp);
+ rb_hook_list_t *local_hooks = NULL;
+ unsigned int local_hooks_cnt = iseq->aux.exec.local_hooks_cnt;
+ if (RB_UNLIKELY(local_hooks_cnt > 0)) {
+ local_hooks = rb_iseq_local_hooks(iseq, rb_ec_ractor_ptr(ec), false);
+ }
switch (VM_FRAME_TYPE(ec->cfp)) {
case VM_FRAME_MAGIC_METHOD:
@@ -2424,15 +2622,18 @@ hook_before_rewind(rb_execution_context_t *ec, bool cfp_returning_with_value, in
bmethod_return_value);
VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
- local_hooks = me->def->body.bmethod.hooks;
-
- if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_RETURN)) {
- rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_RETURN, ec->cfp->self,
- rb_vm_frame_method_entry(ec->cfp)->def->original_id,
- rb_vm_frame_method_entry(ec->cfp)->called_id,
- rb_vm_frame_method_entry(ec->cfp)->owner,
- bmethod_return_value, TRUE);
+ unsigned int local_hooks_cnt = me->def->body.bmethod.local_hooks_cnt;
+ if (UNLIKELY(local_hooks_cnt > 0)) {
+ local_hooks = rb_method_def_local_hooks(me->def, rb_ec_ractor_ptr(ec), false);
+ if (local_hooks && local_hooks->events & RUBY_EVENT_RETURN) {
+ rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_RETURN, ec->cfp->self,
+ rb_vm_frame_method_entry(ec->cfp)->def->original_id,
+ rb_vm_frame_method_entry(ec->cfp)->called_id,
+ rb_vm_frame_method_entry(ec->cfp)->owner,
+ bmethod_return_value, TRUE);
+ }
}
+
THROW_DATA_CONSUMED_SET(err);
}
else {
@@ -2631,6 +2832,31 @@ vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state,
return result;
}
+#if USE_ZJIT
+// Materialize JITFrame-enabled CFP into interpreter-compatible CFP
+void
+rb_zjit_materialize_frames(const rb_execution_context_t *ec, rb_control_frame_t *cfp)
+{
+ if (!rb_zjit_enabled_p) return;
+ const rb_control_frame_t *end_cfp = ec->tag->cfp;
+ VM_ASSERT(cfp <= end_cfp);
+
+ while (true) {
+ if (CFP_ZJIT_FRAME_P(cfp)) {
+ const zjit_jit_frame_t *jit_frame = CFP_ZJIT_FRAME(cfp);
+ cfp->pc = jit_frame->pc;
+ cfp->_iseq = (rb_iseq_t *)jit_frame->iseq;
+ if (jit_frame->materialize_block_code) {
+ cfp->block_code = NULL;
+ }
+ cfp->jit_return = 0;
+ }
+ if (end_cfp == cfp) break;
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+}
+#endif
+
static inline VALUE
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo)
{
@@ -2648,7 +2874,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
cont_pc = cont_sp = 0;
catch_iseq = NULL;
- while (ec->cfp->pc == 0 || ec->cfp->iseq == 0) {
+ while (CFP_PC(ec->cfp) == 0 || CFP_ISEQ(ec->cfp) == 0) {
if (UNLIKELY(VM_FRAME_TYPE(ec->cfp) == VM_FRAME_MAGIC_CFUNC)) {
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_C_RETURN, ec->cfp->self,
rb_vm_frame_method_entry(ec->cfp)->def->original_id,
@@ -2662,7 +2888,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
}
rb_control_frame_t *const cfp = ec->cfp;
- epc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded;
+ epc = CFP_PC(cfp) - ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
escape_cfp = NULL;
if (state == TAG_BREAK || state == TAG_RETURN) {
@@ -2675,7 +2901,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
THROW_DATA_STATE_SET(err, state = TAG_BREAK);
}
else {
- ct = ISEQ_BODY(cfp->iseq)->catch_table;
+ ct = ISEQ_BODY(CFP_ISEQ(cfp))->catch_table;
if (ct) for (i = 0; i < ct->size; i++) {
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
if (entry->start < epc && entry->end >= epc) {
@@ -2702,13 +2928,14 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
/* TAG_BREAK */
*cfp->sp++ = THROW_DATA_VAL(err);
ec->errinfo = Qnil;
+ rb_zjit_materialize_frames(ec, cfp);
return Qundef;
}
}
}
if (state == TAG_RAISE) {
- ct = ISEQ_BODY(cfp->iseq)->catch_table;
+ ct = ISEQ_BODY(CFP_ISEQ(cfp))->catch_table;
if (ct) for (i = 0; i < ct->size; i++) {
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
if (entry->start < epc && entry->end >= epc) {
@@ -2724,7 +2951,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
}
}
else if (state == TAG_RETRY) {
- ct = ISEQ_BODY(cfp->iseq)->catch_table;
+ ct = ISEQ_BODY(CFP_ISEQ(cfp))->catch_table;
if (ct) for (i = 0; i < ct->size; i++) {
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
if (entry->start < epc && entry->end >= epc) {
@@ -2739,7 +2966,8 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
const rb_control_frame_t *escape_cfp;
escape_cfp = THROW_DATA_CATCH_FRAME(err);
if (cfp == escape_cfp) {
- cfp->pc = ISEQ_BODY(cfp->iseq)->iseq_encoded + entry->cont;
+ rb_zjit_materialize_frames(ec, cfp);
+ cfp->pc = ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded + entry->cont;
ec->errinfo = Qnil;
return Qundef;
}
@@ -2757,7 +2985,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
/* otherwise = dontcare */
}[state];
- ct = ISEQ_BODY(cfp->iseq)->catch_table;
+ ct = ISEQ_BODY(CFP_ISEQ(cfp))->catch_table;
if (ct) for (i = 0; i < ct->size; i++) {
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
@@ -2769,7 +2997,8 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
break;
}
else if (entry->type == type) {
- cfp->pc = ISEQ_BODY(cfp->iseq)->iseq_encoded + entry->cont;
+ rb_zjit_materialize_frames(ec, cfp);
+ cfp->pc = ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded + entry->cont;
cfp->sp = vm_base_ptr(cfp) + entry->sp;
if (state != TAG_REDO) {
@@ -2783,7 +3012,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
}
}
else {
- ct = ISEQ_BODY(cfp->iseq)->catch_table;
+ ct = ISEQ_BODY(CFP_ISEQ(cfp))->catch_table;
if (ct) for (i = 0; i < ct->size; i++) {
entry = UNALIGNED_MEMBER_PTR(ct, entries[i]);
if (entry->start < epc && entry->end >= epc) {
@@ -2803,8 +3032,9 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
const int arg_size = 1;
rb_iseq_check(catch_iseq);
+ rb_zjit_materialize_frames(ec, cfp); // vm_base_ptr looks at cfp->_iseq
cfp->sp = vm_base_ptr(cfp) + cont_sp;
- cfp->pc = ISEQ_BODY(cfp->iseq)->iseq_encoded + cont_pc;
+ cfp->pc = ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded + cont_pc;
/* push block frame */
cfp->sp[0] = (VALUE)err;
@@ -2829,6 +3059,7 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
if (VM_FRAME_FINISHED_P(ec->cfp)) {
rb_vm_pop_frame(ec);
ec->errinfo = (VALUE)err;
+ rb_vm_tag_jmpbuf_deinit(&ec->tag->buf);
ec->tag = ec->tag->prev;
EC_JUMP_TAG(ec, state);
}
@@ -2842,11 +3073,11 @@ vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, V
/* misc */
VALUE
-rb_iseq_eval(const rb_iseq_t *iseq)
+rb_iseq_eval(const rb_iseq_t *iseq, const rb_box_t *box)
{
rb_execution_context_t *ec = GET_EC();
VALUE val;
- vm_set_top_stack(ec, iseq);
+ vm_set_top_stack(ec, iseq, box);
val = vm_exec(ec);
return val;
}
@@ -2856,7 +3087,6 @@ rb_iseq_eval_main(const rb_iseq_t *iseq)
{
rb_execution_context_t *ec = GET_EC();
VALUE val;
-
vm_set_main_stack(ec, iseq);
val = vm_exec(ec);
return val;
@@ -2897,10 +3127,11 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
rb_execution_context_t *ec = GET_EC();
const rb_control_frame_t *reg_cfp = ec->cfp;
const rb_iseq_t *iseq = rb_iseq_new(Qnil, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
+ const rb_box_t *box = rb_current_box();
VALUE val;
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
- recv, block_handler,
+ recv, GC_GUARDED_PTR(box),
(VALUE)vm_cref_new_toplevel(ec), /* cref or me */
0, reg_cfp->sp, 0, 0);
@@ -2910,6 +3141,117 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
return val;
}
+/* Ruby::Box */
+
+VALUE
+rb_vm_call_cfunc_in_box(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2,
+ VALUE filename, const rb_box_t *box)
+{
+ rb_execution_context_t *ec = GET_EC();
+ const rb_control_frame_t *reg_cfp = ec->cfp;
+ const rb_iseq_t *iseq = rb_iseq_new(Qnil, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
+ VALUE val;
+
+ vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
+ recv, GC_GUARDED_PTR(box),
+ (VALUE)vm_cref_new_toplevel(ec), /* cref or me */
+ 0, reg_cfp->sp, 0, 0);
+
+ val = (*func)(arg1, arg2);
+
+ rb_vm_pop_frame(ec);
+ return val;
+}
+
+void
+rb_vm_frame_flag_set_box_require(const rb_execution_context_t *ec)
+{
+ VM_ASSERT(rb_box_available());
+ VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_BOX_REQUIRE);
+}
+
+static const rb_box_t *
+current_box_on_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
+{
+ rb_callable_method_entry_t *cme;
+ const rb_box_t *box;
+ const VALUE *lep = VM_EP_RUBY_LEP(ec, cfp);
+ VM_BOX_ASSERT(lep, "lep should be valid");
+ VM_BOX_ASSERT(rb_box_available(), "box should be available here");
+
+ if (VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_METHOD) || VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_CFUNC)) {
+ cme = check_method_entry(lep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
+ VM_BOX_ASSERT(cme, "cme should be valid");
+ VM_BOX_ASSERT(cme->def, "cme->def shold be valid");
+ return cme->def->box;
+ }
+ else if (VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_TOP) || VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_CLASS)) {
+ VM_BOX_ASSERT(VM_ENV_LOCAL_P(lep), "lep should be local on MAGIC_TOP or MAGIC_CLASS frames");
+ return VM_ENV_BOX(lep);
+ }
+ else if (VM_ENV_FRAME_TYPE_P(lep, VM_FRAME_MAGIC_DUMMY)) {
+ // No valid local ep found (just after process boot?)
+ // return the root box (the only valid box) until the main is initialized
+ box = rb_main_box();
+ if (box)
+ return box;
+ return rb_root_box();
+ }
+ else {
+ VM_BOX_CRASHED();
+ rb_bug("BUG: Local ep without cme/box, flags: %08lX", (unsigned long)lep[VM_ENV_DATA_INDEX_FLAGS]);
+ }
+ UNREACHABLE_RETURN(0);
+}
+
+const rb_box_t *
+rb_vm_current_box(const rb_execution_context_t *ec)
+{
+ return current_box_on_cfp(ec, ec->cfp);
+}
+
+static const rb_control_frame_t *
+find_loader_control_frame(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const rb_control_frame_t *end_cfp)
+{
+ while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
+ if (!VM_ENV_FRAME_TYPE_P(cfp->ep, VM_FRAME_MAGIC_CFUNC))
+ break;
+ if (!BOX_MASTER_P(current_box_on_cfp(ec, cfp)))
+ break;
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+ VM_ASSERT(RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp));
+ return cfp;
+}
+
+const rb_box_t *
+rb_vm_loading_box(const rb_execution_context_t *ec)
+{
+ const rb_control_frame_t *cfp, *current_cfp, *end_cfp;
+
+ if (!rb_box_available() || !ec)
+ return rb_root_box();
+
+ cfp = ec->cfp;
+ current_cfp = cfp;
+ end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
+
+ while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
+ if (VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BOX_REQUIRE)) {
+ if (RTEST(cfp->self) && BOX_OBJ_P(cfp->self)) {
+ // Box#require, #require_relative, #load
+ return rb_get_box_t(cfp->self);
+ }
+ // Kernel#require, #require_relative, #load
+ cfp = find_loader_control_frame(ec, cfp, end_cfp);
+ return current_box_on_cfp(ec, cfp);
+ }
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+ // no require/load with explicit boxes.
+ return current_box_on_cfp(ec, current_cfp);
+}
+
/* vm */
void
@@ -2918,21 +3260,15 @@ rb_vm_update_references(void *ptr)
if (ptr) {
rb_vm_t *vm = ptr;
+ vm->self = rb_gc_location(vm->self);
vm->mark_object_ary = rb_gc_location(vm->mark_object_ary);
- vm->load_path = rb_gc_location(vm->load_path);
- vm->load_path_snapshot = rb_gc_location(vm->load_path_snapshot);
-
- if (vm->load_path_check_cache) {
- vm->load_path_check_cache = rb_gc_location(vm->load_path_check_cache);
- }
-
- vm->expanded_load_path = rb_gc_location(vm->expanded_load_path);
- vm->loaded_features = rb_gc_location(vm->loaded_features);
- vm->loaded_features_snapshot = rb_gc_location(vm->loaded_features_snapshot);
- vm->loaded_features_realpaths = rb_gc_location(vm->loaded_features_realpaths);
- vm->loaded_features_realpath_map = rb_gc_location(vm->loaded_features_realpath_map);
- vm->top_self = rb_gc_location(vm->top_self);
vm->orig_progname = rb_gc_location(vm->orig_progname);
+ vm->cc_refinement_set = rb_gc_location(vm->cc_refinement_set);
+
+ if (vm->root_box)
+ rb_box_gc_update_references(vm->root_box);
+ if (vm->main_box)
+ rb_box_gc_update_references(vm->main_box);
rb_gc_update_values(RUBY_NSIG, vm->trap_list.cmd);
@@ -2999,32 +3335,31 @@ rb_vm_mark(void *ptr)
rb_gc_mark(rb_ractor_self(r));
}
- for (struct global_object_list *list = vm->global_object_list; list; list = list->next) {
- rb_gc_mark_maybe(*list->varptr);
+ for (size_t index = 0; index < vm->global_object_list_size; index++) {
+ rb_gc_mark_maybe(*vm->global_object_list[index]);
+ }
+
+ rb_gc_mark_movable(vm->self);
+
+ if (vm->root_box) {
+ rb_box_entry_mark(vm->root_box);
+ }
+ if (vm->main_box) {
+ rb_box_entry_mark(vm->main_box);
}
rb_gc_mark_movable(vm->mark_object_ary);
- rb_gc_mark_movable(vm->load_path);
- rb_gc_mark_movable(vm->load_path_snapshot);
- rb_gc_mark_movable(vm->load_path_check_cache);
- rb_gc_mark_movable(vm->expanded_load_path);
- rb_gc_mark_movable(vm->loaded_features);
- rb_gc_mark_movable(vm->loaded_features_snapshot);
- rb_gc_mark_movable(vm->loaded_features_realpaths);
- rb_gc_mark_movable(vm->loaded_features_realpath_map);
- rb_gc_mark_movable(vm->top_self);
rb_gc_mark_movable(vm->orig_progname);
rb_gc_mark_movable(vm->coverages);
rb_gc_mark_movable(vm->me2counter);
-
- if (vm->loading_table) {
- rb_mark_tbl(vm->loading_table);
- }
+ rb_gc_mark_movable(vm->cc_refinement_set);
rb_gc_mark_values(RUBY_NSIG, vm->trap_list.cmd);
- rb_id_table_foreach_values(vm->negative_cme_table, vm_mark_negative_cme, NULL);
- rb_mark_tbl_no_pin(vm->overloaded_cme_table);
+ rb_hook_list_mark(&vm->global_hooks);
+
+ rb_id_table_foreach_values(&vm->negative_cme_table, vm_mark_negative_cme, NULL);
+ rb_mark_tbl_no_pin(&vm->overloaded_cme_table);
for (i=0; i<VM_GLOBAL_CC_CACHE_TABLE_SIZE; i++) {
const struct rb_callcache *cc = vm->global_cc_cache_table[i];
@@ -3055,62 +3390,41 @@ rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE cls,
rb_vm_register_global_object(exc);
}
-static int
-free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
-{
- xfree((char *)key);
- return ST_DELETE;
-}
-
-void rb_free_loaded_features_index(rb_vm_t *vm);
void rb_objspace_free_objects(void *objspace);
int
ruby_vm_destruct(rb_vm_t *vm)
{
RUBY_FREE_ENTER("vm");
+ ruby_vm_during_cleanup = true;
if (vm) {
rb_thread_t *th = vm->ractor.main_thread;
- VALUE *stack = th->ec->vm_stack;
+
if (rb_free_at_exit) {
rb_free_encoded_insn_data();
rb_free_global_enc_table();
rb_free_loaded_builtin_table();
+ rb_free_global_symbol_table();
rb_free_shared_fiber_pool();
- rb_free_static_symid_str();
rb_free_transcoder_table();
rb_free_vm_opt_tables();
rb_free_warning();
rb_free_rb_global_tbl();
- rb_free_loaded_features_index(vm);
- rb_id_table_free(vm->negative_cme_table);
- st_free_table(vm->overloaded_cme_table);
+ rb_id_table_free_items(&vm->negative_cme_table);
+ st_free_embedded_table(&vm->overloaded_cme_table);
- rb_id_table_free(RCLASS(rb_mRubyVMFrozenCore)->m_tbl);
-
- 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);
- while (cursor < end) {
- // 0x1 == SINGLE_CHILD_P
- if (cursor->edges && !(((uintptr_t)cursor->edges) & 0x1))
- rb_id_table_free(cursor->edges);
- cursor += 1;
- }
+ // TODO: Is this ignorable for classext->m_tbl ?
+ // rb_id_table_free(RCLASS(rb_mRubyVMFrozenCore)->m_tbl);
- xfree(GET_SHAPE_TREE());
+ st_free_embedded_table(&vm->static_ext_inits);
- st_free_table(vm->static_ext_inits);
+ rb_id_table_free_items(&vm->constant_cache);
+ set_free_embedded_table(&vm->unused_block_warning_table);
- rb_vm_postponed_job_free();
-
- rb_id_table_free(vm->constant_cache);
- st_free_table(vm->unused_block_warning_table);
-
- xfree(th->nt);
- th->nt = NULL;
+ rb_thread_free_native_thread(th);
#ifndef HAVE_SETPROCTITLE
ruby_free_proctitle();
@@ -3125,56 +3439,33 @@ ruby_vm_destruct(rb_vm_t *vm)
rb_vm_living_threads_init(vm);
ruby_vm_run_at_exit_hooks(vm);
- if (vm->loading_table) {
- st_foreach(vm->loading_table, free_loading_table_entry, 0);
- st_free_table(vm->loading_table);
- vm->loading_table = 0;
- }
- if (vm->ci_table) {
- st_free_table(vm->ci_table);
- vm->ci_table = NULL;
- }
- if (vm->frozen_strings) {
- st_free_table(vm->frozen_strings);
- vm->frozen_strings = 0;
- }
+ st_free_embedded_table(&vm->ci_table);
RB_ALTSTACK_FREE(vm->main_altstack);
- struct global_object_list *next;
- for (struct global_object_list *list = vm->global_object_list; list; list = next) {
- next = list->next;
- xfree(list);
- }
+ SIZED_FREE_N(vm->global_object_list, vm->global_object_list_capa);
if (objspace) {
if (rb_free_at_exit) {
rb_objspace_free_objects(objspace);
- rb_free_generic_iv_tbl_();
+ rb_free_generic_fields_tbl_();
rb_free_default_rand_key();
- if (th && vm->fork_gen == 0) {
- /* If we have forked, main_thread may not be the initial thread */
- xfree(stack);
- ruby_mimfree(th);
- }
}
rb_objspace_free(objspace);
}
rb_native_mutex_destroy(&vm->workqueue_lock);
/* after freeing objspace, you *can't* use ruby_xfree() */
- ruby_mimfree(vm);
ruby_current_vm_ptr = NULL;
-#if USE_YJIT
if (rb_free_at_exit) {
+#if USE_YJIT
rb_yjit_free_at_exit();
- }
#endif
+ }
}
RUBY_FREE_LEAVE("vm");
return 0;
}
-size_t rb_vm_memsize_waiting_fds(struct ccan_list_head *waiting_fds); // thread.c
size_t rb_vm_memsize_workqueue(struct ccan_list_head *workqueue); // vm_trace.c
// Used for VM memsize reporting. Returns the size of the at_exit list by
@@ -3182,7 +3473,7 @@ size_t rb_vm_memsize_workqueue(struct ccan_list_head *workqueue); // vm_trace.c
static enum rb_id_table_iterator_result
vm_memsize_constant_cache_i(ID id, VALUE ics, void *size)
{
- *((size_t *) size) += rb_st_memsize((st_table *) ics);
+ *((size_t *) size) += rb_set_memsize((set_table *) ics);
return ID_TABLE_CONTINUE;
}
@@ -3193,9 +3484,9 @@ static size_t
vm_memsize_constant_cache(void)
{
rb_vm_t *vm = GET_VM();
- size_t size = rb_id_table_memsize(vm->constant_cache);
+ size_t size = rb_id_table_memsize(&vm->constant_cache) - sizeof(struct rb_id_table);
- rb_id_table_foreach(vm->constant_cache, vm_memsize_constant_cache_i, &size);
+ rb_id_table_foreach(&vm->constant_cache, vm_memsize_constant_cache_i, &size);
return size;
}
@@ -3229,19 +3520,15 @@ vm_memsize(const void *ptr)
return (
sizeof(rb_vm_t) +
- rb_vm_memsize_waiting_fds(&vm->waiting_fds) +
- rb_st_memsize(vm->loaded_features_index) +
- rb_st_memsize(vm->loading_table) +
rb_vm_memsize_postponed_job_queue() +
rb_vm_memsize_workqueue(&vm->workqueue) +
vm_memsize_at_exit_list(vm->at_exit) +
- rb_st_memsize(vm->ci_table) +
- rb_st_memsize(vm->frozen_strings) +
+ (rb_st_memsize(&vm->ci_table) - sizeof(struct st_table)) +
vm_memsize_builtin_function_table(vm->builtin_function_table) +
- rb_id_table_memsize(vm->negative_cme_table) +
- rb_st_memsize(vm->overloaded_cme_table) +
- vm_memsize_constant_cache() +
- GET_SHAPE_TREE()->cache_size * sizeof(redblack_node_t)
+ (rb_id_table_memsize(&vm->negative_cme_table) - sizeof(struct rb_id_table)) +
+ (rb_st_memsize(&vm->overloaded_cme_table) - sizeof(struct st_table)) +
+ (vm->global_object_list_capa * sizeof(*vm->global_object_list)) +
+ vm_memsize_constant_cache()
);
// TODO
@@ -3250,12 +3537,13 @@ vm_memsize(const void *ptr)
// struct rb_objspace *objspace;
}
-static const rb_data_type_t vm_data_type = {
+const rb_data_type_t ruby_vm_data_type = {
"VM",
{0, 0, vm_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
+#define vm_data_type ruby_vm_data_type
static VALUE
vm_default_params(void)
@@ -3364,8 +3652,18 @@ rb_execution_context_update(rb_execution_context_t *ec)
while (cfp != limit_cfp) {
const VALUE *ep = cfp->ep;
cfp->self = rb_gc_location(cfp->self);
- cfp->iseq = (rb_iseq_t *)rb_gc_location((VALUE)cfp->iseq);
- cfp->block_code = (void *)rb_gc_location((VALUE)cfp->block_code);
+ if (CFP_ZJIT_FRAME_P(cfp)) {
+ rb_zjit_jit_frame_update_references((zjit_jit_frame_t *)CFP_ZJIT_FRAME(cfp));
+ // block_code must always be relocated. For ISEQ frames, the JIT caller
+ // may have written it (gen_block_handler_specval) for passing blocks.
+ // For C frames, rb_iterate0 may have written an ifunc to block_code
+ // after the JIT pushed the frame. NULL is safe to pass to rb_gc_location.
+ cfp->block_code = (void *)rb_gc_location((VALUE)cfp->block_code);
+ }
+ else {
+ cfp->_iseq = (rb_iseq_t *)rb_gc_location((VALUE)cfp->_iseq);
+ cfp->block_code = (void *)rb_gc_location((VALUE)cfp->block_code);
+ }
if (!VM_ENV_LOCAL_P(ep)) {
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
@@ -3384,6 +3682,9 @@ rb_execution_context_update(rb_execution_context_t *ec)
}
ec->storage = rb_gc_location(ec->storage);
+
+ ec->gen_fields_cache.obj = rb_gc_location(ec->gen_fields_cache.obj);
+ ec->gen_fields_cache.fields_obj = rb_gc_location(ec->gen_fields_cache.fields_obj);
}
static enum rb_id_table_iterator_result
@@ -3404,17 +3705,27 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
rb_control_frame_t *cfp = ec->cfp;
rb_control_frame_t *limit_cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
- VM_ASSERT(sp == ec->cfp->sp);
- rb_gc_mark_vm_stack_values((long)(sp - p), p);
+ for (long i = 0; i < (long)(sp - p); i++) {
+ rb_gc_mark_movable(p[i]);
+ }
while (cfp != limit_cfp) {
const VALUE *ep = cfp->ep;
VM_ASSERT(!!VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED) == vm_ep_in_heap_p_(ec, ep));
rb_gc_mark_movable(cfp->self);
- rb_gc_mark_movable((VALUE)cfp->iseq);
+ rb_gc_mark_movable((VALUE)CFP_ISEQ(cfp));
+ // Mark block_code directly (not through rb_zjit_cfp_block_code)
+ // because rb_iterate0 may write a valid ifunc after JIT frame push.
rb_gc_mark_movable((VALUE)cfp->block_code);
+ if (VM_ENV_LOCAL_P(ep) && VM_ENV_BOXED_P(ep)) {
+ const rb_box_t *box = VM_ENV_BOX(ep);
+ if (BOX_USER_P(box)) {
+ rb_gc_mark_movable(box->box_object);
+ }
+ }
+
if (!VM_ENV_LOCAL_P(ep)) {
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
@@ -3433,8 +3744,8 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
/* mark machine stack */
if (ec->machine.stack_start && ec->machine.stack_end &&
- ec != GET_EC() /* marked for current ec at the first stage of marking */
- ) {
+ /* marked for current ec at the first stage of marking */
+ ec != rb_gc_get_ec()) {
rb_gc_mark_machine_context(ec);
}
@@ -3453,6 +3764,7 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
void rb_fiber_mark_self(rb_fiber_t *fib);
void rb_fiber_update_self(rb_fiber_t *fib);
void rb_threadptr_root_fiber_setup(rb_thread_t *th);
+void rb_root_fiber_obj_setup(rb_thread_t *th);
void rb_threadptr_root_fiber_release(rb_thread_t *th);
static void
@@ -3461,10 +3773,6 @@ thread_compact(void *ptr)
rb_thread_t *th = ptr;
th->self = rb_gc_location(th->self);
-
- if (!th->root_fiber) {
- rb_execution_context_update(th->ec);
- }
}
static void
@@ -3472,7 +3780,11 @@ thread_mark(void *ptr)
{
rb_thread_t *th = ptr;
RUBY_MARK_ENTER("thread");
- rb_fiber_mark_self(th->ec->fiber_ptr);
+
+ // ec is null when setting up the thread in rb_threadptr_root_fiber_setup
+ if (th->ec) {
+ rb_fiber_mark_self(th->ec->fiber_ptr);
+ }
/* mark ruby objects */
switch (th->invoke_type) {
@@ -3497,8 +3809,7 @@ thread_mark(void *ptr)
rb_gc_mark(th->top_wrapper);
if (th->root_fiber) rb_fiber_mark_self(th->root_fiber);
- RUBY_ASSERT(th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr));
- rb_gc_mark(th->stat_insn_usage);
+ RUBY_ASSERT(th->ec == NULL || th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr));
rb_gc_mark(th->last_status);
rb_gc_mark(th->locking_mutex);
rb_gc_mark(th->name);
@@ -3529,15 +3840,15 @@ thread_free(void *ptr)
ruby_xfree(th->specific_storage);
- rb_threadptr_root_fiber_release(th);
-
if (th->vm && th->vm->ractor.main_thread == th) {
RUBY_GC_INFO("MRI main thread\n");
}
else {
// ruby_xfree(th->nt);
// TODO: MN system collect nt, but without MN system it should be freed here.
- ruby_xfree(th);
+ if (!th->main_thread) {
+ ruby_xfree(th);
+ }
}
RUBY_FREE_LEAVE("thread");
@@ -3613,17 +3924,28 @@ rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
void
rb_ec_clear_vm_stack(rb_execution_context_t *ec)
{
+ // set cfp to NULL before clearing the stack in case `thread_profile_frames`
+ // gets called in this middle of `rb_ec_set_vm_stack` via signal handler.
+ ec->cfp = NULL;
rb_ec_set_vm_stack(ec, NULL, 0);
+}
- // Avoid dangling pointers:
- ec->cfp = NULL;
+void
+rb_ec_close(rb_execution_context_t *ec)
+{
+ // Fiber storage is not accessible from outside the running fiber, so it is safe to clear it here.
+ ec->storage = Qnil;
}
static void
th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
{
+ const rb_box_t *box = rb_current_box();
+
th->self = self;
+ ccan_list_head_init(&th->interrupt_exec_tasks);
+
rb_threadptr_root_fiber_setup(th);
/* All threads are blocking until a non-blocking fiber is scheduled */
@@ -3632,7 +3954,9 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
if (self == 0) {
size_t size = vm->default_params.thread_vm_stack_size / sizeof(VALUE);
- rb_ec_initialize_vm_stack(th->ec, ALLOC_N(VALUE, size), size);
+ VALUE *stack = ALLOC_N(VALUE, size);
+ rb_ec_initialize_vm_stack(th->ec, stack, size);
+ rb_thread_malloc_stack_set(th, stack, size);
}
else {
VM_ASSERT(th->ec->cfp == NULL);
@@ -3643,7 +3967,12 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
th->status = THREAD_RUNNABLE;
th->last_status = Qnil;
th->top_wrapper = 0;
- th->top_self = vm->top_self; // 0 while self == 0
+ if (box->top_self) {
+ th->top_self = box->top_self;
+ }
+ else {
+ th->top_self = 0;
+ }
th->value = Qundef;
th->ec->errinfo = Qnil;
@@ -3652,6 +3981,7 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
th->ec->local_storage_recursive_hash_for_trace = Qnil;
th->ec->storage = Qnil;
+ th->ec->ractor_id = rb_ractor_id(th->ractor);
#if OPT_CALL_THREADED_CODE
th->retval = Qundef;
@@ -3660,8 +3990,6 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
th->report_on_exception = vm->thread_report_on_exception;
th->ext_config.ractor_safe = true;
- ccan_list_head_init(&th->interrupt_exec_tasks);
-
#if USE_RUBY_DEBUG_LOG
static rb_atomic_t thread_serial = 1;
th->serial = RUBY_ATOMIC_FETCH_ADD(thread_serial, 1);
@@ -3677,6 +4005,7 @@ rb_thread_alloc(VALUE klass)
rb_thread_t *target_th = rb_thread_ptr(self);
target_th->ractor = GET_RACTOR();
th_init(target_th, self, target_th->vm = GET_VM());
+ rb_root_fiber_obj_setup(target_th);
return self;
}
@@ -3948,9 +4277,7 @@ Init_VM(void)
/* FrozenCore (hidden) */
fcore = rb_class_new(rb_cBasicObject);
rb_set_class_path(fcore, rb_cRubyVM, "FrozenCore");
- rb_vm_register_global_object(rb_class_path_cached(fcore));
- RB_FL_UNSET_RAW(fcore, T_MASK);
- RB_FL_SET_RAW(fcore, T_ICLASS);
+ rb_vm_register_global_object(rb_mod_name(fcore));
klass = rb_singleton_class(fcore);
rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
@@ -4226,8 +4553,10 @@ Init_VM(void)
th->top_wrapper = 0;
th->top_self = rb_vm_top_self();
+ rb_root_fiber_obj_setup(th);
+
rb_vm_register_global_object((VALUE)iseq);
- th->ec->cfp->iseq = iseq;
+ th->ec->cfp->_iseq = iseq;
th->ec->cfp->pc = ISEQ_BODY(iseq)->iseq_encoded;
th->ec->cfp->self = th->top_self;
@@ -4263,42 +4592,44 @@ rb_vm_set_progname(VALUE filename)
--cfp;
filename = rb_str_new_frozen(filename);
- rb_iseq_pathobj_set(cfp->iseq, filename, rb_iseq_realpath(cfp->iseq));
+ rb_iseq_pathobj_set(CFP_ISEQ(cfp), filename, rb_iseq_realpath(CFP_ISEQ(cfp)));
}
extern const struct st_hash_type rb_fstring_hash_type;
+static rb_vm_t _vm;
+static rb_thread_t _main_thread = {
+ .vm = &_vm,
+ .main_thread = 1,
+};
+
void
Init_BareVM(void)
{
/* VM bootstrap: phase 1 */
- rb_vm_t *vm = ruby_mimcalloc(1, sizeof(*vm));
- rb_thread_t *th = ruby_mimcalloc(1, sizeof(*th));
- if (!vm || !th) {
- fputs("[FATAL] failed to allocate memory\n", stderr);
- exit(EXIT_FAILURE);
- }
+ rb_vm_t *vm = &_vm;
+ rb_thread_t *th = &_main_thread;
// setup the VM
vm_init2(vm);
- rb_vm_postponed_job_queue_init(vm);
ruby_current_vm_ptr = vm;
rb_objspace_alloc();
- vm->negative_cme_table = rb_id_table_create(16);
- vm->overloaded_cme_table = st_init_numtable();
- vm->constant_cache = rb_id_table_create(0);
- vm->unused_block_warning_table = st_init_numtable();
+ rb_id_table_init(&vm->negative_cme_table, 16);
+ st_init_existing_numtable_with_size(&vm->overloaded_cme_table, 0);
+ st_init_existing_strtable_with_size(&vm->static_ext_inits, 0);
+ set_init_embedded_numtable_with_size(&vm->unused_block_warning_table, 0);
+ vm->global_hooks.type = hook_list_type_global;
// setup main thread
th->nt = ZALLOC(struct rb_native_thread);
- th->vm = vm;
th->ractor = vm->ractor.main_ractor = rb_ractor_main_alloc();
Init_native_thread(th);
rb_jit_cont_init();
th_init(th, 0, vm);
rb_ractor_set_current_ec(th->ractor, th->ec);
+
/* n.b. native_main_thread_stack_top is set by the INIT_STACK macro */
ruby_thread_init_stack(th, native_main_thread_stack_top);
@@ -4310,7 +4641,8 @@ Init_BareVM(void)
vm_opt_mid_table = st_init_numtable();
#ifdef RUBY_THREAD_WIN32_H
- rb_native_cond_initialize(&vm->ractor.sync.barrier_cond);
+ rb_native_cond_initialize(&vm->ractor.sync.barrier_complete_cond);
+ rb_native_cond_initialize(&vm->ractor.sync.barrier_release_cond);
#endif
}
@@ -4421,8 +4753,7 @@ rb_vm_register_global_object(VALUE obj)
default:
break;
}
- RB_VM_LOCK_ENTER();
- {
+ RB_VM_LOCKING() {
VALUE list = GET_VM()->mark_object_ary;
VALUE head = pin_array_list_append(list, obj);
if (head != list) {
@@ -4430,9 +4761,10 @@ rb_vm_register_global_object(VALUE obj)
}
RB_GC_GUARD(obj);
}
- RB_VM_LOCK_LEAVE();
}
+VALUE rb_cc_refinement_set_create(void);
+
void
Init_vm_objects(void)
{
@@ -4440,18 +4772,23 @@ Init_vm_objects(void)
/* initialize mark object array, hash */
vm->mark_object_ary = pin_array_list_new(Qnil);
- vm->loading_table = st_init_strtable();
- vm->ci_table = st_init_table(&vm_ci_hashtype);
- vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000);
+ st_init_existing_table_with_size(&vm->ci_table, &vm_ci_hashtype, 0);
+ vm->cc_refinement_set = rb_cc_refinement_set_create();
}
+// Whether JIT is enabled or not, we need to load/undef `#with_jit` for other builtins.
+#include "jit_hook.rbinc"
+#include "jit_undef.rbinc"
+
// Stub for builtin function when not building YJIT units
#if !USE_YJIT
void Init_builtin_yjit(void) {}
#endif
-// Whether YJIT is enabled or not, we load yjit_hook.rb to remove Kernel#with_yjit.
-#include "yjit_hook.rbinc"
+// Stub for builtin function when not building ZJIT units
+#if !USE_ZJIT
+void Init_builtin_zjit(void) {}
+#endif
/* top self */
@@ -4464,17 +4801,20 @@ main_to_s(VALUE obj)
VALUE
rb_vm_top_self(void)
{
- return GET_VM()->top_self;
+ const rb_box_t *box = rb_current_box();
+ VM_ASSERT(box);
+ VM_ASSERT(box->top_self);
+ return box->top_self;
}
void
Init_top_self(void)
{
rb_vm_t *vm = GET_VM();
-
- vm->top_self = rb_obj_alloc(rb_cObject);
- rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0);
- rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s");
+ vm->root_box = (rb_box_t *)rb_root_box();
+ vm->root_box->top_self = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(vm->root_box->top_self, "to_s", main_to_s, 0);
+ rb_define_alias(rb_singleton_class(vm->root_box->top_self), "inspect", "to_s");
}
VALUE *
@@ -4504,12 +4844,6 @@ VALUE rb_insn_operand_intern(const rb_iseq_t *iseq,
VALUE insn, int op_no, VALUE op,
int len, size_t pos, VALUE *pnop, VALUE child);
-st_table *
-rb_vm_fstring_table(void)
-{
- return GET_VM()->frozen_strings;
-}
-
#if VM_COLLECT_USAGE_DETAILS
#define HASH_ASET(h, k, v) rb_hash_aset((h), (st_data_t)(k), (st_data_t)(v))
@@ -4590,7 +4924,7 @@ vm_analysis_operand(int insn, int n, VALUE op)
HASH_ASET(ihash, INT2FIX(n), ophash);
}
/* intern */
- valstr = rb_insn_operand_intern(GET_EC()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
+ valstr = rb_insn_operand_intern(CFP_ISEQ(GET_EC()->cfp), insn, n, op, 0, 0, 0, 0);
/* set count */
if (NIL_P(cv = rb_hash_aref(ophash, valstr))) {
@@ -4792,7 +5126,7 @@ vm_collect_usage_operand(int insn, int n, VALUE op)
if (RUBY_DTRACE_INSN_OPERAND_ENABLED()) {
VALUE valstr;
- valstr = rb_insn_operand_intern(GET_EC()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
+ valstr = rb_insn_operand_intern(CFP_ISEQ(GET_EC()->cfp), insn, n, op, 0, 0, 0, 0);
RUBY_DTRACE_INSN_OPERAND(RSTRING_PTR(valstr), rb_insns_name(insn));
RB_GC_GUARD(valstr);
diff --git a/vm_args.c b/vm_args.c
index a84540c61b..3d67c6540a 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -1,6 +1,6 @@
/**********************************************************************
- vm_args.c - process method call arguments.
+ vm_args.c - process method call arguments. Included into vm.c.
$Author$
@@ -8,10 +8,12 @@
**********************************************************************/
-NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc));
-NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc));
-NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys));
+NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc));
+NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const int miss_argc, const int min_argc, const int max_argc));
+NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const char *error, const VALUE keys));
VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */
+static VALUE set_error_backtrace(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc);
+
static VALUE method_missing(rb_execution_context_t *ec, VALUE obj, ID id, int argc, const VALUE *argv,
enum method_missing_reason call_status, int kw_splat);
const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
@@ -318,10 +320,8 @@ args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const pas
return FALSE;
}
-#define KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */
-
static void
-args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
+args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
VALUE *const locals)
{
@@ -345,7 +345,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
}
}
- if (missing) argument_kw_error(ec, iseq, "missing", missing);
+ if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
for (di=0; i<key_num; i++, di++) {
if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
@@ -355,7 +355,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
if (UNDEF_P(default_values[di])) {
locals[i] = Qnil;
- if (LIKELY(i < KW_SPECIFIED_BITS_MAX)) {
+ if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) {
unspecified_bits |= 0x01 << di;
}
else {
@@ -364,7 +364,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
int j;
unspecified_bits_value = rb_hash_new();
- for (j=0; j<KW_SPECIFIED_BITS_MAX; j++) {
+ for (j=0; j<VM_KW_SPECIFIED_BITS_MAX; j++) {
if (unspecified_bits & (0x01 << j)) {
rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue);
}
@@ -386,7 +386,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
else {
if (found != passed_keyword_len) {
VALUE keys = make_unknown_kw_hash(passed_keywords, passed_keyword_len, passed_values);
- argument_kw_error(ec, iseq, "unknown", keys);
+ argument_kw_error(ec, iseq, cme, "unknown", keys);
}
}
@@ -397,7 +397,7 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
}
static void
-args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
+args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
VALUE keyword_hash, VALUE *const locals, bool remove_hash_value)
{
const ID *acceptable_keywords = ISEQ_BODY(iseq)->param.keyword->table;
@@ -430,7 +430,7 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
}
}
- if (missing) argument_kw_error(ec, iseq, "missing", missing);
+ if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
for (di=0; i<key_num; i++, di++) {
VALUE key = ID2SYM(acceptable_keywords[i]);
@@ -450,7 +450,7 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
if (UNDEF_P(default_values[di])) {
locals[i] = Qnil;
- if (LIKELY(i < KW_SPECIFIED_BITS_MAX)) {
+ if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) {
unspecified_bits |= 0x01 << di;
}
else {
@@ -459,7 +459,7 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
int j;
unspecified_bits_value = rb_hash_new();
- for (j=0; j<KW_SPECIFIED_BITS_MAX; j++) {
+ for (j=0; j<VM_KW_SPECIFIED_BITS_MAX; j++) {
if (unspecified_bits & (0x01 << j)) {
rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue);
}
@@ -485,11 +485,11 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
* This is simpler than writing code to check which entries in the hash do not match.
* This will raise an exception, so the additional performance impact shouldn't be material.
*/
- args_setup_kw_parameters_from_kwsplat(ec, iseq, rb_hash_dup(keyword_hash), locals, true);
+ args_setup_kw_parameters_from_kwsplat(ec, iseq, cme, rb_hash_dup(keyword_hash), locals, true);
}
}
else if (!RHASH_EMPTY_P(keyword_hash)) {
- argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
+ argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
}
}
@@ -607,6 +607,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
VALUE splat_flagged_keyword_hash = 0;
VALUE converted_keyword_hash = 0;
VALUE rest_last = 0;
+ const rb_callable_method_entry_t *cme = calling->cc ? vm_cc_cme(calling->cc) : NULL;
vm_check_canary(ec, orig_sp);
/*
@@ -639,12 +640,26 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
given_argc == ISEQ_BODY(iseq)->param.lead_num + (kw_flag ? 2 : 1) &&
!ISEQ_BODY(iseq)->param.flags.has_opt &&
!ISEQ_BODY(iseq)->param.flags.has_post &&
- !ISEQ_BODY(iseq)->param.flags.ruby2_keywords &&
- (!kw_flag ||
- !ISEQ_BODY(iseq)->param.flags.has_kw ||
- !ISEQ_BODY(iseq)->param.flags.has_kwrest ||
- !ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg)) {
- args->rest_dupped = true;
+ !ISEQ_BODY(iseq)->param.flags.ruby2_keywords) {
+ if (kw_flag) {
+ if (ISEQ_BODY(iseq)->param.flags.has_kw ||
+ ISEQ_BODY(iseq)->param.flags.has_kwrest) {
+ args->rest_dupped = true;
+ }
+ else if (kw_flag & VM_CALL_KW_SPLAT) {
+ VALUE kw_hash = locals[args->argc - 1];
+ if (kw_hash == Qnil ||
+ (RB_TYPE_P(kw_hash, T_HASH) && RHASH_EMPTY_P(kw_hash))) {
+ args->rest_dupped = true;
+ }
+ }
+
+ }
+ else if (!ISEQ_BODY(iseq)->param.flags.has_kw &&
+ !ISEQ_BODY(iseq)->param.flags.has_kwrest &&
+ !ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg) {
+ args->rest_dupped = true;
+ }
}
}
@@ -861,7 +876,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
args_extend(args, min_argc);
}
else {
- argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
+ argument_arity_error(ec, iseq, cme, given_argc, min_argc, max_argc);
}
}
@@ -872,7 +887,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
given_argc = max_argc;
}
else {
- argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
+ argument_arity_error(ec, iseq, cme, given_argc, min_argc, max_argc);
}
}
@@ -896,6 +911,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
if (ISEQ_BODY(iseq)->param.flags.has_rest) {
if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.anon_rest && args->argc == 0 && !args->rest && !ISEQ_BODY(iseq)->param.flags.has_post)) {
*(locals + ISEQ_BODY(iseq)->param.rest_start) = args->rest = rb_cArray_empty_frozen;
+ args->rest_index = 0;
}
else {
args_setup_rest_parameter(args, locals + ISEQ_BODY(iseq)->param.rest_start);
@@ -917,7 +933,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
if (args->kw_argv != NULL) {
const struct rb_callinfo_kwarg *kw_arg = args->kw_arg;
- args_setup_kw_parameters(ec, iseq, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
+ args_setup_kw_parameters(ec, iseq, cme, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
}
else if (!NIL_P(keyword_hash)) {
bool remove_hash_value = false;
@@ -925,7 +941,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
keyword_hash = check_kwrestarg(keyword_hash, &kw_flag);
remove_hash_value = true;
}
- args_setup_kw_parameters_from_kwsplat(ec, iseq, keyword_hash, klocals, remove_hash_value);
+ args_setup_kw_parameters_from_kwsplat(ec, iseq, cme, keyword_hash, klocals, remove_hash_value);
}
else {
#if VM_CHECK_MODE > 0
@@ -940,7 +956,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
VM_ASSERT(args_argc(args) == 1);
}
#endif
- args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
+ args_setup_kw_parameters(ec, iseq, cme, NULL, 0, NULL, klocals);
}
}
else if (ISEQ_BODY(iseq)->param.flags.has_kwrest) {
@@ -948,10 +964,18 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
kw_flag, ISEQ_BODY(iseq)->param.flags.anon_kwrest);
}
else if (!NIL_P(keyword_hash) && RHASH_SIZE(keyword_hash) > 0 && arg_setup_type == arg_setup_method) {
- argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
+ argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
}
- if (ISEQ_BODY(iseq)->param.flags.has_block) {
+ if (ISEQ_BODY(iseq)->param.flags.accepts_no_block) {
+ VALUE given_block;
+ args_setup_block_parameter(ec, calling, &given_block);
+ if (!NIL_P(given_block)) {
+ VALUE exc = rb_exc_new_cstr(rb_eArgError, "no block accepted");
+ rb_exc_raise(set_error_backtrace(ec, iseq, cme, exc));
+ }
+ }
+ else if (ISEQ_BODY(iseq)->param.flags.has_block) {
if (ISEQ_BODY(iseq)->local_iseq == iseq) {
/* Do nothing */
}
@@ -973,18 +997,17 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
return opt_pc;
}
-static void
-raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc)
+static VALUE
+set_error_backtrace(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
{
VALUE at;
if (iseq) {
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL, Qnil /* self */,
- VM_BLOCK_HANDLER_NONE /* specval*/, Qfalse /* me or cref */,
+ VM_BLOCK_HANDLER_NONE /* specval*/, (VALUE) cme /* me or cref */,
ISEQ_BODY(iseq)->iseq_encoded,
ec->cfp->sp, 0, 0 /* stack_max */);
at = rb_ec_backtrace_object(ec);
- rb_backtrace_use_iseq_first_lineno_for_last_location(at);
rb_vm_pop_frame(ec);
}
else {
@@ -993,11 +1016,18 @@ raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VA
rb_ivar_set(exc, idBt_locations, at);
rb_exc_set_backtrace(exc, at);
+ return exc;
+}
+
+static void
+raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
+{
+ set_error_backtrace(ec, iseq, cme, exc);
rb_exc_raise(exc);
}
static void
-argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc)
+argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const int miss_argc, const int min_argc, const int max_argc)
{
VALUE exc = rb_arity_error_new(miss_argc, min_argc, max_argc);
if (ISEQ_BODY(iseq)->param.flags.has_kw) {
@@ -1018,13 +1048,13 @@ argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const in
RSTRING_PTR(mesg)[RSTRING_LEN(mesg)-1] = ')';
}
}
- raise_argument_error(ec, iseq, exc);
+ raise_argument_error(ec, iseq, cme, exc);
}
static void
-argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys)
+argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const char *error, const VALUE keys)
{
- raise_argument_error(ec, iseq, rb_keyword_error_new(error, keys));
+ raise_argument_error(ec, iseq, cme, rb_keyword_error_new(error, keys));
}
static VALUE
@@ -1044,9 +1074,12 @@ vm_to_proc(VALUE proc)
}
if (NIL_P(b) || !rb_obj_is_proc(b)) {
- rb_raise(rb_eTypeError,
- "wrong argument type %s (expected Proc)",
- rb_obj_classname(proc));
+ if (me) {
+ rb_cant_convert_invalid_return(proc, "Proc", "to_proc", b);
+ }
+ else {
+ rb_no_implicit_conversion(proc, "Proc");
+ }
}
return b;
}
diff --git a/vm_backtrace.c b/vm_backtrace.c
index 26e0a6fb76..85a0658612 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -13,11 +13,13 @@
#include "internal.h"
#include "internal/class.h"
#include "internal/error.h"
+#include "internal/object.h"
#include "internal/vm.h"
#include "iseq.h"
#include "ruby/debug.h"
#include "ruby/encoding.h"
#include "vm_core.h"
+#include "zjit.h"
static VALUE rb_cBacktrace;
static VALUE rb_cBacktraceLocation;
@@ -44,7 +46,7 @@ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
}
if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
#ifdef USE_ISEQ_NODE_ID
- if (node_id) *node_id = -1;
+ if (node_id) *node_id = ISEQ_BODY(iseq)->location.node_id;
#endif
return 1;
}
@@ -101,9 +103,9 @@ calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
int
rb_vm_get_sourceline(const rb_control_frame_t *cfp)
{
- if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
- const rb_iseq_t *iseq = cfp->iseq;
- int line = calc_lineno(iseq, cfp->pc);
+ if (VM_FRAME_RUBYFRAME_P(cfp) && CFP_ISEQ(cfp)) {
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
+ int line = calc_lineno(iseq, CFP_PC(cfp));
if (line != 0) {
return line;
}
@@ -262,6 +264,15 @@ retry:
}
}
+static bool
+is_internal_location(const rb_iseq_t *iseq)
+{
+ static const char prefix[] = "<internal:";
+ const size_t prefix_len = sizeof(prefix) - 1;
+ VALUE file = rb_iseq_path(iseq);
+ return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
+}
+
// Return true if a given location is a C method or supposed to behave like one.
static inline bool
location_cfunc_p(rb_backtrace_location_t *loc)
@@ -272,7 +283,7 @@ location_cfunc_p(rb_backtrace_location_t *loc)
case VM_METHOD_TYPE_CFUNC:
return true;
case VM_METHOD_TYPE_ISEQ:
- return rb_iseq_attr_p(loc->cme->def->body.iseq.iseqptr, BUILTIN_ATTR_C_TRACE);
+ return is_internal_location(loc->cme->def->body.iseq.iseqptr);
default:
return false;
}
@@ -391,7 +402,7 @@ location_path_m(VALUE self)
static int
location_node_id(rb_backtrace_location_t *loc)
{
- if (loc->iseq && loc->pc) {
+ if (loc->iseq) {
return calc_node_id(loc->iseq, loc->pc);
}
return -1;
@@ -452,6 +463,7 @@ location_format(VALUE file, int lineno, VALUE name)
else {
rb_str_catf(s, "'%s'", RSTRING_PTR(name));
}
+ RB_GC_GUARD(name);
return s;
}
@@ -566,14 +578,6 @@ rb_backtrace_p(VALUE obj)
}
static VALUE
-backtrace_alloc(VALUE klass)
-{
- rb_backtrace_t *bt;
- VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
- return obj;
-}
-
-static VALUE
backtrace_alloc_capa(long num_frames, rb_backtrace_t **backtrace)
{
size_t memsize = offsetof(rb_backtrace_t, backtrace) + num_frames * sizeof(rb_backtrace_location_t);
@@ -605,27 +609,18 @@ backtrace_size(const rb_execution_context_t *ec)
}
static bool
-is_internal_location(const rb_control_frame_t *cfp)
-{
- static const char prefix[] = "<internal:";
- const size_t prefix_len = sizeof(prefix) - 1;
- VALUE file = rb_iseq_path(cfp->iseq);
- return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
-}
-
-static bool
is_rescue_or_ensure_frame(const rb_control_frame_t *cfp)
{
- enum rb_iseq_type type = ISEQ_BODY(cfp->iseq)->type;
+ enum rb_iseq_type type = ISEQ_BODY(CFP_ISEQ(cfp))->type;
return type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE;
}
static void
-bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc)
+bt_backpatch_loc(unsigned long backpatch_counter, rb_backtrace_location_t *loc, const rb_iseq_t *iseq, const VALUE *pc)
{
- for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
- cfunc_loc->iseq = iseq;
- cfunc_loc->pc = pc;
+ for (; backpatch_counter > 0; backpatch_counter--, loc--) {
+ loc->iseq = iseq;
+ loc->pc = pc;
}
}
@@ -648,7 +643,7 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram
rb_backtrace_t *bt = NULL;
VALUE btobj = Qnil;
rb_backtrace_location_t *loc = NULL;
- unsigned long cfunc_counter = 0;
+ unsigned long backpatch_counter = 0;
bool skip_next_frame = FALSE;
// In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
@@ -686,31 +681,46 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram
}
for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
- if (cfp->iseq) {
- if (cfp->pc) {
+ if (CFP_ISEQ(cfp)) {
+ if (CFP_PC(cfp)) {
if (start_frame > 0) {
start_frame--;
}
- else if (!(skip_internal && is_internal_location(cfp))) {
+ else {
+ bool internal = is_internal_location(CFP_ISEQ(cfp));
+ if (skip_internal && internal) continue;
if (!skip_next_frame) {
- const rb_iseq_t *iseq = cfp->iseq;
- const VALUE *pc = cfp->pc;
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
+ const VALUE *pc = CFP_PC(cfp);
+ if (internal && backpatch_counter > 0) {
+ // To keep only one internal frame, discard the previous backpatch frames
+ bt->backtrace_size -= backpatch_counter;
+ backpatch_counter = 0;
+ }
loc = &bt->backtrace[bt->backtrace_size++];
RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
- // Ruby methods with `Primitive.attr! :c_trace` should behave like C methods
- if (rb_iseq_attr_p(cfp->iseq, BUILTIN_ATTR_C_TRACE)) {
- loc->iseq = NULL;
- loc->pc = NULL;
- cfunc_counter++;
+ // internal frames (`<internal:...>`) should behave like C methods
+ if (internal) {
+ // Typically, these iseq and pc are not needed because they will be backpatched later.
+ // But when the call stack starts with an internal frame (i.e., prelude.rb),
+ // they will be used to show the `<internal:...>` location.
+ RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
+ loc->pc = pc;
+ backpatch_counter++;
}
else {
RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
- loc->pc = pc;
- bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc);
+ if ((VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY) {
+ loc->pc = NULL; // means location.first_lineno
+ }
+ else {
+ loc->pc = pc;
+ }
+ bt_backpatch_loc(backpatch_counter, loc-1, iseq, pc);
if (do_yield) {
- bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj);
+ bt_yield_loc(loc - backpatch_counter, backpatch_counter+1, btobj);
}
- cfunc_counter = 0;
+ backpatch_counter = 0;
}
}
skip_next_frame = is_rescue_or_ensure_frame(cfp);
@@ -727,21 +737,21 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram
RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
loc->iseq = NULL;
loc->pc = NULL;
- cfunc_counter++;
+ backpatch_counter++;
}
}
}
// When a backtrace entry corresponds to a method defined in C (e.g. rb_define_method), the reported file:line
// is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here.
- if (cfunc_counter > 0) {
+ if (backpatch_counter > 0) {
for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
- if (cfp->iseq && cfp->pc && !(skip_internal && is_internal_location(cfp))) {
+ if (CFP_ISEQ(cfp) && CFP_PC(cfp) && !(skip_internal && is_internal_location(CFP_ISEQ(cfp)))) {
VM_ASSERT(!skip_next_frame); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc
- bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc);
- RB_OBJ_WRITTEN(btobj, Qundef, cfp->iseq);
+ bt_backpatch_loc(backpatch_counter, loc, CFP_ISEQ(cfp), CFP_PC(cfp));
+ RB_OBJ_WRITTEN(btobj, Qundef, CFP_ISEQ(cfp));
if (do_yield) {
- bt_yield_loc(loc - cfunc_counter, cfunc_counter, btobj);
+ bt_yield_loc(loc - backpatch_counter + 1, backpatch_counter, btobj);
}
break;
}
@@ -803,22 +813,6 @@ rb_backtrace_to_str_ary(VALUE self)
return bt->strary;
}
-void
-rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
-{
- rb_backtrace_t *bt;
- rb_backtrace_location_t *loc;
-
- TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
- VM_ASSERT(bt->backtrace_size > 0);
-
- loc = &bt->backtrace[0];
-
- VM_ASSERT(!loc->cme || loc->cme->def->type == VM_METHOD_TYPE_ISEQ);
-
- loc->pc = NULL; // means location.first_lineno
-}
-
static VALUE
location_create(rb_backtrace_location_t *srcloc, void *btobj)
{
@@ -858,7 +852,7 @@ rb_backtrace_to_location_ary(VALUE self)
VALUE
rb_location_ary_to_backtrace(VALUE ary)
{
- if (!RB_TYPE_P(ary, T_ARRAY) || !rb_frame_info_p(RARRAY_AREF(ary, 0))) {
+ if (!RB_TYPE_P(ary, T_ARRAY) || RARRAY_LEN(ary) == 0 || !rb_frame_info_p(RARRAY_AREF(ary, 0))) {
return Qfalse;
}
@@ -961,6 +955,47 @@ backtrace_limit(VALUE self)
return LONG2NUM(rb_backtrace_length_limit);
}
+/* :nodoc: */
+static VALUE
+backtrace_clone(VALUE self)
+{
+ rb_backtrace_t *bt;
+ TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
+
+ rb_backtrace_t *other_bt;
+ VALUE clone = backtrace_alloc_capa(bt->backtrace_size, &other_bt);
+
+ rb_obj_clone_setup(self, clone, Qfalse);
+
+ return clone;
+}
+
+/* :nodoc: */
+static VALUE
+backtrace_dup(VALUE self)
+{
+ rb_notimplement();
+
+ UNREACHABLE_RETURN(Qnil);
+}
+
+/* :nodoc: */
+static VALUE
+backtrace_initialize_copy(VALUE self, VALUE original)
+{
+ rb_backtrace_t *bt;
+ TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
+
+ rb_backtrace_t *original_bt;
+ TypedData_Get_Struct(original, rb_backtrace_t, &backtrace_data_type, original_bt);
+
+ bt->backtrace_size = original_bt->backtrace_size;
+ MEMCPY(bt->backtrace, original_bt->backtrace, rb_backtrace_location_t, original_bt->backtrace_size);
+ rb_gc_writebarrier_remember(self);
+
+ return Qnil;
+}
+
VALUE
rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
{
@@ -1019,8 +1054,8 @@ backtrace_each(const rb_execution_context_t *ec,
/* SDR(); */
for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
/* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
- if (cfp->iseq) {
- if (cfp->pc) {
+ if (CFP_ISEQ(cfp)) {
+ if (CFP_PC(cfp)) {
iter_iseq(arg, cfp);
}
}
@@ -1052,8 +1087,8 @@ oldbt_init(void *ptr, size_t dmy)
static void
oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
{
- const rb_iseq_t *iseq = cfp->iseq;
- const VALUE *pc = cfp->pc;
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
+ const VALUE *pc = CFP_PC(cfp);
struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
VALUE file = arg->filename = rb_iseq_path(iseq);
VALUE name = ISEQ_BODY(iseq)->location.label;
@@ -1405,6 +1440,14 @@ each_caller_location(int argc, VALUE *argv, VALUE _)
return Qnil;
}
+static VALUE
+backtrace_no_allocator(VALUE klass)
+{
+ rb_notimplement();
+
+ UNREACHABLE_RETURN(Qnil);
+}
+
/* called from Init_vm() in vm.c */
void
Init_vm_backtrace(void)
@@ -1415,11 +1458,18 @@ Init_vm_backtrace(void)
* settings of the current session.
*/
rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
- rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
- rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
+
+ // Can't undefine the allocator, as it's needed as a key by Marshal
+ rb_define_alloc_func(rb_cBacktrace, backtrace_no_allocator);
rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
+
+ rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
rb_define_singleton_method(rb_cBacktrace, "limit", backtrace_limit, 0);
+ rb_define_method(rb_cBacktrace, "clone", backtrace_clone, 0);
+ rb_define_method(rb_cBacktrace, "dup", backtrace_dup, 0);
+ rb_define_method(rb_cBacktrace, "initialize_copy", backtrace_initialize_copy, 1);
+
/*
* An object representation of a stack frame, initialized by
* Kernel#caller_locations.
@@ -1493,9 +1543,8 @@ RUBY_SYMBOL_EXPORT_END
struct rb_debug_inspector_struct {
rb_execution_context_t *ec;
rb_control_frame_t *cfp;
- VALUE backtrace;
VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
- long backtrace_size;
+ VALUE raw_backtrace;
};
enum {
@@ -1504,18 +1553,22 @@ enum {
CALLER_BINDING_BINDING,
CALLER_BINDING_ISEQ,
CALLER_BINDING_CFP,
+ CALLER_BINDING_LOC,
CALLER_BINDING_DEPTH,
};
struct collect_caller_bindings_data {
VALUE ary;
const rb_execution_context_t *ec;
+ VALUE btobj;
+ rb_backtrace_t *bt;
};
static void
-collect_caller_bindings_init(void *arg, size_t size)
+collect_caller_bindings_init(void *arg, size_t num_frames)
{
- /* */
+ struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
+ data->btobj = backtrace_alloc_capa(num_frames, &data->bt);
}
static VALUE
@@ -1547,12 +1600,21 @@ collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
{
struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
VALUE frame = rb_ary_new2(6);
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
- rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
+ rb_ary_store(frame, CALLER_BINDING_ISEQ, iseq ? (VALUE)iseq : Qnil);
rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
+
+ rb_backtrace_location_t *loc = &data->bt->backtrace[data->bt->backtrace_size++];
+ RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
+ RB_OBJ_WRITE(data->btobj, &loc->iseq, iseq);
+ loc->pc = CFP_PC(cfp);
+ VALUE vloc = location_create(loc, (void *)data->btobj);
+ rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
+
rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
rb_ary_push(data->ary, frame);
@@ -1569,6 +1631,14 @@ collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
+
+ rb_backtrace_location_t *loc = &data->bt->backtrace[data->bt->backtrace_size++];
+ RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
+ loc->iseq = NULL;
+ loc->pc = NULL;
+ VALUE vloc = location_create(loc, (void *)data->btobj);
+ rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
+
rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
rb_ary_push(data->ary, frame);
@@ -1617,15 +1687,19 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
rb_execution_context_t *ec = GET_EC();
enum ruby_tag_type state;
volatile VALUE MAYBE_UNUSED(result);
+ int i;
/* escape all env to heap */
rb_vm_stack_to_heap(ec);
dbg_context.ec = ec;
dbg_context.cfp = dbg_context.ec->cfp;
- dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, FALSE);
- dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
dbg_context.contexts = collect_caller_bindings(ec);
+ dbg_context.raw_backtrace = rb_ary_new();
+ for (i=0; i<RARRAY_LEN(dbg_context.contexts); i++) {
+ VALUE frame = rb_ary_entry(dbg_context.contexts, i);
+ rb_ary_push(dbg_context.raw_backtrace, rb_ary_entry(frame, CALLER_BINDING_LOC));
+ }
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
@@ -1645,7 +1719,7 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
static VALUE
frame_get(const rb_debug_inspector_t *dc, long index)
{
- if (index < 0 || index >= dc->backtrace_size) {
+ if (index < 0 || index >= RARRAY_LEN(dc->contexts)) {
rb_raise(rb_eArgError, "no such frame");
}
return rb_ary_entry(dc->contexts, index);
@@ -1698,7 +1772,7 @@ rb_debug_inspector_current_depth(void)
VALUE
rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
{
- return dc->backtrace;
+ return dc->raw_backtrace;
}
static int
@@ -1722,38 +1796,48 @@ thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *b
end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
for (i=0; i<limit && cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
- if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc != 0) {
+ if (VM_FRAME_RUBYFRAME_P_UNCHECKED(cfp) && CFP_PC(cfp)) {
if (start > 0) {
start--;
continue;
}
/* record frame info */
- cme = rb_vm_frame_method_entry(cfp);
+ cme = rb_vm_frame_method_entry_unchecked(cfp);
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
buff[i] = (VALUE)cme;
}
else {
- buff[i] = (VALUE)cfp->iseq;
+ buff[i] = (VALUE)iseq;
}
if (lines) {
- // The topmost frame may not have an updated PC because the JIT
- // may not have set one. The JIT compiler will update the PC
- // before entering a new function (so that `caller` will work),
- // so only the topmost frame could possibly have an out of date PC
- if (cfp == top && cfp->jit_return) {
+ const VALUE *pc = CFP_PC(cfp);
+ VALUE *iseq_encoded = ISEQ_BODY(iseq)->iseq_encoded;
+ VALUE *pc_end = iseq_encoded + ISEQ_BODY(iseq)->iseq_size;
+
+ // The topmost frame may have an invalid PC because the JIT
+ // may leave it uninitialized for speed. JIT code must update the PC
+ // before entering a non-leaf method (so that `caller` will work),
+ // so only the topmost frame could possibly have an out-of-date PC.
+ // ZJIT doesn't set `cfp->jit_return`, so it's not a reliable signal.
+ // TODO(zjit): lightweight frames potentially makes more than
+ // the top most frame invalid.
+ //
+ // Avoid passing invalid PC to calc_lineno() to avoid crashing.
+ if (cfp == top && (pc < iseq_encoded || pc > pc_end)) {
lines[i] = 0;
}
else {
- lines[i] = calc_lineno(cfp->iseq, cfp->pc);
+ lines[i] = calc_lineno(iseq, pc);
}
}
i++;
}
else {
- cme = rb_vm_frame_method_entry(cfp);
+ cme = rb_vm_frame_method_entry_unchecked(cfp);
if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
if (start > 0) {
start--;
diff --git a/vm_callinfo.h b/vm_callinfo.h
index 399cd8d746..9a6c69deae 100644
--- a/vm_callinfo.h
+++ b/vm_callinfo.h
@@ -47,7 +47,7 @@ enum vm_call_flag_bits {
struct rb_callinfo_kwarg {
int keyword_len;
- int references;
+ rb_atomic_t references;
VALUE keywords[];
};
@@ -66,8 +66,8 @@ struct rb_callinfo {
VALUE flags;
const struct rb_callinfo_kwarg *kwarg;
VALUE mid;
- VALUE flag;
- VALUE argc;
+ unsigned int flag;
+ unsigned int argc;
};
#if !defined(USE_EMBED_CI) || (USE_EMBED_CI+0)
@@ -146,7 +146,7 @@ vm_ci_flag(const struct rb_callinfo *ci)
return (unsigned int)((((VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
}
else {
- return (unsigned int)ci->flag;
+ return ci->flag;
}
}
@@ -157,7 +157,7 @@ vm_ci_argc(const struct rb_callinfo *ci)
return (unsigned int)((((VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
}
else {
- return (unsigned int)ci->argc;
+ return ci->argc;
}
}
@@ -279,9 +279,7 @@ struct rb_callcache {
const VALUE flags;
/* inline cache: key */
- const VALUE klass; // should not mark it because klass can not be free'd
- // because of this marking. When klass is collected,
- // cc will be cleared (cc->klass = 0) at vm_ccs_free().
+ const VALUE klass; // Weak reference. When klass is collected, `cc->klass = Qundef`.
/* inline cache: values */
const struct rb_callable_method_entry_struct * const cme_;
@@ -289,7 +287,7 @@ struct rb_callcache {
union {
struct {
- uintptr_t value; // Shape ID in upper bits, index in lower bits
+ uint64_t value; // Shape ID in former half, index in latter half
} attr;
const enum method_missing_reason method_missing_reason; /* used by method_missing */
VALUE v;
@@ -297,14 +295,14 @@ struct rb_callcache {
} aux_;
};
-#define VM_CALLCACHE_UNMARKABLE FL_FREEZE
-#define VM_CALLCACHE_ON_STACK FL_EXIVAR
-
/* VM_CALLCACHE_IVAR used for IVAR/ATTRSET/STRUCT_AREF/STRUCT_ASET methods */
#define VM_CALLCACHE_IVAR IMEMO_FL_USER0
#define VM_CALLCACHE_BF IMEMO_FL_USER1
#define VM_CALLCACHE_SUPER IMEMO_FL_USER2
#define VM_CALLCACHE_REFINEMENT IMEMO_FL_USER3
+#define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER4
+#define VM_CALLCACHE_ON_STACK IMEMO_FL_USER5
+#define VM_CALLCACHE_INVALID_SUPER IMEMO_FL_USER6
enum vm_cc_type {
cc_type_normal, // chained from ccs
@@ -317,26 +315,32 @@ extern const struct rb_callcache *rb_vm_empty_cc_for_super(void);
#define vm_cc_empty() rb_vm_empty_cc()
-static inline void vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id);
-
-static inline void
-vm_cc_attr_index_initialize(const struct rb_callcache *cc, shape_id_t shape_id)
+static inline VALUE
+cc_check_class(VALUE klass)
{
- vm_cc_attr_index_set(cc, (attr_index_t)-1, shape_id);
+ VM_ASSERT(klass == Qundef || RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
+ return klass;
}
+VALUE rb_vm_cc_table_create(size_t capa);
+VALUE rb_vm_cc_table_dup(VALUE old_table);
+void rb_vm_cc_table_delete(VALUE table, ID mid);
+
+static inline void vm_cc_attr_index_set(const struct rb_callcache *cc, uint64_t packed_cache);
+
static inline const struct rb_callcache *
vm_cc_new(VALUE klass,
const struct rb_callable_method_entry_struct *cme,
vm_call_handler call,
enum vm_cc_type type)
{
- struct rb_callcache *cc = IMEMO_NEW(struct rb_callcache, imemo_callcache, klass);
+ cc_check_class(klass);
+ struct rb_callcache *cc = SHAREABLE_IMEMO_NEW(struct rb_callcache, imemo_callcache, klass);
+ rb_gc_declare_weak_references((VALUE)cc);
+
*((struct rb_callable_method_entry_struct **)&cc->cme_) = (struct rb_callable_method_entry_struct *)cme;
*((vm_call_handler *)&cc->call_) = call;
- VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
-
switch (type) {
case cc_type_normal:
break;
@@ -345,11 +349,20 @@ vm_cc_new(VALUE klass,
break;
case cc_type_refinement:
*(VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT;
+ rb_vm_insert_cc_refinement(cc);
break;
}
- if (cme->def->type == VM_METHOD_TYPE_ATTRSET || cme->def->type == VM_METHOD_TYPE_IVAR) {
- vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
+ if (cme) {
+ if (cme->def->type == VM_METHOD_TYPE_ATTRSET) {
+ vm_cc_attr_index_set(cc, IVAR_CACHE_INIT);
+ }
+ else if (cme->def->type == VM_METHOD_TYPE_IVAR) {
+ vm_cc_attr_index_set(cc, rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET));
+ }
+ }
+ else {
+ *(VALUE *)&cc->flags |= VM_CALLCACHE_INVALID_SUPER;
}
RB_DEBUG_COUNTER_INC(cc_new);
@@ -374,7 +387,7 @@ vm_cc_refinement_p(const struct rb_callcache *cc)
(imemo_callcache << FL_USHIFT) | \
VM_CALLCACHE_UNMARKABLE | \
VM_CALLCACHE_ON_STACK, \
- .klass = clazz, \
+ .klass = cc_check_class(clazz), \
.cme_ = cme, \
.call_ = call, \
.aux_ = aux, \
@@ -384,8 +397,7 @@ static inline bool
vm_cc_class_check(const struct rb_callcache *cc, VALUE klass)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
- VM_ASSERT(cc->klass == 0 ||
- RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
+ VM_ASSERT(cc_check_class(cc->klass));
return cc->klass == klass;
}
@@ -396,12 +408,32 @@ vm_cc_markable(const struct rb_callcache *cc)
return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_UNMARKABLE) == 0;
}
+static inline bool
+vm_cc_invalid_super(const struct rb_callcache *cc)
+{
+ VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
+ // Set when calling super and there is no superclass.
+ return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_INVALID_SUPER);
+}
+
+static inline bool
+vm_cc_valid(const struct rb_callcache *cc)
+{
+ VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
+ VM_ASSERT(cc_check_class(cc->klass));
+
+ return !UNDEF_P(cc->klass);
+}
+
static inline const struct rb_callable_method_entry_struct *
vm_cc_cme(const struct rb_callcache *cc)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
+ VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc));
+ VM_ASSERT(cc_check_class(cc->klass));
VM_ASSERT(cc->call_ == NULL || // not initialized yet
!vm_cc_markable(cc) ||
+ vm_cc_invalid_super(cc) ||
cc->cme_ != NULL);
return cc->cme_;
@@ -412,46 +444,32 @@ vm_cc_call(const struct rb_callcache *cc)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
VM_ASSERT(cc->call_ != NULL);
+ VM_ASSERT(cc->klass != Qundef || !vm_cc_markable(cc) || vm_cc_invalid_super(cc));
+ VM_ASSERT(cc_check_class(cc->klass));
return cc->call_;
}
-static inline attr_index_t
-vm_cc_attr_index(const struct rb_callcache *cc)
+static inline uint64_t
+vm_cc_atomic_cache_read(const struct rb_callcache *cc)
{
- VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
- return (attr_index_t)((cc->aux_.attr.value & SHAPE_FLAG_MASK) - 1);
+ return ATOMIC_U64_LOAD_RELAXED(cc->aux_.attr.value);
}
-static inline shape_id_t
-vm_cc_attr_index_dest_shape_id(const struct rb_callcache *cc)
-{
- VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
-
- return cc->aux_.attr.value >> SHAPE_FLAG_SHIFT;
-}
-
-static inline void
-vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t * shape_id, attr_index_t * index)
-{
- uintptr_t cache_value = cc->aux_.attr.value; // Atomically read 64 bits
- *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
- *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
- return;
-}
-
-static inline void
-vm_ic_atomic_shape_and_index(const struct iseq_inline_iv_cache_entry *ic, shape_id_t * shape_id, attr_index_t * index)
+static inline uint64_t
+vm_ic_atomic_cache_read(const struct iseq_inline_iv_cache_entry *ic)
{
- uintptr_t cache_value = ic->value; // Atomically read 64 bits
- *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
- *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;
- return;
+ return ATOMIC_U64_LOAD_RELAXED(ic->value);
}
-static inline shape_id_t
-vm_ic_attr_index_dest_shape_id(const struct iseq_inline_iv_cache_entry *ic)
+static inline uint64_t
+vm_cache_attr_index_atomic_read(bool is_attr, const struct iseq_inline_iv_cache_entry *ic, const struct rb_callcache *cc)
{
- return (shape_id_t)(ic->value >> SHAPE_FLAG_SHIFT);
+ if (is_attr) {
+ return vm_cc_atomic_cache_read(cc);
+ }
+ else {
+ return vm_ic_atomic_cache_read(ic);
+ }
}
static inline unsigned int
@@ -464,7 +482,7 @@ vm_cc_cmethod_missing_reason(const struct rb_callcache *cc)
static inline bool
vm_cc_invalidated_p(const struct rb_callcache *cc)
{
- if (cc->klass && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
+ if (vm_cc_valid(cc) && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
return false;
}
else {
@@ -488,20 +506,6 @@ set_vm_cc_ivar(const struct rb_callcache *cc)
*(VALUE *)&cc->flags |= VM_CALLCACHE_IVAR;
}
-static inline void
-vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id)
-{
- uintptr_t *attr_value = (uintptr_t *)&cc->aux_.attr.value;
- if (!vm_cc_markable(cc)) {
- *attr_value = (uintptr_t)INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT;
- return;
- }
- VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
- VM_ASSERT(cc != vm_cc_empty());
- *attr_value = (attr_index_t)(index + 1) | ((uintptr_t)(dest_shape_id) << SHAPE_FLAG_SHIFT);
- set_vm_cc_ivar(cc);
-}
-
static inline bool
vm_cc_ivar_p(const struct rb_callcache *cc)
{
@@ -509,15 +513,28 @@ vm_cc_ivar_p(const struct rb_callcache *cc)
}
static inline void
-vm_ic_attr_index_set(const rb_iseq_t *iseq, const struct iseq_inline_iv_cache_entry *ic, attr_index_t index, shape_id_t dest_shape_id)
+vm_cc_attr_index_set(const struct rb_callcache *cc, uint64_t packed_cache)
{
- *(uintptr_t *)&ic->value = ((uintptr_t)dest_shape_id << SHAPE_FLAG_SHIFT) | (attr_index_t)(index + 1);
+ uint64_t *attr_value = (uint64_t *)&cc->aux_.attr.value;
+ if (!vm_cc_markable(cc)) {
+ *attr_value = IVAR_CACHE_INIT;
+ return;
+ }
+ VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
+ VM_ASSERT(cc != vm_cc_empty());
+ *attr_value = packed_cache;
+ set_vm_cc_ivar(cc);
}
static inline void
-vm_ic_attr_index_initialize(const struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id)
+vm_cache_attr_index_set(bool is_attr, struct iseq_inline_iv_cache_entry *ic, const struct rb_callcache *cc, uint64_t packed_cache)
{
- *(uintptr_t *)&ic->value = (uintptr_t)shape_id << SHAPE_FLAG_SHIFT;
+ if (is_attr) {
+ vm_cc_attr_index_set(cc, packed_cache);
+ }
+ else {
+ ATOMIC_U64_SET_RELAXED(ic->value, packed_cache);
+ }
}
static inline void
@@ -548,9 +565,10 @@ vm_cc_invalidate(const struct rb_callcache *cc)
{
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
VM_ASSERT(cc != vm_cc_empty());
- VM_ASSERT(cc->klass != 0); // should be enable
+ // TODO: rb_multi_ractor_p() is a workaround to stabilize CI
+ VM_ASSERT(cc->klass != Qundef || rb_multi_ractor_p()); // should be enable
- *(VALUE *)&cc->klass = 0;
+ *(VALUE *)&cc->klass = Qundef;
RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
}
@@ -572,9 +590,15 @@ struct rb_class_cc_entries {
unsigned int argc;
unsigned int flag;
const struct rb_callcache *cc;
- } *entries;
+ } entries[FLEX_ARY_LEN];
};
+static inline size_t
+vm_ccs_alloc_size(size_t capa)
+{
+ return offsetof(struct rb_class_cc_entries, entries) + (sizeof(struct rb_class_cc_entries_entry) * capa);
+}
+
#if VM_CHECK_MODE > 0
const rb_callable_method_entry_t *rb_vm_lookup_overloaded_cme(const rb_callable_method_entry_t *cme);
@@ -589,26 +613,28 @@ vm_ccs_p(const struct rb_class_cc_entries *ccs)
static inline bool
vm_cc_check_cme(const struct rb_callcache *cc, const rb_callable_method_entry_t *cme)
{
- if (vm_cc_cme(cc) == cme ||
- (cme->def->iseq_overload && vm_cc_cme(cc) == rb_vm_lookup_overloaded_cme(cme))) {
+ bool valid;
+ RB_VM_LOCKING_NO_BARRIER() {
+ valid = vm_cc_cme(cc) == cme ||
+ (cme->def->iseq_overload && vm_cc_cme(cc) == rb_vm_lookup_overloaded_cme(cme));
+ }
+ if (valid) {
return true;
}
- else {
#if 1
// debug print
- fprintf(stderr, "iseq_overload:%d\n", (int)cme->def->iseq_overload);
+ fprintf(stderr, "iseq_overload:%d, cme:%p (def:%p), cm_cc_cme(cc):%p (def:%p)\n",
+ (int)cme->def->iseq_overload,
+ cme, cme->def,
+ vm_cc_cme(cc), vm_cc_cme(cc)->def);
rp(cme);
rp(vm_cc_cme(cc));
- rb_vm_lookup_overloaded_cme(cme);
+ rp(rb_vm_lookup_overloaded_cme(cme));
#endif
- return false;
- }
+ return false;
}
#endif
-// gc.c
-void rb_vm_ccs_free(struct rb_class_cc_entries *ccs);
-
#endif /* RUBY_VM_CALLINFO_H */
diff --git a/vm_core.h b/vm_core.h
index 28d742feed..3b0fe0a811 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -118,8 +118,10 @@ extern int ruby_assert_critical_section_entered;
#include "internal.h"
#include "internal/array.h"
#include "internal/basic_operators.h"
+#include "internal/box.h"
#include "internal/sanitizers.h"
#include "internal/serial.h"
+#include "internal/set_table.h"
#include "internal/vm.h"
#include "method.h"
#include "node.h"
@@ -259,10 +261,8 @@ union ic_serial_entry {
struct iseq_inline_constant_cache_entry {
VALUE flags;
- VALUE value; // v0
- VALUE _unused1; // v1
- VALUE _unused2; // v2
- const rb_cref_t *ic_cref; // v3
+ VALUE value;
+ const rb_cref_t *ic_cref;
};
STATIC_ASSERT(sizeof_iseq_inline_constant_cache_entry,
(offsetof(struct iseq_inline_constant_cache_entry, ic_cref) +
@@ -286,7 +286,7 @@ struct iseq_inline_constant_cache {
};
struct iseq_inline_iv_cache_entry {
- uintptr_t value; // attr_index in lower bits, dest_shape_id in upper bits
+ uint64_t value; // Either rb_setivar_cache or rb_getivar_cache packed in a uint64_t.
ID iv_set_name;
};
@@ -317,16 +317,24 @@ struct rb_calling_info {
#define VM_ARGC_STACK_MAX 128
#endif
+#define VM_KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */
+
# define CALLING_ARGC(calling) ((calling)->heap_argv ? RARRAY_LENINT((calling)->heap_argv) : (calling)->argc)
struct rb_execution_context_struct;
-#if 1
-#define CoreDataFromValue(obj, type) (type*)DATA_PTR(obj)
+#ifndef RUBY_CORE_DATA_TYPE_CHECK
+# if RUBY_DEBUG
+# define RUBY_CORE_DATA_TYPE_CHECK 1
+# else
+# define RUBY_CORE_DATA_TYPE_CHECK 0
+# endif
+#endif
+#if !RUBY_CORE_DATA_TYPE_CHECK
+#define GetCoreDataFromValue(obj, type, data_type, ptr) ((ptr) = (type*)RTYPEDDATA_GET_DATA(obj))
#else
-#define CoreDataFromValue(obj, type) (type*)rb_data_object_get(obj)
+#define GetCoreDataFromValue(obj, type, data_type, ptr) TypedData_Get_Struct(obj, type, data_type, ptr)
#endif
-#define GetCoreDataFromValue(obj, type, ptr) ((ptr) = CoreDataFromValue((obj), type))
typedef struct rb_iseq_location_struct {
VALUE pathobj; /* String (path) or Array [path, realpath]. Frozen. */
@@ -395,9 +403,12 @@ enum rb_builtin_attr {
BUILTIN_ATTR_INLINE_BLOCK = 0x04,
// The iseq acts like a C method in backtraces.
BUILTIN_ATTR_C_TRACE = 0x08,
+ // The iseq uses noint branch/jump opcodes that skip interrupt checking.
+ BUILTIN_ATTR_WITHOUT_INTERRUPTS = 0x10,
};
typedef VALUE (*rb_jit_func_t)(struct rb_execution_context_struct *, struct rb_control_frame_struct *);
+typedef VALUE (*rb_zjit_func_t)(struct rb_execution_context_struct *, struct rb_control_frame_struct *, rb_jit_func_t);
struct rb_iseq_constant_body {
enum rb_iseq_type type;
@@ -428,7 +439,7 @@ struct rb_iseq_constant_body {
* size = M+N+O+(*1)+K+(&1)+(**1) // parameter size.
*/
- struct {
+ struct rb_iseq_parameters {
struct {
unsigned int has_lead : 1;
unsigned int has_opt : 1;
@@ -445,6 +456,7 @@ struct rb_iseq_constant_body {
unsigned int anon_kwrest: 1;
unsigned int use_block: 1;
unsigned int forwardable: 1;
+ unsigned int accepts_no_block: 1;
} flags;
unsigned int size;
@@ -495,6 +507,12 @@ struct rb_iseq_constant_body {
const ID *local_table; /* must free */
+ enum lvar_state {
+ lvar_uninitialized,
+ lvar_initialized,
+ lvar_reassigned,
+ } *lvar_states;
+
/* catch table */
struct iseq_catch_table *catch_table;
@@ -534,14 +552,11 @@ struct rb_iseq_constant_body {
const rb_iseq_t *mandatory_only_iseq;
-#if USE_YJIT
+#if USE_YJIT || USE_ZJIT
// Function pointer for JIT code on jit_exec()
rb_jit_func_t jit_entry;
// Number of calls on jit_exec()
long unsigned jit_entry_calls;
-#endif
-
-#if USE_YJIT
// Function pointer for JIT code on jit_exec_exception()
rb_jit_func_t jit_exception;
// Number of calls on jit_exec_exception()
@@ -554,6 +569,11 @@ struct rb_iseq_constant_body {
// Used to estimate how frequently this ISEQ gets called
uint64_t yjit_calls_at_interv;
#endif
+
+#if USE_ZJIT
+ // ZJIT stores some data on each iseq.
+ void *zjit_payload;
+#endif
};
/* T_IMEMO/iseq */
@@ -573,7 +593,7 @@ struct rb_iseq_struct {
} loader;
struct {
- struct rb_hook_list_struct *local_hooks;
+ unsigned int local_hooks_cnt;
rb_event_flag_t global_trace_events;
} exec;
} aux;
@@ -624,8 +644,10 @@ enum ruby_special_exceptions {
ruby_special_error_count
};
+extern const rb_data_type_t ruby_vm_data_type;
+
#define GetVMPtr(obj, ptr) \
- GetCoreDataFromValue((obj), rb_vm_t, (ptr))
+ GetCoreDataFromValue((obj), rb_vm_t, &ruby_vm_data_type, (ptr))
struct rb_vm_struct;
typedef void rb_vm_at_exit_func(struct rb_vm_struct*);
@@ -639,23 +661,24 @@ void *rb_objspace_alloc(void);
void rb_objspace_free(void *objspace);
void rb_objspace_call_finalizer(void);
+enum rb_hook_list_type {
+ hook_list_type_ractor_local,
+ hook_list_type_targeted_iseq,
+ hook_list_type_targeted_def, // C function
+ hook_list_type_global
+};
+
typedef struct rb_hook_list_struct {
struct rb_event_hook_struct *hooks;
rb_event_flag_t events;
unsigned int running;
+ enum rb_hook_list_type type;
bool need_clean;
- bool is_local;
} rb_hook_list_t;
-
// see builtin.h for definition
typedef const struct rb_builtin_function *RB_BUILTIN;
-struct global_object_list {
- VALUE *varptr;
- struct global_object_list *next;
-};
-
typedef struct rb_vm_struct {
VALUE self;
@@ -678,12 +701,15 @@ typedef struct rb_vm_struct {
bool terminate_waiting;
#ifndef RUBY_THREAD_PTHREAD_H
+ // win32
bool barrier_waiting;
unsigned int barrier_cnt;
- rb_nativethread_cond_t barrier_cond;
+ rb_nativethread_cond_t barrier_complete_cond;
+ rb_nativethread_cond_t barrier_release_cond;
#endif
} sync;
+#ifdef RUBY_THREAD_PTHREAD_H
// ractor scheduling
struct {
rb_nativethread_lock_t lock;
@@ -717,7 +743,10 @@ typedef struct rb_vm_struct {
bool barrier_waiting;
unsigned int barrier_waiting_cnt;
unsigned int barrier_serial;
+ struct rb_ractor_struct *barrier_ractor;
+ unsigned int barrier_lock_rec;
} sched;
+#endif
} ractor;
#ifdef USE_SIGALTSTACK
@@ -725,7 +754,6 @@ typedef struct rb_vm_struct {
#endif
rb_serial_t fork_gen;
- struct ccan_list_head waiting_fds; /* <=> struct waiting_fd */
/* set in single-threaded processes only: */
volatile int ubf_async_safe;
@@ -737,32 +765,28 @@ typedef struct rb_vm_struct {
/* object management */
VALUE mark_object_ary;
- struct global_object_list *global_object_list;
+ VALUE **global_object_list;
+ size_t global_object_list_size;
+ size_t global_object_list_capa;
const VALUE special_exceptions[ruby_special_error_count];
+ /* Ruby Box */
+ rb_box_t *master_box;
+ rb_box_t *root_box;
+ rb_box_t *main_box;
+
/* load */
- VALUE top_self;
- VALUE load_path;
- VALUE load_path_snapshot;
- VALUE load_path_check_cache;
- VALUE expanded_load_path;
- VALUE loaded_features;
- VALUE loaded_features_snapshot;
- VALUE loaded_features_realpaths;
- VALUE loaded_features_realpath_map;
- struct st_table *loaded_features_index;
- struct st_table *loading_table;
// For running the init function of statically linked
// extensions when they are loaded
- struct st_table *static_ext_inits;
+ struct st_table static_ext_inits;
/* signal */
struct {
VALUE cmd[RUBY_NSIG];
} trap_list;
- /* postponed_job (async-signal-safe, and thread-safe) */
- struct rb_postponed_job_queue *postponed_job_queue;
+ /* hook (for internal events: NEWOBJ, FREEOBJ, GC events, etc.) */
+ rb_hook_list_t global_hooks;
int src_encoding_index;
@@ -784,26 +808,26 @@ typedef struct rb_vm_struct {
rb_at_exit_list *at_exit;
- st_table *frozen_strings;
-
const struct rb_builtin_function *builtin_function_table;
- st_table *ci_table;
- struct rb_id_table *negative_cme_table;
- st_table *overloaded_cme_table; // cme -> overloaded_cme
- st_table *unused_block_warning_table;
+ st_table ci_table;
+ struct rb_id_table negative_cme_table;
+ st_table overloaded_cme_table; // cme -> overloaded_cme
+ set_table unused_block_warning_table;
+ VALUE cc_refinement_set;
// This id table contains a mapping from ID to ICs. It does this with ID
// keys and nested st_tables as values. The nested tables have ICs as keys
// and Qtrue as values. It is used when inline constant caches need to be
// invalidated or ISEQs are being freed.
- struct rb_id_table *constant_cache;
+ struct rb_id_table constant_cache;
ID inserting_constant_cache_id;
#ifndef VM_GLOBAL_CC_CACHE_TABLE_SIZE
#define VM_GLOBAL_CC_CACHE_TABLE_SIZE 1023
#endif
const struct rb_callcache *global_cc_cache_table[VM_GLOBAL_CC_CACHE_TABLE_SIZE]; // vm_eval.c
+ bool global_cc_cache_table_used; // vm_eval.c
#if defined(USE_VM_CLOCK) && USE_VM_CLOCK
uint32_t clock;
@@ -816,9 +840,10 @@ typedef struct rb_vm_struct {
size_t fiber_vm_stack_size;
size_t fiber_machine_stack_size;
} default_params;
-
} rb_vm_t;
+extern bool ruby_vm_during_cleanup;
+
/* default values */
#define RUBY_VM_SIZE_ALIGN 4096
@@ -837,7 +862,7 @@ typedef struct rb_vm_struct {
#define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */
#endif
-#if __has_feature(memory_sanitizer) || __has_feature(address_sanitizer)
+#if __has_feature(memory_sanitizer) || __has_feature(address_sanitizer) || __has_feature(leak_sanitizer)
/* It seems sanitizers consume A LOT of machine stacks */
#undef RUBY_VM_THREAD_MACHINE_STACK_SIZE
#define RUBY_VM_THREAD_MACHINE_STACK_SIZE (1024 * 1024 * sizeof(VALUE))
@@ -893,7 +918,7 @@ struct rb_block {
typedef struct rb_control_frame_struct {
const VALUE *pc; // cfp[0]
VALUE *sp; // cfp[1]
- const rb_iseq_t *iseq; // cfp[2]
+ const rb_iseq_t *_iseq; // cfp[2] -- use CFP_ISEQ(cfp) to read
VALUE self; // cfp[3] / block[0]
const VALUE *ep; // cfp[4] / block[1]
const void *block_code; // cfp[5] / block[2] -- iseq, ifunc, or forwarded block handler
@@ -946,79 +971,56 @@ typedef void *rb_jmpbuf_t[5];
Therefore, we allocates the buffer on the heap on such
environments.
*/
-typedef struct _rb_vm_tag_jmpbuf {
- struct _rb_vm_tag_jmpbuf *next;
- rb_jmpbuf_t buf;
-} *rb_vm_tag_jmpbuf_t;
-
-#define RB_VM_TAG_JMPBUF_GET(jmpbuf) ((jmpbuf)->buf)
-#else
-typedef rb_jmpbuf_t rb_vm_tag_jmpbuf_t;
-
-#define RB_VM_TAG_JMPBUF_GET(jmpbuf) (jmpbuf)
-#endif
-
-/*
- the members which are written in EC_PUSH_TAG() should be placed at
- the beginning and the end, so that entire region is accessible.
-*/
-struct rb_vm_tag {
- VALUE tag;
- VALUE retval;
- rb_vm_tag_jmpbuf_t buf;
- struct rb_vm_tag *prev;
- enum ruby_tag_type state;
- unsigned int lock_rec;
-};
+typedef rb_jmpbuf_t *rb_vm_tag_jmpbuf_t;
-#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
-static inline void
-_rb_vm_tag_jmpbuf_deinit_internal(rb_vm_tag_jmpbuf_t jmpbuf)
-{
- rb_vm_tag_jmpbuf_t buf = jmpbuf;
- while (buf != NULL) {
- rb_vm_tag_jmpbuf_t next = buf->next;
- ruby_xfree(buf);
- buf = next;
- }
-}
+#define RB_VM_TAG_JMPBUF_GET(buf) (*buf)
static inline void
-rb_vm_tag_jmpbuf_init(struct rb_vm_tag *tag)
+rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf)
{
- if (tag->prev != NULL && tag->prev->buf->next != NULL) {
- _rb_vm_tag_jmpbuf_deinit_internal(tag->prev->buf->next);
- tag->prev->buf->next = NULL;
- }
- tag->buf = ruby_xmalloc(sizeof *tag->buf);
- tag->buf->next = NULL;
- if (tag->prev != NULL) {
- tag->prev->buf->next = tag->buf;
- }
+ *jmpbuf = ruby_xmalloc(sizeof(rb_jmpbuf_t));
}
static inline void
-rb_vm_tag_jmpbuf_deinit(struct rb_vm_tag *tag)
+rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf)
{
- if (tag->prev != NULL) {
- tag->prev->buf->next = NULL;
- }
- _rb_vm_tag_jmpbuf_deinit_internal(tag->buf);
+ ruby_xfree(*jmpbuf);
}
#else
+typedef rb_jmpbuf_t rb_vm_tag_jmpbuf_t;
+
+#define RB_VM_TAG_JMPBUF_GET(buf) (buf)
+
static inline void
-rb_vm_tag_jmpbuf_init(struct rb_vm_tag *tag)
+rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf)
{
// no-op
}
static inline void
-rb_vm_tag_jmpbuf_deinit(struct rb_vm_tag *tag)
+rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf)
{
// no-op
}
#endif
+/*
+ the members which are written in EC_PUSH_TAG() should be placed at
+ the beginning and the end, so that entire region is accessible.
+*/
+struct rb_vm_tag {
+ VALUE tag;
+ VALUE retval;
+ rb_vm_tag_jmpbuf_t buf;
+ struct rb_vm_tag *prev;
+ enum ruby_tag_type state;
+ unsigned int lock_rec;
+#if USE_ZJIT
+ // ec->cfp as of EC_PUSH_TAG, which is saved for materializing JITFrame.
+ rb_control_frame_t *cfp;
+#endif
+};
+
STATIC_ASSERT(rb_vm_tag_buf_offset, offsetof(struct rb_vm_tag, buf) > 0);
STATIC_ASSERT(rb_vm_tag_buf_end,
offsetof(struct rb_vm_tag, buf) + sizeof(rb_vm_tag_jmpbuf_t) <
@@ -1027,6 +1029,7 @@ STATIC_ASSERT(rb_vm_tag_buf_end,
struct rb_unblock_callback {
rb_unblock_function_t *func;
void *arg;
+ rb_atomic_t event_serial;
};
struct rb_mutex_struct;
@@ -1056,6 +1059,8 @@ struct rb_execution_context_struct {
rb_fiber_t *fiber_ptr;
struct rb_thread_struct *thread_ptr;
+ rb_serial_t serial;
+ rb_serial_t ractor_id;
/* storage (ec (fiber) local) */
struct rb_id_table *local_storage;
@@ -1083,6 +1088,11 @@ struct rb_execution_context_struct {
VALUE private_const_reference;
+ struct {
+ VALUE obj;
+ VALUE fields_obj;
+ } gen_fields_cache;
+
/* for GC */
struct {
VALUE *stack_start;
@@ -1117,6 +1127,10 @@ void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t
// @param ec the execution context to update.
void rb_ec_clear_vm_stack(rb_execution_context_t *ec);
+// Close an execution context and free related resources that are no longer needed.
+// @param ec the execution context to close.
+void rb_ec_close(rb_execution_context_t *ec);
+
struct rb_ext_config {
bool ractor_safe;
};
@@ -1126,7 +1140,7 @@ typedef struct rb_ractor_struct rb_ractor_t;
struct rb_native_thread;
typedef struct rb_thread_struct {
- struct ccan_list_node lt_node; // managed by a ractor
+ struct ccan_list_node lt_node; // managed by a ractor (r->threads.set)
VALUE self;
rb_ractor_t *ractor;
rb_vm_t *vm;
@@ -1150,6 +1164,7 @@ typedef struct rb_thread_struct {
BITFIELD(enum rb_thread_status, status, 2);
/* bit flags */
+ unsigned int main_thread : 1;
unsigned int has_dedicated_nt : 1;
unsigned int to_kill : 1;
unsigned int abort_on_exception: 1;
@@ -1200,9 +1215,6 @@ typedef struct rb_thread_struct {
thread_invoke_type_func
} invoke_type;
- /* statistics data for profiler */
- VALUE stat_insn_usage;
-
/* fiber */
rb_fiber_t *root_fiber;
@@ -1233,9 +1245,12 @@ typedef enum {
#define VM_DEFINECLASS_TYPE(x) ((rb_vm_defineclass_type_t)(x) & VM_DEFINECLASS_TYPE_MASK)
#define VM_DEFINECLASS_FLAG_SCOPED 0x08
#define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS 0x10
+#define VM_DEFINECLASS_FLAG_DYNAMIC_CREF 0x20
#define VM_DEFINECLASS_SCOPED_P(x) ((x) & VM_DEFINECLASS_FLAG_SCOPED)
#define VM_DEFINECLASS_HAS_SUPERCLASS_P(x) \
((x) & VM_DEFINECLASS_FLAG_HAS_SUPERCLASS)
+#define VM_DEFINECLASS_DYNAMIC_CREF_P(x) \
+ ((x) & VM_DEFINECLASS_FLAG_DYNAMIC_CREF)
/* iseq.c */
RUBY_SYMBOL_EXPORT_BEGIN
@@ -1282,8 +1297,10 @@ RUBY_EXTERN VALUE rb_mRubyVMFrozenCore;
RUBY_EXTERN VALUE rb_block_param_proxy;
RUBY_SYMBOL_EXPORT_END
+extern const rb_data_type_t ruby_proc_data_type;
+
#define GetProcPtr(obj, ptr) \
- GetCoreDataFromValue((obj), rb_proc_t, (ptr))
+ GetCoreDataFromValue((obj), rb_proc_t, &ruby_proc_data_type, (ptr))
typedef struct {
const struct rb_block block;
@@ -1294,8 +1311,8 @@ typedef struct {
RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_proc_isolate(VALUE self);
-VALUE rb_proc_isolate_bang(VALUE self);
-VALUE rb_proc_ractor_make_shareable(VALUE self);
+VALUE rb_proc_isolate_bang(VALUE self, VALUE replace_self);
+VALUE rb_proc_ractor_make_shareable(VALUE proc, VALUE replace_self);
RUBY_SYMBOL_EXPORT_END
typedef struct {
@@ -1309,7 +1326,7 @@ typedef struct {
extern const rb_data_type_t ruby_binding_data_type;
#define GetBindingPtr(obj, ptr) \
- GetCoreDataFromValue((obj), rb_binding_t, (ptr))
+ GetCoreDataFromValue((obj), rb_binding_t, &ruby_binding_data_type, (ptr))
typedef struct {
const struct rb_block block;
@@ -1378,11 +1395,11 @@ typedef rb_control_frame_t *
enum vm_frame_env_flags {
/* Frame/Environment flag bits:
- * MMMM MMMM MMMM MMMM ____ FFFF FFFE EEEX (LSB)
+ * MMMM MMMM MMMM MMMM ___F FFFF FFFE EEEX (LSB)
*
* X : tag for GC marking (It seems as Fixnum)
* EEE : 4 bits Env flags
- * FF..: 7 bits Frame flags
+ * FF..: 8 bits Frame flags
* MM..: 15 bits frame magic (to check frame corruption)
*/
@@ -1405,8 +1422,9 @@ enum vm_frame_env_flags {
VM_FRAME_FLAG_CFRAME = 0x0080,
VM_FRAME_FLAG_LAMBDA = 0x0100,
VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200,
- VM_FRAME_FLAG_CFRAME_KW = 0x0400,
- VM_FRAME_FLAG_PASSED = 0x0800,
+ VM_FRAME_FLAG_CFRAME_KW = 0x0400,
+ VM_FRAME_FLAG_PASSED = 0x0800,
+ VM_FRAME_FLAG_BOX_REQUIRE = 0x1000,
/* env flag */
VM_ENV_FLAG_LOCAL = 0x0002,
@@ -1451,11 +1469,30 @@ VM_ENV_FLAGS(const VALUE *ep, long flag)
}
static inline unsigned long
+VM_ENV_FLAGS_UNCHECKED(const VALUE *ep, long flag)
+{
+ VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
+ return flags & flag;
+}
+
+static inline unsigned long
+VM_ENV_FRAME_TYPE_P(const VALUE *ep, unsigned long frame_type)
+{
+ return VM_ENV_FLAGS(ep, VM_FRAME_MAGIC_MASK) == frame_type;
+}
+
+static inline unsigned long
VM_FRAME_TYPE(const rb_control_frame_t *cfp)
{
return VM_ENV_FLAGS(cfp->ep, VM_FRAME_MAGIC_MASK);
}
+static inline unsigned long
+VM_FRAME_TYPE_UNCHECKED(const rb_control_frame_t *cfp)
+{
+ return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_MAGIC_MASK);
+}
+
static inline int
VM_FRAME_LAMBDA_P(const rb_control_frame_t *cfp)
{
@@ -1475,6 +1512,12 @@ VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp)
}
static inline int
+VM_FRAME_FINISHED_P_UNCHECKED(const rb_control_frame_t *cfp)
+{
+ return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_FINISH) != 0;
+}
+
+static inline int
VM_FRAME_BMETHOD_P(const rb_control_frame_t *cfp)
{
return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BMETHOD) != 0;
@@ -1494,17 +1537,38 @@ static inline int
VM_FRAME_CFRAME_P(const rb_control_frame_t *cfp)
{
int cframe_p = VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0;
- VM_ASSERT(RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) != cframe_p ||
+ // With ZJIT lightweight frames, cfp->_iseq may be stale (not yet materialized),
+ // so skip this assertion when jit_return is set (zjit.h is not available here).
+ VM_ASSERT(cfp->jit_return ||
+ RUBY_VM_NORMAL_ISEQ_P(cfp->_iseq) != cframe_p ||
(VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY);
return cframe_p;
}
static inline int
+VM_FRAME_CFRAME_P_UNCHECKED(const rb_control_frame_t *cfp)
+{
+ return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0;
+}
+
+static inline int
VM_FRAME_RUBYFRAME_P(const rb_control_frame_t *cfp)
{
return !VM_FRAME_CFRAME_P(cfp);
}
+static inline int
+VM_FRAME_RUBYFRAME_P_UNCHECKED(const rb_control_frame_t *cfp)
+{
+ return !VM_FRAME_CFRAME_P_UNCHECKED(cfp);
+}
+
+static inline int
+VM_FRAME_NS_REQUIRE_P(const rb_control_frame_t *cfp)
+{
+ return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BOX_REQUIRE) != 0;
+}
+
#define RUBYVM_CFUNC_FRAME_P(cfp) \
(VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC)
@@ -1517,20 +1581,57 @@ VM_ENV_LOCAL_P(const VALUE *ep)
return VM_ENV_FLAGS(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0;
}
+static inline int
+VM_ENV_LOCAL_P_UNCHECKED(const VALUE *ep)
+{
+ return VM_ENV_FLAGS_UNCHECKED(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0;
+}
+
+static inline const VALUE *
+VM_ENV_PREV_EP_UNCHECKED(const VALUE *ep)
+{
+ return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]);
+}
+
static inline const VALUE *
VM_ENV_PREV_EP(const VALUE *ep)
{
VM_ASSERT(VM_ENV_LOCAL_P(ep) == 0);
- return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]);
+ return VM_ENV_PREV_EP_UNCHECKED(ep);
+}
+
+static inline bool
+VM_ENV_BOXED_P(const VALUE *ep)
+{
+ return VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CLASS) || VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_TOP);
}
static inline VALUE
VM_ENV_BLOCK_HANDLER(const VALUE *ep)
{
+ if (VM_ENV_BOXED_P(ep)) {
+ VM_ASSERT(VM_ENV_LOCAL_P(ep));
+ return VM_BLOCK_HANDLER_NONE;
+ }
+
VM_ASSERT(VM_ENV_LOCAL_P(ep));
return ep[VM_ENV_DATA_INDEX_SPECVAL];
}
+static inline const rb_box_t *
+VM_ENV_BOX(const VALUE *ep)
+{
+ VM_ASSERT(VM_ENV_BOXED_P(ep));
+ VM_ASSERT(VM_ENV_LOCAL_P(ep));
+ return (const rb_box_t *)GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]);
+}
+
+static inline const rb_box_t *
+VM_ENV_BOX_UNCHECKED(const VALUE *ep)
+{
+ return (const rb_box_t *)GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]);
+}
+
#if VM_CHECK_MODE > 0
int rb_vm_ep_in_heap_p(const VALUE *ep);
#endif
@@ -1851,7 +1952,7 @@ NORETURN(void rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int
/* functions about thread/vm execution */
RUBY_SYMBOL_EXPORT_BEGIN
-VALUE rb_iseq_eval(const rb_iseq_t *iseq);
+VALUE rb_iseq_eval(const rb_iseq_t *iseq, const rb_box_t *box);
VALUE rb_iseq_eval_main(const rb_iseq_t *iseq);
VALUE rb_iseq_path(const rb_iseq_t *iseq);
VALUE rb_iseq_realpath(const rb_iseq_t *iseq);
@@ -1897,10 +1998,11 @@ void rb_thread_wakeup_timer_thread(int);
static inline void
rb_vm_living_threads_init(rb_vm_t *vm)
{
- ccan_list_head_init(&vm->waiting_fds);
ccan_list_head_init(&vm->workqueue);
ccan_list_head_init(&vm->ractor.set);
+#ifdef RUBY_THREAD_PTHREAD_H
ccan_list_head_init(&vm->ractor.sched.zombie_threads);
+#endif
}
typedef int rb_backtrace_iter_func(void *, VALUE, int, VALUE);
@@ -1910,6 +2012,7 @@ VALUE *rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t
int rb_vm_get_sourceline(const rb_control_frame_t *);
void rb_vm_stack_to_heap(rb_execution_context_t *ec);
void ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame);
+void rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size);
rb_thread_t * ruby_thread_from_native(void);
int ruby_thread_set_native(rb_thread_t *th);
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp);
@@ -1924,9 +2027,8 @@ void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE
void rb_gc_mark_machine_context(const rb_execution_context_t *ec);
-void rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr);
-
const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
+const rb_callable_method_entry_t *rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp);
#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack]
@@ -1953,14 +2055,22 @@ rb_execution_context_t *rb_vm_main_ractor_ec(rb_vm_t *vm); // ractor.c
RUBY_EXTERN struct rb_ractor_struct *ruby_single_main_ractor; // ractor.c
RUBY_EXTERN rb_vm_t *ruby_current_vm_ptr;
RUBY_EXTERN rb_event_flag_t ruby_vm_event_flags;
-RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags;
-RUBY_EXTERN unsigned int ruby_vm_event_local_num;
+RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags; // only ever added to
+RUBY_EXTERN unsigned int ruby_vm_iseq_events_enabled;
+RUBY_EXTERN unsigned int ruby_vm_c_events_enabled;
#define GET_VM() rb_current_vm()
#define GET_RACTOR() rb_current_ractor()
#define GET_THREAD() rb_current_thread()
#define GET_EC() rb_current_execution_context(true)
+static inline rb_serial_t
+rb_ec_serial(struct rb_execution_context_struct *ec)
+{
+ VM_ASSERT(ec->serial >= 1);
+ return ec->serial;
+}
+
static inline rb_thread_t *
rb_ec_thread_ptr(const rb_execution_context_t *ec)
{
@@ -1980,6 +2090,14 @@ rb_ec_ractor_ptr(const rb_execution_context_t *ec)
}
}
+static inline rb_serial_t
+rb_ec_ractor_id(const rb_execution_context_t *ec)
+{
+ rb_serial_t ractor_id = ec->ractor_id;
+ RUBY_ASSERT(ractor_id);
+ return ractor_id;
+}
+
static inline rb_vm_t *
rb_ec_vm_ptr(const rb_execution_context_t *ec)
{
@@ -1998,19 +2116,19 @@ static inline rb_execution_context_t *
rb_current_execution_context(bool expect_ec)
{
#ifdef RB_THREAD_LOCAL_SPECIFIER
- #if defined(__arm64__) || defined(__aarch64__)
- rb_execution_context_t *ec = rb_current_ec();
+ #ifdef RB_THREAD_CURRENT_EC_NOINLINE
+ rb_execution_context_t * volatile ec = rb_current_ec();
#else
- rb_execution_context_t *ec = ruby_current_ec;
+ rb_execution_context_t * volatile ec = ruby_current_ec;
#endif
/* On the shared objects, `__tls_get_addr()` is used to access the TLS
* and the address of the `ruby_current_ec` can be stored on a function
* frame. However, this address can be mis-used after native thread
* migration of a coroutine.
- * 1) Get `ptr =&ruby_current_ec` op NT1 and store it on the frame.
+ * 1) Get `ptr = &ruby_current_ec` on NT1 and store it on the frame.
* 2) Context switch and resume it on the NT2.
- * 3) `ptr` is used on NT2 but it accesses to the TLS on NT1.
+ * 3) `ptr` is used on NT2 but it accesses the TLS of NT1.
* This assertion checks such misusage.
*
* To avoid accidents, `GET_EC()` should be called once on the frame.
@@ -2018,7 +2136,7 @@ rb_current_execution_context(bool expect_ec)
*/
VM_ASSERT(ec == rb_current_ec_noinline());
#else
- rb_execution_context_t *ec = native_tls_get(ruby_current_ec_key);
+ rb_execution_context_t * volatile ec = native_tls_get(ruby_current_ec_key);
#endif
VM_ASSERT(!expect_ec || ec != NULL);
return ec;
@@ -2067,12 +2185,21 @@ void rb_ec_vm_lock_rec_release(const rb_execution_context_t *ec,
unsigned int recorded_lock_rec,
unsigned int current_lock_rec);
+/* This technically is a data race, as it's checked without the lock, however we
+ * check against a value only our own thread will write. */
+NO_SANITIZE("thread", static inline bool
+vm_locked_by_ractor_p(rb_vm_t *vm, rb_ractor_t *cr))
+{
+ VM_ASSERT(cr == GET_RACTOR());
+ return vm->ractor.sync.lock_owner == cr;
+}
+
static inline unsigned int
rb_ec_vm_lock_rec(const rb_execution_context_t *ec)
{
rb_vm_t *vm = rb_ec_vm_ptr(ec);
- if (vm->ractor.sync.lock_owner != rb_ec_ractor_ptr(ec)) {
+ if (!vm_locked_by_ractor_p(vm, rb_ec_ractor_ptr(ec))) {
return 0;
}
else {
@@ -2099,8 +2226,12 @@ enum {
#define RUBY_VM_SET_TRAP_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TRAP_INTERRUPT_MASK)
#define RUBY_VM_SET_TERMINATE_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TERMINATE_INTERRUPT_MASK)
#define RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, VM_BARRIER_INTERRUPT_MASK)
-#define RUBY_VM_INTERRUPTED(ec) ((ec)->interrupt_flag & ~(ec)->interrupt_mask & \
- (PENDING_INTERRUPT_MASK|TRAP_INTERRUPT_MASK))
+
+static inline bool
+RUBY_VM_INTERRUPTED(rb_execution_context_t *ec)
+{
+ return (ATOMIC_LOAD_RELAXED(ec->interrupt_flag) & ~(ec->interrupt_mask) & (PENDING_INTERRUPT_MASK|TRAP_INTERRUPT_MASK));
+}
static inline bool
RUBY_VM_INTERRUPTED_ANY(rb_execution_context_t *ec)
@@ -2113,7 +2244,7 @@ RUBY_VM_INTERRUPTED_ANY(rb_execution_context_t *ec)
RUBY_VM_SET_TIMER_INTERRUPT(ec);
}
#endif
- return ec->interrupt_flag & ~(ec)->interrupt_mask;
+ return ATOMIC_LOAD_RELAXED(ec->interrupt_flag) & ~(ec)->interrupt_mask;
}
VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt);
@@ -2147,7 +2278,7 @@ rb_vm_check_ints(rb_execution_context_t *ec)
VM_ASSERT(ruby_assert_critical_section_entered == 0);
#endif
- VM_ASSERT(ec == GET_EC());
+ VM_ASSERT(ec == rb_current_ec_noinline());
if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {
rb_threadptr_execute_interrupts(rb_ec_thread_ptr(ec), 0);
@@ -2174,10 +2305,11 @@ struct rb_trace_arg_struct {
};
void rb_hook_list_mark(rb_hook_list_t *hooks);
-void rb_hook_list_mark_and_update(rb_hook_list_t *hooks);
+void rb_hook_list_mark_and_move(rb_hook_list_t *hooks);
void rb_hook_list_free(rb_hook_list_t *hooks);
-void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line);
-void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval);
+void rb_hook_list_connect_local_tracepoint(rb_hook_list_t *list, VALUE tpval, unsigned int target_line);
+bool rb_hook_list_remove_local_tracepoint(rb_hook_list_t *list, VALUE tpval);
+unsigned int rb_hook_list_count(rb_hook_list_t *list);
void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, rb_hook_list_t *hooks, int pop_p);
@@ -2216,6 +2348,8 @@ struct rb_ractor_pub {
VALUE self;
uint32_t id;
rb_hook_list_t hooks;
+ st_table targeted_hooks; // also called "local hooks". {ISEQ => hook_list, def => hook_list...}
+ unsigned int targeted_hooks_cnt; // ex: tp.enabled(target: method(:puts))
};
static inline rb_hook_list_t *
@@ -2225,11 +2359,31 @@ rb_ec_ractor_hooks(const rb_execution_context_t *ec)
return &cr_pub->hooks;
}
+static inline rb_hook_list_t *
+rb_vm_global_hooks(const rb_execution_context_t *ec)
+{
+ return &rb_ec_vm_ptr(ec)->global_hooks;
+}
+
+static inline rb_hook_list_t *
+rb_ec_hooks(const rb_execution_context_t *ec, rb_event_flag_t event)
+{
+ // Should be a single bit set
+ VM_ASSERT(event != 0 && ((event - 1) & event) == 0);
+
+ if (event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK) {
+ return rb_vm_global_hooks(ec);
+ }
+ else {
+ return rb_ec_ractor_hooks(ec);
+ }
+}
+
#define EXEC_EVENT_HOOK(ec_, flag_, self_, id_, called_id_, klass_, data_) \
- EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_ractor_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 0)
+ EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_hooks(ec_, flag_), flag_, self_, id_, called_id_, klass_, data_, 0)
#define EXEC_EVENT_HOOK_AND_POP_FRAME(ec_, flag_, self_, id_, called_id_, klass_, data_) \
- EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_ractor_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 1)
+ EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_hooks(ec_, flag_), flag_, self_, id_, called_id_, klass_, data_, 1)
static inline void
rb_exec_event_hook_script_compiled(rb_execution_context_t *ec, const rb_iseq_t *iseq, VALUE eval_script)
@@ -2241,9 +2395,7 @@ rb_exec_event_hook_script_compiled(rb_execution_context_t *ec, const rb_iseq_t *
void rb_vm_trap_exit(rb_vm_t *vm);
void rb_vm_postponed_job_atfork(void); /* vm_trace.c */
-void rb_vm_postponed_job_free(void); /* vm_trace.c */
size_t rb_vm_memsize_postponed_job_queue(void); /* vm_trace.c */
-void rb_vm_postponed_job_queue_init(rb_vm_t *vm); /* vm_trace.c */
RUBY_SYMBOL_EXPORT_BEGIN
diff --git a/vm_debug.h b/vm_debug.h
index d0bc81574a..cf80232f3a 100644
--- a/vm_debug.h
+++ b/vm_debug.h
@@ -88,6 +88,10 @@ void ruby_debug_log(const char *file, int line, const char *func_name, const cha
void ruby_debug_log_print(unsigned int n);
bool ruby_debug_log_filter(const char *func_name, const char *file_name);
+// convenient macro to log even if the USE_RUBY_DEBUG_LOG macro is not specified.
+// You can use this macro for temporary usage (you should not commit it).
+#define _RUBY_DEBUG_LOG(...) ruby_debug_log(__FILE__, __LINE__, RUBY_FUNCTION_NAME_STRING, "" __VA_ARGS__)
+
#if RBIMPL_COMPILER_IS(GCC) && defined(__OPTIMIZE__)
# define ruby_debug_log(...) \
RB_GNUC_EXTENSION_BLOCK( \
@@ -97,10 +101,6 @@ bool ruby_debug_log_filter(const char *func_name, const char *file_name);
RBIMPL_WARNING_POP())
#endif
-// convenient macro to log even if the USE_RUBY_DEBUG_LOG macro is not specified.
-// You can use this macro for temporary usage (you should not commit it).
-#define _RUBY_DEBUG_LOG(...) ruby_debug_log(__FILE__, __LINE__, RUBY_FUNCTION_NAME_STRING, "" __VA_ARGS__)
-
#if USE_RUBY_DEBUG_LOG
# define RUBY_DEBUG_LOG_ENABLED(func_name, file_name) \
(ruby_debug_log_mode && ruby_debug_log_filter(func_name, file_name))
diff --git a/vm_dump.c b/vm_dump.c
index 7bfa7c1d7a..00b03ff58d 100644
--- a/vm_dump.c
+++ b/vm_dump.c
@@ -37,6 +37,7 @@
#include "iseq.h"
#include "vm_core.h"
#include "ractor_core.h"
+#include "zjit.h"
#define MAX_POSBUF 128
@@ -61,28 +62,37 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
VALUE tmp;
const rb_iseq_t *iseq = NULL;
- const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
+ const rb_callable_method_entry_t *me = rb_vm_frame_method_entry_unchecked(cfp);
+ const rb_box_t *box = NULL;
if (ep < 0 || (size_t)ep > ec->vm_stack_size) {
ep = (ptrdiff_t)cfp->ep;
ep_in_heap = 'p';
}
- switch (VM_FRAME_TYPE(cfp)) {
+ switch (VM_FRAME_TYPE_UNCHECKED(cfp)) {
case VM_FRAME_MAGIC_TOP:
magic = "TOP";
+ box = VM_ENV_BOX_UNCHECKED(cfp->ep);
break;
case VM_FRAME_MAGIC_METHOD:
magic = "METHOD";
+ if (me) {
+ box = me->def->box;
+ }
break;
case VM_FRAME_MAGIC_CLASS:
magic = "CLASS";
+ box = VM_ENV_BOX_UNCHECKED(cfp->ep);
break;
case VM_FRAME_MAGIC_BLOCK:
magic = "BLOCK";
break;
case VM_FRAME_MAGIC_CFUNC:
magic = "CFUNC";
+ if (me) {
+ box = me->def->box;
+ }
break;
case VM_FRAME_MAGIC_IFUNC:
magic = "IFUNC";
@@ -112,23 +122,25 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
selfstr = "";
}
- if (cfp->iseq != 0) {
+ if (CFP_ISEQ(cfp)) {
+ iseq = CFP_ISEQ(cfp);
#define RUBY_VM_IFUNC_P(ptr) IMEMO_TYPE_P(ptr, imemo_ifunc)
- if (RUBY_VM_IFUNC_P(cfp->iseq)) {
+ if (RUBY_VM_IFUNC_P(iseq)) {
iseq_name = "<ifunc>";
}
- else if (SYMBOL_P((VALUE)cfp->iseq)) {
- tmp = rb_sym2str((VALUE)cfp->iseq);
+ else if (SYMBOL_P((VALUE)iseq)) {
+ tmp = rb_sym2str((VALUE)iseq);
iseq_name = RSTRING_PTR(tmp);
snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
line = -1;
}
else {
- if (cfp->pc) {
- iseq = cfp->iseq;
- pc = cfp->pc - ISEQ_BODY(iseq)->iseq_encoded;
+ if (CFP_PC(cfp)) {
+ pc = CFP_PC(cfp) - ISEQ_BODY(iseq)->iseq_encoded;
iseq_name = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);
- line = rb_vm_get_sourceline(cfp);
+ if (pc >= 0 && (size_t)pc <= ISEQ_BODY(iseq)->iseq_size) {
+ line = rb_vm_get_sourceline(cfp);
+ }
if (line) {
snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(rb_iseq_path(iseq)), line);
}
@@ -138,7 +150,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
}
}
}
- else if (me != NULL) {
+ else if (me != NULL && IMEMO_TYPE_P(me, imemo_ment)) {
iseq_name = rb_id2name(me->def->original_id);
snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
line = -1;
@@ -154,11 +166,19 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
}
kprintf("s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack);
kprintf(ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
+ kprintf("l:%s ", VM_ENV_LOCAL_P(cfp->ep) ? "y" : "n");
+ if (box) {
+ kprintf("b:%04ld ", box->box_id % 10000);
+ }
+ else {
+ kprintf("b:---- ");
+ }
+ kprintf("r:%p ", cfp->jit_return);
kprintf("%-6s", magic);
if (line) {
kprintf(" %s", posbuf);
}
- if (VM_FRAME_FINISHED_P(cfp)) {
+ if (VM_FRAME_FINISHED_P_UNCHECKED(cfp)) {
kprintf(" [FINISH]");
}
if (0) {
@@ -193,7 +213,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
if (ISEQ_BODY(iseq)->local_table_size > 0) {
kprintf(" lvars:\n");
for (unsigned int i=0; i<ISEQ_BODY(iseq)->local_table_size; i++) {
- const VALUE *argv = cfp->ep - ISEQ_BODY(cfp->iseq)->local_table_size - VM_ENV_DATA_SIZE + 1;
+ const VALUE *argv = cfp->ep - ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size - VM_ENV_DATA_SIZE + 1;
kprintf(" %s: %s\n",
rb_id2name(ISEQ_BODY(iseq)->local_table[i]),
rb_raw_obj_info(buff, 0x100, argv[i]));
@@ -206,6 +226,251 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
return false;
}
+static inline const rb_control_frame_t *
+vmdebug_search_cf_from_ep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE * const ep)
+{
+ if (!ep) {
+ return NULL;
+ }
+ else {
+ const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(ec); /* end of control frame pointer */
+
+ while (cfp < eocfp) {
+ if (cfp->ep == ep) {
+ return cfp;
+ }
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+
+ return NULL;
+ }
+}
+
+static rb_callable_method_entry_t *
+vmdebug_env_method_entry_unchecked(VALUE obj, int can_be_svar)
+{
+ if (obj == Qfalse) return NULL;
+
+ switch (imemo_type(obj)) {
+ case imemo_ment:
+ return (rb_callable_method_entry_t *)obj;
+ case imemo_cref:
+ return NULL;
+ case imemo_svar:
+ if (can_be_svar) {
+ return vmdebug_env_method_entry_unchecked(((struct vm_svar *)obj)->cref_or_me, FALSE);
+ }
+ default:
+ return NULL;
+ }
+}
+
+static const rb_callable_method_entry_t *
+vmdebug_frame_method_entry_unchecked(const VALUE *ep)
+{
+ rb_callable_method_entry_t *me;
+
+ while (!VM_ENV_LOCAL_P_UNCHECKED(ep)) {
+ if ((me = vmdebug_env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
+ ep = VM_ENV_PREV_EP_UNCHECKED(ep);
+ }
+
+ return vmdebug_env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
+}
+
+static bool
+box_env_dump(const rb_execution_context_t *ec, const VALUE *env, const rb_control_frame_t *checkpoint_cfp, FILE *errout)
+{
+ ptrdiff_t pc = -1;
+ ptrdiff_t ep = env - ec->vm_stack;
+ char ep_in_heap = ' ';
+ char posbuf[MAX_POSBUF+1];
+ int line = 0;
+ const char *magic, *iseq_name = "-";
+ VALUE tmp;
+ const rb_iseq_t *iseq = NULL;
+ const rb_box_t *box = NULL;
+ const rb_control_frame_t *cfp = vmdebug_search_cf_from_ep(ec, checkpoint_cfp, env);
+ const rb_callable_method_entry_t *me = vmdebug_frame_method_entry_unchecked(env);
+
+ if (ep < 0 || (size_t)ep > ec->vm_stack_size) {
+ if (cfp) {
+ ep = (ptrdiff_t)cfp->ep;
+ ep_in_heap = 'p';
+ }
+ }
+
+ switch (VM_ENV_FLAGS_UNCHECKED(env, VM_FRAME_MAGIC_MASK)) {
+ case VM_FRAME_MAGIC_TOP:
+ magic = "TOP";
+ box = VM_ENV_BOX_UNCHECKED(env);
+ break;
+ case VM_FRAME_MAGIC_METHOD:
+ magic = "METHOD";
+ if (me) {
+ box = me->def->box;
+ }
+ break;
+ case VM_FRAME_MAGIC_CLASS:
+ magic = "CLASS";
+ box = VM_ENV_BOX_UNCHECKED(env);
+ break;
+ case VM_FRAME_MAGIC_BLOCK:
+ magic = "BLOCK";
+ break;
+ case VM_FRAME_MAGIC_CFUNC:
+ magic = "CFUNC";
+ if (me) {
+ box = me->def->box;
+ }
+ break;
+ case VM_FRAME_MAGIC_IFUNC:
+ magic = "IFUNC";
+ break;
+ case VM_FRAME_MAGIC_EVAL:
+ magic = "EVAL";
+ break;
+ case VM_FRAME_MAGIC_RESCUE:
+ magic = "RESCUE";
+ break;
+ case VM_FRAME_MAGIC_DUMMY:
+ magic = "DUMMY";
+ break;
+ case 0:
+ magic = "------";
+ break;
+ default:
+ magic = "(none)";
+ break;
+ }
+
+ if (cfp && CFP_ISEQ(cfp)) {
+#define RUBY_VM_IFUNC_P(ptr) IMEMO_TYPE_P(ptr, imemo_ifunc)
+ const rb_iseq_t *resolved_iseq = CFP_ISEQ(cfp);
+ if (RUBY_VM_IFUNC_P(resolved_iseq)) {
+ iseq_name = "<ifunc>";
+ }
+ else if (SYMBOL_P((VALUE)resolved_iseq)) {
+ tmp = rb_sym2str((VALUE)resolved_iseq);
+ iseq_name = RSTRING_PTR(tmp);
+ snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
+ line = -1;
+ }
+ else {
+ if (CFP_PC(cfp)) {
+ iseq = resolved_iseq;
+ pc = CFP_PC(cfp) - ISEQ_BODY(iseq)->iseq_encoded;
+ iseq_name = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);
+ if (pc >= 0 && (size_t)pc <= ISEQ_BODY(iseq)->iseq_size) {
+ line = rb_vm_get_sourceline(cfp);
+ }
+ if (line) {
+ snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(rb_iseq_path(iseq)), line);
+ }
+ }
+ else {
+ iseq_name = "<dummy_frame>";
+ }
+ }
+ }
+ else if (me != NULL && IMEMO_TYPE_P(me, imemo_ment)) {
+ iseq_name = rb_id2name(me->def->original_id);
+ snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
+ line = -1;
+ }
+
+ if (cfp) {
+ kprintf("c:%04"PRIdPTRDIFF" ",
+ ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp));
+ }
+ else {
+ kprintf("c:---- ");
+ }
+ kprintf(ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000);
+ kprintf("l:%s ", VM_ENV_LOCAL_P(env) ? "y" : "n");
+ if (box) {
+ kprintf("b:%04ld ", box->box_id % 10000);
+ }
+ else {
+ kprintf("b:---- ");
+ }
+ kprintf("%-6s", magic);
+ if (line) {
+ kprintf(" %s", posbuf);
+ }
+ if (VM_ENV_FLAGS_UNCHECKED(env, VM_FRAME_FLAG_FINISH) != 0) {
+ kprintf(" [FINISH]");
+ }
+ kprintf("\n");
+ return true;
+ error:
+ return false;
+}
+
+static bool
+box_env_dump_unchecked(const rb_execution_context_t *ec, const VALUE *env, const rb_control_frame_t *checkpoint_cfp, FILE *errout)
+{
+ if (env == NULL) {
+ kprintf("c:---- e:000000 l:- b:---- (none)\n");
+ return true;
+ }
+ else {
+ return box_env_dump(ec, env, checkpoint_cfp, errout);
+ }
+ error:
+ return false;
+}
+
+bool
+rb_vmdebug_box_env_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *current_cfp, FILE *errout)
+{
+ // See VM_EP_RUBY_LEP for the original logic
+ const VALUE *ep = current_cfp->ep;
+ const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(ec); /* end of control frame pointer */
+ const rb_control_frame_t *cfp = current_cfp, *checkpoint_cfp = current_cfp;
+
+ kprintf("-- Ruby Box detection information "
+ "-----------------------------------------\n");
+
+ box_env_dump_unchecked(ec, ep, checkpoint_cfp, errout);
+
+ if (VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_IFUNC)) {
+ while (!VM_ENV_LOCAL_P(ep)) {
+ ep = VM_ENV_PREV_EP(ep);
+ box_env_dump_unchecked(ec, ep, checkpoint_cfp, errout);
+ }
+ goto stop;
+ }
+
+ while (VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CFUNC)) {
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ if (!cfp) {
+ goto stop;
+ }
+ if (cfp >= eocfp) {
+ kprintf("[PREVIOUS CONTROL FRAME IS OUT OF BOUND]\n");
+ goto stop;
+ }
+ ep = cfp->ep;
+ box_env_dump_unchecked(ec, ep, checkpoint_cfp, errout);
+ if (!ep) {
+ goto stop;
+ }
+ }
+
+ while (!VM_ENV_LOCAL_P(ep)) {
+ ep = VM_ENV_PREV_EP(ep);
+ box_env_dump_unchecked(ec, ep, checkpoint_cfp, errout);
+ }
+
+ stop:
+ kprintf("\n");
+ return true;
+
+ error:
+ return false;
+}
+
bool
rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout)
{
@@ -305,9 +570,9 @@ static const VALUE *
vm_base_ptr(const rb_control_frame_t *cfp)
{
const rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- const VALUE *bp = prev_cfp->sp + ISEQ_BODY(cfp->iseq)->local_table_size + VM_ENV_DATA_SIZE;
+ const VALUE *bp = prev_cfp->sp + ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size + VM_ENV_DATA_SIZE;
- if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
+ if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
bp += 1;
}
return bp;
@@ -322,7 +587,7 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c
const VALUE *ep = cfp->ep;
if (VM_FRAME_RUBYFRAME_P(cfp)) {
- const rb_iseq_t *iseq = cfp->iseq;
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
argc = ISEQ_BODY(iseq)->param.lead_num;
local_table_size = ISEQ_BODY(iseq)->local_table_size;
}
@@ -393,7 +658,7 @@ rb_vmdebug_debug_print_register(const rb_execution_context_t *ec, FILE *errout)
ptrdiff_t cfpi;
if (VM_FRAME_RUBYFRAME_P(cfp)) {
- pc = cfp->pc - ISEQ_BODY(cfp->iseq)->iseq_encoded;
+ pc = cfp->pc - ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
}
if (ep < 0 || (size_t)ep > ec->vm_stack_size) {
@@ -418,7 +683,7 @@ rb_vmdebug_thread_dump_regs(VALUE thval, FILE *errout)
bool
rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *errout)
{
- const rb_iseq_t *iseq = cfp->iseq;
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
if (iseq != 0) {
ptrdiff_t pc = _pc - ISEQ_BODY(iseq)->iseq_encoded;
@@ -511,13 +776,19 @@ rb_vmdebug_thread_dump_state(FILE *errout, VALUE self)
# include <sys/mman.h>
# undef backtrace
+# if defined(__arm64__) || defined(__POWERPC__)
static bool
is_coroutine_start(unw_word_t ip)
{
+#if defined(USE_MN_THREADS) && USE_MN_THREADS
struct coroutine_context;
extern void ruby_coroutine_start(struct coroutine_context *, struct coroutine_context *);
return ((void *)(ip) == (void *)ruby_coroutine_start);
+#else
+ return false;
+#endif
}
+# endif
int
backtrace(void **trace, int size)
@@ -614,23 +885,28 @@ darwin_sigtramp:
}
return n;
-# else /* defined(__arm64__) */
+# elif defined(__arm64__) || defined(__POWERPC__)
/* Since Darwin arm64's _sigtramp is implemented as normal function,
* unwind can unwind frames without special code.
* https://github.com/apple/darwin-libplatform/blob/215b09856ab5765b7462a91be7076183076600df/src/setjmp/generic/sigtramp.c
*/
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
+# if defined(__arm64__)
// Strip Arm64's pointer authentication.
// https://developer.apple.com/documentation/security/preparing_your_app_to_work_with_pointer_authentication
// I wish I could use "ptrauth_strip()" but I get an error:
// "this target does not support pointer authentication"
trace[n++] = (void *)(ip & 0x7fffffffffffull);
-
+# else
+ trace[n++] = (void *)ip;
+# endif
// Apple's libunwind can't handle our coroutine switching code
if (is_coroutine_start(ip)) break;
}
return n;
+# else
+# error unsupported architecture
# endif
}
# elif defined(BROKEN_BACKTRACE)
@@ -1110,6 +1386,7 @@ rb_dump_machine_register(FILE *errout, const ucontext_t *ctx)
bool
rb_vm_bugreport(const void *ctx, FILE *errout)
{
+ const char *box_env = getenv("RUBY_BUGREPORT_BOX_ENV");
const char *cmd = getenv("RUBY_ON_BUG");
if (cmd) {
char buf[0x100];
@@ -1140,10 +1417,22 @@ rb_vm_bugreport(const void *ctx, FILE *errout)
enum {other_runtime_info = 0};
#endif
const rb_vm_t *const vm = GET_VM();
+ const rb_box_t *current_box = rb_current_box_in_crash_report();
const rb_execution_context_t *ec = rb_current_execution_context(false);
+ VALUE loaded_features;
+
+ if (current_box) {
+ loaded_features = current_box->loaded_features;
+ }
+ else {
+ loaded_features = rb_root_box()->loaded_features;
+ }
if (vm && ec) {
rb_vmdebug_stack_dump_raw(ec, ec->cfp, errout);
+ if (box_env) {
+ rb_vmdebug_box_env_dump_raw(ec, ec->cfp, errout);
+ }
rb_backtrace_print_as_bugreport(errout);
kputs("\n");
// If we get here, hopefully things are intact enough that
@@ -1152,8 +1441,11 @@ rb_vm_bugreport(const void *ctx, FILE *errout)
kprintf("-- Threading information "
"---------------------------------------------------\n");
kprintf("Total ractor count: %u\n", vm->ractor.cnt);
- kprintf("Ruby thread count for this ractor: %u\n", rb_ec_ractor_ptr(ec)->threads.cnt);
- if (rb_fiber_scheduler_get() != Qnil) {
+ const rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ if (cr) {
+ kprintf("Ruby thread count for this ractor: %u\n", cr->threads.cnt);
+ }
+ if (ec->thread_ptr && ec->thread_ptr->scheduler != Qnil) {
kprintf("Note that the Fiber scheduler is enabled\n");
}
kputs("\n");
@@ -1188,10 +1480,24 @@ rb_vm_bugreport(const void *ctx, FILE *errout)
LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
kprintf("\n");
}
- if (vm->loaded_features) {
+ if (rb_box_available()) {
+ kprintf("* Ruby Box: enabled\n");
+ if (current_box) {
+ kprintf("* Current box id: %ld, type: %s\n",
+ current_box->box_id,
+ BOX_USER_P(current_box) ? (BOX_MAIN_P(current_box) ? "main" : "user") : "root");
+ }
+ else {
+ kprintf("* Current box: NULL (crashed)\n");
+ }
+ }
+ else {
+ kprintf("* Ruby Box: disabled\n");
+ }
+ if (loaded_features) {
kprintf("* Loaded features:\n\n");
- for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
- name = RARRAY_AREF(vm->loaded_features, i);
+ for (i=0; i<RARRAY_LEN(loaded_features); i++) {
+ name = RARRAY_AREF(loaded_features, i);
if (RB_TYPE_P(name, T_STRING)) {
kprintf(" %4d %.*s\n", i,
LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
diff --git a/vm_eval.c b/vm_eval.c
index 229dbf03b3..84bb40ba80 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1,6 +1,6 @@
/**********************************************************************
- vm_eval.c -
+ vm_eval.c - Included into vm.c.
$Author$
created at: Sat May 24 16:02:32 JST 2008
@@ -57,7 +57,7 @@ static inline VALUE vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, i
VALUE
rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *cme, int kw_splat)
{
- const struct rb_callcache cc = VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
+ const struct rb_callcache cc = VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
return vm_call0_cc(ec, recv, id, argc, argv, &cc, kw_splat);
}
@@ -104,7 +104,7 @@ vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE
static VALUE
vm_call0_cme(rb_execution_context_t *ec, struct rb_calling_info *calling, const VALUE *argv, const rb_callable_method_entry_t *cme)
{
- calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
+ calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
return vm_call0_body(ec, calling, argv);
}
@@ -381,7 +381,7 @@ stack_check(rb_execution_context_t *ec)
if (!rb_ec_raised_p(ec, RAISED_STACKOVERFLOW) &&
rb_ec_stack_check(ec)) {
rb_ec_raised_set(ec, RAISED_STACKOVERFLOW);
- rb_ec_stack_overflow(ec, FALSE);
+ rb_ec_stack_overflow(ec, 0);
}
}
@@ -400,9 +400,9 @@ static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE rec
static inline enum method_missing_reason rb_method_call_status(rb_execution_context_t *ec, const rb_callable_method_entry_t *me, call_type scope, VALUE self);
static VALUE
-gccct_hash(VALUE klass, ID mid)
+gccct_hash(VALUE klass, VALUE box_value, ID mid)
{
- return (klass >> 3) ^ (VALUE)mid;
+ return ((klass ^ box_value) >> 3) ^ (VALUE)mid;
}
NOINLINE(static const struct rb_callcache *gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const struct rb_callinfo * ci));
@@ -417,6 +417,9 @@ gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const
vm_search_method_slowpath0(vm->self, &cd, klass);
+ if (UNLIKELY(!vm->global_cc_cache_table_used)) {
+ vm->global_cc_cache_table_used = true;
+ }
return vm->global_cc_cache_table[index] = cd.cc;
}
@@ -447,7 +450,8 @@ scope_to_ci(call_type scope, ID mid, int argc, struct rb_callinfo *ci)
static inline const struct rb_callcache *
gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci)
{
- VALUE klass;
+ VALUE klass, box_value;
+ const rb_box_t *box = rb_current_box();
if (!SPECIAL_CONST_P(recv)) {
klass = RBASIC_CLASS(recv);
@@ -457,8 +461,14 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct
klass = CLASS_OF(recv);
}
+ if (BOX_USER_P(box)) {
+ box_value = box->box_object;
+ }
+ else {
+ box_value = 0;
+ }
// search global method cache
- unsigned int index = (unsigned int)(gccct_hash(klass, mid) % VM_GLOBAL_CC_CACHE_TABLE_SIZE);
+ unsigned int index = (unsigned int)(gccct_hash(klass, box_value, mid) % VM_GLOBAL_CC_CACHE_TABLE_SIZE);
rb_vm_t *vm = rb_ec_vm_ptr(ec);
const struct rb_callcache *cc = vm->global_cc_cache_table[index];
@@ -483,6 +493,18 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct
return gccct_method_search_slowpath(vm, klass, index, ci);
}
+VALUE
+rb_gccct_clear_table(void)
+{
+ rb_vm_t *vm = GET_VM();
+ if (vm->global_cc_cache_table_used) {
+ const struct rb_callcache **const table = vm->global_cc_cache_table;
+ MEMZERO(table, struct rb_callcache *, VM_GLOBAL_CC_CACHE_TABLE_SIZE);
+ vm->global_cc_cache_table_used = false;
+ }
+ return Qnil;
+}
+
/**
* @internal
* calls the specified method.
@@ -1361,6 +1383,17 @@ rb_yield(VALUE val)
}
}
+VALUE
+rb_ec_yield(rb_execution_context_t *ec, VALUE val)
+{
+ if (UNDEF_P(val)) {
+ return vm_yield(ec, 0, NULL, RB_NO_KEYWORDS);
+ }
+ else {
+ return vm_yield(ec, 1, &val, RB_NO_KEYWORDS);
+ }
+}
+
#undef rb_yield_values
VALUE
rb_yield_values(int n, ...)
@@ -1504,13 +1537,6 @@ rb_iterate_internal(VALUE (* it_proc)(VALUE), VALUE data1,
GET_EC());
}
-VALUE
-rb_iterate(VALUE (* it_proc)(VALUE), VALUE data1,
- rb_block_call_func_t bl_proc, VALUE data2)
-{
- return rb_iterate_internal(it_proc, data1, bl_proc, data2);
-}
-
struct iter_method_arg {
VALUE obj;
ID mid;
@@ -1651,6 +1677,24 @@ get_eval_default_path(void)
return eval_default_path;
}
+static inline int
+compute_isolated_depth_from_ep(const VALUE *ep)
+{
+ int depth = 1;
+ while (1) {
+ if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) return depth;
+ if (VM_ENV_LOCAL_P(ep)) return 0;
+ ep = VM_ENV_PREV_EP(ep);
+ depth++;
+ }
+}
+
+static inline int
+compute_isolated_depth_from_block(const struct rb_block *blk)
+{
+ return compute_isolated_depth_from_ep(vm_block_ep(blk));
+}
+
static const rb_iseq_t *
pm_eval_make_iseq(VALUE src, VALUE fname, int line,
const struct rb_block *base_block)
@@ -1659,8 +1703,8 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
const rb_iseq_t *iseq = parent;
VALUE name = rb_fstring_lit("<compiled>");
- // Conditionally enable coverage depending on the current mode:
int coverage_enabled = ((rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) != 0) ? 1 : 0;
+ int isolated_depth = compute_isolated_depth_from_block(base_block);
if (!fname) {
fname = rb_source_location(&line);
@@ -1674,16 +1718,17 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
coverage_enabled = 0;
}
- pm_parse_result_t result = { 0 };
- pm_options_line_set(&result.options, line);
+ pm_parse_result_t result;
+ pm_parse_result_init(&result);
+ pm_options_line_set(result.options, line);
result.node.coverage_enabled = coverage_enabled;
- // Cout scopes, one for each parent iseq, plus one for our local scope
+ // Count scopes, one for each parent iseq, plus one for our local scope
int scopes_count = 0;
do {
scopes_count++;
} while ((iseq = ISEQ_BODY(iseq)->parent_iseq));
- pm_options_scopes_init(&result.options, scopes_count + 1);
+ pm_options_scopes_init(result.options, scopes_count + 1);
// Walk over the scope tree, adding known locals at the correct depths. The
// scope array should be deepest -> shallowest. so lower indexes in the
@@ -1705,19 +1750,19 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
VALUE iseq_value = (VALUE)iseq;
int locals_count = ISEQ_BODY(iseq)->local_table_size;
- pm_options_scope_t *options_scope = &result.options.scopes[scopes_count - scopes_index - 1];
+ pm_options_scope_t *options_scope = pm_options_scope_mut(result.options, scopes_count - scopes_index - 1);
pm_options_scope_init(options_scope, locals_count);
uint8_t forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
for (int local_index = 0; local_index < locals_count; local_index++) {
- pm_string_t *scope_local = &options_scope->locals[local_index];
+ pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index);
ID local = ISEQ_BODY(iseq)->local_table[local_index];
if (rb_is_local_id(local)) {
VALUE name_obj = rb_id2str(local);
const char *name = RSTRING_PTR(name_obj);
- size_t length = strlen(name);
+ size_t length = RSTRING_LEN(name_obj);
// Explicitly skip numbered parameters. These should not be sent
// into the eval.
@@ -1736,22 +1781,26 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
/* We need to duplicate the string because the Ruby string may
* be embedded so compaction could move the string and the pointer
* will change. */
- char *name_dup = xmalloc(length + 1);
- strlcpy(name_dup, name, length + 1);
+ char *name_dup = xmalloc(length);
+ MEMCPY(name_dup, name, char, length);
RB_GC_GUARD(name_obj);
pm_string_owned_init(scope_local, (uint8_t *) name_dup, length);
- } else if (local == idMULT) {
+ }
+ else if (local == idMULT) {
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS;
pm_string_constant_init(scope_local, FORWARDING_POSITIONALS_STR, 1);
- } else if (local == idPow) {
+ }
+ else if (local == idPow) {
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS;
pm_string_constant_init(scope_local, FORWARDING_KEYWORDS_STR, 1);
- } else if (local == idAnd) {
+ }
+ else if (local == idAnd) {
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_BLOCK;
pm_string_constant_init(scope_local, FORWARDING_BLOCK_STR, 1);
- } else if (local == idDot3) {
+ }
+ else if (local == idDot3) {
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_ALL;
pm_string_constant_init(scope_local, FORWARDING_ALL_STR, 1);
}
@@ -1768,7 +1817,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
// Add our empty local scope at the very end of the array for our eval
// scope's locals.
- pm_options_scope_init(&result.options.scopes[scopes_count], 0);
+ pm_options_scope_init(pm_options_scope_mut(result.options, scopes_count), 0);
VALUE script_lines;
VALUE error = pm_parse_string(&result, src, fname, ruby_vm_keep_script_lines ? &script_lines : NULL);
@@ -1789,17 +1838,16 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
pm_scope_node_t *parent_scope = ruby_xcalloc(1, sizeof(pm_scope_node_t));
RUBY_ASSERT(parent_scope != NULL);
- pm_options_scope_t *options_scope = &result.options.scopes[scopes_count - scopes_index - 1];
+ const pm_options_scope_t *options_scope = pm_options_scope(result.options, scopes_count - scopes_index - 1);
parent_scope->coverage_enabled = coverage_enabled;
- parent_scope->parser = &result.parser;
- parent_scope->index_lookup_table = st_init_numtable();
-
+ parent_scope->parser = result.parser;
int locals_count = ISEQ_BODY(iseq)->local_table_size;
+ pm_index_lookup_table_init_heap(&parent_scope->index_lookup_table, (int) pm_parser_constants_size(result.parser));
parent_scope->local_table_for_iseq_size = locals_count;
pm_constant_id_list_init(&parent_scope->locals);
for (int local_index = 0; local_index < locals_count; local_index++) {
- const pm_string_t *scope_local = &options_scope->locals[local_index];
+ const pm_string_t *scope_local = pm_options_scope_local(options_scope, local_index);
pm_constant_id_t constant_id = 0;
const uint8_t *source = pm_string_source(scope_local);
@@ -1821,18 +1869,18 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
constant_id = PM_CONSTANT_DOT3;
break;
default:
- constant_id = pm_constant_pool_insert_constant(&result.parser.constant_pool, source, length);
+ constant_id = pm_parser_constant_find(result.parser, source, length);
break;
}
}
else {
- constant_id = pm_constant_pool_insert_constant(&result.parser.constant_pool, source, length);
+ constant_id = pm_parser_constant_find(result.parser, source, length);
}
- st_insert(parent_scope->index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index);
+ pm_index_lookup_table_insert(&parent_scope->index_lookup_table, constant_id, local_index);
}
- pm_constant_id_list_append(&parent_scope->locals, constant_id);
+ pm_constant_id_list_append(result.arena, &parent_scope->locals, constant_id);
}
node->previous = parent_scope;
@@ -1850,14 +1898,13 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
#undef FORWARDING_ALL_STR
int error_state;
- iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, 0, &error_state);
+ iseq = pm_iseq_new_eval(&result.node, name, fname, Qnil, line, parent, isolated_depth, &error_state);
pm_scope_node_t *prev = result.node.previous;
while (prev) {
pm_scope_node_t *next = prev->previous;
- pm_constant_id_list_free(&prev->locals);
pm_scope_node_destroy(prev);
- ruby_xfree(prev);
+ SIZED_FREE(prev);
prev = next;
}
@@ -1886,27 +1933,9 @@ eval_make_iseq(VALUE src, VALUE fname, int line,
rb_iseq_t *iseq = NULL;
VALUE ast_value;
rb_ast_t *ast;
- int isolated_depth = 0;
- // Conditionally enable coverage depending on the current mode:
int coverage_enabled = (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) != 0;
-
- {
- int depth = 1;
- const VALUE *ep = vm_block_ep(base_block);
-
- while (1) {
- if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ISOLATED)) {
- isolated_depth = depth;
- break;
- }
- else if (VM_ENV_LOCAL_P(ep)) {
- break;
- }
- ep = VM_ENV_PREV_EP(ep);
- depth++;
- }
- }
+ int isolated_depth = compute_isolated_depth_from_block(base_block);
if (!fname) {
fname = rb_source_location(&line);
@@ -1960,9 +1989,13 @@ eval_string_with_cref(VALUE self, VALUE src, rb_cref_t *cref, VALUE file, int li
block.as.captured = *VM_CFP_TO_CAPTURED_BLOCK(cfp);
block.as.captured.self = self;
- block.as.captured.code.iseq = cfp->iseq;
+ block.as.captured.code.iseq = CFP_ISEQ(cfp);
block.type = block_type_iseq;
+ // EP is not escaped to the heap here, but captured and reused by another frame.
+ // ZJIT's locals are incompatible with it unlike YJIT's, so invalidate the ISEQ for ZJIT.
+ rb_zjit_invalidate_no_ep_escape(CFP_ISEQ(cfp));
+
iseq = eval_make_iseq(src, file, line, &block);
if (!iseq) {
rb_exc_raise(ec->errinfo);
@@ -2001,21 +2034,38 @@ eval_string_with_scope(VALUE scope, VALUE src, VALUE file, int line)
}
/*
- * call-seq:
- * eval(string [, binding [, filename [,lineno]]]) -> obj
+ * call-seq:
+ * eval(string, binding = nil, filename = default_filename, lineno = 1) -> obj
*
- * Evaluates the Ruby expression(s) in <em>string</em>. If
- * <em>binding</em> is given, which must be a Binding object, the
- * evaluation is performed in its context. If the optional
- * <em>filename</em> and <em>lineno</em> parameters are present, they
- * will be used when reporting syntax errors.
+ * Evaluates the Ruby expression(s) in +string+. Returns the result of the last
+ * expression.
*
- * def get_binding(str)
- * return binding
- * end
- * str = "hello"
- * eval "str + ' Fred'" #=> "hello Fred"
- * eval "str + ' Fred'", get_binding("bye") #=> "bye Fred"
+ * str = "Hello"
+ * eval("str + ' World'") # => "Hello World"
+ *
+ * If +binding+ is given, which must be a Binding object, the
+ * evaluation is performed in its context. Otherwise, the
+ * evaluation is performed in the context of the caller.
+ *
+ * def get_binding(str) = binding
+ * str = "Hello"
+ * eval("str + ' World'", get_binding("Bye")) # => "Bye World"
+ *
+ * If the optional +filename+ is given, it will be used as the
+ * filename of the evaluation (for <tt>__FILE__</tt> and errors).
+ * Otherwise, it will default to <tt>(eval at __FILE__:__LINE__)</tt>
+ * where <tt>__FILE__</tt> and <tt>__LINE__</tt> are the filename and
+ * line number of the caller, respectively.
+ *
+ * eval("puts __FILE__") # => "(eval at test.rb:1)"
+ * eval("puts __FILE__", nil, "foobar.rb") # => "foobar.rb"
+ *
+ * If the optional +lineno+ is given, it will be used as the
+ * line number of the evaluation (for <tt>__LINE__</tt> and errors).
+ * Otherwise, it will default to 1.
+ *
+ * eval("puts __LINE__") # => 1
+ * eval("puts __LINE__", nil, "foobar.rb", 10) # => 10
*/
VALUE
@@ -2122,6 +2172,17 @@ rb_eval_string_wrap(const char *str, int *pstate)
VALUE
rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat)
{
+ Check_Type(arg, T_ARRAY);
+ int argc = RARRAY_LENINT(arg);
+ const VALUE *argv = RARRAY_CONST_PTR(arg);
+ VALUE val = rb_eval_cmd_call_kw(cmd, argc, argv, kw_splat);
+ RB_GC_GUARD(arg);
+ return val;
+}
+
+VALUE
+rb_eval_cmd_call_kw(VALUE cmd, int argc, const VALUE *argv, int kw_splat)
+{
enum ruby_tag_type state;
volatile VALUE val = Qnil; /* OK */
rb_execution_context_t * volatile ec = GET_EC();
@@ -2129,8 +2190,7 @@ rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
if (!RB_TYPE_P(cmd, T_STRING)) {
- val = rb_funcallv_kw(cmd, idCall, RARRAY_LENINT(arg),
- RARRAY_CONST_PTR(arg), kw_splat);
+ val = rb_funcallv_kw(cmd, idCall, argc, argv, kw_splat);
}
else {
val = eval_string_with_cref(rb_vm_top_self(), cmd, NULL, 0, 0);
@@ -2332,29 +2392,66 @@ rb_obj_instance_exec(int argc, const VALUE *argv, VALUE self)
/*
* call-seq:
- * mod.class_eval(string [, filename [, lineno]]) -> obj
- * mod.class_eval {|mod| block } -> obj
- * mod.module_eval(string [, filename [, lineno]]) -> obj
- * mod.module_eval {|mod| block } -> obj
+ * class_eval(string, filename = nil, lineno = 1) -> obj
+ * class_eval { |mod| ... } -> obj
+ * module_eval(string, filename = nil, lineno = 1) -> obj
+ * module_eval { |mod| ... } -> obj
*
- * Evaluates the string or block in the context of _mod_, except that when
- * a block is given, constant/class variable lookup is not affected. This
- * can be used to add methods to a class. <code>module_eval</code> returns
- * the result of evaluating its argument. The optional _filename_ and
- * _lineno_ parameters set the text for error messages.
+ * Evaluates the +string+ or block in the context of +self+.
+ * Returns the result of the last expression.
*
- * class Thing
- * end
- * a = %q{def hello() "Hello there!" end}
- * Thing.module_eval(a)
- * puts Thing.new.hello()
- * Thing.module_eval("invalid code", "dummy", 123)
+ * When +string+ is given, evaluates the given string in the
+ * context of +self+:
*
- * <em>produces:</em>
+ * class Foo; end
*
- * Hello there!
- * dummy:123:in `module_eval': undefined local variable
- * or method `code' for Thing:Class
+ * Foo.module_eval("def greeting = puts 'hello'")
+ *
+ * Foo.new.greeting # => "hello"
+ *
+ * If the optional +filename+ is given, it will be used as the
+ * filename of the evaluation (for <tt>__FILE__</tt> and errors).
+ * Otherwise, it will default to <tt>(eval at __FILE__:__LINE__)</tt>
+ * where <tt>__FILE__</tt> and <tt>__LINE__</tt> are the filename and
+ * line number of the caller, respectively:
+ *
+ * class Foo; end
+ *
+ * Foo.module_eval("puts __FILE__") # => "(eval at ../test.rb:3)"
+ * Foo.module_eval("puts __FILE__", "foobar.rb") # => "foobar.rb"
+ *
+ * If the optional +lineno+ is given, it will be used as the
+ * line number of the evaluation (for <tt>__LINE__</tt> and errors).
+ * Otherwise, it will default to 1:
+ *
+ * class Foo; end
+ *
+ * Foo.module_eval("puts __LINE__") # => 1
+ * Foo.module_eval("puts __FILE__", nil, 10) # => 10
+ *
+ * When a block is given, evaluates the block in the context
+ * of +self+:
+ *
+ * class Foo; end
+ *
+ * Foo.module_eval do
+ * def greeting = puts "hello"
+ * end
+ *
+ * Foo.new.greeting
+ *
+ * However, constant and class variable lookup differs between
+ * +string+ and block. When +string+ is given, contant and class
+ * variables are looked up in the context of +self+. When a block
+ * is given, the context of the lookup is not changed:
+ *
+ * class Foo
+ * GREETING = "hello"
+ * end
+ *
+ * Foo.module_eval("puts GREETING") # => "hello"
+ *
+ * Foo.module_eval { puts GREETING } # => NameError: uninitialized constant GREETING
*/
static VALUE
@@ -2714,9 +2811,9 @@ rb_f_local_variables(VALUE _)
local_var_list_init(&vars);
while (cfp) {
- if (cfp->iseq) {
- for (i = 0; i < ISEQ_BODY(cfp->iseq)->local_table_size; i++) {
- local_var_list_add(&vars, ISEQ_BODY(cfp->iseq)->local_table[i]);
+ if (CFP_ISEQ(cfp)) {
+ for (i = 0; i < ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size; i++) {
+ local_var_list_add(&vars, ISEQ_BODY(CFP_ISEQ(cfp))->local_table[i]);
}
}
if (!VM_ENV_LOCAL_P(cfp->ep)) {
@@ -2790,10 +2887,11 @@ rb_current_realfilepath(void)
rb_control_frame_t *cfp = ec->cfp;
cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
if (cfp != NULL) {
- VALUE path = rb_iseq_realpath(cfp->iseq);
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
+ VALUE path = rb_iseq_realpath(iseq);
if (RTEST(path)) return path;
// eval context
- path = rb_iseq_path(cfp->iseq);
+ path = rb_iseq_path(iseq);
if (path == eval_default_path) {
return Qnil;
}
@@ -2819,7 +2917,7 @@ struct vm_ifunc *
rb_current_ifunc(void)
{
// Search VM_FRAME_MAGIC_IFUNC to see ifunc imemos put on the iseq field.
- VALUE ifunc = (VALUE)GET_EC()->cfp->iseq;
+ VALUE ifunc = (VALUE)CFP_ISEQ(GET_EC()->cfp);
RUBY_ASSERT_ALWAYS(imemo_type_p(ifunc, imemo_ifunc));
return (struct vm_ifunc *)ifunc;
}
diff --git a/vm_exec.c b/vm_exec.c
index 947d4dc421..bd8c170d76 100644
--- a/vm_exec.c
+++ b/vm_exec.c
@@ -11,9 +11,9 @@
#include <math.h>
-#if USE_YJIT
-// The number of instructions executed on vm_exec_core. --yjit-stats uses this.
-uint64_t rb_vm_insns_count = 0;
+#if USE_YJIT || USE_ZJIT
+// The number of instructions executed on vm_exec_core. --yjit-stats and --zjit-stats use this.
+uint64_t rb_vm_insn_count = 0;
#endif
#if VM_COLLECT_USAGE_DETAILS
diff --git a/vm_exec.h b/vm_exec.h
index c3b7d4e488..ecf8df3c7d 100644
--- a/vm_exec.h
+++ b/vm_exec.h
@@ -68,10 +68,10 @@ error !
#define INSN_ENTRY_SIG(insn) \
if (0) { \
ruby_debug_printf("exec: %s@(%"PRIdPTRDIFF", %"PRIdPTRDIFF")@%s:%u\n", #insn, \
- (reg_pc - ISEQ_BODY(reg_cfp->iseq)->iseq_encoded), \
- (reg_cfp->pc - ISEQ_BODY(reg_cfp->iseq)->iseq_encoded), \
- RSTRING_PTR(rb_iseq_path(reg_cfp->iseq)), \
- rb_iseq_line_no(reg_cfp->iseq, reg_pc - ISEQ_BODY(reg_cfp->iseq)->iseq_encoded)); \
+ (reg_pc - ISEQ_BODY(CFP_ISEQ(reg_cfp))->iseq_encoded), \
+ (reg_cfp->pc - ISEQ_BODY(CFP_ISEQ(reg_cfp))->iseq_encoded), \
+ RSTRING_PTR(rb_iseq_path(CFP_ISEQ(reg_cfp))), \
+ rb_iseq_line_no(CFP_ISEQ(reg_cfp), reg_pc - ISEQ_BODY(CFP_ISEQ(reg_cfp))->iseq_encoded)); \
}
#define INSN_DISPATCH_SIG(insn)
@@ -175,11 +175,22 @@ default: \
// Run the JIT from the interpreter
#define JIT_EXEC(ec, val) do { \
- rb_jit_func_t func; \
/* don't run tailcalls since that breaks FINISH */ \
- if (UNDEF_P(val) && GET_CFP() != ec->cfp && (func = jit_compile(ec))) { \
- val = func(ec, ec->cfp); \
- if (ec->tag->state) THROW_EXCEPTION(val); \
+ if (UNDEF_P(val) && GET_CFP() != ec->cfp) { \
+ rb_zjit_func_t zjit_entry; \
+ if (rb_yjit_enabled_p) { \
+ rb_jit_func_t func = yjit_compile(ec); \
+ if (func) { \
+ val = func(ec, ec->cfp); \
+ if (ec->tag->state) THROW_EXCEPTION(val); \
+ } \
+ } \
+ else if ((zjit_entry = (rb_zjit_func_t)rb_zjit_entry)) { \
+ rb_jit_func_t func = zjit_compile(ec); \
+ if (func) { \
+ val = zjit_entry(ec, ec->cfp, func); \
+ } \
+ } \
} \
} while (0)
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index cae307d743..f515662bf0 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1,6 +1,6 @@
/**********************************************************************
- vm_insnhelper.c - instruction helper functions.
+ vm_insnhelper.c - instruction helper functions. Included into vm.c.
$Author$
@@ -26,6 +26,7 @@
#include "internal/proc.h"
#include "internal/random.h"
#include "internal/variable.h"
+#include "internal/set_table.h"
#include "internal/struct.h"
#include "variable.h"
@@ -78,23 +79,18 @@ vm_stackoverflow(void)
ec_stack_overflow(GET_EC(), TRUE);
}
-NORETURN(void rb_ec_stack_overflow(rb_execution_context_t *ec, int crit));
void
-rb_ec_stack_overflow(rb_execution_context_t *ec, int crit)
+rb_ec_stack_overflow(rb_execution_context_t *ec, ruby_stack_overflow_critical_level crit)
{
if (rb_during_gc()) {
rb_bug("system stack overflow during GC. Faulty native extension?");
}
- if (crit) {
+ if (crit >= rb_stack_overflow_fatal) {
ec->raised_flag = RAISED_STACKOVERFLOW;
ec->errinfo = rb_ec_vm_ptr(ec)->special_exceptions[ruby_error_stackfatal];
EC_JUMP_TAG(ec, TAG_RAISE);
}
-#ifdef USE_SIGALTSTACK
- ec_stack_overflow(ec, TRUE);
-#else
- ec_stack_overflow(ec, FALSE);
-#endif
+ ec_stack_overflow(ec, crit < rb_stack_overflow_signal);
}
static inline void stack_check(rb_execution_context_t *ec);
@@ -132,7 +128,7 @@ callable_method_entry_p(const rb_callable_method_entry_t *cme)
return TRUE;
}
else {
- VM_ASSERT(IMEMO_TYPE_P((VALUE)cme, imemo_ment));
+ VM_ASSERT(IMEMO_TYPE_P((VALUE)cme, imemo_ment), "imemo_type:%s", rb_imemo_name(imemo_type((VALUE)cme)));
if (callable_class_p(cme->defined_class)) {
return TRUE;
@@ -174,7 +170,7 @@ vm_check_frame_detail(VALUE type, int req_block, int req_me, int req_cref, VALUE
}
else { /* cref or Qfalse */
if (cref_or_me != Qfalse && cref_or_me_type != imemo_cref) {
- if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC) && (cref_or_me_type == imemo_ment)) {
+ if (((type & VM_FRAME_FLAG_LAMBDA) || magic == VM_FRAME_MAGIC_IFUNC || magic == VM_FRAME_MAGIC_DUMMY) && (cref_or_me_type == imemo_ment)) {
/* ignore */
}
else {
@@ -409,14 +405,14 @@ vm_push_frame(rb_execution_context_t *ec,
*cfp = (const struct rb_control_frame_struct) {
.pc = pc,
.sp = sp,
- .iseq = iseq,
+ ._iseq = iseq,
.self = self,
.ep = sp - 1,
.block_code = NULL,
#if VM_DEBUG_BP_CHECK
.bp_check = sp,
#endif
- .jit_return = NULL
+ .jit_return = NULL,
};
/* Ensure the initialization of `*cfp` above never gets reordered with the update of `ec->cfp` below.
@@ -765,6 +761,25 @@ check_method_entry(VALUE obj, int can_be_svar)
}
}
+static rb_callable_method_entry_t *
+env_method_entry_unchecked(VALUE obj, int can_be_svar)
+{
+ if (obj == Qfalse) return NULL;
+
+ switch (imemo_type(obj)) {
+ case imemo_ment:
+ return (rb_callable_method_entry_t *)obj;
+ case imemo_cref:
+ return NULL;
+ case imemo_svar:
+ if (can_be_svar) {
+ return env_method_entry_unchecked(((struct vm_svar *)obj)->cref_or_me, FALSE);
+ }
+ default:
+ return NULL;
+ }
+}
+
const rb_callable_method_entry_t *
rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
{
@@ -779,6 +794,20 @@ rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
}
+const rb_callable_method_entry_t *
+rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp)
+{
+ const VALUE *ep = cfp->ep;
+ rb_callable_method_entry_t *me;
+
+ while (!VM_ENV_LOCAL_P_UNCHECKED(ep)) {
+ if ((me = env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
+ ep = VM_ENV_PREV_EP_UNCHECKED(ep);
+ }
+
+ return env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
+}
+
static const rb_iseq_t *
method_entry_iseqptr(const rb_callable_method_entry_t *me)
{
@@ -960,36 +989,16 @@ vm_get_const_key_cref(const VALUE *ep)
const rb_cref_t *key_cref = cref;
while (cref) {
- if (RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
- RCLASS_EXT(CREF_CLASS(cref))->cloned) {
+ if (CREF_DYNAMIC(cref)) {
return key_cref;
}
cref = CREF_NEXT(cref);
}
- /* does not include singleton class */
+ /* no dynamic singleton class or cloned class found */
return NULL;
}
-void
-rb_vm_rewrite_cref(rb_cref_t *cref, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr)
-{
- rb_cref_t *new_cref;
-
- while (cref) {
- if (CREF_CLASS(cref) == old_klass) {
- new_cref = vm_cref_new_use_prev(new_klass, METHOD_VISI_UNDEF, FALSE, cref, FALSE);
- *new_cref_ptr = new_cref;
- return;
- }
- new_cref = vm_cref_new_use_prev(CREF_CLASS(cref), METHOD_VISI_UNDEF, FALSE, cref, FALSE);
- cref = CREF_NEXT(cref);
- *new_cref_ptr = new_cref;
- new_cref_ptr = &new_cref->next;
- }
- *new_cref_ptr = NULL;
-}
-
static rb_cref_t *
vm_cref_push(const rb_execution_context_t *ec, VALUE klass, const VALUE *ep, int pushed_by_eval, int singleton)
{
@@ -1102,7 +1111,7 @@ vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, bool allow_
if (UNLIKELY(!rb_ractor_main_p())) {
if (!rb_ractor_shareable_p(val)) {
rb_raise(rb_eRactorIsolationError,
- "can not access non-shareable objects in constant %"PRIsVALUE"::%s by non-main ractor.", rb_class_path(klass), rb_id2name(id));
+ "can not access non-shareable objects in constant %"PRIsVALUE"::%"PRIsVALUE" by non-main ractor.", rb_class_path(klass), rb_id2str(id));
}
}
return val;
@@ -1190,50 +1199,24 @@ vm_get_cvar_base(const rb_cref_t *cref, const rb_control_frame_t *cfp, int top_l
return klass;
}
-ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id));
-static inline void
-fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id)
-{
- if (is_attr) {
- vm_cc_attr_index_set(cc, index, shape_id);
- }
- else {
- vm_ic_attr_index_set(iseq, ic, index, shape_id);
- }
-}
-
#define ractor_incidental_shareable_p(cond, val) \
(!(cond) || rb_ractor_shareable_p(val))
#define ractor_object_incidental_shareable_p(obj, val) \
ractor_incidental_shareable_p(rb_ractor_shareable_p(obj), val)
-#define ATTR_INDEX_NOT_SET (attr_index_t)-1
-
ALWAYS_INLINE(static VALUE vm_getivar(VALUE, ID, const rb_iseq_t *, IVC, const struct rb_callcache *, int, VALUE));
static inline VALUE
vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, VALUE default_value)
{
+ VALUE fields_obj;
#if OPT_IC_FOR_IVAR
- VALUE val = Qundef;
- shape_id_t shape_id;
- VALUE * ivar_list;
-
if (SPECIAL_CONST_P(obj)) {
return default_value;
}
-#if SHAPE_IN_BASIC_FLAGS
- shape_id = RBASIC_SHAPE_ID(obj);
-#endif
-
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- ivar_list = ROBJECT_IVPTR(obj);
- VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true);
-
-#if !SHAPE_IN_BASIC_FLAGS
- shape_id = ROBJECT_SHAPE_ID(obj);
-#endif
+ fields_obj = obj;
break;
case T_CLASS:
case T_MODULE:
@@ -1254,46 +1237,30 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
}
}
- ivar_list = RCLASS_IVPTR(obj);
-
-#if !SHAPE_IN_BASIC_FLAGS
- shape_id = RCLASS_SHAPE_ID(obj);
-#endif
-
+ fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
break;
}
default:
- if (FL_TEST_RAW(obj, FL_EXIVAR)) {
- struct gen_ivtbl *ivtbl;
- rb_gen_ivtbl_get(obj, id, &ivtbl);
-#if !SHAPE_IN_BASIC_FLAGS
- shape_id = ivtbl->shape_id;
-#endif
- ivar_list = ivtbl->as.shape.ivptr;
- }
- else {
- return default_value;
- }
+ fields_obj = rb_obj_fields(obj, id);
}
- shape_id_t cached_id;
- attr_index_t index;
-
- if (is_attr) {
- vm_cc_atomic_shape_and_index(cc, &cached_id, &index);
- }
- else {
- vm_ic_atomic_shape_and_index(ic, &cached_id, &index);
+ if (!fields_obj) {
+ return default_value;
}
- if (LIKELY(cached_id == shape_id)) {
- RUBY_ASSERT(cached_id != OBJ_TOO_COMPLEX_SHAPE_ID);
+ VALUE val = Qundef;
+
+ shape_id_t shape_id = RBASIC_SHAPE_ID_FOR_READ(fields_obj);
+ VALUE *ivar_list = rb_imemo_fields_ptr(fields_obj);
+
+ rb_getivar_cache cache = rb_getivar_cache_unpack(vm_cache_attr_index_atomic_read(is_attr, ic, cc));
- if (index == ATTR_INDEX_NOT_SET) {
+ if (LIKELY(cache.shape_offset == shape_id)) {
+ if (cache.index == ATTR_INDEX_NOT_SET) {
return default_value;
}
- val = ivar_list[index];
+ val = ivar_list[cache.index];
#if USE_DEBUG_COUNTER
RB_DEBUG_COUNTER_INC(ivar_get_ic_hit);
@@ -1306,7 +1273,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
else { // cache miss case
#if USE_DEBUG_COUNTER
if (is_attr) {
- if (cached_id != INVALID_SHAPE_ID) {
+ if (cache.shape_offset != INVALID_SHAPE_ID) {
RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_set);
}
else {
@@ -1314,7 +1281,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
}
}
else {
- if (cached_id != INVALID_SHAPE_ID) {
+ if (cache.shape_offset != INVALID_SHAPE_ID) {
RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_set);
}
else {
@@ -1328,61 +1295,41 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
}
#endif
- if (shape_id == OBJ_TOO_COMPLEX_SHAPE_ID) {
- st_table *table = NULL;
- switch (BUILTIN_TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- table = (st_table *)RCLASS_IVPTR(obj);
- break;
-
- case T_OBJECT:
- table = ROBJECT_IV_HASH(obj);
- break;
+ if (UNLIKELY(rb_shape_complex_p(shape_id))) {
+ st_table *table = (st_table *)ivar_list;
- default: {
- struct gen_ivtbl *ivtbl;
- if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
- table = ivtbl->as.complex.table;
- }
- break;
- }
- }
+ RUBY_ASSERT(table);
+ RUBY_ASSERT(table == rb_imemo_fields_complex_tbl(fields_obj));
- if (!table || !st_lookup(table, id, &val)) {
+ if (!st_lookup(table, id, &val)) {
val = default_value;
}
}
else {
- shape_id_t previous_cached_id = cached_id;
- if (rb_shape_get_iv_index_with_hint(shape_id, id, &index, &cached_id)) {
- // This fills in the cache with the shared cache object.
- // "ent" is the shared cache object
- if (cached_id != previous_cached_id) {
- fill_ivar_cache(iseq, ic, cc, is_attr, index, cached_id);
+ shape_id_t previous_cached_offset = cache.shape_offset;
+ if (rb_shape_get_iv_index_with_hint(shape_id, id, &cache.index, &cache.shape_offset)) {
+ if (cache.shape_offset != previous_cached_offset) {
+ RUBY_ASSERT(!rb_shape_complex_p(cache.shape_offset));
+ RUBY_ASSERT(cache.shape_offset != INVALID_SHAPE_ID);
+
+ uint64_t packed_cache = rb_getivar_cache_pack(cache.shape_offset, cache.index);
+ vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
}
- if (index == ATTR_INDEX_NOT_SET) {
+ if (cache.index == ATTR_INDEX_NOT_SET) {
val = default_value;
}
else {
// We fetched the ivar list above
- val = ivar_list[index];
+ val = ivar_list[cache.index];
RUBY_ASSERT(!UNDEF_P(val));
}
}
else {
- if (is_attr) {
- vm_cc_attr_index_initialize(cc, shape_id);
- }
- else {
- vm_ic_attr_index_initialize(ic, shape_id);
- }
-
+ vm_cache_attr_index_set(is_attr, ic, cc, rb_getivar_cache_pack(shape_id, ATTR_INDEX_NOT_SET));
val = default_value;
}
}
-
}
if (!UNDEF_P(default_value)) {
@@ -1403,20 +1350,6 @@ general_path:
}
}
-static void
-populate_cache(attr_index_t index, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr)
-{
- RUBY_ASSERT(next_shape_id != OBJ_TOO_COMPLEX_SHAPE_ID);
-
- // Cache population code
- if (is_attr) {
- vm_cc_attr_index_set(cc, index, next_shape_id);
- }
- else {
- vm_ic_attr_index_set(iseq, ic, index, next_shape_id);
- }
-}
-
ALWAYS_INLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr));
NOINLINE(static VALUE vm_setivar_slowpath_ivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic));
NOINLINE(static VALUE vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache *cc));
@@ -1427,22 +1360,22 @@ vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic,
#if OPT_IC_FOR_IVAR
RB_DEBUG_COUNTER_INC(ivar_set_ic_miss);
- if (BUILTIN_TYPE(obj) == T_OBJECT) {
- rb_check_frozen(obj);
-
- attr_index_t index = rb_obj_ivar_set(obj, id, val);
-
- shape_id_t next_shape_id = ROBJECT_SHAPE_ID(obj);
+ rb_check_frozen(obj);
- if (next_shape_id != OBJ_TOO_COMPLEX_SHAPE_ID) {
- populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr);
- }
+ shape_id_t previous_shape_id = RBASIC_SHAPE_ID(obj);
+ attr_index_t index = rb_ivar_set_index(obj, id, val);
+ shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj);
- RB_DEBUG_COUNTER_INC(ivar_set_obj_miss);
- return val;
+ if (!rb_shape_complex_p(next_shape_id)) {
+ uint64_t packed_cache = rb_setivar_cache_pack(RSHAPE_OFFSET(previous_shape_id), RSHAPE_OFFSET(next_shape_id), index);
+ vm_cache_attr_index_set(is_attr, ic, cc, packed_cache);
}
-#endif
+
+ RB_DEBUG_COUNTER_INC(ivar_set_obj_miss);
+ return val;
+#else
return rb_ivar_set(obj, id, val);
+#endif
}
static VALUE
@@ -1457,56 +1390,66 @@ vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache
return vm_setivar_slowpath(obj, id, val, NULL, NULL, cc, true);
}
-NOINLINE(static VALUE vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index));
+NOINLINE(static VALUE vm_setivar_class(VALUE obj, VALUE val, rb_setivar_cache cache));
static VALUE
-vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index)
+vm_setivar_class(VALUE obj, VALUE val, rb_setivar_cache cache)
{
-#if SHAPE_IN_BASIC_FLAGS
- shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
-#else
- shape_id_t shape_id = rb_generic_shape_id(obj);
-#endif
+ if (UNLIKELY(!rb_ractor_main_p())) {
+ return Qundef;
+ }
- struct gen_ivtbl *ivtbl = 0;
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (UNLIKELY(!fields_obj)) {
+ return Qundef;
+ }
- // Cache hit case
- if (shape_id == dest_shape_id) {
- RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
+ shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
+ shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, cache);
+ if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
+ return Qundef;
}
- else if (dest_shape_id != INVALID_SHAPE_ID) {
- rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
- rb_shape_t *dest_shape = rb_shape_get_shape_by_id(dest_shape_id);
- if (shape_id == dest_shape->parent_id && dest_shape->edge_name == id && shape->capacity == dest_shape->capacity) {
- RUBY_ASSERT(index < dest_shape->capacity);
- }
- else {
- return Qundef;
- }
+ RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
+
+ if (shape_id != dest_shape_id) {
+ // The dest_shape_id comes from the fields_obj
+ RBASIC_SET_SHAPE_ID(obj, SHAPE_ID_LAYOUT_RCLASS | (dest_shape_id & ~SHAPE_ID_LAYOUT_MASK));
+ RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id);
}
- else {
+
+ RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
+
+ return val;
+}
+
+NOINLINE(static VALUE vm_setivar_default(VALUE obj, ID id, VALUE val, rb_setivar_cache cache));
+static VALUE
+vm_setivar_default(VALUE obj, ID id, VALUE val, rb_setivar_cache cache)
+{
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, cache);
+ if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
return Qundef;
}
- rb_gen_ivtbl_get(obj, 0, &ivtbl);
+ VALUE fields_obj = rb_obj_fields(obj, id);
+ RUBY_ASSERT(fields_obj);
+ RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val);
if (shape_id != dest_shape_id) {
-#if SHAPE_IN_BASIC_FLAGS
RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
-#else
- ivtbl->shape_id = dest_shape_id;
-#endif
+ // The dest_shape_id comes from the owner, but fields_obj must always
+ // have layout RObject, so give the fields_object the right layout.
+ RBASIC_SET_SHAPE_ID(fields_obj, rb_shape_id_with_robject_layout(dest_shape_id));
}
- RB_OBJ_WRITE(obj, &ivtbl->as.shape.ivptr[index], val);
-
RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
return val;
}
static inline VALUE
-vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index)
+vm_setivar(VALUE obj, VALUE val, rb_setivar_cache cache)
{
#if OPT_IC_FOR_IVAR
switch (BUILTIN_TYPE(obj)) {
@@ -1514,38 +1457,16 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i
{
VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj));
- shape_id_t shape_id = ROBJECT_SHAPE_ID(obj);
- RUBY_ASSERT(dest_shape_id != OBJ_TOO_COMPLEX_SHAPE_ID);
-
- if (LIKELY(shape_id == dest_shape_id)) {
- RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
- VM_ASSERT(!rb_ractor_shareable_p(obj));
- }
- else if (dest_shape_id != INVALID_SHAPE_ID) {
- rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
- rb_shape_t *dest_shape = rb_shape_get_shape_by_id(dest_shape_id);
- shape_id_t source_shape_id = dest_shape->parent_id;
-
- if (shape_id == source_shape_id && dest_shape->edge_name == id && shape->capacity == dest_shape->capacity) {
- RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID);
-
- ROBJECT_SET_SHAPE_ID(obj, dest_shape_id);
-
- RUBY_ASSERT(rb_shape_get_next_iv_shape(rb_shape_get_shape_by_id(source_shape_id), id) == dest_shape);
- RUBY_ASSERT(index < dest_shape->capacity);
- }
- else {
- break;
- }
- }
- else {
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
+ shape_id_t dest_shape_id = rb_setivar_cache_revalidate(shape_id, cache);
+ if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) {
break;
}
- VALUE *ptr = ROBJECT_IVPTR(obj);
-
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
- RB_OBJ_WRITE(obj, &ptr[index], val);
+ RB_OBJ_WRITE(obj, &ROBJECT_FIELDS(obj)[cache.index], val);
+ if (shape_id != dest_shape_id) {
+ RBASIC_SET_SHAPE_ID(obj, dest_shape_id);
+ }
RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
RB_DEBUG_COUNTER_INC(ivar_set_obj_hit);
@@ -1573,26 +1494,23 @@ update_classvariable_cache(const rb_iseq_t *iseq, VALUE klass, ID id, const rb_c
defined_class = RBASIC(defined_class)->klass;
}
- struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
+ VALUE rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
if (!rb_cvc_tbl) {
rb_bug("the cvc table should be set");
}
VALUE ent_data;
- if (!rb_id_table_lookup(rb_cvc_tbl, id, &ent_data)) {
+ if (!rb_marked_id_table_lookup(rb_cvc_tbl, id, &ent_data)) {
rb_bug("should have cvar cache entry");
}
struct rb_cvar_class_tbl_entry *ent = (void *)ent_data;
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
- ent->cref = cref;
- ic->entry = ent;
+ RB_OBJ_WRITE((VALUE)ent, &ent->cref, cref);
+ RB_OBJ_WRITE(iseq, &ic->entry, ent);
RUBY_ASSERT(BUILTIN_TYPE((VALUE)cref) == T_IMEMO && IMEMO_TYPE_P(cref, imemo_cref));
- RB_OBJ_WRITTEN(iseq, Qundef, ent->cref);
- RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value);
- RB_OBJ_WRITTEN(ent->class_value, Qundef, ent->cref);
return cvar_value;
}
@@ -1649,6 +1567,7 @@ rb_vm_setclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID
vm_setclassvariable(iseq, cfp, id, val, ic);
}
+ALWAYS_INLINE(static VALUE vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic));
static inline VALUE
vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic)
{
@@ -1663,18 +1582,19 @@ vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC i
return;
}
- shape_id_t dest_shape_id;
- attr_index_t index;
- vm_ic_atomic_shape_and_index(ic, &dest_shape_id, &index);
-
- if (UNLIKELY(UNDEF_P(vm_setivar(obj, id, val, dest_shape_id, index)))) {
+ rb_setivar_cache cache = rb_setivar_cache_unpack(vm_ic_atomic_cache_read(ic));
+ if (UNLIKELY(UNDEF_P(vm_setivar(obj, val, cache)))) {
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
+ break;
case T_CLASS:
case T_MODULE:
+ if (!UNDEF_P(vm_setivar_class(obj, val, cache))) {
+ return;
+ }
break;
default:
- if (!UNDEF_P(vm_setivar_default(obj, id, val, dest_shape_id, index))) {
+ if (!UNDEF_P(vm_setivar_default(obj, id, val, cache))) {
return;
}
}
@@ -1688,6 +1608,12 @@ rb_vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IV
vm_setinstancevariable(iseq, obj, id, val, ic);
}
+VALUE
+rb_vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic)
+{
+ return vm_getinstancevariable(iseq, obj, id, ic);
+}
+
static VALUE
vm_throw_continue(const rb_execution_context_t *ec, VALUE err)
{
@@ -1725,16 +1651,16 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c
escape_cfp = reg_cfp;
while (ISEQ_BODY(base_iseq)->type != ISEQ_TYPE_BLOCK) {
- if (ISEQ_BODY(escape_cfp->iseq)->type == ISEQ_TYPE_CLASS) {
+ if (ISEQ_BODY(CFP_ISEQ(escape_cfp))->type == ISEQ_TYPE_CLASS) {
escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
ep = escape_cfp->ep;
- base_iseq = escape_cfp->iseq;
+ base_iseq = CFP_ISEQ(escape_cfp);
}
else {
ep = VM_ENV_PREV_EP(ep);
base_iseq = ISEQ_BODY(base_iseq)->parent_iseq;
escape_cfp = rb_vm_search_cf_from_ep(ec, escape_cfp, ep);
- VM_ASSERT(escape_cfp->iseq == base_iseq);
+ VM_ASSERT(CFP_ISEQ(escape_cfp) == base_iseq);
}
}
@@ -1748,8 +1674,8 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c
while (escape_cfp < eocfp) {
if (escape_cfp->ep == ep) {
- const rb_iseq_t *const iseq = escape_cfp->iseq;
- const VALUE epc = escape_cfp->pc - ISEQ_BODY(iseq)->iseq_encoded;
+ const rb_iseq_t *const iseq = CFP_ISEQ(escape_cfp);
+ const VALUE epc = CFP_PC(escape_cfp) - ISEQ_BODY(iseq)->iseq_encoded;
const struct iseq_catch_table *const ct = ISEQ_BODY(iseq)->catch_table;
unsigned int i;
@@ -1808,7 +1734,7 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c
if (lep == target_lep &&
VM_FRAME_RUBYFRAME_P(escape_cfp) &&
- ISEQ_BODY(escape_cfp->iseq)->type == ISEQ_TYPE_CLASS) {
+ ISEQ_BODY(CFP_ISEQ(escape_cfp))->type == ISEQ_TYPE_CLASS) {
in_class_frame = 1;
target_lep = 0;
}
@@ -1838,7 +1764,7 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c
}
}
else if (VM_FRAME_RUBYFRAME_P(escape_cfp)) {
- switch (ISEQ_BODY(escape_cfp->iseq)->type) {
+ switch (ISEQ_BODY(CFP_ISEQ(escape_cfp))->type) {
case ISEQ_TYPE_TOP:
case ISEQ_TYPE_MAIN:
if (toplevel) {
@@ -1852,7 +1778,7 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c
}
break;
case ISEQ_TYPE_EVAL: {
- const rb_iseq_t *is = escape_cfp->iseq;
+ const rb_iseq_t *is = CFP_ISEQ(escape_cfp);
enum rb_iseq_type t = ISEQ_BODY(is)->type;
while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE || t == ISEQ_TYPE_EVAL) {
if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
@@ -1870,7 +1796,7 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c
}
}
- if (escape_cfp->ep == target_lep && ISEQ_BODY(escape_cfp->iseq)->type == ISEQ_TYPE_METHOD) {
+ if (escape_cfp->ep == target_lep && ISEQ_BODY(CFP_ISEQ(escape_cfp))->type == ISEQ_TYPE_METHOD) {
if (target_ep == NULL) {
goto valid_return;
}
@@ -1992,46 +1918,46 @@ static VALUE vm_call_general(rb_execution_context_t *ec, rb_control_frame_t *reg
static VALUE vm_mtbl_dump(VALUE klass, ID target_mid);
static struct rb_class_cc_entries *
-vm_ccs_create(VALUE klass, struct rb_id_table *cc_tbl, ID mid, const rb_callable_method_entry_t *cme)
+vm_ccs_create(VALUE klass, VALUE cc_tbl, ID mid, const rb_callable_method_entry_t *cme)
{
- struct rb_class_cc_entries *ccs = ALLOC(struct rb_class_cc_entries);
+ int initial_capa = 2;
+ struct rb_class_cc_entries *ccs = ruby_xmalloc(vm_ccs_alloc_size(initial_capa));
#if VM_CHECK_MODE > 0
ccs->debug_sig = ~(VALUE)ccs;
#endif
- ccs->capa = 0;
+ ccs->capa = initial_capa;
ccs->len = 0;
ccs->cme = cme;
METHOD_ENTRY_CACHED_SET((rb_callable_method_entry_t *)cme);
- ccs->entries = NULL;
- rb_id_table_insert(cc_tbl, mid, (VALUE)ccs);
- RB_OBJ_WRITTEN(klass, Qundef, cme);
+ rb_managed_id_table_insert(cc_tbl, mid, (VALUE)ccs);
+ RB_OBJ_WRITTEN(cc_tbl, Qundef, cme);
return ccs;
}
static void
-vm_ccs_push(VALUE klass, struct rb_class_cc_entries *ccs, const struct rb_callinfo *ci, const struct rb_callcache *cc)
+vm_ccs_push(VALUE cc_tbl, ID mid, struct rb_class_cc_entries *ccs, const struct rb_callinfo *ci, const struct rb_callcache *cc)
{
if (! vm_cc_markable(cc)) {
return;
}
if (UNLIKELY(ccs->len == ccs->capa)) {
- if (ccs->capa == 0) {
- ccs->capa = 1;
- ccs->entries = ALLOC_N(struct rb_class_cc_entries_entry, ccs->capa);
- }
- else {
- ccs->capa *= 2;
- REALLOC_N(ccs->entries, struct rb_class_cc_entries_entry, ccs->capa);
- }
+ RUBY_ASSERT(ccs->capa > 0);
+ ccs->capa *= 2;
+ ccs = ruby_xrealloc(ccs, vm_ccs_alloc_size(ccs->capa));
+#if VM_CHECK_MODE > 0
+ ccs->debug_sig = ~(VALUE)ccs;
+#endif
+ // GC?
+ rb_managed_id_table_insert(cc_tbl, mid, (VALUE)ccs);
}
VM_ASSERT(ccs->len < ccs->capa);
const int pos = ccs->len++;
ccs->entries[pos].argc = vm_ci_argc(ci);
ccs->entries[pos].flag = vm_ci_flag(ci);
- RB_OBJ_WRITE(klass, &ccs->entries[pos].cc, cc);
+ RB_OBJ_WRITE(cc_tbl, &ccs->entries[pos].cc, cc);
if (RB_DEBUG_COUNTER_SETMAX(ccs_maxlen, ccs->len)) {
// for tuning
@@ -2073,25 +1999,120 @@ vm_ccs_verify(struct rb_class_cc_entries *ccs, ID mid, VALUE klass)
const rb_callable_method_entry_t *rb_check_overloaded_cme(const rb_callable_method_entry_t *cme, const struct rb_callinfo * const ci);
+static void
+vm_evict_cc(VALUE klass, VALUE cc_tbl, ID mid)
+{
+ ASSERT_vm_locking();
+
+ if (rb_multi_ractor_p()) {
+ if (RCLASS_WRITABLE_CC_TBL(klass) != cc_tbl) {
+ // Another ractor updated the CC table while we were waiting on the VM lock.
+ // We have to retry.
+ return;
+ }
+
+ VALUE ccs_obj = 0;
+ rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj);
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_obj;
+
+ if (!ccs || !METHOD_ENTRY_INVALIDATED(ccs->cme)) {
+ // Another ractor replaced that entry while we were waiting on the VM lock.
+ return;
+ }
+
+ VALUE new_table = rb_vm_cc_table_dup(cc_tbl);
+ rb_vm_cc_table_delete(new_table, mid);
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), new_table);
+ }
+ else {
+ rb_vm_cc_table_delete(cc_tbl, mid);
+ }
+}
+
static const struct rb_callcache *
-vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
+vm_populate_cc(VALUE klass, const struct rb_callinfo * const ci, ID mid)
{
- const ID mid = vm_ci_mid(ci);
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+ ASSERT_vm_locking();
+
+ RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs);
+
+ const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
+
+ VM_ASSERT(cme == NULL || IMEMO_TYPE_P(cme, imemo_ment));
+
+ if (cme == NULL) {
+ // undef or not found: can't cache the information
+ VM_ASSERT(vm_cc_cme(&vm_empty_cc) == NULL);
+ return &vm_empty_cc;
+ }
+
+ VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
+ const VALUE original_cc_table = cc_tbl;
+ if (!cc_tbl) {
+ // Is this possible after rb_callable_method_entry ?
+ cc_tbl = rb_vm_cc_table_create(1);
+ }
+ else if (rb_multi_ractor_p()) {
+ cc_tbl = rb_vm_cc_table_dup(cc_tbl);
+ }
+
+ VM_ASSERT(cme == rb_callable_method_entry(klass, mid));
+
+ METHOD_ENTRY_CACHED_SET((struct rb_callable_method_entry_struct *)cme);
+
+ VM_ASSERT(cc_tbl);
+
struct rb_class_cc_entries *ccs = NULL;
- VALUE ccs_data;
+ {
+ VALUE ccs_obj;
+ if (UNLIKELY(rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj))) {
+ ccs = (struct rb_class_cc_entries *)ccs_obj;
+ }
+ else {
+ // TODO: required?
+ ccs = vm_ccs_create(klass, cc_tbl, mid, cme);
+ }
+ }
+
+ cme = rb_check_overloaded_cme(cme, ci);
+
+ const struct rb_callcache *cc = vm_cc_new(klass, cme, vm_call_general, cc_type_normal);
+ vm_ccs_push(cc_tbl, mid, ccs, ci, cc);
+
+ VM_ASSERT(vm_cc_cme(cc) != NULL);
+ VM_ASSERT(cme->called_id == mid);
+ VM_ASSERT(vm_cc_cme(cc)->called_id == mid);
+
+ if (original_cc_table != cc_tbl) {
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASS_WRITABLE_CC_TBL(klass), cc_tbl);
+ }
+
+ return cc;
+}
+
+static const struct rb_callcache *
+vm_lookup_cc(const VALUE klass, const struct rb_callinfo * const ci, ID mid)
+{
+ VALUE cc_tbl;
+ struct rb_class_cc_entries *ccs;
+retry:
+ cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass));
+ ccs = NULL;
if (cc_tbl) {
// CCS data is keyed on method id, so we don't need the method id
// for doing comparisons in the `for` loop below.
- if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
- ccs = (struct rb_class_cc_entries *)ccs_data;
+
+ VALUE ccs_obj;
+ if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_obj)) {
+ ccs = (struct rb_class_cc_entries *)ccs_obj;
const int ccs_len = ccs->len;
if (UNLIKELY(METHOD_ENTRY_INVALIDATED(ccs->cme))) {
- rb_vm_ccs_free(ccs);
- rb_id_table_delete(cc_tbl, mid);
- ccs = NULL;
+ RB_VM_LOCKING() {
+ vm_evict_cc(klass, cc_tbl, mid);
+ }
+ goto retry;
}
else {
VM_ASSERT(vm_ccs_verify(ccs, mid, klass));
@@ -2122,58 +2143,33 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
}
}
}
- else {
- cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2);
- }
-
- RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs);
- const rb_callable_method_entry_t *cme;
-
- if (ccs) {
- cme = ccs->cme;
- cme = UNDEFINED_METHOD_ENTRY_P(cme) ? NULL : cme;
-
- VM_ASSERT(cme == rb_callable_method_entry(klass, mid));
- }
- else {
- cme = rb_callable_method_entry(klass, mid);
- }
+ RB_GC_GUARD(cc_tbl);
+ return NULL;
+}
- VM_ASSERT(cme == NULL || IMEMO_TYPE_P(cme, imemo_ment));
+static const struct rb_callcache *
+vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
+{
+ const ID mid = vm_ci_mid(ci);
- if (cme == NULL) {
- // undef or not found: can't cache the information
- VM_ASSERT(vm_cc_cme(&vm_empty_cc) == NULL);
- return &vm_empty_cc;
+ const struct rb_callcache *cc = vm_lookup_cc(klass, ci, mid);
+ if (cc) {
+ return cc;
}
- VM_ASSERT(cme == rb_callable_method_entry(klass, mid));
-
- METHOD_ENTRY_CACHED_SET((struct rb_callable_method_entry_struct *)cme);
-
- if (ccs == NULL) {
- VM_ASSERT(cc_tbl != NULL);
-
- if (LIKELY(rb_id_table_lookup(cc_tbl, mid, &ccs_data))) {
- // rb_callable_method_entry() prepares ccs.
- ccs = (struct rb_class_cc_entries *)ccs_data;
+ RB_VM_LOCKING() {
+ if (rb_multi_ractor_p()) {
+ // The CC may have been populated by another ractor while we were waiting on the lock,
+ // so we must lookup a second time.
+ cc = vm_lookup_cc(klass, ci, mid);
}
- else {
- // TODO: required?
- ccs = vm_ccs_create(klass, cc_tbl, mid, cme);
+
+ if (!cc) {
+ cc = vm_populate_cc(klass, ci, mid);
}
}
- cme = rb_check_overloaded_cme(cme, ci);
-
- const struct rb_callcache *cc = vm_cc_new(klass, cme, vm_call_general, cc_type_normal);
- vm_ccs_push(klass, ccs, ci, cc);
-
- VM_ASSERT(vm_cc_cme(cc) != NULL);
- VM_ASSERT(cme->called_id == mid);
- VM_ASSERT(vm_cc_cme(cc)->called_id == mid);
-
return cc;
}
@@ -2184,18 +2180,14 @@ rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass)
VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
- RB_VM_LOCK_ENTER();
- {
- cc = vm_search_cc(klass, ci);
+ cc = vm_search_cc(klass, ci);
- VM_ASSERT(cc);
- VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
- VM_ASSERT(cc == vm_cc_empty() || cc->klass == klass);
- VM_ASSERT(cc == vm_cc_empty() || callable_method_entry_p(vm_cc_cme(cc)));
- VM_ASSERT(cc == vm_cc_empty() || !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)));
- VM_ASSERT(cc == vm_cc_empty() || vm_cc_cme(cc)->called_id == vm_ci_mid(ci));
- }
- RB_VM_LOCK_LEAVE();
+ VM_ASSERT(cc);
+ VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
+ VM_ASSERT(cc == vm_cc_empty() || cc->klass == klass);
+ VM_ASSERT(cc == vm_cc_empty() || callable_method_entry_p(vm_cc_cme(cc)));
+ VM_ASSERT(cc == vm_cc_empty() || !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)));
+ VM_ASSERT(cc == vm_cc_empty() || vm_cc_cme(cc)->called_id == vm_ci_mid(ci));
return cc;
}
@@ -2244,12 +2236,14 @@ vm_search_method_slowpath0(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
return cc;
}
-ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass));
+ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass));
static const struct rb_callcache *
-vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
+vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass)
{
const struct rb_callcache *cc = cd->cc;
+ VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
+
#if OPT_INLINE_METHOD_CACHE
if (LIKELY(vm_cc_class_check(cc, klass))) {
if (LIKELY(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc)))) {
@@ -2268,17 +2262,28 @@ vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
}
#endif
- return vm_search_method_slowpath0(cd_owner, cd, klass);
+ return vm_search_method_slowpath0((VALUE)CFP_ISEQ(reg_cfp), cd, klass);
}
-static const struct rb_callcache *
-vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
+static const struct rb_callable_method_entry_struct *
+vm_search_method(struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE recv)
{
VALUE klass = CLASS_OF(recv);
VM_ASSERT(klass != Qfalse);
VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
- return vm_search_method_fastpath(cd_owner, cd, klass);
+ const struct rb_callcache *cc = vm_search_method_fastpath(reg_cfp, cd, klass);
+ return vm_cc_cme(cc);
+}
+
+const struct rb_callable_method_entry_struct *
+rb_zjit_vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
+{
+ // Called from ZJIT with the compile-time iseq, which may differ from
+ // the iseq on the current CFP. Use the slowpath to avoid stale caches.
+ VALUE klass = CLASS_OF(recv);
+ const struct rb_callcache *cc = vm_search_method_slowpath0(cd_owner, cd, klass);
+ return vm_cc_cme(cc);
}
#if __has_attribute(transparent_union)
@@ -2338,15 +2343,32 @@ check_method_basic_definition(const rb_callable_method_entry_t *me)
}
static inline int
-vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
+vm_method_cfunc_is(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv, cfunc_type func)
+{
+ VM_ASSERT(reg_cfp != NULL);
+ const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
+ return check_cfunc(cme, func);
+}
+
+bool
+rb_zjit_cme_is_cfunc(const rb_callable_method_entry_t *me, const cfunc_type func)
+{
+ return check_cfunc(me, func);
+}
+
+int
+rb_vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
{
- VM_ASSERT(iseq != NULL);
- const struct rb_callcache *cc = vm_search_method((VALUE)iseq, cd, recv);
- return check_cfunc(vm_cc_cme(cc), func);
+ // Called from ZJIT with the compile-time iseq, which may differ from
+ // the iseq on the current CFP. Use the slowpath to avoid stale caches.
+ VALUE klass = CLASS_OF(recv);
+ const struct rb_callcache *cc = vm_search_method_slowpath0((VALUE)iseq, cd, klass);
+ const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
+ return check_cfunc(cme, func);
}
#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
-#define vm_method_cfunc_is(iseq, cd, recv, func) vm_method_cfunc_is(iseq, cd, recv, make_cfunc_type(func))
+#define vm_method_cfunc_is(reg_cfp, cd, recv, func) vm_method_cfunc_is(reg_cfp, cd, recv, make_cfunc_type(func))
#define EQ_UNREDEFINED_P(t) BASIC_OP_UNREDEFINED_P(BOP_EQ, t##_REDEFINED_OP_FLAG)
@@ -2398,15 +2420,6 @@ opt_equality_specialized(VALUE recv, VALUE obj)
double a = RFLOAT_VALUE(recv);
double b = RFLOAT_VALUE(obj);
-#if MSC_VERSION_BEFORE(1300)
- if (isnan(a)) {
- return Qfalse;
- }
- else if (isnan(b)) {
- return Qfalse;
- }
- else
-#endif
return RBOOL(a == b);
}
else if (RBASIC_CLASS(recv) == rb_cString && EQ_UNREDEFINED_P(STRING)) {
@@ -2424,14 +2437,14 @@ opt_equality_specialized(VALUE recv, VALUE obj)
}
static VALUE
-opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
+opt_equality(struct rb_control_frame_struct *reg_cfp, VALUE recv, VALUE obj, CALL_DATA cd)
{
- VM_ASSERT(cd_owner != NULL);
+ VM_ASSERT(reg_cfp != NULL);
VALUE val = opt_equality_specialized(recv, obj);
if (!UNDEF_P(val)) return val;
- if (!vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) {
+ if (!vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_equal)) {
return Qundef;
}
else {
@@ -2504,37 +2517,27 @@ check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_che
}
-#if MSC_VERSION_BEFORE(1300)
-#define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse;
-#else
-#define CHECK_CMP_NAN(a, b) /* do nothing */
-#endif
-
static inline VALUE
double_cmp_lt(double a, double b)
{
- CHECK_CMP_NAN(a, b);
return RBOOL(a < b);
}
static inline VALUE
double_cmp_le(double a, double b)
{
- CHECK_CMP_NAN(a, b);
return RBOOL(a <= b);
}
static inline VALUE
double_cmp_gt(double a, double b)
{
- CHECK_CMP_NAN(a, b);
return RBOOL(a > b);
}
static inline VALUE
double_cmp_ge(double a, double b)
{
- CHECK_CMP_NAN(a, b);
return RBOOL(a >= b);
}
@@ -2544,18 +2547,18 @@ vm_base_ptr(const rb_control_frame_t *cfp)
{
const rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- if (cfp->iseq && VM_FRAME_RUBYFRAME_P(cfp)) {
- VALUE *bp = prev_cfp->sp + ISEQ_BODY(cfp->iseq)->local_table_size + VM_ENV_DATA_SIZE;
+ if (CFP_ISEQ(cfp) && VM_FRAME_RUBYFRAME_P(cfp)) {
+ VALUE *bp = prev_cfp->sp + ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size + VM_ENV_DATA_SIZE;
- if (ISEQ_BODY(cfp->iseq)->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
- int lts = ISEQ_BODY(cfp->iseq)->local_table_size;
- int params = ISEQ_BODY(cfp->iseq)->param.size;
+ if (ISEQ_BODY(CFP_ISEQ(cfp))->param.flags.forwardable && VM_ENV_LOCAL_P(cfp->ep)) {
+ int lts = ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size;
+ int params = ISEQ_BODY(CFP_ISEQ(cfp))->param.size;
CALL_INFO ci = (CALL_INFO)cfp->ep[-(VM_ENV_DATA_SIZE + (lts - params))]; // skip EP stuff, CI should be last local
bp += vm_ci_argc(ci);
}
- if (ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
+ if (ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_METHOD || VM_FRAME_BMETHOD_P(cfp)) {
/* adjust `self' */
bp += 1;
}
@@ -2624,7 +2627,8 @@ rb_simple_iseq_p(const rb_iseq_t *iseq)
ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
- ISEQ_BODY(iseq)->param.flags.has_block == FALSE;
+ ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
}
bool
@@ -2637,7 +2641,8 @@ rb_iseq_only_optparam_p(const rb_iseq_t *iseq)
ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
- ISEQ_BODY(iseq)->param.flags.has_block == FALSE;
+ ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
}
bool
@@ -2649,7 +2654,8 @@ rb_iseq_only_kwparam_p(const rb_iseq_t *iseq)
ISEQ_BODY(iseq)->param.flags.has_kw == TRUE &&
ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
- ISEQ_BODY(iseq)->param.flags.has_block == FALSE;
+ ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
}
#define ALLOW_HEAP_ARGV (-2)
@@ -2934,7 +2940,7 @@ vm_call_iseq_setup_tailcall_opt_start(rb_execution_context_t *ec, rb_control_fra
}
static void
-args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
+args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
VALUE *const locals);
@@ -2978,7 +2984,7 @@ vm_call_iseq_setup_kwparm_kwarg(rb_execution_context_t *ec, rb_control_frame_t *
const int lead_num = ISEQ_BODY(iseq)->param.lead_num;
VALUE * const ci_kws = ALLOCA_N(VALUE, ci_kw_len);
MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
- args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
+ args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
int param = ISEQ_BODY(iseq)->param.size;
int local = ISEQ_BODY(iseq)->local_table_size;
@@ -3032,7 +3038,7 @@ static void
warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, void *pc)
{
rb_vm_t *vm = GET_VM();
- st_table *dup_check_table = vm->unused_block_warning_table;
+ set_table *dup_check_table = &vm->unused_block_warning_table;
st_data_t key;
bool strict_unused_block = rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK);
@@ -3049,7 +3055,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
if (!strict_unused_block) {
key = (st_data_t)cme->def->original_id;
- if (st_lookup(dup_check_table, key, NULL)) {
+ if (set_table_lookup(dup_check_table, key)) {
return;
}
}
@@ -3069,7 +3075,7 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
}
// duplication check
- if (st_insert(dup_check_table, key, 1)) {
+ if (set_insert(dup_check_table, key)) {
// already shown
}
else if (RTEST(ruby_verbose) || strict_unused_block) {
@@ -3099,7 +3105,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
calling->block_handler != VM_BLOCK_HANDLER_NONE &&
!(vm_ci_flag(calling->cd->ci) & (VM_CALL_OPT_SEND | VM_CALL_SUPER)))) {
- warn_unused_block(vm_cc_cme(cc), iseq, (void *)ec->cfp->pc);
+ warn_unused_block(vm_cc_cme(cc), iseq, (void *)CFP_PC(ec->cfp));
}
if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_KW_SPLAT))) {
@@ -3109,15 +3115,14 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
CALLER_SETUP_ARG(cfp, calling, ci, lead_num);
if (calling->argc != lead_num) {
- argument_arity_error(ec, iseq, calling->argc, lead_num, lead_num);
+ argument_arity_error(ec, iseq, vm_cc_cme(cc), calling->argc, lead_num, lead_num);
}
//VM_ASSERT(ci == calling->cd->ci);
VM_ASSERT(cc == calling->cc);
if (vm_call_iseq_optimizable_p(ci, cc)) {
- if ((iseq->body->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) &&
- !(ruby_vm_event_flags & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN))) {
+ if ((iseq->body->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) && ruby_vm_c_events_enabled == 0) {
VM_ASSERT(iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF);
vm_cc_bf_set(cc, (void *)iseq->body->iseq_encoded[1]);
CC_SET_FASTPATH(cc, vm_call_single_noarg_leaf_builtin, true);
@@ -3139,7 +3144,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
const int opt = argc - lead_num;
if (opt < 0 || opt > opt_num) {
- argument_arity_error(ec, iseq, argc, lead_num, lead_num + opt_num);
+ argument_arity_error(ec, iseq, vm_cc_cme(cc), argc, lead_num, lead_num + opt_num);
}
if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_TAILCALL))) {
@@ -3175,7 +3180,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
MEMCPY(ci_kws, argv + lead_num, VALUE, ci_kw_len);
VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
- args_setup_kw_parameters(ec, iseq, ci_kws, ci_kw_len, ci_keywords, klocals);
+ args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), ci_kws, ci_kw_len, ci_keywords, klocals);
CC_SET_FASTPATH(cc, vm_call_iseq_setup_kwparm_kwarg,
vm_call_cacheable(ci, cc));
@@ -3186,7 +3191,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
else if (argc == lead_num) {
/* no kwarg */
VALUE *const klocals = argv + kw_param->bits_start - kw_param->num;
- args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
+ args_setup_kw_parameters(ec, iseq, vm_cc_cme(cc), NULL, 0, NULL, klocals);
if (klocals[kw_param->num] == INT2FIX(0)) {
/* copy from default_values */
@@ -3228,7 +3233,8 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
vm_ci_flag(ci),
vm_ci_argc(ci),
vm_ci_kwarg(ci));
- } else {
+ }
+ else {
ci = forward_cd->caller_ci;
}
can_fastpath = false;
@@ -3286,7 +3292,7 @@ vm_adjust_stack_forwarding(const struct rb_execution_context_struct *ec, struct
iseq = env->iseq;
}
else { // Otherwise use the lep to find the caller
- iseq = rb_vm_search_cf_from_ep(ec, cfp, lep)->iseq;
+ iseq = CFP_ISEQ(rb_vm_search_cf_from_ep(ec, cfp, lep));
}
// Our local storage is below the args we need to copy
@@ -3964,20 +3970,26 @@ vm_call_attrset_direct(rb_execution_context_t *ec, rb_control_frame_t *cfp, cons
RB_DEBUG_COUNTER_INC(ccf_attrset);
VALUE val = *(cfp->sp - 1);
cfp->sp -= 2;
- attr_index_t index = vm_cc_attr_index(cc);
- shape_id_t dest_shape_id = vm_cc_attr_index_dest_shape_id(cc);
+ rb_setivar_cache cache = rb_setivar_cache_unpack(vm_cc_atomic_cache_read(cc));
ID id = vm_cc_cme(cc)->def->body.attr.id;
rb_check_frozen(obj);
- VALUE res = vm_setivar(obj, id, val, dest_shape_id, index);
+ VALUE res = vm_setivar(obj, val, cache);
if (UNDEF_P(res)) {
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
+ break;
case T_CLASS:
case T_MODULE:
+ {
+ res = vm_setivar_class(obj, val, cache);
+ if (!UNDEF_P(res)) {
+ return res;
+ }
+ }
break;
default:
{
- res = vm_setivar_default(obj, id, val, dest_shape_id, index);
+ res = vm_setivar_default(obj, id, val, cache);
if (!UNDEF_P(res)) {
return res;
}
@@ -4004,7 +4016,7 @@ vm_call_bmethod_body(rb_execution_context_t *ec, struct rb_calling_info *calling
VALUE procv = cme->def->body.bmethod.proc;
if (!RB_OBJ_SHAREABLE_P(procv) &&
- cme->def->body.bmethod.defined_ractor != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
+ cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor");
}
@@ -4027,7 +4039,7 @@ vm_call_iseq_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct
VALUE procv = cme->def->body.bmethod.proc;
if (!RB_OBJ_SHAREABLE_P(procv) &&
- cme->def->body.bmethod.defined_ractor != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
+ cme->def->body.bmethod.defined_ractor_id != rb_ec_ractor_id(ec)) {
rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor");
}
@@ -4120,7 +4132,7 @@ rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
VALUE klass = current_class;
/* for prepended Module, then start from cover class */
- if (RB_TYPE_P(klass, T_ICLASS) && FL_TEST(klass, RICLASS_IS_ORIGIN) &&
+ if (RB_TYPE_P(klass, T_ICLASS) && RICLASS_IS_ORIGIN_P(klass) &&
RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) {
klass = RBASIC_CLASS(klass);
}
@@ -4185,7 +4197,7 @@ static enum method_missing_reason
ci_missing_reason(const struct rb_callinfo *ci)
{
enum method_missing_reason stat = MISSING_NOENTRY;
- if (vm_ci_flag(ci) & VM_CALL_VCALL) stat |= MISSING_VCALL;
+ if (vm_ci_flag(ci) & VM_CALL_VCALL && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) stat |= MISSING_VCALL;
if (vm_ci_flag(ci) & VM_CALL_FCALL) stat |= MISSING_FCALL;
if (vm_ci_flag(ci) & VM_CALL_SUPER) stat |= MISSING_SUPER;
return stat;
@@ -4485,8 +4497,8 @@ current_method_entry(const rb_execution_context_t *ec, rb_control_frame_t *cfp)
{
rb_control_frame_t *top_cfp = cfp;
- if (cfp->iseq && ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_BLOCK) {
- const rb_iseq_t *local_iseq = ISEQ_BODY(cfp->iseq)->local_iseq;
+ if (CFP_ISEQ(cfp) && ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_BLOCK) {
+ const rb_iseq_t *local_iseq = ISEQ_BODY(CFP_ISEQ(cfp))->local_iseq;
do {
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
@@ -4494,7 +4506,7 @@ current_method_entry(const rb_execution_context_t *ec, rb_control_frame_t *cfp)
/* TODO: orphan block */
return top_cfp;
}
- } while (cfp->iseq != local_iseq);
+ } while (CFP_ISEQ(cfp) != local_iseq);
}
return cfp;
}
@@ -4577,7 +4589,7 @@ vm_call_refined(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_c
if (ref_cme) {
if (calling->cd->cc) {
const struct rb_callcache *cc = calling->cc = vm_cc_new(vm_cc_cme(calling->cc)->defined_class, ref_cme, vm_call_general, cc_type_refinement);
- RB_OBJ_WRITE(cfp->iseq, &calling->cd->cc, cc);
+ RB_OBJ_WRITE(CFP_ISEQ(cfp), &calling->cd->cc, cc);
return vm_call_method(ec, cfp, calling);
}
else {
@@ -4648,7 +4660,7 @@ vm_call_opt_struct_aref0(rb_execution_context_t *ec, struct rb_calling_info *cal
VM_ASSERT(vm_cc_cme(calling->cc)->def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_AREF);
const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
- return internal_RSTRUCT_GET(recv, off);
+ return RSTRUCT_GET_RAW(recv, off);
}
static VALUE
@@ -4673,7 +4685,7 @@ vm_call_opt_struct_aset0(rb_execution_context_t *ec, struct rb_calling_info *cal
rb_check_frozen(recv);
const unsigned int off = vm_cc_cme(calling->cc)->def->body.optimized.index;
- internal_RSTRUCT_SET(recv, off, val);
+ RSTRUCT_SET_RAW(recv, off, val);
return val;
}
@@ -4692,7 +4704,7 @@ NOINLINE(static VALUE vm_call_optimized(rb_execution_context_t *ec, rb_control_f
const struct rb_callinfo *ci, const struct rb_callcache *cc));
#define VM_CALL_METHOD_ATTR(var, func, nohook) \
- if (UNLIKELY(ruby_vm_event_flags & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN))) { \
+ if (UNLIKELY(ruby_vm_c_events_enabled > 0)) { \
EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, calling->recv, vm_cc_cme(cc)->def->original_id, \
vm_ci_mid(ci), vm_cc_cme(cc)->owner, Qundef); \
var = func; \
@@ -4779,7 +4791,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
const unsigned int aset_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_KWARG | VM_CALL_FORWARDING);
if (vm_cc_markable(cc)) {
- vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
+ vm_cc_attr_index_set(cc, IVAR_CACHE_INIT);
VM_CALL_METHOD_ATTR(v,
vm_call_attrset_direct(ec, cfp, cc, calling->recv),
CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask)));
@@ -4795,7 +4807,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
.call_ = cc->call_,
.aux_ = {
.attr = {
- .value = INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT,
+ .value = IVAR_CACHE_INIT,
}
},
});
@@ -4809,7 +4821,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
case VM_METHOD_TYPE_IVAR:
CALLER_SETUP_ARG(cfp, calling, ci, 0);
rb_check_arity(calling->argc, 0, 0);
- vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID);
+ vm_cc_attr_index_set(cc, rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET));
const unsigned int ivar_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING);
VM_CALL_METHOD_ATTR(v,
vm_call_ivar(ec, cfp, calling),
@@ -4971,9 +4983,7 @@ vm_call_super_method(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, st
static inline VALUE
vm_search_normal_superclass(VALUE klass)
{
- if (BUILTIN_TYPE(klass) == T_ICLASS &&
- RB_TYPE_P(RBASIC(klass)->klass, T_MODULE) &&
- FL_TEST_RAW(RBASIC(klass)->klass, RMODULE_IS_REFINEMENT)) {
+ if (RICLASS_FOR_REFINEMENT_P(klass)) {
klass = RBASIC(klass)->klass;
}
klass = RCLASS_ORIGIN(klass);
@@ -4998,6 +5008,7 @@ static const struct rb_callcache *
vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *cd, VALUE recv)
{
VALUE current_defined_class;
+ const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp);
if (!me) {
@@ -5007,7 +5018,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
current_defined_class = vm_defined_class_for_protected_call(me);
if (BUILTIN_TYPE(current_defined_class) != T_MODULE &&
- reg_cfp->iseq != method_entry_iseqptr(me) &&
+ iseq != method_entry_iseqptr(me) &&
!rb_obj_is_kind_of(recv, current_defined_class)) {
VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ?
RCLASS_INCLUDER(current_defined_class) : current_defined_class;
@@ -5039,7 +5050,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
vm_ci_argc(cd->ci),
vm_ci_kwarg(cd->ci));
- RB_OBJ_WRITTEN(reg_cfp->iseq, Qundef, cd->ci);
+ RB_OBJ_WRITTEN(iseq, Qundef, cd->ci);
}
const struct rb_callcache *cc;
@@ -5048,11 +5059,18 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
if (!klass) {
/* bound instance method of module */
- cc = vm_cc_new(klass, NULL, vm_call_method_missing, cc_type_super);
- RB_OBJ_WRITE(reg_cfp->iseq, &cd->cc, cc);
+ cc = vm_cc_new(Qundef, NULL, vm_call_method_missing, cc_type_super);
+ RB_OBJ_WRITE(iseq, &cd->cc, cc);
+ }
+ else if (klass == rb_cBasicObject &&
+ RB_TYPE_P(me->defined_class, T_ICLASS) &&
+ RCLASS_INCLUDER(me->defined_class) == 0) {
+ rb_raise(rb_eNoMethodError,
+ "super in a method in a module that has been refined and that is called via super"
+ " from a refinement method is not supported.");
}
else {
- cc = vm_search_method_fastpath((VALUE)reg_cfp->iseq, cd, klass);
+ cc = vm_search_method_fastpath(reg_cfp, cd, klass);
const rb_callable_method_entry_t *cached_cme = vm_cc_cme(cc);
// define_method can cache for different method id
@@ -5064,7 +5082,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
if (cme) {
cc = vm_cc_new(klass, cme, vm_call_super_method, cc_type_super);
- RB_OBJ_WRITE(reg_cfp->iseq, &cd->cc, cc);
+ RB_OBJ_WRITE(iseq, &cd->cc, cc);
}
else {
cd->cc = cc = empty_cc_for_super();
@@ -5216,7 +5234,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca
}
}
else {
- argument_arity_error(ec, iseq, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
+ argument_arity_error(ec, iseq, NULL, calling->argc, ISEQ_BODY(iseq)->param.lead_num, ISEQ_BODY(iseq)->param.lead_num);
}
}
@@ -5238,6 +5256,7 @@ vm_yield_setup_args(rb_execution_context_t *ec, const rb_iseq_t *iseq, const int
calling->kw_splat = (flags & VM_CALL_KW_SPLAT) ? 1 : 0;
calling->recv = Qundef;
calling->heap_argv = 0;
+ calling->cc = NULL;
struct rb_callinfo dummy_ci = VM_CI_ON_STACK(0, flags, 0, 0);
return vm_callee_setup_block_arg(ec, calling, &dummy_ci, iseq, argv, arg_setup_type);
@@ -5256,11 +5275,12 @@ vm_invoke_iseq_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
VALUE * const rsp = GET_SP() - calling->argc;
VALUE * const argv = rsp;
int opt_pc = vm_callee_setup_block_arg(ec, calling, ci, iseq, argv, is_lambda ? arg_setup_method : arg_setup_block);
+ int frame_flag = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
SET_SP(rsp);
vm_push_frame(ec, iseq,
- VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0),
+ frame_flag,
captured->self,
VM_GUARDED_PREV_EP(captured->ep), 0,
ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
@@ -5468,21 +5488,21 @@ vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_
break;
case DEFINED_METHOD:{
VALUE klass = CLASS_OF(v);
- const rb_method_entry_t *me = rb_method_entry_with_refinements(klass, SYM2ID(obj), NULL);
+ const rb_callable_method_entry_t *cme = rb_callable_method_entry_with_refinements(klass, SYM2ID(obj), NULL);
- if (me) {
- switch (METHOD_ENTRY_VISI(me)) {
+ if (cme) {
+ switch (METHOD_ENTRY_VISI(cme)) {
case METHOD_VISI_PRIVATE:
break;
case METHOD_VISI_PROTECTED:
- if (!rb_obj_is_kind_of(GET_SELF(), rb_class_real(me->defined_class))) {
+ if (!rb_obj_is_kind_of(GET_SELF(), vm_defined_class_for_protected_call(cme))) {
break;
}
case METHOD_VISI_PUBLIC:
return true;
break;
default:
- rb_bug("vm_defined: unreachable: %u", (unsigned int)METHOD_ENTRY_VISI(me));
+ rb_bug("vm_defined: unreachable: %u", (unsigned int)METHOD_ENTRY_VISI(cme));
}
}
else {
@@ -5552,6 +5572,14 @@ vm_get_special_object(const VALUE *const reg_ep,
}
}
+// ZJIT implementation is using the C function
+// and needs to call a non-static function
+VALUE
+rb_vm_get_special_object(const VALUE *reg_ep, enum vm_special_object_type type)
+{
+ return vm_get_special_object(reg_ep, type);
+}
+
static VALUE
vm_concat_array(VALUE ary1, VALUE ary2st)
{
@@ -5568,7 +5596,8 @@ vm_concat_array(VALUE ary1, VALUE ary2st)
if (NIL_P(tmp2)) {
return rb_ary_push(tmp1, ary2);
- } else {
+ }
+ else {
return rb_ary_concat(tmp1, tmp2);
}
}
@@ -5585,7 +5614,8 @@ vm_concat_to_array(VALUE ary1, VALUE ary2st)
if (NIL_P(tmp2)) {
return rb_ary_push(ary1, ary2);
- } else {
+ }
+ else {
return rb_ary_concat(ary1, tmp2);
}
}
@@ -5667,7 +5697,7 @@ vm_check_keyword(lindex_t bits, lindex_t idx, const VALUE *ep)
if (FIXNUM_P(kw_bits)) {
unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
- if ((idx < KW_SPECIFIED_BITS_MAX) && (b & (0x01 << idx)))
+ if ((idx < VM_KW_SPECIFIED_BITS_MAX) && (b & (0x01 << idx)))
return Qfalse;
}
else {
@@ -5751,26 +5781,28 @@ vm_check_if_module(ID id, VALUE mod)
}
static VALUE
+declare_under(ID id, VALUE cbase, VALUE c)
+{
+ rb_set_class_path_string(c, cbase, rb_id2str(id));
+ rb_const_set(cbase, id, c);
+ return c;
+}
+
+static VALUE
vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
{
/* new class declaration */
VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject;
- VALUE c = rb_define_class_id(id, s);
- rb_define_alloc_func(c, rb_get_alloc_func(c));
- rb_set_class_path_string(c, cbase, rb_id2str(id));
- rb_const_set_raw(cbase, id, c);
+ VALUE c = declare_under(id, cbase, rb_define_class_id(id, s));
rb_class_inherited(s, c);
- rb_const_added(cbase, id);
return c;
}
static VALUE
vm_declare_module(ID id, VALUE cbase)
{
- VALUE m = rb_module_new();
- rb_set_class_path_string(m, cbase, rb_id2str(id));
- rb_const_set(cbase, id, m);
- return m;
+ /* new module declaration */
+ return declare_under(id, cbase, rb_module_new());
}
NORETURN(static void unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old));
@@ -5804,6 +5836,7 @@ vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
/* find klass */
rb_autoload_load(cbase, id);
+
if ((klass = vm_const_get_under(id, flags, cbase)) != 0) {
if (!vm_check_if_class(id, flags, super, klass))
unmatched_redefinition("class", cbase, id, klass);
@@ -5904,9 +5937,10 @@ vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqv
rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, visi);
// Set max_iv_count on klasses based on number of ivar sets that are in the initialize method
- if (id == idInitialize && klass != rb_cObject && RB_TYPE_P(klass, T_CLASS) && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
-
- RCLASS_EXT(klass)->max_iv_count = rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval);
+ if (id == idInitialize && RB_TYPE_P(klass, T_CLASS) &&
+ !RCLASS_SINGLETON_P(klass) && !RCLASS_EXPECT_NO_IVAR(klass) &&
+ (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
+ RCLASS_SET_MAX_IV_COUNT(klass, rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval));
}
if (!is_singleton && vm_scope_module_func_check(ec)) {
@@ -5915,6 +5949,35 @@ vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqv
}
}
+// Return the untagged block handler:
+// * If it's VM_BLOCK_HANDLER_NONE, return nil
+// * If it's an ISEQ or an IFUNC, fetch it from its rb_captured_block
+// * If it's a PROC or SYMBOL, return it as is
+VALUE
+rb_vm_untag_block_handler(VALUE block_handler)
+{
+ if (VM_BLOCK_HANDLER_NONE == block_handler) return Qnil;
+
+ switch (vm_block_handler_type(block_handler)) {
+ case block_handler_type_iseq:
+ case block_handler_type_ifunc: {
+ struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03);
+ return captured->code.val;
+ }
+ case block_handler_type_proc:
+ case block_handler_type_symbol:
+ return block_handler;
+ default:
+ rb_bug("rb_vm_untag_block_handler: unreachable");
+ }
+}
+
+VALUE
+rb_vm_get_untagged_block_handler(rb_control_frame_t *reg_cfp)
+{
+ return rb_vm_untag_block_handler(VM_CF_BLOCK_HANDLER(reg_cfp));
+}
+
static VALUE
vm_invokeblock_i(struct rb_execution_context_struct *ec,
struct rb_control_frame_struct *reg_cfp,
@@ -5960,7 +6023,7 @@ vm_sendish(
switch (method_explorer) {
case mexp_search_method:
- calling.cc = cc = vm_search_method_fastpath((VALUE)reg_cfp->iseq, cd, CLASS_OF(recv));
+ calling.cc = cc = vm_search_method_fastpath(reg_cfp, cd, CLASS_OF(recv));
val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
break;
case mexp_search_super:
@@ -5978,25 +6041,27 @@ VALUE
rb_vm_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
{
stack_check(ec);
+ VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
+ VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
+ VM_EXEC(ec, val);
+ return val;
+}
+
+// Fallback for YJIT/ZJIT, not used by the interpreter
+VALUE
+rb_vm_sendforward(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
+{
+ stack_check(ec);
struct rb_forwarding_call_data adjusted_cd;
struct rb_callinfo adjusted_ci;
- VALUE bh;
- VALUE val;
-
- if (vm_ci_flag(cd->ci) & VM_CALL_FORWARDING) {
- bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, false, &adjusted_cd, &adjusted_ci);
+ VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, false, &adjusted_cd, &adjusted_ci);
- val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method);
+ VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method);
- if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
- RB_OBJ_WRITE(GET_ISEQ(), &cd->cc, adjusted_cd.cd.cc);
- }
- }
- else {
- bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
- val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
+ if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
+ RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
}
VM_EXEC(ec, val);
@@ -6017,24 +6082,43 @@ VALUE
rb_vm_invokesuper(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
{
stack_check(ec);
+
+ struct rb_callinfo adjusted_ci = VM_CI_ON_STACK(vm_ci_mid(cd->ci),
+ vm_ci_flag(cd->ci),
+ vm_ci_argc(cd->ci),
+ vm_ci_kwarg(cd->ci));
+ const struct rb_callcache *original_cc = rbimpl_atomic_ptr_load((void **)&cd->cc, RBIMPL_ATOMIC_ACQUIRE);
+ struct rb_call_data adjusted_cd = {
+ .ci = &adjusted_ci,
+ .cc = original_cc,
+ };
+
+ VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), adjusted_cd.ci, blockiseq, true);
+ VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd, bh, mexp_search_super);
+
+ if (original_cc != adjusted_cd.cc && vm_cc_markable(adjusted_cd.cc)) {
+ rbimpl_atomic_ptr_store((volatile void **)&cd->cc, (void *)adjusted_cd.cc, RBIMPL_ATOMIC_RELEASE);
+ RB_OBJ_WRITTEN(CFP_ISEQ(GET_CFP()), Qundef, adjusted_cd.cc);
+ }
+
+ VM_EXEC(ec, val);
+ return val;
+}
+
+// Fallback for YJIT/ZJIT, not used by the interpreter
+VALUE
+rb_vm_invokesuperforward(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd, ISEQ blockiseq)
+{
+ stack_check(ec);
struct rb_forwarding_call_data adjusted_cd;
struct rb_callinfo adjusted_ci;
- VALUE bh;
- VALUE val;
-
- if (vm_ci_flag(cd->ci) & VM_CALL_FORWARDING) {
- bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, true, &adjusted_cd, &adjusted_ci);
+ VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, true, &adjusted_cd, &adjusted_ci);
- val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super);
+ VALUE val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super);
- if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
- RB_OBJ_WRITE(GET_ISEQ(), &cd->cc, adjusted_cd.cd.cc);
- }
- }
- else {
- bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
- val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
+ if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
+ RB_OBJ_WRITE(CFP_ISEQ(GET_CFP()), &cd->cc, adjusted_cd.cd.cc);
}
VM_EXEC(ec, val);
@@ -6063,18 +6147,18 @@ VALUE rb_mod_to_s(VALUE);
VALUE rb_mod_name(VALUE);
static VALUE
-vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
+vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
{
int type = TYPE(recv);
if (type == T_STRING) {
return recv;
}
- const struct rb_callcache *cc = vm_search_method((VALUE)iseq, cd, recv);
+ const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
switch (type) {
case T_SYMBOL:
- if (check_method_basic_definition(vm_cc_cme(cc))) {
+ if (check_method_basic_definition(cme)) {
// rb_sym_to_s() allocates a mutable string, but since we are only
// going to use this string for interpolation, it's fine to use the
// frozen string.
@@ -6083,7 +6167,7 @@ vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
break;
case T_MODULE:
case T_CLASS:
- if (check_cfunc(vm_cc_cme(cc), rb_mod_to_s)) {
+ if (check_cfunc(cme, rb_mod_to_s)) {
// rb_mod_to_s() allocates a mutable string, but since we are only
// going to use this string for interpolation, it's fine to use the
// frozen string.
@@ -6095,22 +6179,22 @@ vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
}
break;
case T_NIL:
- if (check_cfunc(vm_cc_cme(cc), rb_nil_to_s)) {
+ if (check_cfunc(cme, rb_nil_to_s)) {
return rb_nil_to_s(recv);
}
break;
case T_TRUE:
- if (check_cfunc(vm_cc_cme(cc), rb_true_to_s)) {
+ if (check_cfunc(cme, rb_true_to_s)) {
return rb_true_to_s(recv);
}
break;
case T_FALSE:
- if (check_cfunc(vm_cc_cme(cc), rb_false_to_s)) {
+ if (check_cfunc(cme, rb_false_to_s)) {
return rb_false_to_s(recv);
}
break;
case T_FIXNUM:
- if (check_cfunc(vm_cc_cme(cc), rb_int_to_s)) {
+ if (check_cfunc(cme, rb_int_to_s)) {
return rb_fix_to_s(recv);
}
break;
@@ -6118,6 +6202,14 @@ vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
return Qundef;
}
+// ZJIT implementation is using the C function
+// and needs to call a non-static function
+VALUE
+rb_vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
+{
+ return vm_objtostring(reg_cfp, recv, cd);
+}
+
static VALUE
vm_opt_ary_freeze(VALUE ary, int bop, ID id)
{
@@ -6178,15 +6270,15 @@ rb_vm_opt_duparray_include_p(rb_execution_context_t *ec, const VALUE ary, VALUE
}
static VALUE
-vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
+vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
{
if (BASIC_OP_UNREDEFINED_P(BOP_MAX, ARRAY_REDEFINED_OP_FLAG)) {
- if (num == 0) {
+ if (array_len == 0) {
return Qnil;
}
else {
VALUE result = *ptr;
- rb_snum_t i = num - 1;
+ rb_snum_t i = array_len - 1;
while (i-- > 0) {
const VALUE v = *++ptr;
if (OPTIMIZED_CMP(v, result) > 0) {
@@ -6197,26 +6289,26 @@ vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
}
}
else {
- return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idMax, 0, NULL, RB_NO_KEYWORDS);
+ return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idMax, 0, NULL, RB_NO_KEYWORDS);
}
}
VALUE
-rb_vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
+rb_vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
{
- return vm_opt_newarray_max(ec, num, ptr);
+ return vm_opt_newarray_max(ec, array_len, ptr);
}
static VALUE
-vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
+vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
{
if (BASIC_OP_UNREDEFINED_P(BOP_MIN, ARRAY_REDEFINED_OP_FLAG)) {
- if (num == 0) {
+ if (array_len == 0) {
return Qnil;
}
else {
VALUE result = *ptr;
- rb_snum_t i = num - 1;
+ rb_snum_t i = array_len - 1;
while (i-- > 0) {
const VALUE v = *++ptr;
if (OPTIMIZED_CMP(v, result) < 0) {
@@ -6227,63 +6319,63 @@ vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
}
}
else {
- return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idMin, 0, NULL, RB_NO_KEYWORDS);
+ return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idMin, 0, NULL, RB_NO_KEYWORDS);
}
}
VALUE
-rb_vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
+rb_vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
{
- return vm_opt_newarray_min(ec, num, ptr);
+ return vm_opt_newarray_min(ec, array_len, ptr);
}
static VALUE
-vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
+vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
{
// If Array#hash is _not_ monkeypatched, use the optimized call
if (BASIC_OP_UNREDEFINED_P(BOP_HASH, ARRAY_REDEFINED_OP_FLAG)) {
- return rb_ary_hash_values(num, ptr);
+ return rb_ary_hash_values(array_len, ptr);
}
else {
- return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idHash, 0, NULL, RB_NO_KEYWORDS);
+ return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idHash, 0, NULL, RB_NO_KEYWORDS);
}
}
VALUE
-rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
+rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr)
{
- return vm_opt_newarray_hash(ec, num, ptr);
+ return vm_opt_newarray_hash(ec, array_len, ptr);
}
VALUE rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len);
VALUE rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer);
static VALUE
-vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE target)
+vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE target)
{
if (BASIC_OP_UNREDEFINED_P(BOP_INCLUDE_P, ARRAY_REDEFINED_OP_FLAG)) {
- struct RArray fake_ary;
- VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, num);
+ struct RArray fake_ary = {RBASIC_INIT};
+ VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, array_len);
return rb_ary_includes(ary, target);
}
else {
VALUE args[1] = {target};
- return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idIncludeP, 1, args, RB_NO_KEYWORDS);
+ return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idIncludeP, 1, args, RB_NO_KEYWORDS);
}
}
VALUE
-rb_vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE target)
+rb_vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE target)
{
- return vm_opt_newarray_include_p(ec, num, ptr, target);
+ return vm_opt_newarray_include_p(ec, array_len, ptr, target);
}
static VALUE
-vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt, VALUE buffer)
+vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE fmt, VALUE buffer)
{
if (BASIC_OP_UNREDEFINED_P(BOP_PACK, ARRAY_REDEFINED_OP_FLAG)) {
- struct RArray fake_ary;
- VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, num);
+ struct RArray fake_ary = {RBASIC_INIT};
+ VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, array_len);
return rb_ec_pack_ary(ec, ary, fmt, (UNDEF_P(buffer) ? Qnil : buffer));
}
else {
@@ -6301,20 +6393,20 @@ vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t num, const VALU
argc++;
}
- return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idPack, argc, args, kw_splat);
+ return rb_vm_call_with_refinements(ec, rb_ary_new4(array_len, ptr), idPack, argc, args, kw_splat);
}
}
VALUE
-rb_vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt, VALUE buffer)
+rb_vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE fmt, VALUE buffer)
{
- return vm_opt_newarray_pack_buffer(ec, num, ptr, fmt, buffer);
+ return vm_opt_newarray_pack_buffer(ec, array_len, ptr, fmt, buffer);
}
VALUE
-rb_vm_opt_newarray_pack(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt)
+rb_vm_opt_newarray_pack(rb_execution_context_t *ec, rb_num_t array_len, const VALUE *ptr, VALUE fmt)
{
- return vm_opt_newarray_pack_buffer(ec, num, ptr, fmt, Qundef);
+ return vm_opt_newarray_pack_buffer(ec, array_len, ptr, fmt, Qundef);
}
#undef id_cmp
@@ -6323,15 +6415,15 @@ static void
vm_track_constant_cache(ID id, void *ic)
{
rb_vm_t *vm = GET_VM();
- struct rb_id_table *const_cache = vm->constant_cache;
+ struct rb_id_table *const_cache = &vm->constant_cache;
VALUE lookup_result;
- st_table *ics;
+ set_table *ics;
if (rb_id_table_lookup(const_cache, id, &lookup_result)) {
- ics = (st_table *)lookup_result;
+ ics = (set_table *)lookup_result;
}
else {
- ics = st_init_numtable();
+ ics = set_init_numtable();
rb_id_table_insert(const_cache, id, (VALUE)ics);
}
@@ -6349,7 +6441,7 @@ vm_track_constant_cache(ID id, void *ic)
*/
vm->inserting_constant_cache_id = id;
- st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue);
+ set_insert(ics, (st_data_t)ic);
vm->inserting_constant_cache_id = (ID)0;
}
@@ -6357,15 +6449,13 @@ vm_track_constant_cache(ID id, void *ic)
static void
vm_ic_track_const_chain(rb_control_frame_t *cfp, IC ic, const ID *segments)
{
- RB_VM_LOCK_ENTER();
-
- for (int i = 0; segments[i]; i++) {
- ID id = segments[i];
- if (id == idNULL) continue;
- vm_track_constant_cache(id, ic);
+ RB_VM_LOCKING() {
+ for (int i = 0; segments[i]; i++) {
+ ID id = segments[i];
+ if (id == idNULL) continue;
+ vm_track_constant_cache(id, ic);
+ }
}
-
- RB_VM_LOCK_LEAVE();
}
// For JIT inlining
@@ -6404,12 +6494,15 @@ vm_ic_update(const rb_iseq_t *iseq, IC ic, VALUE val, const VALUE *reg_ep, const
return;
}
- struct iseq_inline_constant_cache_entry *ice = IMEMO_NEW(struct iseq_inline_constant_cache_entry, imemo_constcache, 0);
+ struct iseq_inline_constant_cache_entry *ice = SHAREABLE_IMEMO_NEW(struct iseq_inline_constant_cache_entry, imemo_constcache, 0);
RB_OBJ_WRITE(ice, &ice->value, val);
ice->ic_cref = vm_get_const_key_cref(reg_ep);
- if (rb_ractor_shareable_p(val)) ice->flags |= IMEMO_CONST_CACHE_SHAREABLE;
- RB_OBJ_WRITE(iseq, &ic->entry, ice);
+ if (rb_ractor_shareable_p(val)) {
+ RUBY_ASSERT((rb_gc_verify_shareable(val), 1));
+ ice->flags |= IMEMO_CONST_CACHE_SHAREABLE;
+ }
+ RB_OBJ_WRITE(iseq, &ic->entry, ice);
RUBY_ASSERT(pc >= ISEQ_BODY(iseq)->iseq_encoded);
unsigned pos = (unsigned)(pc - ISEQ_BODY(iseq)->iseq_encoded);
rb_yjit_constant_ic_update(iseq, ic, pos);
@@ -6421,6 +6514,7 @@ rb_vm_opt_getconstant_path(rb_execution_context_t *ec, rb_control_frame_t *const
VALUE val;
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;
@@ -6432,7 +6526,7 @@ rb_vm_opt_getconstant_path(rb_execution_context_t *ec, rb_control_frame_t *const
vm_ic_track_const_chain(GET_CFP(), ic, segments);
// 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);
+ vm_ic_update(CFP_ISEQ(GET_CFP()), ic, val, GET_EP(), CFP_PC(GET_CFP()) - 2);
}
return val;
}
@@ -6451,7 +6545,14 @@ vm_once_dispatch(rb_execution_context_t *ec, ISEQ iseq, ISE is)
VALUE val;
is->once.running_thread = th;
val = rb_ensure(vm_once_exec, (VALUE)iseq, vm_once_clear, (VALUE)is);
- RB_OBJ_WRITE(ec->cfp->iseq, &is->once.value, val);
+ // TODO: confirm that it is shareable
+
+ if (RB_FL_ABLE(val)) {
+ RB_OBJ_SET_SHAREABLE(val);
+ }
+
+ RB_OBJ_WRITE(CFP_ISEQ(ec->cfp), &is->once.value, val);
+
/* is->once.running_thread is cleared by vm_once_clear() */
is->once.running_thread = RUNNING_THREAD_ONCE_DONE; /* success */
return val;
@@ -6492,8 +6593,8 @@ vm_case_dispatch(CDHASH hash, OFFSET else_offset, VALUE key)
key = FIXABLE(kval) ? LONG2FIX((long)kval) : rb_dbl2big(kval);
}
}
- if (rb_hash_stlike_lookup(hash, key, &val)) {
- return FIX2LONG((VALUE)val);
+ if (st_lookup(rb_imemo_cdhash_tbl(hash), key, &val)) {
+ return (VALUE)val;
}
else {
return else_offset;
@@ -6519,7 +6620,7 @@ vm_stack_consistency_error(const rb_execution_context_t *ec,
#if defined RUBY_DEVEL
VALUE mesg = rb_sprintf(stack_consistency_error, nsp, nbp);
rb_str_cat_cstr(mesg, "\n");
- rb_str_append(mesg, rb_iseq_disasm(cfp->iseq));
+ rb_str_append(mesg, rb_iseq_disasm(CFP_ISEQ(cfp)));
rb_exc_fatal(rb_exc_new3(rb_eFatal, mesg));
#else
rb_bug(stack_consistency_error, nsp, nbp);
@@ -6657,10 +6758,10 @@ vm_opt_mod(VALUE recv, VALUE obj)
}
static VALUE
-vm_opt_neq(const rb_iseq_t *iseq, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
+vm_opt_neq(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
{
- if (vm_method_cfunc_is(iseq, cd, recv, rb_obj_not_equal)) {
- VALUE val = opt_equality(iseq, recv, obj, cd_eq);
+ if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not_equal)) {
+ VALUE val = opt_equality(reg_cfp, recv, obj, cd_eq);
if (!UNDEF_P(val)) {
return RBOOL(!RTEST(val));
@@ -6687,7 +6788,6 @@ vm_opt_lt(VALUE recv, VALUE obj)
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) {
- CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RBOOL(RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj));
}
else {
@@ -6712,7 +6812,6 @@ vm_opt_le(VALUE recv, VALUE obj)
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) {
- CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RBOOL(RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj));
}
else {
@@ -6737,7 +6836,6 @@ vm_opt_gt(VALUE recv, VALUE obj)
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) {
- CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RBOOL(RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj));
}
else {
@@ -6762,7 +6860,6 @@ vm_opt_ge(VALUE recv, VALUE obj)
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) {
- CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RBOOL(RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj));
}
else {
@@ -6876,39 +6973,6 @@ vm_opt_aset(VALUE recv, VALUE obj, VALUE set)
}
static VALUE
-vm_opt_aref_with(VALUE recv, VALUE key)
-{
- if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash &&
- BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG) &&
- rb_hash_compare_by_id_p(recv) == Qfalse &&
- !FL_TEST(recv, RHASH_PROC_DEFAULT)) {
- return rb_hash_aref(recv, key);
- }
- else {
- return Qundef;
- }
-}
-
-VALUE
-rb_vm_opt_aref_with(VALUE recv, VALUE key)
-{
- return vm_opt_aref_with(recv, key);
-}
-
-static VALUE
-vm_opt_aset_with(VALUE recv, VALUE key, VALUE val)
-{
- if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash &&
- BASIC_OP_UNREDEFINED_P(BOP_ASET, HASH_REDEFINED_OP_FLAG) &&
- rb_hash_compare_by_id_p(recv) == Qfalse) {
- return rb_hash_aset(recv, key, val);
- }
- else {
- return Qundef;
- }
-}
-
-static VALUE
vm_opt_length(VALUE recv, int bop)
{
if (SPECIAL_CONST_P(recv)) {
@@ -6949,13 +7013,13 @@ vm_opt_empty_p(VALUE recv)
VALUE rb_false(VALUE obj);
static VALUE
-vm_opt_nil_p(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv)
+vm_opt_nil_p(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
{
if (NIL_P(recv) &&
BASIC_OP_UNREDEFINED_P(BOP_NIL_P, NIL_REDEFINED_OP_FLAG)) {
return Qtrue;
}
- else if (vm_method_cfunc_is(iseq, cd, recv, rb_false)) {
+ else if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_false)) {
return Qfalse;
}
else {
@@ -7011,9 +7075,9 @@ vm_opt_succ(VALUE recv)
}
static VALUE
-vm_opt_not(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv)
+vm_opt_not(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
{
- if (vm_method_cfunc_is(iseq, cd, recv, rb_obj_not)) {
+ if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not)) {
return RBOOL(!RTEST(recv));
}
else {
@@ -7048,13 +7112,15 @@ NOINLINE(static void vm_trace(rb_execution_context_t *ec, rb_control_frame_t *re
static inline void
vm_trace_hook(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE *pc,
rb_event_flag_t pc_events, rb_event_flag_t target_event,
- rb_hook_list_t *global_hooks, rb_hook_list_t *const *local_hooks_ptr, VALUE val)
+ rb_hook_list_t *global_hooks, rb_hook_list_t *local_hooks, VALUE val)
{
rb_event_flag_t event = pc_events & target_event;
VALUE self = GET_SELF();
VM_ASSERT(rb_popcount64((uint64_t)event) == 1);
+ if (local_hooks) local_hooks->running++; // make sure they don't get deleted while global hooks run
+
if (event & global_hooks->events) {
/* increment PC because source line is calculated with PC-1 */
reg_cfp->pc++;
@@ -7063,8 +7129,7 @@ vm_trace_hook(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VAL
reg_cfp->pc--;
}
- // Load here since global hook above can add and free local hooks
- rb_hook_list_t *local_hooks = *local_hooks_ptr;
+ if (local_hooks) local_hooks->running--;
if (local_hooks != NULL) {
if (event & local_hooks->events) {
/* increment PC because source line is calculated with PC-1 */
@@ -7077,7 +7142,7 @@ vm_trace_hook(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VAL
#define VM_TRACE_HOOK(target_event, val) do { \
if ((pc_events & (target_event)) & enabled_flags) { \
- vm_trace_hook(ec, reg_cfp, pc, pc_events, (target_event), global_hooks, local_hooks_ptr, (val)); \
+ vm_trace_hook(ec, reg_cfp, pc, pc_events, (target_event), global_hooks, local_hooks, (val)); \
} \
} while (0)
@@ -7085,7 +7150,7 @@ static VALUE
rescue_errinfo(rb_execution_context_t *ec, rb_control_frame_t *cfp)
{
VM_ASSERT(VM_FRAME_RUBYFRAME_P(cfp));
- VM_ASSERT(ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_RESCUE);
+ VM_ASSERT(ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_RESCUE);
return cfp->ep[VM_ENV_INDEX_LAST_LVAR];
}
@@ -7093,22 +7158,28 @@ static void
vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
{
const VALUE *pc = reg_cfp->pc;
- rb_event_flag_t enabled_flags = ruby_vm_event_flags & ISEQ_TRACE_EVENTS;
- rb_event_flag_t global_events = enabled_flags;
+ rb_ractor_t *r = rb_ec_ractor_ptr(ec);
+ rb_event_flag_t enabled_flags = r->pub.hooks.events & ISEQ_TRACE_EVENTS;
+ rb_event_flag_t ractor_events = enabled_flags;
- if (enabled_flags == 0 && ruby_vm_event_local_num == 0) {
+ if (enabled_flags == 0 && rb_ractor_targeted_hooks_cnt(r) == 0) {
return;
}
else {
- const rb_iseq_t *iseq = reg_cfp->iseq;
- VALUE iseq_val = (VALUE)iseq;
+ const rb_iseq_t *iseq = CFP_ISEQ(reg_cfp);
size_t pos = pc - ISEQ_BODY(iseq)->iseq_encoded;
rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pos);
- rb_hook_list_t *local_hooks = iseq->aux.exec.local_hooks;
- rb_hook_list_t *const *local_hooks_ptr = &iseq->aux.exec.local_hooks;
+ unsigned int local_hooks_cnt = iseq->aux.exec.local_hooks_cnt;
+ rb_hook_list_t *local_hooks = NULL;
+ if (RB_UNLIKELY(local_hooks_cnt > 0)) {
+ st_data_t val;
+ if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)iseq, &val)) {
+ local_hooks = (rb_hook_list_t*)val;
+ }
+ }
rb_event_flag_t iseq_local_events = local_hooks != NULL ? local_hooks->events : 0;
+
rb_hook_list_t *bmethod_local_hooks = NULL;
- rb_hook_list_t **bmethod_local_hooks_ptr = NULL;
rb_event_flag_t bmethod_local_events = 0;
const bool bmethod_frame = VM_FRAME_BMETHOD_P(reg_cfp);
enabled_flags |= iseq_local_events;
@@ -7118,14 +7189,18 @@ vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
if (bmethod_frame) {
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp);
VM_ASSERT(me->def->type == VM_METHOD_TYPE_BMETHOD);
- bmethod_local_hooks = me->def->body.bmethod.hooks;
- bmethod_local_hooks_ptr = &me->def->body.bmethod.hooks;
- if (bmethod_local_hooks) {
- bmethod_local_events = bmethod_local_hooks->events;
+ unsigned int bmethod_hooks_cnt = me->def->body.bmethod.local_hooks_cnt;
+ if (RB_UNLIKELY(bmethod_hooks_cnt > 0)) {
+ st_data_t val;
+ if (st_lookup(rb_ractor_targeted_hooks(r), (st_data_t)me->def, &val)) {
+ bmethod_local_hooks = (rb_hook_list_t*)val;
+ }
+ if (bmethod_local_hooks) {
+ bmethod_local_events = bmethod_local_hooks->events;
+ }
}
}
-
if ((pc_events & enabled_flags) == 0 && !bmethod_frame) {
#if 0
/* disable trace */
@@ -7146,7 +7221,7 @@ vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
rb_hook_list_t *global_hooks = rb_ec_ractor_hooks(ec);
/* Note, not considering iseq local events here since the same
* iseq could be used in multiple bmethods. */
- rb_event_flag_t bmethod_events = global_events | bmethod_local_events;
+ rb_event_flag_t bmethod_events = ractor_events | bmethod_local_events;
if (0) {
ruby_debug_printf("vm_trace>>%4d (%4x) - %s:%d %s\n",
@@ -7162,7 +7237,7 @@ vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
/* check traces */
if ((pc_events & RUBY_EVENT_B_CALL) && bmethod_frame && (bmethod_events & RUBY_EVENT_CALL)) {
/* b_call instruction running as a method. Fire call event. */
- vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_CALL, RUBY_EVENT_CALL, global_hooks, bmethod_local_hooks_ptr, Qundef);
+ vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_CALL, RUBY_EVENT_CALL, global_hooks, bmethod_local_hooks, Qundef);
}
VM_TRACE_HOOK(RUBY_EVENT_CLASS | RUBY_EVENT_CALL | RUBY_EVENT_B_CALL, Qundef);
VM_TRACE_HOOK(RUBY_EVENT_RESCUE, rescue_errinfo(ec, reg_cfp));
@@ -7172,15 +7247,8 @@ vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)
VM_TRACE_HOOK(RUBY_EVENT_END | RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN, TOPN(0));
if ((pc_events & RUBY_EVENT_B_RETURN) && bmethod_frame && (bmethod_events & RUBY_EVENT_RETURN)) {
/* b_return instruction running as a method. Fire return event. */
- vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_RETURN, RUBY_EVENT_RETURN, global_hooks, bmethod_local_hooks_ptr, TOPN(0));
+ vm_trace_hook(ec, reg_cfp, pc, RUBY_EVENT_RETURN, RUBY_EVENT_RETURN, global_hooks, bmethod_local_hooks, TOPN(0));
}
-
- // Pin the iseq since `local_hooks_ptr` points inside the iseq's slot on the GC heap.
- // We need the pointer to stay valid in case compaction happens in a trace hook.
- //
- // Similar treatment is unnecessary for `bmethod_local_hooks_ptr` since
- // storage for `rb_method_definition_t` is not on the GC heap.
- RB_GC_GUARD(iseq_val);
}
}
}
@@ -7384,7 +7452,7 @@ lookup_builtin_invoker(int argc)
static inline VALUE
invoke_bf(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const struct rb_builtin_function* bf, const VALUE *argv)
{
- const bool canary_p = ISEQ_BODY(reg_cfp->iseq)->builtin_attrs & BUILTIN_ATTR_LEAF; // Verify an assumption of `Primitive.attr! :leaf`
+ const bool canary_p = ISEQ_BODY(CFP_ISEQ(reg_cfp))->builtin_attrs & BUILTIN_ATTR_LEAF; // Verify an assumption of `Primitive.attr! :leaf`
SETUP_CANARY(canary_p);
rb_insn_func_t func_ptr = (rb_insn_func_t)(uintptr_t)bf->func_ptr;
VALUE ret = (*lookup_builtin_invoker(bf->argc))(ec, reg_cfp->self, argv, func_ptr);
@@ -7404,7 +7472,7 @@ vm_invoke_builtin_delegate(rb_execution_context_t *ec, rb_control_frame_t *cfp,
if (0) { // debug print
fputs("vm_invoke_builtin_delegate: passing -> ", stderr);
for (int i=0; i<bf->argc; i++) {
- ruby_debug_printf(":%s ", rb_id2name(ISEQ_BODY(cfp->iseq)->local_table[i+start_index]));
+ ruby_debug_printf(":%s ", rb_id2name(ISEQ_BODY(CFP_ISEQ(cfp))->local_table[i+start_index]));
}
ruby_debug_printf("\n" "%s %s(%d):%p\n", RUBY_FUNCTION_NAME_STRING, bf->name, bf->argc,
(void *)(uintptr_t)bf->func_ptr);
@@ -7414,7 +7482,7 @@ vm_invoke_builtin_delegate(rb_execution_context_t *ec, rb_control_frame_t *cfp,
return invoke_bf(ec, cfp, bf, NULL);
}
else {
- const VALUE *argv = cfp->ep - ISEQ_BODY(cfp->iseq)->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index;
+ const VALUE *argv = cfp->ep - ISEQ_BODY(CFP_ISEQ(cfp))->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index;
return invoke_bf(ec, cfp, bf, argv);
}
}
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index ba95740697..2d83fb5897 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -16,11 +16,11 @@ RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_invalidations;
RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_misses;
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
-#if USE_YJIT && YJIT_STATS // We want vm_insns_count only on stats builds.
-// Increment vm_insns_count for --yjit-stats. We increment this even when
+#if YJIT_STATS || ZJIT_STATS // We want vm_insn_count only on stats builds.
+// Increment vm_insn_count for --yjit-stats. We increment this even when
// --yjit or --yjit-stats is not used because branching to skip it is slower.
// We also don't use ATOMIC_INC for performance, allowing inaccuracy on Ractors.
-#define JIT_COLLECT_USAGE_INSN(insn) rb_vm_insns_count++
+#define JIT_COLLECT_USAGE_INSN(insn) rb_vm_insn_count++
#else
#define JIT_COLLECT_USAGE_INSN(insn) // none
#endif
@@ -113,8 +113,11 @@ enum vm_regan_acttype {
#define SET_SV(x) (*GET_SP() = rb_ractor_confirm_belonging(x))
/* set current stack value as x */
-/* instruction sequence C struct */
-#define GET_ISEQ() (GET_CFP()->iseq)
+// instruction sequence C struct
+// Uses cfp->_iseq directly because the interpreter always has a valid _iseq
+// field (it's written on exit from JIT code). Code in vm_insnhelper.c that
+// may be called as a ZJIT fallback should use CFP_ISEQ() instead.
+#define GET_ISEQ() (GET_CFP()->_iseq)
/**********************************************************/
/* deal with variables */
@@ -144,7 +147,7 @@ CC_SET_FASTPATH(const struct rb_callcache *cc, vm_call_handler func, bool enable
}
}
-#define GET_BLOCK_HANDLER() (GET_LEP()[VM_ENV_DATA_INDEX_SPECVAL])
+#define GET_BLOCK_HANDLER() VM_CF_BLOCK_HANDLER(GET_CFP())
/**********************************************************/
/* deal with control flow 3: exception */
diff --git a/vm_method.c b/vm_method.c
index 95a252337f..fb34426bf2 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -23,6 +23,199 @@ static inline rb_method_entry_t *lookup_method_table(VALUE klass, ID id);
/* int ruby_running = 0; */
static enum rb_id_table_iterator_result
+mark_cc_entry_i(VALUE ccs_ptr, void *data)
+{
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
+
+ VM_ASSERT(vm_ccs_p(ccs));
+
+ if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
+ /* Before detaching the CCs from this class, we need to invalidate the cc
+ * since we will no longer be marking the cme on their behalf.
+ */
+ for (int i = 0; i < ccs->len; i++) {
+ const struct rb_callcache *cc = ccs->entries[i].cc;
+ if (cc->klass == Qundef) continue; // already invalidated
+ VM_ASSERT(cc->klass == Qundef || vm_cc_check_cme(cc, ccs->cme));
+ VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
+ vm_cc_invalidate(cc);
+ }
+ ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
+ return ID_TABLE_DELETE;
+ }
+ else {
+ rb_gc_mark_movable((VALUE)ccs->cme);
+
+ for (int i = 0; i < ccs->len; i++) {
+ const struct rb_callcache *cc = ccs->entries[i].cc;
+ VM_ASSERT(cc->klass == Qundef || vm_cc_check_cme(cc, ccs->cme));
+
+ rb_gc_mark_movable((VALUE)cc);
+ }
+ return ID_TABLE_CONTINUE;
+ }
+}
+
+static void
+vm_cc_table_mark(void *data)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)data;
+ if (tbl) {
+ rb_id_table_foreach_values(tbl, mark_cc_entry_i, NULL);
+ }
+}
+
+static enum rb_id_table_iterator_result
+cc_table_free_i(VALUE ccs_ptr, void *data)
+{
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
+ VM_ASSERT(vm_ccs_p(ccs));
+
+ ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
+
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+vm_cc_table_free(void *data)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)data;
+
+ rb_id_table_foreach_values(tbl, cc_table_free_i, NULL);
+ rb_managed_id_table_type.function.dfree(data);
+}
+
+static enum rb_id_table_iterator_result
+cc_table_memsize_i(VALUE ccs_ptr, void *data_ptr)
+{
+ size_t *total_size = data_ptr;
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
+ *total_size += sizeof(*ccs);
+ *total_size += sizeof(ccs->entries[0]) * ccs->capa;
+ return ID_TABLE_CONTINUE;
+}
+
+static size_t
+vm_cc_table_memsize(const void *data)
+{
+ size_t memsize = rb_managed_id_table_type.function.dsize(data);
+ struct rb_id_table *tbl = (struct rb_id_table *)data;
+ rb_id_table_foreach_values(tbl, cc_table_memsize_i, &memsize);
+ return memsize;
+}
+
+static enum rb_id_table_iterator_result
+compact_cc_entry_i(VALUE ccs_ptr, void *data)
+{
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
+
+ ccs->cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)ccs->cme);
+ VM_ASSERT(vm_ccs_p(ccs));
+
+ for (int i=0; i<ccs->len; i++) {
+ ccs->entries[i].cc = (const struct rb_callcache *)rb_gc_location((VALUE)ccs->entries[i].cc);
+ }
+
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+vm_cc_table_compact(void *data)
+{
+ struct rb_id_table *tbl = (struct rb_id_table *)data;
+ rb_id_table_foreach_values(tbl, compact_cc_entry_i, NULL);
+}
+
+static const rb_data_type_t cc_table_type = {
+ .wrap_struct_name = "VM/cc_table",
+ .function = {
+ .dmark = vm_cc_table_mark,
+ .dfree = vm_cc_table_free,
+ .dsize = vm_cc_table_memsize,
+ .dcompact = vm_cc_table_compact,
+ },
+ .parent = &rb_managed_id_table_type,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+};
+
+VALUE
+rb_vm_cc_table_create(size_t capa)
+{
+ return rb_managed_id_table_create(&cc_table_type, capa);
+}
+
+static enum rb_id_table_iterator_result
+vm_cc_table_dup_i(ID key, VALUE old_ccs_ptr, void *data)
+{
+ VALUE new_table = (VALUE)data;
+ struct rb_class_cc_entries *old_ccs = (struct rb_class_cc_entries *)old_ccs_ptr;
+
+ if (METHOD_ENTRY_INVALIDATED(old_ccs->cme)) {
+ // Invalidated CME. This entry will be removed from the old table on
+ // the next GC mark, so it's unsafe (and undesirable) to copy
+ return ID_TABLE_CONTINUE;
+ }
+
+ size_t memsize = vm_ccs_alloc_size(old_ccs->capa);
+ struct rb_class_cc_entries *new_ccs = ruby_xcalloc(1, memsize);
+ rb_managed_id_table_insert(new_table, key, (VALUE)new_ccs);
+
+ // We hold the VM lock, so invalidation should not have happened between
+ // our earlier invalidation check and now.
+ VM_ASSERT(!METHOD_ENTRY_INVALIDATED(old_ccs->cme));
+
+ memcpy(new_ccs, old_ccs, memsize);
+
+#if VM_CHECK_MODE > 0
+ new_ccs->debug_sig = ~(VALUE)new_ccs;
+#endif
+
+ RB_OBJ_WRITTEN(new_table, Qundef, (VALUE)new_ccs->cme);
+ for (int index = 0; index < new_ccs->len; index++) {
+ RB_OBJ_WRITTEN(new_table, Qundef, new_ccs->entries[index].cc);
+ }
+ return ID_TABLE_CONTINUE;
+}
+
+VALUE
+rb_vm_cc_table_dup(VALUE old_table)
+{
+ ASSERT_vm_locking();
+ VALUE new_table = rb_vm_cc_table_create(rb_managed_id_table_size(old_table));
+ rb_managed_id_table_foreach(old_table, vm_cc_table_dup_i, (void *)new_table);
+ return new_table;
+}
+
+static void
+vm_ccs_invalidate(struct rb_class_cc_entries *ccs)
+{
+ for (int i=0; i<ccs->len; i++) {
+ const struct rb_callcache *cc = ccs->entries[i].cc;
+ VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
+ vm_cc_invalidate(cc);
+ }
+}
+
+static void
+rb_vm_ccs_invalidate_and_free(struct rb_class_cc_entries *ccs)
+{
+ RB_DEBUG_COUNTER_INC(ccs_free);
+ vm_ccs_invalidate(ccs);
+ ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
+}
+
+void
+rb_vm_cc_table_delete(VALUE table, ID mid)
+{
+ VALUE ccs_obj;
+ if (rb_managed_id_table_lookup(table, mid, &ccs_obj)) {
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_obj;
+ rb_managed_id_table_delete(table, mid);
+ rb_vm_ccs_invalidate_and_free(ccs);
+ }
+}
+
+static enum rb_id_table_iterator_result
vm_ccs_dump_i(ID mid, VALUE val, void *data)
{
const struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)val;
@@ -39,18 +232,18 @@ vm_ccs_dump_i(ID mid, VALUE val, void *data)
static void
vm_ccs_dump(VALUE klass, ID target_mid)
{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+ VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
if (cc_tbl) {
VALUE ccs;
if (target_mid) {
- if (rb_id_table_lookup(cc_tbl, target_mid, &ccs)) {
+ if (rb_managed_id_table_lookup(cc_tbl, target_mid, &ccs)) {
fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
vm_ccs_dump_i(target_mid, ccs, NULL);
}
}
else {
fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
- rb_id_table_foreach(cc_tbl, vm_ccs_dump_i, (void *)target_mid);
+ rb_managed_id_table_foreach(cc_tbl, vm_ccs_dump_i, (void *)target_mid);
}
}
}
@@ -87,18 +280,18 @@ vm_mtbl_dump(VALUE klass, ID target_mid)
else {
fprintf(stderr, " MTBL: NULL\n");
}
- if (RCLASS_CALLABLE_M_TBL(klass)) {
+ if (RCLASS_WRITABLE_CALLABLE_M_TBL(klass)) {
if (target_mid != 0) {
- if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, &me)) {
+ if (rb_id_table_lookup(RCLASS_WRITABLE_CALLABLE_M_TBL(klass), target_mid, &me)) {
rp_m(" [CM**] ", me);
}
}
else {
fprintf(stderr, " ## RCLASS_CALLABLE_M_TBL\n");
- rb_id_table_foreach(RCLASS_CALLABLE_M_TBL(klass), vm_cme_dump_i, NULL);
+ rb_id_table_foreach(RCLASS_WRITABLE_CALLABLE_M_TBL(klass), vm_cme_dump_i, NULL);
}
}
- if (RCLASS_CC_TBL(klass)) {
+ if (RCLASS_WRITABLE_CC_TBL(klass)) {
vm_ccs_dump(klass, target_mid);
}
klass = RCLASS_SUPER(klass);
@@ -122,31 +315,30 @@ vm_cme_invalidate(rb_callable_method_entry_t *cme)
RB_DEBUG_COUNTER_INC(cc_cme_invalidate);
rb_yjit_cme_invalidate(cme);
+ rb_zjit_cme_invalidate(cme);
}
static int
-rb_clear_constant_cache_for_id_i(st_data_t ic, st_data_t idx, st_data_t arg)
+rb_clear_constant_cache_for_id_i(st_data_t ic, st_data_t arg)
{
((IC) ic)->entry = NULL;
return ST_CONTINUE;
}
-// Here for backward compat.
-void rb_clear_constant_cache(void) {}
-
void
rb_clear_constant_cache_for_id(ID id)
{
VALUE lookup_result;
rb_vm_t *vm = GET_VM();
- if (rb_id_table_lookup(vm->constant_cache, id, &lookup_result)) {
- st_table *ics = (st_table *)lookup_result;
- st_foreach(ics, rb_clear_constant_cache_for_id_i, (st_data_t) NULL);
+ if (rb_id_table_lookup(&vm->constant_cache, id, &lookup_result)) {
+ set_table *ics = (set_table *)lookup_result;
+ set_table_foreach(ics, rb_clear_constant_cache_for_id_i, (st_data_t) NULL);
ruby_vm_constant_cache_invalidations += ics->num_entries;
}
rb_yjit_constant_state_changed(id);
+ rb_zjit_constant_state_changed(id);
}
static void
@@ -155,8 +347,8 @@ invalidate_negative_cache(ID mid)
VALUE cme;
rb_vm_t *vm = GET_VM();
- if (rb_id_table_lookup(vm->negative_cme_table, mid, &cme)) {
- rb_id_table_delete(vm->negative_cme_table, mid);
+ if (rb_id_table_lookup(&vm->negative_cme_table, mid, &cme)) {
+ rb_id_table_delete(&vm->negative_cme_table, mid);
vm_cme_invalidate((rb_callable_method_entry_t *)cme);
RB_DEBUG_COUNTER_INC(cc_invalidate_negative);
}
@@ -166,6 +358,101 @@ const rb_method_entry_t * rb_method_entry_clone(const rb_method_entry_t *src_me)
static const rb_callable_method_entry_t *complemented_callable_method_entry(VALUE klass, ID id);
static const rb_callable_method_entry_t *lookup_overloaded_cme(const rb_callable_method_entry_t *cme);
+static void
+invalidate_method_cache_in_cc_table(VALUE tbl, ID mid)
+{
+ VALUE ccs_data;
+ if (tbl && rb_managed_id_table_lookup(tbl, mid, &ccs_data)) {
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
+ rb_yjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
+ rb_zjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
+ if (NIL_P(ccs->cme->owner)) invalidate_negative_cache(mid);
+ rb_vm_ccs_invalidate_and_free(ccs);
+ rb_managed_id_table_delete(tbl, mid);
+ RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
+ }
+}
+
+static void
+invalidate_callable_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID mid)
+{
+ VALUE cme;
+ if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
+ rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
+ rb_zjit_cme_invalidate((rb_callable_method_entry_t *)cme);
+ rb_id_table_delete(tbl, mid);
+ RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
+ }
+}
+
+struct invalidate_callable_method_entry_foreach_arg {
+ VALUE klass;
+ ID mid;
+ const rb_method_entry_t *cme;
+ const rb_method_entry_t *newer;
+};
+
+static void
+invalidate_callable_method_entry_in_every_m_table_i(rb_classext_t *ext, bool is_prime, VALUE box_value, void *data)
+{
+ st_data_t me;
+ struct invalidate_callable_method_entry_foreach_arg *arg = (struct invalidate_callable_method_entry_foreach_arg *)data;
+ struct rb_id_table *tbl = RCLASSEXT_M_TBL(ext);
+
+ if (rb_id_table_lookup(tbl, arg->mid, &me) && arg->cme == (const rb_method_entry_t *)me) {
+ rb_method_table_insert(arg->klass, tbl, arg->mid, arg->newer);
+ }
+}
+
+struct collect_per_box_origins_arg {
+ VALUE owner;
+ VALUE klass_housing_cme;
+ VALUE origins; // Array of origins
+};
+
+static void
+collect_per_box_origins_i(rb_classext_t *ext, bool is_prime, VALUE box_value, void *data)
+{
+ struct collect_per_box_origins_arg *arg = (struct collect_per_box_origins_arg *)data;
+ VALUE origin = RCLASSEXT_ORIGIN(ext);
+
+ if (origin == arg->owner || origin == arg->klass_housing_cme) {
+ return;
+ }
+ long len = RARRAY_LEN(arg->origins);
+ for (long i = 0; i < len; i++) {
+ if (RARRAY_AREF(arg->origins, i) == origin) {
+ return;
+ }
+ }
+ rb_ary_push(arg->origins, origin);
+}
+
+static void
+invalidate_callable_method_entry_in_every_m_table(VALUE klass, ID mid, const rb_callable_method_entry_t *cme)
+{
+ // The argument cme must be invalidated later in the caller side
+ const rb_method_entry_t *newer = rb_method_entry_clone((const rb_method_entry_t *)cme);
+ struct invalidate_callable_method_entry_foreach_arg arg = {
+ .klass = klass,
+ .mid = mid,
+ .cme = (const rb_method_entry_t *) cme,
+ .newer = newer,
+ };
+ rb_class_classext_foreach(klass, invalidate_callable_method_entry_in_every_m_table_i, (void *)&arg);
+}
+
+static void
+invalidate_complemented_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID mid)
+{
+ VALUE cme;
+ if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
+ rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
+ rb_zjit_cme_invalidate((rb_callable_method_entry_t *)cme);
+ rb_id_table_delete(tbl, mid);
+ RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
+ }
+}
static void
clear_method_cache_by_id_in_class(VALUE klass, ID mid)
@@ -173,97 +460,119 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
if (rb_objspace_garbage_object_p(klass)) return;
- RB_VM_LOCK_ENTER();
- if (LIKELY(RCLASS_SUBCLASSES(klass) == NULL)) {
- // no subclasses
- // check only current class
-
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- VALUE ccs_data;
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+
+ if (LIKELY(!RCLASS_SUBCLASSES(klass)) &&
+ !FL_TEST_RAW(klass, RCLASS_HAS_SUBCLASSES) &&
+ // Non-refinement ICLASSes (from module inclusion) previously had
+ // subclasses reparented onto them, so they need the tree path for
+ // broader cme-based invalidation even though they now have no subclasses.
+ !(RB_TYPE_P(klass, T_ICLASS) && NIL_P(RCLASS_REFINED_CLASS(klass)))) {
+ // no subclasses
+ // check only current class
+
+ // invalidate CCs
+ VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
+ invalidate_method_cache_in_cc_table(cc_tbl, mid);
+ if (RCLASS_CC_TBL_NOT_PRIME_P(klass, cc_tbl)) {
+ invalidate_method_cache_in_cc_table(RCLASS_PRIME_CC_TBL(klass), mid);
+ }
- // invalidate CCs
- if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
- rb_yjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
- if (NIL_P(ccs->cme->owner)) invalidate_negative_cache(mid);
- rb_vm_ccs_free(ccs);
- rb_id_table_delete(cc_tbl, mid);
- RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
- }
-
- // remove from callable_m_tbl, if exists
- struct rb_id_table *cm_tbl;
- if ((cm_tbl = RCLASS_CALLABLE_M_TBL(klass)) != NULL) {
- VALUE cme;
- if (rb_yjit_enabled_p && rb_id_table_lookup(cm_tbl, mid, &cme)) {
- rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
+ // remove from callable_m_tbl, if exists
+ struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(klass);
+ invalidate_callable_method_entry_in_callable_m_table(cm_tbl, mid);
+ if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(klass, cm_tbl)) {
+ invalidate_callable_method_entry_in_callable_m_table(RCLASS_PRIME_CALLABLE_M_TBL(klass), mid);
}
- rb_id_table_delete(cm_tbl, mid);
- RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
+
+ RB_DEBUG_COUNTER_INC(cc_invalidate_leaf);
}
- RB_DEBUG_COUNTER_INC(cc_invalidate_leaf);
- }
- else {
- const rb_callable_method_entry_t *cme = complemented_callable_method_entry(klass, mid);
+ else {
+ const rb_callable_method_entry_t *cme = complemented_callable_method_entry(klass, mid);
- if (cme) {
- // invalidate cme if found to invalidate the inline method cache.
- if (METHOD_ENTRY_CACHED(cme)) {
- if (METHOD_ENTRY_COMPLEMENTED(cme)) {
- // do nothing
- }
- else {
- // invalidate cc by invalidating cc->cme
- VALUE owner = cme->owner;
- VM_ASSERT_TYPE(owner, T_CLASS);
- VALUE klass_housing_cme;
- if (cme->def->type == VM_METHOD_TYPE_REFINED && !cme->def->body.refined.orig_me) {
- klass_housing_cme = owner;
+ if (cme) {
+ // invalidate cme if found to invalidate the inline method cache.
+ if (METHOD_ENTRY_CACHED(cme)) {
+ if (METHOD_ENTRY_COMPLEMENTED(cme)) {
+ // do nothing
}
else {
- klass_housing_cme = RCLASS_ORIGIN(owner);
+ // invalidate cc by invalidating cc->cme
+ VALUE owner = cme->owner;
+ VM_ASSERT_TYPE(owner, T_CLASS);
+ VALUE klass_housing_cme;
+ if (cme->def->type == VM_METHOD_TYPE_REFINED && !cme->def->body.refined.orig_me) {
+ klass_housing_cme = owner;
+ }
+ else {
+ klass_housing_cme = RCLASS_ORIGIN(owner);
+ }
+
+ // replace the cme that will be invalid in the all classexts
+ invalidate_callable_method_entry_in_every_m_table(klass_housing_cme, mid, cme);
+ // owner may be a boxable class with per-box classext copies of its m_tbl
+ // (klass_housing_cme may be a non-boxable origin ICLASS that doesn't cover them)
+ if (klass_housing_cme != owner) {
+ invalidate_callable_method_entry_in_every_m_table(owner, mid, cme);
+ }
+ // Also update per-box origin ICLASSes. When ensure_origin is called in
+ // one box's context, it creates a per-box origin ICLASS whose m_tbl is
+ // a copy of owner's m_tbl at that time. The current execution box may
+ // not see these origins via RCLASS_ORIGIN(owner), so we find them by
+ // iterating all of owner's classexts and checking their origin_ fields.
+ {
+ VALUE origins = rb_ary_new();
+ struct collect_per_box_origins_arg origins_arg = {
+ .owner = owner,
+ .klass_housing_cme = klass_housing_cme,
+ .origins = origins,
+ };
+ rb_class_classext_foreach(owner, collect_per_box_origins_i, &origins_arg);
+ for (long i = 0; i < RARRAY_LEN(origins); i++) {
+ invalidate_callable_method_entry_in_every_m_table(RARRAY_AREF(origins, i), mid, cme);
+ }
+ }
}
- // replace the cme that will be invalid
- VM_ASSERT(lookup_method_table(klass_housing_cme, mid) == (const rb_method_entry_t *)cme);
- const rb_method_entry_t *new_cme = rb_method_entry_clone((const rb_method_entry_t *)cme);
- rb_method_table_insert(klass_housing_cme, RCLASS_M_TBL(klass_housing_cme), mid, new_cme);
- }
- vm_cme_invalidate((rb_callable_method_entry_t *)cme);
- RB_DEBUG_COUNTER_INC(cc_invalidate_tree_cme);
+ vm_cme_invalidate((rb_callable_method_entry_t *)cme);
+ RB_DEBUG_COUNTER_INC(cc_invalidate_tree_cme);
+
+ // In case of refinement ME, also invalidate the wrapped ME that
+ // could be cached at some callsite and is unreachable from any
+ // RCLASS_WRITABLE_CC_TBL.
+ if (cme->def->type == VM_METHOD_TYPE_REFINED && cme->def->body.refined.orig_me) {
+ vm_cme_invalidate((rb_callable_method_entry_t *)cme->def->body.refined.orig_me);
+ }
- // In case of refinement ME, also invalidate the wrapped ME that
- // could be cached at some callsite and is unreachable from any
- // RCLASS_CC_TBL.
- if (cme->def->type == VM_METHOD_TYPE_REFINED && cme->def->body.refined.orig_me) {
- vm_cme_invalidate((rb_callable_method_entry_t *)cme->def->body.refined.orig_me);
+ if (cme->def->iseq_overload) {
+ rb_callable_method_entry_t *monly_cme = (rb_callable_method_entry_t *)lookup_overloaded_cme(cme);
+ if (monly_cme) {
+ vm_cme_invalidate(monly_cme);
+ }
+ }
}
- if (cme->def->iseq_overload) {
- rb_callable_method_entry_t *monly_cme = (rb_callable_method_entry_t *)lookup_overloaded_cme(cme);
- if (monly_cme) {
- vm_cme_invalidate(monly_cme);
+ // invalidate complement tbl
+ if (METHOD_ENTRY_COMPLEMENTED(cme)) {
+ VALUE defined_class = cme->defined_class;
+ struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
+ invalidate_complemented_method_entry_in_callable_m_table(cm_tbl, mid);
+ if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(defined_class, cm_tbl)) {
+ struct rb_id_table *prime_cm_table = RCLASS_PRIME_CALLABLE_M_TBL(defined_class);
+ invalidate_complemented_method_entry_in_callable_m_table(prime_cm_table, mid);
}
}
- }
- // invalidate complement tbl
- if (METHOD_ENTRY_COMPLEMENTED(cme)) {
- VALUE defined_class = cme->defined_class;
- struct rb_id_table *cm_tbl = RCLASS_CALLABLE_M_TBL(defined_class);
- VM_ASSERT(cm_tbl != NULL);
- int r = rb_id_table_delete(cm_tbl, mid);
- VM_ASSERT(r == TRUE); (void)r;
- RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
+ RB_DEBUG_COUNTER_INC(cc_invalidate_tree);
+ }
+ else {
+ invalidate_negative_cache(mid);
}
-
- RB_DEBUG_COUNTER_INC(cc_invalidate_tree);
- }
- else {
- invalidate_negative_cache(mid);
}
+
+ rb_gccct_clear_table();
}
- RB_VM_LOCK_LEAVE();
}
static void
@@ -302,28 +611,31 @@ rb_clear_method_cache(VALUE klass_or_module, ID mid)
}
}
-static int
-invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data)
-{
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- void *ptr = rb_asan_poisoned_object_p(v);
- rb_asan_unpoison_object(v, false);
-
- if (RBASIC(v)->flags) { // liveness check
- if (imemo_type_p(v, imemo_callcache)) {
- const struct rb_callcache *cc = (const struct rb_callcache *)v;
- if (vm_cc_refinement_p(cc) && cc->klass) {
- vm_cc_invalidate(cc);
- }
- }
- }
+static enum rb_id_table_iterator_result
+invalidate_method_entry_in_iclass_callable_m_tbl(VALUE cme, void *data)
+{
+ vm_cme_invalidate((rb_callable_method_entry_t *)cme);
+ return ID_TABLE_DELETE;
+}
- if (ptr) {
- rb_asan_poison_object(v);
- }
+static enum rb_id_table_iterator_result
+invalidate_ccs_in_iclass_cc_tbl(VALUE value, void *data)
+{
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)value;
+ vm_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
+ ruby_xfree_sized(ccs, vm_ccs_alloc_size(ccs->capa));
+ return ID_TABLE_DELETE;
+}
+
+void
+rb_invalidate_method_caches(struct rb_id_table *cm_tbl, VALUE cc_tbl)
+{
+ if (cm_tbl) {
+ rb_id_table_foreach_values(cm_tbl, invalidate_method_entry_in_iclass_callable_m_tbl, NULL);
+ }
+ if (cc_tbl) {
+ rb_managed_id_table_foreach_values(cc_tbl, invalidate_ccs_in_iclass_cc_tbl, NULL);
}
- return 0; // continue to iteration
}
static st_index_t
@@ -361,7 +673,8 @@ vm_ci_hash_cmp(VALUE v1, VALUE v2)
return 1;
}
}
- } else {
+ }
+ else {
VM_ASSERT(ci2->kwarg == NULL); // implied by matching flags
}
return 0;
@@ -382,7 +695,8 @@ ci_lookup_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
if (rb_objspace_garbage_object_p((VALUE)ci)) {
*ret = (st_data_t)NULL;
return ST_DELETE;
- } else {
+ }
+ else {
*ret = *key;
return ST_STOP;
}
@@ -400,24 +714,21 @@ rb_vm_ci_lookup(ID mid, unsigned int flag, unsigned int argc, const struct rb_ca
const struct rb_callinfo *ci = NULL;
if (kwarg) {
- ((struct rb_callinfo_kwarg *)kwarg)->references++;
+ RUBY_ATOMIC_FETCH_ADD(((struct rb_callinfo_kwarg *)kwarg)->references, 1);
}
- struct rb_callinfo *new_ci = IMEMO_NEW(struct rb_callinfo, imemo_callinfo, (VALUE)kwarg);
+ struct rb_callinfo *new_ci = SHAREABLE_IMEMO_NEW(struct rb_callinfo, imemo_callinfo, (VALUE)kwarg);
new_ci->mid = mid;
new_ci->flag = flag;
new_ci->argc = argc;
- RB_VM_LOCK_ENTER();
- {
- st_table *ci_table = vm->ci_table;
- VM_ASSERT(ci_table);
+ RB_VM_LOCKING() {
+ st_table *ci_table = &vm->ci_table;
do {
st_update(ci_table, (st_data_t)new_ci, ci_lookup_i, (st_data_t)&ci);
} while (ci == NULL);
}
- RB_VM_LOCK_LEAVE();
VM_ASSERT(ci);
@@ -432,25 +743,145 @@ rb_vm_ci_free(const struct rb_callinfo *ci)
rb_vm_t *vm = GET_VM();
st_data_t key = (st_data_t)ci;
- st_delete(vm->ci_table, &key, NULL);
+ st_delete(&vm->ci_table, &key, NULL);
+}
+
+struct cc_refinement_entries {
+ VALUE *entries;
+ size_t len;
+ size_t capa;
+};
+
+static void
+cc_refinement_set_free(void *ptr)
+{
+ struct cc_refinement_entries *e = ptr;
+ xfree(e->entries);
+}
+
+static size_t
+cc_refinement_set_memsize(const void *ptr)
+{
+ const struct cc_refinement_entries *e = ptr;
+ return e->capa * sizeof(VALUE);
+}
+
+static void
+cc_refinement_set_compact(void *ptr)
+{
+ struct cc_refinement_entries *e = ptr;
+ for (size_t i = 0; i < e->len; i++) {
+ e->entries[i] = rb_gc_location(e->entries[i]);
+ }
+}
+
+static void
+cc_refinement_set_handle_weak_references(void *ptr)
+{
+ struct cc_refinement_entries *e = ptr;
+ size_t write = 0;
+ for (size_t read = 0; read < e->len; read++) {
+ if (rb_gc_handle_weak_references_alive_p(e->entries[read])) {
+ e->entries[write++] = e->entries[read];
+ }
+ }
+ e->len = write;
+}
+
+static const rb_data_type_t cc_refinement_set_type = {
+ "VM/cc_refinement_set",
+ {
+ NULL,
+ cc_refinement_set_free,
+ cc_refinement_set_memsize,
+ cc_refinement_set_compact,
+ cc_refinement_set_handle_weak_references,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+};
+
+VALUE
+rb_cc_refinement_set_create(void)
+{
+ struct cc_refinement_entries *e;
+ VALUE obj = TypedData_Make_Struct(0, struct cc_refinement_entries, &cc_refinement_set_type, e);
+
+ e->entries = NULL;
+ e->len = 0;
+ e->capa = 0;
+
+ rb_gc_declare_weak_references(obj);
+
+ return obj;
+}
+
+void
+rb_vm_insert_cc_refinement(const struct rb_callcache *cc)
+{
+ rb_vm_t *vm = GET_VM();
+ RB_VM_LOCK_ENTER();
+ {
+ struct cc_refinement_entries *e = RTYPEDDATA_GET_DATA(vm->cc_refinement_set);
+ if (e->len == e->capa) {
+ size_t new_capa = e->capa == 0 ? 16 : e->capa * 2;
+ SIZED_REALLOC_N(e->entries, VALUE, new_capa, e->capa);
+ e->capa = new_capa;
+ }
+ e->entries[e->len++] = (VALUE)cc;
+
+ // We never mark the cc, but we need to issue a writebarrier so that
+ // the refinement set can be added to the remembered set
+ RB_OBJ_WRITTEN(vm->cc_refinement_set, Qundef, (VALUE)cc);
+ }
+ RB_VM_LOCK_LEAVE();
}
void
rb_clear_all_refinement_method_cache(void)
{
- rb_objspace_each_objects(invalidate_all_refinement_cc, NULL);
+ rb_vm_t *vm = GET_VM();
+
+ RB_VM_LOCK_ENTER();
+ {
+ struct cc_refinement_entries *e = RTYPEDDATA_GET_DATA(vm->cc_refinement_set);
+ for (size_t i = 0; i < e->len; i++) {
+ VALUE v = e->entries[i];
+
+ // All objects should be live as weak references are pruned in
+ // cc_refinement_set_handle_weak_references
+ VM_ASSERT(rb_gc_pointer_to_heap_p(v));
+ VM_ASSERT(!rb_objspace_garbage_object_p(v));
+
+ const struct rb_callcache *cc = (const struct rb_callcache *)v;
+ VM_ASSERT(vm_cc_refinement_p(cc));
+
+ if (vm_cc_valid(cc)) {
+ vm_cc_invalidate(cc);
+ }
+ }
+ e->len = 0;
+ }
+ RB_VM_LOCK_LEAVE();
+
rb_yjit_invalidate_all_method_lookup_assumptions();
}
void
rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me)
{
+ RB_VM_LOCKING() {
+ rb_method_table_insert0(klass, table, method_id, me, RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass));
+ }
+}
+
+void
+rb_method_table_insert0(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me, bool iclass_shared_mtbl)
+{
VALUE table_owner = klass;
- if (RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass)) {
+ if (iclass_shared_mtbl) {
table_owner = RBASIC(table_owner)->klass;
}
VM_ASSERT_TYPE3(table_owner, T_CLASS, T_ICLASS, T_MODULE);
- VM_ASSERT(table == RCLASS_M_TBL(table_owner));
rb_id_table_insert(table, method_id, (VALUE)me);
RB_OBJ_WRITTEN(table_owner, Qundef, (VALUE)me);
}
@@ -508,7 +939,7 @@ rb_add_method_optimized(VALUE klass, ID mid, enum method_optimized_type opt_type
}
static void
-rb_method_definition_release(rb_method_definition_t *def)
+method_definition_release(rb_method_definition_t *def)
{
if (def != NULL) {
const unsigned int reference_count_was = RUBY_ATOMIC_FETCH_SUB(def->reference_count, 1);
@@ -518,10 +949,7 @@ rb_method_definition_release(rb_method_definition_t *def)
if (reference_count_was == 1) {
if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:1->0 (remove)\n", (void *)def,
rb_id2name(def->original_id));
- if (def->type == VM_METHOD_TYPE_BMETHOD && def->body.bmethod.hooks) {
- xfree(def->body.bmethod.hooks);
- }
- xfree(def);
+ SIZED_FREE(def);
}
else {
if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:%d->%d (dec)\n", (void *)def, rb_id2name(def->original_id),
@@ -530,6 +958,12 @@ rb_method_definition_release(rb_method_definition_t *def)
}
}
+void
+rb_method_definition_release(rb_method_definition_t *def)
+{
+ method_definition_release(def);
+}
+
static void delete_overloaded_cme(const rb_callable_method_entry_t *cme);
void
@@ -543,7 +977,18 @@ rb_free_method_entry_vm_weak_references(const rb_method_entry_t *me)
void
rb_free_method_entry(const rb_method_entry_t *me)
{
- rb_method_definition_release(me->def);
+#if USE_ZJIT
+ if (METHOD_ENTRY_CACHED(me)) {
+ rb_zjit_cme_free((const rb_callable_method_entry_t *)me);
+ }
+#endif
+
+#if USE_YJIT
+ // YJIT rb_yjit_root_mark() roots CMEs in `Invariants`,
+ // to remove from `Invariants` here.
+#endif
+
+ method_definition_release(me->def);
}
static inline rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr);
@@ -610,6 +1055,7 @@ setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(ANYARGS), int
cfunc->invoker = call_cfunc_invoker_func(argc);
}
+
static rb_method_definition_t *
method_definition_addref(rb_method_definition_t *def, bool complemented)
{
@@ -624,9 +1070,15 @@ method_definition_addref(rb_method_definition_t *def, bool complemented)
}
void
+rb_method_definition_addref(rb_method_definition_t *def)
+{
+ method_definition_addref(def, false);
+}
+
+void
rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
{
- rb_method_definition_release(me->def);
+ method_definition_release(me->def);
*(rb_method_definition_t **)&me->def = method_definition_addref(def, METHOD_ENTRY_COMPLEMENTED(me));
if (!ruby_running) add_opt_method_entry(me);
@@ -642,7 +1094,7 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de
/* setup iseq first (before invoking GC) */
RB_OBJ_WRITE(me, &def->body.iseq.iseqptr, iseq);
- // Methods defined in `with_yjit` should be considered METHOD_ENTRY_BASIC
+ // Methods defined in `with_jit` should be considered METHOD_ENTRY_BASIC
if (rb_iseq_attr_p(iseq, BUILTIN_ATTR_C_TRACE)) {
METHOD_ENTRY_BASIC_SET((rb_method_entry_t *)me, TRUE);
}
@@ -679,8 +1131,10 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de
cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
if (cfp && (line = rb_vm_get_sourceline(cfp))) {
- VALUE location = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line));
- RB_OBJ_WRITE(me, &def->body.attr.location, rb_ary_freeze(location));
+ VALUE location = rb_ary_new3(2, rb_iseq_path(CFP_ISEQ(cfp)), INT2FIX(line));
+ rb_ary_freeze(location);
+ RB_OBJ_SET_SHAREABLE(location);
+ RB_OBJ_WRITE(me, &def->body.attr.location, location);
}
else {
VM_ASSERT(def->body.attr.location == 0);
@@ -689,7 +1143,7 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de
}
case VM_METHOD_TYPE_BMETHOD:
RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts);
- RB_OBJ_WRITE(me, &def->body.bmethod.defined_ractor, rb_ractor_self(GET_RACTOR()));
+ def->body.bmethod.defined_ractor_id = rb_ec_ractor_id(GET_EC());
return;
case VM_METHOD_TYPE_NOTIMPLEMENTED:
setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), (VALUE(*)(ANYARGS))rb_f_notimplement_internal, -1);
@@ -729,9 +1183,6 @@ method_definition_reset(const rb_method_entry_t *me)
break;
case VM_METHOD_TYPE_BMETHOD:
RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.proc);
- RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.defined_ractor);
- /* give up to check all in a list */
- if (def->body.bmethod.hooks) rb_gc_writebarrier_remember((VALUE)me);
break;
case VM_METHOD_TYPE_REFINED:
RB_OBJ_WRITTEN(me, Qundef, def->body.refined.orig_me);
@@ -749,6 +1200,8 @@ method_definition_reset(const rb_method_entry_t *me)
}
}
+static rb_atomic_t method_serial = 1;
+
rb_method_definition_t *
rb_method_definition_create(rb_method_type_t type, ID mid)
{
@@ -756,8 +1209,8 @@ rb_method_definition_create(rb_method_type_t type, ID mid)
def = ZALLOC(rb_method_definition_t);
def->type = type;
def->original_id = mid;
- static uintptr_t method_serial = 1;
- def->method_serial = method_serial++;
+ def->method_serial = (uintptr_t)RUBY_ATOMIC_FETCH_ADD(method_serial, 1);
+ def->box = rb_current_box();
return def;
}
@@ -769,7 +1222,11 @@ rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, rb_method_
// not negative cache
VM_ASSERT_TYPE2(defined_class, T_CLASS, T_ICLASS);
}
- rb_method_entry_t *me = IMEMO_NEW(rb_method_entry_t, imemo_ment, defined_class);
+ rb_method_entry_t *me = SHAREABLE_IMEMO_NEW(rb_method_entry_t, imemo_ment, defined_class);
+
+ // mark_and_move_method_entry pins itself when it is in the overloaded_cme table
+ rb_gc_register_pinning_obj((VALUE)me);
+
*((rb_method_definition_t **)&me->def) = def;
me->called_id = called_id;
me->owner = owner;
@@ -863,7 +1320,7 @@ rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID cal
void
rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src)
{
- rb_method_definition_release(dst->def);
+ method_definition_release(dst->def);
*(rb_method_definition_t **)&dst->def = method_definition_addref(src->def, METHOD_ENTRY_COMPLEMENTED(src));
method_definition_reset(dst);
dst->called_id = src->called_id;
@@ -928,6 +1385,16 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid)
static void
check_override_opt_method_i(VALUE klass, VALUE arg)
{
+ if (RB_TYPE_P(klass, T_ICLASS)) {
+ // ICLASS from a module's subclass list: check the includer and
+ // recurse into the includer's T_CLASS subclasses.
+ VALUE includer = RCLASS_INCLUDER(klass);
+ if (!UNDEF_P(includer) && includer) {
+ check_override_opt_method_i(includer, arg);
+ }
+ return;
+ }
+
ID mid = (ID)arg;
const rb_method_entry_t *me, *newme;
@@ -949,6 +1416,13 @@ check_override_opt_method(VALUE klass, VALUE mid)
}
}
+VALUE
+rb_zsuper_to_super(int argc, VALUE *argv, VALUE self)
+{
+ return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
+}
+
+static inline rb_method_entry_t* search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined);
/*
* klass->method_table[mid] = method_entry(defined_class, visi, def)
*
@@ -964,6 +1438,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
st_data_t data;
int make_refined = 0;
VALUE orig_klass;
+ bool turn_zsuper_to_super = false;
if (NIL_P(klass)) {
klass = rb_cObject;
@@ -989,6 +1464,9 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
if (RB_TYPE_P(klass, T_MODULE) && FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
VALUE refined_class = rb_refinement_module_get_refined_class(klass);
+ if (type == VM_METHOD_TYPE_ZSUPER) {
+ turn_zsuper_to_super = true;
+ }
rb_add_refined_method_entry(refined_class, mid);
}
if (type == VM_METHOD_TYPE_REFINED) {
@@ -1001,7 +1479,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
rb_clear_method_cache(orig_klass, mid);
}
}
- mtbl = RCLASS_M_TBL(klass);
+ mtbl = RCLASS_WRITABLE_M_TBL(klass);
/* check re-definition */
if (rb_id_table_lookup(mtbl, mid, &data)) {
@@ -1052,6 +1530,12 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
me = rb_method_entry_create(mid, defined_class, visi, NULL);
if (def == NULL) {
def = rb_method_definition_create(type, original_id);
+ if (turn_zsuper_to_super) {
+ def->type = VM_METHOD_TYPE_CFUNC;
+ def->body.cfunc.func = (rb_cfunc_t)rb_zsuper_to_super;
+ def->body.cfunc.invoker = ractor_safe_call_cfunc_m1;
+ def->body.cfunc.argc = -1;
+ }
}
rb_method_definition_set(me, def, opts);
@@ -1093,8 +1577,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
static st_table *
overloaded_cme_table(void)
{
- VM_ASSERT(GET_VM()->overloaded_cme_table != NULL);
- return GET_VM()->overloaded_cme_table;
+ return &GET_VM()->overloaded_cme_table;
}
#if VM_CHECK_MODE > 0
@@ -1229,7 +1712,9 @@ method_added(VALUE klass, ID mid)
void
rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_visibility_t visi)
{
- rb_method_entry_make(klass, mid, klass, visi, type, NULL, mid, opts);
+ RB_VM_LOCKING() {
+ rb_method_entry_make(klass, mid, klass, visi, type, NULL, mid, opts);
+ }
if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
method_added(klass, mid);
@@ -1254,11 +1739,14 @@ static rb_method_entry_t *
method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me,
rb_method_visibility_t visi, VALUE defined_class)
{
- rb_method_entry_t *newme = rb_method_entry_make(klass, mid, defined_class, visi,
- me->def->type, me->def, 0, NULL);
- if (newme == me) {
- me->def->no_redef_warning = TRUE;
- METHOD_ENTRY_FLAGS_SET(newme, visi, FALSE);
+ rb_method_entry_t *newme;
+ RB_VM_LOCKING() {
+ newme = rb_method_entry_make(klass, mid, defined_class, visi,
+ me->def->type, me->def, 0, NULL);
+ if (newme == me) {
+ me->def->no_redef_warning = TRUE;
+ METHOD_ENTRY_FLAGS_SET(newme, visi, FALSE);
+ }
}
method_added(klass, mid);
@@ -1273,6 +1761,17 @@ rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_
#define UNDEF_ALLOC_FUNC ((rb_alloc_func_t)-1)
+static void
+propagate_alloc_func(VALUE subclass, VALUE arg)
+{
+ if (RB_TYPE_P(subclass, T_CLASS) &&
+ !RCLASS_SINGLETON_P(subclass) &&
+ !FL_TEST_RAW(subclass, RCLASS_ALLOCATOR_DEFINED)) {
+ RCLASS_SET_ALLOCATOR(subclass, (rb_alloc_func_t)arg);
+ rb_class_foreach_subclass(subclass, propagate_alloc_func, arg);
+ }
+}
+
void
rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
{
@@ -1281,25 +1780,28 @@ rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
rb_raise(rb_eTypeError, "can't define an allocator for a singleton class");
}
RCLASS_SET_ALLOCATOR(klass, func);
+ FL_SET_RAW(klass, RCLASS_ALLOCATOR_DEFINED);
+ rb_class_foreach_subclass(klass, propagate_alloc_func, (VALUE)func);
}
void
rb_undef_alloc_func(VALUE klass)
{
- rb_define_alloc_func(klass, UNDEF_ALLOC_FUNC);
+ Check_Type(klass, T_CLASS);
+ RCLASS_SET_ALLOCATOR(klass, UNDEF_ALLOC_FUNC);
+ FL_SET_RAW(klass, RCLASS_ALLOCATOR_DEFINED);
+ rb_class_foreach_subclass(klass, propagate_alloc_func, (VALUE)UNDEF_ALLOC_FUNC);
}
rb_alloc_func_t
rb_get_alloc_func(VALUE klass)
{
- Check_Type(klass, T_CLASS);
+ RBIMPL_ASSERT_TYPE(klass, T_CLASS);
- for (; klass; klass = RCLASS_SUPER(klass)) {
- rb_alloc_func_t allocator = RCLASS_ALLOCATOR(klass);
- if (allocator == UNDEF_ALLOC_FUNC) break;
- if (allocator) return allocator;
- }
- return 0;
+ rb_alloc_func_t allocator = RCLASS_ALLOCATOR(klass);
+ if (allocator == UNDEF_ALLOC_FUNC) return 0;
+ RUBY_ASSERT(allocator);
+ return allocator;
}
const rb_method_entry_t *
@@ -1329,7 +1831,11 @@ search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined)
if (me == NULL) RB_DEBUG_COUNTER_INC(mc_search_notfound);
- VM_ASSERT(me == NULL || !METHOD_ENTRY_INVALIDATED(me));
+ VM_ASSERT(me == NULL || !METHOD_ENTRY_INVALIDATED(me),
+ "invalid me, mid:%s, klass:%s(%s)",
+ rb_id2name(id),
+ RTEST(rb_mod_name(klass)) ? RSTRING_PTR(rb_mod_name(klass)) : "anonymous",
+ rb_obj_info(klass));
return me;
}
@@ -1364,24 +1870,27 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_
struct rb_id_table *mtbl;
const rb_callable_method_entry_t *cme;
VALUE cme_data;
+ int cme_found = 0;
if (me) {
if (me->defined_class == 0) {
RB_DEBUG_COUNTER_INC(mc_cme_complement);
VM_ASSERT_TYPE2(defined_class, T_ICLASS, T_MODULE);
- VM_ASSERT(me->defined_class == 0, "me->defined_class: %s", rb_obj_info(me->defined_class));
-
- mtbl = RCLASS_CALLABLE_M_TBL(defined_class);
+ mtbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
if (mtbl && rb_id_table_lookup(mtbl, id, &cme_data)) {
cme = (rb_callable_method_entry_t *)cme_data;
+ cme_found = 1;
+ }
+ if (cme_found) {
RB_DEBUG_COUNTER_INC(mc_cme_complement_hit);
VM_ASSERT(callable_method_entry_p(cme));
VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
}
else if (create) {
if (!mtbl) {
- mtbl = RCLASS_EXT(defined_class)->callable_m_tbl = rb_id_table_create(0);
+ mtbl = rb_id_table_create(0);
+ RCLASS_WRITE_CALLABLE_M_TBL(defined_class, mtbl);
}
cme = rb_method_entry_complement_defined_class(me, me->called_id, defined_class);
rb_id_table_insert(mtbl, id, (VALUE)cme);
@@ -1417,10 +1926,10 @@ cached_callable_method_entry(VALUE klass, ID mid)
{
ASSERT_vm_locking();
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+ VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
VALUE ccs_data;
- if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ if (cc_tbl && rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) {
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
VM_ASSERT(vm_ccs_p(ccs));
@@ -1430,8 +1939,10 @@ cached_callable_method_entry(VALUE klass, ID mid)
return ccs->cme;
}
else {
- rb_vm_ccs_free(ccs);
- rb_id_table_delete(cc_tbl, mid);
+ rb_vm_barrier();
+
+ rb_managed_id_table_delete(cc_tbl, mid);
+ rb_vm_ccs_invalidate_and_free(ccs);
}
}
@@ -1445,21 +1956,29 @@ cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_
ASSERT_vm_locking();
VM_ASSERT(cme != NULL);
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+ VALUE cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
VALUE ccs_data;
if (!cc_tbl) {
- cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2);
+ cc_tbl = rb_vm_cc_table_create(2);
+ RCLASS_WRITE_CC_TBL(klass, cc_tbl);
}
- if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) {
#if VM_CHECK_MODE > 0
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
VM_ASSERT(ccs->cme == cme);
#endif
}
else {
- vm_ccs_create(klass, cc_tbl, mid, cme);
+ if (rb_multi_ractor_p()) {
+ VALUE new_cc_tbl = rb_vm_cc_table_dup(cc_tbl);
+ vm_ccs_create(klass, new_cc_tbl, mid, cme);
+ RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)), new_cc_tbl);
+ }
+ else {
+ vm_ccs_create(klass, cc_tbl, mid, cme);
+ }
}
}
@@ -1470,12 +1989,12 @@ negative_cme(ID mid)
const rb_callable_method_entry_t *cme;
VALUE cme_data;
- if (rb_id_table_lookup(vm->negative_cme_table, mid, &cme_data)) {
+ if (rb_id_table_lookup(&vm->negative_cme_table, mid, &cme_data)) {
cme = (rb_callable_method_entry_t *)cme_data;
}
else {
cme = (rb_callable_method_entry_t *)rb_method_entry_alloc(mid, Qnil, Qnil, NULL, false);
- rb_id_table_insert(vm->negative_cme_table, mid, (VALUE)cme);
+ rb_id_table_insert(&vm->negative_cme_table, mid, (VALUE)cme);
}
VM_ASSERT(cme != NULL);
@@ -1488,8 +2007,26 @@ callable_method_entry_or_negative(VALUE klass, ID mid, VALUE *defined_class_ptr)
const rb_callable_method_entry_t *cme;
VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS);
- RB_VM_LOCK_ENTER();
- {
+
+ /* Fast path: lock-free read from cache */
+ VALUE cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass));
+ if (cc_tbl) {
+ VALUE ccs_data;
+ if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) {
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
+ VM_ASSERT(vm_ccs_p(ccs));
+
+ if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) {
+ VM_ASSERT(ccs->cme->called_id == mid);
+ if (defined_class_ptr != NULL) *defined_class_ptr = ccs->cme->defined_class;
+ RB_DEBUG_COUNTER_INC(ccs_found);
+ return ccs->cme;
+ }
+ }
+ }
+
+ /* Slow path: need to lock and potentially populate cache */
+ RB_VM_LOCKING() {
cme = cached_callable_method_entry(klass, mid);
if (cme) {
@@ -1510,7 +2047,6 @@ callable_method_entry_or_negative(VALUE klass, ID mid, VALUE *defined_class_ptr)
cache_callable_method_entry(klass, mid, cme);
}
}
- RB_VM_LOCK_LEAVE();
return cme;
}
@@ -1634,7 +2170,12 @@ resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *de
tmp_me = me->def->body.refined.orig_me;
if (tmp_me) {
- if (defined_class_ptr) *defined_class_ptr = tmp_me->defined_class;
+ if (!tmp_me->defined_class) {
+ VM_ASSERT_TYPE(tmp_me->owner, T_MODULE);
+ }
+ else if (defined_class_ptr) {
+ *defined_class_ptr = tmp_me->defined_class;
+ }
return tmp_me;
}
@@ -1693,7 +2234,7 @@ remove_method(VALUE klass, ID mid)
rb_clear_method_cache(self, mid);
}
rb_clear_method_cache(klass, mid);
- rb_id_table_delete(RCLASS_M_TBL(klass), mid);
+ rb_id_table_delete(RCLASS_WRITABLE_M_TBL(klass), mid);
rb_vm_check_redefinition_opt_method(me, klass);
@@ -1847,7 +2388,7 @@ scope_visibility_check(void)
{
/* Check for public/protected/private/module_function called inside a method */
rb_control_frame_t *cfp = GET_EC()->cfp+1;
- if (cfp && cfp->iseq && ISEQ_BODY(cfp->iseq)->type == ISEQ_TYPE_METHOD) {
+ if (cfp && CFP_ISEQ(cfp) && ISEQ_BODY(CFP_ISEQ(cfp))->type == ISEQ_TYPE_METHOD) {
rb_warn("calling %s without arguments inside a method may not have the intended effect",
rb_id2name(rb_frame_this_func()));
}
@@ -2467,21 +3008,53 @@ rb_mod_public(int argc, VALUE *argv, VALUE module)
* protected(method_name, method_name, ...) -> array
* protected(array) -> array
*
- * With no arguments, sets the default visibility for subsequently
- * defined methods to protected. With arguments, sets the named methods
- * to have protected visibility.
- * String arguments are converted to symbols.
- * An Array of Symbols and/or Strings is also accepted.
- * If a single argument is passed, it is returned.
- * If no argument is passed, nil is returned.
- * If multiple arguments are passed, the arguments are returned as an array.
+ * Sets the visibility of a section or of a list of method names as protected.
+ * Accepts no arguments, a splat of method names (symbols or strings) or an
+ * array of method names. Returns the arguments that it received.
+ *
+ * == Important difference between protected in other languages
+ *
+ * Protected methods in Ruby are different from other languages such as Java,
+ * where methods are marked as protected to give access to subclasses. In Ruby,
+ * subclasses <b>already have access to all methods defined in the parent
+ * class</b>, even private ones.
+ *
+ * Marking a method as protected allows <b>different objects of the same
+ * class</b> to call it.
+ *
+ * One use case is for comparison methods, such as <code>==</code>, if we want
+ * to expose a method for comparison between objects of the same class without
+ * making the method public to objects of other classes.
+ *
+ * == Performance considerations
+ *
+ * Protected methods are slower than others because they can't use inline
+ * cache.
+ *
+ * == Example
+ *
+ * class Account
+ * # Mark balance as protected, so that we can compare between accounts
+ * # without making it public.
+ * attr_reader :balance
+ * protected :balance
+ *
+ * def initialize(balance)
+ * @balance = balance
+ * end
+ *
+ * def >(other)
+ * # The invocation to `other.balance` is allowed because `other` is a
+ * # different object of the same class (Account).
+ * balance > other.balance
+ * end
+ * end
*
- * If a method has protected visibility, it is callable only where
- * <code>self</code> of the context is the same as the method.
- * (method definition or instance_eval). This behavior is different from
- * Java's protected method. Usually <code>private</code> should be used.
+ * account1 = Account.new(100)
+ * account2 = Account.new(50)
*
- * Note that a protected method is slow because it can't use inline cache.
+ * account1 > account2 # => true (works)
+ * account1.balance # => NoMethodError (fails because balance is not public)
*
* To show a private method on RDoc, use <code>:doc:</code> instead of this.
*/
@@ -2595,13 +3168,14 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
switch (me->def->type) {
case VM_METHOD_TYPE_ISEQ:
if (ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_rest &&
+ !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_post &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kw &&
!ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kwrest) {
ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.ruby2_keywords = 1;
rb_clear_method_cache(module, name);
}
else {
- rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name));
+ rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
}
break;
case VM_METHOD_TYPE_BMETHOD: {
@@ -2614,13 +3188,14 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval);
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
if (ISEQ_BODY(iseq)->param.flags.has_rest &&
+ !ISEQ_BODY(iseq)->param.flags.has_post &&
!ISEQ_BODY(iseq)->param.flags.has_kw &&
!ISEQ_BODY(iseq)->param.flags.has_kwrest) {
ISEQ_BODY(iseq)->param.flags.ruby2_keywords = 1;
rb_clear_method_cache(module, name);
}
else {
- rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name));
+ rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name));
}
break;
}
diff --git a/vm_sync.c b/vm_sync.c
index b57bd86647..aca83dde5a 100644
--- a/vm_sync.c
+++ b/vm_sync.c
@@ -7,11 +7,12 @@
void rb_ractor_sched_barrier_start(rb_vm_t *vm, rb_ractor_t *cr);
void rb_ractor_sched_barrier_join(rb_vm_t *vm, rb_ractor_t *cr);
+void rb_ractor_sched_barrier_end(rb_vm_t *vm, rb_ractor_t *cr);
static bool
vm_locked(rb_vm_t *vm)
{
- return vm->ractor.sync.lock_owner == GET_RACTOR();
+ return vm_locked_by_ractor_p(vm, GET_RACTOR());
}
#if RUBY_DEBUG > 0
@@ -25,6 +26,20 @@ RUBY_ASSERT_vm_locking(void)
}
void
+RUBY_ASSERT_vm_locking_with_barrier(void)
+{
+ if (rb_multi_ractor_p()) {
+ rb_vm_t *vm = GET_VM();
+ VM_ASSERT(vm_locked(vm));
+
+ if (vm->ractor.cnt > 1) {
+ /* Written to only when holding both ractor.sync and ractor.sched lock */
+ VM_ASSERT(vm->ractor.sched.barrier_waiting);
+ }
+ }
+}
+
+void
RUBY_ASSERT_vm_unlocking(void)
{
if (rb_multi_ractor_p()) {
@@ -103,15 +118,26 @@ vm_lock_enter(rb_ractor_t *cr, rb_vm_t *vm, bool locked, bool no_barrier, unsign
}
static void
-vm_lock_leave(rb_vm_t *vm, unsigned int *lev APPEND_LOCATION_ARGS)
+vm_lock_leave(rb_vm_t *vm, bool no_barrier, unsigned int *lev APPEND_LOCATION_ARGS)
{
+ MAYBE_UNUSED(rb_ractor_t *cr = vm->ractor.sync.lock_owner);
+
RUBY_DEBUG_LOG2(file, line, "rec:%u owner:%u%s", vm->ractor.sync.lock_rec,
- (unsigned int)rb_ractor_id(vm->ractor.sync.lock_owner),
+ (unsigned int)rb_ractor_id(cr),
vm->ractor.sync.lock_rec == 1 ? " (leave)" : "");
ASSERT_vm_locking();
VM_ASSERT(vm->ractor.sync.lock_rec > 0);
VM_ASSERT(vm->ractor.sync.lock_rec == *lev);
+ VM_ASSERT(cr == GET_RACTOR());
+
+#ifdef RUBY_THREAD_PTHREAD_H
+ if (vm->ractor.sched.barrier_ractor == cr &&
+ vm->ractor.sched.barrier_lock_rec == vm->ractor.sync.lock_rec) {
+ VM_ASSERT(!no_barrier);
+ rb_ractor_sched_barrier_end(vm, cr);
+ }
+#endif
vm->ractor.sync.lock_rec--;
*lev = vm->ractor.sync.lock_rec;
@@ -154,9 +180,15 @@ rb_vm_lock_enter_body_cr(rb_ractor_t *cr, unsigned int *lev APPEND_LOCATION_ARGS
}
void
+rb_vm_lock_leave_body_nb(unsigned int *lev APPEND_LOCATION_ARGS)
+{
+ vm_lock_leave(GET_VM(), true, lev APPEND_LOCATION_PARAMS);
+}
+
+void
rb_vm_lock_leave_body(unsigned int *lev APPEND_LOCATION_ARGS)
{
- vm_lock_leave(GET_VM(), lev APPEND_LOCATION_PARAMS);
+ vm_lock_leave(GET_VM(), false, lev APPEND_LOCATION_PARAMS);
}
void
@@ -174,7 +206,7 @@ rb_vm_unlock_body(LOCATION_ARGS)
rb_vm_t *vm = GET_VM();
ASSERT_vm_locking();
VM_ASSERT(vm->ractor.sync.lock_rec == 1);
- vm_lock_leave(vm, &vm->ractor.sync.lock_rec APPEND_LOCATION_PARAMS);
+ vm_lock_leave(vm, false, &vm->ractor.sync.lock_rec APPEND_LOCATION_PARAMS);
}
static void
@@ -208,6 +240,16 @@ rb_vm_cond_timedwait(rb_vm_t *vm, rb_nativethread_cond_t *cond, unsigned long ms
vm_cond_wait(vm, cond, msec);
}
+static bool
+vm_barrier_acquired_p(const rb_vm_t *vm, const rb_ractor_t *cr)
+{
+#ifdef RUBY_THREAD_PTHREAD_H
+ return vm->ractor.sched.barrier_ractor == cr;
+#else
+ return false;
+#endif
+}
+
void
rb_vm_barrier(void)
{
@@ -219,13 +261,20 @@ rb_vm_barrier(void)
}
else {
rb_vm_t *vm = GET_VM();
- VM_ASSERT(!vm->ractor.sched.barrier_waiting);
- ASSERT_vm_locking();
rb_ractor_t *cr = vm->ractor.sync.lock_owner;
+
+ ASSERT_vm_locking();
VM_ASSERT(cr == GET_RACTOR());
VM_ASSERT(rb_ractor_status_p(cr, ractor_running));
- rb_ractor_sched_barrier_start(vm, cr);
+ if (vm_barrier_acquired_p(vm, cr)) {
+ // already in barrier synchronization
+ return;
+ }
+ else {
+ VM_ASSERT(!vm->ractor.sched.barrier_waiting);
+ rb_ractor_sched_barrier_start(vm, cr);
+ }
}
}
@@ -248,3 +297,14 @@ rb_ec_vm_lock_rec_release(const rb_execution_context_t *ec,
VM_ASSERT(recorded_lock_rec == rb_ec_vm_lock_rec(ec));
}
+
+VALUE
+rb_vm_lock_with_barrier(VALUE (*func)(void *args), void *args)
+{
+ VALUE result = 0;
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+ result = func(args);
+ }
+ return result;
+}
diff --git a/vm_sync.h b/vm_sync.h
index e8243d6f50..314a2238a9 100644
--- a/vm_sync.h
+++ b/vm_sync.h
@@ -24,9 +24,14 @@ struct rb_ractor_struct;
NOINLINE(void rb_vm_lock_enter_body_cr(struct rb_ractor_struct *cr, unsigned int *lev APPEND_LOCATION_ARGS));
NOINLINE(void rb_vm_lock_enter_body_nb(unsigned int *lev APPEND_LOCATION_ARGS));
NOINLINE(void rb_vm_lock_enter_body(unsigned int *lev APPEND_LOCATION_ARGS));
+void rb_vm_lock_leave_body_nb(unsigned int *lev APPEND_LOCATION_ARGS);
void rb_vm_lock_leave_body(unsigned int *lev APPEND_LOCATION_ARGS);
void rb_vm_barrier(void);
+RUBY_SYMBOL_EXPORT_BEGIN
+VALUE rb_vm_lock_with_barrier(VALUE (*func)(void *args), void *args);
+RUBY_SYMBOL_EXPORT_END
+
#if RUBY_DEBUG
// GET_VM()
#include "vm_core.h"
@@ -87,6 +92,14 @@ rb_vm_lock_enter_nb(unsigned int *lev, const char *file, int line)
}
static inline void
+rb_vm_lock_leave_nb(unsigned int *lev, const char *file, int line)
+{
+ if (rb_multi_ractor_p()) {
+ rb_vm_lock_leave_body_nb(lev APPEND_LOCATION_PARAMS);
+ }
+}
+
+static inline void
rb_vm_lock_leave(unsigned int *lev, const char *file, int line)
{
if (rb_multi_ractor_p()) {
@@ -119,18 +132,28 @@ rb_vm_lock_leave_cr(struct rb_ractor_struct *cr, unsigned int *levp, const char
#define RB_VM_LOCK_ENTER() { unsigned int _lev; RB_VM_LOCK_ENTER_LEV(&_lev);
#define RB_VM_LOCK_LEAVE() RB_VM_LOCK_LEAVE_LEV(&_lev); }
+#define RB_VM_LOCKING() \
+ for (unsigned int vm_locking_level, vm_locking_do = (RB_VM_LOCK_ENTER_LEV(&vm_locking_level), 1); \
+ vm_locking_do; RB_VM_LOCK_LEAVE_LEV(&vm_locking_level), vm_locking_do = 0)
#define RB_VM_LOCK_ENTER_LEV_NB(levp) rb_vm_lock_enter_nb(levp, __FILE__, __LINE__)
+#define RB_VM_LOCK_LEAVE_LEV_NB(levp) rb_vm_lock_leave_nb(levp, __FILE__, __LINE__)
#define RB_VM_LOCK_ENTER_NO_BARRIER() { unsigned int _lev; RB_VM_LOCK_ENTER_LEV_NB(&_lev);
-#define RB_VM_LOCK_LEAVE_NO_BARRIER() RB_VM_LOCK_LEAVE_LEV(&_lev); }
+#define RB_VM_LOCK_LEAVE_NO_BARRIER() RB_VM_LOCK_LEAVE_LEV_NB(&_lev); }
+#define RB_VM_LOCKING_NO_BARRIER() \
+ for (unsigned int vm_locking_level, vm_locking_do = (RB_VM_LOCK_ENTER_LEV_NB(&vm_locking_level), 1); \
+ vm_locking_do; RB_VM_LOCK_LEAVE_LEV_NB(&vm_locking_level), vm_locking_do = 0)
#if RUBY_DEBUG > 0
void RUBY_ASSERT_vm_locking(void);
+void RUBY_ASSERT_vm_locking_with_barrier(void);
void RUBY_ASSERT_vm_unlocking(void);
#define ASSERT_vm_locking() RUBY_ASSERT_vm_locking()
+#define ASSERT_vm_locking_with_barrier() RUBY_ASSERT_vm_locking_with_barrier()
#define ASSERT_vm_unlocking() RUBY_ASSERT_vm_unlocking()
#else
#define ASSERT_vm_locking()
+#define ASSERT_vm_locking_with_barrier()
#define ASSERT_vm_unlocking()
#endif
diff --git a/vm_trace.c b/vm_trace.c
index 81fa6458b7..305802f469 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -34,7 +34,9 @@
#include "ruby/debug.h"
#include "vm_core.h"
#include "ruby/ractor.h"
+#include "ractor_core.h"
#include "yjit.h"
+#include "zjit.h"
#include "builtin.h"
@@ -71,13 +73,17 @@ rb_hook_list_mark(rb_hook_list_t *hooks)
}
void
-rb_hook_list_mark_and_update(rb_hook_list_t *hooks)
+rb_hook_list_mark_and_move(rb_hook_list_t *hooks)
{
- rb_event_hook_t *hook = hooks->hooks;
+ if (!rb_gc_checking_shareable()) {
+ // hooks can be unshareable
- while (hook) {
- rb_gc_mark_and_move(&hook->data);
- hook = hook->next;
+ rb_event_hook_t *hook = hooks->hooks;
+
+ while (hook) {
+ rb_gc_mark_and_move(&hook->data);
+ hook = hook->next;
+ }
}
}
@@ -98,43 +104,89 @@ rb_hook_list_free(rb_hook_list_t *hooks)
void rb_clear_attr_ccs(void);
void rb_clear_bf_ccs(void);
-static void
-update_global_event_hook(rb_event_flag_t prev_events, rb_event_flag_t new_events)
+static bool iseq_trace_set_all_needed(rb_event_flag_t new_events)
{
rb_event_flag_t new_iseq_events = new_events & ISEQ_TRACE_EVENTS;
rb_event_flag_t enabled_iseq_events = ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS;
- bool first_time_iseq_events_p = new_iseq_events & ~enabled_iseq_events;
- bool enable_c_call = (prev_events & RUBY_EVENT_C_CALL) == 0 && (new_events & RUBY_EVENT_C_CALL);
+ return new_iseq_events & ~enabled_iseq_events;
+
+}
+
+static bool clear_attr_ccs_needed(rb_event_flag_t prev_events, rb_event_flag_t new_events)
+{
+ bool enable_c_call = (prev_events & RUBY_EVENT_C_CALL) == 0 && (new_events & RUBY_EVENT_C_CALL);
bool enable_c_return = (prev_events & RUBY_EVENT_C_RETURN) == 0 && (new_events & RUBY_EVENT_C_RETURN);
- bool enable_call = (prev_events & RUBY_EVENT_CALL) == 0 && (new_events & RUBY_EVENT_CALL);
- bool enable_return = (prev_events & RUBY_EVENT_RETURN) == 0 && (new_events & RUBY_EVENT_RETURN);
+ return enable_c_call || enable_c_return;
+}
+
+/* If the events are internal events (e.g. gc hooks), it updates them globally for all ractors. Otherwise
+ * they are ractor local. You cannot listen to internal events through set_trace_func or TracePoint.
+ * Some ractor-local tracepoint events cause global level iseq changes, so are still called `global events`.
+ */
+static void
+update_global_event_hooks(rb_hook_list_t *list, rb_event_flag_t prev_events, rb_event_flag_t new_events, int change_iseq_events, int change_c_events)
+{
+ rb_execution_context_t *ec = rb_current_execution_context(false);
+ unsigned int lev;
+
+ // Can't enter VM lock during freeing of ractor hook list on MMTK, where ec == NULL.
+ if (ec) {
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ rb_vm_barrier();
+ }
+
+ rb_event_flag_t new_iseq_events = new_events & ISEQ_TRACE_EVENTS;
+ rb_event_flag_t enabled_iseq_events = ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS;
+ bool new_iseq_events_p = iseq_trace_set_all_needed(new_events);
+ bool enable_call = (prev_events & RUBY_EVENT_CALL) == 0 && (new_events & RUBY_EVENT_CALL);
+ bool enable_return = (prev_events & RUBY_EVENT_RETURN) == 0 && (new_events & RUBY_EVENT_RETURN);
+ bool clear_attr_ccs_p = clear_attr_ccs_needed(prev_events, new_events);
+
+ // FIXME: `ruby_vm_event_flags` should have the global list of event flags for internal events as well
+ // as for all ractors. That's not how it works right now, so we shouldn't rely on it apart from the
+ // internal events. Since it doesn't work like this, we have to track more state with `ruby_vm_iseq_events_enabled`,
+ // `ruby_vm_c_events_enabled`, etc.
+ rb_event_flag_t new_events_global = (ruby_vm_event_flags & ~prev_events) | new_events;
+ ruby_vm_event_flags = new_events_global;
// Modify ISEQs or CCs to enable tracing
- if (first_time_iseq_events_p) {
+ if (new_iseq_events_p) {
// write all ISeqs only when new events are added for the first time
rb_iseq_trace_set_all(new_iseq_events | enabled_iseq_events);
}
- // if c_call or c_return is activated
- else if (enable_c_call || enable_c_return) {
+ else if (clear_attr_ccs_p) { // turn on C_CALL or C_RETURN ractor locally
rb_clear_attr_ccs();
}
- else if (enable_call || enable_return) {
+ else if (enable_call || enable_return) { // turn on CALL or RETURN ractor locally
rb_clear_bf_ccs();
}
- ruby_vm_event_flags = new_events;
- ruby_vm_event_enabled_global_flags |= new_events;
- rb_objspace_set_event_hook(new_events);
+ if (change_iseq_events < 0) {
+ RUBY_ASSERT(ruby_vm_iseq_events_enabled >= (unsigned int)(-change_iseq_events));
+ }
+ ruby_vm_iseq_events_enabled += change_iseq_events;
+ if (change_c_events < 0) {
+ RUBY_ASSERT(ruby_vm_c_events_enabled >= (unsigned int)(-change_iseq_events));
+ }
+ ruby_vm_c_events_enabled += change_c_events;
+
+ ruby_vm_event_enabled_global_flags |= new_events; // NOTE: this is only ever added to
+ if (new_events_global & RUBY_INTERNAL_EVENT_MASK) {
+ rb_objspace_set_event_hook(new_events_global);
+ }
// Invalidate JIT code as needed
- if (first_time_iseq_events_p || enable_c_call || enable_c_return) {
+ if (new_iseq_events_p || clear_attr_ccs_p) {
// Invalidate all code when ISEQs are modified to use trace_* insns above.
// Also invalidate when enabling c_call or c_return because generated code
// never fires these events.
// Internal events fire inside C routines so don't need special handling.
- // Do this after event flags updates so other ractors see updated vm events
- // when they wake up.
rb_yjit_tracing_invalidate_all();
+ rb_zjit_tracing_invalidate_all();
+ }
+
+ if (ec) {
+ RB_VM_LOCK_LEAVE_LEV(&lev);
}
}
@@ -162,28 +214,43 @@ alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data,
return hook;
}
+// Connect a hook onto a ractor, an iseq or a method definition's hook list
static void
-hook_list_connect(VALUE list_owner, rb_hook_list_t *list, rb_event_hook_t *hook, int global_p)
+hook_list_connect(rb_hook_list_t *list, rb_event_hook_t *hook, int global_p)
{
rb_event_flag_t prev_events = list->events;
+ int change_iseq_events = 0;
+ int change_c_events = 0;
hook->next = list->hooks;
list->hooks = hook;
list->events |= hook->events;
if (global_p) {
- /* global hooks are root objects at GC mark. */
- update_global_event_hook(prev_events, list->events);
- }
- else {
- RB_OBJ_WRITTEN(list_owner, Qundef, hook->data);
+ if (hook->events & ISEQ_TRACE_EVENTS) {
+ change_iseq_events++;
+ }
+ if ((hook->events & RUBY_EVENT_C_CALL) || (hook->events & RUBY_EVENT_C_RETURN)) {
+ change_c_events++;
+ }
+ update_global_event_hooks(list, prev_events, list->events, change_iseq_events, change_c_events);
}
}
static void
-connect_event_hook(const rb_execution_context_t *ec, rb_event_hook_t *hook)
+connect_non_targeted_event_hook(const rb_execution_context_t *ec, rb_event_hook_t *hook)
{
- rb_hook_list_t *list = rb_ec_ractor_hooks(ec);
- hook_list_connect(Qundef, list, hook, TRUE);
+ rb_hook_list_t *list;
+
+ /* internal events are VM-global, non-internal are ractor-local */
+ VM_ASSERT(!(hook->events & RUBY_INTERNAL_EVENT_OBJSPACE_MASK) || !(hook->events & ~RUBY_INTERNAL_EVENT_OBJSPACE_MASK));
+
+ if (hook->events & RUBY_INTERNAL_EVENT_OBJSPACE_MASK) {
+ list = rb_vm_global_hooks(ec);
+ }
+ else {
+ list = rb_ec_ractor_hooks(ec);
+ }
+ hook_list_connect(list, hook, TRUE);
}
static void
@@ -192,7 +259,7 @@ rb_threadptr_add_event_hook(const rb_execution_context_t *ec, rb_thread_t *th,
{
rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
hook->filter.th = th;
- connect_event_hook(ec, hook);
+ connect_non_targeted_event_hook(ec, hook);
}
void
@@ -217,7 +284,35 @@ void
rb_add_event_hook2(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
{
rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
- connect_event_hook(GET_EC(), hook);
+ connect_non_targeted_event_hook(GET_EC(), hook);
+}
+
+static bool
+hook_list_targeted_p(rb_hook_list_t *list)
+{
+ switch (list->type) {
+ case hook_list_type_targeted_iseq:
+ case hook_list_type_targeted_def:
+ return true;
+ default:
+ return false;
+ }
+}
+
+unsigned int
+rb_hook_list_count(rb_hook_list_t *list)
+{
+ rb_event_hook_t *hook = list->hooks;
+ unsigned int count = 0;
+
+ while (hook) {
+ if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED)) {
+ count++;
+ }
+ hook = hook->next;
+ }
+
+ return count;
}
static void
@@ -225,6 +320,8 @@ clean_hooks(rb_hook_list_t *list)
{
rb_event_hook_t *hook, **nextp = &list->hooks;
rb_event_flag_t prev_events = list->events;
+ int change_iseq_events = 0;
+ int change_c_events = 0;
VM_ASSERT(list->running == 0);
VM_ASSERT(list->need_clean == true);
@@ -235,7 +332,15 @@ clean_hooks(rb_hook_list_t *list)
while ((hook = *nextp) != 0) {
if (hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) {
*nextp = hook->next;
- xfree(hook);
+ if (!hook_list_targeted_p(list)) {
+ if (hook->events & ISEQ_TRACE_EVENTS) {
+ change_iseq_events--;
+ }
+ if ((hook->events & RUBY_EVENT_C_CALL) || (hook->events & RUBY_EVENT_C_RETURN)) {
+ change_c_events--;
+ }
+ }
+ SIZED_FREE(hook);
}
else {
list->events |= hook->events; /* update active events */
@@ -243,14 +348,13 @@ clean_hooks(rb_hook_list_t *list)
}
}
- if (list->is_local) {
+ if (hook_list_targeted_p(list)) {
if (list->events == 0) {
- /* local events */
- ruby_xfree(list);
+ SIZED_FREE(list);
}
}
else {
- update_global_event_hook(prev_events, list->events);
+ update_global_event_hooks(list, prev_events, list->events, change_iseq_events, change_c_events);
}
}
@@ -266,11 +370,9 @@ clean_hooks_check(rb_hook_list_t *list)
#define MATCH_ANY_FILTER_TH ((rb_thread_t *)1)
-/* if func is 0, then clear all funcs */
static int
-remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th, rb_event_hook_func_t func, VALUE data)
+remove_event_hook_from_list(rb_hook_list_t *list, const rb_thread_t *filter_th, rb_event_hook_func_t func, VALUE data)
{
- rb_hook_list_t *list = rb_ec_ractor_hooks(ec);
int ret = 0;
rb_event_hook_t *hook = list->hooks;
@@ -279,8 +381,8 @@ remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th
if (hook->filter.th == filter_th || filter_th == MATCH_ANY_FILTER_TH) {
if (UNDEF_P(data) || hook->data == data) {
hook->hook_flags |= RUBY_EVENT_HOOK_FLAG_DELETED;
- ret+=1;
list->need_clean = true;
+ ret+=1;
}
}
}
@@ -291,6 +393,18 @@ remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th
return ret;
}
+/* if func is 0, then clear all funcs */
+static int
+remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th, rb_event_hook_func_t func, VALUE data)
+{
+ int ret = 0;
+
+ ret += remove_event_hook_from_list(rb_ec_ractor_hooks(ec), filter_th, func, data);
+ ret += remove_event_hook_from_list(rb_vm_global_hooks(ec), filter_th, func, data);
+
+ return ret;
+}
+
static int
rb_threadptr_remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th, rb_event_hook_func_t func, VALUE data)
{
@@ -415,8 +529,10 @@ rb_exec_event_hooks(rb_trace_arg_t *trace_arg, rb_hook_list_t *hooks, int pop_p)
{
rb_execution_context_t *ec = trace_arg->ec;
- if (UNLIKELY(trace_arg->event & RUBY_INTERNAL_EVENT_MASK)) {
- if (ec->trace_arg && (ec->trace_arg->event & RUBY_INTERNAL_EVENT_MASK)) {
+ if (UNLIKELY(trace_arg->event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK)) {
+ VM_ASSERT(hooks == rb_vm_global_hooks(ec));
+
+ if (ec->trace_arg && (ec->trace_arg->event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK)) {
/* skip hooks because this thread doing INTERNAL_EVENT */
}
else {
@@ -424,7 +540,7 @@ rb_exec_event_hooks(rb_trace_arg_t *trace_arg, rb_hook_list_t *hooks, int pop_p)
ec->trace_arg = trace_arg;
/* only global hooks */
- exec_hooks_unprotected(ec, rb_ec_ractor_hooks(ec), trace_arg);
+ exec_hooks_unprotected(ec, hooks, trace_arg);
ec->trace_arg = prev_trace_arg;
}
}
@@ -453,6 +569,7 @@ rb_exec_event_hooks(rb_trace_arg_t *trace_arg, rb_hook_list_t *hooks, int pop_p)
if (state) {
if (pop_p) {
if (VM_FRAME_FINISHED_P(ec->cfp)) {
+ rb_vm_tag_jmpbuf_deinit(&ec->tag->buf);
ec->tag = ec->tag->prev;
}
rb_vm_pop_frame(ec);
@@ -695,7 +812,7 @@ get_path_and_lineno(const rb_execution_context_t *ec, const rb_control_frame_t *
cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
if (cfp) {
- const rb_iseq_t *iseq = cfp->iseq;
+ const rb_iseq_t *iseq = CFP_ISEQ(cfp);
*pathp = rb_iseq_path(iseq);
if (event & (RUBY_EVENT_CLASS |
@@ -745,7 +862,7 @@ call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klas
if (self && (filename != Qnil) &&
event != RUBY_EVENT_C_CALL &&
event != RUBY_EVENT_C_RETURN &&
- (VM_FRAME_RUBYFRAME_P(ec->cfp) && imemo_type_p((VALUE)ec->cfp->iseq, imemo_iseq))) {
+ (VM_FRAME_RUBYFRAME_P(ec->cfp) && imemo_type_p((VALUE)CFP_ISEQ(ec->cfp), imemo_iseq))) {
argv[4] = rb_binding_new();
}
argv[5] = klass ? klass : Qnil;
@@ -773,20 +890,21 @@ typedef struct rb_tp_struct {
} rb_tp_t;
static void
-tp_mark(void *ptr)
+tp_mark_and_move(void *ptr)
{
rb_tp_t *tp = ptr;
- rb_gc_mark(tp->proc);
- rb_gc_mark(tp->local_target_set);
- if (tp->target_th) rb_gc_mark(tp->target_th->self);
+ rb_gc_mark_and_move(&tp->proc);
+ rb_gc_mark_and_move(&tp->local_target_set);
+ if (tp->target_th) rb_gc_mark_and_move(&tp->target_th->self);
}
static const rb_data_type_t tp_data_type = {
"tracepoint",
{
- tp_mark,
+ tp_mark_and_move,
RUBY_TYPED_DEFAULT_FREE,
NULL, // Nothing allocated externally, so don't need a memsize function
+ tp_mark_and_move,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -924,7 +1042,7 @@ rb_tracearg_parameters(rb_trace_arg_t *trace_arg)
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK && !VM_FRAME_LAMBDA_P(cfp)) {
is_proc = 1;
}
- return rb_iseq_parameters(cfp->iseq, is_proc);
+ return rb_iseq_parameters(CFP_ISEQ(cfp), is_proc);
}
break;
}
@@ -986,7 +1104,7 @@ rb_tracearg_binding(rb_trace_arg_t *trace_arg)
}
cfp = rb_vm_get_binding_creatable_next_cfp(trace_arg->ec, trace_arg->cfp);
- if (cfp && imemo_type_p((VALUE)cfp->iseq, imemo_iseq)) {
+ if (cfp && imemo_type_p((VALUE)CFP_ISEQ(cfp), imemo_iseq)) {
return rb_vm_make_binding(trace_arg->ec, cfp);
}
else {
@@ -1000,15 +1118,18 @@ rb_tracearg_self(rb_trace_arg_t *trace_arg)
return trace_arg->self;
}
-VALUE
-rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
+static void
+check_event_support(rb_trace_arg_t *trace_arg, rb_event_flag_t supported)
{
- if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN)) {
- /* ok */
- }
- else {
+ if (!(trace_arg->event & supported)) {
rb_raise(rb_eRuntimeError, "not supported by this event");
}
+}
+
+VALUE
+rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
+{
+ check_event_support(trace_arg, RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN);
if (UNDEF_P(trace_arg->data)) {
rb_bug("rb_tracearg_return_value: unreachable");
}
@@ -1018,12 +1139,7 @@ rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
VALUE
rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
{
- if (trace_arg->event & (RUBY_EVENT_RAISE | RUBY_EVENT_RESCUE)) {
- /* ok */
- }
- else {
- rb_raise(rb_eRuntimeError, "not supported by this event");
- }
+ check_event_support(trace_arg, RUBY_EVENT_RAISE | RUBY_EVENT_RESCUE);
if (UNDEF_P(trace_arg->data)) {
rb_bug("rb_tracearg_raised_exception: unreachable");
}
@@ -1035,14 +1151,9 @@ rb_tracearg_eval_script(rb_trace_arg_t *trace_arg)
{
VALUE data = trace_arg->data;
- if (trace_arg->event & (RUBY_EVENT_SCRIPT_COMPILED)) {
- /* ok */
- }
- else {
- rb_raise(rb_eRuntimeError, "not supported by this event");
- }
+ check_event_support(trace_arg, RUBY_EVENT_SCRIPT_COMPILED);
if (UNDEF_P(data)) {
- rb_bug("rb_tracearg_raised_exception: unreachable");
+ rb_bug("rb_tracearg_eval_script: unreachable");
}
if (rb_obj_is_iseq(data)) {
return Qnil;
@@ -1059,14 +1170,9 @@ rb_tracearg_instruction_sequence(rb_trace_arg_t *trace_arg)
{
VALUE data = trace_arg->data;
- if (trace_arg->event & (RUBY_EVENT_SCRIPT_COMPILED)) {
- /* ok */
- }
- else {
- rb_raise(rb_eRuntimeError, "not supported by this event");
- }
+ check_event_support(trace_arg, RUBY_EVENT_SCRIPT_COMPILED);
if (UNDEF_P(data)) {
- rb_bug("rb_tracearg_raised_exception: unreachable");
+ rb_bug("rb_tracearg_instruction_sequence: unreachable");
}
if (rb_obj_is_iseq(data)) {
@@ -1084,12 +1190,7 @@ rb_tracearg_instruction_sequence(rb_trace_arg_t *trace_arg)
VALUE
rb_tracearg_object(rb_trace_arg_t *trace_arg)
{
- if (trace_arg->event & (RUBY_INTERNAL_EVENT_NEWOBJ | RUBY_INTERNAL_EVENT_FREEOBJ)) {
- /* ok */
- }
- else {
- rb_raise(rb_eRuntimeError, "not supported by this event");
- }
+ check_event_support(trace_arg, RUBY_INTERNAL_EVENT_NEWOBJ | RUBY_INTERNAL_EVENT_FREEOBJ);
if (UNDEF_P(trace_arg->data)) {
rb_bug("rb_tracearg_object: unreachable");
}
@@ -1182,7 +1283,7 @@ tp_call_trace(VALUE tpval, rb_trace_arg_t *trace_arg)
(*tp->func)(tpval, tp->data);
}
else {
- if (tp->ractor == NULL || tp->ractor == GET_RACTOR()) {
+ if (tp->ractor == GET_RACTOR()) {
rb_proc_call_with_block((VALUE)tp->proc, 1, &tpval, Qnil);
}
}
@@ -1228,14 +1329,33 @@ iseq_of(VALUE target)
const rb_method_definition_t *rb_method_def(VALUE method); /* proc.c */
+rb_hook_list_t *
+rb_method_def_local_hooks(rb_method_definition_t *def, rb_ractor_t *cr, bool create)
+{
+ st_data_t val;
+ rb_hook_list_t *hook_list = NULL;
+ if (st_lookup(rb_ractor_targeted_hooks(cr), (st_data_t)def, &val)) {
+ hook_list = (rb_hook_list_t*)val;
+ RUBY_ASSERT(hook_list->type == hook_list_type_targeted_def);
+ }
+ else if (create) {
+ hook_list = ZALLOC(rb_hook_list_t);
+ hook_list->type = hook_list_type_targeted_def;
+ st_insert(&cr->pub.targeted_hooks, (st_data_t)def, (st_data_t)hook_list);
+ }
+ return hook_list;
+}
+
+// Enable "local" (targeted) tracepoint
static VALUE
rb_tracepoint_enable_for_target(VALUE tpval, VALUE target, VALUE target_line)
{
rb_tp_t *tp = tpptr(tpval);
- const rb_iseq_t *iseq = iseq_of(target);
+ const rb_iseq_t *iseq = iseq_of(target); // takes Proc, Iseq, Method
int n = 0;
unsigned int line = 0;
bool target_bmethod = false;
+ rb_ractor_t *cr = GET_RACTOR();
if (tp->tracing > 0) {
rb_raise(rb_eArgError, "can't nest-enable a targeting TracePoint");
@@ -1253,61 +1373,80 @@ rb_tracepoint_enable_for_target(VALUE tpval, VALUE target, VALUE target_line)
VM_ASSERT(tp->local_target_set == Qfalse);
RB_OBJ_WRITE(tpval, &tp->local_target_set, rb_obj_hide(rb_ident_hash_new()));
- /* bmethod */
- if (rb_obj_is_method(target)) {
- rb_method_definition_t *def = (rb_method_definition_t *)rb_method_def(target);
- if (def->type == VM_METHOD_TYPE_BMETHOD &&
- (tp->events & (RUBY_EVENT_CALL | RUBY_EVENT_RETURN))) {
- if (def->body.bmethod.hooks == NULL) {
- def->body.bmethod.hooks = ZALLOC(rb_hook_list_t);
- def->body.bmethod.hooks->is_local = true;
- }
- rb_hook_list_connect_tracepoint(target, def->body.bmethod.hooks, tpval, 0);
- rb_hash_aset(tp->local_target_set, target, Qfalse);
- target_bmethod = true;
+ RB_VM_LOCKING() {
+ // Rewriting iseq instructions across ractors is not safe unless they are stopped.
+ rb_vm_barrier();
- n++;
+ /* bmethod */
+ if (rb_obj_is_method(target)) {
+ rb_method_definition_t *def = (rb_method_definition_t *)rb_method_def(target);
+ if (def->type == VM_METHOD_TYPE_BMETHOD && (tp->events & (RUBY_EVENT_CALL | RUBY_EVENT_RETURN))) {
+ rb_hook_list_t *hook_list = rb_method_def_local_hooks(def, cr, true);
+ rb_hook_list_connect_local_tracepoint(hook_list, tpval, 0);
+ rb_hash_aset(tp->local_target_set, target, Qfalse); // Qfalse means not an iseq
+ rb_method_definition_addref(def); // in case `tp` gets GC'd and didn't disable the hook, `def` needs to stay alive
+ def->body.bmethod.local_hooks_cnt++;
+ target_bmethod = true;
+ n++;
+ }
}
- }
- /* iseq */
- n += rb_iseq_add_local_tracepoint_recursively(iseq, tp->events, tpval, line, target_bmethod);
- rb_hash_aset(tp->local_target_set, (VALUE)iseq, Qtrue);
+ /* iseq */
+ n += rb_iseq_add_local_tracepoint_recursively(iseq, tp->events, tpval, line, target_bmethod);
+ if (n > 0) {
+ rb_hash_aset(tp->local_target_set, (VALUE)iseq, Qtrue);
- if ((tp->events & (RUBY_EVENT_CALL | RUBY_EVENT_RETURN)) &&
- iseq->body->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) {
- rb_clear_bf_ccs();
+ if ((tp->events & (RUBY_EVENT_CALL | RUBY_EVENT_RETURN)) &&
+ iseq->body->builtin_attrs & BUILTIN_ATTR_SINGLE_NOARG_LEAF) {
+ rb_clear_bf_ccs();
+ }
+
+ rb_yjit_tracing_invalidate_all();
+ rb_zjit_tracing_invalidate_all();
+ rb_ractor_targeted_hooks_incr(tp->ractor);
+ if (tp->events & ISEQ_TRACE_EVENTS) {
+ ruby_vm_iseq_events_enabled++;
+ }
+ if ((tp->events & RUBY_EVENT_C_CALL) || (tp->events & RUBY_EVENT_C_RETURN)) {
+ ruby_vm_c_events_enabled++;
+ }
+ tp->tracing = 1;
+ }
}
if (n == 0) {
rb_raise(rb_eArgError, "can not enable any hooks");
}
- rb_yjit_tracing_invalidate_all();
-
- ruby_vm_event_local_num++;
-
- tp->tracing = 1;
-
return Qnil;
}
static int
-disable_local_event_iseq_i(VALUE target, VALUE iseq_p, VALUE tpval)
+disable_local_tracepoint_i(VALUE target, VALUE iseq_p, VALUE tpval)
{
+ rb_tp_t *tp = tpptr(tpval);
+ rb_ractor_t *cr;
+ rb_method_definition_t *def;
+ rb_hook_list_t *hook_list;
+ ASSERT_vm_locking_with_barrier();
+
if (iseq_p) {
- rb_iseq_remove_local_tracepoint_recursively((rb_iseq_t *)target, tpval);
+ rb_iseq_remove_local_tracepoint_recursively((rb_iseq_t *)target, tpval, tp->ractor);
}
else {
+ cr = GET_RACTOR();
/* bmethod */
- rb_method_definition_t *def = (rb_method_definition_t *)rb_method_def(target);
- rb_hook_list_t *hooks = def->body.bmethod.hooks;
- VM_ASSERT(hooks != NULL);
- rb_hook_list_remove_tracepoint(hooks, tpval);
-
- if (hooks->events == 0) {
- rb_hook_list_free(def->body.bmethod.hooks);
- def->body.bmethod.hooks = NULL;
+ def = (rb_method_definition_t *)rb_method_def(target);
+ hook_list = rb_method_def_local_hooks(def, cr, false);
+ RUBY_ASSERT(hook_list != NULL);
+ if (rb_hook_list_remove_local_tracepoint(hook_list, tpval)) {
+ RUBY_ASSERT(def->body.bmethod.local_hooks_cnt > 0);
+ def->body.bmethod.local_hooks_cnt--;
+ if (hook_list->events == 0) {
+ st_delete(rb_ractor_targeted_hooks(cr), (st_data_t*)&def, NULL);
+ rb_hook_list_free(hook_list);
+ }
+ rb_method_definition_release(def);
}
}
return ST_CONTINUE;
@@ -1320,10 +1459,23 @@ rb_tracepoint_disable(VALUE tpval)
tp = tpptr(tpval);
- if (tp->local_target_set) {
- rb_hash_foreach(tp->local_target_set, disable_local_event_iseq_i, tpval);
- RB_OBJ_WRITE(tpval, &tp->local_target_set, Qfalse);
- ruby_vm_event_local_num--;
+ if (RTEST(tp->local_target_set)) {
+ RUBY_ASSERT(GET_RACTOR() == tp->ractor);
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
+
+ rb_hash_foreach(tp->local_target_set, disable_local_tracepoint_i, tpval);
+ RB_OBJ_WRITE(tpval, &tp->local_target_set, Qfalse);
+ rb_ractor_targeted_hooks_decr(tp->ractor);
+ if (tp->events & ISEQ_TRACE_EVENTS) {
+ RUBY_ASSERT(ruby_vm_iseq_events_enabled > 0);
+ ruby_vm_iseq_events_enabled--;
+ }
+ if ((tp->events & RUBY_EVENT_C_CALL) || (tp->events & RUBY_EVENT_C_RETURN)) {
+ RUBY_ASSERT(ruby_vm_c_events_enabled > 0);
+ ruby_vm_c_events_enabled--;
+ }
+ }
}
else {
if (tp->target_th) {
@@ -1338,26 +1490,30 @@ rb_tracepoint_disable(VALUE tpval)
return Qundef;
}
+// connect a targeted (ie: "local") tracepoint to the hook list for the method
+// ex: tp.enable(target: method(:puts))
void
-rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line)
+rb_hook_list_connect_local_tracepoint(rb_hook_list_t *list, VALUE tpval, unsigned int target_line)
{
rb_tp_t *tp = tpptr(tpval);
rb_event_hook_t *hook = alloc_event_hook((rb_event_hook_func_t)tp_call_trace, tp->events & ISEQ_TRACE_EVENTS, tpval,
RUBY_EVENT_HOOK_FLAG_SAFE | RUBY_EVENT_HOOK_FLAG_RAW_ARG);
hook->filter.target_line = target_line;
- hook_list_connect(target, list, hook, FALSE);
+ hook_list_connect(list, hook, FALSE);
}
-void
-rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval)
+bool
+rb_hook_list_remove_local_tracepoint(rb_hook_list_t *list, VALUE tpval)
{
rb_event_hook_t *hook = list->hooks;
rb_event_flag_t events = 0;
+ bool removed = false;
while (hook) {
if (hook->data == tpval) {
hook->hook_flags |= RUBY_EVENT_HOOK_FLAG_DELETED;
list->need_clean = true;
+ removed = true;
}
else if ((hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) == 0) {
events |= hook->events;
@@ -1366,6 +1522,7 @@ rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval)
}
list->events = events;
+ return removed;
}
static VALUE
@@ -1460,8 +1617,8 @@ tracepoint_new(VALUE klass, rb_thread_t *target_th, rb_event_flag_t events, void
TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
RB_OBJ_WRITE(tpval, &tp->proc, proc);
- tp->ractor = rb_ractor_shareable_p(proc) ? NULL : GET_RACTOR();
- tp->func = func;
+ tp->ractor = GET_RACTOR();
+ tp->func = func; // for internal events
tp->data = data;
tp->events = events;
tp->self = tpval;
@@ -1476,9 +1633,6 @@ rb_tracepoint_new(VALUE target_thval, rb_event_flag_t events, void (*func)(VALUE
if (RTEST(target_thval)) {
target_th = rb_thread_ptr(target_thval);
- /* TODO: Test it!
- * Warning: This function is not tested.
- */
}
return tracepoint_new(rb_cTracePoint, target_th, events, func, data, Qundef);
}
@@ -1585,7 +1739,6 @@ tracepoint_stat_s(rb_execution_context_t *ec, VALUE self)
VALUE stat = rb_hash_new();
tracepoint_stat_event_hooks(stat, vm->self, rb_ec_ractor_hooks(ec)->hooks);
- /* TODO: thread local hooks */
return stat;
}
@@ -1695,16 +1848,7 @@ typedef struct rb_postponed_job_queue {
rb_atomic_t triggered_bitset;
} rb_postponed_job_queues_t;
-void
-rb_vm_postponed_job_queue_init(rb_vm_t *vm)
-{
- /* use mimmalloc; postponed job registration is a dependency of objspace, so this gets
- * called _VERY_ early inside Init_BareVM */
- rb_postponed_job_queues_t *pjq = ruby_mimmalloc(sizeof(rb_postponed_job_queues_t));
- pjq->triggered_bitset = 0;
- memset(pjq->table, 0, sizeof(pjq->table));
- vm->postponed_job_queue = pjq;
-}
+static rb_postponed_job_queues_t postponed_job_queue;
static rb_execution_context_t *
get_valid_ec(rb_vm_t *vm)
@@ -1717,25 +1861,15 @@ get_valid_ec(rb_vm_t *vm)
void
rb_vm_postponed_job_atfork(void)
{
- rb_vm_t *vm = GET_VM();
- rb_postponed_job_queues_t *pjq = vm->postponed_job_queue;
+ rb_postponed_job_queues_t *pjq = &postponed_job_queue;
/* make sure we set the interrupt flag on _this_ thread if we carried any pjobs over
* from the other side of the fork */
if (pjq->triggered_bitset) {
- RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(vm));
+ RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(GET_VM()));
}
}
-/* Frees the memory managed by the postponed job infrastructure at shutdown */
-void
-rb_vm_postponed_job_free(void)
-{
- rb_vm_t *vm = GET_VM();
- ruby_xfree(vm->postponed_job_queue);
- vm->postponed_job_queue = NULL;
-}
-
// Used for VM memsize reporting. Returns the total size of the postponed job
// queue infrastructure.
size_t
@@ -1757,7 +1891,7 @@ rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, v
* of concurrent calls to both _preregister and _register functions on the same
* func, however, the data may get mixed up between them. */
- rb_postponed_job_queues_t *pjq = GET_VM()->postponed_job_queue;
+ rb_postponed_job_queues_t *pjq = &postponed_job_queue;
for (unsigned int i = 0; i < PJOB_TABLE_SIZE; i++) {
/* Try and set this slot to equal `func` */
rb_postponed_job_func_t existing_func = (rb_postponed_job_func_t)(uintptr_t)RUBY_ATOMIC_PTR_CAS(pjq->table[i].func, NULL, (void *)(uintptr_t)func);
@@ -1782,44 +1916,16 @@ rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, v
void
rb_postponed_job_trigger(rb_postponed_job_handle_t h)
{
- rb_vm_t *vm = GET_VM();
- rb_postponed_job_queues_t *pjq = vm->postponed_job_queue;
+ rb_postponed_job_queues_t *pjq = &postponed_job_queue;
RUBY_ATOMIC_OR(pjq->triggered_bitset, (((rb_atomic_t)1UL) << h));
- RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(vm));
-}
-
-
-static int
-pjob_register_legacy_impl(unsigned int flags, rb_postponed_job_func_t func, void *data)
-{
- /* We _know_ calling preregister from a signal handler like this is racy; what is
- * and is not promised is very exhaustively documented in debug.h */
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, func, data);
- if (h == POSTPONED_JOB_HANDLE_INVALID) {
- return 0;
- }
- rb_postponed_job_trigger(h);
- return 1;
+ RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(GET_VM()));
}
-int
-rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
-{
- return pjob_register_legacy_impl(flags, func, data);
-}
-
-int
-rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
-{
- return pjob_register_legacy_impl(flags, func, data);
-}
-
-
void
rb_postponed_job_flush(rb_vm_t *vm)
{
- rb_postponed_job_queues_t *pjq = GET_VM()->postponed_job_queue;
+ rb_postponed_job_queues_t *pjq = &postponed_job_queue;
rb_execution_context_t *ec = GET_EC();
const rb_atomic_t block_mask = POSTPONED_JOB_INTERRUPT_MASK | TRAP_INTERRUPT_MASK;
volatile rb_atomic_t saved_mask = ec->interrupt_mask & block_mask;
diff --git a/wasm/setjmp.h b/wasm/setjmp.h
index e65bfc0ca0..82cfff1d00 100644
--- a/wasm/setjmp.h
+++ b/wasm/setjmp.h
@@ -5,7 +5,7 @@
#include <stdbool.h>
#ifndef WASM_SETJMP_STACK_BUFFER_SIZE
-# define WASM_SETJMP_STACK_BUFFER_SIZE 6144
+# define WASM_SETJMP_STACK_BUFFER_SIZE 8192
#endif
struct __rb_wasm_asyncify_jmp_buf {
diff --git a/weakmap.c b/weakmap.c
index 2ebf7d204f..7cef1fd46a 100644
--- a/weakmap.c
+++ b/weakmap.c
@@ -34,102 +34,11 @@ struct weakmap_entry {
VALUE val;
};
-static bool
-wmap_live_p(VALUE obj)
-{
- return !UNDEF_P(obj);
-}
-
-struct wmap_foreach_data {
- int (*func)(struct weakmap_entry *, st_data_t);
- st_data_t arg;
-
- struct weakmap_entry *dead_entry;
-};
-
-static int
-wmap_foreach_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- struct wmap_foreach_data *data = (struct wmap_foreach_data *)arg;
-
- if (data->dead_entry != NULL) {
- ruby_sized_xfree(data->dead_entry, sizeof(struct weakmap_entry));
- data->dead_entry = NULL;
- }
-
- struct weakmap_entry *entry = (struct weakmap_entry *)key;
- RUBY_ASSERT(&entry->val == (VALUE *)val);
-
- if (wmap_live_p(entry->key) && wmap_live_p(entry->val)) {
- VALUE k = entry->key;
- VALUE v = entry->val;
-
- int ret = data->func(entry, data->arg);
-
- RB_GC_GUARD(k);
- RB_GC_GUARD(v);
-
- return ret;
- }
- else {
- /* We cannot free the weakmap_entry here because the ST_DELETE could
- * hash the key which would read the weakmap_entry and would cause a
- * use-after-free. Instead, we store this entry and free it on the next
- * iteration. */
- data->dead_entry = entry;
-
- return ST_DELETE;
- }
-}
-
-static void
-wmap_foreach(struct weakmap *w, int (*func)(struct weakmap_entry *, st_data_t), st_data_t arg)
-{
- struct wmap_foreach_data foreach_data = {
- .func = func,
- .arg = arg,
- .dead_entry = NULL,
- };
-
- st_foreach(w->table, wmap_foreach_i, (st_data_t)&foreach_data);
-
- ruby_sized_xfree(foreach_data.dead_entry, sizeof(struct weakmap_entry));
-}
-
-static int
-wmap_mark_weak_table_i(struct weakmap_entry *entry, st_data_t _)
-{
- rb_gc_mark_weak(&entry->key);
- rb_gc_mark_weak(&entry->val);
-
- return ST_CONTINUE;
-}
-
-static void
-wmap_mark(void *ptr)
-{
- struct weakmap *w = ptr;
- if (w->table) {
- wmap_foreach(w, wmap_mark_weak_table_i, (st_data_t)0);
- }
-}
-
-static int
-wmap_free_table_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- struct weakmap_entry *entry = (struct weakmap_entry *)key;
- RUBY_ASSERT(&entry->val == (VALUE *)val);
- ruby_sized_xfree(entry, sizeof(struct weakmap_entry));
-
- return ST_CONTINUE;
-}
-
static void
wmap_free(void *ptr)
{
struct weakmap *w = ptr;
- st_foreach(w->table, wmap_free_table_i, 0);
st_free_table(w->table);
}
@@ -139,9 +48,11 @@ wmap_memsize(const void *ptr)
const struct weakmap *w = ptr;
size_t size = 0;
- size += st_memsize(w->table);
- /* The key and value of the table each take sizeof(VALUE) in size. */
- size += st_table_size(w->table) * (2 * sizeof(VALUE));
+ if (w->table) {
+ size += st_memsize(w->table);
+ /* The key and value of the table each take sizeof(VALUE) in size. */
+ size += st_table_size(w->table) * (2 * sizeof(VALUE));
+ }
return size;
}
@@ -152,40 +63,37 @@ struct wmap_compact_table_data {
};
static int
-wmap_compact_table_i(st_data_t key, st_data_t val, st_data_t d)
+wmap_compact_table_each_i(st_data_t k, st_data_t v, st_data_t d, int error)
{
- struct wmap_compact_table_data *data = (struct wmap_compact_table_data *)d;
- if (data->dead_entry != NULL) {
- ruby_sized_xfree(data->dead_entry, sizeof(struct weakmap_entry));
- data->dead_entry = NULL;
- }
-
- struct weakmap_entry *entry = (struct weakmap_entry *)key;
+ st_table *table = (st_table *)d;
- entry->val = rb_gc_location(entry->val);
+ VALUE key = (VALUE)k;
+ VALUE val = (VALUE)v;
- VALUE new_key = rb_gc_location(entry->key);
+ VALUE moved_key = rb_gc_location(key);
+ VALUE moved_val = rb_gc_location(val);
/* If the key object moves, then we must reinsert because the hash is
* based on the pointer rather than the object itself. */
- if (entry->key != new_key) {
- DURING_GC_COULD_MALLOC_REGION_START();
- {
- struct weakmap_entry *new_entry = xmalloc(sizeof(struct weakmap_entry));
- new_entry->key = new_key;
- new_entry->val = entry->val;
- st_insert(data->table, (st_data_t)&new_entry->key, (st_data_t)&new_entry->val);
- }
- DURING_GC_COULD_MALLOC_REGION_END();
-
- /* We cannot free the weakmap_entry here because the ST_DELETE could
- * hash the key which would read the weakmap_entry and would cause a
- * use-after-free. Instead, we store this entry and free it on the next
- * iteration. */
- data->dead_entry = entry;
+ if (key != moved_key) {
+ st_insert(table, (st_data_t)moved_key, (st_data_t)moved_val);
return ST_DELETE;
}
+ else if (val != moved_val) {
+ return ST_REPLACE;
+ }
+ else {
+ return ST_CONTINUE;
+ }
+}
+
+static int
+wmap_compact_table_replace_i(st_data_t *k, st_data_t *v, st_data_t d, int existing)
+{
+ RUBY_ASSERT((VALUE)*k == rb_gc_location((VALUE)*k));
+
+ *v = (st_data_t)rb_gc_location((VALUE)*v);
return ST_CONTINUE;
}
@@ -196,24 +104,42 @@ wmap_compact(void *ptr)
struct weakmap *w = ptr;
if (w->table) {
- struct wmap_compact_table_data compact_data = {
- .table = w->table,
- .dead_entry = NULL,
- };
-
- st_foreach(w->table, wmap_compact_table_i, (st_data_t)&compact_data);
+ DURING_GC_COULD_MALLOC_REGION_START();
+ {
+ st_foreach_with_replace(w->table, wmap_compact_table_each_i, wmap_compact_table_replace_i, (st_data_t)w->table);
+ }
+ DURING_GC_COULD_MALLOC_REGION_END();
+ }
+}
- ruby_sized_xfree(compact_data.dead_entry, sizeof(struct weakmap_entry));
+static int
+rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ if (rb_gc_handle_weak_references_alive_p(key) &&
+ rb_gc_handle_weak_references_alive_p(val)) {
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
}
}
-static const rb_data_type_t weakmap_type = {
+static void
+wmap_handle_weak_references(void *ptr)
+{
+ struct weakmap *w = ptr;
+
+ st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)0);
+}
+
+const rb_data_type_t rb_weakmap_type = {
"weakmap",
{
- wmap_mark,
+ NULL,
wmap_free,
wmap_memsize,
wmap_compact,
+ wmap_handle_weak_references,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -221,21 +147,13 @@ static const rb_data_type_t weakmap_type = {
static int
wmap_cmp(st_data_t x, st_data_t y)
{
- VALUE x_obj = *(VALUE *)x;
- VALUE y_obj = *(VALUE *)y;
-
- if (!wmap_live_p(x_obj) && !wmap_live_p(y_obj)) {
- return x != y;
- }
- else {
- return x_obj != y_obj;
- }
+ return x != y;
}
static st_index_t
wmap_hash(st_data_t n)
{
- return st_numhash(*(VALUE *)n);
+ return st_numhash(n);
}
static const struct st_hash_type wmap_hash_type = {
@@ -247,8 +165,12 @@ static VALUE
wmap_allocate(VALUE klass)
{
struct weakmap *w;
- VALUE obj = TypedData_Make_Struct(klass, struct weakmap, &weakmap_type, w);
+ VALUE obj = TypedData_Make_Struct(klass, struct weakmap, &rb_weakmap_type, w);
+
w->table = st_init_table(&wmap_hash_type);
+
+ rb_gc_declare_weak_references(obj);
+
return obj;
}
@@ -264,8 +186,10 @@ wmap_inspect_append(VALUE str, VALUE obj)
}
static int
-wmap_inspect_i(struct weakmap_entry *entry, st_data_t data)
+wmap_inspect_i(st_data_t k, st_data_t v, st_data_t data)
{
+ VALUE key = (VALUE)k;
+ VALUE val = (VALUE)v;
VALUE str = (VALUE)data;
if (RSTRING_PTR(str)[0] == '#') {
@@ -276,23 +200,34 @@ wmap_inspect_i(struct weakmap_entry *entry, st_data_t data)
RSTRING_PTR(str)[0] = '#';
}
- wmap_inspect_append(str, entry->key);
+ wmap_inspect_append(str, key);
rb_str_cat2(str, " => ");
- wmap_inspect_append(str, entry->val);
+ wmap_inspect_append(str, val);
return ST_CONTINUE;
}
+/* call-seq:
+ * inspect -> new_string
+ *
+ * Returns a new string containing the \WeakMap entries:
+ *
+ * m = ObjectSpace::WeakMap.new
+ * m["one"] = 1
+ * m["two"] = 2
+ * m.inspect
+ * # => "#<ObjectSpace::WeakMap:0x00007c457b2523e8: #<String:0x00007c457b2674f0> => 1, #<String:0x00007c457b27b8d8> => 2>"
+ */
static VALUE
wmap_inspect(VALUE self)
{
VALUE c = rb_class_name(CLASS_OF(self));
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
VALUE str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void *)self);
- wmap_foreach(w, wmap_inspect_i, (st_data_t)str);
+ st_foreach(w->table, wmap_inspect_i, (st_data_t)str);
RSTRING_PTR(str)[0] = '#';
rb_str_cat2(str, ">");
@@ -301,9 +236,9 @@ wmap_inspect(VALUE self)
}
static int
-wmap_each_i(struct weakmap_entry *entry, st_data_t _)
+wmap_each_i(st_data_t k, st_data_t v, st_data_t _)
{
- rb_yield_values(2, entry->key, entry->val);
+ rb_yield_values(2, (VALUE)k, (VALUE)v);
return ST_CONTINUE;
}
@@ -320,17 +255,17 @@ static VALUE
wmap_each(VALUE self)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
- wmap_foreach(w, wmap_each_i, (st_data_t)0);
+ st_foreach(w->table, wmap_each_i, (st_data_t)0);
return self;
}
static int
-wmap_each_key_i(struct weakmap_entry *entry, st_data_t _data)
+wmap_each_key_i(st_data_t k, st_data_t _v, st_data_t _data)
{
- rb_yield(entry->key);
+ rb_yield((VALUE)k);
return ST_CONTINUE;
}
@@ -347,17 +282,17 @@ static VALUE
wmap_each_key(VALUE self)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
- wmap_foreach(w, wmap_each_key_i, (st_data_t)0);
+ st_foreach(w->table, wmap_each_key_i, (st_data_t)0);
return self;
}
static int
-wmap_each_value_i(struct weakmap_entry *entry, st_data_t _data)
+wmap_each_value_i(st_data_t k, st_data_t v, st_data_t _data)
{
- rb_yield(entry->val);
+ rb_yield((VALUE)v);
return ST_CONTINUE;
}
@@ -374,19 +309,19 @@ static VALUE
wmap_each_value(VALUE self)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
- wmap_foreach(w, wmap_each_value_i, (st_data_t)0);
+ st_foreach(w->table, wmap_each_value_i, (st_data_t)0);
return self;
}
static int
-wmap_keys_i(struct weakmap_entry *entry, st_data_t arg)
+wmap_keys_i(st_data_t k, st_data_t v, st_data_t data)
{
- VALUE ary = (VALUE)arg;
+ VALUE ary = (VALUE)data;
- rb_ary_push(ary, entry->key);
+ rb_ary_push(ary, (VALUE)k);
return ST_CONTINUE;
}
@@ -402,20 +337,20 @@ static VALUE
wmap_keys(VALUE self)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
VALUE ary = rb_ary_new();
- wmap_foreach(w, wmap_keys_i, (st_data_t)ary);
+ st_foreach(w->table, wmap_keys_i, (st_data_t)ary);
return ary;
}
static int
-wmap_values_i(struct weakmap_entry *entry, st_data_t arg)
+wmap_values_i(st_data_t k, st_data_t v, st_data_t data)
{
- VALUE ary = (VALUE)arg;
+ VALUE ary = (VALUE)data;
- rb_ary_push(ary, entry->val);
+ rb_ary_push(ary, (VALUE)v);
return ST_CONTINUE;
}
@@ -431,36 +366,14 @@ static VALUE
wmap_values(VALUE self)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
VALUE ary = rb_ary_new();
- wmap_foreach(w, wmap_values_i, (st_data_t)ary);
+ st_foreach(w->table, wmap_values_i, (st_data_t)ary);
return ary;
}
-static int
-wmap_aset_replace(st_data_t *key, st_data_t *val, st_data_t new_key_ptr, int existing)
-{
- VALUE new_key = *(VALUE *)new_key_ptr;
- VALUE new_val = *(((VALUE *)new_key_ptr) + 1);
-
- if (existing) {
- RUBY_ASSERT(*(VALUE *)*key == new_key);
- }
- else {
- struct weakmap_entry *entry = xmalloc(sizeof(struct weakmap_entry));
-
- *key = (st_data_t)&entry->key;
- *val = (st_data_t)&entry->val;
- }
-
- *(VALUE *)*key = new_key;
- *(VALUE *)*val = new_val;
-
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* map[key] = value -> value
@@ -474,33 +387,27 @@ static VALUE
wmap_aset(VALUE self, VALUE key, VALUE val)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
- VALUE pair[2] = { key, val };
-
- st_update(w->table, (st_data_t)pair, wmap_aset_replace, (st_data_t)pair);
+ st_insert(w->table, (st_data_t)key, (st_data_t)val);
RB_OBJ_WRITTEN(self, Qundef, key);
RB_OBJ_WRITTEN(self, Qundef, val);
- return Qnil;
+ return val;
}
/* Retrieves a weakly referenced object with the given key */
static VALUE
wmap_lookup(VALUE self, VALUE key)
{
- RUBY_ASSERT(wmap_live_p(key));
-
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
st_data_t data;
- if (!st_lookup(w->table, (st_data_t)&key, &data)) return Qundef;
+ if (!st_lookup(w->table, (st_data_t)key, &data)) return Qundef;
- if (!wmap_live_p(*(VALUE *)data)) return Qundef;
-
- return *(VALUE *)data;
+ return (VALUE)data;
}
/*
@@ -550,23 +457,12 @@ static VALUE
wmap_delete(VALUE self, VALUE key)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
-
- VALUE orig_key = key;
- st_data_t orig_key_data = (st_data_t)&orig_key;
- st_data_t orig_val_data;
- if (st_delete(w->table, &orig_key_data, &orig_val_data)) {
- VALUE orig_val = *(VALUE *)orig_val_data;
-
- rb_gc_remove_weak(self, (VALUE *)orig_key_data);
- rb_gc_remove_weak(self, (VALUE *)orig_val_data);
-
- struct weakmap_entry *entry = (struct weakmap_entry *)orig_key_data;
- ruby_sized_xfree(entry, sizeof(struct weakmap_entry));
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
- if (wmap_live_p(orig_val)) {
- return orig_val;
- }
+ st_data_t orig_key = (st_data_t)key;
+ st_data_t orig_val;
+ if (st_delete(w->table, &orig_key, &orig_val)) {
+ return (VALUE)orig_val;
}
if (rb_block_given_p()) {
@@ -599,7 +495,7 @@ static VALUE
wmap_size(VALUE self)
{
struct weakmap *w;
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
st_index_t n = st_table_size(w->table);
@@ -633,25 +529,11 @@ struct weakkeymap {
};
static int
-wkmap_mark_table_i(st_data_t key, st_data_t val_obj, st_data_t data)
+wkmap_mark_table_i(st_data_t key, st_data_t val_obj, st_data_t _data)
{
- VALUE **dead_entry = (VALUE **)data;
- ruby_sized_xfree(*dead_entry, sizeof(VALUE));
- *dead_entry = NULL;
-
- VALUE *key_ptr = (VALUE *)key;
-
- if (wmap_live_p(*key_ptr)) {
- rb_gc_mark_weak(key_ptr);
- rb_gc_mark_movable((VALUE)val_obj);
-
- return ST_CONTINUE;
- }
- else {
- *dead_entry = key_ptr;
+ rb_gc_mark_movable((VALUE)val_obj);
- return ST_DELETE;
- }
+ return ST_CONTINUE;
}
static void
@@ -659,27 +541,15 @@ wkmap_mark(void *ptr)
{
struct weakkeymap *w = ptr;
if (w->table) {
- VALUE *dead_entry = NULL;
- st_foreach(w->table, wkmap_mark_table_i, (st_data_t)&dead_entry);
- if (dead_entry != NULL) {
- ruby_sized_xfree(dead_entry, sizeof(VALUE));
- }
+ st_foreach(w->table, wkmap_mark_table_i, (st_data_t)0);
}
}
-static int
-wkmap_free_table_i(st_data_t key, st_data_t _val, st_data_t _arg)
-{
- ruby_sized_xfree((VALUE *)key, sizeof(VALUE));
- return ST_CONTINUE;
-}
-
static void
wkmap_free(void *ptr)
{
struct weakkeymap *w = ptr;
- st_foreach(w->table, wkmap_free_table_i, 0);
st_free_table(w->table);
}
@@ -689,34 +559,23 @@ wkmap_memsize(const void *ptr)
const struct weakkeymap *w = ptr;
size_t size = 0;
- size += st_memsize(w->table);
- /* Each key of the table takes sizeof(VALUE) in size. */
- size += st_table_size(w->table) * sizeof(VALUE);
+ if (w->table) {
+ size += st_memsize(w->table);
+ /* Each key of the table takes sizeof(VALUE) in size. */
+ size += st_table_size(w->table) * sizeof(VALUE);
+ }
return size;
}
static int
-wkmap_compact_table_i(st_data_t key, st_data_t val_obj, st_data_t data, int _error)
+wkmap_compact_table_i(st_data_t key, st_data_t val, st_data_t _data, int _error)
{
- VALUE **dead_entry = (VALUE **)data;
- ruby_sized_xfree(*dead_entry, sizeof(VALUE));
- *dead_entry = NULL;
-
- VALUE *key_ptr = (VALUE *)key;
-
- if (wmap_live_p(*key_ptr)) {
- if (*key_ptr != rb_gc_location(*key_ptr) || val_obj != rb_gc_location(val_obj)) {
- return ST_REPLACE;
- }
-
- return ST_CONTINUE;
+ if ((VALUE)key != rb_gc_location((VALUE)key) || (VALUE)val != rb_gc_location((VALUE)val)) {
+ return ST_REPLACE;
}
- else {
- *dead_entry = key_ptr;
- return ST_DELETE;
- }
+ return ST_CONTINUE;
}
static int
@@ -724,7 +583,7 @@ wkmap_compact_table_replace(st_data_t *key_ptr, st_data_t *val_ptr, st_data_t _d
{
RUBY_ASSERT(existing);
- *(VALUE *)*key_ptr = rb_gc_location(*(VALUE *)*key_ptr);
+ *key_ptr = (st_data_t)rb_gc_location((VALUE)*key_ptr);
*val_ptr = (st_data_t)rb_gc_location((VALUE)*val_ptr);
return ST_CONTINUE;
@@ -736,21 +595,37 @@ wkmap_compact(void *ptr)
struct weakkeymap *w = ptr;
if (w->table) {
- VALUE *dead_entry = NULL;
- st_foreach_with_replace(w->table, wkmap_compact_table_i, wkmap_compact_table_replace, (st_data_t)&dead_entry);
- if (dead_entry != NULL) {
- ruby_sized_xfree(dead_entry, sizeof(VALUE));
- }
+ st_foreach_with_replace(w->table, wkmap_compact_table_i, wkmap_compact_table_replace, (st_data_t)0);
}
}
-static const rb_data_type_t weakkeymap_type = {
+static int
+rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ if (rb_gc_handle_weak_references_alive_p(key)) {
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+static void
+wkmap_handle_weak_references(void *ptr)
+{
+ struct weakkeymap *w = ptr;
+
+ st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)0);
+}
+
+static const rb_data_type_t rb_weakkeymap_type = {
"weakkeymap",
{
wkmap_mark,
wkmap_free,
wkmap_memsize,
wkmap_compact,
+ wkmap_handle_weak_references,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@@ -758,23 +633,16 @@ static const rb_data_type_t weakkeymap_type = {
static int
wkmap_cmp(st_data_t x, st_data_t y)
{
- VALUE x_obj = *(VALUE *)x;
- VALUE y_obj = *(VALUE *)y;
+ VALUE x_obj = (VALUE)x;
+ VALUE y_obj = (VALUE)y;
- if (wmap_live_p(x_obj) && wmap_live_p(y_obj)) {
- return rb_any_cmp(x_obj, y_obj);
- }
- else {
- /* If one of the objects is dead, then they cannot be the same. */
- return 1;
- }
+ return rb_any_cmp(x_obj, y_obj);
}
static st_index_t
wkmap_hash(st_data_t n)
{
- VALUE obj = *(VALUE *)n;
- RUBY_ASSERT(wmap_live_p(obj));
+ VALUE obj = (VALUE)n;
return rb_any_hash(obj);
}
@@ -788,8 +656,13 @@ static VALUE
wkmap_allocate(VALUE klass)
{
struct weakkeymap *w;
- VALUE obj = TypedData_Make_Struct(klass, struct weakkeymap, &weakkeymap_type, w);
+
+ VALUE obj = TypedData_Make_Struct(klass, struct weakkeymap, &rb_weakkeymap_type, w);
+
w->table = st_init_table(&wkmap_hash_type);
+
+ rb_gc_declare_weak_references(obj);
+
return obj;
}
@@ -797,10 +670,10 @@ static VALUE
wkmap_lookup(VALUE self, VALUE key)
{
struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
+ TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
st_data_t data;
- if (!st_lookup(w->table, (st_data_t)&key, &data)) return Qundef;
+ if (!st_lookup(w->table, (st_data_t)key, &data)) return Qundef;
return (VALUE)data;
}
@@ -825,21 +698,6 @@ struct wkmap_aset_args {
VALUE new_val;
};
-static int
-wkmap_aset_replace(st_data_t *key, st_data_t *val, st_data_t data_args, int existing)
-{
- struct wkmap_aset_args *args = (struct wkmap_aset_args *)data_args;
-
- if (!existing) {
- *key = (st_data_t)xmalloc(sizeof(VALUE));
- }
-
- *(VALUE *)*key = args->new_key;
- *val = (st_data_t)args->new_val;
-
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* map[key] = value -> value
@@ -856,19 +714,14 @@ static VALUE
wkmap_aset(VALUE self, VALUE key, VALUE val)
{
struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
+ TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
if (!FL_ABLE(key) || SYMBOL_P(key) || RB_BIGNUM_TYPE_P(key) || RB_TYPE_P(key, T_FLOAT)) {
rb_raise(rb_eArgError, "WeakKeyMap keys must be garbage collectable");
UNREACHABLE_RETURN(Qnil);
}
- struct wkmap_aset_args args = {
- .new_key = key,
- .new_val = val,
- };
-
- st_update(w->table, (st_data_t)&key, wkmap_aset_replace, (st_data_t)&args);
+ st_insert(w->table, (st_data_t)key, (st_data_t)val);
RB_OBJ_WRITTEN(self, Qundef, key);
RB_OBJ_WRITTEN(self, Qundef, val);
@@ -909,19 +762,12 @@ static VALUE
wkmap_delete(VALUE self, VALUE key)
{
struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
-
- VALUE orig_key = key;
- st_data_t orig_key_data = (st_data_t)&orig_key;
- st_data_t orig_val_data;
- if (st_delete(w->table, &orig_key_data, &orig_val_data)) {
- VALUE orig_val = (VALUE)orig_val_data;
-
- rb_gc_remove_weak(self, (VALUE *)orig_key_data);
-
- ruby_sized_xfree((VALUE *)orig_key_data, sizeof(VALUE));
+ TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
- return orig_val;
+ st_data_t orig_key = (st_data_t)key;
+ st_data_t orig_val;
+ if (st_delete(w->table, &orig_key, &orig_val)) {
+ return (VALUE)orig_val;
}
if (rb_block_given_p()) {
@@ -955,12 +801,12 @@ static VALUE
wkmap_getkey(VALUE self, VALUE key)
{
struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
+ TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
st_data_t orig_key;
- if (!st_get_key(w->table, (st_data_t)&key, &orig_key)) return Qnil;
+ if (!st_get_key(w->table, (st_data_t)key, &orig_key)) return Qnil;
- return *(VALUE *)orig_key;
+ return (VALUE)orig_key;
}
/*
@@ -975,17 +821,6 @@ wkmap_has_key(VALUE self, VALUE key)
return RBOOL(!UNDEF_P(wkmap_lookup(self, key)));
}
-static int
-wkmap_clear_i(st_data_t key, st_data_t val, st_data_t data)
-{
- VALUE self = (VALUE)data;
-
- /* This WeakKeyMap may have already been marked, so we need to remove the
- * keys to prevent a use-after-free. */
- rb_gc_remove_weak(self, (VALUE *)key);
- return wkmap_free_table_i(key, val, 0);
-}
-
/*
* call-seq:
* map.clear -> self
@@ -996,9 +831,8 @@ static VALUE
wkmap_clear(VALUE self)
{
struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
+ TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
- st_foreach(w->table, wkmap_clear_i, (st_data_t)self);
st_clear(w->table);
return self;
@@ -1019,7 +853,7 @@ static VALUE
wkmap_inspect(VALUE self)
{
struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
+ TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
st_index_t n = st_table_size(w->table);
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 3acdb1a2bd..47837c42ad 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -13,22 +13,28 @@ PWD = $(MAKEDIR)
empty =
tooldir = $(srcdir)/tool
+PROMPT = +$$S
+
+MAKEFLAGS = l$(MAKEFLAGS)
+
!ifndef MFLAGS
MFLAGS=-l
!endif
-!if "$(BASERUBY)" == ""
+!if "$(HAVE_BASERUBY)" == "no"
+BASERUBY =
+!else if "$(BASERUBY)" == ""
# After `nmake`, just built `ruby.exe` exists in the build directory,
# and is searched first prior to $PATH. Assume that no ruby
# executable in $(tooldir).
! if [cd $(tooldir) && ruby missing-baseruby.bat 2> nul]
! else if [(cd $(tooldir) && for %I in (ruby.exe) do @echo BASERUBY = %~s$$PATH:I) > baseruby.mk]
-! else
+! else if exist(baseruby.mk)
! include baseruby.mk
! endif
-! if [del baseruby.mk]
+! if [del baseruby.mk 2> nul]
! endif
-!else if "$(BASERUBY)" == "no" || [($(BASERUBY) -eexit) > nul 2> nul]
+!else if [($(BASERUBY) $(tooldir)/missing-baseruby.bat) > nul 2> nul]
BASERUBY =
!endif
!if "$(BASERUBY)" == ""
@@ -115,22 +121,24 @@ IFCHANGE = $(COMSPEC) /C $(srcdir:/=\)\win32\ifchange.bat
RM = $(COMSPEC) /C $(srcdir:/=\)\win32\rm.bat
RM1 = del
RMDIR = $(COMSPEC) /C $(srcdir:/=\)\win32\rmdirs.bat
-RMDIRS = $(COMSPEC) /C $(srcdir:/=\)\win32\rmdirs.bat
+RMDIRS = $(COMSPEC) /C $(srcdir:/=\)\win32\rmdirs.bat -p
RMALL = $(COMSPEC) /C $(srcdir:/=\)\win32\rm.bat -f -r
MAKEDIRS = $(COMSPEC) /E:ON /C $(srcdir:/=\)\win32\makedirs.bat
TOUCH = $(BASERUBY) -run -e touch --
CP = copy > nul
MV = move > nul
RM1 = del /f /q
-!if !defined(BASERUBY)
-BASERUBY = ruby
-!endif
!if !defined(TEST_RUNNABLE)
TEST_RUNNABLE = yes
!endif
CAT_DEPEND = type
+!if !defined(MSC_VER)
+! error MSC_VER not defined. Retry from configure pass.
+!else if $(MSC_VER) < 1900
+! error MSVC $(MSC_VER) is not supported
+!endif
!if !defined(MACHINE)
MACHINE = x86
!endif
@@ -141,9 +149,6 @@ PROCESSOR_LEVEL = 5
!if 6 < $(PROCESSOR_LEVEL)
PROCESSOR_LEVEL = 6
!endif
-!if $(MSC_VER) < 1400
-PROCESSOR_FLAG = -G$(PROCESSOR_LEVEL)
-!endif
CPU = i$(PROCESSOR_LEVEL)86
ARCH = i386
!else
@@ -160,15 +165,9 @@ XCFLAGS = $(XCFLAGS) -DRUBY_DEVEL=1
XCFLAGS = $(XCFLAGS) -Dmodular_gc_dir="$(modular_gc_dir)"
!endif
!if !defined(OPTFLAGS)
-!if $(MSC_VER) < 1400
-OPTFLAGS = -O2b2xg-
-!else
OPTFLAGS = -O2sy-
!endif
-!endif
-!if $(MSC_VER) >= 1900
OPTFLAGS = $(OPTFLAGS) -Zc:inline
-!endif
!if !defined(incflags)
incflags =
!endif
@@ -177,6 +176,8 @@ PLATFORM = mswin32
!endif
!if !defined(RT)
!error RT not defined. Retry from configure pass.
+!else if $(RT_VER) < 140
+! error Runtime library $(RT_VER) is not supported
!endif
!ifndef NTVER
NTVER = _WIN32_WINNT_WIN8
@@ -263,11 +264,7 @@ OUTFLAG = -Fe
COUTFLAG = -Fo
!endif
!if !defined(CPPOUTFLAG)
-! if $(MSC_VER) < 1600
-CPPOUTFLAG = >
-! else
CPPOUTFLAG = -Fi
-! endif
!endif
!if !defined(CSRCFLAG)
CSRCFLAG = -Tc
@@ -279,12 +276,12 @@ RUNTIMEFLAG = -MD
COMPILERFLAG = -Zm600
!endif
!if !defined(WARNFLAGS)
-!if $(MSC_VER) >= 1400
WARNFLAGS = -W2 -wd4100 -wd4127 -wd4210 -wd4214 -wd4255 -wd4574 \
-wd4668 -wd4710 -wd4711 -wd4820 -wd4996 \
-we4028 -we4142 -we4047 -we4013
-!else
-WARNFLAGS = -W2
+!if $(MSC_VER) >= 1944
+# https://developercommunity.visualstudio.com/t/warning-C5287:-operands-are-different-e/10877942
+WARNFLAGS = $(WARNFLAGS) -wd5287
!endif
!endif
WERRORFLAG = -WX
@@ -315,9 +312,7 @@ EXTSOLIBS =
!endif
!if !defined(LIBS)
LIBS = user32.lib advapi32.lib shell32.lib ws2_32.lib
-!if $(MSC_VER) >= 1400
LIBS = $(LIBS) iphlpapi.lib
-!endif
!if defined(USE_GMP)
LIBS = $(LIBS) gmp.lib
!endif
@@ -325,9 +320,6 @@ LIBS = $(LIBS) imagehlp.lib shlwapi.lib bcrypt.lib $(EXTLIBS)
!endif
!if !defined(MISSING)
MISSING = crypt.obj ffs.obj langinfo.obj lgamma_r.obj strlcat.obj strlcpy.obj win32/win32.obj win32/file.obj setproctitle.obj
-!if $(RT_VER) < 120
-MISSING = $(MISSING) acosh.obj cbrt.obj erf.obj nan.obj tgamma.obj
-!endif
MISSING = $(MISSING) explicit_bzero.obj
!endif
DLNOBJ = dln.obj
@@ -350,15 +342,7 @@ ARFLAGS = -machine:$(MACHINE) -out:
LD = $(CC)
LDSHARED = $(LD) -LD
XCFLAGS = -DRUBY_EXPORT $(INCFLAGS) $(XCFLAGS) $(XINCFLAGS)
-!if $(MSC_VER) >= 1800
LDFLAGS = $(LDFLAGS) -manifest:embed,ID=2
-!elseif $(MSC_VER) >= 1400
-# Prevents VC++ 2005 (cl ver 14) warnings
-MANIFESTTOOL = mt -nologo
-LDSHARED_0 = @if exist $(@).manifest $(MINIRUBY) -run -e wait_writable -- -n 10 $@
-LDSHARED_1 = @if exist $(@).manifest $(MANIFESTTOOL) -manifest $(@).manifest -outputresource:$(@);2
-LDSHARED_2 = @if exist $(@).manifest @$(RM) $(@:/=\).manifest
-!endif
CPPFLAGS = $(DEFS) $(ARCHDEFS) $(CPPFLAGS)
!if "$(USE_RUBYGEMS)" == "no"
CPPFLAGS = -DDISABLE_RUBYGEMS $(CPPFLAGS)
@@ -370,16 +354,15 @@ MAINLIBS = $(LIBS)
SOLIBS =
RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc
!ifndef RCFLAGS
-!if $(MSC_VER) >= 1600
RCFLAGS=-nologo
!endif
-!endif
ENABLE_SHARED = yes
LIBRUBY_LDSHARED = $(LDSHARED)
LIBRUBY_DLDFLAGS = $(EXTLDFLAGS) -implib:dummy.lib -def:$(RUBYDEF)
EXEEXT = .exe
+BUILD_EXEEXT = $(EXEEXT)
EXECUTABLE_EXTS = ".exe",".com",".cmd",".bat"
!if !defined(PROGRAM)
PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT)
@@ -457,9 +440,11 @@ EXTSTATIC =
OBJEXT = obj
ASMEXT = asm
+DLEXT = so
INSTALLED_LIST= .installed.list
+HASH_SIGN = ^#
SRC_FILE = $(<:\=/)
OS_SRC_FILE = $(<:/=\)
DEST_FILE = $(@:\=/)
@@ -493,7 +478,8 @@ ENCOBJS = dmyenc.$(OBJEXT)
EXTOBJS = dmyext.$(OBJEXT)
!endif
-arch_hdrdir = $(EXTOUT)/include/$(arch)
+ext_hdrdir = $(EXTOUT)/include
+arch_hdrdir = $(ext_hdrdir)/$(arch)
top_srcdir = $(srcdir)
hdrdir = $(srcdir)/include
VPATH = $(arch_hdrdir)/ruby;$(hdrdir)/ruby;$(srcdir);$(srcdir)/missing;$(win_srcdir)
@@ -517,6 +503,15 @@ HAVE_GIT = yes
HAVE_GIT = no
! endif
!endif
+!if "$(HAVE_GIT)" == "no"
+!else if [for /f "tokens=3" %I in ('git --version') do @(\
+ for /f "delims=. tokens=1-2" %I in ("%I") do @(\
+ if %I lss 2 (exit 1) else if %I gtr 2 (exit 0) \
+ else if %J lss 10 (exit 1) else (exit 0)\
+ )\
+ )]
+HAVE_GIT = no
+!endif
!if defined(VCS)
!else if exist($(srcdir)/.git)
@@ -532,9 +527,10 @@ MESSAGE_END = ) do @echo.%~I)
ECHO_BEGIN = @echo.
ECHO_END =
-all: $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub $(srcdir)/common.mk
+all: $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub $(srcdir)/common.mk $(srcdir)/depend
prog: config
+# The default non-transformed names without $(EXEEXT).
ruby: $(PROGRAM)
rubyw: $(WPROGRAM)
stub: $(STUBPROGRAM)
@@ -563,6 +559,13 @@ ACTIONS_ENDGROUP = @::
ABI_VERSION_HDR = $(hdrdir)/ruby/internal/abi.h
+!if defined(DUMP_AST)
+DUMP_AST_TARGET = $(empty)
+!else
+DUMP_AST = dump_ast$(BUILD_EXEEXT)
+DUMP_AST_TARGET = $(DUMP_AST)
+!endif
+
!include $(srcdir)/common.mk
!ifdef SCRIPTPROGRAMS
@@ -643,7 +646,8 @@ config.status: nul
guard = INCLUDE_RUBY_CONFIG_H
-$(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
+$(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub \
+ $(ABI_VERSION_HDR)
@echo Creating config.h
!if !exist("$(arch_hdrdir)")
@md $(arch_hdrdir:/=\)
@@ -671,9 +675,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define STDC_HEADERS 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_SYS_STAT_H 1
-!if $(MSC_VER) >= 1800
#define HAVE_STDBOOL_H 1
-!endif
#define HAVE_STDLIB_H 1
#define HAVE_STDDEF_H 1
#define HAVE_STRING_H 1
@@ -681,11 +683,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
!if $(MSC_VER) >= 1920
#define HAVE_AFUNIX_H 1
!endif
-!if $(MSC_VER) >= 1400
#define HAVE_LONG_LONG 1
-!else
-#define ULL_TO_DOUBLE(n) ((double)(unsigned long)((n)>>32) * (1I64 << 32) + (unsigned long)(n))
-!endif
#define HAVE_OFF_T 1
#define rb_off_t __int64
#define SIGNEDNESS_OF_OFF_T -1
@@ -694,11 +692,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define SIZEOF_INT 4
#define SIZEOF_SHORT 2
#define SIZEOF_LONG 4
-!if $(MSC_VER) >= 1400
#define SIZEOF_LONG_LONG 8
-!else
-#define SIZEOF_LONG_LONG 0
-!endif
#define SIZEOF___INT64 8
#ifndef _INTEGRAL_MAX_BITS
#define _INTEGRAL_MAX_BITS 64
@@ -713,15 +707,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define SIZEOF_DOUBLE 8
#define SIGNEDNESS_OF_TIME_T -1
#define NEGATIVE_TIME_T 1
-!if $(RT_VER) >= 80
#define SIZEOF_TIME_T 8
#define TIMET2NUM(v) LL2NUM(v)
#define NUM2TIMET(v) NUM2LL(v)
-!else
-#define SIZEOF_TIME_T 4
-#define TIMET2NUM(v) LONG2NUM(v)
-#define NUM2TIMET(v) NUM2LONG(v)
-!endif
#define CLOCKID2NUM(v) INT2NUM(v)
#define NUM2CLOCKID(v) NUM2INT(v)
#define SIZEOF_CLOCK_T 4
@@ -737,22 +725,11 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define SIZEOF_INTPTR_T 4
#define SIZEOF_UINTPTR_T 4
!endif
-!if $(MSC_VER) < 1400
-#define SIZE_MAX UINT_MAX
-!endif
-!if $(MSC_VER) >= 1800
#define HAVE_VA_COPY 1
-!else
-#define HAVE_VA_COPY_VIA_STRUCT_ASSIGNMENT 1
-!endif
-!if $(MSC_VER) > 1100
#define NORETURN(x) __declspec(noreturn) x
-!endif
-!if $(MSC_VER) >= 1300
#define DEPRECATED(x) __declspec(deprecated) x
#define RUBY_CXX_DEPRECATED(mesg) __declspec(deprecated(mesg))
#define NOINLINE(x) __declspec(noinline) x
-!endif
#define ALWAYS_INLINE(x) __forceinline x
#define WARN_UNUSED_RESULT(x) x
#define MAYBE_UNUSED(x) x
@@ -760,11 +737,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define FUNC_STDCALL(x) __stdcall x
#define FUNC_CDECL(x) __cdecl x
#define FUNC_FASTCALL(x) __fastcall x
-!if $(MSC_VER) >= 1500
#define RUBY_FUNCTION_NAME_STRING __FUNCTION__
#define RBIMPL_ATTR_PACKED_STRUCT_BEGIN() __pragma(pack(push, 1))
#define RBIMPL_ATTR_PACKED_STRUCT_END() __pragma(pack(pop))
-!endif
#define RUBY_EXTERN extern __declspec(dllimport)
#define RUBY_FUNC_EXPORTED extern __declspec(dllexport)
#define RUBY_ALIGNAS(n) __declspec(align(n))
@@ -780,34 +755,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define rb_uid_t int
#define HAVE_STRUCT_STAT_ST_RDEV 1
#define HAVE_STRUCT_TIMEVAL 1
-!if $(MSC_VER) >= 1900
#define HAVE_STRUCT_TIMESPEC
-!endif
-!if $(MSC_VER) >= 1600
#define HAVE_INTTYPES_H 1
#define HAVE_STDINT_H 1
-!else
-#define int8_t signed char
-#define uint8_t unsigned char
-#define int16_t short
-#define uint16_t unsigned short
-#define int32_t int
-#define uint32_t unsigned int
-#define int64_t __int64
-#define uint64_t unsigned __int64
-#define INT8_MIN _I8_MIN
-#define INT8_MAX _I8_MAX
-#define UINT8_MAX _UI8_MAX
-#define INT16_MIN _I16_MIN
-#define INT16_MAX _I16_MAX
-#define UINT16_MAX _UI16_MAX
-#define INT32_MIN _I32_MIN
-#define INT32_MAX _I32_MAX
-#define UINT32_MAX _UI32_MAX
-#define INT64_MIN _I64_MIN
-#define INT64_MAX _I64_MAX
-#define UINT64_MAX _UI64_MAX
-!endif
#define HAVE_INT8_T 1
#define HAVE_UINT8_T 1
#define SIZEOF_INT8_T 1
@@ -838,7 +788,6 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define PRI_PIDT_PREFIX PRI_INT_PREFIX
#define GETGROUPS_T int
#define TYPEOF_TIMEVAL_TV_SEC long
-!if $(RT_VER) >= 120
#define HAVE_ACOSH 1
#define HAVE_ASINH 1
#define HAVE_ATANH 1
@@ -850,7 +799,6 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_ROUND 1
#define HAVE_TGAMMA 1
#define HAVE_NEXTAFTER 1
-!endif
#define HAVE_ALLOCA 1
#define HAVE_DUP2 1
#define HAVE_MEMCMP 1
@@ -867,14 +815,10 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_STRCHR 1
#define HAVE_STRSTR 1
#define HAVE_FLOCK 1
-!if $(MSC_VER) >= 1800
#define HAVE_ISINF 1
-!endif
#define HAVE_ISNAN 1
#define HAVE_FINITE 1
-!if $(RT_VER) >= 120
#define HAVE_NAN 1
-!endif
#define HAVE_HYPOT 1
#define HAVE_FMOD 1
#define HAVE_FREXP 1
@@ -920,13 +864,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_SYSTEM 1
#define HAVE_TZSET 1
#define HAVE_UMASK 1
-!if $(RT_VER) > 120
#define HAVE_QSORT_S
-!endif
#define HAVE_TYPE_NET_LUID 1
-!if $(MSC_VER) >= 1600
#define HAVE_NULLPTR 1
-!endif
#define SETPGRP_VOID 1
#define RSHIFT(x,y) ((x)>>(int)y)
#define HAVE_RB_FD_INIT 1
@@ -935,11 +875,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define RUBY_JMP_BUF jmp_buf
#ifndef __cplusplus
#define inline __inline
-!if $(MSC_VER) >= 1800
#define restrict __restrict
-!else
-#define restrict /* not supported */
-!endif
#endif
#define NEED_IO_SEEK_BETWEEN_RW 1
!if "$(MACHINE)" == "x86" || "$(ARCH)" == "x64"
@@ -949,7 +885,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define THREAD_IMPL_H "$(THREAD_IMPL_H)"
#define THREAD_IMPL_SRC "$(THREAD_IMPL_SRC)"
#define LOAD_RELATIVE 1
-#define DLEXT ".so"
+#define DLEXT ".$(DLEXT)"
!if "$(libdir_basename)" != "lib"
#define LIBDIR_BASENAME "$(libdir_basename)"
!endif
@@ -1044,7 +980,7 @@ s,@LN_S@,$(LN_S),;t t
s,@SET_MAKE@,MFLAGS = -$$(MAKEFLAGS),;t t
s,@RM@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rm.bat,;t t
s,@RMDIR@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rmdirs.bat,:t t
-s,@RMDIRS@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rmdirs.bat,;t t
+s,@RMDIRS@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rmdirs.bat -p,;t t
s,@RMALL@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rm.bat -f -r,:t t
s,@MAKEDIRS@,$$(COMSPEC) /E:ON /C $$(top_srcdir:/=\)\win32\makedirs.bat,;t t
s,@LIBOBJS@,$(LIBOBJS),;t t
@@ -1062,7 +998,7 @@ s,@STATIC@,$(STATIC),;t t
s,@CCDLFLAGS@,,;t t
s,@LDSHARED@,$(LDSHARED),;t t
s,@SOEXT@,dll,;t t
-s,@DLEXT@,so,;t t
+s,@DLEXT@,$(DLEXT),;t t
s,@LIBEXT@,lib,;t t
s,@STRIP@,$(STRIP),;t t
s,@ENCSTATIC@,$(ENCSTATIC),;t t
@@ -1103,11 +1039,6 @@ s,@LIBPATHFLAG@,-libpath:%s,;t t
s,@RPATHFLAG@,,;t t
s,@LIBARG@,%s.lib,;t t
s,@LINK_SO@,$$(LDSHARED) -Fe$$(@) $$(OBJS) $$(LIBS) $$(LOCAL_LIBS) -link $$(DLDFLAGS) -implib:$$(*F:.so=)-$$(arch).lib -pdb:$$(*F:.so=)-$$(arch).pdb -def:$$(DEFFILE),;t t
-!if $(MSC_VER) >= 1400 && $(MSC_VER) < 1800
-s,@LINK_SO@,@if exist $$(@).manifest $$(RUBY) -run -e wait_writable -- -n 10 $$(@),;t t
-s,@LINK_SO@,@if exist $$(@).manifest $(MANIFESTTOOL) -manifest $$(@).manifest -outputresource:$$(@);2,;t t
-s,@LINK_SO@,@if exist $$(@).manifest $$(RM) $$(@:/=\).manifest,;t t
-!endif
s,@COMPILE_C@,$$(CC) $$(INCFLAGS) $$(CFLAGS) $$(CPPFLAGS) $$(COUTFLAG)$$(@) -c $$(CSRCFLAG)$$(<:\=/),;t t
s,@COMPILE_CXX@,$$(CXX) $$(INCFLAGS) $$(CXXFLAGS) $$(CPPFLAGS) $$(COUTFLAG)$$(@) -c -Tp$$(<:\=/),;t t
s,@ASSEMBLE_C@,$$(CC) $$(CFLAGS) $$(CPPFLAGS) -Fa$$(@) -c $$(CSRCFLAG)$$(<:\=/),;t t
@@ -1189,11 +1120,6 @@ $(PROGRAM): $(MAINOBJ) $(LIBRUBY_SO) $(RUBY_INSTALL_NAME).res
$(ECHO) linking $(@:\=/)
$(Q) $(PURIFY) $(CC) $(MAINOBJ) $(EXTOBJS) $(RUBY_INSTALL_NAME).res \
$(OUTFLAG)$@ $(LIBRUBYARG) -link $(LDFLAGS) $(XLDFLAGS)
-! if defined(LDSHARED_0)
- $(Q) $(LDSHARED_0)
- $(Q) $(LDSHARED_1)
- $(Q) $(LDSHARED_2)
-! endif
!endif
!if "$(WPROGRAM)" != ""
@@ -1202,11 +1128,6 @@ $(WPROGRAM): $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_SO) $(RUBYW_INSTALL_NAME).res
$(Q) $(PURIFY) $(CC) $(MAINOBJ) $(WINMAINOBJ) \
$(RUBYW_INSTALL_NAME).res $(OUTFLAG)$@ $(LIBRUBYARG) \
-link $(LDFLAGS) $(XLDFLAGS) -subsystem:Windows
-! if defined(LDSHARED_0)
- $(Q) $(LDSHARED_0)
- $(Q) $(LDSHARED_1)
- $(Q) $(LDSHARED_2)
-! endif
!endif
!if "$(STUBPROGRAM)" != ""
@@ -1214,11 +1135,6 @@ $(STUBPROGRAM): rubystub.$(OBJEXT) $(LIBRUBY) $(LIBRUBY_SO) $(RUBY_INSTALL_NAME)
$(ECHO) linking $(@:\=/)
$(Q) $(PURIFY) $(CC) rubystub.$(OBJEXT) $(RUBY_INSTALL_NAME).res \
$(OUTFLAG)$@ $(LIBRUBYARG) -link $(LDFLAGS) $(XLDFLAGS)
-! if defined(LDSHARED_0)
- $(Q) $(LDSHARED_0)
- $(Q) $(LDSHARED_1)
- $(Q) $(LDSHARED_2)
-! endif
!endif
!if "$(LIBRUBY_SO_UPDATE)" == ""
@@ -1249,12 +1165,6 @@ $(LIBRUBY_SO): $(LIBRUBY_A) $(DLDOBJS) $(RUBYDEF) $(RUBY_SO_NAME).res
$(OUTFLAG)$@ -link $(LDFLAGS) $(XLDFLAGS) \
$(LIBRUBY_DLDFLAGS)
@$(RM) dummy.lib dummy.exp
-!if defined(LDSHARED_0)
- $(Q) $(LDSHARED_0)
- $(Q) $(LDSHARED_1)
- $(Q) $(LDSHARED_2)
-# | findstr -v -c:LNK4049 -c:LNK4217
-!endif
$(RUBYDEF): $(LIBRUBY_A) $(RBCONFIG)
$(ECHO) generating $(@:\=/)
@@ -1268,14 +1178,44 @@ clean-local::
$(Q)$(RM) $(WINMAINOBJ) ext\extinit.c ext\extinit.$(OBJEXT) ext\vc*.pdb miniruby.lib
$(Q)$(RM) $(RUBY_INSTALL_NAME).res $(RUBYW_INSTALL_NAME).res $(RUBY_SO_NAME).res
$(Q)$(RM) miniruby.rc $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc
- $(Q)$(RM) *.map *.pdb *.ilk *.exp $(RUBYDEF) ext\ripper\y.output
+ $(Q)$(RM) *.map *.pdb *.ilk *.exp *.dll $(RUBYDEF) ext\ripper\y.output
+
+clean-local:: clean-prism
+
+clean-prism:
+ @for /R $(PRISM_BUILD_DIR:/=\) %I in (.time) do @(del /q %I && $(RMDIRS) %~pI) 2> nul || $(NULLCMD)
distclean-local::
- $(Q)$(RM) ext\config.cache $(RBCONFIG:/=\) $(CONFIG_H:/=\)
+ $(Q)$(RM) ext\config.cache $(RBCONFIG:/=\) $(CONFIG_H:/=\) miniprelude.c
-$(Q)$(RM) $(INSTALLED_LIST:/=\) $(arch_hdrdir:/=\)\ruby\config.h verconf.h
-$(Q)$(RMDIRS) $(arch_hdrdir:/=\)\ruby
-$(Q)$(RMDIR) win32
+distclean-local:: clean-srcs-local
+distclean-ext:: clean-srcs-ext
+
+distclean-local:: distclean-prism
+
+distclean-prism: clean-prism
+!if "$(srcdir)" != "."
+ $(Q)for %I in ( \
+ $(PRISM_SRCDIR:/=\)\templates\ext\prism\*.c.erb \
+ $(PRISM_SRCDIR:/=\)\templates\include\prism\*.h.erb \
+ $(PRISM_SRCDIR:/=\)\templates\src\*.c.erb \
+ ) do $(Q)(del /q prism\%~nI 2> nul || $(NULLCMD))
+ $(Q)for /D %I in (prism\*) do $(Q)$(RMDIRS) %I
+ $(Q)$(RMDIRS) prism
+!endif
+
+realclean-prism: distclean-prism
+!if "$(srcdir)" == "."
+ $(Q)for %I in ( \
+ $(PRISM_SRCDIR:/=\)\templates\ext\prism\*.c.erb \
+ $(PRISM_SRCDIR:/=\)\templates\include\prism\*.h.erb \
+ $(PRISM_SRCDIR:/=\)\templates\src\*.c.erb \
+ ) do $(Q)(del /q $(PRISM_SRCDIR:/=\)\%~nI 2> nul || $(NULLCMD))
+!endif
+
.bundle/clean:: .bundle/clean.sub
.bundle/distclean:: .bundle/distclean.sub
.bundle/realclean:: .bundle/realclean.sub
@@ -1285,7 +1225,7 @@ distclean-local::
.bundle/realclean.sub:: ext/realclean.mk
ext/clean.mk ext/distclean.mk ext/realclean.mk::
- $(Q)if exist $(EXTS_MK) $(MAKE) -k -f $(EXTS_MK) top_srcdir=$(srcdir) $(*F)
+ $(Q)if exist $(EXTS_MK) $(MAKE) $(MFLAGS) -k -f $(EXTS_MK) top_srcdir=$(srcdir) $(*F)
ext/clean.sub ext/distclean.sub ext/realclean.sub \
.bundle/clean.sub .bundle/distclean.sub .bundle/realclean.sub::
@@ -1295,16 +1235,18 @@ ext/clean.sub ext/distclean.sub ext/realclean.sub \
call set n=%I && \
call set n=%n:%CD%\$(@D)\=% && \
call set n=%n:\.=% && \
- call echo $(@F)ing %n:\=/% & \
- $(MAKE) $(MFLAGS) $(@F) & \
+ call echo $(@F:.sub=)ing %n:\=/% & \
+ $(MAKE) $(MFLAGS) $(@F:.sub=) & \
cd %CD% & \
$(RMDIRS) %I \
- ))) || @
+ ))) || $(NULLCMD)
ext/distclean ext/realclean .bundle/distclean .bundle/realclean::
- $(Q)cd $(@D) 2>nul && (for /R $(EXTS) %I in (exts.mk*) \
- do $(Q)(del %I & rmdir %~dpI)) || @
- -$(Q)rmdir $(@D) 2> nul || @
+ $(Q)(for /D /R $(@D) %I in (.) do $(Q)$(RMDIRS) %I) || $(NULLCMD)
+
+.bundle/distclean .bundle/realclean::
+ $(Q)for /D %I in ($(@D)\*) do $(Q)$(RMDIRS) %I || $(NULLCMD)
+ -$(Q)rmdir $(@D) 2> nul || $(NULLCMD)
.bundle/realclean::
@$(RMALL) $(tooldir)/bunlder/*.lock $(srcdir)/.bundle
@@ -1329,7 +1271,7 @@ $(RCFILES): $(RBCONFIG) $(srcdir)/revision.h $(srcdir)/win32/resource.rb
update-benchmark-driver:
$(GIT) clone https://github.com/benchmark-driver/benchmark-driver $(srcdir)/benchmark/benchmark-driver || \
- $(GIT) -C $(srcdir)/benchmark/benchmark-driver pull origin master
+ $(GIT_IN_SRC)/benchmark/benchmark-driver pull origin master
$(ruby_pc): $(RBCONFIG)
@$(BOOTSTRAPRUBY) $(tooldir)/expand-config.rb \
@@ -1468,8 +1410,20 @@ loadpath: verconf.h
sed -e '1,/^const char ruby_initial_load_paths/d;/;/,$$d' \
-e '/^^ /!d;s/ *"\\\\0"$$//;s/" *"//g'
-RUBYSPEC_CAPIEXT_SRCDIR = $(srcdir)/$(RUBYSPEC_CAPIEXT)
-RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY)
+!if [exit > rbincs.mk]
+!else if [for %I in ($(BUILTIN_RB_SRCS)) do \
+ @for %J in (\
+"%~nI.rbinc: %I $$(tooldir)/mk_builtin_loader.rb $$(DUMP_AST_TARGET)" \
+" $$(ECHO) making $$@" \
+" $$(Q) $$(BASERUBY) $$(tooldir)/mk_builtin_loader.rb $$(DUMP_AST) %I" \
+"" \
+) do @echo.%~J>>rbincs.mk]
+!else
+! include rbincs.mk
+! if [del rbincs.mk > nul]
+! endif
+!endif
+
RUBYSPEC_CAPIEXT_EXTS =
!if [echo>rubyspec-capiext.mk RUBYSPEC_CAPIEXT_EXTS = \]
@@ -1484,23 +1438,16 @@ RUBYSPEC_CAPIEXT_EXTS =
$(RUBYSPEC_CAPIEXT_EXTS): $(RUBYSPEC_CAPIEXT_DEPS)
rubyspec-capiext: $(RUBYSPEC_CAPIEXT_EXTS)
- @ $(NULLCMD)
{$(RUBYSPEC_CAPIEXT_SRCDIR)}.c{$(RUBYSPEC_CAPIEXT)}.so:
$(ECHO) building $(@F)
$(Q)$(MAKEDIRS) $(@D)
$(Q)(echo EXPORTS&&echo Init_$(*F))> $*.def
$(Q)$(LDSHARED) -Fe$(@) -Fo$(*).obj $(INCFLAGS) $(CFLAGS) $(CPPFLAGS) $< $(LIBRUBYARG) -link $(DLDFLAGS) $(XLDFLAGS) $(LIBS) $(LOCAL_LIBS) -implib:$*.lib -pdb:$*.pdb -def:$*.def
-!if defined(LDSHARED_0)
- $(Q)$(LDSHARED_0)
- $(Q)$(LDSHARED_1)
- $(Q)$(LDSHARED_2)
-!endif
$(Q)$(RM) $*.def $*.exp $*.lib $*.obj $*.pdb
-exts: rubyspec-capiext
-
yesterday:
+ (set TZ=UTC-9) && \
for /f "usebackq" %H in \
- (`$(GIT) -C $(srcdir) log -1 "--before=00:00+0900" "--format=%H"`) do \
- $(GIT) -C $(srcdir) reset --hard %%H
+ (`$(GIT_LOG_FORMAT)%H -1 "--before=00:00"`) do \
+ $(GIT_IN_SRC) reset --hard %%H
diff --git a/win32/configure.bat b/win32/configure.bat
index bad09cd3f5..e8d6b5f95b 100755..100644
--- a/win32/configure.bat
+++ b/win32/configure.bat
@@ -1,272 +1,260 @@
@echo off
-@setlocal disabledelayedexpansion
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
set PROMPT=$E[94m+$E[m$S
-set witharg=
+goto :main
-for %%I in (%0) do if /%%~dpI/ == /%CD%\/ (
+:set
+set %*
+exit /b
+
+:shift
+call %~dp0shellsplit.cmd
+set "argv1=%argv2%"
+set "argv2=%argv%"
+if not defined argv1 if defined argv2 goto :shift
+exit /b
+
+:take_arg
+if defined arg exit /b
+if not defined argv2 exit /b
+if not "%argv2:~0,1%"=="-" (set "arg=%argv2%" & call :shift)
+exit /b
+
+:main
+if "%~dp0" == "%CD%\" (
echo don't run in win32 directory.
exit /b 999
+) else if "%~0" == "%~nx0" (
+ set "WIN32DIR=%~$PATH:0"
+) else if "%~0" == "%~n0" (
+ set "WIN32DIR=%~$PATH:0"
+) else (
+ set "WIN32DIR=%~0"
)
-set XINCFLAGS=
-set XLDFLAGS=
+set "WIN32DIR=%WIN32DIR:\=/%:/:"
+call :set "WIN32DIR=%%WIN32DIR:%~x0:/:=:/:%%"
+call :set "WIN32DIR=%%WIN32DIR:/%~n0:/:=:/:%%"
+set "WIN32DIR=%WIN32DIR:~0,-3%"
-set conf=%0
+set configure=%~0
+set args=%*
+set target=
+set optdirs=
set pathlist=
set config_make=confargs~%RANDOM%.mak
-set confargs=%config_make:.mak=.c%
+set confargs=%config_make:.mak=.sub%
+set debug_configure=
echo>%config_make% # CONFIGURE
-(
- echo #define $ $$ //
- echo !ifndef CONFIGURE_ARGS
- echo #define CONFIGURE_ARGS \
-) >%confargs%
+type nul > %confargs%
:loop
-set opt=%1
-if "%1" == "" goto :end
-if "%1" == "--debug-configure" (echo on & shift & goto :loop)
-if "%1" == "--no-debug-configure" (echo off & shift & goto :loop)
-if "%1" == "--prefix" goto :prefix
-if "%1" == "--srcdir" goto :srcdir
-if "%1" == "srcdir" goto :srcdir
-if "%1" == "--target" goto :target
-if "%1" == "target" goto :target
-if "%1" == "--with-static-linked-ext" goto :extstatic
-if "%1" == "--program-prefix" goto :pprefix
-if "%1" == "--program-suffix" goto :suffix
-if "%1" == "--program-transform-name" goto :transform_name
-if "%1" == "--program-name" goto :installname
-if "%1" == "--install-name" goto :installname
-if "%1" == "--so-name" goto :soname
-if "%1" == "--enable-install-doc" goto :enable-rdoc
-if "%1" == "--disable-install-doc" goto :disable-rdoc
-if "%1" == "--enable-install-static-library" goto :enable-lib
-if "%1" == "--disable-install-static-library" goto :disable-lib
-if "%1" == "--enable-debug-env" goto :enable-debug-env
-if "%1" == "--disable-debug-env" goto :disable-debug-env
-if "%1" == "--enable-devel" goto :enable-devel
-if "%1" == "--disable-devel" goto :disable-devel
-if "%1" == "--enable-rubygems" goto :enable-rubygems
-if "%1" == "--disable-rubygems" goto :disable-rubygems
-if "%1" == "--extout" goto :extout
-if "%1" == "--path" goto :path
-if "%1" == "--with-baseruby" goto :baseruby
-if "%1" == "--without-baseruby" goto :baseruby
-if "%1" == "--with-ntver" goto :ntver
-if "%1" == "--with-libdir" goto :libdir
-if "%1" == "--with-git" goto :git
-if "%1" == "--without-git" goto :nogit
-if "%1" == "--without-ext" goto :witharg
-if "%1" == "--without-extensions" goto :witharg
-if "%1" == "--with-opt-dir" goto :opt-dir
-if "%1" == "--with-gmp" goto :gmp
-if "%1" == "--with-gmp-dir" goto :gmp-dir
-if "%opt:~0,10%" == "--without-" goto :withoutarg
-if "%opt:~0,7%" == "--with-" goto :witharg
-if "%1" == "-h" goto :help
-if "%1" == "--help" goto :help
+call :shift
+if not defined argv1 goto :end
+for /f "delims== tokens=1,*" %%I in (" %argv1% ") do ((set "opt=%%I") && (set "arg=%%J"))
+ set "opt=%opt:~1%"
+ if defined arg (
+ set "eq=="
+ set "arg=%arg:~0,-1%"
+ ) else (
+ set "eq="
+ set "opt=%opt:~0,-1%"
+ )
+ if "%opt%"=="" (
+ echo 1>&2 %configure%: assignment for empty variable name %argv1%
+ exit /b 1
+ )
+ if "%opt%" == "--debug-configure" (
+ echo on
+ set "debug_configure=yes"
+ goto :loop ;
+ )
+ if "%opt%" == "--no-debug-configure" (
+ echo off
+ set "debug_configure="
+ goto :loop ;
+ )
+ if "%opt%" == "--prefix" goto :dir
+ if "%opt%" == "srcdir" set "opt=--srcdir"
+ if "%opt%" == "--srcdir" goto :dir
+ if "%opt%" == "--target" goto :target
+ if "%opt%" == "target" goto :target
+ if "%opt:~0,10%" == "--program-" goto :program_name
+ if "%opt%" == "--install-name" (set "var=RUBY_INSTALL_NAME" & goto :name)
+ if "%opt%" == "--so-name" (set "var=RUBY_SO_NAME" & goto :name)
+ if "%opt%" == "--extout" goto :extout
+ if "%opt%" == "--path" goto :path
+ if "%opt:~0,9%" == "--enable-" (set "enable=yes" & goto :enable)
+ if "%opt:~0,10%" == "--disable-" (set "enable=no" & goto :enable)
+ if "%opt:~0,10%" == "--without-" goto :withoutarg
+ if "%opt:~0,7%" == "--with-" goto :witharg
+ if "%opt%" == "-h" goto :help
+ if "%opt%" == "--help" goto :help
if "%opt:~0,1%" == "-" (
- echo>>%confargs% %1 \
- set witharg=
- ) else if "%witharg%" == "" (
- echo>>%confargs% %1 \
+ goto :unknown_opt
+ )
+ if "%eq%" == "=" (
+ set "var=%opt%"
+ goto :name
+ )
+ set "arg=%opt%"
+ set "eq=="
+ set "opt=--target"
+ set "target=%arg%"
+:loopend
+ if not "%arg%" == "" (
+ echo>>%confargs% "%opt%=%arg:$=$$%" \
) else (
- echo>>%confargs% ,%1\
+ echo>>%confargs% "%opt%%eq%" \
)
- shift
-goto :loop ;
-:srcdir
- echo>> %config_make% srcdir = %~2
- echo>>%confargs% --srcdir=%2 \
- shift
- shift
-goto :loop ;
-:prefix
- echo>> %config_make% prefix = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
-:pprefix
- echo>> %config_make% PROGRAM_PREFIX = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
-:suffix
- echo>> %config_make% PROGRAM_SUFFIX = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
-:installname
- echo>> %config_make% RUBY_INSTALL_NAME = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
-:soname
- echo>> %config_make% RUBY_SO_NAME = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
-:transform_name
-
- shift
- shift
goto :loop ;
:target
- echo>> %config_make% target = %~2
- echo>>%confargs% --target=%2 \
- if "%~2" == "x64-mswin64" (
- echo>> %config_make% TARGET_OS = mswin64
+ if "%eq%" == "" call :take_arg
+ if "%arg%" == "" (
+ echo 1>&2 %configure%: missing argument for %opt%
+ exit /b 1
)
- shift
- shift
-goto :loop ;
-:extstatic
- echo>> %config_make% EXTSTATIC = static
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:enable-rdoc
- echo>> %config_make% RDOCTARGET = rdoc
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:disable-rdoc
- echo>> %config_make% RDOCTARGET = nodoc
- echo>>%confargs% %1 \
- shift
+ set "target=%arg%"
+ set "opt=--target"
+ echo>>%confargs% "--target=%arg:$=$$%" \
goto :loop ;
-:enable-lib
- echo>> %config_make% INSTALL_STATIC_LIBRARY = yes
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:disable-lib
- echo>> %config_make% INSTALL_STATIC_LIBRARY = no
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:enable-debug-env
- echo>> %config_make% ENABLE_DEBUG_ENV = yes
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:disable-debug-env
- echo>> %config_make% ENABLE_DEBUG_ENV = no
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:enable-devel
- echo>> %config_make% RUBY_DEVEL = yes
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:disable-devel
- echo>> %config_make% RUBY_DEVEL = no
- echo>>%confargs% %1 \
- shift
-goto :loop ;
-:enable-rubygems
- echo>> %config_make% USE_RUBYGEMS = yes
- echo>>%confargs% %1 \
- shift
+:program_name
+ for /f "delims=- tokens=1,*" %I in ("%opt%") do set "var=%%J"
+ if "%var%" == "prefix" (set "var=PROGRAM_PREFIX" & goto :name)
+ if "%var%" == "suffix" (set "var=PROGRAM_SUFFIX" & goto :name)
+ if "%var%" == "name" (set "var=RUBY_INSTALL_NAME" & goto :name)
+ if "%var%" == "transform-name" (
+ echo.1>&2 %configure%: --program-transform-name option is not supported
+ exit /b 1
+ )
+goto :unknown_opt
+:name
+ if "%eq%" == "" call :take_arg
+ echo>> %config_make% %var% = %arg%
+goto :loopend ;
+:dir
+ if "%eq%" == "" call :take_arg
+ if defined arg set "arg=%arg:\=/%"
+ echo>> %config_make% %opt:~2% = %arg%
+goto :loopend ;
+:enable
+ if %enable% == yes (
+ if "%eq%" == "" call :take_arg
+ set "feature=%opt:~9%"
+ ) else (
+ set "feature=%opt:~10%"
+ )
+ if %enable% == yes if defined arg (set "enable=%arg%")
+ if "%feature%" == "install-doc" (
+ echo>> %config_make% RDOCTARGET = %enable:yes=r%doc
+ )
+ if "%feature%" == "install-static-library" (
+ echo>> %config_make% INSTALL_STATIC_LIBRARY = %enable%
+ )
+ if "%feature%" == "debug-env" (
+ echo>> %config_make% ENABLE_DEBUG_ENV = %enable%
+ )
+ if "%feature%" == "devel" (
+ echo>> %config_make% RUBY_DEVEL = %enable%
+ )
+ if "%feature%" == "rubygems" (
+ echo>> %config_make% USE_RUBYGEMS = %enable%
+ )
+goto :loopend ;
+:withoutarg
+ echo>>%confargs% "%opt%" \
+ if "%opt%" == "--without-baseruby" goto :nobaseruby
+ if "%opt%" == "--without-git" goto :nogit
+ if "%opt%" == "--without-ext" goto :witharg
+ if "%opt%" == "--without-extensions" goto :witharg
goto :loop ;
-:disable-rubygems
- echo>> %config_make% USE_RUBYGEMS = no
- echo>>%confargs% %1 \
- shift
+:witharg
+ if "%opt%" == "--with-static-linked-ext" goto :extstatic
+ if "%eq%" == "" call :take_arg
+ if not "%arg%" == "" (
+ echo>>%confargs% "%opt%=%arg:$=$$%" \
+ ) else (
+ echo>>%confargs% "%opt%%eq%" \
+ )
+ if "%opt%" == "--with-baseruby" goto :baseruby
+ if "%opt%" == "--with-ntver" goto :ntver
+ if "%opt%" == "--with-libdir" goto :libdir
+ if "%opt%" == "--with-git" goto :git
+ if "%opt%" == "--with-opt-dir" goto :opt-dir
+ if "%opt%" == "--with-gmp-dir" goto :opt-dir
+ if "%opt%" == "--with-gmp" goto :gmp
+ if "%opt%" == "--with-destdir" goto :destdir
+ if "%opt%" == "--with-dump-ast" goto :dump-ast
goto :loop ;
:ntver
::- For version constants, see
::- https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt#remarks
- set NTVER=%~2
+ if "%eq%" == "" (set "NTVER=%~1" & call :shift) else (set "NTVER=%arg%")
if /i not "%NTVER:~0,2%" == "0x" if /i not "%NTVER:~0,13%" == "_WIN32_WINNT_" (
for %%i in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
- call set NTVER=%%NTVER:%%i=%%i%%
+ call :set NTVER=%%NTVER:%%i=%%i%%
)
- call set NTVER=_WIN32_WINNT_%%NTVER%%
+ call :set NTVER=_WIN32_WINNT_%%NTVER%%
)
echo>> %config_make% NTVER = %NTVER%
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
+goto :loopend ;
:extout
- if not "%~2" == ".ext" (echo>> %config_make% EXTOUT = %~2)
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
+ if "%eq%" == "" call :take_arg
+ if not "%arg%" == ".ext" (echo>> %config_make% EXTOUT = %arg%)
+goto :loopend ;
:path
- set pathlist=%pathlist%%~2;
- echo>>%confargs% %1=%2 \
- shift
- shift
-goto :loop ;
+ if "%eq%" == "" call :take_arg
+ set "pathlist=%pathlist%%arg:\=/%;"
+goto :loopend ;
+:extstatic
+ if "%eq%" == "" (set "arg=static")
+ echo>> %config_make% EXTSTATIC = %arg%
+goto :loopend ;
:baseruby
- echo>> %config_make% BASERUBY = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
+ echo>> %config_make% HAVE_BASERUBY = yes
+ echo>> %config_make% BASERUBY = %arg%
goto :loop ;
:nobaseruby
echo>> %config_make% HAVE_BASERUBY = no
- echo>>%confargs% %1=%2 \
- shift
+ echo>> %config_make% BASERUBY =
goto :loop ;
:libdir
- echo>> %config_make% libdir_basename = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
+ echo>> %config_make% libdir_basename = %arg%
goto :loop ;
:git
- echo>> %config_make% GIT = %~2
- echo>>%confargs% %1=%2 \
- shift
- shift
+ echo>> %config_make% GIT = %arg%
goto :loop ;
:nogit
echo>> %config_make% GIT = never-use
echo>> %config_make% HAVE_GIT = no
- echo>>%confargs% %1 \
- shift
goto :loop ;
:gmp
echo>> %config_make% WITH_GMP = yes
- echo>>%confargs% %1=1 \
- shift
- shift
goto :loop ;
-:gmp-dir
+:destdir
+ echo>> %config_make% DESTDIR = %arg%
+goto :loop ;
+:dump-ast
+ echo>> %config_make% DUMP_AST = %arg%
+goto :loop ;
:opt-dir
- set opt=%~2
- for %%I in (%opt:;= %) do (
- set d=%%I
- call pushd %%d:/=\%% && (
- call set XINCFLAGS=%%XINCFLAGS%% -I%%CD:\=/%%/include
- call set XLDFLAGS=%%XLDFLAGS%% -libpath:%%CD:\=/%%/lib
+ if "%arg%" == "" (
+ echo 1>&2 %configure%: missing argument for %opt%
+ exit /b 1
+ )
+ :optdir-loop
+ for /f "delims=; tokens=1,*" %%I in ("%arg%") do (set "d=%%I" & set "arg=%%J")
+ pushd %d:/=\% 2> nul && (
+ call :set "optdirs=%optdirs%;%%CD:\=/%%"
popd
+ ) || (
+ set "optdirs=%optdirs%;%d:\=/%"
)
- )
-:witharg
- echo>>%confargs% %1=%2\
- set witharg=1
- shift
- shift
-goto :loop ;
-:withoutarg
- echo>>%confargs% %1 \
- shift
+ if not "%arg%" == "" goto :optdir-loop
goto :loop ;
:help
echo Configuration:
echo --help display this help
- echo --srcdir=DIR find the sources in DIR [configure dir or `..']
+ echo --srcdir=DIR find the sources in DIR [configure dir or '..']
echo Installation directories:
echo --prefix=PREFIX install files in PREFIX [/usr]
echo System types:
@@ -276,47 +264,50 @@ goto :loop ;
echo --with-static-linked-ext link external modules statically
echo --with-ext="a,b,..." use extensions a, b, ...
echo --without-ext="a,b,..." ignore extensions a, b, ...
- echo --with-opt-dir="DIR-LIST" add optional headers and libraries directories separated by `;'
+ echo --with-opt-dir="DIR-LIST" add optional headers and libraries directories separated by ';'
echo --disable-install-doc do not install rdoc indexes during install
echo --with-ntver=0xXXXX target NT version (shouldn't use with old SDK)
echo --with-ntver=_WIN32_WINNT_XXXX
echo --with-ntver=XXXX same as --with-ntver=_WIN32_WINNT_XXXX
- echo Note that `,' and `;' need to be enclosed within double quotes in batch file command line.
+ echo Note that parameters containing spaces must be enclosed within double quotes.
del %confargs% %config_make%
-goto :exit
+goto :EOF
+:unknown_opt
+ (
+ echo %configure%: unknown option %opt%
+ echo Try --help option.
+ ) 1>&2
+ exit /b 1
:end
+if "%debug_configure%" == "yes" (type %confargs%)
+if defined optdirs (echo>>%config_make% optdirs = %optdirs:~1%)
(
- echo //
- echo configure_args = CONFIGURE_ARGS
- echo !endif
- echo #undef $
-) >> %confargs%
-(
- cl -EP %confargs% 2>nul | findstr "! ="
echo.
- if NOT "%XINCFLAGS%" == "" echo XINCFLAGS = %XINCFLAGS%
- if NOT "%XLDFLAGS%" == "" echo XLDFLAGS = %XLDFLAGS%
- if NOT "%pathlist%" == "" (
+ echo configure_args = \
+ type %confargs%
+ echo # configure_args
+
+ echo.
+ echo !if "$(optdirs)" != ""
+ for %%I in ("$(optdirs:\=/)" "$(optdirs:/;=;)") do @echo optdirs = %%~I
+ echo XINCFLAGS = -I"$(optdirs:;=/include" -I")/include"
+ echo XLDFLAGS = -libpath:"$(optdirs:;=/lib" -libpath:")/lib"
+ echo !endif
+
+ if not "%pathlist%" == "" (
+ echo.
call echo PATH = %%pathlist:;=/bin;%%$^(PATH^)
call echo INCLUDE = %%pathlist:;=/include;%%$^(INCLUDE^)
call echo LIB = %%pathlist:;=/lib;%%$^(LIB^)
)
) >> %config_make%
-del %confargs% > nul
-set setup_make=%config_make:confargs=setup%
-(
- echo #### -*- makefile -*-
- echo conf = %conf%
- echo $^(conf^): nul
- echo @del %setup_make%
- echo @$^(MAKE^) -l$^(MAKEFLAGS^) -f $^(@D^)/setup.mak \
- echo WIN32DIR=$^(@D:\=/^) config_make=%config_make%
- echo -@move /y Makefile Makefile.old ^> nul 2^> nul
- echo @ren Makefile.new Makefile
-) > %setup_make%
-nmake -alf %setup_make% MAKEFILE=Makefile.new
+del %confargs%
+if "%debug_configure%" == "yes" (type %config_make%)
-exit /b %ERRORLEVEL%
-:exit
-@endlocal
+nmake -al -f %WIN32DIR%/setup.mak "WIN32DIR=%WIN32DIR%" ^
+ config_make=%config_make% ^
+ MAKEFILE=Makefile.new MAKEFILE_BACK=Makefile.old MAKEFILE_NEW=Makefile ^
+ %target%
+set error=%ERRORLEVEL%
+if exist %config_make% del /q %config_make%
diff --git a/win32/enc-setup.mak b/win32/enc-setup.mak
index 44345a2f45..b012161e32 100644
--- a/win32/enc-setup.mak
+++ b/win32/enc-setup.mak
@@ -4,7 +4,7 @@ BUILTIN_ENCOBJS BUILTIN_TRANSOBJS: $(srcdir)/enc/Makefile.in
!include $(srcdir)/enc/Makefile.in
BUILTIN_ENCOBJS:
- @echo BUILTIN_ENCOBJS = $(BUILTIN_ENCS:.c=.obj) >> $(MAKEFILE)
+ @echo>> $(MAKEFILE) BUILTIN_ENCOBJS = $(BUILTIN_ENCS:.c=.obj)
BUILTIN_TRANSOBJS:
- @echo BUILTIN_TRANSOBJS = $(BUILTIN_TRANSES:.trans=.obj) >> $(MAKEFILE)
+ @echo>> $(MAKEFILE) BUILTIN_TRANSOBJS = $(BUILTIN_TRANSES:.trans=.obj)
diff --git a/win32/file.c b/win32/file.c
index f137f04c43..26b99715cd 100644
--- a/win32/file.c
+++ b/win32/file.c
@@ -629,14 +629,10 @@ rb_freopen(VALUE fname, const char *mode, FILE *file)
len = MultiByteToWideChar(CP_UTF8, 0, name, n, wname, len);
wname[len] = L'\0';
RB_GC_GUARD(fname);
-#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__WFREOPEN_S)
- e = _wfreopen(wname, wmode, file) ? 0 : errno;
-#else
{
FILE *newfp = 0;
e = _wfreopen_s(&newfp, wname, wmode, file);
}
-#endif
ALLOCV_END(wtmp);
return e;
}
diff --git a/win32/ifchange.bat b/win32/ifchange.bat
index 1de98f9990..f3fc9ea37c 100755
--- a/win32/ifchange.bat
+++ b/win32/ifchange.bat
@@ -1,54 +1,80 @@
@echo off
:: usage: ifchange target temporary
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+
+:: @set PROMPT=$T:$S
for %%I in (%0) do set progname=%%~nI
set timestamp=
set keepsuffix=
set empty=
set color=auto
:optloop
+set optarg=
+:optnext
for %%I in (%1) do set opt=%%~I
-if "%opt%" == "--" (
- shift
-) else if "%opt%" == "--timestamp" (
- set timestamp=.
- shift
- goto :optloop
-) else if "%opt:~0,12%" == "--timestamp=" (
- set timestamp=%opt:~12%
- shift
- goto :optloop
-) else if "%opt%" == "--keep" (
- set keepsuffix=.old
- shift
- goto :optloop
-) else if "%opt:~0,7%" == "--keep=" (
- set keepsuffix=%opt:~7%
- shift
- goto :optloop
-) else if "%opt%" == "--empty" (
- set empty=yes
- shift
- goto :optloop
-) else if "%opt%" == "--color" (
- set color=always
- shift
- goto :optloop
-) else if "%opt:~0,8%" == "--color=" (
- set color=%opt:~8%
- shift
- goto :optloop
-) else if "%opt%" == "--debug" (
- shift
- echo on
- goto :optloop
-) else if "%opt%" == "--help" (
- call :help
- exit /b
-) else if "%opt:~0,2%" == "--" (
+ if not "%opt:~0,2%" == "--" (
+ if not "%optarg%" == "" (
+ call set %optarg%=%%opt%%
+ shift
+ goto :optloop
+ )
+ goto :optend
+ )
+ if "%opt%" == "--" (
+ shift
+ goto :optend
+ )
+ if "%opt%" == "--timestamp" (
+ set timestamp=.
+ set optarg=timestamp
+ shift
+ goto :optnext
+ )
+ if "%opt:~0,12%" == "--timestamp=" (
+ set timestamp=%opt:~12%
+ shift
+ goto :optloop
+ )
+ if "%opt%" == "--keep" (
+ set keepsuffix=.old
+ set optarg=keep
+ shift
+ goto :optnext
+ )
+ if "%opt:~0,7%" == "--keep=" (
+ set keepsuffix=%opt:~7%
+ shift
+ goto :optloop
+ )
+ if "%opt%" == "--empty" (
+ set empty=yes
+ shift
+ goto :optloop
+ )
+ if "%opt%" == "--color" (
+ set color=always
+ set optarg=color
+ shift
+ goto :optnext
+ )
+ if "%opt:~0,8%" == "--color=" (
+ set color=%opt:~8%
+ shift
+ goto :optloop
+ )
+ if "%opt%" == "--debug" (
+ shift
+ echo on
+ goto :optloop
+ )
+ if "%opt%" == "--help" (
+ call :help
+ exit /b
+ )
echo %progname%: unknown option: %1 1>&2
exit /b 1
-)
+:optend
if "%2" == "" (
call :help 1>&2
@@ -60,6 +86,19 @@ set src=%2
set dest=%dest:/=\%
set src=%src:/=\%
+if not "%src%" == "-" goto :srcfile
+ if not "%TMPDIR%" == "" (
+ set src=%TMPDIR%\ifchange%RANDOM%.tmp
+ ) else if not "%TEMP%" == "" (
+ set src=%TEMP%\ifchange%RANDOM%.tmp
+ ) else if not "%TMP%" == "" (
+ set src=%TMP%\ifchange%RANDOM%.tmp
+ ) else (
+ set src=.\ifchange%RANDOM%.tmp
+ )
+ findstr -r -c:"^" > "%src%"
+:srcfile
+
if exist %dest% (
if not exist %src% goto :nt_unchanged1
if not "%empty%" == "" for %%I in (%src%) do if %%~zI == 0 goto :nt_unchanged
diff --git a/win32/install-buildtools.cmd b/win32/install-buildtools.cmd
new file mode 100755
index 0000000000..7f5e20293b
--- /dev/null
+++ b/win32/install-buildtools.cmd
@@ -0,0 +1,14 @@
+@echo off
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+
+set components=VC.Tools.x86.x64 VC.Redist.14.Latest CoreBuildTools
+set components=%components% Windows11SDK.26100
+if /i "%PROCESSOR_ARCHITECTURE%" == "ARM64" (
+ set components=%components% VC.Tools.ARM64 VC.Tools.ARM64EC
+)
+set override=--passive
+for %%I in (%components%) do (
+ call set override=%%override%% --add Microsoft.VisualStudio.Component.%%I
+)
+echo on
+winget install --id Microsoft.VisualStudio.2022.BuildTools --override "%override%"
diff --git a/win32/install-msys-packages.cmd b/win32/install-msys-packages.cmd
new file mode 100755
index 0000000000..f388de5692
--- /dev/null
+++ b/win32/install-msys-packages.cmd
@@ -0,0 +1,29 @@
+::- Install msys packages for rubygems
+::- The dependencies are taken from vcpkg.json to share the common info.
+
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b - 1
+@set PROMPT=$h$e[96m$g$e[39m$s
+@set script=%0
+@call set "srcdir=%%script:\win32\%~nx0=%%"
+
+@if not defined MINGW_PACKAGE_PREFIX (
+ ::- Enable msys environment by ridk (from RubyInstaller-DevKit)
+ where ridk >nul 2>&1 || (
+ (echo MINGW_PACKAGE_PREFIX is not set, you have to enable development environment.) 1>&2
+ exit /b 1
+ )
+ call ridk enable %*
+ echo:
+) else if not "%1" == "" (
+ ::- Switch msys environment by ridk (from RubyInstaller-DevKit)
+ call ridk enable %*
+ echo:
+)
+
+@set pkgs=
+@(
+ for /f %%I in ('powershell -c "(ConvertFrom-Json $input).dependencies"') do @(
+ call set "pkgs=%%pkgs%% %%MINGW_PACKAGE_PREFIX%%-%%%%I"
+ )
+) < "%srcdir%\vcpkg.json"
+pacman -S --needed --noconfirm %pkgs:~1%
diff --git a/win32/lastrev.bat b/win32/lastrev.bat
new file mode 100755
index 0000000000..48e5750c6e
--- /dev/null
+++ b/win32/lastrev.bat
@@ -0,0 +1,30 @@
+@echo off
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+
+if "%1" == "" (set gitdir=.) else (set gitdir=%1)
+set TZ=UTC
+for /f "usebackq tokens=1-3" %%I in (
+ `git -C "%gitdir%" log -1 --no-show-signature "--date=format-local:%%F %%T" "--format=%%H %%cd" HEAD`
+) do (
+ set rev=%%I
+ set dt=%%J
+ set tm=%%K
+)
+if not "%dt%" == "" (
+ set /a yy=%dt:-=% / 10000
+ set /a mm=%dt:-=% / 100 %% 100
+ set /a dd=%dt:-=% %% 100
+)
+for /f "usebackq tokens=1" %%I in (
+ `git -C "%gitdir%" symbolic-ref --short HEAD`
+) do set branch=%%I
+if not "%rev%" == "" (
+ echo #define RUBY_REVISION "%rev:~,10%"
+ echo #define RUBY_FULL_REVISION "%rev%"
+ echo #define RUBY_BRANCH_NAME "%branch%"
+ echo #define RUBY_RELEASE_DATETIME "%dt%T%tm%Z"
+ echo #define RUBY_RELEASE_YEAR %yy%
+ echo #define RUBY_RELEASE_MONTH %mm%
+ echo #define RUBY_RELEASE_DAY %dd%
+)
+@endlocal
diff --git a/win32/makedirs.bat b/win32/makedirs.bat
index 13740d8778..8c06d94041 100755
--- a/win32/makedirs.bat
+++ b/win32/makedirs.bat
@@ -1,3 +1,3 @@
@echo off
-setlocal EnableExtensions
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
for %%I in (%*) do if not exist "%%~I/." mkdir "%%~I"
diff --git a/win32/mkexports.rb b/win32/mkexports.rb
index 1a37c7ee91..44bda94990 100755
--- a/win32/mkexports.rb
+++ b/win32/mkexports.rb
@@ -110,6 +110,7 @@ class Exports::Mswin < Exports
case filetype
when /OBJECT/, /LIBRARY/
l.chomp!
+ next if (/^ .*\(pick any\)$/ =~ l)...true
next if /^[[:xdigit:]]+ 0+ UNDEF / =~ l
next unless /External/ =~ l
next if /(?:_local_stdio_printf_options|v(f|sn?)printf(_s)?_l)\Z/ =~ l
@@ -137,7 +138,11 @@ end
class Exports::Cygwin < Exports
def self.nm
- @@nm ||= RbConfig::CONFIG["NM"]
+ @@nm ||=
+ begin
+ require 'shellwords'
+ RbConfig::CONFIG["NM"].shellsplit
+ end
end
def exports(*)
@@ -145,7 +150,9 @@ class Exports::Cygwin < Exports
end
def each_line(objs, &block)
- IO.foreach("|#{self.class.nm} --extern-only --defined-only #{objs.join(' ')}", &block)
+ IO.popen([*self.class.nm, *%w[--extern-only --defined-only], *objs]) do |f|
+ f.each(&block)
+ end
end
def each_export(objs)
@@ -154,7 +161,7 @@ class Exports::Cygwin < Exports
re = /\s(?:(T)|[[:upper:]])\s#{symprefix}((?!#{PrivateNames}).*)$/
objdump(objs) do |l|
next if /@.*@/ =~ l
- yield $2, !$1 if re =~ l
+ yield $2.strip, !$1 if re =~ l
end
end
end
diff --git a/win32/rm.bat b/win32/rm.bat
index fefc030545..c41ebfa5ee 100755
--- a/win32/rm.bat
+++ b/win32/rm.bat
@@ -1,18 +1,64 @@
@echo off
-setlocal
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+
+set prog=%~n0
+set dryrun=
set recursive=
+set debug=
+set error=0
+set parent=
+
:optloop
if "%1" == "-f" shift
-if "%1" == "-r" (shift & set "recursive=1" & goto :optloop)
-if "%1" == "--debug" (shift & set PROMPT=$E[34m+$E[m$S & echo on & goto :optloop)
+if "%1" == "-n" (shift & set "dryrun=%1" & goto :optloop)
+if "%1" == "-r" (shift & set "recursive=%1" & goto :optloop)
+if "%1" == "--debug" (shift & set "debug=%1" & set PROMPT=$E[34m+$E[m$S & echo on & goto :optloop)
:begin
-if "%1" == "" goto :end
-set p=%1
-set p=%p:/=\%
-if exist "%p%" del /q "%p%" > nul
-if "%recursive%" == "1" for /D %%I in (%p%) do (
- rd /s /q %%I
-)
-shift
+if "%1" == "" goto :EOF
+ set p=%1
+ shift
+ set p=%p:/=\%
+ call :remove %p%
goto :begin
-:end
+
+:remove
+setlocal
+
+::- Split %1 by '?' and '*', wildcard characters
+for /f "usebackq delims=?* tokens=1*" %%I in ('%1') do (set "par=%%I" & set "sub=%%J")
+if "%sub%" == "" goto :remove_plain
+if "%sub:\=%" == "%sub%" goto :remove_plain
+ ::- Extract the first wildcard
+ set "q=%1"
+ call set "q=%%q:%par%=%%"
+ set q=%q:~0,1%
+
+ ::- `delims` chars at the beginning are removed in `for`
+ if "%sub:~0,1%" == "\" (
+ set "sub=%sub:~1%"
+ set "par=%par%%q%"
+ ) else (
+ for /f "usebackq delims=\\ tokens=1*" %%I in ('%sub%') do (set "par=%par%%q%%%I" & set "sub=%%J")
+ )
+
+ ::- Recursive search
+ for /d %%D in (%par%) do (
+ call :remove %sub% %2%%D\
+ )
+goto :remove_end
+:remove_plain
+ set p=%2%1
+ if not exist "%1" goto :remove_end
+ if not "%dryrun%" == "" (
+ echo Removing %p:\=/%
+ goto :remove_end
+ )
+ ::- Try `rd` first for symlink to a directory; `del` attemps to remove all
+ ::- files under the target directory, instead of the symlink itself.
+ (rd /q "%p%" || del /q "%p%") 2> nul && goto :remove_end
+
+ if "%recursive%" == "-r" for /D %%I in (%p%) do (
+ rd /s /q %%I || call set error=%%ERRORLEVEL%%
+ )
+:remove_end
+endlocal & set "error=%error%" & goto :EOF
diff --git a/win32/rmdirs.bat b/win32/rmdirs.bat
index 308b648322..a8abebd383 100755
--- a/win32/rmdirs.bat
+++ b/win32/rmdirs.bat
@@ -1,6 +1,9 @@
-::-*- batch -*-
@echo off
-if "%1" == "-p" shift
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+set parents=1
+:optloop
+if "%1" == "--debug" (shift & set PROMPT=$E[34m+$E[m$S & echo on & goto :optloop)
+if "%1" == "-p" (shift & (set parents=1) & goto :optloop)
:begin
if "%1" == "" goto :end
set dir=%1
@@ -12,6 +15,7 @@ if "%1" == "" goto :end
if "%dir%" == "." goto :begin
if "%dir%" == ".." goto :begin
rd "%dir%" 2> nul || goto :begin
+ if "%parents%" == "" goto :begin
:trim_sep
if not /%dir:~-1%/ == /\/ goto :trim_base
set dir=%dir:~0,-1%
diff --git a/win32/rtname.cmd b/win32/rtname.cmd
index 775e81681a..b85c6a0c7c 100755
--- a/win32/rtname.cmd
+++ b/win32/rtname.cmd
@@ -1,35 +1,36 @@
-@echo off
-set rt=
-set rtver=
-set osver=
-for /f "usebackq" %%I in (`
- dumpbin -dependents %1 ^|
- findstr -r -i -c:"\<vcruntime.*\.dll$" -c:"\<msvcr.*\.dll$"
-`) do (
- set rt=%%~nI
-)
-
-for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do @(
- ::- downcase
- call set rt=%%rt:%%i=%%i%%
-)
-
-if "%rt%" == "msvcrt" (
- call set rtver=60
-) else if "%rt:~0,5%" == "msvcr" (
- call set rtver=%%rt:msvcr=%%
- call set osver=_%%rtver%%
-) else if "%rt:~0,9%" == "vcruntime" (
- call set rtver=%%rt:vcruntime=%%
- call set osver=_%%rtver%%
-) else (
- (echo %0: %1 is not linked to msvcrt nor vcruntime) 1>&2
- exit 1
-)
-for %%I in (
- "PLATFORM = $(TARGET_OS)%osver%"
- "RT = %rt%"
- "RT_VER = %rtver%"
-) do @(
- echo %%~I
-)
+@echo off
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+set rt=
+set rtver=
+set osver=
+for /f "usebackq" %%I in (`
+ dumpbin -dependents %1 ^|
+ findstr -r -i -c:"\<vcruntime.*\.dll$" -c:"\<msvcr.*\.dll$"
+`) do (
+ set rt=%%~nI
+)
+
+for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do @(
+ ::- downcase
+ call set rt=%%rt:%%i=%%i%%
+)
+
+if "%rt%" == "msvcrt" (
+ call set rtver=60
+) else if "%rt:~0,5%" == "msvcr" (
+ call set rtver=%%rt:msvcr=%%
+ call set osver=_%%rtver%%
+) else if "%rt:~0,9%" == "vcruntime" (
+ call set rtver=%%rt:vcruntime=%%
+ call set osver=_%%rtver%%
+) else (
+ (echo %0: %1 is not linked to msvcrt nor vcruntime) 1>&2
+ exit 1
+)
+for %%I in (
+ "PLATFORM = $(TARGET_OS)%osver%"
+ "RT = %rt%"
+ "RT_VER = %rtver%"
+) do @(
+ echo %%~I
+)
diff --git a/win32/setup.mak b/win32/setup.mak
index 275ccda3bb..19ace3445c 100644
--- a/win32/setup.mak
+++ b/win32/setup.mak
@@ -24,6 +24,9 @@ MAKEFILE = Makefile
CPU = PROCESSOR_LEVEL
CC = $(CC) -nologo
CPP = $(CC) -EP
+!if "$(HAVE_BASERUBY)" != "no" && "$(BASERUBY)" == ""
+BASERUBY = ruby
+!endif
all: -prologue- -generic- -epilogue-
i386-mswin32: -prologue- -i386- -epilogue-
@@ -32,13 +35,14 @@ i586-mswin32: -prologue- -i586- -epilogue-
i686-mswin32: -prologue- -i686- -epilogue-
alpha-mswin32: -prologue- -alpha- -epilogue-
x64-mswin64: -prologue- -x64- -epilogue-
+arm64-mswin64: -prologue- -arm64- -epilogue-
--prologue-: -basic-vars-
+-prologue-: -basic-vars- -baseruby- -gmp-
-generic-: -osname-
-basic-vars-: nul
- @type << > $(MAKEFILE)
-### Makefile for ruby $(TARGET_OS) ###
+ @rem <<$(MAKEFILE)
+### Makefile for ruby ###
MAKE = nmake
srcdir = $(srcdir:\=/)
prefix = $(prefix:\=/)
@@ -46,9 +50,13 @@ prefix = $(prefix:\=/)
<<
@type $(config_make) >>$(MAKEFILE)
@del $(config_make) > nul
-!if defined(BASERUBY)
- $(BASERUBY:/=\) "$(srcdir)/tool/missing-baseruby.bat"
+
+-baseruby-: nul
+!if "$(HAVE_BASERUBY)" != "no"
+ @cd $(srcdir:/=\)\tool && $(BASERUBY:/=\) missing-baseruby.bat --verbose || exit $(HAVE_BASERUBY:yes=non-)0
!endif
+
+-gmp-:
!if "$(WITH_GMP)" != "no"
@($(CC) $(XINCFLAGS) <<conftest.c -link $(XLDFLAGS) gmp.lib > nul && (echo USE_GMP = yes) || exit /b 0) >>$(MAKEFILE)
#include <gmp.h>
@@ -63,20 +71,31 @@ int main(void) {mpz_init(x); return 0;}
@echo # TARGET>>$(MAKEFILE)
-osname32-: -osname-section-
- @echo TARGET_OS = mswin32>>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking if target OS is 32bit" >>$(MAKEFILE)
+#ifdef _WIN64
+#error
+#else
+TARGET_OS = mswin32
+#endif
+<<
-osname64-: -osname-section-
- @echo TARGET_OS = mswin64>>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking if target OS is 64bit" >>$(MAKEFILE)
+#ifndef _WIN64
+#error
+#else
+TARGET_OS = mswin64
+#endif
+<<
-osname-: -osname-section-
- @echo !ifndef TARGET_OS>>$(MAKEFILE)
- @($(CC) -c <<conftest.c > nul && (echo TARGET_OS = mswin32) || (echo TARGET_OS = mswin64)) >>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking for target OS" 2>nul | findstr = >>$(MAKEFILE)
#ifdef _WIN64
-#error
+TARGET_OS = mswin64
+#else
+TARGET_OS = mswin32
#endif
<<
- @echo !endif>>$(MAKEFILE)
- @$(WIN32DIR:/=\)\rm.bat conftest.*
-compiler-: -compiler-section- -version- -runtime- -headers-
@@ -143,8 +162,8 @@ main(void)
<<
@( \
$(CC) -O2 $@.c && .\$@ || \
- set bug=%ERRORLEVEL% \
- echo This compiler has an optimization bug \
+ (set bug=%ERRORLEVEL% & \
+ echo This compiler has an optimization bug) \
) & $(WIN32DIR:/=\)\rm.bat $@.* & exit /b %bug%
-version-: nul verconf.mk
@@ -188,39 +207,70 @@ echo TEENY = RUBY_VERSION_TEENY
echo ABI_VERSION = RUBY_ABI_VERSION
#endif
set /a MSC_VER = _MSC_VER
-#if _MSC_VER >= 1920
+#ifndef _MSC_VER
+# error _MSC_VER not defined
+#elif _MSC_VER >= 1920
set /a MSC_VER_LOWER = MSC_VER/20*20+0
set /a MSC_VER_UPPER = MSC_VER/20*20+19
#elif _MSC_VER >= 1900
set /a MSC_VER_LOWER = MSC_VER/10*10+0
set /a MSC_VER_UPPER = MSC_VER/10*10+9
+#elif _MSC_VER < 1400
+# error Unsupported VC++ compiler
#endif
set MSC_VER
del %0 & exit
<<
-generic-: nul
- @$(CPP) <<conftest.c 2>nul | findstr = >>$(MAKEFILE)
+ @$(CPP) -Tc <<checking-target 2>nul | findstr = >>$(MAKEFILE)
#if defined _M_ARM64
MACHINE = arm64
#elif defined _M_X64
MACHINE = x64
#else
MACHINE = x86
-#endif
-<<
!if defined($(CPU))
- @echo>>$(MAKEFILE) $(CPU) = $(PROCESSOR_LEVEL)
+$(CPU) = $(PROCESSOR_LEVEL)
!endif
+#endif
-alpha-: -osname32-
- @echo MACHINE = alpha>>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking if compiler is for $(@:-=)" >>$(MAKEFILE)
+#ifndef _M_ALPHA
+#error Not compiler for $(@:-=)
+#else
+MACHINE = $(@:-=)
+#endif
+<<
+
-x64-: -osname64-
- @echo MACHINE = x64>>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking if compiler is for $(@:-=)" >>$(MAKEFILE)
+#ifndef _M_AMD64
+#error Not compiler for $(@:-=)
+#else
+MACHINE = $(@:-=)
+#endif
+<<
+
-ix86-: -osname32-
- @echo MACHINE = x86>>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking if compiler is for $(@:-=)" >>$(MAKEFILE)
+#ifndef _M_IX86
+#error Not compiler for $(@:-=)
+#else
+#define ix86 x86
+MACHINE = $(@:-=)
+#endif
+<<
+
-arm64-: -osname64-
- @echo MACHINE = arm64>>$(MAKEFILE)
+ @$(CPP) -Tc <<"checking if compiler is for $(@:-=)" >>$(MAKEFILE)
+#ifndef _M_ARM64
+#error Not compiler for $(@:-=)
+#else
+MACHINE = $(@:-=)
+#endif
+<<
-i386-: -ix86-
@echo $(CPU) = 3>>$(MAKEFILE)
@@ -250,7 +300,7 @@ MACHINE = x86
# XLDFLAGS =
# RFLAGS = -r
# EXTLIBS =
-CC = $(CC)
+CC = $(CC) -source-charset:utf-8
!if "$(AS)" != "ml64"
AS = $(AS) -nologo
!endif
@@ -265,4 +315,6 @@ AS = $(AS) -nologo
$(BANG)include $$(srcdir)/win32/Makefile.sub
<<
@$(COMSPEC) /C $(srcdir:/=\)\win32\rm.bat config.h config.status
+ -@move /y $(MAKEFILE_NEW) $(MAKEFILE_BACK) > nul 2> nul
+ @move /y $(MAKEFILE) $(MAKEFILE_NEW) > nul
@echo type 'nmake' to make ruby.
diff --git a/win32/shellsplit.cmd b/win32/shellsplit.cmd
new file mode 100644
index 0000000000..0594f22df1
--- /dev/null
+++ b/win32/shellsplit.cmd
@@ -0,0 +1,114 @@
+setlocal EnableExtensions DisableDelayedExpansion
+if not defined V set V=0
+if not defined args (
+ goto :return_arg
+)
+set INPUT=%args%
+set OUTBUF=
+set UNQ=
+set QTD=
+
+set INPUT=%INPUT:#=#35%
+set INPUT=%INPUT:@=#64%
+set "PENDING=%INPUT:"=@sep%" &:: escape double quotes and split consecutive marks
+
+::#### split into unquoted part, quoted part, remains
+:loop
+
+for /F "tokens=1,2* delims=@" %%I in (" %PENDING%") do (
+ set "UNQ=%%I"
+ set "QTD=%%J"
+ set "PENDING=%%K"
+)
+set "UNQ=%UNQ:~1%"
+
+if %V%==1 (
+ echo unquoted:
+ (echo UNQ :"%UNQ%")&(echo QTD :"%QTD%")&(echo REST:"%PENDING%")&(if defined OUTBUF echo OUTBUF:"%OUTBUF%")
+)
+
+if defined QTD (set "QTD=%QTD:~3%")
+if defined PENDING (set "PENDING=%PENDING:~3%")
+
+if %V%==1 (
+ (echo QTD :"%QTD%")&(echo REST:"%PENDING%")
+)
+
+if not defined UNQ if defined OUTBUF (
+ set concat_next=true
+ goto :process_unquote
+)
+
+set concat_prev=
+set concat_check=
+if defined UNQ (set "concat_check=%UNQ:~0,1%")
+if not "%concat_check%"==" " (set concat_prev=true)
+
+set concat_next=
+set concat_check=
+if defined UNQ (set "concat_check=%UNQ:~-1%")
+if not "%concat_check%"==" " (set concat_next=true)
+
+if not defined concat_prev if defined OUTBUF (
+ goto :return_arg
+)
+
+::#### process unquoted part
+:process_unquote
+
+if defined UNQ if "%UNQ: =%"=="" (set UNQ=)
+if not defined UNQ goto :process_quoted
+
+for /F "tokens=1* eol=" %%I in ("%UNQ%") do (
+ set "token=%%I"
+ set "UNQ=%%J"
+)
+
+if %V%==1 (
+ (echo unq :"%token%")&(echo UNQ :"%UNQ%")
+)
+
+set "OUTBUF=%OUTBUF%%token%"
+if defined UNQ (
+ goto :return_arg
+) else (
+ if not defined concat_next (
+ goto :return_arg
+ )
+)
+
+::#### process quoted part
+:process_quoted
+
+if %V%==1 (
+ echo quoted:
+ (echo UNQ :"%UNQ%")&(echo QTD :"%QTD%")&(echo REST:"%PENDING%")&(if defined OUTBUF echo OUTBUF:"%OUTBUF%")
+)
+
+set "OUTBUF=%OUTBUF%%QTD%"
+set QTD=
+
+if not defined PENDING (
+ goto :return_arg
+)
+goto :loop
+
+::#### return splitted argv
+:return_arg
+
+set "argv=%OUTBUF%"
+if defined argv (set "argv=%argv:#64=@%")
+if defined argv (set "argv=%argv:#35=#%")
+
+if defined QTD (set QTD="%QTD%")
+
+:: special handling is required because they may contain double quotes
+
+if defined PENDING set PENDING=%PENDING:@sep="%
+set args=%UNQ%%QTD%%PENDING%
+if defined args set args=%args:#64=@%
+if defined args set args=%args:#35=#%
+
+endlocal & set "argv=%argv%" & set args=%args%
+
+exit /b
diff --git a/win32/test_shellsplit.cmd b/win32/test_shellsplit.cmd
new file mode 100644
index 0000000000..8a2e8ec8f4
--- /dev/null
+++ b/win32/test_shellsplit.cmd
@@ -0,0 +1,28 @@
+@echo off & if not [%1]==[] goto :process
+
+echo.
+echo This script demonstrates how shellsplit.cmd works.
+echo usage: %0 arg1 arg2...
+echo.
+echo Prints separated arguments as (arg1)(arg2)...
+echo - splits commandline with spaces/tabs. cmd.exe standard rule is ignored.
+echo - you can use double quotes to contain spaces/tabs into an argument.
+echo - you can not escape double quote.
+echo - solitary "" is ignored since cmd.exe variables cannot represent empty value.
+exit /b 0
+
+:process
+setlocal
+set V=0
+
+:: %* can contain meta character inside quote. do not use set "args=%*" here.
+set args=%*
+
+:loop
+call %~dp0\shellsplit.cmd
+if not defined argv goto :end
+set /p "tmp=(%argv%)"<NUL
+goto :loop
+
+:end
+endlocal & exit /b 0
diff --git a/win32/vssetup.cmd b/win32/vssetup.cmd
new file mode 100755
index 0000000000..f9f49fb276
--- /dev/null
+++ b/win32/vssetup.cmd
@@ -0,0 +1,56 @@
+@setlocal EnableExtensions DisableDelayedExpansion || exit /b -1
+::- do not `echo off` that affects the called batch files
+
+::- check for vswhere
+@set vswhere=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
+@if not exist "%vswhere%" (
+ echo 1>&2 vswhere.exe not found
+ exit /b 1
+)
+
+::- find the latest build tool and its setup batch file.
+@set VSDEVCMD=
+@set VSDEV_ARGS=
+@set where_opt=
+@set arch=
+:argloop
+@(set arg=%1) & if defined arg (shift) else (goto :argend)
+ @if "%arg%" == "-prerelease" (
+ set where_opt=-prerelease
+ goto :argloop
+ )
+ @if /i "%arg%" == "-arch" (
+ set arch=%1
+ shift
+ goto :argloop
+ )
+ @if /i "%arg:~0,6%" == "-arch=" (
+ set arch=%arg:~6%
+ goto :argloop
+ )
+
+ @set VSDEV_ARGS=%VSDEV_ARGS% %arg%
+ @goto :argloop
+:argend
+@if defined VSDEV_ARGS set VSDEV_ARGS=%VSDEV_ARGS:~1%
+
+@for /f "delims=" %%I in ('"%vswhere%" -products * -latest -property installationPath %where_opt%') do @(
+ set VSDEVCMD=%%I\Common7\Tools\VsDevCmd.bat
+)
+@if not defined VSDEVCMD (
+ echo 1>&2 Visual Studio not found
+ exit /b 1
+)
+
+::- default to the current processor.
+@set host_arch=%PROCESSOR_ARCHITECTURE%
+@if not defined arch set arch=%PROCESSOR_ARCHITECTURE%
+::- `vsdevcmd.bat` requires arch names to be lowercase
+@for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do @(
+ call set arch=%%arch:%%i=%%i%%
+ call set host_arch=%%host_arch:%%i=%%i%%
+)
+@if "%arch%" == "x86_64" set arch=amd64
+
+::- chain to `vsdevcmd.bat`
+@(endlocal && "%VSDEVCMD%" -arch=%arch% -host_arch=%host_arch% %VSDEV_ARGS%)
diff --git a/win32/win32.c b/win32/win32.c
index a2daba2fa1..e3a3df71f6 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -21,6 +21,10 @@
#undef __STRICT_ANSI__
+/* Visual C++ 2015 (14.0):
+ * - _MSC_VER: 1900
+ * - MSVCRT_VERSION: 140
+ */
#include "ruby/ruby.h"
#include "ruby/encoding.h"
#include "ruby/io.h"
@@ -42,7 +46,7 @@
#include <shlobj.h>
#include <mbstring.h>
#include <shlwapi.h>
-#if defined _MSC_VER && _MSC_VER >= 1400
+#if defined _MSC_VER
#include <crtdbg.h>
#include <rtcapi.h>
#endif
@@ -65,10 +69,6 @@
#include "encindex.h"
#define isdirsep(x) ((x) == '/' || (x) == '\\')
-#if defined _MSC_VER && _MSC_VER <= 1200
-# define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags))
-#endif
-
static int w32_wopen(const WCHAR *file, int oflag, int perm);
static int w32_stati128(const char *path, struct stati128 *st, UINT cp, BOOL lstat);
static char *w32_getenv(const char *name, UINT cp);
@@ -113,10 +113,8 @@ static char *w32_getenv(const char *name, UINT cp);
#undef dup2
#undef strdup
-#if RUBY_MSVCRT_VERSION >= 140
-# define _filbuf _fgetc_nolock
-# define _flsbuf _fputc_nolock
-#endif
+#define _filbuf _fgetc_nolock
+#define _flsbuf _fputc_nolock
#define enough_to_get(n) (--(n) >= 0)
#define enough_to_put(n) (--(n) >= 0)
@@ -316,15 +314,6 @@ get_version(void)
GetVersionEx(&osver);
}
-#ifdef _M_IX86
-/* License: Artistic or GPL */
-DWORD
-rb_w32_osid(void)
-{
- return osver.dwPlatformId;
-}
-#endif
-
/* License: Artistic or GPL */
DWORD
rb_w32_osver(void)
@@ -503,11 +492,6 @@ rb_w32_special_folder(int type)
return rb_w32_conv_from_wchar(path, rb_filesystem_encoding());
}
-#if defined _MSC_VER && _MSC_VER <= 1200
-/* License: Ruby's */
-#define GetSystemWindowsDirectoryW GetWindowsDirectoryW
-#endif
-
/* License: Ruby's */
UINT
rb_w32_system_tmpdir(WCHAR *path, UINT len)
@@ -629,7 +613,6 @@ init_env(void)
static void init_stdhandle(void);
-#if RUBY_MSVCRT_VERSION >= 80
/* License: Ruby's */
static void
invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy)
@@ -639,7 +622,7 @@ invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file,
int ruby_w32_rtc_error;
-# ifndef __MINGW32__
+#ifndef __MINGW32__
/* License: Ruby's */
RBIMPL_ATTR_NONNULL((5))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 5, 6)
@@ -658,7 +641,6 @@ rtc_error_handler(int e, const char *src, int line, const char *exe, const char
rb_write_error2(RSTRING_PTR(str), RSTRING_LEN(str));
return 0;
}
-# endif
#endif
static CRITICAL_SECTION select_mutex;
@@ -852,13 +834,11 @@ socklist_delete(SOCKET *sockp, int *flagp)
return ret;
}
-#if RUBY_MSVCRT_VERSION >= 80
# ifdef __MINGW32__
# define _CrtSetReportMode(type,mode) ((void)0)
# define _RTC_SetErrorFunc(func) ((void)0)
# endif
static void set_pioinfo_extra(void);
-#endif
static int w32_cmdvector(const WCHAR *, char ***, UINT, rb_encoding *);
//
// Initialization stuff
@@ -867,13 +847,10 @@ static int w32_cmdvector(const WCHAR *, char ***, UINT, rb_encoding *);
void
rb_w32_sysinit(int *argc, char ***argv)
{
-#if RUBY_MSVCRT_VERSION >= 80
-
_CrtSetReportMode(_CRT_ASSERT, 0);
_set_invalid_parameter_handler(invalid_parameter);
_RTC_SetErrorFunc(rtc_error_handler);
set_pioinfo_extra();
-#endif
SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
get_version();
@@ -2413,7 +2390,6 @@ rb_w32_closedir(DIR *dirp)
return 0;
}
-#if RUBY_MSVCRT_VERSION >= 140
typedef struct {
union
{
@@ -2433,14 +2409,8 @@ typedef struct {
#define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt
#define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr
#define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file
-#else
-#define FILE_COUNT(stream) stream->_cnt
-#define FILE_READPTR(stream) stream->_ptr
-#define FILE_FILENO(stream) stream->_file
-#endif
/* License: Ruby's */
-#if RUBY_MSVCRT_VERSION >= 140
typedef char lowio_text_mode;
typedef char lowio_pipe_lookahead[3];
@@ -2457,32 +2427,14 @@ typedef struct {
uint8_t dbcsBufferUsed : 1; // Is the dbcsBuffer in use?
char dbcsBuffer; // Buffer for the lead byte of DBCS when converting from DBCS to Unicode
} ioinfo;
-#else
-typedef struct {
- intptr_t osfhnd; /* underlying OS file HANDLE */
- char osfile; /* attributes of file (e.g., open in text mode?) */
- char pipech; /* one char buffer for handles opened on pipes */
- int lockinitflag;
- CRITICAL_SECTION lock;
-#if RUBY_MSVCRT_VERSION >= 80
- char textmode;
- char pipech2[2];
-#endif
-} ioinfo;
-#endif
#if !defined _CRTIMP || defined __MINGW32__
#undef _CRTIMP
#define _CRTIMP __declspec(dllimport)
#endif
-#if RUBY_MSVCRT_VERSION >= 140
static ioinfo ** __pioinfo = NULL;
#define IOINFO_L2E 6
-#else
-EXTERN_C _CRTIMP ioinfo * __pioinfo[];
-#define IOINFO_L2E 5
-#endif
static inline ioinfo* _pioinfo(int);
@@ -2492,20 +2444,18 @@ static inline ioinfo* _pioinfo(int);
#define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock)
#define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock)
-#if RUBY_MSVCRT_VERSION >= 80
static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */
/* License: Ruby's */
static void
set_pioinfo_extra(void)
{
-#if RUBY_MSVCRT_VERSION >= 140
-# define FUNCTION_RET 0xc3 /* ret */
-# ifdef _DEBUG
-# define UCRTBASE "ucrtbased.dll"
-# else
-# define UCRTBASE "ucrtbase.dll"
-# endif
+#define FUNCTION_RET 0xc3 /* ret */
+#ifdef _DEBUG
+# define UCRTBASE "ucrtbased.dll"
+#else
+# define UCRTBASE "ucrtbase.dll"
+#endif
/* get __pioinfo addr with _isatty */
/*
* Why Ruby depends to _pioinfo is
@@ -2640,7 +2590,6 @@ set_pioinfo_extra(void)
__pioinfo = *(ioinfo***)(p);
#endif
#endif /* _M_ARM64 */
-#endif /* RUBY_MSVCRT_VERSION */
int fd;
fd = _open("NUL", O_RDONLY);
@@ -2656,9 +2605,6 @@ set_pioinfo_extra(void)
pioinfo_extra = 0;
}
}
-#else
-#define pioinfo_extra 0
-#endif
static inline ioinfo*
_pioinfo(int fd)
@@ -4235,7 +4181,6 @@ socketpair(int af, int type, int protocol, int *sv)
return 0;
}
-#if !defined(_MSC_VER) || _MSC_VER >= 1400
/* License: Ruby's */
static void
str2guid(const char *str, GUID *guid)
@@ -4361,7 +4306,6 @@ freeifaddrs(struct ifaddrs *ifp)
ifp = next;
}
}
-#endif
#if 0 // Have never been used
//
@@ -4725,26 +4669,35 @@ waitpid(rb_pid_t pid, int *stat_loc, int options)
#include <sys/timeb.h>
/* License: Ruby's */
+#define filetime_unit (10UL * 1000 * 1000)
+#define filetime_diff_days ((1970-1601)*3652425UL/10000)
+#define filetime_diff_secs (filetime_diff_days * (24ULL * 60 * 60))
+#define unix_to_filetime(sec) (((sec) + filetime_diff_secs) * filetime_unit)
+#define filetime_unix_offset unix_to_filetime(0ULL)
+
+/* License: Ruby's */
+typedef union {
+ /* FILETIME and ULARGE_INTEGER::u are the same layout */
+ FILETIME ft;
+ ULARGE_INTEGER i;
+} FILETIME_INTEGER;
+
+/* License: Ruby's */
/* split FILETIME value into UNIX time and sub-seconds in NT ticks */
static time_t
filetime_split(const FILETIME* ft, long *subsec)
{
- ULARGE_INTEGER tmp;
- unsigned LONG_LONG lt;
- const unsigned LONG_LONG subsec_unit = (unsigned LONG_LONG)10 * 1000 * 1000;
-
- tmp.LowPart = ft->dwLowDateTime;
- tmp.HighPart = ft->dwHighDateTime;
- lt = tmp.QuadPart;
+ FILETIME_INTEGER fi = {.ft = *ft};
+ ULONGLONG lt = fi.i.QuadPart;
/* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC,
convert it into UNIX time (since 1970/01/01 00:00:00 UTC).
the first leap second is at 1972/06/30, so we doesn't need to think
about it. */
- lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * subsec_unit;
+ lt -= unix_to_filetime(0);
- *subsec = (long)(lt % subsec_unit);
- return (time_t)(lt / subsec_unit);
+ *subsec = (long)(lt % filetime_unit);
+ return (time_t)(lt / filetime_unit);
}
/* License: Ruby's */
@@ -4762,37 +4715,67 @@ gettimeofday(struct timeval *tv, struct timezone *tz)
}
/* License: Ruby's */
+static void
+filetime_to_timespec(FILETIME ft, struct timespec *sp)
+{
+ long subsec;
+ sp->tv_sec = filetime_split(&ft, &subsec);
+ sp->tv_nsec = subsec * 100;
+}
+
+/* License: Ruby's */
+static const long secs_in_ns = 1000000000;
+
+/* License: Ruby's */
int
clock_gettime(clockid_t clock_id, struct timespec *sp)
{
switch (clock_id) {
case CLOCK_REALTIME:
+ case CLOCK_REALTIME_COARSE:
{
FILETIME ft;
- long subsec;
GetSystemTimePreciseAsFileTime(&ft);
- sp->tv_sec = filetime_split(&ft, &subsec);
- sp->tv_nsec = subsec * 100;
+ filetime_to_timespec(ft, sp);
return 0;
}
case CLOCK_MONOTONIC:
{
LARGE_INTEGER freq;
LARGE_INTEGER count;
- if (!QueryPerformanceFrequency(&freq)) {
+ if (UNLIKELY(!QueryPerformanceFrequency(&freq))) {
errno = map_errno(GetLastError());
return -1;
}
- if (!QueryPerformanceCounter(&count)) {
+ if (UNLIKELY(!QueryPerformanceCounter(&count))) {
errno = map_errno(GetLastError());
return -1;
}
sp->tv_sec = count.QuadPart / freq.QuadPart;
- if (freq.QuadPart < 1000000000)
- sp->tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
+ if (freq.QuadPart < secs_in_ns)
+ sp->tv_nsec = (count.QuadPart % freq.QuadPart) * secs_in_ns / freq.QuadPart;
else
- sp->tv_nsec = (long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
+ sp->tv_nsec = (long)((count.QuadPart % freq.QuadPart) * ((double)secs_in_ns / freq.QuadPart));
+ return 0;
+ }
+ case CLOCK_PROCESS_CPUTIME_ID:
+ case CLOCK_THREAD_CPUTIME_ID:
+ {
+ FILETIME_INTEGER c, e, k, u, total;
+ BOOL ok;
+ if (clock_id == CLOCK_PROCESS_CPUTIME_ID) {
+ ok = GetProcessTimes(GetCurrentProcess(), &c.ft, &e.ft, &k.ft, &u.ft);
+ }
+ else {
+ ok = GetThreadTimes(GetCurrentThread(), &c.ft, &e.ft, &k.ft, &u.ft);
+ }
+ if (UNLIKELY(!ok)) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ total.i.QuadPart = k.i.QuadPart + u.i.QuadPart;
+ filetime_to_timespec(total.ft, sp);
return 0;
}
default:
@@ -4807,6 +4790,7 @@ clock_getres(clockid_t clock_id, struct timespec *sp)
{
switch (clock_id) {
case CLOCK_REALTIME:
+ case CLOCK_REALTIME_COARSE:
{
sp->tv_sec = 0;
sp->tv_nsec = 1000;
@@ -4820,7 +4804,15 @@ clock_getres(clockid_t clock_id, struct timespec *sp)
return -1;
}
sp->tv_sec = 0;
- sp->tv_nsec = (long)(1000000000.0 / freq.QuadPart);
+ sp->tv_nsec = (long)((double)secs_in_ns / freq.QuadPart);
+ return 0;
+ }
+ case CLOCK_PROCESS_CPUTIME_ID:
+ case CLOCK_THREAD_CPUTIME_ID:
+ {
+ const int frames_in_sec = 60;
+ sp->tv_sec = 0;
+ sp->tv_nsec = (long)(secs_in_ns / frames_in_sec);
return 0;
}
default:
@@ -6611,7 +6603,7 @@ rb_w32_pipe(int fds[2])
memcpy(name, prefix, width_of_prefix);
snprintf(name + width_of_prefix, width_of_ids, "%.*"PRI_PIDT_PREFIX"x-%.*lx",
- width_of_pid, rb_w32_getpid(), width_of_serial, InterlockedIncrement(&serial)-1);
+ width_of_pid, rb_w32_getpid(), width_of_serial, (unsigned long)(InterlockedIncrement(&serial)-1));
sec.nLength = sizeof(sec);
sec.lpSecurityDescriptor = NULL;
@@ -6745,20 +6737,6 @@ constat_handle(HANDLE h)
return p;
}
-/* License: Ruby's */
-static void
-constat_reset(HANDLE h)
-{
- st_data_t data;
- struct constat *p;
- thread_exclusive(conlist) {
- if (!conlist || conlist == conlist_disabled) continue;
- if (!st_lookup(conlist, (st_data_t)h, &data)) continue;
- p = (struct constat *)data;
- p->vt100.state = constat_init;
- }
-}
-
#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
@@ -6789,47 +6767,54 @@ constat_attr(int count, const int *seq, WORD attr, WORD default_attr, int *rever
case 1:
bold = FOREGROUND_INTENSITY;
break;
+ case 22:
+ bold = 0;
+ break;
case 4:
#ifndef COMMON_LVB_UNDERSCORE
#define COMMON_LVB_UNDERSCORE 0x8000
#endif
attr |= COMMON_LVB_UNDERSCORE;
break;
+ case 24:
+ attr &= ~COMMON_LVB_UNDERSCORE;
+ break;
case 7:
rev = 1;
break;
+ case 27:
+ rev = 0;
+ break;
case 30:
attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
break;
- case 17:
case 31:
attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN)) | FOREGROUND_RED;
break;
- case 18:
case 32:
attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_RED)) | FOREGROUND_GREEN;
break;
- case 19:
case 33:
attr = (attr & ~FOREGROUND_BLUE) | FOREGROUND_GREEN | FOREGROUND_RED;
break;
- case 20:
case 34:
attr = (attr & ~(FOREGROUND_GREEN | FOREGROUND_RED)) | FOREGROUND_BLUE;
break;
- case 21:
case 35:
attr = (attr & ~FOREGROUND_GREEN) | FOREGROUND_BLUE | FOREGROUND_RED;
break;
- case 22:
case 36:
attr = (attr & ~FOREGROUND_RED) | FOREGROUND_BLUE | FOREGROUND_GREEN;
break;
- case 23:
case 37:
attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
break;
+ case 38: /* 256-color or true color; N/A on old Command Prompt */
+ break;
+ case 39:
+ attr = (attr & ~FOREGROUND_MASK) | (default_attr & FOREGROUND_MASK);
+ break;
case 40:
attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
@@ -6855,6 +6840,11 @@ constat_attr(int count, const int *seq, WORD attr, WORD default_attr, int *rever
case 47:
attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
break;
+ case 48: /* 256-color or true color; N/A on old Command Prompt */
+ break;
+ case 49:
+ attr = (attr & ~BACKGROUND_MASK) | (default_attr & BACKGROUND_MASK);
+ break;
}
}
attr |= bold;
@@ -7210,9 +7200,6 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset)
size_t len;
size_t ret;
OVERLAPPED ol;
- BOOL isconsole;
- BOOL islineinput = FALSE;
- int start = 0;
if (is_socket(sock))
return rb_w32_recv(fd, buf, size, 0);
@@ -7235,25 +7222,8 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset)
}
ret = 0;
- isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
- if (isconsole) {
- DWORD mode;
- GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
- islineinput = (mode & ENABLE_LINE_INPUT) != 0;
- }
retry:
- /* get rid of console reading bug */
- if (isconsole) {
- constat_reset((HANDLE)_osfhnd(fd));
- if (start)
- len = 1;
- else {
- len = 0;
- start = 1;
- }
- }
- else
- len = size;
+ len = size;
size -= len;
if (setup_overlapped(&ol, fd, FALSE, offset)) {
@@ -7324,8 +7294,7 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset)
ret += read;
if (read >= len) {
buf = (char *)buf + read;
- if (err != ERROR_OPERATION_ABORTED &&
- !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
+ if (err != ERROR_OPERATION_ABORTED && size > 0)
goto retry;
}
if (read == 0)
@@ -7532,27 +7501,13 @@ rb_w32_write_console(uintptr_t strarg, int fd)
return (long)reslen;
}
-#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
-/* License: Ruby's */
-static int
-unixtime_to_filetime(time_t time, FILETIME *ft)
-{
- ULARGE_INTEGER tmp;
-
- tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
- ft->dwLowDateTime = tmp.LowPart;
- ft->dwHighDateTime = tmp.HighPart;
- return 0;
-}
-#endif
-
/* License: Ruby's */
static int
timespec_to_filetime(const struct timespec *ts, FILETIME *ft)
{
ULARGE_INTEGER tmp;
- tmp.QuadPart = ((LONG_LONG)ts->tv_sec + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
+ tmp.QuadPart = unix_to_filetime((ULONGLONG)ts->tv_sec);
tmp.QuadPart += ts->tv_nsec / 100;
ft->dwLowDateTime = tmp.LowPart;
ft->dwHighDateTime = tmp.HighPart;
@@ -7922,23 +7877,6 @@ rb_w32_isatty(int fd)
return 1;
}
-#if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
-extern long _ftol(double);
-/* License: Ruby's */
-long
-_ftol2(double d)
-{
- return _ftol(d);
-}
-
-/* License: Ruby's */
-long
-_ftol2_sse(double d)
-{
- return _ftol(d);
-}
-#endif
-
#ifndef signbit
/* License: Ruby's */
int
@@ -7970,68 +7908,6 @@ rb_w32_fd_is_text(int fd)
return _osfile(fd) & FTEXT;
}
-#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
-/* License: Ruby's */
-static int
-unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
-{
- FILETIME ft;
- if (unixtime_to_filetime(t, &ft)) return -1;
- if (!FileTimeToSystemTime(&ft, st)) return -1;
- return 0;
-}
-
-/* License: Ruby's */
-static void
-systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
-{
- int y = st->wYear, m = st->wMonth, d = st->wDay;
- t->tm_sec = st->wSecond;
- t->tm_min = st->wMinute;
- t->tm_hour = st->wHour;
- t->tm_mday = st->wDay;
- t->tm_mon = st->wMonth - 1;
- t->tm_year = y - 1900;
- t->tm_wday = st->wDayOfWeek;
- switch (m) {
- case 1:
- break;
- case 2:
- d += 31;
- break;
- default:
- d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
- d += ((m - 3) * 153 + 2) / 5;
- break;
- }
- t->tm_yday = d - 1;
-}
-
-/* License: Ruby's */
-static int
-systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
-{
- TIME_ZONE_INFORMATION stdtz;
- SYSTEMTIME sst;
-
- if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
- if (!tz) {
- GetTimeZoneInformation(&stdtz);
- tz = &stdtz;
- }
- if (tz->StandardBias == tz->DaylightBias) return 0;
- if (!tz->StandardDate.wMonth) return 0;
- if (!tz->DaylightDate.wMonth) return 0;
- if (tz != &stdtz) stdtz = *tz;
-
- stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
- if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
- if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
- return 0;
- return 1;
-}
-#endif
-
#ifdef HAVE__GMTIME64_S
# ifndef HAVE__LOCALTIME64_S
/* assume same as _gmtime64_s() */
@@ -8055,17 +7931,8 @@ gmtime_r(const time_t *tp, struct tm *rp)
errno = e;
return NULL;
}
-#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S)
e = gmtime_s(rp, tp);
if (e != 0) goto error;
-#else
- {
- SYSTEMTIME st;
- if (unixtime_to_systemtime(*tp, &st)) goto error;
- rp->tm_isdst = 0;
- systemtime_to_tm(&st, rp);
- }
-#endif
return rp;
}
@@ -8079,17 +7946,8 @@ localtime_r(const time_t *tp, struct tm *rp)
errno = e;
return NULL;
}
-#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S)
e = localtime_s(rp, tp);
if (e) goto error;
-#else
- {
- SYSTEMTIME gst, lst;
- if (unixtime_to_systemtime(*tp, &gst)) goto error;
- rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
- systemtime_to_tm(&lst, rp);
- }
-#endif
return rp;
}
@@ -8306,10 +8164,6 @@ rb_w32_set_thread_description_str(HANDLE th, VALUE name)
VALUE (*const rb_f_notimplement_)(int, const VALUE *, VALUE, VALUE) = rb_f_notimplement;
-#if RUBY_MSVCRT_VERSION < 120
-#include "missing/nextafter.c"
-#endif
-
void *
rb_w32_mmap(void *addr, size_t len, int prot, int flags, int fd, rb_off_t offset)
{
diff --git a/yjit.c b/yjit.c
index 04231a0491..99375a1cda 100644
--- a/yjit.c
+++ b/yjit.c
@@ -21,8 +21,8 @@
#include "builtin.h"
#include "insns.inc"
#include "insns_info.inc"
-#include "vm_sync.h"
#include "yjit.h"
+#include "zjit.h"
#include "vm_insnhelper.h"
#include "probes.h"
#include "probes_helper.h"
@@ -38,17 +38,6 @@
#include <errno.h>
-// Field offsets for the RObject struct
-enum robject_offsets {
- ROBJECT_OFFSET_AS_HEAP_IVPTR = offsetof(struct RObject, as.heap.ivptr),
- ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary),
-};
-
-// Field offsets for the RString struct
-enum rstring_offsets {
- RUBY_OFFSET_RSTRING_LEN = offsetof(struct RString, len)
-};
-
// We need size_t to have a known size to simplify code generation and FFI.
// TODO(alan): check this in configure.ac to fail fast on 32 bit platforms.
STATIC_ASSERT(64b_size_t, SIZE_MAX == UINT64_MAX);
@@ -75,62 +64,6 @@ STATIC_ASSERT(pointer_tagging_scheme, USE_FLONUM);
// The "_yjit_" part is for trying to be informative. We might want different
// suffixes for symbols meant for Rust and symbols meant for broader CRuby.
-bool
-rb_yjit_mark_writable(void *mem_block, uint32_t mem_size)
-{
- return mprotect(mem_block, mem_size, PROT_READ | PROT_WRITE) == 0;
-}
-
-void
-rb_yjit_mark_executable(void *mem_block, uint32_t mem_size)
-{
- // Do not call mprotect when mem_size is zero. Some platforms may return
- // an error for it. https://github.com/Shopify/ruby/issues/450
- if (mem_size == 0) {
- return;
- }
- 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));
- }
-}
-
-// Free the specified memory block.
-bool
-rb_yjit_mark_unused(void *mem_block, uint32_t mem_size)
-{
- // On Linux, you need to use madvise MADV_DONTNEED to free memory.
- // We might not need to call this on macOS, but it's not really documented.
- // We generally prefer to do the same thing on both to ease testing too.
- madvise(mem_block, mem_size, MADV_DONTNEED);
-
- // On macOS, mprotect PROT_NONE seems to reduce RSS.
- // We also call this on Linux to avoid executing unused pages.
- return mprotect(mem_block, mem_size, PROT_NONE) == 0;
-}
-
-long
-rb_yjit_array_len(VALUE a)
-{
- return rb_array_len(a);
-}
-
-// `start` is inclusive and `end` is exclusive.
-void
-rb_yjit_icache_invalidate(void *start, void *end)
-{
- // Clear/invalidate the instruction cache. Compiles to nothing on x86_64
- // but required on ARM before running freshly written code.
- // On Darwin it's the same as calling sys_icache_invalidate().
-#ifdef __GNUC__
- __builtin___clear_cache(start, end);
-#elif defined(__aarch64__)
-#error No instruction cache clear available with this compiler on Aarch64!
-#endif
-}
-
-# define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
-
// 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
@@ -223,147 +156,11 @@ rb_yjit_exit_locations_dict(VALUE *yjit_raw_samples, int *yjit_line_samples, int
return result;
}
-uint32_t
-rb_yjit_get_page_size(void)
-{
-#if defined(_SC_PAGESIZE)
- long page_size = sysconf(_SC_PAGESIZE);
- if (page_size <= 0) rb_bug("yjit: failed to get page size");
-
- // 1 GiB limit. x86 CPUs with PDPE1GB can do this and anything larger is unexpected.
- // Though our design sort of assume we have fine grained control over memory protection
- // which require small page sizes.
- if (page_size > 0x40000000l) rb_bug("yjit page size too large");
-
- return (uint32_t)page_size;
-#else
-#error "YJIT supports POSIX only for now"
-#endif
-}
-
-#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.
-uint8_t *
-rb_yjit_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 *)(uintptr_t)&rb_yjit_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) {
- ruby_annotate_mmap(mem_block, mem_size, "Ruby:rb_yjit_reserve_addr_space");
- break;
- }
-
- // -4MiB. Downwards to probe away from the heap. (On x86/A64 Linux
- // main_code_addr < heap_addr, and in case we are in a shared
- // library mapped higher than the heap, downwards is still better
- // since it's towards the end of the heap rather than the stack.)
- 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 *)rb_yjit_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
- );
-
- if (mem_block != MAP_FAILED) {
- ruby_annotate_mmap(mem_block, mem_size, "Ruby:rb_yjit_reserve_addr_space:fallback");
- }
- }
-
- // 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
-}
-
// Is anyone listening for :c_call and :c_return event currently?
bool
rb_c_method_tracing_currently_enabled(const rb_execution_context_t *ec)
{
- rb_event_flag_t tracing_events;
- if (rb_multi_ractor_p()) {
- tracing_events = ruby_vm_event_enabled_global_flags;
- }
- else {
- // At the time of writing, events are never removed from
- // ruby_vm_event_enabled_global_flags so always checking using it would
- // mean we don't compile even after tracing is disabled.
- tracing_events = rb_ec_ractor_hooks(ec)->events;
- }
-
- return tracing_events & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN);
+ return ruby_vm_c_events_enabled > 0;
}
// The code we generate in gen_send_cfunc() doesn't fire the c_return TracePoint event
@@ -396,12 +193,6 @@ rb_full_cfunc_return(rb_execution_context_t *ec, VALUE return_value)
ec->cfp->sp++;
}
-unsigned int
-rb_iseq_encoded_size(const rb_iseq_t *iseq)
-{
- return iseq->body->iseq_size;
-}
-
// TODO(alan): consider using an opaque pointer for the payload rather than a void pointer
void *
rb_iseq_get_yjit_payload(const rb_iseq_t *iseq)
@@ -425,339 +216,13 @@ rb_iseq_set_yjit_payload(const rb_iseq_t *iseq, void *payload)
iseq->body->yjit_payload = payload;
}
-void
-rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
- iseq->body->jit_entry = NULL;
- iseq->body->jit_exception = NULL;
- // Enable re-compiling this ISEQ. Event when it's invalidated for TracePoint,
- // we'd like to re-compile ISEQs that haven't been converted to trace_* insns.
- iseq->body->jit_entry_calls = 0;
- iseq->body->jit_exception_calls = 0;
-}
-
-// Get the PC for a given index in an iseq
-VALUE *
-rb_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
- RUBY_ASSERT_ALWAYS(insn_idx < iseq->body->iseq_size);
- VALUE *encoded = iseq->body->iseq_encoded;
- VALUE *pc = &encoded[insn_idx];
- return pc;
-}
-
-// Get the opcode given a program counter. Can return trace opcode variants.
-int
-rb_iseq_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
-{
- // YJIT should only use iseqs after AST to bytecode compilation
- RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
-
- const VALUE at_pc = *pc;
- return rb_vm_insn_addr2opcode((const void *)at_pc);
-}
-
-unsigned long
-rb_RSTRING_LEN(VALUE str)
-{
- return RSTRING_LEN(str);
-}
-
-char *
-rb_RSTRING_PTR(VALUE str)
-{
- return RSTRING_PTR(str);
-}
-
-rb_proc_t *
-rb_yjit_get_proc_ptr(VALUE procv)
-{
- rb_proc_t *proc;
- GetProcPtr(procv, proc);
- return proc;
-}
-
// This is defined only as a named struct inside rb_iseq_constant_body.
// By giving it a separate typedef, we make it nameable by rust-bindgen.
// Bindgen's temp/anon name isn't guaranteed stable.
typedef struct rb_iseq_param_keyword rb_seq_param_keyword_struct;
-const char *
-rb_insn_name(VALUE insn)
-{
- return insn_name(insn);
-}
-
-unsigned int
-rb_vm_ci_argc(const struct rb_callinfo *ci)
-{
- return vm_ci_argc(ci);
-}
-
-ID
-rb_vm_ci_mid(const struct rb_callinfo *ci)
-{
- return vm_ci_mid(ci);
-}
-
-unsigned int
-rb_vm_ci_flag(const struct rb_callinfo *ci)
-{
- return vm_ci_flag(ci);
-}
-
-const struct rb_callinfo_kwarg *
-rb_vm_ci_kwarg(const struct rb_callinfo *ci)
-{
- return vm_ci_kwarg(ci);
-}
-
-int
-rb_get_cikw_keyword_len(const struct rb_callinfo_kwarg *cikw)
-{
- return cikw->keyword_len;
-}
-
-VALUE
-rb_get_cikw_keywords_idx(const struct rb_callinfo_kwarg *cikw, int idx)
-{
- return cikw->keywords[idx];
-}
-
-rb_method_visibility_t
-rb_METHOD_ENTRY_VISI(const rb_callable_method_entry_t *me)
-{
- return METHOD_ENTRY_VISI(me);
-}
-
-rb_method_type_t
-rb_get_cme_def_type(const rb_callable_method_entry_t *cme)
-{
- if (UNDEFINED_METHOD_ENTRY_P(cme)) {
- return VM_METHOD_TYPE_UNDEF;
- }
- else {
- return cme->def->type;
- }
-}
-
-ID
-rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.attr.id;
-}
-
ID rb_get_symbol_id(VALUE namep);
-enum method_optimized_type
-rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.optimized.type;
-}
-
-unsigned int
-rb_get_cme_def_body_optimized_index(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.optimized.index;
-}
-
-rb_method_cfunc_t *
-rb_get_cme_def_body_cfunc(const rb_callable_method_entry_t *cme)
-{
- return UNALIGNED_MEMBER_PTR(cme->def, body.cfunc);
-}
-
-uintptr_t
-rb_get_def_method_serial(const rb_method_definition_t *def)
-{
- return def->method_serial;
-}
-
-ID
-rb_get_def_original_id(const rb_method_definition_t *def)
-{
- return def->original_id;
-}
-
-int
-rb_get_mct_argc(const rb_method_cfunc_t *mct)
-{
- return mct->argc;
-}
-
-void *
-rb_get_mct_func(const rb_method_cfunc_t *mct)
-{
- return (void*)(uintptr_t)mct->func; // this field is defined as type VALUE (*func)(ANYARGS)
-}
-
-const rb_iseq_t *
-rb_get_def_iseq_ptr(rb_method_definition_t *def)
-{
- return def_iseq_ptr(def);
-}
-
-VALUE
-rb_get_def_bmethod_proc(rb_method_definition_t *def)
-{
- RUBY_ASSERT(def->type == VM_METHOD_TYPE_BMETHOD);
- return def->body.bmethod.proc;
-}
-
-const rb_iseq_t *
-rb_get_iseq_body_local_iseq(const rb_iseq_t *iseq)
-{
- return iseq->body->local_iseq;
-}
-
-const rb_iseq_t *
-rb_get_iseq_body_parent_iseq(const rb_iseq_t *iseq)
-{
- return iseq->body->parent_iseq;
-}
-
-unsigned int
-rb_get_iseq_body_local_table_size(const rb_iseq_t *iseq)
-{
- return iseq->body->local_table_size;
-}
-
-VALUE *
-rb_get_iseq_body_iseq_encoded(const rb_iseq_t *iseq)
-{
- return iseq->body->iseq_encoded;
-}
-
-unsigned
-rb_get_iseq_body_stack_max(const rb_iseq_t *iseq)
-{
- return iseq->body->stack_max;
-}
-
-enum rb_iseq_type
-rb_get_iseq_body_type(const rb_iseq_t *iseq)
-{
- return iseq->body->type;
-}
-
-bool
-rb_get_iseq_flags_has_lead(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_lead;
-}
-
-bool
-rb_get_iseq_flags_has_opt(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_opt;
-}
-
-bool
-rb_get_iseq_flags_has_kw(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_kw;
-}
-
-bool
-rb_get_iseq_flags_has_post(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_post;
-}
-
-bool
-rb_get_iseq_flags_has_kwrest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_kwrest;
-}
-
-bool
-rb_get_iseq_flags_anon_kwrest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.anon_kwrest;
-}
-
-bool
-rb_get_iseq_flags_has_rest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_rest;
-}
-
-bool
-rb_get_iseq_flags_ruby2_keywords(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.ruby2_keywords;
-}
-
-bool
-rb_get_iseq_flags_has_block(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_block;
-}
-
-bool
-rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.ambiguous_param0;
-}
-
-bool
-rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.accepts_no_kwarg;
-}
-
-bool
-rb_get_iseq_flags_forwardable(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.forwardable;
-}
-
-const rb_seq_param_keyword_struct *
-rb_get_iseq_body_param_keyword(const rb_iseq_t *iseq)
-{
- return iseq->body->param.keyword;
-}
-
-unsigned
-rb_get_iseq_body_param_size(const rb_iseq_t *iseq)
-{
- return iseq->body->param.size;
-}
-
-int
-rb_get_iseq_body_param_lead_num(const rb_iseq_t *iseq)
-{
- return iseq->body->param.lead_num;
-}
-
-int
-rb_get_iseq_body_param_opt_num(const rb_iseq_t *iseq)
-{
- return iseq->body->param.opt_num;
-}
-
-const VALUE *
-rb_get_iseq_body_param_opt_table(const rb_iseq_t *iseq)
-{
- return iseq->body->param.opt_table;
-}
-
-VALUE
-rb_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);
-}
-
-unsigned int
-rb_yjit_iseq_builtin_attrs(const rb_iseq_t *iseq)
-{
- return iseq->body->builtin_attrs;
-}
-
// If true, the iseq has only opt_invokebuiltin_delegate(_leave) and leave insns.
static bool
invokebuiltin_delegate_leave_p(const rb_iseq_t *iseq)
@@ -789,94 +254,14 @@ rb_yjit_str_simple_append(VALUE str1, VALUE str2)
return rb_str_cat(str1, RSTRING_PTR(str2), RSTRING_LEN(str2));
}
-struct rb_control_frame_struct *
-rb_get_ec_cfp(const rb_execution_context_t *ec)
-{
- return ec->cfp;
-}
-
-const rb_iseq_t *
-rb_get_cfp_iseq(struct rb_control_frame_struct *cfp)
-{
- return cfp->iseq;
-}
-
-VALUE *
-rb_get_cfp_pc(struct rb_control_frame_struct *cfp)
-{
- return (VALUE*)cfp->pc;
-}
-
-VALUE *
-rb_get_cfp_sp(struct rb_control_frame_struct *cfp)
-{
- return cfp->sp;
-}
-
-void
-rb_set_cfp_pc(struct rb_control_frame_struct *cfp, const VALUE *pc)
-{
- cfp->pc = pc;
-}
-
-void
-rb_set_cfp_sp(struct rb_control_frame_struct *cfp, VALUE *sp)
-{
- cfp->sp = sp;
-}
-
-VALUE
-rb_get_cfp_self(struct rb_control_frame_struct *cfp)
-{
- return cfp->self;
-}
-
-VALUE *
-rb_get_cfp_ep(struct rb_control_frame_struct *cfp)
-{
- return (VALUE*)cfp->ep;
-}
-
-const VALUE *
-rb_get_cfp_ep_level(struct rb_control_frame_struct *cfp, uint32_t lv)
-{
- uint32_t i;
- const VALUE *ep = (VALUE*)cfp->ep;
- for (i = 0; i < lv; i++) {
- ep = VM_ENV_PREV_EP(ep);
- }
- return ep;
-}
-
extern VALUE *rb_vm_base_ptr(struct rb_control_frame_struct *cfp);
VALUE
-rb_yarv_class_of(VALUE obj)
-{
- return rb_class_of(obj);
-}
-
-// YJIT needs this function to never allocate and never raise
-VALUE
-rb_yarv_str_eql_internal(VALUE str1, VALUE str2)
-{
- // We wrap this since it's static inline
- return rb_str_eql_internal(str1, str2);
-}
-
-VALUE
rb_str_neq_internal(VALUE str1, VALUE str2)
{
return rb_str_eql_internal(str1, str2) == Qtrue ? Qfalse : Qtrue;
}
-// YJIT needs this function to never allocate and never raise
-VALUE
-rb_yarv_ary_entry_internal(VALUE ary, long offset)
-{
- return rb_ary_entry_internal(ary, offset);
-}
-
extern VALUE rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary);
VALUE
@@ -886,18 +271,6 @@ rb_yjit_rb_ary_subseq_length(VALUE ary, long beg)
return rb_ary_subseq(ary, beg, len);
}
-VALUE
-rb_yjit_fix_div_fix(VALUE recv, VALUE obj)
-{
- return rb_fix_div_fix(recv, obj);
-}
-
-VALUE
-rb_yjit_fix_mod_fix(VALUE recv, VALUE obj)
-{
- return rb_fix_mod_fix(recv, obj);
-}
-
// Return non-zero when `obj` is an array and its last item is a
// `ruby2_keywords` hash. We don't support this kind of splat.
size_t
@@ -984,38 +357,12 @@ rb_yjit_iseq_inspect(const rb_iseq_t *iseq)
const char *path = RSTRING_PTR(rb_iseq_path(iseq));
int lineno = iseq->body->location.code_location.beg_pos.lineno;
- char *buf = ZALLOC_N(char, strlen(label) + strlen(path) + num_digits(lineno) + 3);
- sprintf(buf, "%s@%s:%d", label, path, lineno);
+ const size_t size = strlen(label) + strlen(path) + num_digits(lineno) + 3;
+ char *buf = ZALLOC_N(char, size);
+ snprintf(buf, size, "%s@%s:%d", label, path, lineno);
return buf;
}
-// The FL_TEST() macro
-VALUE
-rb_FL_TEST(VALUE obj, VALUE flags)
-{
- return RB_FL_TEST(obj, flags);
-}
-
-// The FL_TEST_RAW() macro, normally an internal implementation detail
-VALUE
-rb_FL_TEST_RAW(VALUE obj, VALUE flags)
-{
- return FL_TEST_RAW(obj, flags);
-}
-
-// The RB_TYPE_P macro
-bool
-rb_RB_TYPE_P(VALUE obj, enum ruby_value_type t)
-{
- return RB_TYPE_P(obj, t);
-}
-
-long
-rb_RSTRUCT_LEN(VALUE st)
-{
- return RSTRUCT_LEN(st);
-}
-
// There are RSTRUCT_SETs in ruby/internal/core/rstruct.h and internal/struct.h
// with different types (int vs long) for k. Here we use the one from ruby/internal/core/rstruct.h,
// which takes an int.
@@ -1025,24 +372,6 @@ rb_RSTRUCT_SET(VALUE st, int k, VALUE v)
RSTRUCT_SET(st, k, v);
}
-const struct rb_callinfo *
-rb_get_call_data_ci(const struct rb_call_data *cd)
-{
- return cd->ci;
-}
-
-bool
-rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop, uint32_t klass)
-{
- return BASIC_OP_UNREDEFINED_P(bop, klass);
-}
-
-VALUE
-rb_RCLASS_ORIGIN(VALUE c)
-{
- return RCLASS_ORIGIN(c);
-}
-
// Return the string encoding index
int
rb_ENCODING_GET(VALUE obj)
@@ -1051,72 +380,11 @@ rb_ENCODING_GET(VALUE obj)
}
bool
-rb_yjit_multi_ractor_p(void)
-{
- return rb_multi_ractor_p();
-}
-
-// For debug builds
-void
-rb_assert_iseq_handle(VALUE handle)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
-}
-
-int
-rb_IMEMO_TYPE_P(VALUE imemo, enum imemo_type imemo_type)
-{
- return IMEMO_TYPE_P(imemo, imemo_type);
-}
-
-bool
rb_yjit_constcache_shareable(const struct iseq_inline_constant_cache_entry *ice)
{
return (ice->flags & IMEMO_CONST_CACHE_SHAREABLE) != 0;
}
-void
-rb_assert_cme_handle(VALUE handle)
-{
- RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle));
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment));
-}
-
-// Used for passing a callback and other data over rb_objspace_each_objects
-struct iseq_callback_data {
- rb_iseq_callback callback;
- void *data;
-};
-
-// Heap-walking callback for rb_yjit_for_each_iseq().
-static int
-for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
-{
- const struct iseq_callback_data *callback_data = (struct iseq_callback_data *)data;
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- void *ptr = rb_asan_poisoned_object_p(v);
- rb_asan_unpoison_object(v, false);
-
- if (rb_obj_is_iseq(v)) {
- rb_iseq_t *iseq = (rb_iseq_t *)v;
- callback_data->callback(iseq, callback_data->data);
- }
-
- asan_poison_object_if(ptr, v);
- }
- return 0;
-}
-
-// Iterate through the whole GC heap and invoke a callback for each iseq.
-// Used for global code invalidation.
-void
-rb_yjit_for_each_iseq(rb_iseq_callback callback, void *data)
-{
- struct iseq_callback_data callback_data = { .callback = callback, .data = data };
- rb_objspace_each_objects(for_each_iseq_i, (void *)&callback_data);
-}
-
// For running write barriers from Rust. Required when we add a new edge in the
// object graph from `old` to `young`.
void
@@ -1125,43 +393,23 @@ rb_yjit_obj_written(VALUE old, VALUE young, const char *file, int line)
rb_obj_written(old, Qundef, young, file, line);
}
-// Acquire the VM lock and then signal all other Ruby threads (ractors) to
-// contend for the VM lock, putting them to sleep. YJIT uses this to evict
-// threads running inside generated code so among other things, it can
-// safely change memory protection of regions housing generated code.
-void
-rb_yjit_vm_lock_then_barrier(unsigned int *recursive_lock_level, const char *file, int line)
-{
- rb_vm_lock_enter(recursive_lock_level, file, line);
- rb_vm_barrier();
-}
-
-// Release the VM lock. The lock level must point to the same integer used to
-// acquire the lock.
-void
-rb_yjit_vm_unlock(unsigned int *recursive_lock_level, const char *file, int line)
-{
- rb_vm_lock_leave(recursive_lock_level, file, line);
-}
-
void
rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception)
{
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
+ RB_VM_LOCKING() {
+ rb_vm_barrier();
- // Compile a block version starting at the current instruction
- uint8_t *rb_yjit_iseq_gen_entry_point(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception); // defined in Rust
- uintptr_t code_ptr = (uintptr_t)rb_yjit_iseq_gen_entry_point(iseq, ec, jit_exception);
+ // Compile a block version starting at the current instruction
+ uint8_t *rb_yjit_iseq_gen_entry_point(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception); // defined in Rust
+ uintptr_t code_ptr = (uintptr_t)rb_yjit_iseq_gen_entry_point(iseq, ec, jit_exception);
- if (jit_exception) {
- iseq->body->jit_exception = (rb_jit_func_t)code_ptr;
- }
- else {
- iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
+ if (jit_exception) {
+ iseq->body->jit_exception = (rb_jit_func_t)code_ptr;
+ }
+ else {
+ iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
+ }
}
-
- RB_VM_LOCK_LEAVE();
}
// GC root for interacting with the GC
@@ -1182,15 +430,25 @@ VALUE
rb_object_shape_count(void)
{
// next_shape_id starts from 0, so it's the same as the count
- return ULONG2NUM((unsigned long)GET_SHAPE_TREE()->next_shape_id);
+ return ULONG2NUM((unsigned long)rb_shapes_count());
}
-// Assert that we have the VM lock. Relevant mostly for multi ractor situations.
-// The GC takes the lock before calling us, and this asserts that it indeed happens.
-void
-rb_yjit_assert_holding_vm_lock(void)
+bool
+rb_yjit_shape_obj_complex_p(VALUE obj)
+{
+ return rb_obj_shape_complex_p(obj);
+}
+
+attr_index_t
+rb_yjit_shape_capacity(shape_id_t shape_id)
{
- ASSERT_vm_locking();
+ return RSHAPE_CAPACITY(shape_id);
+}
+
+attr_index_t
+rb_yjit_shape_index(shape_id_t shape_id)
+{
+ return RSHAPE_INDEX(shape_id);
}
// The number of stack slots that vm_sendish() pops for send and invokesuper.
@@ -1207,6 +465,12 @@ rb_yjit_invokeblock_sp_pops(const struct rb_callinfo *ci)
return 1 - sp_inc_of_invokeblock(ci); // + 1 to ignore return value push
}
+rb_serial_t
+rb_yjit_cme_ractor_serial(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.bmethod.defined_ractor_id;
+}
+
// Setup jit_return to avoid returning a non-Qundef value on a non-FINISH frame.
// See [jit_compile_exception] for details.
void
@@ -1236,6 +500,39 @@ rb_yjit_set_exception_return(rb_control_frame_t *cfp, void *leave_exit, void *le
}
}
+// VM_INSTRUCTION_SIZE changes depending on if ZJIT is in the build. Since
+// bindgen can only grab one version of the constant and copy that to rust,
+// we make that the upper bound and this the accurate value.
+uint32_t
+rb_vm_instruction_size(void)
+{
+ return VM_INSTRUCTION_SIZE;
+}
+
+static int
+yjit_cdhash_all_fixnum_i(st_data_t key, st_data_t _val, st_data_t data)
+{
+ if (!FIXNUM_P((VALUE)key)) {
+ *((bool *)data) = false;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+bool
+rb_yjit_cdhash_all_fixnum_p(VALUE cdhash)
+{
+ bool all_fixnum = true;
+ st_foreach(rb_imemo_cdhash_tbl(cdhash), yjit_cdhash_all_fixnum_i, (st_data_t)&all_fixnum);
+ return all_fixnum;
+}
+
+int
+rb_yjit_cdhash_lookup(VALUE cdhash, st_data_t key, st_data_t *val)
+{
+ return st_lookup(rb_imemo_cdhash_tbl(cdhash), key, val);
+}
+
// Primitives used by yjit.rb
VALUE rb_yjit_stats_enabled_p(rb_execution_context_t *ec, VALUE self);
VALUE rb_yjit_print_stats_p(rb_execution_context_t *ec, VALUE self);
@@ -1262,3 +559,4 @@ static VALUE yjit_c_builtin_p(rb_execution_context_t *ec, VALUE self) { return Q
// Preprocessed yjit.rb generated during build
#include "yjit.rbinc"
+
diff --git a/yjit.h b/yjit.h
index 9360e7fe3c..45a9f74c86 100644
--- a/yjit.h
+++ b/yjit.h
@@ -9,10 +9,9 @@
#include "vm_core.h"
#include "method.h"
-// YJIT_STATS controls whether to support runtime counters in generated code
-// and in the interpreter.
+// YJIT_STATS controls whether to support runtime counters in the interpreter
#ifndef YJIT_STATS
-# define YJIT_STATS RUBY_DEBUG
+# define YJIT_STATS (USE_YJIT && RUBY_DEBUG)
#endif
#if USE_YJIT
@@ -36,8 +35,9 @@ void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme);
void rb_yjit_collect_binding_alloc(void);
void rb_yjit_collect_binding_set(void);
void rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception);
+void rb_yjit_init_builtin_cmes(void);
void rb_yjit_init(bool yjit_enabled);
-void rb_yjit_free_at_exit();
+void rb_yjit_free_at_exit(void);
void rb_yjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
void rb_yjit_constant_state_changed(ID id);
void rb_yjit_iseq_mark(void *payload);
@@ -50,6 +50,8 @@ void rb_yjit_show_usage(int help, int highlight, unsigned int width, int columns
void rb_yjit_lazy_push_frame(const VALUE *pc);
void rb_yjit_invalidate_no_singleton_class(VALUE klass);
void rb_yjit_invalidate_ep_is_bp(const rb_iseq_t *iseq);
+void rb_yjit_mark_all_writeable(void);
+void rb_yjit_mark_all_executable(void);
#else
// !USE_YJIT
@@ -62,6 +64,7 @@ static inline void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
static inline void rb_yjit_collect_binding_alloc(void) {}
static inline void rb_yjit_collect_binding_set(void) {}
static inline void rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
+static inline void rb_yjit_init_builtin_cmes(void) {}
static inline void rb_yjit_init(bool yjit_enabled) {}
static inline void rb_yjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
static inline void rb_yjit_constant_state_changed(ID id) {}
diff --git a/yjit.rb b/yjit.rb
index 045fea2656..9fb4d6876b 100644
--- a/yjit.rb
+++ b/yjit.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
# :markup: markdown
-# This module allows for introspection of \YJIT, CRuby's just-in-time compiler.
+# This module allows for introspection of YJIT, CRuby's just-in-time compiler.
# Everything in the module is highly implementation specific and the API might
# be less stable compared to the standard library.
#
-# This module may not exist if \YJIT does not support the particular platform
+# This module may not exist if YJIT does not support the particular platform
# for which CRuby is built.
module RubyVM::YJIT
- # Check if \YJIT is enabled.
+ # Check if YJIT is enabled.
def self.enabled?
Primitive.cexpr! 'RBOOL(rb_yjit_enabled_p)'
end
@@ -33,8 +33,8 @@ module RubyVM::YJIT
Primitive.rb_yjit_reset_stats_bang
end
- # Enable \YJIT compilation. `stats` option decides whether to enable \YJIT stats or not. `log` decides
- # whether to enable \YJIT compilation logging or not. Optional `mem_size` and `call_threshold` can be
+ # Enable YJIT compilation. `stats` option decides whether to enable YJIT stats or not. `log` decides
+ # whether to enable YJIT compilation logging or not. Optional `mem_size` and `call_threshold` can be
# provided to override default configuration.
#
# * `stats`:
@@ -48,6 +48,11 @@ module RubyVM::YJIT
def self.enable(stats: false, log: false, mem_size: nil, call_threshold: nil)
return false if enabled?
+ if Primitive.cexpr! 'RBOOL(rb_zjit_enabled_p)'
+ warn("Only one JIT can be enabled at the same time.")
+ return false
+ end
+
if mem_size
raise ArgumentError, "mem_size must be a Integer" unless mem_size.is_a?(Integer)
raise ArgumentError, "mem_size must be between 1 and 2048 MB" unless (1..2048).include?(mem_size)
@@ -59,7 +64,6 @@ module RubyVM::YJIT
end
at_exit { print_and_dump_stats } if stats
- call_yjit_hooks
Primitive.rb_yjit_enable(stats, stats != :quiet, log, log != :quiet, mem_size, call_threshold)
end
@@ -215,7 +219,7 @@ module RubyVM::YJIT
if !self.enabled?
warn(
"YJIT needs to be enabled to produce disasm output, e.g.\n" +
- "ruby --yjit-call-threshold=1 my_script.rb (see doc/yjit/yjit.md)"
+ "ruby --yjit-call-threshold=1 my_script.rb (see doc/jit/yjit.md)"
)
return nil
end
@@ -225,7 +229,7 @@ module RubyVM::YJIT
if !disasm_str
warn(
"YJIT disasm is only available when YJIT is built in dev mode, i.e.\n" +
- "./configure --enable-yjit=dev (see doc/yjit/yjit.md)\n"
+ "./configure --enable-yjit=dev (see doc/jit/yjit.md)\n"
)
return nil
end
@@ -260,23 +264,23 @@ module RubyVM::YJIT
end
# Blocks that are called when YJIT is enabled
- @yjit_hooks = []
+ @jit_hooks = []
class << self
# :stopdoc:
private
# Register a block to be called when YJIT is enabled
- def add_yjit_hook(hook)
- @yjit_hooks << hook
+ def add_jit_hook(hook)
+ @jit_hooks << hook
end
- # Run YJIT hooks registered by RubyVM::YJIT.with_yjit
- def call_yjit_hooks
+ # Run YJIT hooks registered by `#with_jit`
+ def call_jit_hooks
# Skip using builtin methods in Ruby if --yjit-c-builtin is given
return if Primitive.yjit_c_builtin_p
- @yjit_hooks.each(&:call)
- @yjit_hooks.clear
+ @jit_hooks.each(&:call)
+ @jit_hooks.clear
end
# Print stats and dump exit locations
@@ -318,7 +322,6 @@ module RubyVM::YJIT
leave
objtostring
opt_aref
- opt_aref_with
opt_aset
opt_case_dispatch
opt_div
@@ -350,6 +353,9 @@ module RubyVM::YJIT
# Number of failed compiler invocations
compilation_failure = stats[:compilation_failure]
+ # Number of refused exceptional entries with an escaped environment
+ exceptional_entry_escaped_env = stats[:exceptional_entry_escaped_env]
+
code_region_overhead = stats[:code_region_size] - (stats[:inline_code_size] + stats[:outlined_code_size])
out.puts "num_send: " + format_number(13, stats[:num_send])
@@ -386,6 +392,7 @@ module RubyVM::YJIT
out.puts "bindings_allocations: " + format_number(13, stats[:binding_allocations])
out.puts "bindings_set: " + format_number(13, stats[:binding_set])
out.puts "compilation_failure: " + format_number(13, compilation_failure) if compilation_failure != 0
+ out.puts "exceptional_entry_escaped_env:" + format_number(6, exceptional_entry_escaped_env) if exceptional_entry_escaped_env != 0
out.puts "live_iseq_count: " + format_number(13, stats[:live_iseq_count])
out.puts "iseq_alloc_count: " + format_number(13, stats[:iseq_alloc_count])
out.puts "compiled_iseq_entry: " + format_number(13, stats[:compiled_iseq_entry])
diff --git a/yjit/Cargo.lock b/yjit/Cargo.lock
index 8b6ac39806..78e6c40986 100644
--- a/yjit/Cargo.lock
+++ b/yjit/Cargo.lock